Set the svn:eol-style property for all files to "native". The only exception is enterprise\test_gold.adm, which is set to CRLF as required by Group Policy Editor.

git-svn-id: http://omaha.googlecode.com/svn/trunk@66 e782f428-02b4-11de-a43f-ff96a2b7a9af
diff --git a/VERSION b/VERSION
index 21de866..6774a8e 100644
--- a/VERSION
+++ b/VERSION
@@ -1,10 +1,10 @@
-# -*- Python -*-

-

-# update these manually - don't autogenerate, autoincrement, etc.

-# REMEMBER TO INCREMENT BUILD BY TWO! BUILD SHOULD ALWAYS BE ODD!

-version_major = 1    # 1-65535

-version_minor = 2    # 0-65535

-version_build = 185  # 1-65535

-version_patch = 0    # 0-65535

-

-oneclick_plugin_version = '8'

+# -*- Python -*-
+
+# update these manually - don't autogenerate, autoincrement, etc.
+# REMEMBER TO INCREMENT BUILD BY TWO! BUILD SHOULD ALWAYS BE ODD!
+version_major = 1    # 1-65535
+version_minor = 2    # 0-65535
+version_build = 185  # 1-65535
+version_patch = 0    # 0-65535
+
+oneclick_plugin_version = '8'
diff --git a/bho/bho_dll.cc b/bho/bho_dll.cc
index 058ec10..c263b3b 100644
--- a/bho/bho_dll.cc
+++ b/bho/bho_dll.cc
@@ -1,68 +1,68 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// DLL entry points for the Bho DLL

-

-#include <atlbase.h>

-#include <atlcom.h>

-#include <atlctl.h>

-#include "omaha/bho/bho_entrypoint.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-class BhoDllModule : public CAtlDllModuleT<BhoDllModule> {

-};

-

-// Add BhoEntry to class library table so IE can CoCreate it.

-OBJECT_ENTRY_AUTO(__uuidof(BhoEntrypointClass), BhoEntrypoint);

-

-BhoDllModule _AtlModule;

-

-}  // namespace omaha

-

-using omaha::_AtlModule;

-

-extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID reserved) {

-  if (reason == DLL_PROCESS_ATTACH) {

-    VERIFY1(SUCCEEDED(omaha::PinModuleIntoProcess(BHO_FILENAME)));

-  }

-

-  return _AtlModule.DllMain(reason, reserved);

-}

-

-STDAPI DllCanUnloadNow() {

-  // Do not allow unloading until the process terminates.

-  return S_FALSE;

-}

-

-STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {

-  CORE_LOG(L2, (_T("[DllGetClassObject]")));

-  return _AtlModule.DllGetClassObject(rclsid, riid, ppv);

-}

-

-STDAPI DllRegisterServer(void) {

-  // Not registering the typelib.

-  return _AtlModule.DllRegisterServer(FALSE);

-}

-

-

-STDAPI DllUnregisterServer(void) {

-  // Not unregistering the typelib.

-  return _AtlModule.DllUnregisterServer(FALSE);

-}

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// DLL entry points for the Bho DLL
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlctl.h>
+#include "omaha/bho/bho_entrypoint.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+class BhoDllModule : public CAtlDllModuleT<BhoDllModule> {
+};
+
+// Add BhoEntry to class library table so IE can CoCreate it.
+OBJECT_ENTRY_AUTO(__uuidof(BhoEntrypointClass), BhoEntrypoint);
+
+BhoDllModule _AtlModule;
+
+}  // namespace omaha
+
+using omaha::_AtlModule;
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID reserved) {
+  if (reason == DLL_PROCESS_ATTACH) {
+    VERIFY1(SUCCEEDED(omaha::PinModuleIntoProcess(BHO_FILENAME)));
+  }
+
+  return _AtlModule.DllMain(reason, reserved);
+}
+
+STDAPI DllCanUnloadNow() {
+  // Do not allow unloading until the process terminates.
+  return S_FALSE;
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
+  CORE_LOG(L2, (_T("[DllGetClassObject]")));
+  return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
+}
+
+STDAPI DllRegisterServer(void) {
+  // Not registering the typelib.
+  return _AtlModule.DllRegisterServer(FALSE);
+}
+
+
+STDAPI DllUnregisterServer(void) {
+  // Not unregistering the typelib.
+  return _AtlModule.DllUnregisterServer(FALSE);
+}
+
diff --git a/bho/bho_dll.def b/bho/bho_dll.def
index 7dff3cb..f2e5579 100644
--- a/bho/bho_dll.def
+++ b/bho/bho_dll.def
@@ -1,23 +1,23 @@
-; Copyright 2007-2009 Google Inc.

-;

-; Licensed under the Apache License, Version 2.0 (the "License");

-; you may not use this file except in compliance with the License.

-; You may obtain a copy of the License at

-;

-;      http://www.apache.org/licenses/LICENSE-2.0

-;

-; Unless required by applicable law or agreed to in writing, software

-; distributed under the License is distributed on an "AS IS" BASIS,

-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-; See the License for the specific language governing permissions and

-; limitations under the License.

-; ========================================================================

-

-LIBRARY      "GoopdateBho.dll"

-

-EXPORTS

-  DllCanUnloadNow     PRIVATE

-  DllGetClassObject   PRIVATE

-  DllRegisterServer   PRIVATE

-  DllUnregisterServer PRIVATE

-

+; Copyright 2007-2009 Google Inc.
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+; ========================================================================
+
+LIBRARY      "GoopdateBho.dll"
+
+EXPORTS
+  DllCanUnloadNow     PRIVATE
+  DllGetClassObject   PRIVATE
+  DllRegisterServer   PRIVATE
+  DllUnregisterServer PRIVATE
+
diff --git a/bho/bho_dll.idl b/bho/bho_dll.idl
index 41a55c4..a56fad1 100644
--- a/bho/bho_dll.idl
+++ b/bho/bho_dll.idl
@@ -1,53 +1,53 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Template IDL file for the Bho DLL. This template is a complete IDL file in

-// all but one respect; it has one replaceable entry for the CLSID for

-// BhoEntrypointClass. This template is processed by generate_oneclick_idl.py,

-// which generates a GUID using UUIDGEN.EXE, and writes out a complete IDL

-// file with the new CLSID.

-//

-// Background Information:

-// We generate new CLSIDs for each fresh build of Omaha. This allows us to "hot

-// swap" the BHO, and we don't face the issue of IE using the older version of

-// the BHO unless it is restarted.

-

-import "oaidl.idl";

-import "ocidl.idl";

-

-// MK keeps rebuilding unless there is an interface in the IDL file. Adding in a

-// dummy interface.

-[

-  object,

-  uuid(A91B50B2-48B3-40b1-86A3-0FE0AF3AB5BF),

-]

-interface INotUsedInterface : IUnknown {

-  HRESULT NotUsedFunction([in] BSTR not_used);

-};

-

-

-[

-  uuid(B137D75E-D05F-4146-AD27-C106D89FB4F4),

-  version(1.0)

-]

-library BhoDllLib {

-  [

-    uuid(%s)

-  ]

-  coclass BhoEntrypointClass {

-    [default] interface IObjectWithSite;

-  };

-}

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Template IDL file for the Bho DLL. This template is a complete IDL file in
+// all but one respect; it has one replaceable entry for the CLSID for
+// BhoEntrypointClass. This template is processed by generate_oneclick_idl.py,
+// which generates a GUID using UUIDGEN.EXE, and writes out a complete IDL
+// file with the new CLSID.
+//
+// Background Information:
+// We generate new CLSIDs for each fresh build of Omaha. This allows us to "hot
+// swap" the BHO, and we don't face the issue of IE using the older version of
+// the BHO unless it is restarted.
+
+import "oaidl.idl";
+import "ocidl.idl";
+
+// MK keeps rebuilding unless there is an interface in the IDL file. Adding in a
+// dummy interface.
+[
+  object,
+  uuid(A91B50B2-48B3-40b1-86A3-0FE0AF3AB5BF),
+]
+interface INotUsedInterface : IUnknown {
+  HRESULT NotUsedFunction([in] BSTR not_used);
+};
+
+
+[
+  uuid(B137D75E-D05F-4146-AD27-C106D89FB4F4),
+  version(1.0)
+]
+library BhoDllLib {
+  [
+    uuid(%s)
+  ]
+  coclass BhoEntrypointClass {
+    [default] interface IObjectWithSite;
+  };
+}
+
diff --git a/bho/bho_dll.rc b/bho/bho_dll.rc
index 42cf282..5542498 100644
--- a/bho/bho_dll.rc
+++ b/bho/bho_dll.rc
@@ -1,23 +1,23 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// BHO resource file.

-

-#include "omaha/bho/resource.h"

-

-#include "goopdate/goopdate_version.rc"

-

-IDR_BHO_ENTRY  REGISTRY  "bho_dll.rgs"

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// BHO resource file.
+
+#include "omaha/bho/resource.h"
+
+#include "goopdate/goopdate_version.rc"
+
+IDR_BHO_ENTRY  REGISTRY  "bho_dll.rgs"
+
diff --git a/bho/bho_dll.rgs b/bho/bho_dll.rgs
index 3f72415..1fe543e 100644
--- a/bho/bho_dll.rgs
+++ b/bho/bho_dll.rgs
@@ -1,28 +1,28 @@
-HKCR {

-  NoRemove CLSID {

-    ForceRemove '%CLSID%' = s '%PRODUCT% Helper' {

-      InprocServer32 = s '%MODULE%' {

-        val ThreadingModel = s 'Apartment'

-      }

-    }

-  }

-}

-

-HKLM {

-  NoRemove SOFTWARE {

-    NoRemove Microsoft {

-      NoRemove Windows {

-        NoRemove CurrentVersion {

-          NoRemove Explorer {

-            NoRemove 'Browser Helper Objects' {

-              ForceRemove '%CLSID%' = s '%PRODUCT% Helper' {

-                val 'NoExplorer' = d '1'

-              }

-            }

-          }

-        }

-      }

-    }

-  }

-}

-

+HKCR {
+  NoRemove CLSID {
+    ForceRemove '%CLSID%' = s '%PRODUCT% Helper' {
+      InprocServer32 = s '%MODULE%' {
+        val ThreadingModel = s 'Apartment'
+      }
+    }
+  }
+}
+
+HKLM {
+  NoRemove SOFTWARE {
+    NoRemove Microsoft {
+      NoRemove Windows {
+        NoRemove CurrentVersion {
+          NoRemove Explorer {
+            NoRemove 'Browser Helper Objects' {
+              ForceRemove '%CLSID%' = s '%PRODUCT% Helper' {
+                val 'NoExplorer' = d '1'
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
diff --git a/bho/bho_entrypoint.cc b/bho/bho_entrypoint.cc
index dbda0f5..2b96178 100644
--- a/bho/bho_entrypoint.cc
+++ b/bho/bho_entrypoint.cc
@@ -1,49 +1,49 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// The main BHO COM object that IE instantiates. See the .h file for detailed

-// description.

-

-#include "omaha/bho/bho_entrypoint.h"

-#include "omaha/bho/browser_http_request.h"

-

-namespace omaha {

-

-BhoEntrypoint::BhoEntrypoint() {

-  CORE_LOG(L2, (_T("[BhoEntrypoint::BhoEntrypoint]")));

-}

-

-BhoEntrypoint::~BhoEntrypoint() {

-  CORE_LOG(L2, (_T("[BhoEntrypoint::~BhoEntrypoint]")));

-}

-

-STDMETHODIMP BhoEntrypoint::SetSite(IUnknown* site) {

-  CORE_LOG(L2, (_T("[BhoEntrypoint::SetSite]")));

-  HRESULT hr = IObjectWithSiteImpl<BhoEntrypoint>::SetSite(site);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[IObjectWithSiteImpl::SetSite failed][0x%x]"), hr));

-    return hr;

-  }

-

-  if (site) {

-    return BrowserHttpRequest::Init();

-  }

-

-  return hr;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// The main BHO COM object that IE instantiates. See the .h file for detailed
+// description.
+
+#include "omaha/bho/bho_entrypoint.h"
+#include "omaha/bho/browser_http_request.h"
+
+namespace omaha {
+
+BhoEntrypoint::BhoEntrypoint() {
+  CORE_LOG(L2, (_T("[BhoEntrypoint::BhoEntrypoint]")));
+}
+
+BhoEntrypoint::~BhoEntrypoint() {
+  CORE_LOG(L2, (_T("[BhoEntrypoint::~BhoEntrypoint]")));
+}
+
+STDMETHODIMP BhoEntrypoint::SetSite(IUnknown* site) {
+  CORE_LOG(L2, (_T("[BhoEntrypoint::SetSite]")));
+  HRESULT hr = IObjectWithSiteImpl<BhoEntrypoint>::SetSite(site);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[IObjectWithSiteImpl::SetSite failed][0x%x]"), hr));
+    return hr;
+  }
+
+  if (site) {
+    return BrowserHttpRequest::Init();
+  }
+
+  return hr;
+}
+
+}  // namespace omaha
+
diff --git a/bho/bho_entrypoint.h b/bho/bho_entrypoint.h
index 8f3559f..8a2f16f 100644
--- a/bho/bho_entrypoint.h
+++ b/bho/bho_entrypoint.h
@@ -1,68 +1,68 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// The main BHO COM object that IE instantiates. Creates a thread for

-// registering itself with GoogleUpdate.exe. Does http requests on

-// GoogleUpdate.exe's behalf.

-

-#ifndef OMAHA_BHO_BHO_ENTRYPOINT_H__

-#define OMAHA_BHO_BHO_ENTRYPOINT_H__

-

-#include <atlbase.h>

-#include <atlcom.h>

-#include <atlctl.h>

-#include "bho/bho_dll.h"

-#include "omaha/bho/resource.h"

-#include "omaha/common/ATLRegMapEx.h"

-#include "omaha/common/const_config.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-

-namespace omaha {

-

-class ATL_NO_VTABLE BhoEntrypoint

-  : public CComObjectRootEx<CComObjectThreadModel>,

-    public CComCoClass<BhoEntrypoint, &__uuidof(BhoEntrypointClass)>,

-    public IObjectWithSiteImpl<BhoEntrypoint> {

- public:

-

-  DECLARE_REGISTRY_RESOURCEID_EX(IDR_BHO_ENTRY)

-  DECLARE_NOT_AGGREGATABLE(BhoEntrypoint)

-  DECLARE_PROTECT_FINAL_CONSTRUCT()

-

-  #pragma warning(push)

-  // C4640: construction of local static object is not thread-safe

-  #pragma warning(disable : 4640)

-  BEGIN_REGISTRY_MAP()

-    REGMAP_ENTRY(_T("PRODUCT"),           kCiProgram)

-    REGMAP_ENTRY(_T("CLSID"),             __uuidof(BhoEntrypointClass))

-  END_REGISTRY_MAP()

-  #pragma warning(pop)

-

-  BEGIN_COM_MAP(BhoEntrypoint)

-    COM_INTERFACE_ENTRY(IObjectWithSite)

-  END_COM_MAP()

-

-  BhoEntrypoint();

-  virtual ~BhoEntrypoint();

-

-  STDMETHODIMP SetSite(IUnknown* site);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_BHO_BHO_ENTRYPOINT_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// The main BHO COM object that IE instantiates. Creates a thread for
+// registering itself with GoogleUpdate.exe. Does http requests on
+// GoogleUpdate.exe's behalf.
+
+#ifndef OMAHA_BHO_BHO_ENTRYPOINT_H__
+#define OMAHA_BHO_BHO_ENTRYPOINT_H__
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlctl.h>
+#include "bho/bho_dll.h"
+#include "omaha/bho/resource.h"
+#include "omaha/common/ATLRegMapEx.h"
+#include "omaha/common/const_config.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+
+namespace omaha {
+
+class ATL_NO_VTABLE BhoEntrypoint
+  : public CComObjectRootEx<CComObjectThreadModel>,
+    public CComCoClass<BhoEntrypoint, &__uuidof(BhoEntrypointClass)>,
+    public IObjectWithSiteImpl<BhoEntrypoint> {
+ public:
+
+  DECLARE_REGISTRY_RESOURCEID_EX(IDR_BHO_ENTRY)
+  DECLARE_NOT_AGGREGATABLE(BhoEntrypoint)
+  DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+  #pragma warning(push)
+  // C4640: construction of local static object is not thread-safe
+  #pragma warning(disable : 4640)
+  BEGIN_REGISTRY_MAP()
+    REGMAP_ENTRY(_T("PRODUCT"),           kCiProgram)
+    REGMAP_ENTRY(_T("CLSID"),             __uuidof(BhoEntrypointClass))
+  END_REGISTRY_MAP()
+  #pragma warning(pop)
+
+  BEGIN_COM_MAP(BhoEntrypoint)
+    COM_INTERFACE_ENTRY(IObjectWithSite)
+  END_COM_MAP()
+
+  BhoEntrypoint();
+  virtual ~BhoEntrypoint();
+
+  STDMETHODIMP SetSite(IUnknown* site);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_BHO_BHO_ENTRYPOINT_H__
+
diff --git a/bho/browser_http_request.cc b/bho/browser_http_request.cc
index 577c61e..8c96c4d 100644
--- a/bho/browser_http_request.cc
+++ b/bho/browser_http_request.cc
@@ -1,153 +1,153 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Browser Http Request class. Created by BhoEntrypoint. Creates a thread that

-// registers with GoogleUpdate.exe, and waits for calls into the Send() method.

-

-#include "omaha/bho/browser_http_request.h"

-#include <atlsecurity.h>

-#include <atlstr.h>

-#include "omaha/common/error.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/net/bind_status_callback.h"

-

-namespace omaha {

-

-CComPtr<IBrowserHttpRequest2> BrowserHttpRequest::instance_;

-LLock BrowserHttpRequest::lock_;

-scoped_thread BrowserHttpRequest::request_thread_;

-SharedBrowserRequestObj* BrowserHttpRequest::shared_obj_ = NULL;

-

-// Use Urlmon to download.

-STDMETHODIMP BrowserHttpRequest::Send(BSTR url,

-                                      BSTR post_data,

-                                      BSTR request_headers,

-                                      VARIANT response_headers_needed,

-                                      VARIANT* response_headers,

-                                      DWORD* response_code,

-                                      BSTR* cache_filename) {

-  CORE_LOG(L2, (_T("[BrowserHttpRequest::Send][url \"%s\"]"), url));

-  return BindStatusCallback::CreateAndSend(url,

-                                           post_data,

-                                           request_headers,

-                                           response_headers_needed,

-                                           response_headers,

-                                           response_code,

-                                           cache_filename);

-}

-

-// Creates and register static instance of the BrowserHttpRequest, if it does

-// not exist.

-HRESULT BrowserHttpRequest::Init() {

-  CORE_LOG(L2, (_T("[BrowserHttpRequest::Register]")));

-

-  __mutexBlock(lock_) {

-    if (!request_thread_) {

-      // Start thread that accepts incoming COM requests from GoogleUpdate.

-      DWORD thread_id = 0;

-      reset(request_thread_,

-            ::CreateThread(NULL, 0, ProxyThreadProc, NULL, 0, &thread_id));

-      if (!request_thread_) {

-        HRESULT hr = HRESULTFromLastError();

-        CORE_LOG(LE, (_T("::CreateThread failed 0x%x"), hr));

-        return hr;

-      }

-      CORE_LOG(L2, (_T("[Init][request_thread_ id=%d]"), thread_id));

-    }

-  }

-

-  return S_OK;

-}

-

-DWORD WINAPI BrowserHttpRequest::ProxyThreadProc(LPVOID /* parameter */) {

-  CORE_LOG(L2, (_T("[BrowserHttpRequest::ProxyThreadProc]")));

-

-  scoped_co_init init_com_apt;

-  ASSERT1(SUCCEEDED(init_com_apt.hresult()));

-

-  if (FAILED(init_com_apt.hresult()) || FAILED(CreateAndRegister())) {

-    __mutexBlock(lock_) {

-      // Try to recreate the request thread later.

-      reset(request_thread_);

-    }

-    return 1;

-  }

-

-  // Message Loop

-  MSG msg = {0};

-  while (::GetMessage(&msg, NULL, 0, 0)) {

-    if (WM_QUIT == msg.message)

-      break;

-    ::TranslateMessage(&msg);

-    ::DispatchMessage(&msg);

-  }

-

-  // Since nobody posts a WM_QUIT message for this thread, shared_obj_ is

-  // leaked. This is ok, because the DLL is not unloaded until the process

-  // terminates, since we pin it. At that point, not releasing the shared_obj_

-  // is inconsequential. The OS will release the file mapping associated with

-  // the shared memory.

-  return 0;

-}

-

-HRESULT BrowserHttpRequest::CreateAndRegister() {

-  CORE_LOG(L2, (_T("[BrowserHttpRequest::CreateAndRegister]")));

-  if (instance_ != NULL) {

-    // Already exists. Exit early.

-    return S_OK;

-  }

-

-  CComObject<BrowserHttpRequest>* http_request = NULL;

-  HRESULT hr = CComObject<BrowserHttpRequest>::CreateInstance(&http_request);

-  CORE_LOG(L2, (_T("[BrowserHttpRequest CreateInstance returned 0x%x]"), hr));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  instance_ = http_request;

-  hr = RegisterInSharedMemory(instance_);

-  CORE_LOG(L2, (_T("[RegisterInSharedMemory returned 0x%x]"), hr));

-  if (FAILED(hr)) {

-    instance_ = NULL;

-  }

-

-  return hr;

-}

-

-// Insert the IBrowserHttpRequest2 interface into shared memory.

-HRESULT BrowserHttpRequest::RegisterInSharedMemory(

-            IBrowserHttpRequest2* http_request) {

-  ASSERT1(http_request);

-

-  // There is one browser helper per browser process. Each helper registers

-  // itself into a separate shared memory suffixed with the PID of the process.

-  // This is to keep the registration of each object distinct.

-  // For example,"Local\\IBrowserRequest2_2229".

-  // * GoogleUpdate.exe running as SYSTEM will choose the browser helper objects

-  // registered and running in the currently active session.

-  // * GoogleUpdate.exe running as the  user, either elevated or not, will

-  // choose browser helpers registered in the same session and running as that

-  // user.

-  CString shared_memory_name(_T("Local\\"));

-  shared_memory_name.AppendFormat(_T("%s%d"),

-                                  omaha::kBrowserHttpRequestShareName,

-                                  ::GetCurrentProcessId());

-  omaha::SharedMemoryAttributes attr(shared_memory_name, CSecurityDesc());

-  shared_obj_ = new SharedBrowserRequestObj(false, &attr);

-  ASSERT1(shared_obj_ != NULL);

-  return shared_obj_->RegisterObject(http_request);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Browser Http Request class. Created by BhoEntrypoint. Creates a thread that
+// registers with GoogleUpdate.exe, and waits for calls into the Send() method.
+
+#include "omaha/bho/browser_http_request.h"
+#include <atlsecurity.h>
+#include <atlstr.h>
+#include "omaha/common/error.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/net/bind_status_callback.h"
+
+namespace omaha {
+
+CComPtr<IBrowserHttpRequest2> BrowserHttpRequest::instance_;
+LLock BrowserHttpRequest::lock_;
+scoped_thread BrowserHttpRequest::request_thread_;
+SharedBrowserRequestObj* BrowserHttpRequest::shared_obj_ = NULL;
+
+// Use Urlmon to download.
+STDMETHODIMP BrowserHttpRequest::Send(BSTR url,
+                                      BSTR post_data,
+                                      BSTR request_headers,
+                                      VARIANT response_headers_needed,
+                                      VARIANT* response_headers,
+                                      DWORD* response_code,
+                                      BSTR* cache_filename) {
+  CORE_LOG(L2, (_T("[BrowserHttpRequest::Send][url \"%s\"]"), url));
+  return BindStatusCallback::CreateAndSend(url,
+                                           post_data,
+                                           request_headers,
+                                           response_headers_needed,
+                                           response_headers,
+                                           response_code,
+                                           cache_filename);
+}
+
+// Creates and register static instance of the BrowserHttpRequest, if it does
+// not exist.
+HRESULT BrowserHttpRequest::Init() {
+  CORE_LOG(L2, (_T("[BrowserHttpRequest::Register]")));
+
+  __mutexBlock(lock_) {
+    if (!request_thread_) {
+      // Start thread that accepts incoming COM requests from GoogleUpdate.
+      DWORD thread_id = 0;
+      reset(request_thread_,
+            ::CreateThread(NULL, 0, ProxyThreadProc, NULL, 0, &thread_id));
+      if (!request_thread_) {
+        HRESULT hr = HRESULTFromLastError();
+        CORE_LOG(LE, (_T("::CreateThread failed 0x%x"), hr));
+        return hr;
+      }
+      CORE_LOG(L2, (_T("[Init][request_thread_ id=%d]"), thread_id));
+    }
+  }
+
+  return S_OK;
+}
+
+DWORD WINAPI BrowserHttpRequest::ProxyThreadProc(LPVOID /* parameter */) {
+  CORE_LOG(L2, (_T("[BrowserHttpRequest::ProxyThreadProc]")));
+
+  scoped_co_init init_com_apt;
+  ASSERT1(SUCCEEDED(init_com_apt.hresult()));
+
+  if (FAILED(init_com_apt.hresult()) || FAILED(CreateAndRegister())) {
+    __mutexBlock(lock_) {
+      // Try to recreate the request thread later.
+      reset(request_thread_);
+    }
+    return 1;
+  }
+
+  // Message Loop
+  MSG msg = {0};
+  while (::GetMessage(&msg, NULL, 0, 0)) {
+    if (WM_QUIT == msg.message)
+      break;
+    ::TranslateMessage(&msg);
+    ::DispatchMessage(&msg);
+  }
+
+  // Since nobody posts a WM_QUIT message for this thread, shared_obj_ is
+  // leaked. This is ok, because the DLL is not unloaded until the process
+  // terminates, since we pin it. At that point, not releasing the shared_obj_
+  // is inconsequential. The OS will release the file mapping associated with
+  // the shared memory.
+  return 0;
+}
+
+HRESULT BrowserHttpRequest::CreateAndRegister() {
+  CORE_LOG(L2, (_T("[BrowserHttpRequest::CreateAndRegister]")));
+  if (instance_ != NULL) {
+    // Already exists. Exit early.
+    return S_OK;
+  }
+
+  CComObject<BrowserHttpRequest>* http_request = NULL;
+  HRESULT hr = CComObject<BrowserHttpRequest>::CreateInstance(&http_request);
+  CORE_LOG(L2, (_T("[BrowserHttpRequest CreateInstance returned 0x%x]"), hr));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  instance_ = http_request;
+  hr = RegisterInSharedMemory(instance_);
+  CORE_LOG(L2, (_T("[RegisterInSharedMemory returned 0x%x]"), hr));
+  if (FAILED(hr)) {
+    instance_ = NULL;
+  }
+
+  return hr;
+}
+
+// Insert the IBrowserHttpRequest2 interface into shared memory.
+HRESULT BrowserHttpRequest::RegisterInSharedMemory(
+            IBrowserHttpRequest2* http_request) {
+  ASSERT1(http_request);
+
+  // There is one browser helper per browser process. Each helper registers
+  // itself into a separate shared memory suffixed with the PID of the process.
+  // This is to keep the registration of each object distinct.
+  // For example,"Local\\IBrowserRequest2_2229".
+  // * GoogleUpdate.exe running as SYSTEM will choose the browser helper objects
+  // registered and running in the currently active session.
+  // * GoogleUpdate.exe running as the  user, either elevated or not, will
+  // choose browser helpers registered in the same session and running as that
+  // user.
+  CString shared_memory_name(_T("Local\\"));
+  shared_memory_name.AppendFormat(_T("%s%d"),
+                                  omaha::kBrowserHttpRequestShareName,
+                                  ::GetCurrentProcessId());
+  omaha::SharedMemoryAttributes attr(shared_memory_name, CSecurityDesc());
+  shared_obj_ = new SharedBrowserRequestObj(false, &attr);
+  ASSERT1(shared_obj_ != NULL);
+  return shared_obj_->RegisterObject(http_request);
+}
+
+}  // namespace omaha
diff --git a/bho/browser_http_request.h b/bho/browser_http_request.h
index f05de06..4a73b63 100644
--- a/bho/browser_http_request.h
+++ b/bho/browser_http_request.h
@@ -1,79 +1,79 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Browser Http Request class. Created by BhoEntrypoint. Creates a thread that

-// registers with GoogleUpdate.exe, and waits for calls into the Send() method.

-

-#ifndef OMAHA_BHO_BROWSER_HTTP_REQUEST_H__

-#define OMAHA_BHO_BROWSER_HTTP_REQUEST_H__

-

-#include <atlbase.h>

-#include <atlcom.h>

-#include <atlctl.h>

-#include "base/scoped_ptr.h"

-#include "goopdate/google_update_idl.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/google_update_proxy.h"

-

-namespace omaha {

-

-typedef omaha::SharedMemoryProxy<IBrowserHttpRequest2,

-                                 FakeGLock> SharedBrowserRequestObj;

-

-class ATL_NO_VTABLE BrowserHttpRequest

-  : public CComObjectRootEx<CComObjectThreadModel>,

-    public IBrowserHttpRequest2 {

- public:

-  BrowserHttpRequest() {}

-  virtual ~BrowserHttpRequest() {

-    CORE_LOG(L2, (_T("[BrowserHttpRequest::~BrowserHttpRequest]")));

-  }

-

-  BEGIN_COM_MAP(BrowserHttpRequest)

-    COM_INTERFACE_ENTRY(IBrowserHttpRequest2)

-  END_COM_MAP()

-

-  DECLARE_PROTECT_FINAL_CONSTRUCT()

-

-  STDMETHOD(Send)(BSTR url,

-                  BSTR post_data,

-                  BSTR request_headers,

-                  VARIANT response_headers_needed,

-                  VARIANT* response_headers,

-                  DWORD* response_code,

-                  BSTR* cache_filename);

-

-  static HRESULT Init();

-

- private:

-  static DWORD WINAPI ProxyThreadProc(void* parameter);

-  static HRESULT CreateAndRegister();

-  static HRESULT RegisterInSharedMemory(IBrowserHttpRequest2* http_request);

-

-  static CComPtr<IBrowserHttpRequest2> instance_;

-  static LLock lock_;

-  static scoped_thread request_thread_;

-

-  // The browser http request shared with other processes.

-  static SharedBrowserRequestObj* shared_obj_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_BHO_BROWSER_HTTP_REQUEST_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Browser Http Request class. Created by BhoEntrypoint. Creates a thread that
+// registers with GoogleUpdate.exe, and waits for calls into the Send() method.
+
+#ifndef OMAHA_BHO_BROWSER_HTTP_REQUEST_H__
+#define OMAHA_BHO_BROWSER_HTTP_REQUEST_H__
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlctl.h>
+#include "base/scoped_ptr.h"
+#include "goopdate/google_update_idl.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/google_update_proxy.h"
+
+namespace omaha {
+
+typedef omaha::SharedMemoryProxy<IBrowserHttpRequest2,
+                                 FakeGLock> SharedBrowserRequestObj;
+
+class ATL_NO_VTABLE BrowserHttpRequest
+  : public CComObjectRootEx<CComObjectThreadModel>,
+    public IBrowserHttpRequest2 {
+ public:
+  BrowserHttpRequest() {}
+  virtual ~BrowserHttpRequest() {
+    CORE_LOG(L2, (_T("[BrowserHttpRequest::~BrowserHttpRequest]")));
+  }
+
+  BEGIN_COM_MAP(BrowserHttpRequest)
+    COM_INTERFACE_ENTRY(IBrowserHttpRequest2)
+  END_COM_MAP()
+
+  DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+  STDMETHOD(Send)(BSTR url,
+                  BSTR post_data,
+                  BSTR request_headers,
+                  VARIANT response_headers_needed,
+                  VARIANT* response_headers,
+                  DWORD* response_code,
+                  BSTR* cache_filename);
+
+  static HRESULT Init();
+
+ private:
+  static DWORD WINAPI ProxyThreadProc(void* parameter);
+  static HRESULT CreateAndRegister();
+  static HRESULT RegisterInSharedMemory(IBrowserHttpRequest2* http_request);
+
+  static CComPtr<IBrowserHttpRequest2> instance_;
+  static LLock lock_;
+  static scoped_thread request_thread_;
+
+  // The browser http request shared with other processes.
+  static SharedBrowserRequestObj* shared_obj_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_BHO_BROWSER_HTTP_REQUEST_H__
+
diff --git a/bho/build.scons b/bho/build.scons
index 4cf10ce..65ef1b8 100644
--- a/bho/build.scons
+++ b/bho/build.scons
@@ -1,202 +1,202 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-_first = True

-for v in env['product_version']:

-  temp_env = env.Clone(COMPONENT_STATIC=False)

-

-  if _first:

-    _first = False

-    prefix = ''

-  else:

-    prefix = 'TEST_'

-    temp_env['OBJPREFIX'] = temp_env['OBJPREFIX'] + 'test/'

-

-  temp_env.Append(

-      CPPPATH = [

-          '$OBJ_ROOT',    # Needed for generated files.

-          ],

-      CPPDEFINES = [

-          '_ATL_APARTMENT_THREADED',

-          ],

-      LIBS = [

-          '$LIB_DIR/bho_dll.lib',

-          '$LIB_DIR/bho_dll_no_pch.lib',

-          '$LIB_DIR/breakpad.lib',

-          '$LIB_DIR/common.lib',

-          '$LIB_DIR/google_update_recovery.lib',

-          '$LIB_DIR/goopdate_dll.lib',

-          '$LIB_DIR/logging.lib',

-          '$LIB_DIR/net.lib',

-          '$LIB_DIR/repair_goopdate.lib',

-          '$LIB_DIR/statsreport.lib',

-          ('atls.lib', 'atlsd.lib')[temp_env.Bit('debug')],

-          ('libcmt.lib', 'libcmtd.lib')[temp_env.Bit('debug')],

-          ('libcpmt.lib', 'libcpmtd.lib')[temp_env.Bit('debug')],

-          'comctl32.lib',

-          'crypt32.lib',

-          'delayimp.lib',

-          'Iphlpapi.lib',

-          'msi.lib',

-          'Mstask.lib',

-          'Netapi32.lib',

-          'psapi.lib',

-          'rasapi32.lib',

-          'rpcrt4.lib',

-          'shlwapi.lib',

-          'Version.lib',

-          'userenv.lib',

-          'wininet.lib',

-          'urlmon.lib',

-          'Wintrust.lib',

-          'WtsApi32.lib',

-          ],

-      LINKFLAGS = [

-          '/DELAYLOAD:ole32.dll',

-          '/DELAYLOAD:oleaut32.dll',

-          '/DELAYLOAD:psapi.dll',

-          '/DELAYLOAD:shell32.dll',

-          '/DELAYLOAD:shlwapi.dll',

-          '/DELAYLOAD:userenv.dll',

-          '/DELAYLOAD:version.dll',

-          ],

-      RCFLAGS = [

-          '/DVERSION_MAJOR=%d' % v[0],

-          '/DVERSION_MINOR=%d' % v[1],

-          '/DVERSION_BUILD=%d' % v[2],

-          '/DVERSION_PATCH=%d' % v[3],

-          '/DVERSION_NUMBER_STRING=\\"%d.%d.%d.%d\\"' % (v[0],v[1],v[2],v[3]),

-          ],

-  )

-

-  bho_res = temp_env.RES(

-      target=prefix+'bho_dll.res',

-      source='bho_dll.rc'

-  )

-

-  # Force a rebuild when the version changes.

-  temp_env.Depends(bho_res, '$MAIN_DIR/VERSION')

-

-  target_name = prefix + temp_env['BHO_UNSIGNED_FILENAME']

-

-  temp_inputs = [

-      'bho_dll.cc',

-      'bho_dll.def',

-      bho_res,

-      ]

-  if env.Bit('use_precompiled_headers'):

-    temp_inputs += temp_env.EnablePrecompile(target_name)

-

-  unsigned_dll = temp_env.ComponentLibrary(

-      lib_name=target_name,

-      source=temp_inputs,

-  )

-

-  signed_dll = temp_env.SignedBinary(

-      target=prefix + temp_env['BHO_FILENAME'],

-      source=unsigned_dll,

-  )

-

-  env.Replicate('$STAGING_DIR', signed_dll)

-  env.Replicate('$STAGING_DIR', [f for f in unsigned_dll if f.suffix == '.pdb'])

-

-#

-# Build a new idl from the template *before* building the type library itself.

-#

-env.Command(

-    target='bho_dll.idl',

-    # Need to specify a path for the input, or Hammer gets confused by

-    # the identical file names.

-    source='$MAIN_DIR/bho/bho_dll.idl',

-    action=('@python %s/plugins/generate_oneclick_idl.py --idl_template_file'

-        ' $SOURCE --idl_output_file $TARGET' % (env.Dir('$MAIN_DIR').abspath))

-)

-

-

-#

-# Generate the type library

-#

-midl_env = env.Clone()

-

-midl_env.Tool('midl')

-

-midl_env.Append(

-  MIDLFLAGS = [

-    '/Oicf',  # Generate optimized stubless proxy/stub code.

-    ],

-)

-

-# Create the type library.

-midl_output = midl_env.TypeLibrary(source='$OBJ_ROOT/bho/bho_dll.idl')

-

-

-#

-# Build bho_dll_no_pch.lib

-# Need to generate the GUIDs with no precompile, otherwise we get an error.

-#

-env_no_precomp = env.Clone()

-

-env_no_precomp.Append(

-    CCFLAGS = [

-        '/wd4255',  # no function prototype given: converting '()' to '(void)'

-        ],

-)

-

-env_no_precomp.ComponentLibrary(

-    lib_name='bho_dll_no_pch.lib',

-    source=[

-        '$OBJ_ROOT/bho/bho_dll_i.c',

-        '$OBJ_ROOT/bho/bho_dll_p.c',

-        ]

-)

-

-

-#

-# Build bho_dll.lib.

-#

-env_main = env.Clone()

-

-env_main.Append(

-    CPPPATH = [

-        '$OBJ_ROOT',

-        ],

-    CPPDEFINES = [

-        '_ATL_APARTMENT_THREADED',

-        ],

-)

-

-target_name = 'bho_dll.lib'

-

-# Set up inputs. Note one of the inputs is a file generated by the midl

-# compiler in the previous step.

-env_main_inputs = [

-    'bho_entrypoint.cc',

-    'browser_http_request.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  env_main_inputs += env_main.EnablePrecompile(target_name)

-

-main_output = env_main.ComponentLibrary(

-    lib_name=target_name,

-    source=env_main_inputs

-)

-

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+_first = True
+for v in env['product_version']:
+  temp_env = env.Clone(COMPONENT_STATIC=False)
+
+  if _first:
+    _first = False
+    prefix = ''
+  else:
+    prefix = 'TEST_'
+    temp_env['OBJPREFIX'] = temp_env['OBJPREFIX'] + 'test/'
+
+  temp_env.Append(
+      CPPPATH = [
+          '$OBJ_ROOT',    # Needed for generated files.
+          ],
+      CPPDEFINES = [
+          '_ATL_APARTMENT_THREADED',
+          ],
+      LIBS = [
+          '$LIB_DIR/bho_dll.lib',
+          '$LIB_DIR/bho_dll_no_pch.lib',
+          '$LIB_DIR/breakpad.lib',
+          '$LIB_DIR/common.lib',
+          '$LIB_DIR/google_update_recovery.lib',
+          '$LIB_DIR/goopdate_dll.lib',
+          '$LIB_DIR/logging.lib',
+          '$LIB_DIR/net.lib',
+          '$LIB_DIR/repair_goopdate.lib',
+          '$LIB_DIR/statsreport.lib',
+          ('atls.lib', 'atlsd.lib')[temp_env.Bit('debug')],
+          ('libcmt.lib', 'libcmtd.lib')[temp_env.Bit('debug')],
+          ('libcpmt.lib', 'libcpmtd.lib')[temp_env.Bit('debug')],
+          'comctl32.lib',
+          'crypt32.lib',
+          'delayimp.lib',
+          'Iphlpapi.lib',
+          'msi.lib',
+          'Mstask.lib',
+          'Netapi32.lib',
+          'psapi.lib',
+          'rasapi32.lib',
+          'rpcrt4.lib',
+          'shlwapi.lib',
+          'Version.lib',
+          'userenv.lib',
+          'wininet.lib',
+          'urlmon.lib',
+          'Wintrust.lib',
+          'WtsApi32.lib',
+          ],
+      LINKFLAGS = [
+          '/DELAYLOAD:ole32.dll',
+          '/DELAYLOAD:oleaut32.dll',
+          '/DELAYLOAD:psapi.dll',
+          '/DELAYLOAD:shell32.dll',
+          '/DELAYLOAD:shlwapi.dll',
+          '/DELAYLOAD:userenv.dll',
+          '/DELAYLOAD:version.dll',
+          ],
+      RCFLAGS = [
+          '/DVERSION_MAJOR=%d' % v[0],
+          '/DVERSION_MINOR=%d' % v[1],
+          '/DVERSION_BUILD=%d' % v[2],
+          '/DVERSION_PATCH=%d' % v[3],
+          '/DVERSION_NUMBER_STRING=\\"%d.%d.%d.%d\\"' % (v[0],v[1],v[2],v[3]),
+          ],
+  )
+
+  bho_res = temp_env.RES(
+      target=prefix+'bho_dll.res',
+      source='bho_dll.rc'
+  )
+
+  # Force a rebuild when the version changes.
+  temp_env.Depends(bho_res, '$MAIN_DIR/VERSION')
+
+  target_name = prefix + temp_env['BHO_UNSIGNED_FILENAME']
+
+  temp_inputs = [
+      'bho_dll.cc',
+      'bho_dll.def',
+      bho_res,
+      ]
+  if env.Bit('use_precompiled_headers'):
+    temp_inputs += temp_env.EnablePrecompile(target_name)
+
+  unsigned_dll = temp_env.ComponentLibrary(
+      lib_name=target_name,
+      source=temp_inputs,
+  )
+
+  signed_dll = temp_env.SignedBinary(
+      target=prefix + temp_env['BHO_FILENAME'],
+      source=unsigned_dll,
+  )
+
+  env.Replicate('$STAGING_DIR', signed_dll)
+  env.Replicate('$STAGING_DIR', [f for f in unsigned_dll if f.suffix == '.pdb'])
+
+#
+# Build a new idl from the template *before* building the type library itself.
+#
+env.Command(
+    target='bho_dll.idl',
+    # Need to specify a path for the input, or Hammer gets confused by
+    # the identical file names.
+    source='$MAIN_DIR/bho/bho_dll.idl',
+    action=('@python %s/plugins/generate_oneclick_idl.py --idl_template_file'
+        ' $SOURCE --idl_output_file $TARGET' % (env.Dir('$MAIN_DIR').abspath))
+)
+
+
+#
+# Generate the type library
+#
+midl_env = env.Clone()
+
+midl_env.Tool('midl')
+
+midl_env.Append(
+  MIDLFLAGS = [
+    '/Oicf',  # Generate optimized stubless proxy/stub code.
+    ],
+)
+
+# Create the type library.
+midl_output = midl_env.TypeLibrary(source='$OBJ_ROOT/bho/bho_dll.idl')
+
+
+#
+# Build bho_dll_no_pch.lib
+# Need to generate the GUIDs with no precompile, otherwise we get an error.
+#
+env_no_precomp = env.Clone()
+
+env_no_precomp.Append(
+    CCFLAGS = [
+        '/wd4255',  # no function prototype given: converting '()' to '(void)'
+        ],
+)
+
+env_no_precomp.ComponentLibrary(
+    lib_name='bho_dll_no_pch.lib',
+    source=[
+        '$OBJ_ROOT/bho/bho_dll_i.c',
+        '$OBJ_ROOT/bho/bho_dll_p.c',
+        ]
+)
+
+
+#
+# Build bho_dll.lib.
+#
+env_main = env.Clone()
+
+env_main.Append(
+    CPPPATH = [
+        '$OBJ_ROOT',
+        ],
+    CPPDEFINES = [
+        '_ATL_APARTMENT_THREADED',
+        ],
+)
+
+target_name = 'bho_dll.lib'
+
+# Set up inputs. Note one of the inputs is a file generated by the midl
+# compiler in the previous step.
+env_main_inputs = [
+    'bho_entrypoint.cc',
+    'browser_http_request.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  env_main_inputs += env_main.EnablePrecompile(target_name)
+
+main_output = env_main.ComponentLibrary(
+    lib_name=target_name,
+    source=env_main_inputs
+)
+
+
diff --git a/bho/resource.h b/bho/resource.h
index 5a855b1..d28a52d 100644
--- a/bho/resource.h
+++ b/bho/resource.h
@@ -1,25 +1,25 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// symbol definitions for the BHO DLL resources

-

-#ifndef OMAHA_BHO_RESOURCE_H__

-#define OMAHA_BHO_RESOURCE_H__

-

-// The id of the ATL COM registration script

-#define IDR_BHO_ENTRY                       100

-

-#endif  // OMAHA_BHO_RESOURCE_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// symbol definitions for the BHO DLL resources
+
+#ifndef OMAHA_BHO_RESOURCE_H__
+#define OMAHA_BHO_RESOURCE_H__
+
+// The id of the ATL COM registration script
+#define IDR_BHO_ENTRY                       100
+
+#endif  // OMAHA_BHO_RESOURCE_H__
+
diff --git a/build.scons b/build.scons
index 94848b4..b182e7a 100644
--- a/build.scons
+++ b/build.scons
@@ -1,30 +1,30 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-# Copy useful test files to the build output.

-files = [

-    '$MAIN_DIR/VERSION',

-    '$MAIN_DIR/data/GoogleUpdate.ini',

-    '$MAIN_DIR/data/make_dev_system.reg',

-    '$MAIN_DIR/data/make_qa_system.reg',

-    ]

-env.Replicate('$STAGING_DIR', files)

-

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+# Copy useful test files to the build output.
+files = [
+    '$MAIN_DIR/VERSION',
+    '$MAIN_DIR/data/GoogleUpdate.ini',
+    '$MAIN_DIR/data/make_dev_system.reg',
+    '$MAIN_DIR/data/make_qa_system.reg',
+    ]
+env.Replicate('$STAGING_DIR', files)
+
+
diff --git a/clickonce/add_trusturlparams.py b/clickonce/add_trusturlparams.py
index 872ec6c..18a7357 100644
--- a/clickonce/add_trusturlparams.py
+++ b/clickonce/add_trusturlparams.py
@@ -1,106 +1,106 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2008-2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-"""

-mage.exe does not provide a way to add the trustURLParameters attribute to an

-application manifest. This script fills that gap. It also adds in the

-localized display name, to get around issues with the Python commands

-module.

-"""

-

-import sys

-import os

-import getopt

-import commands

-

-

-def _AddTrustURLParametersAndName(manifest_file, output_file, display_name):

-  f_in = open(manifest_file, 'r')

-  manifest_contents = f_in.read()

-  f_in.close()

-

-  manifest_contents = manifest_contents.replace('<deployment ', \

-      '<deployment trustURLParameters="true" ')

-  manifest_contents = manifest_contents.replace('\"xxxXXXxxx', \

-      '\"%s' % display_name)

-

-  f_out = open(output_file, 'w')

-  # Works without needing to write the codecs.BOM_UTF8 at the beginning of the

-  # file. May need to write this at some point though.

-  f_out.write(manifest_contents)

-  f_out.close()

-

-

-def _Usage():

-  """Prints out script usage information."""

-  print """

-add_trusturlparams.py: Modify the given manifest file by adding in a

-trustURLParameters=true to the deployment section. Also substitutes

-the dummy name xxxXXXxxx with the localized display name.

-

-Usage:

-  add_trusturlparams.py [--help

-                         | --manifest_file filename

-                         | --output_file filename

-                           --display_name {i18n display name}]

-

-Options:

-  --help                    Show this information.

-  --manifest_file filename     Path/name of input/output manifest file.

-  --output_file filename       Path/name of an optional output manifest file.

-  --display_name  name         i18n display name.

-"""

-

-

-def _Main():

-  # use getopt to parse the option and argument list; this may raise, but

-  # don't catch it

-  _ARGUMENT_LIST = ["help", "manifest_file=", "output_file=", "display_name="]

-  (opts, args) = getopt.getopt(sys.argv[1:], "", _ARGUMENT_LIST)

-  if not opts or ("--help", "") in opts:

-    _Usage()

-    sys.exit()

-

-  manifest_file = ""

-  output_file = ""

-  display_name = ""

-

-  for (o, v) in opts:

-    if o == "--manifest_file":

-      manifest_file = v

-    if o == "--output_file":

-      output_file = v

-    if o == "--display_name":

-      display_name = v

-

-  # make sure we have work to do

-  if not manifest_file:

-    raise SystemExit("no manifest_filename specified")

-  if not display_name:

-    raise SystemExit("no display_name specified")

-

-  # overwrite existing file if no separate output specified

-  if not output_file:

-    output_file = manifest_file

-

-  _AddTrustURLParametersAndName(manifest_file, output_file, display_name)

-  sys.exit()

-

-

-if __name__ == "__main__":

-  _Main()

-

+#!/usr/bin/python2.4
+#
+# Copyright 2008-2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+"""
+mage.exe does not provide a way to add the trustURLParameters attribute to an
+application manifest. This script fills that gap. It also adds in the
+localized display name, to get around issues with the Python commands
+module.
+"""
+
+import sys
+import os
+import getopt
+import commands
+
+
+def _AddTrustURLParametersAndName(manifest_file, output_file, display_name):
+  f_in = open(manifest_file, 'r')
+  manifest_contents = f_in.read()
+  f_in.close()
+
+  manifest_contents = manifest_contents.replace('<deployment ', \
+      '<deployment trustURLParameters="true" ')
+  manifest_contents = manifest_contents.replace('\"xxxXXXxxx', \
+      '\"%s' % display_name)
+
+  f_out = open(output_file, 'w')
+  # Works without needing to write the codecs.BOM_UTF8 at the beginning of the
+  # file. May need to write this at some point though.
+  f_out.write(manifest_contents)
+  f_out.close()
+
+
+def _Usage():
+  """Prints out script usage information."""
+  print """
+add_trusturlparams.py: Modify the given manifest file by adding in a
+trustURLParameters=true to the deployment section. Also substitutes
+the dummy name xxxXXXxxx with the localized display name.
+
+Usage:
+  add_trusturlparams.py [--help
+                         | --manifest_file filename
+                         | --output_file filename
+                           --display_name {i18n display name}]
+
+Options:
+  --help                    Show this information.
+  --manifest_file filename     Path/name of input/output manifest file.
+  --output_file filename       Path/name of an optional output manifest file.
+  --display_name  name         i18n display name.
+"""
+
+
+def _Main():
+  # use getopt to parse the option and argument list; this may raise, but
+  # don't catch it
+  _ARGUMENT_LIST = ["help", "manifest_file=", "output_file=", "display_name="]
+  (opts, args) = getopt.getopt(sys.argv[1:], "", _ARGUMENT_LIST)
+  if not opts or ("--help", "") in opts:
+    _Usage()
+    sys.exit()
+
+  manifest_file = ""
+  output_file = ""
+  display_name = ""
+
+  for (o, v) in opts:
+    if o == "--manifest_file":
+      manifest_file = v
+    if o == "--output_file":
+      output_file = v
+    if o == "--display_name":
+      display_name = v
+
+  # make sure we have work to do
+  if not manifest_file:
+    raise SystemExit("no manifest_filename specified")
+  if not display_name:
+    raise SystemExit("no display_name specified")
+
+  # overwrite existing file if no separate output specified
+  if not output_file:
+    output_file = manifest_file
+
+  _AddTrustURLParametersAndName(manifest_file, output_file, display_name)
+  sys.exit()
+
+
+if __name__ == "__main__":
+  _Main()
+
diff --git a/clickonce/build.scons b/clickonce/build.scons
index 8b5087c..d28f46a 100644
--- a/clickonce/build.scons
+++ b/clickonce/build.scons
@@ -1,101 +1,101 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-# Note: The localized ClickOnce deployment manifest is generated in

-# installers/build.scons.

-

-

-Import('env')

-

-clickonce_name = 'clickonce_bootstrap'

-clickonce_binary = clickonce_name + '.exe'

-clickonce_res = clickonce_name + '.res'

-

-

-#

-# Build the .res file.

-#

-env.RES(target=clickonce_res, source='clickonce_bootstrap.rc')

-

-

-#

-# Generate the executable.

-#

-exe_action = 'csc.exe /target:winexe /platform:x86 /out:$TARGET /win32res:%s '\

-    '$SOURCES' % (env.File(clickonce_res).path)

-

-exe_output = env.Command(

-    target=clickonce_binary,

-    source='clickonce_bootstrap.cs',

-    action=exe_action

-)

-

-# Inform Hammer that the .res file must be built before the executeable

-env.Requires(exe_output, clickonce_res)

-

-clickonce_deploy_dir = '$TARGET_ROOT/Clickonce_Deployment'

-clickonce_deploy_bin_dir = clickonce_deploy_dir + '/bin'

-

-# Copy executable into Clickonce deployment directory.

-replicate_output = env.Replicate(clickonce_deploy_bin_dir, exe_output)

-

-

-#

-# Generate the application manifest.

-#

-v = env['product_version'][0]

-version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-generate_manifest_action = ('@mage -New Application -ToFile $TARGET -Name %s'

-    ' -Version %s -FromDirectory %s -Processor x86 -TrustLevel FullTrust' % (

-    clickonce_name, version_string, env.Dir(clickonce_deploy_bin_dir).abspath))

-

-unsigned_manifest = env.Command(

-    target=clickonce_binary + '.manifest',

-    source=replicate_output,

-    action=generate_manifest_action

-)

-

-# Sign the application manifest.

-sign_manifest_cmd =('@mage -Sign $SOURCE -ToFile $TARGET -TimestampUri '

-                    'http://timestamp.verisign.com/scripts/timstamp.dll ')

-

-if env.Bit('build_server'):

-  sign_manifest_cmd += '-CertHash fe5008fe0da7a2033816752d6eafe95214f5a7e1'

-else:

-  sign_manifest_cmd += '-CertFile %s -Password %s' % (

-      GetOption('authenticode_file'), GetOption('authenticode_password'))

-

-signed_manifest = env.Command(

-    target='%s/%s.manifest' % (clickonce_deploy_dir, clickonce_binary),

-    source=unsigned_manifest,

-    action=sign_manifest_cmd

-)

-

-

-# Instruct Hammer to regenerate the manifests when either of these

-# executables change

-env.Depends(

-    target = [

-        unsigned_manifest,

-        signed_manifest,

-        ],

-    dependency = [

-        '%s/%s' % (clickonce_deploy_bin_dir, clickonce_binary),

-        '%s/GoogleUpdateSetup.exe' % (clickonce_deploy_bin_dir),

-        ]

-)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+# Note: The localized ClickOnce deployment manifest is generated in
+# installers/build.scons.
+
+
+Import('env')
+
+clickonce_name = 'clickonce_bootstrap'
+clickonce_binary = clickonce_name + '.exe'
+clickonce_res = clickonce_name + '.res'
+
+
+#
+# Build the .res file.
+#
+env.RES(target=clickonce_res, source='clickonce_bootstrap.rc')
+
+
+#
+# Generate the executable.
+#
+exe_action = 'csc.exe /target:winexe /platform:x86 /out:$TARGET /win32res:%s '\
+    '$SOURCES' % (env.File(clickonce_res).path)
+
+exe_output = env.Command(
+    target=clickonce_binary,
+    source='clickonce_bootstrap.cs',
+    action=exe_action
+)
+
+# Inform Hammer that the .res file must be built before the executeable
+env.Requires(exe_output, clickonce_res)
+
+clickonce_deploy_dir = '$TARGET_ROOT/Clickonce_Deployment'
+clickonce_deploy_bin_dir = clickonce_deploy_dir + '/bin'
+
+# Copy executable into Clickonce deployment directory.
+replicate_output = env.Replicate(clickonce_deploy_bin_dir, exe_output)
+
+
+#
+# Generate the application manifest.
+#
+v = env['product_version'][0]
+version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+generate_manifest_action = ('@mage -New Application -ToFile $TARGET -Name %s'
+    ' -Version %s -FromDirectory %s -Processor x86 -TrustLevel FullTrust' % (
+    clickonce_name, version_string, env.Dir(clickonce_deploy_bin_dir).abspath))
+
+unsigned_manifest = env.Command(
+    target=clickonce_binary + '.manifest',
+    source=replicate_output,
+    action=generate_manifest_action
+)
+
+# Sign the application manifest.
+sign_manifest_cmd =('@mage -Sign $SOURCE -ToFile $TARGET -TimestampUri '
+                    'http://timestamp.verisign.com/scripts/timstamp.dll ')
+
+if env.Bit('build_server'):
+  sign_manifest_cmd += '-CertHash fe5008fe0da7a2033816752d6eafe95214f5a7e1'
+else:
+  sign_manifest_cmd += '-CertFile %s -Password %s' % (
+      GetOption('authenticode_file'), GetOption('authenticode_password'))
+
+signed_manifest = env.Command(
+    target='%s/%s.manifest' % (clickonce_deploy_dir, clickonce_binary),
+    source=unsigned_manifest,
+    action=sign_manifest_cmd
+)
+
+
+# Instruct Hammer to regenerate the manifests when either of these
+# executables change
+env.Depends(
+    target = [
+        unsigned_manifest,
+        signed_manifest,
+        ],
+    dependency = [
+        '%s/%s' % (clickonce_deploy_bin_dir, clickonce_binary),
+        '%s/GoogleUpdateSetup.exe' % (clickonce_deploy_bin_dir),
+        ]
+)
diff --git a/clickonce/clickonce_bootstrap.cs b/clickonce/clickonce_bootstrap.cs
index 06bc216..4a48eb1 100644
--- a/clickonce/clickonce_bootstrap.cs
+++ b/clickonce/clickonce_bootstrap.cs
@@ -1,70 +1,70 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// C# stub that allows a ClickOnce install of an Omaha application.

-

-using System;

-using System.Deployment.Application;

-using System.Diagnostics;

-using System.IO;

-using System.Security;

-using System.Security.Permissions;

-using System.Windows.Forms;

-using System.Web;

-

-namespace ClickOnceBootstrap {

-  static class ClickOnceEntry {

-    [STAThread]

-    static void Main() {

-      try {

-        // Try to get FullTrust. Will throw if we cannot get it.

-        new PermissionSet(PermissionState.Unrestricted).Demand();

-

-        if (!ApplicationDeployment.IsNetworkDeployed) {

-          // Only support running via ClickOnce.

-          return;

-        }

-

-        string query_string =

-            ApplicationDeployment.CurrentDeployment.ActivationUri.Query;

-        if (query_string.Length < 2) {

-          // Query string will be of the form "?xyz=abc". Should have atleast

-          // a question mark and atleast a single character to qualify as a

-          // valid query string. Hence the check against "2".

-          return;

-        }

-        // Remove the '?' prefix.

-        query_string = query_string.Substring(1);

-        query_string = HttpUtility.UrlDecode(query_string);

-        string setup_path = Path.Combine(Application.StartupPath,

-                                          "GoogleUpdateSetup.exe");

-

-        ProcessStartInfo psi = new ProcessStartInfo();

-        psi.FileName = setup_path;

-        psi.Verb = "open";

-        psi.Arguments = "/installsource clickonce /install \"";

-        psi.Arguments += query_string;

-        psi.Arguments += "\"";

-        Process.Start(psi);

-      } catch(Exception e) {

-        MessageBox.Show(e.ToString());

-        return;

-      }

-

-      return;

-    }

-  }

-}

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// C# stub that allows a ClickOnce install of an Omaha application.
+
+using System;
+using System.Deployment.Application;
+using System.Diagnostics;
+using System.IO;
+using System.Security;
+using System.Security.Permissions;
+using System.Windows.Forms;
+using System.Web;
+
+namespace ClickOnceBootstrap {
+  static class ClickOnceEntry {
+    [STAThread]
+    static void Main() {
+      try {
+        // Try to get FullTrust. Will throw if we cannot get it.
+        new PermissionSet(PermissionState.Unrestricted).Demand();
+
+        if (!ApplicationDeployment.IsNetworkDeployed) {
+          // Only support running via ClickOnce.
+          return;
+        }
+
+        string query_string =
+            ApplicationDeployment.CurrentDeployment.ActivationUri.Query;
+        if (query_string.Length < 2) {
+          // Query string will be of the form "?xyz=abc". Should have atleast
+          // a question mark and atleast a single character to qualify as a
+          // valid query string. Hence the check against "2".
+          return;
+        }
+        // Remove the '?' prefix.
+        query_string = query_string.Substring(1);
+        query_string = HttpUtility.UrlDecode(query_string);
+        string setup_path = Path.Combine(Application.StartupPath,
+                                          "GoogleUpdateSetup.exe");
+
+        ProcessStartInfo psi = new ProcessStartInfo();
+        psi.FileName = setup_path;
+        psi.Verb = "open";
+        psi.Arguments = "/installsource clickonce /install \"";
+        psi.Arguments += query_string;
+        psi.Arguments += "\"";
+        Process.Start(psi);
+      } catch(Exception e) {
+        MessageBox.Show(e.ToString());
+        return;
+      }
+
+      return;
+    }
+  }
+}
+
diff --git a/clickonce/clickonce_bootstrap.manifest b/clickonce/clickonce_bootstrap.manifest
index a485609..c3263b5 100644
--- a/clickonce/clickonce_bootstrap.manifest
+++ b/clickonce/clickonce_bootstrap.manifest
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="utf-8"?>

-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

-  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">

-    <security>

-      <requestedPrivileges>

-        <requestedExecutionLevel level="asInvoker" />

-      </requestedPrivileges>

-    </security>

-  </trustInfo>

-</assembly>

+<?xml version="1.0" encoding="utf-8"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+</assembly>
diff --git a/clickonce/clickonce_bootstrap.rc b/clickonce/clickonce_bootstrap.rc
index eee6dff..f291ca9 100644
--- a/clickonce/clickonce_bootstrap.rc
+++ b/clickonce/clickonce_bootstrap.rc
@@ -1,17 +1,17 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-1 24 "clickonce_bootstrap.manifest"

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+1 24 "clickonce_bootstrap.manifest"
+
diff --git a/common/ATLRegMapEx.h b/common/ATLRegMapEx.h
index e29dd0e..2a71575 100644
--- a/common/ATLRegMapEx.h
+++ b/common/ATLRegMapEx.h
@@ -1,230 +1,230 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Extension to DECLARE_REGISTRY_RESOURCEID that makes adding stuff to

-// your reg file as simple as using an atl macro map.

-//

-// Adapted from http://thecodeproject.com/atl/RegistryMap.asp

-/*

- * Defines a 'registry' map for adding variables to rgs files.

- * Original Code Copyright 2001-2003 Michael Geddes.  All rights reserved.

- * Modified Code Copyright 2005 Google Inc.

- */

-

-/* use this as your RGS file -- remove or add parameters as you see fit

-

-HKCR

-{

-  %PROGID%.%VERSION% = s '%DESCRIPTION%'

-  {

-    CLSID = s '%CLSID%'

-  }

-  %PROGID% = s '%DESCRIPTION%'

-  {

-    CLSID = s '%CLSID%'

-    CurVer = s '%PROGID%.%VERSION%'

-  }

-  NoRemove CLSID

-  {

-    ForceRemove %CLSID% = s '%DESCRIPTION%'

-    {

-      ProgID = s '%PROGID%.%VERSION%'

-       VersionIndependentProgID = s '%PROGID%'

-      ForceRemove 'Programmable'

-      InprocServer32 = s '%MODULE%'

-      {

-        val ThreadingModel = s '%THREADING%'

-      }

-      'TypeLib' = s '%LIBID%'

-    }

-  }

-}

-

-*/

-

-#ifndef OMAHA_COMMON_ATLREGMAPEX_H__

-#define OMAHA_COMMON_ATLREGMAPEX_H__

-

-#include <atlbase.h>

-#include <atlconv.h>

-#include <atlstr.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/path.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-struct _ATL_REGMAP_ENTRYKeeper : public _ATL_REGMAP_ENTRY {

-  // Returns a new Olestr that needs to be freed by caller.

-  LPCOLESTR NewOlestrFromTstr(LPCTSTR tstr)  {

-    CT2COLE olestr(tstr);

-    int alloc_length = lstrlen(olestr) + 1;

-    LPOLESTR new_olestr =  new OLECHAR[alloc_length];

-    if (new_olestr) {

-      lstrcpyn(new_olestr, olestr, alloc_length);

-    }

-    return new_olestr;

-  }

-

-  _ATL_REGMAP_ENTRYKeeper() {

-    szKey = NULL;

-    szData = NULL;

-  }

-

-  // REGMAP_ENTRY(x, y)

-  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, LPCWSTR data_tstr)  {

-    szKey = NewOlestrFromTstr(key_tstr);

-    szData = NewOlestrFromTstr(CW2T(data_tstr));

-  }

-

-  // REGMAP_ENTRY(x, y)

-  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, LPCSTR data_tstr)  {

-    szKey = NewOlestrFromTstr(key_tstr);

-    szData = NewOlestrFromTstr(CA2T(data_tstr));

-  }

-

-  // REGMAP_MODULE(x)

-  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr) {

-    szKey = NewOlestrFromTstr(key_tstr);

-    szData =

-        NewOlestrFromTstr(EnclosePathIfExe(app_util::GetCurrentModulePath()));

-  }

-

-  // REGMAP_MODULE2(x, modulename)

-  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr,

-                          LPCTSTR module_name_tstr,

-                          bool /* is_relative_to_current_module */)  {

-    szKey = NewOlestrFromTstr(key_tstr);

-    szData = NULL;

-

-    CStringW full_module_name(app_util::GetCurrentModuleDirectory());

-    full_module_name += _T("\\");

-    full_module_name += module_name_tstr;

-    szData = NewOlestrFromTstr(EnclosePathIfExe(full_module_name));

-  }

-

-  // REGMAP_EXE_MODULE(x)

-  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr,

-                          bool /* is_current_exe_module */)  {

-    szKey = NewOlestrFromTstr(key_tstr);

-    szData = NewOlestrFromTstr(EnclosePathIfExe(app_util::GetModulePath(NULL)));

-  }

-

-  // REGMAP_RESOURCE(x, resid)

-  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, UINT resid, bool /* resource */)  {

-    szKey = NewOlestrFromTstr(key_tstr);

-    CStringW res_name;

-    BOOL success = res_name.LoadString(resid);

-    ATLASSERT(success);

-    szData = NewOlestrFromTstr(res_name);

-  }

-

-  // REGMAP_UUID(x, clsid)

-  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, REFGUID guid)  {

-    szKey = NewOlestrFromTstr(key_tstr);

-    szData = NewOlestrFromTstr(GuidToString(guid));

-  }

-

-  ~_ATL_REGMAP_ENTRYKeeper()  {

-    delete [] szKey;

-    delete [] szData;

-  }

-};

-

-// This now supports DECLARE_OLEMISC_STATUS()

-#define BEGIN_REGISTRY_MAP()                                                \

-  __if_exists(_GetMiscStatus) {                                             \

-    static LPCTSTR _GetMiscStatusString()  {                                \

-      static TCHAR misc_string[32] = {0}                                    \

-      if (!misc_string[0])  {                                               \

-        wsprintf(misc_string, _T("%d"), _GetMiscStatus());                  \

-      }                                                                     \

-                                                                            \

-      return misc_string;                                                   \

-    }                                                                       \

-  }                                                                         \

-                                                                            \

-  static struct _ATL_REGMAP_ENTRY *_GetRegistryMap() {                      \

-    static const _ATL_REGMAP_ENTRYKeeper map[] = {                          \

-      __if_exists(_GetMiscStatusString) {                                   \

-        _ATL_REGMAP_ENTRYKeeper(_T("OLEMISC"), _GetMiscStatusString()),     \

-      }                                                                     \

-      __if_exists(GetAppIdT) {                                              \

-        _ATL_REGMAP_ENTRYKeeper(_T("APPID"), GetAppIdT()),                  \

-      }                                                                     \

-

-#define REGMAP_ENTRY(x, y) _ATL_REGMAP_ENTRYKeeper((x), (y)),

-

-#define REGMAP_RESOURCE(x, resid) _ATL_REGMAP_ENTRYKeeper((x), (resid), true),

-

-#define REGMAP_UUID(x, clsid) _ATL_REGMAP_ENTRYKeeper((x), (clsid)),

-

-// Add in an entry with key x, and value being the current module path.

-// For example, REGMAP_MODULE("foo"), with the current module being

-// "goopdate.dll" will result in the entry:

-// "foo", "{blah}\\Google\\Update\\1.2.71.7\\goopdate.dll"

-#define REGMAP_MODULE(x) _ATL_REGMAP_ENTRYKeeper((x)),

-

-// Add in an entry with key x, and value being modulename, fully qualified with

-// the current module path. For example, REGMAP_MODULE2("foo", "npClick7.dll")

-// with the current module being "goopdate.dll" will result in the entry:

-// "foo", "{blah}\\Google\\Update\\1.2.71.7\\npClick7.dll"

-#define REGMAP_MODULE2(x, modulename)                                       \

-    _ATL_REGMAP_ENTRYKeeper((x), (modulename), true),

-

-// Add in an entry with key x, and value being the currently running EXE's

-// module path. For example, REGMAP_EXE_MODULE("foo"), with the current process

-// being googleupdate.exe will result in the entry:

-// "foo", "{blah}\\Google\\Update\\googleupdate.exe"

-#define REGMAP_EXE_MODULE(x) _ATL_REGMAP_ENTRYKeeper((x), true),

-

-#define END_REGISTRY_MAP() _ATL_REGMAP_ENTRYKeeper()                        \

-    };                                                                      \

-    return (_ATL_REGMAP_ENTRY *)map;                                        \

-  }

-

-#define DECLARE_REGISTRY_RESOURCEID_EX(x)                                   \

-  static HRESULT WINAPI UpdateRegistry(BOOL reg) {                          \

-  __if_exists(_Module) {                                                    \

-    return _Module.UpdateRegistryFromResource((UINT)(x),                    \

-                                               (reg),                       \

-                                               _GetRegistryMap());          \

-  }                                                                         \

-  __if_not_exists(_Module) {                                                \

-    return ATL::_pAtlModule->UpdateRegistryFromResource((UINT)(x),          \

-                                                        (reg),              \

-                                                        _GetRegistryMap()); \

-  }                                                                         \

-}

-

-#define DECLARE_REGISTRY_APPID_RESOURCEID_EX(resid, appid)                  \

-  static LPCOLESTR GetAppId() throw() {                                     \

-    static const CString app_id(appid);                                     \

-    return app_id;                                                          \

-  }                                                                         \

-  static LPCTSTR GetAppIdT() throw() {                                      \

-    return GetAppId();                                                      \

-  }                                                                         \

-  static HRESULT WINAPI UpdateRegistryAppId(BOOL reg) throw() {             \

-    return ATL::_pAtlModule->UpdateRegistryFromResource(resid,              \

-                                                        (reg),              \

-                                                        _GetRegistryMap()); \

-  }

-// END registry map

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_ATLREGMAPEX_H__

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Extension to DECLARE_REGISTRY_RESOURCEID that makes adding stuff to
+// your reg file as simple as using an atl macro map.
+//
+// Adapted from http://thecodeproject.com/atl/RegistryMap.asp
+/*
+ * Defines a 'registry' map for adding variables to rgs files.
+ * Original Code Copyright 2001-2003 Michael Geddes.  All rights reserved.
+ * Modified Code Copyright 2005 Google Inc.
+ */
+
+/* use this as your RGS file -- remove or add parameters as you see fit
+
+HKCR
+{
+  %PROGID%.%VERSION% = s '%DESCRIPTION%'
+  {
+    CLSID = s '%CLSID%'
+  }
+  %PROGID% = s '%DESCRIPTION%'
+  {
+    CLSID = s '%CLSID%'
+    CurVer = s '%PROGID%.%VERSION%'
+  }
+  NoRemove CLSID
+  {
+    ForceRemove %CLSID% = s '%DESCRIPTION%'
+    {
+      ProgID = s '%PROGID%.%VERSION%'
+       VersionIndependentProgID = s '%PROGID%'
+      ForceRemove 'Programmable'
+      InprocServer32 = s '%MODULE%'
+      {
+        val ThreadingModel = s '%THREADING%'
+      }
+      'TypeLib' = s '%LIBID%'
+    }
+  }
+}
+
+*/
+
+#ifndef OMAHA_COMMON_ATLREGMAPEX_H__
+#define OMAHA_COMMON_ATLREGMAPEX_H__
+
+#include <atlbase.h>
+#include <atlconv.h>
+#include <atlstr.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/path.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+struct _ATL_REGMAP_ENTRYKeeper : public _ATL_REGMAP_ENTRY {
+  // Returns a new Olestr that needs to be freed by caller.
+  LPCOLESTR NewOlestrFromTstr(LPCTSTR tstr)  {
+    CT2COLE olestr(tstr);
+    int alloc_length = lstrlen(olestr) + 1;
+    LPOLESTR new_olestr =  new OLECHAR[alloc_length];
+    if (new_olestr) {
+      lstrcpyn(new_olestr, olestr, alloc_length);
+    }
+    return new_olestr;
+  }
+
+  _ATL_REGMAP_ENTRYKeeper() {
+    szKey = NULL;
+    szData = NULL;
+  }
+
+  // REGMAP_ENTRY(x, y)
+  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, LPCWSTR data_tstr)  {
+    szKey = NewOlestrFromTstr(key_tstr);
+    szData = NewOlestrFromTstr(CW2T(data_tstr));
+  }
+
+  // REGMAP_ENTRY(x, y)
+  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, LPCSTR data_tstr)  {
+    szKey = NewOlestrFromTstr(key_tstr);
+    szData = NewOlestrFromTstr(CA2T(data_tstr));
+  }
+
+  // REGMAP_MODULE(x)
+  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr) {
+    szKey = NewOlestrFromTstr(key_tstr);
+    szData =
+        NewOlestrFromTstr(EnclosePathIfExe(app_util::GetCurrentModulePath()));
+  }
+
+  // REGMAP_MODULE2(x, modulename)
+  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr,
+                          LPCTSTR module_name_tstr,
+                          bool /* is_relative_to_current_module */)  {
+    szKey = NewOlestrFromTstr(key_tstr);
+    szData = NULL;
+
+    CStringW full_module_name(app_util::GetCurrentModuleDirectory());
+    full_module_name += _T("\\");
+    full_module_name += module_name_tstr;
+    szData = NewOlestrFromTstr(EnclosePathIfExe(full_module_name));
+  }
+
+  // REGMAP_EXE_MODULE(x)
+  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr,
+                          bool /* is_current_exe_module */)  {
+    szKey = NewOlestrFromTstr(key_tstr);
+    szData = NewOlestrFromTstr(EnclosePathIfExe(app_util::GetModulePath(NULL)));
+  }
+
+  // REGMAP_RESOURCE(x, resid)
+  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, UINT resid, bool /* resource */)  {
+    szKey = NewOlestrFromTstr(key_tstr);
+    CStringW res_name;
+    BOOL success = res_name.LoadString(resid);
+    ATLASSERT(success);
+    szData = NewOlestrFromTstr(res_name);
+  }
+
+  // REGMAP_UUID(x, clsid)
+  _ATL_REGMAP_ENTRYKeeper(LPCTSTR key_tstr, REFGUID guid)  {
+    szKey = NewOlestrFromTstr(key_tstr);
+    szData = NewOlestrFromTstr(GuidToString(guid));
+  }
+
+  ~_ATL_REGMAP_ENTRYKeeper()  {
+    delete [] szKey;
+    delete [] szData;
+  }
+};
+
+// This now supports DECLARE_OLEMISC_STATUS()
+#define BEGIN_REGISTRY_MAP()                                                \
+  __if_exists(_GetMiscStatus) {                                             \
+    static LPCTSTR _GetMiscStatusString()  {                                \
+      static TCHAR misc_string[32] = {0}                                    \
+      if (!misc_string[0])  {                                               \
+        wsprintf(misc_string, _T("%d"), _GetMiscStatus());                  \
+      }                                                                     \
+                                                                            \
+      return misc_string;                                                   \
+    }                                                                       \
+  }                                                                         \
+                                                                            \
+  static struct _ATL_REGMAP_ENTRY *_GetRegistryMap() {                      \
+    static const _ATL_REGMAP_ENTRYKeeper map[] = {                          \
+      __if_exists(_GetMiscStatusString) {                                   \
+        _ATL_REGMAP_ENTRYKeeper(_T("OLEMISC"), _GetMiscStatusString()),     \
+      }                                                                     \
+      __if_exists(GetAppIdT) {                                              \
+        _ATL_REGMAP_ENTRYKeeper(_T("APPID"), GetAppIdT()),                  \
+      }                                                                     \
+
+#define REGMAP_ENTRY(x, y) _ATL_REGMAP_ENTRYKeeper((x), (y)),
+
+#define REGMAP_RESOURCE(x, resid) _ATL_REGMAP_ENTRYKeeper((x), (resid), true),
+
+#define REGMAP_UUID(x, clsid) _ATL_REGMAP_ENTRYKeeper((x), (clsid)),
+
+// Add in an entry with key x, and value being the current module path.
+// For example, REGMAP_MODULE("foo"), with the current module being
+// "goopdate.dll" will result in the entry:
+// "foo", "{blah}\\Google\\Update\\1.2.71.7\\goopdate.dll"
+#define REGMAP_MODULE(x) _ATL_REGMAP_ENTRYKeeper((x)),
+
+// Add in an entry with key x, and value being modulename, fully qualified with
+// the current module path. For example, REGMAP_MODULE2("foo", "npClick7.dll")
+// with the current module being "goopdate.dll" will result in the entry:
+// "foo", "{blah}\\Google\\Update\\1.2.71.7\\npClick7.dll"
+#define REGMAP_MODULE2(x, modulename)                                       \
+    _ATL_REGMAP_ENTRYKeeper((x), (modulename), true),
+
+// Add in an entry with key x, and value being the currently running EXE's
+// module path. For example, REGMAP_EXE_MODULE("foo"), with the current process
+// being googleupdate.exe will result in the entry:
+// "foo", "{blah}\\Google\\Update\\googleupdate.exe"
+#define REGMAP_EXE_MODULE(x) _ATL_REGMAP_ENTRYKeeper((x), true),
+
+#define END_REGISTRY_MAP() _ATL_REGMAP_ENTRYKeeper()                        \
+    };                                                                      \
+    return (_ATL_REGMAP_ENTRY *)map;                                        \
+  }
+
+#define DECLARE_REGISTRY_RESOURCEID_EX(x)                                   \
+  static HRESULT WINAPI UpdateRegistry(BOOL reg) {                          \
+  __if_exists(_Module) {                                                    \
+    return _Module.UpdateRegistryFromResource((UINT)(x),                    \
+                                               (reg),                       \
+                                               _GetRegistryMap());          \
+  }                                                                         \
+  __if_not_exists(_Module) {                                                \
+    return ATL::_pAtlModule->UpdateRegistryFromResource((UINT)(x),          \
+                                                        (reg),              \
+                                                        _GetRegistryMap()); \
+  }                                                                         \
+}
+
+#define DECLARE_REGISTRY_APPID_RESOURCEID_EX(resid, appid)                  \
+  static LPCOLESTR GetAppId() throw() {                                     \
+    static const CString app_id(appid);                                     \
+    return app_id;                                                          \
+  }                                                                         \
+  static LPCTSTR GetAppIdT() throw() {                                      \
+    return GetAppId();                                                      \
+  }                                                                         \
+  static HRESULT WINAPI UpdateRegistryAppId(BOOL reg) throw() {             \
+    return ATL::_pAtlModule->UpdateRegistryFromResource(resid,              \
+                                                        (reg),              \
+                                                        _GetRegistryMap()); \
+  }
+// END registry map
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_ATLREGMAPEX_H__
+
diff --git a/common/accounts.cc b/common/accounts.cc
index 0ed327c..95a1727 100644
--- a/common/accounts.cc
+++ b/common/accounts.cc
@@ -1,123 +1,123 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Enumeration of the user accounts on the PC.

-

-#include "omaha/common/accounts.h"

-

-#include <sddl.h>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/reg_key.h"

-

-namespace omaha {

-

-namespace accounts {

-

-const wchar_t kActiveProfilesKey[] =

-    L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList";

-

-HRESULT GetAllUserSids(CSimpleArray<CString> *sid_array) {

-  ASSERT(sid_array, (L""));

-

-  RegKey key_profiles;

-  HRESULT hr = key_profiles.Open(HKEY_LOCAL_MACHINE, kActiveProfilesKey);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  sid_array->RemoveAll();

-

-  uint32 total_keys = key_profiles.GetSubkeyCount();

-

-  for (uint32 i = 0 ; i < total_keys ; ++i) {

-    CString possible_user_sid, name, domain;

-    SID_NAME_USE user_type;

-

-    if (SUCCEEDED(key_profiles.GetSubkeyNameAt(i, &possible_user_sid))) {

-      if (SUCCEEDED(GetUserInfo(possible_user_sid, &name,

-                                &domain, &user_type)) &&

-          user_type == SidTypeUser) {

-        sid_array->Add(possible_user_sid);

-      }

-    }

-  }

-

-  return hr;

-}

-

-HRESULT GetUserInfo(const wchar_t *sid_str, CString *name,

-                    CString *domain, SID_NAME_USE *user_type) {

-  ASSERT(sid_str, (L""));

-  ASSERT(name, (L""));

-  ASSERT(domain, (L""));

-  ASSERT(user_type, (L""));

-

-  PSID sid = NULL;

-  HRESULT ret = E_FAIL;

-  if (ConvertStringSidToSid(sid_str, &sid)) {

-    DWORD name_size = 0, domain_size = 0;

-    if (!LookupAccountSid(NULL, sid, NULL, &name_size, NULL,

-                          &domain_size, user_type) &&

-        ERROR_INSUFFICIENT_BUFFER != GetLastError()) {

-      ret = GetCurError();

-      LocalFree(sid);

-      return ret;

-    }

-

-    ASSERT(name_size, (L""));

-    ASSERT(domain_size, (L""));

-    if (!domain_size || !name_size) {

-      LocalFree(sid);

-      return E_UNEXPECTED;

-    }

-

-    wchar_t* c_name = new wchar_t[name_size];

-    ASSERT(c_name, (L""));

-    if (!c_name) {

-      LocalFree(sid);

-      return E_OUTOFMEMORY;

-    }

-

-    wchar_t* c_domain = new wchar_t[domain_size];

-    ASSERT(c_domain, (L""));

-    if (!c_domain) {

-      delete[] c_name;

-      LocalFree(sid);

-      return E_OUTOFMEMORY;

-    }

-

-    if (LookupAccountSid(NULL, sid, c_name, &name_size, c_domain,

-                         &domain_size, user_type)) {

-      ret = S_OK;

-      name->SetString(c_name);

-      domain->SetString(c_domain);

-    } else {

-      ret = GetCurError();

-    }

-

-    delete[] c_name;

-    delete[] c_domain;

-    LocalFree(sid);

-  }

-

-  return ret;

-}

-

-}  // namespace accounts

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Enumeration of the user accounts on the PC.
+
+#include "omaha/common/accounts.h"
+
+#include <sddl.h>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/reg_key.h"
+
+namespace omaha {
+
+namespace accounts {
+
+const wchar_t kActiveProfilesKey[] =
+    L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList";
+
+HRESULT GetAllUserSids(CSimpleArray<CString> *sid_array) {
+  ASSERT(sid_array, (L""));
+
+  RegKey key_profiles;
+  HRESULT hr = key_profiles.Open(HKEY_LOCAL_MACHINE, kActiveProfilesKey);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  sid_array->RemoveAll();
+
+  uint32 total_keys = key_profiles.GetSubkeyCount();
+
+  for (uint32 i = 0 ; i < total_keys ; ++i) {
+    CString possible_user_sid, name, domain;
+    SID_NAME_USE user_type;
+
+    if (SUCCEEDED(key_profiles.GetSubkeyNameAt(i, &possible_user_sid))) {
+      if (SUCCEEDED(GetUserInfo(possible_user_sid, &name,
+                                &domain, &user_type)) &&
+          user_type == SidTypeUser) {
+        sid_array->Add(possible_user_sid);
+      }
+    }
+  }
+
+  return hr;
+}
+
+HRESULT GetUserInfo(const wchar_t *sid_str, CString *name,
+                    CString *domain, SID_NAME_USE *user_type) {
+  ASSERT(sid_str, (L""));
+  ASSERT(name, (L""));
+  ASSERT(domain, (L""));
+  ASSERT(user_type, (L""));
+
+  PSID sid = NULL;
+  HRESULT ret = E_FAIL;
+  if (ConvertStringSidToSid(sid_str, &sid)) {
+    DWORD name_size = 0, domain_size = 0;
+    if (!LookupAccountSid(NULL, sid, NULL, &name_size, NULL,
+                          &domain_size, user_type) &&
+        ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
+      ret = GetCurError();
+      LocalFree(sid);
+      return ret;
+    }
+
+    ASSERT(name_size, (L""));
+    ASSERT(domain_size, (L""));
+    if (!domain_size || !name_size) {
+      LocalFree(sid);
+      return E_UNEXPECTED;
+    }
+
+    wchar_t* c_name = new wchar_t[name_size];
+    ASSERT(c_name, (L""));
+    if (!c_name) {
+      LocalFree(sid);
+      return E_OUTOFMEMORY;
+    }
+
+    wchar_t* c_domain = new wchar_t[domain_size];
+    ASSERT(c_domain, (L""));
+    if (!c_domain) {
+      delete[] c_name;
+      LocalFree(sid);
+      return E_OUTOFMEMORY;
+    }
+
+    if (LookupAccountSid(NULL, sid, c_name, &name_size, c_domain,
+                         &domain_size, user_type)) {
+      ret = S_OK;
+      name->SetString(c_name);
+      domain->SetString(c_domain);
+    } else {
+      ret = GetCurError();
+    }
+
+    delete[] c_name;
+    delete[] c_domain;
+    LocalFree(sid);
+  }
+
+  return ret;
+}
+
+}  // namespace accounts
+
+}  // namespace omaha
+
diff --git a/common/accounts.h b/common/accounts.h
index 17ad654..26c713d 100644
--- a/common/accounts.h
+++ b/common/accounts.h
@@ -1,56 +1,56 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// Enumeration of the user accounts on the PC.

-

-#ifndef OMAHA_COMMON_ACCOUNTS_H__

-#define OMAHA_COMMON_ACCOUNTS_H__

-

-#include <windows.h>

-#include <atlcoll.h>

-#include <atlstr.h>

-

-namespace omaha {

-

-namespace accounts {

-

-// Populates sid_array with string SIDs for all users, that have profiles

-// on PC. Includes only user SIDs, no groups, computers or aliases.

-HRESULT GetAllUserSids(CSimpleArray<CString>* sid_array);

-

-// Looks up account info for given SID.

-// sid - SID to look up account info for.

-// On success populates:

-// name - name on the account

-// domain - domain name for account

-// user_type - the type of the passed SID, possible values:

-//   SidTypeUser

-//   SidTypeGroup

-//   SidTypeDomain

-//   SidTypeAlias

-//   SidTypeWellKnownGroup

-//   SidTypeDeletedAccount

-//   SidTypeInvalid

-//   SidTypeUnknown

-//   SidTypeComputer

-HRESULT GetUserInfo(const wchar_t* sid,

-                    CString* name,

-                    CString* domain,

-                    SID_NAME_USE* user_type);

-

-}  // namespace accounts

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_ACCOUNTS_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// Enumeration of the user accounts on the PC.
+
+#ifndef OMAHA_COMMON_ACCOUNTS_H__
+#define OMAHA_COMMON_ACCOUNTS_H__
+
+#include <windows.h>
+#include <atlcoll.h>
+#include <atlstr.h>
+
+namespace omaha {
+
+namespace accounts {
+
+// Populates sid_array with string SIDs for all users, that have profiles
+// on PC. Includes only user SIDs, no groups, computers or aliases.
+HRESULT GetAllUserSids(CSimpleArray<CString>* sid_array);
+
+// Looks up account info for given SID.
+// sid - SID to look up account info for.
+// On success populates:
+// name - name on the account
+// domain - domain name for account
+// user_type - the type of the passed SID, possible values:
+//   SidTypeUser
+//   SidTypeGroup
+//   SidTypeDomain
+//   SidTypeAlias
+//   SidTypeWellKnownGroup
+//   SidTypeDeletedAccount
+//   SidTypeInvalid
+//   SidTypeUnknown
+//   SidTypeComputer
+HRESULT GetUserInfo(const wchar_t* sid,
+                    CString* name,
+                    CString* domain,
+                    SID_NAME_USE* user_type);
+
+}  // namespace accounts
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_ACCOUNTS_H__
diff --git a/common/app_util.cc b/common/app_util.cc
index 77eff6a..8d1d540 100644
--- a/common/app_util.cc
+++ b/common/app_util.cc
@@ -1,242 +1,242 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/app_util.h"

-

-#include <vector>

-#include "omaha/common/cgi.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/file_ver.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-namespace app_util {

-

-HRESULT GetGuid(CString* guid) {

-  GUID guid_local = {0};

-  CString guid_str_local;

-  HRESULT hr = ::CoCreateGuid(&guid_local);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  guid_str_local = GuidToString(guid_local);

-

-  // Strip the braces around the guid.

-  guid_str_local.Delete(0);

-  guid_str_local.Delete(guid_str_local.GetLength() - 1);

-

-  *guid = guid_str_local;

-  return S_OK;

-}

-

-HMODULE GetModuleHandleFromAddress(void* address) {

-  MEMORY_BASIC_INFORMATION mbi = {0};

-  DWORD result = ::VirtualQuery(address, &mbi, sizeof(mbi));

-  ASSERT1(result == sizeof(mbi));

-  return static_cast<HMODULE>(mbi.AllocationBase);

-}

-

-HMODULE GetCurrentModuleHandle() {

-  return GetModuleHandleFromAddress(GetCurrentModuleHandle);

-}

-

-

-CString GetModulePath(HMODULE module_handle) {

-  ASSERT1(IsModuleHandleValid(module_handle));

-  CString mod_path;

-

-  DWORD result = ::GetModuleFileName(module_handle,

-                                     mod_path.GetBufferSetLength(MAX_PATH),

-                                     MAX_PATH);

-  mod_path.ReleaseBuffer();

-  ASSERT1(result == static_cast<DWORD>(mod_path.GetLength()));

-

-  return mod_path;

-}

-

-CString GetModuleDirectory(HMODULE module_handle) {

-  ASSERT1(IsModuleHandleValid(module_handle));

-  CString mod_dir(GetDirectoryFromPath(GetModulePath(module_handle)));

-

-  UTIL_LOG(L5, (_T("[GetModuleDirectory]")

-                _T("[module 0x%08x][path '%s'][directory '%s']"),

-                module_handle, GetModulePath(module_handle), mod_dir));

-

-  return mod_dir;

-}

-

-CString GetModuleName(HMODULE module_handle) {

-  ASSERT1(IsModuleHandleValid(module_handle));

-  CString app_name(GetFileFromPath(GetModulePath(module_handle)));

-

-  UTIL_LOG(L5, (_T("[GetModuleName][module 0x%08x][path '%s'][name '%s']"),

-                module_handle, GetModulePath(module_handle), app_name));

-

-  return app_name;

-}

-

-CString GetModuleNameWithoutExtension(HMODULE module_handle) {

-  ASSERT1(IsModuleHandleValid(module_handle));

-  CString module_name(GetPathRemoveExtension(GetModuleName(module_handle)));

-

-  UTIL_LOG(L5, (_T("[GetModuleNameWithoutExtension]")

-                _T("[module 0x%08x][module '%s'][name '%s']"),

-                module_handle, GetModulePath(module_handle), module_name));

-

-  return module_name;

-}

-

-CString GetCurrentModulePath() {

-  return GetModulePath(GetCurrentModuleHandle());

-}

-

-CString GetCurrentModuleDirectory() {

-  return GetModuleDirectory(GetCurrentModuleHandle());

-}

-

-CString GetCurrentModuleName() {

-  return GetModuleName(GetCurrentModuleHandle());

-}

-

-CString GetCurrentModuleNameWithoutExtension() {

-  return GetModuleNameWithoutExtension(GetCurrentModuleHandle());

-}

-

-bool IsCurrentModuleDll() {

-  return IsModuleDll(GetCurrentModuleHandle());

-}

-

-bool IsAddressInCurrentModule(void* address) {

-  return GetCurrentModuleHandle() == GetModuleHandleFromAddress(address);

-}

-

-bool IsModuleDll(HMODULE module_handle) {

-  ASSERT1(IsModuleHandleValid(module_handle));

-  const HMODULE kModuleExe = reinterpret_cast<HMODULE>(kExeLoadingAddress);

-  return (module_handle != kModuleExe) ? true : false;

-}

-

-CString GetHostName() {

-  CString hostName;

-  DWORD name_len = MAX_COMPUTERNAME_LENGTH + 1;

-  bool result = !!::GetComputerName(hostName.GetBufferSetLength(name_len),

-                                    &name_len);

-  ASSERT1(result);

-  hostName.ReleaseBuffer();

-  ASSERT1(name_len == static_cast<DWORD>(hostName.GetLength()));

-

-  return hostName;

-}

-

-CString GetWindowsDir() {

-  CString windows_path;

-

-  DWORD result = ::GetWindowsDirectory(

-      windows_path.GetBufferSetLength(MAX_PATH), MAX_PATH);

-  windows_path.ReleaseBuffer();

-  ASSERT1(result == static_cast<DWORD>(windows_path.GetLength()));

-

-  return windows_path;

-}

-

-CString GetSystemDir() {

-  CString systemPath;

-

-  DWORD result = ::GetSystemDirectory(systemPath.GetBufferSetLength(MAX_PATH),

-                                      MAX_PATH);

-  systemPath.ReleaseBuffer();

-  ASSERT1(result == static_cast<DWORD>(systemPath.GetLength()));

-

-  return systemPath;

-}

-

-CString GetTempDir() {

-  CString tempPath;

-

-  DWORD result = ::GetTempPath(MAX_PATH, tempPath.GetBufferSetLength(MAX_PATH));

-  tempPath.ReleaseBuffer();

-  ASSERT1(result == static_cast<DWORD>(tempPath.GetLength()));

-

-  return tempPath;

-}

-

-bool IsModuleHandleValid(HMODULE module_handle) {

-  if (!module_handle) {

-    return true;

-  }

-  return module_handle == GetModuleHandleFromAddress(module_handle);

-}

-

-DWORD DllGetVersion(const CString& dll_path)  {

-  HINSTANCE hInst = ::GetModuleHandle(dll_path);

-  ASSERT(hInst,

-         (_T("[GetModuleHandle failed][%s][%d]"), dll_path, ::GetLastError()));

-  DWORD dwVersion = 0;

-  DLLGETVERSIONPROC pfn = reinterpret_cast<DLLGETVERSIONPROC>(

-                              ::GetProcAddress(hInst, "DllGetVersion"));

-  if (pfn != NULL) {

-    DLLVERSIONINFO dvi = {0};

-    dvi.cbSize = sizeof(dvi);

-    HRESULT hr = (*pfn)(&dvi);

-    if (SUCCEEDED(hr)) {

-      // Since we're fitting both the major and minor versions into a DWORD,

-      // let's sanity check that we're not in an overflow situation here

-      ASSERT1(dvi.dwMajorVersion <= 0xFFFF);

-      ASSERT1(dvi.dwMinorVersion <= 0xFFFF);

-      dwVersion = MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion);

-    }

-  }

-  return dwVersion;

-}

-

-DWORD SystemDllGetVersion(const TCHAR* dll_name)  {

-  ASSERT1(dll_name);

-  CString full_dll_path(String_MakeEndWith(GetSystemDir(), _T("\\"), false) +

-                        dll_name);

-  ASSERT1(File::Exists(full_dll_path));

-  return DllGetVersion(full_dll_path);

-}

-

-ULONGLONG GetVersionFromModule(HMODULE instance) {

-  TCHAR module_path[MAX_PATH] = {0};

-  if (!::GetModuleFileName(instance, module_path, MAX_PATH) != 0) {

-    return 0;

-  }

-

-  return GetVersionFromFile(module_path);

-}

-

-ULONGLONG GetVersionFromFile(const CString& file_path) {

-  FileVer existing_file_ver;

-  if (!existing_file_ver.Open(file_path)) {

-    return 0;

-  }

-

-  return existing_file_ver.GetFileVersionAsULONGLONG();

-}

-

-}  // namespace app_util

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/app_util.h"
+
+#include <vector>
+#include "omaha/common/cgi.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/file_ver.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+namespace app_util {
+
+HRESULT GetGuid(CString* guid) {
+  GUID guid_local = {0};
+  CString guid_str_local;
+  HRESULT hr = ::CoCreateGuid(&guid_local);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  guid_str_local = GuidToString(guid_local);
+
+  // Strip the braces around the guid.
+  guid_str_local.Delete(0);
+  guid_str_local.Delete(guid_str_local.GetLength() - 1);
+
+  *guid = guid_str_local;
+  return S_OK;
+}
+
+HMODULE GetModuleHandleFromAddress(void* address) {
+  MEMORY_BASIC_INFORMATION mbi = {0};
+  DWORD result = ::VirtualQuery(address, &mbi, sizeof(mbi));
+  ASSERT1(result == sizeof(mbi));
+  return static_cast<HMODULE>(mbi.AllocationBase);
+}
+
+HMODULE GetCurrentModuleHandle() {
+  return GetModuleHandleFromAddress(GetCurrentModuleHandle);
+}
+
+
+CString GetModulePath(HMODULE module_handle) {
+  ASSERT1(IsModuleHandleValid(module_handle));
+  CString mod_path;
+
+  DWORD result = ::GetModuleFileName(module_handle,
+                                     mod_path.GetBufferSetLength(MAX_PATH),
+                                     MAX_PATH);
+  mod_path.ReleaseBuffer();
+  ASSERT1(result == static_cast<DWORD>(mod_path.GetLength()));
+
+  return mod_path;
+}
+
+CString GetModuleDirectory(HMODULE module_handle) {
+  ASSERT1(IsModuleHandleValid(module_handle));
+  CString mod_dir(GetDirectoryFromPath(GetModulePath(module_handle)));
+
+  UTIL_LOG(L5, (_T("[GetModuleDirectory]")
+                _T("[module 0x%08x][path '%s'][directory '%s']"),
+                module_handle, GetModulePath(module_handle), mod_dir));
+
+  return mod_dir;
+}
+
+CString GetModuleName(HMODULE module_handle) {
+  ASSERT1(IsModuleHandleValid(module_handle));
+  CString app_name(GetFileFromPath(GetModulePath(module_handle)));
+
+  UTIL_LOG(L5, (_T("[GetModuleName][module 0x%08x][path '%s'][name '%s']"),
+                module_handle, GetModulePath(module_handle), app_name));
+
+  return app_name;
+}
+
+CString GetModuleNameWithoutExtension(HMODULE module_handle) {
+  ASSERT1(IsModuleHandleValid(module_handle));
+  CString module_name(GetPathRemoveExtension(GetModuleName(module_handle)));
+
+  UTIL_LOG(L5, (_T("[GetModuleNameWithoutExtension]")
+                _T("[module 0x%08x][module '%s'][name '%s']"),
+                module_handle, GetModulePath(module_handle), module_name));
+
+  return module_name;
+}
+
+CString GetCurrentModulePath() {
+  return GetModulePath(GetCurrentModuleHandle());
+}
+
+CString GetCurrentModuleDirectory() {
+  return GetModuleDirectory(GetCurrentModuleHandle());
+}
+
+CString GetCurrentModuleName() {
+  return GetModuleName(GetCurrentModuleHandle());
+}
+
+CString GetCurrentModuleNameWithoutExtension() {
+  return GetModuleNameWithoutExtension(GetCurrentModuleHandle());
+}
+
+bool IsCurrentModuleDll() {
+  return IsModuleDll(GetCurrentModuleHandle());
+}
+
+bool IsAddressInCurrentModule(void* address) {
+  return GetCurrentModuleHandle() == GetModuleHandleFromAddress(address);
+}
+
+bool IsModuleDll(HMODULE module_handle) {
+  ASSERT1(IsModuleHandleValid(module_handle));
+  const HMODULE kModuleExe = reinterpret_cast<HMODULE>(kExeLoadingAddress);
+  return (module_handle != kModuleExe) ? true : false;
+}
+
+CString GetHostName() {
+  CString hostName;
+  DWORD name_len = MAX_COMPUTERNAME_LENGTH + 1;
+  bool result = !!::GetComputerName(hostName.GetBufferSetLength(name_len),
+                                    &name_len);
+  ASSERT1(result);
+  hostName.ReleaseBuffer();
+  ASSERT1(name_len == static_cast<DWORD>(hostName.GetLength()));
+
+  return hostName;
+}
+
+CString GetWindowsDir() {
+  CString windows_path;
+
+  DWORD result = ::GetWindowsDirectory(
+      windows_path.GetBufferSetLength(MAX_PATH), MAX_PATH);
+  windows_path.ReleaseBuffer();
+  ASSERT1(result == static_cast<DWORD>(windows_path.GetLength()));
+
+  return windows_path;
+}
+
+CString GetSystemDir() {
+  CString systemPath;
+
+  DWORD result = ::GetSystemDirectory(systemPath.GetBufferSetLength(MAX_PATH),
+                                      MAX_PATH);
+  systemPath.ReleaseBuffer();
+  ASSERT1(result == static_cast<DWORD>(systemPath.GetLength()));
+
+  return systemPath;
+}
+
+CString GetTempDir() {
+  CString tempPath;
+
+  DWORD result = ::GetTempPath(MAX_PATH, tempPath.GetBufferSetLength(MAX_PATH));
+  tempPath.ReleaseBuffer();
+  ASSERT1(result == static_cast<DWORD>(tempPath.GetLength()));
+
+  return tempPath;
+}
+
+bool IsModuleHandleValid(HMODULE module_handle) {
+  if (!module_handle) {
+    return true;
+  }
+  return module_handle == GetModuleHandleFromAddress(module_handle);
+}
+
+DWORD DllGetVersion(const CString& dll_path)  {
+  HINSTANCE hInst = ::GetModuleHandle(dll_path);
+  ASSERT(hInst,
+         (_T("[GetModuleHandle failed][%s][%d]"), dll_path, ::GetLastError()));
+  DWORD dwVersion = 0;
+  DLLGETVERSIONPROC pfn = reinterpret_cast<DLLGETVERSIONPROC>(
+                              ::GetProcAddress(hInst, "DllGetVersion"));
+  if (pfn != NULL) {
+    DLLVERSIONINFO dvi = {0};
+    dvi.cbSize = sizeof(dvi);
+    HRESULT hr = (*pfn)(&dvi);
+    if (SUCCEEDED(hr)) {
+      // Since we're fitting both the major and minor versions into a DWORD,
+      // let's sanity check that we're not in an overflow situation here
+      ASSERT1(dvi.dwMajorVersion <= 0xFFFF);
+      ASSERT1(dvi.dwMinorVersion <= 0xFFFF);
+      dwVersion = MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion);
+    }
+  }
+  return dwVersion;
+}
+
+DWORD SystemDllGetVersion(const TCHAR* dll_name)  {
+  ASSERT1(dll_name);
+  CString full_dll_path(String_MakeEndWith(GetSystemDir(), _T("\\"), false) +
+                        dll_name);
+  ASSERT1(File::Exists(full_dll_path));
+  return DllGetVersion(full_dll_path);
+}
+
+ULONGLONG GetVersionFromModule(HMODULE instance) {
+  TCHAR module_path[MAX_PATH] = {0};
+  if (!::GetModuleFileName(instance, module_path, MAX_PATH) != 0) {
+    return 0;
+  }
+
+  return GetVersionFromFile(module_path);
+}
+
+ULONGLONG GetVersionFromFile(const CString& file_path) {
+  FileVer existing_file_ver;
+  if (!existing_file_ver.Open(file_path)) {
+    return 0;
+  }
+
+  return existing_file_ver.GetFileVersionAsULONGLONG();
+}
+
+}  // namespace app_util
+
+}  // namespace omaha
+
diff --git a/common/app_util.h b/common/app_util.h
index df5eefb..8ff9f55 100644
--- a/common/app_util.h
+++ b/common/app_util.h
@@ -1,133 +1,133 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Utility functions for getting app and module information

-

-#ifndef OMAHA_COMMON_APP_UTIL_H__

-#define OMAHA_COMMON_APP_UTIL_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-

-namespace omaha {

-

-namespace app_util {

-

-// Gets the handle to the module containing the given executing address.

-HMODULE GetModuleHandleFromAddress(void* address);

-

-// Gets the handle to the currently executing module.

-HMODULE GetCurrentModuleHandle();

-

-// Gets the path of the loaded module.

-// If module_handle == NULL returns the path of the current executable.

-CString GetModulePath(HMODULE module_handle);

-

-// Gets the directory of the specified module

-// Returns the part of the module path, before the last '\'.

-// Returns the dir from where the module was loaded (could be exe or dll).

-CString GetModuleDirectory(HMODULE module_handle);

-

-// Gets the name of the specified module

-// Returns the part of the module path, after the last '\'.

-CString GetModuleName(HMODULE module_handle);

-

-// Gets the name of the specified module without the extension.

-CString GetModuleNameWithoutExtension(HMODULE module_handle);

-

-// Gets the current app name (i.e. exe name).

-CString GetAppName();

-

-// Gets the current app name without the extension.

-CString GetAppNameWithoutExtension();

-

-// Gets the current module path

-// returns the path from where the module was loaded (could be exe or dll).

-CString GetCurrentModulePath();

-

-// Gets the current module directory

-// returns the dir from where the module was loaded (could be exe or dll).

-CString GetCurrentModuleDirectory();

-

-// Gets the current module name.

-CString GetCurrentModuleName();

-

-// Gets the current module name without the extension.

-CString GetCurrentModuleNameWithoutExtension();

-

-// Checks if the given module is a dll or an exe.

-// Assumes a correct HMODULE.

-bool IsModuleDll(HMODULE module_handle);

-

-// Checks if the current module is a dll or an exe.

-bool IsCurrentModuleDll();

-

-// Checks if the given address is in the current module.

-bool IsAddressInCurrentModule(void* address);

-

-// Gets the host machine name.

-CString GetHostName();

-

-// Gets the Windows directory.

-CString GetWindowsDir();

-

-// Gets the System directory.

-CString GetSystemDir();

-

-// Gets the TEMP directory for the current user.

-CString GetTempDir();

-

-// Helper that gets us the version of a DLL in a DWORD format,

-// with the major and minor versions squeezed into it.

-DWORD DllGetVersion(const CString& dll_path);

-

-// Helper that gets us the version of a System DLL in a DWORD format,

-// with the major and minor versions squeezed into it. The assumption

-// is that the dll_name is only a name, and not a path. Using this

-// function (over DllGetVersion directly) for System DLLs is recommended

-// from a security perspective.

-// However, this may not work for DLLs that are loaded from the side-by-side

-// location (WinSxS) instead of the system directory.

-DWORD SystemDllGetVersion(const TCHAR* dll_name);

-

-// Gets the version from a module.

-ULONGLONG GetVersionFromModule(HMODULE instance);

-

-// Gets the version from a file path.

-ULONGLONG GetVersionFromFile(const CString& file_path);

-

-// Gets a guid from the system (for user id, etc.)

-// The guid will be of the form: 00000000-0000-0000-0000-000000000000

-HRESULT GetGuid(CString* guid);

-

-// Helper to check if a module handle is valid.

-bool IsModuleHandleValid(HMODULE module_handle);

-

-inline CString GetAppName() {

-  return GetModuleName(NULL);

-}

-

-inline CString GetAppNameWithoutExtension() {

-  return GetModuleNameWithoutExtension(NULL);

-}

-

-}  // namespace app_util

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_APP_UTIL_H__

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Utility functions for getting app and module information
+
+#ifndef OMAHA_COMMON_APP_UTIL_H__
+#define OMAHA_COMMON_APP_UTIL_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+
+namespace omaha {
+
+namespace app_util {
+
+// Gets the handle to the module containing the given executing address.
+HMODULE GetModuleHandleFromAddress(void* address);
+
+// Gets the handle to the currently executing module.
+HMODULE GetCurrentModuleHandle();
+
+// Gets the path of the loaded module.
+// If module_handle == NULL returns the path of the current executable.
+CString GetModulePath(HMODULE module_handle);
+
+// Gets the directory of the specified module
+// Returns the part of the module path, before the last '\'.
+// Returns the dir from where the module was loaded (could be exe or dll).
+CString GetModuleDirectory(HMODULE module_handle);
+
+// Gets the name of the specified module
+// Returns the part of the module path, after the last '\'.
+CString GetModuleName(HMODULE module_handle);
+
+// Gets the name of the specified module without the extension.
+CString GetModuleNameWithoutExtension(HMODULE module_handle);
+
+// Gets the current app name (i.e. exe name).
+CString GetAppName();
+
+// Gets the current app name without the extension.
+CString GetAppNameWithoutExtension();
+
+// Gets the current module path
+// returns the path from where the module was loaded (could be exe or dll).
+CString GetCurrentModulePath();
+
+// Gets the current module directory
+// returns the dir from where the module was loaded (could be exe or dll).
+CString GetCurrentModuleDirectory();
+
+// Gets the current module name.
+CString GetCurrentModuleName();
+
+// Gets the current module name without the extension.
+CString GetCurrentModuleNameWithoutExtension();
+
+// Checks if the given module is a dll or an exe.
+// Assumes a correct HMODULE.
+bool IsModuleDll(HMODULE module_handle);
+
+// Checks if the current module is a dll or an exe.
+bool IsCurrentModuleDll();
+
+// Checks if the given address is in the current module.
+bool IsAddressInCurrentModule(void* address);
+
+// Gets the host machine name.
+CString GetHostName();
+
+// Gets the Windows directory.
+CString GetWindowsDir();
+
+// Gets the System directory.
+CString GetSystemDir();
+
+// Gets the TEMP directory for the current user.
+CString GetTempDir();
+
+// Helper that gets us the version of a DLL in a DWORD format,
+// with the major and minor versions squeezed into it.
+DWORD DllGetVersion(const CString& dll_path);
+
+// Helper that gets us the version of a System DLL in a DWORD format,
+// with the major and minor versions squeezed into it. The assumption
+// is that the dll_name is only a name, and not a path. Using this
+// function (over DllGetVersion directly) for System DLLs is recommended
+// from a security perspective.
+// However, this may not work for DLLs that are loaded from the side-by-side
+// location (WinSxS) instead of the system directory.
+DWORD SystemDllGetVersion(const TCHAR* dll_name);
+
+// Gets the version from a module.
+ULONGLONG GetVersionFromModule(HMODULE instance);
+
+// Gets the version from a file path.
+ULONGLONG GetVersionFromFile(const CString& file_path);
+
+// Gets a guid from the system (for user id, etc.)
+// The guid will be of the form: 00000000-0000-0000-0000-000000000000
+HRESULT GetGuid(CString* guid);
+
+// Helper to check if a module handle is valid.
+bool IsModuleHandleValid(HMODULE module_handle);
+
+inline CString GetAppName() {
+  return GetModuleName(NULL);
+}
+
+inline CString GetAppNameWithoutExtension() {
+  return GetModuleNameWithoutExtension(NULL);
+}
+
+}  // namespace app_util
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_APP_UTIL_H__
+
diff --git a/common/app_util_unittest.cc b/common/app_util_unittest.cc
index 87d8457..fc13f89 100644
--- a/common/app_util_unittest.cc
+++ b/common/app_util_unittest.cc
@@ -1,151 +1,151 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <atlpath.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/file.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/testing/unit_test.h"

-

-const TCHAR* const kKernel32Name  = L"kernel32.dll";

-const TCHAR* const kShell32Name   = L"shell32.dll";

-const TCHAR* const kComCtl32Name  = L"comctl32.dll";

-

-namespace omaha {

-

-namespace app_util {

-

-TEST(AppUtilTest, AppUtil) {

-  HMODULE module = NULL;

-  CString name;

-

-  // First test the functionality for EXE applications.

-

-  // Test the exe module handle.

-  module = GetCurrentModuleHandle();

-  EXPECT_EQ(reinterpret_cast<HMODULE>(kExeLoadingAddress), module);

-

-  // Test the exe module handle using an address inside this module.

-  struct Local {

-    static void Func() {}

-  };

-  module = GetModuleHandleFromAddress(&Local::Func);

-  EXPECT_EQ(reinterpret_cast<HMODULE>(kExeLoadingAddress), module);

-

-  // Test the app name.

-  name = GetAppName();

-  EXPECT_STREQ(kUnittestName, name);

-

-  // Test the module name.

-  name = GetCurrentModuleName();

-  EXPECT_STREQ(kUnittestName, name);

-

-  // Test the app name w/o extension.

-  name = GetAppNameWithoutExtension() + L".exe";

-  EXPECT_STREQ(kUnittestName, name);

-

-  // Test the module name w/o extension.

-  name = GetCurrentModulePath();

-  EXPECT_STREQ(GetCurrentModuleDirectory() + L"\\" + kUnittestName, name);

-

-  // Test the module path and directory.

-  name = GetCurrentModuleName();

-  EXPECT_STREQ(kUnittestName, name);

-

-  // Test that the module is an exe.

-  module = GetCurrentModuleHandle();

-  EXPECT_FALSE(IsModuleDll(module));

-  EXPECT_FALSE(IsCurrentModuleDll());

-

-  // Test an address.

-  module = GetCurrentModuleHandle();

-  EXPECT_TRUE(IsAddressInCurrentModule(module + 0x1));

-  EXPECT_TRUE(IsAddressInCurrentModule(&Local::Func));

-  EXPECT_FALSE(IsAddressInCurrentModule(reinterpret_cast<void*>(0x1)));

-

-  // Test the functionality for DLL modules.

-  // Use kernel32.dll

-

-  // Get the loading address of kernel32.

-  HMODULE kernel32Module = ::LoadLibrary(kKernel32Name);

-  EXPECT_TRUE(kernel32Module != NULL);

-

-  // Test the dll module handle using an address.

-  module = GetModuleHandleFromAddress(::ReadFile);

-  EXPECT_EQ(kernel32Module, module);

-

-  // Check that the module is a dll.

-  EXPECT_TRUE(IsModuleDll(module));

-

-  CString system_path;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_SYSTEMX86, &system_path));

-

-  // Test the dll module directory.

-  name = GetModuleDirectory(module);

-  EXPECT_EQ(0, name.CompareNoCase(system_path));

-

-  // Test the dll module path.

-  name = GetModulePath(module);

-  EXPECT_EQ(0, name.CompareNoCase(system_path + L"\\" + kKernel32Name));

-

-  // Test the dll module name.

-  name = GetModuleName(module);

-  EXPECT_EQ(0, name.CompareNoCase(kKernel32Name));

-

-  // Other checks.

-  EXPECT_FALSE(GetWindowsDir().IsEmpty());

-  EXPECT_FALSE(GetHostName().IsEmpty());

-  EXPECT_FALSE(GetTempDir().IsEmpty());

-

-  // DLL versioning.

-  // For the tests to succeed, shell32.dll must be loaded in memory.

-  HMODULE shell32Module = ::LoadLibrary(kShell32Name);

-  EXPECT_NE(0, DllGetVersion(GetSystemDir() + L"\\" + kShell32Name));

-  EXPECT_NE(0, DllGetVersion(kShell32Name));

-  EXPECT_NE(0, SystemDllGetVersion(kShell32Name));

-

-  // For the tests to succeed, comctl32.dll must be loaded in memory.

-  // ComCtl32 may be loaded from a side-by-side (WinSxS) directory, so it is not

-  // practical to do a full-path or SystemDllGetVersion test with it.

-  HMODULE comctl32_module = ::LoadLibrary(kComCtl32Name);

-  EXPECT_NE(0, DllGetVersion(kComCtl32Name));

-

-  // kernel32 does not export DllGetVersion.

-  EXPECT_EQ(0, SystemDllGetVersion(kKernel32Name));

-

-  // Module clean-up.

-  EXPECT_TRUE(::FreeLibrary(comctl32_module));

-  EXPECT_TRUE(::FreeLibrary(shell32Module));

-  EXPECT_TRUE(::FreeLibrary(kernel32Module));

-}

-

-TEST(AppUtilTest, GetVersionFromModule) {

-  EXPECT_EQ(OMAHA_BUILD_VERSION, GetVersionFromModule(NULL));

-}

-

-TEST(AppUtilTest, GetVersionFromFile) {

-  CPath goopdate_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(goopdate_path.Append(kGoopdateDllName));

-  ASSERT_TRUE(File::Exists(goopdate_path));

-

-  EXPECT_EQ(OMAHA_BUILD_VERSION, GetVersionFromFile(goopdate_path));

-}

-

-}  // namespace app_util

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <atlpath.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/file.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/testing/unit_test.h"
+
+const TCHAR* const kKernel32Name  = L"kernel32.dll";
+const TCHAR* const kShell32Name   = L"shell32.dll";
+const TCHAR* const kComCtl32Name  = L"comctl32.dll";
+
+namespace omaha {
+
+namespace app_util {
+
+TEST(AppUtilTest, AppUtil) {
+  HMODULE module = NULL;
+  CString name;
+
+  // First test the functionality for EXE applications.
+
+  // Test the exe module handle.
+  module = GetCurrentModuleHandle();
+  EXPECT_EQ(reinterpret_cast<HMODULE>(kExeLoadingAddress), module);
+
+  // Test the exe module handle using an address inside this module.
+  struct Local {
+    static void Func() {}
+  };
+  module = GetModuleHandleFromAddress(&Local::Func);
+  EXPECT_EQ(reinterpret_cast<HMODULE>(kExeLoadingAddress), module);
+
+  // Test the app name.
+  name = GetAppName();
+  EXPECT_STREQ(kUnittestName, name);
+
+  // Test the module name.
+  name = GetCurrentModuleName();
+  EXPECT_STREQ(kUnittestName, name);
+
+  // Test the app name w/o extension.
+  name = GetAppNameWithoutExtension() + L".exe";
+  EXPECT_STREQ(kUnittestName, name);
+
+  // Test the module name w/o extension.
+  name = GetCurrentModulePath();
+  EXPECT_STREQ(GetCurrentModuleDirectory() + L"\\" + kUnittestName, name);
+
+  // Test the module path and directory.
+  name = GetCurrentModuleName();
+  EXPECT_STREQ(kUnittestName, name);
+
+  // Test that the module is an exe.
+  module = GetCurrentModuleHandle();
+  EXPECT_FALSE(IsModuleDll(module));
+  EXPECT_FALSE(IsCurrentModuleDll());
+
+  // Test an address.
+  module = GetCurrentModuleHandle();
+  EXPECT_TRUE(IsAddressInCurrentModule(module + 0x1));
+  EXPECT_TRUE(IsAddressInCurrentModule(&Local::Func));
+  EXPECT_FALSE(IsAddressInCurrentModule(reinterpret_cast<void*>(0x1)));
+
+  // Test the functionality for DLL modules.
+  // Use kernel32.dll
+
+  // Get the loading address of kernel32.
+  HMODULE kernel32Module = ::LoadLibrary(kKernel32Name);
+  EXPECT_TRUE(kernel32Module != NULL);
+
+  // Test the dll module handle using an address.
+  module = GetModuleHandleFromAddress(::ReadFile);
+  EXPECT_EQ(kernel32Module, module);
+
+  // Check that the module is a dll.
+  EXPECT_TRUE(IsModuleDll(module));
+
+  CString system_path;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_SYSTEMX86, &system_path));
+
+  // Test the dll module directory.
+  name = GetModuleDirectory(module);
+  EXPECT_EQ(0, name.CompareNoCase(system_path));
+
+  // Test the dll module path.
+  name = GetModulePath(module);
+  EXPECT_EQ(0, name.CompareNoCase(system_path + L"\\" + kKernel32Name));
+
+  // Test the dll module name.
+  name = GetModuleName(module);
+  EXPECT_EQ(0, name.CompareNoCase(kKernel32Name));
+
+  // Other checks.
+  EXPECT_FALSE(GetWindowsDir().IsEmpty());
+  EXPECT_FALSE(GetHostName().IsEmpty());
+  EXPECT_FALSE(GetTempDir().IsEmpty());
+
+  // DLL versioning.
+  // For the tests to succeed, shell32.dll must be loaded in memory.
+  HMODULE shell32Module = ::LoadLibrary(kShell32Name);
+  EXPECT_NE(0, DllGetVersion(GetSystemDir() + L"\\" + kShell32Name));
+  EXPECT_NE(0, DllGetVersion(kShell32Name));
+  EXPECT_NE(0, SystemDllGetVersion(kShell32Name));
+
+  // For the tests to succeed, comctl32.dll must be loaded in memory.
+  // ComCtl32 may be loaded from a side-by-side (WinSxS) directory, so it is not
+  // practical to do a full-path or SystemDllGetVersion test with it.
+  HMODULE comctl32_module = ::LoadLibrary(kComCtl32Name);
+  EXPECT_NE(0, DllGetVersion(kComCtl32Name));
+
+  // kernel32 does not export DllGetVersion.
+  EXPECT_EQ(0, SystemDllGetVersion(kKernel32Name));
+
+  // Module clean-up.
+  EXPECT_TRUE(::FreeLibrary(comctl32_module));
+  EXPECT_TRUE(::FreeLibrary(shell32Module));
+  EXPECT_TRUE(::FreeLibrary(kernel32Module));
+}
+
+TEST(AppUtilTest, GetVersionFromModule) {
+  EXPECT_EQ(OMAHA_BUILD_VERSION, GetVersionFromModule(NULL));
+}
+
+TEST(AppUtilTest, GetVersionFromFile) {
+  CPath goopdate_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(goopdate_path.Append(kGoopdateDllName));
+  ASSERT_TRUE(File::Exists(goopdate_path));
+
+  EXPECT_EQ(OMAHA_BUILD_VERSION, GetVersionFromFile(goopdate_path));
+}
+
+}  // namespace app_util
+
+}  // namespace omaha
+
diff --git a/common/apply_tag.cc b/common/apply_tag.cc
index 8c7f352..48d13e2 100644
--- a/common/apply_tag.cc
+++ b/common/apply_tag.cc
@@ -1,244 +1,244 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Applies a tag to a signed file.

-

-#include "omaha/common/apply_tag.h"

-#include <atlrx.h>

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/extractor.h"

-

-namespace omaha {

-

-const char kMagicBytes[] = "Gact";

-const uint32 kPEHeaderOffset = 60;

-

-ApplyTag::ApplyTag()

-    : prev_tag_string_length_(0),

-      prev_cert_length_(0),

-      append_(0) {}

-

-bool ApplyTag::IsValidTagString(const char* tag_string) {

-  ASSERT1(tag_string);

-

-  CAtlRegExp<CAtlRECharTraitsA> regex;

-  REParseError error = regex.Parse(kValidTagStringRegEx);

-  if (error != REPARSE_ERROR_OK) {

-    return false;

-  }

-

-  CAtlREMatchContext<CAtlRECharTraitsA> context;

-  return !!regex.Match(tag_string, &context);

-}

-

-HRESULT ApplyTag::Init(const TCHAR* signed_exe_file,

-                       const char* tag_string,

-                       int tag_string_length,

-                       const TCHAR* tagged_file,

-                       bool append) {

-  ASSERT1(signed_exe_file);

-  ASSERT1(tag_string);

-  ASSERT1(tagged_file);

-

-  signed_exe_file_ = signed_exe_file;

-  tagged_file_ = tagged_file;

-  append_ = append;

-

-  // Check the tag_string for invalid characters.

-  if (!IsValidTagString(tag_string)) {

-    return E_INVALIDARG;

-  }

-

-  for (int i = 0; i < tag_string_length; ++i) {

-    tag_string_.push_back(tag_string[i]);

-  }

-

-  return S_OK;

-}

-

-HRESULT ApplyTag::EmbedTagString() {

-  std::vector<byte> input_file_buffer;

-  HRESULT hr = ReadEntireFile(signed_exe_file_, 0, &input_file_buffer);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ASSERT1(!input_file_buffer.empty());

-  VERIFY1(ReadExistingTag(&input_file_buffer));

-  if (!append_ && prev_tag_string_length_) {

-    // If there is a previous tag and the append flag is not set, then

-    // we should error out.

-    return APPLYTAG_E_ALREADY_TAGGED;

-  }

-

-  if (!CreateBufferToWrite()) {

-    return E_FAIL;

-  }

-

-  // The input_file_buffer might contain the previously read tag, in which

-  // case the buffer_data_ is larger than the actual output buffer length.

-  // The real output buffer length is returned by the ApplyTagToBuffer

-  // method.

-  buffer_data_.resize(input_file_buffer.size() + tag_buffer_.size());

-

-  copy(input_file_buffer.begin(),

-       input_file_buffer.end(),

-       buffer_data_.begin());

-

-  int output_length = 0;

-  if (!ApplyTagToBuffer(&output_length))

-    return E_FAIL;

-

-  std::vector<byte> output_buffer(output_length);

-  ASSERT1(static_cast<size_t>(output_length) <= buffer_data_.size());

-  copy(buffer_data_.begin(),

-       buffer_data_.begin() + output_length,

-       output_buffer.begin());

-  return WriteEntireFile(tagged_file_, output_buffer);

-}

-

-uint32 ApplyTag::GetUint32(const void* p) {

-  ASSERT1(p);

-

-  const uint32* pu = reinterpret_cast<const uint32*>(p);

-  return *pu;

-}

-

-void ApplyTag::PutUint32(uint32 i, void* p) {

-  ASSERT1(p);

-

-  uint32* pu = reinterpret_cast<uint32*>(p);

-  *pu = i;

-}

-

-bool ApplyTag::ReadExistingTag(std::vector<byte>* binary) {

-  ASSERT1(binary);

-

-  int len = 0;

-  TagExtractor tag;

-  char* bin = reinterpret_cast<char*>(&binary->front());

-  ASSERT1(bin);

-  if (tag.ExtractTag(bin, binary->size(), NULL, &len)) {

-    prev_tag_string_.resize(len);

-    if (tag.ExtractTag(bin, binary->size(), &prev_tag_string_.front(), &len)) {

-      // The extractor returns the actual length

-      // of the string + 1 for the terminating null.

-      prev_tag_string_length_ = len - 1;

-    }

-  }

-

-  // Set the existing certificate length even if previous

-  // tag does not exist.

-  prev_cert_length_ = tag.cert_length();

-  return true;

-}

-

-bool ApplyTag::CreateBufferToWrite() {

-  ASSERT1(!append_ && !prev_tag_string_length_ || append_);

-  ASSERT1(!tag_string_.empty());

-  ASSERT1(!prev_tag_string_.size() ||

-          prev_tag_string_.size() ==

-          static_cast<size_t>(prev_tag_string_length_ + 1));

-

-  // Build the tag buffer.

-  // The format of the tag buffer is:

-  // 000000-000003: 4-byte magic (big-endian)

-  // 000004-000005: unsigned 16-bit int string length (big-endian)

-  // 000006-??????: ASCII string

-  int tag_string_len = tag_string_.size() + prev_tag_string_length_;

-  int kMagicBytesLen = ::lstrlenA(kMagicBytes);

-  int tag_header_len = kMagicBytesLen + 2;

-  int unpadded_tag_buffer_len = tag_string_len + tag_header_len;

-  // The tag buffer should be padded to multiples of 8, otherwise it will

-  // break the signature of the executable file.

-  int padded_tag_buffer_length = (unpadded_tag_buffer_len + 15) & (-8);

-

-  tag_buffer_.clear();

-  tag_buffer_.resize(padded_tag_buffer_length, 0);

-  memcpy(&tag_buffer_.front(), kMagicBytes, kMagicBytesLen);

-  tag_buffer_[kMagicBytesLen] =

-      static_cast<char>((tag_string_len & 0xff00) >> 8);

-  tag_buffer_[kMagicBytesLen+1] = static_cast<char>(tag_string_len & 0xff);

-

-  if (prev_tag_string_length_ > 0) {

-    copy(prev_tag_string_.begin(),

-         prev_tag_string_.end(),

-         tag_buffer_.begin() + tag_header_len);

-  }

-

-  copy(tag_string_.begin(),

-       tag_string_.end(),

-       tag_buffer_.begin() + tag_header_len + prev_tag_string_length_);

-  ASSERT1(static_cast<int>(tag_buffer_.size()) == padded_tag_buffer_length);

-

-  return true;

-}

-

-bool ApplyTag::ApplyTagToBuffer(int* output_len) {

-  ASSERT1(output_len);

-

-  uint32 original_data_len = buffer_data_.size() - tag_buffer_.size();

-  uint32 peheader = GetUint32(&buffer_data_.front() + kPEHeaderOffset);

-  uint32 kCertDirAddressOffset = 152;

-  uint32 kCertDirInfoSize = 4 + 4;

-

-  ASSERT1(peheader + kCertDirAddressOffset + kCertDirInfoSize <=

-          original_data_len);

-

-  // Read certificate directory info.

-  uint32 cert_dir_offset = GetUint32(&buffer_data_.front() + peheader +

-                                     kCertDirAddressOffset);

-  if (cert_dir_offset == 0)

-    return false;

-  uint32 cert_dir_len = GetUint32(&buffer_data_.front() + peheader +

-                                  kCertDirAddressOffset + 4);

-  ASSERT1(cert_dir_offset + cert_dir_len <= original_data_len);

-

-  // Calculate the new output length.

-  int prev_pad_length = cert_dir_len - prev_cert_length_ -

-                        prev_tag_string_length_;

-  ASSERT1(prev_pad_length >= 0);

-  int orig_dir_len = cert_dir_len - prev_tag_string_length_ -

-                     prev_pad_length;

-  ASSERT1(orig_dir_len == prev_cert_length_);

-  int output_length = original_data_len - prev_tag_string_length_ -

-                      prev_pad_length + tag_buffer_.size();

-  *output_len = output_length;

-  ASSERT1(static_cast<size_t>(output_length) <= buffer_data_.size());

-  ASSERT1(output_length >= orig_dir_len);

-

-  // Increase the size of certificate directory.

-  int new_cert_len = prev_cert_length_ + tag_buffer_.size();

-  PutUint32(new_cert_len,

-            &buffer_data_.front() + peheader + kCertDirAddressOffset + 4);

-

-  // Read certificate struct info.

-  uint32 cert_struct_len = GetUint32(&buffer_data_.front() + cert_dir_offset);

-  ASSERT1(!(cert_struct_len > cert_dir_len ||

-            cert_struct_len < cert_dir_len - 8));

-

-  // Increase the certificate struct size.

-  PutUint32(new_cert_len, &buffer_data_.front() + cert_dir_offset);

-

-  // Copy the tag buffer.

-  copy(tag_buffer_.begin(), tag_buffer_.end(),

-       buffer_data_.begin() + cert_dir_offset + prev_cert_length_);

-

-  return true;

-}

-

-}  // namespace omaha.

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Applies a tag to a signed file.
+
+#include "omaha/common/apply_tag.h"
+#include <atlrx.h>
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/extractor.h"
+
+namespace omaha {
+
+const char kMagicBytes[] = "Gact";
+const uint32 kPEHeaderOffset = 60;
+
+ApplyTag::ApplyTag()
+    : prev_tag_string_length_(0),
+      prev_cert_length_(0),
+      append_(0) {}
+
+bool ApplyTag::IsValidTagString(const char* tag_string) {
+  ASSERT1(tag_string);
+
+  CAtlRegExp<CAtlRECharTraitsA> regex;
+  REParseError error = regex.Parse(kValidTagStringRegEx);
+  if (error != REPARSE_ERROR_OK) {
+    return false;
+  }
+
+  CAtlREMatchContext<CAtlRECharTraitsA> context;
+  return !!regex.Match(tag_string, &context);
+}
+
+HRESULT ApplyTag::Init(const TCHAR* signed_exe_file,
+                       const char* tag_string,
+                       int tag_string_length,
+                       const TCHAR* tagged_file,
+                       bool append) {
+  ASSERT1(signed_exe_file);
+  ASSERT1(tag_string);
+  ASSERT1(tagged_file);
+
+  signed_exe_file_ = signed_exe_file;
+  tagged_file_ = tagged_file;
+  append_ = append;
+
+  // Check the tag_string for invalid characters.
+  if (!IsValidTagString(tag_string)) {
+    return E_INVALIDARG;
+  }
+
+  for (int i = 0; i < tag_string_length; ++i) {
+    tag_string_.push_back(tag_string[i]);
+  }
+
+  return S_OK;
+}
+
+HRESULT ApplyTag::EmbedTagString() {
+  std::vector<byte> input_file_buffer;
+  HRESULT hr = ReadEntireFile(signed_exe_file_, 0, &input_file_buffer);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ASSERT1(!input_file_buffer.empty());
+  VERIFY1(ReadExistingTag(&input_file_buffer));
+  if (!append_ && prev_tag_string_length_) {
+    // If there is a previous tag and the append flag is not set, then
+    // we should error out.
+    return APPLYTAG_E_ALREADY_TAGGED;
+  }
+
+  if (!CreateBufferToWrite()) {
+    return E_FAIL;
+  }
+
+  // The input_file_buffer might contain the previously read tag, in which
+  // case the buffer_data_ is larger than the actual output buffer length.
+  // The real output buffer length is returned by the ApplyTagToBuffer
+  // method.
+  buffer_data_.resize(input_file_buffer.size() + tag_buffer_.size());
+
+  copy(input_file_buffer.begin(),
+       input_file_buffer.end(),
+       buffer_data_.begin());
+
+  int output_length = 0;
+  if (!ApplyTagToBuffer(&output_length))
+    return E_FAIL;
+
+  std::vector<byte> output_buffer(output_length);
+  ASSERT1(static_cast<size_t>(output_length) <= buffer_data_.size());
+  copy(buffer_data_.begin(),
+       buffer_data_.begin() + output_length,
+       output_buffer.begin());
+  return WriteEntireFile(tagged_file_, output_buffer);
+}
+
+uint32 ApplyTag::GetUint32(const void* p) {
+  ASSERT1(p);
+
+  const uint32* pu = reinterpret_cast<const uint32*>(p);
+  return *pu;
+}
+
+void ApplyTag::PutUint32(uint32 i, void* p) {
+  ASSERT1(p);
+
+  uint32* pu = reinterpret_cast<uint32*>(p);
+  *pu = i;
+}
+
+bool ApplyTag::ReadExistingTag(std::vector<byte>* binary) {
+  ASSERT1(binary);
+
+  int len = 0;
+  TagExtractor tag;
+  char* bin = reinterpret_cast<char*>(&binary->front());
+  ASSERT1(bin);
+  if (tag.ExtractTag(bin, binary->size(), NULL, &len)) {
+    prev_tag_string_.resize(len);
+    if (tag.ExtractTag(bin, binary->size(), &prev_tag_string_.front(), &len)) {
+      // The extractor returns the actual length
+      // of the string + 1 for the terminating null.
+      prev_tag_string_length_ = len - 1;
+    }
+  }
+
+  // Set the existing certificate length even if previous
+  // tag does not exist.
+  prev_cert_length_ = tag.cert_length();
+  return true;
+}
+
+bool ApplyTag::CreateBufferToWrite() {
+  ASSERT1(!append_ && !prev_tag_string_length_ || append_);
+  ASSERT1(!tag_string_.empty());
+  ASSERT1(!prev_tag_string_.size() ||
+          prev_tag_string_.size() ==
+          static_cast<size_t>(prev_tag_string_length_ + 1));
+
+  // Build the tag buffer.
+  // The format of the tag buffer is:
+  // 000000-000003: 4-byte magic (big-endian)
+  // 000004-000005: unsigned 16-bit int string length (big-endian)
+  // 000006-??????: ASCII string
+  int tag_string_len = tag_string_.size() + prev_tag_string_length_;
+  int kMagicBytesLen = ::lstrlenA(kMagicBytes);
+  int tag_header_len = kMagicBytesLen + 2;
+  int unpadded_tag_buffer_len = tag_string_len + tag_header_len;
+  // The tag buffer should be padded to multiples of 8, otherwise it will
+  // break the signature of the executable file.
+  int padded_tag_buffer_length = (unpadded_tag_buffer_len + 15) & (-8);
+
+  tag_buffer_.clear();
+  tag_buffer_.resize(padded_tag_buffer_length, 0);
+  memcpy(&tag_buffer_.front(), kMagicBytes, kMagicBytesLen);
+  tag_buffer_[kMagicBytesLen] =
+      static_cast<char>((tag_string_len & 0xff00) >> 8);
+  tag_buffer_[kMagicBytesLen+1] = static_cast<char>(tag_string_len & 0xff);
+
+  if (prev_tag_string_length_ > 0) {
+    copy(prev_tag_string_.begin(),
+         prev_tag_string_.end(),
+         tag_buffer_.begin() + tag_header_len);
+  }
+
+  copy(tag_string_.begin(),
+       tag_string_.end(),
+       tag_buffer_.begin() + tag_header_len + prev_tag_string_length_);
+  ASSERT1(static_cast<int>(tag_buffer_.size()) == padded_tag_buffer_length);
+
+  return true;
+}
+
+bool ApplyTag::ApplyTagToBuffer(int* output_len) {
+  ASSERT1(output_len);
+
+  uint32 original_data_len = buffer_data_.size() - tag_buffer_.size();
+  uint32 peheader = GetUint32(&buffer_data_.front() + kPEHeaderOffset);
+  uint32 kCertDirAddressOffset = 152;
+  uint32 kCertDirInfoSize = 4 + 4;
+
+  ASSERT1(peheader + kCertDirAddressOffset + kCertDirInfoSize <=
+          original_data_len);
+
+  // Read certificate directory info.
+  uint32 cert_dir_offset = GetUint32(&buffer_data_.front() + peheader +
+                                     kCertDirAddressOffset);
+  if (cert_dir_offset == 0)
+    return false;
+  uint32 cert_dir_len = GetUint32(&buffer_data_.front() + peheader +
+                                  kCertDirAddressOffset + 4);
+  ASSERT1(cert_dir_offset + cert_dir_len <= original_data_len);
+
+  // Calculate the new output length.
+  int prev_pad_length = cert_dir_len - prev_cert_length_ -
+                        prev_tag_string_length_;
+  ASSERT1(prev_pad_length >= 0);
+  int orig_dir_len = cert_dir_len - prev_tag_string_length_ -
+                     prev_pad_length;
+  ASSERT1(orig_dir_len == prev_cert_length_);
+  int output_length = original_data_len - prev_tag_string_length_ -
+                      prev_pad_length + tag_buffer_.size();
+  *output_len = output_length;
+  ASSERT1(static_cast<size_t>(output_length) <= buffer_data_.size());
+  ASSERT1(output_length >= orig_dir_len);
+
+  // Increase the size of certificate directory.
+  int new_cert_len = prev_cert_length_ + tag_buffer_.size();
+  PutUint32(new_cert_len,
+            &buffer_data_.front() + peheader + kCertDirAddressOffset + 4);
+
+  // Read certificate struct info.
+  uint32 cert_struct_len = GetUint32(&buffer_data_.front() + cert_dir_offset);
+  ASSERT1(!(cert_struct_len > cert_dir_len ||
+            cert_struct_len < cert_dir_len - 8));
+
+  // Increase the certificate struct size.
+  PutUint32(new_cert_len, &buffer_data_.front() + cert_dir_offset);
+
+  // Copy the tag buffer.
+  copy(tag_buffer_.begin(), tag_buffer_.end(),
+       buffer_data_.begin() + cert_dir_offset + prev_cert_length_);
+
+  return true;
+}
+
+}  // namespace omaha.
diff --git a/common/apply_tag.h b/common/apply_tag.h
index 81b6c17..b0c6eb1 100644
--- a/common/apply_tag.h
+++ b/common/apply_tag.h
@@ -1,97 +1,97 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_APPLY_TAG_H__

-#define OMAHA_COMMON_APPLY_TAG_H__

-

-#include <atlbase.h>

-#include <atlstr.h>

-

-#include <vector>

-

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/error.h"

-

-namespace omaha {

-

-// This regular expression represents the valid characters allowed in the

-// binary tag.

-// When changing this regular expression make sure that string patterns on

-// the server are also updated.

-const char* const kValidTagStringRegEx = "^[-%{}/&=.,_a-zA-Z0-9_]*$";

-

-// Stamps the tag_string into the signed_exe_file.

-// Appends the tag_string to the existing tag if append is

-// true, else errors out. Note that we do not support a

-// overwrite.

-// The tagging is done by adding bytes to the signature

-// directory in the PE flie.

-// The modified signature directory looks something like this

-// <Signature>Gact.<tag_len><tag_string>

-// There are no restrictions on the tag_string, it is just treated

-// as a sequence of bytes.

-class ApplyTag {

- public:

-  ApplyTag();

-  HRESULT Init(const TCHAR* signed_exe_file,

-               const char* tag_string,

-               int tag_string_length,

-               const TCHAR* tagged_file,

-               bool append);

-  HRESULT EmbedTagString();

-

- private:

-  static uint32 GetUint32(const void* p);

-  static void PutUint32(uint32 i, void* p);

-  bool ReadExistingTag(std::vector<byte>* binary);

-  bool CreateBufferToWrite();

-  bool ApplyTagToBuffer(int* output_len);

-  bool IsValidTagString(const char* tag_string);

-

-  // The string to be tagged into the binary.

-  std::vector<char> tag_string_;

-

-  // Existing tag string inside the binary.

-  std::vector<char> prev_tag_string_;

-

-  // This is prev_tag_string_.size - 1, to exclude the terminating null.

-  int prev_tag_string_length_;

-

-  // Length of the certificate inside the binary.

-  int prev_cert_length_;

-

-  // The input binary to be tagged.

-  CString signed_exe_file_;

-

-  // The output binary name.

-  CString tagged_file_;

-

-  // Whether to append the tag string to the existing one.

-  bool append_;

-

-  // Internal buffer to hold the appended string.

-  std::vector<char> tag_buffer_;

-

-  // The output buffer that contains the original binary

-  // data with the tagged information.

-  std::vector<char> buffer_data_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(ApplyTag);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_APPLY_TAG_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_APPLY_TAG_H__
+#define OMAHA_COMMON_APPLY_TAG_H__
+
+#include <atlbase.h>
+#include <atlstr.h>
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/error.h"
+
+namespace omaha {
+
+// This regular expression represents the valid characters allowed in the
+// binary tag.
+// When changing this regular expression make sure that string patterns on
+// the server are also updated.
+const char* const kValidTagStringRegEx = "^[-%{}/&=.,_a-zA-Z0-9_]*$";
+
+// Stamps the tag_string into the signed_exe_file.
+// Appends the tag_string to the existing tag if append is
+// true, else errors out. Note that we do not support a
+// overwrite.
+// The tagging is done by adding bytes to the signature
+// directory in the PE flie.
+// The modified signature directory looks something like this
+// <Signature>Gact.<tag_len><tag_string>
+// There are no restrictions on the tag_string, it is just treated
+// as a sequence of bytes.
+class ApplyTag {
+ public:
+  ApplyTag();
+  HRESULT Init(const TCHAR* signed_exe_file,
+               const char* tag_string,
+               int tag_string_length,
+               const TCHAR* tagged_file,
+               bool append);
+  HRESULT EmbedTagString();
+
+ private:
+  static uint32 GetUint32(const void* p);
+  static void PutUint32(uint32 i, void* p);
+  bool ReadExistingTag(std::vector<byte>* binary);
+  bool CreateBufferToWrite();
+  bool ApplyTagToBuffer(int* output_len);
+  bool IsValidTagString(const char* tag_string);
+
+  // The string to be tagged into the binary.
+  std::vector<char> tag_string_;
+
+  // Existing tag string inside the binary.
+  std::vector<char> prev_tag_string_;
+
+  // This is prev_tag_string_.size - 1, to exclude the terminating null.
+  int prev_tag_string_length_;
+
+  // Length of the certificate inside the binary.
+  int prev_cert_length_;
+
+  // The input binary to be tagged.
+  CString signed_exe_file_;
+
+  // The output binary name.
+  CString tagged_file_;
+
+  // Whether to append the tag string to the existing one.
+  bool append_;
+
+  // Internal buffer to hold the appended string.
+  std::vector<char> tag_buffer_;
+
+  // The output buffer that contains the original binary
+  // data with the tagged information.
+  std::vector<char> buffer_data_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ApplyTag);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_APPLY_TAG_H__
diff --git a/common/atl_regexp.cc b/common/atl_regexp.cc
index e28aee0..910939b 100644
--- a/common/atl_regexp.cc
+++ b/common/atl_regexp.cc
@@ -1,70 +1,70 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-

-#include "omaha/common/atl_regexp.h"

-

-namespace omaha {

-

-const int kMaxArgs  = 16;

-

-AtlRE::AtlRE(const TCHAR* pattern, bool case_sensitive) {

-  ASSERT(pattern, (L""));

-  REParseError status = re_.Parse(pattern, case_sensitive);

-  ASSERT(status == REPARSE_ERROR_OK, (L""));

-}

-

-AtlRE::~AtlRE() {

-}

-

-bool AtlRE::DoMatchImpl(const TCHAR* text,

-                        CString* args[],

-                        int n,

-                        const TCHAR** match_end) const {

-  // text may be NULL.

-  ASSERT(args, (L""));

-

-  if (!text) {

-    return false;

-  }

-

-  AtlMatchContext matches;

-  BOOL b = re_.Match(text, &matches, match_end);

-  if (!b || matches.m_uNumGroups < static_cast<uint32>(n)) {

-    return false;

-  }

-

-  // Oddly enough, the Match call will make match_end

-  // point off the end of the string if the result is at the

-  // end of the string. We check this and handle it.

-  if (match_end) {

-    if ((*match_end - text) >= lstrlen(text)) {

-      *match_end = NULL;

-    }

-  }

-

-  const TCHAR* start = 0;

-  const TCHAR* end = 0;

-  for (int i = 0; i < n; ++i) {

-    matches.GetMatch(i, &start, &end);

-    ptrdiff_t len = end - start;

-    ASSERT(args[i], (L""));

-    // len+1 for the NULL character that's placed by lstrlen

-    VERIFY1(lstrcpyn(args[i]->GetBufferSetLength(len), start, len + 1) != NULL);

-  }

-  return true;

-}

-

-}  // namespace omaha

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+
+#include "omaha/common/atl_regexp.h"
+
+namespace omaha {
+
+const int kMaxArgs  = 16;
+
+AtlRE::AtlRE(const TCHAR* pattern, bool case_sensitive) {
+  ASSERT(pattern, (L""));
+  REParseError status = re_.Parse(pattern, case_sensitive);
+  ASSERT(status == REPARSE_ERROR_OK, (L""));
+}
+
+AtlRE::~AtlRE() {
+}
+
+bool AtlRE::DoMatchImpl(const TCHAR* text,
+                        CString* args[],
+                        int n,
+                        const TCHAR** match_end) const {
+  // text may be NULL.
+  ASSERT(args, (L""));
+
+  if (!text) {
+    return false;
+  }
+
+  AtlMatchContext matches;
+  BOOL b = re_.Match(text, &matches, match_end);
+  if (!b || matches.m_uNumGroups < static_cast<uint32>(n)) {
+    return false;
+  }
+
+  // Oddly enough, the Match call will make match_end
+  // point off the end of the string if the result is at the
+  // end of the string. We check this and handle it.
+  if (match_end) {
+    if ((*match_end - text) >= lstrlen(text)) {
+      *match_end = NULL;
+    }
+  }
+
+  const TCHAR* start = 0;
+  const TCHAR* end = 0;
+  for (int i = 0; i < n; ++i) {
+    matches.GetMatch(i, &start, &end);
+    ptrdiff_t len = end - start;
+    ASSERT(args[i], (L""));
+    // len+1 for the NULL character that's placed by lstrlen
+    VERIFY1(lstrcpyn(args[i]->GetBufferSetLength(len), start, len + 1) != NULL);
+  }
+  return true;
+}
+
+}  // namespace omaha
diff --git a/common/atl_regexp.h b/common/atl_regexp.h
index 0a47624..675dde8 100644
--- a/common/atl_regexp.h
+++ b/common/atl_regexp.h
@@ -1,145 +1,145 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// ATL Regular expression class that implements the RE interface.

-// See MSDN help for example patterns (lookup help on CAtlRegExp)

-// NOTE: This class adds about 8k to release builds.

-// TODO(omaha): add a unit test, showing examples, testing functionality

-// and perf.

-

-#ifndef OMAHA_COMMON_ATL_REGEXP_H__

-#define OMAHA_COMMON_ATL_REGEXP_H__

-

-#include <atlstr.h>

-#include <atlrx.h>

-#include "base/basictypes.h"

-#include "omaha/common/regexp.h"

-#include "omaha/common/string.h"

-

-namespace omaha {

-

-// This class is essentially a copy of CAtlRECharTraitsWide from <atlrx.h>, but

-// I've replaced CRT functions that are not in our minicrt.

-//

-// TODO(omaha): do we need this?

-class CAtlRECharTraitsWideNoCrt

-{

-public:

-  typedef WCHAR RECHARTYPE;

-

-  // ATL80 addition.

-  static size_t GetBitFieldForRangeArrayIndex(const RECHARTYPE *sz) throw()

-  {

-#ifndef ATL_NO_CHECK_BIT_FIELD

-    ATLASSERT(UseBitFieldForRange());

-#endif

-    return static_cast<size_t>(*sz);

-  }

-

-  static RECHARTYPE *Next(const RECHARTYPE *sz) throw()

-  {

-    return (RECHARTYPE *) (sz+1);

-  }

-

-  static int Strncmp(const RECHARTYPE *szLeft,

-                     const RECHARTYPE *szRight, size_t nCount) throw()

-  {

-    return String_StrNCmp(szLeft, szRight, nCount,false);

-  }

-

-  static int Strnicmp(const RECHARTYPE *szLeft,

-                      const RECHARTYPE *szRight, size_t nCount) throw()

-  {

-    return String_StrNCmp(szLeft, szRight, nCount,true);

-  }

-

-  static RECHARTYPE *Strlwr(RECHARTYPE *sz) throw()

-  {

-    return String_FastToLower(sz);

-  }

-

-  // In ATL 80 Strlwr must be passed a buffer size for security reasons.

-  // TODO(omaha): Implement the function to consider the nSize param.

-  static RECHARTYPE *Strlwr(RECHARTYPE *sz, int) throw()

-  {

-    return Strlwr(sz);

-  }

-

-  static long Strtol(const RECHARTYPE *sz,

-                     RECHARTYPE **szEnd, int nBase) throw()

-  {

-    return Wcstol(sz, szEnd, nBase);

-  }

-

-  static int Isdigit(RECHARTYPE ch) throw()

-  {

-    return String_IsDigit(ch) ? 1 : 0;

-  }

-

-  static const RECHARTYPE** GetAbbrevs()

-  {

-    static const RECHARTYPE *s_szAbbrevs[] =

-    {

-      L"a([a-zA-Z0-9])",  // alpha numeric

-        L"b([ \\t])",    // white space (blank)

-        L"c([a-zA-Z])",  // alpha

-        L"d([0-9])",    // digit

-        L"h([0-9a-fA-F])",  // hex digit

-        L"n(\r|(\r?\n))",  // newline

-        L"q(\"[^\"]*\")|(\'[^\']*\')",  // quoted string

-        L"w([a-zA-Z]+)",  // simple word

-        L"z([0-9]+)",    // integer

-        NULL

-    };

-

-    return s_szAbbrevs;

-  }

-

-  static BOOL UseBitFieldForRange() throw()

-  {

-    return FALSE;

-  }

-

-  static int ByteLen(const RECHARTYPE *sz) throw()

-  {

-    return int(lstrlen(sz)*sizeof(WCHAR));

-  }

-};

-

-typedef CAtlRegExp<CAtlRECharTraitsWideNoCrt> AtlRegExp;

-typedef CAtlREMatchContext<CAtlRECharTraitsWideNoCrt> AtlMatchContext;

-

-// implements the RE class using the ATL Regular Expressions class

-class AtlRE : public RE {

- public:

-

-  AtlRE(const TCHAR* pattern, bool case_sensitive = true);

-  virtual ~AtlRE();

-

- protected:

-  // See regexp.h for an explanation.

-  virtual bool DoMatchImpl(const TCHAR* text,

-                           CString* args[],

-                           int n,

-                           const TCHAR** match_end) const;

-

- private:

-  mutable AtlRegExp re_;

-  DISALLOW_EVIL_CONSTRUCTORS(AtlRE);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_ATL_REGEXP_H__

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// ATL Regular expression class that implements the RE interface.
+// See MSDN help for example patterns (lookup help on CAtlRegExp)
+// NOTE: This class adds about 8k to release builds.
+// TODO(omaha): add a unit test, showing examples, testing functionality
+// and perf.
+
+#ifndef OMAHA_COMMON_ATL_REGEXP_H__
+#define OMAHA_COMMON_ATL_REGEXP_H__
+
+#include <atlstr.h>
+#include <atlrx.h>
+#include "base/basictypes.h"
+#include "omaha/common/regexp.h"
+#include "omaha/common/string.h"
+
+namespace omaha {
+
+// This class is essentially a copy of CAtlRECharTraitsWide from <atlrx.h>, but
+// I've replaced CRT functions that are not in our minicrt.
+//
+// TODO(omaha): do we need this?
+class CAtlRECharTraitsWideNoCrt
+{
+public:
+  typedef WCHAR RECHARTYPE;
+
+  // ATL80 addition.
+  static size_t GetBitFieldForRangeArrayIndex(const RECHARTYPE *sz) throw()
+  {
+#ifndef ATL_NO_CHECK_BIT_FIELD
+    ATLASSERT(UseBitFieldForRange());
+#endif
+    return static_cast<size_t>(*sz);
+  }
+
+  static RECHARTYPE *Next(const RECHARTYPE *sz) throw()
+  {
+    return (RECHARTYPE *) (sz+1);
+  }
+
+  static int Strncmp(const RECHARTYPE *szLeft,
+                     const RECHARTYPE *szRight, size_t nCount) throw()
+  {
+    return String_StrNCmp(szLeft, szRight, nCount,false);
+  }
+
+  static int Strnicmp(const RECHARTYPE *szLeft,
+                      const RECHARTYPE *szRight, size_t nCount) throw()
+  {
+    return String_StrNCmp(szLeft, szRight, nCount,true);
+  }
+
+  static RECHARTYPE *Strlwr(RECHARTYPE *sz) throw()
+  {
+    return String_FastToLower(sz);
+  }
+
+  // In ATL 80 Strlwr must be passed a buffer size for security reasons.
+  // TODO(omaha): Implement the function to consider the nSize param.
+  static RECHARTYPE *Strlwr(RECHARTYPE *sz, int) throw()
+  {
+    return Strlwr(sz);
+  }
+
+  static long Strtol(const RECHARTYPE *sz,
+                     RECHARTYPE **szEnd, int nBase) throw()
+  {
+    return Wcstol(sz, szEnd, nBase);
+  }
+
+  static int Isdigit(RECHARTYPE ch) throw()
+  {
+    return String_IsDigit(ch) ? 1 : 0;
+  }
+
+  static const RECHARTYPE** GetAbbrevs()
+  {
+    static const RECHARTYPE *s_szAbbrevs[] =
+    {
+      L"a([a-zA-Z0-9])",  // alpha numeric
+        L"b([ \\t])",    // white space (blank)
+        L"c([a-zA-Z])",  // alpha
+        L"d([0-9])",    // digit
+        L"h([0-9a-fA-F])",  // hex digit
+        L"n(\r|(\r?\n))",  // newline
+        L"q(\"[^\"]*\")|(\'[^\']*\')",  // quoted string
+        L"w([a-zA-Z]+)",  // simple word
+        L"z([0-9]+)",    // integer
+        NULL
+    };
+
+    return s_szAbbrevs;
+  }
+
+  static BOOL UseBitFieldForRange() throw()
+  {
+    return FALSE;
+  }
+
+  static int ByteLen(const RECHARTYPE *sz) throw()
+  {
+    return int(lstrlen(sz)*sizeof(WCHAR));
+  }
+};
+
+typedef CAtlRegExp<CAtlRECharTraitsWideNoCrt> AtlRegExp;
+typedef CAtlREMatchContext<CAtlRECharTraitsWideNoCrt> AtlMatchContext;
+
+// implements the RE class using the ATL Regular Expressions class
+class AtlRE : public RE {
+ public:
+
+  AtlRE(const TCHAR* pattern, bool case_sensitive = true);
+  virtual ~AtlRE();
+
+ protected:
+  // See regexp.h for an explanation.
+  virtual bool DoMatchImpl(const TCHAR* text,
+                           CString* args[],
+                           int n,
+                           const TCHAR** match_end) const;
+
+ private:
+  mutable AtlRegExp re_;
+  DISALLOW_EVIL_CONSTRUCTORS(AtlRE);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_ATL_REGEXP_H__
diff --git a/common/atl_regexp_unittest.cc b/common/atl_regexp_unittest.cc
index 18c55c6..6ca3cec 100644
--- a/common/atl_regexp_unittest.cc
+++ b/common/atl_regexp_unittest.cc
@@ -1,39 +1,39 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/atl_regexp.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(AtlRETest, AtlRE) {

-  AtlRE newline_test_re(_T("ab{\\n}cd"));

-  const TCHAR* newline_strings[] = { _T("\n"), _T("\r"), _T("\r\n") };

-  for (size_t i = 0; i < arraysize(newline_strings); ++i) {

-    CString content(_T("ab"));

-    content.Append(newline_strings[i]);

-    content.Append(_T("cd"));

-    const TCHAR* content_ptr = content.GetString();

-    CString newline;

-    EXPECT_TRUE(RE::FindAndConsume(&content_ptr, newline_test_re, &newline));

-    EXPECT_STREQ(newline, newline_strings[i]);

-  }

-

-  // Check that AtlRE works with Unicode characters.

-  AtlRE one_two_three_four(_T("\x1234"));

-  EXPECT_TRUE(RE::PartialMatch(_T("\x4321\x1234\x4321"), one_two_three_four));

-}

-

-}  // namespace omaha

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/atl_regexp.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(AtlRETest, AtlRE) {
+  AtlRE newline_test_re(_T("ab{\\n}cd"));
+  const TCHAR* newline_strings[] = { _T("\n"), _T("\r"), _T("\r\n") };
+  for (size_t i = 0; i < arraysize(newline_strings); ++i) {
+    CString content(_T("ab"));
+    content.Append(newline_strings[i]);
+    content.Append(_T("cd"));
+    const TCHAR* content_ptr = content.GetString();
+    CString newline;
+    EXPECT_TRUE(RE::FindAndConsume(&content_ptr, newline_test_re, &newline));
+    EXPECT_STREQ(newline, newline_strings[i]);
+  }
+
+  // Check that AtlRE works with Unicode characters.
+  AtlRE one_two_three_four(_T("\x1234"));
+  EXPECT_TRUE(RE::PartialMatch(_T("\x4321\x1234\x4321"), one_two_three_four));
+}
+
+}  // namespace omaha
diff --git a/common/atlassert.h b/common/atlassert.h
index 91cf165..069c0b7 100644
--- a/common/atlassert.h
+++ b/common/atlassert.h
@@ -1,76 +1,76 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Take over ATLASSERT

-//

-

-#ifndef OMAHA_COMMON_ATLASSERT_H__

-#define OMAHA_COMMON_ATLASSERT_H__

-

-#include <tchar.h>

-

-#ifdef _DEBUG

-#ifndef DEBUG

-#error DEBUG and _DEBUG must be in sync

-#endif

-#endif

-

-namespace omaha {

-

-enum ReportType {

-  R_INFO = 1,   // Not an error, used for accumulating statistics.

-  R_WARNING,    // May or may not be an error.

-  R_ERROR,      // Definitely an error.

-  R_FATAL       // halt program == ASSERT for release mode.

-};

-

-enum DebugReportKind {

-  DEBUGREPORT_NONE   = 0,

-  DEBUGREPORT_ASSERT = 1,

-  DEBUGREPORT_REPORT = 2,

-  DEBUGREPORT_ABORT  = 3

-};

-

-#ifdef DEBUG

-extern "C" bool DebugReport(unsigned int id,

-                            omaha::ReportType type,

-                            const char* expr,

-                            const TCHAR* message,

-                            const char* filename,

-                            int linenumber,

-                            omaha::DebugReportKind debug_report_kind);

-  #ifndef ATLASSERT

-  #define ATLASSERT(expr)                         \

-    do {                                          \

-      if (!(expr)) {                              \

-        DebugReport(0,                            \

-                    omaha::R_FATAL,               \

-                    #expr,                        \

-                    _T("ATL assertion"),          \

-                    __FILE__,                     \

-                    __LINE__,                     \

-                    omaha::DEBUGREPORT_ASSERT);   \

-      }                                           \

-    } while (0)

-  #endif

-#else

-  #ifndef ATLASSERT

-  #define ATLASSERT(expr) ((void)0)

-  #endif

-#endif

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_ATLASSERT_H__

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Take over ATLASSERT
+//
+
+#ifndef OMAHA_COMMON_ATLASSERT_H__
+#define OMAHA_COMMON_ATLASSERT_H__
+
+#include <tchar.h>
+
+#ifdef _DEBUG
+#ifndef DEBUG
+#error DEBUG and _DEBUG must be in sync
+#endif
+#endif
+
+namespace omaha {
+
+enum ReportType {
+  R_INFO = 1,   // Not an error, used for accumulating statistics.
+  R_WARNING,    // May or may not be an error.
+  R_ERROR,      // Definitely an error.
+  R_FATAL       // halt program == ASSERT for release mode.
+};
+
+enum DebugReportKind {
+  DEBUGREPORT_NONE   = 0,
+  DEBUGREPORT_ASSERT = 1,
+  DEBUGREPORT_REPORT = 2,
+  DEBUGREPORT_ABORT  = 3
+};
+
+#ifdef DEBUG
+extern "C" bool DebugReport(unsigned int id,
+                            omaha::ReportType type,
+                            const char* expr,
+                            const TCHAR* message,
+                            const char* filename,
+                            int linenumber,
+                            omaha::DebugReportKind debug_report_kind);
+  #ifndef ATLASSERT
+  #define ATLASSERT(expr)                         \
+    do {                                          \
+      if (!(expr)) {                              \
+        DebugReport(0,                            \
+                    omaha::R_FATAL,               \
+                    #expr,                        \
+                    _T("ATL assertion"),          \
+                    __FILE__,                     \
+                    __LINE__,                     \
+                    omaha::DEBUGREPORT_ASSERT);   \
+      }                                           \
+    } while (0)
+  #endif
+#else
+  #ifndef ATLASSERT
+  #define ATLASSERT(expr) ((void)0)
+  #endif
+#endif
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_ATLASSERT_H__
diff --git a/common/atlassert_unittest.cc b/common/atlassert_unittest.cc
index 33ccdf7..2e1deb9 100644
--- a/common/atlassert_unittest.cc
+++ b/common/atlassert_unittest.cc
@@ -1,28 +1,28 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/debug.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Test what happens when we hit an ATLASSERT within ATL code.

-// The CComPtr expects the parameter to be 0.

-TEST(AtlAssertTest, AtlAssert) {

-  ExpectAsserts expect_asserts;

-  CComPtr<IUnknown> p(1);

-}

-

-}  // namespace omaha

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/debug.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Test what happens when we hit an ATLASSERT within ATL code.
+// The CComPtr expects the parameter to be 0.
+TEST(AtlAssertTest, AtlAssert) {
+  ExpectAsserts expect_asserts;
+  CComPtr<IUnknown> p(1);
+}
+
+}  // namespace omaha
diff --git a/common/atlconvfix.h b/common/atlconvfix.h
index a6a1f32..76ffaa4 100644
--- a/common/atlconvfix.h
+++ b/common/atlconvfix.h
@@ -1,105 +1,105 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// atlconvfix.h

-//

-// This file is included in the precompile headers.

-// Do not include the base/basictypes.h here.

-

-#ifndef OMAHA_COMMON_ATLCONVFIX_H_

-#define OMAHA_COMMON_ATLCONVFIX_H_

-

-#ifndef DISALLOW_EVIL_CONSTRUCTORS

-// A macro to disallow the evil copy constructor and operator= functions

-// This should be used in the private: declarations for a class

-#define DISALLOW_EVIL_CONSTRUCTORS(TypeName)    \

-  TypeName(const TypeName&);                    \

-  void operator=(const TypeName&)

-#endif

-

-// These use alloca which can be dangerous,

-// so we don't allow them to be used.  Use

-// CA2[C]W, etc. instead.

-#undef A2W

-#undef W2A

-#undef A2W_EX

-#undef W2A_EX

-#undef USES_CONVERSION

-

-#ifdef DEBUG

-// The DestroyBuffer template and the macros following it are

-// all there to ensure that when the string classes get destroyed,

-// so does the string that they return since it is no longer valid.

-// Without them it is very easy to make simple and hard to catch mistakes

-// when using the atl C*2[C]* string converstion classes.

-

-// In non-debug code, the atl string macros do not need to be destroyed,

-// so they aren't wrapped there.

-

-template <int buffer_length, template <int buffer_length> class ConversionClass,

-          typename StringType>

-class DestroyBuffer : public ConversionClass<buffer_length> {

- public:

-  DestroyBuffer(StringType string) : ConversionClass<buffer_length>(string) {

-  }

-

-  DestroyBuffer(StringType string, UINT code_page) :

-      ConversionClass<buffer_length>(string, code_page) {

-  }

-

-  ~DestroyBuffer() {

-    memset(m_szBuffer, 0xdd, sizeof(m_szBuffer));

-  }

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(DestroyBuffer);

-};

-

-#define DECLARED_DESTROY_NAME(base_type) DestroyBuffer##base_type

-#define DECLARE_DESTROY_TYPES(base_type, string_type) \

-  template <int buffer_length = 128> \

-  class DECLARED_DESTROY_NAME(base_type##EX) : \

-      public DestroyBuffer<buffer_length, base_type##EX, string_type> { \

-   public: \

-    DECLARED_DESTROY_NAME(base_type##EX)(string_type string) : \

-      DestroyBuffer<buffer_length, base_type##EX, string_type>(string) {  \

-    } \

-    DECLARED_DESTROY_NAME(base_type##EX)(string_type string, \

-                                         UINT code_page) : \

-      DestroyBuffer<buffer_length, base_type##EX, string_type>(string, \

-                                                               code_page) { \

-    } \

-   private: \

-    DISALLOW_EVIL_CONSTRUCTORS(DECLARED_DESTROY_NAME(base_type##EX)); \

-  }; \

-  typedef DECLARED_DESTROY_NAME(base_type##EX)<> \

-      DECLARED_DESTROY_NAME(base_type)

-

-DECLARE_DESTROY_TYPES(CW2W, LPCWSTR);

-DECLARE_DESTROY_TYPES(CW2A, LPCWSTR);

-DECLARE_DESTROY_TYPES(CA2W, LPCSTR);

-DECLARE_DESTROY_TYPES(CA2A, LPCSTR);

-

-#define CW2WEX DECLARED_DESTROY_NAME(CW2WEX)

-#define CW2AEX DECLARED_DESTROY_NAME(CW2AEX)

-#define CA2WEX DECLARED_DESTROY_NAME(CA2WEX)

-#define CA2AEX DECLARED_DESTROY_NAME(CA2AEX)

-#define CW2W   DECLARED_DESTROY_NAME(CW2W)

-#define CW2A   DECLARED_DESTROY_NAME(CW2A)

-#define CA2W   DECLARED_DESTROY_NAME(CA2W)

-#define CA2A   DECLARED_DESTROY_NAME(CA2A)

-#endif // DEBUG

-

-#endif // OMAHA_COMMON_ATLCONVFIX_H_

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// atlconvfix.h
+//
+// This file is included in the precompile headers.
+// Do not include the base/basictypes.h here.
+
+#ifndef OMAHA_COMMON_ATLCONVFIX_H_
+#define OMAHA_COMMON_ATLCONVFIX_H_
+
+#ifndef DISALLOW_EVIL_CONSTRUCTORS
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_EVIL_CONSTRUCTORS(TypeName)    \
+  TypeName(const TypeName&);                    \
+  void operator=(const TypeName&)
+#endif
+
+// These use alloca which can be dangerous,
+// so we don't allow them to be used.  Use
+// CA2[C]W, etc. instead.
+#undef A2W
+#undef W2A
+#undef A2W_EX
+#undef W2A_EX
+#undef USES_CONVERSION
+
+#ifdef DEBUG
+// The DestroyBuffer template and the macros following it are
+// all there to ensure that when the string classes get destroyed,
+// so does the string that they return since it is no longer valid.
+// Without them it is very easy to make simple and hard to catch mistakes
+// when using the atl C*2[C]* string converstion classes.
+
+// In non-debug code, the atl string macros do not need to be destroyed,
+// so they aren't wrapped there.
+
+template <int buffer_length, template <int buffer_length> class ConversionClass,
+          typename StringType>
+class DestroyBuffer : public ConversionClass<buffer_length> {
+ public:
+  DestroyBuffer(StringType string) : ConversionClass<buffer_length>(string) {
+  }
+
+  DestroyBuffer(StringType string, UINT code_page) :
+      ConversionClass<buffer_length>(string, code_page) {
+  }
+
+  ~DestroyBuffer() {
+    memset(m_szBuffer, 0xdd, sizeof(m_szBuffer));
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(DestroyBuffer);
+};
+
+#define DECLARED_DESTROY_NAME(base_type) DestroyBuffer##base_type
+#define DECLARE_DESTROY_TYPES(base_type, string_type) \
+  template <int buffer_length = 128> \
+  class DECLARED_DESTROY_NAME(base_type##EX) : \
+      public DestroyBuffer<buffer_length, base_type##EX, string_type> { \
+   public: \
+    DECLARED_DESTROY_NAME(base_type##EX)(string_type string) : \
+      DestroyBuffer<buffer_length, base_type##EX, string_type>(string) {  \
+    } \
+    DECLARED_DESTROY_NAME(base_type##EX)(string_type string, \
+                                         UINT code_page) : \
+      DestroyBuffer<buffer_length, base_type##EX, string_type>(string, \
+                                                               code_page) { \
+    } \
+   private: \
+    DISALLOW_EVIL_CONSTRUCTORS(DECLARED_DESTROY_NAME(base_type##EX)); \
+  }; \
+  typedef DECLARED_DESTROY_NAME(base_type##EX)<> \
+      DECLARED_DESTROY_NAME(base_type)
+
+DECLARE_DESTROY_TYPES(CW2W, LPCWSTR);
+DECLARE_DESTROY_TYPES(CW2A, LPCWSTR);
+DECLARE_DESTROY_TYPES(CA2W, LPCSTR);
+DECLARE_DESTROY_TYPES(CA2A, LPCSTR);
+
+#define CW2WEX DECLARED_DESTROY_NAME(CW2WEX)
+#define CW2AEX DECLARED_DESTROY_NAME(CW2AEX)
+#define CA2WEX DECLARED_DESTROY_NAME(CA2WEX)
+#define CA2AEX DECLARED_DESTROY_NAME(CA2AEX)
+#define CW2W   DECLARED_DESTROY_NAME(CW2W)
+#define CW2A   DECLARED_DESTROY_NAME(CW2A)
+#define CA2W   DECLARED_DESTROY_NAME(CA2W)
+#define CA2A   DECLARED_DESTROY_NAME(CA2A)
+#endif // DEBUG
+
+#endif // OMAHA_COMMON_ATLCONVFIX_H_
diff --git a/common/auto_any.h b/common/auto_any.h
index a8580bc..4b550a2 100644
--- a/common/auto_any.h
+++ b/common/auto_any.h
@@ -1,28 +1,28 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// See the comments in omaha/common/scoped_any.h for details.

-

-#ifndef OMAHA_COMMON_AUTO_ANY_H__

-#define OMAHA_COMMON_AUTO_ANY_H__

-

-#pragma warning(push)

-// C4640: construction of local static object is not thread-safe

-#pragma warning(disable : 4640)

-#include "omaha/third_party/smartany/scoped_any.h"

-#pragma warning(pop)

-

-#endif  // OMAHA_COMMON_AUTO_ANY_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// See the comments in omaha/common/scoped_any.h for details.
+
+#ifndef OMAHA_COMMON_AUTO_ANY_H__
+#define OMAHA_COMMON_AUTO_ANY_H__
+
+#pragma warning(push)
+// C4640: construction of local static object is not thread-safe
+#pragma warning(disable : 4640)
+#include "omaha/third_party/smartany/scoped_any.h"
+#pragma warning(pop)
+
+#endif  // OMAHA_COMMON_AUTO_ANY_H__
+
diff --git a/common/browser_utils.cc b/common/browser_utils.cc
index cdbc608..975fe46 100644
--- a/common/browser_utils.cc
+++ b/common/browser_utils.cc
@@ -1,593 +1,593 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/browser_utils.h"

-#include "base/basictypes.h"

-#include "omaha/common/commands.h"

-#include "omaha/common/const_utils.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/proc_utils.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/shell.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/common/vista_utils.h"

-

-namespace omaha {

-

-HRESULT GetLegacyDefaultBrowserInfo(CString* name, CString* path) {

-  UTIL_LOG(L3, (_T("[GetLegacyDefaultBrowserInfo]")));

-  ASSERT1(name);

-  ASSERT1(path);

-  name->Empty();

-  path->Empty();

-

-  CString browser_command_line;

-  HRESULT hr = RegKey::GetValue(kRegKeyLegacyDefaultBrowserCommand,

-                                NULL,

-                                &browser_command_line);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[Read failed][%s]"), kRegKeyLegacyDefaultBrowserCommand));

-    return hr;

-  }

-

-  UTIL_LOG(L5, (_T("[browser_command_line][%s]"), browser_command_line));

-  browser_command_line.Trim(_T(" "));

-  if (browser_command_line.IsEmpty()) {

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-

-  CString browser_path;

-  if (File::Exists(browser_command_line)) {

-    if (File::IsDirectory(browser_command_line)) {

-      UTIL_LOG(LE, (_T("[Unexpected. Command line should not be directory]")));

-      return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-    }

-

-    browser_path = browser_command_line;

-  } else {

-    hr = GetExePathFromCommandLine(browser_command_line, &browser_path);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    if (!File::Exists(browser_path) ||

-        File::IsDirectory(browser_path)) {

-      UTIL_LOG(LE, (_T("[browser_path invalid][%s]"), browser_path));

-      return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-    }

-  }

-

-  CString browser_name = ::PathFindFileName(browser_path);

-  if (browser_name.IsEmpty() ||

-      !String_EndsWith(browser_name, _T(".exe"), true)) {

-    UTIL_LOG(LE, (_T("[browser name invalid][%s]"), browser_name));

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-

-  *path = browser_path;

-  *name = browser_name;

-  return S_OK;

-}

-

-HRESULT GetDefaultBrowserName(CString* name) {

-  ASSERT1(name);

-  name->Empty();

-

-  // Get the default browser name from current user registry.

-  HKEY user_root_key = NULL;

-  VERIFY1(::RegOpenCurrentUser(KEY_READ, &user_root_key) == ERROR_SUCCESS);

-  RegKey user_default_browser;

-  HRESULT hr = user_default_browser.Open(

-      user_root_key ? user_root_key : HKEY_CURRENT_USER,

-      kRegKeyDefaultBrowser,

-      KEY_READ);

-  if (SUCCEEDED(hr)) {

-    hr = user_default_browser.GetValue(NULL, name);

-  }

-  if (user_root_key) {

-    LONG error(::RegCloseKey(user_root_key));

-

-    // See bug http://b/issue?id=1231862 for details when RegCloseKey can

-    // return ERROR_INVALID_HANDLE.

-    ASSERT1(error == ERROR_SUCCESS ||

-            error == ERROR_INVALID_HANDLE);

-  }

-

-  if (SUCCEEDED(hr) && !name->IsEmpty()) {

-    UTIL_LOG(L3, (_T("[Default browser for the user is %s]"), *name));

-    return S_OK;

-  }

-

-  // Try to get from local machine registry.

-  hr = RegKey::GetValue(kRegKeyMachineDefaultBrowser, NULL, name);

-  if (SUCCEEDED(hr) && !name->IsEmpty()) {

-    UTIL_LOG(L3, (_T("[Default browser for the machine is %s]"), *name));

-    return S_OK;

-  }

-

-  // Try to get from legacy default browser location.

-  CString browser_path;

-  hr = GetLegacyDefaultBrowserInfo(name, &browser_path);

-  if (SUCCEEDED(hr) && !name->IsEmpty()) {

-    UTIL_LOG(L3, (_T("[Legacy default browser is %s]"), *name));

-    return S_OK;

-  }

-

-  // If still failed, we don't want to break in this case so we default to

-  // IEXPLORE.EXE. A scenario where this can happen is when the user installs

-  // a browser that configures itself to be default. Then the user uninstalls

-  // or somehow removes that browser and the registry is not updated correctly.

-  *name = kIeExeName;

-  return S_OK;

-}

-

-HRESULT GetDefaultBrowserType(BrowserType* type) {

-  ASSERT1(type);

-

-  CString name;

-  HRESULT hr = GetDefaultBrowserName(&name);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (name.CompareNoCase(kIeExeName) == 0) {

-    *type = BROWSER_IE;

-  } else if (name.CompareNoCase(kFirefoxExeName) == 0) {

-    *type = BROWSER_FIREFOX;

-  } else if (name.CompareNoCase(kChromeExeName) == 0) {

-    *type = BROWSER_CHROME;

-  } else {

-    *type = BROWSER_UNKNOWN;

-  }

-

-  return S_OK;

-}

-

-// Returns a path that is always unenclosed. The method could return a short or

-// long form path.

-HRESULT GetDefaultBrowserPath(CString* path) {

-  ASSERT1(path);

-  path->Empty();

-  ON_SCOPE_EXIT(UnenclosePath, path);

-

-  // Get the default browser name.

-  CString name;

-  if (FAILED(GetDefaultBrowserName(&name))) {

-    // Try getting IE's path through COM registration and app path entries.

-    return GetBrowserImagePath(BROWSER_IE, path);

-  }

-

-  CString shell_open_path(_T("\\"));

-  shell_open_path += name;

-  shell_open_path += kRegKeyShellOpenCommand;

-

-  // Read the path corresponding to it from current user registry.

-  CString browser_key(kRegKeyUserDefaultBrowser);

-  browser_key += shell_open_path;

-  HRESULT hr = RegKey::GetValue(browser_key, NULL, path);

-

-  CString cmd_line(*path);

-  CString args;

-  if (SUCCEEDED(hr) &&

-      !path->IsEmpty() &&

-      SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(cmd_line,

-                                                           path,

-                                                           &args))) {

-    return S_OK;

-  }

-

-  // If failed, try to get from local machine registry.

-  browser_key = kRegKeyMachineDefaultBrowser;

-  browser_key += shell_open_path;

-  hr = RegKey::GetValue(browser_key, NULL, path);

-

-  cmd_line = *path;

-  args.Empty();

-  if (SUCCEEDED(hr) &&

-      !path->IsEmpty() &&

-      SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(cmd_line,

-                                                           path,

-                                                           &args))) {

-    return S_OK;

-  }

-

-  // Try to get from legacy default browser location.

-  hr = GetLegacyDefaultBrowserInfo(&name, path);

-  if (SUCCEEDED(hr) && !path->IsEmpty()) {

-    return S_OK;

-  }

-

-  // If failed and the default browser is not IE, try IE once again.

-  if (name.CompareNoCase(kIeExeName) != 0) {

-    browser_key = kRegKeyMachineDefaultBrowser

-                  _T("\\") kIeExeName kRegKeyShellOpenCommand;

-    hr = RegKey::GetValue(browser_key, NULL, path);

-

-    cmd_line = *path;

-    args.Empty();

-    if (SUCCEEDED(hr) &&

-        !path->IsEmpty() &&

-        SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(cmd_line,

-                                                             path,

-                                                             &args))) {

-      return S_OK;

-    }

-  }

-

-  // Try getting the default browser's path through COM registration and app

-  // path entries.

-  BrowserType default_type = BROWSER_UNKNOWN;

-  hr = GetDefaultBrowserType(&default_type);

-  if (FAILED(hr) ||

-      default_type == BROWSER_UNKNOWN ||

-      default_type == BROWSER_DEFAULT) {

-    default_type = BROWSER_IE;

-  }

-

-  return GetBrowserImagePath(default_type, path);

-}

-

-HRESULT GetFirefoxDefaultProfile(CString* name, CString* path) {

-  ASSERT1(name);

-  ASSERT1(path);

-

-  const TCHAR kFirefoxAppDataPath[] = _T("\\Mozilla\\Firefox\\");

-  const TCHAR kFirefoxProfileIni[] = _T("profiles.ini");

-  const TCHAR kFirefoxDefaultProfileSecName[] = _T("Profile0");

-  const TCHAR kFirefoxProfileIniNameKey[] = _T("Name");

-  const TCHAR kFirefoxProfileIniIsRelativeKey[] = _T("IsRelative");

-  const TCHAR kFirefoxProfileIniPathKey[] = _T("Path");

-  const TCHAR kFirefoxProfileIniDefaultKey[] = _T("Default");

-

-  name->Empty();

-  path->Empty();

-

-  // Get appdata path for storing Firefox settings.

-  CString appdata_path;

-  RET_IF_FAILED(Shell::GetSpecialFolder(CSIDL_APPDATA, false, &appdata_path));

-  appdata_path += kFirefoxAppDataPath;

-

-  // Get profile.ini.

-  CString profile_ini = appdata_path + kFirefoxProfileIni;

-  UTIL_LOG(L3, (_T("[FireFox profile.ini][%s]"), profile_ini));

-

-  if (!File::Exists(profile_ini)) {

-    UTIL_LOG(LE, (_T("[File does not exist][%s]"), profile_ini));

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-

-  // Read all section names in profile.ini.

-  // The buffer is filled with one or more null-terminated strings; the last

-  // string is followed by a second null character.

-  const int kMaxProfileSecNamesLength = 2048;

-  CString profile_sec_names;

-  DWORD char_returned = ::GetPrivateProfileSectionNames(

-      profile_sec_names.GetBufferSetLength(kMaxProfileSecNamesLength),

-      kMaxProfileSecNamesLength,

-      profile_ini);

-  if (char_returned == kMaxProfileSecNamesLength - 2) {

-    UTIL_LOG(LW, (_T("[FireFox profile.ini contains too many sections]")));

-  }

-  profile_sec_names.ReleaseBuffer(char_returned);

-

-  // Iterate through all the sections to find the default profile.

-  const TCHAR* default_profile_sec = NULL;

-  const TCHAR* ptr = profile_sec_names.GetString();

-  const TCHAR* end = ptr + char_returned;

-  while (ptr < end && *ptr) {

-    if (::GetPrivateProfileInt(ptr,

-                               kFirefoxProfileIniDefaultKey,

-                               0,

-                               profile_ini)) {

-      default_profile_sec = ptr;

-      break;

-    }

-

-    for (; ptr < end && *ptr; ++ptr) {

-    }

-    ++ptr;

-  }

-

-  if (!default_profile_sec) {

-    default_profile_sec = kFirefoxDefaultProfileSecName;

-  }

-

-  DWORD name_len = ::GetPrivateProfileString(default_profile_sec,

-                                             kFirefoxProfileIniNameKey, _T(""),

-                                             name->GetBufferSetLength(256),

-                                             256,

-                                             profile_ini);

-  name->ReleaseBuffer(name_len);

-

-  DWORD path_len = ::GetPrivateProfileString(default_profile_sec,

-                                             kFirefoxProfileIniPathKey,

-                                             _T(""),

-                                             path->GetBufferSetLength(1024),

-                                             1024,

-                                             profile_ini);

-  path->ReleaseBuffer(path_len);

-  path->Replace(_T('/'), _T('\\'));

-

-  bool is_relative = ::GetPrivateProfileInt(default_profile_sec,

-                                            kFirefoxProfileIniIsRelativeKey,

-                                            0,

-                                            profile_ini) != 0;

-

-  if (is_relative && !path->IsEmpty()) {

-    path->Insert(0, appdata_path);

-  }

-

-  return S_OK;

-}

-

-HRESULT BrowserTypeToProcessName(BrowserType type, CString* exe_name) {

-  ASSERT1(exe_name);

-  ASSERT1(type < BROWSER_MAX);

-

-  switch (type) {

-    case BROWSER_IE:

-      *exe_name = kIeExeName;

-      break;

-    case BROWSER_FIREFOX:

-      *exe_name = kFirefoxExeName;

-      break;

-    case BROWSER_CHROME:

-      *exe_name = kChromeExeName;

-      break;

-    case BROWSER_DEFAULT:

-      return GetDefaultBrowserName(exe_name);

-    case BROWSER_UNKNOWN:

-      // Fall through.

-    case BROWSER_MAX:

-      // Fall through.

-    default:

-      return E_FAIL;

-  }

-

-  return S_OK;

-}

-

-// Returns a path that is always unenclosed. The method could return a short or

-// long form path.

-HRESULT GetBrowserImagePath(BrowserType type, CString* path) {

-  ASSERT1(path);

-  ASSERT1(type < BROWSER_MAX);

-

-  HRESULT hr = E_FAIL;

-  switch (type) {

-    case BROWSER_IE: {

-      hr = RegKey::GetValue(kRegKeyIeClass, kRegValueIeClass, path);

-      break;

-    }

-    case BROWSER_FIREFOX: {

-      hr = RegKey::GetValue(kRegKeyFirefox, kRegValueFirefox, path);

-      if (SUCCEEDED(hr) && !path->IsEmpty()) {

-        // The Firefox registry key contains a -url %1 value. Remove this

-        // because we only want to return the path.

-        ReplaceCString(*path, _T("-url \"%1\""), _T(""));

-      }

-      break;

-    }

-    case BROWSER_CHROME: {

-      hr = RegKey::GetValue(kRegKeyChrome, kRegValueChrome, path);

-      if (SUCCEEDED(hr) && !path->IsEmpty()) {

-        // The Chrome registry key contains a -- "%1" value. Remove this because

-        // we only want to return the path.

-        ReplaceCString(*path, _T("-- \"%1\""), _T(""));

-      }

-      break;

-    }

-    case BROWSER_DEFAULT: {

-      hr = GetDefaultBrowserPath(path);

-      if (FAILED(hr)) {

-        UTIL_LOG(LE, (_T("[GetDefaultBrowserPath failed.][0x%08x]"), hr));

-      }

-      path->Trim();

-      UnenclosePath(path);

-      return hr;

-    }

-    case BROWSER_UNKNOWN:

-      // Fall through.

-    case BROWSER_MAX:

-      // Fall through.

-    default:

-      return E_FAIL;

-  }

-

-  CString cmd_line(*path);

-  CString args;

-  if (SUCCEEDED(hr) &&

-      !path->IsEmpty() &&

-      SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(cmd_line,

-                                                           path,

-                                                           &args))) {

-    return S_OK;

-  }

-

-  // If the above did not work, then we try to read the value from

-  // "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths".

-  CString browser_exe_name;

-  hr = BrowserTypeToProcessName(type, &browser_exe_name);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[BrowserTypeToProcessName failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  CString exe_path;

-  hr = Shell::GetApplicationExecutablePath(browser_exe_name, &exe_path);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[GetApplicationExecutablePath failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  *path = ConcatenatePath(exe_path, browser_exe_name);

-  ASSERT1(!path->IsEmpty());

-

-  path->Trim();

-  UnenclosePath(path);

-  return S_OK;

-}

-

-HRESULT TerminateBrowserProcess(BrowserType type,

-                                const CString& sid,

-                                int timeout_msec,

-                                bool* found) {

-  UTIL_LOG(L3, (_T("[TerminateBrowserProcess][%d]"), type));

-  ASSERT1(found);

-  ASSERT1(type < BROWSER_MAX);

-

-  *found = false;

-  if (type == BROWSER_UNKNOWN || type >= BROWSER_MAX) {

-    return E_FAIL;

-  }

-

-  CString browser_exe_name;

-  HRESULT hr = BrowserTypeToProcessName(type, &browser_exe_name);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[BrowserTypeToProcessName failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  DWORD current_session = System::GetCurrentSessionId();

-  uint32 method_mask = ProcessTerminator::KILL_METHOD_1_WINDOW_MESSAGE;

-  ProcessTerminator process(browser_exe_name, sid, current_session);

-  hr = process.KillTheProcess(timeout_msec, found, method_mask, true);

-  if (FAILED(hr)) {

-    UTIL_LOG(LEVEL_WARNING, (_T("[KillTheProcess failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT WaitForBrowserToDie(BrowserType type,

-                            const CString& sid,

-                            int timeout_msec) {

-  UTIL_LOG(L3, (_T("[WaitForBrowserToDie][%d]"), type));

-  ASSERT1(type < BROWSER_MAX);

-

-  if (type == BROWSER_UNKNOWN || type >= BROWSER_MAX) {

-    return E_FAIL;

-  }

-

-  CString browser_exe_name;

-  HRESULT hr = BrowserTypeToProcessName(type, &browser_exe_name);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[BrowserTypeToProcessName failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  DWORD current_session = System::GetCurrentSessionId();

-  ProcessTerminator process(browser_exe_name, sid, current_session);

-  hr = process.WaitForAllToDie(timeout_msec);

-  if (FAILED(hr)) {

-    UTIL_LOG(LEVEL_WARNING, (_T("[WaitForAllToDie failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT ShellExecuteBrowser(BrowserType type, const CString& url) {

-  UTIL_LOG(L3, (_T("[ShellExecuteBrowser][%d][%s]"), type, url));

-  ASSERT1(type < BROWSER_MAX);

-

-  if (type == BROWSER_UNKNOWN || type >= BROWSER_MAX) {

-    return E_FAIL;

-  }

-

-  CString path;

-  HRESULT hr =  GetBrowserImagePath(type, &path);

-  if (FAILED(hr)) {

-    UTIL_LOG(LW, (_T("[GetBrowserImagePath failed][0x%08x]"), hr));

-    // ShellExecute the url directly as a last resort.

-    return Shell::Execute(url);

-  }

-  EnclosePath(&path);

-

-  UTIL_LOG(L3, (_T("[Execute browser][%s][%s]"), path, url));

-

-  // http://b/1219313: For Vista, in some cases, using ShellExecuteEx does not

-  // re-launch the process. So, using CreateProcess instead.

-  // http://b/1223658: For Vista, especially in the impersonated case, need to

-  // create a fresh environment block. Otherwise, the environment is tainted.

-  hr = vista_util::IsVistaOrLater() ?

-           vista::RunAsCurrentUser(path + _T(' ') + url) :

-           System::ShellExecuteProcess(path, url, NULL, NULL);

-

-  if (FAILED(hr)) {

-    UTIL_LOG(LW, (_T("[%s failed][0x%08x]"),

-                  vista_util::IsVistaOrLater() ? _T("RunAsCurrentUser") :

-                                                 _T("ShellExecuteProcess"),

-                  hr));

-    // ShellExecute the url directly as a last resort.

-    return Shell::Execute(url);

-  }

-

-  return S_OK;

-}

-

-// Gets the font size of IE. This is the value that corresponds to what IE

-// displays in "Page/Text Size" menu option. There are 5 values and the default

-// is "Medium", for which the numeric value is 2. The "IEFontSize" is only

-// present after the user has modified the default text size in IE, therefore

-// the absence of the value indicates "Medium" text size.

-HRESULT GetIeFontSize(uint32* font_size) {

-  ASSERT1(font_size);

-

-  const TCHAR ie_scripts_key[] =

-    _T("HKCU\\Software\\Microsoft\\Internet Explorer\\International\\Scripts\\3");  // NOLINT

-  const TCHAR ie_font_size[] = _T("IEFontSize");

-  const uint32 kDefaultFontSize = 2;

-

-  // We expect the scripts key to be there in all cases. The "IEFontSize" value

-  // is optional but we want to fail if the key is not there.

-  if (!RegKey::HasKey(ie_scripts_key)) {

-    return E_UNEXPECTED;

-  }

-

-  scoped_array<byte> buf;   // The font size is a binary registry value.

-  DWORD buf_size(0);

-  if (FAILED(RegKey::GetValue(ie_scripts_key, ie_font_size,

-                              address(buf), &buf_size))) {

-    *font_size = kDefaultFontSize;

-    return S_OK;

-  }

-

-  ASSERT1(buf_size == sizeof(uint32));  // NOLINT

-  if (buf_size != sizeof(uint32)) {     // NOLINT

-    return E_UNEXPECTED;

-  }

-

-  uint32 val = *reinterpret_cast<uint32*>(buf.get());

-  ASSERT1(val <= 4);

-  if (val > 4) {

-    return E_UNEXPECTED;

-  }

-

-  *font_size = val;

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/browser_utils.h"
+#include "base/basictypes.h"
+#include "omaha/common/commands.h"
+#include "omaha/common/const_utils.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/proc_utils.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/shell.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/common/vista_utils.h"
+
+namespace omaha {
+
+HRESULT GetLegacyDefaultBrowserInfo(CString* name, CString* path) {
+  UTIL_LOG(L3, (_T("[GetLegacyDefaultBrowserInfo]")));
+  ASSERT1(name);
+  ASSERT1(path);
+  name->Empty();
+  path->Empty();
+
+  CString browser_command_line;
+  HRESULT hr = RegKey::GetValue(kRegKeyLegacyDefaultBrowserCommand,
+                                NULL,
+                                &browser_command_line);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[Read failed][%s]"), kRegKeyLegacyDefaultBrowserCommand));
+    return hr;
+  }
+
+  UTIL_LOG(L5, (_T("[browser_command_line][%s]"), browser_command_line));
+  browser_command_line.Trim(_T(" "));
+  if (browser_command_line.IsEmpty()) {
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+
+  CString browser_path;
+  if (File::Exists(browser_command_line)) {
+    if (File::IsDirectory(browser_command_line)) {
+      UTIL_LOG(LE, (_T("[Unexpected. Command line should not be directory]")));
+      return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+    }
+
+    browser_path = browser_command_line;
+  } else {
+    hr = GetExePathFromCommandLine(browser_command_line, &browser_path);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    if (!File::Exists(browser_path) ||
+        File::IsDirectory(browser_path)) {
+      UTIL_LOG(LE, (_T("[browser_path invalid][%s]"), browser_path));
+      return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+    }
+  }
+
+  CString browser_name = ::PathFindFileName(browser_path);
+  if (browser_name.IsEmpty() ||
+      !String_EndsWith(browser_name, _T(".exe"), true)) {
+    UTIL_LOG(LE, (_T("[browser name invalid][%s]"), browser_name));
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+
+  *path = browser_path;
+  *name = browser_name;
+  return S_OK;
+}
+
+HRESULT GetDefaultBrowserName(CString* name) {
+  ASSERT1(name);
+  name->Empty();
+
+  // Get the default browser name from current user registry.
+  HKEY user_root_key = NULL;
+  VERIFY1(::RegOpenCurrentUser(KEY_READ, &user_root_key) == ERROR_SUCCESS);
+  RegKey user_default_browser;
+  HRESULT hr = user_default_browser.Open(
+      user_root_key ? user_root_key : HKEY_CURRENT_USER,
+      kRegKeyDefaultBrowser,
+      KEY_READ);
+  if (SUCCEEDED(hr)) {
+    hr = user_default_browser.GetValue(NULL, name);
+  }
+  if (user_root_key) {
+    LONG error(::RegCloseKey(user_root_key));
+
+    // See bug http://b/issue?id=1231862 for details when RegCloseKey can
+    // return ERROR_INVALID_HANDLE.
+    ASSERT1(error == ERROR_SUCCESS ||
+            error == ERROR_INVALID_HANDLE);
+  }
+
+  if (SUCCEEDED(hr) && !name->IsEmpty()) {
+    UTIL_LOG(L3, (_T("[Default browser for the user is %s]"), *name));
+    return S_OK;
+  }
+
+  // Try to get from local machine registry.
+  hr = RegKey::GetValue(kRegKeyMachineDefaultBrowser, NULL, name);
+  if (SUCCEEDED(hr) && !name->IsEmpty()) {
+    UTIL_LOG(L3, (_T("[Default browser for the machine is %s]"), *name));
+    return S_OK;
+  }
+
+  // Try to get from legacy default browser location.
+  CString browser_path;
+  hr = GetLegacyDefaultBrowserInfo(name, &browser_path);
+  if (SUCCEEDED(hr) && !name->IsEmpty()) {
+    UTIL_LOG(L3, (_T("[Legacy default browser is %s]"), *name));
+    return S_OK;
+  }
+
+  // If still failed, we don't want to break in this case so we default to
+  // IEXPLORE.EXE. A scenario where this can happen is when the user installs
+  // a browser that configures itself to be default. Then the user uninstalls
+  // or somehow removes that browser and the registry is not updated correctly.
+  *name = kIeExeName;
+  return S_OK;
+}
+
+HRESULT GetDefaultBrowserType(BrowserType* type) {
+  ASSERT1(type);
+
+  CString name;
+  HRESULT hr = GetDefaultBrowserName(&name);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (name.CompareNoCase(kIeExeName) == 0) {
+    *type = BROWSER_IE;
+  } else if (name.CompareNoCase(kFirefoxExeName) == 0) {
+    *type = BROWSER_FIREFOX;
+  } else if (name.CompareNoCase(kChromeExeName) == 0) {
+    *type = BROWSER_CHROME;
+  } else {
+    *type = BROWSER_UNKNOWN;
+  }
+
+  return S_OK;
+}
+
+// Returns a path that is always unenclosed. The method could return a short or
+// long form path.
+HRESULT GetDefaultBrowserPath(CString* path) {
+  ASSERT1(path);
+  path->Empty();
+  ON_SCOPE_EXIT(UnenclosePath, path);
+
+  // Get the default browser name.
+  CString name;
+  if (FAILED(GetDefaultBrowserName(&name))) {
+    // Try getting IE's path through COM registration and app path entries.
+    return GetBrowserImagePath(BROWSER_IE, path);
+  }
+
+  CString shell_open_path(_T("\\"));
+  shell_open_path += name;
+  shell_open_path += kRegKeyShellOpenCommand;
+
+  // Read the path corresponding to it from current user registry.
+  CString browser_key(kRegKeyUserDefaultBrowser);
+  browser_key += shell_open_path;
+  HRESULT hr = RegKey::GetValue(browser_key, NULL, path);
+
+  CString cmd_line(*path);
+  CString args;
+  if (SUCCEEDED(hr) &&
+      !path->IsEmpty() &&
+      SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(cmd_line,
+                                                           path,
+                                                           &args))) {
+    return S_OK;
+  }
+
+  // If failed, try to get from local machine registry.
+  browser_key = kRegKeyMachineDefaultBrowser;
+  browser_key += shell_open_path;
+  hr = RegKey::GetValue(browser_key, NULL, path);
+
+  cmd_line = *path;
+  args.Empty();
+  if (SUCCEEDED(hr) &&
+      !path->IsEmpty() &&
+      SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(cmd_line,
+                                                           path,
+                                                           &args))) {
+    return S_OK;
+  }
+
+  // Try to get from legacy default browser location.
+  hr = GetLegacyDefaultBrowserInfo(&name, path);
+  if (SUCCEEDED(hr) && !path->IsEmpty()) {
+    return S_OK;
+  }
+
+  // If failed and the default browser is not IE, try IE once again.
+  if (name.CompareNoCase(kIeExeName) != 0) {
+    browser_key = kRegKeyMachineDefaultBrowser
+                  _T("\\") kIeExeName kRegKeyShellOpenCommand;
+    hr = RegKey::GetValue(browser_key, NULL, path);
+
+    cmd_line = *path;
+    args.Empty();
+    if (SUCCEEDED(hr) &&
+        !path->IsEmpty() &&
+        SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(cmd_line,
+                                                             path,
+                                                             &args))) {
+      return S_OK;
+    }
+  }
+
+  // Try getting the default browser's path through COM registration and app
+  // path entries.
+  BrowserType default_type = BROWSER_UNKNOWN;
+  hr = GetDefaultBrowserType(&default_type);
+  if (FAILED(hr) ||
+      default_type == BROWSER_UNKNOWN ||
+      default_type == BROWSER_DEFAULT) {
+    default_type = BROWSER_IE;
+  }
+
+  return GetBrowserImagePath(default_type, path);
+}
+
+HRESULT GetFirefoxDefaultProfile(CString* name, CString* path) {
+  ASSERT1(name);
+  ASSERT1(path);
+
+  const TCHAR kFirefoxAppDataPath[] = _T("\\Mozilla\\Firefox\\");
+  const TCHAR kFirefoxProfileIni[] = _T("profiles.ini");
+  const TCHAR kFirefoxDefaultProfileSecName[] = _T("Profile0");
+  const TCHAR kFirefoxProfileIniNameKey[] = _T("Name");
+  const TCHAR kFirefoxProfileIniIsRelativeKey[] = _T("IsRelative");
+  const TCHAR kFirefoxProfileIniPathKey[] = _T("Path");
+  const TCHAR kFirefoxProfileIniDefaultKey[] = _T("Default");
+
+  name->Empty();
+  path->Empty();
+
+  // Get appdata path for storing Firefox settings.
+  CString appdata_path;
+  RET_IF_FAILED(Shell::GetSpecialFolder(CSIDL_APPDATA, false, &appdata_path));
+  appdata_path += kFirefoxAppDataPath;
+
+  // Get profile.ini.
+  CString profile_ini = appdata_path + kFirefoxProfileIni;
+  UTIL_LOG(L3, (_T("[FireFox profile.ini][%s]"), profile_ini));
+
+  if (!File::Exists(profile_ini)) {
+    UTIL_LOG(LE, (_T("[File does not exist][%s]"), profile_ini));
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+
+  // Read all section names in profile.ini.
+  // The buffer is filled with one or more null-terminated strings; the last
+  // string is followed by a second null character.
+  const int kMaxProfileSecNamesLength = 2048;
+  CString profile_sec_names;
+  DWORD char_returned = ::GetPrivateProfileSectionNames(
+      profile_sec_names.GetBufferSetLength(kMaxProfileSecNamesLength),
+      kMaxProfileSecNamesLength,
+      profile_ini);
+  if (char_returned == kMaxProfileSecNamesLength - 2) {
+    UTIL_LOG(LW, (_T("[FireFox profile.ini contains too many sections]")));
+  }
+  profile_sec_names.ReleaseBuffer(char_returned);
+
+  // Iterate through all the sections to find the default profile.
+  const TCHAR* default_profile_sec = NULL;
+  const TCHAR* ptr = profile_sec_names.GetString();
+  const TCHAR* end = ptr + char_returned;
+  while (ptr < end && *ptr) {
+    if (::GetPrivateProfileInt(ptr,
+                               kFirefoxProfileIniDefaultKey,
+                               0,
+                               profile_ini)) {
+      default_profile_sec = ptr;
+      break;
+    }
+
+    for (; ptr < end && *ptr; ++ptr) {
+    }
+    ++ptr;
+  }
+
+  if (!default_profile_sec) {
+    default_profile_sec = kFirefoxDefaultProfileSecName;
+  }
+
+  DWORD name_len = ::GetPrivateProfileString(default_profile_sec,
+                                             kFirefoxProfileIniNameKey, _T(""),
+                                             name->GetBufferSetLength(256),
+                                             256,
+                                             profile_ini);
+  name->ReleaseBuffer(name_len);
+
+  DWORD path_len = ::GetPrivateProfileString(default_profile_sec,
+                                             kFirefoxProfileIniPathKey,
+                                             _T(""),
+                                             path->GetBufferSetLength(1024),
+                                             1024,
+                                             profile_ini);
+  path->ReleaseBuffer(path_len);
+  path->Replace(_T('/'), _T('\\'));
+
+  bool is_relative = ::GetPrivateProfileInt(default_profile_sec,
+                                            kFirefoxProfileIniIsRelativeKey,
+                                            0,
+                                            profile_ini) != 0;
+
+  if (is_relative && !path->IsEmpty()) {
+    path->Insert(0, appdata_path);
+  }
+
+  return S_OK;
+}
+
+HRESULT BrowserTypeToProcessName(BrowserType type, CString* exe_name) {
+  ASSERT1(exe_name);
+  ASSERT1(type < BROWSER_MAX);
+
+  switch (type) {
+    case BROWSER_IE:
+      *exe_name = kIeExeName;
+      break;
+    case BROWSER_FIREFOX:
+      *exe_name = kFirefoxExeName;
+      break;
+    case BROWSER_CHROME:
+      *exe_name = kChromeExeName;
+      break;
+    case BROWSER_DEFAULT:
+      return GetDefaultBrowserName(exe_name);
+    case BROWSER_UNKNOWN:
+      // Fall through.
+    case BROWSER_MAX:
+      // Fall through.
+    default:
+      return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+// Returns a path that is always unenclosed. The method could return a short or
+// long form path.
+HRESULT GetBrowserImagePath(BrowserType type, CString* path) {
+  ASSERT1(path);
+  ASSERT1(type < BROWSER_MAX);
+
+  HRESULT hr = E_FAIL;
+  switch (type) {
+    case BROWSER_IE: {
+      hr = RegKey::GetValue(kRegKeyIeClass, kRegValueIeClass, path);
+      break;
+    }
+    case BROWSER_FIREFOX: {
+      hr = RegKey::GetValue(kRegKeyFirefox, kRegValueFirefox, path);
+      if (SUCCEEDED(hr) && !path->IsEmpty()) {
+        // The Firefox registry key contains a -url %1 value. Remove this
+        // because we only want to return the path.
+        ReplaceCString(*path, _T("-url \"%1\""), _T(""));
+      }
+      break;
+    }
+    case BROWSER_CHROME: {
+      hr = RegKey::GetValue(kRegKeyChrome, kRegValueChrome, path);
+      if (SUCCEEDED(hr) && !path->IsEmpty()) {
+        // The Chrome registry key contains a -- "%1" value. Remove this because
+        // we only want to return the path.
+        ReplaceCString(*path, _T("-- \"%1\""), _T(""));
+      }
+      break;
+    }
+    case BROWSER_DEFAULT: {
+      hr = GetDefaultBrowserPath(path);
+      if (FAILED(hr)) {
+        UTIL_LOG(LE, (_T("[GetDefaultBrowserPath failed.][0x%08x]"), hr));
+      }
+      path->Trim();
+      UnenclosePath(path);
+      return hr;
+    }
+    case BROWSER_UNKNOWN:
+      // Fall through.
+    case BROWSER_MAX:
+      // Fall through.
+    default:
+      return E_FAIL;
+  }
+
+  CString cmd_line(*path);
+  CString args;
+  if (SUCCEEDED(hr) &&
+      !path->IsEmpty() &&
+      SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(cmd_line,
+                                                           path,
+                                                           &args))) {
+    return S_OK;
+  }
+
+  // If the above did not work, then we try to read the value from
+  // "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths".
+  CString browser_exe_name;
+  hr = BrowserTypeToProcessName(type, &browser_exe_name);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[BrowserTypeToProcessName failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  CString exe_path;
+  hr = Shell::GetApplicationExecutablePath(browser_exe_name, &exe_path);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[GetApplicationExecutablePath failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  *path = ConcatenatePath(exe_path, browser_exe_name);
+  ASSERT1(!path->IsEmpty());
+
+  path->Trim();
+  UnenclosePath(path);
+  return S_OK;
+}
+
+HRESULT TerminateBrowserProcess(BrowserType type,
+                                const CString& sid,
+                                int timeout_msec,
+                                bool* found) {
+  UTIL_LOG(L3, (_T("[TerminateBrowserProcess][%d]"), type));
+  ASSERT1(found);
+  ASSERT1(type < BROWSER_MAX);
+
+  *found = false;
+  if (type == BROWSER_UNKNOWN || type >= BROWSER_MAX) {
+    return E_FAIL;
+  }
+
+  CString browser_exe_name;
+  HRESULT hr = BrowserTypeToProcessName(type, &browser_exe_name);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[BrowserTypeToProcessName failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  DWORD current_session = System::GetCurrentSessionId();
+  uint32 method_mask = ProcessTerminator::KILL_METHOD_1_WINDOW_MESSAGE;
+  ProcessTerminator process(browser_exe_name, sid, current_session);
+  hr = process.KillTheProcess(timeout_msec, found, method_mask, true);
+  if (FAILED(hr)) {
+    UTIL_LOG(LEVEL_WARNING, (_T("[KillTheProcess failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT WaitForBrowserToDie(BrowserType type,
+                            const CString& sid,
+                            int timeout_msec) {
+  UTIL_LOG(L3, (_T("[WaitForBrowserToDie][%d]"), type));
+  ASSERT1(type < BROWSER_MAX);
+
+  if (type == BROWSER_UNKNOWN || type >= BROWSER_MAX) {
+    return E_FAIL;
+  }
+
+  CString browser_exe_name;
+  HRESULT hr = BrowserTypeToProcessName(type, &browser_exe_name);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[BrowserTypeToProcessName failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  DWORD current_session = System::GetCurrentSessionId();
+  ProcessTerminator process(browser_exe_name, sid, current_session);
+  hr = process.WaitForAllToDie(timeout_msec);
+  if (FAILED(hr)) {
+    UTIL_LOG(LEVEL_WARNING, (_T("[WaitForAllToDie failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT ShellExecuteBrowser(BrowserType type, const CString& url) {
+  UTIL_LOG(L3, (_T("[ShellExecuteBrowser][%d][%s]"), type, url));
+  ASSERT1(type < BROWSER_MAX);
+
+  if (type == BROWSER_UNKNOWN || type >= BROWSER_MAX) {
+    return E_FAIL;
+  }
+
+  CString path;
+  HRESULT hr =  GetBrowserImagePath(type, &path);
+  if (FAILED(hr)) {
+    UTIL_LOG(LW, (_T("[GetBrowserImagePath failed][0x%08x]"), hr));
+    // ShellExecute the url directly as a last resort.
+    return Shell::Execute(url);
+  }
+  EnclosePath(&path);
+
+  UTIL_LOG(L3, (_T("[Execute browser][%s][%s]"), path, url));
+
+  // http://b/1219313: For Vista, in some cases, using ShellExecuteEx does not
+  // re-launch the process. So, using CreateProcess instead.
+  // http://b/1223658: For Vista, especially in the impersonated case, need to
+  // create a fresh environment block. Otherwise, the environment is tainted.
+  hr = vista_util::IsVistaOrLater() ?
+           vista::RunAsCurrentUser(path + _T(' ') + url) :
+           System::ShellExecuteProcess(path, url, NULL, NULL);
+
+  if (FAILED(hr)) {
+    UTIL_LOG(LW, (_T("[%s failed][0x%08x]"),
+                  vista_util::IsVistaOrLater() ? _T("RunAsCurrentUser") :
+                                                 _T("ShellExecuteProcess"),
+                  hr));
+    // ShellExecute the url directly as a last resort.
+    return Shell::Execute(url);
+  }
+
+  return S_OK;
+}
+
+// Gets the font size of IE. This is the value that corresponds to what IE
+// displays in "Page/Text Size" menu option. There are 5 values and the default
+// is "Medium", for which the numeric value is 2. The "IEFontSize" is only
+// present after the user has modified the default text size in IE, therefore
+// the absence of the value indicates "Medium" text size.
+HRESULT GetIeFontSize(uint32* font_size) {
+  ASSERT1(font_size);
+
+  const TCHAR ie_scripts_key[] =
+    _T("HKCU\\Software\\Microsoft\\Internet Explorer\\International\\Scripts\\3");  // NOLINT
+  const TCHAR ie_font_size[] = _T("IEFontSize");
+  const uint32 kDefaultFontSize = 2;
+
+  // We expect the scripts key to be there in all cases. The "IEFontSize" value
+  // is optional but we want to fail if the key is not there.
+  if (!RegKey::HasKey(ie_scripts_key)) {
+    return E_UNEXPECTED;
+  }
+
+  scoped_array<byte> buf;   // The font size is a binary registry value.
+  DWORD buf_size(0);
+  if (FAILED(RegKey::GetValue(ie_scripts_key, ie_font_size,
+                              address(buf), &buf_size))) {
+    *font_size = kDefaultFontSize;
+    return S_OK;
+  }
+
+  ASSERT1(buf_size == sizeof(uint32));  // NOLINT
+  if (buf_size != sizeof(uint32)) {     // NOLINT
+    return E_UNEXPECTED;
+  }
+
+  uint32 val = *reinterpret_cast<uint32*>(buf.get());
+  ASSERT1(val <= 4);
+  if (val > 4) {
+    return E_UNEXPECTED;
+  }
+
+  *font_size = val;
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/common/browser_utils.h b/common/browser_utils.h
index 38f35a1..400b123 100644
--- a/common/browser_utils.h
+++ b/common/browser_utils.h
@@ -1,90 +1,90 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// TODO(omaha): namespaces

-

-#ifndef OMAHA_COMMON_BROWSER_UTILS_H__

-#define OMAHA_COMMON_BROWSER_UTILS_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// Do not move or remove existing elements as this is used by applications.

-enum BrowserType {

-  BROWSER_UNKNOWN = 0,

-  BROWSER_DEFAULT = 1,

-  BROWSER_IE      = 2,

-  BROWSER_FIREFOX = 3,

-  BROWSER_CHROME  = 4,

-  // Add all browsers above this.

-  BROWSER_MAX

-};

-

-// Read the browser information from legacy keys. See

-// http://support.microsoft.com/kb/224816.

-HRESULT GetLegacyDefaultBrowserInfo(CString* name, CString* browser_path);

-

-// Gets the default browser name.

-// When calling this method from the local system account, the caller must

-// impersonate the user first. This assumes the user profile is loaded under

-// HKEY_USERS, which is true if the user has an interactive session.

-// Otherwise, the caller must load the profile for the user before

-// calling the function.

-HRESULT GetDefaultBrowserName(CString* name);

-

-// Returns the default browser type.

-HRESULT GetDefaultBrowserType(BrowserType* type);

-

-// Get the default browser path

-HRESULT GetDefaultBrowserPath(CString* path);

-

-// Get the default profile of Firefox

-HRESULT GetFirefoxDefaultProfile(CString* name, CString* path);

-

-// Returns the executable name corresponding to the browser type.

-HRESULT BrowserTypeToProcessName(BrowserType type, CString* exe_name);

-

-// Returns the absolute filename of the browser executable.

-HRESULT GetBrowserImagePath(BrowserType type, CString* path);

-

-// Terminates all the browsers identified by type for a user.

-HRESULT TerminateBrowserProcess(BrowserType type,

-                                const CString& sid,

-                                int timeout_msec,

-                                bool* found);

-

-// Waits for all instances of browser to die.

-HRESULT WaitForBrowserToDie(BrowserType type,

-                            const CString& sid,

-                            int timeout_msec);

-

-// Launches the browser using shell execute.

-HRESULT ShellExecuteBrowser(BrowserType type, const CString& url);

-

-// Returns the current font size selection in Internet Explorer.

-// Possible font size values:

-// 0 : smallest font

-// 1 : small font

-// 2 : medium font

-// 3 : large font

-// 4 : largest font

-HRESULT GetIeFontSize(uint32* font_size);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_BROWSER_UTILS_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// TODO(omaha): namespaces
+
+#ifndef OMAHA_COMMON_BROWSER_UTILS_H__
+#define OMAHA_COMMON_BROWSER_UTILS_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// Do not move or remove existing elements as this is used by applications.
+enum BrowserType {
+  BROWSER_UNKNOWN = 0,
+  BROWSER_DEFAULT = 1,
+  BROWSER_IE      = 2,
+  BROWSER_FIREFOX = 3,
+  BROWSER_CHROME  = 4,
+  // Add all browsers above this.
+  BROWSER_MAX
+};
+
+// Read the browser information from legacy keys. See
+// http://support.microsoft.com/kb/224816.
+HRESULT GetLegacyDefaultBrowserInfo(CString* name, CString* browser_path);
+
+// Gets the default browser name.
+// When calling this method from the local system account, the caller must
+// impersonate the user first. This assumes the user profile is loaded under
+// HKEY_USERS, which is true if the user has an interactive session.
+// Otherwise, the caller must load the profile for the user before
+// calling the function.
+HRESULT GetDefaultBrowserName(CString* name);
+
+// Returns the default browser type.
+HRESULT GetDefaultBrowserType(BrowserType* type);
+
+// Get the default browser path
+HRESULT GetDefaultBrowserPath(CString* path);
+
+// Get the default profile of Firefox
+HRESULT GetFirefoxDefaultProfile(CString* name, CString* path);
+
+// Returns the executable name corresponding to the browser type.
+HRESULT BrowserTypeToProcessName(BrowserType type, CString* exe_name);
+
+// Returns the absolute filename of the browser executable.
+HRESULT GetBrowserImagePath(BrowserType type, CString* path);
+
+// Terminates all the browsers identified by type for a user.
+HRESULT TerminateBrowserProcess(BrowserType type,
+                                const CString& sid,
+                                int timeout_msec,
+                                bool* found);
+
+// Waits for all instances of browser to die.
+HRESULT WaitForBrowserToDie(BrowserType type,
+                            const CString& sid,
+                            int timeout_msec);
+
+// Launches the browser using shell execute.
+HRESULT ShellExecuteBrowser(BrowserType type, const CString& url);
+
+// Returns the current font size selection in Internet Explorer.
+// Possible font size values:
+// 0 : smallest font
+// 1 : small font
+// 2 : medium font
+// 3 : large font
+// 4 : largest font
+HRESULT GetIeFontSize(uint32* font_size);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_BROWSER_UTILS_H__
diff --git a/common/browser_utils_unittest.cc b/common/browser_utils_unittest.cc
index ab79fa1..801442b 100644
--- a/common/browser_utils_unittest.cc
+++ b/common/browser_utils_unittest.cc
@@ -1,378 +1,378 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/const_utils.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-const CString kRegistryHiveOverrideClasses =

-    CString(kRegistryHiveOverrideRoot) + _T("HKCR");

-

-// GetDefaultBrowserName() uses ::RegOpenCurrentUser, which does not appear to

-// be affected by registry hive overrides. Therefore, in order to test methods

-// that rely on it, the actual value must be replaced. This class saves the

-// value and restores it. If the test is interrupted before TearDown, the

-// default browser may not be correctly registered.

-class BrowserUtilsDefaultBrowserSavedTest : public testing::Test {

- protected:

-  virtual void SetUp() {

-    if (!RegKey::HasKey(kRegKeyUserDefaultBrowser)) {

-      return;

-    }

-

-    EXPECT_SUCCEEDED(RegKey::GetValue(kRegKeyUserDefaultBrowser,

-                                      NULL,

-                                      &default_browser_name_));

-  }

-

-  virtual void TearDown() {

-    if (default_browser_name_.IsEmpty()) {

-      RegKey::DeleteKey(kRegKeyUserDefaultBrowser);

-      return;

-    }

-

-    EXPECT_SUCCEEDED(RegKey::SetValue(kRegKeyUserDefaultBrowser,

-                                      NULL,

-                                      default_browser_name_));

-  }

-

-  CString default_browser_name_;

-};

-

-class GetLegacyDefaultBrowserInfoTest : public testing::Test {

- protected:

-  virtual void SetUp() {

-    RegKey::DeleteKey(kRegistryHiveOverrideClasses, true);

-    RegKey classes_key;

-    ASSERT_HRESULT_SUCCEEDED(classes_key.Create(kRegistryHiveOverrideClasses));

-    ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_CLASSES_ROOT,

-                                                    classes_key.Key()));

-  }

-

-  virtual void TearDown() {

-    ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_CLASSES_ROOT, NULL));

-    ASSERT_HRESULT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideClasses,

-                             true));

-  }

-};

-

-TEST_F(BrowserUtilsDefaultBrowserSavedTest, GetDefaultBrowserType_IE) {

-  if (!ShouldRunLargeTest()) {

-    return;

-  }

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyUserDefaultBrowser, NULL, _T("IeXpLoRe.ExE")));

-  BrowserType type = BROWSER_UNKNOWN;

-  EXPECT_SUCCEEDED(GetDefaultBrowserType(&type));

-  EXPECT_EQ(BROWSER_IE, type);

-}

-

-TEST_F(BrowserUtilsDefaultBrowserSavedTest, GetDefaultBrowserType_Firefox) {

-  if (!ShouldRunLargeTest()) {

-    return;

-  }

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyUserDefaultBrowser, NULL, _T("FiReFoX.ExE")));

-  BrowserType type = BROWSER_UNKNOWN;

-  EXPECT_SUCCEEDED(GetDefaultBrowserType(&type));

-  EXPECT_EQ(BROWSER_FIREFOX, type);

-}

-

-TEST_F(BrowserUtilsDefaultBrowserSavedTest, GetDefaultBrowserType_Chrome) {

-  if (!ShouldRunLargeTest()) {

-    return;

-  }

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyUserDefaultBrowser, NULL, _T("ChRoMe.ExE")));

-  BrowserType type = BROWSER_UNKNOWN;

-  EXPECT_SUCCEEDED(GetDefaultBrowserType(&type));

-  EXPECT_EQ(BROWSER_CHROME, type);

-}

-

-TEST_F(BrowserUtilsDefaultBrowserSavedTest, GetDefaultBrowserType_Unsupported) {

-  if (!ShouldRunLargeTest()) {

-    return;

-  }

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyUserDefaultBrowser, NULL, _T("FoO.ExE")));

-  BrowserType type = BROWSER_UNKNOWN;

-  EXPECT_SUCCEEDED(GetDefaultBrowserType(&type));

-  EXPECT_EQ(BROWSER_UNKNOWN, type);

-}

-

-TEST(BrowserUtilsTest, BrowserTypeToProcessName_Unknown) {

-  CString exe_name;

-  EXPECT_EQ(E_FAIL, BrowserTypeToProcessName(BROWSER_UNKNOWN, &exe_name));

-  EXPECT_TRUE(exe_name.IsEmpty());

-}

-

-// Writes the default browser to ensure consistent results.

-TEST_F(BrowserUtilsDefaultBrowserSavedTest, BrowserTypeToProcessName_Default) {

-  if (!ShouldRunLargeTest()) {

-    return;

-  }

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyUserDefaultBrowser, NULL, _T("IeXpLoRe.ExE")));

-

-  CString default_exe_name;

-  EXPECT_SUCCEEDED(GetDefaultBrowserName(&default_exe_name));

-  EXPECT_STREQ(_T("IeXpLoRe.ExE"), default_exe_name);

-

-  CString exe_name;

-  EXPECT_SUCCEEDED(BrowserTypeToProcessName(BROWSER_DEFAULT, &exe_name));

-  EXPECT_STREQ(_T("IeXpLoRe.ExE"), exe_name);

-}

-

-TEST(BrowserUtilsTest, BrowserTypeToProcessName_Browsers) {

-  CString exe_name;

-  EXPECT_SUCCEEDED(BrowserTypeToProcessName(BROWSER_IE, &exe_name));

-  EXPECT_STREQ(_T("IEXPLORE.EXE"), exe_name);

-  EXPECT_SUCCEEDED(BrowserTypeToProcessName(BROWSER_FIREFOX, &exe_name));

-  EXPECT_STREQ(_T("FIREFOX.EXE"), exe_name);

-  EXPECT_SUCCEEDED(BrowserTypeToProcessName(BROWSER_CHROME, &exe_name));

-  EXPECT_STREQ(_T("CHROME.EXE"), exe_name);

-}

-

-TEST(BrowserUtilsTest, BrowserTypeToProcessName_Invalid) {

-  CString exe_name;

-  ExpectAsserts expect_asserts;

-  EXPECT_EQ(E_FAIL, BrowserTypeToProcessName(BROWSER_MAX, &exe_name));

-  EXPECT_TRUE(exe_name.IsEmpty());

-  EXPECT_EQ(E_FAIL,

-            BrowserTypeToProcessName(static_cast<BrowserType>(9), &exe_name));

-  EXPECT_TRUE(exe_name.IsEmpty());

-  EXPECT_EQ(E_FAIL,

-            BrowserTypeToProcessName(static_cast<BrowserType>(-1), &exe_name));

-  EXPECT_TRUE(exe_name.IsEmpty());

-}

-

-TEST(BrowserUtilsTest, GetBrowserImagePath_DefaultBrowser) {

-  CString browser;

-  ASSERT_SUCCEEDED(GetDefaultBrowserName(&browser));

-

-  BrowserType default_type = BROWSER_UNKNOWN;

-  if (browser.CompareNoCase(kIeExeName) == 0) {

-    default_type = BROWSER_IE;

-  } else if (browser.CompareNoCase(kFirefoxExeName) == 0) {

-    default_type = BROWSER_FIREFOX;

-  } else if (browser.CompareNoCase(kChromeExeName) == 0) {

-    default_type = BROWSER_CHROME;

-  }

-

-  CString exp_browser_path;

-  ASSERT_SUCCEEDED(GetDefaultBrowserPath(&exp_browser_path));

-

-  if (default_type == BROWSER_IE) {

-    CString path;

-    ASSERT_SUCCEEDED(GetBrowserImagePath(BROWSER_IE, &path));

-

-    CString long_name;

-    ASSERT_SUCCEEDED(ShortPathToLongPath(path, &long_name));

-    CString exp_long_name;

-    ASSERT_SUCCEEDED(ShortPathToLongPath(exp_browser_path, &exp_long_name));

-    ASSERT_STREQ(exp_long_name.MakeLower(), long_name.MakeLower());

-  } else if (default_type == BROWSER_FIREFOX) {

-    CString path;

-    ASSERT_SUCCEEDED(GetBrowserImagePath(BROWSER_FIREFOX, &path));

-

-    CString long_name;

-    ASSERT_SUCCEEDED(ShortPathToLongPath(path, &long_name));

-    CString exp_long_name;

-    ASSERT_SUCCEEDED(ShortPathToLongPath(exp_browser_path, &exp_long_name));

-    ASSERT_STREQ(exp_long_name.MakeLower(), long_name.MakeLower());

-  } else if (default_type == BROWSER_CHROME) {

-    CString path;

-    ASSERT_SUCCEEDED(GetBrowserImagePath(BROWSER_CHROME, &path));

-

-    CString long_name;

-    ASSERT_SUCCEEDED(ShortPathToLongPath(path, &long_name));

-    CString exp_long_name;

-    ASSERT_SUCCEEDED(ShortPathToLongPath(exp_browser_path, &exp_long_name));

-    ASSERT_STREQ(exp_long_name.MakeLower(), long_name.MakeLower());

-  }

-

-  CString path;

-  ASSERT_SUCCEEDED(GetBrowserImagePath(BROWSER_DEFAULT, &path));

-  CString long_name;

-  ASSERT_SUCCEEDED(ShortPathToLongPath(path, &long_name));

-  CString exp_long_name;

-  ASSERT_SUCCEEDED(ShortPathToLongPath(exp_browser_path, &exp_long_name));

-  ASSERT_STREQ(exp_long_name.MakeLower(), long_name.MakeLower());

-

-  ASSERT_FAILED(GetBrowserImagePath(BROWSER_UNKNOWN, &path));

-}

-

-// Try all browsers to get more test coverage.

-TEST(BrowserUtilsTest, GetBrowserImagePath_AllSupportedBrowsers) {

-  CString path;

-

-  HRESULT hr = GetBrowserImagePath(BROWSER_IE, &path);

-  if (SUCCEEDED(hr)) {

-    EXPECT_EQ(0, path.CompareNoCase(

-                     _T("C:\\Program Files\\Internet Explorer\\iexplore.exe")))

-        << _T("Actual path: ") << path.GetString();

-  } else {

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);

-  }

-

-  hr = GetBrowserImagePath(BROWSER_FIREFOX, &path);

-  if (SUCCEEDED(hr)) {

-    EXPECT_TRUE(

-        0 == path.CompareNoCase(

-            _T("C:\\Program Files\\Mozilla Firefox\\firefox.exe")) ||

-        0 == path.CompareNoCase(

-            _T("C:\\PROGRA~1\\MOZILL~1\\FIREFOX.EXE")))

-        << _T("Actual path: ") << path.GetString();

-  } else {

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);

-  }

-

-  hr = GetBrowserImagePath(BROWSER_CHROME, &path);

-  if (SUCCEEDED(hr)) {

-    EXPECT_TRUE(

-        0 == path.CompareNoCase(

-            _T("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe")) ||

-        0 == path.CompareNoCase(

-            GetLocalAppDataPath() +

-            _T("Google\\Chrome\\Application\\chrome.exe")))

-        << _T("Actual path: ") << path.GetString();

-  } else {

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);

-  }

-}

-

-TEST(BrowserUtilsTest, GetLegacyDefaultBrowserInfo) {

-  CString name;

-  CString browser_path;

-  EXPECT_SUCCEEDED(GetLegacyDefaultBrowserInfo(&name, &browser_path));

-  EXPECT_FALSE(browser_path.IsEmpty());

-  EXPECT_FALSE(name.IsEmpty());

-}

-

-TEST(BrowserUtilsTest, GetIeFontSize) {

-  // The build server might not have IE configured.

-  if (!IsBuildSystem()) {

-    uint32 font_size = 0;

-    const uint32 kMaxFontSize = 4;

-    EXPECT_SUCCEEDED(GetIeFontSize(&font_size));

-    EXPECT_LE(font_size, kMaxFontSize);

-  }

-}

-

-TEST_F(GetLegacyDefaultBrowserInfoTest, ValidQuotedIE) {

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(

-      kRegKeyLegacyDefaultBrowserCommand,

-      NULL,

-      _T("\"C:\\Program Files\\Internet Explorer\\iexplore.exe\" -nohome")));

-

-  CString name;

-  CString browser_path;

-  EXPECT_SUCCEEDED(GetLegacyDefaultBrowserInfo(&name, &browser_path));

-  EXPECT_STREQ(_T("C:\\Program Files\\Internet Explorer\\iexplore.exe"),

-               browser_path);

-  EXPECT_STREQ(_T("iexplore.exe"), name);

-}

-

-TEST_F(GetLegacyDefaultBrowserInfoTest, ValidUnquotedPath) {

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(

-      kRegKeyLegacyDefaultBrowserCommand,

-      NULL,

-      _T("C:\\Program Files\\Internet Explorer\\iexplore.exe")));

-

-  CString name;

-  CString browser_path;

-  EXPECT_SUCCEEDED(GetLegacyDefaultBrowserInfo(&name, &browser_path));

-  EXPECT_STREQ(_T("C:\\Program Files\\Internet Explorer\\iexplore.exe"),

-               browser_path);

-  EXPECT_STREQ(_T("iexplore.exe"), name);

-}

-

-TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidNoKey) {

-  CString name;

-  CString browser_path;

-  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));

-  EXPECT_TRUE(browser_path.IsEmpty());

-  EXPECT_TRUE(name.IsEmpty());

-}

-

-TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidNoValue) {

-  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKey(

-      kRegKeyLegacyDefaultBrowserCommand));

-

-  CString name;

-  CString browser_path;

-  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));

-  EXPECT_TRUE(browser_path.IsEmpty());

-  EXPECT_TRUE(name.IsEmpty());

-}

-

-TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidPath) {

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(

-      kRegKeyLegacyDefaultBrowserCommand,

-      NULL,

-      _T("\"C:\\Program File\\iexplore.exe\" -nohome")));

-

-  CString name;

-  CString browser_path;

-  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));

-  EXPECT_TRUE(browser_path.IsEmpty());

-  EXPECT_TRUE(name.IsEmpty());

-}

-

-TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidUnquotedPath) {

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(

-      kRegKeyLegacyDefaultBrowserCommand,

-      NULL,

-      _T("C:\\Program Files\\Internet Explorer\\iexplore.exe -nohome")));

-

-  CString name;

-  CString browser_path;

-  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));

-  EXPECT_TRUE(browser_path.IsEmpty());

-  EXPECT_TRUE(name.IsEmpty());

-}

-

-TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidUnquotedDirectory) {

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(

-      kRegKeyLegacyDefaultBrowserCommand,

-      NULL,

-      _T("C:\\Program Files\\Internet Explorer\\")));

-

-  CString name;

-  CString browser_path;

-  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));

-  EXPECT_TRUE(browser_path.IsEmpty());

-  EXPECT_TRUE(name.IsEmpty());

-}

-

-TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidQuotedDirectory) {

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(

-      kRegKeyLegacyDefaultBrowserCommand,

-      NULL,

-      _T("\"C:\\Program Files\\Internet Explorer\\\" -nohome")));

-

-  CString name;

-  CString browser_path;

-  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));

-  EXPECT_TRUE(browser_path.IsEmpty());

-  EXPECT_TRUE(name.IsEmpty());

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/const_utils.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+const CString kRegistryHiveOverrideClasses =
+    CString(kRegistryHiveOverrideRoot) + _T("HKCR");
+
+// GetDefaultBrowserName() uses ::RegOpenCurrentUser, which does not appear to
+// be affected by registry hive overrides. Therefore, in order to test methods
+// that rely on it, the actual value must be replaced. This class saves the
+// value and restores it. If the test is interrupted before TearDown, the
+// default browser may not be correctly registered.
+class BrowserUtilsDefaultBrowserSavedTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    if (!RegKey::HasKey(kRegKeyUserDefaultBrowser)) {
+      return;
+    }
+
+    EXPECT_SUCCEEDED(RegKey::GetValue(kRegKeyUserDefaultBrowser,
+                                      NULL,
+                                      &default_browser_name_));
+  }
+
+  virtual void TearDown() {
+    if (default_browser_name_.IsEmpty()) {
+      RegKey::DeleteKey(kRegKeyUserDefaultBrowser);
+      return;
+    }
+
+    EXPECT_SUCCEEDED(RegKey::SetValue(kRegKeyUserDefaultBrowser,
+                                      NULL,
+                                      default_browser_name_));
+  }
+
+  CString default_browser_name_;
+};
+
+class GetLegacyDefaultBrowserInfoTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    RegKey::DeleteKey(kRegistryHiveOverrideClasses, true);
+    RegKey classes_key;
+    ASSERT_HRESULT_SUCCEEDED(classes_key.Create(kRegistryHiveOverrideClasses));
+    ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_CLASSES_ROOT,
+                                                    classes_key.Key()));
+  }
+
+  virtual void TearDown() {
+    ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_CLASSES_ROOT, NULL));
+    ASSERT_HRESULT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideClasses,
+                             true));
+  }
+};
+
+TEST_F(BrowserUtilsDefaultBrowserSavedTest, GetDefaultBrowserType_IE) {
+  if (!ShouldRunLargeTest()) {
+    return;
+  }
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyUserDefaultBrowser, NULL, _T("IeXpLoRe.ExE")));
+  BrowserType type = BROWSER_UNKNOWN;
+  EXPECT_SUCCEEDED(GetDefaultBrowserType(&type));
+  EXPECT_EQ(BROWSER_IE, type);
+}
+
+TEST_F(BrowserUtilsDefaultBrowserSavedTest, GetDefaultBrowserType_Firefox) {
+  if (!ShouldRunLargeTest()) {
+    return;
+  }
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyUserDefaultBrowser, NULL, _T("FiReFoX.ExE")));
+  BrowserType type = BROWSER_UNKNOWN;
+  EXPECT_SUCCEEDED(GetDefaultBrowserType(&type));
+  EXPECT_EQ(BROWSER_FIREFOX, type);
+}
+
+TEST_F(BrowserUtilsDefaultBrowserSavedTest, GetDefaultBrowserType_Chrome) {
+  if (!ShouldRunLargeTest()) {
+    return;
+  }
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyUserDefaultBrowser, NULL, _T("ChRoMe.ExE")));
+  BrowserType type = BROWSER_UNKNOWN;
+  EXPECT_SUCCEEDED(GetDefaultBrowserType(&type));
+  EXPECT_EQ(BROWSER_CHROME, type);
+}
+
+TEST_F(BrowserUtilsDefaultBrowserSavedTest, GetDefaultBrowserType_Unsupported) {
+  if (!ShouldRunLargeTest()) {
+    return;
+  }
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyUserDefaultBrowser, NULL, _T("FoO.ExE")));
+  BrowserType type = BROWSER_UNKNOWN;
+  EXPECT_SUCCEEDED(GetDefaultBrowserType(&type));
+  EXPECT_EQ(BROWSER_UNKNOWN, type);
+}
+
+TEST(BrowserUtilsTest, BrowserTypeToProcessName_Unknown) {
+  CString exe_name;
+  EXPECT_EQ(E_FAIL, BrowserTypeToProcessName(BROWSER_UNKNOWN, &exe_name));
+  EXPECT_TRUE(exe_name.IsEmpty());
+}
+
+// Writes the default browser to ensure consistent results.
+TEST_F(BrowserUtilsDefaultBrowserSavedTest, BrowserTypeToProcessName_Default) {
+  if (!ShouldRunLargeTest()) {
+    return;
+  }
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyUserDefaultBrowser, NULL, _T("IeXpLoRe.ExE")));
+
+  CString default_exe_name;
+  EXPECT_SUCCEEDED(GetDefaultBrowserName(&default_exe_name));
+  EXPECT_STREQ(_T("IeXpLoRe.ExE"), default_exe_name);
+
+  CString exe_name;
+  EXPECT_SUCCEEDED(BrowserTypeToProcessName(BROWSER_DEFAULT, &exe_name));
+  EXPECT_STREQ(_T("IeXpLoRe.ExE"), exe_name);
+}
+
+TEST(BrowserUtilsTest, BrowserTypeToProcessName_Browsers) {
+  CString exe_name;
+  EXPECT_SUCCEEDED(BrowserTypeToProcessName(BROWSER_IE, &exe_name));
+  EXPECT_STREQ(_T("IEXPLORE.EXE"), exe_name);
+  EXPECT_SUCCEEDED(BrowserTypeToProcessName(BROWSER_FIREFOX, &exe_name));
+  EXPECT_STREQ(_T("FIREFOX.EXE"), exe_name);
+  EXPECT_SUCCEEDED(BrowserTypeToProcessName(BROWSER_CHROME, &exe_name));
+  EXPECT_STREQ(_T("CHROME.EXE"), exe_name);
+}
+
+TEST(BrowserUtilsTest, BrowserTypeToProcessName_Invalid) {
+  CString exe_name;
+  ExpectAsserts expect_asserts;
+  EXPECT_EQ(E_FAIL, BrowserTypeToProcessName(BROWSER_MAX, &exe_name));
+  EXPECT_TRUE(exe_name.IsEmpty());
+  EXPECT_EQ(E_FAIL,
+            BrowserTypeToProcessName(static_cast<BrowserType>(9), &exe_name));
+  EXPECT_TRUE(exe_name.IsEmpty());
+  EXPECT_EQ(E_FAIL,
+            BrowserTypeToProcessName(static_cast<BrowserType>(-1), &exe_name));
+  EXPECT_TRUE(exe_name.IsEmpty());
+}
+
+TEST(BrowserUtilsTest, GetBrowserImagePath_DefaultBrowser) {
+  CString browser;
+  ASSERT_SUCCEEDED(GetDefaultBrowserName(&browser));
+
+  BrowserType default_type = BROWSER_UNKNOWN;
+  if (browser.CompareNoCase(kIeExeName) == 0) {
+    default_type = BROWSER_IE;
+  } else if (browser.CompareNoCase(kFirefoxExeName) == 0) {
+    default_type = BROWSER_FIREFOX;
+  } else if (browser.CompareNoCase(kChromeExeName) == 0) {
+    default_type = BROWSER_CHROME;
+  }
+
+  CString exp_browser_path;
+  ASSERT_SUCCEEDED(GetDefaultBrowserPath(&exp_browser_path));
+
+  if (default_type == BROWSER_IE) {
+    CString path;
+    ASSERT_SUCCEEDED(GetBrowserImagePath(BROWSER_IE, &path));
+
+    CString long_name;
+    ASSERT_SUCCEEDED(ShortPathToLongPath(path, &long_name));
+    CString exp_long_name;
+    ASSERT_SUCCEEDED(ShortPathToLongPath(exp_browser_path, &exp_long_name));
+    ASSERT_STREQ(exp_long_name.MakeLower(), long_name.MakeLower());
+  } else if (default_type == BROWSER_FIREFOX) {
+    CString path;
+    ASSERT_SUCCEEDED(GetBrowserImagePath(BROWSER_FIREFOX, &path));
+
+    CString long_name;
+    ASSERT_SUCCEEDED(ShortPathToLongPath(path, &long_name));
+    CString exp_long_name;
+    ASSERT_SUCCEEDED(ShortPathToLongPath(exp_browser_path, &exp_long_name));
+    ASSERT_STREQ(exp_long_name.MakeLower(), long_name.MakeLower());
+  } else if (default_type == BROWSER_CHROME) {
+    CString path;
+    ASSERT_SUCCEEDED(GetBrowserImagePath(BROWSER_CHROME, &path));
+
+    CString long_name;
+    ASSERT_SUCCEEDED(ShortPathToLongPath(path, &long_name));
+    CString exp_long_name;
+    ASSERT_SUCCEEDED(ShortPathToLongPath(exp_browser_path, &exp_long_name));
+    ASSERT_STREQ(exp_long_name.MakeLower(), long_name.MakeLower());
+  }
+
+  CString path;
+  ASSERT_SUCCEEDED(GetBrowserImagePath(BROWSER_DEFAULT, &path));
+  CString long_name;
+  ASSERT_SUCCEEDED(ShortPathToLongPath(path, &long_name));
+  CString exp_long_name;
+  ASSERT_SUCCEEDED(ShortPathToLongPath(exp_browser_path, &exp_long_name));
+  ASSERT_STREQ(exp_long_name.MakeLower(), long_name.MakeLower());
+
+  ASSERT_FAILED(GetBrowserImagePath(BROWSER_UNKNOWN, &path));
+}
+
+// Try all browsers to get more test coverage.
+TEST(BrowserUtilsTest, GetBrowserImagePath_AllSupportedBrowsers) {
+  CString path;
+
+  HRESULT hr = GetBrowserImagePath(BROWSER_IE, &path);
+  if (SUCCEEDED(hr)) {
+    EXPECT_EQ(0, path.CompareNoCase(
+                     _T("C:\\Program Files\\Internet Explorer\\iexplore.exe")))
+        << _T("Actual path: ") << path.GetString();
+  } else {
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);
+  }
+
+  hr = GetBrowserImagePath(BROWSER_FIREFOX, &path);
+  if (SUCCEEDED(hr)) {
+    EXPECT_TRUE(
+        0 == path.CompareNoCase(
+            _T("C:\\Program Files\\Mozilla Firefox\\firefox.exe")) ||
+        0 == path.CompareNoCase(
+            _T("C:\\PROGRA~1\\MOZILL~1\\FIREFOX.EXE")))
+        << _T("Actual path: ") << path.GetString();
+  } else {
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);
+  }
+
+  hr = GetBrowserImagePath(BROWSER_CHROME, &path);
+  if (SUCCEEDED(hr)) {
+    EXPECT_TRUE(
+        0 == path.CompareNoCase(
+            _T("C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe")) ||
+        0 == path.CompareNoCase(
+            GetLocalAppDataPath() +
+            _T("Google\\Chrome\\Application\\chrome.exe")))
+        << _T("Actual path: ") << path.GetString();
+  } else {
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);
+  }
+}
+
+TEST(BrowserUtilsTest, GetLegacyDefaultBrowserInfo) {
+  CString name;
+  CString browser_path;
+  EXPECT_SUCCEEDED(GetLegacyDefaultBrowserInfo(&name, &browser_path));
+  EXPECT_FALSE(browser_path.IsEmpty());
+  EXPECT_FALSE(name.IsEmpty());
+}
+
+TEST(BrowserUtilsTest, GetIeFontSize) {
+  // The build server might not have IE configured.
+  if (!IsBuildSystem()) {
+    uint32 font_size = 0;
+    const uint32 kMaxFontSize = 4;
+    EXPECT_SUCCEEDED(GetIeFontSize(&font_size));
+    EXPECT_LE(font_size, kMaxFontSize);
+  }
+}
+
+TEST_F(GetLegacyDefaultBrowserInfoTest, ValidQuotedIE) {
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(
+      kRegKeyLegacyDefaultBrowserCommand,
+      NULL,
+      _T("\"C:\\Program Files\\Internet Explorer\\iexplore.exe\" -nohome")));
+
+  CString name;
+  CString browser_path;
+  EXPECT_SUCCEEDED(GetLegacyDefaultBrowserInfo(&name, &browser_path));
+  EXPECT_STREQ(_T("C:\\Program Files\\Internet Explorer\\iexplore.exe"),
+               browser_path);
+  EXPECT_STREQ(_T("iexplore.exe"), name);
+}
+
+TEST_F(GetLegacyDefaultBrowserInfoTest, ValidUnquotedPath) {
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(
+      kRegKeyLegacyDefaultBrowserCommand,
+      NULL,
+      _T("C:\\Program Files\\Internet Explorer\\iexplore.exe")));
+
+  CString name;
+  CString browser_path;
+  EXPECT_SUCCEEDED(GetLegacyDefaultBrowserInfo(&name, &browser_path));
+  EXPECT_STREQ(_T("C:\\Program Files\\Internet Explorer\\iexplore.exe"),
+               browser_path);
+  EXPECT_STREQ(_T("iexplore.exe"), name);
+}
+
+TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidNoKey) {
+  CString name;
+  CString browser_path;
+  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));
+  EXPECT_TRUE(browser_path.IsEmpty());
+  EXPECT_TRUE(name.IsEmpty());
+}
+
+TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidNoValue) {
+  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKey(
+      kRegKeyLegacyDefaultBrowserCommand));
+
+  CString name;
+  CString browser_path;
+  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));
+  EXPECT_TRUE(browser_path.IsEmpty());
+  EXPECT_TRUE(name.IsEmpty());
+}
+
+TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidPath) {
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(
+      kRegKeyLegacyDefaultBrowserCommand,
+      NULL,
+      _T("\"C:\\Program File\\iexplore.exe\" -nohome")));
+
+  CString name;
+  CString browser_path;
+  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));
+  EXPECT_TRUE(browser_path.IsEmpty());
+  EXPECT_TRUE(name.IsEmpty());
+}
+
+TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidUnquotedPath) {
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(
+      kRegKeyLegacyDefaultBrowserCommand,
+      NULL,
+      _T("C:\\Program Files\\Internet Explorer\\iexplore.exe -nohome")));
+
+  CString name;
+  CString browser_path;
+  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));
+  EXPECT_TRUE(browser_path.IsEmpty());
+  EXPECT_TRUE(name.IsEmpty());
+}
+
+TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidUnquotedDirectory) {
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(
+      kRegKeyLegacyDefaultBrowserCommand,
+      NULL,
+      _T("C:\\Program Files\\Internet Explorer\\")));
+
+  CString name;
+  CString browser_path;
+  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));
+  EXPECT_TRUE(browser_path.IsEmpty());
+  EXPECT_TRUE(name.IsEmpty());
+}
+
+TEST_F(GetLegacyDefaultBrowserInfoTest, InvalidQuotedDirectory) {
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(
+      kRegKeyLegacyDefaultBrowserCommand,
+      NULL,
+      _T("\"C:\\Program Files\\Internet Explorer\\\" -nohome")));
+
+  CString name;
+  CString browser_path;
+  EXPECT_FAILED(GetLegacyDefaultBrowserInfo(&name, &browser_path));
+  EXPECT_TRUE(browser_path.IsEmpty());
+  EXPECT_TRUE(name.IsEmpty());
+}
+
+}  // namespace omaha
+
diff --git a/common/build.scons b/common/build.scons
index 90beab4..5bee199 100644
--- a/common/build.scons
+++ b/common/build.scons
@@ -1,99 +1,99 @@
-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-env.BuildSConscript('logging')

-env.BuildSConscript('security')

-

-inputs = [

-    'accounts.cc',

-    'app_util.cc',

-    'atl_regexp.cc',

-    'browser_utils.cc',

-    'cgi.cc',

-    'clipboard.cc',

-    'commands.cc',

-    'crc.cc',

-    'debug.cc',

-    'disk.cc',

-    'dynamic_link_dbghelp.cc',

-    'dynamic_link_kernel32.cc',

-    'encrypt.cc',

-    'error.cc',

-    'exception_barrier.cc',

-    'exception_barrier_lowlevel.asm',

-    'exception_utils.cc',

-    'extractor.cc',

-    'file.cc',

-    'file_reader.cc',

-    'file_store.cc',

-    'file_ver.cc',

-    'firewall_product_detection.cc',

-    'highres_timer-win32.cc',

-    'localization.cc',

-    'logging.cc',

-    'md5.cc',

-    'module_utils.cc',

-    'omaha_version.cc',

-    'path.cc',

-    'pe_utils.cc',

-    'popup_menu.cc',

-    'process.cc',

-    'proc_utils.cc',

-    'queue_timer.cc',

-    'reactor.cc',

-    'reg_key.cc',

-    'regexp.cc',

-    'registry_hive.cc',

-    'registry_monitor_manager.cc',

-    'registry_store.cc',

-    'serializable_object.cc',

-    'service_utils.cc',

-    'sha.cc',

-    'shell.cc',

-    'shutdown_handler.cc',

-    'signatures.cc',

-    'signaturevalidator.cc',

-    'single_instance.cc',

-    'sta.cc',

-    'string.cc',

-    'synchronized.cc',

-    'system.cc',

-    'system_info.cc',

-    '../third_party/smartany/shared_any.cc',

-    'thread.cc',

-    'thread_pool.cc',

-    'time.cc',

-    'timer.cc',

-    'tr_rand.cc',

-    'unittest_utils.cc',

-    'user_info.cc',

-    'user_rights.cc',

-    'utils.cc',

-    'vista_utils.cc',

-    'vistautil.cc',

-    'window_utils.cc',

-    'wmi_query.cc',

-    'xml_utils.cc',

-    ]

-

-local_env = env.Clone()

-

-# Required by the exception barrier code.

-local_env.Append(ASFLAGS = ['/safeseh'])

-

-# Build these into a library.

-local_env.ComponentLibrary('common', inputs)

+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+env.BuildSConscript('logging')
+env.BuildSConscript('security')
+
+inputs = [
+    'accounts.cc',
+    'app_util.cc',
+    'atl_regexp.cc',
+    'browser_utils.cc',
+    'cgi.cc',
+    'clipboard.cc',
+    'commands.cc',
+    'crc.cc',
+    'debug.cc',
+    'disk.cc',
+    'dynamic_link_dbghelp.cc',
+    'dynamic_link_kernel32.cc',
+    'encrypt.cc',
+    'error.cc',
+    'exception_barrier.cc',
+    'exception_barrier_lowlevel.asm',
+    'exception_utils.cc',
+    'extractor.cc',
+    'file.cc',
+    'file_reader.cc',
+    'file_store.cc',
+    'file_ver.cc',
+    'firewall_product_detection.cc',
+    'highres_timer-win32.cc',
+    'localization.cc',
+    'logging.cc',
+    'md5.cc',
+    'module_utils.cc',
+    'omaha_version.cc',
+    'path.cc',
+    'pe_utils.cc',
+    'popup_menu.cc',
+    'process.cc',
+    'proc_utils.cc',
+    'queue_timer.cc',
+    'reactor.cc',
+    'reg_key.cc',
+    'regexp.cc',
+    'registry_hive.cc',
+    'registry_monitor_manager.cc',
+    'registry_store.cc',
+    'serializable_object.cc',
+    'service_utils.cc',
+    'sha.cc',
+    'shell.cc',
+    'shutdown_handler.cc',
+    'signatures.cc',
+    'signaturevalidator.cc',
+    'single_instance.cc',
+    'sta.cc',
+    'string.cc',
+    'synchronized.cc',
+    'system.cc',
+    'system_info.cc',
+    '../third_party/smartany/shared_any.cc',
+    'thread.cc',
+    'thread_pool.cc',
+    'time.cc',
+    'timer.cc',
+    'tr_rand.cc',
+    'unittest_utils.cc',
+    'user_info.cc',
+    'user_rights.cc',
+    'utils.cc',
+    'vista_utils.cc',
+    'vistautil.cc',
+    'window_utils.cc',
+    'wmi_query.cc',
+    'xml_utils.cc',
+    ]
+
+local_env = env.Clone()
+
+# Required by the exception barrier code.
+local_env.Append(ASFLAGS = ['/safeseh'])
+
+# Build these into a library.
+local_env.ComponentLibrary('common', inputs)
diff --git a/common/cgi.cc b/common/cgi.cc
index 57e3c04..28aa4d1 100644
--- a/common/cgi.cc
+++ b/common/cgi.cc
@@ -1,101 +1,101 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/cgi.h"

-

-#include <tchar.h>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-static uint32 _needs_escape[8] = {

-  0xffffffffL,

-  0xf80008fdL,

-  0x78000001L,

-  0xb8000001L,

-  0xffffffffL,

-  0xffffffffL,

-  0xffffffffL,

-  0xffffffffL

-};

-#define needs_escape(c) (_needs_escape[(c)>>5]&(1<<((c)&31)))

-

-// Here are a couple utility methods to change ints to hex chars & back.

-inline int int_to_hex_digit(int i) {

-  ASSERT((i >= 0) && (i <= 16), (_T("")));

-  return ((i < 10) ? (i + '0') : ((i - 10) + 'A'));

-}

-

-inline int hex_digit_to_int(TCHAR c) {

-  ASSERT(isxdigit(c), (_T("")));

-  return ((c >= 'a') ? ((c - 'a') + 10) :

-          (c >= 'A') ? ((c - 'A') + 10) :

-          (c - '0'));

-}

-

-bool CGI::EscapeString(const TCHAR* src, int srcn, TCHAR* dst, int dstn) {

-  ASSERT1(src != dst);  // In-place escaping will fail.

-  ASSERT1(srcn >= 0);

-  ASSERT1(dstn >= 1);

-  dstn--;   // Number of characters we can write, not including null terminator.

-

-  int i, j;

-  for (i = 0, j = 0; i < srcn && j < dstn; i++) {

-    TCHAR c = src[i];

-    if (c == ' ') {

-      dst[j++] = '+';

-    } else if (!needs_escape(c)) {

-      dst[j++] = c;

-    } else if (j + 3 > dstn) {

-      break;  // Escape sequence will not fit.

-    } else {

-      dst[j++] = '%';

-      dst[j++] = static_cast<TCHAR>(int_to_hex_digit((c >> 4) & 0xf));

-      dst[j++] = static_cast<TCHAR>(int_to_hex_digit(c & 0xf));

-    }

-  }

-  dst[j] = '\0';

-  return i == srcn;

-}

-

-bool CGI::UnescapeString(const TCHAR* src, int srcn, TCHAR* dst, int dstn) {

-  ASSERT1(srcn >= 0);

-  ASSERT1(dstn >= 1);

-  dstn--;   // Number of characters we can write, not including null terminator.

-

-  int i, j;

-  for (i = 0, j = 0; i < srcn && j < dstn; ++j) {

-    TCHAR c = src[i++];

-    if (c == '+') {

-      dst[j] = ' ';

-    } else if (c != '%') {

-      dst[j] = c;

-    } else if (i + 2 > srcn) {

-      break;  // Escape sequence is incomplete.

-    } else if (!isxdigit(src[i]) || !isxdigit(src[i + 1])) {

-      break;  // Escape sequence isn't hex.

-    } else {

-      int num = hex_digit_to_int(src[i++]) << 4;

-      num += hex_digit_to_int(src[i++]);

-      dst[j] = static_cast<TCHAR>(num);

-    }

-  }

-  dst[j] = '\0';

-  return i == srcn;

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/cgi.h"
+
+#include <tchar.h>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+static uint32 _needs_escape[8] = {
+  0xffffffffL,
+  0xf80008fdL,
+  0x78000001L,
+  0xb8000001L,
+  0xffffffffL,
+  0xffffffffL,
+  0xffffffffL,
+  0xffffffffL
+};
+#define needs_escape(c) (_needs_escape[(c)>>5]&(1<<((c)&31)))
+
+// Here are a couple utility methods to change ints to hex chars & back.
+inline int int_to_hex_digit(int i) {
+  ASSERT((i >= 0) && (i <= 16), (_T("")));
+  return ((i < 10) ? (i + '0') : ((i - 10) + 'A'));
+}
+
+inline int hex_digit_to_int(TCHAR c) {
+  ASSERT(isxdigit(c), (_T("")));
+  return ((c >= 'a') ? ((c - 'a') + 10) :
+          (c >= 'A') ? ((c - 'A') + 10) :
+          (c - '0'));
+}
+
+bool CGI::EscapeString(const TCHAR* src, int srcn, TCHAR* dst, int dstn) {
+  ASSERT1(src != dst);  // In-place escaping will fail.
+  ASSERT1(srcn >= 0);
+  ASSERT1(dstn >= 1);
+  dstn--;   // Number of characters we can write, not including null terminator.
+
+  int i, j;
+  for (i = 0, j = 0; i < srcn && j < dstn; i++) {
+    TCHAR c = src[i];
+    if (c == ' ') {
+      dst[j++] = '+';
+    } else if (!needs_escape(c)) {
+      dst[j++] = c;
+    } else if (j + 3 > dstn) {
+      break;  // Escape sequence will not fit.
+    } else {
+      dst[j++] = '%';
+      dst[j++] = static_cast<TCHAR>(int_to_hex_digit((c >> 4) & 0xf));
+      dst[j++] = static_cast<TCHAR>(int_to_hex_digit(c & 0xf));
+    }
+  }
+  dst[j] = '\0';
+  return i == srcn;
+}
+
+bool CGI::UnescapeString(const TCHAR* src, int srcn, TCHAR* dst, int dstn) {
+  ASSERT1(srcn >= 0);
+  ASSERT1(dstn >= 1);
+  dstn--;   // Number of characters we can write, not including null terminator.
+
+  int i, j;
+  for (i = 0, j = 0; i < srcn && j < dstn; ++j) {
+    TCHAR c = src[i++];
+    if (c == '+') {
+      dst[j] = ' ';
+    } else if (c != '%') {
+      dst[j] = c;
+    } else if (i + 2 > srcn) {
+      break;  // Escape sequence is incomplete.
+    } else if (!isxdigit(src[i]) || !isxdigit(src[i + 1])) {
+      break;  // Escape sequence isn't hex.
+    } else {
+      int num = hex_digit_to_int(src[i++]) << 4;
+      num += hex_digit_to_int(src[i++]);
+      dst[j] = static_cast<TCHAR>(num);
+    }
+  }
+  dst[j] = '\0';
+  return i == srcn;
+}
+
+}  // namespace omaha
+
diff --git a/common/cgi.h b/common/cgi.h
index 45a4c03..bb78b08 100644
--- a/common/cgi.h
+++ b/common/cgi.h
@@ -1,51 +1,51 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_CGI_H__

-#define OMAHA_COMMON_CGI_H__

-

-#include <tchar.h>

-

-namespace omaha {

-

-class CGI {

- public:

-  // Maximum factor by which EscapeString() can increase the string length

-  static const int kEscapeFactor = 3;

-

-  // EscapeString() converts funky characters found in "src[0,srcn-1]" into

-  // escape sequences.  The escaped string is placed back in "dst".  At most

-  // "dstn" characters are written into "dst", including the

-  // null-termination byte.  Returns true if

-  // successful, false if the escaped string will not fit entirely in "dstn"

-  // characters.  Since escaping can increase the length, "dst" should not

-  // be the same as "src".

-

-  // These functions always return a null-terminated string, even if they

-  // fail (e.g. if a bad escape sequence is found).  As a consequence, you

-  // must pass in a dstn > 0.

-  // If you want to guarantee that the result will fit, you need

-  //      dstn >= kEscapeFactor * srcn + 1

-  // for EscapeString and

-  //      dstn >= srcn + 1

-  // for UnescapeString.

-

-  static bool EscapeString(const TCHAR* src, int srcn, TCHAR* dst, int dstn);

-  static bool UnescapeString(const TCHAR* src, int srcn, TCHAR* dst, int dstn);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_CGI_H__

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_CGI_H__
+#define OMAHA_COMMON_CGI_H__
+
+#include <tchar.h>
+
+namespace omaha {
+
+class CGI {
+ public:
+  // Maximum factor by which EscapeString() can increase the string length
+  static const int kEscapeFactor = 3;
+
+  // EscapeString() converts funky characters found in "src[0,srcn-1]" into
+  // escape sequences.  The escaped string is placed back in "dst".  At most
+  // "dstn" characters are written into "dst", including the
+  // null-termination byte.  Returns true if
+  // successful, false if the escaped string will not fit entirely in "dstn"
+  // characters.  Since escaping can increase the length, "dst" should not
+  // be the same as "src".
+
+  // These functions always return a null-terminated string, even if they
+  // fail (e.g. if a bad escape sequence is found).  As a consequence, you
+  // must pass in a dstn > 0.
+  // If you want to guarantee that the result will fit, you need
+  //      dstn >= kEscapeFactor * srcn + 1
+  // for EscapeString and
+  //      dstn >= srcn + 1
+  // for UnescapeString.
+
+  static bool EscapeString(const TCHAR* src, int srcn, TCHAR* dst, int dstn);
+  static bool UnescapeString(const TCHAR* src, int srcn, TCHAR* dst, int dstn);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_CGI_H__
diff --git a/common/cgi_unittest.cc b/common/cgi_unittest.cc
index 056c7d8..a4f1394 100644
--- a/common/cgi_unittest.cc
+++ b/common/cgi_unittest.cc
@@ -1,60 +1,60 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Unit test for the CGI escape/unescape string..

-

-#include "base/scoped_ptr.h"

-#include "omaha/common/cgi.h"

-#include "omaha/common/string.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-void TestEscapeUnescape(const TCHAR* origin, const TCHAR* escaped) {

-  int origin_len = lstrlen(origin);

-  int buffer_len = origin_len * CGI::kEscapeFactor + 1;

-  scoped_array<TCHAR> escaped_buffer(new TCHAR[buffer_len]);

-  ASSERT_TRUE(CGI::EscapeString(origin, origin_len,

-                                escaped_buffer.get(), buffer_len));

-  ASSERT_STREQ(escaped_buffer.get(), escaped);

-

-  scoped_array<TCHAR> origin_buffer(new TCHAR[buffer_len]);

-  ASSERT_TRUE(CGI::UnescapeString(escaped_buffer.get(),

-                                  lstrlen(escaped_buffer.get()),

-                                  origin_buffer.get(), buffer_len));

-  ASSERT_STREQ(origin_buffer.get(), origin);

-}

-

-TEST(CGITEST, EscapeUnescape) {

-  // Regular chars.

-  TCHAR origin1[] = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");

-  TestEscapeUnescape(origin1, origin1);

-

-  String_ToLower(origin1);

-  TestEscapeUnescape(origin1, origin1);

-

-  // Special chars.

-  TCHAR origin2[] =  _T("^&`{}|][\"<>\\");    // NOLINT

-  TCHAR escaped2[] = _T("%5E%26%60%7B%7D%7C%5D%5B%22%3C%3E%5C");

-  TestEscapeUnescape(origin2, escaped2);

-

-  // Real case.

-  TCHAR origin3[] = _T("http://foo2.bar.google.com:80/pagead/conversion/1067912086/?ai=123&gclid=456&label=installation&value=0.0");                    // NOLINT

-  TCHAR escaped3[] = _T("http://foo2.bar.google.com:80/pagead/conversion/1067912086/%3Fai%3D123%26gclid%3D456%26label%3Dinstallation%26value%3D0.0");   // NOLINT

-  TestEscapeUnescape(origin3, escaped3);

-}

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Unit test for the CGI escape/unescape string..
+
+#include "base/scoped_ptr.h"
+#include "omaha/common/cgi.h"
+#include "omaha/common/string.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+void TestEscapeUnescape(const TCHAR* origin, const TCHAR* escaped) {
+  int origin_len = lstrlen(origin);
+  int buffer_len = origin_len * CGI::kEscapeFactor + 1;
+  scoped_array<TCHAR> escaped_buffer(new TCHAR[buffer_len]);
+  ASSERT_TRUE(CGI::EscapeString(origin, origin_len,
+                                escaped_buffer.get(), buffer_len));
+  ASSERT_STREQ(escaped_buffer.get(), escaped);
+
+  scoped_array<TCHAR> origin_buffer(new TCHAR[buffer_len]);
+  ASSERT_TRUE(CGI::UnescapeString(escaped_buffer.get(),
+                                  lstrlen(escaped_buffer.get()),
+                                  origin_buffer.get(), buffer_len));
+  ASSERT_STREQ(origin_buffer.get(), origin);
+}
+
+TEST(CGITEST, EscapeUnescape) {
+  // Regular chars.
+  TCHAR origin1[] = _T("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
+  TestEscapeUnescape(origin1, origin1);
+
+  String_ToLower(origin1);
+  TestEscapeUnescape(origin1, origin1);
+
+  // Special chars.
+  TCHAR origin2[] =  _T("^&`{}|][\"<>\\");    // NOLINT
+  TCHAR escaped2[] = _T("%5E%26%60%7B%7D%7C%5D%5B%22%3C%3E%5C");
+  TestEscapeUnescape(origin2, escaped2);
+
+  // Real case.
+  TCHAR origin3[] = _T("http://foo2.bar.google.com:80/pagead/conversion/1067912086/?ai=123&gclid=456&label=installation&value=0.0");                    // NOLINT
+  TCHAR escaped3[] = _T("http://foo2.bar.google.com:80/pagead/conversion/1067912086/%3Fai%3D123%26gclid%3D456%26label%3Dinstallation%26value%3D0.0");   // NOLINT
+  TestEscapeUnescape(origin3, escaped3);
+}
+
+}  // namespace omaha
+
diff --git a/common/clipboard.cc b/common/clipboard.cc
index a42681c..1302d9a 100644
--- a/common/clipboard.cc
+++ b/common/clipboard.cc
@@ -1,69 +1,69 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/clipboard.h"

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-// Put the given string on the system clipboard

-void SetClipboard(const TCHAR *string_to_set) {

-  ASSERT(string_to_set, (L""));

-

-  int len = lstrlen(string_to_set);

-

-  //

-  // Note to developer: It is not always possible to step through this code

-  //  since the debugger will possibly steal the clipboard.  E.g. OpenClipboard

-  //  might succeed and EmptyClipboard might fail with "Thread does not have

-  //  clipboard open".

-  //

-

-  // Actual clipboard processing

-  if (::OpenClipboard(NULL)) {

-    BOOL b = ::EmptyClipboard();

-    ASSERT(b, (L"EmptyClipboard failed"));

-

-    // Include the terminating null

-    len++;

-

-    HANDLE copy_handle = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,

-                                       len * sizeof(TCHAR));

-    ASSERT(copy_handle, (L""));

-

-    byte* copy_data = reinterpret_cast<byte*>(::GlobalLock(copy_handle));

-    memcpy(copy_data, string_to_set, len * sizeof(TCHAR));

-    ::GlobalUnlock(copy_handle);

-

-#ifdef _UNICODE

-    HANDLE h = ::SetClipboardData(CF_UNICODETEXT, copy_handle);

-#else

-    HANDLE h = ::SetClipboardData(CF_TEXT, copy_handle);

-#endif

-

-    ASSERT(h != NULL, (L"SetClipboardData failed"));

-    if (!h) {

-      ::GlobalFree(copy_handle);

-    }

-

-    VERIFY(::CloseClipboard(), (L""));

-  } else {

-    ASSERT(false, (L"OpenClipboard failed - %i", ::GetLastError()));

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/clipboard.h"
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+// Put the given string on the system clipboard
+void SetClipboard(const TCHAR *string_to_set) {
+  ASSERT(string_to_set, (L""));
+
+  int len = lstrlen(string_to_set);
+
+  //
+  // Note to developer: It is not always possible to step through this code
+  //  since the debugger will possibly steal the clipboard.  E.g. OpenClipboard
+  //  might succeed and EmptyClipboard might fail with "Thread does not have
+  //  clipboard open".
+  //
+
+  // Actual clipboard processing
+  if (::OpenClipboard(NULL)) {
+    BOOL b = ::EmptyClipboard();
+    ASSERT(b, (L"EmptyClipboard failed"));
+
+    // Include the terminating null
+    len++;
+
+    HANDLE copy_handle = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
+                                       len * sizeof(TCHAR));
+    ASSERT(copy_handle, (L""));
+
+    byte* copy_data = reinterpret_cast<byte*>(::GlobalLock(copy_handle));
+    memcpy(copy_data, string_to_set, len * sizeof(TCHAR));
+    ::GlobalUnlock(copy_handle);
+
+#ifdef _UNICODE
+    HANDLE h = ::SetClipboardData(CF_UNICODETEXT, copy_handle);
+#else
+    HANDLE h = ::SetClipboardData(CF_TEXT, copy_handle);
+#endif
+
+    ASSERT(h != NULL, (L"SetClipboardData failed"));
+    if (!h) {
+      ::GlobalFree(copy_handle);
+    }
+
+    VERIFY(::CloseClipboard(), (L""));
+  } else {
+    ASSERT(false, (L"OpenClipboard failed - %i", ::GetLastError()));
+  }
+}
+
+}  // namespace omaha
+
diff --git a/common/clipboard.h b/common/clipboard.h
index 8bbcb3d..832e853 100644
--- a/common/clipboard.h
+++ b/common/clipboard.h
@@ -1,29 +1,29 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_CLIPBOARD_H__

-#define OMAHA_COMMON_CLIPBOARD_H__

-

-#include <windows.h>

-#include <tchar.h>

-

-namespace omaha {

-

-// Copies the given string to the system clipboard.

-void SetClipboard(const TCHAR *string_to_set);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_CLIPBOARD_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_CLIPBOARD_H__
+#define OMAHA_COMMON_CLIPBOARD_H__
+
+#include <windows.h>
+#include <tchar.h>
+
+namespace omaha {
+
+// Copies the given string to the system clipboard.
+void SetClipboard(const TCHAR *string_to_set);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_CLIPBOARD_H__
diff --git a/common/commands.cc b/common/commands.cc
index 8c1c395..5df8ac1 100644
--- a/common/commands.cc
+++ b/common/commands.cc
@@ -1,570 +1,570 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Parse command-line options

-

-#include "omaha/common/commands.h"

-#include <cstdlib>

-#include "base/scoped_ptr.h"

-#include "omaha/common/cgi.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-#define kNameValueChar  _T('=')

-#define kTrueValue      _T("true")

-#define kFalseValue     _T("false")

-#define kOnValue        _T("on")

-#define kOffValue       _T("off")

-

-

-//

-// Helper functions

-//

-

-template<class T>

-HRESULT ConvertValue(const TCHAR* str_value, T* value);

-

-// Convert the three-valued value from the string representation

-template<>

-HRESULT ConvertValue<ThreeValue>(const TCHAR* str_value, ThreeValue* value) {

-  ASSERT1(value);

-

-  *value = VALUE_NOT_SET;

-  if (str_value && *str_value) {

-    if (String_StrNCmp(str_value,

-                       kTrueValue,

-                       TSTR_SIZE(kTrueValue) + 1,

-                       true) == 0 ||

-        String_StrNCmp(str_value,

-                       kOnValue,

-                       TSTR_SIZE(kOnValue) + 1,

-                       true) == 0) {

-      *value = TRUE_VALUE;

-    } else if (String_StrNCmp(str_value,

-                              kFalseValue,

-                              TSTR_SIZE(kFalseValue) + 1,

-                              true) == 0 ||

-               String_StrNCmp(str_value,

-                              kOffValue,

-                              TSTR_SIZE(kOffValue) + 1,

-                              true) == 0) {

-      *value = FALSE_VALUE;

-    } else {

-      return CI_E_INVALID_ARG;

-    }

-  }

-  return S_OK;

-}

-

-// Convert the int value from the string representation

-template<>

-HRESULT ConvertValue<int>(const TCHAR* str_value, int* value) {

-  ASSERT1(str_value && *str_value);

-  ASSERT1(value);

-

-  *value = _tcstol(str_value, NULL, 0);

-  if (errno == ERANGE) {

-    return CI_E_INVALID_ARG;

-  }

-  return S_OK;

-}

-

-// Convert the unsigned int value from the string representation

-template<>

-HRESULT ConvertValue<uint32>(const TCHAR* str_value, uint32* value) {

-  ASSERT1(str_value && *str_value);

-  ASSERT1(value);

-

-  *value = _tcstoul(str_value, NULL, 0);

-  if (errno == ERANGE) {

-    return CI_E_INVALID_ARG;

-  }

-  return S_OK;

-}

-

-// Convert the string value from the string representation

-HRESULT ConvertValue(const TCHAR* str_value, CString* value, bool to_unescape) {

-  ASSERT1(str_value && *str_value);

-  ASSERT1(value);

-

-  *value = str_value;

-

-  if (to_unescape) {

-    int length = value->GetLength();

-    scoped_array<TCHAR> unescaped_value(new TCHAR[length + 1]);

-    RET_IF_FALSE(CGI::UnescapeString(*value, length, unescaped_value.get(),

-      length + 1), CI_E_INVALID_ARG);

-    *value = unescaped_value.get();

-  }

-

-  return S_OK;

-}

-

-//

-// Struct CommandOption

-//

-void CommandOption::Init(const TCHAR* name, CommandOptionType type,

-                         void* value, int max_value_len) {

-  this->name = name;

-  this->type = type;

-  this->value = value;

-  this->max_value_len = max_value_len;

-}

-

-void CommandOption::Copy(const CommandOption& option) {

-  Init(option.name, option.type, option.value, option.max_value_len);

-}

-

-//

-// Class CommandParsingSimple

-//

-

-// Constructor

-CommandParsingSimple::CommandParsingSimple()

-    : separator_(_T(' ')) {

-}

-

-// Constructor

-CommandParsingSimple::CommandParsingSimple(TCHAR separator)

-    : separator_(separator) {

-}

-

-// Parse a command line string into args

-HRESULT CommandParsingSimple::ParseSimple(const TCHAR* cmd_line) {

-  ASSERT1(cmd_line);

-

-  UTIL_LOG(L3, (_T("[CommandParsingSimple::ParseSimple][%s]"), cmd_line));

-

-  args_.clear();

-

-  // Split command line string into list of arguments

-  for (const TCHAR* s = cmd_line; *s; ++s) {

-    // Handle separator

-    if (*s == separator_) {

-      continue;

-    }

-

-    // Handle single/double quote

-    if (*s == _T('"') || *s == _T('\'')) {

-      int right_quote = String_FindChar(s + 1, *s);

-      if (right_quote == -1) {

-        UTIL_LOG(LE, (_T("[CommandParsingSimple::ParseSimple]")

-                      _T("[single/double quote mismatches]")));

-        return CI_E_INVALID_ARG;

-      }

-      args_.push_back(CString(s + 1, right_quote));

-      s += right_quote + 1;

-      continue;

-    }

-

-    // Handle all other char

-    int next_space = String_FindChar(s + 1, separator_);

-    if (next_space == -1) {

-      args_.push_back(CString(s));

-      break;

-    } else {

-      args_.push_back(CString(s, next_space + 1));

-      s += next_space + 1;

-    }

-  }

-

-  return S_OK;

-}

-

-// Get the arg at specified position from the command line

-HRESULT CommandParsingSimple::GetAt(uint32 position, CString* arg) {

-  ASSERT1(arg);

-  ASSERT1(position < args_.size());

-

-  if (!arg || position >= args_.size()) {

-    return E_INVALIDARG;

-  }

-

-  *arg = args_[position];

-  return S_OK;

-}

-

-// Remove the arg at specified position from the command line

-HRESULT CommandParsingSimple::RemoveAt(uint32 position) {

-  ASSERT1(position < args_.size());

-

-  if (position >= args_.size()) {

-    return E_INVALIDARG;

-  }

-

-  uint32 i = 0;

-  std::vector<CString>::iterator it(args_.begin());

-  for (; i < position; ++it, ++i) {

-    ASSERT1(it != args_.end());

-  }

-  args_.erase(it);

-  return S_OK;

-}

-

-// Converted to the string

-HRESULT CommandParsingSimple::ToString(CString* cmd_line) {

-  ASSERT1(cmd_line);

-

-  bool is_first = true;

-  cmd_line->Empty();

-  for (std::vector<CString>::const_iterator it(args_.begin());

-       it != args_.end();

-       ++it) {

-    if (is_first) {

-      is_first = false;

-    } else {

-      cmd_line->AppendChar(separator_);

-    }

-    const TCHAR* arg = it->GetString();

-    if (String_FindChar(arg, separator_) != -1) {

-      cmd_line->AppendChar(_T('"'));

-      cmd_line->Append(arg);

-      cmd_line->AppendChar(_T('"'));

-    } else {

-      cmd_line->Append(arg);

-    }

-  }

-

-  return S_OK;

-}

-

-// Static Helper function that splits a command line

-// string into executable and any arguments

-HRESULT CommandParsingSimple::SplitExeAndArgs(const TCHAR* cmd_line,

-                                              CString* exe,

-                                              CString* args) {

-  ASSERT1(cmd_line);

-  ASSERT1(exe);

-  ASSERT1(args);

-

-  // Do the parsing

-  CommandParsingSimple cmd_parsing_simple;

-

-  RET_IF_FAILED(cmd_parsing_simple.ParseSimple(cmd_line));

-  RET_IF_FAILED(cmd_parsing_simple.GetAt(0, exe));

-  exe->Trim();

-  RET_IF_FAILED(cmd_parsing_simple.RemoveAt(0));

-  return (cmd_parsing_simple.ToString(args));

-}

-

-HRESULT CommandParsingSimple::SplitExeAndArgsGuess(const TCHAR* cmd_line,

-                                                   CString* exe,

-                                                   CString* args) {

-  ASSERT1(cmd_line);

-  ASSERT1(exe);

-  ASSERT1(args);

-

-  if (File::Exists(cmd_line)) {

-    // Optimization for the single executable case.

-    // Fill the [out] parameters and return.

-    *exe = cmd_line;

-    exe->Trim();

-    args->Empty();

-    return S_OK;

-  }

-

-  CString command_line(cmd_line);

-  // Check if the command line is properly enclosed, or that it does not have

-  // spaces

-  if (command_line.GetAt(0) != _T('"') && command_line.Find(_T(' ')) != -1) {

-    // File::Exists() does not handle leading spaces so remove it.

-    command_line.Trim();

-

-    // If not, need to find the executable, and if valid, enclose it in

-    // double quotes

-    const TCHAR* index_dot_exe = stristrW(command_line.GetString(), _T(".EXE"));

-

-    if (index_dot_exe != NULL) {

-      int dot_exe_end = (index_dot_exe - command_line.GetString())

-                         + arraysize(_T(".EXE")) - 1;

-      if (File::Exists(CString(command_line, dot_exe_end))) {

-        // Enclose the EXE in double quotes

-        command_line.Insert(dot_exe_end, _T('"'));

-        command_line.Insert(0, _T('"'));

-      } else {

-        UTIL_LOG(L1, (_T("[CommandParsing::SplitExeAndArgsGuess]")

-                      _T("[Could not guess the Executable file within [%s]. ")

-                      _T("Passing on to SplitExeAndArgs as-is."),

-                      command_line));

-      }

-    }

-  }

-

-  // Do the parsing

-  return SplitExeAndArgs(command_line, exe, args);

-}

-

-

-// Static Helper function that returns the number of arguments

-// in the passed in cmd_line

-HRESULT CommandParsingSimple::GetNumberOfArgs(const TCHAR* cmd_line,

-                                              uint32* number_of_args) {

-  ASSERT1(cmd_line);

-  ASSERT1(number_of_args);

-

-  // Do the parsing

-  CommandParsingSimple cmd_parsing_simple;

-

-  RET_IF_FAILED(cmd_parsing_simple.ParseSimple(cmd_line));

-  *number_of_args = cmd_parsing_simple.args_.size();

-  return S_OK;

-}

-

-

-//

-// Class CommandParsing

-//

-

-// Constructor

-CommandParsing::CommandParsing(CommandOption* options, int options_count)

-    : CommandParsingSimple(),

-      options_(options),

-      options_count_(options_count),

-      as_name_value_pair_(false) {

-}

-

-// Constructor

-CommandParsing::CommandParsing(CommandOption* options, int options_count,

-                               TCHAR separator, bool as_name_value_pair)

-    : CommandParsingSimple(separator),

-      options_(options),

-      options_count_(options_count),

-      as_name_value_pair_(as_name_value_pair) {

-}

-

-// Parse a command line string

-HRESULT CommandParsing::Parse(const TCHAR* cmd_line, bool ignore_unknown_args) {

-  ASSERT1(cmd_line);

-

-  UTIL_LOG(L3, (_T("[CommandParsing::Parse][%s][%d]"),

-                cmd_line, ignore_unknown_args));

-

-  // Parse into args_ vector

-  RET_IF_FAILED(ParseSimple(cmd_line));

-

-  // Do the internal parsing

-  return InternalParse(ignore_unknown_args);

-}

-

-// Parse a list of command line arguments

-HRESULT CommandParsing::ParseArguments(int argc, TCHAR* argv[]) {

-  if (argc <= 1) {

-    return S_OK;

-  }

-

-  // Push each argument

-  args_.clear();

-  for (int i = 1; i < argc; ++i) {

-    args_.push_back(CString(argv[i]));

-  }

-

-  // Do the internal parsing

-  return InternalParse(false);

-}

-

-// Internal parsing

-HRESULT CommandParsing::InternalParse(bool ignore_unknown_args) {

-  CString name, value;

-  for (std::vector<CString>::const_iterator it(args_.begin());

-       it != args_.end();

-       ++it) {

-    RET_IF_FAILED(ExtractName(&name, &it));

-

-    int i = FindOption(name);

-    if (i == -1) {

-      if (ignore_unknown_args) {

-        UTIL_LOG(L3, (_T("[CommandParsing::Parse][unknown arg %s]"), name));

-        continue;

-      } else {

-        UTIL_LOG(LE, (_T("[CommandParsing::Parse][invalid arg %s]"), name));

-        return CI_E_INVALID_ARG;

-      }

-    }

-

-    if (options_[i].type != COMMAND_OPTION_BOOL) {

-      RET_IF_FAILED(ExtractValue(options_[i], &value, &it, args_.end()));

-    }

-

-    switch (options_[i].type & COMMAND_OPTION_FLAGS_MASK) {

-      case COMMAND_OPTION_BOOL: {

-        bool bool_value = true;

-        SetParsedValue(options_[i], bool_value);

-        break;

-      }

-

-      case COMMAND_OPTION_THREE: {

-        ThreeValue three_value = VALUE_NOT_SET;

-        RET_IF_FAILED(ConvertValue(value, &three_value));

-        SetParsedValue(options_[i], three_value);

-        break;

-      }

-

-      case COMMAND_OPTION_INT: {

-        int int_value = 0;

-        RET_IF_FAILED(ConvertValue(value, &int_value));

-        SetParsedValue(options_[i], int_value);

-        break;

-      }

-

-      case COMMAND_OPTION_UINT: {

-        int uint_value = 0;

-        RET_IF_FAILED(ConvertValue(value, &uint_value));

-        SetParsedValue(options_[i], uint_value);

-        break;

-      }

-

-      case COMMAND_OPTION_STRING: {

-        CString str_value;

-        bool is_unescape = (options_[i].type & COMMAND_OPTION_UNESCAPE) != 0;

-        RET_IF_FAILED(ConvertValue(value, &str_value, is_unescape));

-        SetParsedValue(options_[i], str_value);

-        break;

-      }

-

-      default:

-        ASSERT1(false);

-        break;

-    }

-  }

-

-  return S_OK;

-}

-

-// Extract the name

-HRESULT CommandParsing::ExtractName(CString* name,

-                                    std::vector<CString>::const_iterator* it) {

-  ASSERT1(name);

-  ASSERT1(it);

-

-  if (as_name_value_pair_) {

-    int idx = (*it)->Find(kNameValueChar);

-    if (idx == -1) {

-      return CI_E_INVALID_ARG;

-    } else {

-      *name = (*it)->Left(idx);

-    }

-  } else {

-    *name = (*it)->GetString();

-  }

-  return S_OK;

-}

-

-// Extract the value

-// Also validate the value length if necessary

-HRESULT CommandParsing::ExtractValue(

-    const CommandOption& option,

-    CString* value,

-    std::vector<CString>::const_iterator* it,

-    const std::vector<CString>::const_iterator& end) {

-  ASSERT1(value);

-  ASSERT1(it);

-

-  if (as_name_value_pair_) {

-    int idx = (*it)->Find(kNameValueChar);

-    if (idx == -1) {

-      return CI_E_INVALID_ARG;

-    } else {

-      *value = (*it)->Right((*it)->GetLength() - idx - 1);

-    }

-  } else {

-    ++(*it);

-    if (*it == end) {

-      UTIL_LOG(LE, (_T("[CommandParsing::ExtractValue]")

-                    _T("[argument %s missing value]"), option.name));

-      return CI_E_INVALID_ARG;

-    }

-    *value = (*it)->GetString();

-  }

-

-  if (option.max_value_len >= 0) {

-    if (value->GetLength() > option.max_value_len) {

-      return CI_E_INVALID_ARG;

-    }

-  }

-

-  return S_OK;

-}

-

-// Set the parsed value

-template<class T>

-void CommandParsing::SetParsedValue(const CommandOption& option,

-                                    const T& value) {

-  if (option.type & COMMAND_OPTION_MULTIPLE) {

-    ASSERT((option.type & COMMAND_OPTION_FLAGS_MASK) != COMMAND_OPTION_BOOL,

-      (_T("COMMAND_OPTION_BOOL can't be used with COMMAND_OPTION_MULTIPLE")));

-    ASSERT((option.type & COMMAND_OPTION_FLAGS_MASK) != COMMAND_OPTION_THREE,

-      (_T("COMMAND_OPTION_THREE can't be used with COMMAND_OPTION_MULTIPLE")));

-

-    std::vector<T>* ptr = reinterpret_cast<std::vector<T>*>(option.value);

-    ptr->push_back(value);

-  } else {

-    T* ptr = reinterpret_cast<T*>(option.value);

-    *ptr = value;

-  }

-}

-

-// Helper function to find an option in the CommandOption list

-int CommandParsing::FindOption(const TCHAR* option_name) {

-  ASSERT1(option_name);

-

-  for (int i = 0; i < options_count_; ++i) {

-    if (String_StrNCmp(option_name,

-                       options_[i].name,

-                       options_[i].name.GetLength() + 1,

-                       false) == 0) {

-      return i;

-    }

-  }

-

-  return -1;

-}

-

-// Remove an option from the command line

-HRESULT CommandParsing::Remove(const TCHAR* option_name) {

-  ASSERT1(option_name);

-

-  for (std::vector<CString>::iterator it(args_.begin());

-       it != args_.end();

-       ++it) {

-    if (*it == option_name) {

-      int i = FindOption(option_name);

-      if (i == -1) {

-        return E_FAIL;

-      }

-      args_.erase(it);

-      if (!as_name_value_pair_) {

-        if (options_[i].type != COMMAND_OPTION_BOOL) {

-          if (it == args_.end()) {

-            return E_FAIL;

-          }

-          args_.erase(it);

-        }

-      }

-

-      return S_OK;

-    }

-  }

-

-  return E_FAIL;

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Parse command-line options
+
+#include "omaha/common/commands.h"
+#include <cstdlib>
+#include "base/scoped_ptr.h"
+#include "omaha/common/cgi.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+#define kNameValueChar  _T('=')
+#define kTrueValue      _T("true")
+#define kFalseValue     _T("false")
+#define kOnValue        _T("on")
+#define kOffValue       _T("off")
+
+
+//
+// Helper functions
+//
+
+template<class T>
+HRESULT ConvertValue(const TCHAR* str_value, T* value);
+
+// Convert the three-valued value from the string representation
+template<>
+HRESULT ConvertValue<ThreeValue>(const TCHAR* str_value, ThreeValue* value) {
+  ASSERT1(value);
+
+  *value = VALUE_NOT_SET;
+  if (str_value && *str_value) {
+    if (String_StrNCmp(str_value,
+                       kTrueValue,
+                       TSTR_SIZE(kTrueValue) + 1,
+                       true) == 0 ||
+        String_StrNCmp(str_value,
+                       kOnValue,
+                       TSTR_SIZE(kOnValue) + 1,
+                       true) == 0) {
+      *value = TRUE_VALUE;
+    } else if (String_StrNCmp(str_value,
+                              kFalseValue,
+                              TSTR_SIZE(kFalseValue) + 1,
+                              true) == 0 ||
+               String_StrNCmp(str_value,
+                              kOffValue,
+                              TSTR_SIZE(kOffValue) + 1,
+                              true) == 0) {
+      *value = FALSE_VALUE;
+    } else {
+      return CI_E_INVALID_ARG;
+    }
+  }
+  return S_OK;
+}
+
+// Convert the int value from the string representation
+template<>
+HRESULT ConvertValue<int>(const TCHAR* str_value, int* value) {
+  ASSERT1(str_value && *str_value);
+  ASSERT1(value);
+
+  *value = _tcstol(str_value, NULL, 0);
+  if (errno == ERANGE) {
+    return CI_E_INVALID_ARG;
+  }
+  return S_OK;
+}
+
+// Convert the unsigned int value from the string representation
+template<>
+HRESULT ConvertValue<uint32>(const TCHAR* str_value, uint32* value) {
+  ASSERT1(str_value && *str_value);
+  ASSERT1(value);
+
+  *value = _tcstoul(str_value, NULL, 0);
+  if (errno == ERANGE) {
+    return CI_E_INVALID_ARG;
+  }
+  return S_OK;
+}
+
+// Convert the string value from the string representation
+HRESULT ConvertValue(const TCHAR* str_value, CString* value, bool to_unescape) {
+  ASSERT1(str_value && *str_value);
+  ASSERT1(value);
+
+  *value = str_value;
+
+  if (to_unescape) {
+    int length = value->GetLength();
+    scoped_array<TCHAR> unescaped_value(new TCHAR[length + 1]);
+    RET_IF_FALSE(CGI::UnescapeString(*value, length, unescaped_value.get(),
+      length + 1), CI_E_INVALID_ARG);
+    *value = unescaped_value.get();
+  }
+
+  return S_OK;
+}
+
+//
+// Struct CommandOption
+//
+void CommandOption::Init(const TCHAR* name, CommandOptionType type,
+                         void* value, int max_value_len) {
+  this->name = name;
+  this->type = type;
+  this->value = value;
+  this->max_value_len = max_value_len;
+}
+
+void CommandOption::Copy(const CommandOption& option) {
+  Init(option.name, option.type, option.value, option.max_value_len);
+}
+
+//
+// Class CommandParsingSimple
+//
+
+// Constructor
+CommandParsingSimple::CommandParsingSimple()
+    : separator_(_T(' ')) {
+}
+
+// Constructor
+CommandParsingSimple::CommandParsingSimple(TCHAR separator)
+    : separator_(separator) {
+}
+
+// Parse a command line string into args
+HRESULT CommandParsingSimple::ParseSimple(const TCHAR* cmd_line) {
+  ASSERT1(cmd_line);
+
+  UTIL_LOG(L3, (_T("[CommandParsingSimple::ParseSimple][%s]"), cmd_line));
+
+  args_.clear();
+
+  // Split command line string into list of arguments
+  for (const TCHAR* s = cmd_line; *s; ++s) {
+    // Handle separator
+    if (*s == separator_) {
+      continue;
+    }
+
+    // Handle single/double quote
+    if (*s == _T('"') || *s == _T('\'')) {
+      int right_quote = String_FindChar(s + 1, *s);
+      if (right_quote == -1) {
+        UTIL_LOG(LE, (_T("[CommandParsingSimple::ParseSimple]")
+                      _T("[single/double quote mismatches]")));
+        return CI_E_INVALID_ARG;
+      }
+      args_.push_back(CString(s + 1, right_quote));
+      s += right_quote + 1;
+      continue;
+    }
+
+    // Handle all other char
+    int next_space = String_FindChar(s + 1, separator_);
+    if (next_space == -1) {
+      args_.push_back(CString(s));
+      break;
+    } else {
+      args_.push_back(CString(s, next_space + 1));
+      s += next_space + 1;
+    }
+  }
+
+  return S_OK;
+}
+
+// Get the arg at specified position from the command line
+HRESULT CommandParsingSimple::GetAt(uint32 position, CString* arg) {
+  ASSERT1(arg);
+  ASSERT1(position < args_.size());
+
+  if (!arg || position >= args_.size()) {
+    return E_INVALIDARG;
+  }
+
+  *arg = args_[position];
+  return S_OK;
+}
+
+// Remove the arg at specified position from the command line
+HRESULT CommandParsingSimple::RemoveAt(uint32 position) {
+  ASSERT1(position < args_.size());
+
+  if (position >= args_.size()) {
+    return E_INVALIDARG;
+  }
+
+  uint32 i = 0;
+  std::vector<CString>::iterator it(args_.begin());
+  for (; i < position; ++it, ++i) {
+    ASSERT1(it != args_.end());
+  }
+  args_.erase(it);
+  return S_OK;
+}
+
+// Converted to the string
+HRESULT CommandParsingSimple::ToString(CString* cmd_line) {
+  ASSERT1(cmd_line);
+
+  bool is_first = true;
+  cmd_line->Empty();
+  for (std::vector<CString>::const_iterator it(args_.begin());
+       it != args_.end();
+       ++it) {
+    if (is_first) {
+      is_first = false;
+    } else {
+      cmd_line->AppendChar(separator_);
+    }
+    const TCHAR* arg = it->GetString();
+    if (String_FindChar(arg, separator_) != -1) {
+      cmd_line->AppendChar(_T('"'));
+      cmd_line->Append(arg);
+      cmd_line->AppendChar(_T('"'));
+    } else {
+      cmd_line->Append(arg);
+    }
+  }
+
+  return S_OK;
+}
+
+// Static Helper function that splits a command line
+// string into executable and any arguments
+HRESULT CommandParsingSimple::SplitExeAndArgs(const TCHAR* cmd_line,
+                                              CString* exe,
+                                              CString* args) {
+  ASSERT1(cmd_line);
+  ASSERT1(exe);
+  ASSERT1(args);
+
+  // Do the parsing
+  CommandParsingSimple cmd_parsing_simple;
+
+  RET_IF_FAILED(cmd_parsing_simple.ParseSimple(cmd_line));
+  RET_IF_FAILED(cmd_parsing_simple.GetAt(0, exe));
+  exe->Trim();
+  RET_IF_FAILED(cmd_parsing_simple.RemoveAt(0));
+  return (cmd_parsing_simple.ToString(args));
+}
+
+HRESULT CommandParsingSimple::SplitExeAndArgsGuess(const TCHAR* cmd_line,
+                                                   CString* exe,
+                                                   CString* args) {
+  ASSERT1(cmd_line);
+  ASSERT1(exe);
+  ASSERT1(args);
+
+  if (File::Exists(cmd_line)) {
+    // Optimization for the single executable case.
+    // Fill the [out] parameters and return.
+    *exe = cmd_line;
+    exe->Trim();
+    args->Empty();
+    return S_OK;
+  }
+
+  CString command_line(cmd_line);
+  // Check if the command line is properly enclosed, or that it does not have
+  // spaces
+  if (command_line.GetAt(0) != _T('"') && command_line.Find(_T(' ')) != -1) {
+    // File::Exists() does not handle leading spaces so remove it.
+    command_line.Trim();
+
+    // If not, need to find the executable, and if valid, enclose it in
+    // double quotes
+    const TCHAR* index_dot_exe = stristrW(command_line.GetString(), _T(".EXE"));
+
+    if (index_dot_exe != NULL) {
+      int dot_exe_end = (index_dot_exe - command_line.GetString())
+                         + arraysize(_T(".EXE")) - 1;
+      if (File::Exists(CString(command_line, dot_exe_end))) {
+        // Enclose the EXE in double quotes
+        command_line.Insert(dot_exe_end, _T('"'));
+        command_line.Insert(0, _T('"'));
+      } else {
+        UTIL_LOG(L1, (_T("[CommandParsing::SplitExeAndArgsGuess]")
+                      _T("[Could not guess the Executable file within [%s]. ")
+                      _T("Passing on to SplitExeAndArgs as-is."),
+                      command_line));
+      }
+    }
+  }
+
+  // Do the parsing
+  return SplitExeAndArgs(command_line, exe, args);
+}
+
+
+// Static Helper function that returns the number of arguments
+// in the passed in cmd_line
+HRESULT CommandParsingSimple::GetNumberOfArgs(const TCHAR* cmd_line,
+                                              uint32* number_of_args) {
+  ASSERT1(cmd_line);
+  ASSERT1(number_of_args);
+
+  // Do the parsing
+  CommandParsingSimple cmd_parsing_simple;
+
+  RET_IF_FAILED(cmd_parsing_simple.ParseSimple(cmd_line));
+  *number_of_args = cmd_parsing_simple.args_.size();
+  return S_OK;
+}
+
+
+//
+// Class CommandParsing
+//
+
+// Constructor
+CommandParsing::CommandParsing(CommandOption* options, int options_count)
+    : CommandParsingSimple(),
+      options_(options),
+      options_count_(options_count),
+      as_name_value_pair_(false) {
+}
+
+// Constructor
+CommandParsing::CommandParsing(CommandOption* options, int options_count,
+                               TCHAR separator, bool as_name_value_pair)
+    : CommandParsingSimple(separator),
+      options_(options),
+      options_count_(options_count),
+      as_name_value_pair_(as_name_value_pair) {
+}
+
+// Parse a command line string
+HRESULT CommandParsing::Parse(const TCHAR* cmd_line, bool ignore_unknown_args) {
+  ASSERT1(cmd_line);
+
+  UTIL_LOG(L3, (_T("[CommandParsing::Parse][%s][%d]"),
+                cmd_line, ignore_unknown_args));
+
+  // Parse into args_ vector
+  RET_IF_FAILED(ParseSimple(cmd_line));
+
+  // Do the internal parsing
+  return InternalParse(ignore_unknown_args);
+}
+
+// Parse a list of command line arguments
+HRESULT CommandParsing::ParseArguments(int argc, TCHAR* argv[]) {
+  if (argc <= 1) {
+    return S_OK;
+  }
+
+  // Push each argument
+  args_.clear();
+  for (int i = 1; i < argc; ++i) {
+    args_.push_back(CString(argv[i]));
+  }
+
+  // Do the internal parsing
+  return InternalParse(false);
+}
+
+// Internal parsing
+HRESULT CommandParsing::InternalParse(bool ignore_unknown_args) {
+  CString name, value;
+  for (std::vector<CString>::const_iterator it(args_.begin());
+       it != args_.end();
+       ++it) {
+    RET_IF_FAILED(ExtractName(&name, &it));
+
+    int i = FindOption(name);
+    if (i == -1) {
+      if (ignore_unknown_args) {
+        UTIL_LOG(L3, (_T("[CommandParsing::Parse][unknown arg %s]"), name));
+        continue;
+      } else {
+        UTIL_LOG(LE, (_T("[CommandParsing::Parse][invalid arg %s]"), name));
+        return CI_E_INVALID_ARG;
+      }
+    }
+
+    if (options_[i].type != COMMAND_OPTION_BOOL) {
+      RET_IF_FAILED(ExtractValue(options_[i], &value, &it, args_.end()));
+    }
+
+    switch (options_[i].type & COMMAND_OPTION_FLAGS_MASK) {
+      case COMMAND_OPTION_BOOL: {
+        bool bool_value = true;
+        SetParsedValue(options_[i], bool_value);
+        break;
+      }
+
+      case COMMAND_OPTION_THREE: {
+        ThreeValue three_value = VALUE_NOT_SET;
+        RET_IF_FAILED(ConvertValue(value, &three_value));
+        SetParsedValue(options_[i], three_value);
+        break;
+      }
+
+      case COMMAND_OPTION_INT: {
+        int int_value = 0;
+        RET_IF_FAILED(ConvertValue(value, &int_value));
+        SetParsedValue(options_[i], int_value);
+        break;
+      }
+
+      case COMMAND_OPTION_UINT: {
+        int uint_value = 0;
+        RET_IF_FAILED(ConvertValue(value, &uint_value));
+        SetParsedValue(options_[i], uint_value);
+        break;
+      }
+
+      case COMMAND_OPTION_STRING: {
+        CString str_value;
+        bool is_unescape = (options_[i].type & COMMAND_OPTION_UNESCAPE) != 0;
+        RET_IF_FAILED(ConvertValue(value, &str_value, is_unescape));
+        SetParsedValue(options_[i], str_value);
+        break;
+      }
+
+      default:
+        ASSERT1(false);
+        break;
+    }
+  }
+
+  return S_OK;
+}
+
+// Extract the name
+HRESULT CommandParsing::ExtractName(CString* name,
+                                    std::vector<CString>::const_iterator* it) {
+  ASSERT1(name);
+  ASSERT1(it);
+
+  if (as_name_value_pair_) {
+    int idx = (*it)->Find(kNameValueChar);
+    if (idx == -1) {
+      return CI_E_INVALID_ARG;
+    } else {
+      *name = (*it)->Left(idx);
+    }
+  } else {
+    *name = (*it)->GetString();
+  }
+  return S_OK;
+}
+
+// Extract the value
+// Also validate the value length if necessary
+HRESULT CommandParsing::ExtractValue(
+    const CommandOption& option,
+    CString* value,
+    std::vector<CString>::const_iterator* it,
+    const std::vector<CString>::const_iterator& end) {
+  ASSERT1(value);
+  ASSERT1(it);
+
+  if (as_name_value_pair_) {
+    int idx = (*it)->Find(kNameValueChar);
+    if (idx == -1) {
+      return CI_E_INVALID_ARG;
+    } else {
+      *value = (*it)->Right((*it)->GetLength() - idx - 1);
+    }
+  } else {
+    ++(*it);
+    if (*it == end) {
+      UTIL_LOG(LE, (_T("[CommandParsing::ExtractValue]")
+                    _T("[argument %s missing value]"), option.name));
+      return CI_E_INVALID_ARG;
+    }
+    *value = (*it)->GetString();
+  }
+
+  if (option.max_value_len >= 0) {
+    if (value->GetLength() > option.max_value_len) {
+      return CI_E_INVALID_ARG;
+    }
+  }
+
+  return S_OK;
+}
+
+// Set the parsed value
+template<class T>
+void CommandParsing::SetParsedValue(const CommandOption& option,
+                                    const T& value) {
+  if (option.type & COMMAND_OPTION_MULTIPLE) {
+    ASSERT((option.type & COMMAND_OPTION_FLAGS_MASK) != COMMAND_OPTION_BOOL,
+      (_T("COMMAND_OPTION_BOOL can't be used with COMMAND_OPTION_MULTIPLE")));
+    ASSERT((option.type & COMMAND_OPTION_FLAGS_MASK) != COMMAND_OPTION_THREE,
+      (_T("COMMAND_OPTION_THREE can't be used with COMMAND_OPTION_MULTIPLE")));
+
+    std::vector<T>* ptr = reinterpret_cast<std::vector<T>*>(option.value);
+    ptr->push_back(value);
+  } else {
+    T* ptr = reinterpret_cast<T*>(option.value);
+    *ptr = value;
+  }
+}
+
+// Helper function to find an option in the CommandOption list
+int CommandParsing::FindOption(const TCHAR* option_name) {
+  ASSERT1(option_name);
+
+  for (int i = 0; i < options_count_; ++i) {
+    if (String_StrNCmp(option_name,
+                       options_[i].name,
+                       options_[i].name.GetLength() + 1,
+                       false) == 0) {
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+// Remove an option from the command line
+HRESULT CommandParsing::Remove(const TCHAR* option_name) {
+  ASSERT1(option_name);
+
+  for (std::vector<CString>::iterator it(args_.begin());
+       it != args_.end();
+       ++it) {
+    if (*it == option_name) {
+      int i = FindOption(option_name);
+      if (i == -1) {
+        return E_FAIL;
+      }
+      args_.erase(it);
+      if (!as_name_value_pair_) {
+        if (options_[i].type != COMMAND_OPTION_BOOL) {
+          if (it == args_.end()) {
+            return E_FAIL;
+          }
+          args_.erase(it);
+        }
+      }
+
+      return S_OK;
+    }
+  }
+
+  return E_FAIL;
+}
+
+}  // namespace omaha
+
diff --git a/common/commands.h b/common/commands.h
index 4f6d1a9..c2a857b 100644
--- a/common/commands.h
+++ b/common/commands.h
@@ -1,159 +1,159 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Parse command-line options

-//

-// Class CommandParsing supports two kinds of command line options:

-// 1) Traditional option, like "-b -v 100"

-// 2) Name-value-pairs, like "b=&v=100"

-

-#ifndef OMAHA_COMMON_COMMANDS_H_

-#define OMAHA_COMMON_COMMANDS_H_

-

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-enum ThreeValue {

-  VALUE_NOT_SET = 0,

-  TRUE_VALUE = 1,

-  FALSE_VALUE = 2

-};

-

-enum CommandOptionType {

-  COMMAND_OPTION_BOOL = 0x1,

-  COMMAND_OPTION_INT = 0x2,

-  COMMAND_OPTION_UINT = 0x3,

-  COMMAND_OPTION_STRING = 0x4,

-  COMMAND_OPTION_THREE = 0x5,

-  COMMAND_OPTION_UNESCAPE = 0x1000,

-  COMMAND_OPTION_MULTIPLE = 0x2000

-};

-

-#define COMMAND_OPTION_FLAGS_MASK   0x0FFF

-

-struct CommandOption {

-  void Init(const TCHAR* name, CommandOptionType type,

-            void* value, int max_value_len);

-  void Copy(const CommandOption& option);

-

-  CString name;

-  CommandOptionType type;

-  void* value;

-  int max_value_len;

-};

-

-class CommandParsingSimple {

- public:

-  // Static Helper function that splits a command line

-  // string into executable and any arguments

-  static HRESULT SplitExeAndArgs(const TCHAR* cmd_line,

-                                 CString* exe,

-                                 CString* args);

-

-  // Static Helper function that splits a command line

-  // string into executable and any arguments. Tries to

-  // guess the positioning of the EXE argument in cases

-  // where the EXE argument has spaces and is not enclosed

-  // in quotes. For instance, earlier versions of Google Desktop

-  // used to have an "Uninstall" string of the form:

-  // C:\Program Files\Google\Google Toolbar\GoogleToolbarSetup.exe -uninstall

-  // This function is meant to accomodate such cases.

-  static HRESULT SplitExeAndArgsGuess(const TCHAR* cmd_line,

-                                      CString* exe,

-                                      CString* args);

-

-  // Static Helper function that returns the number of arguments

-  // in the passed in cmd_line

-  static HRESULT GetNumberOfArgs(const TCHAR* cmd_line, uint32* number_of_args);

-

-  // Converted to a string

-  HRESULT ToString(CString* cmd_line);

-

- protected:

-  // Constructor

-  CommandParsingSimple();

-

-  // Constructor

-  explicit CommandParsingSimple(TCHAR separator);

-

-  // Parse a command line string into args

-  HRESULT ParseSimple(const TCHAR* cmd_line);

-

-  // Get the arg at specified position from the command line

-  HRESULT GetAt(uint32 position, CString* arg);

-

-  // Remove the arg at specified position from the command line

-  HRESULT RemoveAt(uint32 position);

-

-  TCHAR separator_;                   // Separator

-  std::vector<CString> args_;         // Splitted args

-

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(CommandParsingSimple);

-};

-

-

-class CommandParsing : public CommandParsingSimple {

- public:

-  // Constructor

-  CommandParsing(CommandOption* options, int options_count);

-

-  CommandParsing(CommandOption* options, int options_count,

-                 TCHAR separator, bool as_name_value_pair);

-

-  // Parse a command line string

-  HRESULT Parse(const TCHAR* cmd_line, bool ignore_unknown_args);

-

-  // Parse a list of command line arguments

-  HRESULT ParseArguments(int argc, TCHAR* argv[]);

-

-  // Remove an option from the command line

-  HRESULT Remove(const TCHAR* option_name);

-

- private:

-  // Internal parsing

-  HRESULT InternalParse(bool ignore_unknown_args);

-

-  // Extract the name

-  HRESULT ExtractName(CString* name, std::vector<CString>::const_iterator* it);

-

-  // Extract the value

-  // Also validate the value length if necessary

-  HRESULT ExtractValue(const CommandOption& option,

-                       CString* value,

-                       std::vector<CString>::const_iterator* it,

-                       const std::vector<CString>::const_iterator& end);

-

-  // Set the parsed value

-  template<class T>

-  static void SetParsedValue(const CommandOption& option, const T& value);

-

-  // Helper function to find an option in the CommandOption list

-  int FindOption(const TCHAR* option_name);

-

-  CommandOption* options_;            // Command-line option list

-  int options_count_;                 // Count of command-line options

-  bool as_name_value_pair_;           // Parse as name-value-pair

-

-  DISALLOW_EVIL_CONSTRUCTORS(CommandParsing);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_COMMANDS_H_

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Parse command-line options
+//
+// Class CommandParsing supports two kinds of command line options:
+// 1) Traditional option, like "-b -v 100"
+// 2) Name-value-pairs, like "b=&v=100"
+
+#ifndef OMAHA_COMMON_COMMANDS_H_
+#define OMAHA_COMMON_COMMANDS_H_
+
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+enum ThreeValue {
+  VALUE_NOT_SET = 0,
+  TRUE_VALUE = 1,
+  FALSE_VALUE = 2
+};
+
+enum CommandOptionType {
+  COMMAND_OPTION_BOOL = 0x1,
+  COMMAND_OPTION_INT = 0x2,
+  COMMAND_OPTION_UINT = 0x3,
+  COMMAND_OPTION_STRING = 0x4,
+  COMMAND_OPTION_THREE = 0x5,
+  COMMAND_OPTION_UNESCAPE = 0x1000,
+  COMMAND_OPTION_MULTIPLE = 0x2000
+};
+
+#define COMMAND_OPTION_FLAGS_MASK   0x0FFF
+
+struct CommandOption {
+  void Init(const TCHAR* name, CommandOptionType type,
+            void* value, int max_value_len);
+  void Copy(const CommandOption& option);
+
+  CString name;
+  CommandOptionType type;
+  void* value;
+  int max_value_len;
+};
+
+class CommandParsingSimple {
+ public:
+  // Static Helper function that splits a command line
+  // string into executable and any arguments
+  static HRESULT SplitExeAndArgs(const TCHAR* cmd_line,
+                                 CString* exe,
+                                 CString* args);
+
+  // Static Helper function that splits a command line
+  // string into executable and any arguments. Tries to
+  // guess the positioning of the EXE argument in cases
+  // where the EXE argument has spaces and is not enclosed
+  // in quotes. For instance, earlier versions of Google Desktop
+  // used to have an "Uninstall" string of the form:
+  // C:\Program Files\Google\Google Toolbar\GoogleToolbarSetup.exe -uninstall
+  // This function is meant to accomodate such cases.
+  static HRESULT SplitExeAndArgsGuess(const TCHAR* cmd_line,
+                                      CString* exe,
+                                      CString* args);
+
+  // Static Helper function that returns the number of arguments
+  // in the passed in cmd_line
+  static HRESULT GetNumberOfArgs(const TCHAR* cmd_line, uint32* number_of_args);
+
+  // Converted to a string
+  HRESULT ToString(CString* cmd_line);
+
+ protected:
+  // Constructor
+  CommandParsingSimple();
+
+  // Constructor
+  explicit CommandParsingSimple(TCHAR separator);
+
+  // Parse a command line string into args
+  HRESULT ParseSimple(const TCHAR* cmd_line);
+
+  // Get the arg at specified position from the command line
+  HRESULT GetAt(uint32 position, CString* arg);
+
+  // Remove the arg at specified position from the command line
+  HRESULT RemoveAt(uint32 position);
+
+  TCHAR separator_;                   // Separator
+  std::vector<CString> args_;         // Splitted args
+
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(CommandParsingSimple);
+};
+
+
+class CommandParsing : public CommandParsingSimple {
+ public:
+  // Constructor
+  CommandParsing(CommandOption* options, int options_count);
+
+  CommandParsing(CommandOption* options, int options_count,
+                 TCHAR separator, bool as_name_value_pair);
+
+  // Parse a command line string
+  HRESULT Parse(const TCHAR* cmd_line, bool ignore_unknown_args);
+
+  // Parse a list of command line arguments
+  HRESULT ParseArguments(int argc, TCHAR* argv[]);
+
+  // Remove an option from the command line
+  HRESULT Remove(const TCHAR* option_name);
+
+ private:
+  // Internal parsing
+  HRESULT InternalParse(bool ignore_unknown_args);
+
+  // Extract the name
+  HRESULT ExtractName(CString* name, std::vector<CString>::const_iterator* it);
+
+  // Extract the value
+  // Also validate the value length if necessary
+  HRESULT ExtractValue(const CommandOption& option,
+                       CString* value,
+                       std::vector<CString>::const_iterator* it,
+                       const std::vector<CString>::const_iterator& end);
+
+  // Set the parsed value
+  template<class T>
+  static void SetParsedValue(const CommandOption& option, const T& value);
+
+  // Helper function to find an option in the CommandOption list
+  int FindOption(const TCHAR* option_name);
+
+  CommandOption* options_;            // Command-line option list
+  int options_count_;                 // Count of command-line options
+  bool as_name_value_pair_;           // Parse as name-value-pair
+
+  DISALLOW_EVIL_CONSTRUCTORS(CommandParsing);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_COMMANDS_H_
diff --git a/common/commands_unittest.cc b/common/commands_unittest.cc
index 5a6d473..8071432 100644
--- a/common/commands_unittest.cc
+++ b/common/commands_unittest.cc
@@ -1,430 +1,430 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Unit tests of command line options parsing

-

-#include <cstdio>

-#include "omaha/common/commands.h"

-#include "omaha/common/file.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-#define kDash         _T("-")

-#define kBoolOption   _T("bool")

-#define kThreeOption  _T("three")

-#define kIntOption    _T("int")

-#define kUintOption   _T("uint")

-#define kStrOption    _T("str")

-

-#define kIEBrowserExe \

-  _T("C:\\PROGRAM FILES\\Internet Explorer\\iexplore.exe")

-

-#define kIEBrowserQuotedExe \

-  _T("\"") kIEBrowserExe _T("\"")

-

-#define kIEBrowserQuotedArgs          _T("-h \"%1\"")

-#define kIEBrowserQuotedCommandLine \

-    kIEBrowserQuotedExe _T(" ") kIEBrowserQuotedArgs

-

-#define kIEBrowserQuotedExeResult \

-    _T("C:\\PROGRAM FILES\\Internet Explorer\\iexplore.exe")

-#define kIEBrowserQuotedArgsResult    _T("-h %1")

-

-#define kIEBrowserUnquotedCommandLine \

-    _T("C:\\Program Files\\Internet Explorer\\iexplore.exe -nohome")

-#define kIEBrowserUnquotedExe \

-    _T("C:\\Program Files\\Internet Explorer\\iexplore.exe")

-#define kIEBrowserUnquotedArgs        _T("-nohome")

-

-#define kGEUninstallCommandLine       _T("RunDll32 C:\\PROGRA~1\\COMMON~1\\INSTAL~1\\PROFES~1\\RunTime\\10\\01\\Intel32\\Ctor.dll,LaunchSetup \"C:\\Program Files\\InstallShield Installation Information\\{3DE5E7D4-7B88-403C-A3FD-2017A8240C5B}\\setup.exe\" -l0x9  -removeonly")  // NOLINT

-#define kGEUninstallExe               _T("RunDll32")

-#define kGEUninstallArgs              _T("C:\\PROGRA~1\\COMMON~1\\INSTAL~1\\PROFES~1\\RunTime\\10\\01\\Intel32\\Ctor.dll,LaunchSetup \"C:\\Program Files\\InstallShield Installation Information\\{3DE5E7D4-7B88-403C-A3FD-2017A8240C5B}\\setup.exe\" -l0x9 -removeonly")            // NOLINT

-

-

-struct TestData {

-  TestData() {

-    Clear();

-  }

-

-  void Clear() {

-    bool_value = false;

-    three_value = VALUE_NOT_SET;

-    int_value = 0;

-    uint_value = 0;

-    str_value.Empty();

-  }

-

-  bool bool_value;

-  ThreeValue three_value;

-  int int_value;

-  uint32 uint_value;

-  CString str_value;

-};

-

-void FillTestData(TestData* data) {

-  data->bool_value = true;

-  data->three_value = FALSE_VALUE;

-  data->int_value = -128;

-  data->uint_value = 256;

-  data->str_value = _T("Foo");

-}

-

-void CheckTestData(const TestData& d1, const TestData& d2) {

-  EXPECT_EQ(d1.bool_value, d2.bool_value);

-  EXPECT_EQ(d1.three_value, d2.three_value);

-  EXPECT_EQ(d1.int_value, d2.int_value);

-  EXPECT_EQ(d1.uint_value, d2.uint_value);

-  EXPECT_STREQ(d1.str_value, d2.str_value);

-}

-

-TEST(CommandsTest, TraditionalCommandLineOptionsParsingTest) {

-  TestData data;

-  FillTestData(&data);

-  CString cmd_line;

-  cmd_line.Format(_T("%s%s %s ")

-                  _T("%s%s %d ")

-                  _T("%s%s %u ")

-                  _T("%s%s %s "),

-                  kDash, kThreeOption, (data.three_value == TRUE_VALUE) ? _T("on") : _T("off"),   // NOLINT

-                  kDash, kIntOption, data.int_value,

-                  kDash, kUintOption, data.uint_value,

-                  kDash, kStrOption, data.str_value);

-  if (data.bool_value) {

-    cmd_line.AppendFormat(_T("%s%s"), kDash, kBoolOption);

-  }

-

-  TestData option_data;

-  CommandOption cmd_options[] = {

-    { kDash kBoolOption,  COMMAND_OPTION_BOOL,   &option_data.bool_value,  -1 },

-    { kDash kThreeOption, COMMAND_OPTION_THREE,  &option_data.three_value, -1 },

-    { kDash kIntOption,   COMMAND_OPTION_INT,    &option_data.int_value,   -1 },

-    { kDash kUintOption,  COMMAND_OPTION_UINT,   &option_data.uint_value,  -1 },

-    { kDash kStrOption,   COMMAND_OPTION_STRING, &option_data.str_value,   -1 }

-  };

-

-  option_data.Clear();

-  CommandParsing cmd_parsing(cmd_options, arraysize(cmd_options));

-  ASSERT_SUCCEEDED(cmd_parsing.Parse(cmd_line, false));

-

-  CheckTestData(option_data, data);

-}

-

-TEST(CommandsTest, TraditionalIgnoreUnknownArgsParsingTest) {

-  TestData data;

-  FillTestData(&data);

-  CString cmd_line;

-  cmd_line.Format(_T("%s%s %s ")

-                  _T("%s%s %d ")

-                  _T("%s%s %u ")

-                  _T("%s%s %s "),

-                  kDash, kThreeOption, (data.three_value == TRUE_VALUE) ? _T("on") : _T("off"),   // NOLINT

-                  kDash, kIntOption, data.int_value,

-                  kDash, kUintOption, data.uint_value,

-                  kDash, kStrOption, data.str_value);

-  if (data.bool_value) {

-    cmd_line.AppendFormat(_T("%s%s"), kDash, kBoolOption);

-  }

-

-  TestData option_data;

-  CommandOption cmd_options[] = {

-    { kDash kThreeOption, COMMAND_OPTION_THREE,  &option_data.three_value, -1 },

-    { kDash kIntOption,   COMMAND_OPTION_INT,    &option_data.int_value,   -1 },

-    { kDash kUintOption,  COMMAND_OPTION_UINT,   &option_data.uint_value,  -1 },

-    { kDash kStrOption,   COMMAND_OPTION_STRING, &option_data.str_value,   -1 }

-  };

-

-  option_data.Clear();

-  CommandParsing cmd_parsing(cmd_options, arraysize(cmd_options));

-  ASSERT_FAILED(cmd_parsing.Parse(cmd_line, false));

-  ASSERT_SUCCEEDED(cmd_parsing.Parse(cmd_line, true));

-

-  option_data.bool_value = data.bool_value;

-  CheckTestData(option_data, data);

-}

-

-TEST(CommandsTest, NameValuePairCommandLineOptionsParsingTest) {

-  TestData data;

-  FillTestData(&data);

-  CString cmd_line;

-  cmd_line.Format(

-      _T("%s=%s&")

-      _T("%s=%d&")

-      _T("%s=%u&")

-      _T("%s=%s"),

-      kThreeOption, (data.three_value == TRUE_VALUE) ? _T("on") : _T("off"),

-      kIntOption, data.int_value,

-      kUintOption, data.uint_value,

-      kStrOption, data.str_value);

-  if (data.bool_value) {

-    cmd_line.AppendFormat(_T("&%s="), kBoolOption);

-  }

-

-  TestData option_data;

-  CommandOption cmd_options[] = {

-    { kBoolOption,  COMMAND_OPTION_BOOL,   &option_data.bool_value,    -1 },

-    { kThreeOption, COMMAND_OPTION_THREE,  &option_data.three_value,   -1 },

-    { kIntOption,   COMMAND_OPTION_INT,    &option_data.int_value,     -1 },

-    { kUintOption,  COMMAND_OPTION_UINT,   &option_data.uint_value,    -1 },

-    { kStrOption,   COMMAND_OPTION_STRING, &option_data.str_value,     -1 }

-  };

-

-  option_data.Clear();

-  CommandParsing cmd_parsing(cmd_options,

-                             arraysize(cmd_options),

-                             _T('&'),

-                             true);

-  ASSERT_SUCCEEDED(cmd_parsing.Parse(cmd_line, false));

-

-  CheckTestData(option_data, data);

-}

-

-TEST(CommandsTest, NameValuePairIgnoreUnknownArgsParsingTest) {

-  TestData data;

-  FillTestData(&data);

-  CString cmd_line;

-  cmd_line.Format(

-      _T("%s=%s&")

-      _T("%s=%d&")

-      _T("%s=%u&")

-      _T("%s=%s"),

-      kThreeOption, (data.three_value == TRUE_VALUE) ? _T("on") : _T("off"),

-      kIntOption, data.int_value,

-      kUintOption, data.uint_value,

-      kStrOption, data.str_value);

-  if (data.bool_value) {

-    cmd_line.AppendFormat(_T("&%s="), kBoolOption);

-  }

-

-  TestData option_data;

-  CommandOption cmd_options[] = {

-    { kBoolOption,  COMMAND_OPTION_BOOL,   &option_data.bool_value,    -1 },

-    { kThreeOption, COMMAND_OPTION_THREE,  &option_data.three_value,   -1 },

-    { kUintOption,  COMMAND_OPTION_UINT,   &option_data.uint_value,    -1 },

-    { kStrOption,   COMMAND_OPTION_STRING, &option_data.str_value,     -1 }

-  };

-

-  option_data.Clear();

-  CommandParsing cmd_parsing(cmd_options,

-                             arraysize(cmd_options),

-                             _T('&'),

-                             true);

-  ASSERT_FAILED(cmd_parsing.Parse(cmd_line, false));

-  ASSERT_SUCCEEDED(cmd_parsing.Parse(cmd_line, true));

-

-  option_data.int_value = data.int_value;

-  CheckTestData(option_data, data);

-}

-

-TEST(CommandsTest, CommandParsingSimpleSplitTest) {

-  CString exe;

-  CString args;

-

-  // Test to make sure SplitExeAndArgs correctly splits

-  // a properly constructed command line

-  ASSERT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgs(kIEBrowserQuotedCommandLine,

-                                          &exe,

-                                          &args));

-

-  EXPECT_STREQ(kIEBrowserQuotedExeResult, exe);

-  EXPECT_STREQ(kIEBrowserQuotedArgsResult, args);

-}

-

-TEST(CommandsTest, CommandParsingGuessSplitTest) {

-  CString exe;

-  CString args;

-

-  // Test to make sure SplitExeAndArgsGuess correctly splits

-  // a properly constructed command line

-  ASSERT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserQuotedCommandLine,

-                                               &exe,

-                                               &args));

-

-  EXPECT_STREQ(kIEBrowserQuotedExeResult, exe);

-  EXPECT_STREQ(kIEBrowserQuotedArgsResult, args);

-

-  // Test to make sure SplitExeAndArgsGuess correctly splits

-  // an improperly constructed "Uninstall" command line

-  ASSERT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserUnquotedCommandLine,

-                                               &exe,

-                                               &args));

-

-  EXPECT_STREQ(kIEBrowserUnquotedExe, exe);

-  EXPECT_STREQ(kIEBrowserUnquotedArgs, args);

-

-  // Test to make sure SplitExeAndArgsGuess correctly splits

-  // a properly constructed "Uninstall" command line, where

-  // the executable does not have a ".EXE" extension, and

-  // where there happens to be an argument which happens to

-  // be an executable

-  ASSERT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(kGEUninstallCommandLine,

-                                               &exe,

-                                               &args));

-

-  EXPECT_STREQ(kGEUninstallExe, exe);

-  EXPECT_STREQ(kGEUninstallArgs, args);

-}

-

-TEST(CommandsTest, CommandParsingGuessSplit_ExtraWhiteSpace) {

-  CString exe;

-  CString args;

-

-  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(

-      kIEBrowserUnquotedCommandLine _T(" "),

-      &exe,

-      &args));

-  EXPECT_STREQ(kIEBrowserUnquotedExe, exe);

-  EXPECT_STREQ(kIEBrowserUnquotedArgs, args);

-

-  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(

-      kIEBrowserUnquotedCommandLine _T("\t"),

-      &exe,

-      &args));

-  EXPECT_STREQ(kIEBrowserUnquotedExe, exe);

-  EXPECT_STREQ(kIEBrowserUnquotedArgs, args);

-

-  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(

-      _T(" ") kIEBrowserUnquotedCommandLine,

-      &exe,

-      &args));

-  EXPECT_STREQ(kIEBrowserUnquotedExe, exe);

-  EXPECT_STREQ(kIEBrowserUnquotedArgs, args);

-

-  // The following cases have unexpected results.

-  // Quoting a command line with args is not handled correctly.

-  // The entire thing is interpreted as an EXE.

-

-  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(

-      _T("\" ") kIEBrowserUnquotedCommandLine _T("\""),

-      &exe,

-      &args));

-  EXPECT_STREQ(kIEBrowserUnquotedCommandLine, exe);

-  EXPECT_TRUE(args.IsEmpty());

-

-  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(

-      _T("\"") kIEBrowserUnquotedCommandLine _T(" \""),

-      &exe,

-      &args));

-  EXPECT_STREQ(kIEBrowserUnquotedCommandLine, exe);

-  EXPECT_TRUE(args.IsEmpty());

-

-  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(

-      _T("\"") kIEBrowserUnquotedCommandLine _T("\t\""),

-      &exe,

-      &args));

-  EXPECT_STREQ(kIEBrowserUnquotedCommandLine, exe);

-  EXPECT_TRUE(args.IsEmpty());

-}

-

-TEST(CommandsTest, CommandParsingGuessSplit_CommandLineIsExistingFile) {

-  CString exe;

-  CString args;

-

-  EXPECT_TRUE(File::Exists(kIEBrowserExe));

-  EXPECT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserExe, &exe, &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  EXPECT_TRUE(args.IsEmpty());

-

-  // File::Exists does not handle enclosed paths.

-  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe));

-  EXPECT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserQuotedExe,

-                                               &exe,

-                                               &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  EXPECT_TRUE(args.IsEmpty());

-}

-

-TEST(CommandsTest,

-     CommandParsingGuessSplit_CommandLineIsExistingFileWithExtraWhiteSpace) {

-  CString exe;

-  CString args;

-

-  EXPECT_TRUE(File::Exists(kIEBrowserExe));

-  // File::Exists does not handle enclosed paths.

-  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe));

-

-  EXPECT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserExe _T(" "),

-                                               &exe,

-                                               &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  EXPECT_TRUE(args.IsEmpty());

-

-  EXPECT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserQuotedExe _T(" "),

-                                               &exe,

-                                               &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  EXPECT_TRUE(args.IsEmpty());

-

-  EXPECT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserExe _T("\t"),

-                                               &exe,

-                                               &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  EXPECT_TRUE(args.IsEmpty());

-

-  EXPECT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserQuotedExe _T("\t"),

-                                               &exe,

-                                               &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  // SplitExeAndArgs does not treat tab like whitespace and args aren't trimmed.

-  EXPECT_STREQ(_T("\t"), args);

-

-  EXPECT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(_T(" ") kIEBrowserExe,

-                                               &exe,

-                                               &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  EXPECT_TRUE(args.IsEmpty());

-

-  EXPECT_SUCCEEDED(

-    CommandParsingSimple::SplitExeAndArgsGuess(_T(" ") kIEBrowserQuotedExe,

-                                               &exe,

-                                               &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  EXPECT_TRUE(args.IsEmpty());

-

-  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(

-                       _T("\" ") kIEBrowserExe _T("\""),

-                       &exe,

-                       &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  EXPECT_TRUE(args.IsEmpty());

-

-  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(

-                       _T("\"") kIEBrowserExe _T(" \""),

-                       &exe,

-                       &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  EXPECT_TRUE(args.IsEmpty());

-

-  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(

-                       _T("\"") kIEBrowserExe _T("\t\""),

-                       &exe,

-                       &args));

-  EXPECT_STREQ(kIEBrowserExe, exe);

-  EXPECT_TRUE(args.IsEmpty());

-}

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Unit tests of command line options parsing
+
+#include <cstdio>
+#include "omaha/common/commands.h"
+#include "omaha/common/file.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+#define kDash         _T("-")
+#define kBoolOption   _T("bool")
+#define kThreeOption  _T("three")
+#define kIntOption    _T("int")
+#define kUintOption   _T("uint")
+#define kStrOption    _T("str")
+
+#define kIEBrowserExe \
+  _T("C:\\PROGRAM FILES\\Internet Explorer\\iexplore.exe")
+
+#define kIEBrowserQuotedExe \
+  _T("\"") kIEBrowserExe _T("\"")
+
+#define kIEBrowserQuotedArgs          _T("-h \"%1\"")
+#define kIEBrowserQuotedCommandLine \
+    kIEBrowserQuotedExe _T(" ") kIEBrowserQuotedArgs
+
+#define kIEBrowserQuotedExeResult \
+    _T("C:\\PROGRAM FILES\\Internet Explorer\\iexplore.exe")
+#define kIEBrowserQuotedArgsResult    _T("-h %1")
+
+#define kIEBrowserUnquotedCommandLine \
+    _T("C:\\Program Files\\Internet Explorer\\iexplore.exe -nohome")
+#define kIEBrowserUnquotedExe \
+    _T("C:\\Program Files\\Internet Explorer\\iexplore.exe")
+#define kIEBrowserUnquotedArgs        _T("-nohome")
+
+#define kGEUninstallCommandLine       _T("RunDll32 C:\\PROGRA~1\\COMMON~1\\INSTAL~1\\PROFES~1\\RunTime\\10\\01\\Intel32\\Ctor.dll,LaunchSetup \"C:\\Program Files\\InstallShield Installation Information\\{3DE5E7D4-7B88-403C-A3FD-2017A8240C5B}\\setup.exe\" -l0x9  -removeonly")  // NOLINT
+#define kGEUninstallExe               _T("RunDll32")
+#define kGEUninstallArgs              _T("C:\\PROGRA~1\\COMMON~1\\INSTAL~1\\PROFES~1\\RunTime\\10\\01\\Intel32\\Ctor.dll,LaunchSetup \"C:\\Program Files\\InstallShield Installation Information\\{3DE5E7D4-7B88-403C-A3FD-2017A8240C5B}\\setup.exe\" -l0x9 -removeonly")            // NOLINT
+
+
+struct TestData {
+  TestData() {
+    Clear();
+  }
+
+  void Clear() {
+    bool_value = false;
+    three_value = VALUE_NOT_SET;
+    int_value = 0;
+    uint_value = 0;
+    str_value.Empty();
+  }
+
+  bool bool_value;
+  ThreeValue three_value;
+  int int_value;
+  uint32 uint_value;
+  CString str_value;
+};
+
+void FillTestData(TestData* data) {
+  data->bool_value = true;
+  data->three_value = FALSE_VALUE;
+  data->int_value = -128;
+  data->uint_value = 256;
+  data->str_value = _T("Foo");
+}
+
+void CheckTestData(const TestData& d1, const TestData& d2) {
+  EXPECT_EQ(d1.bool_value, d2.bool_value);
+  EXPECT_EQ(d1.three_value, d2.three_value);
+  EXPECT_EQ(d1.int_value, d2.int_value);
+  EXPECT_EQ(d1.uint_value, d2.uint_value);
+  EXPECT_STREQ(d1.str_value, d2.str_value);
+}
+
+TEST(CommandsTest, TraditionalCommandLineOptionsParsingTest) {
+  TestData data;
+  FillTestData(&data);
+  CString cmd_line;
+  cmd_line.Format(_T("%s%s %s ")
+                  _T("%s%s %d ")
+                  _T("%s%s %u ")
+                  _T("%s%s %s "),
+                  kDash, kThreeOption, (data.three_value == TRUE_VALUE) ? _T("on") : _T("off"),   // NOLINT
+                  kDash, kIntOption, data.int_value,
+                  kDash, kUintOption, data.uint_value,
+                  kDash, kStrOption, data.str_value);
+  if (data.bool_value) {
+    cmd_line.AppendFormat(_T("%s%s"), kDash, kBoolOption);
+  }
+
+  TestData option_data;
+  CommandOption cmd_options[] = {
+    { kDash kBoolOption,  COMMAND_OPTION_BOOL,   &option_data.bool_value,  -1 },
+    { kDash kThreeOption, COMMAND_OPTION_THREE,  &option_data.three_value, -1 },
+    { kDash kIntOption,   COMMAND_OPTION_INT,    &option_data.int_value,   -1 },
+    { kDash kUintOption,  COMMAND_OPTION_UINT,   &option_data.uint_value,  -1 },
+    { kDash kStrOption,   COMMAND_OPTION_STRING, &option_data.str_value,   -1 }
+  };
+
+  option_data.Clear();
+  CommandParsing cmd_parsing(cmd_options, arraysize(cmd_options));
+  ASSERT_SUCCEEDED(cmd_parsing.Parse(cmd_line, false));
+
+  CheckTestData(option_data, data);
+}
+
+TEST(CommandsTest, TraditionalIgnoreUnknownArgsParsingTest) {
+  TestData data;
+  FillTestData(&data);
+  CString cmd_line;
+  cmd_line.Format(_T("%s%s %s ")
+                  _T("%s%s %d ")
+                  _T("%s%s %u ")
+                  _T("%s%s %s "),
+                  kDash, kThreeOption, (data.three_value == TRUE_VALUE) ? _T("on") : _T("off"),   // NOLINT
+                  kDash, kIntOption, data.int_value,
+                  kDash, kUintOption, data.uint_value,
+                  kDash, kStrOption, data.str_value);
+  if (data.bool_value) {
+    cmd_line.AppendFormat(_T("%s%s"), kDash, kBoolOption);
+  }
+
+  TestData option_data;
+  CommandOption cmd_options[] = {
+    { kDash kThreeOption, COMMAND_OPTION_THREE,  &option_data.three_value, -1 },
+    { kDash kIntOption,   COMMAND_OPTION_INT,    &option_data.int_value,   -1 },
+    { kDash kUintOption,  COMMAND_OPTION_UINT,   &option_data.uint_value,  -1 },
+    { kDash kStrOption,   COMMAND_OPTION_STRING, &option_data.str_value,   -1 }
+  };
+
+  option_data.Clear();
+  CommandParsing cmd_parsing(cmd_options, arraysize(cmd_options));
+  ASSERT_FAILED(cmd_parsing.Parse(cmd_line, false));
+  ASSERT_SUCCEEDED(cmd_parsing.Parse(cmd_line, true));
+
+  option_data.bool_value = data.bool_value;
+  CheckTestData(option_data, data);
+}
+
+TEST(CommandsTest, NameValuePairCommandLineOptionsParsingTest) {
+  TestData data;
+  FillTestData(&data);
+  CString cmd_line;
+  cmd_line.Format(
+      _T("%s=%s&")
+      _T("%s=%d&")
+      _T("%s=%u&")
+      _T("%s=%s"),
+      kThreeOption, (data.three_value == TRUE_VALUE) ? _T("on") : _T("off"),
+      kIntOption, data.int_value,
+      kUintOption, data.uint_value,
+      kStrOption, data.str_value);
+  if (data.bool_value) {
+    cmd_line.AppendFormat(_T("&%s="), kBoolOption);
+  }
+
+  TestData option_data;
+  CommandOption cmd_options[] = {
+    { kBoolOption,  COMMAND_OPTION_BOOL,   &option_data.bool_value,    -1 },
+    { kThreeOption, COMMAND_OPTION_THREE,  &option_data.three_value,   -1 },
+    { kIntOption,   COMMAND_OPTION_INT,    &option_data.int_value,     -1 },
+    { kUintOption,  COMMAND_OPTION_UINT,   &option_data.uint_value,    -1 },
+    { kStrOption,   COMMAND_OPTION_STRING, &option_data.str_value,     -1 }
+  };
+
+  option_data.Clear();
+  CommandParsing cmd_parsing(cmd_options,
+                             arraysize(cmd_options),
+                             _T('&'),
+                             true);
+  ASSERT_SUCCEEDED(cmd_parsing.Parse(cmd_line, false));
+
+  CheckTestData(option_data, data);
+}
+
+TEST(CommandsTest, NameValuePairIgnoreUnknownArgsParsingTest) {
+  TestData data;
+  FillTestData(&data);
+  CString cmd_line;
+  cmd_line.Format(
+      _T("%s=%s&")
+      _T("%s=%d&")
+      _T("%s=%u&")
+      _T("%s=%s"),
+      kThreeOption, (data.three_value == TRUE_VALUE) ? _T("on") : _T("off"),
+      kIntOption, data.int_value,
+      kUintOption, data.uint_value,
+      kStrOption, data.str_value);
+  if (data.bool_value) {
+    cmd_line.AppendFormat(_T("&%s="), kBoolOption);
+  }
+
+  TestData option_data;
+  CommandOption cmd_options[] = {
+    { kBoolOption,  COMMAND_OPTION_BOOL,   &option_data.bool_value,    -1 },
+    { kThreeOption, COMMAND_OPTION_THREE,  &option_data.three_value,   -1 },
+    { kUintOption,  COMMAND_OPTION_UINT,   &option_data.uint_value,    -1 },
+    { kStrOption,   COMMAND_OPTION_STRING, &option_data.str_value,     -1 }
+  };
+
+  option_data.Clear();
+  CommandParsing cmd_parsing(cmd_options,
+                             arraysize(cmd_options),
+                             _T('&'),
+                             true);
+  ASSERT_FAILED(cmd_parsing.Parse(cmd_line, false));
+  ASSERT_SUCCEEDED(cmd_parsing.Parse(cmd_line, true));
+
+  option_data.int_value = data.int_value;
+  CheckTestData(option_data, data);
+}
+
+TEST(CommandsTest, CommandParsingSimpleSplitTest) {
+  CString exe;
+  CString args;
+
+  // Test to make sure SplitExeAndArgs correctly splits
+  // a properly constructed command line
+  ASSERT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgs(kIEBrowserQuotedCommandLine,
+                                          &exe,
+                                          &args));
+
+  EXPECT_STREQ(kIEBrowserQuotedExeResult, exe);
+  EXPECT_STREQ(kIEBrowserQuotedArgsResult, args);
+}
+
+TEST(CommandsTest, CommandParsingGuessSplitTest) {
+  CString exe;
+  CString args;
+
+  // Test to make sure SplitExeAndArgsGuess correctly splits
+  // a properly constructed command line
+  ASSERT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserQuotedCommandLine,
+                                               &exe,
+                                               &args));
+
+  EXPECT_STREQ(kIEBrowserQuotedExeResult, exe);
+  EXPECT_STREQ(kIEBrowserQuotedArgsResult, args);
+
+  // Test to make sure SplitExeAndArgsGuess correctly splits
+  // an improperly constructed "Uninstall" command line
+  ASSERT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserUnquotedCommandLine,
+                                               &exe,
+                                               &args));
+
+  EXPECT_STREQ(kIEBrowserUnquotedExe, exe);
+  EXPECT_STREQ(kIEBrowserUnquotedArgs, args);
+
+  // Test to make sure SplitExeAndArgsGuess correctly splits
+  // a properly constructed "Uninstall" command line, where
+  // the executable does not have a ".EXE" extension, and
+  // where there happens to be an argument which happens to
+  // be an executable
+  ASSERT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(kGEUninstallCommandLine,
+                                               &exe,
+                                               &args));
+
+  EXPECT_STREQ(kGEUninstallExe, exe);
+  EXPECT_STREQ(kGEUninstallArgs, args);
+}
+
+TEST(CommandsTest, CommandParsingGuessSplit_ExtraWhiteSpace) {
+  CString exe;
+  CString args;
+
+  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(
+      kIEBrowserUnquotedCommandLine _T(" "),
+      &exe,
+      &args));
+  EXPECT_STREQ(kIEBrowserUnquotedExe, exe);
+  EXPECT_STREQ(kIEBrowserUnquotedArgs, args);
+
+  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(
+      kIEBrowserUnquotedCommandLine _T("\t"),
+      &exe,
+      &args));
+  EXPECT_STREQ(kIEBrowserUnquotedExe, exe);
+  EXPECT_STREQ(kIEBrowserUnquotedArgs, args);
+
+  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(
+      _T(" ") kIEBrowserUnquotedCommandLine,
+      &exe,
+      &args));
+  EXPECT_STREQ(kIEBrowserUnquotedExe, exe);
+  EXPECT_STREQ(kIEBrowserUnquotedArgs, args);
+
+  // The following cases have unexpected results.
+  // Quoting a command line with args is not handled correctly.
+  // The entire thing is interpreted as an EXE.
+
+  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(
+      _T("\" ") kIEBrowserUnquotedCommandLine _T("\""),
+      &exe,
+      &args));
+  EXPECT_STREQ(kIEBrowserUnquotedCommandLine, exe);
+  EXPECT_TRUE(args.IsEmpty());
+
+  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(
+      _T("\"") kIEBrowserUnquotedCommandLine _T(" \""),
+      &exe,
+      &args));
+  EXPECT_STREQ(kIEBrowserUnquotedCommandLine, exe);
+  EXPECT_TRUE(args.IsEmpty());
+
+  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(
+      _T("\"") kIEBrowserUnquotedCommandLine _T("\t\""),
+      &exe,
+      &args));
+  EXPECT_STREQ(kIEBrowserUnquotedCommandLine, exe);
+  EXPECT_TRUE(args.IsEmpty());
+}
+
+TEST(CommandsTest, CommandParsingGuessSplit_CommandLineIsExistingFile) {
+  CString exe;
+  CString args;
+
+  EXPECT_TRUE(File::Exists(kIEBrowserExe));
+  EXPECT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserExe, &exe, &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  EXPECT_TRUE(args.IsEmpty());
+
+  // File::Exists does not handle enclosed paths.
+  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe));
+  EXPECT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserQuotedExe,
+                                               &exe,
+                                               &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  EXPECT_TRUE(args.IsEmpty());
+}
+
+TEST(CommandsTest,
+     CommandParsingGuessSplit_CommandLineIsExistingFileWithExtraWhiteSpace) {
+  CString exe;
+  CString args;
+
+  EXPECT_TRUE(File::Exists(kIEBrowserExe));
+  // File::Exists does not handle enclosed paths.
+  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe));
+
+  EXPECT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserExe _T(" "),
+                                               &exe,
+                                               &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  EXPECT_TRUE(args.IsEmpty());
+
+  EXPECT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserQuotedExe _T(" "),
+                                               &exe,
+                                               &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  EXPECT_TRUE(args.IsEmpty());
+
+  EXPECT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserExe _T("\t"),
+                                               &exe,
+                                               &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  EXPECT_TRUE(args.IsEmpty());
+
+  EXPECT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(kIEBrowserQuotedExe _T("\t"),
+                                               &exe,
+                                               &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  // SplitExeAndArgs does not treat tab like whitespace and args aren't trimmed.
+  EXPECT_STREQ(_T("\t"), args);
+
+  EXPECT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(_T(" ") kIEBrowserExe,
+                                               &exe,
+                                               &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  EXPECT_TRUE(args.IsEmpty());
+
+  EXPECT_SUCCEEDED(
+    CommandParsingSimple::SplitExeAndArgsGuess(_T(" ") kIEBrowserQuotedExe,
+                                               &exe,
+                                               &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  EXPECT_TRUE(args.IsEmpty());
+
+  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(
+                       _T("\" ") kIEBrowserExe _T("\""),
+                       &exe,
+                       &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  EXPECT_TRUE(args.IsEmpty());
+
+  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(
+                       _T("\"") kIEBrowserExe _T(" \""),
+                       &exe,
+                       &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  EXPECT_TRUE(args.IsEmpty());
+
+  EXPECT_SUCCEEDED(CommandParsingSimple::SplitExeAndArgsGuess(
+                       _T("\"") kIEBrowserExe _T("\t\""),
+                       &exe,
+                       &args));
+  EXPECT_STREQ(kIEBrowserExe, exe);
+  EXPECT_TRUE(args.IsEmpty());
+}
+
+}  // namespace omaha
+
diff --git a/common/commontypes.h b/common/commontypes.h
index 0daca58..bcc7bfe 100644
--- a/common/commontypes.h
+++ b/common/commontypes.h
@@ -1,66 +1,66 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// TODO(omaha): refactor to eliminate this file.

-

-#ifndef OMAHA_COMMON_COMMONTYPES_H_

-#define OMAHA_COMMON_COMMONTYPES_H_

-

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// ---------------------- Defines -------------------------------

-// Define some variable types, so that we can change them under the hood

-// easier if need be.

-typedef unsigned char      uchar;

-

-typedef uint32 flags32;

-typedef uint16 time16;

-typedef uint64 time64;

-

-#define kInt32Max 2147483647

-#define kUint32Max 4294967295U

-#define kUint64Max 18446744073709551615U

-#define kTime64Max kUint64Max

-

-

-template <typename T>

-inline T ABS(T val) {

-  return val < (T)0 ? -val : val;

-}

-

-// Isolate some VisualC++-isms to macros for easy redefinition

-#define SELECTANY __declspec(selectany)

-#define DLLIMPORT __declspec(dllimport)

-#define DLLEXPORT __declspec(dllexport)

-

-// Put this around string literals that don't need to be localized

-// to indicate this fact.  Note that you don't need to do this for string

-// literals used in functions where they obviously don't need to be localized,

-// such as REPORT(), XXX_LOG(), CHK(), ASSERT(), VERIFY(), TRACE(), dbgprint(),

-// OutputDebugString(), GetProcAddress(), GetModuleHandle(), etc.

-//

-// For large blocks of non-localizable string literals, you can use a comment

-// line including "SKIP_LOC_BEGIN" to start a non-localizable section of

-// your file, and "SKIP_LOC_END" to end the section.

-//

-// Don't worry about NOTRANSL or the SKIP_LOC blocks in unit tests, experimental

-// code, etc. as they are ignored when checking for localizable string literals.

-#define NOTRANSL(x) x

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_COMMONTYPES_H_

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// TODO(omaha): refactor to eliminate this file.
+
+#ifndef OMAHA_COMMON_COMMONTYPES_H_
+#define OMAHA_COMMON_COMMONTYPES_H_
+
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// ---------------------- Defines -------------------------------
+// Define some variable types, so that we can change them under the hood
+// easier if need be.
+typedef unsigned char      uchar;
+
+typedef uint32 flags32;
+typedef uint16 time16;
+typedef uint64 time64;
+
+#define kInt32Max 2147483647
+#define kUint32Max 4294967295U
+#define kUint64Max 18446744073709551615U
+#define kTime64Max kUint64Max
+
+
+template <typename T>
+inline T ABS(T val) {
+  return val < (T)0 ? -val : val;
+}
+
+// Isolate some VisualC++-isms to macros for easy redefinition
+#define SELECTANY __declspec(selectany)
+#define DLLIMPORT __declspec(dllimport)
+#define DLLEXPORT __declspec(dllexport)
+
+// Put this around string literals that don't need to be localized
+// to indicate this fact.  Note that you don't need to do this for string
+// literals used in functions where they obviously don't need to be localized,
+// such as REPORT(), XXX_LOG(), CHK(), ASSERT(), VERIFY(), TRACE(), dbgprint(),
+// OutputDebugString(), GetProcAddress(), GetModuleHandle(), etc.
+//
+// For large blocks of non-localizable string literals, you can use a comment
+// line including "SKIP_LOC_BEGIN" to start a non-localizable section of
+// your file, and "SKIP_LOC_END" to end the section.
+//
+// Don't worry about NOTRANSL or the SKIP_LOC blocks in unit tests, experimental
+// code, etc. as they are ignored when checking for localizable string literals.
+#define NOTRANSL(x) x
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_COMMONTYPES_H_
diff --git a/common/const_addresses.h b/common/const_addresses.h
index 0d01d56..585784e 100644
--- a/common/const_addresses.h
+++ b/common/const_addresses.h
@@ -1,76 +1,76 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Constants for dealing with machines.

-//

-// Manifests are requested over HTTPS. All other network communication goes

-// over HTTP.

-

-#ifndef OMAHA_COMMON_CONST_ADDRESSES_H__

-#define OMAHA_COMMON_CONST_ADDRESSES_H__

-

-#include <tchar.h>

-

-namespace omaha {

-

-// Static string that gives the main Google website address

-#define kGoogleHttpServer         _T("www.google.com")

-

-// Static string used as an identity for the "Omaha" Google domain.

-#define kGoopdateServer           _T("tools.google.com")

-

-// HTTP protocol prefix

-#define kProtoSuffix              _T("://")

-#define kFileProtoScheme          _T("file")

-#define kHttpProtoScheme          _T("http")

-#define kHttpsProtoScheme         _T("https")

-#define kHttpProto                kHttpProtoScheme kProtoSuffix

-#define kHttpsProto               kHttpsProtoScheme kProtoSuffix

-#define kFileProto                kFileProtoScheme kProtoSuffix

-

-// Default ports for proxies

-#define kDefaultHttpProxyPort     80

-#define kDefaultSslProxyPort      443

-

-// Update checks and manifest requests.

-const TCHAR* const kUrlUpdateCheck =

-    _T("https://tools.google.com/service/update2");

-

-// Pings.

-const TCHAR* const kUrlPing = _T("http://tools.google.com/service/update2");

-

-// WebPlugin checks

-const TCHAR* const kUrlWebPluginCheck =

-    _T("https://tools.google.com/service/update2/oneclick");

-

-// Crash reports.

-const TCHAR* const kUrlCrashReport =

-    _T("http://clients2.google.com/cr/report");

-

-// More information url.

-const TCHAR* const kUrlMoreInformation =

-    _T("http://www.google.com/support/installer/?");

-

-// Code Red check url.

-const TCHAR* const kUrlCodeRedCheck =

-    _T("http://cr-tools.clients.google.com/service/check2");

-

-// Usage stats url.

-const TCHAR* const kUrlUsageStatsReport =

-    _T("http://clients5.google.com/tbproxy/usagestats");

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_CONST_ADDRESSES_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Constants for dealing with machines.
+//
+// Manifests are requested over HTTPS. All other network communication goes
+// over HTTP.
+
+#ifndef OMAHA_COMMON_CONST_ADDRESSES_H__
+#define OMAHA_COMMON_CONST_ADDRESSES_H__
+
+#include <tchar.h>
+
+namespace omaha {
+
+// Static string that gives the main Google website address
+#define kGoogleHttpServer         _T("www.google.com")
+
+// Static string used as an identity for the "Omaha" Google domain.
+#define kGoopdateServer           _T("tools.google.com")
+
+// HTTP protocol prefix
+#define kProtoSuffix              _T("://")
+#define kFileProtoScheme          _T("file")
+#define kHttpProtoScheme          _T("http")
+#define kHttpsProtoScheme         _T("https")
+#define kHttpProto                kHttpProtoScheme kProtoSuffix
+#define kHttpsProto               kHttpsProtoScheme kProtoSuffix
+#define kFileProto                kFileProtoScheme kProtoSuffix
+
+// Default ports for proxies
+#define kDefaultHttpProxyPort     80
+#define kDefaultSslProxyPort      443
+
+// Update checks and manifest requests.
+const TCHAR* const kUrlUpdateCheck =
+    _T("https://tools.google.com/service/update2");
+
+// Pings.
+const TCHAR* const kUrlPing = _T("http://tools.google.com/service/update2");
+
+// WebPlugin checks
+const TCHAR* const kUrlWebPluginCheck =
+    _T("https://tools.google.com/service/update2/oneclick");
+
+// Crash reports.
+const TCHAR* const kUrlCrashReport =
+    _T("http://clients2.google.com/cr/report");
+
+// More information url.
+const TCHAR* const kUrlMoreInformation =
+    _T("http://www.google.com/support/installer/?");
+
+// Code Red check url.
+const TCHAR* const kUrlCodeRedCheck =
+    _T("http://cr-tools.clients.google.com/service/check2");
+
+// Usage stats url.
+const TCHAR* const kUrlUsageStatsReport =
+    _T("http://clients5.google.com/tbproxy/usagestats");
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_CONST_ADDRESSES_H__
diff --git a/common/const_cmd_line.h b/common/const_cmd_line.h
index bdfe95f..fa2b117 100644
--- a/common/const_cmd_line.h
+++ b/common/const_cmd_line.h
@@ -1,288 +1,288 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Constants used as command line arguments.

-

-#ifndef OMAHA_COMMON_CONST_CMD_LINE_H__

-#define OMAHA_COMMON_CONST_CMD_LINE_H__

-

-namespace omaha {

-

-//

-// Externally initiated modes.

-// These modes are invoked by or on metainstallers or by the OneClick plugin  .

-//

-

-// The "install" switch indicates installing Google Update and the app.

-const TCHAR* const kCmdLineInstall = _T("install");

-

-// The "installelevated" switch indicates installing after elevating.

-const TCHAR* const kCmdLineInstallElevated = _T("installelevated");

-

-// The "update" switch indicates a self-update Google Update.

-const TCHAR* const kCmdLineUpdate = _T("update");

-

-// The "recover" switch indicates Google Update is to be repaired due to a

-// Code Red scenario.

-const TCHAR* const kCmdLineRecover = _T("recover");

-

-// The "pi" switch indicates that this came from a webplugin.

-// Requires two subarguments "siteurl" and "{args}" where

-// siteurl is the base URL where the plugin ran from and {args}

-// are the args to pass on once validation is complete.

-const TCHAR* const kCmdLineWebPlugin = _T("pi");

-

-//

-// Main operating modes

-//

-

-// The "c" option indicates a core process.

-const TCHAR* const kCmdLineCore = _T("c");

-

-// Specifies to not kick off the crash handler from the Core.

-const TCHAR* const kCmdLineNoCrashHandler = _T("nocrashserver");

-

-// The "crashhandler" option indicates a crash handler process.

-const TCHAR* const kCmdLineCrashHandler = _T("crashhandler");

-

-// Types of "Workers"

-

-// The "handoff" switch indicates a worker to perform an interactive install of

-// an application.

-const TCHAR* const kCmdLineAppHandoffInstall = _T("handoff");

-

-// The "ig" switch indicates a worker to finish installing Google Update and

-// perform an interactive install of an application.

-// ig = Install Google Update.

-const TCHAR* const kCmdLineFinishGoogleUpdateInstall = _T("ig");

-

-// The "ua" switch indicates a worker to perform an update check for all

-// applications.

-// ua = Update Applications.

-const TCHAR* const kCmdLineUpdateApps = _T("ua");

-

-// The "ug" switch indicates a worker to finish updating Google Update.

-// No application update checks are performed.

-// ug = Update Google Update.

-const TCHAR* const kCmdLineFinishGoogleUpdateUpdate = _T("ug");

-

-// The "cr" switch indicates that the worker has been invoked to perform a Code

-// Red check.

-const TCHAR* const kCmdLineCodeRedCheck = _T("cr");

-

-// The "registerproduct" switch will register a product GUID in Clients and

-// install only goopdate.

-const TCHAR* const kCmdLineRegisterProduct = _T("registerproduct");

-

-// The "unregisterproduct" switch will unregister a product GUID from Clients.

-const TCHAR* const kCmdLineUnregisterProduct = _T("unregisterproduct");

-

-//

-// Minor modes

-//

-

-// The "svc" switch indicates that goopdate runs as a service.

-const TCHAR* const kCmdLineService = _T("svc");

-

-// The "regsvc" switch is used to register the service. Only used by unit

-// tests at the moment.

-const TCHAR* const kCmdLineRegisterService = _T("regsvc");

-

-// The "unregsvc" switch is used to unregister the service. Only used by

-// unit tests at the moment.

-const TCHAR* const kCmdLineUnregisterService = _T("unregsvc");

-

-// The "/comsvc" switch indicates that has the service is being invoked via COM.

-// This switch will be passed in via ServiceParameters.

-const TCHAR* const kCmdLineServiceComServer = _T("/comsvc");

-

-// The "regserver" switch indicates that goopdate should do its Windows

-// service COM server registration including coclasses and its APPID.

-const TCHAR* const kCmdRegServer = _T("regserver");

-

-// The "unregserver" switch indicates that goopdate should undo its

-// COM registration.

-const TCHAR* const kCmdUnregServer = _T("unregserver");

-

-// The "report" switch makes Omaha upload the crash report.

-const TCHAR* const kCmdLineReport = _T("report");

-

-// The "custom_info_filename" switch specifies the file that contains custom

-// crash info.

-const TCHAR* const kCmdLineCustomInfoFileName = _T("custom_info_filename");

-

-// The "Embedding" switch indicates that the worker has been invoked to launch

-// the browser. The -Embedding switch is automatically added by COM when

-// launching the COM server.

-const TCHAR* const kCmdLineComServer = _T("Embedding");

-const TCHAR* const kCmdLineComServerDash = _T("-Embedding");

-

-//

-// Legacy support modes

-//

-

-// The legacy "UI" switch supports hand-off machine installs from Omaha 1.

-const TCHAR* const kCmdLineLegacyUi = _T("ui");

-

-// The legacy "lang" switch supports /lang for the /ui command.  No one else

-// should be sending /lang as a command line switch to goopdate.

-const TCHAR* const kCmdLineLegacyLang = _T("lang");

-

-// The "uiuser" switch is used to support hand off of of Omaha 1 user manifests.

-const TCHAR* const kCmdLineLegacyUserManifest = _T("uiuser");

-

-// The "extra" switch was used to provide a string containing additional

-// arguments. Extra args are now passed as an argument to the respective switch.

-const TCHAR* const kCmdLineLegacyExtra = _T("extra");

-

-// Passed to the new instance when launching it elevated.

-const TCHAR* const kCmdLineLegacyVistaInstall = _T("installelevated");

-

-//

-// Non-product modes

-// These are used for debug, testing, etc.

-//

-

-// Run network diagnostics.

-const TCHAR* const kCmdLineNetDiags = _T("netdiags");

-

-// The "crash" switch indicates that goopdate should crash upon startup.

-// This option is used to test the crash reporting system.

-const TCHAR* const kCmdLineCrash = _T("crash");

-

-//

-// Parameters for other modes

-//

-

-// The "silent" switch specifies that normally interactive modes should run

-// silently.

-const TCHAR* const kCmdLineSilent = _T("silent");

-

-const TCHAR* const kCmdLineOfflineInstall = _T("offlineinstall");

-

-// The "oem" switch specifies that this is an OEM install in Sysprep mode in an

-// OEM factory.

-const TCHAR* const kCmdLineOem = _T("oem");

-

-// The "eularequired" switch specifies that a EULA must be accepted before

-// checking for updates or pinging.

-const TCHAR* const kCmdLineEulaRequired = _T("eularequired");

-

-// The "machine" switch specifies to repair machine Omaha when specified with

-// "recover". Also used to tell the setup phase 2 worker to do a machine install

-// when doing a recover setup.

-const TCHAR* const kCmdLineMachine = _T("machine");

-

-// The "uninstall" switch is an option to /ua to tell it to skip the update

-// check and proceed with an uninstall.

-const TCHAR* const kCmdLineUninstall = _T("uninstall");

-

-// The "i" switch indicates that the crash has happend in an

-// interactive process which has a UI up. The switch is an option for

-// the "report" switch.

-const TCHAR* const kCmdLineInteractive = _T("i");

-

-// The "installsource" switch that is used to pass the source of installation

-// for ping tracking.  For example:  "/installsource OneClick".

-const TCHAR* const kCmdLineInstallSource = _T("installsource");

-

-// This is a valid value for installsource that means it's a OneClick install.

-const TCHAR* const kCmdLineInstallSource_OneClick = _T("oneclick");

-

-const TCHAR* const kCmdLineInstallSource_OnDemandUpdate = _T("ondemandupdate");

-const TCHAR* const kCmdLineInstallSource_OnDemandCheckForUpdate =

-    _T("ondemandcheckforupdate");

-

-const TCHAR* const kCmdLineInstallSource_ClickOnce = _T("clickonce");

-

-const TCHAR* const kCmdLineInstallSource_Offline = _T("offline");

-

-const TCHAR* const kCmdLineInstallSourceScheduler = _T("scheduler");

-const TCHAR* const kCmdLineInstallSourceCore = _T("core");

-

-//

-// "Extra" arguments provided in the metainstaller tag.

-//

-

-// "lang" extra argument tells Omaha the language of the product the user is

-// installing.

-const TCHAR* const kExtraArgLanguage = _T("lang");

-

-// "usagestats" extra argument tells Omaha the user has agreed to provide

-// usage stats, crashreports etc.

-const TCHAR* const kExtraArgUsageStats = _T("usagestats");

-

-// "iid" extra argument is a unique value for this installation session.

-// It can be used to follow the progress from the website to installation

-// completion.

-const TCHAR* const kExtraArgInstallationId = _T("iid");

-

-// "brand" extra argument is the Brand Code used for branding.

-// If a brand value already exists on the system, it is ignored.

-// This value is used to set the initial brand for Omaha and the client app.

-const TCHAR* const kExtraArgBrandCode = _T("brand");

-

-// "client" extra argument is the Client ID used for branding.

-// If a client value already exists on the system, it is ignored.

-// This value is used to set the initial client for Omaha and the client app.

-const TCHAR* const kExtraArgClientId = _T("client");

-

-// "referral" extra argument is a referral ID used for tracking referrals.

-const TCHAR* const kExtraArgReferralId = _T("referral");

-

-// '" extra argument tells Omaha to set the ap value in the registry.

-const TCHAR* const kExtraArgAdditionalParameters = _T("ap");

-

-// "tt_token" extra argument tells Omaha to set the TT value in the registry.

-const TCHAR* const kExtraArgTTToken = _T("tttoken");

-

-

-// "browser" extra argument tells Omaha which browser to restart on

-// successful install.

-const TCHAR* const kExtraArgBrowserType = _T("browser");

-

-// The list of arguments that are needed for a meta-installer, to

-// indicate which application is being installed. These are stamped

-// inside the meta-installer binary.

-const TCHAR* const kExtraArgAppGuid = _T("appguid");

-const TCHAR* const kExtraArgAppName = _T("appname");

-const TCHAR* const kExtraArgNeedsAdmin = _T("needsadmin");

-const TCHAR* const kExtraArgInstallDataIndex = _T("installdataindex");

-

-// App arguments are arguments explicitly passed on the command line. They are

-// formatted similar to the regular extra args. For example:

-//     /appargs "appguid={GUID}&installerdata=BlahData"

-// Unlike the regular extra args, they are not embedded in the executable.

-const TCHAR* const kCmdLineAppArgs = _T("appargs");

-

-// This switch allows extra data to be communicated to the application

-// installer. The extra data needs to be URL-encoded. The data will be decoded

-// and written to the file, that is then passed in the command line to the

-// application installer in the form "/installerdata=blah.dat". One per

-// application.

-const TCHAR* const kExtraArgInstallerData = _T("installerdata");

-

-//

-// Parsing characters

-//

-

-const TCHAR* const kExtraArgsSeparators        = _T("&");

-const TCHAR* const kDisallowedCharsInExtraArgs = _T("/");

-const TCHAR        kNameValueSeparatorChar     = _T('=');

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_CONST_CMD_LINE_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Constants used as command line arguments.
+
+#ifndef OMAHA_COMMON_CONST_CMD_LINE_H__
+#define OMAHA_COMMON_CONST_CMD_LINE_H__
+
+namespace omaha {
+
+//
+// Externally initiated modes.
+// These modes are invoked by or on metainstallers or by the OneClick plugin  .
+//
+
+// The "install" switch indicates installing Google Update and the app.
+const TCHAR* const kCmdLineInstall = _T("install");
+
+// The "installelevated" switch indicates installing after elevating.
+const TCHAR* const kCmdLineInstallElevated = _T("installelevated");
+
+// The "update" switch indicates a self-update Google Update.
+const TCHAR* const kCmdLineUpdate = _T("update");
+
+// The "recover" switch indicates Google Update is to be repaired due to a
+// Code Red scenario.
+const TCHAR* const kCmdLineRecover = _T("recover");
+
+// The "pi" switch indicates that this came from a webplugin.
+// Requires two subarguments "siteurl" and "{args}" where
+// siteurl is the base URL where the plugin ran from and {args}
+// are the args to pass on once validation is complete.
+const TCHAR* const kCmdLineWebPlugin = _T("pi");
+
+//
+// Main operating modes
+//
+
+// The "c" option indicates a core process.
+const TCHAR* const kCmdLineCore = _T("c");
+
+// Specifies to not kick off the crash handler from the Core.
+const TCHAR* const kCmdLineNoCrashHandler = _T("nocrashserver");
+
+// The "crashhandler" option indicates a crash handler process.
+const TCHAR* const kCmdLineCrashHandler = _T("crashhandler");
+
+// Types of "Workers"
+
+// The "handoff" switch indicates a worker to perform an interactive install of
+// an application.
+const TCHAR* const kCmdLineAppHandoffInstall = _T("handoff");
+
+// The "ig" switch indicates a worker to finish installing Google Update and
+// perform an interactive install of an application.
+// ig = Install Google Update.
+const TCHAR* const kCmdLineFinishGoogleUpdateInstall = _T("ig");
+
+// The "ua" switch indicates a worker to perform an update check for all
+// applications.
+// ua = Update Applications.
+const TCHAR* const kCmdLineUpdateApps = _T("ua");
+
+// The "ug" switch indicates a worker to finish updating Google Update.
+// No application update checks are performed.
+// ug = Update Google Update.
+const TCHAR* const kCmdLineFinishGoogleUpdateUpdate = _T("ug");
+
+// The "cr" switch indicates that the worker has been invoked to perform a Code
+// Red check.
+const TCHAR* const kCmdLineCodeRedCheck = _T("cr");
+
+// The "registerproduct" switch will register a product GUID in Clients and
+// install only goopdate.
+const TCHAR* const kCmdLineRegisterProduct = _T("registerproduct");
+
+// The "unregisterproduct" switch will unregister a product GUID from Clients.
+const TCHAR* const kCmdLineUnregisterProduct = _T("unregisterproduct");
+
+//
+// Minor modes
+//
+
+// The "svc" switch indicates that goopdate runs as a service.
+const TCHAR* const kCmdLineService = _T("svc");
+
+// The "regsvc" switch is used to register the service. Only used by unit
+// tests at the moment.
+const TCHAR* const kCmdLineRegisterService = _T("regsvc");
+
+// The "unregsvc" switch is used to unregister the service. Only used by
+// unit tests at the moment.
+const TCHAR* const kCmdLineUnregisterService = _T("unregsvc");
+
+// The "/comsvc" switch indicates that has the service is being invoked via COM.
+// This switch will be passed in via ServiceParameters.
+const TCHAR* const kCmdLineServiceComServer = _T("/comsvc");
+
+// The "regserver" switch indicates that goopdate should do its Windows
+// service COM server registration including coclasses and its APPID.
+const TCHAR* const kCmdRegServer = _T("regserver");
+
+// The "unregserver" switch indicates that goopdate should undo its
+// COM registration.
+const TCHAR* const kCmdUnregServer = _T("unregserver");
+
+// The "report" switch makes Omaha upload the crash report.
+const TCHAR* const kCmdLineReport = _T("report");
+
+// The "custom_info_filename" switch specifies the file that contains custom
+// crash info.
+const TCHAR* const kCmdLineCustomInfoFileName = _T("custom_info_filename");
+
+// The "Embedding" switch indicates that the worker has been invoked to launch
+// the browser. The -Embedding switch is automatically added by COM when
+// launching the COM server.
+const TCHAR* const kCmdLineComServer = _T("Embedding");
+const TCHAR* const kCmdLineComServerDash = _T("-Embedding");
+
+//
+// Legacy support modes
+//
+
+// The legacy "UI" switch supports hand-off machine installs from Omaha 1.
+const TCHAR* const kCmdLineLegacyUi = _T("ui");
+
+// The legacy "lang" switch supports /lang for the /ui command.  No one else
+// should be sending /lang as a command line switch to goopdate.
+const TCHAR* const kCmdLineLegacyLang = _T("lang");
+
+// The "uiuser" switch is used to support hand off of of Omaha 1 user manifests.
+const TCHAR* const kCmdLineLegacyUserManifest = _T("uiuser");
+
+// The "extra" switch was used to provide a string containing additional
+// arguments. Extra args are now passed as an argument to the respective switch.
+const TCHAR* const kCmdLineLegacyExtra = _T("extra");
+
+// Passed to the new instance when launching it elevated.
+const TCHAR* const kCmdLineLegacyVistaInstall = _T("installelevated");
+
+//
+// Non-product modes
+// These are used for debug, testing, etc.
+//
+
+// Run network diagnostics.
+const TCHAR* const kCmdLineNetDiags = _T("netdiags");
+
+// The "crash" switch indicates that goopdate should crash upon startup.
+// This option is used to test the crash reporting system.
+const TCHAR* const kCmdLineCrash = _T("crash");
+
+//
+// Parameters for other modes
+//
+
+// The "silent" switch specifies that normally interactive modes should run
+// silently.
+const TCHAR* const kCmdLineSilent = _T("silent");
+
+const TCHAR* const kCmdLineOfflineInstall = _T("offlineinstall");
+
+// The "oem" switch specifies that this is an OEM install in Sysprep mode in an
+// OEM factory.
+const TCHAR* const kCmdLineOem = _T("oem");
+
+// The "eularequired" switch specifies that a EULA must be accepted before
+// checking for updates or pinging.
+const TCHAR* const kCmdLineEulaRequired = _T("eularequired");
+
+// The "machine" switch specifies to repair machine Omaha when specified with
+// "recover". Also used to tell the setup phase 2 worker to do a machine install
+// when doing a recover setup.
+const TCHAR* const kCmdLineMachine = _T("machine");
+
+// The "uninstall" switch is an option to /ua to tell it to skip the update
+// check and proceed with an uninstall.
+const TCHAR* const kCmdLineUninstall = _T("uninstall");
+
+// The "i" switch indicates that the crash has happend in an
+// interactive process which has a UI up. The switch is an option for
+// the "report" switch.
+const TCHAR* const kCmdLineInteractive = _T("i");
+
+// The "installsource" switch that is used to pass the source of installation
+// for ping tracking.  For example:  "/installsource OneClick".
+const TCHAR* const kCmdLineInstallSource = _T("installsource");
+
+// This is a valid value for installsource that means it's a OneClick install.
+const TCHAR* const kCmdLineInstallSource_OneClick = _T("oneclick");
+
+const TCHAR* const kCmdLineInstallSource_OnDemandUpdate = _T("ondemandupdate");
+const TCHAR* const kCmdLineInstallSource_OnDemandCheckForUpdate =
+    _T("ondemandcheckforupdate");
+
+const TCHAR* const kCmdLineInstallSource_ClickOnce = _T("clickonce");
+
+const TCHAR* const kCmdLineInstallSource_Offline = _T("offline");
+
+const TCHAR* const kCmdLineInstallSourceScheduler = _T("scheduler");
+const TCHAR* const kCmdLineInstallSourceCore = _T("core");
+
+//
+// "Extra" arguments provided in the metainstaller tag.
+//
+
+// "lang" extra argument tells Omaha the language of the product the user is
+// installing.
+const TCHAR* const kExtraArgLanguage = _T("lang");
+
+// "usagestats" extra argument tells Omaha the user has agreed to provide
+// usage stats, crashreports etc.
+const TCHAR* const kExtraArgUsageStats = _T("usagestats");
+
+// "iid" extra argument is a unique value for this installation session.
+// It can be used to follow the progress from the website to installation
+// completion.
+const TCHAR* const kExtraArgInstallationId = _T("iid");
+
+// "brand" extra argument is the Brand Code used for branding.
+// If a brand value already exists on the system, it is ignored.
+// This value is used to set the initial brand for Omaha and the client app.
+const TCHAR* const kExtraArgBrandCode = _T("brand");
+
+// "client" extra argument is the Client ID used for branding.
+// If a client value already exists on the system, it is ignored.
+// This value is used to set the initial client for Omaha and the client app.
+const TCHAR* const kExtraArgClientId = _T("client");
+
+// "referral" extra argument is a referral ID used for tracking referrals.
+const TCHAR* const kExtraArgReferralId = _T("referral");
+
+// '" extra argument tells Omaha to set the ap value in the registry.
+const TCHAR* const kExtraArgAdditionalParameters = _T("ap");
+
+// "tt_token" extra argument tells Omaha to set the TT value in the registry.
+const TCHAR* const kExtraArgTTToken = _T("tttoken");
+
+
+// "browser" extra argument tells Omaha which browser to restart on
+// successful install.
+const TCHAR* const kExtraArgBrowserType = _T("browser");
+
+// The list of arguments that are needed for a meta-installer, to
+// indicate which application is being installed. These are stamped
+// inside the meta-installer binary.
+const TCHAR* const kExtraArgAppGuid = _T("appguid");
+const TCHAR* const kExtraArgAppName = _T("appname");
+const TCHAR* const kExtraArgNeedsAdmin = _T("needsadmin");
+const TCHAR* const kExtraArgInstallDataIndex = _T("installdataindex");
+
+// App arguments are arguments explicitly passed on the command line. They are
+// formatted similar to the regular extra args. For example:
+//     /appargs "appguid={GUID}&installerdata=BlahData"
+// Unlike the regular extra args, they are not embedded in the executable.
+const TCHAR* const kCmdLineAppArgs = _T("appargs");
+
+// This switch allows extra data to be communicated to the application
+// installer. The extra data needs to be URL-encoded. The data will be decoded
+// and written to the file, that is then passed in the command line to the
+// application installer in the form "/installerdata=blah.dat". One per
+// application.
+const TCHAR* const kExtraArgInstallerData = _T("installerdata");
+
+//
+// Parsing characters
+//
+
+const TCHAR* const kExtraArgsSeparators        = _T("&");
+const TCHAR* const kDisallowedCharsInExtraArgs = _T("/");
+const TCHAR        kNameValueSeparatorChar     = _T('=');
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_CONST_CMD_LINE_H__
+
diff --git a/common/const_config.h b/common/const_config.h
index a0f8bd2..14e24ad 100644
--- a/common/const_config.h
+++ b/common/const_config.h
@@ -1,65 +1,65 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_CONST_CONFIG_H__

-#define OMAHA_COMMON_CONST_CONFIG_H__

-

-namespace omaha {

-

-// Root Registry keys

-//

-// In this version, everything is put under HKLM.

-// NOTE: PUBLISHER_NAME_ANSI and PRODUCT_NAME_ANSI are defined in mk_common

-// kProgramAnsi is "Google Update"

-#define kProgramAnsi      PUBLISHER_NAME_ANSI " " PRODUCT_NAME_ANSI

-#define kCiProgram        _T(PUBLISHER_NAME_ANSI) _T(" ") _T(PRODUCT_NAME_ANSI)

-#define kGoogleRegKey     _T("Software\\") _T(PUBLISHER_NAME_ANSI) _T("\\")

-#define kGoogleFullRegKey _T("HKLM\\") kGoogleRegKey

-

-// kProductRegKey is _T("Software\\Google\\Update")

-#define kProductRegKey       kGoogleRegKey _T(PRODUCT_NAME_ANSI)

-#define kCiFullRegKey        _T("HKLM\\") kProductRegKey

-#define kRegKeyConfig        _T("Config")

-#define kRegKeyConfigPrefix  kRegKeyConfig

-#define kCiFullRegKeyConfig  kCiFullRegKey _T("\\") kRegKeyConfig

-#define kRegKeyShared        _T("Shared")

-#define kCiRegKeyShared      kProductRegKey _T("\\") kRegKeyShared

-#define kRegValueReportIds   _T("report_ids")

-

-// NOTE: ACTIVEX_VERSION_ANSI is defined in mk_common

-// For example: kOneClickProgIdAnsi == "Google.OneClickCtrl.1"

-#define kOneClickProgIdAnsi  PUBLISHER_NAME_ANSI \

-                             ".OneClickCtrl." \

-                             ACTIVEX_VERSION_ANSI

-#define kOneClickProgId      _T(PUBLISHER_NAME_ANSI) \

-                             _T(".OneClickCtrl.") \

-                             _T(ACTIVEX_VERSION_ANSI)

-

-// The plug-in MIME type.

-// For example:

-//     kOneClickPluginMimeTypeAnsi == "application/x-vnd.google.oneclickctrl.1"

-#define kOneClickPluginMimeTypeAnsi  "application/x-vnd.google.oneclickctrl." \

-                                     ACTIVEX_VERSION_ANSI

-

-// .oii is just an arbitrary extension.

-#define kOneClickPluginMimeDescriptionAnsi  kOneClickPluginMimeTypeAnsi \

-                                            ":.oii:" \

-                                            kProgramAnsi

-

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_CONST_CONFIG_H__

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_CONST_CONFIG_H__
+#define OMAHA_COMMON_CONST_CONFIG_H__
+
+namespace omaha {
+
+// Root Registry keys
+//
+// In this version, everything is put under HKLM.
+// NOTE: PUBLISHER_NAME_ANSI and PRODUCT_NAME_ANSI are defined in mk_common
+// kProgramAnsi is "Google Update"
+#define kProgramAnsi      PUBLISHER_NAME_ANSI " " PRODUCT_NAME_ANSI
+#define kCiProgram        _T(PUBLISHER_NAME_ANSI) _T(" ") _T(PRODUCT_NAME_ANSI)
+#define kGoogleRegKey     _T("Software\\") _T(PUBLISHER_NAME_ANSI) _T("\\")
+#define kGoogleFullRegKey _T("HKLM\\") kGoogleRegKey
+
+// kProductRegKey is _T("Software\\Google\\Update")
+#define kProductRegKey       kGoogleRegKey _T(PRODUCT_NAME_ANSI)
+#define kCiFullRegKey        _T("HKLM\\") kProductRegKey
+#define kRegKeyConfig        _T("Config")
+#define kRegKeyConfigPrefix  kRegKeyConfig
+#define kCiFullRegKeyConfig  kCiFullRegKey _T("\\") kRegKeyConfig
+#define kRegKeyShared        _T("Shared")
+#define kCiRegKeyShared      kProductRegKey _T("\\") kRegKeyShared
+#define kRegValueReportIds   _T("report_ids")
+
+// NOTE: ACTIVEX_VERSION_ANSI is defined in mk_common
+// For example: kOneClickProgIdAnsi == "Google.OneClickCtrl.1"
+#define kOneClickProgIdAnsi  PUBLISHER_NAME_ANSI \
+                             ".OneClickCtrl." \
+                             ACTIVEX_VERSION_ANSI
+#define kOneClickProgId      _T(PUBLISHER_NAME_ANSI) \
+                             _T(".OneClickCtrl.") \
+                             _T(ACTIVEX_VERSION_ANSI)
+
+// The plug-in MIME type.
+// For example:
+//     kOneClickPluginMimeTypeAnsi == "application/x-vnd.google.oneclickctrl.1"
+#define kOneClickPluginMimeTypeAnsi  "application/x-vnd.google.oneclickctrl." \
+                                     ACTIVEX_VERSION_ANSI
+
+// .oii is just an arbitrary extension.
+#define kOneClickPluginMimeDescriptionAnsi  kOneClickPluginMimeTypeAnsi \
+                                            ":.oii:" \
+                                            kProgramAnsi
+
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_CONST_CONFIG_H__
+
diff --git a/common/const_debug.h b/common/const_debug.h
index 2f7687c..d2cf292 100644
--- a/common/const_debug.h
+++ b/common/const_debug.h
@@ -1,36 +1,36 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_CONST_DEBUG_H_

-#define OMAHA_COMMON_CONST_DEBUG_H_

-

-namespace omaha {

-

-#include "omaha/common/constants.h"

-

-// kCiDebugDirectory is relative to the system drive if available or the

-// current directory otherwise. The expectation is that %SystemDrive% is

-// always avaialable, including for the code running as system.

-#define kCiDebugDirectory     kFilePrefix _T("-debug")

-

-// TODO(omaha): unify the debugging and logging support so that these files

-// are created under the same directory as the log file.

-#define kCiDebugLogFile                   _T("debug.log")

-#define kCiAssertOccurredFile             _T("assert.log")

-#define kCiAbortOccurredFile              _T("abort.log")

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_CONST_DEBUG_H_

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_CONST_DEBUG_H_
+#define OMAHA_COMMON_CONST_DEBUG_H_
+
+namespace omaha {
+
+#include "omaha/common/constants.h"
+
+// kCiDebugDirectory is relative to the system drive if available or the
+// current directory otherwise. The expectation is that %SystemDrive% is
+// always avaialable, including for the code running as system.
+#define kCiDebugDirectory     kFilePrefix _T("-debug")
+
+// TODO(omaha): unify the debugging and logging support so that these files
+// are created under the same directory as the log file.
+#define kCiDebugLogFile                   _T("debug.log")
+#define kCiAssertOccurredFile             _T("assert.log")
+#define kCiAbortOccurredFile              _T("abort.log")
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_CONST_DEBUG_H_
diff --git a/common/const_object_names.h b/common/const_object_names.h
index d3a2260..80d02c0 100644
--- a/common/const_object_names.h
+++ b/common/const_object_names.h
@@ -1,128 +1,128 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Kernel object names.

-//

-// TODO(omaha): rename MutexPrefix to ObjectPrefix

-//              remove the similar names from constants.h

-

-#ifndef OMAHA_COMMON_CONST_OBJECT_NAMES_H__

-#define OMAHA_COMMON_CONST_OBJECT_NAMES_H__

-

-#include <tchar.h>

-

-namespace omaha {

-

-// The prefix to use for global names in the win32 API's.

-const TCHAR* const kGlobalPrefix = _T("Global\\G");

-

-// Preserve legacy prefixes

-const TCHAR* const kOmaha10GlobalPrefix = _T("Global\\");

-const TCHAR* const kOmaha11GlobalPrefix = _T("Global\\G");

-const TCHAR* const kOmaha11LocalPrefix = _T("Local\\L");

-

-// Ensures that only one instance of machine or user Omaha is trying to setup at

-// a time.

-const TCHAR* const kSetupMutex = _T("{A9A86B93-B54E-4570-BE89-42418507707B}");

-

-// Signals the process to exit. Currently the core and the worker listen to

-// this event.

-// This same name was used in Omaha 1 (post-i18n).

-// TODO(omaha): Consider making all our processes listen to it. Maybe not the

-// service, since the SCM controls the life time of the service.

-const TCHAR* const kShutdownEvent =

-    _T("{A0C1F415-D2CE-4ddc-9B48-14E56FD55162}");

-

-// Only used to shut down older (pre-i18n) Goopdates.

-const TCHAR* const kEventLegacyQuietModeName =

-    _T("Global\\%s{B048F41D-5515-40eb-B4A6-B7F460379454}");

-

-// The installed setup worker sends an event to the setup worker running from

-// the temp directory to tell it to release the Setup Lock. The event's name

-// is passed in this environment variable name.

-const TCHAR* const kSetupCompleteEventEnvironmentVariableName =

-    _T("GOOGLE_UPDATE_SETUP_COMPLETE_EVENT_NAME");

-

-// The installed setup worker sends an event to the setup worker running from

-// the temp directory to tell it a UI has been displayed so it will not display

-// a second UI on error. The event's name is passed in this environment variable

-// name.

-const TCHAR* const kUiDisplayedEventEnvironmentVariableName =

-    _T("GOOGLE_UPDATE_UI_DISPLAYED_EVENT_NAME");

-

-// It enforces the Core only runs one instance per machine and one instance per

-// each user session.

-const TCHAR* const kCoreSingleInstance =

-    _T("{B5665124-2B19-40e2-A7BC-B44321E72C4B}");

-

-// It enforces the Crash Handler only runs one instance per machine and one

-// instance per each user session.

-const TCHAR* const kCrashHandlerSingleInstance =

-    _T("{C4F406E5-F024-4e3f-89A7-D5AB7663C3CD}");

-

-// The mutex names for ensuring single instances of the worker.

-// We allow only one instance of the update worker per session,

-// and only one instance of the install worker per application.

-// However since user omaha cannot create global names, the interactive

-// worker is also per session. I.e. two users can simultaneously install

-// the same application.

-const TCHAR* const kSingleupdateWorker =

-    _T("{D0BB2EF1-C183-4cdb-B218-040922092869}");

-

-// Mutex name for ensuring only one installer for an app is running in a

-// session. The %s is replaced with the application guid.

-const TCHAR* const kSingleInstallWorker =

-    _T("%s-{F707E94F-D66B-4525-AD84-B1DA87D6A971}");

-

-// Base name of job object for Setup phase 1 processes except self updates.

-// These may not be running as Local System for machine installs like

-// self-updates do.

-const TCHAR* const kSetupPhase1NonSelfUpdateJobObject =

-    _T("{5A913EF1-4160-48bc-B688-4D67EAEB698A}");

-

-// Base name of job object for interactive install processes except /install.

-const TCHAR* const kAppInstallJobObject =

-    _T("{8AD051DB-4FE6-458b-B103-7DCC78D56013}");

-

-// Base name of job object for silent processes that are okay to kill.

-const TCHAR* const kSilentJobObject =

-    _T("{A2300FD6-CBED-48a6-A3CB-B35C38A42F8E}");

-

-// Base name of job object for silent processes that should not be killed.

-const TCHAR* const kSilentDoNotKillJobObject =

-    _T("{D33A8A53-F57D-4fd9-A32D-238FD69B4BC4}");

-

-// The global lock to ensure that a single app is being installed for this

-// user/machine at a given time.

-const TCHAR* const kInstallManagerSerializer =

-    _T("{0A175FBE-AEEC-4fea-855A-2AA549A88846}");

-

-// Serializes access to metrics stores, machine and user, respectively.

-const TCHAR* const kMetricsSerializer =

-    _T("{C68009EA-1163-4498-8E93-D5C4E317D8CE}");

-

-// Serializes access to the global network configuration, such as the CUP keys.

-const TCHAR* const kNetworkConfigLock =

-    _T("{0E900C7B-04B0-47f9-81B0-F8D94F2DF01B}");

-

-// The name of the shared memory object containing the serialized COM

-// interface pointer exposed by the machine core.

-const TCHAR* const kGoogleUpdateCoreSharedMemoryName =

-    _T("Global\\GoogleUpdateCore");

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_CONST_OBJECT_NAMES_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Kernel object names.
+//
+// TODO(omaha): rename MutexPrefix to ObjectPrefix
+//              remove the similar names from constants.h
+
+#ifndef OMAHA_COMMON_CONST_OBJECT_NAMES_H__
+#define OMAHA_COMMON_CONST_OBJECT_NAMES_H__
+
+#include <tchar.h>
+
+namespace omaha {
+
+// The prefix to use for global names in the win32 API's.
+const TCHAR* const kGlobalPrefix = _T("Global\\G");
+
+// Preserve legacy prefixes
+const TCHAR* const kOmaha10GlobalPrefix = _T("Global\\");
+const TCHAR* const kOmaha11GlobalPrefix = _T("Global\\G");
+const TCHAR* const kOmaha11LocalPrefix = _T("Local\\L");
+
+// Ensures that only one instance of machine or user Omaha is trying to setup at
+// a time.
+const TCHAR* const kSetupMutex = _T("{A9A86B93-B54E-4570-BE89-42418507707B}");
+
+// Signals the process to exit. Currently the core and the worker listen to
+// this event.
+// This same name was used in Omaha 1 (post-i18n).
+// TODO(omaha): Consider making all our processes listen to it. Maybe not the
+// service, since the SCM controls the life time of the service.
+const TCHAR* const kShutdownEvent =
+    _T("{A0C1F415-D2CE-4ddc-9B48-14E56FD55162}");
+
+// Only used to shut down older (pre-i18n) Goopdates.
+const TCHAR* const kEventLegacyQuietModeName =
+    _T("Global\\%s{B048F41D-5515-40eb-B4A6-B7F460379454}");
+
+// The installed setup worker sends an event to the setup worker running from
+// the temp directory to tell it to release the Setup Lock. The event's name
+// is passed in this environment variable name.
+const TCHAR* const kSetupCompleteEventEnvironmentVariableName =
+    _T("GOOGLE_UPDATE_SETUP_COMPLETE_EVENT_NAME");
+
+// The installed setup worker sends an event to the setup worker running from
+// the temp directory to tell it a UI has been displayed so it will not display
+// a second UI on error. The event's name is passed in this environment variable
+// name.
+const TCHAR* const kUiDisplayedEventEnvironmentVariableName =
+    _T("GOOGLE_UPDATE_UI_DISPLAYED_EVENT_NAME");
+
+// It enforces the Core only runs one instance per machine and one instance per
+// each user session.
+const TCHAR* const kCoreSingleInstance =
+    _T("{B5665124-2B19-40e2-A7BC-B44321E72C4B}");
+
+// It enforces the Crash Handler only runs one instance per machine and one
+// instance per each user session.
+const TCHAR* const kCrashHandlerSingleInstance =
+    _T("{C4F406E5-F024-4e3f-89A7-D5AB7663C3CD}");
+
+// The mutex names for ensuring single instances of the worker.
+// We allow only one instance of the update worker per session,
+// and only one instance of the install worker per application.
+// However since user omaha cannot create global names, the interactive
+// worker is also per session. I.e. two users can simultaneously install
+// the same application.
+const TCHAR* const kSingleupdateWorker =
+    _T("{D0BB2EF1-C183-4cdb-B218-040922092869}");
+
+// Mutex name for ensuring only one installer for an app is running in a
+// session. The %s is replaced with the application guid.
+const TCHAR* const kSingleInstallWorker =
+    _T("%s-{F707E94F-D66B-4525-AD84-B1DA87D6A971}");
+
+// Base name of job object for Setup phase 1 processes except self updates.
+// These may not be running as Local System for machine installs like
+// self-updates do.
+const TCHAR* const kSetupPhase1NonSelfUpdateJobObject =
+    _T("{5A913EF1-4160-48bc-B688-4D67EAEB698A}");
+
+// Base name of job object for interactive install processes except /install.
+const TCHAR* const kAppInstallJobObject =
+    _T("{8AD051DB-4FE6-458b-B103-7DCC78D56013}");
+
+// Base name of job object for silent processes that are okay to kill.
+const TCHAR* const kSilentJobObject =
+    _T("{A2300FD6-CBED-48a6-A3CB-B35C38A42F8E}");
+
+// Base name of job object for silent processes that should not be killed.
+const TCHAR* const kSilentDoNotKillJobObject =
+    _T("{D33A8A53-F57D-4fd9-A32D-238FD69B4BC4}");
+
+// The global lock to ensure that a single app is being installed for this
+// user/machine at a given time.
+const TCHAR* const kInstallManagerSerializer =
+    _T("{0A175FBE-AEEC-4fea-855A-2AA549A88846}");
+
+// Serializes access to metrics stores, machine and user, respectively.
+const TCHAR* const kMetricsSerializer =
+    _T("{C68009EA-1163-4498-8E93-D5C4E317D8CE}");
+
+// Serializes access to the global network configuration, such as the CUP keys.
+const TCHAR* const kNetworkConfigLock =
+    _T("{0E900C7B-04B0-47f9-81B0-F8D94F2DF01B}");
+
+// The name of the shared memory object containing the serialized COM
+// interface pointer exposed by the machine core.
+const TCHAR* const kGoogleUpdateCoreSharedMemoryName =
+    _T("Global\\GoogleUpdateCore");
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_CONST_OBJECT_NAMES_H__
+
diff --git a/common/const_timeouts.h b/common/const_timeouts.h
index fdff5b4..60c29bf 100644
--- a/common/const_timeouts.h
+++ b/common/const_timeouts.h
@@ -1,31 +1,31 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Constants used for different timeouts in Common Installer

-

-#ifndef OMAHA_COMMON_CONST_TIMEOUTS_H__

-#define OMAHA_COMMON_CONST_TIMEOUTS_H__

-

-namespace omaha {

-

-// Timeout for tearing down thread

-const int kMaxThreadDestructionTimeMs = 2000;

-

-const int kRegisterExeTimeoutMs =                  30000;      // 30 seconds

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_CONST_TIMEOUTS_H__

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Constants used for different timeouts in Common Installer
+
+#ifndef OMAHA_COMMON_CONST_TIMEOUTS_H__
+#define OMAHA_COMMON_CONST_TIMEOUTS_H__
+
+namespace omaha {
+
+// Timeout for tearing down thread
+const int kMaxThreadDestructionTimeMs = 2000;
+
+const int kRegisterExeTimeoutMs =                  30000;      // 30 seconds
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_CONST_TIMEOUTS_H__
+
diff --git a/common/const_ui.h b/common/const_ui.h
index eedfc92..b41be7a 100644
--- a/common/const_ui.h
+++ b/common/const_ui.h
@@ -1,24 +1,24 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// UI constants

-

-#ifndef OMAHA_COMMON_CONST_UI_H_

-#define OMAHA_COMMON_CONST_UI_H_

-

-namespace omaha {

-}

-

-#endif  // OMAHA_COMMON_CONST_UI_H_

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// UI constants
+
+#ifndef OMAHA_COMMON_CONST_UI_H_
+#define OMAHA_COMMON_CONST_UI_H_
+
+namespace omaha {
+}
+
+#endif  // OMAHA_COMMON_CONST_UI_H_
diff --git a/common/const_utils.h b/common/const_utils.h
index 363787c..75b5d49 100644
--- a/common/const_utils.h
+++ b/common/const_utils.h
@@ -1,90 +1,90 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Constants used in util functions

-

-#ifndef OMAHA_COMMON_CONST_UTILS_H__

-#define OMAHA_COMMON_CONST_UTILS_H__

-

-namespace omaha {

-

-// The registry key for the registered application path. Take a look at

-// http://msdn2.microsoft.com/en-us/library/ms997545.aspx for more information.

-#define kRegKeyApplicationPath \

-    _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths")

-#define kRegKeyPathValue _T("Path")

-

-// The regkey for the default browser the Windows Shell opens.

-#define kRegKeyDefaultBrowser _T("SOFTWARE\\Clients\\StartMenuInternet")

-#define kRegKeyUserDefaultBrowser _T("HKCU\\") kRegKeyDefaultBrowser

-#define kRegKeyMachineDefaultBrowser _T("HKLM\\") kRegKeyDefaultBrowser

-#define kRegKeyShellOpenCommand _T("\\shell\\open\\command")

-#define kRegKeyLegacyDefaultBrowser _T("HKCR\\http")

-#define kRegKeyLegacyDefaultBrowserCommand \

-            kRegKeyLegacyDefaultBrowser kRegKeyShellOpenCommand

-

-#define kIeExeName _T("IEXPLORE.EXE")

-#define kFirefoxExeName _T("FIREFOX.EXE")

-#define kChromeExeName _T("CHROME.EXE")

-

-// The regkey for proxy settings for IE.

-const TCHAR* const kRegKeyIESettings =

-    _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");

-const TCHAR* const kRegKeyIESettingsConnections = _T("Connections");

-const TCHAR* const kRegValueIEDefaultConnectionSettings =

-    _T("DefaultConnectionSettings");

-const TCHAR* const kRegValueIEProxyEnable = _T("ProxyEnable");

-const TCHAR* const kRegValueIEProxyServer = _T("ProxyServer");

-const TCHAR* const kRegValueIEAutoConfigURL = _T("AutoConfigURL");

-

-// Internet Explorer.

-#define kRegKeyIeClass \

-    _T("HKCR\\CLSID\\{0002DF01-0000-0000-C000-000000000046}\\LocalServer32")

-#define kRegValueIeClass _T("")

-

-// Firefox.

-#define kRegKeyFirefox \

-    _T("HKCR\\Applications\\FIREFOX.EXE\\shell\\open\\command")

-#define kRegValueFirefox        _T("")

-#define kFullRegKeyFirefox      _T("HKLM\\SOFTWARE\\Mozilla\\Mozilla Firefox")

-#define kRegKeyFirefoxPlugins   _T("plugins")

-#define kFirefoxCurrentVersion  _T("CurrentVersion")

-#define kFirefoxInstallDir      _T("Install Directory")

-

-// Chrome.

-#define kRegKeyChrome _T("HKCR\\Applications\\chrome.exe\\shell\\open\\command")

-#define kRegValueChrome _T("")

-

-// Amount of disk space required for program files.

-#ifdef _DEBUG

-// 100 MB since debug usually includes PDBs in addition to huge EXEs.

-#define kSpaceRequiredToInstallProgramFiles (100LL * 1000LL * 1000LL)

-#else

-#define kSpaceRequiredToInstallProgramFiles (10LL * 1000LL * 1000LL)  // 10MB

-#endif

-

-// Preferred amount of disk space for data (choose first location if found).

-#define kSpacePreferredToInstallDataDir (1000LL * 1000LL * 1000LL)

-

-// Amount of disk space required for data (choose first location if

-// could not find a location with the preferred amount of space).

-#define kSpaceRequiredToInstallDataDir (500LL * 1000LL * 1000LL)

-

-// Maximum file size allowed for performing authentication.

-#define kMaxFileSizeForAuthentication (512000000L)    // 512MB

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_CONST_UTILS_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Constants used in util functions
+
+#ifndef OMAHA_COMMON_CONST_UTILS_H__
+#define OMAHA_COMMON_CONST_UTILS_H__
+
+namespace omaha {
+
+// The registry key for the registered application path. Take a look at
+// http://msdn2.microsoft.com/en-us/library/ms997545.aspx for more information.
+#define kRegKeyApplicationPath \
+    _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths")
+#define kRegKeyPathValue _T("Path")
+
+// The regkey for the default browser the Windows Shell opens.
+#define kRegKeyDefaultBrowser _T("SOFTWARE\\Clients\\StartMenuInternet")
+#define kRegKeyUserDefaultBrowser _T("HKCU\\") kRegKeyDefaultBrowser
+#define kRegKeyMachineDefaultBrowser _T("HKLM\\") kRegKeyDefaultBrowser
+#define kRegKeyShellOpenCommand _T("\\shell\\open\\command")
+#define kRegKeyLegacyDefaultBrowser _T("HKCR\\http")
+#define kRegKeyLegacyDefaultBrowserCommand \
+            kRegKeyLegacyDefaultBrowser kRegKeyShellOpenCommand
+
+#define kIeExeName _T("IEXPLORE.EXE")
+#define kFirefoxExeName _T("FIREFOX.EXE")
+#define kChromeExeName _T("CHROME.EXE")
+
+// The regkey for proxy settings for IE.
+const TCHAR* const kRegKeyIESettings =
+    _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings");
+const TCHAR* const kRegKeyIESettingsConnections = _T("Connections");
+const TCHAR* const kRegValueIEDefaultConnectionSettings =
+    _T("DefaultConnectionSettings");
+const TCHAR* const kRegValueIEProxyEnable = _T("ProxyEnable");
+const TCHAR* const kRegValueIEProxyServer = _T("ProxyServer");
+const TCHAR* const kRegValueIEAutoConfigURL = _T("AutoConfigURL");
+
+// Internet Explorer.
+#define kRegKeyIeClass \
+    _T("HKCR\\CLSID\\{0002DF01-0000-0000-C000-000000000046}\\LocalServer32")
+#define kRegValueIeClass _T("")
+
+// Firefox.
+#define kRegKeyFirefox \
+    _T("HKCR\\Applications\\FIREFOX.EXE\\shell\\open\\command")
+#define kRegValueFirefox        _T("")
+#define kFullRegKeyFirefox      _T("HKLM\\SOFTWARE\\Mozilla\\Mozilla Firefox")
+#define kRegKeyFirefoxPlugins   _T("plugins")
+#define kFirefoxCurrentVersion  _T("CurrentVersion")
+#define kFirefoxInstallDir      _T("Install Directory")
+
+// Chrome.
+#define kRegKeyChrome _T("HKCR\\Applications\\chrome.exe\\shell\\open\\command")
+#define kRegValueChrome _T("")
+
+// Amount of disk space required for program files.
+#ifdef _DEBUG
+// 100 MB since debug usually includes PDBs in addition to huge EXEs.
+#define kSpaceRequiredToInstallProgramFiles (100LL * 1000LL * 1000LL)
+#else
+#define kSpaceRequiredToInstallProgramFiles (10LL * 1000LL * 1000LL)  // 10MB
+#endif
+
+// Preferred amount of disk space for data (choose first location if found).
+#define kSpacePreferredToInstallDataDir (1000LL * 1000LL * 1000LL)
+
+// Amount of disk space required for data (choose first location if
+// could not find a location with the preferred amount of space).
+#define kSpaceRequiredToInstallDataDir (500LL * 1000LL * 1000LL)
+
+// Maximum file size allowed for performing authentication.
+#define kMaxFileSizeForAuthentication (512000000L)    // 512MB
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_CONST_UTILS_H__
diff --git a/common/constants.h b/common/constants.h
index 5ebef82..006780f 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -1,316 +1,316 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Constants used by Omaha project

-

-#ifndef OMAHA_COMMON_CONSTANTS_H__

-#define OMAHA_COMMON_CONSTANTS_H__

-

-#include <windows.h>

-#include <tchar.h>

-

-namespace omaha {

-

-// Exe loading address for Windows executables

-// (also the HMODULE for an exe app)

-#define kExeLoadingAddress      0x00400000

-

-// application name (for debugging messages)

-// kAppName == "Google Update"

-#define kAppName          _T(PUBLISHER_NAME_ANSI) _T(" ") _T(PRODUCT_NAME_ANSI)

-

-// Product name to report

-// kProductNameToReport == "Google Update"

-#define kProductNameToReport    kAppName

-

-// prefix for any created files

-#define kFilePrefix  _T("GoogleUpdate")

-

-// prefix for any Win32 objects (mutexes, events, etc.)

-#define kLockPrefix   _T("_GOOGLE_UPDATE_")

-

-//

-// Omaha's app ID

-//

-#define GOOPDATE_APP_ID _T("{430FD4D0-B729-4F61-AA34-91526481799D}")

-const TCHAR* const kGoogleUpdateAppId = GOOPDATE_APP_ID;

-const GUID kGoopdateGuid = {0x430FD4D0, 0xB729, 0x4F61,

-                            {0xAA, 0x34, 0x91, 0x52, 0x64, 0x81, 0x79, 0x9D}};

-

-//

-// Directory names

-//

-#define OFFLINE_DIR_NAME _T("Offline")

-

-#define OMAHA_REL_GOOGLE_DIR _T("Google")

-#define OMAHA_REL_CRASH_DIR OMAHA_REL_GOOGLE_DIR _T("\\CrashReports")

-#define OMAHA_REL_GOOPDATE_INSTALL_DIR OMAHA_REL_GOOGLE_DIR _T("\\Update")

-#define OMAHA_REL_LOG_DIR OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\Log")

-#define OMAHA_REL_OFFLINE_STORAGE_DIR \

-    OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\") OFFLINE_DIR_NAME

-#define OMAHA_REL_DOWNLOAD_STORAGE_DIR \

-    OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\Download")

-#define OMAHA_REL_TEMP_DOWNLOAD_DIR  _T("\\Temp")

-#define OMAHA_REL_MANIEFST_DIR OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\Manifest")

-#define OMAHA_REL_INITIAL_MANIFEST_DIR OMAHA_REL_MANIEFST_DIR _T("\\Initial")

-#define OMAHA_REL_MANIFEST_INPROGRESS_DIR \

-    OMAHA_REL_MANIEFST_DIR _T("\\InProgress")

-

-//

-// Registry keys and values

-//

-#define MACHINE_KEY_NAME _T("HKLM")

-#define MACHINE_KEY MACHINE_KEY_NAME _T("\\")

-#define USER_KEY_NAME _T("HKCU")

-#define USER_KEY USER_KEY_NAME _T("\\")

-#define USERS_KEY _T("HKU\\")

-#define GOOGLE_MAIN_KEY _T("Software\\Google\\")

-#define GOOPDATE_MAIN_KEY GOOGLE_MAIN_KEY _T("Update\\")

-#define GOOPDATE_REG_RELATIVE_CLIENTS GOOPDATE_MAIN_KEY _T("Clients\\")

-#define GOOPDATE_REG_RELATIVE_CLIENT_STATE GOOPDATE_MAIN_KEY _T("ClientState\\")

-#define GOOPDATE_REG_RELATIVE_CLIENT_STATE_MEDIUM \

-    GOOPDATE_MAIN_KEY _T("ClientStateMedium\\")

-#define GOOGLE_POLICIES_MAIN_KEY _T("Software\\Policies\\Google\\")

-#define GOOPDATE_POLICIES_RELATIVE GOOGLE_POLICIES_MAIN_KEY _T("Update\\")

-

-#define USER_REG_GOOGLE USER_KEY GOOGLE_MAIN_KEY

-#define USER_REG_UPDATE USER_KEY GOOPDATE_MAIN_KEY

-#define USER_REG_CLIENTS USER_KEY GOOPDATE_REG_RELATIVE_CLIENTS

-#define USER_REG_CLIENTS_GOOPDATE  USER_REG_CLIENTS GOOPDATE_APP_ID

-#define USER_REG_CLIENT_STATE USER_KEY GOOPDATE_REG_RELATIVE_CLIENT_STATE

-#define USER_REG_CLIENT_STATE_GOOPDATE USER_REG_CLIENT_STATE GOOPDATE_APP_ID

-

-#define MACHINE_REG_GOOGLE MACHINE_KEY GOOGLE_MAIN_KEY

-#define MACHINE_REG_UPDATE MACHINE_KEY GOOPDATE_MAIN_KEY

-#define MACHINE_REG_CLIENTS MACHINE_KEY GOOPDATE_REG_RELATIVE_CLIENTS

-#define MACHINE_REG_CLIENTS_GOOPDATE  MACHINE_REG_CLIENTS GOOPDATE_APP_ID

-#define MACHINE_REG_CLIENT_STATE MACHINE_KEY GOOPDATE_REG_RELATIVE_CLIENT_STATE

-#define MACHINE_REG_CLIENT_STATE_GOOPDATE \

-    MACHINE_REG_CLIENT_STATE GOOPDATE_APP_ID

-#define MACHINE_REG_CLIENT_STATE_MEDIUM \

-    MACHINE_KEY GOOPDATE_REG_RELATIVE_CLIENT_STATE_MEDIUM

-

-#define USER_REG_VISTA_LOW_INTEGRITY_HKCU \

-    _T("Software\\Microsoft\\Internet Explorer\\") \

-    _T("InternetRegistry\\REGISTRY\\USER")

-

-#define MACHINE_REG_UPDATE_DEV MACHINE_KEY GOOGLE_MAIN_KEY _T("UpdateDev\\")

-

-//

-// Registry values under MACHINE_REG_UPDATE_DEV allow customization of the

-// default behavior. The overrides apply for both user and machine

-// instances of omaha.

-//

-// The values below can only be overriden in debug builds.

-const TCHAR* const kRegValueNameOverInstall    = _T("OverInstall");

-const TCHAR* const kRegValueNameUrl            = _T("url");

-const TCHAR* const kRegValueNamePingUrl        = _T("PingUrl");

-const TCHAR* const kRegValueNameWebPluginUrl   = _T("WebPluginUrl");

-

-// The values below can be overriden in both debug and opt builds.

-const TCHAR* const kRegValueTestSource         = _T("TestSource");

-const TCHAR* const kRegValueAuCheckPeriodMs    = _T("AuCheckPeriodMs");

-const TCHAR* const kRegValueCrCheckPeriodMs    = _T("CrCheckPeriodMs");

-const TCHAR* const kRegValueProxyHost          = _T("ProxyHost");

-const TCHAR* const kRegValueProxyPort          = _T("ProxyPort");

-

-// The values below can be overriden in unofficial builds.

-const TCHAR* const kRegValueNameWindowsInstalling = _T("WindowsInstalling");

-

-// Allows Google Update to log events in the Windows Event Log. This is

-// a DWORD value 0: Log nothing, 1: Log warnings and errors, 2: Log everything.

-const TCHAR* const kRegValueEventLogLevel      = _T("LogEventLevel");

-

-enum LogEventLevel {

-  LOG_EVENT_LEVEL_NONE           = 0,

-  LOG_EVENT_LEVEL_WARN_AND_ERROR = 1,

-  LOG_EVENT_LEVEL_ALL            = 2

-};

-

-// How often Google Update checks the server for updates.

-const TCHAR* const kRegValueLastCheckPeriodSec = _T("LastCheckPeriodSec");

-

-// Uses the production or the test cup keys. Once the client has negotiated

-// CUP credentials {sk, c} and it has saved them under the corresponding

-// Google\Update\network key then the client does not need any of the CUP keys.

-// To force the client to use test or production keys, {sk, c} credentials must

-// be cleared too.

-const TCHAR* const kRegValueCupKeys            = _T("TestKeys");

-

-// Allow a custom host pattern to be specified. For example,

-// "^https?://some_test_server\.google\.com/". For other examples, look at

-// site_lock_pattern_strings in oneclick_worker.cc. The detailed regular

-// expression syntax is documented in the MSDN documentation for the CAtlRegExp

-// class: http://msdn.microsoft.com/en-us/library/k3zs4axe(VS.80).aspx

-const TCHAR* const kRegValueOneClickHostPattern = _T("OneClickHostPattern");

-

-// Disables the Code Red check.

-const TCHAR* const kRegValueNoCodeRedCheck     = _T("NoCrCheck");

-

-// Enables sending usage stats always if the value is present.

-const TCHAR* const kRegValueForceUsageStats    = _T("UsageStats");

-

-// Enables monitoring the 'LastChecked' value for testing purposes. When

-// the 'LastChecked' is deleted, the core starts a worker process to do an

-// update check. This value must be set before the core process starts.

-const TCHAR* const kRegValueMonitorLastChecked = _T("MonitorLastChecked");

-

-// The test_source value to use for googleupdate instances that have

-// customizations, and hence should be discarded from metrics on the dashboard.

-const TCHAR* const kRegValueTestSourceAuto     = _T("auto");

-

-// The network configuration to override the network detection.

-// The corresponding value must have the following format:

-// wpad=[false|true];script=script_url;proxy=host:port

-const TCHAR* const kRegValueNetConfig          = _T("NetConfig");

-

-const int kMaxAppNameLength = 512;

-

-// Specifies whether a tristate item has a value and if so what the value is.

-enum Tristate {

-  TRISTATE_FALSE,

-  TRISTATE_TRUE,

-  TRISTATE_NONE

-};

-

-// Number of periods to use when abbreviating URLs

-#define kAbbreviationPeriodLength 3

-

-// The Unicode "Byte Order Marker" character.  This is the native

-// encoding, i.e. after conversion from UTF-8 or whatever.

-const wchar_t kUnicodeBom = 0xFEFF;

-

-// Using these constants will make ATL load the

-// typelib directly from a DLL instead of looking up typelib

-// registration in registry.

-const DWORD kMajorTypeLibVersion = 0xFFFF;

-const DWORD kMinorTypeLibVersion = 0xFFFF;

-

-// Brand id length

-const int kBrandIdLength = 4;

-

-// Country code length according to ISO 3166-3.

-const int kCountryCodeMaxLength = 5;

-

-// Language code length.

-const int kLangMaxLength = 10;

-

-// When not specified, the country code defaults to USA

-const TCHAR* const kDefaultCountryCode = _T("us");

-

-// the max length of the extra info we can store inside the install stubs.

-const int kExtraMaxLength = 64 * 1024;  // 64 KB

-

-// The value that is used in the run key.

-const TCHAR* const kRunValueName = _T("Google Update");

-

-// Default brand code value when one is not specified.

-// This has been specifically assigned to Omaha.

-const TCHAR* const kDefaultGoogleUpdateBrandCode = _T("GGLS");

-

-// The platform named used for Windows.

-const TCHAR* const kPlatformWin = _T("win");

-

-// The following are response strings returned by the server.

-// They must exactly match the strings returned by the server.

-const TCHAR* const kResponseStatusOkValue = _T("ok");

-const TCHAR* const kResponseStatusNoUpdate = _T("noupdate");

-const TCHAR* const kResponseStatusRestrictedExportCountry = _T("restricted");

-const TCHAR* const kResponseStatusOsNotSupported = _T("error-osnotsupported");

-const TCHAR* const kResponseStatusUnKnownApplication =

-    _T("error-UnKnownApplication");

-const TCHAR* const kResponseStatusInternalError = _T("error-internal");

-

-const TCHAR* const kLocalSystemSid = _T("S-1-5-18");

-

-// Defines LastCheckPeriodSec: the time interval between actual server

-// update checks. Opt builds have an aggressive check for updates every 5 hours.

-// This introduces some time shift for computers connected all the time, for

-// example, the update checks occur at: 12, 17, 22, 3, 8, 13, 18, etc...

-const int kMsPerSec           = 1000;

-const int kMinPerHour         = 60;

-const int kSecondsPerHour     = 60 * 60;

-

-// Since time computation for LastChecked is done in seconds, sometimes it

-// can miss an update check, depending on arithmetic truncations.

-// Adjust down the LastCheckPeriod so that the update worker does not miss it.

-//

-// Almost 5 hours for production users and almost hourly for Googlers.

-const int kLastCheckPeriodSec         = 5 * 59 * kMinPerHour;

-const int kLastCheckPeriodGooglerSec  = 1 * 59 * kMinPerHour;

-

-

-const int kMinLastCheckPeriodSec = 60;  // 60 seconds minimum.

-

-// Defines the time interval when the core is kicking off silent workers. When

-// there is nothing to do, a worker does not take more than 200 ms to run.

-// Googlers are supposed to update at least once every hour. Therefore, start

-// workers every 30 minutes.

-const int kAUCheckPeriodMs        = 60 * 60 * 1000;   // Hourly.

-const int kAUCheckPeriodGooglerMs = 30 * 60 * 1000;   // 30 minutes.

-

-// Avoids starting workers too soon. This helps reduce disk thrashing at

-// boot or logon, as well as needlessly starting a worker after setting up.

-const int kUpdateTimerStartupDelayMinMs = 5 * 60 * 1000;   // 5 minutes.

-

-// Maximum amount of time to wait before starting an update worker.

-const int kUpdateTimerStartupDelayMaxMs = 15 * 60 * 1000;   // 15 minutes.

-

-// Minimum AU check interval is lowered to 3 seconds to speed up test

-// automation.

-const int kMinAUCheckPeriodMs = 1000 * 3;   // 3 seconds.

-

-// The Code Red check frequency.

-const int kCodeRedCheckPeriodMs     = 24 * 60 * 60 * 1000;    // 24 hours.

-const int kMinCodeRedCheckPeriodMs  = 60 * 1000;              // 1 minute.

-

-// The minimum amount of time after a /oem install that Google Update is

-// considered to be in OEM mode regardless of audit mode.

-const int kMinOemModeMs = 72 * 60 * 60 * 1000;  // 72 hours.

-

-// The amount of time to wait for the setup lock before giving up.

-const int kSetupLockWaitMs = 1000;  // 1 second.

-

-// The amount of time to wait for other instances to shutdown before giving up.

-// There is no UI during this time, so the interactive value cannot be too long.

-// Even the silent value cannot be too long because Setup Lock is being held.

-const int kSetupShutdownWaitMsInteractiveNoUi = 2000;   // 2 seconds.

-const int kSetupShutdownWaitMsSilent          = 15000;  // 15 seconds.

-

-// Time to wait for the busy MSI when uninstalling. If MSI is found busy,

-// Omaha won't uninstall. The timeout should be high enough so that it allows

-// a normal application uninstall to finish and trigger an Omaha uninstall

-// when needed.

-const int kWaitForMSIExecuteMs                = 5 * 60000;  // 5 minutes.

-

-// Name of the language key-value pair inside the version resource.

-const TCHAR* const kLanguageVersionName = _T("LanguageId");

-

-// These must be in sync with the WiX files.

-const TCHAR* const kHelperInstallerName = _T("GoogleUpdateHelper.msi");

-const TCHAR* const kHelperInstallerProductGuid =

-    _T("{A92DAB39-4E2C-4304-9AB6-BC44E68B55E2}");

-const TCHAR* const kHelperPatchName = _T("GoogleUpdateHelperPatch.msp");

-const TCHAR* const kHelperPatchGuid =

-    _T("{E0D0D2C9-5836-4023-AB1D-54EC3B90AD03}");

-

-// Group name to use to read/write INI files for custom crash client info.

-const TCHAR* const kCustomClientInfoGroup = _T("ClientCustomData");

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_CONSTANTS_H__

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Constants used by Omaha project
+
+#ifndef OMAHA_COMMON_CONSTANTS_H__
+#define OMAHA_COMMON_CONSTANTS_H__
+
+#include <windows.h>
+#include <tchar.h>
+
+namespace omaha {
+
+// Exe loading address for Windows executables
+// (also the HMODULE for an exe app)
+#define kExeLoadingAddress      0x00400000
+
+// application name (for debugging messages)
+// kAppName == "Google Update"
+#define kAppName          _T(PUBLISHER_NAME_ANSI) _T(" ") _T(PRODUCT_NAME_ANSI)
+
+// Product name to report
+// kProductNameToReport == "Google Update"
+#define kProductNameToReport    kAppName
+
+// prefix for any created files
+#define kFilePrefix  _T("GoogleUpdate")
+
+// prefix for any Win32 objects (mutexes, events, etc.)
+#define kLockPrefix   _T("_GOOGLE_UPDATE_")
+
+//
+// Omaha's app ID
+//
+#define GOOPDATE_APP_ID _T("{430FD4D0-B729-4F61-AA34-91526481799D}")
+const TCHAR* const kGoogleUpdateAppId = GOOPDATE_APP_ID;
+const GUID kGoopdateGuid = {0x430FD4D0, 0xB729, 0x4F61,
+                            {0xAA, 0x34, 0x91, 0x52, 0x64, 0x81, 0x79, 0x9D}};
+
+//
+// Directory names
+//
+#define OFFLINE_DIR_NAME _T("Offline")
+
+#define OMAHA_REL_GOOGLE_DIR _T("Google")
+#define OMAHA_REL_CRASH_DIR OMAHA_REL_GOOGLE_DIR _T("\\CrashReports")
+#define OMAHA_REL_GOOPDATE_INSTALL_DIR OMAHA_REL_GOOGLE_DIR _T("\\Update")
+#define OMAHA_REL_LOG_DIR OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\Log")
+#define OMAHA_REL_OFFLINE_STORAGE_DIR \
+    OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\") OFFLINE_DIR_NAME
+#define OMAHA_REL_DOWNLOAD_STORAGE_DIR \
+    OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\Download")
+#define OMAHA_REL_TEMP_DOWNLOAD_DIR  _T("\\Temp")
+#define OMAHA_REL_MANIEFST_DIR OMAHA_REL_GOOPDATE_INSTALL_DIR _T("\\Manifest")
+#define OMAHA_REL_INITIAL_MANIFEST_DIR OMAHA_REL_MANIEFST_DIR _T("\\Initial")
+#define OMAHA_REL_MANIFEST_INPROGRESS_DIR \
+    OMAHA_REL_MANIEFST_DIR _T("\\InProgress")
+
+//
+// Registry keys and values
+//
+#define MACHINE_KEY_NAME _T("HKLM")
+#define MACHINE_KEY MACHINE_KEY_NAME _T("\\")
+#define USER_KEY_NAME _T("HKCU")
+#define USER_KEY USER_KEY_NAME _T("\\")
+#define USERS_KEY _T("HKU\\")
+#define GOOGLE_MAIN_KEY _T("Software\\Google\\")
+#define GOOPDATE_MAIN_KEY GOOGLE_MAIN_KEY _T("Update\\")
+#define GOOPDATE_REG_RELATIVE_CLIENTS GOOPDATE_MAIN_KEY _T("Clients\\")
+#define GOOPDATE_REG_RELATIVE_CLIENT_STATE GOOPDATE_MAIN_KEY _T("ClientState\\")
+#define GOOPDATE_REG_RELATIVE_CLIENT_STATE_MEDIUM \
+    GOOPDATE_MAIN_KEY _T("ClientStateMedium\\")
+#define GOOGLE_POLICIES_MAIN_KEY _T("Software\\Policies\\Google\\")
+#define GOOPDATE_POLICIES_RELATIVE GOOGLE_POLICIES_MAIN_KEY _T("Update\\")
+
+#define USER_REG_GOOGLE USER_KEY GOOGLE_MAIN_KEY
+#define USER_REG_UPDATE USER_KEY GOOPDATE_MAIN_KEY
+#define USER_REG_CLIENTS USER_KEY GOOPDATE_REG_RELATIVE_CLIENTS
+#define USER_REG_CLIENTS_GOOPDATE  USER_REG_CLIENTS GOOPDATE_APP_ID
+#define USER_REG_CLIENT_STATE USER_KEY GOOPDATE_REG_RELATIVE_CLIENT_STATE
+#define USER_REG_CLIENT_STATE_GOOPDATE USER_REG_CLIENT_STATE GOOPDATE_APP_ID
+
+#define MACHINE_REG_GOOGLE MACHINE_KEY GOOGLE_MAIN_KEY
+#define MACHINE_REG_UPDATE MACHINE_KEY GOOPDATE_MAIN_KEY
+#define MACHINE_REG_CLIENTS MACHINE_KEY GOOPDATE_REG_RELATIVE_CLIENTS
+#define MACHINE_REG_CLIENTS_GOOPDATE  MACHINE_REG_CLIENTS GOOPDATE_APP_ID
+#define MACHINE_REG_CLIENT_STATE MACHINE_KEY GOOPDATE_REG_RELATIVE_CLIENT_STATE
+#define MACHINE_REG_CLIENT_STATE_GOOPDATE \
+    MACHINE_REG_CLIENT_STATE GOOPDATE_APP_ID
+#define MACHINE_REG_CLIENT_STATE_MEDIUM \
+    MACHINE_KEY GOOPDATE_REG_RELATIVE_CLIENT_STATE_MEDIUM
+
+#define USER_REG_VISTA_LOW_INTEGRITY_HKCU \
+    _T("Software\\Microsoft\\Internet Explorer\\") \
+    _T("InternetRegistry\\REGISTRY\\USER")
+
+#define MACHINE_REG_UPDATE_DEV MACHINE_KEY GOOGLE_MAIN_KEY _T("UpdateDev\\")
+
+//
+// Registry values under MACHINE_REG_UPDATE_DEV allow customization of the
+// default behavior. The overrides apply for both user and machine
+// instances of omaha.
+//
+// The values below can only be overriden in debug builds.
+const TCHAR* const kRegValueNameOverInstall    = _T("OverInstall");
+const TCHAR* const kRegValueNameUrl            = _T("url");
+const TCHAR* const kRegValueNamePingUrl        = _T("PingUrl");
+const TCHAR* const kRegValueNameWebPluginUrl   = _T("WebPluginUrl");
+
+// The values below can be overriden in both debug and opt builds.
+const TCHAR* const kRegValueTestSource         = _T("TestSource");
+const TCHAR* const kRegValueAuCheckPeriodMs    = _T("AuCheckPeriodMs");
+const TCHAR* const kRegValueCrCheckPeriodMs    = _T("CrCheckPeriodMs");
+const TCHAR* const kRegValueProxyHost          = _T("ProxyHost");
+const TCHAR* const kRegValueProxyPort          = _T("ProxyPort");
+
+// The values below can be overriden in unofficial builds.
+const TCHAR* const kRegValueNameWindowsInstalling = _T("WindowsInstalling");
+
+// Allows Google Update to log events in the Windows Event Log. This is
+// a DWORD value 0: Log nothing, 1: Log warnings and errors, 2: Log everything.
+const TCHAR* const kRegValueEventLogLevel      = _T("LogEventLevel");
+
+enum LogEventLevel {
+  LOG_EVENT_LEVEL_NONE           = 0,
+  LOG_EVENT_LEVEL_WARN_AND_ERROR = 1,
+  LOG_EVENT_LEVEL_ALL            = 2
+};
+
+// How often Google Update checks the server for updates.
+const TCHAR* const kRegValueLastCheckPeriodSec = _T("LastCheckPeriodSec");
+
+// Uses the production or the test cup keys. Once the client has negotiated
+// CUP credentials {sk, c} and it has saved them under the corresponding
+// Google\Update\network key then the client does not need any of the CUP keys.
+// To force the client to use test or production keys, {sk, c} credentials must
+// be cleared too.
+const TCHAR* const kRegValueCupKeys            = _T("TestKeys");
+
+// Allow a custom host pattern to be specified. For example,
+// "^https?://some_test_server\.google\.com/". For other examples, look at
+// site_lock_pattern_strings in oneclick_worker.cc. The detailed regular
+// expression syntax is documented in the MSDN documentation for the CAtlRegExp
+// class: http://msdn.microsoft.com/en-us/library/k3zs4axe(VS.80).aspx
+const TCHAR* const kRegValueOneClickHostPattern = _T("OneClickHostPattern");
+
+// Disables the Code Red check.
+const TCHAR* const kRegValueNoCodeRedCheck     = _T("NoCrCheck");
+
+// Enables sending usage stats always if the value is present.
+const TCHAR* const kRegValueForceUsageStats    = _T("UsageStats");
+
+// Enables monitoring the 'LastChecked' value for testing purposes. When
+// the 'LastChecked' is deleted, the core starts a worker process to do an
+// update check. This value must be set before the core process starts.
+const TCHAR* const kRegValueMonitorLastChecked = _T("MonitorLastChecked");
+
+// The test_source value to use for googleupdate instances that have
+// customizations, and hence should be discarded from metrics on the dashboard.
+const TCHAR* const kRegValueTestSourceAuto     = _T("auto");
+
+// The network configuration to override the network detection.
+// The corresponding value must have the following format:
+// wpad=[false|true];script=script_url;proxy=host:port
+const TCHAR* const kRegValueNetConfig          = _T("NetConfig");
+
+const int kMaxAppNameLength = 512;
+
+// Specifies whether a tristate item has a value and if so what the value is.
+enum Tristate {
+  TRISTATE_FALSE,
+  TRISTATE_TRUE,
+  TRISTATE_NONE
+};
+
+// Number of periods to use when abbreviating URLs
+#define kAbbreviationPeriodLength 3
+
+// The Unicode "Byte Order Marker" character.  This is the native
+// encoding, i.e. after conversion from UTF-8 or whatever.
+const wchar_t kUnicodeBom = 0xFEFF;
+
+// Using these constants will make ATL load the
+// typelib directly from a DLL instead of looking up typelib
+// registration in registry.
+const DWORD kMajorTypeLibVersion = 0xFFFF;
+const DWORD kMinorTypeLibVersion = 0xFFFF;
+
+// Brand id length
+const int kBrandIdLength = 4;
+
+// Country code length according to ISO 3166-3.
+const int kCountryCodeMaxLength = 5;
+
+// Language code length.
+const int kLangMaxLength = 10;
+
+// When not specified, the country code defaults to USA
+const TCHAR* const kDefaultCountryCode = _T("us");
+
+// the max length of the extra info we can store inside the install stubs.
+const int kExtraMaxLength = 64 * 1024;  // 64 KB
+
+// The value that is used in the run key.
+const TCHAR* const kRunValueName = _T("Google Update");
+
+// Default brand code value when one is not specified.
+// This has been specifically assigned to Omaha.
+const TCHAR* const kDefaultGoogleUpdateBrandCode = _T("GGLS");
+
+// The platform named used for Windows.
+const TCHAR* const kPlatformWin = _T("win");
+
+// The following are response strings returned by the server.
+// They must exactly match the strings returned by the server.
+const TCHAR* const kResponseStatusOkValue = _T("ok");
+const TCHAR* const kResponseStatusNoUpdate = _T("noupdate");
+const TCHAR* const kResponseStatusRestrictedExportCountry = _T("restricted");
+const TCHAR* const kResponseStatusOsNotSupported = _T("error-osnotsupported");
+const TCHAR* const kResponseStatusUnKnownApplication =
+    _T("error-UnKnownApplication");
+const TCHAR* const kResponseStatusInternalError = _T("error-internal");
+
+const TCHAR* const kLocalSystemSid = _T("S-1-5-18");
+
+// Defines LastCheckPeriodSec: the time interval between actual server
+// update checks. Opt builds have an aggressive check for updates every 5 hours.
+// This introduces some time shift for computers connected all the time, for
+// example, the update checks occur at: 12, 17, 22, 3, 8, 13, 18, etc...
+const int kMsPerSec           = 1000;
+const int kMinPerHour         = 60;
+const int kSecondsPerHour     = 60 * 60;
+
+// Since time computation for LastChecked is done in seconds, sometimes it
+// can miss an update check, depending on arithmetic truncations.
+// Adjust down the LastCheckPeriod so that the update worker does not miss it.
+//
+// Almost 5 hours for production users and almost hourly for Googlers.
+const int kLastCheckPeriodSec         = 5 * 59 * kMinPerHour;
+const int kLastCheckPeriodGooglerSec  = 1 * 59 * kMinPerHour;
+
+
+const int kMinLastCheckPeriodSec = 60;  // 60 seconds minimum.
+
+// Defines the time interval when the core is kicking off silent workers. When
+// there is nothing to do, a worker does not take more than 200 ms to run.
+// Googlers are supposed to update at least once every hour. Therefore, start
+// workers every 30 minutes.
+const int kAUCheckPeriodMs        = 60 * 60 * 1000;   // Hourly.
+const int kAUCheckPeriodGooglerMs = 30 * 60 * 1000;   // 30 minutes.
+
+// Avoids starting workers too soon. This helps reduce disk thrashing at
+// boot or logon, as well as needlessly starting a worker after setting up.
+const int kUpdateTimerStartupDelayMinMs = 5 * 60 * 1000;   // 5 minutes.
+
+// Maximum amount of time to wait before starting an update worker.
+const int kUpdateTimerStartupDelayMaxMs = 15 * 60 * 1000;   // 15 minutes.
+
+// Minimum AU check interval is lowered to 3 seconds to speed up test
+// automation.
+const int kMinAUCheckPeriodMs = 1000 * 3;   // 3 seconds.
+
+// The Code Red check frequency.
+const int kCodeRedCheckPeriodMs     = 24 * 60 * 60 * 1000;    // 24 hours.
+const int kMinCodeRedCheckPeriodMs  = 60 * 1000;              // 1 minute.
+
+// The minimum amount of time after a /oem install that Google Update is
+// considered to be in OEM mode regardless of audit mode.
+const int kMinOemModeMs = 72 * 60 * 60 * 1000;  // 72 hours.
+
+// The amount of time to wait for the setup lock before giving up.
+const int kSetupLockWaitMs = 1000;  // 1 second.
+
+// The amount of time to wait for other instances to shutdown before giving up.
+// There is no UI during this time, so the interactive value cannot be too long.
+// Even the silent value cannot be too long because Setup Lock is being held.
+const int kSetupShutdownWaitMsInteractiveNoUi = 2000;   // 2 seconds.
+const int kSetupShutdownWaitMsSilent          = 15000;  // 15 seconds.
+
+// Time to wait for the busy MSI when uninstalling. If MSI is found busy,
+// Omaha won't uninstall. The timeout should be high enough so that it allows
+// a normal application uninstall to finish and trigger an Omaha uninstall
+// when needed.
+const int kWaitForMSIExecuteMs                = 5 * 60000;  // 5 minutes.
+
+// Name of the language key-value pair inside the version resource.
+const TCHAR* const kLanguageVersionName = _T("LanguageId");
+
+// These must be in sync with the WiX files.
+const TCHAR* const kHelperInstallerName = _T("GoogleUpdateHelper.msi");
+const TCHAR* const kHelperInstallerProductGuid =
+    _T("{A92DAB39-4E2C-4304-9AB6-BC44E68B55E2}");
+const TCHAR* const kHelperPatchName = _T("GoogleUpdateHelperPatch.msp");
+const TCHAR* const kHelperPatchGuid =
+    _T("{E0D0D2C9-5836-4023-AB1D-54EC3B90AD03}");
+
+// Group name to use to read/write INI files for custom crash client info.
+const TCHAR* const kCustomClientInfoGroup = _T("ClientCustomData");
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_CONSTANTS_H__
+
diff --git a/common/crc.cc b/common/crc.cc
index 4cb8d3c..94341f0 100644
--- a/common/crc.cc
+++ b/common/crc.cc
@@ -1,898 +1,898 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Implemetation of CRCs (aka Rabin Fingerprints).

-// Treats the input as a polynomial with coefficients in Z(2),

-// and finds the remainder when divided by an irreducible polynomial

-// of the appropriate length.

-// It handles all CRC sizes from 8 to 128 bits.

-// It's somewhat complicated by having separate implementations optimized for

-// CRC's <=32 bits, <= 64 bits, and <= 128 bits.

-// The input string is prefixed with a "1" bit, and has "degree" "0" bits

-// appended to it before the remainder is found.   This ensures that

-// short strings are scrambled somewhat and that strings consisting

-// of all nulls have a non-zero CRC.

-

-#include <stddef.h>

-#include "omaha/common/crc.h"

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-static const int SMALL_BITS = 8;

-                   // When extending an input with a string of zeroes,

-                   // if the number of zeroes is less than 2**SMALL_BITS,

-                   // a normal Extend is done, rather than a polynomial

-                   // multiplication.

-static const char zeroes[1 << SMALL_BITS] = { 0 };  // an array of zeroes

-

-static const uint8 *zero_ptr = 0;   // The 0 pointer---used for alignment

-

-// These are used to index a 2-entry array of words that together

-// for a longer integer.  LO indexes the low-order half.

-#define LO 0

-#define HI (1-LO)

-

-// Constructor and destructor for baseclase CRC.

-CRC::~CRC() {}

-CRC::CRC() {}

-

-struct CRC_pair {             // Used to represent a 128-bit value

-  uint64 lo;

-  uint64 hi;

-};

-

-class CRCImpl : public CRC {    // Implemention of the abstract class CRC

- public:

-  CRCImpl() {}

-  virtual ~CRCImpl() {}

-

-  // The internal version of CRC::New().

-  static CRCImpl *NewInternal(uint64 lo, uint64 hi,

-                              int degree, size_t roll_length);

-

-  virtual void Empty(uint64 *lo, uint64 *hi) const;

-

-  size_t roll_length_;    // length of window in rolling CRC

-  int degree_;            // bits in the CRC

-  uint64 poly_lo_;        // The CRC of the empty string, low part

-  uint64 poly_hi_;        // The CRC of the empty string, high part

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(CRCImpl);

-};

-

-// This is the 32-bit implementation.  It handles all sizes from 8 to 32.

-class CRC32 : public CRCImpl {

- public:

-  CRC32() {}

-  virtual ~CRC32() {}

-

-  virtual void Extend(uint64 *lo, uint64 *hi,

-                      const void *bytes, size_t length) const;

-  virtual void ExtendByZeroes(uint64 *lo, uint64 *hi, size_t length) const;

-  virtual void Roll(uint64 *lo, uint64 *hi, uint8 o_byte, uint8 i_byte) const;

-

-  uint32 table0_[256];  // table of byte extensions

-  uint32 table1_[256];  // table of byte extensions, shifted by 1 byte

-  uint32 table2_[256];  // table of byte extensions, shifted by 2 bytes

-  uint32 table3_[256];  // table of byte extensions, shifted by 3 bytes

-  uint32 roll_[256];    // table of byte roll values

-  uint32 zeroes_[256];  // table of zero extensions

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(CRC32);

-};

-

-static const uint64 UINT64_ZERO = 0;    // a 64-bit zero

-static const uint64 UINT64_ONE = 1;     // a 64-bit 1

-

-// The B() macro sets the bit corresponding to X**(_x) in the polynomial

-#define B(_x) (UINT64_ONE << ((_x) < 64?(63-(_x)):(127-(_x))))

-

-// Used to initialize polynomials.

-// The redundant tests on _len are to avoid warnings from the

-// compiler about inappropriate shift lengths.   These shifts

-// occur on not-taken branch of the ?: in some cases.

-#define kDefPoly(_h,_l,_len) \

- { ((_len) <= 64  ? (_l) >> ((_len) <= 64? 64 - (_len): 0) : \

-    (_len) == 128 ? (_h) : \

-                     ((_h) >> ((_len) > 64? 128 - (_len): 0)) | \

-                     ((_l) << ((_len) > 64 && (_len) < 128? (_len)-64: 0))), \

-   ((_len) <= 64  ? 0 : \

-    (_len) == 128 ? (_l) :  \

-                    (_l) >> ((_len) > 64? 128 - (_len): 0)), \

-   (_len) }

-

-// A table of irreducible polynomials suitable for use with the implementation.

-// Indexes 0...1 have degree 32 polynomials.

-// Indexes 2...3 have degree 64 polynomials.

-// Indexes 4...5 have degree 96 polynomials.

-// Indexes 6...7 have degree 128 polynomials.

-// Index i=8...128 has a degree i polynomial.

-// All polynomials in the table are guaranteed distinct.

-// lint -save -e572 -e648 -e778   Excessive shift value, expression evaluates to 0

-static const struct CRC::Poly poly_list[] = {

- kDefPoly(UINT64_ZERO, B(30)+B(27)+B(26)+B(25)+B(23)+B(20)+B(17)+B(15)+B(14)+

-          B(12)+B(6)+B(5)+B(2)+B(0), 32),

- kDefPoly(UINT64_ZERO, B(31)+B(28)+B(27)+B(26)+B(24)+B(22)+B(19)+B(18)+B(16)+

-          B(13)+B(11)+B(10)+B(9)+B(4)+B(2)+B(0), 32),

- kDefPoly(UINT64_ZERO, B(60)+B(59)+B(58)+B(56)+B(55)+B(54)+B(51)+B(50)+B(49)+

-          B(48)+B(47)+B(45)+B(44)+B(42)+B(40)+B(39)+B(38)+B(36)+B(34)+B(33)+

-          B(32)+B(31)+B(30)+B(27)+B(25)+B(23)+B(22)+B(21)+B(20)+B(19)+

-          B(17)+B(16)+B(15)+B(8)+B(7)+B(6)+B(5)+B(0), 64),

- kDefPoly(UINT64_ZERO, B(63)+B(62)+B(60)+B(58)+B(57)+B(56)+B(54)+B(52)+B(46)+

-          B(45)+B(43)+B(40)+B(37)+B(36)+B(34)+B(33)+B(32)+B(31)+B(30)+B(29)+

-          B(28)+B(27)+B(26)+B(23)+B(19)+B(18)+B(15)+B(14)+B(13)+B(9)+B(8)+

-          B(0), 64),

- kDefPoly(B(95)+B(94)+B(91)+B(90)+B(89)+B(88)+B(87)+B(86)+B(79)+B(78)+

-          B(77)+B(76)+B(75)+B(74)+B(73)+B(69)+B(68)+B(66), B(63)+B(61)+

-          B(59)+B(57)+B(53)+B(51)+B(50)+B(47)+B(40)+B(39)+B(38)+B(36)+

-          B(35)+B(33)+B(29)+B(28)+B(27)+B(25)+B(24)+B(23)+B(21)+B(19)+

-          B(18)+B(17)+B(16)+B(13)+B(12)+B(10)+B(9)+B(7)+B(4)+B(2)+B(1)+

-          B(0), 96),

- kDefPoly(B(95)+B(92)+B(89)+B(88)+B(87)+B(85)+B(84)+B(82)+B(81)+B(80)+

-          B(79)+B(78)+B(76)+B(75)+B(70)+B(69)+B(66)+B(65), B(60)+B(56)+

-          B(55)+B(52)+B(51)+B(49)+B(48)+B(46)+B(44)+B(42)+B(41)+B(39)+

-          B(38)+B(37)+B(35)+B(33)+B(32)+B(30)+B(28)+B(27)+B(25)+B(22)+

-          B(19)+B(17)+B(14)+B(12)+B(10)+B(0), 96),

- kDefPoly(B(122)+B(121)+B(120)+B(119)+B(117)+B(116)+B(114)+B(113)+B(112)+

-          B(111)+B(109)+B(107)+B(104)+B(102)+B(100)+B(98)+B(96)+B(94)+

-          B(93)+B(92)+B(91)+B(90)+B(88)+B(87)+B(86)+B(84)+B(82)+B(80)+

-          B(75)+B(74)+B(73)+B(69), B(62)+B(61)+B(58)+B(52)+B(48)+B(47)+

-          B(46)+B(45)+B(42)+B(41)+B(38)+B(37)+B(35)+B(33)+B(32)+B(31)+

-          B(30)+B(28)+B(26)+B(24)+B(22)+B(21)+B(20)+B(19)+B(18)+B(17)+

-          B(10)+B(9)+B(8)+B(7)+B(5)+B(2)+B(1)+B(0), 128),

- kDefPoly(B(127)+B(126)+B(124)+B(121)+B(117)+B(116)+B(115)+B(113)+B(112)+

-          B(111)+B(108)+B(105)+B(104)+B(103)+B(100)+B(98)+B(96)+B(93)+

-          B(92)+B(90)+B(89)+B(88)+B(86)+B(85)+B(80)+B(77)+B(76)+B(72)+

-          B(70)+B(69)+B(68)+B(65)+B(64), B(62)+B(61)+B(59)+B(58)+B(56)+

-          B(53)+B(52)+B(51)+B(50)+B(48)+B(46)+B(39)+B(35)+B(34)+B(33)+

-          B(32)+B(30)+B(29)+B(28)+B(22)+B(21)+B(19)+B(18)+B(17)+B(14)+

-          B(10)+B(9)+B(7)+B(5)+B(4)+B(3)+B(2)+B(0), 128),

- kDefPoly(UINT64_ZERO, B(7)+B(6)+B(5)+B(4)+B(2)+B(0), 8),

- kDefPoly(UINT64_ZERO, B(8)+B(4)+B(3)+B(2)+B(1)+B(0), 9),

- kDefPoly(UINT64_ZERO, B(8)+B(6)+B(5)+B(3)+B(1)+B(0), 10),

- kDefPoly(UINT64_ZERO, B(10)+B(9)+B(7)+B(5)+B(1)+B(0), 11),

- kDefPoly(UINT64_ZERO, B(11)+B(10)+B(5)+B(2)+B(1)+B(0), 12),

- kDefPoly(UINT64_ZERO, B(12)+B(11)+B(10)+B(8)+B(5)+B(3)+B(2)+B(0), 13),

- kDefPoly(UINT64_ZERO, B(11)+B(10)+B(9)+B(8)+B(7)+B(5)+B(4)+B(2)+B(1)+

-          B(0), 14),

- kDefPoly(UINT64_ZERO, B(14)+B(12)+B(11)+B(10)+B(9)+B(5)+B(3)+B(2)+B(1)+

-          B(0), 15),

- kDefPoly(UINT64_ZERO, B(12)+B(11)+B(7)+B(6)+B(5)+B(4)+B(3)+B(0), 16),

- kDefPoly(UINT64_ZERO, B(16)+B(14)+B(11)+B(10)+B(8)+B(3)+B(1)+B(0), 17),

- kDefPoly(UINT64_ZERO, B(12)+B(11)+B(9)+B(8)+B(7)+B(4)+B(3)+B(0), 18),

- kDefPoly(UINT64_ZERO, B(12)+B(11)+B(8)+B(7)+B(6)+B(5)+B(2)+B(0), 19),

- kDefPoly(UINT64_ZERO, B(18)+B(15)+B(14)+B(12)+B(9)+B(6)+B(3)+B(0), 20),

- kDefPoly(UINT64_ZERO, B(20)+B(19)+B(14)+B(13)+B(12)+B(11)+B(8)+B(7)+B(6)+

-          B(5)+B(2)+B(0), 21),

- kDefPoly(UINT64_ZERO, B(21)+B(20)+B(18)+B(16)+B(15)+B(14)+B(12)+B(9)+B(7)+

-          B(2)+B(1)+B(0), 22),

- kDefPoly(UINT64_ZERO, B(22)+B(21)+B(17)+B(16)+B(15)+B(14)+B(12)+B(10)+B(7)+

-          B(4)+B(1)+B(0), 23),

- kDefPoly(UINT64_ZERO, B(23)+B(22)+B(21)+B(18)+B(17)+B(15)+B(14)+B(12)+B(4)+

-          B(0), 24),

- kDefPoly(UINT64_ZERO, B(24)+B(23)+B(22)+B(20)+B(18)+B(17)+B(14)+B(13)+B(9)+

-          B(0), 25),

- kDefPoly(UINT64_ZERO, B(25)+B(22)+B(21)+B(19)+B(17)+B(15)+B(14)+B(12)+B(11)+

-          B(10)+B(6)+B(4)+B(3)+B(0), 26),

- kDefPoly(UINT64_ZERO, B(26)+B(25)+B(19)+B(17)+B(16)+B(13)+B(5)+B(4)+B(1)+

-          B(0), 27),

- kDefPoly(UINT64_ZERO, B(23)+B(22)+B(21)+B(20)+B(19)+B(18)+B(13)+B(12)+B(10)+

-          B(9)+B(8)+B(6)+B(5)+B(3)+B(1)+B(0), 28),

- kDefPoly(UINT64_ZERO, B(27)+B(26)+B(25)+B(23)+B(22)+B(20)+B(19)+B(15)+B(14)+

-          B(11)+B(10)+B(8)+B(7)+B(6)+B(4)+B(0), 29),

- kDefPoly(UINT64_ZERO, B(29)+B(27)+B(25)+B(23)+B(20)+B(19)+B(18)+B(17)+B(16)+

-          B(14)+B(11)+B(10)+B(9)+B(7)+B(6)+B(5)+B(4)+B(0), 30),

- kDefPoly(UINT64_ZERO, B(30)+B(29)+B(28)+B(27)+B(25)+B(23)+B(22)+B(21)+B(20)+

-          B(19)+B(18)+B(16)+B(15)+B(10)+B(9)+B(8)+B(4)+B(3)+B(1)+B(0), 31),

- kDefPoly(UINT64_ZERO, B(31)+B(29)+B(28)+B(27)+B(21)+B(20)+B(15)+B(13)+B(10)+

-          B(9)+B(8)+B(7)+B(4)+B(3)+B(2)+B(0), 32),

- kDefPoly(UINT64_ZERO, B(32)+B(31)+B(30)+B(29)+B(27)+B(25)+B(24)+B(22)+B(21)+

-          B(19)+B(15)+B(10)+B(4)+B(3)+B(2)+B(0), 33),

- kDefPoly(UINT64_ZERO, B(30)+B(27)+B(26)+B(25)+B(24)+B(20)+B(19)+B(18)+B(16)+

-          B(15)+B(14)+B(12)+B(9)+B(8)+B(7)+B(5)+B(1)+B(0), 34),

- kDefPoly(UINT64_ZERO, B(34)+B(32)+B(28)+B(27)+B(26)+B(22)+B(21)+B(20)+B(19)+

-          B(14)+B(13)+B(12)+B(10)+B(6)+B(5)+B(4)+B(3)+B(0), 35),

- kDefPoly(UINT64_ZERO, B(35)+B(34)+B(33)+B(32)+B(31)+B(28)+B(26)+B(24)+B(22)+

-          B(21)+B(20)+B(19)+B(18)+B(14)+B(13)+B(12)+B(10)+B(9)+B(8)+B(6)+B(5)+

-          B(4)+B(3)+B(0), 36),

- kDefPoly(UINT64_ZERO, B(36)+B(35)+B(31)+B(30)+B(28)+B(26)+B(25)+B(23)+B(22)+

-          B(20)+B(19)+B(18)+B(16)+B(13)+B(12)+B(7)+B(6)+B(4)+B(3)+B(0), 37),

- kDefPoly(UINT64_ZERO, B(37)+B(34)+B(33)+B(32)+B(31)+B(30)+B(29)+B(28)+B(27)+

-          B(26)+B(25)+B(23)+B(18)+B(16)+B(15)+B(13)+B(12)+B(11)+B(10)+B(9)+

-          B(8)+B(7)+B(6)+B(2)+B(1)+B(0), 38),

- kDefPoly(UINT64_ZERO, B(38)+B(37)+B(33)+B(32)+B(31)+B(27)+B(25)+B(24)+B(21)+

-          B(20)+B(19)+B(18)+B(17)+B(15)+B(14)+B(8)+B(7)+B(6)+B(3)+B(2)+B(1)+

-          B(0), 39),

- kDefPoly(UINT64_ZERO, B(38)+B(37)+B(35)+B(34)+B(32)+B(31)+B(30)+B(27)+B(24)+

-          B(21)+B(20)+B(14)+B(13)+B(11)+B(8)+B(4)+B(2)+B(0), 40),

- kDefPoly(UINT64_ZERO, B(38)+B(36)+B(35)+B(34)+B(33)+B(31)+B(30)+B(29)+B(28)+

-          B(27)+B(23)+B(22)+B(20)+B(19)+B(18)+B(17)+B(15)+B(14)+B(11)+B(5)+

-          B(4)+B(0), 41),

- kDefPoly(UINT64_ZERO, B(41)+B(37)+B(36)+B(35)+B(32)+B(31)+B(30)+B(29)+B(28)+

-          B(25)+B(19)+B(18)+B(14)+B(13)+B(12)+B(7)+B(6)+B(4)+B(2)+B(0), 42),

- kDefPoly(UINT64_ZERO, B(42)+B(40)+B(38)+B(37)+B(36)+B(35)+B(34)+B(33)+B(31)+

-          B(29)+B(27)+B(26)+B(25)+B(23)+B(21)+B(20)+B(19)+B(15)+B(11)+B(10)+

-          B(9)+B(8)+B(6)+B(5)+B(3)+B(0), 43),

- kDefPoly(UINT64_ZERO, B(43)+B(42)+B(40)+B(39)+B(37)+B(35)+B(32)+B(30)+B(26)+

-          B(25)+B(24)+B(20)+B(16)+B(13)+B(12)+B(11)+B(8)+B(6)+B(5)+B(4)+B(1)+

-          B(0), 44),

- kDefPoly(UINT64_ZERO, B(43)+B(42)+B(41)+B(40)+B(39)+B(38)+B(33)+B(32)+B(27)+

-          B(26)+B(25)+B(23)+B(20)+B(18)+B(17)+B(16)+B(14)+B(11)+B(10)+B(9)+

-          B(6)+B(5)+B(1)+B(0), 45),

- kDefPoly(UINT64_ZERO, B(45)+B(43)+B(42)+B(41)+B(40)+B(39)+B(32)+B(31)+B(30)+

-          B(29)+B(27)+B(25)+B(23)+B(18)+B(17)+B(16)+B(10)+B(9)+B(7)+B(6)+B(4)+

-          B(3)+B(2)+B(0), 46),

- kDefPoly(UINT64_ZERO, B(45)+B(44)+B(43)+B(41)+B(40)+B(39)+B(38)+B(37)+B(32)+

-          B(30)+B(23)+B(21)+B(20)+B(17)+B(15)+B(13)+B(11)+B(10)+B(7)+B(5)+

-          B(3)+B(0), 47),

- kDefPoly(UINT64_ZERO, B(46)+B(42)+B(41)+B(39)+B(37)+B(36)+B(35)+B(29)+B(28)+

-          B(25)+B(24)+B(21)+B(20)+B(18)+B(17)+B(13)+B(12)+B(11)+B(10)+B(9)+

-          B(8)+B(5)+B(1)+B(0), 48),

- kDefPoly(UINT64_ZERO, B(48)+B(44)+B(41)+B(40)+B(39)+B(38)+B(37)+B(36)+B(35)+

-          B(34)+B(30)+B(28)+B(27)+B(24)+B(21)+B(18)+B(17)+B(8)+B(3)+B(0), 49),

- kDefPoly(UINT64_ZERO, B(48)+B(47)+B(46)+B(45)+B(44)+B(43)+B(42)+B(35)+B(33)+

-          B(29)+B(26)+B(24)+B(23)+B(21)+B(18)+B(16)+B(14)+B(13)+B(12)+B(9)+

-          B(7)+B(6)+B(5)+B(4)+B(3)+B(0), 50),

- kDefPoly(UINT64_ZERO, B(47)+B(46)+B(45)+B(44)+B(43)+B(40)+B(39)+B(38)+B(36)+

-          B(35)+B(30)+B(29)+B(28)+B(26)+B(25)+B(24)+B(23)+B(22)+B(20)+B(19)+

-          B(18)+B(17)+B(15)+B(11)+B(7)+B(4)+B(3)+B(0), 51),

- kDefPoly(UINT64_ZERO, B(51)+B(46)+B(43)+B(38)+B(37)+B(36)+B(34)+B(31)+B(27)+

-          B(26)+B(20)+B(17)+B(16)+B(15)+B(13)+B(12)+B(11)+B(9)+B(7)+B(5)+B(1)+

-          B(0), 52),

- kDefPoly(UINT64_ZERO, B(50)+B(49)+B(47)+B(46)+B(44)+B(42)+B(41)+B(37)+B(36)+

-          B(35)+B(33)+B(29)+B(28)+B(26)+B(24)+B(23)+B(21)+B(20)+B(14)+B(13)+

-          B(12)+B(11)+B(10)+B(9)+B(8)+B(6)+B(3)+B(2)+B(1)+B(0), 53),

- kDefPoly(UINT64_ZERO, B(52)+B(47)+B(46)+B(44)+B(43)+B(42)+B(40)+B(36)+B(32)+

-          B(31)+B(30)+B(29)+B(28)+B(26)+B(25)+B(24)+B(23)+B(22)+B(20)+B(19)+

-          B(17)+B(16)+B(15)+B(14)+B(13)+B(12)+B(11)+B(10)+B(7)+B(4)+B(2)+

-          B(0), 54),

- kDefPoly(UINT64_ZERO, B(53)+B(50)+B(48)+B(47)+B(37)+B(35)+B(31)+B(30)+B(25)+

-          B(22)+B(21)+B(20)+B(19)+B(18)+B(15)+B(10)+B(8)+B(6)+B(3)+B(2)+B(1)+

-          B(0), 55),

- kDefPoly(UINT64_ZERO, B(54)+B(52)+B(51)+B(49)+B(48)+B(42)+B(38)+B(37)+B(31)+

-          B(30)+B(27)+B(26)+B(24)+B(23)+B(22)+B(19)+B(16)+B(12)+B(11)+B(8)+

-          B(6)+B(4)+B(3)+B(0), 56),

- kDefPoly(UINT64_ZERO, B(55)+B(54)+B(51)+B(49)+B(48)+B(47)+B(46)+B(44)+B(43)+

-          B(42)+B(41)+B(40)+B(39)+B(38)+B(32)+B(29)+B(27)+B(26)+B(23)+B(21)+

-          B(20)+B(15)+B(12)+B(7)+B(6)+B(5)+B(3)+B(0), 57),

- kDefPoly(UINT64_ZERO, B(57)+B(54)+B(52)+B(47)+B(45)+B(42)+B(41)+B(40)+B(39)+

-          B(36)+B(34)+B(33)+B(31)+B(28)+B(26)+B(21)+B(20)+B(18)+B(17)+B(16)+

-          B(13)+B(11)+B(8)+B(7)+B(4)+B(2)+B(1)+B(0), 58),

- kDefPoly(UINT64_ZERO, B(58)+B(56)+B(54)+B(49)+B(47)+B(46)+B(43)+B(40)+B(38)+

-          B(36)+B(35)+B(33)+B(32)+B(31)+B(30)+B(27)+B(24)+B(22)+B(21)+B(19)+

-          B(17)+B(16)+B(11)+B(10)+B(9)+B(8)+B(7)+B(4)+B(3)+B(2)+B(1)+B(0),

-          59),

- kDefPoly(UINT64_ZERO, B(56)+B(54)+B(51)+B(46)+B(43)+B(42)+B(40)+B(39)+B(37)+

-          B(35)+B(34)+B(33)+B(32)+B(31)+B(30)+B(29)+B(27)+B(25)+B(22)+B(21)+

-          B(20)+B(19)+B(17)+B(16)+B(15)+B(14)+B(13)+B(12)+B(9)+B(7)+B(4)+

-          B(3)+B(1)+B(0), 60),

- kDefPoly(UINT64_ZERO, B(59)+B(58)+B(57)+B(56)+B(54)+B(53)+B(50)+B(49)+B(47)+

-          B(44)+B(42)+B(41)+B(40)+B(37)+B(35)+B(34)+B(32)+B(30)+B(29)+B(27)+

-          B(26)+B(22)+B(21)+B(20)+B(17)+B(14)+B(13)+B(12)+B(8)+B(5)+B(4)+

-          B(0), 61),

- kDefPoly(UINT64_ZERO, B(61)+B(59)+B(57)+B(55)+B(54)+B(53)+B(52)+B(51)+B(50)+

-          B(49)+B(48)+B(45)+B(44)+B(40)+B(37)+B(35)+B(32)+B(31)+B(29)+B(25)+

-          B(24)+B(23)+B(20)+B(17)+B(16)+B(15)+B(13)+B(12)+B(11)+B(10)+B(6)+

-          B(5)+B(2)+B(0), 62),

- kDefPoly(UINT64_ZERO, B(62)+B(57)+B(56)+B(53)+B(52)+B(51)+B(50)+B(46)+B(41)+

-          B(38)+B(35)+B(34)+B(33)+B(31)+B(27)+B(25)+B(23)+B(21)+B(19)+B(18)+

-          B(17)+B(16)+B(13)+B(11)+B(7)+B(5)+B(1)+B(0), 63),

- kDefPoly(UINT64_ZERO, B(62)+B(61)+B(60)+B(57)+B(55)+B(54)+B(53)+B(49)+B(48)+

-          B(46)+B(44)+B(42)+B(40)+B(39)+B(37)+B(36)+B(28)+B(27)+B(25)+B(23)+

-          B(22)+B(21)+B(17)+B(15)+B(13)+B(7)+B(6)+B(4)+B(2)+B(0), 64),

- kDefPoly(UINT64_ZERO, B(63)+B(62)+B(59)+B(57)+B(54)+B(53)+B(51)+B(48)+

-          B(47)+B(46)+B(45)+B(44)+B(41)+B(40)+B(38)+B(36)+B(35)+B(28)+

-          B(25)+B(24)+B(21)+B(20)+B(18)+B(16)+B(15)+B(13)+B(11)+B(8)+B(7)+

-          B(3)+B(1)+B(0), 65),

- kDefPoly(UINT64_ZERO, B(63)+B(58)+B(57)+B(56)+B(52)+B(51)+B(50)+B(44)+

-          B(41)+B(40)+B(36)+B(34)+B(32)+B(31)+B(27)+B(25)+B(23)+B(21)+

-          B(20)+B(19)+B(18)+B(17)+B(15)+B(14)+B(12)+B(11)+B(10)+B(8)+B(5)+

-          B(4)+B(3)+B(0), 66),

- kDefPoly(B(66), B(62)+B(60)+B(59)+B(58)+B(57)+B(56)+B(55)+B(54)+B(52)+

-          B(50)+B(47)+B(46)+B(45)+B(43)+B(42)+B(41)+B(38)+B(37)+B(36)+

-          B(33)+B(32)+B(31)+B(30)+B(28)+B(27)+B(26)+B(24)+B(21)+B(18)+

-          B(17)+B(14)+B(13)+B(12)+B(11)+B(10)+B(7)+B(4)+B(3)+B(0), 67),

- kDefPoly(B(67)+B(66), B(63)+B(61)+B(57)+B(55)+B(51)+B(47)+B(45)+B(43)+

-          B(42)+B(41)+B(40)+B(39)+B(32)+B(31)+B(30)+B(28)+B(27)+B(25)+

-          B(19)+B(18)+B(17)+B(15)+B(11)+B(9)+B(8)+B(7)+B(6)+B(5)+B(4)+B(3)+

-          B(1)+B(0), 68),

- kDefPoly(B(68), B(60)+B(57)+B(55)+B(54)+B(52)+B(50)+B(49)+B(48)+B(44)+

-          B(40)+B(38)+B(37)+B(33)+B(31)+B(28)+B(25)+B(22)+B(21)+B(20)+

-          B(19)+B(18)+B(17)+B(13)+B(12)+B(9)+B(8)+B(6)+B(5)+B(4)+B(1)+

-          B(0), 69),

- kDefPoly(B(69)+B(68)+B(67)+B(66), B(63)+B(62)+B(61)+B(59)+B(51)+B(49)+

-          B(48)+B(46)+B(45)+B(42)+B(40)+B(38)+B(36)+B(35)+B(33)+B(32)+

-          B(30)+B(29)+B(27)+B(23)+B(22)+B(21)+B(16)+B(12)+B(5)+B(4)+B(1)+

-          B(0), 70),

- kDefPoly(B(70)+B(69)+B(68)+B(64), B(63)+B(62)+B(61)+B(60)+B(59)+B(57)+

-          B(56)+B(55)+B(54)+B(53)+B(51)+B(50)+B(47)+B(44)+B(43)+B(41)+

-          B(39)+B(37)+B(36)+B(33)+B(32)+B(26)+B(25)+B(24)+B(23)+B(21)+

-          B(20)+B(19)+B(17)+B(12)+B(11)+B(10)+B(8)+B(6)+B(5)+B(4)+B(2)+

-          B(0), 71),

- kDefPoly(B(71)+B(69)+B(68)+B(65)+B(64), B(62)+B(61)+B(59)+B(58)+B(55)+

-          B(53)+B(51)+B(49)+B(48)+B(47)+B(43)+B(40)+B(38)+B(37)+B(36)+

-          B(35)+B(33)+B(32)+B(31)+B(30)+B(29)+B(26)+B(24)+B(19)+B(18)+

-          B(15)+B(13)+B(9)+B(7)+B(6)+B(3)+B(1)+B(0), 72),

- kDefPoly(B(71)+B(70)+B(69)+B(67)+B(65), B(63)+B(62)+B(61)+B(58)+B(57)+

-          B(56)+B(55)+B(52)+B(51)+B(50)+B(49)+B(46)+B(45)+B(44)+B(43)+

-          B(41)+B(37)+B(36)+B(34)+B(33)+B(27)+B(26)+B(25)+B(21)+B(19)+

-          B(18)+B(16)+B(15)+B(14)+B(13)+B(9)+B(8)+B(6)+B(5)+B(2)+B(1)+

-          B(0), 73),

- kDefPoly(B(73)+B(71)+B(70)+B(65)+B(64), B(62)+B(60)+B(55)+B(54)+B(52)+

-          B(50)+B(48)+B(47)+B(46)+B(44)+B(41)+B(40)+B(31)+B(29)+B(28)+

-          B(27)+B(26)+B(24)+B(23)+B(22)+B(20)+B(16)+B(12)+B(9)+B(6)+B(5)+

-          B(4)+B(2)+B(0), 74),

- kDefPoly(B(74)+B(73)+B(72)+B(67)+B(64), B(63)+B(61)+B(60)+B(58)+B(57)+

-          B(56)+B(54)+B(52)+B(51)+B(50)+B(44)+B(43)+B(42)+B(41)+B(40)+

-          B(39)+B(38)+B(36)+B(35)+B(33)+B(32)+B(31)+B(29)+B(28)+B(26)+

-          B(23)+B(21)+B(19)+B(18)+B(16)+B(15)+B(13)+B(12)+B(11)+B(7)+B(6)+

-          B(5)+B(4)+B(3)+B(2)+B(0), 75),

- kDefPoly(B(75)+B(74)+B(71)+B(70)+B(66), B(63)+B(61)+B(59)+B(57)+B(53)+

-          B(50)+B(49)+B(48)+B(44)+B(43)+B(42)+B(37)+B(33)+B(30)+B(27)+

-          B(24)+B(23)+B(20)+B(18)+B(15)+B(12)+B(11)+B(9)+B(7)+B(6)+B(4)+

-          B(3)+B(2)+B(0), 76),

- kDefPoly(B(73)+B(71)+B(70)+B(68)+B(67)+B(66)+B(65), B(63)+B(60)+B(59)+

-          B(58)+B(57)+B(54)+B(49)+B(47)+B(46)+B(45)+B(43)+B(41)+B(38)+

-          B(34)+B(33)+B(31)+B(30)+B(29)+B(27)+B(25)+B(24)+B(21)+B(20)+

-          B(19)+B(16)+B(15)+B(14)+B(13)+B(10)+B(8)+B(6)+B(5)+B(4)+B(2)+

-          B(0), 77),

- kDefPoly(B(77)+B(76)+B(75)+B(74)+B(70)+B(66)+B(65)+B(64), B(63)+B(62)+

-          B(60)+B(58)+B(57)+B(55)+B(52)+B(51)+B(44)+B(41)+B(39)+B(38)+

-          B(35)+B(31)+B(30)+B(29)+B(26)+B(22)+B(21)+B(20)+B(19)+B(15)+

-          B(13)+B(11)+B(6)+B(4)+B(1)+B(0), 78),

- kDefPoly(B(78)+B(76)+B(75)+B(71)+B(68)+B(67)+B(65), B(63)+B(61)+B(60)+

-          B(55)+B(54)+B(51)+B(50)+B(48)+B(44)+B(42)+B(41)+B(40)+B(38)+

-          B(35)+B(34)+B(32)+B(28)+B(26)+B(23)+B(22)+B(19)+B(15)+B(13)+

-          B(12)+B(8)+B(7)+B(5)+B(2)+B(0), 79),

- kDefPoly(B(77)+B(76)+B(75)+B(73)+B(70)+B(66), B(63)+B(61)+B(60)+B(59)+

-          B(56)+B(54)+B(53)+B(52)+B(50)+B(44)+B(43)+B(40)+B(39)+B(38)+

-          B(35)+B(34)+B(33)+B(29)+B(28)+B(27)+B(26)+B(25)+B(24)+B(23)+

-          B(22)+B(21)+B(20)+B(18)+B(16)+B(13)+B(12)+B(11)+B(10)+B(8)+B(7)+

-          B(6)+B(3)+B(2)+B(1)+B(0), 80),

- kDefPoly(B(78)+B(77)+B(76)+B(75)+B(73)+B(71)+B(67)+B(66)+B(65)+

-          B(64), B(61)+B(54)+B(53)+B(52)+B(49)+B(47)+B(44)+B(41)+B(40)+

-          B(35)+B(33)+B(31)+B(30)+B(28)+B(27)+B(26)+B(25)+B(22)+B(21)+

-          B(20)+B(16)+B(15)+B(13)+B(12)+B(11)+B(0), 81),

- kDefPoly(B(81)+B(80)+B(79)+B(77)+B(76)+B(74)+B(73)+B(72)+B(68)+B(67)+

-          B(66)+B(64), B(62)+B(51)+B(50)+B(49)+B(47)+B(46)+B(45)+B(43)+

-          B(41)+B(38)+B(37)+B(34)+B(32)+B(30)+B(27)+B(26)+B(25)+B(24)+

-          B(23)+B(22)+B(20)+B(19)+B(16)+B(15)+B(13)+B(12)+B(9)+B(7)+B(5)+

-          B(4)+B(1)+B(0), 82),

- kDefPoly(B(82)+B(81)+B(79)+B(78)+B(77)+B(75)+B(72)+B(71)+B(69)+B(68)+

-          B(67)+B(66)+B(65)+B(64), B(60)+B(58)+B(57)+B(56)+B(53)+B(52)+

-          B(51)+B(49)+B(48)+B(45)+B(43)+B(41)+B(40)+B(39)+B(38)+B(37)+

-          B(36)+B(35)+B(33)+B(26)+B(24)+B(21)+B(19)+B(16)+B(13)+B(12)+

-          B(11)+B(9)+B(7)+B(5)+B(4)+B(3)+B(1)+B(0), 83),

- kDefPoly(B(79)+B(77)+B(73)+B(72)+B(71)+B(66)+B(64), B(62)+B(61)+B(59)+

-          B(58)+B(57)+B(56)+B(53)+B(52)+B(51)+B(48)+B(47)+B(46)+B(45)+

-          B(43)+B(42)+B(41)+B(38)+B(37)+B(35)+B(33)+B(32)+B(29)+B(24)+

-          B(22)+B(17)+B(16)+B(15)+B(13)+B(11)+B(10)+B(9)+B(7)+B(6)+B(5)+

-          B(0), 84),

- kDefPoly(B(83)+B(78)+B(76)+B(73)+B(70)+B(69)+B(68)+B(67)+B(66)+

-          B(64), B(62)+B(61)+B(60)+B(59)+B(54)+B(51)+B(50)+B(48)+B(47)+

-          B(42)+B(41)+B(40)+B(38)+B(37)+B(36)+B(34)+B(31)+B(30)+B(28)+

-          B(27)+B(26)+B(24)+B(22)+B(21)+B(20)+B(19)+B(18)+B(16)+B(15)+

-          B(14)+B(13)+B(12)+B(10)+B(6)+B(4)+B(0), 85),

- kDefPoly(B(84)+B(77)+B(76)+B(75)+B(71)+B(70)+B(69)+B(67)+B(65), B(63)+

-          B(62)+B(59)+B(58)+B(57)+B(55)+B(53)+B(52)+B(51)+B(48)+B(47)+

-          B(45)+B(43)+B(40)+B(38)+B(36)+B(34)+B(33)+B(31)+B(27)+B(25)+

-          B(24)+B(23)+B(22)+B(19)+B(15)+B(13)+B(12)+B(11)+B(8)+B(6)+B(4)+

-          B(0), 86),

- kDefPoly(B(85)+B(84)+B(83)+B(81)+B(80)+B(78)+B(73)+B(72)+B(70)+B(68)+

-          B(67)+B(64), B(61)+B(60)+B(58)+B(57)+B(55)+B(52)+B(50)+B(49)+

-          B(47)+B(44)+B(37)+B(36)+B(35)+B(34)+B(32)+B(31)+B(30)+B(25)+

-          B(24)+B(23)+B(20)+B(13)+B(12)+B(11)+B(10)+B(9)+B(7)+B(6)+B(4)+

-          B(3)+B(2)+B(0), 87),

- kDefPoly(B(86)+B(85)+B(84)+B(83)+B(82)+B(80)+B(77)+B(74)+B(70)+B(69)+

-          B(65), B(63)+B(60)+B(59)+B(57)+B(56)+B(55)+B(53)+B(50)+B(49)+

-          B(48)+B(45)+B(42)+B(41)+B(40)+B(39)+B(38)+B(37)+B(36)+B(25)+

-          B(21)+B(19)+B(13)+B(11)+B(8)+B(5)+B(4)+B(2)+B(1)+B(0), 88),

- kDefPoly(B(86)+B(85)+B(83)+B(82)+B(81)+B(78)+B(77)+B(74)+B(73)+B(72)+

-          B(70)+B(69)+B(68)+B(65)+B(64), B(59)+B(57)+B(55)+B(54)+B(51)+

-          B(50)+B(46)+B(45)+B(44)+B(43)+B(42)+B(40)+B(38)+B(37)+B(33)+

-          B(31)+B(30)+B(29)+B(28)+B(27)+B(23)+B(22)+B(21)+B(20)+B(18)+

-          B(17)+B(16)+B(15)+B(10)+B(9)+B(3)+B(1)+B(0), 89),

- kDefPoly(B(86)+B(83)+B(82)+B(80)+B(79)+B(73)+B(70)+B(69)+B(67)+

-          B(64), B(63)+B(62)+B(61)+B(57)+B(56)+B(54)+B(51)+B(49)+B(47)+

-          B(46)+B(45)+B(40)+B(39)+B(37)+B(35)+B(33)+B(32)+B(29)+B(28)+

-          B(27)+B(25)+B(24)+B(23)+B(22)+B(21)+B(20)+B(19)+B(18)+B(17)+

-          B(15)+B(9)+B(8)+B(7)+B(3)+B(2)+B(0), 90),

- kDefPoly(B(90)+B(89)+B(84)+B(81)+B(80)+B(78)+B(74)+B(73)+B(71)+B(68)+

-          B(64), B(60)+B(59)+B(58)+B(57)+B(55)+B(54)+B(52)+B(50)+B(49)+

-          B(47)+B(45)+B(42)+B(41)+B(39)+B(38)+B(36)+B(32)+B(28)+B(25)+

-          B(21)+B(20)+B(19)+B(15)+B(12)+B(11)+B(9)+B(8)+B(3)+

-          B(0), 91),

- kDefPoly(B(91)+B(89)+B(88)+B(87)+B(86)+B(85)+B(84)+B(83)+B(80)+B(78)+

-          B(76)+B(72)+B(70)+B(68), B(63)+B(62)+B(61)+B(59)+B(57)+B(56)+

-          B(52)+B(51)+B(50)+B(49)+B(43)+B(40)+B(39)+B(37)+B(36)+B(35)+

-          B(34)+B(33)+B(32)+B(26)+B(25)+B(24)+B(23)+B(22)+B(18)+B(15)+

-          B(12)+B(11)+B(9)+B(7)+B(6)+B(3)+B(1)+B(0), 92),

- kDefPoly(B(86)+B(85)+B(83)+B(82)+B(79)+B(78)+B(77)+B(75)+B(74)+B(73)+

-          B(66)+B(64), B(59)+B(57)+B(56)+B(55)+B(54)+B(52)+B(51)+B(40)+

-          B(38)+B(36)+B(34)+B(33)+B(28)+B(27)+B(26)+B(25)+B(23)+B(22)+

-          B(21)+B(20)+B(19)+B(18)+B(16)+B(15)+B(14)+B(13)+B(12)+B(11)+B(8)+

-          B(7)+B(6)+B(5)+B(4)+B(0), 93),

- kDefPoly(B(93)+B(92)+B(91)+B(89)+B(88)+B(87)+B(86)+B(81)+B(80)+B(75)+

-          B(66)+B(64), B(62)+B(61)+B(60)+B(59)+B(58)+B(57)+B(56)+B(54)+

-          B(48)+B(47)+B(46)+B(45)+B(44)+B(42)+B(41)+B(38)+B(37)+B(36)+

-          B(34)+B(33)+B(31)+B(30)+B(27)+B(26)+B(25)+B(22)+B(13)+B(12)+

-          B(11)+B(10)+B(8)+B(7)+B(4)+B(0), 94),

- kDefPoly(B(94)+B(88)+B(87)+B(82)+B(79)+B(78)+B(76)+B(73)+B(65)+

-          B(64), B(62)+B(61)+B(60)+B(59)+B(58)+B(57)+B(53)+B(51)+B(50)+

-          B(49)+B(48)+B(47)+B(46)+B(44)+B(40)+B(36)+B(34)+B(33)+B(30)+

-          B(28)+B(27)+B(25)+B(22)+B(19)+B(18)+B(17)+B(16)+B(14)+B(7)+B(5)+

-          B(3)+B(2)+B(1)+B(0), 95),

- kDefPoly(B(92)+B(89)+B(88)+B(86)+B(83)+B(79)+B(78)+B(76)+B(75)+B(74)+

-          B(72)+B(70)+B(67)+B(66), B(63)+B(60)+B(57)+B(55)+B(53)+B(51)+

-          B(47)+B(46)+B(44)+B(43)+B(42)+B(39)+B(38)+B(36)+B(34)+B(32)+

-          B(31)+B(30)+B(27)+B(26)+B(25)+B(22)+B(21)+B(19)+B(17)+B(13)+

-          B(11)+B(10)+B(9)+B(8)+B(7)+B(4)+B(1)+B(0), 96),

- kDefPoly(B(96)+B(94)+B(93)+B(91)+B(89)+B(87)+B(85)+B(83)+B(81)+B(78)+

-          B(76)+B(74)+B(73)+B(68)+B(67)+B(64), B(62)+B(61)+B(57)+B(55)+

-          B(54)+B(53)+B(49)+B(47)+B(41)+B(38)+B(35)+B(33)+B(28)+B(27)+

-          B(24)+B(23)+B(21)+B(19)+B(18)+B(17)+B(15)+B(13)+B(12)+B(11)+B(8)+

-          B(6)+B(4)+B(3)+B(1)+B(0), 97),

- kDefPoly(B(97)+B(93)+B(92)+B(91)+B(90)+B(87)+B(83)+B(82)+B(80)+B(77)+

-          B(76)+B(75)+B(74)+B(73)+B(72)+B(70)+B(69)+B(68)+B(66)+B(65)+

-          B(64), B(63)+B(62)+B(61)+B(60)+B(59)+B(57)+B(55)+B(53)+B(50)+

-          B(49)+B(48)+B(45)+B(44)+B(43)+B(42)+B(40)+B(38)+B(36)+B(35)+

-          B(34)+B(28)+B(27)+B(24)+B(22)+B(21)+B(18)+B(17)+B(16)+B(15)+

-          B(14)+B(12)+B(11)+B(9)+B(8)+B(2)+B(1)+B(0), 98),

- kDefPoly(B(96)+B(94)+B(92)+B(86)+B(85)+B(84)+B(78)+B(77)+B(76)+B(75)+

-          B(73)+B(71)+B(69)+B(68)+B(65), B(61)+B(59)+B(57)+B(56)+B(54)+

-          B(50)+B(47)+B(46)+B(44)+B(41)+B(38)+B(36)+B(35)+B(34)+B(33)+

-          B(32)+B(29)+B(27)+B(26)+B(25)+B(23)+B(22)+B(21)+B(19)+B(17)+

-          B(16)+B(11)+B(9)+B(7)+B(6)+B(3)+B(2)+B(0), 99),

- kDefPoly(B(99)+B(96)+B(95)+B(93)+B(92)+B(88)+B(87)+B(83)+B(78)+B(77)+

-          B(76)+B(75)+B(74)+B(73)+B(70)+B(66)+B(64), B(63)+B(62)+B(60)+

-          B(59)+B(57)+B(56)+B(53)+B(50)+B(47)+B(41)+B(39)+B(38)+B(37)+

-          B(34)+B(25)+B(23)+B(21)+B(20)+B(19)+B(18)+B(17)+B(16)+B(13)+B(9)+

-          B(8)+B(6)+B(5)+B(1)+B(0), 100),

- kDefPoly(B(100)+B(98)+B(97)+B(95)+B(93)+B(92)+B(91)+B(89)+B(87)+B(85)+

-          B(84)+B(82)+B(81)+B(80)+B(79)+B(76)+B(68)+B(66)+B(65), B(63)+

-          B(62)+B(59)+B(57)+B(52)+B(51)+B(50)+B(47)+B(46)+B(45)+B(42)+

-          B(41)+B(40)+B(39)+B(38)+B(37)+B(36)+B(34)+B(32)+B(31)+B(30)+

-          B(24)+B(22)+B(21)+B(20)+B(18)+B(17)+B(16)+B(14)+B(12)+B(11)+

-          B(10)+B(8)+B(7)+B(5)+B(4)+B(2)+B(1)+B(0), 101),

- kDefPoly(B(101)+B(99)+B(97)+B(96)+B(92)+B(89)+B(88)+B(87)+B(86)+B(84)+

-          B(82)+B(81)+B(80)+B(78)+B(77)+B(76)+B(75)+B(74)+B(73)+

-          B(69), B(60)+B(59)+B(57)+B(56)+B(55)+B(54)+B(53)+B(51)+B(50)+

-          B(49)+B(47)+B(45)+B(43)+B(41)+B(35)+B(34)+B(32)+B(31)+B(29)+

-          B(27)+B(26)+B(25)+B(24)+B(21)+B(13)+B(12)+B(9)+B(8)+B(6)+B(5)+

-          B(3)+B(0), 102),

- kDefPoly(B(101)+B(98)+B(97)+B(96)+B(94)+B(93)+B(92)+B(90)+B(89)+B(88)+

-          B(87)+B(85)+B(83)+B(81)+B(80)+B(79)+B(76)+B(75)+B(71)+B(70)+

-          B(69)+B(66), B(63)+B(62)+B(60)+B(59)+B(58)+B(56)+B(54)+B(53)+

-          B(48)+B(45)+B(43)+B(42)+B(41)+B(37)+B(36)+B(32)+B(31)+B(30)+

-          B(27)+B(25)+B(23)+B(22)+B(19)+B(16)+B(15)+B(11)+B(9)+B(5)+B(3)+

-          B(0), 103),

- kDefPoly(B(98)+B(97)+B(95)+B(94)+B(91)+B(89)+B(88)+B(86)+B(85)+B(84)+

-          B(81)+B(79)+B(78)+B(76)+B(74)+B(73)+B(70)+B(69)+B(68)+B(67)+

-          B(66)+B(64), B(59)+B(53)+B(52)+B(51)+B(48)+B(46)+B(45)+B(43)+

-          B(37)+B(34)+B(33)+B(31)+B(30)+B(28)+B(25)+B(22)+B(21)+B(20)+

-          B(19)+B(14)+B(10)+B(8)+B(4)+B(2)+B(1)+B(0), 104),

- kDefPoly(B(103)+B(100)+B(99)+B(98)+B(94)+B(90)+B(89)+B(86)+B(84)+B(82)+

-          B(79)+B(76)+B(74)+B(73)+B(72)+B(71)+B(70)+B(69)+B(67)+

-          B(66), B(63)+B(62)+B(59)+B(58)+B(57)+B(55)+B(51)+B(49)+B(48)+

-          B(47)+B(46)+B(43)+B(42)+B(38)+B(36)+B(34)+B(33)+B(31)+B(30)+

-          B(29)+B(28)+B(27)+B(24)+B(21)+B(20)+B(18)+B(17)+B(16)+B(14)+

-          B(13)+B(11)+B(9)+B(7)+B(6)+B(5)+B(0), 105),

- kDefPoly(B(105)+B(104)+B(103)+B(102)+B(100)+B(98)+B(94)+B(93)+B(92)+B(91)+

-          B(90)+B(89)+B(87)+B(86)+B(85)+B(83)+B(82)+B(81)+B(79)+B(77)+

-          B(69)+B(68)+B(67)+B(64), B(61)+B(60)+B(59)+B(58)+B(56)+B(55)+

-          B(53)+B(50)+B(48)+B(44)+B(40)+B(38)+B(37)+B(36)+B(35)+B(34)+

-          B(33)+B(30)+B(29)+B(26)+B(22)+B(20)+B(13)+B(10)+B(8)+B(7)+B(5)+

-          B(0), 106),

- kDefPoly(B(105)+B(101)+B(100)+B(98)+B(97)+B(96)+B(93)+B(92)+B(91)+B(90)+

-          B(87)+B(86)+B(81)+B(79)+B(77)+B(75)+B(74)+B(72)+B(68)+B(67)+

-          B(64), B(63)+B(62)+B(61)+B(60)+B(59)+B(58)+B(54)+B(53)+B(52)+

-          B(50)+B(48)+B(47)+B(45)+B(42)+B(41)+B(38)+B(32)+B(29)+B(27)+

-          B(26)+B(24)+B(21)+B(19)+B(18)+B(16)+B(15)+B(14)+B(13)+B(12)+

-          B(10)+B(7)+B(6)+B(4)+B(1)+B(0), 107),

- kDefPoly(B(106)+B(105)+B(102)+B(100)+B(97)+B(95)+B(90)+B(89)+B(88)+B(86)+

-          B(83)+B(82)+B(81)+B(79)+B(78)+B(75)+B(72)+B(66)+B(64), B(63)+

-          B(62)+B(59)+B(58)+B(56)+B(54)+B(52)+B(51)+B(50)+B(48)+B(46)+

-          B(45)+B(44)+B(42)+B(40)+B(37)+B(36)+B(35)+B(33)+B(29)+B(27)+

-          B(22)+B(19)+B(17)+B(14)+B(12)+B(11)+B(10)+B(9)+B(8)+B(7)+B(6)+

-          B(5)+B(3)+B(0), 108),

- kDefPoly(B(108)+B(102)+B(101)+B(100)+B(99)+B(98)+B(96)+B(95)+B(94)+B(90)+

-          B(89)+B(88)+B(87)+B(84)+B(83)+B(81)+B(80)+B(77)+B(76)+B(75)+

-          B(71)+B(67)+B(65), B(63)+B(61)+B(60)+B(54)+B(50)+B(49)+B(48)+

-          B(43)+B(40)+B(39)+B(38)+B(36)+B(34)+B(29)+B(28)+B(27)+B(22)+

-          B(21)+B(19)+B(16)+B(14)+B(13)+B(12)+B(10)+B(9)+B(7)+B(6)+B(5)+

-          B(3)+B(2)+B(0), 109),

- kDefPoly(B(109)+B(108)+B(107)+B(102)+B(101)+B(98)+B(97)+B(96)+B(94)+B(92)+

-          B(91)+B(90)+B(88)+B(87)+B(85)+B(84)+B(83)+B(82)+B(81)+B(80)+

-          B(79)+B(78)+B(74)+B(73)+B(71)+B(70)+B(69)+B(66)+B(64), B(61)+

-          B(58)+B(57)+B(56)+B(50)+B(49)+B(46)+B(44)+B(43)+B(41)+B(36)+

-          B(35)+B(34)+B(30)+B(29)+B(26)+B(25)+B(24)+B(22)+B(21)+B(17)+

-          B(13)+B(11)+B(9)+B(4)+B(1)+B(0), 110),

- kDefPoly(B(110)+B(109)+B(105)+B(98)+B(97)+B(95)+B(94)+B(93)+B(92)+B(90)+

-          B(88)+B(84)+B(83)+B(82)+B(80)+B(77)+B(75)+B(72)+B(71)+B(70)+

-          B(69)+B(66), B(63)+B(61)+B(60)+B(59)+B(57)+B(56)+B(55)+B(52)+

-          B(51)+B(50)+B(49)+B(47)+B(43)+B(40)+B(36)+B(35)+B(34)+B(33)+

-          B(31)+B(27)+B(26)+B(21)+B(20)+B(19)+B(17)+B(16)+B(12)+B(8)+B(6)+

-          B(4)+B(3)+B(2)+B(1)+B(0), 111),

- kDefPoly(B(109)+B(107)+B(106)+B(104)+B(100)+B(98)+B(96)+B(95)+B(94)+B(92)+

-          B(91)+B(90)+B(89)+B(88)+B(86)+B(84)+B(81)+B(79)+B(78)+B(77)+

-          B(75)+B(73)+B(71)+B(70)+B(69)+B(67)+B(64), B(63)+B(62)+B(61)+

-          B(60)+B(58)+B(56)+B(54)+B(52)+B(51)+B(49)+B(48)+B(45)+B(44)+

-          B(39)+B(38)+B(37)+B(36)+B(35)+B(34)+B(32)+B(30)+B(26)+B(25)+

-          B(24)+B(23)+B(22)+B(21)+B(19)+B(16)+B(15)+B(11)+B(10)+B(9)+B(8)+

-          B(3)+B(1)+B(0), 112),

- kDefPoly(B(111)+B(107)+B(102)+B(100)+B(99)+B(98)+B(97)+B(96)+B(95)+B(94)+

-          B(93)+B(92)+B(87)+B(86)+B(82)+B(81)+B(80)+B(79)+B(77)+B(76)+

-          B(75)+B(72)+B(69)+B(64), B(61)+B(58)+B(56)+B(54)+B(53)+B(52)+

-          B(51)+B(49)+B(46)+B(43)+B(40)+B(39)+B(37)+B(36)+B(35)+B(34)+

-          B(33)+B(31)+B(29)+B(24)+B(22)+B(21)+B(20)+B(15)+B(14)+B(12)+

-          B(10)+B(6)+B(1)+B(0), 113),

- kDefPoly(B(112)+B(111)+B(110)+B(104)+B(102)+B(101)+B(100)+B(92)+B(89)+

-          B(87)+B(83)+B(82)+B(80)+B(79)+B(75)+B(74)+B(73)+B(72)+B(71)+

-          B(70)+B(68)+B(67)+B(65), B(60)+B(59)+B(57)+B(56)+B(55)+B(52)+

-          B(50)+B(47)+B(44)+B(41)+B(36)+B(35)+B(30)+B(29)+B(26)+B(25)+

-          B(24)+B(21)+B(18)+B(17)+B(16)+B(14)+B(12)+B(10)+B(7)+B(6)+

-          B(0), 114),

- kDefPoly(B(114)+B(112)+B(111)+B(110)+B(108)+B(107)+B(103)+B(102)+B(98)+

-          B(97)+B(96)+B(90)+B(88)+B(87)+B(86)+B(83)+B(82)+B(80)+B(79)+

-          B(77)+B(75)+B(70)+B(66)+B(65)+B(64), B(61)+B(60)+B(59)+B(58)+

-          B(57)+B(53)+B(52)+B(51)+B(50)+B(47)+B(45)+B(43)+B(39)+B(38)+

-          B(33)+B(32)+B(31)+B(29)+B(27)+B(21)+B(17)+B(14)+B(12)+B(10)+B(7)+

-          B(4)+B(2)+B(1)+B(0), 115),

- kDefPoly(B(113)+B(110)+B(108)+B(106)+B(105)+B(102)+B(101)+B(100)+B(98)+

-          B(96)+B(92)+B(89)+B(87)+B(86)+B(84)+B(81)+B(79)+B(78)+B(76)+

-          B(75)+B(73)+B(72)+B(71)+B(70)+B(67)+B(64), B(63)+B(62)+B(61)+

-          B(52)+B(47)+B(45)+B(44)+B(42)+B(40)+B(39)+B(35)+B(34)+B(33)+

-          B(31)+B(29)+B(25)+B(18)+B(15)+B(14)+B(10)+B(8)+B(6)+B(1)+

-          B(0), 116),

- kDefPoly(B(113)+B(111)+B(110)+B(109)+B(107)+B(106)+B(103)+B(102)+B(100)+

-          B(96)+B(95)+B(94)+B(91)+B(90)+B(89)+B(86)+B(82)+B(81)+B(78)+

-          B(77)+B(76)+B(75)+B(74)+B(73)+B(70)+B(67)+B(66), B(63)+B(61)+

-          B(59)+B(57)+B(56)+B(55)+B(53)+B(52)+B(51)+B(50)+B(47)+B(45)+

-          B(42)+B(40)+B(37)+B(35)+B(32)+B(30)+B(29)+B(25)+B(22)+B(21)+

-          B(20)+B(19)+B(16)+B(15)+B(14)+B(12)+B(8)+B(5)+B(0), 117),

- kDefPoly(B(117)+B(113)+B(110)+B(108)+B(105)+B(104)+B(103)+B(102)+B(99)+

-          B(98)+B(97)+B(94)+B(93)+B(91)+B(90)+B(89)+B(85)+B(84)+B(82)+

-          B(81)+B(79)+B(78)+B(77)+B(74)+B(73)+B(69)+B(67)+B(64), B(63)+

-          B(62)+B(61)+B(57)+B(55)+B(51)+B(50)+B(46)+B(45)+B(43)+B(42)+

-          B(41)+B(37)+B(33)+B(32)+B(30)+B(27)+B(26)+B(21)+B(19)+B(18)+

-          B(17)+B(15)+B(14)+B(12)+B(10)+B(8)+B(7)+B(3)+B(2)+B(1)+

-          B(0), 118),

- kDefPoly(B(118)+B(111)+B(109)+B(107)+B(106)+B(105)+B(104)+B(101)+B(99)+

-          B(98)+B(97)+B(94)+B(92)+B(91)+B(89)+B(83)+B(82)+B(80)+B(79)+

-          B(67)+B(66), B(62)+B(61)+B(60)+B(58)+B(57)+B(52)+B(48)+B(46)+

-          B(44)+B(42)+B(40)+B(39)+B(38)+B(36)+B(34)+B(33)+B(32)+B(29)+

-          B(23)+B(22)+B(20)+B(19)+B(18)+B(15)+B(13)+B(12)+B(11)+B(6)+B(5)+

-          B(4)+B(3)+B(1)+B(0), 119),

- kDefPoly(B(116)+B(115)+B(113)+B(112)+B(110)+B(107)+B(106)+B(104)+B(103)+

-          B(101)+B(100)+B(99)+B(98)+B(90)+B(89)+B(88)+B(87)+B(82)+B(80)+

-          B(79)+B(77)+B(76)+B(75)+B(74)+B(73)+B(71)+B(70)+B(68)+B(65)+

-          B(64), B(63)+B(62)+B(59)+B(55)+B(54)+B(48)+B(47)+B(45)+B(44)+

-          B(40)+B(39)+B(38)+B(35)+B(33)+B(29)+B(27)+B(26)+B(25)+B(24)+

-          B(23)+B(22)+B(21)+B(18)+B(17)+B(15)+B(13)+B(12)+B(10)+B(8)+B(3)+

-          B(2)+B(0), 120),

- kDefPoly(B(118)+B(117)+B(114)+B(113)+B(112)+B(110)+B(109)+B(104)+B(103)+

-          B(101)+B(99)+B(97)+B(96)+B(95)+B(93)+B(92)+B(91)+B(90)+B(89)+

-          B(87)+B(85)+B(84)+B(82)+B(81)+B(79)+B(73)+B(72)+B(68)+B(67)+

-          B(66)+B(64), B(60)+B(58)+B(57)+B(56)+B(54)+B(53)+B(52)+B(51)+

-          B(49)+B(48)+B(47)+B(45)+B(44)+B(38)+B(37)+B(36)+B(35)+B(33)+

-          B(32)+B(31)+B(30)+B(27)+B(26)+B(24)+B(23)+B(22)+B(20)+B(19)+

-          B(18)+B(16)+B(15)+B(12)+B(6)+B(5)+B(4)+B(2)+B(0), 121),

- kDefPoly(B(121)+B(118)+B(114)+B(112)+B(109)+B(106)+B(103)+B(102)+B(101)+

-          B(100)+B(97)+B(95)+B(90)+B(89)+B(87)+B(83)+B(81)+B(80)+B(79)+

-          B(78)+B(77)+B(76)+B(75)+B(74)+B(72)+B(71)+B(70)+B(69)+B(68)+

-          B(66)+B(64), B(61)+B(57)+B(51)+B(50)+B(47)+B(46)+B(43)+B(39)+

-          B(38)+B(37)+B(36)+B(34)+B(33)+B(32)+B(30)+B(28)+B(27)+B(24)+

-          B(22)+B(20)+B(18)+B(17)+B(14)+B(12)+B(11)+B(9)+B(7)+B(2)+

-          B(0), 122),

- kDefPoly(B(122)+B(121)+B(120)+B(119)+B(118)+B(117)+B(116)+B(113)+B(112)+

-          B(111)+B(109)+B(106)+B(105)+B(103)+B(100)+B(98)+B(97)+B(95)+

-          B(93)+B(92)+B(90)+B(87)+B(86)+B(85)+B(83)+B(81)+B(78)+B(77)+

-          B(75)+B(74)+B(73)+B(72)+B(71)+B(70)+B(69)+B(68)+B(67)+B(65)+

-          B(64), B(63)+B(62)+B(60)+B(55)+B(52)+B(51)+B(49)+B(47)+B(45)+

-          B(43)+B(42)+B(41)+B(37)+B(36)+B(35)+B(34)+B(32)+B(28)+B(27)+

-          B(26)+B(24)+B(23)+B(21)+B(20)+B(16)+B(13)+B(10)+B(9)+B(8)+B(7)+

-          B(5)+B(2)+B(0), 123),

- kDefPoly(B(123)+B(121)+B(120)+B(118)+B(117)+B(116)+B(115)+B(112)+B(111)+

-          B(110)+B(109)+B(107)+B(104)+B(102)+B(101)+B(100)+B(99)+B(98)+

-          B(97)+B(94)+B(90)+B(87)+B(86)+B(84)+B(83)+B(82)+B(79)+B(75)+

-          B(72)+B(71)+B(70)+B(64), B(63)+B(56)+B(54)+B(51)+B(50)+B(47)+

-          B(45)+B(44)+B(42)+B(39)+B(38)+B(36)+B(34)+B(33)+B(29)+B(26)+

-          B(24)+B(20)+B(16)+B(14)+B(11)+B(10)+B(8)+B(7)+B(6)+B(4)+B(2)+

-          B(0), 124),

- kDefPoly(B(124)+B(123)+B(121)+B(119)+B(118)+B(116)+B(115)+B(114)+B(107)+

-          B(105)+B(104)+B(103)+B(102)+B(99)+B(98)+B(96)+B(94)+B(93)+B(89)+

-          B(83)+B(82)+B(81)+B(80)+B(79)+B(78)+B(75)+B(74)+B(73)+B(72)+

-          B(70)+B(69)+B(68)+B(64), B(63)+B(59)+B(56)+B(55)+B(52)+B(51)+

-          B(50)+B(49)+B(48)+B(44)+B(42)+B(38)+B(37)+B(36)+B(33)+B(31)+

-          B(29)+B(27)+B(26)+B(25)+B(23)+B(21)+B(19)+B(18)+B(16)+B(14)+

-          B(11)+B(8)+B(7)+B(6)+B(4)+B(1)+B(0), 125),

- kDefPoly(B(124)+B(122)+B(121)+B(120)+B(119)+B(117)+B(113)+B(110)+B(108)+

-          B(105)+B(103)+B(102)+B(101)+B(97)+B(93)+B(91)+B(90)+B(88)+B(86)+

-          B(84)+B(82)+B(81)+B(79)+B(77)+B(76)+B(75)+B(73)+B(72)+B(71)+

-          B(69)+B(67)+B(64), B(63)+B(62)+B(61)+B(60)+B(58)+B(56)+B(55)+

-          B(52)+B(51)+B(48)+B(47)+B(45)+B(44)+B(42)+B(41)+B(40)+B(39)+

-          B(37)+B(33)+B(32)+B(30)+B(29)+B(28)+B(27)+B(26)+B(25)+B(24)+

-          B(23)+B(19)+B(18)+B(17)+B(16)+B(14)+B(13)+B(11)+B(9)+B(8)+B(7)+

-          B(4)+B(2)+B(1)+B(0), 126),

- kDefPoly(B(125)+B(124)+B(121)+B(116)+B(115)+B(105)+B(103)+B(101)+B(94)+

-          B(93)+B(91)+B(90)+B(88)+B(87)+B(86)+B(85)+B(77)+B(73)+B(72)+

-          B(70)+B(68)+B(67), B(63)+B(62)+B(61)+B(59)+B(57)+B(53)+B(52)+

-          B(51)+B(49)+B(48)+B(46)+B(44)+B(41)+B(39)+B(38)+B(36)+B(35)+

-          B(30)+B(27)+B(25)+B(23)+B(20)+B(19)+B(13)+B(12)+B(11)+B(10)+B(8)+

-          B(7)+B(5)+B(4)+B(3)+B(2)+B(0), 127),

- kDefPoly(B(127)+B(122)+B(121)+B(118)+B(117)+B(116)+B(109)+B(108)+B(107)+

-          B(106)+B(104)+B(103)+B(102)+B(101)+B(96)+B(93)+B(92)+B(91)+B(89)+

-          B(86)+B(85)+B(80)+B(78)+B(77)+B(76)+B(75)+B(74)+B(73)+B(72)+

-          B(71)+B(66), B(60)+B(56)+B(53)+B(52)+B(50)+B(47)+B(45)+B(41)+

-          B(39)+B(38)+B(37)+B(35)+B(34)+B(33)+B(30)+B(28)+B(25)+B(24)+

-          B(23)+B(21)+B(20)+B(19)+B(14)+B(13)+B(10)+B(8)+B(5)+B(4)+B(2)+

-          B(1)+B(0), 128),

-};

-// lint -restore

-

-// The number of polynomials in POLYS[].

-SELECTANY const int CRC::N_POLYS = sizeof (poly_list) / sizeof (poly_list[0]);

-

-// The externally visible name of poly_list.

-// This guarantees that the size of poly_list is opaque.

-SELECTANY const struct CRC::Poly *const CRC::POLYS = poly_list;

-

-// The "constructor" for a CRC with an default polynomial.

-CRC *CRC::Default(int degree, size_t roll_length) {

-  ASSERT1(32 == degree);

-

-  CRC *crc = CRCImpl::NewInternal(CRC::POLYS[degree].lo, CRC::POLYS[degree].hi,

-                                  degree, roll_length);  // Build the table

-  return crc;

-}

-

-// The "constructor" for a CRC with an arbitrary polynomial.

-CRC *CRC::New(uint64 lo, uint64 hi, int degree, size_t roll_length) {

-  return CRCImpl::NewInternal(lo, hi, degree, roll_length);

-}

-

-// Internal version of the "constructor".

-CRCImpl *CRCImpl::NewInternal(uint64 lo, uint64 hi,

-                             int degree, size_t roll_length) {

-  ASSERT1(8 <= degree && degree <= 64);  // precondition

-  ASSERT1(lo != 0 || hi != 0);            // precondition

-  // Generate the tables for extending a CRC by 4 bytes at a time.

-  // Why 4 and not 8?  Because Pentium 4 has such small caches.

-  struct CRC_pair t[4][256];

-  for (int j = 0; j != 4; j++) {      // for each byte of extension....

-    t[j][0].lo = 0;                   // a zero has no effect

-    t[j][0].hi = 0;

-    for (int i = 128; i != 0;  i >>= 1) {  // fill in entries for powers of 2

-      if (j == 0 && i == 128) {

-        t[j][i].lo = lo;  // top bit in first byte is easy---it's the polynomial

-        t[j][i].hi = hi;

-      } else {

-                  // each successive power of two is derive from the previous

-                  // one, either in this table, or the last table

-        struct CRC_pair pred;

-        if (i == 128) {

-          pred = t[j-1][1];

-        } else {

-          pred = t[j][i << 1];

-        }

-        // Advance the CRC by one bit (multiply by X, and take remainder

-        // through one step of polynomial long division)

-        if (pred.lo & 1) {

-          t[j][i].lo = (pred.lo >> 1) ^ (pred.hi << 63) ^ lo;

-          t[j][i].hi = (pred.hi >> 1) ^ hi;

-        } else {

-          t[j][i].lo = (pred.lo >> 1) ^ (pred.hi << 63);

-          t[j][i].hi = pred.hi >> 1;

-        }

-      }

-    }

-    // CRCs have the property that CRC(a xor b) == CRC(a) xor CRC(b)

-    // so we can make all the tables for non-powers of two by

-    // xoring previously created entries.

-    for (int i = 2; i != 256;  i <<= 1) {

-      for (int k = i+1; k != (i << 1); k++) {

-        t[j][k].lo = t[j][i].lo ^ t[j][k-i].lo;

-        t[j][k].hi = t[j][i].hi ^ t[j][k-i].hi;

-      }

-    }

-  }

-

-  // Copy the newly built tables in t[] into an appropriate

-  // CRC implenentation object.

-  CRCImpl *result = 0;

-  CRC32 *crc32 = 0;

-  crc32 = new CRC32();

-  for (int i = 0; i != 256; i++) {

-    crc32->table0_[i] = static_cast<uint32>(t[0][i].lo);

-    crc32->table1_[i] = static_cast<uint32>(t[1][i].lo);

-    crc32->table2_[i] = static_cast<uint32>(t[2][i].lo);

-    crc32->table3_[i] = static_cast<uint32>(t[3][i].lo);

-  }

-  result = crc32;

-

-  // "result" is now a CRC object of the right type to handle

-  // the polynomial of the right degree.

-

-  result->roll_length_ = roll_length;

-  result->degree_ = degree;

-  result->poly_lo_ = lo;

-  result->poly_hi_ = hi;

-

-  // Build the table for extending by zeroes.

-  // Entry i=a-1+3*b (a in {1, 2, 3}, b in {0, 1, 2, 3, ...}

-  // contains a polynomial Pi such that multiplying

-  // a CRC by Pi mod P, where P is the CRC polynomial, is equivalent to

-  // appending a*2**(2*b+SMALL_BITS) zero bytes to the original string.

-  // Entry is generated by calling ExtendByZeroes() twice using

-  // half the length from the previous entry.

-  int pos = 0;

-  for (uint64 inc_len = (1 << SMALL_BITS); inc_len != 0; inc_len <<= 2) {

-    result->Empty(&lo, &hi);

-    for (int k = 0; k != 3; k++) {

-      result->ExtendByZeroes(&lo, &hi, (size_t) (inc_len >> 1));

-      result->ExtendByZeroes(&lo, &hi, (size_t) (inc_len >> 1));

-      crc32->zeroes_[pos] = static_cast<uint32>(lo);

-      pos++;

-    }

-  }

-

-  // Calculate the entries in the roll table, used for rolling checksums

-  // of a fixed length.

-  // Extend the powers of two in the one-byte extension table by the roll

-  // length.

-  int bit = 256;

-  do {

-    bit >>= 1;

-    result->ExtendByZeroes(&t[0][bit].lo, &t[0][bit].hi, roll_length);

-  } while (bit != 0);

-  // Calculate the non-powers of two using CRC(a xor b) == CRC(a) xor CRC(b)

-  for (int i = 2; i != 256;  i <<= 1) {

-    for (int j = i+1; j != (i << 1); j++) {

-      t[0][j].lo = t[0][i].lo ^ t[0][j-i].lo;

-      t[0][j].hi = t[0][i].hi ^ t[0][j-i].hi;

-    }

-  }

-  // Now xor the CRC of (binary) 100000001 followed by

-  // the roll length of zeroes.   This will be xored into every

-  // entry.   This will simultaneously roll out the CRC

-  // of the empty string that's been pushed one byte too far,

-  // and roll in the CRC of the empty string in the correct place again.

-  result->Empty(&lo, &hi);

-  const uint8 x = 0x80;

-  result->Extend(&lo, &hi, &x, 1);

-  result->ExtendByZeroes(&lo, &hi, roll_length);

-  for (int i = 0; i != 256; i++) {

-    t[0][i].lo ^= lo;

-    t[0][i].hi ^= hi;

-  }

-

-  // Put the roll table into the object.

-  for (int i = 0; i != 256; i++) {

-    crc32->roll_[i] = static_cast<uint32>(t[0][i].lo);

-  }

-

-  return result;

-}

-

-// The CRC of the empty string is always the CRC polynomial itself.

-void CRCImpl::Empty(uint64 *lo, uint64 *hi) const {

-  ASSERT1(hi);

-  ASSERT1(lo);

-

-  *lo = this->poly_lo_;

-  *hi = this->poly_hi_;

-}

-

-//  The 32-bit implementation

-

-void CRC32::Extend(uint64 *lo, uint64 *hi, const void *bytes, size_t length)

-                      const {

-  ASSERT1(hi);

-  ASSERT1(lo);

-

-  hi;   // unreferenced formal parameter

-

-  const uint8 *p = static_cast<const uint8 *>(bytes);

-  const uint8 *e = p + length;

-  uint32 l = static_cast<uint32>(*lo);

-  // point x at MIN(first 4-byte aligned byte in string, end of string)

-  const uint8 *x = p + ((zero_ptr - p) & 3);

-  if (x > e) {

-    x = e;

-  }

-  // Process bytes until finished or p is 4-byte aligned

-  while (p != x) {

-    int c = (l & 0xff) ^ *p++;

-    l = this->table0_[c] ^ (l >> 8);

-  }

-  // point x at MIN(last 4-byte aligned byte in string, end of string)

-  x = e - ((e - zero_ptr) & 3);

-  // Process bytes 4 at a time

-  while (p < x) {

-    uint32 c = l ^ *reinterpret_cast<const uint32*>(p);

-    p += 4;

-    l = this->table3_[c & 0xff] ^

-        this->table2_[(c >> 8) & 0xff] ^

-        this->table1_[(c >> 16) & 0xff] ^

-        this->table0_[c >> 24];

-  }

-

-  // Process the last few bytes

-  while (p != e) {

-    int c = (l & 0xff) ^ *p++;

-    l = this->table0_[c] ^ (l >> 8);

-  }

-  *lo = l;

-}

-

-void CRC32::ExtendByZeroes(uint64 *lo, uint64 *hi, size_t length) const {

-  ASSERT1(hi);

-  ASSERT1(lo);

-

-  // Process the low order SMALL_BITS of the length by simply

-  // using Extend() on an array of bytes that are zero.

-  int small_part = (length & ((1 << SMALL_BITS)-1));

-  if (small_part != 0) {

-    this->Extend(lo, hi, zeroes, small_part);

-  }

-  length >>= SMALL_BITS;

-  if (length != 0) {          // if the length was at least 2**SMALL_BITS

-    uint32 l = static_cast<uint32>(*lo);

-    uint32 onebit = 1;

-    onebit <<= this->degree_ - 1;

-    // For each pair of bits in length

-    // (after the low-oder bits have been removed)

-    // we lookup the appropriate polynomial in the zeroes_ array

-    // and do a polynomial long multiplication (mod the CRC polynomial)

-    // to extend the CRC by the appropriate number of bits.

-    for (int i = 0; length != 0; i += 3, length >>= 2) {

-      int c = length & 3;       // pick next two bits

-      if (c != 0) {             // if they are not zero,

-                                // multiply by entry in table

-        uint32 m = this->zeroes_[c+i-1];

-        uint32 result = 0;

-        for (uint32 one = onebit; one != 0; one >>= 1) {

-          if ((l & one) != 0) {

-            result ^= m;

-          }

-          if (m & 1) {

-            m = (m >> 1) ^ static_cast<uint32>(poly_lo_);

-          } else {

-            m = (m >> 1);

-          }

-        }

-        l = result;

-      }

-    }

-    *lo = l;

-  }

-}

-

-void CRC32::Roll(uint64 *lo, uint64 *hi, uint8 o_byte, uint8 i_byte) const {

-  ASSERT1(hi);

-  ASSERT1(lo);

-

-  hi;   // unreferenced formal parameter

-

-  uint32 l = static_cast<uint32>(*lo);

-  // Roll in i_byte and out o_byte

-  *lo = this->table0_[(l & 0xff) ^ i_byte] ^ (l >> 8) ^ this->roll_[o_byte];

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Implemetation of CRCs (aka Rabin Fingerprints).
+// Treats the input as a polynomial with coefficients in Z(2),
+// and finds the remainder when divided by an irreducible polynomial
+// of the appropriate length.
+// It handles all CRC sizes from 8 to 128 bits.
+// It's somewhat complicated by having separate implementations optimized for
+// CRC's <=32 bits, <= 64 bits, and <= 128 bits.
+// The input string is prefixed with a "1" bit, and has "degree" "0" bits
+// appended to it before the remainder is found.   This ensures that
+// short strings are scrambled somewhat and that strings consisting
+// of all nulls have a non-zero CRC.
+
+#include <stddef.h>
+#include "omaha/common/crc.h"
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+static const int SMALL_BITS = 8;
+                   // When extending an input with a string of zeroes,
+                   // if the number of zeroes is less than 2**SMALL_BITS,
+                   // a normal Extend is done, rather than a polynomial
+                   // multiplication.
+static const char zeroes[1 << SMALL_BITS] = { 0 };  // an array of zeroes
+
+static const uint8 *zero_ptr = 0;   // The 0 pointer---used for alignment
+
+// These are used to index a 2-entry array of words that together
+// for a longer integer.  LO indexes the low-order half.
+#define LO 0
+#define HI (1-LO)
+
+// Constructor and destructor for baseclase CRC.
+CRC::~CRC() {}
+CRC::CRC() {}
+
+struct CRC_pair {             // Used to represent a 128-bit value
+  uint64 lo;
+  uint64 hi;
+};
+
+class CRCImpl : public CRC {    // Implemention of the abstract class CRC
+ public:
+  CRCImpl() {}
+  virtual ~CRCImpl() {}
+
+  // The internal version of CRC::New().
+  static CRCImpl *NewInternal(uint64 lo, uint64 hi,
+                              int degree, size_t roll_length);
+
+  virtual void Empty(uint64 *lo, uint64 *hi) const;
+
+  size_t roll_length_;    // length of window in rolling CRC
+  int degree_;            // bits in the CRC
+  uint64 poly_lo_;        // The CRC of the empty string, low part
+  uint64 poly_hi_;        // The CRC of the empty string, high part
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(CRCImpl);
+};
+
+// This is the 32-bit implementation.  It handles all sizes from 8 to 32.
+class CRC32 : public CRCImpl {
+ public:
+  CRC32() {}
+  virtual ~CRC32() {}
+
+  virtual void Extend(uint64 *lo, uint64 *hi,
+                      const void *bytes, size_t length) const;
+  virtual void ExtendByZeroes(uint64 *lo, uint64 *hi, size_t length) const;
+  virtual void Roll(uint64 *lo, uint64 *hi, uint8 o_byte, uint8 i_byte) const;
+
+  uint32 table0_[256];  // table of byte extensions
+  uint32 table1_[256];  // table of byte extensions, shifted by 1 byte
+  uint32 table2_[256];  // table of byte extensions, shifted by 2 bytes
+  uint32 table3_[256];  // table of byte extensions, shifted by 3 bytes
+  uint32 roll_[256];    // table of byte roll values
+  uint32 zeroes_[256];  // table of zero extensions
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(CRC32);
+};
+
+static const uint64 UINT64_ZERO = 0;    // a 64-bit zero
+static const uint64 UINT64_ONE = 1;     // a 64-bit 1
+
+// The B() macro sets the bit corresponding to X**(_x) in the polynomial
+#define B(_x) (UINT64_ONE << ((_x) < 64?(63-(_x)):(127-(_x))))
+
+// Used to initialize polynomials.
+// The redundant tests on _len are to avoid warnings from the
+// compiler about inappropriate shift lengths.   These shifts
+// occur on not-taken branch of the ?: in some cases.
+#define kDefPoly(_h,_l,_len) \
+ { ((_len) <= 64  ? (_l) >> ((_len) <= 64? 64 - (_len): 0) : \
+    (_len) == 128 ? (_h) : \
+                     ((_h) >> ((_len) > 64? 128 - (_len): 0)) | \
+                     ((_l) << ((_len) > 64 && (_len) < 128? (_len)-64: 0))), \
+   ((_len) <= 64  ? 0 : \
+    (_len) == 128 ? (_l) :  \
+                    (_l) >> ((_len) > 64? 128 - (_len): 0)), \
+   (_len) }
+
+// A table of irreducible polynomials suitable for use with the implementation.
+// Indexes 0...1 have degree 32 polynomials.
+// Indexes 2...3 have degree 64 polynomials.
+// Indexes 4...5 have degree 96 polynomials.
+// Indexes 6...7 have degree 128 polynomials.
+// Index i=8...128 has a degree i polynomial.
+// All polynomials in the table are guaranteed distinct.
+// lint -save -e572 -e648 -e778   Excessive shift value, expression evaluates to 0
+static const struct CRC::Poly poly_list[] = {
+ kDefPoly(UINT64_ZERO, B(30)+B(27)+B(26)+B(25)+B(23)+B(20)+B(17)+B(15)+B(14)+
+          B(12)+B(6)+B(5)+B(2)+B(0), 32),
+ kDefPoly(UINT64_ZERO, B(31)+B(28)+B(27)+B(26)+B(24)+B(22)+B(19)+B(18)+B(16)+
+          B(13)+B(11)+B(10)+B(9)+B(4)+B(2)+B(0), 32),
+ kDefPoly(UINT64_ZERO, B(60)+B(59)+B(58)+B(56)+B(55)+B(54)+B(51)+B(50)+B(49)+
+          B(48)+B(47)+B(45)+B(44)+B(42)+B(40)+B(39)+B(38)+B(36)+B(34)+B(33)+
+          B(32)+B(31)+B(30)+B(27)+B(25)+B(23)+B(22)+B(21)+B(20)+B(19)+
+          B(17)+B(16)+B(15)+B(8)+B(7)+B(6)+B(5)+B(0), 64),
+ kDefPoly(UINT64_ZERO, B(63)+B(62)+B(60)+B(58)+B(57)+B(56)+B(54)+B(52)+B(46)+
+          B(45)+B(43)+B(40)+B(37)+B(36)+B(34)+B(33)+B(32)+B(31)+B(30)+B(29)+
+          B(28)+B(27)+B(26)+B(23)+B(19)+B(18)+B(15)+B(14)+B(13)+B(9)+B(8)+
+          B(0), 64),
+ kDefPoly(B(95)+B(94)+B(91)+B(90)+B(89)+B(88)+B(87)+B(86)+B(79)+B(78)+
+          B(77)+B(76)+B(75)+B(74)+B(73)+B(69)+B(68)+B(66), B(63)+B(61)+
+          B(59)+B(57)+B(53)+B(51)+B(50)+B(47)+B(40)+B(39)+B(38)+B(36)+
+          B(35)+B(33)+B(29)+B(28)+B(27)+B(25)+B(24)+B(23)+B(21)+B(19)+
+          B(18)+B(17)+B(16)+B(13)+B(12)+B(10)+B(9)+B(7)+B(4)+B(2)+B(1)+
+          B(0), 96),
+ kDefPoly(B(95)+B(92)+B(89)+B(88)+B(87)+B(85)+B(84)+B(82)+B(81)+B(80)+
+          B(79)+B(78)+B(76)+B(75)+B(70)+B(69)+B(66)+B(65), B(60)+B(56)+
+          B(55)+B(52)+B(51)+B(49)+B(48)+B(46)+B(44)+B(42)+B(41)+B(39)+
+          B(38)+B(37)+B(35)+B(33)+B(32)+B(30)+B(28)+B(27)+B(25)+B(22)+
+          B(19)+B(17)+B(14)+B(12)+B(10)+B(0), 96),
+ kDefPoly(B(122)+B(121)+B(120)+B(119)+B(117)+B(116)+B(114)+B(113)+B(112)+
+          B(111)+B(109)+B(107)+B(104)+B(102)+B(100)+B(98)+B(96)+B(94)+
+          B(93)+B(92)+B(91)+B(90)+B(88)+B(87)+B(86)+B(84)+B(82)+B(80)+
+          B(75)+B(74)+B(73)+B(69), B(62)+B(61)+B(58)+B(52)+B(48)+B(47)+
+          B(46)+B(45)+B(42)+B(41)+B(38)+B(37)+B(35)+B(33)+B(32)+B(31)+
+          B(30)+B(28)+B(26)+B(24)+B(22)+B(21)+B(20)+B(19)+B(18)+B(17)+
+          B(10)+B(9)+B(8)+B(7)+B(5)+B(2)+B(1)+B(0), 128),
+ kDefPoly(B(127)+B(126)+B(124)+B(121)+B(117)+B(116)+B(115)+B(113)+B(112)+
+          B(111)+B(108)+B(105)+B(104)+B(103)+B(100)+B(98)+B(96)+B(93)+
+          B(92)+B(90)+B(89)+B(88)+B(86)+B(85)+B(80)+B(77)+B(76)+B(72)+
+          B(70)+B(69)+B(68)+B(65)+B(64), B(62)+B(61)+B(59)+B(58)+B(56)+
+          B(53)+B(52)+B(51)+B(50)+B(48)+B(46)+B(39)+B(35)+B(34)+B(33)+
+          B(32)+B(30)+B(29)+B(28)+B(22)+B(21)+B(19)+B(18)+B(17)+B(14)+
+          B(10)+B(9)+B(7)+B(5)+B(4)+B(3)+B(2)+B(0), 128),
+ kDefPoly(UINT64_ZERO, B(7)+B(6)+B(5)+B(4)+B(2)+B(0), 8),
+ kDefPoly(UINT64_ZERO, B(8)+B(4)+B(3)+B(2)+B(1)+B(0), 9),
+ kDefPoly(UINT64_ZERO, B(8)+B(6)+B(5)+B(3)+B(1)+B(0), 10),
+ kDefPoly(UINT64_ZERO, B(10)+B(9)+B(7)+B(5)+B(1)+B(0), 11),
+ kDefPoly(UINT64_ZERO, B(11)+B(10)+B(5)+B(2)+B(1)+B(0), 12),
+ kDefPoly(UINT64_ZERO, B(12)+B(11)+B(10)+B(8)+B(5)+B(3)+B(2)+B(0), 13),
+ kDefPoly(UINT64_ZERO, B(11)+B(10)+B(9)+B(8)+B(7)+B(5)+B(4)+B(2)+B(1)+
+          B(0), 14),
+ kDefPoly(UINT64_ZERO, B(14)+B(12)+B(11)+B(10)+B(9)+B(5)+B(3)+B(2)+B(1)+
+          B(0), 15),
+ kDefPoly(UINT64_ZERO, B(12)+B(11)+B(7)+B(6)+B(5)+B(4)+B(3)+B(0), 16),
+ kDefPoly(UINT64_ZERO, B(16)+B(14)+B(11)+B(10)+B(8)+B(3)+B(1)+B(0), 17),
+ kDefPoly(UINT64_ZERO, B(12)+B(11)+B(9)+B(8)+B(7)+B(4)+B(3)+B(0), 18),
+ kDefPoly(UINT64_ZERO, B(12)+B(11)+B(8)+B(7)+B(6)+B(5)+B(2)+B(0), 19),
+ kDefPoly(UINT64_ZERO, B(18)+B(15)+B(14)+B(12)+B(9)+B(6)+B(3)+B(0), 20),
+ kDefPoly(UINT64_ZERO, B(20)+B(19)+B(14)+B(13)+B(12)+B(11)+B(8)+B(7)+B(6)+
+          B(5)+B(2)+B(0), 21),
+ kDefPoly(UINT64_ZERO, B(21)+B(20)+B(18)+B(16)+B(15)+B(14)+B(12)+B(9)+B(7)+
+          B(2)+B(1)+B(0), 22),
+ kDefPoly(UINT64_ZERO, B(22)+B(21)+B(17)+B(16)+B(15)+B(14)+B(12)+B(10)+B(7)+
+          B(4)+B(1)+B(0), 23),
+ kDefPoly(UINT64_ZERO, B(23)+B(22)+B(21)+B(18)+B(17)+B(15)+B(14)+B(12)+B(4)+
+          B(0), 24),
+ kDefPoly(UINT64_ZERO, B(24)+B(23)+B(22)+B(20)+B(18)+B(17)+B(14)+B(13)+B(9)+
+          B(0), 25),
+ kDefPoly(UINT64_ZERO, B(25)+B(22)+B(21)+B(19)+B(17)+B(15)+B(14)+B(12)+B(11)+
+          B(10)+B(6)+B(4)+B(3)+B(0), 26),
+ kDefPoly(UINT64_ZERO, B(26)+B(25)+B(19)+B(17)+B(16)+B(13)+B(5)+B(4)+B(1)+
+          B(0), 27),
+ kDefPoly(UINT64_ZERO, B(23)+B(22)+B(21)+B(20)+B(19)+B(18)+B(13)+B(12)+B(10)+
+          B(9)+B(8)+B(6)+B(5)+B(3)+B(1)+B(0), 28),
+ kDefPoly(UINT64_ZERO, B(27)+B(26)+B(25)+B(23)+B(22)+B(20)+B(19)+B(15)+B(14)+
+          B(11)+B(10)+B(8)+B(7)+B(6)+B(4)+B(0), 29),
+ kDefPoly(UINT64_ZERO, B(29)+B(27)+B(25)+B(23)+B(20)+B(19)+B(18)+B(17)+B(16)+
+          B(14)+B(11)+B(10)+B(9)+B(7)+B(6)+B(5)+B(4)+B(0), 30),
+ kDefPoly(UINT64_ZERO, B(30)+B(29)+B(28)+B(27)+B(25)+B(23)+B(22)+B(21)+B(20)+
+          B(19)+B(18)+B(16)+B(15)+B(10)+B(9)+B(8)+B(4)+B(3)+B(1)+B(0), 31),
+ kDefPoly(UINT64_ZERO, B(31)+B(29)+B(28)+B(27)+B(21)+B(20)+B(15)+B(13)+B(10)+
+          B(9)+B(8)+B(7)+B(4)+B(3)+B(2)+B(0), 32),
+ kDefPoly(UINT64_ZERO, B(32)+B(31)+B(30)+B(29)+B(27)+B(25)+B(24)+B(22)+B(21)+
+          B(19)+B(15)+B(10)+B(4)+B(3)+B(2)+B(0), 33),
+ kDefPoly(UINT64_ZERO, B(30)+B(27)+B(26)+B(25)+B(24)+B(20)+B(19)+B(18)+B(16)+
+          B(15)+B(14)+B(12)+B(9)+B(8)+B(7)+B(5)+B(1)+B(0), 34),
+ kDefPoly(UINT64_ZERO, B(34)+B(32)+B(28)+B(27)+B(26)+B(22)+B(21)+B(20)+B(19)+
+          B(14)+B(13)+B(12)+B(10)+B(6)+B(5)+B(4)+B(3)+B(0), 35),
+ kDefPoly(UINT64_ZERO, B(35)+B(34)+B(33)+B(32)+B(31)+B(28)+B(26)+B(24)+B(22)+
+          B(21)+B(20)+B(19)+B(18)+B(14)+B(13)+B(12)+B(10)+B(9)+B(8)+B(6)+B(5)+
+          B(4)+B(3)+B(0), 36),
+ kDefPoly(UINT64_ZERO, B(36)+B(35)+B(31)+B(30)+B(28)+B(26)+B(25)+B(23)+B(22)+
+          B(20)+B(19)+B(18)+B(16)+B(13)+B(12)+B(7)+B(6)+B(4)+B(3)+B(0), 37),
+ kDefPoly(UINT64_ZERO, B(37)+B(34)+B(33)+B(32)+B(31)+B(30)+B(29)+B(28)+B(27)+
+          B(26)+B(25)+B(23)+B(18)+B(16)+B(15)+B(13)+B(12)+B(11)+B(10)+B(9)+
+          B(8)+B(7)+B(6)+B(2)+B(1)+B(0), 38),
+ kDefPoly(UINT64_ZERO, B(38)+B(37)+B(33)+B(32)+B(31)+B(27)+B(25)+B(24)+B(21)+
+          B(20)+B(19)+B(18)+B(17)+B(15)+B(14)+B(8)+B(7)+B(6)+B(3)+B(2)+B(1)+
+          B(0), 39),
+ kDefPoly(UINT64_ZERO, B(38)+B(37)+B(35)+B(34)+B(32)+B(31)+B(30)+B(27)+B(24)+
+          B(21)+B(20)+B(14)+B(13)+B(11)+B(8)+B(4)+B(2)+B(0), 40),
+ kDefPoly(UINT64_ZERO, B(38)+B(36)+B(35)+B(34)+B(33)+B(31)+B(30)+B(29)+B(28)+
+          B(27)+B(23)+B(22)+B(20)+B(19)+B(18)+B(17)+B(15)+B(14)+B(11)+B(5)+
+          B(4)+B(0), 41),
+ kDefPoly(UINT64_ZERO, B(41)+B(37)+B(36)+B(35)+B(32)+B(31)+B(30)+B(29)+B(28)+
+          B(25)+B(19)+B(18)+B(14)+B(13)+B(12)+B(7)+B(6)+B(4)+B(2)+B(0), 42),
+ kDefPoly(UINT64_ZERO, B(42)+B(40)+B(38)+B(37)+B(36)+B(35)+B(34)+B(33)+B(31)+
+          B(29)+B(27)+B(26)+B(25)+B(23)+B(21)+B(20)+B(19)+B(15)+B(11)+B(10)+
+          B(9)+B(8)+B(6)+B(5)+B(3)+B(0), 43),
+ kDefPoly(UINT64_ZERO, B(43)+B(42)+B(40)+B(39)+B(37)+B(35)+B(32)+B(30)+B(26)+
+          B(25)+B(24)+B(20)+B(16)+B(13)+B(12)+B(11)+B(8)+B(6)+B(5)+B(4)+B(1)+
+          B(0), 44),
+ kDefPoly(UINT64_ZERO, B(43)+B(42)+B(41)+B(40)+B(39)+B(38)+B(33)+B(32)+B(27)+
+          B(26)+B(25)+B(23)+B(20)+B(18)+B(17)+B(16)+B(14)+B(11)+B(10)+B(9)+
+          B(6)+B(5)+B(1)+B(0), 45),
+ kDefPoly(UINT64_ZERO, B(45)+B(43)+B(42)+B(41)+B(40)+B(39)+B(32)+B(31)+B(30)+
+          B(29)+B(27)+B(25)+B(23)+B(18)+B(17)+B(16)+B(10)+B(9)+B(7)+B(6)+B(4)+
+          B(3)+B(2)+B(0), 46),
+ kDefPoly(UINT64_ZERO, B(45)+B(44)+B(43)+B(41)+B(40)+B(39)+B(38)+B(37)+B(32)+
+          B(30)+B(23)+B(21)+B(20)+B(17)+B(15)+B(13)+B(11)+B(10)+B(7)+B(5)+
+          B(3)+B(0), 47),
+ kDefPoly(UINT64_ZERO, B(46)+B(42)+B(41)+B(39)+B(37)+B(36)+B(35)+B(29)+B(28)+
+          B(25)+B(24)+B(21)+B(20)+B(18)+B(17)+B(13)+B(12)+B(11)+B(10)+B(9)+
+          B(8)+B(5)+B(1)+B(0), 48),
+ kDefPoly(UINT64_ZERO, B(48)+B(44)+B(41)+B(40)+B(39)+B(38)+B(37)+B(36)+B(35)+
+          B(34)+B(30)+B(28)+B(27)+B(24)+B(21)+B(18)+B(17)+B(8)+B(3)+B(0), 49),
+ kDefPoly(UINT64_ZERO, B(48)+B(47)+B(46)+B(45)+B(44)+B(43)+B(42)+B(35)+B(33)+
+          B(29)+B(26)+B(24)+B(23)+B(21)+B(18)+B(16)+B(14)+B(13)+B(12)+B(9)+
+          B(7)+B(6)+B(5)+B(4)+B(3)+B(0), 50),
+ kDefPoly(UINT64_ZERO, B(47)+B(46)+B(45)+B(44)+B(43)+B(40)+B(39)+B(38)+B(36)+
+          B(35)+B(30)+B(29)+B(28)+B(26)+B(25)+B(24)+B(23)+B(22)+B(20)+B(19)+
+          B(18)+B(17)+B(15)+B(11)+B(7)+B(4)+B(3)+B(0), 51),
+ kDefPoly(UINT64_ZERO, B(51)+B(46)+B(43)+B(38)+B(37)+B(36)+B(34)+B(31)+B(27)+
+          B(26)+B(20)+B(17)+B(16)+B(15)+B(13)+B(12)+B(11)+B(9)+B(7)+B(5)+B(1)+
+          B(0), 52),
+ kDefPoly(UINT64_ZERO, B(50)+B(49)+B(47)+B(46)+B(44)+B(42)+B(41)+B(37)+B(36)+
+          B(35)+B(33)+B(29)+B(28)+B(26)+B(24)+B(23)+B(21)+B(20)+B(14)+B(13)+
+          B(12)+B(11)+B(10)+B(9)+B(8)+B(6)+B(3)+B(2)+B(1)+B(0), 53),
+ kDefPoly(UINT64_ZERO, B(52)+B(47)+B(46)+B(44)+B(43)+B(42)+B(40)+B(36)+B(32)+
+          B(31)+B(30)+B(29)+B(28)+B(26)+B(25)+B(24)+B(23)+B(22)+B(20)+B(19)+
+          B(17)+B(16)+B(15)+B(14)+B(13)+B(12)+B(11)+B(10)+B(7)+B(4)+B(2)+
+          B(0), 54),
+ kDefPoly(UINT64_ZERO, B(53)+B(50)+B(48)+B(47)+B(37)+B(35)+B(31)+B(30)+B(25)+
+          B(22)+B(21)+B(20)+B(19)+B(18)+B(15)+B(10)+B(8)+B(6)+B(3)+B(2)+B(1)+
+          B(0), 55),
+ kDefPoly(UINT64_ZERO, B(54)+B(52)+B(51)+B(49)+B(48)+B(42)+B(38)+B(37)+B(31)+
+          B(30)+B(27)+B(26)+B(24)+B(23)+B(22)+B(19)+B(16)+B(12)+B(11)+B(8)+
+          B(6)+B(4)+B(3)+B(0), 56),
+ kDefPoly(UINT64_ZERO, B(55)+B(54)+B(51)+B(49)+B(48)+B(47)+B(46)+B(44)+B(43)+
+          B(42)+B(41)+B(40)+B(39)+B(38)+B(32)+B(29)+B(27)+B(26)+B(23)+B(21)+
+          B(20)+B(15)+B(12)+B(7)+B(6)+B(5)+B(3)+B(0), 57),
+ kDefPoly(UINT64_ZERO, B(57)+B(54)+B(52)+B(47)+B(45)+B(42)+B(41)+B(40)+B(39)+
+          B(36)+B(34)+B(33)+B(31)+B(28)+B(26)+B(21)+B(20)+B(18)+B(17)+B(16)+
+          B(13)+B(11)+B(8)+B(7)+B(4)+B(2)+B(1)+B(0), 58),
+ kDefPoly(UINT64_ZERO, B(58)+B(56)+B(54)+B(49)+B(47)+B(46)+B(43)+B(40)+B(38)+
+          B(36)+B(35)+B(33)+B(32)+B(31)+B(30)+B(27)+B(24)+B(22)+B(21)+B(19)+
+          B(17)+B(16)+B(11)+B(10)+B(9)+B(8)+B(7)+B(4)+B(3)+B(2)+B(1)+B(0),
+          59),
+ kDefPoly(UINT64_ZERO, B(56)+B(54)+B(51)+B(46)+B(43)+B(42)+B(40)+B(39)+B(37)+
+          B(35)+B(34)+B(33)+B(32)+B(31)+B(30)+B(29)+B(27)+B(25)+B(22)+B(21)+
+          B(20)+B(19)+B(17)+B(16)+B(15)+B(14)+B(13)+B(12)+B(9)+B(7)+B(4)+
+          B(3)+B(1)+B(0), 60),
+ kDefPoly(UINT64_ZERO, B(59)+B(58)+B(57)+B(56)+B(54)+B(53)+B(50)+B(49)+B(47)+
+          B(44)+B(42)+B(41)+B(40)+B(37)+B(35)+B(34)+B(32)+B(30)+B(29)+B(27)+
+          B(26)+B(22)+B(21)+B(20)+B(17)+B(14)+B(13)+B(12)+B(8)+B(5)+B(4)+
+          B(0), 61),
+ kDefPoly(UINT64_ZERO, B(61)+B(59)+B(57)+B(55)+B(54)+B(53)+B(52)+B(51)+B(50)+
+          B(49)+B(48)+B(45)+B(44)+B(40)+B(37)+B(35)+B(32)+B(31)+B(29)+B(25)+
+          B(24)+B(23)+B(20)+B(17)+B(16)+B(15)+B(13)+B(12)+B(11)+B(10)+B(6)+
+          B(5)+B(2)+B(0), 62),
+ kDefPoly(UINT64_ZERO, B(62)+B(57)+B(56)+B(53)+B(52)+B(51)+B(50)+B(46)+B(41)+
+          B(38)+B(35)+B(34)+B(33)+B(31)+B(27)+B(25)+B(23)+B(21)+B(19)+B(18)+
+          B(17)+B(16)+B(13)+B(11)+B(7)+B(5)+B(1)+B(0), 63),
+ kDefPoly(UINT64_ZERO, B(62)+B(61)+B(60)+B(57)+B(55)+B(54)+B(53)+B(49)+B(48)+
+          B(46)+B(44)+B(42)+B(40)+B(39)+B(37)+B(36)+B(28)+B(27)+B(25)+B(23)+
+          B(22)+B(21)+B(17)+B(15)+B(13)+B(7)+B(6)+B(4)+B(2)+B(0), 64),
+ kDefPoly(UINT64_ZERO, B(63)+B(62)+B(59)+B(57)+B(54)+B(53)+B(51)+B(48)+
+          B(47)+B(46)+B(45)+B(44)+B(41)+B(40)+B(38)+B(36)+B(35)+B(28)+
+          B(25)+B(24)+B(21)+B(20)+B(18)+B(16)+B(15)+B(13)+B(11)+B(8)+B(7)+
+          B(3)+B(1)+B(0), 65),
+ kDefPoly(UINT64_ZERO, B(63)+B(58)+B(57)+B(56)+B(52)+B(51)+B(50)+B(44)+
+          B(41)+B(40)+B(36)+B(34)+B(32)+B(31)+B(27)+B(25)+B(23)+B(21)+
+          B(20)+B(19)+B(18)+B(17)+B(15)+B(14)+B(12)+B(11)+B(10)+B(8)+B(5)+
+          B(4)+B(3)+B(0), 66),
+ kDefPoly(B(66), B(62)+B(60)+B(59)+B(58)+B(57)+B(56)+B(55)+B(54)+B(52)+
+          B(50)+B(47)+B(46)+B(45)+B(43)+B(42)+B(41)+B(38)+B(37)+B(36)+
+          B(33)+B(32)+B(31)+B(30)+B(28)+B(27)+B(26)+B(24)+B(21)+B(18)+
+          B(17)+B(14)+B(13)+B(12)+B(11)+B(10)+B(7)+B(4)+B(3)+B(0), 67),
+ kDefPoly(B(67)+B(66), B(63)+B(61)+B(57)+B(55)+B(51)+B(47)+B(45)+B(43)+
+          B(42)+B(41)+B(40)+B(39)+B(32)+B(31)+B(30)+B(28)+B(27)+B(25)+
+          B(19)+B(18)+B(17)+B(15)+B(11)+B(9)+B(8)+B(7)+B(6)+B(5)+B(4)+B(3)+
+          B(1)+B(0), 68),
+ kDefPoly(B(68), B(60)+B(57)+B(55)+B(54)+B(52)+B(50)+B(49)+B(48)+B(44)+
+          B(40)+B(38)+B(37)+B(33)+B(31)+B(28)+B(25)+B(22)+B(21)+B(20)+
+          B(19)+B(18)+B(17)+B(13)+B(12)+B(9)+B(8)+B(6)+B(5)+B(4)+B(1)+
+          B(0), 69),
+ kDefPoly(B(69)+B(68)+B(67)+B(66), B(63)+B(62)+B(61)+B(59)+B(51)+B(49)+
+          B(48)+B(46)+B(45)+B(42)+B(40)+B(38)+B(36)+B(35)+B(33)+B(32)+
+          B(30)+B(29)+B(27)+B(23)+B(22)+B(21)+B(16)+B(12)+B(5)+B(4)+B(1)+
+          B(0), 70),
+ kDefPoly(B(70)+B(69)+B(68)+B(64), B(63)+B(62)+B(61)+B(60)+B(59)+B(57)+
+          B(56)+B(55)+B(54)+B(53)+B(51)+B(50)+B(47)+B(44)+B(43)+B(41)+
+          B(39)+B(37)+B(36)+B(33)+B(32)+B(26)+B(25)+B(24)+B(23)+B(21)+
+          B(20)+B(19)+B(17)+B(12)+B(11)+B(10)+B(8)+B(6)+B(5)+B(4)+B(2)+
+          B(0), 71),
+ kDefPoly(B(71)+B(69)+B(68)+B(65)+B(64), B(62)+B(61)+B(59)+B(58)+B(55)+
+          B(53)+B(51)+B(49)+B(48)+B(47)+B(43)+B(40)+B(38)+B(37)+B(36)+
+          B(35)+B(33)+B(32)+B(31)+B(30)+B(29)+B(26)+B(24)+B(19)+B(18)+
+          B(15)+B(13)+B(9)+B(7)+B(6)+B(3)+B(1)+B(0), 72),
+ kDefPoly(B(71)+B(70)+B(69)+B(67)+B(65), B(63)+B(62)+B(61)+B(58)+B(57)+
+          B(56)+B(55)+B(52)+B(51)+B(50)+B(49)+B(46)+B(45)+B(44)+B(43)+
+          B(41)+B(37)+B(36)+B(34)+B(33)+B(27)+B(26)+B(25)+B(21)+B(19)+
+          B(18)+B(16)+B(15)+B(14)+B(13)+B(9)+B(8)+B(6)+B(5)+B(2)+B(1)+
+          B(0), 73),
+ kDefPoly(B(73)+B(71)+B(70)+B(65)+B(64), B(62)+B(60)+B(55)+B(54)+B(52)+
+          B(50)+B(48)+B(47)+B(46)+B(44)+B(41)+B(40)+B(31)+B(29)+B(28)+
+          B(27)+B(26)+B(24)+B(23)+B(22)+B(20)+B(16)+B(12)+B(9)+B(6)+B(5)+
+          B(4)+B(2)+B(0), 74),
+ kDefPoly(B(74)+B(73)+B(72)+B(67)+B(64), B(63)+B(61)+B(60)+B(58)+B(57)+
+          B(56)+B(54)+B(52)+B(51)+B(50)+B(44)+B(43)+B(42)+B(41)+B(40)+
+          B(39)+B(38)+B(36)+B(35)+B(33)+B(32)+B(31)+B(29)+B(28)+B(26)+
+          B(23)+B(21)+B(19)+B(18)+B(16)+B(15)+B(13)+B(12)+B(11)+B(7)+B(6)+
+          B(5)+B(4)+B(3)+B(2)+B(0), 75),
+ kDefPoly(B(75)+B(74)+B(71)+B(70)+B(66), B(63)+B(61)+B(59)+B(57)+B(53)+
+          B(50)+B(49)+B(48)+B(44)+B(43)+B(42)+B(37)+B(33)+B(30)+B(27)+
+          B(24)+B(23)+B(20)+B(18)+B(15)+B(12)+B(11)+B(9)+B(7)+B(6)+B(4)+
+          B(3)+B(2)+B(0), 76),
+ kDefPoly(B(73)+B(71)+B(70)+B(68)+B(67)+B(66)+B(65), B(63)+B(60)+B(59)+
+          B(58)+B(57)+B(54)+B(49)+B(47)+B(46)+B(45)+B(43)+B(41)+B(38)+
+          B(34)+B(33)+B(31)+B(30)+B(29)+B(27)+B(25)+B(24)+B(21)+B(20)+
+          B(19)+B(16)+B(15)+B(14)+B(13)+B(10)+B(8)+B(6)+B(5)+B(4)+B(2)+
+          B(0), 77),
+ kDefPoly(B(77)+B(76)+B(75)+B(74)+B(70)+B(66)+B(65)+B(64), B(63)+B(62)+
+          B(60)+B(58)+B(57)+B(55)+B(52)+B(51)+B(44)+B(41)+B(39)+B(38)+
+          B(35)+B(31)+B(30)+B(29)+B(26)+B(22)+B(21)+B(20)+B(19)+B(15)+
+          B(13)+B(11)+B(6)+B(4)+B(1)+B(0), 78),
+ kDefPoly(B(78)+B(76)+B(75)+B(71)+B(68)+B(67)+B(65), B(63)+B(61)+B(60)+
+          B(55)+B(54)+B(51)+B(50)+B(48)+B(44)+B(42)+B(41)+B(40)+B(38)+
+          B(35)+B(34)+B(32)+B(28)+B(26)+B(23)+B(22)+B(19)+B(15)+B(13)+
+          B(12)+B(8)+B(7)+B(5)+B(2)+B(0), 79),
+ kDefPoly(B(77)+B(76)+B(75)+B(73)+B(70)+B(66), B(63)+B(61)+B(60)+B(59)+
+          B(56)+B(54)+B(53)+B(52)+B(50)+B(44)+B(43)+B(40)+B(39)+B(38)+
+          B(35)+B(34)+B(33)+B(29)+B(28)+B(27)+B(26)+B(25)+B(24)+B(23)+
+          B(22)+B(21)+B(20)+B(18)+B(16)+B(13)+B(12)+B(11)+B(10)+B(8)+B(7)+
+          B(6)+B(3)+B(2)+B(1)+B(0), 80),
+ kDefPoly(B(78)+B(77)+B(76)+B(75)+B(73)+B(71)+B(67)+B(66)+B(65)+
+          B(64), B(61)+B(54)+B(53)+B(52)+B(49)+B(47)+B(44)+B(41)+B(40)+
+          B(35)+B(33)+B(31)+B(30)+B(28)+B(27)+B(26)+B(25)+B(22)+B(21)+
+          B(20)+B(16)+B(15)+B(13)+B(12)+B(11)+B(0), 81),
+ kDefPoly(B(81)+B(80)+B(79)+B(77)+B(76)+B(74)+B(73)+B(72)+B(68)+B(67)+
+          B(66)+B(64), B(62)+B(51)+B(50)+B(49)+B(47)+B(46)+B(45)+B(43)+
+          B(41)+B(38)+B(37)+B(34)+B(32)+B(30)+B(27)+B(26)+B(25)+B(24)+
+          B(23)+B(22)+B(20)+B(19)+B(16)+B(15)+B(13)+B(12)+B(9)+B(7)+B(5)+
+          B(4)+B(1)+B(0), 82),
+ kDefPoly(B(82)+B(81)+B(79)+B(78)+B(77)+B(75)+B(72)+B(71)+B(69)+B(68)+
+          B(67)+B(66)+B(65)+B(64), B(60)+B(58)+B(57)+B(56)+B(53)+B(52)+
+          B(51)+B(49)+B(48)+B(45)+B(43)+B(41)+B(40)+B(39)+B(38)+B(37)+
+          B(36)+B(35)+B(33)+B(26)+B(24)+B(21)+B(19)+B(16)+B(13)+B(12)+
+          B(11)+B(9)+B(7)+B(5)+B(4)+B(3)+B(1)+B(0), 83),
+ kDefPoly(B(79)+B(77)+B(73)+B(72)+B(71)+B(66)+B(64), B(62)+B(61)+B(59)+
+          B(58)+B(57)+B(56)+B(53)+B(52)+B(51)+B(48)+B(47)+B(46)+B(45)+
+          B(43)+B(42)+B(41)+B(38)+B(37)+B(35)+B(33)+B(32)+B(29)+B(24)+
+          B(22)+B(17)+B(16)+B(15)+B(13)+B(11)+B(10)+B(9)+B(7)+B(6)+B(5)+
+          B(0), 84),
+ kDefPoly(B(83)+B(78)+B(76)+B(73)+B(70)+B(69)+B(68)+B(67)+B(66)+
+          B(64), B(62)+B(61)+B(60)+B(59)+B(54)+B(51)+B(50)+B(48)+B(47)+
+          B(42)+B(41)+B(40)+B(38)+B(37)+B(36)+B(34)+B(31)+B(30)+B(28)+
+          B(27)+B(26)+B(24)+B(22)+B(21)+B(20)+B(19)+B(18)+B(16)+B(15)+
+          B(14)+B(13)+B(12)+B(10)+B(6)+B(4)+B(0), 85),
+ kDefPoly(B(84)+B(77)+B(76)+B(75)+B(71)+B(70)+B(69)+B(67)+B(65), B(63)+
+          B(62)+B(59)+B(58)+B(57)+B(55)+B(53)+B(52)+B(51)+B(48)+B(47)+
+          B(45)+B(43)+B(40)+B(38)+B(36)+B(34)+B(33)+B(31)+B(27)+B(25)+
+          B(24)+B(23)+B(22)+B(19)+B(15)+B(13)+B(12)+B(11)+B(8)+B(6)+B(4)+
+          B(0), 86),
+ kDefPoly(B(85)+B(84)+B(83)+B(81)+B(80)+B(78)+B(73)+B(72)+B(70)+B(68)+
+          B(67)+B(64), B(61)+B(60)+B(58)+B(57)+B(55)+B(52)+B(50)+B(49)+
+          B(47)+B(44)+B(37)+B(36)+B(35)+B(34)+B(32)+B(31)+B(30)+B(25)+
+          B(24)+B(23)+B(20)+B(13)+B(12)+B(11)+B(10)+B(9)+B(7)+B(6)+B(4)+
+          B(3)+B(2)+B(0), 87),
+ kDefPoly(B(86)+B(85)+B(84)+B(83)+B(82)+B(80)+B(77)+B(74)+B(70)+B(69)+
+          B(65), B(63)+B(60)+B(59)+B(57)+B(56)+B(55)+B(53)+B(50)+B(49)+
+          B(48)+B(45)+B(42)+B(41)+B(40)+B(39)+B(38)+B(37)+B(36)+B(25)+
+          B(21)+B(19)+B(13)+B(11)+B(8)+B(5)+B(4)+B(2)+B(1)+B(0), 88),
+ kDefPoly(B(86)+B(85)+B(83)+B(82)+B(81)+B(78)+B(77)+B(74)+B(73)+B(72)+
+          B(70)+B(69)+B(68)+B(65)+B(64), B(59)+B(57)+B(55)+B(54)+B(51)+
+          B(50)+B(46)+B(45)+B(44)+B(43)+B(42)+B(40)+B(38)+B(37)+B(33)+
+          B(31)+B(30)+B(29)+B(28)+B(27)+B(23)+B(22)+B(21)+B(20)+B(18)+
+          B(17)+B(16)+B(15)+B(10)+B(9)+B(3)+B(1)+B(0), 89),
+ kDefPoly(B(86)+B(83)+B(82)+B(80)+B(79)+B(73)+B(70)+B(69)+B(67)+
+          B(64), B(63)+B(62)+B(61)+B(57)+B(56)+B(54)+B(51)+B(49)+B(47)+
+          B(46)+B(45)+B(40)+B(39)+B(37)+B(35)+B(33)+B(32)+B(29)+B(28)+
+          B(27)+B(25)+B(24)+B(23)+B(22)+B(21)+B(20)+B(19)+B(18)+B(17)+
+          B(15)+B(9)+B(8)+B(7)+B(3)+B(2)+B(0), 90),
+ kDefPoly(B(90)+B(89)+B(84)+B(81)+B(80)+B(78)+B(74)+B(73)+B(71)+B(68)+
+          B(64), B(60)+B(59)+B(58)+B(57)+B(55)+B(54)+B(52)+B(50)+B(49)+
+          B(47)+B(45)+B(42)+B(41)+B(39)+B(38)+B(36)+B(32)+B(28)+B(25)+
+          B(21)+B(20)+B(19)+B(15)+B(12)+B(11)+B(9)+B(8)+B(3)+
+          B(0), 91),
+ kDefPoly(B(91)+B(89)+B(88)+B(87)+B(86)+B(85)+B(84)+B(83)+B(80)+B(78)+
+          B(76)+B(72)+B(70)+B(68), B(63)+B(62)+B(61)+B(59)+B(57)+B(56)+
+          B(52)+B(51)+B(50)+B(49)+B(43)+B(40)+B(39)+B(37)+B(36)+B(35)+
+          B(34)+B(33)+B(32)+B(26)+B(25)+B(24)+B(23)+B(22)+B(18)+B(15)+
+          B(12)+B(11)+B(9)+B(7)+B(6)+B(3)+B(1)+B(0), 92),
+ kDefPoly(B(86)+B(85)+B(83)+B(82)+B(79)+B(78)+B(77)+B(75)+B(74)+B(73)+
+          B(66)+B(64), B(59)+B(57)+B(56)+B(55)+B(54)+B(52)+B(51)+B(40)+
+          B(38)+B(36)+B(34)+B(33)+B(28)+B(27)+B(26)+B(25)+B(23)+B(22)+
+          B(21)+B(20)+B(19)+B(18)+B(16)+B(15)+B(14)+B(13)+B(12)+B(11)+B(8)+
+          B(7)+B(6)+B(5)+B(4)+B(0), 93),
+ kDefPoly(B(93)+B(92)+B(91)+B(89)+B(88)+B(87)+B(86)+B(81)+B(80)+B(75)+
+          B(66)+B(64), B(62)+B(61)+B(60)+B(59)+B(58)+B(57)+B(56)+B(54)+
+          B(48)+B(47)+B(46)+B(45)+B(44)+B(42)+B(41)+B(38)+B(37)+B(36)+
+          B(34)+B(33)+B(31)+B(30)+B(27)+B(26)+B(25)+B(22)+B(13)+B(12)+
+          B(11)+B(10)+B(8)+B(7)+B(4)+B(0), 94),
+ kDefPoly(B(94)+B(88)+B(87)+B(82)+B(79)+B(78)+B(76)+B(73)+B(65)+
+          B(64), B(62)+B(61)+B(60)+B(59)+B(58)+B(57)+B(53)+B(51)+B(50)+
+          B(49)+B(48)+B(47)+B(46)+B(44)+B(40)+B(36)+B(34)+B(33)+B(30)+
+          B(28)+B(27)+B(25)+B(22)+B(19)+B(18)+B(17)+B(16)+B(14)+B(7)+B(5)+
+          B(3)+B(2)+B(1)+B(0), 95),
+ kDefPoly(B(92)+B(89)+B(88)+B(86)+B(83)+B(79)+B(78)+B(76)+B(75)+B(74)+
+          B(72)+B(70)+B(67)+B(66), B(63)+B(60)+B(57)+B(55)+B(53)+B(51)+
+          B(47)+B(46)+B(44)+B(43)+B(42)+B(39)+B(38)+B(36)+B(34)+B(32)+
+          B(31)+B(30)+B(27)+B(26)+B(25)+B(22)+B(21)+B(19)+B(17)+B(13)+
+          B(11)+B(10)+B(9)+B(8)+B(7)+B(4)+B(1)+B(0), 96),
+ kDefPoly(B(96)+B(94)+B(93)+B(91)+B(89)+B(87)+B(85)+B(83)+B(81)+B(78)+
+          B(76)+B(74)+B(73)+B(68)+B(67)+B(64), B(62)+B(61)+B(57)+B(55)+
+          B(54)+B(53)+B(49)+B(47)+B(41)+B(38)+B(35)+B(33)+B(28)+B(27)+
+          B(24)+B(23)+B(21)+B(19)+B(18)+B(17)+B(15)+B(13)+B(12)+B(11)+B(8)+
+          B(6)+B(4)+B(3)+B(1)+B(0), 97),
+ kDefPoly(B(97)+B(93)+B(92)+B(91)+B(90)+B(87)+B(83)+B(82)+B(80)+B(77)+
+          B(76)+B(75)+B(74)+B(73)+B(72)+B(70)+B(69)+B(68)+B(66)+B(65)+
+          B(64), B(63)+B(62)+B(61)+B(60)+B(59)+B(57)+B(55)+B(53)+B(50)+
+          B(49)+B(48)+B(45)+B(44)+B(43)+B(42)+B(40)+B(38)+B(36)+B(35)+
+          B(34)+B(28)+B(27)+B(24)+B(22)+B(21)+B(18)+B(17)+B(16)+B(15)+
+          B(14)+B(12)+B(11)+B(9)+B(8)+B(2)+B(1)+B(0), 98),
+ kDefPoly(B(96)+B(94)+B(92)+B(86)+B(85)+B(84)+B(78)+B(77)+B(76)+B(75)+
+          B(73)+B(71)+B(69)+B(68)+B(65), B(61)+B(59)+B(57)+B(56)+B(54)+
+          B(50)+B(47)+B(46)+B(44)+B(41)+B(38)+B(36)+B(35)+B(34)+B(33)+
+          B(32)+B(29)+B(27)+B(26)+B(25)+B(23)+B(22)+B(21)+B(19)+B(17)+
+          B(16)+B(11)+B(9)+B(7)+B(6)+B(3)+B(2)+B(0), 99),
+ kDefPoly(B(99)+B(96)+B(95)+B(93)+B(92)+B(88)+B(87)+B(83)+B(78)+B(77)+
+          B(76)+B(75)+B(74)+B(73)+B(70)+B(66)+B(64), B(63)+B(62)+B(60)+
+          B(59)+B(57)+B(56)+B(53)+B(50)+B(47)+B(41)+B(39)+B(38)+B(37)+
+          B(34)+B(25)+B(23)+B(21)+B(20)+B(19)+B(18)+B(17)+B(16)+B(13)+B(9)+
+          B(8)+B(6)+B(5)+B(1)+B(0), 100),
+ kDefPoly(B(100)+B(98)+B(97)+B(95)+B(93)+B(92)+B(91)+B(89)+B(87)+B(85)+
+          B(84)+B(82)+B(81)+B(80)+B(79)+B(76)+B(68)+B(66)+B(65), B(63)+
+          B(62)+B(59)+B(57)+B(52)+B(51)+B(50)+B(47)+B(46)+B(45)+B(42)+
+          B(41)+B(40)+B(39)+B(38)+B(37)+B(36)+B(34)+B(32)+B(31)+B(30)+
+          B(24)+B(22)+B(21)+B(20)+B(18)+B(17)+B(16)+B(14)+B(12)+B(11)+
+          B(10)+B(8)+B(7)+B(5)+B(4)+B(2)+B(1)+B(0), 101),
+ kDefPoly(B(101)+B(99)+B(97)+B(96)+B(92)+B(89)+B(88)+B(87)+B(86)+B(84)+
+          B(82)+B(81)+B(80)+B(78)+B(77)+B(76)+B(75)+B(74)+B(73)+
+          B(69), B(60)+B(59)+B(57)+B(56)+B(55)+B(54)+B(53)+B(51)+B(50)+
+          B(49)+B(47)+B(45)+B(43)+B(41)+B(35)+B(34)+B(32)+B(31)+B(29)+
+          B(27)+B(26)+B(25)+B(24)+B(21)+B(13)+B(12)+B(9)+B(8)+B(6)+B(5)+
+          B(3)+B(0), 102),
+ kDefPoly(B(101)+B(98)+B(97)+B(96)+B(94)+B(93)+B(92)+B(90)+B(89)+B(88)+
+          B(87)+B(85)+B(83)+B(81)+B(80)+B(79)+B(76)+B(75)+B(71)+B(70)+
+          B(69)+B(66), B(63)+B(62)+B(60)+B(59)+B(58)+B(56)+B(54)+B(53)+
+          B(48)+B(45)+B(43)+B(42)+B(41)+B(37)+B(36)+B(32)+B(31)+B(30)+
+          B(27)+B(25)+B(23)+B(22)+B(19)+B(16)+B(15)+B(11)+B(9)+B(5)+B(3)+
+          B(0), 103),
+ kDefPoly(B(98)+B(97)+B(95)+B(94)+B(91)+B(89)+B(88)+B(86)+B(85)+B(84)+
+          B(81)+B(79)+B(78)+B(76)+B(74)+B(73)+B(70)+B(69)+B(68)+B(67)+
+          B(66)+B(64), B(59)+B(53)+B(52)+B(51)+B(48)+B(46)+B(45)+B(43)+
+          B(37)+B(34)+B(33)+B(31)+B(30)+B(28)+B(25)+B(22)+B(21)+B(20)+
+          B(19)+B(14)+B(10)+B(8)+B(4)+B(2)+B(1)+B(0), 104),
+ kDefPoly(B(103)+B(100)+B(99)+B(98)+B(94)+B(90)+B(89)+B(86)+B(84)+B(82)+
+          B(79)+B(76)+B(74)+B(73)+B(72)+B(71)+B(70)+B(69)+B(67)+
+          B(66), B(63)+B(62)+B(59)+B(58)+B(57)+B(55)+B(51)+B(49)+B(48)+
+          B(47)+B(46)+B(43)+B(42)+B(38)+B(36)+B(34)+B(33)+B(31)+B(30)+
+          B(29)+B(28)+B(27)+B(24)+B(21)+B(20)+B(18)+B(17)+B(16)+B(14)+
+          B(13)+B(11)+B(9)+B(7)+B(6)+B(5)+B(0), 105),
+ kDefPoly(B(105)+B(104)+B(103)+B(102)+B(100)+B(98)+B(94)+B(93)+B(92)+B(91)+
+          B(90)+B(89)+B(87)+B(86)+B(85)+B(83)+B(82)+B(81)+B(79)+B(77)+
+          B(69)+B(68)+B(67)+B(64), B(61)+B(60)+B(59)+B(58)+B(56)+B(55)+
+          B(53)+B(50)+B(48)+B(44)+B(40)+B(38)+B(37)+B(36)+B(35)+B(34)+
+          B(33)+B(30)+B(29)+B(26)+B(22)+B(20)+B(13)+B(10)+B(8)+B(7)+B(5)+
+          B(0), 106),
+ kDefPoly(B(105)+B(101)+B(100)+B(98)+B(97)+B(96)+B(93)+B(92)+B(91)+B(90)+
+          B(87)+B(86)+B(81)+B(79)+B(77)+B(75)+B(74)+B(72)+B(68)+B(67)+
+          B(64), B(63)+B(62)+B(61)+B(60)+B(59)+B(58)+B(54)+B(53)+B(52)+
+          B(50)+B(48)+B(47)+B(45)+B(42)+B(41)+B(38)+B(32)+B(29)+B(27)+
+          B(26)+B(24)+B(21)+B(19)+B(18)+B(16)+B(15)+B(14)+B(13)+B(12)+
+          B(10)+B(7)+B(6)+B(4)+B(1)+B(0), 107),
+ kDefPoly(B(106)+B(105)+B(102)+B(100)+B(97)+B(95)+B(90)+B(89)+B(88)+B(86)+
+          B(83)+B(82)+B(81)+B(79)+B(78)+B(75)+B(72)+B(66)+B(64), B(63)+
+          B(62)+B(59)+B(58)+B(56)+B(54)+B(52)+B(51)+B(50)+B(48)+B(46)+
+          B(45)+B(44)+B(42)+B(40)+B(37)+B(36)+B(35)+B(33)+B(29)+B(27)+
+          B(22)+B(19)+B(17)+B(14)+B(12)+B(11)+B(10)+B(9)+B(8)+B(7)+B(6)+
+          B(5)+B(3)+B(0), 108),
+ kDefPoly(B(108)+B(102)+B(101)+B(100)+B(99)+B(98)+B(96)+B(95)+B(94)+B(90)+
+          B(89)+B(88)+B(87)+B(84)+B(83)+B(81)+B(80)+B(77)+B(76)+B(75)+
+          B(71)+B(67)+B(65), B(63)+B(61)+B(60)+B(54)+B(50)+B(49)+B(48)+
+          B(43)+B(40)+B(39)+B(38)+B(36)+B(34)+B(29)+B(28)+B(27)+B(22)+
+          B(21)+B(19)+B(16)+B(14)+B(13)+B(12)+B(10)+B(9)+B(7)+B(6)+B(5)+
+          B(3)+B(2)+B(0), 109),
+ kDefPoly(B(109)+B(108)+B(107)+B(102)+B(101)+B(98)+B(97)+B(96)+B(94)+B(92)+
+          B(91)+B(90)+B(88)+B(87)+B(85)+B(84)+B(83)+B(82)+B(81)+B(80)+
+          B(79)+B(78)+B(74)+B(73)+B(71)+B(70)+B(69)+B(66)+B(64), B(61)+
+          B(58)+B(57)+B(56)+B(50)+B(49)+B(46)+B(44)+B(43)+B(41)+B(36)+
+          B(35)+B(34)+B(30)+B(29)+B(26)+B(25)+B(24)+B(22)+B(21)+B(17)+
+          B(13)+B(11)+B(9)+B(4)+B(1)+B(0), 110),
+ kDefPoly(B(110)+B(109)+B(105)+B(98)+B(97)+B(95)+B(94)+B(93)+B(92)+B(90)+
+          B(88)+B(84)+B(83)+B(82)+B(80)+B(77)+B(75)+B(72)+B(71)+B(70)+
+          B(69)+B(66), B(63)+B(61)+B(60)+B(59)+B(57)+B(56)+B(55)+B(52)+
+          B(51)+B(50)+B(49)+B(47)+B(43)+B(40)+B(36)+B(35)+B(34)+B(33)+
+          B(31)+B(27)+B(26)+B(21)+B(20)+B(19)+B(17)+B(16)+B(12)+B(8)+B(6)+
+          B(4)+B(3)+B(2)+B(1)+B(0), 111),
+ kDefPoly(B(109)+B(107)+B(106)+B(104)+B(100)+B(98)+B(96)+B(95)+B(94)+B(92)+
+          B(91)+B(90)+B(89)+B(88)+B(86)+B(84)+B(81)+B(79)+B(78)+B(77)+
+          B(75)+B(73)+B(71)+B(70)+B(69)+B(67)+B(64), B(63)+B(62)+B(61)+
+          B(60)+B(58)+B(56)+B(54)+B(52)+B(51)+B(49)+B(48)+B(45)+B(44)+
+          B(39)+B(38)+B(37)+B(36)+B(35)+B(34)+B(32)+B(30)+B(26)+B(25)+
+          B(24)+B(23)+B(22)+B(21)+B(19)+B(16)+B(15)+B(11)+B(10)+B(9)+B(8)+
+          B(3)+B(1)+B(0), 112),
+ kDefPoly(B(111)+B(107)+B(102)+B(100)+B(99)+B(98)+B(97)+B(96)+B(95)+B(94)+
+          B(93)+B(92)+B(87)+B(86)+B(82)+B(81)+B(80)+B(79)+B(77)+B(76)+
+          B(75)+B(72)+B(69)+B(64), B(61)+B(58)+B(56)+B(54)+B(53)+B(52)+
+          B(51)+B(49)+B(46)+B(43)+B(40)+B(39)+B(37)+B(36)+B(35)+B(34)+
+          B(33)+B(31)+B(29)+B(24)+B(22)+B(21)+B(20)+B(15)+B(14)+B(12)+
+          B(10)+B(6)+B(1)+B(0), 113),
+ kDefPoly(B(112)+B(111)+B(110)+B(104)+B(102)+B(101)+B(100)+B(92)+B(89)+
+          B(87)+B(83)+B(82)+B(80)+B(79)+B(75)+B(74)+B(73)+B(72)+B(71)+
+          B(70)+B(68)+B(67)+B(65), B(60)+B(59)+B(57)+B(56)+B(55)+B(52)+
+          B(50)+B(47)+B(44)+B(41)+B(36)+B(35)+B(30)+B(29)+B(26)+B(25)+
+          B(24)+B(21)+B(18)+B(17)+B(16)+B(14)+B(12)+B(10)+B(7)+B(6)+
+          B(0), 114),
+ kDefPoly(B(114)+B(112)+B(111)+B(110)+B(108)+B(107)+B(103)+B(102)+B(98)+
+          B(97)+B(96)+B(90)+B(88)+B(87)+B(86)+B(83)+B(82)+B(80)+B(79)+
+          B(77)+B(75)+B(70)+B(66)+B(65)+B(64), B(61)+B(60)+B(59)+B(58)+
+          B(57)+B(53)+B(52)+B(51)+B(50)+B(47)+B(45)+B(43)+B(39)+B(38)+
+          B(33)+B(32)+B(31)+B(29)+B(27)+B(21)+B(17)+B(14)+B(12)+B(10)+B(7)+
+          B(4)+B(2)+B(1)+B(0), 115),
+ kDefPoly(B(113)+B(110)+B(108)+B(106)+B(105)+B(102)+B(101)+B(100)+B(98)+
+          B(96)+B(92)+B(89)+B(87)+B(86)+B(84)+B(81)+B(79)+B(78)+B(76)+
+          B(75)+B(73)+B(72)+B(71)+B(70)+B(67)+B(64), B(63)+B(62)+B(61)+
+          B(52)+B(47)+B(45)+B(44)+B(42)+B(40)+B(39)+B(35)+B(34)+B(33)+
+          B(31)+B(29)+B(25)+B(18)+B(15)+B(14)+B(10)+B(8)+B(6)+B(1)+
+          B(0), 116),
+ kDefPoly(B(113)+B(111)+B(110)+B(109)+B(107)+B(106)+B(103)+B(102)+B(100)+
+          B(96)+B(95)+B(94)+B(91)+B(90)+B(89)+B(86)+B(82)+B(81)+B(78)+
+          B(77)+B(76)+B(75)+B(74)+B(73)+B(70)+B(67)+B(66), B(63)+B(61)+
+          B(59)+B(57)+B(56)+B(55)+B(53)+B(52)+B(51)+B(50)+B(47)+B(45)+
+          B(42)+B(40)+B(37)+B(35)+B(32)+B(30)+B(29)+B(25)+B(22)+B(21)+
+          B(20)+B(19)+B(16)+B(15)+B(14)+B(12)+B(8)+B(5)+B(0), 117),
+ kDefPoly(B(117)+B(113)+B(110)+B(108)+B(105)+B(104)+B(103)+B(102)+B(99)+
+          B(98)+B(97)+B(94)+B(93)+B(91)+B(90)+B(89)+B(85)+B(84)+B(82)+
+          B(81)+B(79)+B(78)+B(77)+B(74)+B(73)+B(69)+B(67)+B(64), B(63)+
+          B(62)+B(61)+B(57)+B(55)+B(51)+B(50)+B(46)+B(45)+B(43)+B(42)+
+          B(41)+B(37)+B(33)+B(32)+B(30)+B(27)+B(26)+B(21)+B(19)+B(18)+
+          B(17)+B(15)+B(14)+B(12)+B(10)+B(8)+B(7)+B(3)+B(2)+B(1)+
+          B(0), 118),
+ kDefPoly(B(118)+B(111)+B(109)+B(107)+B(106)+B(105)+B(104)+B(101)+B(99)+
+          B(98)+B(97)+B(94)+B(92)+B(91)+B(89)+B(83)+B(82)+B(80)+B(79)+
+          B(67)+B(66), B(62)+B(61)+B(60)+B(58)+B(57)+B(52)+B(48)+B(46)+
+          B(44)+B(42)+B(40)+B(39)+B(38)+B(36)+B(34)+B(33)+B(32)+B(29)+
+          B(23)+B(22)+B(20)+B(19)+B(18)+B(15)+B(13)+B(12)+B(11)+B(6)+B(5)+
+          B(4)+B(3)+B(1)+B(0), 119),
+ kDefPoly(B(116)+B(115)+B(113)+B(112)+B(110)+B(107)+B(106)+B(104)+B(103)+
+          B(101)+B(100)+B(99)+B(98)+B(90)+B(89)+B(88)+B(87)+B(82)+B(80)+
+          B(79)+B(77)+B(76)+B(75)+B(74)+B(73)+B(71)+B(70)+B(68)+B(65)+
+          B(64), B(63)+B(62)+B(59)+B(55)+B(54)+B(48)+B(47)+B(45)+B(44)+
+          B(40)+B(39)+B(38)+B(35)+B(33)+B(29)+B(27)+B(26)+B(25)+B(24)+
+          B(23)+B(22)+B(21)+B(18)+B(17)+B(15)+B(13)+B(12)+B(10)+B(8)+B(3)+
+          B(2)+B(0), 120),
+ kDefPoly(B(118)+B(117)+B(114)+B(113)+B(112)+B(110)+B(109)+B(104)+B(103)+
+          B(101)+B(99)+B(97)+B(96)+B(95)+B(93)+B(92)+B(91)+B(90)+B(89)+
+          B(87)+B(85)+B(84)+B(82)+B(81)+B(79)+B(73)+B(72)+B(68)+B(67)+
+          B(66)+B(64), B(60)+B(58)+B(57)+B(56)+B(54)+B(53)+B(52)+B(51)+
+          B(49)+B(48)+B(47)+B(45)+B(44)+B(38)+B(37)+B(36)+B(35)+B(33)+
+          B(32)+B(31)+B(30)+B(27)+B(26)+B(24)+B(23)+B(22)+B(20)+B(19)+
+          B(18)+B(16)+B(15)+B(12)+B(6)+B(5)+B(4)+B(2)+B(0), 121),
+ kDefPoly(B(121)+B(118)+B(114)+B(112)+B(109)+B(106)+B(103)+B(102)+B(101)+
+          B(100)+B(97)+B(95)+B(90)+B(89)+B(87)+B(83)+B(81)+B(80)+B(79)+
+          B(78)+B(77)+B(76)+B(75)+B(74)+B(72)+B(71)+B(70)+B(69)+B(68)+
+          B(66)+B(64), B(61)+B(57)+B(51)+B(50)+B(47)+B(46)+B(43)+B(39)+
+          B(38)+B(37)+B(36)+B(34)+B(33)+B(32)+B(30)+B(28)+B(27)+B(24)+
+          B(22)+B(20)+B(18)+B(17)+B(14)+B(12)+B(11)+B(9)+B(7)+B(2)+
+          B(0), 122),
+ kDefPoly(B(122)+B(121)+B(120)+B(119)+B(118)+B(117)+B(116)+B(113)+B(112)+
+          B(111)+B(109)+B(106)+B(105)+B(103)+B(100)+B(98)+B(97)+B(95)+
+          B(93)+B(92)+B(90)+B(87)+B(86)+B(85)+B(83)+B(81)+B(78)+B(77)+
+          B(75)+B(74)+B(73)+B(72)+B(71)+B(70)+B(69)+B(68)+B(67)+B(65)+
+          B(64), B(63)+B(62)+B(60)+B(55)+B(52)+B(51)+B(49)+B(47)+B(45)+
+          B(43)+B(42)+B(41)+B(37)+B(36)+B(35)+B(34)+B(32)+B(28)+B(27)+
+          B(26)+B(24)+B(23)+B(21)+B(20)+B(16)+B(13)+B(10)+B(9)+B(8)+B(7)+
+          B(5)+B(2)+B(0), 123),
+ kDefPoly(B(123)+B(121)+B(120)+B(118)+B(117)+B(116)+B(115)+B(112)+B(111)+
+          B(110)+B(109)+B(107)+B(104)+B(102)+B(101)+B(100)+B(99)+B(98)+
+          B(97)+B(94)+B(90)+B(87)+B(86)+B(84)+B(83)+B(82)+B(79)+B(75)+
+          B(72)+B(71)+B(70)+B(64), B(63)+B(56)+B(54)+B(51)+B(50)+B(47)+
+          B(45)+B(44)+B(42)+B(39)+B(38)+B(36)+B(34)+B(33)+B(29)+B(26)+
+          B(24)+B(20)+B(16)+B(14)+B(11)+B(10)+B(8)+B(7)+B(6)+B(4)+B(2)+
+          B(0), 124),
+ kDefPoly(B(124)+B(123)+B(121)+B(119)+B(118)+B(116)+B(115)+B(114)+B(107)+
+          B(105)+B(104)+B(103)+B(102)+B(99)+B(98)+B(96)+B(94)+B(93)+B(89)+
+          B(83)+B(82)+B(81)+B(80)+B(79)+B(78)+B(75)+B(74)+B(73)+B(72)+
+          B(70)+B(69)+B(68)+B(64), B(63)+B(59)+B(56)+B(55)+B(52)+B(51)+
+          B(50)+B(49)+B(48)+B(44)+B(42)+B(38)+B(37)+B(36)+B(33)+B(31)+
+          B(29)+B(27)+B(26)+B(25)+B(23)+B(21)+B(19)+B(18)+B(16)+B(14)+
+          B(11)+B(8)+B(7)+B(6)+B(4)+B(1)+B(0), 125),
+ kDefPoly(B(124)+B(122)+B(121)+B(120)+B(119)+B(117)+B(113)+B(110)+B(108)+
+          B(105)+B(103)+B(102)+B(101)+B(97)+B(93)+B(91)+B(90)+B(88)+B(86)+
+          B(84)+B(82)+B(81)+B(79)+B(77)+B(76)+B(75)+B(73)+B(72)+B(71)+
+          B(69)+B(67)+B(64), B(63)+B(62)+B(61)+B(60)+B(58)+B(56)+B(55)+
+          B(52)+B(51)+B(48)+B(47)+B(45)+B(44)+B(42)+B(41)+B(40)+B(39)+
+          B(37)+B(33)+B(32)+B(30)+B(29)+B(28)+B(27)+B(26)+B(25)+B(24)+
+          B(23)+B(19)+B(18)+B(17)+B(16)+B(14)+B(13)+B(11)+B(9)+B(8)+B(7)+
+          B(4)+B(2)+B(1)+B(0), 126),
+ kDefPoly(B(125)+B(124)+B(121)+B(116)+B(115)+B(105)+B(103)+B(101)+B(94)+
+          B(93)+B(91)+B(90)+B(88)+B(87)+B(86)+B(85)+B(77)+B(73)+B(72)+
+          B(70)+B(68)+B(67), B(63)+B(62)+B(61)+B(59)+B(57)+B(53)+B(52)+
+          B(51)+B(49)+B(48)+B(46)+B(44)+B(41)+B(39)+B(38)+B(36)+B(35)+
+          B(30)+B(27)+B(25)+B(23)+B(20)+B(19)+B(13)+B(12)+B(11)+B(10)+B(8)+
+          B(7)+B(5)+B(4)+B(3)+B(2)+B(0), 127),
+ kDefPoly(B(127)+B(122)+B(121)+B(118)+B(117)+B(116)+B(109)+B(108)+B(107)+
+          B(106)+B(104)+B(103)+B(102)+B(101)+B(96)+B(93)+B(92)+B(91)+B(89)+
+          B(86)+B(85)+B(80)+B(78)+B(77)+B(76)+B(75)+B(74)+B(73)+B(72)+
+          B(71)+B(66), B(60)+B(56)+B(53)+B(52)+B(50)+B(47)+B(45)+B(41)+
+          B(39)+B(38)+B(37)+B(35)+B(34)+B(33)+B(30)+B(28)+B(25)+B(24)+
+          B(23)+B(21)+B(20)+B(19)+B(14)+B(13)+B(10)+B(8)+B(5)+B(4)+B(2)+
+          B(1)+B(0), 128),
+};
+// lint -restore
+
+// The number of polynomials in POLYS[].
+SELECTANY const int CRC::N_POLYS = sizeof (poly_list) / sizeof (poly_list[0]);
+
+// The externally visible name of poly_list.
+// This guarantees that the size of poly_list is opaque.
+SELECTANY const struct CRC::Poly *const CRC::POLYS = poly_list;
+
+// The "constructor" for a CRC with an default polynomial.
+CRC *CRC::Default(int degree, size_t roll_length) {
+  ASSERT1(32 == degree);
+
+  CRC *crc = CRCImpl::NewInternal(CRC::POLYS[degree].lo, CRC::POLYS[degree].hi,
+                                  degree, roll_length);  // Build the table
+  return crc;
+}
+
+// The "constructor" for a CRC with an arbitrary polynomial.
+CRC *CRC::New(uint64 lo, uint64 hi, int degree, size_t roll_length) {
+  return CRCImpl::NewInternal(lo, hi, degree, roll_length);
+}
+
+// Internal version of the "constructor".
+CRCImpl *CRCImpl::NewInternal(uint64 lo, uint64 hi,
+                             int degree, size_t roll_length) {
+  ASSERT1(8 <= degree && degree <= 64);  // precondition
+  ASSERT1(lo != 0 || hi != 0);            // precondition
+  // Generate the tables for extending a CRC by 4 bytes at a time.
+  // Why 4 and not 8?  Because Pentium 4 has such small caches.
+  struct CRC_pair t[4][256];
+  for (int j = 0; j != 4; j++) {      // for each byte of extension....
+    t[j][0].lo = 0;                   // a zero has no effect
+    t[j][0].hi = 0;
+    for (int i = 128; i != 0;  i >>= 1) {  // fill in entries for powers of 2
+      if (j == 0 && i == 128) {
+        t[j][i].lo = lo;  // top bit in first byte is easy---it's the polynomial
+        t[j][i].hi = hi;
+      } else {
+                  // each successive power of two is derive from the previous
+                  // one, either in this table, or the last table
+        struct CRC_pair pred;
+        if (i == 128) {
+          pred = t[j-1][1];
+        } else {
+          pred = t[j][i << 1];
+        }
+        // Advance the CRC by one bit (multiply by X, and take remainder
+        // through one step of polynomial long division)
+        if (pred.lo & 1) {
+          t[j][i].lo = (pred.lo >> 1) ^ (pred.hi << 63) ^ lo;
+          t[j][i].hi = (pred.hi >> 1) ^ hi;
+        } else {
+          t[j][i].lo = (pred.lo >> 1) ^ (pred.hi << 63);
+          t[j][i].hi = pred.hi >> 1;
+        }
+      }
+    }
+    // CRCs have the property that CRC(a xor b) == CRC(a) xor CRC(b)
+    // so we can make all the tables for non-powers of two by
+    // xoring previously created entries.
+    for (int i = 2; i != 256;  i <<= 1) {
+      for (int k = i+1; k != (i << 1); k++) {
+        t[j][k].lo = t[j][i].lo ^ t[j][k-i].lo;
+        t[j][k].hi = t[j][i].hi ^ t[j][k-i].hi;
+      }
+    }
+  }
+
+  // Copy the newly built tables in t[] into an appropriate
+  // CRC implenentation object.
+  CRCImpl *result = 0;
+  CRC32 *crc32 = 0;
+  crc32 = new CRC32();
+  for (int i = 0; i != 256; i++) {
+    crc32->table0_[i] = static_cast<uint32>(t[0][i].lo);
+    crc32->table1_[i] = static_cast<uint32>(t[1][i].lo);
+    crc32->table2_[i] = static_cast<uint32>(t[2][i].lo);
+    crc32->table3_[i] = static_cast<uint32>(t[3][i].lo);
+  }
+  result = crc32;
+
+  // "result" is now a CRC object of the right type to handle
+  // the polynomial of the right degree.
+
+  result->roll_length_ = roll_length;
+  result->degree_ = degree;
+  result->poly_lo_ = lo;
+  result->poly_hi_ = hi;
+
+  // Build the table for extending by zeroes.
+  // Entry i=a-1+3*b (a in {1, 2, 3}, b in {0, 1, 2, 3, ...}
+  // contains a polynomial Pi such that multiplying
+  // a CRC by Pi mod P, where P is the CRC polynomial, is equivalent to
+  // appending a*2**(2*b+SMALL_BITS) zero bytes to the original string.
+  // Entry is generated by calling ExtendByZeroes() twice using
+  // half the length from the previous entry.
+  int pos = 0;
+  for (uint64 inc_len = (1 << SMALL_BITS); inc_len != 0; inc_len <<= 2) {
+    result->Empty(&lo, &hi);
+    for (int k = 0; k != 3; k++) {
+      result->ExtendByZeroes(&lo, &hi, (size_t) (inc_len >> 1));
+      result->ExtendByZeroes(&lo, &hi, (size_t) (inc_len >> 1));
+      crc32->zeroes_[pos] = static_cast<uint32>(lo);
+      pos++;
+    }
+  }
+
+  // Calculate the entries in the roll table, used for rolling checksums
+  // of a fixed length.
+  // Extend the powers of two in the one-byte extension table by the roll
+  // length.
+  int bit = 256;
+  do {
+    bit >>= 1;
+    result->ExtendByZeroes(&t[0][bit].lo, &t[0][bit].hi, roll_length);
+  } while (bit != 0);
+  // Calculate the non-powers of two using CRC(a xor b) == CRC(a) xor CRC(b)
+  for (int i = 2; i != 256;  i <<= 1) {
+    for (int j = i+1; j != (i << 1); j++) {
+      t[0][j].lo = t[0][i].lo ^ t[0][j-i].lo;
+      t[0][j].hi = t[0][i].hi ^ t[0][j-i].hi;
+    }
+  }
+  // Now xor the CRC of (binary) 100000001 followed by
+  // the roll length of zeroes.   This will be xored into every
+  // entry.   This will simultaneously roll out the CRC
+  // of the empty string that's been pushed one byte too far,
+  // and roll in the CRC of the empty string in the correct place again.
+  result->Empty(&lo, &hi);
+  const uint8 x = 0x80;
+  result->Extend(&lo, &hi, &x, 1);
+  result->ExtendByZeroes(&lo, &hi, roll_length);
+  for (int i = 0; i != 256; i++) {
+    t[0][i].lo ^= lo;
+    t[0][i].hi ^= hi;
+  }
+
+  // Put the roll table into the object.
+  for (int i = 0; i != 256; i++) {
+    crc32->roll_[i] = static_cast<uint32>(t[0][i].lo);
+  }
+
+  return result;
+}
+
+// The CRC of the empty string is always the CRC polynomial itself.
+void CRCImpl::Empty(uint64 *lo, uint64 *hi) const {
+  ASSERT1(hi);
+  ASSERT1(lo);
+
+  *lo = this->poly_lo_;
+  *hi = this->poly_hi_;
+}
+
+//  The 32-bit implementation
+
+void CRC32::Extend(uint64 *lo, uint64 *hi, const void *bytes, size_t length)
+                      const {
+  ASSERT1(hi);
+  ASSERT1(lo);
+
+  hi;   // unreferenced formal parameter
+
+  const uint8 *p = static_cast<const uint8 *>(bytes);
+  const uint8 *e = p + length;
+  uint32 l = static_cast<uint32>(*lo);
+  // point x at MIN(first 4-byte aligned byte in string, end of string)
+  const uint8 *x = p + ((zero_ptr - p) & 3);
+  if (x > e) {
+    x = e;
+  }
+  // Process bytes until finished or p is 4-byte aligned
+  while (p != x) {
+    int c = (l & 0xff) ^ *p++;
+    l = this->table0_[c] ^ (l >> 8);
+  }
+  // point x at MIN(last 4-byte aligned byte in string, end of string)
+  x = e - ((e - zero_ptr) & 3);
+  // Process bytes 4 at a time
+  while (p < x) {
+    uint32 c = l ^ *reinterpret_cast<const uint32*>(p);
+    p += 4;
+    l = this->table3_[c & 0xff] ^
+        this->table2_[(c >> 8) & 0xff] ^
+        this->table1_[(c >> 16) & 0xff] ^
+        this->table0_[c >> 24];
+  }
+
+  // Process the last few bytes
+  while (p != e) {
+    int c = (l & 0xff) ^ *p++;
+    l = this->table0_[c] ^ (l >> 8);
+  }
+  *lo = l;
+}
+
+void CRC32::ExtendByZeroes(uint64 *lo, uint64 *hi, size_t length) const {
+  ASSERT1(hi);
+  ASSERT1(lo);
+
+  // Process the low order SMALL_BITS of the length by simply
+  // using Extend() on an array of bytes that are zero.
+  int small_part = (length & ((1 << SMALL_BITS)-1));
+  if (small_part != 0) {
+    this->Extend(lo, hi, zeroes, small_part);
+  }
+  length >>= SMALL_BITS;
+  if (length != 0) {          // if the length was at least 2**SMALL_BITS
+    uint32 l = static_cast<uint32>(*lo);
+    uint32 onebit = 1;
+    onebit <<= this->degree_ - 1;
+    // For each pair of bits in length
+    // (after the low-oder bits have been removed)
+    // we lookup the appropriate polynomial in the zeroes_ array
+    // and do a polynomial long multiplication (mod the CRC polynomial)
+    // to extend the CRC by the appropriate number of bits.
+    for (int i = 0; length != 0; i += 3, length >>= 2) {
+      int c = length & 3;       // pick next two bits
+      if (c != 0) {             // if they are not zero,
+                                // multiply by entry in table
+        uint32 m = this->zeroes_[c+i-1];
+        uint32 result = 0;
+        for (uint32 one = onebit; one != 0; one >>= 1) {
+          if ((l & one) != 0) {
+            result ^= m;
+          }
+          if (m & 1) {
+            m = (m >> 1) ^ static_cast<uint32>(poly_lo_);
+          } else {
+            m = (m >> 1);
+          }
+        }
+        l = result;
+      }
+    }
+    *lo = l;
+  }
+}
+
+void CRC32::Roll(uint64 *lo, uint64 *hi, uint8 o_byte, uint8 i_byte) const {
+  ASSERT1(hi);
+  ASSERT1(lo);
+
+  hi;   // unreferenced formal parameter
+
+  uint32 l = static_cast<uint32>(*lo);
+  // Roll in i_byte and out o_byte
+  *lo = this->table0_[(l & 0xff) ^ i_byte] ^ (l >> 8) ^ this->roll_[o_byte];
+}
+
+}  // namespace omaha
+
diff --git a/common/crc.h b/common/crc.h
index 15e864b..26abe59 100644
--- a/common/crc.h
+++ b/common/crc.h
@@ -1,140 +1,140 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef _CRC_H_

-#define _CRC_H_

-

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// This class implements CRCs (aka Rabin Fingerprints).

-// Treats the input as a polynomial with coefficients in Z(2),

-// and finds the remainder when divided by an irreducible polynomial

-// of the appropriate length.

-// It handles all CRC sizes from 8 to 128 bits.

-// The input string is prefixed with a "1" bit, and has "degree" "0" bits

-// appended to it before the remainder is found.   This ensures that

-// short strings are scrambled somewhat.

-

-// A polynomial is represented by the bit pattern formed by its coefficients,

-// but with the highest order bit not stored.

-// The highest degree coefficient is stored in the lowest numbered bit

-// in the the lowest adderessed byte.   Thus, in what follows,

-// the highest degree coeficient that is stored is in the low order bit

-// of "lo" or "*lo".

-

-// Typical usage:

-//

-// // prepare to do 32-bit CRCs using the default polynomial.  No rolling hash.

-// scoped_ptr<CRC> crc(CRC::Default(32, 0));

-// ...

-// uint64 lo;   // declare a lo,hi pair to hold the CRC

-// uint64 hi;

-// crc->Empty(&lo, &hi);      // Initialize to CRC of empty string

-// crc->Extend(&lo, &hi, "hello", 5);     // Get CRC of "hello"

-// ...

-//

-// // prepare to use a 32-bit rolling hash over 6 bytes

-// scoped_ptr<CRC> crc(CRC::Default(32, 6));

-// ...

-// uint64 lo;   // declare a lo,hi pair to hold the CRC

-// uint64 hi;

-// crc->Empty(&lo, &hi);      // Initialize to CRC of empty string

-// crc->Extend(&lo, &hi, data, 6);     // Get CRC of first 6 bytes

-// for (int i = 6; i != sizeof (data); i++) {

-//   crc->Roll(&lo, &hi, data[i-6], data[i]); // Move window by one byte

-//   // lo,hi is CRC of bytes data[i-5...i]

-// }

-// ...

-//

-

-class CRC {

-public:

- // Initialize all the tables for CRC's of a given bit length "degree"

- // using a default polynomial of the given length.

- //

- // The argument "roll_length" is used by subsequent calls to

- // Roll().

- // Returns a handle that MUST NOT be destroyed with delete.

- // The default polynomials are those in POLYS[8...128].

- // Handles returned by Default() MUST NOT be deleted.

- // Identical calls to Default() yield identical handles.

- static CRC *Default(int degree, size_t roll_length);

-

- // Initialize all the tables for CRC's of a given bit length "degree"

- // using an arbitrary CRC polynomial.

- // Normally, you would use Default() instead of New()---see above.

- //

- // Requires that "lo,hi" contain an irreducible polynomial of degree "degree"

- // Requires 8 <= degree && degree <= 128

- // Any irreducible polynomial of the correct degree will work.

- // See the POLYS array for suitable irredicible polynomials.

- //

- // The argument "roll_length" is used by subsequent calls to

- // Roll().

- // Each call to New() yeilds a pointer to a new object

- // that may be deallocated with delete.

- static CRC *New(uint64 lo, uint64 hi, int degree, size_t roll_length);

-

- virtual ~CRC();

-

- // Place the CRC of the empty string in "*lo,*hi"

- virtual void Empty(uint64 *lo, uint64 *hi) const = 0;

-

- // If "*lo,*hi" is the CRC of bytestring A, place the CRC of

- // the bytestring formed from the concatenation of A and the "length"

- // bytes at "bytes" into "*lo,*hi".

- virtual void Extend(/*INOUT*/ uint64 *lo, /*INOUT*/ uint64 *hi,

-                     const void *bytes, size_t length) const = 0;

-

- // Equivalent to Extend(lo, hi, bytes, length) where "bytes"

- // points to an array of "length" zero bytes.

- virtual void ExtendByZeroes(/*INOUT*/ uint64 *lo, /*INOUT*/ uint64 *hi,

-                             size_t length) const = 0;

-

- // If "*lo,*hi" is the CRC of a byte string of length "roll_length"

- // (which is an argument to New() and Default()) that consists of

- // byte "o_byte" followed by string S, set "*lo,*hi" to the CRC of

- // the string that consists of S followed by the byte "i_byte".

- virtual void Roll(/*INOUT*/ uint64 *lo, /*INOUT*/ uint64 *hi,

-                   uint8 o_byte, uint8 i_byte) const = 0;

-

- // POLYS[] is an array of valid triples that may be given to New()

- static const struct Poly {

-   uint64 lo;                      // first half suitable CRC polynomial

-   uint64 hi;                      // second half of suitable CRC polynomial

-   int degree;                     // degree of suitable CRC polynomial

- } *const POLYS;

- // It is guaranteed that no two entries in POLYS[] are identical,

- // that POLYS[i] cnotains a polynomial of degree i for 8 <= i <= 128,

- // that POLYS[0] and POLYS[1] contains polynomials of degree 32,

- // that POLYS[2] and POLYS[3] contains polynomials of degree 64,

- // that POLYS[4] and POLYS[5] contains polynomials of degree 96, and

- // that POLYS[6] and POLYS[7] contains polynomials of degree 128.

-

- static const int N_POLYS;         // Number of elements in POLYS array.

-

-protected:

- CRC();      // Clients may not call constructor;

-               // use Default() or New() instead.

-

-private:

- DISALLOW_EVIL_CONSTRUCTORS(CRC);

-};

-

-}  // namespace omaha

-

-#endif

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef _CRC_H_
+#define _CRC_H_
+
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// This class implements CRCs (aka Rabin Fingerprints).
+// Treats the input as a polynomial with coefficients in Z(2),
+// and finds the remainder when divided by an irreducible polynomial
+// of the appropriate length.
+// It handles all CRC sizes from 8 to 128 bits.
+// The input string is prefixed with a "1" bit, and has "degree" "0" bits
+// appended to it before the remainder is found.   This ensures that
+// short strings are scrambled somewhat.
+
+// A polynomial is represented by the bit pattern formed by its coefficients,
+// but with the highest order bit not stored.
+// The highest degree coefficient is stored in the lowest numbered bit
+// in the the lowest adderessed byte.   Thus, in what follows,
+// the highest degree coeficient that is stored is in the low order bit
+// of "lo" or "*lo".
+
+// Typical usage:
+//
+// // prepare to do 32-bit CRCs using the default polynomial.  No rolling hash.
+// scoped_ptr<CRC> crc(CRC::Default(32, 0));
+// ...
+// uint64 lo;   // declare a lo,hi pair to hold the CRC
+// uint64 hi;
+// crc->Empty(&lo, &hi);      // Initialize to CRC of empty string
+// crc->Extend(&lo, &hi, "hello", 5);     // Get CRC of "hello"
+// ...
+//
+// // prepare to use a 32-bit rolling hash over 6 bytes
+// scoped_ptr<CRC> crc(CRC::Default(32, 6));
+// ...
+// uint64 lo;   // declare a lo,hi pair to hold the CRC
+// uint64 hi;
+// crc->Empty(&lo, &hi);      // Initialize to CRC of empty string
+// crc->Extend(&lo, &hi, data, 6);     // Get CRC of first 6 bytes
+// for (int i = 6; i != sizeof (data); i++) {
+//   crc->Roll(&lo, &hi, data[i-6], data[i]); // Move window by one byte
+//   // lo,hi is CRC of bytes data[i-5...i]
+// }
+// ...
+//
+
+class CRC {
+public:
+ // Initialize all the tables for CRC's of a given bit length "degree"
+ // using a default polynomial of the given length.
+ //
+ // The argument "roll_length" is used by subsequent calls to
+ // Roll().
+ // Returns a handle that MUST NOT be destroyed with delete.
+ // The default polynomials are those in POLYS[8...128].
+ // Handles returned by Default() MUST NOT be deleted.
+ // Identical calls to Default() yield identical handles.
+ static CRC *Default(int degree, size_t roll_length);
+
+ // Initialize all the tables for CRC's of a given bit length "degree"
+ // using an arbitrary CRC polynomial.
+ // Normally, you would use Default() instead of New()---see above.
+ //
+ // Requires that "lo,hi" contain an irreducible polynomial of degree "degree"
+ // Requires 8 <= degree && degree <= 128
+ // Any irreducible polynomial of the correct degree will work.
+ // See the POLYS array for suitable irredicible polynomials.
+ //
+ // The argument "roll_length" is used by subsequent calls to
+ // Roll().
+ // Each call to New() yeilds a pointer to a new object
+ // that may be deallocated with delete.
+ static CRC *New(uint64 lo, uint64 hi, int degree, size_t roll_length);
+
+ virtual ~CRC();
+
+ // Place the CRC of the empty string in "*lo,*hi"
+ virtual void Empty(uint64 *lo, uint64 *hi) const = 0;
+
+ // If "*lo,*hi" is the CRC of bytestring A, place the CRC of
+ // the bytestring formed from the concatenation of A and the "length"
+ // bytes at "bytes" into "*lo,*hi".
+ virtual void Extend(/*INOUT*/ uint64 *lo, /*INOUT*/ uint64 *hi,
+                     const void *bytes, size_t length) const = 0;
+
+ // Equivalent to Extend(lo, hi, bytes, length) where "bytes"
+ // points to an array of "length" zero bytes.
+ virtual void ExtendByZeroes(/*INOUT*/ uint64 *lo, /*INOUT*/ uint64 *hi,
+                             size_t length) const = 0;
+
+ // If "*lo,*hi" is the CRC of a byte string of length "roll_length"
+ // (which is an argument to New() and Default()) that consists of
+ // byte "o_byte" followed by string S, set "*lo,*hi" to the CRC of
+ // the string that consists of S followed by the byte "i_byte".
+ virtual void Roll(/*INOUT*/ uint64 *lo, /*INOUT*/ uint64 *hi,
+                   uint8 o_byte, uint8 i_byte) const = 0;
+
+ // POLYS[] is an array of valid triples that may be given to New()
+ static const struct Poly {
+   uint64 lo;                      // first half suitable CRC polynomial
+   uint64 hi;                      // second half of suitable CRC polynomial
+   int degree;                     // degree of suitable CRC polynomial
+ } *const POLYS;
+ // It is guaranteed that no two entries in POLYS[] are identical,
+ // that POLYS[i] cnotains a polynomial of degree i for 8 <= i <= 128,
+ // that POLYS[0] and POLYS[1] contains polynomials of degree 32,
+ // that POLYS[2] and POLYS[3] contains polynomials of degree 64,
+ // that POLYS[4] and POLYS[5] contains polynomials of degree 96, and
+ // that POLYS[6] and POLYS[7] contains polynomials of degree 128.
+
+ static const int N_POLYS;         // Number of elements in POLYS array.
+
+protected:
+ CRC();      // Clients may not call constructor;
+               // use Default() or New() instead.
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(CRC);
+};
+
+}  // namespace omaha
+
+#endif
diff --git a/common/debug.cc b/common/debug.cc
index aab33db..96b6e70 100644
--- a/common/debug.cc
+++ b/common/debug.cc
@@ -1,1183 +1,1183 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Debug functions

-

-#include "omaha/common/debug.h"

-

-#include <dbghelp.h>

-#include <wtsapi32.h>

-#include <atlstr.h>

-#ifdef _DEBUG

-#include <atlcom.h>

-#define STRSAFE_NO_DEPRECATE

-#include <strsafe.h>

-#endif

-#include <stdlib.h>

-#include <signal.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/clipboard.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/const_config.h"

-#include "omaha/common/const_debug.h"

-#include "omaha/common/const_timeouts.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/module_utils.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/common/vista_utils.h"

-

-namespace omaha {

-

-#ifdef _DEBUG

-#define kSprintfBuffers (100)  // number of buffers for SPRINTF

-#else

-#define kSprintfBuffers (3)  // number of buffers for SPRINTF

-#endif

-

-// pad SPRINTF buffer to check for overruns

-#if SHIPPING

-#define kSprintfBufferOverrunPadding 0

-#else  // !SHIPPING

-#ifdef DEBUG

-#define kSprintfBufferOverrunPadding 20000

-#else

-#define kSprintfBufferOverrunPadding 1024

-#endif  // DEBUG

-#endif  // SHIPPING

-

-#define kErrorRequestToSend                                                    \

-    _T("*** Please hit Ignore to continue and send error information to the ") \

-    kAppName                                                                   \

-    _T(" team ***\n*** These details have been pasted to the clipboard ***")

-

-#define kMaxReportSummaryLen (1024*100)  // max length of report summary string

-

-#define kReportIdsLock kLockPrefix                                             \

-    _T("Report_Ids_Lock_57146B01-6A07-4b8d-A1D8-0C3AFC3B2F9B")

-

-SELECTANY bool g_always_assert = false;

-SELECTANY TCHAR *g_additional_status_ping_info = NULL;

-

-#define kSprintfMaxLen (1024 + 2)  // max length that wvsprintf writes is 1024

-static bool g_initialized_sprintf = false;

-static volatile LONG g_sprintf_interlock = 0;

-static int g_current_sprintf_buffer = 0;

-static TCHAR *g_sprintf_buffer = NULL;

-static TCHAR *g_sprintf_buffers[kSprintfBuffers];

-SELECTANY volatile LONG g_debugassertrecursioncheck = 0;

-static int g_total_reports = 0;

-

-SELECTANY ReportIds g_report_ids;

-

-// Builds a full path name out of the given filename. If the filename is

-// a relative path, it is appended to the debug directory. Otherwise, if the

-// filename is a full path, it returns it as the full debug filename.

-static CString MakeFullDebugFilename(const TCHAR *filename) {

-  CString full_name;

-  if (lstrlen(filename) <= 2 || filename[1] != _T(':')) {

-    full_name = GetDebugDirectory();

-    full_name += L"\\";

-  }

-  full_name += filename;

-  return full_name;

-}

-

-

-// Displays the assert box. Due to session isolation, MB_SERVICE_NOTIFICATION

-// flag does not work for Vista services. In this case, use WTS to display

-// a message box in the active console session.

-void ShowAssertDialog(const TCHAR *message, const TCHAR *title) {

-  int ret = 0;

-  OSVERSIONINFOEX osviex = {sizeof(OSVERSIONINFOEX), 0};

-  const bool is_vista_or_greater =

-     ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osviex)) &&

-     osviex.dwMajorVersion >= 6;

-  bool is_system_process = false;

-  if (is_vista_or_greater &&

-      SUCCEEDED(IsSystemProcess(&is_system_process)) &&

-      is_system_process) {

-    DWORD session_id = System::WTSGetActiveConsoleSessionId();

-    if (session_id == kInvalidSessionId) {

-      session_id = WTS_CURRENT_SESSION;

-    }

-    DWORD response = 0;

-    ::WTSSendMessage(WTS_CURRENT_SERVER_HANDLE,

-                     session_id,

-                     const_cast<TCHAR*>(title),

-                     _tcslen(title) * sizeof(TCHAR),

-                     const_cast<TCHAR*>(message),

-                     _tcslen(message) * sizeof(TCHAR),

-                     MB_ABORTRETRYIGNORE | MB_ICONERROR,

-                     0,

-                     &response,

-                     true);

-    ret = response;

-  } else {

-    ret = ::MessageBoxW(NULL,

-                        message,

-                        title,

-                        MB_ABORTRETRYIGNORE |

-                        MB_ICONERROR        |

-                        MB_SERVICE_NOTIFICATION);

-  }

-

-  switch (ret) {

-    case IDABORT:

-      // Terminate the process if the user chose 'Abort'. Calling ExitProcess

-      // here results in calling the destructors for static objects which can

-      // result in deadlocks.

-      raise(SIGABRT);

-      break;

-

-    case IDRETRY:

-      // Break if the user chose "Retry".

-      __debugbreak();

-      break;

-    default:

-      // By default we ignore the message.

-      break;

-  }

-}

-

-DebugObserver* g_debug_observer = NULL;

-

-// replaces the debug observer, returns the previous value.

-DebugObserver* SetDebugObserver(DebugObserver* observer) {

-  DebugObserver* old_value = g_debug_observer;

-  g_debug_observer = observer;

-  return old_value;

-}

-

-DebugObserver* PeekDebugObserver() {

-  return g_debug_observer;

-}

-

-int SehSendMinidump(unsigned int code,

-                    struct _EXCEPTION_POINTERS *ep,

-                    time64 time_between_minidumps) {

-    if (code == EXCEPTION_BREAKPOINT)

-    return EXCEPTION_CONTINUE_SEARCH;

-

-  if (::IsDebuggerPresent())

-    return EXCEPTION_CONTINUE_SEARCH;

-

-  OutputDebugString(L"**SehSendMinidump**\r\n");

-

-  if (g_debug_observer) {

-    return g_debug_observer->SehSendMinidump(code, ep, time_between_minidumps);

-  }

-

-  return EXCEPTION_EXECUTE_HANDLER;

-}

-

-#if defined(_DEBUG) || defined(ASSERT_IN_RELEASE)

-CallInterceptor<DebugAssertFunctionType> debug_assert_interceptor;

-

-// Replaces the debug assert function; returns the old value.

-DebugAssertFunctionType* ReplaceDebugAssertFunction(

-    DebugAssertFunctionType* replacement) {

-  return debug_assert_interceptor.ReplaceFunction(replacement);

-}

-

-void OnAssert(const char *expr, const TCHAR *msg,

-              const char *filename, int32 linenumber) {

-  if (g_debug_observer) {

-    g_debug_observer->OnAssert(expr, msg, filename, linenumber);

-  }

-}

-#endif

-

-#if defined(_DEBUG)

-CString OnDebugReport(uint32 id,

-                      bool is_report,

-                      ReportType type,

-                      const char *expr,

-                      const TCHAR *message,

-                      const char *filename,

-                      int32 linenumber,

-                      DebugReportKind debug_report_kind) {

-  CString trace;

-  if (g_debug_observer) {

-    trace = g_debug_observer->OnDebugReport(id, is_report,

-                                            type, expr, message, filename,

-                                            linenumber, debug_report_kind);

-  }

-  return trace;

-}

-

-void SendExceptionReport(const TCHAR *log_file, const TCHAR *filename, int line,

-                         const TCHAR *type, uint32 id, bool offline) {

-  if (g_debug_observer) {

-    g_debug_observer->SendExceptionReport(log_file, filename, line,

-                                          type, id, offline);

-  }

-}

-#endif

-

-

-#ifdef _DEBUG  // won't compile since _CrtDbgReport isn't defined.

-

-#include <crtdbg.h>    // NOLINT

-static CString g_report_summary;

-

-// dump summary of reports on exit

-SELECTANY ReportSummaryGenerator g_report_summary_generator;

-

-ReportSummaryGenerator::~ReportSummaryGenerator() {

-  DumpReportSummary();

-}

-

-void ReportSummaryGenerator::DumpReportSummary() {

-  if (g_total_reports) {

-    ::OutputDebugString(L"REPORT SUMMARY:\r\n");

-    ::OutputDebugString(SPRINTF(L"%d total reports\r\n", g_total_reports));

-    ::OutputDebugString(g_report_summary);

-  } else {

-    ::OutputDebugString(L"NO REPORTS!!\r\n");

-  }

-}

-

-TCHAR *ReportSummaryGenerator::GetReportSummary() {

-  TCHAR *s = new TCHAR[kMaxReportSummaryLen];

-  if (s) {

-    s[0] = 0;

-    if (g_total_reports) {

-      SafeStrCat(s, L"REPORT SUMMARY:\r\n\r\n", kMaxReportSummaryLen);

-      SafeStrCat(s,

-                 SPRINTF(L"%d total reports\r\n\r\n", g_total_reports),

-                 kMaxReportSummaryLen);

-      SafeStrCat(s,

-                 g_report_summary.

-                     Left(kMaxReportSummaryLen - lstrlen(s) - 1).GetString(),

-                 kMaxReportSummaryLen);

-      CString report_string = g_report_ids.DebugReportString();

-      ReplaceCString(report_string, L"&", L"\r\n");

-      SafeStrCat(s,

-                 report_string.

-                     Left(kMaxReportSummaryLen - lstrlen(s) - 1).GetString(),

-                 kMaxReportSummaryLen);

-    } else {

-      SafeStrCat(s, L"NO REPORTS!!\r\n", kMaxReportSummaryLen);

-    }

-  }

-

-  return s;

-}

-

-static CAtlMap<CString, uint32> g_reports_done;

-

-#endif  // _DEBUG

-

-#ifdef _DEBUG

-

-void TraceError(DWORD error) {

-  HLOCAL mem = NULL;

-  ::FormatMessage(

-    FORMAT_MESSAGE_ALLOCATE_BUFFER |

-    FORMAT_MESSAGE_FROM_SYSTEM |

-    FORMAT_MESSAGE_IGNORE_INSERTS,

-    static_cast<LPVOID>(_AtlBaseModule.GetResourceInstance()),

-    error,

-    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),  // default language

-    reinterpret_cast<TCHAR*>(&mem),

-    0,

-    NULL);

-

-  TCHAR* str = reinterpret_cast<TCHAR*>(::LocalLock(mem));

-  ::OutputDebugString(str);

-  REPORT(false, R_ERROR, (str), 3968294226);

-  ::LocalFree(mem);

-}

-

-// ban ASSERT/VERIFY/REPORT to prevent recursion

-#undef ASSERT

-#undef VERIFY

-#undef REPORT

-

-// TODO(omaha): fix static initialization order below.

-// The initialization order of static variables is not deterministic per C++

-// standard and it depends completely on the compiler implementation.

-// For VC++ compiler we are using, it seems to work as expected.

-// One real fix is to put all definitons of static variables inside a class and

-// define a boolean variable in this class to indicate that all necessary

-// static initializations have been done.

-//

-// The follow definition is used to detect whether we get the exception

-// during initializing static variables. If this is the case, DebugReport()

-// will not function and will throw an exception because some of its refering

-// static variables are not initialized yet (i.e. g_reports_done).

-const int kTestInitStaticVariablesDoneValue = 1234;

-struct TestInitStaticVariablesDone {

-  int value;

-  TestInitStaticVariablesDone() : value(kTestInitStaticVariablesDoneValue) {}

-};

-static TestInitStaticVariablesDone test_var;

-

-bool DebugReport(unsigned int id,

-                 ReportType type,

-                 const char *expr,

-                 const TCHAR *message,

-                 const char *filename,

-                 int linenumber,

-                 DebugReportKind debug_report_kind) {

-  int recursion_count = ::InterlockedIncrement(&g_debugassertrecursioncheck);

-  ON_SCOPE_EXIT(::InterlockedDecrement, &g_debugassertrecursioncheck);

-  if (recursion_count > 1) {

-    ::OutputDebugString(_T("recursive debugreport skipped\n"));

-    return 1;

-  }

-

-  if (debug_assert_interceptor.interceptor()) {

-    // call replacement function (typically used for unit tests)

-    // Note that I'm doing this inside the in_assert block for paranoia;

-    // it's not really necessary and perhaps the wrong choice.

-    debug_assert_interceptor.interceptor()(expr, CT2A(message), filename,

-                                            linenumber);

-    return true;

-  }

-

-

-  // Check whether we have already finished initializing all static variables

-  // needed for executing DebugReport(). If not, bail out.

-  if (test_var.value != kTestInitStaticVariablesDoneValue) {

-    CString debug_msg;

-    debug_msg.Format(_T("%hs:%d - %s - %S"),

-                     filename, linenumber, message, expr);

-    debug_msg.Append(_T("\n\nException occurs while initializing ")

-                     _T("static variables needed for DebugReport"));

-    ShowAssertDialog(debug_msg, _T("DebugReport"));

-    return true;

-  }

-

-  bool is_assert = debug_report_kind == DEBUGREPORT_ASSERT;

-  bool is_report = debug_report_kind == DEBUGREPORT_REPORT;

-  bool is_abort  = debug_report_kind == DEBUGREPORT_ABORT;

-

-  if (is_report)

-    g_total_reports++;

-

-  g_report_ids.ReleaseReport(id);

-

-  if (type == R_FATAL) {

-    if (is_report) {

-      // Treat as ASSERT

-      is_report = false;

-      is_assert = true;

-    }

-  }

-

-  bool always_assert = g_always_assert;

-

-  if (always_assert) {

-    is_report = false;

-    is_assert = true;

-  }

-

-  if (!message) {

-    message = _T("");

-  }

-

-  // log to debugger

-  TCHAR *debug_string;

-  // ::OutputDebugString(DEBUG_LOG_SEPARATOR);

-  ::OutputDebugString(is_report ? _T("REPORT: ") :

-                                  (is_assert ? _T("ASSERT: ") : _T("ABORT: ")));

-

-  CFixedStringT<CString, 1024> proc_name = app_util::GetAppName();

-

-  // last %s now %s skip %d

-  const TCHAR* format = message && *message ?

-                        _T("[%hs:%d][%hs][%s]") : _T("[%hs:%d][%hs]");

-  debug_string = SPRINTF(format, filename, linenumber, expr, message);

-

-  // String_Int64ToString(g_last_report_time, 10),

-  // String_Int64ToString(time, 10), skip_report));

-

-  // ::OutputDebugString(DEBUG_LOG_SEPARATOR);

-  // ::OutputDebugString(_T("\n"));

-

-#ifdef LOGGING

-  // Log the reports via the logging system to all loggers.

-  CString what = is_report ? _T("REPORT") :

-                             is_assert ? _T("ASSERT") : _T("ABORT");

-  LC_LOG(LC_LOGGING, LEVEL_ERROR, (_T("[%s]%s"), what, debug_string));

-#else

-  ::OutputDebugString(debug_string);

-  ::OutputDebugString(_T("\n"));

-#endif

-

-  // skip sending strack trace for duplicate reports

-  CString report_id;

-  report_id.Format(_T("%hs:%d"), filename, linenumber);

-

-  uint32 prev_reports = 0;

-  if (g_reports_done.Lookup(report_id, prev_reports) && is_report) {

-    prev_reports++;

-    g_reports_done.SetAt(report_id, prev_reports);

-    ::OutputDebugString(SPRINTF(_T("skipping duplicate report %s %d\n"),

-                                report_id.GetString(),

-                                prev_reports));

-    return 1;

-  }

-

-  prev_reports++;

-  g_reports_done.SetAt(report_id, prev_reports);

-

-  g_report_summary.Append(debug_string);

-  g_report_summary.Append(L" (");

-  g_report_summary.Append(itostr(id));

-  g_report_summary.Append(L")");

-  g_report_summary.Append(L"\r\n");

-

-  // ::OutputDebugString(_T("log to file\n"));

-

-  // log to file

-  CString path_name(MakeFullDebugFilename(kCiDebugLogFile));

-  HANDLE h = CreateFile(path_name,

-                        GENERIC_WRITE | GENERIC_READ,

-                        FILE_SHARE_READ | FILE_SHARE_WRITE,

-                        NULL,

-                        OPEN_ALWAYS,

-                        FILE_ATTRIBUTE_NORMAL,

-                        NULL);

-

-  HANDLE assert_file = INVALID_HANDLE_VALUE;

-  if (is_assert) {

-    path_name = MakeFullDebugFilename(kCiAssertOccurredFile);

-    assert_file = CreateFile(path_name,

-                             GENERIC_WRITE,

-                             0,

-                             0,

-                             OPEN_ALWAYS,

-                             FILE_FLAG_WRITE_THROUGH,

-                             NULL);

-  }

-

-  HANDLE abort_file = INVALID_HANDLE_VALUE;

-  if (is_abort) {

-    path_name = MakeFullDebugFilename(kCiAbortOccurredFile);

-    abort_file = CreateFile(path_name,

-                            GENERIC_WRITE,

-                            0,

-                            0,

-                            OPEN_ALWAYS,

-                            FILE_FLAG_WRITE_THROUGH,

-                            NULL);

-  }

-

-  if (h != INVALID_HANDLE_VALUE ||

-      assert_file != INVALID_HANDLE_VALUE ||

-      abort_file != INVALID_HANDLE_VALUE) {

-    // more convenient for now to have this in UTF8

-    char *utf8_buffer = new char[(lstrlen(debug_string)*2) + 1];

-    if (utf8_buffer) {

-        int conv_bytes = WideCharToMultiByte(CP_UTF8,

-                                             0,

-                                             debug_string,

-                                             lstrlen(debug_string),

-                                             utf8_buffer,

-                                             (lstrlen(debug_string) * 2) + 1,

-                                             NULL,

-                                             NULL);

-

-        if (conv_bytes) {

-            DWORD bytes_written;

-            BOOL result;

-

-            if (h != INVALID_HANDLE_VALUE) {

-              SetFilePointer(h, 0, NULL, FILE_END);

-              result = ::WriteFile(h,

-                                   (LPCVOID)utf8_buffer,

-                                   conv_bytes,

-                                   &bytes_written,

-                                   NULL);

-              result = ::WriteFile(h,

-                                   (LPCVOID)DEBUG_LOG_SEPARATOR_CHAR,

-                                   strlen(DEBUG_LOG_SEPARATOR_CHAR),

-                                   &bytes_written,

-                                   NULL);

-            }

-            if (assert_file != INVALID_HANDLE_VALUE) {

-              result = ::WriteFile(assert_file,

-                                   (LPCVOID)utf8_buffer,

-                                   conv_bytes,

-                                   &bytes_written,

-                                   NULL);

-            }

-            if (abort_file != INVALID_HANDLE_VALUE) {

-              result = ::WriteFile(abort_file,

-                                   (LPCVOID)utf8_buffer,

-                                   conv_bytes,

-                                   &bytes_written,

-                                   NULL);

-            }

-        }

-

-        delete [] utf8_buffer;

-    }

-  }

-

-  if (h != INVALID_HANDLE_VALUE) {

-    ::CloseHandle(h);

-  }

-  if (assert_file != INVALID_HANDLE_VALUE) {

-    ::CloseHandle(assert_file);

-  }

-  if (abort_file != INVALID_HANDLE_VALUE) {

-    ::CloseHandle(abort_file);

-  }

-

-  CString stack_trace = OnDebugReport(id, is_report, type, expr, message,

-                                      filename, linenumber, debug_report_kind);

-

-  if (is_report) {

-    return 1;

-  }

-

-  ::OutputDebugString(L"show assert dialog\r\n");

-  ::OutputDebugString(stack_trace.GetString());

-

-  CString process_path;

-  GetModuleFileName(NULL, &process_path);

-

-  static TCHAR clipboard_string[4096] = {0};

-  lstrcpyn(clipboard_string,

-           SPRINTF(L"%ls (pid=%i)\r\n%hs:%d\r\n\r\n%hs\r\n%s\r\n\r\n",

-                   process_path,

-                   ::GetCurrentProcessId(),

-                   filename,

-                   linenumber,

-                   expr,

-                   message),

-           arraysize(clipboard_string));

-  stack_trace = stack_trace.Left(

-      arraysize(clipboard_string) - lstrlen(clipboard_string) - 1);

-  SafeStrCat(clipboard_string, stack_trace, arraysize(clipboard_string));

-  SetClipboard(clipboard_string);

-

-  stack_trace = stack_trace.Left(kMaxStackTraceDialogLen);

-

-  CString assert_text;

-  assert_text.Format(_T("Assertion (%ls) failed!\r\n\r\nProcess: %d ")

-    _T("(0x%08X)\r\nThread %d (0x%08X)\r\nProgram: %ls\r\n")

-    _T("Version: %s\r\nFile: %hs\r\nLine: %d\r\n\r\n"),

-    debug_report_kind == DEBUGREPORT_ASSERT ?

-      L"Assert" : (debug_report_kind == DEBUGREPORT_ABORT ?

-      L"Abort" : L"Report"),

-    ::GetCurrentProcessId(), ::GetCurrentProcessId(), ::GetCurrentThreadId(),

-    ::GetCurrentThreadId(), process_path, omaha::GetVersionString(), filename,

-    linenumber);

-

-  if (lstrlen(message) > 0) {

-    assert_text.AppendFormat(

-        _T("Expression: %hs\r\nMessage: %s\r\n\r\n%s\r\n\r\n%hs"),

-        expr,

-        message,

-        stack_trace,

-        kErrorRequestToSend);

-  } else {

-    assert_text.AppendFormat(_T("Expression: %hs\r\n\r\n%s\r\n\r\n%hs"),

-                             expr, stack_trace, kErrorRequestToSend);

-  }

-

-  ShowAssertDialog(assert_text, CString(filename));

-  return 1;

-}

-

-#endif  // #ifdef _DEBUG

-

-

-ReportIds::ReportIds() {

-  data_.report_counts_num = 0;

-  NamedObjectAttributes lock_attr;

-  GetNamedObjectAttributes(kReportIdsLock,

-                           vista_util::IsUserAdmin(),

-                           &lock_attr);

-  InitializeWithSecAttr(lock_attr.name, &lock_attr.sa);

-}

-

-ReportIds::~ReportIds() {

-  // don't attempt to write out reports from low integrity mode.

-  //

-  // TODO(omaha): save reports from a low integrity process (specifically IE

-  // which does some extra special magic to thwart this) --

-  // possible by launch a process or a broker, etc.

-  if (vista::IsProcessProtected()) {

-    return;

-  }

-

-  if (data_.report_counts_num != 0) {

-    // Back the report IDs to the registry

-    __mutexBlock(this) {

-      ReportData *reports_in_config = NULL;

-      if (LoadReportData(&reports_in_config)) {

-        MergeReports(reports_in_config, &data_);

-        SaveReportData(reports_in_config);

-

-        byte *data = reinterpret_cast<byte*>(reports_in_config);

-        delete [] data;

-      } else {

-        // There's no data in the registry, so just fill it up with this

-        // component's data.

-        SaveReportData(&data_);

-      }

-    }

-  }

-}

-

-const TCHAR* const GetRegKeyShared() {

-  return vista_util::IsUserAdmin() ? _T("HKLM\\") kCiRegKeyShared :

-                                     _T("HKCU\\") kCiRegKeyShared;

-}

-

-void ReportIds::ResetReportsAfterPing() {

-  // We will lose reports from TRS between the time DebugReportString was called

-  // and now. We'll also lose reports from non TRS components if they exit in

-  // between this time.  Not important.

-  data_.report_counts_num = 0;

-  __mutexBlock(this) {

-    RegKey::DeleteValue(GetRegKeyShared(), kRegValueReportIds);

-  }

-}

-

-void ReportIds::MergeReports(ReportData *data1, const ReportData *data2) {

-  // Loop through each report ID from data2.  If we find it already, increment

-  // the report's count in data1. Otherwise, if there's enough space, add the

-  // report ID to data1.

-  uint32 i, j;

-  for (i = 0; i < data2->report_counts_num; ++i) {

-    bool duplicate_report = false;

-    for (j = 0; j < data1->report_counts_num; ++j) {

-      if (data1->report_ids[j] == data2->report_ids[i]) {

-        // uint16 is promoted to int.

-        data1->report_counts[j] = static_cast<uint16>(

-            data1->report_counts[j] + data2->report_counts[i]);

-        duplicate_report = true;

-      }

-    }

-

-    if (!duplicate_report && j < kMaxUniqueReports) {

-      data1->report_ids[j] = data2->report_ids[i];

-      data1->report_counts[j] = data2->report_counts[i];

-      data1->report_counts_num++;

-    }

-  }

-}

-

-bool ReportIds::LoadReportData(ReportData **data) {

-  DWORD byte_count = 0;

-  *data = NULL;

-  HRESULT hr = RegKey::GetValue(GetRegKeyShared(),

-                                kRegValueReportIds,

-                                reinterpret_cast<byte**>(data),

-                                &byte_count);

-  if (SUCCEEDED(hr)) {

-    if (byte_count == sizeof(ReportData)) {

-      return true;

-    } else {

-      delete[] data;

-      data = NULL;

-      return false;

-    }

-  } else {

-    return false;

-  }

-}

-

-void ReportIds::SaveReportData(ReportData *data) {

-  if (data->report_counts_num) {

-    RegKey::SetValue(GetRegKeyShared(),

-                     kRegValueReportIds,

-                     reinterpret_cast<byte*>(data),

-                     sizeof(ReportData));

-  }

-}

-

-bool ReportIds::ReleaseReport(uint32 id) {

-  uint32 max = data_.report_counts_num;

-

-  // If two threads call simultaneously, might miss one of an existing report

-  // here; not important.

-

-  uint32 i = 0;

-  for (i = 0; i < max; ++i) {

-    if (data_.report_ids[i] == id) {

-      data_.report_counts[i]++;

-      return true;

-      }

-  }

-

-  // If two threads call simultaneously, might overwrite first of another

-  // report; not important.

-

-  if (i < kMaxUniqueReports) {

-    data_.report_ids[i] = id;

-    data_.report_counts[i] = 1;

-    data_.report_counts_num = i + 1;  // Set only after setting ids and count;

-                                      // don't use ++

-  }

-

-#ifdef _DEBUG

-  OutputDebugString(SPRINTF(_T("release report %u\n"), id));

-#endif

-  // must return true (return value of REPORT)

-  return true;

-}

-

-// caller deletes the string

-TCHAR *ReportIds::DebugReportString() {

-  TCHAR *s = new TCHAR[(kMaxUniqueReports * kMaxReportCountString) + 1];

-  if (!s) { return NULL; }

-  s[0] = '\0';

-

-#if 0

-  // this version if we use a hash table for the report counts:

-  uint32 id;

-  uint16 count;

-  hr = g_reports->First(&found, &id, &count);

-  while (SUCCEEDED(hr) && found) {

-    if (count) {

-        status_info.AppendFormat(_T("%d=%d"), id, static_cast<uint32>(count));

-    }

-

-    hr = g_reports->Next(&found, &id, &count);

-  }

-#endif

-

-  // The registry will contain the REPORTs from other components, so get that

-  // list and merge it with TRS'.

-  __mutexBlock(this) {

-    ReportData *reports_in_config = NULL;

-    if (LoadReportData(&reports_in_config)) {

-      MergeReports(&data_, reports_in_config);

-

-      byte *data = reinterpret_cast<byte*>(reports_in_config);

-      delete[] data;

-    }

-  }

-

-  TCHAR *current_pos = s;

-  for (uint32 i = 0; i < data_.report_counts_num; i++) {

-    if (data_.report_counts[i]) {

-      // should be no chance of overflow, ok to use wsprintf

-      int n = wsprintf(current_pos,

-                       _T("%u:%u,"),

-                       data_.report_ids[i],

-                       static_cast<uint32>(data_.report_counts[i]));

-      current_pos += n;

-    }

-  }

-

-  return s;

-}

-

-// A simple helper function whose sole purpose is

-// to isolate the dtor from SPRINTF which uses try/except.

-// app_util::GetAppName returns a CString and dtor's

-// aren't allowed in functions with try/except when

-// the /EHsc flag is set.

-void FillInSprintfErrorString(const TCHAR * format, TCHAR * error_string) {

-  wsprintf(error_string, L"SPRINTF buffer overrun %ls %hs %ls",

-    app_util::GetAppName(), omaha::GetVersionString(), format);

-}

-

-// following is currently included in release build

-// return string from format+arglist; for debugging

-TCHAR * __cdecl SPRINTF(const TCHAR * format, ...) {

-  while (::InterlockedCompareExchange(&g_sprintf_interlock, 1, 0) == 1) {

-  // while (::InterlockedIncrement(&g_sprintf_interlock)>1) {

-    // ::InterlockedDecrement(&g_sprintf_interlock);

-    // Don't process APCs here.

-    // Can lead to infinite recursion, for example: filecap->logging->filecap...

-    Sleep(0);

-  }

-

-  g_current_sprintf_buffer++;

-  if (g_current_sprintf_buffer >= kSprintfBuffers) {

-    g_current_sprintf_buffer = 0;

-  }

-

-  TCHAR *sprintf_buf = NULL;

-

-  if (!g_initialized_sprintf) {  // initialize buffers

-    g_sprintf_buffer = new TCHAR[

-        ((kSprintfMaxLen + 1) * kSprintfBuffers) +

-        kSprintfBufferOverrunPadding];

-    TCHAR* buffer = g_sprintf_buffer;

-    if (!buffer) { goto cleanup; }

-    for (int i = 0; i < kSprintfBuffers; ++i) {

-      g_sprintf_buffers[i] = buffer;

-      buffer += kSprintfMaxLen + 1;

-    }

-

-#if !SHIPPING

-    for (int i = ((kSprintfMaxLen+1) * kSprintfBuffers);

-         i < ((kSprintfMaxLen + 1) * kSprintfBuffers) +

-            kSprintfBufferOverrunPadding;

-         ++i) {

-      g_sprintf_buffer[i] = 1;

-    }

-#endif

-

-    // InitializeCriticalSection(&g_sprintf_critical_section);

-    g_initialized_sprintf = true;

-  }

-

-  sprintf_buf = g_sprintf_buffers[g_current_sprintf_buffer];

-

-  // EnterCriticalSection(&g_sprintf_critical_section);

-

-  __try {

-    // create the formatted CString

-    va_list vl;

-    va_start(vl, format);

-#ifdef DEBUG

-    StringCbVPrintfW(sprintf_buf, kSprintfMaxLen, format, vl);

-#else

-    wvsprintfW(sprintf_buf, format, vl);

-#endif

-    va_end(vl);

-

-#if !SHIPPING

-    for (int i = ((kSprintfMaxLen+1) * kSprintfBuffers);

-         i < ((kSprintfMaxLen+1) * kSprintfBuffers) +

-            kSprintfBufferOverrunPadding;

-         ++i) {

-      if (g_sprintf_buffer[i] != 1) {

-        TCHAR error_string[1024];

-        FillInSprintfErrorString(format, error_string);

-        MessageBox(NULL,

-                   error_string,

-                   error_string,

-                   MB_OK | MB_SETFOREGROUND | MB_TOPMOST);

-        break;

-      }

-    }

-#endif

-  }

-  __except(EXCEPTION_EXECUTE_HANDLER) {

-    lstrcpyn(sprintf_buf, _T("sprintf failure"), kSprintfMaxLen);

-  }

-

-  // LeaveCriticalSection(&g_sprintf_critical_section);

-

-  cleanup:

-

-  ::InterlockedDecrement(&g_sprintf_interlock);

-  return sprintf_buf;

-}

-

-#if 0

-  TCHAR * __cdecl SPRINTF(const TCHAR * format, ...) {

-  ASSERT(format, (L""));

-

-  g_current_sprintf_buffer++;

-  if (g_current_sprintf_buffer >= kSprintfBuffers) {

-    g_current_sprintf_buffer = 0;

-    }

-

-  TCHAR *sprintf_buf = sprintf_buffers[g_current_sprintf_buffer];

-  CFixedStringT<CString, kSprintfMaxLen> out;

-

-  va_list argptr;

-  va_start(argptr, format);

-  out.FormatV(format, argptr);

-  va_end(argptr);

-

-  // copy to fixed return buffers

-  SafeStrCat(sprintf_buf,

-             out.GetBufferSetLength(kSprintfMaxLen),

-             g_current_sprintf_buffer);

-  sprintf_buf[kSprintfMaxLen] = '\0';

-

-  return sprintf_buf;

-}

-#endif

-

-// Cleanup allocated memory

-class SprintfCleaner {

- public:

-  SprintfCleaner() {}

-

-  ~SprintfCleaner() {

-    while (::InterlockedCompareExchange(&g_sprintf_interlock, 1, 0) == 1) {

-      Sleep(0);

-    }

-

-    if (g_initialized_sprintf) {

-      delete[] g_sprintf_buffer;

-      for (int i = 0; i < kSprintfBuffers; ++i) {

-        g_sprintf_buffers[i] = NULL;

-      }

-      g_initialized_sprintf = false;

-    }

-

-    ::InterlockedDecrement(&g_sprintf_interlock);

-  }

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(SprintfCleaner);

-};

-

-static SprintfCleaner cleaner;

-

-// This is for our testers to find asserts in release mode.

-#if !defined(_DEBUG) && defined(ASSERT_IN_RELEASE)

-bool ReleaseAssert(const char *expr,

-                   const TCHAR *msg,

-                   const char *filename,

-                   int32 linenumber) {

-  ASSERT(filename, (L""));

-  ASSERT(msg, (L""));

-  ASSERT(expr, (L""));

-

-  if (debug_assert_interceptor.interceptor()) {

-    // call replacement function (typically used for unit tests)

-    // Note that I'm doing this inside the in_assert block for paranoia;

-    // it's not really necessary and perhaps the wrong choice.

-    debug_assert_interceptor.interceptor()(expr,

-                                           CT2CA(msg),

-                                           filename,

-                                           linenumber);

-    return true;

-  }

-

-  OnAssert(expr, msg, filename, linenumber);

-

-  // Also put up a message box.

-  TCHAR error_string[1024] = {0};

-  wsprintf(error_string,

-           L"App: %ls\r\n"

-           L"Expr: %hs\r\n"

-           L"File: %hs\r\n"

-           L"Line: %d\r\n"

-           L"Version: %hs\r\n"

-           L"Message: ",

-           app_util::GetAppName(),

-           expr,

-           filename,

-           linenumber,

-           VER_TIMESTAMP_STR_FILE);

-  SafeStrCat(error_string, msg, arraysize(error_string));

-  SafeStrCat(error_string,

-             L"\r\n\r\n*** This message has been copied to the clipboard. ***",

-             arraysize(error_string));

-  SetClipboard(error_string);

-

-  TCHAR title_string[1024];

-  wsprintf(title_string, kAppName L" ASSERT %ls %hs",

-    app_util::GetAppName(), VER_TIMESTAMP_STR_FILE);

-  MessageBox(NULL,

-             error_string,

-             title_string,

-             MB_OK | MB_SETFOREGROUND | MB_TOPMOST);

-  return true;

-}

-#endif

-

-#if defined(_DEBUG)

-void DebugAbort(const TCHAR *msg,

-                const char* filename,

-                int32 linenumber,

-                bool do_abort) {

-  DebugReport(0, R_FATAL, "", msg, filename, linenumber, DEBUGREPORT_ABORT);

-  if (do_abort) {

-    abort();

-  }

-}

-#else

-void ReleaseAbort(const TCHAR *msg,

-                  const char* filename,

-                  int32 linenumber,

-                  bool do_abort) {

-  // Send info to the server.

-#if defined(ASSERT_IN_RELEASE)

-  OnAssert("", msg, filename, linenumber);

-#endif

-

-  // Also put up a message box.

-  TCHAR error_string[1024] = {0};

-  wsprintf(error_string,

-           L"App: %ls\r\n"

-           L"File: %hs\r\n"

-           L"Line: %d\r\n"

-           L"Version: %hs\r\n"

-           L"Message: ",

-           app_util::GetAppName(),

-           filename,

-           linenumber,

-           omaha::GetVersionString());

-  SafeStrCat(error_string, msg, arraysize(error_string));

-  SafeStrCat(error_string,

-             L"\r\n\r\n*** This message has been copied to the clipboard. ***",

-             arraysize(error_string));

-  SetClipboard(error_string);

-

-  TCHAR title_string[1024];

-  wsprintf(title_string,

-           kAppName L" ABORT %ls %hs",

-           app_util::GetAppName(),

-           omaha::GetVersionString());

-  MessageBox(NULL,

-             error_string,

-             title_string,

-             MB_OK | MB_SETFOREGROUND | MB_TOPMOST);

-

-  if (do_abort) {

-    abort();

-  }

-}

-#endif

-

-

-#ifdef _DEBUG

-

-void DumpInterface(IUnknown* unknown) {

-  if (!unknown)

-    return;

-

-  OutputDebugString(_T("------------------------------------------------\r\n"));

-

-  // Open the HKCR\Interfaces key where the IIDs of marshalable interfaces

-  // are stored.

-  RegKey key;

-  if (SUCCEEDED(key.Open(HKEY_CLASSES_ROOT, _T("Interface"), KEY_READ))) {

-    TCHAR name[_MAX_PATH + 1] = {0};

-    DWORD name_size = _MAX_PATH;

-    DWORD index = 0;

-    FILETIME last_written;

-

-    //

-    // Enumerate through the IIDs and see if the object supports it

-    // by calling QueryInterface.

-    //

-    while (::RegEnumKeyEx(key.Key(),

-                          index++,

-                          name,

-                          &name_size,

-                          NULL,

-                          NULL,

-                          NULL,

-                          &last_written) == ERROR_SUCCESS) {

-      // Convert the string to an IID

-      IID iid;

-      HRESULT hr = ::CLSIDFromString(name, &iid);

-

-      CComPtr<IUnknown> test;

-      if (unknown->QueryInterface(iid,

-                                  reinterpret_cast<void**>(&test)) == S_OK) {

-        //

-        // The object supports this interface.

-        // See if we can get a human readable name for the interface

-        // If not, the name buffer already contains the string

-        // representation of the IID, which we'll use as a fallback.

-        //

-        RegKey sub_key;

-        if (sub_key.Open(key.Key(), name, KEY_READ) == S_OK) {

-          scoped_array<TCHAR> display;

-          // If this fails, we should still have the IID

-          if (sub_key.GetValue(NULL, address(display)) == S_OK)

-            lstrcpyn(name, display.get(), _MAX_PATH);

-        }

-

-        CString fmt;

-        fmt.Format(_T("  %s\r\n"), name);

-        OutputDebugString(fmt);

-      }

-

-      ZeroMemory(name, arraysize(name));

-      name_size = _MAX_PATH;

-    }

-  }

-

-  OutputDebugString(_T("------------------------------------------------\r\n"));

-}

-#endif

-

-// TODO(omaha): the implementation below is using CStrings so it is not very

-// conservative in terms of memory allocations.

-int SehNoMinidump(unsigned int code, struct _EXCEPTION_POINTERS *,

-                  const char *filename, int32 linenumber, bool show_message) {

-  if (code == EXCEPTION_BREAKPOINT)

-    return EXCEPTION_CONTINUE_SEARCH;

-

-  uint32 latest_cl = 0;

-#ifdef VERSION_LATEST_CL

-  latest_cl = VERSION_LATEST_CL;

-#endif

-

-  if (show_message) {

-    TCHAR message[1025] = {0};

-    wsprintf(message,

-             _T("Exception %x in %s %s %u\r\n\r\n%hs:%d\r\n"),

-             code,

-             app_util::GetAppName(),

-             omaha::GetVersionString(),

-             latest_cl,

-             filename,

-             linenumber);

-

-    SetClipboard(message);

-    uint32 type = MB_ABORTRETRYIGNORE |

-                  MB_ICONERROR |

-                  MB_SERVICE_NOTIFICATION |

-                  MB_SETFOREGROUND |

-                  MB_TOPMOST;

-    int ret = ::MessageBox(NULL, message, _T("Exception"), type);

-    switch (ret) {

-      case IDABORT:

-        // Kamikaze if the user chose 'abort'

-        ::ExitProcess(static_cast<UINT>(-1));

-        break;

-

-      case IDRETRY:

-        // Break if the user chose "retry"

-        __debugbreak();

-        break;

-

-      default:

-        // By default we ignore the message

-      break;

-    }

-  }

-  return EXCEPTION_EXECUTE_HANDLER;

-}

-

-CString GetDebugDirectory() {

-  CString debug_dir;

-  CString system_drive = GetEnvironmentVariableAsString(_T("SystemDrive"));

-  if (!system_drive.IsEmpty()) {

-    debug_dir += system_drive;

-    debug_dir += L"\\";

-  }

-  debug_dir += kCiDebugDirectory;

-  return debug_dir;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Debug functions
+
+#include "omaha/common/debug.h"
+
+#include <dbghelp.h>
+#include <wtsapi32.h>
+#include <atlstr.h>
+#ifdef _DEBUG
+#include <atlcom.h>
+#define STRSAFE_NO_DEPRECATE
+#include <strsafe.h>
+#endif
+#include <stdlib.h>
+#include <signal.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/clipboard.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/const_config.h"
+#include "omaha/common/const_debug.h"
+#include "omaha/common/const_timeouts.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/module_utils.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/common/vista_utils.h"
+
+namespace omaha {
+
+#ifdef _DEBUG
+#define kSprintfBuffers (100)  // number of buffers for SPRINTF
+#else
+#define kSprintfBuffers (3)  // number of buffers for SPRINTF
+#endif
+
+// pad SPRINTF buffer to check for overruns
+#if SHIPPING
+#define kSprintfBufferOverrunPadding 0
+#else  // !SHIPPING
+#ifdef DEBUG
+#define kSprintfBufferOverrunPadding 20000
+#else
+#define kSprintfBufferOverrunPadding 1024
+#endif  // DEBUG
+#endif  // SHIPPING
+
+#define kErrorRequestToSend                                                    \
+    _T("*** Please hit Ignore to continue and send error information to the ") \
+    kAppName                                                                   \
+    _T(" team ***\n*** These details have been pasted to the clipboard ***")
+
+#define kMaxReportSummaryLen (1024*100)  // max length of report summary string
+
+#define kReportIdsLock kLockPrefix                                             \
+    _T("Report_Ids_Lock_57146B01-6A07-4b8d-A1D8-0C3AFC3B2F9B")
+
+SELECTANY bool g_always_assert = false;
+SELECTANY TCHAR *g_additional_status_ping_info = NULL;
+
+#define kSprintfMaxLen (1024 + 2)  // max length that wvsprintf writes is 1024
+static bool g_initialized_sprintf = false;
+static volatile LONG g_sprintf_interlock = 0;
+static int g_current_sprintf_buffer = 0;
+static TCHAR *g_sprintf_buffer = NULL;
+static TCHAR *g_sprintf_buffers[kSprintfBuffers];
+SELECTANY volatile LONG g_debugassertrecursioncheck = 0;
+static int g_total_reports = 0;
+
+SELECTANY ReportIds g_report_ids;
+
+// Builds a full path name out of the given filename. If the filename is
+// a relative path, it is appended to the debug directory. Otherwise, if the
+// filename is a full path, it returns it as the full debug filename.
+static CString MakeFullDebugFilename(const TCHAR *filename) {
+  CString full_name;
+  if (lstrlen(filename) <= 2 || filename[1] != _T(':')) {
+    full_name = GetDebugDirectory();
+    full_name += L"\\";
+  }
+  full_name += filename;
+  return full_name;
+}
+
+
+// Displays the assert box. Due to session isolation, MB_SERVICE_NOTIFICATION
+// flag does not work for Vista services. In this case, use WTS to display
+// a message box in the active console session.
+void ShowAssertDialog(const TCHAR *message, const TCHAR *title) {
+  int ret = 0;
+  OSVERSIONINFOEX osviex = {sizeof(OSVERSIONINFOEX), 0};
+  const bool is_vista_or_greater =
+     ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osviex)) &&
+     osviex.dwMajorVersion >= 6;
+  bool is_system_process = false;
+  if (is_vista_or_greater &&
+      SUCCEEDED(IsSystemProcess(&is_system_process)) &&
+      is_system_process) {
+    DWORD session_id = System::WTSGetActiveConsoleSessionId();
+    if (session_id == kInvalidSessionId) {
+      session_id = WTS_CURRENT_SESSION;
+    }
+    DWORD response = 0;
+    ::WTSSendMessage(WTS_CURRENT_SERVER_HANDLE,
+                     session_id,
+                     const_cast<TCHAR*>(title),
+                     _tcslen(title) * sizeof(TCHAR),
+                     const_cast<TCHAR*>(message),
+                     _tcslen(message) * sizeof(TCHAR),
+                     MB_ABORTRETRYIGNORE | MB_ICONERROR,
+                     0,
+                     &response,
+                     true);
+    ret = response;
+  } else {
+    ret = ::MessageBoxW(NULL,
+                        message,
+                        title,
+                        MB_ABORTRETRYIGNORE |
+                        MB_ICONERROR        |
+                        MB_SERVICE_NOTIFICATION);
+  }
+
+  switch (ret) {
+    case IDABORT:
+      // Terminate the process if the user chose 'Abort'. Calling ExitProcess
+      // here results in calling the destructors for static objects which can
+      // result in deadlocks.
+      raise(SIGABRT);
+      break;
+
+    case IDRETRY:
+      // Break if the user chose "Retry".
+      __debugbreak();
+      break;
+    default:
+      // By default we ignore the message.
+      break;
+  }
+}
+
+DebugObserver* g_debug_observer = NULL;
+
+// replaces the debug observer, returns the previous value.
+DebugObserver* SetDebugObserver(DebugObserver* observer) {
+  DebugObserver* old_value = g_debug_observer;
+  g_debug_observer = observer;
+  return old_value;
+}
+
+DebugObserver* PeekDebugObserver() {
+  return g_debug_observer;
+}
+
+int SehSendMinidump(unsigned int code,
+                    struct _EXCEPTION_POINTERS *ep,
+                    time64 time_between_minidumps) {
+    if (code == EXCEPTION_BREAKPOINT)
+    return EXCEPTION_CONTINUE_SEARCH;
+
+  if (::IsDebuggerPresent())
+    return EXCEPTION_CONTINUE_SEARCH;
+
+  OutputDebugString(L"**SehSendMinidump**\r\n");
+
+  if (g_debug_observer) {
+    return g_debug_observer->SehSendMinidump(code, ep, time_between_minidumps);
+  }
+
+  return EXCEPTION_EXECUTE_HANDLER;
+}
+
+#if defined(_DEBUG) || defined(ASSERT_IN_RELEASE)
+CallInterceptor<DebugAssertFunctionType> debug_assert_interceptor;
+
+// Replaces the debug assert function; returns the old value.
+DebugAssertFunctionType* ReplaceDebugAssertFunction(
+    DebugAssertFunctionType* replacement) {
+  return debug_assert_interceptor.ReplaceFunction(replacement);
+}
+
+void OnAssert(const char *expr, const TCHAR *msg,
+              const char *filename, int32 linenumber) {
+  if (g_debug_observer) {
+    g_debug_observer->OnAssert(expr, msg, filename, linenumber);
+  }
+}
+#endif
+
+#if defined(_DEBUG)
+CString OnDebugReport(uint32 id,
+                      bool is_report,
+                      ReportType type,
+                      const char *expr,
+                      const TCHAR *message,
+                      const char *filename,
+                      int32 linenumber,
+                      DebugReportKind debug_report_kind) {
+  CString trace;
+  if (g_debug_observer) {
+    trace = g_debug_observer->OnDebugReport(id, is_report,
+                                            type, expr, message, filename,
+                                            linenumber, debug_report_kind);
+  }
+  return trace;
+}
+
+void SendExceptionReport(const TCHAR *log_file, const TCHAR *filename, int line,
+                         const TCHAR *type, uint32 id, bool offline) {
+  if (g_debug_observer) {
+    g_debug_observer->SendExceptionReport(log_file, filename, line,
+                                          type, id, offline);
+  }
+}
+#endif
+
+
+#ifdef _DEBUG  // won't compile since _CrtDbgReport isn't defined.
+
+#include <crtdbg.h>    // NOLINT
+static CString g_report_summary;
+
+// dump summary of reports on exit
+SELECTANY ReportSummaryGenerator g_report_summary_generator;
+
+ReportSummaryGenerator::~ReportSummaryGenerator() {
+  DumpReportSummary();
+}
+
+void ReportSummaryGenerator::DumpReportSummary() {
+  if (g_total_reports) {
+    ::OutputDebugString(L"REPORT SUMMARY:\r\n");
+    ::OutputDebugString(SPRINTF(L"%d total reports\r\n", g_total_reports));
+    ::OutputDebugString(g_report_summary);
+  } else {
+    ::OutputDebugString(L"NO REPORTS!!\r\n");
+  }
+}
+
+TCHAR *ReportSummaryGenerator::GetReportSummary() {
+  TCHAR *s = new TCHAR[kMaxReportSummaryLen];
+  if (s) {
+    s[0] = 0;
+    if (g_total_reports) {
+      SafeStrCat(s, L"REPORT SUMMARY:\r\n\r\n", kMaxReportSummaryLen);
+      SafeStrCat(s,
+                 SPRINTF(L"%d total reports\r\n\r\n", g_total_reports),
+                 kMaxReportSummaryLen);
+      SafeStrCat(s,
+                 g_report_summary.
+                     Left(kMaxReportSummaryLen - lstrlen(s) - 1).GetString(),
+                 kMaxReportSummaryLen);
+      CString report_string = g_report_ids.DebugReportString();
+      ReplaceCString(report_string, L"&", L"\r\n");
+      SafeStrCat(s,
+                 report_string.
+                     Left(kMaxReportSummaryLen - lstrlen(s) - 1).GetString(),
+                 kMaxReportSummaryLen);
+    } else {
+      SafeStrCat(s, L"NO REPORTS!!\r\n", kMaxReportSummaryLen);
+    }
+  }
+
+  return s;
+}
+
+static CAtlMap<CString, uint32> g_reports_done;
+
+#endif  // _DEBUG
+
+#ifdef _DEBUG
+
+void TraceError(DWORD error) {
+  HLOCAL mem = NULL;
+  ::FormatMessage(
+    FORMAT_MESSAGE_ALLOCATE_BUFFER |
+    FORMAT_MESSAGE_FROM_SYSTEM |
+    FORMAT_MESSAGE_IGNORE_INSERTS,
+    static_cast<LPVOID>(_AtlBaseModule.GetResourceInstance()),
+    error,
+    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),  // default language
+    reinterpret_cast<TCHAR*>(&mem),
+    0,
+    NULL);
+
+  TCHAR* str = reinterpret_cast<TCHAR*>(::LocalLock(mem));
+  ::OutputDebugString(str);
+  REPORT(false, R_ERROR, (str), 3968294226);
+  ::LocalFree(mem);
+}
+
+// ban ASSERT/VERIFY/REPORT to prevent recursion
+#undef ASSERT
+#undef VERIFY
+#undef REPORT
+
+// TODO(omaha): fix static initialization order below.
+// The initialization order of static variables is not deterministic per C++
+// standard and it depends completely on the compiler implementation.
+// For VC++ compiler we are using, it seems to work as expected.
+// One real fix is to put all definitons of static variables inside a class and
+// define a boolean variable in this class to indicate that all necessary
+// static initializations have been done.
+//
+// The follow definition is used to detect whether we get the exception
+// during initializing static variables. If this is the case, DebugReport()
+// will not function and will throw an exception because some of its refering
+// static variables are not initialized yet (i.e. g_reports_done).
+const int kTestInitStaticVariablesDoneValue = 1234;
+struct TestInitStaticVariablesDone {
+  int value;
+  TestInitStaticVariablesDone() : value(kTestInitStaticVariablesDoneValue) {}
+};
+static TestInitStaticVariablesDone test_var;
+
+bool DebugReport(unsigned int id,
+                 ReportType type,
+                 const char *expr,
+                 const TCHAR *message,
+                 const char *filename,
+                 int linenumber,
+                 DebugReportKind debug_report_kind) {
+  int recursion_count = ::InterlockedIncrement(&g_debugassertrecursioncheck);
+  ON_SCOPE_EXIT(::InterlockedDecrement, &g_debugassertrecursioncheck);
+  if (recursion_count > 1) {
+    ::OutputDebugString(_T("recursive debugreport skipped\n"));
+    return 1;
+  }
+
+  if (debug_assert_interceptor.interceptor()) {
+    // call replacement function (typically used for unit tests)
+    // Note that I'm doing this inside the in_assert block for paranoia;
+    // it's not really necessary and perhaps the wrong choice.
+    debug_assert_interceptor.interceptor()(expr, CT2A(message), filename,
+                                            linenumber);
+    return true;
+  }
+
+
+  // Check whether we have already finished initializing all static variables
+  // needed for executing DebugReport(). If not, bail out.
+  if (test_var.value != kTestInitStaticVariablesDoneValue) {
+    CString debug_msg;
+    debug_msg.Format(_T("%hs:%d - %s - %S"),
+                     filename, linenumber, message, expr);
+    debug_msg.Append(_T("\n\nException occurs while initializing ")
+                     _T("static variables needed for DebugReport"));
+    ShowAssertDialog(debug_msg, _T("DebugReport"));
+    return true;
+  }
+
+  bool is_assert = debug_report_kind == DEBUGREPORT_ASSERT;
+  bool is_report = debug_report_kind == DEBUGREPORT_REPORT;
+  bool is_abort  = debug_report_kind == DEBUGREPORT_ABORT;
+
+  if (is_report)
+    g_total_reports++;
+
+  g_report_ids.ReleaseReport(id);
+
+  if (type == R_FATAL) {
+    if (is_report) {
+      // Treat as ASSERT
+      is_report = false;
+      is_assert = true;
+    }
+  }
+
+  bool always_assert = g_always_assert;
+
+  if (always_assert) {
+    is_report = false;
+    is_assert = true;
+  }
+
+  if (!message) {
+    message = _T("");
+  }
+
+  // log to debugger
+  TCHAR *debug_string;
+  // ::OutputDebugString(DEBUG_LOG_SEPARATOR);
+  ::OutputDebugString(is_report ? _T("REPORT: ") :
+                                  (is_assert ? _T("ASSERT: ") : _T("ABORT: ")));
+
+  CFixedStringT<CString, 1024> proc_name = app_util::GetAppName();
+
+  // last %s now %s skip %d
+  const TCHAR* format = message && *message ?
+                        _T("[%hs:%d][%hs][%s]") : _T("[%hs:%d][%hs]");
+  debug_string = SPRINTF(format, filename, linenumber, expr, message);
+
+  // String_Int64ToString(g_last_report_time, 10),
+  // String_Int64ToString(time, 10), skip_report));
+
+  // ::OutputDebugString(DEBUG_LOG_SEPARATOR);
+  // ::OutputDebugString(_T("\n"));
+
+#ifdef LOGGING
+  // Log the reports via the logging system to all loggers.
+  CString what = is_report ? _T("REPORT") :
+                             is_assert ? _T("ASSERT") : _T("ABORT");
+  LC_LOG(LC_LOGGING, LEVEL_ERROR, (_T("[%s]%s"), what, debug_string));
+#else
+  ::OutputDebugString(debug_string);
+  ::OutputDebugString(_T("\n"));
+#endif
+
+  // skip sending strack trace for duplicate reports
+  CString report_id;
+  report_id.Format(_T("%hs:%d"), filename, linenumber);
+
+  uint32 prev_reports = 0;
+  if (g_reports_done.Lookup(report_id, prev_reports) && is_report) {
+    prev_reports++;
+    g_reports_done.SetAt(report_id, prev_reports);
+    ::OutputDebugString(SPRINTF(_T("skipping duplicate report %s %d\n"),
+                                report_id.GetString(),
+                                prev_reports));
+    return 1;
+  }
+
+  prev_reports++;
+  g_reports_done.SetAt(report_id, prev_reports);
+
+  g_report_summary.Append(debug_string);
+  g_report_summary.Append(L" (");
+  g_report_summary.Append(itostr(id));
+  g_report_summary.Append(L")");
+  g_report_summary.Append(L"\r\n");
+
+  // ::OutputDebugString(_T("log to file\n"));
+
+  // log to file
+  CString path_name(MakeFullDebugFilename(kCiDebugLogFile));
+  HANDLE h = CreateFile(path_name,
+                        GENERIC_WRITE | GENERIC_READ,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        NULL,
+                        OPEN_ALWAYS,
+                        FILE_ATTRIBUTE_NORMAL,
+                        NULL);
+
+  HANDLE assert_file = INVALID_HANDLE_VALUE;
+  if (is_assert) {
+    path_name = MakeFullDebugFilename(kCiAssertOccurredFile);
+    assert_file = CreateFile(path_name,
+                             GENERIC_WRITE,
+                             0,
+                             0,
+                             OPEN_ALWAYS,
+                             FILE_FLAG_WRITE_THROUGH,
+                             NULL);
+  }
+
+  HANDLE abort_file = INVALID_HANDLE_VALUE;
+  if (is_abort) {
+    path_name = MakeFullDebugFilename(kCiAbortOccurredFile);
+    abort_file = CreateFile(path_name,
+                            GENERIC_WRITE,
+                            0,
+                            0,
+                            OPEN_ALWAYS,
+                            FILE_FLAG_WRITE_THROUGH,
+                            NULL);
+  }
+
+  if (h != INVALID_HANDLE_VALUE ||
+      assert_file != INVALID_HANDLE_VALUE ||
+      abort_file != INVALID_HANDLE_VALUE) {
+    // more convenient for now to have this in UTF8
+    char *utf8_buffer = new char[(lstrlen(debug_string)*2) + 1];
+    if (utf8_buffer) {
+        int conv_bytes = WideCharToMultiByte(CP_UTF8,
+                                             0,
+                                             debug_string,
+                                             lstrlen(debug_string),
+                                             utf8_buffer,
+                                             (lstrlen(debug_string) * 2) + 1,
+                                             NULL,
+                                             NULL);
+
+        if (conv_bytes) {
+            DWORD bytes_written;
+            BOOL result;
+
+            if (h != INVALID_HANDLE_VALUE) {
+              SetFilePointer(h, 0, NULL, FILE_END);
+              result = ::WriteFile(h,
+                                   (LPCVOID)utf8_buffer,
+                                   conv_bytes,
+                                   &bytes_written,
+                                   NULL);
+              result = ::WriteFile(h,
+                                   (LPCVOID)DEBUG_LOG_SEPARATOR_CHAR,
+                                   strlen(DEBUG_LOG_SEPARATOR_CHAR),
+                                   &bytes_written,
+                                   NULL);
+            }
+            if (assert_file != INVALID_HANDLE_VALUE) {
+              result = ::WriteFile(assert_file,
+                                   (LPCVOID)utf8_buffer,
+                                   conv_bytes,
+                                   &bytes_written,
+                                   NULL);
+            }
+            if (abort_file != INVALID_HANDLE_VALUE) {
+              result = ::WriteFile(abort_file,
+                                   (LPCVOID)utf8_buffer,
+                                   conv_bytes,
+                                   &bytes_written,
+                                   NULL);
+            }
+        }
+
+        delete [] utf8_buffer;
+    }
+  }
+
+  if (h != INVALID_HANDLE_VALUE) {
+    ::CloseHandle(h);
+  }
+  if (assert_file != INVALID_HANDLE_VALUE) {
+    ::CloseHandle(assert_file);
+  }
+  if (abort_file != INVALID_HANDLE_VALUE) {
+    ::CloseHandle(abort_file);
+  }
+
+  CString stack_trace = OnDebugReport(id, is_report, type, expr, message,
+                                      filename, linenumber, debug_report_kind);
+
+  if (is_report) {
+    return 1;
+  }
+
+  ::OutputDebugString(L"show assert dialog\r\n");
+  ::OutputDebugString(stack_trace.GetString());
+
+  CString process_path;
+  GetModuleFileName(NULL, &process_path);
+
+  static TCHAR clipboard_string[4096] = {0};
+  lstrcpyn(clipboard_string,
+           SPRINTF(L"%ls (pid=%i)\r\n%hs:%d\r\n\r\n%hs\r\n%s\r\n\r\n",
+                   process_path,
+                   ::GetCurrentProcessId(),
+                   filename,
+                   linenumber,
+                   expr,
+                   message),
+           arraysize(clipboard_string));
+  stack_trace = stack_trace.Left(
+      arraysize(clipboard_string) - lstrlen(clipboard_string) - 1);
+  SafeStrCat(clipboard_string, stack_trace, arraysize(clipboard_string));
+  SetClipboard(clipboard_string);
+
+  stack_trace = stack_trace.Left(kMaxStackTraceDialogLen);
+
+  CString assert_text;
+  assert_text.Format(_T("Assertion (%ls) failed!\r\n\r\nProcess: %d ")
+    _T("(0x%08X)\r\nThread %d (0x%08X)\r\nProgram: %ls\r\n")
+    _T("Version: %s\r\nFile: %hs\r\nLine: %d\r\n\r\n"),
+    debug_report_kind == DEBUGREPORT_ASSERT ?
+      L"Assert" : (debug_report_kind == DEBUGREPORT_ABORT ?
+      L"Abort" : L"Report"),
+    ::GetCurrentProcessId(), ::GetCurrentProcessId(), ::GetCurrentThreadId(),
+    ::GetCurrentThreadId(), process_path, omaha::GetVersionString(), filename,
+    linenumber);
+
+  if (lstrlen(message) > 0) {
+    assert_text.AppendFormat(
+        _T("Expression: %hs\r\nMessage: %s\r\n\r\n%s\r\n\r\n%hs"),
+        expr,
+        message,
+        stack_trace,
+        kErrorRequestToSend);
+  } else {
+    assert_text.AppendFormat(_T("Expression: %hs\r\n\r\n%s\r\n\r\n%hs"),
+                             expr, stack_trace, kErrorRequestToSend);
+  }
+
+  ShowAssertDialog(assert_text, CString(filename));
+  return 1;
+}
+
+#endif  // #ifdef _DEBUG
+
+
+ReportIds::ReportIds() {
+  data_.report_counts_num = 0;
+  NamedObjectAttributes lock_attr;
+  GetNamedObjectAttributes(kReportIdsLock,
+                           vista_util::IsUserAdmin(),
+                           &lock_attr);
+  InitializeWithSecAttr(lock_attr.name, &lock_attr.sa);
+}
+
+ReportIds::~ReportIds() {
+  // don't attempt to write out reports from low integrity mode.
+  //
+  // TODO(omaha): save reports from a low integrity process (specifically IE
+  // which does some extra special magic to thwart this) --
+  // possible by launch a process or a broker, etc.
+  if (vista::IsProcessProtected()) {
+    return;
+  }
+
+  if (data_.report_counts_num != 0) {
+    // Back the report IDs to the registry
+    __mutexBlock(this) {
+      ReportData *reports_in_config = NULL;
+      if (LoadReportData(&reports_in_config)) {
+        MergeReports(reports_in_config, &data_);
+        SaveReportData(reports_in_config);
+
+        byte *data = reinterpret_cast<byte*>(reports_in_config);
+        delete [] data;
+      } else {
+        // There's no data in the registry, so just fill it up with this
+        // component's data.
+        SaveReportData(&data_);
+      }
+    }
+  }
+}
+
+const TCHAR* const GetRegKeyShared() {
+  return vista_util::IsUserAdmin() ? _T("HKLM\\") kCiRegKeyShared :
+                                     _T("HKCU\\") kCiRegKeyShared;
+}
+
+void ReportIds::ResetReportsAfterPing() {
+  // We will lose reports from TRS between the time DebugReportString was called
+  // and now. We'll also lose reports from non TRS components if they exit in
+  // between this time.  Not important.
+  data_.report_counts_num = 0;
+  __mutexBlock(this) {
+    RegKey::DeleteValue(GetRegKeyShared(), kRegValueReportIds);
+  }
+}
+
+void ReportIds::MergeReports(ReportData *data1, const ReportData *data2) {
+  // Loop through each report ID from data2.  If we find it already, increment
+  // the report's count in data1. Otherwise, if there's enough space, add the
+  // report ID to data1.
+  uint32 i, j;
+  for (i = 0; i < data2->report_counts_num; ++i) {
+    bool duplicate_report = false;
+    for (j = 0; j < data1->report_counts_num; ++j) {
+      if (data1->report_ids[j] == data2->report_ids[i]) {
+        // uint16 is promoted to int.
+        data1->report_counts[j] = static_cast<uint16>(
+            data1->report_counts[j] + data2->report_counts[i]);
+        duplicate_report = true;
+      }
+    }
+
+    if (!duplicate_report && j < kMaxUniqueReports) {
+      data1->report_ids[j] = data2->report_ids[i];
+      data1->report_counts[j] = data2->report_counts[i];
+      data1->report_counts_num++;
+    }
+  }
+}
+
+bool ReportIds::LoadReportData(ReportData **data) {
+  DWORD byte_count = 0;
+  *data = NULL;
+  HRESULT hr = RegKey::GetValue(GetRegKeyShared(),
+                                kRegValueReportIds,
+                                reinterpret_cast<byte**>(data),
+                                &byte_count);
+  if (SUCCEEDED(hr)) {
+    if (byte_count == sizeof(ReportData)) {
+      return true;
+    } else {
+      delete[] data;
+      data = NULL;
+      return false;
+    }
+  } else {
+    return false;
+  }
+}
+
+void ReportIds::SaveReportData(ReportData *data) {
+  if (data->report_counts_num) {
+    RegKey::SetValue(GetRegKeyShared(),
+                     kRegValueReportIds,
+                     reinterpret_cast<byte*>(data),
+                     sizeof(ReportData));
+  }
+}
+
+bool ReportIds::ReleaseReport(uint32 id) {
+  uint32 max = data_.report_counts_num;
+
+  // If two threads call simultaneously, might miss one of an existing report
+  // here; not important.
+
+  uint32 i = 0;
+  for (i = 0; i < max; ++i) {
+    if (data_.report_ids[i] == id) {
+      data_.report_counts[i]++;
+      return true;
+      }
+  }
+
+  // If two threads call simultaneously, might overwrite first of another
+  // report; not important.
+
+  if (i < kMaxUniqueReports) {
+    data_.report_ids[i] = id;
+    data_.report_counts[i] = 1;
+    data_.report_counts_num = i + 1;  // Set only after setting ids and count;
+                                      // don't use ++
+  }
+
+#ifdef _DEBUG
+  OutputDebugString(SPRINTF(_T("release report %u\n"), id));
+#endif
+  // must return true (return value of REPORT)
+  return true;
+}
+
+// caller deletes the string
+TCHAR *ReportIds::DebugReportString() {
+  TCHAR *s = new TCHAR[(kMaxUniqueReports * kMaxReportCountString) + 1];
+  if (!s) { return NULL; }
+  s[0] = '\0';
+
+#if 0
+  // this version if we use a hash table for the report counts:
+  uint32 id;
+  uint16 count;
+  hr = g_reports->First(&found, &id, &count);
+  while (SUCCEEDED(hr) && found) {
+    if (count) {
+        status_info.AppendFormat(_T("%d=%d"), id, static_cast<uint32>(count));
+    }
+
+    hr = g_reports->Next(&found, &id, &count);
+  }
+#endif
+
+  // The registry will contain the REPORTs from other components, so get that
+  // list and merge it with TRS'.
+  __mutexBlock(this) {
+    ReportData *reports_in_config = NULL;
+    if (LoadReportData(&reports_in_config)) {
+      MergeReports(&data_, reports_in_config);
+
+      byte *data = reinterpret_cast<byte*>(reports_in_config);
+      delete[] data;
+    }
+  }
+
+  TCHAR *current_pos = s;
+  for (uint32 i = 0; i < data_.report_counts_num; i++) {
+    if (data_.report_counts[i]) {
+      // should be no chance of overflow, ok to use wsprintf
+      int n = wsprintf(current_pos,
+                       _T("%u:%u,"),
+                       data_.report_ids[i],
+                       static_cast<uint32>(data_.report_counts[i]));
+      current_pos += n;
+    }
+  }
+
+  return s;
+}
+
+// A simple helper function whose sole purpose is
+// to isolate the dtor from SPRINTF which uses try/except.
+// app_util::GetAppName returns a CString and dtor's
+// aren't allowed in functions with try/except when
+// the /EHsc flag is set.
+void FillInSprintfErrorString(const TCHAR * format, TCHAR * error_string) {
+  wsprintf(error_string, L"SPRINTF buffer overrun %ls %hs %ls",
+    app_util::GetAppName(), omaha::GetVersionString(), format);
+}
+
+// following is currently included in release build
+// return string from format+arglist; for debugging
+TCHAR * __cdecl SPRINTF(const TCHAR * format, ...) {
+  while (::InterlockedCompareExchange(&g_sprintf_interlock, 1, 0) == 1) {
+  // while (::InterlockedIncrement(&g_sprintf_interlock)>1) {
+    // ::InterlockedDecrement(&g_sprintf_interlock);
+    // Don't process APCs here.
+    // Can lead to infinite recursion, for example: filecap->logging->filecap...
+    Sleep(0);
+  }
+
+  g_current_sprintf_buffer++;
+  if (g_current_sprintf_buffer >= kSprintfBuffers) {
+    g_current_sprintf_buffer = 0;
+  }
+
+  TCHAR *sprintf_buf = NULL;
+
+  if (!g_initialized_sprintf) {  // initialize buffers
+    g_sprintf_buffer = new TCHAR[
+        ((kSprintfMaxLen + 1) * kSprintfBuffers) +
+        kSprintfBufferOverrunPadding];
+    TCHAR* buffer = g_sprintf_buffer;
+    if (!buffer) { goto cleanup; }
+    for (int i = 0; i < kSprintfBuffers; ++i) {
+      g_sprintf_buffers[i] = buffer;
+      buffer += kSprintfMaxLen + 1;
+    }
+
+#if !SHIPPING
+    for (int i = ((kSprintfMaxLen+1) * kSprintfBuffers);
+         i < ((kSprintfMaxLen + 1) * kSprintfBuffers) +
+            kSprintfBufferOverrunPadding;
+         ++i) {
+      g_sprintf_buffer[i] = 1;
+    }
+#endif
+
+    // InitializeCriticalSection(&g_sprintf_critical_section);
+    g_initialized_sprintf = true;
+  }
+
+  sprintf_buf = g_sprintf_buffers[g_current_sprintf_buffer];
+
+  // EnterCriticalSection(&g_sprintf_critical_section);
+
+  __try {
+    // create the formatted CString
+    va_list vl;
+    va_start(vl, format);
+#ifdef DEBUG
+    StringCbVPrintfW(sprintf_buf, kSprintfMaxLen, format, vl);
+#else
+    wvsprintfW(sprintf_buf, format, vl);
+#endif
+    va_end(vl);
+
+#if !SHIPPING
+    for (int i = ((kSprintfMaxLen+1) * kSprintfBuffers);
+         i < ((kSprintfMaxLen+1) * kSprintfBuffers) +
+            kSprintfBufferOverrunPadding;
+         ++i) {
+      if (g_sprintf_buffer[i] != 1) {
+        TCHAR error_string[1024];
+        FillInSprintfErrorString(format, error_string);
+        MessageBox(NULL,
+                   error_string,
+                   error_string,
+                   MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
+        break;
+      }
+    }
+#endif
+  }
+  __except(EXCEPTION_EXECUTE_HANDLER) {
+    lstrcpyn(sprintf_buf, _T("sprintf failure"), kSprintfMaxLen);
+  }
+
+  // LeaveCriticalSection(&g_sprintf_critical_section);
+
+  cleanup:
+
+  ::InterlockedDecrement(&g_sprintf_interlock);
+  return sprintf_buf;
+}
+
+#if 0
+  TCHAR * __cdecl SPRINTF(const TCHAR * format, ...) {
+  ASSERT(format, (L""));
+
+  g_current_sprintf_buffer++;
+  if (g_current_sprintf_buffer >= kSprintfBuffers) {
+    g_current_sprintf_buffer = 0;
+    }
+
+  TCHAR *sprintf_buf = sprintf_buffers[g_current_sprintf_buffer];
+  CFixedStringT<CString, kSprintfMaxLen> out;
+
+  va_list argptr;
+  va_start(argptr, format);
+  out.FormatV(format, argptr);
+  va_end(argptr);
+
+  // copy to fixed return buffers
+  SafeStrCat(sprintf_buf,
+             out.GetBufferSetLength(kSprintfMaxLen),
+             g_current_sprintf_buffer);
+  sprintf_buf[kSprintfMaxLen] = '\0';
+
+  return sprintf_buf;
+}
+#endif
+
+// Cleanup allocated memory
+class SprintfCleaner {
+ public:
+  SprintfCleaner() {}
+
+  ~SprintfCleaner() {
+    while (::InterlockedCompareExchange(&g_sprintf_interlock, 1, 0) == 1) {
+      Sleep(0);
+    }
+
+    if (g_initialized_sprintf) {
+      delete[] g_sprintf_buffer;
+      for (int i = 0; i < kSprintfBuffers; ++i) {
+        g_sprintf_buffers[i] = NULL;
+      }
+      g_initialized_sprintf = false;
+    }
+
+    ::InterlockedDecrement(&g_sprintf_interlock);
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(SprintfCleaner);
+};
+
+static SprintfCleaner cleaner;
+
+// This is for our testers to find asserts in release mode.
+#if !defined(_DEBUG) && defined(ASSERT_IN_RELEASE)
+bool ReleaseAssert(const char *expr,
+                   const TCHAR *msg,
+                   const char *filename,
+                   int32 linenumber) {
+  ASSERT(filename, (L""));
+  ASSERT(msg, (L""));
+  ASSERT(expr, (L""));
+
+  if (debug_assert_interceptor.interceptor()) {
+    // call replacement function (typically used for unit tests)
+    // Note that I'm doing this inside the in_assert block for paranoia;
+    // it's not really necessary and perhaps the wrong choice.
+    debug_assert_interceptor.interceptor()(expr,
+                                           CT2CA(msg),
+                                           filename,
+                                           linenumber);
+    return true;
+  }
+
+  OnAssert(expr, msg, filename, linenumber);
+
+  // Also put up a message box.
+  TCHAR error_string[1024] = {0};
+  wsprintf(error_string,
+           L"App: %ls\r\n"
+           L"Expr: %hs\r\n"
+           L"File: %hs\r\n"
+           L"Line: %d\r\n"
+           L"Version: %hs\r\n"
+           L"Message: ",
+           app_util::GetAppName(),
+           expr,
+           filename,
+           linenumber,
+           VER_TIMESTAMP_STR_FILE);
+  SafeStrCat(error_string, msg, arraysize(error_string));
+  SafeStrCat(error_string,
+             L"\r\n\r\n*** This message has been copied to the clipboard. ***",
+             arraysize(error_string));
+  SetClipboard(error_string);
+
+  TCHAR title_string[1024];
+  wsprintf(title_string, kAppName L" ASSERT %ls %hs",
+    app_util::GetAppName(), VER_TIMESTAMP_STR_FILE);
+  MessageBox(NULL,
+             error_string,
+             title_string,
+             MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
+  return true;
+}
+#endif
+
+#if defined(_DEBUG)
+void DebugAbort(const TCHAR *msg,
+                const char* filename,
+                int32 linenumber,
+                bool do_abort) {
+  DebugReport(0, R_FATAL, "", msg, filename, linenumber, DEBUGREPORT_ABORT);
+  if (do_abort) {
+    abort();
+  }
+}
+#else
+void ReleaseAbort(const TCHAR *msg,
+                  const char* filename,
+                  int32 linenumber,
+                  bool do_abort) {
+  // Send info to the server.
+#if defined(ASSERT_IN_RELEASE)
+  OnAssert("", msg, filename, linenumber);
+#endif
+
+  // Also put up a message box.
+  TCHAR error_string[1024] = {0};
+  wsprintf(error_string,
+           L"App: %ls\r\n"
+           L"File: %hs\r\n"
+           L"Line: %d\r\n"
+           L"Version: %hs\r\n"
+           L"Message: ",
+           app_util::GetAppName(),
+           filename,
+           linenumber,
+           omaha::GetVersionString());
+  SafeStrCat(error_string, msg, arraysize(error_string));
+  SafeStrCat(error_string,
+             L"\r\n\r\n*** This message has been copied to the clipboard. ***",
+             arraysize(error_string));
+  SetClipboard(error_string);
+
+  TCHAR title_string[1024];
+  wsprintf(title_string,
+           kAppName L" ABORT %ls %hs",
+           app_util::GetAppName(),
+           omaha::GetVersionString());
+  MessageBox(NULL,
+             error_string,
+             title_string,
+             MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
+
+  if (do_abort) {
+    abort();
+  }
+}
+#endif
+
+
+#ifdef _DEBUG
+
+void DumpInterface(IUnknown* unknown) {
+  if (!unknown)
+    return;
+
+  OutputDebugString(_T("------------------------------------------------\r\n"));
+
+  // Open the HKCR\Interfaces key where the IIDs of marshalable interfaces
+  // are stored.
+  RegKey key;
+  if (SUCCEEDED(key.Open(HKEY_CLASSES_ROOT, _T("Interface"), KEY_READ))) {
+    TCHAR name[_MAX_PATH + 1] = {0};
+    DWORD name_size = _MAX_PATH;
+    DWORD index = 0;
+    FILETIME last_written;
+
+    //
+    // Enumerate through the IIDs and see if the object supports it
+    // by calling QueryInterface.
+    //
+    while (::RegEnumKeyEx(key.Key(),
+                          index++,
+                          name,
+                          &name_size,
+                          NULL,
+                          NULL,
+                          NULL,
+                          &last_written) == ERROR_SUCCESS) {
+      // Convert the string to an IID
+      IID iid;
+      HRESULT hr = ::CLSIDFromString(name, &iid);
+
+      CComPtr<IUnknown> test;
+      if (unknown->QueryInterface(iid,
+                                  reinterpret_cast<void**>(&test)) == S_OK) {
+        //
+        // The object supports this interface.
+        // See if we can get a human readable name for the interface
+        // If not, the name buffer already contains the string
+        // representation of the IID, which we'll use as a fallback.
+        //
+        RegKey sub_key;
+        if (sub_key.Open(key.Key(), name, KEY_READ) == S_OK) {
+          scoped_array<TCHAR> display;
+          // If this fails, we should still have the IID
+          if (sub_key.GetValue(NULL, address(display)) == S_OK)
+            lstrcpyn(name, display.get(), _MAX_PATH);
+        }
+
+        CString fmt;
+        fmt.Format(_T("  %s\r\n"), name);
+        OutputDebugString(fmt);
+      }
+
+      ZeroMemory(name, arraysize(name));
+      name_size = _MAX_PATH;
+    }
+  }
+
+  OutputDebugString(_T("------------------------------------------------\r\n"));
+}
+#endif
+
+// TODO(omaha): the implementation below is using CStrings so it is not very
+// conservative in terms of memory allocations.
+int SehNoMinidump(unsigned int code, struct _EXCEPTION_POINTERS *,
+                  const char *filename, int32 linenumber, bool show_message) {
+  if (code == EXCEPTION_BREAKPOINT)
+    return EXCEPTION_CONTINUE_SEARCH;
+
+  uint32 latest_cl = 0;
+#ifdef VERSION_LATEST_CL
+  latest_cl = VERSION_LATEST_CL;
+#endif
+
+  if (show_message) {
+    TCHAR message[1025] = {0};
+    wsprintf(message,
+             _T("Exception %x in %s %s %u\r\n\r\n%hs:%d\r\n"),
+             code,
+             app_util::GetAppName(),
+             omaha::GetVersionString(),
+             latest_cl,
+             filename,
+             linenumber);
+
+    SetClipboard(message);
+    uint32 type = MB_ABORTRETRYIGNORE |
+                  MB_ICONERROR |
+                  MB_SERVICE_NOTIFICATION |
+                  MB_SETFOREGROUND |
+                  MB_TOPMOST;
+    int ret = ::MessageBox(NULL, message, _T("Exception"), type);
+    switch (ret) {
+      case IDABORT:
+        // Kamikaze if the user chose 'abort'
+        ::ExitProcess(static_cast<UINT>(-1));
+        break;
+
+      case IDRETRY:
+        // Break if the user chose "retry"
+        __debugbreak();
+        break;
+
+      default:
+        // By default we ignore the message
+      break;
+    }
+  }
+  return EXCEPTION_EXECUTE_HANDLER;
+}
+
+CString GetDebugDirectory() {
+  CString debug_dir;
+  CString system_drive = GetEnvironmentVariableAsString(_T("SystemDrive"));
+  if (!system_drive.IsEmpty()) {
+    debug_dir += system_drive;
+    debug_dir += L"\\";
+  }
+  debug_dir += kCiDebugDirectory;
+  return debug_dir;
+}
+
+}  // namespace omaha
+
diff --git a/common/debug.h b/common/debug.h
index b45d495..6f0679f 100644
--- a/common/debug.h
+++ b/common/debug.h
@@ -1,316 +1,316 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Debug functions

-

-#ifndef OMAHA_COMMON_DEBUG_H__

-#define OMAHA_COMMON_DEBUG_H__

-

-// To create a release build with asserts turned on, uncomment the

-// following line, and uncomment the linking with atls.lib in api.

-//

-// #define ASSERT_IN_RELEASE

-

-#include "omaha/common/atlassert.h"

-#include "omaha/common/commontypes.h"

-#include "omaha/common/synchronized.h"

-

-namespace omaha {

-

-// hash table for counts of the number of times REPORTs occur

-// template<class K, class V>

-// class HashTable;

-// extern HashTable<uint32, uint16> *g_reports;

-

-#define kMaxUniqueReports (20)

-#define kMaxReportCountString (20)

-

-class ReportIds;

-extern ReportIds g_report_ids;

-extern volatile LONG g_debugassertrecursioncheck;

-extern bool g_always_assert;

-

-const int kMaxStackTraceDialogLen = 512;  // too long and dialog box fails

-

-// TODO(omaha): consider merging this into DebugObserver.

-//

-// For automated testing, we don't (always) want asserts to fire. So

-// we allow the unit test system to handle asserts instead.

-//

-// Give a function matching the prototype to REPLACE_ASSERT_FUNCTION to

-// have your function called instead of the normal assert function.

-typedef int DebugAssertFunctionType(const char *expression,

-  const char *message, const char *file, int line);

-

-enum ReportType;

-enum DebugReportKind;

-class DebugObserver {

- public:

-  virtual ~DebugObserver() {}

-  virtual int SehSendMinidump(unsigned int code, struct _EXCEPTION_POINTERS *ep,

-                              time64 time_between_minidumps) = 0;

-

-#if defined(_DEBUG) || defined(ASSERT_IN_RELEASE)

-  virtual void OnAssert(const char *expr, const TCHAR *msg,

-                        const char *filename, int32 linenumber) = 0;

-#endif

-

-#if defined(_DEBUG)

-  virtual void SendExceptionReport(const TCHAR *log_file, const TCHAR *filename,

-                                   int line, const TCHAR *type, uint32 id,

-                                   bool offline) = 0;

-  virtual CString OnDebugReport(uint32 id, bool is_report, ReportType type,

-                                const char *expr, const TCHAR *message,

-                                const char *filename, int32 linenumber,

-                                DebugReportKind debug_report_kind) = 0;

-#endif

-};

-

-// replaces the debug observer, returns the previous value.

-DebugObserver* SetDebugObserver(DebugObserver* observer);

-DebugObserver* PeekDebugObserver();

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-int SehSendMinidump(unsigned int code,

-                    struct _EXCEPTION_POINTERS *ep,

-                    time64 time_between_minidumps);

-

-#define kMinReportInterval100ns (60 * kSecsTo100ns)

-#define kMinStackReportInterval100ns (60 * kSecsTo100ns)

-#define DEBUG_LOG_SEPARATOR_CHAR "-------------------------------------------\n"

-#define DEBUG_LOG_SEPARATOR     L"-------------------------------------------\n"

-#define kExceptionReportHeaders L"Content-Type: binary"

-

-// TODO(omaha): disable the exception reporting feature to save .data space

-#define kMaxExceptionReportLen 1

-

-#define kMinidumpRequestToSendMessage                               \

-    kAppName L" has encountered a problem.\n***"                    \

-    L"Please hit OK to debug if you have a debugger installed, "    \

-    L"or cancel to continue."                                       \

-

-#define kMinidumpRequestToSendTitle kAppName L" quality assurance"

-

-#undef ASSERT

-#undef VERIFY

-#undef TRACE

-

-// Holds information about REPORTS and their frequency

-struct ReportData {

-  uint32 report_counts_num;

-  uint32 report_ids[kMaxUniqueReports];

-  uint16 report_counts[kMaxUniqueReports];

-};

-

-// Used to hold REPORT IDs and to back them to the registry, where they'll be

-// read and sent in a ping.

-class ReportIds : public GLock {

- public:

-  ReportIds();

-  ~ReportIds();

-

-  // Call this after a successful ping to clear the report IDs from the registry

-  // and from this component (TRS).

-  void ResetReportsAfterPing();

-

-  // Adds a report ID to our list, if there's enough space.

-  bool ReleaseReport(uint32 id);

-

-  // Creates a string with the report IDs and their frequency.

-  // Caller deletes string.

-  TCHAR *DebugReportString();

-

- private:

-  ReportData data_;

-

-  // Merges the report data from data2 with data1.

-  void MergeReports(ReportData *data1, const ReportData *data2);

-

-  // We have to use RegKey directly, because we can't depend on the global

-  // Config object during destruction.

-  bool LoadReportData(ReportData **data);

-  void SaveReportData(ReportData *data);

-

-  DISALLOW_EVIL_CONSTRUCTORS(ReportIds);

-};

-

-#if defined(_DEBUG) || defined(ASSERT_IN_RELEASE)

-  // Replaces the debug assert function; returns the old value.

-  DebugAssertFunctionType *ReplaceDebugAssertFunction(DebugAssertFunctionType

-                                                      *replacement);

-  #define REPLACE_ASSERT_FUNCTION(replacement) \

-      ReplaceDebugAssertFunction(replacement)

-#else

-  #define REPLACE_ASSERT_FUNCTION(replacement) NULL

-#endif

-

-#ifdef _DEBUG

-  void SendExceptionReport(const TCHAR *log_file,

-                           const TCHAR *filename,

-                           int line,

-                           const TCHAR *type,

-                           uint32 id,

-                           bool offline);

-

-  void SendStackTrace(const TCHAR *filename,

-                      int line,

-                      const TCHAR *type,

-                      bool all_threads,

-                      uint32 id);

-

-  // DEBUG MODE

-

-  extern bool g_LSPMode;

-

-  bool DebugReport(unsigned int id,

-                   ReportType type,

-                   const char *expr,

-                   const TCHAR *message,

-                   const char *filename,

-                   int linenumber,

-                   DebugReportKind debug_report_kind);

-

-  #define VERIFY(expr, msg) ASSERT(expr, msg)  // VERIFY is ASSERT

-

-  #define ASSERT(expr, msg)                                                    \

-      do {                                                                     \

-        ((expr) ? 0 : omaha::DebugReport(0, omaha::R_FATAL, #expr,             \

-          omaha::SPRINTF msg, __FILE__, __LINE__, omaha::DEBUGREPORT_ASSERT)); \

-      } while (0)

-

-  #define REPORT(expr, type, msg, id)                           \

-    ((expr) ? 0 : omaha::DebugReport(id,                        \

-                                     type,                      \

-                                     #expr,                     \

-                                     omaha::SPRINTF msg,        \

-                                     __FILE__,                  \

-                                     __LINE__,                  \

-                                     omaha::DEBUGREPORT_REPORT))

-  void DebugAbort(const TCHAR* msg,

-                  const char* filename,

-                  int32 linenumber,

-                  bool do_abort);

-  #define ABORT(msg)                                            \

-      omaha::DebugAbort(omaha::SPRINTF msg, __FILE__, __LINE__, true)

-

-  void TraceError(DWORD error);

-  inline void TraceLastError() { TraceError(GetLastError()); }

-

-  /**

-  * Iterates through HKEY_CLASSES_ROOT\Interface and calls QI for

-  * all the interfaces there.  Useful for finding out what type of

-  * object you're dealing with :-)

-  */

-  void DumpInterface(IUnknown* unknown);

-

-#else  // #ifdef _DEBUG

-

-  #ifdef ASSERT_IN_RELEASE

-    bool ReleaseAssert(const char *expr,

-                       const TCHAR *msg,

-                       const char *filename,

-                       int32 linenumber);

-    #define ASSERT(expr, msg) \

-        ((expr) ? 0 : ReleaseAssert(#expr, SPRINTF msg, __FILE__, __LINE__))

-  #else

-    #define ASSERT(expr, msg) 0

-  #endif

-

-  // VERIFY executes but does not check expression

-  #define VERIFY(expr, msg) \

-    do {                   \

-      (expr);              \

-    } while (0)

-  #define REPORT(expr, type, msg, id) \

-      ((expr) ? 0 : g_report_ids.ReleaseReport(id))

-  void ReleaseAbort(const TCHAR* msg,

-                    const char* filename,

-                    int32 linenumber,

-                    bool do_abort);

-  #define ABORT(msg) ReleaseAbort(SPRINTF msg, __FILE__, __LINE__, true)

-

-#endif  // #ifdef _DEBUG

-

-#define ASSERT1(expr) ASSERT(expr, (_T("")))

-#define VERIFY1(expr) VERIFY(expr, (_T("")))

-

-#ifdef __cplusplus

-}  // extern "C"{

-#endif

-

-#ifdef _DEBUG

-void ShowAssertDialog(const TCHAR *message, const TCHAR *title);

-

-// used to automatically dump the global summary of reports when the

-// program exits

-class ReportSummaryGenerator {

- public:

-  ReportSummaryGenerator() {}

-  // calls DumpReportSummary()

-  ~ReportSummaryGenerator();

-  // some programs exit without calling destructors, they can use this function

-  // to dump the report summary

-  void DumpReportSummary();

-  // get text summary of reports

-  // caller is responsible for deleting the string returned

-  TCHAR *GetReportSummary();

-  DISALLOW_EVIL_CONSTRUCTORS(ReportSummaryGenerator);

-};

-

-extern ReportSummaryGenerator g_report_summary_generator;

-#endif

-

-// return string from format+arglist; for debugging; not thread-safe

-TCHAR * __cdecl SPRINTF(const TCHAR * format, ...);

-bool DebugError(const char * expr,

-                const TCHAR * message,

-                const char * filename,

-                INT linenumber,

-                BOOL report_only);

-

-// shows an error dialog in DEBUG and when g_release_debug is true

-//

-// example usage:

-//

-//  __try {

-//    do something that sometimes causes a known exception (e.g.,

-//    calling third party code)

-//  } __except(SehNoMinidump(GetExceptionCode(), GetExceptionInformation(),

-//      __FILE__, __LINE__)) {

-//    REPORT(false, R_ERROR, (L"exception doing something"), 103178920);

-//  }

-// show_message - show an error dialog in DEBUG and when g_release_debug is true

-int SehNoMinidump(unsigned int code, struct _EXCEPTION_POINTERS *ep,

-  const char *filename, int32 linenumber, bool show_message);

-

-/**

-* @return Always returns an error value.  If GetLastError is not ERROR_SUCCESS

-*   the function returns an HRESULT value derived from GetLastError()

-*/

-inline HRESULT GetCurError() {

-  return ::GetLastError() == ERROR_SUCCESS ?

-      E_FAIL : HRESULT_FROM_WIN32(::GetLastError());

-}

-

-// Returns the directory where the debugging module stores debug-related files.

-CString GetDebugDirectory();

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_DEBUG_H__

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Debug functions
+
+#ifndef OMAHA_COMMON_DEBUG_H__
+#define OMAHA_COMMON_DEBUG_H__
+
+// To create a release build with asserts turned on, uncomment the
+// following line, and uncomment the linking with atls.lib in api.
+//
+// #define ASSERT_IN_RELEASE
+
+#include "omaha/common/atlassert.h"
+#include "omaha/common/commontypes.h"
+#include "omaha/common/synchronized.h"
+
+namespace omaha {
+
+// hash table for counts of the number of times REPORTs occur
+// template<class K, class V>
+// class HashTable;
+// extern HashTable<uint32, uint16> *g_reports;
+
+#define kMaxUniqueReports (20)
+#define kMaxReportCountString (20)
+
+class ReportIds;
+extern ReportIds g_report_ids;
+extern volatile LONG g_debugassertrecursioncheck;
+extern bool g_always_assert;
+
+const int kMaxStackTraceDialogLen = 512;  // too long and dialog box fails
+
+// TODO(omaha): consider merging this into DebugObserver.
+//
+// For automated testing, we don't (always) want asserts to fire. So
+// we allow the unit test system to handle asserts instead.
+//
+// Give a function matching the prototype to REPLACE_ASSERT_FUNCTION to
+// have your function called instead of the normal assert function.
+typedef int DebugAssertFunctionType(const char *expression,
+  const char *message, const char *file, int line);
+
+enum ReportType;
+enum DebugReportKind;
+class DebugObserver {
+ public:
+  virtual ~DebugObserver() {}
+  virtual int SehSendMinidump(unsigned int code, struct _EXCEPTION_POINTERS *ep,
+                              time64 time_between_minidumps) = 0;
+
+#if defined(_DEBUG) || defined(ASSERT_IN_RELEASE)
+  virtual void OnAssert(const char *expr, const TCHAR *msg,
+                        const char *filename, int32 linenumber) = 0;
+#endif
+
+#if defined(_DEBUG)
+  virtual void SendExceptionReport(const TCHAR *log_file, const TCHAR *filename,
+                                   int line, const TCHAR *type, uint32 id,
+                                   bool offline) = 0;
+  virtual CString OnDebugReport(uint32 id, bool is_report, ReportType type,
+                                const char *expr, const TCHAR *message,
+                                const char *filename, int32 linenumber,
+                                DebugReportKind debug_report_kind) = 0;
+#endif
+};
+
+// replaces the debug observer, returns the previous value.
+DebugObserver* SetDebugObserver(DebugObserver* observer);
+DebugObserver* PeekDebugObserver();
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int SehSendMinidump(unsigned int code,
+                    struct _EXCEPTION_POINTERS *ep,
+                    time64 time_between_minidumps);
+
+#define kMinReportInterval100ns (60 * kSecsTo100ns)
+#define kMinStackReportInterval100ns (60 * kSecsTo100ns)
+#define DEBUG_LOG_SEPARATOR_CHAR "-------------------------------------------\n"
+#define DEBUG_LOG_SEPARATOR     L"-------------------------------------------\n"
+#define kExceptionReportHeaders L"Content-Type: binary"
+
+// TODO(omaha): disable the exception reporting feature to save .data space
+#define kMaxExceptionReportLen 1
+
+#define kMinidumpRequestToSendMessage                               \
+    kAppName L" has encountered a problem.\n***"                    \
+    L"Please hit OK to debug if you have a debugger installed, "    \
+    L"or cancel to continue."                                       \
+
+#define kMinidumpRequestToSendTitle kAppName L" quality assurance"
+
+#undef ASSERT
+#undef VERIFY
+#undef TRACE
+
+// Holds information about REPORTS and their frequency
+struct ReportData {
+  uint32 report_counts_num;
+  uint32 report_ids[kMaxUniqueReports];
+  uint16 report_counts[kMaxUniqueReports];
+};
+
+// Used to hold REPORT IDs and to back them to the registry, where they'll be
+// read and sent in a ping.
+class ReportIds : public GLock {
+ public:
+  ReportIds();
+  ~ReportIds();
+
+  // Call this after a successful ping to clear the report IDs from the registry
+  // and from this component (TRS).
+  void ResetReportsAfterPing();
+
+  // Adds a report ID to our list, if there's enough space.
+  bool ReleaseReport(uint32 id);
+
+  // Creates a string with the report IDs and their frequency.
+  // Caller deletes string.
+  TCHAR *DebugReportString();
+
+ private:
+  ReportData data_;
+
+  // Merges the report data from data2 with data1.
+  void MergeReports(ReportData *data1, const ReportData *data2);
+
+  // We have to use RegKey directly, because we can't depend on the global
+  // Config object during destruction.
+  bool LoadReportData(ReportData **data);
+  void SaveReportData(ReportData *data);
+
+  DISALLOW_EVIL_CONSTRUCTORS(ReportIds);
+};
+
+#if defined(_DEBUG) || defined(ASSERT_IN_RELEASE)
+  // Replaces the debug assert function; returns the old value.
+  DebugAssertFunctionType *ReplaceDebugAssertFunction(DebugAssertFunctionType
+                                                      *replacement);
+  #define REPLACE_ASSERT_FUNCTION(replacement) \
+      ReplaceDebugAssertFunction(replacement)
+#else
+  #define REPLACE_ASSERT_FUNCTION(replacement) NULL
+#endif
+
+#ifdef _DEBUG
+  void SendExceptionReport(const TCHAR *log_file,
+                           const TCHAR *filename,
+                           int line,
+                           const TCHAR *type,
+                           uint32 id,
+                           bool offline);
+
+  void SendStackTrace(const TCHAR *filename,
+                      int line,
+                      const TCHAR *type,
+                      bool all_threads,
+                      uint32 id);
+
+  // DEBUG MODE
+
+  extern bool g_LSPMode;
+
+  bool DebugReport(unsigned int id,
+                   ReportType type,
+                   const char *expr,
+                   const TCHAR *message,
+                   const char *filename,
+                   int linenumber,
+                   DebugReportKind debug_report_kind);
+
+  #define VERIFY(expr, msg) ASSERT(expr, msg)  // VERIFY is ASSERT
+
+  #define ASSERT(expr, msg)                                                    \
+      do {                                                                     \
+        ((expr) ? 0 : omaha::DebugReport(0, omaha::R_FATAL, #expr,             \
+          omaha::SPRINTF msg, __FILE__, __LINE__, omaha::DEBUGREPORT_ASSERT)); \
+      } while (0)
+
+  #define REPORT(expr, type, msg, id)                           \
+    ((expr) ? 0 : omaha::DebugReport(id,                        \
+                                     type,                      \
+                                     #expr,                     \
+                                     omaha::SPRINTF msg,        \
+                                     __FILE__,                  \
+                                     __LINE__,                  \
+                                     omaha::DEBUGREPORT_REPORT))
+  void DebugAbort(const TCHAR* msg,
+                  const char* filename,
+                  int32 linenumber,
+                  bool do_abort);
+  #define ABORT(msg)                                            \
+      omaha::DebugAbort(omaha::SPRINTF msg, __FILE__, __LINE__, true)
+
+  void TraceError(DWORD error);
+  inline void TraceLastError() { TraceError(GetLastError()); }
+
+  /**
+  * Iterates through HKEY_CLASSES_ROOT\Interface and calls QI for
+  * all the interfaces there.  Useful for finding out what type of
+  * object you're dealing with :-)
+  */
+  void DumpInterface(IUnknown* unknown);
+
+#else  // #ifdef _DEBUG
+
+  #ifdef ASSERT_IN_RELEASE
+    bool ReleaseAssert(const char *expr,
+                       const TCHAR *msg,
+                       const char *filename,
+                       int32 linenumber);
+    #define ASSERT(expr, msg) \
+        ((expr) ? 0 : ReleaseAssert(#expr, SPRINTF msg, __FILE__, __LINE__))
+  #else
+    #define ASSERT(expr, msg) 0
+  #endif
+
+  // VERIFY executes but does not check expression
+  #define VERIFY(expr, msg) \
+    do {                   \
+      (expr);              \
+    } while (0)
+  #define REPORT(expr, type, msg, id) \
+      ((expr) ? 0 : g_report_ids.ReleaseReport(id))
+  void ReleaseAbort(const TCHAR* msg,
+                    const char* filename,
+                    int32 linenumber,
+                    bool do_abort);
+  #define ABORT(msg) ReleaseAbort(SPRINTF msg, __FILE__, __LINE__, true)
+
+#endif  // #ifdef _DEBUG
+
+#define ASSERT1(expr) ASSERT(expr, (_T("")))
+#define VERIFY1(expr) VERIFY(expr, (_T("")))
+
+#ifdef __cplusplus
+}  // extern "C"{
+#endif
+
+#ifdef _DEBUG
+void ShowAssertDialog(const TCHAR *message, const TCHAR *title);
+
+// used to automatically dump the global summary of reports when the
+// program exits
+class ReportSummaryGenerator {
+ public:
+  ReportSummaryGenerator() {}
+  // calls DumpReportSummary()
+  ~ReportSummaryGenerator();
+  // some programs exit without calling destructors, they can use this function
+  // to dump the report summary
+  void DumpReportSummary();
+  // get text summary of reports
+  // caller is responsible for deleting the string returned
+  TCHAR *GetReportSummary();
+  DISALLOW_EVIL_CONSTRUCTORS(ReportSummaryGenerator);
+};
+
+extern ReportSummaryGenerator g_report_summary_generator;
+#endif
+
+// return string from format+arglist; for debugging; not thread-safe
+TCHAR * __cdecl SPRINTF(const TCHAR * format, ...);
+bool DebugError(const char * expr,
+                const TCHAR * message,
+                const char * filename,
+                INT linenumber,
+                BOOL report_only);
+
+// shows an error dialog in DEBUG and when g_release_debug is true
+//
+// example usage:
+//
+//  __try {
+//    do something that sometimes causes a known exception (e.g.,
+//    calling third party code)
+//  } __except(SehNoMinidump(GetExceptionCode(), GetExceptionInformation(),
+//      __FILE__, __LINE__)) {
+//    REPORT(false, R_ERROR, (L"exception doing something"), 103178920);
+//  }
+// show_message - show an error dialog in DEBUG and when g_release_debug is true
+int SehNoMinidump(unsigned int code, struct _EXCEPTION_POINTERS *ep,
+  const char *filename, int32 linenumber, bool show_message);
+
+/**
+* @return Always returns an error value.  If GetLastError is not ERROR_SUCCESS
+*   the function returns an HRESULT value derived from GetLastError()
+*/
+inline HRESULT GetCurError() {
+  return ::GetLastError() == ERROR_SUCCESS ?
+      E_FAIL : HRESULT_FROM_WIN32(::GetLastError());
+}
+
+// Returns the directory where the debugging module stores debug-related files.
+CString GetDebugDirectory();
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_DEBUG_H__
+
diff --git a/common/debug_unittest.cc b/common/debug_unittest.cc
index ab33b0e..634a79e 100644
--- a/common/debug_unittest.cc
+++ b/common/debug_unittest.cc
@@ -1,107 +1,107 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Debug unittest

-

-#include <stdexcept>

-

-#include "omaha/common/debug.h"

-#include "omaha/common/test.h"

-#include "omaha/common/time.h"

-

-namespace omaha {

-

-// test what happens when we hit an exception

-int SEHExceptionTest(int level, int reserved) {

-  const uint32 kflags = MB_SETFOREGROUND  |

-                        MB_TOPMOST        |

-                        MB_ICONWARNING    |

-                        MB_OKCANCEL;

-  if (::MessageBox(NULL,

-                   L"do exception?",

-                   L"exception test",

-                   kflags) == IDOK) {

-    int *a1 = static_cast<int *>(1);

-    *a1 = 2;

-

-    // if that does not work try:

-    // simulate a divide by zero

-    int a = 10;

-    int b2 = a;

-    b2 /= 2;

-    b2 -= 5;

-    // int c = a/b2;

-    int c = 0;

-    TCHAR *s = 0;

-    s++;

-    *s = 0;

-

-    RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);

-  }

-

-  return 0;

-}

-

-int SEHCatchExceptionTest(int level, int reserved) {

-  __try {

-    SEHExceptionTest(level, reserved);

-  } __except (SehSendMinidump(GetExceptionCode(),

-                              GetExceptionInformation(),

-                              kMinsTo100ns)) {

-  }

-

-  return 0;

-}

-

-#pragma warning(push)

-#pragma warning(disable:4702)

-// test what happens when we do a C++ exception

-int CppExceptionTest(int level, int reserved) {

-  _TRY_BEGIN

-#if 0

-    _THROW(std::logic_error, "throwing a fake logic_error");

-#else

-//    std::logic_error e("throwing a fake logic_error");

-  //    e._Raise();

-  std::runtime_error(std::string("throwing a fake logic_error"))._Raise();

-#endif

-  _CATCH(std::logic_error e)

-    ASSERT(false, (L"caught exception"));

-  _CATCH_END

-  return 0;

-}

-#pragma warning(pop)

-

-// test what happens when we do a REPORT

-int ReportTest(int level, int reserved) {

-  REPORT(false, R_ERROR, (L"test REPORT"), 592854117);

-  return 0;

-}

-

-// test what happens when we hit an ASSERT

-int AssertTest(int level, int reserved) {

-  ASSERT(false, (L"test ASSERT"));

-  return 0;

-}

-

-// test what happens when we hit an ABORT

-int AbortTest(int level, int reserved) {

-  ABORT((L"test ABORT"));

-  ASSERT(false, (L"returned from ABORT"));

-  return 0;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Debug unittest
+
+#include <stdexcept>
+
+#include "omaha/common/debug.h"
+#include "omaha/common/test.h"
+#include "omaha/common/time.h"
+
+namespace omaha {
+
+// test what happens when we hit an exception
+int SEHExceptionTest(int level, int reserved) {
+  const uint32 kflags = MB_SETFOREGROUND  |
+                        MB_TOPMOST        |
+                        MB_ICONWARNING    |
+                        MB_OKCANCEL;
+  if (::MessageBox(NULL,
+                   L"do exception?",
+                   L"exception test",
+                   kflags) == IDOK) {
+    int *a1 = static_cast<int *>(1);
+    *a1 = 2;
+
+    // if that does not work try:
+    // simulate a divide by zero
+    int a = 10;
+    int b2 = a;
+    b2 /= 2;
+    b2 -= 5;
+    // int c = a/b2;
+    int c = 0;
+    TCHAR *s = 0;
+    s++;
+    *s = 0;
+
+    RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
+  }
+
+  return 0;
+}
+
+int SEHCatchExceptionTest(int level, int reserved) {
+  __try {
+    SEHExceptionTest(level, reserved);
+  } __except (SehSendMinidump(GetExceptionCode(),
+                              GetExceptionInformation(),
+                              kMinsTo100ns)) {
+  }
+
+  return 0;
+}
+
+#pragma warning(push)
+#pragma warning(disable:4702)
+// test what happens when we do a C++ exception
+int CppExceptionTest(int level, int reserved) {
+  _TRY_BEGIN
+#if 0
+    _THROW(std::logic_error, "throwing a fake logic_error");
+#else
+//    std::logic_error e("throwing a fake logic_error");
+  //    e._Raise();
+  std::runtime_error(std::string("throwing a fake logic_error"))._Raise();
+#endif
+  _CATCH(std::logic_error e)
+    ASSERT(false, (L"caught exception"));
+  _CATCH_END
+  return 0;
+}
+#pragma warning(pop)
+
+// test what happens when we do a REPORT
+int ReportTest(int level, int reserved) {
+  REPORT(false, R_ERROR, (L"test REPORT"), 592854117);
+  return 0;
+}
+
+// test what happens when we hit an ASSERT
+int AssertTest(int level, int reserved) {
+  ASSERT(false, (L"test ASSERT"));
+  return 0;
+}
+
+// test what happens when we hit an ABORT
+int AbortTest(int level, int reserved) {
+  ABORT((L"test ABORT"));
+  ASSERT(false, (L"returned from ABORT"));
+  return 0;
+}
+
+}  // namespace omaha
+
diff --git a/common/disk.cc b/common/disk.cc
index c591e24..36123de 100644
--- a/common/disk.cc
+++ b/common/disk.cc
@@ -1,396 +1,396 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Disk functions

-

-#include "omaha/common/disk.h"

-

-#include <winioctl.h>

-#include "omaha/common/const_config.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/localization.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/shell.h"

-#include "omaha/common/string.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/system.h"

-#include "omaha/common/timer.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-#define kNetdiskVendorId "netdisk"

-

-// see also: http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q264203

-

-#if _MSC_VER < 1400

-// Not defined in the headers we have; from MSDN:

-#define IOCTL_STORAGE_QUERY_PROPERTY \

-          CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)

-

-typedef struct _STORAGE_DEVICE_DESCRIPTOR {

-  ULONG  Version;

-  ULONG  Size;

-  UCHAR  DeviceType;

-  UCHAR  DeviceTypeModifier;

-  BOOLEAN  RemovableMedia;

-  BOOLEAN  CommandQueueing;

-  ULONG  VendorIdOffset;

-  ULONG  ProductIdOffset;

-  ULONG  ProductRevisionOffset;

-  ULONG  SerialNumberOffset;

-  STORAGE_BUS_TYPE  BusType;

-  ULONG  RawPropertiesLength;

-  UCHAR  RawDeviceProperties[1];

-} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;

-

-typedef enum _STORAGE_QUERY_TYPE {

-  PropertyStandardQuery = 0,

-  PropertyExistsQuery,

-  PropertyMaskQuery,

-  PropertyQueryMaxDefined

-} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;

-

-typedef enum _STORAGE_PROPERTY_ID {

-  StorageDeviceProperty = 0,

-  StorageAdapterProperty,

-  StorageDeviceIdProperty

-} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;

-

-typedef struct _STORAGE_PROPERTY_QUERY {

-  STORAGE_PROPERTY_ID  PropertyId;

-  STORAGE_QUERY_TYPE  QueryType;

-  UCHAR  AdditionalParameters[1];

-} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;

-

-// -------

-#endif

-

-#define kIoctlBufferSize 1024

-

-#define kMaxDrivesCached 3

-#define kMaxDriveLen 20

-static TCHAR g_cache_drive[kMaxDrivesCached][kMaxDriveLen+1];

-static bool g_cache_external[kMaxDrivesCached];

-static int g_cache_pos;

-static LLock g_cache_lock;

-

-bool IsDiskExternal(const TCHAR *drive) {

-  ASSERT(drive, (L""));

-  ASSERT(lstrlen(drive) < kMaxDriveLen, (L""));

-

-  DisableThreadErrorUI disable_error_dialog_box;

-

-  {

-    __mutexScope(g_cache_lock);

-    for (int i = 0; i < kMaxDrivesCached; i++)

-      if (!lstrcmp(drive, g_cache_drive[i])) {

-        UTIL_LOG(L1, (L"cached disk ext %s %d", drive, g_cache_external[i]));

-        return g_cache_external[i];

-      }

-  }

-

-#ifdef _DEBUG

-  Timer timer(true);

-#endif

-

-  byte buffer[kIoctlBufferSize+1];

-

-  bool external = false;

-  HANDLE device = CreateFile(drive,

-                             GENERIC_READ,

-                             FILE_SHARE_READ | FILE_SHARE_WRITE,

-                             NULL,

-                             OPEN_EXISTING,

-                             NULL,

-                             NULL);

-  if (device == INVALID_HANDLE_VALUE) {

-      UTIL_LOG(L1, (L"disk external could not open drive %s", drive));

-      goto done;

-  }

-  STORAGE_DEVICE_DESCRIPTOR *device_desc;

-  STORAGE_PROPERTY_QUERY query;

-  DWORD out_bytes;

-  query.PropertyId = StorageDeviceProperty;

-  query.QueryType = PropertyStandardQuery;

-  *(query.AdditionalParameters) = 0;

-

-  device_desc = reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(buffer);

-  // should not be needed, but just to be safer

-  ZeroMemory(buffer, kIoctlBufferSize);

-

-  BOOL ok = ::DeviceIoControl(device,

-                              IOCTL_STORAGE_QUERY_PROPERTY,

-                              &query,

-                              sizeof(STORAGE_PROPERTY_QUERY),

-                              buffer,

-                              kIoctlBufferSize,

-                              &out_bytes,

-                              (LPOVERLAPPED)NULL);

-

-  if (ok &&

-      device_desc->VendorIdOffset &&

-      stristr(reinterpret_cast<char*>(buffer + device_desc->VendorIdOffset),

-              kNetdiskVendorId)) {

-    external = true;

-    UTIL_LOG(L1, (L"ximeta netdisk %s", drive));

-  }

-

-  if (ok &&

-      (device_desc->BusType == BusTypeUsb ||

-       device_desc->BusType == BusType1394)) {

-    external = true;

-  }

-  if (!ok) {

-    UTIL_LOG(L1, (L"disk external ioctl failed %s", drive));

-  }

-  CloseHandle(device);

-  done:

-  UTIL_LOG(L1, (L"disk external %s %d time %s",

-      drive, external, String_DoubleToString(timer.GetMilliseconds(), 3)));

-

-  {

-    __mutexScope(g_cache_lock);

-    lstrcpyn(g_cache_drive[g_cache_pos], drive, kMaxDriveLen+1);

-    g_cache_external[g_cache_pos] = external;

-    if (++g_cache_pos >= kMaxDrivesCached) g_cache_pos = 0;

-  }

-

-  return external;

-}

-

-// find the first fixed local disk with at least the space requested

-// confirms that we can create a directory on the drive

-// returns the drive in the drive parameter

-// returns E_FAIL if no drive with enough space could be found

-HRESULT FindFirstLocalDriveWithEnoughSpace(const uint64 space_required,

-                                           CString *drive) {

-  ASSERT1(drive);

-

-  DisableThreadErrorUI disable_error_dialog_box;

-

-  const int kMaxNumDrives = 26;

-  static const size_t kBufLen = (STR_SIZE("c:\\\0") * kMaxNumDrives) + 1;

-

-  // obtain the fixed system drives

-  TCHAR buf[kBufLen];

-  DWORD str_len = ::GetLogicalDriveStrings(kBufLen, buf);

-  if (str_len > 0 && str_len < kBufLen) {

-    for (TCHAR* ptr = buf; *ptr != L'\0'; ptr += (lstrlen(ptr) + 1)) {

-      UINT drive_type = GetDriveType(ptr);

-      if (drive_type == DRIVE_FIXED) {

-        CString test_drive(ptr);

-        if (!IsDiskExternal(CString(L"\\\\?\\") + test_drive.Left(2))) {

-          uint64 free_disk_space = 0;

-          HRESULT hr = GetFreeDiskSpace(test_drive, &free_disk_space);

-

-          if (SUCCEEDED(hr) && space_required <= free_disk_space) {

-            CString temp_dir;

-            // confirm that we can create a directory on this drive

-            bool found = false;

-            while (!found) {

-              temp_dir = test_drive +

-                         NOTRANSL(L"test") +

-                         itostr(static_cast<uint32>(::GetTickCount()));

-              if (!File::Exists (temp_dir)) found = true;

-            }

-

-            if (SUCCEEDED(CreateDir(temp_dir, NULL))) {

-              VERIFY1(SUCCEEDED(DeleteDirectory(temp_dir)));

-              *drive = test_drive;

-              UTIL_LOG(L1, (L"drive %s enough space %d", test_drive.GetString(),

-                            free_disk_space));

-              return S_OK;

-            }

-          }

-        }

-      }

-    }

-  }

-

-  return E_FAIL;

-}

-

-// Get free disk space of a drive containing the specified folder

-HRESULT GetFreeDiskSpace(uint32 csidl, uint64* free_disk_space) {

-  ASSERT1(free_disk_space);

-

-  CString path;

-  RET_IF_FAILED(Shell::GetSpecialFolder(csidl, false, &path));

-

-  return GetFreeDiskSpace(path, free_disk_space);

-}

-

-// Get free disk space of a drive containing the specified folder

-HRESULT GetFreeDiskSpace(const TCHAR* folder, uint64* free_disk_space) {

-  ASSERT1(folder && *folder);

-  ASSERT1(free_disk_space);

-

-  DisableThreadErrorUI disable_error_dialog_box;

-

-  CString drive(folder);

-

-  // (Stupid API used by System::GetDiskStatistics will work with any folder -

-  // as long as it EXISTS.  Since the data storage folder might not exist yet

-  // (e.g., on a clean install) we'll just truncate it down to a drive letter.)

-  drive = drive.Left(3);  // "X:\"

-  ASSERT1(String_EndsWith(drive, _T(":\\"), false));

-

-  // Get the free disk space available to this user on this drive

-  uint64 free_bytes_current_user = 0LL;

-  uint64 total_bytes_current_user = 0LL;

-  uint64 free_bytes_all_users = 0LL;

-  RET_IF_FAILED(System::GetDiskStatistics(drive,

-                                          &free_bytes_current_user,

-                                          &total_bytes_current_user,

-                                          &free_bytes_all_users));

-

-  *free_disk_space = std::min(free_bytes_current_user, free_bytes_all_users);

-

-  return S_OK;

-}

-

-// Has enough free disk space on a drive containing the specified folder

-HRESULT HasEnoughFreeDiskSpace(uint32 csidl, uint64 disk_space_needed) {

-  uint64 free_disk_space = 0;

-  if (SUCCEEDED(GetFreeDiskSpace(csidl, &free_disk_space))) {

-    return (disk_space_needed <= free_disk_space) ?

-           S_OK : CI_E_NOT_ENOUGH_DISK_SPACE;

-  }

-  return S_OK;

-}

-

-// Has enough free disk space on a drive containing the specified folder

-HRESULT HasEnoughFreeDiskSpace(const TCHAR* folder, uint64 disk_space_needed) {

-  uint64 free_disk_space = 0;

-  if (SUCCEEDED(GetFreeDiskSpace(folder, &free_disk_space))) {

-    return (disk_space_needed <= free_disk_space) ?

-           S_OK : CI_E_NOT_ENOUGH_DISK_SPACE;

-  }

-  return S_OK;

-}

-

-bool IsHotPluggable(const TCHAR* drive) {

-  ASSERT(drive, (L""));

-

-  // Disable potential error dialogs during this check

-  DisableThreadErrorUI disable_error_dialog_box;

-

-  //

-  // We set the default return value to true so that

-  // we treat the disk as hot-pluggable in case we

-  // don't know.

-  //

-  bool ret = true;

-

-  if (drive && lstrlen(drive) >= 2) {

-    CString volume_path(_T("\\\\.\\"));

-    // We don't want the trailing backslash.

-    volume_path.Append(drive, 2);

-

-    CHandle volume(CreateFile(volume_path, GENERIC_READ,

-                              FILE_SHARE_READ | FILE_SHARE_WRITE,

-                              NULL, OPEN_EXISTING, 0, NULL));

-

-    if (volume != INVALID_HANDLE_VALUE) {

-      STORAGE_HOTPLUG_INFO shi = {0};

-      shi.Size = sizeof(shi);

-      DWORD bytes_returned = 0;

-      if (::DeviceIoControl(volume, IOCTL_STORAGE_GET_HOTPLUG_INFO,  NULL, 0,

-                            &shi, sizeof(STORAGE_HOTPLUG_INFO), &bytes_returned,

-                            NULL)) {

-          ret = (shi.DeviceHotplug != false);

-        }

-    }

-  } else {

-    ASSERT(false, (L"Invalid path"));

-  }

-

-  return ret;

-}

-

-bool IsLargeDrive(const TCHAR* drive) {

-  ASSERT1(drive && *drive);

-

-  DisableThreadErrorUI disable_error_dialog_box;

-

-  ULARGE_INTEGER caller_free_bytes = {0};

-  ULARGE_INTEGER total_bytes = {0};

-  ULARGE_INTEGER total_free_bytes = {0};

-

-  if (!::GetDiskFreeSpaceEx(drive,

-                            &caller_free_bytes,

-                            &total_bytes,

-                            &total_free_bytes)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[IsLargeDrive - failed to GetDiskFreeSpaceEx][0x%x]"), hr));

-    return false;

-  }

-

-  return (total_bytes.QuadPart > kLargeDriveSize);

-}

-

-HRESULT DevicePathToDosPath(const TCHAR* device_path, CString* dos_path) {

-  ASSERT1(device_path);

-  ASSERT1(dos_path);

-  UTIL_LOG(L4, (_T("[DevicePathToDosPath][device_path=%s]"), device_path));

-

-  dos_path->Empty();

-

-  TCHAR drive_strings[MAX_PATH] = _T("");

-  if (!::GetLogicalDriveStrings(arraysize(drive_strings), drive_strings)) {

-    UTIL_LOG(L4, (_T("[DevicePathToDosPath-GetLogicalDriveStrings fail][0x%x]"),

-                  HRESULTFromLastError()));

-    return HRESULTFromLastError();

-  }

-

-  // Drive strings are stored as a set of null terminated strings, with an

-  // extra null after the last string. Each drive string is of the form "C:\".

-  // We convert it to the form "C:", which is the format expected by

-  // ::QueryDosDevice().

-  TCHAR drive_colon[3] = _T(" :");

-  for (const TCHAR* next_drive_letter = drive_strings;

-       *next_drive_letter;

-       next_drive_letter += _tcslen(next_drive_letter) + 1) {

-    // Dos device of the form "C:".

-    *drive_colon = *next_drive_letter;

-    TCHAR device_name[MAX_PATH] = _T("");

-    if (!::QueryDosDevice(drive_colon, device_name, arraysize(device_name))) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[QueryDosDevice failed][0x%x]"),

-                             HRESULTFromLastError()));

-      continue;

-    }

-

-    UTIL_LOG(L4, (_T("[DevicePathToDosPath found drive]")

-                  _T("[logical drive %s][device name %s]"),

-                  drive_colon, device_name));

-

-    size_t name_length = _tcslen(device_name);

-    if (_tcsnicmp(device_path, device_name, name_length) == 0) {

-      // Construct DOS path.

-      dos_path->Format(_T("%s%s"), drive_colon, device_path + name_length);

-      UTIL_LOG(L4, (_T("[DevicePathToDosPath][dos_path=%s]"), *dos_path));

-      return S_OK;

-    }

-  }

-

-  return HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE);

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Disk functions
+
+#include "omaha/common/disk.h"
+
+#include <winioctl.h>
+#include "omaha/common/const_config.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/localization.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/shell.h"
+#include "omaha/common/string.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/system.h"
+#include "omaha/common/timer.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+#define kNetdiskVendorId "netdisk"
+
+// see also: http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q264203
+
+#if _MSC_VER < 1400
+// Not defined in the headers we have; from MSDN:
+#define IOCTL_STORAGE_QUERY_PROPERTY \
+          CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+typedef struct _STORAGE_DEVICE_DESCRIPTOR {
+  ULONG  Version;
+  ULONG  Size;
+  UCHAR  DeviceType;
+  UCHAR  DeviceTypeModifier;
+  BOOLEAN  RemovableMedia;
+  BOOLEAN  CommandQueueing;
+  ULONG  VendorIdOffset;
+  ULONG  ProductIdOffset;
+  ULONG  ProductRevisionOffset;
+  ULONG  SerialNumberOffset;
+  STORAGE_BUS_TYPE  BusType;
+  ULONG  RawPropertiesLength;
+  UCHAR  RawDeviceProperties[1];
+} STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR;
+
+typedef enum _STORAGE_QUERY_TYPE {
+  PropertyStandardQuery = 0,
+  PropertyExistsQuery,
+  PropertyMaskQuery,
+  PropertyQueryMaxDefined
+} STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE;
+
+typedef enum _STORAGE_PROPERTY_ID {
+  StorageDeviceProperty = 0,
+  StorageAdapterProperty,
+  StorageDeviceIdProperty
+} STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID;
+
+typedef struct _STORAGE_PROPERTY_QUERY {
+  STORAGE_PROPERTY_ID  PropertyId;
+  STORAGE_QUERY_TYPE  QueryType;
+  UCHAR  AdditionalParameters[1];
+} STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY;
+
+// -------
+#endif
+
+#define kIoctlBufferSize 1024
+
+#define kMaxDrivesCached 3
+#define kMaxDriveLen 20
+static TCHAR g_cache_drive[kMaxDrivesCached][kMaxDriveLen+1];
+static bool g_cache_external[kMaxDrivesCached];
+static int g_cache_pos;
+static LLock g_cache_lock;
+
+bool IsDiskExternal(const TCHAR *drive) {
+  ASSERT(drive, (L""));
+  ASSERT(lstrlen(drive) < kMaxDriveLen, (L""));
+
+  DisableThreadErrorUI disable_error_dialog_box;
+
+  {
+    __mutexScope(g_cache_lock);
+    for (int i = 0; i < kMaxDrivesCached; i++)
+      if (!lstrcmp(drive, g_cache_drive[i])) {
+        UTIL_LOG(L1, (L"cached disk ext %s %d", drive, g_cache_external[i]));
+        return g_cache_external[i];
+      }
+  }
+
+#ifdef _DEBUG
+  Timer timer(true);
+#endif
+
+  byte buffer[kIoctlBufferSize+1];
+
+  bool external = false;
+  HANDLE device = CreateFile(drive,
+                             GENERIC_READ,
+                             FILE_SHARE_READ | FILE_SHARE_WRITE,
+                             NULL,
+                             OPEN_EXISTING,
+                             NULL,
+                             NULL);
+  if (device == INVALID_HANDLE_VALUE) {
+      UTIL_LOG(L1, (L"disk external could not open drive %s", drive));
+      goto done;
+  }
+  STORAGE_DEVICE_DESCRIPTOR *device_desc;
+  STORAGE_PROPERTY_QUERY query;
+  DWORD out_bytes;
+  query.PropertyId = StorageDeviceProperty;
+  query.QueryType = PropertyStandardQuery;
+  *(query.AdditionalParameters) = 0;
+
+  device_desc = reinterpret_cast<STORAGE_DEVICE_DESCRIPTOR*>(buffer);
+  // should not be needed, but just to be safer
+  ZeroMemory(buffer, kIoctlBufferSize);
+
+  BOOL ok = ::DeviceIoControl(device,
+                              IOCTL_STORAGE_QUERY_PROPERTY,
+                              &query,
+                              sizeof(STORAGE_PROPERTY_QUERY),
+                              buffer,
+                              kIoctlBufferSize,
+                              &out_bytes,
+                              (LPOVERLAPPED)NULL);
+
+  if (ok &&
+      device_desc->VendorIdOffset &&
+      stristr(reinterpret_cast<char*>(buffer + device_desc->VendorIdOffset),
+              kNetdiskVendorId)) {
+    external = true;
+    UTIL_LOG(L1, (L"ximeta netdisk %s", drive));
+  }
+
+  if (ok &&
+      (device_desc->BusType == BusTypeUsb ||
+       device_desc->BusType == BusType1394)) {
+    external = true;
+  }
+  if (!ok) {
+    UTIL_LOG(L1, (L"disk external ioctl failed %s", drive));
+  }
+  CloseHandle(device);
+  done:
+  UTIL_LOG(L1, (L"disk external %s %d time %s",
+      drive, external, String_DoubleToString(timer.GetMilliseconds(), 3)));
+
+  {
+    __mutexScope(g_cache_lock);
+    lstrcpyn(g_cache_drive[g_cache_pos], drive, kMaxDriveLen+1);
+    g_cache_external[g_cache_pos] = external;
+    if (++g_cache_pos >= kMaxDrivesCached) g_cache_pos = 0;
+  }
+
+  return external;
+}
+
+// find the first fixed local disk with at least the space requested
+// confirms that we can create a directory on the drive
+// returns the drive in the drive parameter
+// returns E_FAIL if no drive with enough space could be found
+HRESULT FindFirstLocalDriveWithEnoughSpace(const uint64 space_required,
+                                           CString *drive) {
+  ASSERT1(drive);
+
+  DisableThreadErrorUI disable_error_dialog_box;
+
+  const int kMaxNumDrives = 26;
+  static const size_t kBufLen = (STR_SIZE("c:\\\0") * kMaxNumDrives) + 1;
+
+  // obtain the fixed system drives
+  TCHAR buf[kBufLen];
+  DWORD str_len = ::GetLogicalDriveStrings(kBufLen, buf);
+  if (str_len > 0 && str_len < kBufLen) {
+    for (TCHAR* ptr = buf; *ptr != L'\0'; ptr += (lstrlen(ptr) + 1)) {
+      UINT drive_type = GetDriveType(ptr);
+      if (drive_type == DRIVE_FIXED) {
+        CString test_drive(ptr);
+        if (!IsDiskExternal(CString(L"\\\\?\\") + test_drive.Left(2))) {
+          uint64 free_disk_space = 0;
+          HRESULT hr = GetFreeDiskSpace(test_drive, &free_disk_space);
+
+          if (SUCCEEDED(hr) && space_required <= free_disk_space) {
+            CString temp_dir;
+            // confirm that we can create a directory on this drive
+            bool found = false;
+            while (!found) {
+              temp_dir = test_drive +
+                         NOTRANSL(L"test") +
+                         itostr(static_cast<uint32>(::GetTickCount()));
+              if (!File::Exists (temp_dir)) found = true;
+            }
+
+            if (SUCCEEDED(CreateDir(temp_dir, NULL))) {
+              VERIFY1(SUCCEEDED(DeleteDirectory(temp_dir)));
+              *drive = test_drive;
+              UTIL_LOG(L1, (L"drive %s enough space %d", test_drive.GetString(),
+                            free_disk_space));
+              return S_OK;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return E_FAIL;
+}
+
+// Get free disk space of a drive containing the specified folder
+HRESULT GetFreeDiskSpace(uint32 csidl, uint64* free_disk_space) {
+  ASSERT1(free_disk_space);
+
+  CString path;
+  RET_IF_FAILED(Shell::GetSpecialFolder(csidl, false, &path));
+
+  return GetFreeDiskSpace(path, free_disk_space);
+}
+
+// Get free disk space of a drive containing the specified folder
+HRESULT GetFreeDiskSpace(const TCHAR* folder, uint64* free_disk_space) {
+  ASSERT1(folder && *folder);
+  ASSERT1(free_disk_space);
+
+  DisableThreadErrorUI disable_error_dialog_box;
+
+  CString drive(folder);
+
+  // (Stupid API used by System::GetDiskStatistics will work with any folder -
+  // as long as it EXISTS.  Since the data storage folder might not exist yet
+  // (e.g., on a clean install) we'll just truncate it down to a drive letter.)
+  drive = drive.Left(3);  // "X:\"
+  ASSERT1(String_EndsWith(drive, _T(":\\"), false));
+
+  // Get the free disk space available to this user on this drive
+  uint64 free_bytes_current_user = 0LL;
+  uint64 total_bytes_current_user = 0LL;
+  uint64 free_bytes_all_users = 0LL;
+  RET_IF_FAILED(System::GetDiskStatistics(drive,
+                                          &free_bytes_current_user,
+                                          &total_bytes_current_user,
+                                          &free_bytes_all_users));
+
+  *free_disk_space = std::min(free_bytes_current_user, free_bytes_all_users);
+
+  return S_OK;
+}
+
+// Has enough free disk space on a drive containing the specified folder
+HRESULT HasEnoughFreeDiskSpace(uint32 csidl, uint64 disk_space_needed) {
+  uint64 free_disk_space = 0;
+  if (SUCCEEDED(GetFreeDiskSpace(csidl, &free_disk_space))) {
+    return (disk_space_needed <= free_disk_space) ?
+           S_OK : CI_E_NOT_ENOUGH_DISK_SPACE;
+  }
+  return S_OK;
+}
+
+// Has enough free disk space on a drive containing the specified folder
+HRESULT HasEnoughFreeDiskSpace(const TCHAR* folder, uint64 disk_space_needed) {
+  uint64 free_disk_space = 0;
+  if (SUCCEEDED(GetFreeDiskSpace(folder, &free_disk_space))) {
+    return (disk_space_needed <= free_disk_space) ?
+           S_OK : CI_E_NOT_ENOUGH_DISK_SPACE;
+  }
+  return S_OK;
+}
+
+bool IsHotPluggable(const TCHAR* drive) {
+  ASSERT(drive, (L""));
+
+  // Disable potential error dialogs during this check
+  DisableThreadErrorUI disable_error_dialog_box;
+
+  //
+  // We set the default return value to true so that
+  // we treat the disk as hot-pluggable in case we
+  // don't know.
+  //
+  bool ret = true;
+
+  if (drive && lstrlen(drive) >= 2) {
+    CString volume_path(_T("\\\\.\\"));
+    // We don't want the trailing backslash.
+    volume_path.Append(drive, 2);
+
+    CHandle volume(CreateFile(volume_path, GENERIC_READ,
+                              FILE_SHARE_READ | FILE_SHARE_WRITE,
+                              NULL, OPEN_EXISTING, 0, NULL));
+
+    if (volume != INVALID_HANDLE_VALUE) {
+      STORAGE_HOTPLUG_INFO shi = {0};
+      shi.Size = sizeof(shi);
+      DWORD bytes_returned = 0;
+      if (::DeviceIoControl(volume, IOCTL_STORAGE_GET_HOTPLUG_INFO,  NULL, 0,
+                            &shi, sizeof(STORAGE_HOTPLUG_INFO), &bytes_returned,
+                            NULL)) {
+          ret = (shi.DeviceHotplug != false);
+        }
+    }
+  } else {
+    ASSERT(false, (L"Invalid path"));
+  }
+
+  return ret;
+}
+
+bool IsLargeDrive(const TCHAR* drive) {
+  ASSERT1(drive && *drive);
+
+  DisableThreadErrorUI disable_error_dialog_box;
+
+  ULARGE_INTEGER caller_free_bytes = {0};
+  ULARGE_INTEGER total_bytes = {0};
+  ULARGE_INTEGER total_free_bytes = {0};
+
+  if (!::GetDiskFreeSpaceEx(drive,
+                            &caller_free_bytes,
+                            &total_bytes,
+                            &total_free_bytes)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[IsLargeDrive - failed to GetDiskFreeSpaceEx][0x%x]"), hr));
+    return false;
+  }
+
+  return (total_bytes.QuadPart > kLargeDriveSize);
+}
+
+HRESULT DevicePathToDosPath(const TCHAR* device_path, CString* dos_path) {
+  ASSERT1(device_path);
+  ASSERT1(dos_path);
+  UTIL_LOG(L4, (_T("[DevicePathToDosPath][device_path=%s]"), device_path));
+
+  dos_path->Empty();
+
+  TCHAR drive_strings[MAX_PATH] = _T("");
+  if (!::GetLogicalDriveStrings(arraysize(drive_strings), drive_strings)) {
+    UTIL_LOG(L4, (_T("[DevicePathToDosPath-GetLogicalDriveStrings fail][0x%x]"),
+                  HRESULTFromLastError()));
+    return HRESULTFromLastError();
+  }
+
+  // Drive strings are stored as a set of null terminated strings, with an
+  // extra null after the last string. Each drive string is of the form "C:\".
+  // We convert it to the form "C:", which is the format expected by
+  // ::QueryDosDevice().
+  TCHAR drive_colon[3] = _T(" :");
+  for (const TCHAR* next_drive_letter = drive_strings;
+       *next_drive_letter;
+       next_drive_letter += _tcslen(next_drive_letter) + 1) {
+    // Dos device of the form "C:".
+    *drive_colon = *next_drive_letter;
+    TCHAR device_name[MAX_PATH] = _T("");
+    if (!::QueryDosDevice(drive_colon, device_name, arraysize(device_name))) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[QueryDosDevice failed][0x%x]"),
+                             HRESULTFromLastError()));
+      continue;
+    }
+
+    UTIL_LOG(L4, (_T("[DevicePathToDosPath found drive]")
+                  _T("[logical drive %s][device name %s]"),
+                  drive_colon, device_name));
+
+    size_t name_length = _tcslen(device_name);
+    if (_tcsnicmp(device_path, device_name, name_length) == 0) {
+      // Construct DOS path.
+      dos_path->Format(_T("%s%s"), drive_colon, device_path + name_length);
+      UTIL_LOG(L4, (_T("[DevicePathToDosPath][dos_path=%s]"), *dos_path));
+      return S_OK;
+    }
+  }
+
+  return HRESULT_FROM_WIN32(ERROR_INVALID_DRIVE);
+}
+
+}  // namespace omaha
+
diff --git a/common/disk.h b/common/disk.h
index a5f249e..dd59006 100644
--- a/common/disk.h
+++ b/common/disk.h
@@ -1,109 +1,109 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Disk functions

-

-#ifndef OMAHA_COMMON_DISK_H__

-#define OMAHA_COMMON_DISK_H__

-

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// A constant we use to determine a large drive.

-// Although today this isn't really really large,

-// it is enough to distinguish small, removable

-// drives that are not continually connected to

-// a computer, from the drives that are.

-// In addition to using this constant, we

-// also check if the drive is hot-pluggable.

-const uint64 kLargeDriveSize = 0x00000000ffffffff;

-

-// returns true if the device is an external disk

-// drive typically is something like: \\?\C:

-bool IsDiskExternal(const TCHAR *drive);

-

-//

-// Determines if a drive can be unplugged without manually disabling

-// the drive first.  By default, USB drives are initialized with

-// "surprise removal" enabled, which means they are hot-pluggable.

-//

-// @param drive  The root of the drive, as returned from GetLogicalDriveStrings

-//               e.g. "E:\\".

-//

-// @returns true if the drive is optimized for quick/surprise removal.

-//   If the function returns false, then caching (lazy write) is enabled for

-//   the drive, otherwise it is not.

-//   If an error occurs during this call, the return value will be 'true' since

-//   we always want to treat a drive as hot-pluggable if we're not sure.

-//

-bool IsHotPluggable(const TCHAR* drive);

-

-//

-// @returns true if the specified drive is larger than kLargeDriveSize.

-//

-// @param drive  The root of the drive, as returned from GetLogicalDriveStrings

-//               e.g. "E:\\".

-//

-bool IsLargeDrive(const TCHAR* drive);

-

-// find the first fixed local disk with at least the space requested

-// returns the drive in the drive parameter

-// returns E_FAIL if no drive with enough space could be found

-HRESULT FindFirstLocalDriveWithEnoughSpace(const uint64 space_required,

-                                           CString *drive);

-

-// Get free disk space of a drive containing the specified folder

-HRESULT GetFreeDiskSpace(uint32 csidl, uint64* free_disk_space);

-

-// Get free disk space of a drive containing the specified folder

-HRESULT GetFreeDiskSpace(const TCHAR* folder, uint64* free_disk_space);

-

-// Has enough free disk space on a drive containing the specified folder

-HRESULT HasEnoughFreeDiskSpace(uint32 csidl, uint64 disk_space_needed);

-

-// Has enough free disk space on a drive containing the specified folder

-HRESULT HasEnoughFreeDiskSpace(const TCHAR* folder, uint64 disk_space_needed);

-

-// Convert from "\Device\Harddisk0\Partition1\WINNT\System32\ntdll.dll" to

-// "C:\WINNT\System32\ntdll.dll"

-HRESULT DevicePathToDosPath(const TCHAR* device_path, CString* dos_path);

-

-//

-// Disables critical error dialogs on the current thread.

-// The system does not display the critical-error-handler message box.

-// Instead, the system returns the error to the calling process.

-//

-class DisableThreadErrorUI {

- public:

-  DisableThreadErrorUI() {

-    // Set the error mode

-    prev_mode_ = SetErrorMode(SEM_FAILCRITICALERRORS);

-  }

-

-  ~DisableThreadErrorUI() {

-    // Restore the error mode

-    SetErrorMode(prev_mode_);

-  }

-

- protected:

-  UINT prev_mode_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_DISK_H__

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Disk functions
+
+#ifndef OMAHA_COMMON_DISK_H__
+#define OMAHA_COMMON_DISK_H__
+
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// A constant we use to determine a large drive.
+// Although today this isn't really really large,
+// it is enough to distinguish small, removable
+// drives that are not continually connected to
+// a computer, from the drives that are.
+// In addition to using this constant, we
+// also check if the drive is hot-pluggable.
+const uint64 kLargeDriveSize = 0x00000000ffffffff;
+
+// returns true if the device is an external disk
+// drive typically is something like: \\?\C:
+bool IsDiskExternal(const TCHAR *drive);
+
+//
+// Determines if a drive can be unplugged without manually disabling
+// the drive first.  By default, USB drives are initialized with
+// "surprise removal" enabled, which means they are hot-pluggable.
+//
+// @param drive  The root of the drive, as returned from GetLogicalDriveStrings
+//               e.g. "E:\\".
+//
+// @returns true if the drive is optimized for quick/surprise removal.
+//   If the function returns false, then caching (lazy write) is enabled for
+//   the drive, otherwise it is not.
+//   If an error occurs during this call, the return value will be 'true' since
+//   we always want to treat a drive as hot-pluggable if we're not sure.
+//
+bool IsHotPluggable(const TCHAR* drive);
+
+//
+// @returns true if the specified drive is larger than kLargeDriveSize.
+//
+// @param drive  The root of the drive, as returned from GetLogicalDriveStrings
+//               e.g. "E:\\".
+//
+bool IsLargeDrive(const TCHAR* drive);
+
+// find the first fixed local disk with at least the space requested
+// returns the drive in the drive parameter
+// returns E_FAIL if no drive with enough space could be found
+HRESULT FindFirstLocalDriveWithEnoughSpace(const uint64 space_required,
+                                           CString *drive);
+
+// Get free disk space of a drive containing the specified folder
+HRESULT GetFreeDiskSpace(uint32 csidl, uint64* free_disk_space);
+
+// Get free disk space of a drive containing the specified folder
+HRESULT GetFreeDiskSpace(const TCHAR* folder, uint64* free_disk_space);
+
+// Has enough free disk space on a drive containing the specified folder
+HRESULT HasEnoughFreeDiskSpace(uint32 csidl, uint64 disk_space_needed);
+
+// Has enough free disk space on a drive containing the specified folder
+HRESULT HasEnoughFreeDiskSpace(const TCHAR* folder, uint64 disk_space_needed);
+
+// Convert from "\Device\Harddisk0\Partition1\WINNT\System32\ntdll.dll" to
+// "C:\WINNT\System32\ntdll.dll"
+HRESULT DevicePathToDosPath(const TCHAR* device_path, CString* dos_path);
+
+//
+// Disables critical error dialogs on the current thread.
+// The system does not display the critical-error-handler message box.
+// Instead, the system returns the error to the calling process.
+//
+class DisableThreadErrorUI {
+ public:
+  DisableThreadErrorUI() {
+    // Set the error mode
+    prev_mode_ = SetErrorMode(SEM_FAILCRITICALERRORS);
+  }
+
+  ~DisableThreadErrorUI() {
+    // Restore the error mode
+    SetErrorMode(prev_mode_);
+  }
+
+ protected:
+  UINT prev_mode_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_DISK_H__
+
diff --git a/common/disk_unittest.cc b/common/disk_unittest.cc
index 9d28993..d44fb6e 100644
--- a/common/disk_unittest.cc
+++ b/common/disk_unittest.cc
@@ -1,73 +1,73 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <shlobj.h>

-#include <psapi.h>

-

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_utils.h"

-#include "omaha/common/disk.h"

-#include "omaha/common/file.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(DiskTest, Disk) {

-  uint64 bytes_available = 0;

-  ASSERT_SUCCEEDED(GetFreeDiskSpace(_T("C:\\"), &bytes_available));

-

-  bytes_available = 0;

-  ASSERT_SUCCEEDED(GetFreeDiskSpace(CSIDL_PROGRAM_FILES, &bytes_available));

-

-  TCHAR system_drive[MAX_PATH] = _T("%SystemDrive%");

-  ASSERT_TRUE(::ExpandEnvironmentStrings(system_drive, system_drive, MAX_PATH));

-  ASSERT_TRUE(::PathAddBackslash(system_drive));

-

-  if (vista_util::IsUserAdmin()) {

-    // System drive should not be hot-pluggable

-    ASSERT_FALSE(IsHotPluggable(system_drive));

-  }

-

-  // System drive is expected to be > 4GB.

-  ASSERT_TRUE(IsLargeDrive(system_drive));

-

-  CString drive;

-  ASSERT_SUCCEEDED(FindFirstLocalDriveWithEnoughSpace(

-      kSpacePreferredToInstallDataDir, &drive));

-  if (vista_util::IsUserAdmin()) {

-    ASSERT_FALSE(IsHotPluggable(drive));

-  }

-  ASSERT_TRUE(IsLargeDrive(drive));

-}

-

-#if 0

-// http://b/1076675: test fails when run on mapped drives

-TEST(DiskTest, DevicePathToDosPath) {

-  TCHAR image_name[MAX_PATH] = _T("");

-  ASSERT_TRUE(::GetProcessImageFileName(::GetCurrentProcess(),

-                                        image_name,

-                                        arraysize(image_name)) != 0);

-

-  CString dos_name;

-  ASSERT_SUCCEEDED(DevicePathToDosPath(image_name, &dos_name));

-  ASSERT_TRUE(File::Exists(dos_name));

-

-  ASSERT_EQ(dos_name.CompareNoCase(app_util::GetCurrentModulePath()), 0);

-}

-#endif

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <shlobj.h>
+#include <psapi.h>
+
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_utils.h"
+#include "omaha/common/disk.h"
+#include "omaha/common/file.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(DiskTest, Disk) {
+  uint64 bytes_available = 0;
+  ASSERT_SUCCEEDED(GetFreeDiskSpace(_T("C:\\"), &bytes_available));
+
+  bytes_available = 0;
+  ASSERT_SUCCEEDED(GetFreeDiskSpace(CSIDL_PROGRAM_FILES, &bytes_available));
+
+  TCHAR system_drive[MAX_PATH] = _T("%SystemDrive%");
+  ASSERT_TRUE(::ExpandEnvironmentStrings(system_drive, system_drive, MAX_PATH));
+  ASSERT_TRUE(::PathAddBackslash(system_drive));
+
+  if (vista_util::IsUserAdmin()) {
+    // System drive should not be hot-pluggable
+    ASSERT_FALSE(IsHotPluggable(system_drive));
+  }
+
+  // System drive is expected to be > 4GB.
+  ASSERT_TRUE(IsLargeDrive(system_drive));
+
+  CString drive;
+  ASSERT_SUCCEEDED(FindFirstLocalDriveWithEnoughSpace(
+      kSpacePreferredToInstallDataDir, &drive));
+  if (vista_util::IsUserAdmin()) {
+    ASSERT_FALSE(IsHotPluggable(drive));
+  }
+  ASSERT_TRUE(IsLargeDrive(drive));
+}
+
+#if 0
+// http://b/1076675: test fails when run on mapped drives
+TEST(DiskTest, DevicePathToDosPath) {
+  TCHAR image_name[MAX_PATH] = _T("");
+  ASSERT_TRUE(::GetProcessImageFileName(::GetCurrentProcess(),
+                                        image_name,
+                                        arraysize(image_name)) != 0);
+
+  CString dos_name;
+  ASSERT_SUCCEEDED(DevicePathToDosPath(image_name, &dos_name));
+  ASSERT_TRUE(File::Exists(dos_name));
+
+  ASSERT_EQ(dos_name.CompareNoCase(app_util::GetCurrentModulePath()), 0);
+}
+#endif
+
+}  // namespace omaha
+
diff --git a/common/dynamic_link_dbghelp.cc b/common/dynamic_link_dbghelp.cc
index f887938..1d54d93 100644
--- a/common/dynamic_link_dbghelp.cc
+++ b/common/dynamic_link_dbghelp.cc
@@ -1,111 +1,111 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// dynamic loading of dbghelp dll functions

-

-#include "omaha/common/debug.h"

-#include "omaha/common/dynamic_link_dbghelp.h"

-

-namespace omaha {

-

-BOOL (CALLBACK *Dbghelp::SymInitialize)(HANDLE, PCSTR, BOOL);

-BOOL (CALLBACK *Dbghelp::SymCleanup)(HANDLE);

-BOOL (CALLBACK *Dbghelp::SymEnumSymbols)(HANDLE, ULONG64, PCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);

-DWORD (CALLBACK *Dbghelp::SymSetOptions)(DWORD);

-BOOL (CALLBACK *Dbghelp::SymSetContext)(HANDLE, PIMAGEHLP_STACK_FRAME, PIMAGEHLP_CONTEXT);

-BOOL (CALLBACK *Dbghelp::SymGetLineFromAddr)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE);

-BOOL (CALLBACK *Dbghelp::SymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);

-BOOL (CALLBACK *Dbghelp::SymFromAddr)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);

-BOOL (CALLBACK *Dbghelp::StackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,

-        PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);

-BOOL (CALLBACK *Dbghelp::StackWalk)(DWORD, HANDLE, HANDLE, LPSTACKFRAME, PVOID, PREAD_PROCESS_MEMORY_ROUTINE,

-        PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE);

-PVOID (CALLBACK *Dbghelp::SymFunctionTableAccess64)(HANDLE, DWORD64);

-PVOID (CALLBACK *Dbghelp::SymFunctionTableAccess)(HANDLE, DWORD);

-DWORD64 (CALLBACK *Dbghelp::SymGetModuleBase64)(HANDLE, DWORD64);

-DWORD64 (CALLBACK *Dbghelp::SymGetModuleBase)(HANDLE, DWORD);

-BOOL (CALLBACK *Dbghelp::SymGetTypeInfo)(HANDLE, DWORD64, ULONG, IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);

-BOOL (CALLBACK *Dbghelp::MiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION,

-        PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION);

-

-Dbghelp::LoadedState Dbghelp::loaded_state_ = Dbghelp::NOT_LOADED;

-HINSTANCE Dbghelp::library_ = NULL;

-

-template <typename T>

-bool Dbghelp::GPA(const char * function_name, T& function_pointer) {

-  ASSERT(function_name, (L""));

-

-  function_pointer = reinterpret_cast<T>(::GetProcAddress(library_,

-                                                          function_name));

-  return function_pointer != NULL;

-}

-

-HRESULT Dbghelp::Load() {

-  // If we've already tried to load, don't try again.

-  if (loaded_state_ != NOT_LOADED) goto Exit;

-

-  Clear();

-

-  // UTIL_LOG((L2, _T("dbghelp loading")));

-  library_ = ::LoadLibrary(_T("dbghelp"));

-  // UTIL_LOG((L2, _T("dbghelp loaded")));

-

-  if (!library_) return E_FAIL;

-

-  bool all_valid = (GPA("SymInitialize", SymInitialize))

-    & (GPA("SymCleanup", SymCleanup))

-    & (GPA("SymSetOptions", SymSetOptions))

-    & (GPA("SymGetLineFromAddr", SymGetLineFromAddr))

-    & (GPA("SymGetLineFromAddr64", SymGetLineFromAddr64))

-    & (GPA("StackWalk", StackWalk))

-    & (GPA("StackWalk64", StackWalk64))

-    & (GPA("SymFunctionTableAccess", SymFunctionTableAccess))

-    & (GPA("SymFunctionTableAccess64", SymFunctionTableAccess64))

-    & (GPA("SymGetModuleBase", SymGetModuleBase))

-    & (GPA("SymGetModuleBase64", SymGetModuleBase64))

-    & (GPA("MiniDumpWriteDump", MiniDumpWriteDump));

-

-  // These are not supported in the Win2k version of DbgHelp;

-  // failing to load them is not an error.

-  GPA("SymEnumSymbols", SymEnumSymbols);

-  GPA("SymGetTypeInfo", SymGetTypeInfo);

-  GPA("SymSetContext", SymSetContext);

-  GPA("SymFromAddr", SymFromAddr);

-

-  if (!all_valid) Unload();

-  loaded_state_ = all_valid ? LOAD_SUCCEEDED : LOAD_FAILED;

-

- Exit:

-  return (loaded_state_ == LOAD_SUCCEEDED) ? S_OK : E_FAIL;

-}

-

-void Dbghelp::Unload() {

-  if (library_) {

-    VERIFY(::FreeLibrary(library_), (L""));

-

-    // Must set library_ to NULL so that Loaded() will return FALSE.

-    library_ = NULL;

-    }

-  Clear();

-}

-

-void Dbghelp::Clear() {

-  // just clear the main entry points

-  SymInitialize = NULL;

-  MiniDumpWriteDump = NULL;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// dynamic loading of dbghelp dll functions
+
+#include "omaha/common/debug.h"
+#include "omaha/common/dynamic_link_dbghelp.h"
+
+namespace omaha {
+
+BOOL (CALLBACK *Dbghelp::SymInitialize)(HANDLE, PCSTR, BOOL);
+BOOL (CALLBACK *Dbghelp::SymCleanup)(HANDLE);
+BOOL (CALLBACK *Dbghelp::SymEnumSymbols)(HANDLE, ULONG64, PCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
+DWORD (CALLBACK *Dbghelp::SymSetOptions)(DWORD);
+BOOL (CALLBACK *Dbghelp::SymSetContext)(HANDLE, PIMAGEHLP_STACK_FRAME, PIMAGEHLP_CONTEXT);
+BOOL (CALLBACK *Dbghelp::SymGetLineFromAddr)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE);
+BOOL (CALLBACK *Dbghelp::SymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);
+BOOL (CALLBACK *Dbghelp::SymFromAddr)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
+BOOL (CALLBACK *Dbghelp::StackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
+        PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
+BOOL (CALLBACK *Dbghelp::StackWalk)(DWORD, HANDLE, HANDLE, LPSTACKFRAME, PVOID, PREAD_PROCESS_MEMORY_ROUTINE,
+        PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE);
+PVOID (CALLBACK *Dbghelp::SymFunctionTableAccess64)(HANDLE, DWORD64);
+PVOID (CALLBACK *Dbghelp::SymFunctionTableAccess)(HANDLE, DWORD);
+DWORD64 (CALLBACK *Dbghelp::SymGetModuleBase64)(HANDLE, DWORD64);
+DWORD64 (CALLBACK *Dbghelp::SymGetModuleBase)(HANDLE, DWORD);
+BOOL (CALLBACK *Dbghelp::SymGetTypeInfo)(HANDLE, DWORD64, ULONG, IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);
+BOOL (CALLBACK *Dbghelp::MiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION,
+        PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION);
+
+Dbghelp::LoadedState Dbghelp::loaded_state_ = Dbghelp::NOT_LOADED;
+HINSTANCE Dbghelp::library_ = NULL;
+
+template <typename T>
+bool Dbghelp::GPA(const char * function_name, T& function_pointer) {
+  ASSERT(function_name, (L""));
+
+  function_pointer = reinterpret_cast<T>(::GetProcAddress(library_,
+                                                          function_name));
+  return function_pointer != NULL;
+}
+
+HRESULT Dbghelp::Load() {
+  // If we've already tried to load, don't try again.
+  if (loaded_state_ != NOT_LOADED) goto Exit;
+
+  Clear();
+
+  // UTIL_LOG((L2, _T("dbghelp loading")));
+  library_ = ::LoadLibrary(_T("dbghelp"));
+  // UTIL_LOG((L2, _T("dbghelp loaded")));
+
+  if (!library_) return E_FAIL;
+
+  bool all_valid = (GPA("SymInitialize", SymInitialize))
+    & (GPA("SymCleanup", SymCleanup))
+    & (GPA("SymSetOptions", SymSetOptions))
+    & (GPA("SymGetLineFromAddr", SymGetLineFromAddr))
+    & (GPA("SymGetLineFromAddr64", SymGetLineFromAddr64))
+    & (GPA("StackWalk", StackWalk))
+    & (GPA("StackWalk64", StackWalk64))
+    & (GPA("SymFunctionTableAccess", SymFunctionTableAccess))
+    & (GPA("SymFunctionTableAccess64", SymFunctionTableAccess64))
+    & (GPA("SymGetModuleBase", SymGetModuleBase))
+    & (GPA("SymGetModuleBase64", SymGetModuleBase64))
+    & (GPA("MiniDumpWriteDump", MiniDumpWriteDump));
+
+  // These are not supported in the Win2k version of DbgHelp;
+  // failing to load them is not an error.
+  GPA("SymEnumSymbols", SymEnumSymbols);
+  GPA("SymGetTypeInfo", SymGetTypeInfo);
+  GPA("SymSetContext", SymSetContext);
+  GPA("SymFromAddr", SymFromAddr);
+
+  if (!all_valid) Unload();
+  loaded_state_ = all_valid ? LOAD_SUCCEEDED : LOAD_FAILED;
+
+ Exit:
+  return (loaded_state_ == LOAD_SUCCEEDED) ? S_OK : E_FAIL;
+}
+
+void Dbghelp::Unload() {
+  if (library_) {
+    VERIFY(::FreeLibrary(library_), (L""));
+
+    // Must set library_ to NULL so that Loaded() will return FALSE.
+    library_ = NULL;
+    }
+  Clear();
+}
+
+void Dbghelp::Clear() {
+  // just clear the main entry points
+  SymInitialize = NULL;
+  MiniDumpWriteDump = NULL;
+}
+
+}  // namespace omaha
+
diff --git a/common/dynamic_link_dbghelp.h b/common/dynamic_link_dbghelp.h
index 7b470a9..df6de46 100644
--- a/common/dynamic_link_dbghelp.h
+++ b/common/dynamic_link_dbghelp.h
@@ -1,70 +1,70 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// dynamic loading of dbghelp dll functions

-//

-

-#ifndef OMAHA_COMMON_DYNAMIC_LINK_DBGHELP_H_

-#define OMAHA_COMMON_DYNAMIC_LINK_DBGHELP_H_

-

-#include <dbghelp.h>

-

-namespace omaha {

-

-class Dbghelp {

- public:

-  static BOOL (CALLBACK *SymInitialize)(HANDLE, PCSTR, BOOL);

-  static BOOL (CALLBACK *SymCleanup)(HANDLE);

-  static BOOL (CALLBACK *SymEnumSymbols)(HANDLE, ULONG64, PCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);

-  static DWORD (CALLBACK *SymSetOptions)(DWORD);

-  static BOOL (CALLBACK *SymSetContext)(HANDLE, PIMAGEHLP_STACK_FRAME, PIMAGEHLP_CONTEXT);

-  static BOOL (CALLBACK *SymGetLineFromAddr)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE);

-  static BOOL (CALLBACK *SymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);

-  static BOOL (CALLBACK *SymFromAddr)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);

-  static BOOL (CALLBACK *StackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,

-      PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);

-  static BOOL (CALLBACK *StackWalk)(DWORD, HANDLE, HANDLE, LPSTACKFRAME, PVOID, PREAD_PROCESS_MEMORY_ROUTINE,

-      PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE);

-  static PVOID (CALLBACK *SymFunctionTableAccess64)(HANDLE, DWORD64);

-  static PVOID (CALLBACK *SymFunctionTableAccess)(HANDLE, DWORD);

-  static DWORD64 (CALLBACK *SymGetModuleBase64)(HANDLE, DWORD64);

-  static DWORD64 (CALLBACK *SymGetModuleBase)(HANDLE, DWORD);

-  static BOOL (CALLBACK *SymGetTypeInfo)(HANDLE, DWORD64, ULONG, IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);

-  static BOOL (CALLBACK *MiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION,

-      PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION);

-

-  static HRESULT Load();

-  static void Unload();

-  static bool Loaded() { return (loaded_state_ == LOAD_SUCCEEDED && library_ != NULL); }

-

- private:

-  // If we tried to load and failed, do not try again.

-  static enum LoadedState {NOT_LOADED, LOAD_FAILED, LOAD_SUCCEEDED};

-

-  static LoadedState loaded_state_;

-  static HINSTANCE library_;

-

-  static void Clear();

-

-  // wrapper around GetProcAddress()

-  template <typename T>

-  static bool GPA(const char * function_name, T& function_pointer);

-

-  DISALLOW_EVIL_CONSTRUCTORS(Dbghelp);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_DYNAMIC_LINK_DBGHELP_H_

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// dynamic loading of dbghelp dll functions
+//
+
+#ifndef OMAHA_COMMON_DYNAMIC_LINK_DBGHELP_H_
+#define OMAHA_COMMON_DYNAMIC_LINK_DBGHELP_H_
+
+#include <dbghelp.h>
+
+namespace omaha {
+
+class Dbghelp {
+ public:
+  static BOOL (CALLBACK *SymInitialize)(HANDLE, PCSTR, BOOL);
+  static BOOL (CALLBACK *SymCleanup)(HANDLE);
+  static BOOL (CALLBACK *SymEnumSymbols)(HANDLE, ULONG64, PCSTR, PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
+  static DWORD (CALLBACK *SymSetOptions)(DWORD);
+  static BOOL (CALLBACK *SymSetContext)(HANDLE, PIMAGEHLP_STACK_FRAME, PIMAGEHLP_CONTEXT);
+  static BOOL (CALLBACK *SymGetLineFromAddr)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE);
+  static BOOL (CALLBACK *SymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);
+  static BOOL (CALLBACK *SymFromAddr)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
+  static BOOL (CALLBACK *StackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64,
+      PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64);
+  static BOOL (CALLBACK *StackWalk)(DWORD, HANDLE, HANDLE, LPSTACKFRAME, PVOID, PREAD_PROCESS_MEMORY_ROUTINE,
+      PFUNCTION_TABLE_ACCESS_ROUTINE, PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE);
+  static PVOID (CALLBACK *SymFunctionTableAccess64)(HANDLE, DWORD64);
+  static PVOID (CALLBACK *SymFunctionTableAccess)(HANDLE, DWORD);
+  static DWORD64 (CALLBACK *SymGetModuleBase64)(HANDLE, DWORD64);
+  static DWORD64 (CALLBACK *SymGetModuleBase)(HANDLE, DWORD);
+  static BOOL (CALLBACK *SymGetTypeInfo)(HANDLE, DWORD64, ULONG, IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);
+  static BOOL (CALLBACK *MiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION,
+      PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION);
+
+  static HRESULT Load();
+  static void Unload();
+  static bool Loaded() { return (loaded_state_ == LOAD_SUCCEEDED && library_ != NULL); }
+
+ private:
+  // If we tried to load and failed, do not try again.
+  static enum LoadedState {NOT_LOADED, LOAD_FAILED, LOAD_SUCCEEDED};
+
+  static LoadedState loaded_state_;
+  static HINSTANCE library_;
+
+  static void Clear();
+
+  // wrapper around GetProcAddress()
+  template <typename T>
+  static bool GPA(const char * function_name, T& function_pointer);
+
+  DISALLOW_EVIL_CONSTRUCTORS(Dbghelp);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_DYNAMIC_LINK_DBGHELP_H_
diff --git a/common/dynamic_link_kernel32.cc b/common/dynamic_link_kernel32.cc
index 61190b6..c440479 100644
--- a/common/dynamic_link_kernel32.cc
+++ b/common/dynamic_link_kernel32.cc
@@ -1,108 +1,108 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// dynamic loading of Windows kernel32.dll API dll functions

-// wrappers for win32 functions not supported on windows 95/98/ME

-

-#include "omaha/common/debug.h"

-#include "omaha/common/dynamic_link_kernel32.h"

-

-namespace omaha {

-

-typedef BOOL (WINAPI * Module32FirstFunc)(HANDLE, LPMODULEENTRY32);

-typedef BOOL (WINAPI * Module32NextFunc)(HANDLE, LPMODULEENTRY32);

-typedef BOOL (WINAPI * Process32FirstFunc)(HANDLE, LPPROCESSENTRY32);

-typedef BOOL (WINAPI * Process32NextFunc)(HANDLE, LPPROCESSENTRY32);

-typedef BOOL (WINAPI * IsWow64ProcessFunc)(HANDLE, PBOOL);

-

-#define kKernel32Module L"kernel32"

-

-BOOL WINAPI Kernel32::Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme) {

-  static Module32FirstFunc f = NULL;

-

-  if (f == NULL) {

-    HMODULE handle = GetModuleHandle(kKernel32Module);

-    ASSERT(handle, (L""));

-    f = (Module32FirstFunc) GetProcAddress(handle, "Module32FirstW");

-  }

-

-  if (f == NULL)

-    return FALSE;

-

-  return f(hSnapshot, lpme);

-}

-

-BOOL WINAPI Kernel32::Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme) {

-  static Module32NextFunc f = NULL;

-

-  if (f == NULL) {

-    HMODULE handle = GetModuleHandle(kKernel32Module);

-    ASSERT(handle, (L""));

-    f = (Module32NextFunc) GetProcAddress(handle, "Module32NextW");

-  }

-

-  if (f == NULL)

-    return FALSE;

-

-  return f(hSnapshot, lpme);

-}

-

-BOOL WINAPI Kernel32::Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe) {

-  static Process32FirstFunc f = NULL;

-

-  if (f == NULL) {

-    HMODULE handle = GetModuleHandle(kKernel32Module);

-    ASSERT(handle, (L""));

-    f = (Process32FirstFunc) GetProcAddress(handle, "Process32FirstW");

-  }

-

-  if (f == NULL)

-    return FALSE;

-

-  return f(hSnapshot, lppe);

-}

-

-BOOL WINAPI Kernel32::Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe) {

-  static Process32NextFunc f = NULL;

-

-  if (f == NULL) {

-    HMODULE handle = GetModuleHandle(kKernel32Module);

-    ASSERT(handle, (L""));

-    f = (Process32NextFunc) GetProcAddress(handle, "Process32NextW");

-  }

-

-  if (f == NULL)

-    return FALSE;

-

-  return f(hSnapshot, lppe);

-}

-

-BOOL WINAPI Kernel32::IsWow64Process(HANDLE hProcess, PBOOL Wow64Process) {

-  static IsWow64ProcessFunc f = NULL;

-

-  if (f == NULL) {

-    HMODULE handle = GetModuleHandle(kKernel32Module);

-    ASSERT(handle, (L""));

-    f = (IsWow64ProcessFunc) GetProcAddress(handle, "IsWow64Process");

-  }

-

-  if (f == NULL)

-    return FALSE;

-

-  return f(hProcess, Wow64Process);

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// dynamic loading of Windows kernel32.dll API dll functions
+// wrappers for win32 functions not supported on windows 95/98/ME
+
+#include "omaha/common/debug.h"
+#include "omaha/common/dynamic_link_kernel32.h"
+
+namespace omaha {
+
+typedef BOOL (WINAPI * Module32FirstFunc)(HANDLE, LPMODULEENTRY32);
+typedef BOOL (WINAPI * Module32NextFunc)(HANDLE, LPMODULEENTRY32);
+typedef BOOL (WINAPI * Process32FirstFunc)(HANDLE, LPPROCESSENTRY32);
+typedef BOOL (WINAPI * Process32NextFunc)(HANDLE, LPPROCESSENTRY32);
+typedef BOOL (WINAPI * IsWow64ProcessFunc)(HANDLE, PBOOL);
+
+#define kKernel32Module L"kernel32"
+
+BOOL WINAPI Kernel32::Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme) {
+  static Module32FirstFunc f = NULL;
+
+  if (f == NULL) {
+    HMODULE handle = GetModuleHandle(kKernel32Module);
+    ASSERT(handle, (L""));
+    f = (Module32FirstFunc) GetProcAddress(handle, "Module32FirstW");
+  }
+
+  if (f == NULL)
+    return FALSE;
+
+  return f(hSnapshot, lpme);
+}
+
+BOOL WINAPI Kernel32::Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme) {
+  static Module32NextFunc f = NULL;
+
+  if (f == NULL) {
+    HMODULE handle = GetModuleHandle(kKernel32Module);
+    ASSERT(handle, (L""));
+    f = (Module32NextFunc) GetProcAddress(handle, "Module32NextW");
+  }
+
+  if (f == NULL)
+    return FALSE;
+
+  return f(hSnapshot, lpme);
+}
+
+BOOL WINAPI Kernel32::Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe) {
+  static Process32FirstFunc f = NULL;
+
+  if (f == NULL) {
+    HMODULE handle = GetModuleHandle(kKernel32Module);
+    ASSERT(handle, (L""));
+    f = (Process32FirstFunc) GetProcAddress(handle, "Process32FirstW");
+  }
+
+  if (f == NULL)
+    return FALSE;
+
+  return f(hSnapshot, lppe);
+}
+
+BOOL WINAPI Kernel32::Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe) {
+  static Process32NextFunc f = NULL;
+
+  if (f == NULL) {
+    HMODULE handle = GetModuleHandle(kKernel32Module);
+    ASSERT(handle, (L""));
+    f = (Process32NextFunc) GetProcAddress(handle, "Process32NextW");
+  }
+
+  if (f == NULL)
+    return FALSE;
+
+  return f(hSnapshot, lppe);
+}
+
+BOOL WINAPI Kernel32::IsWow64Process(HANDLE hProcess, PBOOL Wow64Process) {
+  static IsWow64ProcessFunc f = NULL;
+
+  if (f == NULL) {
+    HMODULE handle = GetModuleHandle(kKernel32Module);
+    ASSERT(handle, (L""));
+    f = (IsWow64ProcessFunc) GetProcAddress(handle, "IsWow64Process");
+  }
+
+  if (f == NULL)
+    return FALSE;
+
+  return f(hProcess, Wow64Process);
+}
+
+}  // namespace omaha
+
diff --git a/common/dynamic_link_kernel32.h b/common/dynamic_link_kernel32.h
index 1e34233..b8542f8 100644
--- a/common/dynamic_link_kernel32.h
+++ b/common/dynamic_link_kernel32.h
@@ -1,46 +1,46 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Dynamic loading of Windows kernel32.dll API dll functions not supported

-// on Windows 95/98/ME.

-

-#ifndef OMAHA_COMMON_DYNAMIC_LINK_KERNEL32_H_

-#define OMAHA_COMMON_DYNAMIC_LINK_KERNEL32_H_

-

-#include <windows.h>

-#include <tlhelp32.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class Kernel32 {

- public:

-

-  static BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme);

-  static BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme);

-  static BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);

-  static BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);

-

-  // Is process running under WOW64?

-  // WOW64 is the emulator for win32 applications running on win64.

-  static BOOL WINAPI IsWow64Process(HANDLE hProcess, PBOOL Wow64Process);

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(Kernel32);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_DYNAMIC_LINK_KERNEL32_H_

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Dynamic loading of Windows kernel32.dll API dll functions not supported
+// on Windows 95/98/ME.
+
+#ifndef OMAHA_COMMON_DYNAMIC_LINK_KERNEL32_H_
+#define OMAHA_COMMON_DYNAMIC_LINK_KERNEL32_H_
+
+#include <windows.h>
+#include <tlhelp32.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class Kernel32 {
+ public:
+
+  static BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
+  static BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
+  static BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
+  static BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
+
+  // Is process running under WOW64?
+  // WOW64 is the emulator for win32 applications running on win64.
+  static BOOL WINAPI IsWow64Process(HANDLE hProcess, PBOOL Wow64Process);
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(Kernel32);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_DYNAMIC_LINK_KERNEL32_H_
diff --git a/common/dynamic_link_kernel32_unittest.cc b/common/dynamic_link_kernel32_unittest.cc
index 6358146..6df570c 100644
--- a/common/dynamic_link_kernel32_unittest.cc
+++ b/common/dynamic_link_kernel32_unittest.cc
@@ -1,30 +1,30 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// dynamic link kernel 32 unittest

-

-#include "omaha/common/dynamic_link_kernel32.h"

-#include "omaha/common/system_info.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(DynamicLinkKernel32Test, DynamicLinkKernel32) {

-  BOOL is64(0);

-  ASSERT_TRUE(Kernel32::IsWow64Process(GetCurrentProcess(), &is64));

-  ASSERT_EQ(static_cast<BOOL>(SystemInfo::IsRunningOn64Bit()), is64);

-}

-

-}  // namespace omaha

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// dynamic link kernel 32 unittest
+
+#include "omaha/common/dynamic_link_kernel32.h"
+#include "omaha/common/system_info.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(DynamicLinkKernel32Test, DynamicLinkKernel32) {
+  BOOL is64(0);
+  ASSERT_TRUE(Kernel32::IsWow64Process(GetCurrentProcess(), &is64));
+  ASSERT_EQ(static_cast<BOOL>(SystemInfo::IsRunningOn64Bit()), is64);
+}
+
+}  // namespace omaha
diff --git a/common/encrypt.cc b/common/encrypt.cc
index cbaa996..4d5a758 100644
--- a/common/encrypt.cc
+++ b/common/encrypt.cc
@@ -1,95 +1,95 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/encrypt.h"

-

-#include <vector>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-

-namespace omaha {

-

-namespace encrypt {

-

-// TODO(omaha): consider loading crypt32.dll dynamically, as these functions

-// are used infrequently.

-

-HRESULT EncryptData(const void* key, size_t key_len,

-                    const void* data, size_t data_len,

-                    std::vector<uint8>* data_out) {

-  // key may be null.

-  ASSERT1(data);

-  ASSERT1(data_out);

-  DATA_BLOB blob_out = {0, NULL};

-  DATA_BLOB blob_in = { data_len, static_cast<BYTE*>(const_cast<void*>(data)) };

-  DATA_BLOB entropy = { 0, NULL };

-  if (key != NULL && key_len != 0) {

-    entropy.cbData = key_len;

-    entropy.pbData = static_cast<BYTE*>(const_cast<void*>(key));

-  }

-

-  // The description parameter is required on W2K.

-  if (!::CryptProtectData(&blob_in, _T("gupdate"), &entropy, NULL, NULL,

-                          CRYPTPROTECT_UI_FORBIDDEN, &blob_out)) {

-    return HRESULTFromLastError();

-  }

-

-  data_out->clear();

-  const uint8* first = reinterpret_cast<const uint8*>(blob_out.pbData);

-  const uint8* last = first + blob_out.cbData;

-  data_out->insert(data_out->begin(), first, last);

-  ::LocalFree(blob_out.pbData);

-

-  ASSERT1(data_out->size() == blob_out.cbData);

-  return S_OK;

-}

-

-HRESULT DecryptData(const void* key, size_t key_len,

-                    const void* data, size_t data_len,

-                    std::vector<uint8>* data_out) {

-  // key may be null.

-  ASSERT1(data);

-  ASSERT1(data_out);

-

-  DATA_BLOB blob_out = {0, NULL};

-  DATA_BLOB blob_in = { data_len, static_cast<BYTE*>(const_cast<void*>(data)) };

-  DATA_BLOB entropy = { 0, NULL };

-

-  if (key != NULL && key_len != 0) {

-    entropy.cbData = key_len;

-    entropy.pbData = static_cast<BYTE*>(const_cast<void*>(key));

-  }

-

-  if (!::CryptUnprotectData(&blob_in, NULL, &entropy, NULL, NULL,

-                            CRYPTPROTECT_UI_FORBIDDEN, &blob_out)) {

-    return (::GetLastError() != ERROR_SUCCESS) ?

-        HRESULTFromLastError() : HRESULT_FROM_WIN32(ERROR_INVALID_DATA);

-  }

-

-  data_out->clear();

-  const uint8* first = reinterpret_cast<const uint8*>(blob_out.pbData);

-  const uint8* last = first + blob_out.cbData;

-  data_out->insert(data_out->begin(), first, last);

-  ::LocalFree(blob_out.pbData);

-

-  ASSERT1(data_out->size() == blob_out.cbData);

-  return S_OK;

-}

-

-}  // namespace encrypt

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/encrypt.h"
+
+#include <vector>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+
+namespace omaha {
+
+namespace encrypt {
+
+// TODO(omaha): consider loading crypt32.dll dynamically, as these functions
+// are used infrequently.
+
+HRESULT EncryptData(const void* key, size_t key_len,
+                    const void* data, size_t data_len,
+                    std::vector<uint8>* data_out) {
+  // key may be null.
+  ASSERT1(data);
+  ASSERT1(data_out);
+  DATA_BLOB blob_out = {0, NULL};
+  DATA_BLOB blob_in = { data_len, static_cast<BYTE*>(const_cast<void*>(data)) };
+  DATA_BLOB entropy = { 0, NULL };
+  if (key != NULL && key_len != 0) {
+    entropy.cbData = key_len;
+    entropy.pbData = static_cast<BYTE*>(const_cast<void*>(key));
+  }
+
+  // The description parameter is required on W2K.
+  if (!::CryptProtectData(&blob_in, _T("gupdate"), &entropy, NULL, NULL,
+                          CRYPTPROTECT_UI_FORBIDDEN, &blob_out)) {
+    return HRESULTFromLastError();
+  }
+
+  data_out->clear();
+  const uint8* first = reinterpret_cast<const uint8*>(blob_out.pbData);
+  const uint8* last = first + blob_out.cbData;
+  data_out->insert(data_out->begin(), first, last);
+  ::LocalFree(blob_out.pbData);
+
+  ASSERT1(data_out->size() == blob_out.cbData);
+  return S_OK;
+}
+
+HRESULT DecryptData(const void* key, size_t key_len,
+                    const void* data, size_t data_len,
+                    std::vector<uint8>* data_out) {
+  // key may be null.
+  ASSERT1(data);
+  ASSERT1(data_out);
+
+  DATA_BLOB blob_out = {0, NULL};
+  DATA_BLOB blob_in = { data_len, static_cast<BYTE*>(const_cast<void*>(data)) };
+  DATA_BLOB entropy = { 0, NULL };
+
+  if (key != NULL && key_len != 0) {
+    entropy.cbData = key_len;
+    entropy.pbData = static_cast<BYTE*>(const_cast<void*>(key));
+  }
+
+  if (!::CryptUnprotectData(&blob_in, NULL, &entropy, NULL, NULL,
+                            CRYPTPROTECT_UI_FORBIDDEN, &blob_out)) {
+    return (::GetLastError() != ERROR_SUCCESS) ?
+        HRESULTFromLastError() : HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+  }
+
+  data_out->clear();
+  const uint8* first = reinterpret_cast<const uint8*>(blob_out.pbData);
+  const uint8* last = first + blob_out.cbData;
+  data_out->insert(data_out->begin(), first, last);
+  ::LocalFree(blob_out.pbData);
+
+  ASSERT1(data_out->size() == blob_out.cbData);
+  return S_OK;
+}
+
+}  // namespace encrypt
+
+}  // namespace omaha
+
diff --git a/common/encrypt.h b/common/encrypt.h
index 599cc46..59a43de 100644
--- a/common/encrypt.h
+++ b/common/encrypt.h
@@ -1,46 +1,46 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Encryption functions

-

-#ifndef OMAHA_COMMON_ENCRYPT_H__

-#define OMAHA_COMMON_ENCRYPT_H__

-

-#include <windows.h>

-#include <wincrypt.h>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-namespace encrypt {

-

-// Encrypts a data buffer by using the user's credentials as well as

-// the provided key. The key may be NULL, if no entropy is needed.

-HRESULT EncryptData(const void* key, size_t key_len,

-                    const void* data, size_t data_len,

-                    std::vector<uint8>* data_out);

-

-// Decrypts the provided data buffer. The key may be NULL, if no entropy

-// is needed.

-HRESULT DecryptData(const void* key, size_t key_len,

-                    const void* data, size_t data_len,

-                    std::vector<uint8>* data_out);

-

-}  // namespace encrypt

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_ENCRYPT_H__

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Encryption functions
+
+#ifndef OMAHA_COMMON_ENCRYPT_H__
+#define OMAHA_COMMON_ENCRYPT_H__
+
+#include <windows.h>
+#include <wincrypt.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+namespace encrypt {
+
+// Encrypts a data buffer by using the user's credentials as well as
+// the provided key. The key may be NULL, if no entropy is needed.
+HRESULT EncryptData(const void* key, size_t key_len,
+                    const void* data, size_t data_len,
+                    std::vector<uint8>* data_out);
+
+// Decrypts the provided data buffer. The key may be NULL, if no entropy
+// is needed.
+HRESULT DecryptData(const void* key, size_t key_len,
+                    const void* data, size_t data_len,
+                    std::vector<uint8>* data_out);
+
+}  // namespace encrypt
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_ENCRYPT_H__
diff --git a/common/encrypt_test.cc b/common/encrypt_test.cc
index 1acb253..55ca9b2 100644
--- a/common/encrypt_test.cc
+++ b/common/encrypt_test.cc
@@ -1,57 +1,57 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <omaha/common/encrypt.h>

-#include <cstring>

-#include <vector>

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace encrypt {

-

-TEST(EncryptTest, Test) {

-  const char* plaintext = "the quick brown fox jumps over the lazy dog";

-  std::vector<uint8> ciphertext;

-  EXPECT_HRESULT_SUCCEEDED(EncryptData(NULL, 0,

-                                       plaintext, strlen(plaintext),

-                                       &ciphertext));

-  std::vector<uint8> decrypted_text;

-  EXPECT_HRESULT_SUCCEEDED(DecryptData(NULL, 0,

-                                       &ciphertext.front(), ciphertext.size(),

-                                       &decrypted_text));

-  EXPECT_EQ(decrypted_text.size(), strlen(plaintext));

-  decrypted_text.push_back(0);

-  EXPECT_STREQ(reinterpret_cast<char*>(&decrypted_text.front()), plaintext);

-

-

-  const char* key = "foobar";

-  ciphertext.clear();

-  EXPECT_HRESULT_SUCCEEDED(EncryptData(key, strlen(key),

-                                       plaintext, strlen(plaintext),

-                                       &ciphertext));

-  decrypted_text.clear();

-  EXPECT_HRESULT_SUCCEEDED(DecryptData(key, strlen(key),

-                                       &ciphertext.front(), ciphertext.size(),

-                                       &decrypted_text));

-  EXPECT_EQ(decrypted_text.size(), strlen(plaintext));

-  decrypted_text.push_back(0);

-  EXPECT_STREQ(reinterpret_cast<char*>(&decrypted_text.front()), plaintext);

-}

-

-}  // namespace encrypt

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <omaha/common/encrypt.h>
+#include <cstring>
+#include <vector>
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace encrypt {
+
+TEST(EncryptTest, Test) {
+  const char* plaintext = "the quick brown fox jumps over the lazy dog";
+  std::vector<uint8> ciphertext;
+  EXPECT_HRESULT_SUCCEEDED(EncryptData(NULL, 0,
+                                       plaintext, strlen(plaintext),
+                                       &ciphertext));
+  std::vector<uint8> decrypted_text;
+  EXPECT_HRESULT_SUCCEEDED(DecryptData(NULL, 0,
+                                       &ciphertext.front(), ciphertext.size(),
+                                       &decrypted_text));
+  EXPECT_EQ(decrypted_text.size(), strlen(plaintext));
+  decrypted_text.push_back(0);
+  EXPECT_STREQ(reinterpret_cast<char*>(&decrypted_text.front()), plaintext);
+
+
+  const char* key = "foobar";
+  ciphertext.clear();
+  EXPECT_HRESULT_SUCCEEDED(EncryptData(key, strlen(key),
+                                       plaintext, strlen(plaintext),
+                                       &ciphertext));
+  decrypted_text.clear();
+  EXPECT_HRESULT_SUCCEEDED(DecryptData(key, strlen(key),
+                                       &ciphertext.front(), ciphertext.size(),
+                                       &decrypted_text));
+  EXPECT_EQ(decrypted_text.size(), strlen(plaintext));
+  decrypted_text.push_back(0);
+  EXPECT_STREQ(reinterpret_cast<char*>(&decrypted_text.front()), plaintext);
+}
+
+}  // namespace encrypt
+
+}  // namespace omaha
+
diff --git a/common/error.cc b/common/error.cc
index 444af9b..1838882 100644
--- a/common/error.cc
+++ b/common/error.cc
@@ -1,44 +1,44 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/error.h"

-#include <winhttp.h>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-HRESULT HRESULTFromLastError() {

-  DWORD error_code = ::GetLastError();

-  ASSERT1(error_code != NO_ERROR);

-  return (error_code != NO_ERROR) ? HRESULT_FROM_WIN32(error_code) : E_FAIL;

-}

-

-HRESULT HRESULTFromHttpStatusCode(int status_code) {

-  COMPILE_ASSERT(GOOPDATE_E_NETWORK_FIRST + HTTP_STATUS_LAST <

-                 GOOPDATE_E_NETWORK_LAST,

-                 GOOPDATE_E_NETWORK_LAST_too_small);

-  HRESULT hr = S_OK;

-  if (HTTP_STATUS_FIRST <= status_code && status_code <= HTTP_STATUS_LAST) {

-    hr = GOOPDATE_E_NETWORK_FIRST + status_code;

-  } else {

-    hr = GOOPDATE_E_NETWORK_LAST;

-  }

-  ASSERT1(HRESULT_FACILITY(hr) == FACILITY_ITF);

-  return hr;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/error.h"
+#include <winhttp.h>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+HRESULT HRESULTFromLastError() {
+  DWORD error_code = ::GetLastError();
+  ASSERT1(error_code != NO_ERROR);
+  return (error_code != NO_ERROR) ? HRESULT_FROM_WIN32(error_code) : E_FAIL;
+}
+
+HRESULT HRESULTFromHttpStatusCode(int status_code) {
+  COMPILE_ASSERT(GOOPDATE_E_NETWORK_FIRST + HTTP_STATUS_LAST <
+                 GOOPDATE_E_NETWORK_LAST,
+                 GOOPDATE_E_NETWORK_LAST_too_small);
+  HRESULT hr = S_OK;
+  if (HTTP_STATUS_FIRST <= status_code && status_code <= HTTP_STATUS_LAST) {
+    hr = GOOPDATE_E_NETWORK_FIRST + status_code;
+  } else {
+    hr = GOOPDATE_E_NETWORK_LAST;
+  }
+  ASSERT1(HRESULT_FACILITY(hr) == FACILITY_ITF);
+  return hr;
+}
+
+}  // namespace omaha
+
diff --git a/common/error.h b/common/error.h
index d5ae5f6..ff6dce3 100644
--- a/common/error.h
+++ b/common/error.h
@@ -1,430 +1,430 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Error codes and HRESULTS

-//

-// TODO(omaha): reduce the number of custom error codes below by searching and

-// seeing what is handled and what is not.

-//

-// TODO(omaha): rename CI and GOOPDATE to OMAHA.

-

-#ifndef OMAHA_COMMON_ERROR_H_

-#define OMAHA_COMMON_ERROR_H_

-

-#include <windows.h>

-

-namespace omaha {

-

-// Returns the last error as an HRESULT or E_FAIL if last error is NO_ERROR.

-// This is not a drop in replacement for the HRESULT_FROM_WIN32 macro.

-// The macro maps a NO_ERROR to S_OK, whereas the function below maps a

-// NO_ERROR to E_FAIL. Also, the macro is evaluating arguments multiple times.

-HRESULT HRESULTFromLastError();

-

-// Returns the http status_code as an HRESULT.

-HRESULT HRESULTFromHttpStatusCode(int status_code);

-

-// HRESULTs

-//

-// Top bit indicates success (0) or failure (1)

-// 16 bits available for 'code' field at end

-

-#define kFacilityCi 67

-

-#define CI_E_NOT_ENOUGH_DISK_SPACE                \

-    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0003)

-

-// CI_E_INVALID_MANIFEST is returned when the manifest file is missing a

-// required field or has some other kind of semantic error

-#define CI_E_INVALID_MANIFEST                     \

-    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0012)

-

-// CI_E_XML_LOAD_ERROR is returned when MSXML can't load the document into DOM.

-// It may be because the document is not well formed (tags, namespaces, etc)

-#define CI_E_XML_LOAD_ERROR                       \

-    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0013)

-

-// CI_E_INVALID_ARG is returned when invalid command line arugment is specified

-#define CI_E_INVALID_ARG                          \

-    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x001B)

-

-// CI_E_PROXY_AUTH_REQUIRED is returned when proxy authentication is required

-#define CI_E_PROXY_AUTH_REQUIRED                  \

-    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0028)

-

-// CI_E_INVALID_PROXY_AUTH_SCHEME is returned when the proxy authentication

-// scheme is unknown or not supported

-#define CI_E_INVALID_PROXY_AUTH_SCHEME            \

-    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0029)

-

-// CI_E_BITS_DISABLED is returned by the download manager when the BITS service

-// is not enabled.

-#define CI_E_BITS_DISABLED                        \

-    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0030)

-

-// CI_E_HTTPS_CERT_FAILURE is returned when the https connection fails.

-// One cause of this is when the system clock is off by a significant

-// amount which makes the server certificate appear invalid.

-#define CI_E_HTTPS_CERT_FAILURE                   \

-    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0035)

-

-// Return values from Process::WaitUntilDeadOrInterrupt

-// TODO(omaha) Move this constants to the Process class. They do not look like

-// error codes.

-#define CI_S_PROCESSWAIT_DEAD                     \

-    MAKE_HRESULT(SEVERITY_SUCCESS, kFacilityCi, 0x0100)

-#define CI_S_PROCESSWAIT_TIMEOUT                  \

-    MAKE_HRESULT(SEVERITY_SUCCESS, kFacilityCi, 0x0101)

-#define CI_S_PROCESSWAIT_MESSAGE                  \

-    MAKE_HRESULT(SEVERITY_SUCCESS, kFacilityCi, 0x0102)

-

-// Signatures error codes.

-#define SIGS_E_INVALID_PFX_CERTIFICATE            \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0200)

-#define SIGS_E_INVALID_DER_CERTIFICATE            \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0201)

-#define SIGS_E_INVALID_PASSWORD                   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0202)

-#define SIGS_E_INVALID_KEY_TYPE                   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0203)

-#define SIGS_E_INVALID_SIGNATURE                  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0204)

-

-// Goopdate XML parser error codes.

-#define GOOPDATEXML_E_STRTOUINT                   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x300)

-#define GOOPDATEXML_E_RESPONSESNODE               \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x301)

-#define GOOPDATEXML_E_XMLVERSION                  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x302)

-#define GOOPDATEXML_E_NEEDSADMIN                  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x303)

-#define GOOPDATEXML_E_UNEXPECTED_URI              \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x304)

-#define GOOPDATEXML_E_TOO_MANY_APPS               \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x305)

-

-// Goopdate job queue error codes.

-// Errors 0x401 - 0x407 are legacy codes and should not be reused.

-

-// Download Manager custom error codes.

-// Obsolete: GOOPDATEDOWNLOAD_E_FILE_ALREADY_DOWNLOADED - 0x500.

-// Obsolete: GOOPDATEDOWNLOAD_E_FAILED_GET_ERROR - 0x501.

-#define GOOPDATEDOWNLOAD_E_INVALID_PATH             \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x502)

-#define GOOPDATEDOWNLOAD_E_CRACKURL_FAILED          \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x503)

-#define GOOPDATEDOWNLOAD_E_FILE_NAME_EMPTY          \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x504)

-#define GOOPDATEDOWNLOAD_E_DEST_FILE_PATH_EMPTY     \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x505)

-#define GOOPDATEDOWNLOAD_E_STORAGE_DIR_NOT_EXIST    \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x506)

-#define GOOPDATEDOWNLOAD_E_FILE_SIZE_ZERO           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x507)

-#define GOOPDATEDOWNLOAD_E_FILE_SIZE_SMALLER        \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x508)

-#define GOOPDATEDOWNLOAD_E_FILE_SIZE_LARGER         \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x509)

-#define GOOPDATEDOWNLOAD_E_UNIQUE_FILE_PATH_EMPTY   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x50A)

-#define GOOPDATEDOWNLOAD_E_DEST_PATH_EMPTY          \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x50B)

-#define GOOPDATEDOWNLOAD_E_DEST_FILENAME_EMPTY      \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x50C)

-#define GOOPDATEDOWNLOAD_E_FAILED_MOVE              \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x5FF)

-

-// Goopdate custom error codes.

-// Obsolete this error when legacy support is removed.

-#define GOOPDATE_E_NON_ADMINS_CANNOT_INSTALL_ADMIN  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x600)

-// Obsolete: GOOPDATE_S_WORKER_ALREADY_RUNNING - 0x601.

-// Obsolete: GOOPDATE_E_INVALID_ARG_COMBINATION - 0x602.

-#define GOOPDATE_E_WORKER_ALREADY_RUNNING           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x603)

-#define GOOPDATE_E_APP_BEING_INSTALLED              \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x604)

-#define GOOPDATE_E_RESOURCE_DLL_PATH_EMPTY          \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x605)

-

-// Setup and metainstaller custom error codes.

-#define GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP       \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x700)

-// Obsolete: GOOPDATE_E_MANIFEST_FILENAME_EMPTY - 0x701.

-// Obsolete: GOOPDATE_E_MANIFEST_FILE_DOES_NOT_EXIST - 0x702.

-// This error appears in the metainstaller.

-#define GOOPDATE_E_RUNNING_INFERIOR_WINDOWS         \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x703)

-#define GOOPDATE_E_RUNNING_INFERIOR_MSXML           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x704)

-// Obsolete: GOOPDATE_E_ELEVATION_FAILED - 0x705

-#define GOOPDATE_E_FAILED_TO_GET_LOCK               \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x706)

-#define GOOPDATE_E_INSTANCES_RUNNING                \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x707)

-#define GOOPDATE_E_HANDOFF_FAILED                   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x708)

-#define GOOPDATE_E_PATH_APPEND_FAILED               \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x709)

-#define GOOPDATE_E_SERVICE_NAME_EMPTY               \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70a)

-#define GOOPDATE_E_SETUP_LOCK_INIT_FAILED           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70b)

-#define GOOPDATE_E_ACCESSDENIED_COPYING_CORE_FILES  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70c)

-#define GOOPDATE_E_ACCESSDENIED_COPYING_SHELL       \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70d)

-#define GOOPDATE_E_ACCESSDENIED_STOP_PROCESSES      \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70e)

-#define GOOPDATE_E_ACCESSDENIED_SETUP_REG_ACCESS    \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70f)

-// User may have accidentally run the metainstaller twice.

-#define GOOPDATE_E_FAILED_TO_GET_LOCK_MATCHING_INSTALL_PROCESS_RUNNING  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x710)

-#define GOOPDATE_E_FAILED_TO_GET_LOCK_NONMATCHING_INSTALL_PROCESS_RUNNING \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x711)

-#define GOOPDATE_E_FAILED_TO_GET_LOCK_UPDATE_PROCESS_RUNNING  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x712)

-#define GOOPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x713)

-#define GOOPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED_TIMESTAMP_CHECK \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x714)

-#define GOOPDATE_E_INSTALL_ELEVATED_PROCESS_NEEDS_ELEVATION \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x715)

-#define GOOPDATE_E_ELEVATION_FAILED_ADMIN           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x716)

-#define GOOPDATE_E_ELEVATION_FAILED_NON_ADMIN       \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x717)

-#define GOOPDATE_E_CANT_UNINSTALL                   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x718)

-#define GOOPDATE_E_SILENT_INSTALL_NEEDS_ELEVATION   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x719)

-#define GOOPDATE_E_OEM_NOT_MACHINE_AND_PRIVILEGED_AND_AUDIT_MODE  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x71a)

-#define GOOPDATE_E_OEM_WITH_ONLINE_INSTALLER        \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x71b)

-#define GOOPDATE_E_NON_OEM_INSTALL_IN_AUDIT_MODE    \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x71c)

-#define GOOPDATE_E_OEM_INSTALL_SUCCEEDED_BUT_NOT_IN_OEM_INSTALLING_MODE \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x71d)

-#define GOOPDATE_E_EULA_REQURED_WITH_ONLINE_INSTALLER \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x71e)

-

-// Metainstaller custom error codes.

-#define GOOPDATE_E_UNTAGGED_METAINSTALLER           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x750)

-

-

-// Obsolete: GOOPDATE_E_NO_SERVER_RESPONSE - 0x800.

-#define GOOPDATE_E_NO_NETWORK \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x801)

-// Obsolete: GOOPDATE_E_UPDATE_CHECK_FAILED - 0x802.

-// Obsolete: GOOPDATE_COULD_NOT_GET_IGOOGLEUPDATE - 0x803.

-// Obsolete: GOOPDATE_E_BAD_SERVER_RESPONSE - 0x804.

-#define GOOPDATE_E_UNKNOWN_SERVER_RESPONSE          \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x805)

-#define GOOPDATE_E_RESTRICTED_SERVER_RESPONSE       \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x806)

-// Obsolete: GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED - 0x807.

-// Obsolete: GOOPDATE_E_ABANDON_UPDATE            - 0x808.

-#define GOOPDATE_E_NO_UPDATE_RESPONSE               \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x809)

-#define GOOPDATE_E_BUNDLE_ERROR                     \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80A)

-#define GOOPDATE_E_APP_UNINSTALLED                  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80B)

-#define GOOPDATE_E_CALL_INPROGRESS                  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80C)

-#define GOOPDATE_E_UNKNOWN_APP_SERVER_RESPONSE      \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80D)

-#define GOOPDATE_E_INTERNAL_ERROR_SERVER_RESPONSE   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80E)

-#define GOOPDATE_E_NO_SERVER_RESPONSE               \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80F)

-#define GOOPDATE_E_WORKER_CANCELLED                 \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x810)

-#define GOOPDATE_E_OS_NOT_SUPPORTED                 \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x811)

-#define GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x812)

-#define GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY    \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x813)

-#define GOOPDATE_E_APP_NOT_REGISTERED               \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x814)

-#define GOOPDATE_E_CANNOT_USE_NETWORK               \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x815)

-#define GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x816)

-

-//

-// Network stack error codes.

-//

-

-// The CUP response is missing the ETag header containing the server proof.

-#define OMAHA_NET_E_CUP_NO_SERVER_PROOF            \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x880)

-

-// The CUP response is not trusted.

-#define OMAHA_NET_E_CUP_NOT_TRUSTED                \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x881)

-#define OMAHA_NET_E_REQUEST_CANCELLED              \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x882)

-

-// CUP could not instantiate an http client.

-#define OMAHA_NET_E_CUP_NO_HTTP_CLIENT              \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x883)

-

-// CUP could not generate random bytes.

-#define OMAHA_NET_E_CUP_NO_ENTROPY                  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x884)

-

-// Non-CUP network errors.

-#define OMAHA_NET_E_WINHTTP_NOT_AVAILABLE           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x890)

-

-// Install Manager custom error codes.

-#define GOOPDATEINSTALL_E_FILENAME_INVALID         \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x900)

-#define GOOPDATEINSTALL_E_INSTALLER_FAILED_START   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x901)

-#define GOOPDATEINSTALL_E_INSTALLER_FAILED         \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x902)

-#define GOOPDATEINSTALL_E_INSTALLER_INTERNAL_ERROR \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x903)

-#define GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT      \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x904)

-#define GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x905)

-#define GOOPDATEINSTALL_E_CANNOT_GET_INSTALLER_LOCK           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x906)

-#define GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING         \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x907)

-#define GOOPDATEINSTALL_E_INSTALLER_DID_NOT_CHANGE_VERSION    \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x908)

-#define GOOPDATE_E_INVALID_INSTALL_DATA_INDEX                 \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x909)

-#define GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS          \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x90A)

-

-// GoopdateUtils custom error codes.

-#define GOOPDATEUTILS_E_BROWSERTYPE                 \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA00)

-

-// GoogleUpdate.exe shell custom error codes.

-#define GOOGLEUPDATE_E_DLL_NOT_FOUND           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xB00)

-#define GOOGLEUPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xB01)

-

-// Command line parse custom error codes.

-#define GOOGLEUPDATE_COMMANDLINE_E_NO_SCENARIO_HANDLER \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xC00)

-#define GOOGLEUPDATE_COMMANDLINE_E_NO_SCENARIO_HANDLER_MATCHED \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xC01)

-

-// OneClick custom error codes

-#define GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED        \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD01)

-#define GOOPDATE_E_ONECLICK_NO_LANGUAGE_RESOURCE    \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD02)

-

-// Usage stats / metrics error codes

-#define GOOPDATE_E_METRICS_LOCK_INIT_FAILED         \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD80)

-#define GOOPDATE_E_METRICS_AGGREGATE_FAILED         \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD81)

-

-// Core error codes

-#define GOOPDATE_E_CORE_INTERNAL_ERROR              \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xE00)

-#define GOOPDATE_E_CORE_MISSING_CMD                 \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xE01)

-

-// UI & Observer error codes

-#define GOOPDATE_E_UI_INTERNAL_ERROR                \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xE80)

-#define GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL  \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xE81)

-

-// ApplyTagTool error codes.

-#define APPLYTAG_E_ALREADY_TAGGED                   \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x1000)

-

-// The range [0x2000, 0x2400) is reserved for certain network stack errors

-// when the server returns an HTTP result code that is not a success code.

-// The size of the range is 1024, which is enough to map all the HTTP result

-// codes.

-#define GOOPDATE_E_NETWORK_FIRST                            \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2000)

-

-// Http Status Code 401 -- Unauthorized.

-#define GOOPDATE_E_NETWORK_UNAUTHORIZED                     \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2191)

-

-// Http Status Code 403 -- Forbidden.

-#define GOOPDATE_E_NETWORK_FORBIDDEN                        \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2193)

-

-// Http Status Code 407 -- Proxy Authentication Required.

-#define GOOPDATE_E_NETWORK_PROXYAUTHREQUIRED                \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2197)

-

-#define GOOPDATE_E_NETWORK_LAST                             \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x23FF)

-

-// Shared Memory Proxy error codes.

-#define GOOPDATE_E_INVALID_SHARED_MEMORY_PTR                \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2401)

-#define GOOPDATE_E_INVALID_INTERFACE_MARSHAL_SIZE           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2402)

-

-// Crash handling error codes.

-

-// The crash reporting cannot start the crash server for

-// out-of-process crash handling.

-#define GOOPDATE_E_CRASH_START_SERVER_FAILED                 \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFA)

-

-// The crash reporting cannot set the security descriptors for

-// a securable object.

-#define GOOPDATE_E_CRASH_SECURITY_FAILED                     \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFB)

-

-// The crash reporting could not get the crash reports dir.

-#define GOOPDATE_E_CRASH_NO_DIR                             \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFC)

-

-// The crash reporting failed due to the client side metering of the crashes.

-#define GOOPDATE_E_CRASH_THROTTLED                          \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFD)

-

-// The crash reporting failed due to the server rejecting the crash.

-#define GOOPDATE_E_CRASH_REJECTED                           \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFE)

-

-// Goopdate crash. The error code is returned when the process is terminated

-// due to a crash handled by breakpad.

-#define GOOPDATE_E_CRASH                            \

-    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFF)

-

-

-// This is the end of the range for FACILITY_ITF errors. Do not define errors

-// below.

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_ERROR_H_

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Error codes and HRESULTS
+//
+// TODO(omaha): reduce the number of custom error codes below by searching and
+// seeing what is handled and what is not.
+//
+// TODO(omaha): rename CI and GOOPDATE to OMAHA.
+
+#ifndef OMAHA_COMMON_ERROR_H_
+#define OMAHA_COMMON_ERROR_H_
+
+#include <windows.h>
+
+namespace omaha {
+
+// Returns the last error as an HRESULT or E_FAIL if last error is NO_ERROR.
+// This is not a drop in replacement for the HRESULT_FROM_WIN32 macro.
+// The macro maps a NO_ERROR to S_OK, whereas the function below maps a
+// NO_ERROR to E_FAIL. Also, the macro is evaluating arguments multiple times.
+HRESULT HRESULTFromLastError();
+
+// Returns the http status_code as an HRESULT.
+HRESULT HRESULTFromHttpStatusCode(int status_code);
+
+// HRESULTs
+//
+// Top bit indicates success (0) or failure (1)
+// 16 bits available for 'code' field at end
+
+#define kFacilityCi 67
+
+#define CI_E_NOT_ENOUGH_DISK_SPACE                \
+    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0003)
+
+// CI_E_INVALID_MANIFEST is returned when the manifest file is missing a
+// required field or has some other kind of semantic error
+#define CI_E_INVALID_MANIFEST                     \
+    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0012)
+
+// CI_E_XML_LOAD_ERROR is returned when MSXML can't load the document into DOM.
+// It may be because the document is not well formed (tags, namespaces, etc)
+#define CI_E_XML_LOAD_ERROR                       \
+    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0013)
+
+// CI_E_INVALID_ARG is returned when invalid command line arugment is specified
+#define CI_E_INVALID_ARG                          \
+    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x001B)
+
+// CI_E_PROXY_AUTH_REQUIRED is returned when proxy authentication is required
+#define CI_E_PROXY_AUTH_REQUIRED                  \
+    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0028)
+
+// CI_E_INVALID_PROXY_AUTH_SCHEME is returned when the proxy authentication
+// scheme is unknown or not supported
+#define CI_E_INVALID_PROXY_AUTH_SCHEME            \
+    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0029)
+
+// CI_E_BITS_DISABLED is returned by the download manager when the BITS service
+// is not enabled.
+#define CI_E_BITS_DISABLED                        \
+    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0030)
+
+// CI_E_HTTPS_CERT_FAILURE is returned when the https connection fails.
+// One cause of this is when the system clock is off by a significant
+// amount which makes the server certificate appear invalid.
+#define CI_E_HTTPS_CERT_FAILURE                   \
+    MAKE_HRESULT(SEVERITY_ERROR, kFacilityCi, 0x0035)
+
+// Return values from Process::WaitUntilDeadOrInterrupt
+// TODO(omaha) Move this constants to the Process class. They do not look like
+// error codes.
+#define CI_S_PROCESSWAIT_DEAD                     \
+    MAKE_HRESULT(SEVERITY_SUCCESS, kFacilityCi, 0x0100)
+#define CI_S_PROCESSWAIT_TIMEOUT                  \
+    MAKE_HRESULT(SEVERITY_SUCCESS, kFacilityCi, 0x0101)
+#define CI_S_PROCESSWAIT_MESSAGE                  \
+    MAKE_HRESULT(SEVERITY_SUCCESS, kFacilityCi, 0x0102)
+
+// Signatures error codes.
+#define SIGS_E_INVALID_PFX_CERTIFICATE            \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0200)
+#define SIGS_E_INVALID_DER_CERTIFICATE            \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0201)
+#define SIGS_E_INVALID_PASSWORD                   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0202)
+#define SIGS_E_INVALID_KEY_TYPE                   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0203)
+#define SIGS_E_INVALID_SIGNATURE                  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x0204)
+
+// Goopdate XML parser error codes.
+#define GOOPDATEXML_E_STRTOUINT                   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x300)
+#define GOOPDATEXML_E_RESPONSESNODE               \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x301)
+#define GOOPDATEXML_E_XMLVERSION                  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x302)
+#define GOOPDATEXML_E_NEEDSADMIN                  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x303)
+#define GOOPDATEXML_E_UNEXPECTED_URI              \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x304)
+#define GOOPDATEXML_E_TOO_MANY_APPS               \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x305)
+
+// Goopdate job queue error codes.
+// Errors 0x401 - 0x407 are legacy codes and should not be reused.
+
+// Download Manager custom error codes.
+// Obsolete: GOOPDATEDOWNLOAD_E_FILE_ALREADY_DOWNLOADED - 0x500.
+// Obsolete: GOOPDATEDOWNLOAD_E_FAILED_GET_ERROR - 0x501.
+#define GOOPDATEDOWNLOAD_E_INVALID_PATH             \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x502)
+#define GOOPDATEDOWNLOAD_E_CRACKURL_FAILED          \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x503)
+#define GOOPDATEDOWNLOAD_E_FILE_NAME_EMPTY          \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x504)
+#define GOOPDATEDOWNLOAD_E_DEST_FILE_PATH_EMPTY     \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x505)
+#define GOOPDATEDOWNLOAD_E_STORAGE_DIR_NOT_EXIST    \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x506)
+#define GOOPDATEDOWNLOAD_E_FILE_SIZE_ZERO           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x507)
+#define GOOPDATEDOWNLOAD_E_FILE_SIZE_SMALLER        \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x508)
+#define GOOPDATEDOWNLOAD_E_FILE_SIZE_LARGER         \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x509)
+#define GOOPDATEDOWNLOAD_E_UNIQUE_FILE_PATH_EMPTY   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x50A)
+#define GOOPDATEDOWNLOAD_E_DEST_PATH_EMPTY          \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x50B)
+#define GOOPDATEDOWNLOAD_E_DEST_FILENAME_EMPTY      \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x50C)
+#define GOOPDATEDOWNLOAD_E_FAILED_MOVE              \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x5FF)
+
+// Goopdate custom error codes.
+// Obsolete this error when legacy support is removed.
+#define GOOPDATE_E_NON_ADMINS_CANNOT_INSTALL_ADMIN  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x600)
+// Obsolete: GOOPDATE_S_WORKER_ALREADY_RUNNING - 0x601.
+// Obsolete: GOOPDATE_E_INVALID_ARG_COMBINATION - 0x602.
+#define GOOPDATE_E_WORKER_ALREADY_RUNNING           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x603)
+#define GOOPDATE_E_APP_BEING_INSTALLED              \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x604)
+#define GOOPDATE_E_RESOURCE_DLL_PATH_EMPTY          \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x605)
+
+// Setup and metainstaller custom error codes.
+#define GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP       \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x700)
+// Obsolete: GOOPDATE_E_MANIFEST_FILENAME_EMPTY - 0x701.
+// Obsolete: GOOPDATE_E_MANIFEST_FILE_DOES_NOT_EXIST - 0x702.
+// This error appears in the metainstaller.
+#define GOOPDATE_E_RUNNING_INFERIOR_WINDOWS         \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x703)
+#define GOOPDATE_E_RUNNING_INFERIOR_MSXML           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x704)
+// Obsolete: GOOPDATE_E_ELEVATION_FAILED - 0x705
+#define GOOPDATE_E_FAILED_TO_GET_LOCK               \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x706)
+#define GOOPDATE_E_INSTANCES_RUNNING                \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x707)
+#define GOOPDATE_E_HANDOFF_FAILED                   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x708)
+#define GOOPDATE_E_PATH_APPEND_FAILED               \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x709)
+#define GOOPDATE_E_SERVICE_NAME_EMPTY               \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70a)
+#define GOOPDATE_E_SETUP_LOCK_INIT_FAILED           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70b)
+#define GOOPDATE_E_ACCESSDENIED_COPYING_CORE_FILES  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70c)
+#define GOOPDATE_E_ACCESSDENIED_COPYING_SHELL       \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70d)
+#define GOOPDATE_E_ACCESSDENIED_STOP_PROCESSES      \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70e)
+#define GOOPDATE_E_ACCESSDENIED_SETUP_REG_ACCESS    \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x70f)
+// User may have accidentally run the metainstaller twice.
+#define GOOPDATE_E_FAILED_TO_GET_LOCK_MATCHING_INSTALL_PROCESS_RUNNING  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x710)
+#define GOOPDATE_E_FAILED_TO_GET_LOCK_NONMATCHING_INSTALL_PROCESS_RUNNING \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x711)
+#define GOOPDATE_E_FAILED_TO_GET_LOCK_UPDATE_PROCESS_RUNNING  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x712)
+#define GOOPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x713)
+#define GOOPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED_TIMESTAMP_CHECK \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x714)
+#define GOOPDATE_E_INSTALL_ELEVATED_PROCESS_NEEDS_ELEVATION \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x715)
+#define GOOPDATE_E_ELEVATION_FAILED_ADMIN           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x716)
+#define GOOPDATE_E_ELEVATION_FAILED_NON_ADMIN       \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x717)
+#define GOOPDATE_E_CANT_UNINSTALL                   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x718)
+#define GOOPDATE_E_SILENT_INSTALL_NEEDS_ELEVATION   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x719)
+#define GOOPDATE_E_OEM_NOT_MACHINE_AND_PRIVILEGED_AND_AUDIT_MODE  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x71a)
+#define GOOPDATE_E_OEM_WITH_ONLINE_INSTALLER        \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x71b)
+#define GOOPDATE_E_NON_OEM_INSTALL_IN_AUDIT_MODE    \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x71c)
+#define GOOPDATE_E_OEM_INSTALL_SUCCEEDED_BUT_NOT_IN_OEM_INSTALLING_MODE \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x71d)
+#define GOOPDATE_E_EULA_REQURED_WITH_ONLINE_INSTALLER \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x71e)
+
+// Metainstaller custom error codes.
+#define GOOPDATE_E_UNTAGGED_METAINSTALLER           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x750)
+
+
+// Obsolete: GOOPDATE_E_NO_SERVER_RESPONSE - 0x800.
+#define GOOPDATE_E_NO_NETWORK \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x801)
+// Obsolete: GOOPDATE_E_UPDATE_CHECK_FAILED - 0x802.
+// Obsolete: GOOPDATE_COULD_NOT_GET_IGOOGLEUPDATE - 0x803.
+// Obsolete: GOOPDATE_E_BAD_SERVER_RESPONSE - 0x804.
+#define GOOPDATE_E_UNKNOWN_SERVER_RESPONSE          \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x805)
+#define GOOPDATE_E_RESTRICTED_SERVER_RESPONSE       \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x806)
+// Obsolete: GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED - 0x807.
+// Obsolete: GOOPDATE_E_ABANDON_UPDATE            - 0x808.
+#define GOOPDATE_E_NO_UPDATE_RESPONSE               \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x809)
+#define GOOPDATE_E_BUNDLE_ERROR                     \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80A)
+#define GOOPDATE_E_APP_UNINSTALLED                  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80B)
+#define GOOPDATE_E_CALL_INPROGRESS                  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80C)
+#define GOOPDATE_E_UNKNOWN_APP_SERVER_RESPONSE      \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80D)
+#define GOOPDATE_E_INTERNAL_ERROR_SERVER_RESPONSE   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80E)
+#define GOOPDATE_E_NO_SERVER_RESPONSE               \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x80F)
+#define GOOPDATE_E_WORKER_CANCELLED                 \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x810)
+#define GOOPDATE_E_OS_NOT_SUPPORTED                 \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x811)
+#define GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x812)
+#define GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY    \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x813)
+#define GOOPDATE_E_APP_NOT_REGISTERED               \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x814)
+#define GOOPDATE_E_CANNOT_USE_NETWORK               \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x815)
+#define GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x816)
+
+//
+// Network stack error codes.
+//
+
+// The CUP response is missing the ETag header containing the server proof.
+#define OMAHA_NET_E_CUP_NO_SERVER_PROOF            \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x880)
+
+// The CUP response is not trusted.
+#define OMAHA_NET_E_CUP_NOT_TRUSTED                \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x881)
+#define OMAHA_NET_E_REQUEST_CANCELLED              \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x882)
+
+// CUP could not instantiate an http client.
+#define OMAHA_NET_E_CUP_NO_HTTP_CLIENT              \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x883)
+
+// CUP could not generate random bytes.
+#define OMAHA_NET_E_CUP_NO_ENTROPY                  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x884)
+
+// Non-CUP network errors.
+#define OMAHA_NET_E_WINHTTP_NOT_AVAILABLE           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x890)
+
+// Install Manager custom error codes.
+#define GOOPDATEINSTALL_E_FILENAME_INVALID         \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x900)
+#define GOOPDATEINSTALL_E_INSTALLER_FAILED_START   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x901)
+#define GOOPDATEINSTALL_E_INSTALLER_FAILED         \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x902)
+#define GOOPDATEINSTALL_E_INSTALLER_INTERNAL_ERROR \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x903)
+#define GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT      \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x904)
+#define GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x905)
+#define GOOPDATEINSTALL_E_CANNOT_GET_INSTALLER_LOCK           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x906)
+#define GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING         \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x907)
+#define GOOPDATEINSTALL_E_INSTALLER_DID_NOT_CHANGE_VERSION    \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x908)
+#define GOOPDATE_E_INVALID_INSTALL_DATA_INDEX                 \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x909)
+#define GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS          \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x90A)
+
+// GoopdateUtils custom error codes.
+#define GOOPDATEUTILS_E_BROWSERTYPE                 \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA00)
+
+// GoogleUpdate.exe shell custom error codes.
+#define GOOGLEUPDATE_E_DLL_NOT_FOUND           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xB00)
+#define GOOGLEUPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xB01)
+
+// Command line parse custom error codes.
+#define GOOGLEUPDATE_COMMANDLINE_E_NO_SCENARIO_HANDLER \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xC00)
+#define GOOGLEUPDATE_COMMANDLINE_E_NO_SCENARIO_HANDLER_MATCHED \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xC01)
+
+// OneClick custom error codes
+#define GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED        \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD01)
+#define GOOPDATE_E_ONECLICK_NO_LANGUAGE_RESOURCE    \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD02)
+
+// Usage stats / metrics error codes
+#define GOOPDATE_E_METRICS_LOCK_INIT_FAILED         \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD80)
+#define GOOPDATE_E_METRICS_AGGREGATE_FAILED         \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD81)
+
+// Core error codes
+#define GOOPDATE_E_CORE_INTERNAL_ERROR              \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xE00)
+#define GOOPDATE_E_CORE_MISSING_CMD                 \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xE01)
+
+// UI & Observer error codes
+#define GOOPDATE_E_UI_INTERNAL_ERROR                \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xE80)
+#define GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL  \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xE81)
+
+// ApplyTagTool error codes.
+#define APPLYTAG_E_ALREADY_TAGGED                   \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x1000)
+
+// The range [0x2000, 0x2400) is reserved for certain network stack errors
+// when the server returns an HTTP result code that is not a success code.
+// The size of the range is 1024, which is enough to map all the HTTP result
+// codes.
+#define GOOPDATE_E_NETWORK_FIRST                            \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2000)
+
+// Http Status Code 401 -- Unauthorized.
+#define GOOPDATE_E_NETWORK_UNAUTHORIZED                     \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2191)
+
+// Http Status Code 403 -- Forbidden.
+#define GOOPDATE_E_NETWORK_FORBIDDEN                        \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2193)
+
+// Http Status Code 407 -- Proxy Authentication Required.
+#define GOOPDATE_E_NETWORK_PROXYAUTHREQUIRED                \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2197)
+
+#define GOOPDATE_E_NETWORK_LAST                             \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x23FF)
+
+// Shared Memory Proxy error codes.
+#define GOOPDATE_E_INVALID_SHARED_MEMORY_PTR                \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2401)
+#define GOOPDATE_E_INVALID_INTERFACE_MARSHAL_SIZE           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x2402)
+
+// Crash handling error codes.
+
+// The crash reporting cannot start the crash server for
+// out-of-process crash handling.
+#define GOOPDATE_E_CRASH_START_SERVER_FAILED                 \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFA)
+
+// The crash reporting cannot set the security descriptors for
+// a securable object.
+#define GOOPDATE_E_CRASH_SECURITY_FAILED                     \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFB)
+
+// The crash reporting could not get the crash reports dir.
+#define GOOPDATE_E_CRASH_NO_DIR                             \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFC)
+
+// The crash reporting failed due to the client side metering of the crashes.
+#define GOOPDATE_E_CRASH_THROTTLED                          \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFD)
+
+// The crash reporting failed due to the server rejecting the crash.
+#define GOOPDATE_E_CRASH_REJECTED                           \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFE)
+
+// Goopdate crash. The error code is returned when the process is terminated
+// due to a crash handled by breakpad.
+#define GOOPDATE_E_CRASH                            \
+    MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xFFFF)
+
+
+// This is the end of the range for FACILITY_ITF errors. Do not define errors
+// below.
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_ERROR_H_
+
diff --git a/common/error_unittest.cc b/common/error_unittest.cc
index 366003e..b9df549 100644
--- a/common/error_unittest.cc
+++ b/common/error_unittest.cc
@@ -1,38 +1,38 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/commontypes.h"

-#include "omaha/common/error.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(ErrorTest, HRESULTFromLastError) {

-  ::SetLastError(ERROR_ACCESS_DENIED);

-  EXPECT_EQ(HRESULTFromLastError(), E_ACCESSDENIED);

-

-  ::SetLastError(static_cast<DWORD>(E_INVALIDARG));

-  EXPECT_EQ(HRESULTFromLastError(), E_INVALIDARG);

-}

-

-TEST(ErrorTest, HRESULTFromLastErrorAssert) {

-  ExpectAsserts expect_asserts;

-  ::SetLastError(0);

-  EXPECT_EQ(HRESULTFromLastError(), E_FAIL);

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/commontypes.h"
+#include "omaha/common/error.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(ErrorTest, HRESULTFromLastError) {
+  ::SetLastError(ERROR_ACCESS_DENIED);
+  EXPECT_EQ(HRESULTFromLastError(), E_ACCESSDENIED);
+
+  ::SetLastError(static_cast<DWORD>(E_INVALIDARG));
+  EXPECT_EQ(HRESULTFromLastError(), E_INVALIDARG);
+}
+
+TEST(ErrorTest, HRESULTFromLastErrorAssert) {
+  ExpectAsserts expect_asserts;
+  ::SetLastError(0);
+  EXPECT_EQ(HRESULTFromLastError(), E_FAIL);
+}
+
+}  // namespace omaha
+
diff --git a/common/event_handler.h b/common/event_handler.h
index 11d7afc..1a0990c 100644
--- a/common/event_handler.h
+++ b/common/event_handler.h
@@ -1,36 +1,36 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_EVENT_HANDLER_H_

-#define OMAHA_COMMON_EVENT_HANDLER_H_

-

-#include <windows.h>

-

-namespace omaha {

-

-// Defines an abstract interface for the event handlers associated with

-// waitable kernel objects.

-class EventHandler {

- public:

-  virtual ~EventHandler() {}

-

-  // Gets called when the handle is signaled.

-  virtual void HandleEvent(HANDLE h) = 0;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_EVENT_HANDLER_H_

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_EVENT_HANDLER_H_
+#define OMAHA_COMMON_EVENT_HANDLER_H_
+
+#include <windows.h>
+
+namespace omaha {
+
+// Defines an abstract interface for the event handlers associated with
+// waitable kernel objects.
+class EventHandler {
+ public:
+  virtual ~EventHandler() {}
+
+  // Gets called when the handle is signaled.
+  virtual void HandleEvent(HANDLE h) = 0;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_EVENT_HANDLER_H_
+
diff --git a/common/exception_barrier.cc b/common/exception_barrier.cc
index ebd13e6..526cc55 100644
--- a/common/exception_barrier.cc
+++ b/common/exception_barrier.cc
@@ -1,53 +1,53 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// A class to make it easy to tag exception propagation boundaries and

-// get crash reports of exceptions that pass over same.

-#include "omaha/common/exception_barrier.h"

-

-enum {

-  // Flag set by exception handling machinery when unwinding

-  EH_UNWINDING = 0x00000002

-};

-

-// TODO(omaha): How to make this statically parameterizable?

-ExceptionBarrier::ExceptionHandler ExceptionBarrier::s_handler_ = NULL;

-

-// This function must be extern "C" to match up with the SAFESEH

-// declaration in our corresponding ASM file

-extern "C" EXCEPTION_DISPOSITION __cdecl

-ExceptionBarrierHandler(struct _EXCEPTION_RECORD *exception_record,

-                        void * establisher_frame,

-                        struct _CONTEXT *context,

-                        void * reserved) {

-  establisher_frame;  // unreferenced formal parameter

-  reserved;

-  if (!(exception_record->ExceptionFlags & EH_UNWINDING)) {

-    // When the exception is really propagating through us, we'd like to be

-    // called before the state of the program has been modified by the stack

-    // unwinding. In the absence of an exception handler, the unhandled

-    // exception filter gets called between the first chance and the second

-    // chance exceptions, so Windows pops either the JIT debugger or WER UI.

-    // This is not desirable in most of the cases.

-    ExceptionBarrier::ExceptionHandler handler = ExceptionBarrier::handler();

-    if (handler) {

-      EXCEPTION_POINTERS ptrs = { exception_record, context };

-

-      handler(&ptrs);

-    }

-  }

-

-  return ExceptionContinueSearch;

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// A class to make it easy to tag exception propagation boundaries and
+// get crash reports of exceptions that pass over same.
+#include "omaha/common/exception_barrier.h"
+
+enum {
+  // Flag set by exception handling machinery when unwinding
+  EH_UNWINDING = 0x00000002
+};
+
+// TODO(omaha): How to make this statically parameterizable?
+ExceptionBarrier::ExceptionHandler ExceptionBarrier::s_handler_ = NULL;
+
+// This function must be extern "C" to match up with the SAFESEH
+// declaration in our corresponding ASM file
+extern "C" EXCEPTION_DISPOSITION __cdecl
+ExceptionBarrierHandler(struct _EXCEPTION_RECORD *exception_record,
+                        void * establisher_frame,
+                        struct _CONTEXT *context,
+                        void * reserved) {
+  establisher_frame;  // unreferenced formal parameter
+  reserved;
+  if (!(exception_record->ExceptionFlags & EH_UNWINDING)) {
+    // When the exception is really propagating through us, we'd like to be
+    // called before the state of the program has been modified by the stack
+    // unwinding. In the absence of an exception handler, the unhandled
+    // exception filter gets called between the first chance and the second
+    // chance exceptions, so Windows pops either the JIT debugger or WER UI.
+    // This is not desirable in most of the cases.
+    ExceptionBarrier::ExceptionHandler handler = ExceptionBarrier::handler();
+    if (handler) {
+      EXCEPTION_POINTERS ptrs = { exception_record, context };
+
+      handler(&ptrs);
+    }
+  }
+
+  return ExceptionContinueSearch;
+}
diff --git a/common/exception_barrier.h b/common/exception_barrier.h
index 568166a..ecc01b6 100644
--- a/common/exception_barrier.h
+++ b/common/exception_barrier.h
@@ -1,110 +1,110 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// A class to make it easy to tag exception propagation boundaries and

-// get crash reports of exceptions that pass over same.

-#ifndef OMAHA_COMMON_EXCEPTION_BARRIER_H_

-#define OMAHA_COMMON_EXCEPTION_BARRIER_H_

-

-#include <windows.h>

-

-/// This is the type dictated for an exception handler by the platform ABI

-/// @see _except_handler in excpt.h

-typedef EXCEPTION_DISPOSITION (__cdecl *ExceptionHandlerFunc)(

-                                struct _EXCEPTION_RECORD *exception_record,

-                                void * establisher_frame,

-                                struct _CONTEXT *context,

-                                void * reserved);

-

-/// The type of an exception record in the exception handler chain

-struct EXCEPTION_REGISTRATION {

-  EXCEPTION_REGISTRATION *prev;

-  ExceptionHandlerFunc  handler;

-};

-

-/// This is our raw exception handler, it must be declared extern "C" to

-/// match up with the SAFESEH declaration in our corresponding ASM file

-extern "C" EXCEPTION_DISPOSITION __cdecl

-ExceptionBarrierHandler(struct _EXCEPTION_RECORD *exception_record,

-                        void * establisher_frame,

-                        struct _CONTEXT *context,

-                        void * reserved);

-

-/// An exception barrier is used to report exceptions that pass through

-/// a boundary where exceptions shouldn't pass, such as e.g. COM interface

-/// boundaries.

-/// This is handy for any kind of plugin code, where if the exception passes

-/// through unhindered, it'll either be swallowed by an SEH exception handler

-/// above us on the stack, or be reported as an unhandled exception for

-/// the application hosting the plugin code.

-///

-/// To use this class, simply instantiate an ExceptionBarrier just inside

-/// the code boundary, like this:

-/// @code

-/// HRESULT SomeObject::SomeCOMMethod(...) {

-///   ExceptionBarrier report_crashes;

-///

-///   ... other code here ...

-/// }

-/// @endcode

-class ExceptionBarrier {

- public:

-  /// Register the barrier in the SEH chain

-  ExceptionBarrier();

-

-  /// And unregister on destruction

-  ~ExceptionBarrier();

-

-  /// Signature of the handler function which gets notified when

-  /// an exception propagates through a barrier.

-  typedef void (CALLBACK *ExceptionHandler)(EXCEPTION_POINTERS *ptrs);

-

-  /// @name Accessors

-  /// @{

-  static void set_handler(ExceptionHandler handler) { s_handler_ = handler; }

-  static ExceptionHandler handler() { return s_handler_; }

-  /// @}

-

- private:

-  /// Our SEH frame

-  EXCEPTION_REGISTRATION registration_;

-

-  /// The function that gets invoked if an exception

-  /// propagates through a barrier

-  /// TODO(omaha): how can this be statically parametrized?

-  static ExceptionHandler s_handler_;

-};

-

-/// @name These are implemented in the associated .asm file

-/// @{

-extern "C" void WINAPI RegisterExceptionRecord(

-                          EXCEPTION_REGISTRATION *registration,

-                          ExceptionHandlerFunc func);

-extern "C" void WINAPI UnregisterExceptionRecord(

-                          EXCEPTION_REGISTRATION *registration);

-/// @}

-

-

-inline ExceptionBarrier::ExceptionBarrier() {

-  RegisterExceptionRecord(&registration_, ExceptionBarrierHandler);

-}

-

-inline ExceptionBarrier::~ExceptionBarrier() {

-  // TODO(omaha): I don't think it's safe to unregister after an exception

-  //          has taken place???

-  UnregisterExceptionRecord(&registration_);

-}

-

-#endif  // OMAHA_COMMON_EXCEPTION_BARRIER_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// A class to make it easy to tag exception propagation boundaries and
+// get crash reports of exceptions that pass over same.
+#ifndef OMAHA_COMMON_EXCEPTION_BARRIER_H_
+#define OMAHA_COMMON_EXCEPTION_BARRIER_H_
+
+#include <windows.h>
+
+/// This is the type dictated for an exception handler by the platform ABI
+/// @see _except_handler in excpt.h
+typedef EXCEPTION_DISPOSITION (__cdecl *ExceptionHandlerFunc)(
+                                struct _EXCEPTION_RECORD *exception_record,
+                                void * establisher_frame,
+                                struct _CONTEXT *context,
+                                void * reserved);
+
+/// The type of an exception record in the exception handler chain
+struct EXCEPTION_REGISTRATION {
+  EXCEPTION_REGISTRATION *prev;
+  ExceptionHandlerFunc  handler;
+};
+
+/// This is our raw exception handler, it must be declared extern "C" to
+/// match up with the SAFESEH declaration in our corresponding ASM file
+extern "C" EXCEPTION_DISPOSITION __cdecl
+ExceptionBarrierHandler(struct _EXCEPTION_RECORD *exception_record,
+                        void * establisher_frame,
+                        struct _CONTEXT *context,
+                        void * reserved);
+
+/// An exception barrier is used to report exceptions that pass through
+/// a boundary where exceptions shouldn't pass, such as e.g. COM interface
+/// boundaries.
+/// This is handy for any kind of plugin code, where if the exception passes
+/// through unhindered, it'll either be swallowed by an SEH exception handler
+/// above us on the stack, or be reported as an unhandled exception for
+/// the application hosting the plugin code.
+///
+/// To use this class, simply instantiate an ExceptionBarrier just inside
+/// the code boundary, like this:
+/// @code
+/// HRESULT SomeObject::SomeCOMMethod(...) {
+///   ExceptionBarrier report_crashes;
+///
+///   ... other code here ...
+/// }
+/// @endcode
+class ExceptionBarrier {
+ public:
+  /// Register the barrier in the SEH chain
+  ExceptionBarrier();
+
+  /// And unregister on destruction
+  ~ExceptionBarrier();
+
+  /// Signature of the handler function which gets notified when
+  /// an exception propagates through a barrier.
+  typedef void (CALLBACK *ExceptionHandler)(EXCEPTION_POINTERS *ptrs);
+
+  /// @name Accessors
+  /// @{
+  static void set_handler(ExceptionHandler handler) { s_handler_ = handler; }
+  static ExceptionHandler handler() { return s_handler_; }
+  /// @}
+
+ private:
+  /// Our SEH frame
+  EXCEPTION_REGISTRATION registration_;
+
+  /// The function that gets invoked if an exception
+  /// propagates through a barrier
+  /// TODO(omaha): how can this be statically parametrized?
+  static ExceptionHandler s_handler_;
+};
+
+/// @name These are implemented in the associated .asm file
+/// @{
+extern "C" void WINAPI RegisterExceptionRecord(
+                          EXCEPTION_REGISTRATION *registration,
+                          ExceptionHandlerFunc func);
+extern "C" void WINAPI UnregisterExceptionRecord(
+                          EXCEPTION_REGISTRATION *registration);
+/// @}
+
+
+inline ExceptionBarrier::ExceptionBarrier() {
+  RegisterExceptionRecord(&registration_, ExceptionBarrierHandler);
+}
+
+inline ExceptionBarrier::~ExceptionBarrier() {
+  // TODO(omaha): I don't think it's safe to unregister after an exception
+  //          has taken place???
+  UnregisterExceptionRecord(&registration_);
+}
+
+#endif  // OMAHA_COMMON_EXCEPTION_BARRIER_H_
diff --git a/common/exception_barrier_lowlevel.asm b/common/exception_barrier_lowlevel.asm
index 5d5fd4a..0906b92 100644
--- a/common/exception_barrier_lowlevel.asm
+++ b/common/exception_barrier_lowlevel.asm
@@ -1,63 +1,63 @@
-; Copyright 2006-2009 Google Inc.

-;

-; Licensed under the Apache License, Version 2.0 (the "License");

-; you may not use this file except in compliance with the License.

-; You may obtain a copy of the License at

-;

-;      http://www.apache.org/licenses/LICENSE-2.0

-;

-; Unless required by applicable law or agreed to in writing, software

-; distributed under the License is distributed on an "AS IS" BASIS,

-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-; See the License for the specific language governing permissions and

-; limitations under the License.

-; ========================================================================

-;

-; Tag the exception handler as an SEH handler in case the executable

-; is linked with /SAFESEH (which is the default).

-;

-; MASM 8.0 inserts an additional leading underscore in front of names

-; and this is an attempted fix until we understand why.

-IF @version LT 800

-_ExceptionBarrierHandler PROTO

-.SAFESEH _ExceptionBarrierHandler

-ELSE

-ExceptionBarrierHandler PROTO

-.SAFESEH ExceptionBarrierHandler

-ENDIF

-

-.586

-.MODEL FLAT, STDCALL

-ASSUME FS:NOTHING

-.CODE

-

-; extern "C" void WINAPI RegisterExceptionRecord(

-;                          EXCEPTION_REGISTRATION *registration,

-;                          ExceptionHandlerFunc func);

-RegisterExceptionRecord PROC registration:DWORD, func:DWORD

-OPTION PROLOGUE:None

-OPTION EPILOGUE:None

-  mov   edx, DWORD PTR [esp + 4]  ; edx is registration

-  mov   eax, DWORD PTR [esp + 8] ; eax is func

-  mov   DWORD PTR [edx + 4], eax

-  mov   eax, FS:[0]

-  mov   DWORD PTR [edx], eax

-  mov   FS:[0], edx

-  ret   8

-

-RegisterExceptionRecord ENDP

-

-; extern "C" void UnregisterExceptionRecord(

-;                           EXCEPTION_REGISTRATION *registration);

-UnregisterExceptionRecord PROC registration:DWORD

-OPTION PROLOGUE:None

-OPTION EPILOGUE:None

-

-  mov   edx, DWORD PTR [esp + 4]

-  mov   eax, [edx]

-  mov   FS:[0], eax

-  ret   4

-

-UnregisterExceptionRecord ENDP

-

-END

+; Copyright 2006-2009 Google Inc.
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+; ========================================================================
+;
+; Tag the exception handler as an SEH handler in case the executable
+; is linked with /SAFESEH (which is the default).
+;
+; MASM 8.0 inserts an additional leading underscore in front of names
+; and this is an attempted fix until we understand why.
+IF @version LT 800
+_ExceptionBarrierHandler PROTO
+.SAFESEH _ExceptionBarrierHandler
+ELSE
+ExceptionBarrierHandler PROTO
+.SAFESEH ExceptionBarrierHandler
+ENDIF
+
+.586
+.MODEL FLAT, STDCALL
+ASSUME FS:NOTHING
+.CODE
+
+; extern "C" void WINAPI RegisterExceptionRecord(
+;                          EXCEPTION_REGISTRATION *registration,
+;                          ExceptionHandlerFunc func);
+RegisterExceptionRecord PROC registration:DWORD, func:DWORD
+OPTION PROLOGUE:None
+OPTION EPILOGUE:None
+  mov   edx, DWORD PTR [esp + 4]  ; edx is registration
+  mov   eax, DWORD PTR [esp + 8] ; eax is func
+  mov   DWORD PTR [edx + 4], eax
+  mov   eax, FS:[0]
+  mov   DWORD PTR [edx], eax
+  mov   FS:[0], edx
+  ret   8
+
+RegisterExceptionRecord ENDP
+
+; extern "C" void UnregisterExceptionRecord(
+;                           EXCEPTION_REGISTRATION *registration);
+UnregisterExceptionRecord PROC registration:DWORD
+OPTION PROLOGUE:None
+OPTION EPILOGUE:None
+
+  mov   edx, DWORD PTR [esp + 4]
+  mov   eax, [edx]
+  mov   FS:[0], eax
+  ret   4
+
+UnregisterExceptionRecord ENDP
+
+END
diff --git a/common/exception_utils.cc b/common/exception_utils.cc
index 4a70577..56af779 100644
--- a/common/exception_utils.cc
+++ b/common/exception_utils.cc
@@ -1,86 +1,86 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "exception_utils.h"

-

-

-// Capture a CONTEXT that represents machine state at callsite

-// TODO(omaha): 64 bit platforms can pass through to

-//      RtlCaptureContext (or can they?)

-__declspec(naked) PCONTEXT WINAPI CaptureContext(PCONTEXT runner) {

-  runner;   // unreferenced formal parameter

-  __asm {

-    // set up a call frame

-    push ebp

-    mov ebp, esp

-

-    // save ecx for later

-    push ecx

-

-    // fetch the context record pointer argument into ecx

-    // which we use as pointer to context throughout the rest

-    // of this function

-    mov ecx, DWORD PTR [ebp + 8]

-

-    // set flags

-    mov [ecx]CONTEXT.ContextFlags, CONTEXT_SEGMENTS | CONTEXT_INTEGER | \

-                                   CONTEXT_CONTROL | CONTEXT_FLOATING_POINT

-

-    // stash the integer registers away

-    mov [ecx]CONTEXT.Edi, edi

-    mov [ecx]CONTEXT.Ebx, ebx

-    mov [ecx]CONTEXT.Edx, edx

-    mov [ecx]CONTEXT.Eax, eax

-    mov [ecx]CONTEXT.Esi, esi

-    // get the saved ecx

-    pop eax

-    mov [ecx]CONTEXT.Ecx, eax

-

-    // now control registers

-    pushfd

-    pop eax

-    mov [ecx]CONTEXT.EFlags, eax

-

-    // get the old ebp, our FP points to it

-    mov eax, [ebp]

-    mov [ecx]CONTEXT.Ebp, eax

-

-    // get return address and record as eip

-    mov eax, [ebp + 4]

-    mov [ecx]CONTEXT.Eip, eax

-

-    // esp post-return is ...

-    lea eax, [ebp + 0xC]

-    mov [ecx]CONTEXT.Esp, eax

-

-    // snarf segment registers

-    mov word ptr [ecx]CONTEXT.SegSs, ss

-    mov word ptr [ecx]CONTEXT.SegCs, cs

-    mov word ptr [ecx]CONTEXT.SegGs, gs

-    mov word ptr [ecx]CONTEXT.SegFs, fs

-    mov word ptr [ecx]CONTEXT.SegEs, es

-    mov word ptr [ecx]CONTEXT.SegDs, ds

-

-    // and lastly grab floating point state

-    fnsave [ecx]CONTEXT.FloatSave

-

-    // return the CONTEXT pointer

-    mov eax, ecx

-

-    // and return

-    pop ebp

-    ret 4

-  }

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "exception_utils.h"
+
+
+// Capture a CONTEXT that represents machine state at callsite
+// TODO(omaha): 64 bit platforms can pass through to
+//      RtlCaptureContext (or can they?)
+__declspec(naked) PCONTEXT WINAPI CaptureContext(PCONTEXT runner) {
+  runner;   // unreferenced formal parameter
+  __asm {
+    // set up a call frame
+    push ebp
+    mov ebp, esp
+
+    // save ecx for later
+    push ecx
+
+    // fetch the context record pointer argument into ecx
+    // which we use as pointer to context throughout the rest
+    // of this function
+    mov ecx, DWORD PTR [ebp + 8]
+
+    // set flags
+    mov [ecx]CONTEXT.ContextFlags, CONTEXT_SEGMENTS | CONTEXT_INTEGER | \
+                                   CONTEXT_CONTROL | CONTEXT_FLOATING_POINT
+
+    // stash the integer registers away
+    mov [ecx]CONTEXT.Edi, edi
+    mov [ecx]CONTEXT.Ebx, ebx
+    mov [ecx]CONTEXT.Edx, edx
+    mov [ecx]CONTEXT.Eax, eax
+    mov [ecx]CONTEXT.Esi, esi
+    // get the saved ecx
+    pop eax
+    mov [ecx]CONTEXT.Ecx, eax
+
+    // now control registers
+    pushfd
+    pop eax
+    mov [ecx]CONTEXT.EFlags, eax
+
+    // get the old ebp, our FP points to it
+    mov eax, [ebp]
+    mov [ecx]CONTEXT.Ebp, eax
+
+    // get return address and record as eip
+    mov eax, [ebp + 4]
+    mov [ecx]CONTEXT.Eip, eax
+
+    // esp post-return is ...
+    lea eax, [ebp + 0xC]
+    mov [ecx]CONTEXT.Esp, eax
+
+    // snarf segment registers
+    mov word ptr [ecx]CONTEXT.SegSs, ss
+    mov word ptr [ecx]CONTEXT.SegCs, cs
+    mov word ptr [ecx]CONTEXT.SegGs, gs
+    mov word ptr [ecx]CONTEXT.SegFs, fs
+    mov word ptr [ecx]CONTEXT.SegEs, es
+    mov word ptr [ecx]CONTEXT.SegDs, ds
+
+    // and lastly grab floating point state
+    fnsave [ecx]CONTEXT.FloatSave
+
+    // return the CONTEXT pointer
+    mov eax, ecx
+
+    // and return
+    pop ebp
+    ret 4
+  }
+}
diff --git a/common/exception_utils.h b/common/exception_utils.h
index e170433..9ee9005 100644
--- a/common/exception_utils.h
+++ b/common/exception_utils.h
@@ -1,25 +1,25 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Utility functions for crash reporting

-#ifndef OMAHA_COMMON_EXCEPTION_UTILS_H_

-#define OMAHA_COMMON_EXCEPTION_UTILS_H_

-

-#include <windows.h>

-

-/// Captures machine state at callsite.

-PCONTEXT WINAPI CaptureContext(PCONTEXT runner);

-

-#endif  // OMAHA_COMMON_EXCEPTION_UTILS_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Utility functions for crash reporting
+#ifndef OMAHA_COMMON_EXCEPTION_UTILS_H_
+#define OMAHA_COMMON_EXCEPTION_UTILS_H_
+
+#include <windows.h>
+
+/// Captures machine state at callsite.
+PCONTEXT WINAPI CaptureContext(PCONTEXT runner);
+
+#endif  // OMAHA_COMMON_EXCEPTION_UTILS_H_
diff --git a/common/extractor.cc b/common/extractor.cc
index 0e31df6..a315ab5 100644
--- a/common/extractor.cc
+++ b/common/extractor.cc
@@ -1,257 +1,257 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/extractor.h"

-

-#include <windows.h>

-#include <wintrust.h>

-#include <crtdbg.h>

-#pragma warning(push)

-// C4100: unreferenced formal parameter

-// C4310: cast truncates constant value

-// C4548: expression before comma has no effect

-#pragma warning(disable : 4100 4310 4548)

-#include "base/basictypes.h"

-#pragma warning(pop)

-

-namespace omaha {

-

-#define AFFILIATE_ID_MAGIC "Gact"

-

-TagExtractor::TagExtractor()

-    : file_handle_(INVALID_HANDLE_VALUE),

-      file_mapping_(NULL),

-      file_base_(NULL),

-      file_length_(0),

-      cert_length_(0),

-      cert_dir_base_(NULL) {

-}

-

-TagExtractor::~TagExtractor() {

-  CloseFile();

-}

-

-bool TagExtractor::OpenFile(const TCHAR* filename) {

-  CloseFile();

-  file_handle_ = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,

-    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

-  if (IsFileOpen()) {

-    file_mapping_ = CreateFileMapping(file_handle_, NULL, PAGE_READONLY,

-      0, 0, NULL);

-    if (file_mapping_ != NULL) {

-      file_base_ = MapViewOfFile(file_mapping_, FILE_MAP_READ, 0, 0, 0);

-      if (file_base_ != NULL) {

-        MEMORY_BASIC_INFORMATION info = {0};

-        if (::VirtualQuery(file_base_, &info, sizeof(info))) {

-          file_length_ = info.RegionSize;

-          return true;

-        }

-      }

-      CloseHandle(file_mapping_);

-    }

-    CloseFile();

-  }

-  return false;

-}

-

-bool TagExtractor::IsFileOpen() const {

-  return file_handle_ != INVALID_HANDLE_VALUE;

-}

-

-void TagExtractor::CloseFile() {

-  if (file_base_ != NULL) {

-    UnmapViewOfFile(file_base_);

-    file_base_ = NULL;

-  }

-  if (file_mapping_ != NULL) {

-    CloseHandle(file_mapping_);

-    file_mapping_ = NULL;

-  }

-  if (IsFileOpen()) {

-    CloseHandle(file_handle_);

-    file_handle_ = INVALID_HANDLE_VALUE;

-  }

-}

-

-bool TagExtractor::ExtractTag(const char* binary_file,

-                              size_t binary_file_length,

-                              char* tag_buffer,

-                              int* tag_buffer_len) {

-  file_length_ = binary_file_length;

-  return InternalExtractTag(binary_file, tag_buffer, tag_buffer_len);

-}

-

-bool TagExtractor::ExtractTag(char* tag_buffer, int* tag_buffer_len) {

-  if (tag_buffer_len == NULL) {

-    return false;

-  }

-  if (!IsFileOpen()) {

-    return false;

-  }

-

-  return InternalExtractTag(static_cast<char*>(file_base_),

-                            tag_buffer,

-                            tag_buffer_len);

-}

-

-bool TagExtractor::InternalReadCertificate(const char* file_buffer) {

-  if (!file_buffer) {

-    return false;

-  }

-

-  const void* certificate_directory_pointer =

-    GetCertificateDirectoryPointer(file_buffer);

-  if (NULL == certificate_directory_pointer) {

-    return false;

-  }

-  const void* asn1_signature_pointer =

-    GetASN1SignaturePointer(certificate_directory_pointer);

-  if (NULL == asn1_signature_pointer) {

-    return false;

-  }

-  DWORD asn1_signature_length =

-    GetASN1SignatureLength(asn1_signature_pointer);

-  if (0 == asn1_signature_length) {

-    return false;

-  }

-

-  cert_length_ = asn1_signature_length;

-  cert_dir_base_ = certificate_directory_pointer;

-

-  return true;

-}

-

-bool TagExtractor::InternalExtractTag(const char* file_buffer,

-                                      char* tag_buffer,

-                                      int* tag_buffer_len) {

-  if (!file_buffer) {

-    return false;

-  }

-

-  if (!InternalReadCertificate(file_buffer)) {

-    return false;

-  }

-

-  const char* read_base = static_cast<const char*>(cert_dir_base_) +

-                          cert_length_;

-  if (read_base >= file_buffer + file_length_) {

-    // The file is not tagged.

-    return false;

-  }

-

-  return ReadTag(read_base, tag_buffer, tag_buffer_len);

-}

-

-bool TagExtractor::ReadTag(const char* tag_pointer,

-                           char* tag_buffer,

-                           int* tag_buffer_len) const {

-  int mc = memcmp(tag_pointer,

-                  AFFILIATE_ID_MAGIC,

-                  arraysize(AFFILIATE_ID_MAGIC) - 1);

-  if (0 != mc) {

-    return false;

-  }

-  tag_pointer += arraysize(AFFILIATE_ID_MAGIC) - 1;

-

-  uint16 id_len = 0;

-  const unsigned char* id_len_serialized =

-    reinterpret_cast<const unsigned char*>(tag_pointer);

-  id_len = id_len_serialized[0] << 8;

-  // unsigned char and uint16 get promoted to int.

-  id_len = static_cast<uint16>(id_len + id_len_serialized[1]);

-

-  int buffer_size_required = id_len + 1;

-  if (tag_buffer == NULL) {

-    *tag_buffer_len = buffer_size_required;

-    return true;

-  }

-  if (*tag_buffer_len < buffer_size_required) {

-    return false;

-  }

-  tag_pointer += sizeof(id_len);

-  memcpy(tag_buffer, tag_pointer, id_len);

-  tag_buffer[id_len] = '\0';

-  return true;

-}

-

-const void* TagExtractor::GetCertificateDirectoryPointer(

-    const void* base) const {

-  const char* image_base = reinterpret_cast<const char*>(base);

-

-  // Is this a PEF?

-  const IMAGE_DOS_HEADER* dos_header =

-    reinterpret_cast<const IMAGE_DOS_HEADER *>(image_base);

-  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {

-    return NULL;

-  }

-

-  // Get PE header.

-  const IMAGE_NT_HEADERS* nt_headers = reinterpret_cast<const IMAGE_NT_HEADERS*>

-      (image_base + dos_header->e_lfanew);

-

-  // Again, is this a PEF? This code should get an F for not being endian-

-  // safe, but it gets an A for working in the real world.

-  if (nt_headers->Signature != IMAGE_NT_SIGNATURE) {

-    return NULL;

-  }

-

-  const IMAGE_DATA_DIRECTORY* idd =

-    reinterpret_cast<const IMAGE_DATA_DIRECTORY *>

-    (&nt_headers->

-    OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);

-  if (idd->VirtualAddress != NULL) {

-    return image_base + idd->VirtualAddress;

-  }

-  return NULL;

-}

-

-const void* TagExtractor::GetASN1SignaturePointer(const void* base) const {

-  const WIN_CERTIFICATE* cert =

-    reinterpret_cast<const WIN_CERTIFICATE *>(base);

-  return cert->bCertificate;

-}

-

-int TagExtractor::GetASN1SignatureLength(const void* base) const {

-  const unsigned char* sig_base =

-    reinterpret_cast<const unsigned char*>(base);

-

-  // No, this isn't a full ASN.1 parser. We're just doing the very bare

-  // minimum to extract a length.

-  if (*sig_base++ == 0x30 && *sig_base++ == 0x82) {

-    int len = (*sig_base++ << 8);

-    len += *sig_base++;

-    // Windows pads the certificate directory to align at a 8-byte boundary.

-    // This piece of code it trying to replicate the logic that is used to

-    // calculate the padding to be added to the certificate. It returns

-    // the entire length of the certificate directory from the windows

-    // certificate directory start to the end of padding.

-    // The windows certificate directory has the following structure

-    // <WIN_CERTIFICATE><Certificate><Padding>.

-    // WIN_CERTIFICATE is the windows certificate directory structure.

-    // <Certificate> has the following format:

-    // <Magic(2 bytes)><Cert length(2 bytes)><Certificate Data>

-    // Note that the "Cert length" does not include the magic bytes or

-    // the length.

-    //

-    // Hence the total length of the certificate is:

-    // cert_length + "WIN_CERTIFICATE header size" + magic + length

-    // + padding = (cert length + 8 + 2 + 2 + 7) & (0-8)

-    return (len + 8 + 2 + 2 + 7) & 0xffffff8;

-  }

-  return 0;

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/extractor.h"
+
+#include <windows.h>
+#include <wintrust.h>
+#include <crtdbg.h>
+#pragma warning(push)
+// C4100: unreferenced formal parameter
+// C4310: cast truncates constant value
+// C4548: expression before comma has no effect
+#pragma warning(disable : 4100 4310 4548)
+#include "base/basictypes.h"
+#pragma warning(pop)
+
+namespace omaha {
+
+#define AFFILIATE_ID_MAGIC "Gact"
+
+TagExtractor::TagExtractor()
+    : file_handle_(INVALID_HANDLE_VALUE),
+      file_mapping_(NULL),
+      file_base_(NULL),
+      file_length_(0),
+      cert_length_(0),
+      cert_dir_base_(NULL) {
+}
+
+TagExtractor::~TagExtractor() {
+  CloseFile();
+}
+
+bool TagExtractor::OpenFile(const TCHAR* filename) {
+  CloseFile();
+  file_handle_ = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+  if (IsFileOpen()) {
+    file_mapping_ = CreateFileMapping(file_handle_, NULL, PAGE_READONLY,
+      0, 0, NULL);
+    if (file_mapping_ != NULL) {
+      file_base_ = MapViewOfFile(file_mapping_, FILE_MAP_READ, 0, 0, 0);
+      if (file_base_ != NULL) {
+        MEMORY_BASIC_INFORMATION info = {0};
+        if (::VirtualQuery(file_base_, &info, sizeof(info))) {
+          file_length_ = info.RegionSize;
+          return true;
+        }
+      }
+      CloseHandle(file_mapping_);
+    }
+    CloseFile();
+  }
+  return false;
+}
+
+bool TagExtractor::IsFileOpen() const {
+  return file_handle_ != INVALID_HANDLE_VALUE;
+}
+
+void TagExtractor::CloseFile() {
+  if (file_base_ != NULL) {
+    UnmapViewOfFile(file_base_);
+    file_base_ = NULL;
+  }
+  if (file_mapping_ != NULL) {
+    CloseHandle(file_mapping_);
+    file_mapping_ = NULL;
+  }
+  if (IsFileOpen()) {
+    CloseHandle(file_handle_);
+    file_handle_ = INVALID_HANDLE_VALUE;
+  }
+}
+
+bool TagExtractor::ExtractTag(const char* binary_file,
+                              size_t binary_file_length,
+                              char* tag_buffer,
+                              int* tag_buffer_len) {
+  file_length_ = binary_file_length;
+  return InternalExtractTag(binary_file, tag_buffer, tag_buffer_len);
+}
+
+bool TagExtractor::ExtractTag(char* tag_buffer, int* tag_buffer_len) {
+  if (tag_buffer_len == NULL) {
+    return false;
+  }
+  if (!IsFileOpen()) {
+    return false;
+  }
+
+  return InternalExtractTag(static_cast<char*>(file_base_),
+                            tag_buffer,
+                            tag_buffer_len);
+}
+
+bool TagExtractor::InternalReadCertificate(const char* file_buffer) {
+  if (!file_buffer) {
+    return false;
+  }
+
+  const void* certificate_directory_pointer =
+    GetCertificateDirectoryPointer(file_buffer);
+  if (NULL == certificate_directory_pointer) {
+    return false;
+  }
+  const void* asn1_signature_pointer =
+    GetASN1SignaturePointer(certificate_directory_pointer);
+  if (NULL == asn1_signature_pointer) {
+    return false;
+  }
+  DWORD asn1_signature_length =
+    GetASN1SignatureLength(asn1_signature_pointer);
+  if (0 == asn1_signature_length) {
+    return false;
+  }
+
+  cert_length_ = asn1_signature_length;
+  cert_dir_base_ = certificate_directory_pointer;
+
+  return true;
+}
+
+bool TagExtractor::InternalExtractTag(const char* file_buffer,
+                                      char* tag_buffer,
+                                      int* tag_buffer_len) {
+  if (!file_buffer) {
+    return false;
+  }
+
+  if (!InternalReadCertificate(file_buffer)) {
+    return false;
+  }
+
+  const char* read_base = static_cast<const char*>(cert_dir_base_) +
+                          cert_length_;
+  if (read_base >= file_buffer + file_length_) {
+    // The file is not tagged.
+    return false;
+  }
+
+  return ReadTag(read_base, tag_buffer, tag_buffer_len);
+}
+
+bool TagExtractor::ReadTag(const char* tag_pointer,
+                           char* tag_buffer,
+                           int* tag_buffer_len) const {
+  int mc = memcmp(tag_pointer,
+                  AFFILIATE_ID_MAGIC,
+                  arraysize(AFFILIATE_ID_MAGIC) - 1);
+  if (0 != mc) {
+    return false;
+  }
+  tag_pointer += arraysize(AFFILIATE_ID_MAGIC) - 1;
+
+  uint16 id_len = 0;
+  const unsigned char* id_len_serialized =
+    reinterpret_cast<const unsigned char*>(tag_pointer);
+  id_len = id_len_serialized[0] << 8;
+  // unsigned char and uint16 get promoted to int.
+  id_len = static_cast<uint16>(id_len + id_len_serialized[1]);
+
+  int buffer_size_required = id_len + 1;
+  if (tag_buffer == NULL) {
+    *tag_buffer_len = buffer_size_required;
+    return true;
+  }
+  if (*tag_buffer_len < buffer_size_required) {
+    return false;
+  }
+  tag_pointer += sizeof(id_len);
+  memcpy(tag_buffer, tag_pointer, id_len);
+  tag_buffer[id_len] = '\0';
+  return true;
+}
+
+const void* TagExtractor::GetCertificateDirectoryPointer(
+    const void* base) const {
+  const char* image_base = reinterpret_cast<const char*>(base);
+
+  // Is this a PEF?
+  const IMAGE_DOS_HEADER* dos_header =
+    reinterpret_cast<const IMAGE_DOS_HEADER *>(image_base);
+  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
+    return NULL;
+  }
+
+  // Get PE header.
+  const IMAGE_NT_HEADERS* nt_headers = reinterpret_cast<const IMAGE_NT_HEADERS*>
+      (image_base + dos_header->e_lfanew);
+
+  // Again, is this a PEF? This code should get an F for not being endian-
+  // safe, but it gets an A for working in the real world.
+  if (nt_headers->Signature != IMAGE_NT_SIGNATURE) {
+    return NULL;
+  }
+
+  const IMAGE_DATA_DIRECTORY* idd =
+    reinterpret_cast<const IMAGE_DATA_DIRECTORY *>
+    (&nt_headers->
+    OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);
+  if (idd->VirtualAddress != NULL) {
+    return image_base + idd->VirtualAddress;
+  }
+  return NULL;
+}
+
+const void* TagExtractor::GetASN1SignaturePointer(const void* base) const {
+  const WIN_CERTIFICATE* cert =
+    reinterpret_cast<const WIN_CERTIFICATE *>(base);
+  return cert->bCertificate;
+}
+
+int TagExtractor::GetASN1SignatureLength(const void* base) const {
+  const unsigned char* sig_base =
+    reinterpret_cast<const unsigned char*>(base);
+
+  // No, this isn't a full ASN.1 parser. We're just doing the very bare
+  // minimum to extract a length.
+  if (*sig_base++ == 0x30 && *sig_base++ == 0x82) {
+    int len = (*sig_base++ << 8);
+    len += *sig_base++;
+    // Windows pads the certificate directory to align at a 8-byte boundary.
+    // This piece of code it trying to replicate the logic that is used to
+    // calculate the padding to be added to the certificate. It returns
+    // the entire length of the certificate directory from the windows
+    // certificate directory start to the end of padding.
+    // The windows certificate directory has the following structure
+    // <WIN_CERTIFICATE><Certificate><Padding>.
+    // WIN_CERTIFICATE is the windows certificate directory structure.
+    // <Certificate> has the following format:
+    // <Magic(2 bytes)><Cert length(2 bytes)><Certificate Data>
+    // Note that the "Cert length" does not include the magic bytes or
+    // the length.
+    //
+    // Hence the total length of the certificate is:
+    // cert_length + "WIN_CERTIFICATE header size" + magic + length
+    // + padding = (cert length + 8 + 2 + 2 + 7) & (0-8)
+    return (len + 8 + 2 + 2 + 7) & 0xffffff8;
+  }
+  return 0;
+}
+
+}  // namespace omaha
+
diff --git a/common/extractor.h b/common/extractor.h
index abefd57..21a8def 100644
--- a/common/extractor.h
+++ b/common/extractor.h
@@ -1,105 +1,105 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_COMMON_EXTRACTOR_H_

-#define OMAHA_COMMON_EXTRACTOR_H_

-

-#include <windows.h>

-

-namespace omaha {

-

-class TagExtractor {

- public:

-  TagExtractor();

-  virtual ~TagExtractor();

-

-    /**

-    * @return true if we successfully opened the file.

-    */

-    bool OpenFile(const TCHAR* filename);

-

-    /**

-    * @return true if we currently have a handle to an open file.

-    */

-    bool IsFileOpen() const;

-

-    void CloseFile();

-

-    /**

-    * Returns the tag in the current file.

-    *

-    * We're exploiting the empirical observation that Windows checks the

-    * signature on a PEF but doesn't care if the signature container includes

-    * extra bytes after the signature.

-    *

-    * Logic:

-    *

-    *   - Sanity-check that we're a PEF image.

-    *   - Find the signature, which should be stored in the PE "Certificates

-    *     Directory" (dumpbin.exe /headers "Firefox Setup 1.0.7.exe") in a

-    *     WIN_CERTIFICATE structure.

-    *   - Crudely parse the ASN.1 signature to determine its end.

-    *   - Read the signature starting from the first byte past the ASN.1.

-    *

-    * @param tag_buffer: a buffer that will be filled with the extracted tag as

-    *   a null-terminated string, or NULL if the caller doesn't want the tag.

-    *

-    * @param tag_buffer_len: a pointer to an int that represents the length in

-    *   bytes of the buffer pointed to by tag_buffer. If tag_buffer is NULL and

-    *   there is a tag to extract, then we fill this int with the size of the

-    *   smallest buffer needed to contain the tag (plus the null terminator).

-    *

-    * @return true if we found a tag and either successfully copied all of it

-    *   into tag_buffer, or tag_buffer was NULL and we successfully returned

-    *   the required buffer size in tag_buffer_len.

-    */

-    bool ExtractTag(char* tag_buffer, int* tag_buffer_len);

-    bool ExtractTag(const char* binary_file,

-                    size_t binary_file_length,

-                    char* tag_buffer,

-                    int* tag_buffer_len);

-

-    int cert_length() const { return cert_length_; }

-    const void* cert_dir_base() const { return cert_dir_base_; }

-

- private:

-  HANDLE file_handle_;

-  HANDLE file_mapping_;

-  LPVOID file_base_;

-  size_t file_length_;

-  int cert_length_;

-  const void* cert_dir_base_;

-

-  bool ReadTag(const char* tag_pointer,

-               char* tag_buffer,

-               int* tag_buffer_len) const;

-

-  const void* GetCertificateDirectoryPointer(const void* base) const;

-

-  const void* GetASN1SignaturePointer(const void* base) const;

-

-  int GetASN1SignatureLength(const void* base) const;

-

-  bool InternalExtractTag(const char* file_buffer,

-                          char* tag_buffer,

-                          int* tag_buffer_len);

-

-  bool InternalReadCertificate(const char* file_buffer);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_EXTRACTOR_H_

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_COMMON_EXTRACTOR_H_
+#define OMAHA_COMMON_EXTRACTOR_H_
+
+#include <windows.h>
+
+namespace omaha {
+
+class TagExtractor {
+ public:
+  TagExtractor();
+  virtual ~TagExtractor();
+
+    /**
+    * @return true if we successfully opened the file.
+    */
+    bool OpenFile(const TCHAR* filename);
+
+    /**
+    * @return true if we currently have a handle to an open file.
+    */
+    bool IsFileOpen() const;
+
+    void CloseFile();
+
+    /**
+    * Returns the tag in the current file.
+    *
+    * We're exploiting the empirical observation that Windows checks the
+    * signature on a PEF but doesn't care if the signature container includes
+    * extra bytes after the signature.
+    *
+    * Logic:
+    *
+    *   - Sanity-check that we're a PEF image.
+    *   - Find the signature, which should be stored in the PE "Certificates
+    *     Directory" (dumpbin.exe /headers "Firefox Setup 1.0.7.exe") in a
+    *     WIN_CERTIFICATE structure.
+    *   - Crudely parse the ASN.1 signature to determine its end.
+    *   - Read the signature starting from the first byte past the ASN.1.
+    *
+    * @param tag_buffer: a buffer that will be filled with the extracted tag as
+    *   a null-terminated string, or NULL if the caller doesn't want the tag.
+    *
+    * @param tag_buffer_len: a pointer to an int that represents the length in
+    *   bytes of the buffer pointed to by tag_buffer. If tag_buffer is NULL and
+    *   there is a tag to extract, then we fill this int with the size of the
+    *   smallest buffer needed to contain the tag (plus the null terminator).
+    *
+    * @return true if we found a tag and either successfully copied all of it
+    *   into tag_buffer, or tag_buffer was NULL and we successfully returned
+    *   the required buffer size in tag_buffer_len.
+    */
+    bool ExtractTag(char* tag_buffer, int* tag_buffer_len);
+    bool ExtractTag(const char* binary_file,
+                    size_t binary_file_length,
+                    char* tag_buffer,
+                    int* tag_buffer_len);
+
+    int cert_length() const { return cert_length_; }
+    const void* cert_dir_base() const { return cert_dir_base_; }
+
+ private:
+  HANDLE file_handle_;
+  HANDLE file_mapping_;
+  LPVOID file_base_;
+  size_t file_length_;
+  int cert_length_;
+  const void* cert_dir_base_;
+
+  bool ReadTag(const char* tag_pointer,
+               char* tag_buffer,
+               int* tag_buffer_len) const;
+
+  const void* GetCertificateDirectoryPointer(const void* base) const;
+
+  const void* GetASN1SignaturePointer(const void* base) const;
+
+  int GetASN1SignatureLength(const void* base) const;
+
+  bool InternalExtractTag(const char* file_buffer,
+                          char* tag_buffer,
+                          int* tag_buffer_len);
+
+  bool InternalReadCertificate(const char* file_buffer);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_EXTRACTOR_H_
diff --git a/common/extractor_unittest.cc b/common/extractor_unittest.cc
index 1440759..754a3f2 100644
--- a/common/extractor_unittest.cc
+++ b/common/extractor_unittest.cc
@@ -1,261 +1,261 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Unit test for the extractor and the ApplyTag class.

-//

-// TODO(omaha): eliminate the dependency on the hardcoded "GoogleUpdate.exe"

-// program name.

-

-#include <shlobj.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/apply_tag.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/extractor.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-const TCHAR kFilePath[] = _T(".");

-const TCHAR kFileName[] = _T("GoogleUpdate.exe");

-const char kTagString[] = "1234567890abcdefg";

-const char kAppendTagString[] = "..AppendedStr";

-

-TEST(ExtractorTest, EmbedExtract) {

-  // Test the extractor.

-  TagExtractor extractor;

-  ASSERT_FALSE(extractor.IsFileOpen());

-

-  CString signed_exe_file;

-  signed_exe_file.Format(_T("%s\\%s\\%s"),

-                         app_util::GetCurrentModuleDirectory(),

-                         kFilePath, kFileName);

-  ASSERT_TRUE(extractor.OpenFile(signed_exe_file));

-

-  // No tag string in the original exe file.

-  int tag_buffer_size = 0;

-  ASSERT_FALSE(extractor.ExtractTag(NULL, &tag_buffer_size));

-  ASSERT_EQ(tag_buffer_size, 0);

-  extractor.CloseFile();

-

-  // Create a temp dir.

-  TCHAR temp_path[MAX_PATH] = {0};

-  *temp_path = 0;

-  ASSERT_NE(::GetTempPath(MAX_PATH, temp_path), 0);

-

-  // Embed the tag string.

-  CString tagged_file;

-  tagged_file.Format(_T("%s%s"), temp_path, kFileName);

-  omaha::ApplyTag tag;

-  ASSERT_HRESULT_SUCCEEDED(tag.Init(signed_exe_file,

-                                    kTagString,

-                                    strlen(kTagString),

-                                    tagged_file,

-                                    false));

-// TODO(omaha): Remove the ifdef when signing occurs after instrumentation.

-#ifdef COVERAGE_ENABLED

-  std::wcout << _T("\tTest does not run in coverage builds.") << std::endl;

-#else

-  ASSERT_SUCCEEDED(tag.EmbedTagString());

-  ON_SCOPE_EXIT(::DeleteFile, tagged_file);

-

-  // Extract the tag string.

-  tag_buffer_size = 0;

-  ASSERT_TRUE(extractor.OpenFile(tagged_file));

-  ASSERT_TRUE(extractor.ExtractTag(NULL, &tag_buffer_size));

-  ASSERT_EQ(tag_buffer_size, arraysize(kTagString));

-

-  char tag_buffer[arraysize(kTagString)] = {0};

-  ASSERT_TRUE(extractor.ExtractTag(tag_buffer, &tag_buffer_size));

-  ASSERT_EQ(tag_buffer_size, arraysize(kTagString));

-  ASSERT_EQ(memcmp(tag_buffer, kTagString, arraysize(kTagString)), 0);

-  extractor.CloseFile();

-#endif

-}

-

-TEST(ExtractorTest, EmbedAppendExtract) {

-  // Test the extractor.

-  TagExtractor extractor;

-  ASSERT_FALSE(extractor.IsFileOpen());

-

-  CString signed_exe_file;

-  signed_exe_file.Format(_T("%s\\%s\\%s"),

-                         app_util::GetCurrentModuleDirectory(),

-                         kFilePath, kFileName);

-  ASSERT_TRUE(extractor.OpenFile(signed_exe_file));

-

-  // No tag string in the original exe file.

-  int tag_buffer_size = 0;

-  ASSERT_FALSE(extractor.ExtractTag(NULL, &tag_buffer_size));

-// TODO(omaha): Remove the ifdef when signing occurs after instrumentation.

-#ifdef COVERAGE_ENABLED

-  std::wcout << _T("\tTest does not run in coverage builds.") << std::endl;

-#else

-  ASSERT_GT(extractor.cert_length(), 0);

-  ASSERT_EQ(tag_buffer_size, 0);

-  extractor.CloseFile();

-

-  // Create a temp dir.

-  TCHAR temp_path[MAX_PATH] = {0};

-  *temp_path = 0;

-  ASSERT_NE(::GetTempPath(MAX_PATH, temp_path), 0);

-

-  // Embed the tag string.

-  CString tagged_file;

-  tagged_file.Format(_T("%s%d%s"), temp_path, 1, kFileName);

-  omaha::ApplyTag tag;

-  ASSERT_HRESULT_SUCCEEDED(tag.Init(signed_exe_file,

-                                    kTagString,

-                                    strlen(kTagString),

-                                    tagged_file,

-                                    false));

-  ASSERT_SUCCEEDED(tag.EmbedTagString());

-  ON_SCOPE_EXIT(::DeleteFile, tagged_file);

-

-  // Append another tag string.

-  CString tagged_appended_file;

-  tagged_appended_file.Format(_T("%s%d%s"), temp_path, 2, kFileName);

-  omaha::ApplyTag tag1;

-

-  ASSERT_HRESULT_SUCCEEDED(tag1.Init(tagged_file,

-                                     kAppendTagString,

-                                     strlen(kAppendTagString),

-                                     tagged_appended_file,

-                                     true));

-  ASSERT_SUCCEEDED(tag1.EmbedTagString());

-  ON_SCOPE_EXIT(::DeleteFile, tagged_appended_file);

-

-  // Append another tag string.

-  CString tagged_appended_file2;

-  tagged_appended_file2.Format(_T("%s%d%s"), temp_path, 3, kFileName);

-  omaha::ApplyTag tag2;

-  ASSERT_HRESULT_SUCCEEDED(tag2.Init(tagged_appended_file,

-                                     kAppendTagString,

-                                     strlen(kAppendTagString),

-                                     tagged_appended_file2,

-                                     true));

-  ASSERT_SUCCEEDED(tag2.EmbedTagString());

-  ON_SCOPE_EXIT(::DeleteFile, tagged_appended_file2);

-

-  // Extract the tag string.

-  tag_buffer_size = 0;

-  CStringA expected_tag_string(kTagString);

-  expected_tag_string += kAppendTagString;

-  expected_tag_string += kAppendTagString;

-  int expected_tag_string_len = expected_tag_string.GetLength() + 1;

-  ASSERT_TRUE(extractor.OpenFile(tagged_appended_file2));

-  ASSERT_TRUE(extractor.ExtractTag(NULL, &tag_buffer_size));

-  ASSERT_EQ(tag_buffer_size, expected_tag_string_len);

-

-  scoped_array<char> tag_buffer(new char[expected_tag_string_len]);

-  ASSERT_TRUE(extractor.ExtractTag(tag_buffer.get(), &tag_buffer_size));

-  ASSERT_EQ(tag_buffer_size, expected_tag_string_len);

-  ASSERT_EQ(memcmp(tag_buffer.get(),

-                   expected_tag_string,

-                   expected_tag_string_len),

-            0);

-#endif

-  extractor.CloseFile();

-}

-

-TEST(ExtractorTest, AlreadyTaggedError) {

-  // Test the extractor.

-  TagExtractor extractor;

-  ASSERT_FALSE(extractor.IsFileOpen());

-

-  CString signed_exe_file;

-  signed_exe_file.Format(_T("%s\\%s\\%s"),

-                         app_util::GetCurrentModuleDirectory(),

-                         kFilePath, kFileName);

-  ASSERT_TRUE(extractor.OpenFile(signed_exe_file));

-

-  // No tag string in the original exe file.

-  int tag_buffer_size = 0;

-  ASSERT_FALSE(extractor.ExtractTag(NULL, &tag_buffer_size));

-// TODO(omaha): Remove the ifdef when signing occurs after instrumentation.

-#ifdef COVERAGE_ENABLED

-  std::wcout << _T("\tTest does not run in coverage builds.") << std::endl;

-#else

-  ASSERT_GT(extractor.cert_length(), 0);

-  ASSERT_EQ(tag_buffer_size, 0);

-  extractor.CloseFile();

-

-  // Create a temp dir.

-  TCHAR temp_path[MAX_PATH] = {0};

-  *temp_path = 0;

-  ASSERT_NE(::GetTempPath(MAX_PATH, temp_path), 0);

-

-  // Embed the tag string.

-  CString tagged_file;

-  tagged_file.Format(_T("%s%d%s"), temp_path, 1, kFileName);

-  omaha::ApplyTag tag1;

-  ASSERT_HRESULT_SUCCEEDED(tag1.Init(signed_exe_file,

-                                     kTagString,

-                                     strlen(kTagString),

-                                     tagged_file,

-                                     false));

-  ASSERT_SUCCEEDED(tag1.EmbedTagString());

-  ON_SCOPE_EXIT(::DeleteFile, tagged_file);

-

-  CString tagged_appended_file;

-  tagged_appended_file.Format(_T("%s%d%s"), temp_path, 2, kFileName);

-  omaha::ApplyTag tag2;

-  ASSERT_HRESULT_SUCCEEDED(tag2.Init(tagged_file,

-                                     kAppendTagString,

-                                     strlen(kAppendTagString),

-                                     tagged_appended_file,

-                                     false));

-  ASSERT_EQ(tag2.EmbedTagString(), APPLYTAG_E_ALREADY_TAGGED);

-  ON_SCOPE_EXIT(::DeleteFile, tagged_appended_file);

-#endif

-  extractor.CloseFile();

-}

-

-TEST(ApplyTagTest, InvalidCharsTest) {

-  // Accepted Regex = [-%{}/\a&=._]*

-  CString signed_exe_file;

-  signed_exe_file.Format(_T("%s\\%s\\%s"),

-                         app_util::GetCurrentModuleDirectory(),

-                         kFilePath, kFileName);

-  CString tagged_file(_T("out.txt"));

-

-  const char* const input_str = "abcd";

-  omaha::ApplyTag tag1;

-  ASSERT_HRESULT_SUCCEEDED(tag1.Init(signed_exe_file,

-                                     input_str,

-                                     strlen(input_str),

-                                     tagged_file,

-                                     false));

-

-  const char* const input_str2 = "abcd$%#";

-  omaha::ApplyTag tag2;

-  ASSERT_HRESULT_FAILED(tag2.Init(signed_exe_file,

-                                  input_str2,

-                                  strlen(input_str2),

-                                  tagged_file,

-                                  false));

-

-  const char* const input_str3 = "abcd asdf";

-  omaha::ApplyTag tag3;

-  ASSERT_HRESULT_FAILED(tag3.Init(signed_exe_file,

-                                  input_str3,

-                                  strlen(input_str3),

-                                  tagged_file,

-                                  false));

-}

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Unit test for the extractor and the ApplyTag class.
+//
+// TODO(omaha): eliminate the dependency on the hardcoded "GoogleUpdate.exe"
+// program name.
+
+#include <shlobj.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/apply_tag.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/extractor.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+const TCHAR kFilePath[] = _T(".");
+const TCHAR kFileName[] = _T("GoogleUpdate.exe");
+const char kTagString[] = "1234567890abcdefg";
+const char kAppendTagString[] = "..AppendedStr";
+
+TEST(ExtractorTest, EmbedExtract) {
+  // Test the extractor.
+  TagExtractor extractor;
+  ASSERT_FALSE(extractor.IsFileOpen());
+
+  CString signed_exe_file;
+  signed_exe_file.Format(_T("%s\\%s\\%s"),
+                         app_util::GetCurrentModuleDirectory(),
+                         kFilePath, kFileName);
+  ASSERT_TRUE(extractor.OpenFile(signed_exe_file));
+
+  // No tag string in the original exe file.
+  int tag_buffer_size = 0;
+  ASSERT_FALSE(extractor.ExtractTag(NULL, &tag_buffer_size));
+  ASSERT_EQ(tag_buffer_size, 0);
+  extractor.CloseFile();
+
+  // Create a temp dir.
+  TCHAR temp_path[MAX_PATH] = {0};
+  *temp_path = 0;
+  ASSERT_NE(::GetTempPath(MAX_PATH, temp_path), 0);
+
+  // Embed the tag string.
+  CString tagged_file;
+  tagged_file.Format(_T("%s%s"), temp_path, kFileName);
+  omaha::ApplyTag tag;
+  ASSERT_HRESULT_SUCCEEDED(tag.Init(signed_exe_file,
+                                    kTagString,
+                                    strlen(kTagString),
+                                    tagged_file,
+                                    false));
+// TODO(omaha): Remove the ifdef when signing occurs after instrumentation.
+#ifdef COVERAGE_ENABLED
+  std::wcout << _T("\tTest does not run in coverage builds.") << std::endl;
+#else
+  ASSERT_SUCCEEDED(tag.EmbedTagString());
+  ON_SCOPE_EXIT(::DeleteFile, tagged_file);
+
+  // Extract the tag string.
+  tag_buffer_size = 0;
+  ASSERT_TRUE(extractor.OpenFile(tagged_file));
+  ASSERT_TRUE(extractor.ExtractTag(NULL, &tag_buffer_size));
+  ASSERT_EQ(tag_buffer_size, arraysize(kTagString));
+
+  char tag_buffer[arraysize(kTagString)] = {0};
+  ASSERT_TRUE(extractor.ExtractTag(tag_buffer, &tag_buffer_size));
+  ASSERT_EQ(tag_buffer_size, arraysize(kTagString));
+  ASSERT_EQ(memcmp(tag_buffer, kTagString, arraysize(kTagString)), 0);
+  extractor.CloseFile();
+#endif
+}
+
+TEST(ExtractorTest, EmbedAppendExtract) {
+  // Test the extractor.
+  TagExtractor extractor;
+  ASSERT_FALSE(extractor.IsFileOpen());
+
+  CString signed_exe_file;
+  signed_exe_file.Format(_T("%s\\%s\\%s"),
+                         app_util::GetCurrentModuleDirectory(),
+                         kFilePath, kFileName);
+  ASSERT_TRUE(extractor.OpenFile(signed_exe_file));
+
+  // No tag string in the original exe file.
+  int tag_buffer_size = 0;
+  ASSERT_FALSE(extractor.ExtractTag(NULL, &tag_buffer_size));
+// TODO(omaha): Remove the ifdef when signing occurs after instrumentation.
+#ifdef COVERAGE_ENABLED
+  std::wcout << _T("\tTest does not run in coverage builds.") << std::endl;
+#else
+  ASSERT_GT(extractor.cert_length(), 0);
+  ASSERT_EQ(tag_buffer_size, 0);
+  extractor.CloseFile();
+
+  // Create a temp dir.
+  TCHAR temp_path[MAX_PATH] = {0};
+  *temp_path = 0;
+  ASSERT_NE(::GetTempPath(MAX_PATH, temp_path), 0);
+
+  // Embed the tag string.
+  CString tagged_file;
+  tagged_file.Format(_T("%s%d%s"), temp_path, 1, kFileName);
+  omaha::ApplyTag tag;
+  ASSERT_HRESULT_SUCCEEDED(tag.Init(signed_exe_file,
+                                    kTagString,
+                                    strlen(kTagString),
+                                    tagged_file,
+                                    false));
+  ASSERT_SUCCEEDED(tag.EmbedTagString());
+  ON_SCOPE_EXIT(::DeleteFile, tagged_file);
+
+  // Append another tag string.
+  CString tagged_appended_file;
+  tagged_appended_file.Format(_T("%s%d%s"), temp_path, 2, kFileName);
+  omaha::ApplyTag tag1;
+
+  ASSERT_HRESULT_SUCCEEDED(tag1.Init(tagged_file,
+                                     kAppendTagString,
+                                     strlen(kAppendTagString),
+                                     tagged_appended_file,
+                                     true));
+  ASSERT_SUCCEEDED(tag1.EmbedTagString());
+  ON_SCOPE_EXIT(::DeleteFile, tagged_appended_file);
+
+  // Append another tag string.
+  CString tagged_appended_file2;
+  tagged_appended_file2.Format(_T("%s%d%s"), temp_path, 3, kFileName);
+  omaha::ApplyTag tag2;
+  ASSERT_HRESULT_SUCCEEDED(tag2.Init(tagged_appended_file,
+                                     kAppendTagString,
+                                     strlen(kAppendTagString),
+                                     tagged_appended_file2,
+                                     true));
+  ASSERT_SUCCEEDED(tag2.EmbedTagString());
+  ON_SCOPE_EXIT(::DeleteFile, tagged_appended_file2);
+
+  // Extract the tag string.
+  tag_buffer_size = 0;
+  CStringA expected_tag_string(kTagString);
+  expected_tag_string += kAppendTagString;
+  expected_tag_string += kAppendTagString;
+  int expected_tag_string_len = expected_tag_string.GetLength() + 1;
+  ASSERT_TRUE(extractor.OpenFile(tagged_appended_file2));
+  ASSERT_TRUE(extractor.ExtractTag(NULL, &tag_buffer_size));
+  ASSERT_EQ(tag_buffer_size, expected_tag_string_len);
+
+  scoped_array<char> tag_buffer(new char[expected_tag_string_len]);
+  ASSERT_TRUE(extractor.ExtractTag(tag_buffer.get(), &tag_buffer_size));
+  ASSERT_EQ(tag_buffer_size, expected_tag_string_len);
+  ASSERT_EQ(memcmp(tag_buffer.get(),
+                   expected_tag_string,
+                   expected_tag_string_len),
+            0);
+#endif
+  extractor.CloseFile();
+}
+
+TEST(ExtractorTest, AlreadyTaggedError) {
+  // Test the extractor.
+  TagExtractor extractor;
+  ASSERT_FALSE(extractor.IsFileOpen());
+
+  CString signed_exe_file;
+  signed_exe_file.Format(_T("%s\\%s\\%s"),
+                         app_util::GetCurrentModuleDirectory(),
+                         kFilePath, kFileName);
+  ASSERT_TRUE(extractor.OpenFile(signed_exe_file));
+
+  // No tag string in the original exe file.
+  int tag_buffer_size = 0;
+  ASSERT_FALSE(extractor.ExtractTag(NULL, &tag_buffer_size));
+// TODO(omaha): Remove the ifdef when signing occurs after instrumentation.
+#ifdef COVERAGE_ENABLED
+  std::wcout << _T("\tTest does not run in coverage builds.") << std::endl;
+#else
+  ASSERT_GT(extractor.cert_length(), 0);
+  ASSERT_EQ(tag_buffer_size, 0);
+  extractor.CloseFile();
+
+  // Create a temp dir.
+  TCHAR temp_path[MAX_PATH] = {0};
+  *temp_path = 0;
+  ASSERT_NE(::GetTempPath(MAX_PATH, temp_path), 0);
+
+  // Embed the tag string.
+  CString tagged_file;
+  tagged_file.Format(_T("%s%d%s"), temp_path, 1, kFileName);
+  omaha::ApplyTag tag1;
+  ASSERT_HRESULT_SUCCEEDED(tag1.Init(signed_exe_file,
+                                     kTagString,
+                                     strlen(kTagString),
+                                     tagged_file,
+                                     false));
+  ASSERT_SUCCEEDED(tag1.EmbedTagString());
+  ON_SCOPE_EXIT(::DeleteFile, tagged_file);
+
+  CString tagged_appended_file;
+  tagged_appended_file.Format(_T("%s%d%s"), temp_path, 2, kFileName);
+  omaha::ApplyTag tag2;
+  ASSERT_HRESULT_SUCCEEDED(tag2.Init(tagged_file,
+                                     kAppendTagString,
+                                     strlen(kAppendTagString),
+                                     tagged_appended_file,
+                                     false));
+  ASSERT_EQ(tag2.EmbedTagString(), APPLYTAG_E_ALREADY_TAGGED);
+  ON_SCOPE_EXIT(::DeleteFile, tagged_appended_file);
+#endif
+  extractor.CloseFile();
+}
+
+TEST(ApplyTagTest, InvalidCharsTest) {
+  // Accepted Regex = [-%{}/\a&=._]*
+  CString signed_exe_file;
+  signed_exe_file.Format(_T("%s\\%s\\%s"),
+                         app_util::GetCurrentModuleDirectory(),
+                         kFilePath, kFileName);
+  CString tagged_file(_T("out.txt"));
+
+  const char* const input_str = "abcd";
+  omaha::ApplyTag tag1;
+  ASSERT_HRESULT_SUCCEEDED(tag1.Init(signed_exe_file,
+                                     input_str,
+                                     strlen(input_str),
+                                     tagged_file,
+                                     false));
+
+  const char* const input_str2 = "abcd$%#";
+  omaha::ApplyTag tag2;
+  ASSERT_HRESULT_FAILED(tag2.Init(signed_exe_file,
+                                  input_str2,
+                                  strlen(input_str2),
+                                  tagged_file,
+                                  false));
+
+  const char* const input_str3 = "abcd asdf";
+  omaha::ApplyTag tag3;
+  ASSERT_HRESULT_FAILED(tag3.Init(signed_exe_file,
+                                  input_str3,
+                                  strlen(input_str3),
+                                  tagged_file,
+                                  false));
+}
+
+}  // namespace omaha
+
diff --git a/common/file.cc b/common/file.cc
index 4d6fcb7..b4effa3 100644
--- a/common/file.cc
+++ b/common/file.cc
@@ -1,1344 +1,1344 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// File handling routines

-//

-// Possible performance improvement: make a subclass or alternate class

-// that reads an entire file into memory and fulfills read/write requests

-// in memory (or equivalently, use a memory mapped file). This can greatly

-// improve performance if there are files we do a lot of read/write requests on.

-//

-// We generally are dealing with files that can be very large and want to

-// minimize memory usage, so this is not high priority

-//

-// this has the beginnings of asynchronous access support

-//

-// Unfortunately, doing asynchronous reads with FILE_FLAG_OVERLAPPED buys us

-// nothing because the system cache manager enforces serial requests.

-//

-// Hence, we need to also use FILE_FLAG_NO_BUFFERING. this has a number of

-// constraints:

-// - file read/write position must be aligned on multiples of the disk sector

-//   size

-// - file read/write length must be a multiple of the sector size

-// - read/write buffer must be aligned on multiples of the disk sector size

-//

-// In particular, this means that we cannot write 8 bytes, for example, because

-// we have to write an entire sector.

-//

-// Currently, the implementation only supports enough to do some simple read

-// tests

-//

-// The general idea is code that wants to to a sequence of asynchronous actions

-// will look like the following, for an example of reading multiple event

-// records asynchronously:

-//

-// uint32 async_id = File::GetNextAsyncId()

-// while (!done) {

-//   for (everything_to_do, e.g., for each event to read) {

-//     call File::Read to read items needed;

-//     returns TR_E_FILE_ASYNC_PENDING if queued; or returns data if done

-//     process the item (e.g., event) if desired

-//   }

-//   call some routine to process pending completions; initiate delayed action

-// }

-// call some cleanup routine

-

-#include "omaha/common/file.h"

-#include <algorithm>

-#include "base/scoped_ptr.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_config.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system.h"

-#include "omaha/common/timer.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-// Constants

-const uint32 kZeroSize = 4096;  // Buffer size used for clearing data in a file.

-

-// The moves-pending-reboot is a MULTISZ registry key in the HKLM part of the

-// registry.

-static const TCHAR* kSessionManagerKey =

-    _T("HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager");

-static const TCHAR* kPendingFileRenameOps = _T("PendingFileRenameOperations");

-

-File::File()

-    : handle_(INVALID_HANDLE_VALUE), read_only_(false), sequence_id_(0) {

-}

-

-File::~File() {

-  if (handle_ != INVALID_HANDLE_VALUE) {

-    VERIFY1(SUCCEEDED(Close()));

-  }

-}

-

-// open for reading only if write == false, otherwise both reading and writing

-// allow asynchronous operations if async == true. Use this function when you

-// need exclusive access to the file.

-HRESULT File::Open(const TCHAR* file_name, bool write, bool async) {

-  return OpenShareMode(file_name, write, async, 0);

-}

-

-// Allows specifying a sharing mode such as FILE_SHARE_READ. Otherwise,

-// this is identical to File::Open().

-HRESULT File::OpenShareMode(const TCHAR* file_name,

-                            bool write,

-                            bool async,

-                            DWORD share_mode) {

-  ASSERT1(file_name && *file_name);

-  ASSERT1(handle_ == INVALID_HANDLE_VALUE);

-  VERIFY1(!async);

-

-  file_name_ = file_name;

-

-  // there are restrictions on what we can do if using FILE_FLAG_NO_BUFFERING

-  // if (!buffer) { flags |= FILE_FLAG_NO_BUFFERING; }

-  // FILE_FLAG_WRITE_THROUGH

-  // how efficient is NTFS encryption? FILE_ATTRIBUTE_ENCRYPTED

-  // FILE_ATTRIBUTE_TEMPORARY

-  // FILE_FLAG_RANDOM_ACCESS

-  // FILE_FLAG_SEQUENTIAL_SCAN

-

-  handle_ = ::CreateFile(file_name,

-                         write ? (FILE_WRITE_DATA       |

-                                  FILE_WRITE_ATTRIBUTES |

-                                  FILE_READ_DATA) : FILE_READ_DATA,

-                         share_mode,

-                         NULL,

-                         write ? OPEN_ALWAYS : OPEN_EXISTING,

-                         FILE_FLAG_RANDOM_ACCESS,

-                         NULL);

-

-  if (handle_ == INVALID_HANDLE_VALUE) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-            (_T("[File::OpenShareMode - CreateFile failed][%s][%d][%d][0x%x]"),

-             file_name, write, async, hr));

-    return hr;

-  }

-

-  // This attribute is not supported directly by the CreateFile function.

-  if (!::SetFileAttributes(file_name, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-            (_T("[File::OpenShareMode - SetFileAttributes failed][0x%x]"), hr));

-    return hr;

-  }

-

-  read_only_ = !write;

-  pos_ = 0;

-  return S_OK;

-}

-

-// The path must not be enclosed in quotes. This is the Windows standard.

-// ::GetFileAttributesEx() returns ERROR_INVALID_NAME for quoted paths.

-bool File::Exists(const TCHAR* file_name) {

-  ASSERT1(file_name && *file_name);

-  ASSERT1(lstrlen(file_name) > 0);

-

-  // NOTE: This is the fastest implementation I found.  The results were:

-  //   CreateFile           1783739 avg ticks/call

-  //   FindFirstFile         634148 avg ticks/call

-  //   GetFileAttributes     428714 avg ticks/call

-  //   GetFileAttributesEx   396324 avg ticks/call

-  WIN32_FILE_ATTRIBUTE_DATA attrs = {0};

-  return 0 != ::GetFileAttributesEx(file_name, ::GetFileExInfoStandard, &attrs);

-}

-

-bool File::IsDirectory(const TCHAR* file_name) {

-  ASSERT1(file_name && *file_name);

-

-  WIN32_FILE_ATTRIBUTE_DATA attrs;

-  SetZero(attrs);

-  if (!::GetFileAttributesEx(file_name, ::GetFileExInfoStandard, &attrs)) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[File::IsDirectory - GetFileAttributesEx failed][%s][0x%x]"),

-              file_name, HRESULTFromLastError()));

-    return false;

-  }

-

-  return (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;

-}

-

-HRESULT File::GetWildcards(const TCHAR* dir,

-                           const TCHAR* wildcard,

-                           std::vector<CString>* matching_paths) {

-  ASSERT1(dir && *dir);

-  ASSERT1(wildcard && *wildcard);

-  ASSERT1(matching_paths);

-

-  matching_paths->clear();

-

-  // Make sure directory name ends with "\"

-  CString directory = String_MakeEndWith(dir, _T("\\"), false);

-

-  WIN32_FIND_DATA find_data;

-  SetZero(find_data);

-  scoped_hfind hfind(::FindFirstFile(directory + wildcard, &find_data));

-  if (!hfind) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(L5, (_T("[File::GetWildcards - FindFirstFile failed][0x%x]"), hr));

-    return hr;

-  }

-  do {

-    if (find_data.dwFileAttributes == FILE_ATTRIBUTE_NORMAL ||

-        !(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {

-      CString to_file(directory + find_data.cFileName);

-      matching_paths->push_back(to_file);

-    }

-  } while (::FindNextFile(get(hfind), &find_data));

-

-  HRESULT hr = HRESULTFromLastError();

-  if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES)) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[File::GetWildcards - FindNextFile failed][0x%x]"), hr));

-    return hr;

-  }

-  return S_OK;

-}

-

-// returns error if cannot remove

-// returns success if removed or already removed

-HRESULT File::Remove(const TCHAR* file_name) {

-  ASSERT1(file_name && *file_name);

-

-  if (!Exists(file_name)) {

-    return S_OK;

-  }

-

-  if (!::DeleteFile(file_name)) {

-    return HRESULTFromLastError();

-  }

-

-  return S_OK;

-}

-

-HRESULT File::CopyWildcards(const TCHAR* from_dir,

-                            const TCHAR* to_dir,

-                            const TCHAR* wildcard,

-                            bool replace_existing_files) {

-  ASSERT1(from_dir && *from_dir);

-  ASSERT1(to_dir && *to_dir);

-  ASSERT1(wildcard && *wildcard);

-

-  // Make sure dir names end with a "\"

-  CString from_directory = String_MakeEndWith(from_dir, _T("\\"), false);

-  CString to_directory = String_MakeEndWith(to_dir, _T("\\"), false);

-

-  // Get full path to source files (which is a wildcard)

-  CString from_files(from_directory + wildcard);

-

-  // Run over all files that match wildcard

-  WIN32_FIND_DATA find_data;

-  SetZero(find_data);

-

-  scoped_hfind hfind(::FindFirstFile(from_files, &find_data));

-  if (!hfind) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[File::CopyWildcards - FindFirstFile failed][0x%x]"), hr));

-    return hr;

-  }

-  do {

-    // Copy files

-    if (find_data.dwFileAttributes == FILE_ATTRIBUTE_NORMAL ||

-        !(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {

-      CString from_file(from_directory + find_data.cFileName);

-      CString to_file(to_directory + find_data.cFileName);

-

-      if (!replace_existing_files && Exists(to_file)) {

-        // Continue, since the caller has explicitly asked us to not replace an

-        // existing file

-        continue;

-      }

-

-      RET_IF_FAILED(Copy(from_file, to_file, replace_existing_files));

-    }

-  } while (::FindNextFile(get(hfind), &find_data));

-

-  HRESULT hr = HRESULTFromLastError();

-  if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES)) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[File::CopyWildcards - FindNextFile failed][0x%x]"), hr));

-    return hr;

-  }

-  return S_OK;

-}

-

-HRESULT File::CopyTree(const TCHAR* from_dir,

-                       const TCHAR* to_dir,

-                       bool replace_existing_files) {

-  ASSERT1(from_dir && *from_dir);

-  ASSERT1(to_dir && *to_dir);

-

-  UTIL_LOG(L3, (L"[File::CopyTree][from_dir %s][to_dir %s][replace %d]",

-                from_dir, to_dir, replace_existing_files));

-

-  // Make sure dir names end with a "\"

-  CString from_directory(String_MakeEndWith(from_dir, L"\\", false));

-  CString to_directory(String_MakeEndWith(to_dir, L"\\", false));

-

-  RET_IF_FAILED(CreateDir(to_directory, NULL));

-  RET_IF_FAILED(CopyWildcards(from_directory,

-                              to_directory,

-                              L"*.*",

-                              replace_existing_files));

-

-  // Run over all directories

-  WIN32_FIND_DATA find_data;

-  SetZero(find_data);

-

-  CString from_files(from_directory);

-  from_files += _T("*.*");

-

-  scoped_hfind hfind(::FindFirstFile(from_files, &find_data));

-  if (!hfind) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[File::CopyTree - FindFirstFile failed][0x%x]"), hr));

-    return hr;

-  }

-  do {

-    // Copy files

-    if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 &&

-        String_StrNCmp(find_data.cFileName, L"..", 2, false) &&

-        String_StrNCmp(find_data.cFileName, L".", 2, false)) {

-      CString from_subdir(from_directory + find_data.cFileName);

-      CString to_subdir(to_directory + find_data.cFileName);

-      RET_IF_FAILED(CopyTree(from_subdir, to_subdir, replace_existing_files));

-    }

-  } while (::FindNextFile(get(hfind), &find_data));

-

-  HRESULT hr = HRESULTFromLastError();

-  if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES)) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[File::CopyTree - FindNextFile failed][0x%x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT File::Copy(const TCHAR* from,

-                   const TCHAR* to,

-                   bool replace_existing_file) {

-  ASSERT1(from && *from);

-  ASSERT1(to && *to);

-

-  if (!replace_existing_file && Exists(to)) {

-    // Return success, since the caller has explicitly asked us to not replace

-    // an existing file

-    return S_OK;

-  }

-

-  if (!::CopyFile(from, to, !replace_existing_file)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[File::Copy - CopyFile failed]")

-                           _T("[from=%s][to=%s][replace=%u][0x%x]"),

-                           from, to, replace_existing_file, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// TODO(omaha): Combine common code in Move/MoveAfterReboot

-HRESULT File::Move(const TCHAR* from,

-                   const TCHAR* to,

-                   bool replace_existing_file) {

-  ASSERT1(from && *from);

-  ASSERT1(to && *to);

-

-  DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH;

-  if (replace_existing_file) {

-    flags |= MOVEFILE_REPLACE_EXISTING;

-  }

-

-  if (!::MoveFileEx(from, to, flags)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[File::Move - MoveFileEx failed]")

-              _T("[from=%s][to=%s][replace=%u][0x%x]"),

-              from, to, replace_existing_file, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// DeleteAfterReboot tries to delete the files by either moving them to the TEMP

-// directory and deleting them on reboot, or if that fails, by trying to delete

-// them in-place on reboot

-HRESULT File::DeleteAfterReboot(const TCHAR* from) {

-  ASSERT1(from && *from);

-

-  if (File::Exists(from)) {

-    HRESULT hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-    CString from_temp;

-

-    // No point in moving into TEMP if we're already there

-    if (!String_StartsWith(from, app_util::GetTempDir(), true)) {

-      // Try to move to the TEMP directory first

-      CString temp_dir(String_MakeEndWith(app_util::GetTempDir(),

-                                          _T("\\"),

-                                          false));

-      // Of the form "C:\\Windows\\Temp\\FROM.EXE1f4c0b7f"

-      from_temp.Format(_T("%s%s%x"),

-                       temp_dir,

-                       GetFileFromPath(from),

-                       ::GetTickCount());

-

-      hr = File::Move(from, from_temp, true);

-      UTIL_LOG(L2, (_T("[File::DeleteAfterReboot - move %s to %s][0x%x]"),

-                    from, from_temp, hr));

-    }

-

-    if (SUCCEEDED(hr)) {

-      UTIL_LOG(L2, (_T("[File::DeleteAfterReboot - delete %s after reboot]"),

-                    from_temp));

-      // Move temp file after reboot

-      if (FAILED(hr = File::MoveAfterReboot(from_temp, NULL))) {

-        UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")

-                               _T("[failed to delete after reboot %s][0x%x]"),

-                               from_temp, hr));

-      }

-    } else  {

-      // Move original file after reboot

-      if (FAILED(hr = File::MoveAfterReboot(from, NULL))) {

-        UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")

-                               _T("[failed to delete after reboot %s][0x%x]"),

-                               from, hr));

-      }

-    }

-

-    return hr;

-  }

-

-  return S_OK;

-}

-

-

-HRESULT File::MoveAfterReboot(const TCHAR* from, const TCHAR* to) {

-  ASSERT1(from && *from);

-

-  if (!File::Exists(from)) {

-    // File/directory doesn't exist, should this return failure or success?

-    // Decision:  Failure.  Because the caller can decide if it is really

-    // failure or not in his specific case.

-    UTIL_LOG(LEVEL_WARNING, (_T("[File::MoveAfterReboot]")

-                             _T("[file doesn't exist][from %s]"), from));

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-

-  DWORD flags = MOVEFILE_DELAY_UNTIL_REBOOT;

-  if (!File::IsDirectory(from)) {

-    // This flag valid only for files

-    flags |= MOVEFILE_REPLACE_EXISTING;

-  }

-

-  if (!::MoveFileEx(from, to, flags)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[File::MoveAfterReboot]")

-                           _T("[failed to MoveFileEx from '%s' to '%s'][0x%x]"),

-                           from, to, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// See if we have any moves pending a reboot. Return SUCCESS if we do

-// not encounter errors (not finding a move is not an error). We need to

-// also check the value of *found_ptr for whether we actually found a move.

-// On return, *value_multisz_ptr is the value within

-// "PendingFileRenameOperations", but with any moves for in_directory removed

-// from it.

-// The prefix_match boolean controls whether we do an exact match on

-// in_directory, or remove all entries with the in_directory prefix.

-// NOTE: If the only values found were our own keys, the whole

-// PendingFileRenameOperations MULTISZ needs to be deleted.

-// This is signified by a returned *value_size_chars_ptr of 0.

-HRESULT File::GetPendingRenamesValueMinusDir(const TCHAR* in_directory,

-                                             bool prefix_match,

-                                             TCHAR** value_multisz_ptr,

-                                             DWORD* value_size_chars_ptr,

-                                             bool* found_ptr) {

-  ASSERT1(in_directory && *in_directory);

-

-  // Convert to references for easier-to-read-code:

-  TCHAR*& value_multisz = *value_multisz_ptr;

-  DWORD& value_size_chars = *value_size_chars_ptr;

-  bool& found = *found_ptr;

-

-  // Initialize [out] parameters

-  value_multisz = NULL;

-  value_size_chars = 0;

-  found = false;

-

-  // Locals mirroring the [out] parameters.

-  // We will only set the corresponding [out] parameters when we have something

-  // meaningful to return to the caller

-  scoped_array<TCHAR> value_multisz_local;

-  DWORD value_size_chars_local = 0;

-

-  DWORD value_size_bytes = 0;

-  // Get the current value of the key

-  // If the Key is missing, that's totally acceptable.

-  RET_IF_FALSE(

-      RegKey::HasValue(kSessionManagerKey, kPendingFileRenameOps) &&

-      SUCCEEDED(RegKey::GetValue(kSessionManagerKey,

-                                 kPendingFileRenameOps,

-                                 reinterpret_cast<byte**>(&value_multisz_local),

-                                 &value_size_bytes)),

-      S_OK);

-

-  ASSERT1(value_multisz_local.get() || value_size_bytes == 0);

-  UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")

-                _T("[read multisz %d bytes]"),

-                value_size_bytes));

-  RET_IF_FALSE(value_size_bytes > 0, S_OK);

-

-  // The size should always be aligned to a TCHAR boundary, otherwise the key

-  // is corrupted.

-  ASSERT1((value_size_bytes % sizeof(TCHAR)) == 0);

-  RET_IF_FALSE((value_size_bytes % sizeof(TCHAR)) == 0,

-               HRESULT_FROM_WIN32(ERROR_BADKEY));

-  // Valid size, so convert to TCHARs:

-  value_size_chars_local = value_size_bytes / sizeof(TCHAR);

-

-  // Buffer must terminate with two nulls

-  ASSERT(value_size_chars_local >= 2 &&

-         !value_multisz_local[value_size_chars_local - 1] &&

-         !value_multisz_local[value_size_chars_local - 2],

-         (_T("buffer must terminate with two nulls")));

-  RET_IF_FALSE(value_size_chars_local >= 2 &&

-               !value_multisz_local[value_size_chars_local - 1] &&

-               !value_multisz_local[value_size_chars_local - 2],

-               HRESULT_FROM_WIN32(ERROR_BADKEY));

-  // Mark the end of the string.

-  // multisz_end will point at the character past end of buffer:

-  TCHAR* multisz_end = value_multisz_local.get() + value_size_chars_local;

-

-  // We're looking for \??\C:\...  The \??\ was

-  // added by the OS to the directory name we specified.

-  CString from_dir(_T("\\??\\"));

-  from_dir += in_directory;

-  DWORD from_dir_len = from_dir.GetLength();

-

-  // A MULTISZ is a list of null terminated strings, terminated by a double

-  // null.  We keep two pointers marching along the string in parallel.

-  TCHAR* str_read = value_multisz_local.get();

-  TCHAR* str_write = str_read;

-

-  while ((str_read < multisz_end) && *str_read) {

-    size_t str_len = ::lstrlen(str_read);

-  // A FALSE here indicates a corrupt PendingFileRenameOperations

-    RET_IF_FALSE((str_read + str_len + 1) < multisz_end,

-      HRESULT_FROM_WIN32(ERROR_BADKEY));

-    if (0 == String_StrNCmp(str_read,

-                            from_dir,

-                            from_dir_len + (prefix_match ? 0 : 1),

-                            true)) {

-      // String matches, we want to remove this string, so advance only the

-      // read pointer - past this string and the replacement string.

-      UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")

-                    _T("[skips past match '%s']"),

-                    str_read));

-      str_read += str_len + 1;

-      str_read += ::lstrlen(str_read) + 1;

-      continue;

-    }

-    // String doesn't match, we want to keep it.

-    if (str_read != str_write) {

-      // Here we're not in sync in the buffer, we've got to move two

-      // strings down.

-      UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")

-                    _T("[copying some other deletion][%s][%s]"),

-                    str_read, str_read + ::lstrlen(str_read) + 1));

-      ASSERT1(str_write < str_read);

-      String_StrNCpy(str_write, str_read, str_len+1);

-      str_read += str_len + 1;

-      str_write += str_len + 1;

-      str_len = ::lstrlen(str_read);

-      String_StrNCpy(str_write, str_read, str_len+1);

-      str_read += str_len + 1;

-      str_write += str_len + 1;

-    } else {

-      // We're in sync in the buffer, advance both pointers past two strings

-      UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")

-                    _T("[skipping past some other deletion][%s][%s]"),

-                    str_read, str_read + ::lstrlen(str_read) + 1));

-      str_read += str_len + 1;

-      str_read += ::lstrlen(str_read) + 1;

-      str_write = str_read;

-    }

-  }

-

-  // A FALSE here indicates a corrupt PendingFileRenameOperations

-  RET_IF_FALSE(str_read < multisz_end,

-    HRESULT_FROM_WIN32(ERROR_BADKEY));

-

-  if (str_read != str_write) {

-    // We found some values

-    found = true;

-

-    if (str_write == value_multisz_local.get()) {

-      // The only values were our own keys,

-      // and the whole PendingFileRenameOperations

-      // value needs to be deleted. We do not populate

-      // value_size_chars or value_multisz in this case.

-      ASSERT1(!value_size_chars);

-      ASSERT1(!value_multisz);

-    } else  {

-      // The last string should have a NULL terminator:

-      ASSERT1(str_write[-1] == '\0');

-      RET_IF_FALSE(str_write[-1] == '\0',

-        HRESULT_FROM_WIN32(ERROR_INVALID_DATA));

-      // a REG_MULTI_SZ needs to be terminated with an extra NULL.

-      *str_write = '\0';

-      ++str_write;

-

-      // Populate value_size_chars and value_multisz in this case.

-      value_multisz = value_multisz_local.release();

-      value_size_chars = str_write - value_multisz;

-    }

-  }

-

-  return S_OK;

-}

-

-// Remove any moves pending a reboot from the PendingFileRenameOperations

-// in the registry.

-// The prefix_match boolean controls whether we do an exact match on

-// in_directory, or remove all entries with the in_directory prefix.

-HRESULT File::RemoveFromMovesPendingReboot(const TCHAR* in_directory,

-                                           bool prefix_match) {

-  ASSERT1(in_directory && *in_directory);

-

-  bool found = false;

-  // scoped_array will free the value_multisz buffer on stack unwind:

-  scoped_array<TCHAR> value_multisz;

-  DWORD value_size_chars = 0;

-  HRESULT hr = GetPendingRenamesValueMinusDir(in_directory,

-                                              prefix_match,

-                                              address(value_multisz),

-                                              &value_size_chars,

-                                              &found);

-  if (SUCCEEDED(hr) && found) {

-    if (value_multisz.get() == NULL)  {

-      // There's no point in writing an empty value_multisz.

-      // Let's delete the PendingFileRenameOperations value

-      UTIL_LOG(L5, (_T("[File::RemoveFromMovesPendingReboot]")

-                    _T("[deleting PendingFileRenameOperations value]")));

-      RET_IF_FAILED(RegKey::DeleteValue(kSessionManagerKey,

-                    kPendingFileRenameOps));

-    } else  {

-      // Let's write the modified value_multisz into the

-      // PendingFileRenameOperations value

-      UTIL_LOG(L5, (_T("[File::RemoveFromMovesPendingReboot]")

-                    _T("[rewriting multisz %d bytes]"),

-                    value_size_chars * sizeof(TCHAR)));

-      RET_IF_FAILED(RegKey::SetValueMultiSZ(

-          kSessionManagerKey,

-          kPendingFileRenameOps,

-          reinterpret_cast<byte*>(value_multisz.get()),

-          value_size_chars * sizeof(TCHAR)));

-    }

-  }

-

-  // Failure of GetPendingRenamesValueMinusDir() may indicate something

-  // seriously wrong with the system. Propogate error.

-  return hr;

-}

-

-// Did the user try to uninstall a previous install of the same version, and

-// we couldn't clean up without a reboot?

-// We check if there are any moves pending a reboot from the

-// PendingFileRenameOperations in the registry.

-// The prefix_match boolean controls whether we do an exact match on

-// in_directory, or check all entries with the in_directory prefix.

-bool File::AreMovesPendingReboot(const TCHAR* in_directory, bool prefix_match) {

-  ASSERT1(in_directory && *in_directory);

-

-  bool found = false;

-  // scoped_array will free the value_multisz buffer on stack unwind:

-  scoped_array<TCHAR> value_multisz;

-  DWORD value_size_chars = 0;

-

-  if (SUCCEEDED(GetPendingRenamesValueMinusDir(in_directory,

-                                               prefix_match,

-                                               address(value_multisz),

-                                               &value_size_chars,

-                                               &found)) && found) {

-    return true;

-  }

-

-  return false;

-}

-

-HRESULT File::GetFileTime(const TCHAR* file_name,

-                          FILETIME* created,

-                          FILETIME* accessed,

-                          FILETIME* modified) {

-  ASSERT1(file_name && *file_name);

-

-  bool is_dir = IsDirectory(file_name);

-  // To obtain a handle to a directory, call the CreateFile function with

-  // the FILE_FLAG_BACKUP_SEMANTICS flag

-  scoped_hfile file_handle(

-      ::CreateFile(file_name,

-                   FILE_READ_DATA,

-                   FILE_SHARE_READ,

-                   NULL,

-                   OPEN_EXISTING,

-                   is_dir ? FILE_FLAG_BACKUP_SEMANTICS : NULL,

-                   NULL));

-  HRESULT hr = S_OK;

-

-  if (!file_handle) {

-    hr = HRESULTFromLastError();

-    UTIL_LOG(LE, (_T("[File::GetFileTime]")

-                  _T("[failed to open file][%s][0x%x]"), file_name, hr));

-  } else {

-    if (!::GetFileTime(get(file_handle), created, accessed, modified)) {

-      hr = HRESULTFromLastError();

-      UTIL_LOG(LEVEL_ERROR, (_T("[File::GetFileTime]")

-                             _T("[failed to get file time][%s][0x%x]"),

-                             file_name, hr));

-    }

-  }

-

-  return hr;

-}

-

-HRESULT File::SetFileTime(const TCHAR* file_name,

-                          const FILETIME* created,

-                          const FILETIME* accessed,

-                          const FILETIME* modified) {

-  ASSERT1(file_name && *file_name);

-

-  bool is_dir = IsDirectory(file_name);

-  // To obtain a handle to a directory, call the CreateFile function with

-  // the FILE_FLAG_BACKUP_SEMANTICS flag

-  scoped_hfile file_handle(

-      ::CreateFile(file_name,

-                   FILE_WRITE_ATTRIBUTES,

-                   FILE_SHARE_WRITE,

-                   NULL,

-                   OPEN_EXISTING,

-                   is_dir ? FILE_FLAG_BACKUP_SEMANTICS : NULL,

-                   NULL));

-  HRESULT hr = S_OK;

-

-  if (!file_handle) {

-    hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[File::GetFileTime]")

-                           _T("[failed to open file][%s][0x%x]"),

-                           file_name, hr));

-  } else {

-    BOOL res = ::SetFileTime(get(file_handle), created, accessed, modified);

-    if (!res) {

-      hr = HRESULTFromLastError();

-      UTIL_LOG(LEVEL_ERROR, (_T("[File::SetFileTime]")

-                             _T("[failed to set file time][%s][0x%x]"),

-                             file_name, hr));

-    }

-  }

-

-  return hr;

-}

-

-HRESULT File::Sync() {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-

-  if (!::FlushFileBuffers(handle_)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[File::Sync]")

-                           _T("[FlushFileBuffers failed][%s][0x%x]"),

-                           file_name_, hr));

-    return hr;

-  }

-  return S_OK;

-}

-

-HRESULT File::SeekToBegin() {

-  return SeekFromBegin(0);

-}

-

-HRESULT File::SeekFromBegin(uint32 n) {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-

-  if (::SetFilePointer(handle_, n, NULL, FILE_BEGIN) ==

-      INVALID_SET_FILE_POINTER) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[File::SeekFromBegin]")

-                           _T("[SetFilePointer failed][%s][0x%x]"),

-                           file_name_, hr));

-    return hr;

-  }

-  pos_ = n;

-  return S_OK;

-}

-

-// read nLen bytes starting at position n

-// returns number of bytes read

-//

-// async operations:

-//

-// async_id - identifier of a sequence of async operations, 0 for synchronous

-//

-// if the async operation has not been initiated, we initiate it

-// if it is in progress we do nothing

-// if it has been completed we return the data

-// does not delete async data entry

-HRESULT File::ReadAt(const uint32 offset, byte* buf, const uint32 len,

-                     const uint32, uint32* bytes_read) {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-  ASSERT1(buf);

-  ASSERT1(len);  // reading 0 bytes is not valid (differs from CRT API)

-

-  RET_IF_FAILED(SeekFromBegin(offset));

-

-  DWORD read = 0;

-  if (!::ReadFile(handle_, buf, len, &read, NULL)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[File::ReadAt]")

-                           _T("[ReadFile failed][%s][0x%x]"), file_name_, hr));

-    return hr;

-  }

-

-  if (bytes_read) {

-    *bytes_read = read;

-  }

-

-  return (read == len) ? S_OK : E_FAIL;

-}

-

-

-// reads up to max_len bytes from the start of the file

-// not considered an error if there are less than max_len bytes read

-// returns number of bytes read

-HRESULT File::ReadFromStartOfFile(const uint32 max_len,

-                                  byte* buf,

-                                  uint32* bytes_read) {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-  ASSERT1(buf);

-  ASSERT1(max_len);

-

-  RET_IF_FAILED(SeekFromBegin(0));

-

-  uint32 file_len = 0;

-  RET_IF_FAILED(GetLength(&file_len));

-

-  if (!file_len) {

-    if (bytes_read) {

-      *bytes_read = 0;

-    }

-    return S_OK;

-  }

-

-  uint32 len = max_len;

-  if (len > file_len) {

-    len = static_cast<uint32>(file_len);

-  }

-

-  return Read(len, buf, bytes_read);

-}

-

-// this function handles lines terminated with LF or CRLF

-// all CR characters are removed from each line, and LF is assumed

-// to be the end of line and is removed

-HRESULT File::ReadLineAnsi(uint32 max_len, char* line, uint32* len) {

-  ASSERT1(line);

-  ASSERT1(max_len);

-

-  char c = 0;

-  uint32 len_read = 0;

-  uint32 total_len = 0;

-

-  while (SUCCEEDED(Read(1, reinterpret_cast<byte *>(&c), &len_read)) &&

-         len_read  &&

-         c != '\n') {

-    if (total_len < max_len - 1 && c != '\r') {

-      line[total_len++] = c;

-    }

-  }

-

-  ASSERT1(total_len < max_len);

-  line[total_len] = '\0';

-

-  if (len) {

-    *len = total_len;

-  }

-

-  return (len_read || total_len) ? S_OK : E_FAIL;

-}

-

-// used by ReadFromStartOfFile and ReadLineAnsi; not reading all requested bytes

-// is not considered fatal

-HRESULT File::Read(const uint32 len, byte* buf, uint32* bytes_read) {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-  ASSERT1(buf);

-  ASSERT1(len);

-

-  DWORD read = 0;

-  if (!::ReadFile(handle_, buf, len, &read, NULL)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[File::ReadAt]")

-                           _T("[ReadFile failed][%s][0x%x]"),

-                           file_name_, hr));

-    return hr;

-  }

-

-  if (bytes_read) {

-    *bytes_read = read;

-  }

-

-  return S_OK;

-}

-

-

-// returns number of bytes written

-HRESULT File::WriteAt(const uint32 offset,

-                      const byte* buf,

-                      const uint32 len,

-                      uint32,

-                      uint32* bytes_written) {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-  ASSERT1(!read_only_);

-  ASSERT1(buf);

-  ASSERT1(len);

-

-  RET_IF_FAILED(SeekFromBegin(offset));

-

-  return Write(buf, len, bytes_written);

-}

-

-

-// write buffer n times

-HRESULT File::WriteN(const byte* buf,

-                     const uint32 len,

-                     const uint32 n,

-                     uint32* bytes_written) {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-  ASSERT1(!read_only_);

-  ASSERT1(buf);

-  ASSERT1(len);

-  ASSERT1(n);

-

-  HRESULT hr = S_OK;

-

-  uint32 total_wrote = 0;

-

-  byte* temp_buf = const_cast<byte*>(buf);

-

-  scoped_array<byte> encrypt_buf;

-

-  uint32 to_go = n;

-  while (to_go) {

-    uint32 wrote = 0;

-    hr = Write(temp_buf, len, &wrote);

-    if (FAILED(hr)) {

-      if (bytes_written) {

-        *bytes_written = total_wrote;

-      }

-      return hr;

-    }

-

-    total_wrote += wrote;

-    to_go--;

-  }

-

-  if (bytes_written) {

-    *bytes_written = total_wrote;

-  }

-  return hr;

-}

-

-// returns number of bytes written

-HRESULT File::Write(const byte* buf, const uint32 len, uint32* bytes_written) {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-  ASSERT1(!read_only_);

-  ASSERT1(buf);

-  ASSERT1(len);  // writing 0 bytes is not valid (differs from CRT API)

-

-  byte* b = const_cast<byte*>(buf);

-

-  scoped_array<byte> encrypt_buf;

-

-  DWORD wrote = 0;

-  if (!::WriteFile(handle_, b, len, &wrote, NULL)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[File::Write]")

-                           _T("[WriteFile failed][%s][0x%x]"),

-                           file_name_, hr));

-    return hr;

-  }

-

-  if (bytes_written) {

-    *bytes_written = wrote;

-  }

-  pos_ += wrote;

-

-  return (wrote == len) ? S_OK : E_FAIL;

-}

-

-HRESULT File::ClearAt(const uint32 offset,

-                      const uint32 len,

-                      uint32* bytes_written) {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-  ASSERT1(!read_only_);

-  ASSERT1(len);

-

-  byte zero[kZeroSize] = {0};

-  uint32 to_go = len;

-  uint32 written = 0;

-  uint32 pos = offset;

-

-  while (to_go) {

-    uint32 wrote = 0;

-    uint32 write_len = std::min(to_go, kZeroSize);

-    RET_IF_FAILED(WriteAt(pos, zero, write_len, 0, &wrote));

-

-    if (wrote != write_len) {

-      return E_FAIL;

-    }

-    pos += wrote;

-    written += wrote;

-    to_go -= write_len;

-  }

-

-  if (bytes_written) {

-    *bytes_written = written;

-  }

-  return S_OK;

-}

-

-// returns true on failure

-// zeros new data if zero_data == true

-HRESULT File::SetLength(const uint32 n, bool zero_data) {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-  ASSERT1(!read_only_);

-  ASSERT1(n <= kMaxFileSize);

-

-  HRESULT hr = S_OK;

-

-  uint32 len = 0;

-  VERIFY1(SUCCEEDED(GetLength(&len)));

-

-  if (len == n) {

-    return S_OK;

-  }

-

-  // according to the documentation, the

-  // new space will not be initialized

-  if (n > len) {

-    if (zero_data) {

-      uint32 bytes_written = 0;

-      RET_IF_FAILED(ClearAt(len, n - len, &bytes_written));

-      if (bytes_written != n - len) {

-        return E_FAIL;

-      }

-    } else {

-      byte zero = 0;

-      uint32 bytes_written = 0;

-      RET_IF_FAILED(WriteAt(n - 1, &zero, 1, 0, &bytes_written));

-      if (bytes_written != 1) {

-        return E_FAIL;

-      }

-    }

-  } else {

-    SeekFromBegin(n);

-    SetEndOfFile(handle_);

-  }

-

-  ASSERT1(SUCCEEDED(GetLength(&len)) && len == n);

-

-  return S_OK;

-}

-

-HRESULT File::ExtendInBlocks(const uint32 block_size, uint32 size_needed,

-                             uint32* new_size, bool clear_new_space) {

-  ASSERT1(new_size);

-

-  *new_size = size_needed;

-

-  if (*new_size % block_size) {

-    *new_size += block_size - (*new_size % block_size);

-  }

-

-  // is zero_data needed? may reduce fragmentation by causing the block to

-  // be written

-  return SetLength(*new_size, clear_new_space);

-}

-

-// returns S_OK on success

-HRESULT File::GetLength(uint32* length) {

-  ASSERT1(length);

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-

-  DWORD len = GetFileSize(handle_, NULL);

-  if (len == INVALID_FILE_SIZE) {

-    ASSERT(false, (_T("cannot get file length")));

-    return E_FAIL;

-  }

-  *length = len;

-  return S_OK;

-}

-

-HRESULT File::Touch() {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-

-  FILETIME file_time;

-  SetZero(file_time);

-

-  ::GetSystemTimeAsFileTime(&file_time);

-

-  if (!::SetFileTime(handle_, NULL, NULL, &file_time)) {

-    return HRESULTFromLastError();

-  }

-  return S_OK;

-}

-

-HRESULT File::Close() {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-

-  HRESULT hr = S_OK;

-  if (!::CloseHandle(handle_)) {

-    hr = HRESULTFromLastError();

-  }

-

-  handle_ = INVALID_HANDLE_VALUE;

-

-  return hr;

-}

-

-// this is just for consistency with other classes; does not do anything

-HRESULT File::Reload(uint32* number_errors) {

-  ASSERT1(number_errors);

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-

-  *number_errors = 0;

-  return S_OK;

-}

-

-// this is just for consistency with other classes; does not do anything

-HRESULT File::Verify(uint32* number_errors) {

-  ASSERT1(number_errors);

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-

-  *number_errors = 0;

-  return S_OK;

-}

-

-// this is just for consistency with other classes; does not do anything

-HRESULT File::Dump() {

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-  return S_OK;

-}

-

-// for consistency with other classes

-HRESULT File::GetSizeOnDisk(uint64* size_on_disk) {

-  ASSERT1(size_on_disk);

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-

-  uint32 len = 0;

-  RET_IF_FAILED(GetLength(&len));

-

-  *size_on_disk = len;

-  return S_OK;

-}

-

-// for consistency with other classes

-HRESULT File::GetReloadDiskSpaceNeeded(uint64* bytes_needed) {

-  ASSERT1(bytes_needed);

-  ASSERT1(handle_ != INVALID_HANDLE_VALUE);

-

-  uint32 len = 0;

-  RET_IF_FAILED(GetLength(&len));

-

-  *bytes_needed = len;

-  return S_OK;

-}

-

-// Get the file size

-HRESULT File::GetFileSizeUnopen(const TCHAR* filename, uint32* out_size) {

-  ASSERT1(filename);

-  ASSERT1(out_size);

-

-  WIN32_FILE_ATTRIBUTE_DATA data;

-  SetZero(data);

-

-  if (!::GetFileAttributesEx(filename, ::GetFileExInfoStandard, &data)) {

-    return HRESULTFromLastError();

-  }

-

-  *out_size = data.nFileSizeLow;

-

-  return S_OK;

-}

-

-// Get the last time with a file was written to, and the size

-HRESULT File::GetLastWriteTimeAndSize(const TCHAR* file_path,

-                                      SYSTEMTIME* out_time,

-                                      unsigned int* out_size) {

-  ASSERT1(file_path);

-

-  WIN32_FIND_DATA wfd;

-  SetZero(wfd);

-

-  HANDLE find = ::FindFirstFile(file_path, &wfd);

-  if (find == INVALID_HANDLE_VALUE) {

-    return HRESULTFromLastError();

-  }

-

-  ::FindClose(find);

-

-  if (out_size) {

-    *out_size = wfd.nFileSizeLow;

-  }

-

-  if (out_time) {

-    // If created time is newer than write time, then use that instead

-    // [it tends to be more relevant when copying files around]

-    FILETIME* latest_time = NULL;

-    if (::CompareFileTime(&wfd.ftCreationTime, &wfd.ftLastWriteTime) > 0) {

-      latest_time = &wfd.ftCreationTime;

-    } else {

-      latest_time = &wfd.ftLastWriteTime;

-    }

-

-    if (!::FileTimeToSystemTime(latest_time, out_time)) {

-      return HRESULTFromLastError();

-    }

-  }

-

-  return S_OK;

-}

-

-FileLock::FileLock() {

-}

-

-FileLock::~FileLock() {

-  Unlock();

-}

-

-HRESULT FileLock::Lock(const TCHAR* file) {

-  std::vector<CString> files;

-  files.push_back(file);

-  return Lock(files);

-}

-

-HRESULT FileLock::Lock(const std::vector<CString>& files) {

-  ASSERT1(!files.empty());

-

-  // Try to lock all files

-  size_t curr_size = handles_.size();

-  for (size_t i = 0; i < files.size(); ++i) {

-    scoped_hfile handle(::CreateFile(files[i],

-                                     GENERIC_READ,

-                                     FILE_SHARE_READ,

-                                     NULL,

-                                     OPEN_EXISTING,

-                                     FILE_ATTRIBUTE_NORMAL,

-                                     NULL));

-    if (!handle) {

-      UTIL_LOG(LEVEL_ERROR,

-               (_T("[FileLock::Lock - failed to lock file][%s][0x%x]"),

-                files[i], HRESULTFromLastError()));

-      break;

-    }

-    handles_.push_back(release(handle));

-  }

-

-  // Cleanup if we fail to lock all the files

-  if (curr_size +  files.size() < handles_.size()) {

-    for (size_t i = handles_.size() - 1; i >= curr_size; --i) {

-      VERIFY(::CloseHandle(handles_[i]), (_T("")));

-      handles_.pop_back();

-    }

-    return E_FAIL;

-  }

-

-  return S_OK;

-}

-

-HRESULT FileLock::Unlock() {

-  for (size_t i = 0; i < handles_.size(); ++i) {

-    VERIFY(::CloseHandle(handles_[i]), (_T("")));

-  }

-  handles_.clear();

-  return S_OK;

-}

-

-

-// path_name: the directory to watch

-// watch_subtree: watch all subdirectory changes  or

-//                only immediate child values

-// notify_filter: See the documentation for FindFirstChangeNotification

-FileWatcher::FileWatcher(const TCHAR* path_name, bool watch_subtree,

-                         DWORD notify_filter)

-    : path_name_(path_name),

-      watch_subtree_(watch_subtree),

-      notify_filter_(notify_filter) {

-  ASSERT1(path_name && *path_name);

-  UTIL_LOG(L3, (_T("[FileWatcher::FileWatcher][%s]"), path_name));

-}

-

-// Get the event that is signaled on store changes.

-HANDLE FileWatcher::change_event() const {

-  ASSERT(valid(change_event_), (_T("call FileWatcher::SetupEvent first")));

-  return get(change_event_);

-}

-

-

-// Called to create/reset the event that gets signaled

-// any time the store changes.  Access the created

-// event using change_event().

-HRESULT FileWatcher::EnsureEventSetup() {

-  UTIL_LOG(L3, (_T("[FileWatcher::EnsureEventSetup]")));

-  if (!valid(change_event_)) {

-    reset(change_event_, ::FindFirstChangeNotification(path_name_,

-                                                       watch_subtree_,

-                                                       notify_filter_));

-    if (!valid(change_event_)) {

-      ASSERT(false, (_T("unable to get file change notification")));

-      return E_FAIL;

-    }

-    // path name was only needed to set-up the event and now that is done....

-    path_name_.Empty();

-    return S_OK;

-  }

-

-  // if the event is set-up and no changes have occurred,

-  // then there is no need to re-setup the event.

-  if (valid(change_event_) && !HasChangeOccurred()) {

-    return NOERROR;

-  }

-

-  return ::FindNextChangeNotification(get(change_event_)) ? S_OK : E_FAIL;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// File handling routines
+//
+// Possible performance improvement: make a subclass or alternate class
+// that reads an entire file into memory and fulfills read/write requests
+// in memory (or equivalently, use a memory mapped file). This can greatly
+// improve performance if there are files we do a lot of read/write requests on.
+//
+// We generally are dealing with files that can be very large and want to
+// minimize memory usage, so this is not high priority
+//
+// this has the beginnings of asynchronous access support
+//
+// Unfortunately, doing asynchronous reads with FILE_FLAG_OVERLAPPED buys us
+// nothing because the system cache manager enforces serial requests.
+//
+// Hence, we need to also use FILE_FLAG_NO_BUFFERING. this has a number of
+// constraints:
+// - file read/write position must be aligned on multiples of the disk sector
+//   size
+// - file read/write length must be a multiple of the sector size
+// - read/write buffer must be aligned on multiples of the disk sector size
+//
+// In particular, this means that we cannot write 8 bytes, for example, because
+// we have to write an entire sector.
+//
+// Currently, the implementation only supports enough to do some simple read
+// tests
+//
+// The general idea is code that wants to to a sequence of asynchronous actions
+// will look like the following, for an example of reading multiple event
+// records asynchronously:
+//
+// uint32 async_id = File::GetNextAsyncId()
+// while (!done) {
+//   for (everything_to_do, e.g., for each event to read) {
+//     call File::Read to read items needed;
+//     returns TR_E_FILE_ASYNC_PENDING if queued; or returns data if done
+//     process the item (e.g., event) if desired
+//   }
+//   call some routine to process pending completions; initiate delayed action
+// }
+// call some cleanup routine
+
+#include "omaha/common/file.h"
+#include <algorithm>
+#include "base/scoped_ptr.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_config.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system.h"
+#include "omaha/common/timer.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+// Constants
+const uint32 kZeroSize = 4096;  // Buffer size used for clearing data in a file.
+
+// The moves-pending-reboot is a MULTISZ registry key in the HKLM part of the
+// registry.
+static const TCHAR* kSessionManagerKey =
+    _T("HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager");
+static const TCHAR* kPendingFileRenameOps = _T("PendingFileRenameOperations");
+
+File::File()
+    : handle_(INVALID_HANDLE_VALUE), read_only_(false), sequence_id_(0) {
+}
+
+File::~File() {
+  if (handle_ != INVALID_HANDLE_VALUE) {
+    VERIFY1(SUCCEEDED(Close()));
+  }
+}
+
+// open for reading only if write == false, otherwise both reading and writing
+// allow asynchronous operations if async == true. Use this function when you
+// need exclusive access to the file.
+HRESULT File::Open(const TCHAR* file_name, bool write, bool async) {
+  return OpenShareMode(file_name, write, async, 0);
+}
+
+// Allows specifying a sharing mode such as FILE_SHARE_READ. Otherwise,
+// this is identical to File::Open().
+HRESULT File::OpenShareMode(const TCHAR* file_name,
+                            bool write,
+                            bool async,
+                            DWORD share_mode) {
+  ASSERT1(file_name && *file_name);
+  ASSERT1(handle_ == INVALID_HANDLE_VALUE);
+  VERIFY1(!async);
+
+  file_name_ = file_name;
+
+  // there are restrictions on what we can do if using FILE_FLAG_NO_BUFFERING
+  // if (!buffer) { flags |= FILE_FLAG_NO_BUFFERING; }
+  // FILE_FLAG_WRITE_THROUGH
+  // how efficient is NTFS encryption? FILE_ATTRIBUTE_ENCRYPTED
+  // FILE_ATTRIBUTE_TEMPORARY
+  // FILE_FLAG_RANDOM_ACCESS
+  // FILE_FLAG_SEQUENTIAL_SCAN
+
+  handle_ = ::CreateFile(file_name,
+                         write ? (FILE_WRITE_DATA       |
+                                  FILE_WRITE_ATTRIBUTES |
+                                  FILE_READ_DATA) : FILE_READ_DATA,
+                         share_mode,
+                         NULL,
+                         write ? OPEN_ALWAYS : OPEN_EXISTING,
+                         FILE_FLAG_RANDOM_ACCESS,
+                         NULL);
+
+  if (handle_ == INVALID_HANDLE_VALUE) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+            (_T("[File::OpenShareMode - CreateFile failed][%s][%d][%d][0x%x]"),
+             file_name, write, async, hr));
+    return hr;
+  }
+
+  // This attribute is not supported directly by the CreateFile function.
+  if (!::SetFileAttributes(file_name, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+            (_T("[File::OpenShareMode - SetFileAttributes failed][0x%x]"), hr));
+    return hr;
+  }
+
+  read_only_ = !write;
+  pos_ = 0;
+  return S_OK;
+}
+
+// The path must not be enclosed in quotes. This is the Windows standard.
+// ::GetFileAttributesEx() returns ERROR_INVALID_NAME for quoted paths.
+bool File::Exists(const TCHAR* file_name) {
+  ASSERT1(file_name && *file_name);
+  ASSERT1(lstrlen(file_name) > 0);
+
+  // NOTE: This is the fastest implementation I found.  The results were:
+  //   CreateFile           1783739 avg ticks/call
+  //   FindFirstFile         634148 avg ticks/call
+  //   GetFileAttributes     428714 avg ticks/call
+  //   GetFileAttributesEx   396324 avg ticks/call
+  WIN32_FILE_ATTRIBUTE_DATA attrs = {0};
+  return 0 != ::GetFileAttributesEx(file_name, ::GetFileExInfoStandard, &attrs);
+}
+
+bool File::IsDirectory(const TCHAR* file_name) {
+  ASSERT1(file_name && *file_name);
+
+  WIN32_FILE_ATTRIBUTE_DATA attrs;
+  SetZero(attrs);
+  if (!::GetFileAttributesEx(file_name, ::GetFileExInfoStandard, &attrs)) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[File::IsDirectory - GetFileAttributesEx failed][%s][0x%x]"),
+              file_name, HRESULTFromLastError()));
+    return false;
+  }
+
+  return (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+HRESULT File::GetWildcards(const TCHAR* dir,
+                           const TCHAR* wildcard,
+                           std::vector<CString>* matching_paths) {
+  ASSERT1(dir && *dir);
+  ASSERT1(wildcard && *wildcard);
+  ASSERT1(matching_paths);
+
+  matching_paths->clear();
+
+  // Make sure directory name ends with "\"
+  CString directory = String_MakeEndWith(dir, _T("\\"), false);
+
+  WIN32_FIND_DATA find_data;
+  SetZero(find_data);
+  scoped_hfind hfind(::FindFirstFile(directory + wildcard, &find_data));
+  if (!hfind) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(L5, (_T("[File::GetWildcards - FindFirstFile failed][0x%x]"), hr));
+    return hr;
+  }
+  do {
+    if (find_data.dwFileAttributes == FILE_ATTRIBUTE_NORMAL ||
+        !(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+      CString to_file(directory + find_data.cFileName);
+      matching_paths->push_back(to_file);
+    }
+  } while (::FindNextFile(get(hfind), &find_data));
+
+  HRESULT hr = HRESULTFromLastError();
+  if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES)) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[File::GetWildcards - FindNextFile failed][0x%x]"), hr));
+    return hr;
+  }
+  return S_OK;
+}
+
+// returns error if cannot remove
+// returns success if removed or already removed
+HRESULT File::Remove(const TCHAR* file_name) {
+  ASSERT1(file_name && *file_name);
+
+  if (!Exists(file_name)) {
+    return S_OK;
+  }
+
+  if (!::DeleteFile(file_name)) {
+    return HRESULTFromLastError();
+  }
+
+  return S_OK;
+}
+
+HRESULT File::CopyWildcards(const TCHAR* from_dir,
+                            const TCHAR* to_dir,
+                            const TCHAR* wildcard,
+                            bool replace_existing_files) {
+  ASSERT1(from_dir && *from_dir);
+  ASSERT1(to_dir && *to_dir);
+  ASSERT1(wildcard && *wildcard);
+
+  // Make sure dir names end with a "\"
+  CString from_directory = String_MakeEndWith(from_dir, _T("\\"), false);
+  CString to_directory = String_MakeEndWith(to_dir, _T("\\"), false);
+
+  // Get full path to source files (which is a wildcard)
+  CString from_files(from_directory + wildcard);
+
+  // Run over all files that match wildcard
+  WIN32_FIND_DATA find_data;
+  SetZero(find_data);
+
+  scoped_hfind hfind(::FindFirstFile(from_files, &find_data));
+  if (!hfind) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[File::CopyWildcards - FindFirstFile failed][0x%x]"), hr));
+    return hr;
+  }
+  do {
+    // Copy files
+    if (find_data.dwFileAttributes == FILE_ATTRIBUTE_NORMAL ||
+        !(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+      CString from_file(from_directory + find_data.cFileName);
+      CString to_file(to_directory + find_data.cFileName);
+
+      if (!replace_existing_files && Exists(to_file)) {
+        // Continue, since the caller has explicitly asked us to not replace an
+        // existing file
+        continue;
+      }
+
+      RET_IF_FAILED(Copy(from_file, to_file, replace_existing_files));
+    }
+  } while (::FindNextFile(get(hfind), &find_data));
+
+  HRESULT hr = HRESULTFromLastError();
+  if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES)) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[File::CopyWildcards - FindNextFile failed][0x%x]"), hr));
+    return hr;
+  }
+  return S_OK;
+}
+
+HRESULT File::CopyTree(const TCHAR* from_dir,
+                       const TCHAR* to_dir,
+                       bool replace_existing_files) {
+  ASSERT1(from_dir && *from_dir);
+  ASSERT1(to_dir && *to_dir);
+
+  UTIL_LOG(L3, (L"[File::CopyTree][from_dir %s][to_dir %s][replace %d]",
+                from_dir, to_dir, replace_existing_files));
+
+  // Make sure dir names end with a "\"
+  CString from_directory(String_MakeEndWith(from_dir, L"\\", false));
+  CString to_directory(String_MakeEndWith(to_dir, L"\\", false));
+
+  RET_IF_FAILED(CreateDir(to_directory, NULL));
+  RET_IF_FAILED(CopyWildcards(from_directory,
+                              to_directory,
+                              L"*.*",
+                              replace_existing_files));
+
+  // Run over all directories
+  WIN32_FIND_DATA find_data;
+  SetZero(find_data);
+
+  CString from_files(from_directory);
+  from_files += _T("*.*");
+
+  scoped_hfind hfind(::FindFirstFile(from_files, &find_data));
+  if (!hfind) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[File::CopyTree - FindFirstFile failed][0x%x]"), hr));
+    return hr;
+  }
+  do {
+    // Copy files
+    if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0 &&
+        String_StrNCmp(find_data.cFileName, L"..", 2, false) &&
+        String_StrNCmp(find_data.cFileName, L".", 2, false)) {
+      CString from_subdir(from_directory + find_data.cFileName);
+      CString to_subdir(to_directory + find_data.cFileName);
+      RET_IF_FAILED(CopyTree(from_subdir, to_subdir, replace_existing_files));
+    }
+  } while (::FindNextFile(get(hfind), &find_data));
+
+  HRESULT hr = HRESULTFromLastError();
+  if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES)) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[File::CopyTree - FindNextFile failed][0x%x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT File::Copy(const TCHAR* from,
+                   const TCHAR* to,
+                   bool replace_existing_file) {
+  ASSERT1(from && *from);
+  ASSERT1(to && *to);
+
+  if (!replace_existing_file && Exists(to)) {
+    // Return success, since the caller has explicitly asked us to not replace
+    // an existing file
+    return S_OK;
+  }
+
+  if (!::CopyFile(from, to, !replace_existing_file)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[File::Copy - CopyFile failed]")
+                           _T("[from=%s][to=%s][replace=%u][0x%x]"),
+                           from, to, replace_existing_file, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// TODO(omaha): Combine common code in Move/MoveAfterReboot
+HRESULT File::Move(const TCHAR* from,
+                   const TCHAR* to,
+                   bool replace_existing_file) {
+  ASSERT1(from && *from);
+  ASSERT1(to && *to);
+
+  DWORD flags = MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH;
+  if (replace_existing_file) {
+    flags |= MOVEFILE_REPLACE_EXISTING;
+  }
+
+  if (!::MoveFileEx(from, to, flags)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[File::Move - MoveFileEx failed]")
+              _T("[from=%s][to=%s][replace=%u][0x%x]"),
+              from, to, replace_existing_file, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// DeleteAfterReboot tries to delete the files by either moving them to the TEMP
+// directory and deleting them on reboot, or if that fails, by trying to delete
+// them in-place on reboot
+HRESULT File::DeleteAfterReboot(const TCHAR* from) {
+  ASSERT1(from && *from);
+
+  if (File::Exists(from)) {
+    HRESULT hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+    CString from_temp;
+
+    // No point in moving into TEMP if we're already there
+    if (!String_StartsWith(from, app_util::GetTempDir(), true)) {
+      // Try to move to the TEMP directory first
+      CString temp_dir(String_MakeEndWith(app_util::GetTempDir(),
+                                          _T("\\"),
+                                          false));
+      // Of the form "C:\\Windows\\Temp\\FROM.EXE1f4c0b7f"
+      from_temp.Format(_T("%s%s%x"),
+                       temp_dir,
+                       GetFileFromPath(from),
+                       ::GetTickCount());
+
+      hr = File::Move(from, from_temp, true);
+      UTIL_LOG(L2, (_T("[File::DeleteAfterReboot - move %s to %s][0x%x]"),
+                    from, from_temp, hr));
+    }
+
+    if (SUCCEEDED(hr)) {
+      UTIL_LOG(L2, (_T("[File::DeleteAfterReboot - delete %s after reboot]"),
+                    from_temp));
+      // Move temp file after reboot
+      if (FAILED(hr = File::MoveAfterReboot(from_temp, NULL))) {
+        UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")
+                               _T("[failed to delete after reboot %s][0x%x]"),
+                               from_temp, hr));
+      }
+    } else  {
+      // Move original file after reboot
+      if (FAILED(hr = File::MoveAfterReboot(from, NULL))) {
+        UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")
+                               _T("[failed to delete after reboot %s][0x%x]"),
+                               from, hr));
+      }
+    }
+
+    return hr;
+  }
+
+  return S_OK;
+}
+
+
+HRESULT File::MoveAfterReboot(const TCHAR* from, const TCHAR* to) {
+  ASSERT1(from && *from);
+
+  if (!File::Exists(from)) {
+    // File/directory doesn't exist, should this return failure or success?
+    // Decision:  Failure.  Because the caller can decide if it is really
+    // failure or not in his specific case.
+    UTIL_LOG(LEVEL_WARNING, (_T("[File::MoveAfterReboot]")
+                             _T("[file doesn't exist][from %s]"), from));
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+
+  DWORD flags = MOVEFILE_DELAY_UNTIL_REBOOT;
+  if (!File::IsDirectory(from)) {
+    // This flag valid only for files
+    flags |= MOVEFILE_REPLACE_EXISTING;
+  }
+
+  if (!::MoveFileEx(from, to, flags)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[File::MoveAfterReboot]")
+                           _T("[failed to MoveFileEx from '%s' to '%s'][0x%x]"),
+                           from, to, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// See if we have any moves pending a reboot. Return SUCCESS if we do
+// not encounter errors (not finding a move is not an error). We need to
+// also check the value of *found_ptr for whether we actually found a move.
+// On return, *value_multisz_ptr is the value within
+// "PendingFileRenameOperations", but with any moves for in_directory removed
+// from it.
+// The prefix_match boolean controls whether we do an exact match on
+// in_directory, or remove all entries with the in_directory prefix.
+// NOTE: If the only values found were our own keys, the whole
+// PendingFileRenameOperations MULTISZ needs to be deleted.
+// This is signified by a returned *value_size_chars_ptr of 0.
+HRESULT File::GetPendingRenamesValueMinusDir(const TCHAR* in_directory,
+                                             bool prefix_match,
+                                             TCHAR** value_multisz_ptr,
+                                             DWORD* value_size_chars_ptr,
+                                             bool* found_ptr) {
+  ASSERT1(in_directory && *in_directory);
+
+  // Convert to references for easier-to-read-code:
+  TCHAR*& value_multisz = *value_multisz_ptr;
+  DWORD& value_size_chars = *value_size_chars_ptr;
+  bool& found = *found_ptr;
+
+  // Initialize [out] parameters
+  value_multisz = NULL;
+  value_size_chars = 0;
+  found = false;
+
+  // Locals mirroring the [out] parameters.
+  // We will only set the corresponding [out] parameters when we have something
+  // meaningful to return to the caller
+  scoped_array<TCHAR> value_multisz_local;
+  DWORD value_size_chars_local = 0;
+
+  DWORD value_size_bytes = 0;
+  // Get the current value of the key
+  // If the Key is missing, that's totally acceptable.
+  RET_IF_FALSE(
+      RegKey::HasValue(kSessionManagerKey, kPendingFileRenameOps) &&
+      SUCCEEDED(RegKey::GetValue(kSessionManagerKey,
+                                 kPendingFileRenameOps,
+                                 reinterpret_cast<byte**>(&value_multisz_local),
+                                 &value_size_bytes)),
+      S_OK);
+
+  ASSERT1(value_multisz_local.get() || value_size_bytes == 0);
+  UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")
+                _T("[read multisz %d bytes]"),
+                value_size_bytes));
+  RET_IF_FALSE(value_size_bytes > 0, S_OK);
+
+  // The size should always be aligned to a TCHAR boundary, otherwise the key
+  // is corrupted.
+  ASSERT1((value_size_bytes % sizeof(TCHAR)) == 0);
+  RET_IF_FALSE((value_size_bytes % sizeof(TCHAR)) == 0,
+               HRESULT_FROM_WIN32(ERROR_BADKEY));
+  // Valid size, so convert to TCHARs:
+  value_size_chars_local = value_size_bytes / sizeof(TCHAR);
+
+  // Buffer must terminate with two nulls
+  ASSERT(value_size_chars_local >= 2 &&
+         !value_multisz_local[value_size_chars_local - 1] &&
+         !value_multisz_local[value_size_chars_local - 2],
+         (_T("buffer must terminate with two nulls")));
+  RET_IF_FALSE(value_size_chars_local >= 2 &&
+               !value_multisz_local[value_size_chars_local - 1] &&
+               !value_multisz_local[value_size_chars_local - 2],
+               HRESULT_FROM_WIN32(ERROR_BADKEY));
+  // Mark the end of the string.
+  // multisz_end will point at the character past end of buffer:
+  TCHAR* multisz_end = value_multisz_local.get() + value_size_chars_local;
+
+  // We're looking for \??\C:\...  The \??\ was
+  // added by the OS to the directory name we specified.
+  CString from_dir(_T("\\??\\"));
+  from_dir += in_directory;
+  DWORD from_dir_len = from_dir.GetLength();
+
+  // A MULTISZ is a list of null terminated strings, terminated by a double
+  // null.  We keep two pointers marching along the string in parallel.
+  TCHAR* str_read = value_multisz_local.get();
+  TCHAR* str_write = str_read;
+
+  while ((str_read < multisz_end) && *str_read) {
+    size_t str_len = ::lstrlen(str_read);
+  // A FALSE here indicates a corrupt PendingFileRenameOperations
+    RET_IF_FALSE((str_read + str_len + 1) < multisz_end,
+      HRESULT_FROM_WIN32(ERROR_BADKEY));
+    if (0 == String_StrNCmp(str_read,
+                            from_dir,
+                            from_dir_len + (prefix_match ? 0 : 1),
+                            true)) {
+      // String matches, we want to remove this string, so advance only the
+      // read pointer - past this string and the replacement string.
+      UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")
+                    _T("[skips past match '%s']"),
+                    str_read));
+      str_read += str_len + 1;
+      str_read += ::lstrlen(str_read) + 1;
+      continue;
+    }
+    // String doesn't match, we want to keep it.
+    if (str_read != str_write) {
+      // Here we're not in sync in the buffer, we've got to move two
+      // strings down.
+      UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")
+                    _T("[copying some other deletion][%s][%s]"),
+                    str_read, str_read + ::lstrlen(str_read) + 1));
+      ASSERT1(str_write < str_read);
+      String_StrNCpy(str_write, str_read, str_len+1);
+      str_read += str_len + 1;
+      str_write += str_len + 1;
+      str_len = ::lstrlen(str_read);
+      String_StrNCpy(str_write, str_read, str_len+1);
+      str_read += str_len + 1;
+      str_write += str_len + 1;
+    } else {
+      // We're in sync in the buffer, advance both pointers past two strings
+      UTIL_LOG(L5, (_T("[File::GetPendingRenamesValueMinusDir]")
+                    _T("[skipping past some other deletion][%s][%s]"),
+                    str_read, str_read + ::lstrlen(str_read) + 1));
+      str_read += str_len + 1;
+      str_read += ::lstrlen(str_read) + 1;
+      str_write = str_read;
+    }
+  }
+
+  // A FALSE here indicates a corrupt PendingFileRenameOperations
+  RET_IF_FALSE(str_read < multisz_end,
+    HRESULT_FROM_WIN32(ERROR_BADKEY));
+
+  if (str_read != str_write) {
+    // We found some values
+    found = true;
+
+    if (str_write == value_multisz_local.get()) {
+      // The only values were our own keys,
+      // and the whole PendingFileRenameOperations
+      // value needs to be deleted. We do not populate
+      // value_size_chars or value_multisz in this case.
+      ASSERT1(!value_size_chars);
+      ASSERT1(!value_multisz);
+    } else  {
+      // The last string should have a NULL terminator:
+      ASSERT1(str_write[-1] == '\0');
+      RET_IF_FALSE(str_write[-1] == '\0',
+        HRESULT_FROM_WIN32(ERROR_INVALID_DATA));
+      // a REG_MULTI_SZ needs to be terminated with an extra NULL.
+      *str_write = '\0';
+      ++str_write;
+
+      // Populate value_size_chars and value_multisz in this case.
+      value_multisz = value_multisz_local.release();
+      value_size_chars = str_write - value_multisz;
+    }
+  }
+
+  return S_OK;
+}
+
+// Remove any moves pending a reboot from the PendingFileRenameOperations
+// in the registry.
+// The prefix_match boolean controls whether we do an exact match on
+// in_directory, or remove all entries with the in_directory prefix.
+HRESULT File::RemoveFromMovesPendingReboot(const TCHAR* in_directory,
+                                           bool prefix_match) {
+  ASSERT1(in_directory && *in_directory);
+
+  bool found = false;
+  // scoped_array will free the value_multisz buffer on stack unwind:
+  scoped_array<TCHAR> value_multisz;
+  DWORD value_size_chars = 0;
+  HRESULT hr = GetPendingRenamesValueMinusDir(in_directory,
+                                              prefix_match,
+                                              address(value_multisz),
+                                              &value_size_chars,
+                                              &found);
+  if (SUCCEEDED(hr) && found) {
+    if (value_multisz.get() == NULL)  {
+      // There's no point in writing an empty value_multisz.
+      // Let's delete the PendingFileRenameOperations value
+      UTIL_LOG(L5, (_T("[File::RemoveFromMovesPendingReboot]")
+                    _T("[deleting PendingFileRenameOperations value]")));
+      RET_IF_FAILED(RegKey::DeleteValue(kSessionManagerKey,
+                    kPendingFileRenameOps));
+    } else  {
+      // Let's write the modified value_multisz into the
+      // PendingFileRenameOperations value
+      UTIL_LOG(L5, (_T("[File::RemoveFromMovesPendingReboot]")
+                    _T("[rewriting multisz %d bytes]"),
+                    value_size_chars * sizeof(TCHAR)));
+      RET_IF_FAILED(RegKey::SetValueMultiSZ(
+          kSessionManagerKey,
+          kPendingFileRenameOps,
+          reinterpret_cast<byte*>(value_multisz.get()),
+          value_size_chars * sizeof(TCHAR)));
+    }
+  }
+
+  // Failure of GetPendingRenamesValueMinusDir() may indicate something
+  // seriously wrong with the system. Propogate error.
+  return hr;
+}
+
+// Did the user try to uninstall a previous install of the same version, and
+// we couldn't clean up without a reboot?
+// We check if there are any moves pending a reboot from the
+// PendingFileRenameOperations in the registry.
+// The prefix_match boolean controls whether we do an exact match on
+// in_directory, or check all entries with the in_directory prefix.
+bool File::AreMovesPendingReboot(const TCHAR* in_directory, bool prefix_match) {
+  ASSERT1(in_directory && *in_directory);
+
+  bool found = false;
+  // scoped_array will free the value_multisz buffer on stack unwind:
+  scoped_array<TCHAR> value_multisz;
+  DWORD value_size_chars = 0;
+
+  if (SUCCEEDED(GetPendingRenamesValueMinusDir(in_directory,
+                                               prefix_match,
+                                               address(value_multisz),
+                                               &value_size_chars,
+                                               &found)) && found) {
+    return true;
+  }
+
+  return false;
+}
+
+HRESULT File::GetFileTime(const TCHAR* file_name,
+                          FILETIME* created,
+                          FILETIME* accessed,
+                          FILETIME* modified) {
+  ASSERT1(file_name && *file_name);
+
+  bool is_dir = IsDirectory(file_name);
+  // To obtain a handle to a directory, call the CreateFile function with
+  // the FILE_FLAG_BACKUP_SEMANTICS flag
+  scoped_hfile file_handle(
+      ::CreateFile(file_name,
+                   FILE_READ_DATA,
+                   FILE_SHARE_READ,
+                   NULL,
+                   OPEN_EXISTING,
+                   is_dir ? FILE_FLAG_BACKUP_SEMANTICS : NULL,
+                   NULL));
+  HRESULT hr = S_OK;
+
+  if (!file_handle) {
+    hr = HRESULTFromLastError();
+    UTIL_LOG(LE, (_T("[File::GetFileTime]")
+                  _T("[failed to open file][%s][0x%x]"), file_name, hr));
+  } else {
+    if (!::GetFileTime(get(file_handle), created, accessed, modified)) {
+      hr = HRESULTFromLastError();
+      UTIL_LOG(LEVEL_ERROR, (_T("[File::GetFileTime]")
+                             _T("[failed to get file time][%s][0x%x]"),
+                             file_name, hr));
+    }
+  }
+
+  return hr;
+}
+
+HRESULT File::SetFileTime(const TCHAR* file_name,
+                          const FILETIME* created,
+                          const FILETIME* accessed,
+                          const FILETIME* modified) {
+  ASSERT1(file_name && *file_name);
+
+  bool is_dir = IsDirectory(file_name);
+  // To obtain a handle to a directory, call the CreateFile function with
+  // the FILE_FLAG_BACKUP_SEMANTICS flag
+  scoped_hfile file_handle(
+      ::CreateFile(file_name,
+                   FILE_WRITE_ATTRIBUTES,
+                   FILE_SHARE_WRITE,
+                   NULL,
+                   OPEN_EXISTING,
+                   is_dir ? FILE_FLAG_BACKUP_SEMANTICS : NULL,
+                   NULL));
+  HRESULT hr = S_OK;
+
+  if (!file_handle) {
+    hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[File::GetFileTime]")
+                           _T("[failed to open file][%s][0x%x]"),
+                           file_name, hr));
+  } else {
+    BOOL res = ::SetFileTime(get(file_handle), created, accessed, modified);
+    if (!res) {
+      hr = HRESULTFromLastError();
+      UTIL_LOG(LEVEL_ERROR, (_T("[File::SetFileTime]")
+                             _T("[failed to set file time][%s][0x%x]"),
+                             file_name, hr));
+    }
+  }
+
+  return hr;
+}
+
+HRESULT File::Sync() {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+
+  if (!::FlushFileBuffers(handle_)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[File::Sync]")
+                           _T("[FlushFileBuffers failed][%s][0x%x]"),
+                           file_name_, hr));
+    return hr;
+  }
+  return S_OK;
+}
+
+HRESULT File::SeekToBegin() {
+  return SeekFromBegin(0);
+}
+
+HRESULT File::SeekFromBegin(uint32 n) {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+
+  if (::SetFilePointer(handle_, n, NULL, FILE_BEGIN) ==
+      INVALID_SET_FILE_POINTER) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[File::SeekFromBegin]")
+                           _T("[SetFilePointer failed][%s][0x%x]"),
+                           file_name_, hr));
+    return hr;
+  }
+  pos_ = n;
+  return S_OK;
+}
+
+// read nLen bytes starting at position n
+// returns number of bytes read
+//
+// async operations:
+//
+// async_id - identifier of a sequence of async operations, 0 for synchronous
+//
+// if the async operation has not been initiated, we initiate it
+// if it is in progress we do nothing
+// if it has been completed we return the data
+// does not delete async data entry
+HRESULT File::ReadAt(const uint32 offset, byte* buf, const uint32 len,
+                     const uint32, uint32* bytes_read) {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+  ASSERT1(buf);
+  ASSERT1(len);  // reading 0 bytes is not valid (differs from CRT API)
+
+  RET_IF_FAILED(SeekFromBegin(offset));
+
+  DWORD read = 0;
+  if (!::ReadFile(handle_, buf, len, &read, NULL)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[File::ReadAt]")
+                           _T("[ReadFile failed][%s][0x%x]"), file_name_, hr));
+    return hr;
+  }
+
+  if (bytes_read) {
+    *bytes_read = read;
+  }
+
+  return (read == len) ? S_OK : E_FAIL;
+}
+
+
+// reads up to max_len bytes from the start of the file
+// not considered an error if there are less than max_len bytes read
+// returns number of bytes read
+HRESULT File::ReadFromStartOfFile(const uint32 max_len,
+                                  byte* buf,
+                                  uint32* bytes_read) {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+  ASSERT1(buf);
+  ASSERT1(max_len);
+
+  RET_IF_FAILED(SeekFromBegin(0));
+
+  uint32 file_len = 0;
+  RET_IF_FAILED(GetLength(&file_len));
+
+  if (!file_len) {
+    if (bytes_read) {
+      *bytes_read = 0;
+    }
+    return S_OK;
+  }
+
+  uint32 len = max_len;
+  if (len > file_len) {
+    len = static_cast<uint32>(file_len);
+  }
+
+  return Read(len, buf, bytes_read);
+}
+
+// this function handles lines terminated with LF or CRLF
+// all CR characters are removed from each line, and LF is assumed
+// to be the end of line and is removed
+HRESULT File::ReadLineAnsi(uint32 max_len, char* line, uint32* len) {
+  ASSERT1(line);
+  ASSERT1(max_len);
+
+  char c = 0;
+  uint32 len_read = 0;
+  uint32 total_len = 0;
+
+  while (SUCCEEDED(Read(1, reinterpret_cast<byte *>(&c), &len_read)) &&
+         len_read  &&
+         c != '\n') {
+    if (total_len < max_len - 1 && c != '\r') {
+      line[total_len++] = c;
+    }
+  }
+
+  ASSERT1(total_len < max_len);
+  line[total_len] = '\0';
+
+  if (len) {
+    *len = total_len;
+  }
+
+  return (len_read || total_len) ? S_OK : E_FAIL;
+}
+
+// used by ReadFromStartOfFile and ReadLineAnsi; not reading all requested bytes
+// is not considered fatal
+HRESULT File::Read(const uint32 len, byte* buf, uint32* bytes_read) {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+  ASSERT1(buf);
+  ASSERT1(len);
+
+  DWORD read = 0;
+  if (!::ReadFile(handle_, buf, len, &read, NULL)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[File::ReadAt]")
+                           _T("[ReadFile failed][%s][0x%x]"),
+                           file_name_, hr));
+    return hr;
+  }
+
+  if (bytes_read) {
+    *bytes_read = read;
+  }
+
+  return S_OK;
+}
+
+
+// returns number of bytes written
+HRESULT File::WriteAt(const uint32 offset,
+                      const byte* buf,
+                      const uint32 len,
+                      uint32,
+                      uint32* bytes_written) {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+  ASSERT1(!read_only_);
+  ASSERT1(buf);
+  ASSERT1(len);
+
+  RET_IF_FAILED(SeekFromBegin(offset));
+
+  return Write(buf, len, bytes_written);
+}
+
+
+// write buffer n times
+HRESULT File::WriteN(const byte* buf,
+                     const uint32 len,
+                     const uint32 n,
+                     uint32* bytes_written) {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+  ASSERT1(!read_only_);
+  ASSERT1(buf);
+  ASSERT1(len);
+  ASSERT1(n);
+
+  HRESULT hr = S_OK;
+
+  uint32 total_wrote = 0;
+
+  byte* temp_buf = const_cast<byte*>(buf);
+
+  scoped_array<byte> encrypt_buf;
+
+  uint32 to_go = n;
+  while (to_go) {
+    uint32 wrote = 0;
+    hr = Write(temp_buf, len, &wrote);
+    if (FAILED(hr)) {
+      if (bytes_written) {
+        *bytes_written = total_wrote;
+      }
+      return hr;
+    }
+
+    total_wrote += wrote;
+    to_go--;
+  }
+
+  if (bytes_written) {
+    *bytes_written = total_wrote;
+  }
+  return hr;
+}
+
+// returns number of bytes written
+HRESULT File::Write(const byte* buf, const uint32 len, uint32* bytes_written) {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+  ASSERT1(!read_only_);
+  ASSERT1(buf);
+  ASSERT1(len);  // writing 0 bytes is not valid (differs from CRT API)
+
+  byte* b = const_cast<byte*>(buf);
+
+  scoped_array<byte> encrypt_buf;
+
+  DWORD wrote = 0;
+  if (!::WriteFile(handle_, b, len, &wrote, NULL)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[File::Write]")
+                           _T("[WriteFile failed][%s][0x%x]"),
+                           file_name_, hr));
+    return hr;
+  }
+
+  if (bytes_written) {
+    *bytes_written = wrote;
+  }
+  pos_ += wrote;
+
+  return (wrote == len) ? S_OK : E_FAIL;
+}
+
+HRESULT File::ClearAt(const uint32 offset,
+                      const uint32 len,
+                      uint32* bytes_written) {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+  ASSERT1(!read_only_);
+  ASSERT1(len);
+
+  byte zero[kZeroSize] = {0};
+  uint32 to_go = len;
+  uint32 written = 0;
+  uint32 pos = offset;
+
+  while (to_go) {
+    uint32 wrote = 0;
+    uint32 write_len = std::min(to_go, kZeroSize);
+    RET_IF_FAILED(WriteAt(pos, zero, write_len, 0, &wrote));
+
+    if (wrote != write_len) {
+      return E_FAIL;
+    }
+    pos += wrote;
+    written += wrote;
+    to_go -= write_len;
+  }
+
+  if (bytes_written) {
+    *bytes_written = written;
+  }
+  return S_OK;
+}
+
+// returns true on failure
+// zeros new data if zero_data == true
+HRESULT File::SetLength(const uint32 n, bool zero_data) {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+  ASSERT1(!read_only_);
+  ASSERT1(n <= kMaxFileSize);
+
+  HRESULT hr = S_OK;
+
+  uint32 len = 0;
+  VERIFY1(SUCCEEDED(GetLength(&len)));
+
+  if (len == n) {
+    return S_OK;
+  }
+
+  // according to the documentation, the
+  // new space will not be initialized
+  if (n > len) {
+    if (zero_data) {
+      uint32 bytes_written = 0;
+      RET_IF_FAILED(ClearAt(len, n - len, &bytes_written));
+      if (bytes_written != n - len) {
+        return E_FAIL;
+      }
+    } else {
+      byte zero = 0;
+      uint32 bytes_written = 0;
+      RET_IF_FAILED(WriteAt(n - 1, &zero, 1, 0, &bytes_written));
+      if (bytes_written != 1) {
+        return E_FAIL;
+      }
+    }
+  } else {
+    SeekFromBegin(n);
+    SetEndOfFile(handle_);
+  }
+
+  ASSERT1(SUCCEEDED(GetLength(&len)) && len == n);
+
+  return S_OK;
+}
+
+HRESULT File::ExtendInBlocks(const uint32 block_size, uint32 size_needed,
+                             uint32* new_size, bool clear_new_space) {
+  ASSERT1(new_size);
+
+  *new_size = size_needed;
+
+  if (*new_size % block_size) {
+    *new_size += block_size - (*new_size % block_size);
+  }
+
+  // is zero_data needed? may reduce fragmentation by causing the block to
+  // be written
+  return SetLength(*new_size, clear_new_space);
+}
+
+// returns S_OK on success
+HRESULT File::GetLength(uint32* length) {
+  ASSERT1(length);
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+
+  DWORD len = GetFileSize(handle_, NULL);
+  if (len == INVALID_FILE_SIZE) {
+    ASSERT(false, (_T("cannot get file length")));
+    return E_FAIL;
+  }
+  *length = len;
+  return S_OK;
+}
+
+HRESULT File::Touch() {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+
+  FILETIME file_time;
+  SetZero(file_time);
+
+  ::GetSystemTimeAsFileTime(&file_time);
+
+  if (!::SetFileTime(handle_, NULL, NULL, &file_time)) {
+    return HRESULTFromLastError();
+  }
+  return S_OK;
+}
+
+HRESULT File::Close() {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+
+  HRESULT hr = S_OK;
+  if (!::CloseHandle(handle_)) {
+    hr = HRESULTFromLastError();
+  }
+
+  handle_ = INVALID_HANDLE_VALUE;
+
+  return hr;
+}
+
+// this is just for consistency with other classes; does not do anything
+HRESULT File::Reload(uint32* number_errors) {
+  ASSERT1(number_errors);
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+
+  *number_errors = 0;
+  return S_OK;
+}
+
+// this is just for consistency with other classes; does not do anything
+HRESULT File::Verify(uint32* number_errors) {
+  ASSERT1(number_errors);
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+
+  *number_errors = 0;
+  return S_OK;
+}
+
+// this is just for consistency with other classes; does not do anything
+HRESULT File::Dump() {
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+  return S_OK;
+}
+
+// for consistency with other classes
+HRESULT File::GetSizeOnDisk(uint64* size_on_disk) {
+  ASSERT1(size_on_disk);
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+
+  uint32 len = 0;
+  RET_IF_FAILED(GetLength(&len));
+
+  *size_on_disk = len;
+  return S_OK;
+}
+
+// for consistency with other classes
+HRESULT File::GetReloadDiskSpaceNeeded(uint64* bytes_needed) {
+  ASSERT1(bytes_needed);
+  ASSERT1(handle_ != INVALID_HANDLE_VALUE);
+
+  uint32 len = 0;
+  RET_IF_FAILED(GetLength(&len));
+
+  *bytes_needed = len;
+  return S_OK;
+}
+
+// Get the file size
+HRESULT File::GetFileSizeUnopen(const TCHAR* filename, uint32* out_size) {
+  ASSERT1(filename);
+  ASSERT1(out_size);
+
+  WIN32_FILE_ATTRIBUTE_DATA data;
+  SetZero(data);
+
+  if (!::GetFileAttributesEx(filename, ::GetFileExInfoStandard, &data)) {
+    return HRESULTFromLastError();
+  }
+
+  *out_size = data.nFileSizeLow;
+
+  return S_OK;
+}
+
+// Get the last time with a file was written to, and the size
+HRESULT File::GetLastWriteTimeAndSize(const TCHAR* file_path,
+                                      SYSTEMTIME* out_time,
+                                      unsigned int* out_size) {
+  ASSERT1(file_path);
+
+  WIN32_FIND_DATA wfd;
+  SetZero(wfd);
+
+  HANDLE find = ::FindFirstFile(file_path, &wfd);
+  if (find == INVALID_HANDLE_VALUE) {
+    return HRESULTFromLastError();
+  }
+
+  ::FindClose(find);
+
+  if (out_size) {
+    *out_size = wfd.nFileSizeLow;
+  }
+
+  if (out_time) {
+    // If created time is newer than write time, then use that instead
+    // [it tends to be more relevant when copying files around]
+    FILETIME* latest_time = NULL;
+    if (::CompareFileTime(&wfd.ftCreationTime, &wfd.ftLastWriteTime) > 0) {
+      latest_time = &wfd.ftCreationTime;
+    } else {
+      latest_time = &wfd.ftLastWriteTime;
+    }
+
+    if (!::FileTimeToSystemTime(latest_time, out_time)) {
+      return HRESULTFromLastError();
+    }
+  }
+
+  return S_OK;
+}
+
+FileLock::FileLock() {
+}
+
+FileLock::~FileLock() {
+  Unlock();
+}
+
+HRESULT FileLock::Lock(const TCHAR* file) {
+  std::vector<CString> files;
+  files.push_back(file);
+  return Lock(files);
+}
+
+HRESULT FileLock::Lock(const std::vector<CString>& files) {
+  ASSERT1(!files.empty());
+
+  // Try to lock all files
+  size_t curr_size = handles_.size();
+  for (size_t i = 0; i < files.size(); ++i) {
+    scoped_hfile handle(::CreateFile(files[i],
+                                     GENERIC_READ,
+                                     FILE_SHARE_READ,
+                                     NULL,
+                                     OPEN_EXISTING,
+                                     FILE_ATTRIBUTE_NORMAL,
+                                     NULL));
+    if (!handle) {
+      UTIL_LOG(LEVEL_ERROR,
+               (_T("[FileLock::Lock - failed to lock file][%s][0x%x]"),
+                files[i], HRESULTFromLastError()));
+      break;
+    }
+    handles_.push_back(release(handle));
+  }
+
+  // Cleanup if we fail to lock all the files
+  if (curr_size +  files.size() < handles_.size()) {
+    for (size_t i = handles_.size() - 1; i >= curr_size; --i) {
+      VERIFY(::CloseHandle(handles_[i]), (_T("")));
+      handles_.pop_back();
+    }
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+HRESULT FileLock::Unlock() {
+  for (size_t i = 0; i < handles_.size(); ++i) {
+    VERIFY(::CloseHandle(handles_[i]), (_T("")));
+  }
+  handles_.clear();
+  return S_OK;
+}
+
+
+// path_name: the directory to watch
+// watch_subtree: watch all subdirectory changes  or
+//                only immediate child values
+// notify_filter: See the documentation for FindFirstChangeNotification
+FileWatcher::FileWatcher(const TCHAR* path_name, bool watch_subtree,
+                         DWORD notify_filter)
+    : path_name_(path_name),
+      watch_subtree_(watch_subtree),
+      notify_filter_(notify_filter) {
+  ASSERT1(path_name && *path_name);
+  UTIL_LOG(L3, (_T("[FileWatcher::FileWatcher][%s]"), path_name));
+}
+
+// Get the event that is signaled on store changes.
+HANDLE FileWatcher::change_event() const {
+  ASSERT(valid(change_event_), (_T("call FileWatcher::SetupEvent first")));
+  return get(change_event_);
+}
+
+
+// Called to create/reset the event that gets signaled
+// any time the store changes.  Access the created
+// event using change_event().
+HRESULT FileWatcher::EnsureEventSetup() {
+  UTIL_LOG(L3, (_T("[FileWatcher::EnsureEventSetup]")));
+  if (!valid(change_event_)) {
+    reset(change_event_, ::FindFirstChangeNotification(path_name_,
+                                                       watch_subtree_,
+                                                       notify_filter_));
+    if (!valid(change_event_)) {
+      ASSERT(false, (_T("unable to get file change notification")));
+      return E_FAIL;
+    }
+    // path name was only needed to set-up the event and now that is done....
+    path_name_.Empty();
+    return S_OK;
+  }
+
+  // if the event is set-up and no changes have occurred,
+  // then there is no need to re-setup the event.
+  if (valid(change_event_) && !HasChangeOccurred()) {
+    return NOERROR;
+  }
+
+  return ::FindNextChangeNotification(get(change_event_)) ? S_OK : E_FAIL;
+}
+
+}  // namespace omaha
+
diff --git a/common/file.h b/common/file.h
index 2190875..060b63c 100644
--- a/common/file.h
+++ b/common/file.h
@@ -1,251 +1,251 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// File handling routines

-//

-// encryption is not currently active

-//

-#ifndef OMAHA_COMMON_FILE_H__

-#define OMAHA_COMMON_FILE_H__

-

-#include <windows.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/store_watcher.h"

-

-namespace omaha {

-

-#define kMinimumDiskSpaceRequired 100000000

-// if we hit the minimum at some point, then this is the amount of space we

-// require before restarting indexing (at which point we'll lower the minimum

-// back to the usual level)

-#define kMinimumDiskSpaceRequiredToRestartIndexing \

-        (kMinimumDiskSpaceRequired + 100000000)

-#define kMaxFileSize kInt32Max

-

-class File {

- public:

-

-    File();

-    ~File();

-

-    HRESULT Open(const TCHAR* file_name, bool write, bool async);

-    HRESULT OpenShareMode(const TCHAR* file_name,

-                          bool write,

-                          bool async,

-                          DWORD share_mode);

-

-    HRESULT Close();

-

-    static bool Exists(const TCHAR* file_name);

-    static bool IsDirectory(const TCHAR *file_name);

-    static HRESULT GetWildcards(const TCHAR* dir, const TCHAR* wildcard,

-                                std::vector<CString>* matching_paths);

-    // returns S_OK on successful removal or if not existing

-    static HRESULT Remove(const TCHAR* file_name);

-    // CopyWildcards doesn't work recursively

-    static HRESULT CopyWildcards(const TCHAR* from_dir, const TCHAR* to_dir,

-                                 const TCHAR* wildcard,

-                                 bool replace_existing_files);

-    static HRESULT CopyTree(const TCHAR* from_dir, const TCHAR* to_dir,

-                            bool replace_existing_files);

-                                                    // to_dir need not exist

-    static HRESULT Copy(const TCHAR* from, const TCHAR* to,

-                        bool replace_existing_file);

-    static HRESULT Move(const TCHAR* from, const TCHAR* to,

-                        bool replace_existing_file);

-    // DeleteAfterReboot tries to delete the files by either moving them to

-    // the TEMP directory and deleting them on reboot, or if that fails, by

-    // trying to delete them in-place on reboot

-    static HRESULT DeleteAfterReboot(const TCHAR* from);

-    static HRESULT MoveAfterReboot(const TCHAR* from, const TCHAR* to);

-    // Remove any moves pending a reboot from the PendingFileRenameOperations

-    // in the registry.

-    // The prefix_match boolean controls whether we do an exact match on

-    // in_directory, or remove all entries with the in_directory prefix.

-    static HRESULT RemoveFromMovesPendingReboot(const TCHAR* in_directory,

-                                                bool prefix_match);

-    // Did the user try to uninstall a previous install of the same version,

-    // and we couldn't clean up without a reboot?

-    // We check if there are any moves pending a reboot from the

-    // PendingFileRenameOperations in the registry.

-    // The prefix_match boolean controls whether we do an exact match on

-    // in_directory, or check all entries with the in_directory prefix.

-    static bool AreMovesPendingReboot(const TCHAR* in_directory,

-                                      bool prefix_match);

-

-    // The GetFileTime function retrieves the date and time that a file was

-    // created, last accessed, and last modified. The parameters 'created',

-    // 'accessed', 'modified' can be null if the caller does not require that

-    // information. All times are utc

-    // (http://support.microsoft.com/default.aspx?scid=kb;%5BLN%5D;158588)

-    // To compare FILETIME values, use CompareFileTime API.

-    static HRESULT GetFileTime(const TCHAR* file_name, FILETIME* created,

-                               FILETIME* accessed, FILETIME* modified);

-

-    // Sets the file time

-    static HRESULT SetFileTime(const TCHAR* file_name,

-                               const FILETIME* created,

-                               const FILETIME* accessed,

-                               const FILETIME* modified);

-

-    // sync flushes any pending writes to disk

-    HRESULT Sync();

-    // static HRESULT SyncAllFiles();

-

-    HRESULT SeekToBegin();

-    HRESULT SeekFromBegin(uint32 n);

-

-    HRESULT ReadFromStartOfFile(const uint32 max_len, byte *buf,

-                                uint32 *bytes_read);

-    HRESULT ReadLineAnsi(uint32 max_len, char *line, uint32 *len);

-

-    // read len bytes, reading 0 bytes is invalid

-    HRESULT Read(const uint32 len, byte *buf, uint32 *bytes_read);

-    // read len bytes starting at position n, reading 0 bytes is invalid

-    HRESULT ReadAt(const uint32 offset, byte *buf, const uint32 len,

-                    const uint32 async_id, uint32 *bytes_read);

-

-    // write len bytes, writing 0 bytes is invalid

-    HRESULT Write(const byte *buf, const uint32 len, uint32 *bytes_written);

-    // write len bytes, writing 0 bytes is invalid

-    HRESULT WriteAt(const uint32 offset, const byte *buf, const uint32 len,

-                     const uint32 async_id, uint32 *bytes_written);

-

-    // write buffer n times

-    HRESULT WriteN(const byte *buf, const uint32 len, const uint32 n,

-                    uint32 *bytes_written);

-

-    // zeros section of file

-    HRESULT ClearAt(const uint32 offset, const uint32 len,

-                     uint32 *bytes_written);

-

-    // set length of file

-    // if new length is greater than current length, new data is undefined

-    // unless zero_data == true in which case the new data is zeroed.

-    HRESULT SetLength(const uint32 n, bool zero_data);

-    HRESULT ExtendInBlocks(const uint32 block_size, uint32 size_needed,

-                            uint32 *new_size, bool clear_new_space);

-    HRESULT GetLength(uint32 *len);

-

-    // Sets the last write time to the current time

-    HRESULT Touch();

-

-    // all the data storage classes contain these functions

-    // we implemenent them here for consistency

-    // e.g., so we can do object->GetSizeOnDisk independent of the object type

-    HRESULT GetSizeOnDisk(uint64 *size_on_disk);

-    HRESULT GetReloadDiskSpaceNeeded(uint64 *bytes_needed);

-    HRESULT Reload(uint32 *number_errors);

-    HRESULT Verify(uint32 *number_errors);

-    HRESULT Dump();

-

-    // Gets the size of a file, without opening it [the regular GetFileSize

-    // requires a file handle, which conflicts if the file is already opened

-    // and locked]

-    static HRESULT GetFileSizeUnopen(const TCHAR * filename,

-                                     uint32 * out_size);

-

-    // Optimized function that gets the last write time and size

-    static HRESULT GetLastWriteTimeAndSize(const TCHAR* file_path,

-                                           SYSTEMTIME* out_time,

-                                           unsigned int* out_size);

-

- private:

-    // See if we have any moves pending a reboot. Return SUCCESS if we do

-    // not encounter errors (not finding a move is not an error). We need to

-    // also check the value of *found_ptr for whether we actually found a move.

-    // On return, *value_multisz_ptr is the value within

-    // "PendingFileRenameOperations", but with any moves for in_directory

-    // removed from it.

-    // The prefix_match boolean controls whether we do an exact match on

-    // in_directory, or remove all entries with the in_directory prefix.

-    // NOTE: If the only values found were our own keys, the whole

-    // PendingFileRenameOperations MULTISZ needs to be deleted. This is

-    // signified by a returned *value_size_chars_ptr of 0.

-    static HRESULT GetPendingRenamesValueMinusDir(const TCHAR* in_directory,

-      bool prefix_match, TCHAR** value_multisz_ptr, DWORD* value_size_chars_ptr,

-      bool* found_ptr);

-

-    HANDLE handle_;

-    CString file_name_;

-    bool read_only_;

-    bool sync_write_done_;

-    uint32 pos_;

-    uint32 encryption_seed_;

-    uint32 sequence_id_;

-    enum EncryptionTypes encryption_;

-

-    DISALLOW_EVIL_CONSTRUCTORS(File);

-};

-

-// File lock

-class FileLock {

- public:

-  // Default constructor

-  FileLock();

-

-  // Destructor

-  ~FileLock();

-

-  // Lock a single file

-  HRESULT Lock(const TCHAR* file);

-

-  // Lock multiple files (atomic)

-  HRESULT Lock(const std::vector<CString>& files);

-

-  // Unlock all

-  HRESULT Unlock();

-

- private:

-  std::vector<HANDLE> handles_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(FileLock);

-};

-

-

-// Does the common things necessary for watching

-// changes in a directory.  If there are file change or other watchers,

-// there could be a common interface for the three methods to decouple

-// the code that is doing the watching from the code that owns the store.

-class FileWatcher : public StoreWatcher {

- public:

-  // path_name: the directory to watch

-  // watch_subtree: watch all subdirectory changes  or

-  //                only immediate child values

-  // notify_filter: See the documentation for FindFirstChangeNotification

-  FileWatcher(const TCHAR* path_name, bool watch_subtree, DWORD notify_filter);

-

-  // Called to create/reset the event that gets signaled

-  // any time the store changes.  Access the created

-  // event using change_event().

-  virtual HRESULT EnsureEventSetup();

-

-  // Get the event that is signaled on store changes.

-  virtual HANDLE change_event() const;

-

- private:

-  scoped_hfind_change_notification change_event_;

-  CString path_name_;

-  bool watch_subtree_;

-  DWORD notify_filter_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(FileWatcher);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_FILE_H__

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// File handling routines
+//
+// encryption is not currently active
+//
+#ifndef OMAHA_COMMON_FILE_H__
+#define OMAHA_COMMON_FILE_H__
+
+#include <windows.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/store_watcher.h"
+
+namespace omaha {
+
+#define kMinimumDiskSpaceRequired 100000000
+// if we hit the minimum at some point, then this is the amount of space we
+// require before restarting indexing (at which point we'll lower the minimum
+// back to the usual level)
+#define kMinimumDiskSpaceRequiredToRestartIndexing \
+        (kMinimumDiskSpaceRequired + 100000000)
+#define kMaxFileSize kInt32Max
+
+class File {
+ public:
+
+    File();
+    ~File();
+
+    HRESULT Open(const TCHAR* file_name, bool write, bool async);
+    HRESULT OpenShareMode(const TCHAR* file_name,
+                          bool write,
+                          bool async,
+                          DWORD share_mode);
+
+    HRESULT Close();
+
+    static bool Exists(const TCHAR* file_name);
+    static bool IsDirectory(const TCHAR *file_name);
+    static HRESULT GetWildcards(const TCHAR* dir, const TCHAR* wildcard,
+                                std::vector<CString>* matching_paths);
+    // returns S_OK on successful removal or if not existing
+    static HRESULT Remove(const TCHAR* file_name);
+    // CopyWildcards doesn't work recursively
+    static HRESULT CopyWildcards(const TCHAR* from_dir, const TCHAR* to_dir,
+                                 const TCHAR* wildcard,
+                                 bool replace_existing_files);
+    static HRESULT CopyTree(const TCHAR* from_dir, const TCHAR* to_dir,
+                            bool replace_existing_files);
+                                                    // to_dir need not exist
+    static HRESULT Copy(const TCHAR* from, const TCHAR* to,
+                        bool replace_existing_file);
+    static HRESULT Move(const TCHAR* from, const TCHAR* to,
+                        bool replace_existing_file);
+    // DeleteAfterReboot tries to delete the files by either moving them to
+    // the TEMP directory and deleting them on reboot, or if that fails, by
+    // trying to delete them in-place on reboot
+    static HRESULT DeleteAfterReboot(const TCHAR* from);
+    static HRESULT MoveAfterReboot(const TCHAR* from, const TCHAR* to);
+    // Remove any moves pending a reboot from the PendingFileRenameOperations
+    // in the registry.
+    // The prefix_match boolean controls whether we do an exact match on
+    // in_directory, or remove all entries with the in_directory prefix.
+    static HRESULT RemoveFromMovesPendingReboot(const TCHAR* in_directory,
+                                                bool prefix_match);
+    // Did the user try to uninstall a previous install of the same version,
+    // and we couldn't clean up without a reboot?
+    // We check if there are any moves pending a reboot from the
+    // PendingFileRenameOperations in the registry.
+    // The prefix_match boolean controls whether we do an exact match on
+    // in_directory, or check all entries with the in_directory prefix.
+    static bool AreMovesPendingReboot(const TCHAR* in_directory,
+                                      bool prefix_match);
+
+    // The GetFileTime function retrieves the date and time that a file was
+    // created, last accessed, and last modified. The parameters 'created',
+    // 'accessed', 'modified' can be null if the caller does not require that
+    // information. All times are utc
+    // (http://support.microsoft.com/default.aspx?scid=kb;%5BLN%5D;158588)
+    // To compare FILETIME values, use CompareFileTime API.
+    static HRESULT GetFileTime(const TCHAR* file_name, FILETIME* created,
+                               FILETIME* accessed, FILETIME* modified);
+
+    // Sets the file time
+    static HRESULT SetFileTime(const TCHAR* file_name,
+                               const FILETIME* created,
+                               const FILETIME* accessed,
+                               const FILETIME* modified);
+
+    // sync flushes any pending writes to disk
+    HRESULT Sync();
+    // static HRESULT SyncAllFiles();
+
+    HRESULT SeekToBegin();
+    HRESULT SeekFromBegin(uint32 n);
+
+    HRESULT ReadFromStartOfFile(const uint32 max_len, byte *buf,
+                                uint32 *bytes_read);
+    HRESULT ReadLineAnsi(uint32 max_len, char *line, uint32 *len);
+
+    // read len bytes, reading 0 bytes is invalid
+    HRESULT Read(const uint32 len, byte *buf, uint32 *bytes_read);
+    // read len bytes starting at position n, reading 0 bytes is invalid
+    HRESULT ReadAt(const uint32 offset, byte *buf, const uint32 len,
+                    const uint32 async_id, uint32 *bytes_read);
+
+    // write len bytes, writing 0 bytes is invalid
+    HRESULT Write(const byte *buf, const uint32 len, uint32 *bytes_written);
+    // write len bytes, writing 0 bytes is invalid
+    HRESULT WriteAt(const uint32 offset, const byte *buf, const uint32 len,
+                     const uint32 async_id, uint32 *bytes_written);
+
+    // write buffer n times
+    HRESULT WriteN(const byte *buf, const uint32 len, const uint32 n,
+                    uint32 *bytes_written);
+
+    // zeros section of file
+    HRESULT ClearAt(const uint32 offset, const uint32 len,
+                     uint32 *bytes_written);
+
+    // set length of file
+    // if new length is greater than current length, new data is undefined
+    // unless zero_data == true in which case the new data is zeroed.
+    HRESULT SetLength(const uint32 n, bool zero_data);
+    HRESULT ExtendInBlocks(const uint32 block_size, uint32 size_needed,
+                            uint32 *new_size, bool clear_new_space);
+    HRESULT GetLength(uint32 *len);
+
+    // Sets the last write time to the current time
+    HRESULT Touch();
+
+    // all the data storage classes contain these functions
+    // we implemenent them here for consistency
+    // e.g., so we can do object->GetSizeOnDisk independent of the object type
+    HRESULT GetSizeOnDisk(uint64 *size_on_disk);
+    HRESULT GetReloadDiskSpaceNeeded(uint64 *bytes_needed);
+    HRESULT Reload(uint32 *number_errors);
+    HRESULT Verify(uint32 *number_errors);
+    HRESULT Dump();
+
+    // Gets the size of a file, without opening it [the regular GetFileSize
+    // requires a file handle, which conflicts if the file is already opened
+    // and locked]
+    static HRESULT GetFileSizeUnopen(const TCHAR * filename,
+                                     uint32 * out_size);
+
+    // Optimized function that gets the last write time and size
+    static HRESULT GetLastWriteTimeAndSize(const TCHAR* file_path,
+                                           SYSTEMTIME* out_time,
+                                           unsigned int* out_size);
+
+ private:
+    // See if we have any moves pending a reboot. Return SUCCESS if we do
+    // not encounter errors (not finding a move is not an error). We need to
+    // also check the value of *found_ptr for whether we actually found a move.
+    // On return, *value_multisz_ptr is the value within
+    // "PendingFileRenameOperations", but with any moves for in_directory
+    // removed from it.
+    // The prefix_match boolean controls whether we do an exact match on
+    // in_directory, or remove all entries with the in_directory prefix.
+    // NOTE: If the only values found were our own keys, the whole
+    // PendingFileRenameOperations MULTISZ needs to be deleted. This is
+    // signified by a returned *value_size_chars_ptr of 0.
+    static HRESULT GetPendingRenamesValueMinusDir(const TCHAR* in_directory,
+      bool prefix_match, TCHAR** value_multisz_ptr, DWORD* value_size_chars_ptr,
+      bool* found_ptr);
+
+    HANDLE handle_;
+    CString file_name_;
+    bool read_only_;
+    bool sync_write_done_;
+    uint32 pos_;
+    uint32 encryption_seed_;
+    uint32 sequence_id_;
+    enum EncryptionTypes encryption_;
+
+    DISALLOW_EVIL_CONSTRUCTORS(File);
+};
+
+// File lock
+class FileLock {
+ public:
+  // Default constructor
+  FileLock();
+
+  // Destructor
+  ~FileLock();
+
+  // Lock a single file
+  HRESULT Lock(const TCHAR* file);
+
+  // Lock multiple files (atomic)
+  HRESULT Lock(const std::vector<CString>& files);
+
+  // Unlock all
+  HRESULT Unlock();
+
+ private:
+  std::vector<HANDLE> handles_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(FileLock);
+};
+
+
+// Does the common things necessary for watching
+// changes in a directory.  If there are file change or other watchers,
+// there could be a common interface for the three methods to decouple
+// the code that is doing the watching from the code that owns the store.
+class FileWatcher : public StoreWatcher {
+ public:
+  // path_name: the directory to watch
+  // watch_subtree: watch all subdirectory changes  or
+  //                only immediate child values
+  // notify_filter: See the documentation for FindFirstChangeNotification
+  FileWatcher(const TCHAR* path_name, bool watch_subtree, DWORD notify_filter);
+
+  // Called to create/reset the event that gets signaled
+  // any time the store changes.  Access the created
+  // event using change_event().
+  virtual HRESULT EnsureEventSetup();
+
+  // Get the event that is signaled on store changes.
+  virtual HANDLE change_event() const;
+
+ private:
+  scoped_hfind_change_notification change_event_;
+  CString path_name_;
+  bool watch_subtree_;
+  DWORD notify_filter_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(FileWatcher);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_FILE_H__
+
diff --git a/common/file_reader.cc b/common/file_reader.cc
index ed1f6d2..4f3304c 100644
--- a/common/file_reader.cc
+++ b/common/file_reader.cc
@@ -1,248 +1,248 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/file_reader.h"

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-FileReader::FileReader()

-    : file_is_open_(false),

-      buffered_byte_count_(0),

-      current_position_(0),

-      file_buffer_size_(0),

-      is_unicode_(false) {}

-

-FileReader::~FileReader() {

-  if (file_is_open_) {

-    file_.Close();

-    file_is_open_ = false;

-  }

-}

-

-HRESULT FileReader::Init(const TCHAR* file_name, size_t buffer_size) {

-  ASSERT1(file_name);

-  ASSERT1(buffer_size);

-  file_buffer_size_ = buffer_size;

-  file_buffer_.reset(new byte[file_buffer_size()]);

-  HRESULT hr = file_.OpenShareMode(file_name, false, false, FILE_SHARE_WRITE |

-                                                            FILE_SHARE_READ);

-  file_is_open_ = SUCCEEDED(hr);

-  is_unicode_ = false;

-

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = file_.SeekToBegin();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  const int unicode_header_length = 2;

-

-  char buf[unicode_header_length] = {0};

-  uint32 bytes_read = 0;

-  hr = file_.Read(sizeof(buf), reinterpret_cast<byte*>(buf), &bytes_read);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (bytes_read == sizeof(buf)) {

-    char unicode_buf[unicode_header_length] = {0xff, 0xfe};

-    is_unicode_ = (memcmp(buf, unicode_buf, sizeof(buf)) == 0);

-  }

-

-  if (!is_unicode_) {

-    file_.SeekToBegin();

-  }

-

-  if (is_unicode_ && (buffer_size < sizeof(WCHAR))) {

-    return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);

-  }

-

-  return S_OK;

-}

-

-HRESULT FileReader::GetNextChar(bool peek, CString* next_char) {

-  ASSERT1(next_char);

-  next_char->Empty();

-

-  // Do we need to read in more of the file?

-  if (current_position_ >= buffered_byte_count_) {

-    current_position_ = 0;

-    if (FAILED(file_.Read(file_buffer_size(),

-                          file_buffer_.get(),

-                          &buffered_byte_count_))) {

-      // There is no more of the file buffered.

-      buffered_byte_count_ = 0;

-    }

-  }

-

-  // Have we gone past the end of the file?

-  if (current_position_ >= buffered_byte_count_) {

-    return E_FAIL;

-  }

-

-  if (is_unicode_) {

-    // Need to make sure there are at least 2 characters still in the buffer.

-    // If we're right at the end of the buffer and there's only one character,

-    // then we will need to read more from the file.

-

-    if (current_position_ + 1 >= buffered_byte_count_) {

-      // We need one more byte to make a WCHAR.

-      // Due to the need to peek, we're going to take that byte and put it at

-      // the beginning of the file_buffer_ and read in as many remaining bytes

-      // as we can from the file.

-

-      // Copy current (and last) byte to the beginning of the buffer.

-      file_buffer_[0] = file_buffer_[current_position_];

-

-      // Reset current_position.

-      current_position_ = 0;

-

-      if (SUCCEEDED(file_.Read(file_buffer_size() - 1,

-                               file_buffer_.get() + 1,

-                               &buffered_byte_count_))) {

-        // Incrememt count to deal with byte we pre-filled at offset 0.

-        buffered_byte_count_++;

-      } else {

-        // We've got a Unicode file with an extra byte.  We're going to drop the

-        // byte and call it end of file.

-        buffered_byte_count_ = 0;

-        return E_FAIL;

-      }

-    }

-

-    // Get the next character.

-    char c1 = file_buffer_[current_position_];

-    ++current_position_;

-    char c2 = file_buffer_[current_position_];

-    ++current_position_;

-

-    if (peek) {

-      // Reset the current position pointer backwards if we're peeking.

-      current_position_ -= 2;

-    }

-

-    WCHAR c = (static_cast<WCHAR>(c2) << 8) | static_cast<WCHAR>(c1);

-

-    *next_char = c;

-  } else {

-    char c = file_buffer_[current_position_];

-    if (!peek) {

-      ++current_position_;

-    }

-    *next_char = c;

-  }

-

-  return S_OK;

-}

-

-HRESULT FileReader::ReadLineString(CString* line) {

-  ASSERT1(line);

-

-  line->Empty();

-

-  while (true) {

-    CString current_char;

-    HRESULT hr = GetNextChar(false, &current_char);

-    // If we failed to get the next char, we're at the end of the file.

-    // If the current line is empty, then fail out signalling we're done.

-    // Otherwise, return the current line and we'll fail out on the next call to

-    // ReadLine().

-    if (FAILED(hr)) {

-      if (line->IsEmpty()) {

-        return hr;

-      } else {

-        return S_OK;

-      }

-    }

-

-    // Have we reached end of line?

-    if (current_char.Compare(_T("\r")) == 0) {

-      // Seek ahead to see if the next char is "\n"

-      CString next_char;

-      GetNextChar(true, &next_char);

-      if (next_char.Compare(_T("\n")) == 0) {

-        // Get in the next char too.

-        GetNextChar(false, &next_char);

-      }

-      break;

-    } else if (current_char.Compare(_T("\n")) == 0) {

-      break;

-    }

-

-    line->Append(current_char);

-  }

-

-  return S_OK;

-}

-

-HRESULT FileReader::ReadLineAnsi(size_t max_len, char* line) {

-  ASSERT1(line);

-  ASSERT1(max_len);

-

-  size_t total_len = 0;

-

-  while (true) {

-    // Do we need to read in more of the file?

-    if (current_position_ >= buffered_byte_count_) {

-      current_position_ = 0;

-      if (FAILED(file_.Read(file_buffer_size(),

-                            file_buffer_.get(),

-                            &buffered_byte_count_))) {

-        // There is no more of the file buffered.

-        buffered_byte_count_ = 0;

-      }

-    }

-

-    // Have we gone past the end of the file?

-    if (current_position_ >= buffered_byte_count_) {

-      break;

-    }

-

-    // Get the next character.

-    char c = file_buffer_[current_position_];

-    ++current_position_;

-

-    // Have we reached end of line?

-    // TODO(omaha): if the line is terminated with a \r\n pair then perhaps

-    // the code should skip the whole pair not only half of it.

-    if (c == '\n' || c == '\r') {

-      break;

-    }

-

-    // Fill up the passed in buffer for the line.

-    if (total_len < max_len - 1) {

-      line[total_len] = c;

-      ++total_len;

-    }

-  }

-  // Terminate the passed in buffer.

-  ASSERT1(total_len < max_len);

-  line[total_len] = '\0';

-

-  // If we are out of bytes and we didn't read in any bytes.

-  // then fail signaling end of file.

-  if (!buffered_byte_count_ && !total_len) {

-    return E_FAIL;

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/file_reader.h"
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+FileReader::FileReader()
+    : file_is_open_(false),
+      buffered_byte_count_(0),
+      current_position_(0),
+      file_buffer_size_(0),
+      is_unicode_(false) {}
+
+FileReader::~FileReader() {
+  if (file_is_open_) {
+    file_.Close();
+    file_is_open_ = false;
+  }
+}
+
+HRESULT FileReader::Init(const TCHAR* file_name, size_t buffer_size) {
+  ASSERT1(file_name);
+  ASSERT1(buffer_size);
+  file_buffer_size_ = buffer_size;
+  file_buffer_.reset(new byte[file_buffer_size()]);
+  HRESULT hr = file_.OpenShareMode(file_name, false, false, FILE_SHARE_WRITE |
+                                                            FILE_SHARE_READ);
+  file_is_open_ = SUCCEEDED(hr);
+  is_unicode_ = false;
+
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = file_.SeekToBegin();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  const int unicode_header_length = 2;
+
+  char buf[unicode_header_length] = {0};
+  uint32 bytes_read = 0;
+  hr = file_.Read(sizeof(buf), reinterpret_cast<byte*>(buf), &bytes_read);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (bytes_read == sizeof(buf)) {
+    char unicode_buf[unicode_header_length] = {0xff, 0xfe};
+    is_unicode_ = (memcmp(buf, unicode_buf, sizeof(buf)) == 0);
+  }
+
+  if (!is_unicode_) {
+    file_.SeekToBegin();
+  }
+
+  if (is_unicode_ && (buffer_size < sizeof(WCHAR))) {
+    return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+  }
+
+  return S_OK;
+}
+
+HRESULT FileReader::GetNextChar(bool peek, CString* next_char) {
+  ASSERT1(next_char);
+  next_char->Empty();
+
+  // Do we need to read in more of the file?
+  if (current_position_ >= buffered_byte_count_) {
+    current_position_ = 0;
+    if (FAILED(file_.Read(file_buffer_size(),
+                          file_buffer_.get(),
+                          &buffered_byte_count_))) {
+      // There is no more of the file buffered.
+      buffered_byte_count_ = 0;
+    }
+  }
+
+  // Have we gone past the end of the file?
+  if (current_position_ >= buffered_byte_count_) {
+    return E_FAIL;
+  }
+
+  if (is_unicode_) {
+    // Need to make sure there are at least 2 characters still in the buffer.
+    // If we're right at the end of the buffer and there's only one character,
+    // then we will need to read more from the file.
+
+    if (current_position_ + 1 >= buffered_byte_count_) {
+      // We need one more byte to make a WCHAR.
+      // Due to the need to peek, we're going to take that byte and put it at
+      // the beginning of the file_buffer_ and read in as many remaining bytes
+      // as we can from the file.
+
+      // Copy current (and last) byte to the beginning of the buffer.
+      file_buffer_[0] = file_buffer_[current_position_];
+
+      // Reset current_position.
+      current_position_ = 0;
+
+      if (SUCCEEDED(file_.Read(file_buffer_size() - 1,
+                               file_buffer_.get() + 1,
+                               &buffered_byte_count_))) {
+        // Incrememt count to deal with byte we pre-filled at offset 0.
+        buffered_byte_count_++;
+      } else {
+        // We've got a Unicode file with an extra byte.  We're going to drop the
+        // byte and call it end of file.
+        buffered_byte_count_ = 0;
+        return E_FAIL;
+      }
+    }
+
+    // Get the next character.
+    char c1 = file_buffer_[current_position_];
+    ++current_position_;
+    char c2 = file_buffer_[current_position_];
+    ++current_position_;
+
+    if (peek) {
+      // Reset the current position pointer backwards if we're peeking.
+      current_position_ -= 2;
+    }
+
+    WCHAR c = (static_cast<WCHAR>(c2) << 8) | static_cast<WCHAR>(c1);
+
+    *next_char = c;
+  } else {
+    char c = file_buffer_[current_position_];
+    if (!peek) {
+      ++current_position_;
+    }
+    *next_char = c;
+  }
+
+  return S_OK;
+}
+
+HRESULT FileReader::ReadLineString(CString* line) {
+  ASSERT1(line);
+
+  line->Empty();
+
+  while (true) {
+    CString current_char;
+    HRESULT hr = GetNextChar(false, &current_char);
+    // If we failed to get the next char, we're at the end of the file.
+    // If the current line is empty, then fail out signalling we're done.
+    // Otherwise, return the current line and we'll fail out on the next call to
+    // ReadLine().
+    if (FAILED(hr)) {
+      if (line->IsEmpty()) {
+        return hr;
+      } else {
+        return S_OK;
+      }
+    }
+
+    // Have we reached end of line?
+    if (current_char.Compare(_T("\r")) == 0) {
+      // Seek ahead to see if the next char is "\n"
+      CString next_char;
+      GetNextChar(true, &next_char);
+      if (next_char.Compare(_T("\n")) == 0) {
+        // Get in the next char too.
+        GetNextChar(false, &next_char);
+      }
+      break;
+    } else if (current_char.Compare(_T("\n")) == 0) {
+      break;
+    }
+
+    line->Append(current_char);
+  }
+
+  return S_OK;
+}
+
+HRESULT FileReader::ReadLineAnsi(size_t max_len, char* line) {
+  ASSERT1(line);
+  ASSERT1(max_len);
+
+  size_t total_len = 0;
+
+  while (true) {
+    // Do we need to read in more of the file?
+    if (current_position_ >= buffered_byte_count_) {
+      current_position_ = 0;
+      if (FAILED(file_.Read(file_buffer_size(),
+                            file_buffer_.get(),
+                            &buffered_byte_count_))) {
+        // There is no more of the file buffered.
+        buffered_byte_count_ = 0;
+      }
+    }
+
+    // Have we gone past the end of the file?
+    if (current_position_ >= buffered_byte_count_) {
+      break;
+    }
+
+    // Get the next character.
+    char c = file_buffer_[current_position_];
+    ++current_position_;
+
+    // Have we reached end of line?
+    // TODO(omaha): if the line is terminated with a \r\n pair then perhaps
+    // the code should skip the whole pair not only half of it.
+    if (c == '\n' || c == '\r') {
+      break;
+    }
+
+    // Fill up the passed in buffer for the line.
+    if (total_len < max_len - 1) {
+      line[total_len] = c;
+      ++total_len;
+    }
+  }
+  // Terminate the passed in buffer.
+  ASSERT1(total_len < max_len);
+  line[total_len] = '\0';
+
+  // If we are out of bytes and we didn't read in any bytes.
+  // then fail signaling end of file.
+  if (!buffered_byte_count_ && !total_len) {
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/common/file_reader.h b/common/file_reader.h
index ec7f9fe..c97c3e9 100644
--- a/common/file_reader.h
+++ b/common/file_reader.h
@@ -1,60 +1,60 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_FILE_READER_H_

-#define OMAHA_COMMON_FILE_READER_H_

-

-#include <windows.h>

-#include <tchar.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/file.h"

-

-namespace omaha {

-

-// Allows one to read files quickly and easily line by line.

-class FileReader {

- public:

-  FileReader();

-  ~FileReader();

-

-  // Specifies the underlying file name and the size of internal read buffer.

-  HRESULT Init(const TCHAR* file_name, size_t buffer_size);

-

-  // Reads one line of text from the file, taking advantage of the internal

-  // file buffer to optimize I/O reads. It reads at most max_len - 1 characters

-  // and it always terminates the line.

-  HRESULT ReadLineAnsi(size_t max_len, char* line);

-  HRESULT ReadLineString(CString* line);

-

- private:

-  HRESULT GetNextChar(bool peek, CString* next_char);

-  size_t file_buffer_size() const { return file_buffer_size_; }

-

-  File file_;

-  bool file_is_open_;

-  size_t buffered_byte_count_;          // How many bytes are in the buffer.

-  size_t current_position_;             // An index into the buffer.

-  scoped_array<byte> file_buffer_;      // A buffer (cache) of the file.

-  size_t file_buffer_size_;             // How much of the file to slurp

-                                        // in on each read.

-  bool is_unicode_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(FileReader);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_FILE_READER_H_

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_FILE_READER_H_
+#define OMAHA_COMMON_FILE_READER_H_
+
+#include <windows.h>
+#include <tchar.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/file.h"
+
+namespace omaha {
+
+// Allows one to read files quickly and easily line by line.
+class FileReader {
+ public:
+  FileReader();
+  ~FileReader();
+
+  // Specifies the underlying file name and the size of internal read buffer.
+  HRESULT Init(const TCHAR* file_name, size_t buffer_size);
+
+  // Reads one line of text from the file, taking advantage of the internal
+  // file buffer to optimize I/O reads. It reads at most max_len - 1 characters
+  // and it always terminates the line.
+  HRESULT ReadLineAnsi(size_t max_len, char* line);
+  HRESULT ReadLineString(CString* line);
+
+ private:
+  HRESULT GetNextChar(bool peek, CString* next_char);
+  size_t file_buffer_size() const { return file_buffer_size_; }
+
+  File file_;
+  bool file_is_open_;
+  size_t buffered_byte_count_;          // How many bytes are in the buffer.
+  size_t current_position_;             // An index into the buffer.
+  scoped_array<byte> file_buffer_;      // A buffer (cache) of the file.
+  size_t file_buffer_size_;             // How much of the file to slurp
+                                        // in on each read.
+  bool is_unicode_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(FileReader);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_FILE_READER_H_
diff --git a/common/file_reader_unittest.cc b/common/file_reader_unittest.cc
index 74e8cb6..af62b00 100644
--- a/common/file_reader_unittest.cc
+++ b/common/file_reader_unittest.cc
@@ -1,304 +1,304 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// TODO(omaha): improve unit test. For example, test we are handling correctly

-// different types of line termination.

-

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/file_reader.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class ReadingFilesTest : public testing::Test {

- protected:

-  ReadingFilesTest() {

-    temp_file_[0] = '\0';

-  }

-

-  virtual void SetUp() {

-    // create a temporary file

-    TCHAR temp_path[MAX_PATH] = {0};

-    EXPECT_LT(::GetTempPath(arraysize(temp_path), temp_path),

-              arraysize(temp_path));

-    EXPECT_NE(::GetTempFileName(temp_path, _T("ut_"), 0, temp_file_), 0);

-  }

-

-  virtual void TearDown() {

-    // remove the temporary file

-    if (::lstrlen(temp_file_) > 0) {

-      ASSERT_SUCCEEDED(File::Remove(temp_file_));

-    }

-  }

-

-  void Compare(const std::vector<char*>& lines1,

-               const std::vector<char*>& lines2,

-               byte** orig_lines, int* lengths, int* copies) {

-    // verify that all three things match

-    //  * The lines read using the File class,

-    //  * The lines read using the FileReader class,

-    //  * The original data used to write the files

-    EXPECT_EQ(lines1.size(), lines2.size());

-

-    for (uint32 line_number = 0; line_number < lines1.size(); line_number++) {

-      int index = 0;

-      int data_length = lengths[line_number];

-      int data_copies = copies[line_number];

-      for (int copy = 0; copy < data_copies; copy++) {

-        for (int index_data = 0; index_data < data_length; index_data++) {

-          EXPECT_EQ(lines1[line_number][index], lines2[line_number][index]);

-          EXPECT_EQ(lines1[line_number][index],

-                    orig_lines[line_number][index_data]);

-          index++;

-        }

-      }

-      EXPECT_EQ(lines1[line_number][index], lines2[line_number][index]);

-      EXPECT_EQ(lines1[line_number][index], '\0');

-    }

-  }

-

-  void DeleteContainedArrays(std::vector<char*>* lines) {

-    for (uint32 line_number = 0; line_number < lines->size(); line_number++) {

-      delete[] (*lines)[line_number];

-      (*lines)[line_number] = NULL;

-    }

-  }

-

-  HRESULT WriteCStringW(File* file, CStringW* str) {

-    return file->Write(reinterpret_cast<const byte*>(str->GetBuffer()),

-                       str->GetLength() * sizeof(WCHAR),

-                       NULL);

-  }

-

-  void TestReadFileStringUnicode(int buffer_size) {

-    CStringW line1 = L"hello there, here's some data";

-    CStringW line2 = L"i've got more\tdata over here.";

-    CStringW eol1 = L"\r";

-    CStringW eol2 = L"\r\n";

-    CStringW eol3 = L"\n";

-

-    std::vector<CString> expected_lines;

-    expected_lines.push_back(CString(line1));

-    expected_lines.push_back(CString(line2));

-    expected_lines.push_back(CString(line1));

-    expected_lines.push_back(CString(line1));

-    expected_lines.push_back(CString(line2));

-

-    File file_write;

-    EXPECT_SUCCEEDED(file_write.Open(temp_file_, true, false));

-

-    // Write the unicode marker to the beginning of the file.

-    byte buf[2] = {0xff, 0xfe};

-    EXPECT_SUCCEEDED(file_write.Write(buf, sizeof(buf), NULL));

-

-    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &line1));

-    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &eol1));

-    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &line2));

-    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &eol1));

-    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &line1));

-    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &eol3));

-    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &line1));

-    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &eol2));

-    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &line2));

-    file_write.Close();

-

-    FileReader reader;

-    EXPECT_SUCCEEDED(reader.Init(temp_file_, buffer_size));

-

-    std::vector<CString> read_lines;

-    CString current_string;

-    while (SUCCEEDED(reader.ReadLineString(&current_string))) {

-      read_lines.push_back(current_string);

-    }

-

-    ASSERT_EQ(expected_lines.size(), read_lines.size());

-

-    if (expected_lines.size() == read_lines.size()) {

-      for (size_t i = 0; i < expected_lines.size(); ++i) {

-        CString expected_str = expected_lines[i];

-        CString read_str = read_lines[i];

-        ASSERT_STREQ(expected_str, read_str);

-      }

-    }

-  }

-

-  TCHAR temp_file_[MAX_PATH];

-

-  DISALLOW_EVIL_CONSTRUCTORS(ReadingFilesTest);

-};

-

-

-TEST_F(ReadingFilesTest, ReadFile1) {

-  // write the data to the file

-  File file_write;

-  EXPECT_SUCCEEDED(file_write.Open(temp_file_, true, false));

-  byte data1[] = {'a', 'b', 'c', 'z', '!', '&', '\t'};

-  int data1_copies = 1;

-  EXPECT_SUCCEEDED(file_write.WriteN(data1, arraysize(data1), data1_copies,

-                                     NULL));

-  byte return_data = '\n';

-  EXPECT_SUCCEEDED(file_write.WriteN(&return_data, 1, 1, NULL));

-

-  byte data2[] = {'d', 'a', 'v', 'e', ' ', ' ', '\t', '\\'};

-  int data2_copies = 2;

-  EXPECT_SUCCEEDED(file_write.WriteN(data2, arraysize(data2), data2_copies,

-                                     NULL));

-  file_write.Close();

-

-  // read in the file line by line using the File class

-  std::vector<char*> lines1;

-  File file_read1;

-  ASSERT_SUCCEEDED(file_read1.Open(temp_file_, false, false));

-  while (true) {

-    uint32 bytes_read;

-    scoped_array<char> line(new char[256]);

-    if (FAILED(file_read1.ReadLineAnsi(256, line.get(), &bytes_read))) {

-      break;

-    }

-    lines1.push_back(line.release());

-  }

-

-  file_read1.Close();

-

-  // read in the file line by line using the FileReader class

-  std::vector<char*> lines2;

-  FileReader file_read2;

-  size_t buffer_size = 512;

-  ASSERT_SUCCEEDED(file_read2.Init(temp_file_, buffer_size));

-  while (true) {

-    scoped_array<char> line(new char[256]);

-    if (FAILED(file_read2.ReadLineAnsi(256, line.get()))) {

-      break;

-    }

-    lines2.push_back(line.release());

-  }

-

-  // Verify that everything matches

-  byte* (orig_lines[]) = {data1, data2};

-  int copies[] = {data1_copies, data2_copies};

-  int lengths[] = {arraysize(data1), arraysize(data2)};

-  Compare(lines1, lines2, orig_lines, lengths, copies);

-

-  // Free the allocated memory

-  DeleteContainedArrays(&lines1);

-  DeleteContainedArrays(&lines1);

-}

-

-// Two readers should be able to read from the same file.

-TEST_F(ReadingFilesTest, ReadFileShare) {

-  File file;

-  EXPECT_SUCCEEDED(file.Open(temp_file_, true, false));

-  file.Close();

-

-  const size_t kBufferSize = 0x100;

-

-  FileReader reader1;

-  EXPECT_SUCCEEDED(reader1.Init(temp_file_, kBufferSize));

-

-  FileReader reader2;

-  EXPECT_SUCCEEDED(reader2.Init(temp_file_, kBufferSize));

-}

-

-HRESULT WriteCStringA(File* file, CStringA* str) {

-  return file->Write(reinterpret_cast<const byte*>(str->GetBuffer()),

-                     str->GetLength(),

-                     NULL);

-}

-

-TEST_F(ReadingFilesTest, ReadFileStringAnsi) {

-  CStringA line1 = "hello there, here's some data";

-  CStringA line2 = "i've got more\tdata over here.";

-  CStringA eol1 = "\r";

-  CStringA eol2 = "\r\n";

-  CStringA eol3 = "\n";

-

-  std::vector<CString> expected_lines;

-  expected_lines.push_back(CString(line1));

-  expected_lines.push_back(CString(line2));

-  expected_lines.push_back(CString(line1));

-  expected_lines.push_back(CString(line1));

-  expected_lines.push_back(CString(line2));

-

-  File file_write;

-  EXPECT_SUCCEEDED(file_write.Open(temp_file_, true, false));

-  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &line1));

-  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &eol1));

-  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &line2));

-  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &eol1));

-  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &line1));

-  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &eol3));

-  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &line1));

-  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &eol2));

-  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &line2));

-  file_write.Close();

-

-  FileReader reader;

-  EXPECT_SUCCEEDED(reader.Init(temp_file_, 20));

-

-  std::vector<CString> read_lines;

-  CString current_string;

-  while (SUCCEEDED(reader.ReadLineString(&current_string))) {

-    read_lines.push_back(current_string);

-  }

-

-  ASSERT_EQ(expected_lines.size(), read_lines.size());

-

-  if (expected_lines.size() == read_lines.size()) {

-    for (size_t i = 0; i < expected_lines.size(); ++i) {

-      CString expected_str = expected_lines[i];

-      CString read_str = read_lines[i];

-      ASSERT_STREQ(expected_str, read_str);

-    }

-  }

-}

-

-TEST_F(ReadingFilesTest, ReadFileStringUnicodeSmallBuffer) {

-  TestReadFileStringUnicode(20);

-}

-

-TEST_F(ReadingFilesTest, ReadFileStringUnicodeHugeBuffer) {

-  TestReadFileStringUnicode(4096);

-}

-

-TEST_F(ReadingFilesTest, ReadFileStringUnicodeSmallOddBufferBuffer) {

-  TestReadFileStringUnicode(19);

-}

-

-TEST_F(ReadingFilesTest, ReadFileStringUnicodeTinyOddBuffer) {

-  TestReadFileStringUnicode(3);

-}

-

-TEST_F(ReadingFilesTest, ReadFileStringUnicodeTinyEvenBuffer) {

-  TestReadFileStringUnicode(2);

-}

-

-TEST_F(ReadingFilesTest, ReadFileStringUnicodeOneByteBuffer) {

-  File file_write;

-  EXPECT_SUCCEEDED(file_write.Open(temp_file_, true, false));

-

-  // Write the unicode marker to the beginning of the file.

-  byte buf[2] = {0xff, 0xfe};

-  EXPECT_SUCCEEDED(file_write.Write(buf, sizeof(buf), NULL));

-

-  file_write.Close();

-

-  FileReader reader;

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER),

-            reader.Init(temp_file_, 1));

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// TODO(omaha): improve unit test. For example, test we are handling correctly
+// different types of line termination.
+
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/file_reader.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class ReadingFilesTest : public testing::Test {
+ protected:
+  ReadingFilesTest() {
+    temp_file_[0] = '\0';
+  }
+
+  virtual void SetUp() {
+    // create a temporary file
+    TCHAR temp_path[MAX_PATH] = {0};
+    EXPECT_LT(::GetTempPath(arraysize(temp_path), temp_path),
+              arraysize(temp_path));
+    EXPECT_NE(::GetTempFileName(temp_path, _T("ut_"), 0, temp_file_), 0);
+  }
+
+  virtual void TearDown() {
+    // remove the temporary file
+    if (::lstrlen(temp_file_) > 0) {
+      ASSERT_SUCCEEDED(File::Remove(temp_file_));
+    }
+  }
+
+  void Compare(const std::vector<char*>& lines1,
+               const std::vector<char*>& lines2,
+               byte** orig_lines, int* lengths, int* copies) {
+    // verify that all three things match
+    //  * The lines read using the File class,
+    //  * The lines read using the FileReader class,
+    //  * The original data used to write the files
+    EXPECT_EQ(lines1.size(), lines2.size());
+
+    for (uint32 line_number = 0; line_number < lines1.size(); line_number++) {
+      int index = 0;
+      int data_length = lengths[line_number];
+      int data_copies = copies[line_number];
+      for (int copy = 0; copy < data_copies; copy++) {
+        for (int index_data = 0; index_data < data_length; index_data++) {
+          EXPECT_EQ(lines1[line_number][index], lines2[line_number][index]);
+          EXPECT_EQ(lines1[line_number][index],
+                    orig_lines[line_number][index_data]);
+          index++;
+        }
+      }
+      EXPECT_EQ(lines1[line_number][index], lines2[line_number][index]);
+      EXPECT_EQ(lines1[line_number][index], '\0');
+    }
+  }
+
+  void DeleteContainedArrays(std::vector<char*>* lines) {
+    for (uint32 line_number = 0; line_number < lines->size(); line_number++) {
+      delete[] (*lines)[line_number];
+      (*lines)[line_number] = NULL;
+    }
+  }
+
+  HRESULT WriteCStringW(File* file, CStringW* str) {
+    return file->Write(reinterpret_cast<const byte*>(str->GetBuffer()),
+                       str->GetLength() * sizeof(WCHAR),
+                       NULL);
+  }
+
+  void TestReadFileStringUnicode(int buffer_size) {
+    CStringW line1 = L"hello there, here's some data";
+    CStringW line2 = L"i've got more\tdata over here.";
+    CStringW eol1 = L"\r";
+    CStringW eol2 = L"\r\n";
+    CStringW eol3 = L"\n";
+
+    std::vector<CString> expected_lines;
+    expected_lines.push_back(CString(line1));
+    expected_lines.push_back(CString(line2));
+    expected_lines.push_back(CString(line1));
+    expected_lines.push_back(CString(line1));
+    expected_lines.push_back(CString(line2));
+
+    File file_write;
+    EXPECT_SUCCEEDED(file_write.Open(temp_file_, true, false));
+
+    // Write the unicode marker to the beginning of the file.
+    byte buf[2] = {0xff, 0xfe};
+    EXPECT_SUCCEEDED(file_write.Write(buf, sizeof(buf), NULL));
+
+    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &line1));
+    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &eol1));
+    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &line2));
+    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &eol1));
+    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &line1));
+    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &eol3));
+    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &line1));
+    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &eol2));
+    EXPECT_SUCCEEDED(WriteCStringW(&file_write, &line2));
+    file_write.Close();
+
+    FileReader reader;
+    EXPECT_SUCCEEDED(reader.Init(temp_file_, buffer_size));
+
+    std::vector<CString> read_lines;
+    CString current_string;
+    while (SUCCEEDED(reader.ReadLineString(&current_string))) {
+      read_lines.push_back(current_string);
+    }
+
+    ASSERT_EQ(expected_lines.size(), read_lines.size());
+
+    if (expected_lines.size() == read_lines.size()) {
+      for (size_t i = 0; i < expected_lines.size(); ++i) {
+        CString expected_str = expected_lines[i];
+        CString read_str = read_lines[i];
+        ASSERT_STREQ(expected_str, read_str);
+      }
+    }
+  }
+
+  TCHAR temp_file_[MAX_PATH];
+
+  DISALLOW_EVIL_CONSTRUCTORS(ReadingFilesTest);
+};
+
+
+TEST_F(ReadingFilesTest, ReadFile1) {
+  // write the data to the file
+  File file_write;
+  EXPECT_SUCCEEDED(file_write.Open(temp_file_, true, false));
+  byte data1[] = {'a', 'b', 'c', 'z', '!', '&', '\t'};
+  int data1_copies = 1;
+  EXPECT_SUCCEEDED(file_write.WriteN(data1, arraysize(data1), data1_copies,
+                                     NULL));
+  byte return_data = '\n';
+  EXPECT_SUCCEEDED(file_write.WriteN(&return_data, 1, 1, NULL));
+
+  byte data2[] = {'d', 'a', 'v', 'e', ' ', ' ', '\t', '\\'};
+  int data2_copies = 2;
+  EXPECT_SUCCEEDED(file_write.WriteN(data2, arraysize(data2), data2_copies,
+                                     NULL));
+  file_write.Close();
+
+  // read in the file line by line using the File class
+  std::vector<char*> lines1;
+  File file_read1;
+  ASSERT_SUCCEEDED(file_read1.Open(temp_file_, false, false));
+  while (true) {
+    uint32 bytes_read;
+    scoped_array<char> line(new char[256]);
+    if (FAILED(file_read1.ReadLineAnsi(256, line.get(), &bytes_read))) {
+      break;
+    }
+    lines1.push_back(line.release());
+  }
+
+  file_read1.Close();
+
+  // read in the file line by line using the FileReader class
+  std::vector<char*> lines2;
+  FileReader file_read2;
+  size_t buffer_size = 512;
+  ASSERT_SUCCEEDED(file_read2.Init(temp_file_, buffer_size));
+  while (true) {
+    scoped_array<char> line(new char[256]);
+    if (FAILED(file_read2.ReadLineAnsi(256, line.get()))) {
+      break;
+    }
+    lines2.push_back(line.release());
+  }
+
+  // Verify that everything matches
+  byte* (orig_lines[]) = {data1, data2};
+  int copies[] = {data1_copies, data2_copies};
+  int lengths[] = {arraysize(data1), arraysize(data2)};
+  Compare(lines1, lines2, orig_lines, lengths, copies);
+
+  // Free the allocated memory
+  DeleteContainedArrays(&lines1);
+  DeleteContainedArrays(&lines1);
+}
+
+// Two readers should be able to read from the same file.
+TEST_F(ReadingFilesTest, ReadFileShare) {
+  File file;
+  EXPECT_SUCCEEDED(file.Open(temp_file_, true, false));
+  file.Close();
+
+  const size_t kBufferSize = 0x100;
+
+  FileReader reader1;
+  EXPECT_SUCCEEDED(reader1.Init(temp_file_, kBufferSize));
+
+  FileReader reader2;
+  EXPECT_SUCCEEDED(reader2.Init(temp_file_, kBufferSize));
+}
+
+HRESULT WriteCStringA(File* file, CStringA* str) {
+  return file->Write(reinterpret_cast<const byte*>(str->GetBuffer()),
+                     str->GetLength(),
+                     NULL);
+}
+
+TEST_F(ReadingFilesTest, ReadFileStringAnsi) {
+  CStringA line1 = "hello there, here's some data";
+  CStringA line2 = "i've got more\tdata over here.";
+  CStringA eol1 = "\r";
+  CStringA eol2 = "\r\n";
+  CStringA eol3 = "\n";
+
+  std::vector<CString> expected_lines;
+  expected_lines.push_back(CString(line1));
+  expected_lines.push_back(CString(line2));
+  expected_lines.push_back(CString(line1));
+  expected_lines.push_back(CString(line1));
+  expected_lines.push_back(CString(line2));
+
+  File file_write;
+  EXPECT_SUCCEEDED(file_write.Open(temp_file_, true, false));
+  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &line1));
+  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &eol1));
+  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &line2));
+  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &eol1));
+  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &line1));
+  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &eol3));
+  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &line1));
+  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &eol2));
+  EXPECT_SUCCEEDED(WriteCStringA(&file_write, &line2));
+  file_write.Close();
+
+  FileReader reader;
+  EXPECT_SUCCEEDED(reader.Init(temp_file_, 20));
+
+  std::vector<CString> read_lines;
+  CString current_string;
+  while (SUCCEEDED(reader.ReadLineString(&current_string))) {
+    read_lines.push_back(current_string);
+  }
+
+  ASSERT_EQ(expected_lines.size(), read_lines.size());
+
+  if (expected_lines.size() == read_lines.size()) {
+    for (size_t i = 0; i < expected_lines.size(); ++i) {
+      CString expected_str = expected_lines[i];
+      CString read_str = read_lines[i];
+      ASSERT_STREQ(expected_str, read_str);
+    }
+  }
+}
+
+TEST_F(ReadingFilesTest, ReadFileStringUnicodeSmallBuffer) {
+  TestReadFileStringUnicode(20);
+}
+
+TEST_F(ReadingFilesTest, ReadFileStringUnicodeHugeBuffer) {
+  TestReadFileStringUnicode(4096);
+}
+
+TEST_F(ReadingFilesTest, ReadFileStringUnicodeSmallOddBufferBuffer) {
+  TestReadFileStringUnicode(19);
+}
+
+TEST_F(ReadingFilesTest, ReadFileStringUnicodeTinyOddBuffer) {
+  TestReadFileStringUnicode(3);
+}
+
+TEST_F(ReadingFilesTest, ReadFileStringUnicodeTinyEvenBuffer) {
+  TestReadFileStringUnicode(2);
+}
+
+TEST_F(ReadingFilesTest, ReadFileStringUnicodeOneByteBuffer) {
+  File file_write;
+  EXPECT_SUCCEEDED(file_write.Open(temp_file_, true, false));
+
+  // Write the unicode marker to the beginning of the file.
+  byte buf[2] = {0xff, 0xfe};
+  EXPECT_SUCCEEDED(file_write.Write(buf, sizeof(buf), NULL));
+
+  file_write.Close();
+
+  FileReader reader;
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER),
+            reader.Init(temp_file_, 1));
+}
+
+}  // namespace omaha
+
diff --git a/common/file_store.cc b/common/file_store.cc
index 3f3732c..85b2dc0 100644
--- a/common/file_store.cc
+++ b/common/file_store.cc
@@ -1,116 +1,116 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines class FileStore

-

-#include <vector>

-#include "omaha/common/debug.h"

-#include "omaha/common/file.h"

-#include "omaha/common/file_store.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-// Open the store

-bool FileStore::Open(const TCHAR* file_path) {

-  file_path_ = String_MakeEndWith(file_path, _T("\\"), false);

-  return true;

-}

-

-// Close the store

-bool FileStore::Close() {

-  file_path_.Empty();

-  return true;

-}

-

-// Clear the store

-bool FileStore::Clear() {

-  if (File::Exists(file_path_) && File::IsDirectory(file_path_)) {

-    return SUCCEEDED(DeleteDirectoryFiles(file_path_));

-  } else {

-    return true;

-  }

-}

-

-// Read a value from the store

-bool FileStore::Read(const TCHAR* name, std::vector<byte>* data) const {

-  ASSERT1(name);

-  ASSERT1(data);

-

-  return Exists(name) && SUCCEEDED(ReadEntireFile(file_path_ + name, 0, data));

-}

-

-// Write a value to the store

-bool FileStore::Write(const TCHAR* name, byte* data, int data_size) {

-  ASSERT1(name);

-  ASSERT1(data);

-  ASSERT1(data_size);

-

-  std::vector<byte> buffer(data_size);

-  memcpy(&buffer.front(), data, data_size);

-

-  return SUCCEEDED(WriteEntireFile(file_path_ + name, buffer));

-}

-

-// Check to see a named value exists in the store

-bool FileStore::Exists(const TCHAR* name) const {

-  ASSERT1(name);

-

-  return File::Exists(file_path_ + name);

-}

-

-// Remove a value from the store

-bool FileStore::Remove(const TCHAR* name) {

-  ASSERT1(name);

-

-  return SUCCEEDED(File::Remove(file_path_ + name));

-}

-

-// Get the number of values for this store

-bool FileStore::GetValueCount(uint32* value_count) {

-  ASSERT1(value_count);

-

-  std::vector<CString> matching_paths;

-

-  if (FAILED(File::GetWildcards(file_path_, _T("*"), &matching_paths))) {

-    return false;

-  }

-

-  *value_count = matching_paths.size();

-

-  return true;

-}

-

-// Get the value name for the given value name index

-bool FileStore::GetValueNameAt(uint32 index, CString* value_name) {

-  ASSERT1(value_name);

-

-  std::vector<CString> matching_paths;

-

-  if (FAILED(File::GetWildcards(file_path_, _T("*"), &matching_paths))) {

-    return false;

-  }

-  if (index >= matching_paths.size()) {

-    return false;

-  }

-

-  *value_name = matching_paths[index].Mid(file_path_.GetLength());

-

-  return true;

-}

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines class FileStore
+
+#include <vector>
+#include "omaha/common/debug.h"
+#include "omaha/common/file.h"
+#include "omaha/common/file_store.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+// Open the store
+bool FileStore::Open(const TCHAR* file_path) {
+  file_path_ = String_MakeEndWith(file_path, _T("\\"), false);
+  return true;
+}
+
+// Close the store
+bool FileStore::Close() {
+  file_path_.Empty();
+  return true;
+}
+
+// Clear the store
+bool FileStore::Clear() {
+  if (File::Exists(file_path_) && File::IsDirectory(file_path_)) {
+    return SUCCEEDED(DeleteDirectoryFiles(file_path_));
+  } else {
+    return true;
+  }
+}
+
+// Read a value from the store
+bool FileStore::Read(const TCHAR* name, std::vector<byte>* data) const {
+  ASSERT1(name);
+  ASSERT1(data);
+
+  return Exists(name) && SUCCEEDED(ReadEntireFile(file_path_ + name, 0, data));
+}
+
+// Write a value to the store
+bool FileStore::Write(const TCHAR* name, byte* data, int data_size) {
+  ASSERT1(name);
+  ASSERT1(data);
+  ASSERT1(data_size);
+
+  std::vector<byte> buffer(data_size);
+  memcpy(&buffer.front(), data, data_size);
+
+  return SUCCEEDED(WriteEntireFile(file_path_ + name, buffer));
+}
+
+// Check to see a named value exists in the store
+bool FileStore::Exists(const TCHAR* name) const {
+  ASSERT1(name);
+
+  return File::Exists(file_path_ + name);
+}
+
+// Remove a value from the store
+bool FileStore::Remove(const TCHAR* name) {
+  ASSERT1(name);
+
+  return SUCCEEDED(File::Remove(file_path_ + name));
+}
+
+// Get the number of values for this store
+bool FileStore::GetValueCount(uint32* value_count) {
+  ASSERT1(value_count);
+
+  std::vector<CString> matching_paths;
+
+  if (FAILED(File::GetWildcards(file_path_, _T("*"), &matching_paths))) {
+    return false;
+  }
+
+  *value_count = matching_paths.size();
+
+  return true;
+}
+
+// Get the value name for the given value name index
+bool FileStore::GetValueNameAt(uint32 index, CString* value_name) {
+  ASSERT1(value_name);
+
+  std::vector<CString> matching_paths;
+
+  if (FAILED(File::GetWildcards(file_path_, _T("*"), &matching_paths))) {
+    return false;
+  }
+  if (index >= matching_paths.size()) {
+    return false;
+  }
+
+  *value_name = matching_paths[index].Mid(file_path_.GetLength());
+
+  return true;
+}
+
+}  // namespace omaha
+
diff --git a/common/file_store.h b/common/file_store.h
index 4a7b050..43febe9 100644
--- a/common/file_store.h
+++ b/common/file_store.h
@@ -1,62 +1,62 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines class FileStore

-

-#ifndef OMAHA_COMMON_FILE_STORE_H__

-#define OMAHA_COMMON_FILE_STORE_H__

-

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class FileStore {

- public:

-  // Open the store

-  bool Open(const TCHAR* file_path);

-

-  // Close the store

-  bool Close();

-

-  // Clear the store

-  bool Clear();

-

-  // Read a value from the store

-  bool Read(const TCHAR* name, std::vector<byte>* data) const;

-

-  // Write a value to the store

-  bool Write(const TCHAR* name, byte* data, int data_size);

-

-  // Check to see a named value exists in the store

-  bool Exists(const TCHAR* name) const;

-

-  // Remove a value from the store

-  bool Remove(const TCHAR* name);

-

-  // Get the number of values for this store

-  bool GetValueCount(uint32* value_count);

-

-  // Get the value name for the given value name index

-  bool GetValueNameAt(uint32 index, CString* value_name);

-

- private:

-  CString file_path_;      // Full path to the file store

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_FILE_STORE_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines class FileStore
+
+#ifndef OMAHA_COMMON_FILE_STORE_H__
+#define OMAHA_COMMON_FILE_STORE_H__
+
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class FileStore {
+ public:
+  // Open the store
+  bool Open(const TCHAR* file_path);
+
+  // Close the store
+  bool Close();
+
+  // Clear the store
+  bool Clear();
+
+  // Read a value from the store
+  bool Read(const TCHAR* name, std::vector<byte>* data) const;
+
+  // Write a value to the store
+  bool Write(const TCHAR* name, byte* data, int data_size);
+
+  // Check to see a named value exists in the store
+  bool Exists(const TCHAR* name) const;
+
+  // Remove a value from the store
+  bool Remove(const TCHAR* name);
+
+  // Get the number of values for this store
+  bool GetValueCount(uint32* value_count);
+
+  // Get the value name for the given value name index
+  bool GetValueNameAt(uint32 index, CString* value_name);
+
+ private:
+  CString file_path_;      // Full path to the file store
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_FILE_STORE_H__
diff --git a/common/file_store_unittest.cc b/common/file_store_unittest.cc
index 0598542..eb127de 100644
--- a/common/file_store_unittest.cc
+++ b/common/file_store_unittest.cc
@@ -1,98 +1,98 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Unit test for the file_store.

-

-

-

-#include <shlobj.h>

-#include "base/basictypes.h"

-#include "omaha/common/file_store.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-const TCHAR kFilePathPrefix[] = _T("unittest");

-const TCHAR kFileName1[] = _T("fname1");

-const TCHAR kFileName2[] = _T("fname2");

-char kFileContent[] = "1234567890abcdefg";

-

-TEST(FileStoreTest, FileStore) {

-  // Create a temp dir

-  TCHAR temp_path[MAX_PATH];

-  *temp_path = 0;

-  ASSERT_LT(0u, ::GetTempPath(MAX_PATH, temp_path));

-

-  CString temp_dir;

-  temp_dir.Format(_T("%s%s%x"), temp_path, kFilePathPrefix, ::GetTickCount());

-  ASSERT_EQ(::SHCreateDirectoryEx(0, temp_dir, 0), ERROR_SUCCESS);

-  ON_SCOPE_EXIT(DeleteDirectory, temp_dir);

-

-  // Test the file store

-  FileStore file_store;

-  ASSERT_TRUE(file_store.Open(temp_dir));

-

-  // Make sure the folder is empty

-  uint32 value_count;

-  ASSERT_TRUE(file_store.GetValueCount(&value_count));

-  ASSERT_EQ(value_count, 0);

-  CString value_name;

-  ASSERT_FALSE(file_store.GetValueNameAt(0, &value_name));

-

-  // Write 2 files

-  std::vector<byte> buffer;

-  ASSERT_TRUE(file_store.Write(kFileName1,

-                               reinterpret_cast<byte*>(kFileContent),

-                               arraysize(kFileContent)));

-  ASSERT_TRUE(file_store.Exists(kFileName1));

-  ASSERT_TRUE(file_store.GetValueCount(&value_count));

-  ASSERT_EQ(value_count, 1);

-  ASSERT_TRUE(file_store.GetValueNameAt(0, &value_name));

-  ASSERT_TRUE(value_name == kFileName1);

-  ASSERT_TRUE(file_store.Read(kFileName1, &buffer));

-  ASSERT_TRUE(memcmp(kFileContent,

-                     &buffer.front(),

-                     arraysize(kFileContent)) == 0);

-

-  ASSERT_TRUE(file_store.Write(kFileName2,

-                               reinterpret_cast<byte*>(kFileContent),

-                               arraysize(kFileContent)));

-  ASSERT_TRUE(file_store.Exists(kFileName2));

-  ASSERT_TRUE(file_store.GetValueCount(&value_count));

-  ASSERT_EQ(value_count, 2);

-  ASSERT_TRUE(file_store.GetValueNameAt(1, &value_name));

-  ASSERT_TRUE(value_name == kFileName2);

-  ASSERT_TRUE(file_store.Read(kFileName2, &buffer));

-  ASSERT_TRUE(memcmp(kFileContent,

-                     &buffer.front(),

-                     arraysize(kFileContent)) == 0);

-

-  // Remove files

-  ASSERT_TRUE(file_store.Remove(kFileName1));

-  ASSERT_FALSE(file_store.Exists(kFileName1));

-  ASSERT_TRUE(file_store.GetValueCount(&value_count));

-  ASSERT_EQ(value_count, 1);

-  ASSERT_TRUE(file_store.Remove(kFileName2));

-  ASSERT_FALSE(file_store.Exists(kFileName2));

-  ASSERT_TRUE(file_store.GetValueCount(&value_count));

-  ASSERT_EQ(value_count, 0);

-

-  ASSERT_TRUE(file_store.Close());

-}

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Unit test for the file_store.
+
+
+
+#include <shlobj.h>
+#include "base/basictypes.h"
+#include "omaha/common/file_store.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+const TCHAR kFilePathPrefix[] = _T("unittest");
+const TCHAR kFileName1[] = _T("fname1");
+const TCHAR kFileName2[] = _T("fname2");
+char kFileContent[] = "1234567890abcdefg";
+
+TEST(FileStoreTest, FileStore) {
+  // Create a temp dir
+  TCHAR temp_path[MAX_PATH];
+  *temp_path = 0;
+  ASSERT_LT(0u, ::GetTempPath(MAX_PATH, temp_path));
+
+  CString temp_dir;
+  temp_dir.Format(_T("%s%s%x"), temp_path, kFilePathPrefix, ::GetTickCount());
+  ASSERT_EQ(::SHCreateDirectoryEx(0, temp_dir, 0), ERROR_SUCCESS);
+  ON_SCOPE_EXIT(DeleteDirectory, temp_dir);
+
+  // Test the file store
+  FileStore file_store;
+  ASSERT_TRUE(file_store.Open(temp_dir));
+
+  // Make sure the folder is empty
+  uint32 value_count;
+  ASSERT_TRUE(file_store.GetValueCount(&value_count));
+  ASSERT_EQ(value_count, 0);
+  CString value_name;
+  ASSERT_FALSE(file_store.GetValueNameAt(0, &value_name));
+
+  // Write 2 files
+  std::vector<byte> buffer;
+  ASSERT_TRUE(file_store.Write(kFileName1,
+                               reinterpret_cast<byte*>(kFileContent),
+                               arraysize(kFileContent)));
+  ASSERT_TRUE(file_store.Exists(kFileName1));
+  ASSERT_TRUE(file_store.GetValueCount(&value_count));
+  ASSERT_EQ(value_count, 1);
+  ASSERT_TRUE(file_store.GetValueNameAt(0, &value_name));
+  ASSERT_TRUE(value_name == kFileName1);
+  ASSERT_TRUE(file_store.Read(kFileName1, &buffer));
+  ASSERT_TRUE(memcmp(kFileContent,
+                     &buffer.front(),
+                     arraysize(kFileContent)) == 0);
+
+  ASSERT_TRUE(file_store.Write(kFileName2,
+                               reinterpret_cast<byte*>(kFileContent),
+                               arraysize(kFileContent)));
+  ASSERT_TRUE(file_store.Exists(kFileName2));
+  ASSERT_TRUE(file_store.GetValueCount(&value_count));
+  ASSERT_EQ(value_count, 2);
+  ASSERT_TRUE(file_store.GetValueNameAt(1, &value_name));
+  ASSERT_TRUE(value_name == kFileName2);
+  ASSERT_TRUE(file_store.Read(kFileName2, &buffer));
+  ASSERT_TRUE(memcmp(kFileContent,
+                     &buffer.front(),
+                     arraysize(kFileContent)) == 0);
+
+  // Remove files
+  ASSERT_TRUE(file_store.Remove(kFileName1));
+  ASSERT_FALSE(file_store.Exists(kFileName1));
+  ASSERT_TRUE(file_store.GetValueCount(&value_count));
+  ASSERT_EQ(value_count, 1);
+  ASSERT_TRUE(file_store.Remove(kFileName2));
+  ASSERT_FALSE(file_store.Exists(kFileName2));
+  ASSERT_TRUE(file_store.GetValueCount(&value_count));
+  ASSERT_EQ(value_count, 0);
+
+  ASSERT_TRUE(file_store.Close());
+}
+
+}  // namespace omaha
+
diff --git a/common/file_unittest.cc b/common/file_unittest.cc
index daed9a0..4607509 100644
--- a/common/file_unittest.cc
+++ b/common/file_unittest.cc
@@ -1,418 +1,418 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// File unittest

-

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/timer.h"

-#include "omaha/common/tr_rand.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// TODO(omaha): test error-prone functions such as ReadLineAnsi

-

-namespace {

-

-#define kIEBrowserExe \

-  _T("C:\\PROGRAM FILES\\Internet Explorer\\iexplore.exe")

-

-#define kIEBrowserQuotedExe \

-  _T("\"") kIEBrowserExe _T("\"")

-

-}  // namespace

-

-void SimpleTest(bool async) {

-  File f;

-

-  char buf[1000] = "test";

-  uint32 len1 = 4;

-

-  char buf2[1000] = "aaaa";

-  uint32 len2 = 4;

-

-  char buf3[1000] = "bbbb";

-  uint32 len3 = 4;

-

-  char buf4[1000] = "    ";

-  uint32 len4 = 4;

-

-  CString s(_T("test"));

-  CString testfile(_T("testfile.1"));

-

-  ASSERT_SUCCEEDED(f.Open(testfile, true, async));

-  uint32 pos = 0;

-  ASSERT_SUCCEEDED(f.WriteAt(pos,

-                             reinterpret_cast<byte*>(buf),

-                             len1,

-                             0,

-                             NULL));

-  pos += len1;

-

-  ASSERT_SUCCEEDED(f.WriteAt(pos,

-                             reinterpret_cast<byte*>(buf3),

-                             len3,

-                             0,

-                             NULL));

-  pos += len3;

-

-  ASSERT_SUCCEEDED(f.WriteAt(pos,

-                             reinterpret_cast<byte*>(buf3),

-                             len3,

-                             0,

-                             NULL));

-  pos += len3;

-

-  ASSERT_SUCCEEDED(f.WriteAt(pos,

-                             reinterpret_cast<byte*>(buf3),

-                             len3,

-                             0,

-                             NULL));

-  pos += len3;

-

-  ASSERT_SUCCEEDED(f.WriteAt(pos,

-                             reinterpret_cast<byte*>(buf3),

-                             len3,

-                             0,

-                             NULL));

-  pos += len3;

-

-  ASSERT_SUCCEEDED(f.WriteAt(pos,

-                             reinterpret_cast<byte*>(buf3),

-                             len3,

-                             0,

-                             NULL));

-  pos += len3;

-

-  ASSERT_SUCCEEDED(f.WriteAt(pos,

-                             reinterpret_cast<byte*>(buf3),

-                             len3,

-                             0,

-                             NULL));

-  pos += len3;

-

-  ASSERT_SUCCEEDED(f.ReadAt(0, reinterpret_cast<byte*>(buf4), len1, 0, NULL));

-  ASSERT_STREQ(buf, buf4);

-

-  ASSERT_SUCCEEDED(f.ReadAt(4, reinterpret_cast<byte*>(buf4), len3, 0, NULL));

-  ASSERT_STREQ(buf3, buf4);

-

-  ASSERT_SUCCEEDED(f.WriteAt(1, reinterpret_cast<byte*>(buf3), 2, 0, NULL));

-

-  ASSERT_SUCCEEDED(f.WriteAt(20, reinterpret_cast<byte*>(buf), 2, 0, NULL));

-  ASSERT_SUCCEEDED(f.ReadAt(20, reinterpret_cast<byte*>(buf), 2, 0, NULL));

-

-  ASSERT_SUCCEEDED(f.WriteAt(30, reinterpret_cast<byte*>(buf), 2, 0, NULL));

-

-  ASSERT_SUCCEEDED(f.SeekFromBegin(0));

-

-  ASSERT_SUCCEEDED(f.ReadAt(30, reinterpret_cast<byte*>(buf), 2, 0, NULL));

-

-  ASSERT_SUCCEEDED(f.Close());

-

-  ASSERT_SUCCEEDED(f.Open(L"testfile.1", false, false));

-  ASSERT_SUCCEEDED(f.ReadAt(0, reinterpret_cast<byte*>(buf), 16, 0, NULL));

-  buf[17] = '\0';

-

-  uint64 size_on_disk = 0;

-  ASSERT_SUCCEEDED(f.GetSizeOnDisk(&size_on_disk));

-  ASSERT_EQ(size_on_disk, 32);

-

-  ASSERT_SUCCEEDED(f.Close());

-

-  ASSERT_TRUE(File::Exists(testfile));

-  ASSERT_SUCCEEDED(File::Remove(testfile));

-  ASSERT_FALSE(File::Exists(testfile));

-}

-

-void FileWriteCreate(uint32 file_size) {

-  Timer time(true);

-  CString testfile;

-  testfile.Format(L"testfile%u", file_size);

-

-  File f;

-  ASSERT_SUCCEEDED(f.Open(testfile, true, false));

-  ASSERT_SUCCEEDED(f.SetLength(file_size, false));

-

-  uint32 write_size = 512;

-

-  byte *buf2 = new byte[write_size];

-

-  for (uint32 j = 0; j < file_size - write_size; j += write_size) {

-      for (uint32 i = 0; i < write_size; i++) {

-        buf2[i] = static_cast<byte>(tr_rand() % 255);

-      }

-      ASSERT_SUCCEEDED(f.WriteAt(j, buf2, write_size, 0, NULL));

-  }

-

-  f.Sync();

-  f.Close();

-}

-

-void FileWriteTimeTest(uint32 file_size,

-                       uint32 number_writes,

-                       uint32 write_size) {

-  Timer time(true);

-  CString testfile;

-  testfile.Format(L"testfile%u", file_size);

-

-  File f;

-  ASSERT_SUCCEEDED(f.Open(testfile, true, false));

-

-  byte *buf = new byte[write_size];

-

-  for (uint32 i = 0; i < number_writes; i++) {

-    for (uint32 j = 0; j < write_size; j++) {

-      buf[j] = static_cast<byte>(tr_rand() % 255);

-    }

-    uint32 pos = (tr_rand() * 65536 + tr_rand()) % (file_size - write_size);

-    ASSERT_SUCCEEDED(f.WriteAt(pos, buf, write_size, 0, NULL));

-  }

-

-  delete[] buf;

-

-  ASSERT_SUCCEEDED(f.Sync());

-  ASSERT_SUCCEEDED(f.Close());

-}

-

-TEST(FileTest, File) {

-  SimpleTest(false);

-

-  int header = 123;

-  int header2 = 0;

-

-  File f2;

-  ASSERT_SUCCEEDED(f2.Open(L"testfile.3", true, false));

-  ASSERT_SUCCEEDED(f2.WriteAt(0,

-                              reinterpret_cast<byte*>(&header),

-                              sizeof(header),

-                              0,

-                              NULL));

-  ASSERT_SUCCEEDED(f2.ReadAt(0,

-                             reinterpret_cast<byte*>(&header2),

-                             sizeof(header),

-                             0,

-                             NULL));

-  ASSERT_EQ(header, header2);

-

-  uint64 size_on_disk = 0;

-

-  ASSERT_SUCCEEDED(f2.GetSizeOnDisk(&size_on_disk));

-  ASSERT_EQ(size_on_disk, sizeof(header));

-  ASSERT_SUCCEEDED(f2.Close());

-

-  const int kLevel = 1;

-  for (uint32 file_size = 2 * 1024 * 1024;

-       file_size <= 2 * 1024 * 1024;

-       file_size *= 2) {

-    for (uint32 number_writes = 100;

-         number_writes <= (300 * static_cast<uint32>(kLevel));

-         number_writes *= 2) {

-      uint32 write_size = 128;

-      FileWriteTimeTest(file_size, number_writes, write_size);

-    }

-  }

-

-  // Test File::Copy, File::Move, File::CopyWildcards

-  {

-    CString windows_dir;

-    CString temp_dir;

-    DWORD dw = ::GetEnvironmentVariable(

-        L"SystemRoot",

-        windows_dir.GetBufferSetLength(MAX_PATH),

-        MAX_PATH);

-    windows_dir.ReleaseBuffer();

-    ASSERT_TRUE(dw);

-    dw = ::GetEnvironmentVariable(L"TEMP",

-                                  temp_dir.GetBufferSetLength(MAX_PATH),

-                                  MAX_PATH);

-    temp_dir.ReleaseBuffer();

-    ASSERT_TRUE(dw);

-    CString known_file1(windows_dir + L"\\NOTEPAD.EXE");

-    CString known_file2(windows_dir + L"\\REGEDIT.EXE");

-    CString temp_file1(temp_dir + L"\\FOO.TMP");

-    CString temp_file2(temp_dir + L"\\BAR.TMP");

-    uint32 known_size1 = 0;

-    uint32 known_size2 = 0;

-    uint32 temp_size1 = 0;

-

-    // Start with neither file existing

-    if (File::Exists(temp_file1))

-      File::Remove(temp_file1);

-    if (File::Exists(temp_file2))

-      File::Remove(temp_file2);

-    ASSERT_FALSE(File::Exists(temp_file1));

-    ASSERT_FALSE(File::Exists(temp_file2));

-    ASSERT_SUCCEEDED(File::GetFileSizeUnopen(known_file1, &known_size1));

-    ASSERT_SUCCEEDED(File::GetFileSizeUnopen(known_file2, &known_size2));

-    ASSERT_NE(known_size1, known_size2);

-

-    // Copy to create a file, move it to 2nd file, then remove 2nd file

-    ASSERT_SUCCEEDED(File::Copy(known_file1, temp_file1, false));

-    ASSERT_TRUE(File::Exists(temp_file1));

-    ASSERT_SUCCEEDED(File::Move(temp_file1, temp_file2, false));

-    ASSERT_FALSE(File::Exists(temp_file1));

-    ASSERT_TRUE(File::Exists(temp_file2));

-    ASSERT_SUCCEEDED(File::Remove(temp_file2));

-    ASSERT_FALSE(File::Exists(temp_file2));

-

-    // Try copying a file on top of a file - with and without

-    // replace_existing_file=true

-    ASSERT_SUCCEEDED(File::Copy(known_file1, temp_file1, false));

-    ASSERT_SUCCEEDED(File::GetFileSizeUnopen(temp_file1, &temp_size1));

-    ASSERT_EQ(temp_size1, known_size1);

-    ASSERT_SUCCEEDED(File::Copy(known_file2, temp_file1, false));

-    ASSERT_TRUE(File::Exists(temp_file1));

-    ASSERT_SUCCEEDED(File::GetFileSizeUnopen(temp_file1, &temp_size1));

-    ASSERT_EQ(temp_size1, known_size1);

-    ASSERT_SUCCEEDED(File::Copy(known_file2, temp_file1, true));

-    ASSERT_TRUE(File::Exists(temp_file1));

-    ASSERT_SUCCEEDED(File::GetFileSizeUnopen(temp_file1, &temp_size1));

-    ASSERT_EQ(temp_size1, known_size2);

-    ASSERT_SUCCEEDED(File::Remove(temp_file1));

-

-    // Try copying a bunch of files

-    CString known_file3(windows_dir + L"\\twunk_32.exe");

-    CString known_file4(windows_dir + L"\\twunk_16.exe");

-    CString temp_file3(temp_dir + L"\\twunk_32.exe");

-    CString temp_file4(temp_dir + L"\\twunk_16.exe");

-    if (File::Exists(temp_file3))

-      File::Remove(temp_file3);

-    if (File::Exists(temp_file4))

-      File::Remove(temp_file4);

-    ASSERT_TRUE(File::Exists(known_file3));

-    ASSERT_TRUE(File::Exists(known_file4));

-    ASSERT_FALSE(File::Exists(temp_file3));

-    ASSERT_FALSE(File::Exists(temp_file4));

-    ASSERT_SUCCEEDED(File::CopyWildcards(windows_dir,

-                                         temp_dir,

-                                         L"twunk*.exe",

-                                         true));

-    ASSERT_TRUE(File::Exists(temp_file3));

-    ASSERT_TRUE(File::Exists(temp_file4));

-    ASSERT_SUCCEEDED(File::Remove(temp_file3));

-    ASSERT_SUCCEEDED(File::Remove(temp_file4));

-

-    std::vector<CString> matching_files;

-    ASSERT_SUCCEEDED(File::GetWildcards(windows_dir,

-                                        L"twunk*.exe",

-                                        &matching_files));

-    ASSERT_EQ(matching_files.size(), 2);

-    ASSERT_TRUE(matching_files[0] == known_file3 ||

-                matching_files[0] == known_file4);

-    ASSERT_TRUE(matching_files[1] == known_file3 ||

-                matching_files[1] == known_file4);

-    ASSERT_TRUE(matching_files[0] != matching_files[1]);

-  }

-}

-

-

-TEST(FileTest, FileChangeWatcher) {

-  CString temp_dir;

-  ASSERT_TRUE(::GetEnvironmentVariable(L"TEMP",

-                                       temp_dir.GetBufferSetLength(MAX_PATH),

-                                       MAX_PATH) != 0);

-  temp_dir.ReleaseBuffer();

-  temp_dir = String_MakeEndWith(temp_dir, _T("\\"), false /* ignore_case */);

-  temp_dir = temp_dir + _T("omaha_unittest") + itostr(tr_rand() % 255);

-  EXPECT_SUCCEEDED(CreateDir(temp_dir, 0));

-

-  // watch the directory for changes

-  FileWatcher watcher(temp_dir, false, FILE_NOTIFY_CHANGE_LAST_WRITE);

-  EXPECT_SUCCEEDED(watcher.EnsureEventSetup());

-  EXPECT_FALSE(watcher.HasChangeOccurred());

-

-  //

-  // verify that the watcher got set-up correctly the first time

-  //

-

-  // do something in the dir

-  File f;

-  int header1 = 94;

-  ASSERT_SUCCEEDED(f.Open(temp_dir + _T("\\testfile.1"), true, false));

-  ASSERT_SUCCEEDED(f.WriteAt(0, reinterpret_cast<byte*>(&header1),

-                             sizeof(header1), 0, NULL));

-  ASSERT_SUCCEEDED(f.Sync());

-  ASSERT_SUCCEEDED(f.Close());

-

-  // Did we noticed that something happened?

-  EXPECT_TRUE(watcher.HasChangeOccurred());

-  EXPECT_SUCCEEDED(watcher.EnsureEventSetup());

-  EXPECT_FALSE(watcher.HasChangeOccurred());

-

-  //

-  // verify that the watcher got set-up correctly the second time

-  //

-

-  // do something in the dir

-  byte header2 = 2;

-  ASSERT_SUCCEEDED(f.Open(temp_dir + _T("\\testfile.2"), true, false));

-  ASSERT_SUCCEEDED(f.WriteAt(0, reinterpret_cast<byte*>(&header2),

-                             sizeof(header2), 0, NULL));

-  ASSERT_SUCCEEDED(f.Sync());

-  ASSERT_SUCCEEDED(f.Close());

-

-  // Did we noticed that something happened?

-  EXPECT_TRUE(watcher.HasChangeOccurred());

-  EXPECT_SUCCEEDED(watcher.EnsureEventSetup());

-  EXPECT_FALSE(watcher.HasChangeOccurred());

-

-  EXPECT_SUCCEEDED(DeleteDirectory(temp_dir));

-}

-

-TEST(FileTest, Exists_UnQuoted) {

-  EXPECT_TRUE(File::Exists(kIEBrowserExe));

-  EXPECT_FALSE(File::Exists(_T("C:\\foo\\does not exist.exe")));

-  EXPECT_FALSE(File::Exists(_T("Z:\\foo\\does not exist.exe")));

-  if (ShouldRunLargeTest()) {

-    EXPECT_FALSE(File::Exists(_T("\\\\foo\\does not exist.exe")));

-  }

-}

-

-// File::Exists() expects unquoted paths.

-TEST(FileTest, Exists_Quoted) {

-  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe));

-  EXPECT_FALSE(File::Exists(_T("\"C:\\foo\\does not exist.exe\"")));

-  EXPECT_FALSE(File::Exists(_T("\"Z:\\foo\\does not exist.exe\"")));

-  if (ShouldRunLargeTest()) {

-    EXPECT_FALSE(File::Exists(_T("\"\\\\foo\\does not exist.exe\"")));

-  }

-}

-

-// File::Exists() handles trailing spaces but not leading whitespace, tabs, or

-// enclosed paths.

-TEST(FileTest, Exists_ExtraWhitespace) {

-  EXPECT_TRUE(File::Exists(kIEBrowserExe _T(" ")));

-  EXPECT_TRUE(File::Exists(kIEBrowserExe _T("    ")));

-  EXPECT_FALSE(File::Exists(_T(" ") kIEBrowserExe));

-  EXPECT_FALSE(File::Exists(kIEBrowserExe _T("\t")));

-

-  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe _T(" ")));

-  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe _T("    ")));

-  EXPECT_FALSE(File::Exists(_T(" ") kIEBrowserQuotedExe));

-  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe _T("\t")));

-

-  EXPECT_FALSE(File::Exists(_T("\"") kIEBrowserExe _T(" \"")));

-  EXPECT_FALSE(File::Exists(_T("\"") kIEBrowserExe _T("    \"")));

-  EXPECT_FALSE(File::Exists(_T("\" ") kIEBrowserExe _T("\"") ));

-  EXPECT_FALSE(File::Exists(_T("\"") kIEBrowserExe _T("\t\"")));

-

-  EXPECT_FALSE(File::Exists(_T("\"") kIEBrowserExe _T(" \" ")));

-}

-

-}  // namespace omaha

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// File unittest
+
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/timer.h"
+#include "omaha/common/tr_rand.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// TODO(omaha): test error-prone functions such as ReadLineAnsi
+
+namespace {
+
+#define kIEBrowserExe \
+  _T("C:\\PROGRAM FILES\\Internet Explorer\\iexplore.exe")
+
+#define kIEBrowserQuotedExe \
+  _T("\"") kIEBrowserExe _T("\"")
+
+}  // namespace
+
+void SimpleTest(bool async) {
+  File f;
+
+  char buf[1000] = "test";
+  uint32 len1 = 4;
+
+  char buf2[1000] = "aaaa";
+  uint32 len2 = 4;
+
+  char buf3[1000] = "bbbb";
+  uint32 len3 = 4;
+
+  char buf4[1000] = "    ";
+  uint32 len4 = 4;
+
+  CString s(_T("test"));
+  CString testfile(_T("testfile.1"));
+
+  ASSERT_SUCCEEDED(f.Open(testfile, true, async));
+  uint32 pos = 0;
+  ASSERT_SUCCEEDED(f.WriteAt(pos,
+                             reinterpret_cast<byte*>(buf),
+                             len1,
+                             0,
+                             NULL));
+  pos += len1;
+
+  ASSERT_SUCCEEDED(f.WriteAt(pos,
+                             reinterpret_cast<byte*>(buf3),
+                             len3,
+                             0,
+                             NULL));
+  pos += len3;
+
+  ASSERT_SUCCEEDED(f.WriteAt(pos,
+                             reinterpret_cast<byte*>(buf3),
+                             len3,
+                             0,
+                             NULL));
+  pos += len3;
+
+  ASSERT_SUCCEEDED(f.WriteAt(pos,
+                             reinterpret_cast<byte*>(buf3),
+                             len3,
+                             0,
+                             NULL));
+  pos += len3;
+
+  ASSERT_SUCCEEDED(f.WriteAt(pos,
+                             reinterpret_cast<byte*>(buf3),
+                             len3,
+                             0,
+                             NULL));
+  pos += len3;
+
+  ASSERT_SUCCEEDED(f.WriteAt(pos,
+                             reinterpret_cast<byte*>(buf3),
+                             len3,
+                             0,
+                             NULL));
+  pos += len3;
+
+  ASSERT_SUCCEEDED(f.WriteAt(pos,
+                             reinterpret_cast<byte*>(buf3),
+                             len3,
+                             0,
+                             NULL));
+  pos += len3;
+
+  ASSERT_SUCCEEDED(f.ReadAt(0, reinterpret_cast<byte*>(buf4), len1, 0, NULL));
+  ASSERT_STREQ(buf, buf4);
+
+  ASSERT_SUCCEEDED(f.ReadAt(4, reinterpret_cast<byte*>(buf4), len3, 0, NULL));
+  ASSERT_STREQ(buf3, buf4);
+
+  ASSERT_SUCCEEDED(f.WriteAt(1, reinterpret_cast<byte*>(buf3), 2, 0, NULL));
+
+  ASSERT_SUCCEEDED(f.WriteAt(20, reinterpret_cast<byte*>(buf), 2, 0, NULL));
+  ASSERT_SUCCEEDED(f.ReadAt(20, reinterpret_cast<byte*>(buf), 2, 0, NULL));
+
+  ASSERT_SUCCEEDED(f.WriteAt(30, reinterpret_cast<byte*>(buf), 2, 0, NULL));
+
+  ASSERT_SUCCEEDED(f.SeekFromBegin(0));
+
+  ASSERT_SUCCEEDED(f.ReadAt(30, reinterpret_cast<byte*>(buf), 2, 0, NULL));
+
+  ASSERT_SUCCEEDED(f.Close());
+
+  ASSERT_SUCCEEDED(f.Open(L"testfile.1", false, false));
+  ASSERT_SUCCEEDED(f.ReadAt(0, reinterpret_cast<byte*>(buf), 16, 0, NULL));
+  buf[17] = '\0';
+
+  uint64 size_on_disk = 0;
+  ASSERT_SUCCEEDED(f.GetSizeOnDisk(&size_on_disk));
+  ASSERT_EQ(size_on_disk, 32);
+
+  ASSERT_SUCCEEDED(f.Close());
+
+  ASSERT_TRUE(File::Exists(testfile));
+  ASSERT_SUCCEEDED(File::Remove(testfile));
+  ASSERT_FALSE(File::Exists(testfile));
+}
+
+void FileWriteCreate(uint32 file_size) {
+  Timer time(true);
+  CString testfile;
+  testfile.Format(L"testfile%u", file_size);
+
+  File f;
+  ASSERT_SUCCEEDED(f.Open(testfile, true, false));
+  ASSERT_SUCCEEDED(f.SetLength(file_size, false));
+
+  uint32 write_size = 512;
+
+  byte *buf2 = new byte[write_size];
+
+  for (uint32 j = 0; j < file_size - write_size; j += write_size) {
+      for (uint32 i = 0; i < write_size; i++) {
+        buf2[i] = static_cast<byte>(tr_rand() % 255);
+      }
+      ASSERT_SUCCEEDED(f.WriteAt(j, buf2, write_size, 0, NULL));
+  }
+
+  f.Sync();
+  f.Close();
+}
+
+void FileWriteTimeTest(uint32 file_size,
+                       uint32 number_writes,
+                       uint32 write_size) {
+  Timer time(true);
+  CString testfile;
+  testfile.Format(L"testfile%u", file_size);
+
+  File f;
+  ASSERT_SUCCEEDED(f.Open(testfile, true, false));
+
+  byte *buf = new byte[write_size];
+
+  for (uint32 i = 0; i < number_writes; i++) {
+    for (uint32 j = 0; j < write_size; j++) {
+      buf[j] = static_cast<byte>(tr_rand() % 255);
+    }
+    uint32 pos = (tr_rand() * 65536 + tr_rand()) % (file_size - write_size);
+    ASSERT_SUCCEEDED(f.WriteAt(pos, buf, write_size, 0, NULL));
+  }
+
+  delete[] buf;
+
+  ASSERT_SUCCEEDED(f.Sync());
+  ASSERT_SUCCEEDED(f.Close());
+}
+
+TEST(FileTest, File) {
+  SimpleTest(false);
+
+  int header = 123;
+  int header2 = 0;
+
+  File f2;
+  ASSERT_SUCCEEDED(f2.Open(L"testfile.3", true, false));
+  ASSERT_SUCCEEDED(f2.WriteAt(0,
+                              reinterpret_cast<byte*>(&header),
+                              sizeof(header),
+                              0,
+                              NULL));
+  ASSERT_SUCCEEDED(f2.ReadAt(0,
+                             reinterpret_cast<byte*>(&header2),
+                             sizeof(header),
+                             0,
+                             NULL));
+  ASSERT_EQ(header, header2);
+
+  uint64 size_on_disk = 0;
+
+  ASSERT_SUCCEEDED(f2.GetSizeOnDisk(&size_on_disk));
+  ASSERT_EQ(size_on_disk, sizeof(header));
+  ASSERT_SUCCEEDED(f2.Close());
+
+  const int kLevel = 1;
+  for (uint32 file_size = 2 * 1024 * 1024;
+       file_size <= 2 * 1024 * 1024;
+       file_size *= 2) {
+    for (uint32 number_writes = 100;
+         number_writes <= (300 * static_cast<uint32>(kLevel));
+         number_writes *= 2) {
+      uint32 write_size = 128;
+      FileWriteTimeTest(file_size, number_writes, write_size);
+    }
+  }
+
+  // Test File::Copy, File::Move, File::CopyWildcards
+  {
+    CString windows_dir;
+    CString temp_dir;
+    DWORD dw = ::GetEnvironmentVariable(
+        L"SystemRoot",
+        windows_dir.GetBufferSetLength(MAX_PATH),
+        MAX_PATH);
+    windows_dir.ReleaseBuffer();
+    ASSERT_TRUE(dw);
+    dw = ::GetEnvironmentVariable(L"TEMP",
+                                  temp_dir.GetBufferSetLength(MAX_PATH),
+                                  MAX_PATH);
+    temp_dir.ReleaseBuffer();
+    ASSERT_TRUE(dw);
+    CString known_file1(windows_dir + L"\\NOTEPAD.EXE");
+    CString known_file2(windows_dir + L"\\REGEDIT.EXE");
+    CString temp_file1(temp_dir + L"\\FOO.TMP");
+    CString temp_file2(temp_dir + L"\\BAR.TMP");
+    uint32 known_size1 = 0;
+    uint32 known_size2 = 0;
+    uint32 temp_size1 = 0;
+
+    // Start with neither file existing
+    if (File::Exists(temp_file1))
+      File::Remove(temp_file1);
+    if (File::Exists(temp_file2))
+      File::Remove(temp_file2);
+    ASSERT_FALSE(File::Exists(temp_file1));
+    ASSERT_FALSE(File::Exists(temp_file2));
+    ASSERT_SUCCEEDED(File::GetFileSizeUnopen(known_file1, &known_size1));
+    ASSERT_SUCCEEDED(File::GetFileSizeUnopen(known_file2, &known_size2));
+    ASSERT_NE(known_size1, known_size2);
+
+    // Copy to create a file, move it to 2nd file, then remove 2nd file
+    ASSERT_SUCCEEDED(File::Copy(known_file1, temp_file1, false));
+    ASSERT_TRUE(File::Exists(temp_file1));
+    ASSERT_SUCCEEDED(File::Move(temp_file1, temp_file2, false));
+    ASSERT_FALSE(File::Exists(temp_file1));
+    ASSERT_TRUE(File::Exists(temp_file2));
+    ASSERT_SUCCEEDED(File::Remove(temp_file2));
+    ASSERT_FALSE(File::Exists(temp_file2));
+
+    // Try copying a file on top of a file - with and without
+    // replace_existing_file=true
+    ASSERT_SUCCEEDED(File::Copy(known_file1, temp_file1, false));
+    ASSERT_SUCCEEDED(File::GetFileSizeUnopen(temp_file1, &temp_size1));
+    ASSERT_EQ(temp_size1, known_size1);
+    ASSERT_SUCCEEDED(File::Copy(known_file2, temp_file1, false));
+    ASSERT_TRUE(File::Exists(temp_file1));
+    ASSERT_SUCCEEDED(File::GetFileSizeUnopen(temp_file1, &temp_size1));
+    ASSERT_EQ(temp_size1, known_size1);
+    ASSERT_SUCCEEDED(File::Copy(known_file2, temp_file1, true));
+    ASSERT_TRUE(File::Exists(temp_file1));
+    ASSERT_SUCCEEDED(File::GetFileSizeUnopen(temp_file1, &temp_size1));
+    ASSERT_EQ(temp_size1, known_size2);
+    ASSERT_SUCCEEDED(File::Remove(temp_file1));
+
+    // Try copying a bunch of files
+    CString known_file3(windows_dir + L"\\twunk_32.exe");
+    CString known_file4(windows_dir + L"\\twunk_16.exe");
+    CString temp_file3(temp_dir + L"\\twunk_32.exe");
+    CString temp_file4(temp_dir + L"\\twunk_16.exe");
+    if (File::Exists(temp_file3))
+      File::Remove(temp_file3);
+    if (File::Exists(temp_file4))
+      File::Remove(temp_file4);
+    ASSERT_TRUE(File::Exists(known_file3));
+    ASSERT_TRUE(File::Exists(known_file4));
+    ASSERT_FALSE(File::Exists(temp_file3));
+    ASSERT_FALSE(File::Exists(temp_file4));
+    ASSERT_SUCCEEDED(File::CopyWildcards(windows_dir,
+                                         temp_dir,
+                                         L"twunk*.exe",
+                                         true));
+    ASSERT_TRUE(File::Exists(temp_file3));
+    ASSERT_TRUE(File::Exists(temp_file4));
+    ASSERT_SUCCEEDED(File::Remove(temp_file3));
+    ASSERT_SUCCEEDED(File::Remove(temp_file4));
+
+    std::vector<CString> matching_files;
+    ASSERT_SUCCEEDED(File::GetWildcards(windows_dir,
+                                        L"twunk*.exe",
+                                        &matching_files));
+    ASSERT_EQ(matching_files.size(), 2);
+    ASSERT_TRUE(matching_files[0] == known_file3 ||
+                matching_files[0] == known_file4);
+    ASSERT_TRUE(matching_files[1] == known_file3 ||
+                matching_files[1] == known_file4);
+    ASSERT_TRUE(matching_files[0] != matching_files[1]);
+  }
+}
+
+
+TEST(FileTest, FileChangeWatcher) {
+  CString temp_dir;
+  ASSERT_TRUE(::GetEnvironmentVariable(L"TEMP",
+                                       temp_dir.GetBufferSetLength(MAX_PATH),
+                                       MAX_PATH) != 0);
+  temp_dir.ReleaseBuffer();
+  temp_dir = String_MakeEndWith(temp_dir, _T("\\"), false /* ignore_case */);
+  temp_dir = temp_dir + _T("omaha_unittest") + itostr(tr_rand() % 255);
+  EXPECT_SUCCEEDED(CreateDir(temp_dir, 0));
+
+  // watch the directory for changes
+  FileWatcher watcher(temp_dir, false, FILE_NOTIFY_CHANGE_LAST_WRITE);
+  EXPECT_SUCCEEDED(watcher.EnsureEventSetup());
+  EXPECT_FALSE(watcher.HasChangeOccurred());
+
+  //
+  // verify that the watcher got set-up correctly the first time
+  //
+
+  // do something in the dir
+  File f;
+  int header1 = 94;
+  ASSERT_SUCCEEDED(f.Open(temp_dir + _T("\\testfile.1"), true, false));
+  ASSERT_SUCCEEDED(f.WriteAt(0, reinterpret_cast<byte*>(&header1),
+                             sizeof(header1), 0, NULL));
+  ASSERT_SUCCEEDED(f.Sync());
+  ASSERT_SUCCEEDED(f.Close());
+
+  // Did we noticed that something happened?
+  EXPECT_TRUE(watcher.HasChangeOccurred());
+  EXPECT_SUCCEEDED(watcher.EnsureEventSetup());
+  EXPECT_FALSE(watcher.HasChangeOccurred());
+
+  //
+  // verify that the watcher got set-up correctly the second time
+  //
+
+  // do something in the dir
+  byte header2 = 2;
+  ASSERT_SUCCEEDED(f.Open(temp_dir + _T("\\testfile.2"), true, false));
+  ASSERT_SUCCEEDED(f.WriteAt(0, reinterpret_cast<byte*>(&header2),
+                             sizeof(header2), 0, NULL));
+  ASSERT_SUCCEEDED(f.Sync());
+  ASSERT_SUCCEEDED(f.Close());
+
+  // Did we noticed that something happened?
+  EXPECT_TRUE(watcher.HasChangeOccurred());
+  EXPECT_SUCCEEDED(watcher.EnsureEventSetup());
+  EXPECT_FALSE(watcher.HasChangeOccurred());
+
+  EXPECT_SUCCEEDED(DeleteDirectory(temp_dir));
+}
+
+TEST(FileTest, Exists_UnQuoted) {
+  EXPECT_TRUE(File::Exists(kIEBrowserExe));
+  EXPECT_FALSE(File::Exists(_T("C:\\foo\\does not exist.exe")));
+  EXPECT_FALSE(File::Exists(_T("Z:\\foo\\does not exist.exe")));
+  if (ShouldRunLargeTest()) {
+    EXPECT_FALSE(File::Exists(_T("\\\\foo\\does not exist.exe")));
+  }
+}
+
+// File::Exists() expects unquoted paths.
+TEST(FileTest, Exists_Quoted) {
+  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe));
+  EXPECT_FALSE(File::Exists(_T("\"C:\\foo\\does not exist.exe\"")));
+  EXPECT_FALSE(File::Exists(_T("\"Z:\\foo\\does not exist.exe\"")));
+  if (ShouldRunLargeTest()) {
+    EXPECT_FALSE(File::Exists(_T("\"\\\\foo\\does not exist.exe\"")));
+  }
+}
+
+// File::Exists() handles trailing spaces but not leading whitespace, tabs, or
+// enclosed paths.
+TEST(FileTest, Exists_ExtraWhitespace) {
+  EXPECT_TRUE(File::Exists(kIEBrowserExe _T(" ")));
+  EXPECT_TRUE(File::Exists(kIEBrowserExe _T("    ")));
+  EXPECT_FALSE(File::Exists(_T(" ") kIEBrowserExe));
+  EXPECT_FALSE(File::Exists(kIEBrowserExe _T("\t")));
+
+  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe _T(" ")));
+  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe _T("    ")));
+  EXPECT_FALSE(File::Exists(_T(" ") kIEBrowserQuotedExe));
+  EXPECT_FALSE(File::Exists(kIEBrowserQuotedExe _T("\t")));
+
+  EXPECT_FALSE(File::Exists(_T("\"") kIEBrowserExe _T(" \"")));
+  EXPECT_FALSE(File::Exists(_T("\"") kIEBrowserExe _T("    \"")));
+  EXPECT_FALSE(File::Exists(_T("\" ") kIEBrowserExe _T("\"") ));
+  EXPECT_FALSE(File::Exists(_T("\"") kIEBrowserExe _T("\t\"")));
+
+  EXPECT_FALSE(File::Exists(_T("\"") kIEBrowserExe _T(" \" ")));
+}
+
+}  // namespace omaha
diff --git a/common/file_ver.cc b/common/file_ver.cc
index 2754a5b..6aed887 100644
--- a/common/file_ver.cc
+++ b/common/file_ver.cc
@@ -1,177 +1,177 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/file_ver.h"

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-// TODO(omaha): Write unittest for this class.

-

-FileVer::FileVer() {

-  file_ver_data_ = NULL;

-  lang_charset_ = 0;

-}

-

-FileVer::~FileVer() {

-  Close();

-}

-

-void FileVer::Close() {

-  delete[] file_ver_data_;

-  file_ver_data_ = NULL;

-  lang_charset_ = 0;

-}

-

-BOOL FileVer::Open(const TCHAR* lpszModuleName) {

-  ASSERT1(lpszModuleName);

-

-  // Get the version information size and allocate the buffer.

-  DWORD handle;

-  DWORD ver_info_size =

-      ::GetFileVersionInfoSize(const_cast<TCHAR*>(lpszModuleName), &handle);

-  if (ver_info_size == 0) {

-    return FALSE;

-  }

-

-  // Get version information.

-  // file_ver_data_ is allocated here and deleted in Close() (or implicitly

-  // in the destructor).

-  file_ver_data_ = new byte[ver_info_size];

-  ASSERT1(file_ver_data_);

-  if (!file_ver_data_) {

-    return FALSE;

-  }

-

-  if (!::GetFileVersionInfo(const_cast<TCHAR*>(lpszModuleName), handle,

-                            ver_info_size,

-                            reinterpret_cast<void**>(file_ver_data_))) {

-    Close();

-    return FALSE;

-  }

-

-  // Get the first language and character-set identifier.

-  UINT query_size = 0;

-  DWORD* translation_table = NULL;

-  if (!::VerQueryValue(file_ver_data_,

-                       _T("\\VarFileInfo\\Translation"),

-                       reinterpret_cast<void**>(&translation_table),

-                       &query_size) ||

-      query_size == 0) {

-    Close();

-    return FALSE;

-  }

-

-  ASSERT1(query_size != 0);

-  ASSERT1(translation_table);

-

-  // Create charset.

-  lang_charset_ = MAKELONG(HIWORD(translation_table[0]),

-                           LOWORD(translation_table[0]));

-  return TRUE;

-}

-

-CString FileVer::QueryValue(const TCHAR* lpszValueName) const {

-  ASSERT1(lpszValueName);

-

-  if (file_ver_data_ == NULL) {

-    return (CString)_T("");

-  }

-

-  // Query version information value.

-  UINT query_size = 0;

-  LPVOID query_data = NULL;

-  CString str_query_value, str_block_name;

-  str_block_name.Format(_T("\\StringFileInfo\\%08lx\\%s"),

-                        lang_charset_,

-                        lpszValueName);

-

-  if (::VerQueryValue(reinterpret_cast<void**>(file_ver_data_),

-                      str_block_name.GetBuffer(0),

-                      &query_data,

-                      &query_size) &&

-      query_size != 0 &&

-      query_data) {

-    str_query_value = reinterpret_cast<const TCHAR*>(query_data);

-  }

-

-  str_block_name.ReleaseBuffer();

-

-  return str_query_value;

-}

-

-BOOL FileVer::GetFixedInfo(VS_FIXEDFILEINFO& vsffi) const {   // NOLINT

-  if (file_ver_data_ == NULL) {

-    return FALSE;

-  }

-

-  UINT query_size = 0;

-  VS_FIXEDFILEINFO* pVsffi = NULL;

-  if (::VerQueryValue(reinterpret_cast<void**>(file_ver_data_),

-                      _T("\\"),

-                      reinterpret_cast<void**>(&pVsffi),

-                      &query_size) &&

-      query_size != 0 &&

-      pVsffi) {

-    vsffi = *pVsffi;

-    return TRUE;

-  }

-

-  return FALSE;

-}

-

-CString FileVer::FormatFixedFileVersion() const {

-  CString str_version;

-  VS_FIXEDFILEINFO vsffi = {0};

-

-  if (GetFixedInfo(vsffi)) {

-    str_version.Format(NOTRANSL(_T("%u.%u.%u.%u")),

-                       HIWORD(vsffi.dwFileVersionMS),

-                       LOWORD(vsffi.dwFileVersionMS),

-                       HIWORD(vsffi.dwFileVersionLS),

-                       LOWORD(vsffi.dwFileVersionLS));

-  }

-  return str_version;

-}

-

-CString FileVer::FormatFixedProductVersion() const {

-  CString str_version;

-  VS_FIXEDFILEINFO vsffi = {0};

-

-  if (GetFixedInfo(vsffi)) {

-    str_version.Format(NOTRANSL(_T("%u.%u.%u.%u")),

-                       HIWORD(vsffi.dwProductVersionMS),

-                       LOWORD(vsffi.dwProductVersionMS),

-                       HIWORD(vsffi.dwProductVersionLS),

-                       LOWORD(vsffi.dwProductVersionLS));

-  }

-  return str_version;

-}

-

-ULONGLONG FileVer::GetFileVersionAsULONGLONG() const {

-  ULONGLONG version = 0;

-  VS_FIXEDFILEINFO vsffi = {0};

-

-  if (GetFixedInfo(vsffi)) {

-    version = MAKEDLLVERULL(HIWORD(vsffi.dwProductVersionMS),

-                            LOWORD(vsffi.dwProductVersionMS),

-                            HIWORD(vsffi.dwProductVersionLS),

-                            LOWORD(vsffi.dwProductVersionLS));

-  }

-  return version;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/file_ver.h"
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+// TODO(omaha): Write unittest for this class.
+
+FileVer::FileVer() {
+  file_ver_data_ = NULL;
+  lang_charset_ = 0;
+}
+
+FileVer::~FileVer() {
+  Close();
+}
+
+void FileVer::Close() {
+  delete[] file_ver_data_;
+  file_ver_data_ = NULL;
+  lang_charset_ = 0;
+}
+
+BOOL FileVer::Open(const TCHAR* lpszModuleName) {
+  ASSERT1(lpszModuleName);
+
+  // Get the version information size and allocate the buffer.
+  DWORD handle;
+  DWORD ver_info_size =
+      ::GetFileVersionInfoSize(const_cast<TCHAR*>(lpszModuleName), &handle);
+  if (ver_info_size == 0) {
+    return FALSE;
+  }
+
+  // Get version information.
+  // file_ver_data_ is allocated here and deleted in Close() (or implicitly
+  // in the destructor).
+  file_ver_data_ = new byte[ver_info_size];
+  ASSERT1(file_ver_data_);
+  if (!file_ver_data_) {
+    return FALSE;
+  }
+
+  if (!::GetFileVersionInfo(const_cast<TCHAR*>(lpszModuleName), handle,
+                            ver_info_size,
+                            reinterpret_cast<void**>(file_ver_data_))) {
+    Close();
+    return FALSE;
+  }
+
+  // Get the first language and character-set identifier.
+  UINT query_size = 0;
+  DWORD* translation_table = NULL;
+  if (!::VerQueryValue(file_ver_data_,
+                       _T("\\VarFileInfo\\Translation"),
+                       reinterpret_cast<void**>(&translation_table),
+                       &query_size) ||
+      query_size == 0) {
+    Close();
+    return FALSE;
+  }
+
+  ASSERT1(query_size != 0);
+  ASSERT1(translation_table);
+
+  // Create charset.
+  lang_charset_ = MAKELONG(HIWORD(translation_table[0]),
+                           LOWORD(translation_table[0]));
+  return TRUE;
+}
+
+CString FileVer::QueryValue(const TCHAR* lpszValueName) const {
+  ASSERT1(lpszValueName);
+
+  if (file_ver_data_ == NULL) {
+    return (CString)_T("");
+  }
+
+  // Query version information value.
+  UINT query_size = 0;
+  LPVOID query_data = NULL;
+  CString str_query_value, str_block_name;
+  str_block_name.Format(_T("\\StringFileInfo\\%08lx\\%s"),
+                        lang_charset_,
+                        lpszValueName);
+
+  if (::VerQueryValue(reinterpret_cast<void**>(file_ver_data_),
+                      str_block_name.GetBuffer(0),
+                      &query_data,
+                      &query_size) &&
+      query_size != 0 &&
+      query_data) {
+    str_query_value = reinterpret_cast<const TCHAR*>(query_data);
+  }
+
+  str_block_name.ReleaseBuffer();
+
+  return str_query_value;
+}
+
+BOOL FileVer::GetFixedInfo(VS_FIXEDFILEINFO& vsffi) const {   // NOLINT
+  if (file_ver_data_ == NULL) {
+    return FALSE;
+  }
+
+  UINT query_size = 0;
+  VS_FIXEDFILEINFO* pVsffi = NULL;
+  if (::VerQueryValue(reinterpret_cast<void**>(file_ver_data_),
+                      _T("\\"),
+                      reinterpret_cast<void**>(&pVsffi),
+                      &query_size) &&
+      query_size != 0 &&
+      pVsffi) {
+    vsffi = *pVsffi;
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+CString FileVer::FormatFixedFileVersion() const {
+  CString str_version;
+  VS_FIXEDFILEINFO vsffi = {0};
+
+  if (GetFixedInfo(vsffi)) {
+    str_version.Format(NOTRANSL(_T("%u.%u.%u.%u")),
+                       HIWORD(vsffi.dwFileVersionMS),
+                       LOWORD(vsffi.dwFileVersionMS),
+                       HIWORD(vsffi.dwFileVersionLS),
+                       LOWORD(vsffi.dwFileVersionLS));
+  }
+  return str_version;
+}
+
+CString FileVer::FormatFixedProductVersion() const {
+  CString str_version;
+  VS_FIXEDFILEINFO vsffi = {0};
+
+  if (GetFixedInfo(vsffi)) {
+    str_version.Format(NOTRANSL(_T("%u.%u.%u.%u")),
+                       HIWORD(vsffi.dwProductVersionMS),
+                       LOWORD(vsffi.dwProductVersionMS),
+                       HIWORD(vsffi.dwProductVersionLS),
+                       LOWORD(vsffi.dwProductVersionLS));
+  }
+  return str_version;
+}
+
+ULONGLONG FileVer::GetFileVersionAsULONGLONG() const {
+  ULONGLONG version = 0;
+  VS_FIXEDFILEINFO vsffi = {0};
+
+  if (GetFixedInfo(vsffi)) {
+    version = MAKEDLLVERULL(HIWORD(vsffi.dwProductVersionMS),
+                            LOWORD(vsffi.dwProductVersionMS),
+                            HIWORD(vsffi.dwProductVersionLS),
+                            LOWORD(vsffi.dwProductVersionLS));
+  }
+  return version;
+}
+
+}  // namespace omaha
+
diff --git a/common/file_ver.h b/common/file_ver.h
index d3c9815..6ba29f0 100644
--- a/common/file_ver.h
+++ b/common/file_ver.h
@@ -1,73 +1,73 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_FILE_VER_H_

-#define OMAHA_COMMON_FILE_VER_H_

-

-#include <windows.h>

-#include <tchar.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class FileVer {

- public:

-  FileVer();

-  ~FileVer();

-

-  // opens the version info for the specified file

-  BOOL Open(const TCHAR* lpszModuleName);

-

-  // Cleanup

-  void Close();

-

-  // Query for a given vlaue

-  CString QueryValue(const TCHAR* lpszValueName) const;

-

-  // Shortcuts for common values

-  CString GetFileDescription() const {return QueryValue(_T("FileDescription"));}

-  CString GetFileVersion() const     {return QueryValue(_T("FileVersion"));    }

-  CString GetCompanyName() const     {return QueryValue(_T("CompanyName"));    }

-  CString GetProductName() const     {return QueryValue(_T("ProductName"));    }

-  CString GetProductVersion() const  {return QueryValue(_T("ProductVersion")); }

-

-  // gets the FIXEDFILEINFO datastructure

-  BOOL GetFixedInfo(VS_FIXEDFILEINFO& vsffi) const;   // NOLINT

-

-  // returns a formated string representing the file and product versions

-  // e.g. 2.4.124.34

-  CString FormatFixedFileVersion() const;

-  CString FormatFixedProductVersion() const;

-

-  // Returns a ULONGLONG containing the version in DLL version format.

-  ULONGLONG GetFileVersionAsULONGLONG() const;

-

-  // gets the language ID

-  LCID GetLanguageID() const         { return HIWORD(lang_charset_); }

-

- private:

-  // versioning data returned by GetFileVersionInfo

-  byte*  file_ver_data_;

-

-  // language charset

-  DWORD   lang_charset_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(FileVer);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_FILE_VER_H_

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_FILE_VER_H_
+#define OMAHA_COMMON_FILE_VER_H_
+
+#include <windows.h>
+#include <tchar.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class FileVer {
+ public:
+  FileVer();
+  ~FileVer();
+
+  // opens the version info for the specified file
+  BOOL Open(const TCHAR* lpszModuleName);
+
+  // Cleanup
+  void Close();
+
+  // Query for a given vlaue
+  CString QueryValue(const TCHAR* lpszValueName) const;
+
+  // Shortcuts for common values
+  CString GetFileDescription() const {return QueryValue(_T("FileDescription"));}
+  CString GetFileVersion() const     {return QueryValue(_T("FileVersion"));    }
+  CString GetCompanyName() const     {return QueryValue(_T("CompanyName"));    }
+  CString GetProductName() const     {return QueryValue(_T("ProductName"));    }
+  CString GetProductVersion() const  {return QueryValue(_T("ProductVersion")); }
+
+  // gets the FIXEDFILEINFO datastructure
+  BOOL GetFixedInfo(VS_FIXEDFILEINFO& vsffi) const;   // NOLINT
+
+  // returns a formated string representing the file and product versions
+  // e.g. 2.4.124.34
+  CString FormatFixedFileVersion() const;
+  CString FormatFixedProductVersion() const;
+
+  // Returns a ULONGLONG containing the version in DLL version format.
+  ULONGLONG GetFileVersionAsULONGLONG() const;
+
+  // gets the language ID
+  LCID GetLanguageID() const         { return HIWORD(lang_charset_); }
+
+ private:
+  // versioning data returned by GetFileVersionInfo
+  byte*  file_ver_data_;
+
+  // language charset
+  DWORD   lang_charset_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(FileVer);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_FILE_VER_H_
diff --git a/common/firewall_product_detection.cc b/common/firewall_product_detection.cc
index 1b80d9f..cc32cfa 100644
--- a/common/firewall_product_detection.cc
+++ b/common/firewall_product_detection.cc
@@ -1,67 +1,67 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/firewall_product_detection.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/wmi_query.h"

-

-namespace omaha {

-

-namespace firewall_detection {

-

-namespace {

-

-const TCHAR kWmiSecurityCenter[]        = _T("root\\SecurityCenter");

-const TCHAR kWmiQueryFirewallProduct[]  = _T("select * from FirewallProduct");

-const TCHAR kWmiPropDisplayName[]       = _T("displayName");

-const TCHAR kWmiPropVersionNumber[]     = _T("versionNumber");

-

-}  // namespace

-

-

-HRESULT Detect(CString* name, CString* version) {

-  ASSERT1(name);

-  ASSERT1(version);

-

-  name->Empty();

-  version->Empty();

-

-  WmiQuery wmi_query;

-  HRESULT hr = wmi_query.Connect(kWmiSecurityCenter);

-  if FAILED(hr) {

-    return hr;

-  }

-  hr = wmi_query.Query(kWmiQueryFirewallProduct);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (wmi_query.AtEnd()) {

-    return E_FAIL;

-  }

-  hr = wmi_query.GetValue(kWmiPropDisplayName, name);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  wmi_query.GetValue(kWmiPropVersionNumber, version);

-  return S_OK;

-}

-

-}  // namespace firewall_detection

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/firewall_product_detection.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/wmi_query.h"
+
+namespace omaha {
+
+namespace firewall_detection {
+
+namespace {
+
+const TCHAR kWmiSecurityCenter[]        = _T("root\\SecurityCenter");
+const TCHAR kWmiQueryFirewallProduct[]  = _T("select * from FirewallProduct");
+const TCHAR kWmiPropDisplayName[]       = _T("displayName");
+const TCHAR kWmiPropVersionNumber[]     = _T("versionNumber");
+
+}  // namespace
+
+
+HRESULT Detect(CString* name, CString* version) {
+  ASSERT1(name);
+  ASSERT1(version);
+
+  name->Empty();
+  version->Empty();
+
+  WmiQuery wmi_query;
+  HRESULT hr = wmi_query.Connect(kWmiSecurityCenter);
+  if FAILED(hr) {
+    return hr;
+  }
+  hr = wmi_query.Query(kWmiQueryFirewallProduct);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (wmi_query.AtEnd()) {
+    return E_FAIL;
+  }
+  hr = wmi_query.GetValue(kWmiPropDisplayName, name);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  wmi_query.GetValue(kWmiPropVersionNumber, version);
+  return S_OK;
+}
+
+}  // namespace firewall_detection
+
+}  // namespace omaha
+
diff --git a/common/firewall_product_detection.h b/common/firewall_product_detection.h
index c09ef16..d29e786 100644
--- a/common/firewall_product_detection.h
+++ b/common/firewall_product_detection.h
@@ -1,33 +1,33 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_FIREWALL_PRODUCT_DETECTION_H_

-#define OMAHA_COMMON_FIREWALL_PRODUCT_DETECTION_H_

-

-#include <windows.h>

-#include <atlstr.h>

-

-namespace omaha {

-

-namespace firewall_detection {

-

-// Detects if the computer is running a software firewall.

-HRESULT Detect(CString* name, CString* version);

-

-}  // namespace firewall_detection

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_FIREWALL_PRODUCT_DETECTION_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_FIREWALL_PRODUCT_DETECTION_H_
+#define OMAHA_COMMON_FIREWALL_PRODUCT_DETECTION_H_
+
+#include <windows.h>
+#include <atlstr.h>
+
+namespace omaha {
+
+namespace firewall_detection {
+
+// Detects if the computer is running a software firewall.
+HRESULT Detect(CString* name, CString* version);
+
+}  // namespace firewall_detection
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_FIREWALL_PRODUCT_DETECTION_H_
diff --git a/common/firewall_product_detection_unittest.cc b/common/firewall_product_detection_unittest.cc
index 46b4a19..fe440ee 100644
--- a/common/firewall_product_detection_unittest.cc
+++ b/common/firewall_product_detection_unittest.cc
@@ -1,36 +1,36 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/firewall_product_detection.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace firewall_detection {

-

-TEST(FirewallProductDetection, Detect) {

-  CString name, version;

-  HRESULT hr = Detect(&name, &version);

-  if (SUCCEEDED(hr)) {

-    EXPECT_FALSE(name.IsEmpty());

-    EXPECT_FALSE(version.IsEmpty());

-  }

-}

-

-}  // namespace firewall_detection

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/firewall_product_detection.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace firewall_detection {
+
+TEST(FirewallProductDetection, Detect) {
+  CString name, version;
+  HRESULT hr = Detect(&name, &version);
+  if (SUCCEEDED(hr)) {
+    EXPECT_FALSE(name.IsEmpty());
+    EXPECT_FALSE(version.IsEmpty());
+  }
+}
+
+}  // namespace firewall_detection
+
+}  // namespace omaha
+
diff --git a/common/generic_reg_file_appid.rgs b/common/generic_reg_file_appid.rgs
index d4b42da..829d0b2 100644
--- a/common/generic_reg_file_appid.rgs
+++ b/common/generic_reg_file_appid.rgs
@@ -1,18 +1,18 @@
-HKLM

-{

-  NoRemove SOFTWARE

-  {

-    NoRemove Classes

-    {

-      NoRemove AppID

-      {

-        ForceRemove '%APPID%' = s '%DESCRIPTION%'

-        ForceRemove '%FILENAME%'

-        {

-          val AppID = s '%APPID%'

-        }

-      }

-    }

-  }

-}

-

+HKLM
+{
+  NoRemove SOFTWARE
+  {
+    NoRemove Classes
+    {
+      NoRemove AppID
+      {
+        ForceRemove '%APPID%' = s '%DESCRIPTION%'
+        ForceRemove '%FILENAME%'
+        {
+          val AppID = s '%APPID%'
+        }
+      }
+    }
+  }
+}
+
diff --git a/common/generic_reg_file_elevation_localserver.rgs b/common/generic_reg_file_elevation_localserver.rgs
index 10cc551..15aeb12 100644
--- a/common/generic_reg_file_elevation_localserver.rgs
+++ b/common/generic_reg_file_elevation_localserver.rgs
@@ -1,35 +1,35 @@
-HKLM

-{

-  NoRemove SOFTWARE

-  {

-    NoRemove Classes

-    {

-      %PROGID%.%VERSION% = s '%DESCRIPTION%'

-      {

-        CLSID = s '%CLSID%'

-      }

-      %PROGID% = s '%DESCRIPTION%'

-      {

-        CLSID = s '%CLSID%'

-        CurVer = s '%PROGID%.%VERSION%'

-      }

-      NoRemove CLSID

-      {

-        ForceRemove %CLSID% = s '%DESCRIPTION%'

-        {

-          ProgID = s '%PROGID%.%VERSION%'

-          VersionIndependentProgID = s '%PROGID%'

-          LocalServer32 = s '%MODULE%'

-          'TypeLib' = s '%LIBID%'

-          val LocalizedString = s '@%MODULE_RAW%,-%STRINGRESID%'

-          Elevation

-          {

-            val Enabled = d '1'

-            val IconReference = s '@%MODULE_RAW%,-%ICONRESID%'

-          }

-        }

-      }

-    }

-  }

-}

-

+HKLM
+{
+  NoRemove SOFTWARE
+  {
+    NoRemove Classes
+    {
+      %PROGID%.%VERSION% = s '%DESCRIPTION%'
+      {
+        CLSID = s '%CLSID%'
+      }
+      %PROGID% = s '%DESCRIPTION%'
+      {
+        CLSID = s '%CLSID%'
+        CurVer = s '%PROGID%.%VERSION%'
+      }
+      NoRemove CLSID
+      {
+        ForceRemove %CLSID% = s '%DESCRIPTION%'
+        {
+          ProgID = s '%PROGID%.%VERSION%'
+          VersionIndependentProgID = s '%PROGID%'
+          LocalServer32 = s '%MODULE%'
+          'TypeLib' = s '%LIBID%'
+          val LocalizedString = s '@%MODULE_RAW%,-%STRINGRESID%'
+          Elevation
+          {
+            val Enabled = d '1'
+            val IconReference = s '@%MODULE_RAW%,-%ICONRESID%'
+          }
+        }
+      }
+    }
+  }
+}
+
diff --git a/common/generic_reg_file_local_server.rgs b/common/generic_reg_file_local_server.rgs
index 7d0f518..d98b665 100644
--- a/common/generic_reg_file_local_server.rgs
+++ b/common/generic_reg_file_local_server.rgs
@@ -1,29 +1,29 @@
-%HKROOT%

-{

-  NoRemove SOFTWARE

-  {

-    NoRemove Classes

-    {

-      %PROGID%.%VERSION% = s '%DESCRIPTION%'

-      {

-        CLSID = s '%CLSID%'

-      }

-      %PROGID% = s '%DESCRIPTION%'

-      {

-        CLSID = s '%CLSID%'

-        CurVer = s '%PROGID%.%VERSION%'

-      }

-      NoRemove CLSID

-      {

-        ForceRemove %CLSID% = s '%DESCRIPTION%'

-        {

-          ProgID = s '%PROGID%.%VERSION%'

-          VersionIndependentProgID = s '%PROGID%'

-          LocalServer32 = s '%MODULE%'

-          'TypeLib' = s '%LIBID%'

-        }

-      }

-    }

-  }

-}

-

+%HKROOT%
+{
+  NoRemove SOFTWARE
+  {
+    NoRemove Classes
+    {
+      %PROGID%.%VERSION% = s '%DESCRIPTION%'
+      {
+        CLSID = s '%CLSID%'
+      }
+      %PROGID% = s '%DESCRIPTION%'
+      {
+        CLSID = s '%CLSID%'
+        CurVer = s '%PROGID%.%VERSION%'
+      }
+      NoRemove CLSID
+      {
+        ForceRemove %CLSID% = s '%DESCRIPTION%'
+        {
+          ProgID = s '%PROGID%.%VERSION%'
+          VersionIndependentProgID = s '%PROGID%'
+          LocalServer32 = s '%MODULE%'
+          'TypeLib' = s '%LIBID%'
+        }
+      }
+    }
+  }
+}
+
diff --git a/common/generic_reg_file_local_server_w_appid.rgs b/common/generic_reg_file_local_server_w_appid.rgs
index 444e0d8..f3be278 100644
--- a/common/generic_reg_file_local_server_w_appid.rgs
+++ b/common/generic_reg_file_local_server_w_appid.rgs
@@ -1,62 +1,62 @@
-HKCR

-{

-  %PROGID%.%VERSION% = s '%DESCRIPTION%'

-  {

-    CLSID = s '%CLSID%'

-  }

-  %PROGID% = s '%DESCRIPTION%'

-  {

-    CLSID = s '%CLSID%'

-    CurVer = s '%PROGID%.%VERSION%'

-  }

-  NoRemove CLSID

-  {

-    ForceRemove %CLSID% = s '%DESCRIPTION%'

-    {

-      ProgID = s '%PROGID%.%VERSION%'

-      VersionIndependentProgID = s '%PROGID%'

-      ForceRemove 'Programmable'

-      LocalServer32 = s '%MODULE%'

-      {

-        val ThreadingModel = s '%THREADING%'

-      }

-      val AppID = s '%APPID%'

-      'TypeLib' = s '%LIBID%'

-    }

-  }

-  NoRemove AppID

-  {

-    ForceRemove %APPID% = s '%DESCRIPTION%'

-    {

-    

-    }

-    ForceRemove %OBJECTFILENAME%

-    {

-      val AppID = s '%APPID%'

-    }    

-  }	

-}

-HKLM

-{

-  NoRemove SOFTWARE

-  {

-    NoRemove Microsoft

-    {

-      NoRemove 'Internet Explorer'

-      {

-        NoRemove 'Low Rights'

-        {

-          NoRemove ElevationPolicy

-          {

-            ForceRemove %APPID%

-            {

-              val AppName = s '%OBJECTFILENAME%'

-              val AppPath = s '%MODULEPATH%'

-              val Policy = d '3'

-            }          

-          }      

-        }  

-      }  

-    }  

-  }

+HKCR
+{
+  %PROGID%.%VERSION% = s '%DESCRIPTION%'
+  {
+    CLSID = s '%CLSID%'
+  }
+  %PROGID% = s '%DESCRIPTION%'
+  {
+    CLSID = s '%CLSID%'
+    CurVer = s '%PROGID%.%VERSION%'
+  }
+  NoRemove CLSID
+  {
+    ForceRemove %CLSID% = s '%DESCRIPTION%'
+    {
+      ProgID = s '%PROGID%.%VERSION%'
+      VersionIndependentProgID = s '%PROGID%'
+      ForceRemove 'Programmable'
+      LocalServer32 = s '%MODULE%'
+      {
+        val ThreadingModel = s '%THREADING%'
+      }
+      val AppID = s '%APPID%'
+      'TypeLib' = s '%LIBID%'
+    }
+  }
+  NoRemove AppID
+  {
+    ForceRemove %APPID% = s '%DESCRIPTION%'
+    {
+    
+    }
+    ForceRemove %OBJECTFILENAME%
+    {
+      val AppID = s '%APPID%'
+    }    
+  }	
+}
+HKLM
+{
+  NoRemove SOFTWARE
+  {
+    NoRemove Microsoft
+    {
+      NoRemove 'Internet Explorer'
+      {
+        NoRemove 'Low Rights'
+        {
+          NoRemove ElevationPolicy
+          {
+            ForceRemove %APPID%
+            {
+              val AppName = s '%OBJECTFILENAME%'
+              val AppPath = s '%MODULEPATH%'
+              val Policy = d '3'
+            }          
+          }      
+        }  
+      }  
+    }  
+  }
 }
\ No newline at end of file
diff --git a/common/generic_reg_file_localservice.rgs b/common/generic_reg_file_localservice.rgs
index f570709..77eaf13 100644
--- a/common/generic_reg_file_localservice.rgs
+++ b/common/generic_reg_file_localservice.rgs
@@ -1,28 +1,28 @@
-HKLM

-{

-  NoRemove SOFTWARE

-  {

-    NoRemove Classes

-    {

-      %PROGID%.%VERSION% = s '%DESCRIPTION%'

-      {

-        CLSID = s '%CLSID%'

-      }

-      %PROGID% = s '%DESCRIPTION%'

-      {

-        CLSID = s '%CLSID%'

-        CurVer = s '%PROGID%.%VERSION%'

-      }

-      NoRemove CLSID

-      {

-        ForceRemove %CLSID% = s '%DESCRIPTION%'

-        {

-          ProgID = s '%PROGID%.%VERSION%'

-          VersionIndependentProgID = s '%PROGID%'

-          val AppID = s '%APPID%'

-        }

-      }

-    }

-  }

-}

-

+HKLM
+{
+  NoRemove SOFTWARE
+  {
+    NoRemove Classes
+    {
+      %PROGID%.%VERSION% = s '%DESCRIPTION%'
+      {
+        CLSID = s '%CLSID%'
+      }
+      %PROGID% = s '%DESCRIPTION%'
+      {
+        CLSID = s '%CLSID%'
+        CurVer = s '%PROGID%.%VERSION%'
+      }
+      NoRemove CLSID
+      {
+        ForceRemove %CLSID% = s '%DESCRIPTION%'
+        {
+          ProgID = s '%PROGID%.%VERSION%'
+          VersionIndependentProgID = s '%PROGID%'
+          val AppID = s '%APPID%'
+        }
+      }
+    }
+  }
+}
+
diff --git a/common/generic_reg_file_typelib.rgs b/common/generic_reg_file_typelib.rgs
index 026809d..909aa96 100644
--- a/common/generic_reg_file_typelib.rgs
+++ b/common/generic_reg_file_typelib.rgs
@@ -1,10 +1,10 @@
-HKCR

-{

-  NoRemove CLSID

-  {

-    ForceRemove %CLSID% = s '%DESCRIPTION%'

-    {

-      'TypeLib' = s '%LIBID%'

-    }

-  }

-}

+HKCR
+{
+  NoRemove CLSID
+  {
+    ForceRemove %CLSID% = s '%DESCRIPTION%'
+    {
+      'TypeLib' = s '%LIBID%'
+    }
+  }
+}
diff --git a/common/google_update_recovery.cc b/common/google_update_recovery.cc
index 4513826..f3dcec5 100644
--- a/common/google_update_recovery.cc
+++ b/common/google_update_recovery.cc
@@ -1,639 +1,639 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Implementation of the Google Update recovery mechanism to be included in

-// Google apps.

-

-#include "omaha/common/google_update_recovery.h"

-#include <shellapi.h>

-#include <wininet.h>

-#include <atlstr.h>

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/signaturevalidator.h"

-// TODO(omaha): Move this file to common.

-#include "omaha/enterprise/const_group_policy.h"

-#include "omaha/third_party/smartany/scoped_any.h"

-

-namespace omaha {

-

-namespace {

-

-const int kRollbackWindowDays = 100;

-

-const TCHAR* const kMachineRepairArgs = _T("/recover /machine");

-const TCHAR* const kUserRepairArgs = _T("/recover");

-

-// TODO(omaha): Add a Code Red lib version that is manually updated when

-// we check in the lib.

-const TCHAR* const kQueryStringFormat =

-    _T("?appid=%s&appversion=%s&applang=%s&machine=%u")

-    _T("&version=%s&machineid=%s&userid=%s")

-    _T("&osversion=%s&servicepack=%s");

-

-// Information about where to obtain Omaha info.

-// This must never change in Omaha.

-const TCHAR* const kRegValueProductVersion  = _T("pv");

-const TCHAR* const kRegValueUserId          = _T("ui");

-const TCHAR* const kRegValueMachineId       = _T("mi");

-const TCHAR* const kRelativeGoopdateRegPath = _T("Software\\Google\\Update\\");

-const TCHAR* const kRelativeClientsGoopdateRegPath =

-    _T("Software\\Google\\Update\\Clients\\")

-    _T("{430FD4D0-B729-4F61-AA34-91526481799D}");

-

-// Starts another process via ::CreateProcess.

-HRESULT StartProcess(const TCHAR* process_name,

-                     TCHAR* command_line) {

-  if (!process_name && !command_line) {

-    return E_INVALIDARG;

-  }

-

-  PROCESS_INFORMATION pi = {0};

-  STARTUPINFO si = {sizeof(si), 0};

-

-  // Feedback cursor is off while the process is starting.

-  si.dwFlags = STARTF_FORCEOFFFEEDBACK;

-

-  BOOL success = ::CreateProcess(

-      process_name,     // Module name

-      command_line,     // Command line

-      NULL,             // Process handle not inheritable

-      NULL,             // Thread handle not inheritable

-      FALSE,            // Set handle inheritance to FALSE

-      0,                // No creation flags

-      NULL,             // Use parent's environment block

-      NULL,             // Use parent's starting directory

-      &si,              // Pointer to STARTUPINFO structure

-      &pi);             // Pointer to PROCESS_INFORMATION structure

-

-  if (!success) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  ::CloseHandle(pi.hProcess);

-  ::CloseHandle(pi.hThread);

-

-  return S_OK;

-}

-

-// Check if a string starts with another string. Case-sensitive.

-bool StringStartsWith(const TCHAR *str, const TCHAR *start_str) {

-  if (!start_str || !str) {

-    return false;

-  }

-

-  while (0 != *str) {

-    // Check for matching characters

-    TCHAR c1 = *str;

-    TCHAR c2 = *start_str;

-

-    // Reached the end of start_str?

-    if (0 == c2)

-      return true;

-

-    if (c1 != c2)

-      return false;

-

-    ++str;

-    ++start_str;

-  }

-

-  // If str is shorter than start_str, no match.  If equal size, match.

-  return 0 == *start_str;

-}

-

-// Escape and unescape strings (shlwapi-based implementation).

-// The intended usage for these APIs is escaping strings to make up

-// URLs, for example building query strings.

-//

-// Pass false to the flag segment_only to escape the url. This will not

-// cause the conversion of the # (%23), ? (%3F), and / (%2F) characters.

-

-// Characters that must be encoded include any characters that have no

-// corresponding graphic character in the US-ASCII coded character

-// set (hexadecimal 80-FF, which are not used in the US-ASCII coded character

-// set, and hexadecimal 00-1F and 7F, which are control characters),

-// blank spaces, "%" (which is used to encode other characters),

-// and unsafe characters (<, >, ", #, {, }, |, \, ^, ~, [, ], and ').

-//

-// The input and output strings can't be longer than INTERNET_MAX_URL_LENGTH

-

-HRESULT StringEscape(const CString& str_in,

-                     bool segment_only,

-                     CString* escaped_string) {

-  if (!escaped_string) {

-    return E_INVALIDARG;

-  }

-

-  DWORD buf_len = INTERNET_MAX_URL_LENGTH + 1;

-  HRESULT hr = ::UrlEscape(str_in,

-                           escaped_string->GetBufferSetLength(buf_len),

-                           &buf_len,

-                           segment_only ?

-                           URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY :

-                           URL_ESCAPE_PERCENT);

-  if (SUCCEEDED(hr)) {

-    escaped_string->ReleaseBuffer();

-  }

-  return hr;

-}

-

-// Gets the temporary files directory for the current user.

-// The directory returned may not exist.

-// The returned path ends with a '\'.

-// Fails if the path is longer than MAX_PATH.

-HRESULT GetTempDir(CString* temp_path) {

-  if (!temp_path) {

-    return E_INVALIDARG;

-  }

-

-  temp_path->Empty();

-

-  TCHAR buffer[MAX_PATH] = {0};

-  DWORD num_chars = ::GetTempPath(MAX_PATH, buffer);

-  if (!num_chars) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  } else if (num_chars >= MAX_PATH) {

-    return E_FAIL;

-  }

-

-  *temp_path = buffer;

-  return S_OK;

-}

-

-// Creates the specified directory.

-HRESULT CreateDir(const CString& dir) {

-  if (!::CreateDirectory(dir, NULL)) {

-    DWORD error = ::GetLastError();

-    if (ERROR_FILE_EXISTS != error && ERROR_ALREADY_EXISTS != error) {

-      return HRESULT_FROM_WIN32(error);

-    }

-  }

-  return S_OK;

-}

-

-HRESULT GetAndCreateTempDir(CString* temp_path) {

-  if (!temp_path) {

-    return E_INVALIDARG;

-  }

-

-  HRESULT hr = GetTempDir(temp_path);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (temp_path->IsEmpty()) {

-    return E_FAIL;

-  }

-

-  // Create this dir if it doesn't already exist.

-  return CreateDir(*temp_path);

-}

-

-

-// Create a unique temporary file and returns the full path.

-HRESULT CreateUniqueTempFile(const CString& user_temp_dir,

-                             CString* unique_temp_file_path) {

-  if (user_temp_dir.IsEmpty() || !unique_temp_file_path) {

-    return E_INVALIDARG;

-  }

-

-  TCHAR unique_temp_filename[MAX_PATH] = {0};

-  if (!::GetTempFileName(user_temp_dir,

-                         _T("GUR"),  // prefix

-                         0,          // form a unique filename

-                         unique_temp_filename)) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  *unique_temp_file_path = unique_temp_filename;

-  if (unique_temp_file_path->IsEmpty()) {

-    return E_FAIL;

-  }

-

-  return S_OK;

-}

-

-// Obtains the OS version and service pack.

-HRESULT GetOSInfo(CString* os_version, CString* service_pack) {

-  if (!os_version || !service_pack) {

-    return E_INVALIDARG;

-  }

-

-  OSVERSIONINFO os_version_info = { 0 };

-  os_version_info.dwOSVersionInfoSize = sizeof(os_version_info);

-  if (!::GetVersionEx(&os_version_info)) {

-    HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());

-    return hr;

-  } else {

-    os_version->Format(_T("%d.%d"),

-                       os_version_info.dwMajorVersion,

-                       os_version_info.dwMinorVersion);

-    *service_pack = os_version_info.szCSDVersion;

-  }

-  return S_OK;

-}

-

-// Reads the specified string value from the specified registry key.

-// Only supports value types REG_SZ and REG_EXPAND_SZ.

-// REG_EXPAND_SZ strings are not expanded.

-HRESULT GetRegStringValue(bool is_machine_key,

-                          const CString& relative_key_path,

-                          const CString& value_name,

-                          CString* value) {

-  if (!value) {

-    return E_INVALIDARG;

-  }

-

-  value->Empty();

-  HKEY root_key = is_machine_key ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

-  HKEY key = NULL;

-  LONG res = ::RegOpenKeyEx(root_key, relative_key_path, 0, KEY_READ, &key);

-  if (res != ERROR_SUCCESS) {

-    return HRESULT_FROM_WIN32(res);

-  }

-

-  // First get the size of the string buffer.

-  DWORD type = 0;

-  DWORD byte_count = 0;

-  res = ::RegQueryValueEx(key, value_name, NULL, &type, NULL, &byte_count);

-  if (ERROR_SUCCESS != res) {

-    ::RegCloseKey(key);

-    return HRESULT_FROM_WIN32(res);

-  }

-  if ((type != REG_SZ && type != REG_EXPAND_SZ) || (0 == byte_count)) {

-    ::RegCloseKey(key);

-    return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);

-  }

-

-  CString local_value;

-  // GetBuffer throws when not able to allocate the requested buffer.

-  TCHAR* buffer = local_value.GetBuffer(byte_count / sizeof(TCHAR));

-  res = ::RegQueryValueEx(key,

-                          value_name,

-                          NULL,

-                          NULL,

-                          reinterpret_cast<BYTE*>(buffer),

-                          &byte_count);

-  ::RegCloseKey(key);

-  if (ERROR_SUCCESS == res) {

-    local_value.ReleaseBufferSetLength(byte_count / sizeof(TCHAR));

-    *value = local_value;

-  }

-

-  return HRESULT_FROM_WIN32(res);

-}

-

-// Reads the specified DWORD value from the specified registry key.

-// Only supports value types REG_DWORD.

-// Assumes DWORD is sufficient buffer, which must be true for valid value type.

-HRESULT GetRegDwordValue(bool is_machine_key,

-                         const CString& relative_key_path,

-                         const CString& value_name,

-                         DWORD* value) {

-  if (!value) {

-    return E_INVALIDARG;

-  }

-

-  HKEY root_key = is_machine_key ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

-  HKEY key = NULL;

-  LONG res = ::RegOpenKeyEx(root_key, relative_key_path, 0, KEY_READ, &key);

-  if (res != ERROR_SUCCESS) {

-    return HRESULT_FROM_WIN32(res);

-  }

-

-  DWORD type = 0;

-  DWORD byte_count = sizeof(*value);

-  res = ::RegQueryValueEx(key,

-                          value_name,

-                          NULL,

-                          &type,

-                          reinterpret_cast<BYTE*>(value),

-                          &byte_count);

-  ::RegCloseKey(key);

-  if (ERROR_SUCCESS != res) {

-    return HRESULT_FROM_WIN32(res);

-  }

-  if ((type != REG_DWORD) || (0 == byte_count)) {

-    return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);

-  }

-

-  return S_OK;

-}

-

-// Obtains information about the current Omaha installation.

-// Attempts to obtain as much information as possible even if errors occur.

-// Therefore, return values of GetRegStringValue are ignored.

-HRESULT GetOmahaInformation(bool is_machine_app,

-                            CString* omaha_version,

-                            CString* machine_id,

-                            CString* user_id) {

-  if (!omaha_version || !machine_id || !user_id) {

-    return E_INVALIDARG;

-  }

-

-  if (FAILED(GetRegStringValue(is_machine_app,

-                               kRelativeClientsGoopdateRegPath,

-                               kRegValueProductVersion,

-                               omaha_version))) {

-    *omaha_version = _T("0.0.0.0");

-  }

-

-  GetRegStringValue(true,  // Machine ID is always in HKLM.

-                    kRelativeGoopdateRegPath,

-                    kRegValueMachineId,

-                    machine_id);

-

-  GetRegStringValue(is_machine_app,

-                    kRelativeGoopdateRegPath,

-                    kRegValueUserId,

-                    user_id);

-

-  return S_OK;

-}

-

-// Builds the query portion of the recovery url.

-// This method obtains values necessary to build the query that are not provided

-// as parameters.

-// Attempts to build with as much information as possible even if errors occur.

-HRESULT BuildUrlQueryPortion(const CString& app_guid,

-                             const CString& app_version,

-                             const CString& app_language,

-                             bool is_machine_app,

-                             CString* query) {

-  if (!query) {

-    return E_INVALIDARG;

-  }

-

-  CString omaha_version;

-  CString machine_id;

-  CString user_id;

-  GetOmahaInformation(is_machine_app, &omaha_version, &machine_id, &user_id);

-

-  CString os_version;

-  CString os_service_pack;

-  GetOSInfo(&os_version, &os_service_pack);

-

-  // All parameters must be escaped individually before building the query.

-  CString app_guid_escaped;

-  CString app_version_escaped;

-  CString app_language_escaped;

-  CString omaha_version_escaped;

-  CString machine_id_escaped;

-  CString user_id_escaped;

-  CString os_version_escaped;

-  CString os_service_pack_escaped;

-  StringEscape(app_guid, true, &app_guid_escaped);

-  StringEscape(app_version, true, &app_version_escaped);

-  StringEscape(app_language, true, &app_language_escaped);

-  StringEscape(omaha_version, true, &omaha_version_escaped);

-  StringEscape(machine_id, true, &machine_id_escaped);

-  StringEscape(user_id, true, &user_id_escaped);

-  StringEscape(os_version, true, &os_version_escaped);

-  StringEscape(os_service_pack, true, &os_service_pack_escaped);

-

-  query->Format(kQueryStringFormat,

-                app_guid_escaped,

-                app_version_escaped,

-                app_language_escaped,

-                is_machine_app ? 1 : 0,

-                omaha_version_escaped,

-                machine_id_escaped,

-                user_id_escaped,

-                os_version_escaped,

-                os_service_pack_escaped);

-

-  return S_OK;

-}

-

-// Returns the full path to save the downloaded file to.

-// The path is based on a unique temporary filename to avoid a conflict

-// between multiple apps downloading to the same location.

-// The path to this file is also returned. The caller is responsible for

-// deleting the temporary file after using the download target path.

-// If it cannot create the unique directory, it attempts to use the user's

-// temporary directory and a constant filename.

-HRESULT GetDownloadTargetPath(CString* download_target_path,

-                              CString* temp_file_path) {

-  if (!download_target_path || !temp_file_path) {

-    return E_INVALIDARG;

-  }

-

-  CString user_temp_dir;

-  HRESULT hr = GetAndCreateTempDir(&user_temp_dir);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = CreateUniqueTempFile(user_temp_dir, temp_file_path);

-  if (SUCCEEDED(hr) && !temp_file_path->IsEmpty()) {

-    *download_target_path = *temp_file_path;

-    // Ignore the return value. A .tmp filename is better than none.

-    download_target_path->Replace(_T(".tmp"), _T(".exe"));

-  } else {

-    // Try a static filename in the temp directory as a fallback.

-    *download_target_path = user_temp_dir + _T("GoogleUpdateSetup.exe");

-    *temp_file_path = _T("");

-  }

-

-  return S_OK;

-}

-

-HRESULT DownloadRepairFile(const CString& download_target_path,

-                           const CString& app_guid,

-                           const CString& app_version,

-                           const CString& app_language,

-                           bool is_machine_app,

-                           DownloadCallback download_callback,

-                           void* context) {

-  CString query;

-  BuildUrlQueryPortion(app_guid,

-                       app_version,

-                       app_language,

-                       is_machine_app,

-                       &query);

-

-  CString url = omaha::kUrlCodeRedCheck + query;

-

-  return download_callback(url, download_target_path, context);

-}

-

-// Makes sure the path is enclosed with double quotation marks.

-void EnclosePath(CString* path) {

-  if (path) {

-    return;

-  }

-

-  if (!path->IsEmpty() && path->GetAt(0) != _T('"')) {

-    path->Insert(0, _T('"'));

-    path->AppendChar(_T('"'));

-  }

-}

-

-HRESULT RunRepairFile(const CString& file_path, bool is_machine_app) {

-  const TCHAR* repair_file_args = is_machine_app ? kMachineRepairArgs :

-                                                   kUserRepairArgs;

-

-  CString command_line(file_path);

-  EnclosePath(&command_line);

-  command_line.AppendChar(_T(' '));

-  command_line.Append(repair_file_args);

-

-  return StartProcess(NULL, command_line.GetBuffer());

-}

-

-}  // namespace

-

-// Verifies the file's integrity and that it is signed by Google.

-// We cannot prevent rollback attacks by using a version because the client

-// may not be able to determine the current version if the files and/or

-// registry entries have been deleted/corrupted.

-// Therefore, we check that the file was signed recently.

-HRESULT VerifyFileSignature(const CString& filename) {

-  // Use Authenticode/WinVerifyTrust to verify the file.

-  // Allow the revocation check to use the network.

-  HRESULT hr = VerifySignature(filename, true);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Verify that there is a Google certificate and that it has not expired.

-  if (!VerifySigneeIsGoogle(filename)) {

-    return CERT_E_CN_NO_MATCH;

-  }

-

-  // Check that the file was signed recently to limit the window for

-  // rollback attacks.

-  return VerifyFileSignedWithinDays(filename, kRollbackWindowDays);

-}

-

-// Verifies the file contains the special markup resource for repair files.

-HRESULT VerifyRepairFileMarkup(const CString& filename) {

-  const TCHAR* kMarkupResourceName = MAKEINTRESOURCE(1);

-  const TCHAR* kMarkupResourceType = _T("GOOGLEUPDATEREPAIR");

-  const DWORD kMarkupResourceExpectedValue = 1;

-

-  scoped_library module(::LoadLibraryEx(filename, 0, LOAD_LIBRARY_AS_DATAFILE));

-  if (!module) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  HRSRC resource(::FindResource(get(module),

-                                kMarkupResourceName,

-                                kMarkupResourceType));

-  if (!resource) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  if (sizeof(kMarkupResourceExpectedValue) !=

-      ::SizeofResource(get(module), resource)) {

-    return E_UNEXPECTED;

-  }

-

-  HGLOBAL loaded_resource(::LoadResource(get(module), resource));

-  if (!loaded_resource) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  const DWORD* value = static_cast<DWORD*>(::LockResource(loaded_resource));

-  if (!value) {

-    return E_HANDLE;

-  }

-

-  if (kMarkupResourceExpectedValue != *value) {

-    return E_UNEXPECTED;

-  }

-

-  return S_OK;

-}

-

-// Verifies the filename is not UNC name, the file exists, has a valid signature

-// chain, is signed by Google, and contains the special markup resource for

-// repair files.

-HRESULT VerifyIsValidRepairFile(const CString& filename) {

-  // Make sure file exists.

-  if (!::PathFileExists(filename)) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  HRESULT hr = VerifyFileSignature(filename);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return VerifyRepairFileMarkup(filename);

-}

-

-}  // namespace omaha

-

-// If a repair file is run, the file will not be deleted until reboot. Delete

-// after reboot will only succeed when executed by an admin or LocalSystem.

-// Returns HRESULT_FROM_WIN32(ERROR_ACCESS_DISABLED_BY_POLICY) if automatic

-// update checks are disabled.

-HRESULT FixGoogleUpdate(const TCHAR* app_guid,

-                        const TCHAR* app_version,

-                        const TCHAR* app_language,

-                        bool is_machine_app,

-                        DownloadCallback download_callback,

-                        void* context) {

-  if (!app_guid || !app_version || !app_language || !download_callback) {

-    return E_INVALIDARG;

-  }

-

-  DWORD update_check_period_override_minutes(UINT_MAX);

-  HRESULT hr = omaha::GetRegDwordValue(

-                   true,

-                   GOOPDATE_POLICIES_RELATIVE,

-                   omaha::kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                   &update_check_period_override_minutes);

-  if (SUCCEEDED(hr) && (0 == update_check_period_override_minutes)) {

-    return HRESULT_FROM_WIN32(ERROR_ACCESS_DISABLED_BY_POLICY);

-  }

-

-  CString download_target_path;

-  CString temp_file_path;

-  hr = omaha::GetDownloadTargetPath(&download_target_path, &temp_file_path);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (download_target_path.IsEmpty()) {

-    hr = E_FAIL;

-  }

-

-  // After calling DownloadRepairFile, don't return until the repair file and

-  // temp file have been deleted.

-  hr = omaha::DownloadRepairFile(download_target_path,

-                                 app_guid,

-                                 app_version,

-                                 app_language,

-                                 is_machine_app,

-                                 download_callback,

-                                 context);

-

-  if (SUCCEEDED(hr)) {

-    hr = omaha::VerifyIsValidRepairFile(download_target_path);

-  }

-

-  if (FAILED(hr)) {

-    ::DeleteFile(download_target_path);

-    ::DeleteFile(temp_file_path);

-    return hr;

-  }

-

-  hr = omaha::RunRepairFile(download_target_path, is_machine_app);

-  ::MoveFileEx(download_target_path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);

-  ::DeleteFile(temp_file_path);

-

-  return hr;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Implementation of the Google Update recovery mechanism to be included in
+// Google apps.
+
+#include "omaha/common/google_update_recovery.h"
+#include <shellapi.h>
+#include <wininet.h>
+#include <atlstr.h>
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/signaturevalidator.h"
+// TODO(omaha): Move this file to common.
+#include "omaha/enterprise/const_group_policy.h"
+#include "omaha/third_party/smartany/scoped_any.h"
+
+namespace omaha {
+
+namespace {
+
+const int kRollbackWindowDays = 100;
+
+const TCHAR* const kMachineRepairArgs = _T("/recover /machine");
+const TCHAR* const kUserRepairArgs = _T("/recover");
+
+// TODO(omaha): Add a Code Red lib version that is manually updated when
+// we check in the lib.
+const TCHAR* const kQueryStringFormat =
+    _T("?appid=%s&appversion=%s&applang=%s&machine=%u")
+    _T("&version=%s&machineid=%s&userid=%s")
+    _T("&osversion=%s&servicepack=%s");
+
+// Information about where to obtain Omaha info.
+// This must never change in Omaha.
+const TCHAR* const kRegValueProductVersion  = _T("pv");
+const TCHAR* const kRegValueUserId          = _T("ui");
+const TCHAR* const kRegValueMachineId       = _T("mi");
+const TCHAR* const kRelativeGoopdateRegPath = _T("Software\\Google\\Update\\");
+const TCHAR* const kRelativeClientsGoopdateRegPath =
+    _T("Software\\Google\\Update\\Clients\\")
+    _T("{430FD4D0-B729-4F61-AA34-91526481799D}");
+
+// Starts another process via ::CreateProcess.
+HRESULT StartProcess(const TCHAR* process_name,
+                     TCHAR* command_line) {
+  if (!process_name && !command_line) {
+    return E_INVALIDARG;
+  }
+
+  PROCESS_INFORMATION pi = {0};
+  STARTUPINFO si = {sizeof(si), 0};
+
+  // Feedback cursor is off while the process is starting.
+  si.dwFlags = STARTF_FORCEOFFFEEDBACK;
+
+  BOOL success = ::CreateProcess(
+      process_name,     // Module name
+      command_line,     // Command line
+      NULL,             // Process handle not inheritable
+      NULL,             // Thread handle not inheritable
+      FALSE,            // Set handle inheritance to FALSE
+      0,                // No creation flags
+      NULL,             // Use parent's environment block
+      NULL,             // Use parent's starting directory
+      &si,              // Pointer to STARTUPINFO structure
+      &pi);             // Pointer to PROCESS_INFORMATION structure
+
+  if (!success) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  ::CloseHandle(pi.hProcess);
+  ::CloseHandle(pi.hThread);
+
+  return S_OK;
+}
+
+// Check if a string starts with another string. Case-sensitive.
+bool StringStartsWith(const TCHAR *str, const TCHAR *start_str) {
+  if (!start_str || !str) {
+    return false;
+  }
+
+  while (0 != *str) {
+    // Check for matching characters
+    TCHAR c1 = *str;
+    TCHAR c2 = *start_str;
+
+    // Reached the end of start_str?
+    if (0 == c2)
+      return true;
+
+    if (c1 != c2)
+      return false;
+
+    ++str;
+    ++start_str;
+  }
+
+  // If str is shorter than start_str, no match.  If equal size, match.
+  return 0 == *start_str;
+}
+
+// Escape and unescape strings (shlwapi-based implementation).
+// The intended usage for these APIs is escaping strings to make up
+// URLs, for example building query strings.
+//
+// Pass false to the flag segment_only to escape the url. This will not
+// cause the conversion of the # (%23), ? (%3F), and / (%2F) characters.
+
+// Characters that must be encoded include any characters that have no
+// corresponding graphic character in the US-ASCII coded character
+// set (hexadecimal 80-FF, which are not used in the US-ASCII coded character
+// set, and hexadecimal 00-1F and 7F, which are control characters),
+// blank spaces, "%" (which is used to encode other characters),
+// and unsafe characters (<, >, ", #, {, }, |, \, ^, ~, [, ], and ').
+//
+// The input and output strings can't be longer than INTERNET_MAX_URL_LENGTH
+
+HRESULT StringEscape(const CString& str_in,
+                     bool segment_only,
+                     CString* escaped_string) {
+  if (!escaped_string) {
+    return E_INVALIDARG;
+  }
+
+  DWORD buf_len = INTERNET_MAX_URL_LENGTH + 1;
+  HRESULT hr = ::UrlEscape(str_in,
+                           escaped_string->GetBufferSetLength(buf_len),
+                           &buf_len,
+                           segment_only ?
+                           URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY :
+                           URL_ESCAPE_PERCENT);
+  if (SUCCEEDED(hr)) {
+    escaped_string->ReleaseBuffer();
+  }
+  return hr;
+}
+
+// Gets the temporary files directory for the current user.
+// The directory returned may not exist.
+// The returned path ends with a '\'.
+// Fails if the path is longer than MAX_PATH.
+HRESULT GetTempDir(CString* temp_path) {
+  if (!temp_path) {
+    return E_INVALIDARG;
+  }
+
+  temp_path->Empty();
+
+  TCHAR buffer[MAX_PATH] = {0};
+  DWORD num_chars = ::GetTempPath(MAX_PATH, buffer);
+  if (!num_chars) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  } else if (num_chars >= MAX_PATH) {
+    return E_FAIL;
+  }
+
+  *temp_path = buffer;
+  return S_OK;
+}
+
+// Creates the specified directory.
+HRESULT CreateDir(const CString& dir) {
+  if (!::CreateDirectory(dir, NULL)) {
+    DWORD error = ::GetLastError();
+    if (ERROR_FILE_EXISTS != error && ERROR_ALREADY_EXISTS != error) {
+      return HRESULT_FROM_WIN32(error);
+    }
+  }
+  return S_OK;
+}
+
+HRESULT GetAndCreateTempDir(CString* temp_path) {
+  if (!temp_path) {
+    return E_INVALIDARG;
+  }
+
+  HRESULT hr = GetTempDir(temp_path);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (temp_path->IsEmpty()) {
+    return E_FAIL;
+  }
+
+  // Create this dir if it doesn't already exist.
+  return CreateDir(*temp_path);
+}
+
+
+// Create a unique temporary file and returns the full path.
+HRESULT CreateUniqueTempFile(const CString& user_temp_dir,
+                             CString* unique_temp_file_path) {
+  if (user_temp_dir.IsEmpty() || !unique_temp_file_path) {
+    return E_INVALIDARG;
+  }
+
+  TCHAR unique_temp_filename[MAX_PATH] = {0};
+  if (!::GetTempFileName(user_temp_dir,
+                         _T("GUR"),  // prefix
+                         0,          // form a unique filename
+                         unique_temp_filename)) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  *unique_temp_file_path = unique_temp_filename;
+  if (unique_temp_file_path->IsEmpty()) {
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+// Obtains the OS version and service pack.
+HRESULT GetOSInfo(CString* os_version, CString* service_pack) {
+  if (!os_version || !service_pack) {
+    return E_INVALIDARG;
+  }
+
+  OSVERSIONINFO os_version_info = { 0 };
+  os_version_info.dwOSVersionInfoSize = sizeof(os_version_info);
+  if (!::GetVersionEx(&os_version_info)) {
+    HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());
+    return hr;
+  } else {
+    os_version->Format(_T("%d.%d"),
+                       os_version_info.dwMajorVersion,
+                       os_version_info.dwMinorVersion);
+    *service_pack = os_version_info.szCSDVersion;
+  }
+  return S_OK;
+}
+
+// Reads the specified string value from the specified registry key.
+// Only supports value types REG_SZ and REG_EXPAND_SZ.
+// REG_EXPAND_SZ strings are not expanded.
+HRESULT GetRegStringValue(bool is_machine_key,
+                          const CString& relative_key_path,
+                          const CString& value_name,
+                          CString* value) {
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
+  value->Empty();
+  HKEY root_key = is_machine_key ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+  HKEY key = NULL;
+  LONG res = ::RegOpenKeyEx(root_key, relative_key_path, 0, KEY_READ, &key);
+  if (res != ERROR_SUCCESS) {
+    return HRESULT_FROM_WIN32(res);
+  }
+
+  // First get the size of the string buffer.
+  DWORD type = 0;
+  DWORD byte_count = 0;
+  res = ::RegQueryValueEx(key, value_name, NULL, &type, NULL, &byte_count);
+  if (ERROR_SUCCESS != res) {
+    ::RegCloseKey(key);
+    return HRESULT_FROM_WIN32(res);
+  }
+  if ((type != REG_SZ && type != REG_EXPAND_SZ) || (0 == byte_count)) {
+    ::RegCloseKey(key);
+    return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+  }
+
+  CString local_value;
+  // GetBuffer throws when not able to allocate the requested buffer.
+  TCHAR* buffer = local_value.GetBuffer(byte_count / sizeof(TCHAR));
+  res = ::RegQueryValueEx(key,
+                          value_name,
+                          NULL,
+                          NULL,
+                          reinterpret_cast<BYTE*>(buffer),
+                          &byte_count);
+  ::RegCloseKey(key);
+  if (ERROR_SUCCESS == res) {
+    local_value.ReleaseBufferSetLength(byte_count / sizeof(TCHAR));
+    *value = local_value;
+  }
+
+  return HRESULT_FROM_WIN32(res);
+}
+
+// Reads the specified DWORD value from the specified registry key.
+// Only supports value types REG_DWORD.
+// Assumes DWORD is sufficient buffer, which must be true for valid value type.
+HRESULT GetRegDwordValue(bool is_machine_key,
+                         const CString& relative_key_path,
+                         const CString& value_name,
+                         DWORD* value) {
+  if (!value) {
+    return E_INVALIDARG;
+  }
+
+  HKEY root_key = is_machine_key ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+  HKEY key = NULL;
+  LONG res = ::RegOpenKeyEx(root_key, relative_key_path, 0, KEY_READ, &key);
+  if (res != ERROR_SUCCESS) {
+    return HRESULT_FROM_WIN32(res);
+  }
+
+  DWORD type = 0;
+  DWORD byte_count = sizeof(*value);
+  res = ::RegQueryValueEx(key,
+                          value_name,
+                          NULL,
+                          &type,
+                          reinterpret_cast<BYTE*>(value),
+                          &byte_count);
+  ::RegCloseKey(key);
+  if (ERROR_SUCCESS != res) {
+    return HRESULT_FROM_WIN32(res);
+  }
+  if ((type != REG_DWORD) || (0 == byte_count)) {
+    return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+  }
+
+  return S_OK;
+}
+
+// Obtains information about the current Omaha installation.
+// Attempts to obtain as much information as possible even if errors occur.
+// Therefore, return values of GetRegStringValue are ignored.
+HRESULT GetOmahaInformation(bool is_machine_app,
+                            CString* omaha_version,
+                            CString* machine_id,
+                            CString* user_id) {
+  if (!omaha_version || !machine_id || !user_id) {
+    return E_INVALIDARG;
+  }
+
+  if (FAILED(GetRegStringValue(is_machine_app,
+                               kRelativeClientsGoopdateRegPath,
+                               kRegValueProductVersion,
+                               omaha_version))) {
+    *omaha_version = _T("0.0.0.0");
+  }
+
+  GetRegStringValue(true,  // Machine ID is always in HKLM.
+                    kRelativeGoopdateRegPath,
+                    kRegValueMachineId,
+                    machine_id);
+
+  GetRegStringValue(is_machine_app,
+                    kRelativeGoopdateRegPath,
+                    kRegValueUserId,
+                    user_id);
+
+  return S_OK;
+}
+
+// Builds the query portion of the recovery url.
+// This method obtains values necessary to build the query that are not provided
+// as parameters.
+// Attempts to build with as much information as possible even if errors occur.
+HRESULT BuildUrlQueryPortion(const CString& app_guid,
+                             const CString& app_version,
+                             const CString& app_language,
+                             bool is_machine_app,
+                             CString* query) {
+  if (!query) {
+    return E_INVALIDARG;
+  }
+
+  CString omaha_version;
+  CString machine_id;
+  CString user_id;
+  GetOmahaInformation(is_machine_app, &omaha_version, &machine_id, &user_id);
+
+  CString os_version;
+  CString os_service_pack;
+  GetOSInfo(&os_version, &os_service_pack);
+
+  // All parameters must be escaped individually before building the query.
+  CString app_guid_escaped;
+  CString app_version_escaped;
+  CString app_language_escaped;
+  CString omaha_version_escaped;
+  CString machine_id_escaped;
+  CString user_id_escaped;
+  CString os_version_escaped;
+  CString os_service_pack_escaped;
+  StringEscape(app_guid, true, &app_guid_escaped);
+  StringEscape(app_version, true, &app_version_escaped);
+  StringEscape(app_language, true, &app_language_escaped);
+  StringEscape(omaha_version, true, &omaha_version_escaped);
+  StringEscape(machine_id, true, &machine_id_escaped);
+  StringEscape(user_id, true, &user_id_escaped);
+  StringEscape(os_version, true, &os_version_escaped);
+  StringEscape(os_service_pack, true, &os_service_pack_escaped);
+
+  query->Format(kQueryStringFormat,
+                app_guid_escaped,
+                app_version_escaped,
+                app_language_escaped,
+                is_machine_app ? 1 : 0,
+                omaha_version_escaped,
+                machine_id_escaped,
+                user_id_escaped,
+                os_version_escaped,
+                os_service_pack_escaped);
+
+  return S_OK;
+}
+
+// Returns the full path to save the downloaded file to.
+// The path is based on a unique temporary filename to avoid a conflict
+// between multiple apps downloading to the same location.
+// The path to this file is also returned. The caller is responsible for
+// deleting the temporary file after using the download target path.
+// If it cannot create the unique directory, it attempts to use the user's
+// temporary directory and a constant filename.
+HRESULT GetDownloadTargetPath(CString* download_target_path,
+                              CString* temp_file_path) {
+  if (!download_target_path || !temp_file_path) {
+    return E_INVALIDARG;
+  }
+
+  CString user_temp_dir;
+  HRESULT hr = GetAndCreateTempDir(&user_temp_dir);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = CreateUniqueTempFile(user_temp_dir, temp_file_path);
+  if (SUCCEEDED(hr) && !temp_file_path->IsEmpty()) {
+    *download_target_path = *temp_file_path;
+    // Ignore the return value. A .tmp filename is better than none.
+    download_target_path->Replace(_T(".tmp"), _T(".exe"));
+  } else {
+    // Try a static filename in the temp directory as a fallback.
+    *download_target_path = user_temp_dir + _T("GoogleUpdateSetup.exe");
+    *temp_file_path = _T("");
+  }
+
+  return S_OK;
+}
+
+HRESULT DownloadRepairFile(const CString& download_target_path,
+                           const CString& app_guid,
+                           const CString& app_version,
+                           const CString& app_language,
+                           bool is_machine_app,
+                           DownloadCallback download_callback,
+                           void* context) {
+  CString query;
+  BuildUrlQueryPortion(app_guid,
+                       app_version,
+                       app_language,
+                       is_machine_app,
+                       &query);
+
+  CString url = omaha::kUrlCodeRedCheck + query;
+
+  return download_callback(url, download_target_path, context);
+}
+
+// Makes sure the path is enclosed with double quotation marks.
+void EnclosePath(CString* path) {
+  if (path) {
+    return;
+  }
+
+  if (!path->IsEmpty() && path->GetAt(0) != _T('"')) {
+    path->Insert(0, _T('"'));
+    path->AppendChar(_T('"'));
+  }
+}
+
+HRESULT RunRepairFile(const CString& file_path, bool is_machine_app) {
+  const TCHAR* repair_file_args = is_machine_app ? kMachineRepairArgs :
+                                                   kUserRepairArgs;
+
+  CString command_line(file_path);
+  EnclosePath(&command_line);
+  command_line.AppendChar(_T(' '));
+  command_line.Append(repair_file_args);
+
+  return StartProcess(NULL, command_line.GetBuffer());
+}
+
+}  // namespace
+
+// Verifies the file's integrity and that it is signed by Google.
+// We cannot prevent rollback attacks by using a version because the client
+// may not be able to determine the current version if the files and/or
+// registry entries have been deleted/corrupted.
+// Therefore, we check that the file was signed recently.
+HRESULT VerifyFileSignature(const CString& filename) {
+  // Use Authenticode/WinVerifyTrust to verify the file.
+  // Allow the revocation check to use the network.
+  HRESULT hr = VerifySignature(filename, true);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Verify that there is a Google certificate and that it has not expired.
+  if (!VerifySigneeIsGoogle(filename)) {
+    return CERT_E_CN_NO_MATCH;
+  }
+
+  // Check that the file was signed recently to limit the window for
+  // rollback attacks.
+  return VerifyFileSignedWithinDays(filename, kRollbackWindowDays);
+}
+
+// Verifies the file contains the special markup resource for repair files.
+HRESULT VerifyRepairFileMarkup(const CString& filename) {
+  const TCHAR* kMarkupResourceName = MAKEINTRESOURCE(1);
+  const TCHAR* kMarkupResourceType = _T("GOOGLEUPDATEREPAIR");
+  const DWORD kMarkupResourceExpectedValue = 1;
+
+  scoped_library module(::LoadLibraryEx(filename, 0, LOAD_LIBRARY_AS_DATAFILE));
+  if (!module) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  HRSRC resource(::FindResource(get(module),
+                                kMarkupResourceName,
+                                kMarkupResourceType));
+  if (!resource) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  if (sizeof(kMarkupResourceExpectedValue) !=
+      ::SizeofResource(get(module), resource)) {
+    return E_UNEXPECTED;
+  }
+
+  HGLOBAL loaded_resource(::LoadResource(get(module), resource));
+  if (!loaded_resource) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  const DWORD* value = static_cast<DWORD*>(::LockResource(loaded_resource));
+  if (!value) {
+    return E_HANDLE;
+  }
+
+  if (kMarkupResourceExpectedValue != *value) {
+    return E_UNEXPECTED;
+  }
+
+  return S_OK;
+}
+
+// Verifies the filename is not UNC name, the file exists, has a valid signature
+// chain, is signed by Google, and contains the special markup resource for
+// repair files.
+HRESULT VerifyIsValidRepairFile(const CString& filename) {
+  // Make sure file exists.
+  if (!::PathFileExists(filename)) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  HRESULT hr = VerifyFileSignature(filename);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return VerifyRepairFileMarkup(filename);
+}
+
+}  // namespace omaha
+
+// If a repair file is run, the file will not be deleted until reboot. Delete
+// after reboot will only succeed when executed by an admin or LocalSystem.
+// Returns HRESULT_FROM_WIN32(ERROR_ACCESS_DISABLED_BY_POLICY) if automatic
+// update checks are disabled.
+HRESULT FixGoogleUpdate(const TCHAR* app_guid,
+                        const TCHAR* app_version,
+                        const TCHAR* app_language,
+                        bool is_machine_app,
+                        DownloadCallback download_callback,
+                        void* context) {
+  if (!app_guid || !app_version || !app_language || !download_callback) {
+    return E_INVALIDARG;
+  }
+
+  DWORD update_check_period_override_minutes(UINT_MAX);
+  HRESULT hr = omaha::GetRegDwordValue(
+                   true,
+                   GOOPDATE_POLICIES_RELATIVE,
+                   omaha::kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                   &update_check_period_override_minutes);
+  if (SUCCEEDED(hr) && (0 == update_check_period_override_minutes)) {
+    return HRESULT_FROM_WIN32(ERROR_ACCESS_DISABLED_BY_POLICY);
+  }
+
+  CString download_target_path;
+  CString temp_file_path;
+  hr = omaha::GetDownloadTargetPath(&download_target_path, &temp_file_path);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (download_target_path.IsEmpty()) {
+    hr = E_FAIL;
+  }
+
+  // After calling DownloadRepairFile, don't return until the repair file and
+  // temp file have been deleted.
+  hr = omaha::DownloadRepairFile(download_target_path,
+                                 app_guid,
+                                 app_version,
+                                 app_language,
+                                 is_machine_app,
+                                 download_callback,
+                                 context);
+
+  if (SUCCEEDED(hr)) {
+    hr = omaha::VerifyIsValidRepairFile(download_target_path);
+  }
+
+  if (FAILED(hr)) {
+    ::DeleteFile(download_target_path);
+    ::DeleteFile(temp_file_path);
+    return hr;
+  }
+
+  hr = omaha::RunRepairFile(download_target_path, is_machine_app);
+  ::MoveFileEx(download_target_path, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
+  ::DeleteFile(temp_file_path);
+
+  return hr;
+}
diff --git a/common/google_update_recovery.h b/common/google_update_recovery.h
index 0a5372f..a096c4e 100644
--- a/common/google_update_recovery.h
+++ b/common/google_update_recovery.h
@@ -1,48 +1,48 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Defines the interface to the Google Update recovery mechanism to be included

-// in Google apps.

-

-#ifndef OMAHA_COMMON_GOOGLE_UPDATE_RECOVERY_H__

-#define OMAHA_COMMON_GOOGLE_UPDATE_RECOVERY_H__

-

-#include <tchar.h>

-#include <windows.h>

-

-#ifndef UNICODE

-#error The distributed library only supports UNICODE.

-#endif

-

-extern "C" {

-typedef HRESULT (*DownloadCallback)(const TCHAR* url,

-                                    const TCHAR* file_path,

-                                    void* context);

-

-// Determines whether there is a Code Red event for the current installation

-// and repairs it if necessary.

-// app_language should follow the external Internet standard

-// Best Common Practice (BCP) 47: http://www.rfc-editor.org/rfc/bcp/bcp47.txt

-// context can be NULL if download_callback does not use it.

-HRESULT FixGoogleUpdate(const TCHAR* app_guid,

-                        const TCHAR* app_version,

-                        const TCHAR* app_language,

-                        bool is_machine_app,

-                        DownloadCallback download_callback,

-                        void* context);

-}  // extern "C"

-

-#endif  // OMAHA_COMMON_GOOGLE_UPDATE_RECOVERY_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Defines the interface to the Google Update recovery mechanism to be included
+// in Google apps.
+
+#ifndef OMAHA_COMMON_GOOGLE_UPDATE_RECOVERY_H__
+#define OMAHA_COMMON_GOOGLE_UPDATE_RECOVERY_H__
+
+#include <tchar.h>
+#include <windows.h>
+
+#ifndef UNICODE
+#error The distributed library only supports UNICODE.
+#endif
+
+extern "C" {
+typedef HRESULT (*DownloadCallback)(const TCHAR* url,
+                                    const TCHAR* file_path,
+                                    void* context);
+
+// Determines whether there is a Code Red event for the current installation
+// and repairs it if necessary.
+// app_language should follow the external Internet standard
+// Best Common Practice (BCP) 47: http://www.rfc-editor.org/rfc/bcp/bcp47.txt
+// context can be NULL if download_callback does not use it.
+HRESULT FixGoogleUpdate(const TCHAR* app_guid,
+                        const TCHAR* app_version,
+                        const TCHAR* app_language,
+                        bool is_machine_app,
+                        DownloadCallback download_callback,
+                        void* context);
+}  // extern "C"
+
+#endif  // OMAHA_COMMON_GOOGLE_UPDATE_RECOVERY_H__
diff --git a/common/google_update_recovery_unittest.cc b/common/google_update_recovery_unittest.cc
index 4b0b6e0..5db397a 100644
--- a/common/google_update_recovery_unittest.cc
+++ b/common/google_update_recovery_unittest.cc
@@ -1,939 +1,939 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Unit tests for the Google Update recovery mechanism.

-// All apps that are using the mechanism must also run this test.

-//

-// Unlike the mechanism code, this code relies on code from common because it

-// makes writing the tests much simpler and size is not a concern.

-

-#include <windows.h>

-#include <atlstr.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/google_update_recovery.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/signaturevalidator.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/enterprise/const_group_policy.h"

-#include "omaha/net/browser_request.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/simple_request.h"

-#include "omaha/third_party/gtest/include/gtest/gtest.h"

-

-namespace omaha {

-

-namespace {

-

-const TCHAR kDummyAppGuid[] = _T("{8E472B0D-3E8B-43b1-B89A-E8506AAF1F16}");

-const TCHAR kDummyAppVersion[] = _T("3.4.5.6");

-const TCHAR kDummyAppLang[] = _T("en-us");

-const TCHAR kDummyMachineId[] = _T("{12A7B304-B4ED-4b5c-8122-31E7ECB8BE3C}");

-const TCHAR kDummyUserId[] = _T("{29388E49-2995-437c-BF47-587C7E9247E5}");

-

-const TCHAR kTempDirectory[] = _T("C:\\WINDOWS\\Temp");

-

-const TCHAR kFullMachineOmahaMainKeyPath[] =

-    _T("HKLM\\Software\\Google\\Update\\");

-const TCHAR kFullUserOmahaMainKeyPath[] =

-    _T("HKCU\\Software\\Google\\Update\\");

-const TCHAR kFullMachineOmahaClientKeyPath[] =

-    _T("HKLM\\Software\\Google\\Update\\Clients\\")

-    _T("{430FD4D0-B729-4f61-AA34-91526481799D}");

-const TCHAR kFullUserOmahaClientKeyPath[] =

-    _T("HKCU\\Software\\Google\\Update\\Clients\\")

-    _T("{430FD4D0-B729-4f61-AA34-91526481799D}");

-

-const HRESULT kDummyNoFileError = 0x80041234;

-

-const TCHAR kArgumentSavingExecutableRelativePath[] =

-    _T("unittest_support\\SaveArguments.exe");

-const TCHAR kSavedArgumentsFileName[] = _T("saved_arguments.txt");

-const TCHAR* const kInvalidFileAddress = _T("http://www.google.com/robots.txt");

-

-#define MACHINE_KEY_NAME _T("HKLM")

-#define MACHINE_KEY MACHINE_KEY_NAME _T("\\")

-#define USER_KEY_NAME _T("HKCU")

-#define USER_KEY USER_KEY_NAME _T("\\")

-

-// These methods were copied from omaha/testing/omaha_unittest.cpp.

-const TCHAR kRegistryHiveOverrideRoot[] =

-    _T("HKCU\\Software\\Google\\Update\\UnitTest\\");

-

-const TCHAR kExpectedUrlForDummyAppAndNoOmahaValues[] = _T("http://cr-tools.clients.google.com/service/check2?appid=%7B8E472B0D-3E8B-43b1-B89A-E8506AAF1F16%7D&appversion=3.4.5.6&applang=en-us&machine=1&version=0.0.0.0&machineid=&userid=&osversion=");  // NOLINT

-const int kExpectedUrlForDummyAppAndNoOmahaValuesLength =

-    arraysize(kExpectedUrlForDummyAppAndNoOmahaValues) - 1;

-

-// Overrides the HKLM and HKCU registry hives so that accesses go to the

-// specified registry key instead.

-// This method is most often used in SetUp().

-void OverrideRegistryHives(const CString& hive_override_key_name) {

-  // Override the destinations of HKLM and HKCU to use a special location

-  // for the unit tests so that we don't disturb the actual Omaha state.

-  RegKey machine_key;

-  RegKey user_key;

-  ASSERT_HRESULT_SUCCEEDED(

-      machine_key.Create(hive_override_key_name + MACHINE_KEY));

-  ASSERT_HRESULT_SUCCEEDED(user_key.Create(hive_override_key_name + USER_KEY));

-  ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_LOCAL_MACHINE,

-                                                  machine_key.Key()));

-  ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_CURRENT_USER,

-                                                  user_key.Key()));

-}

-

-// Restores HKLM and HKCU registry accesses to the real hives.

-// This method is most often used in TearDown().

-void RestoreRegistryHives() {

-  ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_LOCAL_MACHINE, NULL));

-  ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_CURRENT_USER, NULL));

-}

-

-CString GetTmp() {

-  TCHAR temp_dir[MAX_PATH] = {0};

-  EXPECT_NE(0, ::GetEnvironmentVariable(_T("TMP"), temp_dir, MAX_PATH));

-  return temp_dir;

-}

-

-}  // namespace

-

-HRESULT VerifyFileSignature(const CString& filename);

-HRESULT VerifyRepairFileMarkup(const CString& filename);

-

-class GoogleUpdateRecoveryTest : public testing::Test {

- public:

-  static void set_saved_url(const CString& saved_url) {

-    saved_url_ = saved_url;

-  }

-

-  static void set_saved_file_path(const CString& saved_file_path) {

-    saved_file_path_ = saved_file_path;

-  }

-

-  static void set_saved_context(void* context) {

-    saved_context_ = context;

-  }

-

- protected:

-  GoogleUpdateRecoveryTest() {

-    saved_url_.Empty();

-    saved_file_path_.Empty();

-    saved_context_ = NULL;

-  }

-

-  virtual void SetUp() {

-  }

-

-  virtual void TearDown() {

-  }

-

-  void CheckSavedUrlOSFragment() {

-    const TCHAR kExpectedOSXpSp2[] = _T("5.1&servicepack=Service%20Pack%202");

-    const TCHAR kExpectedOSXpSp3[] = _T("5.1&servicepack=Service%20Pack%203");

-    const TCHAR kExpectedOS2003Sp1[] = _T("5.2&servicepack=Service%20Pack%201");

-    const TCHAR kExpectedOS2003Sp2[] = _T("5.2&servicepack=Service%20Pack%202");

-    const TCHAR kExpectedOSVistaRtm[] = _T("6.0&servicepack=");

-    const TCHAR kExpectedOSVistaSp1[] =

-        _T("6.0&servicepack=Service%20Pack%201");

-

-    EXPECT_TRUE((kExpectedOSXpSp2 ==

-                 saved_url_.Right(arraysize(kExpectedOSXpSp2) - 1)) ||

-                (kExpectedOSXpSp3 ==

-                 saved_url_.Right(arraysize(kExpectedOSXpSp3) - 1)) ||

-                (kExpectedOS2003Sp1 ==

-                 saved_url_.Right(arraysize(kExpectedOS2003Sp1) - 1)) ||

-                (kExpectedOS2003Sp2 ==

-                 saved_url_.Right(arraysize(kExpectedOS2003Sp2) - 1)) ||

-                (kExpectedOSVistaRtm ==

-                 saved_url_.Right(arraysize(kExpectedOSVistaRtm) - 1)) ||

-                (kExpectedOSVistaSp1 ==

-                 saved_url_.Right(arraysize(kExpectedOSVistaSp1) - 1)));

-  }

-

-  void VerifySavedArgumentsFile(const CString& expected_string) {

-    CString saved_arguments_path = ConcatenatePath(

-                                       GetDirectoryFromPath(saved_file_path_),

-                                       kSavedArgumentsFileName);

-    bool is_found = false;

-    for (int tries = 0; tries < 100 && !is_found; ++tries) {

-      ::Sleep(50);

-      is_found = File::Exists(saved_arguments_path);

-    }

-    ASSERT_TRUE(is_found);

-

-    scoped_hfile file(::CreateFile(saved_arguments_path,

-                                   GENERIC_READ,

-                                   0,                     // do not share

-                                   NULL,                  // default security

-                                   OPEN_EXISTING,         // existing file only

-                                   FILE_ATTRIBUTE_NORMAL,

-                                   NULL));                // no template

-    ASSERT_NE(INVALID_HANDLE_VALUE, get(file));

-

-    const int kBufferLen = 50;

-    TCHAR buffer[kBufferLen + 1] = {0};

-    DWORD bytes_read = 0;

-

-    EXPECT_TRUE(::ReadFile(get(file),

-                           buffer,

-                           kBufferLen * sizeof(TCHAR),

-                           &bytes_read,

-                           NULL));

-    EXPECT_EQ(0, bytes_read % sizeof(TCHAR));

-    buffer[bytes_read / sizeof(TCHAR)] = _T('\0');

-

-    EXPECT_STREQ(expected_string, buffer);

-  }

-

-  void VerifyExpectedSavedFilePath(const CString& expected_temp_directory) {

-    const int kMaxUniqueChars = 4;

-    const CString expected_path_part_a = expected_temp_directory + _T("\\GUR");

-    const CString expected_path_part_b = _T(".exe");

-    EXPECT_STREQ(expected_path_part_a,

-                 saved_file_path_.Left(expected_path_part_a.GetLength()));

-    EXPECT_STREQ(expected_path_part_b,

-                 saved_file_path_.Right(expected_path_part_b.GetLength()));

-    const int constant_chars = expected_path_part_a.GetLength() +

-                               expected_path_part_b.GetLength();

-    EXPECT_GT(saved_file_path_.GetLength(), constant_chars);

-    EXPECT_LE(saved_file_path_.GetLength(), constant_chars + kMaxUniqueChars);

-  }

-

-  static CString saved_url_;

-  static CString saved_file_path_;

-  static void* saved_context_;

-

- protected:

-  // Copies SaveArguments.exe to the specified location.

-  static HRESULT DownloadArgumentSavingFile(const TCHAR* url,

-                                            const TCHAR* file_path,

-                                            void* context) {

-    ASSERT1(url);

-    ASSERT1(file_path);

-

-    GoogleUpdateRecoveryTest::set_saved_url(url);

-    GoogleUpdateRecoveryTest::set_saved_file_path(file_path);

-    GoogleUpdateRecoveryTest::set_saved_context(context);

-

-    CString executable_full_path(app_util::GetCurrentModuleDirectory());

-    VERIFY1(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),

-                         kArgumentSavingExecutableRelativePath));

-

-    if (!::CopyFile(executable_full_path, file_path, false)) {

-      HRESULT hr = HRESULTFromLastError();

-      return hr;

-    }

-

-    return S_OK;

-  }

-

-  // Returns kDummyNoFileError, simulating no file to download.

-  static HRESULT DownloadFileNoFile(const TCHAR* url,

-                                    const TCHAR* file_path,

-                                    void* context) {

-    ASSERT1(url);

-    ASSERT1(file_path);

-

-    GoogleUpdateRecoveryTest::set_saved_url(url);

-    GoogleUpdateRecoveryTest::set_saved_file_path(file_path);

-    GoogleUpdateRecoveryTest::set_saved_context(context);

-

-    return kDummyNoFileError;

-  }

-

-  // Overrides the address to cause a file to be downloaded via HTTP.

-  // Uses a real HTTP stack, so it is similar to a real implementation.

-  // The file is invalid, so signature verification should return

-  // TRUST_E_SUBJECT_FORM_UNKNOWN.

-  static HRESULT DownloadFileInvalidFile(const TCHAR* url,

-                                         const TCHAR* file_path,

-                                         void* context) {

-    ASSERT1(url);

-    CString test_url(url);

-

-    VERIFY1(1 == test_url.Replace(kUrlCodeRedCheck, kInvalidFileAddress));

-

-    return DownloadFileFromServer(test_url, file_path, context);

-  }

-

-  // Uses a real HTTP stack, so it is similar to a real implementation.

-  static HRESULT DownloadFileFromServer(const TCHAR* url,

-                                        const TCHAR* file_path,

-                                        void* context) {

-    UTIL_LOG(L2, (_T("[DownloadFileFromServer][%s][%s]"), url, file_path));

-

-    ASSERT1(url);

-    ASSERT1(file_path);

-

-    GoogleUpdateRecoveryTest::set_saved_url(url);

-    GoogleUpdateRecoveryTest::set_saved_file_path(file_path);

-    GoogleUpdateRecoveryTest::set_saved_context(context);

-

-    NetworkConfig& network_config = NetworkConfig::Instance();

-    ON_SCOPE_EXIT_OBJ(network_config, &NetworkConfig::Clear);

-

-    network_config.Clear();

-    network_config.Add(new GoogleProxyDetector(MACHINE_REG_UPDATE_DEV));

-    network_config.Add(new FirefoxProxyDetector());

-    network_config.Add(new IEProxyDetector());

-

-    NetworkRequest network_request(network_config.session());

-    network_request.AddHttpRequest(new SimpleRequest);

-    network_request.AddHttpRequest(new BrowserRequest);

-

-    HRESULT hr = network_request.DownloadFile(url, CString(file_path));

-    if (FAILED(hr)) {

-      UTIL_LOG(LE, (_T("[DownloadFile failed][%s][0x%08x]"), url, hr));

-      return hr;

-    }

-

-    int status_code = network_request.http_status_code();

-    UTIL_LOG(L2, (_T("[HTTP status][%u]"), status_code));

-

-    if (HTTP_STATUS_OK == status_code) {

-      return S_OK;

-    } else if (HTTP_STATUS_NO_CONTENT == status_code) {

-      return kDummyNoFileError;

-    } else {

-      // Apps would not have this assumption.

-      ASSERT(false, (_T("Status code %i received. Expected 200 or 204."),

-                     status_code));

-      return E_FAIL;

-    }

-  }

-};

-

-CString GoogleUpdateRecoveryTest::saved_url_;

-CString GoogleUpdateRecoveryTest::saved_file_path_;

-void* GoogleUpdateRecoveryTest::saved_context_;

-

-class GoogleUpdateRecoveryRegistryProtectedTest

-    : public GoogleUpdateRecoveryTest {

- protected:

-  GoogleUpdateRecoveryRegistryProtectedTest()

-      : hive_override_key_name_(kRegistryHiveOverrideRoot) {

-  }

-

-  CString hive_override_key_name_;

-

-  virtual void SetUp() {

-    GoogleUpdateRecoveryTest::SetUp();

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    OverrideRegistryHives(hive_override_key_name_);

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    ASSERT_HRESULT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-    GoogleUpdateRecoveryTest::TearDown();

-  }

-};

-

-//

-// FixGoogleUpdate Tests

-//

-

-TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_UseRealHttpClient) {

-  EXPECT_EQ(TRUST_E_SUBJECT_FORM_UNKNOWN,

-            FixGoogleUpdate(kDummyAppGuid,

-                            kDummyAppVersion,

-                            kDummyAppLang,

-                            true,

-                            DownloadFileInvalidFile,

-                            NULL));

-}

-

-TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_FileReturned_Machine) {

-  CString saved_arguments_path = ConcatenatePath(app_util::GetTempDir(),

-                                                 kSavedArgumentsFileName);

-

-  ::DeleteFile(saved_arguments_path);

-  ASSERT_FALSE(File::Exists(saved_arguments_path));

-

-  CString context_string(_T("some context"));

-  EXPECT_HRESULT_SUCCEEDED(FixGoogleUpdate(kDummyAppGuid,

-                                           kDummyAppVersion,

-                                           kDummyAppLang,

-                                           true,

-                                           DownloadArgumentSavingFile,

-                                           &context_string));

-

-  EXPECT_EQ(&context_string, saved_context_);

-  EXPECT_STREQ(_T("some context"), *static_cast<CString*>(saved_context_));

-

-  ::Sleep(200);

-  EXPECT_TRUE(File::Exists(saved_file_path_));

-  VerifySavedArgumentsFile(_T("/recover /machine"));

-

-  EXPECT_TRUE(::DeleteFile(saved_file_path_));

-  EXPECT_TRUE(::DeleteFile(saved_arguments_path));

-}

-

-TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_FileReturned_User) {

-  CString saved_arguments_path = ConcatenatePath(app_util::GetTempDir(),

-                                                 kSavedArgumentsFileName);

-

-  ::DeleteFile(saved_arguments_path);

-  ASSERT_FALSE(File::Exists(saved_arguments_path));

-

-  CString context_string(_T("more context"));

-  EXPECT_HRESULT_SUCCEEDED(FixGoogleUpdate(kDummyAppGuid,

-                                           kDummyAppVersion,

-                                           kDummyAppLang,

-                                           false,

-                                           DownloadArgumentSavingFile,

-                                           &context_string));

-

-  EXPECT_EQ(&context_string, saved_context_);

-  EXPECT_STREQ(_T("more context"), *static_cast<CString*>(saved_context_));

-

-  ::Sleep(200);

-  EXPECT_TRUE(File::Exists(saved_file_path_));

-  VerifySavedArgumentsFile(_T("/recover"));

-

-  EXPECT_TRUE(::DeleteFile(saved_file_path_));

-  EXPECT_TRUE(::DeleteFile(saved_arguments_path));

-}

-

-TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_NoFile_Machine) {

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-

-  EXPECT_EQ(static_cast<void*>(NULL), saved_context_);

-  EXPECT_FALSE(File::Exists(saved_file_path_));

-

-  TCHAR temp_dir[MAX_PATH] = {0};

-  EXPECT_TRUE(::GetEnvironmentVariable(_T("TMP"), temp_dir, MAX_PATH));

-  EXPECT_TRUE(File::Exists(temp_dir))

-      << _T("The temp directory was deleted or not created.");

-}

-

-TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_NoFile_User) {

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               false,

-                                               DownloadFileNoFile,

-                                               NULL));

-

-  EXPECT_EQ(static_cast<void*>(NULL), saved_context_);

-  EXPECT_FALSE(File::Exists(saved_file_path_));

-

-  TCHAR temp_dir[MAX_PATH] = {0};

-  EXPECT_TRUE(::GetEnvironmentVariable(_T("TMP"), temp_dir, MAX_PATH));

-  EXPECT_TRUE(File::Exists(temp_dir))

-      << _T("The temp directory was deleted or not created.");

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_AllValues_MachineApp) {

-  const TCHAR kExpectedUrl[] = _T("http://cr-tools.clients.google.com/service/check2?appid=%7B8E472B0D-3E8B-43b1-B89A-E8506AAF1F16%7D&appversion=3.4.5.6&applang=en-us&machine=1&version=5.6.78.1&machineid=%7B12A7B304-B4ED-4b5c-8122-31E7ECB8BE3C%7D&userid=%7B29388E49-2995-437c-BF47-587C7E9247E5%7D&osversion=");  // NOLINT

-

-  const CString prev_tmp = GetTmp();

-  ASSERT_TRUE(::SetEnvironmentVariable(_T("TMP"), kTempDirectory));

-

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullMachineOmahaClientKeyPath,

-                                            _T("pv"),

-                                            _T("5.6.78.1")));

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullMachineOmahaMainKeyPath,

-                                            _T("mi"),

-                                            kDummyMachineId));

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullMachineOmahaMainKeyPath,

-                                            _T("ui"),

-                                            kDummyUserId));

-

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-

-  EXPECT_STREQ(kExpectedUrl, saved_url_.Left(arraysize(kExpectedUrl) - 1));

-  CheckSavedUrlOSFragment();

-  VerifyExpectedSavedFilePath(kTempDirectory);

-

-  EXPECT_TRUE(::SetEnvironmentVariable(_T("TMP"), prev_tmp));

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_AllValues_UserApp) {

-  const TCHAR kExpectedUrl[] = _T("http://cr-tools.clients.google.com/service/check2?appid=%7B8E472B0D-3E8B-43b1-B89A-E8506AAF1F16%7D&appversion=3.4.5.6&applang=en-us&machine=0&version=5.6.78.1&machineid=%7B12A7B304-B4ED-4b5c-8122-31E7ECB8BE3C%7D&userid=%7B29388E49-2995-437c-BF47-587C7E9247E5%7D&osversion=");  // NOLINT

-

-  const CString prev_tmp = GetTmp();

-  ASSERT_TRUE(::SetEnvironmentVariable(_T("TMP"), kTempDirectory));

-

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullUserOmahaClientKeyPath,

-                                            _T("pv"),

-                                            _T("5.6.78.1")));

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullMachineOmahaMainKeyPath,

-                                            _T("mi"),

-                                            kDummyMachineId));

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullUserOmahaMainKeyPath,

-                                            _T("ui"),

-                                            kDummyUserId));

-

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               false,

-                                               DownloadFileNoFile,

-                                               NULL));

-

-  EXPECT_STREQ(kExpectedUrl, saved_url_.Left(arraysize(kExpectedUrl) - 1));

-  CheckSavedUrlOSFragment();

-  VerifyExpectedSavedFilePath(kTempDirectory);

-

-  EXPECT_TRUE(::SetEnvironmentVariable(_T("TMP"), prev_tmp));

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_NoOmahaRegKeys) {

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,

-               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));

-  CheckSavedUrlOSFragment();

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_EmptyAppInfo) {

-  const TCHAR kExpectedUrl[] = _T("http://cr-tools.clients.google.com/service/check2?appid=&appversion=&applang=&machine=1&version=0.0.0.0&machineid=&userid=&osversion=");  // NOLINT

-

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(_T(""),

-                                               _T(""),

-                                               _T(""),

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-  EXPECT_STREQ(kExpectedUrl, saved_url_.Left(arraysize(kExpectedUrl) - 1));

-  CheckSavedUrlOSFragment();

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_NullArgs) {

-  EXPECT_EQ(E_INVALIDARG, FixGoogleUpdate(NULL,

-                                          _T(""),

-                                          _T(""),

-                                          true,

-                                          DownloadFileNoFile,

-                                          NULL));

-  EXPECT_EQ(E_INVALIDARG, FixGoogleUpdate(_T(""),

-                                          NULL,

-                                          _T(""),

-                                          true,

-                                          DownloadFileNoFile,

-                                          NULL));

-  EXPECT_EQ(E_INVALIDARG, FixGoogleUpdate(_T(""),

-                                          _T(""),

-                                          NULL,

-                                          true,

-                                          DownloadFileNoFile,

-                                          NULL));

-  EXPECT_EQ(E_INVALIDARG, FixGoogleUpdate(_T(""),

-                                          _T(""),

-                                          _T(""),

-                                          true,

-                                          NULL,

-                                          NULL));

-}

-

-// Setting kRegValueAutoUpdateCheckPeriodOverrideMinutes to zero disables

-// Code Red checks just as it does regular update checks.

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsZeroDword) {

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,

-                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                       static_cast<DWORD>(0)));

-

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_ACCESS_DISABLED_BY_POLICY),

-            FixGoogleUpdate(kDummyAppGuid,

-                            kDummyAppVersion,

-                            kDummyAppLang,

-                            true,

-                            DownloadFileNoFile,

-                            NULL));

-  EXPECT_TRUE(saved_url_.IsEmpty());

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsZeroDwordInHkcu) {

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(USER_KEY GOOPDATE_POLICIES_RELATIVE,

-                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                       static_cast<DWORD>(0)));

-

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,

-               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));

-  CheckSavedUrlOSFragment();

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsNonZeroDword) {

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,

-                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                       static_cast<DWORD>(1400)));

-

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,

-               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));

-  CheckSavedUrlOSFragment();

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsZeroDword64) {

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,

-                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                       static_cast<DWORD64>(0)));

-

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,

-               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));

-  CheckSavedUrlOSFragment();

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsNonZeroDword64) {

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,

-                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                       static_cast<DWORD64>(1400)));

-

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,

-               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));

-  CheckSavedUrlOSFragment();

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsZeroAsString) {

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,

-                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                       _T("0")));

-

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,

-               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));

-  CheckSavedUrlOSFragment();

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsZeroAsBinary) {

-  const byte zero = 0;

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,

-                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                       &zero,

-                       sizeof(zero)));

-

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,

-               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));

-  CheckSavedUrlOSFragment();

-}

-

-TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,

-       FixGoogleUpdate_GroupPolicyKeyExistsButNoAutoUpdateCheckPeriodMinutes) {

-  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKey(kRegKeyGoopdateGroupPolicy));

-

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileNoFile,

-                                               NULL));

-  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,

-               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));

-  CheckSavedUrlOSFragment();

-}

-

-// Verifies that the file is saved even if the temp directory doesn't exist.

-TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_SaveToNonExistantDirectory) {

-  const TCHAR kNonExistantDirectory[] = _T("c:\\directory_does_not_exist");

-  DeleteDirectory(kNonExistantDirectory);

-  ASSERT_FALSE(File::Exists(kNonExistantDirectory));

-

-  const CString prev_tmp = GetTmp();

-  ASSERT_TRUE(::SetEnvironmentVariable(_T("TMP"), kNonExistantDirectory));

-

-  EXPECT_EQ(TRUST_E_SUBJECT_FORM_UNKNOWN,

-            FixGoogleUpdate(kDummyAppGuid,

-                            kDummyAppVersion,

-                            kDummyAppLang,

-                            true,

-                            DownloadFileInvalidFile,

-                            NULL));

-

-  VerifyExpectedSavedFilePath(kNonExistantDirectory);

-

-  EXPECT_TRUE(::SetEnvironmentVariable(_T("TMP"), prev_tmp));

-}

-

-TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_FileCollision) {

-  const CString prev_tmp = GetTmp();

-  ASSERT_TRUE(::SetEnvironmentVariable(_T("TMP"), kTempDirectory));

-

-  CString saved_arguments_path = ConcatenatePath(app_util::GetTempDir(),

-                                                 kSavedArgumentsFileName);

-

-  EXPECT_HRESULT_SUCCEEDED(FixGoogleUpdate(kDummyAppGuid,

-                                           kDummyAppVersion,

-                                           kDummyAppLang,

-                                           false,

-                                           DownloadArgumentSavingFile,

-                                           NULL));

-

-  EXPECT_TRUE(File::Exists(saved_file_path_));

-  VerifyExpectedSavedFilePath(kTempDirectory);

-

-  CString first_saved_file_path = saved_file_path_;

-

-  // Ensure that the first downloaded file is in use.

-  FileLock lock;

-  EXPECT_HRESULT_SUCCEEDED(lock.Lock(first_saved_file_path));

-

-  EXPECT_HRESULT_SUCCEEDED(FixGoogleUpdate(kDummyAppGuid,

-                                           kDummyAppVersion,

-                                           kDummyAppLang,

-                                           false,

-                                           DownloadArgumentSavingFile,

-                                           NULL));

-  EXPECT_TRUE(File::Exists(saved_file_path_));

-  VerifyExpectedSavedFilePath(kTempDirectory);

-

-  EXPECT_STRNE(first_saved_file_path, saved_file_path_);

-

-  EXPECT_HRESULT_SUCCEEDED(lock.Unlock());

-

-  bool is_deleted = false;

-  for (int tries = 0; tries < 100 && !is_deleted; ++tries) {

-    ::Sleep(50);

-    is_deleted = !!::DeleteFile(saved_file_path_);

-  }

-  EXPECT_TRUE(is_deleted);

-

-  EXPECT_TRUE(::DeleteFile(first_saved_file_path));

-  EXPECT_TRUE(::DeleteFile(saved_arguments_path));

-

-  EXPECT_TRUE(::SetEnvironmentVariable(_T("TMP"), prev_tmp));

-}

-

-//

-// VerifyFileSignature Tests

-//

-TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_SignedValid) {

-  CString executable_full_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),

-                           kArgumentSavingExecutableRelativePath));

-  ASSERT_TRUE(File::Exists(executable_full_path));

-  EXPECT_HRESULT_SUCCEEDED(VerifyFileSignature(executable_full_path));

-}

-

-TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_NotSigned) {

-  const TCHAR kUnsignedExecutable[] = _T("GoogleUpdate_unsigned.exe");

-

-  CString executable_full_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),

-                           kUnsignedExecutable));

-  ASSERT_TRUE(File::Exists(executable_full_path));

-  EXPECT_EQ(TRUST_E_NOSIGNATURE, VerifyFileSignature(executable_full_path));

-}

-

-// The certificate is still valid, but the executable was signed more than N

-// days ago.

-TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_SignedOldWithValidCert) {

-  const TCHAR kUnsignedExecutable[] =

-      _T("unittest_support\\GoogleUpdate_old_signature.exe");

-

-  CString executable_full_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),

-                           kUnsignedExecutable));

-  ASSERT_TRUE(File::Exists(executable_full_path));

-  EXPECT_EQ(TRUST_E_TIME_STAMP, VerifyFileSignature(executable_full_path));

-}

-

-// The certificate was valid when it was used to sign the executable, but it has

-// since expired.

-// The error returned is inappropriate for this case because of the way

-// expiration checking is implemented.

-TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_SignedWithNowExpiredCert) {

-  const TCHAR kUnsignedExecutable[] =

-      _T("unittest_support\\GoogleUpdate_now_expired_cert.exe");

-

-  CString executable_full_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),

-                           kUnsignedExecutable));

-  ASSERT_TRUE(File::Exists(executable_full_path));

-  EXPECT_EQ(CERT_E_CN_NO_MATCH, VerifyFileSignature(executable_full_path));

-}

-

-TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_UntrustedChain) {

-  const TCHAR kUntrustedChainExecutable[] =

-      _T("unittest_support\\SaveArguments_OmahaTestSigned.exe");

-

-  CString executable_full_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),

-                           kUntrustedChainExecutable));

-  ASSERT_TRUE(File::Exists(executable_full_path));

-  EXPECT_EQ(CERT_E_UNTRUSTEDROOT, VerifyFileSignature(executable_full_path));

-}

-

-TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_HashFails) {

-  const TCHAR kCorruptedExecutable[] =

-      _T("unittest_support\\GoogleUpdate_corrupted.exe");

-

-  CString executable_full_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),

-                           kCorruptedExecutable));

-  ASSERT_TRUE(File::Exists(executable_full_path));

-  EXPECT_EQ(TRUST_E_BAD_DIGEST, VerifyFileSignature(executable_full_path));

-}

-

-// The file for Windows Vista and later may not exist on all systems.

-TEST_F(GoogleUpdateRecoveryTest,

-       VerifyFileSignature_NonGoogleSignature) {

-  CString file_path = SystemInfo::IsRunningOnVistaOrLater() ?

-      _T("%SYSTEM%\\rcagent.exe") : _T("%SYSTEM%\\wuauclt.exe");

-  if (!File::Exists(file_path) && SystemInfo::IsRunningOnVistaOrLater()) {

-    std::wcout << _T("\tTest did not run because '") << file_path

-               << _T("' was not found.") << std::endl;

-    return;

-  }

-  ASSERT_HRESULT_SUCCEEDED(ExpandStringWithSpecialFolders(&file_path));

-  ASSERT_TRUE(File::Exists(file_path));

-  ASSERT_TRUE(SignatureIsValid(file_path, false));

-  EXPECT_EQ(CERT_E_CN_NO_MATCH, VerifyFileSignature(file_path));

-}

-

-TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_BadFilenames) {

-  EXPECT_EQ(CRYPT_E_FILE_ERROR, VerifyFileSignature(_T("NoSuchFile.exe")));

-

-  EXPECT_EQ(CRYPT_E_FILE_ERROR, VerifyFileSignature(NULL));

-

-  EXPECT_EQ(CRYPT_E_FILE_ERROR, VerifyFileSignature(_T("")));

-}

-

-//

-// VerifyRepairFileMarkup Tests

-//

-TEST_F(GoogleUpdateRecoveryTest, VerifyRepairFileMarkup_ValidMarkup) {

-  const TCHAR kExecutableWithMarkup[] =

-      _T("unittest_support\\SaveArguments.exe");

-  EXPECT_HRESULT_SUCCEEDED(VerifyRepairFileMarkup(kExecutableWithMarkup));

-}

-

-TEST_F(GoogleUpdateRecoveryTest, VerifyRepairFileMarkup_InvalidMarkups) {

-  const TCHAR kNoResourcesExecutable[] = _T("RecoveryTest.exe");

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND),

-            VerifyRepairFileMarkup(kNoResourcesExecutable));

-

-  const TCHAR kResourcesButNoMarkupExecutable[] = _T("GoogleUpdate.exe");

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND),

-            VerifyRepairFileMarkup(kResourcesButNoMarkupExecutable));

-

-  const TCHAR kWrongMarkupResourceNameExecutable[] =

-      _T("unittest_support\\SaveArguments_unsigned_wrong_resource_name.exe");

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_RESOURCE_NAME_NOT_FOUND),

-            VerifyRepairFileMarkup(kWrongMarkupResourceNameExecutable));

-

-  const TCHAR kWrongMarkupSizeExecutable[] =

-      _T("unittest_support\\SaveArguments_unsigned_wrong_markup_size.exe");

-  EXPECT_EQ(E_UNEXPECTED, VerifyRepairFileMarkup(kWrongMarkupSizeExecutable));

-

-  const TCHAR kWrongMarkupValueExecutable[] =

-      _T("unittest_support\\SaveArguments_unsigned_wrong_markup_value.exe");

-  EXPECT_EQ(E_UNEXPECTED, VerifyRepairFileMarkup(kWrongMarkupValueExecutable));

-}

-

-TEST_F(GoogleUpdateRecoveryTest, VerifyRepairFileMarkup_BadFilenames) {

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            VerifyRepairFileMarkup(_T("NoSuchFile.exe")));

-

-  EXPECT_EQ(E_INVALIDARG, VerifyRepairFileMarkup(NULL));

-

-  EXPECT_EQ(E_INVALIDARG, VerifyRepairFileMarkup(_T("")));

-}

-

-//

-// VerifyRepairFileMarkup Tests

-//

-// TODO(omaha): Unit test VerifyIsValidRepairFile.

-

-//

-// Production Server Response Tests Tests

-//

-TEST_F(GoogleUpdateRecoveryTest, ProductionServerResponseTest) {

-  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,

-                                               kDummyAppVersion,

-                                               kDummyAppLang,

-                                               true,

-                                               DownloadFileFromServer,

-                                               NULL)) <<

-      _T("The production server did not return 204. This may indicate network ")

-      _T("issues or that the Code Red server is configured incorrectly");

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Unit tests for the Google Update recovery mechanism.
+// All apps that are using the mechanism must also run this test.
+//
+// Unlike the mechanism code, this code relies on code from common because it
+// makes writing the tests much simpler and size is not a concern.
+
+#include <windows.h>
+#include <atlstr.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/google_update_recovery.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/signaturevalidator.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/enterprise/const_group_policy.h"
+#include "omaha/net/browser_request.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/simple_request.h"
+#include "omaha/third_party/gtest/include/gtest/gtest.h"
+
+namespace omaha {
+
+namespace {
+
+const TCHAR kDummyAppGuid[] = _T("{8E472B0D-3E8B-43b1-B89A-E8506AAF1F16}");
+const TCHAR kDummyAppVersion[] = _T("3.4.5.6");
+const TCHAR kDummyAppLang[] = _T("en-us");
+const TCHAR kDummyMachineId[] = _T("{12A7B304-B4ED-4b5c-8122-31E7ECB8BE3C}");
+const TCHAR kDummyUserId[] = _T("{29388E49-2995-437c-BF47-587C7E9247E5}");
+
+const TCHAR kTempDirectory[] = _T("C:\\WINDOWS\\Temp");
+
+const TCHAR kFullMachineOmahaMainKeyPath[] =
+    _T("HKLM\\Software\\Google\\Update\\");
+const TCHAR kFullUserOmahaMainKeyPath[] =
+    _T("HKCU\\Software\\Google\\Update\\");
+const TCHAR kFullMachineOmahaClientKeyPath[] =
+    _T("HKLM\\Software\\Google\\Update\\Clients\\")
+    _T("{430FD4D0-B729-4f61-AA34-91526481799D}");
+const TCHAR kFullUserOmahaClientKeyPath[] =
+    _T("HKCU\\Software\\Google\\Update\\Clients\\")
+    _T("{430FD4D0-B729-4f61-AA34-91526481799D}");
+
+const HRESULT kDummyNoFileError = 0x80041234;
+
+const TCHAR kArgumentSavingExecutableRelativePath[] =
+    _T("unittest_support\\SaveArguments.exe");
+const TCHAR kSavedArgumentsFileName[] = _T("saved_arguments.txt");
+const TCHAR* const kInvalidFileAddress = _T("http://www.google.com/robots.txt");
+
+#define MACHINE_KEY_NAME _T("HKLM")
+#define MACHINE_KEY MACHINE_KEY_NAME _T("\\")
+#define USER_KEY_NAME _T("HKCU")
+#define USER_KEY USER_KEY_NAME _T("\\")
+
+// These methods were copied from omaha/testing/omaha_unittest.cpp.
+const TCHAR kRegistryHiveOverrideRoot[] =
+    _T("HKCU\\Software\\Google\\Update\\UnitTest\\");
+
+const TCHAR kExpectedUrlForDummyAppAndNoOmahaValues[] = _T("http://cr-tools.clients.google.com/service/check2?appid=%7B8E472B0D-3E8B-43b1-B89A-E8506AAF1F16%7D&appversion=3.4.5.6&applang=en-us&machine=1&version=0.0.0.0&machineid=&userid=&osversion=");  // NOLINT
+const int kExpectedUrlForDummyAppAndNoOmahaValuesLength =
+    arraysize(kExpectedUrlForDummyAppAndNoOmahaValues) - 1;
+
+// Overrides the HKLM and HKCU registry hives so that accesses go to the
+// specified registry key instead.
+// This method is most often used in SetUp().
+void OverrideRegistryHives(const CString& hive_override_key_name) {
+  // Override the destinations of HKLM and HKCU to use a special location
+  // for the unit tests so that we don't disturb the actual Omaha state.
+  RegKey machine_key;
+  RegKey user_key;
+  ASSERT_HRESULT_SUCCEEDED(
+      machine_key.Create(hive_override_key_name + MACHINE_KEY));
+  ASSERT_HRESULT_SUCCEEDED(user_key.Create(hive_override_key_name + USER_KEY));
+  ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_LOCAL_MACHINE,
+                                                  machine_key.Key()));
+  ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_CURRENT_USER,
+                                                  user_key.Key()));
+}
+
+// Restores HKLM and HKCU registry accesses to the real hives.
+// This method is most often used in TearDown().
+void RestoreRegistryHives() {
+  ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_LOCAL_MACHINE, NULL));
+  ASSERT_HRESULT_SUCCEEDED(::RegOverridePredefKey(HKEY_CURRENT_USER, NULL));
+}
+
+CString GetTmp() {
+  TCHAR temp_dir[MAX_PATH] = {0};
+  EXPECT_NE(0, ::GetEnvironmentVariable(_T("TMP"), temp_dir, MAX_PATH));
+  return temp_dir;
+}
+
+}  // namespace
+
+HRESULT VerifyFileSignature(const CString& filename);
+HRESULT VerifyRepairFileMarkup(const CString& filename);
+
+class GoogleUpdateRecoveryTest : public testing::Test {
+ public:
+  static void set_saved_url(const CString& saved_url) {
+    saved_url_ = saved_url;
+  }
+
+  static void set_saved_file_path(const CString& saved_file_path) {
+    saved_file_path_ = saved_file_path;
+  }
+
+  static void set_saved_context(void* context) {
+    saved_context_ = context;
+  }
+
+ protected:
+  GoogleUpdateRecoveryTest() {
+    saved_url_.Empty();
+    saved_file_path_.Empty();
+    saved_context_ = NULL;
+  }
+
+  virtual void SetUp() {
+  }
+
+  virtual void TearDown() {
+  }
+
+  void CheckSavedUrlOSFragment() {
+    const TCHAR kExpectedOSXpSp2[] = _T("5.1&servicepack=Service%20Pack%202");
+    const TCHAR kExpectedOSXpSp3[] = _T("5.1&servicepack=Service%20Pack%203");
+    const TCHAR kExpectedOS2003Sp1[] = _T("5.2&servicepack=Service%20Pack%201");
+    const TCHAR kExpectedOS2003Sp2[] = _T("5.2&servicepack=Service%20Pack%202");
+    const TCHAR kExpectedOSVistaRtm[] = _T("6.0&servicepack=");
+    const TCHAR kExpectedOSVistaSp1[] =
+        _T("6.0&servicepack=Service%20Pack%201");
+
+    EXPECT_TRUE((kExpectedOSXpSp2 ==
+                 saved_url_.Right(arraysize(kExpectedOSXpSp2) - 1)) ||
+                (kExpectedOSXpSp3 ==
+                 saved_url_.Right(arraysize(kExpectedOSXpSp3) - 1)) ||
+                (kExpectedOS2003Sp1 ==
+                 saved_url_.Right(arraysize(kExpectedOS2003Sp1) - 1)) ||
+                (kExpectedOS2003Sp2 ==
+                 saved_url_.Right(arraysize(kExpectedOS2003Sp2) - 1)) ||
+                (kExpectedOSVistaRtm ==
+                 saved_url_.Right(arraysize(kExpectedOSVistaRtm) - 1)) ||
+                (kExpectedOSVistaSp1 ==
+                 saved_url_.Right(arraysize(kExpectedOSVistaSp1) - 1)));
+  }
+
+  void VerifySavedArgumentsFile(const CString& expected_string) {
+    CString saved_arguments_path = ConcatenatePath(
+                                       GetDirectoryFromPath(saved_file_path_),
+                                       kSavedArgumentsFileName);
+    bool is_found = false;
+    for (int tries = 0; tries < 100 && !is_found; ++tries) {
+      ::Sleep(50);
+      is_found = File::Exists(saved_arguments_path);
+    }
+    ASSERT_TRUE(is_found);
+
+    scoped_hfile file(::CreateFile(saved_arguments_path,
+                                   GENERIC_READ,
+                                   0,                     // do not share
+                                   NULL,                  // default security
+                                   OPEN_EXISTING,         // existing file only
+                                   FILE_ATTRIBUTE_NORMAL,
+                                   NULL));                // no template
+    ASSERT_NE(INVALID_HANDLE_VALUE, get(file));
+
+    const int kBufferLen = 50;
+    TCHAR buffer[kBufferLen + 1] = {0};
+    DWORD bytes_read = 0;
+
+    EXPECT_TRUE(::ReadFile(get(file),
+                           buffer,
+                           kBufferLen * sizeof(TCHAR),
+                           &bytes_read,
+                           NULL));
+    EXPECT_EQ(0, bytes_read % sizeof(TCHAR));
+    buffer[bytes_read / sizeof(TCHAR)] = _T('\0');
+
+    EXPECT_STREQ(expected_string, buffer);
+  }
+
+  void VerifyExpectedSavedFilePath(const CString& expected_temp_directory) {
+    const int kMaxUniqueChars = 4;
+    const CString expected_path_part_a = expected_temp_directory + _T("\\GUR");
+    const CString expected_path_part_b = _T(".exe");
+    EXPECT_STREQ(expected_path_part_a,
+                 saved_file_path_.Left(expected_path_part_a.GetLength()));
+    EXPECT_STREQ(expected_path_part_b,
+                 saved_file_path_.Right(expected_path_part_b.GetLength()));
+    const int constant_chars = expected_path_part_a.GetLength() +
+                               expected_path_part_b.GetLength();
+    EXPECT_GT(saved_file_path_.GetLength(), constant_chars);
+    EXPECT_LE(saved_file_path_.GetLength(), constant_chars + kMaxUniqueChars);
+  }
+
+  static CString saved_url_;
+  static CString saved_file_path_;
+  static void* saved_context_;
+
+ protected:
+  // Copies SaveArguments.exe to the specified location.
+  static HRESULT DownloadArgumentSavingFile(const TCHAR* url,
+                                            const TCHAR* file_path,
+                                            void* context) {
+    ASSERT1(url);
+    ASSERT1(file_path);
+
+    GoogleUpdateRecoveryTest::set_saved_url(url);
+    GoogleUpdateRecoveryTest::set_saved_file_path(file_path);
+    GoogleUpdateRecoveryTest::set_saved_context(context);
+
+    CString executable_full_path(app_util::GetCurrentModuleDirectory());
+    VERIFY1(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),
+                         kArgumentSavingExecutableRelativePath));
+
+    if (!::CopyFile(executable_full_path, file_path, false)) {
+      HRESULT hr = HRESULTFromLastError();
+      return hr;
+    }
+
+    return S_OK;
+  }
+
+  // Returns kDummyNoFileError, simulating no file to download.
+  static HRESULT DownloadFileNoFile(const TCHAR* url,
+                                    const TCHAR* file_path,
+                                    void* context) {
+    ASSERT1(url);
+    ASSERT1(file_path);
+
+    GoogleUpdateRecoveryTest::set_saved_url(url);
+    GoogleUpdateRecoveryTest::set_saved_file_path(file_path);
+    GoogleUpdateRecoveryTest::set_saved_context(context);
+
+    return kDummyNoFileError;
+  }
+
+  // Overrides the address to cause a file to be downloaded via HTTP.
+  // Uses a real HTTP stack, so it is similar to a real implementation.
+  // The file is invalid, so signature verification should return
+  // TRUST_E_SUBJECT_FORM_UNKNOWN.
+  static HRESULT DownloadFileInvalidFile(const TCHAR* url,
+                                         const TCHAR* file_path,
+                                         void* context) {
+    ASSERT1(url);
+    CString test_url(url);
+
+    VERIFY1(1 == test_url.Replace(kUrlCodeRedCheck, kInvalidFileAddress));
+
+    return DownloadFileFromServer(test_url, file_path, context);
+  }
+
+  // Uses a real HTTP stack, so it is similar to a real implementation.
+  static HRESULT DownloadFileFromServer(const TCHAR* url,
+                                        const TCHAR* file_path,
+                                        void* context) {
+    UTIL_LOG(L2, (_T("[DownloadFileFromServer][%s][%s]"), url, file_path));
+
+    ASSERT1(url);
+    ASSERT1(file_path);
+
+    GoogleUpdateRecoveryTest::set_saved_url(url);
+    GoogleUpdateRecoveryTest::set_saved_file_path(file_path);
+    GoogleUpdateRecoveryTest::set_saved_context(context);
+
+    NetworkConfig& network_config = NetworkConfig::Instance();
+    ON_SCOPE_EXIT_OBJ(network_config, &NetworkConfig::Clear);
+
+    network_config.Clear();
+    network_config.Add(new GoogleProxyDetector(MACHINE_REG_UPDATE_DEV));
+    network_config.Add(new FirefoxProxyDetector());
+    network_config.Add(new IEProxyDetector());
+
+    NetworkRequest network_request(network_config.session());
+    network_request.AddHttpRequest(new SimpleRequest);
+    network_request.AddHttpRequest(new BrowserRequest);
+
+    HRESULT hr = network_request.DownloadFile(url, CString(file_path));
+    if (FAILED(hr)) {
+      UTIL_LOG(LE, (_T("[DownloadFile failed][%s][0x%08x]"), url, hr));
+      return hr;
+    }
+
+    int status_code = network_request.http_status_code();
+    UTIL_LOG(L2, (_T("[HTTP status][%u]"), status_code));
+
+    if (HTTP_STATUS_OK == status_code) {
+      return S_OK;
+    } else if (HTTP_STATUS_NO_CONTENT == status_code) {
+      return kDummyNoFileError;
+    } else {
+      // Apps would not have this assumption.
+      ASSERT(false, (_T("Status code %i received. Expected 200 or 204."),
+                     status_code));
+      return E_FAIL;
+    }
+  }
+};
+
+CString GoogleUpdateRecoveryTest::saved_url_;
+CString GoogleUpdateRecoveryTest::saved_file_path_;
+void* GoogleUpdateRecoveryTest::saved_context_;
+
+class GoogleUpdateRecoveryRegistryProtectedTest
+    : public GoogleUpdateRecoveryTest {
+ protected:
+  GoogleUpdateRecoveryRegistryProtectedTest()
+      : hive_override_key_name_(kRegistryHiveOverrideRoot) {
+  }
+
+  CString hive_override_key_name_;
+
+  virtual void SetUp() {
+    GoogleUpdateRecoveryTest::SetUp();
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    OverrideRegistryHives(hive_override_key_name_);
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    ASSERT_HRESULT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+    GoogleUpdateRecoveryTest::TearDown();
+  }
+};
+
+//
+// FixGoogleUpdate Tests
+//
+
+TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_UseRealHttpClient) {
+  EXPECT_EQ(TRUST_E_SUBJECT_FORM_UNKNOWN,
+            FixGoogleUpdate(kDummyAppGuid,
+                            kDummyAppVersion,
+                            kDummyAppLang,
+                            true,
+                            DownloadFileInvalidFile,
+                            NULL));
+}
+
+TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_FileReturned_Machine) {
+  CString saved_arguments_path = ConcatenatePath(app_util::GetTempDir(),
+                                                 kSavedArgumentsFileName);
+
+  ::DeleteFile(saved_arguments_path);
+  ASSERT_FALSE(File::Exists(saved_arguments_path));
+
+  CString context_string(_T("some context"));
+  EXPECT_HRESULT_SUCCEEDED(FixGoogleUpdate(kDummyAppGuid,
+                                           kDummyAppVersion,
+                                           kDummyAppLang,
+                                           true,
+                                           DownloadArgumentSavingFile,
+                                           &context_string));
+
+  EXPECT_EQ(&context_string, saved_context_);
+  EXPECT_STREQ(_T("some context"), *static_cast<CString*>(saved_context_));
+
+  ::Sleep(200);
+  EXPECT_TRUE(File::Exists(saved_file_path_));
+  VerifySavedArgumentsFile(_T("/recover /machine"));
+
+  EXPECT_TRUE(::DeleteFile(saved_file_path_));
+  EXPECT_TRUE(::DeleteFile(saved_arguments_path));
+}
+
+TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_FileReturned_User) {
+  CString saved_arguments_path = ConcatenatePath(app_util::GetTempDir(),
+                                                 kSavedArgumentsFileName);
+
+  ::DeleteFile(saved_arguments_path);
+  ASSERT_FALSE(File::Exists(saved_arguments_path));
+
+  CString context_string(_T("more context"));
+  EXPECT_HRESULT_SUCCEEDED(FixGoogleUpdate(kDummyAppGuid,
+                                           kDummyAppVersion,
+                                           kDummyAppLang,
+                                           false,
+                                           DownloadArgumentSavingFile,
+                                           &context_string));
+
+  EXPECT_EQ(&context_string, saved_context_);
+  EXPECT_STREQ(_T("more context"), *static_cast<CString*>(saved_context_));
+
+  ::Sleep(200);
+  EXPECT_TRUE(File::Exists(saved_file_path_));
+  VerifySavedArgumentsFile(_T("/recover"));
+
+  EXPECT_TRUE(::DeleteFile(saved_file_path_));
+  EXPECT_TRUE(::DeleteFile(saved_arguments_path));
+}
+
+TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_NoFile_Machine) {
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+
+  EXPECT_EQ(static_cast<void*>(NULL), saved_context_);
+  EXPECT_FALSE(File::Exists(saved_file_path_));
+
+  TCHAR temp_dir[MAX_PATH] = {0};
+  EXPECT_TRUE(::GetEnvironmentVariable(_T("TMP"), temp_dir, MAX_PATH));
+  EXPECT_TRUE(File::Exists(temp_dir))
+      << _T("The temp directory was deleted or not created.");
+}
+
+TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_NoFile_User) {
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               false,
+                                               DownloadFileNoFile,
+                                               NULL));
+
+  EXPECT_EQ(static_cast<void*>(NULL), saved_context_);
+  EXPECT_FALSE(File::Exists(saved_file_path_));
+
+  TCHAR temp_dir[MAX_PATH] = {0};
+  EXPECT_TRUE(::GetEnvironmentVariable(_T("TMP"), temp_dir, MAX_PATH));
+  EXPECT_TRUE(File::Exists(temp_dir))
+      << _T("The temp directory was deleted or not created.");
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_AllValues_MachineApp) {
+  const TCHAR kExpectedUrl[] = _T("http://cr-tools.clients.google.com/service/check2?appid=%7B8E472B0D-3E8B-43b1-B89A-E8506AAF1F16%7D&appversion=3.4.5.6&applang=en-us&machine=1&version=5.6.78.1&machineid=%7B12A7B304-B4ED-4b5c-8122-31E7ECB8BE3C%7D&userid=%7B29388E49-2995-437c-BF47-587C7E9247E5%7D&osversion=");  // NOLINT
+
+  const CString prev_tmp = GetTmp();
+  ASSERT_TRUE(::SetEnvironmentVariable(_T("TMP"), kTempDirectory));
+
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullMachineOmahaClientKeyPath,
+                                            _T("pv"),
+                                            _T("5.6.78.1")));
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullMachineOmahaMainKeyPath,
+                                            _T("mi"),
+                                            kDummyMachineId));
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullMachineOmahaMainKeyPath,
+                                            _T("ui"),
+                                            kDummyUserId));
+
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+
+  EXPECT_STREQ(kExpectedUrl, saved_url_.Left(arraysize(kExpectedUrl) - 1));
+  CheckSavedUrlOSFragment();
+  VerifyExpectedSavedFilePath(kTempDirectory);
+
+  EXPECT_TRUE(::SetEnvironmentVariable(_T("TMP"), prev_tmp));
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_AllValues_UserApp) {
+  const TCHAR kExpectedUrl[] = _T("http://cr-tools.clients.google.com/service/check2?appid=%7B8E472B0D-3E8B-43b1-B89A-E8506AAF1F16%7D&appversion=3.4.5.6&applang=en-us&machine=0&version=5.6.78.1&machineid=%7B12A7B304-B4ED-4b5c-8122-31E7ECB8BE3C%7D&userid=%7B29388E49-2995-437c-BF47-587C7E9247E5%7D&osversion=");  // NOLINT
+
+  const CString prev_tmp = GetTmp();
+  ASSERT_TRUE(::SetEnvironmentVariable(_T("TMP"), kTempDirectory));
+
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullUserOmahaClientKeyPath,
+                                            _T("pv"),
+                                            _T("5.6.78.1")));
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullMachineOmahaMainKeyPath,
+                                            _T("mi"),
+                                            kDummyMachineId));
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullUserOmahaMainKeyPath,
+                                            _T("ui"),
+                                            kDummyUserId));
+
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               false,
+                                               DownloadFileNoFile,
+                                               NULL));
+
+  EXPECT_STREQ(kExpectedUrl, saved_url_.Left(arraysize(kExpectedUrl) - 1));
+  CheckSavedUrlOSFragment();
+  VerifyExpectedSavedFilePath(kTempDirectory);
+
+  EXPECT_TRUE(::SetEnvironmentVariable(_T("TMP"), prev_tmp));
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_NoOmahaRegKeys) {
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,
+               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));
+  CheckSavedUrlOSFragment();
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_EmptyAppInfo) {
+  const TCHAR kExpectedUrl[] = _T("http://cr-tools.clients.google.com/service/check2?appid=&appversion=&applang=&machine=1&version=0.0.0.0&machineid=&userid=&osversion=");  // NOLINT
+
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(_T(""),
+                                               _T(""),
+                                               _T(""),
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+  EXPECT_STREQ(kExpectedUrl, saved_url_.Left(arraysize(kExpectedUrl) - 1));
+  CheckSavedUrlOSFragment();
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_NullArgs) {
+  EXPECT_EQ(E_INVALIDARG, FixGoogleUpdate(NULL,
+                                          _T(""),
+                                          _T(""),
+                                          true,
+                                          DownloadFileNoFile,
+                                          NULL));
+  EXPECT_EQ(E_INVALIDARG, FixGoogleUpdate(_T(""),
+                                          NULL,
+                                          _T(""),
+                                          true,
+                                          DownloadFileNoFile,
+                                          NULL));
+  EXPECT_EQ(E_INVALIDARG, FixGoogleUpdate(_T(""),
+                                          _T(""),
+                                          NULL,
+                                          true,
+                                          DownloadFileNoFile,
+                                          NULL));
+  EXPECT_EQ(E_INVALIDARG, FixGoogleUpdate(_T(""),
+                                          _T(""),
+                                          _T(""),
+                                          true,
+                                          NULL,
+                                          NULL));
+}
+
+// Setting kRegValueAutoUpdateCheckPeriodOverrideMinutes to zero disables
+// Code Red checks just as it does regular update checks.
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsZeroDword) {
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,
+                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                       static_cast<DWORD>(0)));
+
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_ACCESS_DISABLED_BY_POLICY),
+            FixGoogleUpdate(kDummyAppGuid,
+                            kDummyAppVersion,
+                            kDummyAppLang,
+                            true,
+                            DownloadFileNoFile,
+                            NULL));
+  EXPECT_TRUE(saved_url_.IsEmpty());
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsZeroDwordInHkcu) {
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(USER_KEY GOOPDATE_POLICIES_RELATIVE,
+                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                       static_cast<DWORD>(0)));
+
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,
+               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));
+  CheckSavedUrlOSFragment();
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsNonZeroDword) {
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,
+                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                       static_cast<DWORD>(1400)));
+
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,
+               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));
+  CheckSavedUrlOSFragment();
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsZeroDword64) {
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,
+                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                       static_cast<DWORD64>(0)));
+
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,
+               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));
+  CheckSavedUrlOSFragment();
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsNonZeroDword64) {
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,
+                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                       static_cast<DWORD64>(1400)));
+
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,
+               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));
+  CheckSavedUrlOSFragment();
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsZeroAsString) {
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,
+                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                       _T("0")));
+
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,
+               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));
+  CheckSavedUrlOSFragment();
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_AutoUpdateCheckPeriodMinutesIsZeroAsBinary) {
+  const byte zero = 0;
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,
+                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                       &zero,
+                       sizeof(zero)));
+
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,
+               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));
+  CheckSavedUrlOSFragment();
+}
+
+TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,
+       FixGoogleUpdate_GroupPolicyKeyExistsButNoAutoUpdateCheckPeriodMinutes) {
+  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKey(kRegKeyGoopdateGroupPolicy));
+
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileNoFile,
+                                               NULL));
+  EXPECT_STREQ(kExpectedUrlForDummyAppAndNoOmahaValues,
+               saved_url_.Left(kExpectedUrlForDummyAppAndNoOmahaValuesLength));
+  CheckSavedUrlOSFragment();
+}
+
+// Verifies that the file is saved even if the temp directory doesn't exist.
+TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_SaveToNonExistantDirectory) {
+  const TCHAR kNonExistantDirectory[] = _T("c:\\directory_does_not_exist");
+  DeleteDirectory(kNonExistantDirectory);
+  ASSERT_FALSE(File::Exists(kNonExistantDirectory));
+
+  const CString prev_tmp = GetTmp();
+  ASSERT_TRUE(::SetEnvironmentVariable(_T("TMP"), kNonExistantDirectory));
+
+  EXPECT_EQ(TRUST_E_SUBJECT_FORM_UNKNOWN,
+            FixGoogleUpdate(kDummyAppGuid,
+                            kDummyAppVersion,
+                            kDummyAppLang,
+                            true,
+                            DownloadFileInvalidFile,
+                            NULL));
+
+  VerifyExpectedSavedFilePath(kNonExistantDirectory);
+
+  EXPECT_TRUE(::SetEnvironmentVariable(_T("TMP"), prev_tmp));
+}
+
+TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_FileCollision) {
+  const CString prev_tmp = GetTmp();
+  ASSERT_TRUE(::SetEnvironmentVariable(_T("TMP"), kTempDirectory));
+
+  CString saved_arguments_path = ConcatenatePath(app_util::GetTempDir(),
+                                                 kSavedArgumentsFileName);
+
+  EXPECT_HRESULT_SUCCEEDED(FixGoogleUpdate(kDummyAppGuid,
+                                           kDummyAppVersion,
+                                           kDummyAppLang,
+                                           false,
+                                           DownloadArgumentSavingFile,
+                                           NULL));
+
+  EXPECT_TRUE(File::Exists(saved_file_path_));
+  VerifyExpectedSavedFilePath(kTempDirectory);
+
+  CString first_saved_file_path = saved_file_path_;
+
+  // Ensure that the first downloaded file is in use.
+  FileLock lock;
+  EXPECT_HRESULT_SUCCEEDED(lock.Lock(first_saved_file_path));
+
+  EXPECT_HRESULT_SUCCEEDED(FixGoogleUpdate(kDummyAppGuid,
+                                           kDummyAppVersion,
+                                           kDummyAppLang,
+                                           false,
+                                           DownloadArgumentSavingFile,
+                                           NULL));
+  EXPECT_TRUE(File::Exists(saved_file_path_));
+  VerifyExpectedSavedFilePath(kTempDirectory);
+
+  EXPECT_STRNE(first_saved_file_path, saved_file_path_);
+
+  EXPECT_HRESULT_SUCCEEDED(lock.Unlock());
+
+  bool is_deleted = false;
+  for (int tries = 0; tries < 100 && !is_deleted; ++tries) {
+    ::Sleep(50);
+    is_deleted = !!::DeleteFile(saved_file_path_);
+  }
+  EXPECT_TRUE(is_deleted);
+
+  EXPECT_TRUE(::DeleteFile(first_saved_file_path));
+  EXPECT_TRUE(::DeleteFile(saved_arguments_path));
+
+  EXPECT_TRUE(::SetEnvironmentVariable(_T("TMP"), prev_tmp));
+}
+
+//
+// VerifyFileSignature Tests
+//
+TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_SignedValid) {
+  CString executable_full_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),
+                           kArgumentSavingExecutableRelativePath));
+  ASSERT_TRUE(File::Exists(executable_full_path));
+  EXPECT_HRESULT_SUCCEEDED(VerifyFileSignature(executable_full_path));
+}
+
+TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_NotSigned) {
+  const TCHAR kUnsignedExecutable[] = _T("GoogleUpdate_unsigned.exe");
+
+  CString executable_full_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),
+                           kUnsignedExecutable));
+  ASSERT_TRUE(File::Exists(executable_full_path));
+  EXPECT_EQ(TRUST_E_NOSIGNATURE, VerifyFileSignature(executable_full_path));
+}
+
+// The certificate is still valid, but the executable was signed more than N
+// days ago.
+TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_SignedOldWithValidCert) {
+  const TCHAR kUnsignedExecutable[] =
+      _T("unittest_support\\GoogleUpdate_old_signature.exe");
+
+  CString executable_full_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),
+                           kUnsignedExecutable));
+  ASSERT_TRUE(File::Exists(executable_full_path));
+  EXPECT_EQ(TRUST_E_TIME_STAMP, VerifyFileSignature(executable_full_path));
+}
+
+// The certificate was valid when it was used to sign the executable, but it has
+// since expired.
+// The error returned is inappropriate for this case because of the way
+// expiration checking is implemented.
+TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_SignedWithNowExpiredCert) {
+  const TCHAR kUnsignedExecutable[] =
+      _T("unittest_support\\GoogleUpdate_now_expired_cert.exe");
+
+  CString executable_full_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),
+                           kUnsignedExecutable));
+  ASSERT_TRUE(File::Exists(executable_full_path));
+  EXPECT_EQ(CERT_E_CN_NO_MATCH, VerifyFileSignature(executable_full_path));
+}
+
+TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_UntrustedChain) {
+  const TCHAR kUntrustedChainExecutable[] =
+      _T("unittest_support\\SaveArguments_OmahaTestSigned.exe");
+
+  CString executable_full_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),
+                           kUntrustedChainExecutable));
+  ASSERT_TRUE(File::Exists(executable_full_path));
+  EXPECT_EQ(CERT_E_UNTRUSTEDROOT, VerifyFileSignature(executable_full_path));
+}
+
+TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_HashFails) {
+  const TCHAR kCorruptedExecutable[] =
+      _T("unittest_support\\GoogleUpdate_corrupted.exe");
+
+  CString executable_full_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),
+                           kCorruptedExecutable));
+  ASSERT_TRUE(File::Exists(executable_full_path));
+  EXPECT_EQ(TRUST_E_BAD_DIGEST, VerifyFileSignature(executable_full_path));
+}
+
+// The file for Windows Vista and later may not exist on all systems.
+TEST_F(GoogleUpdateRecoveryTest,
+       VerifyFileSignature_NonGoogleSignature) {
+  CString file_path = SystemInfo::IsRunningOnVistaOrLater() ?
+      _T("%SYSTEM%\\rcagent.exe") : _T("%SYSTEM%\\wuauclt.exe");
+  if (!File::Exists(file_path) && SystemInfo::IsRunningOnVistaOrLater()) {
+    std::wcout << _T("\tTest did not run because '") << file_path
+               << _T("' was not found.") << std::endl;
+    return;
+  }
+  ASSERT_HRESULT_SUCCEEDED(ExpandStringWithSpecialFolders(&file_path));
+  ASSERT_TRUE(File::Exists(file_path));
+  ASSERT_TRUE(SignatureIsValid(file_path, false));
+  EXPECT_EQ(CERT_E_CN_NO_MATCH, VerifyFileSignature(file_path));
+}
+
+TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_BadFilenames) {
+  EXPECT_EQ(CRYPT_E_FILE_ERROR, VerifyFileSignature(_T("NoSuchFile.exe")));
+
+  EXPECT_EQ(CRYPT_E_FILE_ERROR, VerifyFileSignature(NULL));
+
+  EXPECT_EQ(CRYPT_E_FILE_ERROR, VerifyFileSignature(_T("")));
+}
+
+//
+// VerifyRepairFileMarkup Tests
+//
+TEST_F(GoogleUpdateRecoveryTest, VerifyRepairFileMarkup_ValidMarkup) {
+  const TCHAR kExecutableWithMarkup[] =
+      _T("unittest_support\\SaveArguments.exe");
+  EXPECT_HRESULT_SUCCEEDED(VerifyRepairFileMarkup(kExecutableWithMarkup));
+}
+
+TEST_F(GoogleUpdateRecoveryTest, VerifyRepairFileMarkup_InvalidMarkups) {
+  const TCHAR kNoResourcesExecutable[] = _T("RecoveryTest.exe");
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND),
+            VerifyRepairFileMarkup(kNoResourcesExecutable));
+
+  const TCHAR kResourcesButNoMarkupExecutable[] = _T("GoogleUpdate.exe");
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND),
+            VerifyRepairFileMarkup(kResourcesButNoMarkupExecutable));
+
+  const TCHAR kWrongMarkupResourceNameExecutable[] =
+      _T("unittest_support\\SaveArguments_unsigned_wrong_resource_name.exe");
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_RESOURCE_NAME_NOT_FOUND),
+            VerifyRepairFileMarkup(kWrongMarkupResourceNameExecutable));
+
+  const TCHAR kWrongMarkupSizeExecutable[] =
+      _T("unittest_support\\SaveArguments_unsigned_wrong_markup_size.exe");
+  EXPECT_EQ(E_UNEXPECTED, VerifyRepairFileMarkup(kWrongMarkupSizeExecutable));
+
+  const TCHAR kWrongMarkupValueExecutable[] =
+      _T("unittest_support\\SaveArguments_unsigned_wrong_markup_value.exe");
+  EXPECT_EQ(E_UNEXPECTED, VerifyRepairFileMarkup(kWrongMarkupValueExecutable));
+}
+
+TEST_F(GoogleUpdateRecoveryTest, VerifyRepairFileMarkup_BadFilenames) {
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            VerifyRepairFileMarkup(_T("NoSuchFile.exe")));
+
+  EXPECT_EQ(E_INVALIDARG, VerifyRepairFileMarkup(NULL));
+
+  EXPECT_EQ(E_INVALIDARG, VerifyRepairFileMarkup(_T("")));
+}
+
+//
+// VerifyRepairFileMarkup Tests
+//
+// TODO(omaha): Unit test VerifyIsValidRepairFile.
+
+//
+// Production Server Response Tests Tests
+//
+TEST_F(GoogleUpdateRecoveryTest, ProductionServerResponseTest) {
+  EXPECT_EQ(kDummyNoFileError, FixGoogleUpdate(kDummyAppGuid,
+                                               kDummyAppVersion,
+                                               kDummyAppLang,
+                                               true,
+                                               DownloadFileFromServer,
+                                               NULL)) <<
+      _T("The production server did not return 204. This may indicate network ")
+      _T("issues or that the Code Red server is configured incorrectly");
+}
+
+}  // namespace omaha
+
diff --git a/common/has_exception_namespace_fix.h b/common/has_exception_namespace_fix.h
index 4c23f2a..e4f6367 100644
--- a/common/has_exception_namespace_fix.h
+++ b/common/has_exception_namespace_fix.h
@@ -1,21 +1,21 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#if !_HAS_EXCEPTIONS

-// Fixes a problem with using the standard library with exceptions turned off.

-// See discussion at http://tiny.cc/byLhe

-#include <exception>

-using std::exception;

-#endif

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#if !_HAS_EXCEPTIONS
+// Fixes a problem with using the standard library with exceptions turned off.
+// See discussion at http://tiny.cc/byLhe
+#include <exception>
+using std::exception;
+#endif
diff --git a/common/highres_timer-win32.cc b/common/highres_timer-win32.cc
index 9e83fab..f4597f3 100644
--- a/common/highres_timer-win32.cc
+++ b/common/highres_timer-win32.cc
@@ -1,60 +1,60 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-#include "omaha/common/highres_timer-win32.h"

-

-namespace omaha {

-

-bool HighresTimer::perf_freq_collected_ = false;

-ULONGLONG HighresTimer::perf_freq_ = 0;

-

-ULONGLONG HighresTimer::GetElapsedMs() const {

-  ULONGLONG end_time = GetCurrentTicks();

-

-  // Scale to ms and round to nearerst ms - rounding is important

-  // because otherwise the truncation error may accumulate e.g. in sums.

-  //

-  // Given infinite resolution, this expression could be written as:

-  //  trunc((end - start (units:freq*sec))/freq (units:sec) *

-  //                1000 (unit:ms) + 1/2 (unit:ms))

-  ULONGLONG freq = GetTimerFrequency();

-  return ((end_time - start_ticks_) * 1000L + freq / 2) / freq;

-}

-

-ULONGLONG HighresTimer::GetElapsedSec() const {

-  ULONGLONG end_time = GetCurrentTicks();

-

-  // Scale to ms and round to nearerst ms - rounding is important

-  // because otherwise the truncation error may accumulate e.g. in sums.

-  //

-  // Given infinite resolution, this expression could be written as:

-  //  trunc((end - start (units:freq*sec))/freq (unit:sec) + 1/2 (unit:sec))

-  ULONGLONG freq = GetTimerFrequency();

-  return ((end_time - start_ticks_) + freq / 2) / freq;

-}

-

-void HighresTimer::CollectPerfFreq() {

-  LARGE_INTEGER freq;

-

-  // Note that this is racy.

-  // It's OK, however, because even concurrent executions of this

-  // are idempotent.

-  if (::QueryPerformanceFrequency(&freq)) {

-    perf_freq_ = freq.QuadPart;

-    perf_freq_collected_ = true;

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+#include "omaha/common/highres_timer-win32.h"
+
+namespace omaha {
+
+bool HighresTimer::perf_freq_collected_ = false;
+ULONGLONG HighresTimer::perf_freq_ = 0;
+
+ULONGLONG HighresTimer::GetElapsedMs() const {
+  ULONGLONG end_time = GetCurrentTicks();
+
+  // Scale to ms and round to nearerst ms - rounding is important
+  // because otherwise the truncation error may accumulate e.g. in sums.
+  //
+  // Given infinite resolution, this expression could be written as:
+  //  trunc((end - start (units:freq*sec))/freq (units:sec) *
+  //                1000 (unit:ms) + 1/2 (unit:ms))
+  ULONGLONG freq = GetTimerFrequency();
+  return ((end_time - start_ticks_) * 1000L + freq / 2) / freq;
+}
+
+ULONGLONG HighresTimer::GetElapsedSec() const {
+  ULONGLONG end_time = GetCurrentTicks();
+
+  // Scale to ms and round to nearerst ms - rounding is important
+  // because otherwise the truncation error may accumulate e.g. in sums.
+  //
+  // Given infinite resolution, this expression could be written as:
+  //  trunc((end - start (units:freq*sec))/freq (unit:sec) + 1/2 (unit:sec))
+  ULONGLONG freq = GetTimerFrequency();
+  return ((end_time - start_ticks_) + freq / 2) / freq;
+}
+
+void HighresTimer::CollectPerfFreq() {
+  LARGE_INTEGER freq;
+
+  // Note that this is racy.
+  // It's OK, however, because even concurrent executions of this
+  // are idempotent.
+  if (::QueryPerformanceFrequency(&freq)) {
+    perf_freq_ = freq.QuadPart;
+    perf_freq_collected_ = true;
+  }
+}
+
+}  // namespace omaha
+
diff --git a/common/highres_timer-win32.h b/common/highres_timer-win32.h
index ce801d8..68a9f6e 100644
--- a/common/highres_timer-win32.h
+++ b/common/highres_timer-win32.h
@@ -1,90 +1,90 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-#ifndef OMAHA_COMMON_HIGHRES_TIMER_WIN32_H__

-#define OMAHA_COMMON_HIGHRES_TIMER_WIN32_H__

-

-#include <windows.h>

-

-namespace omaha {

-

-/// A handy class for reliably measuring wall-clock time with decent resolution,

-/// even on multi-processor machines and on laptops (where RDTSC potentially

-/// returns different results on different processors and/or the RDTSC timer

-/// clocks at different rates depending on the power state of the CPU,

-/// respectively).

-class HighresTimer {

- public:

-  /// Captures the current start time

-  HighresTimer();

-

-  /// Captures the current tick, can be used to reset a timer for reuse.

-  void Start();

-

-  /// Returns the elapsed ticks with full resolution

-  ULONGLONG GetElapsedTicks() const;

-

-  /// Returns the elapsed time in milliseconds, rounded to the nearest

-  /// millisecond.

-  ULONGLONG GetElapsedMs() const;

-

-  /// Returns the elapsed time in seconds, rounded to the nearest second.

-  ULONGLONG GetElapsedSec() const;

-

-  ULONGLONG start_ticks() const { return start_ticks_; }

-

-  /// Returns timer frequency from cache, should be less

-  /// overhead than ::QueryPerformanceFrequency

-  static ULONGLONG GetTimerFrequency();

-  /// Returns current ticks

-  static ULONGLONG GetCurrentTicks();

-

- private:

-  static void CollectPerfFreq();

-

-  /// Captured start time

-  ULONGLONG start_ticks_;

-

-  /// Captured performance counter frequency

-  static bool perf_freq_collected_;

-  static ULONGLONG perf_freq_;

-};

-

-inline HighresTimer::HighresTimer() {

-  Start();

-}

-

-inline void HighresTimer::Start() {

-  start_ticks_ = GetCurrentTicks();

-}

-

-inline ULONGLONG HighresTimer::GetTimerFrequency() {

-  if (!perf_freq_collected_)

-    CollectPerfFreq();

-  return perf_freq_;

-}

-

-inline ULONGLONG HighresTimer::GetCurrentTicks() {

-  LARGE_INTEGER ticks;

-  ::QueryPerformanceCounter(&ticks);

-  return ticks.QuadPart;

-}

-

-inline ULONGLONG HighresTimer::GetElapsedTicks() const {

-  return start_ticks_ - GetCurrentTicks();

-}

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_HIGHRES_TIMER_WIN32_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+#ifndef OMAHA_COMMON_HIGHRES_TIMER_WIN32_H__
+#define OMAHA_COMMON_HIGHRES_TIMER_WIN32_H__
+
+#include <windows.h>
+
+namespace omaha {
+
+/// A handy class for reliably measuring wall-clock time with decent resolution,
+/// even on multi-processor machines and on laptops (where RDTSC potentially
+/// returns different results on different processors and/or the RDTSC timer
+/// clocks at different rates depending on the power state of the CPU,
+/// respectively).
+class HighresTimer {
+ public:
+  /// Captures the current start time
+  HighresTimer();
+
+  /// Captures the current tick, can be used to reset a timer for reuse.
+  void Start();
+
+  /// Returns the elapsed ticks with full resolution
+  ULONGLONG GetElapsedTicks() const;
+
+  /// Returns the elapsed time in milliseconds, rounded to the nearest
+  /// millisecond.
+  ULONGLONG GetElapsedMs() const;
+
+  /// Returns the elapsed time in seconds, rounded to the nearest second.
+  ULONGLONG GetElapsedSec() const;
+
+  ULONGLONG start_ticks() const { return start_ticks_; }
+
+  /// Returns timer frequency from cache, should be less
+  /// overhead than ::QueryPerformanceFrequency
+  static ULONGLONG GetTimerFrequency();
+  /// Returns current ticks
+  static ULONGLONG GetCurrentTicks();
+
+ private:
+  static void CollectPerfFreq();
+
+  /// Captured start time
+  ULONGLONG start_ticks_;
+
+  /// Captured performance counter frequency
+  static bool perf_freq_collected_;
+  static ULONGLONG perf_freq_;
+};
+
+inline HighresTimer::HighresTimer() {
+  Start();
+}
+
+inline void HighresTimer::Start() {
+  start_ticks_ = GetCurrentTicks();
+}
+
+inline ULONGLONG HighresTimer::GetTimerFrequency() {
+  if (!perf_freq_collected_)
+    CollectPerfFreq();
+  return perf_freq_;
+}
+
+inline ULONGLONG HighresTimer::GetCurrentTicks() {
+  LARGE_INTEGER ticks;
+  ::QueryPerformanceCounter(&ticks);
+  return ticks.QuadPart;
+}
+
+inline ULONGLONG HighresTimer::GetElapsedTicks() const {
+  return start_ticks_ - GetCurrentTicks();
+}
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_HIGHRES_TIMER_WIN32_H__
diff --git a/common/highres_timer_unittest.cc b/common/highres_timer_unittest.cc
index e1f4eb1..09ad671 100644
--- a/common/highres_timer_unittest.cc
+++ b/common/highres_timer_unittest.cc
@@ -1,68 +1,68 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-#include "base/basictypes.h"

-#include "omaha/common/highres_timer-win32.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Timing tests are very flaky on Pulse.

-TEST(HighresTimer, MillisecondClock) {

-  if (omaha::IsBuildSystem()) {

-    return;

-  }

-

-  HighresTimer timer;

-

-  // note: this could fail if we context switch between initializing the timer

-  // and here. Very unlikely however.

-  EXPECT_EQ(0, timer.GetElapsedMs());

-  timer.Start();

-  uint64 half_ms = HighresTimer::GetTimerFrequency() / 2000;

-  // busy wait for half a millisecond

-  while (timer.start_ticks() + half_ms > HighresTimer::GetCurrentTicks()) {

-    // Nothing

-  }

-  EXPECT_EQ(1, timer.GetElapsedMs());

-}

-

-TEST(HighresTimer, SecondClock) {

-  if (omaha::IsBuildSystem()) {

-    return;

-  }

-

-  HighresTimer timer;

-

-  EXPECT_EQ(0, timer.GetElapsedSec());

-#ifdef OS_WINDOWS

-  ::Sleep(250);

-#else

-  struct timespec ts1 = {0, 250000000};

-  nanosleep(&ts1, 0);

-#endif

-  EXPECT_EQ(0, timer.GetElapsedSec());

-  EXPECT_LE(230, timer.GetElapsedMs());

-  EXPECT_GE(270, timer.GetElapsedMs());

-#ifdef OS_WINDOWS

-  ::Sleep(251);

-#else

-  struct timespec ts2 = {0, 251000000};

-  nanosleep(&ts2, 0);

-#endif

-  EXPECT_EQ(1, timer.GetElapsedSec());

-}

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+#include "base/basictypes.h"
+#include "omaha/common/highres_timer-win32.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Timing tests are very flaky on Pulse.
+TEST(HighresTimer, MillisecondClock) {
+  if (omaha::IsBuildSystem()) {
+    return;
+  }
+
+  HighresTimer timer;
+
+  // note: this could fail if we context switch between initializing the timer
+  // and here. Very unlikely however.
+  EXPECT_EQ(0, timer.GetElapsedMs());
+  timer.Start();
+  uint64 half_ms = HighresTimer::GetTimerFrequency() / 2000;
+  // busy wait for half a millisecond
+  while (timer.start_ticks() + half_ms > HighresTimer::GetCurrentTicks()) {
+    // Nothing
+  }
+  EXPECT_EQ(1, timer.GetElapsedMs());
+}
+
+TEST(HighresTimer, SecondClock) {
+  if (omaha::IsBuildSystem()) {
+    return;
+  }
+
+  HighresTimer timer;
+
+  EXPECT_EQ(0, timer.GetElapsedSec());
+#ifdef OS_WINDOWS
+  ::Sleep(250);
+#else
+  struct timespec ts1 = {0, 250000000};
+  nanosleep(&ts1, 0);
+#endif
+  EXPECT_EQ(0, timer.GetElapsedSec());
+  EXPECT_LE(230, timer.GetElapsedMs());
+  EXPECT_GE(270, timer.GetElapsedMs());
+#ifdef OS_WINDOWS
+  ::Sleep(251);
+#else
+  struct timespec ts2 = {0, 251000000};
+  nanosleep(&ts2, 0);
+#endif
+  EXPECT_EQ(1, timer.GetElapsedSec());
+}
+
+}  // namespace omaha
+
diff --git a/common/lang_enc.h b/common/lang_enc.h
index 978ea6f..e6df865 100644
--- a/common/lang_enc.h
+++ b/common/lang_enc.h
@@ -1,299 +1,299 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// This file is for i18n. It contains two enums, namely Language and

-// Encoding, where Language is the linguistic convention, and Encoding

-// contains information on both language encoding and character set.

-//

-// The language and encoding are both based on Teragram's conventions,

-// except for some common ISO-8859 encodings that are not detected by

-// Teragram but might be in the future.

-//

-// This file also includes functions that do mappings among

-// Language/Encoding enums, language/encoding string names (typically

-// the output from Language Encoding identifier), and language codes

-// (iso 639), and two-letter country codes (iso 3166)

-//

-// NOTE: Both Language and Encoding enums should always start from

-// zero value. This assumption has been made and used.

-

-#ifndef  OMAHA_COMMON_LANG_ENC_H_

-#define  OMAHA_COMMON_LANG_ENC_H_

-

-#include "omaha/common/commontypes.h"

-

-// some of the popular encoding aliases

-#define LATIN1     ISO_8859_1

-#define LATIN2     ISO_8859_2

-#define LATIN3     ISO_8859_3

-#define LATIN4     ISO_8859_4

-#define CYRILLIC   ISO_8859_5

-#define ARABIC_ENCODING  ISO_8859_6     // avoiding the same name as language

-#define GREEK_ENCODING   ISO_8859_7     // avoiding the same name as language

-#define HEBREW_ENCODING  ISO_8859_8     // avoiding the same name as language

-#define LATIN5     ISO_8859_9

-#define LATIN6     ISO_8859_10

-#define KOREAN_HANGUL  KOREAN_EUC_KR

-

-// NOTE: Only add new languages to the end of this list (but before

-// NUM_LANGUAGES).

-enum Language {

-  ENGLISH = 0,  /* 0 */

-  DANISH,       /* 1 */

-  DUTCH,        /* 2 */

-  FINNISH,      /* 3 */

-  FRENCH,       /* 4 */

-  GERMAN,       /* 5 */

-  HEBREW,       /* 6 */

-  ITALIAN,      /* 7 */

-  JAPANESE,     /* 8 */

-  KOREAN,       /* 9 */

-  NORWEGIAN,    /* 10 */

-  POLISH,       /* 11 */

-  PORTUGUESE,   /* 12 */

-  RUSSIAN,      /* 13 */

-  SPANISH,      /* 14 */

-  SWEDISH,      /* 15 */

-  CHINESE,      /* 16 */

-  CZECH,        /* 17 */

-  GREEK,        /* 18 */

-  ICELANDIC,    /* 19 */

-  LATVIAN,      /* 20 */

-  LITHUANIAN,   /* 21 */

-  ROMANIAN,     /* 22 */

-  HUNGARIAN,    /* 23 */

-  ESTONIAN,     /* 24 */

-  TG_UNKNOWN_LANGUAGE,  /* 25 */

-  UNKNOWN_LANGUAGE,     /* 26 */

-  BULGARIAN,    /* 27 */

-  CROATIAN,     /* 28 */

-  SERBIAN,      /* 29 */

-  IRISH,        /* 30 */

-  GALICIAN,     /* 31 */

-  TAGALOG,      /* 32 */

-  TURKISH,      /* 33 */

-  UKRAINIAN,    /* 34 */

-  HINDI,        /* 35 */

-  MACEDONIAN,   /* 36 */

-  BENGALI,      /* 37 */

-  INDONESIAN,   /* 38 */

-  LATIN,        /* 39 */

-  MALAY,        /* 40 */

-  MALAYALAM,    /* 41 */

-  WELSH,        /* 42 */

-  NEPALI,       /* 43 */

-  TELUGU,       /* 44 */

-  ALBANIAN,     /* 45 */

-  TAMIL,        /* 46 */

-  BELARUSIAN,   /* 47 */

-  JAVANESE,     /* 48 */

-  OCCITAN,      /* 49 */

-  URDU,         /* 50 */

-  BIHARI,       /* 51 */

-  GUJARATI,     /* 52 */

-  THAI,         /* 53 */

-  ARABIC,       /* 54 */

-  CATALAN,      /* 55 */

-  ESPERANTO,    /* 56 */

-  BASQUE,       /* 57 */

-  INTERLINGUA,  /* 58 */

-  KANNADA,      /* 59 */

-  PUNJABI,      /* 60 */

-  SCOTS_GAELIC, /* 61 */

-  SWAHILI,      /* 62 */

-  SLOVENIAN,    /* 63 */

-  MARATHI,      /* 64 */

-  MALTESE,      /* 65 */

-  VIETNAMESE,   /* 66 */

-  FRISIAN,      /* 67 */

-  SLOVAK,       /* 68 */

-  CHINESE_T,    /* 69 */      // This is added to solve the problem of

-                              // distinguishing Traditional and Simplified

-                              // Chinese when the encoding is UTF8.

-  FAROESE,      /* 70 */

-  SUNDANESE,    /* 71 */

-  UZBEK,        /* 72 */

-  AMHARIC,      /* 73 */

-  AZERBAIJANI,  /* 74 */

-  GEORGIAN,     /* 75 */

-  TIGRINYA,     /* 76 */

-  PERSIAN,      /* 77 */

-  BOSNIAN,      /* 78 */

-  SINHALESE,    /* 79 */

-  NORWEGIAN_N,  /* 80 */

-  PORTUGUESE_P, /* 81 */

-  PORTUGUESE_B, /* 82 */

-  XHOSA,        /* 83 */

-  ZULU,         /* 84 */

-  GUARANI,      /* 85 */

-  SESOTHO,      /* 86 */

-  TURKMEN,      /* 87 */

-  KYRGYZ,       /* 88 */

-  BRETON,       /* 89 */

-  TWI,          /* 90 */

-  YIDDISH,      /* 91 */

-  ORIYA,        /* 92 */

-  SERBO_CROATIAN,       /* 93 */

-  SOMALI,       /* 94 */

-  UIGHUR,       /* 95 */

-  KURDISH,      /* 96 */

-  MONGOLIAN,    /* 97 */

-  ARMENIAN,     /* 98 */

-  LAOTHIAN,     /* 99 */

-  SINDHI,       /* 100! */

-  RHAETO_ROMANCE,  /* 101 */

-  CHINESE_JAPANESE_KOREAN,  /* 103 */  // Not really a language

-  PSEUDOTRANSLATION,  /* 104 */  // Not really a language

-  NUM_LANGUAGES,              // Always keep this at the end. It is not a

-                              // valid Language enum, it is only used to

-                              // indicate the total number of Languages.

-};

-

-

-// Language codes for those languages we support, used to map to IDs from

-// the Language enumeration.  We could have used the Rfc1766ToLcid from the

-// Win32 system's mlang.dll to map these to LCIDs, but a) we don't want to

-// have to load mlang.dll and b) we are using our own language IDs.

-const TCHAR* const kLangCodeChinesePrc = _T("zh_cn");

-const TCHAR* const kLangCodeChineseTaiwan = _T("zh_tw");

-const TCHAR* const kLangCodeCjk = _T("cjk");

-const TCHAR* const kLangCodeDutch = _T("nl");

-const TCHAR* const kLangCodeEnglish = _T("en");

-const TCHAR* const kLangCodeFrench = _T("fr");

-const TCHAR* const kLangCodeGerman = _T("de");

-const TCHAR* const kLangCodeItalian = _T("it");

-const TCHAR* const kLangCodeJapanese = _T("ja");

-const TCHAR* const kLangCodeKorean = _T("ko");

-const TCHAR* const kLangCodePseudo = _T("x");

-const TCHAR* const kLangCodeSpanish = _T("es");

-

-

-// Maps language codes to languages.  Terminated by a { NULL, UNKNOWN_LANGUAGE }

-// item.

-struct CodeToLanguage {

-  const TCHAR* code;

-  Language language;

-};

-

-SELECTANY CodeToLanguage codes_to_languages[] = {

-  { kLangCodeChinesePrc, CHINESE },

-  { kLangCodeChineseTaiwan, CHINESE_T },

-  { kLangCodeCjk, CHINESE_JAPANESE_KOREAN },

-  { kLangCodeDutch, DUTCH },

-  { kLangCodeEnglish, ENGLISH },

-  { kLangCodeFrench, FRENCH },

-  { kLangCodeGerman, GERMAN },

-  { kLangCodeItalian, ITALIAN },

-  { kLangCodeJapanese, JAPANESE },

-  { kLangCodeKorean, KOREAN },

-  { kLangCodePseudo, PSEUDOTRANSLATION },

-  { kLangCodeSpanish, SPANISH },

-  { NULL, UNKNOWN_LANGUAGE }

-};

-

-

-

-// Macro to wrap the notion of "unknown language".

-#define IS_LANGUAGE_UNKNOWN(l)  \

-  ((l) == TG_UNKNOWN_LANGUAGE || (l) == UNKNOWN_LANGUAGE)

-

-// NOTE: Only add new encodings to the end of this list (but before

-// NUM_ENCODINGS).

-// NOTE: If you add an encoding here, you must also modify basistech_encoding()

-// and google2/com/google/i18n/Encoding.java

-enum Encoding {

-  ISO_8859_1 = 0,       // 0: Teragram ASCII

-  ISO_8859_2,           // 1: Teragram Latin2

-  ISO_8859_3,           // 2: in BasisTech but not in Teragram

-  ISO_8859_4,           // 3: Teragram Latin4

-  ISO_8859_5,           // 4: Teragram ISO-8859-5

-  ISO_8859_6,           // 5: Teragram Arabic

-  ISO_8859_7,           // 6: Teragram Greek

-  ISO_8859_8,           // 7: Teragram Hebrew

-  ISO_8859_9,           // 8: in BasisTech but not in Teragram

-  ISO_8859_10,          // 9: in BasisTech but not in Teragram

-  JAPANESE_EUC_JP,      // 10: Teragram EUC_JP

-  JAPANESE_SHIFT_JIS,   // 11: Teragram SJS

-  JAPANESE_JIS,         // 12: Teragram JIS

-  CHINESE_BIG5,         // 13: Teragram BIG5

-  CHINESE_GB,           // 14: Teragram GB

-  CHINESE_EUC_CN,       // 15: Teragram EUC-CN

-  KOREAN_EUC_KR,        // 16: Teragram KSC

-  UNICODE_ENCODING,     // 17: Teragram Unicode, changed to UNICODE_ENCODING

-                        //     from UNICODE, which is predefined by WINDOW

-  CHINESE_EUC_DEC,      // 18: Teragram EUC

-  CHINESE_CNS,          // 19: Teragram CNS

-  CHINESE_BIG5_CP950,   // 20: Teragram BIG5_CP950

-  JAPANESE_CP932,       // 21: Teragram CP932

-  UTF8,                 // 22

-  UNKNOWN_ENCODING,     // 23

-  ASCII_7BIT,           // 24: ISO_8859_1 with all characters <= 127.

-                        //     Should be present only in the crawler

-                        //     and in the repository,

-                        //     *never* as a result of Document::encoding().

-  RUSSIAN_KOI8_R,       // 25: Teragram KOI8R

-  RUSSIAN_CP1251,       // 26: Teragram CP1251

-

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

-  // These are _not_ output from teragram. Instead, they are as

-  // detected in the headers of usenet articles.

-  MSFT_CP1252,          // 27: CP1252 aka MSFT euro ascii

-  RUSSIAN_KOI8_RU,      // 28: CP21866 aka KOI8_RU, used for Ukrainian

-  MSFT_CP1250,          // 29: CP1250 aka MSFT eastern european

-  ISO_8859_15,          // 30: aka ISO_8859_0 aka ISO_8859_1 euroized

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

-

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

-  // These are in BasisTech but not in Teragram. They are

-  // needed for new interface languages. Now detected by

-  // research langid

-  MSFT_CP1254,          // 31: used for Turkish

-  MSFT_CP1257,          // 32: used in Baltic countries

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

-

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

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

-  // New encodings detected by Teragram

-  ISO_8859_11,          // 33: aka TIS-620, used for Thai

-  MSFT_CP874,           // 34: used for Thai

-  MSFT_CP1256,          // 35: used for Arabic

-

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

-  // Detected as ISO_8859_8 by Teragram, but can be found in META tags

-  MSFT_CP1255,          // 36: Logical Hebrew Microsoft

-  ISO_8859_8_I,         // 37: Iso Hebrew Logical

-  HEBREW_VISUAL,        // 38: Iso Hebrew Visual

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

-

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

-  // Detected by research langid

-  CZECH_CP852,          // 39

-  CZECH_CSN_369103,     // 40: aka ISO_IR_139 aka KOI8_CS

-  MSFT_CP1253,          // 41: used for Greek

-  RUSSIAN_CP866,        // 42

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

-  HZ_ENCODING,

-  ISO2022_CN,

-  ISO2022_KR,

-

-  NUM_ENCODINGS              // Always keep this at the end. It is not a

-                             // valid Encoding enum, it is only used to

-                             // indicate the total number of Encodings.

-};

-

-const int kNumLanguages = NUM_LANGUAGES;

-const int kNumEncodings = NUM_ENCODINGS;

-

-#endif  // OMAHA_COMMON_LANG_ENC_H_

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// This file is for i18n. It contains two enums, namely Language and
+// Encoding, where Language is the linguistic convention, and Encoding
+// contains information on both language encoding and character set.
+//
+// The language and encoding are both based on Teragram's conventions,
+// except for some common ISO-8859 encodings that are not detected by
+// Teragram but might be in the future.
+//
+// This file also includes functions that do mappings among
+// Language/Encoding enums, language/encoding string names (typically
+// the output from Language Encoding identifier), and language codes
+// (iso 639), and two-letter country codes (iso 3166)
+//
+// NOTE: Both Language and Encoding enums should always start from
+// zero value. This assumption has been made and used.
+
+#ifndef  OMAHA_COMMON_LANG_ENC_H_
+#define  OMAHA_COMMON_LANG_ENC_H_
+
+#include "omaha/common/commontypes.h"
+
+// some of the popular encoding aliases
+#define LATIN1     ISO_8859_1
+#define LATIN2     ISO_8859_2
+#define LATIN3     ISO_8859_3
+#define LATIN4     ISO_8859_4
+#define CYRILLIC   ISO_8859_5
+#define ARABIC_ENCODING  ISO_8859_6     // avoiding the same name as language
+#define GREEK_ENCODING   ISO_8859_7     // avoiding the same name as language
+#define HEBREW_ENCODING  ISO_8859_8     // avoiding the same name as language
+#define LATIN5     ISO_8859_9
+#define LATIN6     ISO_8859_10
+#define KOREAN_HANGUL  KOREAN_EUC_KR
+
+// NOTE: Only add new languages to the end of this list (but before
+// NUM_LANGUAGES).
+enum Language {
+  ENGLISH = 0,  /* 0 */
+  DANISH,       /* 1 */
+  DUTCH,        /* 2 */
+  FINNISH,      /* 3 */
+  FRENCH,       /* 4 */
+  GERMAN,       /* 5 */
+  HEBREW,       /* 6 */
+  ITALIAN,      /* 7 */
+  JAPANESE,     /* 8 */
+  KOREAN,       /* 9 */
+  NORWEGIAN,    /* 10 */
+  POLISH,       /* 11 */
+  PORTUGUESE,   /* 12 */
+  RUSSIAN,      /* 13 */
+  SPANISH,      /* 14 */
+  SWEDISH,      /* 15 */
+  CHINESE,      /* 16 */
+  CZECH,        /* 17 */
+  GREEK,        /* 18 */
+  ICELANDIC,    /* 19 */
+  LATVIAN,      /* 20 */
+  LITHUANIAN,   /* 21 */
+  ROMANIAN,     /* 22 */
+  HUNGARIAN,    /* 23 */
+  ESTONIAN,     /* 24 */
+  TG_UNKNOWN_LANGUAGE,  /* 25 */
+  UNKNOWN_LANGUAGE,     /* 26 */
+  BULGARIAN,    /* 27 */
+  CROATIAN,     /* 28 */
+  SERBIAN,      /* 29 */
+  IRISH,        /* 30 */
+  GALICIAN,     /* 31 */
+  TAGALOG,      /* 32 */
+  TURKISH,      /* 33 */
+  UKRAINIAN,    /* 34 */
+  HINDI,        /* 35 */
+  MACEDONIAN,   /* 36 */
+  BENGALI,      /* 37 */
+  INDONESIAN,   /* 38 */
+  LATIN,        /* 39 */
+  MALAY,        /* 40 */
+  MALAYALAM,    /* 41 */
+  WELSH,        /* 42 */
+  NEPALI,       /* 43 */
+  TELUGU,       /* 44 */
+  ALBANIAN,     /* 45 */
+  TAMIL,        /* 46 */
+  BELARUSIAN,   /* 47 */
+  JAVANESE,     /* 48 */
+  OCCITAN,      /* 49 */
+  URDU,         /* 50 */
+  BIHARI,       /* 51 */
+  GUJARATI,     /* 52 */
+  THAI,         /* 53 */
+  ARABIC,       /* 54 */
+  CATALAN,      /* 55 */
+  ESPERANTO,    /* 56 */
+  BASQUE,       /* 57 */
+  INTERLINGUA,  /* 58 */
+  KANNADA,      /* 59 */
+  PUNJABI,      /* 60 */
+  SCOTS_GAELIC, /* 61 */
+  SWAHILI,      /* 62 */
+  SLOVENIAN,    /* 63 */
+  MARATHI,      /* 64 */
+  MALTESE,      /* 65 */
+  VIETNAMESE,   /* 66 */
+  FRISIAN,      /* 67 */
+  SLOVAK,       /* 68 */
+  CHINESE_T,    /* 69 */      // This is added to solve the problem of
+                              // distinguishing Traditional and Simplified
+                              // Chinese when the encoding is UTF8.
+  FAROESE,      /* 70 */
+  SUNDANESE,    /* 71 */
+  UZBEK,        /* 72 */
+  AMHARIC,      /* 73 */
+  AZERBAIJANI,  /* 74 */
+  GEORGIAN,     /* 75 */
+  TIGRINYA,     /* 76 */
+  PERSIAN,      /* 77 */
+  BOSNIAN,      /* 78 */
+  SINHALESE,    /* 79 */
+  NORWEGIAN_N,  /* 80 */
+  PORTUGUESE_P, /* 81 */
+  PORTUGUESE_B, /* 82 */
+  XHOSA,        /* 83 */
+  ZULU,         /* 84 */
+  GUARANI,      /* 85 */
+  SESOTHO,      /* 86 */
+  TURKMEN,      /* 87 */
+  KYRGYZ,       /* 88 */
+  BRETON,       /* 89 */
+  TWI,          /* 90 */
+  YIDDISH,      /* 91 */
+  ORIYA,        /* 92 */
+  SERBO_CROATIAN,       /* 93 */
+  SOMALI,       /* 94 */
+  UIGHUR,       /* 95 */
+  KURDISH,      /* 96 */
+  MONGOLIAN,    /* 97 */
+  ARMENIAN,     /* 98 */
+  LAOTHIAN,     /* 99 */
+  SINDHI,       /* 100! */
+  RHAETO_ROMANCE,  /* 101 */
+  CHINESE_JAPANESE_KOREAN,  /* 103 */  // Not really a language
+  PSEUDOTRANSLATION,  /* 104 */  // Not really a language
+  NUM_LANGUAGES,              // Always keep this at the end. It is not a
+                              // valid Language enum, it is only used to
+                              // indicate the total number of Languages.
+};
+
+
+// Language codes for those languages we support, used to map to IDs from
+// the Language enumeration.  We could have used the Rfc1766ToLcid from the
+// Win32 system's mlang.dll to map these to LCIDs, but a) we don't want to
+// have to load mlang.dll and b) we are using our own language IDs.
+const TCHAR* const kLangCodeChinesePrc = _T("zh_cn");
+const TCHAR* const kLangCodeChineseTaiwan = _T("zh_tw");
+const TCHAR* const kLangCodeCjk = _T("cjk");
+const TCHAR* const kLangCodeDutch = _T("nl");
+const TCHAR* const kLangCodeEnglish = _T("en");
+const TCHAR* const kLangCodeFrench = _T("fr");
+const TCHAR* const kLangCodeGerman = _T("de");
+const TCHAR* const kLangCodeItalian = _T("it");
+const TCHAR* const kLangCodeJapanese = _T("ja");
+const TCHAR* const kLangCodeKorean = _T("ko");
+const TCHAR* const kLangCodePseudo = _T("x");
+const TCHAR* const kLangCodeSpanish = _T("es");
+
+
+// Maps language codes to languages.  Terminated by a { NULL, UNKNOWN_LANGUAGE }
+// item.
+struct CodeToLanguage {
+  const TCHAR* code;
+  Language language;
+};
+
+SELECTANY CodeToLanguage codes_to_languages[] = {
+  { kLangCodeChinesePrc, CHINESE },
+  { kLangCodeChineseTaiwan, CHINESE_T },
+  { kLangCodeCjk, CHINESE_JAPANESE_KOREAN },
+  { kLangCodeDutch, DUTCH },
+  { kLangCodeEnglish, ENGLISH },
+  { kLangCodeFrench, FRENCH },
+  { kLangCodeGerman, GERMAN },
+  { kLangCodeItalian, ITALIAN },
+  { kLangCodeJapanese, JAPANESE },
+  { kLangCodeKorean, KOREAN },
+  { kLangCodePseudo, PSEUDOTRANSLATION },
+  { kLangCodeSpanish, SPANISH },
+  { NULL, UNKNOWN_LANGUAGE }
+};
+
+
+
+// Macro to wrap the notion of "unknown language".
+#define IS_LANGUAGE_UNKNOWN(l)  \
+  ((l) == TG_UNKNOWN_LANGUAGE || (l) == UNKNOWN_LANGUAGE)
+
+// NOTE: Only add new encodings to the end of this list (but before
+// NUM_ENCODINGS).
+// NOTE: If you add an encoding here, you must also modify basistech_encoding()
+// and google2/com/google/i18n/Encoding.java
+enum Encoding {
+  ISO_8859_1 = 0,       // 0: Teragram ASCII
+  ISO_8859_2,           // 1: Teragram Latin2
+  ISO_8859_3,           // 2: in BasisTech but not in Teragram
+  ISO_8859_4,           // 3: Teragram Latin4
+  ISO_8859_5,           // 4: Teragram ISO-8859-5
+  ISO_8859_6,           // 5: Teragram Arabic
+  ISO_8859_7,           // 6: Teragram Greek
+  ISO_8859_8,           // 7: Teragram Hebrew
+  ISO_8859_9,           // 8: in BasisTech but not in Teragram
+  ISO_8859_10,          // 9: in BasisTech but not in Teragram
+  JAPANESE_EUC_JP,      // 10: Teragram EUC_JP
+  JAPANESE_SHIFT_JIS,   // 11: Teragram SJS
+  JAPANESE_JIS,         // 12: Teragram JIS
+  CHINESE_BIG5,         // 13: Teragram BIG5
+  CHINESE_GB,           // 14: Teragram GB
+  CHINESE_EUC_CN,       // 15: Teragram EUC-CN
+  KOREAN_EUC_KR,        // 16: Teragram KSC
+  UNICODE_ENCODING,     // 17: Teragram Unicode, changed to UNICODE_ENCODING
+                        //     from UNICODE, which is predefined by WINDOW
+  CHINESE_EUC_DEC,      // 18: Teragram EUC
+  CHINESE_CNS,          // 19: Teragram CNS
+  CHINESE_BIG5_CP950,   // 20: Teragram BIG5_CP950
+  JAPANESE_CP932,       // 21: Teragram CP932
+  UTF8,                 // 22
+  UNKNOWN_ENCODING,     // 23
+  ASCII_7BIT,           // 24: ISO_8859_1 with all characters <= 127.
+                        //     Should be present only in the crawler
+                        //     and in the repository,
+                        //     *never* as a result of Document::encoding().
+  RUSSIAN_KOI8_R,       // 25: Teragram KOI8R
+  RUSSIAN_CP1251,       // 26: Teragram CP1251
+
+  //----------------------------------------------------------
+  // These are _not_ output from teragram. Instead, they are as
+  // detected in the headers of usenet articles.
+  MSFT_CP1252,          // 27: CP1252 aka MSFT euro ascii
+  RUSSIAN_KOI8_RU,      // 28: CP21866 aka KOI8_RU, used for Ukrainian
+  MSFT_CP1250,          // 29: CP1250 aka MSFT eastern european
+  ISO_8859_15,          // 30: aka ISO_8859_0 aka ISO_8859_1 euroized
+  //----------------------------------------------------------
+
+  //----------------------------------------------------------
+  // These are in BasisTech but not in Teragram. They are
+  // needed for new interface languages. Now detected by
+  // research langid
+  MSFT_CP1254,          // 31: used for Turkish
+  MSFT_CP1257,          // 32: used in Baltic countries
+  //----------------------------------------------------------
+
+  //----------------------------------------------------------
+  //----------------------------------------------------------
+  // New encodings detected by Teragram
+  ISO_8859_11,          // 33: aka TIS-620, used for Thai
+  MSFT_CP874,           // 34: used for Thai
+  MSFT_CP1256,          // 35: used for Arabic
+
+  //----------------------------------------------------------
+  // Detected as ISO_8859_8 by Teragram, but can be found in META tags
+  MSFT_CP1255,          // 36: Logical Hebrew Microsoft
+  ISO_8859_8_I,         // 37: Iso Hebrew Logical
+  HEBREW_VISUAL,        // 38: Iso Hebrew Visual
+  //----------------------------------------------------------
+
+  //----------------------------------------------------------
+  // Detected by research langid
+  CZECH_CP852,          // 39
+  CZECH_CSN_369103,     // 40: aka ISO_IR_139 aka KOI8_CS
+  MSFT_CP1253,          // 41: used for Greek
+  RUSSIAN_CP866,        // 42
+  //----------------------------------------------------------
+  HZ_ENCODING,
+  ISO2022_CN,
+  ISO2022_KR,
+
+  NUM_ENCODINGS              // Always keep this at the end. It is not a
+                             // valid Encoding enum, it is only used to
+                             // indicate the total number of Encodings.
+};
+
+const int kNumLanguages = NUM_LANGUAGES;
+const int kNumEncodings = NUM_ENCODINGS;
+
+#endif  // OMAHA_COMMON_LANG_ENC_H_
diff --git a/common/localization.cc b/common/localization.cc
index b4fde52..4a14058 100644
--- a/common/localization.cc
+++ b/common/localization.cc
@@ -1,336 +1,336 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// localization.cpp

-//

-// Localization functions for date-time, strings, locales, and numbers

-

-#include "omaha/common/localization.h"

-

-#include <windows.h>  // SetThreadLocale

-#include <mlang.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-// The maximum length for a date

-#define kDateLengthMax 200

-

-// The maximum length for chracter seperators

-#define kDecimalSeparatorMaxLen 5

-

-// Allow the unittest to override.

-static LCID lcid_override = MAKELCID(-1, -1);

-

-void SetLcidOverride(const LCID & lcid_new) {

-  lcid_override = lcid_new;

-}

-

-// We should call this, it allows for our override

-LCID GetLiveLcid() {

-  if (lcid_override != MAKELCID(-1, -1))

-    return lcid_override;

-

-  return GetUserDefaultLCID();

-}

-

-

-CString ShowDateInternal(const time64 & t, const LCID & lcid,

-                         // Either type needs to be 0 or format needs to be

-                         // NULL; both cannot be set simultaneously:

-                         const DWORD type, const TCHAR * format ) {

-  SYSTEMTIME time = Time64ToLocalTime(t);

-  TCHAR buf[kDateLengthMax] = {_T('\0')};

-  int num = ::GetDateFormat(lcid, type, &time, format, buf, kDateLengthMax);

-  ASSERT(num > 0, (_T("[localization::ShowDateInternal] - GetDateFormat ")

-                   _T("failed")));

-

-  return CString(buf);

-}

-

-CString ShowDateForLocale(const time64 & t, const LCID & lcid) {

-  return ShowDateInternal(t, lcid, DATE_SHORTDATE, NULL);

-}

-

-CString ShowFormattedDateForLocale(const time64 & t, const LCID & lcid,

-                                   const TCHAR * format) {

-  return ShowDateInternal(t, lcid, 0, format);

-}

-

-

-CString ShowTimeInternal(const time64 & t, const LCID & lcid,

-                         // Either type needs to be 0 or format needs to be

-                         // NULL; both cannot be set simultaneously:

-                         const DWORD type, const TCHAR * format) {

-  ASSERT(IsValidTime(t), (_T("[localization::ShowTimeInternal - Invalid ")

-                          _T("time %llu"), t));

-

-  SYSTEMTIME time = Time64ToLocalTime(t);

-  TCHAR buf[kDateLengthMax] = {_T('\0')};

-  int num = ::GetTimeFormat(lcid, type, &time, format, buf, kDateLengthMax);

-  ASSERT(num > 0, (_T("[localization::ShowTimeInternal - GetTimeFormat ")

-                   _T("failed")));

-

-  return CString(buf);

-}

-

-CString ShowTimeForLocale(const time64 & t, const LCID & lcid) {

-  return ShowTimeInternal(t, lcid, TIME_NOSECONDS, NULL);

-}

-

-CString ShowFormattedTimeForLocale(const time64 & t, const LCID & lcid,

-                                   const TCHAR * format) {

-  return ShowTimeInternal(t, lcid, 0, format);

-}

-

-// Show the long date and time [ie - Tuesday, March 20, 2004 5:15pm]

-CString ShowDateTimeForLocale(const time64 & t, const LCID & lcid) {

-  return ShowDateForLocale(t, lcid) + _T(" ") + ShowTimeForLocale(t, lcid);

-}

-

-// Get the long data and time in a (US English) format for logging

-CString ShowDateTimeForLogging(const time64 & t) {

-  if (t == 0) {

-     return CString();

-  }

-  const LCID lcid = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);

-  return ShowDateTimeForLocale(t, lcid);

-}

-

-// Convert a number in string format to formatted string

-static CString Show(const CString & in, const int decimal_places) {

-  NUMBERFMT nf = {0};

-  TCHAR decimal_seperator[8] = {_T('\0')};

-  TCHAR thousands_seperator[8] = {_T('\0')};

-  GetNumberFormatForLCID(GetLiveLcid(), &nf,

-                         decimal_seperator, arraysize(decimal_seperator),

-                         thousands_seperator, arraysize(thousands_seperator));

-  nf.NumDigits = decimal_places;

-

-  TCHAR buf[kDateLengthMax] = {_T('\0')};

-  int num = GetNumberFormat(GetLiveLcid(),  // locale (current user locale)

-    0,                                      // options

-    in,                                     // input string (see MSDN for chars)

-    &nf,                                    // formatting information

-    buf,                                    // formatted string buffer

-    kDateLengthMax);                        // size of buffer

-

-  ASSERT(num > 0, (_T("GetNumberFormat failed: %s?"), in.GetString()));

-

-  return CString(buf);

-}

-

-// If we have a formatted number containing a decimal, and we want it to be

-// an int

-CString TrimDecimal(const CString & in) {

-  // Get the decimal seperator -- cache it as this is very slow

-  static LCID last_user_default_lcid = MAKELCID(-1, -1);

-  static TCHAR buf[kDecimalSeparatorMaxLen] = {_T('\0')};

-

-  LCID current_lcid = GetLiveLcid();

-  if (last_user_default_lcid != current_lcid) {

-    int num = GetLocaleInfo(GetLiveLcid(),

-                            LOCALE_SDECIMAL,

-                            buf,

-                            kDecimalSeparatorMaxLen);

-    ASSERT(num > 0, (L"GetLocaleInfo(.., LOCALE_SDECIMAL, ..) failed?"));

-    last_user_default_lcid = current_lcid;

-  }

-

-  CString sep(buf);

-

-  // Trim it if necessary

-  int pos = String_FindString(in, sep);

-  if (pos != -1)

-    return in.Left(pos);

-

-  return in;

-}

-

-// Number Functions

-// Changes the number into a user viewable format for the current locale

-

-// TODO(omaha): Rename these functions into ShowNumberForLocale.

-CString Show(const int i) {

-  return TrimDecimal(Show(itostr(i), 0));

-}

-

-CString Show(const uint32 u) {

-  return TrimDecimal(Show(itostr(u), 0));

-}

-

-CString Show(const double & d, const int decimal_places) {

-  return Show(String_DoubleToString(d, decimal_places), decimal_places);

-}

-

-HRESULT SetLocaleToRfc1766(const TCHAR * rfc1766_locale) {

-  ASSERT1(rfc1766_locale != NULL);

-

-  // Convert the RFC 1766 locale (eg, "fr-CA" for Canadian French to a

-  // Windows LCID (eg, 0x0c0c for Canadian French)

-  CComPtr<IMultiLanguage2> pIM;

-  RET_IF_FAILED(pIM.CoCreateInstance(__uuidof(CMultiLanguage)));

-

-  LCID lcid = 0;

-  CComBSTR rfc1766_locale_bstr(rfc1766_locale);

-  RET_IF_FAILED(pIM->GetLcidFromRfc1766(&lcid, (BSTR)rfc1766_locale_bstr));

-

-  return SetLocaleToLCID(lcid);

-}

-

-HRESULT SetLocaleToLCID(const LCID & lcid) {

-  // Initialize the locales

-  //   (in an attempt to cut down on our memory footprint, don't call

-  //    the libc version of setlocale)

-  if (!::SetThreadLocale(lcid)) {

-    UTIL_LOG(LEVEL_ERROR, (_T("Unable to SetThreadLocale to lcid 0x%x"),

-                           lcid));

-    return E_FAIL;

-  }

-

-  return S_OK;

-}

-

-HRESULT GetLocaleAsLCID(LCID * lcid) {

-  ASSERT1(lcid != NULL);

-

-  *lcid = GetThreadLocale();

-  return S_OK;

-}

-

-HRESULT GetLocaleAsRfc1766(CString * rfc1766_locale) {

-  ASSERT1(rfc1766_locale != NULL);

-

-  LCID lcid = 0;

-  HRESULT hr = GetLocaleAsLCID(&lcid);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CComPtr<IMultiLanguage2> pIM;

-  RET_IF_FAILED(pIM.CoCreateInstance(__uuidof(CMultiLanguage)));

-

-  CComBSTR bstr;

-  RET_IF_FAILED(pIM->GetRfc1766FromLcid(lcid, &bstr));

-

-  *rfc1766_locale = bstr;

-  return hr;

-}

-

-HRESULT GetNumberFormatForLCID(const LCID & lcid, NUMBERFMT * fmt,

-                               TCHAR * fmt_decimal_buf,

-                               size_t decimal_buf_len,  // including null char

-                               TCHAR * fmt_thousand_buf,

-                               size_t thousand_buf_len) {  // including null

-  ASSERT1(fmt);

-

-  TCHAR buf[64] = {_T('\0')};

-  size_t buf_len = arraysize(buf);

-

-  HRESULT hr = S_OK;

-  int retval = GetLocaleInfo(lcid, LOCALE_IDIGITS, buf, buf_len);

-

-  if (!retval) {

-    CORE_LOG(LEVEL_WARNING, (_T("[localization::GetNumberFormatForLCID - ")

-                             _T("Failed to load LOCALE_IDIGITS]")));

-    hr = E_FAIL;

-  } else {

-    fmt->NumDigits = String_StringToInt(buf);

-  }

-

-  retval = GetLocaleInfo(lcid, LOCALE_ILZERO, buf, buf_len);

-  if (!retval) {

-    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")

-                             _T("Failed to load LOCALE_ILZERO]")));

-    hr = E_FAIL;

-  } else {

-    fmt->LeadingZero = String_StringToInt(buf);

-  }

-

-  retval = GetLocaleInfo(lcid, LOCALE_INEGNUMBER, buf, buf_len);

-  if (!retval) {

-    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")

-                             _T("Failed to load LOCALE_INEGNUMBER]")));

-    hr = E_FAIL;

-  } else {

-    fmt->NegativeOrder = String_StringToInt(buf);

-  }

-

-  retval = GetLocaleInfo(lcid, LOCALE_SGROUPING, buf, buf_len);

-  if (!retval) {

-    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")

-                             _T("Failed to load LOCALE_SGROUPING]")));

-    hr = E_FAIL;

-  } else {

-    // A string terminated in ';0' is equivalent to the substring without

-    // the ';0', so just truncate the ';0' from the string

-    int semicolon_idx = String_ReverseFindChar(buf, _T(';'));

-    if (retval > semicolon_idx && buf[semicolon_idx + 1] == _T('0')) {

-      buf[semicolon_idx] = _T('\0');

-    }

-

-    if (String_FindChar(buf, _T(';')) != -1) {

-      // NUMBERFMT only allows values 0-9 or 32 for number grouping.  If

-      // this locale has variable-length grouping rules (as indicated by

-      // the presence of ';[1-9]'), pass in the only variable-length

-      // grouping rule NUMBERFMT understands: 32.  Note that '3;0' is

-      // considered a fixed-length grouping rule and handled above.

-      // This is a HACK.

-      fmt->Grouping = 32;

-    } else {

-      fmt->Grouping = String_StringToInt(buf);

-    }

-  }

-

-  // GetLocaleInfo doesn't write more than 4 chars for this field (per MSDN)

-  retval = GetLocaleInfo(lcid, LOCALE_SDECIMAL, fmt_decimal_buf,

-                         decimal_buf_len);

-  if (!retval) {

-    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")

-                             _T("Failed to load LOCALE_SDECIMAL]")));

-    hr = E_FAIL;

-  } else {

-    fmt->lpDecimalSep = fmt_decimal_buf;

-  }

-

-  // GetLocaleInfo doesn't write more than 4 chars for this field (per MSDN)

-  retval = GetLocaleInfo(lcid, LOCALE_STHOUSAND, fmt_thousand_buf,

-                         thousand_buf_len);

-  if (!retval) {

-    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")

-                             _T("Failed to load LOCALE_STHOUSAND]")));

-    hr = E_FAIL;

-  } else {

-    fmt->lpThousandSep = fmt_thousand_buf;

-  }

-

-  retval = GetLocaleInfo(lcid, LOCALE_INEGNUMBER, buf, buf_len);

-  if (!retval) {

-    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")

-                             _T("Failed to load LOCALE_INEGNUMBER]")));

-    hr = E_FAIL;

-  } else {

-    fmt->NegativeOrder = String_StringToInt(buf);

-  }

-

-  return hr;

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// localization.cpp
+//
+// Localization functions for date-time, strings, locales, and numbers
+
+#include "omaha/common/localization.h"
+
+#include <windows.h>  // SetThreadLocale
+#include <mlang.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+// The maximum length for a date
+#define kDateLengthMax 200
+
+// The maximum length for chracter seperators
+#define kDecimalSeparatorMaxLen 5
+
+// Allow the unittest to override.
+static LCID lcid_override = MAKELCID(-1, -1);
+
+void SetLcidOverride(const LCID & lcid_new) {
+  lcid_override = lcid_new;
+}
+
+// We should call this, it allows for our override
+LCID GetLiveLcid() {
+  if (lcid_override != MAKELCID(-1, -1))
+    return lcid_override;
+
+  return GetUserDefaultLCID();
+}
+
+
+CString ShowDateInternal(const time64 & t, const LCID & lcid,
+                         // Either type needs to be 0 or format needs to be
+                         // NULL; both cannot be set simultaneously:
+                         const DWORD type, const TCHAR * format ) {
+  SYSTEMTIME time = Time64ToLocalTime(t);
+  TCHAR buf[kDateLengthMax] = {_T('\0')};
+  int num = ::GetDateFormat(lcid, type, &time, format, buf, kDateLengthMax);
+  ASSERT(num > 0, (_T("[localization::ShowDateInternal] - GetDateFormat ")
+                   _T("failed")));
+
+  return CString(buf);
+}
+
+CString ShowDateForLocale(const time64 & t, const LCID & lcid) {
+  return ShowDateInternal(t, lcid, DATE_SHORTDATE, NULL);
+}
+
+CString ShowFormattedDateForLocale(const time64 & t, const LCID & lcid,
+                                   const TCHAR * format) {
+  return ShowDateInternal(t, lcid, 0, format);
+}
+
+
+CString ShowTimeInternal(const time64 & t, const LCID & lcid,
+                         // Either type needs to be 0 or format needs to be
+                         // NULL; both cannot be set simultaneously:
+                         const DWORD type, const TCHAR * format) {
+  ASSERT(IsValidTime(t), (_T("[localization::ShowTimeInternal - Invalid ")
+                          _T("time %llu"), t));
+
+  SYSTEMTIME time = Time64ToLocalTime(t);
+  TCHAR buf[kDateLengthMax] = {_T('\0')};
+  int num = ::GetTimeFormat(lcid, type, &time, format, buf, kDateLengthMax);
+  ASSERT(num > 0, (_T("[localization::ShowTimeInternal - GetTimeFormat ")
+                   _T("failed")));
+
+  return CString(buf);
+}
+
+CString ShowTimeForLocale(const time64 & t, const LCID & lcid) {
+  return ShowTimeInternal(t, lcid, TIME_NOSECONDS, NULL);
+}
+
+CString ShowFormattedTimeForLocale(const time64 & t, const LCID & lcid,
+                                   const TCHAR * format) {
+  return ShowTimeInternal(t, lcid, 0, format);
+}
+
+// Show the long date and time [ie - Tuesday, March 20, 2004 5:15pm]
+CString ShowDateTimeForLocale(const time64 & t, const LCID & lcid) {
+  return ShowDateForLocale(t, lcid) + _T(" ") + ShowTimeForLocale(t, lcid);
+}
+
+// Get the long data and time in a (US English) format for logging
+CString ShowDateTimeForLogging(const time64 & t) {
+  if (t == 0) {
+     return CString();
+  }
+  const LCID lcid = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
+  return ShowDateTimeForLocale(t, lcid);
+}
+
+// Convert a number in string format to formatted string
+static CString Show(const CString & in, const int decimal_places) {
+  NUMBERFMT nf = {0};
+  TCHAR decimal_seperator[8] = {_T('\0')};
+  TCHAR thousands_seperator[8] = {_T('\0')};
+  GetNumberFormatForLCID(GetLiveLcid(), &nf,
+                         decimal_seperator, arraysize(decimal_seperator),
+                         thousands_seperator, arraysize(thousands_seperator));
+  nf.NumDigits = decimal_places;
+
+  TCHAR buf[kDateLengthMax] = {_T('\0')};
+  int num = GetNumberFormat(GetLiveLcid(),  // locale (current user locale)
+    0,                                      // options
+    in,                                     // input string (see MSDN for chars)
+    &nf,                                    // formatting information
+    buf,                                    // formatted string buffer
+    kDateLengthMax);                        // size of buffer
+
+  ASSERT(num > 0, (_T("GetNumberFormat failed: %s?"), in.GetString()));
+
+  return CString(buf);
+}
+
+// If we have a formatted number containing a decimal, and we want it to be
+// an int
+CString TrimDecimal(const CString & in) {
+  // Get the decimal seperator -- cache it as this is very slow
+  static LCID last_user_default_lcid = MAKELCID(-1, -1);
+  static TCHAR buf[kDecimalSeparatorMaxLen] = {_T('\0')};
+
+  LCID current_lcid = GetLiveLcid();
+  if (last_user_default_lcid != current_lcid) {
+    int num = GetLocaleInfo(GetLiveLcid(),
+                            LOCALE_SDECIMAL,
+                            buf,
+                            kDecimalSeparatorMaxLen);
+    ASSERT(num > 0, (L"GetLocaleInfo(.., LOCALE_SDECIMAL, ..) failed?"));
+    last_user_default_lcid = current_lcid;
+  }
+
+  CString sep(buf);
+
+  // Trim it if necessary
+  int pos = String_FindString(in, sep);
+  if (pos != -1)
+    return in.Left(pos);
+
+  return in;
+}
+
+// Number Functions
+// Changes the number into a user viewable format for the current locale
+
+// TODO(omaha): Rename these functions into ShowNumberForLocale.
+CString Show(const int i) {
+  return TrimDecimal(Show(itostr(i), 0));
+}
+
+CString Show(const uint32 u) {
+  return TrimDecimal(Show(itostr(u), 0));
+}
+
+CString Show(const double & d, const int decimal_places) {
+  return Show(String_DoubleToString(d, decimal_places), decimal_places);
+}
+
+HRESULT SetLocaleToRfc1766(const TCHAR * rfc1766_locale) {
+  ASSERT1(rfc1766_locale != NULL);
+
+  // Convert the RFC 1766 locale (eg, "fr-CA" for Canadian French to a
+  // Windows LCID (eg, 0x0c0c for Canadian French)
+  CComPtr<IMultiLanguage2> pIM;
+  RET_IF_FAILED(pIM.CoCreateInstance(__uuidof(CMultiLanguage)));
+
+  LCID lcid = 0;
+  CComBSTR rfc1766_locale_bstr(rfc1766_locale);
+  RET_IF_FAILED(pIM->GetLcidFromRfc1766(&lcid, (BSTR)rfc1766_locale_bstr));
+
+  return SetLocaleToLCID(lcid);
+}
+
+HRESULT SetLocaleToLCID(const LCID & lcid) {
+  // Initialize the locales
+  //   (in an attempt to cut down on our memory footprint, don't call
+  //    the libc version of setlocale)
+  if (!::SetThreadLocale(lcid)) {
+    UTIL_LOG(LEVEL_ERROR, (_T("Unable to SetThreadLocale to lcid 0x%x"),
+                           lcid));
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+HRESULT GetLocaleAsLCID(LCID * lcid) {
+  ASSERT1(lcid != NULL);
+
+  *lcid = GetThreadLocale();
+  return S_OK;
+}
+
+HRESULT GetLocaleAsRfc1766(CString * rfc1766_locale) {
+  ASSERT1(rfc1766_locale != NULL);
+
+  LCID lcid = 0;
+  HRESULT hr = GetLocaleAsLCID(&lcid);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CComPtr<IMultiLanguage2> pIM;
+  RET_IF_FAILED(pIM.CoCreateInstance(__uuidof(CMultiLanguage)));
+
+  CComBSTR bstr;
+  RET_IF_FAILED(pIM->GetRfc1766FromLcid(lcid, &bstr));
+
+  *rfc1766_locale = bstr;
+  return hr;
+}
+
+HRESULT GetNumberFormatForLCID(const LCID & lcid, NUMBERFMT * fmt,
+                               TCHAR * fmt_decimal_buf,
+                               size_t decimal_buf_len,  // including null char
+                               TCHAR * fmt_thousand_buf,
+                               size_t thousand_buf_len) {  // including null
+  ASSERT1(fmt);
+
+  TCHAR buf[64] = {_T('\0')};
+  size_t buf_len = arraysize(buf);
+
+  HRESULT hr = S_OK;
+  int retval = GetLocaleInfo(lcid, LOCALE_IDIGITS, buf, buf_len);
+
+  if (!retval) {
+    CORE_LOG(LEVEL_WARNING, (_T("[localization::GetNumberFormatForLCID - ")
+                             _T("Failed to load LOCALE_IDIGITS]")));
+    hr = E_FAIL;
+  } else {
+    fmt->NumDigits = String_StringToInt(buf);
+  }
+
+  retval = GetLocaleInfo(lcid, LOCALE_ILZERO, buf, buf_len);
+  if (!retval) {
+    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")
+                             _T("Failed to load LOCALE_ILZERO]")));
+    hr = E_FAIL;
+  } else {
+    fmt->LeadingZero = String_StringToInt(buf);
+  }
+
+  retval = GetLocaleInfo(lcid, LOCALE_INEGNUMBER, buf, buf_len);
+  if (!retval) {
+    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")
+                             _T("Failed to load LOCALE_INEGNUMBER]")));
+    hr = E_FAIL;
+  } else {
+    fmt->NegativeOrder = String_StringToInt(buf);
+  }
+
+  retval = GetLocaleInfo(lcid, LOCALE_SGROUPING, buf, buf_len);
+  if (!retval) {
+    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")
+                             _T("Failed to load LOCALE_SGROUPING]")));
+    hr = E_FAIL;
+  } else {
+    // A string terminated in ';0' is equivalent to the substring without
+    // the ';0', so just truncate the ';0' from the string
+    int semicolon_idx = String_ReverseFindChar(buf, _T(';'));
+    if (retval > semicolon_idx && buf[semicolon_idx + 1] == _T('0')) {
+      buf[semicolon_idx] = _T('\0');
+    }
+
+    if (String_FindChar(buf, _T(';')) != -1) {
+      // NUMBERFMT only allows values 0-9 or 32 for number grouping.  If
+      // this locale has variable-length grouping rules (as indicated by
+      // the presence of ';[1-9]'), pass in the only variable-length
+      // grouping rule NUMBERFMT understands: 32.  Note that '3;0' is
+      // considered a fixed-length grouping rule and handled above.
+      // This is a HACK.
+      fmt->Grouping = 32;
+    } else {
+      fmt->Grouping = String_StringToInt(buf);
+    }
+  }
+
+  // GetLocaleInfo doesn't write more than 4 chars for this field (per MSDN)
+  retval = GetLocaleInfo(lcid, LOCALE_SDECIMAL, fmt_decimal_buf,
+                         decimal_buf_len);
+  if (!retval) {
+    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")
+                             _T("Failed to load LOCALE_SDECIMAL]")));
+    hr = E_FAIL;
+  } else {
+    fmt->lpDecimalSep = fmt_decimal_buf;
+  }
+
+  // GetLocaleInfo doesn't write more than 4 chars for this field (per MSDN)
+  retval = GetLocaleInfo(lcid, LOCALE_STHOUSAND, fmt_thousand_buf,
+                         thousand_buf_len);
+  if (!retval) {
+    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")
+                             _T("Failed to load LOCALE_STHOUSAND]")));
+    hr = E_FAIL;
+  } else {
+    fmt->lpThousandSep = fmt_thousand_buf;
+  }
+
+  retval = GetLocaleInfo(lcid, LOCALE_INEGNUMBER, buf, buf_len);
+  if (!retval) {
+    CORE_LOG(LEVEL_WARNING, (_T("[App::Impl::InitializeLocaleSettings - ")
+                             _T("Failed to load LOCALE_INEGNUMBER]")));
+    hr = E_FAIL;
+  } else {
+    fmt->NegativeOrder = String_StringToInt(buf);
+  }
+
+  return hr;
+}
+
+}  // namespace omaha
+
diff --git a/common/localization.h b/common/localization.h
index 78a296b..c710d72 100644
--- a/common/localization.h
+++ b/common/localization.h
@@ -1,94 +1,94 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-//

-// localization.h

-//

-// Localization functions for date-time, strings, locales, and numbers

-

-#ifndef OMAHA_COMMON_LOCALIZATION_H__

-#define OMAHA_COMMON_LOCALIZATION_H__

-

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "omaha/common/commontypes.h"

-

-namespace omaha {

-

-// Allows us to override LCIDs for unittests

-void SetLcidOverride(const LCID & lcid_new);

-

-

-//

-// Date-time Functions

-//

-

-// Show the time in the specified locale's default format.

-// If you want to use the user's default format, use LOCALE_USER_DEFAULT

-// for the locale [eg - "5:15:34 pm" is the US default]

-CString ShowDateForLocale(const time64 & t, const LCID & lcid);

-

-// Show the time in the specified format for the specified locale.

-// If you want to use the user's default format, use LOCALE_USER_DEFAULT

-// for the locale [eg - "5:15:34 pm" is the US default]

-CString ShowFormattedDateForLocale(const time64 & t, const LCID & lcid,

-                                   const TCHAR * format);

-

-

-// Show the time in the specified locale's default format.

-// If you want to use the user's default format, use LOCALE_USER_DEFAULT

-// for the locale [eg - "5:15:34 pm" is the US default]

-CString ShowTimeForLocale(const time64 & t, const LCID & lcid);

-

-// Show the time in the specified format for the specified locale.

-// If you want to use the user's default format, use LOCALE_USER_DEFAULT

-// for the locale [eg - "5:15:34 pm" is the US default]

-CString ShowFormattedTimeForLocale(const time64 & t, const LCID & lcid,

-                                   const TCHAR * format);

-

-// Show the long date and time [ie - Tuesday, March 20, 2004 5:15pm]

-CString ShowDateTimeForLocale(const time64 & t, const LCID & lcid);

-

-// Get the long data and time in a (US English) format for logging

-CString ShowDateTimeForLogging(const time64 & t);

-

-//

-// Number Functions

-//

-

-// Changes the number into a user viewable format for the current locale

-CString Show(const int i);

-CString Show(const uint32 u);

-CString Show(const double & d, const int decimal_places);

-

-

-//

-// Locale Name / LCID / RFC 1766 conversions

-//

-HRESULT SetLocaleToRfc1766(const TCHAR * rfc1766_locale);

-HRESULT SetLocaleToLCID(const LCID & lcid);

-

-HRESULT GetLocaleAsLCID(LCID * lcid);

-HRESULT GetLocaleAsRfc1766(CString * rfc1766_locale);

-

-HRESULT GetNumberFormatForLCID(const LCID & lcid, NUMBERFMT * fmt,

-                               TCHAR * fmt_decimal_buf,

-                               size_t decimal_buf_len,

-                               TCHAR * fmt_thousand_buf,

-                               size_t thousand_buf_len);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_LOCALIZATION_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+//
+// localization.h
+//
+// Localization functions for date-time, strings, locales, and numbers
+
+#ifndef OMAHA_COMMON_LOCALIZATION_H__
+#define OMAHA_COMMON_LOCALIZATION_H__
+
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "omaha/common/commontypes.h"
+
+namespace omaha {
+
+// Allows us to override LCIDs for unittests
+void SetLcidOverride(const LCID & lcid_new);
+
+
+//
+// Date-time Functions
+//
+
+// Show the time in the specified locale's default format.
+// If you want to use the user's default format, use LOCALE_USER_DEFAULT
+// for the locale [eg - "5:15:34 pm" is the US default]
+CString ShowDateForLocale(const time64 & t, const LCID & lcid);
+
+// Show the time in the specified format for the specified locale.
+// If you want to use the user's default format, use LOCALE_USER_DEFAULT
+// for the locale [eg - "5:15:34 pm" is the US default]
+CString ShowFormattedDateForLocale(const time64 & t, const LCID & lcid,
+                                   const TCHAR * format);
+
+
+// Show the time in the specified locale's default format.
+// If you want to use the user's default format, use LOCALE_USER_DEFAULT
+// for the locale [eg - "5:15:34 pm" is the US default]
+CString ShowTimeForLocale(const time64 & t, const LCID & lcid);
+
+// Show the time in the specified format for the specified locale.
+// If you want to use the user's default format, use LOCALE_USER_DEFAULT
+// for the locale [eg - "5:15:34 pm" is the US default]
+CString ShowFormattedTimeForLocale(const time64 & t, const LCID & lcid,
+                                   const TCHAR * format);
+
+// Show the long date and time [ie - Tuesday, March 20, 2004 5:15pm]
+CString ShowDateTimeForLocale(const time64 & t, const LCID & lcid);
+
+// Get the long data and time in a (US English) format for logging
+CString ShowDateTimeForLogging(const time64 & t);
+
+//
+// Number Functions
+//
+
+// Changes the number into a user viewable format for the current locale
+CString Show(const int i);
+CString Show(const uint32 u);
+CString Show(const double & d, const int decimal_places);
+
+
+//
+// Locale Name / LCID / RFC 1766 conversions
+//
+HRESULT SetLocaleToRfc1766(const TCHAR * rfc1766_locale);
+HRESULT SetLocaleToLCID(const LCID & lcid);
+
+HRESULT GetLocaleAsLCID(LCID * lcid);
+HRESULT GetLocaleAsRfc1766(CString * rfc1766_locale);
+
+HRESULT GetNumberFormatForLCID(const LCID & lcid, NUMBERFMT * fmt,
+                               TCHAR * fmt_decimal_buf,
+                               size_t decimal_buf_len,
+                               TCHAR * fmt_thousand_buf,
+                               size_t thousand_buf_len);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_LOCALIZATION_H__
diff --git a/common/localization_unittest.cc b/common/localization_unittest.cc
index 4d0f98a..2fcc7f4 100644
--- a/common/localization_unittest.cc
+++ b/common/localization_unittest.cc
@@ -1,158 +1,158 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// localization_unittest.cpp

-//

-// Unit test functions for Localization

-

-#include "omaha/common/localization.h"

-#include "omaha/common/string.h"

-#include "omaha/common/time.h"

-#include "omaha/testing/unit_test.h"

-

-using testing::Message;

-

-namespace omaha {

-

-// Test out the time display functions

-void LocalizationTimeTest() {

-  CString time_str;

-

-  // Lets process this a bit to give ourselves a known time.

-  SYSTEMTIME temp_time;

-  temp_time.wYear = 2004;

-  temp_time.wMonth = 4;

-  temp_time.wDayOfWeek = 1;

-  temp_time.wDay = 19;

-  temp_time.wHour = 19;

-  temp_time.wMinute = 18;

-  temp_time.wSecond = 17;

-  temp_time.wMilliseconds = 16;

-

-  time64 override_time = SystemTimeToTime64(&temp_time);

-

-  // Useful when debugging to confirm that this worked

-  SYSTEMTIME confirm = Time64ToSystemTime(override_time);

-

-  // the need to check two different times below is because:

-

-  // FileTimeToLocalFileTime uses the current settings for the time

-  // zone and daylight saving time. Therefore, if it is daylight

-  // saving time, this function will take daylight saving time into

-  // account, even if the time you are converting is in standard

-  // time.

-  // TODO(omaha): we may want to fix this.

-

-  // Show just the time [ie -12:19pm]

-  time_str = ShowTimeForLocale(override_time, 1033 /* US english */);

-  ASSERT_TRUE(time_str == _T("12:18 PM") || time_str == _T("11:18 AM"))

-      << _T("Returned time string was ") << time_str.GetString();

-

-  // Show just the time [ie - 12:19:18pm]

-  time_str = ShowFormattedTimeForLocale(override_time, 1033,

-                                        _T("hh:mm:ss tt"));

-  ASSERT_TRUE(time_str == _T("12:18:17 PM") || time_str == _T("11:18:17 AM"))

-      << _T("Returned time string was ") << time_str.GetString();

-

-  // Try it out with a some different values to test out single digit

-  // minutes and such

-  temp_time.wHour = 15;

-  temp_time.wMinute = 4;

-  temp_time.wSecond = 3;

-  temp_time.wMilliseconds = 2;

-  override_time = SystemTimeToTime64(&temp_time);

-

-  time_str = ShowTimeForLocale(override_time, 1033);

-  ASSERT_TRUE(time_str == _T("8:04 AM") || time_str == _T("7:04 AM"))

-      << _T("Returned time string was ") << time_str.GetString();

-

-  time_str = ShowFormattedTimeForLocale(override_time, 1033,

-                                        _T("hh:mm:ss tt"));

-  ASSERT_TRUE(time_str == _T("08:04:03 AM") || time_str == _T("07:04:03 AM"))

-      << _T("Returned time string was ") << time_str.GetString();

-

-

-  //

-  // Check the date functionality

-  //

-

-  temp_time.wYear = 2004;

-  temp_time.wMonth = 4;

-  temp_time.wDayOfWeek = 1;

-  temp_time.wDay = 19;

-

-  // Show the short date

-  time_str = ShowDateForLocale(override_time, 1033);

-//  CHKM(time_str == _T("Monday, April 19, 2004"),

-  ASSERT_STREQ(time_str, _T("4/19/2004"));

-

-  // Show the customized date

-  time_str = ShowFormattedDateForLocale(override_time, 1033,

-                                        _T("MMM d, yyyy"));

-  ASSERT_STREQ(time_str, _T("Apr 19, 2004"));

-

-  // Try it out with a some different values to test out single dates and such

-  temp_time.wDay = 1;

-  override_time = SystemTimeToTime64(&temp_time);

-

-  time_str = ShowFormattedDateForLocale(override_time, 1033,

-                                        _T("ddd, MMM dd"));

-  ASSERT_STREQ(time_str, _T("Thu, Apr 01"));

-

-  time_str = ShowFormattedDateForLocale(override_time, 1033, _T("MM/dd/yyyy"));

-  ASSERT_STREQ(time_str, _T("04/01/2004"));

-}

-

-// Test out the numbers and display functions

-void LocalizationNumberTest() {

-  // Make sure we are using the normal american version

-  SetLcidOverride(1033);  // the codepage for american english

-

-  // Try some basics

-  ASSERT_STREQ(Show(1), _T("1"));

-  ASSERT_STREQ(Show(2), _T("2"));

-

-  // Try some extremes

-  ASSERT_STREQ(Show(0), _T("0"));

-  ASSERT_STREQ(Show(kInt32Max), _T("2,147,483,647"));

-  ASSERT_STREQ(Show(-kInt32Max), _T("-2,147,483,647"));

-  ASSERT_STREQ(Show(kUint32Max), _T("4,294,967,295"));

-

-  // Try some doubles

-  ASSERT_STREQ(Show(0.3, 0), _T("0"));

-  ASSERT_STREQ(Show(0.3, 1), _T("0.3"));

-  ASSERT_STREQ(Show(0.3, 2), _T("0.30"));

-  ASSERT_STREQ(Show(0.3, 5), _T("0.30000"));

-

-  // Try some with interesting rounding

-  ASSERT_STREQ(Show(0.159, 0), _T("0"));

-  ASSERT_STREQ(Show(0.159, 1), _T("0.1"));

-  ASSERT_STREQ(Show(0.159, 2), _T("0.15"));

-  ASSERT_STREQ(Show(0.159, 5), _T("0.15900"));

-

-  // Try a nice whole number

-  ASSERT_STREQ(Show(12.0, 0), _T("12"));

-  ASSERT_STREQ(Show(12.0, 1), _T("12.0"));

-  ASSERT_STREQ(Show(12.0, 2), _T("12.00"));

-  ASSERT_STREQ(Show(12.0, 5), _T("12.00000"));

-}

-

-TEST(LocalizationTest, Localization) {

-  LocalizationTimeTest();

-  LocalizationNumberTest();

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// localization_unittest.cpp
+//
+// Unit test functions for Localization
+
+#include "omaha/common/localization.h"
+#include "omaha/common/string.h"
+#include "omaha/common/time.h"
+#include "omaha/testing/unit_test.h"
+
+using testing::Message;
+
+namespace omaha {
+
+// Test out the time display functions
+void LocalizationTimeTest() {
+  CString time_str;
+
+  // Lets process this a bit to give ourselves a known time.
+  SYSTEMTIME temp_time;
+  temp_time.wYear = 2004;
+  temp_time.wMonth = 4;
+  temp_time.wDayOfWeek = 1;
+  temp_time.wDay = 19;
+  temp_time.wHour = 19;
+  temp_time.wMinute = 18;
+  temp_time.wSecond = 17;
+  temp_time.wMilliseconds = 16;
+
+  time64 override_time = SystemTimeToTime64(&temp_time);
+
+  // Useful when debugging to confirm that this worked
+  SYSTEMTIME confirm = Time64ToSystemTime(override_time);
+
+  // the need to check two different times below is because:
+
+  // FileTimeToLocalFileTime uses the current settings for the time
+  // zone and daylight saving time. Therefore, if it is daylight
+  // saving time, this function will take daylight saving time into
+  // account, even if the time you are converting is in standard
+  // time.
+  // TODO(omaha): we may want to fix this.
+
+  // Show just the time [ie -12:19pm]
+  time_str = ShowTimeForLocale(override_time, 1033 /* US english */);
+  ASSERT_TRUE(time_str == _T("12:18 PM") || time_str == _T("11:18 AM"))
+      << _T("Returned time string was ") << time_str.GetString();
+
+  // Show just the time [ie - 12:19:18pm]
+  time_str = ShowFormattedTimeForLocale(override_time, 1033,
+                                        _T("hh:mm:ss tt"));
+  ASSERT_TRUE(time_str == _T("12:18:17 PM") || time_str == _T("11:18:17 AM"))
+      << _T("Returned time string was ") << time_str.GetString();
+
+  // Try it out with a some different values to test out single digit
+  // minutes and such
+  temp_time.wHour = 15;
+  temp_time.wMinute = 4;
+  temp_time.wSecond = 3;
+  temp_time.wMilliseconds = 2;
+  override_time = SystemTimeToTime64(&temp_time);
+
+  time_str = ShowTimeForLocale(override_time, 1033);
+  ASSERT_TRUE(time_str == _T("8:04 AM") || time_str == _T("7:04 AM"))
+      << _T("Returned time string was ") << time_str.GetString();
+
+  time_str = ShowFormattedTimeForLocale(override_time, 1033,
+                                        _T("hh:mm:ss tt"));
+  ASSERT_TRUE(time_str == _T("08:04:03 AM") || time_str == _T("07:04:03 AM"))
+      << _T("Returned time string was ") << time_str.GetString();
+
+
+  //
+  // Check the date functionality
+  //
+
+  temp_time.wYear = 2004;
+  temp_time.wMonth = 4;
+  temp_time.wDayOfWeek = 1;
+  temp_time.wDay = 19;
+
+  // Show the short date
+  time_str = ShowDateForLocale(override_time, 1033);
+//  CHKM(time_str == _T("Monday, April 19, 2004"),
+  ASSERT_STREQ(time_str, _T("4/19/2004"));
+
+  // Show the customized date
+  time_str = ShowFormattedDateForLocale(override_time, 1033,
+                                        _T("MMM d, yyyy"));
+  ASSERT_STREQ(time_str, _T("Apr 19, 2004"));
+
+  // Try it out with a some different values to test out single dates and such
+  temp_time.wDay = 1;
+  override_time = SystemTimeToTime64(&temp_time);
+
+  time_str = ShowFormattedDateForLocale(override_time, 1033,
+                                        _T("ddd, MMM dd"));
+  ASSERT_STREQ(time_str, _T("Thu, Apr 01"));
+
+  time_str = ShowFormattedDateForLocale(override_time, 1033, _T("MM/dd/yyyy"));
+  ASSERT_STREQ(time_str, _T("04/01/2004"));
+}
+
+// Test out the numbers and display functions
+void LocalizationNumberTest() {
+  // Make sure we are using the normal american version
+  SetLcidOverride(1033);  // the codepage for american english
+
+  // Try some basics
+  ASSERT_STREQ(Show(1), _T("1"));
+  ASSERT_STREQ(Show(2), _T("2"));
+
+  // Try some extremes
+  ASSERT_STREQ(Show(0), _T("0"));
+  ASSERT_STREQ(Show(kInt32Max), _T("2,147,483,647"));
+  ASSERT_STREQ(Show(-kInt32Max), _T("-2,147,483,647"));
+  ASSERT_STREQ(Show(kUint32Max), _T("4,294,967,295"));
+
+  // Try some doubles
+  ASSERT_STREQ(Show(0.3, 0), _T("0"));
+  ASSERT_STREQ(Show(0.3, 1), _T("0.3"));
+  ASSERT_STREQ(Show(0.3, 2), _T("0.30"));
+  ASSERT_STREQ(Show(0.3, 5), _T("0.30000"));
+
+  // Try some with interesting rounding
+  ASSERT_STREQ(Show(0.159, 0), _T("0"));
+  ASSERT_STREQ(Show(0.159, 1), _T("0.1"));
+  ASSERT_STREQ(Show(0.159, 2), _T("0.15"));
+  ASSERT_STREQ(Show(0.159, 5), _T("0.15900"));
+
+  // Try a nice whole number
+  ASSERT_STREQ(Show(12.0, 0), _T("12"));
+  ASSERT_STREQ(Show(12.0, 1), _T("12.0"));
+  ASSERT_STREQ(Show(12.0, 2), _T("12.00"));
+  ASSERT_STREQ(Show(12.0, 5), _T("12.00000"));
+}
+
+TEST(LocalizationTest, Localization) {
+  LocalizationTimeTest();
+  LocalizationNumberTest();
+}
+
+}  // namespace omaha
+
diff --git a/common/lock_ptr.h b/common/lock_ptr.h
index 22eea17..da29f1d 100644
--- a/common/lock_ptr.h
+++ b/common/lock_ptr.h
@@ -1,128 +1,128 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// lock_ptr.h

-//

-// A smart pointer to manage synchronized access to a shared resource.

-//

-// LockPtr provides a simple and concise syntax for accessing a

-// shared resource. The LockPtr is a smart pointer and provides

-// pointer operators -> and *. LockPtr does not have copy semantics and it is

-// not intended to be stored in containers. Instead, instances of LockPtr are

-// usually unamed or short-lived named variables.

-//

-// LockPtr uses an external lock, it acquires the lock in the constructor, and

-// it guarantees the lock is released in the destructor.

-//

-// Since different types of locks have different method names, such as

-// Enter/Exit or Lock/Unlock, etc, LockPtr uses an external customizable policy

-// to bind to different operations. The external policy is a set of template

-// functions that can be specialized for different types of locks, if needed.

-// Think of this policy as an adapter between the lock type and the LockPtr.

-//

-// Usage: let's assume that we have the type below:

-//

-// class X {

-//  public:

-//    X() : i_(0) {}

-//    void f() {}

-//

-//  private:

-//    int i_;

-//

-//    friend int LockPtrTest(int, int);

-// };

-//

-// We have an instance of this type and an external lock instance to serialize

-// the access to the X instance.

-//

-// Using LockPtr, the code is:

-//

-//    X x;

-//    LLock local_lock;

-//

-//    LockPtr<X>(x, local_lock)->f();

-//

-// For more example, please see the unit test of the module.

-

-

-

-#ifndef OMAHA_COMMON_LOCK_PTR_H_

-#define OMAHA_COMMON_LOCK_PTR_H_

-

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-template <typename T>

-class LockPtr {

- public:

-  template <typename U>

-  LockPtr(T& obj, U& lock)

-      : pobj_(&obj),

-        plock_(&lock),

-        punlock_method_(&LockPtr::Unlock<U>) {

-    AcquireLock(lock);

-  }

-

-  ~LockPtr() {

-    ASSERT1(punlock_method_);

-    (this->*punlock_method_)();

-  }

-

-  // Pointer behavior

-  T& operator*() {

-    ASSERT1(pobj_);

-    return *pobj_;

-  }

-

-  T* operator->() {

-    return pobj_;

-  }

-

- private:

-  // template method to restore the type of the lock and to call the

-  // release policy for the lock

-  template <class U>

-  void Unlock() {

-    ASSERT1(plock_);

-    U& lock = *(static_cast<U*>(plock_));

-    ReleaseLock(lock);

-  }

-

-  T* pobj_;       // managed shared object

-  void* plock_;   // type-less lock to control access to pobj_

-

-  void (LockPtr::*punlock_method_)();   // the address of the method to Unlock

-

-  DISALLOW_EVIL_CONSTRUCTORS(LockPtr);

-};

-

-// template functions to define the policy of acquiring and releasing

-// the locks.

-template <class Lock> inline void AcquireLock(Lock& lock) { lock.Lock(); }

-template <class Lock> inline void ReleaseLock(Lock& lock) { lock.Unlock(); }

-

-// specialization of policy for diferent types of locks.

-#include "omaha/common/synchronized.h"

-template <> void inline AcquireLock(CriticalSection& cs) { cs.Enter(); }

-template <> void inline ReleaseLock(CriticalSection& cs) { cs.Exit(); }

-

-// Add more policy specializations below, if needed.

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_LOCK_PTR_H_

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// lock_ptr.h
+//
+// A smart pointer to manage synchronized access to a shared resource.
+//
+// LockPtr provides a simple and concise syntax for accessing a
+// shared resource. The LockPtr is a smart pointer and provides
+// pointer operators -> and *. LockPtr does not have copy semantics and it is
+// not intended to be stored in containers. Instead, instances of LockPtr are
+// usually unamed or short-lived named variables.
+//
+// LockPtr uses an external lock, it acquires the lock in the constructor, and
+// it guarantees the lock is released in the destructor.
+//
+// Since different types of locks have different method names, such as
+// Enter/Exit or Lock/Unlock, etc, LockPtr uses an external customizable policy
+// to bind to different operations. The external policy is a set of template
+// functions that can be specialized for different types of locks, if needed.
+// Think of this policy as an adapter between the lock type and the LockPtr.
+//
+// Usage: let's assume that we have the type below:
+//
+// class X {
+//  public:
+//    X() : i_(0) {}
+//    void f() {}
+//
+//  private:
+//    int i_;
+//
+//    friend int LockPtrTest(int, int);
+// };
+//
+// We have an instance of this type and an external lock instance to serialize
+// the access to the X instance.
+//
+// Using LockPtr, the code is:
+//
+//    X x;
+//    LLock local_lock;
+//
+//    LockPtr<X>(x, local_lock)->f();
+//
+// For more example, please see the unit test of the module.
+
+
+
+#ifndef OMAHA_COMMON_LOCK_PTR_H_
+#define OMAHA_COMMON_LOCK_PTR_H_
+
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+template <typename T>
+class LockPtr {
+ public:
+  template <typename U>
+  LockPtr(T& obj, U& lock)
+      : pobj_(&obj),
+        plock_(&lock),
+        punlock_method_(&LockPtr::Unlock<U>) {
+    AcquireLock(lock);
+  }
+
+  ~LockPtr() {
+    ASSERT1(punlock_method_);
+    (this->*punlock_method_)();
+  }
+
+  // Pointer behavior
+  T& operator*() {
+    ASSERT1(pobj_);
+    return *pobj_;
+  }
+
+  T* operator->() {
+    return pobj_;
+  }
+
+ private:
+  // template method to restore the type of the lock and to call the
+  // release policy for the lock
+  template <class U>
+  void Unlock() {
+    ASSERT1(plock_);
+    U& lock = *(static_cast<U*>(plock_));
+    ReleaseLock(lock);
+  }
+
+  T* pobj_;       // managed shared object
+  void* plock_;   // type-less lock to control access to pobj_
+
+  void (LockPtr::*punlock_method_)();   // the address of the method to Unlock
+
+  DISALLOW_EVIL_CONSTRUCTORS(LockPtr);
+};
+
+// template functions to define the policy of acquiring and releasing
+// the locks.
+template <class Lock> inline void AcquireLock(Lock& lock) { lock.Lock(); }
+template <class Lock> inline void ReleaseLock(Lock& lock) { lock.Unlock(); }
+
+// specialization of policy for diferent types of locks.
+#include "omaha/common/synchronized.h"
+template <> void inline AcquireLock(CriticalSection& cs) { cs.Enter(); }
+template <> void inline ReleaseLock(CriticalSection& cs) { cs.Exit(); }
+
+// Add more policy specializations below, if needed.
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_LOCK_PTR_H_
+
diff --git a/common/lock_ptr_unittest.cc b/common/lock_ptr_unittest.cc
index 6ffb5ec..4a363f7 100644
--- a/common/lock_ptr_unittest.cc
+++ b/common/lock_ptr_unittest.cc
@@ -1,98 +1,98 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// lock_ptr_unittest.cpp

-

-#include "omaha/common/lock_ptr.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Test type.

-class X {

- public:

-  X() : i_(0) {}

-  void f() { i_ = 10; }

-

- private:

-  int i_;

-

-  friend class LockTest;

-  FRIEND_TEST(LockTest, X);

-};

-

-// A dummy lock just to test that locking and unlocking methods get called.

-class DummyLock {

- public:

-  DummyLock() : cnt_(0) {}

-

-  void FakeLock() { ++cnt_; }

-  void FakeUnlock() { --cnt_; }

-

- private:

-  int cnt_;

-

-  friend class LockTest;

-  FRIEND_TEST(LockTest, DummyLock);

-};

-

-// Specialization of the policy for the DummyLock.

-template<> void AcquireLock(DummyLock& lock) { lock.FakeLock(); }

-template<> void ReleaseLock(DummyLock& lock) { lock.FakeUnlock(); }

-

-// Empty test fixture.

-class LockTest : public testing::Test {};

-

-TEST_F(LockTest, X) {

-  // Create a few synchronization objects.

-  CriticalSection cs_lock;

-  LLock local_lock;

-  GLock global_lock;

-  ASSERT_TRUE(global_lock.Initialize(_T("test")));

-

-  // The instance to lock.

-  X x;

-

-  // Lock the instance and call a method.

-  LockPtr<X>(x, local_lock)->f();

-  ASSERT_EQ((*LockPtr<X>(x, cs_lock)).i_, 10);

-

-  // Lock the instance and access a data member.

-  LockPtr<X>(x, cs_lock)->i_ = 0;

-  ASSERT_EQ((*LockPtr<X>(x, cs_lock)).i_, 0);

-

-  // Lock the instance and call a method.

-  LockPtr<X>(x, global_lock)->f();

-  ASSERT_EQ((*LockPtr<X>(x, cs_lock)).i_, 10);

-}

-

-TEST_F(LockTest, DummyLock) {

-  DummyLock dummy_lock;

-  ASSERT_EQ(dummy_lock.cnt_, 0);

-

-  // The instance to lock.

-  X x;

-

-  {

-    LockPtr<X> p(x, dummy_lock);

-    ASSERT_EQ(dummy_lock.cnt_, 1);

-  }

-

-  ASSERT_EQ(dummy_lock.cnt_, 0);

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// lock_ptr_unittest.cpp
+
+#include "omaha/common/lock_ptr.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Test type.
+class X {
+ public:
+  X() : i_(0) {}
+  void f() { i_ = 10; }
+
+ private:
+  int i_;
+
+  friend class LockTest;
+  FRIEND_TEST(LockTest, X);
+};
+
+// A dummy lock just to test that locking and unlocking methods get called.
+class DummyLock {
+ public:
+  DummyLock() : cnt_(0) {}
+
+  void FakeLock() { ++cnt_; }
+  void FakeUnlock() { --cnt_; }
+
+ private:
+  int cnt_;
+
+  friend class LockTest;
+  FRIEND_TEST(LockTest, DummyLock);
+};
+
+// Specialization of the policy for the DummyLock.
+template<> void AcquireLock(DummyLock& lock) { lock.FakeLock(); }
+template<> void ReleaseLock(DummyLock& lock) { lock.FakeUnlock(); }
+
+// Empty test fixture.
+class LockTest : public testing::Test {};
+
+TEST_F(LockTest, X) {
+  // Create a few synchronization objects.
+  CriticalSection cs_lock;
+  LLock local_lock;
+  GLock global_lock;
+  ASSERT_TRUE(global_lock.Initialize(_T("test")));
+
+  // The instance to lock.
+  X x;
+
+  // Lock the instance and call a method.
+  LockPtr<X>(x, local_lock)->f();
+  ASSERT_EQ((*LockPtr<X>(x, cs_lock)).i_, 10);
+
+  // Lock the instance and access a data member.
+  LockPtr<X>(x, cs_lock)->i_ = 0;
+  ASSERT_EQ((*LockPtr<X>(x, cs_lock)).i_, 0);
+
+  // Lock the instance and call a method.
+  LockPtr<X>(x, global_lock)->f();
+  ASSERT_EQ((*LockPtr<X>(x, cs_lock)).i_, 10);
+}
+
+TEST_F(LockTest, DummyLock) {
+  DummyLock dummy_lock;
+  ASSERT_EQ(dummy_lock.cnt_, 0);
+
+  // The instance to lock.
+  X x;
+
+  {
+    LockPtr<X> p(x, dummy_lock);
+    ASSERT_EQ(dummy_lock.cnt_, 1);
+  }
+
+  ASSERT_EQ(dummy_lock.cnt_, 0);
+}
+
+}  // namespace omaha
+
diff --git a/common/logging.cc b/common/logging.cc
index 56591d2..3cdfcd0 100644
--- a/common/logging.cc
+++ b/common/logging.cc
@@ -1,1349 +1,1349 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Tracing and logging system.

-//

-// The log output goes to "All Users/Application Data/Google/Update/Log/".

-// The log configuration file is under

-// "%Program Files%/C:\Program Files\Google\Common\Update".

-// By default, the logging is on in debug modes and off in opt mode although in

-// opt mode only the OPT_LOG statements write to the log.

-//

-// The log is open to all the users to write to. There is a known vulnerability

-// where a DOS can be created by holding on to the logging mutex.

-//

-// In this module use of ASSERT & REPORT is banned.  This is to prevent any

-// possible recursion issues between logging (logging.h) and

-// asserting/reporting (debug.h).  Both are basement-level systems that need to

-// work when almost nothing else works and interdependencies are best avoided.

-// One unavoidable interdependency is that debugASSERT will send messages to

-// the logger via Logger::OutputMessage - which then broadcasts it to each

-// LogWriter's OutputMessage.  So these methods should be as simple as

-// possible.  (Also, unlike asserting/reporting - this module will not avoid

-// use of the heap, however the code executed from Logger::OutputMessage

-// doesn't use the heap (for all the LogWriters in this file).)

-//

-// TODO(omaha): implement the minidump handling in terms of breakpad.

-//              Log initialization if full of lazy init. Consider doing

-//              eager init of log and its registered log writers when the

-//              log is created and initialized.

-//              Reimplement in terms of smart handles and locks.

-//              Reimplement without dependency on any other compilation unit

-//               that can call assert, verify, or the log itself.

-//              Redo the history logging feature

-

-#include "omaha/common/logging.h"

-

-#include <excpt.h>  // Microsoft specific: structured exceptions.

-#include <shlobj.h>

-#include <shlwapi.h>

-#include <string.h>

-#include <atlpath.h>

-#include <atlsecurity.h>

-#include "base/basictypes.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_debug.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/string.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-// enforce ban on ASSERT/REPORT

-#undef ASSERT

-#undef REPORT

-

-#ifdef LOGGING

-

-#define kNumLockRetries (20)

-#define kLockRetryDelayMs (50)

-

-// Circular buffer to log history.

-static wchar_t history_buffer[kMaxHistoryBufferSize];

-

-// Index into the history buffer to begin writing at.

-static int history_buffer_next_idx = 0;

-

-// Indicates whether the history buffer has ever reached its full capacity.

-// Once this boolean is true, if never becomes false.

-static bool history_buffer_full = false;

-

-// If you want to log anything else, add it to this structure.  This structure

-// basically says that each logged message is composed of two parts, and they

-// are output one after the other.  Intended to be used for a message "prefix"

-// and the message itself (the prefix can contain the component name, the time,

-// and any other logging system boilerplate, while the message is supplied by

-// the component).  (This basically saves having to copy a variable length -

-// possibly very large - message just to tack it onto the end of the message

-// prefix.)

-struct OutputInfo {

-  LogCategory category;

-  LogLevel level;

-  const wchar_t* msg1;

-  const wchar_t* msg2;

-

-  OutputInfo(LogCategory cat, LogLevel log_level,

-             const wchar_t* m1, const wchar_t* m2)

-      : category(cat),

-        level(log_level),

-        msg1(m1),

-        msg2(m2) {}

-};

-

-//

-// Table of category names to categories.

-//

-#define LC_ENTRY(lc_value)  (L#lc_value), (lc_value)

-struct {

-  wchar_t* category_name;

-  LogCategory category;

-} static LogCategoryNames[] = {

-  LC_ENTRY(LC_UTIL),

-  LC_ENTRY(LC_SETUP),

-  LC_ENTRY(LC_SHELL),

-  LC_ENTRY(LC_CORE),

-  LC_ENTRY(LC_JS),

-  LC_ENTRY(LC_PLUGIN),

-  LC_ENTRY(LC_SERVICE),

-  LC_ENTRY(LC_OPT),

-  LC_ENTRY(LC_NET),

-};

-

-static CString StripBackslashes(const CString& name) {

-  int n = String_FindChar(name, L'\\');

-  if (n == -1) {

-    return name;

-  } else {

-    CString result;

-    for (int i = 0; i < name.GetLength(); ++i) {

-      if (name[i] != L'\\') {

-        result += name[i];

-      }

-    }

-    return result;

-  }

-}

-

-static CString GetProcName() {

-  CString proc_name(app_util::GetAppNameWithoutExtension());

-  CString module_name(app_util::GetCurrentModuleNameWithoutExtension());

-  CString result(proc_name);

-  if (module_name.CompareNoCase(proc_name) != 0) {

-    result += L":";

-    result += module_name;

-  }

-  return result;

-}

-

-// Formats a line prefix with the current time min:sec:milisec if wanted,

-// otherwise just the process:module.

-static void FormatLinePrefix(bool show_time,

-                             const wchar_t* proc_name,

-                             CString& result) {

-  if (show_time) {

-    SYSTEMTIME system_time = {0};

-    GetLocalTime(&system_time);

-    result.Format(L"[%02d/%02d/%02d %02d:%02d:%02d.%03d]",

-                  system_time.wMonth, system_time.wDay, system_time.wYear % 100,

-                  system_time.wHour, system_time.wMinute, system_time.wSecond,

-                  system_time.wMilliseconds);

-  }

-  result.AppendFormat(L"[%s][%u:%u]",

-                      proc_name,

-                      ::GetCurrentProcessId(),

-                      ::GetCurrentThreadId());

-}

-

-static bool g_logging_valid = false;

-static Logging g_logging;

-

-// Singleton factory for the Logging object.

-Logging* GetLogging() {

-  return g_logging_valid ? &g_logging : NULL;

-}

-

-// Force the logging system to be initialized during elaboration of static

-// constructors, while the program is still single-threaded.  This global

-// static object will cause the static logger inside of GetLogging() to be

-// constructed.  However, it might not be the first call to GetLogging() -

-// another static object in another object file might get constructed first,

-// and in its constructor call a logging API.  Just as long as it is done when

-// the system is single threaded.  (Reason: because the Logger object has a

-// LLock object which has a Win32 critical section which needs to be

-// initialized - only once!)

-

-

-Logging::Logging()

-    : logging_initialized_(false),

-      logging_enabled_(true),

-      force_show_time_(false),

-      show_time_(true),

-      log_to_file_(true),

-      log_to_debug_out_(true),

-      append_to_file_(true),

-      logging_shutdown_(false),

-      num_writers_(0),

-      file_log_writer_(NULL),

-      debug_out_writer_(NULL),

-      is_initializing_(false),

-      log_file_name_(kDefaultLogFileName),

-      config_file_path_(GetConfigurationFilePath()) {

-  g_last_category_check_time = 0;

-  for (int i = 0; i < max_writers; ++i) {

-    writers_[i] = NULL;

-  }

-  proc_name_ = GetProcName();

-  g_logging_valid = true;

-

-  // Read initial settings from the config file.

-  ReadLoggingSettings();

-}

-

-// TODO(omaha): why aren't we using a mutexscope and what if an the code

-// throws? Will the lock be unlocked?

-Logging::~Logging() {

-  // Acquire the lock outside the try/except block so we'll always release it

-  lock_.Lock();

-

-  __try {

-    // prevent further access to the system

-    // necessary because the static destructors happen

-    // in a non-deterministic order

-    logging_shutdown_ = true;

-

-    // Delete all registered LogWriters

-    for (int i = 0; i < num_writers_; ++i) {

-      if (writers_[i]) {

-        delete writers_[i];

-      }

-    }

-

-    logging_initialized_ = false;

-  } __except(SehNoMinidump(GetExceptionCode(),

-                           GetExceptionInformation(),

-                           __FILE__,

-                           __LINE__,

-                           true)) {

-    OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");

-    logging_initialized_  = false;

-  }

-

-  g_logging_valid = false;

-  lock_.Unlock();

-}

-

-void Logging::UpdateCatAndLevel(const wchar_t* cat_name, LogCategory cat) {

-  if (cat_name == NULL) {

-    return;

-  }

-  if (cat >= LC_MAX_CAT) {

-    return;

-  }

-  int log_level = kDefaultLogLevel;

-  CString config_file = GetCurrentConfigurationFilePath();

-  if (!config_file.IsEmpty()) {

-    log_level = GetPrivateProfileInt(kConfigSectionLoggingLevel,

-                                     cat_name,

-                                     kDefaultLogLevel,

-                                     config_file);

-  }

-  category_list_[cat].enabled = (log_level != 0);

-  category_list_[cat].log_level = static_cast<LogLevel>(log_level);

-}

-

-void Logging::ReadLoggingSettings() {

-  CString config_file = GetCurrentConfigurationFilePath();

-  if (!config_file.IsEmpty()) {

-    logging_enabled_ = ::GetPrivateProfileInt(

-        kConfigSectionLoggingSettings,

-        kConfigAttrEnableLogging,

-        kDefaultLoggingEnabled,

-        config_file) == 0 ? false : true;

-

-    show_time_ = ::GetPrivateProfileInt(

-        kConfigSectionLoggingSettings,

-        kConfigAttrShowTime,

-        kDefaultShowTime,

-        config_file) == 0 ? false : true;

-

-    log_to_file_ = ::GetPrivateProfileInt(

-        kConfigSectionLoggingSettings,

-        kConfigAttrLogToFile,

-        kDefaultLogToFile,

-        config_file) == 0 ? false : true;

-

-    log_to_debug_out_ = ::GetPrivateProfileInt(

-        kConfigSectionLoggingSettings,

-        kConfigAttrLogToOutputDebug,

-        kDefaultLogToOutputDebug,

-        config_file) == 0 ? false : true;

-

-    append_to_file_ = ::GetPrivateProfileInt(

-        kConfigSectionLoggingSettings,

-        kConfigAttrAppendToFile,

-        kDefaultAppendToFile,

-        config_file) == 0 ? false : true;

-

-    ::GetPrivateProfileString(kConfigSectionLoggingSettings,

-                              kConfigAttrLogFilePath,

-                              kDefaultLogFileName,

-                              CStrBuf(log_file_name_, MAX_PATH),

-                              MAX_PATH,

-                              config_file);

-  } else {

-    logging_enabled_ = kDefaultLoggingEnabled;

-    show_time_ = kDefaultShowTime;

-    log_to_file_ = kDefaultLogToFile;

-    log_to_debug_out_ = kDefaultLogToOutputDebug;

-    append_to_file_ = kDefaultAppendToFile;

-    log_file_name_ = kDefaultLogFileName;

-  }

-

-  if (force_show_time_) {

-    show_time_ = true;

-  }

-

-  // The "default" category is always enabled.

-  category_list_[LC_LOGGING].enabled = true;

-  category_list_[LC_LOGGING].log_level = LEVEL_ALL;

-

-  // Read each category from the ini file.

-  for (size_t i = 0; i < arraysize(LogCategoryNames); ++i) {

-    UpdateCatAndLevel(LogCategoryNames[i].category_name,

-                      LogCategoryNames[i].category);

-  }

-

-  g_last_category_check_time = GetCurrent100NSTime();

-}

-

-CString Logging::GetDefaultLogDirectory() const {

-  CString path;

-  CStrBuf buf(path, MAX_PATH);

-  HRESULT hr = ::SHGetFolderPath(NULL,

-                                 CSIDL_COMMON_APPDATA,

-                                 NULL,

-                                 SHGFP_TYPE_CURRENT,

-                                 buf);

-  if (FAILED(hr)) {

-    return L"";

-  }

-  if (!::PathAppend(buf, OMAHA_REL_LOG_DIR)) {

-    return L"";

-  }

-  return path;

-}

-

-CString Logging::GetLogFilePath() const {

-  if (log_file_name_.IsEmpty()) {

-    return CString();

-  }

-

-  if (!ATLPath::IsRelative(log_file_name_)) {

-    return log_file_name_;

-  }

-

-  CString path = GetDefaultLogDirectory();

-  if (path.IsEmpty()) {

-    return CString();

-  }

-

-  if (!::PathAppend(CStrBuf(path, MAX_PATH), log_file_name_)) {

-    return CString();

-  }

-

-  return path;

-}

-

-// Configures/unconfigures the log writers for the current settings.

-bool Logging::ConfigureLogging() {

-  // Create the logging file.

-  if (log_to_file_ && file_log_writer_ == NULL) {

-    CString path = GetLogFilePath();

-    if (path.IsEmpty()) {

-      return false;

-    }

-

-    // Extract the final target directory which will not be what

-    // GetDefaultLogDirectory() returns if log_file_name_ is an absolute path.

-    CString log_file_dir = GetDirectoryFromPath(path);

-    if (!File::Exists(log_file_dir)) {

-      if (FAILED(CreateDir(log_file_dir, NULL))) {

-        return false;

-      }

-    }

-    file_log_writer_ = FileLogWriter::Create(path, append_to_file_);

-    if (file_log_writer_ == NULL) {

-      OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - "

-                                L"Cannot create log writer to %s",

-                                proc_name_, path));

-    }

-  }

-  if (log_to_file_ && file_log_writer_ != NULL) {

-    InternalRegisterWriter(file_log_writer_);

-  }

-  if (log_to_debug_out_ && debug_out_writer_ == NULL) {

-    debug_out_writer_ = OutputDebugStringLogWriter::Create();

-    if (debug_out_writer_ == NULL) {

-      OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - "

-                                L"Cannot create OutputDebugString log writer",

-                                proc_name_));

-    }

-  }

-  if (log_to_debug_out_ && debug_out_writer_ != NULL) {

-    InternalRegisterWriter(debug_out_writer_);

-  }

-  return true;

-}

-

-void Logging::UnconfigureLogging() {

-  if (file_log_writer_ != NULL) {

-    InternalUnregisterWriter(file_log_writer_);

-  }

-  if (debug_out_writer_ != NULL) {

-    InternalUnregisterWriter(debug_out_writer_);

-  }

-}

-

-bool Logging::InternalInitialize() {

-  __try {

-    if (logging_shutdown_ == true) {

-      OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - "

-                                L"Calling the logging system after "

-                                L"it has been shut down \n",

-                                GetProcName()));

-      return false;

-    }

-

-    if (logging_initialized_ == true) {

-      return true;

-    }

-    // If something called by this method is attempting to do logging,

-    // just ignore it. The cost/benefit ratio is too high to do otherwise.

-    if (is_initializing_) {

-      return false;

-    }

-    is_initializing_ = true;

-

-    // Read the initial settings from the config file.

-    ReadLoggingSettings();

-

-    // Initialize logging system if enabled at start.

-    if (logging_enabled_) {

-      logging_initialized_ = ConfigureLogging();

-    }

-  } __except(SehNoMinidump(GetExceptionCode(),

-                           GetExceptionInformation(),

-                           __FILE__,

-                           __LINE__,

-                           true)) {

-    OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");

-    logging_initialized_  = false;

-    return false;

-  }

-

-  is_initializing_ = false;

-  return true;

-}

-

-bool Logging::InitializeLogging() {

-  // Double-checked locking idiom is broken, especially on multicore machines.

-  // TODO(omaha): understand how this works and fix it.

-  if (logging_shutdown_ == true) {

-    OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - Calling the logging "

-                              L"system after it has been shut down \n",

-                              GetProcName()));

-    return false;

-  }

-

-  if (logging_initialized_ == true) {

-    return true;

-  }

-

-  // Acquire the lock outside the try/except block so we'll always release it.

-  __mutexScope(lock_);

-  return InternalInitialize();

-}

-

-// Enables/disables the logging mechanism. Allows turning logging on/off

-// in mid-run.

-// TODO(omaha):  same comment as for the destructor.

-void Logging::EnableLogging() {

-  if (!InitializeLogging()) {

-    return;

-  }

-

-  // Acquire the lock outside the try/except block so we'll always release it.

-  lock_.Lock();

-

-  __try {

-    if (!logging_enabled_) {

-      ConfigureLogging();

-      logging_enabled_ = true;

-    }

-  } __except(SehNoMinidump(GetExceptionCode(),

-                           GetExceptionInformation(),

-                           __FILE__,

-                           __LINE__,

-                           true)) {

-    OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");

-    logging_enabled_  = false;

-  }

-

-  lock_.Unlock();

-}

-

-void Logging::DisableLogging() {

-  if (!InitializeLogging()) {

-    return;

-  }

-

-  // Acquire the lock outside the try/except block so we'll always release it.

-  lock_.Lock();

-

-  __try {

-    if (logging_enabled_) {

-      logging_enabled_ = false;

-      UnconfigureLogging();

-    }

-  } __except(SehNoMinidump(GetExceptionCode(),

-             GetExceptionInformation(),

-             __FILE__,

-             __LINE__,

-             true)) {

-    OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");

-    logging_enabled_  = false;

-  }

-

-  lock_.Unlock();

-}

-

-// Checks if logging is enabled - and updates logging settings from the

-// configuration file every kLogSettingsCheckInterval seconds.

-bool Logging::IsLoggingEnabled() {

-  if (!InitializeLogging()) {

-    return false;

-  }

-

-  // Dynamic update - including reading a new value of logging_enabled_.

-  bool prev_logging_enabled = logging_enabled_;

-  if (GetCurrent100NSTime() >

-      g_last_category_check_time + kLogSettingsCheckInterval) {

-    ReadLoggingSettings();

-  }

-

-  // If enabled state has changed either enable or disable logging.

-  if (prev_logging_enabled != logging_enabled_) {

-    if (logging_enabled_) {

-      EnableLogging();

-    } else {

-      DisableLogging();

-    }

-  }

-

-  return logging_enabled_;

-}

-

-bool Logging::IsLoggingAlreadyEnabled() const {

-  return logging_enabled_;

-}

-

-void Logging::ForceShowTimestamp(bool force_show_time) {

-  force_show_time_ = show_time_ = force_show_time;

-}

-

-// Get category level

-LogLevel Logging::GetCatLevel(LogCategory category) const {

-  if (!IsLoggingAlreadyEnabled()) {

-    return kDefaultLogLevel;

-  }

-

-  if (category >= LC_MAX_CAT) {

-    return kDefaultLogLevel;

-  }

-

-  return category_list_[category].log_level;

-}

-

-// Check if logging is enabled for a given category and level

-DWORD Logging::IsCatLevelEnabled(LogCategory category, LogLevel level) {

-  if (!IsLoggingEnabled()) {

-    return 0;

-  }

-

-  if (category >= LC_MAX_CAT) {

-    return 0;

-  }

-

-  // If the config value is to log: then log to all writers.

-  if (category_list_[category].enabled &&

-      level <= category_list_[category].log_level) {

-    return static_cast<DWORD>(all_writers_mask);

-  }

-

-  // Check each of the registered loggers to see if they want to override the

-  // negative config value.

-  DWORD mask = 0;

-  for (int i = num_writers_ - 1; i >= 0; --i) {

-    mask <<= 1;

-    if (writers_[i] && writers_[i]->IsCatLevelEnabled(category, level)) {

-      mask |= 1;

-    }

-  }

-

-  return mask;

-}

-

-// TODO(omaha): For now this is hard coded and there is no way to override

-// writing other log categories into the history. Add a store_in_history

-// boolean into the CategoryInfo struct that allows reading from the config

-// file. This will enable other log categories to get buffered in the history.

-bool Logging::IsCategoryEnabledForBuffering(LogCategory cat) {

-  return cat == LC_REPORT;

-}

-

-void Logging::LogMessage(LogCategory cat, LogLevel level,

-                         const wchar_t* fmt, ...) {

-  va_list args;

-  va_start(args, fmt);

-  LogMessageVA(cat, level, fmt, args);

-  va_end(args);

-}

-

-void Logging::LogMessageVA(LogCategory cat, LogLevel level,

-                           const wchar_t* fmt, va_list args) {

-  LogMessageMaskedVA(static_cast<DWORD>(all_writers_mask),

-                     cat,

-                     level,

-                     fmt,

-                     args);

-}

-

-void Logging::InternalLogMessageMaskedVA(DWORD writer_mask,

-                                         LogCategory cat,

-                                         LogLevel level,

-                                         CString* log_buffer,

-                                         CString* prefix,

-                                         const wchar_t* fmt,

-                                         va_list args) {

-  __try {

-    // Initial buffer size in characters.

-    // It will adjust dynamically if the message is bigger.

-    DWORD buffer_size = 512;

-

-    // Count of chars / bytes written.

-    int num_chars = 0;

-    bool result = false;

-

-    // Write the message in the buffer.

-    // Dynamically adjust the size to hold the entire message.

-

-    while ((num_chars = _vsnwprintf_s(

-        log_buffer->GetBufferSetLength(buffer_size),

-        buffer_size,

-        _TRUNCATE,

-        fmt,

-        args)) == -1) {

-      // Truncate if the message is too big.

-      if (buffer_size >= kMaxLogMessageSize) {

-        num_chars = buffer_size;

-        break;

-      }

-

-      // Get a buffer that is big enough.

-      buffer_size *= 2;

-    }

-

-    log_buffer->ReleaseBuffer(num_chars);

-

-    FormatLinePrefix(show_time_, proc_name_, *prefix);

-

-    // Log the message.

-    OutputInfo info(cat, level, *prefix, *log_buffer);

-    OutputMessage(writer_mask, &info);

-  } __except(SehSendMinidump(GetExceptionCode(),

-                             GetExceptionInformation(),

-                             kMinsTo100ns)) {

-    OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");

-    OutputDebugString(fmt);

-    OutputDebugString(L"\n\r");

-  }

-}

-

-void Logging::LogMessageMaskedVA(DWORD writer_mask,

-                                 LogCategory cat,

-                                 LogLevel level,

-                                 const wchar_t* fmt,

-                                 va_list args) {

-  if (!fmt) {

-    return;

-  }

-

-  if (writer_mask == 0 && level > kMaxLevelToStoreInLogHistory) {

-    return;

-  }

-

-#pragma warning(push)

-// construction of local static object is not thread-safe

-#pragma warning(disable : 4640)

-  // TODO(omaha): make these class members.

-  static CString log_buffer;    // The buffer for formatted log messages.

-  static CString prefix;

-#pragma warning(pop)

-

-  int i = 0;

-  while (++i <= kNumLockRetries) {

-    if (lock_.Lock(0)) {

-      InternalLogMessageMaskedVA(writer_mask, cat, level, &log_buffer,

-                                 &prefix, fmt, args);

-      lock_.Unlock();

-      break;

-    }

-

-    Sleep(kLockRetryDelayMs);

-  }

-

-  if (i > kNumLockRetries) {

-    OutputDebugStringA("LOG_SYSTEM: Couldn't acquire lock - ");

-    OutputDebugString(fmt);

-    OutputDebugString(L"\n\r");

-  }

-}

-

-void Logging::OutputMessage(DWORD writer_mask, LogCategory cat, LogLevel level,

-                            const wchar_t* msg1, const wchar_t* msg2) {

-  OutputInfo info(cat, level, msg1, msg2);

-  OutputMessage(writer_mask, &info);

-}

-

-// Store log message in in-memory history buffer.

-void Logging::StoreInHistory(const OutputInfo* output_info) {

-  AppendToHistory(output_info->msg1);

-  AppendToHistory(output_info->msg2);

-  AppendToHistory(L"\r\n");

-}

-

-// Append string to in-memory history buffer.

-// history_buffer_next_idx points to the next index to write at,

-// thus it should always be in (0 - kHistoryBufferEndIdx).

-void Logging::AppendToHistory(const wchar_t* msg) {

-  int msg_len = wcslen(msg);

-  if (msg_len == 0) {

-    return;

-  }

-

-  if (msg_len >= kMaxHistoryBufferSize) {

-    // Write the first kMaxHistoryBufferSize chars.

-    memcpy(history_buffer, msg, kMaxHistoryBufferSize * sizeof(TCHAR));

-    history_buffer_next_idx = 0;

-    history_buffer_full = true;

-    return;

-  }

-

-  // Determine if the message fits into the portion of the buffer after

-  // history_buffer_next_idx.

-  if (msg_len + history_buffer_next_idx < kMaxHistoryBufferSize) {

-    memcpy(history_buffer + history_buffer_next_idx, msg,

-           msg_len * sizeof(TCHAR));

-    history_buffer_next_idx += msg_len;

-    return;

-  }

-

-  // Have to split the input message into the part that fits in

-  // history_buffer_next_idx to kMaxHistoryBufferSize and the remaining message.

-  int msg_first_part_len = kMaxHistoryBufferSize - history_buffer_next_idx;

-  int msg_second_part_len = msg_len - msg_first_part_len;

-  memcpy(history_buffer + history_buffer_next_idx,

-         msg,

-         msg_first_part_len * sizeof(TCHAR));

-

-  history_buffer_full = true;

-  history_buffer_next_idx = msg_second_part_len;

-  if (msg_second_part_len) {

-    memcpy(history_buffer,

-           msg + msg_first_part_len,

-           msg_second_part_len * sizeof(TCHAR));

-  }

-}

-

-// Retrieve in-memory history buffer.

-CString Logging::GetHistory() {

-  CString history;

-

-  if (history_buffer_full) {

-    history.Append(history_buffer + history_buffer_next_idx,

-                   kMaxHistoryBufferSize - history_buffer_next_idx);

-  }

-  history.Append(history_buffer, history_buffer_next_idx);

-

-  // Reset the history buffer to the original state.

-  history_buffer_next_idx = 0;

-  history_buffer_full = false;

-  memset(history_buffer, 0, kMaxHistoryBufferSize * sizeof(TCHAR));

-

-  return history;

-}

-

-void Logging::OutputMessage(DWORD writer_mask,

-                            const OutputInfo* output_info) {

-  if (output_info->level <= kMaxLevelToStoreInLogHistory &&

-      IsCategoryEnabledForBuffering(output_info->category)) {

-    StoreInHistory(output_info);

-  }

-

-  for (int i = 0; i < num_writers_; ++i) {

-    if (writer_mask & 1) {

-      __try {

-        if (logging_enabled_ || writers_[i]->WantsToLogRegardless()) {

-          writers_[i]->OutputMessage(output_info);

-        }

-      }

-      __except(SehNoMinidump(GetExceptionCode(),

-                             GetExceptionInformation(),

-                             __FILE__,

-                             __LINE__,

-                             true)) {

-        // Just eat errors that happen from within the LogWriters.  This is

-        // important so that if such an error happens when OutputMessage is

-        // called from debugASSERT we don't go recursively into more

-        // error handling ...

-      }

-    }

-    writer_mask >>= 1;

-  }

-}

-

-bool Logging::InternalRegisterWriter(LogWriter* log_writer) {

-  if (num_writers_ >= max_writers) {

-    return false;

-  }

-  writers_[num_writers_++] = log_writer;

-  return true;

-}

-

-bool Logging::RegisterWriter(LogWriter* log_writer) {

-  if (!InternalRegisterWriter(log_writer)) {

-    return false;

-  }

-  if (log_writer->WantsToLogRegardless()) {

-    EnableLogging();

-  }

-  return true;

-}

-

-bool Logging::InternalUnregisterWriter(LogWriter* log_writer) {

-  bool result = false;

-  for (int i = 0; i < num_writers_; ++i) {

-    if (writers_[i] == log_writer) {

-      // Replace this entry with last entry in array, then truncate.

-      writers_[i] = writers_[--num_writers_];

-      result = true;

-      break;

-    }

-  }

-  return result;

-}

-

-bool Logging::UnregisterWriter(LogWriter* log_writer) {

-  if (!InternalUnregisterWriter(log_writer)) {

-    return false;

-  }

-  if (num_writers_ == 0) {

-    DisableLogging();

-  }

-  return true;

-}

-

-// The primary configuration file under %PROGRAMFILES%\Google\Update is

-// removed on uninstall. This is midly inconvenient during development

-// therefore a fallback location for the configuration file is desired.

-CString Logging::GetCurrentConfigurationFilePath() const {

-  if (!config_file_path_.IsEmpty() &&

-      File::Exists(config_file_path_)) {

-    return config_file_path_;

-  } else {

-    return L"";

-  }

-}

-

-CString Logging::GetConfigurationFilePath() const {

-  CString file_path;

-  CString system_drive = GetEnvironmentVariableAsString(_T("SystemDrive"));

-  if (!system_drive.IsEmpty()) {

-    file_path = system_drive;

-    file_path += L"\\";

-  }

-  return file_path + kFilePrefix L".ini";

-}

-

-LogWriter::LogWriter() {

-}

-

-LogWriter::~LogWriter() {

-}

-

-void LogWriter::Cleanup() {}

-

-bool LogWriter::WantsToLogRegardless() const { return false; }

-

-bool LogWriter::IsCatLevelEnabled(LogCategory, LogLevel) const {

-  return false;

-}

-

-void LogWriter::OutputMessage(const OutputInfo*) { }

-

-bool LogWriter::Register() {

-  Logging* logger = GetLogging();

-  if (logger) {

-    return logger->RegisterWriter(this);

-  } else {

-    return false;

-  }

-}

-

-bool LogWriter::Unregister() {

-  Logging* logger = GetLogging();

-  if (logger) {

-    return logger->RegisterWriter(this);

-  } else {

-    return false;

-  }

-}

-

-// FileLogWriter

-

-FileLogWriter* FileLogWriter::Create(const wchar_t* file_name, bool append) {

-  return new FileLogWriter(file_name, append);

-}

-

-FileLogWriter::FileLogWriter(const wchar_t* file_name, bool append)

-    : initialized_(false),

-      valid_(false),

-      file_name_(file_name),

-      log_file_mutex_(NULL),

-      log_file_(NULL),

-      append_(append),

-      max_file_size_(kDefaultMaxLogFileSize),

-      log_file_wide_(kDefaultLogFileWide) {

-  Logging* logger = GetLogging();

-  if (logger) {

-    CString config_file_path = logger->GetCurrentConfigurationFilePath();

-    if (!config_file_path.IsEmpty()) {

-        max_file_size_ = ::GetPrivateProfileInt(

-            kConfigSectionLoggingSettings,

-            kConfigAttrMaxLogFileSize,

-            kDefaultMaxLogFileSize,

-            config_file_path);

-        log_file_wide_ = ::GetPrivateProfileInt(

-            kConfigSectionLoggingSettings,

-            kConfigAttrLogFileWide,

-            kDefaultLogFileWide,

-            config_file_path) == 0 ? false : true;

-    } else {

-      max_file_size_ = kDefaultMaxLogFileSize;

-      log_file_wide_ = kDefaultLogFileWide;

-    }

-    proc_name_ = logger->proc_name();

-  }

-}

-

-FileLogWriter::~FileLogWriter() {

-  // TODO(omaha): Figure out a way to pass the proc_name - and possibly

-  // the show_time var - into here.

-  Logging* logger = GetLogging();

-  if (logger && logger->IsLoggingAlreadyEnabled()) {

-    // OutputInfo info(LEVEL_WARNING, NULL, kEndOfLogMessage);

-    // OutputMessage(&info);

-  }

-  Cleanup();

-}

-

-void FileLogWriter::Initialize() {

-  if (initialized_) {

-    return;

-  }

-

-  initialized_ = true;

-

-  bool already_created = CreateLoggingMutex();

-  if (!log_file_mutex_) {

-    return;

-  }

-

-  if (already_created) {

-    append_ = true;

-  }

-

-  if (!GetMutex()) {

-    ::OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: "

-                                L"Could not acquire logging mutex %s\n",

-                                proc_name_,

-                                log_file_mutex_name_));

-    return;

-  }

-

-  CreateLoggingFile();

-  if (!log_file_) {

-    ::OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: "

-                                L"Could not create logging file %s\n",

-                                proc_name_,

-                                file_name_));

-    valid_ = false;

-  }

-

-  valid_ = true;

-  ReleaseMutex();

-}

-

-void FileLogWriter::Cleanup() {

-  if (log_file_) {

-    ::CloseHandle(log_file_);

-  }

-  if (log_file_mutex_) {

-    ::ReleaseMutex(log_file_mutex_);

-    ::CloseHandle(log_file_mutex_);

-  }

-}

-

-bool FileLogWriter::CreateLoggingMutex() {

-  log_file_mutex_name_ = StripBackslashes(kLoggingMutexName L"_" + file_name_);

-  // TODO(omaha): I don't see where this class is used, but I guess the

-  // caller is always in the same context. We should use the default security

-  // here.  If the caller can be in different contexts (System Service, Usermode

-  // applications, etc), then we should revisit this code to give access only

-  // to those who really need it.  What if a malicious piece a code decide

-  // to get the mutex and lock it? If it happens, everytime you try to log

-  // something, the thread would hang for 500ms and then fail to log the

-  // message.

-  CSecurityAttributes sa;

-  GetEveryoneDaclSecurityAttributes(&sa, GENERIC_ALL);

-  log_file_mutex_ = CreateMutexWithSyncAccess(log_file_mutex_name_, &sa);

-  if (log_file_mutex_) {

-    return ERROR_ALREADY_EXISTS == ::GetLastError();

-  }

-  return false;

-}

-

-bool FileLogWriter::CreateLoggingFile() {

-  uint32 file_size(0);

-  File::GetFileSizeUnopen(file_name_, &file_size);

-  if (file_size > max_file_size_) {

-    ArchiveLoggingFile();

-  }

-  log_file_ = ::CreateFile(file_name_,

-                           GENERIC_WRITE,

-                           FILE_SHARE_WRITE | FILE_SHARE_READ,

-                           NULL,

-                           append_ ? OPEN_ALWAYS : CREATE_ALWAYS,

-                           FILE_ATTRIBUTE_NORMAL,

-                           NULL);

-  if (log_file_ == INVALID_HANDLE_VALUE) {

-    // The code in this file is written with the assumption that log_file_ is

-    // NULL on creation errors. The easy fix is to set it to NULL here. The

-    // long term fix should be implementing it in terms of a smart handle.

-    log_file_ = NULL;

-    return false;

-  }

-

-  // Allow users to read, write, and delete the log file.

-  ACCESS_MASK mask = GENERIC_READ | GENERIC_WRITE | DELETE;

-  CDacl dacl;

-  if (dacl.AddAllowedAce(ATL::Sids::Users(), mask)) {

-    AtlSetDacl(file_name_, SE_FILE_OBJECT, dacl);

-  }

-

-  // Insert a BOM in the newly created file.

-  if (GetLastError() != ERROR_ALREADY_EXISTS && log_file_wide_) {

-    DWORD num = 0;

-    ::WriteFile(log_file_, &kUnicodeBom, sizeof(kUnicodeBom), &num, NULL);

-  }

-  return true;

-}

-

-bool FileLogWriter::TruncateLoggingFile() {

-  DWORD share_mode = FILE_SHARE_WRITE;

-  HANDLE log_file = ::CreateFile(file_name_,

-                                 GENERIC_WRITE,

-                                 FILE_SHARE_WRITE | FILE_SHARE_READ,

-                                 NULL,

-                                 TRUNCATE_EXISTING,

-                                 FILE_ATTRIBUTE_NORMAL,

-                                 NULL);

-  if (log_file_ == INVALID_HANDLE_VALUE) {

-    return false;

-  }

-

-  // Insert a BOM in the newly created file.

-  if (log_file_wide_) {

-    DWORD num = 0;

-    ::WriteFile(log_file, &kUnicodeBom, sizeof(kUnicodeBom), &num, NULL);

-  }

-  ::CloseHandle(log_file);

-  return true;

-}

-

-bool FileLogWriter::ArchiveLoggingFile() {

-  ::OutputDebugString(L"LOG_SYSTEM: trying to move log file to backup\n");

-  CString backup_file_name = file_name_ + L".bak";

-  HRESULT hr = File::Move(file_name_, backup_file_name, true);

-  if (FAILED(hr)) {

-    ::OutputDebugString(L"LOG_SYSTEM: failed to move log file to backup\n");

-

-    // Trying to move the log file when loggers have it open returns

-    // ERROR_SHARING_VIOLATION. Each call to MoveFileAfterReboot inserts the

-    // file into PendingFileRenames list. Moving files at reboot requires the

-    // user to be either the LocalSystem account or in the Administrators

-    // group.

-    if (!IsArchivePending()) {

-      File::MoveAfterReboot(file_name_, backup_file_name);

-    }

-    return false;

-  }

-  return true;

-}

-

-bool FileLogWriter::IsArchivePending() {

-  // We look at the PendingFileRenameOperations to see if our log file is

-  // pending a rename. The list is a REG_MULTI_SZ, which is a sequence of

-  // null-terminated strings, terminated by an empty string "\0".

-  // The strings have the structure:

-  // \??\file1\0!\??\file2\0\file3\0\0...\0\0. where file1 is to be renamed to

-  // file2 and file3 is to be deleted.

-  // It is valid for the PFR list to include an empty string in the middle

-  // of the sequence.

-  const wchar_t sub_key_name[] = L"SYSTEM\\CurrentControlSet\\Control\\"

-                                 L"Session Manager";

-  HKEY key = NULL;

-  int res = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,

-                            sub_key_name,

-                            0,

-                            KEY_READ,

-                            &key);

-  if (res != ERROR_SUCCESS) {

-    return false;

-  }

-  DWORD bytes = 0;

-  DWORD type = REG_MULTI_SZ;

-  res = ::RegQueryValueEx(key,

-                          L"PendingFileRenameOperations",

-                          0,

-                          &type,

-                          NULL,

-                          &bytes);

-  if (!(res == ERROR_SUCCESS && type == REG_MULTI_SZ)) {

-    return false;

-  }

-  scoped_array<byte> buf(new byte[bytes]);

-  memset(buf.get(), 0, bytes);

-  res = ::RegQueryValueEx(key,

-                          L"PendingFileRenameOperations",

-                          0,

-                          NULL,

-                          buf.get(),

-                          &bytes);

-  if (res != ERROR_SUCCESS) {

-    return false;

-  }

-  const wchar_t* multi_str = reinterpret_cast<const wchar_t*>(buf.get());

-  size_t count = bytes / sizeof(*multi_str);

-  const size_t kMaxRegistryValueLen = 1024 * 1024;  // 1MB

-  if (!(count >= 2 &&

-        count < kMaxRegistryValueLen &&

-        multi_str[count - 2] == L'\0' &&

-        multi_str[count - 1] == L'\0')) {

-    return false;

-  }

-  // The file names in the PFR list are prefixed by \??\.

-  CString file_name = L"\\??\\" + file_name_;

-  return FindFirstInMultiString(multi_str, count, file_name) != -1;

-}

-

-int FileLogWriter::FindFirstInMultiString(const wchar_t* multi_str,

-                                          size_t count,

-                                          const wchar_t* str) {

-  const wchar_t* p = multi_str;

-  size_t i = 0;

-  while (i < count) {

-    p =  multi_str + i;

-    if (lstrcmp(p, str) == 0) {

-      return i;

-    } else {

-      size_t len = lstrlen(p);

-      i += len + 1;

-    }

-  }

-  return -1;

-}

-

-void FileLogWriter::OutputMessage(const OutputInfo* output_info) {

-  if (!initialized_) {

-    Initialize();

-  }

-

-  if (!valid_) {

-    return;

-  }

-

-  // Acquire the mutex.

-  if (!GetMutex()) {

-    return;

-  }

-

-  // Move to end of file.

-  DWORD pos = ::SetFilePointer(log_file_, 0, NULL, FILE_END);

-  int64 stop_gap_file_size = kStopGapLogFileSizeFactor *

-                             static_cast<int64>(max_file_size_);

-  if (pos >= stop_gap_file_size) {

-    if (!TruncateLoggingFile()) {

-      // Logging stops until the log can be archived over since we do not

-      // want to overfill the disk.

-      return;

-    }

-  }

-  pos = ::SetFilePointer(log_file_, 0, NULL, FILE_END);

-

-  // Write the date, followed by a CRLF

-  DWORD written_size = 0;

-  if (output_info->msg1) {

-    if (log_file_wide_) {

-      ::WriteFile(log_file_, output_info->msg1,

-                  lstrlen(output_info->msg1) * sizeof(wchar_t), &written_size,

-                  NULL);

-    } else {

-      CStringA msg(WideToAnsiDirect(output_info->msg1));

-      ::WriteFile(log_file_, msg.GetString(), msg.GetLength(), &written_size,

-                  NULL);

-    }

-  }

-

-  if (output_info->msg2) {

-    if (log_file_wide_) {

-      ::WriteFile(log_file_, output_info->msg2,

-                  lstrlen(output_info->msg2) * sizeof(wchar_t), &written_size,

-                  NULL);

-    } else {

-      CStringA msg(WideToAnsiDirect(output_info->msg2));

-      ::WriteFile(log_file_, msg.GetString(), msg.GetLength(), &written_size,

-                  NULL);

-    }

-  }

-

-  if (log_file_wide_) {

-    ::WriteFile(log_file_, L"\r\n", 2 * sizeof(wchar_t), &written_size, NULL);

-  } else {

-    ::WriteFile(log_file_, "\r\n", 2, &written_size, NULL);

-  }

-

-  ReleaseMutex();

-}

-

-bool FileLogWriter::GetMutex() {

-  if (!log_file_mutex_) {

-    return false;

-  }

-

-  DWORD res = ::WaitForSingleObject(log_file_mutex_, kMaxMutexWaitTimeMs);

-  if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {

-    ::OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: "

-                                L"Could not acquire logging mutex %s\n",

-                                proc_name_, log_file_mutex_name_));

-    valid_ = false;

-    return false;

-  }

-

-  return true;

-}

-

-void FileLogWriter::ReleaseMutex() {

-  if (log_file_mutex_) {

-    ::ReleaseMutex(log_file_mutex_);

-  }

-}

-

-// OutputDebugStringLogWriter.

-OutputDebugStringLogWriter* OutputDebugStringLogWriter::Create() {

-  return new OutputDebugStringLogWriter();

-}

-

-OutputDebugStringLogWriter::OutputDebugStringLogWriter() {}

-

-OutputDebugStringLogWriter::~OutputDebugStringLogWriter() {

-  Logging* logger = GetLogging();

-  if (logger && logger->IsLoggingAlreadyEnabled()) {

-    // OutputInfo info(LEVEL_WARNING, NULL, kEndOfLogMessage);

-    // OutputMessage(&info);

-  }

-  Cleanup();

-}

-

-void OutputDebugStringLogWriter::OutputMessage(const OutputInfo* output_info) {

-  // Combine everything into one string so that messages coming from

-  // multiple threads don't get interleaved.

-  ::OutputDebugString(SPRINTF(L"%s%s\n", output_info->msg1, output_info->msg2));

-}

-

-// OverrideConfigLogWriter.

-OverrideConfigLogWriter* OverrideConfigLogWriter::Create(LogCategory category,

-    LogLevel level, LogWriter* log_writer, bool force_logging_enabled) {

-  return new OverrideConfigLogWriter(category,

-                                     level,

-                                     log_writer,

-                                     force_logging_enabled);

-}

-

-OverrideConfigLogWriter::OverrideConfigLogWriter(LogCategory category,

-                                                 LogLevel level,

-                                                 LogWriter* log_writer,

-                                                 bool force_logging_enabled)

-    : category_(category),

-      level_(level),

-      log_writer_(log_writer),

-      force_logging_enabled_(force_logging_enabled) {}

-

-void OverrideConfigLogWriter::Cleanup() {

-  if (log_writer_) {

-    delete log_writer_;

-  }

-}

-

-bool OverrideConfigLogWriter::WantsToLogRegardless() const {

-  return force_logging_enabled_;

-}

-

-bool OverrideConfigLogWriter::IsCatLevelEnabled(LogCategory category,

-                                                LogLevel level) const {

-  if (category != category_) {

-    return false;

-  }

-  if (level > level_) {

-    return false;

-  }

-  return true;

-}

-

-void OverrideConfigLogWriter::OutputMessage(const OutputInfo* output_info) {

-  if (log_writer_) {

-    log_writer_->OutputMessage(output_info);

-  }

-  return;

-}

-

-}  // namespace omaha

-

-#endif  // LOGGING

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Tracing and logging system.
+//
+// The log output goes to "All Users/Application Data/Google/Update/Log/".
+// The log configuration file is under
+// "%Program Files%/C:\Program Files\Google\Common\Update".
+// By default, the logging is on in debug modes and off in opt mode although in
+// opt mode only the OPT_LOG statements write to the log.
+//
+// The log is open to all the users to write to. There is a known vulnerability
+// where a DOS can be created by holding on to the logging mutex.
+//
+// In this module use of ASSERT & REPORT is banned.  This is to prevent any
+// possible recursion issues between logging (logging.h) and
+// asserting/reporting (debug.h).  Both are basement-level systems that need to
+// work when almost nothing else works and interdependencies are best avoided.
+// One unavoidable interdependency is that debugASSERT will send messages to
+// the logger via Logger::OutputMessage - which then broadcasts it to each
+// LogWriter's OutputMessage.  So these methods should be as simple as
+// possible.  (Also, unlike asserting/reporting - this module will not avoid
+// use of the heap, however the code executed from Logger::OutputMessage
+// doesn't use the heap (for all the LogWriters in this file).)
+//
+// TODO(omaha): implement the minidump handling in terms of breakpad.
+//              Log initialization if full of lazy init. Consider doing
+//              eager init of log and its registered log writers when the
+//              log is created and initialized.
+//              Reimplement in terms of smart handles and locks.
+//              Reimplement without dependency on any other compilation unit
+//               that can call assert, verify, or the log itself.
+//              Redo the history logging feature
+
+#include "omaha/common/logging.h"
+
+#include <excpt.h>  // Microsoft specific: structured exceptions.
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <string.h>
+#include <atlpath.h>
+#include <atlsecurity.h>
+#include "base/basictypes.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_debug.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/string.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+// enforce ban on ASSERT/REPORT
+#undef ASSERT
+#undef REPORT
+
+#ifdef LOGGING
+
+#define kNumLockRetries (20)
+#define kLockRetryDelayMs (50)
+
+// Circular buffer to log history.
+static wchar_t history_buffer[kMaxHistoryBufferSize];
+
+// Index into the history buffer to begin writing at.
+static int history_buffer_next_idx = 0;
+
+// Indicates whether the history buffer has ever reached its full capacity.
+// Once this boolean is true, if never becomes false.
+static bool history_buffer_full = false;
+
+// If you want to log anything else, add it to this structure.  This structure
+// basically says that each logged message is composed of two parts, and they
+// are output one after the other.  Intended to be used for a message "prefix"
+// and the message itself (the prefix can contain the component name, the time,
+// and any other logging system boilerplate, while the message is supplied by
+// the component).  (This basically saves having to copy a variable length -
+// possibly very large - message just to tack it onto the end of the message
+// prefix.)
+struct OutputInfo {
+  LogCategory category;
+  LogLevel level;
+  const wchar_t* msg1;
+  const wchar_t* msg2;
+
+  OutputInfo(LogCategory cat, LogLevel log_level,
+             const wchar_t* m1, const wchar_t* m2)
+      : category(cat),
+        level(log_level),
+        msg1(m1),
+        msg2(m2) {}
+};
+
+//
+// Table of category names to categories.
+//
+#define LC_ENTRY(lc_value)  (L#lc_value), (lc_value)
+struct {
+  wchar_t* category_name;
+  LogCategory category;
+} static LogCategoryNames[] = {
+  LC_ENTRY(LC_UTIL),
+  LC_ENTRY(LC_SETUP),
+  LC_ENTRY(LC_SHELL),
+  LC_ENTRY(LC_CORE),
+  LC_ENTRY(LC_JS),
+  LC_ENTRY(LC_PLUGIN),
+  LC_ENTRY(LC_SERVICE),
+  LC_ENTRY(LC_OPT),
+  LC_ENTRY(LC_NET),
+};
+
+static CString StripBackslashes(const CString& name) {
+  int n = String_FindChar(name, L'\\');
+  if (n == -1) {
+    return name;
+  } else {
+    CString result;
+    for (int i = 0; i < name.GetLength(); ++i) {
+      if (name[i] != L'\\') {
+        result += name[i];
+      }
+    }
+    return result;
+  }
+}
+
+static CString GetProcName() {
+  CString proc_name(app_util::GetAppNameWithoutExtension());
+  CString module_name(app_util::GetCurrentModuleNameWithoutExtension());
+  CString result(proc_name);
+  if (module_name.CompareNoCase(proc_name) != 0) {
+    result += L":";
+    result += module_name;
+  }
+  return result;
+}
+
+// Formats a line prefix with the current time min:sec:milisec if wanted,
+// otherwise just the process:module.
+static void FormatLinePrefix(bool show_time,
+                             const wchar_t* proc_name,
+                             CString& result) {
+  if (show_time) {
+    SYSTEMTIME system_time = {0};
+    GetLocalTime(&system_time);
+    result.Format(L"[%02d/%02d/%02d %02d:%02d:%02d.%03d]",
+                  system_time.wMonth, system_time.wDay, system_time.wYear % 100,
+                  system_time.wHour, system_time.wMinute, system_time.wSecond,
+                  system_time.wMilliseconds);
+  }
+  result.AppendFormat(L"[%s][%u:%u]",
+                      proc_name,
+                      ::GetCurrentProcessId(),
+                      ::GetCurrentThreadId());
+}
+
+static bool g_logging_valid = false;
+static Logging g_logging;
+
+// Singleton factory for the Logging object.
+Logging* GetLogging() {
+  return g_logging_valid ? &g_logging : NULL;
+}
+
+// Force the logging system to be initialized during elaboration of static
+// constructors, while the program is still single-threaded.  This global
+// static object will cause the static logger inside of GetLogging() to be
+// constructed.  However, it might not be the first call to GetLogging() -
+// another static object in another object file might get constructed first,
+// and in its constructor call a logging API.  Just as long as it is done when
+// the system is single threaded.  (Reason: because the Logger object has a
+// LLock object which has a Win32 critical section which needs to be
+// initialized - only once!)
+
+
+Logging::Logging()
+    : logging_initialized_(false),
+      logging_enabled_(true),
+      force_show_time_(false),
+      show_time_(true),
+      log_to_file_(true),
+      log_to_debug_out_(true),
+      append_to_file_(true),
+      logging_shutdown_(false),
+      num_writers_(0),
+      file_log_writer_(NULL),
+      debug_out_writer_(NULL),
+      is_initializing_(false),
+      log_file_name_(kDefaultLogFileName),
+      config_file_path_(GetConfigurationFilePath()) {
+  g_last_category_check_time = 0;
+  for (int i = 0; i < max_writers; ++i) {
+    writers_[i] = NULL;
+  }
+  proc_name_ = GetProcName();
+  g_logging_valid = true;
+
+  // Read initial settings from the config file.
+  ReadLoggingSettings();
+}
+
+// TODO(omaha): why aren't we using a mutexscope and what if an the code
+// throws? Will the lock be unlocked?
+Logging::~Logging() {
+  // Acquire the lock outside the try/except block so we'll always release it
+  lock_.Lock();
+
+  __try {
+    // prevent further access to the system
+    // necessary because the static destructors happen
+    // in a non-deterministic order
+    logging_shutdown_ = true;
+
+    // Delete all registered LogWriters
+    for (int i = 0; i < num_writers_; ++i) {
+      if (writers_[i]) {
+        delete writers_[i];
+      }
+    }
+
+    logging_initialized_ = false;
+  } __except(SehNoMinidump(GetExceptionCode(),
+                           GetExceptionInformation(),
+                           __FILE__,
+                           __LINE__,
+                           true)) {
+    OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");
+    logging_initialized_  = false;
+  }
+
+  g_logging_valid = false;
+  lock_.Unlock();
+}
+
+void Logging::UpdateCatAndLevel(const wchar_t* cat_name, LogCategory cat) {
+  if (cat_name == NULL) {
+    return;
+  }
+  if (cat >= LC_MAX_CAT) {
+    return;
+  }
+  int log_level = kDefaultLogLevel;
+  CString config_file = GetCurrentConfigurationFilePath();
+  if (!config_file.IsEmpty()) {
+    log_level = GetPrivateProfileInt(kConfigSectionLoggingLevel,
+                                     cat_name,
+                                     kDefaultLogLevel,
+                                     config_file);
+  }
+  category_list_[cat].enabled = (log_level != 0);
+  category_list_[cat].log_level = static_cast<LogLevel>(log_level);
+}
+
+void Logging::ReadLoggingSettings() {
+  CString config_file = GetCurrentConfigurationFilePath();
+  if (!config_file.IsEmpty()) {
+    logging_enabled_ = ::GetPrivateProfileInt(
+        kConfigSectionLoggingSettings,
+        kConfigAttrEnableLogging,
+        kDefaultLoggingEnabled,
+        config_file) == 0 ? false : true;
+
+    show_time_ = ::GetPrivateProfileInt(
+        kConfigSectionLoggingSettings,
+        kConfigAttrShowTime,
+        kDefaultShowTime,
+        config_file) == 0 ? false : true;
+
+    log_to_file_ = ::GetPrivateProfileInt(
+        kConfigSectionLoggingSettings,
+        kConfigAttrLogToFile,
+        kDefaultLogToFile,
+        config_file) == 0 ? false : true;
+
+    log_to_debug_out_ = ::GetPrivateProfileInt(
+        kConfigSectionLoggingSettings,
+        kConfigAttrLogToOutputDebug,
+        kDefaultLogToOutputDebug,
+        config_file) == 0 ? false : true;
+
+    append_to_file_ = ::GetPrivateProfileInt(
+        kConfigSectionLoggingSettings,
+        kConfigAttrAppendToFile,
+        kDefaultAppendToFile,
+        config_file) == 0 ? false : true;
+
+    ::GetPrivateProfileString(kConfigSectionLoggingSettings,
+                              kConfigAttrLogFilePath,
+                              kDefaultLogFileName,
+                              CStrBuf(log_file_name_, MAX_PATH),
+                              MAX_PATH,
+                              config_file);
+  } else {
+    logging_enabled_ = kDefaultLoggingEnabled;
+    show_time_ = kDefaultShowTime;
+    log_to_file_ = kDefaultLogToFile;
+    log_to_debug_out_ = kDefaultLogToOutputDebug;
+    append_to_file_ = kDefaultAppendToFile;
+    log_file_name_ = kDefaultLogFileName;
+  }
+
+  if (force_show_time_) {
+    show_time_ = true;
+  }
+
+  // The "default" category is always enabled.
+  category_list_[LC_LOGGING].enabled = true;
+  category_list_[LC_LOGGING].log_level = LEVEL_ALL;
+
+  // Read each category from the ini file.
+  for (size_t i = 0; i < arraysize(LogCategoryNames); ++i) {
+    UpdateCatAndLevel(LogCategoryNames[i].category_name,
+                      LogCategoryNames[i].category);
+  }
+
+  g_last_category_check_time = GetCurrent100NSTime();
+}
+
+CString Logging::GetDefaultLogDirectory() const {
+  CString path;
+  CStrBuf buf(path, MAX_PATH);
+  HRESULT hr = ::SHGetFolderPath(NULL,
+                                 CSIDL_COMMON_APPDATA,
+                                 NULL,
+                                 SHGFP_TYPE_CURRENT,
+                                 buf);
+  if (FAILED(hr)) {
+    return L"";
+  }
+  if (!::PathAppend(buf, OMAHA_REL_LOG_DIR)) {
+    return L"";
+  }
+  return path;
+}
+
+CString Logging::GetLogFilePath() const {
+  if (log_file_name_.IsEmpty()) {
+    return CString();
+  }
+
+  if (!ATLPath::IsRelative(log_file_name_)) {
+    return log_file_name_;
+  }
+
+  CString path = GetDefaultLogDirectory();
+  if (path.IsEmpty()) {
+    return CString();
+  }
+
+  if (!::PathAppend(CStrBuf(path, MAX_PATH), log_file_name_)) {
+    return CString();
+  }
+
+  return path;
+}
+
+// Configures/unconfigures the log writers for the current settings.
+bool Logging::ConfigureLogging() {
+  // Create the logging file.
+  if (log_to_file_ && file_log_writer_ == NULL) {
+    CString path = GetLogFilePath();
+    if (path.IsEmpty()) {
+      return false;
+    }
+
+    // Extract the final target directory which will not be what
+    // GetDefaultLogDirectory() returns if log_file_name_ is an absolute path.
+    CString log_file_dir = GetDirectoryFromPath(path);
+    if (!File::Exists(log_file_dir)) {
+      if (FAILED(CreateDir(log_file_dir, NULL))) {
+        return false;
+      }
+    }
+    file_log_writer_ = FileLogWriter::Create(path, append_to_file_);
+    if (file_log_writer_ == NULL) {
+      OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - "
+                                L"Cannot create log writer to %s",
+                                proc_name_, path));
+    }
+  }
+  if (log_to_file_ && file_log_writer_ != NULL) {
+    InternalRegisterWriter(file_log_writer_);
+  }
+  if (log_to_debug_out_ && debug_out_writer_ == NULL) {
+    debug_out_writer_ = OutputDebugStringLogWriter::Create();
+    if (debug_out_writer_ == NULL) {
+      OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - "
+                                L"Cannot create OutputDebugString log writer",
+                                proc_name_));
+    }
+  }
+  if (log_to_debug_out_ && debug_out_writer_ != NULL) {
+    InternalRegisterWriter(debug_out_writer_);
+  }
+  return true;
+}
+
+void Logging::UnconfigureLogging() {
+  if (file_log_writer_ != NULL) {
+    InternalUnregisterWriter(file_log_writer_);
+  }
+  if (debug_out_writer_ != NULL) {
+    InternalUnregisterWriter(debug_out_writer_);
+  }
+}
+
+bool Logging::InternalInitialize() {
+  __try {
+    if (logging_shutdown_ == true) {
+      OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - "
+                                L"Calling the logging system after "
+                                L"it has been shut down \n",
+                                GetProcName()));
+      return false;
+    }
+
+    if (logging_initialized_ == true) {
+      return true;
+    }
+    // If something called by this method is attempting to do logging,
+    // just ignore it. The cost/benefit ratio is too high to do otherwise.
+    if (is_initializing_) {
+      return false;
+    }
+    is_initializing_ = true;
+
+    // Read the initial settings from the config file.
+    ReadLoggingSettings();
+
+    // Initialize logging system if enabled at start.
+    if (logging_enabled_) {
+      logging_initialized_ = ConfigureLogging();
+    }
+  } __except(SehNoMinidump(GetExceptionCode(),
+                           GetExceptionInformation(),
+                           __FILE__,
+                           __LINE__,
+                           true)) {
+    OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");
+    logging_initialized_  = false;
+    return false;
+  }
+
+  is_initializing_ = false;
+  return true;
+}
+
+bool Logging::InitializeLogging() {
+  // Double-checked locking idiom is broken, especially on multicore machines.
+  // TODO(omaha): understand how this works and fix it.
+  if (logging_shutdown_ == true) {
+    OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: ERROR - Calling the logging "
+                              L"system after it has been shut down \n",
+                              GetProcName()));
+    return false;
+  }
+
+  if (logging_initialized_ == true) {
+    return true;
+  }
+
+  // Acquire the lock outside the try/except block so we'll always release it.
+  __mutexScope(lock_);
+  return InternalInitialize();
+}
+
+// Enables/disables the logging mechanism. Allows turning logging on/off
+// in mid-run.
+// TODO(omaha):  same comment as for the destructor.
+void Logging::EnableLogging() {
+  if (!InitializeLogging()) {
+    return;
+  }
+
+  // Acquire the lock outside the try/except block so we'll always release it.
+  lock_.Lock();
+
+  __try {
+    if (!logging_enabled_) {
+      ConfigureLogging();
+      logging_enabled_ = true;
+    }
+  } __except(SehNoMinidump(GetExceptionCode(),
+                           GetExceptionInformation(),
+                           __FILE__,
+                           __LINE__,
+                           true)) {
+    OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");
+    logging_enabled_  = false;
+  }
+
+  lock_.Unlock();
+}
+
+void Logging::DisableLogging() {
+  if (!InitializeLogging()) {
+    return;
+  }
+
+  // Acquire the lock outside the try/except block so we'll always release it.
+  lock_.Lock();
+
+  __try {
+    if (logging_enabled_) {
+      logging_enabled_ = false;
+      UnconfigureLogging();
+    }
+  } __except(SehNoMinidump(GetExceptionCode(),
+             GetExceptionInformation(),
+             __FILE__,
+             __LINE__,
+             true)) {
+    OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");
+    logging_enabled_  = false;
+  }
+
+  lock_.Unlock();
+}
+
+// Checks if logging is enabled - and updates logging settings from the
+// configuration file every kLogSettingsCheckInterval seconds.
+bool Logging::IsLoggingEnabled() {
+  if (!InitializeLogging()) {
+    return false;
+  }
+
+  // Dynamic update - including reading a new value of logging_enabled_.
+  bool prev_logging_enabled = logging_enabled_;
+  if (GetCurrent100NSTime() >
+      g_last_category_check_time + kLogSettingsCheckInterval) {
+    ReadLoggingSettings();
+  }
+
+  // If enabled state has changed either enable or disable logging.
+  if (prev_logging_enabled != logging_enabled_) {
+    if (logging_enabled_) {
+      EnableLogging();
+    } else {
+      DisableLogging();
+    }
+  }
+
+  return logging_enabled_;
+}
+
+bool Logging::IsLoggingAlreadyEnabled() const {
+  return logging_enabled_;
+}
+
+void Logging::ForceShowTimestamp(bool force_show_time) {
+  force_show_time_ = show_time_ = force_show_time;
+}
+
+// Get category level
+LogLevel Logging::GetCatLevel(LogCategory category) const {
+  if (!IsLoggingAlreadyEnabled()) {
+    return kDefaultLogLevel;
+  }
+
+  if (category >= LC_MAX_CAT) {
+    return kDefaultLogLevel;
+  }
+
+  return category_list_[category].log_level;
+}
+
+// Check if logging is enabled for a given category and level
+DWORD Logging::IsCatLevelEnabled(LogCategory category, LogLevel level) {
+  if (!IsLoggingEnabled()) {
+    return 0;
+  }
+
+  if (category >= LC_MAX_CAT) {
+    return 0;
+  }
+
+  // If the config value is to log: then log to all writers.
+  if (category_list_[category].enabled &&
+      level <= category_list_[category].log_level) {
+    return static_cast<DWORD>(all_writers_mask);
+  }
+
+  // Check each of the registered loggers to see if they want to override the
+  // negative config value.
+  DWORD mask = 0;
+  for (int i = num_writers_ - 1; i >= 0; --i) {
+    mask <<= 1;
+    if (writers_[i] && writers_[i]->IsCatLevelEnabled(category, level)) {
+      mask |= 1;
+    }
+  }
+
+  return mask;
+}
+
+// TODO(omaha): For now this is hard coded and there is no way to override
+// writing other log categories into the history. Add a store_in_history
+// boolean into the CategoryInfo struct that allows reading from the config
+// file. This will enable other log categories to get buffered in the history.
+bool Logging::IsCategoryEnabledForBuffering(LogCategory cat) {
+  return cat == LC_REPORT;
+}
+
+void Logging::LogMessage(LogCategory cat, LogLevel level,
+                         const wchar_t* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  LogMessageVA(cat, level, fmt, args);
+  va_end(args);
+}
+
+void Logging::LogMessageVA(LogCategory cat, LogLevel level,
+                           const wchar_t* fmt, va_list args) {
+  LogMessageMaskedVA(static_cast<DWORD>(all_writers_mask),
+                     cat,
+                     level,
+                     fmt,
+                     args);
+}
+
+void Logging::InternalLogMessageMaskedVA(DWORD writer_mask,
+                                         LogCategory cat,
+                                         LogLevel level,
+                                         CString* log_buffer,
+                                         CString* prefix,
+                                         const wchar_t* fmt,
+                                         va_list args) {
+  __try {
+    // Initial buffer size in characters.
+    // It will adjust dynamically if the message is bigger.
+    DWORD buffer_size = 512;
+
+    // Count of chars / bytes written.
+    int num_chars = 0;
+    bool result = false;
+
+    // Write the message in the buffer.
+    // Dynamically adjust the size to hold the entire message.
+
+    while ((num_chars = _vsnwprintf_s(
+        log_buffer->GetBufferSetLength(buffer_size),
+        buffer_size,
+        _TRUNCATE,
+        fmt,
+        args)) == -1) {
+      // Truncate if the message is too big.
+      if (buffer_size >= kMaxLogMessageSize) {
+        num_chars = buffer_size;
+        break;
+      }
+
+      // Get a buffer that is big enough.
+      buffer_size *= 2;
+    }
+
+    log_buffer->ReleaseBuffer(num_chars);
+
+    FormatLinePrefix(show_time_, proc_name_, *prefix);
+
+    // Log the message.
+    OutputInfo info(cat, level, *prefix, *log_buffer);
+    OutputMessage(writer_mask, &info);
+  } __except(SehSendMinidump(GetExceptionCode(),
+                             GetExceptionInformation(),
+                             kMinsTo100ns)) {
+    OutputDebugStringA("Unexpected exception in: " __FUNCTION__ "\r\n");
+    OutputDebugString(fmt);
+    OutputDebugString(L"\n\r");
+  }
+}
+
+void Logging::LogMessageMaskedVA(DWORD writer_mask,
+                                 LogCategory cat,
+                                 LogLevel level,
+                                 const wchar_t* fmt,
+                                 va_list args) {
+  if (!fmt) {
+    return;
+  }
+
+  if (writer_mask == 0 && level > kMaxLevelToStoreInLogHistory) {
+    return;
+  }
+
+#pragma warning(push)
+// construction of local static object is not thread-safe
+#pragma warning(disable : 4640)
+  // TODO(omaha): make these class members.
+  static CString log_buffer;    // The buffer for formatted log messages.
+  static CString prefix;
+#pragma warning(pop)
+
+  int i = 0;
+  while (++i <= kNumLockRetries) {
+    if (lock_.Lock(0)) {
+      InternalLogMessageMaskedVA(writer_mask, cat, level, &log_buffer,
+                                 &prefix, fmt, args);
+      lock_.Unlock();
+      break;
+    }
+
+    Sleep(kLockRetryDelayMs);
+  }
+
+  if (i > kNumLockRetries) {
+    OutputDebugStringA("LOG_SYSTEM: Couldn't acquire lock - ");
+    OutputDebugString(fmt);
+    OutputDebugString(L"\n\r");
+  }
+}
+
+void Logging::OutputMessage(DWORD writer_mask, LogCategory cat, LogLevel level,
+                            const wchar_t* msg1, const wchar_t* msg2) {
+  OutputInfo info(cat, level, msg1, msg2);
+  OutputMessage(writer_mask, &info);
+}
+
+// Store log message in in-memory history buffer.
+void Logging::StoreInHistory(const OutputInfo* output_info) {
+  AppendToHistory(output_info->msg1);
+  AppendToHistory(output_info->msg2);
+  AppendToHistory(L"\r\n");
+}
+
+// Append string to in-memory history buffer.
+// history_buffer_next_idx points to the next index to write at,
+// thus it should always be in (0 - kHistoryBufferEndIdx).
+void Logging::AppendToHistory(const wchar_t* msg) {
+  int msg_len = wcslen(msg);
+  if (msg_len == 0) {
+    return;
+  }
+
+  if (msg_len >= kMaxHistoryBufferSize) {
+    // Write the first kMaxHistoryBufferSize chars.
+    memcpy(history_buffer, msg, kMaxHistoryBufferSize * sizeof(TCHAR));
+    history_buffer_next_idx = 0;
+    history_buffer_full = true;
+    return;
+  }
+
+  // Determine if the message fits into the portion of the buffer after
+  // history_buffer_next_idx.
+  if (msg_len + history_buffer_next_idx < kMaxHistoryBufferSize) {
+    memcpy(history_buffer + history_buffer_next_idx, msg,
+           msg_len * sizeof(TCHAR));
+    history_buffer_next_idx += msg_len;
+    return;
+  }
+
+  // Have to split the input message into the part that fits in
+  // history_buffer_next_idx to kMaxHistoryBufferSize and the remaining message.
+  int msg_first_part_len = kMaxHistoryBufferSize - history_buffer_next_idx;
+  int msg_second_part_len = msg_len - msg_first_part_len;
+  memcpy(history_buffer + history_buffer_next_idx,
+         msg,
+         msg_first_part_len * sizeof(TCHAR));
+
+  history_buffer_full = true;
+  history_buffer_next_idx = msg_second_part_len;
+  if (msg_second_part_len) {
+    memcpy(history_buffer,
+           msg + msg_first_part_len,
+           msg_second_part_len * sizeof(TCHAR));
+  }
+}
+
+// Retrieve in-memory history buffer.
+CString Logging::GetHistory() {
+  CString history;
+
+  if (history_buffer_full) {
+    history.Append(history_buffer + history_buffer_next_idx,
+                   kMaxHistoryBufferSize - history_buffer_next_idx);
+  }
+  history.Append(history_buffer, history_buffer_next_idx);
+
+  // Reset the history buffer to the original state.
+  history_buffer_next_idx = 0;
+  history_buffer_full = false;
+  memset(history_buffer, 0, kMaxHistoryBufferSize * sizeof(TCHAR));
+
+  return history;
+}
+
+void Logging::OutputMessage(DWORD writer_mask,
+                            const OutputInfo* output_info) {
+  if (output_info->level <= kMaxLevelToStoreInLogHistory &&
+      IsCategoryEnabledForBuffering(output_info->category)) {
+    StoreInHistory(output_info);
+  }
+
+  for (int i = 0; i < num_writers_; ++i) {
+    if (writer_mask & 1) {
+      __try {
+        if (logging_enabled_ || writers_[i]->WantsToLogRegardless()) {
+          writers_[i]->OutputMessage(output_info);
+        }
+      }
+      __except(SehNoMinidump(GetExceptionCode(),
+                             GetExceptionInformation(),
+                             __FILE__,
+                             __LINE__,
+                             true)) {
+        // Just eat errors that happen from within the LogWriters.  This is
+        // important so that if such an error happens when OutputMessage is
+        // called from debugASSERT we don't go recursively into more
+        // error handling ...
+      }
+    }
+    writer_mask >>= 1;
+  }
+}
+
+bool Logging::InternalRegisterWriter(LogWriter* log_writer) {
+  if (num_writers_ >= max_writers) {
+    return false;
+  }
+  writers_[num_writers_++] = log_writer;
+  return true;
+}
+
+bool Logging::RegisterWriter(LogWriter* log_writer) {
+  if (!InternalRegisterWriter(log_writer)) {
+    return false;
+  }
+  if (log_writer->WantsToLogRegardless()) {
+    EnableLogging();
+  }
+  return true;
+}
+
+bool Logging::InternalUnregisterWriter(LogWriter* log_writer) {
+  bool result = false;
+  for (int i = 0; i < num_writers_; ++i) {
+    if (writers_[i] == log_writer) {
+      // Replace this entry with last entry in array, then truncate.
+      writers_[i] = writers_[--num_writers_];
+      result = true;
+      break;
+    }
+  }
+  return result;
+}
+
+bool Logging::UnregisterWriter(LogWriter* log_writer) {
+  if (!InternalUnregisterWriter(log_writer)) {
+    return false;
+  }
+  if (num_writers_ == 0) {
+    DisableLogging();
+  }
+  return true;
+}
+
+// The primary configuration file under %PROGRAMFILES%\Google\Update is
+// removed on uninstall. This is midly inconvenient during development
+// therefore a fallback location for the configuration file is desired.
+CString Logging::GetCurrentConfigurationFilePath() const {
+  if (!config_file_path_.IsEmpty() &&
+      File::Exists(config_file_path_)) {
+    return config_file_path_;
+  } else {
+    return L"";
+  }
+}
+
+CString Logging::GetConfigurationFilePath() const {
+  CString file_path;
+  CString system_drive = GetEnvironmentVariableAsString(_T("SystemDrive"));
+  if (!system_drive.IsEmpty()) {
+    file_path = system_drive;
+    file_path += L"\\";
+  }
+  return file_path + kFilePrefix L".ini";
+}
+
+LogWriter::LogWriter() {
+}
+
+LogWriter::~LogWriter() {
+}
+
+void LogWriter::Cleanup() {}
+
+bool LogWriter::WantsToLogRegardless() const { return false; }
+
+bool LogWriter::IsCatLevelEnabled(LogCategory, LogLevel) const {
+  return false;
+}
+
+void LogWriter::OutputMessage(const OutputInfo*) { }
+
+bool LogWriter::Register() {
+  Logging* logger = GetLogging();
+  if (logger) {
+    return logger->RegisterWriter(this);
+  } else {
+    return false;
+  }
+}
+
+bool LogWriter::Unregister() {
+  Logging* logger = GetLogging();
+  if (logger) {
+    return logger->RegisterWriter(this);
+  } else {
+    return false;
+  }
+}
+
+// FileLogWriter
+
+FileLogWriter* FileLogWriter::Create(const wchar_t* file_name, bool append) {
+  return new FileLogWriter(file_name, append);
+}
+
+FileLogWriter::FileLogWriter(const wchar_t* file_name, bool append)
+    : initialized_(false),
+      valid_(false),
+      file_name_(file_name),
+      log_file_mutex_(NULL),
+      log_file_(NULL),
+      append_(append),
+      max_file_size_(kDefaultMaxLogFileSize),
+      log_file_wide_(kDefaultLogFileWide) {
+  Logging* logger = GetLogging();
+  if (logger) {
+    CString config_file_path = logger->GetCurrentConfigurationFilePath();
+    if (!config_file_path.IsEmpty()) {
+        max_file_size_ = ::GetPrivateProfileInt(
+            kConfigSectionLoggingSettings,
+            kConfigAttrMaxLogFileSize,
+            kDefaultMaxLogFileSize,
+            config_file_path);
+        log_file_wide_ = ::GetPrivateProfileInt(
+            kConfigSectionLoggingSettings,
+            kConfigAttrLogFileWide,
+            kDefaultLogFileWide,
+            config_file_path) == 0 ? false : true;
+    } else {
+      max_file_size_ = kDefaultMaxLogFileSize;
+      log_file_wide_ = kDefaultLogFileWide;
+    }
+    proc_name_ = logger->proc_name();
+  }
+}
+
+FileLogWriter::~FileLogWriter() {
+  // TODO(omaha): Figure out a way to pass the proc_name - and possibly
+  // the show_time var - into here.
+  Logging* logger = GetLogging();
+  if (logger && logger->IsLoggingAlreadyEnabled()) {
+    // OutputInfo info(LEVEL_WARNING, NULL, kEndOfLogMessage);
+    // OutputMessage(&info);
+  }
+  Cleanup();
+}
+
+void FileLogWriter::Initialize() {
+  if (initialized_) {
+    return;
+  }
+
+  initialized_ = true;
+
+  bool already_created = CreateLoggingMutex();
+  if (!log_file_mutex_) {
+    return;
+  }
+
+  if (already_created) {
+    append_ = true;
+  }
+
+  if (!GetMutex()) {
+    ::OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: "
+                                L"Could not acquire logging mutex %s\n",
+                                proc_name_,
+                                log_file_mutex_name_));
+    return;
+  }
+
+  CreateLoggingFile();
+  if (!log_file_) {
+    ::OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: "
+                                L"Could not create logging file %s\n",
+                                proc_name_,
+                                file_name_));
+    valid_ = false;
+  }
+
+  valid_ = true;
+  ReleaseMutex();
+}
+
+void FileLogWriter::Cleanup() {
+  if (log_file_) {
+    ::CloseHandle(log_file_);
+  }
+  if (log_file_mutex_) {
+    ::ReleaseMutex(log_file_mutex_);
+    ::CloseHandle(log_file_mutex_);
+  }
+}
+
+bool FileLogWriter::CreateLoggingMutex() {
+  log_file_mutex_name_ = StripBackslashes(kLoggingMutexName L"_" + file_name_);
+  // TODO(omaha): I don't see where this class is used, but I guess the
+  // caller is always in the same context. We should use the default security
+  // here.  If the caller can be in different contexts (System Service, Usermode
+  // applications, etc), then we should revisit this code to give access only
+  // to those who really need it.  What if a malicious piece a code decide
+  // to get the mutex and lock it? If it happens, everytime you try to log
+  // something, the thread would hang for 500ms and then fail to log the
+  // message.
+  CSecurityAttributes sa;
+  GetEveryoneDaclSecurityAttributes(&sa, GENERIC_ALL);
+  log_file_mutex_ = CreateMutexWithSyncAccess(log_file_mutex_name_, &sa);
+  if (log_file_mutex_) {
+    return ERROR_ALREADY_EXISTS == ::GetLastError();
+  }
+  return false;
+}
+
+bool FileLogWriter::CreateLoggingFile() {
+  uint32 file_size(0);
+  File::GetFileSizeUnopen(file_name_, &file_size);
+  if (file_size > max_file_size_) {
+    ArchiveLoggingFile();
+  }
+  log_file_ = ::CreateFile(file_name_,
+                           GENERIC_WRITE,
+                           FILE_SHARE_WRITE | FILE_SHARE_READ,
+                           NULL,
+                           append_ ? OPEN_ALWAYS : CREATE_ALWAYS,
+                           FILE_ATTRIBUTE_NORMAL,
+                           NULL);
+  if (log_file_ == INVALID_HANDLE_VALUE) {
+    // The code in this file is written with the assumption that log_file_ is
+    // NULL on creation errors. The easy fix is to set it to NULL here. The
+    // long term fix should be implementing it in terms of a smart handle.
+    log_file_ = NULL;
+    return false;
+  }
+
+  // Allow users to read, write, and delete the log file.
+  ACCESS_MASK mask = GENERIC_READ | GENERIC_WRITE | DELETE;
+  CDacl dacl;
+  if (dacl.AddAllowedAce(ATL::Sids::Users(), mask)) {
+    AtlSetDacl(file_name_, SE_FILE_OBJECT, dacl);
+  }
+
+  // Insert a BOM in the newly created file.
+  if (GetLastError() != ERROR_ALREADY_EXISTS && log_file_wide_) {
+    DWORD num = 0;
+    ::WriteFile(log_file_, &kUnicodeBom, sizeof(kUnicodeBom), &num, NULL);
+  }
+  return true;
+}
+
+bool FileLogWriter::TruncateLoggingFile() {
+  DWORD share_mode = FILE_SHARE_WRITE;
+  HANDLE log_file = ::CreateFile(file_name_,
+                                 GENERIC_WRITE,
+                                 FILE_SHARE_WRITE | FILE_SHARE_READ,
+                                 NULL,
+                                 TRUNCATE_EXISTING,
+                                 FILE_ATTRIBUTE_NORMAL,
+                                 NULL);
+  if (log_file_ == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+
+  // Insert a BOM in the newly created file.
+  if (log_file_wide_) {
+    DWORD num = 0;
+    ::WriteFile(log_file, &kUnicodeBom, sizeof(kUnicodeBom), &num, NULL);
+  }
+  ::CloseHandle(log_file);
+  return true;
+}
+
+bool FileLogWriter::ArchiveLoggingFile() {
+  ::OutputDebugString(L"LOG_SYSTEM: trying to move log file to backup\n");
+  CString backup_file_name = file_name_ + L".bak";
+  HRESULT hr = File::Move(file_name_, backup_file_name, true);
+  if (FAILED(hr)) {
+    ::OutputDebugString(L"LOG_SYSTEM: failed to move log file to backup\n");
+
+    // Trying to move the log file when loggers have it open returns
+    // ERROR_SHARING_VIOLATION. Each call to MoveFileAfterReboot inserts the
+    // file into PendingFileRenames list. Moving files at reboot requires the
+    // user to be either the LocalSystem account or in the Administrators
+    // group.
+    if (!IsArchivePending()) {
+      File::MoveAfterReboot(file_name_, backup_file_name);
+    }
+    return false;
+  }
+  return true;
+}
+
+bool FileLogWriter::IsArchivePending() {
+  // We look at the PendingFileRenameOperations to see if our log file is
+  // pending a rename. The list is a REG_MULTI_SZ, which is a sequence of
+  // null-terminated strings, terminated by an empty string "\0".
+  // The strings have the structure:
+  // \??\file1\0!\??\file2\0\file3\0\0...\0\0. where file1 is to be renamed to
+  // file2 and file3 is to be deleted.
+  // It is valid for the PFR list to include an empty string in the middle
+  // of the sequence.
+  const wchar_t sub_key_name[] = L"SYSTEM\\CurrentControlSet\\Control\\"
+                                 L"Session Manager";
+  HKEY key = NULL;
+  int res = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                            sub_key_name,
+                            0,
+                            KEY_READ,
+                            &key);
+  if (res != ERROR_SUCCESS) {
+    return false;
+  }
+  DWORD bytes = 0;
+  DWORD type = REG_MULTI_SZ;
+  res = ::RegQueryValueEx(key,
+                          L"PendingFileRenameOperations",
+                          0,
+                          &type,
+                          NULL,
+                          &bytes);
+  if (!(res == ERROR_SUCCESS && type == REG_MULTI_SZ)) {
+    return false;
+  }
+  scoped_array<byte> buf(new byte[bytes]);
+  memset(buf.get(), 0, bytes);
+  res = ::RegQueryValueEx(key,
+                          L"PendingFileRenameOperations",
+                          0,
+                          NULL,
+                          buf.get(),
+                          &bytes);
+  if (res != ERROR_SUCCESS) {
+    return false;
+  }
+  const wchar_t* multi_str = reinterpret_cast<const wchar_t*>(buf.get());
+  size_t count = bytes / sizeof(*multi_str);
+  const size_t kMaxRegistryValueLen = 1024 * 1024;  // 1MB
+  if (!(count >= 2 &&
+        count < kMaxRegistryValueLen &&
+        multi_str[count - 2] == L'\0' &&
+        multi_str[count - 1] == L'\0')) {
+    return false;
+  }
+  // The file names in the PFR list are prefixed by \??\.
+  CString file_name = L"\\??\\" + file_name_;
+  return FindFirstInMultiString(multi_str, count, file_name) != -1;
+}
+
+int FileLogWriter::FindFirstInMultiString(const wchar_t* multi_str,
+                                          size_t count,
+                                          const wchar_t* str) {
+  const wchar_t* p = multi_str;
+  size_t i = 0;
+  while (i < count) {
+    p =  multi_str + i;
+    if (lstrcmp(p, str) == 0) {
+      return i;
+    } else {
+      size_t len = lstrlen(p);
+      i += len + 1;
+    }
+  }
+  return -1;
+}
+
+void FileLogWriter::OutputMessage(const OutputInfo* output_info) {
+  if (!initialized_) {
+    Initialize();
+  }
+
+  if (!valid_) {
+    return;
+  }
+
+  // Acquire the mutex.
+  if (!GetMutex()) {
+    return;
+  }
+
+  // Move to end of file.
+  DWORD pos = ::SetFilePointer(log_file_, 0, NULL, FILE_END);
+  int64 stop_gap_file_size = kStopGapLogFileSizeFactor *
+                             static_cast<int64>(max_file_size_);
+  if (pos >= stop_gap_file_size) {
+    if (!TruncateLoggingFile()) {
+      // Logging stops until the log can be archived over since we do not
+      // want to overfill the disk.
+      return;
+    }
+  }
+  pos = ::SetFilePointer(log_file_, 0, NULL, FILE_END);
+
+  // Write the date, followed by a CRLF
+  DWORD written_size = 0;
+  if (output_info->msg1) {
+    if (log_file_wide_) {
+      ::WriteFile(log_file_, output_info->msg1,
+                  lstrlen(output_info->msg1) * sizeof(wchar_t), &written_size,
+                  NULL);
+    } else {
+      CStringA msg(WideToAnsiDirect(output_info->msg1));
+      ::WriteFile(log_file_, msg.GetString(), msg.GetLength(), &written_size,
+                  NULL);
+    }
+  }
+
+  if (output_info->msg2) {
+    if (log_file_wide_) {
+      ::WriteFile(log_file_, output_info->msg2,
+                  lstrlen(output_info->msg2) * sizeof(wchar_t), &written_size,
+                  NULL);
+    } else {
+      CStringA msg(WideToAnsiDirect(output_info->msg2));
+      ::WriteFile(log_file_, msg.GetString(), msg.GetLength(), &written_size,
+                  NULL);
+    }
+  }
+
+  if (log_file_wide_) {
+    ::WriteFile(log_file_, L"\r\n", 2 * sizeof(wchar_t), &written_size, NULL);
+  } else {
+    ::WriteFile(log_file_, "\r\n", 2, &written_size, NULL);
+  }
+
+  ReleaseMutex();
+}
+
+bool FileLogWriter::GetMutex() {
+  if (!log_file_mutex_) {
+    return false;
+  }
+
+  DWORD res = ::WaitForSingleObject(log_file_mutex_, kMaxMutexWaitTimeMs);
+  if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
+    ::OutputDebugString(SPRINTF(L"LOG_SYSTEM: [%s]: "
+                                L"Could not acquire logging mutex %s\n",
+                                proc_name_, log_file_mutex_name_));
+    valid_ = false;
+    return false;
+  }
+
+  return true;
+}
+
+void FileLogWriter::ReleaseMutex() {
+  if (log_file_mutex_) {
+    ::ReleaseMutex(log_file_mutex_);
+  }
+}
+
+// OutputDebugStringLogWriter.
+OutputDebugStringLogWriter* OutputDebugStringLogWriter::Create() {
+  return new OutputDebugStringLogWriter();
+}
+
+OutputDebugStringLogWriter::OutputDebugStringLogWriter() {}
+
+OutputDebugStringLogWriter::~OutputDebugStringLogWriter() {
+  Logging* logger = GetLogging();
+  if (logger && logger->IsLoggingAlreadyEnabled()) {
+    // OutputInfo info(LEVEL_WARNING, NULL, kEndOfLogMessage);
+    // OutputMessage(&info);
+  }
+  Cleanup();
+}
+
+void OutputDebugStringLogWriter::OutputMessage(const OutputInfo* output_info) {
+  // Combine everything into one string so that messages coming from
+  // multiple threads don't get interleaved.
+  ::OutputDebugString(SPRINTF(L"%s%s\n", output_info->msg1, output_info->msg2));
+}
+
+// OverrideConfigLogWriter.
+OverrideConfigLogWriter* OverrideConfigLogWriter::Create(LogCategory category,
+    LogLevel level, LogWriter* log_writer, bool force_logging_enabled) {
+  return new OverrideConfigLogWriter(category,
+                                     level,
+                                     log_writer,
+                                     force_logging_enabled);
+}
+
+OverrideConfigLogWriter::OverrideConfigLogWriter(LogCategory category,
+                                                 LogLevel level,
+                                                 LogWriter* log_writer,
+                                                 bool force_logging_enabled)
+    : category_(category),
+      level_(level),
+      log_writer_(log_writer),
+      force_logging_enabled_(force_logging_enabled) {}
+
+void OverrideConfigLogWriter::Cleanup() {
+  if (log_writer_) {
+    delete log_writer_;
+  }
+}
+
+bool OverrideConfigLogWriter::WantsToLogRegardless() const {
+  return force_logging_enabled_;
+}
+
+bool OverrideConfigLogWriter::IsCatLevelEnabled(LogCategory category,
+                                                LogLevel level) const {
+  if (category != category_) {
+    return false;
+  }
+  if (level > level_) {
+    return false;
+  }
+  return true;
+}
+
+void OverrideConfigLogWriter::OutputMessage(const OutputInfo* output_info) {
+  if (log_writer_) {
+    log_writer_->OutputMessage(output_info);
+  }
+  return;
+}
+
+}  // namespace omaha
+
+#endif  // LOGGING
+
diff --git a/common/logging.h b/common/logging.h
index eda83a5..800f36f 100644
--- a/common/logging.h
+++ b/common/logging.h
@@ -1,499 +1,499 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// logging.h

-//

-// Tracing and logging system.

-// Allows filtering of the log messages based on logging categories and levels.

-

-#ifndef OMAHA_COMMON_LOGGING_H__

-#define OMAHA_COMMON_LOGGING_H__

-

-#include "omaha/common/commontypes.h"

-#include "omaha/common/synchronized.h"

-

-#ifdef LOGGING

-

-// Logging levels.

-enum LogLevel {

-  LEVEL_FATALERROR = -3,      // crashing fatal error

-  LEVEL_ERROR      = -2,      // errors - recoverable but shouldn't happen

-  LE               = -2,

-  LEVEL_WARNING    = -1,      // warnings

-  LW               = -1,

-  L1               =  1,      // for aprox. 10 logs per run

-  L2,                         // for aprox. 100 logs per run

-  L3,                         // for aprox. 1,000 logs per run

-  L4,                         // for aprox. 10,000 logs per run

-  L5,                         // for aprox. 100,000 logs per run

-  L6,                         // for > 1,000,000 logs per run

-

-  // add above

-  LEVEL_ALL                   // all errors

-};

-

-#endif

-

-namespace omaha {

-

-#define kDefaultLogFileName             kFilePrefix L".log"

-#define kDefaultLogFileWide             1

-#define kDefaultLogToFile               1

-#define kDefaultShowTime                1

-#define kDefaultAppendToFile            1

-

-#ifdef _DEBUG

-#define kDefaultMaxLogFileSize          0xFFFFFFFF  // 4GB

-#define kDefaultLogToOutputDebug        1

-#define kDefaultLogLevel                L3

-#define kDefaultLoggingEnabled          1

-#else

-#define kDefaultMaxLogFileSize          10000000    // 10MB

-#define kDefaultLogToOutputDebug        0

-#define kDefaultLogLevel                L1

-#define kDefaultLoggingEnabled          0

-#endif

-

-// Truncates the log file when the size of the log file is this many

-// times over the MaxLogFileSize to prevent disk overfill.

-#define kStopGapLogFileSizeFactor       10

-

-// config file sections

-#define kConfigSectionLoggingLevel      L"LoggingLevel"

-#define kConfigSectionLoggingSettings   L"LoggingSettings"

-

-// config file attributes

-#define kConfigAttrEnableLogging        L"EnableLogging"

-#define kConfigAttrShowTime             L"ShowTime"

-#define kConfigAttrLogToFile            L"LogToFile"

-#define kConfigAttrLogFilePath          L"LogFilePath"

-#define kConfigAttrLogFileWide          L"LogFileWide"

-#define kConfigAttrLogToOutputDebug     L"LogToOutputDebug"

-#define kConfigAttrAppendToFile         L"AppendToFile"

-#define kConfigAttrMaxLogFileSize       L"MaxLogFileSize"

-

-#define kLoggingMutexName               kLockPrefix L"logging_mutex"

-#define kMaxMutexWaitTimeMs             500

-

-// Does not allow messages bigger than 1 MB.

-#define kMaxLogMessageSize              (1024 * 1024)

-

-#define kLogSettingsCheckInterval       (5 * kSecsTo100ns)

-

-#define kStartOfLogMessage \

-    L"********************* NEW LOG *********************"

-#define kEndOfLogMessage   \

-    L"********************* END LOG *********************"

-

-// TODO(omaha): Allow these defaults to be overriden in the config file.

-#define kMaxLevelToStoreInLogHistory L2

-#define kMaxHistoryBufferSize 1024

-

-#ifdef LOGGING

-

-#define LC_LOG(cat, level, msg) \

-  do {                                                     \

-    omaha::Logging* logger = omaha::GetLogging();          \

-    if (logger) {                                          \

-      omaha::LoggingHelper(logger, cat, level,             \

-        logger->IsCatLevelEnabled(cat, level)) msg;        \

-    }                                                      \

-  } while (0)

-

-#define LC_LOG_OPT(cat, level, msg)   LC_LOG(cat, level, msg)

-

-#else

-#define LC_LOG(cat, level, msg)   ((void)0)

-#endif

-

-#ifdef _DEBUG

-#define LC_LOG_DEBUG(cat, level, msg) LC_LOG(cat, level, msg)

-#else

-#define LC_LOG_DEBUG(cat, level, msg) ((void)0)

-#endif

-

-// Shortcuts for different logging categories - no need to specify the category.

-#define CORE_LOG(x, y)         LC_LOG_DEBUG(omaha::LC_CORE, x, y)

-#define NET_LOG(x, y)          LC_LOG_DEBUG(omaha::LC_NET, x, y)

-#define PLUGIN_LOG(x, y)       LC_LOG_DEBUG(omaha::LC_PLUGIN, x, y)

-#define SERVICE_LOG(x, y)      LC_LOG_DEBUG(omaha::LC_SERVICE, x, y)

-#define SETUP_LOG(x, y)        LC_LOG_DEBUG(omaha::LC_SETUP, x, y)

-#define SHELL_LOG(x, y)        LC_LOG_DEBUG(omaha::LC_SHELL, x, y)

-#define UTIL_LOG(x, y)         LC_LOG_DEBUG(omaha::LC_UTIL, x, y)

-

-#define OPT_LOG(x, y)          LC_LOG_OPT(omaha::LC_OPT, x, y)

-#define REPORT_LOG(x, y)       LC_LOG_OPT(omaha::LC_REPORT, x, y)

-

-#ifdef LOGGING

-

-// Logging components.

-// Maximum 32 categories unless mask is increased to 64 bits.

-enum LogCategory {

-  LC_LOGGING = 0,

-

-  // ADD BELOW - AND REMEMBER:

-  //   - add a line to the LogCategoryNames table in logging.cpp!!!

-  //   - add to C:\GoogleUpdate.ini

-

-  LC_UTIL,

-  LC_SETUP,

-  LC_SHELL,

-  LC_CORE,

-  LC_JS,

-  LC_PLUGIN,

-  LC_SERVICE,

-  LC_OPT,

-  LC_NET,

-  LC_REPORT,

-

-  // ADD ABOVE

-

-  LC_MAX_CAT

-};

-

-#define kCatEnabledField      L"Enabled"

-#define kCatLevelField        L"Level"

-

-struct CategoryInfo {

-  bool enabled;

-  LogLevel log_level;

-};

-

-struct OutputInfo;

-

-// The LogWriter - can decide whether to process message or not, then

-// will process it.  Actually, the message is processed if either a) the

-// individual LogWriter wants to process it or b) it is marked as processable

-// by settings in config ini.

-//

-// Included LogWriters:

-//   OutputDebugStringLogWriter - Logs to OutputDebugString() API

-//   FileLogWriter - Logs to a file

-//   OverrideConfigLogWriter - Overrides the level settings of a

-//     particular category, uses another writer to actually do the writing.

-//     Used, e.g., in installer to force SETUP_LOG messages to go to a file

-//     tr_setup_log.info even if the there is no trconfig.ini file.

-//

-// Not included LogWriters:

-//   StdLogWriter - Logs to stdout or stderr

-//   SubmitToGoogleLogWriter - When done logging submits the log file to

-//     Google's status-receiving server

-class LogWriter {

- protected:

-  LogWriter();

-  virtual void Cleanup();

- public:

-  virtual ~LogWriter();

-

-  // Returns true if this Logging object wants to log even if the global

-  // "enable logging" flag is off.  Useful for always creating a log, e.g., an

-  // install log, even without a GoogleUpdate.ini.

-  virtual bool WantsToLogRegardless() const;

-

-  // Returns true if this Logging object wants to handle the message,

-  // regardless of other settings.

-  virtual bool IsCatLevelEnabled(LogCategory category, LogLevel level) const;

-

-  virtual void OutputMessage(const OutputInfo* output_info);

-

-  // Registers and unregisters this LogWriter with the Logging system.  When

-  // registered, the Logging class assumes ownership.

-  bool Register();

-  bool Unregister();

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(LogWriter);

-};

-

-// A LogWriter that writes to a named file.

-class FileLogWriter : public LogWriter {

- protected:

-  FileLogWriter(const wchar_t* file_name, bool append);

-  ~FileLogWriter();

-  virtual void Cleanup();

-

- public:

-  static FileLogWriter* Create(const wchar_t* file_name, bool append);

-  virtual void OutputMessage(const OutputInfo* output_info);

-

- private:

-  void Initialize();

-  bool CreateLoggingMutex();

-  bool CreateLoggingFile();

-  bool ArchiveLoggingFile();

-  bool TruncateLoggingFile();

-  bool GetMutex();

-  void ReleaseMutex();

-

-  // Returns true if archiving of the log file is pending a computer restart.

-  bool IsArchivePending();

-

-  // Returns the first position of str inside of a MULTI_SZ of count characters

-  // including the terminating zeros.

-  static int FindFirstInMultiString(const wchar_t* multi_str,

-                                    size_t count,

-                                    const wchar_t* str);

-

-  uint32 max_file_size_;

-  bool initialized_;

-  bool valid_;

-  bool append_;

-  bool log_file_wide_;

-  CString log_file_mutex_name_;

-  HANDLE log_file_mutex_;

-  CString file_name_;

-  HANDLE log_file_;

-  CString proc_name_;

-

-  friend class FileLogWriterTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(FileLogWriter);

-};

-

-// A LogWriter that uses OutputDebugString() to write messages.

-class OutputDebugStringLogWriter : public LogWriter {

- protected:

-  OutputDebugStringLogWriter();

-  ~OutputDebugStringLogWriter();

- public:

-  static OutputDebugStringLogWriter* Create();

-  virtual void OutputMessage(const OutputInfo* info);

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(OutputDebugStringLogWriter);

-};

-

-// A LogWriter that overrides the settings in trconfig.ini and sends messages

-// to another LogWriter.  Takes ownership of the other LogWriter.

-class OverrideConfigLogWriter : public LogWriter {

- protected:

-  OverrideConfigLogWriter(LogCategory category, LogLevel level,

-                          LogWriter* log_writer, bool force_logging_enabled);

-  virtual void Cleanup();

- public:

-  static OverrideConfigLogWriter* Create(LogCategory category, LogLevel level,

-    LogWriter* log_writer, bool force_logging_enabled);

-  virtual bool WantsToLogRegardless() const;

-  virtual bool IsCatLevelEnabled(LogCategory category, LogLevel level) const;

-  virtual void OutputMessage(const OutputInfo* output_info);

- private:

-  LogCategory category_;

-  LogLevel level_;

-  LogWriter* log_writer_;

-  bool force_logging_enabled_;

-  DISALLOW_EVIL_CONSTRUCTORS(OverrideConfigLogWriter);

-};

-

-// The Logging class - Singleton class

-// Fine-grain logging based on categories and levels.

-// Can log to a file, stdout or debugger.

-class Logging {

- public:

-  // constructor

-  Logging();

-

-  // destructor

-  ~Logging();

-

-  // Enables/disables the logging mechanism.  Allows turning logging on/off

-  // in mid-run.  Returns true for success (not for 'logging enabled').

-  void EnableLogging();

-  void DisableLogging();

-

-  // Checks if logging is enabled - and updates logging settings from the

-  // configuration file every kLogSettingsCheckInterval seconds

-  bool IsLoggingEnabled();

-

-  // Checks if logging is already enabled. It does not try to enable it.

-  bool IsLoggingAlreadyEnabled() const;

-

-  // Overrides the config file settings for showing the time stamps.

-  void ForceShowTimestamp(bool force_show_time);

-

-  // Checks if logging is enabled for a given category and level.

-  DWORD IsCatLevelEnabled(LogCategory category, LogLevel level);

-  LogLevel GetCatLevel(LogCategory category) const;

-

-  // Logs a message.

-  void LogMessage(LogCategory cat, LogLevel level, const wchar_t* fmt, ...);

-  void LogMessageVA(LogCategory cat, LogLevel level, const wchar_t* fmt,

-                    va_list args);

-

-  // Retrieves the default location of the log directory.

-  CString GetDefaultLogDirectory() const;

-

-  // Computes and returns the complete path of the log file.

-  CString GetLogFilePath() const;

-

-  // Retrieves in-memory history buffer.

-  CString GetHistory();

-

-  // Returns the file path of the current GoogleUpdate.ini.

-  CString GetCurrentConfigurationFilePath() const;

-

-  const CString& proc_name() const { return proc_name_; }

-

-  bool IsCategoryEnabledForBuffering(LogCategory cat);

- private:

-  bool InternalInitialize();

-  void InternalLogMessageMaskedVA(DWORD writer_mask,

-                                  LogCategory cat,

-                                  LogLevel level,

-                                  CString* log_buffer,

-                                  CString* prefix,

-                                  const wchar_t* fmt,

-                                  va_list args);

-

-  friend class LoggingHelper;

-  void LogMessageMaskedVA(DWORD writer_mask, LogCategory cat, LogLevel level,

-                          const wchar_t* fmt, va_list args);

-

-  // Stores log message in in-memory history buffer.

-  void StoreInHistory(const OutputInfo* output_info);

-

-  // Appends string to in-memory history buffer.

-  void AppendToHistory(const wchar_t* msg);

-

-  // Initializes the logging engine. Harmless to call multiple times.

-  bool InitializeLogging();

-

-  // Configures/unconfigures the log writers for the current settings.  That

-  // is, given the current settings from GoogleUpdate.ini, either initializes

-  // and registers the file-out and debug-out logwriters, or unregisters them.

-  bool ConfigureLogging();

-  void UnconfigureLogging();

-

-  void UpdateCatAndLevel(const wchar_t* cat_name, LogCategory cat);

-  void ReadLoggingSettings();

-

-  // Returns the primary file path of the GoogleUpdate.ini.

-  CString GetConfigurationFilePath() const;

-

-  // Returns the alternate file path of the GoogleUpdate.ini.

-  CString GetAltConfigurationFilePath() const;

-

- public:

-

-  // Passes the messages along to other OutputMessage()

-  void OutputMessage(DWORD writer_mask, LogCategory cat, LogLevel level,

-                     const wchar_t* msg1, const wchar_t* msg2);

-

-  // Broadcasts the message to each LogWriter.

-  // It should be private but the function we want to be able to use this,

-  // debugASSERT is extern "C" and thus can't be declared a friend of

-  // Logging.

-  void OutputMessage(DWORD writer_mask, const OutputInfo* output_info);

-

- private:

-

-  CategoryInfo category_list_[LC_MAX_CAT];

-

-  // Checks if logging is initialized.

-  bool logging_initialized_;

-

-  // Is logging in the process of initializing?

-  bool is_initializing_;

-

-  // The logging process name including the calling module.

-  CString proc_name_;

-

-  // Serializes changing logging init/uninit/enable/disable status.

-  LLock lock_;

-

-  // Bunch of settings from the config .ini file.

-  bool logging_enabled_;     // Checks if logging is enabled.

-  bool force_show_time_;

-  bool show_time_;

-  bool log_to_file_;

-  CString log_file_name_;

-  bool log_to_debug_out_;

-  bool append_to_file_;

-

-  // Signals the logging system is shutting down.

-  bool logging_shutdown_;

-

-  // Checkpoint time for dynamic category updates.

-  time64 g_last_category_check_time;

-

-  // The file path of the optional ini file which defines the logging

-  // configuration.

-  CString config_file_path_;

-

- private:

-  bool InternalRegisterWriter(LogWriter* log_writer);

-  bool InternalUnregisterWriter(LogWriter* log_writer);

-

- public:

-  bool RegisterWriter(LogWriter* log_writer);

-  bool UnregisterWriter(LogWriter* log_writer);

-  enum { all_writers_mask = -1 };

-

- private:

-  enum { max_writers = 15 };

-  int num_writers_;

-  LogWriter* writers_[max_writers];

-

-  LogWriter* file_log_writer_;

-  LogWriter* debug_out_writer_;

-

-  friend class HistoryTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Logging);

-};

-

-// In order to make the logging macro LC_LOG work out we need to pass a

-// parameter (the mask of loggers to write to) (*) to the actual logging

-// method. However, the last parameter to the macro LC_LOG has its own

-// parenthesis - it encloses multiple expressions (a format string and

-// arguments). So this function object is used as an intermediary in order to

-// hold the writer mask.

-//

-// (*) The mask needs to be transferred separately because we want to keep the

-// LC_LOG structure of asking if the message is going to be logged before

-// evaluating the arguments, and we can't store it in the singleton Logging

-// object - wouldn't be thread-safe.

-

-class LoggingHelper {

- public:

-  LoggingHelper(Logging* logger, LogCategory cat,

-                LogLevel level, DWORD writer_mask)

-      : logger_(logger),

-        category_(cat),

-        level_(level),

-        writer_mask_(writer_mask) {}

-

-  void operator()(const wchar_t* fmt, ...) {

-    va_list args;

-    va_start(args, fmt);

-    logger_->LogMessageMaskedVA(writer_mask_, category_, level_, fmt, args);

-    va_end(args);

-  }

-

- private:

-  Logging* logger_;

-  DWORD writer_mask_;

-  LogLevel level_;

-  LogCategory category_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(LoggingHelper);

-};

-

-// Getter for the Logging singleton class.

-Logging* GetLogging();

-

-#endif  // LOGGING

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_LOGGING_H__

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// logging.h
+//
+// Tracing and logging system.
+// Allows filtering of the log messages based on logging categories and levels.
+
+#ifndef OMAHA_COMMON_LOGGING_H__
+#define OMAHA_COMMON_LOGGING_H__
+
+#include "omaha/common/commontypes.h"
+#include "omaha/common/synchronized.h"
+
+#ifdef LOGGING
+
+// Logging levels.
+enum LogLevel {
+  LEVEL_FATALERROR = -3,      // crashing fatal error
+  LEVEL_ERROR      = -2,      // errors - recoverable but shouldn't happen
+  LE               = -2,
+  LEVEL_WARNING    = -1,      // warnings
+  LW               = -1,
+  L1               =  1,      // for aprox. 10 logs per run
+  L2,                         // for aprox. 100 logs per run
+  L3,                         // for aprox. 1,000 logs per run
+  L4,                         // for aprox. 10,000 logs per run
+  L5,                         // for aprox. 100,000 logs per run
+  L6,                         // for > 1,000,000 logs per run
+
+  // add above
+  LEVEL_ALL                   // all errors
+};
+
+#endif
+
+namespace omaha {
+
+#define kDefaultLogFileName             kFilePrefix L".log"
+#define kDefaultLogFileWide             1
+#define kDefaultLogToFile               1
+#define kDefaultShowTime                1
+#define kDefaultAppendToFile            1
+
+#ifdef _DEBUG
+#define kDefaultMaxLogFileSize          0xFFFFFFFF  // 4GB
+#define kDefaultLogToOutputDebug        1
+#define kDefaultLogLevel                L3
+#define kDefaultLoggingEnabled          1
+#else
+#define kDefaultMaxLogFileSize          10000000    // 10MB
+#define kDefaultLogToOutputDebug        0
+#define kDefaultLogLevel                L1
+#define kDefaultLoggingEnabled          0
+#endif
+
+// Truncates the log file when the size of the log file is this many
+// times over the MaxLogFileSize to prevent disk overfill.
+#define kStopGapLogFileSizeFactor       10
+
+// config file sections
+#define kConfigSectionLoggingLevel      L"LoggingLevel"
+#define kConfigSectionLoggingSettings   L"LoggingSettings"
+
+// config file attributes
+#define kConfigAttrEnableLogging        L"EnableLogging"
+#define kConfigAttrShowTime             L"ShowTime"
+#define kConfigAttrLogToFile            L"LogToFile"
+#define kConfigAttrLogFilePath          L"LogFilePath"
+#define kConfigAttrLogFileWide          L"LogFileWide"
+#define kConfigAttrLogToOutputDebug     L"LogToOutputDebug"
+#define kConfigAttrAppendToFile         L"AppendToFile"
+#define kConfigAttrMaxLogFileSize       L"MaxLogFileSize"
+
+#define kLoggingMutexName               kLockPrefix L"logging_mutex"
+#define kMaxMutexWaitTimeMs             500
+
+// Does not allow messages bigger than 1 MB.
+#define kMaxLogMessageSize              (1024 * 1024)
+
+#define kLogSettingsCheckInterval       (5 * kSecsTo100ns)
+
+#define kStartOfLogMessage \
+    L"********************* NEW LOG *********************"
+#define kEndOfLogMessage   \
+    L"********************* END LOG *********************"
+
+// TODO(omaha): Allow these defaults to be overriden in the config file.
+#define kMaxLevelToStoreInLogHistory L2
+#define kMaxHistoryBufferSize 1024
+
+#ifdef LOGGING
+
+#define LC_LOG(cat, level, msg) \
+  do {                                                     \
+    omaha::Logging* logger = omaha::GetLogging();          \
+    if (logger) {                                          \
+      omaha::LoggingHelper(logger, cat, level,             \
+        logger->IsCatLevelEnabled(cat, level)) msg;        \
+    }                                                      \
+  } while (0)
+
+#define LC_LOG_OPT(cat, level, msg)   LC_LOG(cat, level, msg)
+
+#else
+#define LC_LOG(cat, level, msg)   ((void)0)
+#endif
+
+#ifdef _DEBUG
+#define LC_LOG_DEBUG(cat, level, msg) LC_LOG(cat, level, msg)
+#else
+#define LC_LOG_DEBUG(cat, level, msg) ((void)0)
+#endif
+
+// Shortcuts for different logging categories - no need to specify the category.
+#define CORE_LOG(x, y)         LC_LOG_DEBUG(omaha::LC_CORE, x, y)
+#define NET_LOG(x, y)          LC_LOG_DEBUG(omaha::LC_NET, x, y)
+#define PLUGIN_LOG(x, y)       LC_LOG_DEBUG(omaha::LC_PLUGIN, x, y)
+#define SERVICE_LOG(x, y)      LC_LOG_DEBUG(omaha::LC_SERVICE, x, y)
+#define SETUP_LOG(x, y)        LC_LOG_DEBUG(omaha::LC_SETUP, x, y)
+#define SHELL_LOG(x, y)        LC_LOG_DEBUG(omaha::LC_SHELL, x, y)
+#define UTIL_LOG(x, y)         LC_LOG_DEBUG(omaha::LC_UTIL, x, y)
+
+#define OPT_LOG(x, y)          LC_LOG_OPT(omaha::LC_OPT, x, y)
+#define REPORT_LOG(x, y)       LC_LOG_OPT(omaha::LC_REPORT, x, y)
+
+#ifdef LOGGING
+
+// Logging components.
+// Maximum 32 categories unless mask is increased to 64 bits.
+enum LogCategory {
+  LC_LOGGING = 0,
+
+  // ADD BELOW - AND REMEMBER:
+  //   - add a line to the LogCategoryNames table in logging.cpp!!!
+  //   - add to C:\GoogleUpdate.ini
+
+  LC_UTIL,
+  LC_SETUP,
+  LC_SHELL,
+  LC_CORE,
+  LC_JS,
+  LC_PLUGIN,
+  LC_SERVICE,
+  LC_OPT,
+  LC_NET,
+  LC_REPORT,
+
+  // ADD ABOVE
+
+  LC_MAX_CAT
+};
+
+#define kCatEnabledField      L"Enabled"
+#define kCatLevelField        L"Level"
+
+struct CategoryInfo {
+  bool enabled;
+  LogLevel log_level;
+};
+
+struct OutputInfo;
+
+// The LogWriter - can decide whether to process message or not, then
+// will process it.  Actually, the message is processed if either a) the
+// individual LogWriter wants to process it or b) it is marked as processable
+// by settings in config ini.
+//
+// Included LogWriters:
+//   OutputDebugStringLogWriter - Logs to OutputDebugString() API
+//   FileLogWriter - Logs to a file
+//   OverrideConfigLogWriter - Overrides the level settings of a
+//     particular category, uses another writer to actually do the writing.
+//     Used, e.g., in installer to force SETUP_LOG messages to go to a file
+//     tr_setup_log.info even if the there is no trconfig.ini file.
+//
+// Not included LogWriters:
+//   StdLogWriter - Logs to stdout or stderr
+//   SubmitToGoogleLogWriter - When done logging submits the log file to
+//     Google's status-receiving server
+class LogWriter {
+ protected:
+  LogWriter();
+  virtual void Cleanup();
+ public:
+  virtual ~LogWriter();
+
+  // Returns true if this Logging object wants to log even if the global
+  // "enable logging" flag is off.  Useful for always creating a log, e.g., an
+  // install log, even without a GoogleUpdate.ini.
+  virtual bool WantsToLogRegardless() const;
+
+  // Returns true if this Logging object wants to handle the message,
+  // regardless of other settings.
+  virtual bool IsCatLevelEnabled(LogCategory category, LogLevel level) const;
+
+  virtual void OutputMessage(const OutputInfo* output_info);
+
+  // Registers and unregisters this LogWriter with the Logging system.  When
+  // registered, the Logging class assumes ownership.
+  bool Register();
+  bool Unregister();
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(LogWriter);
+};
+
+// A LogWriter that writes to a named file.
+class FileLogWriter : public LogWriter {
+ protected:
+  FileLogWriter(const wchar_t* file_name, bool append);
+  ~FileLogWriter();
+  virtual void Cleanup();
+
+ public:
+  static FileLogWriter* Create(const wchar_t* file_name, bool append);
+  virtual void OutputMessage(const OutputInfo* output_info);
+
+ private:
+  void Initialize();
+  bool CreateLoggingMutex();
+  bool CreateLoggingFile();
+  bool ArchiveLoggingFile();
+  bool TruncateLoggingFile();
+  bool GetMutex();
+  void ReleaseMutex();
+
+  // Returns true if archiving of the log file is pending a computer restart.
+  bool IsArchivePending();
+
+  // Returns the first position of str inside of a MULTI_SZ of count characters
+  // including the terminating zeros.
+  static int FindFirstInMultiString(const wchar_t* multi_str,
+                                    size_t count,
+                                    const wchar_t* str);
+
+  uint32 max_file_size_;
+  bool initialized_;
+  bool valid_;
+  bool append_;
+  bool log_file_wide_;
+  CString log_file_mutex_name_;
+  HANDLE log_file_mutex_;
+  CString file_name_;
+  HANDLE log_file_;
+  CString proc_name_;
+
+  friend class FileLogWriterTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(FileLogWriter);
+};
+
+// A LogWriter that uses OutputDebugString() to write messages.
+class OutputDebugStringLogWriter : public LogWriter {
+ protected:
+  OutputDebugStringLogWriter();
+  ~OutputDebugStringLogWriter();
+ public:
+  static OutputDebugStringLogWriter* Create();
+  virtual void OutputMessage(const OutputInfo* info);
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(OutputDebugStringLogWriter);
+};
+
+// A LogWriter that overrides the settings in trconfig.ini and sends messages
+// to another LogWriter.  Takes ownership of the other LogWriter.
+class OverrideConfigLogWriter : public LogWriter {
+ protected:
+  OverrideConfigLogWriter(LogCategory category, LogLevel level,
+                          LogWriter* log_writer, bool force_logging_enabled);
+  virtual void Cleanup();
+ public:
+  static OverrideConfigLogWriter* Create(LogCategory category, LogLevel level,
+    LogWriter* log_writer, bool force_logging_enabled);
+  virtual bool WantsToLogRegardless() const;
+  virtual bool IsCatLevelEnabled(LogCategory category, LogLevel level) const;
+  virtual void OutputMessage(const OutputInfo* output_info);
+ private:
+  LogCategory category_;
+  LogLevel level_;
+  LogWriter* log_writer_;
+  bool force_logging_enabled_;
+  DISALLOW_EVIL_CONSTRUCTORS(OverrideConfigLogWriter);
+};
+
+// The Logging class - Singleton class
+// Fine-grain logging based on categories and levels.
+// Can log to a file, stdout or debugger.
+class Logging {
+ public:
+  // constructor
+  Logging();
+
+  // destructor
+  ~Logging();
+
+  // Enables/disables the logging mechanism.  Allows turning logging on/off
+  // in mid-run.  Returns true for success (not for 'logging enabled').
+  void EnableLogging();
+  void DisableLogging();
+
+  // Checks if logging is enabled - and updates logging settings from the
+  // configuration file every kLogSettingsCheckInterval seconds
+  bool IsLoggingEnabled();
+
+  // Checks if logging is already enabled. It does not try to enable it.
+  bool IsLoggingAlreadyEnabled() const;
+
+  // Overrides the config file settings for showing the time stamps.
+  void ForceShowTimestamp(bool force_show_time);
+
+  // Checks if logging is enabled for a given category and level.
+  DWORD IsCatLevelEnabled(LogCategory category, LogLevel level);
+  LogLevel GetCatLevel(LogCategory category) const;
+
+  // Logs a message.
+  void LogMessage(LogCategory cat, LogLevel level, const wchar_t* fmt, ...);
+  void LogMessageVA(LogCategory cat, LogLevel level, const wchar_t* fmt,
+                    va_list args);
+
+  // Retrieves the default location of the log directory.
+  CString GetDefaultLogDirectory() const;
+
+  // Computes and returns the complete path of the log file.
+  CString GetLogFilePath() const;
+
+  // Retrieves in-memory history buffer.
+  CString GetHistory();
+
+  // Returns the file path of the current GoogleUpdate.ini.
+  CString GetCurrentConfigurationFilePath() const;
+
+  const CString& proc_name() const { return proc_name_; }
+
+  bool IsCategoryEnabledForBuffering(LogCategory cat);
+ private:
+  bool InternalInitialize();
+  void InternalLogMessageMaskedVA(DWORD writer_mask,
+                                  LogCategory cat,
+                                  LogLevel level,
+                                  CString* log_buffer,
+                                  CString* prefix,
+                                  const wchar_t* fmt,
+                                  va_list args);
+
+  friend class LoggingHelper;
+  void LogMessageMaskedVA(DWORD writer_mask, LogCategory cat, LogLevel level,
+                          const wchar_t* fmt, va_list args);
+
+  // Stores log message in in-memory history buffer.
+  void StoreInHistory(const OutputInfo* output_info);
+
+  // Appends string to in-memory history buffer.
+  void AppendToHistory(const wchar_t* msg);
+
+  // Initializes the logging engine. Harmless to call multiple times.
+  bool InitializeLogging();
+
+  // Configures/unconfigures the log writers for the current settings.  That
+  // is, given the current settings from GoogleUpdate.ini, either initializes
+  // and registers the file-out and debug-out logwriters, or unregisters them.
+  bool ConfigureLogging();
+  void UnconfigureLogging();
+
+  void UpdateCatAndLevel(const wchar_t* cat_name, LogCategory cat);
+  void ReadLoggingSettings();
+
+  // Returns the primary file path of the GoogleUpdate.ini.
+  CString GetConfigurationFilePath() const;
+
+  // Returns the alternate file path of the GoogleUpdate.ini.
+  CString GetAltConfigurationFilePath() const;
+
+ public:
+
+  // Passes the messages along to other OutputMessage()
+  void OutputMessage(DWORD writer_mask, LogCategory cat, LogLevel level,
+                     const wchar_t* msg1, const wchar_t* msg2);
+
+  // Broadcasts the message to each LogWriter.
+  // It should be private but the function we want to be able to use this,
+  // debugASSERT is extern "C" and thus can't be declared a friend of
+  // Logging.
+  void OutputMessage(DWORD writer_mask, const OutputInfo* output_info);
+
+ private:
+
+  CategoryInfo category_list_[LC_MAX_CAT];
+
+  // Checks if logging is initialized.
+  bool logging_initialized_;
+
+  // Is logging in the process of initializing?
+  bool is_initializing_;
+
+  // The logging process name including the calling module.
+  CString proc_name_;
+
+  // Serializes changing logging init/uninit/enable/disable status.
+  LLock lock_;
+
+  // Bunch of settings from the config .ini file.
+  bool logging_enabled_;     // Checks if logging is enabled.
+  bool force_show_time_;
+  bool show_time_;
+  bool log_to_file_;
+  CString log_file_name_;
+  bool log_to_debug_out_;
+  bool append_to_file_;
+
+  // Signals the logging system is shutting down.
+  bool logging_shutdown_;
+
+  // Checkpoint time for dynamic category updates.
+  time64 g_last_category_check_time;
+
+  // The file path of the optional ini file which defines the logging
+  // configuration.
+  CString config_file_path_;
+
+ private:
+  bool InternalRegisterWriter(LogWriter* log_writer);
+  bool InternalUnregisterWriter(LogWriter* log_writer);
+
+ public:
+  bool RegisterWriter(LogWriter* log_writer);
+  bool UnregisterWriter(LogWriter* log_writer);
+  enum { all_writers_mask = -1 };
+
+ private:
+  enum { max_writers = 15 };
+  int num_writers_;
+  LogWriter* writers_[max_writers];
+
+  LogWriter* file_log_writer_;
+  LogWriter* debug_out_writer_;
+
+  friend class HistoryTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Logging);
+};
+
+// In order to make the logging macro LC_LOG work out we need to pass a
+// parameter (the mask of loggers to write to) (*) to the actual logging
+// method. However, the last parameter to the macro LC_LOG has its own
+// parenthesis - it encloses multiple expressions (a format string and
+// arguments). So this function object is used as an intermediary in order to
+// hold the writer mask.
+//
+// (*) The mask needs to be transferred separately because we want to keep the
+// LC_LOG structure of asking if the message is going to be logged before
+// evaluating the arguments, and we can't store it in the singleton Logging
+// object - wouldn't be thread-safe.
+
+class LoggingHelper {
+ public:
+  LoggingHelper(Logging* logger, LogCategory cat,
+                LogLevel level, DWORD writer_mask)
+      : logger_(logger),
+        category_(cat),
+        level_(level),
+        writer_mask_(writer_mask) {}
+
+  void operator()(const wchar_t* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    logger_->LogMessageMaskedVA(writer_mask_, category_, level_, fmt, args);
+    va_end(args);
+  }
+
+ private:
+  Logging* logger_;
+  DWORD writer_mask_;
+  LogLevel level_;
+  LogCategory category_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(LoggingHelper);
+};
+
+// Getter for the Logging singleton class.
+Logging* GetLogging();
+
+#endif  // LOGGING
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_LOGGING_H__
diff --git a/common/logging/build.scons b/common/logging/build.scons
index ac5ea8c..a74fd8b 100644
--- a/common/logging/build.scons
+++ b/common/logging/build.scons
@@ -1,38 +1,38 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-#

-# Build the googleclient port of the logging module.

-#

-logging_env = env.Clone()

-

-target_name = 'logging.lib'

-

-logging_inputs = [

-    'logging.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  logging_inputs += logging_env.EnablePrecompile(target_name)

-

-logging_env.ComponentLibrary(

-    lib_name=target_name,

-    source=logging_inputs,

-)

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+#
+# Build the googleclient port of the logging module.
+#
+logging_env = env.Clone()
+
+target_name = 'logging.lib'
+
+logging_inputs = [
+    'logging.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  logging_inputs += logging_env.EnablePrecompile(target_name)
+
+logging_env.ComponentLibrary(
+    lib_name=target_name,
+    source=logging_inputs,
+)
+
diff --git a/common/logging/logging.cc b/common/logging/logging.cc
index 0d2734b..2101baa 100644
--- a/common/logging/logging.cc
+++ b/common/logging/logging.cc
@@ -1,348 +1,348 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// This is code that defines the backend for the new LogMessage definition

-// and the functions that the client application can call to control logging.

-

-#include <ctime>

-#include <iomanip>

-#include <cstring>

-#include <windows.h>

-#include <tchar.h>

-#include <algorithm>

-#include "omaha/common/logging/logging.h"

-

-namespace logging {

-

-const char* const log_severity_names[LOG_NUM_SEVERITIES] = {

-  "INFO", "WARNING", "ERROR", "FATAL" };

-

-int min_log_level = 0;

-LogLockingState lock_log_file = LOCK_LOG_FILE;

-LoggingDestination logging_destination = LOG_ONLY_TO_FILE;

-

-// which log file to use? This is initialized by InitLogging or

-// will be lazily initialized to the default value when it is

-// first needed.

-TCHAR log_file_name[MAX_PATH] = { 0 };

-

-// this file is lazily opened and the handle may be NULL

-HANDLE log_file = NULL;

-

-// what should be prepended to each message?

-bool log_process_id = false;

-bool log_thread_id = false;

-bool log_timestamp = true;

-bool log_tickcount = false;

-

-// An assert handler override specified by the client to be called instead of

-// the debug message dialog.

-LogAssertHandlerFunction log_assert_handler = NULL;

-

-// The critical section is used if log file locking is false. It helps us

-// avoid problems with multiple threads writing to the log file at the same

-// time.

-bool initialized_critical_section = false;

-CRITICAL_SECTION log_critical_section;

-

-// When we don't use a critical section, we are using a global mutex. We

-// need to do this because LockFileEx is not thread safe

-HANDLE log_mutex = NULL;

-

-void InitLogMutex() {

-  if (!log_mutex) {

-    // \ is not a legal character in mutex names so we replace \ with /

-    std::wstring safe_name(log_file_name);

-    std::replace(safe_name.begin(), safe_name.end(), '\\', '/');

-    std::wstring t(L"Global\\");

-    t.append(safe_name);

-    log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());

-  }

-}

-

-void InitLogging(const TCHAR* new_log_file, LoggingDestination logging_dest,

-                 LogLockingState lock_log, OldFileDeletionState delete_old) {

-  if (log_file) {

-    // calling InitLogging twice or after some log call has already opened the

-    // default log file will re-initialize to the new options

-    CloseHandle(log_file);

-    log_file = NULL;

-  }

-

-  lock_log_file = lock_log;

-  logging_destination = logging_dest;

-

-  // ignore file options if logging is only to system

-  if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)

-    return;

-

-  _tcsncpy(log_file_name, new_log_file, MAX_PATH);

-  log_file_name[MAX_PATH - 1] = _T('\0');

-  if (delete_old == DELETE_OLD_LOG_FILE)

-    DeleteFile(log_file_name);

-

-  if (lock_log_file == LOCK_LOG_FILE) {

-    InitLogMutex();

-  } else if (!initialized_critical_section) {

-    // initialize the critical section

-    InitializeCriticalSection(&log_critical_section);

-    initialized_critical_section = true;

-  }

-}

-

-void SetMinLogLevel(int level) {

-  min_log_level = level;

-}

-

-void SetLogItems(bool enable_process_id, bool enable_thread_id,

-                 bool enable_timestamp, bool enable_tickcount) {

-  log_process_id = enable_process_id;

-  log_thread_id = enable_thread_id;

-  log_timestamp = enable_timestamp;

-  log_tickcount = enable_tickcount;

-}

-

-void SetLogAssertHandler(LogAssertHandlerFunction handler) {

-  log_assert_handler = handler;

-}

-

-// Called by logging functions to ensure that debug_file is initialized

-// and can be used for writing. Returns false if the file could not be

-// initialized. debug_file will be NULL in this case.

-bool VerifyLogFileHandle() {

-  if (log_file)

-    return true;

-

-  if (!log_file_name[0]) {

-    // nobody has called InitLogging to specify a debug log file, so here we

-    // initialize the log file name to the default

-    GetModuleFileName(NULL, log_file_name, MAX_PATH);

-    TCHAR* last_backslash = _tcsrchr(log_file_name, '\\');

-    if (last_backslash)

-      last_backslash[1] = 0; // name now ends with the backslash

-    _tcscat(log_file_name, _T("debug.log"));

-  }

-

-  log_file = CreateFile(log_file_name, GENERIC_WRITE,

-                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,

-                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

-  if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {

-    log_file = NULL;

-    return false;

-  }

-  SetFilePointer(log_file, 0, 0, FILE_END);

-  return true;

-}

-

-// Displays a message box to the user with the error message in it. For

-// Windows programs, it's possible that the message loop is messed up on

-// a fatal error, and creating a MessageBox will cause that message loop

-// to be run. Instead, we try to spawn another process that displays its

-// command line. We look for "Debug Message.exe" in the same directory as

-// the application. If it exists, we use it, otherwise, we use a regular

-// message box.

-void DisplayDebugMessage(const std::string& str) {

-  if (str.empty())

-    return;

-

-  // look for the debug dialog program next to our application

-  wchar_t prog_name[MAX_PATH];

-  GetModuleFileNameW(NULL, prog_name, MAX_PATH);

-  wchar_t* backslash = wcsrchr(prog_name, '\\');

-  if (backslash)

-    backslash[1] = 0;

-  wcsncat(prog_name, L"DebugMessage.exe", MAX_PATH);

-  prog_name[MAX_PATH - 1] = L'\0';

-

-  // stupid CreateProcess requires a non-const command line and may modify it.

-  // We also want to use the wide string

-  int charcount = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);

-  if (!charcount)

-    return;

-  scoped_array<wchar_t> cmdline(new wchar_t[charcount]);

-  if (!MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, cmdline.get(),

-      charcount))

-    return;

-

-  STARTUPINFO startup_info;

-  memset(&startup_info, 0, sizeof(startup_info));

-  startup_info.cb = sizeof(startup_info);

-

-  PROCESS_INFORMATION process_info;

-  if (CreateProcessW(prog_name, cmdline.get(), NULL, NULL, false, 0, NULL,

-                     NULL, &startup_info, &process_info)) {

-    WaitForSingleObject(process_info.hProcess, INFINITE);

-    CloseHandle(process_info.hThread);

-    CloseHandle(process_info.hProcess);

-  } else {

-    // debug process broken, let's just do a message box

-    MessageBoxW(NULL, cmdline.get(), L"Fatal error", MB_OK | MB_ICONHAND);

-  }

-}

-

-LogMessage::LogMessage(const char* file, int line, LogSeverity severity, int)

-    : severity_(severity) {

-  Init(file, line);

-}

-

-LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)

-    : severity_(LOG_FATAL) {

-  Init(file, line);

-  stream_ << "Check failed: " << (*result.str_);

-}

-

-LogMessage::LogMessage(const char* file, int line)

-     : severity_(LOG_INFO) {

-  Init(file, line);

-}

-

-LogMessage::LogMessage(const char* file, int line, LogSeverity severity)

-    : severity_(severity) {

-  Init(file, line);

-}

-

-// writes the common header info to the stream

-void LogMessage::Init(const char* file, int line) {

-  // log only the filename

-  const char* last_slash = strrchr(file, '\\');

-  if (last_slash)

-    file = last_slash + 1;

-

-  // TODO(omaha): It might be nice if the columns were fixed width.

-

-  stream_ <<  '[';

-  if (log_process_id)

-    stream_ << GetCurrentProcessId() << ':';

-  if (log_thread_id)

-    stream_ << GetCurrentThreadId() << ':';

-  if (log_timestamp) {

-    time_t t = time(NULL);

-#if _MSC_VER >= 1400

-    struct tm local_time = {0};

-    localtime_s(&local_time, &t);

-    struct tm* tm_time = &local_time;

-#else

-    struct tm* tm_time = localtime(&t);

-#endif

-    stream_ << std::setfill('0')

-            << std::setw(2) << 1 + tm_time->tm_mon

-            << std::setw(2) << tm_time->tm_mday

-            << '/'

-            << std::setw(2) << tm_time->tm_hour

-            << std::setw(2) << tm_time->tm_min

-            << std::setw(2) << tm_time->tm_sec

-            << ':';

-  }

-  if (log_tickcount)

-    stream_ << GetTickCount() << ':';

-  stream_ << log_severity_names[severity_] << ":" << file << "(" << line

-      << ")] ";

-}

-

-LogMessage::~LogMessage() {

-  // TODO(omaha) modify the macros so that nothing is executed when the log

-  // level is too high or there is

-  if (severity_ < min_log_level)

-    return;

-

-  std::string str_newline(stream_.str(), stream_.pcount());

-  str_newline.append("\r\n");

-  if (logging_destination != LOG_ONLY_TO_FILE)

-    OutputDebugStringA(str_newline.c_str());

-

-  // write to log file

-  if (logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&

-      VerifyLogFileHandle()) {

-    // we can have multiple threads and/or processes, so try to prevent them

-    // from clobbering each other's writes

-    if (lock_log_file == LOCK_LOG_FILE) {

-      // Ensure that the mutex is initialized in case the client app did not

-      // call InitLogging. This is not thread safe. See below

-      InitLogMutex();

-

-      DWORD r = ::WaitForSingleObject(log_mutex, INFINITE);

-      DCHECK(r != WAIT_ABANDONED);

-    } else {

-      // use the critical section

-      if (!initialized_critical_section) {

-        // The client app did not call InitLogging, and so the critical section

-        // has not been created. We do this on demand, but if two threads try to

-        // do this at the same time, there will be a race condition to create

-        // the critical section. This is why InitLogging should be called from

-        // the main thread at the beginning of execution.

-        InitializeCriticalSection(&log_critical_section);

-        initialized_critical_section = true;

-      }

-      EnterCriticalSection(&log_critical_section);

-    }

-

-    SetFilePointer(log_file, 0, 0, SEEK_END);

-    DWORD num_written;

-    WriteFile(log_file, (void*)str_newline.c_str(), (DWORD)str_newline.length(),

-              &num_written, NULL);

-

-    if (lock_log_file == LOCK_LOG_FILE) {

-      ReleaseMutex(log_mutex);

-    } else {

-      LeaveCriticalSection(&log_critical_section);

-    }

-  }

-

-  if (severity_ == LOG_FATAL) {

-    // display a message or break into the debugger on a fatal error

-    if (::IsDebuggerPresent()) {

-      DebugBreak();

-    } else {

-      if (log_assert_handler) {

-        log_assert_handler(std::string(stream_.str(), stream_.pcount()));

-      } else {

-        // don't use the string with the newline, get a fresh version to send to

-        // the debug message process

-        DisplayDebugMessage(std::string(stream_.str(), stream_.pcount()));

-        TerminateProcess(GetCurrentProcess(), 1);

-      }

-    }

-  }

-

-  // Calling stream_.str() freezes the stream buffer.  A frozen buffer will

-  // not be freed during strstreambuf destruction.

-  stream_.freeze(false);

-}

-

-void CloseLogFile() {

-  if (!log_file)

-    return;

-

-  CloseHandle(log_file);

-  log_file = NULL;

-}

-

-} // namespace logging

-

-std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {

-  if (!wstr || !wstr[0])

-    return out;

-

-  // compute the length of the buffer we'll need

-  int charcount = WideCharToMultiByte(CP_UTF8, 0, wstr, -1,

-                                      NULL, 0, NULL, NULL);

-  if (charcount == 0)

-    return out;

-

-  // convert

-  scoped_array<char> buf(new char[charcount]);

-  WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buf.get(), charcount, NULL, NULL);

-  return out << buf.get();

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// This is code that defines the backend for the new LogMessage definition
+// and the functions that the client application can call to control logging.
+
+#include <ctime>
+#include <iomanip>
+#include <cstring>
+#include <windows.h>
+#include <tchar.h>
+#include <algorithm>
+#include "omaha/common/logging/logging.h"
+
+namespace logging {
+
+const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
+  "INFO", "WARNING", "ERROR", "FATAL" };
+
+int min_log_level = 0;
+LogLockingState lock_log_file = LOCK_LOG_FILE;
+LoggingDestination logging_destination = LOG_ONLY_TO_FILE;
+
+// which log file to use? This is initialized by InitLogging or
+// will be lazily initialized to the default value when it is
+// first needed.
+TCHAR log_file_name[MAX_PATH] = { 0 };
+
+// this file is lazily opened and the handle may be NULL
+HANDLE log_file = NULL;
+
+// what should be prepended to each message?
+bool log_process_id = false;
+bool log_thread_id = false;
+bool log_timestamp = true;
+bool log_tickcount = false;
+
+// An assert handler override specified by the client to be called instead of
+// the debug message dialog.
+LogAssertHandlerFunction log_assert_handler = NULL;
+
+// The critical section is used if log file locking is false. It helps us
+// avoid problems with multiple threads writing to the log file at the same
+// time.
+bool initialized_critical_section = false;
+CRITICAL_SECTION log_critical_section;
+
+// When we don't use a critical section, we are using a global mutex. We
+// need to do this because LockFileEx is not thread safe
+HANDLE log_mutex = NULL;
+
+void InitLogMutex() {
+  if (!log_mutex) {
+    // \ is not a legal character in mutex names so we replace \ with /
+    std::wstring safe_name(log_file_name);
+    std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
+    std::wstring t(L"Global\\");
+    t.append(safe_name);
+    log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
+  }
+}
+
+void InitLogging(const TCHAR* new_log_file, LoggingDestination logging_dest,
+                 LogLockingState lock_log, OldFileDeletionState delete_old) {
+  if (log_file) {
+    // calling InitLogging twice or after some log call has already opened the
+    // default log file will re-initialize to the new options
+    CloseHandle(log_file);
+    log_file = NULL;
+  }
+
+  lock_log_file = lock_log;
+  logging_destination = logging_dest;
+
+  // ignore file options if logging is only to system
+  if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
+    return;
+
+  _tcsncpy(log_file_name, new_log_file, MAX_PATH);
+  log_file_name[MAX_PATH - 1] = _T('\0');
+  if (delete_old == DELETE_OLD_LOG_FILE)
+    DeleteFile(log_file_name);
+
+  if (lock_log_file == LOCK_LOG_FILE) {
+    InitLogMutex();
+  } else if (!initialized_critical_section) {
+    // initialize the critical section
+    InitializeCriticalSection(&log_critical_section);
+    initialized_critical_section = true;
+  }
+}
+
+void SetMinLogLevel(int level) {
+  min_log_level = level;
+}
+
+void SetLogItems(bool enable_process_id, bool enable_thread_id,
+                 bool enable_timestamp, bool enable_tickcount) {
+  log_process_id = enable_process_id;
+  log_thread_id = enable_thread_id;
+  log_timestamp = enable_timestamp;
+  log_tickcount = enable_tickcount;
+}
+
+void SetLogAssertHandler(LogAssertHandlerFunction handler) {
+  log_assert_handler = handler;
+}
+
+// Called by logging functions to ensure that debug_file is initialized
+// and can be used for writing. Returns false if the file could not be
+// initialized. debug_file will be NULL in this case.
+bool VerifyLogFileHandle() {
+  if (log_file)
+    return true;
+
+  if (!log_file_name[0]) {
+    // nobody has called InitLogging to specify a debug log file, so here we
+    // initialize the log file name to the default
+    GetModuleFileName(NULL, log_file_name, MAX_PATH);
+    TCHAR* last_backslash = _tcsrchr(log_file_name, '\\');
+    if (last_backslash)
+      last_backslash[1] = 0; // name now ends with the backslash
+    _tcscat(log_file_name, _T("debug.log"));
+  }
+
+  log_file = CreateFile(log_file_name, GENERIC_WRITE,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+  if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
+    log_file = NULL;
+    return false;
+  }
+  SetFilePointer(log_file, 0, 0, FILE_END);
+  return true;
+}
+
+// Displays a message box to the user with the error message in it. For
+// Windows programs, it's possible that the message loop is messed up on
+// a fatal error, and creating a MessageBox will cause that message loop
+// to be run. Instead, we try to spawn another process that displays its
+// command line. We look for "Debug Message.exe" in the same directory as
+// the application. If it exists, we use it, otherwise, we use a regular
+// message box.
+void DisplayDebugMessage(const std::string& str) {
+  if (str.empty())
+    return;
+
+  // look for the debug dialog program next to our application
+  wchar_t prog_name[MAX_PATH];
+  GetModuleFileNameW(NULL, prog_name, MAX_PATH);
+  wchar_t* backslash = wcsrchr(prog_name, '\\');
+  if (backslash)
+    backslash[1] = 0;
+  wcsncat(prog_name, L"DebugMessage.exe", MAX_PATH);
+  prog_name[MAX_PATH - 1] = L'\0';
+
+  // stupid CreateProcess requires a non-const command line and may modify it.
+  // We also want to use the wide string
+  int charcount = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
+  if (!charcount)
+    return;
+  scoped_array<wchar_t> cmdline(new wchar_t[charcount]);
+  if (!MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, cmdline.get(),
+      charcount))
+    return;
+
+  STARTUPINFO startup_info;
+  memset(&startup_info, 0, sizeof(startup_info));
+  startup_info.cb = sizeof(startup_info);
+
+  PROCESS_INFORMATION process_info;
+  if (CreateProcessW(prog_name, cmdline.get(), NULL, NULL, false, 0, NULL,
+                     NULL, &startup_info, &process_info)) {
+    WaitForSingleObject(process_info.hProcess, INFINITE);
+    CloseHandle(process_info.hThread);
+    CloseHandle(process_info.hProcess);
+  } else {
+    // debug process broken, let's just do a message box
+    MessageBoxW(NULL, cmdline.get(), L"Fatal error", MB_OK | MB_ICONHAND);
+  }
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity, int)
+    : severity_(severity) {
+  Init(file, line);
+}
+
+LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
+    : severity_(LOG_FATAL) {
+  Init(file, line);
+  stream_ << "Check failed: " << (*result.str_);
+}
+
+LogMessage::LogMessage(const char* file, int line)
+     : severity_(LOG_INFO) {
+  Init(file, line);
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
+    : severity_(severity) {
+  Init(file, line);
+}
+
+// writes the common header info to the stream
+void LogMessage::Init(const char* file, int line) {
+  // log only the filename
+  const char* last_slash = strrchr(file, '\\');
+  if (last_slash)
+    file = last_slash + 1;
+
+  // TODO(omaha): It might be nice if the columns were fixed width.
+
+  stream_ <<  '[';
+  if (log_process_id)
+    stream_ << GetCurrentProcessId() << ':';
+  if (log_thread_id)
+    stream_ << GetCurrentThreadId() << ':';
+  if (log_timestamp) {
+    time_t t = time(NULL);
+#if _MSC_VER >= 1400
+    struct tm local_time = {0};
+    localtime_s(&local_time, &t);
+    struct tm* tm_time = &local_time;
+#else
+    struct tm* tm_time = localtime(&t);
+#endif
+    stream_ << std::setfill('0')
+            << std::setw(2) << 1 + tm_time->tm_mon
+            << std::setw(2) << tm_time->tm_mday
+            << '/'
+            << std::setw(2) << tm_time->tm_hour
+            << std::setw(2) << tm_time->tm_min
+            << std::setw(2) << tm_time->tm_sec
+            << ':';
+  }
+  if (log_tickcount)
+    stream_ << GetTickCount() << ':';
+  stream_ << log_severity_names[severity_] << ":" << file << "(" << line
+      << ")] ";
+}
+
+LogMessage::~LogMessage() {
+  // TODO(omaha) modify the macros so that nothing is executed when the log
+  // level is too high or there is
+  if (severity_ < min_log_level)
+    return;
+
+  std::string str_newline(stream_.str(), stream_.pcount());
+  str_newline.append("\r\n");
+  if (logging_destination != LOG_ONLY_TO_FILE)
+    OutputDebugStringA(str_newline.c_str());
+
+  // write to log file
+  if (logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
+      VerifyLogFileHandle()) {
+    // we can have multiple threads and/or processes, so try to prevent them
+    // from clobbering each other's writes
+    if (lock_log_file == LOCK_LOG_FILE) {
+      // Ensure that the mutex is initialized in case the client app did not
+      // call InitLogging. This is not thread safe. See below
+      InitLogMutex();
+
+      DWORD r = ::WaitForSingleObject(log_mutex, INFINITE);
+      DCHECK(r != WAIT_ABANDONED);
+    } else {
+      // use the critical section
+      if (!initialized_critical_section) {
+        // The client app did not call InitLogging, and so the critical section
+        // has not been created. We do this on demand, but if two threads try to
+        // do this at the same time, there will be a race condition to create
+        // the critical section. This is why InitLogging should be called from
+        // the main thread at the beginning of execution.
+        InitializeCriticalSection(&log_critical_section);
+        initialized_critical_section = true;
+      }
+      EnterCriticalSection(&log_critical_section);
+    }
+
+    SetFilePointer(log_file, 0, 0, SEEK_END);
+    DWORD num_written;
+    WriteFile(log_file, (void*)str_newline.c_str(), (DWORD)str_newline.length(),
+              &num_written, NULL);
+
+    if (lock_log_file == LOCK_LOG_FILE) {
+      ReleaseMutex(log_mutex);
+    } else {
+      LeaveCriticalSection(&log_critical_section);
+    }
+  }
+
+  if (severity_ == LOG_FATAL) {
+    // display a message or break into the debugger on a fatal error
+    if (::IsDebuggerPresent()) {
+      DebugBreak();
+    } else {
+      if (log_assert_handler) {
+        log_assert_handler(std::string(stream_.str(), stream_.pcount()));
+      } else {
+        // don't use the string with the newline, get a fresh version to send to
+        // the debug message process
+        DisplayDebugMessage(std::string(stream_.str(), stream_.pcount()));
+        TerminateProcess(GetCurrentProcess(), 1);
+      }
+    }
+  }
+
+  // Calling stream_.str() freezes the stream buffer.  A frozen buffer will
+  // not be freed during strstreambuf destruction.
+  stream_.freeze(false);
+}
+
+void CloseLogFile() {
+  if (!log_file)
+    return;
+
+  CloseHandle(log_file);
+  log_file = NULL;
+}
+
+} // namespace logging
+
+std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
+  if (!wstr || !wstr[0])
+    return out;
+
+  // compute the length of the buffer we'll need
+  int charcount = WideCharToMultiByte(CP_UTF8, 0, wstr, -1,
+                                      NULL, 0, NULL, NULL);
+  if (charcount == 0)
+    return out;
+
+  // convert
+  scoped_array<char> buf(new char[charcount]);
+  WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buf.get(), charcount, NULL, NULL);
+  return out << buf.get();
+}
diff --git a/common/logging/logging.h b/common/logging/logging.h
index 3da64d4..4008561 100644
--- a/common/logging/logging.h
+++ b/common/logging/logging.h
@@ -1,499 +1,499 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_LOGGING_LOGGING_H__

-#define OMAHA_COMMON_LOGGING_LOGGING_H__

-

-#include <string>

-#include <cstring>

-#include <strstream>

-#include <tchar.h>

-

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-

-// This file provides logging facility for Windows client apps.

-//

-// Optional message capabilities

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

-// Assertion failed messages and fatal errors are displayed in a dialog box

-// before the application exits. However, running this UI creates a message

-// loop, which causes application messages to be processed and potentially

-// dispatched to existing application windows. Since the application is in a

-// bad state when this assertion dialog is displayed, these messages may not

-// get processed and hang the dialog, or the application might go crazy.

-//

-// Therefore, it can be beneficial to display the error dialog in a separate

-// process from the main application. When the logging system needs to display

-// a fatal error dialog box, it will look for a program called

-// "DebugMessage.exe" in the same directory as the application executable. It

-// will run this application with the message as the command line, and will

-// not include the name of the application as is traditional for easier

-// parsing.

-//

-// The code for DebugMessage.exe is only one line. In WinMain, do:

-//   MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);

-//

-// If DebugMessage.exe is not found, the logging code will use a normal

-// MessageBox, potentially causing the problems discussed above.

-

-

-// Instructions

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

-//

-// Make a bunch of macros for logging.  The way to log things is to stream

-// things to LOG(<a particular severity level>).  E.g.,

-//

-//   LOG(INFO) << "Found " << num_cookies << " cookies";

-//

-// You can also do conditional logging:

-//

-//   LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";

-//

-// The above will cause log messages to be output on the 1st, 11th, 21st, ...

-// times it is executed.  Note that the special COUNTER value is used to

-// identify which repetition is happening.

-//

-// The CHECK(condition) macro is active in both debug and release builds and

-// effectively performs a LOG(FATAL) which terminates the process and

-// generates a crashdump unless a debugger is attached.

-//

-// There are also "debug mode" logging macros like the ones above:

-//

-//   DLOG(INFO) << "Found cookies";

-//

-//   DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";

-//

-// All "debug mode" logging is compiled away to nothing for non-debug mode

-// compiles.  LOG_IF and development flags also work well together

-// because the code can be compiled away sometimes.

-//

-// We also have

-//

-//   LOG_ASSERT(assertion);

-//   DLOG_ASSERT(assertion);

-//

-// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;

-//

-// We also override the standard 'assert' to use 'DLOG_ASSERT'.

-//

-// The supported severity levels for macros that allow you to specify one

-// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.

-//

-// There is also the special severity of DFATAL, which logs FATAL in

-// debug mode, ERROR in normal mode.

-//

-// Very important: logging a message at the FATAL severity level causes

-// the program to terminate (after the message is logged).

-

-namespace logging {

-

-// Where to record logging output? A flat file and/or system debug log via

-// OutputDebugString. Defaults to LOG_ONLY_TO_FILE.

-enum LoggingDestination { LOG_ONLY_TO_FILE, 

-                          LOG_ONLY_TO_SYSTEM_DEBUG_LOG,

-                          LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG };

-

-// Indicates that the log file should be locked when being written to.

-// Often, there is no locking, which is fine for a single threaded program.

-// If logging is being done from multiple threads or there can be more than

-// one process doing the logging, the file should be locked during writes to

-// make each log outut atomic. Other writers will block.

-//

-// All processes writing to the log file must have their locking set for it to

-// work properly. Defaults to DONT_LOCK_LOG_FILE.

-enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };

-

-// On startup, should we delete or append to an existing log file (if any)?

-// Defaults to APPEND_TO_OLD_LOG_FILE.

-enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };

-

-// Sets the log file name and other global logging state. Calling this function

-// is recommended, and is normally done at the beginning of application init.

-// If you don't call it, all the flags will be initialized to their default

-// values, and there is a race condition that may leak a critical section

-// object if two threads try to do the first log at the same time.

-// See the definition of the enums above for descriptions and default values.

-//

-// The default log file is initialized to "debug.log" in the application

-// directory. You probably don't want this, especially since the program

-// directory may not be writable on an enduser's system.

-void InitLogging(const TCHAR* log_file, LoggingDestination logging_dest,

-                 LogLockingState lock_log, OldFileDeletionState delete_old);

-

-// Sets the log level. Anything at or above this level will be written to the

-// log file/displayed to the user (if applicable). Anything below this level

-// will be silently ignored. The log level defaults to 0 (everything is logged)

-// if this function is not called.

-void SetMinLogLevel(int level);

-

-// Sets the common items you want to be prepended to each log message.

-// process and thread IDs default to off, the timestamp defaults to on.

-// If this function is not called, logging defaults to writing the timestamp

-// only.

-void SetLogItems(bool enable_process_id, bool enable_thread_id,

-                 bool enable_timestamp, bool enable_tickcount);

-

-// Sets the Log Assert Handler that will be used to notify of check failures.

-// The default handler shows a dialog box, however clients can use this 

-// function to override with their own handling (e.g. a silent one for Unit

-// Tests)

-typedef void (*LogAssertHandlerFunction)(const std::string& str);

-void SetLogAssertHandler(LogAssertHandlerFunction handler);

-

-typedef int LogSeverity;

-const LogSeverity LOG_INFO = 0;

-const LogSeverity LOG_WARNING = 1;

-const LogSeverity LOG_ERROR = 2;

-const LogSeverity LOG_FATAL = 3;

-const LogSeverity LOG_NUM_SEVERITIES = 4;

-

-// LOG_DFATAL_LEVEL is LOG_FATAL in debug mode, ERROR in normal mode

-#ifdef NDEBUG

-const LogSeverity LOG_DFATAL_LEVEL = LOG_ERROR;

-#else

-const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL;

-#endif

-

-// A few definitions of macros that don't generate much code. These are used

-// by LOG() and LOG_IF, etc. Since these are used all over our code, it's

-// better to have compact code for these operations.

-#define COMPACT_GOOGLE_LOG_INFO \

-  logging::LogMessage(__FILE__, __LINE__)

-#define COMPACT_GOOGLE_LOG_WARNING \

-  logging::LogMessage(__FILE__, __LINE__, logging::LOG_WARNING)

-#define COMPACT_GOOGLE_LOG_ERROR \

-  logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR)

-#define COMPACT_GOOGLE_LOG_FATAL \

-  logging::LogMessage(__FILE__, __LINE__, logging::LOG_FATAL)

-#define COMPACT_GOOGLE_LOG_DFATAL \

-  logging::LogMessage(__FILE__, __LINE__, logging::LOG_DFATAL_LEVEL)

-

-// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets

-// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us

-// to keep using this syntax, we define this macro to do the same thing

-// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that

-// the Windows SDK does for consistency.

-#define ERROR 0

-#define COMPACT_GOOGLE_LOG_0 \

-  logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR)

-

-// We use the preprocessor's merging operator, "##", so that, e.g.,

-// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO.  There's some funny

-// subtle difference between ostream member streaming functions (e.g.,

-// ostream::operator<<(int) and ostream non-member streaming functions

-// (e.g., ::operator<<(ostream&, string&): it turns out that it's

-// impossible to stream something like a string directly to an unnamed

-// ostream. We employ a neat hack by calling the stream() member

-// function of LogMessage which seems to avoid the problem.

-

-#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()

-#define SYSLOG(severity) LOG(severity)

-

-#define LOG_IF(severity, condition) \

-  !(condition) ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)

-#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)

-

-#define LOG_ASSERT(condition)  \

-  LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "

-#define SYSLOG_ASSERT(condition) \

-  SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "

-

-// CHECK dies with a fatal error if condition is not true.  It is *not*

-// controlled by NDEBUG, so the check will be executed regardless of

-// compilation mode.

-#define CHECK(condition) \

-  LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "

-

-// A container for a string pointer which can be evaluated to a bool -

-// true iff the pointer is NULL.

-struct CheckOpString {

-  CheckOpString(std::string* str) : str_(str) { }

-  // No destructor: if str_ is non-NULL, we're about to LOG(FATAL),

-  // so there's no point in cleaning up str_.

-  operator bool() const { return str_ != NULL; }

-  std::string* str_;

-};

-

-// Build the error message string.  This is separate from the "Impl"

-// function template because it is not performance critical and so can

-// be out of line, while the "Impl" code should be inline.

-template<class t1, class t2>

-std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {

-  std::ostrstream ss;

-  ss << names << " (" << v1 << " vs. " << v2 << ")";

-  return new std::string(ss.str(), ss.pcount());

-}

-

-extern std::string* MakeCheckOpStringIntInt(int v1, int v2, const char* names);

-

-template<int, int>

-std::string* MakeCheckOpString(const int& v1, const int& v2, const char* names) {

-  return MakeCheckOpStringIntInt(v1, v2, names);

-}

-

-// Plus some debug-logging macros that get compiled to nothing for production

-//

-// DEBUG_MODE is for uses like

-//   if (DEBUG_MODE) foo.CheckThatFoo();

-// instead of

-//   #ifndef NDEBUG

-//     foo.CheckThatFoo();

-//   #endif

-

-#ifndef NDEBUG

-

-#define DLOG(severity) LOG(severity)

-#define DLOG_IF(severity, condition) LOG_IF(severity, condition)

-#define DLOG_ASSERT(condition) LOG_ASSERT(condition)

-

-// debug-only checking.  not executed in NDEBUG mode.

-enum { DEBUG_MODE = 1 };

-#define DCHECK(condition) \

-  LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "

-

-// Helper functions for DCHECK_OP macro.

-// The (int, int) specialization works around the issue that the compiler

-// will not instantiate the template version of the function on values of

-// unnamed enum type - see comment below.

-#define DEFINE_DCHECK_OP_IMPL(name, op) \

-  template <class t1, class t2> \

-  inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \

-                                        const char* names) { \

-    if (v1 op v2) return NULL; \

-    else return MakeCheckOpString(v1, v2, names); \

-  } \

-  inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \

-    if (v1 op v2) return NULL; \

-    else return MakeCheckOpString(v1, v2, names); \

-  }

-DEFINE_DCHECK_OP_IMPL(EQ, ==)

-DEFINE_DCHECK_OP_IMPL(NE, !=)

-DEFINE_DCHECK_OP_IMPL(LE, <=)

-DEFINE_DCHECK_OP_IMPL(LT, < )

-DEFINE_DCHECK_OP_IMPL(GE, >=)

-DEFINE_DCHECK_OP_IMPL(GT, > )

-#undef DEFINE_DCHECK_OP_IMPL

-

-// Helper macro for binary operators.

-// Don't use this macro directly in your code, use CHECK_EQ et al below.

-#define DCHECK_OP(name, op, val1, val2)  \

-  while (logging::CheckOpString _result = \

-         logging::Check##name##Impl((val1), (val2), #val1 " " #op " " #val2)) \

-    logging::LogMessage(__FILE__, __LINE__, _result).stream()

-

-// Equality/Inequality checks - compare two values, and log a LOG_FATAL message

-// including the two values when the result is not as expected.  The values

-// must have operator<<(ostream, ...) defined.

-//

-// You may append to the error message like so:

-//   CHECK_NE(1, 2) << ": The world must be ending!";

-//

-// We are very careful to ensure that each argument is evaluated exactly

-// once, and that anything which is legal to pass as a function argument is

-// legal here.  In particular, the arguments may be temporary expressions

-// which will end up being destroyed at the end of the apparent statement,

-// for example:

-//   CHECK_EQ(string("abc")[1], 'b');

-//

-// WARNING: These don't compile correctly if one of the arguments is a pointer

-// and the other is NULL. To work around this, simply static_cast NULL to the

-// type of the desired pointer.

-

-#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)

-#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)

-#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)

-#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)

-#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)

-#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)

-

-// Helper functions for string comparisons.

-// To avoid bloat, the definitions are in logging.cc.

-#define DECLARE_DCHECK_STROP_IMPL(func, expected) \

-  std::string* Check##func##expected##Impl(const char* s1, \

-                                           const char* s2, \

-                                           const char* names);

-DECLARE_DCHECK_STROP_IMPL(strcmp, true)

-DECLARE_DCHECK_STROP_IMPL(strcmp, false)

-DECLARE_DCHECK_STROP_IMPL(_stricmp, true)

-DECLARE_DCHECK_STROP_IMPL(_stricmp, false)

-#undef DECLARE_DCHECK_STROP_IMPL

-

-// Helper macro for string comparisons.

-// Don't use this macro directly in your code, use CHECK_STREQ et al below.

-#define DCHECK_STROP(func, op, expected, s1, s2) \

-  while (CheckOpString _result = \

-      logging::Check##func##expected##Impl((s1), (s2), \

-                                           #s1 " " #op " " #s2)) \

-    LOG(FATAL) << *_result.str_

-

-// String (char*) equality/inequality checks.

-// CASE versions are case-insensitive.

-//

-// Note that "s1" and "s2" may be temporary strings which are destroyed

-// by the compiler at the end of the current "full expression"

-// (e.g. DCHECK_STREQ(Foo().c_str(), Bar().c_str())).

-

-#define DCHECK_STREQ(s1, s2) DCHECK_STROP(strcmp, ==, true, s1, s2)

-#define DCHECK_STRNE(s1, s2) DCHECK_STROP(strcmp, !=, false, s1, s2)

-#define DCHECK_STRCASEEQ(s1, s2) DCHECK_STROP(_stricmp, ==, true, s1, s2)

-#define DCHECK_STRCASENE(s1, s2) DCHECK_STROP(_stricmp, !=, false, s1, s2)

-

-#define DCHECK_INDEX(I,A) DCHECK(I < (sizeof(A)/sizeof(A[0])))

-#define DCHECK_BOUND(B,A) DCHECK(B <= (sizeof(A)/sizeof(A[0])))

-

-#else  // NDEBUG

-

-#define DLOG(severity) \

-  true ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)

-

-#define DLOG_IF(severity, condition) \

-  true ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)

-

-#define DLOG_ASSERT(condition) \

-  true ? (void) 0 : LOG_ASSERT(condition)

-

-enum { DEBUG_MODE = 0 };

-

-// This macro can be followed by a sequence of stream parameters in

-// non-debug mode. The DCHECK and friends macros use this so that

-// the expanded expression DCHECK(foo) << "asdf" is still syntactically

-// valid, even though the expression will get optimized away.

-#define NDEBUG_EAT_STREAM_PARAMETERS \

-  logging::LogMessage(__FILE__, __LINE__).stream()

-

-#define DCHECK(condition) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#define DCHECK_EQ(val1, val2) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#define DCHECK_NE(val1, val2) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#define DCHECK_LE(val1, val2) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#define DCHECK_LT(val1, val2) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#define DCHECK_GE(val1, val2) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#define DCHECK_GT(val1, val2) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#define DCHECK_STREQ(str1, str2) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#define DCHECK_STRCASEEQ(str1, str2) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#define DCHECK_STRNE(str1, str2) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#define DCHECK_STRCASENE(str1, str2) \

-  while (false) NDEBUG_EAT_STREAM_PARAMETERS

-

-#endif  // NDEBUG

-

-#define NOTREACHED() DCHECK(false)

-

-// Redefine the standard assert to use our nice log files

-#undef assert

-#define assert(x) DLOG_ASSERT(x)

-

-// This class more or less represents a particular log message.  You

-// create an instance of LogMessage and then stream stuff to it.

-// When you finish streaming to it, ~LogMessage is called and the

-// full message gets streamed to the appropriate destination.

-//

-// You shouldn't actually use LogMessage's constructor to log things,

-// though.  You should use the LOG() macro (and variants thereof)

-// above.

-class LogMessage {

- public:

-  LogMessage(const char* file, int line, LogSeverity severity, int ctr);

-

-  // Two special constructors that generate reduced amounts of code at

-  // LOG call sites for common cases.

-  //

-  // Used for LOG(INFO): Implied are:

-  // severity = LOG_INFO, ctr = 0

-  //

-  // Using this constructor instead of the more complex constructor above

-  // saves a couple of bytes per call site.

-  LogMessage(const char* file, int line);

-

-  // Used for LOG(severity) where severity != INFO.  Implied

-  // are: ctr = 0

-  //

-  // Using this constructor instead of the more complex constructor above

-  // saves a couple of bytes per call site.

-  LogMessage(const char* file, int line, LogSeverity severity);

-

-  // A special constructor used for check failures.

-  // Implied severity = LOG_FATAL

-  LogMessage(const char* file, int line, const CheckOpString& result);

-

-  ~LogMessage();

-

-  std::ostream& stream() { return stream_; }

-

- private:

-  void Init(const char* file, int line);

-

-  LogSeverity severity_;

-  std::ostrstream stream_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(LogMessage);

-};

-

-// A non-macro interface to the log facility; (useful

-// when the logging level is not a compile-time constant).

-inline void LogAtLevel(int const log_level, std::string const &msg) {

-  LogMessage(__FILE__, __LINE__, log_level).stream() << msg;

-}

-

-// This class is used to explicitly ignore values in the conditional

-// logging macros.  This avoids compiler warnings like "value computed

-// is not used" and "statement has no effect".

-class LogMessageVoidify {

- public:

-  LogMessageVoidify() { }

-  // This has to be an operator with a precedence lower than << but

-  // higher than ?:

-  void operator&(std::ostream&) { }

-};

-

-// Closes the log file explicitly if open.

-// NOTE: Since the log file is opened as necessary by the action of logging

-//       statements, there's no guarantee that it will stay closed

-//       after this call.

-void CloseLogFile();

-

-} // namespace Logging

-

-// These functions are provided as a convenience for logging, which is where we

-// use streams (it is against Google style to use streams in other places). It

-// is designed to allow you to emit non-ASCII Unicode strings to the log file,

-// which is normally ASCII. It is relatively slow, so try not to use it for

-// common cases. Non-ASCII characters will be converted to UTF-8 by these operators.

-std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);

-inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {

-  return out << wstr.c_str();

-}

-

-#endif  // OMAHA_COMMON_LOGGING_LOGGING_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_LOGGING_LOGGING_H__
+#define OMAHA_COMMON_LOGGING_LOGGING_H__
+
+#include <string>
+#include <cstring>
+#include <strstream>
+#include <tchar.h>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+
+// This file provides logging facility for Windows client apps.
+//
+// Optional message capabilities
+// -----------------------------
+// Assertion failed messages and fatal errors are displayed in a dialog box
+// before the application exits. However, running this UI creates a message
+// loop, which causes application messages to be processed and potentially
+// dispatched to existing application windows. Since the application is in a
+// bad state when this assertion dialog is displayed, these messages may not
+// get processed and hang the dialog, or the application might go crazy.
+//
+// Therefore, it can be beneficial to display the error dialog in a separate
+// process from the main application. When the logging system needs to display
+// a fatal error dialog box, it will look for a program called
+// "DebugMessage.exe" in the same directory as the application executable. It
+// will run this application with the message as the command line, and will
+// not include the name of the application as is traditional for easier
+// parsing.
+//
+// The code for DebugMessage.exe is only one line. In WinMain, do:
+//   MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);
+//
+// If DebugMessage.exe is not found, the logging code will use a normal
+// MessageBox, potentially causing the problems discussed above.
+
+
+// Instructions
+// ------------
+//
+// Make a bunch of macros for logging.  The way to log things is to stream
+// things to LOG(<a particular severity level>).  E.g.,
+//
+//   LOG(INFO) << "Found " << num_cookies << " cookies";
+//
+// You can also do conditional logging:
+//
+//   LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// The above will cause log messages to be output on the 1st, 11th, 21st, ...
+// times it is executed.  Note that the special COUNTER value is used to
+// identify which repetition is happening.
+//
+// The CHECK(condition) macro is active in both debug and release builds and
+// effectively performs a LOG(FATAL) which terminates the process and
+// generates a crashdump unless a debugger is attached.
+//
+// There are also "debug mode" logging macros like the ones above:
+//
+//   DLOG(INFO) << "Found cookies";
+//
+//   DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// All "debug mode" logging is compiled away to nothing for non-debug mode
+// compiles.  LOG_IF and development flags also work well together
+// because the code can be compiled away sometimes.
+//
+// We also have
+//
+//   LOG_ASSERT(assertion);
+//   DLOG_ASSERT(assertion);
+//
+// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
+//
+// We also override the standard 'assert' to use 'DLOG_ASSERT'.
+//
+// The supported severity levels for macros that allow you to specify one
+// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
+//
+// There is also the special severity of DFATAL, which logs FATAL in
+// debug mode, ERROR in normal mode.
+//
+// Very important: logging a message at the FATAL severity level causes
+// the program to terminate (after the message is logged).
+
+namespace logging {
+
+// Where to record logging output? A flat file and/or system debug log via
+// OutputDebugString. Defaults to LOG_ONLY_TO_FILE.
+enum LoggingDestination { LOG_ONLY_TO_FILE, 
+                          LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
+                          LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG };
+
+// Indicates that the log file should be locked when being written to.
+// Often, there is no locking, which is fine for a single threaded program.
+// If logging is being done from multiple threads or there can be more than
+// one process doing the logging, the file should be locked during writes to
+// make each log outut atomic. Other writers will block.
+//
+// All processes writing to the log file must have their locking set for it to
+// work properly. Defaults to DONT_LOCK_LOG_FILE.
+enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
+
+// On startup, should we delete or append to an existing log file (if any)?
+// Defaults to APPEND_TO_OLD_LOG_FILE.
+enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
+
+// Sets the log file name and other global logging state. Calling this function
+// is recommended, and is normally done at the beginning of application init.
+// If you don't call it, all the flags will be initialized to their default
+// values, and there is a race condition that may leak a critical section
+// object if two threads try to do the first log at the same time.
+// See the definition of the enums above for descriptions and default values.
+//
+// The default log file is initialized to "debug.log" in the application
+// directory. You probably don't want this, especially since the program
+// directory may not be writable on an enduser's system.
+void InitLogging(const TCHAR* log_file, LoggingDestination logging_dest,
+                 LogLockingState lock_log, OldFileDeletionState delete_old);
+
+// Sets the log level. Anything at or above this level will be written to the
+// log file/displayed to the user (if applicable). Anything below this level
+// will be silently ignored. The log level defaults to 0 (everything is logged)
+// if this function is not called.
+void SetMinLogLevel(int level);
+
+// Sets the common items you want to be prepended to each log message.
+// process and thread IDs default to off, the timestamp defaults to on.
+// If this function is not called, logging defaults to writing the timestamp
+// only.
+void SetLogItems(bool enable_process_id, bool enable_thread_id,
+                 bool enable_timestamp, bool enable_tickcount);
+
+// Sets the Log Assert Handler that will be used to notify of check failures.
+// The default handler shows a dialog box, however clients can use this 
+// function to override with their own handling (e.g. a silent one for Unit
+// Tests)
+typedef void (*LogAssertHandlerFunction)(const std::string& str);
+void SetLogAssertHandler(LogAssertHandlerFunction handler);
+
+typedef int LogSeverity;
+const LogSeverity LOG_INFO = 0;
+const LogSeverity LOG_WARNING = 1;
+const LogSeverity LOG_ERROR = 2;
+const LogSeverity LOG_FATAL = 3;
+const LogSeverity LOG_NUM_SEVERITIES = 4;
+
+// LOG_DFATAL_LEVEL is LOG_FATAL in debug mode, ERROR in normal mode
+#ifdef NDEBUG
+const LogSeverity LOG_DFATAL_LEVEL = LOG_ERROR;
+#else
+const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL;
+#endif
+
+// A few definitions of macros that don't generate much code. These are used
+// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
+// better to have compact code for these operations.
+#define COMPACT_GOOGLE_LOG_INFO \
+  logging::LogMessage(__FILE__, __LINE__)
+#define COMPACT_GOOGLE_LOG_WARNING \
+  logging::LogMessage(__FILE__, __LINE__, logging::LOG_WARNING)
+#define COMPACT_GOOGLE_LOG_ERROR \
+  logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR)
+#define COMPACT_GOOGLE_LOG_FATAL \
+  logging::LogMessage(__FILE__, __LINE__, logging::LOG_FATAL)
+#define COMPACT_GOOGLE_LOG_DFATAL \
+  logging::LogMessage(__FILE__, __LINE__, logging::LOG_DFATAL_LEVEL)
+
+// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
+// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
+// to keep using this syntax, we define this macro to do the same thing
+// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
+// the Windows SDK does for consistency.
+#define ERROR 0
+#define COMPACT_GOOGLE_LOG_0 \
+  logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR)
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO.  There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+
+#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
+#define SYSLOG(severity) LOG(severity)
+
+#define LOG_IF(severity, condition) \
+  !(condition) ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)
+#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
+
+#define LOG_ASSERT(condition)  \
+  LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+#define SYSLOG_ASSERT(condition) \
+  SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+
+// CHECK dies with a fatal error if condition is not true.  It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode.
+#define CHECK(condition) \
+  LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
+
+// A container for a string pointer which can be evaluated to a bool -
+// true iff the pointer is NULL.
+struct CheckOpString {
+  CheckOpString(std::string* str) : str_(str) { }
+  // No destructor: if str_ is non-NULL, we're about to LOG(FATAL),
+  // so there's no point in cleaning up str_.
+  operator bool() const { return str_ != NULL; }
+  std::string* str_;
+};
+
+// Build the error message string.  This is separate from the "Impl"
+// function template because it is not performance critical and so can
+// be out of line, while the "Impl" code should be inline.
+template<class t1, class t2>
+std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
+  std::ostrstream ss;
+  ss << names << " (" << v1 << " vs. " << v2 << ")";
+  return new std::string(ss.str(), ss.pcount());
+}
+
+extern std::string* MakeCheckOpStringIntInt(int v1, int v2, const char* names);
+
+template<int, int>
+std::string* MakeCheckOpString(const int& v1, const int& v2, const char* names) {
+  return MakeCheckOpStringIntInt(v1, v2, names);
+}
+
+// Plus some debug-logging macros that get compiled to nothing for production
+//
+// DEBUG_MODE is for uses like
+//   if (DEBUG_MODE) foo.CheckThatFoo();
+// instead of
+//   #ifndef NDEBUG
+//     foo.CheckThatFoo();
+//   #endif
+
+#ifndef NDEBUG
+
+#define DLOG(severity) LOG(severity)
+#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+
+// debug-only checking.  not executed in NDEBUG mode.
+enum { DEBUG_MODE = 1 };
+#define DCHECK(condition) \
+  LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
+
+// Helper functions for DCHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_DCHECK_OP_IMPL(name, op) \
+  template <class t1, class t2> \
+  inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
+                                        const char* names) { \
+    if (v1 op v2) return NULL; \
+    else return MakeCheckOpString(v1, v2, names); \
+  } \
+  inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
+    if (v1 op v2) return NULL; \
+    else return MakeCheckOpString(v1, v2, names); \
+  }
+DEFINE_DCHECK_OP_IMPL(EQ, ==)
+DEFINE_DCHECK_OP_IMPL(NE, !=)
+DEFINE_DCHECK_OP_IMPL(LE, <=)
+DEFINE_DCHECK_OP_IMPL(LT, < )
+DEFINE_DCHECK_OP_IMPL(GE, >=)
+DEFINE_DCHECK_OP_IMPL(GT, > )
+#undef DEFINE_DCHECK_OP_IMPL
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+#define DCHECK_OP(name, op, val1, val2)  \
+  while (logging::CheckOpString _result = \
+         logging::Check##name##Impl((val1), (val2), #val1 " " #op " " #val2)) \
+    logging::LogMessage(__FILE__, __LINE__, _result).stream()
+
+// Equality/Inequality checks - compare two values, and log a LOG_FATAL message
+// including the two values when the result is not as expected.  The values
+// must have operator<<(ostream, ...) defined.
+//
+// You may append to the error message like so:
+//   CHECK_NE(1, 2) << ": The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here.  In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+//   CHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These don't compile correctly if one of the arguments is a pointer
+// and the other is NULL. To work around this, simply static_cast NULL to the
+// type of the desired pointer.
+
+#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
+#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
+#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
+#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
+#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
+#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
+
+// Helper functions for string comparisons.
+// To avoid bloat, the definitions are in logging.cc.
+#define DECLARE_DCHECK_STROP_IMPL(func, expected) \
+  std::string* Check##func##expected##Impl(const char* s1, \
+                                           const char* s2, \
+                                           const char* names);
+DECLARE_DCHECK_STROP_IMPL(strcmp, true)
+DECLARE_DCHECK_STROP_IMPL(strcmp, false)
+DECLARE_DCHECK_STROP_IMPL(_stricmp, true)
+DECLARE_DCHECK_STROP_IMPL(_stricmp, false)
+#undef DECLARE_DCHECK_STROP_IMPL
+
+// Helper macro for string comparisons.
+// Don't use this macro directly in your code, use CHECK_STREQ et al below.
+#define DCHECK_STROP(func, op, expected, s1, s2) \
+  while (CheckOpString _result = \
+      logging::Check##func##expected##Impl((s1), (s2), \
+                                           #s1 " " #op " " #s2)) \
+    LOG(FATAL) << *_result.str_
+
+// String (char*) equality/inequality checks.
+// CASE versions are case-insensitive.
+//
+// Note that "s1" and "s2" may be temporary strings which are destroyed
+// by the compiler at the end of the current "full expression"
+// (e.g. DCHECK_STREQ(Foo().c_str(), Bar().c_str())).
+
+#define DCHECK_STREQ(s1, s2) DCHECK_STROP(strcmp, ==, true, s1, s2)
+#define DCHECK_STRNE(s1, s2) DCHECK_STROP(strcmp, !=, false, s1, s2)
+#define DCHECK_STRCASEEQ(s1, s2) DCHECK_STROP(_stricmp, ==, true, s1, s2)
+#define DCHECK_STRCASENE(s1, s2) DCHECK_STROP(_stricmp, !=, false, s1, s2)
+
+#define DCHECK_INDEX(I,A) DCHECK(I < (sizeof(A)/sizeof(A[0])))
+#define DCHECK_BOUND(B,A) DCHECK(B <= (sizeof(A)/sizeof(A[0])))
+
+#else  // NDEBUG
+
+#define DLOG(severity) \
+  true ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_IF(severity, condition) \
+  true ? (void) 0 : logging::LogMessageVoidify() & LOG(severity)
+
+#define DLOG_ASSERT(condition) \
+  true ? (void) 0 : LOG_ASSERT(condition)
+
+enum { DEBUG_MODE = 0 };
+
+// This macro can be followed by a sequence of stream parameters in
+// non-debug mode. The DCHECK and friends macros use this so that
+// the expanded expression DCHECK(foo) << "asdf" is still syntactically
+// valid, even though the expression will get optimized away.
+#define NDEBUG_EAT_STREAM_PARAMETERS \
+  logging::LogMessage(__FILE__, __LINE__).stream()
+
+#define DCHECK(condition) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#define DCHECK_EQ(val1, val2) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#define DCHECK_NE(val1, val2) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#define DCHECK_LE(val1, val2) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#define DCHECK_LT(val1, val2) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#define DCHECK_GE(val1, val2) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#define DCHECK_GT(val1, val2) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#define DCHECK_STREQ(str1, str2) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#define DCHECK_STRCASEEQ(str1, str2) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#define DCHECK_STRNE(str1, str2) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#define DCHECK_STRCASENE(str1, str2) \
+  while (false) NDEBUG_EAT_STREAM_PARAMETERS
+
+#endif  // NDEBUG
+
+#define NOTREACHED() DCHECK(false)
+
+// Redefine the standard assert to use our nice log files
+#undef assert
+#define assert(x) DLOG_ASSERT(x)
+
+// This class more or less represents a particular log message.  You
+// create an instance of LogMessage and then stream stuff to it.
+// When you finish streaming to it, ~LogMessage is called and the
+// full message gets streamed to the appropriate destination.
+//
+// You shouldn't actually use LogMessage's constructor to log things,
+// though.  You should use the LOG() macro (and variants thereof)
+// above.
+class LogMessage {
+ public:
+  LogMessage(const char* file, int line, LogSeverity severity, int ctr);
+
+  // Two special constructors that generate reduced amounts of code at
+  // LOG call sites for common cases.
+  //
+  // Used for LOG(INFO): Implied are:
+  // severity = LOG_INFO, ctr = 0
+  //
+  // Using this constructor instead of the more complex constructor above
+  // saves a couple of bytes per call site.
+  LogMessage(const char* file, int line);
+
+  // Used for LOG(severity) where severity != INFO.  Implied
+  // are: ctr = 0
+  //
+  // Using this constructor instead of the more complex constructor above
+  // saves a couple of bytes per call site.
+  LogMessage(const char* file, int line, LogSeverity severity);
+
+  // A special constructor used for check failures.
+  // Implied severity = LOG_FATAL
+  LogMessage(const char* file, int line, const CheckOpString& result);
+
+  ~LogMessage();
+
+  std::ostream& stream() { return stream_; }
+
+ private:
+  void Init(const char* file, int line);
+
+  LogSeverity severity_;
+  std::ostrstream stream_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(LogMessage);
+};
+
+// A non-macro interface to the log facility; (useful
+// when the logging level is not a compile-time constant).
+inline void LogAtLevel(int const log_level, std::string const &msg) {
+  LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
+}
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros.  This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+class LogMessageVoidify {
+ public:
+  LogMessageVoidify() { }
+  // This has to be an operator with a precedence lower than << but
+  // higher than ?:
+  void operator&(std::ostream&) { }
+};
+
+// Closes the log file explicitly if open.
+// NOTE: Since the log file is opened as necessary by the action of logging
+//       statements, there's no guarantee that it will stay closed
+//       after this call.
+void CloseLogFile();
+
+} // namespace Logging
+
+// These functions are provided as a convenience for logging, which is where we
+// use streams (it is against Google style to use streams in other places). It
+// is designed to allow you to emit non-ASCII Unicode strings to the log file,
+// which is normally ASCII. It is relatively slow, so try not to use it for
+// common cases. Non-ASCII characters will be converted to UTF-8 by these operators.
+std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
+inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
+  return out << wstr.c_str();
+}
+
+#endif  // OMAHA_COMMON_LOGGING_LOGGING_H__
diff --git a/common/logging_unittest.cc b/common/logging_unittest.cc
index eb85c10..4693a82 100644
--- a/common/logging_unittest.cc
+++ b/common/logging_unittest.cc
@@ -1,268 +1,268 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "base/basictypes.h"

-#include "omaha/common/logging.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(LoggingTest, Logging) {

-#ifdef _DEBUG

-  OPT_LOG(L1, (_T("[OPT_LOG from debug build.]")));

-#else

-  OPT_LOG(L1, (_T("[OPT_LOG from optimized build.]")));

-#endif

-}

-

-class FileLogWriterTest : public testing::Test {

- public:

-

-  int FindFirstInMultiString(const TCHAR* multi_str,

-                             size_t count,

-                             const TCHAR* str) {

-    return FileLogWriter::FindFirstInMultiString(multi_str, count, str);

-  }

-};

-

-class HistoryTest : public testing::Test {

- protected:

-  HistoryTest() {

-    logging_ = GetLogging();

-  }

-

-  void AppendToHistory(const wchar_t* msg) {

-    logging_->AppendToHistory(msg);

-  }

-

-  CString GetHistory() {

-    return logging_->GetHistory();

-  }

-

- private:

-  Logging* logging_;

-};

-

-#define EOS _T("")

-TEST_F(FileLogWriterTest, FindInMultiString) {

-  // One string of one char.

-  const TCHAR s1[] = _T("a\0") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s1, arraysize(s1), _T("a")), 0);

-

-  // One string.

-  const TCHAR s2[] = _T("abc\0") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s2, arraysize(s2), _T("abc")), 0);

-

-  // Two strings of one char.

-  const TCHAR s3[] = _T("a\0b\0") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s3, arraysize(s3), _T("b")), 2);

-

-  // Two strings.

-  const TCHAR s4[] = _T("ab\0cde\0") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s4, arraysize(s4), _T("cde")), 3);

-

-  // Three strings one char.

-  const TCHAR s5[] = _T("a\0b\0c\0") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s5, arraysize(s5), _T("c")), 4);

-

-  // Many strings.

-  const TCHAR s6[] = _T("a\0bcd\0efgh\0") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s6, arraysize(s6), _T("efgh")), 6);

-

-  // Many strings including empty string.

-  const TCHAR s7[] = _T("a\0\0bc\0\0de\0fg") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s7, arraysize(s7), _T("fg")), 10);

-

-  // Many strings, empty string at the end, negative test.

-  const TCHAR s8[] = _T("a\0bcd\0efgh\0\0") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s8, arraysize(s8), _T("foo")), -1);

-

-  // Another negative test.

-  const TCHAR s9[] = _T("a\0bcd\0\0\0efgh\0") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s9, arraysize(s9), _T("foo")), -1);

-

-  // Empty string is always found.

-  const TCHAR s10[] = _T("\0") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s10, arraysize(s10), _T("\0")), 0);

-

-  const TCHAR s11[] = _T("\0") EOS;

-  EXPECT_EQ(FindFirstInMultiString(s11, arraysize(s11), _T("a")), -1);

-}

-

-TEST_F(HistoryTest, GetHistory) {

-  EXPECT_TRUE(GetHistory().IsEmpty());

-

-  const TCHAR msg1[] = _T("Hello");

-  AppendToHistory(msg1);

-  EXPECT_STREQ(msg1, GetHistory());

-  EXPECT_TRUE(GetHistory().IsEmpty());

-}

-

-TEST_F(HistoryTest, AppendToHistoryTest) {

-  // Test one character.

-  const TCHAR msg1[] = _T("A");

-  AppendToHistory(msg1);

-  EXPECT_STREQ(msg1, GetHistory());

-

-  // Test small string.

-  const TCHAR msg2[] = _T("ABCD");

-  AppendToHistory(msg2);

-  EXPECT_STREQ(msg2, GetHistory());

-

-  // Test one string that fills the buffer.

-  TCHAR msg3[kMaxHistoryBufferSize + 1] = {0};

-  for (int i = 0; i <= kMaxHistoryBufferSize; ++i) {

-    msg3[i] = _T('A');

-  }

-  msg3[kMaxHistoryBufferSize] = _T('\0');

-  AppendToHistory(msg3);

-  EXPECT_STREQ(msg3, GetHistory());

-

-  // Test set of strings that exactly fill buffer.

-  const int test_buffer_size = 64;

-  TCHAR msg4[test_buffer_size + 1] = {0};

-  for (int i = 0; i <= test_buffer_size; ++i) {

-    msg4[i] = _T('A');

-  }

-  msg4[test_buffer_size] = _T('\0');

-

-  int num_times_to_append = kMaxHistoryBufferSize / test_buffer_size;

-  EXPECT_EQ(kMaxHistoryBufferSize, num_times_to_append * test_buffer_size);

-  for (int i = 0; i < num_times_to_append; ++i) {

-    AppendToHistory(msg4);

-  }

-  EXPECT_STREQ(msg3, GetHistory());

-}

-

-TEST_F(HistoryTest, AppendToHistoryTest_WrapAround) {

-  // Test string that wraps around the buffer.

-  // First fill kMaxHistoryBufferSize - 1 with one string, then use

-  // another string of length 2("XX"), and another string to length of length 3.

-  // "XFFFGGGGG....GGGX" should be the result. The returned string should

-  // be in correct FIFO order i.e. "GGGGG......XXFFF".

-  const TCHAR msg6[] = _T("XX");

-  const TCHAR msg7[] = _T("FFF");

-  const int test_buffer_size = kMaxHistoryBufferSize - 1;

-  TCHAR msg5[test_buffer_size + 1] = {0};

-  TCHAR expected_buffer[kMaxHistoryBufferSize + 1] = {0};

-  for (int i = 0; i <= test_buffer_size; ++i) {

-    msg5[i] = _T('G');

-  }

-  msg5[test_buffer_size] = _T('\0');

-

-  // Call test method.

-  AppendToHistory(msg5);

-  AppendToHistory(msg6);

-  AppendToHistory(msg7);

-

-  // Create the expected string.

-  for (int i = 0; i <= kMaxHistoryBufferSize; ++i) {

-    expected_buffer[i] = _T('G');

-  }

-  int msg6len = wcslen(msg6);

-  int msg7len = wcslen(msg7);

-  memcpy(expected_buffer + kMaxHistoryBufferSize - msg6len - msg7len,

-         msg6,

-         msg6len * sizeof(TCHAR));

-  memcpy(expected_buffer + kMaxHistoryBufferSize - msg7len,

-         msg7,

-         msg7len * sizeof(TCHAR));

-  expected_buffer[kMaxHistoryBufferSize] = _T('\0');

-  EXPECT_STREQ(expected_buffer, GetHistory());

-}

-

-TEST_F(HistoryTest, AppendToHistoryTest_AnotherWrapAroundTest) {

-  // Test string that wraps around the buffer.

-  // First fill the kMaxHistoryBufferSize - 1 with one string, then fill it with

-  // another string of same length.

-  const int test_buffer_size = kMaxHistoryBufferSize - 1;

-  TCHAR msg2[test_buffer_size + 1] = {0};

-  TCHAR msg1[test_buffer_size + 1] = {0};

-  TCHAR expected_buffer[kMaxHistoryBufferSize + 1] = {0};

-  for (int i = 0; i <= test_buffer_size; ++i) {

-    msg1[i] = _T('G');

-    msg2[i] = _T('J');

-  }

-  msg2[test_buffer_size] = _T('\0');

-  msg1[test_buffer_size] = _T('\0');

-

-  // Call test method.

-  AppendToHistory(msg1);

-  AppendToHistory(msg2);

-

-  // Create the expected string.

-  for (int i = 0; i <= kMaxHistoryBufferSize; ++i) {

-    expected_buffer[i] = _T('J');

-  }

-  expected_buffer[0] = _T('G');

-  expected_buffer[kMaxHistoryBufferSize] = _T('\0');

-  EXPECT_STREQ(expected_buffer, GetHistory());

-}

-

-TEST_F(HistoryTest, AppendToHistoryTest_LotsOfLogs) {

-  // Run over a number of Append calls, with strings length

-  // (kMaxHistoryBufferSize / 2) + 1, causing wrap on every run.

-  TCHAR expected_buffer[kMaxHistoryBufferSize + 1] = {0};

-  const int test_buffer_size = (kMaxHistoryBufferSize / 2) + 1;

-  TCHAR msg1[test_buffer_size + 1] = {0};

-  for (int test_char = 'A'; test_char <= 'Z'; ++test_char) {

-    for (int i = 0; i <= test_buffer_size; ++i) {

-      msg1[i] = static_cast<TCHAR>(test_char);

-    }

-    msg1[test_buffer_size] = _T('\0');

-

-    // Call test method.

-    AppendToHistory(msg1);

-  }

-

-  // Create the expected string.

-  int i = 0;

-  for (; i < test_buffer_size - 2; ++i) {

-    expected_buffer[i] = _T('Y');

-  }

-  for (; i <= kMaxHistoryBufferSize; ++i) {

-    expected_buffer[i] = _T('Z');

-  }

-  expected_buffer[kMaxHistoryBufferSize] = _T('\0');

-  EXPECT_STREQ(expected_buffer, GetHistory());

-}

-

-TEST_F(HistoryTest, AppendToHistoryTest_LargeBuffer) {

-  // Test with a message that is larger than the buffer.

-  const int test_buffer_size = kMaxHistoryBufferSize + 10;

-  TCHAR msg4[test_buffer_size + 1] = {0};

-  TCHAR expected_buffer[kMaxHistoryBufferSize + 1] = {0};

-  for (int i = 0; i < test_buffer_size; ++i) {

-    msg4[i] = _T('A');

-  }

-  msg4[test_buffer_size] = _T('\0');

-

-  for (int i = 0; i <= kMaxHistoryBufferSize; ++i) {

-    expected_buffer[i] = _T('A');

-  }

-  expected_buffer[kMaxHistoryBufferSize] = _T('\0');

-

-  AppendToHistory(msg4);

-  EXPECT_STREQ(expected_buffer, GetHistory());

-}

-

-TEST_F(HistoryTest, AppendToHistoryTest_EmptyBuffer) {

-  CString test_string;

-  AppendToHistory(test_string);

-  EXPECT_TRUE(GetHistory().IsEmpty());

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "base/basictypes.h"
+#include "omaha/common/logging.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(LoggingTest, Logging) {
+#ifdef _DEBUG
+  OPT_LOG(L1, (_T("[OPT_LOG from debug build.]")));
+#else
+  OPT_LOG(L1, (_T("[OPT_LOG from optimized build.]")));
+#endif
+}
+
+class FileLogWriterTest : public testing::Test {
+ public:
+
+  int FindFirstInMultiString(const TCHAR* multi_str,
+                             size_t count,
+                             const TCHAR* str) {
+    return FileLogWriter::FindFirstInMultiString(multi_str, count, str);
+  }
+};
+
+class HistoryTest : public testing::Test {
+ protected:
+  HistoryTest() {
+    logging_ = GetLogging();
+  }
+
+  void AppendToHistory(const wchar_t* msg) {
+    logging_->AppendToHistory(msg);
+  }
+
+  CString GetHistory() {
+    return logging_->GetHistory();
+  }
+
+ private:
+  Logging* logging_;
+};
+
+#define EOS _T("")
+TEST_F(FileLogWriterTest, FindInMultiString) {
+  // One string of one char.
+  const TCHAR s1[] = _T("a\0") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s1, arraysize(s1), _T("a")), 0);
+
+  // One string.
+  const TCHAR s2[] = _T("abc\0") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s2, arraysize(s2), _T("abc")), 0);
+
+  // Two strings of one char.
+  const TCHAR s3[] = _T("a\0b\0") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s3, arraysize(s3), _T("b")), 2);
+
+  // Two strings.
+  const TCHAR s4[] = _T("ab\0cde\0") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s4, arraysize(s4), _T("cde")), 3);
+
+  // Three strings one char.
+  const TCHAR s5[] = _T("a\0b\0c\0") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s5, arraysize(s5), _T("c")), 4);
+
+  // Many strings.
+  const TCHAR s6[] = _T("a\0bcd\0efgh\0") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s6, arraysize(s6), _T("efgh")), 6);
+
+  // Many strings including empty string.
+  const TCHAR s7[] = _T("a\0\0bc\0\0de\0fg") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s7, arraysize(s7), _T("fg")), 10);
+
+  // Many strings, empty string at the end, negative test.
+  const TCHAR s8[] = _T("a\0bcd\0efgh\0\0") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s8, arraysize(s8), _T("foo")), -1);
+
+  // Another negative test.
+  const TCHAR s9[] = _T("a\0bcd\0\0\0efgh\0") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s9, arraysize(s9), _T("foo")), -1);
+
+  // Empty string is always found.
+  const TCHAR s10[] = _T("\0") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s10, arraysize(s10), _T("\0")), 0);
+
+  const TCHAR s11[] = _T("\0") EOS;
+  EXPECT_EQ(FindFirstInMultiString(s11, arraysize(s11), _T("a")), -1);
+}
+
+TEST_F(HistoryTest, GetHistory) {
+  EXPECT_TRUE(GetHistory().IsEmpty());
+
+  const TCHAR msg1[] = _T("Hello");
+  AppendToHistory(msg1);
+  EXPECT_STREQ(msg1, GetHistory());
+  EXPECT_TRUE(GetHistory().IsEmpty());
+}
+
+TEST_F(HistoryTest, AppendToHistoryTest) {
+  // Test one character.
+  const TCHAR msg1[] = _T("A");
+  AppendToHistory(msg1);
+  EXPECT_STREQ(msg1, GetHistory());
+
+  // Test small string.
+  const TCHAR msg2[] = _T("ABCD");
+  AppendToHistory(msg2);
+  EXPECT_STREQ(msg2, GetHistory());
+
+  // Test one string that fills the buffer.
+  TCHAR msg3[kMaxHistoryBufferSize + 1] = {0};
+  for (int i = 0; i <= kMaxHistoryBufferSize; ++i) {
+    msg3[i] = _T('A');
+  }
+  msg3[kMaxHistoryBufferSize] = _T('\0');
+  AppendToHistory(msg3);
+  EXPECT_STREQ(msg3, GetHistory());
+
+  // Test set of strings that exactly fill buffer.
+  const int test_buffer_size = 64;
+  TCHAR msg4[test_buffer_size + 1] = {0};
+  for (int i = 0; i <= test_buffer_size; ++i) {
+    msg4[i] = _T('A');
+  }
+  msg4[test_buffer_size] = _T('\0');
+
+  int num_times_to_append = kMaxHistoryBufferSize / test_buffer_size;
+  EXPECT_EQ(kMaxHistoryBufferSize, num_times_to_append * test_buffer_size);
+  for (int i = 0; i < num_times_to_append; ++i) {
+    AppendToHistory(msg4);
+  }
+  EXPECT_STREQ(msg3, GetHistory());
+}
+
+TEST_F(HistoryTest, AppendToHistoryTest_WrapAround) {
+  // Test string that wraps around the buffer.
+  // First fill kMaxHistoryBufferSize - 1 with one string, then use
+  // another string of length 2("XX"), and another string to length of length 3.
+  // "XFFFGGGGG....GGGX" should be the result. The returned string should
+  // be in correct FIFO order i.e. "GGGGG......XXFFF".
+  const TCHAR msg6[] = _T("XX");
+  const TCHAR msg7[] = _T("FFF");
+  const int test_buffer_size = kMaxHistoryBufferSize - 1;
+  TCHAR msg5[test_buffer_size + 1] = {0};
+  TCHAR expected_buffer[kMaxHistoryBufferSize + 1] = {0};
+  for (int i = 0; i <= test_buffer_size; ++i) {
+    msg5[i] = _T('G');
+  }
+  msg5[test_buffer_size] = _T('\0');
+
+  // Call test method.
+  AppendToHistory(msg5);
+  AppendToHistory(msg6);
+  AppendToHistory(msg7);
+
+  // Create the expected string.
+  for (int i = 0; i <= kMaxHistoryBufferSize; ++i) {
+    expected_buffer[i] = _T('G');
+  }
+  int msg6len = wcslen(msg6);
+  int msg7len = wcslen(msg7);
+  memcpy(expected_buffer + kMaxHistoryBufferSize - msg6len - msg7len,
+         msg6,
+         msg6len * sizeof(TCHAR));
+  memcpy(expected_buffer + kMaxHistoryBufferSize - msg7len,
+         msg7,
+         msg7len * sizeof(TCHAR));
+  expected_buffer[kMaxHistoryBufferSize] = _T('\0');
+  EXPECT_STREQ(expected_buffer, GetHistory());
+}
+
+TEST_F(HistoryTest, AppendToHistoryTest_AnotherWrapAroundTest) {
+  // Test string that wraps around the buffer.
+  // First fill the kMaxHistoryBufferSize - 1 with one string, then fill it with
+  // another string of same length.
+  const int test_buffer_size = kMaxHistoryBufferSize - 1;
+  TCHAR msg2[test_buffer_size + 1] = {0};
+  TCHAR msg1[test_buffer_size + 1] = {0};
+  TCHAR expected_buffer[kMaxHistoryBufferSize + 1] = {0};
+  for (int i = 0; i <= test_buffer_size; ++i) {
+    msg1[i] = _T('G');
+    msg2[i] = _T('J');
+  }
+  msg2[test_buffer_size] = _T('\0');
+  msg1[test_buffer_size] = _T('\0');
+
+  // Call test method.
+  AppendToHistory(msg1);
+  AppendToHistory(msg2);
+
+  // Create the expected string.
+  for (int i = 0; i <= kMaxHistoryBufferSize; ++i) {
+    expected_buffer[i] = _T('J');
+  }
+  expected_buffer[0] = _T('G');
+  expected_buffer[kMaxHistoryBufferSize] = _T('\0');
+  EXPECT_STREQ(expected_buffer, GetHistory());
+}
+
+TEST_F(HistoryTest, AppendToHistoryTest_LotsOfLogs) {
+  // Run over a number of Append calls, with strings length
+  // (kMaxHistoryBufferSize / 2) + 1, causing wrap on every run.
+  TCHAR expected_buffer[kMaxHistoryBufferSize + 1] = {0};
+  const int test_buffer_size = (kMaxHistoryBufferSize / 2) + 1;
+  TCHAR msg1[test_buffer_size + 1] = {0};
+  for (int test_char = 'A'; test_char <= 'Z'; ++test_char) {
+    for (int i = 0; i <= test_buffer_size; ++i) {
+      msg1[i] = static_cast<TCHAR>(test_char);
+    }
+    msg1[test_buffer_size] = _T('\0');
+
+    // Call test method.
+    AppendToHistory(msg1);
+  }
+
+  // Create the expected string.
+  int i = 0;
+  for (; i < test_buffer_size - 2; ++i) {
+    expected_buffer[i] = _T('Y');
+  }
+  for (; i <= kMaxHistoryBufferSize; ++i) {
+    expected_buffer[i] = _T('Z');
+  }
+  expected_buffer[kMaxHistoryBufferSize] = _T('\0');
+  EXPECT_STREQ(expected_buffer, GetHistory());
+}
+
+TEST_F(HistoryTest, AppendToHistoryTest_LargeBuffer) {
+  // Test with a message that is larger than the buffer.
+  const int test_buffer_size = kMaxHistoryBufferSize + 10;
+  TCHAR msg4[test_buffer_size + 1] = {0};
+  TCHAR expected_buffer[kMaxHistoryBufferSize + 1] = {0};
+  for (int i = 0; i < test_buffer_size; ++i) {
+    msg4[i] = _T('A');
+  }
+  msg4[test_buffer_size] = _T('\0');
+
+  for (int i = 0; i <= kMaxHistoryBufferSize; ++i) {
+    expected_buffer[i] = _T('A');
+  }
+  expected_buffer[kMaxHistoryBufferSize] = _T('\0');
+
+  AppendToHistory(msg4);
+  EXPECT_STREQ(expected_buffer, GetHistory());
+}
+
+TEST_F(HistoryTest, AppendToHistoryTest_EmptyBuffer) {
+  CString test_string;
+  AppendToHistory(test_string);
+  EXPECT_TRUE(GetHistory().IsEmpty());
+}
+
+}  // namespace omaha
+
diff --git a/common/md5.cc b/common/md5.cc
index 62331fd..1477361 100644
--- a/common/md5.cc
+++ b/common/md5.cc
@@ -1,453 +1,453 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-/*

- * md5_opt.c V1.0 - optimized md5c.c from RFC1321 reference implementation

- *

- * Copyright (c) 1995 University of Southern California.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms are permitted

- * provided that the above copyright notice and this paragraph are

- * duplicated in all such forms and that any documentation, advertising

- * materials, and other materials related to such distribution and use

- * acknowledge that the software was developed by the University of

- * Southern California, Information Sciences Institute.  The name of the

- * University may not be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED

- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF

- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

- *

- J. Touch / touch@isi.edu

- 5/1/95

-

-*/

-/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm

- */

-

-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All

-rights reserved.

-

-License to copy and use this software is granted provided that it

-is identified as the "RSA Data Security, Inc. MD5 Message-Digest

-Algorithm" in all material mentioning or referencing this software

-or this function.

-

-License is also granted to make and use derivative works provided

-that such works are identified as "derived from the RSA Data

-Security, Inc. MD5 Message-Digest Algorithm" in all material

-mentioning or referencing the derived work.

-

-RSA Data Security, Inc. makes no representations concerning either

-the merchantability of this software or the suitability of this

-software for any particular purpose. It is provided "as is"

-without express or implied warranty of any kind.

-

-These notices must be retained in any copies of any part of this

-documentation and/or software.

-*/

-

-#include "md5.h"

-#include "common/debug.h"

-

-namespace omaha {

-

-#if (defined(i386) || defined (__i386__) || defined (_M_IX86) || defined(__alpha))  // little-endian

-#undef REORDER

-#else

-#define REORDER 1

-#endif

-

-// Constants for MD5Transform routine

-#define kS11 7

-#define kS12 12

-#define kS13 17

-#define kS14 22

-#define kS21 5

-#define kS22 9

-#define kS23 14

-#define kS24 20

-#define kS31 4

-#define kS32 11

-#define kS33 16

-#define kS34 23

-#define kS41 6

-#define kS42 10

-#define kS43 15

-#define kS44 21

-

-static void MD5Transform (uint32 [4], unsigned char [64]);

-static void Encode (unsigned char *, uint32 *, unsigned int);

-#ifdef REORDER

-static void Decode (uint32 *, unsigned char *, unsigned int);

-#endif

-

-// SELECTANY static unsigned char PADDING[64] = {

-static unsigned char PADDING[64] = {

-    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

-};

-

-// F, G, H and I are basic MD5 functions.

-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))

-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))

-#define H(x, y, z) ((x) ^ (y) ^ (z))

-#define I(x, y, z) ((y) ^ ((x) | (~z)))

-

-// ROTATE_LEFT rotates x left n bits.

-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

-

-// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.

-// Rotation is separate from addition to prevent recomputation.

-#define FF(a, b, c, d, x, s, ac) { \

-    (a) += F ((b), (c), (d)) + (x) + (uint32)(ac); \

-    (a) = ROTATE_LEFT ((a), (s)); \

-    (a) += (b); \

-    }

-#define GG(a, b, c, d, x, s, ac) { \

-    (a) += G ((b), (c), (d)) + (x) + (uint32)(ac); \

-    (a) = ROTATE_LEFT ((a), (s)); \

-    (a) += (b); \

-    }

-#define HH(a, b, c, d, x, s, ac) { \

-    (a) += H ((b), (c), (d)) + (x) + (uint32)(ac); \

-    (a) = ROTATE_LEFT ((a), (s)); \

-    (a) += (b); \

-    }

-#define II(a, b, c, d, x, s, ac) { \

-    (a) += I ((b), (c), (d)) + (x) + (uint32)(ac); \

-    (a) = ROTATE_LEFT ((a), (s)); \

-    (a) += (b); \

-    }

-

-// MD5 initialization. Begins an MD5 operation, writing a new context.

-void MD5Init (MD5_CTX *context) {

-    ASSERT(context, (L""));

-

-    context->count[0] = context->count[1] = 0;

-    // Load magic initialization constants.

-    context->state[0] = 0x67452301;

-    context->state[1] = 0xefcdab89;

-    context->state[2] = 0x98badcfe;

-    context->state[3] = 0x10325476;

-}

-

-// MD5 block update operation. Continues an MD5 message-digest

-// operation, processing another message block, and updating the context.

-void MD5Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen) {

-    ASSERT(input, (L""));

-    ASSERT(context, (L""));

-

-    unsigned int i, index, partLen;

-

-    // Compute number of bytes mod 64

-    index = (unsigned int)((context->count[0] >> 3) & 0x3F);

-

-    // Update number of bits

-    if ((context->count[0] += ((uint32)inputLen << 3)) < ((uint32)inputLen << 3))

-        context->count[1]++;

-

-    context->count[1] += ((uint32)inputLen >> 29);

-    partLen = 64 - index;

-

-    // Transform as many times as possible

-    if (inputLen >= partLen) {

-       memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen);

-       MD5Transform (context->state, context->buffer);

-

-       for (i = partLen; i + 63 < inputLen; i += 64) MD5Transform (context->state, &input[i]);

-       index = 0;

-       }

-    else

-       i = 0;

-

-    // Buffer remaining input

-    memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);

-}

-

-// MD5 finalization. Ends an MD5 message-digest operation, writing the

-// the message digest and zeroizing the context.

-void MD5Final (unsigned char digest[16], MD5_CTX *context) {

-    ASSERT(context, (L""));

-

-    unsigned char bits[8];

-    unsigned int index, padLen;

-

-    // Save number of bits

-    Encode (bits, context->count, 8);

-

-    // Pad out to 56 mod 64.

-    index = (unsigned int)((context->count[0] >> 3) & 0x3f);

-    padLen = (index < 56) ? (56 - index) : (120 - index);

-    MD5Update (context, PADDING, padLen);

-

-    // Append length (before padding)

-    MD5Update (context, bits, 8);

-    // Store state in digest

-    Encode (digest, context->state, 16);

-

-    // Zeroize sensitive information.

-    memset ((POINTER)context, 0, sizeof (*context));

-}

-

-// MD5 basic transformation. Transforms state based on block.

-void MD5Transform (uint32 state[4], unsigned char block[64]) {

-    // USC/ISI J. Touch - encourage pushing state variables into registers

-    register uint32 a = state[0], b = state[1], c = state[2], d = state[3];

-

-    /* USC/ISI J. Touch

-    decode and using copied data vs. direct use of input buffer

-    depends on whether reordering is required, which is a combination

-    of the byte order of the architecture and the command-line option

-    override

-    */

-

-#ifdef REORDER

-    uint32 x[16];

-

-    Decode (x, block, 64);

-

-    /* Round 1 */

-    FF (a, b, c, d, x[ 0], kS11, 0xd76aa478); /* 1 */

-    FF (d, a, b, c, x[ 1], kS12, 0xe8c7b756); /* 2 */

-    FF (c, d, a, b, x[ 2], kS13, 0x242070db); /* 3 */

-    FF (b, c, d, a, x[ 3], kS14, 0xc1bdceee); /* 4 */

-    FF (a, b, c, d, x[ 4], kS11, 0xf57c0faf); /* 5 */

-    FF (d, a, b, c, x[ 5], kS12, 0x4787c62a); /* 6 */

-    FF (c, d, a, b, x[ 6], kS13, 0xa8304613); /* 7 */

-    FF (b, c, d, a, x[ 7], kS14, 0xfd469501); /* 8 */

-    FF (a, b, c, d, x[ 8], kS11, 0x698098d8); /* 9 */

-    FF (d, a, b, c, x[ 9], kS12, 0x8b44f7af); /* 10 */

-    FF (c, d, a, b, x[10], kS13, 0xffff5bb1); /* 11 */

-    FF (b, c, d, a, x[11], kS14, 0x895cd7be); /* 12 */

-    FF (a, b, c, d, x[12], kS11, 0x6b901122); /* 13 */

-    FF (d, a, b, c, x[13], kS12, 0xfd987193); /* 14 */

-    FF (c, d, a, b, x[14], kS13, 0xa679438e); /* 15 */

-    FF (b, c, d, a, x[15], kS14, 0x49b40821); /* 16 */

-

-    /* Round 2 */

-    GG (a, b, c, d, x[ 1], kS21, 0xf61e2562); /* 17 */

-    GG (d, a, b, c, x[ 6], kS22, 0xc040b340); /* 18 */

-    GG (c, d, a, b, x[11], kS23, 0x265e5a51); /* 19 */

-    GG (b, c, d, a, x[ 0], kS24, 0xe9b6c7aa); /* 20 */

-    GG (a, b, c, d, x[ 5], kS21, 0xd62f105d); /* 21 */

-    GG (d, a, b, c, x[10], kS22,  0x2441453); /* 22 */

-    GG (c, d, a, b, x[15], kS23, 0xd8a1e681); /* 23 */

-    GG (b, c, d, a, x[ 4], kS24, 0xe7d3fbc8); /* 24 */

-    GG (a, b, c, d, x[ 9], kS21, 0x21e1cde6); /* 25 */

-    GG (d, a, b, c, x[14], kS22, 0xc33707d6); /* 26 */

-    GG (c, d, a, b, x[ 3], kS23, 0xf4d50d87); /* 27 */

-    GG (b, c, d, a, x[ 8], kS24, 0x455a14ed); /* 28 */

-    GG (a, b, c, d, x[13], kS21, 0xa9e3e905); /* 29 */

-    GG (d, a, b, c, x[ 2], kS22, 0xfcefa3f8); /* 30 */

-    GG (c, d, a, b, x[ 7], kS23, 0x676f02d9); /* 31 */

-    GG (b, c, d, a, x[12], kS24, 0x8d2a4c8a); /* 32 */

-

-    /* Round 3 */

-    HH (a, b, c, d, x[ 5], kS31, 0xfffa3942); /* 33 */

-    HH (d, a, b, c, x[ 8], kS32, 0x8771f681); /* 34 */

-    HH (c, d, a, b, x[11], kS33, 0x6d9d6122); /* 35 */

-    HH (b, c, d, a, x[14], kS34, 0xfde5380c); /* 36 */

-    HH (a, b, c, d, x[ 1], kS31, 0xa4beea44); /* 37 */

-    HH (d, a, b, c, x[ 4], kS32, 0x4bdecfa9); /* 38 */

-    HH (c, d, a, b, x[ 7], kS33, 0xf6bb4b60); /* 39 */

-    HH (b, c, d, a, x[10], kS34, 0xbebfbc70); /* 40 */

-    HH (a, b, c, d, x[13], kS31, 0x289b7ec6); /* 41 */

-    HH (d, a, b, c, x[ 0], kS32, 0xeaa127fa); /* 42 */

-    HH (c, d, a, b, x[ 3], kS33, 0xd4ef3085); /* 43 */

-    HH (b, c, d, a, x[ 6], kS34,  0x4881d05); /* 44 */

-    HH (a, b, c, d, x[ 9], kS31, 0xd9d4d039); /* 45 */

-    HH (d, a, b, c, x[12], kS32, 0xe6db99e5); /* 46 */

-    HH (c, d, a, b, x[15], kS33, 0x1fa27cf8); /* 47 */

-    HH (b, c, d, a, x[ 2], kS34, 0xc4ac5665); /* 48 */

-

-    /* Round 4 */

-    II (a, b, c, d, x[ 0], kS41, 0xf4292244); /* 49 */

-    II (d, a, b, c, x[ 7], kS42, 0x432aff97); /* 50 */

-    II (c, d, a, b, x[14], kS43, 0xab9423a7); /* 51 */

-    II (b, c, d, a, x[ 5], kS44, 0xfc93a039); /* 52 */

-    II (a, b, c, d, x[12], kS41, 0x655b59c3); /* 53 */

-    II (d, a, b, c, x[ 3], kS42, 0x8f0ccc92); /* 54 */

-    II (c, d, a, b, x[10], kS43, 0xffeff47d); /* 55 */

-    II (b, c, d, a, x[ 1], kS44, 0x85845dd1); /* 56 */

-    II (a, b, c, d, x[ 8], kS41, 0x6fa87e4f); /* 57 */

-    II (d, a, b, c, x[15], kS42, 0xfe2ce6e0); /* 58 */

-    II (c, d, a, b, x[ 6], kS43, 0xa3014314); /* 59 */

-    II (b, c, d, a, x[13], kS44, 0x4e0811a1); /* 60 */

-    II (a, b, c, d, x[ 4], kS41, 0xf7537e82); /* 61 */

-    II (d, a, b, c, x[11], kS42, 0xbd3af235); /* 62 */

-    II (c, d, a, b, x[ 2], kS43, 0x2ad7d2bb); /* 63 */

-    II (b, c, d, a, x[ 9], kS44, 0xeb86d391); /* 64 */

-

-#else

-    // USC/ISI J. Touch

-    // omit reordering, and use the input block as source data

-    /* Round 1 */

-    FF (a, b, c, d, ((uint32 *)block)[ 0], kS11, 0xd76aa478); /* 1 */

-    FF (d, a, b, c, ((uint32 *)block)[ 1], kS12, 0xe8c7b756); /* 2 */

-    FF (c, d, a, b, ((uint32 *)block)[ 2], kS13, 0x242070db); /* 3 */

-    FF (b, c, d, a, ((uint32 *)block)[ 3], kS14, 0xc1bdceee); /* 4 */

-    FF (a, b, c, d, ((uint32 *)block)[ 4], kS11, 0xf57c0faf); /* 5 */

-    FF (d, a, b, c, ((uint32 *)block)[ 5], kS12, 0x4787c62a); /* 6 */

-    FF (c, d, a, b, ((uint32 *)block)[ 6], kS13, 0xa8304613); /* 7 */

-    FF (b, c, d, a, ((uint32 *)block)[ 7], kS14, 0xfd469501); /* 8 */

-    FF (a, b, c, d, ((uint32 *)block)[ 8], kS11, 0x698098d8); /* 9 */

-    FF (d, a, b, c, ((uint32 *)block)[ 9], kS12, 0x8b44f7af); /* 10 */

-    FF (c, d, a, b, ((uint32 *)block)[10], kS13, 0xffff5bb1); /* 11 */

-    FF (b, c, d, a, ((uint32 *)block)[11], kS14, 0x895cd7be); /* 12 */

-    FF (a, b, c, d, ((uint32 *)block)[12], kS11, 0x6b901122); /* 13 */

-    FF (d, a, b, c, ((uint32 *)block)[13], kS12, 0xfd987193); /* 14 */

-    FF (c, d, a, b, ((uint32 *)block)[14], kS13, 0xa679438e); /* 15 */

-    FF (b, c, d, a, ((uint32 *)block)[15], kS14, 0x49b40821); /* 16 */

-

-    /* Round 2 */

-    GG (a, b, c, d, ((uint32 *)block)[ 1], kS21, 0xf61e2562); /* 17 */

-    GG (d, a, b, c, ((uint32 *)block)[ 6], kS22, 0xc040b340); /* 18 */

-    GG (c, d, a, b, ((uint32 *)block)[11], kS23, 0x265e5a51); /* 19 */

-    GG (b, c, d, a, ((uint32 *)block)[ 0], kS24, 0xe9b6c7aa); /* 20 */

-    GG (a, b, c, d, ((uint32 *)block)[ 5], kS21, 0xd62f105d); /* 21 */

-    GG (d, a, b, c, ((uint32 *)block)[10], kS22,  0x2441453); /* 22 */

-    GG (c, d, a, b, ((uint32 *)block)[15], kS23, 0xd8a1e681); /* 23 */

-    GG (b, c, d, a, ((uint32 *)block)[ 4], kS24, 0xe7d3fbc8); /* 24 */

-    GG (a, b, c, d, ((uint32 *)block)[ 9], kS21, 0x21e1cde6); /* 25 */

-    GG (d, a, b, c, ((uint32 *)block)[14], kS22, 0xc33707d6); /* 26 */

-    GG (c, d, a, b, ((uint32 *)block)[ 3], kS23, 0xf4d50d87); /* 27 */

-    GG (b, c, d, a, ((uint32 *)block)[ 8], kS24, 0x455a14ed); /* 28 */

-    GG (a, b, c, d, ((uint32 *)block)[13], kS21, 0xa9e3e905); /* 29 */

-    GG (d, a, b, c, ((uint32 *)block)[ 2], kS22, 0xfcefa3f8); /* 30 */

-    GG (c, d, a, b, ((uint32 *)block)[ 7], kS23, 0x676f02d9); /* 31 */

-    GG (b, c, d, a, ((uint32 *)block)[12], kS24, 0x8d2a4c8a); /* 32 */

-

-    /* Round 3 */

-    HH (a, b, c, d, ((uint32 *)block)[ 5], kS31, 0xfffa3942); /* 33 */

-    HH (d, a, b, c, ((uint32 *)block)[ 8], kS32, 0x8771f681); /* 34 */

-    HH (c, d, a, b, ((uint32 *)block)[11], kS33, 0x6d9d6122); /* 35 */

-    HH (b, c, d, a, ((uint32 *)block)[14], kS34, 0xfde5380c); /* 36 */

-    HH (a, b, c, d, ((uint32 *)block)[ 1], kS31, 0xa4beea44); /* 37 */

-    HH (d, a, b, c, ((uint32 *)block)[ 4], kS32, 0x4bdecfa9); /* 38 */

-    HH (c, d, a, b, ((uint32 *)block)[ 7], kS33, 0xf6bb4b60); /* 39 */

-    HH (b, c, d, a, ((uint32 *)block)[10], kS34, 0xbebfbc70); /* 40 */

-    HH (a, b, c, d, ((uint32 *)block)[13], kS31, 0x289b7ec6); /* 41 */

-    HH (d, a, b, c, ((uint32 *)block)[ 0], kS32, 0xeaa127fa); /* 42 */

-    HH (c, d, a, b, ((uint32 *)block)[ 3], kS33, 0xd4ef3085); /* 43 */

-    HH (b, c, d, a, ((uint32 *)block)[ 6], kS34,  0x4881d05); /* 44 */

-    HH (a, b, c, d, ((uint32 *)block)[ 9], kS31, 0xd9d4d039); /* 45 */

-    HH (d, a, b, c, ((uint32 *)block)[12], kS32, 0xe6db99e5); /* 46 */

-    HH (c, d, a, b, ((uint32 *)block)[15], kS33, 0x1fa27cf8); /* 47 */

-    HH (b, c, d, a, ((uint32 *)block)[ 2], kS34, 0xc4ac5665); /* 48 */

-

-    /* Round 4 */

-    II (a, b, c, d, ((uint32 *)block)[ 0], kS41, 0xf4292244); /* 49 */

-    II (d, a, b, c, ((uint32 *)block)[ 7], kS42, 0x432aff97); /* 50 */

-    II (c, d, a, b, ((uint32 *)block)[14], kS43, 0xab9423a7); /* 51 */

-    II (b, c, d, a, ((uint32 *)block)[ 5], kS44, 0xfc93a039); /* 52 */

-    II (a, b, c, d, ((uint32 *)block)[12], kS41, 0x655b59c3); /* 53 */

-    II (d, a, b, c, ((uint32 *)block)[ 3], kS42, 0x8f0ccc92); /* 54 */

-    II (c, d, a, b, ((uint32 *)block)[10], kS43, 0xffeff47d); /* 55 */

-    II (b, c, d, a, ((uint32 *)block)[ 1], kS44, 0x85845dd1); /* 56 */

-    II (a, b, c, d, ((uint32 *)block)[ 8], kS41, 0x6fa87e4f); /* 57 */

-    II (d, a, b, c, ((uint32 *)block)[15], kS42, 0xfe2ce6e0); /* 58 */

-    II (c, d, a, b, ((uint32 *)block)[ 6], kS43, 0xa3014314); /* 59 */

-    II (b, c, d, a, ((uint32 *)block)[13], kS44, 0x4e0811a1); /* 60 */

-    II (a, b, c, d, ((uint32 *)block)[ 4], kS41, 0xf7537e82); /* 61 */

-    II (d, a, b, c, ((uint32 *)block)[11], kS42, 0xbd3af235); /* 62 */

-    II (c, d, a, b, ((uint32 *)block)[ 2], kS43, 0x2ad7d2bb); /* 63 */

-    II (b, c, d, a, ((uint32 *)block)[ 9], kS44, 0xeb86d391); /* 64 */

-#endif  // REORDER

-

-    state[0] += a;

-    state[1] += b;

-    state[2] += c;

-    state[3] += d;

-

-#ifdef REORDER

-    memset ((POINTER)x, 0, sizeof (x));  // zero sensitive information

-#endif

-}

-

-// Encodes input (uint32) into output (unsigned char). Assumes len is a multiple of 4.

-void Encode (unsigned char *output, uint32 *input, unsigned int len) {

-    ASSERT(input, (L""));

-    ASSERT(output, (L""));

-

-    unsigned int i, j;

-

-    for (i = 0, j = 0; j < len; i++, j += 4) {

-        output[j] = (unsigned char)(input[i] & 0xff);

-        output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);

-        output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);

-        output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);

-        }

-}

-

-#ifdef REORDER

-

-// Decodes input (unsigned char) into output (uint32). Assumes len is a multiple of 4.

-void Decode (uint32 *output, unsigned char *input, unsigned int len) {

-    ASSERT(input, (L""));

-    ASSERT(output, (L""));

-

-    register uint32 out,other;

-

-    // for (i = 0, j = 0; j < len; i++, j += 4)

-    // output[i] = ((uint32)input[j]) | (((uint32)input[j+1]) << 8) |

-    // (((uint32)input[j+2]) << 16) | (((uint32)input[j+3]) << 24);

-

-    // USC/ISI J. Touch

-    // these are optimized swap routines, in C code they cost more in "computation" operations, but less in

-    // "loads" than the above code, and run substantially faster as a result

-#if (!defined(hpux))

-#define swapbyte(src,dst) { \

-     out = ROTATE_LEFT((src),16); \

-     other = out >> 8; \

-     other &= 0x00ff00ff; \

-     out &= 0x00ff00ff; \

-     out <<= 8; \

-     (dst) = out | other; \

-     }

-#else

-#define swapbyte(src,dst) { \

-     (dst) = (ROTATE_LEFT((src),8) & 0x00ff00ff) | ROTATE_LEFT((src) & 0x00ff00ff,24); \

-     }

-#endif

-

-    // USC/ISI J. Touch

-    // unroll the loop above, because the code runs faster with constants for indices than even with variable indices

-    // as conventional (automatic) unrolling would perform (!)

-    swapbyte(((uint32 *)input)[0],output[0]);

-    swapbyte(((uint32 *)input)[1],output[1]);

-    swapbyte(((uint32 *)input)[2],output[2]);

-    swapbyte(((uint32 *)input)[3],output[3]);

-    swapbyte(((uint32 *)input)[4],output[4]);

-    swapbyte(((uint32 *)input)[5],output[5]);

-    swapbyte(((uint32 *)input)[6],output[6]);

-    swapbyte(((uint32 *)input)[7],output[7]);

-    swapbyte(((uint32 *)input)[8],output[8]);

-    swapbyte(((uint32 *)input)[9],output[9]);

-    swapbyte(((uint32 *)input)[10],output[10]);

-    swapbyte(((uint32 *)input)[11],output[11]);

-    swapbyte(((uint32 *)input)[12],output[12]);

-    swapbyte(((uint32 *)input)[13],output[13]);

-    swapbyte(((uint32 *)input)[14],output[14]);

-    swapbyte(((uint32 *)input)[15],output[15]);

-}

-

-#endif // #ifdef REORDER

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+/*
+ * md5_opt.c V1.0 - optimized md5c.c from RFC1321 reference implementation
+ *
+ * Copyright (c) 1995 University of Southern California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation, advertising
+ * materials, and other materials related to such distribution and use
+ * acknowledge that the software was developed by the University of
+ * Southern California, Information Sciences Institute.  The name of the
+ * University may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ J. Touch / touch@isi.edu
+ 5/1/95
+
+*/
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+#include "md5.h"
+#include "common/debug.h"
+
+namespace omaha {
+
+#if (defined(i386) || defined (__i386__) || defined (_M_IX86) || defined(__alpha))  // little-endian
+#undef REORDER
+#else
+#define REORDER 1
+#endif
+
+// Constants for MD5Transform routine
+#define kS11 7
+#define kS12 12
+#define kS13 17
+#define kS14 22
+#define kS21 5
+#define kS22 9
+#define kS23 14
+#define kS24 20
+#define kS31 4
+#define kS32 11
+#define kS33 16
+#define kS34 23
+#define kS41 6
+#define kS42 10
+#define kS43 15
+#define kS44 21
+
+static void MD5Transform (uint32 [4], unsigned char [64]);
+static void Encode (unsigned char *, uint32 *, unsigned int);
+#ifdef REORDER
+static void Decode (uint32 *, unsigned char *, unsigned int);
+#endif
+
+// SELECTANY static unsigned char PADDING[64] = {
+static unsigned char PADDING[64] = {
+    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+// F, G, H and I are basic MD5 functions.
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+// ROTATE_LEFT rotates x left n bits.
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+// Rotation is separate from addition to prevent recomputation.
+#define FF(a, b, c, d, x, s, ac) { \
+    (a) += F ((b), (c), (d)) + (x) + (uint32)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+    }
+#define GG(a, b, c, d, x, s, ac) { \
+    (a) += G ((b), (c), (d)) + (x) + (uint32)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+    }
+#define HH(a, b, c, d, x, s, ac) { \
+    (a) += H ((b), (c), (d)) + (x) + (uint32)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+    }
+#define II(a, b, c, d, x, s, ac) { \
+    (a) += I ((b), (c), (d)) + (x) + (uint32)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+    }
+
+// MD5 initialization. Begins an MD5 operation, writing a new context.
+void MD5Init (MD5_CTX *context) {
+    ASSERT(context, (L""));
+
+    context->count[0] = context->count[1] = 0;
+    // Load magic initialization constants.
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xefcdab89;
+    context->state[2] = 0x98badcfe;
+    context->state[3] = 0x10325476;
+}
+
+// MD5 block update operation. Continues an MD5 message-digest
+// operation, processing another message block, and updating the context.
+void MD5Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen) {
+    ASSERT(input, (L""));
+    ASSERT(context, (L""));
+
+    unsigned int i, index, partLen;
+
+    // Compute number of bytes mod 64
+    index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+    // Update number of bits
+    if ((context->count[0] += ((uint32)inputLen << 3)) < ((uint32)inputLen << 3))
+        context->count[1]++;
+
+    context->count[1] += ((uint32)inputLen >> 29);
+    partLen = 64 - index;
+
+    // Transform as many times as possible
+    if (inputLen >= partLen) {
+       memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+       MD5Transform (context->state, context->buffer);
+
+       for (i = partLen; i + 63 < inputLen; i += 64) MD5Transform (context->state, &input[i]);
+       index = 0;
+       }
+    else
+       i = 0;
+
+    // Buffer remaining input
+    memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
+}
+
+// MD5 finalization. Ends an MD5 message-digest operation, writing the
+// the message digest and zeroizing the context.
+void MD5Final (unsigned char digest[16], MD5_CTX *context) {
+    ASSERT(context, (L""));
+
+    unsigned char bits[8];
+    unsigned int index, padLen;
+
+    // Save number of bits
+    Encode (bits, context->count, 8);
+
+    // Pad out to 56 mod 64.
+    index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+    padLen = (index < 56) ? (56 - index) : (120 - index);
+    MD5Update (context, PADDING, padLen);
+
+    // Append length (before padding)
+    MD5Update (context, bits, 8);
+    // Store state in digest
+    Encode (digest, context->state, 16);
+
+    // Zeroize sensitive information.
+    memset ((POINTER)context, 0, sizeof (*context));
+}
+
+// MD5 basic transformation. Transforms state based on block.
+void MD5Transform (uint32 state[4], unsigned char block[64]) {
+    // USC/ISI J. Touch - encourage pushing state variables into registers
+    register uint32 a = state[0], b = state[1], c = state[2], d = state[3];
+
+    /* USC/ISI J. Touch
+    decode and using copied data vs. direct use of input buffer
+    depends on whether reordering is required, which is a combination
+    of the byte order of the architecture and the command-line option
+    override
+    */
+
+#ifdef REORDER
+    uint32 x[16];
+
+    Decode (x, block, 64);
+
+    /* Round 1 */
+    FF (a, b, c, d, x[ 0], kS11, 0xd76aa478); /* 1 */
+    FF (d, a, b, c, x[ 1], kS12, 0xe8c7b756); /* 2 */
+    FF (c, d, a, b, x[ 2], kS13, 0x242070db); /* 3 */
+    FF (b, c, d, a, x[ 3], kS14, 0xc1bdceee); /* 4 */
+    FF (a, b, c, d, x[ 4], kS11, 0xf57c0faf); /* 5 */
+    FF (d, a, b, c, x[ 5], kS12, 0x4787c62a); /* 6 */
+    FF (c, d, a, b, x[ 6], kS13, 0xa8304613); /* 7 */
+    FF (b, c, d, a, x[ 7], kS14, 0xfd469501); /* 8 */
+    FF (a, b, c, d, x[ 8], kS11, 0x698098d8); /* 9 */
+    FF (d, a, b, c, x[ 9], kS12, 0x8b44f7af); /* 10 */
+    FF (c, d, a, b, x[10], kS13, 0xffff5bb1); /* 11 */
+    FF (b, c, d, a, x[11], kS14, 0x895cd7be); /* 12 */
+    FF (a, b, c, d, x[12], kS11, 0x6b901122); /* 13 */
+    FF (d, a, b, c, x[13], kS12, 0xfd987193); /* 14 */
+    FF (c, d, a, b, x[14], kS13, 0xa679438e); /* 15 */
+    FF (b, c, d, a, x[15], kS14, 0x49b40821); /* 16 */
+
+    /* Round 2 */
+    GG (a, b, c, d, x[ 1], kS21, 0xf61e2562); /* 17 */
+    GG (d, a, b, c, x[ 6], kS22, 0xc040b340); /* 18 */
+    GG (c, d, a, b, x[11], kS23, 0x265e5a51); /* 19 */
+    GG (b, c, d, a, x[ 0], kS24, 0xe9b6c7aa); /* 20 */
+    GG (a, b, c, d, x[ 5], kS21, 0xd62f105d); /* 21 */
+    GG (d, a, b, c, x[10], kS22,  0x2441453); /* 22 */
+    GG (c, d, a, b, x[15], kS23, 0xd8a1e681); /* 23 */
+    GG (b, c, d, a, x[ 4], kS24, 0xe7d3fbc8); /* 24 */
+    GG (a, b, c, d, x[ 9], kS21, 0x21e1cde6); /* 25 */
+    GG (d, a, b, c, x[14], kS22, 0xc33707d6); /* 26 */
+    GG (c, d, a, b, x[ 3], kS23, 0xf4d50d87); /* 27 */
+    GG (b, c, d, a, x[ 8], kS24, 0x455a14ed); /* 28 */
+    GG (a, b, c, d, x[13], kS21, 0xa9e3e905); /* 29 */
+    GG (d, a, b, c, x[ 2], kS22, 0xfcefa3f8); /* 30 */
+    GG (c, d, a, b, x[ 7], kS23, 0x676f02d9); /* 31 */
+    GG (b, c, d, a, x[12], kS24, 0x8d2a4c8a); /* 32 */
+
+    /* Round 3 */
+    HH (a, b, c, d, x[ 5], kS31, 0xfffa3942); /* 33 */
+    HH (d, a, b, c, x[ 8], kS32, 0x8771f681); /* 34 */
+    HH (c, d, a, b, x[11], kS33, 0x6d9d6122); /* 35 */
+    HH (b, c, d, a, x[14], kS34, 0xfde5380c); /* 36 */
+    HH (a, b, c, d, x[ 1], kS31, 0xa4beea44); /* 37 */
+    HH (d, a, b, c, x[ 4], kS32, 0x4bdecfa9); /* 38 */
+    HH (c, d, a, b, x[ 7], kS33, 0xf6bb4b60); /* 39 */
+    HH (b, c, d, a, x[10], kS34, 0xbebfbc70); /* 40 */
+    HH (a, b, c, d, x[13], kS31, 0x289b7ec6); /* 41 */
+    HH (d, a, b, c, x[ 0], kS32, 0xeaa127fa); /* 42 */
+    HH (c, d, a, b, x[ 3], kS33, 0xd4ef3085); /* 43 */
+    HH (b, c, d, a, x[ 6], kS34,  0x4881d05); /* 44 */
+    HH (a, b, c, d, x[ 9], kS31, 0xd9d4d039); /* 45 */
+    HH (d, a, b, c, x[12], kS32, 0xe6db99e5); /* 46 */
+    HH (c, d, a, b, x[15], kS33, 0x1fa27cf8); /* 47 */
+    HH (b, c, d, a, x[ 2], kS34, 0xc4ac5665); /* 48 */
+
+    /* Round 4 */
+    II (a, b, c, d, x[ 0], kS41, 0xf4292244); /* 49 */
+    II (d, a, b, c, x[ 7], kS42, 0x432aff97); /* 50 */
+    II (c, d, a, b, x[14], kS43, 0xab9423a7); /* 51 */
+    II (b, c, d, a, x[ 5], kS44, 0xfc93a039); /* 52 */
+    II (a, b, c, d, x[12], kS41, 0x655b59c3); /* 53 */
+    II (d, a, b, c, x[ 3], kS42, 0x8f0ccc92); /* 54 */
+    II (c, d, a, b, x[10], kS43, 0xffeff47d); /* 55 */
+    II (b, c, d, a, x[ 1], kS44, 0x85845dd1); /* 56 */
+    II (a, b, c, d, x[ 8], kS41, 0x6fa87e4f); /* 57 */
+    II (d, a, b, c, x[15], kS42, 0xfe2ce6e0); /* 58 */
+    II (c, d, a, b, x[ 6], kS43, 0xa3014314); /* 59 */
+    II (b, c, d, a, x[13], kS44, 0x4e0811a1); /* 60 */
+    II (a, b, c, d, x[ 4], kS41, 0xf7537e82); /* 61 */
+    II (d, a, b, c, x[11], kS42, 0xbd3af235); /* 62 */
+    II (c, d, a, b, x[ 2], kS43, 0x2ad7d2bb); /* 63 */
+    II (b, c, d, a, x[ 9], kS44, 0xeb86d391); /* 64 */
+
+#else
+    // USC/ISI J. Touch
+    // omit reordering, and use the input block as source data
+    /* Round 1 */
+    FF (a, b, c, d, ((uint32 *)block)[ 0], kS11, 0xd76aa478); /* 1 */
+    FF (d, a, b, c, ((uint32 *)block)[ 1], kS12, 0xe8c7b756); /* 2 */
+    FF (c, d, a, b, ((uint32 *)block)[ 2], kS13, 0x242070db); /* 3 */
+    FF (b, c, d, a, ((uint32 *)block)[ 3], kS14, 0xc1bdceee); /* 4 */
+    FF (a, b, c, d, ((uint32 *)block)[ 4], kS11, 0xf57c0faf); /* 5 */
+    FF (d, a, b, c, ((uint32 *)block)[ 5], kS12, 0x4787c62a); /* 6 */
+    FF (c, d, a, b, ((uint32 *)block)[ 6], kS13, 0xa8304613); /* 7 */
+    FF (b, c, d, a, ((uint32 *)block)[ 7], kS14, 0xfd469501); /* 8 */
+    FF (a, b, c, d, ((uint32 *)block)[ 8], kS11, 0x698098d8); /* 9 */
+    FF (d, a, b, c, ((uint32 *)block)[ 9], kS12, 0x8b44f7af); /* 10 */
+    FF (c, d, a, b, ((uint32 *)block)[10], kS13, 0xffff5bb1); /* 11 */
+    FF (b, c, d, a, ((uint32 *)block)[11], kS14, 0x895cd7be); /* 12 */
+    FF (a, b, c, d, ((uint32 *)block)[12], kS11, 0x6b901122); /* 13 */
+    FF (d, a, b, c, ((uint32 *)block)[13], kS12, 0xfd987193); /* 14 */
+    FF (c, d, a, b, ((uint32 *)block)[14], kS13, 0xa679438e); /* 15 */
+    FF (b, c, d, a, ((uint32 *)block)[15], kS14, 0x49b40821); /* 16 */
+
+    /* Round 2 */
+    GG (a, b, c, d, ((uint32 *)block)[ 1], kS21, 0xf61e2562); /* 17 */
+    GG (d, a, b, c, ((uint32 *)block)[ 6], kS22, 0xc040b340); /* 18 */
+    GG (c, d, a, b, ((uint32 *)block)[11], kS23, 0x265e5a51); /* 19 */
+    GG (b, c, d, a, ((uint32 *)block)[ 0], kS24, 0xe9b6c7aa); /* 20 */
+    GG (a, b, c, d, ((uint32 *)block)[ 5], kS21, 0xd62f105d); /* 21 */
+    GG (d, a, b, c, ((uint32 *)block)[10], kS22,  0x2441453); /* 22 */
+    GG (c, d, a, b, ((uint32 *)block)[15], kS23, 0xd8a1e681); /* 23 */
+    GG (b, c, d, a, ((uint32 *)block)[ 4], kS24, 0xe7d3fbc8); /* 24 */
+    GG (a, b, c, d, ((uint32 *)block)[ 9], kS21, 0x21e1cde6); /* 25 */
+    GG (d, a, b, c, ((uint32 *)block)[14], kS22, 0xc33707d6); /* 26 */
+    GG (c, d, a, b, ((uint32 *)block)[ 3], kS23, 0xf4d50d87); /* 27 */
+    GG (b, c, d, a, ((uint32 *)block)[ 8], kS24, 0x455a14ed); /* 28 */
+    GG (a, b, c, d, ((uint32 *)block)[13], kS21, 0xa9e3e905); /* 29 */
+    GG (d, a, b, c, ((uint32 *)block)[ 2], kS22, 0xfcefa3f8); /* 30 */
+    GG (c, d, a, b, ((uint32 *)block)[ 7], kS23, 0x676f02d9); /* 31 */
+    GG (b, c, d, a, ((uint32 *)block)[12], kS24, 0x8d2a4c8a); /* 32 */
+
+    /* Round 3 */
+    HH (a, b, c, d, ((uint32 *)block)[ 5], kS31, 0xfffa3942); /* 33 */
+    HH (d, a, b, c, ((uint32 *)block)[ 8], kS32, 0x8771f681); /* 34 */
+    HH (c, d, a, b, ((uint32 *)block)[11], kS33, 0x6d9d6122); /* 35 */
+    HH (b, c, d, a, ((uint32 *)block)[14], kS34, 0xfde5380c); /* 36 */
+    HH (a, b, c, d, ((uint32 *)block)[ 1], kS31, 0xa4beea44); /* 37 */
+    HH (d, a, b, c, ((uint32 *)block)[ 4], kS32, 0x4bdecfa9); /* 38 */
+    HH (c, d, a, b, ((uint32 *)block)[ 7], kS33, 0xf6bb4b60); /* 39 */
+    HH (b, c, d, a, ((uint32 *)block)[10], kS34, 0xbebfbc70); /* 40 */
+    HH (a, b, c, d, ((uint32 *)block)[13], kS31, 0x289b7ec6); /* 41 */
+    HH (d, a, b, c, ((uint32 *)block)[ 0], kS32, 0xeaa127fa); /* 42 */
+    HH (c, d, a, b, ((uint32 *)block)[ 3], kS33, 0xd4ef3085); /* 43 */
+    HH (b, c, d, a, ((uint32 *)block)[ 6], kS34,  0x4881d05); /* 44 */
+    HH (a, b, c, d, ((uint32 *)block)[ 9], kS31, 0xd9d4d039); /* 45 */
+    HH (d, a, b, c, ((uint32 *)block)[12], kS32, 0xe6db99e5); /* 46 */
+    HH (c, d, a, b, ((uint32 *)block)[15], kS33, 0x1fa27cf8); /* 47 */
+    HH (b, c, d, a, ((uint32 *)block)[ 2], kS34, 0xc4ac5665); /* 48 */
+
+    /* Round 4 */
+    II (a, b, c, d, ((uint32 *)block)[ 0], kS41, 0xf4292244); /* 49 */
+    II (d, a, b, c, ((uint32 *)block)[ 7], kS42, 0x432aff97); /* 50 */
+    II (c, d, a, b, ((uint32 *)block)[14], kS43, 0xab9423a7); /* 51 */
+    II (b, c, d, a, ((uint32 *)block)[ 5], kS44, 0xfc93a039); /* 52 */
+    II (a, b, c, d, ((uint32 *)block)[12], kS41, 0x655b59c3); /* 53 */
+    II (d, a, b, c, ((uint32 *)block)[ 3], kS42, 0x8f0ccc92); /* 54 */
+    II (c, d, a, b, ((uint32 *)block)[10], kS43, 0xffeff47d); /* 55 */
+    II (b, c, d, a, ((uint32 *)block)[ 1], kS44, 0x85845dd1); /* 56 */
+    II (a, b, c, d, ((uint32 *)block)[ 8], kS41, 0x6fa87e4f); /* 57 */
+    II (d, a, b, c, ((uint32 *)block)[15], kS42, 0xfe2ce6e0); /* 58 */
+    II (c, d, a, b, ((uint32 *)block)[ 6], kS43, 0xa3014314); /* 59 */
+    II (b, c, d, a, ((uint32 *)block)[13], kS44, 0x4e0811a1); /* 60 */
+    II (a, b, c, d, ((uint32 *)block)[ 4], kS41, 0xf7537e82); /* 61 */
+    II (d, a, b, c, ((uint32 *)block)[11], kS42, 0xbd3af235); /* 62 */
+    II (c, d, a, b, ((uint32 *)block)[ 2], kS43, 0x2ad7d2bb); /* 63 */
+    II (b, c, d, a, ((uint32 *)block)[ 9], kS44, 0xeb86d391); /* 64 */
+#endif  // REORDER
+
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+
+#ifdef REORDER
+    memset ((POINTER)x, 0, sizeof (x));  // zero sensitive information
+#endif
+}
+
+// Encodes input (uint32) into output (unsigned char). Assumes len is a multiple of 4.
+void Encode (unsigned char *output, uint32 *input, unsigned int len) {
+    ASSERT(input, (L""));
+    ASSERT(output, (L""));
+
+    unsigned int i, j;
+
+    for (i = 0, j = 0; j < len; i++, j += 4) {
+        output[j] = (unsigned char)(input[i] & 0xff);
+        output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+        output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+        output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+        }
+}
+
+#ifdef REORDER
+
+// Decodes input (unsigned char) into output (uint32). Assumes len is a multiple of 4.
+void Decode (uint32 *output, unsigned char *input, unsigned int len) {
+    ASSERT(input, (L""));
+    ASSERT(output, (L""));
+
+    register uint32 out,other;
+
+    // for (i = 0, j = 0; j < len; i++, j += 4)
+    // output[i] = ((uint32)input[j]) | (((uint32)input[j+1]) << 8) |
+    // (((uint32)input[j+2]) << 16) | (((uint32)input[j+3]) << 24);
+
+    // USC/ISI J. Touch
+    // these are optimized swap routines, in C code they cost more in "computation" operations, but less in
+    // "loads" than the above code, and run substantially faster as a result
+#if (!defined(hpux))
+#define swapbyte(src,dst) { \
+     out = ROTATE_LEFT((src),16); \
+     other = out >> 8; \
+     other &= 0x00ff00ff; \
+     out &= 0x00ff00ff; \
+     out <<= 8; \
+     (dst) = out | other; \
+     }
+#else
+#define swapbyte(src,dst) { \
+     (dst) = (ROTATE_LEFT((src),8) & 0x00ff00ff) | ROTATE_LEFT((src) & 0x00ff00ff,24); \
+     }
+#endif
+
+    // USC/ISI J. Touch
+    // unroll the loop above, because the code runs faster with constants for indices than even with variable indices
+    // as conventional (automatic) unrolling would perform (!)
+    swapbyte(((uint32 *)input)[0],output[0]);
+    swapbyte(((uint32 *)input)[1],output[1]);
+    swapbyte(((uint32 *)input)[2],output[2]);
+    swapbyte(((uint32 *)input)[3],output[3]);
+    swapbyte(((uint32 *)input)[4],output[4]);
+    swapbyte(((uint32 *)input)[5],output[5]);
+    swapbyte(((uint32 *)input)[6],output[6]);
+    swapbyte(((uint32 *)input)[7],output[7]);
+    swapbyte(((uint32 *)input)[8],output[8]);
+    swapbyte(((uint32 *)input)[9],output[9]);
+    swapbyte(((uint32 *)input)[10],output[10]);
+    swapbyte(((uint32 *)input)[11],output[11]);
+    swapbyte(((uint32 *)input)[12],output[12]);
+    swapbyte(((uint32 *)input)[13],output[13]);
+    swapbyte(((uint32 *)input)[14],output[14]);
+    swapbyte(((uint32 *)input)[15],output[15]);
+}
+
+#endif // #ifdef REORDER
+
+}  // namespace omaha
+
diff --git a/common/md5.h b/common/md5.h
index e647307..a688c3d 100644
--- a/common/md5.h
+++ b/common/md5.h
@@ -1,67 +1,67 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-/* MD5.H - header file for MD5C.C

-*/

-

-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All

-rights reserved.

-

-License to copy and use this software is granted provided that it

-is identified as the "RSA Data Security, Inc. MD5 Message-Digest

-Algorithm" in all material mentioning or referencing this software

-or this function.

-

-License is also granted to make and use derivative works provided

-that such works are identified as "derived from the RSA Data

-Security, Inc. MD5 Message-Digest Algorithm" in all material

-mentioning or referencing the derived work.

-

-RSA Data Security, Inc. makes no representations concerning either

-the merchantability of this software or the suitability of this

-software for any particular purpose. It is provided "as is"

-without express or implied warranty of any kind.

-

-These notices must be retained in any copies of any part of this

-documentation and/or software.

-*/

-

-/* GLOBAL.H - RSAREF types and constants

-*/

-

-#ifndef TR_COMMON_MD5_H_

-#define TR_COMMON_MD5_H_

-

-#include "base/basictypes.h"

-

-namespace omaha {

-

-/* POINTER defines a generic pointer type */

-typedef unsigned char *POINTER;

-

-/* MD5 context */

-typedef struct {

-  uint32 state[4];                                  /* state (ABCD) */

-  uint32 count[2];        /* number of bits, modulo 2^64 (lsb first) */

-  unsigned char buffer[64];                         /* input buffer */

-} MD5_CTX;

-

-void MD5Init (MD5_CTX *);

-void MD5Update (MD5_CTX *, unsigned char *, unsigned int);

-void MD5Final (unsigned char [16], MD5_CTX *);

-

-}  // namespace omaha

-

-#endif  // TR_COMMON_MD5_H_

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+/* MD5.H - header file for MD5C.C
+*/
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+/* GLOBAL.H - RSAREF types and constants
+*/
+
+#ifndef TR_COMMON_MD5_H_
+#define TR_COMMON_MD5_H_
+
+#include "base/basictypes.h"
+
+namespace omaha {
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* MD5 context */
+typedef struct {
+  uint32 state[4];                                  /* state (ABCD) */
+  uint32 count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                         /* input buffer */
+} MD5_CTX;
+
+void MD5Init (MD5_CTX *);
+void MD5Update (MD5_CTX *, unsigned char *, unsigned int);
+void MD5Final (unsigned char [16], MD5_CTX *);
+
+}  // namespace omaha
+
+#endif  // TR_COMMON_MD5_H_
diff --git a/common/md5_unittest.cc b/common/md5_unittest.cc
index 85011dc..ac4ff42 100644
--- a/common/md5_unittest.cc
+++ b/common/md5_unittest.cc
@@ -1,58 +1,58 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// MD5 unittest

-

-#include <atlstr.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/md5.h"

-#include "omaha/common/string.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-void CheckMD5 (char *string, TCHAR *correct_digest) {

-    ASSERT_TRUE(correct_digest);

-    ASSERT_TRUE(string);

-

-    MD5_CTX context;

-    MD5Init (&context);

-    MD5Update (&context, (unsigned char *)string, strlen (string));

-    unsigned char digest[16];

-    MD5Final (digest, &context);

-

-    const DWORD digest_len = 32+1;

-    TCHAR digest_string[digest_len];

-    digest_string[31] = '\0';

-    digest_string[0] = '\0';

-

-    for (int i = 0; i < 16; i++) {

-        SafeStrCat (digest_string, SPRINTF (_T("%02x"), digest[i]), digest_len);

-    }

-

-    ASSERT_STREQ(digest_string, correct_digest);

-}

-

-TEST(Md5Test, MD5) {

-    CheckMD5 ("", _T("d41d8cd98f00b204e9800998ecf8427e"));

-    CheckMD5 ("a", _T("0cc175b9c0f1b6a831c399e269772661"));

-    CheckMD5 ("abc", _T("900150983cd24fb0d6963f7d28e17f72"));

-    CheckMD5 ("message digest", _T("f96b697d7cb7938d525a2f31aaf161d0"));

-    CheckMD5 ("abcdefghijklmnopqrstuvwxyz", _T("c3fcd3d76192e4007dfb496cca67e13b"));

-    CheckMD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", _T("d174ab98d277d9f5a5611c2c9f419d9f"));

-    CheckMD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890", _T("57edf4a22be3c955ac49da2e2107b67a"));

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// MD5 unittest
+
+#include <atlstr.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/md5.h"
+#include "omaha/common/string.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+void CheckMD5 (char *string, TCHAR *correct_digest) {
+    ASSERT_TRUE(correct_digest);
+    ASSERT_TRUE(string);
+
+    MD5_CTX context;
+    MD5Init (&context);
+    MD5Update (&context, (unsigned char *)string, strlen (string));
+    unsigned char digest[16];
+    MD5Final (digest, &context);
+
+    const DWORD digest_len = 32+1;
+    TCHAR digest_string[digest_len];
+    digest_string[31] = '\0';
+    digest_string[0] = '\0';
+
+    for (int i = 0; i < 16; i++) {
+        SafeStrCat (digest_string, SPRINTF (_T("%02x"), digest[i]), digest_len);
+    }
+
+    ASSERT_STREQ(digest_string, correct_digest);
+}
+
+TEST(Md5Test, MD5) {
+    CheckMD5 ("", _T("d41d8cd98f00b204e9800998ecf8427e"));
+    CheckMD5 ("a", _T("0cc175b9c0f1b6a831c399e269772661"));
+    CheckMD5 ("abc", _T("900150983cd24fb0d6963f7d28e17f72"));
+    CheckMD5 ("message digest", _T("f96b697d7cb7938d525a2f31aaf161d0"));
+    CheckMD5 ("abcdefghijklmnopqrstuvwxyz", _T("c3fcd3d76192e4007dfb496cca67e13b"));
+    CheckMD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", _T("d174ab98d277d9f5a5611c2c9f419d9f"));
+    CheckMD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890", _T("57edf4a22be3c955ac49da2e2107b67a"));
+}
+
+}  // namespace omaha
+
diff --git a/common/module_utils.cc b/common/module_utils.cc
index cc7d758..2a34a4c 100644
--- a/common/module_utils.cc
+++ b/common/module_utils.cc
@@ -1,91 +1,91 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/module_utils.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-const int kLongPath = (_MAX_PATH * 2);

-const int kReallyLongPath = (kLongPath * 2);

-

-HMODULE ModuleFromStatic(void* pointer_to_static_in_module) {

-  ASSERT(pointer_to_static_in_module, (L""));

-

-  MEMORY_BASIC_INFORMATION info = { 0 };

-  VirtualQuery(reinterpret_cast<void*>(pointer_to_static_in_module),

-    &info, sizeof(info));

-  // Module handles are just the allocation base address of the module.

-  return reinterpret_cast<HMODULE>(info.AllocationBase);

-}

-

-bool GetModuleDirectory(HMODULE module, TCHAR* directory) {

-  ASSERT(directory, (L"Invalid arguments"));

-  if (!directory) {

-    return false;

-  }

-

-  // PathRemoveFileSpec only supports buffers up to MAX_PATH so we must

-  // limit ourselves to this.  It will "always" work anyway, given that

-  // our installation path is not absurdly deep.

-  if (0 == GetModuleFileName(module, directory, MAX_PATH)) {

-    ASSERT(false, (L"Path longer than MAX_PATH"));

-    return false;

-  }

-

-  if (!String_PathRemoveFileSpec(directory)) {

-    ASSERT(false, (L"PathRemoveFileSpec failed"));

-    // Ensure we don't return with an incorrect path in the buffer that was

-    // passed in.

-    ZeroMemory(directory, MAX_PATH * sizeof(TCHAR));

-    return false;

-  }

-

-  return true;

-}

-

-HRESULT GetModuleFileName(HMODULE module, CString* path) {

-  ASSERT(path, (_T("must be valid")));

-

-  // _MAX_PATH should cover at least 99% of the paths

-  int buf_size = _MAX_PATH;

-  int chars_copied = 0;

-  while ((chars_copied = ::GetModuleFileName(module,

-                                             CStrBuf(*path, buf_size + 1),

-                                             buf_size)) == buf_size) {

-    // We'll stop before things get ridiculous

-    if (buf_size >= kReallyLongPath) {

-      UTIL_LOG(LEVEL_ERROR,

-               (_T("[GetModuleFileName - unusually long path '%s']"), path));

-      chars_copied = 0;

-      ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);

-      break;

-    }

-

-    buf_size *= 2;

-  }

-

-  if (!chars_copied) {

-    path->Empty();

-    return GetCurError();

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/module_utils.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+const int kLongPath = (_MAX_PATH * 2);
+const int kReallyLongPath = (kLongPath * 2);
+
+HMODULE ModuleFromStatic(void* pointer_to_static_in_module) {
+  ASSERT(pointer_to_static_in_module, (L""));
+
+  MEMORY_BASIC_INFORMATION info = { 0 };
+  VirtualQuery(reinterpret_cast<void*>(pointer_to_static_in_module),
+    &info, sizeof(info));
+  // Module handles are just the allocation base address of the module.
+  return reinterpret_cast<HMODULE>(info.AllocationBase);
+}
+
+bool GetModuleDirectory(HMODULE module, TCHAR* directory) {
+  ASSERT(directory, (L"Invalid arguments"));
+  if (!directory) {
+    return false;
+  }
+
+  // PathRemoveFileSpec only supports buffers up to MAX_PATH so we must
+  // limit ourselves to this.  It will "always" work anyway, given that
+  // our installation path is not absurdly deep.
+  if (0 == GetModuleFileName(module, directory, MAX_PATH)) {
+    ASSERT(false, (L"Path longer than MAX_PATH"));
+    return false;
+  }
+
+  if (!String_PathRemoveFileSpec(directory)) {
+    ASSERT(false, (L"PathRemoveFileSpec failed"));
+    // Ensure we don't return with an incorrect path in the buffer that was
+    // passed in.
+    ZeroMemory(directory, MAX_PATH * sizeof(TCHAR));
+    return false;
+  }
+
+  return true;
+}
+
+HRESULT GetModuleFileName(HMODULE module, CString* path) {
+  ASSERT(path, (_T("must be valid")));
+
+  // _MAX_PATH should cover at least 99% of the paths
+  int buf_size = _MAX_PATH;
+  int chars_copied = 0;
+  while ((chars_copied = ::GetModuleFileName(module,
+                                             CStrBuf(*path, buf_size + 1),
+                                             buf_size)) == buf_size) {
+    // We'll stop before things get ridiculous
+    if (buf_size >= kReallyLongPath) {
+      UTIL_LOG(LEVEL_ERROR,
+               (_T("[GetModuleFileName - unusually long path '%s']"), path));
+      chars_copied = 0;
+      ::SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+      break;
+    }
+
+    buf_size *= 2;
+  }
+
+  if (!chars_copied) {
+    path->Empty();
+    return GetCurError();
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/common/module_utils.h b/common/module_utils.h
index d01ed06..9c4c61e 100644
--- a/common/module_utils.h
+++ b/common/module_utils.h
@@ -1,52 +1,52 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_MODULE_UTILS_H_

-#define OMAHA_COMMON_MODULE_UTILS_H_

-

-#include "omaha/common/string.h"

-

-namespace omaha {

-

-// Utilities for working with modules in processes.

-

-// Returns the module handle of a module, given a pointer to a static

-// member of the module (e.g. a static function or static variable).

-HMODULE ModuleFromStatic(void* pointer_to_static_in_module);

-

-// Copies the path of the directory that contains the file for 'module' into

-// 'directory'.

-//

-// @param module Must be a valid, non-NULL module handle.

-// @param directory MUST have room for MAX_PATH characters or more.  The path

-// copied into this buffer will not have a trailing backslash.

-//

-// @return false iff there is an error.

-bool GetModuleDirectory(HMODULE module, TCHAR* directory);

-

-/**

-* Returns a path to a module.  Uses the

-* Win32 GetModuleFileName function, so you

-* can pass NULL for module.

-*

-* @param module Handle to the module or NULL for the current module.

-* @param path Holds the path to the module on successful return.

-* @returns S_OK if successful, otherwise an error value.

-*/

-HRESULT GetModuleFileName(HMODULE module, OUT CString* path);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_MODULE_UTILS_H_

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_MODULE_UTILS_H_
+#define OMAHA_COMMON_MODULE_UTILS_H_
+
+#include "omaha/common/string.h"
+
+namespace omaha {
+
+// Utilities for working with modules in processes.
+
+// Returns the module handle of a module, given a pointer to a static
+// member of the module (e.g. a static function or static variable).
+HMODULE ModuleFromStatic(void* pointer_to_static_in_module);
+
+// Copies the path of the directory that contains the file for 'module' into
+// 'directory'.
+//
+// @param module Must be a valid, non-NULL module handle.
+// @param directory MUST have room for MAX_PATH characters or more.  The path
+// copied into this buffer will not have a trailing backslash.
+//
+// @return false iff there is an error.
+bool GetModuleDirectory(HMODULE module, TCHAR* directory);
+
+/**
+* Returns a path to a module.  Uses the
+* Win32 GetModuleFileName function, so you
+* can pass NULL for module.
+*
+* @param module Handle to the module or NULL for the current module.
+* @param path Holds the path to the module on successful return.
+* @returns S_OK if successful, otherwise an error value.
+*/
+HRESULT GetModuleFileName(HMODULE module, OUT CString* path);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_MODULE_UTILS_H_
diff --git a/common/module_utils_unittest.cc b/common/module_utils_unittest.cc
index ebf519a..fa409b3 100644
--- a/common/module_utils_unittest.cc
+++ b/common/module_utils_unittest.cc
@@ -1,53 +1,53 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Unit test for module utility functions.

-

-#include "omaha/common/constants.h"

-#include "omaha/common/module_utils.h"

-#include "omaha/common/path.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(ModuleUtilsTest, ModuleUtils) {

-  // ModuleFromStatic

-  HMODULE module = ModuleFromStatic(reinterpret_cast<void*>(ModuleFromStatic));

-  ASSERT_TRUE(module);

-

-  // GetModuleDirectory

-  TCHAR directory1[MAX_PATH] = {0};

-  TCHAR directory2[MAX_PATH] = {0};

-  ASSERT_TRUE(GetModuleDirectory(module, directory1));

-  ASSERT_TRUE(GetModuleDirectory(NULL, directory2));

-  EXPECT_STREQ(directory1, directory2);

-

-  // GetModuleFileName

-  CString path1;

-  CString path2;

-  ASSERT_SUCCEEDED(GetModuleFileName(module, &path1));

-  ASSERT_SUCCEEDED(GetModuleFileName(NULL, &path2));

-  EXPECT_STREQ(path1, path2);

-

-  // Verify values, as much as we can.

-  CString file(GetFileFromPath(path1));

-  EXPECT_STREQ(file, kUnittestName);

-

-  CString dir(GetDirectoryFromPath(path1));

-  EXPECT_STREQ(dir, directory1);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Unit test for module utility functions.
+
+#include "omaha/common/constants.h"
+#include "omaha/common/module_utils.h"
+#include "omaha/common/path.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(ModuleUtilsTest, ModuleUtils) {
+  // ModuleFromStatic
+  HMODULE module = ModuleFromStatic(reinterpret_cast<void*>(ModuleFromStatic));
+  ASSERT_TRUE(module);
+
+  // GetModuleDirectory
+  TCHAR directory1[MAX_PATH] = {0};
+  TCHAR directory2[MAX_PATH] = {0};
+  ASSERT_TRUE(GetModuleDirectory(module, directory1));
+  ASSERT_TRUE(GetModuleDirectory(NULL, directory2));
+  EXPECT_STREQ(directory1, directory2);
+
+  // GetModuleFileName
+  CString path1;
+  CString path2;
+  ASSERT_SUCCEEDED(GetModuleFileName(module, &path1));
+  ASSERT_SUCCEEDED(GetModuleFileName(NULL, &path2));
+  EXPECT_STREQ(path1, path2);
+
+  // Verify values, as much as we can.
+  CString file(GetFileFromPath(path1));
+  EXPECT_STREQ(file, kUnittestName);
+
+  CString dir(GetDirectoryFromPath(path1));
+  EXPECT_STREQ(dir, directory1);
+}
+
+}  // namespace omaha
diff --git a/common/object_factory.h b/common/object_factory.h
index e4ecd1b..18c04e4 100644
--- a/common/object_factory.h
+++ b/common/object_factory.h
@@ -1,67 +1,67 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_OBJECT_FACTORY_H__

-#define OMAHA_COMMON_OBJECT_FACTORY_H__

-

-#include <map>

-

-namespace omaha {

-

-// Factory creates instances of objects based on a unique type id.

-//

-// AbstractProduct - base class of the product hierarchy.

-// TypeId - type id for each type in the hierarchy.

-// ProductCreator - callable entity to create objects.

-

-template <class AbstractProduct,

-          typename TypeId,

-          typename ProductCreator = AbstractProduct* (*)()>

-class Factory {

- public:

-  Factory() {}

-

-  // Registers a creator for the type id. Returns true if the creator has

-  // been registered succesfully.

-  bool Register(const TypeId& id, ProductCreator creator) {

-    return id_to_creators_.insert(Map::value_type(id, creator)).second;

-  }

-

-  // Unregisters a type id.

-  bool Unregister(const TypeId& id) {

-    return id_to_creators_.erase(id) == 1;

-  }

-

-  // Creates an instance of the abstract product.

-  AbstractProduct* CreateObject(const TypeId& id) {

-    typename Map::const_iterator it = id_to_creators_.find(id);

-    if (it != id_to_creators_.end()) {

-      return (it->second)();

-    } else {

-      return NULL;

-    }

-  }

-

- private:

-  typedef std::map<TypeId, ProductCreator> Map;

-  Map id_to_creators_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Factory);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_OBJECT_FACTORY_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_OBJECT_FACTORY_H__
+#define OMAHA_COMMON_OBJECT_FACTORY_H__
+
+#include <map>
+
+namespace omaha {
+
+// Factory creates instances of objects based on a unique type id.
+//
+// AbstractProduct - base class of the product hierarchy.
+// TypeId - type id for each type in the hierarchy.
+// ProductCreator - callable entity to create objects.
+
+template <class AbstractProduct,
+          typename TypeId,
+          typename ProductCreator = AbstractProduct* (*)()>
+class Factory {
+ public:
+  Factory() {}
+
+  // Registers a creator for the type id. Returns true if the creator has
+  // been registered succesfully.
+  bool Register(const TypeId& id, ProductCreator creator) {
+    return id_to_creators_.insert(Map::value_type(id, creator)).second;
+  }
+
+  // Unregisters a type id.
+  bool Unregister(const TypeId& id) {
+    return id_to_creators_.erase(id) == 1;
+  }
+
+  // Creates an instance of the abstract product.
+  AbstractProduct* CreateObject(const TypeId& id) {
+    typename Map::const_iterator it = id_to_creators_.find(id);
+    if (it != id_to_creators_.end()) {
+      return (it->second)();
+    } else {
+      return NULL;
+    }
+  }
+
+ private:
+  typedef std::map<TypeId, ProductCreator> Map;
+  Map id_to_creators_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Factory);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_OBJECT_FACTORY_H__
+
diff --git a/common/object_factory_unittest.cc b/common/object_factory_unittest.cc
index 2690713..2e7bf11 100644
--- a/common/object_factory_unittest.cc
+++ b/common/object_factory_unittest.cc
@@ -1,19 +1,19 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/object_factory.h"

-#include "omaha/testing/unit_test.h"

-

-// TODO(omaha): write unit tests

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/object_factory.h"
+#include "omaha/testing/unit_test.h"
+
+// TODO(omaha): write unit tests
diff --git a/common/omaha_version.cc b/common/omaha_version.cc
index 0e84312..05b8611 100644
--- a/common/omaha_version.cc
+++ b/common/omaha_version.cc
@@ -1,63 +1,63 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/file_ver.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/utils.h"

-

-namespace {

-

-// The version string is not visible outside this module and it is only

-// accessible through the omaha::GetVersionString accessor.

-CString version_string;

-

-ULONGLONG omaha_version = 0;

-

-}  // namespace

-

-namespace omaha {

-

-// In both GetVersion* methods, we assert only that InitializeVersion* was

-// already called and not that they weren't called twice, which is OK.

-// There is no detection that the version_ variables aren't accessed before

-// being initialized because this would require accessor methods to enforce and

-// lead to bloat.

-

-const TCHAR* GetVersionString() {

-  ASSERT1(!version_string.IsEmpty());

-  return version_string;

-}

-

-ULONGLONG GetVersion() {

-  ASSERT1(!version_string.IsEmpty());

-  return omaha_version;

-}

-

-void InitializeVersionFromModule(HINSTANCE instance) {

-  ULONGLONG module_version = app_util::GetVersionFromModule(instance);

-

-  InitializeVersion(module_version);

-}

-

-void InitializeVersion(ULONGLONG version) {

-  omaha_version = version;

-

-  version_string = StringFromVersion(omaha_version);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/file_ver.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/utils.h"
+
+namespace {
+
+// The version string is not visible outside this module and it is only
+// accessible through the omaha::GetVersionString accessor.
+CString version_string;
+
+ULONGLONG omaha_version = 0;
+
+}  // namespace
+
+namespace omaha {
+
+// In both GetVersion* methods, we assert only that InitializeVersion* was
+// already called and not that they weren't called twice, which is OK.
+// There is no detection that the version_ variables aren't accessed before
+// being initialized because this would require accessor methods to enforce and
+// lead to bloat.
+
+const TCHAR* GetVersionString() {
+  ASSERT1(!version_string.IsEmpty());
+  return version_string;
+}
+
+ULONGLONG GetVersion() {
+  ASSERT1(!version_string.IsEmpty());
+  return omaha_version;
+}
+
+void InitializeVersionFromModule(HINSTANCE instance) {
+  ULONGLONG module_version = app_util::GetVersionFromModule(instance);
+
+  InitializeVersion(module_version);
+}
+
+void InitializeVersion(ULONGLONG version) {
+  omaha_version = version;
+
+  version_string = StringFromVersion(omaha_version);
+}
+
+}  // namespace omaha
diff --git a/common/omaha_version.h b/common/omaha_version.h
index e5098c0..76f9f06 100644
--- a/common/omaha_version.h
+++ b/common/omaha_version.h
@@ -1,43 +1,43 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_OMAHA_VERSION_H__

-#define OMAHA_COMMON_OMAHA_VERSION_H__

-

-#include <windows.h>

-#include <tchar.h>

-

-namespace omaha {

-

-// Overloading on pointer types and integral types is not possible in this

-// case and generally speaking not a good idea anyway. It leads to either

-// compile time ambiguities or surprising results at runtime, such as

-// which overload is being called if foobar(NULL).

-

-// Initializes the version variables from the version resource of the module.

-void InitializeVersionFromModule(HINSTANCE instance);

-

-// Initializes the version variables from a ULONGLONG version.

-void InitializeVersion(ULONGLONG version);

-

-// Returns the version string as "major.minor.build.patch".

-const TCHAR* GetVersionString();

-

-// Returns the version string as a ULONGLONG.

-ULONGLONG GetVersion();

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_OMAHA_VERSION_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_OMAHA_VERSION_H__
+#define OMAHA_COMMON_OMAHA_VERSION_H__
+
+#include <windows.h>
+#include <tchar.h>
+
+namespace omaha {
+
+// Overloading on pointer types and integral types is not possible in this
+// case and generally speaking not a good idea anyway. It leads to either
+// compile time ambiguities or surprising results at runtime, such as
+// which overload is being called if foobar(NULL).
+
+// Initializes the version variables from the version resource of the module.
+void InitializeVersionFromModule(HINSTANCE instance);
+
+// Initializes the version variables from a ULONGLONG version.
+void InitializeVersion(ULONGLONG version);
+
+// Returns the version string as "major.minor.build.patch".
+const TCHAR* GetVersionString();
+
+// Returns the version string as a ULONGLONG.
+ULONGLONG GetVersion();
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_OMAHA_VERSION_H__
diff --git a/common/omaha_version_unittest.cc b/common/omaha_version_unittest.cc
index eceb293..ec6e4ad 100644
--- a/common/omaha_version_unittest.cc
+++ b/common/omaha_version_unittest.cc
@@ -1,51 +1,51 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(OmahaVersionTest, InitializeVersion) {

-  CString version_string = GetVersionString();

-  ULONGLONG version = GetVersion();

-

-  EXPECT_STREQ(OMAHA_BUILD_VERSION_STRING, version_string);

-  EXPECT_EQ(OMAHA_BUILD_VERSION, version);

-

-  InitializeVersion(MAKEDLLVERULL(0, 0, 0, 0));

-  EXPECT_STREQ(_T("0.0.0.0"), GetVersionString());

-  EXPECT_EQ(0, GetVersion());

-

-  InitializeVersion(MAKEDLLVERULL(1, 2, 3, 4));

-  EXPECT_STREQ(_T("1.2.3.4"), GetVersionString());

-  EXPECT_EQ(0x0001000200030004, GetVersion());

-

-  InitializeVersion(MAKEDLLVERULL(0x7fff, 0x7fff, 0x7fff, 0x7fff));

-  EXPECT_STREQ(_T("32767.32767.32767.32767"), GetVersionString());

-  EXPECT_EQ(0x7fff7fff7fff7fff, GetVersion());

-

-  InitializeVersion(MAKEDLLVERULL(0xffff, 0xffff, 0xffff, 0xffff));

-  EXPECT_STREQ(_T("65535.65535.65535.65535"), GetVersionString());

-  EXPECT_EQ(0xffffffffffffffff, GetVersion());

-

-  // Sets back the initial version.

-  InitializeVersion(VersionFromString(version_string));

-  EXPECT_STREQ(version_string, GetVersionString());

-  EXPECT_EQ(version, GetVersion());

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(OmahaVersionTest, InitializeVersion) {
+  CString version_string = GetVersionString();
+  ULONGLONG version = GetVersion();
+
+  EXPECT_STREQ(OMAHA_BUILD_VERSION_STRING, version_string);
+  EXPECT_EQ(OMAHA_BUILD_VERSION, version);
+
+  InitializeVersion(MAKEDLLVERULL(0, 0, 0, 0));
+  EXPECT_STREQ(_T("0.0.0.0"), GetVersionString());
+  EXPECT_EQ(0, GetVersion());
+
+  InitializeVersion(MAKEDLLVERULL(1, 2, 3, 4));
+  EXPECT_STREQ(_T("1.2.3.4"), GetVersionString());
+  EXPECT_EQ(0x0001000200030004, GetVersion());
+
+  InitializeVersion(MAKEDLLVERULL(0x7fff, 0x7fff, 0x7fff, 0x7fff));
+  EXPECT_STREQ(_T("32767.32767.32767.32767"), GetVersionString());
+  EXPECT_EQ(0x7fff7fff7fff7fff, GetVersion());
+
+  InitializeVersion(MAKEDLLVERULL(0xffff, 0xffff, 0xffff, 0xffff));
+  EXPECT_STREQ(_T("65535.65535.65535.65535"), GetVersionString());
+  EXPECT_EQ(0xffffffffffffffff, GetVersion());
+
+  // Sets back the initial version.
+  InitializeVersion(VersionFromString(version_string));
+  EXPECT_STREQ(version_string, GetVersionString());
+  EXPECT_EQ(version, GetVersion());
+}
+
+}  // namespace omaha
diff --git a/common/path.cc b/common/path.cc
index f4df5a8..92cf7a6 100644
--- a/common/path.cc
+++ b/common/path.cc
@@ -1,448 +1,448 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Path utility functions.

-

-#include "omaha/common/path.h"

-

-#include <atlbase.h>

-#include <atlstr.h>

-#include <atlpath.h>

-#include <map>

-#include <vector>

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/shell.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-const TCHAR* const kRegSvr32Cmd1 = _T("regsvr32 ");

-const TCHAR* const kRegSvr32Cmd2 = _T("regsvr32.exe ");

-const TCHAR* const kRunDll32Cmd1 = _T("rundll32 ");

-const TCHAR* const kRunDll32Cmd2 = _T("rundll32.exe ");

-const TCHAR* const kMsiExecCmd1  = _T("msiexec ");

-const TCHAR* const kMsiExecCmd2  = _T("msiexec.exe ");

-const TCHAR* const kDotExe       = _T(".exe");

-

-

-namespace detail {

-

-typedef bool (*Filter)(const WIN32_FIND_DATA&);

-

-bool IsFile(const WIN32_FIND_DATA& find_data) {

-  return (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;

-}

-

-bool IsDirectory(const WIN32_FIND_DATA& find_data) {

-  return (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;

-}

-

-bool AllFiles(const WIN32_FIND_DATA&) {

-  return true;

-}

-

-HRESULT FindFilesEx(const CString& dir,

-                    const CString& pattern,

-                    std::vector<CString>* files,

-                    Filter func) {

-  ASSERT1(files);

-

-  files->clear();

-  if (!File::Exists(dir)) {

-    return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);

-  }

-

-  CString files_to_find = ConcatenatePath(dir, pattern);

-  WIN32_FIND_DATA find_data = {0};

-  scoped_hfind hfind(::FindFirstFile(files_to_find, &find_data));

-  if (!hfind) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(L5, (_T("[File::GetWildcards - FindFirstFile failed][0x%x]"), hr));

-    return hr;

-  }

-

-  do {

-    if (func(find_data)) {

-      files->push_back(find_data.cFileName);

-    }

-  } while (::FindNextFile(get(hfind), &find_data));

-

-  return S_OK;

-}

-

-}  // namespace detail.

-

-// Get the starting path from the command string

-CString GetStartingPathFromString(const CString& s) {

-  CString path;

-  CString str(s);

-  TrimCString(str);

-

-  int len = str.GetLength();

-  if (len > 0) {

-    if (str[0] == _T('"')) {

-      // For something like:  "c:\Program Files\...\" ...

-      int idx = String_FindChar(str.GetString() + 1, _T('"'));

-      if (idx != -1)

-        path.SetString(str.GetString() + 1, idx);

-    } else {

-      // For something like:  c:\PRGRA~1\... ...

-      int idx = String_FindChar(str, _T(' '));

-      path.SetString(str, idx == -1 ? len : idx);

-    }

-  }

-

-  return path;

-}

-

-// Get the trailing path from the command string

-CString GetTrailingPathFromString(const CString& s) {

-  CString path;

-  CString str(s);

-  TrimCString(str);

-

-  int len = str.GetLength();

-  if (len > 0) {

-    if (str[len - 1] == _T('"')) {

-      // For something like:  regsvr32 /u /s "c:\Program Files\..."

-      str.Truncate(len - 1);

-      int idx = String_ReverseFindChar(str, _T('"'));

-      if (idx != -1)

-        path.SetString(str.GetString() + idx + 1, len - idx - 1);

-    } else {

-      // For something like:  regsvr32 /u /s c:\PRGRA~1\...

-      int idx = String_ReverseFindChar(str, _T(' '));

-      if (idx != -1)

-        path.SetString(str.GetString() + idx + 1, len - idx - 1);

-    }

-  }

-

-  return path;

-}

-

-// Get the file from the command string

-HRESULT GetFileFromCommandString(const TCHAR* s, CString* file) {

-  ASSERT1(file);

-

-  if (!s || !*s) {

-    return E_INVALIDARG;

-  }

-

-  CString str(s);

-  TrimCString(str);

-

-  // Handle the string starting with quotation mark

-  // For example: "C:\Program Files\WinZip\WINZIP32.EXE" /uninstall

-  if (str[0] == _T('"')) {

-    int idx_quote = str.Find(_T('"'), 1);

-    if (idx_quote != -1) {

-      file->SetString(str.GetString() + 1, idx_quote - 1);

-      return S_OK;

-    } else {

-      return E_FAIL;

-    }

-  }

-

-  // Handle the string starting with "regsvr32"

-  // For example: regsvr32 /u /s "c:\program files\google\googletoolbar3.dll"

-  if (String_StartsWith(str, kRegSvr32Cmd1, true) ||

-      String_StartsWith(str, kRegSvr32Cmd2, true)) {

-    file->SetString(GetTrailingPathFromString(str));

-    return S_OK;

-  }

-

-  // Handle the string starting with "rundll32"

-  // For example: "rundll32.exe setupapi.dll,InstallHinfSection DefaultUninstall 132 C:\WINDOWS\INF\PCHealth.inf"  // NOLINT

-  if (String_StartsWith(str, kRunDll32Cmd1, true) ||

-      String_StartsWith(str, kRunDll32Cmd2, true)) {

-    int idx_space = str.Find(_T(' '));

-    ASSERT1(idx_space != -1);

-    int idx_comma = str.Find(_T(','), idx_space + 1);

-    if (idx_comma != -1) {

-      file->SetString(str.GetString() + idx_space + 1,

-                      idx_comma - idx_space - 1);

-      TrimCString(*file);

-      return S_OK;

-    } else {

-      return E_FAIL;

-    }

-  }

-

-  // Handle the string starting with "msiexec"

-  // For example: MsiExec.exe /I{25A13826-8E4A-4FBF-AD2B-776447FE9646}

-  if (String_StartsWith(str, kMsiExecCmd1, true) ||

-      String_StartsWith(str, kMsiExecCmd2, true)) {

-    return E_FAIL;

-  }

-

-  // Otherwise, try to find the file till reaching ".exe"

-  // For example: "C:\Program Files\Google\Google Desktop Search\GoogleDesktopSetup.exe -uninstall"  // NOLINT

-  for (int i = 0; i < str.GetLength(); ++i) {

-    if (String_StartsWith(str.GetString() + i, kDotExe, true)) {

-      file->SetString(str, i + _tcslen(kDotExe));

-      return S_OK;

-    }

-  }

-

-  // As last resort, return the part from the beginning to first space found.

-  int idx = str.Find(_T(' '));

-  if (idx == -1) {

-    file->SetString(str);

-  } else {

-    file->SetString(str, idx);

-  }

-

-  return S_OK;

-}

-

-// Expands the string with embedded special folder variables.

-// TODO(omaha): This function seems to have a very specific purpose, which

-// is not used in our code base. Consider removing it.

-HRESULT ExpandStringWithSpecialFolders(CString* str) {

-  ASSERT(str, (L""));

-

-#pragma warning(push)

-// construction of local static object is not thread-safe

-#pragma warning(disable : 4640)

-  static std::map<CString, CString> g_special_folders_mapping;

-#pragma warning(pop)

-

-  if (g_special_folders_mapping.size() == 0) {

-    RET_IF_FAILED(

-        Shell::GetSpecialFolderKeywordsMapping(&g_special_folders_mapping));

-  }

-

-  CString expanded_str;

-  RET_IF_FAILED(

-      ExpandEnvLikeStrings(*str, g_special_folders_mapping, &expanded_str));

-

-  str->SetString(expanded_str);

-

-  return S_OK;

-}

-

-// Internal helper method for normalizing a path

-HRESULT NormalizePathInternal(const TCHAR* path, CString* normalized_path) {

-  // We use '|' to separate fields

-  CString field;

-  int bar_idx = String_FindChar(path, _T('|'));

-  if (bar_idx == -1)

-    field = path;

-  else

-    field.SetString(path, bar_idx);

-

-  if (IsRegistryPath(field)) {

-    CString key_name, value_name;

-    RET_IF_FAILED(RegSplitKeyvalueName(field, &key_name, &value_name));

-

-    CString reg_value;

-    RET_IF_FAILED(RegKey::GetValue(key_name, value_name, &reg_value));

-    normalized_path->Append(reg_value);

-  } else {

-    RET_IF_FAILED(ExpandStringWithSpecialFolders(&field));

-    normalized_path->Append(field);

-  }

-

-  if (bar_idx != -1)

-    return NormalizePathInternal(path + bar_idx + 1, normalized_path);

-  else

-    return S_OK;

-}

-

-// Normalize a path

-HRESULT NormalizePath(const TCHAR* path, CString* normalized_path) {

-  ASSERT1(normalized_path);

-

-  normalized_path->Empty();

-

-  if (path) {

-    HRESULT hr = NormalizePathInternal(path, normalized_path);

-    if (FAILED(hr)) {

-      normalized_path->Empty();

-      UTIL_LOG(LE, (_T("[NormalizePath - unable to normalize path][%s][0x%x]"),

-                    path, hr));

-    }

-    return hr;

-  } else {

-    return S_OK;

-  }

-}

-

-CString ConcatenatePath(const CString& path1, const CString& path2) {

-  CString ret(path1);

-

-  // Append the file path using the PathAppend.

-  VERIFY1(::PathAppend(CStrBuf(ret, MAX_PATH), path2));

-

-  return ret;

-}

-

-// Get the filename from the path

-// "C:\TEST\sample.txt" returns "sample.txt"

-CString GetFileFromPath(const CString& path) {

-  CPath path1(path);

-  path1.StripPath();

-  return static_cast<CString>(path1);

-}

-

-// Get the directory from the path

-// "C:\TEST\sample.txt" returns "C:\TEST"

-// Get the directory out of the file path

-CString GetDirectoryFromPath(const CString& path) {

-  CPath path1(path);

-  path1.RemoveFileSpec();

-  return static_cast<CString>(path1);

-}

-

-// Remove the extension from the path.

-// "C:\TEST\sample.txt" returns "C:\TEST\sample"

-CString GetPathRemoveExtension(const CString& path) {

-  CPath path1(path);

-  path1.RemoveExtension();

-  return static_cast<CString>(path1);

-}

-

-// Basically, an absolute path starts with X:\ or \\ (a UNC name)

-bool IsAbsolutePath(const TCHAR* path) {

-  ASSERT1(path);

-

-  int len = ::_tcslen(path);

-  if (len < 3)

-    return false;

-  if (*path == _T('"'))

-    path++;

-  if (String_StartsWith(path+1, _T(":\\"), false))

-    return true;

-  if (String_StartsWith(path, _T("\\\\"), false))

-    return true;

-  return false;

-}

-

-void EnclosePath(CString* path) {

-  ASSERT1(path);

-

-  if (path->IsEmpty()) {

-    return;

-  }

-

-  bool starts_with_quote = (_T('"') == path->GetAt(0));

-  bool ends_with_quote = (_T('"') == path->GetAt(path->GetLength() - 1));

-  ASSERT(starts_with_quote == ends_with_quote, (_T("%s"), path->GetString()));

-  bool is_enclosed = starts_with_quote && ends_with_quote;

-  if (is_enclosed) {

-    return;

-  }

-

-  path->Insert(0, _T('"'));

-  path->AppendChar(_T('"'));

-}

-

-CString EnclosePathIfExe(const CString& module_path) {

-  if (!String_EndsWith(module_path, _T(".exe"), true)) {

-    return module_path;

-  }

-

-  CString enclosed_path(module_path);

-  EnclosePath(&enclosed_path);

-  return enclosed_path;

-}

-

-// remove any double quotation masks from an enclosed path

-void UnenclosePath(CString* path) {

-  ASSERT1(path);

-

-  if (path->GetLength() > 1 && path->GetAt(0) == _T('"')) {

-    bool right_quote_exists = (path->GetAt(path->GetLength() - 1) == _T('"'));

-    ASSERT(right_quote_exists,

-           (_T("[UnenclosePath - double quote mismatches]")));

-    if (right_quote_exists) {

-      // Remove the double quotation masks

-      path->Delete(0);

-      path->Truncate(path->GetLength() - 1);

-    }

-  }

-}

-

-HRESULT ShortPathToLongPath(const CString& short_path, CString* long_path) {

-  ASSERT1(long_path);

-

-  TCHAR long_name[MAX_PATH] = {0};

-  if (!::GetLongPathName(short_path, long_name, MAX_PATH)) {

-    return HRESULTFromLastError();

-  }

-

-  *long_path = long_name;

-  return S_OK;

-}

-

-HRESULT FindFilesEx(const CString& dir,

-                    const CString& pattern,

-                    std::vector<CString>* files) {

-  return detail::FindFilesEx(dir, pattern, files, &detail::IsFile);

-}

-

-HRESULT FindFiles(const CString& dir,

-                  const CString& pattern,

-                  std::vector<CString>* files) {

-  return detail::FindFilesEx(dir, pattern, files, &detail::AllFiles);

-}

-

-HRESULT FindSubDirectories(const CString& dir,

-                           const CString& pattern,

-                           std::vector<CString>* files) {

-  return detail::FindFilesEx(dir, pattern, files, &detail::IsDirectory);

-}

-

-HRESULT FindFileRecursive(const CString& dir,

-                          const CString& pattern,

-                          std::vector<CString>* files) {

-  ASSERT1(files);

-

-  std::vector<CString> temp_files;

-  HRESULT hr = FindFilesEx(dir, pattern, &temp_files);

-  if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) && FAILED(hr)) {

-    return hr;

-  }

-

-  for (size_t i = 0; i < temp_files.size(); ++i) {

-    files->push_back(ConcatenatePath(dir, temp_files[i]));

-  }

-

-  std::vector<CString> sub_dirs;

-  hr = FindSubDirectories(dir, _T("*"), &sub_dirs);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  for (size_t i = 0; i < sub_dirs.size(); ++i) {

-    const CString& sub_dir = sub_dirs[i];

-    if (sub_dir == _T(".") || sub_dir == _T("..")) {

-      continue;

-    }

-

-    CString path = ConcatenatePath(dir, sub_dir);

-    hr = FindFileRecursive(path, pattern, files);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Path utility functions.
+
+#include "omaha/common/path.h"
+
+#include <atlbase.h>
+#include <atlstr.h>
+#include <atlpath.h>
+#include <map>
+#include <vector>
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/shell.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+const TCHAR* const kRegSvr32Cmd1 = _T("regsvr32 ");
+const TCHAR* const kRegSvr32Cmd2 = _T("regsvr32.exe ");
+const TCHAR* const kRunDll32Cmd1 = _T("rundll32 ");
+const TCHAR* const kRunDll32Cmd2 = _T("rundll32.exe ");
+const TCHAR* const kMsiExecCmd1  = _T("msiexec ");
+const TCHAR* const kMsiExecCmd2  = _T("msiexec.exe ");
+const TCHAR* const kDotExe       = _T(".exe");
+
+
+namespace detail {
+
+typedef bool (*Filter)(const WIN32_FIND_DATA&);
+
+bool IsFile(const WIN32_FIND_DATA& find_data) {
+  return (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
+}
+
+bool IsDirectory(const WIN32_FIND_DATA& find_data) {
+  return (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+bool AllFiles(const WIN32_FIND_DATA&) {
+  return true;
+}
+
+HRESULT FindFilesEx(const CString& dir,
+                    const CString& pattern,
+                    std::vector<CString>* files,
+                    Filter func) {
+  ASSERT1(files);
+
+  files->clear();
+  if (!File::Exists(dir)) {
+    return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+  }
+
+  CString files_to_find = ConcatenatePath(dir, pattern);
+  WIN32_FIND_DATA find_data = {0};
+  scoped_hfind hfind(::FindFirstFile(files_to_find, &find_data));
+  if (!hfind) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(L5, (_T("[File::GetWildcards - FindFirstFile failed][0x%x]"), hr));
+    return hr;
+  }
+
+  do {
+    if (func(find_data)) {
+      files->push_back(find_data.cFileName);
+    }
+  } while (::FindNextFile(get(hfind), &find_data));
+
+  return S_OK;
+}
+
+}  // namespace detail.
+
+// Get the starting path from the command string
+CString GetStartingPathFromString(const CString& s) {
+  CString path;
+  CString str(s);
+  TrimCString(str);
+
+  int len = str.GetLength();
+  if (len > 0) {
+    if (str[0] == _T('"')) {
+      // For something like:  "c:\Program Files\...\" ...
+      int idx = String_FindChar(str.GetString() + 1, _T('"'));
+      if (idx != -1)
+        path.SetString(str.GetString() + 1, idx);
+    } else {
+      // For something like:  c:\PRGRA~1\... ...
+      int idx = String_FindChar(str, _T(' '));
+      path.SetString(str, idx == -1 ? len : idx);
+    }
+  }
+
+  return path;
+}
+
+// Get the trailing path from the command string
+CString GetTrailingPathFromString(const CString& s) {
+  CString path;
+  CString str(s);
+  TrimCString(str);
+
+  int len = str.GetLength();
+  if (len > 0) {
+    if (str[len - 1] == _T('"')) {
+      // For something like:  regsvr32 /u /s "c:\Program Files\..."
+      str.Truncate(len - 1);
+      int idx = String_ReverseFindChar(str, _T('"'));
+      if (idx != -1)
+        path.SetString(str.GetString() + idx + 1, len - idx - 1);
+    } else {
+      // For something like:  regsvr32 /u /s c:\PRGRA~1\...
+      int idx = String_ReverseFindChar(str, _T(' '));
+      if (idx != -1)
+        path.SetString(str.GetString() + idx + 1, len - idx - 1);
+    }
+  }
+
+  return path;
+}
+
+// Get the file from the command string
+HRESULT GetFileFromCommandString(const TCHAR* s, CString* file) {
+  ASSERT1(file);
+
+  if (!s || !*s) {
+    return E_INVALIDARG;
+  }
+
+  CString str(s);
+  TrimCString(str);
+
+  // Handle the string starting with quotation mark
+  // For example: "C:\Program Files\WinZip\WINZIP32.EXE" /uninstall
+  if (str[0] == _T('"')) {
+    int idx_quote = str.Find(_T('"'), 1);
+    if (idx_quote != -1) {
+      file->SetString(str.GetString() + 1, idx_quote - 1);
+      return S_OK;
+    } else {
+      return E_FAIL;
+    }
+  }
+
+  // Handle the string starting with "regsvr32"
+  // For example: regsvr32 /u /s "c:\program files\google\googletoolbar3.dll"
+  if (String_StartsWith(str, kRegSvr32Cmd1, true) ||
+      String_StartsWith(str, kRegSvr32Cmd2, true)) {
+    file->SetString(GetTrailingPathFromString(str));
+    return S_OK;
+  }
+
+  // Handle the string starting with "rundll32"
+  // For example: "rundll32.exe setupapi.dll,InstallHinfSection DefaultUninstall 132 C:\WINDOWS\INF\PCHealth.inf"  // NOLINT
+  if (String_StartsWith(str, kRunDll32Cmd1, true) ||
+      String_StartsWith(str, kRunDll32Cmd2, true)) {
+    int idx_space = str.Find(_T(' '));
+    ASSERT1(idx_space != -1);
+    int idx_comma = str.Find(_T(','), idx_space + 1);
+    if (idx_comma != -1) {
+      file->SetString(str.GetString() + idx_space + 1,
+                      idx_comma - idx_space - 1);
+      TrimCString(*file);
+      return S_OK;
+    } else {
+      return E_FAIL;
+    }
+  }
+
+  // Handle the string starting with "msiexec"
+  // For example: MsiExec.exe /I{25A13826-8E4A-4FBF-AD2B-776447FE9646}
+  if (String_StartsWith(str, kMsiExecCmd1, true) ||
+      String_StartsWith(str, kMsiExecCmd2, true)) {
+    return E_FAIL;
+  }
+
+  // Otherwise, try to find the file till reaching ".exe"
+  // For example: "C:\Program Files\Google\Google Desktop Search\GoogleDesktopSetup.exe -uninstall"  // NOLINT
+  for (int i = 0; i < str.GetLength(); ++i) {
+    if (String_StartsWith(str.GetString() + i, kDotExe, true)) {
+      file->SetString(str, i + _tcslen(kDotExe));
+      return S_OK;
+    }
+  }
+
+  // As last resort, return the part from the beginning to first space found.
+  int idx = str.Find(_T(' '));
+  if (idx == -1) {
+    file->SetString(str);
+  } else {
+    file->SetString(str, idx);
+  }
+
+  return S_OK;
+}
+
+// Expands the string with embedded special folder variables.
+// TODO(omaha): This function seems to have a very specific purpose, which
+// is not used in our code base. Consider removing it.
+HRESULT ExpandStringWithSpecialFolders(CString* str) {
+  ASSERT(str, (L""));
+
+#pragma warning(push)
+// construction of local static object is not thread-safe
+#pragma warning(disable : 4640)
+  static std::map<CString, CString> g_special_folders_mapping;
+#pragma warning(pop)
+
+  if (g_special_folders_mapping.size() == 0) {
+    RET_IF_FAILED(
+        Shell::GetSpecialFolderKeywordsMapping(&g_special_folders_mapping));
+  }
+
+  CString expanded_str;
+  RET_IF_FAILED(
+      ExpandEnvLikeStrings(*str, g_special_folders_mapping, &expanded_str));
+
+  str->SetString(expanded_str);
+
+  return S_OK;
+}
+
+// Internal helper method for normalizing a path
+HRESULT NormalizePathInternal(const TCHAR* path, CString* normalized_path) {
+  // We use '|' to separate fields
+  CString field;
+  int bar_idx = String_FindChar(path, _T('|'));
+  if (bar_idx == -1)
+    field = path;
+  else
+    field.SetString(path, bar_idx);
+
+  if (IsRegistryPath(field)) {
+    CString key_name, value_name;
+    RET_IF_FAILED(RegSplitKeyvalueName(field, &key_name, &value_name));
+
+    CString reg_value;
+    RET_IF_FAILED(RegKey::GetValue(key_name, value_name, &reg_value));
+    normalized_path->Append(reg_value);
+  } else {
+    RET_IF_FAILED(ExpandStringWithSpecialFolders(&field));
+    normalized_path->Append(field);
+  }
+
+  if (bar_idx != -1)
+    return NormalizePathInternal(path + bar_idx + 1, normalized_path);
+  else
+    return S_OK;
+}
+
+// Normalize a path
+HRESULT NormalizePath(const TCHAR* path, CString* normalized_path) {
+  ASSERT1(normalized_path);
+
+  normalized_path->Empty();
+
+  if (path) {
+    HRESULT hr = NormalizePathInternal(path, normalized_path);
+    if (FAILED(hr)) {
+      normalized_path->Empty();
+      UTIL_LOG(LE, (_T("[NormalizePath - unable to normalize path][%s][0x%x]"),
+                    path, hr));
+    }
+    return hr;
+  } else {
+    return S_OK;
+  }
+}
+
+CString ConcatenatePath(const CString& path1, const CString& path2) {
+  CString ret(path1);
+
+  // Append the file path using the PathAppend.
+  VERIFY1(::PathAppend(CStrBuf(ret, MAX_PATH), path2));
+
+  return ret;
+}
+
+// Get the filename from the path
+// "C:\TEST\sample.txt" returns "sample.txt"
+CString GetFileFromPath(const CString& path) {
+  CPath path1(path);
+  path1.StripPath();
+  return static_cast<CString>(path1);
+}
+
+// Get the directory from the path
+// "C:\TEST\sample.txt" returns "C:\TEST"
+// Get the directory out of the file path
+CString GetDirectoryFromPath(const CString& path) {
+  CPath path1(path);
+  path1.RemoveFileSpec();
+  return static_cast<CString>(path1);
+}
+
+// Remove the extension from the path.
+// "C:\TEST\sample.txt" returns "C:\TEST\sample"
+CString GetPathRemoveExtension(const CString& path) {
+  CPath path1(path);
+  path1.RemoveExtension();
+  return static_cast<CString>(path1);
+}
+
+// Basically, an absolute path starts with X:\ or \\ (a UNC name)
+bool IsAbsolutePath(const TCHAR* path) {
+  ASSERT1(path);
+
+  int len = ::_tcslen(path);
+  if (len < 3)
+    return false;
+  if (*path == _T('"'))
+    path++;
+  if (String_StartsWith(path+1, _T(":\\"), false))
+    return true;
+  if (String_StartsWith(path, _T("\\\\"), false))
+    return true;
+  return false;
+}
+
+void EnclosePath(CString* path) {
+  ASSERT1(path);
+
+  if (path->IsEmpty()) {
+    return;
+  }
+
+  bool starts_with_quote = (_T('"') == path->GetAt(0));
+  bool ends_with_quote = (_T('"') == path->GetAt(path->GetLength() - 1));
+  ASSERT(starts_with_quote == ends_with_quote, (_T("%s"), path->GetString()));
+  bool is_enclosed = starts_with_quote && ends_with_quote;
+  if (is_enclosed) {
+    return;
+  }
+
+  path->Insert(0, _T('"'));
+  path->AppendChar(_T('"'));
+}
+
+CString EnclosePathIfExe(const CString& module_path) {
+  if (!String_EndsWith(module_path, _T(".exe"), true)) {
+    return module_path;
+  }
+
+  CString enclosed_path(module_path);
+  EnclosePath(&enclosed_path);
+  return enclosed_path;
+}
+
+// remove any double quotation masks from an enclosed path
+void UnenclosePath(CString* path) {
+  ASSERT1(path);
+
+  if (path->GetLength() > 1 && path->GetAt(0) == _T('"')) {
+    bool right_quote_exists = (path->GetAt(path->GetLength() - 1) == _T('"'));
+    ASSERT(right_quote_exists,
+           (_T("[UnenclosePath - double quote mismatches]")));
+    if (right_quote_exists) {
+      // Remove the double quotation masks
+      path->Delete(0);
+      path->Truncate(path->GetLength() - 1);
+    }
+  }
+}
+
+HRESULT ShortPathToLongPath(const CString& short_path, CString* long_path) {
+  ASSERT1(long_path);
+
+  TCHAR long_name[MAX_PATH] = {0};
+  if (!::GetLongPathName(short_path, long_name, MAX_PATH)) {
+    return HRESULTFromLastError();
+  }
+
+  *long_path = long_name;
+  return S_OK;
+}
+
+HRESULT FindFilesEx(const CString& dir,
+                    const CString& pattern,
+                    std::vector<CString>* files) {
+  return detail::FindFilesEx(dir, pattern, files, &detail::IsFile);
+}
+
+HRESULT FindFiles(const CString& dir,
+                  const CString& pattern,
+                  std::vector<CString>* files) {
+  return detail::FindFilesEx(dir, pattern, files, &detail::AllFiles);
+}
+
+HRESULT FindSubDirectories(const CString& dir,
+                           const CString& pattern,
+                           std::vector<CString>* files) {
+  return detail::FindFilesEx(dir, pattern, files, &detail::IsDirectory);
+}
+
+HRESULT FindFileRecursive(const CString& dir,
+                          const CString& pattern,
+                          std::vector<CString>* files) {
+  ASSERT1(files);
+
+  std::vector<CString> temp_files;
+  HRESULT hr = FindFilesEx(dir, pattern, &temp_files);
+  if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) && FAILED(hr)) {
+    return hr;
+  }
+
+  for (size_t i = 0; i < temp_files.size(); ++i) {
+    files->push_back(ConcatenatePath(dir, temp_files[i]));
+  }
+
+  std::vector<CString> sub_dirs;
+  hr = FindSubDirectories(dir, _T("*"), &sub_dirs);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  for (size_t i = 0; i < sub_dirs.size(); ++i) {
+    const CString& sub_dir = sub_dirs[i];
+    if (sub_dir == _T(".") || sub_dir == _T("..")) {
+      continue;
+    }
+
+    CString path = ConcatenatePath(dir, sub_dir);
+    hr = FindFileRecursive(path, pattern, files);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/common/path.h b/common/path.h
index a5bb771..f3f288b 100644
--- a/common/path.h
+++ b/common/path.h
@@ -1,87 +1,87 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Path utility functions.

-

-#ifndef OMAHA_COMMON_PATH_H__

-#define OMAHA_COMMON_PATH_H__

-

-#include <atlstr.h>

-#include <vector>

-

-namespace omaha {

-

-// Get the starting path from the command string

-CString GetStartingPathFromString(const CString& s);

-

-// Get the trailing path from the command string

-CString GetTrailingPathFromString(const CString& s);

-

-// Get the file from the command string

-HRESULT GetFileFromCommandString(const TCHAR* s, CString* file);

-

-// Expands the string with embedded special folder variables

-HRESULT ExpandStringWithSpecialFolders(CString* str);

-

-// Normalize a path

-HRESULT NormalizePath(const TCHAR* path, CString* normalized_path);

-

-// Concatenate two paths together

-CString ConcatenatePath(const CString& path1, const CString& path2);

-

-// Get the file out of the file path

-CString GetFileFromPath(const CString& path);

-

-// Get the directory from the path

-CString GetDirectoryFromPath(const CString& path);

-

-// Remove the extension from the path.

-CString GetPathRemoveExtension(const CString& path);

-

-// Returns true iff path is an absolute path (starts with a drive name)

-bool IsAbsolutePath(const TCHAR* path);

-

-// Makes sure the path is enclosed with double quotation marks.

-void EnclosePath(CString* path);

-

-// Used to enclose paths that are typically used with LocalServer32 entries.

-// Unenclosed LocalServer32 entries with spaces are not recommended because

-// the LocalServer32 entry is a command line, not just an EXE path.

-// DLL paths should not be enclosed, because InProcServer32 entries are just

-// a DLL path and not a command line.

-CString EnclosePathIfExe(const CString& module_path);

-

-// remove any double quotation masks from an enclosed path

-void UnenclosePath(CString* path);

-

-// Converts the short path name to long name.

-HRESULT ShortPathToLongPath(const CString& short_path, CString* long_path);

-

-// Returns a list of files that match the criteria.

-HRESULT FindFiles(const CString& dir,

-                  const CString& pattern,

-                  std::vector<CString>* files);

-

-HRESULT FindFilesEx(const CString& dir,

-                    const CString& pattern,

-                    std::vector<CString>* files);

-

-HRESULT FindFileRecursive(const CString& dir,

-                          const CString& pattern,

-                          std::vector<CString>* files);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_PATH_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Path utility functions.
+
+#ifndef OMAHA_COMMON_PATH_H__
+#define OMAHA_COMMON_PATH_H__
+
+#include <atlstr.h>
+#include <vector>
+
+namespace omaha {
+
+// Get the starting path from the command string
+CString GetStartingPathFromString(const CString& s);
+
+// Get the trailing path from the command string
+CString GetTrailingPathFromString(const CString& s);
+
+// Get the file from the command string
+HRESULT GetFileFromCommandString(const TCHAR* s, CString* file);
+
+// Expands the string with embedded special folder variables
+HRESULT ExpandStringWithSpecialFolders(CString* str);
+
+// Normalize a path
+HRESULT NormalizePath(const TCHAR* path, CString* normalized_path);
+
+// Concatenate two paths together
+CString ConcatenatePath(const CString& path1, const CString& path2);
+
+// Get the file out of the file path
+CString GetFileFromPath(const CString& path);
+
+// Get the directory from the path
+CString GetDirectoryFromPath(const CString& path);
+
+// Remove the extension from the path.
+CString GetPathRemoveExtension(const CString& path);
+
+// Returns true iff path is an absolute path (starts with a drive name)
+bool IsAbsolutePath(const TCHAR* path);
+
+// Makes sure the path is enclosed with double quotation marks.
+void EnclosePath(CString* path);
+
+// Used to enclose paths that are typically used with LocalServer32 entries.
+// Unenclosed LocalServer32 entries with spaces are not recommended because
+// the LocalServer32 entry is a command line, not just an EXE path.
+// DLL paths should not be enclosed, because InProcServer32 entries are just
+// a DLL path and not a command line.
+CString EnclosePathIfExe(const CString& module_path);
+
+// remove any double quotation masks from an enclosed path
+void UnenclosePath(CString* path);
+
+// Converts the short path name to long name.
+HRESULT ShortPathToLongPath(const CString& short_path, CString* long_path);
+
+// Returns a list of files that match the criteria.
+HRESULT FindFiles(const CString& dir,
+                  const CString& pattern,
+                  std::vector<CString>* files);
+
+HRESULT FindFilesEx(const CString& dir,
+                    const CString& pattern,
+                    std::vector<CString>* files);
+
+HRESULT FindFileRecursive(const CString& dir,
+                          const CString& pattern,
+                          std::vector<CString>* files);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_PATH_H__
diff --git a/common/path_unittest.cc b/common/path_unittest.cc
index 61268c3..4769baa 100644
--- a/common/path_unittest.cc
+++ b/common/path_unittest.cc
@@ -1,413 +1,413 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Path-utility unit tests.

-

-#include <vector>

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(PathTest, IsAbsolutePath) {

-  ASSERT_TRUE(IsAbsolutePath(L"C:\\Foo.bar"));

-  ASSERT_TRUE(IsAbsolutePath(L"\\\\user-laptop1\\path"));

-  ASSERT_FALSE(IsAbsolutePath(L"windows\\system32"));

-}

-

-// EnclosePath is overzealous and quotes a path even though no spaces exists.

-TEST(PathTest, EnclosePath) {

-  CString path;

-  EnclosePath(&path);

-  EXPECT_STREQ(_T(""), path);

-

-  path = _T("");

-  EnclosePath(&path);

-  EXPECT_STREQ(_T(""), path);

-

-  path = _T("a");

-  EnclosePath(&path);

-  EXPECT_STREQ(_T("\"a\""), path);

-

-  path = _T("a b");

-  EnclosePath(&path);

-  EXPECT_STREQ(_T("\"a b\""), path);

-

-  path = " a b ";

-  EnclosePath(&path);

-  EXPECT_STREQ(_T("\" a b \""), path);

-

-  path = _T("\"a b\"");

-  EnclosePath(&path);

-  EXPECT_STREQ(_T("\"a b\""), path);

-

-  path = _T("c:\\Windows\\notepad.exe");

-  EnclosePath(&path);

-  EXPECT_STREQ(_T("\"c:\\Windows\\notepad.exe\""), path);

-

-  path = _T("c:\\Program Files\\Google\\Common\\Google Update");

-  EnclosePath(&path);

-  EXPECT_STREQ(_T("\"c:\\Program Files\\Google\\Common\\Google Update\""),

-               path);

-}

-

-// EnclosePath encloses a string that has a quote only at the beginning or end.

-TEST(PathTest, EnclosePath_OnlyOneQuote) {

-  ExpectAsserts expect_asserts;

-  CString path = _T("\"a b");

-  EnclosePath(&path);

-  EXPECT_STREQ(_T("\"\"a b\""), path);

-

-  path = _T("a b\"");

-  EnclosePath(&path);

-  EXPECT_STREQ(_T("\"a b\"\""), path);

-}

-

-// EnclosePath does not look at the middle of the string.

-TEST(PathTest, EnclosePath_QuoteInMiddle) {

-  CString path = _T("a\" b");

-  EnclosePath(&path);

-  EXPECT_STREQ(_T("\"a\" b\""), path);

-}

-

-TEST(PathTest, EnclosePath_SingleQuotes) {

-  CString path = _T("'foo'");

-  EnclosePath(&path);

-  EXPECT_STREQ(_T("\"'foo'\""), path);

-}

-

-TEST(PathTest, EnclosePathIfExe) {

-  CString original_path;

-  CString new_path;

-  new_path = EnclosePathIfExe(original_path);

-  EXPECT_STREQ(original_path, new_path);

-

-  original_path = _T("");

-  new_path = EnclosePathIfExe(original_path);

-  EXPECT_STREQ(original_path, new_path);

-

-  original_path = _T("a");

-  new_path = EnclosePathIfExe(original_path);

-  EXPECT_STREQ(original_path, new_path);

-

-  original_path = _T("a b");

-  new_path = EnclosePathIfExe(original_path);

-  EXPECT_STREQ(original_path, new_path);

-

-  original_path = " a b ";

-  new_path = EnclosePathIfExe(original_path);

-  EXPECT_STREQ(original_path, new_path);

-

-  original_path = _T("\"a b\"");

-  new_path = EnclosePathIfExe(original_path);

-  EXPECT_STREQ(original_path, new_path);

-

-  original_path = _T("c:\\Windows\\notepad.exe");

-  new_path = EnclosePathIfExe(original_path);

-  EXPECT_STREQ(_T("\"c:\\Windows\\notepad.exe\""), new_path);

-

-  original_path = _T("c:\\Program Files\\Google\\Update");

-  new_path = EnclosePathIfExe(original_path);

-  EXPECT_STREQ(original_path, new_path);

-

-  original_path = _T("c:\\Progra Files\\Google\\Update\\1.1.1.1\\goopdate.dll");

-  new_path = EnclosePathIfExe(original_path);

-  EXPECT_STREQ(original_path, new_path);

-

-  original_path = _T("c:\\Prog F\\Googl\\Update\\GoogleUpdate.exe");

-  new_path = EnclosePathIfExe(original_path);

-  EXPECT_STREQ(_T("\"c:\\Prog F\\Googl\\Update\\GoogleUpdate.exe\""), new_path);

-}

-

-TEST(PathTest, ConcatenatePath) {

-  CString expected_path("C:\\first\\part\\second\\part");

-

-  CString start("C:\\first\\part");

-  CString start_slash("C:\\first\\part\\");

-  CString end("second\\part");

-  CString end_slash("\\second\\part");

-

-  EXPECT_STREQ(expected_path, ConcatenatePath(start, end));

-  EXPECT_STREQ(expected_path, ConcatenatePath(start_slash, end));

-  EXPECT_STREQ(expected_path, ConcatenatePath(start, end_slash));

-  EXPECT_STREQ(expected_path, ConcatenatePath(start_slash, end_slash));

-}

-

-TEST(PathTest, ConcatenatePath_PathTooLong) {

-  CString two_hundred_char_root_path(_T("C:\\reallllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllly\\loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"));  // NOLINT

-  CString two_hundred_char_path(_T("realllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllly\\loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"));  // NOLINT

-  EXPECT_EQ(200, two_hundred_char_root_path.GetLength());

-  CString fifty_eight_char_name(

-      _T("filenaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaame"));

-  EXPECT_EQ(58, fifty_eight_char_name.GetLength());

-  CString fifty_nine_char_name(

-      _T("filenaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaame"));

-  EXPECT_EQ(59, fifty_nine_char_name.GetLength());

-  CString sixty_char_name(

-      _T("filenaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaame"));

-  EXPECT_EQ(60, sixty_char_name.GetLength());

-

-  // Adding the '\' makes it 259 chars.

-  CString result = ConcatenatePath(two_hundred_char_root_path,

-                                   fifty_eight_char_name);

-  EXPECT_STREQ(_T("C:\\reallllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllly\\loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong\\filenaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaame"),  // NOLINT

-               result);

-

-  // Adding the '\' makes it 260 chars.

-  ExpectAsserts expect_asserts;

-  result = ConcatenatePath(two_hundred_char_root_path,

-                                   fifty_nine_char_name);

-  EXPECT_TRUE(result.IsEmpty());

-

-  // Adding the '\' makes it 261 chars.

-  result = ConcatenatePath(two_hundred_char_root_path, sixty_char_name);

-  EXPECT_TRUE(result.IsEmpty());

-

-  // Test for buffer overflow on long strings.

-}

-

-TEST(PathTest, ConcatenatePath_EmptyString) {

-  EXPECT_STREQ(_T("bar.exe"), ConcatenatePath(_T(""), _T("bar.exe")));

-  EXPECT_STREQ(_T("foo"), ConcatenatePath(_T("foo"), _T("")));

-  // This is not what I would expect, but it is what the API does.

-  EXPECT_STREQ(_T("\\"), ConcatenatePath(_T(""), _T("")));

-}

-

-// TODO(omaha): The expected and actual values are reversed throughout.

-

-TEST(PathTest, ShortPathToLongPath) {

-  CString expected_path("C:\\Program Files");

-  CString short_path("C:\\Progra~1");

-

-  CString long_path;

-  ASSERT_SUCCEEDED(ShortPathToLongPath(short_path, &long_path));

-  ASSERT_STREQ(expected_path, long_path);

-}

-

-TEST(PathTest, FindFilesTest) {

-  GUID guid = GUID_NULL;

-  ASSERT_SUCCEEDED(::CoCreateGuid(&guid));

-

-  TCHAR path[MAX_PATH] = {0};

-  ASSERT_NE(::GetTempPath(MAX_PATH, path), 0);

-

-  CString dir = ConcatenatePath(path, GuidToString(guid));

-  EXPECT_FALSE(dir.IsEmpty());

-  EXPECT_FALSE(File::Exists(dir));

-

-  // Test with non-existent dir.

-  std::vector<CString> files;

-  EXPECT_FAILED(FindFiles(dir, _T("*.txt"), &files));

-  EXPECT_EQ(files.size(), 0);

-

-  // Test with empty dir.

-  EXPECT_NE(::CreateDirectory(dir, NULL), 0);

-  files.clear();

-  EXPECT_EQ(FindFiles(dir, _T("asdf.txt"), &files), 0x80070002);

-  EXPECT_EQ(files.size(), 0);

-

-  CString filename1 = _T("one.txt");

-  CString filepath1 = ConcatenatePath(dir, filename1);

-  CString filename2 = _T("two_en.txt");

-  CString filepath2 = ConcatenatePath(dir, filename2);

-

-  // Test with dir containing one file.

-  HANDLE handle1 = ::CreateFile(filepath1, GENERIC_READ, FILE_SHARE_READ,

-                                NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,

-                                NULL);

-  EXPECT_TRUE(handle1 != NULL);

-  files.clear();

-  EXPECT_SUCCEEDED(FindFiles(dir, _T("*.txt"), &files));

-  EXPECT_EQ(files.size(), 1);

-  EXPECT_STREQ(files[0], filename1);

-

-  files.clear();

-  EXPECT_SUCCEEDED(FindFiles(dir, _T("o*.txt"), &files));

-  EXPECT_EQ(files.size(), 1);

-  EXPECT_STREQ(files[0], filename1);

-

-  files.clear();

-  EXPECT_SUCCEEDED(FindFiles(dir, filepath1, &files));

-  EXPECT_EQ(files.size(), 1);

-  EXPECT_STREQ(files[0], filename1);

-

-  files.clear();

-  EXPECT_EQ(FindFiles(dir, _T("t*.txt"), &files), 0x80070002);

-  EXPECT_EQ(files.size(), 0);

-

-  // Test with dir containing two files.

-  HANDLE handle2 = ::CreateFile(filepath2, GENERIC_READ, FILE_SHARE_READ,

-                                NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,

-                                NULL);

-  EXPECT_TRUE(handle2 != NULL);

-  files.clear();

-  EXPECT_SUCCEEDED(FindFiles(dir, _T("*.txt"), &files));

-  EXPECT_EQ(files.size(), 2);

-  EXPECT_STREQ(files[0], filename1);

-  EXPECT_STREQ(files[1], filename2);

-

-  files.clear();

-  EXPECT_SUCCEEDED(FindFiles(dir, _T("o*.txt"), &files));

-  EXPECT_EQ(files.size(), 1);

-  EXPECT_STREQ(files[0], filename1);

-

-  files.clear();

-  EXPECT_SUCCEEDED(FindFiles(dir, _T("t*.txt"), &files));

-  EXPECT_EQ(files.size(), 1);

-  EXPECT_STREQ(files[0], filename2);

-

-  files.clear();

-  EXPECT_EQ(FindFiles(dir, _T("asdf.txt"), &files), 0x80070002);

-  EXPECT_EQ(files.size(), 0);

-

-  EXPECT_NE(::CloseHandle(handle1), 0);

-  EXPECT_SUCCEEDED(File::Remove(filepath1));

-  EXPECT_NE(::CloseHandle(handle2), 0);

-  EXPECT_SUCCEEDED(File::Remove(filepath2));

-  EXPECT_NE(::RemoveDirectory(dir), 0);

-}

-

-namespace detail {

-

-struct Directory {

-  Directory() {}

-  explicit Directory(const CString& name) : dir_name(name) {}

-

-  CString dir_name;

-  std::vector<Directory> sub_dirs;

-  std::vector<CString> files;

-};

-

-void ConvertDirectoryStructureToFiles(const Directory& directory,

-                                      const CString& dir_path,

-                                      std::vector<CString>* files) {

-  ASSERT_TRUE(files != NULL);

-  ASSERT_HRESULT_SUCCEEDED(CreateDir(dir_path, NULL));

-

-  for (size_t i = 0; i < directory.files.size(); ++i) {

-    const CString& file = ConcatenatePath(dir_path, directory.files[i]);

-    scoped_handle handle(::CreateFile(file, GENERIC_READ, FILE_SHARE_READ,

-                                      NULL, CREATE_ALWAYS,

-                                      FILE_ATTRIBUTE_NORMAL,

-                                      NULL));

-    EXPECT_TRUE(get(handle) != NULL);

-    files->push_back(file);

-  }

-

-  for (size_t i = 0; i < directory.sub_dirs.size(); ++i) {

-    ConvertDirectoryStructureToFiles(

-        directory.sub_dirs[i],

-        ConcatenatePath(dir_path, directory.sub_dirs[i].dir_name),

-        files);

-  }

-}

-

-void CreateTestDirectoryStructure(Directory* root_dir) {

-  EXPECT_TRUE(root_dir != NULL);

-  GUID guid = GUID_NULL;

-  ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&guid));

-

-  TCHAR path[MAX_PATH] = {0};

-  ASSERT_NE(0, ::GetTempPath(MAX_PATH, path));

-

-  CString dir = ConcatenatePath(path, GuidToString(guid));

-  EXPECT_FALSE(dir.IsEmpty());

-  EXPECT_FALSE(File::Exists(dir));

-

-  root_dir->dir_name = dir;

-  root_dir->files.push_back(_T("test1.txt"));

-  root_dir->files.push_back(_T("test2.txt"));

-

-  Directory sub_dir1_level1(_T("sub_dir1_level1"));

-  sub_dir1_level1.files.push_back(_T("sub_dir1_level1_test1.txt"));

-  Directory sub_dir1_level2(_T("sub_dir1_level2"));

-  sub_dir1_level2.files.push_back(_T("sub_dir1_level2_test1.txt"));

-  sub_dir1_level1.sub_dirs.push_back(sub_dir1_level2);

-  root_dir->sub_dirs.push_back(sub_dir1_level1);

-

-  Directory sub_dir2_level1(_T("sub_dir2_level1"));

-  sub_dir2_level1.files.push_back(_T("sub_dir2_level1_test1.txt"));

-  root_dir->sub_dirs.push_back(sub_dir2_level1);

-}

-}  // detail.

-

-TEST(PathTest, FindFileRecursiveTest) {

-  detail::Directory dir;

-  detail::CreateTestDirectoryStructure(&dir);

-

-  std::vector<CString> expected_files;

-  detail::ConvertDirectoryStructureToFiles(dir, dir.dir_name, &expected_files);

-

-  // Call the test method.

-  std::vector<CString> files;

-  ASSERT_HRESULT_SUCCEEDED(FindFileRecursive(dir.dir_name,

-                                             _T("*test*.txt"),

-                                             &files));

-

-  // Validate the results.

-  ASSERT_EQ(expected_files.size(), files.size());

-  for (size_t i = 0; i < expected_files.size(); ++i) {

-    EXPECT_STREQ(expected_files[i], files[i]);

-  }

-

-  // Cleanup.

-  ASSERT_HRESULT_SUCCEEDED(DeleteDirectory(dir.dir_name));

-}

-

-TEST(PathTest, FindFileRecursiveTest_Empty) {

-  GUID guid = GUID_NULL;

-  ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&guid));

-

-  TCHAR path[MAX_PATH] = {0};

-  ASSERT_NE(0, ::GetTempPath(MAX_PATH, path));

-

-  CString dir = ConcatenatePath(path, GuidToString(guid));

-  EXPECT_FALSE(dir.IsEmpty());

-  EXPECT_FALSE(File::Exists(dir));

-

-  ASSERT_HRESULT_SUCCEEDED(CreateDir(dir, NULL));

-

-  // Call the test method.

-  std::vector<CString> files;

-  ASSERT_HRESULT_SUCCEEDED(FindFileRecursive(dir, _T("*test*.txt"),

-                                             &files));

-

-  // Validate results.

-  ASSERT_EQ(0, files.size());

-

-  // Cleanup.

-  ASSERT_HRESULT_SUCCEEDED(DeleteDirectory(dir));

-}

-

-TEST(PathTest, FindFileRecursiveTest_DirNotCreated) {

-  GUID guid = GUID_NULL;

-  ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&guid));

-

-  TCHAR path[MAX_PATH] = {0};

-  ASSERT_NE(0, ::GetTempPath(MAX_PATH, path));

-

-  CString dir = ConcatenatePath(path, GuidToString(guid));

-  EXPECT_FALSE(dir.IsEmpty());

-  EXPECT_FALSE(File::Exists(dir));

-

-  // Call the test method.

-  std::vector<CString> files;

-  ASSERT_HRESULT_FAILED(FindFileRecursive(dir, _T("*test*.txt"), &files));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Path-utility unit tests.
+
+#include <vector>
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(PathTest, IsAbsolutePath) {
+  ASSERT_TRUE(IsAbsolutePath(L"C:\\Foo.bar"));
+  ASSERT_TRUE(IsAbsolutePath(L"\\\\user-laptop1\\path"));
+  ASSERT_FALSE(IsAbsolutePath(L"windows\\system32"));
+}
+
+// EnclosePath is overzealous and quotes a path even though no spaces exists.
+TEST(PathTest, EnclosePath) {
+  CString path;
+  EnclosePath(&path);
+  EXPECT_STREQ(_T(""), path);
+
+  path = _T("");
+  EnclosePath(&path);
+  EXPECT_STREQ(_T(""), path);
+
+  path = _T("a");
+  EnclosePath(&path);
+  EXPECT_STREQ(_T("\"a\""), path);
+
+  path = _T("a b");
+  EnclosePath(&path);
+  EXPECT_STREQ(_T("\"a b\""), path);
+
+  path = " a b ";
+  EnclosePath(&path);
+  EXPECT_STREQ(_T("\" a b \""), path);
+
+  path = _T("\"a b\"");
+  EnclosePath(&path);
+  EXPECT_STREQ(_T("\"a b\""), path);
+
+  path = _T("c:\\Windows\\notepad.exe");
+  EnclosePath(&path);
+  EXPECT_STREQ(_T("\"c:\\Windows\\notepad.exe\""), path);
+
+  path = _T("c:\\Program Files\\Google\\Common\\Google Update");
+  EnclosePath(&path);
+  EXPECT_STREQ(_T("\"c:\\Program Files\\Google\\Common\\Google Update\""),
+               path);
+}
+
+// EnclosePath encloses a string that has a quote only at the beginning or end.
+TEST(PathTest, EnclosePath_OnlyOneQuote) {
+  ExpectAsserts expect_asserts;
+  CString path = _T("\"a b");
+  EnclosePath(&path);
+  EXPECT_STREQ(_T("\"\"a b\""), path);
+
+  path = _T("a b\"");
+  EnclosePath(&path);
+  EXPECT_STREQ(_T("\"a b\"\""), path);
+}
+
+// EnclosePath does not look at the middle of the string.
+TEST(PathTest, EnclosePath_QuoteInMiddle) {
+  CString path = _T("a\" b");
+  EnclosePath(&path);
+  EXPECT_STREQ(_T("\"a\" b\""), path);
+}
+
+TEST(PathTest, EnclosePath_SingleQuotes) {
+  CString path = _T("'foo'");
+  EnclosePath(&path);
+  EXPECT_STREQ(_T("\"'foo'\""), path);
+}
+
+TEST(PathTest, EnclosePathIfExe) {
+  CString original_path;
+  CString new_path;
+  new_path = EnclosePathIfExe(original_path);
+  EXPECT_STREQ(original_path, new_path);
+
+  original_path = _T("");
+  new_path = EnclosePathIfExe(original_path);
+  EXPECT_STREQ(original_path, new_path);
+
+  original_path = _T("a");
+  new_path = EnclosePathIfExe(original_path);
+  EXPECT_STREQ(original_path, new_path);
+
+  original_path = _T("a b");
+  new_path = EnclosePathIfExe(original_path);
+  EXPECT_STREQ(original_path, new_path);
+
+  original_path = " a b ";
+  new_path = EnclosePathIfExe(original_path);
+  EXPECT_STREQ(original_path, new_path);
+
+  original_path = _T("\"a b\"");
+  new_path = EnclosePathIfExe(original_path);
+  EXPECT_STREQ(original_path, new_path);
+
+  original_path = _T("c:\\Windows\\notepad.exe");
+  new_path = EnclosePathIfExe(original_path);
+  EXPECT_STREQ(_T("\"c:\\Windows\\notepad.exe\""), new_path);
+
+  original_path = _T("c:\\Program Files\\Google\\Update");
+  new_path = EnclosePathIfExe(original_path);
+  EXPECT_STREQ(original_path, new_path);
+
+  original_path = _T("c:\\Progra Files\\Google\\Update\\1.1.1.1\\goopdate.dll");
+  new_path = EnclosePathIfExe(original_path);
+  EXPECT_STREQ(original_path, new_path);
+
+  original_path = _T("c:\\Prog F\\Googl\\Update\\GoogleUpdate.exe");
+  new_path = EnclosePathIfExe(original_path);
+  EXPECT_STREQ(_T("\"c:\\Prog F\\Googl\\Update\\GoogleUpdate.exe\""), new_path);
+}
+
+TEST(PathTest, ConcatenatePath) {
+  CString expected_path("C:\\first\\part\\second\\part");
+
+  CString start("C:\\first\\part");
+  CString start_slash("C:\\first\\part\\");
+  CString end("second\\part");
+  CString end_slash("\\second\\part");
+
+  EXPECT_STREQ(expected_path, ConcatenatePath(start, end));
+  EXPECT_STREQ(expected_path, ConcatenatePath(start_slash, end));
+  EXPECT_STREQ(expected_path, ConcatenatePath(start, end_slash));
+  EXPECT_STREQ(expected_path, ConcatenatePath(start_slash, end_slash));
+}
+
+TEST(PathTest, ConcatenatePath_PathTooLong) {
+  CString two_hundred_char_root_path(_T("C:\\reallllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllly\\loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"));  // NOLINT
+  CString two_hundred_char_path(_T("realllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllly\\loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"));  // NOLINT
+  EXPECT_EQ(200, two_hundred_char_root_path.GetLength());
+  CString fifty_eight_char_name(
+      _T("filenaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaame"));
+  EXPECT_EQ(58, fifty_eight_char_name.GetLength());
+  CString fifty_nine_char_name(
+      _T("filenaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaame"));
+  EXPECT_EQ(59, fifty_nine_char_name.GetLength());
+  CString sixty_char_name(
+      _T("filenaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaame"));
+  EXPECT_EQ(60, sixty_char_name.GetLength());
+
+  // Adding the '\' makes it 259 chars.
+  CString result = ConcatenatePath(two_hundred_char_root_path,
+                                   fifty_eight_char_name);
+  EXPECT_STREQ(_T("C:\\reallllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllly\\loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong\\filenaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaame"),  // NOLINT
+               result);
+
+  // Adding the '\' makes it 260 chars.
+  ExpectAsserts expect_asserts;
+  result = ConcatenatePath(two_hundred_char_root_path,
+                                   fifty_nine_char_name);
+  EXPECT_TRUE(result.IsEmpty());
+
+  // Adding the '\' makes it 261 chars.
+  result = ConcatenatePath(two_hundred_char_root_path, sixty_char_name);
+  EXPECT_TRUE(result.IsEmpty());
+
+  // Test for buffer overflow on long strings.
+}
+
+TEST(PathTest, ConcatenatePath_EmptyString) {
+  EXPECT_STREQ(_T("bar.exe"), ConcatenatePath(_T(""), _T("bar.exe")));
+  EXPECT_STREQ(_T("foo"), ConcatenatePath(_T("foo"), _T("")));
+  // This is not what I would expect, but it is what the API does.
+  EXPECT_STREQ(_T("\\"), ConcatenatePath(_T(""), _T("")));
+}
+
+// TODO(omaha): The expected and actual values are reversed throughout.
+
+TEST(PathTest, ShortPathToLongPath) {
+  CString expected_path("C:\\Program Files");
+  CString short_path("C:\\Progra~1");
+
+  CString long_path;
+  ASSERT_SUCCEEDED(ShortPathToLongPath(short_path, &long_path));
+  ASSERT_STREQ(expected_path, long_path);
+}
+
+TEST(PathTest, FindFilesTest) {
+  GUID guid = GUID_NULL;
+  ASSERT_SUCCEEDED(::CoCreateGuid(&guid));
+
+  TCHAR path[MAX_PATH] = {0};
+  ASSERT_NE(::GetTempPath(MAX_PATH, path), 0);
+
+  CString dir = ConcatenatePath(path, GuidToString(guid));
+  EXPECT_FALSE(dir.IsEmpty());
+  EXPECT_FALSE(File::Exists(dir));
+
+  // Test with non-existent dir.
+  std::vector<CString> files;
+  EXPECT_FAILED(FindFiles(dir, _T("*.txt"), &files));
+  EXPECT_EQ(files.size(), 0);
+
+  // Test with empty dir.
+  EXPECT_NE(::CreateDirectory(dir, NULL), 0);
+  files.clear();
+  EXPECT_EQ(FindFiles(dir, _T("asdf.txt"), &files), 0x80070002);
+  EXPECT_EQ(files.size(), 0);
+
+  CString filename1 = _T("one.txt");
+  CString filepath1 = ConcatenatePath(dir, filename1);
+  CString filename2 = _T("two_en.txt");
+  CString filepath2 = ConcatenatePath(dir, filename2);
+
+  // Test with dir containing one file.
+  HANDLE handle1 = ::CreateFile(filepath1, GENERIC_READ, FILE_SHARE_READ,
+                                NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+                                NULL);
+  EXPECT_TRUE(handle1 != NULL);
+  files.clear();
+  EXPECT_SUCCEEDED(FindFiles(dir, _T("*.txt"), &files));
+  EXPECT_EQ(files.size(), 1);
+  EXPECT_STREQ(files[0], filename1);
+
+  files.clear();
+  EXPECT_SUCCEEDED(FindFiles(dir, _T("o*.txt"), &files));
+  EXPECT_EQ(files.size(), 1);
+  EXPECT_STREQ(files[0], filename1);
+
+  files.clear();
+  EXPECT_SUCCEEDED(FindFiles(dir, filepath1, &files));
+  EXPECT_EQ(files.size(), 1);
+  EXPECT_STREQ(files[0], filename1);
+
+  files.clear();
+  EXPECT_EQ(FindFiles(dir, _T("t*.txt"), &files), 0x80070002);
+  EXPECT_EQ(files.size(), 0);
+
+  // Test with dir containing two files.
+  HANDLE handle2 = ::CreateFile(filepath2, GENERIC_READ, FILE_SHARE_READ,
+                                NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+                                NULL);
+  EXPECT_TRUE(handle2 != NULL);
+  files.clear();
+  EXPECT_SUCCEEDED(FindFiles(dir, _T("*.txt"), &files));
+  EXPECT_EQ(files.size(), 2);
+  EXPECT_STREQ(files[0], filename1);
+  EXPECT_STREQ(files[1], filename2);
+
+  files.clear();
+  EXPECT_SUCCEEDED(FindFiles(dir, _T("o*.txt"), &files));
+  EXPECT_EQ(files.size(), 1);
+  EXPECT_STREQ(files[0], filename1);
+
+  files.clear();
+  EXPECT_SUCCEEDED(FindFiles(dir, _T("t*.txt"), &files));
+  EXPECT_EQ(files.size(), 1);
+  EXPECT_STREQ(files[0], filename2);
+
+  files.clear();
+  EXPECT_EQ(FindFiles(dir, _T("asdf.txt"), &files), 0x80070002);
+  EXPECT_EQ(files.size(), 0);
+
+  EXPECT_NE(::CloseHandle(handle1), 0);
+  EXPECT_SUCCEEDED(File::Remove(filepath1));
+  EXPECT_NE(::CloseHandle(handle2), 0);
+  EXPECT_SUCCEEDED(File::Remove(filepath2));
+  EXPECT_NE(::RemoveDirectory(dir), 0);
+}
+
+namespace detail {
+
+struct Directory {
+  Directory() {}
+  explicit Directory(const CString& name) : dir_name(name) {}
+
+  CString dir_name;
+  std::vector<Directory> sub_dirs;
+  std::vector<CString> files;
+};
+
+void ConvertDirectoryStructureToFiles(const Directory& directory,
+                                      const CString& dir_path,
+                                      std::vector<CString>* files) {
+  ASSERT_TRUE(files != NULL);
+  ASSERT_HRESULT_SUCCEEDED(CreateDir(dir_path, NULL));
+
+  for (size_t i = 0; i < directory.files.size(); ++i) {
+    const CString& file = ConcatenatePath(dir_path, directory.files[i]);
+    scoped_handle handle(::CreateFile(file, GENERIC_READ, FILE_SHARE_READ,
+                                      NULL, CREATE_ALWAYS,
+                                      FILE_ATTRIBUTE_NORMAL,
+                                      NULL));
+    EXPECT_TRUE(get(handle) != NULL);
+    files->push_back(file);
+  }
+
+  for (size_t i = 0; i < directory.sub_dirs.size(); ++i) {
+    ConvertDirectoryStructureToFiles(
+        directory.sub_dirs[i],
+        ConcatenatePath(dir_path, directory.sub_dirs[i].dir_name),
+        files);
+  }
+}
+
+void CreateTestDirectoryStructure(Directory* root_dir) {
+  EXPECT_TRUE(root_dir != NULL);
+  GUID guid = GUID_NULL;
+  ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&guid));
+
+  TCHAR path[MAX_PATH] = {0};
+  ASSERT_NE(0, ::GetTempPath(MAX_PATH, path));
+
+  CString dir = ConcatenatePath(path, GuidToString(guid));
+  EXPECT_FALSE(dir.IsEmpty());
+  EXPECT_FALSE(File::Exists(dir));
+
+  root_dir->dir_name = dir;
+  root_dir->files.push_back(_T("test1.txt"));
+  root_dir->files.push_back(_T("test2.txt"));
+
+  Directory sub_dir1_level1(_T("sub_dir1_level1"));
+  sub_dir1_level1.files.push_back(_T("sub_dir1_level1_test1.txt"));
+  Directory sub_dir1_level2(_T("sub_dir1_level2"));
+  sub_dir1_level2.files.push_back(_T("sub_dir1_level2_test1.txt"));
+  sub_dir1_level1.sub_dirs.push_back(sub_dir1_level2);
+  root_dir->sub_dirs.push_back(sub_dir1_level1);
+
+  Directory sub_dir2_level1(_T("sub_dir2_level1"));
+  sub_dir2_level1.files.push_back(_T("sub_dir2_level1_test1.txt"));
+  root_dir->sub_dirs.push_back(sub_dir2_level1);
+}
+}  // detail.
+
+TEST(PathTest, FindFileRecursiveTest) {
+  detail::Directory dir;
+  detail::CreateTestDirectoryStructure(&dir);
+
+  std::vector<CString> expected_files;
+  detail::ConvertDirectoryStructureToFiles(dir, dir.dir_name, &expected_files);
+
+  // Call the test method.
+  std::vector<CString> files;
+  ASSERT_HRESULT_SUCCEEDED(FindFileRecursive(dir.dir_name,
+                                             _T("*test*.txt"),
+                                             &files));
+
+  // Validate the results.
+  ASSERT_EQ(expected_files.size(), files.size());
+  for (size_t i = 0; i < expected_files.size(); ++i) {
+    EXPECT_STREQ(expected_files[i], files[i]);
+  }
+
+  // Cleanup.
+  ASSERT_HRESULT_SUCCEEDED(DeleteDirectory(dir.dir_name));
+}
+
+TEST(PathTest, FindFileRecursiveTest_Empty) {
+  GUID guid = GUID_NULL;
+  ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&guid));
+
+  TCHAR path[MAX_PATH] = {0};
+  ASSERT_NE(0, ::GetTempPath(MAX_PATH, path));
+
+  CString dir = ConcatenatePath(path, GuidToString(guid));
+  EXPECT_FALSE(dir.IsEmpty());
+  EXPECT_FALSE(File::Exists(dir));
+
+  ASSERT_HRESULT_SUCCEEDED(CreateDir(dir, NULL));
+
+  // Call the test method.
+  std::vector<CString> files;
+  ASSERT_HRESULT_SUCCEEDED(FindFileRecursive(dir, _T("*test*.txt"),
+                                             &files));
+
+  // Validate results.
+  ASSERT_EQ(0, files.size());
+
+  // Cleanup.
+  ASSERT_HRESULT_SUCCEEDED(DeleteDirectory(dir));
+}
+
+TEST(PathTest, FindFileRecursiveTest_DirNotCreated) {
+  GUID guid = GUID_NULL;
+  ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&guid));
+
+  TCHAR path[MAX_PATH] = {0};
+  ASSERT_NE(0, ::GetTempPath(MAX_PATH, path));
+
+  CString dir = ConcatenatePath(path, GuidToString(guid));
+  EXPECT_FALSE(dir.IsEmpty());
+  EXPECT_FALSE(File::Exists(dir));
+
+  // Call the test method.
+  std::vector<CString> files;
+  ASSERT_HRESULT_FAILED(FindFileRecursive(dir, _T("*test*.txt"), &files));
+}
+
+}  // namespace omaha
+
diff --git a/common/pe_utils.cc b/common/pe_utils.cc
index d3dddb5..1e3b1e5 100644
--- a/common/pe_utils.cc
+++ b/common/pe_utils.cc
@@ -1,215 +1,215 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Utility functions related to PE files (executables)

-

-#include "omaha/common/pe_utils.h"

-

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/scoped_any.h"

-

-namespace omaha {

-

-// Not really necessary as long as running on x86 architecture throughout, but

-// what the hell

-#if defined(BIG_ENDIAN)

-uint32 GetUint32LE(void const * const p) {

-  uchar const * const pu = reinterpret_cast<uchar const * const>(p);

-  uint32 i = pu[0] | pu[1]<<8 | pu[2]<<16 | pu[3]<<24;

-  return i;

-}

-

-void PutUint32LE(uint32 i, void * const p) {

-  uchar * const pu = reinterpret_cast<uchar * const>(p);

-  pu[0] = i & 0xff;

-  pu[1] = (i >>  8) & 0xff;

-  pu[2] = (i >> 16) & 0xff;

-  pu[3] = (i >> 24) & 0xff;

-}

-#else  // LITTLE_ENDIAN

-inline uint32 GetUint32LE(void const * const p) {

-  uint32 const * const pu = reinterpret_cast<uint32 const * const>(p);

-  return *pu;

-}

-

-inline void PutUint32LE(uint32 i, void * const p) {

-  uint32 * const pu = reinterpret_cast<uint32 * const>(p);

-  *pu = i;

-}

-#endif

-

-// Magic PE constants

-const uint32 kPEHeaderOffset         = 60;

-const uint32 kPEHeaderChecksumOffset = 88;

-const uint32 kPEHeaderSizeMin        = 160;

-const char magic_EXE_header[] = "MZ\0\0";

-const char magic_PE_header[]  = "PE\0\0";

-

-HRESULT SetPEChecksum(const TCHAR *filename, uint32 checksum) {

-  // Write the checksum field of the Windows NT-specific "optional" header.

-  // Use Windows API calls rather than C library calls so that it will be

-  // really a small routine when used in the stub executable.

-

-  ASSERT(filename, (L""));

-

-  scoped_hfile file(::CreateFile(filename,

-                                 GENERIC_READ | GENERIC_WRITE,

-                                 0,

-                                 NULL,

-                                 OPEN_EXISTING,

-                                 FILE_ATTRIBUTE_NORMAL,

-                                 NULL));

-  if (!file)

-    return HRESULTFromLastError();

-

-  size_t size = ::GetFileSize(get(file), NULL);

-  if (size == INVALID_FILE_SIZE)

-    return HRESULTFromLastError();

-

-  scoped_file_mapping mapping(::CreateFileMapping(get(file),

-                                                  NULL,

-                                                  PAGE_READWRITE,

-                                                  0,

-                                                  0,

-                                                  NULL));

-  if (!mapping)

-    return HRESULTFromLastError();

-

-  scoped_file_view file_data(::MapViewOfFile(get(mapping),

-                                             FILE_MAP_WRITE,

-                                             0,

-                                             0,

-                                             size));

-  if (!file_data)

-    return HRESULTFromLastError();

-

-  uchar * image = reinterpret_cast<uchar *>(get(file_data));

-

-  return SetPEChecksumToBuffer(image, size, checksum);

-}

-

-HRESULT GetPEChecksum(const TCHAR *filename, uint32 * checksum) {

-  // Read the checksum field out of the Windows NT-specific "optional" header.

-  // Use Windows API calls rather than C library calls so that it will be

-  // really a small routine when used in the stub executable.

-

-  ASSERT(filename, (L""));

-  ASSERT(checksum, (L""));

-

-  scoped_hfile file(::CreateFile(filename,

-                                 GENERIC_READ,

-                                 FILE_SHARE_READ,

-                                 NULL,

-                                 OPEN_EXISTING,

-                                 FILE_ATTRIBUTE_READONLY,

-                                 NULL));

-  if (!file)

-    return HRESULTFromLastError();

-

-  size_t size = ::GetFileSize(get(file), NULL);

-  if (size == INVALID_FILE_SIZE)

-    return HRESULTFromLastError();

-

-  scoped_file_mapping mapping(::CreateFileMapping(get(file),

-                              NULL,

-                              PAGE_READONLY,

-                              0,

-                              0,

-                              NULL));

-  if (!mapping)

-    return HRESULTFromLastError();

-

-  scoped_file_view file_data(::MapViewOfFile(get(mapping),

-                             FILE_MAP_READ,

-                             0,

-                             0,

-                             size));

-  if (!file_data)

-    return HRESULTFromLastError();

-

-  uchar * image = reinterpret_cast<uchar *>(get(file_data));

-

-  return GetPEChecksumFromBuffer(image, size, checksum);

-}

-

-HRESULT SetPEChecksumToBuffer(uchar *buffer, size_t size, uint32 checksum) {

-  // Sanity checks

-  if (size < 64) {

-    ASSERT(false, (L"File too short to be valid executable"));

-    return E_FAIL;

-  }

-

-  uint32 x = GetUint32LE(magic_EXE_header);

-  if (::memcmp(buffer, &x, 2)) {

-    ASSERT(false, (L"Missing executable's magic number"));

-    return E_FAIL;

-  }

-

-  uint32 peheader = GetUint32LE(buffer + kPEHeaderOffset);

-  if (size < peheader + kPEHeaderSizeMin) {

-    ASSERT(false, (L"Too small given PE header size"));

-    return E_FAIL;

-  }

-

-  x = GetUint32LE(magic_PE_header);

-  if (::memcmp(buffer + peheader, &x, 4)) {

-    ASSERT(false, (L"Missing PE header magic number"));

-    return E_FAIL;

-  }

-

-  // Finally, write the checksum

-  PutUint32LE(checksum, &x);

-  ::memcpy(buffer + peheader + kPEHeaderChecksumOffset, &x, 4);

-

-  return S_OK;

-}

-

-HRESULT GetPEChecksumFromBuffer(const unsigned char *buffer,

-                                size_t size,

-                                uint32 *checksum) {

-  // Sanity checks

-  if (size < 64) {

-    ASSERT(false, (L"File too short to be valid executable"));

-    return E_FAIL;

-  }

-

-  uint32 x = GetUint32LE(magic_EXE_header);

-  if (::memcmp(buffer, &x, 2)) {

-    ASSERT(false, (L"Missing executable's magic number"));

-    return E_FAIL;

-  }

-

-  uint32 peheader = GetUint32LE(buffer + kPEHeaderOffset);

-  if (size < peheader + kPEHeaderSizeMin) {

-    ASSERT(false, (L"Too small given PE header size"));

-    return E_FAIL;

-  }

-

-  x = GetUint32LE(magic_PE_header);

-  if (::memcmp(buffer + peheader, &x, 4)) {

-    ASSERT(false, (L"Missing PE header magic number"));

-    return E_FAIL;

-  }

-

-  // Finally, read the checksum

-

-  *checksum = GetUint32LE(buffer + peheader + kPEHeaderChecksumOffset);

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Utility functions related to PE files (executables)
+
+#include "omaha/common/pe_utils.h"
+
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/scoped_any.h"
+
+namespace omaha {
+
+// Not really necessary as long as running on x86 architecture throughout, but
+// what the hell
+#if defined(BIG_ENDIAN)
+uint32 GetUint32LE(void const * const p) {
+  uchar const * const pu = reinterpret_cast<uchar const * const>(p);
+  uint32 i = pu[0] | pu[1]<<8 | pu[2]<<16 | pu[3]<<24;
+  return i;
+}
+
+void PutUint32LE(uint32 i, void * const p) {
+  uchar * const pu = reinterpret_cast<uchar * const>(p);
+  pu[0] = i & 0xff;
+  pu[1] = (i >>  8) & 0xff;
+  pu[2] = (i >> 16) & 0xff;
+  pu[3] = (i >> 24) & 0xff;
+}
+#else  // LITTLE_ENDIAN
+inline uint32 GetUint32LE(void const * const p) {
+  uint32 const * const pu = reinterpret_cast<uint32 const * const>(p);
+  return *pu;
+}
+
+inline void PutUint32LE(uint32 i, void * const p) {
+  uint32 * const pu = reinterpret_cast<uint32 * const>(p);
+  *pu = i;
+}
+#endif
+
+// Magic PE constants
+const uint32 kPEHeaderOffset         = 60;
+const uint32 kPEHeaderChecksumOffset = 88;
+const uint32 kPEHeaderSizeMin        = 160;
+const char magic_EXE_header[] = "MZ\0\0";
+const char magic_PE_header[]  = "PE\0\0";
+
+HRESULT SetPEChecksum(const TCHAR *filename, uint32 checksum) {
+  // Write the checksum field of the Windows NT-specific "optional" header.
+  // Use Windows API calls rather than C library calls so that it will be
+  // really a small routine when used in the stub executable.
+
+  ASSERT(filename, (L""));
+
+  scoped_hfile file(::CreateFile(filename,
+                                 GENERIC_READ | GENERIC_WRITE,
+                                 0,
+                                 NULL,
+                                 OPEN_EXISTING,
+                                 FILE_ATTRIBUTE_NORMAL,
+                                 NULL));
+  if (!file)
+    return HRESULTFromLastError();
+
+  size_t size = ::GetFileSize(get(file), NULL);
+  if (size == INVALID_FILE_SIZE)
+    return HRESULTFromLastError();
+
+  scoped_file_mapping mapping(::CreateFileMapping(get(file),
+                                                  NULL,
+                                                  PAGE_READWRITE,
+                                                  0,
+                                                  0,
+                                                  NULL));
+  if (!mapping)
+    return HRESULTFromLastError();
+
+  scoped_file_view file_data(::MapViewOfFile(get(mapping),
+                                             FILE_MAP_WRITE,
+                                             0,
+                                             0,
+                                             size));
+  if (!file_data)
+    return HRESULTFromLastError();
+
+  uchar * image = reinterpret_cast<uchar *>(get(file_data));
+
+  return SetPEChecksumToBuffer(image, size, checksum);
+}
+
+HRESULT GetPEChecksum(const TCHAR *filename, uint32 * checksum) {
+  // Read the checksum field out of the Windows NT-specific "optional" header.
+  // Use Windows API calls rather than C library calls so that it will be
+  // really a small routine when used in the stub executable.
+
+  ASSERT(filename, (L""));
+  ASSERT(checksum, (L""));
+
+  scoped_hfile file(::CreateFile(filename,
+                                 GENERIC_READ,
+                                 FILE_SHARE_READ,
+                                 NULL,
+                                 OPEN_EXISTING,
+                                 FILE_ATTRIBUTE_READONLY,
+                                 NULL));
+  if (!file)
+    return HRESULTFromLastError();
+
+  size_t size = ::GetFileSize(get(file), NULL);
+  if (size == INVALID_FILE_SIZE)
+    return HRESULTFromLastError();
+
+  scoped_file_mapping mapping(::CreateFileMapping(get(file),
+                              NULL,
+                              PAGE_READONLY,
+                              0,
+                              0,
+                              NULL));
+  if (!mapping)
+    return HRESULTFromLastError();
+
+  scoped_file_view file_data(::MapViewOfFile(get(mapping),
+                             FILE_MAP_READ,
+                             0,
+                             0,
+                             size));
+  if (!file_data)
+    return HRESULTFromLastError();
+
+  uchar * image = reinterpret_cast<uchar *>(get(file_data));
+
+  return GetPEChecksumFromBuffer(image, size, checksum);
+}
+
+HRESULT SetPEChecksumToBuffer(uchar *buffer, size_t size, uint32 checksum) {
+  // Sanity checks
+  if (size < 64) {
+    ASSERT(false, (L"File too short to be valid executable"));
+    return E_FAIL;
+  }
+
+  uint32 x = GetUint32LE(magic_EXE_header);
+  if (::memcmp(buffer, &x, 2)) {
+    ASSERT(false, (L"Missing executable's magic number"));
+    return E_FAIL;
+  }
+
+  uint32 peheader = GetUint32LE(buffer + kPEHeaderOffset);
+  if (size < peheader + kPEHeaderSizeMin) {
+    ASSERT(false, (L"Too small given PE header size"));
+    return E_FAIL;
+  }
+
+  x = GetUint32LE(magic_PE_header);
+  if (::memcmp(buffer + peheader, &x, 4)) {
+    ASSERT(false, (L"Missing PE header magic number"));
+    return E_FAIL;
+  }
+
+  // Finally, write the checksum
+  PutUint32LE(checksum, &x);
+  ::memcpy(buffer + peheader + kPEHeaderChecksumOffset, &x, 4);
+
+  return S_OK;
+}
+
+HRESULT GetPEChecksumFromBuffer(const unsigned char *buffer,
+                                size_t size,
+                                uint32 *checksum) {
+  // Sanity checks
+  if (size < 64) {
+    ASSERT(false, (L"File too short to be valid executable"));
+    return E_FAIL;
+  }
+
+  uint32 x = GetUint32LE(magic_EXE_header);
+  if (::memcmp(buffer, &x, 2)) {
+    ASSERT(false, (L"Missing executable's magic number"));
+    return E_FAIL;
+  }
+
+  uint32 peheader = GetUint32LE(buffer + kPEHeaderOffset);
+  if (size < peheader + kPEHeaderSizeMin) {
+    ASSERT(false, (L"Too small given PE header size"));
+    return E_FAIL;
+  }
+
+  x = GetUint32LE(magic_PE_header);
+  if (::memcmp(buffer + peheader, &x, 4)) {
+    ASSERT(false, (L"Missing PE header magic number"));
+    return E_FAIL;
+  }
+
+  // Finally, read the checksum
+
+  *checksum = GetUint32LE(buffer + peheader + kPEHeaderChecksumOffset);
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/common/pe_utils.h b/common/pe_utils.h
index 389d81d..cc969c6 100644
--- a/common/pe_utils.h
+++ b/common/pe_utils.h
@@ -1,39 +1,39 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Utility functions related to PE files (executables)

-

-#ifndef OMAHA_COMMON_PE_UTILS_H_

-#define OMAHA_COMMON_PE_UTILS_H_

-

-#include <windows.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-HRESULT SetPEChecksum(const TCHAR *filename, uint32 checksum);

-

-HRESULT SetPEChecksumToBuffer(unsigned char *buffer,

-                              size_t size, uint32 checksum);

-

-HRESULT GetPEChecksum(const TCHAR *filename, uint32 * checksum);

-

-HRESULT GetPEChecksumFromBuffer(const unsigned char *buffer,

-                                size_t size,

-                                uint32 *checksum);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_PE_UTILS_H_

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Utility functions related to PE files (executables)
+
+#ifndef OMAHA_COMMON_PE_UTILS_H_
+#define OMAHA_COMMON_PE_UTILS_H_
+
+#include <windows.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+HRESULT SetPEChecksum(const TCHAR *filename, uint32 checksum);
+
+HRESULT SetPEChecksumToBuffer(unsigned char *buffer,
+                              size_t size, uint32 checksum);
+
+HRESULT GetPEChecksum(const TCHAR *filename, uint32 * checksum);
+
+HRESULT GetPEChecksumFromBuffer(const unsigned char *buffer,
+                                size_t size,
+                                uint32 *checksum);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_PE_UTILS_H_
diff --git a/common/pe_utils_unittest.cc b/common/pe_utils_unittest.cc
index 0002b09..4a14dca 100644
--- a/common/pe_utils_unittest.cc
+++ b/common/pe_utils_unittest.cc
@@ -1,87 +1,87 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Unittests for pe_utils

-

-

-#include "omaha/common/debug.h"

-#include "omaha/common/file.h"

-#include "omaha/common/pe_utils.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(PEUtilsTest, PEUtils) {

-  // Get some known directories

-  CString windows_dir;

-  CString temp_dir;

-  DWORD dw = ::GetEnvironmentVariable(L"SystemRoot",

-                                      CStrBuf(windows_dir, MAX_PATH), MAX_PATH);

-  ASSERT_TRUE(dw);

-  dw = ::GetEnvironmentVariable(L"TEMP", CStrBuf(temp_dir, MAX_PATH), MAX_PATH);

-  ASSERT_TRUE(dw);

-

-  // Get a known executable to play with

-  CString notepad(windows_dir + L"\\NOTEPAD.EXE");

-  ASSERT_TRUE(File::Exists(notepad));

-

-  CString temp_exe(temp_dir + L"\\pe_utils_test.exe");

-  if (File::Exists(temp_exe)) {

-    File::Remove(temp_exe);

-  }

-  ASSERT_FALSE(File::Exists(temp_exe));

-  ASSERT_SUCCEEDED(File::Copy(notepad, temp_exe, true));

-

-  // Stomp on its checksum and check the result

-  const unsigned int kChk1 = 0xFEE1BAD;

-  const unsigned int kChk2 = 0x600DF00D;

-

-  unsigned int checksum = 0;

-

-  // Test Get/SetPEChecksum

-  ASSERT_SUCCEEDED(SetPEChecksum(temp_exe, kChk1));

-  ASSERT_SUCCEEDED(GetPEChecksum(temp_exe, &checksum));

-  ASSERT_EQ(kChk1, checksum);

-

-  ASSERT_SUCCEEDED(SetPEChecksum(temp_exe, kChk2));

-  ASSERT_SUCCEEDED(GetPEChecksum(temp_exe, &checksum));

-  ASSERT_EQ(kChk2, checksum);

-

-  // Test GetPEChecksumFromBuffer/SetPEChecksumToBuffer

-  std::vector<byte> buffer;

-  ASSERT_SUCCEEDED(ReadEntireFile(temp_exe, 0, &buffer));

-

-  int buffer_data_len = buffer.size();

-  uchar *buffer_data = reinterpret_cast<uchar*>(&buffer.front());

-

-  ASSERT_SUCCEEDED(SetPEChecksumToBuffer(buffer_data, buffer_data_len, kChk1));

-  ASSERT_SUCCEEDED(GetPEChecksumFromBuffer(buffer_data,

-                                           buffer_data_len,

-                                           &checksum));

-  ASSERT_EQ(kChk1, checksum);

-

-  ASSERT_SUCCEEDED(SetPEChecksumToBuffer(buffer_data, buffer_data_len, kChk2));

-  ASSERT_SUCCEEDED(GetPEChecksumFromBuffer(buffer_data,

-                                           buffer_data_len,

-                                           &checksum));

-  ASSERT_EQ(kChk2, checksum);

-

-  // Clean up

-  ASSERT_SUCCEEDED(File::Remove(temp_exe));

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Unittests for pe_utils
+
+
+#include "omaha/common/debug.h"
+#include "omaha/common/file.h"
+#include "omaha/common/pe_utils.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(PEUtilsTest, PEUtils) {
+  // Get some known directories
+  CString windows_dir;
+  CString temp_dir;
+  DWORD dw = ::GetEnvironmentVariable(L"SystemRoot",
+                                      CStrBuf(windows_dir, MAX_PATH), MAX_PATH);
+  ASSERT_TRUE(dw);
+  dw = ::GetEnvironmentVariable(L"TEMP", CStrBuf(temp_dir, MAX_PATH), MAX_PATH);
+  ASSERT_TRUE(dw);
+
+  // Get a known executable to play with
+  CString notepad(windows_dir + L"\\NOTEPAD.EXE");
+  ASSERT_TRUE(File::Exists(notepad));
+
+  CString temp_exe(temp_dir + L"\\pe_utils_test.exe");
+  if (File::Exists(temp_exe)) {
+    File::Remove(temp_exe);
+  }
+  ASSERT_FALSE(File::Exists(temp_exe));
+  ASSERT_SUCCEEDED(File::Copy(notepad, temp_exe, true));
+
+  // Stomp on its checksum and check the result
+  const unsigned int kChk1 = 0xFEE1BAD;
+  const unsigned int kChk2 = 0x600DF00D;
+
+  unsigned int checksum = 0;
+
+  // Test Get/SetPEChecksum
+  ASSERT_SUCCEEDED(SetPEChecksum(temp_exe, kChk1));
+  ASSERT_SUCCEEDED(GetPEChecksum(temp_exe, &checksum));
+  ASSERT_EQ(kChk1, checksum);
+
+  ASSERT_SUCCEEDED(SetPEChecksum(temp_exe, kChk2));
+  ASSERT_SUCCEEDED(GetPEChecksum(temp_exe, &checksum));
+  ASSERT_EQ(kChk2, checksum);
+
+  // Test GetPEChecksumFromBuffer/SetPEChecksumToBuffer
+  std::vector<byte> buffer;
+  ASSERT_SUCCEEDED(ReadEntireFile(temp_exe, 0, &buffer));
+
+  int buffer_data_len = buffer.size();
+  uchar *buffer_data = reinterpret_cast<uchar*>(&buffer.front());
+
+  ASSERT_SUCCEEDED(SetPEChecksumToBuffer(buffer_data, buffer_data_len, kChk1));
+  ASSERT_SUCCEEDED(GetPEChecksumFromBuffer(buffer_data,
+                                           buffer_data_len,
+                                           &checksum));
+  ASSERT_EQ(kChk1, checksum);
+
+  ASSERT_SUCCEEDED(SetPEChecksumToBuffer(buffer_data, buffer_data_len, kChk2));
+  ASSERT_SUCCEEDED(GetPEChecksumFromBuffer(buffer_data,
+                                           buffer_data_len,
+                                           &checksum));
+  ASSERT_EQ(kChk2, checksum);
+
+  // Clean up
+  ASSERT_SUCCEEDED(File::Remove(temp_exe));
+}
+
+}  // namespace omaha
+
diff --git a/common/popup_menu.cc b/common/popup_menu.cc
index d2150da..7b9c00a 100644
--- a/common/popup_menu.cc
+++ b/common/popup_menu.cc
@@ -1,464 +1,464 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/popup_menu.h"

-

-#include <windows.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-// Hold owner draw data

-struct OwnerDrawData {

-  HFONT font;

-  CString text;

-  HICON icon;

-

-  OwnerDrawData(HFONT f, const TCHAR* t, HICON i) {

-    font = f;

-    text = t;

-    icon = i;

-  }

-};

-

-

-// Default constructor

-PopupMenu::PopupMenu()

-    : wnd_(NULL) {

-  reset(menu_, ::CreatePopupMenu());

-  ASSERT1(menu_);

-}

-

-// Constructor

-PopupMenu::PopupMenu(HINSTANCE inst, const TCHAR* name)

-    : wnd_(NULL) {

-  LoadFromResource(inst, name);

-  ASSERT1(menu_);

-}

-

-// Destructor

-PopupMenu::~PopupMenu() {

-}

-

-// Load from resource

-bool PopupMenu::LoadFromResource(HINSTANCE inst, const TCHAR* name) {

-  reset(menu_, GetSubMenu(reinterpret_cast<HMENU>(::LoadMenu(inst, name)), 0));

-  return get(menu_) != NULL;

-}

-

-// Append menu item

-bool PopupMenu::AppendMenuItem(int menu_item_id, const TCHAR* text) {

-  return AppendMenuItem(menu_item_id, text, NULL);

-}

-

-// Append menu item

-bool PopupMenu::AppendMenuItem(int menu_item_id,

-                               const TCHAR* text,

-                               const MenuItemDrawStyle* style) {

-  int count = ::GetMenuItemCount(get(menu_));

-  if (count == -1)

-    return false;

-

-  return InsertMenuItem(menu_item_id, count, true, text, style);

-}

-

-// Append separator

-bool PopupMenu::AppendSeparator() {

-  return AppendMenuItem(-1, NULL, NULL);

-}

-

-// Insert menu item

-bool PopupMenu::InsertMenuItem(int menu_item_id,

-                               int before_item,

-                               bool by_pos,

-                               const TCHAR* text) {

-  return InsertMenuItem(menu_item_id, before_item, by_pos, text, NULL);

-}

-

-// Helper function that populates the MENUITEMINFO structure and sets

-// accelerator keys for OWNERDRAW menu items

-MENUITEMINFO PopupMenu::PrepareMenuItemInfo(int menu_item_id, const TCHAR* text,

-                                            const MenuItemDrawStyle* style) {

-  // Fill in the MENUITEMINFO structure

-  MENUITEMINFO menuitem_info;

-  SetZero(menuitem_info);

-  menuitem_info.cbSize = sizeof(MENUITEMINFO);

-  menuitem_info.wID = menu_item_id;

-  if (text == NULL) {

-    menuitem_info.fMask = MIIM_FTYPE | MIIM_ID;

-    menuitem_info.fType = MFT_SEPARATOR;

-  } else {

-    if (!style) {

-      menuitem_info.fMask = MIIM_STRING | MIIM_ID;

-      menuitem_info.fType = MFT_STRING;

-      menuitem_info.dwTypeData = const_cast<TCHAR*>(text);

-    } else {

-      // Handle bold font style

-      HFONT font = NULL;

-      if (style->is_bold) {

-        font = GetBoldFont();

-      }

-

-      // Remove '&' if it is there

-      CString text_str(text);

-      int pos = String_FindChar(text_str, _T('&'));

-      if (pos != -1) {

-        if (pos + 1 < text_str.GetLength()) {

-          accelerator_keys_.Add(Char_ToLower(text_str[pos + 1]), menu_item_id);

-        }

-        ReplaceCString(text_str, _T("&"), _T(""));

-      }

-

-      // Set owner-draw related properties

-      OwnerDrawData* data = new OwnerDrawData(font, text_str, style->icon);

-      menuitem_info.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_ID;

-      menuitem_info.fType = MFT_OWNERDRAW;

-      menuitem_info.dwItemData = reinterpret_cast<ULONG_PTR>(data);

-    }

-  }

-

-  return menuitem_info;

-}

-

-// Insert menu item

-bool PopupMenu::InsertMenuItem(int menu_item_id,

-                               int before_item,

-                               bool by_pos,

-                               const TCHAR* text,

-                               const MenuItemDrawStyle* style) {

-  MENUITEMINFO menuitem_info = PrepareMenuItemInfo(menu_item_id, text, style);

-  if (!::InsertMenuItem(get(menu_), before_item, by_pos, &menuitem_info))

-    return false;

-

-  return Redraw();

-}

-

-// Insert separator

-bool PopupMenu::InsertSeparator(int before_item, bool by_pos) {

-  return InsertMenuItem(-1, before_item, by_pos, NULL, NULL);

-}

-

-// Modify a given menu item

-bool PopupMenu::ModifyMenuItem(int menu_item, bool by_pos, const TCHAR* text,

-                               const MenuItemDrawStyle* style) {

-  // Get OWNERDRAW data for later deletion

-  MENUITEMINFO menuitem_info;

-  SetZero(menuitem_info);

-  menuitem_info.cbSize = sizeof(MENUITEMINFO);

-  menuitem_info.fMask = MIIM_FTYPE | MIIM_DATA;

-  if (!::GetMenuItemInfo(get(menu_), menu_item, by_pos, &menuitem_info)) {

-    return false;

-  }

-

-  OwnerDrawData* old_owner_data = NULL;

-  if ((menuitem_info.fType | MFT_OWNERDRAW) && menuitem_info.dwItemData) {

-    old_owner_data =

-        reinterpret_cast<OwnerDrawData *>(menuitem_info.dwItemData);

-  }

-

-  // Remove old accelerator mapping

-  int menu_item_id = by_pos ? ::GetMenuItemID(get(menu_), menu_item) :

-                              menu_item;

-  int key_pos = accelerator_keys_.FindVal(menu_item_id);

-  if (key_pos != -1) {

-    accelerator_keys_.RemoveAt(key_pos);

-  }

-

-  // Set new menu item info

-  menuitem_info = PrepareMenuItemInfo(menu_item_id, text, style);

-  if (!::SetMenuItemInfo(get(menu_), menu_item, by_pos, &menuitem_info)) {

-    return false;

-  }

-

-  // Delete old owner draw data

-  if (old_owner_data) {

-    delete old_owner_data;

-  }

-

-  // Redraw

-  return Redraw();

-}

-

-// Remove a menu item

-bool PopupMenu::RemoveMenuItem(int menu_item, bool by_pos) {

-  // Get OWNERDRAW data for later deletion

-  MENUITEMINFO menuitem_info;

-  SetZero(menuitem_info);

-  menuitem_info.cbSize = sizeof(MENUITEMINFO);

-  menuitem_info.fMask = MIIM_FTYPE | MIIM_DATA;

-  if (!::GetMenuItemInfo(get(menu_), menu_item, by_pos, &menuitem_info)) {

-    return false;

-  }

-

-  OwnerDrawData* old_owner_data = NULL;

-  if ((menuitem_info.fType | MFT_OWNERDRAW) && menuitem_info.dwItemData) {

-    old_owner_data =

-        reinterpret_cast<OwnerDrawData *>(menuitem_info.dwItemData);

-  }

-

-  // Remove the menu item

-  if (!::RemoveMenu(get(menu_), menu_item, by_pos ? MF_BYPOSITION :

-                                                    MF_BYCOMMAND)) {

-    return false;

-  }

-

-  // Remove old accelerator mapping

-  int menu_item_id = by_pos ? ::GetMenuItemID(get(menu_), menu_item) :

-                              menu_item;

-  int key_pos = accelerator_keys_.FindVal(menu_item_id);

-  if (key_pos != -1) {

-    accelerator_keys_.RemoveAt(key_pos);

-  }

-

-  // Delete old owner draw data

-  if (old_owner_data) {

-    delete old_owner_data;

-  }

-

-  // Redraw

-  return Redraw();

-}

-

-// Enable menu item

-bool PopupMenu::EnableMenuItem(int menu_item, bool by_pos, bool enabled) {

-  if (::EnableMenuItem(get(menu_), menu_item,

-                        (by_pos ? MF_BYPOSITION : MF_BYCOMMAND) |

-                        (enabled ? MF_ENABLED : MF_GRAYED)) == -1)

-    return false;

-

-  return Redraw();

-}

-

-// Get menu state

-bool PopupMenu::GetMenuState(int menu_item, bool by_pos, int* menu_state) {

-  int state = ::GetMenuState(get(menu_),

-                             menu_item, by_pos ? MF_BYPOSITION : MF_BYCOMMAND);

-  if (menu_state)

-    *menu_state = state;

-  return state != -1;

-}

-

-// Exists a menu item

-bool PopupMenu::ExistsMenuItem(int menu_item_id) {

-  return GetMenuState(menu_item_id, false, NULL);

-}

-

-// Redraw menu

-bool PopupMenu::Redraw() {

-  if (!wnd_)

-    return true;

-

-  return ::DrawMenuBar(wnd_) == TRUE;

-}

-

-// Track menu

-bool PopupMenu::Track() {

-  ASSERT1(wnd_);

-

-  // If we don't set it to be foreground, it will not stop tracking even

-  // if we click outside of menu.

-  ::SetForegroundWindow(wnd_);

-

-  POINT point = {0, 0};

-  VERIFY(::GetCursorPos(&point), (_T("")));

-

-  uint32 kFlags = TPM_LEFTALIGN  |

-                  TPM_RETURNCMD  |

-                  TPM_NONOTIFY   |

-                  TPM_LEFTBUTTON |

-                  TPM_VERTICAL;

-  int command = ::TrackPopupMenuEx(get(menu_),

-                                   kFlags,

-                                   point.x, point.y, wnd_, NULL);

-

-  if (command != 0)

-    ::SendMessage(wnd_, WM_COMMAND, command, 0);

-

-  return true;

-}

-

-// Handle WM_MEASUREITEM message

-bool PopupMenu::OnMeasureItem(MEASUREITEMSTRUCT* mi) {

-  ASSERT1(wnd_);

-

-  // Get owner draw data

-  ASSERT1(mi->itemData);

-  OwnerDrawData* data = reinterpret_cast<OwnerDrawData*>(mi->itemData);

-

-  // Get the DC

-  scoped_hdc dc;

-  reset(dc, ::GetDC(wnd_));

-

-  // Select the font

-  HFONT old_font = reinterpret_cast<HFONT>(::SelectObject(get(dc), data->font));

-  if (!old_font)

-    return false;

-

-  // compute the size of the text

-  SIZE size = {0, 0};

-  bool success = ::GetTextExtentPoint32(get(dc),

-                                        data->text.GetString(),

-                                        data->text.GetLength(),

-                                        &size) != 0;

-  if (success) {

-    mi->itemWidth = size.cx;

-    mi->itemHeight = size.cy;

-  }

-

-  // deselect the title font

-  ::SelectObject(get(dc), old_font);

-

-  return success;

-}

-

-// Handle WM_MDRAWITEM message

-bool PopupMenu::OnDrawItem(DRAWITEMSTRUCT* di) {

-  ASSERT1(di);

-

-  // Get owner draw data

-  ASSERT1(di->itemData);

-  OwnerDrawData* data = reinterpret_cast<OwnerDrawData*>(di->itemData);

-

-  // Select the font

-  HFONT prev_font = NULL;

-  if (data->font) {

-    prev_font = reinterpret_cast<HFONT>(::SelectObject(di->hDC, data->font));

-    if (!prev_font) {

-      return false;

-    }

-  }

-

-  // Draw the text per the menuitem state

-  int fg_color_idx =

-      (di->itemState & ODS_DISABLED) ?

-      COLOR_GRAYTEXT :

-      ((di->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT);

-

-  int bg_color_idx =

-      (di->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHT : COLOR_MENU;

-

-  bool success = DrawText(data->text, di, fg_color_idx, bg_color_idx);

-

-  // Restore the original font

-  if (prev_font) {

-    ::SelectObject(di->hDC, prev_font);

-  }

-

-  // Compute the width and height

-  int height = di->rcItem.bottom - di->rcItem.top + 1;

-  int width = static_cast<int>(::GetSystemMetrics(SM_CXMENUCHECK) *

-    (static_cast<double>(height) / ::GetSystemMetrics(SM_CYMENUCHECK)));

-

-  // Draw the icon

-  // TODO(omaha): Draw a grayed icon when the menuitem is disabled

-  if (success && data->icon) {

-    success = ::DrawIconEx(di->hDC,

-                           di->rcItem.left,

-                           di->rcItem.top,

-                           data->icon,

-                           width,

-                           height,

-                           0,

-                           NULL,

-                           DI_NORMAL) != 0;

-  }

-

-  return success;

-}

-

-// Draw the text

-bool PopupMenu::DrawText(const CString& text,

-                         DRAWITEMSTRUCT* di,

-                         int fg_color_idx,

-                         int bg_color_idx) {

-  // Set the appropriate foreground and background colors

-  COLORREF prev_fg_color = 0, prev_bg_color = 0;

-  prev_fg_color = ::SetTextColor(di->hDC, ::GetSysColor(fg_color_idx));

-  if (prev_fg_color == CLR_INVALID) {

-    return false;

-  }

-  prev_bg_color = ::SetBkColor(di->hDC, ::GetSysColor(bg_color_idx));

-  if (prev_bg_color == CLR_INVALID) {

-    return false;

-  }

-

-  // Draw the text

-  bool success = ::ExtTextOut(

-      di->hDC,

-      di->rcItem.left + ::GetSystemMetrics(SM_CXMENUCHECK) + 4,

-      di->rcItem.top,

-      ETO_OPAQUE,

-      &di->rcItem,

-      text.GetString(),

-      text.GetLength(),

-      NULL) == TRUE;

-

-  // Restore the original colors

-  ::SetTextColor(di->hDC, prev_fg_color);

-  ::SetBkColor(di->hDC, prev_bg_color);

-

-  return success;

-}

-

-// Handle WM_MENUCHAR message

-int PopupMenu::OnMenuChar(TCHAR key) {

-  int pos = accelerator_keys_.FindKey(Char_ToLower(key));

-  if (pos != -1)

-    return GetMenuPosFromID(accelerator_keys_.GetValueAt(pos));

-  else

-    return -1;

-}

-

-HFONT PopupMenu::GetBoldFont() {

-  if (!bold_font_) {

-    NONCLIENTMETRICS ncm;

-    SetZero(ncm);

-    ncm.cbSize = sizeof(NONCLIENTMETRICS);

-    if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) {

-      ncm.lfMenuFont.lfWeight = FW_BOLD;

-      reset(bold_font_, ::CreateFontIndirect(&ncm.lfMenuFont));

-    } else {

-      UTIL_LOG(LEVEL_ERROR, (_T("[PopupMenu::GetBoldFont]")

-                             _T("[failed to get system menu font][0x%x]"),

-                             HRESULTFromLastError()));

-    }

-  }

-

-  ASSERT1(bold_font_);

-

-  return get(bold_font_);

-}

-

-// Get menu pos from ID

-int PopupMenu::GetMenuPosFromID(int id) {

-  ASSERT1(id >= 0);

-  int count = ::GetMenuItemCount(get(menu_));

-  if (count > 0) {

-    for (int pos = 0; pos < count; ++pos) {

-      if (::GetMenuItemID(get(menu_), pos) == static_cast<UINT>(id)) {

-        return pos;

-      }

-    }

-  }

-

-  return -1;

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/popup_menu.h"
+
+#include <windows.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+// Hold owner draw data
+struct OwnerDrawData {
+  HFONT font;
+  CString text;
+  HICON icon;
+
+  OwnerDrawData(HFONT f, const TCHAR* t, HICON i) {
+    font = f;
+    text = t;
+    icon = i;
+  }
+};
+
+
+// Default constructor
+PopupMenu::PopupMenu()
+    : wnd_(NULL) {
+  reset(menu_, ::CreatePopupMenu());
+  ASSERT1(menu_);
+}
+
+// Constructor
+PopupMenu::PopupMenu(HINSTANCE inst, const TCHAR* name)
+    : wnd_(NULL) {
+  LoadFromResource(inst, name);
+  ASSERT1(menu_);
+}
+
+// Destructor
+PopupMenu::~PopupMenu() {
+}
+
+// Load from resource
+bool PopupMenu::LoadFromResource(HINSTANCE inst, const TCHAR* name) {
+  reset(menu_, GetSubMenu(reinterpret_cast<HMENU>(::LoadMenu(inst, name)), 0));
+  return get(menu_) != NULL;
+}
+
+// Append menu item
+bool PopupMenu::AppendMenuItem(int menu_item_id, const TCHAR* text) {
+  return AppendMenuItem(menu_item_id, text, NULL);
+}
+
+// Append menu item
+bool PopupMenu::AppendMenuItem(int menu_item_id,
+                               const TCHAR* text,
+                               const MenuItemDrawStyle* style) {
+  int count = ::GetMenuItemCount(get(menu_));
+  if (count == -1)
+    return false;
+
+  return InsertMenuItem(menu_item_id, count, true, text, style);
+}
+
+// Append separator
+bool PopupMenu::AppendSeparator() {
+  return AppendMenuItem(-1, NULL, NULL);
+}
+
+// Insert menu item
+bool PopupMenu::InsertMenuItem(int menu_item_id,
+                               int before_item,
+                               bool by_pos,
+                               const TCHAR* text) {
+  return InsertMenuItem(menu_item_id, before_item, by_pos, text, NULL);
+}
+
+// Helper function that populates the MENUITEMINFO structure and sets
+// accelerator keys for OWNERDRAW menu items
+MENUITEMINFO PopupMenu::PrepareMenuItemInfo(int menu_item_id, const TCHAR* text,
+                                            const MenuItemDrawStyle* style) {
+  // Fill in the MENUITEMINFO structure
+  MENUITEMINFO menuitem_info;
+  SetZero(menuitem_info);
+  menuitem_info.cbSize = sizeof(MENUITEMINFO);
+  menuitem_info.wID = menu_item_id;
+  if (text == NULL) {
+    menuitem_info.fMask = MIIM_FTYPE | MIIM_ID;
+    menuitem_info.fType = MFT_SEPARATOR;
+  } else {
+    if (!style) {
+      menuitem_info.fMask = MIIM_STRING | MIIM_ID;
+      menuitem_info.fType = MFT_STRING;
+      menuitem_info.dwTypeData = const_cast<TCHAR*>(text);
+    } else {
+      // Handle bold font style
+      HFONT font = NULL;
+      if (style->is_bold) {
+        font = GetBoldFont();
+      }
+
+      // Remove '&' if it is there
+      CString text_str(text);
+      int pos = String_FindChar(text_str, _T('&'));
+      if (pos != -1) {
+        if (pos + 1 < text_str.GetLength()) {
+          accelerator_keys_.Add(Char_ToLower(text_str[pos + 1]), menu_item_id);
+        }
+        ReplaceCString(text_str, _T("&"), _T(""));
+      }
+
+      // Set owner-draw related properties
+      OwnerDrawData* data = new OwnerDrawData(font, text_str, style->icon);
+      menuitem_info.fMask = MIIM_FTYPE | MIIM_DATA | MIIM_ID;
+      menuitem_info.fType = MFT_OWNERDRAW;
+      menuitem_info.dwItemData = reinterpret_cast<ULONG_PTR>(data);
+    }
+  }
+
+  return menuitem_info;
+}
+
+// Insert menu item
+bool PopupMenu::InsertMenuItem(int menu_item_id,
+                               int before_item,
+                               bool by_pos,
+                               const TCHAR* text,
+                               const MenuItemDrawStyle* style) {
+  MENUITEMINFO menuitem_info = PrepareMenuItemInfo(menu_item_id, text, style);
+  if (!::InsertMenuItem(get(menu_), before_item, by_pos, &menuitem_info))
+    return false;
+
+  return Redraw();
+}
+
+// Insert separator
+bool PopupMenu::InsertSeparator(int before_item, bool by_pos) {
+  return InsertMenuItem(-1, before_item, by_pos, NULL, NULL);
+}
+
+// Modify a given menu item
+bool PopupMenu::ModifyMenuItem(int menu_item, bool by_pos, const TCHAR* text,
+                               const MenuItemDrawStyle* style) {
+  // Get OWNERDRAW data for later deletion
+  MENUITEMINFO menuitem_info;
+  SetZero(menuitem_info);
+  menuitem_info.cbSize = sizeof(MENUITEMINFO);
+  menuitem_info.fMask = MIIM_FTYPE | MIIM_DATA;
+  if (!::GetMenuItemInfo(get(menu_), menu_item, by_pos, &menuitem_info)) {
+    return false;
+  }
+
+  OwnerDrawData* old_owner_data = NULL;
+  if ((menuitem_info.fType | MFT_OWNERDRAW) && menuitem_info.dwItemData) {
+    old_owner_data =
+        reinterpret_cast<OwnerDrawData *>(menuitem_info.dwItemData);
+  }
+
+  // Remove old accelerator mapping
+  int menu_item_id = by_pos ? ::GetMenuItemID(get(menu_), menu_item) :
+                              menu_item;
+  int key_pos = accelerator_keys_.FindVal(menu_item_id);
+  if (key_pos != -1) {
+    accelerator_keys_.RemoveAt(key_pos);
+  }
+
+  // Set new menu item info
+  menuitem_info = PrepareMenuItemInfo(menu_item_id, text, style);
+  if (!::SetMenuItemInfo(get(menu_), menu_item, by_pos, &menuitem_info)) {
+    return false;
+  }
+
+  // Delete old owner draw data
+  if (old_owner_data) {
+    delete old_owner_data;
+  }
+
+  // Redraw
+  return Redraw();
+}
+
+// Remove a menu item
+bool PopupMenu::RemoveMenuItem(int menu_item, bool by_pos) {
+  // Get OWNERDRAW data for later deletion
+  MENUITEMINFO menuitem_info;
+  SetZero(menuitem_info);
+  menuitem_info.cbSize = sizeof(MENUITEMINFO);
+  menuitem_info.fMask = MIIM_FTYPE | MIIM_DATA;
+  if (!::GetMenuItemInfo(get(menu_), menu_item, by_pos, &menuitem_info)) {
+    return false;
+  }
+
+  OwnerDrawData* old_owner_data = NULL;
+  if ((menuitem_info.fType | MFT_OWNERDRAW) && menuitem_info.dwItemData) {
+    old_owner_data =
+        reinterpret_cast<OwnerDrawData *>(menuitem_info.dwItemData);
+  }
+
+  // Remove the menu item
+  if (!::RemoveMenu(get(menu_), menu_item, by_pos ? MF_BYPOSITION :
+                                                    MF_BYCOMMAND)) {
+    return false;
+  }
+
+  // Remove old accelerator mapping
+  int menu_item_id = by_pos ? ::GetMenuItemID(get(menu_), menu_item) :
+                              menu_item;
+  int key_pos = accelerator_keys_.FindVal(menu_item_id);
+  if (key_pos != -1) {
+    accelerator_keys_.RemoveAt(key_pos);
+  }
+
+  // Delete old owner draw data
+  if (old_owner_data) {
+    delete old_owner_data;
+  }
+
+  // Redraw
+  return Redraw();
+}
+
+// Enable menu item
+bool PopupMenu::EnableMenuItem(int menu_item, bool by_pos, bool enabled) {
+  if (::EnableMenuItem(get(menu_), menu_item,
+                        (by_pos ? MF_BYPOSITION : MF_BYCOMMAND) |
+                        (enabled ? MF_ENABLED : MF_GRAYED)) == -1)
+    return false;
+
+  return Redraw();
+}
+
+// Get menu state
+bool PopupMenu::GetMenuState(int menu_item, bool by_pos, int* menu_state) {
+  int state = ::GetMenuState(get(menu_),
+                             menu_item, by_pos ? MF_BYPOSITION : MF_BYCOMMAND);
+  if (menu_state)
+    *menu_state = state;
+  return state != -1;
+}
+
+// Exists a menu item
+bool PopupMenu::ExistsMenuItem(int menu_item_id) {
+  return GetMenuState(menu_item_id, false, NULL);
+}
+
+// Redraw menu
+bool PopupMenu::Redraw() {
+  if (!wnd_)
+    return true;
+
+  return ::DrawMenuBar(wnd_) == TRUE;
+}
+
+// Track menu
+bool PopupMenu::Track() {
+  ASSERT1(wnd_);
+
+  // If we don't set it to be foreground, it will not stop tracking even
+  // if we click outside of menu.
+  ::SetForegroundWindow(wnd_);
+
+  POINT point = {0, 0};
+  VERIFY(::GetCursorPos(&point), (_T("")));
+
+  uint32 kFlags = TPM_LEFTALIGN  |
+                  TPM_RETURNCMD  |
+                  TPM_NONOTIFY   |
+                  TPM_LEFTBUTTON |
+                  TPM_VERTICAL;
+  int command = ::TrackPopupMenuEx(get(menu_),
+                                   kFlags,
+                                   point.x, point.y, wnd_, NULL);
+
+  if (command != 0)
+    ::SendMessage(wnd_, WM_COMMAND, command, 0);
+
+  return true;
+}
+
+// Handle WM_MEASUREITEM message
+bool PopupMenu::OnMeasureItem(MEASUREITEMSTRUCT* mi) {
+  ASSERT1(wnd_);
+
+  // Get owner draw data
+  ASSERT1(mi->itemData);
+  OwnerDrawData* data = reinterpret_cast<OwnerDrawData*>(mi->itemData);
+
+  // Get the DC
+  scoped_hdc dc;
+  reset(dc, ::GetDC(wnd_));
+
+  // Select the font
+  HFONT old_font = reinterpret_cast<HFONT>(::SelectObject(get(dc), data->font));
+  if (!old_font)
+    return false;
+
+  // compute the size of the text
+  SIZE size = {0, 0};
+  bool success = ::GetTextExtentPoint32(get(dc),
+                                        data->text.GetString(),
+                                        data->text.GetLength(),
+                                        &size) != 0;
+  if (success) {
+    mi->itemWidth = size.cx;
+    mi->itemHeight = size.cy;
+  }
+
+  // deselect the title font
+  ::SelectObject(get(dc), old_font);
+
+  return success;
+}
+
+// Handle WM_MDRAWITEM message
+bool PopupMenu::OnDrawItem(DRAWITEMSTRUCT* di) {
+  ASSERT1(di);
+
+  // Get owner draw data
+  ASSERT1(di->itemData);
+  OwnerDrawData* data = reinterpret_cast<OwnerDrawData*>(di->itemData);
+
+  // Select the font
+  HFONT prev_font = NULL;
+  if (data->font) {
+    prev_font = reinterpret_cast<HFONT>(::SelectObject(di->hDC, data->font));
+    if (!prev_font) {
+      return false;
+    }
+  }
+
+  // Draw the text per the menuitem state
+  int fg_color_idx =
+      (di->itemState & ODS_DISABLED) ?
+      COLOR_GRAYTEXT :
+      ((di->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT);
+
+  int bg_color_idx =
+      (di->itemState & ODS_SELECTED) ? COLOR_HIGHLIGHT : COLOR_MENU;
+
+  bool success = DrawText(data->text, di, fg_color_idx, bg_color_idx);
+
+  // Restore the original font
+  if (prev_font) {
+    ::SelectObject(di->hDC, prev_font);
+  }
+
+  // Compute the width and height
+  int height = di->rcItem.bottom - di->rcItem.top + 1;
+  int width = static_cast<int>(::GetSystemMetrics(SM_CXMENUCHECK) *
+    (static_cast<double>(height) / ::GetSystemMetrics(SM_CYMENUCHECK)));
+
+  // Draw the icon
+  // TODO(omaha): Draw a grayed icon when the menuitem is disabled
+  if (success && data->icon) {
+    success = ::DrawIconEx(di->hDC,
+                           di->rcItem.left,
+                           di->rcItem.top,
+                           data->icon,
+                           width,
+                           height,
+                           0,
+                           NULL,
+                           DI_NORMAL) != 0;
+  }
+
+  return success;
+}
+
+// Draw the text
+bool PopupMenu::DrawText(const CString& text,
+                         DRAWITEMSTRUCT* di,
+                         int fg_color_idx,
+                         int bg_color_idx) {
+  // Set the appropriate foreground and background colors
+  COLORREF prev_fg_color = 0, prev_bg_color = 0;
+  prev_fg_color = ::SetTextColor(di->hDC, ::GetSysColor(fg_color_idx));
+  if (prev_fg_color == CLR_INVALID) {
+    return false;
+  }
+  prev_bg_color = ::SetBkColor(di->hDC, ::GetSysColor(bg_color_idx));
+  if (prev_bg_color == CLR_INVALID) {
+    return false;
+  }
+
+  // Draw the text
+  bool success = ::ExtTextOut(
+      di->hDC,
+      di->rcItem.left + ::GetSystemMetrics(SM_CXMENUCHECK) + 4,
+      di->rcItem.top,
+      ETO_OPAQUE,
+      &di->rcItem,
+      text.GetString(),
+      text.GetLength(),
+      NULL) == TRUE;
+
+  // Restore the original colors
+  ::SetTextColor(di->hDC, prev_fg_color);
+  ::SetBkColor(di->hDC, prev_bg_color);
+
+  return success;
+}
+
+// Handle WM_MENUCHAR message
+int PopupMenu::OnMenuChar(TCHAR key) {
+  int pos = accelerator_keys_.FindKey(Char_ToLower(key));
+  if (pos != -1)
+    return GetMenuPosFromID(accelerator_keys_.GetValueAt(pos));
+  else
+    return -1;
+}
+
+HFONT PopupMenu::GetBoldFont() {
+  if (!bold_font_) {
+    NONCLIENTMETRICS ncm;
+    SetZero(ncm);
+    ncm.cbSize = sizeof(NONCLIENTMETRICS);
+    if (::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) {
+      ncm.lfMenuFont.lfWeight = FW_BOLD;
+      reset(bold_font_, ::CreateFontIndirect(&ncm.lfMenuFont));
+    } else {
+      UTIL_LOG(LEVEL_ERROR, (_T("[PopupMenu::GetBoldFont]")
+                             _T("[failed to get system menu font][0x%x]"),
+                             HRESULTFromLastError()));
+    }
+  }
+
+  ASSERT1(bold_font_);
+
+  return get(bold_font_);
+}
+
+// Get menu pos from ID
+int PopupMenu::GetMenuPosFromID(int id) {
+  ASSERT1(id >= 0);
+  int count = ::GetMenuItemCount(get(menu_));
+  if (count > 0) {
+    for (int pos = 0; pos < count; ++pos) {
+      if (::GetMenuItemID(get(menu_), pos) == static_cast<UINT>(id)) {
+        return pos;
+      }
+    }
+  }
+
+  return -1;
+}
+
+}  // namespace omaha
+
diff --git a/common/popup_menu.h b/common/popup_menu.h
index 5544977..74c40c3 100644
--- a/common/popup_menu.h
+++ b/common/popup_menu.h
@@ -1,139 +1,139 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef  OMAHA_COMMON_POPUP_MENU_H_

-#define  OMAHA_COMMON_POPUP_MENU_H_

-

-#include "omaha/common/debug.h"

-#include "omaha/common/scoped_any.h"

-

-namespace omaha {

-

-struct MenuItemDrawStyle {

-  bool is_bold;

-  HICON icon;

-

-  MenuItemDrawStyle() : is_bold(false), icon(NULL) {}

-};

-

-

-class PopupMenu {

- public:

-  PopupMenu();

-  PopupMenu(HINSTANCE inst, const TCHAR* name);

-

-  ~PopupMenu();

-

-  // Load from resource

-  bool LoadFromResource(HINSTANCE inst, const TCHAR* name);

-

-  // Append menu item

-  bool AppendMenuItem(int menu_item_id, const TCHAR* text);

-  bool AppendMenuItem(int menu_item_id,

-                      const TCHAR* text,

-                      const MenuItemDrawStyle* style);

-

-  // Append separator

-  bool AppendSeparator();

-

-  // Helper function that populates the MENUITEMINFO structure and sets

-  // accelerator keys for OWNERDRAW menu items

-  MENUITEMINFO PrepareMenuItemInfo(int menu_item_id,

-                                   const TCHAR* text,

-                                   const MenuItemDrawStyle* style);

-

-  // Insert menu item

-  bool InsertMenuItem(int menu_item_id,

-                      int before_item,

-                      bool by_pos,

-                      const TCHAR* text);

-

-  bool InsertMenuItem(int menu_item_id,

-                      int before_item,

-                      bool by_pos,

-                      const TCHAR* text,

-                      const MenuItemDrawStyle* style);

-

-  // Insert separator

-  bool InsertSeparator(int before_item, bool by_pos);

-

-  // Modify a given menu item

-  bool ModifyMenuItem(int menu_item,

-                      bool by_pos,

-                      const TCHAR* text,

-                      const MenuItemDrawStyle* style);

-

-  // Remove menu item

-  bool RemoveMenuItem(int menu_item, bool by_pos);

-

-  // Enable menu item

-  bool EnableMenuItem(int menu_item, bool by_pos, bool enabled);

-

-  // Get menu state

-  bool GetMenuState(int menu_item, bool by_pos, int* menu_state);

-

-  // Exists a menu item

-  bool ExistsMenuItem(int menu_item_id);

-

-  // Get menu pos from ID

-  int GetMenuPosFromID(int id);

-

-  // Attach to the window

-  void AttachToWindow(HWND wnd) {

-    ASSERT1(wnd);

-    wnd_ = wnd;

-  }

-

-  // Redraw menu

-  bool Redraw();

-

-  // Track menu

-  bool Track();

-

-  // Handle WM_MEASUREITEM message

-  bool OnMeasureItem(MEASUREITEMSTRUCT* mi);

-

-  // Handle WM_MDRAWITEM message

-  bool OnDrawItem(DRAWITEMSTRUCT* di);

-

-  // Handle WM_MENUCHAR message

-  int OnMenuChar(TCHAR key);

-

- private:

-  // Get bold font

-  HFONT GetBoldFont();

-

-  // Draw the text

-  bool DrawText(const CString& text,

-                DRAWITEMSTRUCT* di,

-                int fg_color_idx,

-                int bg_color_idx);

-

-  HWND wnd_;           // HWND associated with this menu

-  scoped_hmenu menu_;  // HMENU associated with this menu

-

-  // Bold font used in owner draw menu-item

-  scoped_hfont bold_font_;

-

-  // Accelerator key used in owner draw menu-item

-  CSimpleMap<TCHAR, int> accelerator_keys_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(PopupMenu);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_POPUP_MENU_H_

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef  OMAHA_COMMON_POPUP_MENU_H_
+#define  OMAHA_COMMON_POPUP_MENU_H_
+
+#include "omaha/common/debug.h"
+#include "omaha/common/scoped_any.h"
+
+namespace omaha {
+
+struct MenuItemDrawStyle {
+  bool is_bold;
+  HICON icon;
+
+  MenuItemDrawStyle() : is_bold(false), icon(NULL) {}
+};
+
+
+class PopupMenu {
+ public:
+  PopupMenu();
+  PopupMenu(HINSTANCE inst, const TCHAR* name);
+
+  ~PopupMenu();
+
+  // Load from resource
+  bool LoadFromResource(HINSTANCE inst, const TCHAR* name);
+
+  // Append menu item
+  bool AppendMenuItem(int menu_item_id, const TCHAR* text);
+  bool AppendMenuItem(int menu_item_id,
+                      const TCHAR* text,
+                      const MenuItemDrawStyle* style);
+
+  // Append separator
+  bool AppendSeparator();
+
+  // Helper function that populates the MENUITEMINFO structure and sets
+  // accelerator keys for OWNERDRAW menu items
+  MENUITEMINFO PrepareMenuItemInfo(int menu_item_id,
+                                   const TCHAR* text,
+                                   const MenuItemDrawStyle* style);
+
+  // Insert menu item
+  bool InsertMenuItem(int menu_item_id,
+                      int before_item,
+                      bool by_pos,
+                      const TCHAR* text);
+
+  bool InsertMenuItem(int menu_item_id,
+                      int before_item,
+                      bool by_pos,
+                      const TCHAR* text,
+                      const MenuItemDrawStyle* style);
+
+  // Insert separator
+  bool InsertSeparator(int before_item, bool by_pos);
+
+  // Modify a given menu item
+  bool ModifyMenuItem(int menu_item,
+                      bool by_pos,
+                      const TCHAR* text,
+                      const MenuItemDrawStyle* style);
+
+  // Remove menu item
+  bool RemoveMenuItem(int menu_item, bool by_pos);
+
+  // Enable menu item
+  bool EnableMenuItem(int menu_item, bool by_pos, bool enabled);
+
+  // Get menu state
+  bool GetMenuState(int menu_item, bool by_pos, int* menu_state);
+
+  // Exists a menu item
+  bool ExistsMenuItem(int menu_item_id);
+
+  // Get menu pos from ID
+  int GetMenuPosFromID(int id);
+
+  // Attach to the window
+  void AttachToWindow(HWND wnd) {
+    ASSERT1(wnd);
+    wnd_ = wnd;
+  }
+
+  // Redraw menu
+  bool Redraw();
+
+  // Track menu
+  bool Track();
+
+  // Handle WM_MEASUREITEM message
+  bool OnMeasureItem(MEASUREITEMSTRUCT* mi);
+
+  // Handle WM_MDRAWITEM message
+  bool OnDrawItem(DRAWITEMSTRUCT* di);
+
+  // Handle WM_MENUCHAR message
+  int OnMenuChar(TCHAR key);
+
+ private:
+  // Get bold font
+  HFONT GetBoldFont();
+
+  // Draw the text
+  bool DrawText(const CString& text,
+                DRAWITEMSTRUCT* di,
+                int fg_color_idx,
+                int bg_color_idx);
+
+  HWND wnd_;           // HWND associated with this menu
+  scoped_hmenu menu_;  // HMENU associated with this menu
+
+  // Bold font used in owner draw menu-item
+  scoped_hfont bold_font_;
+
+  // Accelerator key used in owner draw menu-item
+  CSimpleMap<TCHAR, int> accelerator_keys_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(PopupMenu);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_POPUP_MENU_H_
+
diff --git a/common/preprocessor_fun.h b/common/preprocessor_fun.h
index 8d78fba..c2f6c12 100644
--- a/common/preprocessor_fun.h
+++ b/common/preprocessor_fun.h
@@ -1,36 +1,36 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// PP_STRINGIZE - expands arguments before stringizing

-// PP_STRINGIZE(PP_CAT(a,b)) => "ab"

-

-#define PP_STRINGIZE(text)   PP_STRINGIZE_A((text))

-#define PP_STRINGIZE_A(arg)  PP_STRINGIZE_B ## (arg)

-#define PP_STRINGIZE_B(arg)  PP_STRINGIZE_I ## arg

-#define PP_STRINGIZE_I(text) #text

-

-// T_PP_STRINGIZE - expands arguments before stringizing

-// T_PP_STRINGIZE(PP_CAT(a,b)) => _T("ab")

-

-#define T_PP_STRINGIZE(text)   T_PP_STRINGIZE_A((text))

-#define T_PP_STRINGIZE_A(arg)  T_PP_STRINGIZE_B ## (arg)

-#define T_PP_STRINGIZE_B(arg)  T_PP_STRINGIZE_I ## arg

-#define T_PP_STRINGIZE_I(text) _T(#text)

-

-// PP_CAT - concatenates arguments after they have been expanded

-// PP_CAT(x, PP_CAT(y,z)) => xyz

-#define PP_CAT(a,b)   PP_CAT_I(a,b)

-#define PP_CAT_I(a,b) PP_CAT_J(a##b)

-#define PP_CAT_J(arg) arg

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// PP_STRINGIZE - expands arguments before stringizing
+// PP_STRINGIZE(PP_CAT(a,b)) => "ab"
+
+#define PP_STRINGIZE(text)   PP_STRINGIZE_A((text))
+#define PP_STRINGIZE_A(arg)  PP_STRINGIZE_B ## (arg)
+#define PP_STRINGIZE_B(arg)  PP_STRINGIZE_I ## arg
+#define PP_STRINGIZE_I(text) #text
+
+// T_PP_STRINGIZE - expands arguments before stringizing
+// T_PP_STRINGIZE(PP_CAT(a,b)) => _T("ab")
+
+#define T_PP_STRINGIZE(text)   T_PP_STRINGIZE_A((text))
+#define T_PP_STRINGIZE_A(arg)  T_PP_STRINGIZE_B ## (arg)
+#define T_PP_STRINGIZE_B(arg)  T_PP_STRINGIZE_I ## arg
+#define T_PP_STRINGIZE_I(text) _T(#text)
+
+// PP_CAT - concatenates arguments after they have been expanded
+// PP_CAT(x, PP_CAT(y,z)) => xyz
+#define PP_CAT(a,b)   PP_CAT_I(a,b)
+#define PP_CAT_I(a,b) PP_CAT_J(a##b)
+#define PP_CAT_J(arg) arg
diff --git a/common/proc_utils.cc b/common/proc_utils.cc
index 8d48efd..f362c33 100644
--- a/common/proc_utils.cc
+++ b/common/proc_utils.cc
@@ -1,463 +1,463 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// proc_utils.cpp

-//

-// Useful functions that relate to process/thread manipulation/information

-// (Originally moved from utils.cpp)

-

-#include "omaha/common/proc_utils.h"

-

-#include <psapi.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_config.h"

-#include "omaha/common/const_timeouts.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/process.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/window_utils.h"

-

-namespace omaha {

-

-ProcessTerminator::ProcessTerminator(const CString& process_name)

-    : recursion_level_(0),

-      process_name_(process_name),

-      flash_window_(false),

-      session_id_(INVALID_SESSION_ID) {

-  MakeLowerCString(process_name_);

-}

-

-ProcessTerminator::ProcessTerminator(const CString& process_name,

-                                     const CString& user_sid)

-    : recursion_level_(0),

-      user_sid_(user_sid),

-      process_name_(process_name),

-      flash_window_(false),

-      session_id_(INVALID_SESSION_ID) {

-  MakeLowerCString(process_name_);

-}

-

-ProcessTerminator::ProcessTerminator(const CString& process_name,

-                                     const CString& user_sid,

-                                     int session_id)

-    : recursion_level_(0),

-      user_sid_(user_sid),

-      session_id_(session_id),

-      process_name_(process_name),

-      flash_window_(false) {

-  MakeLowerCString(process_name_);

-}

-

-ProcessTerminator::~ProcessTerminator() {

-  CloseAllHandles();

-}

-

-// Will close all currently opened handles.

-void ProcessTerminator::CloseAllHandles() {

-  UTIL_LOG(L3, (_T("[CloseAllHandles]")));

-  // Do clean up if we have opened handles.

-  for (size_t i = 0; i < process_handles_.size(); i++) {

-    VERIFY1(::CloseHandle(process_handles_[i]));

-  }

-

-  process_handles_.clear();

-}

-

-// Wait for a while till all process instances will die.

-bool ProcessTerminator::WaitForProcessInstancesToDie(

-    uint32 timeout_msec) const {

-  UTIL_LOG(L3, (_T("[WaitForProcessInstancesToDie]")));

-  size_t size = process_handles_.size();

-  scoped_array<HANDLE> handles(new HANDLE[size]);

-

-  for (size_t i = 0; i < size; i++) {

-    handles[i] = process_handles_[i];

-  }

-

-  DWORD wait_result = ::WaitForMultipleObjectsEx(size,

-                                                 handles.get(),

-                                                 true,

-                                                 timeout_msec,

-                                                 false);

-#pragma warning(disable : 4296)

-// C4296: '>=' : expression is always true

-  if ((wait_result >= WAIT_OBJECT_0) &&

-      (wait_result < WAIT_OBJECT_0 + size)) {

-    return true;

-  }

-#pragma warning(default : 4296)

-

-  UTIL_LOG(L3, (_T("WaitForProcessToDie timed out for '%s'. Waited for %d ms."),

-                process_name_, timeout_msec));

-  return false;

-}

-

-// Finds all process ids for the process of a given name.

-bool ProcessTerminator::FindProcessInstances() {

-  UTIL_LOG(L3, (_T("[FindProcessInstances]")));

-

-  DWORD exclude_mask = EXCLUDE_CURRENT_PROCESS;

-  if (!user_sid_.IsEmpty()) {

-    exclude_mask |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER;

-  }

-

-  std::vector<CString> command_lines;

-  HRESULT hr = S_OK;

-  if (session_id_ != INVALID_SESSION_ID) {

-    hr = Process::FindProcessesInSession(session_id_,

-                                         exclude_mask,

-                                         process_name_,

-                                         true,

-                                         user_sid_,

-                                         command_lines,

-                                         &process_ids_);

-  } else {

-    hr = Process::FindProcesses(exclude_mask,

-                                process_name_,

-                                true,

-                                user_sid_,

-                                command_lines,

-                                &process_ids_);

-  }

-

-  return SUCCEEDED(hr) && !process_ids_.empty();

-}

-

-// Tries to kill all instances of the process that was specified in the

-// constructor.

-// 'method_mask' determines which technique to attempt.

-// 'was_found' is optional and can be NULL.

-// Returns S_OK if all instances were killed, S_FALSE if process wasn't running,

-// and E_FAIL if one or more instances weren't killed.

-// Always sets 'was_found' correctly, regardless of return value.

-HRESULT ProcessTerminator::KillTheProcess(uint32 timeout_msec,

-                                          bool* was_found,

-                                          uint32 method_mask,

-                                          bool flash_window) {

-  UTIL_LOG(L3, (_T("[KillTheProcess]")));

-  if (!FindProcessInstances()) {

-    if (was_found != NULL) {

-      *was_found = false;

-    }

-    return S_FALSE;  // process is not running, so don't return a FAILED hr

-  }

-

-  // If got here, found at least one process to kill

-  if (was_found != NULL) {

-    *was_found = true;

-  }

-

-  flash_window_ = flash_window;

-  // Try the nicest, cleanest method of closing a process: window messages

-  if (method_mask & KILL_METHOD_1_WINDOW_MESSAGE) {

-    if (PrepareToKill(KILL_METHOD_1_WINDOW_MESSAGE)) {

-      KillProcessViaWndMessages(timeout_msec);

-    }

-

-    // Are any instances of the process still running?

-    if (!FindProcessInstances()) {

-      return S_OK;  // killed them all

-    }

-  }

-

-  // Also nice method

-  if (method_mask & KILL_METHOD_2_THREAD_MESSAGE) {

-    if (PrepareToKill(KILL_METHOD_2_THREAD_MESSAGE)) {

-      KillProcessViaThreadMessages(timeout_msec);

-    }

-    // Are any instances of the process still running?

-    if (!FindProcessInstances()) {

-      return S_OK;  // killed them all

-    }

-  }

-

-  // the crude one.

-  if (method_mask & KILL_METHOD_4_TERMINATE_PROCESS) {

-    if (PrepareToKill(KILL_METHOD_4_TERMINATE_PROCESS)) {

-      KillProcessViaTerminate(timeout_msec);

-    }

-    // Are any instances of the process still running?

-    if (!FindProcessInstances()) {

-      return S_OK;  // killed them all

-    }

-

-    UTIL_LOG(LEVEL_ERROR, (_T("[ProcessTerminator::KillTheProcess]")

-                           _T("[totally unable to kill process '%s']"),

-                           process_name_));

-  }

-

-  return E_FAIL;

-}

-

-HRESULT ProcessTerminator::WaitForAllToDie(uint32 timeout_msec) {

-  UTIL_LOG(L3, (_T("[WaitForAllToDie]")));

-  if (!FindProcessInstances()) {

-    return S_OK;

-  }

-

-  if (PrepareToKill(KILL_METHOD_1_WINDOW_MESSAGE)) {

-    return WaitForProcessInstancesToDie(timeout_msec) ? S_OK :

-              HRESULT_FROM_WIN32(WAIT_TIMEOUT);

-  }

-

-  return E_FAIL;

-}

-

-// Given process_ids array will try to

-// open handle to each instance.

-// Leaves process handles open (in member process_handles_)

-// Will use access rights for opening appropriate for the purpose_of_opening.

-// This function recursively calls itself if by the time it tries to open

-// handles to process instances some of the processes died or naturally exited.

-bool ProcessTerminator::PrepareToKill(uint32 method_mask) {

-  UTIL_LOG(L3, (_T("[PrepareToKill]")));

-  uint32 desired_access = 0;

-

-  if (method_mask & KILL_METHOD_4_TERMINATE_PROCESS) {

-    desired_access = SYNCHRONIZE       |

-                     PROCESS_TERMINATE |

-                     PROCESS_QUERY_INFORMATION;

-  } else {

-    desired_access = SYNCHRONIZE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;

-  }

-

-  // do clean up in case some handles are opened.

-  CloseAllHandles();

-

-  if (process_ids_.empty()) {

-    // no instances are running.

-    return false;

-  }

-

-  for (size_t i = 0; i < process_ids_.size(); i++) {

-    HANDLE handle = ::OpenProcess(desired_access, false, process_ids_[i]);

-    if (handle) {

-      process_handles_.push_back(handle);

-    } else {

-      if (::GetLastError() == ERROR_ACCESS_DENIED) {

-        // If we are here that means that we do not have enough priveleges to

-        // open the process for a given kill method. No reason to attempt other

-        // instances. Just clean up and return false.

-        UTIL_LOG(L3, (_T("PrepareToKill failed for '%s'. Kill method %d."),

-                      process_name_, method_mask));

-        CloseAllHandles();

-        return false;

-      }

-    }

-  }

-  // We already handled the case when we don't have enough privileges to open

-  // the process. So if we have less handles than process ids -> some of the

-  // processes have died since we made a snapshot untill the time we tried to

-  // open handles. We need to do another snapshot and try to open handles one

-  // more time. We need number of handles and number of ids to be equal.

-  // We can do it with recursion. The idea is: make the next snapshot and open

-  // handles. Hopefully the number will be equal. Stop recursion at the third

-  // level.

-

-  if (process_handles_.size() != process_ids_.size()) {

-    recursion_level_++;

-

-    // we have a disbalance here. This is pretty bad.

-    // Some of the processes died already so let's try

-    // to balance them.

-    if (!FindProcessInstances()) {

-      // they are all dead.

-      recursion_level_ = 0;

-      return false;

-    }

-

-    // try to balance three times no more.

-    if (recursion_level_ >= 3) {

-      recursion_level_ = 0;

-      UTIL_LOG(L3, (_T("Recursion level too deep in PrepareToKill for '%s'."),

-                    process_name_));

-      return false;

-    }

-

-    // recursively call the function

-    return PrepareToKill(method_mask);

-  }

-  recursion_level_ = 0;

-  return true;

-}

-

-// ProcessTerminator::FindProcessWindows

-// Just calls enumeration function

-bool ProcessTerminator::FindProcessWindows() {

-  window_handles_.clear();

-  return ::EnumWindows(EnumAllWindowsProc, reinterpret_cast<LPARAM>(this)) &&

-         !window_handles_.empty();

-}

-

-// ProcessTerminator::EnumAllWindowsProc

-// During enumeration this function will try to find a match between

-// process id we already found and process id obtained from each window.

-// if there is a match, we record the window in an array

-BOOL ProcessTerminator::EnumAllWindowsProc(HWND hwnd, LPARAM lparam) {

-  ProcessTerminator* this_pointer =

-        reinterpret_cast<ProcessTerminator*>(lparam);

-  ASSERT1(this_pointer);

-

-  uint32 process_id = 0;

-  uint32 thread_id =

-    ::GetWindowThreadProcessId(hwnd, reinterpret_cast<DWORD*>(&process_id));

-

-  typedef std::vector<uint32>::const_iterator ProcessIdIterator;

-  for (ProcessIdIterator it = this_pointer->process_ids_.begin();

-       it != this_pointer->process_ids_.end();

-       ++it) {

-    if (*it == process_id) {

-      // The main idea is: Find all top level windows (NO PARENT!!!)

-      // AND this windows must have system menu and be visible. So we make sure

-      // that we send WM_CLOSE ONLY to the windows that user might close

-      // interactively. This way we are safe. The last thing to check is if it

-      // is tr hidden window.

-      if (WindowUtils::IsMainWindow(hwnd) && WindowUtils::HasSystemMenu(hwnd)) {

-        this_pointer->window_handles_.push_back(hwnd);

-      }

-    }

-  }

-  return TRUE;

-}

-

-// ProcessTerminator::KillProcessViaWndMessages()

-// try to post a windows message

-bool  ProcessTerminator::KillProcessViaWndMessages(uint32 timeout_msec) {

-  UTIL_LOG(L3, (_T("[KillProcessViaWndMessages]")));

-  if (!FindProcessWindows()) {

-    UTIL_LOG(L1, (_T("[KillProcessViaWndMessages]")

-                  _T("[failed to find any windows for '%s']"), process_name_));

-    return false;

-  }

-

-  bool post_messages_succeeded = false;

-

-  for (size_t i = 0; i < window_handles_.size(); i++) {

-    // Previous method used WM_CLOSE, WM_SYSCOMMAND+SC_CLOSE is slightly better.

-    // It closes our apps, and also works correctly on AOL!

-    if (::PostMessage(window_handles_[i], WM_SYSCOMMAND, SC_CLOSE, 0)) {

-      if (flash_window_) {

-        UTIL_LOG(L3, (_T("[PostMessageSucceeded flashing window]")));

-        ::FlashWindow(window_handles_[i], true);

-      }

-      post_messages_succeeded = true;

-    }

-  }

-

-  if (!post_messages_succeeded) {

-    UTIL_LOG(L3, (_T("[KillProcessViaWndMessages]")

-                  _T("[failed to PostMessage to windows of '%s']"),

-                  process_name_));

-  }

-  // If we succeeded in posting message at least one time we have to wait.

-  // We don't know the relationship between windows in the process.

-  return post_messages_succeeded && WaitForProcessInstancesToDie(timeout_msec);

-}

-

-// Try to post a thread message.

-bool ProcessTerminator::KillProcessViaThreadMessages(uint32 timeout_msec) {

-  UTIL_LOG(L3, (_T("[KillProcessViaThreadMessages]")));

-  std::vector<uint32> thread_ids;

-

-  if (!FindProcessThreads(&thread_ids)) {

-    UTIL_LOG(L3, (_T("[KillProcessViaThreadMessages]")

-                  _T("[failed to find any threads for '%s']"), process_name_));

-    return false;

-  }

-

-  bool post_messages_succeeded = false;

-  for (size_t i = 0; i < thread_ids.size(); i++) {

-    if (::PostThreadMessage(thread_ids[i], WM_CLOSE, 0, 0)) {

-      post_messages_succeeded = true;

-    }

-  }

-

-  if (!post_messages_succeeded) {

-    UTIL_LOG(L3, (_T("[KillProcessViaWndMessages]")

-                  _T("[failed to PostMessage to threads of '%s'."),

-                  process_name_));

-  }

-  // If we succeded in posting message to at least one thread we have to wait.

-  // We don't know the relationship between threads in the process.

-  return post_messages_succeeded && WaitForProcessInstancesToDie(timeout_msec);

-}

-

-// find all the threads running in a given process.

-bool ProcessTerminator::FindProcessThreads(std::vector<uint32>* thread_ids) {

-  HANDLE process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

-  if (process_snapshot == INVALID_HANDLE_VALUE) {

-    return false;

-  }

-

-  THREADENTRY32 thread_info = {0};  // zero it out just in case.

-  thread_info.dwSize = sizeof(THREADENTRY32);

-

-  if (::Thread32First(process_snapshot, &thread_info))  {

-    do {

-      for (std::vector<uint32>::const_iterator it = process_ids_.begin();

-           it != process_ids_.end(); ++it) {

-        if (*it == thread_info.th32OwnerProcessID) {

-          // we have found it.

-          thread_ids->push_back(thread_info.th32ThreadID);

-        }

-      }

-      // system changes this value, do not forget to reset to

-      // max possible.

-      thread_info.dwSize = sizeof(THREADENTRY32);

-    } while (::Thread32Next(process_snapshot, &thread_info));

-  }

-

-  return !thread_ids->empty();

-}

-

-// Last and crude method to kill the process. Should be used only

-// if all other methods have failed.

-bool ProcessTerminator::KillProcessViaTerminate(uint32 timeout_msec) {

-  UTIL_LOG(L3, (_T("[KillProcessViaTerminate]")));

-  bool at_least_one_terminated = false;

-

-  for (size_t i = 0; i < process_handles_.size(); i++) {

-    if (!::TerminateProcess(process_handles_[i], 0)) {

-      UTIL_LOG(L3, (_T("[KillProcessViaTerminate]")

-                    _T("[failed for instance of '%s'][System error %d]"),

-                    process_name_, ::GetLastError()));

-    } else {

-       at_least_one_terminated = true;

-    }

-  }

-  return at_least_one_terminated ? WaitForProcessInstancesToDie(timeout_msec) :

-                                   false;

-}

-

-HRESULT SetProcessSilentShutdown() {

-  DWORD shut_down_level(0), shut_down_flags(0);

-  if (!::GetProcessShutdownParameters(&shut_down_level, &shut_down_flags)) {

-    return HRESULTFromLastError();

-  }

-  shut_down_flags |= SHUTDOWN_NORETRY;

-  if (!::SetProcessShutdownParameters(shut_down_level, shut_down_flags)) {

-    return HRESULTFromLastError();

-  }

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// proc_utils.cpp
+//
+// Useful functions that relate to process/thread manipulation/information
+// (Originally moved from utils.cpp)
+
+#include "omaha/common/proc_utils.h"
+
+#include <psapi.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_config.h"
+#include "omaha/common/const_timeouts.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/process.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/window_utils.h"
+
+namespace omaha {
+
+ProcessTerminator::ProcessTerminator(const CString& process_name)
+    : recursion_level_(0),
+      process_name_(process_name),
+      flash_window_(false),
+      session_id_(INVALID_SESSION_ID) {
+  MakeLowerCString(process_name_);
+}
+
+ProcessTerminator::ProcessTerminator(const CString& process_name,
+                                     const CString& user_sid)
+    : recursion_level_(0),
+      user_sid_(user_sid),
+      process_name_(process_name),
+      flash_window_(false),
+      session_id_(INVALID_SESSION_ID) {
+  MakeLowerCString(process_name_);
+}
+
+ProcessTerminator::ProcessTerminator(const CString& process_name,
+                                     const CString& user_sid,
+                                     int session_id)
+    : recursion_level_(0),
+      user_sid_(user_sid),
+      session_id_(session_id),
+      process_name_(process_name),
+      flash_window_(false) {
+  MakeLowerCString(process_name_);
+}
+
+ProcessTerminator::~ProcessTerminator() {
+  CloseAllHandles();
+}
+
+// Will close all currently opened handles.
+void ProcessTerminator::CloseAllHandles() {
+  UTIL_LOG(L3, (_T("[CloseAllHandles]")));
+  // Do clean up if we have opened handles.
+  for (size_t i = 0; i < process_handles_.size(); i++) {
+    VERIFY1(::CloseHandle(process_handles_[i]));
+  }
+
+  process_handles_.clear();
+}
+
+// Wait for a while till all process instances will die.
+bool ProcessTerminator::WaitForProcessInstancesToDie(
+    uint32 timeout_msec) const {
+  UTIL_LOG(L3, (_T("[WaitForProcessInstancesToDie]")));
+  size_t size = process_handles_.size();
+  scoped_array<HANDLE> handles(new HANDLE[size]);
+
+  for (size_t i = 0; i < size; i++) {
+    handles[i] = process_handles_[i];
+  }
+
+  DWORD wait_result = ::WaitForMultipleObjectsEx(size,
+                                                 handles.get(),
+                                                 true,
+                                                 timeout_msec,
+                                                 false);
+#pragma warning(disable : 4296)
+// C4296: '>=' : expression is always true
+  if ((wait_result >= WAIT_OBJECT_0) &&
+      (wait_result < WAIT_OBJECT_0 + size)) {
+    return true;
+  }
+#pragma warning(default : 4296)
+
+  UTIL_LOG(L3, (_T("WaitForProcessToDie timed out for '%s'. Waited for %d ms."),
+                process_name_, timeout_msec));
+  return false;
+}
+
+// Finds all process ids for the process of a given name.
+bool ProcessTerminator::FindProcessInstances() {
+  UTIL_LOG(L3, (_T("[FindProcessInstances]")));
+
+  DWORD exclude_mask = EXCLUDE_CURRENT_PROCESS;
+  if (!user_sid_.IsEmpty()) {
+    exclude_mask |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
+  }
+
+  std::vector<CString> command_lines;
+  HRESULT hr = S_OK;
+  if (session_id_ != INVALID_SESSION_ID) {
+    hr = Process::FindProcessesInSession(session_id_,
+                                         exclude_mask,
+                                         process_name_,
+                                         true,
+                                         user_sid_,
+                                         command_lines,
+                                         &process_ids_);
+  } else {
+    hr = Process::FindProcesses(exclude_mask,
+                                process_name_,
+                                true,
+                                user_sid_,
+                                command_lines,
+                                &process_ids_);
+  }
+
+  return SUCCEEDED(hr) && !process_ids_.empty();
+}
+
+// Tries to kill all instances of the process that was specified in the
+// constructor.
+// 'method_mask' determines which technique to attempt.
+// 'was_found' is optional and can be NULL.
+// Returns S_OK if all instances were killed, S_FALSE if process wasn't running,
+// and E_FAIL if one or more instances weren't killed.
+// Always sets 'was_found' correctly, regardless of return value.
+HRESULT ProcessTerminator::KillTheProcess(uint32 timeout_msec,
+                                          bool* was_found,
+                                          uint32 method_mask,
+                                          bool flash_window) {
+  UTIL_LOG(L3, (_T("[KillTheProcess]")));
+  if (!FindProcessInstances()) {
+    if (was_found != NULL) {
+      *was_found = false;
+    }
+    return S_FALSE;  // process is not running, so don't return a FAILED hr
+  }
+
+  // If got here, found at least one process to kill
+  if (was_found != NULL) {
+    *was_found = true;
+  }
+
+  flash_window_ = flash_window;
+  // Try the nicest, cleanest method of closing a process: window messages
+  if (method_mask & KILL_METHOD_1_WINDOW_MESSAGE) {
+    if (PrepareToKill(KILL_METHOD_1_WINDOW_MESSAGE)) {
+      KillProcessViaWndMessages(timeout_msec);
+    }
+
+    // Are any instances of the process still running?
+    if (!FindProcessInstances()) {
+      return S_OK;  // killed them all
+    }
+  }
+
+  // Also nice method
+  if (method_mask & KILL_METHOD_2_THREAD_MESSAGE) {
+    if (PrepareToKill(KILL_METHOD_2_THREAD_MESSAGE)) {
+      KillProcessViaThreadMessages(timeout_msec);
+    }
+    // Are any instances of the process still running?
+    if (!FindProcessInstances()) {
+      return S_OK;  // killed them all
+    }
+  }
+
+  // the crude one.
+  if (method_mask & KILL_METHOD_4_TERMINATE_PROCESS) {
+    if (PrepareToKill(KILL_METHOD_4_TERMINATE_PROCESS)) {
+      KillProcessViaTerminate(timeout_msec);
+    }
+    // Are any instances of the process still running?
+    if (!FindProcessInstances()) {
+      return S_OK;  // killed them all
+    }
+
+    UTIL_LOG(LEVEL_ERROR, (_T("[ProcessTerminator::KillTheProcess]")
+                           _T("[totally unable to kill process '%s']"),
+                           process_name_));
+  }
+
+  return E_FAIL;
+}
+
+HRESULT ProcessTerminator::WaitForAllToDie(uint32 timeout_msec) {
+  UTIL_LOG(L3, (_T("[WaitForAllToDie]")));
+  if (!FindProcessInstances()) {
+    return S_OK;
+  }
+
+  if (PrepareToKill(KILL_METHOD_1_WINDOW_MESSAGE)) {
+    return WaitForProcessInstancesToDie(timeout_msec) ? S_OK :
+              HRESULT_FROM_WIN32(WAIT_TIMEOUT);
+  }
+
+  return E_FAIL;
+}
+
+// Given process_ids array will try to
+// open handle to each instance.
+// Leaves process handles open (in member process_handles_)
+// Will use access rights for opening appropriate for the purpose_of_opening.
+// This function recursively calls itself if by the time it tries to open
+// handles to process instances some of the processes died or naturally exited.
+bool ProcessTerminator::PrepareToKill(uint32 method_mask) {
+  UTIL_LOG(L3, (_T("[PrepareToKill]")));
+  uint32 desired_access = 0;
+
+  if (method_mask & KILL_METHOD_4_TERMINATE_PROCESS) {
+    desired_access = SYNCHRONIZE       |
+                     PROCESS_TERMINATE |
+                     PROCESS_QUERY_INFORMATION;
+  } else {
+    desired_access = SYNCHRONIZE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
+  }
+
+  // do clean up in case some handles are opened.
+  CloseAllHandles();
+
+  if (process_ids_.empty()) {
+    // no instances are running.
+    return false;
+  }
+
+  for (size_t i = 0; i < process_ids_.size(); i++) {
+    HANDLE handle = ::OpenProcess(desired_access, false, process_ids_[i]);
+    if (handle) {
+      process_handles_.push_back(handle);
+    } else {
+      if (::GetLastError() == ERROR_ACCESS_DENIED) {
+        // If we are here that means that we do not have enough priveleges to
+        // open the process for a given kill method. No reason to attempt other
+        // instances. Just clean up and return false.
+        UTIL_LOG(L3, (_T("PrepareToKill failed for '%s'. Kill method %d."),
+                      process_name_, method_mask));
+        CloseAllHandles();
+        return false;
+      }
+    }
+  }
+  // We already handled the case when we don't have enough privileges to open
+  // the process. So if we have less handles than process ids -> some of the
+  // processes have died since we made a snapshot untill the time we tried to
+  // open handles. We need to do another snapshot and try to open handles one
+  // more time. We need number of handles and number of ids to be equal.
+  // We can do it with recursion. The idea is: make the next snapshot and open
+  // handles. Hopefully the number will be equal. Stop recursion at the third
+  // level.
+
+  if (process_handles_.size() != process_ids_.size()) {
+    recursion_level_++;
+
+    // we have a disbalance here. This is pretty bad.
+    // Some of the processes died already so let's try
+    // to balance them.
+    if (!FindProcessInstances()) {
+      // they are all dead.
+      recursion_level_ = 0;
+      return false;
+    }
+
+    // try to balance three times no more.
+    if (recursion_level_ >= 3) {
+      recursion_level_ = 0;
+      UTIL_LOG(L3, (_T("Recursion level too deep in PrepareToKill for '%s'."),
+                    process_name_));
+      return false;
+    }
+
+    // recursively call the function
+    return PrepareToKill(method_mask);
+  }
+  recursion_level_ = 0;
+  return true;
+}
+
+// ProcessTerminator::FindProcessWindows
+// Just calls enumeration function
+bool ProcessTerminator::FindProcessWindows() {
+  window_handles_.clear();
+  return ::EnumWindows(EnumAllWindowsProc, reinterpret_cast<LPARAM>(this)) &&
+         !window_handles_.empty();
+}
+
+// ProcessTerminator::EnumAllWindowsProc
+// During enumeration this function will try to find a match between
+// process id we already found and process id obtained from each window.
+// if there is a match, we record the window in an array
+BOOL ProcessTerminator::EnumAllWindowsProc(HWND hwnd, LPARAM lparam) {
+  ProcessTerminator* this_pointer =
+        reinterpret_cast<ProcessTerminator*>(lparam);
+  ASSERT1(this_pointer);
+
+  uint32 process_id = 0;
+  uint32 thread_id =
+    ::GetWindowThreadProcessId(hwnd, reinterpret_cast<DWORD*>(&process_id));
+
+  typedef std::vector<uint32>::const_iterator ProcessIdIterator;
+  for (ProcessIdIterator it = this_pointer->process_ids_.begin();
+       it != this_pointer->process_ids_.end();
+       ++it) {
+    if (*it == process_id) {
+      // The main idea is: Find all top level windows (NO PARENT!!!)
+      // AND this windows must have system menu and be visible. So we make sure
+      // that we send WM_CLOSE ONLY to the windows that user might close
+      // interactively. This way we are safe. The last thing to check is if it
+      // is tr hidden window.
+      if (WindowUtils::IsMainWindow(hwnd) && WindowUtils::HasSystemMenu(hwnd)) {
+        this_pointer->window_handles_.push_back(hwnd);
+      }
+    }
+  }
+  return TRUE;
+}
+
+// ProcessTerminator::KillProcessViaWndMessages()
+// try to post a windows message
+bool  ProcessTerminator::KillProcessViaWndMessages(uint32 timeout_msec) {
+  UTIL_LOG(L3, (_T("[KillProcessViaWndMessages]")));
+  if (!FindProcessWindows()) {
+    UTIL_LOG(L1, (_T("[KillProcessViaWndMessages]")
+                  _T("[failed to find any windows for '%s']"), process_name_));
+    return false;
+  }
+
+  bool post_messages_succeeded = false;
+
+  for (size_t i = 0; i < window_handles_.size(); i++) {
+    // Previous method used WM_CLOSE, WM_SYSCOMMAND+SC_CLOSE is slightly better.
+    // It closes our apps, and also works correctly on AOL!
+    if (::PostMessage(window_handles_[i], WM_SYSCOMMAND, SC_CLOSE, 0)) {
+      if (flash_window_) {
+        UTIL_LOG(L3, (_T("[PostMessageSucceeded flashing window]")));
+        ::FlashWindow(window_handles_[i], true);
+      }
+      post_messages_succeeded = true;
+    }
+  }
+
+  if (!post_messages_succeeded) {
+    UTIL_LOG(L3, (_T("[KillProcessViaWndMessages]")
+                  _T("[failed to PostMessage to windows of '%s']"),
+                  process_name_));
+  }
+  // If we succeeded in posting message at least one time we have to wait.
+  // We don't know the relationship between windows in the process.
+  return post_messages_succeeded && WaitForProcessInstancesToDie(timeout_msec);
+}
+
+// Try to post a thread message.
+bool ProcessTerminator::KillProcessViaThreadMessages(uint32 timeout_msec) {
+  UTIL_LOG(L3, (_T("[KillProcessViaThreadMessages]")));
+  std::vector<uint32> thread_ids;
+
+  if (!FindProcessThreads(&thread_ids)) {
+    UTIL_LOG(L3, (_T("[KillProcessViaThreadMessages]")
+                  _T("[failed to find any threads for '%s']"), process_name_));
+    return false;
+  }
+
+  bool post_messages_succeeded = false;
+  for (size_t i = 0; i < thread_ids.size(); i++) {
+    if (::PostThreadMessage(thread_ids[i], WM_CLOSE, 0, 0)) {
+      post_messages_succeeded = true;
+    }
+  }
+
+  if (!post_messages_succeeded) {
+    UTIL_LOG(L3, (_T("[KillProcessViaWndMessages]")
+                  _T("[failed to PostMessage to threads of '%s'."),
+                  process_name_));
+  }
+  // If we succeded in posting message to at least one thread we have to wait.
+  // We don't know the relationship between threads in the process.
+  return post_messages_succeeded && WaitForProcessInstancesToDie(timeout_msec);
+}
+
+// find all the threads running in a given process.
+bool ProcessTerminator::FindProcessThreads(std::vector<uint32>* thread_ids) {
+  HANDLE process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+  if (process_snapshot == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+
+  THREADENTRY32 thread_info = {0};  // zero it out just in case.
+  thread_info.dwSize = sizeof(THREADENTRY32);
+
+  if (::Thread32First(process_snapshot, &thread_info))  {
+    do {
+      for (std::vector<uint32>::const_iterator it = process_ids_.begin();
+           it != process_ids_.end(); ++it) {
+        if (*it == thread_info.th32OwnerProcessID) {
+          // we have found it.
+          thread_ids->push_back(thread_info.th32ThreadID);
+        }
+      }
+      // system changes this value, do not forget to reset to
+      // max possible.
+      thread_info.dwSize = sizeof(THREADENTRY32);
+    } while (::Thread32Next(process_snapshot, &thread_info));
+  }
+
+  return !thread_ids->empty();
+}
+
+// Last and crude method to kill the process. Should be used only
+// if all other methods have failed.
+bool ProcessTerminator::KillProcessViaTerminate(uint32 timeout_msec) {
+  UTIL_LOG(L3, (_T("[KillProcessViaTerminate]")));
+  bool at_least_one_terminated = false;
+
+  for (size_t i = 0; i < process_handles_.size(); i++) {
+    if (!::TerminateProcess(process_handles_[i], 0)) {
+      UTIL_LOG(L3, (_T("[KillProcessViaTerminate]")
+                    _T("[failed for instance of '%s'][System error %d]"),
+                    process_name_, ::GetLastError()));
+    } else {
+       at_least_one_terminated = true;
+    }
+  }
+  return at_least_one_terminated ? WaitForProcessInstancesToDie(timeout_msec) :
+                                   false;
+}
+
+HRESULT SetProcessSilentShutdown() {
+  DWORD shut_down_level(0), shut_down_flags(0);
+  if (!::GetProcessShutdownParameters(&shut_down_level, &shut_down_flags)) {
+    return HRESULTFromLastError();
+  }
+  shut_down_flags |= SHUTDOWN_NORETRY;
+  if (!::SetProcessShutdownParameters(shut_down_level, shut_down_flags)) {
+    return HRESULTFromLastError();
+  }
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/common/proc_utils.h b/common/proc_utils.h
index 1496c9f..4cc78c6 100644
--- a/common/proc_utils.h
+++ b/common/proc_utils.h
@@ -1,148 +1,148 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_PROC_UTILS_H_

-#define OMAHA_COMMON_PROC_UTILS_H_

-

-#include <windows.h>

-#include <tlhelp32.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// Moved here from installation directory. Generic enought to be in common.

-class ProcessTerminator {

- public:

-

-  // constants for specifying which methods to attempt when killing a process

-  static const int KILL_METHOD_1_WINDOW_MESSAGE = 0x01;

-  static const int KILL_METHOD_2_THREAD_MESSAGE = 0x02;

-  static const int KILL_METHOD_4_TERMINATE_PROCESS = 0x08;

-  static const int INVALID_SESSION_ID = 0xFFFF;

-

-  // Creates the object given the process name to kill.

-  explicit ProcessTerminator(const CString& process_name);

-  ProcessTerminator(const CString& process_name, const CString& user_sid);

-  ProcessTerminator(const CString& process_name,

-                    const CString& user_sid,

-                    int session_id);

-

-  // Performs necessary cleanup.

-  ~ProcessTerminator();

-

-  // Go through process list try to find the required one to kill,

-  // trying three methods to kill, from easiest and cleanest to a

-  // harsh one.  S_OK if no process by the right name was found, or if it was

-  // found and was killed.  E_FAIL otherwise.  was_found returns true if

-  // process was found. Kills all instances of a process.

-  HRESULT KillTheProcess(uint32 timeout_msec,

-                         bool* was_found,

-                         uint32 method_mask,

-                         bool flash_window);

-

-  // Wait for all instances of the process to die.

-  HRESULT WaitForAllToDie(uint32 timeout_msec);

-

-  // Finds all process ids for the process of a given name.

-  bool FindProcessInstances();

-

- private:

-

-  // Will try to open handle to each instance.

-  // Leaves process handles open (in member process_handles_)

-  // Will use access rights for opening appropriate for the purpose_of_opening

-  bool PrepareToKill(uint32 method_mask);

-

-  // Wait for process instances to die for timeout_msec

-  // return true if all are dead and false if timed out.

-  bool WaitForProcessInstancesToDie(uint32 timeout_msec) const;

-

-  // Will close all currently opened handles.

-  void CloseAllHandles();

-

-

-  //

-  // Killing via messages to window

-  //

-  // Function which meet win32 requirements for callback

-  // function passed into EnumWindows function.

-  BOOL static CALLBACK EnumAllWindowsProc(HWND hwnd, LPARAM lparam);

-

-  // Will return true if it succeeds in finding a window for the process

-  // to be killed, otherwise false.  If there are such top-level windows

-  // then returns an array of window handles.

-  bool FindProcessWindows();

-

-  // Will try to kill the process via posting windows messages

-  // returns true on success otherwise false.

-  // Timeout is maximum time to wait for WM_CLOSE to work before going to

-  // next method.

-  bool KillProcessViaWndMessages(uint32 timeout_msec);

-

-  //

-  // Killing via messages to thread

-  //

-  // Try to find the threads than run in

-  // the process in question.

-  bool FindProcessThreads(std::vector<uint32>* thread_ids);

-

-  // Will try to kill the process via posing thread messages

-  // returns true on success otherwise false.

-  // Timeout is maximum time to wait for message to work before going to

-  // next method.

-  bool KillProcessViaThreadMessages(uint32 timeout_msec);

-

-  // The last and crude method to kill the process.

-  // Calls TerminateProcess function.

-  bool KillProcessViaTerminate(uint32 timeout_msec);

-

-  // Private member variables:

-  CString process_name_;

-  // One process can have several instances

-  // running. This array will keep handles to all

-  // instances of the process.

-  std::vector<HANDLE> process_handles_;

-  // Array of process ids which correspond to different

-  // instances of the same process.

-  std::vector<uint32>  process_ids_;

-  // Function PrepareToKill can call itself

-  // recursively under some conditions.

-  // We need to stop the recursion at some point.

-  // This is the purpose of this member.

-  int recursion_level_;

-  // Array of window handles.

-  std::vector<HWND> window_handles_;

-  // The sid of the user whose process needs to be terminated.

-  CString user_sid_;

-  // True if the window flashes on shut down.

-  bool flash_window_;

-  // The session to search the processes in.

-  int session_id_;

-

-  // Disable copy constructor and assignment operator.

-  DISALLOW_EVIL_CONSTRUCTORS(ProcessTerminator);

-};

-

-// Application calling this function will be shut down

-// by the system without displaying message boxes if the application

-// fails to shutdown itself properly as a result of processing

-// WM_QUERYENDSESSION.

-HRESULT SetProcessSilentShutdown();

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_PROC_UTILS_H_

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_PROC_UTILS_H_
+#define OMAHA_COMMON_PROC_UTILS_H_
+
+#include <windows.h>
+#include <tlhelp32.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// Moved here from installation directory. Generic enought to be in common.
+class ProcessTerminator {
+ public:
+
+  // constants for specifying which methods to attempt when killing a process
+  static const int KILL_METHOD_1_WINDOW_MESSAGE = 0x01;
+  static const int KILL_METHOD_2_THREAD_MESSAGE = 0x02;
+  static const int KILL_METHOD_4_TERMINATE_PROCESS = 0x08;
+  static const int INVALID_SESSION_ID = 0xFFFF;
+
+  // Creates the object given the process name to kill.
+  explicit ProcessTerminator(const CString& process_name);
+  ProcessTerminator(const CString& process_name, const CString& user_sid);
+  ProcessTerminator(const CString& process_name,
+                    const CString& user_sid,
+                    int session_id);
+
+  // Performs necessary cleanup.
+  ~ProcessTerminator();
+
+  // Go through process list try to find the required one to kill,
+  // trying three methods to kill, from easiest and cleanest to a
+  // harsh one.  S_OK if no process by the right name was found, or if it was
+  // found and was killed.  E_FAIL otherwise.  was_found returns true if
+  // process was found. Kills all instances of a process.
+  HRESULT KillTheProcess(uint32 timeout_msec,
+                         bool* was_found,
+                         uint32 method_mask,
+                         bool flash_window);
+
+  // Wait for all instances of the process to die.
+  HRESULT WaitForAllToDie(uint32 timeout_msec);
+
+  // Finds all process ids for the process of a given name.
+  bool FindProcessInstances();
+
+ private:
+
+  // Will try to open handle to each instance.
+  // Leaves process handles open (in member process_handles_)
+  // Will use access rights for opening appropriate for the purpose_of_opening
+  bool PrepareToKill(uint32 method_mask);
+
+  // Wait for process instances to die for timeout_msec
+  // return true if all are dead and false if timed out.
+  bool WaitForProcessInstancesToDie(uint32 timeout_msec) const;
+
+  // Will close all currently opened handles.
+  void CloseAllHandles();
+
+
+  //
+  // Killing via messages to window
+  //
+  // Function which meet win32 requirements for callback
+  // function passed into EnumWindows function.
+  BOOL static CALLBACK EnumAllWindowsProc(HWND hwnd, LPARAM lparam);
+
+  // Will return true if it succeeds in finding a window for the process
+  // to be killed, otherwise false.  If there are such top-level windows
+  // then returns an array of window handles.
+  bool FindProcessWindows();
+
+  // Will try to kill the process via posting windows messages
+  // returns true on success otherwise false.
+  // Timeout is maximum time to wait for WM_CLOSE to work before going to
+  // next method.
+  bool KillProcessViaWndMessages(uint32 timeout_msec);
+
+  //
+  // Killing via messages to thread
+  //
+  // Try to find the threads than run in
+  // the process in question.
+  bool FindProcessThreads(std::vector<uint32>* thread_ids);
+
+  // Will try to kill the process via posing thread messages
+  // returns true on success otherwise false.
+  // Timeout is maximum time to wait for message to work before going to
+  // next method.
+  bool KillProcessViaThreadMessages(uint32 timeout_msec);
+
+  // The last and crude method to kill the process.
+  // Calls TerminateProcess function.
+  bool KillProcessViaTerminate(uint32 timeout_msec);
+
+  // Private member variables:
+  CString process_name_;
+  // One process can have several instances
+  // running. This array will keep handles to all
+  // instances of the process.
+  std::vector<HANDLE> process_handles_;
+  // Array of process ids which correspond to different
+  // instances of the same process.
+  std::vector<uint32>  process_ids_;
+  // Function PrepareToKill can call itself
+  // recursively under some conditions.
+  // We need to stop the recursion at some point.
+  // This is the purpose of this member.
+  int recursion_level_;
+  // Array of window handles.
+  std::vector<HWND> window_handles_;
+  // The sid of the user whose process needs to be terminated.
+  CString user_sid_;
+  // True if the window flashes on shut down.
+  bool flash_window_;
+  // The session to search the processes in.
+  int session_id_;
+
+  // Disable copy constructor and assignment operator.
+  DISALLOW_EVIL_CONSTRUCTORS(ProcessTerminator);
+};
+
+// Application calling this function will be shut down
+// by the system without displaying message boxes if the application
+// fails to shutdown itself properly as a result of processing
+// WM_QUERYENDSESSION.
+HRESULT SetProcessSilentShutdown();
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_PROC_UTILS_H_
diff --git a/common/proc_utils_unittest.cc b/common/proc_utils_unittest.cc
index a896d2e..3b5c618 100644
--- a/common/proc_utils_unittest.cc
+++ b/common/proc_utils_unittest.cc
@@ -1,26 +1,26 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/proc_utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(ProcUtilsTest, SetSilentShutdown) {

-  ASSERT_HRESULT_SUCCEEDED(SetProcessSilentShutdown());

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/proc_utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(ProcUtilsTest, SetSilentShutdown) {
+  ASSERT_HRESULT_SUCCEEDED(SetProcessSilentShutdown());
+}
+
+}  // namespace omaha
+
diff --git a/common/process.cc b/common/process.cc
index 7557d13..2680be6 100644
--- a/common/process.cc
+++ b/common/process.cc
@@ -1,1631 +1,1631 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines class Process to incapsulate win32

-// functions for creation and some manipulations of

-// processes.

-

-#include "omaha/common/process.h"

-

-#include <ntsecapi.h>

-#include <psapi.h>

-#include <stierr.h>

-#include <tlhelp32.h>

-#include <vector>

-

-#ifndef NT_SUCCESS

-#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)

-#endif

-

-#include "omaha/common/debug.h"

-#include "omaha/common/disk.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/window_utils.h"

-

-namespace omaha {

-

-const int kNumRetriesToFindProcess = 4;

-const int kFindProcessRetryIntervalMs = 500;

-const int kMaxCmdLineLengthBytes = 4096;

-

-// Constructor

-Process::Process(const TCHAR* name, const TCHAR* window_class_name)

-    : process_id_(0),

-      exit_code_(0),

-      number_of_restarts_(static_cast<uint32>(-1)),

-      name_(name),

-      shutdown_event_(NULL) {

-  ASSERT1(name);

-

-  command_line_ = name;

-  window_class_name_ = window_class_name;

-}

-

-// Constructor

-Process::Process(uint32 process_id)

-    : process_id_(process_id),

-      exit_code_(0),

-      number_of_restarts_(static_cast<uint32>(-1)),

-      name_(itostr(static_cast<uint32>(process_id))),

-      shutdown_event_(NULL) {

-  reset(process_, ::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,

-                                false,

-                                process_id));

-  if (!valid(process_)) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[Process::Process - failed to open process][%u][0x%x]"),

-              process_id, HRESULTFromLastError()));

-  }

-}

-

-// Destructor

-Process::~Process() {

-}

-

-// Start with command params

-bool Process::Start(const TCHAR* command_line_parameters) {

-  return StartWithHwnd(command_line_parameters, NULL);

-}

-

-// Start with command params and specific hwnd

-bool Process::StartWithHwnd(const TCHAR* command_line_parameters, HWND hwnd) {

-  // command_line_parameters may be NULL

-  // hwnd may be NULL

-

-  // Can't start the same process twice in the same

-  // containing object.

-  if (Running()) {

-    return false;

-  }

-

-  // Add command line params if any.

-  if (command_line_parameters && *command_line_parameters) {

-    command_line_parameters_ = command_line_parameters;

-  }

-

-  // just reuse the existing function, don't repeat the code.

-  number_of_restarts_ = static_cast<uint32>(-1);

-  time_of_start_      = GetTickCount();

-  return Restart(hwnd);

-}

-

-// Restart with the old command params

-bool Process::Restart(HWND hwnd) {

-  // Can't start the same process twice in the same

-  // containing object.

-  if (Running()) {

-    return false;

-  }

-

-  // start the process.

-  HRESULT hr = System::ShellExecuteProcess(command_line_,

-                                           command_line_parameters_,

-                                           hwnd,

-                                           address(process_));

-

-  if (SUCCEEDED(hr)) {

-    process_id_ = GetProcessIdFromHandle(get(process_));

-    ASSERT1(process_id_);

-    number_of_restarts_++;

-  } else {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("System::ShellExecuteProcess '%s' failed with 0x%08x"),

-             command_line_, hr));

-  }

-

-  return SUCCEEDED(hr);

-}

-

-// Check if the process is running.

-bool Process::Running() const {

-  if (!get(process_)) {

-    return false;

-  }

-

-  return (::WaitForSingleObject(get(process_), 0) == WAIT_TIMEOUT);

-}

-

-// Create a job and assign the process to it

-HANDLE Process::AssignToJob() {

-  // Make sure that the process handle is valid

-  if (!get(process_)) {

-    return false;

-  }

-

-  // Create a job

-  scoped_job job(::CreateJobObject(NULL, NULL));

-  if (!valid(job)) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[Process::AssignToJob - CreateJobObject failed][0x%x]"),

-              HRESULTFromLastError()));

-    return false;

-  }

-

-  // Assign the process to the job

-  if (!::AssignProcessToJobObject(get(job), get(process_))) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[Process::AssignToJob-AssignProcessToJobObject fail][0x%x]"),

-              HRESULTFromLastError()));

-    return false;

-  }

-

-  return release(job);

-}

-

-// Wait till the process finishes

-bool Process::WaitUntilDead(uint32 timeout_msec) {

-  ASSERT1(timeout_msec);

-

-  if (!get(process_)) {

-    return false;

-  }

-

-  uint32 ret = 0;

-  if (shutdown_event_) {

-    HANDLE wait_handles[2] = {0};

-    wait_handles[0] = get(process_);

-    wait_handles[1] = shutdown_event_;

-    ret = ::WaitForMultipleObjectsEx(2,

-                                     wait_handles,

-                                     false,

-                                     timeout_msec,

-                                     true);

-  } else {

-    ret = ::WaitForSingleObjectEx(get(process_), timeout_msec, true);

-  }

-  if (ret == WAIT_OBJECT_0) {

-    UTIL_LOG(L2, (_T("[Process::WaitUntilDead - succeeded to wait process]")

-                  _T("[%s]"), GetName()));

-    return true;

-  } else if (ret == WAIT_IO_COMPLETION) {

-    UTIL_LOG(LEVEL_ERROR, (_T("[Process::WaitUntilDead-recv APC][%s][%u][%u]"),

-                           GetName(), process_id_));

-    return false;

-  } else {

-    UTIL_LOG(LEVEL_ERROR, (_T("[Process::WaitUntilDead - fail to wait process,")

-                           _T("possibly timeout][%s][%u][%u]"),

-                           GetName(), process_id_, ret));

-    return false;

-  }

-}

-

-// Wait some time till the process and all its descendent processes finish

-//

-// Background:

-//   Some process might spawn another process and get itself terminated

-// without waiting the descendant process to finish.

-//

-// Args:

-//   job:                Job to which the process is assigned

-//                       AssignToJob() will be called when NULL value is passed

-//   timeout_msec:       Timeout value in msec

-//   path_to_exclude:    Path of descendant process to excluded from waiting

-//                       (this should be in long format)

-//   exit_code:          To hold the exit code being returned

-bool Process::WaitUntilAllDead(HANDLE job,

-                               uint32 timeout_msec,

-                               const TCHAR* path_to_exclude,

-                               uint32* exit_code) {

-  ASSERT1(timeout_msec);

-

-  UTIL_LOG(L2, (_T("[Process::WaitUntilAllDead][%u][%s]"),

-                timeout_msec, path_to_exclude));

-

-  if (exit_code) {

-  *exit_code = 0;

-  }

-

-  scoped_job job_guard;

-  if (!job) {

-    reset(job_guard, AssignToJob());

-    if (!valid(job_guard)) {

-      return false;

-    }

-    job = get(job_guard);

-  }

-

-  return InternalWaitUntilAllDead(job,

-                                  timeout_msec,

-                                  path_to_exclude,

-                                  exit_code);

-}

-

-// Helper function to wait till the process and all its descendent processes

-// finish.

-bool Process::InternalWaitUntilAllDead(HANDLE job,

-                                       uint32 timeout_msec,

-                                       const TCHAR* path_to_exclude,

-                                       uint32* exit_code) {

-  ASSERT1(job);

-  ASSERT1(timeout_msec);

-

-  // Wait until current process finishes

-  if (!WaitUntilDead(timeout_msec)) {

-    return false;

-  }

-

-  // Find descendant process

-  uint32 desc_process_id = GetDescendantProcess(

-                               job,

-                               false,  // child_only

-                               exit_code != NULL,  // sole_descendent

-                               NULL,  // search_name

-                               path_to_exclude);

-

-  if (desc_process_id) {

-    // Open descendent process

-    Process desc_process(desc_process_id);

-

-    // If descendant process dies too soon, do not need to wait for it

-    if (desc_process.Running()) {

-      // Release the parent process handle

-      // This to handle the scenario that Firefox uninstall code will wait till

-      // parent process handle becomes NULL

-      reset(process_);

-

-      UTIL_LOG(L2, (_T("[Process::InternalWaitUntilAllDead]")

-                    _T("[waiting descendant process][%u]"), desc_process_id));

-

-      // Propagate the shutdown event to descendent process

-      if (shutdown_event_) {

-        desc_process.SetShutdownEvent(shutdown_event_);

-      }

-

-      // Wait till descendant process finishes

-      bool wait_ret = desc_process.InternalWaitUntilAllDead(job,

-                                                            timeout_msec,

-                                                            path_to_exclude,

-                                                            exit_code);

-

-      return wait_ret;

-    }

-  }

-

-  // Use the exit code from parent process

-  if (exit_code) {

-  VERIFY1(GetExitCode(exit_code));

-  }

-

-  // Release the parent process handle

-  reset(process_);

-

-  return true;

-}

-

-// Wait until process is dead or a windows message arrives (for use in a message

-// loop while waiting)

-HRESULT Process::WaitUntilDeadOrInterrupt(uint32 msec) {

-  if (!get(process_)) {

-    return E_FAIL;

-  }

-

-  HANDLE events[1] = { get(process_) };

-  uint32 dw = ::MsgWaitForMultipleObjects(1, events, FALSE, msec, QS_ALLEVENTS);

-  switch (dw) {

-    case WAIT_OBJECT_0:

-      return CI_S_PROCESSWAIT_DEAD;

-    case WAIT_OBJECT_0 + 1:

-      return CI_S_PROCESSWAIT_MESSAGE;

-    case WAIT_TIMEOUT:

-      return CI_S_PROCESSWAIT_TIMEOUT;

-    case WAIT_FAILED:

-    default:

-      return E_FAIL;

-  }

-}

-

-#if !SHIPPING

-CString Process::GetDebugInfo() const {

-  return debug_info_;

-}

-#endif

-

-// Return the process ID

-uint32 Process::GetId() const {

-  return process_id_;

-}

-

-// Return the process name

-const TCHAR *Process::GetName() const {

-  return name_;

-}

-

-// Return win32 handle to the process.

-HANDLE Process::GetHandle() const {

-  return get(process_);

-}

-

-// Get process exit code.

-bool Process::GetExitCode(uint32* exit_code) const {

-  ASSERT1(exit_code);

-

-  if (!get(process_)) {

-    return false;

-  }

-

-  if (!::GetExitCodeProcess(get(process_),

-                            reinterpret_cast<DWORD*>(&exit_code_))) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[Process::GetExitCode - failed to get exit code][%u][0x%x]"),

-              process_id_, HRESULTFromLastError()));

-    return false;

-  }

-  if (exit_code_ == STILL_ACTIVE) {

-    return false;

-  }

-

-  *exit_code = exit_code_;

-  return true;

-}

-

-// default implementation allows termination

-bool Process::IsTerminationAllowed() const {

-  return true;

-}

-

-// Terminate the process. If wait_for_terminate_msec == 0 return value doesn't

-// mean that the process actualy terminated. It becomes assync. operation.

-// Check the status with Running accessor function in this case.

-bool Process::Terminate(uint32 wait_for_terminate_msec) {

-  if (!Running()) {

-    return true;

-  }

-

-  if (!IsTerminationAllowed()) {

-    return false;

-  }

-

-  if (!::TerminateProcess(get(process_), 1)) {

-    return false;

-  }

-

-  return wait_for_terminate_msec ? WaitUntilDead(wait_for_terminate_msec) :

-                                   true;

-}

-

-// Default returns INFINITE means never restart.

-// Return any number of msec if overwriting

-uint32 Process::GetRestartInterval() const {

-  return INFINITE;

-}

-

-// How many times the process can be restarted

-// in case it crashes. When overriding return any

-// number or INFINITE to restart forever.

-uint32 Process::GetMaxNumberOfRestarts() const {

-  return 0;

-}

-

-// what is the time window for number of crashes returned by

-// GetMaxNumberOfRestarts(). If crashed more that this number of restarts

-// in a specified time window - do not restart it anymore.

-// Default implementation returns INFINITE which means that this is not time

-// based at all, if the process crashed more than the value returned by

-// GetMaxNumberOfRestarts it will not be restarted no matter how long it took.

-uint32 Process::GetTimeWindowForCrashes() const {

-  return INFINITE;

-}

-

-uint32 Process::GetMaxMemory() const {

-  return 0;

-}

-

-// Have we exceeded the number of maximum restarting?

-bool Process::AllowedToRestart() const {

-  uint32 max_number_of_restarts = GetMaxNumberOfRestarts();

-

-  if ((max_number_of_restarts == INFINITE) ||

-     (number_of_restarts_ < max_number_of_restarts)) {

-    return true;

-  }

-

-  // process crashed too many times. Let's look at the rate of crashes.

-  // Maybe we can "forgive" the process if it took some time for it to crash.

-  if ((::GetTickCount() - time_of_start_) < GetTimeWindowForCrashes()) {

-    return false;  // not forgiven

-  }

-

-  // Everything is forgiven. Give the process

-  // new start in life.

-  time_of_start_ = ::GetTickCount();

-  number_of_restarts_ = static_cast<uint32>(-1);

-

-  return true;

-}

-

-// Set shutdown event using in signaling the process watch

-void Process::SetShutdownEvent(HANDLE shutdown_event) {

-  ASSERT1(shutdown_event);

-

-  shutdown_event_ = shutdown_event;

-}

-

-// Set priority class to the process.

-bool Process::SetPriority(uint32 priority_class) const {

-  if (!get(process_)) {

-    return false;

-  }

-

-  VERIFY1(::SetPriorityClass(get(process_), priority_class));

-  return true;

-}

-

-// Try to get a descendant process. Return process id if found.

-uint32 Process::GetDescendantProcess(HANDLE job,

-                                     bool child_only,

-                                     bool sole_descedent,

-                                     const TCHAR* search_name,

-                                     const TCHAR* path_to_exclude) {

-  ASSERT1(job);

-

-  // Find all descendent processes

-  std::vector<ProcessInfo> descendant_processes;

-  if (FAILED(GetAllDescendantProcesses(job,

-                                       child_only,

-                                       search_name,

-                                       path_to_exclude,

-                                       &descendant_processes))) {

-    return 0;

-  }

-

-  // If more than one decendent processes is found, filter out those that are

-  // not direct children. This is because it might be the case that in a very

-  // short period of time, process A spawns B and B spawns C, and we capture

-  // both B and C.

-  std::vector<ProcessInfo> child_processes;

-  typedef std::vector<ProcessInfo>::const_iterator ProcessInfoConstIterator;

-  if (descendant_processes.size() > 1) {

-    for (ProcessInfoConstIterator it(descendant_processes.begin());

-         it != descendant_processes.end(); ++it) {

-      if (it->parent_id == process_id_) {

-        child_processes.push_back(*it);

-      }

-    }

-    if (!child_processes.empty()) {

-      descendant_processes = child_processes;

-    }

-  }

-

-  // Save the debugging information if needed

-#if !SHIPPING

-  if (sole_descedent && descendant_processes.size() > 1) {

-    debug_info_ = _T("More than one descendent process is found for process ");

-    debug_info_ += itostr(process_id_);

-    debug_info_ += _T("\n");

-    for (ProcessInfoConstIterator it(descendant_processes.begin());

-         it != descendant_processes.end(); ++it) {

-      debug_info_.AppendFormat(_T("%u %u %s\n"),

-                               it->process_id,

-                               it->parent_id,

-                               it->exe_file);

-    }

-  }

-#else

-  sole_descedent;   // unreferenced formal parameter

-#endif

-

-  return descendant_processes.empty() ? 0 : descendant_processes[0].process_id;

-}

-

-BOOL Process::IsProcessInJob(HANDLE process_handle,

-                             HANDLE job_handle,

-                             PBOOL result)  {

-  typedef BOOL (WINAPI *Fun)(HANDLE process_handle,

-                             HANDLE job_handle,

-                             PBOOL result);

-

-  HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));

-  ASSERT1(kernel_instance);

-  Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(kernel_instance,

-                                                   "IsProcessInJob"));

-  ASSERT(pfn, (_T("IsProcessInJob export not found in kernel32.dll")));

-  return pfn ? (*pfn)(process_handle, job_handle, result) : FALSE;

-}

-

-// Try to get all matching descendant processes

-HRESULT Process::GetAllDescendantProcesses(

-                     HANDLE job,

-                     bool child_only,

-                     const TCHAR* search_name,

-                     const TCHAR* path_to_exclude,

-                     std::vector<ProcessInfo>* descendant_processes) {

-  ASSERT1(job);

-  ASSERT1(descendant_processes);

-

-  // Take a snapshot

-  // Note that we do not have a seperate scoped_* type defined to wrap the

-  // handle returned by CreateToolhelp32Snapshot. So scoped_hfile with similar

-  // behavior is used.

-  scoped_hfile process_snap(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));

-  if (!process_snap) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[Process::GetAllDescendantProcesses - fail to get snapshot]")

-              _T("[0x%x]"), hr));

-    return hr;

-  }

-

-  // Eumerate all processes in the snapshot

-  PROCESSENTRY32 pe32;

-  SetZero(pe32);

-  pe32.dwSize = sizeof(PROCESSENTRY32);

-  if (!::Process32First(get(process_snap), &pe32)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[Process::GetAllDescendantProcesses - failed to")

-                           _T("get first process][0x%x]"), hr));

-    return hr;

-  }

-

-  do {

-    // Skip process 0 and current process

-    if (pe32.th32ProcessID == 0 || pe32.th32ProcessID == process_id_) {

-      continue;

-    }

-

-    // If searching for child only, perform the check

-    if (child_only && pe32.th32ParentProcessID != process_id_) {

-      continue;

-    }

-

-    // Open the process

-    scoped_process process(::OpenProcess(PROCESS_QUERY_INFORMATION |

-                                         SYNCHRONIZE,

-                                         false,

-                                         pe32.th32ProcessID));

-    if (!valid(process)) {

-      continue;

-    }

-

-    // Determines whether the process is running in the specified job

-    BOOL result = FALSE;

-    if (!IsProcessInJob(get(process), job, &result) || !result) {

-      continue;

-    }

-

-    // Check whether the process is still running

-    if (::WaitForSingleObject(get(process), 0) != WAIT_TIMEOUT) {

-      continue;

-    }

-

-    // Compare the name if needed

-    if (search_name && *search_name) {

-      if (_tcsicmp(pe32.szExeFile, search_name) != 0) {

-        continue;

-      }

-    }

-

-    // If we need to exclude certain path, check it now

-    if (path_to_exclude && *path_to_exclude) {

-      if (IsProcessRunningWithPath(pe32.th32ProcessID, path_to_exclude)) {

-        continue;

-      }

-    }

-

-    // Add to the list

-    ProcessInfo proc_info;

-    proc_info.process_id = pe32.th32ProcessID;

-    proc_info.parent_id = pe32.th32ParentProcessID;

-#if !SHIPPING

-    proc_info.exe_file = pe32.szExeFile;

-#endif

-    descendant_processes->push_back(proc_info);

-  } while (::Process32Next(get(process_snap), &pe32));

-

-  return S_OK;

-}

-

-HRESULT Process::FindProcesses(uint32 exclude_mask,

-                               const TCHAR* search_name,

-                               bool search_main_executable_only,

-                               std::vector<uint32>* process_ids_found) {

-  ASSERT1(process_ids_found);

-  // Remove the only include processes owned by user mask from the exclude

-  // mask. This is needed as this is the behavior expected by the method,

-  // before the addition of the user_sid.

-  exclude_mask &= (~INCLUDE_ONLY_PROCESS_OWNED_BY_USER);

-  std::vector<CString> command_lines;

-  return FindProcesses(exclude_mask, search_name, search_main_executable_only,

-                       _T(""), command_lines, process_ids_found);

-}

-

-bool Process::IsStringPresentInList(const CString& process_command_line,

-                                    const std::vector<CString>& list) {

-  std::vector<CString>::const_iterator iter = list.begin();

-  for (; iter != list.end(); ++iter) {

-    CString value_to_find = *iter;

-

-    // If we are able to open the process command line, then we should

-    // ensure that it does not contain the value that we are looking for.

-    if (process_command_line.Find(value_to_find) != -1) {

-      // Found a match.

-      return true;

-    }

-  }

-

-  return false;

-}

-

-// TODO(omaha): Change the implementation of this method to take in a

-// predicate that determines whether a process should be included in the

-// result set.

-HRESULT Process::FindProcesses(uint32 exclude_mask,

-                               const TCHAR* search_name,

-                               bool search_main_executable_only,

-                               const CString& user_sid,

-                               const std::vector<CString>& command_lines,

-                               std::vector<uint32>* process_ids_found) {

-  ASSERT1(search_name && *search_name);

-  ASSERT1(process_ids_found);

-  ASSERT1(!((exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING) &&

-            (exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING)));

-

-  const TCHAR* const kLocalSystemSid = _T("S-1-5-18");

-

-  // Clear the output queue

-  process_ids_found->clear();

-

-  // Get the list of process identifiers.

-  uint32 process_ids[kMaxProcesses];

-  SetZero(process_ids);

-  uint32 bytes_returned = 0;

-  if (!::EnumProcesses(reinterpret_cast<DWORD*>(process_ids),

-                       sizeof(process_ids),

-                       reinterpret_cast<DWORD*>(&bytes_returned))) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[Process::FindProcesses-fail to EnumProcesses]")

-                           _T("[0x%x]"), hr));

-    return hr;

-  }

-

-  // Enumerate all processes

-  int num_processes = bytes_returned / sizeof(process_ids[0]);

-  // We have found an elevated number of crashes in 1.2.584.15114 on what

-  // we believe are Italian systems. The first step to solving this Italian job

-  // is to assert on the condition while we are further testing this.

-  ASSERT1(num_processes <= kMaxProcesses);

-

-  // In Vista, SeDebugPrivilege is required to open the process not owned by

-  // current user. Also required for XP admins to open Local System processes

-  // with PROCESS_QUERY_INFORMATION access rights.

-  System::AdjustPrivilege(SE_DEBUG_NAME, true);

-

-  // Get ID of current process

-  uint32 curr_process_id = ::GetCurrentProcessId();

-

-  // Get SID of current user

-  CString curr_user_sid;

-  HRESULT hr = omaha::user_info::GetCurrentUser(NULL, NULL, &curr_user_sid);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  UTIL_LOG(L4, (_T("[Process::FindProcesses][processes=%d]"), num_processes));

-  for (int i = 0; i < num_processes; ++i) {

-    // Skip the system idle process.

-    if (process_ids[i] == 0) {

-      continue;

-    }

-

-    // Get the owner sid.

-    // Note that we may fail to get the owner which is not current user.

-    // So if the owner_sid is empty, the process is sure not to be owned by the

-    // current user.

-    CString owner_sid;

-    Process::GetProcessOwner(process_ids[i], &owner_sid);

-

-    if ((exclude_mask & INCLUDE_ONLY_PROCESS_OWNED_BY_USER) &&

-      owner_sid != user_sid) {

-      UTIL_LOG(L4,

-          (_T("[Excluding process as not owned by user][%d]"), process_ids[i]));

-      continue;

-    }

-

-    // Skip it if it is owned by the one specified in exclude_mask

-    if ((exclude_mask & EXCLUDE_CURRENT_PROCESS) &&

-        process_ids[i] == curr_process_id) {

-      UTIL_LOG(L4, (_T("[Excluding current process %d"), process_ids[i]));

-      continue;

-    }

-    if ((exclude_mask & EXCLUDE_PROCESS_OWNED_BY_CURRENT_USER) &&

-        owner_sid == curr_user_sid) {

-      UTIL_LOG(L4,

-          (_T("[Excluding process as owned by current user][%d]"),

-           process_ids[i]));

-      continue;

-    }

-    if ((exclude_mask & EXCLUDE_PROCESS_OWNED_BY_SYSTEM) &&

-        owner_sid == kLocalSystemSid) {

-      UTIL_LOG(L4,

-          (_T("[Excluding process as owned by system][%d]"), process_ids[i]));

-      continue;

-    }

-    if (exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING ||

-        exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING) {

-      CString process_command_line;

-      HRESULT hr = GetCommandLine(process_ids[i], &process_command_line);

-      if (FAILED(hr)) {

-        UTIL_LOG(L4,

-          (_T("[Excluding process could not get command line][%d]"),

-           process_ids[i]));

-        continue;

-      }

-

-      // If we are able to open the process command line, then we should

-      // ensure that it does not contain the value that we are looking for if

-      // we are excluding the command line or that it contains the command line

-      // that we are looking for in case the include switch is specified.

-      bool present = IsStringPresentInList(process_command_line, command_lines);

-      if ((present &&

-            (exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING)) ||

-          (!present &&

-            (exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING))) {

-        UTIL_LOG(L4, (_T("[Process command line matches criteria][%d]'[%s]'"),

-                 process_ids[i], process_command_line));

-        continue;

-      }

-    }

-

-    // If search_name is provided, make sure it matches

-    if (Process::IsProcessUsingExeOrDll(process_ids[i],

-                                        search_name,

-                                        search_main_executable_only)) {

-      UTIL_LOG(L4,

-          (_T("[Including process][%d][%s]"), process_ids[i], search_name));

-      process_ids_found->push_back(process_ids[i]);

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT Process::FindProcessesInSession(

-    DWORD session_id,

-    uint32 exclude_mask,

-    const TCHAR* search_name,

-    bool search_main_executable_only,

-    const CString& user_sid,

-    const std::vector<CString>& cmd_lines,

-    std::vector<uint32>* process_ids_found) {

-  HRESULT hr = FindProcesses(exclude_mask,

-                             search_name,

-                             search_main_executable_only,

-                             user_sid,

-                             cmd_lines,

-                             process_ids_found);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Filter to processes running under session_id.

-  std::vector<uint32>::iterator iter = process_ids_found->begin();

-  while (iter != process_ids_found->end()) {

-    uint32 process_pid = *iter;

-    DWORD process_session = 0;

-    hr = S_OK;

-    if (!::ProcessIdToSessionId(process_pid, &process_session)) {

-      hr = HRESULTFromLastError();

-      UTIL_LOG(LE,  (_T("[::ProcessIdToSessionId failed][0x%x]"), hr));

-    }

-

-    if (FAILED(hr) || process_session != session_id) {

-      // Remove from list and continue.

-      iter = process_ids_found->erase(iter);

-      continue;

-    }

-

-    ++iter;

-  }

-

-  return S_OK;

-}

-

-bool Process::IsModuleMatchingExeOrDll(const TCHAR* module_name,

-                                       const TCHAR* search_name,

-                                       bool is_fully_qualified_name) {

-  UTIL_LOG(L4, (_T("[Process::IsModuleMatchingExeOrDll]")

-                _T("[module=%s][search=%s]"), module_name, search_name));

-  CString module_file_name;

-  if (is_fully_qualified_name) {

-    if (FAILED(GetLongPathName(module_name, &module_file_name))) {

-      return false;

-    }

-  } else {

-    module_file_name = ::PathFindFileName(module_name);

-    ASSERT1(!module_file_name.IsEmpty());

-    if (module_file_name.IsEmpty()) {

-      return false;

-    }

-  }

-

-  return (module_file_name.CompareNoCase(search_name) == 0);

-}

-

-DWORD Process::GetProcessImageFileName(HANDLE proc_handle,

-                                       LPTSTR image_file,

-                                       DWORD file_size)  {

-  typedef DWORD (WINAPI *Fun)(HANDLE proc_handle,

-                              LPWSTR image_file,

-                              DWORD file_size);

-

-  HINSTANCE psapi_instance = ::GetModuleHandle(_T("Psapi.dll"));

-  ASSERT1(psapi_instance);

-  Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(psapi_instance,

-                                                   "GetProcessImageFileNameW"));

-  if (!pfn) {

-    UTIL_LOG(L1, (_T("::GetProcessImageFileNameW() not found in Psapi.dll")));

-    return 0;

-  }

-  return (*pfn)(proc_handle, image_file, file_size);

-}

-

-bool Process::IsProcImageMatch(HANDLE proc_handle,

-                               const TCHAR* search_name,

-                               bool is_fully_qualified_name)  {

-  TCHAR image_name[MAX_PATH] = _T("");

-  if (!GetProcessImageFileName(proc_handle,

-                               image_name,

-                               arraysize(image_name))) {

-    UTIL_LOG(L4, (_T("[GetProcessImageFileName fail[0x%x]"),

-                  HRESULTFromLastError()));

-    return false;

-  }

-

-  UTIL_LOG(L4, (_T("[GetProcessImageFileName][%s]"), image_name));

-  CString dos_name;

-  HRESULT hr(DevicePathToDosPath(image_name, &dos_name));

-  if (FAILED(hr)) {

-    UTIL_LOG(L4, (_T("[DevicePathToDosPath fail[0x%x]"), hr));

-    return false;

-  }

-

-  return IsModuleMatchingExeOrDll(dos_name,

-                                  search_name,

-                                  is_fully_qualified_name);

-}

-

-// Is the process using the specified exe/dll?

-bool Process::IsProcessUsingExeOrDll(uint32 process_id,

-                                     const TCHAR* search_name,

-                                     bool search_main_executable_only) {

-  UTIL_LOG(L4, (_T("[Process::IsProcessUsingExeOrDll]")

-                _T("[pid=%d][search_name=%s]"), process_id, search_name));

-  ASSERT1(search_name);

-

-  // Open the process

-  scoped_process process_handle(::OpenProcess(

-                                    PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,

-                                    FALSE,

-                                    process_id));

-  if (!process_handle) {

-    UTIL_LOG(L4, (_T("[::OpenProcess failed][0x%x]"), HRESULTFromLastError()));

-    return false;

-  }

-

-  // Does the name represent a fully qualified name?

-  // We only do a simple check here

-  bool is_fully_qualified_name = String_FindChar(search_name, _T('\\')) != -1;

-  CString long_search_name;

-  if (is_fully_qualified_name) {

-    HRESULT hr(GetLongPathName(search_name, &long_search_name));

-    if (FAILED(hr)) {

-      UTIL_LOG(L4, (_T("[GetLongPathName fail][hr=x%x]"), hr));

-      return false;

-    }

-    search_name = long_search_name;

-  }

-

-  // Take a snapshot of all modules in the specified process

-  int num_modules_to_fetch = search_main_executable_only ? 1 :

-                                                           kMaxProcessModules;

-  HMODULE module_handles[kMaxProcessModules];

-  SetZero(module_handles);

-  uint32 bytes_needed = 0;

-  if (!::EnumProcessModules(get(process_handle),

-                            module_handles,

-                            num_modules_to_fetch * sizeof(HMODULE),

-                            reinterpret_cast<DWORD*>(&bytes_needed))) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[EnumProcessModules failed][0x%x]"), hr));

-

-    if (IsWow64(::GetCurrentProcessId())) {

-      // ::EnumProcessModules from a WoW64 process fails for x64 processes.

-      // We try ::GetProcessImageFileName as a workaround here.

-      return search_main_executable_only ?

-                 IsProcImageMatch(get(process_handle),

-                                  search_name,

-                                  is_fully_qualified_name) :

-                 false;

-    } else {

-      return false;

-    }

-  }

-

-  int num_modules = bytes_needed / sizeof(HMODULE);

-  if (num_modules > num_modules_to_fetch) {

-    num_modules = num_modules_to_fetch;

-  }

-

-  for (int i = 0; i < num_modules; ++i) {

-    TCHAR module_name[MAX_PATH];

-    SetZero(module_name);

-    if (!::GetModuleFileNameEx(get(process_handle),

-                               module_handles[i],

-                               module_name,

-                               arraysize(module_name))) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[GetModuleFileNameEx fail[x%x]"),

-                             HRESULTFromLastError()));

-      continue;

-    }

-

-    if (IsModuleMatchingExeOrDll(module_name,

-                                 search_name,

-                                 is_fully_qualified_name)) {

-      return true;

-    }

-  }

-

-  return false;

-}

-

-// Helper function to get long path name

-HRESULT Process::GetLongPathName(const TCHAR* short_name, CString* long_name) {

-  ASSERT1(short_name);

-  ASSERT1(long_name);

-

-  TCHAR temp_name[MAX_PATH];

-  SetZero(temp_name);

-

-  HRESULT hr = S_OK;

-  if (!::GetLongPathName(short_name, temp_name, arraysize(temp_name))) {

-    hr = HRESULTFromLastError();

-  } else {

-    long_name->SetString(temp_name);

-  }

-

-  return hr;

-}

-

-// Type definitions needed for GetCommandLine() and GetProcessIdFromHandle()

-// From MSDN document on NtQueryInformationProcess() and other sources

-typedef struct _PROCESS_BASIC_INFORMATION {

-  PVOID Reserved1;

-  BYTE *PebBaseAddress;

-  PVOID Reserved2[2];

-  ULONG_PTR UniqueProcessId;

-  PVOID Reserved3;

-} PROCESS_BASIC_INFORMATION;

-

-typedef enum _PROCESSINFOCLASS {

-  ProcessBasicInformation = 0,

-  ProcessWow64Information = 26

-} PROCESSINFOCLASS;

-

-typedef WINBASEAPI DWORD WINAPI

-GetProcessIdFn(

-    HANDLE Process

-);

-

-typedef LONG WINAPI

-NtQueryInformationProcess(

-  IN HANDLE ProcessHandle,

-  IN PROCESSINFOCLASS ProcessInformationClass,

-  OUT PVOID ProcessInformation,

-  IN ULONG ProcessInformationLength,

-  OUT PULONG ReturnLength OPTIONAL

-);

-

-typedef struct _RTL_DRIVE_LETTER_CURDIR {

-  USHORT Flags;

-  USHORT Length;

-  ULONG TimeStamp;

-  UNICODE_STRING DosPath;

-} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;

-

-typedef struct _RTL_USER_PROCESS_PARAMETERS {

-  ULONG MaximumLength;

-  ULONG Length;

-  ULONG Flags;

-  ULONG DebugFlags;

-  PVOID ConsoleHandle;

-  ULONG ConsoleFlags;

-  HANDLE StdInputHandle;

-  HANDLE StdOutputHandle;

-  HANDLE StdErrorHandle;

-  UNICODE_STRING CurrentDirectoryPath;

-  HANDLE CurrentDirectoryHandle;

-  UNICODE_STRING DllPath;

-  UNICODE_STRING ImagePathName;

-  UNICODE_STRING CommandLine;

-  PVOID Environment;

-  ULONG StartingPositionLeft;

-  ULONG StartingPositionTop;

-  ULONG Width;

-  ULONG Height;

-  ULONG CharWidth;

-  ULONG CharHeight;

-  ULONG ConsoleTextAttributes;

-  ULONG WindowFlags;

-  ULONG ShowWindowFlags;

-  UNICODE_STRING WindowTitle;

-  UNICODE_STRING DesktopName;

-  UNICODE_STRING ShellInfo;

-  UNICODE_STRING RuntimeData;

-  RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];

-} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

-

-// Get the function pointer to GetProcessId in KERNEL32.DLL

-static HRESULT EnsureGPIFunction(GetProcessIdFn** gpi_func_ptr) {

-  static GetProcessIdFn* gpi_func = NULL;

-  if (!gpi_func) {

-    HMODULE kernel32_module = ::GetModuleHandle(_T("kernel32.dll"));

-    if (!kernel32_module) {

-      return HRESULTFromLastError();

-    }

-    gpi_func = reinterpret_cast<GetProcessIdFn*>(

-                  ::GetProcAddress(kernel32_module, "GetProcessId"));

-    if (!gpi_func) {

-      return HRESULTFromLastError();

-    }

-  }

-

-  *gpi_func_ptr = gpi_func;

-  return S_OK;

-}

-

-// Get the function pointer to NtQueryInformationProcess in NTDLL.DLL

-static HRESULT EnsureQIPFunction(NtQueryInformationProcess** qip_func_ptr) {

-  static NtQueryInformationProcess* qip_func = NULL;

-  if (!qip_func) {

-    HMODULE ntdll_module = ::GetModuleHandle(_T("ntdll.dll"));

-    if (!ntdll_module) {

-      return HRESULTFromLastError();

-    }

-    qip_func = reinterpret_cast<NtQueryInformationProcess*>(

-                  ::GetProcAddress(ntdll_module, "NtQueryInformationProcess"));

-    if (!qip_func) {

-      return HRESULTFromLastError();

-    }

-  }

-

-  *qip_func_ptr = qip_func;

-  return S_OK;

-}

-

-// Obtain the process ID from a hProcess HANDLE

-ULONG Process::GetProcessIdFromHandle(HANDLE hProcess) {

-  if (SystemInfo::IsRunningOnXPSP1OrLater()) {

-    // Thunk to the documented ::GetProcessId() API

-    GetProcessIdFn* gpi_func = NULL;

-    HRESULT hr = EnsureGPIFunction(&gpi_func);

-    if (FAILED(hr)) {

-      ASSERT(FALSE,

-             (_T("Process::GetProcessIdFromHandle - EnsureGPIFunction")

-              _T(" failed[0x%x]"), hr));

-      return 0;

-    }

-    ASSERT1(gpi_func);

-    return gpi_func(hProcess);

-  }

-

-  // For lower versions of Windows, we use undocumented

-  // function NtQueryInformationProcess to get at the PID

-  NtQueryInformationProcess* qip_func = NULL;

-  HRESULT hr = EnsureQIPFunction(&qip_func);

-  if (FAILED(hr)) {

-    ASSERT(FALSE,

-           (_T("Process::GetProcessIdFromHandle - EnsureQIPFunction")

-            _T(" failed[0x%x]"), hr));

-    return 0;

-  }

-  ASSERT1(qip_func);

-

-  PROCESS_BASIC_INFORMATION info;

-  SetZero(info);

-  if (!NT_SUCCESS(qip_func(hProcess,

-                           ProcessBasicInformation,

-                           &info,

-                           sizeof(info),

-                           NULL))) {

-    ASSERT(FALSE, (_T("Process::GetProcessIdFromHandle - ")

-                   _T("NtQueryInformationProcess failed!")));

-    return 0;

-  }

-

-  return info.UniqueProcessId;

-}

-

-// Get the command line of a process

-HRESULT Process::GetCommandLine(uint32 process_id, CString* cmd_line) {

-  ASSERT1(process_id);

-  ASSERT1(cmd_line);

-

-  // Open the process

-  scoped_process process_handle(::OpenProcess(

-                                    PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,

-                                    false,

-                                    process_id));

-  if (!process_handle) {

-    return HRESULTFromLastError();

-  }

-

-  // Obtain Process Environment Block

-  // Note that NtQueryInformationProcess is not available in Windows 95/98/ME

-  NtQueryInformationProcess* qip_func = NULL;

-  HRESULT hr = EnsureQIPFunction(&qip_func);

-

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(qip_func);

-

-  PROCESS_BASIC_INFORMATION info;

-  SetZero(info);

-  if (!NT_SUCCESS(qip_func(get(process_handle),

-                           ProcessBasicInformation,

-                           &info,

-                           sizeof(info),

-                           NULL))) {

-    return E_FAIL;

-  }

-  BYTE* peb = info.PebBaseAddress;

-

-  // Read address of parameters (see some PEB reference)

-  // TODO(omaha): use offsetof(PEB, ProcessParameters) to replace 0x10

-  // http://msdn.microsoft.com/en-us/library/aa813706.aspx

-  SIZE_T bytes_read = 0;

-  uint32 dw = 0;

-  if (!::ReadProcessMemory(get(process_handle),

-                           peb + 0x10,

-                           &dw,

-                           sizeof(dw),

-                           &bytes_read)) {

-    return HRESULTFromLastError();

-  }

-

-  // Read all the parameters

-  RTL_USER_PROCESS_PARAMETERS params;

-  SetZero(params);

-  if (!::ReadProcessMemory(get(process_handle),

-                           reinterpret_cast<PVOID>(dw),

-                           &params,

-                           sizeof(params),

-                           &bytes_read)) {

-    return HRESULTFromLastError();

-  }

-

-  // Read the command line parameter

-  const int max_cmd_line_len = std::min(

-      static_cast<int>(params.CommandLine.MaximumLength),

-      kMaxCmdLineLengthBytes);

-  if (!::ReadProcessMemory(get(process_handle),

-                           params.CommandLine.Buffer,

-                           cmd_line->GetBufferSetLength(max_cmd_line_len),

-                           max_cmd_line_len,

-                           &bytes_read)) {

-    return HRESULTFromLastError();

-  }

-

-  cmd_line->ReleaseBuffer();

-

-  return S_OK;

-}

-

-// Check if the process is running with a specified path

-bool Process::IsProcessRunningWithPath(uint32 process_id, const TCHAR* path) {

-  ASSERT1(process_id);

-  ASSERT1(path && *path);

-

-  const int kProcessWaitModuleFullyUpMs = 100;

-  const int kProcessWaitModuleRetries = 10;

-

-  // Open the process

-  scoped_process process(::OpenProcess(

-                             PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,

-                             false,

-                             process_id));

-  if (!process) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[Process::IsProcessRunningWithPath - OpenProcess failed]")

-              _T("[%u][0x%x]"),

-             process_id, HRESULTFromLastError()));

-    return false;

-  }

-

-  for (int i = 0; i < kProcessWaitModuleRetries; ++i) {

-    // Get the command line path of the main module

-    // Note that we are using psapi functions which is not supported in Windows

-    // 95/98/ME

-    //

-    // Sometimes it might be the case that the process is created but the main

-    // module is not fully loaded. If so, wait a while and then try again

-    TCHAR process_path[MAX_PATH];

-    if (::GetModuleFileNameEx(get(process),

-                              NULL,

-                              process_path,

-                              arraysize(process_path))) {

-      // Do the check

-      if (String_StartsWith(process_path, path, true)) {

-        return true;

-      }

-

-      // Try again with short form

-      TCHAR short_path[MAX_PATH];

-      if (::GetShortPathName(path, short_path, arraysize(short_path)) &&

-          String_StartsWith(process_path, short_path, true)) {

-        return true;

-      }

-

-      return false;

-    }

-

-    UTIL_LOG(LEVEL_ERROR,

-              (_T("[Process::IsProcessRunningWithPath - GetModuleFileNameEx ")

-               _T("failed][%u][0x%x]"),

-              process_id, HRESULTFromLastError()));

-

-    ::Sleep(kProcessWaitModuleFullyUpMs);

-  }

-

-  UTIL_LOG(LEVEL_ERROR,

-           (_T("[Process::IsProcessRunningWithPath - failed to get process ")

-            _T("path][%u][0x%x]"),

-            process_id, HRESULTFromLastError()));

-

-  return false;

-}

-

-// Get the process owner

-// Note that we may fail to get the owner which is not current user.

-// TODO(omaha): merge with UserInfo::GetCurrentUser

-HRESULT Process::GetProcessOwner(uint32 pid, CString* owner_sid) {

-  ASSERT1(pid);

-  ASSERT1(owner_sid);

-

-  scoped_process process(::OpenProcess(PROCESS_QUERY_INFORMATION, false, pid));

-  if (!valid(process)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[Process::GetProcessOwner - OpenProcess failed][%u][0x%x]"),

-              pid, hr));

-    return hr;

-  }

-

-  scoped_handle process_token;

-  if (!::OpenProcessToken(get(process),

-                          READ_CONTROL | TOKEN_QUERY,

-                          address(process_token))) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(L4,

-             (_T("[Process::GetProcessOwner - OpenProcessToken failed][0x%x]"),

-              hr));

-    return hr;

-  }

-

-  DWORD size_needed = 0;

-  BOOL b = ::GetTokenInformation(get(process_token),

-                                 TokenUser,

-                                 NULL,

-                                 0,

-                                 &size_needed);

-  ASSERT1(!b && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER);

-

-  scoped_array<byte> token_user(new byte[size_needed]);

-  DWORD size_returned = 0;

-  if (!::GetTokenInformation(get(process_token),

-                             TokenUser,

-                             token_user.get(),

-                             size_needed,

-                             &size_returned)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[Process::GetProcessOwner - GetTokenInformation fail][0x%x]"),

-              hr));

-    return hr;

-  }

-

-  PSID process_sid = (reinterpret_cast<TOKEN_USER*>(

-                          token_user.get()))->User.Sid;

-  ASSERT1(process_sid);

-  if (!process_sid) {

-    return E_FAIL;

-  }

-

-  TCHAR* process_sid_str = NULL;

-  if (!::ConvertSidToStringSid(process_sid, &process_sid_str)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[IsOwnedByUser - ConvertSidToStringSid failed][0x%x]"),

-              hr));

-    return hr;

-  }

-  scoped_hlocal scoped_guard_sid_str(process_sid_str);

-

-  *owner_sid = process_sid_str;

-

-  return S_OK;

-}

-

-// Creates an impersonation token for the user running process_id.

-// The caller is responsible for closing the returned handle.

-HRESULT Process::GetImpersonationToken(DWORD process_id, HANDLE* user_token) {

-  // Get a handle to the process.

-  scoped_process process(::OpenProcess(

-                             PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,

-                             TRUE,

-                             process_id));

-  if (!valid(process)) {

-    HRESULT hr(HRESULTFromLastError());

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[GetImpersonationToken - ::OpenProcess failed][0x%x]"),

-              hr));

-    return hr;

-  }

-

-  HRESULT result = S_OK;

-  scoped_handle process_token;

-  if (!::OpenProcessToken(get(process), TOKEN_DUPLICATE | TOKEN_QUERY,

-                          address(process_token))) {

-    result = HRESULTFromLastError();

-  } else {

-    if (!::DuplicateTokenEx(get(process_token),

-                            TOKEN_IMPERSONATE | TOKEN_QUERY |

-                            TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE,

-                            NULL,

-                            SecurityImpersonation,

-                            TokenPrimary,

-                            user_token)) {

-      result = HRESULTFromLastError();

-    }

-  }

-

-  ASSERT(SUCCEEDED(result), (_T("[GetImpersonationToken Failed][hr=0x%x]"),

-                             result));

-  return result;

-}

-

-HRESULT Process::GetUsersOfProcesses(const TCHAR* task_name,

-                                     int maximum_users,

-                                     scoped_handle user_tokens[],

-                                     int* number_of_users) {

-  ASSERT1(task_name && *task_name);

-  ASSERT1(maximum_users);

-  ASSERT1(user_tokens);

-  ASSERT1(number_of_users);

-

-  scoped_hfile th32cs_snapshot(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,

-                                                          0));

-  if (!valid(th32cs_snapshot)) {

-    HRESULT hr(HRESULTFromLastError());

-    UTIL_LOG(LEVEL_ERROR, (_T("[::CreateToolhelp32Snapshot fail][0x%x]"), hr));

-    return hr;

-  }

-

-  HRESULT result = S_OK;

-  *number_of_users = 0;

-  // Walk the list of processes.

-  PROCESSENTRY32 process = {0};

-  process.dwSize = sizeof(PROCESSENTRY32);

-  for (BOOL found = ::Process32First(get(th32cs_snapshot), &process); found;

-       found = ::Process32Next(get(th32cs_snapshot), &process)) {

-    // Check if it is one of the processes we are looking for.

-    if (_tcsicmp(task_name, process.szExeFile) == 0) {

-      // We match.  Get the user's token.

-      scoped_handle user_token;

-      if (FAILED(GetImpersonationToken(process.th32ProcessID,

-                                       address(user_token))))

-        continue;

-

-      // Search through the existing list to see if it's a duplicate.

-      // It's O(n^2) but we should have very few logged on users.

-      int i = 0;

-      for (; i < *number_of_users; i++) {

-        if (get(user_tokens[i]) == get(user_token)) {

-          // It's a duplicate.

-          break;

-        }

-      }

-      if (i >= *number_of_users) {

-        // It's a new one.  Add it if there's room.

-        ASSERT1(i < maximum_users);

-        if (i < maximum_users) {

-          // Release the user_token, we don't want it to be closed

-          // by the user_token destructor

-          reset(user_tokens[(*number_of_users)++], release(user_token));

-        }

-      }

-     }

-  }

-  return result;

-}

-

-HRESULT Process::GetImagePath(const CString& process_name,

-                              const CString& user_sid,

-                              CString* path) {

-  ASSERT1(path);

-

-  // Search for running processes with process_name.

-  uint32 mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER;

-  std::vector<CString> command_line;

-  std::vector<uint32> process_ids;

-  HRESULT hr = FindProcesses(mask,

-                             process_name,

-                             true,

-                             user_sid,

-                             command_line,

-                             &process_ids);

-  if (FAILED(hr)) {

-    UTIL_LOG(LEVEL_WARNING, (_T("[FindProcesses failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (process_ids.empty()) {

-    return E_FAIL;

-  }

-

-  uint32 process_id = process_ids[0];

-  UTIL_LOG(L4, (_T("[GetImagePath][pid=%d]"), process_id));

-  scoped_process process_handle(::OpenProcess(PROCESS_QUERY_INFORMATION |

-                                              PROCESS_VM_READ,

-                                              FALSE,

-                                              process_id));

-  if (!process_handle) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(L4, (_T("[OpenProcess failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  HMODULE module_handle = NULL;

-  DWORD bytes_needed = 0;

-  if (!::EnumProcessModules(get(process_handle),

-                            &module_handle,

-                            sizeof(HMODULE),

-                            &bytes_needed)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_WARNING, (_T("[EnumProcessModules failed][0x%08x]"), hr));

-    // ::EnumProcessModules from a WoW64 process fails for x64 processes. We try

-    // ::GetProcessImageFileName as a workaround here.

-    TCHAR image_name[MAX_PATH] = {0};

-    if (!GetProcessImageFileName(get(process_handle),

-                                 image_name,

-                                 arraysize(image_name))) {

-      HRESULT hr = HRESULTFromLastError();

-      UTIL_LOG(LE, (_T("[GetProcessImageFileName failed][0x%08x]"), hr));

-      return hr;

-    } else {

-      *path = image_name;

-      return S_OK;

-    }

-  }

-

-  TCHAR module_name[MAX_PATH] = {0};

-  if (!::GetModuleFileNameEx(get(process_handle),

-                             module_handle,

-                             module_name,

-                             arraysize(module_name))) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[GetModuleFileNameEx failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  *path = module_name;

-  return S_OK;

-}

-

-bool Process::IsWow64(uint32 pid) {

-  typedef BOOL (WINAPI *IsWow64Process)(HANDLE, BOOL*);

-  scoped_process handle(::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,

-                                      false,

-                                      pid));

-  if (!handle) {

-    return false;

-  }

-

-  HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));

-  if (kernel_instance == NULL) {

-    ASSERT1(false);

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LW, (_T("[::GetModuleHandle  kernel32.dll failed][0x%08x]"), hr));

-    return false;

-  }

-

-  IsWow64Process pfn = reinterpret_cast<IsWow64Process>(::GetProcAddress(

-      kernel_instance,

-      "IsWow64Process"));

-  if (!pfn) {

-    UTIL_LOG(LW, (_T("[::IsWow64Process() not found in kernel32.dll]")));

-    return false;

-  }

-

-  BOOL wow64 = FALSE;

-  if (!(*pfn)(get(handle), &wow64)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LW, (_T("[::IsWow64Process() failed][0x%08x]"), hr));

-    return false;

-  }

-

-  return (wow64 != 0);

-}

-

-HRESULT Process::MakeProcessWindowForeground(const CString& executable) {

-  UTIL_LOG(L3, (_T("[MakeProcessWindowForeground]")));

-

-  CString sid;

-  HRESULT hr = omaha::user_info::GetCurrentUser(NULL, NULL, &sid);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // This code does not handle two cases:

-  // 1. If a new process instance is starting up but there are other process

-  //    instances running, then we will not wait for the new process instance.

-  //    One way to fix this is to pass the number of expected processes to this

-  //    method.

-  // 2. If we find multiple processes, and we are able to find the windows only

-  //    for some of the processes (maybe because the rest are still starting up)

-  //    then we will only set the windows of the one that we found to the

-  //    foreground and ignore the rest.

-  bool found = false;

-  for (int retries = 0; retries < kNumRetriesToFindProcess && !found;

-       ++retries) {

-    std::vector<CString> command_lines;

-    std::vector<uint32> processes;

-    DWORD flags = EXCLUDE_CURRENT_PROCESS | INCLUDE_ONLY_PROCESS_OWNED_BY_USER;

-    hr = Process::FindProcesses(flags,

-                                executable,

-                                true,

-                                sid,

-                                command_lines,

-                                &processes);

-    if (FAILED(hr)) {

-      UTIL_LOG(LW, (_T("[FindProcesses failed][0x%08x]"), hr));

-      return hr;

-    }

-

-    UTIL_LOG(L3, (_T("[Found %d processes]"), processes.size()));

-    for (size_t i = 0; i < processes.size(); ++i) {

-      CSimpleArray<HWND> windows;

-      if (!WindowUtils::FindProcessWindows(processes[i], 0, &windows)) {

-        UTIL_LOG(L3, (_T("[FindProcessWindows failed][0x%08x]"), hr));

-        continue;

-      }

-

-      for (int j = 0; j < windows.GetSize(); ++j) {

-        if (WindowUtils::IsMainWindow(windows[j])) {

-          UTIL_LOG(L4, (_T("[Found main window of process %d]"), processes[i]));

-          WindowUtils::MakeWindowForeground(windows[j]);

-          ::FlashWindow(windows[j], true);

-          found = true;

-          break;

-        }

-      }

-    }

-

-    if (!found) {

-      ::Sleep(kFindProcessRetryIntervalMs);

-    }

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines class Process to incapsulate win32
+// functions for creation and some manipulations of
+// processes.
+
+#include "omaha/common/process.h"
+
+#include <ntsecapi.h>
+#include <psapi.h>
+#include <stierr.h>
+#include <tlhelp32.h>
+#include <vector>
+
+#ifndef NT_SUCCESS
+#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
+#endif
+
+#include "omaha/common/debug.h"
+#include "omaha/common/disk.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/window_utils.h"
+
+namespace omaha {
+
+const int kNumRetriesToFindProcess = 4;
+const int kFindProcessRetryIntervalMs = 500;
+const int kMaxCmdLineLengthBytes = 4096;
+
+// Constructor
+Process::Process(const TCHAR* name, const TCHAR* window_class_name)
+    : process_id_(0),
+      exit_code_(0),
+      number_of_restarts_(static_cast<uint32>(-1)),
+      name_(name),
+      shutdown_event_(NULL) {
+  ASSERT1(name);
+
+  command_line_ = name;
+  window_class_name_ = window_class_name;
+}
+
+// Constructor
+Process::Process(uint32 process_id)
+    : process_id_(process_id),
+      exit_code_(0),
+      number_of_restarts_(static_cast<uint32>(-1)),
+      name_(itostr(static_cast<uint32>(process_id))),
+      shutdown_event_(NULL) {
+  reset(process_, ::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
+                                false,
+                                process_id));
+  if (!valid(process_)) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[Process::Process - failed to open process][%u][0x%x]"),
+              process_id, HRESULTFromLastError()));
+  }
+}
+
+// Destructor
+Process::~Process() {
+}
+
+// Start with command params
+bool Process::Start(const TCHAR* command_line_parameters) {
+  return StartWithHwnd(command_line_parameters, NULL);
+}
+
+// Start with command params and specific hwnd
+bool Process::StartWithHwnd(const TCHAR* command_line_parameters, HWND hwnd) {
+  // command_line_parameters may be NULL
+  // hwnd may be NULL
+
+  // Can't start the same process twice in the same
+  // containing object.
+  if (Running()) {
+    return false;
+  }
+
+  // Add command line params if any.
+  if (command_line_parameters && *command_line_parameters) {
+    command_line_parameters_ = command_line_parameters;
+  }
+
+  // just reuse the existing function, don't repeat the code.
+  number_of_restarts_ = static_cast<uint32>(-1);
+  time_of_start_      = GetTickCount();
+  return Restart(hwnd);
+}
+
+// Restart with the old command params
+bool Process::Restart(HWND hwnd) {
+  // Can't start the same process twice in the same
+  // containing object.
+  if (Running()) {
+    return false;
+  }
+
+  // start the process.
+  HRESULT hr = System::ShellExecuteProcess(command_line_,
+                                           command_line_parameters_,
+                                           hwnd,
+                                           address(process_));
+
+  if (SUCCEEDED(hr)) {
+    process_id_ = GetProcessIdFromHandle(get(process_));
+    ASSERT1(process_id_);
+    number_of_restarts_++;
+  } else {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("System::ShellExecuteProcess '%s' failed with 0x%08x"),
+             command_line_, hr));
+  }
+
+  return SUCCEEDED(hr);
+}
+
+// Check if the process is running.
+bool Process::Running() const {
+  if (!get(process_)) {
+    return false;
+  }
+
+  return (::WaitForSingleObject(get(process_), 0) == WAIT_TIMEOUT);
+}
+
+// Create a job and assign the process to it
+HANDLE Process::AssignToJob() {
+  // Make sure that the process handle is valid
+  if (!get(process_)) {
+    return false;
+  }
+
+  // Create a job
+  scoped_job job(::CreateJobObject(NULL, NULL));
+  if (!valid(job)) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[Process::AssignToJob - CreateJobObject failed][0x%x]"),
+              HRESULTFromLastError()));
+    return false;
+  }
+
+  // Assign the process to the job
+  if (!::AssignProcessToJobObject(get(job), get(process_))) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[Process::AssignToJob-AssignProcessToJobObject fail][0x%x]"),
+              HRESULTFromLastError()));
+    return false;
+  }
+
+  return release(job);
+}
+
+// Wait till the process finishes
+bool Process::WaitUntilDead(uint32 timeout_msec) {
+  ASSERT1(timeout_msec);
+
+  if (!get(process_)) {
+    return false;
+  }
+
+  uint32 ret = 0;
+  if (shutdown_event_) {
+    HANDLE wait_handles[2] = {0};
+    wait_handles[0] = get(process_);
+    wait_handles[1] = shutdown_event_;
+    ret = ::WaitForMultipleObjectsEx(2,
+                                     wait_handles,
+                                     false,
+                                     timeout_msec,
+                                     true);
+  } else {
+    ret = ::WaitForSingleObjectEx(get(process_), timeout_msec, true);
+  }
+  if (ret == WAIT_OBJECT_0) {
+    UTIL_LOG(L2, (_T("[Process::WaitUntilDead - succeeded to wait process]")
+                  _T("[%s]"), GetName()));
+    return true;
+  } else if (ret == WAIT_IO_COMPLETION) {
+    UTIL_LOG(LEVEL_ERROR, (_T("[Process::WaitUntilDead-recv APC][%s][%u][%u]"),
+                           GetName(), process_id_));
+    return false;
+  } else {
+    UTIL_LOG(LEVEL_ERROR, (_T("[Process::WaitUntilDead - fail to wait process,")
+                           _T("possibly timeout][%s][%u][%u]"),
+                           GetName(), process_id_, ret));
+    return false;
+  }
+}
+
+// Wait some time till the process and all its descendent processes finish
+//
+// Background:
+//   Some process might spawn another process and get itself terminated
+// without waiting the descendant process to finish.
+//
+// Args:
+//   job:                Job to which the process is assigned
+//                       AssignToJob() will be called when NULL value is passed
+//   timeout_msec:       Timeout value in msec
+//   path_to_exclude:    Path of descendant process to excluded from waiting
+//                       (this should be in long format)
+//   exit_code:          To hold the exit code being returned
+bool Process::WaitUntilAllDead(HANDLE job,
+                               uint32 timeout_msec,
+                               const TCHAR* path_to_exclude,
+                               uint32* exit_code) {
+  ASSERT1(timeout_msec);
+
+  UTIL_LOG(L2, (_T("[Process::WaitUntilAllDead][%u][%s]"),
+                timeout_msec, path_to_exclude));
+
+  if (exit_code) {
+  *exit_code = 0;
+  }
+
+  scoped_job job_guard;
+  if (!job) {
+    reset(job_guard, AssignToJob());
+    if (!valid(job_guard)) {
+      return false;
+    }
+    job = get(job_guard);
+  }
+
+  return InternalWaitUntilAllDead(job,
+                                  timeout_msec,
+                                  path_to_exclude,
+                                  exit_code);
+}
+
+// Helper function to wait till the process and all its descendent processes
+// finish.
+bool Process::InternalWaitUntilAllDead(HANDLE job,
+                                       uint32 timeout_msec,
+                                       const TCHAR* path_to_exclude,
+                                       uint32* exit_code) {
+  ASSERT1(job);
+  ASSERT1(timeout_msec);
+
+  // Wait until current process finishes
+  if (!WaitUntilDead(timeout_msec)) {
+    return false;
+  }
+
+  // Find descendant process
+  uint32 desc_process_id = GetDescendantProcess(
+                               job,
+                               false,  // child_only
+                               exit_code != NULL,  // sole_descendent
+                               NULL,  // search_name
+                               path_to_exclude);
+
+  if (desc_process_id) {
+    // Open descendent process
+    Process desc_process(desc_process_id);
+
+    // If descendant process dies too soon, do not need to wait for it
+    if (desc_process.Running()) {
+      // Release the parent process handle
+      // This to handle the scenario that Firefox uninstall code will wait till
+      // parent process handle becomes NULL
+      reset(process_);
+
+      UTIL_LOG(L2, (_T("[Process::InternalWaitUntilAllDead]")
+                    _T("[waiting descendant process][%u]"), desc_process_id));
+
+      // Propagate the shutdown event to descendent process
+      if (shutdown_event_) {
+        desc_process.SetShutdownEvent(shutdown_event_);
+      }
+
+      // Wait till descendant process finishes
+      bool wait_ret = desc_process.InternalWaitUntilAllDead(job,
+                                                            timeout_msec,
+                                                            path_to_exclude,
+                                                            exit_code);
+
+      return wait_ret;
+    }
+  }
+
+  // Use the exit code from parent process
+  if (exit_code) {
+  VERIFY1(GetExitCode(exit_code));
+  }
+
+  // Release the parent process handle
+  reset(process_);
+
+  return true;
+}
+
+// Wait until process is dead or a windows message arrives (for use in a message
+// loop while waiting)
+HRESULT Process::WaitUntilDeadOrInterrupt(uint32 msec) {
+  if (!get(process_)) {
+    return E_FAIL;
+  }
+
+  HANDLE events[1] = { get(process_) };
+  uint32 dw = ::MsgWaitForMultipleObjects(1, events, FALSE, msec, QS_ALLEVENTS);
+  switch (dw) {
+    case WAIT_OBJECT_0:
+      return CI_S_PROCESSWAIT_DEAD;
+    case WAIT_OBJECT_0 + 1:
+      return CI_S_PROCESSWAIT_MESSAGE;
+    case WAIT_TIMEOUT:
+      return CI_S_PROCESSWAIT_TIMEOUT;
+    case WAIT_FAILED:
+    default:
+      return E_FAIL;
+  }
+}
+
+#if !SHIPPING
+CString Process::GetDebugInfo() const {
+  return debug_info_;
+}
+#endif
+
+// Return the process ID
+uint32 Process::GetId() const {
+  return process_id_;
+}
+
+// Return the process name
+const TCHAR *Process::GetName() const {
+  return name_;
+}
+
+// Return win32 handle to the process.
+HANDLE Process::GetHandle() const {
+  return get(process_);
+}
+
+// Get process exit code.
+bool Process::GetExitCode(uint32* exit_code) const {
+  ASSERT1(exit_code);
+
+  if (!get(process_)) {
+    return false;
+  }
+
+  if (!::GetExitCodeProcess(get(process_),
+                            reinterpret_cast<DWORD*>(&exit_code_))) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[Process::GetExitCode - failed to get exit code][%u][0x%x]"),
+              process_id_, HRESULTFromLastError()));
+    return false;
+  }
+  if (exit_code_ == STILL_ACTIVE) {
+    return false;
+  }
+
+  *exit_code = exit_code_;
+  return true;
+}
+
+// default implementation allows termination
+bool Process::IsTerminationAllowed() const {
+  return true;
+}
+
+// Terminate the process. If wait_for_terminate_msec == 0 return value doesn't
+// mean that the process actualy terminated. It becomes assync. operation.
+// Check the status with Running accessor function in this case.
+bool Process::Terminate(uint32 wait_for_terminate_msec) {
+  if (!Running()) {
+    return true;
+  }
+
+  if (!IsTerminationAllowed()) {
+    return false;
+  }
+
+  if (!::TerminateProcess(get(process_), 1)) {
+    return false;
+  }
+
+  return wait_for_terminate_msec ? WaitUntilDead(wait_for_terminate_msec) :
+                                   true;
+}
+
+// Default returns INFINITE means never restart.
+// Return any number of msec if overwriting
+uint32 Process::GetRestartInterval() const {
+  return INFINITE;
+}
+
+// How many times the process can be restarted
+// in case it crashes. When overriding return any
+// number or INFINITE to restart forever.
+uint32 Process::GetMaxNumberOfRestarts() const {
+  return 0;
+}
+
+// what is the time window for number of crashes returned by
+// GetMaxNumberOfRestarts(). If crashed more that this number of restarts
+// in a specified time window - do not restart it anymore.
+// Default implementation returns INFINITE which means that this is not time
+// based at all, if the process crashed more than the value returned by
+// GetMaxNumberOfRestarts it will not be restarted no matter how long it took.
+uint32 Process::GetTimeWindowForCrashes() const {
+  return INFINITE;
+}
+
+uint32 Process::GetMaxMemory() const {
+  return 0;
+}
+
+// Have we exceeded the number of maximum restarting?
+bool Process::AllowedToRestart() const {
+  uint32 max_number_of_restarts = GetMaxNumberOfRestarts();
+
+  if ((max_number_of_restarts == INFINITE) ||
+     (number_of_restarts_ < max_number_of_restarts)) {
+    return true;
+  }
+
+  // process crashed too many times. Let's look at the rate of crashes.
+  // Maybe we can "forgive" the process if it took some time for it to crash.
+  if ((::GetTickCount() - time_of_start_) < GetTimeWindowForCrashes()) {
+    return false;  // not forgiven
+  }
+
+  // Everything is forgiven. Give the process
+  // new start in life.
+  time_of_start_ = ::GetTickCount();
+  number_of_restarts_ = static_cast<uint32>(-1);
+
+  return true;
+}
+
+// Set shutdown event using in signaling the process watch
+void Process::SetShutdownEvent(HANDLE shutdown_event) {
+  ASSERT1(shutdown_event);
+
+  shutdown_event_ = shutdown_event;
+}
+
+// Set priority class to the process.
+bool Process::SetPriority(uint32 priority_class) const {
+  if (!get(process_)) {
+    return false;
+  }
+
+  VERIFY1(::SetPriorityClass(get(process_), priority_class));
+  return true;
+}
+
+// Try to get a descendant process. Return process id if found.
+uint32 Process::GetDescendantProcess(HANDLE job,
+                                     bool child_only,
+                                     bool sole_descedent,
+                                     const TCHAR* search_name,
+                                     const TCHAR* path_to_exclude) {
+  ASSERT1(job);
+
+  // Find all descendent processes
+  std::vector<ProcessInfo> descendant_processes;
+  if (FAILED(GetAllDescendantProcesses(job,
+                                       child_only,
+                                       search_name,
+                                       path_to_exclude,
+                                       &descendant_processes))) {
+    return 0;
+  }
+
+  // If more than one decendent processes is found, filter out those that are
+  // not direct children. This is because it might be the case that in a very
+  // short period of time, process A spawns B and B spawns C, and we capture
+  // both B and C.
+  std::vector<ProcessInfo> child_processes;
+  typedef std::vector<ProcessInfo>::const_iterator ProcessInfoConstIterator;
+  if (descendant_processes.size() > 1) {
+    for (ProcessInfoConstIterator it(descendant_processes.begin());
+         it != descendant_processes.end(); ++it) {
+      if (it->parent_id == process_id_) {
+        child_processes.push_back(*it);
+      }
+    }
+    if (!child_processes.empty()) {
+      descendant_processes = child_processes;
+    }
+  }
+
+  // Save the debugging information if needed
+#if !SHIPPING
+  if (sole_descedent && descendant_processes.size() > 1) {
+    debug_info_ = _T("More than one descendent process is found for process ");
+    debug_info_ += itostr(process_id_);
+    debug_info_ += _T("\n");
+    for (ProcessInfoConstIterator it(descendant_processes.begin());
+         it != descendant_processes.end(); ++it) {
+      debug_info_.AppendFormat(_T("%u %u %s\n"),
+                               it->process_id,
+                               it->parent_id,
+                               it->exe_file);
+    }
+  }
+#else
+  sole_descedent;   // unreferenced formal parameter
+#endif
+
+  return descendant_processes.empty() ? 0 : descendant_processes[0].process_id;
+}
+
+BOOL Process::IsProcessInJob(HANDLE process_handle,
+                             HANDLE job_handle,
+                             PBOOL result)  {
+  typedef BOOL (WINAPI *Fun)(HANDLE process_handle,
+                             HANDLE job_handle,
+                             PBOOL result);
+
+  HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));
+  ASSERT1(kernel_instance);
+  Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(kernel_instance,
+                                                   "IsProcessInJob"));
+  ASSERT(pfn, (_T("IsProcessInJob export not found in kernel32.dll")));
+  return pfn ? (*pfn)(process_handle, job_handle, result) : FALSE;
+}
+
+// Try to get all matching descendant processes
+HRESULT Process::GetAllDescendantProcesses(
+                     HANDLE job,
+                     bool child_only,
+                     const TCHAR* search_name,
+                     const TCHAR* path_to_exclude,
+                     std::vector<ProcessInfo>* descendant_processes) {
+  ASSERT1(job);
+  ASSERT1(descendant_processes);
+
+  // Take a snapshot
+  // Note that we do not have a seperate scoped_* type defined to wrap the
+  // handle returned by CreateToolhelp32Snapshot. So scoped_hfile with similar
+  // behavior is used.
+  scoped_hfile process_snap(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
+  if (!process_snap) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[Process::GetAllDescendantProcesses - fail to get snapshot]")
+              _T("[0x%x]"), hr));
+    return hr;
+  }
+
+  // Eumerate all processes in the snapshot
+  PROCESSENTRY32 pe32;
+  SetZero(pe32);
+  pe32.dwSize = sizeof(PROCESSENTRY32);
+  if (!::Process32First(get(process_snap), &pe32)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[Process::GetAllDescendantProcesses - failed to")
+                           _T("get first process][0x%x]"), hr));
+    return hr;
+  }
+
+  do {
+    // Skip process 0 and current process
+    if (pe32.th32ProcessID == 0 || pe32.th32ProcessID == process_id_) {
+      continue;
+    }
+
+    // If searching for child only, perform the check
+    if (child_only && pe32.th32ParentProcessID != process_id_) {
+      continue;
+    }
+
+    // Open the process
+    scoped_process process(::OpenProcess(PROCESS_QUERY_INFORMATION |
+                                         SYNCHRONIZE,
+                                         false,
+                                         pe32.th32ProcessID));
+    if (!valid(process)) {
+      continue;
+    }
+
+    // Determines whether the process is running in the specified job
+    BOOL result = FALSE;
+    if (!IsProcessInJob(get(process), job, &result) || !result) {
+      continue;
+    }
+
+    // Check whether the process is still running
+    if (::WaitForSingleObject(get(process), 0) != WAIT_TIMEOUT) {
+      continue;
+    }
+
+    // Compare the name if needed
+    if (search_name && *search_name) {
+      if (_tcsicmp(pe32.szExeFile, search_name) != 0) {
+        continue;
+      }
+    }
+
+    // If we need to exclude certain path, check it now
+    if (path_to_exclude && *path_to_exclude) {
+      if (IsProcessRunningWithPath(pe32.th32ProcessID, path_to_exclude)) {
+        continue;
+      }
+    }
+
+    // Add to the list
+    ProcessInfo proc_info;
+    proc_info.process_id = pe32.th32ProcessID;
+    proc_info.parent_id = pe32.th32ParentProcessID;
+#if !SHIPPING
+    proc_info.exe_file = pe32.szExeFile;
+#endif
+    descendant_processes->push_back(proc_info);
+  } while (::Process32Next(get(process_snap), &pe32));
+
+  return S_OK;
+}
+
+HRESULT Process::FindProcesses(uint32 exclude_mask,
+                               const TCHAR* search_name,
+                               bool search_main_executable_only,
+                               std::vector<uint32>* process_ids_found) {
+  ASSERT1(process_ids_found);
+  // Remove the only include processes owned by user mask from the exclude
+  // mask. This is needed as this is the behavior expected by the method,
+  // before the addition of the user_sid.
+  exclude_mask &= (~INCLUDE_ONLY_PROCESS_OWNED_BY_USER);
+  std::vector<CString> command_lines;
+  return FindProcesses(exclude_mask, search_name, search_main_executable_only,
+                       _T(""), command_lines, process_ids_found);
+}
+
+bool Process::IsStringPresentInList(const CString& process_command_line,
+                                    const std::vector<CString>& list) {
+  std::vector<CString>::const_iterator iter = list.begin();
+  for (; iter != list.end(); ++iter) {
+    CString value_to_find = *iter;
+
+    // If we are able to open the process command line, then we should
+    // ensure that it does not contain the value that we are looking for.
+    if (process_command_line.Find(value_to_find) != -1) {
+      // Found a match.
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// TODO(omaha): Change the implementation of this method to take in a
+// predicate that determines whether a process should be included in the
+// result set.
+HRESULT Process::FindProcesses(uint32 exclude_mask,
+                               const TCHAR* search_name,
+                               bool search_main_executable_only,
+                               const CString& user_sid,
+                               const std::vector<CString>& command_lines,
+                               std::vector<uint32>* process_ids_found) {
+  ASSERT1(search_name && *search_name);
+  ASSERT1(process_ids_found);
+  ASSERT1(!((exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING) &&
+            (exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING)));
+
+  const TCHAR* const kLocalSystemSid = _T("S-1-5-18");
+
+  // Clear the output queue
+  process_ids_found->clear();
+
+  // Get the list of process identifiers.
+  uint32 process_ids[kMaxProcesses];
+  SetZero(process_ids);
+  uint32 bytes_returned = 0;
+  if (!::EnumProcesses(reinterpret_cast<DWORD*>(process_ids),
+                       sizeof(process_ids),
+                       reinterpret_cast<DWORD*>(&bytes_returned))) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[Process::FindProcesses-fail to EnumProcesses]")
+                           _T("[0x%x]"), hr));
+    return hr;
+  }
+
+  // Enumerate all processes
+  int num_processes = bytes_returned / sizeof(process_ids[0]);
+  // We have found an elevated number of crashes in 1.2.584.15114 on what
+  // we believe are Italian systems. The first step to solving this Italian job
+  // is to assert on the condition while we are further testing this.
+  ASSERT1(num_processes <= kMaxProcesses);
+
+  // In Vista, SeDebugPrivilege is required to open the process not owned by
+  // current user. Also required for XP admins to open Local System processes
+  // with PROCESS_QUERY_INFORMATION access rights.
+  System::AdjustPrivilege(SE_DEBUG_NAME, true);
+
+  // Get ID of current process
+  uint32 curr_process_id = ::GetCurrentProcessId();
+
+  // Get SID of current user
+  CString curr_user_sid;
+  HRESULT hr = omaha::user_info::GetCurrentUser(NULL, NULL, &curr_user_sid);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  UTIL_LOG(L4, (_T("[Process::FindProcesses][processes=%d]"), num_processes));
+  for (int i = 0; i < num_processes; ++i) {
+    // Skip the system idle process.
+    if (process_ids[i] == 0) {
+      continue;
+    }
+
+    // Get the owner sid.
+    // Note that we may fail to get the owner which is not current user.
+    // So if the owner_sid is empty, the process is sure not to be owned by the
+    // current user.
+    CString owner_sid;
+    Process::GetProcessOwner(process_ids[i], &owner_sid);
+
+    if ((exclude_mask & INCLUDE_ONLY_PROCESS_OWNED_BY_USER) &&
+      owner_sid != user_sid) {
+      UTIL_LOG(L4,
+          (_T("[Excluding process as not owned by user][%d]"), process_ids[i]));
+      continue;
+    }
+
+    // Skip it if it is owned by the one specified in exclude_mask
+    if ((exclude_mask & EXCLUDE_CURRENT_PROCESS) &&
+        process_ids[i] == curr_process_id) {
+      UTIL_LOG(L4, (_T("[Excluding current process %d"), process_ids[i]));
+      continue;
+    }
+    if ((exclude_mask & EXCLUDE_PROCESS_OWNED_BY_CURRENT_USER) &&
+        owner_sid == curr_user_sid) {
+      UTIL_LOG(L4,
+          (_T("[Excluding process as owned by current user][%d]"),
+           process_ids[i]));
+      continue;
+    }
+    if ((exclude_mask & EXCLUDE_PROCESS_OWNED_BY_SYSTEM) &&
+        owner_sid == kLocalSystemSid) {
+      UTIL_LOG(L4,
+          (_T("[Excluding process as owned by system][%d]"), process_ids[i]));
+      continue;
+    }
+    if (exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING ||
+        exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING) {
+      CString process_command_line;
+      HRESULT hr = GetCommandLine(process_ids[i], &process_command_line);
+      if (FAILED(hr)) {
+        UTIL_LOG(L4,
+          (_T("[Excluding process could not get command line][%d]"),
+           process_ids[i]));
+        continue;
+      }
+
+      // If we are able to open the process command line, then we should
+      // ensure that it does not contain the value that we are looking for if
+      // we are excluding the command line or that it contains the command line
+      // that we are looking for in case the include switch is specified.
+      bool present = IsStringPresentInList(process_command_line, command_lines);
+      if ((present &&
+            (exclude_mask & EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING)) ||
+          (!present &&
+            (exclude_mask & INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING))) {
+        UTIL_LOG(L4, (_T("[Process command line matches criteria][%d]'[%s]'"),
+                 process_ids[i], process_command_line));
+        continue;
+      }
+    }
+
+    // If search_name is provided, make sure it matches
+    if (Process::IsProcessUsingExeOrDll(process_ids[i],
+                                        search_name,
+                                        search_main_executable_only)) {
+      UTIL_LOG(L4,
+          (_T("[Including process][%d][%s]"), process_ids[i], search_name));
+      process_ids_found->push_back(process_ids[i]);
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT Process::FindProcessesInSession(
+    DWORD session_id,
+    uint32 exclude_mask,
+    const TCHAR* search_name,
+    bool search_main_executable_only,
+    const CString& user_sid,
+    const std::vector<CString>& cmd_lines,
+    std::vector<uint32>* process_ids_found) {
+  HRESULT hr = FindProcesses(exclude_mask,
+                             search_name,
+                             search_main_executable_only,
+                             user_sid,
+                             cmd_lines,
+                             process_ids_found);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Filter to processes running under session_id.
+  std::vector<uint32>::iterator iter = process_ids_found->begin();
+  while (iter != process_ids_found->end()) {
+    uint32 process_pid = *iter;
+    DWORD process_session = 0;
+    hr = S_OK;
+    if (!::ProcessIdToSessionId(process_pid, &process_session)) {
+      hr = HRESULTFromLastError();
+      UTIL_LOG(LE,  (_T("[::ProcessIdToSessionId failed][0x%x]"), hr));
+    }
+
+    if (FAILED(hr) || process_session != session_id) {
+      // Remove from list and continue.
+      iter = process_ids_found->erase(iter);
+      continue;
+    }
+
+    ++iter;
+  }
+
+  return S_OK;
+}
+
+bool Process::IsModuleMatchingExeOrDll(const TCHAR* module_name,
+                                       const TCHAR* search_name,
+                                       bool is_fully_qualified_name) {
+  UTIL_LOG(L4, (_T("[Process::IsModuleMatchingExeOrDll]")
+                _T("[module=%s][search=%s]"), module_name, search_name));
+  CString module_file_name;
+  if (is_fully_qualified_name) {
+    if (FAILED(GetLongPathName(module_name, &module_file_name))) {
+      return false;
+    }
+  } else {
+    module_file_name = ::PathFindFileName(module_name);
+    ASSERT1(!module_file_name.IsEmpty());
+    if (module_file_name.IsEmpty()) {
+      return false;
+    }
+  }
+
+  return (module_file_name.CompareNoCase(search_name) == 0);
+}
+
+DWORD Process::GetProcessImageFileName(HANDLE proc_handle,
+                                       LPTSTR image_file,
+                                       DWORD file_size)  {
+  typedef DWORD (WINAPI *Fun)(HANDLE proc_handle,
+                              LPWSTR image_file,
+                              DWORD file_size);
+
+  HINSTANCE psapi_instance = ::GetModuleHandle(_T("Psapi.dll"));
+  ASSERT1(psapi_instance);
+  Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(psapi_instance,
+                                                   "GetProcessImageFileNameW"));
+  if (!pfn) {
+    UTIL_LOG(L1, (_T("::GetProcessImageFileNameW() not found in Psapi.dll")));
+    return 0;
+  }
+  return (*pfn)(proc_handle, image_file, file_size);
+}
+
+bool Process::IsProcImageMatch(HANDLE proc_handle,
+                               const TCHAR* search_name,
+                               bool is_fully_qualified_name)  {
+  TCHAR image_name[MAX_PATH] = _T("");
+  if (!GetProcessImageFileName(proc_handle,
+                               image_name,
+                               arraysize(image_name))) {
+    UTIL_LOG(L4, (_T("[GetProcessImageFileName fail[0x%x]"),
+                  HRESULTFromLastError()));
+    return false;
+  }
+
+  UTIL_LOG(L4, (_T("[GetProcessImageFileName][%s]"), image_name));
+  CString dos_name;
+  HRESULT hr(DevicePathToDosPath(image_name, &dos_name));
+  if (FAILED(hr)) {
+    UTIL_LOG(L4, (_T("[DevicePathToDosPath fail[0x%x]"), hr));
+    return false;
+  }
+
+  return IsModuleMatchingExeOrDll(dos_name,
+                                  search_name,
+                                  is_fully_qualified_name);
+}
+
+// Is the process using the specified exe/dll?
+bool Process::IsProcessUsingExeOrDll(uint32 process_id,
+                                     const TCHAR* search_name,
+                                     bool search_main_executable_only) {
+  UTIL_LOG(L4, (_T("[Process::IsProcessUsingExeOrDll]")
+                _T("[pid=%d][search_name=%s]"), process_id, search_name));
+  ASSERT1(search_name);
+
+  // Open the process
+  scoped_process process_handle(::OpenProcess(
+                                    PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+                                    FALSE,
+                                    process_id));
+  if (!process_handle) {
+    UTIL_LOG(L4, (_T("[::OpenProcess failed][0x%x]"), HRESULTFromLastError()));
+    return false;
+  }
+
+  // Does the name represent a fully qualified name?
+  // We only do a simple check here
+  bool is_fully_qualified_name = String_FindChar(search_name, _T('\\')) != -1;
+  CString long_search_name;
+  if (is_fully_qualified_name) {
+    HRESULT hr(GetLongPathName(search_name, &long_search_name));
+    if (FAILED(hr)) {
+      UTIL_LOG(L4, (_T("[GetLongPathName fail][hr=x%x]"), hr));
+      return false;
+    }
+    search_name = long_search_name;
+  }
+
+  // Take a snapshot of all modules in the specified process
+  int num_modules_to_fetch = search_main_executable_only ? 1 :
+                                                           kMaxProcessModules;
+  HMODULE module_handles[kMaxProcessModules];
+  SetZero(module_handles);
+  uint32 bytes_needed = 0;
+  if (!::EnumProcessModules(get(process_handle),
+                            module_handles,
+                            num_modules_to_fetch * sizeof(HMODULE),
+                            reinterpret_cast<DWORD*>(&bytes_needed))) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[EnumProcessModules failed][0x%x]"), hr));
+
+    if (IsWow64(::GetCurrentProcessId())) {
+      // ::EnumProcessModules from a WoW64 process fails for x64 processes.
+      // We try ::GetProcessImageFileName as a workaround here.
+      return search_main_executable_only ?
+                 IsProcImageMatch(get(process_handle),
+                                  search_name,
+                                  is_fully_qualified_name) :
+                 false;
+    } else {
+      return false;
+    }
+  }
+
+  int num_modules = bytes_needed / sizeof(HMODULE);
+  if (num_modules > num_modules_to_fetch) {
+    num_modules = num_modules_to_fetch;
+  }
+
+  for (int i = 0; i < num_modules; ++i) {
+    TCHAR module_name[MAX_PATH];
+    SetZero(module_name);
+    if (!::GetModuleFileNameEx(get(process_handle),
+                               module_handles[i],
+                               module_name,
+                               arraysize(module_name))) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[GetModuleFileNameEx fail[x%x]"),
+                             HRESULTFromLastError()));
+      continue;
+    }
+
+    if (IsModuleMatchingExeOrDll(module_name,
+                                 search_name,
+                                 is_fully_qualified_name)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// Helper function to get long path name
+HRESULT Process::GetLongPathName(const TCHAR* short_name, CString* long_name) {
+  ASSERT1(short_name);
+  ASSERT1(long_name);
+
+  TCHAR temp_name[MAX_PATH];
+  SetZero(temp_name);
+
+  HRESULT hr = S_OK;
+  if (!::GetLongPathName(short_name, temp_name, arraysize(temp_name))) {
+    hr = HRESULTFromLastError();
+  } else {
+    long_name->SetString(temp_name);
+  }
+
+  return hr;
+}
+
+// Type definitions needed for GetCommandLine() and GetProcessIdFromHandle()
+// From MSDN document on NtQueryInformationProcess() and other sources
+typedef struct _PROCESS_BASIC_INFORMATION {
+  PVOID Reserved1;
+  BYTE *PebBaseAddress;
+  PVOID Reserved2[2];
+  ULONG_PTR UniqueProcessId;
+  PVOID Reserved3;
+} PROCESS_BASIC_INFORMATION;
+
+typedef enum _PROCESSINFOCLASS {
+  ProcessBasicInformation = 0,
+  ProcessWow64Information = 26
+} PROCESSINFOCLASS;
+
+typedef WINBASEAPI DWORD WINAPI
+GetProcessIdFn(
+    HANDLE Process
+);
+
+typedef LONG WINAPI
+NtQueryInformationProcess(
+  IN HANDLE ProcessHandle,
+  IN PROCESSINFOCLASS ProcessInformationClass,
+  OUT PVOID ProcessInformation,
+  IN ULONG ProcessInformationLength,
+  OUT PULONG ReturnLength OPTIONAL
+);
+
+typedef struct _RTL_DRIVE_LETTER_CURDIR {
+  USHORT Flags;
+  USHORT Length;
+  ULONG TimeStamp;
+  UNICODE_STRING DosPath;
+} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
+
+typedef struct _RTL_USER_PROCESS_PARAMETERS {
+  ULONG MaximumLength;
+  ULONG Length;
+  ULONG Flags;
+  ULONG DebugFlags;
+  PVOID ConsoleHandle;
+  ULONG ConsoleFlags;
+  HANDLE StdInputHandle;
+  HANDLE StdOutputHandle;
+  HANDLE StdErrorHandle;
+  UNICODE_STRING CurrentDirectoryPath;
+  HANDLE CurrentDirectoryHandle;
+  UNICODE_STRING DllPath;
+  UNICODE_STRING ImagePathName;
+  UNICODE_STRING CommandLine;
+  PVOID Environment;
+  ULONG StartingPositionLeft;
+  ULONG StartingPositionTop;
+  ULONG Width;
+  ULONG Height;
+  ULONG CharWidth;
+  ULONG CharHeight;
+  ULONG ConsoleTextAttributes;
+  ULONG WindowFlags;
+  ULONG ShowWindowFlags;
+  UNICODE_STRING WindowTitle;
+  UNICODE_STRING DesktopName;
+  UNICODE_STRING ShellInfo;
+  UNICODE_STRING RuntimeData;
+  RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
+} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
+
+// Get the function pointer to GetProcessId in KERNEL32.DLL
+static HRESULT EnsureGPIFunction(GetProcessIdFn** gpi_func_ptr) {
+  static GetProcessIdFn* gpi_func = NULL;
+  if (!gpi_func) {
+    HMODULE kernel32_module = ::GetModuleHandle(_T("kernel32.dll"));
+    if (!kernel32_module) {
+      return HRESULTFromLastError();
+    }
+    gpi_func = reinterpret_cast<GetProcessIdFn*>(
+                  ::GetProcAddress(kernel32_module, "GetProcessId"));
+    if (!gpi_func) {
+      return HRESULTFromLastError();
+    }
+  }
+
+  *gpi_func_ptr = gpi_func;
+  return S_OK;
+}
+
+// Get the function pointer to NtQueryInformationProcess in NTDLL.DLL
+static HRESULT EnsureQIPFunction(NtQueryInformationProcess** qip_func_ptr) {
+  static NtQueryInformationProcess* qip_func = NULL;
+  if (!qip_func) {
+    HMODULE ntdll_module = ::GetModuleHandle(_T("ntdll.dll"));
+    if (!ntdll_module) {
+      return HRESULTFromLastError();
+    }
+    qip_func = reinterpret_cast<NtQueryInformationProcess*>(
+                  ::GetProcAddress(ntdll_module, "NtQueryInformationProcess"));
+    if (!qip_func) {
+      return HRESULTFromLastError();
+    }
+  }
+
+  *qip_func_ptr = qip_func;
+  return S_OK;
+}
+
+// Obtain the process ID from a hProcess HANDLE
+ULONG Process::GetProcessIdFromHandle(HANDLE hProcess) {
+  if (SystemInfo::IsRunningOnXPSP1OrLater()) {
+    // Thunk to the documented ::GetProcessId() API
+    GetProcessIdFn* gpi_func = NULL;
+    HRESULT hr = EnsureGPIFunction(&gpi_func);
+    if (FAILED(hr)) {
+      ASSERT(FALSE,
+             (_T("Process::GetProcessIdFromHandle - EnsureGPIFunction")
+              _T(" failed[0x%x]"), hr));
+      return 0;
+    }
+    ASSERT1(gpi_func);
+    return gpi_func(hProcess);
+  }
+
+  // For lower versions of Windows, we use undocumented
+  // function NtQueryInformationProcess to get at the PID
+  NtQueryInformationProcess* qip_func = NULL;
+  HRESULT hr = EnsureQIPFunction(&qip_func);
+  if (FAILED(hr)) {
+    ASSERT(FALSE,
+           (_T("Process::GetProcessIdFromHandle - EnsureQIPFunction")
+            _T(" failed[0x%x]"), hr));
+    return 0;
+  }
+  ASSERT1(qip_func);
+
+  PROCESS_BASIC_INFORMATION info;
+  SetZero(info);
+  if (!NT_SUCCESS(qip_func(hProcess,
+                           ProcessBasicInformation,
+                           &info,
+                           sizeof(info),
+                           NULL))) {
+    ASSERT(FALSE, (_T("Process::GetProcessIdFromHandle - ")
+                   _T("NtQueryInformationProcess failed!")));
+    return 0;
+  }
+
+  return info.UniqueProcessId;
+}
+
+// Get the command line of a process
+HRESULT Process::GetCommandLine(uint32 process_id, CString* cmd_line) {
+  ASSERT1(process_id);
+  ASSERT1(cmd_line);
+
+  // Open the process
+  scoped_process process_handle(::OpenProcess(
+                                    PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+                                    false,
+                                    process_id));
+  if (!process_handle) {
+    return HRESULTFromLastError();
+  }
+
+  // Obtain Process Environment Block
+  // Note that NtQueryInformationProcess is not available in Windows 95/98/ME
+  NtQueryInformationProcess* qip_func = NULL;
+  HRESULT hr = EnsureQIPFunction(&qip_func);
+
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(qip_func);
+
+  PROCESS_BASIC_INFORMATION info;
+  SetZero(info);
+  if (!NT_SUCCESS(qip_func(get(process_handle),
+                           ProcessBasicInformation,
+                           &info,
+                           sizeof(info),
+                           NULL))) {
+    return E_FAIL;
+  }
+  BYTE* peb = info.PebBaseAddress;
+
+  // Read address of parameters (see some PEB reference)
+  // TODO(omaha): use offsetof(PEB, ProcessParameters) to replace 0x10
+  // http://msdn.microsoft.com/en-us/library/aa813706.aspx
+  SIZE_T bytes_read = 0;
+  uint32 dw = 0;
+  if (!::ReadProcessMemory(get(process_handle),
+                           peb + 0x10,
+                           &dw,
+                           sizeof(dw),
+                           &bytes_read)) {
+    return HRESULTFromLastError();
+  }
+
+  // Read all the parameters
+  RTL_USER_PROCESS_PARAMETERS params;
+  SetZero(params);
+  if (!::ReadProcessMemory(get(process_handle),
+                           reinterpret_cast<PVOID>(dw),
+                           &params,
+                           sizeof(params),
+                           &bytes_read)) {
+    return HRESULTFromLastError();
+  }
+
+  // Read the command line parameter
+  const int max_cmd_line_len = std::min(
+      static_cast<int>(params.CommandLine.MaximumLength),
+      kMaxCmdLineLengthBytes);
+  if (!::ReadProcessMemory(get(process_handle),
+                           params.CommandLine.Buffer,
+                           cmd_line->GetBufferSetLength(max_cmd_line_len),
+                           max_cmd_line_len,
+                           &bytes_read)) {
+    return HRESULTFromLastError();
+  }
+
+  cmd_line->ReleaseBuffer();
+
+  return S_OK;
+}
+
+// Check if the process is running with a specified path
+bool Process::IsProcessRunningWithPath(uint32 process_id, const TCHAR* path) {
+  ASSERT1(process_id);
+  ASSERT1(path && *path);
+
+  const int kProcessWaitModuleFullyUpMs = 100;
+  const int kProcessWaitModuleRetries = 10;
+
+  // Open the process
+  scoped_process process(::OpenProcess(
+                             PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+                             false,
+                             process_id));
+  if (!process) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[Process::IsProcessRunningWithPath - OpenProcess failed]")
+              _T("[%u][0x%x]"),
+             process_id, HRESULTFromLastError()));
+    return false;
+  }
+
+  for (int i = 0; i < kProcessWaitModuleRetries; ++i) {
+    // Get the command line path of the main module
+    // Note that we are using psapi functions which is not supported in Windows
+    // 95/98/ME
+    //
+    // Sometimes it might be the case that the process is created but the main
+    // module is not fully loaded. If so, wait a while and then try again
+    TCHAR process_path[MAX_PATH];
+    if (::GetModuleFileNameEx(get(process),
+                              NULL,
+                              process_path,
+                              arraysize(process_path))) {
+      // Do the check
+      if (String_StartsWith(process_path, path, true)) {
+        return true;
+      }
+
+      // Try again with short form
+      TCHAR short_path[MAX_PATH];
+      if (::GetShortPathName(path, short_path, arraysize(short_path)) &&
+          String_StartsWith(process_path, short_path, true)) {
+        return true;
+      }
+
+      return false;
+    }
+
+    UTIL_LOG(LEVEL_ERROR,
+              (_T("[Process::IsProcessRunningWithPath - GetModuleFileNameEx ")
+               _T("failed][%u][0x%x]"),
+              process_id, HRESULTFromLastError()));
+
+    ::Sleep(kProcessWaitModuleFullyUpMs);
+  }
+
+  UTIL_LOG(LEVEL_ERROR,
+           (_T("[Process::IsProcessRunningWithPath - failed to get process ")
+            _T("path][%u][0x%x]"),
+            process_id, HRESULTFromLastError()));
+
+  return false;
+}
+
+// Get the process owner
+// Note that we may fail to get the owner which is not current user.
+// TODO(omaha): merge with UserInfo::GetCurrentUser
+HRESULT Process::GetProcessOwner(uint32 pid, CString* owner_sid) {
+  ASSERT1(pid);
+  ASSERT1(owner_sid);
+
+  scoped_process process(::OpenProcess(PROCESS_QUERY_INFORMATION, false, pid));
+  if (!valid(process)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[Process::GetProcessOwner - OpenProcess failed][%u][0x%x]"),
+              pid, hr));
+    return hr;
+  }
+
+  scoped_handle process_token;
+  if (!::OpenProcessToken(get(process),
+                          READ_CONTROL | TOKEN_QUERY,
+                          address(process_token))) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(L4,
+             (_T("[Process::GetProcessOwner - OpenProcessToken failed][0x%x]"),
+              hr));
+    return hr;
+  }
+
+  DWORD size_needed = 0;
+  BOOL b = ::GetTokenInformation(get(process_token),
+                                 TokenUser,
+                                 NULL,
+                                 0,
+                                 &size_needed);
+  ASSERT1(!b && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER);
+
+  scoped_array<byte> token_user(new byte[size_needed]);
+  DWORD size_returned = 0;
+  if (!::GetTokenInformation(get(process_token),
+                             TokenUser,
+                             token_user.get(),
+                             size_needed,
+                             &size_returned)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[Process::GetProcessOwner - GetTokenInformation fail][0x%x]"),
+              hr));
+    return hr;
+  }
+
+  PSID process_sid = (reinterpret_cast<TOKEN_USER*>(
+                          token_user.get()))->User.Sid;
+  ASSERT1(process_sid);
+  if (!process_sid) {
+    return E_FAIL;
+  }
+
+  TCHAR* process_sid_str = NULL;
+  if (!::ConvertSidToStringSid(process_sid, &process_sid_str)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[IsOwnedByUser - ConvertSidToStringSid failed][0x%x]"),
+              hr));
+    return hr;
+  }
+  scoped_hlocal scoped_guard_sid_str(process_sid_str);
+
+  *owner_sid = process_sid_str;
+
+  return S_OK;
+}
+
+// Creates an impersonation token for the user running process_id.
+// The caller is responsible for closing the returned handle.
+HRESULT Process::GetImpersonationToken(DWORD process_id, HANDLE* user_token) {
+  // Get a handle to the process.
+  scoped_process process(::OpenProcess(
+                             PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
+                             TRUE,
+                             process_id));
+  if (!valid(process)) {
+    HRESULT hr(HRESULTFromLastError());
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[GetImpersonationToken - ::OpenProcess failed][0x%x]"),
+              hr));
+    return hr;
+  }
+
+  HRESULT result = S_OK;
+  scoped_handle process_token;
+  if (!::OpenProcessToken(get(process), TOKEN_DUPLICATE | TOKEN_QUERY,
+                          address(process_token))) {
+    result = HRESULTFromLastError();
+  } else {
+    if (!::DuplicateTokenEx(get(process_token),
+                            TOKEN_IMPERSONATE | TOKEN_QUERY |
+                            TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE,
+                            NULL,
+                            SecurityImpersonation,
+                            TokenPrimary,
+                            user_token)) {
+      result = HRESULTFromLastError();
+    }
+  }
+
+  ASSERT(SUCCEEDED(result), (_T("[GetImpersonationToken Failed][hr=0x%x]"),
+                             result));
+  return result;
+}
+
+HRESULT Process::GetUsersOfProcesses(const TCHAR* task_name,
+                                     int maximum_users,
+                                     scoped_handle user_tokens[],
+                                     int* number_of_users) {
+  ASSERT1(task_name && *task_name);
+  ASSERT1(maximum_users);
+  ASSERT1(user_tokens);
+  ASSERT1(number_of_users);
+
+  scoped_hfile th32cs_snapshot(::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,
+                                                          0));
+  if (!valid(th32cs_snapshot)) {
+    HRESULT hr(HRESULTFromLastError());
+    UTIL_LOG(LEVEL_ERROR, (_T("[::CreateToolhelp32Snapshot fail][0x%x]"), hr));
+    return hr;
+  }
+
+  HRESULT result = S_OK;
+  *number_of_users = 0;
+  // Walk the list of processes.
+  PROCESSENTRY32 process = {0};
+  process.dwSize = sizeof(PROCESSENTRY32);
+  for (BOOL found = ::Process32First(get(th32cs_snapshot), &process); found;
+       found = ::Process32Next(get(th32cs_snapshot), &process)) {
+    // Check if it is one of the processes we are looking for.
+    if (_tcsicmp(task_name, process.szExeFile) == 0) {
+      // We match.  Get the user's token.
+      scoped_handle user_token;
+      if (FAILED(GetImpersonationToken(process.th32ProcessID,
+                                       address(user_token))))
+        continue;
+
+      // Search through the existing list to see if it's a duplicate.
+      // It's O(n^2) but we should have very few logged on users.
+      int i = 0;
+      for (; i < *number_of_users; i++) {
+        if (get(user_tokens[i]) == get(user_token)) {
+          // It's a duplicate.
+          break;
+        }
+      }
+      if (i >= *number_of_users) {
+        // It's a new one.  Add it if there's room.
+        ASSERT1(i < maximum_users);
+        if (i < maximum_users) {
+          // Release the user_token, we don't want it to be closed
+          // by the user_token destructor
+          reset(user_tokens[(*number_of_users)++], release(user_token));
+        }
+      }
+     }
+  }
+  return result;
+}
+
+HRESULT Process::GetImagePath(const CString& process_name,
+                              const CString& user_sid,
+                              CString* path) {
+  ASSERT1(path);
+
+  // Search for running processes with process_name.
+  uint32 mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
+  std::vector<CString> command_line;
+  std::vector<uint32> process_ids;
+  HRESULT hr = FindProcesses(mask,
+                             process_name,
+                             true,
+                             user_sid,
+                             command_line,
+                             &process_ids);
+  if (FAILED(hr)) {
+    UTIL_LOG(LEVEL_WARNING, (_T("[FindProcesses failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (process_ids.empty()) {
+    return E_FAIL;
+  }
+
+  uint32 process_id = process_ids[0];
+  UTIL_LOG(L4, (_T("[GetImagePath][pid=%d]"), process_id));
+  scoped_process process_handle(::OpenProcess(PROCESS_QUERY_INFORMATION |
+                                              PROCESS_VM_READ,
+                                              FALSE,
+                                              process_id));
+  if (!process_handle) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(L4, (_T("[OpenProcess failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  HMODULE module_handle = NULL;
+  DWORD bytes_needed = 0;
+  if (!::EnumProcessModules(get(process_handle),
+                            &module_handle,
+                            sizeof(HMODULE),
+                            &bytes_needed)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_WARNING, (_T("[EnumProcessModules failed][0x%08x]"), hr));
+    // ::EnumProcessModules from a WoW64 process fails for x64 processes. We try
+    // ::GetProcessImageFileName as a workaround here.
+    TCHAR image_name[MAX_PATH] = {0};
+    if (!GetProcessImageFileName(get(process_handle),
+                                 image_name,
+                                 arraysize(image_name))) {
+      HRESULT hr = HRESULTFromLastError();
+      UTIL_LOG(LE, (_T("[GetProcessImageFileName failed][0x%08x]"), hr));
+      return hr;
+    } else {
+      *path = image_name;
+      return S_OK;
+    }
+  }
+
+  TCHAR module_name[MAX_PATH] = {0};
+  if (!::GetModuleFileNameEx(get(process_handle),
+                             module_handle,
+                             module_name,
+                             arraysize(module_name))) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[GetModuleFileNameEx failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  *path = module_name;
+  return S_OK;
+}
+
+bool Process::IsWow64(uint32 pid) {
+  typedef BOOL (WINAPI *IsWow64Process)(HANDLE, BOOL*);
+  scoped_process handle(::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
+                                      false,
+                                      pid));
+  if (!handle) {
+    return false;
+  }
+
+  HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));
+  if (kernel_instance == NULL) {
+    ASSERT1(false);
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LW, (_T("[::GetModuleHandle  kernel32.dll failed][0x%08x]"), hr));
+    return false;
+  }
+
+  IsWow64Process pfn = reinterpret_cast<IsWow64Process>(::GetProcAddress(
+      kernel_instance,
+      "IsWow64Process"));
+  if (!pfn) {
+    UTIL_LOG(LW, (_T("[::IsWow64Process() not found in kernel32.dll]")));
+    return false;
+  }
+
+  BOOL wow64 = FALSE;
+  if (!(*pfn)(get(handle), &wow64)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LW, (_T("[::IsWow64Process() failed][0x%08x]"), hr));
+    return false;
+  }
+
+  return (wow64 != 0);
+}
+
+HRESULT Process::MakeProcessWindowForeground(const CString& executable) {
+  UTIL_LOG(L3, (_T("[MakeProcessWindowForeground]")));
+
+  CString sid;
+  HRESULT hr = omaha::user_info::GetCurrentUser(NULL, NULL, &sid);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // This code does not handle two cases:
+  // 1. If a new process instance is starting up but there are other process
+  //    instances running, then we will not wait for the new process instance.
+  //    One way to fix this is to pass the number of expected processes to this
+  //    method.
+  // 2. If we find multiple processes, and we are able to find the windows only
+  //    for some of the processes (maybe because the rest are still starting up)
+  //    then we will only set the windows of the one that we found to the
+  //    foreground and ignore the rest.
+  bool found = false;
+  for (int retries = 0; retries < kNumRetriesToFindProcess && !found;
+       ++retries) {
+    std::vector<CString> command_lines;
+    std::vector<uint32> processes;
+    DWORD flags = EXCLUDE_CURRENT_PROCESS | INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
+    hr = Process::FindProcesses(flags,
+                                executable,
+                                true,
+                                sid,
+                                command_lines,
+                                &processes);
+    if (FAILED(hr)) {
+      UTIL_LOG(LW, (_T("[FindProcesses failed][0x%08x]"), hr));
+      return hr;
+    }
+
+    UTIL_LOG(L3, (_T("[Found %d processes]"), processes.size()));
+    for (size_t i = 0; i < processes.size(); ++i) {
+      CSimpleArray<HWND> windows;
+      if (!WindowUtils::FindProcessWindows(processes[i], 0, &windows)) {
+        UTIL_LOG(L3, (_T("[FindProcessWindows failed][0x%08x]"), hr));
+        continue;
+      }
+
+      for (int j = 0; j < windows.GetSize(); ++j) {
+        if (WindowUtils::IsMainWindow(windows[j])) {
+          UTIL_LOG(L4, (_T("[Found main window of process %d]"), processes[i]));
+          WindowUtils::MakeWindowForeground(windows[j]);
+          ::FlashWindow(windows[j], true);
+          found = true;
+          break;
+        }
+      }
+    }
+
+    if (!found) {
+      ::Sleep(kFindProcessRetryIntervalMs);
+    }
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/common/process.h b/common/process.h
index bd545c5..4cabdf8 100644
--- a/common/process.h
+++ b/common/process.h
@@ -1,306 +1,306 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Declares class Process to incapsulate win32

-// functions for creation and some manipulations of

-// processes.

-

-#ifndef OMAHA_COMMON_PROCESS_H__

-#define OMAHA_COMMON_PROCESS_H__

-

-#include <windows.h>

-#include <psapi.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/commontypes.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/scoped_any.h"

-

-namespace omaha {

-

-const int kMaxProcesses = 1024;

-const int kMaxProcessModules = 1024;

-

-// Exclude mask for finding processes.

-enum FindProcessesExcludeMask {

-  EXCLUDE_NONE = 0,

-  EXCLUDE_CURRENT_PROCESS = 0x1,

-  EXCLUDE_PROCESS_OWNED_BY_CURRENT_USER = 0x2,

-  EXCLUDE_PROCESS_OWNED_BY_SYSTEM = 0x4,

-  INCLUDE_ONLY_PROCESS_OWNED_BY_USER = 0x08,

-  EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING = 0x10,

-  INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING = 0x20

-};

-

-// Process info used in finding descendent processes.

-struct ProcessInfo {

-  uint32 process_id;

-  uint32 parent_id;

-#if !SHIPPING

-  CString exe_file;

-#endif

-};

-

-// Process class

-class Process {

- public:

-  // Constructor

-  // Init the process object with the executable name

-  // and if known the window class name of the process.

-  // If window_class_name is known it will be easy

-  // to stop the process just by sending messages to

-  // a window.

-  Process(const TCHAR* name, const TCHAR* window_class_name);

-

-  // Constructor.

-  // Init the process object with the process id.

-  explicit Process(uint32 process_id);

-

-  // Destructor

-  virtual ~Process();

-

-  // Start the process with some command line params if any.

-  virtual bool Start(const TCHAR* command_line_parameters);

-

-  // Start with command params and specific hwnd.

-  virtual bool StartWithHwnd(const TCHAR* command_line_parameters, HWND hwnd);

-

-  // Restart the process with the old command line params.

-  bool Restart(HWND hwnd);

-

-  // Set shutdown event using in signaling the process watch.

-  void SetShutdownEvent(HANDLE shutdown_event);

-

-  // Sets the specified priority class to the process.

-  bool SetPriority(uint32 priority_class) const;

-

-  // Check if the process is running.

-  bool Running() const;

-

-  // Create a job and assign the process to it.

-  HANDLE AssignToJob();

-

-  // Wait some time till the process finishes.

-  bool WaitUntilDead(uint32 timeout_msec);

-

-  // Wait some time till the process and all its descendent processes finish.

-  bool WaitUntilAllDead(HANDLE job,

-                        uint32 timeout_msec,

-                        const TCHAR* path_to_exclude,

-                        uint32* exit_code);

-

-  // Wait until process is dead or a windows message arrives. For use in a

-  // message loop while waiting.

-  HRESULT WaitUntilDeadOrInterrupt(uint32 msec);

-  // Return values include CI_S_PROCESSWAIT_DEAD, CI_S_PROCESSWAIT_TIMEOUT,

-  // CI_S_PROCESSWAIT_MESSAGE.

-

-#if !SHIPPING

-  CString GetDebugInfo() const;

-#endif

-

-  // Return the process ID.

-  uint32 GetId() const;

-

-  // Return a readable representation of the process's name.

-  const TCHAR *GetName() const;

-

-  // Get win32 handle to process.

-  HANDLE GetHandle() const;

-

-  // Get process exit code.

-  bool GetExitCode(uint32* exit_code) const;

-

-  // can we kill the process via terminating

-  // some processes are not safe to terminate.

-  virtual bool IsTerminationAllowed() const;

-

-  // Second, more rude method to stop the process. window_class_name was

-  // not given or CloseWithMessage didn't succeed.

-  bool Terminate(uint32 wait_for_terminate_msec);

-

-  // Try to get a descendant process. Return process id if found.

-  uint32 GetDescendantProcess(HANDLE job,

-                              bool child_only,

-                              bool sole_descedent,

-                              const TCHAR* search_name,

-                              const TCHAR* path_to_exclude);

-

-  // Dynamically links and calls ::IsProcessInJob() in kernel32.dll.

-  static BOOL IsProcessInJob(HANDLE process_handle,

-                             HANDLE job_handle,

-                             PBOOL result);

-

-  // Try to get all matching descendant processes.

-  HRESULT GetAllDescendantProcesses(

-      HANDLE job,

-      bool child_only,

-      const TCHAR* search_name,

-      const TCHAR* path_to_exclude,

-      std::vector<ProcessInfo>* descendant_proc_ids);

-

-  // Finds the processes based on passed criteria.

-  static HRESULT FindProcesses(uint32 exclude_mask,

-                               const TCHAR* search_name,

-                               bool search_main_executable_only,

-                               std::vector<uint32>* process_ids_found);

-

-  // Find processes which loads the specified exe/dll. Uses the user_sid only

-  // if the INCLUDE_ONLY_PROCESS_OWNED_BY_USER flag has been set.

-  // The command_line is only used when

-  // EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING is set.

-  static HRESULT FindProcesses(uint32 exclude_mask,

-                               const TCHAR* search_name,

-                               bool search_main_executable_only,

-                               const CString& user_sid,

-                               const std::vector<CString>& command_line,

-                               std::vector<uint32>* process_ids_found);

-

-  // Find processes with the specified criteria running in specific session.

-  static HRESULT FindProcessesInSession(DWORD session_id,

-                                        uint32 exclude_mask,

-                                        const TCHAR* search_name,

-                                        bool search_main_executable_only,

-                                        const CString& user_sid,

-                                        const std::vector<CString>& cmd_lines,

-                                        std::vector<uint32>* process_ids_found);

-

-  // Is the process using the specified exe/dll.

-  static bool IsProcessUsingExeOrDll(uint32 process_id,

-                                     const TCHAR* search_name,

-                                     bool search_main_executable_only);

-

-  // Obtain the process ID from a hProcess HANDLE.

-  static ULONG GetProcessIdFromHandle(HANDLE hProcess);

-

-  // Get the command line of a process.

-  static HRESULT GetCommandLine(uint32 process_id, CString* cmd_line);

-

-  // Get the process owner.

-  static HRESULT GetProcessOwner(uint32 pid, CString* owner_sid);

-

-  // Creates an impersonation token for the user running process_id.

-  // The caller is responsible for closing the returned handle.

-  static HRESULT GetImpersonationToken(DWORD process_id, HANDLE* user_token);

-

-  // Returns user token handles for the users currently running the named task.

-  // maximum_users specifies the maximun number of handles to be retured.

-  // The actual number filled is returned.

-  static HRESULT GetUsersOfProcesses(const TCHAR* task_name,

-                                     int maximum_users,

-                                     scoped_handle users[],

-                                     int* number_of_users);

-

-  // Gets the on disk path from where the process image is loaded.

-  static HRESULT GetImagePath(const CString& process_name,

-                              const CString& user_sid,

-                              CString* path);

-

-  // Returns if the process is running under WOW64.

-  static bool IsWow64(uint32 pid);

-

- public:

-  // How many times the process can be restarted in case it crashes.

-  virtual uint32 GetMaxNumberOfRestarts() const;

-

-  // Maximum amount of memory process is allowed to use before it's killed.

-  // Default of 0 means unlimited.

-  virtual uint32 GetMaxMemory() const;

-

-  // Have we exceeded the number of maximum restarting.

-  bool AllowedToRestart() const;

-

-  // In case of crash, how soon to restart.

-  virtual uint32 GetRestartInterval() const;

-

-  // The idea is the following. Each process has maximum number of restarts.

-  // As soon as the process reaches that number of restarts in should no longer

-  // be restarted unless the time window in which the process was crashing is

-  // more than the value returned by this function. For example:

-  // Process X returns 3 from the function GetMaxNumberOfRestarts.

-  // The same process returns 30*1000*60 (30 minutes) from

-  // GetTimeWindowForCrashes if  process X crashed more than 3 times in 30

-  // minutes it will not be restarted. if it took more than 30 minutes for

-  // process X to crash more than 3 times - internal counters for number of

-  // crashes will be reset and the process will be happily restarted.

-  // Each derived process can override this function to return its own time

-  // window for crashes.

-  // Default implementation returns INFINITE which means that this is not time

-  // based at all, if the process crashed more than the value returned by

-  // GetMaxNumberOfRestarts it will not be restarted no matter how long it took.

-  virtual uint32 GetTimeWindowForCrashes() const;

-

-  // Sets the main window of all process instances to the foreground.

-  static HRESULT MakeProcessWindowForeground(const CString& executable);

-

- private:

-  mutable uint32 number_of_restarts_;

-  CString command_line_;

-  CString command_line_parameters_;

-  CString window_class_name_;

-  CString name_;

-  scoped_process process_;

-  uint32 process_id_;

-  mutable uint32 time_of_start_;

-  mutable uint32 exit_code_;

-  HANDLE shutdown_event_;

-

-  // Helper function to wait till the process and all its descendent processes

-  // finish.

-  bool InternalWaitUntilAllDead(HANDLE job,

-                                uint32 timeout_msec,

-                                const TCHAR* path_to_exclude,

-                                uint32* exit_code);

-

-  // Check if the process is running with a specified path.

-  static bool IsProcessRunningWithPath(uint32 process_id, const TCHAR* path);

-

-  // Checks if the command line of the process has been specified as one to

-  // ignore.

-  static bool IsStringPresentInList(const CString& process_command_line,

-                                    const std::vector<CString>& list);

-

-

-  // Helper function to get long path name.

-  static HRESULT GetLongPathName(const TCHAR* short_name, CString* long_name);

-

-  // Helper for Process::IsProcessUsingExeOrDll(). Use GetProcessImageFileName

-  // to get the filename, and match against search_name.

-  static bool IsProcImageMatch(HANDLE proc_handle,

-                               const TCHAR* search_name,

-                               bool is_fully_qualified_name);

-

-  // Dynamically links and calls ::GetProcessImageFileName() in psapi.dll.

-  static DWORD GetProcessImageFileName(HANDLE proc_handle,

-                                       LPTSTR image_file,

-                                       DWORD file_size);

-

-  // Helper for Process::IsProcessUsingExeOrDll().

-  // Is there a match between the module and the specified exe/dll?

-  static bool IsModuleMatchingExeOrDll(const TCHAR* module_name,

-                                       const TCHAR* search_name,

-                                       bool is_fully_qualified_name);

-

-#if !SHIPPING

-  CString debug_info_;

-#endif

-  DISALLOW_EVIL_CONSTRUCTORS(Process);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_PROCESS_H__

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Declares class Process to incapsulate win32
+// functions for creation and some manipulations of
+// processes.
+
+#ifndef OMAHA_COMMON_PROCESS_H__
+#define OMAHA_COMMON_PROCESS_H__
+
+#include <windows.h>
+#include <psapi.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/commontypes.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/scoped_any.h"
+
+namespace omaha {
+
+const int kMaxProcesses = 1024;
+const int kMaxProcessModules = 1024;
+
+// Exclude mask for finding processes.
+enum FindProcessesExcludeMask {
+  EXCLUDE_NONE = 0,
+  EXCLUDE_CURRENT_PROCESS = 0x1,
+  EXCLUDE_PROCESS_OWNED_BY_CURRENT_USER = 0x2,
+  EXCLUDE_PROCESS_OWNED_BY_SYSTEM = 0x4,
+  INCLUDE_ONLY_PROCESS_OWNED_BY_USER = 0x08,
+  EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING = 0x10,
+  INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING = 0x20
+};
+
+// Process info used in finding descendent processes.
+struct ProcessInfo {
+  uint32 process_id;
+  uint32 parent_id;
+#if !SHIPPING
+  CString exe_file;
+#endif
+};
+
+// Process class
+class Process {
+ public:
+  // Constructor
+  // Init the process object with the executable name
+  // and if known the window class name of the process.
+  // If window_class_name is known it will be easy
+  // to stop the process just by sending messages to
+  // a window.
+  Process(const TCHAR* name, const TCHAR* window_class_name);
+
+  // Constructor.
+  // Init the process object with the process id.
+  explicit Process(uint32 process_id);
+
+  // Destructor
+  virtual ~Process();
+
+  // Start the process with some command line params if any.
+  virtual bool Start(const TCHAR* command_line_parameters);
+
+  // Start with command params and specific hwnd.
+  virtual bool StartWithHwnd(const TCHAR* command_line_parameters, HWND hwnd);
+
+  // Restart the process with the old command line params.
+  bool Restart(HWND hwnd);
+
+  // Set shutdown event using in signaling the process watch.
+  void SetShutdownEvent(HANDLE shutdown_event);
+
+  // Sets the specified priority class to the process.
+  bool SetPriority(uint32 priority_class) const;
+
+  // Check if the process is running.
+  bool Running() const;
+
+  // Create a job and assign the process to it.
+  HANDLE AssignToJob();
+
+  // Wait some time till the process finishes.
+  bool WaitUntilDead(uint32 timeout_msec);
+
+  // Wait some time till the process and all its descendent processes finish.
+  bool WaitUntilAllDead(HANDLE job,
+                        uint32 timeout_msec,
+                        const TCHAR* path_to_exclude,
+                        uint32* exit_code);
+
+  // Wait until process is dead or a windows message arrives. For use in a
+  // message loop while waiting.
+  HRESULT WaitUntilDeadOrInterrupt(uint32 msec);
+  // Return values include CI_S_PROCESSWAIT_DEAD, CI_S_PROCESSWAIT_TIMEOUT,
+  // CI_S_PROCESSWAIT_MESSAGE.
+
+#if !SHIPPING
+  CString GetDebugInfo() const;
+#endif
+
+  // Return the process ID.
+  uint32 GetId() const;
+
+  // Return a readable representation of the process's name.
+  const TCHAR *GetName() const;
+
+  // Get win32 handle to process.
+  HANDLE GetHandle() const;
+
+  // Get process exit code.
+  bool GetExitCode(uint32* exit_code) const;
+
+  // can we kill the process via terminating
+  // some processes are not safe to terminate.
+  virtual bool IsTerminationAllowed() const;
+
+  // Second, more rude method to stop the process. window_class_name was
+  // not given or CloseWithMessage didn't succeed.
+  bool Terminate(uint32 wait_for_terminate_msec);
+
+  // Try to get a descendant process. Return process id if found.
+  uint32 GetDescendantProcess(HANDLE job,
+                              bool child_only,
+                              bool sole_descedent,
+                              const TCHAR* search_name,
+                              const TCHAR* path_to_exclude);
+
+  // Dynamically links and calls ::IsProcessInJob() in kernel32.dll.
+  static BOOL IsProcessInJob(HANDLE process_handle,
+                             HANDLE job_handle,
+                             PBOOL result);
+
+  // Try to get all matching descendant processes.
+  HRESULT GetAllDescendantProcesses(
+      HANDLE job,
+      bool child_only,
+      const TCHAR* search_name,
+      const TCHAR* path_to_exclude,
+      std::vector<ProcessInfo>* descendant_proc_ids);
+
+  // Finds the processes based on passed criteria.
+  static HRESULT FindProcesses(uint32 exclude_mask,
+                               const TCHAR* search_name,
+                               bool search_main_executable_only,
+                               std::vector<uint32>* process_ids_found);
+
+  // Find processes which loads the specified exe/dll. Uses the user_sid only
+  // if the INCLUDE_ONLY_PROCESS_OWNED_BY_USER flag has been set.
+  // The command_line is only used when
+  // EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING is set.
+  static HRESULT FindProcesses(uint32 exclude_mask,
+                               const TCHAR* search_name,
+                               bool search_main_executable_only,
+                               const CString& user_sid,
+                               const std::vector<CString>& command_line,
+                               std::vector<uint32>* process_ids_found);
+
+  // Find processes with the specified criteria running in specific session.
+  static HRESULT FindProcessesInSession(DWORD session_id,
+                                        uint32 exclude_mask,
+                                        const TCHAR* search_name,
+                                        bool search_main_executable_only,
+                                        const CString& user_sid,
+                                        const std::vector<CString>& cmd_lines,
+                                        std::vector<uint32>* process_ids_found);
+
+  // Is the process using the specified exe/dll.
+  static bool IsProcessUsingExeOrDll(uint32 process_id,
+                                     const TCHAR* search_name,
+                                     bool search_main_executable_only);
+
+  // Obtain the process ID from a hProcess HANDLE.
+  static ULONG GetProcessIdFromHandle(HANDLE hProcess);
+
+  // Get the command line of a process.
+  static HRESULT GetCommandLine(uint32 process_id, CString* cmd_line);
+
+  // Get the process owner.
+  static HRESULT GetProcessOwner(uint32 pid, CString* owner_sid);
+
+  // Creates an impersonation token for the user running process_id.
+  // The caller is responsible for closing the returned handle.
+  static HRESULT GetImpersonationToken(DWORD process_id, HANDLE* user_token);
+
+  // Returns user token handles for the users currently running the named task.
+  // maximum_users specifies the maximun number of handles to be retured.
+  // The actual number filled is returned.
+  static HRESULT GetUsersOfProcesses(const TCHAR* task_name,
+                                     int maximum_users,
+                                     scoped_handle users[],
+                                     int* number_of_users);
+
+  // Gets the on disk path from where the process image is loaded.
+  static HRESULT GetImagePath(const CString& process_name,
+                              const CString& user_sid,
+                              CString* path);
+
+  // Returns if the process is running under WOW64.
+  static bool IsWow64(uint32 pid);
+
+ public:
+  // How many times the process can be restarted in case it crashes.
+  virtual uint32 GetMaxNumberOfRestarts() const;
+
+  // Maximum amount of memory process is allowed to use before it's killed.
+  // Default of 0 means unlimited.
+  virtual uint32 GetMaxMemory() const;
+
+  // Have we exceeded the number of maximum restarting.
+  bool AllowedToRestart() const;
+
+  // In case of crash, how soon to restart.
+  virtual uint32 GetRestartInterval() const;
+
+  // The idea is the following. Each process has maximum number of restarts.
+  // As soon as the process reaches that number of restarts in should no longer
+  // be restarted unless the time window in which the process was crashing is
+  // more than the value returned by this function. For example:
+  // Process X returns 3 from the function GetMaxNumberOfRestarts.
+  // The same process returns 30*1000*60 (30 minutes) from
+  // GetTimeWindowForCrashes if  process X crashed more than 3 times in 30
+  // minutes it will not be restarted. if it took more than 30 minutes for
+  // process X to crash more than 3 times - internal counters for number of
+  // crashes will be reset and the process will be happily restarted.
+  // Each derived process can override this function to return its own time
+  // window for crashes.
+  // Default implementation returns INFINITE which means that this is not time
+  // based at all, if the process crashed more than the value returned by
+  // GetMaxNumberOfRestarts it will not be restarted no matter how long it took.
+  virtual uint32 GetTimeWindowForCrashes() const;
+
+  // Sets the main window of all process instances to the foreground.
+  static HRESULT MakeProcessWindowForeground(const CString& executable);
+
+ private:
+  mutable uint32 number_of_restarts_;
+  CString command_line_;
+  CString command_line_parameters_;
+  CString window_class_name_;
+  CString name_;
+  scoped_process process_;
+  uint32 process_id_;
+  mutable uint32 time_of_start_;
+  mutable uint32 exit_code_;
+  HANDLE shutdown_event_;
+
+  // Helper function to wait till the process and all its descendent processes
+  // finish.
+  bool InternalWaitUntilAllDead(HANDLE job,
+                                uint32 timeout_msec,
+                                const TCHAR* path_to_exclude,
+                                uint32* exit_code);
+
+  // Check if the process is running with a specified path.
+  static bool IsProcessRunningWithPath(uint32 process_id, const TCHAR* path);
+
+  // Checks if the command line of the process has been specified as one to
+  // ignore.
+  static bool IsStringPresentInList(const CString& process_command_line,
+                                    const std::vector<CString>& list);
+
+
+  // Helper function to get long path name.
+  static HRESULT GetLongPathName(const TCHAR* short_name, CString* long_name);
+
+  // Helper for Process::IsProcessUsingExeOrDll(). Use GetProcessImageFileName
+  // to get the filename, and match against search_name.
+  static bool IsProcImageMatch(HANDLE proc_handle,
+                               const TCHAR* search_name,
+                               bool is_fully_qualified_name);
+
+  // Dynamically links and calls ::GetProcessImageFileName() in psapi.dll.
+  static DWORD GetProcessImageFileName(HANDLE proc_handle,
+                                       LPTSTR image_file,
+                                       DWORD file_size);
+
+  // Helper for Process::IsProcessUsingExeOrDll().
+  // Is there a match between the module and the specified exe/dll?
+  static bool IsModuleMatchingExeOrDll(const TCHAR* module_name,
+                                       const TCHAR* search_name,
+                                       bool is_fully_qualified_name);
+
+#if !SHIPPING
+  CString debug_info_;
+#endif
+  DISALLOW_EVIL_CONSTRUCTORS(Process);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_PROCESS_H__
+
diff --git a/common/process_unittest.cc b/common/process_unittest.cc
index 99d93ae..ae2a176 100644
--- a/common/process_unittest.cc
+++ b/common/process_unittest.cc
@@ -1,217 +1,217 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Process unit tests.

-

-#include <vector>

-

-#include "omaha/common/app_util.h"

-#include "omaha/common/path.h"

-#include "omaha/common/process.h"

-#include "omaha/common/user_info.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-const int kWaitUntilDeadMs = 10000;

-

-// Process class that terminates the associated process when deleted.

-class ScopedProcess : public Process {

- public:

-  explicit ScopedProcess(const TCHAR* name) : Process(name, NULL) {}

-  virtual ~ScopedProcess() {

-    Terminate(0);

-    EXPECT_TRUE(WaitUntilDead(kWaitUntilDeadMs));

-  }

-};

-

-TEST(ProcessTest, StartOneProcess) {

-  const TCHAR kExecutableName[] = _T("cmd.exe");

-  const TCHAR kExecutableArguments[] = _T("/c exit 702");

-  const int kExpectedExitCode = 702;

-

-  CString path = ConcatenatePath(app_util::GetSystemDir(), kExecutableName);

-  ScopedProcess process(path);

-

-  ASSERT_TRUE(process.Start(kExecutableArguments));

-  EXPECT_TRUE(process.WaitUntilDead(kWaitUntilDeadMs));

-

-  // Check the exit code to get some assurance that the process actually ran.

-  uint32 exit_code = 0;

-  EXPECT_TRUE(process.GetExitCode(&exit_code));

-  EXPECT_EQ(kExpectedExitCode, exit_code);

-}

-

-// Dummy process to spin off and then find.  The numeric argument will make

-// netstat run until it's killed by the ScopedProcess destructor.

-const TCHAR kTestExecutable[] = _T("netstat.exe");

-const TCHAR kTestArguments[] = _T("10");

-const TCHAR kTestExcludeArguments[] = _T("-o 20");

-const TCHAR kTestExcludeString[] = _T("20");

-const TCHAR kTestIncludeArguments[] = _T("-o 30");

-const TCHAR kTestIncludeString[] = _T("30");

-const int kWaitForProcessStartMs = 500;

-const int kMaxWaitIterations = 10;

-

-TEST(ProcessTest, FindOneProcess) {

-  CString path = ConcatenatePath(app_util::GetSystemDir(), kTestExecutable);

-  ScopedProcess process(path);

-  ASSERT_TRUE(process.Start(kTestArguments));

-  for (int i = 0; i < kMaxWaitIterations; ++i) {

-    ::Sleep(kWaitForProcessStartMs);

-    if (process.Running())

-      break;

-  }

-  EXPECT_TRUE(process.Running());

-

-  // Try to find the test process.

-  uint32 exclude_mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER;

-  CString user_sid;

-  std::vector<CString> command_lines;

-  std::vector<uint32> process_ids;

-

-  ASSERT_SUCCEEDED(omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid));

-

-  // This test intermittently fails to find the process when run on Pulse.

-  // This code attempts to ensure that the process is further along in the

-  // initialization process by waiting until Process::GetCommandLine succeeds.

-  // This test case does not result in FindProcesses using GetCommandLine, but

-  // waiting until this point may be enough to address the intermitent failures.

-  HRESULT hr = E_FAIL;

-  CString process_cmd;

-  for (int tries = 0; tries < 100 && FAILED(hr); ++tries) {

-    ::Sleep(50);

-    hr = Process::GetCommandLine(process.GetId(), &process_cmd);

-  }

-  EXPECT_SUCCEEDED(hr);

-

-  ASSERT_SUCCEEDED(Process::FindProcesses(exclude_mask,

-                                          kTestExecutable,

-                                          true,

-                                          user_sid,

-                                          command_lines,

-                                          &process_ids));

-  ASSERT_EQ(1, process_ids.size());  // Exit before accessing invalid element.

-  EXPECT_EQ(process.GetId(), process_ids[0]);

-}

-

-TEST(ProcessTest, ExcludeProcess) {

-  // Make sure the test process is not already running.

-  uint32 exclude_mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER;

-  CString user_sid;

-  std::vector<CString> command_lines;

-  std::vector<uint32> process_ids;

-

-  ASSERT_SUCCEEDED(omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid));

-  ASSERT_SUCCEEDED(Process::FindProcesses(exclude_mask,

-                                          kTestExecutable,

-                                          true,

-                                          user_sid,

-                                          command_lines,

-                                          &process_ids));

-  ASSERT_EQ(0, process_ids.size());

-

-  // Ok, test process not running. Let's continue running the test.

-  CString path = ConcatenatePath(app_util::GetSystemDir(), kTestExecutable);

-  ScopedProcess process(path);

-  ScopedProcess exclude_process(path);

-

-  ASSERT_TRUE(process.Start(kTestArguments));

-  ASSERT_TRUE(exclude_process.Start(kTestExcludeArguments));

-  for (int i = 0; i < kMaxWaitIterations; ++i) {

-    ::Sleep(kWaitForProcessStartMs);

-    if (process.Running() && exclude_process.Running())

-      break;

-  }

-  EXPECT_TRUE(process.Running());

-  EXPECT_TRUE(exclude_process.Running());

-

-  // Try to find just the first process, excluding the other.

-  exclude_mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |

-                 EXCLUDE_CURRENT_PROCESS |

-                 EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;

-

-  command_lines.push_back(kTestExcludeString);

-  ASSERT_SUCCEEDED(Process::FindProcesses(exclude_mask,

-                                          kTestExecutable,

-                                          true,

-                                          user_sid,

-                                          command_lines,

-                                          &process_ids));

-  ASSERT_EQ(1, process_ids.size());

-  EXPECT_EQ(process.GetId(), process_ids[0]);

-}

-

-TEST(ProcessTest, IncludeProcess) {

-  CString path = ConcatenatePath(app_util::GetSystemDir(), kTestExecutable);

-  ScopedProcess process(path);

-  ScopedProcess include_process(path);

-

-  ASSERT_TRUE(process.Start(kTestArguments));

-  ASSERT_TRUE(include_process.Start(kTestIncludeArguments));

-  for (int i = 0; i < kMaxWaitIterations; ++i) {

-    ::Sleep(kWaitForProcessStartMs);

-    if (process.Running() && include_process.Running())

-      break;

-  }

-  EXPECT_TRUE(process.Running());

-  EXPECT_TRUE(include_process.Running());

-

-  // Try to find just the first process, excluding the other.

-  uint32 exclude_mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |

-                        EXCLUDE_CURRENT_PROCESS |

-                        INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;

-  CString user_sid;

-  std::vector<CString> command_lines;

-  std::vector<uint32> process_ids;

-

-  command_lines.push_back(kTestIncludeString);

-  ASSERT_SUCCEEDED(omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid));

-  ASSERT_SUCCEEDED(Process::FindProcesses(exclude_mask,

-                                          kTestExecutable,

-                                          true,

-                                          user_sid,

-                                          command_lines,

-                                          &process_ids));

-  ASSERT_EQ(1, process_ids.size());

-  EXPECT_EQ(include_process.GetId(), process_ids[0]);

-}

-

-TEST(ProcessTest, GetImagePath) {

-  // Get this module's path.

-  HMODULE handle = ::GetModuleHandle(NULL);

-  ASSERT_TRUE(handle != NULL);

-

-  TCHAR file_name[MAX_PATH] = {0};

-  ASSERT_NE(::GetModuleFileName(handle, file_name, MAX_PATH), 0);

-  ASSERT_NE(0, wcslen(file_name));

-

-  CString exe = GetFileFromPath(file_name);

-  ASSERT_FALSE(exe.IsEmpty());

-

-  CString user_sid;

-  ASSERT_SUCCEEDED(omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid));

-

-  // Test the method.

-  CString path;

-  ASSERT_SUCCEEDED(Process::GetImagePath(exe, user_sid, &path));

-

-  // Compare the result.

-  ASSERT_STREQ(file_name, path);

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Process unit tests.
+
+#include <vector>
+
+#include "omaha/common/app_util.h"
+#include "omaha/common/path.h"
+#include "omaha/common/process.h"
+#include "omaha/common/user_info.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+const int kWaitUntilDeadMs = 10000;
+
+// Process class that terminates the associated process when deleted.
+class ScopedProcess : public Process {
+ public:
+  explicit ScopedProcess(const TCHAR* name) : Process(name, NULL) {}
+  virtual ~ScopedProcess() {
+    Terminate(0);
+    EXPECT_TRUE(WaitUntilDead(kWaitUntilDeadMs));
+  }
+};
+
+TEST(ProcessTest, StartOneProcess) {
+  const TCHAR kExecutableName[] = _T("cmd.exe");
+  const TCHAR kExecutableArguments[] = _T("/c exit 702");
+  const int kExpectedExitCode = 702;
+
+  CString path = ConcatenatePath(app_util::GetSystemDir(), kExecutableName);
+  ScopedProcess process(path);
+
+  ASSERT_TRUE(process.Start(kExecutableArguments));
+  EXPECT_TRUE(process.WaitUntilDead(kWaitUntilDeadMs));
+
+  // Check the exit code to get some assurance that the process actually ran.
+  uint32 exit_code = 0;
+  EXPECT_TRUE(process.GetExitCode(&exit_code));
+  EXPECT_EQ(kExpectedExitCode, exit_code);
+}
+
+// Dummy process to spin off and then find.  The numeric argument will make
+// netstat run until it's killed by the ScopedProcess destructor.
+const TCHAR kTestExecutable[] = _T("netstat.exe");
+const TCHAR kTestArguments[] = _T("10");
+const TCHAR kTestExcludeArguments[] = _T("-o 20");
+const TCHAR kTestExcludeString[] = _T("20");
+const TCHAR kTestIncludeArguments[] = _T("-o 30");
+const TCHAR kTestIncludeString[] = _T("30");
+const int kWaitForProcessStartMs = 500;
+const int kMaxWaitIterations = 10;
+
+TEST(ProcessTest, FindOneProcess) {
+  CString path = ConcatenatePath(app_util::GetSystemDir(), kTestExecutable);
+  ScopedProcess process(path);
+  ASSERT_TRUE(process.Start(kTestArguments));
+  for (int i = 0; i < kMaxWaitIterations; ++i) {
+    ::Sleep(kWaitForProcessStartMs);
+    if (process.Running())
+      break;
+  }
+  EXPECT_TRUE(process.Running());
+
+  // Try to find the test process.
+  uint32 exclude_mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
+  CString user_sid;
+  std::vector<CString> command_lines;
+  std::vector<uint32> process_ids;
+
+  ASSERT_SUCCEEDED(omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid));
+
+  // This test intermittently fails to find the process when run on Pulse.
+  // This code attempts to ensure that the process is further along in the
+  // initialization process by waiting until Process::GetCommandLine succeeds.
+  // This test case does not result in FindProcesses using GetCommandLine, but
+  // waiting until this point may be enough to address the intermitent failures.
+  HRESULT hr = E_FAIL;
+  CString process_cmd;
+  for (int tries = 0; tries < 100 && FAILED(hr); ++tries) {
+    ::Sleep(50);
+    hr = Process::GetCommandLine(process.GetId(), &process_cmd);
+  }
+  EXPECT_SUCCEEDED(hr);
+
+  ASSERT_SUCCEEDED(Process::FindProcesses(exclude_mask,
+                                          kTestExecutable,
+                                          true,
+                                          user_sid,
+                                          command_lines,
+                                          &process_ids));
+  ASSERT_EQ(1, process_ids.size());  // Exit before accessing invalid element.
+  EXPECT_EQ(process.GetId(), process_ids[0]);
+}
+
+TEST(ProcessTest, ExcludeProcess) {
+  // Make sure the test process is not already running.
+  uint32 exclude_mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
+  CString user_sid;
+  std::vector<CString> command_lines;
+  std::vector<uint32> process_ids;
+
+  ASSERT_SUCCEEDED(omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid));
+  ASSERT_SUCCEEDED(Process::FindProcesses(exclude_mask,
+                                          kTestExecutable,
+                                          true,
+                                          user_sid,
+                                          command_lines,
+                                          &process_ids));
+  ASSERT_EQ(0, process_ids.size());
+
+  // Ok, test process not running. Let's continue running the test.
+  CString path = ConcatenatePath(app_util::GetSystemDir(), kTestExecutable);
+  ScopedProcess process(path);
+  ScopedProcess exclude_process(path);
+
+  ASSERT_TRUE(process.Start(kTestArguments));
+  ASSERT_TRUE(exclude_process.Start(kTestExcludeArguments));
+  for (int i = 0; i < kMaxWaitIterations; ++i) {
+    ::Sleep(kWaitForProcessStartMs);
+    if (process.Running() && exclude_process.Running())
+      break;
+  }
+  EXPECT_TRUE(process.Running());
+  EXPECT_TRUE(exclude_process.Running());
+
+  // Try to find just the first process, excluding the other.
+  exclude_mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |
+                 EXCLUDE_CURRENT_PROCESS |
+                 EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
+
+  command_lines.push_back(kTestExcludeString);
+  ASSERT_SUCCEEDED(Process::FindProcesses(exclude_mask,
+                                          kTestExecutable,
+                                          true,
+                                          user_sid,
+                                          command_lines,
+                                          &process_ids));
+  ASSERT_EQ(1, process_ids.size());
+  EXPECT_EQ(process.GetId(), process_ids[0]);
+}
+
+TEST(ProcessTest, IncludeProcess) {
+  CString path = ConcatenatePath(app_util::GetSystemDir(), kTestExecutable);
+  ScopedProcess process(path);
+  ScopedProcess include_process(path);
+
+  ASSERT_TRUE(process.Start(kTestArguments));
+  ASSERT_TRUE(include_process.Start(kTestIncludeArguments));
+  for (int i = 0; i < kMaxWaitIterations; ++i) {
+    ::Sleep(kWaitForProcessStartMs);
+    if (process.Running() && include_process.Running())
+      break;
+  }
+  EXPECT_TRUE(process.Running());
+  EXPECT_TRUE(include_process.Running());
+
+  // Try to find just the first process, excluding the other.
+  uint32 exclude_mask = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |
+                        EXCLUDE_CURRENT_PROCESS |
+                        INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
+  CString user_sid;
+  std::vector<CString> command_lines;
+  std::vector<uint32> process_ids;
+
+  command_lines.push_back(kTestIncludeString);
+  ASSERT_SUCCEEDED(omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid));
+  ASSERT_SUCCEEDED(Process::FindProcesses(exclude_mask,
+                                          kTestExecutable,
+                                          true,
+                                          user_sid,
+                                          command_lines,
+                                          &process_ids));
+  ASSERT_EQ(1, process_ids.size());
+  EXPECT_EQ(include_process.GetId(), process_ids[0]);
+}
+
+TEST(ProcessTest, GetImagePath) {
+  // Get this module's path.
+  HMODULE handle = ::GetModuleHandle(NULL);
+  ASSERT_TRUE(handle != NULL);
+
+  TCHAR file_name[MAX_PATH] = {0};
+  ASSERT_NE(::GetModuleFileName(handle, file_name, MAX_PATH), 0);
+  ASSERT_NE(0, wcslen(file_name));
+
+  CString exe = GetFileFromPath(file_name);
+  ASSERT_FALSE(exe.IsEmpty());
+
+  CString user_sid;
+  ASSERT_SUCCEEDED(omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid));
+
+  // Test the method.
+  CString path;
+  ASSERT_SUCCEEDED(Process::GetImagePath(exe, user_sid, &path));
+
+  // Compare the result.
+  ASSERT_STREQ(file_name, path);
+}
+
+}  // namespace omaha
+
diff --git a/common/processor_type.cc b/common/processor_type.cc
index 819cd3e..e07f92b 100644
--- a/common/processor_type.cc
+++ b/common/processor_type.cc
@@ -1,51 +1,51 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Processor brand detection implementation

-//

-#include "omaha/common/processor_type.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-// Returns "GenuineIntel", "AuthenticAMD", etc...

-CString GetProcessorType() {

-  // Reference for checking for chip type

-  // http://en.wikipedia.org/wiki/CPUID

-

-  // There are 12 characters in the chip id (e.g. "GenuineIntel")

-  union {

-    char str[16];

-    uint32 n[4];

-  } regs;

-  SetZero(regs.str);

-  __asm {

-    xor eax, eax;  // Set EAX = 0 to get CPU type

-    cpuid;         // Now ebx, edx, ecx will contain cpu brand

-    mov regs.n[0], ebx;

-    mov regs.n[4], edx;

-    mov regs.n[8], ecx;

-  }

-  return CString(regs.str);

-}

-

-// Returns true if we're running on an Intel

-bool IsIntelProcessor() {

-  CString chip = GetProcessorType();

-  return (chip == kIntelVendorId);

-}

-

-}  // namespace omaha

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Processor brand detection implementation
+//
+#include "omaha/common/processor_type.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+// Returns "GenuineIntel", "AuthenticAMD", etc...
+CString GetProcessorType() {
+  // Reference for checking for chip type
+  // http://en.wikipedia.org/wiki/CPUID
+
+  // There are 12 characters in the chip id (e.g. "GenuineIntel")
+  union {
+    char str[16];
+    uint32 n[4];
+  } regs;
+  SetZero(regs.str);
+  __asm {
+    xor eax, eax;  // Set EAX = 0 to get CPU type
+    cpuid;         // Now ebx, edx, ecx will contain cpu brand
+    mov regs.n[0], ebx;
+    mov regs.n[4], edx;
+    mov regs.n[8], ecx;
+  }
+  return CString(regs.str);
+}
+
+// Returns true if we're running on an Intel
+bool IsIntelProcessor() {
+  CString chip = GetProcessorType();
+  return (chip == kIntelVendorId);
+}
+
+}  // namespace omaha
diff --git a/common/processor_type.h b/common/processor_type.h
index 682cca8..cedf778 100644
--- a/common/processor_type.h
+++ b/common/processor_type.h
@@ -1,29 +1,29 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Processor brand detection declarations

-//

-

-#ifndef OMAHA_COMMON_PROCESSOR_TYPE_H_

-#define OMAHA_COMMON_PROCESSOR_TYPE_H_

-

-namespace omaha {

-

-bool IsIntelProcessor();

-CString GetProcessorType();

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_PROCESSOR_TYPE_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Processor brand detection declarations
+//
+
+#ifndef OMAHA_COMMON_PROCESSOR_TYPE_H_
+#define OMAHA_COMMON_PROCESSOR_TYPE_H_
+
+namespace omaha {
+
+bool IsIntelProcessor();
+CString GetProcessorType();
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_PROCESSOR_TYPE_H_
diff --git a/common/queue_timer.cc b/common/queue_timer.cc
index 685415f..5bae3d6 100644
--- a/common/queue_timer.cc
+++ b/common/queue_timer.cc
@@ -1,183 +1,183 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The implementation is straightforward except the destruction of the

-// QueueTimer which needs some clarification.

-// If there is no callback running, then the destructor gets the critical

-// section and then it blocks on the DeleteTimerQueueTimer call, waiting for

-// the kernel to clean up the timer handle. The callback never fires in this

-// case.

-// If a callback is running, then there are two possibilities:

-// 1. The callback gets the critical section. The callback runs as usual and

-// then the destructor gets the critical section. This is also easy.

-// 2. The destructor gets the critical section. In this case, the callback

-// tries the critical section then it returns right away.

-//

-// Alarm timers are started and restarted every time they fire. The usage

-// patterns for alarms is usually Start, Callback, Start, Callback, etc...

-// The cleanup of an alarm timer handle usually happens in the callback, unless

-// the destructor of the QueueTimer is called, in which case the logic

-// above applies.

-//

-// Periodic timers are only started once: Start, Callback, Callback, etc...

-// In this case, the destructor does all the necessary cleanup.

-// Periodic timers must fire at intervals that are reasonable long so that

-// the callbacks do not queue up.

-

-#include "omaha/common/queue_timer.h"

-

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-

-namespace omaha {

-

-QueueTimer::QueueTimer(HANDLE timer_queue, Callback callback, void* ctx)

-    : callback_tid_(0),

-      ctx_(ctx),

-      due_time_(0),

-      period_(0),

-      flags_(0),

-      timer_handle_(NULL),

-      timer_queue_(timer_queue),

-      callback_(callback) {

-  UTIL_LOG(L3, (_T("[QueueTimer::QueueTimer][0x%08x]"), this));

-  ASSERT1(timer_queue);

-  ASSERT1(callback);

-  ::InitializeCriticalSection(&dtor_cs_);

-  ::InitializeCriticalSection(&cs_);

-}

-

-// The destructor blocks on waiting for the timer kernel object to be deleted.

-// We can't call the destructor of QueueTimer while we are handling a callback.

-// This will result is a deadlock.

-QueueTimer::~QueueTimer() {

-  UTIL_LOG(L3, (_T("[QueueTimer::~QueueTimer][0x%08x]"), this));

-

-  ::EnterCriticalSection(&dtor_cs_);

-  if (timer_handle_) {

-    ASSERT1(callback_tid_ != ::GetCurrentThreadId());

-

-    // This is a blocking call waiting for all callbacks to clear up.

-    bool res = !!::DeleteTimerQueueTimer(timer_queue_,

-                                         timer_handle_,

-                                         INVALID_HANDLE_VALUE);

-    ASSERT1(res);

-    timer_handle_ = NULL;

-  }

-  callback_ = NULL;

-  timer_queue_ = NULL;

-  flags_ = 0;

-  period_ = 0;

-  due_time_ = 0;

-  ctx_ = 0;

-  callback_tid_ = 0;

-  ::LeaveCriticalSection(&dtor_cs_);

-

-  ::DeleteCriticalSection(&cs_);

-  ::DeleteCriticalSection(&dtor_cs_);

-}

-

-// Thread safe.

-HRESULT QueueTimer::Start(int due_time, int period, uint32 flags) {

-  // Since Start creates the timer there could be a race condition where

-  // the timer could fire while we are still executing Start. We protect

-  // the start with a critical section so the Start completes before the

-  // timer can be entered by the callback.

-

-  ::EnterCriticalSection(&cs_);

-  HRESULT hr = DoStart(due_time, period, flags);

-  ::LeaveCriticalSection(&cs_);

-  return hr;

-}

-

-// Thread-safe.

-void QueueTimer::TimerCallback(void* param, BOOLEAN timer_or_wait) {

-  ASSERT1(param);

-  VERIFY1(timer_or_wait);

-

-  QueueTimer* timer = static_cast<QueueTimer*>(param);

-

-  if (!::TryEnterCriticalSection(&timer->dtor_cs_)) {

-    return;

-  }

-

-  ::EnterCriticalSection(&timer->cs_);

-  timer->DoCallback();

-  ::LeaveCriticalSection(&timer->cs_);

-

-  ::LeaveCriticalSection(&timer->dtor_cs_);

-}

-

-

-HRESULT QueueTimer::DoStart(int due_time, int period, uint32 flags) {

-  due_time_ = due_time;

-  period_ = period;

-  flags_ = flags;

-

-  // Application Verifier says period must be 0 for WT_EXECUTEONLYONCE timers.

-  if ((flags & WT_EXECUTEONLYONCE) && period != 0) {

-    return E_INVALIDARG;

-  }

-

-  // Periodic timers can't be started more than one time.

-  if (timer_handle_) {

-    return E_UNEXPECTED;

-  }

-

-  bool res = !!::CreateTimerQueueTimer(&timer_handle_,

-                                       timer_queue_,

-                                       &QueueTimer::TimerCallback,

-                                       this,

-                                       due_time,

-                                       period,

-                                       flags_);

-  if (!res) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LE, (_T("[QueueTimer::Start failed][0x%08x][0x%08x]"), hr, this));

-    return hr;

-  }

-

-  ASSERT1(timer_handle_);

-  UTIL_LOG(L3, (_T("[QueueTimer::Start timer created][0x%08x]"), this));

-  return S_OK;

-}

-

-void QueueTimer::DoCallback() {

-  UTIL_LOG(L2, (_T("[QueueTimer::OnCallback][0x%08x]"), this));

-

-  ASSERT1(timer_queue_);

-  ASSERT1(timer_handle_);

-  ASSERT1(callback_);

-

-  if (!period_) {

-    // Non-periodic aka alarm timers fire only once. We delete the timer

-    // handle so that the timer object can be restarted later on.

-    // The call below is non-blocking. The deletion of the kernel object can

-    // succeed right away, for example if the timer runs in the timer thread

-    // itself. Otherwise, if the last error is ERROR_IO_PENDING the kernel

-    // cleans up the object once the callback returns.

-    bool res = !!::DeleteTimerQueueTimer(timer_queue_, timer_handle_, NULL);

-    ASSERT1(res || (!res && ::GetLastError() == ERROR_IO_PENDING));

-    timer_handle_ = NULL;

-  }

-

-  callback_tid_ = ::GetCurrentThreadId();

-  callback_(this);

-  callback_tid_ = 0;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The implementation is straightforward except the destruction of the
+// QueueTimer which needs some clarification.
+// If there is no callback running, then the destructor gets the critical
+// section and then it blocks on the DeleteTimerQueueTimer call, waiting for
+// the kernel to clean up the timer handle. The callback never fires in this
+// case.
+// If a callback is running, then there are two possibilities:
+// 1. The callback gets the critical section. The callback runs as usual and
+// then the destructor gets the critical section. This is also easy.
+// 2. The destructor gets the critical section. In this case, the callback
+// tries the critical section then it returns right away.
+//
+// Alarm timers are started and restarted every time they fire. The usage
+// patterns for alarms is usually Start, Callback, Start, Callback, etc...
+// The cleanup of an alarm timer handle usually happens in the callback, unless
+// the destructor of the QueueTimer is called, in which case the logic
+// above applies.
+//
+// Periodic timers are only started once: Start, Callback, Callback, etc...
+// In this case, the destructor does all the necessary cleanup.
+// Periodic timers must fire at intervals that are reasonable long so that
+// the callbacks do not queue up.
+
+#include "omaha/common/queue_timer.h"
+
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+
+namespace omaha {
+
+QueueTimer::QueueTimer(HANDLE timer_queue, Callback callback, void* ctx)
+    : callback_tid_(0),
+      ctx_(ctx),
+      due_time_(0),
+      period_(0),
+      flags_(0),
+      timer_handle_(NULL),
+      timer_queue_(timer_queue),
+      callback_(callback) {
+  UTIL_LOG(L3, (_T("[QueueTimer::QueueTimer][0x%08x]"), this));
+  ASSERT1(timer_queue);
+  ASSERT1(callback);
+  ::InitializeCriticalSection(&dtor_cs_);
+  ::InitializeCriticalSection(&cs_);
+}
+
+// The destructor blocks on waiting for the timer kernel object to be deleted.
+// We can't call the destructor of QueueTimer while we are handling a callback.
+// This will result is a deadlock.
+QueueTimer::~QueueTimer() {
+  UTIL_LOG(L3, (_T("[QueueTimer::~QueueTimer][0x%08x]"), this));
+
+  ::EnterCriticalSection(&dtor_cs_);
+  if (timer_handle_) {
+    ASSERT1(callback_tid_ != ::GetCurrentThreadId());
+
+    // This is a blocking call waiting for all callbacks to clear up.
+    bool res = !!::DeleteTimerQueueTimer(timer_queue_,
+                                         timer_handle_,
+                                         INVALID_HANDLE_VALUE);
+    ASSERT1(res);
+    timer_handle_ = NULL;
+  }
+  callback_ = NULL;
+  timer_queue_ = NULL;
+  flags_ = 0;
+  period_ = 0;
+  due_time_ = 0;
+  ctx_ = 0;
+  callback_tid_ = 0;
+  ::LeaveCriticalSection(&dtor_cs_);
+
+  ::DeleteCriticalSection(&cs_);
+  ::DeleteCriticalSection(&dtor_cs_);
+}
+
+// Thread safe.
+HRESULT QueueTimer::Start(int due_time, int period, uint32 flags) {
+  // Since Start creates the timer there could be a race condition where
+  // the timer could fire while we are still executing Start. We protect
+  // the start with a critical section so the Start completes before the
+  // timer can be entered by the callback.
+
+  ::EnterCriticalSection(&cs_);
+  HRESULT hr = DoStart(due_time, period, flags);
+  ::LeaveCriticalSection(&cs_);
+  return hr;
+}
+
+// Thread-safe.
+void QueueTimer::TimerCallback(void* param, BOOLEAN timer_or_wait) {
+  ASSERT1(param);
+  VERIFY1(timer_or_wait);
+
+  QueueTimer* timer = static_cast<QueueTimer*>(param);
+
+  if (!::TryEnterCriticalSection(&timer->dtor_cs_)) {
+    return;
+  }
+
+  ::EnterCriticalSection(&timer->cs_);
+  timer->DoCallback();
+  ::LeaveCriticalSection(&timer->cs_);
+
+  ::LeaveCriticalSection(&timer->dtor_cs_);
+}
+
+
+HRESULT QueueTimer::DoStart(int due_time, int period, uint32 flags) {
+  due_time_ = due_time;
+  period_ = period;
+  flags_ = flags;
+
+  // Application Verifier says period must be 0 for WT_EXECUTEONLYONCE timers.
+  if ((flags & WT_EXECUTEONLYONCE) && period != 0) {
+    return E_INVALIDARG;
+  }
+
+  // Periodic timers can't be started more than one time.
+  if (timer_handle_) {
+    return E_UNEXPECTED;
+  }
+
+  bool res = !!::CreateTimerQueueTimer(&timer_handle_,
+                                       timer_queue_,
+                                       &QueueTimer::TimerCallback,
+                                       this,
+                                       due_time,
+                                       period,
+                                       flags_);
+  if (!res) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LE, (_T("[QueueTimer::Start failed][0x%08x][0x%08x]"), hr, this));
+    return hr;
+  }
+
+  ASSERT1(timer_handle_);
+  UTIL_LOG(L3, (_T("[QueueTimer::Start timer created][0x%08x]"), this));
+  return S_OK;
+}
+
+void QueueTimer::DoCallback() {
+  UTIL_LOG(L2, (_T("[QueueTimer::OnCallback][0x%08x]"), this));
+
+  ASSERT1(timer_queue_);
+  ASSERT1(timer_handle_);
+  ASSERT1(callback_);
+
+  if (!period_) {
+    // Non-periodic aka alarm timers fire only once. We delete the timer
+    // handle so that the timer object can be restarted later on.
+    // The call below is non-blocking. The deletion of the kernel object can
+    // succeed right away, for example if the timer runs in the timer thread
+    // itself. Otherwise, if the last error is ERROR_IO_PENDING the kernel
+    // cleans up the object once the callback returns.
+    bool res = !!::DeleteTimerQueueTimer(timer_queue_, timer_handle_, NULL);
+    ASSERT1(res || (!res && ::GetLastError() == ERROR_IO_PENDING));
+    timer_handle_ = NULL;
+  }
+
+  callback_tid_ = ::GetCurrentThreadId();
+  callback_(this);
+  callback_tid_ = 0;
+}
+
+}  // namespace omaha
+
diff --git a/common/queue_timer.h b/common/queue_timer.h
index 439cba8..10d9182 100644
--- a/common/queue_timer.h
+++ b/common/queue_timer.h
@@ -1,83 +1,83 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// QueueTimer is a wrapper for the kernel queue timer.

-//

-// There are two ways to use the QueueTimer:

-// - alarm, where the timer goes off only once.

-// - periodic timer.

-// When working as an alarm, the timer must be restarted after it fired. There

-// is no need to destroy the whole object.

-// When working with a periodic timer, the timer can only be started once.

-// Alarm timers fire only once, so they will have to be restarted every time.

-// It is easy to deadlock when working with timers. As a general rule, never

-// destroy a QueueTimer from its callback.

-

-#ifndef OMAHA_COMMON_QUEUE_TIMER_H__

-#define OMAHA_COMMON_QUEUE_TIMER_H__

-

-#include <windows.h>

-

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class QueueTimer {

-  public:

-    typedef void (*Callback)(QueueTimer* timer);

-

-    QueueTimer(HANDLE timer_queue,  // Caller provided timer queue.

-               Callback callback,   // Callback to call when the timer fires.

-               void* ctx);          // Caller provided context.

-

-    // The destructor waits for the pending callbacks to finish since we do not

-    // want the callback to fire after the C++ object was destroyed.

-    ~QueueTimer();

-

-    // Starts a timer. The time is in milliseconds.

-    HRESULT Start(int due_time, int period, uint32 flags);

-

-    void* ctx() const { return ctx_; }

-

-    int due_time() const { return due_time_; }

-

-    int period() const { return period_; }

-

-    uint32 flags() const { return flags_; }

-

-  private:

-    static void _stdcall TimerCallback(void* param, BOOLEAN timer_or_wait);

-

-    HRESULT DoStart(int due_time, int period, uint32 flags);

-    void DoCallback();

-

-    CRITICAL_SECTION cs_;         // Serializes access to shared state.

-    CRITICAL_SECTION dtor_cs_;    // Serializes the destruction of the object.

-    DWORD callback_tid_;          // The thread id of the callback, if any.

-    void* ctx_;

-    int due_time_;

-    int period_;

-    uint32 flags_;

-    HANDLE timer_handle_;

-    HANDLE timer_queue_;

-    Callback callback_;

-

-    DISALLOW_EVIL_CONSTRUCTORS(QueueTimer);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_QUEUE_TIMER_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// QueueTimer is a wrapper for the kernel queue timer.
+//
+// There are two ways to use the QueueTimer:
+// - alarm, where the timer goes off only once.
+// - periodic timer.
+// When working as an alarm, the timer must be restarted after it fired. There
+// is no need to destroy the whole object.
+// When working with a periodic timer, the timer can only be started once.
+// Alarm timers fire only once, so they will have to be restarted every time.
+// It is easy to deadlock when working with timers. As a general rule, never
+// destroy a QueueTimer from its callback.
+
+#ifndef OMAHA_COMMON_QUEUE_TIMER_H__
+#define OMAHA_COMMON_QUEUE_TIMER_H__
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class QueueTimer {
+  public:
+    typedef void (*Callback)(QueueTimer* timer);
+
+    QueueTimer(HANDLE timer_queue,  // Caller provided timer queue.
+               Callback callback,   // Callback to call when the timer fires.
+               void* ctx);          // Caller provided context.
+
+    // The destructor waits for the pending callbacks to finish since we do not
+    // want the callback to fire after the C++ object was destroyed.
+    ~QueueTimer();
+
+    // Starts a timer. The time is in milliseconds.
+    HRESULT Start(int due_time, int period, uint32 flags);
+
+    void* ctx() const { return ctx_; }
+
+    int due_time() const { return due_time_; }
+
+    int period() const { return period_; }
+
+    uint32 flags() const { return flags_; }
+
+  private:
+    static void _stdcall TimerCallback(void* param, BOOLEAN timer_or_wait);
+
+    HRESULT DoStart(int due_time, int period, uint32 flags);
+    void DoCallback();
+
+    CRITICAL_SECTION cs_;         // Serializes access to shared state.
+    CRITICAL_SECTION dtor_cs_;    // Serializes the destruction of the object.
+    DWORD callback_tid_;          // The thread id of the callback, if any.
+    void* ctx_;
+    int due_time_;
+    int period_;
+    uint32 flags_;
+    HANDLE timer_handle_;
+    HANDLE timer_queue_;
+    Callback callback_;
+
+    DISALLOW_EVIL_CONSTRUCTORS(QueueTimer);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_QUEUE_TIMER_H__
+
diff --git a/common/queue_timer_unittest.cc b/common/queue_timer_unittest.cc
index 996183f..65a1c8a 100644
--- a/common/queue_timer_unittest.cc
+++ b/common/queue_timer_unittest.cc
@@ -1,175 +1,175 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include <iostream>

-#include "base/scoped_ptr.h"

-#include "omaha/common/queue_timer.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/timer.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class QueueTimerTest : public testing::Test {

- protected:

-  QueueTimerTest()

-      : timer_queue_(NULL),

-        cnt_(0),

-        max_cnt_(0) {}

-

-  virtual void SetUp() {

-    cnt_ = 0;

-    timer_queue_ = ::CreateTimerQueue();

-    ASSERT_TRUE(timer_queue_);

-    reset(ev_, ::CreateEvent(NULL, true, false, NULL));

-  }

-

-  virtual void TearDown() {

-    // First destroy the timer, otherwise the timer could fire and

-    // access invalid test case state.

-    queue_timer_.reset();

-    reset(ev_);

-    ASSERT_TRUE(::DeleteTimerQueueEx(timer_queue_, INVALID_HANDLE_VALUE));

-    cnt_ = 0;

-    max_cnt_ = 0;

-  }

-

-  // Handles the alarm mode of the timer queue, where the timer fires once.

-  static void AlarmCallback(QueueTimer* queue_timer);

-

-  // Handles the periodic timer.

-  static void TimerCallback(QueueTimer* queue_timer);

-

-  HANDLE timer_queue_;

-  scoped_ptr<QueueTimer> queue_timer_;

-  scoped_event ev_;

-  volatile int cnt_;

-  volatile int max_cnt_;

-};

-

-void QueueTimerTest::AlarmCallback(QueueTimer* queue_timer) {

-  ASSERT_TRUE(queue_timer);

-  void* ctx = queue_timer->ctx();

-  QueueTimerTest* test = static_cast<QueueTimerTest*>(ctx);

-  test->cnt_ = 1;

-  ASSERT_TRUE(::SetEvent(get(test->ev_)));

-}

-

-void QueueTimerTest::TimerCallback(QueueTimer* queue_timer) {

-  ASSERT_TRUE(queue_timer);

-  void* ctx = queue_timer->ctx();

-  QueueTimerTest* test = static_cast<QueueTimerTest*>(ctx);

-

-  // Wait max_cnt_ ticks before signaling.

-  ++test->cnt_;

-  if (test->cnt_ == test->max_cnt_) {

-    ::SetEvent(get(test->ev_));

-  }

-}

-

-TEST_F(QueueTimerTest, QuickAlarm) {

-  queue_timer_.reset(new QueueTimer(timer_queue_,

-                                    &QueueTimerTest::AlarmCallback,

-                                    this));

-  const int kWaitTimeMaxMs = 1000;

-

-  // Set the timer to fire once right away.

-  LowResTimer timer(true);

-  ASSERT_HRESULT_SUCCEEDED(

-      queue_timer_->Start(0, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(ev_), kWaitTimeMaxMs));

-  EXPECT_EQ(1, cnt_);

-

-  // Expect the alarm to fire quickly.

-  EXPECT_GE(50u, timer.GetMilliseconds());

-}

-

-// The test takes about 50 seconds to run.

-TEST_F(QueueTimerTest, Alarm) {

-  if (!IsBuildSystem()) {

-    std::wcout << _T("\tThe long timing test below only runs on build system")

-               << std::endl;

-    return;

-  }

-

-  queue_timer_.reset(new QueueTimer(timer_queue_,

-                                    &QueueTimerTest::AlarmCallback,

-                                    this));

-  const int kWaitTimeMaxMs = 60 * 1000;     // 60 seconds.

-

-  // Set the timer to fire once after 5 sec, 10 sec, 15 sec, 20 sec and wait.

-  LowResTimer timer(false);

-  for (int i = 1; i <= 4; ++i) {

-    const int time_interval_ms = 5 * 1000 * i;

-    SCOPED_TRACE(testing::Message() << "time_interval_ms=" << time_interval_ms);

-

-    timer.Start();

-    ASSERT_HRESULT_SUCCEEDED(

-        queue_timer_->Start(time_interval_ms, 0, WT_EXECUTEONLYONCE));

-    EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(ev_), kWaitTimeMaxMs));

-

-    int actual_time_ms = timer.GetMilliseconds();

-    timer.Reset();

-

-    // Expect the alarm to fire anytime between a narrow interval.

-    EXPECT_EQ(1, cnt_);

-    EXPECT_LE(time_interval_ms - 50, actual_time_ms);

-    EXPECT_GE(time_interval_ms + 50, actual_time_ms);

-

-    cnt_ = 0;

-    ::ResetEvent(get(ev_));

-  }

-

-  // Set the timer to fire once after 2000 ms but do not wait for it to fire.

-  ASSERT_HRESULT_SUCCEEDED(

-      queue_timer_->Start(2000, 0, WT_EXECUTEONLYONCE));

-  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(ev_), 100));

-  EXPECT_EQ(0, cnt_);

-}

-

-// The test takes about 35 seconds to run.

-TEST_F(QueueTimerTest, Timer) {

-  if (!IsBuildSystem()) {

-    std::wcout << _T("\tThe long timing test below only runs on build system")

-               << std::endl;

-    return;

-  }

-

-  queue_timer_.reset(new QueueTimer(timer_queue_,

-                                    &QueueTimerTest::TimerCallback,

-                                    this));

-  const int kWaitTimeMaxMs = 60 * 1000;       // 60 seconds.

-

-  max_cnt_ = 4;

-

-  // Set the timer to fire at 10 seconds intervals with an initial delay of

-  // 5 seconds.

-  LowResTimer timer(true);

-  ASSERT_HRESULT_SUCCEEDED(queue_timer_->Start(5000, 10000, WT_EXECUTEDEFAULT));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(ev_), kWaitTimeMaxMs));

-

-  int actual_time_ms = timer.GetMilliseconds();

-

-  EXPECT_EQ(4, cnt_);

-  EXPECT_LE(35 * 1000 - 50, actual_time_ms);

-  EXPECT_GE(35 * 1000 + 50, actual_time_ms);

-

-  // Tests it can't start periodic timers more than one time.

-  ASSERT_EQ(E_UNEXPECTED, queue_timer_->Start(25, 50, WT_EXECUTEDEFAULT));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include <iostream>
+#include "base/scoped_ptr.h"
+#include "omaha/common/queue_timer.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/timer.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class QueueTimerTest : public testing::Test {
+ protected:
+  QueueTimerTest()
+      : timer_queue_(NULL),
+        cnt_(0),
+        max_cnt_(0) {}
+
+  virtual void SetUp() {
+    cnt_ = 0;
+    timer_queue_ = ::CreateTimerQueue();
+    ASSERT_TRUE(timer_queue_);
+    reset(ev_, ::CreateEvent(NULL, true, false, NULL));
+  }
+
+  virtual void TearDown() {
+    // First destroy the timer, otherwise the timer could fire and
+    // access invalid test case state.
+    queue_timer_.reset();
+    reset(ev_);
+    ASSERT_TRUE(::DeleteTimerQueueEx(timer_queue_, INVALID_HANDLE_VALUE));
+    cnt_ = 0;
+    max_cnt_ = 0;
+  }
+
+  // Handles the alarm mode of the timer queue, where the timer fires once.
+  static void AlarmCallback(QueueTimer* queue_timer);
+
+  // Handles the periodic timer.
+  static void TimerCallback(QueueTimer* queue_timer);
+
+  HANDLE timer_queue_;
+  scoped_ptr<QueueTimer> queue_timer_;
+  scoped_event ev_;
+  volatile int cnt_;
+  volatile int max_cnt_;
+};
+
+void QueueTimerTest::AlarmCallback(QueueTimer* queue_timer) {
+  ASSERT_TRUE(queue_timer);
+  void* ctx = queue_timer->ctx();
+  QueueTimerTest* test = static_cast<QueueTimerTest*>(ctx);
+  test->cnt_ = 1;
+  ASSERT_TRUE(::SetEvent(get(test->ev_)));
+}
+
+void QueueTimerTest::TimerCallback(QueueTimer* queue_timer) {
+  ASSERT_TRUE(queue_timer);
+  void* ctx = queue_timer->ctx();
+  QueueTimerTest* test = static_cast<QueueTimerTest*>(ctx);
+
+  // Wait max_cnt_ ticks before signaling.
+  ++test->cnt_;
+  if (test->cnt_ == test->max_cnt_) {
+    ::SetEvent(get(test->ev_));
+  }
+}
+
+TEST_F(QueueTimerTest, QuickAlarm) {
+  queue_timer_.reset(new QueueTimer(timer_queue_,
+                                    &QueueTimerTest::AlarmCallback,
+                                    this));
+  const int kWaitTimeMaxMs = 1000;
+
+  // Set the timer to fire once right away.
+  LowResTimer timer(true);
+  ASSERT_HRESULT_SUCCEEDED(
+      queue_timer_->Start(0, 0, WT_EXECUTEINTIMERTHREAD | WT_EXECUTEONLYONCE));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(ev_), kWaitTimeMaxMs));
+  EXPECT_EQ(1, cnt_);
+
+  // Expect the alarm to fire quickly.
+  EXPECT_GE(50u, timer.GetMilliseconds());
+}
+
+// The test takes about 50 seconds to run.
+TEST_F(QueueTimerTest, Alarm) {
+  if (!IsBuildSystem()) {
+    std::wcout << _T("\tThe long timing test below only runs on build system")
+               << std::endl;
+    return;
+  }
+
+  queue_timer_.reset(new QueueTimer(timer_queue_,
+                                    &QueueTimerTest::AlarmCallback,
+                                    this));
+  const int kWaitTimeMaxMs = 60 * 1000;     // 60 seconds.
+
+  // Set the timer to fire once after 5 sec, 10 sec, 15 sec, 20 sec and wait.
+  LowResTimer timer(false);
+  for (int i = 1; i <= 4; ++i) {
+    const int time_interval_ms = 5 * 1000 * i;
+    SCOPED_TRACE(testing::Message() << "time_interval_ms=" << time_interval_ms);
+
+    timer.Start();
+    ASSERT_HRESULT_SUCCEEDED(
+        queue_timer_->Start(time_interval_ms, 0, WT_EXECUTEONLYONCE));
+    EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(ev_), kWaitTimeMaxMs));
+
+    int actual_time_ms = timer.GetMilliseconds();
+    timer.Reset();
+
+    // Expect the alarm to fire anytime between a narrow interval.
+    EXPECT_EQ(1, cnt_);
+    EXPECT_LE(time_interval_ms - 50, actual_time_ms);
+    EXPECT_GE(time_interval_ms + 50, actual_time_ms);
+
+    cnt_ = 0;
+    ::ResetEvent(get(ev_));
+  }
+
+  // Set the timer to fire once after 2000 ms but do not wait for it to fire.
+  ASSERT_HRESULT_SUCCEEDED(
+      queue_timer_->Start(2000, 0, WT_EXECUTEONLYONCE));
+  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(ev_), 100));
+  EXPECT_EQ(0, cnt_);
+}
+
+// The test takes about 35 seconds to run.
+TEST_F(QueueTimerTest, Timer) {
+  if (!IsBuildSystem()) {
+    std::wcout << _T("\tThe long timing test below only runs on build system")
+               << std::endl;
+    return;
+  }
+
+  queue_timer_.reset(new QueueTimer(timer_queue_,
+                                    &QueueTimerTest::TimerCallback,
+                                    this));
+  const int kWaitTimeMaxMs = 60 * 1000;       // 60 seconds.
+
+  max_cnt_ = 4;
+
+  // Set the timer to fire at 10 seconds intervals with an initial delay of
+  // 5 seconds.
+  LowResTimer timer(true);
+  ASSERT_HRESULT_SUCCEEDED(queue_timer_->Start(5000, 10000, WT_EXECUTEDEFAULT));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(ev_), kWaitTimeMaxMs));
+
+  int actual_time_ms = timer.GetMilliseconds();
+
+  EXPECT_EQ(4, cnt_);
+  EXPECT_LE(35 * 1000 - 50, actual_time_ms);
+  EXPECT_GE(35 * 1000 + 50, actual_time_ms);
+
+  // Tests it can't start periodic timers more than one time.
+  ASSERT_EQ(E_UNEXPECTED, queue_timer_->Start(25, 50, WT_EXECUTEDEFAULT));
+}
+
+}  // namespace omaha
+
diff --git a/common/reactor.cc b/common/reactor.cc
index ba2eec2..c9e10a3 100644
--- a/common/reactor.cc
+++ b/common/reactor.cc
@@ -1,205 +1,205 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/reactor.h"

-

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/event_handler.h"

-

-namespace omaha {

-

-Reactor::Reactor() {

-  CORE_LOG(L4, (_T("[Reactor::Reactor]")));

-  ::InitializeCriticalSection(&cs_);

-}

-

-Reactor::~Reactor() {

-  CORE_LOG(L4, (_T("[Reactor::~Reactor]")));

-

-  // Each handle must be unregistered before destroying the reactor.

-  ASSERT1(handlers_.empty());

-  ::DeleteCriticalSection(&cs_);

-}

-

-// The reactor loop is just an efficient wait, as the demultiplexing of the

-// events is actually done by the OS thread pool.

-// TODO(omaha): replace the alertable wait with waiting on an event and provide

-// a method for the reactor to stop handling events.

-HRESULT Reactor::HandleEvents() {

-  CORE_LOG(L1, (_T("[Reactor::HandleEvents]")));

-  VERIFY1(::SleepEx(INFINITE, true) == WAIT_IO_COMPLETION);

-  CORE_LOG(L1, (_T("[Reactor::HandleEvents exit]")));

-  return S_OK;

-}

-

-void __stdcall Reactor::Callback(void* param, BOOLEAN timer_or_wait) {

-  ASSERT1(param);

-

-  // Since we wait an INFINITE the wait handle is always signaled.

-  VERIFY1(!timer_or_wait);

-  RegistrationState* state = static_cast<RegistrationState*>(param);

-  ASSERT1(state->reactor);

-  state->reactor->DoCallback(state);

-}

-

-// Method does not check to see if the same handle is registered twice.

-HRESULT Reactor::RegisterHandle(HANDLE handle,

-                                EventHandler* event_handler,

-                                uint32 flags) {

-  ASSERT1(handle);

-  ASSERT1(event_handler);

-

-  if (!handle || !event_handler) {

-    return E_INVALIDARG;

-  }

-

-  scoped_ptr<RegistrationState> state(new RegistrationState);

-  state->event_handler = event_handler;

-  state->handle = handle;

-  state->reactor = this;

-  state->flags = flags | WT_EXECUTEONLYONCE;

-

-  // The reactor only calls the handler once.

-  ASSERT1(WT_EXECUTEDEFAULT == 0);

-

-  // As soon as the handle is registered, the thread pool can queue up a

-  // callback and reenter the reactor on a different thread.

-  // Acquire the critical section before registering the handle.

-  ::EnterCriticalSection(&cs_);

-#if DEBUG

-  // The same handle should not be registered multiple times.

-  std::vector<RegistrationState*>::iterator it = handlers_.begin();

-  for (; it != handlers_.end(); ++it) {

-    ASSERT((*it)->handle != handle, (_T("[already registered %d]"), handle));

-  }

-#endif

-  bool res = !!::RegisterWaitForSingleObject(&state->wait_handle,

-                                             state->handle,

-                                             &Reactor::Callback,

-                                             state.get(),

-                                             INFINITE,

-                                             state->flags);

-  HRESULT hr = res ? S_OK : HRESULTFromLastError();

-  if (SUCCEEDED(hr)) {

-    handlers_.push_back(state.release());

-  }

-  ::LeaveCriticalSection(&cs_);

-

-  return hr;

-}

-

-HRESULT Reactor::RegisterHandle(HANDLE handle) {

-  ::EnterCriticalSection(&cs_);

-  HRESULT hr = DoRegisterHandle(handle);

-  ::LeaveCriticalSection(&cs_);

-  return hr;

-}

-

-HRESULT Reactor::DoRegisterHandle(HANDLE handle) {

-  ASSERT1(handle);

-  std::vector<RegistrationState*>::iterator it = handlers_.begin();

-  for (; it != handlers_.end(); ++it) {

-    if ((*it)->handle == handle) {

-      break;

-    }

-  }

-  if (it == handlers_.end()) {

-    // The handle is not registered with the reactor anymore. Registering the

-    // the handle again is not possible.

-    return E_FAIL;

-  }

-

-  // Unregister and register the handle again. Unregistering is an non blocking

-  // call.

-  RegistrationState* state = *it;

-  bool res = !!::UnregisterWaitEx(state->wait_handle, NULL);

-  if (!res && ::GetLastError() != ERROR_IO_PENDING) {

-    return HRESULTFromLastError();

-  }

-  if (!::RegisterWaitForSingleObject(&state->wait_handle,

-                                     state->handle,

-                                     &Reactor::Callback,

-                                     state,

-                                     INFINITE,

-                                     state->flags)) {

-    return HRESULTFromLastError();

-  }

-  return S_OK;

-}

-

-HRESULT Reactor::UnregisterHandle(HANDLE handle) {

-  ASSERT1(handle);

-  if (!handle) {

-    return E_INVALIDARG;

-  }

-

-  // Attempts to take the ownership of the registration state for the handle.

-  // If taking the ownership does not succeed, it means the handle has already

-  // been unregistered.

-  scoped_ptr<RegistrationState> state(ReleaseHandlerState(handle));

-  if (!state.get()) {

-    return E_UNEXPECTED;

-  }

-

-  // Unregisters the wait handle from the thread pool. The call blocks waiting

-  // for any pending callbacks to finish. No lock is being held while waiting

-  // here. If there is no callback pending, the call will succeed right away.

-  // Otherwise, if a callback has already started, the call waits for the

-  // callback to complete.

-  bool res = !!::UnregisterWaitEx(state->wait_handle, INVALID_HANDLE_VALUE);

-

-  // Clear the registration state, as a defensive programming measure and

-  // for debugging purposes.

-  state->reactor          = NULL;

-  state->handle           = NULL;

-  state->wait_handle      = NULL;

-  state->event_handler    = NULL;

-

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-void Reactor::DoCallback(RegistrationState* state) {

-  ASSERT1(state);

-  ASSERT1(state->event_handler);

-  ASSERT1(state->handle);

-  state->event_handler->HandleEvent(state->handle);

-}

-

-// Looks up the registration state for a handle and releases the ownership

-// of it to the caller. As the clean up of the state can happen from multiple

-// places, the transfer of ownership ensures the clean up happens once and

-// only once.

-Reactor::RegistrationState* Reactor::ReleaseHandlerState(HANDLE handle) {

-  RegistrationState* registration_state = NULL;

-  ::EnterCriticalSection(&cs_);

-  std::vector<RegistrationState*>::iterator it = handlers_.begin();

-  for (; it != handlers_.end(); ++it) {

-    if ((*it)->handle == handle) {

-      registration_state = *it;

-      handlers_.erase(it);

-      break;

-    }

-  }

-  ::LeaveCriticalSection(&cs_);

-  return registration_state;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/reactor.h"
+
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/event_handler.h"
+
+namespace omaha {
+
+Reactor::Reactor() {
+  CORE_LOG(L4, (_T("[Reactor::Reactor]")));
+  ::InitializeCriticalSection(&cs_);
+}
+
+Reactor::~Reactor() {
+  CORE_LOG(L4, (_T("[Reactor::~Reactor]")));
+
+  // Each handle must be unregistered before destroying the reactor.
+  ASSERT1(handlers_.empty());
+  ::DeleteCriticalSection(&cs_);
+}
+
+// The reactor loop is just an efficient wait, as the demultiplexing of the
+// events is actually done by the OS thread pool.
+// TODO(omaha): replace the alertable wait with waiting on an event and provide
+// a method for the reactor to stop handling events.
+HRESULT Reactor::HandleEvents() {
+  CORE_LOG(L1, (_T("[Reactor::HandleEvents]")));
+  VERIFY1(::SleepEx(INFINITE, true) == WAIT_IO_COMPLETION);
+  CORE_LOG(L1, (_T("[Reactor::HandleEvents exit]")));
+  return S_OK;
+}
+
+void __stdcall Reactor::Callback(void* param, BOOLEAN timer_or_wait) {
+  ASSERT1(param);
+
+  // Since we wait an INFINITE the wait handle is always signaled.
+  VERIFY1(!timer_or_wait);
+  RegistrationState* state = static_cast<RegistrationState*>(param);
+  ASSERT1(state->reactor);
+  state->reactor->DoCallback(state);
+}
+
+// Method does not check to see if the same handle is registered twice.
+HRESULT Reactor::RegisterHandle(HANDLE handle,
+                                EventHandler* event_handler,
+                                uint32 flags) {
+  ASSERT1(handle);
+  ASSERT1(event_handler);
+
+  if (!handle || !event_handler) {
+    return E_INVALIDARG;
+  }
+
+  scoped_ptr<RegistrationState> state(new RegistrationState);
+  state->event_handler = event_handler;
+  state->handle = handle;
+  state->reactor = this;
+  state->flags = flags | WT_EXECUTEONLYONCE;
+
+  // The reactor only calls the handler once.
+  ASSERT1(WT_EXECUTEDEFAULT == 0);
+
+  // As soon as the handle is registered, the thread pool can queue up a
+  // callback and reenter the reactor on a different thread.
+  // Acquire the critical section before registering the handle.
+  ::EnterCriticalSection(&cs_);
+#if DEBUG
+  // The same handle should not be registered multiple times.
+  std::vector<RegistrationState*>::iterator it = handlers_.begin();
+  for (; it != handlers_.end(); ++it) {
+    ASSERT((*it)->handle != handle, (_T("[already registered %d]"), handle));
+  }
+#endif
+  bool res = !!::RegisterWaitForSingleObject(&state->wait_handle,
+                                             state->handle,
+                                             &Reactor::Callback,
+                                             state.get(),
+                                             INFINITE,
+                                             state->flags);
+  HRESULT hr = res ? S_OK : HRESULTFromLastError();
+  if (SUCCEEDED(hr)) {
+    handlers_.push_back(state.release());
+  }
+  ::LeaveCriticalSection(&cs_);
+
+  return hr;
+}
+
+HRESULT Reactor::RegisterHandle(HANDLE handle) {
+  ::EnterCriticalSection(&cs_);
+  HRESULT hr = DoRegisterHandle(handle);
+  ::LeaveCriticalSection(&cs_);
+  return hr;
+}
+
+HRESULT Reactor::DoRegisterHandle(HANDLE handle) {
+  ASSERT1(handle);
+  std::vector<RegistrationState*>::iterator it = handlers_.begin();
+  for (; it != handlers_.end(); ++it) {
+    if ((*it)->handle == handle) {
+      break;
+    }
+  }
+  if (it == handlers_.end()) {
+    // The handle is not registered with the reactor anymore. Registering the
+    // the handle again is not possible.
+    return E_FAIL;
+  }
+
+  // Unregister and register the handle again. Unregistering is an non blocking
+  // call.
+  RegistrationState* state = *it;
+  bool res = !!::UnregisterWaitEx(state->wait_handle, NULL);
+  if (!res && ::GetLastError() != ERROR_IO_PENDING) {
+    return HRESULTFromLastError();
+  }
+  if (!::RegisterWaitForSingleObject(&state->wait_handle,
+                                     state->handle,
+                                     &Reactor::Callback,
+                                     state,
+                                     INFINITE,
+                                     state->flags)) {
+    return HRESULTFromLastError();
+  }
+  return S_OK;
+}
+
+HRESULT Reactor::UnregisterHandle(HANDLE handle) {
+  ASSERT1(handle);
+  if (!handle) {
+    return E_INVALIDARG;
+  }
+
+  // Attempts to take the ownership of the registration state for the handle.
+  // If taking the ownership does not succeed, it means the handle has already
+  // been unregistered.
+  scoped_ptr<RegistrationState> state(ReleaseHandlerState(handle));
+  if (!state.get()) {
+    return E_UNEXPECTED;
+  }
+
+  // Unregisters the wait handle from the thread pool. The call blocks waiting
+  // for any pending callbacks to finish. No lock is being held while waiting
+  // here. If there is no callback pending, the call will succeed right away.
+  // Otherwise, if a callback has already started, the call waits for the
+  // callback to complete.
+  bool res = !!::UnregisterWaitEx(state->wait_handle, INVALID_HANDLE_VALUE);
+
+  // Clear the registration state, as a defensive programming measure and
+  // for debugging purposes.
+  state->reactor          = NULL;
+  state->handle           = NULL;
+  state->wait_handle      = NULL;
+  state->event_handler    = NULL;
+
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+void Reactor::DoCallback(RegistrationState* state) {
+  ASSERT1(state);
+  ASSERT1(state->event_handler);
+  ASSERT1(state->handle);
+  state->event_handler->HandleEvent(state->handle);
+}
+
+// Looks up the registration state for a handle and releases the ownership
+// of it to the caller. As the clean up of the state can happen from multiple
+// places, the transfer of ownership ensures the clean up happens once and
+// only once.
+Reactor::RegistrationState* Reactor::ReleaseHandlerState(HANDLE handle) {
+  RegistrationState* registration_state = NULL;
+  ::EnterCriticalSection(&cs_);
+  std::vector<RegistrationState*>::iterator it = handlers_.begin();
+  for (; it != handlers_.end(); ++it) {
+    if ((*it)->handle == handle) {
+      registration_state = *it;
+      handlers_.erase(it);
+      break;
+    }
+  }
+  ::LeaveCriticalSection(&cs_);
+  return registration_state;
+}
+
+}  // namespace omaha
+
diff --git a/common/reactor.h b/common/reactor.h
index d1e14ae..7cad78e 100644
--- a/common/reactor.h
+++ b/common/reactor.h
@@ -1,92 +1,92 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// reactor.{h, cc} implements the reactor design pattern.

-//

-// For each signaled handle the reactor calls back the event handler only once.

-// To get further notifications, the handle must be registered again with the

-// reactor. This may sound like a lot of work but this is the only way to

-// guarantee that the event handler is only called once.

-// UnregisterHandle can't be called when handling a callback or it results in

-// a deadlock. When handling a callback, the only possible operation is

-// registering back a handle using Register.

-

-#ifndef OMAHA_COMMON_REACTOR_H__

-#define OMAHA_COMMON_REACTOR_H__

-

-#include <windows.h>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class EventHandler;

-

-class Reactor {

- public:

-  Reactor();

-  ~Reactor();

-

-  // Starts demultiplexing and dispatching events.

-  HRESULT HandleEvents();

-

-  // Registers an event handler for a handle. The reactor does not own the

-  // handle. Registering the same handle twice results in undefined behavior.

-  // The flags parameter can be one of the WT* thread pool values or 0 for

-  // a reasonable default.

-  HRESULT RegisterHandle(HANDLE handle,

-                         EventHandler* event_handler,

-                         uint32 flags);

-

-  // Registers the handle again. This method can be called from the callback.

-  HRESULT RegisterHandle(HANDLE handle);

-

-  // Unregisters the handle. The method blocks and waits for any callback to

-  // complete if an event dispatching is in progress.

-  HRESULT UnregisterHandle(HANDLE handle);

-

- private:

-  struct RegistrationState {

-    RegistrationState()

-        : reactor(NULL),

-          event_handler(NULL),

-          handle(NULL),

-          wait_handle(NULL),

-          flags(0) {}

-

-    Reactor*      reactor;

-    EventHandler* event_handler;

-    HANDLE        handle;

-    HANDLE        wait_handle;

-    uint32        flags;

-  };

-

-  static void __stdcall Callback(void* param, BOOLEAN timer_or_wait);

-  void DoCallback(RegistrationState* registration_state);

-

-  HRESULT DoRegisterHandle(HANDLE handle);

-

-  // Releases the ownership of the registration state corresponding to a handle.

-  RegistrationState* ReleaseHandlerState(HANDLE handle);

-

-  CRITICAL_SECTION cs_;

-  std::vector<RegistrationState*> handlers_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Reactor);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_REACTOR_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// reactor.{h, cc} implements the reactor design pattern.
+//
+// For each signaled handle the reactor calls back the event handler only once.
+// To get further notifications, the handle must be registered again with the
+// reactor. This may sound like a lot of work but this is the only way to
+// guarantee that the event handler is only called once.
+// UnregisterHandle can't be called when handling a callback or it results in
+// a deadlock. When handling a callback, the only possible operation is
+// registering back a handle using Register.
+
+#ifndef OMAHA_COMMON_REACTOR_H__
+#define OMAHA_COMMON_REACTOR_H__
+
+#include <windows.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class EventHandler;
+
+class Reactor {
+ public:
+  Reactor();
+  ~Reactor();
+
+  // Starts demultiplexing and dispatching events.
+  HRESULT HandleEvents();
+
+  // Registers an event handler for a handle. The reactor does not own the
+  // handle. Registering the same handle twice results in undefined behavior.
+  // The flags parameter can be one of the WT* thread pool values or 0 for
+  // a reasonable default.
+  HRESULT RegisterHandle(HANDLE handle,
+                         EventHandler* event_handler,
+                         uint32 flags);
+
+  // Registers the handle again. This method can be called from the callback.
+  HRESULT RegisterHandle(HANDLE handle);
+
+  // Unregisters the handle. The method blocks and waits for any callback to
+  // complete if an event dispatching is in progress.
+  HRESULT UnregisterHandle(HANDLE handle);
+
+ private:
+  struct RegistrationState {
+    RegistrationState()
+        : reactor(NULL),
+          event_handler(NULL),
+          handle(NULL),
+          wait_handle(NULL),
+          flags(0) {}
+
+    Reactor*      reactor;
+    EventHandler* event_handler;
+    HANDLE        handle;
+    HANDLE        wait_handle;
+    uint32        flags;
+  };
+
+  static void __stdcall Callback(void* param, BOOLEAN timer_or_wait);
+  void DoCallback(RegistrationState* registration_state);
+
+  HRESULT DoRegisterHandle(HANDLE handle);
+
+  // Releases the ownership of the registration state corresponding to a handle.
+  RegistrationState* ReleaseHandlerState(HANDLE handle);
+
+  CRITICAL_SECTION cs_;
+  std::vector<RegistrationState*> handlers_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Reactor);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_REACTOR_H__
diff --git a/common/reactor_unittest.cc b/common/reactor_unittest.cc
index 09211df..bacb397 100644
--- a/common/reactor_unittest.cc
+++ b/common/reactor_unittest.cc
@@ -1,136 +1,136 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include <stdlib.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/event_handler.h"

-#include "omaha/common/reactor.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// TODO(omaha): rename EventHandler to EventHandlerInterface.

-

-// Creates and registers two waitable timers with the reactor. They go off

-// randomly until the reactor stops handling events.

-class ReactorTest

-    : public testing::Test,

-      public EventHandler {

- protected:

-  ReactorTest() : cnt_(0) {}

-

-  virtual void SetUp() {

-    // Timer handles are with auto reset for simplicity.

-    reset(timer1_, ::CreateWaitableTimer(NULL, false, NULL));

-    reset(timer2_, ::CreateWaitableTimer(NULL, false, NULL));

-

-    reset(event_done_, ::CreateEvent(NULL, true, false, NULL));

-

-    ASSERT_TRUE(timer1_);

-    ASSERT_TRUE(timer2_);

-    ASSERT_TRUE(event_done_);

-

-    // We only need the thread handle to queue an empty APC to it.

-    reset(main_thread_, ::OpenThread(THREAD_ALL_ACCESS,

-                                     false,

-                                     ::GetCurrentThreadId()));

-    ASSERT_TRUE(main_thread_);

-  }

-

-  virtual void TearDown() {

-  }

-

-  // EventHandler.

-  virtual void HandleEvent(HANDLE h);

-

-  // Empty APC to stop the reactor.

-  static void _stdcall Stop(ULONG_PTR) {}

-

-  // Returns an integer value in the [0, 10) range.

-  static int GetSmallInt() {

-    unsigned int val = 0;

-    rand_s(&val);

-    return val % 10;

-  }

-

-  Reactor reactor_;

-

-  scoped_timer timer1_;

-  scoped_timer timer2_;

-  scoped_event event_done_;

-

-  scoped_handle main_thread_;

-  LONG cnt_;

-  static const LONG ReactorTest::kMaxCount = 10;

-};

-

-const LONG ReactorTest::kMaxCount;

-

-void ReactorTest::HandleEvent(HANDLE h) {

-  EXPECT_TRUE(h);

-  if (h == get(event_done_)) {

-    ASSERT_TRUE(::QueueUserAPC(&ReactorTest::Stop,

-                               get(main_thread_),

-                               0));

-  } else if (h == get(timer1_) || h == get(timer2_)) {

-    // Check the handles auto reset correctly.

-    EXPECT_EQ(::WaitForSingleObject(h, 0), WAIT_TIMEOUT);

-    if (::InterlockedIncrement(&cnt_) > kMaxCount) {

-      ASSERT_TRUE(::SetEvent(get(event_done_)));

-    } else {

-      ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(h));

-

-      unsigned int val = 0;

-      ASSERT_EQ(rand_s(&val), 0);

-      val %= 10;

-

-      // Set the timer to fire; negative values indicate relative time.

-      LARGE_INTEGER due_time_100ns = {0};

-      due_time_100ns.QuadPart = -(static_cast<int>(val) * 10 * 1000);

-      ASSERT_TRUE(::SetWaitableTimer(h, &due_time_100ns, 0, NULL, NULL, false));

-    }

-  }

-}

-

-// Registers the handles, primes the timers, and handles events.

-TEST_F(ReactorTest, HandleEvents) {

-  ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(get(event_done_), this, 0));

-  ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(get(timer1_), this, 0));

-  ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(get(timer2_), this, 0));

-

-  LARGE_INTEGER due_time_100ns = {0};

-  ASSERT_TRUE(SetWaitableTimer(get(timer1_),

-                               &due_time_100ns,

-                               0,

-                               NULL,

-                               NULL,

-                               false));

-  ASSERT_TRUE(SetWaitableTimer(get(timer2_),

-                               &due_time_100ns,

-                               0,

-                               NULL,

-                               NULL,

-                               false));

-

-  ASSERT_HRESULT_SUCCEEDED(reactor_.HandleEvents());

-

-  ASSERT_HRESULT_SUCCEEDED(reactor_.UnregisterHandle(get(timer2_)));

-  ASSERT_HRESULT_SUCCEEDED(reactor_.UnregisterHandle(get(timer1_)));

-  ASSERT_HRESULT_SUCCEEDED(reactor_.UnregisterHandle(get(event_done_)));

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include <stdlib.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/event_handler.h"
+#include "omaha/common/reactor.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// TODO(omaha): rename EventHandler to EventHandlerInterface.
+
+// Creates and registers two waitable timers with the reactor. They go off
+// randomly until the reactor stops handling events.
+class ReactorTest
+    : public testing::Test,
+      public EventHandler {
+ protected:
+  ReactorTest() : cnt_(0) {}
+
+  virtual void SetUp() {
+    // Timer handles are with auto reset for simplicity.
+    reset(timer1_, ::CreateWaitableTimer(NULL, false, NULL));
+    reset(timer2_, ::CreateWaitableTimer(NULL, false, NULL));
+
+    reset(event_done_, ::CreateEvent(NULL, true, false, NULL));
+
+    ASSERT_TRUE(timer1_);
+    ASSERT_TRUE(timer2_);
+    ASSERT_TRUE(event_done_);
+
+    // We only need the thread handle to queue an empty APC to it.
+    reset(main_thread_, ::OpenThread(THREAD_ALL_ACCESS,
+                                     false,
+                                     ::GetCurrentThreadId()));
+    ASSERT_TRUE(main_thread_);
+  }
+
+  virtual void TearDown() {
+  }
+
+  // EventHandler.
+  virtual void HandleEvent(HANDLE h);
+
+  // Empty APC to stop the reactor.
+  static void _stdcall Stop(ULONG_PTR) {}
+
+  // Returns an integer value in the [0, 10) range.
+  static int GetSmallInt() {
+    unsigned int val = 0;
+    rand_s(&val);
+    return val % 10;
+  }
+
+  Reactor reactor_;
+
+  scoped_timer timer1_;
+  scoped_timer timer2_;
+  scoped_event event_done_;
+
+  scoped_handle main_thread_;
+  LONG cnt_;
+  static const LONG ReactorTest::kMaxCount = 10;
+};
+
+const LONG ReactorTest::kMaxCount;
+
+void ReactorTest::HandleEvent(HANDLE h) {
+  EXPECT_TRUE(h);
+  if (h == get(event_done_)) {
+    ASSERT_TRUE(::QueueUserAPC(&ReactorTest::Stop,
+                               get(main_thread_),
+                               0));
+  } else if (h == get(timer1_) || h == get(timer2_)) {
+    // Check the handles auto reset correctly.
+    EXPECT_EQ(::WaitForSingleObject(h, 0), WAIT_TIMEOUT);
+    if (::InterlockedIncrement(&cnt_) > kMaxCount) {
+      ASSERT_TRUE(::SetEvent(get(event_done_)));
+    } else {
+      ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(h));
+
+      unsigned int val = 0;
+      ASSERT_EQ(rand_s(&val), 0);
+      val %= 10;
+
+      // Set the timer to fire; negative values indicate relative time.
+      LARGE_INTEGER due_time_100ns = {0};
+      due_time_100ns.QuadPart = -(static_cast<int>(val) * 10 * 1000);
+      ASSERT_TRUE(::SetWaitableTimer(h, &due_time_100ns, 0, NULL, NULL, false));
+    }
+  }
+}
+
+// Registers the handles, primes the timers, and handles events.
+TEST_F(ReactorTest, HandleEvents) {
+  ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(get(event_done_), this, 0));
+  ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(get(timer1_), this, 0));
+  ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(get(timer2_), this, 0));
+
+  LARGE_INTEGER due_time_100ns = {0};
+  ASSERT_TRUE(SetWaitableTimer(get(timer1_),
+                               &due_time_100ns,
+                               0,
+                               NULL,
+                               NULL,
+                               false));
+  ASSERT_TRUE(SetWaitableTimer(get(timer2_),
+                               &due_time_100ns,
+                               0,
+                               NULL,
+                               NULL,
+                               false));
+
+  ASSERT_HRESULT_SUCCEEDED(reactor_.HandleEvents());
+
+  ASSERT_HRESULT_SUCCEEDED(reactor_.UnregisterHandle(get(timer2_)));
+  ASSERT_HRESULT_SUCCEEDED(reactor_.UnregisterHandle(get(timer1_)));
+  ASSERT_HRESULT_SUCCEEDED(reactor_.UnregisterHandle(get(event_done_)));
+}
+
+}  // namespace omaha
diff --git a/common/reg_key.cc b/common/reg_key.cc
index d4f1f7d..ddfc61b 100644
--- a/common/reg_key.cc
+++ b/common/reg_key.cc
@@ -1,1265 +1,1265 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Registry configuration wrapers class implementation

-

-#include <raserror.h>

-#include "omaha/common/reg_key.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/static_assert.h"

-#include "omaha/common/string.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/system.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-HRESULT RegKey::Close() {

-  HRESULT hr = S_OK;

-  if (h_key_ != NULL) {

-    LONG res = RegCloseKey(h_key_);

-    hr = HRESULT_FROM_WIN32(res);

-    h_key_ = NULL;

-  }

-  return hr;

-}

-

-HRESULT RegKey::Create(HKEY hKeyParent,

-                       const TCHAR * key_name,

-                       TCHAR * lpszClass,

-                       DWORD options,

-                       REGSAM sam_desired,

-                       LPSECURITY_ATTRIBUTES lpSecAttr,

-                       LPDWORD lpdwDisposition) {

-  // lpszClass may be NULL

-  ASSERT1(key_name);

-  ASSERT1(hKeyParent != NULL);

-  DWORD dw;

-  HKEY hKey = NULL;

-  LONG res = ::RegCreateKeyEx(hKeyParent,

-                              key_name,

-                              0,

-                              lpszClass,

-                              options,

-                              sam_desired,

-                              lpSecAttr,

-                              &hKey,

-                              &dw);

-  HRESULT hr = HRESULT_FROM_WIN32(res);

-

-  if (lpdwDisposition != NULL)

-    *lpdwDisposition = dw;

-  // we have to close the currently opened key

-  // before replacing it with the new one

-  if (hr == S_OK) {

-    hr = Close();

-    ASSERT1(hr == S_OK);

-    h_key_ = hKey;

-  }

-  return hr;

-}

-

-HRESULT RegKey::Create(const TCHAR * full_key_name,

-                       TCHAR * lpszClass, DWORD options,

-                       REGSAM sam_desired,

-                       LPSECURITY_ATTRIBUTES lpSecAttr,

-                       LPDWORD lpdwDisposition) {

-  // lpszClass may be NULL

-  ASSERT1(full_key_name);

-  CString key_name(full_key_name);

-

-  HKEY parent_key = RegKey::GetRootKeyInfo(&key_name);

-  if (!parent_key) {

-    ASSERT(false, (_T("unable to get root key location %s"), full_key_name));

-    return HRESULT_FROM_WIN32(ERROR_KEY_NOT_FOUND);

-  }

-

-  return Create(parent_key, key_name, lpszClass,

-    options, sam_desired, lpSecAttr, lpdwDisposition);

-}

-

-HRESULT RegKey::CreateKeys(const TCHAR* keys_to_create[],

-                           DWORD number_of_keys,

-                           TCHAR* lpszClass,

-                           DWORD options,

-                           LPSECURITY_ATTRIBUTES lpSecAttr) {

-  ASSERT1(keys_to_create);

-  ASSERT1(number_of_keys);

-

-  for (DWORD i = 0; i < number_of_keys; i++) {

-    HRESULT hr = CreateKey(keys_to_create[i], lpszClass, options, lpSecAttr);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT RegKey::CreateKey(const TCHAR* full_key_name,

-                          TCHAR* lpszClass,

-                          DWORD options,

-                          LPSECURITY_ATTRIBUTES lpSecAttr) {

-  ASSERT1(full_key_name);

-

-  RegKey key;

-  HRESULT hr = key.Create(full_key_name,

-                          lpszClass,

-                          options,

-                          KEY_ALL_ACCESS,

-                          lpSecAttr,

-                          NULL);

-  if (FAILED(hr)) {

-    UTIL_LOG(L3, (_T("[couldn't create %s reg key]"), full_key_name));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT RegKey::Open(HKEY hKeyParent,

-                     const TCHAR * key_name,

-                     REGSAM sam_desired) {

-  ASSERT1(key_name);

-  ASSERT1(hKeyParent != NULL);

-  HKEY hKey = NULL;

-  LONG res = ::RegOpenKeyEx(hKeyParent, key_name, 0, sam_desired, &hKey);

-  HRESULT hr = HRESULT_FROM_WIN32(res);

-

-  // we have to close the currently opened key

-  // before replacing it with the new one

-  if (hr == S_OK) {

-    // close the currently opened key if any

-    hr = Close();

-    ASSERT1(hr == S_OK);

-    h_key_ = hKey;

-  }

-  return hr;

-}

-

-HRESULT RegKey::Open(const TCHAR * full_key_name, REGSAM sam_desired) {

-  ASSERT1(full_key_name);

-  CString key_name(full_key_name);

-

-  HKEY parent_key = RegKey::GetRootKeyInfo(&key_name);

-  if (!parent_key) {

-    ASSERT(false, (_T("unable to get root key for %s"), full_key_name));

-    return HRESULT_FROM_WIN32(ERROR_KEY_NOT_FOUND);

-  }

-

-  return Open(parent_key, key_name, sam_desired);

-}

-

-// save the key and all of its subkeys and values to a file

-HRESULT RegKey::Save(const TCHAR* full_key_name, const TCHAR* file_name) {

-  ASSERT1(full_key_name);

-  ASSERT1(file_name);

-

-  CString key_name(full_key_name);

-  HKEY h_key = GetRootKeyInfo(&key_name);

-  if (!h_key) {

-    return E_FAIL;

-  }

-

-  RegKey key;

-  HRESULT hr = key.Open(h_key, key_name, KEY_READ);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  System::AdjustPrivilege(SE_BACKUP_NAME, true);

-  LONG res = ::RegSaveKey(key.h_key_, file_name, NULL);

-  System::AdjustPrivilege(SE_BACKUP_NAME, false);

-

-  return HRESULT_FROM_WIN32(res);

-}

-

-// restore the key and all of its subkeys and values which are saved into a file

-HRESULT RegKey::Restore(const TCHAR* full_key_name, const TCHAR* file_name) {

-  ASSERT1(full_key_name);

-  ASSERT1(file_name);

-

-  CString key_name(full_key_name);

-  HKEY h_key = GetRootKeyInfo(&key_name);

-  if (!h_key) {

-    return E_FAIL;

-  }

-

-  RegKey key;

-  HRESULT hr = key.Open(h_key, key_name, KEY_WRITE);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  System::AdjustPrivilege(SE_RESTORE_NAME, true);

-  LONG res = ::RegRestoreKey(key.h_key_, file_name, REG_FORCE_RESTORE);

-  System::AdjustPrivilege(SE_RESTORE_NAME, false);

-

-  return HRESULT_FROM_WIN32(res);

-}

-

-// check if the current key has the specified subkey

-bool RegKey::HasSubkey(const TCHAR * key_name) const {

-  ASSERT1(key_name);

-  ASSERT1(h_key_);

-

-  RegKey key;

-  HRESULT hr = key.Open(h_key_, key_name, KEY_READ);

-  key.Close();

-  return S_OK == hr;

-}

-

-// static flush key

-HRESULT RegKey::FlushKey(const TCHAR * full_key_name) {

-  ASSERT1(full_key_name);

-

-  HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);

-  // get the root HKEY

-  CString key_name(full_key_name);

-  HKEY h_key = GetRootKeyInfo(&key_name);

-

-  if (h_key != NULL) {

-    LONG res = RegFlushKey(h_key);

-    hr = HRESULT_FROM_WIN32(res);

-  }

-  return hr;

-}

-

-// static SET helper

-HRESULT RegKey::SetValueStaticHelper(const TCHAR * full_key_name,

-                                     const TCHAR * value_name,

-                                     DWORD type,

-                                     LPVOID value,

-                                     DWORD byte_count) {

-  // value_name may be NULL

-  ASSERT1(full_key_name);

-

-  HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);

-  // get the root HKEY

-  CString key_name(full_key_name);

-  HKEY h_key = GetRootKeyInfo(&key_name);

-

-  if (h_key != NULL) {

-    RegKey key;

-    hr = key.Create(h_key, key_name.GetString());

-    if (hr == S_OK) {

-      switch (type) {

-        case REG_DWORD:

-          hr = key.SetValue(value_name, *reinterpret_cast<DWORD *>(value));

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Wrote int32 key: %s\\%s = %d]"),

-                          full_key_name,

-                          value_name,

-                          *reinterpret_cast<DWORD*>(value)));

-          }

-          break;

-        case REG_QWORD:

-          hr = key.SetValue(value_name, *reinterpret_cast<DWORD64 *>(value));

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Wrote int64 key: %s\\%s = %s]"),

-                          full_key_name,

-                          value_name,

-                          String_Int64ToString(

-                              *reinterpret_cast<DWORD64*>(value), 10)));

-          }

-          break;

-        case REG_SZ:

-          hr = key.SetValue(value_name, reinterpret_cast<const TCHAR *>(value));

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Wrote string key: %s\\%s = %s]"),

-                          full_key_name,

-                          value_name,

-                          reinterpret_cast<const TCHAR *>(value)));

-          }

-          break;

-        case REG_BINARY:

-          hr = key.SetValue(value_name,

-                            reinterpret_cast<const byte *>(value),

-                            byte_count);

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Wrote binary key: %s\\%s, len = %d]"),

-                          full_key_name, value_name, byte_count));

-          }

-          break;

-        case REG_MULTI_SZ:

-          hr = key.SetValue(value_name,

-                            reinterpret_cast<const byte *>(value),

-                            byte_count,

-                            type);

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Wrote multi-sz key: %s\\%s, len = %d]"),

-                          full_key_name, value_name, byte_count));

-          }

-          break;

-        case REG_EXPAND_SZ:

-          hr = key.SetStringValue(value_name,

-                                  reinterpret_cast<const TCHAR *>(value),

-                                  type);

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Wrote expandable string key: %s\\%s = %s]"),

-                          full_key_name, value_name, (const TCHAR *)value));

-          }

-          break;

-        default:

-          ASSERT(false, (_T("Unsupported Registry Type")));

-          hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);

-          break;

-      }

-      // close the key after writing

-      HRESULT temp_res = key.Close();

-      if (hr == S_OK) {

-        hr = temp_res;

-      } else {

-        ASSERT(false, (_T("Failed to write reg key: %s\\%s (hr=0x%x)"),

-                       full_key_name, value_name, hr));

-      }

-    } else {

-      UTIL_LOG(L3, (_T("[Failed to create reg key: %s]"), full_key_name));

-    }

-  }

-  return hr;

-}

-

-// static GET helper

-// byte_count may be NULL.

-// value_name may be NULL.

-HRESULT RegKey::GetValueStaticHelper(const TCHAR * full_key_name,

-                                     const TCHAR * value_name,

-                                     DWORD type,

-                                     LPVOID value,

-                                     DWORD * byte_count) {

-  ASSERT1(full_key_name);

-

-  HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);

-  // get the root HKEY

-  CString key_name(full_key_name);

-  HKEY h_key = GetRootKeyInfo(&key_name);

-

-  if (h_key != NULL) {

-    RegKey key;

-    hr = key.Open(h_key, key_name.GetString(), KEY_READ);

-    if (hr == S_OK) {

-      switch (type) {

-        case REG_DWORD:

-          hr = key.GetValue(value_name, reinterpret_cast<DWORD *>(value));

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Read int32 key: %s\\%s = %d]"),

-                          full_key_name,

-                          value_name,

-                          *reinterpret_cast<DWORD*>(value)));

-          }

-          break;

-        case REG_QWORD:

-          hr = key.GetValue(value_name, reinterpret_cast<DWORD64 *>(value));

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Read int64 key: %s\\%s = %s]"),

-                          full_key_name,

-                          value_name,

-                          String_Int64ToString(

-                              *(reinterpret_cast<DWORD64*>(value)), 10)));

-          }

-          break;

-        case REG_SZ:

-          hr = key.GetValue(value_name, reinterpret_cast<TCHAR * *>(value));

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Read string key: %s\\%s = %s]"),

-                          full_key_name,

-                          value_name,

-                          *reinterpret_cast<TCHAR * *>(value)));

-          }

-          break;

-        case REG_MULTI_SZ:

-          hr = key.GetValue(value_name,

-                            reinterpret_cast<std::vector<CString> *>(value));

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Read multi string key: %s\\%s = %d]"),

-                full_key_name,

-                value_name,

-                reinterpret_cast<std::vector<CString>*>(value)->size()));

-          }

-          break;

-        case REG_BINARY:

-          hr = key.GetValue(value_name,

-                            reinterpret_cast<byte * *>(value),

-                            byte_count);

-          if (SUCCEEDED(hr)) {

-            UTIL_LOG(L6, (_T("[Read binary key: %s\\%s, len = %d]"),

-                          full_key_name, value_name, byte_count));

-          }

-          break;

-        default:

-          ASSERT(false, (_T("Unsupported Registry Type")));

-          hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);

-          break;

-      }

-      // close the key after writing

-      HRESULT temp_res = key.Close();

-      if (hr == S_OK) {

-        hr = temp_res;

-      } else {

-        UTIL_LOG(L5, (_T("[Failed to read key: %s\\%s]"),

-                      full_key_name, value_name));

-      }

-    } else {

-      UTIL_LOG(L5, (_T("[reg key does not exist: %s]"), key_name));

-    }

-  }

-  return hr;

-}

-

-// GET helper

-// value_name may be NULL.

-HRESULT RegKey::GetValueHelper(const TCHAR * value_name,

-                               DWORD * type,

-                               byte * * value,

-                               DWORD * byte_count) const {

-  ASSERT1(byte_count);

-  ASSERT1(value);

-  ASSERT1(type);

-  ASSERT1(h_key_);

-

-  // init return buffer

-  *value = NULL;

-

-  // get the size of the return data buffer

-  LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, type, NULL, byte_count);

-  HRESULT hr = HRESULT_FROM_WIN32(res);

-

-  if (hr == S_OK) {

-    // if the value length is 0, nothing to do

-    if (*byte_count != 0) {

-      // allocate the buffer

-      *value = new byte[*byte_count];

-      ASSERT1(*value);

-

-      // make the call again to get the data

-      res = ::SHQueryValueEx(h_key_,

-                             value_name,

-                             NULL,

-                             type,

-                             *value,

-                             byte_count);

-      hr = HRESULT_FROM_WIN32(res);

-      ASSERT1(S_OK == hr);

-    }

-  }

-  return hr;

-}

-

-// Int32 Get

-// value_name may be NULL.

-HRESULT RegKey::GetValue(const TCHAR * value_name, DWORD * value) const {

-  ASSERT1(value);

-  ASSERT1(h_key_);

-

-  DWORD type = 0;

-  DWORD byte_count = sizeof(DWORD);

-  LONG res = ::SHQueryValueEx(h_key_,

-                              value_name,

-                              NULL,

-                              &type,

-                              reinterpret_cast<byte*>(value),

-                              &byte_count);

-  HRESULT hr = HRESULT_FROM_WIN32(res);

-  ASSERT1((hr != S_OK) || (type == REG_DWORD));

-  ASSERT1((hr != S_OK) || (byte_count == sizeof(DWORD)));

-  return hr;

-}

-

-// Int64 Get

-// value_name may be NULL.

-HRESULT RegKey::GetValue(const TCHAR * value_name, DWORD64 * value) const {

-  ASSERT1(value);

-  ASSERT1(h_key_);

-

-  DWORD type = 0;

-  DWORD byte_count = sizeof(DWORD64);

-  LONG res = ::SHQueryValueEx(h_key_,

-                              value_name,

-                              NULL,

-                              &type,

-                              reinterpret_cast<byte *>(value),

-                              &byte_count);

-  HRESULT hr = HRESULT_FROM_WIN32(res);

-  ASSERT1((hr != S_OK) || (type == REG_QWORD));

-  ASSERT1((hr != S_OK) || (byte_count == sizeof(DWORD64)));

-  return hr;

-}

-

-// String Get

-// value_name may be NULL.

-HRESULT RegKey::GetValue(const TCHAR * value_name, TCHAR * * value) const {

-  ASSERT1(value);

-  ASSERT1(h_key_);

-

-  DWORD byte_count = 0;

-  DWORD type = 0;

-

-  // first get the size of the string buffer

-  LONG res = ::SHQueryValueEx(h_key_,

-                              value_name,

-                              NULL,

-                              &type,

-                              NULL,

-                              &byte_count);

-  HRESULT hr = HRESULT_FROM_WIN32(res);

-

-  if (hr == S_OK) {

-    // allocate room for the string and a terminating \0

-    *value = new TCHAR[(byte_count / sizeof(TCHAR)) + 1];

-

-    if ((*value) != NULL) {

-      if (byte_count != 0) {

-        // make the call again

-        res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,

-                              reinterpret_cast<byte*>(*value), &byte_count);

-        hr = HRESULT_FROM_WIN32(res);

-      } else {

-        (*value)[0] = _T('\0');

-      }

-

-      ASSERT1((hr != S_OK) || (type == REG_SZ) ||

-              (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));

-    } else {

-      hr = E_OUTOFMEMORY;

-    }

-  }

-

-  return hr;

-}

-

-// CString Get

-// value_name may be NULL.

-HRESULT RegKey::GetValue(const TCHAR* value_name, OUT CString* value) const {

-  ASSERT1(value);

-  ASSERT1(h_key_);

-

-  DWORD byte_count = 0;

-  DWORD type = 0;

-

-  // first get the size of the string buffer

-  LONG res = ::SHQueryValueEx(h_key_,

-                              value_name,

-                              NULL,

-                              &type,

-                              NULL,

-                              &byte_count);

-  HRESULT hr = HRESULT_FROM_WIN32(res);

-

-  if (hr == S_OK) {

-    if (byte_count != 0) {

-      // Allocate some memory and make the call again

-      TCHAR* buffer = value->GetBuffer(byte_count / sizeof(TCHAR) + 1);

-      if (buffer == NULL) {

-        hr = E_OUTOFMEMORY;

-      } else {

-        res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,

-                              reinterpret_cast<byte*>(buffer), &byte_count);

-        hr = HRESULT_FROM_WIN32(res);

-      }

-      value->ReleaseBuffer();

-    } else {

-      value->Empty();

-    }

-

-    ASSERT1((hr != S_OK) || (type == REG_SZ) ||

-            (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));

-  }

-

-  return hr;

-}

-

-// convert REG_MULTI_SZ bytes to string array

-HRESULT RegKey::MultiSZBytesToStringArray(const byte * buffer,

-                                          DWORD byte_count,

-                                          std::vector<CString> * value) {

-  ASSERT1(buffer);

-  ASSERT1(value);

-

-  const TCHAR* data = reinterpret_cast<const TCHAR*>(buffer);

-  DWORD data_len = byte_count / sizeof(TCHAR);

-  value->clear();

-  if (data_len > 1) {

-    // must be terminated by two null characters

-    if (data[data_len - 1] != 0 || data[data_len - 2] != 0) {

-      return E_INVALIDARG;

-    }

-

-    // put null-terminated strings into arrays

-    while (*data) {

-      CString str(data);

-      value->push_back(str);

-      data += str.GetLength() + 1;

-    }

-  }

-  return S_OK;

-}

-

-// get a vector<CString> value from REG_MULTI_SZ type

-HRESULT RegKey::GetValue(const TCHAR * value_name,

-                         std::vector<CString> * value) const {

-  ASSERT1(value);

-  // value_name may be NULL

-

-  DWORD byte_count = 0;

-  DWORD type = 0;

-  byte* buffer = 0;

-

-  // first get the size of the buffer

-  HRESULT hr = GetValueHelper(value_name, &type, &buffer, &byte_count);

-  ASSERT1((hr != S_OK) || (type == REG_MULTI_SZ));

-

-  if (SUCCEEDED(hr)) {

-    hr = MultiSZBytesToStringArray(buffer, byte_count, value);

-  }

-

-  return hr;

-}

-

-// Binary data Get

-HRESULT RegKey::GetValue(const TCHAR * value_name,

-                         byte * * value,

-                         DWORD * byte_count) const {

-  ASSERT1(byte_count);

-  ASSERT1(value);

-  // value_name may be NULL

-

-  DWORD type = 0;

-  HRESULT hr = GetValueHelper(value_name, &type, value, byte_count);

-  ASSERT1((hr != S_OK) || (type == REG_MULTI_SZ) || (type == REG_BINARY));

-  return hr;

-}

-

-// Raw data get

-HRESULT RegKey::GetValue(const TCHAR * value_name,

-                         byte * * value,

-                         DWORD * byte_count,

-                         DWORD *type) const {

-  ASSERT1(type);

-  ASSERT1(byte_count);

-  ASSERT1(value);

-

-  return GetValueHelper(value_name, type, value, byte_count);

-}

-

-// Int32 set

-// value_name may be NULL

-HRESULT RegKey::SetValue(const TCHAR * value_name, DWORD value) const {

-  ASSERT1(h_key_);

-  LONG res = RegSetValueEx(h_key_,

-                           value_name,

-                           NULL,

-                           REG_DWORD,

-                           reinterpret_cast<byte *>(&value),

-                           sizeof(DWORD));

-  return HRESULT_FROM_WIN32(res);

-}

-

-// Int64 set

-// value_name may be NULL

-HRESULT RegKey::SetValue(const TCHAR * value_name, DWORD64 value) const {

-  ASSERT1(h_key_);

-  LONG res = RegSetValueEx(h_key_,

-                           value_name,

-                           NULL,

-                           REG_QWORD,

-                           reinterpret_cast<byte *>(&value),

-                           sizeof(DWORD64));

-  return HRESULT_FROM_WIN32(res);

-}

-

-// String set

-HRESULT RegKey::SetValue(const TCHAR * value_name, const TCHAR * value) const {

-  return SetStringValue(value_name, value, REG_SZ);

-}

-

-// String set helper

-// value_name may be NULL.

-HRESULT RegKey::SetStringValue(const TCHAR * value_name,

-                               const TCHAR * value,

-                               DWORD type) const {

-  ASSERT1(value);

-  ASSERT1(h_key_);

-  ASSERT1(type == REG_SZ || type == REG_EXPAND_SZ);

-  LONG res = RegSetValueEx(h_key_,

-                           value_name,

-                           NULL,

-                           type,

-                           reinterpret_cast<const byte *>(value),

-                           (lstrlen(value) + 1) * sizeof(TCHAR));

-  return HRESULT_FROM_WIN32(res);

-}

-

-// Binary data set

-// value may be NULL.

-// value_name may be NULL.

-HRESULT RegKey::SetValue(const TCHAR * value_name,

-                         const byte * value,

-                         DWORD byte_count) const {

-  ASSERT1(h_key_);

-

-  // special case - if 'value' is NULL make sure byte_count is zero

-  if (value == NULL) {

-    byte_count = 0;

-  }

-

-  LONG res = RegSetValueEx(h_key_,

-                           value_name,

-                           NULL,

-                           REG_BINARY,

-                           value,

-                           byte_count);

-  return HRESULT_FROM_WIN32(res);

-}

-

-// Raw data set

-// value_name may be NULL.

-HRESULT RegKey::SetValue(const TCHAR * value_name,

-                         const byte * value,

-                         DWORD byte_count,

-                         DWORD type) const {

-  ASSERT1(value);

-  ASSERT1(h_key_);

-  LONG res = RegSetValueEx(h_key_, value_name, NULL, type, value, byte_count);

-  return HRESULT_FROM_WIN32(res);

-}

-

-HRESULT RegKey::RenameValue(const TCHAR* old_value_name,

-                            const TCHAR* new_value_name) const {

-  ASSERT1(h_key_);

-  ASSERT1(new_value_name);

-  ASSERT1(old_value_name);

-

-  scoped_ptr<byte> value;

-  DWORD byte_count = 0;

-  DWORD type = 0;

-

-  HRESULT hr = GetValue(old_value_name, address(value), &byte_count, &type);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = SetValue(new_value_name, value.get(), byte_count, type);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  VERIFY1(SUCCEEDED(DeleteValue(old_value_name)));

-  return S_OK;

-}

-

-bool RegKey::HasKey(const TCHAR * full_key_name) {

-  return HasKeyHelper(full_key_name, KEY_READ);

-}

-

-bool RegKey::HasNativeKey(const TCHAR * full_key_name) {

-  return HasKeyHelper(full_key_name, KEY_READ | KEY_WOW64_64KEY);

-}

-

-bool RegKey::HasKeyHelper(const TCHAR * full_key_name, DWORD sam_flags) {

-  ASSERT1(full_key_name);

-  ASSERT1(sam_flags & KEY_READ);

-

-  // get the root HKEY

-  CString key_name(full_key_name);

-  HKEY h_key = GetRootKeyInfo(&key_name);

-

-  if (h_key != NULL) {

-    RegKey key;

-    HRESULT hr = key.Open(h_key, key_name.GetString(), sam_flags);

-    key.Close();

-    return S_OK == hr;

-  }

-  return false;

-}

-

-HRESULT RegKey::CopyValue(const TCHAR * full_from_key_name,

-                          const TCHAR * from_value_name,

-                          const TCHAR * full_to_key_name,

-                          const TCHAR * to_value_name) {

-  ASSERT1(full_from_key_name);

-  ASSERT1(full_to_key_name);

-

-  RegKey from_reg_key;

-  HRESULT hr = from_reg_key.Open(full_from_key_name, KEY_READ);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  scoped_ptr<byte> val;

-  DWORD byte_count = 0;

-  DWORD type = 0;

-  hr = from_reg_key.GetValue(from_value_name, address(val), &byte_count, &type);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  RegKey to_reg_key;

-  hr = to_reg_key.Open(full_to_key_name, KEY_WRITE);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return to_reg_key.SetValue(to_value_name, val.get(), byte_count, type);

-}

-

-// static version of HasValue

-bool RegKey::HasValue(const TCHAR * full_key_name, const TCHAR * value_name) {

-  ASSERT1(full_key_name);

-

-  bool has_value = false;

-  // get the root HKEY

-  CString key_name(full_key_name);

-  HKEY h_key = GetRootKeyInfo(&key_name);

-

-  if (h_key != NULL) {

-    RegKey key;

-    if (key.Open(h_key, key_name.GetString(), KEY_READ) == S_OK) {

-      has_value = key.HasValue(value_name);

-      key.Close();

-    }

-  }

-  return has_value;

-}

-

-HRESULT RegKey::GetValueType(const TCHAR* full_key_name,

-                             const TCHAR* value_name,

-                             DWORD* value_type) {

-  ASSERT1(full_key_name);

-  // value_name may be NULL

-  ASSERT1(value_type);

-

-  *value_type = REG_NONE;

-

-  CString key_name(full_key_name);

-  HKEY root_key = GetRootKeyInfo(&key_name);

-

-  HKEY key = NULL;

-  LONG res = ::RegOpenKeyEx(root_key, key_name, 0, KEY_READ, &key);

-  if (res != ERROR_SUCCESS) {

-    return HRESULT_FROM_WIN32(res);

-  }

-

-  scoped_hkey hkey(key);

-

-  res = ::SHQueryValueEx(get(hkey), value_name, NULL, value_type, NULL, NULL);

-  if (res != ERROR_SUCCESS) {

-    return HRESULT_FROM_WIN32(res);

-  }

-

-  return S_OK;

-}

-

-HRESULT RegKey::DeleteKey(const TCHAR* full_key_name) {

-  ASSERT1(full_key_name);

-

-  return DeleteKey(full_key_name, true);

-}

-

-HRESULT RegKey::DeleteKey(const TCHAR* full_key_name, bool recursively) {

-  ASSERT1(full_key_name);

-

-  // need to open the parent key first

-  // get the root HKEY

-  CString key_name(full_key_name);

-  HKEY h_key = GetRootKeyInfo(&key_name);

-

-  // get the parent key

-  CString parent_key(GetParentKeyInfo(&key_name));

-

-  RegKey key;

-  HRESULT hr = key.Open(h_key, parent_key);

-

-  if (hr == S_OK) {

-    hr = recursively ? key.RecurseDeleteSubKey(key_name) :

-                       key.DeleteSubKey(key_name);

-  } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||

-             hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {

-    hr = S_FALSE;

-  }

-

-  key.Close();

-  return hr;

-}

-

-HRESULT RegKey::DeleteValue(const TCHAR * full_key_name,

-                            const TCHAR * value_name) {

-  ASSERT1(value_name);

-  ASSERT1(full_key_name);

-

-  HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);

-  // get the root HKEY

-  CString key_name(full_key_name);

-  HKEY h_key = GetRootKeyInfo(&key_name);

-

-  if (h_key != NULL) {

-    RegKey key;

-    hr = key.Open(h_key, key_name.GetString());

-    if (hr == S_OK) {

-      hr = key.DeleteValue(value_name);

-      key.Close();

-    }

-  }

-  return hr;

-}

-

-HRESULT RegKey::RecurseDeleteSubKey(const TCHAR * key_name) {

-  ASSERT1(key_name);

-  ASSERT1(h_key_);

-

-  RegKey key;

-  HRESULT hr = key.Open(h_key_, key_name);

-  if (hr != S_OK)

-    return hr;

-

-  // enumerate all subkeys of this key

-  // and recursivelly delete them

-  FILETIME time;

-  TCHAR key_name_buf[kMaxKeyNameChars];

-  DWORD key_name_buf_size = kMaxKeyNameChars;

-  while (RegEnumKeyEx(key.h_key_,

-                      0,

-                      key_name_buf,

-                      &key_name_buf_size,

-                      NULL,

-                      NULL,

-                      NULL,

-                      &time) == ERROR_SUCCESS) {

-    hr = key.RecurseDeleteSubKey(key_name_buf);

-    // return if error deleting key

-    if (hr != S_OK)

-      return hr;

-    // restore the buffer size

-    key_name_buf_size = kMaxKeyNameChars;

-  }

-  // close the top key

-  key.Close();

-

-  // the key has no more children keys

-  // delete the key and all of its values

-  return DeleteSubKey(key_name);

-}

-

-HKEY RegKey::GetRootKeyInfo(CString * full_key_name) {

-  ASSERT1(full_key_name);

-

-  HKEY h_key = NULL;

-  // get the root HKEY

-  int index = String_FindChar(*(full_key_name), '\\');

-  CString root_key;

-

-  if (index == -1) {

-    root_key = *full_key_name;

-    *full_key_name = _T("");

-  } else {

-    root_key= full_key_name->Left(index);

-    *full_key_name =

-        full_key_name->Right(full_key_name->GetLength() - index - 1);

-  }

-

-  if (!root_key.CompareNoCase(_T("HKLM")) ||

-      !root_key.CompareNoCase(_T("HKEY_LOCAL_MACHINE")))

-    h_key = HKEY_LOCAL_MACHINE;

-  else if (!root_key.CompareNoCase(_T("HKCU")) ||

-           !root_key.CompareNoCase(_T("HKEY_CURRENT_USER")))

-    h_key = HKEY_CURRENT_USER;

-  else if (!root_key.CompareNoCase(_T("HKU")) ||

-           !root_key.CompareNoCase(_T("HKEY_USERS")))

-    h_key = HKEY_USERS;

-  else if (!root_key.CompareNoCase(_T("HKCR")) ||

-           !root_key.CompareNoCase(_T("HKEY_CLASSES_ROOT")))

-    h_key = HKEY_CLASSES_ROOT;

-

-  return h_key;

-}

-

-

-// Returns true if this key name is 'safe' for deletion (doesn't specify a

-// key root)

-bool RegKey::SafeKeyNameForDeletion(const wchar_t *key_name) {

-  ASSERT1(key_name);

-  CString key(key_name);

-

-  HKEY root_key = GetRootKeyInfo(&key);

-

-  if ( !root_key ) {

-    key = key_name;

-  }

-  if ( key.IsEmpty() ) {

-    return false;

-  }

-  bool found_subkey = false, backslash_found = false;

-  for (int i = 0 ; i < key.GetLength() ; ++i) {

-    if ( key[i] == L'\\' ) {

-      backslash_found = true;

-    } else if ( backslash_found ) {

-      found_subkey = true;

-      break;

-    }

-  }

-  return ( root_key == HKEY_USERS ) ? found_subkey : true;

-}

-

-CString RegKey::GetParentKeyInfo(CString * key_name) {

-  ASSERT1(key_name);

-

-  // get the parent key

-  int index = key_name->ReverseFind('\\');

-  CString parent_key;

-  if (index == -1) {

-    parent_key = _T("");

-  } else {

-    parent_key = key_name->Left(index);

-    *key_name = key_name->Right(key_name->GetLength() - index - 1);

-  }

-

-  return parent_key;

-}

-

-// get the number of values for this key

-uint32 RegKey::GetValueCount() {

-  ASSERT1(h_key_);

-  // number of values for key

-  DWORD  num_values = 0;

-

-  LONG res = ::RegQueryInfoKey(h_key_,       // key handle

-                               NULL,         // buffer for class name

-                               NULL,         // size of class string

-                               NULL,         // reserved

-                               NULL,         // number of subkeys

-                               NULL,         // longest subkey size

-                               NULL,         // longest class string

-                               &num_values,  // number of values for this key

-                               NULL,         // longest value name

-                               NULL,         // longest value data

-                               NULL,         // security descriptor

-                               NULL);        // last write time

-

-  ASSERT1(res == ERROR_SUCCESS);

-  return num_values;

-}

-

-// Enumerators for the value_names for this key

-

-// Called to get the value name for the given value name index

-// Use GetValueCount() to get the total value_name count for this key

-// Returns failure if no key at the specified index

-// type may be NULL.

-HRESULT RegKey::GetValueNameAt(int index, CString *value_name, DWORD *type) {

-  ASSERT1(value_name);

-  ASSERT1(h_key_);

-

-  LONG res = ERROR_SUCCESS;

-  TCHAR value_name_buf[kMaxValueNameChars];

-  DWORD value_name_buf_size = kMaxValueNameChars;

-  res = ::RegEnumValue(h_key_,

-                       index,

-                       value_name_buf,

-                       &value_name_buf_size,

-                       NULL,

-                       type,

-                       NULL,

-                       NULL);

-

-  if (res == ERROR_SUCCESS) {

-    value_name->SetString(value_name_buf);

-  }

-

-  return HRESULT_FROM_WIN32(res);

-}

-

-uint32 RegKey::GetSubkeyCount() {

-  ASSERT1(h_key_);

-

-  DWORD num_subkeys = 0;   // number of values for key

-

-  LONG res = ::RegQueryInfoKey(h_key_,        // key handle

-                               NULL,          // buffer for class name

-                               NULL,          // size of class string

-                               NULL,          // reserved

-                               &num_subkeys,  // number of subkeys

-                               NULL,          // longest subkey size

-                               NULL,          // longest class string

-                               NULL,          // number of values for this key

-                               NULL,          // longest value name

-                               NULL,          // longest value data

-                               NULL,          // security descriptor

-                               NULL);         // last write time

-

-  ASSERT1(res == ERROR_SUCCESS);

-  return num_subkeys;

-}

-

-HRESULT RegKey::GetSubkeyNameAt(int index, CString * key_name) {

-  ASSERT1(key_name);

-  ASSERT1(h_key_);

-

-  LONG res = ERROR_SUCCESS;

-  TCHAR key_name_buf[kMaxKeyNameChars];

-  DWORD key_name_buf_size = kMaxKeyNameChars;

-

-  res = ::RegEnumKeyEx(h_key_,

-                       index,

-                       key_name_buf,

-                       &key_name_buf_size,

-                       NULL,

-                       NULL,

-                       NULL,

-                       NULL);

-

-  if (res == ERROR_SUCCESS) {

-    key_name->SetString(key_name_buf);

-  }

-

-  return HRESULT_FROM_WIN32(res);

-}

-

-// Is the key empty: having no sub-keys and values

-bool RegKey::IsKeyEmpty(const TCHAR* full_key_name) {

-  ASSERT1(full_key_name);

-

-  bool is_empty = true;

-

-  // Get the root HKEY

-  CString key_name(full_key_name);

-  HKEY h_key = GetRootKeyInfo(&key_name);

-

-  // Open the key to check

-  if (h_key != NULL) {

-    RegKey key;

-    HRESULT hr = key.Open(h_key, key_name.GetString(), KEY_READ);

-    if (SUCCEEDED(hr)) {

-      is_empty = key.GetSubkeyCount() == 0 && key.GetValueCount() == 0;

-      key.Close();

-    }

-  }

-

-  return is_empty;

-}

-

-// close this reg key and the event

-HRESULT RegKeyWithChangeEvent::Close() {

-  reset(change_event_);

-  return RegKey::Close();

-}

-

-// Called to create/reset the event that gets signaled

-// any time the registry key changes

-// Note:

-//   * reg key should have been opened using KEY_NOTIFY for the sam_desired

-//

-// See the documentation for RegNotifyChangeKeyValue

-// for values for notify_filter.

-HRESULT RegKeyWithChangeEvent::SetupEvent(bool watch_subtree,

-                                          DWORD notify_filter) {

-  // If the event exists, then it should be in the signaled state

-  // indicating a registry change took place.  If not, then

-  // the caller is setting up the event a second time and this

-  // will create a memory leak.

-  ASSERT(!valid(change_event_) || HasChangeOccurred(),

-         (_T("Event is getting set-up for a second ")

-          _T("time without being signaled.")));

-

-  if (!valid(change_event_)) {

-    reset(change_event_, ::CreateEvent(NULL, TRUE, FALSE, NULL));

-    if (!valid(change_event_)) {

-      ASSERT(false, (_T("create event failed")));

-      return HRESULT_FROM_WIN32(::GetLastError());

-    }

-  } else {

-    if (!::ResetEvent(get(change_event_))) {

-      ASSERT(false, (_T("reset event failed")));

-      return HRESULT_FROM_WIN32(::GetLastError());

-    }

-  }

-

-  LONG res = ::RegNotifyChangeKeyValue(Key(), watch_subtree, notify_filter,

-      get(change_event_), TRUE);

-

-  if (res != ERROR_SUCCESS) {

-    // You may get this failure if you didn't pass in KEY_NOTIFY

-    // as part of the sam_desired flags during Open or Create

-    ASSERT(false, (_T("setting up change notification for a reg key failed")));

-

-    // Leave the event around so that it never changes once it has been set-up

-    // but in this case it will not get signaled again.

-  }

-

-  return HRESULT_FROM_WIN32(res);

-}

-

-// Indicates if any changes (that are being monitored have occured)

-bool RegKeyWithChangeEvent::HasChangeOccurred() const {

-  return IsHandleSignaled(get(change_event_));

-}

-

-

-RegKeyWatcher::RegKeyWatcher(const TCHAR* reg_key, bool watch_subtree,

-                             DWORD notify_filter, bool allow_creation)

-    : reg_key_string_(reg_key),

-      watch_subtree_(watch_subtree),

-      notify_filter_(notify_filter),

-      allow_creation_(allow_creation) {

-  UTIL_LOG(L3, (_T("[RegKeyWatcher::RegKeyWatcher][%s]"), reg_key));

-}

-

-HRESULT RegKeyWatcher::EnsureEventSetup() {

-  UTIL_LOG(L3, (_T("[RegKeyWatcher::EnsureEventSetup]")));

-  if (!reg_key_with_change_event_.get()) {

-    scoped_ptr<RegKeyWithChangeEvent> local_reg_key(new RegKeyWithChangeEvent);

-    if (!local_reg_key.get()) {

-      ASSERT(false, (_T("unable to allocate local_reg_key")));

-      return E_FAIL;

-    }

-

-    if (allow_creation_ && !RegKey::HasKey(reg_key_string_)) {

-      RegKey key;

-      VERIFY1(SUCCEEDED(key.Create(reg_key_string_)));

-    }

-

-    HRESULT hr = local_reg_key->Open(reg_key_string_, KEY_NOTIFY);

-    if (FAILED(hr)) {

-      ASSERT(false, (_T("couldn't open %s reg key for notifications. ")

-                     _T("Make sure you have pre-created the key!"),

-                     reg_key_string_));

-      return hr;

-    }

-    reg_key_with_change_event_.reset(local_reg_key.release());

-    reg_key_string_.Empty();

-  }

-

-  // if the event is set-up and no changes have occurred,

-  // then there is no need to re-setup the event.

-  if (reg_key_with_change_event_->change_event() && !HasChangeOccurred()) {

-    return S_OK;

-  }

-

-  return reg_key_with_change_event_->SetupEvent(watch_subtree_,

-                                                notify_filter_);

-}

-

-// Get the event that is signaled on registry changes.

-HANDLE RegKeyWatcher::change_event() const {

-  if (!reg_key_with_change_event_.get()) {

-    ASSERT(false, (_T("call RegKeyWatcher::EnsureEventSetup first")));

-    return NULL;

-  }

-  return reg_key_with_change_event_->change_event();

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Registry configuration wrapers class implementation
+
+#include <raserror.h>
+#include "omaha/common/reg_key.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/static_assert.h"
+#include "omaha/common/string.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/system.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+HRESULT RegKey::Close() {
+  HRESULT hr = S_OK;
+  if (h_key_ != NULL) {
+    LONG res = RegCloseKey(h_key_);
+    hr = HRESULT_FROM_WIN32(res);
+    h_key_ = NULL;
+  }
+  return hr;
+}
+
+HRESULT RegKey::Create(HKEY hKeyParent,
+                       const TCHAR * key_name,
+                       TCHAR * lpszClass,
+                       DWORD options,
+                       REGSAM sam_desired,
+                       LPSECURITY_ATTRIBUTES lpSecAttr,
+                       LPDWORD lpdwDisposition) {
+  // lpszClass may be NULL
+  ASSERT1(key_name);
+  ASSERT1(hKeyParent != NULL);
+  DWORD dw;
+  HKEY hKey = NULL;
+  LONG res = ::RegCreateKeyEx(hKeyParent,
+                              key_name,
+                              0,
+                              lpszClass,
+                              options,
+                              sam_desired,
+                              lpSecAttr,
+                              &hKey,
+                              &dw);
+  HRESULT hr = HRESULT_FROM_WIN32(res);
+
+  if (lpdwDisposition != NULL)
+    *lpdwDisposition = dw;
+  // we have to close the currently opened key
+  // before replacing it with the new one
+  if (hr == S_OK) {
+    hr = Close();
+    ASSERT1(hr == S_OK);
+    h_key_ = hKey;
+  }
+  return hr;
+}
+
+HRESULT RegKey::Create(const TCHAR * full_key_name,
+                       TCHAR * lpszClass, DWORD options,
+                       REGSAM sam_desired,
+                       LPSECURITY_ATTRIBUTES lpSecAttr,
+                       LPDWORD lpdwDisposition) {
+  // lpszClass may be NULL
+  ASSERT1(full_key_name);
+  CString key_name(full_key_name);
+
+  HKEY parent_key = RegKey::GetRootKeyInfo(&key_name);
+  if (!parent_key) {
+    ASSERT(false, (_T("unable to get root key location %s"), full_key_name));
+    return HRESULT_FROM_WIN32(ERROR_KEY_NOT_FOUND);
+  }
+
+  return Create(parent_key, key_name, lpszClass,
+    options, sam_desired, lpSecAttr, lpdwDisposition);
+}
+
+HRESULT RegKey::CreateKeys(const TCHAR* keys_to_create[],
+                           DWORD number_of_keys,
+                           TCHAR* lpszClass,
+                           DWORD options,
+                           LPSECURITY_ATTRIBUTES lpSecAttr) {
+  ASSERT1(keys_to_create);
+  ASSERT1(number_of_keys);
+
+  for (DWORD i = 0; i < number_of_keys; i++) {
+    HRESULT hr = CreateKey(keys_to_create[i], lpszClass, options, lpSecAttr);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT RegKey::CreateKey(const TCHAR* full_key_name,
+                          TCHAR* lpszClass,
+                          DWORD options,
+                          LPSECURITY_ATTRIBUTES lpSecAttr) {
+  ASSERT1(full_key_name);
+
+  RegKey key;
+  HRESULT hr = key.Create(full_key_name,
+                          lpszClass,
+                          options,
+                          KEY_ALL_ACCESS,
+                          lpSecAttr,
+                          NULL);
+  if (FAILED(hr)) {
+    UTIL_LOG(L3, (_T("[couldn't create %s reg key]"), full_key_name));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT RegKey::Open(HKEY hKeyParent,
+                     const TCHAR * key_name,
+                     REGSAM sam_desired) {
+  ASSERT1(key_name);
+  ASSERT1(hKeyParent != NULL);
+  HKEY hKey = NULL;
+  LONG res = ::RegOpenKeyEx(hKeyParent, key_name, 0, sam_desired, &hKey);
+  HRESULT hr = HRESULT_FROM_WIN32(res);
+
+  // we have to close the currently opened key
+  // before replacing it with the new one
+  if (hr == S_OK) {
+    // close the currently opened key if any
+    hr = Close();
+    ASSERT1(hr == S_OK);
+    h_key_ = hKey;
+  }
+  return hr;
+}
+
+HRESULT RegKey::Open(const TCHAR * full_key_name, REGSAM sam_desired) {
+  ASSERT1(full_key_name);
+  CString key_name(full_key_name);
+
+  HKEY parent_key = RegKey::GetRootKeyInfo(&key_name);
+  if (!parent_key) {
+    ASSERT(false, (_T("unable to get root key for %s"), full_key_name));
+    return HRESULT_FROM_WIN32(ERROR_KEY_NOT_FOUND);
+  }
+
+  return Open(parent_key, key_name, sam_desired);
+}
+
+// save the key and all of its subkeys and values to a file
+HRESULT RegKey::Save(const TCHAR* full_key_name, const TCHAR* file_name) {
+  ASSERT1(full_key_name);
+  ASSERT1(file_name);
+
+  CString key_name(full_key_name);
+  HKEY h_key = GetRootKeyInfo(&key_name);
+  if (!h_key) {
+    return E_FAIL;
+  }
+
+  RegKey key;
+  HRESULT hr = key.Open(h_key, key_name, KEY_READ);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  System::AdjustPrivilege(SE_BACKUP_NAME, true);
+  LONG res = ::RegSaveKey(key.h_key_, file_name, NULL);
+  System::AdjustPrivilege(SE_BACKUP_NAME, false);
+
+  return HRESULT_FROM_WIN32(res);
+}
+
+// restore the key and all of its subkeys and values which are saved into a file
+HRESULT RegKey::Restore(const TCHAR* full_key_name, const TCHAR* file_name) {
+  ASSERT1(full_key_name);
+  ASSERT1(file_name);
+
+  CString key_name(full_key_name);
+  HKEY h_key = GetRootKeyInfo(&key_name);
+  if (!h_key) {
+    return E_FAIL;
+  }
+
+  RegKey key;
+  HRESULT hr = key.Open(h_key, key_name, KEY_WRITE);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  System::AdjustPrivilege(SE_RESTORE_NAME, true);
+  LONG res = ::RegRestoreKey(key.h_key_, file_name, REG_FORCE_RESTORE);
+  System::AdjustPrivilege(SE_RESTORE_NAME, false);
+
+  return HRESULT_FROM_WIN32(res);
+}
+
+// check if the current key has the specified subkey
+bool RegKey::HasSubkey(const TCHAR * key_name) const {
+  ASSERT1(key_name);
+  ASSERT1(h_key_);
+
+  RegKey key;
+  HRESULT hr = key.Open(h_key_, key_name, KEY_READ);
+  key.Close();
+  return S_OK == hr;
+}
+
+// static flush key
+HRESULT RegKey::FlushKey(const TCHAR * full_key_name) {
+  ASSERT1(full_key_name);
+
+  HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+  // get the root HKEY
+  CString key_name(full_key_name);
+  HKEY h_key = GetRootKeyInfo(&key_name);
+
+  if (h_key != NULL) {
+    LONG res = RegFlushKey(h_key);
+    hr = HRESULT_FROM_WIN32(res);
+  }
+  return hr;
+}
+
+// static SET helper
+HRESULT RegKey::SetValueStaticHelper(const TCHAR * full_key_name,
+                                     const TCHAR * value_name,
+                                     DWORD type,
+                                     LPVOID value,
+                                     DWORD byte_count) {
+  // value_name may be NULL
+  ASSERT1(full_key_name);
+
+  HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+  // get the root HKEY
+  CString key_name(full_key_name);
+  HKEY h_key = GetRootKeyInfo(&key_name);
+
+  if (h_key != NULL) {
+    RegKey key;
+    hr = key.Create(h_key, key_name.GetString());
+    if (hr == S_OK) {
+      switch (type) {
+        case REG_DWORD:
+          hr = key.SetValue(value_name, *reinterpret_cast<DWORD *>(value));
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Wrote int32 key: %s\\%s = %d]"),
+                          full_key_name,
+                          value_name,
+                          *reinterpret_cast<DWORD*>(value)));
+          }
+          break;
+        case REG_QWORD:
+          hr = key.SetValue(value_name, *reinterpret_cast<DWORD64 *>(value));
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Wrote int64 key: %s\\%s = %s]"),
+                          full_key_name,
+                          value_name,
+                          String_Int64ToString(
+                              *reinterpret_cast<DWORD64*>(value), 10)));
+          }
+          break;
+        case REG_SZ:
+          hr = key.SetValue(value_name, reinterpret_cast<const TCHAR *>(value));
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Wrote string key: %s\\%s = %s]"),
+                          full_key_name,
+                          value_name,
+                          reinterpret_cast<const TCHAR *>(value)));
+          }
+          break;
+        case REG_BINARY:
+          hr = key.SetValue(value_name,
+                            reinterpret_cast<const byte *>(value),
+                            byte_count);
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Wrote binary key: %s\\%s, len = %d]"),
+                          full_key_name, value_name, byte_count));
+          }
+          break;
+        case REG_MULTI_SZ:
+          hr = key.SetValue(value_name,
+                            reinterpret_cast<const byte *>(value),
+                            byte_count,
+                            type);
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Wrote multi-sz key: %s\\%s, len = %d]"),
+                          full_key_name, value_name, byte_count));
+          }
+          break;
+        case REG_EXPAND_SZ:
+          hr = key.SetStringValue(value_name,
+                                  reinterpret_cast<const TCHAR *>(value),
+                                  type);
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Wrote expandable string key: %s\\%s = %s]"),
+                          full_key_name, value_name, (const TCHAR *)value));
+          }
+          break;
+        default:
+          ASSERT(false, (_T("Unsupported Registry Type")));
+          hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
+          break;
+      }
+      // close the key after writing
+      HRESULT temp_res = key.Close();
+      if (hr == S_OK) {
+        hr = temp_res;
+      } else {
+        ASSERT(false, (_T("Failed to write reg key: %s\\%s (hr=0x%x)"),
+                       full_key_name, value_name, hr));
+      }
+    } else {
+      UTIL_LOG(L3, (_T("[Failed to create reg key: %s]"), full_key_name));
+    }
+  }
+  return hr;
+}
+
+// static GET helper
+// byte_count may be NULL.
+// value_name may be NULL.
+HRESULT RegKey::GetValueStaticHelper(const TCHAR * full_key_name,
+                                     const TCHAR * value_name,
+                                     DWORD type,
+                                     LPVOID value,
+                                     DWORD * byte_count) {
+  ASSERT1(full_key_name);
+
+  HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+  // get the root HKEY
+  CString key_name(full_key_name);
+  HKEY h_key = GetRootKeyInfo(&key_name);
+
+  if (h_key != NULL) {
+    RegKey key;
+    hr = key.Open(h_key, key_name.GetString(), KEY_READ);
+    if (hr == S_OK) {
+      switch (type) {
+        case REG_DWORD:
+          hr = key.GetValue(value_name, reinterpret_cast<DWORD *>(value));
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Read int32 key: %s\\%s = %d]"),
+                          full_key_name,
+                          value_name,
+                          *reinterpret_cast<DWORD*>(value)));
+          }
+          break;
+        case REG_QWORD:
+          hr = key.GetValue(value_name, reinterpret_cast<DWORD64 *>(value));
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Read int64 key: %s\\%s = %s]"),
+                          full_key_name,
+                          value_name,
+                          String_Int64ToString(
+                              *(reinterpret_cast<DWORD64*>(value)), 10)));
+          }
+          break;
+        case REG_SZ:
+          hr = key.GetValue(value_name, reinterpret_cast<TCHAR * *>(value));
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Read string key: %s\\%s = %s]"),
+                          full_key_name,
+                          value_name,
+                          *reinterpret_cast<TCHAR * *>(value)));
+          }
+          break;
+        case REG_MULTI_SZ:
+          hr = key.GetValue(value_name,
+                            reinterpret_cast<std::vector<CString> *>(value));
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Read multi string key: %s\\%s = %d]"),
+                full_key_name,
+                value_name,
+                reinterpret_cast<std::vector<CString>*>(value)->size()));
+          }
+          break;
+        case REG_BINARY:
+          hr = key.GetValue(value_name,
+                            reinterpret_cast<byte * *>(value),
+                            byte_count);
+          if (SUCCEEDED(hr)) {
+            UTIL_LOG(L6, (_T("[Read binary key: %s\\%s, len = %d]"),
+                          full_key_name, value_name, byte_count));
+          }
+          break;
+        default:
+          ASSERT(false, (_T("Unsupported Registry Type")));
+          hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
+          break;
+      }
+      // close the key after writing
+      HRESULT temp_res = key.Close();
+      if (hr == S_OK) {
+        hr = temp_res;
+      } else {
+        UTIL_LOG(L5, (_T("[Failed to read key: %s\\%s]"),
+                      full_key_name, value_name));
+      }
+    } else {
+      UTIL_LOG(L5, (_T("[reg key does not exist: %s]"), key_name));
+    }
+  }
+  return hr;
+}
+
+// GET helper
+// value_name may be NULL.
+HRESULT RegKey::GetValueHelper(const TCHAR * value_name,
+                               DWORD * type,
+                               byte * * value,
+                               DWORD * byte_count) const {
+  ASSERT1(byte_count);
+  ASSERT1(value);
+  ASSERT1(type);
+  ASSERT1(h_key_);
+
+  // init return buffer
+  *value = NULL;
+
+  // get the size of the return data buffer
+  LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, type, NULL, byte_count);
+  HRESULT hr = HRESULT_FROM_WIN32(res);
+
+  if (hr == S_OK) {
+    // if the value length is 0, nothing to do
+    if (*byte_count != 0) {
+      // allocate the buffer
+      *value = new byte[*byte_count];
+      ASSERT1(*value);
+
+      // make the call again to get the data
+      res = ::SHQueryValueEx(h_key_,
+                             value_name,
+                             NULL,
+                             type,
+                             *value,
+                             byte_count);
+      hr = HRESULT_FROM_WIN32(res);
+      ASSERT1(S_OK == hr);
+    }
+  }
+  return hr;
+}
+
+// Int32 Get
+// value_name may be NULL.
+HRESULT RegKey::GetValue(const TCHAR * value_name, DWORD * value) const {
+  ASSERT1(value);
+  ASSERT1(h_key_);
+
+  DWORD type = 0;
+  DWORD byte_count = sizeof(DWORD);
+  LONG res = ::SHQueryValueEx(h_key_,
+                              value_name,
+                              NULL,
+                              &type,
+                              reinterpret_cast<byte*>(value),
+                              &byte_count);
+  HRESULT hr = HRESULT_FROM_WIN32(res);
+  ASSERT1((hr != S_OK) || (type == REG_DWORD));
+  ASSERT1((hr != S_OK) || (byte_count == sizeof(DWORD)));
+  return hr;
+}
+
+// Int64 Get
+// value_name may be NULL.
+HRESULT RegKey::GetValue(const TCHAR * value_name, DWORD64 * value) const {
+  ASSERT1(value);
+  ASSERT1(h_key_);
+
+  DWORD type = 0;
+  DWORD byte_count = sizeof(DWORD64);
+  LONG res = ::SHQueryValueEx(h_key_,
+                              value_name,
+                              NULL,
+                              &type,
+                              reinterpret_cast<byte *>(value),
+                              &byte_count);
+  HRESULT hr = HRESULT_FROM_WIN32(res);
+  ASSERT1((hr != S_OK) || (type == REG_QWORD));
+  ASSERT1((hr != S_OK) || (byte_count == sizeof(DWORD64)));
+  return hr;
+}
+
+// String Get
+// value_name may be NULL.
+HRESULT RegKey::GetValue(const TCHAR * value_name, TCHAR * * value) const {
+  ASSERT1(value);
+  ASSERT1(h_key_);
+
+  DWORD byte_count = 0;
+  DWORD type = 0;
+
+  // first get the size of the string buffer
+  LONG res = ::SHQueryValueEx(h_key_,
+                              value_name,
+                              NULL,
+                              &type,
+                              NULL,
+                              &byte_count);
+  HRESULT hr = HRESULT_FROM_WIN32(res);
+
+  if (hr == S_OK) {
+    // allocate room for the string and a terminating \0
+    *value = new TCHAR[(byte_count / sizeof(TCHAR)) + 1];
+
+    if ((*value) != NULL) {
+      if (byte_count != 0) {
+        // make the call again
+        res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
+                              reinterpret_cast<byte*>(*value), &byte_count);
+        hr = HRESULT_FROM_WIN32(res);
+      } else {
+        (*value)[0] = _T('\0');
+      }
+
+      ASSERT1((hr != S_OK) || (type == REG_SZ) ||
+              (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
+    } else {
+      hr = E_OUTOFMEMORY;
+    }
+  }
+
+  return hr;
+}
+
+// CString Get
+// value_name may be NULL.
+HRESULT RegKey::GetValue(const TCHAR* value_name, OUT CString* value) const {
+  ASSERT1(value);
+  ASSERT1(h_key_);
+
+  DWORD byte_count = 0;
+  DWORD type = 0;
+
+  // first get the size of the string buffer
+  LONG res = ::SHQueryValueEx(h_key_,
+                              value_name,
+                              NULL,
+                              &type,
+                              NULL,
+                              &byte_count);
+  HRESULT hr = HRESULT_FROM_WIN32(res);
+
+  if (hr == S_OK) {
+    if (byte_count != 0) {
+      // Allocate some memory and make the call again
+      TCHAR* buffer = value->GetBuffer(byte_count / sizeof(TCHAR) + 1);
+      if (buffer == NULL) {
+        hr = E_OUTOFMEMORY;
+      } else {
+        res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
+                              reinterpret_cast<byte*>(buffer), &byte_count);
+        hr = HRESULT_FROM_WIN32(res);
+      }
+      value->ReleaseBuffer();
+    } else {
+      value->Empty();
+    }
+
+    ASSERT1((hr != S_OK) || (type == REG_SZ) ||
+            (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
+  }
+
+  return hr;
+}
+
+// convert REG_MULTI_SZ bytes to string array
+HRESULT RegKey::MultiSZBytesToStringArray(const byte * buffer,
+                                          DWORD byte_count,
+                                          std::vector<CString> * value) {
+  ASSERT1(buffer);
+  ASSERT1(value);
+
+  const TCHAR* data = reinterpret_cast<const TCHAR*>(buffer);
+  DWORD data_len = byte_count / sizeof(TCHAR);
+  value->clear();
+  if (data_len > 1) {
+    // must be terminated by two null characters
+    if (data[data_len - 1] != 0 || data[data_len - 2] != 0) {
+      return E_INVALIDARG;
+    }
+
+    // put null-terminated strings into arrays
+    while (*data) {
+      CString str(data);
+      value->push_back(str);
+      data += str.GetLength() + 1;
+    }
+  }
+  return S_OK;
+}
+
+// get a vector<CString> value from REG_MULTI_SZ type
+HRESULT RegKey::GetValue(const TCHAR * value_name,
+                         std::vector<CString> * value) const {
+  ASSERT1(value);
+  // value_name may be NULL
+
+  DWORD byte_count = 0;
+  DWORD type = 0;
+  byte* buffer = 0;
+
+  // first get the size of the buffer
+  HRESULT hr = GetValueHelper(value_name, &type, &buffer, &byte_count);
+  ASSERT1((hr != S_OK) || (type == REG_MULTI_SZ));
+
+  if (SUCCEEDED(hr)) {
+    hr = MultiSZBytesToStringArray(buffer, byte_count, value);
+  }
+
+  return hr;
+}
+
+// Binary data Get
+HRESULT RegKey::GetValue(const TCHAR * value_name,
+                         byte * * value,
+                         DWORD * byte_count) const {
+  ASSERT1(byte_count);
+  ASSERT1(value);
+  // value_name may be NULL
+
+  DWORD type = 0;
+  HRESULT hr = GetValueHelper(value_name, &type, value, byte_count);
+  ASSERT1((hr != S_OK) || (type == REG_MULTI_SZ) || (type == REG_BINARY));
+  return hr;
+}
+
+// Raw data get
+HRESULT RegKey::GetValue(const TCHAR * value_name,
+                         byte * * value,
+                         DWORD * byte_count,
+                         DWORD *type) const {
+  ASSERT1(type);
+  ASSERT1(byte_count);
+  ASSERT1(value);
+
+  return GetValueHelper(value_name, type, value, byte_count);
+}
+
+// Int32 set
+// value_name may be NULL
+HRESULT RegKey::SetValue(const TCHAR * value_name, DWORD value) const {
+  ASSERT1(h_key_);
+  LONG res = RegSetValueEx(h_key_,
+                           value_name,
+                           NULL,
+                           REG_DWORD,
+                           reinterpret_cast<byte *>(&value),
+                           sizeof(DWORD));
+  return HRESULT_FROM_WIN32(res);
+}
+
+// Int64 set
+// value_name may be NULL
+HRESULT RegKey::SetValue(const TCHAR * value_name, DWORD64 value) const {
+  ASSERT1(h_key_);
+  LONG res = RegSetValueEx(h_key_,
+                           value_name,
+                           NULL,
+                           REG_QWORD,
+                           reinterpret_cast<byte *>(&value),
+                           sizeof(DWORD64));
+  return HRESULT_FROM_WIN32(res);
+}
+
+// String set
+HRESULT RegKey::SetValue(const TCHAR * value_name, const TCHAR * value) const {
+  return SetStringValue(value_name, value, REG_SZ);
+}
+
+// String set helper
+// value_name may be NULL.
+HRESULT RegKey::SetStringValue(const TCHAR * value_name,
+                               const TCHAR * value,
+                               DWORD type) const {
+  ASSERT1(value);
+  ASSERT1(h_key_);
+  ASSERT1(type == REG_SZ || type == REG_EXPAND_SZ);
+  LONG res = RegSetValueEx(h_key_,
+                           value_name,
+                           NULL,
+                           type,
+                           reinterpret_cast<const byte *>(value),
+                           (lstrlen(value) + 1) * sizeof(TCHAR));
+  return HRESULT_FROM_WIN32(res);
+}
+
+// Binary data set
+// value may be NULL.
+// value_name may be NULL.
+HRESULT RegKey::SetValue(const TCHAR * value_name,
+                         const byte * value,
+                         DWORD byte_count) const {
+  ASSERT1(h_key_);
+
+  // special case - if 'value' is NULL make sure byte_count is zero
+  if (value == NULL) {
+    byte_count = 0;
+  }
+
+  LONG res = RegSetValueEx(h_key_,
+                           value_name,
+                           NULL,
+                           REG_BINARY,
+                           value,
+                           byte_count);
+  return HRESULT_FROM_WIN32(res);
+}
+
+// Raw data set
+// value_name may be NULL.
+HRESULT RegKey::SetValue(const TCHAR * value_name,
+                         const byte * value,
+                         DWORD byte_count,
+                         DWORD type) const {
+  ASSERT1(value);
+  ASSERT1(h_key_);
+  LONG res = RegSetValueEx(h_key_, value_name, NULL, type, value, byte_count);
+  return HRESULT_FROM_WIN32(res);
+}
+
+HRESULT RegKey::RenameValue(const TCHAR* old_value_name,
+                            const TCHAR* new_value_name) const {
+  ASSERT1(h_key_);
+  ASSERT1(new_value_name);
+  ASSERT1(old_value_name);
+
+  scoped_ptr<byte> value;
+  DWORD byte_count = 0;
+  DWORD type = 0;
+
+  HRESULT hr = GetValue(old_value_name, address(value), &byte_count, &type);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = SetValue(new_value_name, value.get(), byte_count, type);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  VERIFY1(SUCCEEDED(DeleteValue(old_value_name)));
+  return S_OK;
+}
+
+bool RegKey::HasKey(const TCHAR * full_key_name) {
+  return HasKeyHelper(full_key_name, KEY_READ);
+}
+
+bool RegKey::HasNativeKey(const TCHAR * full_key_name) {
+  return HasKeyHelper(full_key_name, KEY_READ | KEY_WOW64_64KEY);
+}
+
+bool RegKey::HasKeyHelper(const TCHAR * full_key_name, DWORD sam_flags) {
+  ASSERT1(full_key_name);
+  ASSERT1(sam_flags & KEY_READ);
+
+  // get the root HKEY
+  CString key_name(full_key_name);
+  HKEY h_key = GetRootKeyInfo(&key_name);
+
+  if (h_key != NULL) {
+    RegKey key;
+    HRESULT hr = key.Open(h_key, key_name.GetString(), sam_flags);
+    key.Close();
+    return S_OK == hr;
+  }
+  return false;
+}
+
+HRESULT RegKey::CopyValue(const TCHAR * full_from_key_name,
+                          const TCHAR * from_value_name,
+                          const TCHAR * full_to_key_name,
+                          const TCHAR * to_value_name) {
+  ASSERT1(full_from_key_name);
+  ASSERT1(full_to_key_name);
+
+  RegKey from_reg_key;
+  HRESULT hr = from_reg_key.Open(full_from_key_name, KEY_READ);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  scoped_ptr<byte> val;
+  DWORD byte_count = 0;
+  DWORD type = 0;
+  hr = from_reg_key.GetValue(from_value_name, address(val), &byte_count, &type);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  RegKey to_reg_key;
+  hr = to_reg_key.Open(full_to_key_name, KEY_WRITE);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return to_reg_key.SetValue(to_value_name, val.get(), byte_count, type);
+}
+
+// static version of HasValue
+bool RegKey::HasValue(const TCHAR * full_key_name, const TCHAR * value_name) {
+  ASSERT1(full_key_name);
+
+  bool has_value = false;
+  // get the root HKEY
+  CString key_name(full_key_name);
+  HKEY h_key = GetRootKeyInfo(&key_name);
+
+  if (h_key != NULL) {
+    RegKey key;
+    if (key.Open(h_key, key_name.GetString(), KEY_READ) == S_OK) {
+      has_value = key.HasValue(value_name);
+      key.Close();
+    }
+  }
+  return has_value;
+}
+
+HRESULT RegKey::GetValueType(const TCHAR* full_key_name,
+                             const TCHAR* value_name,
+                             DWORD* value_type) {
+  ASSERT1(full_key_name);
+  // value_name may be NULL
+  ASSERT1(value_type);
+
+  *value_type = REG_NONE;
+
+  CString key_name(full_key_name);
+  HKEY root_key = GetRootKeyInfo(&key_name);
+
+  HKEY key = NULL;
+  LONG res = ::RegOpenKeyEx(root_key, key_name, 0, KEY_READ, &key);
+  if (res != ERROR_SUCCESS) {
+    return HRESULT_FROM_WIN32(res);
+  }
+
+  scoped_hkey hkey(key);
+
+  res = ::SHQueryValueEx(get(hkey), value_name, NULL, value_type, NULL, NULL);
+  if (res != ERROR_SUCCESS) {
+    return HRESULT_FROM_WIN32(res);
+  }
+
+  return S_OK;
+}
+
+HRESULT RegKey::DeleteKey(const TCHAR* full_key_name) {
+  ASSERT1(full_key_name);
+
+  return DeleteKey(full_key_name, true);
+}
+
+HRESULT RegKey::DeleteKey(const TCHAR* full_key_name, bool recursively) {
+  ASSERT1(full_key_name);
+
+  // need to open the parent key first
+  // get the root HKEY
+  CString key_name(full_key_name);
+  HKEY h_key = GetRootKeyInfo(&key_name);
+
+  // get the parent key
+  CString parent_key(GetParentKeyInfo(&key_name));
+
+  RegKey key;
+  HRESULT hr = key.Open(h_key, parent_key);
+
+  if (hr == S_OK) {
+    hr = recursively ? key.RecurseDeleteSubKey(key_name) :
+                       key.DeleteSubKey(key_name);
+  } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
+             hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
+    hr = S_FALSE;
+  }
+
+  key.Close();
+  return hr;
+}
+
+HRESULT RegKey::DeleteValue(const TCHAR * full_key_name,
+                            const TCHAR * value_name) {
+  ASSERT1(value_name);
+  ASSERT1(full_key_name);
+
+  HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+  // get the root HKEY
+  CString key_name(full_key_name);
+  HKEY h_key = GetRootKeyInfo(&key_name);
+
+  if (h_key != NULL) {
+    RegKey key;
+    hr = key.Open(h_key, key_name.GetString());
+    if (hr == S_OK) {
+      hr = key.DeleteValue(value_name);
+      key.Close();
+    }
+  }
+  return hr;
+}
+
+HRESULT RegKey::RecurseDeleteSubKey(const TCHAR * key_name) {
+  ASSERT1(key_name);
+  ASSERT1(h_key_);
+
+  RegKey key;
+  HRESULT hr = key.Open(h_key_, key_name);
+  if (hr != S_OK)
+    return hr;
+
+  // enumerate all subkeys of this key
+  // and recursivelly delete them
+  FILETIME time;
+  TCHAR key_name_buf[kMaxKeyNameChars];
+  DWORD key_name_buf_size = kMaxKeyNameChars;
+  while (RegEnumKeyEx(key.h_key_,
+                      0,
+                      key_name_buf,
+                      &key_name_buf_size,
+                      NULL,
+                      NULL,
+                      NULL,
+                      &time) == ERROR_SUCCESS) {
+    hr = key.RecurseDeleteSubKey(key_name_buf);
+    // return if error deleting key
+    if (hr != S_OK)
+      return hr;
+    // restore the buffer size
+    key_name_buf_size = kMaxKeyNameChars;
+  }
+  // close the top key
+  key.Close();
+
+  // the key has no more children keys
+  // delete the key and all of its values
+  return DeleteSubKey(key_name);
+}
+
+HKEY RegKey::GetRootKeyInfo(CString * full_key_name) {
+  ASSERT1(full_key_name);
+
+  HKEY h_key = NULL;
+  // get the root HKEY
+  int index = String_FindChar(*(full_key_name), '\\');
+  CString root_key;
+
+  if (index == -1) {
+    root_key = *full_key_name;
+    *full_key_name = _T("");
+  } else {
+    root_key= full_key_name->Left(index);
+    *full_key_name =
+        full_key_name->Right(full_key_name->GetLength() - index - 1);
+  }
+
+  if (!root_key.CompareNoCase(_T("HKLM")) ||
+      !root_key.CompareNoCase(_T("HKEY_LOCAL_MACHINE")))
+    h_key = HKEY_LOCAL_MACHINE;
+  else if (!root_key.CompareNoCase(_T("HKCU")) ||
+           !root_key.CompareNoCase(_T("HKEY_CURRENT_USER")))
+    h_key = HKEY_CURRENT_USER;
+  else if (!root_key.CompareNoCase(_T("HKU")) ||
+           !root_key.CompareNoCase(_T("HKEY_USERS")))
+    h_key = HKEY_USERS;
+  else if (!root_key.CompareNoCase(_T("HKCR")) ||
+           !root_key.CompareNoCase(_T("HKEY_CLASSES_ROOT")))
+    h_key = HKEY_CLASSES_ROOT;
+
+  return h_key;
+}
+
+
+// Returns true if this key name is 'safe' for deletion (doesn't specify a
+// key root)
+bool RegKey::SafeKeyNameForDeletion(const wchar_t *key_name) {
+  ASSERT1(key_name);
+  CString key(key_name);
+
+  HKEY root_key = GetRootKeyInfo(&key);
+
+  if ( !root_key ) {
+    key = key_name;
+  }
+  if ( key.IsEmpty() ) {
+    return false;
+  }
+  bool found_subkey = false, backslash_found = false;
+  for (int i = 0 ; i < key.GetLength() ; ++i) {
+    if ( key[i] == L'\\' ) {
+      backslash_found = true;
+    } else if ( backslash_found ) {
+      found_subkey = true;
+      break;
+    }
+  }
+  return ( root_key == HKEY_USERS ) ? found_subkey : true;
+}
+
+CString RegKey::GetParentKeyInfo(CString * key_name) {
+  ASSERT1(key_name);
+
+  // get the parent key
+  int index = key_name->ReverseFind('\\');
+  CString parent_key;
+  if (index == -1) {
+    parent_key = _T("");
+  } else {
+    parent_key = key_name->Left(index);
+    *key_name = key_name->Right(key_name->GetLength() - index - 1);
+  }
+
+  return parent_key;
+}
+
+// get the number of values for this key
+uint32 RegKey::GetValueCount() {
+  ASSERT1(h_key_);
+  // number of values for key
+  DWORD  num_values = 0;
+
+  LONG res = ::RegQueryInfoKey(h_key_,       // key handle
+                               NULL,         // buffer for class name
+                               NULL,         // size of class string
+                               NULL,         // reserved
+                               NULL,         // number of subkeys
+                               NULL,         // longest subkey size
+                               NULL,         // longest class string
+                               &num_values,  // number of values for this key
+                               NULL,         // longest value name
+                               NULL,         // longest value data
+                               NULL,         // security descriptor
+                               NULL);        // last write time
+
+  ASSERT1(res == ERROR_SUCCESS);
+  return num_values;
+}
+
+// Enumerators for the value_names for this key
+
+// Called to get the value name for the given value name index
+// Use GetValueCount() to get the total value_name count for this key
+// Returns failure if no key at the specified index
+// type may be NULL.
+HRESULT RegKey::GetValueNameAt(int index, CString *value_name, DWORD *type) {
+  ASSERT1(value_name);
+  ASSERT1(h_key_);
+
+  LONG res = ERROR_SUCCESS;
+  TCHAR value_name_buf[kMaxValueNameChars];
+  DWORD value_name_buf_size = kMaxValueNameChars;
+  res = ::RegEnumValue(h_key_,
+                       index,
+                       value_name_buf,
+                       &value_name_buf_size,
+                       NULL,
+                       type,
+                       NULL,
+                       NULL);
+
+  if (res == ERROR_SUCCESS) {
+    value_name->SetString(value_name_buf);
+  }
+
+  return HRESULT_FROM_WIN32(res);
+}
+
+uint32 RegKey::GetSubkeyCount() {
+  ASSERT1(h_key_);
+
+  DWORD num_subkeys = 0;   // number of values for key
+
+  LONG res = ::RegQueryInfoKey(h_key_,        // key handle
+                               NULL,          // buffer for class name
+                               NULL,          // size of class string
+                               NULL,          // reserved
+                               &num_subkeys,  // number of subkeys
+                               NULL,          // longest subkey size
+                               NULL,          // longest class string
+                               NULL,          // number of values for this key
+                               NULL,          // longest value name
+                               NULL,          // longest value data
+                               NULL,          // security descriptor
+                               NULL);         // last write time
+
+  ASSERT1(res == ERROR_SUCCESS);
+  return num_subkeys;
+}
+
+HRESULT RegKey::GetSubkeyNameAt(int index, CString * key_name) {
+  ASSERT1(key_name);
+  ASSERT1(h_key_);
+
+  LONG res = ERROR_SUCCESS;
+  TCHAR key_name_buf[kMaxKeyNameChars];
+  DWORD key_name_buf_size = kMaxKeyNameChars;
+
+  res = ::RegEnumKeyEx(h_key_,
+                       index,
+                       key_name_buf,
+                       &key_name_buf_size,
+                       NULL,
+                       NULL,
+                       NULL,
+                       NULL);
+
+  if (res == ERROR_SUCCESS) {
+    key_name->SetString(key_name_buf);
+  }
+
+  return HRESULT_FROM_WIN32(res);
+}
+
+// Is the key empty: having no sub-keys and values
+bool RegKey::IsKeyEmpty(const TCHAR* full_key_name) {
+  ASSERT1(full_key_name);
+
+  bool is_empty = true;
+
+  // Get the root HKEY
+  CString key_name(full_key_name);
+  HKEY h_key = GetRootKeyInfo(&key_name);
+
+  // Open the key to check
+  if (h_key != NULL) {
+    RegKey key;
+    HRESULT hr = key.Open(h_key, key_name.GetString(), KEY_READ);
+    if (SUCCEEDED(hr)) {
+      is_empty = key.GetSubkeyCount() == 0 && key.GetValueCount() == 0;
+      key.Close();
+    }
+  }
+
+  return is_empty;
+}
+
+// close this reg key and the event
+HRESULT RegKeyWithChangeEvent::Close() {
+  reset(change_event_);
+  return RegKey::Close();
+}
+
+// Called to create/reset the event that gets signaled
+// any time the registry key changes
+// Note:
+//   * reg key should have been opened using KEY_NOTIFY for the sam_desired
+//
+// See the documentation for RegNotifyChangeKeyValue
+// for values for notify_filter.
+HRESULT RegKeyWithChangeEvent::SetupEvent(bool watch_subtree,
+                                          DWORD notify_filter) {
+  // If the event exists, then it should be in the signaled state
+  // indicating a registry change took place.  If not, then
+  // the caller is setting up the event a second time and this
+  // will create a memory leak.
+  ASSERT(!valid(change_event_) || HasChangeOccurred(),
+         (_T("Event is getting set-up for a second ")
+          _T("time without being signaled.")));
+
+  if (!valid(change_event_)) {
+    reset(change_event_, ::CreateEvent(NULL, TRUE, FALSE, NULL));
+    if (!valid(change_event_)) {
+      ASSERT(false, (_T("create event failed")));
+      return HRESULT_FROM_WIN32(::GetLastError());
+    }
+  } else {
+    if (!::ResetEvent(get(change_event_))) {
+      ASSERT(false, (_T("reset event failed")));
+      return HRESULT_FROM_WIN32(::GetLastError());
+    }
+  }
+
+  LONG res = ::RegNotifyChangeKeyValue(Key(), watch_subtree, notify_filter,
+      get(change_event_), TRUE);
+
+  if (res != ERROR_SUCCESS) {
+    // You may get this failure if you didn't pass in KEY_NOTIFY
+    // as part of the sam_desired flags during Open or Create
+    ASSERT(false, (_T("setting up change notification for a reg key failed")));
+
+    // Leave the event around so that it never changes once it has been set-up
+    // but in this case it will not get signaled again.
+  }
+
+  return HRESULT_FROM_WIN32(res);
+}
+
+// Indicates if any changes (that are being monitored have occured)
+bool RegKeyWithChangeEvent::HasChangeOccurred() const {
+  return IsHandleSignaled(get(change_event_));
+}
+
+
+RegKeyWatcher::RegKeyWatcher(const TCHAR* reg_key, bool watch_subtree,
+                             DWORD notify_filter, bool allow_creation)
+    : reg_key_string_(reg_key),
+      watch_subtree_(watch_subtree),
+      notify_filter_(notify_filter),
+      allow_creation_(allow_creation) {
+  UTIL_LOG(L3, (_T("[RegKeyWatcher::RegKeyWatcher][%s]"), reg_key));
+}
+
+HRESULT RegKeyWatcher::EnsureEventSetup() {
+  UTIL_LOG(L3, (_T("[RegKeyWatcher::EnsureEventSetup]")));
+  if (!reg_key_with_change_event_.get()) {
+    scoped_ptr<RegKeyWithChangeEvent> local_reg_key(new RegKeyWithChangeEvent);
+    if (!local_reg_key.get()) {
+      ASSERT(false, (_T("unable to allocate local_reg_key")));
+      return E_FAIL;
+    }
+
+    if (allow_creation_ && !RegKey::HasKey(reg_key_string_)) {
+      RegKey key;
+      VERIFY1(SUCCEEDED(key.Create(reg_key_string_)));
+    }
+
+    HRESULT hr = local_reg_key->Open(reg_key_string_, KEY_NOTIFY);
+    if (FAILED(hr)) {
+      ASSERT(false, (_T("couldn't open %s reg key for notifications. ")
+                     _T("Make sure you have pre-created the key!"),
+                     reg_key_string_));
+      return hr;
+    }
+    reg_key_with_change_event_.reset(local_reg_key.release());
+    reg_key_string_.Empty();
+  }
+
+  // if the event is set-up and no changes have occurred,
+  // then there is no need to re-setup the event.
+  if (reg_key_with_change_event_->change_event() && !HasChangeOccurred()) {
+    return S_OK;
+  }
+
+  return reg_key_with_change_event_->SetupEvent(watch_subtree_,
+                                                notify_filter_);
+}
+
+// Get the event that is signaled on registry changes.
+HANDLE RegKeyWatcher::change_event() const {
+  if (!reg_key_with_change_event_.get()) {
+    ASSERT(false, (_T("call RegKeyWatcher::EnsureEventSetup first")));
+    return NULL;
+  }
+  return reg_key_with_change_event_->change_event();
+}
+
+}  // namespace omaha
+
diff --git a/common/reg_key.h b/common/reg_key.h
index 946d2af..fbf2dcf 100644
--- a/common/reg_key.h
+++ b/common/reg_key.h
@@ -1,784 +1,784 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// reg_key.h

-//

-// Registry configuration wrappers class

-//

-// Offers static functions for convenient

-// fast access for individual values

-//

-// Also provides a wrapper class for efficient

-// batch operations on values of a given registry key.

-

-#ifndef OMAHA_COMMON_REG_KEY_H_

-#define OMAHA_COMMON_REG_KEY_H_

-

-#include <windows.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/static_assert.h"

-#include "omaha/common/store_watcher.h"

-

-namespace omaha {

-

-// maximum sizes registry key and value names

-#define kMaxKeyNameChars   (255 + 1)

-#define kMaxValueNameChars (16383 + 1)

-

-class RegKey {

- public:

-  RegKey();

-  virtual ~RegKey();

-

-  // create a reg key

-  HRESULT Create(HKEY hKeyParent, const TCHAR * key_name,

-        TCHAR * reg_class = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE,

-        REGSAM sam_desired = KEY_ALL_ACCESS,

-        LPSECURITY_ATTRIBUTES lp_sec_attr = NULL,

-        LPDWORD lp_disposition = NULL);

-

-  // create a reg key, given the full key name, including the HKEY root

-  // (say for example, "HKLM\\Software")

-  HRESULT Create(const TCHAR * full_key_name,

-        TCHAR * reg_class = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE,

-        REGSAM sam_desired = KEY_ALL_ACCESS,

-        LPSECURITY_ATTRIBUTES lp_sec_attr = NULL,

-        LPDWORD lp_disposition = NULL);

-

-  // static helper function that create a set of reg keys,

-  // given an array of full key names including the HKEY root

-  // (say for example, "HKLM\\Software")

-  static HRESULT CreateKeys(const TCHAR* keys_to_create[],

-                            DWORD number_of_keys,

-                            TCHAR* reg_class = REG_NONE,

-                            DWORD options = REG_OPTION_NON_VOLATILE,

-                            LPSECURITY_ATTRIBUTES lp_sec_attr = NULL);

-

-  // Static method to create a single key.

-  static HRESULT CreateKey(const TCHAR * full_key_name,

-                           TCHAR * reg_class = REG_NONE,

-                           DWORD options = REG_OPTION_NON_VOLATILE,

-                           LPSECURITY_ATTRIBUTES lp_sec_attr = NULL);

-

-  // open an existing reg key

-  HRESULT Open(HKEY hKeyParent,

-               const TCHAR * key_name,

-               REGSAM sam_desired = KEY_ALL_ACCESS);

-

-  // open an existing reg key, given the full key name, including the HKEY root

-  // (say for example, "HKLM\\Software")

-  HRESULT Open(const TCHAR * full_key_name,

-               REGSAM sam_desired = KEY_ALL_ACCESS);

-

-  // close this reg key

-  virtual HRESULT Close();

-

-  // check if the key has a specified value

-  bool HasValue(const TCHAR * value_name);

-

-  // get the number of values for this key

-  uint32 GetValueCount();

-

-  // Called to get the value name for the given value name index

-  // Use GetValueCount() to get the total value_name count for this key

-  // Returns failure if no key at the specified index

-  // If you modify the key while enumerating, the indexes will be out of order.

-  // Since the index order is not guaranteed, you need to reset your counting

-  // loop.

-  // type refers to REG_DWORD, REG_QWORD, etc..

-  // 'type' can be NULL if not interested in the value type

-  HRESULT GetValueNameAt(int index, CString * value_name, DWORD *type);

-

-  // check if the current key has the specified subkey

-  bool HasSubkey(const TCHAR * key_name) const;

-

-  // get the number of subkeys for this key

-  uint32 GetSubkeyCount();

-

-  // Called to get the key name for the given key index

-  // Use GetSubkeyCount() to get the total count for this key

-  // Returns failure if no key at the specified index

-  // If you modify the key while enumerating, the indexes will be out of order.

-  // Since the index order is not guaranteed, you need to reset your counting

-  // loop.

-  HRESULT GetSubkeyNameAt(int index, CString * key_name);

-

-  // SETTERS

-

-  // set an int32 value - use when reading multiple values from a key

-  HRESULT SetValue(const TCHAR * value_name, DWORD value) const;

-

-  // set an int64 value

-  HRESULT SetValue(const TCHAR * value_name, DWORD64 value) const;

-

-  // set a string value

-  HRESULT SetValue(const TCHAR * value_name, const TCHAR * value) const;

-

-  // set binary data

-  HRESULT SetValue(const TCHAR * value_name,

-                   const byte * value,

-                   DWORD byte_count) const;

-

-  // set raw data, including type

-  HRESULT SetValue(const TCHAR * value_name,

-                   const byte * value,

-                   DWORD byte_count,

-                   DWORD type) const;

-

-  // GETTERS

-

-  // get an int32 value

-  HRESULT GetValue(const TCHAR * value_name, DWORD * value) const;

-

-  // get an int64 value

-  //

-  // Note: if you are using time64 you should

-  // likely use GetLimitedTimeValue (util.h) instead of this method.

-  HRESULT GetValue(const TCHAR * value_name, DWORD64 * value) const;

-

-  // get a string value - the caller must free the return buffer

-  HRESULT GetValue(const TCHAR * value_name, TCHAR * * value) const;

-

-  // get a CString value

-  HRESULT GetValue(const TCHAR* value_name, OUT CString* value) const;

-

-  // get a vector<CString> value from REG_MULTI_SZ type

-  HRESULT GetValue(const TCHAR * value_name,

-                   std::vector<CString> * value) const;

-

-  // get binary data - the caller must free the return buffer

-  HRESULT GetValue(const TCHAR * value_name,

-                   byte * * value,

-                   DWORD * byte_count) const;

-

-  // get raw data, including type - the caller must free the return buffer

-  HRESULT GetValue(const TCHAR * value_name,

-                   byte * * value,

-                   DWORD * byte_count,

-                   DWORD *type) const;

-

-  // RENAMERS

-

-  // Rename a named value.

-  HRESULT RenameValue(const TCHAR * old_value_name,

-                      const TCHAR * new_value_name) const;

-

-  // STATIC VERSIONS

-

-  // flush

-  static HRESULT FlushKey(const TCHAR * full_key_name);

-

-  // Check if a key exists.

-  static bool HasKey(const TCHAR * full_key_name);

-

-  // Check if a key exists in the native (i.e. non-redirected) registry.

-  static bool HasNativeKey(const TCHAR * full_key_name);

-

-  // check if the key has a specified value

-  static bool HasValue(const TCHAR * full_key_name, const TCHAR * value_name);

-

-  // SETTERS

-

-  // STATIC int32 set

-  static HRESULT SetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          DWORD value);

-

-  // STATIC int64 set

-  static HRESULT SetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          DWORD64 value);

-

-  // STATIC float set

-  static HRESULT SetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          float value);

-

-  // STATIC double set

-  static HRESULT SetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          double value);

-

-  // STATIC string set

-  static HRESULT SetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          const TCHAR * value);

-

-  // STATIC binary data set

-  static HRESULT SetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          const byte * value,

-                          DWORD byte_count);

-

-  // STATIC array of strings set

-  static HRESULT SetValueMultiSZ(const TCHAR * full_key_name,

-                                 const TCHAR * value_name,

-                                 const byte * value,

-                                 DWORD byte_count);

-

-  // STATIC expandable string set

-  static HRESULT SetValueExpandSZ(const TCHAR * full_key_name,

-                                  const TCHAR * value_name,

-                                  const TCHAR * value);

-

-  // GETTERS

-

-  // STATIC int32 get

-  static HRESULT GetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          DWORD * value);

-

-  // STATIC int64 get

-  //

-  // Note: if you are using time64 you should

-  // likely use GetLimitedTimeValue (util.h) instead of this method.

-  static HRESULT GetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          DWORD64 * value);

-

-  // STATIC float get

-  static HRESULT GetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          float * value);

-

-  // STATIC double get

-  static HRESULT GetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          double * value);

-

-  // STATIC string get (STR and CString versions) - the caller must free

-  // the return buffer

-  static HRESULT GetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          TCHAR * * value);

-

-  static HRESULT GetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          CString * value);

-

-  // STATIC REG_MULTI_SZ get

-  static HRESULT GetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          std::vector<CString> * value);

-

-  // STATIC get binary data - the caller must free the return buffer

-  static HRESULT GetValue(const TCHAR * full_key_name,

-                          const TCHAR * value_name,

-                          byte * * value,

-                          DWORD * byte_count);

-

-  // Try reg keys successively if there is a failure in getting a value.

-  //

-  // Typically used when there is a user value and a default value if the

-  // user has none.

-  template<typename T>

-  static HRESULT GetValue(const TCHAR * full_key_names[],

-                          int key_names_length,

-                          const TCHAR * value_name,

-                          T* value);

-

-  // RENAMERS

-

-  // Rename a named value.

-  static HRESULT RenameValue(const TCHAR * full_key_name,

-                             const TCHAR * old_value_name,

-                             const TCHAR * new_value_name);

-

-  // COPIERS

-

-  // The full_to_key must exist for CopyValue to succeed.

-  static HRESULT CopyValue(const TCHAR * full_from_key_name,

-                           const TCHAR * from_value_name,

-                           const TCHAR * full_to_key_name,

-                           const TCHAR * to_value_name);

-

-  static HRESULT CopyValue(const TCHAR * full_from_key_name,

-                           const TCHAR * full_to_key_name,

-                           const TCHAR * value_name);

-

-  // Get type of a registry value

-  static HRESULT GetValueType(const TCHAR* full_key_name,

-                              const TCHAR* value_name,

-                              DWORD* value_type);

-

-  // delete a subkey of the current key (with no subkeys)

-  HRESULT DeleteSubKey(const TCHAR * key_name);

-

-  // recursively delete a sub key of the current key (and all its subkeys)

-  HRESULT RecurseDeleteSubKey(const TCHAR * key_name);

-

-  // STATIC version of delete key - handles nested keys also

-  // delete a key and all its sub-keys recursively

-  // Returns S_FALSE if key didn't exist, S_OK if deletion was successful,

-  // and failure otherwise.

-  static HRESULT DeleteKey(const TCHAR* full_key_name);

-

-  // STATIC version of delete key

-  // delete a key recursively or non-recursively

-  // Returns S_FALSE if key didn't exist, S_OK if deletion was successful,

-  // and failure otherwise.

-  static HRESULT DeleteKey(const TCHAR* full_key_name, bool recursive);

-

-  // delete the specified value

-  HRESULT DeleteValue(const TCHAR * value_name) const;

-

-  // STATIC version of delete value

-  // Returns S_FALSE if key didn't exist, S_OK if deletion was successful,

-  // and failure otherwise.

-  static HRESULT DeleteValue(const TCHAR * full_key_name,

-                             const TCHAR * value_name);

-

-  // Peek inside (use a RegKey as a smart wrapper around a registry handle)

-  HKEY Key() { return h_key_; }

-

-  // Used to help test the private functionality

-  friend class RegKeyTestClass;

-

-  // helper function to get the HKEY and the root key from a string

-  // representation modifies the argument in place and returns the key name

-  // e.g. HKLM\\Software\\Google\... returns HKLM, "Software\\Google\..."

-  // Necessary for the static versions that use the full name of the reg key

-  static HKEY GetRootKeyInfo(CString * full_key_name);

-

-  // Returns true if this key name is 'safe' for deletion (doesn't specify

-  // a key root)

-  static bool SafeKeyNameForDeletion(const wchar_t *key_name);

-

-  // save the key and all of its subkeys and values to a file

-  static HRESULT Save(const TCHAR* full_key_name, const TCHAR* file_name);

-

-  // restore the key and all of its subkeys and values which are saved into

-  // a file

-  static HRESULT Restore(const TCHAR* full_key_name, const TCHAR* file_name);

-

-  // Is the key empty: having no sub-keys and values

-  static bool IsKeyEmpty(const TCHAR* full_key_name);

-

- private:

-

-  // Helper function to check if a key exists, using the sam flags specified.

-  // Note: KEY_READ must be included in sam_flags.

-  static bool HasKeyHelper(const TCHAR * full_key_name, DWORD sam_flags);

-

-  // helper function to get the parent key name and the subkey from a string

-  // representation modifies the argument in place and returns the key name

-  // e.g. Software\\Google\\Foo_Bar returns "Software\\Google", "Foo_Bar"

-  // Necessary for the static versions that use the full name of the reg key

-  static CString GetParentKeyInfo(CString * key_name);

-

-  // helper function to get any value from the registry

-  // used when the size of the data is unknown

-  HRESULT GetValueHelper(const TCHAR * value_name,

-                         DWORD * type,

-                         byte * * value,

-                         DWORD * byte_count) const;

-

-  // common SET Helper for the static case

-  static HRESULT SetValueStaticHelper(const TCHAR * full_key_name,

-                                      const TCHAR * value_name,

-                                      DWORD type,

-                                      LPVOID value,

-                                      DWORD byte_count = 0);

-

-  // common GET Helper for the static case

-  static HRESULT GetValueStaticHelper(const TCHAR * full_key_name,

-                                      const TCHAR * value_name,

-                                      DWORD type,

-                                      LPVOID value,

-                                      DWORD * byte_count = NULL);

-

-  // convert REG_MULTI_SZ bytes to string array

-  static HRESULT MultiSZBytesToStringArray(const byte * buffer,

-                                           DWORD byte_count,

-                                           std::vector<CString> * value);

-

-  // set a string or expandable string value

-  HRESULT SetStringValue(const TCHAR * value_name,

-                         const TCHAR * value,

-                         DWORD type) const;

-

-  // the HKEY for the current key

-  HKEY h_key_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(RegKey);

-};

-

-// Provides all the functionality of RegKey plus

-// an event to watch for changes to the registry key.

-class RegKeyWithChangeEvent : public RegKey {

- public:

-  RegKeyWithChangeEvent() {}

-  // close this reg key and the event

-  virtual HRESULT Close();

-

-  // Called to create/reset the event that gets signaled

-  // any time the registry key changes.  Access the created

-  // event using change_event().

-  //

-  // See the documentation for RegNotifyChangeKeyValue

-  // for values for notify_filter.

-  HRESULT SetupEvent(bool watch_subtree, DWORD notify_filter);

-

-  // Indicates if any changes (that are being monitored) have occured

-  bool HasChangeOccurred() const;

-

-  // Get the event that is signaled on registry changes.

-  // Note:

-  //   * This event will remain constant until Close() is called.

-  //   * One should call SetupEvent to set-up the event.

-  //   * The event is only signaled on the next change and remains signaled.

-  //     Do not call ::ResetEvent().  Call SetupEvent() to reset

-  //     the event and wait for more changes.

-  HANDLE change_event() const {

-    return get(change_event_);

-  }

-

- private:

-  scoped_handle change_event_;

-  DISALLOW_EVIL_CONSTRUCTORS(RegKeyWithChangeEvent);

-};

-

-// Does the common things necessary for watching

-// registry key changes.  If there are file change or other watchers,

-// there could be a common interface for the three methods to decouple

-// the code that is doing the watching from the code that owns the store.

-class RegKeyWatcher : public StoreWatcher {

- public:

-  // reg_key: the full string for the reg key

-  // watch_subtree: watch all subkey changes  or

-  //                only immediate child values

-  // notify_filter: See the documentation for RegNotifyChangeKeyValue

-  // allow_creation: Should the key be created if it doesn't exist?

-  RegKeyWatcher(const TCHAR* reg_key, bool watch_subtree,

-                DWORD notify_filter, bool allow_creation);

-  virtual ~RegKeyWatcher() {}

-

-  // Called to create/reset the event that gets signaled

-  // any time the registry key changes.  Access the created

-  // event using change_event().

-  virtual HRESULT EnsureEventSetup();

-

-  // Get the event that is signaled on registry changes.

-  virtual HANDLE change_event() const;

-

- private:

-  // Used to do the SetupEvent method

-  scoped_ptr<RegKeyWithChangeEvent> reg_key_with_change_event_;

-

-  CString reg_key_string_;

-  bool watch_subtree_;

-  bool allow_creation_;

-  DWORD notify_filter_;

-  DISALLOW_EVIL_CONSTRUCTORS(RegKeyWatcher);

-};

-

-

-inline RegKey::RegKey() { h_key_ = NULL; }

-

-inline RegKey::~RegKey() { Close(); }

-

-inline bool RegKey::HasValue(const TCHAR* value_name) {

-  return (ERROR_SUCCESS == ::RegQueryValueEx(h_key_,

-                                             value_name,

-                                             NULL, NULL,

-                                             NULL,

-                                             NULL));

-}

-

-// SETTERS static versions

-inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                DWORD value) {

-  ASSERT1(full_key_name);

-

-  return SetValueStaticHelper(full_key_name, value_name, REG_DWORD, &value);

-}

-

-inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                DWORD64 value) {

-  ASSERT1(full_key_name);

-

-  return SetValueStaticHelper(full_key_name, value_name, REG_QWORD, &value);

-}

-

-inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                float value) {

-  ASSERT1(full_key_name);

-

-  return SetValueStaticHelper(full_key_name,

-                              value_name,

-                              REG_BINARY,

-                              &value,

-                              sizeof(value));

-}

-

-inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                double value) {

-  ASSERT1(full_key_name);

-

-  return SetValueStaticHelper(full_key_name,

-                              value_name,

-                              REG_BINARY,

-                              &value,

-                              sizeof(value));

-}

-

-inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                const TCHAR* value) {

-  ASSERT1(full_key_name);

-  ASSERT1(value);

-

-  return SetValueStaticHelper(full_key_name,

-                              value_name,

-                              REG_SZ,

-                              const_cast<TCHAR*>(value));

-}

-

-inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                const byte* value,

-                                DWORD byte_count) {

-  ASSERT1(full_key_name);

-

-  return SetValueStaticHelper(full_key_name, value_name, REG_BINARY,

-                              const_cast<byte*>(value), byte_count);

-}

-

-inline HRESULT RegKey::SetValueMultiSZ(const TCHAR* full_key_name,

-                                       const TCHAR* value_name,

-                                       const byte* value,

-                                       DWORD byte_count) {

-  ASSERT1(full_key_name);

-

-  return SetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ,

-                              const_cast<byte*>(value), byte_count);

-}

-

-inline HRESULT RegKey::SetValueExpandSZ(const TCHAR* full_key_name,

-                                        const TCHAR* value_name,

-                                        const TCHAR* value) {

-  ASSERT1(full_key_name);

-  ASSERT1(value);

-

-  return SetValueStaticHelper(full_key_name,

-                              value_name,

-                              REG_EXPAND_SZ,

-                              const_cast<TCHAR*>(value));

-}

-

-// GETTERS static versions

-inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                DWORD* value) {

-  ASSERT1(full_key_name);

-  ASSERT1(value);

-

-  return GetValueStaticHelper(full_key_name, value_name, REG_DWORD, value);

-}

-

-inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                DWORD64* value) {

-  ASSERT1(full_key_name);

-  ASSERT1(value);

-

-  return GetValueStaticHelper(full_key_name, value_name, REG_QWORD, value);

-}

-

-inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                float* value) {

-  ASSERT1(value);

-  ASSERT1(value_name);

-  ASSERT1(full_key_name);

-

-  DWORD byte_count = 0;

-  byte* buffer = NULL;

-  HRESULT hr = GetValueStaticHelper(full_key_name,

-                                    value_name,

-                                    REG_BINARY,

-                                    &buffer,

-                                    &byte_count);

-  scoped_array<byte> free_buffer(buffer);

-

-  if (SUCCEEDED(hr)) {

-    if (byte_count == sizeof(*value)) {

-      ::CopyMemory(value, buffer, sizeof(*value));

-    } else {

-      UTIL_LOG(LEVEL_ERROR, (_T("[RegKey::GetValue]")

-                             _T("[size mismatches for float value][%s\\%s]"),

-                             full_key_name, value_name));

-      return HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);

-    }

-  }

-

-  return hr;

-}

-

-inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                double* value) {

-  ASSERT1(value);

-  ASSERT1(value_name);

-  ASSERT1(full_key_name);

-

-  DWORD byte_count = 0;

-  byte* buffer = NULL;

-  HRESULT hr = GetValueStaticHelper(full_key_name,

-                                    value_name,

-                                    REG_BINARY,

-                                    &buffer,

-                                    &byte_count);

-  scoped_array<byte> free_buffer(buffer);

-

-  if (SUCCEEDED(hr)) {

-    if (byte_count == sizeof(*value)) {

-      ::CopyMemory(value, buffer, sizeof(*value));

-    } else {

-      UTIL_LOG(LEVEL_ERROR, (_T("[RegKey::GetValue]")

-                             _T("[size mismatches for double value][%s\\%s]"),

-                             full_key_name, value_name));

-      return HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);

-    }

-  }

-

-  return hr;

-}

-

-inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                TCHAR** value) {

-  ASSERT1(full_key_name);

-  ASSERT1(value);

-

-  return GetValueStaticHelper(full_key_name, value_name, REG_SZ, value);

-}

-

-inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                CString* value) {

-  ASSERT1(full_key_name);

-  ASSERT1(value);

-

-  TCHAR* buffer = NULL;

-  HRESULT hr = RegKey::GetValue(full_key_name, value_name, &buffer);

-  value->SetString(buffer);

-  delete [] buffer;

-  return hr;

-}

-

-inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                std::vector<CString>* value) {

-  ASSERT1(full_key_name);

-  ASSERT1(value);

-

-  return GetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, value);

-}

-

-inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,

-                                const TCHAR* value_name,

-                                byte** value,

-                                DWORD* byte_count) {

-  ASSERT1(full_key_name);

-  ASSERT1(value);

-  ASSERT1(byte_count);

-

-  return GetValueStaticHelper(full_key_name,

-                              value_name,

-                              REG_BINARY,

-                              value,

-                              byte_count);

-}

-

-template<typename T>

-HRESULT RegKey::GetValue(const TCHAR* full_key_names[],

-                         int key_names_length,

-                         const TCHAR* value_name,

-                         T* value) {

-  HRESULT hr = S_OK;

-  for (int i = 0; i < key_names_length; ++i) {

-    hr = GetValue(full_key_names[i], value_name, value);

-    if (SUCCEEDED(hr)) {

-      return hr;

-    }

-  }

-  return hr;

-}

-

-// Rename a named value.

-inline HRESULT RegKey::RenameValue(const TCHAR * full_key_name,

-                                   const TCHAR * old_value_name,

-                                   const TCHAR * new_value_name) {

-  ASSERT1(full_key_name);

-

-  RegKey reg_key;

-  HRESULT hr = reg_key.Open(full_key_name);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return reg_key.RenameValue(old_value_name, new_value_name);

-}

-

-inline HRESULT RegKey::CopyValue(const TCHAR * full_from_key_name,

-                                 const TCHAR * full_to_key_name,

-                                 const TCHAR * value_name) {

-  return CopyValue(full_from_key_name,

-                   value_name,

-                   full_to_key_name,

-                   value_name);

-}

-

-// DELETE

-inline HRESULT RegKey::DeleteSubKey(const TCHAR* key_name) {

-  ASSERT1(key_name);

-  ASSERT1(h_key_);

-

-  LONG res = ::RegDeleteKey(h_key_, key_name);

-  HRESULT hr = HRESULT_FROM_WIN32(res);

-  if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||

-      hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {

-    hr = S_FALSE;

-  }

-  return hr;

-}

-

-inline HRESULT RegKey::DeleteValue(const TCHAR* value_name) const {

-  ASSERT1(value_name);

-  ASSERT1(h_key_);

-

-  LONG res = ::RegDeleteValue(h_key_, value_name);

-  HRESULT hr = HRESULT_FROM_WIN32(res);

-  if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||

-      hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {

-    hr = S_FALSE;

-  }

-  return hr;

-}

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_REG_KEY_H_

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// reg_key.h
+//
+// Registry configuration wrappers class
+//
+// Offers static functions for convenient
+// fast access for individual values
+//
+// Also provides a wrapper class for efficient
+// batch operations on values of a given registry key.
+
+#ifndef OMAHA_COMMON_REG_KEY_H_
+#define OMAHA_COMMON_REG_KEY_H_
+
+#include <windows.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/static_assert.h"
+#include "omaha/common/store_watcher.h"
+
+namespace omaha {
+
+// maximum sizes registry key and value names
+#define kMaxKeyNameChars   (255 + 1)
+#define kMaxValueNameChars (16383 + 1)
+
+class RegKey {
+ public:
+  RegKey();
+  virtual ~RegKey();
+
+  // create a reg key
+  HRESULT Create(HKEY hKeyParent, const TCHAR * key_name,
+        TCHAR * reg_class = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE,
+        REGSAM sam_desired = KEY_ALL_ACCESS,
+        LPSECURITY_ATTRIBUTES lp_sec_attr = NULL,
+        LPDWORD lp_disposition = NULL);
+
+  // create a reg key, given the full key name, including the HKEY root
+  // (say for example, "HKLM\\Software")
+  HRESULT Create(const TCHAR * full_key_name,
+        TCHAR * reg_class = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE,
+        REGSAM sam_desired = KEY_ALL_ACCESS,
+        LPSECURITY_ATTRIBUTES lp_sec_attr = NULL,
+        LPDWORD lp_disposition = NULL);
+
+  // static helper function that create a set of reg keys,
+  // given an array of full key names including the HKEY root
+  // (say for example, "HKLM\\Software")
+  static HRESULT CreateKeys(const TCHAR* keys_to_create[],
+                            DWORD number_of_keys,
+                            TCHAR* reg_class = REG_NONE,
+                            DWORD options = REG_OPTION_NON_VOLATILE,
+                            LPSECURITY_ATTRIBUTES lp_sec_attr = NULL);
+
+  // Static method to create a single key.
+  static HRESULT CreateKey(const TCHAR * full_key_name,
+                           TCHAR * reg_class = REG_NONE,
+                           DWORD options = REG_OPTION_NON_VOLATILE,
+                           LPSECURITY_ATTRIBUTES lp_sec_attr = NULL);
+
+  // open an existing reg key
+  HRESULT Open(HKEY hKeyParent,
+               const TCHAR * key_name,
+               REGSAM sam_desired = KEY_ALL_ACCESS);
+
+  // open an existing reg key, given the full key name, including the HKEY root
+  // (say for example, "HKLM\\Software")
+  HRESULT Open(const TCHAR * full_key_name,
+               REGSAM sam_desired = KEY_ALL_ACCESS);
+
+  // close this reg key
+  virtual HRESULT Close();
+
+  // check if the key has a specified value
+  bool HasValue(const TCHAR * value_name);
+
+  // get the number of values for this key
+  uint32 GetValueCount();
+
+  // Called to get the value name for the given value name index
+  // Use GetValueCount() to get the total value_name count for this key
+  // Returns failure if no key at the specified index
+  // If you modify the key while enumerating, the indexes will be out of order.
+  // Since the index order is not guaranteed, you need to reset your counting
+  // loop.
+  // type refers to REG_DWORD, REG_QWORD, etc..
+  // 'type' can be NULL if not interested in the value type
+  HRESULT GetValueNameAt(int index, CString * value_name, DWORD *type);
+
+  // check if the current key has the specified subkey
+  bool HasSubkey(const TCHAR * key_name) const;
+
+  // get the number of subkeys for this key
+  uint32 GetSubkeyCount();
+
+  // Called to get the key name for the given key index
+  // Use GetSubkeyCount() to get the total count for this key
+  // Returns failure if no key at the specified index
+  // If you modify the key while enumerating, the indexes will be out of order.
+  // Since the index order is not guaranteed, you need to reset your counting
+  // loop.
+  HRESULT GetSubkeyNameAt(int index, CString * key_name);
+
+  // SETTERS
+
+  // set an int32 value - use when reading multiple values from a key
+  HRESULT SetValue(const TCHAR * value_name, DWORD value) const;
+
+  // set an int64 value
+  HRESULT SetValue(const TCHAR * value_name, DWORD64 value) const;
+
+  // set a string value
+  HRESULT SetValue(const TCHAR * value_name, const TCHAR * value) const;
+
+  // set binary data
+  HRESULT SetValue(const TCHAR * value_name,
+                   const byte * value,
+                   DWORD byte_count) const;
+
+  // set raw data, including type
+  HRESULT SetValue(const TCHAR * value_name,
+                   const byte * value,
+                   DWORD byte_count,
+                   DWORD type) const;
+
+  // GETTERS
+
+  // get an int32 value
+  HRESULT GetValue(const TCHAR * value_name, DWORD * value) const;
+
+  // get an int64 value
+  //
+  // Note: if you are using time64 you should
+  // likely use GetLimitedTimeValue (util.h) instead of this method.
+  HRESULT GetValue(const TCHAR * value_name, DWORD64 * value) const;
+
+  // get a string value - the caller must free the return buffer
+  HRESULT GetValue(const TCHAR * value_name, TCHAR * * value) const;
+
+  // get a CString value
+  HRESULT GetValue(const TCHAR* value_name, OUT CString* value) const;
+
+  // get a vector<CString> value from REG_MULTI_SZ type
+  HRESULT GetValue(const TCHAR * value_name,
+                   std::vector<CString> * value) const;
+
+  // get binary data - the caller must free the return buffer
+  HRESULT GetValue(const TCHAR * value_name,
+                   byte * * value,
+                   DWORD * byte_count) const;
+
+  // get raw data, including type - the caller must free the return buffer
+  HRESULT GetValue(const TCHAR * value_name,
+                   byte * * value,
+                   DWORD * byte_count,
+                   DWORD *type) const;
+
+  // RENAMERS
+
+  // Rename a named value.
+  HRESULT RenameValue(const TCHAR * old_value_name,
+                      const TCHAR * new_value_name) const;
+
+  // STATIC VERSIONS
+
+  // flush
+  static HRESULT FlushKey(const TCHAR * full_key_name);
+
+  // Check if a key exists.
+  static bool HasKey(const TCHAR * full_key_name);
+
+  // Check if a key exists in the native (i.e. non-redirected) registry.
+  static bool HasNativeKey(const TCHAR * full_key_name);
+
+  // check if the key has a specified value
+  static bool HasValue(const TCHAR * full_key_name, const TCHAR * value_name);
+
+  // SETTERS
+
+  // STATIC int32 set
+  static HRESULT SetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          DWORD value);
+
+  // STATIC int64 set
+  static HRESULT SetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          DWORD64 value);
+
+  // STATIC float set
+  static HRESULT SetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          float value);
+
+  // STATIC double set
+  static HRESULT SetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          double value);
+
+  // STATIC string set
+  static HRESULT SetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          const TCHAR * value);
+
+  // STATIC binary data set
+  static HRESULT SetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          const byte * value,
+                          DWORD byte_count);
+
+  // STATIC array of strings set
+  static HRESULT SetValueMultiSZ(const TCHAR * full_key_name,
+                                 const TCHAR * value_name,
+                                 const byte * value,
+                                 DWORD byte_count);
+
+  // STATIC expandable string set
+  static HRESULT SetValueExpandSZ(const TCHAR * full_key_name,
+                                  const TCHAR * value_name,
+                                  const TCHAR * value);
+
+  // GETTERS
+
+  // STATIC int32 get
+  static HRESULT GetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          DWORD * value);
+
+  // STATIC int64 get
+  //
+  // Note: if you are using time64 you should
+  // likely use GetLimitedTimeValue (util.h) instead of this method.
+  static HRESULT GetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          DWORD64 * value);
+
+  // STATIC float get
+  static HRESULT GetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          float * value);
+
+  // STATIC double get
+  static HRESULT GetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          double * value);
+
+  // STATIC string get (STR and CString versions) - the caller must free
+  // the return buffer
+  static HRESULT GetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          TCHAR * * value);
+
+  static HRESULT GetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          CString * value);
+
+  // STATIC REG_MULTI_SZ get
+  static HRESULT GetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          std::vector<CString> * value);
+
+  // STATIC get binary data - the caller must free the return buffer
+  static HRESULT GetValue(const TCHAR * full_key_name,
+                          const TCHAR * value_name,
+                          byte * * value,
+                          DWORD * byte_count);
+
+  // Try reg keys successively if there is a failure in getting a value.
+  //
+  // Typically used when there is a user value and a default value if the
+  // user has none.
+  template<typename T>
+  static HRESULT GetValue(const TCHAR * full_key_names[],
+                          int key_names_length,
+                          const TCHAR * value_name,
+                          T* value);
+
+  // RENAMERS
+
+  // Rename a named value.
+  static HRESULT RenameValue(const TCHAR * full_key_name,
+                             const TCHAR * old_value_name,
+                             const TCHAR * new_value_name);
+
+  // COPIERS
+
+  // The full_to_key must exist for CopyValue to succeed.
+  static HRESULT CopyValue(const TCHAR * full_from_key_name,
+                           const TCHAR * from_value_name,
+                           const TCHAR * full_to_key_name,
+                           const TCHAR * to_value_name);
+
+  static HRESULT CopyValue(const TCHAR * full_from_key_name,
+                           const TCHAR * full_to_key_name,
+                           const TCHAR * value_name);
+
+  // Get type of a registry value
+  static HRESULT GetValueType(const TCHAR* full_key_name,
+                              const TCHAR* value_name,
+                              DWORD* value_type);
+
+  // delete a subkey of the current key (with no subkeys)
+  HRESULT DeleteSubKey(const TCHAR * key_name);
+
+  // recursively delete a sub key of the current key (and all its subkeys)
+  HRESULT RecurseDeleteSubKey(const TCHAR * key_name);
+
+  // STATIC version of delete key - handles nested keys also
+  // delete a key and all its sub-keys recursively
+  // Returns S_FALSE if key didn't exist, S_OK if deletion was successful,
+  // and failure otherwise.
+  static HRESULT DeleteKey(const TCHAR* full_key_name);
+
+  // STATIC version of delete key
+  // delete a key recursively or non-recursively
+  // Returns S_FALSE if key didn't exist, S_OK if deletion was successful,
+  // and failure otherwise.
+  static HRESULT DeleteKey(const TCHAR* full_key_name, bool recursive);
+
+  // delete the specified value
+  HRESULT DeleteValue(const TCHAR * value_name) const;
+
+  // STATIC version of delete value
+  // Returns S_FALSE if key didn't exist, S_OK if deletion was successful,
+  // and failure otherwise.
+  static HRESULT DeleteValue(const TCHAR * full_key_name,
+                             const TCHAR * value_name);
+
+  // Peek inside (use a RegKey as a smart wrapper around a registry handle)
+  HKEY Key() { return h_key_; }
+
+  // Used to help test the private functionality
+  friend class RegKeyTestClass;
+
+  // helper function to get the HKEY and the root key from a string
+  // representation modifies the argument in place and returns the key name
+  // e.g. HKLM\\Software\\Google\... returns HKLM, "Software\\Google\..."
+  // Necessary for the static versions that use the full name of the reg key
+  static HKEY GetRootKeyInfo(CString * full_key_name);
+
+  // Returns true if this key name is 'safe' for deletion (doesn't specify
+  // a key root)
+  static bool SafeKeyNameForDeletion(const wchar_t *key_name);
+
+  // save the key and all of its subkeys and values to a file
+  static HRESULT Save(const TCHAR* full_key_name, const TCHAR* file_name);
+
+  // restore the key and all of its subkeys and values which are saved into
+  // a file
+  static HRESULT Restore(const TCHAR* full_key_name, const TCHAR* file_name);
+
+  // Is the key empty: having no sub-keys and values
+  static bool IsKeyEmpty(const TCHAR* full_key_name);
+
+ private:
+
+  // Helper function to check if a key exists, using the sam flags specified.
+  // Note: KEY_READ must be included in sam_flags.
+  static bool HasKeyHelper(const TCHAR * full_key_name, DWORD sam_flags);
+
+  // helper function to get the parent key name and the subkey from a string
+  // representation modifies the argument in place and returns the key name
+  // e.g. Software\\Google\\Foo_Bar returns "Software\\Google", "Foo_Bar"
+  // Necessary for the static versions that use the full name of the reg key
+  static CString GetParentKeyInfo(CString * key_name);
+
+  // helper function to get any value from the registry
+  // used when the size of the data is unknown
+  HRESULT GetValueHelper(const TCHAR * value_name,
+                         DWORD * type,
+                         byte * * value,
+                         DWORD * byte_count) const;
+
+  // common SET Helper for the static case
+  static HRESULT SetValueStaticHelper(const TCHAR * full_key_name,
+                                      const TCHAR * value_name,
+                                      DWORD type,
+                                      LPVOID value,
+                                      DWORD byte_count = 0);
+
+  // common GET Helper for the static case
+  static HRESULT GetValueStaticHelper(const TCHAR * full_key_name,
+                                      const TCHAR * value_name,
+                                      DWORD type,
+                                      LPVOID value,
+                                      DWORD * byte_count = NULL);
+
+  // convert REG_MULTI_SZ bytes to string array
+  static HRESULT MultiSZBytesToStringArray(const byte * buffer,
+                                           DWORD byte_count,
+                                           std::vector<CString> * value);
+
+  // set a string or expandable string value
+  HRESULT SetStringValue(const TCHAR * value_name,
+                         const TCHAR * value,
+                         DWORD type) const;
+
+  // the HKEY for the current key
+  HKEY h_key_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(RegKey);
+};
+
+// Provides all the functionality of RegKey plus
+// an event to watch for changes to the registry key.
+class RegKeyWithChangeEvent : public RegKey {
+ public:
+  RegKeyWithChangeEvent() {}
+  // close this reg key and the event
+  virtual HRESULT Close();
+
+  // Called to create/reset the event that gets signaled
+  // any time the registry key changes.  Access the created
+  // event using change_event().
+  //
+  // See the documentation for RegNotifyChangeKeyValue
+  // for values for notify_filter.
+  HRESULT SetupEvent(bool watch_subtree, DWORD notify_filter);
+
+  // Indicates if any changes (that are being monitored) have occured
+  bool HasChangeOccurred() const;
+
+  // Get the event that is signaled on registry changes.
+  // Note:
+  //   * This event will remain constant until Close() is called.
+  //   * One should call SetupEvent to set-up the event.
+  //   * The event is only signaled on the next change and remains signaled.
+  //     Do not call ::ResetEvent().  Call SetupEvent() to reset
+  //     the event and wait for more changes.
+  HANDLE change_event() const {
+    return get(change_event_);
+  }
+
+ private:
+  scoped_handle change_event_;
+  DISALLOW_EVIL_CONSTRUCTORS(RegKeyWithChangeEvent);
+};
+
+// Does the common things necessary for watching
+// registry key changes.  If there are file change or other watchers,
+// there could be a common interface for the three methods to decouple
+// the code that is doing the watching from the code that owns the store.
+class RegKeyWatcher : public StoreWatcher {
+ public:
+  // reg_key: the full string for the reg key
+  // watch_subtree: watch all subkey changes  or
+  //                only immediate child values
+  // notify_filter: See the documentation for RegNotifyChangeKeyValue
+  // allow_creation: Should the key be created if it doesn't exist?
+  RegKeyWatcher(const TCHAR* reg_key, bool watch_subtree,
+                DWORD notify_filter, bool allow_creation);
+  virtual ~RegKeyWatcher() {}
+
+  // Called to create/reset the event that gets signaled
+  // any time the registry key changes.  Access the created
+  // event using change_event().
+  virtual HRESULT EnsureEventSetup();
+
+  // Get the event that is signaled on registry changes.
+  virtual HANDLE change_event() const;
+
+ private:
+  // Used to do the SetupEvent method
+  scoped_ptr<RegKeyWithChangeEvent> reg_key_with_change_event_;
+
+  CString reg_key_string_;
+  bool watch_subtree_;
+  bool allow_creation_;
+  DWORD notify_filter_;
+  DISALLOW_EVIL_CONSTRUCTORS(RegKeyWatcher);
+};
+
+
+inline RegKey::RegKey() { h_key_ = NULL; }
+
+inline RegKey::~RegKey() { Close(); }
+
+inline bool RegKey::HasValue(const TCHAR* value_name) {
+  return (ERROR_SUCCESS == ::RegQueryValueEx(h_key_,
+                                             value_name,
+                                             NULL, NULL,
+                                             NULL,
+                                             NULL));
+}
+
+// SETTERS static versions
+inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                DWORD value) {
+  ASSERT1(full_key_name);
+
+  return SetValueStaticHelper(full_key_name, value_name, REG_DWORD, &value);
+}
+
+inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                DWORD64 value) {
+  ASSERT1(full_key_name);
+
+  return SetValueStaticHelper(full_key_name, value_name, REG_QWORD, &value);
+}
+
+inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                float value) {
+  ASSERT1(full_key_name);
+
+  return SetValueStaticHelper(full_key_name,
+                              value_name,
+                              REG_BINARY,
+                              &value,
+                              sizeof(value));
+}
+
+inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                double value) {
+  ASSERT1(full_key_name);
+
+  return SetValueStaticHelper(full_key_name,
+                              value_name,
+                              REG_BINARY,
+                              &value,
+                              sizeof(value));
+}
+
+inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                const TCHAR* value) {
+  ASSERT1(full_key_name);
+  ASSERT1(value);
+
+  return SetValueStaticHelper(full_key_name,
+                              value_name,
+                              REG_SZ,
+                              const_cast<TCHAR*>(value));
+}
+
+inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                const byte* value,
+                                DWORD byte_count) {
+  ASSERT1(full_key_name);
+
+  return SetValueStaticHelper(full_key_name, value_name, REG_BINARY,
+                              const_cast<byte*>(value), byte_count);
+}
+
+inline HRESULT RegKey::SetValueMultiSZ(const TCHAR* full_key_name,
+                                       const TCHAR* value_name,
+                                       const byte* value,
+                                       DWORD byte_count) {
+  ASSERT1(full_key_name);
+
+  return SetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ,
+                              const_cast<byte*>(value), byte_count);
+}
+
+inline HRESULT RegKey::SetValueExpandSZ(const TCHAR* full_key_name,
+                                        const TCHAR* value_name,
+                                        const TCHAR* value) {
+  ASSERT1(full_key_name);
+  ASSERT1(value);
+
+  return SetValueStaticHelper(full_key_name,
+                              value_name,
+                              REG_EXPAND_SZ,
+                              const_cast<TCHAR*>(value));
+}
+
+// GETTERS static versions
+inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                DWORD* value) {
+  ASSERT1(full_key_name);
+  ASSERT1(value);
+
+  return GetValueStaticHelper(full_key_name, value_name, REG_DWORD, value);
+}
+
+inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                DWORD64* value) {
+  ASSERT1(full_key_name);
+  ASSERT1(value);
+
+  return GetValueStaticHelper(full_key_name, value_name, REG_QWORD, value);
+}
+
+inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                float* value) {
+  ASSERT1(value);
+  ASSERT1(value_name);
+  ASSERT1(full_key_name);
+
+  DWORD byte_count = 0;
+  byte* buffer = NULL;
+  HRESULT hr = GetValueStaticHelper(full_key_name,
+                                    value_name,
+                                    REG_BINARY,
+                                    &buffer,
+                                    &byte_count);
+  scoped_array<byte> free_buffer(buffer);
+
+  if (SUCCEEDED(hr)) {
+    if (byte_count == sizeof(*value)) {
+      ::CopyMemory(value, buffer, sizeof(*value));
+    } else {
+      UTIL_LOG(LEVEL_ERROR, (_T("[RegKey::GetValue]")
+                             _T("[size mismatches for float value][%s\\%s]"),
+                             full_key_name, value_name));
+      return HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
+    }
+  }
+
+  return hr;
+}
+
+inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                double* value) {
+  ASSERT1(value);
+  ASSERT1(value_name);
+  ASSERT1(full_key_name);
+
+  DWORD byte_count = 0;
+  byte* buffer = NULL;
+  HRESULT hr = GetValueStaticHelper(full_key_name,
+                                    value_name,
+                                    REG_BINARY,
+                                    &buffer,
+                                    &byte_count);
+  scoped_array<byte> free_buffer(buffer);
+
+  if (SUCCEEDED(hr)) {
+    if (byte_count == sizeof(*value)) {
+      ::CopyMemory(value, buffer, sizeof(*value));
+    } else {
+      UTIL_LOG(LEVEL_ERROR, (_T("[RegKey::GetValue]")
+                             _T("[size mismatches for double value][%s\\%s]"),
+                             full_key_name, value_name));
+      return HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
+    }
+  }
+
+  return hr;
+}
+
+inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                TCHAR** value) {
+  ASSERT1(full_key_name);
+  ASSERT1(value);
+
+  return GetValueStaticHelper(full_key_name, value_name, REG_SZ, value);
+}
+
+inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                CString* value) {
+  ASSERT1(full_key_name);
+  ASSERT1(value);
+
+  TCHAR* buffer = NULL;
+  HRESULT hr = RegKey::GetValue(full_key_name, value_name, &buffer);
+  value->SetString(buffer);
+  delete [] buffer;
+  return hr;
+}
+
+inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                std::vector<CString>* value) {
+  ASSERT1(full_key_name);
+  ASSERT1(value);
+
+  return GetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, value);
+}
+
+inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
+                                const TCHAR* value_name,
+                                byte** value,
+                                DWORD* byte_count) {
+  ASSERT1(full_key_name);
+  ASSERT1(value);
+  ASSERT1(byte_count);
+
+  return GetValueStaticHelper(full_key_name,
+                              value_name,
+                              REG_BINARY,
+                              value,
+                              byte_count);
+}
+
+template<typename T>
+HRESULT RegKey::GetValue(const TCHAR* full_key_names[],
+                         int key_names_length,
+                         const TCHAR* value_name,
+                         T* value) {
+  HRESULT hr = S_OK;
+  for (int i = 0; i < key_names_length; ++i) {
+    hr = GetValue(full_key_names[i], value_name, value);
+    if (SUCCEEDED(hr)) {
+      return hr;
+    }
+  }
+  return hr;
+}
+
+// Rename a named value.
+inline HRESULT RegKey::RenameValue(const TCHAR * full_key_name,
+                                   const TCHAR * old_value_name,
+                                   const TCHAR * new_value_name) {
+  ASSERT1(full_key_name);
+
+  RegKey reg_key;
+  HRESULT hr = reg_key.Open(full_key_name);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return reg_key.RenameValue(old_value_name, new_value_name);
+}
+
+inline HRESULT RegKey::CopyValue(const TCHAR * full_from_key_name,
+                                 const TCHAR * full_to_key_name,
+                                 const TCHAR * value_name) {
+  return CopyValue(full_from_key_name,
+                   value_name,
+                   full_to_key_name,
+                   value_name);
+}
+
+// DELETE
+inline HRESULT RegKey::DeleteSubKey(const TCHAR* key_name) {
+  ASSERT1(key_name);
+  ASSERT1(h_key_);
+
+  LONG res = ::RegDeleteKey(h_key_, key_name);
+  HRESULT hr = HRESULT_FROM_WIN32(res);
+  if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
+      hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
+    hr = S_FALSE;
+  }
+  return hr;
+}
+
+inline HRESULT RegKey::DeleteValue(const TCHAR* value_name) const {
+  ASSERT1(value_name);
+  ASSERT1(h_key_);
+
+  LONG res = ::RegDeleteValue(h_key_, value_name);
+  HRESULT hr = HRESULT_FROM_WIN32(res);
+  if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
+      hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
+    hr = S_FALSE;
+  }
+  return hr;
+}
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_REG_KEY_H_
+
diff --git a/common/reg_key_unittest.cc b/common/reg_key_unittest.cc
index faaeae9..ec8032d 100644
--- a/common/reg_key_unittest.cc
+++ b/common/reg_key_unittest.cc
@@ -1,777 +1,777 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/reg_key.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-#define kStRkey1          _T("HKCU\\Software\\Google\\Update\\TEST")

-#define kRkey1            _T("Software\\Google\\Update\\TEST")

-#define kStRkey2          _T("HKCU\\Software\\Google\\Update\\TEST2")

-#define kStRkey3          _T("HKCU\\Software\\Google\\Update\\TEST3")

-#define kRkey1SubkeyName  _T("subkey_test")

-#define kRkey1Subkey      kRkey1 _T("\\") kRkey1SubkeyName

-

-// NON - STATIC

-

-#define kValNameInt          _T("Int32 Value")

-#define kRenameValNameInt    _T("Renamed Int32 Value")

-#define kIntVal              (DWORD)20

-#define kIntVal2             (DWORD)30

-

-#define kValNameInt64        _T("Int64 Value")

-#define kIntVal64            (DWORD64)40

-#define kIntVal642           (DWORD64)50

-

-#define kValNameStr          _T("Str Value")

-#define kStrVal              _T("Some string data 1")

-#define kStrVal2             _T("Some string data 2")

-

-#define kValNameBinary       _T("Binary Value")

-#define kBinaryVal           "Some binary data abcdefghi 1"

-#define kBinaryVal2          "Some binary data abcdefghi 2"

-

-// STATIC

-

-#define kStValNameInt        _T("Static Int32 Value")

-#define kStIntVal            (DWORD)60

-

-#define kStValNameInt64      _T("Static Int64 Value")

-#define kStIntVal64          (DWORD64)80

-

-#define kStValNameFloat      _T("Static Float Value")

-#define kStFloatVal          (static_cast<float>(12.3456789))

-

-#define kStValNameDouble     _T("Static Double Value")

-#define kStDoubleVal         (static_cast<double>(98.7654321))

-

-#define kStValNameStr        _T("Static Str Value")

-#define kRenameStValNameStr  _T("Renamed Static Str Value")

-#define kStStrVal            _T("Some static string data 2")

-

-#define kStValNameBinary     _T("Static Binary Value")

-#define kStBinaryVal         "Some static binary data abcdefghi 2"

-

-// Test the private member functions of RegKey

-class RegKeyTestClass : public testing::Test {

- public:

-  static const HKEY GetHKey(const RegKey& reg) {

-    return reg.h_key_;

-  }

-

-  static CString GetParentKeyInfo(CString* key_name) {

-    return RegKey::GetParentKeyInfo(key_name);

-  }

-};

-

-// Make sure the RegKey is nice and clean when we first initialize it

-TEST_F(RegKeyTestClass, Init) {

-  // Make a new RegKey object so we can test its pristine state

-  RegKey reg;

-

-  ASSERT_TRUE(GetHKey(reg) == NULL);

-}

-

-// Make sure the helper functions work

-TEST_F(RegKeyTestClass, Helper) {

-  // Dud items cause NULL

-  CString temp_key;

-

-  // RegKey::GetRootKeyInfo turns a string into the HKEY and subtree value

-

-  // Try out some dud values

-  temp_key = _T("");

-  ASSERT_TRUE(RegKey::GetRootKeyInfo(&temp_key) == NULL);

-  ASSERT_STREQ(temp_key, _T(""));

-

-  temp_key = _T("a");

-  ASSERT_TRUE(RegKey::GetRootKeyInfo(&temp_key) == NULL);

-  ASSERT_STREQ(temp_key, _T(""));

-

-  // The basics

-  temp_key = _T("HKLM\\a");

-  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_LOCAL_MACHINE);

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  temp_key = _T("HKEY_LOCAL_MACHINE\\a");

-  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_LOCAL_MACHINE);

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  temp_key = _T("HKCU\\a");

-  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CURRENT_USER);

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  temp_key = _T("HKEY_CURRENT_USER\\a");

-  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CURRENT_USER);

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  temp_key = _T("HKU\\a");

-  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_USERS);

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  temp_key = _T("HKEY_USERS\\a");

-  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_USERS);

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  temp_key = _T("HKCR\\a");

-  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CLASSES_ROOT);

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  temp_key = _T("HKEY_CLASSES_ROOT\\a");

-  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CLASSES_ROOT);

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  // Make sure it is case insensitive

-  temp_key = _T("hkcr\\a");

-  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CLASSES_ROOT);

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  temp_key = _T("hkey_CLASSES_ROOT\\a");

-  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CLASSES_ROOT);

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  // Test out temp_GetParentKeyInfo

-

-  // dud cases

-  temp_key = _T("");

-  ASSERT_STREQ(GetParentKeyInfo(&temp_key), _T(""));

-  ASSERT_STREQ(temp_key, _T(""));

-

-  temp_key = _T("a");

-  ASSERT_STREQ(GetParentKeyInfo(&temp_key), _T(""));

-  ASSERT_STREQ(temp_key, _T("a"));

-

-  temp_key = _T("a\\b");

-  ASSERT_STREQ(GetParentKeyInfo(&temp_key), _T("a"));

-  ASSERT_STREQ(temp_key, _T("b"));

-

-  temp_key = _T("\\b");

-  ASSERT_STREQ(GetParentKeyInfo(&temp_key), _T(""));

-  ASSERT_STREQ(temp_key, _T("b"));

-

-

-  // Some regular cases

-  temp_key = _T("HKEY_CLASSES_ROOT\\moon");

-  ASSERT_STREQ(GetParentKeyInfo(&temp_key), _T("HKEY_CLASSES_ROOT"));

-  ASSERT_STREQ(temp_key, _T("moon"));

-

-  temp_key = _T("HKEY_CLASSES_ROOT\\moon\\doggy");

-  ASSERT_STREQ(GetParentKeyInfo(&temp_key),

-               _T("HKEY_CLASSES_ROOT\\moon"));

-  ASSERT_STREQ(temp_key, _T("doggy"));

-}

-

-

-TEST(RegKeyTest, RegKey) {

-  //

-  // PRIVATE MEMBER WHITE BOX TESTS

-  //

-  RegKeyWithChangeEvent r_key;

-  bool bool_res = false;

-  HRESULT hr = E_FAIL;

-  DWORD int_val = 0;

-  DWORD64 int64_val = 0;

-  time64 t = 0;

-  float float_val = 0;

-  double double_val = 0;

-  TCHAR * str_val = NULL;

-  byte * binary_val = NULL;

-  DWORD byte_count = 0;

-

-  // Just in case...

-  // make sure the no test key residue is left from previous aborted runs

-  hr = RegKey::DeleteKey(kStRkey1);

-

-  // first test the non-static version

-

-  // create a reg key

-  hr = r_key.Create(HKEY_CURRENT_USER, kRkey1);

-  ASSERT_SUCCEEDED(hr);

-

-  // do the create twice - it should return the already created one

-  hr = r_key.Create(HKEY_CURRENT_USER, kRkey1);

-  ASSERT_SUCCEEDED(hr);

-

-  // now do an open - should work just fine

-  hr = r_key.Open(HKEY_CURRENT_USER, kRkey1);

-  ASSERT_SUCCEEDED(hr);

-

-  // get an in-existent value

-  hr = r_key.GetValue(kValNameInt, &int_val);

-  ASSERT_EQ(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));

-

-  // set-up an event to watch for changes

-  hr = r_key.SetupEvent(TRUE,

-                        REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET);

-  ASSERT_SUCCEEDED(hr);

-  HANDLE change_event = r_key.change_event();

-  ASSERT_EQ(::WaitForSingleObject(change_event, 0), WAIT_TIMEOUT);

-

-  // set and get some values and verify that the handle gets signaled

-

-  // set an INT 32

-  hr = r_key.SetValue(kValNameInt, kIntVal);

-  ASSERT_SUCCEEDED(hr);

-  // verify that we got the change and that the event got reset appropriately

-  // and set-up the notification again (use the actual event this time)

-  ASSERT_EQ(::WaitForSingleObject(change_event, 0), WAIT_OBJECT_0);

-  hr = r_key.SetupEvent(TRUE,

-                        REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_FALSE(r_key.HasChangeOccurred());

-

-  // check that the value exists

-  bool_res = r_key.HasValue(kValNameInt);

-  ASSERT_TRUE(bool_res);

-  // No change expected on a read

-  ASSERT_FALSE(r_key.HasChangeOccurred());

-

-  // read it back

-  hr = r_key.GetValue(kValNameInt, &int_val);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(int_val, kIntVal);

-  // No change expected on a read

-  ASSERT_FALSE(r_key.HasChangeOccurred());

-

-  // set it again!

-  hr = r_key.SetValue(kValNameInt, kIntVal2);

-  ASSERT_SUCCEEDED(hr);

-  // verify that we got the change and that the event got reset appropriately

-  // and set-up the notification again

-  ASSERT_TRUE(r_key.HasChangeOccurred());

-  hr = r_key.SetupEvent(TRUE,

-                        REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_FALSE(r_key.HasChangeOccurred());

-

-  // read it again

-  hr = r_key.GetValue(kValNameInt, &int_val);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(int_val, kIntVal2);

-  // No change expected on a read

-  ASSERT_FALSE(r_key.HasChangeOccurred());

-

-  // delete the value

-  hr = r_key.DeleteValue(kValNameInt);

-  ASSERT_SUCCEEDED(hr);

-  // verify that we got the change

-  ASSERT_TRUE(r_key.HasChangeOccurred());

-

-  // check that the value is gone

-  bool_res = r_key.HasValue(kValNameInt);

-  ASSERT_FALSE(bool_res);

-

-  // set an INT 64

-  hr = r_key.SetValue(kValNameInt64, kIntVal64);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = r_key.HasValue(kValNameInt64);

-  ASSERT_TRUE(bool_res);

-

-  // read it back

-  hr = r_key.GetValue(kValNameInt64, &int64_val);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(int64_val, kIntVal64);

-

-  // delete the value

-  hr = r_key.DeleteValue(kValNameInt64);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = r_key.HasValue(kValNameInt64);

-  ASSERT_FALSE(bool_res);

-

-  // set a string

-  hr = r_key.SetValue(kValNameStr, kStrVal);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = r_key.HasValue(kValNameStr);

-  ASSERT_TRUE(bool_res);

-

-  // read it back

-  hr = r_key.GetValue(kValNameStr, &str_val);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_STREQ(str_val, kStrVal);

-  delete [] str_val;

-

-  // set it again

-  hr = r_key.SetValue(kValNameStr, kStrVal2);

-  ASSERT_SUCCEEDED(hr);

-

-  // read it again

-  hr = r_key.GetValue(kValNameStr, &str_val);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_STREQ(str_val, kStrVal2);

-  delete [] str_val;

-

-  // delete the value

-  hr = r_key.DeleteValue(kValNameStr);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = r_key.HasValue(kValNameInt);

-  ASSERT_FALSE(bool_res);

-

-  // set a binary value

-  hr = r_key.SetValue(kValNameBinary, (const byte *)kBinaryVal,

-                      sizeof(kBinaryVal)-1);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = r_key.HasValue(kValNameBinary);

-  ASSERT_TRUE(bool_res);

-

-  // read it back

-  hr = r_key.GetValue(kValNameBinary, &binary_val, &byte_count);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(0, memcmp(binary_val, kBinaryVal, sizeof(kBinaryVal)-1));

-  delete [] binary_val;

-

-  // set it again

-  hr = r_key.SetValue(kValNameBinary, (const byte *)kBinaryVal2,

-                      sizeof(kBinaryVal)-1);

-  ASSERT_SUCCEEDED(hr);

-

-  // read it again

-  hr = r_key.GetValue(kValNameBinary, &binary_val, &byte_count);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(0, memcmp(binary_val, kBinaryVal2, sizeof(kBinaryVal2)-1));

-  delete [] binary_val;

-

-  // delete the value

-  hr = r_key.DeleteValue(kValNameBinary);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = r_key.HasValue(kValNameBinary);

-  ASSERT_FALSE(bool_res);

-

-  // set some values and check the total count

-

-  // set an INT 32

-  hr = r_key.SetValue(kValNameInt, kIntVal);

-  ASSERT_SUCCEEDED(hr);

-

-  // set an INT 64

-  hr = r_key.SetValue(kValNameInt64, kIntVal64);

-  ASSERT_SUCCEEDED(hr);

-

-  // set a string

-  hr = r_key.SetValue(kValNameStr, kStrVal);

-  ASSERT_SUCCEEDED(hr);

-

-  // set a binary value

-  hr = r_key.SetValue(kValNameBinary, (const byte *)kBinaryVal,

-                      sizeof(kBinaryVal)-1);

-  ASSERT_SUCCEEDED(hr);

-

-  // get the value count

-  uint32 value_count = r_key.GetValueCount();

-  ASSERT_EQ(value_count, 4);

-

-  // check the value names

-  CString value_name;

-  DWORD type;

-

-  hr = r_key.GetValueNameAt(0, &value_name, &type);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(value_name, kValNameInt);

-  ASSERT_EQ(type, REG_DWORD);

-

-  hr = r_key.GetValueNameAt(1, &value_name, &type);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(value_name, kValNameInt64);

-  ASSERT_EQ(type, REG_QWORD);

-

-  hr = r_key.GetValueNameAt(2, &value_name, &type);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(value_name, kValNameStr);

-  ASSERT_EQ(type, REG_SZ);

-

-  hr = r_key.GetValueNameAt(3, &value_name, &type);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(value_name, kValNameBinary);

-  ASSERT_EQ(type, REG_BINARY);

-

-  // check that there are no more values

-  hr = r_key.GetValueNameAt(4, &value_name, &type);

-  ASSERT_FAILED(hr);

-

-  uint32 subkey_count = r_key.GetSubkeyCount();

-  ASSERT_EQ(subkey_count, 0);

-

-  RegKey temp_key;

-

-  // now create a subkey and make sure we can get the name

-  hr = temp_key.Create(HKEY_CURRENT_USER, kRkey1Subkey);

-  ASSERT_SUCCEEDED(hr);

-

-  // check the subkey exists

-  bool_res = r_key.HasSubkey(kRkey1SubkeyName);

-  ASSERT_TRUE(bool_res);

-

-  // check the name

-  subkey_count = r_key.GetSubkeyCount();

-  ASSERT_EQ(subkey_count, 1);

-

-  CString subkey_name;

-  hr = r_key.GetSubkeyNameAt(0, &subkey_name);

-  ASSERT_EQ(subkey_name, kRkey1SubkeyName);

-

-  // verify that the event handle remained the same throughout everything

-  ASSERT_EQ(change_event, r_key.change_event());

-

-  // close this key

-  r_key.Close();

-

-  // whack the whole key

-  hr = RegKey::DeleteKey(kStRkey1);

-  ASSERT_SUCCEEDED(hr);

-

-  // STATIC

-  // now set a different value using the static versions

-

-  // get an in-existent value from an un-existent key

-  hr = RegKey::GetValue(kStRkey1, kStValNameInt, &int_val);

-  ASSERT_EQ(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));

-

-  // set int32

-  hr = RegKey::SetValue(kStRkey1, kStValNameInt, kStIntVal);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameInt);

-  ASSERT_TRUE(bool_res);

-

-  // get an in-existent value from an existent key

-  hr = RegKey::GetValue(kStRkey1, _T("bogus"), &int_val);

-  ASSERT_EQ(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));

-

-  // read it back

-  hr = RegKey::GetValue(kStRkey1, kStValNameInt, &int_val);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(int_val, kStIntVal);

-

-  // delete the value

-  hr = RegKey::DeleteValue(kStRkey1, kStValNameInt);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameInt);

-  ASSERT_FALSE(bool_res);

-

-

-  // set int64

-  hr = RegKey::SetValue(kStRkey1, kStValNameInt64, kStIntVal64);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameInt64);

-  ASSERT_TRUE(bool_res);

-

-  // read it back

-  hr = RegKey::GetValue(kStRkey1, kStValNameInt64, &int64_val);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(int64_val, kStIntVal64);

-

-  // read it back to test time64

-  bool limited_value;

-  hr = GetLimitedTimeValue(kStRkey1, kStValNameInt64,  kStIntVal64 + 10, &t,

-                           &limited_value);

-  ASSERT_SUCCEEDED(hr);

-  EXPECT_FALSE(limited_value);

-  ASSERT_EQ(t, kStIntVal64);

-  hr = GetLimitedTimeValue(kStRkey1, kStValNameInt64,  kStIntVal64 - 10, &t,

-                           &limited_value);

-  EXPECT_TRUE(limited_value);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(t, kStIntVal64 - 10);

-  // Verify that the GetValue permanently made the value lower

-  hr = GetLimitedTimeValue(kStRkey1, kStValNameInt64,  kStIntVal64, &t,

-                           &limited_value);

-  EXPECT_FALSE(limited_value);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(t, kStIntVal64 - 10);

-

-  // delete the value

-  hr = RegKey::DeleteValue(kStRkey1, kStValNameInt64);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameInt64);

-  ASSERT_FALSE(bool_res);

-

-  // set float

-  hr = RegKey::SetValue(kStRkey1, kStValNameFloat, kStFloatVal);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameFloat);

-  ASSERT_TRUE(bool_res);

-

-  // read it back

-  hr = RegKey::GetValue(kStRkey1, kStValNameFloat, &float_val);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(float_val, kStFloatVal);

-

-  // delete the value

-  hr = RegKey::DeleteValue(kStRkey1, kStValNameFloat);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameFloat);

-  ASSERT_FALSE(bool_res);

-  hr = RegKey::GetValue(kStRkey1, kStValNameFloat, &float_val);

-  ASSERT_FAILED(hr);

-

-

-  // set double

-  hr = RegKey::SetValue(kStRkey1, kStValNameDouble, kStDoubleVal);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameDouble);

-  ASSERT_TRUE(bool_res);

-

-  // read it back

-  hr = RegKey::GetValue(kStRkey1, kStValNameDouble, &double_val);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(double_val, kStDoubleVal);

-

-  // delete the value

-  hr = RegKey::DeleteValue(kStRkey1, kStValNameDouble);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameDouble);

-  ASSERT_FALSE(bool_res);

-  hr = RegKey::GetValue(kStRkey1, kStValNameDouble, &double_val);

-  ASSERT_FAILED(hr);

-

-  // set string

-  hr = RegKey::SetValue(kStRkey1, kStValNameStr, kStStrVal);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameStr);

-  ASSERT_TRUE(bool_res);

-

-  // read it back

-  hr = RegKey::GetValue(kStRkey1, kStValNameStr, &str_val);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_STREQ(str_val, kStStrVal);

-  delete [] str_val;

-

-  // get an in-existent value from an existent key

-  hr = RegKey::GetValue(kStRkey1, _T("bogus"), &str_val);

-  ASSERT_EQ(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));

-

-  // delete the value

-  hr = RegKey::DeleteValue(kStRkey1, kStValNameStr);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameStr);

-  ASSERT_FALSE(bool_res);

-

-  // set binary

-  hr = RegKey::SetValue(kStRkey1, kStValNameBinary, (const byte *)kStBinaryVal,

-                        sizeof(kStBinaryVal)-1);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);

-  ASSERT_TRUE(bool_res);

-

-  // read it back

-  hr = RegKey::GetValue(kStRkey1, kStValNameBinary, &binary_val, &byte_count);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(0, memcmp(binary_val, kStBinaryVal, sizeof(kStBinaryVal)-1));

-  delete [] binary_val;

-

-  // delete the value

-  hr = RegKey::DeleteValue(kStRkey1, kStValNameBinary);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);

-  ASSERT_FALSE(bool_res);

-

-  // special case - set a binary value with length 0

-  hr = RegKey::SetValue(kStRkey1, kStValNameBinary,

-                        (const byte *)kStBinaryVal, 0);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);

-  ASSERT_TRUE(bool_res);

-

-  // read it back

-  hr = RegKey::GetValue(kStRkey1, kStValNameBinary, &binary_val, &byte_count);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(byte_count, 0);

-  ASSERT_TRUE(binary_val == NULL);

-  delete [] binary_val;

-

-  // delete the value

-  hr = RegKey::DeleteValue(kStRkey1, kStValNameBinary);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);

-  ASSERT_FALSE(bool_res);

-

-  // special case - set a NULL binary value

-  hr = RegKey::SetValue(kStRkey1, kStValNameBinary, NULL, 100);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value exists

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);

-  ASSERT_TRUE(bool_res);

-

-  // read it back

-  hr = RegKey::GetValue(kStRkey1, kStValNameBinary, &binary_val, &byte_count);

-  ASSERT_SUCCEEDED(hr);

-  ASSERT_EQ(byte_count, 0);

-  ASSERT_TRUE(binary_val == NULL);

-  delete [] binary_val;

-

-  // delete the value

-  hr = RegKey::DeleteValue(kStRkey1, kStValNameBinary);

-  ASSERT_SUCCEEDED(hr);

-

-  // check that the value is gone

-  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);

-  ASSERT_FALSE(bool_res);

-

-  // whack the whole key

-

-  hr = RegKey::DeleteKey(kStRkey1);

-  ASSERT_SUCCEEDED(hr);

-}

-

-// RegKey::GetValue changes the output CString when errors occur.

-TEST_F(RegKeyTestClass, ChangesStringOnErrors) {

-  CString string_val = _T("foo");

-  EXPECT_FAILED(RegKey::GetValue(_T("HCKU"), _T("no_such_value"), &string_val));

-  ASSERT_TRUE(string_val.IsEmpty());

-}

-

-TEST(RegKeyTest, CreateKeys) {

-  RegKey::DeleteKey(kStRkey1);

-  RegKey::DeleteKey(kStRkey2);

-  RegKey::DeleteKey(kStRkey3);

-  EXPECT_FALSE(RegKey::HasKey(kStRkey1));

-  EXPECT_FALSE(RegKey::HasKey(kStRkey2));

-  EXPECT_FALSE(RegKey::HasKey(kStRkey3));

-

-  // 3 keys specified but the count is two.

-  const TCHAR* keys[] = {kStRkey1, kStRkey2, kStRkey3};

-  ASSERT_SUCCEEDED(RegKey::CreateKeys(keys, 2));

-

-  EXPECT_TRUE(RegKey::HasKey(kStRkey1));

-  EXPECT_TRUE(RegKey::HasKey(kStRkey2));

-  EXPECT_FALSE(RegKey::HasKey(kStRkey3));

-

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey1));

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey2));

-}

-

-TEST(RegKeyTest, CreateKey) {

-  RegKey::DeleteKey(kStRkey1);

-  EXPECT_FALSE(RegKey::HasKey(kStRkey1));

-

-  ASSERT_SUCCEEDED(RegKey::CreateKey(kStRkey1));

-

-  EXPECT_TRUE(RegKey::HasKey(kStRkey1));

-

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey1));

-}

-

-TEST(RegKeyTest, RenameValue) {

-  RegKey reg_key;

-  ASSERT_SUCCEEDED(reg_key.Create(HKEY_CURRENT_USER, kRkey1));

-  ASSERT_SUCCEEDED(reg_key.SetValue(kValNameInt, kIntVal));

-  ASSERT_TRUE(reg_key.HasValue(kValNameInt));

-

-  ASSERT_SUCCEEDED(reg_key.RenameValue(kValNameInt, kRenameValNameInt));

-  ASSERT_FALSE(reg_key.HasValue(kValNameInt));

-

-  DWORD int_val = 0;

-  EXPECT_SUCCEEDED(reg_key.GetValue(kRenameValNameInt, &int_val));

-  EXPECT_EQ(kIntVal, int_val);

-

-  EXPECT_SUCCEEDED(reg_key.Close());

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey1));

-}

-

-TEST(RegKeyTest, RenameValueStatic) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kStRkey1, kStValNameStr, kStStrVal));

-  ASSERT_TRUE(RegKey::HasValue(kStRkey1, kStValNameStr));

-

-  RegKey::RenameValue(kStRkey1, kStValNameStr, kRenameStValNameStr);

-  ASSERT_FALSE(RegKey::HasValue(kStRkey1, kStValNameStr));

-

-  CString str_val;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kStRkey1, kRenameStValNameStr, &str_val));

-  EXPECT_STREQ(kStStrVal, str_val);

-

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey1));

-}

-

-TEST(RegKeyTest, CopyValue) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kStRkey1, kStValNameStr, kStStrVal));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kStRkey1, NULL, kStStrVal));

-  EXPECT_TRUE(RegKey::HasValue(kStRkey1, kStValNameStr));

-

-  // Test that CopyValue fails when the to_key does not exist.

-  EXPECT_FALSE(RegKey::HasKey(kStRkey2));

-  EXPECT_FAILED(RegKey::CopyValue(kStRkey1, kStRkey2, kStValNameStr));

-  EXPECT_FALSE(RegKey::HasKey(kStRkey2));

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kStRkey2));

-  // Test CopyValue(full_from_key_name, full_to_key_name, value_name).

-  EXPECT_FALSE(RegKey::HasValue(kStRkey2, kStValNameStr));

-  RegKey::CopyValue(kStRkey1, kStRkey2, kStValNameStr);

-  CString str_val;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kStRkey2, kStValNameStr, &str_val));

-  EXPECT_STREQ(kStStrVal, str_val);

-

-  // Test CopyValue to a (Default) value.

-  EXPECT_FALSE(RegKey::HasValue(kStRkey2, NULL));

-  RegKey::CopyValue(kStRkey1, kStRkey2, NULL);

-  str_val.Empty();

-  EXPECT_SUCCEEDED(RegKey::GetValue(kStRkey2, NULL, &str_val));

-  EXPECT_STREQ(kStStrVal, str_val);

-

-  // Test CopyValue(full_from_key_name, from_value_name, full_to_key_name,

-  //                to_value_name).

-  EXPECT_FALSE(RegKey::HasValue(kStRkey2, kRenameStValNameStr));

-  RegKey::CopyValue(kStRkey1, kStValNameStr, kStRkey2, kRenameStValNameStr);

-  str_val.Empty();

-  EXPECT_SUCCEEDED(RegKey::GetValue(kStRkey2, kRenameStValNameStr, &str_val));

-  EXPECT_STREQ(kStStrVal, str_val);

-

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey1));

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey2));

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/reg_key.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+#define kStRkey1          _T("HKCU\\Software\\Google\\Update\\TEST")
+#define kRkey1            _T("Software\\Google\\Update\\TEST")
+#define kStRkey2          _T("HKCU\\Software\\Google\\Update\\TEST2")
+#define kStRkey3          _T("HKCU\\Software\\Google\\Update\\TEST3")
+#define kRkey1SubkeyName  _T("subkey_test")
+#define kRkey1Subkey      kRkey1 _T("\\") kRkey1SubkeyName
+
+// NON - STATIC
+
+#define kValNameInt          _T("Int32 Value")
+#define kRenameValNameInt    _T("Renamed Int32 Value")
+#define kIntVal              (DWORD)20
+#define kIntVal2             (DWORD)30
+
+#define kValNameInt64        _T("Int64 Value")
+#define kIntVal64            (DWORD64)40
+#define kIntVal642           (DWORD64)50
+
+#define kValNameStr          _T("Str Value")
+#define kStrVal              _T("Some string data 1")
+#define kStrVal2             _T("Some string data 2")
+
+#define kValNameBinary       _T("Binary Value")
+#define kBinaryVal           "Some binary data abcdefghi 1"
+#define kBinaryVal2          "Some binary data abcdefghi 2"
+
+// STATIC
+
+#define kStValNameInt        _T("Static Int32 Value")
+#define kStIntVal            (DWORD)60
+
+#define kStValNameInt64      _T("Static Int64 Value")
+#define kStIntVal64          (DWORD64)80
+
+#define kStValNameFloat      _T("Static Float Value")
+#define kStFloatVal          (static_cast<float>(12.3456789))
+
+#define kStValNameDouble     _T("Static Double Value")
+#define kStDoubleVal         (static_cast<double>(98.7654321))
+
+#define kStValNameStr        _T("Static Str Value")
+#define kRenameStValNameStr  _T("Renamed Static Str Value")
+#define kStStrVal            _T("Some static string data 2")
+
+#define kStValNameBinary     _T("Static Binary Value")
+#define kStBinaryVal         "Some static binary data abcdefghi 2"
+
+// Test the private member functions of RegKey
+class RegKeyTestClass : public testing::Test {
+ public:
+  static const HKEY GetHKey(const RegKey& reg) {
+    return reg.h_key_;
+  }
+
+  static CString GetParentKeyInfo(CString* key_name) {
+    return RegKey::GetParentKeyInfo(key_name);
+  }
+};
+
+// Make sure the RegKey is nice and clean when we first initialize it
+TEST_F(RegKeyTestClass, Init) {
+  // Make a new RegKey object so we can test its pristine state
+  RegKey reg;
+
+  ASSERT_TRUE(GetHKey(reg) == NULL);
+}
+
+// Make sure the helper functions work
+TEST_F(RegKeyTestClass, Helper) {
+  // Dud items cause NULL
+  CString temp_key;
+
+  // RegKey::GetRootKeyInfo turns a string into the HKEY and subtree value
+
+  // Try out some dud values
+  temp_key = _T("");
+  ASSERT_TRUE(RegKey::GetRootKeyInfo(&temp_key) == NULL);
+  ASSERT_STREQ(temp_key, _T(""));
+
+  temp_key = _T("a");
+  ASSERT_TRUE(RegKey::GetRootKeyInfo(&temp_key) == NULL);
+  ASSERT_STREQ(temp_key, _T(""));
+
+  // The basics
+  temp_key = _T("HKLM\\a");
+  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_LOCAL_MACHINE);
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  temp_key = _T("HKEY_LOCAL_MACHINE\\a");
+  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_LOCAL_MACHINE);
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  temp_key = _T("HKCU\\a");
+  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CURRENT_USER);
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  temp_key = _T("HKEY_CURRENT_USER\\a");
+  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CURRENT_USER);
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  temp_key = _T("HKU\\a");
+  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_USERS);
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  temp_key = _T("HKEY_USERS\\a");
+  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_USERS);
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  temp_key = _T("HKCR\\a");
+  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CLASSES_ROOT);
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  temp_key = _T("HKEY_CLASSES_ROOT\\a");
+  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CLASSES_ROOT);
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  // Make sure it is case insensitive
+  temp_key = _T("hkcr\\a");
+  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CLASSES_ROOT);
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  temp_key = _T("hkey_CLASSES_ROOT\\a");
+  ASSERT_EQ(RegKey::GetRootKeyInfo(&temp_key), HKEY_CLASSES_ROOT);
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  // Test out temp_GetParentKeyInfo
+
+  // dud cases
+  temp_key = _T("");
+  ASSERT_STREQ(GetParentKeyInfo(&temp_key), _T(""));
+  ASSERT_STREQ(temp_key, _T(""));
+
+  temp_key = _T("a");
+  ASSERT_STREQ(GetParentKeyInfo(&temp_key), _T(""));
+  ASSERT_STREQ(temp_key, _T("a"));
+
+  temp_key = _T("a\\b");
+  ASSERT_STREQ(GetParentKeyInfo(&temp_key), _T("a"));
+  ASSERT_STREQ(temp_key, _T("b"));
+
+  temp_key = _T("\\b");
+  ASSERT_STREQ(GetParentKeyInfo(&temp_key), _T(""));
+  ASSERT_STREQ(temp_key, _T("b"));
+
+
+  // Some regular cases
+  temp_key = _T("HKEY_CLASSES_ROOT\\moon");
+  ASSERT_STREQ(GetParentKeyInfo(&temp_key), _T("HKEY_CLASSES_ROOT"));
+  ASSERT_STREQ(temp_key, _T("moon"));
+
+  temp_key = _T("HKEY_CLASSES_ROOT\\moon\\doggy");
+  ASSERT_STREQ(GetParentKeyInfo(&temp_key),
+               _T("HKEY_CLASSES_ROOT\\moon"));
+  ASSERT_STREQ(temp_key, _T("doggy"));
+}
+
+
+TEST(RegKeyTest, RegKey) {
+  //
+  // PRIVATE MEMBER WHITE BOX TESTS
+  //
+  RegKeyWithChangeEvent r_key;
+  bool bool_res = false;
+  HRESULT hr = E_FAIL;
+  DWORD int_val = 0;
+  DWORD64 int64_val = 0;
+  time64 t = 0;
+  float float_val = 0;
+  double double_val = 0;
+  TCHAR * str_val = NULL;
+  byte * binary_val = NULL;
+  DWORD byte_count = 0;
+
+  // Just in case...
+  // make sure the no test key residue is left from previous aborted runs
+  hr = RegKey::DeleteKey(kStRkey1);
+
+  // first test the non-static version
+
+  // create a reg key
+  hr = r_key.Create(HKEY_CURRENT_USER, kRkey1);
+  ASSERT_SUCCEEDED(hr);
+
+  // do the create twice - it should return the already created one
+  hr = r_key.Create(HKEY_CURRENT_USER, kRkey1);
+  ASSERT_SUCCEEDED(hr);
+
+  // now do an open - should work just fine
+  hr = r_key.Open(HKEY_CURRENT_USER, kRkey1);
+  ASSERT_SUCCEEDED(hr);
+
+  // get an in-existent value
+  hr = r_key.GetValue(kValNameInt, &int_val);
+  ASSERT_EQ(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+
+  // set-up an event to watch for changes
+  hr = r_key.SetupEvent(TRUE,
+                        REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET);
+  ASSERT_SUCCEEDED(hr);
+  HANDLE change_event = r_key.change_event();
+  ASSERT_EQ(::WaitForSingleObject(change_event, 0), WAIT_TIMEOUT);
+
+  // set and get some values and verify that the handle gets signaled
+
+  // set an INT 32
+  hr = r_key.SetValue(kValNameInt, kIntVal);
+  ASSERT_SUCCEEDED(hr);
+  // verify that we got the change and that the event got reset appropriately
+  // and set-up the notification again (use the actual event this time)
+  ASSERT_EQ(::WaitForSingleObject(change_event, 0), WAIT_OBJECT_0);
+  hr = r_key.SetupEvent(TRUE,
+                        REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_FALSE(r_key.HasChangeOccurred());
+
+  // check that the value exists
+  bool_res = r_key.HasValue(kValNameInt);
+  ASSERT_TRUE(bool_res);
+  // No change expected on a read
+  ASSERT_FALSE(r_key.HasChangeOccurred());
+
+  // read it back
+  hr = r_key.GetValue(kValNameInt, &int_val);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(int_val, kIntVal);
+  // No change expected on a read
+  ASSERT_FALSE(r_key.HasChangeOccurred());
+
+  // set it again!
+  hr = r_key.SetValue(kValNameInt, kIntVal2);
+  ASSERT_SUCCEEDED(hr);
+  // verify that we got the change and that the event got reset appropriately
+  // and set-up the notification again
+  ASSERT_TRUE(r_key.HasChangeOccurred());
+  hr = r_key.SetupEvent(TRUE,
+                        REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_FALSE(r_key.HasChangeOccurred());
+
+  // read it again
+  hr = r_key.GetValue(kValNameInt, &int_val);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(int_val, kIntVal2);
+  // No change expected on a read
+  ASSERT_FALSE(r_key.HasChangeOccurred());
+
+  // delete the value
+  hr = r_key.DeleteValue(kValNameInt);
+  ASSERT_SUCCEEDED(hr);
+  // verify that we got the change
+  ASSERT_TRUE(r_key.HasChangeOccurred());
+
+  // check that the value is gone
+  bool_res = r_key.HasValue(kValNameInt);
+  ASSERT_FALSE(bool_res);
+
+  // set an INT 64
+  hr = r_key.SetValue(kValNameInt64, kIntVal64);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = r_key.HasValue(kValNameInt64);
+  ASSERT_TRUE(bool_res);
+
+  // read it back
+  hr = r_key.GetValue(kValNameInt64, &int64_val);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(int64_val, kIntVal64);
+
+  // delete the value
+  hr = r_key.DeleteValue(kValNameInt64);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = r_key.HasValue(kValNameInt64);
+  ASSERT_FALSE(bool_res);
+
+  // set a string
+  hr = r_key.SetValue(kValNameStr, kStrVal);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = r_key.HasValue(kValNameStr);
+  ASSERT_TRUE(bool_res);
+
+  // read it back
+  hr = r_key.GetValue(kValNameStr, &str_val);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_STREQ(str_val, kStrVal);
+  delete [] str_val;
+
+  // set it again
+  hr = r_key.SetValue(kValNameStr, kStrVal2);
+  ASSERT_SUCCEEDED(hr);
+
+  // read it again
+  hr = r_key.GetValue(kValNameStr, &str_val);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_STREQ(str_val, kStrVal2);
+  delete [] str_val;
+
+  // delete the value
+  hr = r_key.DeleteValue(kValNameStr);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = r_key.HasValue(kValNameInt);
+  ASSERT_FALSE(bool_res);
+
+  // set a binary value
+  hr = r_key.SetValue(kValNameBinary, (const byte *)kBinaryVal,
+                      sizeof(kBinaryVal)-1);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = r_key.HasValue(kValNameBinary);
+  ASSERT_TRUE(bool_res);
+
+  // read it back
+  hr = r_key.GetValue(kValNameBinary, &binary_val, &byte_count);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(0, memcmp(binary_val, kBinaryVal, sizeof(kBinaryVal)-1));
+  delete [] binary_val;
+
+  // set it again
+  hr = r_key.SetValue(kValNameBinary, (const byte *)kBinaryVal2,
+                      sizeof(kBinaryVal)-1);
+  ASSERT_SUCCEEDED(hr);
+
+  // read it again
+  hr = r_key.GetValue(kValNameBinary, &binary_val, &byte_count);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(0, memcmp(binary_val, kBinaryVal2, sizeof(kBinaryVal2)-1));
+  delete [] binary_val;
+
+  // delete the value
+  hr = r_key.DeleteValue(kValNameBinary);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = r_key.HasValue(kValNameBinary);
+  ASSERT_FALSE(bool_res);
+
+  // set some values and check the total count
+
+  // set an INT 32
+  hr = r_key.SetValue(kValNameInt, kIntVal);
+  ASSERT_SUCCEEDED(hr);
+
+  // set an INT 64
+  hr = r_key.SetValue(kValNameInt64, kIntVal64);
+  ASSERT_SUCCEEDED(hr);
+
+  // set a string
+  hr = r_key.SetValue(kValNameStr, kStrVal);
+  ASSERT_SUCCEEDED(hr);
+
+  // set a binary value
+  hr = r_key.SetValue(kValNameBinary, (const byte *)kBinaryVal,
+                      sizeof(kBinaryVal)-1);
+  ASSERT_SUCCEEDED(hr);
+
+  // get the value count
+  uint32 value_count = r_key.GetValueCount();
+  ASSERT_EQ(value_count, 4);
+
+  // check the value names
+  CString value_name;
+  DWORD type;
+
+  hr = r_key.GetValueNameAt(0, &value_name, &type);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(value_name, kValNameInt);
+  ASSERT_EQ(type, REG_DWORD);
+
+  hr = r_key.GetValueNameAt(1, &value_name, &type);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(value_name, kValNameInt64);
+  ASSERT_EQ(type, REG_QWORD);
+
+  hr = r_key.GetValueNameAt(2, &value_name, &type);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(value_name, kValNameStr);
+  ASSERT_EQ(type, REG_SZ);
+
+  hr = r_key.GetValueNameAt(3, &value_name, &type);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(value_name, kValNameBinary);
+  ASSERT_EQ(type, REG_BINARY);
+
+  // check that there are no more values
+  hr = r_key.GetValueNameAt(4, &value_name, &type);
+  ASSERT_FAILED(hr);
+
+  uint32 subkey_count = r_key.GetSubkeyCount();
+  ASSERT_EQ(subkey_count, 0);
+
+  RegKey temp_key;
+
+  // now create a subkey and make sure we can get the name
+  hr = temp_key.Create(HKEY_CURRENT_USER, kRkey1Subkey);
+  ASSERT_SUCCEEDED(hr);
+
+  // check the subkey exists
+  bool_res = r_key.HasSubkey(kRkey1SubkeyName);
+  ASSERT_TRUE(bool_res);
+
+  // check the name
+  subkey_count = r_key.GetSubkeyCount();
+  ASSERT_EQ(subkey_count, 1);
+
+  CString subkey_name;
+  hr = r_key.GetSubkeyNameAt(0, &subkey_name);
+  ASSERT_EQ(subkey_name, kRkey1SubkeyName);
+
+  // verify that the event handle remained the same throughout everything
+  ASSERT_EQ(change_event, r_key.change_event());
+
+  // close this key
+  r_key.Close();
+
+  // whack the whole key
+  hr = RegKey::DeleteKey(kStRkey1);
+  ASSERT_SUCCEEDED(hr);
+
+  // STATIC
+  // now set a different value using the static versions
+
+  // get an in-existent value from an un-existent key
+  hr = RegKey::GetValue(kStRkey1, kStValNameInt, &int_val);
+  ASSERT_EQ(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+
+  // set int32
+  hr = RegKey::SetValue(kStRkey1, kStValNameInt, kStIntVal);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameInt);
+  ASSERT_TRUE(bool_res);
+
+  // get an in-existent value from an existent key
+  hr = RegKey::GetValue(kStRkey1, _T("bogus"), &int_val);
+  ASSERT_EQ(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+
+  // read it back
+  hr = RegKey::GetValue(kStRkey1, kStValNameInt, &int_val);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(int_val, kStIntVal);
+
+  // delete the value
+  hr = RegKey::DeleteValue(kStRkey1, kStValNameInt);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameInt);
+  ASSERT_FALSE(bool_res);
+
+
+  // set int64
+  hr = RegKey::SetValue(kStRkey1, kStValNameInt64, kStIntVal64);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameInt64);
+  ASSERT_TRUE(bool_res);
+
+  // read it back
+  hr = RegKey::GetValue(kStRkey1, kStValNameInt64, &int64_val);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(int64_val, kStIntVal64);
+
+  // read it back to test time64
+  bool limited_value;
+  hr = GetLimitedTimeValue(kStRkey1, kStValNameInt64,  kStIntVal64 + 10, &t,
+                           &limited_value);
+  ASSERT_SUCCEEDED(hr);
+  EXPECT_FALSE(limited_value);
+  ASSERT_EQ(t, kStIntVal64);
+  hr = GetLimitedTimeValue(kStRkey1, kStValNameInt64,  kStIntVal64 - 10, &t,
+                           &limited_value);
+  EXPECT_TRUE(limited_value);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(t, kStIntVal64 - 10);
+  // Verify that the GetValue permanently made the value lower
+  hr = GetLimitedTimeValue(kStRkey1, kStValNameInt64,  kStIntVal64, &t,
+                           &limited_value);
+  EXPECT_FALSE(limited_value);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(t, kStIntVal64 - 10);
+
+  // delete the value
+  hr = RegKey::DeleteValue(kStRkey1, kStValNameInt64);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameInt64);
+  ASSERT_FALSE(bool_res);
+
+  // set float
+  hr = RegKey::SetValue(kStRkey1, kStValNameFloat, kStFloatVal);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameFloat);
+  ASSERT_TRUE(bool_res);
+
+  // read it back
+  hr = RegKey::GetValue(kStRkey1, kStValNameFloat, &float_val);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(float_val, kStFloatVal);
+
+  // delete the value
+  hr = RegKey::DeleteValue(kStRkey1, kStValNameFloat);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameFloat);
+  ASSERT_FALSE(bool_res);
+  hr = RegKey::GetValue(kStRkey1, kStValNameFloat, &float_val);
+  ASSERT_FAILED(hr);
+
+
+  // set double
+  hr = RegKey::SetValue(kStRkey1, kStValNameDouble, kStDoubleVal);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameDouble);
+  ASSERT_TRUE(bool_res);
+
+  // read it back
+  hr = RegKey::GetValue(kStRkey1, kStValNameDouble, &double_val);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(double_val, kStDoubleVal);
+
+  // delete the value
+  hr = RegKey::DeleteValue(kStRkey1, kStValNameDouble);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameDouble);
+  ASSERT_FALSE(bool_res);
+  hr = RegKey::GetValue(kStRkey1, kStValNameDouble, &double_val);
+  ASSERT_FAILED(hr);
+
+  // set string
+  hr = RegKey::SetValue(kStRkey1, kStValNameStr, kStStrVal);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameStr);
+  ASSERT_TRUE(bool_res);
+
+  // read it back
+  hr = RegKey::GetValue(kStRkey1, kStValNameStr, &str_val);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_STREQ(str_val, kStStrVal);
+  delete [] str_val;
+
+  // get an in-existent value from an existent key
+  hr = RegKey::GetValue(kStRkey1, _T("bogus"), &str_val);
+  ASSERT_EQ(hr, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+
+  // delete the value
+  hr = RegKey::DeleteValue(kStRkey1, kStValNameStr);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameStr);
+  ASSERT_FALSE(bool_res);
+
+  // set binary
+  hr = RegKey::SetValue(kStRkey1, kStValNameBinary, (const byte *)kStBinaryVal,
+                        sizeof(kStBinaryVal)-1);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);
+  ASSERT_TRUE(bool_res);
+
+  // read it back
+  hr = RegKey::GetValue(kStRkey1, kStValNameBinary, &binary_val, &byte_count);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(0, memcmp(binary_val, kStBinaryVal, sizeof(kStBinaryVal)-1));
+  delete [] binary_val;
+
+  // delete the value
+  hr = RegKey::DeleteValue(kStRkey1, kStValNameBinary);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);
+  ASSERT_FALSE(bool_res);
+
+  // special case - set a binary value with length 0
+  hr = RegKey::SetValue(kStRkey1, kStValNameBinary,
+                        (const byte *)kStBinaryVal, 0);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);
+  ASSERT_TRUE(bool_res);
+
+  // read it back
+  hr = RegKey::GetValue(kStRkey1, kStValNameBinary, &binary_val, &byte_count);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(byte_count, 0);
+  ASSERT_TRUE(binary_val == NULL);
+  delete [] binary_val;
+
+  // delete the value
+  hr = RegKey::DeleteValue(kStRkey1, kStValNameBinary);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);
+  ASSERT_FALSE(bool_res);
+
+  // special case - set a NULL binary value
+  hr = RegKey::SetValue(kStRkey1, kStValNameBinary, NULL, 100);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value exists
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);
+  ASSERT_TRUE(bool_res);
+
+  // read it back
+  hr = RegKey::GetValue(kStRkey1, kStValNameBinary, &binary_val, &byte_count);
+  ASSERT_SUCCEEDED(hr);
+  ASSERT_EQ(byte_count, 0);
+  ASSERT_TRUE(binary_val == NULL);
+  delete [] binary_val;
+
+  // delete the value
+  hr = RegKey::DeleteValue(kStRkey1, kStValNameBinary);
+  ASSERT_SUCCEEDED(hr);
+
+  // check that the value is gone
+  bool_res = RegKey::HasValue(kStRkey1, kStValNameBinary);
+  ASSERT_FALSE(bool_res);
+
+  // whack the whole key
+
+  hr = RegKey::DeleteKey(kStRkey1);
+  ASSERT_SUCCEEDED(hr);
+}
+
+// RegKey::GetValue changes the output CString when errors occur.
+TEST_F(RegKeyTestClass, ChangesStringOnErrors) {
+  CString string_val = _T("foo");
+  EXPECT_FAILED(RegKey::GetValue(_T("HCKU"), _T("no_such_value"), &string_val));
+  ASSERT_TRUE(string_val.IsEmpty());
+}
+
+TEST(RegKeyTest, CreateKeys) {
+  RegKey::DeleteKey(kStRkey1);
+  RegKey::DeleteKey(kStRkey2);
+  RegKey::DeleteKey(kStRkey3);
+  EXPECT_FALSE(RegKey::HasKey(kStRkey1));
+  EXPECT_FALSE(RegKey::HasKey(kStRkey2));
+  EXPECT_FALSE(RegKey::HasKey(kStRkey3));
+
+  // 3 keys specified but the count is two.
+  const TCHAR* keys[] = {kStRkey1, kStRkey2, kStRkey3};
+  ASSERT_SUCCEEDED(RegKey::CreateKeys(keys, 2));
+
+  EXPECT_TRUE(RegKey::HasKey(kStRkey1));
+  EXPECT_TRUE(RegKey::HasKey(kStRkey2));
+  EXPECT_FALSE(RegKey::HasKey(kStRkey3));
+
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey1));
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey2));
+}
+
+TEST(RegKeyTest, CreateKey) {
+  RegKey::DeleteKey(kStRkey1);
+  EXPECT_FALSE(RegKey::HasKey(kStRkey1));
+
+  ASSERT_SUCCEEDED(RegKey::CreateKey(kStRkey1));
+
+  EXPECT_TRUE(RegKey::HasKey(kStRkey1));
+
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey1));
+}
+
+TEST(RegKeyTest, RenameValue) {
+  RegKey reg_key;
+  ASSERT_SUCCEEDED(reg_key.Create(HKEY_CURRENT_USER, kRkey1));
+  ASSERT_SUCCEEDED(reg_key.SetValue(kValNameInt, kIntVal));
+  ASSERT_TRUE(reg_key.HasValue(kValNameInt));
+
+  ASSERT_SUCCEEDED(reg_key.RenameValue(kValNameInt, kRenameValNameInt));
+  ASSERT_FALSE(reg_key.HasValue(kValNameInt));
+
+  DWORD int_val = 0;
+  EXPECT_SUCCEEDED(reg_key.GetValue(kRenameValNameInt, &int_val));
+  EXPECT_EQ(kIntVal, int_val);
+
+  EXPECT_SUCCEEDED(reg_key.Close());
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey1));
+}
+
+TEST(RegKeyTest, RenameValueStatic) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kStRkey1, kStValNameStr, kStStrVal));
+  ASSERT_TRUE(RegKey::HasValue(kStRkey1, kStValNameStr));
+
+  RegKey::RenameValue(kStRkey1, kStValNameStr, kRenameStValNameStr);
+  ASSERT_FALSE(RegKey::HasValue(kStRkey1, kStValNameStr));
+
+  CString str_val;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kStRkey1, kRenameStValNameStr, &str_val));
+  EXPECT_STREQ(kStStrVal, str_val);
+
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey1));
+}
+
+TEST(RegKeyTest, CopyValue) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kStRkey1, kStValNameStr, kStStrVal));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kStRkey1, NULL, kStStrVal));
+  EXPECT_TRUE(RegKey::HasValue(kStRkey1, kStValNameStr));
+
+  // Test that CopyValue fails when the to_key does not exist.
+  EXPECT_FALSE(RegKey::HasKey(kStRkey2));
+  EXPECT_FAILED(RegKey::CopyValue(kStRkey1, kStRkey2, kStValNameStr));
+  EXPECT_FALSE(RegKey::HasKey(kStRkey2));
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kStRkey2));
+  // Test CopyValue(full_from_key_name, full_to_key_name, value_name).
+  EXPECT_FALSE(RegKey::HasValue(kStRkey2, kStValNameStr));
+  RegKey::CopyValue(kStRkey1, kStRkey2, kStValNameStr);
+  CString str_val;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kStRkey2, kStValNameStr, &str_val));
+  EXPECT_STREQ(kStStrVal, str_val);
+
+  // Test CopyValue to a (Default) value.
+  EXPECT_FALSE(RegKey::HasValue(kStRkey2, NULL));
+  RegKey::CopyValue(kStRkey1, kStRkey2, NULL);
+  str_val.Empty();
+  EXPECT_SUCCEEDED(RegKey::GetValue(kStRkey2, NULL, &str_val));
+  EXPECT_STREQ(kStStrVal, str_val);
+
+  // Test CopyValue(full_from_key_name, from_value_name, full_to_key_name,
+  //                to_value_name).
+  EXPECT_FALSE(RegKey::HasValue(kStRkey2, kRenameStValNameStr));
+  RegKey::CopyValue(kStRkey1, kStValNameStr, kStRkey2, kRenameStValNameStr);
+  str_val.Empty();
+  EXPECT_SUCCEEDED(RegKey::GetValue(kStRkey2, kRenameStValNameStr, &str_val));
+  EXPECT_STREQ(kStStrVal, str_val);
+
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey1));
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kStRkey2));
+}
+
+}  // namespace omaha
+
diff --git a/common/regexp.cc b/common/regexp.cc
index 2006fa1..a79889e 100644
--- a/common/regexp.cc
+++ b/common/regexp.cc
@@ -1,146 +1,146 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "regexp.h"

-#include "common/debug.h"

-

-namespace omaha {

-

-#define kMaxArgs 16

-

-bool RE::PartialMatch(const TCHAR* text, const RE& re,  // 3..16 args

-                      CString * a0,

-                      CString * a1,

-                      CString * a2,

-                      CString * a3,

-                      CString * a4,

-                      CString * a5,

-                      CString * a6,

-                      CString * a7,

-                      CString * a8,

-                      CString * a9,

-                      CString * a10,

-                      CString * a11,

-                      CString * a12,

-                      CString * a13,

-                      CString * a14,

-                      CString * a15)

-{

-  ASSERT(text, (L""));

-  // a0 may be NULL

-  // a1 may be NULL

-  // a2 may be NULL

-  // a3 may be NULL

-  // a4 may be NULL

-  // a5 may be NULL

-  // a6 may be NULL

-  // a7 may be NULL

-  // a8 may be NULL

-  // a9 may be NULL

-  // a10 may be NULL

-  // a11 may be NULL

-  // a12 may be NULL

-  // a13 may be NULL

-  // a14 may be NULL

-  // a15 may be NULL

-

-  CString * args[kMaxArgs];

-  int n = 0;

-  if (a0 == NULL) goto done; args[n++] = a0;

-  if (a1 == NULL) goto done; args[n++] = a1;

-  if (a2 == NULL) goto done; args[n++] = a2;

-  if (a3 == NULL) goto done; args[n++] = a3;

-  if (a4 == NULL) goto done; args[n++] = a4;

-  if (a5 == NULL) goto done; args[n++] = a5;

-  if (a6 == NULL) goto done; args[n++] = a6;

-  if (a7 == NULL) goto done; args[n++] = a7;

-  if (a8 == NULL) goto done; args[n++] = a8;

-  if (a9 == NULL) goto done; args[n++] = a9;

-  if (a10 == NULL) goto done; args[n++] = a10;

-  if (a11 == NULL) goto done; args[n++] = a11;

-  if (a12 == NULL) goto done; args[n++] = a12;

-  if (a13 == NULL) goto done; args[n++] = a13;

-  if (a14 == NULL) goto done; args[n++] = a14;

-  if (a15 == NULL) goto done; args[n++] = a15;

-

-done:

-  return re.DoMatchImpl(text,args,n,NULL);

-}

-

-// Like PartialMatch(), except the "input" is advanced past the matched

-// text.  Note: "input" is modified iff this routine returns true.

-// For example, "FindAndConsume(s, "(\\w+)", &word)" finds the next

-// word in "s" and stores it in "word".

-bool RE::FindAndConsume(const TCHAR **input, const RE& re,

-                        CString * a0,

-                        CString * a1,

-                        CString * a2,

-                        CString * a3,

-                        CString * a4,

-                        CString * a5,

-                        CString * a6,

-                        CString * a7,

-                        CString * a8,

-                        CString * a9,

-                        CString * a10,

-                        CString * a11,

-                        CString * a12,

-                        CString * a13,

-                        CString * a14,

-                        CString * a15)

-{

-  ASSERT(input, (L""));

-  // a0 may be NULL

-  // a1 may be NULL

-  // a2 may be NULL

-  // a3 may be NULL

-  // a4 may be NULL

-  // a5 may be NULL

-  // a6 may be NULL

-  // a7 may be NULL

-  // a8 may be NULL

-  // a9 may be NULL

-  // a10 may be NULL

-  // a11 may be NULL

-  // a12 may be NULL

-  // a13 may be NULL

-  // a14 may be NULL

-  // a15 may be NULL

-

-  CString * args[kMaxArgs];

-  int n = 0;

-  if (a0 == NULL) goto done; args[n++] = a0;

-  if (a1 == NULL) goto done; args[n++] = a1;

-  if (a2 == NULL) goto done; args[n++] = a2;

-  if (a3 == NULL) goto done; args[n++] = a3;

-  if (a4 == NULL) goto done; args[n++] = a4;

-  if (a5 == NULL) goto done; args[n++] = a5;

-  if (a6 == NULL) goto done; args[n++] = a6;

-  if (a7 == NULL) goto done; args[n++] = a7;

-  if (a8 == NULL) goto done; args[n++] = a8;

-  if (a9 == NULL) goto done; args[n++] = a9;

-  if (a10 == NULL) goto done; args[n++] = a10;

-  if (a11 == NULL) goto done; args[n++] = a11;

-  if (a12 == NULL) goto done; args[n++] = a12;

-  if (a13 == NULL) goto done; args[n++] = a13;

-  if (a14 == NULL) goto done; args[n++] = a14;

-  if (a15 == NULL) goto done; args[n++] = a15;

-

-done:

-  return re.DoMatchImpl(*input,args,n,input);

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "regexp.h"
+#include "common/debug.h"
+
+namespace omaha {
+
+#define kMaxArgs 16
+
+bool RE::PartialMatch(const TCHAR* text, const RE& re,  // 3..16 args
+                      CString * a0,
+                      CString * a1,
+                      CString * a2,
+                      CString * a3,
+                      CString * a4,
+                      CString * a5,
+                      CString * a6,
+                      CString * a7,
+                      CString * a8,
+                      CString * a9,
+                      CString * a10,
+                      CString * a11,
+                      CString * a12,
+                      CString * a13,
+                      CString * a14,
+                      CString * a15)
+{
+  ASSERT(text, (L""));
+  // a0 may be NULL
+  // a1 may be NULL
+  // a2 may be NULL
+  // a3 may be NULL
+  // a4 may be NULL
+  // a5 may be NULL
+  // a6 may be NULL
+  // a7 may be NULL
+  // a8 may be NULL
+  // a9 may be NULL
+  // a10 may be NULL
+  // a11 may be NULL
+  // a12 may be NULL
+  // a13 may be NULL
+  // a14 may be NULL
+  // a15 may be NULL
+
+  CString * args[kMaxArgs];
+  int n = 0;
+  if (a0 == NULL) goto done; args[n++] = a0;
+  if (a1 == NULL) goto done; args[n++] = a1;
+  if (a2 == NULL) goto done; args[n++] = a2;
+  if (a3 == NULL) goto done; args[n++] = a3;
+  if (a4 == NULL) goto done; args[n++] = a4;
+  if (a5 == NULL) goto done; args[n++] = a5;
+  if (a6 == NULL) goto done; args[n++] = a6;
+  if (a7 == NULL) goto done; args[n++] = a7;
+  if (a8 == NULL) goto done; args[n++] = a8;
+  if (a9 == NULL) goto done; args[n++] = a9;
+  if (a10 == NULL) goto done; args[n++] = a10;
+  if (a11 == NULL) goto done; args[n++] = a11;
+  if (a12 == NULL) goto done; args[n++] = a12;
+  if (a13 == NULL) goto done; args[n++] = a13;
+  if (a14 == NULL) goto done; args[n++] = a14;
+  if (a15 == NULL) goto done; args[n++] = a15;
+
+done:
+  return re.DoMatchImpl(text,args,n,NULL);
+}
+
+// Like PartialMatch(), except the "input" is advanced past the matched
+// text.  Note: "input" is modified iff this routine returns true.
+// For example, "FindAndConsume(s, "(\\w+)", &word)" finds the next
+// word in "s" and stores it in "word".
+bool RE::FindAndConsume(const TCHAR **input, const RE& re,
+                        CString * a0,
+                        CString * a1,
+                        CString * a2,
+                        CString * a3,
+                        CString * a4,
+                        CString * a5,
+                        CString * a6,
+                        CString * a7,
+                        CString * a8,
+                        CString * a9,
+                        CString * a10,
+                        CString * a11,
+                        CString * a12,
+                        CString * a13,
+                        CString * a14,
+                        CString * a15)
+{
+  ASSERT(input, (L""));
+  // a0 may be NULL
+  // a1 may be NULL
+  // a2 may be NULL
+  // a3 may be NULL
+  // a4 may be NULL
+  // a5 may be NULL
+  // a6 may be NULL
+  // a7 may be NULL
+  // a8 may be NULL
+  // a9 may be NULL
+  // a10 may be NULL
+  // a11 may be NULL
+  // a12 may be NULL
+  // a13 may be NULL
+  // a14 may be NULL
+  // a15 may be NULL
+
+  CString * args[kMaxArgs];
+  int n = 0;
+  if (a0 == NULL) goto done; args[n++] = a0;
+  if (a1 == NULL) goto done; args[n++] = a1;
+  if (a2 == NULL) goto done; args[n++] = a2;
+  if (a3 == NULL) goto done; args[n++] = a3;
+  if (a4 == NULL) goto done; args[n++] = a4;
+  if (a5 == NULL) goto done; args[n++] = a5;
+  if (a6 == NULL) goto done; args[n++] = a6;
+  if (a7 == NULL) goto done; args[n++] = a7;
+  if (a8 == NULL) goto done; args[n++] = a8;
+  if (a9 == NULL) goto done; args[n++] = a9;
+  if (a10 == NULL) goto done; args[n++] = a10;
+  if (a11 == NULL) goto done; args[n++] = a11;
+  if (a12 == NULL) goto done; args[n++] = a12;
+  if (a13 == NULL) goto done; args[n++] = a13;
+  if (a14 == NULL) goto done; args[n++] = a14;
+  if (a15 == NULL) goto done; args[n++] = a15;
+
+done:
+  return re.DoMatchImpl(*input,args,n,input);
+}
+
+}  // namespace omaha
+
diff --git a/common/regexp.h b/common/regexp.h
index b59d188..25781c1 100644
--- a/common/regexp.h
+++ b/common/regexp.h
@@ -1,103 +1,103 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Implementors: There is only one function to implement -- DoMatchImpl

-// See below

-

-#ifndef OMAHA_COMMON_REGEXP_H__

-#define OMAHA_COMMON_REGEXP_H__

-

-#include <atlstr.h>

-

-namespace omaha {

-

-// Interface for regular expression matching.  Also corresponds to a

-// pre-compiled regular expression.  An "RE" object is safe for

-// concurrent use by multiple threads.

-class RE {

- public:

-

-  // Matches "text" against "pattern".  If pointer arguments are

-  // supplied, copies matched sub-patterns into them. Use braces

-  // "{", "}" within the regexp to indicate a pattern to be copied.

-  //

-  // Returns true iff all of the following conditions are satisfied:

-  //   a. some substring of "text" matches "pattern"

-  //   b. The number of matched sub-patterns is >= number of supplied pointers

-  static bool PartialMatch(const TCHAR* text, const RE& re, // 3..16 args

-    CString * a0 = NULL,

-    CString * a1 = NULL,

-    CString * a2 = NULL,

-    CString * a3 = NULL,

-    CString * a4 = NULL,

-    CString * a5 = NULL,

-    CString * a6 = NULL,

-    CString * a7 = NULL,

-    CString * a8 = NULL,

-    CString * a9 = NULL,

-    CString * a10 = NULL,

-    CString * a11 = NULL,

-    CString * a12 = NULL,

-    CString * a13 = NULL,

-    CString * a14 = NULL,

-    CString * a15 = NULL);

-

-  // Like PartialMatch(), except the "input" is advanced past the matched

-  // text.  Note: "input" is modified iff this routine returns true.

-  // For example, "FindAndConsume(s, "{\\w+}", &word)" finds the next

-  // word in "s" and stores it in "word".

-  static bool FindAndConsume(const TCHAR** input, const RE& re,

-    CString * a0 = NULL,

-    CString * a1 = NULL,

-    CString * a2 = NULL,

-    CString * a3 = NULL,

-    CString * a4 = NULL,

-    CString * a5 = NULL,

-    CString * a6 = NULL,

-    CString * a7 = NULL,

-    CString * a8 = NULL,

-    CString * a9 = NULL,

-    CString * a10 = NULL,

-    CString * a11 = NULL,

-    CString * a12 = NULL,

-    CString * a13 = NULL,

-    CString * a14 = NULL,

-    CString * a15 = NULL);

-

- protected:

-

-  // The behavior of this function is subject to how it's used

-  // in PartialMatch() and FindAndConsume() above. See the header

-  // description of those functions to understand how an implementation

-  // should behave.

-  // text is the text we're looking in

-  // args is where matches should be outputted

-  // n is the number of CStrings in args

-  // match_end is a pointer to the position in text that

-  // we ended matching on

-  // returns true if data was found, false otherwise

-  // Example:Suppose text = "google 1\nYahoo! 2\n ..." and the regexp

-  // is something like "{\w+} \d". If args has two CStrings (n=2),

-  // then args[0] = "google", arg[1] = "1" and match_end will point to the \n

-  // before "Yahoo!"

-  virtual bool DoMatchImpl(const TCHAR *text,

-    CString * args[],

-    int n,

-    const TCHAR ** match_end) const = 0;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_REGEXP_H__

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Implementors: There is only one function to implement -- DoMatchImpl
+// See below
+
+#ifndef OMAHA_COMMON_REGEXP_H__
+#define OMAHA_COMMON_REGEXP_H__
+
+#include <atlstr.h>
+
+namespace omaha {
+
+// Interface for regular expression matching.  Also corresponds to a
+// pre-compiled regular expression.  An "RE" object is safe for
+// concurrent use by multiple threads.
+class RE {
+ public:
+
+  // Matches "text" against "pattern".  If pointer arguments are
+  // supplied, copies matched sub-patterns into them. Use braces
+  // "{", "}" within the regexp to indicate a pattern to be copied.
+  //
+  // Returns true iff all of the following conditions are satisfied:
+  //   a. some substring of "text" matches "pattern"
+  //   b. The number of matched sub-patterns is >= number of supplied pointers
+  static bool PartialMatch(const TCHAR* text, const RE& re, // 3..16 args
+    CString * a0 = NULL,
+    CString * a1 = NULL,
+    CString * a2 = NULL,
+    CString * a3 = NULL,
+    CString * a4 = NULL,
+    CString * a5 = NULL,
+    CString * a6 = NULL,
+    CString * a7 = NULL,
+    CString * a8 = NULL,
+    CString * a9 = NULL,
+    CString * a10 = NULL,
+    CString * a11 = NULL,
+    CString * a12 = NULL,
+    CString * a13 = NULL,
+    CString * a14 = NULL,
+    CString * a15 = NULL);
+
+  // Like PartialMatch(), except the "input" is advanced past the matched
+  // text.  Note: "input" is modified iff this routine returns true.
+  // For example, "FindAndConsume(s, "{\\w+}", &word)" finds the next
+  // word in "s" and stores it in "word".
+  static bool FindAndConsume(const TCHAR** input, const RE& re,
+    CString * a0 = NULL,
+    CString * a1 = NULL,
+    CString * a2 = NULL,
+    CString * a3 = NULL,
+    CString * a4 = NULL,
+    CString * a5 = NULL,
+    CString * a6 = NULL,
+    CString * a7 = NULL,
+    CString * a8 = NULL,
+    CString * a9 = NULL,
+    CString * a10 = NULL,
+    CString * a11 = NULL,
+    CString * a12 = NULL,
+    CString * a13 = NULL,
+    CString * a14 = NULL,
+    CString * a15 = NULL);
+
+ protected:
+
+  // The behavior of this function is subject to how it's used
+  // in PartialMatch() and FindAndConsume() above. See the header
+  // description of those functions to understand how an implementation
+  // should behave.
+  // text is the text we're looking in
+  // args is where matches should be outputted
+  // n is the number of CStrings in args
+  // match_end is a pointer to the position in text that
+  // we ended matching on
+  // returns true if data was found, false otherwise
+  // Example:Suppose text = "google 1\nYahoo! 2\n ..." and the regexp
+  // is something like "{\w+} \d". If args has two CStrings (n=2),
+  // then args[0] = "google", arg[1] = "1" and match_end will point to the \n
+  // before "Yahoo!"
+  virtual bool DoMatchImpl(const TCHAR *text,
+    CString * args[],
+    int n,
+    const TCHAR ** match_end) const = 0;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_REGEXP_H__
diff --git a/common/registry_hive.cc b/common/registry_hive.cc
index 32a0d64..69458ed 100644
--- a/common/registry_hive.cc
+++ b/common/registry_hive.cc
@@ -1,268 +1,268 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/registry_hive.h"

-#include "omaha/common/accounts.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-RegistryHive::RegistryHive()

-    : hive_holding_key_(NULL) {

-}

-

-RegistryHive::~RegistryHive() {

-  if ( !hive_name_.IsEmpty() ) {

-    UnloadHive();

-  }

-}

-

-// Loads hive for requested SID. SID should be in format "S-X-X....."

-// name is a name under which the hive will be added to the HKEY_USERS,

-// you could use persons name here. This parameter should not have '\\'

-// characters!

-// It is not recommended to load more than one hive at once - LoadHive,

-// manipulate hive, UnloadHive, and then work on the next one.

-//

-// Hive could be already loaded: you logged out from other user but system

-// had open key in your current user. In that case I open hive_holding_key_ to

-// prevent system from unloading hive and do not load/unload hive - the system

-// will do it.

-HRESULT RegistryHive::LoadHive(TCHAR const * sid, TCHAR const *name) {

-  ASSERT1(sid);

-  ASSERT1(name);

-  ASSERT1(hive_name_.IsEmpty());

-  ASSERT1(String_FindChar(name, _T('\\')) == -1);

-

-  CString profile_key;

-  CString hive_path;

-

-  // Need set SE_RESTORE_NAME/SE_BACKUP_NAME priveleges to current process

-  // otherwise loading of the hive will fail

-  RET_IF_FAILED(System::AdjustPrivilege(SE_RESTORE_NAME, true));

-  RET_IF_FAILED(System::AdjustPrivilege(SE_BACKUP_NAME, true));

-

-  profile_key.Format(kProfileKeyFormat, sid);

-

-  if ( FAILED(RegKey::GetValue(profile_key, kProfilePathValue, &hive_path)) ) {

-    return E_FAIL;

-  }

-

-

-  wchar_t temporary_buffer[MAX_PATH];

-  DWORD ret = ExpandEnvironmentStrings(hive_path, temporary_buffer, MAX_PATH);

-

-  if ( !ret || ret >= MAX_PATH ) {

-    return E_FAIL;

-  }

-  hive_path = temporary_buffer;

-

-  hive_path.Append(_T("\\"));

-  hive_path.Append(kHiveName);

-

-  hive_name_ = name;

-

-  LONG res = RegLoadKey(HKEY_USERS, hive_name_, hive_path);

-

-  if ( ERROR_SHARING_VIOLATION == res ) {

-    // It is quite possible that the hive is still held by system.

-    hive_name_ = sid;

-

-    // if it is the case, this call will succeeed, and the system will not

-    // unload the hive while there are outstanding keys opened.

-    res = RegOpenKeyEx(HKEY_USERS,

-                       hive_name_,

-                       0,

-                       KEY_ALL_ACCESS,

-                       &hive_holding_key_);

-  }

-

-  return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;

-}

-

-// Loads hive for requested SID, but only if the SID is another user

-// (since we don't need to do anything if the sid is ours)

-HRESULT RegistryHive::LoadHive(TCHAR const * user_sid) {

-  ASSERT1(user_sid != NULL);

-  bool other_user = false;

-

-  // Determine if the SID passed in is really another user

-  CString current_user_sid;

-  HRESULT hr = omaha::user_info::GetCurrentUser(NULL, NULL, &current_user_sid);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[RegistryHive::LoadHive - failed to get current user")));

-    return hr;

-  }

-

-  // user_sid is the current user - no need to load the hive

-  if (lstrcmpi(current_user_sid, user_sid) == 0)

-    return S_FALSE;

-

-  // Get info on the sid we're being asked to load for

-  CString name;

-  CString domain;

-  SID_NAME_USE user_type;

-  hr = accounts::GetUserInfo(user_sid, &name, &domain, &user_type);

-  if ( FAILED(hr) || user_type != SidTypeUser ) {

-    // Either Sid no longer exists or Sid is not a user Sid

-    // (There is other possibility: Sid could be for roaming profile on domain

-    // which is currently down, but we do not support roaming profiles)

-    return FAILED(hr) ? hr : E_FAIL;

-  }

-

-  hr = LoadHive(user_sid, name);  // Use user name as a temporary key name.

-  if ( FAILED(hr) ) {

-    // Hive no longer present.

-    return E_FAIL;

-  }

-

-  return S_OK;

-}

-

-

-// Unloads and saves loaded hive

-HRESULT RegistryHive::UnloadHive() {

-  if (hive_name_.IsEmpty())

-    return S_OK;

-

-  LONG res;

-  if ( hive_holding_key_ ) {

-    res = RegCloseKey(hive_holding_key_);

-    hive_holding_key_ = NULL;

-    // no need to unload hive. System will do it.

-  } else {

-    res = RegUnLoadKey(HKEY_USERS, hive_name_);

-  }

-  hive_name_.Empty();

-  return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;

-}

-

-// Does it recursively. The name should be relative to HKEY_CURRENT_USER.

-HRESULT RegistryHive::DeleteUserKey(TCHAR const * key_name) {

-  ASSERT(key_name && *key_name, (L""));

-  if ( !key_name || !*key_name ) {

-    return E_FAIL;

-  }

-  CString key(key_name);

-  ExpandKeyName(&key);

-

-  if ( !RegKey::SafeKeyNameForDeletion(key) ) {

-    return E_FAIL;

-  }

-

-  return RegKey::DeleteKey(key);

-}

-

-void RegistryHive::ExpandKeyName(CString * str) {

-  ASSERT1(str);

-

-  // If we haven't loaded another user's hive, use HKCU instead of

-  // HKEY_USERS

-  CString key_name;

-  if (hive_name_.IsEmpty()) {

-    key_name = _T("HKCU\\");

-  } else {

-    key_name = _T("HKEY_USERS\\");

-    key_name.Append(hive_name_ + _T("\\"));

-  }

-

-  key_name.Append(*str);

-  *str = key_name;

-}

-

-// Load a user registry

-int LoadUserRegistry(const TCHAR* user_sid,

-                     ProcessUserRegistryFunc* handler,

-                     LONG_PTR param) {

-  ASSERT1(user_sid && *user_sid);

-  ASSERT1(handler);

-

-  // Get current user SID

-  CString curr_user_sid;

-  HRESULT hr = omaha::user_info::GetCurrentUser(NULL, NULL, &curr_user_sid);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[LoadUserRegistry - can't get current user][0x%x]"), hr));

-    return 0;

-  }

-

-  // Is current user?

-  bool other_user = curr_user_sid.CompareNoCase(user_sid) != 0;

-

-  // Get the hive for this user

-  RegistryHive user_hive;

-  if (other_user) {

-    // Get the info about this user

-    SID_NAME_USE user_type = SidTypeInvalid;

-    CString name, domain;

-    hr = accounts::GetUserInfo(user_sid, &name, &domain, &user_type);

-    if (FAILED(hr) || user_type != SidTypeUser) {

-      // Either SID no longer exists or SID is not a user Sid

-      // (There is other possibility: SID could be for roaming profile on domain

-      // which is currently down, but we do not support roaming profiles)

-      UTIL_LOG(LEVEL_WARNING,

-               (_T("[LoadUserRegistry - SID %s invalid or unsupported][0x%x]"),

-                user_sid, hr));

-      return 0;

-    }

-

-    // Load the hive

-    hr = user_hive.LoadHive(user_sid, domain + _T("_") + name);

-    if (FAILED(hr)) {

-      // Hive no longer present.

-      UTIL_LOG(LW, (_T("[LoadUserRegistry]")

-                    _T("[hive not present for %s][0x%x]"), user_sid, hr));

-      return 0;

-    }

-  }

-

-  // Get the registry key path

-  CString user_reg_path;

-  user_hive.ExpandKeyName(&user_reg_path);

-

-  // Call the handler

-  int res = (*handler)(user_sid, user_reg_path, param);

-

-  // Unload the hive

-  if (other_user) {

-    hr = user_hive.UnloadHive();

-    if (FAILED(hr)) {

-      UTIL_LOG(LE, (_T("[LoadUserRegistry]")

-                    _T("[failed to save hive for %s][0x%x]"), user_sid, hr));

-    }

-  }

-

-  return res;

-}

-

-// Enumerate all user registries

-void EnumerateAllUserRegistries(ProcessUserRegistryFunc* handler,

-                                LONG_PTR param) {

-  ASSERT1(handler);

-

-  CSimpleArray<CString> sid_array;

-  accounts::GetAllUserSids(&sid_array);

-  for (int i = 0 ; i < sid_array.GetSize() ; ++i) {

-    if (LoadUserRegistry(sid_array[i], handler, param)) {

-      return;

-    }

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/registry_hive.h"
+#include "omaha/common/accounts.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+RegistryHive::RegistryHive()
+    : hive_holding_key_(NULL) {
+}
+
+RegistryHive::~RegistryHive() {
+  if ( !hive_name_.IsEmpty() ) {
+    UnloadHive();
+  }
+}
+
+// Loads hive for requested SID. SID should be in format "S-X-X....."
+// name is a name under which the hive will be added to the HKEY_USERS,
+// you could use persons name here. This parameter should not have '\\'
+// characters!
+// It is not recommended to load more than one hive at once - LoadHive,
+// manipulate hive, UnloadHive, and then work on the next one.
+//
+// Hive could be already loaded: you logged out from other user but system
+// had open key in your current user. In that case I open hive_holding_key_ to
+// prevent system from unloading hive and do not load/unload hive - the system
+// will do it.
+HRESULT RegistryHive::LoadHive(TCHAR const * sid, TCHAR const *name) {
+  ASSERT1(sid);
+  ASSERT1(name);
+  ASSERT1(hive_name_.IsEmpty());
+  ASSERT1(String_FindChar(name, _T('\\')) == -1);
+
+  CString profile_key;
+  CString hive_path;
+
+  // Need set SE_RESTORE_NAME/SE_BACKUP_NAME priveleges to current process
+  // otherwise loading of the hive will fail
+  RET_IF_FAILED(System::AdjustPrivilege(SE_RESTORE_NAME, true));
+  RET_IF_FAILED(System::AdjustPrivilege(SE_BACKUP_NAME, true));
+
+  profile_key.Format(kProfileKeyFormat, sid);
+
+  if ( FAILED(RegKey::GetValue(profile_key, kProfilePathValue, &hive_path)) ) {
+    return E_FAIL;
+  }
+
+
+  wchar_t temporary_buffer[MAX_PATH];
+  DWORD ret = ExpandEnvironmentStrings(hive_path, temporary_buffer, MAX_PATH);
+
+  if ( !ret || ret >= MAX_PATH ) {
+    return E_FAIL;
+  }
+  hive_path = temporary_buffer;
+
+  hive_path.Append(_T("\\"));
+  hive_path.Append(kHiveName);
+
+  hive_name_ = name;
+
+  LONG res = RegLoadKey(HKEY_USERS, hive_name_, hive_path);
+
+  if ( ERROR_SHARING_VIOLATION == res ) {
+    // It is quite possible that the hive is still held by system.
+    hive_name_ = sid;
+
+    // if it is the case, this call will succeeed, and the system will not
+    // unload the hive while there are outstanding keys opened.
+    res = RegOpenKeyEx(HKEY_USERS,
+                       hive_name_,
+                       0,
+                       KEY_ALL_ACCESS,
+                       &hive_holding_key_);
+  }
+
+  return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
+}
+
+// Loads hive for requested SID, but only if the SID is another user
+// (since we don't need to do anything if the sid is ours)
+HRESULT RegistryHive::LoadHive(TCHAR const * user_sid) {
+  ASSERT1(user_sid != NULL);
+  bool other_user = false;
+
+  // Determine if the SID passed in is really another user
+  CString current_user_sid;
+  HRESULT hr = omaha::user_info::GetCurrentUser(NULL, NULL, &current_user_sid);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[RegistryHive::LoadHive - failed to get current user")));
+    return hr;
+  }
+
+  // user_sid is the current user - no need to load the hive
+  if (lstrcmpi(current_user_sid, user_sid) == 0)
+    return S_FALSE;
+
+  // Get info on the sid we're being asked to load for
+  CString name;
+  CString domain;
+  SID_NAME_USE user_type;
+  hr = accounts::GetUserInfo(user_sid, &name, &domain, &user_type);
+  if ( FAILED(hr) || user_type != SidTypeUser ) {
+    // Either Sid no longer exists or Sid is not a user Sid
+    // (There is other possibility: Sid could be for roaming profile on domain
+    // which is currently down, but we do not support roaming profiles)
+    return FAILED(hr) ? hr : E_FAIL;
+  }
+
+  hr = LoadHive(user_sid, name);  // Use user name as a temporary key name.
+  if ( FAILED(hr) ) {
+    // Hive no longer present.
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+
+// Unloads and saves loaded hive
+HRESULT RegistryHive::UnloadHive() {
+  if (hive_name_.IsEmpty())
+    return S_OK;
+
+  LONG res;
+  if ( hive_holding_key_ ) {
+    res = RegCloseKey(hive_holding_key_);
+    hive_holding_key_ = NULL;
+    // no need to unload hive. System will do it.
+  } else {
+    res = RegUnLoadKey(HKEY_USERS, hive_name_);
+  }
+  hive_name_.Empty();
+  return (res == ERROR_SUCCESS) ? S_OK : E_FAIL;
+}
+
+// Does it recursively. The name should be relative to HKEY_CURRENT_USER.
+HRESULT RegistryHive::DeleteUserKey(TCHAR const * key_name) {
+  ASSERT(key_name && *key_name, (L""));
+  if ( !key_name || !*key_name ) {
+    return E_FAIL;
+  }
+  CString key(key_name);
+  ExpandKeyName(&key);
+
+  if ( !RegKey::SafeKeyNameForDeletion(key) ) {
+    return E_FAIL;
+  }
+
+  return RegKey::DeleteKey(key);
+}
+
+void RegistryHive::ExpandKeyName(CString * str) {
+  ASSERT1(str);
+
+  // If we haven't loaded another user's hive, use HKCU instead of
+  // HKEY_USERS
+  CString key_name;
+  if (hive_name_.IsEmpty()) {
+    key_name = _T("HKCU\\");
+  } else {
+    key_name = _T("HKEY_USERS\\");
+    key_name.Append(hive_name_ + _T("\\"));
+  }
+
+  key_name.Append(*str);
+  *str = key_name;
+}
+
+// Load a user registry
+int LoadUserRegistry(const TCHAR* user_sid,
+                     ProcessUserRegistryFunc* handler,
+                     LONG_PTR param) {
+  ASSERT1(user_sid && *user_sid);
+  ASSERT1(handler);
+
+  // Get current user SID
+  CString curr_user_sid;
+  HRESULT hr = omaha::user_info::GetCurrentUser(NULL, NULL, &curr_user_sid);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[LoadUserRegistry - can't get current user][0x%x]"), hr));
+    return 0;
+  }
+
+  // Is current user?
+  bool other_user = curr_user_sid.CompareNoCase(user_sid) != 0;
+
+  // Get the hive for this user
+  RegistryHive user_hive;
+  if (other_user) {
+    // Get the info about this user
+    SID_NAME_USE user_type = SidTypeInvalid;
+    CString name, domain;
+    hr = accounts::GetUserInfo(user_sid, &name, &domain, &user_type);
+    if (FAILED(hr) || user_type != SidTypeUser) {
+      // Either SID no longer exists or SID is not a user Sid
+      // (There is other possibility: SID could be for roaming profile on domain
+      // which is currently down, but we do not support roaming profiles)
+      UTIL_LOG(LEVEL_WARNING,
+               (_T("[LoadUserRegistry - SID %s invalid or unsupported][0x%x]"),
+                user_sid, hr));
+      return 0;
+    }
+
+    // Load the hive
+    hr = user_hive.LoadHive(user_sid, domain + _T("_") + name);
+    if (FAILED(hr)) {
+      // Hive no longer present.
+      UTIL_LOG(LW, (_T("[LoadUserRegistry]")
+                    _T("[hive not present for %s][0x%x]"), user_sid, hr));
+      return 0;
+    }
+  }
+
+  // Get the registry key path
+  CString user_reg_path;
+  user_hive.ExpandKeyName(&user_reg_path);
+
+  // Call the handler
+  int res = (*handler)(user_sid, user_reg_path, param);
+
+  // Unload the hive
+  if (other_user) {
+    hr = user_hive.UnloadHive();
+    if (FAILED(hr)) {
+      UTIL_LOG(LE, (_T("[LoadUserRegistry]")
+                    _T("[failed to save hive for %s][0x%x]"), user_sid, hr));
+    }
+  }
+
+  return res;
+}
+
+// Enumerate all user registries
+void EnumerateAllUserRegistries(ProcessUserRegistryFunc* handler,
+                                LONG_PTR param) {
+  ASSERT1(handler);
+
+  CSimpleArray<CString> sid_array;
+  accounts::GetAllUserSids(&sid_array);
+  for (int i = 0 ; i < sid_array.GetSize() ; ++i) {
+    if (LoadUserRegistry(sid_array[i], handler, param)) {
+      return;
+    }
+  }
+}
+
+}  // namespace omaha
+
diff --git a/common/registry_hive.h b/common/registry_hive.h
index 45bdb89..cf34680 100644
--- a/common/registry_hive.h
+++ b/common/registry_hive.h
@@ -1,74 +1,74 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Other persons' registry hive manipulations.

-//

-#ifndef OMAHA_COMMON_REGISTRY_HIVE_H_

-#define OMAHA_COMMON_REGISTRY_HIVE_H_

-

-#include <windows.h>

-#include <atlstr.h>

-

-namespace omaha {

-

-#define kProfileKeyFormat \

-    _T("HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%s")

-#define kProfilePathValue _T("ProfileImagePath")

-#define kHiveName         _T("Ntuser.dat")

-

-// !!! Warning !!!

-// You MUST unload hive, or this hive becomes unavailable until PC is restarted

-// This means the person cannot login.

-class RegistryHive {

- public:

-  RegistryHive();

-  ~RegistryHive();

-

-  // Loads hive for requested SID. SID should be in format "S-X-X....."

-  // name is a name under which the hive will be added to the HKEY_USERS,

-  // you could use persons name here. This parameter should not have '\\'

-  // characters!

-  // It is not recommended to load more than one hive at once - LoadHive,

-  // manipulate hive, UnloadHive, and then work on the next one.

-  HRESULT LoadHive(TCHAR const * sid, TCHAR const *name);

-  // Loads hive for requested SID, but only if the SID is another user

-  // (since we don't need to do anything if the sid is ours)

-  HRESULT LoadHive(TCHAR const * sid);

-  // Unloads and saves loaded hive

-  HRESULT UnloadHive();

-  // Does it recursively. The name should be relative to HKEY_CURRENT_USER.

-  HRESULT DeleteUserKey(TCHAR const * key_name);

-  // Expands key name for hive:

-  // "Software\Google" => "HKEY_USERS\[hive_name_]\Software\Google"

-  void ExpandKeyName(CString * str);

-

- private:

-  CString hive_name_;

-  HKEY hive_holding_key_;

-};

-

-// Function pointer

-// Return non-zero to abort the enumeration

-typedef int ProcessUserRegistryFunc(const TCHAR* user_sid,

-                                    const TCHAR* user_reg_key,

-                                    LONG_PTR param);

-

-// Enumerate all user registries

-void EnumerateAllUserRegistries(ProcessUserRegistryFunc* handler,

-                                LONG_PTR param);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_REGISTRY_HIVE_H_

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Other persons' registry hive manipulations.
+//
+#ifndef OMAHA_COMMON_REGISTRY_HIVE_H_
+#define OMAHA_COMMON_REGISTRY_HIVE_H_
+
+#include <windows.h>
+#include <atlstr.h>
+
+namespace omaha {
+
+#define kProfileKeyFormat \
+    _T("HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\%s")
+#define kProfilePathValue _T("ProfileImagePath")
+#define kHiveName         _T("Ntuser.dat")
+
+// !!! Warning !!!
+// You MUST unload hive, or this hive becomes unavailable until PC is restarted
+// This means the person cannot login.
+class RegistryHive {
+ public:
+  RegistryHive();
+  ~RegistryHive();
+
+  // Loads hive for requested SID. SID should be in format "S-X-X....."
+  // name is a name under which the hive will be added to the HKEY_USERS,
+  // you could use persons name here. This parameter should not have '\\'
+  // characters!
+  // It is not recommended to load more than one hive at once - LoadHive,
+  // manipulate hive, UnloadHive, and then work on the next one.
+  HRESULT LoadHive(TCHAR const * sid, TCHAR const *name);
+  // Loads hive for requested SID, but only if the SID is another user
+  // (since we don't need to do anything if the sid is ours)
+  HRESULT LoadHive(TCHAR const * sid);
+  // Unloads and saves loaded hive
+  HRESULT UnloadHive();
+  // Does it recursively. The name should be relative to HKEY_CURRENT_USER.
+  HRESULT DeleteUserKey(TCHAR const * key_name);
+  // Expands key name for hive:
+  // "Software\Google" => "HKEY_USERS\[hive_name_]\Software\Google"
+  void ExpandKeyName(CString * str);
+
+ private:
+  CString hive_name_;
+  HKEY hive_holding_key_;
+};
+
+// Function pointer
+// Return non-zero to abort the enumeration
+typedef int ProcessUserRegistryFunc(const TCHAR* user_sid,
+                                    const TCHAR* user_reg_key,
+                                    LONG_PTR param);
+
+// Enumerate all user registries
+void EnumerateAllUserRegistries(ProcessUserRegistryFunc* handler,
+                                LONG_PTR param);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_REGISTRY_HIVE_H_
diff --git a/common/registry_monitor_manager.cc b/common/registry_monitor_manager.cc
index 3cdbf26..43eb5f7 100644
--- a/common/registry_monitor_manager.cc
+++ b/common/registry_monitor_manager.cc
@@ -1,586 +1,586 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// RegistryMonitor creates a KeyWatcher for every unique registry key that

-// contains a value registered by MonitorValue. Each KeyWatcher is responsible

-// for monitoring one or more values in a single registry key but not its

-// subkeys. RegistryMonitor manages a thread which waits on event objects.

-// The events are signaled when the corresponding monitored key changes.

-

-#include "omaha/common/registry_monitor_manager.h"

-#include <atlbase.h>

-#include <utility>

-#include <vector>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/thread.h"

-

-namespace omaha {

-

-namespace detail {

-

-// converts a registry change type value to a string for logging purposes.

-CString RegistryChangeTypeToString(RegistryChangeType registry_change_type) {

-  switch (registry_change_type) {

-  case REGISTRY_CHANGE_TYPE_CREATE:

-    return _T("create");

-  case REGISTRY_CHANGE_TYPE_UPDATE:

-    return _T("update");

-  case REGISTRY_CHANGE_TYPE_DELETE:

-    return _T("delete");

-  default:

-    ASSERT1(false);

-    return _T("unknown");

-  }

-};

-

-// Holds a pair of root key and sub key, as monitoring must be unique for

-// each pair.

-class KeyId {

- public:

-  KeyId(HKEY parent_key, const CString& key_name)

-      : parent_key_(parent_key), key_name_(key_name) {}

-

-  HKEY parent_key() const { return parent_key_; }

-  CString key_name() const { return key_name_; }

-

-  static bool IsEqual(const KeyId& id1, const KeyId& id2) {

-    return id1.parent_key_ == id2.parent_key_ &&

-           id1.key_name_   == id2.key_name_;

-  }

- private:

-  HKEY    parent_key_;

-  CString key_name_;

-};

-

-class KeyWatcher;

-

-// ValueWatcher represents a single monitored registry value.

-// It is used by KeyWatcher to determine which registry value has changed when

-// it detects a change in its key.

-class ValueWatcher {

- public:

-  ValueWatcher(KeyWatcher* key_watcher,

-               const CString& value_name,

-               int value_type,

-               RegistryValueChangeCallback callback,

-               void* user_data);

-  ~ValueWatcher();

-

-  // Returns true if the initial value has changed.

-  bool HasChanged();

-

-  // Calls the callback function to do the notification of the change.

-  void DoCallback();

-

- private:

-  CString GetCurrentValueString();

-  DWORD   GetCurrentValueDword();

-

-  CString last_known_value_string_;

-  DWORD last_known_value_dword_;

-  bool value_is_valid_;

-  RegistryChangeType change_type_;

-  CString value_name_;

-  int value_type_;

-  KeyWatcher* key_watcher_;

-  RegistryValueChangeCallback callback_;

-  void* callback_param_;

-};

-

-

-// KeyWatcher is responsible for monitoring changes to a single key in the

-// Windows registry. RegistryMonitor keeps a container of KeyWatcher objects,

-// one object for each key that contains a value to be monitored.

-class KeyWatcher {

- public:

-  explicit KeyWatcher(const KeyId& key_id);

-

-  ~KeyWatcher();

-

-  // Adds a new registry value to monitor.

-  HRESULT AddValue(const CString& value_name,

-                   int value_type,

-                   RegistryValueChangeCallback callback,

-                   void* user_data);

-

-  // Registers the key watcher with the OS and gets ready to receive events.

-  HRESULT StartWatching();

-

-  // Returns true if the underlying registry handle corresponds to a valid key.

-  bool IsKeyValid();

-

-  HANDLE notification_event() const { return get(notification_event_); }

-

-  RegKey& key() { return key_; }

-

-  CString key_name() const { return key_id_.key_name(); }

-

-  void set_callback(RegistryKeyChangeCallback callback, void* callback_param) {

-    callback_       = callback;

-    callback_param_ = callback_param;

-  }

-

-  // Callback called when the notification event is signaled by the OS

-  // as a result of a change in the monitored key.

-  void HandleEvent(HANDLE handle);

-

- private:

-  // Ensures the key to monitor is always open.

-  HRESULT EnsureOpen();

-

-  std::vector<ValueWatcher*> values_;

-  RegKey key_;

-  const KeyId key_id_;

-  scoped_event notification_event_;

-

-  RegistryKeyChangeCallback callback_;

-  void* callback_param_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(KeyWatcher);

-};

-

-class RegistryMonitorImpl : public Runnable {

- public:

-  RegistryMonitorImpl();

-  ~RegistryMonitorImpl();

-

-  HRESULT MonitorKey(HKEY root_key,

-                     const CString& sub_key,

-                     RegistryKeyChangeCallback callback,

-                     void* user_data);

-

-  HRESULT MonitorValue(HKEY root_key,

-                       const CString& sub_key,

-                       const CString& value_name,

-                       int value_type,

-                       RegistryValueChangeCallback callback,

-                       void* user_data);

-

-  HRESULT Initialize();

-

-  HRESULT StartMonitoring();

-

- private:

-

-  // Runnable.

-  virtual void Run();

-

-  typedef std::pair<KeyId, KeyWatcher*> Watcher;

-  std::vector<Watcher> watchers_;

-

-  Thread thread_;

-  scoped_ptr<Gate> start_monitoring_gate_;

-  scoped_event stop_monitoring_;

-  DISALLOW_EVIL_CONSTRUCTORS(RegistryMonitorImpl);

-};

-

-

-ValueWatcher::ValueWatcher(KeyWatcher* key_watcher,

-                           const CString &value_name,

-                           int value_type,

-                           RegistryValueChangeCallback callback,

-                           void* user_data)

-    : key_watcher_(key_watcher),

-      value_is_valid_(false),

-      change_type_(REGISTRY_CHANGE_TYPE_CREATE),

-      callback_(callback),

-      callback_param_(user_data),

-      value_name_(value_name),

-      value_type_(value_type),

-      last_known_value_dword_(0) {

-  ASSERT1(key_watcher);

-  ASSERT1(callback);

-  if (value_type_ == REG_SZ) {

-    last_known_value_string_ = GetCurrentValueString();

-  } else if (value_type_ == REG_DWORD) {

-    last_known_value_dword_ = GetCurrentValueDword();

-  } else {

-    ASSERT(false, (_T("value type not supported")));

-  }

-}

-

-ValueWatcher::~ValueWatcher() {

-}

-

-bool ValueWatcher::HasChanged() {

-  UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")

-                _T("[key name '%s'][value '%s'][valid %d]"),

-                key_watcher_->key_name(), value_name_, value_is_valid_));

-

-  const bool value_was_valid = value_is_valid_;

-

-  bool has_changed = false;

-  if (value_type_ == REG_SZ) {

-    CString new_value = GetCurrentValueString();

-    has_changed = last_known_value_string_ != new_value;

-

-    UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged][old value %s][new value %s]"),

-                  last_known_value_string_, new_value));

-

-    last_known_value_string_ = new_value;

-  } else if (value_type_ == REG_DWORD) {

-    DWORD new_value = GetCurrentValueDword();

-    has_changed = last_known_value_dword_ != new_value;

-

-    UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged][old value %d][new value %d]"),

-                  last_known_value_dword_, new_value));

-

-    last_known_value_dword_ = new_value;

-  } else {

-    ASSERT(false, (_T("value type not supported")));

-  }

-

-  // Detect the type of the change based on previous and current value state.

-  if (value_was_valid && value_is_valid_) {

-    change_type_ = REGISTRY_CHANGE_TYPE_UPDATE;

-  } else if (value_was_valid && !value_is_valid_) {

-    change_type_ = REGISTRY_CHANGE_TYPE_DELETE;

-  } else if (!value_was_valid && value_is_valid_) {

-    change_type_ = REGISTRY_CHANGE_TYPE_CREATE;

-  } else {

-    ASSERT1(!value_was_valid && !value_is_valid_);

-  }

-

-  if (has_changed) {

-    UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")

-                  _T("[key name '%s'][value '%s' has changed][%s]"),

-                  key_watcher_->key_name(), value_name_,

-                  RegistryChangeTypeToString(change_type_)));

-  } else {

-    UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")

-                  _T("[key name '%s'][value '%s' is the same]"),

-                  key_watcher_->key_name(), value_name_));

-  }

-

-  return has_changed;

-}

-

-CString ValueWatcher::GetCurrentValueString() {

-  CString value_data;

-  RegKey& key = key_watcher_->key();

-  ASSERT1(key.Key());

-  value_is_valid_ = SUCCEEDED(key.GetValue(value_name_, &value_data));

-  return value_is_valid_ ? value_data : CString();

-}

-

-DWORD ValueWatcher::GetCurrentValueDword() {

-  DWORD value_data = 0;

-  RegKey& key = key_watcher_->key();

-  ASSERT1(key.Key());

-  value_is_valid_ = SUCCEEDED(key.GetValue(value_name_, &value_data));

-  return value_is_valid_ ? value_data : static_cast<DWORD>(-1);

-}

-

-void ValueWatcher::DoCallback() {

-  ASSERT1(callback_ != NULL);

-

-  const void* value = NULL;

-  if (value_type_ == REG_SZ) {

-    value = static_cast<const TCHAR*>(last_known_value_string_);

-  } else if (value_type_ == REG_DWORD) {

-    value = reinterpret_cast<void*>(last_known_value_dword_);

-  }

-

-  callback_(key_watcher_->key_name(), value_name_, change_type_,

-            value, callback_param_);

-

-  // If value was not valid, for example, the key was deleted or renamed, and

-  // it is valid after callback, update last known with the current value.

-  if (!value_is_valid_) {

-    if (value_type_ == REG_SZ) {

-      CString new_value = GetCurrentValueString();

-      if (value_is_valid_) {

-        last_known_value_string_ = new_value;

-      }

-    } else if (value_type_ == REG_DWORD) {

-      DWORD new_value = GetCurrentValueDword();

-      if (value_is_valid_) {

-        last_known_value_dword_ = new_value;

-      }

-    }

-  }

-}

-

-KeyWatcher::KeyWatcher(const KeyId& key_id)

-    : key_id_(key_id),

-      notification_event_(::CreateEvent(NULL, false, false, NULL)),

-      callback_(NULL),

-      callback_param_(NULL) {

-}

-

-KeyWatcher::~KeyWatcher() {

-  for (size_t i = 0; i != values_.size(); ++i) {

-    delete values_[i];

-  }

-}

-

-HRESULT KeyWatcher::StartWatching() {

-  // By this time the key could be deleted or renamed. Check if the handle

-  // is still valid and reopen the key if needed.

-  HRESULT hr = EnsureOpen();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(key_.Key());

-  const DWORD kNotifyFilter = REG_NOTIFY_CHANGE_NAME          |

-                              REG_NOTIFY_CHANGE_ATTRIBUTES    |

-                              REG_NOTIFY_CHANGE_LAST_SET      |

-                              REG_NOTIFY_CHANGE_SECURITY;

-  LONG result = ::RegNotifyChangeKeyValue(key_.Key(), false, kNotifyFilter,

-                                          get(notification_event_), true);

-  UTIL_LOG(L3, (_T("[KeyWatcher::StartWatching][key '%s' %s]"),

-                key_id_.key_name(),

-                result == ERROR_SUCCESS ? _T("ok") : _T("failed")));

-  return HRESULT_FROM_WIN32(result);

-}

-

-HRESULT KeyWatcher::AddValue(const CString& value_name,

-                             int value_type,

-                             RegistryValueChangeCallback callback,

-                             void* user_data) {

-  ASSERT1(callback);

-  HRESULT hr = EnsureOpen();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  values_.push_back(

-      new ValueWatcher(this, value_name, value_type, callback, user_data));

-  return S_OK;

-}

-

-void KeyWatcher::HandleEvent(HANDLE handle) {

-  UTIL_LOG(L3, (_T("[KeyWatcher::HandleEvent][key '%s']"), key_id_.key_name()));

-

-  ASSERT1(handle);

-  ASSERT1(handle == get(notification_event_));

-  UNREFERENCED_PARAMETER(handle);

-

-  // Although not documented, it seems the OS pulses the event so the event

-  // is never signaled at this point.

-  ASSERT1(::WaitForSingleObject(handle, 0) == WAIT_TIMEOUT);

-

-  // Notify the key has changed.

-  if (callback_) {

-    callback_(key_name(), callback_param_);

-  }

-

-  // Notify the values have changed.

-  for (size_t i = 0; i != values_.size(); ++i) {

-    ValueWatcher* value = values_[i];

-    if (value != NULL) {

-      if (value->HasChanged()) {

-        value->DoCallback();

-      }

-    }

-  }

-

-  VERIFY1(SUCCEEDED(StartWatching()));

-}

-

-HRESULT KeyWatcher::EnsureOpen() {

-  // Close the key if it is not valid for whatever reasons, such as it was

-  // deleted and recreated back.

-  if (!IsKeyValid()) {

-    UTIL_LOG(L3, (_T("[key '%s' is not valid]"), key_id_.key_name()));

-    VERIFY1(SUCCEEDED(key_.Close()));

-  }

-

-  // Open the key if not already open or create the key if needed.

-  HRESULT hr = S_OK;

-  if (!key_.Key()) {

-    hr = key_.Create(key_id_.parent_key(), key_id_.key_name());

-    if (SUCCEEDED(hr)) {

-      UTIL_LOG(L3, (_T("[key '%s' has been created]"), key_id_.key_name()));

-    }

-  }

-  return hr;

-}

-

-bool KeyWatcher::IsKeyValid() {

-  if (!key_.Key()) {

-    return false;

-  }

-  LONG ret = RegQueryInfoKey(key_.Key(),

-                             NULL, NULL, NULL, NULL, NULL,

-                             NULL, NULL, NULL, NULL, NULL, NULL);

-  return ret == ERROR_SUCCESS;

-}

-

-RegistryMonitorImpl::RegistryMonitorImpl() {

-}

-

-RegistryMonitorImpl::~RegistryMonitorImpl() {

-  if (stop_monitoring_) {

-    VERIFY1(::SetEvent(get(stop_monitoring_)));

-  }

-  VERIFY1(thread_.WaitTillExit(INFINITE));

-

-  for (size_t i = 0; i != watchers_.size(); ++i) {

-    ASSERT1(watchers_[i].second);

-    delete watchers_[i].second;

-  }

-}

-

-HRESULT RegistryMonitorImpl::Initialize() {

-  reset(stop_monitoring_, ::CreateEvent(NULL, true, false, NULL));

-  if (!stop_monitoring_) {

-    return HRESULTFromLastError();

-  }

-  return S_OK;

-}

-

-HRESULT RegistryMonitorImpl::MonitorKey(HKEY root_key,

-                                        const CString& sub_key,

-                                        RegistryKeyChangeCallback callback,

-                                        void* user_data) {

-  ASSERT1(callback);

-  ASSERT1(!thread_.Running());

-

-  KeyId key_id(root_key, sub_key);

-  for (size_t i = 0; i != watchers_.size(); ++i) {

-    if (KeyId::IsEqual(watchers_[i].first, key_id)) {

-      watchers_[i].second->set_callback(callback, user_data);

-      return S_OK;

-    }

-  }

-  scoped_ptr<KeyWatcher> key_watcher(new KeyWatcher(key_id));

-  key_watcher->set_callback(callback, user_data);

-  Watcher watcher(key_id, key_watcher.release());

-  watchers_.push_back(watcher);

-  return S_OK;

-}

-

-HRESULT RegistryMonitorImpl::MonitorValue(

-    HKEY root_key, const CString& sub_key, const CString& value_name,

-    int value_type, RegistryValueChangeCallback callback, void* user_data) {

-  ASSERT1(callback);

-  ASSERT1(!thread_.Running());

-

-  // Reuse an existing key watcher if there is a value already registered

-  // for monitoring under the respective registry key.

-  KeyId key_id(root_key, sub_key);

-  for (size_t i = 0; i != watchers_.size(); ++i) {

-    if (KeyId::IsEqual(watchers_[i].first, key_id)) {

-      return watchers_[i].second->AddValue(value_name, value_type,

-                                           callback, user_data);

-    }

-  }

-  scoped_ptr<KeyWatcher> key_watcher(new KeyWatcher(key_id));

-  HRESULT hr = key_watcher->AddValue(value_name, value_type,

-                                     callback, user_data);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[RegistryMonitorImpl::RegisterValue failed]")

-                  _T("[key %s][value %s][0x%x]"), sub_key, value_name, hr));

-    return hr;

-  }

-  Watcher watcher(key_id, key_watcher.release());

-  watchers_.push_back(watcher);

-  return S_OK;

-}

-

-HRESULT RegistryMonitorImpl::StartMonitoring() {

-  // Starts the thread and waits on the gate for the thread to open after

-  // it has registered all watchers for notifications and it is ready to

-  // handle notification events. The gate is only needed to synchronize the

-  // caller and the monitoring threads.

-  start_monitoring_gate_.reset(new Gate);

-  if (!thread_.Start(this)) {

-    return E_FAIL;

-  }

-  bool wait_result = start_monitoring_gate_->Wait(INFINITE);

-  start_monitoring_gate_.reset();

-  ASSERT1(wait_result);

-  return wait_result ? S_OK : HRESULTFromLastError();

-}

-

-void RegistryMonitorImpl::Run() {

-  UTIL_LOG(L3, (_T("[started monitoring registry]")));

-

-  const size_t kNumNotificationHandles = watchers_.size();

-  const size_t kNumHandles = kNumNotificationHandles + 1;

-  const size_t kStopMonitoringHandleIndex = kNumNotificationHandles;

-

-  scoped_array<HANDLE> handles(new HANDLE[kNumHandles]);

-  for (size_t i = 0; i != watchers_.size(); ++i) {

-    handles[i] = watchers_[i].second->notification_event();

-    VERIFY1(SUCCEEDED(watchers_[i].second->StartWatching()));

-  }

-  handles[kStopMonitoringHandleIndex] = get(stop_monitoring_);

-

-  // Open the gate and allow the RegistryMonitor::StartMonitoring call to

-  // to return to the caller.

-  ASSERT1(start_monitoring_gate_.get());

-  VERIFY1(start_monitoring_gate_->Open());

-

-  for (;;) {

-    DWORD result = ::WaitForMultipleObjects(kNumHandles,

-                                            handles.get(),

-                                            false,

-                                            INFINITE);

-    COMPILE_ASSERT(0 == WAIT_OBJECT_0, invalid_wait_object_0);

-    ASSERT1(result < kNumHandles);

-    if (result < kNumHandles) {

-      if (result == kStopMonitoringHandleIndex) {

-        break;

-      } else {

-        size_t i = result - WAIT_OBJECT_0;

-        watchers_[i].second->HandleEvent(handles[i]);

-      }

-    }

-  }

-  UTIL_LOG(L3, (_T("[stopped monitoring registry]")));

-}

-

-}  // namespace detail

-

-RegistryMonitor::RegistryMonitor()

-    : impl_(new detail::RegistryMonitorImpl) {

-}

-

-RegistryMonitor::~RegistryMonitor() {

-}

-

-HRESULT RegistryMonitor::MonitorKey(HKEY root_key,

-                                    const CString& sub_key,

-                                    RegistryKeyChangeCallback callback,

-                                    void* user_data) {

-  return impl_->MonitorKey(root_key, sub_key, callback, user_data);

-}

-

-HRESULT RegistryMonitor::MonitorValue(HKEY root_key,

-                                      const CString& sub_key,

-                                      const CString& value_name,

-                                      int value_type,

-                                      RegistryValueChangeCallback callback,

-                                      void* user_data) {

-  return impl_->MonitorValue(root_key, sub_key, value_name, value_type,

-                             callback, user_data);

-}

-

-HRESULT RegistryMonitor::Initialize() {

-  return impl_->Initialize();

-}

-

-HRESULT RegistryMonitor::StartMonitoring() {

-  return impl_->StartMonitoring();

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// RegistryMonitor creates a KeyWatcher for every unique registry key that
+// contains a value registered by MonitorValue. Each KeyWatcher is responsible
+// for monitoring one or more values in a single registry key but not its
+// subkeys. RegistryMonitor manages a thread which waits on event objects.
+// The events are signaled when the corresponding monitored key changes.
+
+#include "omaha/common/registry_monitor_manager.h"
+#include <atlbase.h>
+#include <utility>
+#include <vector>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/thread.h"
+
+namespace omaha {
+
+namespace detail {
+
+// converts a registry change type value to a string for logging purposes.
+CString RegistryChangeTypeToString(RegistryChangeType registry_change_type) {
+  switch (registry_change_type) {
+  case REGISTRY_CHANGE_TYPE_CREATE:
+    return _T("create");
+  case REGISTRY_CHANGE_TYPE_UPDATE:
+    return _T("update");
+  case REGISTRY_CHANGE_TYPE_DELETE:
+    return _T("delete");
+  default:
+    ASSERT1(false);
+    return _T("unknown");
+  }
+};
+
+// Holds a pair of root key and sub key, as monitoring must be unique for
+// each pair.
+class KeyId {
+ public:
+  KeyId(HKEY parent_key, const CString& key_name)
+      : parent_key_(parent_key), key_name_(key_name) {}
+
+  HKEY parent_key() const { return parent_key_; }
+  CString key_name() const { return key_name_; }
+
+  static bool IsEqual(const KeyId& id1, const KeyId& id2) {
+    return id1.parent_key_ == id2.parent_key_ &&
+           id1.key_name_   == id2.key_name_;
+  }
+ private:
+  HKEY    parent_key_;
+  CString key_name_;
+};
+
+class KeyWatcher;
+
+// ValueWatcher represents a single monitored registry value.
+// It is used by KeyWatcher to determine which registry value has changed when
+// it detects a change in its key.
+class ValueWatcher {
+ public:
+  ValueWatcher(KeyWatcher* key_watcher,
+               const CString& value_name,
+               int value_type,
+               RegistryValueChangeCallback callback,
+               void* user_data);
+  ~ValueWatcher();
+
+  // Returns true if the initial value has changed.
+  bool HasChanged();
+
+  // Calls the callback function to do the notification of the change.
+  void DoCallback();
+
+ private:
+  CString GetCurrentValueString();
+  DWORD   GetCurrentValueDword();
+
+  CString last_known_value_string_;
+  DWORD last_known_value_dword_;
+  bool value_is_valid_;
+  RegistryChangeType change_type_;
+  CString value_name_;
+  int value_type_;
+  KeyWatcher* key_watcher_;
+  RegistryValueChangeCallback callback_;
+  void* callback_param_;
+};
+
+
+// KeyWatcher is responsible for monitoring changes to a single key in the
+// Windows registry. RegistryMonitor keeps a container of KeyWatcher objects,
+// one object for each key that contains a value to be monitored.
+class KeyWatcher {
+ public:
+  explicit KeyWatcher(const KeyId& key_id);
+
+  ~KeyWatcher();
+
+  // Adds a new registry value to monitor.
+  HRESULT AddValue(const CString& value_name,
+                   int value_type,
+                   RegistryValueChangeCallback callback,
+                   void* user_data);
+
+  // Registers the key watcher with the OS and gets ready to receive events.
+  HRESULT StartWatching();
+
+  // Returns true if the underlying registry handle corresponds to a valid key.
+  bool IsKeyValid();
+
+  HANDLE notification_event() const { return get(notification_event_); }
+
+  RegKey& key() { return key_; }
+
+  CString key_name() const { return key_id_.key_name(); }
+
+  void set_callback(RegistryKeyChangeCallback callback, void* callback_param) {
+    callback_       = callback;
+    callback_param_ = callback_param;
+  }
+
+  // Callback called when the notification event is signaled by the OS
+  // as a result of a change in the monitored key.
+  void HandleEvent(HANDLE handle);
+
+ private:
+  // Ensures the key to monitor is always open.
+  HRESULT EnsureOpen();
+
+  std::vector<ValueWatcher*> values_;
+  RegKey key_;
+  const KeyId key_id_;
+  scoped_event notification_event_;
+
+  RegistryKeyChangeCallback callback_;
+  void* callback_param_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(KeyWatcher);
+};
+
+class RegistryMonitorImpl : public Runnable {
+ public:
+  RegistryMonitorImpl();
+  ~RegistryMonitorImpl();
+
+  HRESULT MonitorKey(HKEY root_key,
+                     const CString& sub_key,
+                     RegistryKeyChangeCallback callback,
+                     void* user_data);
+
+  HRESULT MonitorValue(HKEY root_key,
+                       const CString& sub_key,
+                       const CString& value_name,
+                       int value_type,
+                       RegistryValueChangeCallback callback,
+                       void* user_data);
+
+  HRESULT Initialize();
+
+  HRESULT StartMonitoring();
+
+ private:
+
+  // Runnable.
+  virtual void Run();
+
+  typedef std::pair<KeyId, KeyWatcher*> Watcher;
+  std::vector<Watcher> watchers_;
+
+  Thread thread_;
+  scoped_ptr<Gate> start_monitoring_gate_;
+  scoped_event stop_monitoring_;
+  DISALLOW_EVIL_CONSTRUCTORS(RegistryMonitorImpl);
+};
+
+
+ValueWatcher::ValueWatcher(KeyWatcher* key_watcher,
+                           const CString &value_name,
+                           int value_type,
+                           RegistryValueChangeCallback callback,
+                           void* user_data)
+    : key_watcher_(key_watcher),
+      value_is_valid_(false),
+      change_type_(REGISTRY_CHANGE_TYPE_CREATE),
+      callback_(callback),
+      callback_param_(user_data),
+      value_name_(value_name),
+      value_type_(value_type),
+      last_known_value_dword_(0) {
+  ASSERT1(key_watcher);
+  ASSERT1(callback);
+  if (value_type_ == REG_SZ) {
+    last_known_value_string_ = GetCurrentValueString();
+  } else if (value_type_ == REG_DWORD) {
+    last_known_value_dword_ = GetCurrentValueDword();
+  } else {
+    ASSERT(false, (_T("value type not supported")));
+  }
+}
+
+ValueWatcher::~ValueWatcher() {
+}
+
+bool ValueWatcher::HasChanged() {
+  UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")
+                _T("[key name '%s'][value '%s'][valid %d]"),
+                key_watcher_->key_name(), value_name_, value_is_valid_));
+
+  const bool value_was_valid = value_is_valid_;
+
+  bool has_changed = false;
+  if (value_type_ == REG_SZ) {
+    CString new_value = GetCurrentValueString();
+    has_changed = last_known_value_string_ != new_value;
+
+    UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged][old value %s][new value %s]"),
+                  last_known_value_string_, new_value));
+
+    last_known_value_string_ = new_value;
+  } else if (value_type_ == REG_DWORD) {
+    DWORD new_value = GetCurrentValueDword();
+    has_changed = last_known_value_dword_ != new_value;
+
+    UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged][old value %d][new value %d]"),
+                  last_known_value_dword_, new_value));
+
+    last_known_value_dword_ = new_value;
+  } else {
+    ASSERT(false, (_T("value type not supported")));
+  }
+
+  // Detect the type of the change based on previous and current value state.
+  if (value_was_valid && value_is_valid_) {
+    change_type_ = REGISTRY_CHANGE_TYPE_UPDATE;
+  } else if (value_was_valid && !value_is_valid_) {
+    change_type_ = REGISTRY_CHANGE_TYPE_DELETE;
+  } else if (!value_was_valid && value_is_valid_) {
+    change_type_ = REGISTRY_CHANGE_TYPE_CREATE;
+  } else {
+    ASSERT1(!value_was_valid && !value_is_valid_);
+  }
+
+  if (has_changed) {
+    UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")
+                  _T("[key name '%s'][value '%s' has changed][%s]"),
+                  key_watcher_->key_name(), value_name_,
+                  RegistryChangeTypeToString(change_type_)));
+  } else {
+    UTIL_LOG(L3, (_T("[ValueWatcher::HasChanged]")
+                  _T("[key name '%s'][value '%s' is the same]"),
+                  key_watcher_->key_name(), value_name_));
+  }
+
+  return has_changed;
+}
+
+CString ValueWatcher::GetCurrentValueString() {
+  CString value_data;
+  RegKey& key = key_watcher_->key();
+  ASSERT1(key.Key());
+  value_is_valid_ = SUCCEEDED(key.GetValue(value_name_, &value_data));
+  return value_is_valid_ ? value_data : CString();
+}
+
+DWORD ValueWatcher::GetCurrentValueDword() {
+  DWORD value_data = 0;
+  RegKey& key = key_watcher_->key();
+  ASSERT1(key.Key());
+  value_is_valid_ = SUCCEEDED(key.GetValue(value_name_, &value_data));
+  return value_is_valid_ ? value_data : static_cast<DWORD>(-1);
+}
+
+void ValueWatcher::DoCallback() {
+  ASSERT1(callback_ != NULL);
+
+  const void* value = NULL;
+  if (value_type_ == REG_SZ) {
+    value = static_cast<const TCHAR*>(last_known_value_string_);
+  } else if (value_type_ == REG_DWORD) {
+    value = reinterpret_cast<void*>(last_known_value_dword_);
+  }
+
+  callback_(key_watcher_->key_name(), value_name_, change_type_,
+            value, callback_param_);
+
+  // If value was not valid, for example, the key was deleted or renamed, and
+  // it is valid after callback, update last known with the current value.
+  if (!value_is_valid_) {
+    if (value_type_ == REG_SZ) {
+      CString new_value = GetCurrentValueString();
+      if (value_is_valid_) {
+        last_known_value_string_ = new_value;
+      }
+    } else if (value_type_ == REG_DWORD) {
+      DWORD new_value = GetCurrentValueDword();
+      if (value_is_valid_) {
+        last_known_value_dword_ = new_value;
+      }
+    }
+  }
+}
+
+KeyWatcher::KeyWatcher(const KeyId& key_id)
+    : key_id_(key_id),
+      notification_event_(::CreateEvent(NULL, false, false, NULL)),
+      callback_(NULL),
+      callback_param_(NULL) {
+}
+
+KeyWatcher::~KeyWatcher() {
+  for (size_t i = 0; i != values_.size(); ++i) {
+    delete values_[i];
+  }
+}
+
+HRESULT KeyWatcher::StartWatching() {
+  // By this time the key could be deleted or renamed. Check if the handle
+  // is still valid and reopen the key if needed.
+  HRESULT hr = EnsureOpen();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(key_.Key());
+  const DWORD kNotifyFilter = REG_NOTIFY_CHANGE_NAME          |
+                              REG_NOTIFY_CHANGE_ATTRIBUTES    |
+                              REG_NOTIFY_CHANGE_LAST_SET      |
+                              REG_NOTIFY_CHANGE_SECURITY;
+  LONG result = ::RegNotifyChangeKeyValue(key_.Key(), false, kNotifyFilter,
+                                          get(notification_event_), true);
+  UTIL_LOG(L3, (_T("[KeyWatcher::StartWatching][key '%s' %s]"),
+                key_id_.key_name(),
+                result == ERROR_SUCCESS ? _T("ok") : _T("failed")));
+  return HRESULT_FROM_WIN32(result);
+}
+
+HRESULT KeyWatcher::AddValue(const CString& value_name,
+                             int value_type,
+                             RegistryValueChangeCallback callback,
+                             void* user_data) {
+  ASSERT1(callback);
+  HRESULT hr = EnsureOpen();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  values_.push_back(
+      new ValueWatcher(this, value_name, value_type, callback, user_data));
+  return S_OK;
+}
+
+void KeyWatcher::HandleEvent(HANDLE handle) {
+  UTIL_LOG(L3, (_T("[KeyWatcher::HandleEvent][key '%s']"), key_id_.key_name()));
+
+  ASSERT1(handle);
+  ASSERT1(handle == get(notification_event_));
+  UNREFERENCED_PARAMETER(handle);
+
+  // Although not documented, it seems the OS pulses the event so the event
+  // is never signaled at this point.
+  ASSERT1(::WaitForSingleObject(handle, 0) == WAIT_TIMEOUT);
+
+  // Notify the key has changed.
+  if (callback_) {
+    callback_(key_name(), callback_param_);
+  }
+
+  // Notify the values have changed.
+  for (size_t i = 0; i != values_.size(); ++i) {
+    ValueWatcher* value = values_[i];
+    if (value != NULL) {
+      if (value->HasChanged()) {
+        value->DoCallback();
+      }
+    }
+  }
+
+  VERIFY1(SUCCEEDED(StartWatching()));
+}
+
+HRESULT KeyWatcher::EnsureOpen() {
+  // Close the key if it is not valid for whatever reasons, such as it was
+  // deleted and recreated back.
+  if (!IsKeyValid()) {
+    UTIL_LOG(L3, (_T("[key '%s' is not valid]"), key_id_.key_name()));
+    VERIFY1(SUCCEEDED(key_.Close()));
+  }
+
+  // Open the key if not already open or create the key if needed.
+  HRESULT hr = S_OK;
+  if (!key_.Key()) {
+    hr = key_.Create(key_id_.parent_key(), key_id_.key_name());
+    if (SUCCEEDED(hr)) {
+      UTIL_LOG(L3, (_T("[key '%s' has been created]"), key_id_.key_name()));
+    }
+  }
+  return hr;
+}
+
+bool KeyWatcher::IsKeyValid() {
+  if (!key_.Key()) {
+    return false;
+  }
+  LONG ret = RegQueryInfoKey(key_.Key(),
+                             NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+  return ret == ERROR_SUCCESS;
+}
+
+RegistryMonitorImpl::RegistryMonitorImpl() {
+}
+
+RegistryMonitorImpl::~RegistryMonitorImpl() {
+  if (stop_monitoring_) {
+    VERIFY1(::SetEvent(get(stop_monitoring_)));
+  }
+  VERIFY1(thread_.WaitTillExit(INFINITE));
+
+  for (size_t i = 0; i != watchers_.size(); ++i) {
+    ASSERT1(watchers_[i].second);
+    delete watchers_[i].second;
+  }
+}
+
+HRESULT RegistryMonitorImpl::Initialize() {
+  reset(stop_monitoring_, ::CreateEvent(NULL, true, false, NULL));
+  if (!stop_monitoring_) {
+    return HRESULTFromLastError();
+  }
+  return S_OK;
+}
+
+HRESULT RegistryMonitorImpl::MonitorKey(HKEY root_key,
+                                        const CString& sub_key,
+                                        RegistryKeyChangeCallback callback,
+                                        void* user_data) {
+  ASSERT1(callback);
+  ASSERT1(!thread_.Running());
+
+  KeyId key_id(root_key, sub_key);
+  for (size_t i = 0; i != watchers_.size(); ++i) {
+    if (KeyId::IsEqual(watchers_[i].first, key_id)) {
+      watchers_[i].second->set_callback(callback, user_data);
+      return S_OK;
+    }
+  }
+  scoped_ptr<KeyWatcher> key_watcher(new KeyWatcher(key_id));
+  key_watcher->set_callback(callback, user_data);
+  Watcher watcher(key_id, key_watcher.release());
+  watchers_.push_back(watcher);
+  return S_OK;
+}
+
+HRESULT RegistryMonitorImpl::MonitorValue(
+    HKEY root_key, const CString& sub_key, const CString& value_name,
+    int value_type, RegistryValueChangeCallback callback, void* user_data) {
+  ASSERT1(callback);
+  ASSERT1(!thread_.Running());
+
+  // Reuse an existing key watcher if there is a value already registered
+  // for monitoring under the respective registry key.
+  KeyId key_id(root_key, sub_key);
+  for (size_t i = 0; i != watchers_.size(); ++i) {
+    if (KeyId::IsEqual(watchers_[i].first, key_id)) {
+      return watchers_[i].second->AddValue(value_name, value_type,
+                                           callback, user_data);
+    }
+  }
+  scoped_ptr<KeyWatcher> key_watcher(new KeyWatcher(key_id));
+  HRESULT hr = key_watcher->AddValue(value_name, value_type,
+                                     callback, user_data);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[RegistryMonitorImpl::RegisterValue failed]")
+                  _T("[key %s][value %s][0x%x]"), sub_key, value_name, hr));
+    return hr;
+  }
+  Watcher watcher(key_id, key_watcher.release());
+  watchers_.push_back(watcher);
+  return S_OK;
+}
+
+HRESULT RegistryMonitorImpl::StartMonitoring() {
+  // Starts the thread and waits on the gate for the thread to open after
+  // it has registered all watchers for notifications and it is ready to
+  // handle notification events. The gate is only needed to synchronize the
+  // caller and the monitoring threads.
+  start_monitoring_gate_.reset(new Gate);
+  if (!thread_.Start(this)) {
+    return E_FAIL;
+  }
+  bool wait_result = start_monitoring_gate_->Wait(INFINITE);
+  start_monitoring_gate_.reset();
+  ASSERT1(wait_result);
+  return wait_result ? S_OK : HRESULTFromLastError();
+}
+
+void RegistryMonitorImpl::Run() {
+  UTIL_LOG(L3, (_T("[started monitoring registry]")));
+
+  const size_t kNumNotificationHandles = watchers_.size();
+  const size_t kNumHandles = kNumNotificationHandles + 1;
+  const size_t kStopMonitoringHandleIndex = kNumNotificationHandles;
+
+  scoped_array<HANDLE> handles(new HANDLE[kNumHandles]);
+  for (size_t i = 0; i != watchers_.size(); ++i) {
+    handles[i] = watchers_[i].second->notification_event();
+    VERIFY1(SUCCEEDED(watchers_[i].second->StartWatching()));
+  }
+  handles[kStopMonitoringHandleIndex] = get(stop_monitoring_);
+
+  // Open the gate and allow the RegistryMonitor::StartMonitoring call to
+  // to return to the caller.
+  ASSERT1(start_monitoring_gate_.get());
+  VERIFY1(start_monitoring_gate_->Open());
+
+  for (;;) {
+    DWORD result = ::WaitForMultipleObjects(kNumHandles,
+                                            handles.get(),
+                                            false,
+                                            INFINITE);
+    COMPILE_ASSERT(0 == WAIT_OBJECT_0, invalid_wait_object_0);
+    ASSERT1(result < kNumHandles);
+    if (result < kNumHandles) {
+      if (result == kStopMonitoringHandleIndex) {
+        break;
+      } else {
+        size_t i = result - WAIT_OBJECT_0;
+        watchers_[i].second->HandleEvent(handles[i]);
+      }
+    }
+  }
+  UTIL_LOG(L3, (_T("[stopped monitoring registry]")));
+}
+
+}  // namespace detail
+
+RegistryMonitor::RegistryMonitor()
+    : impl_(new detail::RegistryMonitorImpl) {
+}
+
+RegistryMonitor::~RegistryMonitor() {
+}
+
+HRESULT RegistryMonitor::MonitorKey(HKEY root_key,
+                                    const CString& sub_key,
+                                    RegistryKeyChangeCallback callback,
+                                    void* user_data) {
+  return impl_->MonitorKey(root_key, sub_key, callback, user_data);
+}
+
+HRESULT RegistryMonitor::MonitorValue(HKEY root_key,
+                                      const CString& sub_key,
+                                      const CString& value_name,
+                                      int value_type,
+                                      RegistryValueChangeCallback callback,
+                                      void* user_data) {
+  return impl_->MonitorValue(root_key, sub_key, value_name, value_type,
+                             callback, user_data);
+}
+
+HRESULT RegistryMonitor::Initialize() {
+  return impl_->Initialize();
+}
+
+HRESULT RegistryMonitor::StartMonitoring() {
+  return impl_->StartMonitoring();
+}
+
+}  // namespace omaha
+
diff --git a/common/registry_monitor_manager.h b/common/registry_monitor_manager.h
index 8e483e6..6cf9952 100644
--- a/common/registry_monitor_manager.h
+++ b/common/registry_monitor_manager.h
@@ -1,92 +1,92 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The RegistryMonitor allows a caller to request monitoring

-// for registry value changes across multiple keys. It uses the Windows API

-// function RegNotifyChangeKeyValue to notify when any value in a key changes.

-

-#ifndef OMAHA_COMMON_REGISTRY_MONITOR_MANAGER_H_

-#define OMAHA_COMMON_REGISTRY_MONITOR_MANAGER_H_

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-

-namespace omaha {

-

-namespace detail {

-

-class RegistryMonitorImpl;

-

-}  // namespace detail

-

-// Called when a registry value changes. 'new_value_data' contains a

-// pointer to the string data for a string value or the value itself for a

-// DWORD value.

-enum RegistryChangeType {

-  REGISTRY_CHANGE_TYPE_CREATE = 0,

-  REGISTRY_CHANGE_TYPE_UPDATE,

-  REGISTRY_CHANGE_TYPE_DELETE,

-};

-typedef void (*RegistryValueChangeCallback)(const TCHAR* key_name,

-                                            const TCHAR* value_name,

-                                            RegistryChangeType change_type,

-                                            const void* new_value_data,

-                                            void* user_data);

-

-// Called when a registry key changes. Changes include subkeys being

-// created or deleted as well as value changes under that key but not under

-// the subkeys of the key.

-typedef void (*RegistryKeyChangeCallback)(const TCHAR* key_name,

-                                          void* user_data);

-

-class RegistryMonitor {

- public:

-  RegistryMonitor();

-  ~RegistryMonitor();

-

-  HRESULT Initialize();

-

-  // Monitors a registry sub key for changes. Registering the same sub key

-  // overrides the previous registration.

-  HRESULT MonitorKey(HKEY root_key,

-                     const CString& sub_key,

-                     RegistryKeyChangeCallback callback,

-                     void* user_data);

-

-  // Adds a registry value to the list of values to monitor for changes.

-  // All values must be registered before starting monitoring. Registering

-  // the same value is allowed, although not particularly useful.

-  HRESULT MonitorValue(HKEY root_key,

-                       const CString& sub_key,

-                       const CString& value_name,

-                       int value_type,

-                       RegistryValueChangeCallback callback,

-                       void* user_data);

-

-  // Starts monitoring for changes.

-  HRESULT StartMonitoring();

-

- private:

-  scoped_ptr<detail::RegistryMonitorImpl> impl_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(RegistryMonitor);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_REGISTRY_MONITOR_MANAGER_H_

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The RegistryMonitor allows a caller to request monitoring
+// for registry value changes across multiple keys. It uses the Windows API
+// function RegNotifyChangeKeyValue to notify when any value in a key changes.
+
+#ifndef OMAHA_COMMON_REGISTRY_MONITOR_MANAGER_H_
+#define OMAHA_COMMON_REGISTRY_MONITOR_MANAGER_H_
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+
+namespace omaha {
+
+namespace detail {
+
+class RegistryMonitorImpl;
+
+}  // namespace detail
+
+// Called when a registry value changes. 'new_value_data' contains a
+// pointer to the string data for a string value or the value itself for a
+// DWORD value.
+enum RegistryChangeType {
+  REGISTRY_CHANGE_TYPE_CREATE = 0,
+  REGISTRY_CHANGE_TYPE_UPDATE,
+  REGISTRY_CHANGE_TYPE_DELETE,
+};
+typedef void (*RegistryValueChangeCallback)(const TCHAR* key_name,
+                                            const TCHAR* value_name,
+                                            RegistryChangeType change_type,
+                                            const void* new_value_data,
+                                            void* user_data);
+
+// Called when a registry key changes. Changes include subkeys being
+// created or deleted as well as value changes under that key but not under
+// the subkeys of the key.
+typedef void (*RegistryKeyChangeCallback)(const TCHAR* key_name,
+                                          void* user_data);
+
+class RegistryMonitor {
+ public:
+  RegistryMonitor();
+  ~RegistryMonitor();
+
+  HRESULT Initialize();
+
+  // Monitors a registry sub key for changes. Registering the same sub key
+  // overrides the previous registration.
+  HRESULT MonitorKey(HKEY root_key,
+                     const CString& sub_key,
+                     RegistryKeyChangeCallback callback,
+                     void* user_data);
+
+  // Adds a registry value to the list of values to monitor for changes.
+  // All values must be registered before starting monitoring. Registering
+  // the same value is allowed, although not particularly useful.
+  HRESULT MonitorValue(HKEY root_key,
+                       const CString& sub_key,
+                       const CString& value_name,
+                       int value_type,
+                       RegistryValueChangeCallback callback,
+                       void* user_data);
+
+  // Starts monitoring for changes.
+  HRESULT StartMonitoring();
+
+ private:
+  scoped_ptr<detail::RegistryMonitorImpl> impl_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(RegistryMonitor);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_REGISTRY_MONITOR_MANAGER_H_
+
diff --git a/common/registry_monitor_manager_unittest.cc b/common/registry_monitor_manager_unittest.cc
index c9faa67..ef20634 100644
--- a/common/registry_monitor_manager_unittest.cc
+++ b/common/registry_monitor_manager_unittest.cc
@@ -1,235 +1,235 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <limits.h>

-#include "base/basictypes.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/reactor.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/registry_monitor_manager.h"

-#include "omaha/common/thread.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-const TCHAR kKeyNameFull[] = _T("HKCU\\key");

-const TCHAR kKeyName[]     = _T("key");

-const TCHAR kValueName[]   = _T("value");

-

-}  // namespace

-

-class RegistryMonitorTest : public testing::Test {

- protected:

-  RegistryMonitorTest() {}

-

-  virtual void SetUp() {

-    // Override HKCU.

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-    OverrideSpecifiedRegistryHives(kRegistryHiveOverrideRoot, false, true);

-    reset(registry_changed_event_, ::CreateEvent(NULL, true, false, NULL));

-  }

-

-  virtual void TearDown() {

-    reset(registry_changed_event_);

-    RestoreRegistryHives();

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-  }

-

-  static void RegistryDeleteCallback(const TCHAR* key_name,

-                                     const TCHAR* value_name,

-                                     RegistryChangeType change_type,

-                                     const void* new_value_data,

-                                     void* user_data) {

-    EXPECT_STREQ(kKeyName, key_name);

-    EXPECT_STREQ(kValueName, value_name);

-    EXPECT_EQ(REGISTRY_CHANGE_TYPE_DELETE, change_type);

-    EXPECT_TRUE(new_value_data);

-    EXPECT_TRUE(user_data);

-    RegistryMonitorTest* object = static_cast<RegistryMonitorTest*>(user_data);

-    DWORD actual_value = reinterpret_cast<DWORD>(new_value_data);

-    EXPECT_EQ(ULONG_MAX, actual_value);

-    EXPECT_TRUE(::SetEvent(get(object->registry_changed_event_)));

-  }

-

-  static void RegistryChangeCallback(const TCHAR* key_name,

-                                     const TCHAR* value_name,

-                                     RegistryChangeType change_type,

-                                     const void* new_value_data,

-                                     void* user_data) {

-    EXPECT_STREQ(kKeyName, key_name);

-    EXPECT_STREQ(kValueName, value_name);

-    EXPECT_EQ(REGISTRY_CHANGE_TYPE_UPDATE, change_type);

-    EXPECT_TRUE(new_value_data);

-    EXPECT_TRUE(user_data);

-    RegistryMonitorTest* object = static_cast<RegistryMonitorTest*>(user_data);

-    const TCHAR* actual_value = static_cast<const TCHAR*>(new_value_data);

-    EXPECT_STREQ(_T("foo"), actual_value);

-    EXPECT_TRUE(::SetEvent(get(object->registry_changed_event_)));

-  }

-

-  static void RegistryChangesCallback(const TCHAR* key_name,

-                                     const TCHAR* value_name,

-                                     RegistryChangeType change_type,

-                                     const void* new_value_data,

-                                     void* user_data) {

-    EXPECT_STREQ(kKeyName, key_name);

-    EXPECT_STREQ(kValueName, value_name);

-    EXPECT_EQ(REGISTRY_CHANGE_TYPE_UPDATE, change_type);

-    EXPECT_TRUE(new_value_data);

-    EXPECT_TRUE(user_data);

-    RegistryMonitorTest* object = static_cast<RegistryMonitorTest*>(user_data);

-    EXPECT_TRUE(::SetEvent(get(object->registry_changed_event_)));

-  }

-

-  static void RegistryCreateCallback(const TCHAR* key_name,

-                                     const TCHAR* value_name,

-                                     RegistryChangeType change_type,

-                                     const void* new_value_data,

-                                     void* user_data) {

-    EXPECT_STREQ(kKeyName, key_name);

-    EXPECT_STREQ(kValueName, value_name);

-    EXPECT_EQ(REGISTRY_CHANGE_TYPE_CREATE, change_type);

-    EXPECT_TRUE(new_value_data);

-    EXPECT_TRUE(user_data);

-    RegistryMonitorTest* object = static_cast<RegistryMonitorTest*>(user_data);

-    DWORD actual_value = reinterpret_cast<DWORD>(new_value_data);

-    EXPECT_EQ(1, actual_value);

-    EXPECT_TRUE(::SetEvent(get(object->registry_changed_event_)));

-  }

-

-  static void RegistryKeyCallback(const TCHAR* key_name, void* user_data) {

-    EXPECT_STREQ(kKeyName, key_name);

-    RegistryMonitorTest* object = static_cast<RegistryMonitorTest*>(user_data);

-    EXPECT_TRUE(::SetEvent(get(object->registry_changed_event_)));

-  }

-

-  scoped_event registry_changed_event_;

-

-  static DWORD const kWaitForChangeMs = 5000;

-};

-

-TEST_F(RegistryMonitorTest, DeleteValue) {

-  DWORD value = 0;

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull, kValueName, value));

-  RegistryMonitor registry_monitor;

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.Initialize());

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(

-      HKEY_CURRENT_USER, kKeyName, kValueName, REG_DWORD,

-      RegistryDeleteCallback, this));

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.StartMonitoring());

-

-  EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteValue(kKeyNameFull, kValueName));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),

-                                                 kWaitForChangeMs));

-}

-

-TEST_F(RegistryMonitorTest, ChangeValue) {

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull, kValueName, _T("")));

-  RegistryMonitor registry_monitor;

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.Initialize());

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(

-    HKEY_CURRENT_USER, kKeyName, kValueName, REG_SZ,

-    RegistryChangeCallback, this));

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.StartMonitoring());

-

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull,

-                                            kValueName,

-                                            _T("foo")));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),

-                                                 kWaitForChangeMs));

-}

-

-// Tests changing the same value two times. This is useful to detect if

-// the key is registered back for notification after a succesful callback.

-TEST_F(RegistryMonitorTest, ChangeValues) {

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull,

-                                            kValueName,

-                                            _T("")));

-

-  RegistryMonitor registry_monitor;

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.Initialize());

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(

-      HKEY_CURRENT_USER, kKeyName, kValueName, REG_SZ,

-      RegistryChangesCallback, this));

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.StartMonitoring());

-

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull,

-                                            kValueName,

-                                            _T("foo")));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),

-                                                 kWaitForChangeMs));

-  EXPECT_TRUE(::ResetEvent(get(registry_changed_event_)));

-

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull,

-                                            kValueName,

-                                            _T("bar")));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),

-                                                 kWaitForChangeMs));

-}

-

-TEST_F(RegistryMonitorTest, CreateValue) {

-  RegistryMonitor registry_monitor;

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.Initialize());

-  ASSERT_HRESULT_SUCCEEDED(RegKey::CreateKey(kKeyNameFull));

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(

-      HKEY_CURRENT_USER, kKeyName, kValueName, REG_DWORD,

-      RegistryCreateCallback, this));

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.StartMonitoring());

-

-  DWORD value = 1;

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull, kValueName, value));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),

-                                                 kWaitForChangeMs));

-}

-

-// Monitoring values under the same key pair is allowed.

-TEST_F(RegistryMonitorTest, MonitorSame) {

-  RegistryMonitor registry_monitor;

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.Initialize());

-  ASSERT_HRESULT_SUCCEEDED(RegKey::CreateKey(kKeyNameFull));

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(

-      HKEY_CURRENT_USER, kKeyName, kValueName, REG_DWORD,

-      RegistryCreateCallback, this));

-  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(

-      HKEY_CURRENT_USER, kKeyName, kValueName, REG_DWORD,

-      RegistryCreateCallback, this));

-}

-

-TEST_F(RegistryMonitorTest, MonitorKey) {

-  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKey(kKeyNameFull));

-

-  RegistryMonitor registry_monitor;

-  EXPECT_HRESULT_SUCCEEDED(registry_monitor.Initialize());

-  EXPECT_HRESULT_SUCCEEDED(registry_monitor.MonitorKey(

-      HKEY_CURRENT_USER, kKeyName, RegistryKeyCallback, this));

-

-  EXPECT_HRESULT_SUCCEEDED(registry_monitor.StartMonitoring());

-

-  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKey(_T("HKCU\\key\\subkey")));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),

-                                                 kWaitForChangeMs));

-

-  EXPECT_TRUE(::ResetEvent(get(registry_changed_event_)));

-  EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteKey(_T("HKCU\\key\\subkey")));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),

-                                                 kWaitForChangeMs));

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <limits.h>
+#include "base/basictypes.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/reactor.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/registry_monitor_manager.h"
+#include "omaha/common/thread.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+const TCHAR kKeyNameFull[] = _T("HKCU\\key");
+const TCHAR kKeyName[]     = _T("key");
+const TCHAR kValueName[]   = _T("value");
+
+}  // namespace
+
+class RegistryMonitorTest : public testing::Test {
+ protected:
+  RegistryMonitorTest() {}
+
+  virtual void SetUp() {
+    // Override HKCU.
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+    OverrideSpecifiedRegistryHives(kRegistryHiveOverrideRoot, false, true);
+    reset(registry_changed_event_, ::CreateEvent(NULL, true, false, NULL));
+  }
+
+  virtual void TearDown() {
+    reset(registry_changed_event_);
+    RestoreRegistryHives();
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+  }
+
+  static void RegistryDeleteCallback(const TCHAR* key_name,
+                                     const TCHAR* value_name,
+                                     RegistryChangeType change_type,
+                                     const void* new_value_data,
+                                     void* user_data) {
+    EXPECT_STREQ(kKeyName, key_name);
+    EXPECT_STREQ(kValueName, value_name);
+    EXPECT_EQ(REGISTRY_CHANGE_TYPE_DELETE, change_type);
+    EXPECT_TRUE(new_value_data);
+    EXPECT_TRUE(user_data);
+    RegistryMonitorTest* object = static_cast<RegistryMonitorTest*>(user_data);
+    DWORD actual_value = reinterpret_cast<DWORD>(new_value_data);
+    EXPECT_EQ(ULONG_MAX, actual_value);
+    EXPECT_TRUE(::SetEvent(get(object->registry_changed_event_)));
+  }
+
+  static void RegistryChangeCallback(const TCHAR* key_name,
+                                     const TCHAR* value_name,
+                                     RegistryChangeType change_type,
+                                     const void* new_value_data,
+                                     void* user_data) {
+    EXPECT_STREQ(kKeyName, key_name);
+    EXPECT_STREQ(kValueName, value_name);
+    EXPECT_EQ(REGISTRY_CHANGE_TYPE_UPDATE, change_type);
+    EXPECT_TRUE(new_value_data);
+    EXPECT_TRUE(user_data);
+    RegistryMonitorTest* object = static_cast<RegistryMonitorTest*>(user_data);
+    const TCHAR* actual_value = static_cast<const TCHAR*>(new_value_data);
+    EXPECT_STREQ(_T("foo"), actual_value);
+    EXPECT_TRUE(::SetEvent(get(object->registry_changed_event_)));
+  }
+
+  static void RegistryChangesCallback(const TCHAR* key_name,
+                                     const TCHAR* value_name,
+                                     RegistryChangeType change_type,
+                                     const void* new_value_data,
+                                     void* user_data) {
+    EXPECT_STREQ(kKeyName, key_name);
+    EXPECT_STREQ(kValueName, value_name);
+    EXPECT_EQ(REGISTRY_CHANGE_TYPE_UPDATE, change_type);
+    EXPECT_TRUE(new_value_data);
+    EXPECT_TRUE(user_data);
+    RegistryMonitorTest* object = static_cast<RegistryMonitorTest*>(user_data);
+    EXPECT_TRUE(::SetEvent(get(object->registry_changed_event_)));
+  }
+
+  static void RegistryCreateCallback(const TCHAR* key_name,
+                                     const TCHAR* value_name,
+                                     RegistryChangeType change_type,
+                                     const void* new_value_data,
+                                     void* user_data) {
+    EXPECT_STREQ(kKeyName, key_name);
+    EXPECT_STREQ(kValueName, value_name);
+    EXPECT_EQ(REGISTRY_CHANGE_TYPE_CREATE, change_type);
+    EXPECT_TRUE(new_value_data);
+    EXPECT_TRUE(user_data);
+    RegistryMonitorTest* object = static_cast<RegistryMonitorTest*>(user_data);
+    DWORD actual_value = reinterpret_cast<DWORD>(new_value_data);
+    EXPECT_EQ(1, actual_value);
+    EXPECT_TRUE(::SetEvent(get(object->registry_changed_event_)));
+  }
+
+  static void RegistryKeyCallback(const TCHAR* key_name, void* user_data) {
+    EXPECT_STREQ(kKeyName, key_name);
+    RegistryMonitorTest* object = static_cast<RegistryMonitorTest*>(user_data);
+    EXPECT_TRUE(::SetEvent(get(object->registry_changed_event_)));
+  }
+
+  scoped_event registry_changed_event_;
+
+  static DWORD const kWaitForChangeMs = 5000;
+};
+
+TEST_F(RegistryMonitorTest, DeleteValue) {
+  DWORD value = 0;
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull, kValueName, value));
+  RegistryMonitor registry_monitor;
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.Initialize());
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(
+      HKEY_CURRENT_USER, kKeyName, kValueName, REG_DWORD,
+      RegistryDeleteCallback, this));
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.StartMonitoring());
+
+  EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteValue(kKeyNameFull, kValueName));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),
+                                                 kWaitForChangeMs));
+}
+
+TEST_F(RegistryMonitorTest, ChangeValue) {
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull, kValueName, _T("")));
+  RegistryMonitor registry_monitor;
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.Initialize());
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(
+    HKEY_CURRENT_USER, kKeyName, kValueName, REG_SZ,
+    RegistryChangeCallback, this));
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.StartMonitoring());
+
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull,
+                                            kValueName,
+                                            _T("foo")));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),
+                                                 kWaitForChangeMs));
+}
+
+// Tests changing the same value two times. This is useful to detect if
+// the key is registered back for notification after a succesful callback.
+TEST_F(RegistryMonitorTest, ChangeValues) {
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull,
+                                            kValueName,
+                                            _T("")));
+
+  RegistryMonitor registry_monitor;
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.Initialize());
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(
+      HKEY_CURRENT_USER, kKeyName, kValueName, REG_SZ,
+      RegistryChangesCallback, this));
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.StartMonitoring());
+
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull,
+                                            kValueName,
+                                            _T("foo")));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),
+                                                 kWaitForChangeMs));
+  EXPECT_TRUE(::ResetEvent(get(registry_changed_event_)));
+
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull,
+                                            kValueName,
+                                            _T("bar")));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),
+                                                 kWaitForChangeMs));
+}
+
+TEST_F(RegistryMonitorTest, CreateValue) {
+  RegistryMonitor registry_monitor;
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.Initialize());
+  ASSERT_HRESULT_SUCCEEDED(RegKey::CreateKey(kKeyNameFull));
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(
+      HKEY_CURRENT_USER, kKeyName, kValueName, REG_DWORD,
+      RegistryCreateCallback, this));
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.StartMonitoring());
+
+  DWORD value = 1;
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(kKeyNameFull, kValueName, value));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),
+                                                 kWaitForChangeMs));
+}
+
+// Monitoring values under the same key pair is allowed.
+TEST_F(RegistryMonitorTest, MonitorSame) {
+  RegistryMonitor registry_monitor;
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.Initialize());
+  ASSERT_HRESULT_SUCCEEDED(RegKey::CreateKey(kKeyNameFull));
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(
+      HKEY_CURRENT_USER, kKeyName, kValueName, REG_DWORD,
+      RegistryCreateCallback, this));
+  ASSERT_HRESULT_SUCCEEDED(registry_monitor.MonitorValue(
+      HKEY_CURRENT_USER, kKeyName, kValueName, REG_DWORD,
+      RegistryCreateCallback, this));
+}
+
+TEST_F(RegistryMonitorTest, MonitorKey) {
+  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKey(kKeyNameFull));
+
+  RegistryMonitor registry_monitor;
+  EXPECT_HRESULT_SUCCEEDED(registry_monitor.Initialize());
+  EXPECT_HRESULT_SUCCEEDED(registry_monitor.MonitorKey(
+      HKEY_CURRENT_USER, kKeyName, RegistryKeyCallback, this));
+
+  EXPECT_HRESULT_SUCCEEDED(registry_monitor.StartMonitoring());
+
+  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKey(_T("HKCU\\key\\subkey")));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),
+                                                 kWaitForChangeMs));
+
+  EXPECT_TRUE(::ResetEvent(get(registry_changed_event_)));
+  EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteKey(_T("HKCU\\key\\subkey")));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(registry_changed_event_),
+                                                 kWaitForChangeMs));
+}
+
+}  // namespace omaha
+
diff --git a/common/registry_store.cc b/common/registry_store.cc
index fec1e25..dca1d63 100644
--- a/common/registry_store.cc
+++ b/common/registry_store.cc
@@ -1,115 +1,115 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/registry_store.h"

-#include <vector>

-#include "omaha/common/debug.h"

-#include "omaha/common/reg_key.h"

-

-namespace omaha {

-

-bool RegistryStore::Open(const TCHAR* key_path) {

-  key_path_ = key_path;

-  return true;

-}

-

-bool RegistryStore::Close() {

-  key_path_.Empty();

-  return true;

-}

-

-bool RegistryStore::Clear() {

-  if (RegKey::HasKey(key_path_)) {

-    return SUCCEEDED(RegKey::DeleteKey(key_path_, false));

-  } else {

-    return true;

-  }

-}

-

-bool RegistryStore::Read(const TCHAR* name, std::vector<byte>* data) const {

-  ASSERT1(name);

-  ASSERT1(data);

-

-  byte* sdata = NULL;

-  DWORD sdata_size = 0;

-  HRESULT hr = RegKey::GetValue(key_path_, name, &sdata, &sdata_size);

-  if (FAILED(hr) || !sdata || !sdata_size)

-    return false;

-

-  data->resize(sdata_size);

-  memcpy(&data->front(), sdata, sdata_size);

-

-  delete[] sdata;

-

-  return true;

-}

-

-bool RegistryStore::Write(const TCHAR* name, byte* data, int data_size) {

-  ASSERT1(name);

-  ASSERT1(data);

-  ASSERT1(data_size);

-

-  return SUCCEEDED(RegKey::SetValue(key_path_, name, data, data_size));

-}

-

-bool RegistryStore::Exists(const TCHAR* name) {

-  ASSERT1(name);

-

-  return RegKey::HasValue(key_path_, name);

-}

-

-bool RegistryStore::Remove(const TCHAR* name) {

-  ASSERT1(name);

-

-  return SUCCEEDED(RegKey::DeleteValue(key_path_, name));

-}

-

-bool RegistryStore::GetValueCount(uint32* value_count) {

-  ASSERT1(value_count);

-

-  CString key_name(key_path_);

-  HKEY h_key = RegKey::GetRootKeyInfo(&key_name);

-

-  RegKey reg_key;

-  if (FAILED(reg_key.Open(h_key, key_name.GetString(), KEY_READ)))

-    return false;

-

-  *value_count = reg_key.GetValueCount();

-

-  reg_key.Close();

-

-  return true;

-}

-

-bool RegistryStore::GetValueNameAt(int index, CString* value_name) {

-  ASSERT1(index >= 0);

-  ASSERT1(value_name);

-

-  CString key_name(key_path_);

-  HKEY h_key = RegKey::GetRootKeyInfo(&key_name);

-

-  RegKey reg_key;

-  if (FAILED(reg_key.Open(h_key, key_name.GetString(), KEY_READ)))

-    return false;

-

-  HRESULT hr = reg_key.GetValueNameAt(index, value_name, NULL);

-

-  reg_key.Close();

-

-  return SUCCEEDED(hr);

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/registry_store.h"
+#include <vector>
+#include "omaha/common/debug.h"
+#include "omaha/common/reg_key.h"
+
+namespace omaha {
+
+bool RegistryStore::Open(const TCHAR* key_path) {
+  key_path_ = key_path;
+  return true;
+}
+
+bool RegistryStore::Close() {
+  key_path_.Empty();
+  return true;
+}
+
+bool RegistryStore::Clear() {
+  if (RegKey::HasKey(key_path_)) {
+    return SUCCEEDED(RegKey::DeleteKey(key_path_, false));
+  } else {
+    return true;
+  }
+}
+
+bool RegistryStore::Read(const TCHAR* name, std::vector<byte>* data) const {
+  ASSERT1(name);
+  ASSERT1(data);
+
+  byte* sdata = NULL;
+  DWORD sdata_size = 0;
+  HRESULT hr = RegKey::GetValue(key_path_, name, &sdata, &sdata_size);
+  if (FAILED(hr) || !sdata || !sdata_size)
+    return false;
+
+  data->resize(sdata_size);
+  memcpy(&data->front(), sdata, sdata_size);
+
+  delete[] sdata;
+
+  return true;
+}
+
+bool RegistryStore::Write(const TCHAR* name, byte* data, int data_size) {
+  ASSERT1(name);
+  ASSERT1(data);
+  ASSERT1(data_size);
+
+  return SUCCEEDED(RegKey::SetValue(key_path_, name, data, data_size));
+}
+
+bool RegistryStore::Exists(const TCHAR* name) {
+  ASSERT1(name);
+
+  return RegKey::HasValue(key_path_, name);
+}
+
+bool RegistryStore::Remove(const TCHAR* name) {
+  ASSERT1(name);
+
+  return SUCCEEDED(RegKey::DeleteValue(key_path_, name));
+}
+
+bool RegistryStore::GetValueCount(uint32* value_count) {
+  ASSERT1(value_count);
+
+  CString key_name(key_path_);
+  HKEY h_key = RegKey::GetRootKeyInfo(&key_name);
+
+  RegKey reg_key;
+  if (FAILED(reg_key.Open(h_key, key_name.GetString(), KEY_READ)))
+    return false;
+
+  *value_count = reg_key.GetValueCount();
+
+  reg_key.Close();
+
+  return true;
+}
+
+bool RegistryStore::GetValueNameAt(int index, CString* value_name) {
+  ASSERT1(index >= 0);
+  ASSERT1(value_name);
+
+  CString key_name(key_path_);
+  HKEY h_key = RegKey::GetRootKeyInfo(&key_name);
+
+  RegKey reg_key;
+  if (FAILED(reg_key.Open(h_key, key_name.GetString(), KEY_READ)))
+    return false;
+
+  HRESULT hr = reg_key.GetValueNameAt(index, value_name, NULL);
+
+  reg_key.Close();
+
+  return SUCCEEDED(hr);
+}
+
+}  // namespace omaha
+
diff --git a/common/registry_store.h b/common/registry_store.h
index ae304fa..d7e55cb 100644
--- a/common/registry_store.h
+++ b/common/registry_store.h
@@ -1,70 +1,70 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Declares class RegistryStore

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

-

-#ifndef OMAHA_COMMON_REGISTRY_STORE_H__

-#define OMAHA_COMMON_REGISTRY_STORE_H__

-

-#include <wtypes.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class RegistryStore {

- public:

-  // Constructor

-  RegistryStore() {}

-

-  // Destructor

-  ~RegistryStore() {}

-

-  // Open the store

-  bool Open(const TCHAR* key_path);

-

-  // Close the store

-  bool Close();

-

-  // Clear the store

-  bool Clear();

-

-  // Read a value from the store

-  bool Read(const TCHAR* name, std::vector<byte>* data) const;

-

-  // Write a value to the store

-  bool Write(const TCHAR* name, byte* data, int data_size);

-

-  // Check to see a named value exists in the store

-  bool Exists(const TCHAR* name);

-

-  // Remove a value from the store

-  bool Remove(const TCHAR* name);

-

-  // Get the number of values for this key

-  bool GetValueCount(uint32* value_count);

-

-  // Get the value name for the given value name index

-  bool GetValueNameAt(int index, CString* value_name);

-

- private:

-  CString key_path_;      // Full path to the registry key

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_REGISTRY_STORE_H__

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Declares class RegistryStore
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef OMAHA_COMMON_REGISTRY_STORE_H__
+#define OMAHA_COMMON_REGISTRY_STORE_H__
+
+#include <wtypes.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class RegistryStore {
+ public:
+  // Constructor
+  RegistryStore() {}
+
+  // Destructor
+  ~RegistryStore() {}
+
+  // Open the store
+  bool Open(const TCHAR* key_path);
+
+  // Close the store
+  bool Close();
+
+  // Clear the store
+  bool Clear();
+
+  // Read a value from the store
+  bool Read(const TCHAR* name, std::vector<byte>* data) const;
+
+  // Write a value to the store
+  bool Write(const TCHAR* name, byte* data, int data_size);
+
+  // Check to see a named value exists in the store
+  bool Exists(const TCHAR* name);
+
+  // Remove a value from the store
+  bool Remove(const TCHAR* name);
+
+  // Get the number of values for this key
+  bool GetValueCount(uint32* value_count);
+
+  // Get the value name for the given value name index
+  bool GetValueNameAt(int index, CString* value_name);
+
+ private:
+  CString key_path_;      // Full path to the registry key
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_REGISTRY_STORE_H__
diff --git a/common/registry_store_unittest.cc b/common/registry_store_unittest.cc
index 47ae8b3..c75de3a 100644
--- a/common/registry_store_unittest.cc
+++ b/common/registry_store_unittest.cc
@@ -1,75 +1,75 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Unit test for RegistryStore.

-

-#include "omaha/common/registry_store.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-static const TCHAR kRSTestKey[] =

-    _T("HKCU\\Software\\Google\\Common_Installer__TEST_STORE");

-static const TCHAR kRSTestName[] = _T("TestValueName");

-static const byte kRSTestValue[] = {0x01, 0x02, 0x03, 0x04, 0x05};

-static const int kRSTestValueSize = arraysize(kRSTestValue);

-

-TEST(RegistryStoreTest, RegistryStore) {

-  RegistryStore registry_store;

-  uint32 value_count = 42; // We want to make sure it's overwritten with 0.

-  CString value_name;

-  std::vector<byte> data;

-

-  // Set up and get in a known state.

-  EXPECT_TRUE(registry_store.Open(kRSTestKey));

-  EXPECT_TRUE(registry_store.Clear());

-

-  // Add and test a single value

-  EXPECT_FALSE(registry_store.Exists(kRSTestName));

-  EXPECT_FALSE(registry_store.Read(kRSTestName, &data));

-  data.clear();

-

-  EXPECT_TRUE(registry_store.Write(kRSTestName,

-                                   const_cast<byte*>(kRSTestValue),

-                                   kRSTestValueSize));

-

-  EXPECT_TRUE(registry_store.Exists(kRSTestName));

-  EXPECT_TRUE(registry_store.Read(kRSTestName, &data));

-  EXPECT_EQ(data.size(), kRSTestValueSize);

-  for (int i = 0; i < kRSTestValueSize; i++)

-    EXPECT_EQ(data[i], kRSTestValue[i]);

-

-  // Remove and re-add value

-  EXPECT_TRUE(registry_store.Remove(kRSTestName));

-  EXPECT_FALSE(registry_store.Exists(kRSTestName));

-  EXPECT_TRUE(registry_store.GetValueCount(&value_count));

-  EXPECT_EQ(value_count, 0);

-  EXPECT_TRUE(registry_store.Write(kRSTestName,

-                                   const_cast<byte*>(kRSTestValue),

-                                   kRSTestValueSize));

-  EXPECT_TRUE(registry_store.GetValueCount(&value_count));

-  EXPECT_EQ(value_count, 1);

-  EXPECT_TRUE(registry_store.GetValueNameAt(0, &value_name));

-  EXPECT_TRUE(value_name == kRSTestName);

-

-  // Clean up and finish.

-  EXPECT_TRUE(registry_store.Clear());

-  EXPECT_FALSE(registry_store.Exists(kRSTestName));

-  EXPECT_FALSE(registry_store.GetValueCount(&value_count));

-  EXPECT_TRUE(registry_store.Close());

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Unit test for RegistryStore.
+
+#include "omaha/common/registry_store.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+static const TCHAR kRSTestKey[] =
+    _T("HKCU\\Software\\Google\\Common_Installer__TEST_STORE");
+static const TCHAR kRSTestName[] = _T("TestValueName");
+static const byte kRSTestValue[] = {0x01, 0x02, 0x03, 0x04, 0x05};
+static const int kRSTestValueSize = arraysize(kRSTestValue);
+
+TEST(RegistryStoreTest, RegistryStore) {
+  RegistryStore registry_store;
+  uint32 value_count = 42; // We want to make sure it's overwritten with 0.
+  CString value_name;
+  std::vector<byte> data;
+
+  // Set up and get in a known state.
+  EXPECT_TRUE(registry_store.Open(kRSTestKey));
+  EXPECT_TRUE(registry_store.Clear());
+
+  // Add and test a single value
+  EXPECT_FALSE(registry_store.Exists(kRSTestName));
+  EXPECT_FALSE(registry_store.Read(kRSTestName, &data));
+  data.clear();
+
+  EXPECT_TRUE(registry_store.Write(kRSTestName,
+                                   const_cast<byte*>(kRSTestValue),
+                                   kRSTestValueSize));
+
+  EXPECT_TRUE(registry_store.Exists(kRSTestName));
+  EXPECT_TRUE(registry_store.Read(kRSTestName, &data));
+  EXPECT_EQ(data.size(), kRSTestValueSize);
+  for (int i = 0; i < kRSTestValueSize; i++)
+    EXPECT_EQ(data[i], kRSTestValue[i]);
+
+  // Remove and re-add value
+  EXPECT_TRUE(registry_store.Remove(kRSTestName));
+  EXPECT_FALSE(registry_store.Exists(kRSTestName));
+  EXPECT_TRUE(registry_store.GetValueCount(&value_count));
+  EXPECT_EQ(value_count, 0);
+  EXPECT_TRUE(registry_store.Write(kRSTestName,
+                                   const_cast<byte*>(kRSTestValue),
+                                   kRSTestValueSize));
+  EXPECT_TRUE(registry_store.GetValueCount(&value_count));
+  EXPECT_EQ(value_count, 1);
+  EXPECT_TRUE(registry_store.GetValueNameAt(0, &value_name));
+  EXPECT_TRUE(value_name == kRSTestName);
+
+  // Clean up and finish.
+  EXPECT_TRUE(registry_store.Clear());
+  EXPECT_FALSE(registry_store.Exists(kRSTestName));
+  EXPECT_FALSE(registry_store.GetValueCount(&value_count));
+  EXPECT_TRUE(registry_store.Close());
+}
+
+}  // namespace omaha
diff --git a/common/run_as_invoker.manifest b/common/run_as_invoker.manifest
index a485609..c3263b5 100644
--- a/common/run_as_invoker.manifest
+++ b/common/run_as_invoker.manifest
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="utf-8"?>

-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

-  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">

-    <security>

-      <requestedPrivileges>

-        <requestedExecutionLevel level="asInvoker" />

-      </requestedPrivileges>

-    </security>

-  </trustInfo>

-</assembly>

+<?xml version="1.0" encoding="utf-8"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+</assembly>
diff --git a/common/run_as_invoker.rc b/common/run_as_invoker.rc
index 997ab2b..4ab0dfb 100644
--- a/common/run_as_invoker.rc
+++ b/common/run_as_invoker.rc
@@ -1,21 +1,21 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "afxres.h"

-

-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

-#pragma code_page(1252)

-

-1 RT_MANIFEST "run_as_invoker.manifest"

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "afxres.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+1 RT_MANIFEST "run_as_invoker.manifest"
diff --git a/common/scope_guard.h b/common/scope_guard.h
index b889142..326dc0c 100644
--- a/common/scope_guard.h
+++ b/common/scope_guard.h
@@ -1,337 +1,337 @@
-//

-// Author: Andrei Alexandrescu - andrei@metalanguage.com

-//

-// The code below is based on the following article published in

-// C/C++ Users Journal by Andrei Alexandrescu:

-//

-// http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm

-//

-// ScopeGuard is useful when you need to perform automatic cleanup of resources.

-// This idiom is important when you want to assemble an operation out of several

-// atomic operations, each of which could fail.

-//

-// Usage

-// ------

-// Scope guard for objects:

-// void f(T& t) {

-//   std::vector<T> v;

-//   v.push_back(t);

-//   ScopeGuard guard = MakeObjGuard(v, &std::vector<T>v::pop_back);

-//   if (!Commit()) {

-//     return;

-//   }

-//   guard.Dismiss();     // removes the t from the vector in the case Commit fails

-// }

-//

-// Scope guard for functions:

-// void open();

-// void close(int i);

-// void g(int i) {

-//   open();

-//   ScopeGuard guard = MakeGuard(close, 0);

-//   if (!read()) {

-//       return;

-//   }

-//   if (!write()) {

-//       return;

-//   }

-// }

-//

-// Using the macros:

-// void g(int i) {

-//   open();

-//   ON_SCOPE_EXIT(close, 0);

-//   if (!read()) {

-//       return;

-//   }

-//   if (!write()) {

-//       return;

-//   }

-// }

-

-// TODO(omaha): provide support to run with or without exceptions enabled.

-// For now it assumes that the code is not throwing exceptions.

-#ifndef SCOPEGUARD_H_

-#define SCOPEGUARD_H_

-

-namespace omaha {

-

-template <class T>

-class RefHolder

-{

-  T& ref_;

-public:

-  RefHolder(T& ref) : ref_(ref) {}

-  operator T& () const

-  {

-    return ref_;

-  }

-private:

-    // Disable assignment - not implemented

-    RefHolder& operator=(const RefHolder&);

-};

-

-template <class T>

-inline RefHolder<T> ByRef(T& t)

-{

-  return RefHolder<T>(t);

-}

-

-class ScopeGuardImplBase

-{

-  ScopeGuardImplBase& operator =(const ScopeGuardImplBase&);

-protected:

-  ~ScopeGuardImplBase()

-  {

-  }

-  ScopeGuardImplBase(const ScopeGuardImplBase& other) throw()

-    : dismissed_(other.dismissed_)

-  {

-    other.Dismiss();

-  }

-  template <typename J>

-  static void SafeExecute(J& j) throw()

-  {

-    if (!j.dismissed_)

-    {

-      // TODO(omaha): assume this does not throw

-      j.Execute();

-    }

-  }

-

-  mutable bool dismissed_;

-public:

-  ScopeGuardImplBase() throw() : dismissed_(false)

-  {

-  }

-  void Dismiss() const throw()

-  {

-    dismissed_ = true;

-  }

-};

-

-typedef const ScopeGuardImplBase& ScopeGuard;

-

-template <typename F>

-class ScopeGuardImpl0 : public ScopeGuardImplBase

-{

-public:

-  static ScopeGuardImpl0<F> MakeGuard(F fun)

-  {

-    return ScopeGuardImpl0<F>(fun);

-  }

-  ~ScopeGuardImpl0() throw()

-  {

-    SafeExecute(*this);

-  }

-  void Execute()

-  {

-    fun_();

-  }

-protected:

-  ScopeGuardImpl0(F fun) : fun_(fun)

-  {

-  }

-  F fun_;

-};

-

-template <typename F>

-inline ScopeGuardImpl0<F> MakeGuard(F fun)

-{

-  return ScopeGuardImpl0<F>::MakeGuard(fun);

-}

-

-template <typename F, typename P1>

-class ScopeGuardImpl1 : public ScopeGuardImplBase

-{

-public:

-  static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)

-  {

-    return ScopeGuardImpl1<F, P1>(fun, p1);

-  }

-  ~ScopeGuardImpl1() throw()

-  {

-    SafeExecute(*this);

-  }

-  void Execute()

-  {

-    fun_(p1_);

-  }

-protected:

-  ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1)

-  {

-  }

-  F fun_;

-  const P1 p1_;

-};

-

-template <typename F, typename P1>

-inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)

-{

-  return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);

-}

-

-template <typename F, typename P1, typename P2>

-class ScopeGuardImpl2: public ScopeGuardImplBase

-{

-public:

-  static ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2)

-  {

-    return ScopeGuardImpl2<F, P1, P2>(fun, p1, p2);

-  }

-  ~ScopeGuardImpl2() throw()

-  {

-    SafeExecute(*this);

-  }

-  void Execute()

-  {

-    fun_(p1_, p2_);

-  }

-protected:

-  ScopeGuardImpl2(F fun, P1 p1, P2 p2) : fun_(fun), p1_(p1), p2_(p2)

-  {

-  }

-  F fun_;

-  const P1 p1_;

-  const P2 p2_;

-};

-

-template <typename F, typename P1, typename P2>

-inline ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2)

-{

-  return ScopeGuardImpl2<F, P1, P2>::MakeGuard(fun, p1, p2);

-}

-

-template <typename F, typename P1, typename P2, typename P3>

-class ScopeGuardImpl3 : public ScopeGuardImplBase

-{

-public:

-  static ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3)

-  {

-    return ScopeGuardImpl3<F, P1, P2, P3>(fun, p1, p2, p3);

-  }

-  ~ScopeGuardImpl3() throw()

-  {

-    SafeExecute(*this);

-  }

-  void Execute()

-  {

-    fun_(p1_, p2_, p3_);

-  }

-protected:

-  ScopeGuardImpl3(F fun, P1 p1, P2 p2, P3 p3) : fun_(fun), p1_(p1), p2_(p2), p3_(p3)

-  {

-  }

-  F fun_;

-  const P1 p1_;

-  const P2 p2_;

-  const P3 p3_;

-};

-

-template <typename F, typename P1, typename P2, typename P3>

-inline ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3)

-{

-  return ScopeGuardImpl3<F, P1, P2, P3>::MakeGuard(fun, p1, p2, p3);

-}

-

-

-template <class Obj, typename MemFun>

-class ObjScopeGuardImpl0 : public ScopeGuardImplBase

-{

-public:

-  static ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun)

-  {

-    return ObjScopeGuardImpl0<Obj, MemFun>(obj, memFun);

-  }

-  ~ObjScopeGuardImpl0() throw()

-  {

-    SafeExecute(*this);

-  }

-  void Execute()

-  {

-    (obj_.*memFun_)();

-  }

-protected:

-  ObjScopeGuardImpl0(Obj& obj, MemFun memFun)

-    : obj_(obj), memFun_(memFun) {}

-  Obj& obj_;

-  MemFun memFun_;

-};

-

-template <class Obj, typename MemFun>

-inline ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun)

-{

-  return ObjScopeGuardImpl0<Obj, MemFun>::MakeObjGuard(obj, memFun);

-}

-

-template <class Obj, typename MemFun, typename P1>

-class ObjScopeGuardImpl1 : public ScopeGuardImplBase

-{

-public:

-  static ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1)

-  {

-    return ObjScopeGuardImpl1<Obj, MemFun, P1>(obj, memFun, p1);

-  }

-  ~ObjScopeGuardImpl1() throw()

-  {

-    SafeExecute(*this);

-  }

-  void Execute()

-  {

-    (obj_.*memFun_)(p1_);

-  }

-protected:

-  ObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1)

-    : obj_(obj), memFun_(memFun), p1_(p1) {}

-  Obj& obj_;

-  MemFun memFun_;

-  const P1 p1_;

-};

-

-template <class Obj, typename MemFun, typename P1>

-inline ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1)

-{

-  return ObjScopeGuardImpl1<Obj, MemFun, P1>::MakeObjGuard(obj, memFun, p1);

-}

-

-template <class Obj, typename MemFun, typename P1, typename P2>

-class ObjScopeGuardImpl2 : public ScopeGuardImplBase

-{

-public:

-  static ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2)

-  {

-    return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>(obj, memFun, p1, p2);

-  }

-  ~ObjScopeGuardImpl2() throw()

-  {

-    SafeExecute(*this);

-  }

-  void Execute()

-  {

-    (obj_.*memFun_)(p1_, p2_);

-  }

-protected:

-  ObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2)

-    : obj_(obj), memFun_(memFun), p1_(p1), p2_(p2) {}

-  Obj& obj_;

-  MemFun memFun_;

-  const P1 p1_;

-  const P2 p2_;

-};

-

-template <class Obj, typename MemFun, typename P1, typename P2>

-inline ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2)

-{

-  return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>::MakeObjGuard(obj, memFun, p1, p2);

-}

-

-#define CONCATENATE_DIRECT(s1, s2) s1##s2

-#define CONCATENATE(s1, s2) CONCATENATE_DIRECT(s1, s2)

-#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__)

-

-#define ON_SCOPE_EXIT ScopeGuard ANONYMOUS_VARIABLE(scopeGuard) = MakeGuard

-#define ON_SCOPE_EXIT_OBJ ScopeGuard ANONYMOUS_VARIABLE(scopeGuard) = MakeObjGuard

-

-}  // namespace omaha

-

-#endif //SCOPEGUARD_H_

+//
+// Author: Andrei Alexandrescu - andrei@metalanguage.com
+//
+// The code below is based on the following article published in
+// C/C++ Users Journal by Andrei Alexandrescu:
+//
+// http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm
+//
+// ScopeGuard is useful when you need to perform automatic cleanup of resources.
+// This idiom is important when you want to assemble an operation out of several
+// atomic operations, each of which could fail.
+//
+// Usage
+// ------
+// Scope guard for objects:
+// void f(T& t) {
+//   std::vector<T> v;
+//   v.push_back(t);
+//   ScopeGuard guard = MakeObjGuard(v, &std::vector<T>v::pop_back);
+//   if (!Commit()) {
+//     return;
+//   }
+//   guard.Dismiss();     // removes the t from the vector in the case Commit fails
+// }
+//
+// Scope guard for functions:
+// void open();
+// void close(int i);
+// void g(int i) {
+//   open();
+//   ScopeGuard guard = MakeGuard(close, 0);
+//   if (!read()) {
+//       return;
+//   }
+//   if (!write()) {
+//       return;
+//   }
+// }
+//
+// Using the macros:
+// void g(int i) {
+//   open();
+//   ON_SCOPE_EXIT(close, 0);
+//   if (!read()) {
+//       return;
+//   }
+//   if (!write()) {
+//       return;
+//   }
+// }
+
+// TODO(omaha): provide support to run with or without exceptions enabled.
+// For now it assumes that the code is not throwing exceptions.
+#ifndef SCOPEGUARD_H_
+#define SCOPEGUARD_H_
+
+namespace omaha {
+
+template <class T>
+class RefHolder
+{
+  T& ref_;
+public:
+  RefHolder(T& ref) : ref_(ref) {}
+  operator T& () const
+  {
+    return ref_;
+  }
+private:
+    // Disable assignment - not implemented
+    RefHolder& operator=(const RefHolder&);
+};
+
+template <class T>
+inline RefHolder<T> ByRef(T& t)
+{
+  return RefHolder<T>(t);
+}
+
+class ScopeGuardImplBase
+{
+  ScopeGuardImplBase& operator =(const ScopeGuardImplBase&);
+protected:
+  ~ScopeGuardImplBase()
+  {
+  }
+  ScopeGuardImplBase(const ScopeGuardImplBase& other) throw()
+    : dismissed_(other.dismissed_)
+  {
+    other.Dismiss();
+  }
+  template <typename J>
+  static void SafeExecute(J& j) throw()
+  {
+    if (!j.dismissed_)
+    {
+      // TODO(omaha): assume this does not throw
+      j.Execute();
+    }
+  }
+
+  mutable bool dismissed_;
+public:
+  ScopeGuardImplBase() throw() : dismissed_(false)
+  {
+  }
+  void Dismiss() const throw()
+  {
+    dismissed_ = true;
+  }
+};
+
+typedef const ScopeGuardImplBase& ScopeGuard;
+
+template <typename F>
+class ScopeGuardImpl0 : public ScopeGuardImplBase
+{
+public:
+  static ScopeGuardImpl0<F> MakeGuard(F fun)
+  {
+    return ScopeGuardImpl0<F>(fun);
+  }
+  ~ScopeGuardImpl0() throw()
+  {
+    SafeExecute(*this);
+  }
+  void Execute()
+  {
+    fun_();
+  }
+protected:
+  ScopeGuardImpl0(F fun) : fun_(fun)
+  {
+  }
+  F fun_;
+};
+
+template <typename F>
+inline ScopeGuardImpl0<F> MakeGuard(F fun)
+{
+  return ScopeGuardImpl0<F>::MakeGuard(fun);
+}
+
+template <typename F, typename P1>
+class ScopeGuardImpl1 : public ScopeGuardImplBase
+{
+public:
+  static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
+  {
+    return ScopeGuardImpl1<F, P1>(fun, p1);
+  }
+  ~ScopeGuardImpl1() throw()
+  {
+    SafeExecute(*this);
+  }
+  void Execute()
+  {
+    fun_(p1_);
+  }
+protected:
+  ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1)
+  {
+  }
+  F fun_;
+  const P1 p1_;
+};
+
+template <typename F, typename P1>
+inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1)
+{
+  return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1);
+}
+
+template <typename F, typename P1, typename P2>
+class ScopeGuardImpl2: public ScopeGuardImplBase
+{
+public:
+  static ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2)
+  {
+    return ScopeGuardImpl2<F, P1, P2>(fun, p1, p2);
+  }
+  ~ScopeGuardImpl2() throw()
+  {
+    SafeExecute(*this);
+  }
+  void Execute()
+  {
+    fun_(p1_, p2_);
+  }
+protected:
+  ScopeGuardImpl2(F fun, P1 p1, P2 p2) : fun_(fun), p1_(p1), p2_(p2)
+  {
+  }
+  F fun_;
+  const P1 p1_;
+  const P2 p2_;
+};
+
+template <typename F, typename P1, typename P2>
+inline ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2)
+{
+  return ScopeGuardImpl2<F, P1, P2>::MakeGuard(fun, p1, p2);
+}
+
+template <typename F, typename P1, typename P2, typename P3>
+class ScopeGuardImpl3 : public ScopeGuardImplBase
+{
+public:
+  static ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3)
+  {
+    return ScopeGuardImpl3<F, P1, P2, P3>(fun, p1, p2, p3);
+  }
+  ~ScopeGuardImpl3() throw()
+  {
+    SafeExecute(*this);
+  }
+  void Execute()
+  {
+    fun_(p1_, p2_, p3_);
+  }
+protected:
+  ScopeGuardImpl3(F fun, P1 p1, P2 p2, P3 p3) : fun_(fun), p1_(p1), p2_(p2), p3_(p3)
+  {
+  }
+  F fun_;
+  const P1 p1_;
+  const P2 p2_;
+  const P3 p3_;
+};
+
+template <typename F, typename P1, typename P2, typename P3>
+inline ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3)
+{
+  return ScopeGuardImpl3<F, P1, P2, P3>::MakeGuard(fun, p1, p2, p3);
+}
+
+
+template <class Obj, typename MemFun>
+class ObjScopeGuardImpl0 : public ScopeGuardImplBase
+{
+public:
+  static ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun)
+  {
+    return ObjScopeGuardImpl0<Obj, MemFun>(obj, memFun);
+  }
+  ~ObjScopeGuardImpl0() throw()
+  {
+    SafeExecute(*this);
+  }
+  void Execute()
+  {
+    (obj_.*memFun_)();
+  }
+protected:
+  ObjScopeGuardImpl0(Obj& obj, MemFun memFun)
+    : obj_(obj), memFun_(memFun) {}
+  Obj& obj_;
+  MemFun memFun_;
+};
+
+template <class Obj, typename MemFun>
+inline ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun)
+{
+  return ObjScopeGuardImpl0<Obj, MemFun>::MakeObjGuard(obj, memFun);
+}
+
+template <class Obj, typename MemFun, typename P1>
+class ObjScopeGuardImpl1 : public ScopeGuardImplBase
+{
+public:
+  static ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1)
+  {
+    return ObjScopeGuardImpl1<Obj, MemFun, P1>(obj, memFun, p1);
+  }
+  ~ObjScopeGuardImpl1() throw()
+  {
+    SafeExecute(*this);
+  }
+  void Execute()
+  {
+    (obj_.*memFun_)(p1_);
+  }
+protected:
+  ObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1)
+    : obj_(obj), memFun_(memFun), p1_(p1) {}
+  Obj& obj_;
+  MemFun memFun_;
+  const P1 p1_;
+};
+
+template <class Obj, typename MemFun, typename P1>
+inline ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1)
+{
+  return ObjScopeGuardImpl1<Obj, MemFun, P1>::MakeObjGuard(obj, memFun, p1);
+}
+
+template <class Obj, typename MemFun, typename P1, typename P2>
+class ObjScopeGuardImpl2 : public ScopeGuardImplBase
+{
+public:
+  static ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2)
+  {
+    return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>(obj, memFun, p1, p2);
+  }
+  ~ObjScopeGuardImpl2() throw()
+  {
+    SafeExecute(*this);
+  }
+  void Execute()
+  {
+    (obj_.*memFun_)(p1_, p2_);
+  }
+protected:
+  ObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2)
+    : obj_(obj), memFun_(memFun), p1_(p1), p2_(p2) {}
+  Obj& obj_;
+  MemFun memFun_;
+  const P1 p1_;
+  const P2 p2_;
+};
+
+template <class Obj, typename MemFun, typename P1, typename P2>
+inline ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2)
+{
+  return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>::MakeObjGuard(obj, memFun, p1, p2);
+}
+
+#define CONCATENATE_DIRECT(s1, s2) s1##s2
+#define CONCATENATE(s1, s2) CONCATENATE_DIRECT(s1, s2)
+#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__)
+
+#define ON_SCOPE_EXIT ScopeGuard ANONYMOUS_VARIABLE(scopeGuard) = MakeGuard
+#define ON_SCOPE_EXIT_OBJ ScopeGuard ANONYMOUS_VARIABLE(scopeGuard) = MakeObjGuard
+
+}  // namespace omaha
+
+#endif //SCOPEGUARD_H_
diff --git a/common/scoped_any.h b/common/scoped_any.h
index bb4d682..d7735f8 100644
--- a/common/scoped_any.h
+++ b/common/scoped_any.h
@@ -1,36 +1,36 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// smartany library uses a poor compile time assert. It is actually generating

-// runtime code to call the constructor of the assert class. Most likely to

-// improve performance, the library uses a static instance of the compile time

-// assert object. In theory the code is not thread-safe. In practice, since the

-// compile time assert is an empty class, there should be no problems. The long

-// term solution requires changing smartany to use a better compile time assert

-// which is completely evaluated at compile time and it has no effects

-// whatsoever at runtime. Short term, the code should include these wrappers

-// to silence the compiler warning.

-

-#ifndef OMAHA_COMMON_SCOPED_ANY__

-#define OMAHA_COMMON_SCOPED_ANY__

-

-#pragma warning(push)

-// C4640: construction of local static object is not thread-safe

-#pragma warning(disable : 4640)

-#include "omaha/third_party/smartany/scoped_any.h"

-#pragma warning(pop)

-

-#endif  // OMAHA_COMMON_SCOPED_ANY__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// smartany library uses a poor compile time assert. It is actually generating
+// runtime code to call the constructor of the assert class. Most likely to
+// improve performance, the library uses a static instance of the compile time
+// assert object. In theory the code is not thread-safe. In practice, since the
+// compile time assert is an empty class, there should be no problems. The long
+// term solution requires changing smartany to use a better compile time assert
+// which is completely evaluated at compile time and it has no effects
+// whatsoever at runtime. Short term, the code should include these wrappers
+// to silence the compiler warning.
+
+#ifndef OMAHA_COMMON_SCOPED_ANY__
+#define OMAHA_COMMON_SCOPED_ANY__
+
+#pragma warning(push)
+// C4640: construction of local static object is not thread-safe
+#pragma warning(disable : 4640)
+#include "omaha/third_party/smartany/scoped_any.h"
+#pragma warning(pop)
+
+#endif  // OMAHA_COMMON_SCOPED_ANY__
+
diff --git a/common/scoped_current_directory.h b/common/scoped_current_directory.h
index 14e91cc..ecb2aba 100644
--- a/common/scoped_current_directory.h
+++ b/common/scoped_current_directory.h
@@ -1,46 +1,46 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SCOPED_CURRENT_DIRECTORY_H_

-#define OMAHA_COMMON_SCOPED_CURRENT_DIRECTORY_H_

-

-namespace omaha {

-

-// Utility class to "scope" the setting of a current directory, and restore

-// to the previous current directory when leaving the scope.  Handles the

-// case where we don't actually have a new current directory to switch to

-// (thus the parameter is the empty string).

-

-class scoped_current_directory {

-  public:

-    explicit scoped_current_directory(const TCHAR* new_directory) {

-      *was_directory_ = _T('\0');

-      if (new_directory && *new_directory) {

-        ::GetCurrentDirectory(arraysize(was_directory_), was_directory_);

-        ::SetCurrentDirectory(new_directory);

-      }

-    }

-    ~scoped_current_directory() {

-      if (*was_directory_) {

-        ::SetCurrentDirectory(was_directory_);

-      }

-    }

-  private:

-    TCHAR was_directory_[MAX_PATH];

-};

-

-}  // namespace omaha

-

-#endif // OMAHA_COMMON_SCOPED_CURRENT_DIRECTORY_H_

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SCOPED_CURRENT_DIRECTORY_H_
+#define OMAHA_COMMON_SCOPED_CURRENT_DIRECTORY_H_
+
+namespace omaha {
+
+// Utility class to "scope" the setting of a current directory, and restore
+// to the previous current directory when leaving the scope.  Handles the
+// case where we don't actually have a new current directory to switch to
+// (thus the parameter is the empty string).
+
+class scoped_current_directory {
+  public:
+    explicit scoped_current_directory(const TCHAR* new_directory) {
+      *was_directory_ = _T('\0');
+      if (new_directory && *new_directory) {
+        ::GetCurrentDirectory(arraysize(was_directory_), was_directory_);
+        ::SetCurrentDirectory(new_directory);
+      }
+    }
+    ~scoped_current_directory() {
+      if (*was_directory_) {
+        ::SetCurrentDirectory(was_directory_);
+      }
+    }
+  private:
+    TCHAR was_directory_[MAX_PATH];
+};
+
+}  // namespace omaha
+
+#endif // OMAHA_COMMON_SCOPED_CURRENT_DIRECTORY_H_
diff --git a/common/scoped_impersonation.h b/common/scoped_impersonation.h
index 582bfd2..e7efec6 100644
--- a/common/scoped_impersonation.h
+++ b/common/scoped_impersonation.h
@@ -1,63 +1,63 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// TODO(omaha): deprecate and use ATL::CAccessToken instead.

-

-#ifndef OMAHA_COMMON_SCOPED_IMPERSONATION_H__

-#define OMAHA_COMMON_SCOPED_IMPERSONATION_H__

-

-#include <windows.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/scoped_any.h"

-

-namespace omaha {

-

-inline DWORD smart_impersonate_helper(HANDLE token) {

-  if (!token) {

-    return ERROR_INVALID_HANDLE;

-  }

-  return ::ImpersonateLoggedOnUser(token) ? ERROR_SUCCESS : ::GetLastError();

-}

-

-inline void smart_unimpersonate_helper(DWORD result) {

-  if (result == ERROR_SUCCESS) {

-    VERIFY1(::RevertToSelf());

-  }

-}

-

-typedef close_fun<void (*)(DWORD), smart_unimpersonate_helper>

-    close_impersonation;

-

-typedef value_const<DWORD, static_cast<DWORD>(-1)>

-    impersonation_not_init;

-

-typedef scoped_any<DWORD, close_impersonation, impersonation_not_init>

-    scoped_impersonation_close;

-

-// Manages the calls to ImpersonateLoggedOnUser and RevertToSelf.

-struct scoped_impersonation {

-  explicit scoped_impersonation(HANDLE token)

-      : result_(smart_impersonate_helper(token)) {

-  }

-

-  HRESULT result() const { return get(result_); }

-

- private:

-  const scoped_impersonation_close result_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SCOPED_IMPERSONATION_H__

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// TODO(omaha): deprecate and use ATL::CAccessToken instead.
+
+#ifndef OMAHA_COMMON_SCOPED_IMPERSONATION_H__
+#define OMAHA_COMMON_SCOPED_IMPERSONATION_H__
+
+#include <windows.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/scoped_any.h"
+
+namespace omaha {
+
+inline DWORD smart_impersonate_helper(HANDLE token) {
+  if (!token) {
+    return ERROR_INVALID_HANDLE;
+  }
+  return ::ImpersonateLoggedOnUser(token) ? ERROR_SUCCESS : ::GetLastError();
+}
+
+inline void smart_unimpersonate_helper(DWORD result) {
+  if (result == ERROR_SUCCESS) {
+    VERIFY1(::RevertToSelf());
+  }
+}
+
+typedef close_fun<void (*)(DWORD), smart_unimpersonate_helper>
+    close_impersonation;
+
+typedef value_const<DWORD, static_cast<DWORD>(-1)>
+    impersonation_not_init;
+
+typedef scoped_any<DWORD, close_impersonation, impersonation_not_init>
+    scoped_impersonation_close;
+
+// Manages the calls to ImpersonateLoggedOnUser and RevertToSelf.
+struct scoped_impersonation {
+  explicit scoped_impersonation(HANDLE token)
+      : result_(smart_impersonate_helper(token)) {
+  }
+
+  HRESULT result() const { return get(result_); }
+
+ private:
+  const scoped_impersonation_close result_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SCOPED_IMPERSONATION_H__
diff --git a/common/scoped_impersonation_unittest.cc b/common/scoped_impersonation_unittest.cc
index 573dbfc..cc2c7a2 100644
--- a/common/scoped_impersonation_unittest.cc
+++ b/common/scoped_impersonation_unittest.cc
@@ -1,41 +1,41 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include "base/basictypes.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/scoped_impersonation.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/vista_utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(ScopedImpersonationTest, ImpersonateLoggedOnUser) {

-  scoped_handle token;

-  vista::GetLoggedOnUserToken(address(token));

-  if (token) {

-    scoped_impersonation impersonate_user(get(token));

-    EXPECT_EQ(impersonate_user.result(), ERROR_SUCCESS);

-  }

-}

-

-TEST(ScopedImpersonationTest, ImpersonateLoggedOnUserInvalidHandle) {

-  scoped_impersonation impersonate_user(NULL);

-  EXPECT_EQ(impersonate_user.result(), ERROR_INVALID_HANDLE);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include "base/basictypes.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/scoped_impersonation.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/vista_utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(ScopedImpersonationTest, ImpersonateLoggedOnUser) {
+  scoped_handle token;
+  vista::GetLoggedOnUserToken(address(token));
+  if (token) {
+    scoped_impersonation impersonate_user(get(token));
+    EXPECT_EQ(impersonate_user.result(), ERROR_SUCCESS);
+  }
+}
+
+TEST(ScopedImpersonationTest, ImpersonateLoggedOnUserInvalidHandle) {
+  scoped_impersonation impersonate_user(NULL);
+  EXPECT_EQ(impersonate_user.result(), ERROR_INVALID_HANDLE);
+}
+
+}  // namespace omaha
+
diff --git a/common/scoped_ptr_address.h b/common/scoped_ptr_address.h
index 84828f4..aa0be1c 100644
--- a/common/scoped_ptr_address.h
+++ b/common/scoped_ptr_address.h
@@ -1,58 +1,58 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// Helper functions to enable a useful pattern of using scoped pointers in

-// which the ownership of the memory is transferred out to an empty

-// scoped_ptr or scoped_array.

-//

-// The usage pattern is as follows:

-//    void foo(Bar** b);

-//

-//    scoped_ptr<B> p;

-//    foo(address(p));

-//

-// To receive the ownwership of the resource the scoped pointer must be

-// empty, otherwise it will leak.

-//

-// As an implementation detail, the scoped pointers in "base/scoped_ptr.h" do

-// not offer support for this idiom. The code below may break if the

-// implementation of the scoped_ptr changes. The code works with the vast

-// majority of the scoped_ptr implementations though.

-//

-// TODO(omaha): add unit tests.

-

-#ifndef OMAHA_COMMON_SCOPED_PTR_ADDRESS__

-#define OMAHA_COMMON_SCOPED_PTR_ADDRESS__

-

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-

-template <typename T>

-inline T** address(const scoped_ptr<T>& t) {

-  COMPILE_ASSERT(sizeof(T*) == sizeof(scoped_ptr<T>), types_do_not_match);

-  ASSERT1(!t.get());

-  return reinterpret_cast<T**>(&const_cast<scoped_ptr<T>&>(t));

-}

-

-template <typename T>

-inline T** address(const scoped_array<T>& t) {

-  COMPILE_ASSERT(sizeof(T*) == sizeof(scoped_ptr<T>), types_do_not_match);

-  ASSERT1(!t.get());

-  return reinterpret_cast<T**>(&const_cast<scoped_array<T>&>(t));

-}

-

-#endif // OMAHA_COMMON_SCOPED_PTR_ADDRESS__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// Helper functions to enable a useful pattern of using scoped pointers in
+// which the ownership of the memory is transferred out to an empty
+// scoped_ptr or scoped_array.
+//
+// The usage pattern is as follows:
+//    void foo(Bar** b);
+//
+//    scoped_ptr<B> p;
+//    foo(address(p));
+//
+// To receive the ownwership of the resource the scoped pointer must be
+// empty, otherwise it will leak.
+//
+// As an implementation detail, the scoped pointers in "base/scoped_ptr.h" do
+// not offer support for this idiom. The code below may break if the
+// implementation of the scoped_ptr changes. The code works with the vast
+// majority of the scoped_ptr implementations though.
+//
+// TODO(omaha): add unit tests.
+
+#ifndef OMAHA_COMMON_SCOPED_PTR_ADDRESS__
+#define OMAHA_COMMON_SCOPED_PTR_ADDRESS__
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+
+template <typename T>
+inline T** address(const scoped_ptr<T>& t) {
+  COMPILE_ASSERT(sizeof(T*) == sizeof(scoped_ptr<T>), types_do_not_match);
+  ASSERT1(!t.get());
+  return reinterpret_cast<T**>(&const_cast<scoped_ptr<T>&>(t));
+}
+
+template <typename T>
+inline T** address(const scoped_array<T>& t) {
+  COMPILE_ASSERT(sizeof(T*) == sizeof(scoped_ptr<T>), types_do_not_match);
+  ASSERT1(!t.get());
+  return reinterpret_cast<T**>(&const_cast<scoped_array<T>&>(t));
+}
+
+#endif // OMAHA_COMMON_SCOPED_PTR_ADDRESS__
+
diff --git a/common/scoped_ptr_cotask.h b/common/scoped_ptr_cotask.h
index c1fb85d..ad0914b 100644
--- a/common/scoped_ptr_cotask.h
+++ b/common/scoped_ptr_cotask.h
@@ -1,260 +1,260 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines utility classes and functions which facilitate working with the

-// memory allocation functions CoTaskMemAlloc and CoTaskMemFree.

-

-#ifndef OMAHA_COMMON_SCOPED_PTR_COTASK_H__

-#define OMAHA_COMMON_SCOPED_PTR_COTASK_H__

-

-#include "omaha/common/debug.h"

-

-// scoped_ptr_cotask is identical to scoped_ptr, except that CoTaskMemFree is

-// called instead of delete.  For documentation of the interface, see

-// scoped_ptr.h.

-

-template <typename T>

-class scoped_ptr_cotask;

-

-template <typename T>

-scoped_ptr_cotask<T> make_scoped_ptr_cotask(T* p);

-

-template <typename T>

-class scoped_ptr_cotask {

- private:

-  T* ptr_;

-

-  scoped_ptr_cotask(scoped_ptr_cotask const &);

-  scoped_ptr_cotask & operator=(scoped_ptr_cotask const &);

-

-  friend scoped_ptr_cotask<T> make_scoped_ptr_cotask<T>(T* p);

-

- public:

-  typedef T element_type;

-

-  explicit scoped_ptr_cotask(T* p = 0): ptr_(p) {}

-

-  ~scoped_ptr_cotask() {

-    typedef char type_must_be_complete[sizeof(T)];

-    ::CoTaskMemFree(ptr_);

-  }

-

-  void reset(T* p = 0) {

-    typedef char type_must_be_complete[sizeof(T)];

-

-    if (ptr_ != p) {

-      ::CoTaskMemFree(ptr_);

-      ptr_ = p;

-    }

-  }

-

-  T& operator*() const {

-    assert(ptr_ != 0);

-    return *ptr_;

-  }

-

-  T* operator->() const  {

-    assert(ptr_ != 0);

-    return ptr_;

-  }

-

-  bool operator==(T* p) const {

-    return ptr_ == p;

-  }

-

-  bool operator!=(T* p) const {

-    return ptr_ != p;

-  }

-

-  T* get() const  {

-    return ptr_;

-  }

-

-  void swap(scoped_ptr_cotask & b) {

-    T* tmp = b.ptr_;

-    b.ptr_ = ptr_;

-    ptr_ = tmp;

-  }

-

-  T* release() {

-    T* tmp = ptr_;

-    ptr_ = 0;

-    return tmp;

-  }

-

- private:

-  template <typename U> bool operator==(scoped_ptr_cotask<U> const& p) const;

-  template <typename U> bool operator!=(scoped_ptr_cotask<U> const& p) const;

-};

-

-template <typename T>

-scoped_ptr_cotask<T> make_scoped_ptr_cotask(T* p) {

-  return scoped_ptr_cotask<T>(p);

-}

-

-template <typename T> inline

-void swap(scoped_ptr_cotask<T>& a, scoped_ptr_cotask<T>& b) {

-  a.swap(b);

-}

-

-template <typename T> inline

-bool operator==(T* p, const scoped_ptr_cotask<T>& b) {

-  return p == b.get();

-}

-

-template <typename T> inline

-bool operator!=(T* p, const scoped_ptr_cotask<T>& b) {

-  return p != b.get();

-}

-

-template <typename T>

-inline T** address(const scoped_ptr_cotask<T>& t) {

-  COMPILE_ASSERT(sizeof(T*) == sizeof(t), types_do_not_match);

-  ASSERT1(!t.get());

-  return reinterpret_cast<T**>(&const_cast<scoped_ptr_cotask<T>&>(t));

-}

-

-// scoped_array_cotask manages an array of pointers to objects allocated by

-// CoTaskMemAlloc.  The array is also allocated via CoTaskMemAlloc.  The

-// interface is similar to scoped_array, except that an array length must be

-// explicitly provided.  When the object is destructed, the array and each

-// element of the array are explicitly freed.

-

-template <typename T>

-class scoped_array_cotask;

-

-template <typename T>

-class scoped_array_cotask<T*> {

- private:

-  size_t count_;

-  T** ptr_;

-

-  scoped_array_cotask(scoped_array_cotask const &);

-  scoped_array_cotask & operator=(scoped_array_cotask const &);

-

- public:

-  typedef T* element_type;

-

-  explicit scoped_array_cotask(size_t c, T** p = 0)

-      : count_(c), ptr_(p) {

-    if (!ptr_) {

-      const size_t array_size = sizeof(T*) * count_;

-      ptr_ = static_cast<T**>(::CoTaskMemAlloc(array_size));

-      memset(ptr_, 0, array_size);

-    }

-  }

-

-  ~scoped_array_cotask() {

-    typedef char type_must_be_complete[sizeof(T*)];

-    if (ptr_) {

-      for (size_t i = 0; i < count_; ++i) {

-        ::CoTaskMemFree(ptr_[i]);

-      }

-      ::CoTaskMemFree(ptr_);

-    }

-  }

-

-  size_t size() const { return count_; }

-

-  void reset(size_t c, T** p = 0) {

-    typedef char type_must_be_complete[sizeof(T*)];

-

-    if (ptr_ != p) {

-      if (ptr_) {

-        for (size_t i = 0; i < count_; ++i) {

-          ::CoTaskMemFree(ptr_[i]);

-        }

-        ::CoTaskMemFree(ptr_);

-      }

-      ptr_ = p;

-    }

-    count_ = c;

-    if (!ptr_) {

-      const size_t array_size = sizeof(T*) * count_;

-      ptr_ = static_cast<T**>(::CoTaskMemAlloc(array_size));

-      memset(ptr_, 0, array_size);

-    }

-  }

-

-  T*& operator[](std::ptrdiff_t i) const {

-    assert(ptr_ != 0);

-    assert(i >= 0);

-    return ptr_[i];

-  }

-

-  bool operator==(T** p) const {

-    return ptr_ == p;

-  }

-

-  bool operator!=(T** p) const {

-    return ptr_ != p;

-  }

-

-  T** get() const {

-    return ptr_;

-  }

-

-  void swap(scoped_array_cotask & b) {

-    T** tmp = b.ptr_;

-    b.ptr_ = ptr_;

-    ptr_ = tmp;

-  }

-

-  T** release() {

-    T** tmp = ptr_;

-    ptr_ = 0;

-    return tmp;

-  }

-

- private:

-  template <typename U> bool operator==(scoped_array_cotask<U> const& p) const;

-  template <typename U> bool operator!=(scoped_array_cotask<U> const& p) const;

-};

-

-template <typename T> inline

-void swap(scoped_array_cotask<T>& a, scoped_array_cotask<T>& b) {

-  a.swap(b);

-}

-

-template <typename T> inline

-bool operator==(T* p, const scoped_array_cotask<T>& b) {

-  return p == b.get();

-}

-

-template <typename T> inline

-bool operator!=(T* p, const scoped_array_cotask<T>& b) {

-  return p != b.get();

-}

-

-// address() is not relevant to scoped_array_cotask, due to the count parameter.

-//

-// template <typename T>

-// inline T** address(const scoped_array_cotask<T>& t) {

-//   COMPILE_ASSERT(sizeof(T*) == sizeof(t), types_do_not_match);

-//   ASSERT1(!t.get());

-//   return reinterpret_cast<T**>(&const_cast<scoped_array_cotask<T>&>(t));

-// }

-

-// StrDupCoTask allocates a copy of a string using CoTaskMemAlloc.

-

-template <class T>

-inline T* StrDupCoTask(const T* str, size_t length) {

-  T* mem = static_cast<T*>(::CoTaskMemAlloc(sizeof(T) * (length + 1)));

-  memcpy(mem, str, sizeof(T) * length);

-  mem[length] = 0;

-  return mem;

-}

-

-#endif  // OMAHA_COMMON_SCOPED_PTR_COTASK_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines utility classes and functions which facilitate working with the
+// memory allocation functions CoTaskMemAlloc and CoTaskMemFree.
+
+#ifndef OMAHA_COMMON_SCOPED_PTR_COTASK_H__
+#define OMAHA_COMMON_SCOPED_PTR_COTASK_H__
+
+#include "omaha/common/debug.h"
+
+// scoped_ptr_cotask is identical to scoped_ptr, except that CoTaskMemFree is
+// called instead of delete.  For documentation of the interface, see
+// scoped_ptr.h.
+
+template <typename T>
+class scoped_ptr_cotask;
+
+template <typename T>
+scoped_ptr_cotask<T> make_scoped_ptr_cotask(T* p);
+
+template <typename T>
+class scoped_ptr_cotask {
+ private:
+  T* ptr_;
+
+  scoped_ptr_cotask(scoped_ptr_cotask const &);
+  scoped_ptr_cotask & operator=(scoped_ptr_cotask const &);
+
+  friend scoped_ptr_cotask<T> make_scoped_ptr_cotask<T>(T* p);
+
+ public:
+  typedef T element_type;
+
+  explicit scoped_ptr_cotask(T* p = 0): ptr_(p) {}
+
+  ~scoped_ptr_cotask() {
+    typedef char type_must_be_complete[sizeof(T)];
+    ::CoTaskMemFree(ptr_);
+  }
+
+  void reset(T* p = 0) {
+    typedef char type_must_be_complete[sizeof(T)];
+
+    if (ptr_ != p) {
+      ::CoTaskMemFree(ptr_);
+      ptr_ = p;
+    }
+  }
+
+  T& operator*() const {
+    assert(ptr_ != 0);
+    return *ptr_;
+  }
+
+  T* operator->() const  {
+    assert(ptr_ != 0);
+    return ptr_;
+  }
+
+  bool operator==(T* p) const {
+    return ptr_ == p;
+  }
+
+  bool operator!=(T* p) const {
+    return ptr_ != p;
+  }
+
+  T* get() const  {
+    return ptr_;
+  }
+
+  void swap(scoped_ptr_cotask & b) {
+    T* tmp = b.ptr_;
+    b.ptr_ = ptr_;
+    ptr_ = tmp;
+  }
+
+  T* release() {
+    T* tmp = ptr_;
+    ptr_ = 0;
+    return tmp;
+  }
+
+ private:
+  template <typename U> bool operator==(scoped_ptr_cotask<U> const& p) const;
+  template <typename U> bool operator!=(scoped_ptr_cotask<U> const& p) const;
+};
+
+template <typename T>
+scoped_ptr_cotask<T> make_scoped_ptr_cotask(T* p) {
+  return scoped_ptr_cotask<T>(p);
+}
+
+template <typename T> inline
+void swap(scoped_ptr_cotask<T>& a, scoped_ptr_cotask<T>& b) {
+  a.swap(b);
+}
+
+template <typename T> inline
+bool operator==(T* p, const scoped_ptr_cotask<T>& b) {
+  return p == b.get();
+}
+
+template <typename T> inline
+bool operator!=(T* p, const scoped_ptr_cotask<T>& b) {
+  return p != b.get();
+}
+
+template <typename T>
+inline T** address(const scoped_ptr_cotask<T>& t) {
+  COMPILE_ASSERT(sizeof(T*) == sizeof(t), types_do_not_match);
+  ASSERT1(!t.get());
+  return reinterpret_cast<T**>(&const_cast<scoped_ptr_cotask<T>&>(t));
+}
+
+// scoped_array_cotask manages an array of pointers to objects allocated by
+// CoTaskMemAlloc.  The array is also allocated via CoTaskMemAlloc.  The
+// interface is similar to scoped_array, except that an array length must be
+// explicitly provided.  When the object is destructed, the array and each
+// element of the array are explicitly freed.
+
+template <typename T>
+class scoped_array_cotask;
+
+template <typename T>
+class scoped_array_cotask<T*> {
+ private:
+  size_t count_;
+  T** ptr_;
+
+  scoped_array_cotask(scoped_array_cotask const &);
+  scoped_array_cotask & operator=(scoped_array_cotask const &);
+
+ public:
+  typedef T* element_type;
+
+  explicit scoped_array_cotask(size_t c, T** p = 0)
+      : count_(c), ptr_(p) {
+    if (!ptr_) {
+      const size_t array_size = sizeof(T*) * count_;
+      ptr_ = static_cast<T**>(::CoTaskMemAlloc(array_size));
+      memset(ptr_, 0, array_size);
+    }
+  }
+
+  ~scoped_array_cotask() {
+    typedef char type_must_be_complete[sizeof(T*)];
+    if (ptr_) {
+      for (size_t i = 0; i < count_; ++i) {
+        ::CoTaskMemFree(ptr_[i]);
+      }
+      ::CoTaskMemFree(ptr_);
+    }
+  }
+
+  size_t size() const { return count_; }
+
+  void reset(size_t c, T** p = 0) {
+    typedef char type_must_be_complete[sizeof(T*)];
+
+    if (ptr_ != p) {
+      if (ptr_) {
+        for (size_t i = 0; i < count_; ++i) {
+          ::CoTaskMemFree(ptr_[i]);
+        }
+        ::CoTaskMemFree(ptr_);
+      }
+      ptr_ = p;
+    }
+    count_ = c;
+    if (!ptr_) {
+      const size_t array_size = sizeof(T*) * count_;
+      ptr_ = static_cast<T**>(::CoTaskMemAlloc(array_size));
+      memset(ptr_, 0, array_size);
+    }
+  }
+
+  T*& operator[](std::ptrdiff_t i) const {
+    assert(ptr_ != 0);
+    assert(i >= 0);
+    return ptr_[i];
+  }
+
+  bool operator==(T** p) const {
+    return ptr_ == p;
+  }
+
+  bool operator!=(T** p) const {
+    return ptr_ != p;
+  }
+
+  T** get() const {
+    return ptr_;
+  }
+
+  void swap(scoped_array_cotask & b) {
+    T** tmp = b.ptr_;
+    b.ptr_ = ptr_;
+    ptr_ = tmp;
+  }
+
+  T** release() {
+    T** tmp = ptr_;
+    ptr_ = 0;
+    return tmp;
+  }
+
+ private:
+  template <typename U> bool operator==(scoped_array_cotask<U> const& p) const;
+  template <typename U> bool operator!=(scoped_array_cotask<U> const& p) const;
+};
+
+template <typename T> inline
+void swap(scoped_array_cotask<T>& a, scoped_array_cotask<T>& b) {
+  a.swap(b);
+}
+
+template <typename T> inline
+bool operator==(T* p, const scoped_array_cotask<T>& b) {
+  return p == b.get();
+}
+
+template <typename T> inline
+bool operator!=(T* p, const scoped_array_cotask<T>& b) {
+  return p != b.get();
+}
+
+// address() is not relevant to scoped_array_cotask, due to the count parameter.
+//
+// template <typename T>
+// inline T** address(const scoped_array_cotask<T>& t) {
+//   COMPILE_ASSERT(sizeof(T*) == sizeof(t), types_do_not_match);
+//   ASSERT1(!t.get());
+//   return reinterpret_cast<T**>(&const_cast<scoped_array_cotask<T>&>(t));
+// }
+
+// StrDupCoTask allocates a copy of a string using CoTaskMemAlloc.
+
+template <class T>
+inline T* StrDupCoTask(const T* str, size_t length) {
+  T* mem = static_cast<T*>(::CoTaskMemAlloc(sizeof(T) * (length + 1)));
+  memcpy(mem, str, sizeof(T) * length);
+  mem[length] = 0;
+  return mem;
+}
+
+#endif  // OMAHA_COMMON_SCOPED_PTR_COTASK_H__
diff --git a/common/scoped_ptr_cotask_unittest.cc b/common/scoped_ptr_cotask_unittest.cc
index 8c9a267..7414eb3 100644
--- a/common/scoped_ptr_cotask_unittest.cc
+++ b/common/scoped_ptr_cotask_unittest.cc
@@ -1,308 +1,308 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <vector>

-#include "omaha/common/debug.h"

-#include "omaha/common/scoped_ptr_cotask.h"

-#include "omaha/testing/unit_test.h"

-

-// TestMallocSpy monitors CoTaskMemAlloc/Free, and records statistics about

-// them.

-

-class TestMallocSpy : public IMallocSpy {

- public:

-  struct Alloc {

-    size_t size;

-    void* ptr;

-    bool freed;

-  };

-

-  TestMallocSpy() : ref_(1) {}

-

-  virtual ~TestMallocSpy() {}

-

-  size_t NumAllocs() const { return allocs_.size(); }

-

-  const Alloc* GetAlloc(size_t i) const {

-    if (i >= allocs_.size())

-      return NULL;

-    return &allocs_[i];

-  }

-

-  size_t NumFrees() const { return frees_.size(); }

-

-  const Alloc* GetFree(size_t i) const {

-    if (i >= frees_.size())

-      return NULL;

-    ASSERT1(frees_[i] < allocs_.size());

-    return &allocs_[frees_[i]];

-  }

-

-  // IUnknown methods

-  virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv) {

-    if (NULL == ppv) {

-      return E_POINTER;

-    }

-    if (::IsEqualIID(__uuidof(IUnknown), riid) ||

-        ::IsEqualIID(__uuidof(IMallocSpy), riid)) {

-      AddRef();

-      *ppv = static_cast<IUnknown*>(this);

-      return S_OK;

-    }

-    *ppv = NULL;

-    return E_NOINTERFACE;

-  }

-  virtual ULONG STDMETHODCALLTYPE AddRef() {

-    return ++ref_;

-  }

-  virtual ULONG STDMETHODCALLTYPE Release() {

-    ULONG r = --ref_;

-    if (0 == r) {

-      delete this;

-    }

-    return r;

-  }

-

-  // IMallocSpy methods

-  virtual SIZE_T STDMETHODCALLTYPE PreAlloc(SIZE_T request_size) {

-    Alloc a = { request_size, NULL, false };

-    allocs_.push_back(a);

-    return request_size;

-  }

-  virtual void* STDMETHODCALLTYPE PostAlloc(void* actual) {

-    ASSERT1(!allocs_.empty());

-    ASSERT1(NULL == allocs_.back().ptr);

-    allocs_.back().ptr = actual;

-    return actual;

-  }

-  virtual void* STDMETHODCALLTYPE PreFree(void* request, BOOL spyed) {

-    if (spyed) {

-      bool found = false;

-      for (size_t i = 0; i < allocs_.size(); ++i) {

-        if ((allocs_[i].ptr == request) && !allocs_[i].freed) {

-          allocs_[i].freed = true;

-          frees_.push_back(i);

-          found = true;

-          break;

-        }

-      }

-      ASSERT1(found);

-    }

-    return request;

-  }

-  virtual void STDMETHODCALLTYPE PostFree(BOOL) {}

-  virtual SIZE_T STDMETHODCALLTYPE PreRealloc(void*,

-                                              SIZE_T request_size,

-                                              void**,

-                                              BOOL) {

-    return request_size;

-  }

-  virtual void* STDMETHODCALLTYPE PostRealloc(void* actual, BOOL) {

-    return actual;

-  }

-  virtual void* STDMETHODCALLTYPE PreGetSize(void* request, BOOL) {

-    return request;

-  }

-  virtual SIZE_T STDMETHODCALLTYPE PostGetSize(SIZE_T actual_size, BOOL) {

-    return actual_size;

-  }

-  virtual void* STDMETHODCALLTYPE PreDidAlloc(void* request, BOOL) {

-    return request;

-  }

-  virtual int STDMETHODCALLTYPE PostDidAlloc(void*, BOOL, int fActual) {

-    return fActual;

-  }

-  virtual void STDMETHODCALLTYPE PreHeapMinimize() {}

-  virtual void STDMETHODCALLTYPE PostHeapMinimize() {}

-

- private:

-  ULONG ref_;

-  std::vector<Alloc> allocs_;

-  std::vector<size_t> frees_;

-};

-

-// MallocTest runs tests with a TestMallocSpy installed.

-

-class MallocTest : public testing::Test {

- public:

-  virtual void SetUp() {

-    spy_.Attach(new TestMallocSpy);

-    ASSERT_SUCCEEDED(::CoRegisterMallocSpy(spy_.p));

-    EXPECT_EQ(0, spy()->NumAllocs());

-  }

-  virtual void TearDown() {

-    EXPECT_EQ(spy()->NumAllocs(), spy()->NumFrees());

-    ASSERT_SUCCEEDED(::CoRevokeMallocSpy());

-  }

-  TestMallocSpy* spy() { return spy_.p; }

-

- private:

-  CComPtr<TestMallocSpy> spy_;

-};

-

-TEST_F(MallocTest, StrDupCoTask) {

-  const char kNarrowString[] = "Hello";

-  const size_t kNarrowLen = strlen(kNarrowString);

-  const wchar_t kWideString[] = L"World";

-  const size_t kWideLen = wcslen(kWideString);

-

-  // Test StrDupCoTask with narrow strings.

-  char* narrow_copy = StrDupCoTask(kNarrowString, kNarrowLen);

-

-  ASSERT_EQ(1, spy()->NumAllocs());

-  EXPECT_EQ(0, spy()->NumFrees());

-  EXPECT_EQ((kNarrowLen + 1) * sizeof(char), spy()->GetAlloc(0)->size);

-  EXPECT_EQ(narrow_copy, spy()->GetAlloc(0)->ptr);

-  EXPECT_FALSE(spy()->GetAlloc(0)->freed);

-

-  ::CoTaskMemFree(narrow_copy);

-

-  ASSERT_EQ(1, spy()->NumFrees());

-  EXPECT_EQ(spy()->GetAlloc(0), spy()->GetFree(0));

-  EXPECT_EQ(narrow_copy, spy()->GetFree(0)->ptr);

-  EXPECT_TRUE(spy()->GetFree(0)->freed);

-

-  // Test StrDupCoTask with wide strings.

-  wchar_t* wide_copy = StrDupCoTask(kWideString, kWideLen);

-

-  ASSERT_EQ(2, spy()->NumAllocs());

-  EXPECT_EQ(1, spy()->NumFrees());

-  EXPECT_EQ((kWideLen + 1) * sizeof(wchar_t), spy()->GetAlloc(1)->size);

-  EXPECT_EQ(wide_copy, spy()->GetAlloc(1)->ptr);

-  EXPECT_FALSE(spy()->GetAlloc(1)->freed);

-

-  ::CoTaskMemFree(wide_copy);

-

-  ASSERT_EQ(2, spy()->NumFrees());

-  EXPECT_EQ(spy()->GetAlloc(1), spy()->GetFree(1));

-  EXPECT_EQ(wide_copy, spy()->GetFree(1)->ptr);

-  EXPECT_TRUE(spy()->GetFree(1)->freed);

-}

-

-TEST_F(MallocTest, scoped_ptr_cotask) {

-  scoped_ptr_cotask<wchar_t>* string_ptr;

-

-  // Creating an empty ptr does no additional allocations.

-  string_ptr = new scoped_ptr_cotask<wchar_t>;

-  ASSERT_EQ(0, spy()->NumAllocs());

-  EXPECT_EQ(0, spy()->NumFrees());

-

-  // Assigning a string does not additional allocations.

-  string_ptr->reset(StrDupCoTask(L"hi", 2));

-  ASSERT_EQ(1, spy()->NumAllocs());

-  EXPECT_EQ(0, spy()->NumFrees());

-  EXPECT_EQ(3 * sizeof(wchar_t), spy()->GetAlloc(0)->size);

-  EXPECT_FALSE(spy()->GetAlloc(0)->freed);

-

-  EXPECT_EQ(0, memcmp(string_ptr->get(), L"hi", 3 * sizeof(wchar_t)));

-

-  // Replacing the string frees the old memory.

-  string_ptr->reset(StrDupCoTask(L"there", 5));

-  ASSERT_EQ(2, spy()->NumAllocs());

-  EXPECT_EQ(1, spy()->NumFrees());

-  EXPECT_EQ(6 * sizeof(wchar_t), spy()->GetAlloc(1)->size);

-  EXPECT_TRUE(spy()->GetAlloc(0)->freed);

-  EXPECT_FALSE(spy()->GetAlloc(1)->freed);

-

-  // Deleting the string frees the memory.

-  delete string_ptr;

-  ASSERT_EQ(2, spy()->NumAllocs());

-  EXPECT_EQ(2, spy()->NumFrees());

-  EXPECT_TRUE(spy()->GetAlloc(1)->freed);

-}

-

-TEST_F(MallocTest, scoped_array_cotask) {

-  const size_t kSize = 5;

-  scoped_array_cotask<wchar_t*>* string_array;

-

-  // Allocate an array of 5 empty elements.

-  string_array = new scoped_array_cotask<wchar_t*>(kSize);

-  ASSERT_EQ(kSize, string_array->size());

-  ASSERT_EQ(1, spy()->NumAllocs());

-  EXPECT_EQ(0, spy()->NumFrees());

-  EXPECT_EQ(kSize * sizeof(wchar_t*), spy()->GetAlloc(0)->size);

-

-  // Populate array elements.

-  for (size_t i = 0; i < kSize; ++i) {

-    EXPECT_TRUE(NULL == (*string_array)[i]);

-    (*string_array)[i] = StrDupCoTask(L"hi", 2);

-  }

-  EXPECT_EQ(1 + kSize, spy()->NumAllocs());

-  EXPECT_EQ(0, spy()->NumFrees());

-

-  // Get is idempotent.

-  wchar_t** ptr = string_array->get();

-  EXPECT_EQ(ptr, string_array->get());

-  EXPECT_EQ(ptr, spy()->GetAlloc(0)->ptr);

-  EXPECT_EQ(0, spy()->NumFrees());

-

-  // Release is not idempotent, but does not free memory.

-  ptr = string_array->release();

-  EXPECT_TRUE(NULL == string_array->release());

-  EXPECT_EQ(ptr, spy()->GetAlloc(0)->ptr);

-  EXPECT_EQ(0, spy()->NumFrees());

-

-  // Deleting a released array does not free memory.

-  delete string_array;

-  EXPECT_EQ(0, spy()->NumFrees());

-

-  // Constructing an array from existing memory, does not cause allocations.

-  string_array = new scoped_array_cotask<wchar_t*>(kSize, ptr);

-  EXPECT_EQ(1 + kSize, spy()->NumAllocs());

-  EXPECT_EQ(0, spy()->NumFrees());

-

-  // Deleting an array frees all elements and the array.

-  delete string_array;

-  ASSERT_EQ(1 + kSize, spy()->NumAllocs());

-  EXPECT_EQ(1 + kSize, spy()->NumFrees());

-  for (size_t i = 0; i < spy()->NumAllocs(); ++i) {

-    EXPECT_TRUE(spy()->GetAlloc(i)->freed);

-  }

-}

-

-TEST_F(MallocTest, scoped_array_cotask_reset) {

-  // This test exposes a former bug, where reset did not reallocate a new

-  // array after being released.

-

-  // Allocate an empty array.

-  const size_t kSize = 5;

-  scoped_array_cotask<int*>* array = new scoped_array_cotask<int*>(kSize);

-  ASSERT_EQ(1, spy()->NumAllocs());

-

-  // Release the array, to verify it was allocated.

-  int** first_raw_array = array->release();

-  EXPECT_TRUE(NULL != first_raw_array);

-  EXPECT_FALSE(spy()->GetAlloc(0)->freed);

-

-  // Allocate another empty array.

-  array->reset(kSize);

-  ASSERT_EQ(2, spy()->NumAllocs());

-

-  // Release the second array, to verify it was allocated.

-  int** second_raw_array = array->release();

-  EXPECT_TRUE(NULL != second_raw_array);

-  EXPECT_FALSE(spy()->GetAlloc(1)->freed);

-

-  // Use the scoped_array_cotask object to dispose of the allocated arrays.

-  array->reset(kSize, first_raw_array);

-  array->reset(kSize, second_raw_array);

-  delete array;

-

-  // Check the final conditions.

-  ASSERT_EQ(2, spy()->NumAllocs());

-  for (size_t i = 0; i < spy()->NumAllocs(); ++i) {

-    EXPECT_TRUE(spy()->GetAlloc(i)->freed);

-  }

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <vector>
+#include "omaha/common/debug.h"
+#include "omaha/common/scoped_ptr_cotask.h"
+#include "omaha/testing/unit_test.h"
+
+// TestMallocSpy monitors CoTaskMemAlloc/Free, and records statistics about
+// them.
+
+class TestMallocSpy : public IMallocSpy {
+ public:
+  struct Alloc {
+    size_t size;
+    void* ptr;
+    bool freed;
+  };
+
+  TestMallocSpy() : ref_(1) {}
+
+  virtual ~TestMallocSpy() {}
+
+  size_t NumAllocs() const { return allocs_.size(); }
+
+  const Alloc* GetAlloc(size_t i) const {
+    if (i >= allocs_.size())
+      return NULL;
+    return &allocs_[i];
+  }
+
+  size_t NumFrees() const { return frees_.size(); }
+
+  const Alloc* GetFree(size_t i) const {
+    if (i >= frees_.size())
+      return NULL;
+    ASSERT1(frees_[i] < allocs_.size());
+    return &allocs_[frees_[i]];
+  }
+
+  // IUnknown methods
+  virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv) {
+    if (NULL == ppv) {
+      return E_POINTER;
+    }
+    if (::IsEqualIID(__uuidof(IUnknown), riid) ||
+        ::IsEqualIID(__uuidof(IMallocSpy), riid)) {
+      AddRef();
+      *ppv = static_cast<IUnknown*>(this);
+      return S_OK;
+    }
+    *ppv = NULL;
+    return E_NOINTERFACE;
+  }
+  virtual ULONG STDMETHODCALLTYPE AddRef() {
+    return ++ref_;
+  }
+  virtual ULONG STDMETHODCALLTYPE Release() {
+    ULONG r = --ref_;
+    if (0 == r) {
+      delete this;
+    }
+    return r;
+  }
+
+  // IMallocSpy methods
+  virtual SIZE_T STDMETHODCALLTYPE PreAlloc(SIZE_T request_size) {
+    Alloc a = { request_size, NULL, false };
+    allocs_.push_back(a);
+    return request_size;
+  }
+  virtual void* STDMETHODCALLTYPE PostAlloc(void* actual) {
+    ASSERT1(!allocs_.empty());
+    ASSERT1(NULL == allocs_.back().ptr);
+    allocs_.back().ptr = actual;
+    return actual;
+  }
+  virtual void* STDMETHODCALLTYPE PreFree(void* request, BOOL spyed) {
+    if (spyed) {
+      bool found = false;
+      for (size_t i = 0; i < allocs_.size(); ++i) {
+        if ((allocs_[i].ptr == request) && !allocs_[i].freed) {
+          allocs_[i].freed = true;
+          frees_.push_back(i);
+          found = true;
+          break;
+        }
+      }
+      ASSERT1(found);
+    }
+    return request;
+  }
+  virtual void STDMETHODCALLTYPE PostFree(BOOL) {}
+  virtual SIZE_T STDMETHODCALLTYPE PreRealloc(void*,
+                                              SIZE_T request_size,
+                                              void**,
+                                              BOOL) {
+    return request_size;
+  }
+  virtual void* STDMETHODCALLTYPE PostRealloc(void* actual, BOOL) {
+    return actual;
+  }
+  virtual void* STDMETHODCALLTYPE PreGetSize(void* request, BOOL) {
+    return request;
+  }
+  virtual SIZE_T STDMETHODCALLTYPE PostGetSize(SIZE_T actual_size, BOOL) {
+    return actual_size;
+  }
+  virtual void* STDMETHODCALLTYPE PreDidAlloc(void* request, BOOL) {
+    return request;
+  }
+  virtual int STDMETHODCALLTYPE PostDidAlloc(void*, BOOL, int fActual) {
+    return fActual;
+  }
+  virtual void STDMETHODCALLTYPE PreHeapMinimize() {}
+  virtual void STDMETHODCALLTYPE PostHeapMinimize() {}
+
+ private:
+  ULONG ref_;
+  std::vector<Alloc> allocs_;
+  std::vector<size_t> frees_;
+};
+
+// MallocTest runs tests with a TestMallocSpy installed.
+
+class MallocTest : public testing::Test {
+ public:
+  virtual void SetUp() {
+    spy_.Attach(new TestMallocSpy);
+    ASSERT_SUCCEEDED(::CoRegisterMallocSpy(spy_.p));
+    EXPECT_EQ(0, spy()->NumAllocs());
+  }
+  virtual void TearDown() {
+    EXPECT_EQ(spy()->NumAllocs(), spy()->NumFrees());
+    ASSERT_SUCCEEDED(::CoRevokeMallocSpy());
+  }
+  TestMallocSpy* spy() { return spy_.p; }
+
+ private:
+  CComPtr<TestMallocSpy> spy_;
+};
+
+TEST_F(MallocTest, StrDupCoTask) {
+  const char kNarrowString[] = "Hello";
+  const size_t kNarrowLen = strlen(kNarrowString);
+  const wchar_t kWideString[] = L"World";
+  const size_t kWideLen = wcslen(kWideString);
+
+  // Test StrDupCoTask with narrow strings.
+  char* narrow_copy = StrDupCoTask(kNarrowString, kNarrowLen);
+
+  ASSERT_EQ(1, spy()->NumAllocs());
+  EXPECT_EQ(0, spy()->NumFrees());
+  EXPECT_EQ((kNarrowLen + 1) * sizeof(char), spy()->GetAlloc(0)->size);
+  EXPECT_EQ(narrow_copy, spy()->GetAlloc(0)->ptr);
+  EXPECT_FALSE(spy()->GetAlloc(0)->freed);
+
+  ::CoTaskMemFree(narrow_copy);
+
+  ASSERT_EQ(1, spy()->NumFrees());
+  EXPECT_EQ(spy()->GetAlloc(0), spy()->GetFree(0));
+  EXPECT_EQ(narrow_copy, spy()->GetFree(0)->ptr);
+  EXPECT_TRUE(spy()->GetFree(0)->freed);
+
+  // Test StrDupCoTask with wide strings.
+  wchar_t* wide_copy = StrDupCoTask(kWideString, kWideLen);
+
+  ASSERT_EQ(2, spy()->NumAllocs());
+  EXPECT_EQ(1, spy()->NumFrees());
+  EXPECT_EQ((kWideLen + 1) * sizeof(wchar_t), spy()->GetAlloc(1)->size);
+  EXPECT_EQ(wide_copy, spy()->GetAlloc(1)->ptr);
+  EXPECT_FALSE(spy()->GetAlloc(1)->freed);
+
+  ::CoTaskMemFree(wide_copy);
+
+  ASSERT_EQ(2, spy()->NumFrees());
+  EXPECT_EQ(spy()->GetAlloc(1), spy()->GetFree(1));
+  EXPECT_EQ(wide_copy, spy()->GetFree(1)->ptr);
+  EXPECT_TRUE(spy()->GetFree(1)->freed);
+}
+
+TEST_F(MallocTest, scoped_ptr_cotask) {
+  scoped_ptr_cotask<wchar_t>* string_ptr;
+
+  // Creating an empty ptr does no additional allocations.
+  string_ptr = new scoped_ptr_cotask<wchar_t>;
+  ASSERT_EQ(0, spy()->NumAllocs());
+  EXPECT_EQ(0, spy()->NumFrees());
+
+  // Assigning a string does not additional allocations.
+  string_ptr->reset(StrDupCoTask(L"hi", 2));
+  ASSERT_EQ(1, spy()->NumAllocs());
+  EXPECT_EQ(0, spy()->NumFrees());
+  EXPECT_EQ(3 * sizeof(wchar_t), spy()->GetAlloc(0)->size);
+  EXPECT_FALSE(spy()->GetAlloc(0)->freed);
+
+  EXPECT_EQ(0, memcmp(string_ptr->get(), L"hi", 3 * sizeof(wchar_t)));
+
+  // Replacing the string frees the old memory.
+  string_ptr->reset(StrDupCoTask(L"there", 5));
+  ASSERT_EQ(2, spy()->NumAllocs());
+  EXPECT_EQ(1, spy()->NumFrees());
+  EXPECT_EQ(6 * sizeof(wchar_t), spy()->GetAlloc(1)->size);
+  EXPECT_TRUE(spy()->GetAlloc(0)->freed);
+  EXPECT_FALSE(spy()->GetAlloc(1)->freed);
+
+  // Deleting the string frees the memory.
+  delete string_ptr;
+  ASSERT_EQ(2, spy()->NumAllocs());
+  EXPECT_EQ(2, spy()->NumFrees());
+  EXPECT_TRUE(spy()->GetAlloc(1)->freed);
+}
+
+TEST_F(MallocTest, scoped_array_cotask) {
+  const size_t kSize = 5;
+  scoped_array_cotask<wchar_t*>* string_array;
+
+  // Allocate an array of 5 empty elements.
+  string_array = new scoped_array_cotask<wchar_t*>(kSize);
+  ASSERT_EQ(kSize, string_array->size());
+  ASSERT_EQ(1, spy()->NumAllocs());
+  EXPECT_EQ(0, spy()->NumFrees());
+  EXPECT_EQ(kSize * sizeof(wchar_t*), spy()->GetAlloc(0)->size);
+
+  // Populate array elements.
+  for (size_t i = 0; i < kSize; ++i) {
+    EXPECT_TRUE(NULL == (*string_array)[i]);
+    (*string_array)[i] = StrDupCoTask(L"hi", 2);
+  }
+  EXPECT_EQ(1 + kSize, spy()->NumAllocs());
+  EXPECT_EQ(0, spy()->NumFrees());
+
+  // Get is idempotent.
+  wchar_t** ptr = string_array->get();
+  EXPECT_EQ(ptr, string_array->get());
+  EXPECT_EQ(ptr, spy()->GetAlloc(0)->ptr);
+  EXPECT_EQ(0, spy()->NumFrees());
+
+  // Release is not idempotent, but does not free memory.
+  ptr = string_array->release();
+  EXPECT_TRUE(NULL == string_array->release());
+  EXPECT_EQ(ptr, spy()->GetAlloc(0)->ptr);
+  EXPECT_EQ(0, spy()->NumFrees());
+
+  // Deleting a released array does not free memory.
+  delete string_array;
+  EXPECT_EQ(0, spy()->NumFrees());
+
+  // Constructing an array from existing memory, does not cause allocations.
+  string_array = new scoped_array_cotask<wchar_t*>(kSize, ptr);
+  EXPECT_EQ(1 + kSize, spy()->NumAllocs());
+  EXPECT_EQ(0, spy()->NumFrees());
+
+  // Deleting an array frees all elements and the array.
+  delete string_array;
+  ASSERT_EQ(1 + kSize, spy()->NumAllocs());
+  EXPECT_EQ(1 + kSize, spy()->NumFrees());
+  for (size_t i = 0; i < spy()->NumAllocs(); ++i) {
+    EXPECT_TRUE(spy()->GetAlloc(i)->freed);
+  }
+}
+
+TEST_F(MallocTest, scoped_array_cotask_reset) {
+  // This test exposes a former bug, where reset did not reallocate a new
+  // array after being released.
+
+  // Allocate an empty array.
+  const size_t kSize = 5;
+  scoped_array_cotask<int*>* array = new scoped_array_cotask<int*>(kSize);
+  ASSERT_EQ(1, spy()->NumAllocs());
+
+  // Release the array, to verify it was allocated.
+  int** first_raw_array = array->release();
+  EXPECT_TRUE(NULL != first_raw_array);
+  EXPECT_FALSE(spy()->GetAlloc(0)->freed);
+
+  // Allocate another empty array.
+  array->reset(kSize);
+  ASSERT_EQ(2, spy()->NumAllocs());
+
+  // Release the second array, to verify it was allocated.
+  int** second_raw_array = array->release();
+  EXPECT_TRUE(NULL != second_raw_array);
+  EXPECT_FALSE(spy()->GetAlloc(1)->freed);
+
+  // Use the scoped_array_cotask object to dispose of the allocated arrays.
+  array->reset(kSize, first_raw_array);
+  array->reset(kSize, second_raw_array);
+  delete array;
+
+  // Check the final conditions.
+  ASSERT_EQ(2, spy()->NumAllocs());
+  for (size_t i = 0; i < spy()->NumAllocs(); ++i) {
+    EXPECT_TRUE(spy()->GetAlloc(i)->freed);
+  }
+}
diff --git a/common/security/aes.c b/common/security/aes.c
index 8152bbb..47cbcf8 100644
--- a/common/security/aes.c
+++ b/common/security/aes.c
@@ -1,177 +1,177 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Optimized for code size. Lacking decrypt functionality.

-// Currently 1042 bytes of code.

-

-#include "aes.h"

-

-#include <stdio.h>

-#include <stdlib.h>

-#include <memory.h>

-#include <inttypes.h>

-

-static const uint8_t sbox_e[256]= {

-    99  , 124 , 119 , 123 , 242 , 107 , 111 , 197

-  , 48  , 1   , 103 , 43  , 254 , 215 , 171 , 118

-  , 202 , 130 , 201 , 125 , 250 , 89  , 71  , 240

-  , 173 , 212 , 162 , 175 , 156 , 164 , 114 , 192

-  , 183 , 253 , 147 , 38  , 54  , 63  , 247 , 204

-  , 52  , 165 , 229 , 241 , 113 , 216 , 49  , 21

-  , 4   , 199 , 35  , 195 , 24  , 150 , 5   , 154

-  , 7   , 18  , 128 , 226 , 235 , 39  , 178 , 117

-  , 9   , 131 , 44  , 26  , 27  , 110 , 90  , 160

-  , 82  , 59  , 214 , 179 , 41  , 227 , 47  , 132

-  , 83  , 209 , 0   , 237 , 32  , 252 , 177 , 91

-  , 106 , 203 , 190 , 57  , 74  , 76  , 88  , 207

-  , 208 , 239 , 170 , 251 , 67  , 77  , 51  , 133

-  , 69  , 249 , 2   , 127 , 80  , 60  , 159 , 168

-  , 81  , 163 , 64  , 143 , 146 , 157 , 56  , 245

-  , 188 , 182 , 218 , 33  , 16  , 255 , 243 , 210

-  , 205 , 12  , 19  , 236 , 95  , 151 , 68  , 23

-  , 196 , 167 , 126 , 61  , 100 , 93  , 25  , 115

-  , 96  , 129 , 79  , 220 , 34  , 42  , 144 , 136

-  , 70  , 238 , 184 , 20  , 222 , 94  , 11  , 219

-  , 224 , 50  , 58  , 10  , 73  , 6   , 36  , 92

-  , 194 , 211 , 172 , 98  , 145 , 149 , 228 , 121

-  , 231 , 200 , 55  , 109 , 141 , 213 , 78  , 169

-  , 108 , 86  , 244 , 234 , 101 , 122 , 174 , 8

-  , 186 , 120 , 37  , 46  , 28  , 166 , 180 , 198

-  , 232 , 221 , 116 , 31  , 75  , 189 , 139 , 138

-  , 112 , 62  , 181 , 102 , 72  , 3   , 246 , 14

-  , 97  , 53  , 87  , 185 , 134 , 193 , 29  , 158

-  , 225 , 248 , 152 , 17  , 105 , 217 , 142 , 148

-  , 155 , 30  , 135 , 233 , 206 , 85  , 40  , 223

-  , 140 , 161 , 137 , 13  , 191 , 230 , 66  , 104

-  , 65  , 153 , 45  , 15  , 176 , 84  , 187 , 22

-  };

-

-static uint8_t xtime(int in) {

-  in <<= 1;

-  if( in&0x100 ) in ^= 0x11b;

-  return (uint8_t)in;

-  }

-

-static void expand_key(const uint8_t* key, uint32_t* expanded_key) {

-  int   nrounds;

-  union {

-    uint8_t b[16];

-    uint32_t w[4];

-    } W;

-  uint8_t xor = 1;

-

-  memcpy( &W, key, 16 );

-  memcpy( expanded_key, &W, 16 );

-

-  for( nrounds = 0; nrounds < 10; ++nrounds ) {

-

-      // update key schedule

-    W.b[0] ^= sbox_e[W.b[12+1]] ^ xor;

-    W.b[1] ^= sbox_e[W.b[12+2]];

-    W.b[2] ^= sbox_e[W.b[12+3]];

-    W.b[3] ^= sbox_e[W.b[12+0]];

-    W.w[1] ^= W.w[0];

-    W.w[2] ^= W.w[1];

-    W.w[3] ^= W.w[2];

-

-    xor = xtime( xor );

-

-    expanded_key += 4;

-    memcpy( expanded_key, &W, 16 );

-    }

-  }

-

-void AES_encrypt_block(const uint8_t* key, const uint8_t* in, uint8_t* out) {

-  int j, nrounds;

-  union {

-    uint8_t b[16];

-    uint32_t w[4];

-    } rd_state;

-  uint32_t expanded_key[11 * 4];

-  uint32_t* expkey = &expanded_key[0];

-

-  expand_key( key, expanded_key );

-

-  memcpy( &rd_state, in, 16 );

-

-    // xor with initial key

-  rd_state.w[0] ^= *expkey++;

-  rd_state.w[1] ^= *expkey++;

-  rd_state.w[2] ^= *expkey++;

-  rd_state.w[3] ^= *expkey++;

-

-  nrounds = 10;

-

-  do {

-    uint8_t tmp;

-

-      // bytesub && shiftrow

-

-      // 1st

-    rd_state.b[0] = sbox_e[rd_state.b[0]];

-    rd_state.b[4] = sbox_e[rd_state.b[4]];

-    rd_state.b[8] = sbox_e[rd_state.b[8]];

-    rd_state.b[12] = sbox_e[rd_state.b[12]];

-

-      // 2nd

-    tmp = rd_state.b[1];

-    rd_state.b[1] = sbox_e[rd_state.b[5]];

-    rd_state.b[5] = sbox_e[rd_state.b[9]];

-    rd_state.b[9] = sbox_e[rd_state.b[13]];

-    rd_state.b[13] = sbox_e[tmp];

-

-      // 3th

-    tmp = rd_state.b[2];

-    rd_state.b[2] = sbox_e[rd_state.b[10]];

-    rd_state.b[10] = sbox_e[tmp];

-    tmp = rd_state.b[6];

-    rd_state.b[6] = sbox_e[rd_state.b[14]];

-    rd_state.b[14] = sbox_e[tmp];

-

-      // 4th

-    tmp = rd_state.b[3];

-    rd_state.b[3] = sbox_e[rd_state.b[15]];

-    rd_state.b[15] = sbox_e[rd_state.b[11]];

-    rd_state.b[11] = sbox_e[rd_state.b[7]];

-    rd_state.b[7] = sbox_e[tmp];

-

-      // mixcolumn except for last round

-    if( --nrounds ) {

-      for( j = 0; j < 16; j += 4 ) {

-        uint8_t tmp =

-            rd_state.b[j+0] ^

-            rd_state.b[j+1] ^

-            rd_state.b[j+2] ^

-            rd_state.b[j+3];

-

-        rd_state.b[j+0] ^= xtime( rd_state.b[j+0] ^ rd_state.b[j+1] ) ^ tmp;

-        rd_state.b[j+1] ^= xtime( rd_state.b[j+1] ^ rd_state.b[j+2] ) ^ tmp;

-        rd_state.b[j+2] ^= xtime( rd_state.b[j+2] ^ rd_state.b[j+3] ) ^ tmp;

-        rd_state.b[j+3] =

-            rd_state.b[j+0] ^

-            rd_state.b[j+1] ^

-            rd_state.b[j+2] ^

-            tmp;

-        }

-      }

-

-    rd_state.w[0] ^= *expkey++;

-    rd_state.w[1] ^= *expkey++;

-    rd_state.w[2] ^= *expkey++;

-    rd_state.w[3] ^= *expkey++;

-  } while( nrounds );

-

-  memcpy( out, &rd_state, 16 );

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Optimized for code size. Lacking decrypt functionality.
+// Currently 1042 bytes of code.
+
+#include "aes.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <inttypes.h>
+
+static const uint8_t sbox_e[256]= {
+    99  , 124 , 119 , 123 , 242 , 107 , 111 , 197
+  , 48  , 1   , 103 , 43  , 254 , 215 , 171 , 118
+  , 202 , 130 , 201 , 125 , 250 , 89  , 71  , 240
+  , 173 , 212 , 162 , 175 , 156 , 164 , 114 , 192
+  , 183 , 253 , 147 , 38  , 54  , 63  , 247 , 204
+  , 52  , 165 , 229 , 241 , 113 , 216 , 49  , 21
+  , 4   , 199 , 35  , 195 , 24  , 150 , 5   , 154
+  , 7   , 18  , 128 , 226 , 235 , 39  , 178 , 117
+  , 9   , 131 , 44  , 26  , 27  , 110 , 90  , 160
+  , 82  , 59  , 214 , 179 , 41  , 227 , 47  , 132
+  , 83  , 209 , 0   , 237 , 32  , 252 , 177 , 91
+  , 106 , 203 , 190 , 57  , 74  , 76  , 88  , 207
+  , 208 , 239 , 170 , 251 , 67  , 77  , 51  , 133
+  , 69  , 249 , 2   , 127 , 80  , 60  , 159 , 168
+  , 81  , 163 , 64  , 143 , 146 , 157 , 56  , 245
+  , 188 , 182 , 218 , 33  , 16  , 255 , 243 , 210
+  , 205 , 12  , 19  , 236 , 95  , 151 , 68  , 23
+  , 196 , 167 , 126 , 61  , 100 , 93  , 25  , 115
+  , 96  , 129 , 79  , 220 , 34  , 42  , 144 , 136
+  , 70  , 238 , 184 , 20  , 222 , 94  , 11  , 219
+  , 224 , 50  , 58  , 10  , 73  , 6   , 36  , 92
+  , 194 , 211 , 172 , 98  , 145 , 149 , 228 , 121
+  , 231 , 200 , 55  , 109 , 141 , 213 , 78  , 169
+  , 108 , 86  , 244 , 234 , 101 , 122 , 174 , 8
+  , 186 , 120 , 37  , 46  , 28  , 166 , 180 , 198
+  , 232 , 221 , 116 , 31  , 75  , 189 , 139 , 138
+  , 112 , 62  , 181 , 102 , 72  , 3   , 246 , 14
+  , 97  , 53  , 87  , 185 , 134 , 193 , 29  , 158
+  , 225 , 248 , 152 , 17  , 105 , 217 , 142 , 148
+  , 155 , 30  , 135 , 233 , 206 , 85  , 40  , 223
+  , 140 , 161 , 137 , 13  , 191 , 230 , 66  , 104
+  , 65  , 153 , 45  , 15  , 176 , 84  , 187 , 22
+  };
+
+static uint8_t xtime(int in) {
+  in <<= 1;
+  if( in&0x100 ) in ^= 0x11b;
+  return (uint8_t)in;
+  }
+
+static void expand_key(const uint8_t* key, uint32_t* expanded_key) {
+  int   nrounds;
+  union {
+    uint8_t b[16];
+    uint32_t w[4];
+    } W;
+  uint8_t xor = 1;
+
+  memcpy( &W, key, 16 );
+  memcpy( expanded_key, &W, 16 );
+
+  for( nrounds = 0; nrounds < 10; ++nrounds ) {
+
+      // update key schedule
+    W.b[0] ^= sbox_e[W.b[12+1]] ^ xor;
+    W.b[1] ^= sbox_e[W.b[12+2]];
+    W.b[2] ^= sbox_e[W.b[12+3]];
+    W.b[3] ^= sbox_e[W.b[12+0]];
+    W.w[1] ^= W.w[0];
+    W.w[2] ^= W.w[1];
+    W.w[3] ^= W.w[2];
+
+    xor = xtime( xor );
+
+    expanded_key += 4;
+    memcpy( expanded_key, &W, 16 );
+    }
+  }
+
+void AES_encrypt_block(const uint8_t* key, const uint8_t* in, uint8_t* out) {
+  int j, nrounds;
+  union {
+    uint8_t b[16];
+    uint32_t w[4];
+    } rd_state;
+  uint32_t expanded_key[11 * 4];
+  uint32_t* expkey = &expanded_key[0];
+
+  expand_key( key, expanded_key );
+
+  memcpy( &rd_state, in, 16 );
+
+    // xor with initial key
+  rd_state.w[0] ^= *expkey++;
+  rd_state.w[1] ^= *expkey++;
+  rd_state.w[2] ^= *expkey++;
+  rd_state.w[3] ^= *expkey++;
+
+  nrounds = 10;
+
+  do {
+    uint8_t tmp;
+
+      // bytesub && shiftrow
+
+      // 1st
+    rd_state.b[0] = sbox_e[rd_state.b[0]];
+    rd_state.b[4] = sbox_e[rd_state.b[4]];
+    rd_state.b[8] = sbox_e[rd_state.b[8]];
+    rd_state.b[12] = sbox_e[rd_state.b[12]];
+
+      // 2nd
+    tmp = rd_state.b[1];
+    rd_state.b[1] = sbox_e[rd_state.b[5]];
+    rd_state.b[5] = sbox_e[rd_state.b[9]];
+    rd_state.b[9] = sbox_e[rd_state.b[13]];
+    rd_state.b[13] = sbox_e[tmp];
+
+      // 3th
+    tmp = rd_state.b[2];
+    rd_state.b[2] = sbox_e[rd_state.b[10]];
+    rd_state.b[10] = sbox_e[tmp];
+    tmp = rd_state.b[6];
+    rd_state.b[6] = sbox_e[rd_state.b[14]];
+    rd_state.b[14] = sbox_e[tmp];
+
+      // 4th
+    tmp = rd_state.b[3];
+    rd_state.b[3] = sbox_e[rd_state.b[15]];
+    rd_state.b[15] = sbox_e[rd_state.b[11]];
+    rd_state.b[11] = sbox_e[rd_state.b[7]];
+    rd_state.b[7] = sbox_e[tmp];
+
+      // mixcolumn except for last round
+    if( --nrounds ) {
+      for( j = 0; j < 16; j += 4 ) {
+        uint8_t tmp =
+            rd_state.b[j+0] ^
+            rd_state.b[j+1] ^
+            rd_state.b[j+2] ^
+            rd_state.b[j+3];
+
+        rd_state.b[j+0] ^= xtime( rd_state.b[j+0] ^ rd_state.b[j+1] ) ^ tmp;
+        rd_state.b[j+1] ^= xtime( rd_state.b[j+1] ^ rd_state.b[j+2] ) ^ tmp;
+        rd_state.b[j+2] ^= xtime( rd_state.b[j+2] ^ rd_state.b[j+3] ) ^ tmp;
+        rd_state.b[j+3] =
+            rd_state.b[j+0] ^
+            rd_state.b[j+1] ^
+            rd_state.b[j+2] ^
+            tmp;
+        }
+      }
+
+    rd_state.w[0] ^= *expkey++;
+    rd_state.w[1] ^= *expkey++;
+    rd_state.w[2] ^= *expkey++;
+    rd_state.w[3] ^= *expkey++;
+  } while( nrounds );
+
+  memcpy( out, &rd_state, 16 );
+}
diff --git a/common/security/aes.h b/common/security/aes.h
index 79c2792..9277d5e 100644
--- a/common/security/aes.h
+++ b/common/security/aes.h
@@ -1,37 +1,37 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SECURITY_AES_H__

-#define OMAHA_COMMON_SECURITY_AES_H__

-

-#include <inttypes.h>

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-// Encrypt a block.

-// Both key and block size are 128 bits.

-void AES_encrypt_block(const uint8_t* key,

-                       const uint8_t* in,

-                       uint8_t* out );

-

-#define AES_BLOCK_SIZE 16

-

-#ifdef __cplusplus

-}

-#endif

-

-#endif  // OMAHA_COMMON_SECURITY_AES_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SECURITY_AES_H__
+#define OMAHA_COMMON_SECURITY_AES_H__
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Encrypt a block.
+// Both key and block size are 128 bits.
+void AES_encrypt_block(const uint8_t* key,
+                       const uint8_t* in,
+                       uint8_t* out );
+
+#define AES_BLOCK_SIZE 16
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // OMAHA_COMMON_SECURITY_AES_H__
diff --git a/common/security/b64.c b/common/security/b64.c
index df7b112..2d95cfc 100644
--- a/common/security/b64.c
+++ b/common/security/b64.c
@@ -1,88 +1,88 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "b64.h"

-

-static const char b64outmap[64] = {

-  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',

-  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',

-  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',

-  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',

-  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'

-};

-

-static const char b64inmap[96] = {

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0,

-  53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 0, 0, 0, 0, 0, 0,

-  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,

-  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 0, 64,

-  0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,

-  42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0,

-};

-

-int B64_encode(const uint8_t* input,

-               int input_length,

-               char* output,

-               int output_max) {

-  unsigned int accu = 0;

-  int shift = 0;

-  int output_size = 0;

-

-  while (input_length--) {

-    accu <<= 8;

-    accu |= *input++;

-    shift += 8;

-

-    while (shift >= 6) {

-      if (output_size >= output_max) return -1;  // out of output space

-      output[output_size++] = b64outmap[(accu >> (shift - 6)) & 63];

-      shift -= 6;

-    }

-  }

-  if (shift) {

-    if (output_size >= output_max) return -1;  // out of output space

-    accu <<= 8;  // pad with 0 byte really

-    shift += 8;

-    output[output_size++] = b64outmap[(accu >> (shift - 6)) & 63];

-  }

-

-  // Output terminating 0

-  if (output_size >= output_max) return -1;  // out of output space

-  output[output_size] = '\0';

-

-  return output_size;

-}

-

-int B64_decode(const char* input,

-               uint8_t* output,

-               int output_max) {

-  unsigned int accu = 0;

-  int shift = 0;

-  int output_size = 0;

-

-  while (*input) {

-    unsigned char in = *input++ & 255;

-    if (in < 32 || in > 127 || !b64inmap[in - 32]) return -1;  // invalid input

-    accu <<= 6;

-    accu |= (b64inmap[in - 32] - 1);

-    shift += 6;

-    if (shift >= 8) {

-      if (output_size >= output_max) return -1;  // out of output space

-      output[output_size++] = (accu >> (shift - 8)) & 255;

-      shift -= 8;

-    }

-  }

-  return output_size;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "b64.h"
+
+static const char b64outmap[64] = {
+  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
+};
+
+static const char b64inmap[96] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0,
+  53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 0, 0, 0, 0, 0, 0,
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 0, 64,
+  0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+  42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0,
+};
+
+int B64_encode(const uint8_t* input,
+               int input_length,
+               char* output,
+               int output_max) {
+  unsigned int accu = 0;
+  int shift = 0;
+  int output_size = 0;
+
+  while (input_length--) {
+    accu <<= 8;
+    accu |= *input++;
+    shift += 8;
+
+    while (shift >= 6) {
+      if (output_size >= output_max) return -1;  // out of output space
+      output[output_size++] = b64outmap[(accu >> (shift - 6)) & 63];
+      shift -= 6;
+    }
+  }
+  if (shift) {
+    if (output_size >= output_max) return -1;  // out of output space
+    accu <<= 8;  // pad with 0 byte really
+    shift += 8;
+    output[output_size++] = b64outmap[(accu >> (shift - 6)) & 63];
+  }
+
+  // Output terminating 0
+  if (output_size >= output_max) return -1;  // out of output space
+  output[output_size] = '\0';
+
+  return output_size;
+}
+
+int B64_decode(const char* input,
+               uint8_t* output,
+               int output_max) {
+  unsigned int accu = 0;
+  int shift = 0;
+  int output_size = 0;
+
+  while (*input) {
+    unsigned char in = *input++ & 255;
+    if (in < 32 || in > 127 || !b64inmap[in - 32]) return -1;  // invalid input
+    accu <<= 6;
+    accu |= (b64inmap[in - 32] - 1);
+    shift += 6;
+    if (shift >= 8) {
+      if (output_size >= output_max) return -1;  // out of output space
+      output[output_size++] = (accu >> (shift - 8)) & 255;
+      shift -= 8;
+    }
+  }
+  return output_size;
+}
diff --git a/common/security/b64.h b/common/security/b64.h
index 1e7364b..a48a931 100644
--- a/common/security/b64.h
+++ b/common/security/b64.h
@@ -1,38 +1,38 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SECURITY_B64_H__

-#define OMAHA_COMMON_SECURITY_B64_H__

-

-#include <inttypes.h>

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-int B64_encode(const uint8_t* input,

-              int input_length,

-              char* output,

-              int output_max);

-

-int B64_decode(const char* input,

-               uint8_t* output,

-               int output_max);

-

-#ifdef __cplusplus

-}

-#endif

-

-#endif  // OMAHA_COMMON_SECURITY_B64_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SECURITY_B64_H__
+#define OMAHA_COMMON_SECURITY_B64_H__
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int B64_encode(const uint8_t* input,
+              int input_length,
+              char* output,
+              int output_max);
+
+int B64_decode(const char* input,
+               uint8_t* output,
+               int output_max);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // OMAHA_COMMON_SECURITY_B64_H__
diff --git a/common/security/build.scons b/common/security/build.scons
index 3812cdc..eb77083 100644
--- a/common/security/build.scons
+++ b/common/security/build.scons
@@ -1,49 +1,49 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-#

-# Build Security library

-#

-security_env = env.Clone()

-security_env.Append(

-    CPPPATH = [

-        '$MAIN_DIR/third_party/c99/include',

-        ],

-    CCFLAGS = [

-        '/wd4242',  # conversion from 'type1' to 'type2', possible loss of data

-        '/wd4244',  # conversion from 'type1' to 'type2', possible loss of data

-        '/wd4255',  # no function prototype given: converting '()' to '(void)'

-        '/wd4510',  # default constructor could not be generated

-        '/wd4610',  # object 'class' can never be instantiated

-        ],

-)

-

-

-security_inputs = [

-    'aes.c',

-    'b64.c',

-    'challenger.cc',

-    'hmac.c',

-    'md5.c',

-    'rc4.c',

-    'rsa.cc',

-    'sha.c',

-    ]

-

-security_env.ComponentLibrary('security.lib', security_inputs)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+#
+# Build Security library
+#
+security_env = env.Clone()
+security_env.Append(
+    CPPPATH = [
+        '$MAIN_DIR/third_party/c99/include',
+        ],
+    CCFLAGS = [
+        '/wd4242',  # conversion from 'type1' to 'type2', possible loss of data
+        '/wd4244',  # conversion from 'type1' to 'type2', possible loss of data
+        '/wd4255',  # no function prototype given: converting '()' to '(void)'
+        '/wd4510',  # default constructor could not be generated
+        '/wd4610',  # object 'class' can never be instantiated
+        ],
+)
+
+
+security_inputs = [
+    'aes.c',
+    'b64.c',
+    'challenger.cc',
+    'hmac.c',
+    'md5.c',
+    'rc4.c',
+    'rsa.cc',
+    'sha.c',
+    ]
+
+security_env.ComponentLibrary('security.lib', security_inputs)
diff --git a/common/security/challenger.cc b/common/security/challenger.cc
index e93bef0..ab3ee95 100644
--- a/common/security/challenger.cc
+++ b/common/security/challenger.cc
@@ -1,84 +1,84 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "challenger.h"

-

-#include <stdlib.h>

-#include <string.h>

-#include <stdio.h>

-

-#include "rsa.h"

-#include "md5.h"

-#include "aes.h"

-#include "b64.h"

-

-// Windows compilers do not have C99 support yet.

-#if defined(WIN32) || defined(_WIN32)

-#ifndef snprintf

-#define snprintf _snprintf

-#endif

-#endif

-

-Challenger::Challenger(RSA::PublicKey pkey,

-                       const unsigned char* seed, int seed_size)

-    : rsa_(pkey) {

-  memset(count_, 0, sizeof(count_));

-  // Use seed as key for AES. Compress seed first.

-  MD5(seed, seed_size, seed_);

-}

-

-const char* Challenger::challenge() {

-  uint8_t ctr[AES_BLOCK_SIZE];

-

-  // Compute current challenge.

-  AES_encrypt_block(seed_, count_, ctr);

-

-  // Increment count for future fresh challenges.

-  for (size_t i = 0; i < sizeof(count_) && !++count_[i]; ++i);

-

-  // Prepend our version number.

-  char* p = challenge_;

-  p += snprintf(challenge_, sizeof(challenge_), "%d:", rsa_.version());

-

-  // Append our current challenge.

-  B64_encode(ctr, sizeof(ctr), p, sizeof(challenge_) - (p - challenge_));

-

-  return challenge_;

-}

-

-bool Challenger::verify(const char* hash, const char* signature) const {

-  char message[128];

-  uint8_t sigbuf[128];

-

-  // Expect exactly 128 bytes of decoded signature data.

-  if (B64_decode(signature, sigbuf, sizeof(sigbuf)) != sizeof(sigbuf))

-    return false;

-

-  // Verify signature with baked-in public key and recover embedded message.

-  int result = rsa_.verify(sigbuf, sizeof(sigbuf),

-                           message, sizeof(message) - 1);

-

-  if (result < 0 || result >= static_cast<int>(sizeof(message) - 1))

-    return false;

-

-  // Since we're expecting a textual message, 0-terminate it.

-  message[result] = '\0';

-

-  // Construct and compare expected against received signed message.

-  char expected[128];

-  snprintf(expected, sizeof(expected), "%s:%s", challenge_, hash);

-

-  return !strcmp(expected, message);

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "challenger.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "rsa.h"
+#include "md5.h"
+#include "aes.h"
+#include "b64.h"
+
+// Windows compilers do not have C99 support yet.
+#if defined(WIN32) || defined(_WIN32)
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+Challenger::Challenger(RSA::PublicKey pkey,
+                       const unsigned char* seed, int seed_size)
+    : rsa_(pkey) {
+  memset(count_, 0, sizeof(count_));
+  // Use seed as key for AES. Compress seed first.
+  MD5(seed, seed_size, seed_);
+}
+
+const char* Challenger::challenge() {
+  uint8_t ctr[AES_BLOCK_SIZE];
+
+  // Compute current challenge.
+  AES_encrypt_block(seed_, count_, ctr);
+
+  // Increment count for future fresh challenges.
+  for (size_t i = 0; i < sizeof(count_) && !++count_[i]; ++i);
+
+  // Prepend our version number.
+  char* p = challenge_;
+  p += snprintf(challenge_, sizeof(challenge_), "%d:", rsa_.version());
+
+  // Append our current challenge.
+  B64_encode(ctr, sizeof(ctr), p, sizeof(challenge_) - (p - challenge_));
+
+  return challenge_;
+}
+
+bool Challenger::verify(const char* hash, const char* signature) const {
+  char message[128];
+  uint8_t sigbuf[128];
+
+  // Expect exactly 128 bytes of decoded signature data.
+  if (B64_decode(signature, sigbuf, sizeof(sigbuf)) != sizeof(sigbuf))
+    return false;
+
+  // Verify signature with baked-in public key and recover embedded message.
+  int result = rsa_.verify(sigbuf, sizeof(sigbuf),
+                           message, sizeof(message) - 1);
+
+  if (result < 0 || result >= static_cast<int>(sizeof(message) - 1))
+    return false;
+
+  // Since we're expecting a textual message, 0-terminate it.
+  message[result] = '\0';
+
+  // Construct and compare expected against received signed message.
+  char expected[128];
+  snprintf(expected, sizeof(expected), "%s:%s", challenge_, hash);
+
+  return !strcmp(expected, message);
+}
diff --git a/common/security/challenger.h b/common/security/challenger.h
index feb067d..d2d6e0a 100644
--- a/common/security/challenger.h
+++ b/common/security/challenger.h
@@ -1,50 +1,50 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SECURITY_CHALLENGER_H__

-#define OMAHA_COMMON_SECURITY_CHALLENGER_H__

-

-#include <inttypes.h>

-

-#include "md5.h"

-#include "aes.h"

-#include "rsa.h"

-

-class Challenger {

- public:

-  // Instantiate internal PRNG with seed. Use a proper method on your

-  // target platform to collect some entropy. For windows for instance,

-  // use CryptoAPI; on unix, read some from /dev/urandom.

-  // 128 bits of entropy is plenty.

-  explicit Challenger(RSA::PublicKey public_key,

-                      const uint8_t* seed, int seed_size);

-

-  // Not a const method! Every call updates internal state and never

-  // are identical challenges returned.

-  // Returns WebSafe base64 encoded string.

-  const char* challenge();

-

-  // Verifies whether signature contains current challenge and hash.

-  // Arguments are expected to be WebSafe base64 encoded strings.

-  bool verify(const char* hash, const char* signature) const;

-

- private:

-  char challenge_[64];

-  uint8_t count_[AES_BLOCK_SIZE];

-  uint8_t seed_[MD5_DIGEST_SIZE];

-  RSA rsa_;

-};

-

-#endif  // OMAHA_COMMON_SECURITY_CHALLENGER_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SECURITY_CHALLENGER_H__
+#define OMAHA_COMMON_SECURITY_CHALLENGER_H__
+
+#include <inttypes.h>
+
+#include "md5.h"
+#include "aes.h"
+#include "rsa.h"
+
+class Challenger {
+ public:
+  // Instantiate internal PRNG with seed. Use a proper method on your
+  // target platform to collect some entropy. For windows for instance,
+  // use CryptoAPI; on unix, read some from /dev/urandom.
+  // 128 bits of entropy is plenty.
+  explicit Challenger(RSA::PublicKey public_key,
+                      const uint8_t* seed, int seed_size);
+
+  // Not a const method! Every call updates internal state and never
+  // are identical challenges returned.
+  // Returns WebSafe base64 encoded string.
+  const char* challenge();
+
+  // Verifies whether signature contains current challenge and hash.
+  // Arguments are expected to be WebSafe base64 encoded strings.
+  bool verify(const char* hash, const char* signature) const;
+
+ private:
+  char challenge_[64];
+  uint8_t count_[AES_BLOCK_SIZE];
+  uint8_t seed_[MD5_DIGEST_SIZE];
+  RSA rsa_;
+};
+
+#endif  // OMAHA_COMMON_SECURITY_CHALLENGER_H__
diff --git a/common/security/hash-internal.h b/common/security/hash-internal.h
index 1b62b05..9bade84 100644
--- a/common/security/hash-internal.h
+++ b/common/security/hash-internal.h
@@ -1,52 +1,52 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SECURITY_HASH_INTERNAL_H__

-#define OMAHA_COMMON_SECURITY_HASH_INTERNAL_H__

-

-#include <inttypes.h>

-

-#ifdef __cplusplus

-extern "C" {

-#endif  // __cplusplus

-

-struct HASH_CTX;  // forward decl

-

-typedef struct HASH_VTAB {

-  void (* const init)(struct HASH_CTX*);

-  void (* const update)(struct HASH_CTX*, const void*, int);

-  const uint8_t* (* const final)(struct HASH_CTX*);

-  const uint8_t* (* const hash)(const void*, int, uint8_t*);

-  int size;

-} HASH_VTAB;

-

-typedef struct HASH_CTX {

-  const HASH_VTAB * f;

-  uint64_t count;

-  uint8_t buf[64];

-  uint32_t state[8];  // upto SHA2

-} HASH_CTX;

-

-#define HASH_init(ctx) (ctx)->f->init(ctx)

-#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)

-#define HASH_final(ctx) (ctx)->f->final(ctx)

-#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)

-#define HASH_size(ctx) (ctx)->f->size

-

-#ifdef __cplusplus

-}

-#endif  // __cplusplus

-

-#endif  // OMAHA_COMMON_SECURITY_HASH_INTERNAL_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SECURITY_HASH_INTERNAL_H__
+#define OMAHA_COMMON_SECURITY_HASH_INTERNAL_H__
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+struct HASH_CTX;  // forward decl
+
+typedef struct HASH_VTAB {
+  void (* const init)(struct HASH_CTX*);
+  void (* const update)(struct HASH_CTX*, const void*, int);
+  const uint8_t* (* const final)(struct HASH_CTX*);
+  const uint8_t* (* const hash)(const void*, int, uint8_t*);
+  int size;
+} HASH_VTAB;
+
+typedef struct HASH_CTX {
+  const HASH_VTAB * f;
+  uint64_t count;
+  uint8_t buf[64];
+  uint32_t state[8];  // upto SHA2
+} HASH_CTX;
+
+#define HASH_init(ctx) (ctx)->f->init(ctx)
+#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)
+#define HASH_final(ctx) (ctx)->f->final(ctx)
+#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)
+#define HASH_size(ctx) (ctx)->f->size
+
+#ifdef __cplusplus
+}
+#endif  // __cplusplus
+
+#endif  // OMAHA_COMMON_SECURITY_HASH_INTERNAL_H__
diff --git a/common/security/hmac.c b/common/security/hmac.c
index e5481e9..f726da3 100644
--- a/common/security/hmac.c
+++ b/common/security/hmac.c
@@ -1,68 +1,68 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Optimized for minimal code size.

-

-#include "hmac.h"

-

-#include <memory.h>

-#include "sha.h"

-#include "md5.h"

-

-static void HMAC_init(HMAC_CTX* ctx, const void* key, int len) {

-  int i;

-  memset(&ctx->opad[0], 0, sizeof(ctx->opad));

-

-  if (len > sizeof(ctx->opad)) {

-    HASH_init(&ctx->hash);

-    HASH_update(&ctx->hash, key, len);

-    memcpy(&ctx->opad[0], HASH_final(&ctx->hash), HASH_size(&ctx->hash));

-  } else {

-    memcpy(&ctx->opad[0], key, len);

-  }

-

-  for (i = 0; i < sizeof(ctx->opad); ++i) {

-    ctx->opad[i] ^= 0x36;

-  }

-

-  HASH_init(&ctx->hash);

-  HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));  // hash ipad

-

-  for (i = 0; i < sizeof(ctx->opad); ++i) {

-    ctx->opad[i] ^= (0x36 ^ 0x5c);

-  }

-}

-

-void HMAC_MD5_init(HMAC_CTX* ctx, const void* key, int len) {

-  MD5_init(&ctx->hash);

-  HMAC_init(ctx, key, len);

-}

-

-void HMAC_SHA_init(HMAC_CTX* ctx, const void* key, int len) {

-  SHA_init(&ctx->hash);

-  HMAC_init(ctx, key, len);

-}

-

-const uint8_t* HMAC_final(HMAC_CTX* ctx) {

-  uint8_t digest[32];  // upto SHA2

-  memcpy(digest, HASH_final(&ctx->hash),

-         (HASH_size(&ctx->hash) <= sizeof(digest) ?

-             HASH_size(&ctx->hash) : sizeof(digest)));

-  HASH_init(&ctx->hash);

-  HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));

-  HASH_update(&ctx->hash, digest, HASH_size(&ctx->hash));

-  memset(&ctx->opad[0], 0, sizeof(ctx->opad));  // wipe key

-  return HASH_final(&ctx->hash);

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Optimized for minimal code size.
+
+#include "hmac.h"
+
+#include <memory.h>
+#include "sha.h"
+#include "md5.h"
+
+static void HMAC_init(HMAC_CTX* ctx, const void* key, int len) {
+  int i;
+  memset(&ctx->opad[0], 0, sizeof(ctx->opad));
+
+  if (len > sizeof(ctx->opad)) {
+    HASH_init(&ctx->hash);
+    HASH_update(&ctx->hash, key, len);
+    memcpy(&ctx->opad[0], HASH_final(&ctx->hash), HASH_size(&ctx->hash));
+  } else {
+    memcpy(&ctx->opad[0], key, len);
+  }
+
+  for (i = 0; i < sizeof(ctx->opad); ++i) {
+    ctx->opad[i] ^= 0x36;
+  }
+
+  HASH_init(&ctx->hash);
+  HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));  // hash ipad
+
+  for (i = 0; i < sizeof(ctx->opad); ++i) {
+    ctx->opad[i] ^= (0x36 ^ 0x5c);
+  }
+}
+
+void HMAC_MD5_init(HMAC_CTX* ctx, const void* key, int len) {
+  MD5_init(&ctx->hash);
+  HMAC_init(ctx, key, len);
+}
+
+void HMAC_SHA_init(HMAC_CTX* ctx, const void* key, int len) {
+  SHA_init(&ctx->hash);
+  HMAC_init(ctx, key, len);
+}
+
+const uint8_t* HMAC_final(HMAC_CTX* ctx) {
+  uint8_t digest[32];  // upto SHA2
+  memcpy(digest, HASH_final(&ctx->hash),
+         (HASH_size(&ctx->hash) <= sizeof(digest) ?
+             HASH_size(&ctx->hash) : sizeof(digest)));
+  HASH_init(&ctx->hash);
+  HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));
+  HASH_update(&ctx->hash, digest, HASH_size(&ctx->hash));
+  memset(&ctx->opad[0], 0, sizeof(ctx->opad));  // wipe key
+  return HASH_final(&ctx->hash);
+}
diff --git a/common/security/hmac.h b/common/security/hmac.h
index 8129d0a..fdfce11 100644
--- a/common/security/hmac.h
+++ b/common/security/hmac.h
@@ -1,42 +1,42 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SECURITY_HMAC_H__

-#define OMAHA_COMMON_SECURITY_HMAC_H__

-

-#include <inttypes.h>

-#include "hash-internal.h"

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-typedef struct HMAC_CTX {

-  HASH_CTX hash;

-  uint8_t opad[64];

-} HMAC_CTX;

-

-void HMAC_MD5_init(HMAC_CTX* ctx, const void* key, int len);

-void HMAC_SHA_init(HMAC_CTX* ctx, const void* key, int len);

-const uint8_t* HMAC_final(HMAC_CTX* ctx);

-

-#define HMAC_update(ctx, data, len) HASH_update(&(ctx)->hash, data, len)

-#define HMAC_size(ctx) HASH_size(&(ctx)->hash)

-

-#ifdef __cplusplus

-}

-#endif

-

-#endif  // OMAHA_COMMON_SECURITY_HMAC_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SECURITY_HMAC_H__
+#define OMAHA_COMMON_SECURITY_HMAC_H__
+
+#include <inttypes.h>
+#include "hash-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct HMAC_CTX {
+  HASH_CTX hash;
+  uint8_t opad[64];
+} HMAC_CTX;
+
+void HMAC_MD5_init(HMAC_CTX* ctx, const void* key, int len);
+void HMAC_SHA_init(HMAC_CTX* ctx, const void* key, int len);
+const uint8_t* HMAC_final(HMAC_CTX* ctx);
+
+#define HMAC_update(ctx, data, len) HASH_update(&(ctx)->hash, data, len)
+#define HMAC_size(ctx) HASH_size(&(ctx)->hash)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // OMAHA_COMMON_SECURITY_HMAC_H__
diff --git a/common/security/md5.c b/common/security/md5.c
index 3226277..7f3b7c1 100644
--- a/common/security/md5.c
+++ b/common/security/md5.c
@@ -1,171 +1,171 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Optimized for minimal code size.

-

-#include "md5.h"

-

-#include <stdio.h>

-#include <string.h>

-#include <inttypes.h>

-

-#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))

-

-static const char Kr[64] =

-{

-  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,

-  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,

-  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,

-  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21

-};

-

-static const int KK[64] =

-{

-  0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,

-  0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,

-  0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,

-  0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,

-  0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,

-  0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,

-  0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,

-  0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,

-  0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,

-  0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,

-  0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,

-  0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,

-  0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,

-  0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,

-  0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,

-  0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391

-};

-

-static void MD5_Transform(MD5_CTX* ctx) {

-  uint32_t W[64];

-  uint32_t A, B, C, D;

-  uint8_t* p = ctx->buf;

-  int t;

-

-  for(t = 0; t < 16; ++t) {

-    uint32_t tmp =  *p++;

-    tmp |= *p++ << 8;

-    tmp |= *p++ << 16;

-    tmp |= *p++ << 24;

-    W[t] = tmp;

-  }

-

-  A = ctx->state[0];

-  B = ctx->state[1];

-  C = ctx->state[2];

-  D = ctx->state[3];

-

-  for(t = 0; t < 64; t++) {

-    uint32_t f, tmp;

-    int g;

-

-    if (t < 16) {

-      f = (D^(B&(C^D)));

-      g = t;

-    } else if ( t < 32) {

-      f = (C^(D&(B^C)));

-      g = (5*t + 1) & 15;

-    } else if ( t < 48) {

-      f = (B^C^D);

-      g = (3*t + 5) & 15;

-    } else {

-      f = (C^(B|(~D)));

-      g = (7*t) & 15;

-    }

-

-    tmp = D;

-    D = C;

-    C = B;

-    B = B + rol(Kr[t], (A+f+KK[t]+W[g]));

-    A = tmp;

-  }

-

-  ctx->state[0] += A;

-  ctx->state[1] += B;

-  ctx->state[2] += C;

-  ctx->state[3] += D;

-}

-

-static const HASH_VTAB MD5_VTAB = {

-  MD5_init,

-  MD5_update,

-  MD5_final,

-  MD5,

-  MD5_DIGEST_SIZE

-};

-

-void MD5_init(MD5_CTX* ctx) {

-  ctx->f = &MD5_VTAB;

-  ctx->state[0] = 0x67452301;

-  ctx->state[1] = 0xEFCDAB89;

-  ctx->state[2] = 0x98BADCFE;

-  ctx->state[3] = 0x10325476;

-  ctx->count = 0;

-}

-

-

-void MD5_update(MD5_CTX* ctx, const void* data, int len) {

-  int i = ctx->count & 63;

-  const uint8_t* p = (const uint8_t*)data;

-

-  ctx->count += len;

-

-  while (len--) {

-    ctx->buf[i++] = *p++;

-    if (i == 64) {

-      MD5_Transform(ctx);

-      i = 0;

-    }

-  }

-}

-

-

-const uint8_t* MD5_final(MD5_CTX* ctx) {

-  uint8_t* p = ctx->buf;

-  uint64_t cnt = ctx->count * 8;

-  int i;

-

-  MD5_update(ctx, (uint8_t*)"\x80", 1);

-  while ((ctx->count & 63) != 56) {

-    MD5_update(ctx, (uint8_t*)"\0", 1);

-  }

-  for (i = 0; i < 8; ++i) {

-    uint8_t tmp = cnt >> (i * 8);

-    MD5_update(ctx, &tmp, 1);

-  }

-

-  for (i = 0; i < 4; i++) {

-    uint32_t tmp = ctx->state[i];

-    *p++ = tmp;

-    *p++ = tmp >> 8;

-    *p++ = tmp >> 16;

-    *p++ = tmp >> 24;

-  }

-

-  return ctx->buf;

-}

-

-

-/* Convenience function */

-const uint8_t* MD5(const void* data, int len, uint8_t* digest) {

-  MD5_CTX ctx;

-  MD5_init(&ctx);

-  MD5_update(&ctx, data, len);

-  memcpy(digest, MD5_final(&ctx), MD5_DIGEST_SIZE);

-  return digest;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Optimized for minimal code size.
+
+#include "md5.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+static const char Kr[64] =
+{
+  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,
+  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,
+  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,
+  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21
+};
+
+static const int KK[64] =
+{
+  0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+  0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+  0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+  0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+  0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+  0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+  0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+  0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+  0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+  0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+  0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+  0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+  0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+  0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+  0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+  0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
+static void MD5_Transform(MD5_CTX* ctx) {
+  uint32_t W[64];
+  uint32_t A, B, C, D;
+  uint8_t* p = ctx->buf;
+  int t;
+
+  for(t = 0; t < 16; ++t) {
+    uint32_t tmp =  *p++;
+    tmp |= *p++ << 8;
+    tmp |= *p++ << 16;
+    tmp |= *p++ << 24;
+    W[t] = tmp;
+  }
+
+  A = ctx->state[0];
+  B = ctx->state[1];
+  C = ctx->state[2];
+  D = ctx->state[3];
+
+  for(t = 0; t < 64; t++) {
+    uint32_t f, tmp;
+    int g;
+
+    if (t < 16) {
+      f = (D^(B&(C^D)));
+      g = t;
+    } else if ( t < 32) {
+      f = (C^(D&(B^C)));
+      g = (5*t + 1) & 15;
+    } else if ( t < 48) {
+      f = (B^C^D);
+      g = (3*t + 5) & 15;
+    } else {
+      f = (C^(B|(~D)));
+      g = (7*t) & 15;
+    }
+
+    tmp = D;
+    D = C;
+    C = B;
+    B = B + rol(Kr[t], (A+f+KK[t]+W[g]));
+    A = tmp;
+  }
+
+  ctx->state[0] += A;
+  ctx->state[1] += B;
+  ctx->state[2] += C;
+  ctx->state[3] += D;
+}
+
+static const HASH_VTAB MD5_VTAB = {
+  MD5_init,
+  MD5_update,
+  MD5_final,
+  MD5,
+  MD5_DIGEST_SIZE
+};
+
+void MD5_init(MD5_CTX* ctx) {
+  ctx->f = &MD5_VTAB;
+  ctx->state[0] = 0x67452301;
+  ctx->state[1] = 0xEFCDAB89;
+  ctx->state[2] = 0x98BADCFE;
+  ctx->state[3] = 0x10325476;
+  ctx->count = 0;
+}
+
+
+void MD5_update(MD5_CTX* ctx, const void* data, int len) {
+  int i = ctx->count & 63;
+  const uint8_t* p = (const uint8_t*)data;
+
+  ctx->count += len;
+
+  while (len--) {
+    ctx->buf[i++] = *p++;
+    if (i == 64) {
+      MD5_Transform(ctx);
+      i = 0;
+    }
+  }
+}
+
+
+const uint8_t* MD5_final(MD5_CTX* ctx) {
+  uint8_t* p = ctx->buf;
+  uint64_t cnt = ctx->count * 8;
+  int i;
+
+  MD5_update(ctx, (uint8_t*)"\x80", 1);
+  while ((ctx->count & 63) != 56) {
+    MD5_update(ctx, (uint8_t*)"\0", 1);
+  }
+  for (i = 0; i < 8; ++i) {
+    uint8_t tmp = cnt >> (i * 8);
+    MD5_update(ctx, &tmp, 1);
+  }
+
+  for (i = 0; i < 4; i++) {
+    uint32_t tmp = ctx->state[i];
+    *p++ = tmp;
+    *p++ = tmp >> 8;
+    *p++ = tmp >> 16;
+    *p++ = tmp >> 24;
+  }
+
+  return ctx->buf;
+}
+
+
+/* Convenience function */
+const uint8_t* MD5(const void* data, int len, uint8_t* digest) {
+  MD5_CTX ctx;
+  MD5_init(&ctx);
+  MD5_update(&ctx, data, len);
+  memcpy(digest, MD5_final(&ctx), MD5_DIGEST_SIZE);
+  return digest;
+}
diff --git a/common/security/md5.h b/common/security/md5.h
index cf51ee8..37cfc04 100644
--- a/common/security/md5.h
+++ b/common/security/md5.h
@@ -1,41 +1,41 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SECURITY_MD5_H__

-#define OMAHA_COMMON_SECURITY_MD5_H__

-

-#include <inttypes.h>

-#include "hash-internal.h"

-

-#ifdef __cplusplus

-extern "C" {

-#endif // __cplusplus

-

-typedef HASH_CTX MD5_CTX;

-

-void MD5_init(MD5_CTX* ctx);

-void MD5_update(MD5_CTX* ctx, const void* data, int len);

-const uint8_t* MD5_final(MD5_CTX* ctx);

-

-// Convenience method. Returns digest address.

-const uint8_t* MD5(const void* data, int len, uint8_t* digest);

-

-#define MD5_DIGEST_SIZE 16

-

-#ifdef __cplusplus

-}

-#endif // __cplusplus

-

-#endif  // OMAHA_COMMON_SECURITY_MD5_H__

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SECURITY_MD5_H__
+#define OMAHA_COMMON_SECURITY_MD5_H__
+
+#include <inttypes.h>
+#include "hash-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+typedef HASH_CTX MD5_CTX;
+
+void MD5_init(MD5_CTX* ctx);
+void MD5_update(MD5_CTX* ctx, const void* data, int len);
+const uint8_t* MD5_final(MD5_CTX* ctx);
+
+// Convenience method. Returns digest address.
+const uint8_t* MD5(const void* data, int len, uint8_t* digest);
+
+#define MD5_DIGEST_SIZE 16
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif  // OMAHA_COMMON_SECURITY_MD5_H__
diff --git a/common/security/rc4.c b/common/security/rc4.c
index 8bdc7d9..3f1b336 100644
--- a/common/security/rc4.c
+++ b/common/security/rc4.c
@@ -1,84 +1,84 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "rc4.h"

-

-#include <inttypes.h>

-

-void RC4_setKey(RC4_CTX* ctx, const uint8_t* key, int len) {

-  uint8_t* S = ctx->S;

-  int i, j;

-

-  for (i = 0; i < 256; ++i) {

-    S[i] = i;

-  }

-

-  j = 0;

-  for (i = 0; i < 256; ++i) {

-    uint8_t tmp;

-

-    j = (j + S[i] + key[i % len]) & 255;

-

-    tmp = S[i];

-    S[i] = S[j];

-    S[j] = tmp;

-  }

-

-  ctx->i = 0;

-  ctx->j = 0;

-}

-

-void RC4_crypt(RC4_CTX* ctx,

-               const uint8_t *in,

-               uint8_t* out,

-               int len) {

-  uint8_t i = ctx->i;

-  uint8_t j = ctx->j;

-  uint8_t* S = ctx->S;

-

-  int n;

-

-  for (n = 0; n < len; ++n) {

-    uint8_t tmp;

-

-    i = (i + 1) & 255;

-    j = (j + S[i]) & 255;

-

-    tmp = S[i];

-    S[i] = S[j];

-    S[j] = tmp;

-

-    if (in) {

-      if (out) {

-        out[n] = in[n] ^ S[(S[i] + S[j]) & 255];

-      }

-    } else {

-      if (out) {

-        out[n] = S[(S[i] + S[j]) & 255];

-      }

-    }

-  }

-

-  ctx->i = i;

-  ctx->j = j;

-}

-

-void RC4_discard(RC4_CTX* ctx, int len) {

-  RC4_crypt(ctx, 0, 0, len);

-}

-

-void RC4_stream(RC4_CTX* ctx, uint8_t* out, int len) {

-  RC4_crypt(ctx, 0, out, len);

-}

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "rc4.h"
+
+#include <inttypes.h>
+
+void RC4_setKey(RC4_CTX* ctx, const uint8_t* key, int len) {
+  uint8_t* S = ctx->S;
+  int i, j;
+
+  for (i = 0; i < 256; ++i) {
+    S[i] = i;
+  }
+
+  j = 0;
+  for (i = 0; i < 256; ++i) {
+    uint8_t tmp;
+
+    j = (j + S[i] + key[i % len]) & 255;
+
+    tmp = S[i];
+    S[i] = S[j];
+    S[j] = tmp;
+  }
+
+  ctx->i = 0;
+  ctx->j = 0;
+}
+
+void RC4_crypt(RC4_CTX* ctx,
+               const uint8_t *in,
+               uint8_t* out,
+               int len) {
+  uint8_t i = ctx->i;
+  uint8_t j = ctx->j;
+  uint8_t* S = ctx->S;
+
+  int n;
+
+  for (n = 0; n < len; ++n) {
+    uint8_t tmp;
+
+    i = (i + 1) & 255;
+    j = (j + S[i]) & 255;
+
+    tmp = S[i];
+    S[i] = S[j];
+    S[j] = tmp;
+
+    if (in) {
+      if (out) {
+        out[n] = in[n] ^ S[(S[i] + S[j]) & 255];
+      }
+    } else {
+      if (out) {
+        out[n] = S[(S[i] + S[j]) & 255];
+      }
+    }
+  }
+
+  ctx->i = i;
+  ctx->j = j;
+}
+
+void RC4_discard(RC4_CTX* ctx, int len) {
+  RC4_crypt(ctx, 0, 0, len);
+}
+
+void RC4_stream(RC4_CTX* ctx, uint8_t* out, int len) {
+  RC4_crypt(ctx, 0, out, len);
+}
diff --git a/common/security/rc4.h b/common/security/rc4.h
index 5752d42..e3e9f6e 100644
--- a/common/security/rc4.h
+++ b/common/security/rc4.h
@@ -1,40 +1,40 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SECURITY_RC4_H__

-#define OMAHA_COMMON_SECURITY_RC4_H__

-

-#include <inttypes.h>

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-typedef struct {

-  uint8_t S[256];

-  uint8_t i;

-  uint8_t j;

-} RC4_CTX;

-

-void RC4_setKey(RC4_CTX* ctx, const uint8_t* data, int len);

-void RC4_discard(RC4_CTX* ctx, int len);

-void RC4_crypt(RC4_CTX* ctx, const uint8_t* in, uint8_t* out, int len);

-void RC4_stream(RC4_CTX* ctx, uint8_t* out, int len);

-

-#ifdef __cplusplus

-}

-#endif

-

-#endif  // OMAHA_COMMON_SECURITY_RC4_H__

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SECURITY_RC4_H__
+#define OMAHA_COMMON_SECURITY_RC4_H__
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+  uint8_t S[256];
+  uint8_t i;
+  uint8_t j;
+} RC4_CTX;
+
+void RC4_setKey(RC4_CTX* ctx, const uint8_t* data, int len);
+void RC4_discard(RC4_CTX* ctx, int len);
+void RC4_crypt(RC4_CTX* ctx, const uint8_t* in, uint8_t* out, int len);
+void RC4_stream(RC4_CTX* ctx, uint8_t* out, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // OMAHA_COMMON_SECURITY_RC4_H__
diff --git a/common/security/rsa.cc b/common/security/rsa.cc
index fa26d20..4f3d104 100644
--- a/common/security/rsa.cc
+++ b/common/security/rsa.cc
@@ -1,290 +1,290 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "rsa.h"

-

-#include <stddef.h>

-#include <inttypes.h>

-#include <string.h>

-#include <stdio.h>

-

-#include "md5.h"

-#include "aes.h"

-#include "sha.h"

-#include "rc4.h"

-

-#define DINV mod[0]

-#define RR(i) mod[1 + 2*(i)]

-#define MOD(i) (mod[2 + 2*(i)] + mod[1 + 2*(i)])  // +mod[1+2*(i)] to deobscure

-

-//

-// a[] -= M

-//

-static void subM(uint32_t* a, const uint32_t* mod, int len) {

-  int64_t A = 0;

-  for (int i = 0; i < len; ++i) {

-    A += (uint64_t)a[i] - MOD(i);

-    a[i] = (uint32_t)A;

-    A >>= 32;

-  }

-}

-

-//

-// return a[] >= M

-//

-static bool geM(const uint32_t* a, const uint32_t* mod, int len) {

-  for (int i = len; i;) {

-    --i;

-    if (a[i] < MOD(i)) return false;

-    if (a[i] > MOD(i)) return true;

-  }

-  return true;  // equal

-}

-

-//

-// montgomery c[] += a * b[] / R mod M

-//

-static void montMulAdd(uint32_t* c,

-                       uint32_t a,

-                       const uint32_t* b,

-                       const uint32_t* mod,

-                       int len) {

-  uint64_t A = (uint64_t)a * b[0] + c[0];

-  uint32_t d0 = (uint32_t)A * DINV;

-  uint64_t B = (uint64_t)d0 * MOD(0) + (uint32_t)A;

-

-  int i = 1;

-  for (; i < len; ++i) {

-    A = (A >> 32) + (uint64_t)a * b[i] + c[i];

-    B = (B >> 32) + (uint64_t)d0 * MOD(i) + (uint32_t)A;

-    c[i - 1] = (uint32_t)B;

-  }

-

-  A = (A >> 32) + (B >> 32);

-

-  c[i - 1] = (uint32_t)A;

-

-  if ((A >> 32)) {  // proper probablistic padding could avoid this?

-    subM(c, mod, len);  // or moduli without the highest bit set..

-  }

-}

-

-//

-// montgomery c[] = a[] * R^2 / R mod M (= a[] * R mod M)

-//

-static void montMulR(uint32_t* c,

-                     const uint32_t* a,

-                     const uint32_t* mod,

-                     int len) {

-  memset(c, 0, len * sizeof(uint32_t));

-

-  for (int i = 0; i < len; ++i) {

-    montMulAdd(c, RR(i), a, mod, len);

-  }

-}

-

-//

-// montgomery c[] = a[] * b[] / R mod M

-//

-static void montMul(uint32_t* c,

-                    const uint32_t* a,

-                    const uint32_t* b,

-                    const uint32_t* mod,

-                    int len) {

-  memset(c, 0, len * sizeof(uint32_t));

-

-  for (int i = 0; i < len; ++i) {

-    montMulAdd(c, a[i], b, mod, len);

-  }

-}

-

-

-//

-// In-place public exponentiation.

-// Input and output big-endian byte array.

-// Returns 0 on failure or # uint8_t written in inout (always inout_len).

-//

-int RSA::raw(uint8_t* inout, int inout_len) const {

-  const uint32_t* mod = &pkey_[1];

-  int len = *mod++;

-

-  if (len > kMaxWords)

-    return 0;  // Only work with up to 2048 bit moduli.

-  if ((len * 4) != inout_len)

-    return 0;  // Input length should match modulus length.

-

-  uint32_t a[kMaxWords];

-

-  // Convert from big endian byte array to little endian word array.

-  for (int i = 0; i < len; ++i) {

-    uint32_t tmp =

-      (inout[((len - 1 - i) * 4) + 0] << 24) |

-      (inout[((len - 1 - i) * 4) + 1] << 16) |

-      (inout[((len - 1 - i) * 4) + 2] << 8) |

-      (inout[((len - 1 - i) * 4) + 3] << 0);

-    a[i] = tmp;

-  }

-

-  uint32_t aR[kMaxWords];

-  uint32_t aaR[kMaxWords];

-  uint32_t aaa[kMaxWords];

-

-  montMulR(aR, a, mod, len);       // aR = a * R mod M

-  montMul(aaR, aR, aR, mod, len);  // aaR = a^2 * R mod M

-  montMul(aaa, aaR, a, mod, len);  // aaa = a^3 mod M

-

-  // Make sure aaa < mod; aaa is at most 1x mod too large.

-  if (geM(aaa, mod, len)) {

-    subM(aaa, mod, len);

-  }

-

-  // Convert to bigendian byte array

-  int reslen = 0;

-

-  for (int i = len - 1; i >= 0; --i) {

-    uint32_t tmp = aaa[i];

-    inout[reslen++] = tmp >> 24;

-    inout[reslen++] = tmp >> 16;

-    inout[reslen++] = tmp >> 8;

-    inout[reslen++] = tmp >> 0;

-  }

-

-  return reslen;

-}

-

-//

-// Verify a Google style padded message recovery signature and return the

-// message.

-//

-int RSA::verify(const uint8_t* data, int data_len,

-                void* output, int output_len) const {

-  uint8_t res[kMaxWords * 4];

-

-  if (data_len < 0 || data_len > (kMaxWords * 4))

-    return 0;  // Input too big, 2048 bit max.

-

-  memcpy(res, data, data_len);

-

-  int reslen = this->raw(res, data_len);

-

-  if (!reslen) return 0;

-

-  uint8_t md5[16];

-

-  MD5(res, reslen - 16, md5);

-

-  for (int i = 0; i < 16; ++i) {

-    res[reslen - 16 + i] ^= md5[i];

-  }

-

-  // Unmask low part using high part as ofb key.

-  uint8_t iv[16] = {0};

-

-  for (int i = 0; i < reslen - 16; i++) {

-    if (!(i & 15))

-      AES_encrypt_block(res + reslen - 16, iv, iv);

-    res[i] ^= iv[i & 15];

-  }

-

-  res[0] &= 127;

-  res[0] %= reslen - 16 - 16;

-

-  bool result = true;

-

-  // Verify high part is hash of random in low part.

-  MD5(res + 1, res[0] + 16, md5);

-  for (int i = 0; i < 16; ++i) {

-    result = result && (res[reslen - 16 + i] == md5[i]);

-  }

-

-  if (!result) {

-    return 0;  // verification failure

-  }

-

-  // Copy message into output[]

-  if (res[0] > output_len) {

-    return 0;  // output too small, return failure

-  }

-

-  memcpy(output, res + 1, res[0]);

-

-  return res[0];

-}

-

-//

-// Hybrid encrypt message.

-// Make up RC4 key using seed and hash of msg.

-// Wrap key with RSA, encrypt msg with RC4.

-//

-int RSA::encrypt(const uint8_t* msg, int msg_len,

-                 const void* seed, int seed_len,

-                 uint8_t* output, int output_max) const {

-  int output_len = this->encryptedSize(msg_len);

-  if (output_max < 0 || output_max < output_len)

-    return 0;

-

-  int header_size = output_len - msg_len;  // Our added overhead.

-

-  // Hash of message. Least significant SHA_DIGEST_SIZE bytes of RSA number.

-  uint8_t* hash = &output[header_size - SHA_DIGEST_SIZE];

-  SHA(msg, msg_len, hash);

-

-  // Hash(Hash(message) | seed).

-  SHA_CTX sha;

-  SHA_init(&sha);

-  SHA_update(&sha, hash, SHA_DIGEST_SIZE);

-  SHA_update(&sha, seed, seed_len);

-

-  // Use this Hash(Hash(message) | seed) as RC4 key for prng.

-  RC4_CTX rc4;

-  RC4_setKey(&rc4, SHA_final(&sha), SHA_DIGEST_SIZE);

-  RC4_discard(&rc4, 1536);  // Drop some to warm up RC4.

-

-  uint8_t* key = &output[1 + 4];

-

-  // Prng conjure some bytes.

-  RC4_stream(&rc4, key, this->size() - SHA_DIGEST_SIZE);

-  key[0] &= 127;  // Drop top bit to be less than modulus.

-

-  // Mask plaintext hash with hash of prng part.

-  SHA_init(&sha);

-  SHA_update(&sha, key, this->size() - SHA_DIGEST_SIZE);

-  const uint8_t* mask = SHA_final(&sha);

-  for (int i = 0; i < SHA_DIGEST_SIZE; ++i)

-    hash[i] ^= mask[i];

-

-  // Use entire RSA number as content encryption key.

-  RC4_setKey(&rc4, key, this->size());

-  RC4_discard(&rc4, 1536);  // Warm up RC4.

-

-  // Output wire-format version, single 0 byte.

-  output[0] = 0;

-

-  // Output version, msb first.

-  uint32_t version = this->version();

-  output[1] = version >> 24;

-  output[2] = version >> 16;

-  output[3] = version >> 8;

-  output[4] = version >> 0;

-

-  // Wrap key data with public RSA key.

-  if (!this->raw(key, this->size()))

-    return 0;

-

-  // Append encrypted message.

-  RC4_crypt(&rc4, msg, &output[header_size], msg_len);

-

-  return output_len;

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "rsa.h"
+
+#include <stddef.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "md5.h"
+#include "aes.h"
+#include "sha.h"
+#include "rc4.h"
+
+#define DINV mod[0]
+#define RR(i) mod[1 + 2*(i)]
+#define MOD(i) (mod[2 + 2*(i)] + mod[1 + 2*(i)])  // +mod[1+2*(i)] to deobscure
+
+//
+// a[] -= M
+//
+static void subM(uint32_t* a, const uint32_t* mod, int len) {
+  int64_t A = 0;
+  for (int i = 0; i < len; ++i) {
+    A += (uint64_t)a[i] - MOD(i);
+    a[i] = (uint32_t)A;
+    A >>= 32;
+  }
+}
+
+//
+// return a[] >= M
+//
+static bool geM(const uint32_t* a, const uint32_t* mod, int len) {
+  for (int i = len; i;) {
+    --i;
+    if (a[i] < MOD(i)) return false;
+    if (a[i] > MOD(i)) return true;
+  }
+  return true;  // equal
+}
+
+//
+// montgomery c[] += a * b[] / R mod M
+//
+static void montMulAdd(uint32_t* c,
+                       uint32_t a,
+                       const uint32_t* b,
+                       const uint32_t* mod,
+                       int len) {
+  uint64_t A = (uint64_t)a * b[0] + c[0];
+  uint32_t d0 = (uint32_t)A * DINV;
+  uint64_t B = (uint64_t)d0 * MOD(0) + (uint32_t)A;
+
+  int i = 1;
+  for (; i < len; ++i) {
+    A = (A >> 32) + (uint64_t)a * b[i] + c[i];
+    B = (B >> 32) + (uint64_t)d0 * MOD(i) + (uint32_t)A;
+    c[i - 1] = (uint32_t)B;
+  }
+
+  A = (A >> 32) + (B >> 32);
+
+  c[i - 1] = (uint32_t)A;
+
+  if ((A >> 32)) {  // proper probablistic padding could avoid this?
+    subM(c, mod, len);  // or moduli without the highest bit set..
+  }
+}
+
+//
+// montgomery c[] = a[] * R^2 / R mod M (= a[] * R mod M)
+//
+static void montMulR(uint32_t* c,
+                     const uint32_t* a,
+                     const uint32_t* mod,
+                     int len) {
+  memset(c, 0, len * sizeof(uint32_t));
+
+  for (int i = 0; i < len; ++i) {
+    montMulAdd(c, RR(i), a, mod, len);
+  }
+}
+
+//
+// montgomery c[] = a[] * b[] / R mod M
+//
+static void montMul(uint32_t* c,
+                    const uint32_t* a,
+                    const uint32_t* b,
+                    const uint32_t* mod,
+                    int len) {
+  memset(c, 0, len * sizeof(uint32_t));
+
+  for (int i = 0; i < len; ++i) {
+    montMulAdd(c, a[i], b, mod, len);
+  }
+}
+
+
+//
+// In-place public exponentiation.
+// Input and output big-endian byte array.
+// Returns 0 on failure or # uint8_t written in inout (always inout_len).
+//
+int RSA::raw(uint8_t* inout, int inout_len) const {
+  const uint32_t* mod = &pkey_[1];
+  int len = *mod++;
+
+  if (len > kMaxWords)
+    return 0;  // Only work with up to 2048 bit moduli.
+  if ((len * 4) != inout_len)
+    return 0;  // Input length should match modulus length.
+
+  uint32_t a[kMaxWords];
+
+  // Convert from big endian byte array to little endian word array.
+  for (int i = 0; i < len; ++i) {
+    uint32_t tmp =
+      (inout[((len - 1 - i) * 4) + 0] << 24) |
+      (inout[((len - 1 - i) * 4) + 1] << 16) |
+      (inout[((len - 1 - i) * 4) + 2] << 8) |
+      (inout[((len - 1 - i) * 4) + 3] << 0);
+    a[i] = tmp;
+  }
+
+  uint32_t aR[kMaxWords];
+  uint32_t aaR[kMaxWords];
+  uint32_t aaa[kMaxWords];
+
+  montMulR(aR, a, mod, len);       // aR = a * R mod M
+  montMul(aaR, aR, aR, mod, len);  // aaR = a^2 * R mod M
+  montMul(aaa, aaR, a, mod, len);  // aaa = a^3 mod M
+
+  // Make sure aaa < mod; aaa is at most 1x mod too large.
+  if (geM(aaa, mod, len)) {
+    subM(aaa, mod, len);
+  }
+
+  // Convert to bigendian byte array
+  int reslen = 0;
+
+  for (int i = len - 1; i >= 0; --i) {
+    uint32_t tmp = aaa[i];
+    inout[reslen++] = tmp >> 24;
+    inout[reslen++] = tmp >> 16;
+    inout[reslen++] = tmp >> 8;
+    inout[reslen++] = tmp >> 0;
+  }
+
+  return reslen;
+}
+
+//
+// Verify a Google style padded message recovery signature and return the
+// message.
+//
+int RSA::verify(const uint8_t* data, int data_len,
+                void* output, int output_len) const {
+  uint8_t res[kMaxWords * 4];
+
+  if (data_len < 0 || data_len > (kMaxWords * 4))
+    return 0;  // Input too big, 2048 bit max.
+
+  memcpy(res, data, data_len);
+
+  int reslen = this->raw(res, data_len);
+
+  if (!reslen) return 0;
+
+  uint8_t md5[16];
+
+  MD5(res, reslen - 16, md5);
+
+  for (int i = 0; i < 16; ++i) {
+    res[reslen - 16 + i] ^= md5[i];
+  }
+
+  // Unmask low part using high part as ofb key.
+  uint8_t iv[16] = {0};
+
+  for (int i = 0; i < reslen - 16; i++) {
+    if (!(i & 15))
+      AES_encrypt_block(res + reslen - 16, iv, iv);
+    res[i] ^= iv[i & 15];
+  }
+
+  res[0] &= 127;
+  res[0] %= reslen - 16 - 16;
+
+  bool result = true;
+
+  // Verify high part is hash of random in low part.
+  MD5(res + 1, res[0] + 16, md5);
+  for (int i = 0; i < 16; ++i) {
+    result = result && (res[reslen - 16 + i] == md5[i]);
+  }
+
+  if (!result) {
+    return 0;  // verification failure
+  }
+
+  // Copy message into output[]
+  if (res[0] > output_len) {
+    return 0;  // output too small, return failure
+  }
+
+  memcpy(output, res + 1, res[0]);
+
+  return res[0];
+}
+
+//
+// Hybrid encrypt message.
+// Make up RC4 key using seed and hash of msg.
+// Wrap key with RSA, encrypt msg with RC4.
+//
+int RSA::encrypt(const uint8_t* msg, int msg_len,
+                 const void* seed, int seed_len,
+                 uint8_t* output, int output_max) const {
+  int output_len = this->encryptedSize(msg_len);
+  if (output_max < 0 || output_max < output_len)
+    return 0;
+
+  int header_size = output_len - msg_len;  // Our added overhead.
+
+  // Hash of message. Least significant SHA_DIGEST_SIZE bytes of RSA number.
+  uint8_t* hash = &output[header_size - SHA_DIGEST_SIZE];
+  SHA(msg, msg_len, hash);
+
+  // Hash(Hash(message) | seed).
+  SHA_CTX sha;
+  SHA_init(&sha);
+  SHA_update(&sha, hash, SHA_DIGEST_SIZE);
+  SHA_update(&sha, seed, seed_len);
+
+  // Use this Hash(Hash(message) | seed) as RC4 key for prng.
+  RC4_CTX rc4;
+  RC4_setKey(&rc4, SHA_final(&sha), SHA_DIGEST_SIZE);
+  RC4_discard(&rc4, 1536);  // Drop some to warm up RC4.
+
+  uint8_t* key = &output[1 + 4];
+
+  // Prng conjure some bytes.
+  RC4_stream(&rc4, key, this->size() - SHA_DIGEST_SIZE);
+  key[0] &= 127;  // Drop top bit to be less than modulus.
+
+  // Mask plaintext hash with hash of prng part.
+  SHA_init(&sha);
+  SHA_update(&sha, key, this->size() - SHA_DIGEST_SIZE);
+  const uint8_t* mask = SHA_final(&sha);
+  for (int i = 0; i < SHA_DIGEST_SIZE; ++i)
+    hash[i] ^= mask[i];
+
+  // Use entire RSA number as content encryption key.
+  RC4_setKey(&rc4, key, this->size());
+  RC4_discard(&rc4, 1536);  // Warm up RC4.
+
+  // Output wire-format version, single 0 byte.
+  output[0] = 0;
+
+  // Output version, msb first.
+  uint32_t version = this->version();
+  output[1] = version >> 24;
+  output[2] = version >> 16;
+  output[3] = version >> 8;
+  output[4] = version >> 0;
+
+  // Wrap key data with public RSA key.
+  if (!this->raw(key, this->size()))
+    return 0;
+
+  // Append encrypted message.
+  RC4_crypt(&rc4, msg, &output[header_size], msg_len);
+
+  return output_len;
+}
diff --git a/common/security/rsa.h b/common/security/rsa.h
index b3bb411..3403c11 100644
--- a/common/security/rsa.h
+++ b/common/security/rsa.h
@@ -1,66 +1,66 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SECURITY_RSA_H__

-#define OMAHA_COMMON_SECURITY_RSA_H__

-

-#include <inttypes.h>

-

-class RSA {

- public:

-  typedef const uint32_t PublicKeyInstance[];

-  typedef const uint32_t* PublicKey;

-

-  // Public_key as montgomery precomputed array

-  explicit RSA(PublicKey public_key) : pkey_(public_key) {}

-

-  // Verifies a Google style RSA message recovery signature.

-  //

-  // sig[] signature to verify, big-endian byte array.

-  // sig_len length of sig[] in bytes.

-  // If verified successfully, output receives the recovered

-  // message and the function returns the number of bytes.

-  // If not successful, the function returns 0.

-  // (empty message is not a useful message)

-  int verify(const uint8_t* sig, int sig_len,

-             void* output, int output_max) const;

-

-  // Hybrid encrypt message.

-  //

-  // output_max should be at least encryptedSize(msg_len)

-  // Returns 0 on failure, # output bytes on success.

-  int encrypt(const uint8_t* msg, int msg_len,

-              const void* seed, int seed_len,

-              uint8_t* output, int output_max) const;

-

-  int encryptedSize(int len) const {

-    return len + 1 + 4 + size();

-  }

-

-  // Performs in-place public key exponentiation.

-  //

-  // Input_len should match size of modulus in bytes.

-  // Returns 0 on failure, # of bytes written on success.

-  int raw(uint8_t* input, int input_len) const;

-

-  int version() const { return pkey_[0]; }

-  int size() const { return pkey_[1] * 4; }

-

- private:

-  const PublicKey pkey_;

-  static const int kMaxWords = 64;

-};

-

-#endif  // OMAHA_COMMON_SECURITY_RSA_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SECURITY_RSA_H__
+#define OMAHA_COMMON_SECURITY_RSA_H__
+
+#include <inttypes.h>
+
+class RSA {
+ public:
+  typedef const uint32_t PublicKeyInstance[];
+  typedef const uint32_t* PublicKey;
+
+  // Public_key as montgomery precomputed array
+  explicit RSA(PublicKey public_key) : pkey_(public_key) {}
+
+  // Verifies a Google style RSA message recovery signature.
+  //
+  // sig[] signature to verify, big-endian byte array.
+  // sig_len length of sig[] in bytes.
+  // If verified successfully, output receives the recovered
+  // message and the function returns the number of bytes.
+  // If not successful, the function returns 0.
+  // (empty message is not a useful message)
+  int verify(const uint8_t* sig, int sig_len,
+             void* output, int output_max) const;
+
+  // Hybrid encrypt message.
+  //
+  // output_max should be at least encryptedSize(msg_len)
+  // Returns 0 on failure, # output bytes on success.
+  int encrypt(const uint8_t* msg, int msg_len,
+              const void* seed, int seed_len,
+              uint8_t* output, int output_max) const;
+
+  int encryptedSize(int len) const {
+    return len + 1 + 4 + size();
+  }
+
+  // Performs in-place public key exponentiation.
+  //
+  // Input_len should match size of modulus in bytes.
+  // Returns 0 on failure, # of bytes written on success.
+  int raw(uint8_t* input, int input_len) const;
+
+  int version() const { return pkey_[0]; }
+  int size() const { return pkey_[1] * 4; }
+
+ private:
+  const PublicKey pkey_;
+  static const int kMaxWords = 64;
+};
+
+#endif  // OMAHA_COMMON_SECURITY_RSA_H__
diff --git a/common/security/sha.c b/common/security/sha.c
index cd6939b..dee6624 100644
--- a/common/security/sha.c
+++ b/common/security/sha.c
@@ -1,143 +1,143 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Optimized for minimal code size.

-

-#include "sha.h"

-

-#include <stdio.h>

-#include <string.h>

-#include <inttypes.h>

-

-#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))

-

-static void SHA1_Transform(SHA_CTX* ctx) {

-  uint32_t W[80];

-  uint32_t A, B, C, D, E;

-  uint8_t* p = ctx->buf;

-  int t;

-

-  for(t = 0; t < 16; ++t) {

-    uint32_t tmp =  *p++ << 24;

-    tmp |= *p++ << 16;

-    tmp |= *p++ << 8;

-    tmp |= *p++;

-    W[t] = tmp;

-  }

-

-  for(; t < 80; t++) {

-    W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);

-  }

-

-  A = ctx->state[0];

-  B = ctx->state[1];

-  C = ctx->state[2];

-  D = ctx->state[3];

-  E = ctx->state[4];

-

-  for(t = 0; t < 80; t++) {

-    uint32_t tmp = rol(5,A) + E + W[t];

-

-    if (t < 20)

-      tmp += (D^(B&(C^D))) + 0x5A827999;

-    else if ( t < 40)

-      tmp += (B^C^D) + 0x6ED9EBA1;

-    else if ( t < 60)

-      tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;

-    else

-      tmp += (B^C^D) + 0xCA62C1D6;

-

-    E = D;

-    D = C;

-    C = rol(30,B);

-    B = A;

-    A = tmp;

-  }

-

-  ctx->state[0] += A;

-  ctx->state[1] += B;

-  ctx->state[2] += C;

-  ctx->state[3] += D;

-  ctx->state[4] += E;

-}

-

-static const HASH_VTAB SHA_VTAB = {

-  SHA_init,

-  SHA_update,

-  SHA_final,

-  SHA,

-  SHA_DIGEST_SIZE

-};

-

-void SHA_init(SHA_CTX* ctx) {

-  ctx->f = &SHA_VTAB;

-  ctx->state[0] = 0x67452301;

-  ctx->state[1] = 0xEFCDAB89;

-  ctx->state[2] = 0x98BADCFE;

-  ctx->state[3] = 0x10325476;

-  ctx->state[4] = 0xC3D2E1F0;

-  ctx->count = 0;

-}

-

-

-void SHA_update(SHA_CTX* ctx, const void* data, int len) {

-  int i = ctx->count & 63;

-  const uint8_t* p = (const uint8_t*)data;

-

-  ctx->count += len;

-

-  while (len--) {

-    ctx->buf[i++] = *p++;

-    if (i == 64) {

-      SHA1_Transform(ctx);

-      i = 0;

-    }

-  }

-}

-

-

-const uint8_t* SHA_final(SHA_CTX* ctx) {

-  uint8_t *p = ctx->buf;

-  uint64_t cnt = ctx->count * 8;

-  int i;

-

-  SHA_update(ctx, (uint8_t*)"\x80", 1);

-  while ((ctx->count & 63) != 56) {

-    SHA_update(ctx, (uint8_t*)"\0", 1);

-  }

-  for (i = 0; i < 8; ++i) {

-    uint8_t tmp = cnt >> ((7 - i) * 8);

-    SHA_update(ctx, &tmp, 1);

-  }

-

-  for (i = 0; i < 5; i++) {

-    uint32_t tmp = ctx->state[i];

-    *p++ = tmp >> 24;

-    *p++ = tmp >> 16;

-    *p++ = tmp >> 8;

-    *p++ = tmp >> 0;

-  }

-

-  return ctx->buf;

-}

-

-/* Convenience function */

-const uint8_t* SHA(const void* data, int len, uint8_t* digest) {

-  SHA_CTX ctx;

-  SHA_init(&ctx);

-  SHA_update(&ctx, data, len);

-  memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);

-  return digest;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Optimized for minimal code size.
+
+#include "sha.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+static void SHA1_Transform(SHA_CTX* ctx) {
+  uint32_t W[80];
+  uint32_t A, B, C, D, E;
+  uint8_t* p = ctx->buf;
+  int t;
+
+  for(t = 0; t < 16; ++t) {
+    uint32_t tmp =  *p++ << 24;
+    tmp |= *p++ << 16;
+    tmp |= *p++ << 8;
+    tmp |= *p++;
+    W[t] = tmp;
+  }
+
+  for(; t < 80; t++) {
+    W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+  }
+
+  A = ctx->state[0];
+  B = ctx->state[1];
+  C = ctx->state[2];
+  D = ctx->state[3];
+  E = ctx->state[4];
+
+  for(t = 0; t < 80; t++) {
+    uint32_t tmp = rol(5,A) + E + W[t];
+
+    if (t < 20)
+      tmp += (D^(B&(C^D))) + 0x5A827999;
+    else if ( t < 40)
+      tmp += (B^C^D) + 0x6ED9EBA1;
+    else if ( t < 60)
+      tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
+    else
+      tmp += (B^C^D) + 0xCA62C1D6;
+
+    E = D;
+    D = C;
+    C = rol(30,B);
+    B = A;
+    A = tmp;
+  }
+
+  ctx->state[0] += A;
+  ctx->state[1] += B;
+  ctx->state[2] += C;
+  ctx->state[3] += D;
+  ctx->state[4] += E;
+}
+
+static const HASH_VTAB SHA_VTAB = {
+  SHA_init,
+  SHA_update,
+  SHA_final,
+  SHA,
+  SHA_DIGEST_SIZE
+};
+
+void SHA_init(SHA_CTX* ctx) {
+  ctx->f = &SHA_VTAB;
+  ctx->state[0] = 0x67452301;
+  ctx->state[1] = 0xEFCDAB89;
+  ctx->state[2] = 0x98BADCFE;
+  ctx->state[3] = 0x10325476;
+  ctx->state[4] = 0xC3D2E1F0;
+  ctx->count = 0;
+}
+
+
+void SHA_update(SHA_CTX* ctx, const void* data, int len) {
+  int i = ctx->count & 63;
+  const uint8_t* p = (const uint8_t*)data;
+
+  ctx->count += len;
+
+  while (len--) {
+    ctx->buf[i++] = *p++;
+    if (i == 64) {
+      SHA1_Transform(ctx);
+      i = 0;
+    }
+  }
+}
+
+
+const uint8_t* SHA_final(SHA_CTX* ctx) {
+  uint8_t *p = ctx->buf;
+  uint64_t cnt = ctx->count * 8;
+  int i;
+
+  SHA_update(ctx, (uint8_t*)"\x80", 1);
+  while ((ctx->count & 63) != 56) {
+    SHA_update(ctx, (uint8_t*)"\0", 1);
+  }
+  for (i = 0; i < 8; ++i) {
+    uint8_t tmp = cnt >> ((7 - i) * 8);
+    SHA_update(ctx, &tmp, 1);
+  }
+
+  for (i = 0; i < 5; i++) {
+    uint32_t tmp = ctx->state[i];
+    *p++ = tmp >> 24;
+    *p++ = tmp >> 16;
+    *p++ = tmp >> 8;
+    *p++ = tmp >> 0;
+  }
+
+  return ctx->buf;
+}
+
+/* Convenience function */
+const uint8_t* SHA(const void* data, int len, uint8_t* digest) {
+  SHA_CTX ctx;
+  SHA_init(&ctx);
+  SHA_update(&ctx, data, len);
+  memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);
+  return digest;
+}
diff --git a/common/security/sha.h b/common/security/sha.h
index 28e993b..e9750dd 100644
--- a/common/security/sha.h
+++ b/common/security/sha.h
@@ -1,41 +1,41 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SECURITY_SHA1_H__

-#define OMAHA_COMMON_SECURITY_SHA1_H__

-

-#include <inttypes.h>

-#include "hash-internal.h"

-

-#ifdef __cplusplus

-extern "C" {

-#endif // __cplusplus

-

-typedef HASH_CTX SHA_CTX;

-

-void SHA_init(SHA_CTX* ctx);

-void SHA_update(SHA_CTX* ctx, const void* data, int len);

-const uint8_t* SHA_final(SHA_CTX* ctx);

-

-// Convenience method. Returns digest address.

-const uint8_t* SHA(const void* data, int len, uint8_t* digest);

-

-#define SHA_DIGEST_SIZE 20

-

-#ifdef __cplusplus

-}

-#endif // __cplusplus

-

-#endif  // OMAHA_COMMON_SECURITY_SHA1_H__

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SECURITY_SHA1_H__
+#define OMAHA_COMMON_SECURITY_SHA1_H__
+
+#include <inttypes.h>
+#include "hash-internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+typedef HASH_CTX SHA_CTX;
+
+void SHA_init(SHA_CTX* ctx);
+void SHA_update(SHA_CTX* ctx, const void* data, int len);
+const uint8_t* SHA_final(SHA_CTX* ctx);
+
+// Convenience method. Returns digest address.
+const uint8_t* SHA(const void* data, int len, uint8_t* digest);
+
+#define SHA_DIGEST_SIZE 20
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif  // OMAHA_COMMON_SECURITY_SHA1_H__
diff --git a/common/serializable_object.cc b/common/serializable_object.cc
index 4f1902f..d3106da 100644
--- a/common/serializable_object.cc
+++ b/common/serializable_object.cc
@@ -1,375 +1,375 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Provides the base class framework for those objects to be serialized

-//

-// HACK:

-//

-// During the serialization/deserialization of vector<T> members, we

-// coerce the type from vector<T> to vector<byte> since we are unable to

-// get the real type vector<T> at later time. This is feasible because

-// vector<T> in the vector library we are linking now keeps track of

-// only front() and end() pointers and use them to calculate size().

-// We need to check whether this approach is still OK if we upgrade the

-// standard libraries.

-

-#include "omaha/common/serializable_object.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-

-namespace omaha {

-

-// Serialize

-bool SerializableObject::Serialize(std::vector<byte>* data) const {

-  ASSERT(data, (_T("")));

-

-  // Estimate how much memory we need

-  int size = data->size();

-  for (size_t i = 0; i < members_.size(); ++i)

-    size += (members_[i].size > 0) ? members_[i].size : sizeof(int);

-

-  // Reserve the estimated size fo vector memory

-  data->reserve(size);

-

-  // Copy over the data

-  for (size_t i = 0; i < members_.size(); ++i) {

-    switch (members_[i].type) {

-      case SERIALIZABLE_VALUE_TYPE: {

-        int pos = data->size();

-        data->resize(data->size() + members_[i].size);

-        memcpy(&(*data)[pos], members_[i].ptr, members_[i].size);

-        break;

-      }

-

-      case SERIALIZABLE_CSTRING: {

-        CString* s = reinterpret_cast<CString*>(members_[i].ptr);

-        SerializeValueList(data,

-                           reinterpret_cast<const byte*>(s->GetString()),

-                           sizeof(TCHAR),

-                           s->GetLength());

-        break;

-      }

-

-      case SERIALIZABLE_NESTED_OBJECT: {

-        SerializableObject* nested_obj =

-            reinterpret_cast<SerializableObject*>(members_[i].ptr);

-        if (!nested_obj->Serialize(data))

-          return false;

-        break;

-      }

-

-      case SERIALIZABLE_VECTOR | SERIALIZABLE_VALUE_TYPE: {

-        // Hack: coerce vector<T> to vector<byte>

-        std::vector<byte>* v =

-            reinterpret_cast<std::vector<byte>*>(members_[i].ptr);

-        if (v->size() != 0) {

-          SerializeValueList(data,

-                             &v->front(),

-                             members_[i].size,

-                             v->size() / members_[i].size);

-        } else {

-          SerializeValueList(data,

-                             NULL,

-                             members_[i].size,

-                             v->size() / members_[i].size);

-        }

-        break;

-      }

-

-      case SERIALIZABLE_VECTOR | SERIALIZABLE_CSTRING: {

-        std::vector<CString>* v =

-            reinterpret_cast<std::vector<CString>*>(members_[i].ptr);

-        SerializeSizeAndCount(data, 1, v->size());

-        if (!v->empty()) {

-          for (std::vector<CString>::const_iterator it = v->begin();

-               it != v->end();

-               ++it) {

-            SerializeValueList(data,

-                               reinterpret_cast<const byte*>(it->GetString()),

-                               sizeof(TCHAR),

-                               it->GetLength());

-          }

-        }

-        break;

-      }

-

-      case SERIALIZABLE_VECTOR | SERIALIZABLE_NESTED_OBJECT: {

-        if (!SerializeVectorNestedObject(data, members_[i].ptr))

-          return false;

-        break;

-      }

-

-      default:

-        ASSERT(false, (_T("")));

-        return false;

-    }

-  }

-

-  return true;

-}

-

-// Serialize the size and count values

-void SerializableObject::SerializeSizeAndCount(std::vector<byte>* data,

-                                               int size,

-                                               int count) const {

-  ASSERT(data, (_T("")));

-  ASSERT(size >= 0, (_T("")));

-

-  // Get current size

-  int pos = data->size();

-

-  // Adjust the size of the data buffer

-  data->resize(data->size() + 2 * sizeof(int));

-

-  // Get pointer to the position of data buffer we start to write

-  byte* ptr = &((*data)[pos]);

-

-  // Push size

-  memcpy(ptr, &size, sizeof(int));

-  ptr += sizeof(int);

-

-  // Push count

-  memcpy(ptr, &count, sizeof(int));

-  ptr += sizeof(int);

-}

-

-// Serialize a list of value-typed elements

-//

-// Args:

-//   ser_data:  pointer to the vector for the serialized data

-//   raw_data:  pointer to the raw data to be serialized

-//   size:      the size of the element in the list

-//   count:     the number of the elements in the list

-void SerializableObject::SerializeValueList(std::vector<byte>* ser_data,

-                                            const byte* raw_data,

-                                            int size,

-                                            int count) const {

-  ASSERT(ser_data, (_T("")));

-  ASSERT(size > 0, (_T("")));

-

-  // Serialize the size and count values

-  SerializeSizeAndCount(ser_data, size, count);

-

-  // Push data

-  if (count > 0) {

-    // Get current size

-    int pos = ser_data->size();

-

-    // Adjust the size of the data buffer

-    ser_data->resize(ser_data->size() + count * size);

-

-    // Get pointer to the position of data buffer we start to write

-    byte* ptr = &((*ser_data)[pos]);

-

-    // Copy data

-    memcpy(ptr, raw_data, count * size);

-  }

-}

-

-// Deserialize

-bool SerializableObject::Deserialize(byte* data, int size, uint32 version) {

-  ASSERT(data, (_T("")));

-  ASSERT(size > 0, (_T("")));

-

-  byte* tail = data + size;

-  byte** data_ptr = &data;

-  if (!DeserializeHelper(data_ptr, size, version))

-    return false;

-

-  if (*data_ptr != tail) {

-    UTIL_LOG(LE, (_T("[SerializableObject::Deserialize]")

-                  _T("[failed to deserialize all data]")));

-    return false;

-  }

-

-  return true;

-}

-

-// Deserialize helper

-bool SerializableObject::DeserializeHelper(byte** data,

-                                           int size,

-                                           uint32 version) {

-  ASSERT(data, (_T("")));

-  ASSERT(size > 0, (_T("")));

-

-  byte* tail = *data + size;

-

-  for (size_t i = 0; i < members_.size(); ++i) {

-    // Ignore those members which are persisted in newer versions

-    if (version != kLatestSerializableVersion &&

-        members_[i].version  > version) {

-      continue;

-    }

-

-    switch (members_[i].type) {

-      case SERIALIZABLE_VALUE_TYPE:

-        if (*data + members_[i].size > tail) {

-          UTIL_LOG(L6, (_T("[SerializableObject::DeserializeHelper]")

-                        _T("[overflow when deserializing value type]")));

-          return false;

-        }

-        memcpy(members_[i].ptr, *data, members_[i].size);

-        *data += members_[i].size;

-        break;

-

-      case SERIALIZABLE_CSTRING: {

-        std::vector<byte> deser_data;

-        if (!DeserializeValueList(&deser_data,

-                                  members_[i].size,

-                                  data,

-                                  tail - *data))

-          return false;

-        CString* s = reinterpret_cast<CString*>(members_[i].ptr);

-        if (deser_data.size() != 0) {

-          s->SetString(reinterpret_cast<const TCHAR*>(&deser_data.front()),

-                       deser_data.size() / members_[i].size);

-        } else {

-          s->SetString(_T(""));

-        }

-        break;

-      }

-

-      case SERIALIZABLE_NESTED_OBJECT: {

-        SerializableObject* nested_obj =

-            reinterpret_cast<SerializableObject*>(members_[i].ptr);

-        if (!nested_obj->DeserializeHelper(data, size, version))

-          return false;

-        break;

-      }

-

-      case SERIALIZABLE_VECTOR | SERIALIZABLE_VALUE_TYPE: {

-        // Hack: coerce vector<T> to vector<byte>

-        std::vector<byte>* v =

-            reinterpret_cast<std::vector<byte>*>(members_[i].ptr);

-        if (!DeserializeValueList(v, members_[i].size, data, tail - *data))

-          return false;

-        break;

-      }

-

-      case SERIALIZABLE_VECTOR | SERIALIZABLE_CSTRING: {

-        std::vector<CString>* v =

-              reinterpret_cast<std::vector<CString>*>(members_[i].ptr);

-        int count = 0;

-        if (!DeserializeSizeAndCount(&count, 1, data, tail - *data))

-          return false;

-        for (int j = 0; j < count; ++j) {

-          std::vector<byte> deser_data;

-          if (!DeserializeValueList(&deser_data,

-                                    members_[i].size,

-                                    data,

-                                    tail - *data))

-            return false;

-

-          CString s;

-          if (deser_data.size() != 0) {

-            s = CString(reinterpret_cast<const TCHAR*>(&deser_data.front()),

-                        deser_data.size() / members_[i].size);

-          }

-          v->push_back(s);

-        }

-        break;

-      }

-

-      case SERIALIZABLE_VECTOR | SERIALIZABLE_NESTED_OBJECT: {

-        if (!DeserializeVectorNestedObject(data,

-                                           tail - *data,

-                                           members_[i].ptr,

-                                           version))

-          return false;

-        break;

-      }

-

-      default:

-        ASSERT(false, (_T("")));

-        break;

-    }

-  }

-

-  return true;

-}

-

-// Serialize the size and count values

-bool SerializableObject::DeserializeSizeAndCount(int* count,

-                                                 int size,

-                                                 byte** ser_data,

-                                                 int ser_size) const {

-  ASSERT(ser_data, (_T("")));

-  ASSERT(count, (_T("")));

-

-  byte* ser_tail = *ser_data + ser_size;

-

-  // Check to make sure that the serialization data should at least contain

-  // 'size' and 'count'

-  if (*ser_data + 2 * sizeof(int) > ser_tail) {

-    UTIL_LOG(L6, (_T("[SerializableObject::DeserializeSizeAndCount]")

-                  _T("[overflow when deserializing size and count]")));

-    return false;

-  }

-

-  // Get size

-  // If the passing size is 0, skip the size check

-  int size2 = *(reinterpret_cast<const int*>(*ser_data));

-  *ser_data += sizeof(int);

-  if (size && size != size2)

-    return false;

-

-  // Get count

-  *count = *(reinterpret_cast<const int*>(*ser_data));

-  *ser_data += sizeof(int);

-

-  return true;

-}

-

-// Deserialize a list of value-typed elements

-//

-// Args:

-//   ser_data:  pointer to the vector for the serialized data

-//   size:      the size of the element in the list

-//   raw_data:  pointer to the raw data to be serialized

-//   ser_size:  size of the serization data

-bool SerializableObject::DeserializeValueList(std::vector<byte>* raw_data,

-                                              int size,

-                                              byte** ser_data,

-                                              int ser_size) {

-  ASSERT(raw_data, (_T("")));

-  ASSERT(ser_data, (_T("")));

-

-  byte* ser_tail = *ser_data + ser_size;

-

-  // Deserialize the size and count values

-  int count = 0;

-  bool ret = DeserializeSizeAndCount(&count, size, ser_data, ser_size);

-  if (!ret)

-    return false;

-

-  // Check to make sure that the serialization data is in the right size

-  if (*ser_data + count * size > ser_tail) {

-    UTIL_LOG(L6, (_T("[SerializableObject::DeserializeValueList]")

-                  _T("[overflow when deserializing value list]")));

-    return false;

-  }

-

-  // Get data

-  raw_data->resize(size * count);

-  if (count > 0) {

-    memcpy(&raw_data->front(), *ser_data, count * size);

-    *ser_data += count * size;

-  }

-

-  return true;

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Provides the base class framework for those objects to be serialized
+//
+// HACK:
+//
+// During the serialization/deserialization of vector<T> members, we
+// coerce the type from vector<T> to vector<byte> since we are unable to
+// get the real type vector<T> at later time. This is feasible because
+// vector<T> in the vector library we are linking now keeps track of
+// only front() and end() pointers and use them to calculate size().
+// We need to check whether this approach is still OK if we upgrade the
+// standard libraries.
+
+#include "omaha/common/serializable_object.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+
+namespace omaha {
+
+// Serialize
+bool SerializableObject::Serialize(std::vector<byte>* data) const {
+  ASSERT(data, (_T("")));
+
+  // Estimate how much memory we need
+  int size = data->size();
+  for (size_t i = 0; i < members_.size(); ++i)
+    size += (members_[i].size > 0) ? members_[i].size : sizeof(int);
+
+  // Reserve the estimated size fo vector memory
+  data->reserve(size);
+
+  // Copy over the data
+  for (size_t i = 0; i < members_.size(); ++i) {
+    switch (members_[i].type) {
+      case SERIALIZABLE_VALUE_TYPE: {
+        int pos = data->size();
+        data->resize(data->size() + members_[i].size);
+        memcpy(&(*data)[pos], members_[i].ptr, members_[i].size);
+        break;
+      }
+
+      case SERIALIZABLE_CSTRING: {
+        CString* s = reinterpret_cast<CString*>(members_[i].ptr);
+        SerializeValueList(data,
+                           reinterpret_cast<const byte*>(s->GetString()),
+                           sizeof(TCHAR),
+                           s->GetLength());
+        break;
+      }
+
+      case SERIALIZABLE_NESTED_OBJECT: {
+        SerializableObject* nested_obj =
+            reinterpret_cast<SerializableObject*>(members_[i].ptr);
+        if (!nested_obj->Serialize(data))
+          return false;
+        break;
+      }
+
+      case SERIALIZABLE_VECTOR | SERIALIZABLE_VALUE_TYPE: {
+        // Hack: coerce vector<T> to vector<byte>
+        std::vector<byte>* v =
+            reinterpret_cast<std::vector<byte>*>(members_[i].ptr);
+        if (v->size() != 0) {
+          SerializeValueList(data,
+                             &v->front(),
+                             members_[i].size,
+                             v->size() / members_[i].size);
+        } else {
+          SerializeValueList(data,
+                             NULL,
+                             members_[i].size,
+                             v->size() / members_[i].size);
+        }
+        break;
+      }
+
+      case SERIALIZABLE_VECTOR | SERIALIZABLE_CSTRING: {
+        std::vector<CString>* v =
+            reinterpret_cast<std::vector<CString>*>(members_[i].ptr);
+        SerializeSizeAndCount(data, 1, v->size());
+        if (!v->empty()) {
+          for (std::vector<CString>::const_iterator it = v->begin();
+               it != v->end();
+               ++it) {
+            SerializeValueList(data,
+                               reinterpret_cast<const byte*>(it->GetString()),
+                               sizeof(TCHAR),
+                               it->GetLength());
+          }
+        }
+        break;
+      }
+
+      case SERIALIZABLE_VECTOR | SERIALIZABLE_NESTED_OBJECT: {
+        if (!SerializeVectorNestedObject(data, members_[i].ptr))
+          return false;
+        break;
+      }
+
+      default:
+        ASSERT(false, (_T("")));
+        return false;
+    }
+  }
+
+  return true;
+}
+
+// Serialize the size and count values
+void SerializableObject::SerializeSizeAndCount(std::vector<byte>* data,
+                                               int size,
+                                               int count) const {
+  ASSERT(data, (_T("")));
+  ASSERT(size >= 0, (_T("")));
+
+  // Get current size
+  int pos = data->size();
+
+  // Adjust the size of the data buffer
+  data->resize(data->size() + 2 * sizeof(int));
+
+  // Get pointer to the position of data buffer we start to write
+  byte* ptr = &((*data)[pos]);
+
+  // Push size
+  memcpy(ptr, &size, sizeof(int));
+  ptr += sizeof(int);
+
+  // Push count
+  memcpy(ptr, &count, sizeof(int));
+  ptr += sizeof(int);
+}
+
+// Serialize a list of value-typed elements
+//
+// Args:
+//   ser_data:  pointer to the vector for the serialized data
+//   raw_data:  pointer to the raw data to be serialized
+//   size:      the size of the element in the list
+//   count:     the number of the elements in the list
+void SerializableObject::SerializeValueList(std::vector<byte>* ser_data,
+                                            const byte* raw_data,
+                                            int size,
+                                            int count) const {
+  ASSERT(ser_data, (_T("")));
+  ASSERT(size > 0, (_T("")));
+
+  // Serialize the size and count values
+  SerializeSizeAndCount(ser_data, size, count);
+
+  // Push data
+  if (count > 0) {
+    // Get current size
+    int pos = ser_data->size();
+
+    // Adjust the size of the data buffer
+    ser_data->resize(ser_data->size() + count * size);
+
+    // Get pointer to the position of data buffer we start to write
+    byte* ptr = &((*ser_data)[pos]);
+
+    // Copy data
+    memcpy(ptr, raw_data, count * size);
+  }
+}
+
+// Deserialize
+bool SerializableObject::Deserialize(byte* data, int size, uint32 version) {
+  ASSERT(data, (_T("")));
+  ASSERT(size > 0, (_T("")));
+
+  byte* tail = data + size;
+  byte** data_ptr = &data;
+  if (!DeserializeHelper(data_ptr, size, version))
+    return false;
+
+  if (*data_ptr != tail) {
+    UTIL_LOG(LE, (_T("[SerializableObject::Deserialize]")
+                  _T("[failed to deserialize all data]")));
+    return false;
+  }
+
+  return true;
+}
+
+// Deserialize helper
+bool SerializableObject::DeserializeHelper(byte** data,
+                                           int size,
+                                           uint32 version) {
+  ASSERT(data, (_T("")));
+  ASSERT(size > 0, (_T("")));
+
+  byte* tail = *data + size;
+
+  for (size_t i = 0; i < members_.size(); ++i) {
+    // Ignore those members which are persisted in newer versions
+    if (version != kLatestSerializableVersion &&
+        members_[i].version  > version) {
+      continue;
+    }
+
+    switch (members_[i].type) {
+      case SERIALIZABLE_VALUE_TYPE:
+        if (*data + members_[i].size > tail) {
+          UTIL_LOG(L6, (_T("[SerializableObject::DeserializeHelper]")
+                        _T("[overflow when deserializing value type]")));
+          return false;
+        }
+        memcpy(members_[i].ptr, *data, members_[i].size);
+        *data += members_[i].size;
+        break;
+
+      case SERIALIZABLE_CSTRING: {
+        std::vector<byte> deser_data;
+        if (!DeserializeValueList(&deser_data,
+                                  members_[i].size,
+                                  data,
+                                  tail - *data))
+          return false;
+        CString* s = reinterpret_cast<CString*>(members_[i].ptr);
+        if (deser_data.size() != 0) {
+          s->SetString(reinterpret_cast<const TCHAR*>(&deser_data.front()),
+                       deser_data.size() / members_[i].size);
+        } else {
+          s->SetString(_T(""));
+        }
+        break;
+      }
+
+      case SERIALIZABLE_NESTED_OBJECT: {
+        SerializableObject* nested_obj =
+            reinterpret_cast<SerializableObject*>(members_[i].ptr);
+        if (!nested_obj->DeserializeHelper(data, size, version))
+          return false;
+        break;
+      }
+
+      case SERIALIZABLE_VECTOR | SERIALIZABLE_VALUE_TYPE: {
+        // Hack: coerce vector<T> to vector<byte>
+        std::vector<byte>* v =
+            reinterpret_cast<std::vector<byte>*>(members_[i].ptr);
+        if (!DeserializeValueList(v, members_[i].size, data, tail - *data))
+          return false;
+        break;
+      }
+
+      case SERIALIZABLE_VECTOR | SERIALIZABLE_CSTRING: {
+        std::vector<CString>* v =
+              reinterpret_cast<std::vector<CString>*>(members_[i].ptr);
+        int count = 0;
+        if (!DeserializeSizeAndCount(&count, 1, data, tail - *data))
+          return false;
+        for (int j = 0; j < count; ++j) {
+          std::vector<byte> deser_data;
+          if (!DeserializeValueList(&deser_data,
+                                    members_[i].size,
+                                    data,
+                                    tail - *data))
+            return false;
+
+          CString s;
+          if (deser_data.size() != 0) {
+            s = CString(reinterpret_cast<const TCHAR*>(&deser_data.front()),
+                        deser_data.size() / members_[i].size);
+          }
+          v->push_back(s);
+        }
+        break;
+      }
+
+      case SERIALIZABLE_VECTOR | SERIALIZABLE_NESTED_OBJECT: {
+        if (!DeserializeVectorNestedObject(data,
+                                           tail - *data,
+                                           members_[i].ptr,
+                                           version))
+          return false;
+        break;
+      }
+
+      default:
+        ASSERT(false, (_T("")));
+        break;
+    }
+  }
+
+  return true;
+}
+
+// Serialize the size and count values
+bool SerializableObject::DeserializeSizeAndCount(int* count,
+                                                 int size,
+                                                 byte** ser_data,
+                                                 int ser_size) const {
+  ASSERT(ser_data, (_T("")));
+  ASSERT(count, (_T("")));
+
+  byte* ser_tail = *ser_data + ser_size;
+
+  // Check to make sure that the serialization data should at least contain
+  // 'size' and 'count'
+  if (*ser_data + 2 * sizeof(int) > ser_tail) {
+    UTIL_LOG(L6, (_T("[SerializableObject::DeserializeSizeAndCount]")
+                  _T("[overflow when deserializing size and count]")));
+    return false;
+  }
+
+  // Get size
+  // If the passing size is 0, skip the size check
+  int size2 = *(reinterpret_cast<const int*>(*ser_data));
+  *ser_data += sizeof(int);
+  if (size && size != size2)
+    return false;
+
+  // Get count
+  *count = *(reinterpret_cast<const int*>(*ser_data));
+  *ser_data += sizeof(int);
+
+  return true;
+}
+
+// Deserialize a list of value-typed elements
+//
+// Args:
+//   ser_data:  pointer to the vector for the serialized data
+//   size:      the size of the element in the list
+//   raw_data:  pointer to the raw data to be serialized
+//   ser_size:  size of the serization data
+bool SerializableObject::DeserializeValueList(std::vector<byte>* raw_data,
+                                              int size,
+                                              byte** ser_data,
+                                              int ser_size) {
+  ASSERT(raw_data, (_T("")));
+  ASSERT(ser_data, (_T("")));
+
+  byte* ser_tail = *ser_data + ser_size;
+
+  // Deserialize the size and count values
+  int count = 0;
+  bool ret = DeserializeSizeAndCount(&count, size, ser_data, ser_size);
+  if (!ret)
+    return false;
+
+  // Check to make sure that the serialization data is in the right size
+  if (*ser_data + count * size > ser_tail) {
+    UTIL_LOG(L6, (_T("[SerializableObject::DeserializeValueList]")
+                  _T("[overflow when deserializing value list]")));
+    return false;
+  }
+
+  // Get data
+  raw_data->resize(size * count);
+  if (count > 0) {
+    memcpy(&raw_data->front(), *ser_data, count * size);
+    *ser_data += count * size;
+  }
+
+  return true;
+}
+
+}  // namespace omaha
+
diff --git a/common/serializable_object.h b/common/serializable_object.h
index 6cf2029..7f7877f 100644
--- a/common/serializable_object.h
+++ b/common/serializable_object.h
@@ -1,373 +1,373 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Declares class SerializableObject

-//

-// Provides the base class framework for those objects to be serialized

-//

-// Currently we support the serialization for the following member type

-//

-//   1) Value-type object

-//   2) CString

-//   3) Nested serializable object

-//   4) Vector of the value-type objects

-//   5) Vector of CString

-//   6) Vector of serializable objects

-//

-// Usage:

-//

-//   1) Declare the object class, which you want to serialize, to be derived

-//      from SerializableObject

-//   2) In its constructor, call AddSerializableMember(...) to add those fields

-//      to be included in the serialization

-//   3) If you need to serialize a vector of serializable objects,

-//      a) The inner object class has to implement copy constructor and

-//         operator =

-//      b) The outer object class has to override SerializeVectorNestedObject()

-//         and DeserializeVectorNestedObject() (see sample)

-//

-// Versioning support:

-//

-//   To add new fields in the new version, call

-//        AddSerializableMember(version, &member);

-//   If "version" is not given, it is 0 by default.

-//

-//   To deserialize the data for latest version, call

-//        Deserialize(data, size, kLatestSerializableVersion);

-//   To deserialize the data for a particular version, call

-//        Deserialize(data, size, version);

-//

-// Sample:

-//

-//   class FooObject : public SerializableObject {

-//     ...

-//   };

-//

-//   class BarObject : public SerializableObject {

-//    public:

-//     BarObject() {

-//      AddSerializableMember(&value1_);

-//      AddSerializableMember(&value2_);

-//      AddSerializableMember(&value3_);

-//      AddSerializableMember(&value4_);

-//      AddSerializableMember(&value5_);

-//      AddSerializableMember(&value6_);

-//      AddSerializableMember(1, &value7_);     // New version

-//     }

-//

-//    protected:

-//     virtual bool SerializeVectorNestedObject(std::vector<byte>* data,

-//                                              const byte* ptr) const {

-//       ASSERT(data, (_T("")));

-//       ASSERT(ptr, (_T("")));

-//       if (ptr == reinterpret_cast<const byte*>(&value6_))

-//         return SerializeVectorNestedObjectHelper(data, &value6_);

-//       return false;

-//     }

-//

-//     virtual bool DeserializeVectorNestedObject(byte** data,

-//                                                int size,

-//                                                byte* ptr,

-//                                                uint32 version) {

-//       ASSERT(data, (_T("")));

-//       ASSERT(*data, (_T("")));

-//       ASSERT(ptr, (_T("")));

-//       if (ptr == reinterpret_cast<byte*>(&value6_))

-//         return DeserializeVectorNestedObjectHelper(data,

-//                                                    size,

-//                                                    &value6_,

-//                                                    version);

-//       return false;

-//     }

-//

-//    private:

-//     int value1_;

-//     CString value2_;

-//     FooObject value3_;

-//     std::vector<byte> value4_;

-//     std::vector<CString> value5_;

-//     std::vector<BarObject> value6_;

-//     int value7_;

-//   };

-//

-// Binary format:

-//

-//   1) Value type: data

-//      e.g.  100           =>   64 00 00 00

-//   2) CString:    size count data

-//      e.g.  "ABC"         =>   02 00 00 00 03 00 00 00 41 00 42 00 43 00

-//   3) Vector:     size count data

-//      e.g.  vector<int> = {1, 2}

-//                          =>   04 00 00 00 02 00 00 00 01 00 00 00 02 00 00 00

-//

-// TODO(omaha):

-//   1) Define struct TypeTrait for all type-related info

-//   2) Initialize TypeTrait on per-type basis instead of per-object basis

-

-#ifndef OMAHA_COMMON_SERIALIZABLE_OBJECT_H_

-#define OMAHA_COMMON_SERIALIZABLE_OBJECT_H_

-

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/type_utils.h"

-

-namespace omaha {

-

-// Constants

-const uint32 kLatestSerializableVersion = 0xFFFFFFFF;

-

-// Serializable object

-class SerializableObject {

- private:

-  // Define SerializableMemberType, for internal use

-  typedef uint32 SerializableMemberType;

-

-  #define SERIALIZABLE_VALUE_TYPE     1

-  #define SERIALIZABLE_CSTRING        2

-  #define SERIALIZABLE_NESTED_OBJECT  3

-  #define SERIALIZABLE_VECTOR         0x8000

-

-  // Serializable member info

-  struct SerializableMemberInfo {

-    byte* ptr;                      // Pointers to the serializable member

-    SerializableMemberType type;    // Type of the serializable member

-    int size;                       // Size of the serializable member

-    uint32 version;                 // Version when the member is added

-

-    SerializableMemberInfo()

-        : ptr(NULL), type(SERIALIZABLE_VALUE_TYPE), size(0) {}

-  };

-

- public:

-  // Constructor

-  SerializableObject() {}

-

-  // Destructor

-  virtual ~SerializableObject() {}

-

-  // Serialize

-  bool Serialize(std::vector<byte>* data) const;

-

-  // Deserialize the data for the latest version

-  bool Deserialize(byte* data, int size) {

-    return Deserialize(data, size, kLatestSerializableVersion);

-  }

-

-  // Deserialize the data for a particular version

-  bool Deserialize(byte* data, int size, uint32 version);

-

- protected:

-  // Clear the serializable member list

-  void ClearSerializableMemberList() {

-    members_.clear();

-  }

-

-  // Add value-typed member to the serializable member list

-  template<typename T>

-  void AddSerializableMember(T* ptr) {

-    return AddSerializableMember(0, ptr);

-  }

-

-  // Add value-typed member to the serializable member list

-  template<typename T>

-  void AddSerializableMember(uint32 version, T* ptr) {

-    if (SUPERSUBCLASS(SerializableObject, T)) {

-      #pragma warning(push)

-      // reinterpret_cast used between related classes

-      #pragma warning(disable : 4946)

-      return AddSerializableMember(version,

-                                   reinterpret_cast<SerializableObject*>(ptr),

-                                   sizeof(T));

-      #pragma warning(pop)

-    }

-    SerializableMemberInfo member;

-    member.ptr = reinterpret_cast<byte*>(ptr);

-    member.type = SERIALIZABLE_VALUE_TYPE;

-    member.size = sizeof(T);

-    member.version = version;

-    members_.push_back(member);

-  }

-

-  // Add CString-typed member to the serializable member list

-  void AddSerializableMember(CString* ptr) {

-    AddSerializableMember(0, ptr);

-  }

-

-  // Add CString-typed member to the serializable member list

-  void AddSerializableMember(uint32 version, CString* ptr) {

-    SerializableMemberInfo member;

-    member.ptr = reinterpret_cast<byte*>(ptr);

-    member.type = SERIALIZABLE_CSTRING;

-    member.size = sizeof(TCHAR);

-    member.version = version;

-    members_.push_back(member);

-  }

-

-  // Add nested serializable member to the serializable member list

-  void AddSerializableMember(SerializableObject* ptr, int size) {

-    AddSerializableMember(0, ptr, size);

-  }

-

-  // Add nested serializable member to the serializable member list

-  void AddSerializableMember(uint32 version,

-                             SerializableObject* ptr,

-                             int size) {

-    SerializableMemberInfo member;

-    member.ptr = reinterpret_cast<byte*>(ptr);

-    member.type = SERIALIZABLE_NESTED_OBJECT;

-    member.size = size;

-    member.version = version;

-    members_.push_back(member);

-  }

-

-  // Add vector-typed member to the serializable member list

-  template<typename T>

-  void AddSerializableMember(std::vector<T>* ptr) {

-    AddSerializableMember(0, ptr);

-  }

-

-  // Add vector-typed member to the serializable member list

-  template<typename T>

-  void AddSerializableMember(uint32 version, std::vector<T>* ptr) {

-    SerializableMemberInfo member;

-    member.ptr = reinterpret_cast<byte*>(ptr);

-    member.version = version;

-

-    if (SUPERSUBCLASS(CString, T)) {

-      member.type =

-          static_cast<SerializableMemberType>(SERIALIZABLE_VECTOR |

-                                              SERIALIZABLE_CSTRING);

-      member.size = sizeof(TCHAR);

-    } else if (SUPERSUBCLASS(SerializableObject, T)) {

-      member.type =

-          static_cast<SerializableMemberType>(SERIALIZABLE_VECTOR |

-                                              SERIALIZABLE_NESTED_OBJECT);

-      member.size = sizeof(T);

-    } else {

-      member.type =

-          static_cast<SerializableMemberType>(SERIALIZABLE_VECTOR |

-                                              SERIALIZABLE_VALUE_TYPE);

-      member.size = sizeof(T);

-    }

-

-    members_.push_back(member);

-  }

-

-  // If there is a vector of SerializableObject to be serialized, the derived

-  // class need to provide the implementation

-  virtual bool SerializeVectorNestedObject(std::vector<byte>*,

-                                           const byte*) const {

-    ASSERT(false, (_T("Provide the implementation in the derived class.")));

-    return false;

-  }

-

-  // Helper method to serialize a vector of SerializableObject

-  template<typename T>

-  bool SerializeVectorNestedObjectHelper(std::vector<byte>* data,

-                                         const std::vector<T>* list) const {

-    ASSERT(data, (_T("")));

-    ASSERT(list, (_T("")));

-    ASSERT(SUPERSUBCLASS(SerializableObject, T), (_T("")));

-

-    // Size of SerializableObject is unknown

-    SerializeSizeAndCount(data, 0, list->size());

-    for (size_t i = 0; i < list->size(); ++i) {

-      // To work around compiler complaint while using dynamic_cast

-      SerializableObject* so =

-          const_cast<SerializableObject*>(

-              static_cast<const SerializableObject*>(&(*list)[i]));

-      bool res = so->Serialize(data);

-      if (!res)

-        return false;

-    }

-    return true;

-  }

-

-  // If there is a vector of SerializableObject to be serialized, the derived

-  // class need to provide the implementation

-  virtual bool DeserializeVectorNestedObject(byte**, int, byte*, uint32) {

-    ASSERT(false, (_T("provide the implementation in the derived class.")));

-    return false;

-  }

-

-  // Helper method to deserialize a vector of SerializableObject

-  template<typename T>

-  bool DeserializeVectorNestedObjectHelper(byte** data,

-                                           int size,

-                                           std::vector<T>* list,

-                                           uint32 version) {

-    ASSERT(data, (_T("")));

-    ASSERT(*data, (_T("")));

-    ASSERT(size, (_T("")));

-    ASSERT(list, (_T("")));

-    ASSERT(SUPERSUBCLASS(SerializableObject, T), (_T("")));

-

-    byte* tail = *data + size;

-

-    // Size of SerializableObject is unknown

-    int count = 0;

-    bool res = DeserializeSizeAndCount(&count, 0, data, size);

-    if (!res)

-      return false;

-

-    for (int i = 0; i < count; ++i) {

-      T obj;

-      bool res = obj.DeserializeHelper(data, tail - *data, version);

-      if (!res)

-        return false;

-      list->push_back(obj);

-    }

-    return true;

-  }

-

- private:

-  // Serialize the size and count values

-  void SerializeSizeAndCount(std::vector<byte>* data,

-                             int size,

-                             int count) const;

-

-  // Serialize a list of value-typed elements

-  void SerializeValueList(std::vector<byte>* ser_data,

-                          const byte* raw_data,

-                          int size,

-                          int count) const;

-

-  // Deserialize helper

-  bool DeserializeHelper(byte** data, int size, uint32 version);

-

-  // Deserialize the size and count values

-  bool DeserializeSizeAndCount(int* count,

-                               int size,

-                               byte** ser_data,

-                               int ser_size) const;

-

-  // Deserialize a list of value-typed elements

-  bool DeserializeValueList(std::vector<byte>* raw_data,

-                            int size,

-                            byte** ser_data,

-                            int ser_size);

-

-  // List of serializable members

-  std::vector<SerializableMemberInfo> members_;

-

-  // We need to initialize TypeTrait on per-type basis instead of per-object

-  // basis and remove the following use of macro.

-  DISALLOW_EVIL_CONSTRUCTORS(SerializableObject);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SERIALIZABLE_OBJECT_H_

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Declares class SerializableObject
+//
+// Provides the base class framework for those objects to be serialized
+//
+// Currently we support the serialization for the following member type
+//
+//   1) Value-type object
+//   2) CString
+//   3) Nested serializable object
+//   4) Vector of the value-type objects
+//   5) Vector of CString
+//   6) Vector of serializable objects
+//
+// Usage:
+//
+//   1) Declare the object class, which you want to serialize, to be derived
+//      from SerializableObject
+//   2) In its constructor, call AddSerializableMember(...) to add those fields
+//      to be included in the serialization
+//   3) If you need to serialize a vector of serializable objects,
+//      a) The inner object class has to implement copy constructor and
+//         operator =
+//      b) The outer object class has to override SerializeVectorNestedObject()
+//         and DeserializeVectorNestedObject() (see sample)
+//
+// Versioning support:
+//
+//   To add new fields in the new version, call
+//        AddSerializableMember(version, &member);
+//   If "version" is not given, it is 0 by default.
+//
+//   To deserialize the data for latest version, call
+//        Deserialize(data, size, kLatestSerializableVersion);
+//   To deserialize the data for a particular version, call
+//        Deserialize(data, size, version);
+//
+// Sample:
+//
+//   class FooObject : public SerializableObject {
+//     ...
+//   };
+//
+//   class BarObject : public SerializableObject {
+//    public:
+//     BarObject() {
+//      AddSerializableMember(&value1_);
+//      AddSerializableMember(&value2_);
+//      AddSerializableMember(&value3_);
+//      AddSerializableMember(&value4_);
+//      AddSerializableMember(&value5_);
+//      AddSerializableMember(&value6_);
+//      AddSerializableMember(1, &value7_);     // New version
+//     }
+//
+//    protected:
+//     virtual bool SerializeVectorNestedObject(std::vector<byte>* data,
+//                                              const byte* ptr) const {
+//       ASSERT(data, (_T("")));
+//       ASSERT(ptr, (_T("")));
+//       if (ptr == reinterpret_cast<const byte*>(&value6_))
+//         return SerializeVectorNestedObjectHelper(data, &value6_);
+//       return false;
+//     }
+//
+//     virtual bool DeserializeVectorNestedObject(byte** data,
+//                                                int size,
+//                                                byte* ptr,
+//                                                uint32 version) {
+//       ASSERT(data, (_T("")));
+//       ASSERT(*data, (_T("")));
+//       ASSERT(ptr, (_T("")));
+//       if (ptr == reinterpret_cast<byte*>(&value6_))
+//         return DeserializeVectorNestedObjectHelper(data,
+//                                                    size,
+//                                                    &value6_,
+//                                                    version);
+//       return false;
+//     }
+//
+//    private:
+//     int value1_;
+//     CString value2_;
+//     FooObject value3_;
+//     std::vector<byte> value4_;
+//     std::vector<CString> value5_;
+//     std::vector<BarObject> value6_;
+//     int value7_;
+//   };
+//
+// Binary format:
+//
+//   1) Value type: data
+//      e.g.  100           =>   64 00 00 00
+//   2) CString:    size count data
+//      e.g.  "ABC"         =>   02 00 00 00 03 00 00 00 41 00 42 00 43 00
+//   3) Vector:     size count data
+//      e.g.  vector<int> = {1, 2}
+//                          =>   04 00 00 00 02 00 00 00 01 00 00 00 02 00 00 00
+//
+// TODO(omaha):
+//   1) Define struct TypeTrait for all type-related info
+//   2) Initialize TypeTrait on per-type basis instead of per-object basis
+
+#ifndef OMAHA_COMMON_SERIALIZABLE_OBJECT_H_
+#define OMAHA_COMMON_SERIALIZABLE_OBJECT_H_
+
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/type_utils.h"
+
+namespace omaha {
+
+// Constants
+const uint32 kLatestSerializableVersion = 0xFFFFFFFF;
+
+// Serializable object
+class SerializableObject {
+ private:
+  // Define SerializableMemberType, for internal use
+  typedef uint32 SerializableMemberType;
+
+  #define SERIALIZABLE_VALUE_TYPE     1
+  #define SERIALIZABLE_CSTRING        2
+  #define SERIALIZABLE_NESTED_OBJECT  3
+  #define SERIALIZABLE_VECTOR         0x8000
+
+  // Serializable member info
+  struct SerializableMemberInfo {
+    byte* ptr;                      // Pointers to the serializable member
+    SerializableMemberType type;    // Type of the serializable member
+    int size;                       // Size of the serializable member
+    uint32 version;                 // Version when the member is added
+
+    SerializableMemberInfo()
+        : ptr(NULL), type(SERIALIZABLE_VALUE_TYPE), size(0) {}
+  };
+
+ public:
+  // Constructor
+  SerializableObject() {}
+
+  // Destructor
+  virtual ~SerializableObject() {}
+
+  // Serialize
+  bool Serialize(std::vector<byte>* data) const;
+
+  // Deserialize the data for the latest version
+  bool Deserialize(byte* data, int size) {
+    return Deserialize(data, size, kLatestSerializableVersion);
+  }
+
+  // Deserialize the data for a particular version
+  bool Deserialize(byte* data, int size, uint32 version);
+
+ protected:
+  // Clear the serializable member list
+  void ClearSerializableMemberList() {
+    members_.clear();
+  }
+
+  // Add value-typed member to the serializable member list
+  template<typename T>
+  void AddSerializableMember(T* ptr) {
+    return AddSerializableMember(0, ptr);
+  }
+
+  // Add value-typed member to the serializable member list
+  template<typename T>
+  void AddSerializableMember(uint32 version, T* ptr) {
+    if (SUPERSUBCLASS(SerializableObject, T)) {
+      #pragma warning(push)
+      // reinterpret_cast used between related classes
+      #pragma warning(disable : 4946)
+      return AddSerializableMember(version,
+                                   reinterpret_cast<SerializableObject*>(ptr),
+                                   sizeof(T));
+      #pragma warning(pop)
+    }
+    SerializableMemberInfo member;
+    member.ptr = reinterpret_cast<byte*>(ptr);
+    member.type = SERIALIZABLE_VALUE_TYPE;
+    member.size = sizeof(T);
+    member.version = version;
+    members_.push_back(member);
+  }
+
+  // Add CString-typed member to the serializable member list
+  void AddSerializableMember(CString* ptr) {
+    AddSerializableMember(0, ptr);
+  }
+
+  // Add CString-typed member to the serializable member list
+  void AddSerializableMember(uint32 version, CString* ptr) {
+    SerializableMemberInfo member;
+    member.ptr = reinterpret_cast<byte*>(ptr);
+    member.type = SERIALIZABLE_CSTRING;
+    member.size = sizeof(TCHAR);
+    member.version = version;
+    members_.push_back(member);
+  }
+
+  // Add nested serializable member to the serializable member list
+  void AddSerializableMember(SerializableObject* ptr, int size) {
+    AddSerializableMember(0, ptr, size);
+  }
+
+  // Add nested serializable member to the serializable member list
+  void AddSerializableMember(uint32 version,
+                             SerializableObject* ptr,
+                             int size) {
+    SerializableMemberInfo member;
+    member.ptr = reinterpret_cast<byte*>(ptr);
+    member.type = SERIALIZABLE_NESTED_OBJECT;
+    member.size = size;
+    member.version = version;
+    members_.push_back(member);
+  }
+
+  // Add vector-typed member to the serializable member list
+  template<typename T>
+  void AddSerializableMember(std::vector<T>* ptr) {
+    AddSerializableMember(0, ptr);
+  }
+
+  // Add vector-typed member to the serializable member list
+  template<typename T>
+  void AddSerializableMember(uint32 version, std::vector<T>* ptr) {
+    SerializableMemberInfo member;
+    member.ptr = reinterpret_cast<byte*>(ptr);
+    member.version = version;
+
+    if (SUPERSUBCLASS(CString, T)) {
+      member.type =
+          static_cast<SerializableMemberType>(SERIALIZABLE_VECTOR |
+                                              SERIALIZABLE_CSTRING);
+      member.size = sizeof(TCHAR);
+    } else if (SUPERSUBCLASS(SerializableObject, T)) {
+      member.type =
+          static_cast<SerializableMemberType>(SERIALIZABLE_VECTOR |
+                                              SERIALIZABLE_NESTED_OBJECT);
+      member.size = sizeof(T);
+    } else {
+      member.type =
+          static_cast<SerializableMemberType>(SERIALIZABLE_VECTOR |
+                                              SERIALIZABLE_VALUE_TYPE);
+      member.size = sizeof(T);
+    }
+
+    members_.push_back(member);
+  }
+
+  // If there is a vector of SerializableObject to be serialized, the derived
+  // class need to provide the implementation
+  virtual bool SerializeVectorNestedObject(std::vector<byte>*,
+                                           const byte*) const {
+    ASSERT(false, (_T("Provide the implementation in the derived class.")));
+    return false;
+  }
+
+  // Helper method to serialize a vector of SerializableObject
+  template<typename T>
+  bool SerializeVectorNestedObjectHelper(std::vector<byte>* data,
+                                         const std::vector<T>* list) const {
+    ASSERT(data, (_T("")));
+    ASSERT(list, (_T("")));
+    ASSERT(SUPERSUBCLASS(SerializableObject, T), (_T("")));
+
+    // Size of SerializableObject is unknown
+    SerializeSizeAndCount(data, 0, list->size());
+    for (size_t i = 0; i < list->size(); ++i) {
+      // To work around compiler complaint while using dynamic_cast
+      SerializableObject* so =
+          const_cast<SerializableObject*>(
+              static_cast<const SerializableObject*>(&(*list)[i]));
+      bool res = so->Serialize(data);
+      if (!res)
+        return false;
+    }
+    return true;
+  }
+
+  // If there is a vector of SerializableObject to be serialized, the derived
+  // class need to provide the implementation
+  virtual bool DeserializeVectorNestedObject(byte**, int, byte*, uint32) {
+    ASSERT(false, (_T("provide the implementation in the derived class.")));
+    return false;
+  }
+
+  // Helper method to deserialize a vector of SerializableObject
+  template<typename T>
+  bool DeserializeVectorNestedObjectHelper(byte** data,
+                                           int size,
+                                           std::vector<T>* list,
+                                           uint32 version) {
+    ASSERT(data, (_T("")));
+    ASSERT(*data, (_T("")));
+    ASSERT(size, (_T("")));
+    ASSERT(list, (_T("")));
+    ASSERT(SUPERSUBCLASS(SerializableObject, T), (_T("")));
+
+    byte* tail = *data + size;
+
+    // Size of SerializableObject is unknown
+    int count = 0;
+    bool res = DeserializeSizeAndCount(&count, 0, data, size);
+    if (!res)
+      return false;
+
+    for (int i = 0; i < count; ++i) {
+      T obj;
+      bool res = obj.DeserializeHelper(data, tail - *data, version);
+      if (!res)
+        return false;
+      list->push_back(obj);
+    }
+    return true;
+  }
+
+ private:
+  // Serialize the size and count values
+  void SerializeSizeAndCount(std::vector<byte>* data,
+                             int size,
+                             int count) const;
+
+  // Serialize a list of value-typed elements
+  void SerializeValueList(std::vector<byte>* ser_data,
+                          const byte* raw_data,
+                          int size,
+                          int count) const;
+
+  // Deserialize helper
+  bool DeserializeHelper(byte** data, int size, uint32 version);
+
+  // Deserialize the size and count values
+  bool DeserializeSizeAndCount(int* count,
+                               int size,
+                               byte** ser_data,
+                               int ser_size) const;
+
+  // Deserialize a list of value-typed elements
+  bool DeserializeValueList(std::vector<byte>* raw_data,
+                            int size,
+                            byte** ser_data,
+                            int ser_size);
+
+  // List of serializable members
+  std::vector<SerializableMemberInfo> members_;
+
+  // We need to initialize TypeTrait on per-type basis instead of per-object
+  // basis and remove the following use of macro.
+  DISALLOW_EVIL_CONSTRUCTORS(SerializableObject);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SERIALIZABLE_OBJECT_H_
diff --git a/common/serializable_object_unittest.cc b/common/serializable_object_unittest.cc
index 7eb7801..68f3581 100644
--- a/common/serializable_object_unittest.cc
+++ b/common/serializable_object_unittest.cc
@@ -1,248 +1,248 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/serializable_object.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Template test function to round-trip an object through its serialized form.

-// Requires the object to implement SetTestValues() and VerifyTestValues().

-template <class T>

-void TestSerializeRoundTrip() {

-  T in;

-  T out;

-  std::vector<byte> data;

-

-  in.SetTestValues();

-  in.VerifyTestValues();  // sanity check to catch broken tests

-  EXPECT_TRUE(in.Serialize(&data));

-  EXPECT_TRUE(out.Deserialize(&data[0], data.size()));

-  out.VerifyTestValues();

-}

-

-

-// Ordinary values.

-class SimpleValues : public SerializableObject {

- public:

-  SimpleValues() {

-    AddSerializableMember(&value1_);

-    AddSerializableMember(&value2_);

-    AddSerializableMember(&value3_);

-    AddSerializableMember(&value4_);

-  }

-

-  virtual void SetTestValues() {

-    value1_ = 452;

-    value2_ = 'Z';

-    value3_ = false;

-    value4_ = 9276554;

-  }

-

-  virtual void VerifyTestValues() {

-    EXPECT_EQ(452, value1_);

-    EXPECT_EQ('Z', value2_);

-    EXPECT_EQ(false, value3_);

-    EXPECT_EQ(9276554, value4_);

-  }

-

- private:

-  int value1_;

-  char value2_;

-  bool value3_;

-  int value4_;

-};

-

-TEST(SerializableObjectTest, SimpleValues) {

-  TestSerializeRoundTrip<SimpleValues>();

-}

-

-

-// Strings.

-const TCHAR kString1[] = _T("an example\tvalue\n");

-const TCHAR kString2[] = _T("");

-const TCHAR kString3[] = _T("and the mome raths outgrabe");

-

-class StringValues : public SerializableObject {

- public:

-  StringValues() {

-    AddSerializableMember(&string1_);

-    AddSerializableMember(&string2_);

-    AddSerializableMember(&string3_);

-  }

-

-  virtual void SetTestValues() {

-    string1_ = kString1;

-    string2_ = kString2;

-    string3_ = kString3;

-  }

-

-  virtual void VerifyTestValues() {

-    EXPECT_STREQ(kString1, string1_);

-    EXPECT_STREQ(kString2, string2_);

-    EXPECT_STREQ(kString3, string3_);

-  }

-

- private:

-  CString string1_;

-  CString string2_;

-  CString string3_;

-};

-

-TEST(SerializableObjectTest, StringValues) {

-  TestSerializeRoundTrip<StringValues>();

-}

-

-

-// Nested objects.

-class NestedObjects : public SerializableObject {

- public:

-  NestedObjects() {

-    AddSerializableMember(&simple_values_);

-    AddSerializableMember(&string_values_);

-  }

-

-  virtual void SetTestValues() {

-    simple_values_.SetTestValues();

-    string_values_.SetTestValues();

-  }

-

-  virtual void VerifyTestValues() {

-    simple_values_.VerifyTestValues();

-    string_values_.VerifyTestValues();

-  }

-

- private:

-  SimpleValues simple_values_;

-  StringValues string_values_;

-};

-

-TEST(SerializableObjectTest, NestedObjects) {

-  TestSerializeRoundTrip<NestedObjects>();

-}

-

-

-// Vector of values.

-class ValueVector : public SerializableObject {

- public:

-  ValueVector() {

-    AddSerializableMember(&vector_);

-    AddSerializableMember(&empty_vector_);

-  }

-

-  virtual void SetTestValues() {

-    vector_.push_back(5);

-    vector_.push_back(8);

-    vector_.push_back(13);

-  }

-

-  virtual void VerifyTestValues() {

-    EXPECT_EQ(0, empty_vector_.size());

-    EXPECT_EQ(3, vector_.size());

-    EXPECT_EQ(5, vector_[0]);

-    EXPECT_EQ(8, vector_[1]);

-    EXPECT_EQ(13, vector_[2]);

-  }

-

- private:

-  std::vector<int> vector_;

-  std::vector<int> empty_vector_;

-};

-

-TEST(SerializableObjectTest, ValueVector) {

-  TestSerializeRoundTrip<ValueVector>();

-}

-

-

-// Vector of objects.

-class InnerObject : public SerializableObject {

- public:

-  InnerObject() : value_(-1) {

-    AddSerializableMember(&value_);

-  }

-

-  explicit InnerObject(int i) : value_(i) {

-    AddSerializableMember(&value_);

-  }

-

-  InnerObject(const InnerObject& other) {

-    AddSerializableMember(&value_);

-    value_ = other.value_;

-  }

-

-  InnerObject& operator=(const InnerObject& other) {

-    value_ = other.value_;

-    return *this;

-  }

-

-  int value() {

-    return value_;

-  }

-

- private:

-  int value_;

-};

-

-class ObjectVector : public SerializableObject {

- public:

-  ObjectVector() {

-    AddSerializableMember(&vector_);

-  }

-

-  virtual void SetTestValues() {

-    vector_.push_back(InnerObject(21));

-    vector_.push_back(InnerObject(34));

-    vector_.push_back(InnerObject(55));

-  }

-

-  virtual void VerifyTestValues() {

-    EXPECT_EQ(3, vector_.size());

-    EXPECT_EQ(21, vector_[0].value());

-    EXPECT_EQ(34, vector_[1].value());

-    EXPECT_EQ(55, vector_[2].value());

-  }

-

-  virtual bool SerializeVectorNestedObject(std::vector<byte>* data,

-                                           const byte* ptr) const {

-    EXPECT_TRUE(data);

-    EXPECT_TRUE(ptr);

-    if (ptr == reinterpret_cast<const byte*>(&vector_))

-      return SerializeVectorNestedObjectHelper(data, &vector_);

-    return false;

-  }

-

-  virtual bool DeserializeVectorNestedObject(byte** data,

-                                             int size,

-                                             byte* ptr,

-                                             uint32 version) {

-    EXPECT_TRUE(data);

-    EXPECT_TRUE(ptr);

-    if (ptr == reinterpret_cast<byte*>(&vector_)) {

-      return DeserializeVectorNestedObjectHelper(data, size,

-                                                 &vector_, version);

-    }

-    return false;

-  }

-

- private:

-  std::vector<InnerObject> vector_;

-};

-

-TEST(SerializableObjectTest, ObjectVector) {

-  TestSerializeRoundTrip<ObjectVector>();

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/serializable_object.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Template test function to round-trip an object through its serialized form.
+// Requires the object to implement SetTestValues() and VerifyTestValues().
+template <class T>
+void TestSerializeRoundTrip() {
+  T in;
+  T out;
+  std::vector<byte> data;
+
+  in.SetTestValues();
+  in.VerifyTestValues();  // sanity check to catch broken tests
+  EXPECT_TRUE(in.Serialize(&data));
+  EXPECT_TRUE(out.Deserialize(&data[0], data.size()));
+  out.VerifyTestValues();
+}
+
+
+// Ordinary values.
+class SimpleValues : public SerializableObject {
+ public:
+  SimpleValues() {
+    AddSerializableMember(&value1_);
+    AddSerializableMember(&value2_);
+    AddSerializableMember(&value3_);
+    AddSerializableMember(&value4_);
+  }
+
+  virtual void SetTestValues() {
+    value1_ = 452;
+    value2_ = 'Z';
+    value3_ = false;
+    value4_ = 9276554;
+  }
+
+  virtual void VerifyTestValues() {
+    EXPECT_EQ(452, value1_);
+    EXPECT_EQ('Z', value2_);
+    EXPECT_EQ(false, value3_);
+    EXPECT_EQ(9276554, value4_);
+  }
+
+ private:
+  int value1_;
+  char value2_;
+  bool value3_;
+  int value4_;
+};
+
+TEST(SerializableObjectTest, SimpleValues) {
+  TestSerializeRoundTrip<SimpleValues>();
+}
+
+
+// Strings.
+const TCHAR kString1[] = _T("an example\tvalue\n");
+const TCHAR kString2[] = _T("");
+const TCHAR kString3[] = _T("and the mome raths outgrabe");
+
+class StringValues : public SerializableObject {
+ public:
+  StringValues() {
+    AddSerializableMember(&string1_);
+    AddSerializableMember(&string2_);
+    AddSerializableMember(&string3_);
+  }
+
+  virtual void SetTestValues() {
+    string1_ = kString1;
+    string2_ = kString2;
+    string3_ = kString3;
+  }
+
+  virtual void VerifyTestValues() {
+    EXPECT_STREQ(kString1, string1_);
+    EXPECT_STREQ(kString2, string2_);
+    EXPECT_STREQ(kString3, string3_);
+  }
+
+ private:
+  CString string1_;
+  CString string2_;
+  CString string3_;
+};
+
+TEST(SerializableObjectTest, StringValues) {
+  TestSerializeRoundTrip<StringValues>();
+}
+
+
+// Nested objects.
+class NestedObjects : public SerializableObject {
+ public:
+  NestedObjects() {
+    AddSerializableMember(&simple_values_);
+    AddSerializableMember(&string_values_);
+  }
+
+  virtual void SetTestValues() {
+    simple_values_.SetTestValues();
+    string_values_.SetTestValues();
+  }
+
+  virtual void VerifyTestValues() {
+    simple_values_.VerifyTestValues();
+    string_values_.VerifyTestValues();
+  }
+
+ private:
+  SimpleValues simple_values_;
+  StringValues string_values_;
+};
+
+TEST(SerializableObjectTest, NestedObjects) {
+  TestSerializeRoundTrip<NestedObjects>();
+}
+
+
+// Vector of values.
+class ValueVector : public SerializableObject {
+ public:
+  ValueVector() {
+    AddSerializableMember(&vector_);
+    AddSerializableMember(&empty_vector_);
+  }
+
+  virtual void SetTestValues() {
+    vector_.push_back(5);
+    vector_.push_back(8);
+    vector_.push_back(13);
+  }
+
+  virtual void VerifyTestValues() {
+    EXPECT_EQ(0, empty_vector_.size());
+    EXPECT_EQ(3, vector_.size());
+    EXPECT_EQ(5, vector_[0]);
+    EXPECT_EQ(8, vector_[1]);
+    EXPECT_EQ(13, vector_[2]);
+  }
+
+ private:
+  std::vector<int> vector_;
+  std::vector<int> empty_vector_;
+};
+
+TEST(SerializableObjectTest, ValueVector) {
+  TestSerializeRoundTrip<ValueVector>();
+}
+
+
+// Vector of objects.
+class InnerObject : public SerializableObject {
+ public:
+  InnerObject() : value_(-1) {
+    AddSerializableMember(&value_);
+  }
+
+  explicit InnerObject(int i) : value_(i) {
+    AddSerializableMember(&value_);
+  }
+
+  InnerObject(const InnerObject& other) {
+    AddSerializableMember(&value_);
+    value_ = other.value_;
+  }
+
+  InnerObject& operator=(const InnerObject& other) {
+    value_ = other.value_;
+    return *this;
+  }
+
+  int value() {
+    return value_;
+  }
+
+ private:
+  int value_;
+};
+
+class ObjectVector : public SerializableObject {
+ public:
+  ObjectVector() {
+    AddSerializableMember(&vector_);
+  }
+
+  virtual void SetTestValues() {
+    vector_.push_back(InnerObject(21));
+    vector_.push_back(InnerObject(34));
+    vector_.push_back(InnerObject(55));
+  }
+
+  virtual void VerifyTestValues() {
+    EXPECT_EQ(3, vector_.size());
+    EXPECT_EQ(21, vector_[0].value());
+    EXPECT_EQ(34, vector_[1].value());
+    EXPECT_EQ(55, vector_[2].value());
+  }
+
+  virtual bool SerializeVectorNestedObject(std::vector<byte>* data,
+                                           const byte* ptr) const {
+    EXPECT_TRUE(data);
+    EXPECT_TRUE(ptr);
+    if (ptr == reinterpret_cast<const byte*>(&vector_))
+      return SerializeVectorNestedObjectHelper(data, &vector_);
+    return false;
+  }
+
+  virtual bool DeserializeVectorNestedObject(byte** data,
+                                             int size,
+                                             byte* ptr,
+                                             uint32 version) {
+    EXPECT_TRUE(data);
+    EXPECT_TRUE(ptr);
+    if (ptr == reinterpret_cast<byte*>(&vector_)) {
+      return DeserializeVectorNestedObjectHelper(data, size,
+                                                 &vector_, version);
+    }
+    return false;
+  }
+
+ private:
+  std::vector<InnerObject> vector_;
+};
+
+TEST(SerializableObjectTest, ObjectVector) {
+  TestSerializeRoundTrip<ObjectVector>();
+}
+
+}  // namespace omaha
+
diff --git a/common/service_utils.cc b/common/service_utils.cc
index 8970797..7bebfac 100644
--- a/common/service_utils.cc
+++ b/common/service_utils.cc
@@ -1,360 +1,360 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Service-related utilities.

-//

-

-#include "omaha/common/service_utils.h"

-

-#include <windows.h>

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/smart_handle.h"

-#include "omaha/common/string.h"

-#include "omaha/common/timer.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-HRESULT ScmDatabase::EnumerateServices(

-    ScmDatabase::EnumerateServicesCallback callback,

-    void* callback_context) {

-  ASSERT1(callback);

-  if (!callback)

-    return E_POINTER;

-

-  const wchar_t* kServicesRegKeyFromRoot =

-    L"SYSTEM\\CurrentControlSet\\Services";

-

-  HRESULT hr = E_FAIL;

-

-  RegKey services_key;

-  if (FAILED(hr = services_key.Open(HKEY_LOCAL_MACHINE,

-                                    kServicesRegKeyFromRoot,

-                                    KEY_ENUMERATE_SUB_KEYS))) {

-    ASSERT1(false);

-    REPORT(false, R_ERROR, (L"Couldn't open services subkey, hr=0x%x", hr),

-           9834572);

-    return hr;

-  }

-

-  CString service_name;

-  int key_index = 0;

-  while (SUCCEEDED(hr = services_key.GetSubkeyNameAt(key_index++,

-                                                     &service_name))) {

-    hr = callback(callback_context, service_name);

-    if (FAILED(hr) || hr == S_FALSE) {

-      // Callback asked to terminate enumeration.

-      return hr;

-    }

-  }

-

-  if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) {

-    ASSERT1(false);

-    REPORT(false, R_ERROR, (L"Failed enumerating service subkeys: 0x%x", hr),

-           1499372);

-    return hr;

-  }

-

-  return S_OK;

-}

-

-bool ScmDatabase::IsServiceStateEqual(SC_HANDLE service, DWORD state) {

-  ASSERT1(service);

-

-  DWORD bytes_needed_ignored = 0;

-  byte buffer[8 * 1024] = { 0 };

-  QUERY_SERVICE_CONFIG* service_config =

-    reinterpret_cast<QUERY_SERVICE_CONFIG*>(buffer);

-  if (!::QueryServiceConfig(service, service_config, sizeof(buffer),

-                            &bytes_needed_ignored)) {

-    ASSERT(false, (L"Failed to query service config, perhaps handle is missing "

-                   L"SERVICE_QUERY_CONFIG rights?"));

-    return false;

-  }

-

-  return (service_config[0].dwStartType == state);

-}

-

-bool ScmDatabase::IsServiceMarkedDeleted(SC_HANDLE service) {

-  ASSERT1(service);

-

-  // Services that have been marked deleted are always in the

-  // SERVICE_DISABLED state.  The converse is not true, and unfortunately

-  // there is no way to check if a service has been marked deleted except by

-  // attempting to change one of its configuration parameters, at which

-  // point you get a specific error indicating it has been marked deleted.

-  //

-  // The following call to ChangeServiceConfig does not actually change any

-  // of the service's configuration, but should hopefully return the

-  // specific error if the service has been marked deleted.

-  if (!::ChangeServiceConfig(service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,

-                             SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL,

-                             NULL, NULL, NULL) &&

-      ::GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE) {

-    ASSERT1(IsServiceStateEqual(service, SERVICE_DISABLED));

-    return true;

-  } else {

-    return false;

-  }

-}

-

-HRESULT ServiceInstall::UninstallByPrefix(void* context,

-                                          const wchar_t* service_name) {

-  ASSERT1(context != NULL);

-  if (!context)

-    return E_POINTER;

-

-  UninstallByPrefixParams* params =

-    reinterpret_cast<UninstallByPrefixParams*>(context);

-

-  if (String_StartsWith(service_name, params->prefix, true) &&

-      lstrcmpiW(service_name, params->unless_matches) != 0) {

-    // The service must be stopped before attempting to remove it from the

-    // database. Otherwise, the SCM database remains dirty and all service

-    // functions return ERROR_SERVICE_MARKED_FOR_DELETE until the system is

-    // restarted.

-    StopService(service_name);

-

-    scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));

-    if (!scm) {

-      HRESULT hr = HRESULTFromLastError();

-      ASSERT1(false);

-      REPORT(false, R_ERROR, (L"Failed to open SCM: 0x%x", hr), 77223399);

-      return hr;

-    }

-    scoped_service service(::OpenService(get(scm),

-                                         service_name,

-                                         SERVICE_CHANGE_CONFIG | DELETE));

-    if (service) {

-      // The service may not get deleted immediately; if there are handles to

-      // it open, it won't get deleted until the last one is closed.  If the

-      // service is running, it won't get deleted immediately but rather will be

-      // marked for deletion (which happens on next reboot).  Having to wait for

-      // a while and even until reboot doesn't matter much to us as our new

-      // service is installed under a new name and we are just cleaning up old

-      // ones.

-      if (!::DeleteService(get(service))) {

-        // We do not assert but just report so that we know if this happens

-        // abnormally often.

-        if (::GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE) {

-          REPORT(false, R_INFO,

-                 (L"Failed to immediately delete service %s", service_name),

-                 5440098);

-        } else {

-          ASSERT(false, (L"Failed to delete service %s, error %d",

-                         service_name, ::GetLastError()));

-        }

-        // DO NOT return an error here; we want to keep going through all the

-        // services.

-      } else {

-        SERVICE_LOG(L1,

-                    (L"Deleted old service %s", service_name));

-      }

-    } else {

-      // Per documentation of the EnumerateServicesCallback interface we can

-      // expect not to be able to open the service with one of the following two

-      // error codes, because of discrepancies between the registry and the SCM

-      // database in memory.

-      DWORD last_error = ::GetLastError();

-      ASSERT(last_error == ERROR_SERVICE_DOES_NOT_EXIST ||

-             last_error == ERROR_INVALID_NAME,

-             (L"Failed to open service %s, last error %d", service_name,

-              last_error));

-      REPORT(last_error == ERROR_SERVICE_DOES_NOT_EXIST ||

-             last_error == ERROR_INVALID_NAME, R_ERROR,

-             (L"Failed to open service %s, last error %d", service_name,

-              last_error), 5576234);

-    }

-  }

-

-  return S_OK;

-}

-

-CString ServiceInstall::GenerateServiceName(const TCHAR* service_prefix) {

-  FILETIME ft = {0};

-  ::GetSystemTimeAsFileTime(&ft);

-  CString versioned_service_name;

-  versioned_service_name.Format(_T("%s%x%x"),

-                                service_prefix,

-                                ft.dwHighDateTime,

-                                ft.dwLowDateTime);

-

-  ASSERT1(!versioned_service_name.IsEmpty());

-  return versioned_service_name;

-}

-

-HRESULT ServiceInstall::UninstallServices(const TCHAR* service_prefix,

-                                          const TCHAR* exclude_service) {

-  SERVICE_LOG(L2, (L"ServiceInstall::UninstallServices"));

-

-  UninstallByPrefixParams params = {

-    service_prefix,

-    exclude_service,

-  };

-

-  return ScmDatabase::EnumerateServices(UninstallByPrefix, &params);

-}

-

-bool ServiceInstall::CanInstallWithoutReboot() {

-  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));

-  if (!scm) {

-    ASSERT1(false);

-    REPORT(false, R_ERROR, (L"Failed to open SCM: %d", ::GetLastError()),

-           77224449);

-    return false;  // request reboot just in case

-  }

-

-  scoped_service service(::OpenService(get(scm),

-                                       _T("gupdate"),

-                                       SERVICE_QUERY_CONFIG |

-                                       SERVICE_CHANGE_CONFIG));

-  if (!service) {

-    DWORD last_error = ::GetLastError();

-    if (last_error == ERROR_ACCESS_DENIED ||

-        last_error == ERROR_INVALID_HANDLE) {

-      // unable to verify the service is fully deleted, so request reboot

-      ASSERT(false, (L"Expected access and correct handle"));

-      return false;

-    } else {

-      // service does not exist

-      return true;

-    }

-  }

-

-  return !ScmDatabase::IsServiceMarkedDeleted(get(service));

-}

-

-HRESULT ServiceInstall::StopService(const CString& service_name) {

-  SERVICE_LOG(L1, (_T("[ServiceInstall::StopService]")));

-

-  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));

-  if (!scm) {

-    return HRESULTFromLastError();

-  }

-  scoped_service service(::OpenService(get(scm),

-                                       service_name,

-                                       SERVICE_QUERY_STATUS | SERVICE_STOP));

-  if (!service) {

-    return HRESULTFromLastError();

-  }

-

-  SERVICE_STATUS status = {0};

-  if (::QueryServiceStatus(get(service), &status)) {

-    if (status.dwCurrentState != SERVICE_STOPPED &&

-        status.dwCurrentState != SERVICE_STOP_PENDING) {

-      // Stop the service.

-      SetZero(status);

-      if (!::ControlService(get(service), SERVICE_CONTROL_STOP, &status)) {

-        return HRESULTFromLastError();

-      }

-    }

-  }

-

-  if (status.dwCurrentState != SERVICE_STOPPED) {

-    SERVICE_LOG(L1, (_T("[Service is stopping...]")));

-

-    const int kWaitForServiceToStopMs = 8000;

-    LowResTimer t(true);

-

-    while (status.dwCurrentState != SERVICE_STOPPED &&

-           t.GetMilliseconds() < kWaitForServiceToStopMs) {

-      const int kSleepTimeMs = 50;

-      ::Sleep(kSleepTimeMs);

-      SetZero(status);

-      VERIFY1(::QueryServiceStatus(get(service), &status));

-      SERVICE_LOG(L1, (_T("[Waiting for service to stop %d]"),

-          static_cast<int>(t.GetMilliseconds())));

-    }

-

-    if (status.dwCurrentState != SERVICE_STOPPED) {

-      SERVICE_LOG(LEVEL_WARNING, (_T("[Service did not stop! Not good...]")));

-      return HRESULT_FROM_WIN32(ERROR_TIMEOUT);

-    }

-  }

-

-  ASSERT1(status.dwCurrentState == SERVICE_STOPPED);

-  SERVICE_LOG(L1, (_T("[ServiceInstall::StopService - service stopped]")));

-  return S_OK;

-}

-

-bool ServiceInstall::IsServiceInstalled(const TCHAR* service_name) {

-  ASSERT1(service_name);

-  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT));

-  if (!scm) {

-    return false;

-  }

-  scoped_service service(::OpenService(get(scm),

-                                       service_name,

-                                       SERVICE_QUERY_CONFIG));

-  return valid(service);

-}

-

-// TODO(Omaha): Move all functions under a common ServiceUtils namespace.

-bool ServiceUtils::IsServiceRunning(const TCHAR* service_name) {

-  ASSERT1(service_name);

-

-  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT));

-  if (!scm) {

-    SERVICE_LOG(LE, (_T("[OpenSCManager fail][0x%x]"), HRESULTFromLastError()));

-    return false;

-  }

-

-  scoped_service service(::OpenService(get(scm),

-                                       service_name,

-                                       SERVICE_QUERY_STATUS));

-  if (!service) {

-    SERVICE_LOG(LE, (_T("[OpenService failed][%s][0x%x]"),

-                     service_name, HRESULTFromLastError()));

-    return false;

-  }

-

-  SERVICE_STATUS status = {0};

-  if (!::QueryServiceStatus(get(service), &status)) {

-    SERVICE_LOG(LE, (_T("[QueryServiceStatus failed][%s][0x%x]"),

-                     service_name, HRESULTFromLastError()));

-    return false;

-  }

-

-  return status.dwCurrentState == SERVICE_RUNNING ||

-         status.dwCurrentState == SERVICE_START_PENDING;

-}

-

-bool ServiceUtils::IsServiceDisabled(const TCHAR* service_name) {

-  ASSERT1(service_name);

-

-  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT));

-  if (!scm) {

-    SERVICE_LOG(LE, (_T("[OpenSCManager fail][0x%x]"), HRESULTFromLastError()));

-    return false;

-  }

-

-  scoped_service service(::OpenService(get(scm),

-                                       service_name,

-                                       SERVICE_QUERY_CONFIG));

-  if (!service) {

-    SERVICE_LOG(LE, (_T("[OpenService failed][%s][0x%x]"),

-                     service_name, HRESULTFromLastError()));

-    return false;

-  }

-

-  return ScmDatabase::IsServiceStateEqual(get(service), SERVICE_DISABLED);

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Service-related utilities.
+//
+
+#include "omaha/common/service_utils.h"
+
+#include <windows.h>
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/smart_handle.h"
+#include "omaha/common/string.h"
+#include "omaha/common/timer.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+HRESULT ScmDatabase::EnumerateServices(
+    ScmDatabase::EnumerateServicesCallback callback,
+    void* callback_context) {
+  ASSERT1(callback);
+  if (!callback)
+    return E_POINTER;
+
+  const wchar_t* kServicesRegKeyFromRoot =
+    L"SYSTEM\\CurrentControlSet\\Services";
+
+  HRESULT hr = E_FAIL;
+
+  RegKey services_key;
+  if (FAILED(hr = services_key.Open(HKEY_LOCAL_MACHINE,
+                                    kServicesRegKeyFromRoot,
+                                    KEY_ENUMERATE_SUB_KEYS))) {
+    ASSERT1(false);
+    REPORT(false, R_ERROR, (L"Couldn't open services subkey, hr=0x%x", hr),
+           9834572);
+    return hr;
+  }
+
+  CString service_name;
+  int key_index = 0;
+  while (SUCCEEDED(hr = services_key.GetSubkeyNameAt(key_index++,
+                                                     &service_name))) {
+    hr = callback(callback_context, service_name);
+    if (FAILED(hr) || hr == S_FALSE) {
+      // Callback asked to terminate enumeration.
+      return hr;
+    }
+  }
+
+  if (hr != HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)) {
+    ASSERT1(false);
+    REPORT(false, R_ERROR, (L"Failed enumerating service subkeys: 0x%x", hr),
+           1499372);
+    return hr;
+  }
+
+  return S_OK;
+}
+
+bool ScmDatabase::IsServiceStateEqual(SC_HANDLE service, DWORD state) {
+  ASSERT1(service);
+
+  DWORD bytes_needed_ignored = 0;
+  byte buffer[8 * 1024] = { 0 };
+  QUERY_SERVICE_CONFIG* service_config =
+    reinterpret_cast<QUERY_SERVICE_CONFIG*>(buffer);
+  if (!::QueryServiceConfig(service, service_config, sizeof(buffer),
+                            &bytes_needed_ignored)) {
+    ASSERT(false, (L"Failed to query service config, perhaps handle is missing "
+                   L"SERVICE_QUERY_CONFIG rights?"));
+    return false;
+  }
+
+  return (service_config[0].dwStartType == state);
+}
+
+bool ScmDatabase::IsServiceMarkedDeleted(SC_HANDLE service) {
+  ASSERT1(service);
+
+  // Services that have been marked deleted are always in the
+  // SERVICE_DISABLED state.  The converse is not true, and unfortunately
+  // there is no way to check if a service has been marked deleted except by
+  // attempting to change one of its configuration parameters, at which
+  // point you get a specific error indicating it has been marked deleted.
+  //
+  // The following call to ChangeServiceConfig does not actually change any
+  // of the service's configuration, but should hopefully return the
+  // specific error if the service has been marked deleted.
+  if (!::ChangeServiceConfig(service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
+                             SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL) &&
+      ::GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE) {
+    ASSERT1(IsServiceStateEqual(service, SERVICE_DISABLED));
+    return true;
+  } else {
+    return false;
+  }
+}
+
+HRESULT ServiceInstall::UninstallByPrefix(void* context,
+                                          const wchar_t* service_name) {
+  ASSERT1(context != NULL);
+  if (!context)
+    return E_POINTER;
+
+  UninstallByPrefixParams* params =
+    reinterpret_cast<UninstallByPrefixParams*>(context);
+
+  if (String_StartsWith(service_name, params->prefix, true) &&
+      lstrcmpiW(service_name, params->unless_matches) != 0) {
+    // The service must be stopped before attempting to remove it from the
+    // database. Otherwise, the SCM database remains dirty and all service
+    // functions return ERROR_SERVICE_MARKED_FOR_DELETE until the system is
+    // restarted.
+    StopService(service_name);
+
+    scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
+    if (!scm) {
+      HRESULT hr = HRESULTFromLastError();
+      ASSERT1(false);
+      REPORT(false, R_ERROR, (L"Failed to open SCM: 0x%x", hr), 77223399);
+      return hr;
+    }
+    scoped_service service(::OpenService(get(scm),
+                                         service_name,
+                                         SERVICE_CHANGE_CONFIG | DELETE));
+    if (service) {
+      // The service may not get deleted immediately; if there are handles to
+      // it open, it won't get deleted until the last one is closed.  If the
+      // service is running, it won't get deleted immediately but rather will be
+      // marked for deletion (which happens on next reboot).  Having to wait for
+      // a while and even until reboot doesn't matter much to us as our new
+      // service is installed under a new name and we are just cleaning up old
+      // ones.
+      if (!::DeleteService(get(service))) {
+        // We do not assert but just report so that we know if this happens
+        // abnormally often.
+        if (::GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE) {
+          REPORT(false, R_INFO,
+                 (L"Failed to immediately delete service %s", service_name),
+                 5440098);
+        } else {
+          ASSERT(false, (L"Failed to delete service %s, error %d",
+                         service_name, ::GetLastError()));
+        }
+        // DO NOT return an error here; we want to keep going through all the
+        // services.
+      } else {
+        SERVICE_LOG(L1,
+                    (L"Deleted old service %s", service_name));
+      }
+    } else {
+      // Per documentation of the EnumerateServicesCallback interface we can
+      // expect not to be able to open the service with one of the following two
+      // error codes, because of discrepancies between the registry and the SCM
+      // database in memory.
+      DWORD last_error = ::GetLastError();
+      ASSERT(last_error == ERROR_SERVICE_DOES_NOT_EXIST ||
+             last_error == ERROR_INVALID_NAME,
+             (L"Failed to open service %s, last error %d", service_name,
+              last_error));
+      REPORT(last_error == ERROR_SERVICE_DOES_NOT_EXIST ||
+             last_error == ERROR_INVALID_NAME, R_ERROR,
+             (L"Failed to open service %s, last error %d", service_name,
+              last_error), 5576234);
+    }
+  }
+
+  return S_OK;
+}
+
+CString ServiceInstall::GenerateServiceName(const TCHAR* service_prefix) {
+  FILETIME ft = {0};
+  ::GetSystemTimeAsFileTime(&ft);
+  CString versioned_service_name;
+  versioned_service_name.Format(_T("%s%x%x"),
+                                service_prefix,
+                                ft.dwHighDateTime,
+                                ft.dwLowDateTime);
+
+  ASSERT1(!versioned_service_name.IsEmpty());
+  return versioned_service_name;
+}
+
+HRESULT ServiceInstall::UninstallServices(const TCHAR* service_prefix,
+                                          const TCHAR* exclude_service) {
+  SERVICE_LOG(L2, (L"ServiceInstall::UninstallServices"));
+
+  UninstallByPrefixParams params = {
+    service_prefix,
+    exclude_service,
+  };
+
+  return ScmDatabase::EnumerateServices(UninstallByPrefix, &params);
+}
+
+bool ServiceInstall::CanInstallWithoutReboot() {
+  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
+  if (!scm) {
+    ASSERT1(false);
+    REPORT(false, R_ERROR, (L"Failed to open SCM: %d", ::GetLastError()),
+           77224449);
+    return false;  // request reboot just in case
+  }
+
+  scoped_service service(::OpenService(get(scm),
+                                       _T("gupdate"),
+                                       SERVICE_QUERY_CONFIG |
+                                       SERVICE_CHANGE_CONFIG));
+  if (!service) {
+    DWORD last_error = ::GetLastError();
+    if (last_error == ERROR_ACCESS_DENIED ||
+        last_error == ERROR_INVALID_HANDLE) {
+      // unable to verify the service is fully deleted, so request reboot
+      ASSERT(false, (L"Expected access and correct handle"));
+      return false;
+    } else {
+      // service does not exist
+      return true;
+    }
+  }
+
+  return !ScmDatabase::IsServiceMarkedDeleted(get(service));
+}
+
+HRESULT ServiceInstall::StopService(const CString& service_name) {
+  SERVICE_LOG(L1, (_T("[ServiceInstall::StopService]")));
+
+  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
+  if (!scm) {
+    return HRESULTFromLastError();
+  }
+  scoped_service service(::OpenService(get(scm),
+                                       service_name,
+                                       SERVICE_QUERY_STATUS | SERVICE_STOP));
+  if (!service) {
+    return HRESULTFromLastError();
+  }
+
+  SERVICE_STATUS status = {0};
+  if (::QueryServiceStatus(get(service), &status)) {
+    if (status.dwCurrentState != SERVICE_STOPPED &&
+        status.dwCurrentState != SERVICE_STOP_PENDING) {
+      // Stop the service.
+      SetZero(status);
+      if (!::ControlService(get(service), SERVICE_CONTROL_STOP, &status)) {
+        return HRESULTFromLastError();
+      }
+    }
+  }
+
+  if (status.dwCurrentState != SERVICE_STOPPED) {
+    SERVICE_LOG(L1, (_T("[Service is stopping...]")));
+
+    const int kWaitForServiceToStopMs = 8000;
+    LowResTimer t(true);
+
+    while (status.dwCurrentState != SERVICE_STOPPED &&
+           t.GetMilliseconds() < kWaitForServiceToStopMs) {
+      const int kSleepTimeMs = 50;
+      ::Sleep(kSleepTimeMs);
+      SetZero(status);
+      VERIFY1(::QueryServiceStatus(get(service), &status));
+      SERVICE_LOG(L1, (_T("[Waiting for service to stop %d]"),
+          static_cast<int>(t.GetMilliseconds())));
+    }
+
+    if (status.dwCurrentState != SERVICE_STOPPED) {
+      SERVICE_LOG(LEVEL_WARNING, (_T("[Service did not stop! Not good...]")));
+      return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+    }
+  }
+
+  ASSERT1(status.dwCurrentState == SERVICE_STOPPED);
+  SERVICE_LOG(L1, (_T("[ServiceInstall::StopService - service stopped]")));
+  return S_OK;
+}
+
+bool ServiceInstall::IsServiceInstalled(const TCHAR* service_name) {
+  ASSERT1(service_name);
+  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT));
+  if (!scm) {
+    return false;
+  }
+  scoped_service service(::OpenService(get(scm),
+                                       service_name,
+                                       SERVICE_QUERY_CONFIG));
+  return valid(service);
+}
+
+// TODO(Omaha): Move all functions under a common ServiceUtils namespace.
+bool ServiceUtils::IsServiceRunning(const TCHAR* service_name) {
+  ASSERT1(service_name);
+
+  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT));
+  if (!scm) {
+    SERVICE_LOG(LE, (_T("[OpenSCManager fail][0x%x]"), HRESULTFromLastError()));
+    return false;
+  }
+
+  scoped_service service(::OpenService(get(scm),
+                                       service_name,
+                                       SERVICE_QUERY_STATUS));
+  if (!service) {
+    SERVICE_LOG(LE, (_T("[OpenService failed][%s][0x%x]"),
+                     service_name, HRESULTFromLastError()));
+    return false;
+  }
+
+  SERVICE_STATUS status = {0};
+  if (!::QueryServiceStatus(get(service), &status)) {
+    SERVICE_LOG(LE, (_T("[QueryServiceStatus failed][%s][0x%x]"),
+                     service_name, HRESULTFromLastError()));
+    return false;
+  }
+
+  return status.dwCurrentState == SERVICE_RUNNING ||
+         status.dwCurrentState == SERVICE_START_PENDING;
+}
+
+bool ServiceUtils::IsServiceDisabled(const TCHAR* service_name) {
+  ASSERT1(service_name);
+
+  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT));
+  if (!scm) {
+    SERVICE_LOG(LE, (_T("[OpenSCManager fail][0x%x]"), HRESULTFromLastError()));
+    return false;
+  }
+
+  scoped_service service(::OpenService(get(scm),
+                                       service_name,
+                                       SERVICE_QUERY_CONFIG));
+  if (!service) {
+    SERVICE_LOG(LE, (_T("[OpenService failed][%s][0x%x]"),
+                     service_name, HRESULTFromLastError()));
+    return false;
+  }
+
+  return ScmDatabase::IsServiceStateEqual(get(service), SERVICE_DISABLED);
+}
+
+}  // namespace omaha
+
diff --git a/common/service_utils.h b/common/service_utils.h
index b808b97..31b654c 100644
--- a/common/service_utils.h
+++ b/common/service_utils.h
@@ -1,144 +1,144 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Service-related utilities.

-

-#ifndef OMAHA_COMMON_SERVICE_UTILS_H__

-#define OMAHA_COMMON_SERVICE_UTILS_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// Utility functions for working with the SCM database.

-class ScmDatabase {

- public:

-  // Callback function type for EnumerateServices. This gets called for each

-  // service in the registry.

-  //

-  // @param callback_context Passed unchanged from the caller of

-  // EnumerateServices to the callback function.

-  // @param service_name The name of the service (not the display name but

-  // rather the canonical name, to be used with e.g. ::OpenService()).  Note

-  // that because this function is based on enumerating the registry, it's

-  // possible that services that were recently deleted will show up in the

-  // enumeration; therefore, it should not be considered an error if you try

-  // to ::OpenService() on this name and it fails with a last error of

-  // ERROR_SERVICE_DOES_NOT_EXIST or possibly ERROR_INVALID_NAME (if

-  // somebody messed up the registry by hand).

-  //

-  // @return S_OK to continue enumeration, S_FALSE or a COM error code to

-  // stop enumeration.  The return value will be propagated to the caller

-  // of Enumerate.

-  //

-  // @note The initial version of this function used EnumServicesStatusEx

-  // but it turns out the function is a fair bit flaky, not returning all

-  // recently created (e.g. created but never started) services.

-  typedef HRESULT(*EnumerateServicesCallback)(void* callback_context,

-                                              const wchar_t* service_name);

-

-  // Calls 'callback' for each of the services in the registry.

-  //

-  // @param callback Callback function to call

-  // @param callback_context Passed unchanged to your callback function

-  //

-  // @return S_OK or a COM error code.

-  static HRESULT EnumerateServices(EnumerateServicesCallback callback,

-                                   void* callback_context);

-

-  // Returns true iff the service passed in is in the indicated state.

-  //

-  // @param service An open handle to a service.  The handle must have at

-  // least SERVICE_QUERY_CONFIG rights.

-  // @param state One of the SERVICE_XXX constants indicating the state of a

-  // service (e.g. SERVICE_DISABLED).

-  //

-  // @return True iff 'service' is in state 'state'.

-  static bool IsServiceStateEqual(SC_HANDLE service, DWORD state);

-

-  // Returns true iff the service passed in has been marked deleted.

-  //

-  // @param service An open handle to a service.  The handle must have at

-  // least SERVICE_QUERY_CONFIG and SERVICE_CHANGE_CONFIG rights.

-  //

-  // @return True iff 'service' has been marked deleted.

-  static bool IsServiceMarkedDeleted(SC_HANDLE service);

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(ScmDatabase);

-};

-

-// Utility functions for the service's installation, overinstall etc.

-class ServiceInstall {

- public:

-

-  // Generates a versioned service name based on the current system time.

-  static CString GenerateServiceName(const TCHAR* service_prefix);

-

-  // Uninstalls all versions of the service other than the one that matches

-  // the service name passed in. Pass in NULL to uninstall everything.

-  static HRESULT UninstallServices(const TCHAR* service_prefix,

-                                   const TCHAR* exclude_service);

-

-  static bool IsServiceInstalled(const TCHAR* service_name);

-

-  // @return True if the current service can be installed without rebooting,

-  // false if a reboot is required before it can be installed.  The cases

-  // where the current service can be installed without rebooting are:

-  // a) when no service exists with the current name

-  // b) when there is an existing service with the current name but it is

-  //    not marked for deletion

-  static bool CanInstallWithoutReboot();

-

-  // Given a service name, stops it if it is already running.

-  static HRESULT StopService(const CString& service_name);

-

- protected:

-  // Context passed to the UninstallIfNotCurrent function; this is made a

-  // parameter so we can unit test the function without mucking with the

-  // "actual" services.

-  struct UninstallByPrefixParams {

-    CString prefix;  // prefix of services we want to uninstall

-    CString unless_matches;  // name of current service, to not touch

-  };

-

-  // Uninstalls a given service if it matches a given prefix but does not match

-  // a given full service name.

-  //

-  // This is an ScmDatabase::EnumerateServicesCallback function.

-  //

-  // @param context Pointer to an UninstallByPrefix structure.

-  static HRESULT UninstallByPrefix(void* context, const wchar_t* service_name);

-

- private:

-  DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceInstall);

-};

-

-// Service utility functions for querying current state, and eventually more.

-class ServiceUtils {

- public:

-  static bool IsServiceRunning(const TCHAR* service_name);

-  static bool IsServiceDisabled(const TCHAR* service_name);

-

- private:

-  DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceUtils);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SERVICE_UTILS_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Service-related utilities.
+
+#ifndef OMAHA_COMMON_SERVICE_UTILS_H__
+#define OMAHA_COMMON_SERVICE_UTILS_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// Utility functions for working with the SCM database.
+class ScmDatabase {
+ public:
+  // Callback function type for EnumerateServices. This gets called for each
+  // service in the registry.
+  //
+  // @param callback_context Passed unchanged from the caller of
+  // EnumerateServices to the callback function.
+  // @param service_name The name of the service (not the display name but
+  // rather the canonical name, to be used with e.g. ::OpenService()).  Note
+  // that because this function is based on enumerating the registry, it's
+  // possible that services that were recently deleted will show up in the
+  // enumeration; therefore, it should not be considered an error if you try
+  // to ::OpenService() on this name and it fails with a last error of
+  // ERROR_SERVICE_DOES_NOT_EXIST or possibly ERROR_INVALID_NAME (if
+  // somebody messed up the registry by hand).
+  //
+  // @return S_OK to continue enumeration, S_FALSE or a COM error code to
+  // stop enumeration.  The return value will be propagated to the caller
+  // of Enumerate.
+  //
+  // @note The initial version of this function used EnumServicesStatusEx
+  // but it turns out the function is a fair bit flaky, not returning all
+  // recently created (e.g. created but never started) services.
+  typedef HRESULT(*EnumerateServicesCallback)(void* callback_context,
+                                              const wchar_t* service_name);
+
+  // Calls 'callback' for each of the services in the registry.
+  //
+  // @param callback Callback function to call
+  // @param callback_context Passed unchanged to your callback function
+  //
+  // @return S_OK or a COM error code.
+  static HRESULT EnumerateServices(EnumerateServicesCallback callback,
+                                   void* callback_context);
+
+  // Returns true iff the service passed in is in the indicated state.
+  //
+  // @param service An open handle to a service.  The handle must have at
+  // least SERVICE_QUERY_CONFIG rights.
+  // @param state One of the SERVICE_XXX constants indicating the state of a
+  // service (e.g. SERVICE_DISABLED).
+  //
+  // @return True iff 'service' is in state 'state'.
+  static bool IsServiceStateEqual(SC_HANDLE service, DWORD state);
+
+  // Returns true iff the service passed in has been marked deleted.
+  //
+  // @param service An open handle to a service.  The handle must have at
+  // least SERVICE_QUERY_CONFIG and SERVICE_CHANGE_CONFIG rights.
+  //
+  // @return True iff 'service' has been marked deleted.
+  static bool IsServiceMarkedDeleted(SC_HANDLE service);
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(ScmDatabase);
+};
+
+// Utility functions for the service's installation, overinstall etc.
+class ServiceInstall {
+ public:
+
+  // Generates a versioned service name based on the current system time.
+  static CString GenerateServiceName(const TCHAR* service_prefix);
+
+  // Uninstalls all versions of the service other than the one that matches
+  // the service name passed in. Pass in NULL to uninstall everything.
+  static HRESULT UninstallServices(const TCHAR* service_prefix,
+                                   const TCHAR* exclude_service);
+
+  static bool IsServiceInstalled(const TCHAR* service_name);
+
+  // @return True if the current service can be installed without rebooting,
+  // false if a reboot is required before it can be installed.  The cases
+  // where the current service can be installed without rebooting are:
+  // a) when no service exists with the current name
+  // b) when there is an existing service with the current name but it is
+  //    not marked for deletion
+  static bool CanInstallWithoutReboot();
+
+  // Given a service name, stops it if it is already running.
+  static HRESULT StopService(const CString& service_name);
+
+ protected:
+  // Context passed to the UninstallIfNotCurrent function; this is made a
+  // parameter so we can unit test the function without mucking with the
+  // "actual" services.
+  struct UninstallByPrefixParams {
+    CString prefix;  // prefix of services we want to uninstall
+    CString unless_matches;  // name of current service, to not touch
+  };
+
+  // Uninstalls a given service if it matches a given prefix but does not match
+  // a given full service name.
+  //
+  // This is an ScmDatabase::EnumerateServicesCallback function.
+  //
+  // @param context Pointer to an UninstallByPrefix structure.
+  static HRESULT UninstallByPrefix(void* context, const wchar_t* service_name);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceInstall);
+};
+
+// Service utility functions for querying current state, and eventually more.
+class ServiceUtils {
+ public:
+  static bool IsServiceRunning(const TCHAR* service_name);
+  static bool IsServiceDisabled(const TCHAR* service_name);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ServiceUtils);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SERVICE_UTILS_H__
+
diff --git a/common/service_utils_unittest.cc b/common/service_utils_unittest.cc
index d52191c..3ece94f 100644
--- a/common/service_utils_unittest.cc
+++ b/common/service_utils_unittest.cc
@@ -1,59 +1,59 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/service_utils.h"

-#include <lmsname.h>

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Set to true when the test callback sees the service indicated in the

-// context parameter.

-bool found_service = false;

-

-HRESULT TestEnumCallback(void* context, const wchar_t* service_name) {

-  EXPECT_TRUE(context);

-

-  const wchar_t* find_service_name = reinterpret_cast<const wchar_t*>(context);

-  if (lstrcmpW(service_name, find_service_name) == 0) {

-    found_service = true;

-  }

-

-  return S_OK;

-}

-

-TEST(ServiceUtilsTest, ScmDatabaseEnumerateServices) {

-  found_service = false;

-  EXPECT_TRUE(SUCCEEDED(ScmDatabase::EnumerateServices(TestEnumCallback,

-                            reinterpret_cast<void*>(_T("Eventlog")))));

-  EXPECT_TRUE(found_service);

-}

-

-TEST(ServiceUtilsTest, IsServiceInstalled) {

-  EXPECT_TRUE(ServiceInstall::IsServiceInstalled(SERVICE_SCHEDULE));

-  EXPECT_FALSE(ServiceInstall::IsServiceInstalled(_T("FooBar")));

-}

-

-TEST(ServiceUtilsTest, IsServiceRunning) {

-  EXPECT_TRUE(ServiceUtils::IsServiceRunning(SERVICE_SCHEDULE));

-  EXPECT_FALSE(ServiceUtils::IsServiceRunning(_T("FooBar")));

-}

-

-TEST(ServiceUtilsTest, IsServiceDisabled) {

-  EXPECT_FALSE(ServiceUtils::IsServiceDisabled(SERVICE_SCHEDULE));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/service_utils.h"
+#include <lmsname.h>
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Set to true when the test callback sees the service indicated in the
+// context parameter.
+bool found_service = false;
+
+HRESULT TestEnumCallback(void* context, const wchar_t* service_name) {
+  EXPECT_TRUE(context);
+
+  const wchar_t* find_service_name = reinterpret_cast<const wchar_t*>(context);
+  if (lstrcmpW(service_name, find_service_name) == 0) {
+    found_service = true;
+  }
+
+  return S_OK;
+}
+
+TEST(ServiceUtilsTest, ScmDatabaseEnumerateServices) {
+  found_service = false;
+  EXPECT_TRUE(SUCCEEDED(ScmDatabase::EnumerateServices(TestEnumCallback,
+                            reinterpret_cast<void*>(_T("Eventlog")))));
+  EXPECT_TRUE(found_service);
+}
+
+TEST(ServiceUtilsTest, IsServiceInstalled) {
+  EXPECT_TRUE(ServiceInstall::IsServiceInstalled(SERVICE_SCHEDULE));
+  EXPECT_FALSE(ServiceInstall::IsServiceInstalled(_T("FooBar")));
+}
+
+TEST(ServiceUtilsTest, IsServiceRunning) {
+  EXPECT_TRUE(ServiceUtils::IsServiceRunning(SERVICE_SCHEDULE));
+  EXPECT_FALSE(ServiceUtils::IsServiceRunning(_T("FooBar")));
+}
+
+TEST(ServiceUtilsTest, IsServiceDisabled) {
+  EXPECT_FALSE(ServiceUtils::IsServiceDisabled(SERVICE_SCHEDULE));
+}
+
+}  // namespace omaha
+
diff --git a/common/sha.cc b/common/sha.cc
index b6e73c4..e6d91e9 100644
--- a/common/sha.cc
+++ b/common/sha.cc
@@ -1,147 +1,147 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// REMINDER: Identifiers are in accordance with the FIPS180-1 spec

-

-#include "sha.h"

-#include "common/debug.h"

-

-namespace omaha {

-

-typedef SecureHashAlgorithm::uint uint;

-

-//const int SecureHashAlgorithm::kDigestSize;

-

-static inline uint f(uint t, uint B, uint C, uint D) {

-  if (t < 20)

-    return (B & C) | ((~B) & D);

-  else if (t < 40)

-    return B ^ C ^ D;

-  else if (t < 60)

-    return (B & C) | (B & D) | (C & D);

-  else

-    return B ^ C ^ D;

-}

-

-static inline uint S(uint n, uint X) {

-  return (X << n) | (X >> (32-n));

-}

-

-static inline uint K(uint t) {

-  if (t < 20)

-    return 0x5a827999;

-  else if (t < 40)

-    return 0x6ed9eba1;

-  else if (t < 60)

-    return 0x8f1bbcdc;

-  else

-    return 0xca62c1d6;

-}

-

-static inline void swapends(uint& t) {

-  t = ((t & 0xff000000) >> 24) |

-      ((t & 0xff0000) >> 8) |

-      ((t & 0xff00) << 8) |

-      ((t & 0xff) << 24);

-}

-

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

-

-void SecureHashAlgorithm::Init() {

-  cursor = 0;

-  l = 0;

-  H[0] = 0x67452301;

-  H[1] = 0xefcdab89;

-  H[2] = 0x98badcfe;

-  H[3] = 0x10325476;

-  H[4] = 0xc3d2e1f0;

-}

-

-void SecureHashAlgorithm::Finished() {

-  Pad();

-  Process();

-

-  for(int t = 0; t < 5; ++t)

-    swapends(H[t]);

-}

-

-void SecureHashAlgorithm::AddBytes(const void * data, int nbytes) {

-  ASSERT(data, (L""));

-

-  const byte * d = reinterpret_cast<const byte *>(data);

-  while (nbytes--) {

-    M[cursor++] = *d++;

-    if (cursor >= 64) this->Process();

-    l += 8;

-  }

-}

-

-void SecureHashAlgorithm::Pad() {

-  M[cursor++] = 0x80;

-  if (cursor > 64-8) {

-    // pad out to next block

-    while (cursor < 64)

-      M[cursor++] = 0;

-    this->Process();

-  }

-  while (cursor < 64-4)

-    M[cursor++] = 0;

-  M[64-4] = static_cast<byte>((l & 0xff000000) >> 24);

-  M[64-3] = static_cast<byte>((l & 0xff0000) >> 16);

-  M[64-2] = static_cast<byte>((l & 0xff00) >> 8);

-  M[64-1] = static_cast<byte>((l & 0xff));

-}

-

-void SecureHashAlgorithm::Process() {

-  uint t;

-

-  // a.

-  // CopyMemory(W, M, sizeof(M));

-  for (t = 0; t < 16; ++t)

-    swapends(W[t]);

-

-  // b.

-  for (t = 16; t < 80; ++t)

-    W[t] = S(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);

-

-  // c.

-  A = H[0];

-  B = H[1];

-  C = H[2];

-  D = H[3];

-  E = H[4];

-

-  // d.

-  for (t = 0; t < 80; ++t) {

-    uint TEMP = S(5,A) + f(t,B,C,D) + E + W[t] + K(t);

-    E = D;

-    D = C;

-    C = S(30,B);

-    B = A;

-    A = TEMP;

-  }

-

-  // e.

-  H[0] += A;

-  H[1] += B;

-  H[2] += C;

-  H[3] += D;

-  H[4] += E;

-

-  cursor = 0;

-}

-

-}  // namespace omaha

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// REMINDER: Identifiers are in accordance with the FIPS180-1 spec
+
+#include "sha.h"
+#include "common/debug.h"
+
+namespace omaha {
+
+typedef SecureHashAlgorithm::uint uint;
+
+//const int SecureHashAlgorithm::kDigestSize;
+
+static inline uint f(uint t, uint B, uint C, uint D) {
+  if (t < 20)
+    return (B & C) | ((~B) & D);
+  else if (t < 40)
+    return B ^ C ^ D;
+  else if (t < 60)
+    return (B & C) | (B & D) | (C & D);
+  else
+    return B ^ C ^ D;
+}
+
+static inline uint S(uint n, uint X) {
+  return (X << n) | (X >> (32-n));
+}
+
+static inline uint K(uint t) {
+  if (t < 20)
+    return 0x5a827999;
+  else if (t < 40)
+    return 0x6ed9eba1;
+  else if (t < 60)
+    return 0x8f1bbcdc;
+  else
+    return 0xca62c1d6;
+}
+
+static inline void swapends(uint& t) {
+  t = ((t & 0xff000000) >> 24) |
+      ((t & 0xff0000) >> 8) |
+      ((t & 0xff00) << 8) |
+      ((t & 0xff) << 24);
+}
+
+//---------------------------------------------------------------------------
+
+void SecureHashAlgorithm::Init() {
+  cursor = 0;
+  l = 0;
+  H[0] = 0x67452301;
+  H[1] = 0xefcdab89;
+  H[2] = 0x98badcfe;
+  H[3] = 0x10325476;
+  H[4] = 0xc3d2e1f0;
+}
+
+void SecureHashAlgorithm::Finished() {
+  Pad();
+  Process();
+
+  for(int t = 0; t < 5; ++t)
+    swapends(H[t]);
+}
+
+void SecureHashAlgorithm::AddBytes(const void * data, int nbytes) {
+  ASSERT(data, (L""));
+
+  const byte * d = reinterpret_cast<const byte *>(data);
+  while (nbytes--) {
+    M[cursor++] = *d++;
+    if (cursor >= 64) this->Process();
+    l += 8;
+  }
+}
+
+void SecureHashAlgorithm::Pad() {
+  M[cursor++] = 0x80;
+  if (cursor > 64-8) {
+    // pad out to next block
+    while (cursor < 64)
+      M[cursor++] = 0;
+    this->Process();
+  }
+  while (cursor < 64-4)
+    M[cursor++] = 0;
+  M[64-4] = static_cast<byte>((l & 0xff000000) >> 24);
+  M[64-3] = static_cast<byte>((l & 0xff0000) >> 16);
+  M[64-2] = static_cast<byte>((l & 0xff00) >> 8);
+  M[64-1] = static_cast<byte>((l & 0xff));
+}
+
+void SecureHashAlgorithm::Process() {
+  uint t;
+
+  // a.
+  // CopyMemory(W, M, sizeof(M));
+  for (t = 0; t < 16; ++t)
+    swapends(W[t]);
+
+  // b.
+  for (t = 16; t < 80; ++t)
+    W[t] = S(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+
+  // c.
+  A = H[0];
+  B = H[1];
+  C = H[2];
+  D = H[3];
+  E = H[4];
+
+  // d.
+  for (t = 0; t < 80; ++t) {
+    uint TEMP = S(5,A) + f(t,B,C,D) + E + W[t] + K(t);
+    E = D;
+    D = C;
+    C = S(30,B);
+    B = A;
+    A = TEMP;
+  }
+
+  // e.
+  H[0] += A;
+  H[1] += B;
+  H[2] += C;
+  H[3] += D;
+  H[4] += E;
+
+  cursor = 0;
+}
+
+}  // namespace omaha
+
diff --git a/common/sha.h b/common/sha.h
index d4daf4b..c5212ec 100644
--- a/common/sha.h
+++ b/common/sha.h
@@ -1,82 +1,82 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SHA_H__

-#define OMAHA_COMMON_SHA_H__

-

-#include <wtypes.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// Implementation of SHA-1. Only handles data in byte-sized blocks,

-// which simplifies the code a fair bit.

-//

-// NOTE: All identifier names follow the notation in FIPS PUB 180-1 for

-// easy debugging. http://www.google.com/search?q=lucky:+FIPS+PUB+180-1

-//

-// Usage example:

-//

-// SecureHashAlgorithm sha;

-// while(there is data to hash)

-//   sha.AddBytes(moredata, size of data);

-// sha.Finished();

-// CopyMemory(somewhere, sha.Digest(), 20);

-//

-// To reuse the instance of sha, call sha.Init();

-//

-// This class is NOT threadsafe!

-

-

-class SecureHashAlgorithm {

-

- public:

-  SecureHashAlgorithm() { Init(); }

-

-  typedef unsigned int uint;         // to keep with notation in the spec

-

-  static const int kDigestSize = 20;   // 20 bytes of output

-

-  void Init();                                   // resets internal registers

-  void AddBytes(const void * data, int nbytes);  // processes bytes

-  void Finished();                               // computes final hash

-

-  // extracts the digest (20 bytes)

-  const unsigned char * Digest() const {

-    return reinterpret_cast<const unsigned char *>(H);

-  }

-

- private:

-  void Pad();           // if length of input is less than blocksize

-  void Process();       // does some rounds

-

-  uint A,B,C,D,E;       // internal registers; see spec

-

-  uint H[5];            // 20 bytes of message digest

-

-  union {

-    uint W[80];         // see spec

-    byte M[64];

-  };

-

-  uint cursor;          // placekeeping variables; see spec

-  uint l;

-

-  DISALLOW_EVIL_CONSTRUCTORS(SecureHashAlgorithm);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SHA_H__

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SHA_H__
+#define OMAHA_COMMON_SHA_H__
+
+#include <wtypes.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// Implementation of SHA-1. Only handles data in byte-sized blocks,
+// which simplifies the code a fair bit.
+//
+// NOTE: All identifier names follow the notation in FIPS PUB 180-1 for
+// easy debugging. http://www.google.com/search?q=lucky:+FIPS+PUB+180-1
+//
+// Usage example:
+//
+// SecureHashAlgorithm sha;
+// while(there is data to hash)
+//   sha.AddBytes(moredata, size of data);
+// sha.Finished();
+// CopyMemory(somewhere, sha.Digest(), 20);
+//
+// To reuse the instance of sha, call sha.Init();
+//
+// This class is NOT threadsafe!
+
+
+class SecureHashAlgorithm {
+
+ public:
+  SecureHashAlgorithm() { Init(); }
+
+  typedef unsigned int uint;         // to keep with notation in the spec
+
+  static const int kDigestSize = 20;   // 20 bytes of output
+
+  void Init();                                   // resets internal registers
+  void AddBytes(const void * data, int nbytes);  // processes bytes
+  void Finished();                               // computes final hash
+
+  // extracts the digest (20 bytes)
+  const unsigned char * Digest() const {
+    return reinterpret_cast<const unsigned char *>(H);
+  }
+
+ private:
+  void Pad();           // if length of input is less than blocksize
+  void Process();       // does some rounds
+
+  uint A,B,C,D,E;       // internal registers; see spec
+
+  uint H[5];            // 20 bytes of message digest
+
+  union {
+    uint W[80];         // see spec
+    byte M[64];
+  };
+
+  uint cursor;          // placekeeping variables; see spec
+  uint l;
+
+  DISALLOW_EVIL_CONSTRUCTORS(SecureHashAlgorithm);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SHA_H__
diff --git a/common/sha_unittest.cc b/common/sha_unittest.cc
index f478d61..bed3ee2 100644
--- a/common/sha_unittest.cc
+++ b/common/sha_unittest.cc
@@ -1,67 +1,67 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// sha_unittest.cpp

-//

-// Unit test functions for SHA

-

-#include <cstring>

-

-#include "omaha/common/sha.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// From the Original Eric Fredricksen implementation

-TEST(ShaTest, Digest) {

-

-  const char * const abc_digest =

-      "\xA9\x99\x3E\x36"

-      "\x47\x06\x81\x6A"

-      "\xBA\x3E\x25\x71"

-      "\x78\x50\xC2\x6C"

-      "\x9C\xD0\xD8\x9D";

-

-  { // FIPS 180-1 Appendix A example

-    SecureHashAlgorithm sha1;

-    sha1.AddBytes("abc", 3);

-    sha1.Finished();

-    ASSERT_TRUE(!memcmp(sha1.Digest(), abc_digest, 20));

-

-    // do it again to make sure Init works

-    sha1.Init();

-    sha1.AddBytes("abc", 3);

-    sha1.Finished();

-    ASSERT_TRUE(!memcmp(sha1.Digest(), abc_digest, 20));

-  }

-

-  const char * const multiblock_digest =

-      "\x84\x98\x3E\x44"

-      "\x1C\x3B\xD2\x6E"

-      "\xBA\xAE\x4A\xA1"

-      "\xF9\x51\x29\xE5"

-      "\xE5\x46\x70\xF1";

-

-  { // FIPS 180-1 Appendix A example

-    SecureHashAlgorithm sha1;

-    char * to_hash = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";

-    sha1.AddBytes(to_hash, strlen(to_hash));

-    sha1.Finished();

-    ASSERT_TRUE(!memcmp(sha1.Digest(), multiblock_digest, 20));

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// sha_unittest.cpp
+//
+// Unit test functions for SHA
+
+#include <cstring>
+
+#include "omaha/common/sha.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// From the Original Eric Fredricksen implementation
+TEST(ShaTest, Digest) {
+
+  const char * const abc_digest =
+      "\xA9\x99\x3E\x36"
+      "\x47\x06\x81\x6A"
+      "\xBA\x3E\x25\x71"
+      "\x78\x50\xC2\x6C"
+      "\x9C\xD0\xD8\x9D";
+
+  { // FIPS 180-1 Appendix A example
+    SecureHashAlgorithm sha1;
+    sha1.AddBytes("abc", 3);
+    sha1.Finished();
+    ASSERT_TRUE(!memcmp(sha1.Digest(), abc_digest, 20));
+
+    // do it again to make sure Init works
+    sha1.Init();
+    sha1.AddBytes("abc", 3);
+    sha1.Finished();
+    ASSERT_TRUE(!memcmp(sha1.Digest(), abc_digest, 20));
+  }
+
+  const char * const multiblock_digest =
+      "\x84\x98\x3E\x44"
+      "\x1C\x3B\xD2\x6E"
+      "\xBA\xAE\x4A\xA1"
+      "\xF9\x51\x29\xE5"
+      "\xE5\x46\x70\xF1";
+
+  { // FIPS 180-1 Appendix A example
+    SecureHashAlgorithm sha1;
+    char * to_hash = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+    sha1.AddBytes(to_hash, strlen(to_hash));
+    sha1.Finished();
+    ASSERT_TRUE(!memcmp(sha1.Digest(), multiblock_digest, 20));
+  }
+}
+
+}  // namespace omaha
+
diff --git a/common/shared_any.h b/common/shared_any.h
index acc9886..3250231 100644
--- a/common/shared_any.h
+++ b/common/shared_any.h
@@ -1,28 +1,28 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// See the comments in omaha/common/scoped_any.h for details.

-

-#ifndef OMAHA_COMMON_SHARED_ANY__

-#define OMAHA_COMMON_SHARED_ANY__

-

-#pragma warning(push)

-// C4640: construction of local static object is not thread-safe

-#pragma warning(disable : 4640)

-#include "omaha/third_party/smartany/shared_any.h"

-#pragma warning(pop)

-

-#endif  // OMAHA_COMMON_SHARED_ANY__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// See the comments in omaha/common/scoped_any.h for details.
+
+#ifndef OMAHA_COMMON_SHARED_ANY__
+#define OMAHA_COMMON_SHARED_ANY__
+
+#pragma warning(push)
+// C4640: construction of local static object is not thread-safe
+#pragma warning(disable : 4640)
+#include "omaha/third_party/smartany/shared_any.h"
+#pragma warning(pop)
+
+#endif  // OMAHA_COMMON_SHARED_ANY__
+
diff --git a/common/shared_memory_ptr.h b/common/shared_memory_ptr.h
index 27a4b25..7761641 100644
--- a/common/shared_memory_ptr.h
+++ b/common/shared_memory_ptr.h
@@ -1,392 +1,392 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines template class used to share data

-// between processes.

-//

-

-#ifndef OMAHA_COMMON_SHARED_MEMORY_PTR_H__

-#define OMAHA_COMMON_SHARED_MEMORY_PTR_H__

-

-#include "common/debug.h"

-#include "common/singleton.h"

-#include "common/system_info.h"

-#include "common/vista_utils.h"

-

-namespace omaha {

-

-// SharedMemoryPtr class is designed to allow seamless data sharing process boundaries.

-// All the data passed as a template parameter will be shared between processes.

-// Very important to remember that for now - all shared data should be on stack.

-// For example if the class A had stl vector as a member, the members of the vector

-// would be allocated not from shared memory and therefore will not be shared.

-// That could be solved with allocators, but for now we don't need that.

-//

-// Here is a typical example of usage:

-//   Class A {

-//    int i_;

-//    double d_;

-//    .......

-//    ........

-//

-//    public:

-//    set_double(double d){d_=d;}

-//    double get_double(){return d_};

-//

-// };

-//

-// ... Prosess one...

-//    SharedMemoryPtr<A> spA("ABC");

-//    if (!spA)

-//      return false;

-//

-//    spA->set_double(3.14);

-//

-//  ... Process two ...

-//

-//

-//    SharedMemoryPtr<A> spA1("ABC");

-//    if (!spA1)

-//      return false;

-//

-//    process two will see the value set by process one.

-//    it will be 3.14

-//    double d = spA1->get_double();

-//

-

-// You should implement a class member of SystemSharedData if the data you want

-// to share is several hundred bytes. Always try this approach first before you implement

-// new class that is derived from SharedMemoryPtr. The main difference is that SharedMemoryPtr

-// will allocate a least page of shared memory. If your class is just a member of SystemSharedData

-// memory mapped file will be shared between members. It is just more efficient.

-// Look in system_shared_data.h , shared_data_member.h, and system_shared_data_members.h

-// for more details.

-

-// Forward declaration.

-template <typename LockType, typename T> class SharedMemoryPtr;

-

-// During several code reviews it has been noticed that the same error gets repeated over and over.

-// People create SharedMemoryPtr<SomeData>. And than the access to member functions of SomeData

-// is not synchronized by __mutexBlock or __mutexScope. So we need to somehow find a way to make

-// automatic syncronization whenever people access shared data methods or  members.

-// Since by design the only way we can acess shared data is through operator -> of SharedMemoryPtr

-// we need to somehow invoke synchronization at the time of access.

-// We can implement this mainly because of the mechanics of operator-> dictated by C++ standard.

-// When you apply operator-> to a type that's not a built-in pointer, the compiler does an interesting thing.

-// After looking up and applying the user-defined operator-> to that type, it applies operator-> again to the result.

-// The compiler keeps doing this recursively until it reaches a pointer to a built-in type, and only then proceeds with member access.

-// It follows that a SharedMemoryPtr<T> operator-> does not have to return a pointer.

-// It can return an object that in turn implements operator->, without changing the use syntax.

-// So we can implement: pre- and postfunction calls. (See Stroustrup 2000)

-// If you return an object of some type X

-// by value from operator->, the sequence of execution is as follows:

-// 1. Constructor of type X

-// 2. X::operator-> called;  returns a pointer to an object of type T of SharedMemoryPtr

-// 3. Member access

-// 4. Destructor of X

-// In a nutshell, we have a  way of implementing locked function calls.

-

-template <typename LockType, typename T>

-class SharedDataLockingProxy {

-public:

-  // Lock on construction.

-  SharedDataLockingProxy(SharedMemoryPtr<LockType, T> * mem_ptr, T* shared_data)

-    : mem_ptr_(mem_ptr), shared_data_(shared_data) {

-      mem_ptr_->Lock();

-    }

-   // Unlock on destruction.

-  ~SharedDataLockingProxy() {

-    mem_ptr_->Unlock();

-  }

-  // operator

-  T* operator->() const  {

-    ASSERT(shared_data_ != NULL, (L"NULL object pointer being dereferenced"));

-    return shared_data_;

-  }

-private:

-  SharedDataLockingProxy& operator=(const SharedDataLockingProxy&);

-  SharedMemoryPtr<LockType, T>* mem_ptr_;

-  T* shared_data_;

-  // To allow this implicit locking - copy constructor must be

-  // enabled. hence, no DISALLOW_EVIL_CONSTRUCTORS

-};

-

-template <typename LockType, typename T> class SharedMemoryPtr

-    : public LockType {

-  // Handle to disk file if we're backing this shared memory by a file

-  HANDLE file_;

-  // Local handle to file mapping.

-  HANDLE file_mapping_;

-  // pointer to a view.

-  T*     data_;

-  // If the first time creation can do some initialization.

-  bool   first_instance_;

-public:

-  // The heart of the whole idea. Points to shared memrory

-  // instead of the beginning of the class.

-  SharedDataLockingProxy<LockType, T> operator->() {

-    return SharedDataLockingProxy<LockType, T>(this, data_);

-  }

-  // To check after creation.

-  // For example:

-  // SharedMemoryPtr<GLock, SomeClass> sm;

-  // if (sm)

-  // { do whatever you want}

-  // else

-  // {error reporting}

-  operator bool() const {return ((file_mapping_ != NULL) && (data_ != NULL));}

-

-  // Initialize memory mapped file and sync mechanics.

-  // by calling InitializeSharedAccess

-  SharedMemoryPtr(const CString& name,

-                  LPSECURITY_ATTRIBUTES sa,

-                  LPSECURITY_ATTRIBUTES sa_mutex,

-                  bool read_only)

-      : file_(INVALID_HANDLE_VALUE),

-        file_mapping_(NULL),

-        data_(NULL) {

-    HRESULT hr = InitializeSharedAccess(name, false, sa, sa_mutex, read_only);

-    if (FAILED(hr)) {

-      UTIL_LOG(LE, (_T("InitializeSharedAccess failed [%s][%s][0x%x]"),

-                    name, read_only ? _T("R") : _T("RW"), hr));

-    }

-  }

-

-  // Use this constructor if you want to back the shared memory by a file.

-  // NOTE: if using a persistent shared memory, every object with this same

-  // name should be persistent. Otherwise, the objects marked as

-  // non-persistent will lead to InitializeSharedData called again if

-  // they are instantiated before the ones marked as persistent.

-  SharedMemoryPtr(bool persist,

-                  LPSECURITY_ATTRIBUTES sa,

-                  LPSECURITY_ATTRIBUTES sa_mutex,

-                  bool read_only)

-      : file_(INVALID_HANDLE_VALUE),

-        file_mapping_(NULL),

-        data_(NULL) {

-    // Each shared data must implement GetFileName() to use this c-tor. The

-    // implementation should be:

-    // const CString GetFileName() const {return L"C:\\directory\file";}

-    // This is purposedly different from GetSharedName, so that the user is

-    // well aware that a file name is expected, not a mutex name.

-    HRESULT hr = InitializeSharedAccess(data_->GetFileName(),

-                                        persist,

-                                        sa,

-                                        sa_mutex,

-                                        read_only);

-    if (FAILED(hr)) {

-      UTIL_LOG(LE, (_T("InitializeSharedAccess failed [%s][%s][0x%x]"),

-                    data_->GetFileName(), read_only ? _T("R") : _T("RW"), hr));

-    }

-  }

-

-  // Initialize memory mapped file and sync mechanics.

-  // by calling InitializeSharedAccess

-  SharedMemoryPtr() :

-      file_(INVALID_HANDLE_VALUE), file_mapping_(NULL), data_(NULL) {

-    // This should never happen but let's assert

-    // in case it does.

-    // Each shared data must implement GetSharedData() to use this c-tor.

-    // The implementation should be:

-    // const TCHAR * GetSharedName() const

-    //     {return L"Some_unique_string_with_no_spaces";}

-    HRESULT hr = InitializeSharedAccess(data_->GetSharedName(),

-                                        false,

-                                        NULL,

-                                        NULL,

-                                        false);

-    if (FAILED(hr)) {

-      UTIL_LOG(LE, (_T("InitializeSharedAccess failed [%s][%s][0x%x]"),

-                    data_->GetSharedName(), _T("RW"), hr));

-    }

-  }

-

-  // Clean up.

-  ~SharedMemoryPtr() {

-    Cleanup();

-  }

-

-  void Cleanup() {

-    __mutexScope(this);

-    if (data_)

-      UnmapViewOfFile(data_);

-    if (file_mapping_)

-      VERIFY(CloseHandle(file_mapping_), (L""));

-    if (file_ != INVALID_HANDLE_VALUE)

-      VERIFY(CloseHandle(file_), (L""));

-  }

-

-  // Initialize memory mapped file and sync object.

-  bool InitializeSharedAccess(const CString& name,

-                              bool persist,

-                              LPSECURITY_ATTRIBUTES sa,

-                              LPSECURITY_ATTRIBUTES sa_mutex,

-                              bool read_only) {

-    return InitializeSharedAccessInternal(name,

-                                          persist,

-                                          sa,

-                                          sa_mutex,

-                                          read_only,

-                                          sizeof(T),

-                                          &T::InitializeSharedData);

-  }

-

- private:

-  // Initialize memory mapped file and sync object.

-  //

-  // This internal method allows template method folding by only using things

-  // that are consistent in all templates.  Things that vary are passed in.

-  bool InitializeSharedAccessInternal(const CString& name, bool persist,

-                                      LPSECURITY_ATTRIBUTES sa,

-                                      LPSECURITY_ATTRIBUTES sa_mutex,

-                                      bool read_only,

-                                      size_t data_size,

-                                      void (T::*initialize_shared_data)

-                                          (const CString&)) {

-    // If this memory mapped object is backed by a file, then "name" is a fully

-    // qualified name with backslashes. Since we can't use backslashes in a

-    // mutex's name, let's make another name where we convert them to

-    // underscores.

-    CString mem_name(name);

-    if (persist) {

-      mem_name.Replace(_T('\\'), _T('_'));

-    }

-

-    // Initialize the mutex

-    CString mutex_name(mem_name + _T("MUTEX"));

-    LPSECURITY_ATTRIBUTES mutex_attr = sa_mutex ? sa_mutex : sa;

-    if (!InitializeWithSecAttr(mutex_name, mutex_attr)) {

-      ASSERT(false, (L"Failed to initialize mutex. Err=%i", ::GetLastError()));

-      return false;

-    }

-

-    // everything is synchronized till the end of the function or return.

-    __mutexScope(this);

-

-    first_instance_ = false;

-

-    if (persist) {

-      // Back this shared memory by a file

-      file_ = CreateFile(name,

-                         GENERIC_READ | (read_only ? 0 : GENERIC_WRITE),

-                         FILE_SHARE_READ | (read_only ? 0 : FILE_SHARE_WRITE),

-                         sa,

-                         OPEN_ALWAYS,

-                         NULL,

-                         NULL);

-      if (file_ == INVALID_HANDLE_VALUE)

-        return false;

-

-      if (!read_only && GetLastError() != ERROR_ALREADY_EXISTS)

-        first_instance_ = true;

-    } else {

-      ASSERT(file_ == INVALID_HANDLE_VALUE, (L""));

-      file_ = INVALID_HANDLE_VALUE;

-    }

-

-    if (read_only) {

-      file_mapping_ = OpenFileMapping(FILE_MAP_READ, false, mem_name);

-      if (!file_mapping_) {

-        UTIL_LOG(LW, (L"[OpenFileMapping failed][error %i]", ::GetLastError()));

-      }

-    } else {

-      file_mapping_ = CreateFileMapping(file_, sa,

-                                        PAGE_READWRITE, 0, data_size, mem_name);

-      ASSERT(file_mapping_, (L"CreateFileMapping. Err=%i", ::GetLastError()));

-    }

-

-    if (!file_mapping_) {

-      return false;

-    } else if (!read_only &&

-               file_ == INVALID_HANDLE_VALUE &&

-               GetLastError() != ERROR_ALREADY_EXISTS) {

-      first_instance_ = true;

-    }

-

-    data_ = reinterpret_cast<T*>(MapViewOfFile(file_mapping_,

-                                               FILE_MAP_READ |

-                                               (read_only ? 0 : FILE_MAP_WRITE),

-                                               0,

-                                               0,

-                                               data_size));

-

-    if (!data_) {

-      ASSERT(false, (L"MapViewOfFile. Err=%i", ::GetLastError()));

-      VERIFY(CloseHandle(file_mapping_), (L""));

-      file_mapping_ = NULL;

-

-      if (file_ != INVALID_HANDLE_VALUE) {

-        VERIFY(CloseHandle(file_), (L""));

-        file_ = INVALID_HANDLE_VALUE;

-      }

-

-      return false;

-    }

-

-    if (!first_instance_) {

-      return true;

-    }

-

-    // If this is the first instance of shared object

-    // call initialization function. This is nice but

-    // at the same time we can not share built in data types.

-    // SharedMemoryPtr<double> - will not compile. But this is OK

-    // We don't want all the overhead to just share couple of bytes.

-    // Signature is void InitializeSharedData()

-    (data_->*initialize_shared_data)(name);

-

-    return true;

-  }

-

-  DISALLOW_EVIL_CONSTRUCTORS(SharedMemoryPtr);

-};

-

-// Sometimes we want Singletons that are shared between processes.

-// SharedMemoryPtr can do that. But if used in C-written module there will be

-// a need to make SharedMemoryPtr a global object. Making a Singleton from SharedMemoryPtr

-// is possible in this situation, but syntactically this is very difficult to read.

-// The following template solves the problem. It hides difficult to read details inside.

-// Usage is the same as SharedMemoryPtr (ONLY through -> operator). Completely thread-safe.

-// Can be used in two ways:

-// Class A {

-//  public:

-//  void foo(){}

-//

-//};

-// SharedMemorySingleton<A> a, b;

-// a->foo();

-// b->foo();  //refers to the same data in any process.

-//

-//  or

-//

-// class A : public SharedMemorySingleton<A> {

-//  public:

-//  void foo(){}

-//};

-//  A a, b;

-//  a->foo();

-//  b->foo(); //refers to the same data in any process.

-

-template <typename LockType, typename T> class SharedMemorySingleton  {

-public:

-  SharedDataLockingProxy<LockType, T> operator->() {

-    return

-      Singleton<SharedMemoryPtr<LockType, T> >::Instance()->operator->();

-  }

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SHARED_MEMORY_PTR_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines template class used to share data
+// between processes.
+//
+
+#ifndef OMAHA_COMMON_SHARED_MEMORY_PTR_H__
+#define OMAHA_COMMON_SHARED_MEMORY_PTR_H__
+
+#include "common/debug.h"
+#include "common/singleton.h"
+#include "common/system_info.h"
+#include "common/vista_utils.h"
+
+namespace omaha {
+
+// SharedMemoryPtr class is designed to allow seamless data sharing process boundaries.
+// All the data passed as a template parameter will be shared between processes.
+// Very important to remember that for now - all shared data should be on stack.
+// For example if the class A had stl vector as a member, the members of the vector
+// would be allocated not from shared memory and therefore will not be shared.
+// That could be solved with allocators, but for now we don't need that.
+//
+// Here is a typical example of usage:
+//   Class A {
+//    int i_;
+//    double d_;
+//    .......
+//    ........
+//
+//    public:
+//    set_double(double d){d_=d;}
+//    double get_double(){return d_};
+//
+// };
+//
+// ... Prosess one...
+//    SharedMemoryPtr<A> spA("ABC");
+//    if (!spA)
+//      return false;
+//
+//    spA->set_double(3.14);
+//
+//  ... Process two ...
+//
+//
+//    SharedMemoryPtr<A> spA1("ABC");
+//    if (!spA1)
+//      return false;
+//
+//    process two will see the value set by process one.
+//    it will be 3.14
+//    double d = spA1->get_double();
+//
+
+// You should implement a class member of SystemSharedData if the data you want
+// to share is several hundred bytes. Always try this approach first before you implement
+// new class that is derived from SharedMemoryPtr. The main difference is that SharedMemoryPtr
+// will allocate a least page of shared memory. If your class is just a member of SystemSharedData
+// memory mapped file will be shared between members. It is just more efficient.
+// Look in system_shared_data.h , shared_data_member.h, and system_shared_data_members.h
+// for more details.
+
+// Forward declaration.
+template <typename LockType, typename T> class SharedMemoryPtr;
+
+// During several code reviews it has been noticed that the same error gets repeated over and over.
+// People create SharedMemoryPtr<SomeData>. And than the access to member functions of SomeData
+// is not synchronized by __mutexBlock or __mutexScope. So we need to somehow find a way to make
+// automatic syncronization whenever people access shared data methods or  members.
+// Since by design the only way we can acess shared data is through operator -> of SharedMemoryPtr
+// we need to somehow invoke synchronization at the time of access.
+// We can implement this mainly because of the mechanics of operator-> dictated by C++ standard.
+// When you apply operator-> to a type that's not a built-in pointer, the compiler does an interesting thing.
+// After looking up and applying the user-defined operator-> to that type, it applies operator-> again to the result.
+// The compiler keeps doing this recursively until it reaches a pointer to a built-in type, and only then proceeds with member access.
+// It follows that a SharedMemoryPtr<T> operator-> does not have to return a pointer.
+// It can return an object that in turn implements operator->, without changing the use syntax.
+// So we can implement: pre- and postfunction calls. (See Stroustrup 2000)
+// If you return an object of some type X
+// by value from operator->, the sequence of execution is as follows:
+// 1. Constructor of type X
+// 2. X::operator-> called;  returns a pointer to an object of type T of SharedMemoryPtr
+// 3. Member access
+// 4. Destructor of X
+// In a nutshell, we have a  way of implementing locked function calls.
+
+template <typename LockType, typename T>
+class SharedDataLockingProxy {
+public:
+  // Lock on construction.
+  SharedDataLockingProxy(SharedMemoryPtr<LockType, T> * mem_ptr, T* shared_data)
+    : mem_ptr_(mem_ptr), shared_data_(shared_data) {
+      mem_ptr_->Lock();
+    }
+   // Unlock on destruction.
+  ~SharedDataLockingProxy() {
+    mem_ptr_->Unlock();
+  }
+  // operator
+  T* operator->() const  {
+    ASSERT(shared_data_ != NULL, (L"NULL object pointer being dereferenced"));
+    return shared_data_;
+  }
+private:
+  SharedDataLockingProxy& operator=(const SharedDataLockingProxy&);
+  SharedMemoryPtr<LockType, T>* mem_ptr_;
+  T* shared_data_;
+  // To allow this implicit locking - copy constructor must be
+  // enabled. hence, no DISALLOW_EVIL_CONSTRUCTORS
+};
+
+template <typename LockType, typename T> class SharedMemoryPtr
+    : public LockType {
+  // Handle to disk file if we're backing this shared memory by a file
+  HANDLE file_;
+  // Local handle to file mapping.
+  HANDLE file_mapping_;
+  // pointer to a view.
+  T*     data_;
+  // If the first time creation can do some initialization.
+  bool   first_instance_;
+public:
+  // The heart of the whole idea. Points to shared memrory
+  // instead of the beginning of the class.
+  SharedDataLockingProxy<LockType, T> operator->() {
+    return SharedDataLockingProxy<LockType, T>(this, data_);
+  }
+  // To check after creation.
+  // For example:
+  // SharedMemoryPtr<GLock, SomeClass> sm;
+  // if (sm)
+  // { do whatever you want}
+  // else
+  // {error reporting}
+  operator bool() const {return ((file_mapping_ != NULL) && (data_ != NULL));}
+
+  // Initialize memory mapped file and sync mechanics.
+  // by calling InitializeSharedAccess
+  SharedMemoryPtr(const CString& name,
+                  LPSECURITY_ATTRIBUTES sa,
+                  LPSECURITY_ATTRIBUTES sa_mutex,
+                  bool read_only)
+      : file_(INVALID_HANDLE_VALUE),
+        file_mapping_(NULL),
+        data_(NULL) {
+    HRESULT hr = InitializeSharedAccess(name, false, sa, sa_mutex, read_only);
+    if (FAILED(hr)) {
+      UTIL_LOG(LE, (_T("InitializeSharedAccess failed [%s][%s][0x%x]"),
+                    name, read_only ? _T("R") : _T("RW"), hr));
+    }
+  }
+
+  // Use this constructor if you want to back the shared memory by a file.
+  // NOTE: if using a persistent shared memory, every object with this same
+  // name should be persistent. Otherwise, the objects marked as
+  // non-persistent will lead to InitializeSharedData called again if
+  // they are instantiated before the ones marked as persistent.
+  SharedMemoryPtr(bool persist,
+                  LPSECURITY_ATTRIBUTES sa,
+                  LPSECURITY_ATTRIBUTES sa_mutex,
+                  bool read_only)
+      : file_(INVALID_HANDLE_VALUE),
+        file_mapping_(NULL),
+        data_(NULL) {
+    // Each shared data must implement GetFileName() to use this c-tor. The
+    // implementation should be:
+    // const CString GetFileName() const {return L"C:\\directory\file";}
+    // This is purposedly different from GetSharedName, so that the user is
+    // well aware that a file name is expected, not a mutex name.
+    HRESULT hr = InitializeSharedAccess(data_->GetFileName(),
+                                        persist,
+                                        sa,
+                                        sa_mutex,
+                                        read_only);
+    if (FAILED(hr)) {
+      UTIL_LOG(LE, (_T("InitializeSharedAccess failed [%s][%s][0x%x]"),
+                    data_->GetFileName(), read_only ? _T("R") : _T("RW"), hr));
+    }
+  }
+
+  // Initialize memory mapped file and sync mechanics.
+  // by calling InitializeSharedAccess
+  SharedMemoryPtr() :
+      file_(INVALID_HANDLE_VALUE), file_mapping_(NULL), data_(NULL) {
+    // This should never happen but let's assert
+    // in case it does.
+    // Each shared data must implement GetSharedData() to use this c-tor.
+    // The implementation should be:
+    // const TCHAR * GetSharedName() const
+    //     {return L"Some_unique_string_with_no_spaces";}
+    HRESULT hr = InitializeSharedAccess(data_->GetSharedName(),
+                                        false,
+                                        NULL,
+                                        NULL,
+                                        false);
+    if (FAILED(hr)) {
+      UTIL_LOG(LE, (_T("InitializeSharedAccess failed [%s][%s][0x%x]"),
+                    data_->GetSharedName(), _T("RW"), hr));
+    }
+  }
+
+  // Clean up.
+  ~SharedMemoryPtr() {
+    Cleanup();
+  }
+
+  void Cleanup() {
+    __mutexScope(this);
+    if (data_)
+      UnmapViewOfFile(data_);
+    if (file_mapping_)
+      VERIFY(CloseHandle(file_mapping_), (L""));
+    if (file_ != INVALID_HANDLE_VALUE)
+      VERIFY(CloseHandle(file_), (L""));
+  }
+
+  // Initialize memory mapped file and sync object.
+  bool InitializeSharedAccess(const CString& name,
+                              bool persist,
+                              LPSECURITY_ATTRIBUTES sa,
+                              LPSECURITY_ATTRIBUTES sa_mutex,
+                              bool read_only) {
+    return InitializeSharedAccessInternal(name,
+                                          persist,
+                                          sa,
+                                          sa_mutex,
+                                          read_only,
+                                          sizeof(T),
+                                          &T::InitializeSharedData);
+  }
+
+ private:
+  // Initialize memory mapped file and sync object.
+  //
+  // This internal method allows template method folding by only using things
+  // that are consistent in all templates.  Things that vary are passed in.
+  bool InitializeSharedAccessInternal(const CString& name, bool persist,
+                                      LPSECURITY_ATTRIBUTES sa,
+                                      LPSECURITY_ATTRIBUTES sa_mutex,
+                                      bool read_only,
+                                      size_t data_size,
+                                      void (T::*initialize_shared_data)
+                                          (const CString&)) {
+    // If this memory mapped object is backed by a file, then "name" is a fully
+    // qualified name with backslashes. Since we can't use backslashes in a
+    // mutex's name, let's make another name where we convert them to
+    // underscores.
+    CString mem_name(name);
+    if (persist) {
+      mem_name.Replace(_T('\\'), _T('_'));
+    }
+
+    // Initialize the mutex
+    CString mutex_name(mem_name + _T("MUTEX"));
+    LPSECURITY_ATTRIBUTES mutex_attr = sa_mutex ? sa_mutex : sa;
+    if (!InitializeWithSecAttr(mutex_name, mutex_attr)) {
+      ASSERT(false, (L"Failed to initialize mutex. Err=%i", ::GetLastError()));
+      return false;
+    }
+
+    // everything is synchronized till the end of the function or return.
+    __mutexScope(this);
+
+    first_instance_ = false;
+
+    if (persist) {
+      // Back this shared memory by a file
+      file_ = CreateFile(name,
+                         GENERIC_READ | (read_only ? 0 : GENERIC_WRITE),
+                         FILE_SHARE_READ | (read_only ? 0 : FILE_SHARE_WRITE),
+                         sa,
+                         OPEN_ALWAYS,
+                         NULL,
+                         NULL);
+      if (file_ == INVALID_HANDLE_VALUE)
+        return false;
+
+      if (!read_only && GetLastError() != ERROR_ALREADY_EXISTS)
+        first_instance_ = true;
+    } else {
+      ASSERT(file_ == INVALID_HANDLE_VALUE, (L""));
+      file_ = INVALID_HANDLE_VALUE;
+    }
+
+    if (read_only) {
+      file_mapping_ = OpenFileMapping(FILE_MAP_READ, false, mem_name);
+      if (!file_mapping_) {
+        UTIL_LOG(LW, (L"[OpenFileMapping failed][error %i]", ::GetLastError()));
+      }
+    } else {
+      file_mapping_ = CreateFileMapping(file_, sa,
+                                        PAGE_READWRITE, 0, data_size, mem_name);
+      ASSERT(file_mapping_, (L"CreateFileMapping. Err=%i", ::GetLastError()));
+    }
+
+    if (!file_mapping_) {
+      return false;
+    } else if (!read_only &&
+               file_ == INVALID_HANDLE_VALUE &&
+               GetLastError() != ERROR_ALREADY_EXISTS) {
+      first_instance_ = true;
+    }
+
+    data_ = reinterpret_cast<T*>(MapViewOfFile(file_mapping_,
+                                               FILE_MAP_READ |
+                                               (read_only ? 0 : FILE_MAP_WRITE),
+                                               0,
+                                               0,
+                                               data_size));
+
+    if (!data_) {
+      ASSERT(false, (L"MapViewOfFile. Err=%i", ::GetLastError()));
+      VERIFY(CloseHandle(file_mapping_), (L""));
+      file_mapping_ = NULL;
+
+      if (file_ != INVALID_HANDLE_VALUE) {
+        VERIFY(CloseHandle(file_), (L""));
+        file_ = INVALID_HANDLE_VALUE;
+      }
+
+      return false;
+    }
+
+    if (!first_instance_) {
+      return true;
+    }
+
+    // If this is the first instance of shared object
+    // call initialization function. This is nice but
+    // at the same time we can not share built in data types.
+    // SharedMemoryPtr<double> - will not compile. But this is OK
+    // We don't want all the overhead to just share couple of bytes.
+    // Signature is void InitializeSharedData()
+    (data_->*initialize_shared_data)(name);
+
+    return true;
+  }
+
+  DISALLOW_EVIL_CONSTRUCTORS(SharedMemoryPtr);
+};
+
+// Sometimes we want Singletons that are shared between processes.
+// SharedMemoryPtr can do that. But if used in C-written module there will be
+// a need to make SharedMemoryPtr a global object. Making a Singleton from SharedMemoryPtr
+// is possible in this situation, but syntactically this is very difficult to read.
+// The following template solves the problem. It hides difficult to read details inside.
+// Usage is the same as SharedMemoryPtr (ONLY through -> operator). Completely thread-safe.
+// Can be used in two ways:
+// Class A {
+//  public:
+//  void foo(){}
+//
+//};
+// SharedMemorySingleton<A> a, b;
+// a->foo();
+// b->foo();  //refers to the same data in any process.
+//
+//  or
+//
+// class A : public SharedMemorySingleton<A> {
+//  public:
+//  void foo(){}
+//};
+//  A a, b;
+//  a->foo();
+//  b->foo(); //refers to the same data in any process.
+
+template <typename LockType, typename T> class SharedMemorySingleton  {
+public:
+  SharedDataLockingProxy<LockType, T> operator->() {
+    return
+      Singleton<SharedMemoryPtr<LockType, T> >::Instance()->operator->();
+  }
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SHARED_MEMORY_PTR_H__
diff --git a/common/shell.cc b/common/shell.cc
index 6e71d1a..32b76b4 100644
--- a/common/shell.cc
+++ b/common/shell.cc
@@ -1,398 +1,398 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Shell functions

-

-#include "omaha/common/shell.h"

-

-#include <shlobj.h>

-#include <shellapi.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/commands.h"

-#include "omaha/common/const_utils.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-// create and store a shortcut

-// uses shell IShellLink and IPersistFile interfaces

-HRESULT Shell::CreateLink(const TCHAR *source,

-                          const TCHAR *destination,

-                          const TCHAR *working_dir,

-                          const TCHAR *arguments,

-                          const TCHAR *description,

-                          WORD hotkey_virtual_key_code,

-                          WORD hotkey_modifiers,

-                          const TCHAR *icon) {

-  ASSERT1(source);

-  ASSERT1(destination);

-  ASSERT1(working_dir);

-  ASSERT1(arguments);

-  ASSERT1(description);

-

-  scoped_co_init co_init(COINIT_APARTMENTTHREADED);

-  HRESULT hr = co_init.hresult();

-  if (FAILED(hr) && hr != RPC_E_CHANGED_MODE) {

-    UTIL_LOG(LEVEL_ERROR, (_T("[Shell::CreateLink - failed to co_init]"), hr));

-    return hr;

-  }

-

-  UTIL_LOG(L1, (_T("[Create shell link]")

-                _T("[source %s dest %s dir %s arg %s desc %s hotkey %x:%x]"),

-                source, destination, working_dir, arguments, description,

-                hotkey_modifiers, hotkey_virtual_key_code));

-

-  // Get a pointer to the IShellLink interface

-  CComPtr<IShellLink> shell_link;

-

-  RET_IF_FAILED(shell_link.CoCreateInstance(CLSID_ShellLink));

-  ASSERT(shell_link, (L""));

-

-  // Set the path to the shortcut target and add the description

-  VERIFY1(SUCCEEDED(shell_link->SetPath(source)));

-  VERIFY1(SUCCEEDED(shell_link->SetArguments(arguments)));

-  VERIFY1(SUCCEEDED(shell_link->SetDescription(description)));

-  VERIFY1(SUCCEEDED(shell_link->SetWorkingDirectory(working_dir)));

-

-  // If we are given an icon, then set it

-  // For now, we always use the first icon if this happens to have multiple ones

-  if (icon) {

-    VERIFY1(SUCCEEDED(shell_link->SetIconLocation(icon, 0)));

-  }

-

-// C4201: nonstandard extension used : nameless struct/union

-#pragma warning(disable : 4201)

-  union {

-    WORD flags;

-    struct {                  // little-endian machine:

-      WORD virtual_key:8;     // low order byte

-      WORD modifiers:8;       // high order byte

-    };

-  } hot_key;

-#pragma warning(default : 4201)

-

-  hot_key.virtual_key = hotkey_virtual_key_code;

-  hot_key.modifiers = hotkey_modifiers;

-

-  if (hot_key.flags) {

-    shell_link->SetHotkey(hot_key.flags);

-  }

-

-  // Query IShellLink for the IPersistFile interface for saving the shortcut in

-  // persistent storage

-  CComQIPtr<IPersistFile> persist_file(shell_link);

-  if (!persist_file)

-    return E_FAIL;

-

-  // Save the link by calling IPersistFile::Save

-  RET_IF_FAILED(persist_file->Save(destination, TRUE));

-

-  return S_OK;

-}

-

-HRESULT Shell::RemoveLink(const TCHAR *link) {

-  ASSERT(link, (L""));

-  ASSERT(*link, (L""));

-

-  return File::Remove(link);

-}

-

-// Open a URL in a new browser window

-HRESULT Shell::OpenLinkInNewWindow(const TCHAR* url, UseBrowser use_browser) {

-  ASSERT1(url);

-

-  HRESULT hr = S_OK;

-  CString browser_path;

-

-  // Try to open with default browser

-  if (use_browser == USE_DEFAULT_BROWSER) {

-    // Load full browser path from regkey

-    hr = GetDefaultBrowserPath(&browser_path);

-

-    // If there is a default browser and it is not AOL, load the url in that

-    // browser

-    if (SUCCEEDED(hr) && !String_Contains(browser_path, _T("aol"))) {

-      if (!browser_path.IsEmpty()) {

-        // Have we figured out how to append the URL onto the browser path?

-        bool acceptable_url = false;

-

-        if (ReplaceCString(browser_path, _T("\"%1\""), url)) {

-          // the "browser.exe "%1"" case

-          acceptable_url = true;

-        } else if (ReplaceCString(browser_path, _T("%1"), url)) {

-          // the "browser.exe %1 "case

-          acceptable_url = true;

-        } else if (ReplaceCString(browser_path, _T("-nohome"), url)) {

-          // the "browser.exe -nohome" case

-          acceptable_url = true;

-        } else {

-          // the browser.exe case.

-          // simply append the quoted url.

-          EnclosePath(&browser_path);

-          browser_path.AppendChar(_T(' '));

-          CString quoted_url(url);

-          EnclosePath(&quoted_url);

-          browser_path.Append(quoted_url);

-          acceptable_url = true;

-        }

-

-        if (acceptable_url) {

-          hr = System::ShellExecuteCommandLine(browser_path, NULL, NULL);

-          if (SUCCEEDED(hr)) {

-            return S_OK;

-          } else {

-            UTIL_LOG(LE, (_T("[Shell::OpenLinkInNewWindow]")

-                          _T("[failed to start default browser to open url]")

-                          _T("[%s][0x%x]"), url, hr));

-          }

-        }

-      }

-    }

-  }

-

-  // Try to open with IE if can't open with default browser or required

-  if (use_browser == USE_DEFAULT_BROWSER ||

-      use_browser == USE_INTERNET_EXPLORER) {

-    hr = RegKey::GetValue(kRegKeyIeClass, kRegValueIeClass, &browser_path);

-    if (SUCCEEDED(hr)) {

-      hr = System::ShellExecuteProcess(browser_path, url, NULL, NULL);

-      if (SUCCEEDED(hr)) {

-        return S_OK;

-      } else {

-        UTIL_LOG(LE, (_T("[Shell::OpenLinkInNewWindow]")

-                      _T("[failed to start IE to open url][%s][0x%x]"),

-                      url, hr));

-      }

-    }

-  }

-

-  // Try to open with Firefox if can't open with default browser or required

-  if (use_browser == USE_DEFAULT_BROWSER || use_browser == USE_FIREFOX) {

-    hr = RegKey::GetValue(kRegKeyFirefox, kRegValueFirefox, &browser_path);

-    if (SUCCEEDED(hr) && !browser_path.IsEmpty()) {

-      ReplaceCString(browser_path, _T("%1"), url);

-      hr = System::ShellExecuteCommandLine(browser_path, NULL, NULL);

-      if (SUCCEEDED(hr)) {

-        return S_OK;

-      } else {

-        UTIL_LOG(LE, (_T("[Shell::OpenLinkInNewWindow]")

-                      _T("[failed to start Firefox to open url][%s][0x%x]"),

-                      url, hr));

-      }

-    }

-  }

-

-  // ShellExecute the url directly as a last resort

-  hr = Shell::Execute(url);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[Shell::OpenLinkInNewWindow]")

-                  _T("[failed to run ShellExecute to open url][%s][0x%x]"),

-                  url, hr));

-  }

-

-  return hr;

-}

-

-HRESULT Shell::Execute(const TCHAR* file) {

-  ASSERT1(file);

-

-  // Prepare everything required for ::ShellExecuteEx().

-  SHELLEXECUTEINFO sei;

-  SetZero(sei);

-  sei.cbSize = sizeof(sei);

-  sei.fMask = SEE_MASK_FLAG_NO_UI     |  // Do not display an error message box.

-              SEE_MASK_NOZONECHECKS   |  // Do not perform a zone check.

-              SEE_MASK_NOASYNC;          // Wait to complete before returning.

-  // Pass NULL for hwnd. This will have ShellExecuteExEnsureParent()

-  // create a dummy parent window for us.

-  // sei.hwnd = NULL;

-  sei.lpVerb = _T("open");

-  sei.lpFile = file;

-  // No parameters to pass

-  // sei.lpParameters = NULL;

-  // Use parent's starting directory

-  // sei.lpDirectory = NULL;

-  sei.nShow = SW_SHOWNORMAL;

-

-  // Use ShellExecuteExEnsureParent to ensure that we always have a parent HWND.

-  // We need to use the HWND Property to be acknowledged as a Foreground

-  // Application on Vista. Otherwise, the elevation prompt will appear minimized

-  // on the taskbar.

-  if (!ShellExecuteExEnsureParent(&sei)) {

-    HRESULT hr(HRESULTFromLastError());

-    ASSERT(false,

-        (_T("Shell::Execute - ShellExecuteEx failed][%s][0x%x]"), file, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT Shell::BasicGetSpecialFolder(DWORD csidl, CString* folder_path) {

-  ASSERT1(folder_path);

-

-  // Get a ITEMIDLIST* (called a PIDL in the MSDN documentation) to the

-  // special folder

-  scoped_any<ITEMIDLIST*, close_co_task_free> folder_location;

-  RET_IF_FAILED(::SHGetFolderLocation(NULL,

-                                      csidl,

-                                      NULL,

-                                      0,

-                                      address(folder_location)));

-  ASSERT(get(folder_location), (_T("")));

-

-  // Get an interface to the Desktop folder

-  CComPtr<IShellFolder> desktop_folder;

-  RET_IF_FAILED(::SHGetDesktopFolder(&desktop_folder));

-  ASSERT1(desktop_folder);

-

-  // Ask the desktop for the display name of the special folder

-  STRRET str_return;

-  SetZero(str_return);

-  str_return.uType = STRRET_WSTR;

-  RET_IF_FAILED(desktop_folder->GetDisplayNameOf(get(folder_location),

-                                                 SHGDN_FORPARSING,

-                                                 &str_return));

-

-  // Get the display name of the special folder and return it

-  scoped_any<wchar_t*, close_co_task_free> folder_name;

-  RET_IF_FAILED(::StrRetToStr(&str_return,

-                              get(folder_location),

-                              address(folder_name)));

-  *folder_path = get(folder_name);

-

-  return S_OK;

-}

-

-HRESULT Shell::GetSpecialFolder(DWORD csidl,

-                                bool create_if_missing,

-                                CString* folder_path) {

-  ASSERT(folder_path, (L""));

-

-  HRESULT hr = Shell::BasicGetSpecialFolder(csidl, folder_path);

-

-  // If the folder does not exist, ::SHGetFolderLocation may return error

-  // code ERROR_FILE_NOT_FOUND.

-  if (create_if_missing) {

-    if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||

-        (SUCCEEDED(hr) && !File::Exists(*folder_path))) {

-      hr = Shell::BasicGetSpecialFolder(csidl | CSIDL_FLAG_CREATE, folder_path);

-    }

-  }

-  ASSERT(FAILED(hr) || File::Exists(*folder_path), (_T("")));

-

-  return hr;

-}

-

-#pragma warning(disable : 4510 4610)

-// C4510: default constructor could not be generated

-// C4610: struct can never be instantiated - user defined constructor required

-struct {

-  const TCHAR* name;

-  const DWORD csidl;

-} const folder_mappings[] = {

-  L"APPDATA",            CSIDL_APPDATA,

-  L"DESKTOP",            CSIDL_DESKTOPDIRECTORY,

-  L"LOCALAPPDATA",       CSIDL_LOCAL_APPDATA,

-  L"MYMUSIC",            CSIDL_MYMUSIC,

-  L"MYPICTURES",         CSIDL_MYPICTURES,

-  L"PROGRAMFILES",       CSIDL_PROGRAM_FILES,

-  L"PROGRAMFILESCOMMON", CSIDL_PROGRAM_FILES_COMMON,

-  L"PROGRAMS",           CSIDL_PROGRAMS,

-  L"STARTMENU",          CSIDL_STARTMENU,

-  L"STARTUP",            CSIDL_STARTUP,

-  L"SYSTEM",             CSIDL_SYSTEM,

-  L"WINDOWS",            CSIDL_WINDOWS,

-};

-#pragma warning(default : 4510 4610)

-

-HRESULT Shell::GetSpecialFolderKeywordsMapping(

-    std::map<CString, CString>* special_folders_map) {

-  ASSERT1(special_folders_map);

-

-  special_folders_map->clear();

-

-  for (size_t i = 0; i < arraysize(folder_mappings); ++i) {

-    CString name(folder_mappings[i].name);

-    DWORD csidl(folder_mappings[i].csidl);

-    CString folder;

-    HRESULT hr = GetSpecialFolder(csidl, false, &folder);

-    if (FAILED(hr)) {

-      UTIL_LOG(LE, (_T("[Shell::GetSpecialFolderKeywordsMapping]")

-                    _T("[failed to retrieve %s]"), name));

-      continue;

-    }

-    special_folders_map->insert(std::make_pair(name, folder));

-  }

-

-  // Get the current module directory

-  CString module_dir = app_util::GetModuleDirectory(::GetModuleHandle(NULL));

-  ASSERT1(module_dir.GetLength() > 0);

-  special_folders_map->insert(std::make_pair(_T("CURRENTMODULEDIR"),

-                                             module_dir));

-

-  return S_OK;

-}

-

-HRESULT Shell::DeleteDirectory(const TCHAR* dir) {

-  ASSERT1(dir && *dir);

-

-  if (!SafeDirectoryNameForDeletion(dir)) {

-    return E_INVALIDARG;

-  }

-

-  uint32 dir_len = lstrlen(dir);

-  if (dir_len >= MAX_PATH) {

-    return E_INVALIDARG;

-  }

-

-  // the 'from' must be double-terminated with 0. Reserve space for one more

-  // zero at the end

-  TCHAR from[MAX_PATH + 1] = {0};

-  lstrcpyn(from, dir, MAX_PATH);

-  from[1 + dir_len] = 0;    // the second zero terminator.

-

-  SHFILEOPSTRUCT file_op = {0};

-

-  file_op.hwnd   = 0;

-  file_op.wFunc  = FO_DELETE;

-  file_op.pFrom  = from;

-  file_op.pTo    = 0;

-  file_op.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;

-

-  // ::SHFileOperation returns non-zero on errors

-  return ::SHFileOperation(&file_op) ? HRESULTFromLastError() : S_OK;

-}

-

-HRESULT Shell::GetApplicationExecutablePath(const CString& exe,

-                                            CString* path) {

-  ASSERT1(path);

-

-  CString reg_key_name = AppendRegKeyPath(kRegKeyApplicationPath, exe);

-  return RegKey::GetValue(reg_key_name, kRegKeyPathValue, path);

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Shell functions
+
+#include "omaha/common/shell.h"
+
+#include <shlobj.h>
+#include <shellapi.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/commands.h"
+#include "omaha/common/const_utils.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+// create and store a shortcut
+// uses shell IShellLink and IPersistFile interfaces
+HRESULT Shell::CreateLink(const TCHAR *source,
+                          const TCHAR *destination,
+                          const TCHAR *working_dir,
+                          const TCHAR *arguments,
+                          const TCHAR *description,
+                          WORD hotkey_virtual_key_code,
+                          WORD hotkey_modifiers,
+                          const TCHAR *icon) {
+  ASSERT1(source);
+  ASSERT1(destination);
+  ASSERT1(working_dir);
+  ASSERT1(arguments);
+  ASSERT1(description);
+
+  scoped_co_init co_init(COINIT_APARTMENTTHREADED);
+  HRESULT hr = co_init.hresult();
+  if (FAILED(hr) && hr != RPC_E_CHANGED_MODE) {
+    UTIL_LOG(LEVEL_ERROR, (_T("[Shell::CreateLink - failed to co_init]"), hr));
+    return hr;
+  }
+
+  UTIL_LOG(L1, (_T("[Create shell link]")
+                _T("[source %s dest %s dir %s arg %s desc %s hotkey %x:%x]"),
+                source, destination, working_dir, arguments, description,
+                hotkey_modifiers, hotkey_virtual_key_code));
+
+  // Get a pointer to the IShellLink interface
+  CComPtr<IShellLink> shell_link;
+
+  RET_IF_FAILED(shell_link.CoCreateInstance(CLSID_ShellLink));
+  ASSERT(shell_link, (L""));
+
+  // Set the path to the shortcut target and add the description
+  VERIFY1(SUCCEEDED(shell_link->SetPath(source)));
+  VERIFY1(SUCCEEDED(shell_link->SetArguments(arguments)));
+  VERIFY1(SUCCEEDED(shell_link->SetDescription(description)));
+  VERIFY1(SUCCEEDED(shell_link->SetWorkingDirectory(working_dir)));
+
+  // If we are given an icon, then set it
+  // For now, we always use the first icon if this happens to have multiple ones
+  if (icon) {
+    VERIFY1(SUCCEEDED(shell_link->SetIconLocation(icon, 0)));
+  }
+
+// C4201: nonstandard extension used : nameless struct/union
+#pragma warning(disable : 4201)
+  union {
+    WORD flags;
+    struct {                  // little-endian machine:
+      WORD virtual_key:8;     // low order byte
+      WORD modifiers:8;       // high order byte
+    };
+  } hot_key;
+#pragma warning(default : 4201)
+
+  hot_key.virtual_key = hotkey_virtual_key_code;
+  hot_key.modifiers = hotkey_modifiers;
+
+  if (hot_key.flags) {
+    shell_link->SetHotkey(hot_key.flags);
+  }
+
+  // Query IShellLink for the IPersistFile interface for saving the shortcut in
+  // persistent storage
+  CComQIPtr<IPersistFile> persist_file(shell_link);
+  if (!persist_file)
+    return E_FAIL;
+
+  // Save the link by calling IPersistFile::Save
+  RET_IF_FAILED(persist_file->Save(destination, TRUE));
+
+  return S_OK;
+}
+
+HRESULT Shell::RemoveLink(const TCHAR *link) {
+  ASSERT(link, (L""));
+  ASSERT(*link, (L""));
+
+  return File::Remove(link);
+}
+
+// Open a URL in a new browser window
+HRESULT Shell::OpenLinkInNewWindow(const TCHAR* url, UseBrowser use_browser) {
+  ASSERT1(url);
+
+  HRESULT hr = S_OK;
+  CString browser_path;
+
+  // Try to open with default browser
+  if (use_browser == USE_DEFAULT_BROWSER) {
+    // Load full browser path from regkey
+    hr = GetDefaultBrowserPath(&browser_path);
+
+    // If there is a default browser and it is not AOL, load the url in that
+    // browser
+    if (SUCCEEDED(hr) && !String_Contains(browser_path, _T("aol"))) {
+      if (!browser_path.IsEmpty()) {
+        // Have we figured out how to append the URL onto the browser path?
+        bool acceptable_url = false;
+
+        if (ReplaceCString(browser_path, _T("\"%1\""), url)) {
+          // the "browser.exe "%1"" case
+          acceptable_url = true;
+        } else if (ReplaceCString(browser_path, _T("%1"), url)) {
+          // the "browser.exe %1 "case
+          acceptable_url = true;
+        } else if (ReplaceCString(browser_path, _T("-nohome"), url)) {
+          // the "browser.exe -nohome" case
+          acceptable_url = true;
+        } else {
+          // the browser.exe case.
+          // simply append the quoted url.
+          EnclosePath(&browser_path);
+          browser_path.AppendChar(_T(' '));
+          CString quoted_url(url);
+          EnclosePath(&quoted_url);
+          browser_path.Append(quoted_url);
+          acceptable_url = true;
+        }
+
+        if (acceptable_url) {
+          hr = System::ShellExecuteCommandLine(browser_path, NULL, NULL);
+          if (SUCCEEDED(hr)) {
+            return S_OK;
+          } else {
+            UTIL_LOG(LE, (_T("[Shell::OpenLinkInNewWindow]")
+                          _T("[failed to start default browser to open url]")
+                          _T("[%s][0x%x]"), url, hr));
+          }
+        }
+      }
+    }
+  }
+
+  // Try to open with IE if can't open with default browser or required
+  if (use_browser == USE_DEFAULT_BROWSER ||
+      use_browser == USE_INTERNET_EXPLORER) {
+    hr = RegKey::GetValue(kRegKeyIeClass, kRegValueIeClass, &browser_path);
+    if (SUCCEEDED(hr)) {
+      hr = System::ShellExecuteProcess(browser_path, url, NULL, NULL);
+      if (SUCCEEDED(hr)) {
+        return S_OK;
+      } else {
+        UTIL_LOG(LE, (_T("[Shell::OpenLinkInNewWindow]")
+                      _T("[failed to start IE to open url][%s][0x%x]"),
+                      url, hr));
+      }
+    }
+  }
+
+  // Try to open with Firefox if can't open with default browser or required
+  if (use_browser == USE_DEFAULT_BROWSER || use_browser == USE_FIREFOX) {
+    hr = RegKey::GetValue(kRegKeyFirefox, kRegValueFirefox, &browser_path);
+    if (SUCCEEDED(hr) && !browser_path.IsEmpty()) {
+      ReplaceCString(browser_path, _T("%1"), url);
+      hr = System::ShellExecuteCommandLine(browser_path, NULL, NULL);
+      if (SUCCEEDED(hr)) {
+        return S_OK;
+      } else {
+        UTIL_LOG(LE, (_T("[Shell::OpenLinkInNewWindow]")
+                      _T("[failed to start Firefox to open url][%s][0x%x]"),
+                      url, hr));
+      }
+    }
+  }
+
+  // ShellExecute the url directly as a last resort
+  hr = Shell::Execute(url);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[Shell::OpenLinkInNewWindow]")
+                  _T("[failed to run ShellExecute to open url][%s][0x%x]"),
+                  url, hr));
+  }
+
+  return hr;
+}
+
+HRESULT Shell::Execute(const TCHAR* file) {
+  ASSERT1(file);
+
+  // Prepare everything required for ::ShellExecuteEx().
+  SHELLEXECUTEINFO sei;
+  SetZero(sei);
+  sei.cbSize = sizeof(sei);
+  sei.fMask = SEE_MASK_FLAG_NO_UI     |  // Do not display an error message box.
+              SEE_MASK_NOZONECHECKS   |  // Do not perform a zone check.
+              SEE_MASK_NOASYNC;          // Wait to complete before returning.
+  // Pass NULL for hwnd. This will have ShellExecuteExEnsureParent()
+  // create a dummy parent window for us.
+  // sei.hwnd = NULL;
+  sei.lpVerb = _T("open");
+  sei.lpFile = file;
+  // No parameters to pass
+  // sei.lpParameters = NULL;
+  // Use parent's starting directory
+  // sei.lpDirectory = NULL;
+  sei.nShow = SW_SHOWNORMAL;
+
+  // Use ShellExecuteExEnsureParent to ensure that we always have a parent HWND.
+  // We need to use the HWND Property to be acknowledged as a Foreground
+  // Application on Vista. Otherwise, the elevation prompt will appear minimized
+  // on the taskbar.
+  if (!ShellExecuteExEnsureParent(&sei)) {
+    HRESULT hr(HRESULTFromLastError());
+    ASSERT(false,
+        (_T("Shell::Execute - ShellExecuteEx failed][%s][0x%x]"), file, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT Shell::BasicGetSpecialFolder(DWORD csidl, CString* folder_path) {
+  ASSERT1(folder_path);
+
+  // Get a ITEMIDLIST* (called a PIDL in the MSDN documentation) to the
+  // special folder
+  scoped_any<ITEMIDLIST*, close_co_task_free> folder_location;
+  RET_IF_FAILED(::SHGetFolderLocation(NULL,
+                                      csidl,
+                                      NULL,
+                                      0,
+                                      address(folder_location)));
+  ASSERT(get(folder_location), (_T("")));
+
+  // Get an interface to the Desktop folder
+  CComPtr<IShellFolder> desktop_folder;
+  RET_IF_FAILED(::SHGetDesktopFolder(&desktop_folder));
+  ASSERT1(desktop_folder);
+
+  // Ask the desktop for the display name of the special folder
+  STRRET str_return;
+  SetZero(str_return);
+  str_return.uType = STRRET_WSTR;
+  RET_IF_FAILED(desktop_folder->GetDisplayNameOf(get(folder_location),
+                                                 SHGDN_FORPARSING,
+                                                 &str_return));
+
+  // Get the display name of the special folder and return it
+  scoped_any<wchar_t*, close_co_task_free> folder_name;
+  RET_IF_FAILED(::StrRetToStr(&str_return,
+                              get(folder_location),
+                              address(folder_name)));
+  *folder_path = get(folder_name);
+
+  return S_OK;
+}
+
+HRESULT Shell::GetSpecialFolder(DWORD csidl,
+                                bool create_if_missing,
+                                CString* folder_path) {
+  ASSERT(folder_path, (L""));
+
+  HRESULT hr = Shell::BasicGetSpecialFolder(csidl, folder_path);
+
+  // If the folder does not exist, ::SHGetFolderLocation may return error
+  // code ERROR_FILE_NOT_FOUND.
+  if (create_if_missing) {
+    if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
+        (SUCCEEDED(hr) && !File::Exists(*folder_path))) {
+      hr = Shell::BasicGetSpecialFolder(csidl | CSIDL_FLAG_CREATE, folder_path);
+    }
+  }
+  ASSERT(FAILED(hr) || File::Exists(*folder_path), (_T("")));
+
+  return hr;
+}
+
+#pragma warning(disable : 4510 4610)
+// C4510: default constructor could not be generated
+// C4610: struct can never be instantiated - user defined constructor required
+struct {
+  const TCHAR* name;
+  const DWORD csidl;
+} const folder_mappings[] = {
+  L"APPDATA",            CSIDL_APPDATA,
+  L"DESKTOP",            CSIDL_DESKTOPDIRECTORY,
+  L"LOCALAPPDATA",       CSIDL_LOCAL_APPDATA,
+  L"MYMUSIC",            CSIDL_MYMUSIC,
+  L"MYPICTURES",         CSIDL_MYPICTURES,
+  L"PROGRAMFILES",       CSIDL_PROGRAM_FILES,
+  L"PROGRAMFILESCOMMON", CSIDL_PROGRAM_FILES_COMMON,
+  L"PROGRAMS",           CSIDL_PROGRAMS,
+  L"STARTMENU",          CSIDL_STARTMENU,
+  L"STARTUP",            CSIDL_STARTUP,
+  L"SYSTEM",             CSIDL_SYSTEM,
+  L"WINDOWS",            CSIDL_WINDOWS,
+};
+#pragma warning(default : 4510 4610)
+
+HRESULT Shell::GetSpecialFolderKeywordsMapping(
+    std::map<CString, CString>* special_folders_map) {
+  ASSERT1(special_folders_map);
+
+  special_folders_map->clear();
+
+  for (size_t i = 0; i < arraysize(folder_mappings); ++i) {
+    CString name(folder_mappings[i].name);
+    DWORD csidl(folder_mappings[i].csidl);
+    CString folder;
+    HRESULT hr = GetSpecialFolder(csidl, false, &folder);
+    if (FAILED(hr)) {
+      UTIL_LOG(LE, (_T("[Shell::GetSpecialFolderKeywordsMapping]")
+                    _T("[failed to retrieve %s]"), name));
+      continue;
+    }
+    special_folders_map->insert(std::make_pair(name, folder));
+  }
+
+  // Get the current module directory
+  CString module_dir = app_util::GetModuleDirectory(::GetModuleHandle(NULL));
+  ASSERT1(module_dir.GetLength() > 0);
+  special_folders_map->insert(std::make_pair(_T("CURRENTMODULEDIR"),
+                                             module_dir));
+
+  return S_OK;
+}
+
+HRESULT Shell::DeleteDirectory(const TCHAR* dir) {
+  ASSERT1(dir && *dir);
+
+  if (!SafeDirectoryNameForDeletion(dir)) {
+    return E_INVALIDARG;
+  }
+
+  uint32 dir_len = lstrlen(dir);
+  if (dir_len >= MAX_PATH) {
+    return E_INVALIDARG;
+  }
+
+  // the 'from' must be double-terminated with 0. Reserve space for one more
+  // zero at the end
+  TCHAR from[MAX_PATH + 1] = {0};
+  lstrcpyn(from, dir, MAX_PATH);
+  from[1 + dir_len] = 0;    // the second zero terminator.
+
+  SHFILEOPSTRUCT file_op = {0};
+
+  file_op.hwnd   = 0;
+  file_op.wFunc  = FO_DELETE;
+  file_op.pFrom  = from;
+  file_op.pTo    = 0;
+  file_op.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
+
+  // ::SHFileOperation returns non-zero on errors
+  return ::SHFileOperation(&file_op) ? HRESULTFromLastError() : S_OK;
+}
+
+HRESULT Shell::GetApplicationExecutablePath(const CString& exe,
+                                            CString* path) {
+  ASSERT1(path);
+
+  CString reg_key_name = AppendRegKeyPath(kRegKeyApplicationPath, exe);
+  return RegKey::GetValue(reg_key_name, kRegKeyPathValue, path);
+}
+
+}  // namespace omaha
+
diff --git a/common/shell.h b/common/shell.h
index 94e35b1..c79382d 100644
--- a/common/shell.h
+++ b/common/shell.h
@@ -1,98 +1,98 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Shell functions

-//

-// create shortcut links

-// remove shortcut links

-

-#ifndef OMAHA_COMMON_SHELL_H_

-#define OMAHA_COMMON_SHELL_H_

-

-#include <windows.h>

-#include <shlobj.h>   // for the CSIDL definitions

-#include <atlstr.h>

-#include <map>

-

-#include "base/basictypes.h"

-

-namespace omaha {

-

-enum UseBrowser {

-  USE_DEFAULT_BROWSER = 0,

-  USE_INTERNET_EXPLORER = 1,

-  USE_FIREFOX = 2

-};

-

-class Shell {

- public:

-

-  // create and store a shortcut link

-  // note that icon can be NULL if no icon is required

-  // note that we always pick the 0th icon for now, this can be changed later

-  // [relevant with EXE and compound icons]

-  static HRESULT CreateLink(const TCHAR *source,

-                            const TCHAR *destination,

-                            const TCHAR *working_dir,

-                            const TCHAR *arguments,

-                            const TCHAR *description,

-                            WORD hotkey_virtual_key_code,

-                            WORD hotkey_modifiers,

-                            const TCHAR *icon);

-  // For information on hotkey modifiers see MSDN IShellLink::GetHotKey method.

-

-  // Delete a shortcut link

-  static HRESULT RemoveLink(const TCHAR *link);

-

-  // Open a URL in a new browser window

-  static HRESULT OpenLinkInNewWindow(const TCHAR* url, UseBrowser use_browser);

-

-  // Execute a file

-  static HRESULT Shell::Execute(const TCHAR* file);

-

-  // Get the location of a special folder.  The special folders are identified

-  // by a unique integer - see the platform SDK files shfolder.h and

-  // shlobj.h.  (These names will be the localized versions for the

-  // system that is running.)

-  static HRESULT GetSpecialFolder(DWORD csidl,

-                                  bool create_if_missing,

-                                  CString* folder_path);

-

-  // Get a mapping from special folder "env var" names to special folder

-  // pathnames.

-  // Provides mappings for: APPDATA, DESKTOP, LOCALAPPDATA, MYMUSIC, MYPICTURES,

-  // PROGRAMFILES, PROGRAMFILESCOMMON, PROGRAMS, STARTMENU, STARTUP, SYSTEM,

-  // WINDOWS.

-  static HRESULT GetSpecialFolderKeywordsMapping(

-      std::map<CString, CString>* special_folders_map);

-

-  // Recursively delete a directory including its files.

-  static HRESULT DeleteDirectory(const TCHAR* dir);

-

-  // Reads the application executable path from

-  // HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths.

-  static HRESULT GetApplicationExecutablePath(const CString& exe,

-                                              CString* path);

-

- private:

-

-  static HRESULT BasicGetSpecialFolder(DWORD csidl, CString* folder_path);

-

-  DISALLOW_EVIL_CONSTRUCTORS(Shell);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SHELL_H_

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Shell functions
+//
+// create shortcut links
+// remove shortcut links
+
+#ifndef OMAHA_COMMON_SHELL_H_
+#define OMAHA_COMMON_SHELL_H_
+
+#include <windows.h>
+#include <shlobj.h>   // for the CSIDL definitions
+#include <atlstr.h>
+#include <map>
+
+#include "base/basictypes.h"
+
+namespace omaha {
+
+enum UseBrowser {
+  USE_DEFAULT_BROWSER = 0,
+  USE_INTERNET_EXPLORER = 1,
+  USE_FIREFOX = 2
+};
+
+class Shell {
+ public:
+
+  // create and store a shortcut link
+  // note that icon can be NULL if no icon is required
+  // note that we always pick the 0th icon for now, this can be changed later
+  // [relevant with EXE and compound icons]
+  static HRESULT CreateLink(const TCHAR *source,
+                            const TCHAR *destination,
+                            const TCHAR *working_dir,
+                            const TCHAR *arguments,
+                            const TCHAR *description,
+                            WORD hotkey_virtual_key_code,
+                            WORD hotkey_modifiers,
+                            const TCHAR *icon);
+  // For information on hotkey modifiers see MSDN IShellLink::GetHotKey method.
+
+  // Delete a shortcut link
+  static HRESULT RemoveLink(const TCHAR *link);
+
+  // Open a URL in a new browser window
+  static HRESULT OpenLinkInNewWindow(const TCHAR* url, UseBrowser use_browser);
+
+  // Execute a file
+  static HRESULT Shell::Execute(const TCHAR* file);
+
+  // Get the location of a special folder.  The special folders are identified
+  // by a unique integer - see the platform SDK files shfolder.h and
+  // shlobj.h.  (These names will be the localized versions for the
+  // system that is running.)
+  static HRESULT GetSpecialFolder(DWORD csidl,
+                                  bool create_if_missing,
+                                  CString* folder_path);
+
+  // Get a mapping from special folder "env var" names to special folder
+  // pathnames.
+  // Provides mappings for: APPDATA, DESKTOP, LOCALAPPDATA, MYMUSIC, MYPICTURES,
+  // PROGRAMFILES, PROGRAMFILESCOMMON, PROGRAMS, STARTMENU, STARTUP, SYSTEM,
+  // WINDOWS.
+  static HRESULT GetSpecialFolderKeywordsMapping(
+      std::map<CString, CString>* special_folders_map);
+
+  // Recursively delete a directory including its files.
+  static HRESULT DeleteDirectory(const TCHAR* dir);
+
+  // Reads the application executable path from
+  // HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths.
+  static HRESULT GetApplicationExecutablePath(const CString& exe,
+                                              CString* path);
+
+ private:
+
+  static HRESULT BasicGetSpecialFolder(DWORD csidl, CString* folder_path);
+
+  DISALLOW_EVIL_CONSTRUCTORS(Shell);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SHELL_H_
diff --git a/common/shell_unittest.cc b/common/shell_unittest.cc
index a42c8c8..ddfe140 100644
--- a/common/shell_unittest.cc
+++ b/common/shell_unittest.cc
@@ -1,100 +1,100 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Shell functions

-

-#include <shlobj.h>

-#include <map>

-#include "base/basictypes.h"

-#include "omaha/common/dynamic_link_kernel32.h"

-#include "omaha/common/file.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/shell.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(ShellTest, ShellLink) {

-  CString desktop;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_DESKTOP, &desktop));

-  CString link(desktop + _T("\\Shell Unittest.lnk"));

-  CString install_dir;

-  ASSERT_SUCCEEDED(Shell::GetSpecialFolder(CSIDL_PROGRAM_FILES,

-                                           true,

-                                           &install_dir));

-  install_dir += _T("\\Shell Unittest");

-  CString exe = install_dir + _T("\\foo.bar.exe");

-  ASSERT_FALSE(File::Exists(link));

-  ASSERT_SUCCEEDED(Shell::CreateLink(exe,

-                                     link,

-                                     install_dir,

-                                     _T(""),

-                                     _T("Google Update Unit Test"),

-                                     'W',

-                                     HOTKEYF_ALT | HOTKEYF_CONTROL,

-                                     NULL));

-  ASSERT_TRUE(File::Exists(link));

-  ASSERT_SUCCEEDED(Shell::RemoveLink(link));

-  ASSERT_FALSE(File::Exists(link));

-}

-

-struct Folders {

-    DWORD csidl;

-    CString name;

-};

-

-TEST(ShellTest, GetSpecialFolder) {

-  Folders folders[] = {

-    { CSIDL_COMMON_APPDATA,

-      CString("C:\\Documents and Settings\\All Users\\Application Data") },

-    { CSIDL_FONTS,

-      CString("C:\\WINDOWS\\Fonts") },

-    { CSIDL_PROGRAM_FILES,

-      CString("C:\\Program Files") },

-  };

-

-  if (SystemInfo::IsRunningOnVistaOrLater()) {

-    folders[0].name = _T("C:\\ProgramData");

-  }

-

-  // Override the program files location, which changes for 32-bit processes

-  // running on 64-bit systems.

-  BOOL isWow64 = FALSE;

-  EXPECT_SUCCEEDED(Kernel32::IsWow64Process(GetCurrentProcess(), &isWow64));

-  if (isWow64) {

-    folders[2].name += _T(" (x86)");

-  }

-

-  for (size_t i = 0; i != arraysize(folders); ++i) {

-    CString folder_name;

-    EXPECT_SUCCEEDED(Shell::GetSpecialFolder(folders[i].csidl,

-                                             false,

-                                             &folder_name));

-    // This should work, but CmpHelperSTRCASEEQ is not overloaded for wchars.

-    // EXPECT_STRCASEEQ(folder_name, folders[i].name);

-    EXPECT_EQ(folder_name.CompareNoCase(folders[i].name), 0);

-  }

-}

-

-TEST(ShellTest, GetSpecialFolderKeywordsMapping) {

-  typedef std::map<CString, CString> mapping;

-  mapping folder_map;

-  ASSERT_SUCCEEDED(Shell::GetSpecialFolderKeywordsMapping(&folder_map));

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Shell functions
+
+#include <shlobj.h>
+#include <map>
+#include "base/basictypes.h"
+#include "omaha/common/dynamic_link_kernel32.h"
+#include "omaha/common/file.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/shell.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(ShellTest, ShellLink) {
+  CString desktop;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_DESKTOP, &desktop));
+  CString link(desktop + _T("\\Shell Unittest.lnk"));
+  CString install_dir;
+  ASSERT_SUCCEEDED(Shell::GetSpecialFolder(CSIDL_PROGRAM_FILES,
+                                           true,
+                                           &install_dir));
+  install_dir += _T("\\Shell Unittest");
+  CString exe = install_dir + _T("\\foo.bar.exe");
+  ASSERT_FALSE(File::Exists(link));
+  ASSERT_SUCCEEDED(Shell::CreateLink(exe,
+                                     link,
+                                     install_dir,
+                                     _T(""),
+                                     _T("Google Update Unit Test"),
+                                     'W',
+                                     HOTKEYF_ALT | HOTKEYF_CONTROL,
+                                     NULL));
+  ASSERT_TRUE(File::Exists(link));
+  ASSERT_SUCCEEDED(Shell::RemoveLink(link));
+  ASSERT_FALSE(File::Exists(link));
+}
+
+struct Folders {
+    DWORD csidl;
+    CString name;
+};
+
+TEST(ShellTest, GetSpecialFolder) {
+  Folders folders[] = {
+    { CSIDL_COMMON_APPDATA,
+      CString("C:\\Documents and Settings\\All Users\\Application Data") },
+    { CSIDL_FONTS,
+      CString("C:\\WINDOWS\\Fonts") },
+    { CSIDL_PROGRAM_FILES,
+      CString("C:\\Program Files") },
+  };
+
+  if (SystemInfo::IsRunningOnVistaOrLater()) {
+    folders[0].name = _T("C:\\ProgramData");
+  }
+
+  // Override the program files location, which changes for 32-bit processes
+  // running on 64-bit systems.
+  BOOL isWow64 = FALSE;
+  EXPECT_SUCCEEDED(Kernel32::IsWow64Process(GetCurrentProcess(), &isWow64));
+  if (isWow64) {
+    folders[2].name += _T(" (x86)");
+  }
+
+  for (size_t i = 0; i != arraysize(folders); ++i) {
+    CString folder_name;
+    EXPECT_SUCCEEDED(Shell::GetSpecialFolder(folders[i].csidl,
+                                             false,
+                                             &folder_name));
+    // This should work, but CmpHelperSTRCASEEQ is not overloaded for wchars.
+    // EXPECT_STRCASEEQ(folder_name, folders[i].name);
+    EXPECT_EQ(folder_name.CompareNoCase(folders[i].name), 0);
+  }
+}
+
+TEST(ShellTest, GetSpecialFolderKeywordsMapping) {
+  typedef std::map<CString, CString> mapping;
+  mapping folder_map;
+  ASSERT_SUCCEEDED(Shell::GetSpecialFolderKeywordsMapping(&folder_map));
+}
+
+}  // namespace omaha
+
diff --git a/common/shutdown_callback.h b/common/shutdown_callback.h
index 169b6e7..e21598a 100644
--- a/common/shutdown_callback.h
+++ b/common/shutdown_callback.h
@@ -1,35 +1,35 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// ShutdownCallBack monitors a shutdown event.

-

-#ifndef OMAHA_COMMON_SHUTDOWN_CALLBACK_H__

-#define OMAHA_COMMON_SHUTDOWN_CALLBACK_H__

-

-#include <windows.h>

-

-namespace omaha {

-

-class ShutdownCallback {

- public:

-  virtual ~ShutdownCallback() {}

-  virtual HRESULT Shutdown() = 0;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SHUTDOWN_CALLBACK_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// ShutdownCallBack monitors a shutdown event.
+
+#ifndef OMAHA_COMMON_SHUTDOWN_CALLBACK_H__
+#define OMAHA_COMMON_SHUTDOWN_CALLBACK_H__
+
+#include <windows.h>
+
+namespace omaha {
+
+class ShutdownCallback {
+ public:
+  virtual ~ShutdownCallback() {}
+  virtual HRESULT Shutdown() = 0;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SHUTDOWN_CALLBACK_H__
+
diff --git a/common/shutdown_handler.cc b/common/shutdown_handler.cc
index 5be93a0..a03fb79 100644
--- a/common/shutdown_handler.cc
+++ b/common/shutdown_handler.cc
@@ -1,75 +1,75 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/shutdown_handler.h"

-

-#include <atlsecurity.h>

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reactor.h"

-#include "omaha/common/shutdown_callback.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-ShutdownHandler::ShutdownHandler()

-  : shutdown_callback_(NULL) {

-}

-

-ShutdownHandler::~ShutdownHandler() {

-  if (get(shutdown_event_)) {

-    VERIFY1(SUCCEEDED(reactor_->UnregisterHandle(get(shutdown_event_))));

-  }

-}

-

-HRESULT ShutdownHandler::Initialize(Reactor* reactor,

-                                    ShutdownCallback* shutdown,

-                                    bool is_machine) {

-  ASSERT1(reactor);

-  ASSERT1(shutdown);

-  shutdown_callback_ = shutdown;

-  reactor_ = reactor;

-  is_machine_ = is_machine;

-

-  NamedObjectAttributes attr;

-  GetNamedObjectAttributes(kShutdownEvent, is_machine_, &attr);

-  // Manual reset=true and signaled=false

-  reset(shutdown_event_, ::CreateEvent(&attr.sa, true, false, attr.name));

-  if (!shutdown_event_) {

-    return HRESULTFromLastError();

-  }

-

-  HRESULT hr = reactor_->RegisterHandle(get(shutdown_event_), this, 0);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return S_OK;

-}

-

-void ShutdownHandler::HandleEvent(HANDLE handle) {

-  if (handle == get(shutdown_event_)) {

-    CORE_LOG(L1, (_T("[shutdown event is signaled]")));

-  } else {

-    ASSERT1(false);

-  }

-  ASSERT1(shutdown_callback_);

-  shutdown_callback_->Shutdown();

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/shutdown_handler.h"
+
+#include <atlsecurity.h>
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reactor.h"
+#include "omaha/common/shutdown_callback.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+ShutdownHandler::ShutdownHandler()
+  : shutdown_callback_(NULL) {
+}
+
+ShutdownHandler::~ShutdownHandler() {
+  if (get(shutdown_event_)) {
+    VERIFY1(SUCCEEDED(reactor_->UnregisterHandle(get(shutdown_event_))));
+  }
+}
+
+HRESULT ShutdownHandler::Initialize(Reactor* reactor,
+                                    ShutdownCallback* shutdown,
+                                    bool is_machine) {
+  ASSERT1(reactor);
+  ASSERT1(shutdown);
+  shutdown_callback_ = shutdown;
+  reactor_ = reactor;
+  is_machine_ = is_machine;
+
+  NamedObjectAttributes attr;
+  GetNamedObjectAttributes(kShutdownEvent, is_machine_, &attr);
+  // Manual reset=true and signaled=false
+  reset(shutdown_event_, ::CreateEvent(&attr.sa, true, false, attr.name));
+  if (!shutdown_event_) {
+    return HRESULTFromLastError();
+  }
+
+  HRESULT hr = reactor_->RegisterHandle(get(shutdown_event_), this, 0);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return S_OK;
+}
+
+void ShutdownHandler::HandleEvent(HANDLE handle) {
+  if (handle == get(shutdown_event_)) {
+    CORE_LOG(L1, (_T("[shutdown event is signaled]")));
+  } else {
+    ASSERT1(false);
+  }
+  ASSERT1(shutdown_callback_);
+  shutdown_callback_->Shutdown();
+}
+
+}  // namespace omaha
+
diff --git a/common/shutdown_handler.h b/common/shutdown_handler.h
index c6508ab..d7cfa94 100644
--- a/common/shutdown_handler.h
+++ b/common/shutdown_handler.h
@@ -1,53 +1,53 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// ShutdownHandler monitors a shutdown event.

-

-#ifndef OMAHA_COMMON_SHUTDOWN_HANDLER_H__

-#define OMAHA_COMMON_SHUTDOWN_HANDLER_H__

-

-#include <windows.h>

-#include "base/basictypes.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/event_handler.h"

-

-namespace omaha {

-

-class Reactor;

-class ShutdownCallback;

-

-class ShutdownHandler : public EventHandler {

- public:

-  ShutdownHandler();

-  ~ShutdownHandler();

-

-  HRESULT Initialize(Reactor* reactor,

-                     ShutdownCallback* shutdown,

-                     bool is_machine);

-  virtual void HandleEvent(HANDLE handle);

-

- private:

-  Reactor* reactor_;

-  scoped_event shutdown_event_;

-  ShutdownCallback* shutdown_callback_;

-  bool is_machine_;

-  DISALLOW_EVIL_CONSTRUCTORS(ShutdownHandler);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SHUTDOWN_HANDLER_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// ShutdownHandler monitors a shutdown event.
+
+#ifndef OMAHA_COMMON_SHUTDOWN_HANDLER_H__
+#define OMAHA_COMMON_SHUTDOWN_HANDLER_H__
+
+#include <windows.h>
+#include "base/basictypes.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/event_handler.h"
+
+namespace omaha {
+
+class Reactor;
+class ShutdownCallback;
+
+class ShutdownHandler : public EventHandler {
+ public:
+  ShutdownHandler();
+  ~ShutdownHandler();
+
+  HRESULT Initialize(Reactor* reactor,
+                     ShutdownCallback* shutdown,
+                     bool is_machine);
+  virtual void HandleEvent(HANDLE handle);
+
+ private:
+  Reactor* reactor_;
+  scoped_event shutdown_event_;
+  ShutdownCallback* shutdown_callback_;
+  bool is_machine_;
+  DISALLOW_EVIL_CONSTRUCTORS(ShutdownHandler);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SHUTDOWN_HANDLER_H__
+
diff --git a/common/signatures.cc b/common/signatures.cc
index beee06a..c0b0cb9 100644
--- a/common/signatures.cc
+++ b/common/signatures.cc
@@ -1,1025 +1,1025 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// signatures.cpp

-//

-// Classes and functions related to crypto-hashes of buffers and digital

-// signatures of buffers.

-

-#include "omaha/common/signatures.h"

-#include <wincrypt.h>

-#include <memory.h>

-

-#pragma warning(disable : 4245)

-// C4245 : conversion from 'type1' to 'type2', signed/unsigned mismatch

-#include <atlenc.h>

-#pragma warning(default : 4245)

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/const_utils.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/sha.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-const ALG_ID kHashAlgorithm = CALG_SHA1;

-const DWORD kEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;

-const DWORD kProviderType = PROV_RSA_FULL;

-const DWORD kCertificateNameType = CERT_NAME_SIMPLE_DISPLAY_TYPE;

-const DWORD kKeyPairType = AT_SIGNATURE;

-

-namespace CryptDetails {

-

-  // Useful scoped pointers for working with CryptoAPI objects

-

-  void crypt_release_context(HCRYPTPROV provider) {

-    UTIL_LOG(L3, (L"Releasing HCRYPTPROV 0x%08lx", provider));

-    BOOL b = ::CryptReleaseContext(provider, 0 /*flags*/);

-    ASSERT(b, (L""));

-  }

-

-  void crypt_close_store(HCERTSTORE store) {

-    UTIL_LOG(L3, (L"Releasing HCERTSTORE 0x%08lx", store));

-    BOOL b = ::CertCloseStore(store, 0 /*flags*/);

-    ASSERT(b, (L""));

-    ASSERT(::GetLastError() != CRYPT_E_PENDING_CLOSE, (L""));

-  }

-

-  void crypt_free_certificate(PCCERT_CONTEXT certificate) {

-    UTIL_LOG(L3, (L"Releasing PCCERT_CONTEXT 0x%08lx", certificate));

-    BOOL b = ::CertFreeCertificateContext(certificate);

-    ASSERT(b, (L""));

-  }

-

-  void crypt_destroy_key(HCRYPTKEY key) {

-    UTIL_LOG(L3, (L"Releasing HCRYPTKEY 0x%08lx", key));

-    BOOL b = ::CryptDestroyKey(key);

-    ASSERT(b, (L""));

-  }

-

-  void crypt_destroy_hash(HCRYPTHASH hash) {

-    UTIL_LOG(L3, (L"Releasing HCRYPTHASH 0x%08lx", hash));

-    BOOL b = ::CryptDestroyHash(hash);

-    ASSERT(b, (L""));

-  }

-

-  typedef close_fun<void (*)(HCRYPTHASH),

-                    crypt_destroy_hash> smart_destroy_hash;

-  typedef scoped_any<HCRYPTHASH, smart_destroy_hash, null_t> scoped_crypt_hash;

-}

-

-// Base64 encode/decode functions are part of ATL Server

-HRESULT Base64::Encode(const std::vector<byte>& buffer_in,

-                       std::vector<byte>* encoded,

-                       bool break_into_lines) {

-  ASSERT(encoded, (L""));

-

-  if (buffer_in.empty()) {

-    encoded->resize(0);

-    return S_OK;

-  }

-

-  int32 encoded_len =

-    Base64EncodeGetRequiredLength(

-        buffer_in.size(),

-        break_into_lines ? ATL_BASE64_FLAG_NONE : ATL_BASE64_FLAG_NOCRLF);

-  ASSERT(encoded_len > 0, (L""));

-

-  encoded->resize(encoded_len);

-  int32 str_out_len = encoded_len;

-

-  BOOL result = Base64Encode(

-      &buffer_in.front(),

-      buffer_in.size(),

-      reinterpret_cast<char*>(&encoded->front()),

-      &str_out_len,

-      break_into_lines ? ATL_BASE64_FLAG_NONE : ATL_BASE64_FLAG_NOCRLF);

-  if (!result)

-    return E_FAIL;

-  ASSERT(str_out_len <= encoded_len, (L""));

-  if (str_out_len < encoded_len)

-    encoded->resize(str_out_len);

-

-  return S_OK;

-}

-

-HRESULT Base64::Encode(const std::vector<byte>& buffer_in,

-                       CStringA* encoded,

-                       bool break_into_lines) {

-  ASSERT(encoded, (L""));

-

-  if (buffer_in.empty()) {

-    return S_OK;

-  }

-

-  std::vector<byte> buffer_out;

-  RET_IF_FAILED(Encode(buffer_in, &buffer_out, break_into_lines));

-  encoded->Append(reinterpret_cast<const char*>(&buffer_out.front()),

-                                                buffer_out.size());

-

-  return S_OK;

-}

-

-HRESULT Base64::Encode(const std::vector<byte>& buffer_in,

-                       CString* encoded,

-                       bool break_into_lines) {

-  ASSERT(encoded, (L""));

-

-  CStringA string_out;

-  RET_IF_FAILED(Encode(buffer_in, &string_out, break_into_lines));

-  *encoded = string_out;

-

-  return S_OK;

-}

-

-HRESULT Base64::Decode(const std::vector<byte>& encoded,

-                       std::vector<byte>* buffer_out) {

-  ASSERT(buffer_out, (L""));

-

-  size_t encoded_len = encoded.size();

-  int32 required_len = Base64DecodeGetRequiredLength(encoded_len);

-

-  buffer_out->resize(required_len);

-

-  if (required_len == 0) {

-    return S_OK;

-  }

-

-  int32 bytes_written = required_len;

-  BOOL result = Base64Decode(reinterpret_cast<const char*>(&encoded.front()),

-                             encoded_len,

-                             &buffer_out->front(),

-                             &bytes_written);

-  if (!result)

-    return E_FAIL;

-  ASSERT(bytes_written <= required_len, (L""));

-  if (bytes_written < required_len) {

-    buffer_out->resize(bytes_written);

-  }

-

-  return S_OK;

-}

-

-HRESULT Base64::Decode(const CStringA& encoded, std::vector<byte>* buffer_out) {

-  ASSERT(buffer_out, (L""));

-

-  size_t encoded_len = encoded.GetLength();

-  std::vector<byte> buffer_in(encoded_len);

-  if (encoded_len != 0) {

-    ::memcpy(&buffer_in.front(), encoded.GetString(), encoded_len);

-  }

-

-  return Decode(buffer_in, buffer_out);

-}

-

-// Base64 in a CString -> binary

-HRESULT Base64::Decode(const CString& encoded, std::vector<byte>* buffer_out) {

-  ASSERT(buffer_out, (L""));

-

-  CW2A encoded_a(encoded.GetString());

-

-  size_t encoded_len = ::strlen(encoded_a);

-  std::vector<byte> buffer_in(encoded_len);

-  if (encoded_len != 0) {

-    ::memcpy(&buffer_in.front(), encoded_a, encoded_len);

-  }

-

-  return Decode(buffer_in, buffer_out);

-}

-

-// Using google SHA-1 algorithms rather than CryptoAPI SHA-1

-// algorithms; saves the trouble of dealing with CSPs and the like.

-

-CryptoHash::CryptoHash() {

-}

-

-CryptoHash::~CryptoHash() {

-}

-

-HRESULT CryptoHash::Compute(const TCHAR* filepath,

-                            uint64 max_len,

-                            std::vector<byte>* hash_out) {

-  ASSERT1(filepath);

-  ASSERT1(hash_out);

-

-  std::vector<CString> filepaths;

-  filepaths.push_back(filepath);

-  return Compute(filepaths, max_len, hash_out);

-}

-

-HRESULT CryptoHash::Compute(const std::vector<CString>& filepaths,

-                            uint64 max_len,

-                            std::vector<byte>* hash_out) {

-  ASSERT1(filepaths.size() > 0);

-  ASSERT1(hash_out);

-

-  return ComputeOrValidate(filepaths, max_len, NULL, hash_out);

-}

-

-HRESULT CryptoHash::Compute(const std::vector<byte>& buffer_in,

-                            std::vector<byte>* hash_out) {

-  ASSERT1(buffer_in.size() > 0);

-  ASSERT1(hash_out);

-

-  return ComputeOrValidate(buffer_in, NULL, hash_out);

-}

-

-HRESULT CryptoHash::Validate(const TCHAR* filepath,

-                             uint64 max_len,

-                             const std::vector<byte>& hash_in) {

-  ASSERT1(filepath);

-  ASSERT1(hash_in.size() == kHashSize);

-

-  std::vector<CString> filepaths;

-  filepaths.push_back(filepath);

-  return Validate(filepaths, max_len, hash_in);

-}

-

-HRESULT CryptoHash::Validate(const std::vector<CString>& filepaths,

-                             uint64 max_len,

-                             const std::vector<byte>& hash_in) {

-  ASSERT1(hash_in.size() == kHashSize);

-

-  return ComputeOrValidate(filepaths, max_len, &hash_in, NULL);

-}

-

-

-HRESULT CryptoHash::Validate(const std::vector<byte>& buffer_in,

-                             const std::vector<byte>& hash_in) {

-  ASSERT1(buffer_in.size() > 0);

-  ASSERT1(hash_in.size() == kHashSize);

-

-  return ComputeOrValidate(buffer_in, &hash_in, NULL);

-}

-

-HRESULT CryptoHash::ComputeOrValidate(const std::vector<CString>& filepaths,

-                                      uint64 max_len,

-                                      const std::vector<byte>* hash_in,

-                                      std::vector<byte>* hash_out) {

-  ASSERT1(filepaths.size() > 0);

-  ASSERT1(hash_in && !hash_out || !hash_in && hash_out);

-

-  byte buf[1024] = {0};

-  SecureHashAlgorithm sha;

-  uint64 curr_len = 0;

-  for (size_t i = 0; i < filepaths.size(); ++i) {

-    scoped_hfile file_handle(::CreateFile(filepaths[i],

-                                          FILE_READ_DATA,

-                                          FILE_SHARE_READ,

-                                          NULL,

-                                          OPEN_EXISTING,

-                                          FILE_ATTRIBUTE_NORMAL,

-                                          NULL));

-    if (!file_handle) {

-      return HRESULTFromLastError();

-    }

-

-    if (max_len) {

-      LARGE_INTEGER file_size = {0};

-      if (!::GetFileSizeEx(get(file_handle), &file_size)) {

-        return HRESULTFromLastError();

-      }

-      curr_len += ((static_cast<uint64>(file_size.HighPart)) << 32) +

-                  static_cast<uint64>(file_size.LowPart);

-      if (curr_len > max_len) {

-        UTIL_LOG(LE, (_T("[CryptoHash::ComputeOrValidate]")

-                      _T(" exceed max len][curr_len=%lu][max_len=%lu]"),

-                      curr_len, max_len));

-        return E_FAIL;

-      }

-    }

-

-    DWORD bytes_read = 0;

-    do {

-      if (!::ReadFile(get(file_handle),

-                      buf,

-                      arraysize(buf),

-                      &bytes_read,

-                      NULL)) {

-        return HRESULTFromLastError();

-      }

-

-      if (bytes_read > 0) {

-        sha.AddBytes(buf, bytes_read);

-      }

-    } while (bytes_read == arraysize(buf));

-  }

-  sha.Finished();

-

-  if (hash_in) {

-    int res = ::memcmp(&hash_in->front(), sha.Digest(), kHashSize);

-    if (res == 0) {

-      return S_OK;

-    }

-

-    std::vector<byte> calculated_hash(kHashSize);

-    memcpy(&calculated_hash.front(), sha.Digest(), kHashSize);

-    CStringA base64_encoded_hash;

-    Base64::Encode(calculated_hash, &base64_encoded_hash, false);

-    CString hash = AnsiToWideString(base64_encoded_hash,

-                                    base64_encoded_hash.GetLength());

-    REPORT_LOG(L1, (_T("[actual hash=%s]"), hash));

-    return SIGS_E_INVALID_SIGNATURE;

-  } else {

-    hash_out->resize(kHashSize);

-    ::memcpy(&hash_out->front(), sha.Digest(), kHashSize);

-    return S_OK;

-  }

-}

-

-HRESULT CryptoHash::ComputeOrValidate(const std::vector<byte>& buffer_in,

-                                      const std::vector<byte>* hash_in,

-                                      std::vector<byte>* hash_out) {

-  ASSERT1(hash_in && !hash_out || !hash_in && hash_out);

-

-  SecureHashAlgorithm sha;

-  if (!buffer_in.empty()) {

-    sha.AddBytes(&buffer_in.front(), buffer_in.size());

-  }

-  sha.Finished();

-

-  if (hash_in) {

-    int res = ::memcmp(&hash_in->front(), sha.Digest(), kHashSize);

-    return (res == 0) ? S_OK : SIGS_E_INVALID_SIGNATURE;

-  } else {

-    hash_out->resize(kHashSize);

-    ::memcpy(&hash_out->front(), sha.Digest(), kHashSize);

-    return S_OK;

-  }

-}

-

-// To sign data you need a CSP with the proper private key installed.

-// To get a signing certificate you start with a PFX file.  This file

-// encodes a "certificate store" which can hold more than one

-// certificate.  (In general it can hold a certificate chain, but we

-// only use the signing certificate.)  There are special APIs to verify

-// the format of a PFX file and read it into a new certificate store.  A

-// password must be specified to read the PFX file as it is encrypted.

-// The password was set when the PFX file was exported or otherwise

-// created.  Then you search for the proper certificate in the store

-// (using the subject_name which tells who the certificate was issued

-// to).  Finally, to get a CSP with the certificate's private key

-// available there is a special API, CryptAcquireCertificatePrivateKey,

-// that takes a CSP and a certificate and makes the private key of the

-// certificate the private key of the CSP.

-

-CryptoSigningCertificate::CryptoSigningCertificate() : key_spec_(0) {

-}

-

-CryptoSigningCertificate::~CryptoSigningCertificate() {

-}

-

-HRESULT CryptoSigningCertificate::ImportCertificate(

-    const TCHAR * filepath,

-    const TCHAR * password,

-    const TCHAR * subject_name) {

-  ASSERT(filepath, (L""));

-  ASSERT(password, (L""));

-

-  std::vector<byte> buffer;

-  HRESULT hr = ReadEntireFile(filepath, kMaxCertificateSize, &buffer);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (L"[CryptoSigningCertificate::ImportCertificate]"

-                  L"['%s' not read, hr 0x%08lx]", filepath, hr));

-    return hr;

-  }

-  return ImportCertificate(buffer, password, subject_name);

-}

-

-HRESULT CryptoSigningCertificate::ImportCertificate(

-    const std::vector<byte>& certificate_in,

-    const TCHAR * password,

-    const TCHAR * subject_name) {

-  ASSERT(password, (L""));

-  ASSERT1(!certificate_in.empty());

-

-  UTIL_LOG(L2, (L"[CryptoSigningCertificate::ImportCertificate]"

-                L"[%d bytes, subject_name '%s']",

-                certificate_in.size(), subject_name ? subject_name : L""));

-

-  // CryptoAPI treats the certificate as a "blob"

-  CRYPT_DATA_BLOB blob;

-  blob.cbData = certificate_in.size();

-  blob.pbData = const_cast<BYTE*>(&certificate_in.front());

-

-  // Ensure that it is PFX formatted

-  BOOL b = ::PFXIsPFXBlob(&blob);

-  if (!b) {

-    ASSERT(0, (L"Invalid PFX certificate, err 0x%08lx", ::GetLastError()));

-    return SIGS_E_INVALID_PFX_CERTIFICATE;

-  }

-

-  // Make sure the password checks out

-  b = ::PFXVerifyPassword(&blob, password, 0 /* flags */);

-  if (!b) {

-    UTIL_LOG(LE, (L"[CryptoSigningCertificate::ImportCertificate]"

-                  L"[invalid password, err 0x%08lx]", ::GetLastError()));

-    return SIGS_E_INVALID_PASSWORD;

-  }

-

-  // Do the import from the certificate to a new certificate store

-  // TODO(omaha): Check that this is in fact a new certificate store, not an

-  // existing one.  If it is an existing one we'll need to delete the

-  // certificate later.

-  // The last parameter to ::PFXImportCertStore() is 0, indicating that we want

-  // the CSP to be "silent"; i.e., not prompt.

-  reset(store_, ::PFXImportCertStore(&blob, password, 0));

-  if (!store_) {

-    DWORD err = ::GetLastError();

-    ASSERT(0, (L"Failed to import PFX certificate into a certificate store, "

-               L"err 0x%08lx", err));

-    return HRESULT_FROM_WIN32(err);

-  }

-  UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"

-                L"[new store 0x%08lx]", get(store_)));

-

-  // Now that we have a store, look for the correct certificate.  (There may

-  // have been more than one in the PFX file, e.g., a certificate chain.)

-  PCCERT_CONTEXT certificate_context = NULL;

-  while ((certificate_context =

-          ::CertEnumCertificatesInStore(get(store_),

-                                        certificate_context)) != NULL) {

-    // Have a certificate, does it look like the right one?  Check the name

-    DWORD name_len = ::CertGetNameString(certificate_context,

-                                         kCertificateNameType,

-                                         0 /*flags*/,

-                                         NULL,

-                                         NULL,

-                                         0);

-    if (name_len <= 1) {

-      // Name attribute not found - should never happen

-      ASSERT(0, (L"CryptoSigningCertificate::ImportCertificate failed to get "

-                 L"certificate name length, err 0x%08lx", ::GetLastError()));

-      continue;

-    }

-    // name_len includes the terminating null

-

-    std::vector<TCHAR> name;

-    name.resize(name_len);

-    ASSERT1(!name.empty());

-    DWORD name_len2 = ::CertGetNameString(certificate_context,

-                                          kCertificateNameType,

-                                          0,

-                                          NULL,

-                                          &name.front(),

-                                          name_len);

-    ASSERT(name_len2 == name_len, (L""));

-

-    UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"

-                  L"[found '%s' in store]", &name.front()));

-

-    // Check the name if the user so desires.  (If subject_name == NULL then

-    // the first certificate found is used.)

-    if (subject_name && (0 != String_StrNCmp(&name.front(),

-                                             subject_name,

-                                             ::lstrlen(subject_name),

-                                             false))) {

-      // name mismatch

-      UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"

-                    L"[not the right certificate, we're looking for '%s']",

-                    subject_name));

-      continue;

-    }

-

-    // This is the right certificate

-    subject_name_ = &name.front();

-    reset(certificate_, certificate_context);

-    UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"

-                  L"[new certificate 0x%08lx]", get(certificate_)));

-    break;

-  }

-

-  return S_OK;

-}

-

-HRESULT CryptoSigningCertificate::GetCSPContext(HCRYPTPROV* csp_context) {

-  ASSERT(csp_context, (L""));

-  ASSERT(get(certificate_), (L""));

-

-  // CSP may have already been used - reset it

-  reset(csp_);

-

-  // Create a CSP context using the private key of the certificate we imported

-  // earlier.

-  HCRYPTPROV csp = NULL;

-  BOOL must_free_csp = FALSE;

-  BOOL b = ::CryptAcquireCertificatePrivateKey(get(certificate_),

-                                               0 /*flags*/,

-                                               0 /*reserved*/,

-                                               &csp,

-                                               &key_spec_,

-                                               &must_free_csp);

-  if (!b) {

-    DWORD err = ::GetLastError();

-    ASSERT(0, (L"CryptoSigningCertificate::GetCSPContext "

-               L"CryptAcquireCertificatePrivateKey failed, err 0x%08lx", err));

-    return HRESULT_FROM_WIN32(err);

-  }

-

-  // (Funky API returns a boolean which tells you whether it is your

-  // responsibility to delete the CSP context or not.)

-  if (must_free_csp) {

-    reset(csp_, csp);

-  }

-  if (get(csp_)) {

-    UTIL_LOG(L3, (L"[CryptoSigningCertificate::GetCSPContext new CSP 0x%08lx]",

-                  get(csp_)));

-  }

-

-  ASSERT(key_spec_ == AT_SIGNATURE || key_spec_ == AT_KEYEXCHANGE, (L""));

-  if (key_spec_ != kKeyPairType) {

-    UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"

-                  L"[requires a AT_SIGNATURE type key]"));

-    return SIGS_E_INVALID_KEY_TYPE;

-  }

-

-#ifdef _DEBUG

-  // Which CSP did we get?

-  char csp_name[256] = {0};

-  DWORD csp_name_len = arraysize(csp_name);

-  b = ::CryptGetProvParam(csp,

-                          PP_NAME,

-                          reinterpret_cast<BYTE*>(&csp_name[0]),

-                          &csp_name_len,

-                          0 /*flags*/);

-  if (!b) {

-    DWORD err = ::GetLastError();

-    UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"

-                  L"[error getting CSP name, err 0x%08lx]", err));

-  }

-  DWORD csp_prov_type;

-  DWORD csp_prov_type_len = sizeof(csp_prov_type);

-  b = ::CryptGetProvParam(csp,

-                          PP_PROVTYPE,

-                          reinterpret_cast<BYTE*>(&csp_prov_type),

-                          &csp_prov_type_len,

-                          0 /*flags*/);

-  if (!b) {

-    DWORD err = ::GetLastError();

-    UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"

-                  L"[error getting CSP provtype, err 0x%08lx]", err));

-  }

-  char csp_container[256] = {0};

-  DWORD csp_container_len = arraysize(csp_container);

-  b = ::CryptGetProvParam(csp,

-                          PP_CONTAINER,

-                          reinterpret_cast<BYTE*>(&csp_container[0]),

-                          &csp_container_len,

-                          0 /*flags*/);

-  if (!b) {

-    DWORD err = ::GetLastError();

-    UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"

-                  L"[error getting CSP current container name, err 0x%08lx]",

-                  err));

-  }

-  UTIL_LOG(L2, (L"[CryptoSigningCertificate::GetCSPContext]"

-                L"[have CSP '%S' (provtype %d) key container '%S']",

-                csp_name, csp_prov_type, csp_container));

-  // End of which CSP did we get

-#endif

-

-  *csp_context = csp;

-

-  UTIL_LOG(L2, (L"[CryptoSigningCertificate::GetCSPContext]"

-                L"[getting CSP with private key from certificate]"

-                L"[HCRYPTPROV 0x%08lx]", csp));

-

-  return S_OK;

-}

-

-// To sign some data using CryptoAPI you first hash it into a hash

-// object, then sign it using the CSP.  The CSP needs to have the

-// private key, of type AT_SIGNATURE, in it already, as it isn't a

-// parameter of the CryptSignHash API.  The CryptoSigningCertificate

-// can provide such a CSP.

-

-CryptoComputeSignature::CryptoComputeSignature(

-    CryptoSigningCertificate* certificate)

-    : certificate_(certificate) {

-}

-

-CryptoComputeSignature::~CryptoComputeSignature() {

-}

-

-HRESULT CryptoComputeSignature::Sign(TCHAR const * const filepath,

-                                     uint32 max_len,

-                                     std::vector<byte>* signature_out) {

-  ASSERT(filepath, (L""));

-  std::vector<byte> buffer;

-  HRESULT hr = ReadEntireFile(filepath, max_len, &buffer);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"

-                  L"['%s not read, hr 0x%08lx]", filepath, hr));

-    return hr;

-  }

-  return Sign(buffer, signature_out);

-}

-

-HRESULT CryptoComputeSignature::Sign(const std::vector<byte>& buffer_in,

-                                     std::vector<byte>* signature_out) {

-  ASSERT(signature_out, (L""));

-  ASSERT1(!buffer_in.empty());

-

-  UTIL_LOG(L2, (L"[CryptoComputeSignature::Sign]"

-                L"[buffer of %d bytes]", buffer_in.size()));

-

-  // Get the proper CSP with the private key (certificate retains ownership)

-  HCRYPTPROV csp = NULL;

-  HRESULT hr = certificate_->GetCSPContext(&csp);

-  ASSERT(SUCCEEDED(hr) && csp, (L""));

-

-  // Hash the data

-  CryptDetails::scoped_crypt_hash hash;

-  BOOL b = ::CryptCreateHash(csp, kHashAlgorithm, 0, 0, address(hash));

-  if (!b) {

-    // hash is now invalid, but might not be NULL, so stomp on it

-    DWORD err = ::GetLastError();

-    ASSERT(!hash, (L""));

-    UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"

-                  L"[could not create hash, err 0x%08lx]", err));

-    return HRESULT_FROM_WIN32(err);

-  }

-  UTIL_LOG(L3, (L"CryptoComputeSignature::Sign new hash 0x%08lx", get(hash)));

-

-  b = ::CryptHashData(get(hash), &buffer_in.front(), buffer_in.size(), 0);

-  if (!b) {

-    DWORD err = ::GetLastError();

-    UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"

-                  L"[could not hash data, err 0x%08lx]", err));

-    return HRESULT_FROM_WIN32(err);

-  }

-

-  // Sign the hash (first get length, then allocate buffer and do real signing)

-  DWORD signature_len = 0;

-  b = ::CryptSignHash(get(hash),

-                      kKeyPairType,

-                      NULL,

-                      0 /*flags*/,

-                      NULL,

-                      &signature_len);

-  if (!b && ::GetLastError() != ERROR_MORE_DATA) {

-    DWORD err = ::GetLastError();

-    UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"

-                  L"[could not compute size of signature, err 0x%08lx]", err));

-    return HRESULT_FROM_WIN32(err);

-  }

-  signature_out->resize(signature_len);

-  b = ::CryptSignHash(get(hash),

-                      kKeyPairType,

-                      NULL,

-                      0,

-                      &signature_out->front(),

-                      &signature_len);

-  if (!b) {

-    DWORD err = ::GetLastError();

-    UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"

-                  L"[could not compute signature, err 0x%08lx]", err));

-    return HRESULT_FROM_WIN32(err);

-  }

-  ASSERT(signature_len == signature_out->size(), (L""));

-

-  UTIL_LOG(L3, (L"[CryptoComputeSignature::Sign]"

-                L"[have %d byte signature]", signature_out->size()));

-

-  return S_OK;

-}

-

-// To verify signed data you need a CSP, and you also need the public

-// key extracted from a certificate.  The CSP can be any RSA CSP on the

-// machine, the default one is fine.  To get the public key you start

-// by importing a certificate in standard "DER encoded" format.  That

-// returns a giant data structure, one field of which is the public key

-// in a format that CryptoAPI understands.  You import this public key

-// into the CSP with the CryptImportPublicKey() API, and then create a

-// key object from it suitable for use with the verification API.

-

-CryptoSignatureVerificationCertificate::CryptoSignatureVerificationCertificate() {   // NOLINT

-}

-

-CryptoSignatureVerificationCertificate::~CryptoSignatureVerificationCertificate() {  // NOLINT

-}

-

-HRESULT CryptoSignatureVerificationCertificate::ImportCertificate(

-    const TCHAR * filepath,

-    const TCHAR * subject_name) {

-  ASSERT(filepath, (L""));

-  std::vector<byte> buffer;

-  HRESULT hr = ReadEntireFile(filepath, kMaxCertificateSize, &buffer);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"

-                  L"['%s' not read, hr 0x%08lx]", filepath, hr));

-    return hr;

-  }

-  return ImportCertificate(buffer, subject_name);

-}

-

-HRESULT CryptoSignatureVerificationCertificate::ImportCertificate(

-    const std::vector<byte>& certificate_in,

-    const TCHAR * subject_name) {

-  // Import the certificate

-  ASSERT1(!certificate_in.empty());

-  reset(certificate_, ::CertCreateCertificateContext(kEncodingType,

-                                                     &certificate_in.front(),

-                                                     certificate_in.size()));

-  if (!certificate_) {

-    DWORD err = ::GetLastError();

-    UTIL_LOG(LE, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"

-                  L"[could not import certificate, err 0x%08lx]", err));

-    return SIGS_E_INVALID_DER_CERTIFICATE;

-  }

-  UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"

-                L"[new certificate 0x%08lx]", get(certificate_)));

-

-  // Get certificate's subject name

-  DWORD name_len = ::CertGetNameString(get(certificate_),

-                                       kCertificateNameType,

-                                       0 /*flags*/,

-                                       NULL,

-                                       NULL,

-                                       0);

-  if (name_len <= 1) {

-    // Name attribute not found - should never happen

-    ASSERT(0, (L"CryptoSignatureVerificationCertificate failed to get "

-               L"certificate name length, err 0x%08lx", ::GetLastError()));

-    return E_FAIL;

-  }

-  // name_len includes the terminating NULL

-

-  std::vector <TCHAR> name;

-  name.resize(name_len);

-  ASSERT1(!name.empty());

-  DWORD name_len2 = ::CertGetNameString(get(certificate_),

-                                        kCertificateNameType,

-                                        0,

-                                        NULL,

-                                        &name.front(),

-                                        name_len);

-  ASSERT(name_len2 == name_len, (L""));

-

-  UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"

-                L"['%s' is subject of certificate]", &name.front()));

-

-  subject_name_ = &name.front();

-

-  // Check the name if the user so desires.

-  if (subject_name && (0 != String_StrNCmp(&name.front(),

-                                           subject_name,

-                                           ::lstrlen(subject_name), false))) {

-      // name mismatch

-    UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"

-                  L"[not the right certificate, we're looking for '%s']",

-                  subject_name));

-    return E_FAIL;

-  }

-

-  return S_OK;

-}

-

-HRESULT CryptoSignatureVerificationCertificate::GetCSPContextAndKey(

-    HCRYPTPROV* csp_context,

-    HCRYPTKEY* public_key) {

-  ASSERT(csp_context, (L""));

-  ASSERT(public_key, (L""));

-  ASSERT(get(certificate_), (L""));

-

-  // Get the public key out of the certificate

-  PCERT_INFO cert_info = get(certificate_)->pCertInfo;

-  ASSERT(cert_info, (L""));

-  PCERT_PUBLIC_KEY_INFO public_key_info = &cert_info->SubjectPublicKeyInfo;

-  ASSERT(public_key_info, (L""));

-

-  // Reset the CSP and key in case it has been used already

-  reset(key_);

-  reset(csp_);

-

-  // Get the default CSP.  With CRYPT_VERIFYCONTEXT don't need to worry

-  // about creating/destroying a key container.

-  // TODO(omaha):  Why wasn't PROV_RSA_SIG available?  Maybe looking for the

-  // default isn't a good idea?

-  BOOL b = ::CryptAcquireContext(address(csp_),

-                                 NULL,

-                                 NULL,

-                                 kProviderType,

-                                 CRYPT_VERIFYCONTEXT|CRYPT_SILENT);

-  if (!b) {

-    DWORD err = ::GetLastError();

-    UTIL_LOG(LE, (L"[GetCSPContextAndKey]"

-                  L"[failed to acquire CSP, err 0x%08lx]", err));

-    return HRESULT_FROM_WIN32(err);

-  }

-  UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::GetCSPContextAndKey]"

-                L"[new CSP 0x%08lx]", get(csp_)));

-

-  // Convert the public key in encoded form into a CryptoAPI HCRYPTKEY

-  b = ::CryptImportPublicKeyInfo(get(csp_),

-                                 kEncodingType,

-                                 public_key_info,

-                                 address(key_));

-  if (!b) {

-    DWORD err = ::GetLastError();

-    UTIL_LOG(LE, (L"[GetCSPContextAndKey]"

-                  L"[failed to import public key, err 0x%08lx]", err));

-    return HRESULT_FROM_WIN32(err);

-  }

-  UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::GetCSPContextAndKey]"

-                L"[new key 0x%08lx]", get(key_)));

-

-  *csp_context = get(csp_);

-  *public_key = get(key_);

-

-  return S_OK;

-}

-

-// To verify the signature of some data using CryptoAPI you first hash

-// it into a hash object, then verify it using the CSP and a public key.

-// In this case the CryptVerifySignature takes the key (of type

-// AT_SIGNATURE) as a separate parameter. The

-// CryptoSignatureVerificationCertificate can provide the proper CSP and

-// the public key from the certificate.

-

-CryptoVerifySignature::CryptoVerifySignature(

-    CryptoSignatureVerificationCertificate& certificate)

-    : certificate_(&certificate) {

-}

-

-CryptoVerifySignature::~CryptoVerifySignature() {

-}

-

-HRESULT CryptoVerifySignature::Validate(const TCHAR* filepath,

-                                        uint32 max_len,

-                                        const std::vector<byte>& signature_in) {

-  ASSERT(filepath, (L""));

-  std::vector<byte> buffer;

-  HRESULT hr = ReadEntireFile(filepath, max_len, &buffer);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (L"[CryptoVerifySignature::Validate]"

-                  L"['%s' not read, hr 0x%08lx]", filepath, hr));

-    return hr;

-  }

-  return Validate(buffer, signature_in);

-}

-

-HRESULT CryptoVerifySignature::Validate(const std::vector<byte>& buffer_in,

-                                        const std::vector<byte>& signature_in) {

-  ASSERT(certificate_, (L""));

-  ASSERT1(!buffer_in.empty());

-  ASSERT1(!signature_in.empty());

-

-  UTIL_LOG(L2, (L"[CryptoVerifySignature::Validate]"

-                L"[buffer of %d bytes, signature of %d bytes]",

-                buffer_in.size(), signature_in.size()));

-

-  // Get the CSP context and the public key from the certificate

-  HCRYPTPROV csp = NULL;

-  HCRYPTKEY key = NULL;

-  HRESULT hr = certificate_->GetCSPContextAndKey(&csp, &key);

-  ASSERT(SUCCEEDED(hr) && csp && key, (L""));

-

-  // Hash the data

-  CryptDetails::scoped_crypt_hash hash;

-  BOOL b = ::CryptCreateHash(csp, kHashAlgorithm, 0, 0, address(hash));

-  if (!b) {

-    // hash is now invalid, but might not be NULL, so stomp on it

-    DWORD err = ::GetLastError();

-    ASSERT(!hash, (L""));

-    UTIL_LOG(LE, (L"[CrypoVerifySignature::Validate]"

-                  L"[could not create hash], err 0x%08lx", err));

-    return HRESULT_FROM_WIN32(err);

-  }

-  UTIL_LOG(L3, (L"CryptoVerifySignature::Validate new hash 0x%08lx", hash));

-

-  b = ::CryptHashData(get(hash),

-                      &buffer_in.front(),

-                      buffer_in.size(),

-                      0 /*flags*/);

-  if (!b) {

-    DWORD err = ::GetLastError();

-    UTIL_LOG(LE, (L"[CryptoVerifySignature::Validate]"

-                  L"[could not hash data, err 0x%08lx]", err));

-    return HRESULT_FROM_WIN32(err);

-  }

-

-  // Verify the hash

-  b = ::CryptVerifySignature(get(hash),

-                             &signature_in.front(),

-                             signature_in.size(),

-                             key,

-                             NULL,

-                             0 /*flags*/);

-  if (!b) {

-    DWORD err = ::GetLastError();

-#ifdef LOGGING

-    CString encoded_signature;

-    Base64::Encode(signature_in, &encoded_signature, false);

-

-    UTIL_LOG(LE, (_T("CryptoVerifySignature::Validate could not ")

-                  _T("verify signature, err 0x%08lx with sig \"%s\""),

-                  err, encoded_signature));

-#endif

-    if (err == NTE_BAD_SIGNATURE)

-      return SIGS_E_INVALID_SIGNATURE;

-    else

-      return HRESULT_FROM_WIN32(err);

-  }

-

-  return S_OK;

-}

-

-HRESULT SignData(const TCHAR* certificate_path,

-                 const TCHAR* certificate_password,

-                 const TCHAR* certificate_subject_name,

-                 const std::vector<byte>& data,

-                 CString* signature_base64) {

-  ASSERT(certificate_path, (L""));

-  ASSERT(certificate_password, (L""));

-  // certificate_subject_name can be NULL

-  ASSERT(signature_base64, (L""));

-

-  CryptoSigningCertificate certificate;

-  RET_IF_FAILED(certificate.ImportCertificate(certificate_path,

-                                              certificate_password,

-                                              certificate_subject_name));

-

-  CryptoComputeSignature signer(&certificate);

-  std::vector<byte> signature;

-  RET_IF_FAILED(signer.Sign(data, &signature));

-  RET_IF_FAILED(Base64::Encode(signature, signature_base64, false));

-

-  return S_OK;

-}

-

-HRESULT VerifyData(const TCHAR* certificate_path,

-                   const TCHAR* certificate_subject_name,

-                   const std::vector<byte>& data,

-                   const TCHAR* signature_base64) {

-  ASSERT(certificate_path, (L""));

-  // certificate_subject_name can be NULL

-  ASSERT(signature_base64, (L""));

-

-  std::vector<byte> signature;

-  RET_IF_FAILED(Base64::Decode(CString(signature_base64), &signature));

-

-  CryptoSignatureVerificationCertificate certificate;

-  RET_IF_FAILED(certificate.ImportCertificate(certificate_path,

-                                              certificate_subject_name));

-

-  CryptoVerifySignature verifier(certificate);

-  RET_IF_FAILED(verifier.Validate(data, signature));

-

-  return S_OK;

-}

-

-HRESULT VerifyData(const std::vector<byte>& certificate_buffer,

-                   const TCHAR* certificate_subject_name,

-                   const std::vector<byte>& data,

-                   const TCHAR* signature_base64) {

-  // certificate_subject_name can be NULL

-  ASSERT(signature_base64, (L""));

-

-  std::vector<byte> signature;

-  RET_IF_FAILED(Base64::Decode(CString(signature_base64), &signature));

-

-  CryptoSignatureVerificationCertificate certificate;

-  RET_IF_FAILED(certificate.ImportCertificate(certificate_buffer,

-                                              certificate_subject_name));

-

-  CryptoVerifySignature verifier(certificate);

-  RET_IF_FAILED(verifier.Validate(data, signature));

-

-  return S_OK;

-}

-

-// Authenticate files

-HRESULT AuthenticateFiles(const std::vector<CString>& files,

-                          const CString& hash) {

-  ASSERT1(files.size() > 0);

-  ASSERT1(!hash.IsEmpty());

-

-  // Test the bytes against its hash

-  std::vector<byte> hash_vector;

-  RET_IF_FAILED(Base64::Decode(hash, &hash_vector));

-  ASSERT1(hash_vector.size() == CryptoHash::kHashSize);

-

-  CryptoHash crypto;

-  return crypto.Validate(files, kMaxFileSizeForAuthentication, hash_vector);

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// signatures.cpp
+//
+// Classes and functions related to crypto-hashes of buffers and digital
+// signatures of buffers.
+
+#include "omaha/common/signatures.h"
+#include <wincrypt.h>
+#include <memory.h>
+
+#pragma warning(disable : 4245)
+// C4245 : conversion from 'type1' to 'type2', signed/unsigned mismatch
+#include <atlenc.h>
+#pragma warning(default : 4245)
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/const_utils.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/sha.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+const ALG_ID kHashAlgorithm = CALG_SHA1;
+const DWORD kEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
+const DWORD kProviderType = PROV_RSA_FULL;
+const DWORD kCertificateNameType = CERT_NAME_SIMPLE_DISPLAY_TYPE;
+const DWORD kKeyPairType = AT_SIGNATURE;
+
+namespace CryptDetails {
+
+  // Useful scoped pointers for working with CryptoAPI objects
+
+  void crypt_release_context(HCRYPTPROV provider) {
+    UTIL_LOG(L3, (L"Releasing HCRYPTPROV 0x%08lx", provider));
+    BOOL b = ::CryptReleaseContext(provider, 0 /*flags*/);
+    ASSERT(b, (L""));
+  }
+
+  void crypt_close_store(HCERTSTORE store) {
+    UTIL_LOG(L3, (L"Releasing HCERTSTORE 0x%08lx", store));
+    BOOL b = ::CertCloseStore(store, 0 /*flags*/);
+    ASSERT(b, (L""));
+    ASSERT(::GetLastError() != CRYPT_E_PENDING_CLOSE, (L""));
+  }
+
+  void crypt_free_certificate(PCCERT_CONTEXT certificate) {
+    UTIL_LOG(L3, (L"Releasing PCCERT_CONTEXT 0x%08lx", certificate));
+    BOOL b = ::CertFreeCertificateContext(certificate);
+    ASSERT(b, (L""));
+  }
+
+  void crypt_destroy_key(HCRYPTKEY key) {
+    UTIL_LOG(L3, (L"Releasing HCRYPTKEY 0x%08lx", key));
+    BOOL b = ::CryptDestroyKey(key);
+    ASSERT(b, (L""));
+  }
+
+  void crypt_destroy_hash(HCRYPTHASH hash) {
+    UTIL_LOG(L3, (L"Releasing HCRYPTHASH 0x%08lx", hash));
+    BOOL b = ::CryptDestroyHash(hash);
+    ASSERT(b, (L""));
+  }
+
+  typedef close_fun<void (*)(HCRYPTHASH),
+                    crypt_destroy_hash> smart_destroy_hash;
+  typedef scoped_any<HCRYPTHASH, smart_destroy_hash, null_t> scoped_crypt_hash;
+}
+
+// Base64 encode/decode functions are part of ATL Server
+HRESULT Base64::Encode(const std::vector<byte>& buffer_in,
+                       std::vector<byte>* encoded,
+                       bool break_into_lines) {
+  ASSERT(encoded, (L""));
+
+  if (buffer_in.empty()) {
+    encoded->resize(0);
+    return S_OK;
+  }
+
+  int32 encoded_len =
+    Base64EncodeGetRequiredLength(
+        buffer_in.size(),
+        break_into_lines ? ATL_BASE64_FLAG_NONE : ATL_BASE64_FLAG_NOCRLF);
+  ASSERT(encoded_len > 0, (L""));
+
+  encoded->resize(encoded_len);
+  int32 str_out_len = encoded_len;
+
+  BOOL result = Base64Encode(
+      &buffer_in.front(),
+      buffer_in.size(),
+      reinterpret_cast<char*>(&encoded->front()),
+      &str_out_len,
+      break_into_lines ? ATL_BASE64_FLAG_NONE : ATL_BASE64_FLAG_NOCRLF);
+  if (!result)
+    return E_FAIL;
+  ASSERT(str_out_len <= encoded_len, (L""));
+  if (str_out_len < encoded_len)
+    encoded->resize(str_out_len);
+
+  return S_OK;
+}
+
+HRESULT Base64::Encode(const std::vector<byte>& buffer_in,
+                       CStringA* encoded,
+                       bool break_into_lines) {
+  ASSERT(encoded, (L""));
+
+  if (buffer_in.empty()) {
+    return S_OK;
+  }
+
+  std::vector<byte> buffer_out;
+  RET_IF_FAILED(Encode(buffer_in, &buffer_out, break_into_lines));
+  encoded->Append(reinterpret_cast<const char*>(&buffer_out.front()),
+                                                buffer_out.size());
+
+  return S_OK;
+}
+
+HRESULT Base64::Encode(const std::vector<byte>& buffer_in,
+                       CString* encoded,
+                       bool break_into_lines) {
+  ASSERT(encoded, (L""));
+
+  CStringA string_out;
+  RET_IF_FAILED(Encode(buffer_in, &string_out, break_into_lines));
+  *encoded = string_out;
+
+  return S_OK;
+}
+
+HRESULT Base64::Decode(const std::vector<byte>& encoded,
+                       std::vector<byte>* buffer_out) {
+  ASSERT(buffer_out, (L""));
+
+  size_t encoded_len = encoded.size();
+  int32 required_len = Base64DecodeGetRequiredLength(encoded_len);
+
+  buffer_out->resize(required_len);
+
+  if (required_len == 0) {
+    return S_OK;
+  }
+
+  int32 bytes_written = required_len;
+  BOOL result = Base64Decode(reinterpret_cast<const char*>(&encoded.front()),
+                             encoded_len,
+                             &buffer_out->front(),
+                             &bytes_written);
+  if (!result)
+    return E_FAIL;
+  ASSERT(bytes_written <= required_len, (L""));
+  if (bytes_written < required_len) {
+    buffer_out->resize(bytes_written);
+  }
+
+  return S_OK;
+}
+
+HRESULT Base64::Decode(const CStringA& encoded, std::vector<byte>* buffer_out) {
+  ASSERT(buffer_out, (L""));
+
+  size_t encoded_len = encoded.GetLength();
+  std::vector<byte> buffer_in(encoded_len);
+  if (encoded_len != 0) {
+    ::memcpy(&buffer_in.front(), encoded.GetString(), encoded_len);
+  }
+
+  return Decode(buffer_in, buffer_out);
+}
+
+// Base64 in a CString -> binary
+HRESULT Base64::Decode(const CString& encoded, std::vector<byte>* buffer_out) {
+  ASSERT(buffer_out, (L""));
+
+  CW2A encoded_a(encoded.GetString());
+
+  size_t encoded_len = ::strlen(encoded_a);
+  std::vector<byte> buffer_in(encoded_len);
+  if (encoded_len != 0) {
+    ::memcpy(&buffer_in.front(), encoded_a, encoded_len);
+  }
+
+  return Decode(buffer_in, buffer_out);
+}
+
+// Using google SHA-1 algorithms rather than CryptoAPI SHA-1
+// algorithms; saves the trouble of dealing with CSPs and the like.
+
+CryptoHash::CryptoHash() {
+}
+
+CryptoHash::~CryptoHash() {
+}
+
+HRESULT CryptoHash::Compute(const TCHAR* filepath,
+                            uint64 max_len,
+                            std::vector<byte>* hash_out) {
+  ASSERT1(filepath);
+  ASSERT1(hash_out);
+
+  std::vector<CString> filepaths;
+  filepaths.push_back(filepath);
+  return Compute(filepaths, max_len, hash_out);
+}
+
+HRESULT CryptoHash::Compute(const std::vector<CString>& filepaths,
+                            uint64 max_len,
+                            std::vector<byte>* hash_out) {
+  ASSERT1(filepaths.size() > 0);
+  ASSERT1(hash_out);
+
+  return ComputeOrValidate(filepaths, max_len, NULL, hash_out);
+}
+
+HRESULT CryptoHash::Compute(const std::vector<byte>& buffer_in,
+                            std::vector<byte>* hash_out) {
+  ASSERT1(buffer_in.size() > 0);
+  ASSERT1(hash_out);
+
+  return ComputeOrValidate(buffer_in, NULL, hash_out);
+}
+
+HRESULT CryptoHash::Validate(const TCHAR* filepath,
+                             uint64 max_len,
+                             const std::vector<byte>& hash_in) {
+  ASSERT1(filepath);
+  ASSERT1(hash_in.size() == kHashSize);
+
+  std::vector<CString> filepaths;
+  filepaths.push_back(filepath);
+  return Validate(filepaths, max_len, hash_in);
+}
+
+HRESULT CryptoHash::Validate(const std::vector<CString>& filepaths,
+                             uint64 max_len,
+                             const std::vector<byte>& hash_in) {
+  ASSERT1(hash_in.size() == kHashSize);
+
+  return ComputeOrValidate(filepaths, max_len, &hash_in, NULL);
+}
+
+
+HRESULT CryptoHash::Validate(const std::vector<byte>& buffer_in,
+                             const std::vector<byte>& hash_in) {
+  ASSERT1(buffer_in.size() > 0);
+  ASSERT1(hash_in.size() == kHashSize);
+
+  return ComputeOrValidate(buffer_in, &hash_in, NULL);
+}
+
+HRESULT CryptoHash::ComputeOrValidate(const std::vector<CString>& filepaths,
+                                      uint64 max_len,
+                                      const std::vector<byte>* hash_in,
+                                      std::vector<byte>* hash_out) {
+  ASSERT1(filepaths.size() > 0);
+  ASSERT1(hash_in && !hash_out || !hash_in && hash_out);
+
+  byte buf[1024] = {0};
+  SecureHashAlgorithm sha;
+  uint64 curr_len = 0;
+  for (size_t i = 0; i < filepaths.size(); ++i) {
+    scoped_hfile file_handle(::CreateFile(filepaths[i],
+                                          FILE_READ_DATA,
+                                          FILE_SHARE_READ,
+                                          NULL,
+                                          OPEN_EXISTING,
+                                          FILE_ATTRIBUTE_NORMAL,
+                                          NULL));
+    if (!file_handle) {
+      return HRESULTFromLastError();
+    }
+
+    if (max_len) {
+      LARGE_INTEGER file_size = {0};
+      if (!::GetFileSizeEx(get(file_handle), &file_size)) {
+        return HRESULTFromLastError();
+      }
+      curr_len += ((static_cast<uint64>(file_size.HighPart)) << 32) +
+                  static_cast<uint64>(file_size.LowPart);
+      if (curr_len > max_len) {
+        UTIL_LOG(LE, (_T("[CryptoHash::ComputeOrValidate]")
+                      _T(" exceed max len][curr_len=%lu][max_len=%lu]"),
+                      curr_len, max_len));
+        return E_FAIL;
+      }
+    }
+
+    DWORD bytes_read = 0;
+    do {
+      if (!::ReadFile(get(file_handle),
+                      buf,
+                      arraysize(buf),
+                      &bytes_read,
+                      NULL)) {
+        return HRESULTFromLastError();
+      }
+
+      if (bytes_read > 0) {
+        sha.AddBytes(buf, bytes_read);
+      }
+    } while (bytes_read == arraysize(buf));
+  }
+  sha.Finished();
+
+  if (hash_in) {
+    int res = ::memcmp(&hash_in->front(), sha.Digest(), kHashSize);
+    if (res == 0) {
+      return S_OK;
+    }
+
+    std::vector<byte> calculated_hash(kHashSize);
+    memcpy(&calculated_hash.front(), sha.Digest(), kHashSize);
+    CStringA base64_encoded_hash;
+    Base64::Encode(calculated_hash, &base64_encoded_hash, false);
+    CString hash = AnsiToWideString(base64_encoded_hash,
+                                    base64_encoded_hash.GetLength());
+    REPORT_LOG(L1, (_T("[actual hash=%s]"), hash));
+    return SIGS_E_INVALID_SIGNATURE;
+  } else {
+    hash_out->resize(kHashSize);
+    ::memcpy(&hash_out->front(), sha.Digest(), kHashSize);
+    return S_OK;
+  }
+}
+
+HRESULT CryptoHash::ComputeOrValidate(const std::vector<byte>& buffer_in,
+                                      const std::vector<byte>* hash_in,
+                                      std::vector<byte>* hash_out) {
+  ASSERT1(hash_in && !hash_out || !hash_in && hash_out);
+
+  SecureHashAlgorithm sha;
+  if (!buffer_in.empty()) {
+    sha.AddBytes(&buffer_in.front(), buffer_in.size());
+  }
+  sha.Finished();
+
+  if (hash_in) {
+    int res = ::memcmp(&hash_in->front(), sha.Digest(), kHashSize);
+    return (res == 0) ? S_OK : SIGS_E_INVALID_SIGNATURE;
+  } else {
+    hash_out->resize(kHashSize);
+    ::memcpy(&hash_out->front(), sha.Digest(), kHashSize);
+    return S_OK;
+  }
+}
+
+// To sign data you need a CSP with the proper private key installed.
+// To get a signing certificate you start with a PFX file.  This file
+// encodes a "certificate store" which can hold more than one
+// certificate.  (In general it can hold a certificate chain, but we
+// only use the signing certificate.)  There are special APIs to verify
+// the format of a PFX file and read it into a new certificate store.  A
+// password must be specified to read the PFX file as it is encrypted.
+// The password was set when the PFX file was exported or otherwise
+// created.  Then you search for the proper certificate in the store
+// (using the subject_name which tells who the certificate was issued
+// to).  Finally, to get a CSP with the certificate's private key
+// available there is a special API, CryptAcquireCertificatePrivateKey,
+// that takes a CSP and a certificate and makes the private key of the
+// certificate the private key of the CSP.
+
+CryptoSigningCertificate::CryptoSigningCertificate() : key_spec_(0) {
+}
+
+CryptoSigningCertificate::~CryptoSigningCertificate() {
+}
+
+HRESULT CryptoSigningCertificate::ImportCertificate(
+    const TCHAR * filepath,
+    const TCHAR * password,
+    const TCHAR * subject_name) {
+  ASSERT(filepath, (L""));
+  ASSERT(password, (L""));
+
+  std::vector<byte> buffer;
+  HRESULT hr = ReadEntireFile(filepath, kMaxCertificateSize, &buffer);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (L"[CryptoSigningCertificate::ImportCertificate]"
+                  L"['%s' not read, hr 0x%08lx]", filepath, hr));
+    return hr;
+  }
+  return ImportCertificate(buffer, password, subject_name);
+}
+
+HRESULT CryptoSigningCertificate::ImportCertificate(
+    const std::vector<byte>& certificate_in,
+    const TCHAR * password,
+    const TCHAR * subject_name) {
+  ASSERT(password, (L""));
+  ASSERT1(!certificate_in.empty());
+
+  UTIL_LOG(L2, (L"[CryptoSigningCertificate::ImportCertificate]"
+                L"[%d bytes, subject_name '%s']",
+                certificate_in.size(), subject_name ? subject_name : L""));
+
+  // CryptoAPI treats the certificate as a "blob"
+  CRYPT_DATA_BLOB blob;
+  blob.cbData = certificate_in.size();
+  blob.pbData = const_cast<BYTE*>(&certificate_in.front());
+
+  // Ensure that it is PFX formatted
+  BOOL b = ::PFXIsPFXBlob(&blob);
+  if (!b) {
+    ASSERT(0, (L"Invalid PFX certificate, err 0x%08lx", ::GetLastError()));
+    return SIGS_E_INVALID_PFX_CERTIFICATE;
+  }
+
+  // Make sure the password checks out
+  b = ::PFXVerifyPassword(&blob, password, 0 /* flags */);
+  if (!b) {
+    UTIL_LOG(LE, (L"[CryptoSigningCertificate::ImportCertificate]"
+                  L"[invalid password, err 0x%08lx]", ::GetLastError()));
+    return SIGS_E_INVALID_PASSWORD;
+  }
+
+  // Do the import from the certificate to a new certificate store
+  // TODO(omaha): Check that this is in fact a new certificate store, not an
+  // existing one.  If it is an existing one we'll need to delete the
+  // certificate later.
+  // The last parameter to ::PFXImportCertStore() is 0, indicating that we want
+  // the CSP to be "silent"; i.e., not prompt.
+  reset(store_, ::PFXImportCertStore(&blob, password, 0));
+  if (!store_) {
+    DWORD err = ::GetLastError();
+    ASSERT(0, (L"Failed to import PFX certificate into a certificate store, "
+               L"err 0x%08lx", err));
+    return HRESULT_FROM_WIN32(err);
+  }
+  UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"
+                L"[new store 0x%08lx]", get(store_)));
+
+  // Now that we have a store, look for the correct certificate.  (There may
+  // have been more than one in the PFX file, e.g., a certificate chain.)
+  PCCERT_CONTEXT certificate_context = NULL;
+  while ((certificate_context =
+          ::CertEnumCertificatesInStore(get(store_),
+                                        certificate_context)) != NULL) {
+    // Have a certificate, does it look like the right one?  Check the name
+    DWORD name_len = ::CertGetNameString(certificate_context,
+                                         kCertificateNameType,
+                                         0 /*flags*/,
+                                         NULL,
+                                         NULL,
+                                         0);
+    if (name_len <= 1) {
+      // Name attribute not found - should never happen
+      ASSERT(0, (L"CryptoSigningCertificate::ImportCertificate failed to get "
+                 L"certificate name length, err 0x%08lx", ::GetLastError()));
+      continue;
+    }
+    // name_len includes the terminating null
+
+    std::vector<TCHAR> name;
+    name.resize(name_len);
+    ASSERT1(!name.empty());
+    DWORD name_len2 = ::CertGetNameString(certificate_context,
+                                          kCertificateNameType,
+                                          0,
+                                          NULL,
+                                          &name.front(),
+                                          name_len);
+    ASSERT(name_len2 == name_len, (L""));
+
+    UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"
+                  L"[found '%s' in store]", &name.front()));
+
+    // Check the name if the user so desires.  (If subject_name == NULL then
+    // the first certificate found is used.)
+    if (subject_name && (0 != String_StrNCmp(&name.front(),
+                                             subject_name,
+                                             ::lstrlen(subject_name),
+                                             false))) {
+      // name mismatch
+      UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"
+                    L"[not the right certificate, we're looking for '%s']",
+                    subject_name));
+      continue;
+    }
+
+    // This is the right certificate
+    subject_name_ = &name.front();
+    reset(certificate_, certificate_context);
+    UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"
+                  L"[new certificate 0x%08lx]", get(certificate_)));
+    break;
+  }
+
+  return S_OK;
+}
+
+HRESULT CryptoSigningCertificate::GetCSPContext(HCRYPTPROV* csp_context) {
+  ASSERT(csp_context, (L""));
+  ASSERT(get(certificate_), (L""));
+
+  // CSP may have already been used - reset it
+  reset(csp_);
+
+  // Create a CSP context using the private key of the certificate we imported
+  // earlier.
+  HCRYPTPROV csp = NULL;
+  BOOL must_free_csp = FALSE;
+  BOOL b = ::CryptAcquireCertificatePrivateKey(get(certificate_),
+                                               0 /*flags*/,
+                                               0 /*reserved*/,
+                                               &csp,
+                                               &key_spec_,
+                                               &must_free_csp);
+  if (!b) {
+    DWORD err = ::GetLastError();
+    ASSERT(0, (L"CryptoSigningCertificate::GetCSPContext "
+               L"CryptAcquireCertificatePrivateKey failed, err 0x%08lx", err));
+    return HRESULT_FROM_WIN32(err);
+  }
+
+  // (Funky API returns a boolean which tells you whether it is your
+  // responsibility to delete the CSP context or not.)
+  if (must_free_csp) {
+    reset(csp_, csp);
+  }
+  if (get(csp_)) {
+    UTIL_LOG(L3, (L"[CryptoSigningCertificate::GetCSPContext new CSP 0x%08lx]",
+                  get(csp_)));
+  }
+
+  ASSERT(key_spec_ == AT_SIGNATURE || key_spec_ == AT_KEYEXCHANGE, (L""));
+  if (key_spec_ != kKeyPairType) {
+    UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"
+                  L"[requires a AT_SIGNATURE type key]"));
+    return SIGS_E_INVALID_KEY_TYPE;
+  }
+
+#ifdef _DEBUG
+  // Which CSP did we get?
+  char csp_name[256] = {0};
+  DWORD csp_name_len = arraysize(csp_name);
+  b = ::CryptGetProvParam(csp,
+                          PP_NAME,
+                          reinterpret_cast<BYTE*>(&csp_name[0]),
+                          &csp_name_len,
+                          0 /*flags*/);
+  if (!b) {
+    DWORD err = ::GetLastError();
+    UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"
+                  L"[error getting CSP name, err 0x%08lx]", err));
+  }
+  DWORD csp_prov_type;
+  DWORD csp_prov_type_len = sizeof(csp_prov_type);
+  b = ::CryptGetProvParam(csp,
+                          PP_PROVTYPE,
+                          reinterpret_cast<BYTE*>(&csp_prov_type),
+                          &csp_prov_type_len,
+                          0 /*flags*/);
+  if (!b) {
+    DWORD err = ::GetLastError();
+    UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"
+                  L"[error getting CSP provtype, err 0x%08lx]", err));
+  }
+  char csp_container[256] = {0};
+  DWORD csp_container_len = arraysize(csp_container);
+  b = ::CryptGetProvParam(csp,
+                          PP_CONTAINER,
+                          reinterpret_cast<BYTE*>(&csp_container[0]),
+                          &csp_container_len,
+                          0 /*flags*/);
+  if (!b) {
+    DWORD err = ::GetLastError();
+    UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"
+                  L"[error getting CSP current container name, err 0x%08lx]",
+                  err));
+  }
+  UTIL_LOG(L2, (L"[CryptoSigningCertificate::GetCSPContext]"
+                L"[have CSP '%S' (provtype %d) key container '%S']",
+                csp_name, csp_prov_type, csp_container));
+  // End of which CSP did we get
+#endif
+
+  *csp_context = csp;
+
+  UTIL_LOG(L2, (L"[CryptoSigningCertificate::GetCSPContext]"
+                L"[getting CSP with private key from certificate]"
+                L"[HCRYPTPROV 0x%08lx]", csp));
+
+  return S_OK;
+}
+
+// To sign some data using CryptoAPI you first hash it into a hash
+// object, then sign it using the CSP.  The CSP needs to have the
+// private key, of type AT_SIGNATURE, in it already, as it isn't a
+// parameter of the CryptSignHash API.  The CryptoSigningCertificate
+// can provide such a CSP.
+
+CryptoComputeSignature::CryptoComputeSignature(
+    CryptoSigningCertificate* certificate)
+    : certificate_(certificate) {
+}
+
+CryptoComputeSignature::~CryptoComputeSignature() {
+}
+
+HRESULT CryptoComputeSignature::Sign(TCHAR const * const filepath,
+                                     uint32 max_len,
+                                     std::vector<byte>* signature_out) {
+  ASSERT(filepath, (L""));
+  std::vector<byte> buffer;
+  HRESULT hr = ReadEntireFile(filepath, max_len, &buffer);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"
+                  L"['%s not read, hr 0x%08lx]", filepath, hr));
+    return hr;
+  }
+  return Sign(buffer, signature_out);
+}
+
+HRESULT CryptoComputeSignature::Sign(const std::vector<byte>& buffer_in,
+                                     std::vector<byte>* signature_out) {
+  ASSERT(signature_out, (L""));
+  ASSERT1(!buffer_in.empty());
+
+  UTIL_LOG(L2, (L"[CryptoComputeSignature::Sign]"
+                L"[buffer of %d bytes]", buffer_in.size()));
+
+  // Get the proper CSP with the private key (certificate retains ownership)
+  HCRYPTPROV csp = NULL;
+  HRESULT hr = certificate_->GetCSPContext(&csp);
+  ASSERT(SUCCEEDED(hr) && csp, (L""));
+
+  // Hash the data
+  CryptDetails::scoped_crypt_hash hash;
+  BOOL b = ::CryptCreateHash(csp, kHashAlgorithm, 0, 0, address(hash));
+  if (!b) {
+    // hash is now invalid, but might not be NULL, so stomp on it
+    DWORD err = ::GetLastError();
+    ASSERT(!hash, (L""));
+    UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"
+                  L"[could not create hash, err 0x%08lx]", err));
+    return HRESULT_FROM_WIN32(err);
+  }
+  UTIL_LOG(L3, (L"CryptoComputeSignature::Sign new hash 0x%08lx", get(hash)));
+
+  b = ::CryptHashData(get(hash), &buffer_in.front(), buffer_in.size(), 0);
+  if (!b) {
+    DWORD err = ::GetLastError();
+    UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"
+                  L"[could not hash data, err 0x%08lx]", err));
+    return HRESULT_FROM_WIN32(err);
+  }
+
+  // Sign the hash (first get length, then allocate buffer and do real signing)
+  DWORD signature_len = 0;
+  b = ::CryptSignHash(get(hash),
+                      kKeyPairType,
+                      NULL,
+                      0 /*flags*/,
+                      NULL,
+                      &signature_len);
+  if (!b && ::GetLastError() != ERROR_MORE_DATA) {
+    DWORD err = ::GetLastError();
+    UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"
+                  L"[could not compute size of signature, err 0x%08lx]", err));
+    return HRESULT_FROM_WIN32(err);
+  }
+  signature_out->resize(signature_len);
+  b = ::CryptSignHash(get(hash),
+                      kKeyPairType,
+                      NULL,
+                      0,
+                      &signature_out->front(),
+                      &signature_len);
+  if (!b) {
+    DWORD err = ::GetLastError();
+    UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"
+                  L"[could not compute signature, err 0x%08lx]", err));
+    return HRESULT_FROM_WIN32(err);
+  }
+  ASSERT(signature_len == signature_out->size(), (L""));
+
+  UTIL_LOG(L3, (L"[CryptoComputeSignature::Sign]"
+                L"[have %d byte signature]", signature_out->size()));
+
+  return S_OK;
+}
+
+// To verify signed data you need a CSP, and you also need the public
+// key extracted from a certificate.  The CSP can be any RSA CSP on the
+// machine, the default one is fine.  To get the public key you start
+// by importing a certificate in standard "DER encoded" format.  That
+// returns a giant data structure, one field of which is the public key
+// in a format that CryptoAPI understands.  You import this public key
+// into the CSP with the CryptImportPublicKey() API, and then create a
+// key object from it suitable for use with the verification API.
+
+CryptoSignatureVerificationCertificate::CryptoSignatureVerificationCertificate() {   // NOLINT
+}
+
+CryptoSignatureVerificationCertificate::~CryptoSignatureVerificationCertificate() {  // NOLINT
+}
+
+HRESULT CryptoSignatureVerificationCertificate::ImportCertificate(
+    const TCHAR * filepath,
+    const TCHAR * subject_name) {
+  ASSERT(filepath, (L""));
+  std::vector<byte> buffer;
+  HRESULT hr = ReadEntireFile(filepath, kMaxCertificateSize, &buffer);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"
+                  L"['%s' not read, hr 0x%08lx]", filepath, hr));
+    return hr;
+  }
+  return ImportCertificate(buffer, subject_name);
+}
+
+HRESULT CryptoSignatureVerificationCertificate::ImportCertificate(
+    const std::vector<byte>& certificate_in,
+    const TCHAR * subject_name) {
+  // Import the certificate
+  ASSERT1(!certificate_in.empty());
+  reset(certificate_, ::CertCreateCertificateContext(kEncodingType,
+                                                     &certificate_in.front(),
+                                                     certificate_in.size()));
+  if (!certificate_) {
+    DWORD err = ::GetLastError();
+    UTIL_LOG(LE, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"
+                  L"[could not import certificate, err 0x%08lx]", err));
+    return SIGS_E_INVALID_DER_CERTIFICATE;
+  }
+  UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"
+                L"[new certificate 0x%08lx]", get(certificate_)));
+
+  // Get certificate's subject name
+  DWORD name_len = ::CertGetNameString(get(certificate_),
+                                       kCertificateNameType,
+                                       0 /*flags*/,
+                                       NULL,
+                                       NULL,
+                                       0);
+  if (name_len <= 1) {
+    // Name attribute not found - should never happen
+    ASSERT(0, (L"CryptoSignatureVerificationCertificate failed to get "
+               L"certificate name length, err 0x%08lx", ::GetLastError()));
+    return E_FAIL;
+  }
+  // name_len includes the terminating NULL
+
+  std::vector <TCHAR> name;
+  name.resize(name_len);
+  ASSERT1(!name.empty());
+  DWORD name_len2 = ::CertGetNameString(get(certificate_),
+                                        kCertificateNameType,
+                                        0,
+                                        NULL,
+                                        &name.front(),
+                                        name_len);
+  ASSERT(name_len2 == name_len, (L""));
+
+  UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"
+                L"['%s' is subject of certificate]", &name.front()));
+
+  subject_name_ = &name.front();
+
+  // Check the name if the user so desires.
+  if (subject_name && (0 != String_StrNCmp(&name.front(),
+                                           subject_name,
+                                           ::lstrlen(subject_name), false))) {
+      // name mismatch
+    UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"
+                  L"[not the right certificate, we're looking for '%s']",
+                  subject_name));
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+HRESULT CryptoSignatureVerificationCertificate::GetCSPContextAndKey(
+    HCRYPTPROV* csp_context,
+    HCRYPTKEY* public_key) {
+  ASSERT(csp_context, (L""));
+  ASSERT(public_key, (L""));
+  ASSERT(get(certificate_), (L""));
+
+  // Get the public key out of the certificate
+  PCERT_INFO cert_info = get(certificate_)->pCertInfo;
+  ASSERT(cert_info, (L""));
+  PCERT_PUBLIC_KEY_INFO public_key_info = &cert_info->SubjectPublicKeyInfo;
+  ASSERT(public_key_info, (L""));
+
+  // Reset the CSP and key in case it has been used already
+  reset(key_);
+  reset(csp_);
+
+  // Get the default CSP.  With CRYPT_VERIFYCONTEXT don't need to worry
+  // about creating/destroying a key container.
+  // TODO(omaha):  Why wasn't PROV_RSA_SIG available?  Maybe looking for the
+  // default isn't a good idea?
+  BOOL b = ::CryptAcquireContext(address(csp_),
+                                 NULL,
+                                 NULL,
+                                 kProviderType,
+                                 CRYPT_VERIFYCONTEXT|CRYPT_SILENT);
+  if (!b) {
+    DWORD err = ::GetLastError();
+    UTIL_LOG(LE, (L"[GetCSPContextAndKey]"
+                  L"[failed to acquire CSP, err 0x%08lx]", err));
+    return HRESULT_FROM_WIN32(err);
+  }
+  UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::GetCSPContextAndKey]"
+                L"[new CSP 0x%08lx]", get(csp_)));
+
+  // Convert the public key in encoded form into a CryptoAPI HCRYPTKEY
+  b = ::CryptImportPublicKeyInfo(get(csp_),
+                                 kEncodingType,
+                                 public_key_info,
+                                 address(key_));
+  if (!b) {
+    DWORD err = ::GetLastError();
+    UTIL_LOG(LE, (L"[GetCSPContextAndKey]"
+                  L"[failed to import public key, err 0x%08lx]", err));
+    return HRESULT_FROM_WIN32(err);
+  }
+  UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::GetCSPContextAndKey]"
+                L"[new key 0x%08lx]", get(key_)));
+
+  *csp_context = get(csp_);
+  *public_key = get(key_);
+
+  return S_OK;
+}
+
+// To verify the signature of some data using CryptoAPI you first hash
+// it into a hash object, then verify it using the CSP and a public key.
+// In this case the CryptVerifySignature takes the key (of type
+// AT_SIGNATURE) as a separate parameter. The
+// CryptoSignatureVerificationCertificate can provide the proper CSP and
+// the public key from the certificate.
+
+CryptoVerifySignature::CryptoVerifySignature(
+    CryptoSignatureVerificationCertificate& certificate)
+    : certificate_(&certificate) {
+}
+
+CryptoVerifySignature::~CryptoVerifySignature() {
+}
+
+HRESULT CryptoVerifySignature::Validate(const TCHAR* filepath,
+                                        uint32 max_len,
+                                        const std::vector<byte>& signature_in) {
+  ASSERT(filepath, (L""));
+  std::vector<byte> buffer;
+  HRESULT hr = ReadEntireFile(filepath, max_len, &buffer);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (L"[CryptoVerifySignature::Validate]"
+                  L"['%s' not read, hr 0x%08lx]", filepath, hr));
+    return hr;
+  }
+  return Validate(buffer, signature_in);
+}
+
+HRESULT CryptoVerifySignature::Validate(const std::vector<byte>& buffer_in,
+                                        const std::vector<byte>& signature_in) {
+  ASSERT(certificate_, (L""));
+  ASSERT1(!buffer_in.empty());
+  ASSERT1(!signature_in.empty());
+
+  UTIL_LOG(L2, (L"[CryptoVerifySignature::Validate]"
+                L"[buffer of %d bytes, signature of %d bytes]",
+                buffer_in.size(), signature_in.size()));
+
+  // Get the CSP context and the public key from the certificate
+  HCRYPTPROV csp = NULL;
+  HCRYPTKEY key = NULL;
+  HRESULT hr = certificate_->GetCSPContextAndKey(&csp, &key);
+  ASSERT(SUCCEEDED(hr) && csp && key, (L""));
+
+  // Hash the data
+  CryptDetails::scoped_crypt_hash hash;
+  BOOL b = ::CryptCreateHash(csp, kHashAlgorithm, 0, 0, address(hash));
+  if (!b) {
+    // hash is now invalid, but might not be NULL, so stomp on it
+    DWORD err = ::GetLastError();
+    ASSERT(!hash, (L""));
+    UTIL_LOG(LE, (L"[CrypoVerifySignature::Validate]"
+                  L"[could not create hash], err 0x%08lx", err));
+    return HRESULT_FROM_WIN32(err);
+  }
+  UTIL_LOG(L3, (L"CryptoVerifySignature::Validate new hash 0x%08lx", hash));
+
+  b = ::CryptHashData(get(hash),
+                      &buffer_in.front(),
+                      buffer_in.size(),
+                      0 /*flags*/);
+  if (!b) {
+    DWORD err = ::GetLastError();
+    UTIL_LOG(LE, (L"[CryptoVerifySignature::Validate]"
+                  L"[could not hash data, err 0x%08lx]", err));
+    return HRESULT_FROM_WIN32(err);
+  }
+
+  // Verify the hash
+  b = ::CryptVerifySignature(get(hash),
+                             &signature_in.front(),
+                             signature_in.size(),
+                             key,
+                             NULL,
+                             0 /*flags*/);
+  if (!b) {
+    DWORD err = ::GetLastError();
+#ifdef LOGGING
+    CString encoded_signature;
+    Base64::Encode(signature_in, &encoded_signature, false);
+
+    UTIL_LOG(LE, (_T("CryptoVerifySignature::Validate could not ")
+                  _T("verify signature, err 0x%08lx with sig \"%s\""),
+                  err, encoded_signature));
+#endif
+    if (err == NTE_BAD_SIGNATURE)
+      return SIGS_E_INVALID_SIGNATURE;
+    else
+      return HRESULT_FROM_WIN32(err);
+  }
+
+  return S_OK;
+}
+
+HRESULT SignData(const TCHAR* certificate_path,
+                 const TCHAR* certificate_password,
+                 const TCHAR* certificate_subject_name,
+                 const std::vector<byte>& data,
+                 CString* signature_base64) {
+  ASSERT(certificate_path, (L""));
+  ASSERT(certificate_password, (L""));
+  // certificate_subject_name can be NULL
+  ASSERT(signature_base64, (L""));
+
+  CryptoSigningCertificate certificate;
+  RET_IF_FAILED(certificate.ImportCertificate(certificate_path,
+                                              certificate_password,
+                                              certificate_subject_name));
+
+  CryptoComputeSignature signer(&certificate);
+  std::vector<byte> signature;
+  RET_IF_FAILED(signer.Sign(data, &signature));
+  RET_IF_FAILED(Base64::Encode(signature, signature_base64, false));
+
+  return S_OK;
+}
+
+HRESULT VerifyData(const TCHAR* certificate_path,
+                   const TCHAR* certificate_subject_name,
+                   const std::vector<byte>& data,
+                   const TCHAR* signature_base64) {
+  ASSERT(certificate_path, (L""));
+  // certificate_subject_name can be NULL
+  ASSERT(signature_base64, (L""));
+
+  std::vector<byte> signature;
+  RET_IF_FAILED(Base64::Decode(CString(signature_base64), &signature));
+
+  CryptoSignatureVerificationCertificate certificate;
+  RET_IF_FAILED(certificate.ImportCertificate(certificate_path,
+                                              certificate_subject_name));
+
+  CryptoVerifySignature verifier(certificate);
+  RET_IF_FAILED(verifier.Validate(data, signature));
+
+  return S_OK;
+}
+
+HRESULT VerifyData(const std::vector<byte>& certificate_buffer,
+                   const TCHAR* certificate_subject_name,
+                   const std::vector<byte>& data,
+                   const TCHAR* signature_base64) {
+  // certificate_subject_name can be NULL
+  ASSERT(signature_base64, (L""));
+
+  std::vector<byte> signature;
+  RET_IF_FAILED(Base64::Decode(CString(signature_base64), &signature));
+
+  CryptoSignatureVerificationCertificate certificate;
+  RET_IF_FAILED(certificate.ImportCertificate(certificate_buffer,
+                                              certificate_subject_name));
+
+  CryptoVerifySignature verifier(certificate);
+  RET_IF_FAILED(verifier.Validate(data, signature));
+
+  return S_OK;
+}
+
+// Authenticate files
+HRESULT AuthenticateFiles(const std::vector<CString>& files,
+                          const CString& hash) {
+  ASSERT1(files.size() > 0);
+  ASSERT1(!hash.IsEmpty());
+
+  // Test the bytes against its hash
+  std::vector<byte> hash_vector;
+  RET_IF_FAILED(Base64::Decode(hash, &hash_vector));
+  ASSERT1(hash_vector.size() == CryptoHash::kHashSize);
+
+  CryptoHash crypto;
+  return crypto.Validate(files, kMaxFileSizeForAuthentication, hash_vector);
+}
+
+}  // namespace omaha
+
diff --git a/common/signatures.h b/common/signatures.h
index c5592be..0a23fe7 100644
--- a/common/signatures.h
+++ b/common/signatures.h
@@ -1,297 +1,297 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// signatures.h

-//

-// Classes and functions related to crypto-hashes of buffers and digital

-// signatures of buffers.

-

-#ifndef OMAHA_COMMON_SIGNATURES_H__

-#define OMAHA_COMMON_SIGNATURES_H__

-

-#include <windows.h>

-#include <wincrypt.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/sha.h"

-

-namespace omaha {

-

-// Forward decls of classes defined here

-class CryptoHash;

-class CryptoComputeSignature;

-class CryptoVerifySignature;

-class CryptoSigningCertificate;

-class CryptoSignatureVerificationCertificate;

-

-// Useful scoped pointers for working with CryptoAPI objects

-namespace CryptDetails {

-

-  void crypt_close_store(HCERTSTORE);

-  void crypt_release_context(HCRYPTPROV);

-  void crypt_free_certificate(PCCERT_CONTEXT);

-  void crypt_destroy_key(HCRYPTKEY);

-

-  typedef close_fun<void (*)(HCERTSTORE),crypt_close_store>          smart_close_store;       // NOLINT

-  typedef close_fun<void (*)(HCRYPTPROV),crypt_release_context>      smart_release_context;   // NOLINT

-  typedef close_fun<void (*)(PCCERT_CONTEXT),crypt_free_certificate> smart_free_certificate;  // NOLINT

-  typedef close_fun<void (*)(HCRYPTKEY),crypt_destroy_key>           smart_destroy_key;       // NOLINT

-

-  typedef scoped_any<HCERTSTORE,smart_close_store,null_t>            scoped_crypt_store;      // NOLINT

-  typedef scoped_any<HCRYPTPROV,smart_release_context,null_t>        scoped_crypt_context;    // NOLINT

-  typedef scoped_any<PCCERT_CONTEXT,smart_free_certificate,null_t>   scoped_crypt_cert;       // NOLINT

-  typedef scoped_any<HCRYPTKEY,smart_destroy_key,null_t>             scoped_crypt_key;        // NOLINT

-}

-

-// A namespace for encoding binary into base64 (portable ASCII) representation

-// and for decoding it again.

-namespace Base64 {

-  // Binary -> base64 in a buffer

-  HRESULT Encode(const std::vector<byte>& buffer_in,

-                 std::vector<byte>* encoded,

-                 bool break_into_lines = true);

-

-  // Binary -> base64 in a string

-  HRESULT Encode(const std::vector<byte>& buffer_in,

-                 CStringA* encoded,

-                 bool break_into_lines = true);

-

-  // Binary -> base64 in a wide string

-  HRESULT Encode(const std::vector<byte>& buffer_in,

-                 CString* encoded,

-                 bool break_into_lines = true);

-

-  // Base64 in a buffer -> binary

-  HRESULT Decode(const std::vector<byte>& encoded,

-                 std::vector<byte>* buffer_out);

-

-  // Base64 in a CStringA -> binary

-  HRESULT Decode(const CStringA& encoded, std::vector<byte>* buffer_out);

-

-  // Base64 in a CString -> binary

-  HRESULT Decode(const CString& encoded, std::vector<byte>* buffer_out);

-}

-

-

-// Compute and validate SHA-1 hashes of data

-class CryptoHash {

-  public:

-

-    CryptoHash();

-    ~CryptoHash();

-

-    static const int kHashSize = SecureHashAlgorithm::kDigestSize;

-

-    // Hash a file

-    HRESULT Compute(const TCHAR * filepath,

-                    uint64 max_len,

-                    std::vector<byte>* hash_out);

-

-    // Hash a list of files

-    HRESULT Compute(const std::vector<CString>& filepaths,

-                    uint64 max_len,

-                    std::vector<byte>* hash_out);

-

-    // Hash a buffer

-    HRESULT Compute(const std::vector<byte>& buffer_in,

-                    std::vector<byte>* hash_out);

-

-    // Verify hash of a file

-    HRESULT Validate(const TCHAR * filepath,

-                     uint64 max_len,

-                     const std::vector<byte>& hash_in);

-

-    // Verify hash of a list of files

-    HRESULT Validate(const std::vector<CString>& filepaths,

-                     uint64 max_len,

-                     const std::vector<byte>& hash_in);

-

-    // Verify hash of a buffer

-    HRESULT Validate(const std::vector<byte>& buffer_in,

-                     const std::vector<byte>& hash_in);

-

-  private:

-    // Compute or verify hash of a file

-    HRESULT ComputeOrValidate(const std::vector<CString>& filepaths,

-                              uint64 max_len,

-                              const std::vector<byte>* hash_in,

-                              std::vector<byte>* hash_out);

-

-    // Compute or verify hash of a buffer

-    HRESULT ComputeOrValidate(const std::vector<byte>& buffer_in,

-                              const std::vector<byte>* hash_in,

-                              std::vector<byte>* hash_out);

-

-    DISALLOW_EVIL_CONSTRUCTORS(CryptoHash);

-};

-

-

-// Import and use a certificate for signing data (has a private key)

-class CryptoSigningCertificate {

-  public:

-    CryptoSigningCertificate();

-    ~CryptoSigningCertificate();

-

-    // Import certificate - with both public key and private key.

-    // Must be in PFX format.  Password must unlock the PFX file.

-    // subject_name is the certificate's subject name (who it was

-    // issued to) - if not NULL then it is checked for an exact

-    // match against the certificate.

-

-    // User can get the certificate in PFX format by following the procedure at

-    // http://support.globalsign.net/en/objectsign/transform.cfm

-

-    HRESULT ImportCertificate(const TCHAR * filepath,

-                              const TCHAR * password,

-                              const TCHAR * subject_name);

-

-    HRESULT ImportCertificate(const std::vector<byte>& certificate_in,

-                              const TCHAR * password,

-                              const TCHAR * subject_name);

-

-    CString subject_name() { return subject_name_; }

-

-  private:

-    static const int kMaxCertificateSize = 100000;

-

-    CryptDetails::scoped_crypt_store   store_;

-    CryptDetails::scoped_crypt_cert    certificate_;

-    CryptDetails::scoped_crypt_context csp_;

-    CString subject_name_;

-    DWORD key_spec_;

-

-    friend class CryptoComputeSignature;

-    // Get the CSP with the private key

-    // (CryptoSigningCertificate retains ownership of csp_context.)

-    HRESULT GetCSPContext(HCRYPTPROV* csp_context);

-

-    DISALLOW_EVIL_CONSTRUCTORS(CryptoSigningCertificate);

-};

-

-

-// Compute digital signatures

-class CryptoComputeSignature {

-  public:

-    explicit CryptoComputeSignature(CryptoSigningCertificate* certificate);

-    ~CryptoComputeSignature();

-

-    // Sign a file, returning a separate signature

-    HRESULT Sign(const TCHAR * filepath,

-                 uint32 max_len,

-                 std::vector<byte>* signature_out);

-

-    // Sign a chunk of memory, returning a separate signature

-    HRESULT Sign(const std::vector<byte>& buffer_in,

-                 std::vector<byte>* signature_out);

-

-  private:

-    // Does not take ownership of the certificate

-    CryptoSigningCertificate* const certificate_;

-

-    DISALLOW_EVIL_CONSTRUCTORS(CryptoComputeSignature);

-};

-

-

-// Import and use a certificate for verifying signatures (has public key only)

-class CryptoSignatureVerificationCertificate {

-  public:

-    CryptoSignatureVerificationCertificate();

-    ~CryptoSignatureVerificationCertificate();

-

-    // Import certificate - with only public key.  Must be in DER (.cer) format.

-    // subject_name is the certificate's subject name (who it was

-    // issued to) - if not NULL then it is checked for an exact

-    // match against the certificate.

-

-    // User can get certificate in DER format (.cer) by exporting from

-    // certmgr.exe, using openssl, etc.)

-

-    HRESULT ImportCertificate(const TCHAR * filepath,

-                              const TCHAR * subject_name);

-    HRESULT ImportCertificate(const std::vector<byte>& certificate_in,

-                              const TCHAR * subject_name);

-

-    CString subject_name() { return subject_name_; }

-

-  private:

-    static const int kMaxCertificateSize = 100000;

-

-    CryptDetails::scoped_crypt_cert    certificate_;

-    CryptDetails::scoped_crypt_context csp_;

-    CryptDetails::scoped_crypt_key     key_;

-    CString subject_name_;

-

-    friend class CryptoVerifySignature;

-    // Get the CSP and the public key

-    // (CryptoSignatureVerificationCertificate retains ownership of csp_context

-    // and public_key.)

-    HRESULT GetCSPContextAndKey(HCRYPTPROV* csp_context, HCRYPTKEY* public_key);

-

-    DISALLOW_EVIL_CONSTRUCTORS(CryptoSignatureVerificationCertificate);

-};

-

-

-// Verify digital signatures

-class CryptoVerifySignature {

-  public:

-    explicit CryptoVerifySignature(

-        CryptoSignatureVerificationCertificate& certificate);

-    ~CryptoVerifySignature();

-

-    // Validate signature of a file, signature given separately

-    HRESULT Validate(const TCHAR * filepath,

-                     uint32 max_len,

-                     const std::vector<byte>& signature_in);

-

-    // Validate signature of a buffer of data, signature given separately

-    HRESULT Validate(const std::vector<byte>& buffer_in,

-                     const std::vector<byte>& signature_in);

-

-  private:

-    // Does not take ownership of the certificate

-    CryptoSignatureVerificationCertificate* const certificate_;

-

-    DISALLOW_EVIL_CONSTRUCTORS(CryptoVerifySignature);

-};

-

-

-// All-in-one routine to sign a chunk of data and return the signature

-// (encoded in base64)

-HRESULT SignData(const TCHAR* certificate_path,

-                 const TCHAR* certificate_password,

-                 const TCHAR* certificate_subject_name,

-                 const std::vector<byte>& data,

-                 CString* signature_base64);

-

-// All-in-one routine to verify the signature of a chunk of data

-HRESULT VerifyData(const TCHAR* certificate_path,

-                   const TCHAR* certificate_subject_name,

-                   const std::vector<byte>& data,

-                   const TCHAR* signature_base64);

-

-HRESULT VerifyData(const std::vector<byte>& certificate_buffer,

-                   const TCHAR* certificate_subject_name,

-                   const std::vector<byte>& data,

-                   const TCHAR* signature_base64);

-

-// Authenticate files

-HRESULT AuthenticateFiles(const std::vector<CString>& files,

-                          const CString& hash);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SIGNATURES_H__

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// signatures.h
+//
+// Classes and functions related to crypto-hashes of buffers and digital
+// signatures of buffers.
+
+#ifndef OMAHA_COMMON_SIGNATURES_H__
+#define OMAHA_COMMON_SIGNATURES_H__
+
+#include <windows.h>
+#include <wincrypt.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/sha.h"
+
+namespace omaha {
+
+// Forward decls of classes defined here
+class CryptoHash;
+class CryptoComputeSignature;
+class CryptoVerifySignature;
+class CryptoSigningCertificate;
+class CryptoSignatureVerificationCertificate;
+
+// Useful scoped pointers for working with CryptoAPI objects
+namespace CryptDetails {
+
+  void crypt_close_store(HCERTSTORE);
+  void crypt_release_context(HCRYPTPROV);
+  void crypt_free_certificate(PCCERT_CONTEXT);
+  void crypt_destroy_key(HCRYPTKEY);
+
+  typedef close_fun<void (*)(HCERTSTORE),crypt_close_store>          smart_close_store;       // NOLINT
+  typedef close_fun<void (*)(HCRYPTPROV),crypt_release_context>      smart_release_context;   // NOLINT
+  typedef close_fun<void (*)(PCCERT_CONTEXT),crypt_free_certificate> smart_free_certificate;  // NOLINT
+  typedef close_fun<void (*)(HCRYPTKEY),crypt_destroy_key>           smart_destroy_key;       // NOLINT
+
+  typedef scoped_any<HCERTSTORE,smart_close_store,null_t>            scoped_crypt_store;      // NOLINT
+  typedef scoped_any<HCRYPTPROV,smart_release_context,null_t>        scoped_crypt_context;    // NOLINT
+  typedef scoped_any<PCCERT_CONTEXT,smart_free_certificate,null_t>   scoped_crypt_cert;       // NOLINT
+  typedef scoped_any<HCRYPTKEY,smart_destroy_key,null_t>             scoped_crypt_key;        // NOLINT
+}
+
+// A namespace for encoding binary into base64 (portable ASCII) representation
+// and for decoding it again.
+namespace Base64 {
+  // Binary -> base64 in a buffer
+  HRESULT Encode(const std::vector<byte>& buffer_in,
+                 std::vector<byte>* encoded,
+                 bool break_into_lines = true);
+
+  // Binary -> base64 in a string
+  HRESULT Encode(const std::vector<byte>& buffer_in,
+                 CStringA* encoded,
+                 bool break_into_lines = true);
+
+  // Binary -> base64 in a wide string
+  HRESULT Encode(const std::vector<byte>& buffer_in,
+                 CString* encoded,
+                 bool break_into_lines = true);
+
+  // Base64 in a buffer -> binary
+  HRESULT Decode(const std::vector<byte>& encoded,
+                 std::vector<byte>* buffer_out);
+
+  // Base64 in a CStringA -> binary
+  HRESULT Decode(const CStringA& encoded, std::vector<byte>* buffer_out);
+
+  // Base64 in a CString -> binary
+  HRESULT Decode(const CString& encoded, std::vector<byte>* buffer_out);
+}
+
+
+// Compute and validate SHA-1 hashes of data
+class CryptoHash {
+  public:
+
+    CryptoHash();
+    ~CryptoHash();
+
+    static const int kHashSize = SecureHashAlgorithm::kDigestSize;
+
+    // Hash a file
+    HRESULT Compute(const TCHAR * filepath,
+                    uint64 max_len,
+                    std::vector<byte>* hash_out);
+
+    // Hash a list of files
+    HRESULT Compute(const std::vector<CString>& filepaths,
+                    uint64 max_len,
+                    std::vector<byte>* hash_out);
+
+    // Hash a buffer
+    HRESULT Compute(const std::vector<byte>& buffer_in,
+                    std::vector<byte>* hash_out);
+
+    // Verify hash of a file
+    HRESULT Validate(const TCHAR * filepath,
+                     uint64 max_len,
+                     const std::vector<byte>& hash_in);
+
+    // Verify hash of a list of files
+    HRESULT Validate(const std::vector<CString>& filepaths,
+                     uint64 max_len,
+                     const std::vector<byte>& hash_in);
+
+    // Verify hash of a buffer
+    HRESULT Validate(const std::vector<byte>& buffer_in,
+                     const std::vector<byte>& hash_in);
+
+  private:
+    // Compute or verify hash of a file
+    HRESULT ComputeOrValidate(const std::vector<CString>& filepaths,
+                              uint64 max_len,
+                              const std::vector<byte>* hash_in,
+                              std::vector<byte>* hash_out);
+
+    // Compute or verify hash of a buffer
+    HRESULT ComputeOrValidate(const std::vector<byte>& buffer_in,
+                              const std::vector<byte>* hash_in,
+                              std::vector<byte>* hash_out);
+
+    DISALLOW_EVIL_CONSTRUCTORS(CryptoHash);
+};
+
+
+// Import and use a certificate for signing data (has a private key)
+class CryptoSigningCertificate {
+  public:
+    CryptoSigningCertificate();
+    ~CryptoSigningCertificate();
+
+    // Import certificate - with both public key and private key.
+    // Must be in PFX format.  Password must unlock the PFX file.
+    // subject_name is the certificate's subject name (who it was
+    // issued to) - if not NULL then it is checked for an exact
+    // match against the certificate.
+
+    // User can get the certificate in PFX format by following the procedure at
+    // http://support.globalsign.net/en/objectsign/transform.cfm
+
+    HRESULT ImportCertificate(const TCHAR * filepath,
+                              const TCHAR * password,
+                              const TCHAR * subject_name);
+
+    HRESULT ImportCertificate(const std::vector<byte>& certificate_in,
+                              const TCHAR * password,
+                              const TCHAR * subject_name);
+
+    CString subject_name() { return subject_name_; }
+
+  private:
+    static const int kMaxCertificateSize = 100000;
+
+    CryptDetails::scoped_crypt_store   store_;
+    CryptDetails::scoped_crypt_cert    certificate_;
+    CryptDetails::scoped_crypt_context csp_;
+    CString subject_name_;
+    DWORD key_spec_;
+
+    friend class CryptoComputeSignature;
+    // Get the CSP with the private key
+    // (CryptoSigningCertificate retains ownership of csp_context.)
+    HRESULT GetCSPContext(HCRYPTPROV* csp_context);
+
+    DISALLOW_EVIL_CONSTRUCTORS(CryptoSigningCertificate);
+};
+
+
+// Compute digital signatures
+class CryptoComputeSignature {
+  public:
+    explicit CryptoComputeSignature(CryptoSigningCertificate* certificate);
+    ~CryptoComputeSignature();
+
+    // Sign a file, returning a separate signature
+    HRESULT Sign(const TCHAR * filepath,
+                 uint32 max_len,
+                 std::vector<byte>* signature_out);
+
+    // Sign a chunk of memory, returning a separate signature
+    HRESULT Sign(const std::vector<byte>& buffer_in,
+                 std::vector<byte>* signature_out);
+
+  private:
+    // Does not take ownership of the certificate
+    CryptoSigningCertificate* const certificate_;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CryptoComputeSignature);
+};
+
+
+// Import and use a certificate for verifying signatures (has public key only)
+class CryptoSignatureVerificationCertificate {
+  public:
+    CryptoSignatureVerificationCertificate();
+    ~CryptoSignatureVerificationCertificate();
+
+    // Import certificate - with only public key.  Must be in DER (.cer) format.
+    // subject_name is the certificate's subject name (who it was
+    // issued to) - if not NULL then it is checked for an exact
+    // match against the certificate.
+
+    // User can get certificate in DER format (.cer) by exporting from
+    // certmgr.exe, using openssl, etc.)
+
+    HRESULT ImportCertificate(const TCHAR * filepath,
+                              const TCHAR * subject_name);
+    HRESULT ImportCertificate(const std::vector<byte>& certificate_in,
+                              const TCHAR * subject_name);
+
+    CString subject_name() { return subject_name_; }
+
+  private:
+    static const int kMaxCertificateSize = 100000;
+
+    CryptDetails::scoped_crypt_cert    certificate_;
+    CryptDetails::scoped_crypt_context csp_;
+    CryptDetails::scoped_crypt_key     key_;
+    CString subject_name_;
+
+    friend class CryptoVerifySignature;
+    // Get the CSP and the public key
+    // (CryptoSignatureVerificationCertificate retains ownership of csp_context
+    // and public_key.)
+    HRESULT GetCSPContextAndKey(HCRYPTPROV* csp_context, HCRYPTKEY* public_key);
+
+    DISALLOW_EVIL_CONSTRUCTORS(CryptoSignatureVerificationCertificate);
+};
+
+
+// Verify digital signatures
+class CryptoVerifySignature {
+  public:
+    explicit CryptoVerifySignature(
+        CryptoSignatureVerificationCertificate& certificate);
+    ~CryptoVerifySignature();
+
+    // Validate signature of a file, signature given separately
+    HRESULT Validate(const TCHAR * filepath,
+                     uint32 max_len,
+                     const std::vector<byte>& signature_in);
+
+    // Validate signature of a buffer of data, signature given separately
+    HRESULT Validate(const std::vector<byte>& buffer_in,
+                     const std::vector<byte>& signature_in);
+
+  private:
+    // Does not take ownership of the certificate
+    CryptoSignatureVerificationCertificate* const certificate_;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CryptoVerifySignature);
+};
+
+
+// All-in-one routine to sign a chunk of data and return the signature
+// (encoded in base64)
+HRESULT SignData(const TCHAR* certificate_path,
+                 const TCHAR* certificate_password,
+                 const TCHAR* certificate_subject_name,
+                 const std::vector<byte>& data,
+                 CString* signature_base64);
+
+// All-in-one routine to verify the signature of a chunk of data
+HRESULT VerifyData(const TCHAR* certificate_path,
+                   const TCHAR* certificate_subject_name,
+                   const std::vector<byte>& data,
+                   const TCHAR* signature_base64);
+
+HRESULT VerifyData(const std::vector<byte>& certificate_buffer,
+                   const TCHAR* certificate_subject_name,
+                   const std::vector<byte>& data,
+                   const TCHAR* signature_base64);
+
+// Authenticate files
+HRESULT AuthenticateFiles(const std::vector<CString>& files,
+                          const CString& hash);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SIGNATURES_H__
diff --git a/common/signatures_unittest.cc b/common/signatures_unittest.cc
index ea937d6..f6ab978 100644
--- a/common/signatures_unittest.cc
+++ b/common/signatures_unittest.cc
@@ -1,162 +1,162 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// signatures_unittest.cpp

-//

-// Unittests for classes and functions related to crypto-hashes of buffers and

-// digital signatures of buffers.

-// TODO(omaha): There are a number of places inside the signatures code, where

-// empty vector iterators were being dereferenced. Ensure that all these are

-// being tested.

-

-#include <cstring>

-#include <vector>

-

-#include "omaha/common/signatures.h"

-#include "omaha/common/module_utils.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-struct {

-  char* binary;

-  char* base64;

-} test_data[] = {

-  "",                                "",

-  "what",                            "d2hhdA==",

-  "what will print out",             "d2hhdCB3aWxsIHByaW50IG91dA==",

-  "foobar",                          "Zm9vYmFy",

-  "a man, a plan, a canal: panama!", "YSBtYW4sIGEgcGxhbiwgYSBjYW5hbDogcGFuYW1hIQ==",    // NOLINT

-};

-

-// This test data from http://en.wikipedia.org/wiki/SHA-1:

-struct {

-  char* binary;

-  byte  hash[20];

-} test_hash[] = {

-  "The quick brown fox jumps over the lazy dog",

-    0x2f, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d, 0x28, 0xfc, 0xed, 0x84,

-    0x9e, 0xe1, 0xbb, 0x76, 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12,

-  "The quick brown fox jumps over the lazy cog",

-    0xde, 0x9f, 0x2c, 0x7f, 0xd2, 0x5e, 0x1b, 0x3a, 0xfa, 0xd3,

-    0xe8, 0x5a, 0x0b, 0xd1, 0x7d, 0x9b, 0x10, 0x0d, 0xb4, 0xb3,

-};

-

-}  // namespace

-

-TEST(SignaturesTest, Base64) {

-  for (size_t i = 0; i != arraysize(test_data); i++) {

-    std::vector<byte> buffer(strlen(test_data[i].binary));

-    if (strlen(test_data[i].binary) != 0) {

-      memcpy(&buffer.front(), test_data[i].binary, strlen(test_data[i].binary));

-    }

-    CStringA test_e;

-    ASSERT_SUCCEEDED(Base64::Encode(buffer, &test_e));

-    ASSERT_STREQ(test_e, test_data[i].base64);

-    std::vector<byte> test_d;

-    uint32 test_d_written = 0;

-    ASSERT_SUCCEEDED(Base64::Decode(test_e, &test_d));

-    ASSERT_EQ(test_d.size(), strlen(test_data[i].binary));

-    if (strlen(test_data[i].binary) != 0) {

-      ASSERT_EQ(0, memcmp(&test_d.front(),

-                          test_data[i].binary,

-                          strlen(test_data[i].binary)));

-    }

-  }

-}

-

-TEST(SignaturesTest, CryptoHash) {

-  CryptoHash chash;

-  for (size_t i = 0; i != arraysize(test_hash); i++) {

-    std::vector<byte> buffer(strlen(test_hash[i].binary));

-    memcpy(&buffer.front(), test_hash[i].binary, strlen(test_hash[i].binary));

-    std::vector<byte> hash;

-    ASSERT_SUCCEEDED(chash.Compute(buffer, &hash));

-    ASSERT_EQ(hash.size(), CryptoHash::kHashSize);

-    ASSERT_EQ(0, memcmp(&hash.front(),

-                        test_hash[i].hash,

-                        CryptoHash::kHashSize));

-    ASSERT_SUCCEEDED(chash.Validate(buffer, hash));

-  }

-}

-

-TEST(SignaturesTest, CreationVerification) {

-  // Load the test certificates from the directory where the unit test is

-  // running from. The test certificates are copied there during the build.

-  TCHAR directory[MAX_PATH] = {0};

-  ASSERT_TRUE(GetModuleDirectory(NULL, directory));

-  CString encoded_cert_with_private_key_path;

-  encoded_cert_with_private_key_path.AppendFormat(

-      _T("%s\\certificate-with-private-key.pfx"), directory);

-  CString encoded_cert_without_private_key_path;

-  encoded_cert_without_private_key_path.AppendFormat(

-      _T("%s\\certificate-without-private-key.cer"), directory);

-  CString raw_test_data_path;

-  raw_test_data_path.AppendFormat(_T("%s\\declaration.txt"), directory);

-

-  // Get cert with private key and cert without private key.

-  std::vector<byte> encoded_cert_with_private_key;

-  std::vector<byte> encoded_cert_without_private_key;

-  ASSERT_SUCCEEDED(ReadEntireFile(encoded_cert_with_private_key_path,

-                                  0,

-                                  &encoded_cert_with_private_key));

-  ASSERT_SUCCEEDED(ReadEntireFile(encoded_cert_without_private_key_path,

-                                  0,

-                                  &encoded_cert_without_private_key));

-  CString cert_password = _T("f00bar");

-  CString cert_subject_name = _T("Unofficial Google Test");

-

-  // Get testdata.

-  std::vector<byte> raw_testdata;

-  ASSERT_SUCCEEDED(ReadEntireFile(raw_test_data_path, 0, &raw_testdata));

-

-  // Create a signing certificate.

-  CryptoSigningCertificate signing_certificate;

-  ASSERT_SUCCEEDED(signing_certificate.ImportCertificate(

-      encoded_cert_with_private_key, cert_password, cert_subject_name));

-

-  // Create a signature object and sign the test data.

-  std::vector<byte> signature;

-  CryptoComputeSignature signer(&signing_certificate);

-  ASSERT_SUCCEEDED(signer.Sign(raw_testdata, &signature));

-

-  // Create a validating certificate.

-  CryptoSignatureVerificationCertificate verification_certificate;

-  ASSERT_SUCCEEDED(verification_certificate.ImportCertificate(

-      encoded_cert_without_private_key, cert_subject_name));

-

-  // Create a signature object and verify the test data's signature.

-  CryptoVerifySignature verifier(verification_certificate);

-  ASSERT_SUCCEEDED(verifier.Validate(raw_testdata, signature));

-

-  // Mess up the signature and show it doesn't verify.

-  size_t mid = signature.size() / 2;

-  byte mid_byte = signature[mid];

-  signature[mid] = ~mid_byte;

-  ASSERT_FAILED(verifier.Validate(raw_testdata, signature));

-

-  // Restore the signature, mess up the test data, and show it doesn't verify.

-  signature[mid] = mid_byte;

-  mid = raw_testdata.size() / 2;

-  mid_byte = raw_testdata[mid];

-  raw_testdata[mid] = ~mid_byte;

-  ASSERT_FAILED(verifier.Validate(raw_testdata, signature));

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// signatures_unittest.cpp
+//
+// Unittests for classes and functions related to crypto-hashes of buffers and
+// digital signatures of buffers.
+// TODO(omaha): There are a number of places inside the signatures code, where
+// empty vector iterators were being dereferenced. Ensure that all these are
+// being tested.
+
+#include <cstring>
+#include <vector>
+
+#include "omaha/common/signatures.h"
+#include "omaha/common/module_utils.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+struct {
+  char* binary;
+  char* base64;
+} test_data[] = {
+  "",                                "",
+  "what",                            "d2hhdA==",
+  "what will print out",             "d2hhdCB3aWxsIHByaW50IG91dA==",
+  "foobar",                          "Zm9vYmFy",
+  "a man, a plan, a canal: panama!", "YSBtYW4sIGEgcGxhbiwgYSBjYW5hbDogcGFuYW1hIQ==",    // NOLINT
+};
+
+// This test data from http://en.wikipedia.org/wiki/SHA-1:
+struct {
+  char* binary;
+  byte  hash[20];
+} test_hash[] = {
+  "The quick brown fox jumps over the lazy dog",
+    0x2f, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d, 0x28, 0xfc, 0xed, 0x84,
+    0x9e, 0xe1, 0xbb, 0x76, 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12,
+  "The quick brown fox jumps over the lazy cog",
+    0xde, 0x9f, 0x2c, 0x7f, 0xd2, 0x5e, 0x1b, 0x3a, 0xfa, 0xd3,
+    0xe8, 0x5a, 0x0b, 0xd1, 0x7d, 0x9b, 0x10, 0x0d, 0xb4, 0xb3,
+};
+
+}  // namespace
+
+TEST(SignaturesTest, Base64) {
+  for (size_t i = 0; i != arraysize(test_data); i++) {
+    std::vector<byte> buffer(strlen(test_data[i].binary));
+    if (strlen(test_data[i].binary) != 0) {
+      memcpy(&buffer.front(), test_data[i].binary, strlen(test_data[i].binary));
+    }
+    CStringA test_e;
+    ASSERT_SUCCEEDED(Base64::Encode(buffer, &test_e));
+    ASSERT_STREQ(test_e, test_data[i].base64);
+    std::vector<byte> test_d;
+    uint32 test_d_written = 0;
+    ASSERT_SUCCEEDED(Base64::Decode(test_e, &test_d));
+    ASSERT_EQ(test_d.size(), strlen(test_data[i].binary));
+    if (strlen(test_data[i].binary) != 0) {
+      ASSERT_EQ(0, memcmp(&test_d.front(),
+                          test_data[i].binary,
+                          strlen(test_data[i].binary)));
+    }
+  }
+}
+
+TEST(SignaturesTest, CryptoHash) {
+  CryptoHash chash;
+  for (size_t i = 0; i != arraysize(test_hash); i++) {
+    std::vector<byte> buffer(strlen(test_hash[i].binary));
+    memcpy(&buffer.front(), test_hash[i].binary, strlen(test_hash[i].binary));
+    std::vector<byte> hash;
+    ASSERT_SUCCEEDED(chash.Compute(buffer, &hash));
+    ASSERT_EQ(hash.size(), CryptoHash::kHashSize);
+    ASSERT_EQ(0, memcmp(&hash.front(),
+                        test_hash[i].hash,
+                        CryptoHash::kHashSize));
+    ASSERT_SUCCEEDED(chash.Validate(buffer, hash));
+  }
+}
+
+TEST(SignaturesTest, CreationVerification) {
+  // Load the test certificates from the directory where the unit test is
+  // running from. The test certificates are copied there during the build.
+  TCHAR directory[MAX_PATH] = {0};
+  ASSERT_TRUE(GetModuleDirectory(NULL, directory));
+  CString encoded_cert_with_private_key_path;
+  encoded_cert_with_private_key_path.AppendFormat(
+      _T("%s\\certificate-with-private-key.pfx"), directory);
+  CString encoded_cert_without_private_key_path;
+  encoded_cert_without_private_key_path.AppendFormat(
+      _T("%s\\certificate-without-private-key.cer"), directory);
+  CString raw_test_data_path;
+  raw_test_data_path.AppendFormat(_T("%s\\declaration.txt"), directory);
+
+  // Get cert with private key and cert without private key.
+  std::vector<byte> encoded_cert_with_private_key;
+  std::vector<byte> encoded_cert_without_private_key;
+  ASSERT_SUCCEEDED(ReadEntireFile(encoded_cert_with_private_key_path,
+                                  0,
+                                  &encoded_cert_with_private_key));
+  ASSERT_SUCCEEDED(ReadEntireFile(encoded_cert_without_private_key_path,
+                                  0,
+                                  &encoded_cert_without_private_key));
+  CString cert_password = _T("f00bar");
+  CString cert_subject_name = _T("Unofficial Google Test");
+
+  // Get testdata.
+  std::vector<byte> raw_testdata;
+  ASSERT_SUCCEEDED(ReadEntireFile(raw_test_data_path, 0, &raw_testdata));
+
+  // Create a signing certificate.
+  CryptoSigningCertificate signing_certificate;
+  ASSERT_SUCCEEDED(signing_certificate.ImportCertificate(
+      encoded_cert_with_private_key, cert_password, cert_subject_name));
+
+  // Create a signature object and sign the test data.
+  std::vector<byte> signature;
+  CryptoComputeSignature signer(&signing_certificate);
+  ASSERT_SUCCEEDED(signer.Sign(raw_testdata, &signature));
+
+  // Create a validating certificate.
+  CryptoSignatureVerificationCertificate verification_certificate;
+  ASSERT_SUCCEEDED(verification_certificate.ImportCertificate(
+      encoded_cert_without_private_key, cert_subject_name));
+
+  // Create a signature object and verify the test data's signature.
+  CryptoVerifySignature verifier(verification_certificate);
+  ASSERT_SUCCEEDED(verifier.Validate(raw_testdata, signature));
+
+  // Mess up the signature and show it doesn't verify.
+  size_t mid = signature.size() / 2;
+  byte mid_byte = signature[mid];
+  signature[mid] = ~mid_byte;
+  ASSERT_FAILED(verifier.Validate(raw_testdata, signature));
+
+  // Restore the signature, mess up the test data, and show it doesn't verify.
+  signature[mid] = mid_byte;
+  mid = raw_testdata.size() / 2;
+  mid_byte = raw_testdata[mid];
+  raw_testdata[mid] = ~mid_byte;
+  ASSERT_FAILED(verifier.Validate(raw_testdata, signature));
+}
+
+}  // namespace omaha
+
diff --git a/common/signaturevalidator.cc b/common/signaturevalidator.cc
index bb20126..2a49b70 100644
--- a/common/signaturevalidator.cc
+++ b/common/signaturevalidator.cc
@@ -1,559 +1,559 @@
-// Copyright 2002-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/signaturevalidator.h"

-

-#include <atltime.h>

-#include <softpub.h>

-#include <wincrypt.h>

-#include <wintrust.h>

-#pragma warning(push)

-// C4100: unreferenced formal parameter

-// C4310: cast truncates constant value

-// C4548: expression before comma has no effect

-#pragma warning(disable : 4100 4310 4548)

-#include "base/basictypes.h"

-#pragma warning(pop)

-#include "omaha/common/error.h"

-

-namespace omaha {

-

-namespace {

-

-const LPCTSTR kEmptyStr = _T("");

-const DWORD kCertificateEncoding = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;

-

-// Gets a handle to the certificate store and optionally the cryptographic

-// message from the specified file.

-// The caller is responsible for closing the store and message.

-// message can be NULL if the handle is not needed.

-HRESULT GetCertStoreFromFile(const wchar_t* signed_file,

-                             HCERTSTORE* cert_store,

-                             HCRYPTMSG* message) {

-  if (!signed_file || !cert_store) {

-    return E_INVALIDARG;

-  }

-

-  // Get message handle and store handle from the signed file.

-  if (!::CryptQueryObject(CERT_QUERY_OBJECT_FILE,

-                          signed_file,

-                          CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,

-                          CERT_QUERY_FORMAT_FLAG_BINARY,

-                          0,              // reserved, must be 0

-                          NULL,           // pdwMsgAndCertEncodingType

-                          NULL,           // pdwContentType

-                          NULL,           // pdwFormatType

-                          cert_store,

-                          message,

-                          NULL)) {        // ppvContext

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  return S_OK;

-}

-

-// Gets the signer info from the crypt message.

-// The caller is responsible for freeing the signer info using LocalFree.

-HRESULT GetSignerInfo(HCRYPTMSG message, PCMSG_SIGNER_INFO* signer_info) {

-  if (!signer_info) {

-    return E_INVALIDARG;

-  }

-  *signer_info = NULL;

-

-  DWORD info_size = 0;

-  if (!::CryptMsgGetParam(message,

-                          CMSG_SIGNER_INFO_PARAM,

-                          0,

-                          NULL,

-                          &info_size)) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  *signer_info = static_cast<PCMSG_SIGNER_INFO>(::LocalAlloc(LPTR, info_size));

-  if (!*signer_info) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  if (!::CryptMsgGetParam(message,

-                          CMSG_SIGNER_INFO_PARAM,

-                          0,

-                          *signer_info,

-                          &info_size)) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  return S_OK;

-}

-

-// Gets the signer info for the time stamp signature in the specified signature.

-HRESULT GetTimeStampSignerInfo(PCMSG_SIGNER_INFO signer_info,

-                               PCMSG_SIGNER_INFO* countersigner_info) {

-  if (!signer_info || !countersigner_info) {

-    return E_INVALIDARG;

-  }

-  *countersigner_info = NULL;

-

-  PCRYPT_ATTRIBUTE attr = NULL;

-

-  // The countersigner info is contained in the unauthenticated attributes and

-  // indicated by the szOID_RSA_counterSign OID.

-  for (size_t i = 0; i < signer_info->UnauthAttrs.cAttr; ++i) {

-    if (lstrcmpA(szOID_RSA_counterSign,

-                 signer_info->UnauthAttrs.rgAttr[i].pszObjId) == 0) {

-      attr = &signer_info->UnauthAttrs.rgAttr[i];

-      break;

-    }

-  }

-

-  if (!attr) {

-    return E_FAIL;

-  }

-

-  // Decode and get CMSG_SIGNER_INFO structure for the timestamp certificate.

-  DWORD data_size = 0;

-  if (!::CryptDecodeObject(kCertificateEncoding,

-                           PKCS7_SIGNER_INFO,

-                           attr->rgValue[0].pbData,

-                           attr->rgValue[0].cbData,

-                           0,

-                           NULL,

-                           &data_size)) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  *countersigner_info =

-      static_cast<PCMSG_SIGNER_INFO>(::LocalAlloc(LPTR, data_size));

-  if (!*countersigner_info) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  if (!::CryptDecodeObject(kCertificateEncoding,

-                           PKCS7_SIGNER_INFO,

-                           attr->rgValue[0].pbData,

-                           attr->rgValue[0].cbData,

-                           0,

-                           *countersigner_info,

-                           &data_size)) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  return S_OK;

-}

-

-// Gets the time of the date stamp for the specified signature.

-// The time is in UTC.

-HRESULT GetDateOfTimeStamp(PCMSG_SIGNER_INFO signer_info,

-                           SYSTEMTIME* system_time) {

-  if (!signer_info || !system_time) {

-    return E_INVALIDARG;

-  }

-

-  PCRYPT_ATTRIBUTE attr = NULL;

-

-  // The signing time is contained in the authenticated attributes and

-  // indicated by the szOID_RSA_signingTime OID.

-  for (size_t i = 0; i < signer_info->AuthAttrs.cAttr; ++i) {

-    if (lstrcmpA(szOID_RSA_signingTime,

-                 signer_info->AuthAttrs.rgAttr[i].pszObjId) == 0) {

-      attr = &signer_info->AuthAttrs.rgAttr[i];

-      break;

-    }

-  }

-

-  if (!attr) {

-    return E_FAIL;

-  }

-

-  FILETIME file_time = {0};

-

-  // Decode and get FILETIME structure.

-  DWORD data_size = sizeof(file_time);

-  if (!::CryptDecodeObject(kCertificateEncoding,

-                           szOID_RSA_signingTime,

-                           attr->rgValue[0].pbData,

-                           attr->rgValue[0].cbData,

-                           0,

-                           &file_time,

-                           &data_size)) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  if (!::FileTimeToSystemTime(&file_time, system_time)) {

-    return HRESULT_FROM_WIN32(::GetLastError());

-  }

-

-  return S_OK;

-}

-

-}  // namespace

-

-CertInfo::CertInfo(const CERT_CONTEXT* given_cert_context)

-    : cert_context_(NULL) {

-  if (given_cert_context) {

-    // CertDuplicateCertificateContext just increases reference count of a given

-    // CERT_CONTEXT.

-    cert_context_ = CertDuplicateCertificateContext(given_cert_context);

-    not_valid_before_ = cert_context_->pCertInfo->NotBefore;

-    not_valid_after_ = cert_context_->pCertInfo->NotAfter;

-    // Extract signed party details.

-    ExtractIssuerInfo(cert_context_,

-                      &issuing_company_name_,

-                      &issuing_dept_name_,

-                      &trust_authority_name_);

-  }

-}

-

-CertInfo::~CertInfo() {

-  // Decrement reference count, if needed.

-  if (cert_context_)

-    CertFreeCertificateContext(cert_context_);

-}

-

-

-bool CertInfo::IsValidNow() const {

-  // we cannot directly get current time in FILETIME format.

-  // so first get it in SYSTEMTIME format and convert it into FILETIME.

-  SYSTEMTIME now;

-  GetSystemTime(&now);

-  FILETIME filetime_now;

-  SystemTimeToFileTime(&now, &filetime_now);

-  // CompareFileTime() is a windows function

-  return ((CompareFileTime(&filetime_now, &not_valid_before_) > 0)

-          && (CompareFileTime(&filetime_now, &not_valid_after_) < 0));

-}

-

-

-CString CertInfo::FileTimeToString(const FILETIME* ft) {

-  if (ft == NULL)

-    return _T("");

-  SYSTEMTIME st;

-  if (!FileTimeToSystemTime(ft, &st))

-    return _T("");

-

-  // Build a string showing the date and time.

-  CString time_str;

-  time_str.Format(_T("%02d/%02d/%d  %02d:%02d"), st.wDay, st.wMonth, st.wYear,

-    st.wHour, st.wMinute);

-  return time_str;

-}

-

-

-bool CertInfo::ExtractField(const TCHAR* str,

-                            const TCHAR* field_name,

-                            CString* field_value) {

-  if ((!str) || (!field_name) || (!field_value))

-    return false;

-

-  // first, we have to locate pattern - "<field-name>="

-  CString field_name_with_equal_sign = field_name + CString(_T("="));

-  const TCHAR* field_name_start = _tcsstr(str, field_name_with_equal_sign);

-

-  // there is no such field? ok, sorry..

-  if (field_name_start == NULL) {

-    field_value->Empty();

-    return false;

-  }

-

-  // now, locate the end of this field-value. we know each field value

-  // is followed by a semi-colon (except last one).

-  const TCHAR* next_field = _tcschr(field_name_start, ';');

-  // identify where exactly field-value starts.

-  const TCHAR* field_value_start = field_name_start +

-                                   field_name_with_equal_sign.GetLength();

-  if (next_field) {

-    // if next-field exists, copy all the chars before semi-colon

-    field_value->SetString(field_value_start,

-        static_cast<int>(next_field - field_value_start));

-  } else {

-    // this must be the last field. copy till the end of the string.

-    field_value->SetString(field_value_start);

-  }

-

-  return true;

-}

-

-

-bool CertInfo::ExtractIssuerInfo(const CERT_CONTEXT* cert_context,

-                                 CString* orgn_name,

-                                 CString* orgn_dept_name,

-                                 CString* trust_authority) {

-  // trust-authority is optional, so no check.

-  if ((!orgn_name) || (!orgn_dept_name))

-    return false;

-

-  if (!cert_context) {

-    orgn_name->Empty();

-    orgn_dept_name->Empty();

-    return false;

-  }

-

-  // Retrieve organization info in the form of a BLOB

-  CERT_NAME_BLOB orgn_blob = cert_context->pCertInfo->Subject;

-

-  TCHAR name_str[1024];

-  DWORD name_size = sizeof(name_str);

-

-  DWORD num_converted_bytes =

-    CertNameToStr(

-        kCertificateEncoding,

-        &orgn_blob,

-        CERT_X500_NAME_STR|CERT_NAME_STR_NO_QUOTING_FLAG|

-        CERT_NAME_STR_SEMICOLON_FLAG|  // all the fields to be separated by ';'

-        CERT_NAME_STR_REVERSE_FLAG,    // we are reversing the order of fields

-                                       // so that subject/signee related fields

-                                       // turn up first.

-        name_str,

-        name_size);

-

-  if ((num_converted_bytes <= 0) || (num_converted_bytes > name_size)) {

-    // num_converted_bytes > name_size - means that name_str needs to be larger.

-    // That's very unlikely so I don't call again it with a bigger string.

-    orgn_name->Empty();

-    orgn_dept_name->Empty();

-    return false;

-  }

-

-  ExtractField(name_str, _T("CN"), orgn_name);       // CN - Common Name

-  ExtractField(name_str, _T("OU"), orgn_dept_name);  // OU - Organizational Unit

-  if (trust_authority != NULL)

-    ExtractField(name_str, _T("O"), trust_authority);

-  return true;

-}

-

-

-void CertList::FindFirstCert(CertInfo** result_cert_info,

-                             const CString &company_name_to_match,

-                             const CString &orgn_unit_to_match,

-                             const CString &trust_authority_to_match,

-                             bool allow_test_variant,

-                             bool check_timestamp) {

-  if (!result_cert_info)

-    return;

-  (*result_cert_info) = NULL;

-

-  for (CertInfoList::const_iterator cert_iter = cert_list_.begin();

-       cert_iter != cert_list_.end();

-       ++cert_iter) {

-    // If any of the criteria does not match, continue on to next certificate

-    if (!company_name_to_match.IsEmpty()) {

-      const TCHAR* certificate_company_name =

-          (*cert_iter)->issuing_company_name_;

-      bool names_match = company_name_to_match == certificate_company_name;

-      if (!names_match && allow_test_variant) {

-        CString test_variant = company_name_to_match;

-        test_variant += _T(" (TEST)");

-        names_match = test_variant == certificate_company_name;

-      }

-      if (!names_match)

-        continue;

-    }

-    if (!orgn_unit_to_match.IsEmpty() &&

-        orgn_unit_to_match != (*cert_iter)->issuing_dept_name_)

-      continue;

-    if (!trust_authority_to_match.IsEmpty() &&

-        trust_authority_to_match != (*cert_iter)->trust_authority_name_)

-      continue;

-    // All the criteria matched. But, add only if it is a valid certificate.

-    if (!check_timestamp || (*cert_iter)->IsValidNow()) {

-      (*result_cert_info) = (*cert_iter);

-      return;

-    }

-  }

-}

-

-

-void ExtractAllCertificatesFromSignature(const wchar_t* signed_file,

-                                         CertList* cert_list) {

-  if ((!signed_file) || (!cert_list))

-    return;

-

-  DWORD encoding_type = 0, content_type = 0, format_type = 0;

-  // If successful, cert_store will be populated by

-  // a store containing all the certificates related to the file signature.

-  HCERTSTORE cert_store = NULL;

-  BOOL succeeded = CryptQueryObject(CERT_QUERY_OBJECT_FILE,

-                    signed_file,

-                    CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,

-                    CERT_QUERY_FORMAT_FLAG_ALL,

-                    0,               // has to be zero as documentation says

-                    &encoding_type,  // DWORD *pdwMsgAndCertEncodingType,

-                    &content_type,   // DWORD *pdwContentType,

-                    &format_type,    // DWORD *pdwFormatType,

-                    &cert_store,     // HCERTSTORE *phCertStore,

-                    NULL,            // HCRYPTMSG *phMsg,

-                    NULL);           // const void** pvContext

-

-  if (succeeded && (cert_store != NULL)) {

-    PCCERT_CONTEXT   cert_context_ptr = NULL;

-    while ((cert_context_ptr =

-            CertEnumCertificatesInStore(cert_store, cert_context_ptr))

-           != NULL) {

-      CertInfo* cert_info = new CertInfo(cert_context_ptr);

-      cert_list->AddCertificate(cert_info);

-    }

-  }

-  if (cert_store) {

-    CertCloseStore(cert_store, 0);

-  }

-  return;

-}

-

-bool VerifySigneeIsGoogleInternal(const wchar_t* signed_file,

-                                  bool check_timestamp) {

-  // Google Name and its dept name as expected on the certificate.

-  // We switched to a slightly different cert in late 2005. The values were

-  // "Google, Inc." and "Engineering" respectively.

-  // Subject Name

-  const TCHAR* google_name = _T("Google Inc");

-  // Organization Unit Name

-  const TCHAR* google_dept_name =

-      _T("Digital ID Class 3 - Netscape Object Signing");

-

-  CertList cert_list;

-  ExtractAllCertificatesFromSignature(signed_file, &cert_list);

-  if (cert_list.size() > 0) {

-    CertInfo* required_cert = NULL;

-    // now, see if one of the certificates in the signature belongs to Google.

-    cert_list.FindFirstCert(&required_cert, google_name, google_dept_name,

-                            CString(), true, check_timestamp);

-    if (required_cert != NULL) {

-      return true;

-    }

-  }

-  return false;

-}

-

-bool VerifySigneeIsGoogle(const wchar_t* signed_file) {

-  return VerifySigneeIsGoogleInternal(signed_file, true);

-}

-

-bool VerifySigneeIsGoogleNoTimestampCheck(const wchar_t* signed_file) {

-  return VerifySigneeIsGoogleInternal(signed_file, false);

-}

-

-HRESULT VerifySignature(const wchar_t* signed_file, bool allow_network_check) {

-  // Don't pop up any windows

-  HWND const kWindowMode = reinterpret_cast<HWND>(INVALID_HANDLE_VALUE);

-

-  // Verify file & certificates

-  GUID verification_type = WINTRUST_ACTION_GENERIC_VERIFY_V2;

-

-  // Info for the file we're going to verify

-  WINTRUST_FILE_INFO file_info = {0};

-  file_info.cbStruct = sizeof(file_info);

-  file_info.pcwszFilePath = signed_file;

-

-  // Info for request to WinVerifyTrust

-  WINTRUST_DATA trust_data;

-  ZeroMemory(&trust_data, sizeof(trust_data));

-  trust_data.cbStruct = sizeof(trust_data);

-  trust_data.dwUIChoice = WTD_UI_NONE;               // no graphics

-  // No additional revocation checking -- note that this flag does not

-  // cancel the flag we set in dwProvFlags; it specifies that no -additional-

-  // checks are to be performed beyond the provider-specified ones.

-  trust_data.fdwRevocationChecks = WTD_REVOKE_NONE;

-  trust_data.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;

-

-  if (!allow_network_check)

-    trust_data.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL;

-

-  trust_data.dwUnionChoice = WTD_CHOICE_FILE;        // check a file

-  trust_data.pFile = &file_info;                     // check this file

-

-  // If the trust provider verifies that the subject is trusted for the

-  // specified action, the return value is zero. No other value besides zero

-  // should be considered a successful return.

-  LONG result = WinVerifyTrust(kWindowMode, &verification_type, &trust_data);

-  if (result != 0) {

-    return FAILED(result) ? result : HRESULT_FROM_WIN32(result);

-  }

-  return S_OK;

-}

-

-// This method must not return until the end to avoid leaking memory.

-// More info on Authenticode Signatures Time Stamping can be found at

-// http://msdn2.microsoft.com/en-us/library/bb931395.aspx.

-HRESULT GetSigningTime(const wchar_t* signed_file, SYSTEMTIME* signing_time) {

-  if (!signed_file || !signing_time) {

-    return E_INVALIDARG;

-  }

-

-  HCERTSTORE cert_store = NULL;

-  HCRYPTMSG message = NULL;

-  PCMSG_SIGNER_INFO signer_info = NULL;

-  PCMSG_SIGNER_INFO countersigner_info = NULL;

-

-  HRESULT hr = GetCertStoreFromFile(signed_file, &cert_store, &message);

-

-  if (SUCCEEDED(hr)) {

-    hr = GetSignerInfo(message, &signer_info);

-  }

-

-  if (SUCCEEDED(hr)) {

-    hr = GetTimeStampSignerInfo(signer_info, &countersigner_info);

-  }

-

-  if (SUCCEEDED(hr)) {

-    hr = GetDateOfTimeStamp(countersigner_info, signing_time);

-  }

-

-  if (cert_store) {

-    ::CertCloseStore(cert_store, 0);

-  }

-  if (message) {

-    ::CryptMsgClose(message);

-  }

-  ::LocalFree(signer_info);

-  ::LocalFree(countersigner_info);

-

-  return hr;

-}

-

-HRESULT VerifyFileSignedWithinDays(const wchar_t* signed_file, int days) {

-  if (!signed_file || days <= 0) {

-    return E_INVALIDARG;

-  }

-

-  SYSTEMTIME signing_time = {0};

-  HRESULT hr = GetSigningTime(signed_file, &signing_time);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Use the Win32 API instead of CTime::GetCurrentTime() because the latter

-  // is broken in VS 2003 and 2005 and doesn't account for the timezone.

-  SYSTEMTIME current_system_time = {0};

-  ::GetSystemTime(&current_system_time);

-

-  CTime signed_time(signing_time);

-  CTime current_time(current_system_time);

-

-  if (current_time <= signed_time) {

-    return TRUST_E_TIME_STAMP;

-  }

-

-  CTimeSpan time_since_signed = current_time - signed_time;

-  CTimeSpan max_duration(days, 0, 0, 0);

-

-  if (max_duration < time_since_signed) {

-    return TRUST_E_TIME_STAMP;

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2002-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/signaturevalidator.h"
+
+#include <atltime.h>
+#include <softpub.h>
+#include <wincrypt.h>
+#include <wintrust.h>
+#pragma warning(push)
+// C4100: unreferenced formal parameter
+// C4310: cast truncates constant value
+// C4548: expression before comma has no effect
+#pragma warning(disable : 4100 4310 4548)
+#include "base/basictypes.h"
+#pragma warning(pop)
+#include "omaha/common/error.h"
+
+namespace omaha {
+
+namespace {
+
+const LPCTSTR kEmptyStr = _T("");
+const DWORD kCertificateEncoding = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
+
+// Gets a handle to the certificate store and optionally the cryptographic
+// message from the specified file.
+// The caller is responsible for closing the store and message.
+// message can be NULL if the handle is not needed.
+HRESULT GetCertStoreFromFile(const wchar_t* signed_file,
+                             HCERTSTORE* cert_store,
+                             HCRYPTMSG* message) {
+  if (!signed_file || !cert_store) {
+    return E_INVALIDARG;
+  }
+
+  // Get message handle and store handle from the signed file.
+  if (!::CryptQueryObject(CERT_QUERY_OBJECT_FILE,
+                          signed_file,
+                          CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+                          CERT_QUERY_FORMAT_FLAG_BINARY,
+                          0,              // reserved, must be 0
+                          NULL,           // pdwMsgAndCertEncodingType
+                          NULL,           // pdwContentType
+                          NULL,           // pdwFormatType
+                          cert_store,
+                          message,
+                          NULL)) {        // ppvContext
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  return S_OK;
+}
+
+// Gets the signer info from the crypt message.
+// The caller is responsible for freeing the signer info using LocalFree.
+HRESULT GetSignerInfo(HCRYPTMSG message, PCMSG_SIGNER_INFO* signer_info) {
+  if (!signer_info) {
+    return E_INVALIDARG;
+  }
+  *signer_info = NULL;
+
+  DWORD info_size = 0;
+  if (!::CryptMsgGetParam(message,
+                          CMSG_SIGNER_INFO_PARAM,
+                          0,
+                          NULL,
+                          &info_size)) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  *signer_info = static_cast<PCMSG_SIGNER_INFO>(::LocalAlloc(LPTR, info_size));
+  if (!*signer_info) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  if (!::CryptMsgGetParam(message,
+                          CMSG_SIGNER_INFO_PARAM,
+                          0,
+                          *signer_info,
+                          &info_size)) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  return S_OK;
+}
+
+// Gets the signer info for the time stamp signature in the specified signature.
+HRESULT GetTimeStampSignerInfo(PCMSG_SIGNER_INFO signer_info,
+                               PCMSG_SIGNER_INFO* countersigner_info) {
+  if (!signer_info || !countersigner_info) {
+    return E_INVALIDARG;
+  }
+  *countersigner_info = NULL;
+
+  PCRYPT_ATTRIBUTE attr = NULL;
+
+  // The countersigner info is contained in the unauthenticated attributes and
+  // indicated by the szOID_RSA_counterSign OID.
+  for (size_t i = 0; i < signer_info->UnauthAttrs.cAttr; ++i) {
+    if (lstrcmpA(szOID_RSA_counterSign,
+                 signer_info->UnauthAttrs.rgAttr[i].pszObjId) == 0) {
+      attr = &signer_info->UnauthAttrs.rgAttr[i];
+      break;
+    }
+  }
+
+  if (!attr) {
+    return E_FAIL;
+  }
+
+  // Decode and get CMSG_SIGNER_INFO structure for the timestamp certificate.
+  DWORD data_size = 0;
+  if (!::CryptDecodeObject(kCertificateEncoding,
+                           PKCS7_SIGNER_INFO,
+                           attr->rgValue[0].pbData,
+                           attr->rgValue[0].cbData,
+                           0,
+                           NULL,
+                           &data_size)) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  *countersigner_info =
+      static_cast<PCMSG_SIGNER_INFO>(::LocalAlloc(LPTR, data_size));
+  if (!*countersigner_info) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  if (!::CryptDecodeObject(kCertificateEncoding,
+                           PKCS7_SIGNER_INFO,
+                           attr->rgValue[0].pbData,
+                           attr->rgValue[0].cbData,
+                           0,
+                           *countersigner_info,
+                           &data_size)) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  return S_OK;
+}
+
+// Gets the time of the date stamp for the specified signature.
+// The time is in UTC.
+HRESULT GetDateOfTimeStamp(PCMSG_SIGNER_INFO signer_info,
+                           SYSTEMTIME* system_time) {
+  if (!signer_info || !system_time) {
+    return E_INVALIDARG;
+  }
+
+  PCRYPT_ATTRIBUTE attr = NULL;
+
+  // The signing time is contained in the authenticated attributes and
+  // indicated by the szOID_RSA_signingTime OID.
+  for (size_t i = 0; i < signer_info->AuthAttrs.cAttr; ++i) {
+    if (lstrcmpA(szOID_RSA_signingTime,
+                 signer_info->AuthAttrs.rgAttr[i].pszObjId) == 0) {
+      attr = &signer_info->AuthAttrs.rgAttr[i];
+      break;
+    }
+  }
+
+  if (!attr) {
+    return E_FAIL;
+  }
+
+  FILETIME file_time = {0};
+
+  // Decode and get FILETIME structure.
+  DWORD data_size = sizeof(file_time);
+  if (!::CryptDecodeObject(kCertificateEncoding,
+                           szOID_RSA_signingTime,
+                           attr->rgValue[0].pbData,
+                           attr->rgValue[0].cbData,
+                           0,
+                           &file_time,
+                           &data_size)) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  if (!::FileTimeToSystemTime(&file_time, system_time)) {
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  return S_OK;
+}
+
+}  // namespace
+
+CertInfo::CertInfo(const CERT_CONTEXT* given_cert_context)
+    : cert_context_(NULL) {
+  if (given_cert_context) {
+    // CertDuplicateCertificateContext just increases reference count of a given
+    // CERT_CONTEXT.
+    cert_context_ = CertDuplicateCertificateContext(given_cert_context);
+    not_valid_before_ = cert_context_->pCertInfo->NotBefore;
+    not_valid_after_ = cert_context_->pCertInfo->NotAfter;
+    // Extract signed party details.
+    ExtractIssuerInfo(cert_context_,
+                      &issuing_company_name_,
+                      &issuing_dept_name_,
+                      &trust_authority_name_);
+  }
+}
+
+CertInfo::~CertInfo() {
+  // Decrement reference count, if needed.
+  if (cert_context_)
+    CertFreeCertificateContext(cert_context_);
+}
+
+
+bool CertInfo::IsValidNow() const {
+  // we cannot directly get current time in FILETIME format.
+  // so first get it in SYSTEMTIME format and convert it into FILETIME.
+  SYSTEMTIME now;
+  GetSystemTime(&now);
+  FILETIME filetime_now;
+  SystemTimeToFileTime(&now, &filetime_now);
+  // CompareFileTime() is a windows function
+  return ((CompareFileTime(&filetime_now, &not_valid_before_) > 0)
+          && (CompareFileTime(&filetime_now, &not_valid_after_) < 0));
+}
+
+
+CString CertInfo::FileTimeToString(const FILETIME* ft) {
+  if (ft == NULL)
+    return _T("");
+  SYSTEMTIME st;
+  if (!FileTimeToSystemTime(ft, &st))
+    return _T("");
+
+  // Build a string showing the date and time.
+  CString time_str;
+  time_str.Format(_T("%02d/%02d/%d  %02d:%02d"), st.wDay, st.wMonth, st.wYear,
+    st.wHour, st.wMinute);
+  return time_str;
+}
+
+
+bool CertInfo::ExtractField(const TCHAR* str,
+                            const TCHAR* field_name,
+                            CString* field_value) {
+  if ((!str) || (!field_name) || (!field_value))
+    return false;
+
+  // first, we have to locate pattern - "<field-name>="
+  CString field_name_with_equal_sign = field_name + CString(_T("="));
+  const TCHAR* field_name_start = _tcsstr(str, field_name_with_equal_sign);
+
+  // there is no such field? ok, sorry..
+  if (field_name_start == NULL) {
+    field_value->Empty();
+    return false;
+  }
+
+  // now, locate the end of this field-value. we know each field value
+  // is followed by a semi-colon (except last one).
+  const TCHAR* next_field = _tcschr(field_name_start, ';');
+  // identify where exactly field-value starts.
+  const TCHAR* field_value_start = field_name_start +
+                                   field_name_with_equal_sign.GetLength();
+  if (next_field) {
+    // if next-field exists, copy all the chars before semi-colon
+    field_value->SetString(field_value_start,
+        static_cast<int>(next_field - field_value_start));
+  } else {
+    // this must be the last field. copy till the end of the string.
+    field_value->SetString(field_value_start);
+  }
+
+  return true;
+}
+
+
+bool CertInfo::ExtractIssuerInfo(const CERT_CONTEXT* cert_context,
+                                 CString* orgn_name,
+                                 CString* orgn_dept_name,
+                                 CString* trust_authority) {
+  // trust-authority is optional, so no check.
+  if ((!orgn_name) || (!orgn_dept_name))
+    return false;
+
+  if (!cert_context) {
+    orgn_name->Empty();
+    orgn_dept_name->Empty();
+    return false;
+  }
+
+  // Retrieve organization info in the form of a BLOB
+  CERT_NAME_BLOB orgn_blob = cert_context->pCertInfo->Subject;
+
+  TCHAR name_str[1024];
+  DWORD name_size = sizeof(name_str);
+
+  DWORD num_converted_bytes =
+    CertNameToStr(
+        kCertificateEncoding,
+        &orgn_blob,
+        CERT_X500_NAME_STR|CERT_NAME_STR_NO_QUOTING_FLAG|
+        CERT_NAME_STR_SEMICOLON_FLAG|  // all the fields to be separated by ';'
+        CERT_NAME_STR_REVERSE_FLAG,    // we are reversing the order of fields
+                                       // so that subject/signee related fields
+                                       // turn up first.
+        name_str,
+        name_size);
+
+  if ((num_converted_bytes <= 0) || (num_converted_bytes > name_size)) {
+    // num_converted_bytes > name_size - means that name_str needs to be larger.
+    // That's very unlikely so I don't call again it with a bigger string.
+    orgn_name->Empty();
+    orgn_dept_name->Empty();
+    return false;
+  }
+
+  ExtractField(name_str, _T("CN"), orgn_name);       // CN - Common Name
+  ExtractField(name_str, _T("OU"), orgn_dept_name);  // OU - Organizational Unit
+  if (trust_authority != NULL)
+    ExtractField(name_str, _T("O"), trust_authority);
+  return true;
+}
+
+
+void CertList::FindFirstCert(CertInfo** result_cert_info,
+                             const CString &company_name_to_match,
+                             const CString &orgn_unit_to_match,
+                             const CString &trust_authority_to_match,
+                             bool allow_test_variant,
+                             bool check_timestamp) {
+  if (!result_cert_info)
+    return;
+  (*result_cert_info) = NULL;
+
+  for (CertInfoList::const_iterator cert_iter = cert_list_.begin();
+       cert_iter != cert_list_.end();
+       ++cert_iter) {
+    // If any of the criteria does not match, continue on to next certificate
+    if (!company_name_to_match.IsEmpty()) {
+      const TCHAR* certificate_company_name =
+          (*cert_iter)->issuing_company_name_;
+      bool names_match = company_name_to_match == certificate_company_name;
+      if (!names_match && allow_test_variant) {
+        CString test_variant = company_name_to_match;
+        test_variant += _T(" (TEST)");
+        names_match = test_variant == certificate_company_name;
+      }
+      if (!names_match)
+        continue;
+    }
+    if (!orgn_unit_to_match.IsEmpty() &&
+        orgn_unit_to_match != (*cert_iter)->issuing_dept_name_)
+      continue;
+    if (!trust_authority_to_match.IsEmpty() &&
+        trust_authority_to_match != (*cert_iter)->trust_authority_name_)
+      continue;
+    // All the criteria matched. But, add only if it is a valid certificate.
+    if (!check_timestamp || (*cert_iter)->IsValidNow()) {
+      (*result_cert_info) = (*cert_iter);
+      return;
+    }
+  }
+}
+
+
+void ExtractAllCertificatesFromSignature(const wchar_t* signed_file,
+                                         CertList* cert_list) {
+  if ((!signed_file) || (!cert_list))
+    return;
+
+  DWORD encoding_type = 0, content_type = 0, format_type = 0;
+  // If successful, cert_store will be populated by
+  // a store containing all the certificates related to the file signature.
+  HCERTSTORE cert_store = NULL;
+  BOOL succeeded = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
+                    signed_file,
+                    CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+                    CERT_QUERY_FORMAT_FLAG_ALL,
+                    0,               // has to be zero as documentation says
+                    &encoding_type,  // DWORD *pdwMsgAndCertEncodingType,
+                    &content_type,   // DWORD *pdwContentType,
+                    &format_type,    // DWORD *pdwFormatType,
+                    &cert_store,     // HCERTSTORE *phCertStore,
+                    NULL,            // HCRYPTMSG *phMsg,
+                    NULL);           // const void** pvContext
+
+  if (succeeded && (cert_store != NULL)) {
+    PCCERT_CONTEXT   cert_context_ptr = NULL;
+    while ((cert_context_ptr =
+            CertEnumCertificatesInStore(cert_store, cert_context_ptr))
+           != NULL) {
+      CertInfo* cert_info = new CertInfo(cert_context_ptr);
+      cert_list->AddCertificate(cert_info);
+    }
+  }
+  if (cert_store) {
+    CertCloseStore(cert_store, 0);
+  }
+  return;
+}
+
+bool VerifySigneeIsGoogleInternal(const wchar_t* signed_file,
+                                  bool check_timestamp) {
+  // Google Name and its dept name as expected on the certificate.
+  // We switched to a slightly different cert in late 2005. The values were
+  // "Google, Inc." and "Engineering" respectively.
+  // Subject Name
+  const TCHAR* google_name = _T("Google Inc");
+  // Organization Unit Name
+  const TCHAR* google_dept_name =
+      _T("Digital ID Class 3 - Netscape Object Signing");
+
+  CertList cert_list;
+  ExtractAllCertificatesFromSignature(signed_file, &cert_list);
+  if (cert_list.size() > 0) {
+    CertInfo* required_cert = NULL;
+    // now, see if one of the certificates in the signature belongs to Google.
+    cert_list.FindFirstCert(&required_cert, google_name, google_dept_name,
+                            CString(), true, check_timestamp);
+    if (required_cert != NULL) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool VerifySigneeIsGoogle(const wchar_t* signed_file) {
+  return VerifySigneeIsGoogleInternal(signed_file, true);
+}
+
+bool VerifySigneeIsGoogleNoTimestampCheck(const wchar_t* signed_file) {
+  return VerifySigneeIsGoogleInternal(signed_file, false);
+}
+
+HRESULT VerifySignature(const wchar_t* signed_file, bool allow_network_check) {
+  // Don't pop up any windows
+  HWND const kWindowMode = reinterpret_cast<HWND>(INVALID_HANDLE_VALUE);
+
+  // Verify file & certificates
+  GUID verification_type = WINTRUST_ACTION_GENERIC_VERIFY_V2;
+
+  // Info for the file we're going to verify
+  WINTRUST_FILE_INFO file_info = {0};
+  file_info.cbStruct = sizeof(file_info);
+  file_info.pcwszFilePath = signed_file;
+
+  // Info for request to WinVerifyTrust
+  WINTRUST_DATA trust_data;
+  ZeroMemory(&trust_data, sizeof(trust_data));
+  trust_data.cbStruct = sizeof(trust_data);
+  trust_data.dwUIChoice = WTD_UI_NONE;               // no graphics
+  // No additional revocation checking -- note that this flag does not
+  // cancel the flag we set in dwProvFlags; it specifies that no -additional-
+  // checks are to be performed beyond the provider-specified ones.
+  trust_data.fdwRevocationChecks = WTD_REVOKE_NONE;
+  trust_data.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
+
+  if (!allow_network_check)
+    trust_data.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL;
+
+  trust_data.dwUnionChoice = WTD_CHOICE_FILE;        // check a file
+  trust_data.pFile = &file_info;                     // check this file
+
+  // If the trust provider verifies that the subject is trusted for the
+  // specified action, the return value is zero. No other value besides zero
+  // should be considered a successful return.
+  LONG result = WinVerifyTrust(kWindowMode, &verification_type, &trust_data);
+  if (result != 0) {
+    return FAILED(result) ? result : HRESULT_FROM_WIN32(result);
+  }
+  return S_OK;
+}
+
+// This method must not return until the end to avoid leaking memory.
+// More info on Authenticode Signatures Time Stamping can be found at
+// http://msdn2.microsoft.com/en-us/library/bb931395.aspx.
+HRESULT GetSigningTime(const wchar_t* signed_file, SYSTEMTIME* signing_time) {
+  if (!signed_file || !signing_time) {
+    return E_INVALIDARG;
+  }
+
+  HCERTSTORE cert_store = NULL;
+  HCRYPTMSG message = NULL;
+  PCMSG_SIGNER_INFO signer_info = NULL;
+  PCMSG_SIGNER_INFO countersigner_info = NULL;
+
+  HRESULT hr = GetCertStoreFromFile(signed_file, &cert_store, &message);
+
+  if (SUCCEEDED(hr)) {
+    hr = GetSignerInfo(message, &signer_info);
+  }
+
+  if (SUCCEEDED(hr)) {
+    hr = GetTimeStampSignerInfo(signer_info, &countersigner_info);
+  }
+
+  if (SUCCEEDED(hr)) {
+    hr = GetDateOfTimeStamp(countersigner_info, signing_time);
+  }
+
+  if (cert_store) {
+    ::CertCloseStore(cert_store, 0);
+  }
+  if (message) {
+    ::CryptMsgClose(message);
+  }
+  ::LocalFree(signer_info);
+  ::LocalFree(countersigner_info);
+
+  return hr;
+}
+
+HRESULT VerifyFileSignedWithinDays(const wchar_t* signed_file, int days) {
+  if (!signed_file || days <= 0) {
+    return E_INVALIDARG;
+  }
+
+  SYSTEMTIME signing_time = {0};
+  HRESULT hr = GetSigningTime(signed_file, &signing_time);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Use the Win32 API instead of CTime::GetCurrentTime() because the latter
+  // is broken in VS 2003 and 2005 and doesn't account for the timezone.
+  SYSTEMTIME current_system_time = {0};
+  ::GetSystemTime(&current_system_time);
+
+  CTime signed_time(signing_time);
+  CTime current_time(current_system_time);
+
+  if (current_time <= signed_time) {
+    return TRUST_E_TIME_STAMP;
+  }
+
+  CTimeSpan time_since_signed = current_time - signed_time;
+  CTimeSpan max_duration(days, 0, 0, 0);
+
+  if (max_duration < time_since_signed) {
+    return TRUST_E_TIME_STAMP;
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/common/signaturevalidator.h b/common/signaturevalidator.h
index 65f711f..9f22c3b 100644
--- a/common/signaturevalidator.h
+++ b/common/signaturevalidator.h
@@ -1,201 +1,201 @@
-// Copyright 2002-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_SIGNATUREVALIDATOR_H__

-#define OMAHA_COMMON_SIGNATUREVALIDATOR_H__

-

-#include <windows.h>

-#include <wincrypt.h>

-#include <atlstr.h>

-#pragma warning(push)

-// C4548: expression before comma has no effect

-#pragma warning(disable : 4548)

-#include <vector>

-#pragma warning(pop)

-

-namespace omaha {

-

-// Class: CertInfo

-//

-// CertInfo holds all sensible details of a certificate. During verification of

-// a signature, one CertInfo object is made for each certificate encountered in

-// the signature.

-class CertInfo {

- public:

-  // certificate issuing company name e.g. "Google Inc".

-  CString issuing_company_name_;

-

-  // a company may own multiple certificates.

-  // so this tells which dept owns this certificate.

-  CString issuing_dept_name_;

-

-  // trust-authority (or trust-provider) name. e.g. "Verisign, Inc.".

-  CString trust_authority_name_;

-

-  // validity period start-date

-  FILETIME not_valid_before_;

-

-  // validity period end-date

-  FILETIME not_valid_after_;

-

-  // CERT_CONTEXT structure, defined by Crypto API, contains all the info about

-  // the certificate.

-  const CERT_CONTEXT *cert_context_;

-

-  explicit CertInfo(const CERT_CONTEXT* given_cert_context);

-

-  ~CertInfo();

-

-  // IsValidNow() functions returns true if this certificate is valid at this

-  // moment, based on the validity period specified in the certificate.

-  bool IsValidNow() const;

-

-  // AsString() is a utility function that's used for printing CertInfo details.

-  CString AsString() const {

-    CString cert_info_str =

-        _T("Issuing Company: \"") + issuing_company_name_ +

-        _T("\"  Dept: \"") + issuing_dept_name_ +

-        _T("\"  Trust Provider: \"") + trust_authority_name_ +

-        _T("\"  Valid From: \"") + this->FileTimeToString(&not_valid_before_) +

-        _T("\"  Valid To: \"") + this->FileTimeToString(&not_valid_after_) +

-        _T("\"");

-    return cert_info_str;

-  }

-

-

-  // FileTimeToString() is just a convenience function to print FILETIME.

-  static CString FileTimeToString(const FILETIME* ft);

-

-  // Given a cerificate context, this function extracts the subject/signee

-  // company name and its dept name(orgnanizational-unit-name, as they call it).

-  // Optionally, you could also retrieve trust-authority name.

-  static bool ExtractIssuerInfo(const CERT_CONTEXT* cert_context,

-                         CString* orgn_name,

-                         CString* orgn_dept_name,

-                         CString* trust_authority = NULL);

-

- private:

-  // we expect the input string to contain field <name, value> pairs

-  // separated by semi-colons. i.e.

-  // <field-name>=<field-value>;<field-name=<field-value>;

-  // N O T E: If more than field exists with the same name, this function

-  //          returns the value of the first field.

-  static bool ExtractField(const TCHAR* str,

-                           const TCHAR* field_name,

-                           CString* field_value);

-};

-

-// CertList is a container for a list of certificates. It is used to hold all

-// the certificates found in the signature of a signed file. In addition, it

-// also provides interface to fetch certificates matching to a particular

-// criterion.

-//

-// Internally, CertList contains basically a vector of CertInfo* pointers.

-// The only reason why CertList is created as opposed to simply putting all

-// the certificates in a vector<CertInfo*> is to avoid memory-leaks. CertList

-// contains a list of CertInfo pointers and users don't have to worry about

-// freeing those pointers. On the other hand, if you use vector<CertInfo>

-// instead, it results in unwanted copying of CertInfo objects around.

-class CertList {

- public:

-  // Constructor

-  CertList() {}

-

-  // Destructor

-  ~CertList() {

-    for (unsigned int inx = 0; inx < cert_list_.size(); ++inx)

-      delete cert_list_[inx];

-    cert_list_.clear();

-  }

-

-  // size() returns the number of certificates in this CertList

-  size_t size() {

-    return cert_list_.size();

-  }

-

-  // AddCertificate() is used to add a certificate to CertList.

-  // NOTE that once a certificate is added, CertList takes ownership of that

-  // CertInfo object.

-  void AddCertificate(CertInfo* cert) {

-    cert_list_.push_back(cert);

-  }

-

-  // FindFirstCert() finds the first certificate that matches given criteria.

-  // If allow_test_variant is true, the company name will also be deemed valid

-  // if it equals company_name_to_match + " (TEST)".

-  void FindFirstCert(CertInfo** result_cert_info,

-                     const CString &company_name_to_match,

-                     const CString &orgn_unit_to_match,

-                     const CString &trust_authority_to_match,

-                     bool allow_test_variant,

-                     bool check_timestamp);

-

-  typedef std::vector<CertInfo*> CertInfoList;

-

-  // FindAllCerts() finds all certificates that match given criteria.

-  void FindAllCerts(CertInfoList* result_cert_info_list,

-                    CString company_name_to_match,

-                    CString orgn_unit_to_match,

-                    CString trust_authority_to_match,

-                    bool check_timestamp);

-

- private:

-  CertInfoList cert_list_;

-};

-

-

-// ExtractAllCertificatesFromSignature() takes in a signed file, extracts all

-// the certificates related to its signature and returns them in a CertList

-// object.

-void ExtractAllCertificatesFromSignature(const wchar_t* signed_file,

-                                         CertList* cert_list);

-

-// TODO(omaha): the time check verification algorithm below seems weak if not

-// completely wrong. The time stamp check should be done against the time

-// stamp signature instead of the current time. For example, modifying the

-// system time allows the test to pass or fail. See the documentation for

-// WinVerifyTrust and WTD_LIFETIME_SIGNING_FLAG.

-//

-// VerifySigneeIsGoogle() tries to verify the signee is Google by matching

-// the subject name on the certificate to "Google Inc" and its corresponding

-// dept name on the certificate to "Engineering". If matched, this returns true

-// otherwise it returns false. The time validity of the certicate is checked.

-bool VerifySigneeIsGoogle(const wchar_t* signed_file);

-

-// Verifies the signee but not the time stamp of the certificate.

-bool VerifySigneeIsGoogleNoTimestampCheck(const wchar_t* signed_file);

-

-// Returns S_OK if a given signed file contains a signature

-// that could be successfully verified using one of the trust providers

-// IE relies on. This means that, whoever signed the file, they should've signed

-// using certificate issued by a well-known (to IE) trust provider like

-// Verisign, Inc.

-HRESULT VerifySignature(const wchar_t* signed_file, bool allow_network_check);

-

-// Returns true if a given signed file contains a valid signature.

-inline bool SignatureIsValid(const wchar_t* signed_file,

-                             bool allow_network_check) {

-  return VerifySignature(signed_file, allow_network_check) == S_OK;

-}

-

-// Gets the timestamp for the file's signature.

-HRESULT GetSigningTime(const wchar_t* signed_file, SYSTEMTIME* signing_time);

-

-// Verifies that the file was signed within the specified number of days.

-HRESULT VerifyFileSignedWithinDays(const wchar_t* signed_file, int days);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SIGNATUREVALIDATOR_H__

+// Copyright 2002-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_SIGNATUREVALIDATOR_H__
+#define OMAHA_COMMON_SIGNATUREVALIDATOR_H__
+
+#include <windows.h>
+#include <wincrypt.h>
+#include <atlstr.h>
+#pragma warning(push)
+// C4548: expression before comma has no effect
+#pragma warning(disable : 4548)
+#include <vector>
+#pragma warning(pop)
+
+namespace omaha {
+
+// Class: CertInfo
+//
+// CertInfo holds all sensible details of a certificate. During verification of
+// a signature, one CertInfo object is made for each certificate encountered in
+// the signature.
+class CertInfo {
+ public:
+  // certificate issuing company name e.g. "Google Inc".
+  CString issuing_company_name_;
+
+  // a company may own multiple certificates.
+  // so this tells which dept owns this certificate.
+  CString issuing_dept_name_;
+
+  // trust-authority (or trust-provider) name. e.g. "Verisign, Inc.".
+  CString trust_authority_name_;
+
+  // validity period start-date
+  FILETIME not_valid_before_;
+
+  // validity period end-date
+  FILETIME not_valid_after_;
+
+  // CERT_CONTEXT structure, defined by Crypto API, contains all the info about
+  // the certificate.
+  const CERT_CONTEXT *cert_context_;
+
+  explicit CertInfo(const CERT_CONTEXT* given_cert_context);
+
+  ~CertInfo();
+
+  // IsValidNow() functions returns true if this certificate is valid at this
+  // moment, based on the validity period specified in the certificate.
+  bool IsValidNow() const;
+
+  // AsString() is a utility function that's used for printing CertInfo details.
+  CString AsString() const {
+    CString cert_info_str =
+        _T("Issuing Company: \"") + issuing_company_name_ +
+        _T("\"  Dept: \"") + issuing_dept_name_ +
+        _T("\"  Trust Provider: \"") + trust_authority_name_ +
+        _T("\"  Valid From: \"") + this->FileTimeToString(&not_valid_before_) +
+        _T("\"  Valid To: \"") + this->FileTimeToString(&not_valid_after_) +
+        _T("\"");
+    return cert_info_str;
+  }
+
+
+  // FileTimeToString() is just a convenience function to print FILETIME.
+  static CString FileTimeToString(const FILETIME* ft);
+
+  // Given a cerificate context, this function extracts the subject/signee
+  // company name and its dept name(orgnanizational-unit-name, as they call it).
+  // Optionally, you could also retrieve trust-authority name.
+  static bool ExtractIssuerInfo(const CERT_CONTEXT* cert_context,
+                         CString* orgn_name,
+                         CString* orgn_dept_name,
+                         CString* trust_authority = NULL);
+
+ private:
+  // we expect the input string to contain field <name, value> pairs
+  // separated by semi-colons. i.e.
+  // <field-name>=<field-value>;<field-name=<field-value>;
+  // N O T E: If more than field exists with the same name, this function
+  //          returns the value of the first field.
+  static bool ExtractField(const TCHAR* str,
+                           const TCHAR* field_name,
+                           CString* field_value);
+};
+
+// CertList is a container for a list of certificates. It is used to hold all
+// the certificates found in the signature of a signed file. In addition, it
+// also provides interface to fetch certificates matching to a particular
+// criterion.
+//
+// Internally, CertList contains basically a vector of CertInfo* pointers.
+// The only reason why CertList is created as opposed to simply putting all
+// the certificates in a vector<CertInfo*> is to avoid memory-leaks. CertList
+// contains a list of CertInfo pointers and users don't have to worry about
+// freeing those pointers. On the other hand, if you use vector<CertInfo>
+// instead, it results in unwanted copying of CertInfo objects around.
+class CertList {
+ public:
+  // Constructor
+  CertList() {}
+
+  // Destructor
+  ~CertList() {
+    for (unsigned int inx = 0; inx < cert_list_.size(); ++inx)
+      delete cert_list_[inx];
+    cert_list_.clear();
+  }
+
+  // size() returns the number of certificates in this CertList
+  size_t size() {
+    return cert_list_.size();
+  }
+
+  // AddCertificate() is used to add a certificate to CertList.
+  // NOTE that once a certificate is added, CertList takes ownership of that
+  // CertInfo object.
+  void AddCertificate(CertInfo* cert) {
+    cert_list_.push_back(cert);
+  }
+
+  // FindFirstCert() finds the first certificate that matches given criteria.
+  // If allow_test_variant is true, the company name will also be deemed valid
+  // if it equals company_name_to_match + " (TEST)".
+  void FindFirstCert(CertInfo** result_cert_info,
+                     const CString &company_name_to_match,
+                     const CString &orgn_unit_to_match,
+                     const CString &trust_authority_to_match,
+                     bool allow_test_variant,
+                     bool check_timestamp);
+
+  typedef std::vector<CertInfo*> CertInfoList;
+
+  // FindAllCerts() finds all certificates that match given criteria.
+  void FindAllCerts(CertInfoList* result_cert_info_list,
+                    CString company_name_to_match,
+                    CString orgn_unit_to_match,
+                    CString trust_authority_to_match,
+                    bool check_timestamp);
+
+ private:
+  CertInfoList cert_list_;
+};
+
+
+// ExtractAllCertificatesFromSignature() takes in a signed file, extracts all
+// the certificates related to its signature and returns them in a CertList
+// object.
+void ExtractAllCertificatesFromSignature(const wchar_t* signed_file,
+                                         CertList* cert_list);
+
+// TODO(omaha): the time check verification algorithm below seems weak if not
+// completely wrong. The time stamp check should be done against the time
+// stamp signature instead of the current time. For example, modifying the
+// system time allows the test to pass or fail. See the documentation for
+// WinVerifyTrust and WTD_LIFETIME_SIGNING_FLAG.
+//
+// VerifySigneeIsGoogle() tries to verify the signee is Google by matching
+// the subject name on the certificate to "Google Inc" and its corresponding
+// dept name on the certificate to "Engineering". If matched, this returns true
+// otherwise it returns false. The time validity of the certicate is checked.
+bool VerifySigneeIsGoogle(const wchar_t* signed_file);
+
+// Verifies the signee but not the time stamp of the certificate.
+bool VerifySigneeIsGoogleNoTimestampCheck(const wchar_t* signed_file);
+
+// Returns S_OK if a given signed file contains a signature
+// that could be successfully verified using one of the trust providers
+// IE relies on. This means that, whoever signed the file, they should've signed
+// using certificate issued by a well-known (to IE) trust provider like
+// Verisign, Inc.
+HRESULT VerifySignature(const wchar_t* signed_file, bool allow_network_check);
+
+// Returns true if a given signed file contains a valid signature.
+inline bool SignatureIsValid(const wchar_t* signed_file,
+                             bool allow_network_check) {
+  return VerifySignature(signed_file, allow_network_check) == S_OK;
+}
+
+// Gets the timestamp for the file's signature.
+HRESULT GetSigningTime(const wchar_t* signed_file, SYSTEMTIME* signing_time);
+
+// Verifies that the file was signed within the specified number of days.
+HRESULT VerifyFileSignedWithinDays(const wchar_t* signed_file, int days);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SIGNATUREVALIDATOR_H__
diff --git a/common/signaturevalidator_unittest.cc b/common/signaturevalidator_unittest.cc
index 65a6918..117cb03 100644
--- a/common/signaturevalidator_unittest.cc
+++ b/common/signaturevalidator_unittest.cc
@@ -1,58 +1,58 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Unit tests for the Google file signature validation.

-

-#include <windows.h>

-#include <atlstr.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/file.h"

-#include "omaha/common/signaturevalidator.h"

-#include "omaha/third_party/gtest/include/gtest/gtest.h"

-

-namespace omaha {

-

-class SignatureValidatorTest : public testing::Test {

-  virtual void SetUp() {

-  }

-

-  virtual void TearDown() {

-  }

-};

-

-

-TEST_F(SignatureValidatorTest, VerifySigneeIsGoogle_OfficiallySigned) {

-  const TCHAR kUnsignedExecutable[] =

-      _T("unittest_support\\SaveArguments.exe");

-

-  CString executable_full_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),

-                           kUnsignedExecutable));

-  ASSERT_TRUE(File::Exists(executable_full_path));

-  EXPECT_TRUE(VerifySigneeIsGoogleNoTimestampCheck(executable_full_path));

-}

-

-TEST_F(SignatureValidatorTest, VerifySigneeIsGoogle_OmahaTestSigned) {

-  const TCHAR kUnsignedExecutable[] =

-      _T("unittest_support\\SaveArguments_OmahaTestSigned.exe");

-

-  CString executable_full_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),

-                           kUnsignedExecutable));

-  ASSERT_TRUE(File::Exists(executable_full_path));

-  EXPECT_TRUE(VerifySigneeIsGoogleNoTimestampCheck(executable_full_path));

-}

-

-}  // namespace omaha

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Unit tests for the Google file signature validation.
+
+#include <windows.h>
+#include <atlstr.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/file.h"
+#include "omaha/common/signaturevalidator.h"
+#include "omaha/third_party/gtest/include/gtest/gtest.h"
+
+namespace omaha {
+
+class SignatureValidatorTest : public testing::Test {
+  virtual void SetUp() {
+  }
+
+  virtual void TearDown() {
+  }
+};
+
+
+TEST_F(SignatureValidatorTest, VerifySigneeIsGoogle_OfficiallySigned) {
+  const TCHAR kUnsignedExecutable[] =
+      _T("unittest_support\\SaveArguments.exe");
+
+  CString executable_full_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),
+                           kUnsignedExecutable));
+  ASSERT_TRUE(File::Exists(executable_full_path));
+  EXPECT_TRUE(VerifySigneeIsGoogleNoTimestampCheck(executable_full_path));
+}
+
+TEST_F(SignatureValidatorTest, VerifySigneeIsGoogle_OmahaTestSigned) {
+  const TCHAR kUnsignedExecutable[] =
+      _T("unittest_support\\SaveArguments_OmahaTestSigned.exe");
+
+  CString executable_full_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH),
+                           kUnsignedExecutable));
+  ASSERT_TRUE(File::Exists(executable_full_path));
+  EXPECT_TRUE(VerifySigneeIsGoogleNoTimestampCheck(executable_full_path));
+}
+
+}  // namespace omaha
diff --git a/common/single_instance.cc b/common/single_instance.cc
index 7a7f281..fea4c06 100644
--- a/common/single_instance.cc
+++ b/common/single_instance.cc
@@ -1,196 +1,196 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Synchronization functions

-

-#include "omaha/common/single_instance.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-// Check to see whether an instance is already running across all sessions.

-// If not, enter single instance protection. The user must call Shutdown()

-// on that SingleInstance once single instance protection is no longer needed.

-bool SingleInstance::StartupSingleInstance(const TCHAR* id) {

-  ASSERT1(id);

-

-  bool already_running = false, already_running_in_different_session = false;

-  HRESULT hr = Startup(id,

-                       &already_running,

-                       &already_running_in_different_session);

-  ASSERT(SUCCEEDED(hr), (_T("")));

-

-  return already_running || already_running_in_different_session;

-}

-

-// Check to see whether an instance is already running in this session. If not,

-// enter session-only single instance protection. The user must call Shutdown()

-// on that SingleInstance once single instance protection is no longer needed.

-bool SingleInstance::StartupSingleSessionInstance(const TCHAR* id) {

-  ASSERT1(id);

-

-  bool already_running = false;

-  HRESULT hr = Startup(id, &already_running, NULL);

-  ASSERT(SUCCEEDED(hr), (_T("")));

-

-  return already_running;

-}

-

-// Startup a single instance protection. The user must call Shutdown() on

-// that SingleInstance once the single instance protection is no longer needed.

-//

-// Returns whether or not the process is already running

-// already_running means "already running in same session".

-// already_running_in_different_session means "already running on machine"

-HRESULT SingleInstance::Startup(const TCHAR* id,

-                                bool* already_running,

-                                bool* already_running_in_different_session) {

-  ASSERT1(id);

-  ASSERT1(already_running);

-

-  CString mutex_id;

-

-  // Use two mutexes: one to check for being the only instance in this

-  // session, and one for being the only instance in any terminal session.

-  // Only create (and check) the global mutex for one-per-machine check if

-  // the result is asked for.

-  // We don't actually obtain ownership of the mutex

-  // For information on the "Local" and "Global" namespace prefixes, see MSDN

-  // article "Kernel Object Namespaces".

-

-  // Create a user level mutex

-  CreateSyncId(id, SYNC_USER, &mutex_id);

-  RET_IF_FAILED(CreateInstanceMutex(mutex_id,

-                                    &user_mutex_handle_,

-                                    already_running));

-

-  // Create a global mutex

-  if (already_running_in_different_session) {

-    CreateSyncId(id, SYNC_GLOBAL, &mutex_id);

-    RET_IF_FAILED(CreateInstanceMutex(mutex_id,

-                                      &global_mutex_handle_,

-                                      already_running_in_different_session));

-  }

-

-  return S_OK;

-}

-

-// Create a mutex

-HRESULT SingleInstance::CreateInstanceMutex(const TCHAR* mutex_id,

-                                            HANDLE* mutex_handle,

-                                            bool* already_running) {

-  ASSERT1(mutex_id && *mutex_id);

-  ASSERT1(mutex_handle);

-  ASSERT1(already_running);

-

-  *already_running = false;

-

-  *mutex_handle = ::CreateMutex(NULL, false, mutex_id);

-  DWORD last_error = ::GetLastError();

-

-  // We check for both values because we sometimes see access

-  // denied.  We expect this to mean that the mutex was created by a

-  // different set of user credentials, which shouldn't happen under

-  // normal circumstances in our applications, but in fact we did

-  // see it happen.

-  if (last_error == ERROR_ALREADY_EXISTS || last_error == ERROR_ACCESS_DENIED) {

-    *already_running = true;

-    return S_OK;

-  }

-

-  if (*mutex_handle == NULL) {

-    HRESULT hr = HRESULT_FROM_WIN32(last_error);

-    ASSERT(false, (_T("[SingleInstance::CreateInstanceMutex]")

-                   _T("[failed to create mutex][%s][0x%x]"), mutex_id, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// Shutdown a single instance protection

-HRESULT SingleInstance::Shutdown() {

-  if (user_mutex_handle_) {

-    VERIFY(::CloseHandle(user_mutex_handle_), (_T("")));

-    user_mutex_handle_ = NULL;

-  }

-

-  if (global_mutex_handle_) {

-    VERIFY(::CloseHandle(global_mutex_handle_), (_T("")));

-    global_mutex_handle_ = NULL;

-  }

-

-  return S_OK;

-}

-

-// Check to see whether an instance is already running

-HRESULT SingleInstance::CheckAlreadyRunning(

-    const TCHAR* id,

-    bool* already_running,

-    bool* already_running_in_different_session) {

-  ASSERT1(id);

-  ASSERT1(already_running);

-

-  CString mutex_id;

-

-  // Open a user level mutex

-  CreateSyncId(id, SYNC_USER, &mutex_id);

-  RET_IF_FAILED(OpenInstanceMutex(mutex_id, already_running));

-

-  // Open a global mutex

-  if (already_running_in_different_session) {

-    CreateSyncId(id, SYNC_GLOBAL, &mutex_id);

-    RET_IF_FAILED(OpenInstanceMutex(mutex_id,

-                                    already_running_in_different_session));

-  }

-

-  return S_OK;

-}

-

-// Open a mutex

-HRESULT SingleInstance::OpenInstanceMutex(const TCHAR* mutex_id,

-                                          bool* already_running) {

-  ASSERT1(mutex_id && *mutex_id);

-  ASSERT1(already_running);

-

-  *already_running = false;

-

-  scoped_handle mutex_handle(::OpenMutex(NULL, false, mutex_id));

-  DWORD last_error = ::GetLastError();

-

-  if (get(mutex_handle) || last_error == ERROR_ACCESS_DENIED) {

-    UTIL_LOG(L3, (_T("[SingleInstance::OpenInstanceMutex]")

-                  _T("[already running][0x%x]"), last_error));

-    *already_running = true;

-    return S_OK;

-  }

-

-  if (last_error != ERROR_FILE_NOT_FOUND) {

-    HRESULT hr = HRESULT_FROM_WIN32(last_error);

-    ASSERT(false, (_T("[SingleInstance::OpenInstanceMutex]")

-                   _T("[failed to open mutex][%s][0x%x]"), mutex_id, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Synchronization functions
+
+#include "omaha/common/single_instance.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+// Check to see whether an instance is already running across all sessions.
+// If not, enter single instance protection. The user must call Shutdown()
+// on that SingleInstance once single instance protection is no longer needed.
+bool SingleInstance::StartupSingleInstance(const TCHAR* id) {
+  ASSERT1(id);
+
+  bool already_running = false, already_running_in_different_session = false;
+  HRESULT hr = Startup(id,
+                       &already_running,
+                       &already_running_in_different_session);
+  ASSERT(SUCCEEDED(hr), (_T("")));
+
+  return already_running || already_running_in_different_session;
+}
+
+// Check to see whether an instance is already running in this session. If not,
+// enter session-only single instance protection. The user must call Shutdown()
+// on that SingleInstance once single instance protection is no longer needed.
+bool SingleInstance::StartupSingleSessionInstance(const TCHAR* id) {
+  ASSERT1(id);
+
+  bool already_running = false;
+  HRESULT hr = Startup(id, &already_running, NULL);
+  ASSERT(SUCCEEDED(hr), (_T("")));
+
+  return already_running;
+}
+
+// Startup a single instance protection. The user must call Shutdown() on
+// that SingleInstance once the single instance protection is no longer needed.
+//
+// Returns whether or not the process is already running
+// already_running means "already running in same session".
+// already_running_in_different_session means "already running on machine"
+HRESULT SingleInstance::Startup(const TCHAR* id,
+                                bool* already_running,
+                                bool* already_running_in_different_session) {
+  ASSERT1(id);
+  ASSERT1(already_running);
+
+  CString mutex_id;
+
+  // Use two mutexes: one to check for being the only instance in this
+  // session, and one for being the only instance in any terminal session.
+  // Only create (and check) the global mutex for one-per-machine check if
+  // the result is asked for.
+  // We don't actually obtain ownership of the mutex
+  // For information on the "Local" and "Global" namespace prefixes, see MSDN
+  // article "Kernel Object Namespaces".
+
+  // Create a user level mutex
+  CreateSyncId(id, SYNC_USER, &mutex_id);
+  RET_IF_FAILED(CreateInstanceMutex(mutex_id,
+                                    &user_mutex_handle_,
+                                    already_running));
+
+  // Create a global mutex
+  if (already_running_in_different_session) {
+    CreateSyncId(id, SYNC_GLOBAL, &mutex_id);
+    RET_IF_FAILED(CreateInstanceMutex(mutex_id,
+                                      &global_mutex_handle_,
+                                      already_running_in_different_session));
+  }
+
+  return S_OK;
+}
+
+// Create a mutex
+HRESULT SingleInstance::CreateInstanceMutex(const TCHAR* mutex_id,
+                                            HANDLE* mutex_handle,
+                                            bool* already_running) {
+  ASSERT1(mutex_id && *mutex_id);
+  ASSERT1(mutex_handle);
+  ASSERT1(already_running);
+
+  *already_running = false;
+
+  *mutex_handle = ::CreateMutex(NULL, false, mutex_id);
+  DWORD last_error = ::GetLastError();
+
+  // We check for both values because we sometimes see access
+  // denied.  We expect this to mean that the mutex was created by a
+  // different set of user credentials, which shouldn't happen under
+  // normal circumstances in our applications, but in fact we did
+  // see it happen.
+  if (last_error == ERROR_ALREADY_EXISTS || last_error == ERROR_ACCESS_DENIED) {
+    *already_running = true;
+    return S_OK;
+  }
+
+  if (*mutex_handle == NULL) {
+    HRESULT hr = HRESULT_FROM_WIN32(last_error);
+    ASSERT(false, (_T("[SingleInstance::CreateInstanceMutex]")
+                   _T("[failed to create mutex][%s][0x%x]"), mutex_id, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// Shutdown a single instance protection
+HRESULT SingleInstance::Shutdown() {
+  if (user_mutex_handle_) {
+    VERIFY(::CloseHandle(user_mutex_handle_), (_T("")));
+    user_mutex_handle_ = NULL;
+  }
+
+  if (global_mutex_handle_) {
+    VERIFY(::CloseHandle(global_mutex_handle_), (_T("")));
+    global_mutex_handle_ = NULL;
+  }
+
+  return S_OK;
+}
+
+// Check to see whether an instance is already running
+HRESULT SingleInstance::CheckAlreadyRunning(
+    const TCHAR* id,
+    bool* already_running,
+    bool* already_running_in_different_session) {
+  ASSERT1(id);
+  ASSERT1(already_running);
+
+  CString mutex_id;
+
+  // Open a user level mutex
+  CreateSyncId(id, SYNC_USER, &mutex_id);
+  RET_IF_FAILED(OpenInstanceMutex(mutex_id, already_running));
+
+  // Open a global mutex
+  if (already_running_in_different_session) {
+    CreateSyncId(id, SYNC_GLOBAL, &mutex_id);
+    RET_IF_FAILED(OpenInstanceMutex(mutex_id,
+                                    already_running_in_different_session));
+  }
+
+  return S_OK;
+}
+
+// Open a mutex
+HRESULT SingleInstance::OpenInstanceMutex(const TCHAR* mutex_id,
+                                          bool* already_running) {
+  ASSERT1(mutex_id && *mutex_id);
+  ASSERT1(already_running);
+
+  *already_running = false;
+
+  scoped_handle mutex_handle(::OpenMutex(NULL, false, mutex_id));
+  DWORD last_error = ::GetLastError();
+
+  if (get(mutex_handle) || last_error == ERROR_ACCESS_DENIED) {
+    UTIL_LOG(L3, (_T("[SingleInstance::OpenInstanceMutex]")
+                  _T("[already running][0x%x]"), last_error));
+    *already_running = true;
+    return S_OK;
+  }
+
+  if (last_error != ERROR_FILE_NOT_FOUND) {
+    HRESULT hr = HRESULT_FROM_WIN32(last_error);
+    ASSERT(false, (_T("[SingleInstance::OpenInstanceMutex]")
+                   _T("[failed to open mutex][%s][0x%x]"), mutex_id, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/common/single_instance.h b/common/single_instance.h
index 56ae247..df0d2d0 100644
--- a/common/single_instance.h
+++ b/common/single_instance.h
@@ -1,83 +1,83 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// Single Instance of a process running (plus some synchronization functions

-// that should be moved elsewhere)

-//

-// synchronization functions

-

-#ifndef OMAHA_COMMON_SINGLE_INSTANCE_H_

-#define OMAHA_COMMON_SINGLE_INSTANCE_H_

-

-#include <windows.h>

-

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-// Used to ensure only a single instance of a process per machine

-// (e.g., even in terminal server sessions)

-class SingleInstance {

- public:

-  // Constructor

-  SingleInstance() : user_mutex_handle_(NULL), global_mutex_handle_(NULL) {}

-

-  // Destructor

-  ~SingleInstance() { Shutdown(); }

-

-  // Check to see whether an instance is already running across all sessions.

-  // If not, enter single instance protection. The user must call Shutdown()

-  // on that SingleInstance once single instance protection is no longer needed.

-  bool StartupSingleInstance(const TCHAR* id);

-

-  // Check to see whether an instance is already running for this user. If not,

-  // enter user-only single instance protection. The user must call Shutdown()

-  // on that SingleInstance once single instance protection is no longer needed.

-  bool StartupSingleSessionInstance(const TCHAR* id);

-

-  // Startup a single instance protection. The user must call Shutdown() on

-  // that SingleInstance once the single instance protection is no longer needed.

-  HRESULT Startup(const TCHAR* id,

-                  bool* already_running,

-                  bool* already_running_in_different_session);

-

-  // Shutdown a single instance protection

-  HRESULT Shutdown();

-

-  // Check to see whether an instance is already running

-  static HRESULT CheckAlreadyRunning(

-      const TCHAR* id,

-      bool* already_running,

-      bool* already_running_in_different_session);

-

- private:

-  // Create a mutex

-  static HRESULT CreateInstanceMutex(const TCHAR* mutex_id,

-                                     HANDLE* mutex_handle,

-                                     bool* already_running);

-

-  // Open a mutex

-  static HRESULT OpenInstanceMutex(const TCHAR* mutex_id,

-                                   bool* already_running);

-

-  HANDLE user_mutex_handle_;

-  HANDLE global_mutex_handle_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(SingleInstance);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SINGLE_INSTANCE_H_

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// Single Instance of a process running (plus some synchronization functions
+// that should be moved elsewhere)
+//
+// synchronization functions
+
+#ifndef OMAHA_COMMON_SINGLE_INSTANCE_H_
+#define OMAHA_COMMON_SINGLE_INSTANCE_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+// Used to ensure only a single instance of a process per machine
+// (e.g., even in terminal server sessions)
+class SingleInstance {
+ public:
+  // Constructor
+  SingleInstance() : user_mutex_handle_(NULL), global_mutex_handle_(NULL) {}
+
+  // Destructor
+  ~SingleInstance() { Shutdown(); }
+
+  // Check to see whether an instance is already running across all sessions.
+  // If not, enter single instance protection. The user must call Shutdown()
+  // on that SingleInstance once single instance protection is no longer needed.
+  bool StartupSingleInstance(const TCHAR* id);
+
+  // Check to see whether an instance is already running for this user. If not,
+  // enter user-only single instance protection. The user must call Shutdown()
+  // on that SingleInstance once single instance protection is no longer needed.
+  bool StartupSingleSessionInstance(const TCHAR* id);
+
+  // Startup a single instance protection. The user must call Shutdown() on
+  // that SingleInstance once the single instance protection is no longer needed.
+  HRESULT Startup(const TCHAR* id,
+                  bool* already_running,
+                  bool* already_running_in_different_session);
+
+  // Shutdown a single instance protection
+  HRESULT Shutdown();
+
+  // Check to see whether an instance is already running
+  static HRESULT CheckAlreadyRunning(
+      const TCHAR* id,
+      bool* already_running,
+      bool* already_running_in_different_session);
+
+ private:
+  // Create a mutex
+  static HRESULT CreateInstanceMutex(const TCHAR* mutex_id,
+                                     HANDLE* mutex_handle,
+                                     bool* already_running);
+
+  // Open a mutex
+  static HRESULT OpenInstanceMutex(const TCHAR* mutex_id,
+                                   bool* already_running);
+
+  HANDLE user_mutex_handle_;
+  HANDLE global_mutex_handle_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(SingleInstance);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SINGLE_INSTANCE_H_
diff --git a/common/singleton.h b/common/singleton.h
index b0d2bcd..3e99f89 100644
--- a/common/singleton.h
+++ b/common/singleton.h
@@ -1,133 +1,133 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines two classes

-// 1. class SingletonBase.

-// 2. template class Singleton.

-// Creation of singletons is a common

-// activity. Use Singleton class to not

-// repeat code every time.

-

-#ifndef OMAHA_COMMON_SINGLETON_H_

-#define OMAHA_COMMON_SINGLETON_H_

-

-#include "omaha/common/debug.h"

-#include "omaha/common/synchronized.h"

-

-

-// Very important design pattern.

-// Singleton class can be used in two ways.

-// 1. Pass the class you want to make into Singleton as a

-//    template parameter.

-//

-//    class SomeClass {

-//     protected:

-//    SomeClass(){}  // note - it is protected

-//    ~SomeClass(){} // note - it is protected

-//    public:

-//    void Foo() {}

-//  };

-//

-//   Singleton<SomeClass> s;

-//   s::Instance()->Foo();

-//

-//     OR

-// 2. You class can be derived from Singleton in a following way:

-//    class SomeClass : public Singleton<SomeClass> {

-//     protected:

-//    SomeClass(){}

-//    ~SomeClass(){}

-//    public:

-//    void Foo() {}

-//  };

-//

-//   SomeClass::Instance()->Foo();

-//

-//  There is no requirement on the class you want to make into

-//  Singleton except is has to have constructor that takes nothing.

-//  As long as the class has void constructor it can become a singleton.

-//  However if you want you class to be trully singleton you have to make

-//  it constructors and destructors protected. Than you can only access your

-//  class through the singlenot interface Instance().

-//  If simple void constructor is not enough for you class, provide some kind of

-//  initialization function, which could be called after the instance is

-// created.

-

-#define kSingletonMutexName               kLockPrefix L"Singleton_Creation_Lock"

-

-#ifdef _DEBUG

-  #define InstanceReturnTypeDeclaration SingletonProxy<T>

-  #define InstanceReturnTypeStatement   SingletonProxy<T>

-#else

-  #define InstanceReturnTypeDeclaration T*

-  #define InstanceReturnTypeStatement

-#endif

-

-template <typename T> class Singleton  {

-  // Caching pointers to Singletons is very dangerous and goes against

-  // Singleton philosophy. So we will return proxy from instance in Debug mode.

-  // In release mode we will not go this route for efficiency.

-  template <typename T> class SingletonProxy {

-    T* data_;

-  public:

-    explicit SingletonProxy(T* data) : data_(data) {}

-    T* operator->() const  {

-      return data_;

-    }

-    SingletonProxy& operator=(const SingletonProxy&);

-  };

-

- public:

-  Singleton() {}

-

-  // Use double-check pattern for efficiency.

-  // TODO(omaha): the pattern is broken on multicore.

-  static InstanceReturnTypeDeclaration Instance() {

-    if(instance_ == NULL) {

-      // We use GLock here since LLock will not give us synchronization and

-      // SimpleLock will create deadlock if one singleton is created in the

-      // constructor of the other singleton.

-      GLock creation_lock;

-      TCHAR mutex_name[MAX_PATH] = {0};

-      wsprintf(mutex_name, L"%s%d",

-               kSingletonMutexName, ::GetCurrentProcessId());

-

-      VERIFY1(creation_lock.Initialize(mutex_name));

-      __mutexScope(creation_lock);

-      if(instance_ == NULL)

-         instance_ = GetInstance();

-    }

-    return InstanceReturnTypeStatement(instance_);

-  }

-

- private:

-  static T* GetInstance() {

-    static MyT my_t;

-    return &my_t;

-  }

-

-  // shared between the same type T.

-  static T * instance_;

-

-  // Needed to access the protected constructor

-  // of a client.

-  class MyT : public T {

-  };

-};

-

-// This instance_ is shared between template of the same type.

-template <typename T>  T* Singleton<T>::instance_ = NULL;

-

-#endif  // OMAHA_COMMON_SINGLETON_H_

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines two classes
+// 1. class SingletonBase.
+// 2. template class Singleton.
+// Creation of singletons is a common
+// activity. Use Singleton class to not
+// repeat code every time.
+
+#ifndef OMAHA_COMMON_SINGLETON_H_
+#define OMAHA_COMMON_SINGLETON_H_
+
+#include "omaha/common/debug.h"
+#include "omaha/common/synchronized.h"
+
+
+// Very important design pattern.
+// Singleton class can be used in two ways.
+// 1. Pass the class you want to make into Singleton as a
+//    template parameter.
+//
+//    class SomeClass {
+//     protected:
+//    SomeClass(){}  // note - it is protected
+//    ~SomeClass(){} // note - it is protected
+//    public:
+//    void Foo() {}
+//  };
+//
+//   Singleton<SomeClass> s;
+//   s::Instance()->Foo();
+//
+//     OR
+// 2. You class can be derived from Singleton in a following way:
+//    class SomeClass : public Singleton<SomeClass> {
+//     protected:
+//    SomeClass(){}
+//    ~SomeClass(){}
+//    public:
+//    void Foo() {}
+//  };
+//
+//   SomeClass::Instance()->Foo();
+//
+//  There is no requirement on the class you want to make into
+//  Singleton except is has to have constructor that takes nothing.
+//  As long as the class has void constructor it can become a singleton.
+//  However if you want you class to be trully singleton you have to make
+//  it constructors and destructors protected. Than you can only access your
+//  class through the singlenot interface Instance().
+//  If simple void constructor is not enough for you class, provide some kind of
+//  initialization function, which could be called after the instance is
+// created.
+
+#define kSingletonMutexName               kLockPrefix L"Singleton_Creation_Lock"
+
+#ifdef _DEBUG
+  #define InstanceReturnTypeDeclaration SingletonProxy<T>
+  #define InstanceReturnTypeStatement   SingletonProxy<T>
+#else
+  #define InstanceReturnTypeDeclaration T*
+  #define InstanceReturnTypeStatement
+#endif
+
+template <typename T> class Singleton  {
+  // Caching pointers to Singletons is very dangerous and goes against
+  // Singleton philosophy. So we will return proxy from instance in Debug mode.
+  // In release mode we will not go this route for efficiency.
+  template <typename T> class SingletonProxy {
+    T* data_;
+  public:
+    explicit SingletonProxy(T* data) : data_(data) {}
+    T* operator->() const  {
+      return data_;
+    }
+    SingletonProxy& operator=(const SingletonProxy&);
+  };
+
+ public:
+  Singleton() {}
+
+  // Use double-check pattern for efficiency.
+  // TODO(omaha): the pattern is broken on multicore.
+  static InstanceReturnTypeDeclaration Instance() {
+    if(instance_ == NULL) {
+      // We use GLock here since LLock will not give us synchronization and
+      // SimpleLock will create deadlock if one singleton is created in the
+      // constructor of the other singleton.
+      GLock creation_lock;
+      TCHAR mutex_name[MAX_PATH] = {0};
+      wsprintf(mutex_name, L"%s%d",
+               kSingletonMutexName, ::GetCurrentProcessId());
+
+      VERIFY1(creation_lock.Initialize(mutex_name));
+      __mutexScope(creation_lock);
+      if(instance_ == NULL)
+         instance_ = GetInstance();
+    }
+    return InstanceReturnTypeStatement(instance_);
+  }
+
+ private:
+  static T* GetInstance() {
+    static MyT my_t;
+    return &my_t;
+  }
+
+  // shared between the same type T.
+  static T * instance_;
+
+  // Needed to access the protected constructor
+  // of a client.
+  class MyT : public T {
+  };
+};
+
+// This instance_ is shared between template of the same type.
+template <typename T>  T* Singleton<T>::instance_ = NULL;
+
+#endif  // OMAHA_COMMON_SINGLETON_H_
diff --git a/common/smart_handle.h b/common/smart_handle.h
index 78fb224..154fe04 100644
--- a/common/smart_handle.h
+++ b/common/smart_handle.h
@@ -1,240 +1,240 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Classes for automatically closing handles.

-

-#ifndef OMAHA_COMMON_SMART_HANDLE_H_

-#define OMAHA_COMMON_SMART_HANDLE_H_

-

-#include <wincrypt.h>

-

-namespace omaha {

-

-/**

-* Base traits class for handles.

-* This base class provides default implementation for InvalidValue and IsValid

-* @param T  The handle type to be wrapped.

-*/

-template<class T>

-class BaseHandleTraitsT {

- public:

-  // Typedef that is used by this class and derived classes

-  typedef T HandleType;

-

-  // Returns the invalid handle value

-  static HandleType InvalidValue() {

-    return NULL;

-  }

-

-  // Returns true only if the given handle h is invalid

-  static bool IsValid(const HandleType& h) {

-    return h != InvalidValue();

-  }

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(BaseHandleTraitsT);

-};

-

-/**

-* Smart handle class.

-* Offers basic HANDLE functionality such as cast, attach/detach and automatic Close().

-*/

-template<class T, class Traits, class AlternateType = T>

-class HandleT {

- public:

-  // Default constructor.

-  HandleT() : h_(Traits::InvalidValue()) {

-  }

-

-  // Constructor that assumes ownership of the supplied handle

-  explicit HandleT(T h) : h_(h) {

-  }

-

-  // Destructor calls @ref Close()

-  ~HandleT() {

-    Close();

-  }

-

-  // Assumes ownership of the supplied handle,

-  // potentially closing an already held handle.

-  void Attach(T h) {

-    Close();

-    h_ = h;

-  }

-

-  // Transfers ownership to the caller and sets the internal

-  // state to InvalidValue().

-  T Detach() {

-    T h = h_;

-    h_ = Traits::InvalidValue();

-    return h;

-  }

-

-  // Handle accessor

-  T handle() {

-    return h_;

-  }

-

-  // An alternate cast for the handle.

-  // This can be useful for GDI objects that are used

-  // in functions that e.g. accept both HGDIOBJ and HBITMAP.

-  AlternateType alt_type() {

-    return reinterpret_cast<AlternateType>(h_);

-  }

-

-  // Accesses the contained handle

-  operator T() {

-    return h_;

-  }

-

-  T& receive() {

-    ASSERT(!IsValid(), (L"Should only be used for out arguments"));

-    return h_;

-  }

-

-  // @returns true only if the handle is valid as depicted

-  //  by the traits class.

-  bool IsValid() {

-    return Traits::IsValid(h_);

-  }

-

-  // Closes the handle

-  void Close() {

-    if (Traits::IsValid(h_)) {

-      Traits::Close(h_);

-      h_ = Traits::InvalidValue();

-    }

-  }

-

- protected:

-  T h_;

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(HandleT);

-};

-

-

-/*

-* Traits class for a regular Win32 HANDLE.

-*/

-class HandleTraitsWin32Handle : public BaseHandleTraitsT<HANDLE> {

- public:

-  // Calls FindClose to close the handle.

-  static bool Close(HandleType h) {

-    return (::CloseHandle(h) != false);

-  }

-

-  // Returns the invalid handle value

-  static HandleType InvalidValue() {

-    return NULL;  // note that INVALID_HANDLE_VALUE is also an invalid handle

-  }

-

-  // Returns true only if the given handle h is invalid

-  static bool IsValid(const HandleType& h) {

-    return h != InvalidValue() && h != INVALID_HANDLE_VALUE;

-  }

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsWin32Handle);

-};

-

-/*

-* Traits class for FindXXXFile handles.

-*/

-class HandleTraitsFindHandle : public BaseHandleTraitsT<HANDLE> {

- public:

-  // Calls FindClose to close the handle.

-  static bool Close(HandleType h) {

-    return (::FindClose(h) != false);

-  }

-

-  // Returns the invalid handle value

-  static HandleType InvalidValue() {

-    return INVALID_HANDLE_VALUE;

-  }

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsFindHandle);

-};

-

-/*

-* Traits for an HMENU.

-*/

-class HandleTraitsHMenu : public BaseHandleTraitsT<HMENU> {

- public:

-  // Calls DestroyMenu to destroy the menu.

-  static bool Close(HandleType h) {

-    return (::DestroyMenu(h) != FALSE);

-  }

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsHMenu);

-};

-

-/*

-* Traits for an HCRYPTKEY.

-*/

-class HandleTraitsHCryptKey : public BaseHandleTraitsT<HCRYPTKEY> {

- public:

-  static bool Close(HandleType h) {

-    return (::CryptDestroyKey(h) != FALSE);

-  }

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsHCryptKey);

-};

-

-/*

-* Traits for an HCRYPTHASH.

-*/

-class HandleTraitsHCryptHash : public BaseHandleTraitsT<HCRYPTHASH> {

- public:

-  static bool Close(HandleType h) {

-    return (::CryptDestroyHash(h) != FALSE);

-  }

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsHCryptHash);

-};

-

-/*

- * Traits for LoadLibrary/FreeLibrary.

- */

-class HandleTraitsLibrary : public BaseHandleTraitsT<HMODULE> {

- public:

-  static bool Close(HandleType h) {

-    return (::FreeLibrary(h) != FALSE);

-  }

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsLibrary);

-};

-

-

-/*

-* Win32 handle types.  Add new ones here as you need them.

-* Note that GDI handle types should be kept in common/gdi_smart_ptr.h

-* rather than here.

-*/

-typedef HandleT<HANDLE, HandleTraitsWin32Handle> AutoHandle;

-typedef HandleT<HANDLE, HandleTraitsFindHandle> AutoFindHandle;

-typedef HandleT<HMENU, HandleTraitsHMenu> AutoHMenu;

-typedef HandleT<HCRYPTHASH, HandleTraitsHCryptHash> AutoHCryptHash;

-typedef HandleT<HCRYPTKEY, HandleTraitsHCryptKey> AutoHCryptKey;

-typedef HandleT<HINSTANCE, HandleTraitsLibrary> AutoLibrary;

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SMART_HANDLE_H_

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Classes for automatically closing handles.
+
+#ifndef OMAHA_COMMON_SMART_HANDLE_H_
+#define OMAHA_COMMON_SMART_HANDLE_H_
+
+#include <wincrypt.h>
+
+namespace omaha {
+
+/**
+* Base traits class for handles.
+* This base class provides default implementation for InvalidValue and IsValid
+* @param T  The handle type to be wrapped.
+*/
+template<class T>
+class BaseHandleTraitsT {
+ public:
+  // Typedef that is used by this class and derived classes
+  typedef T HandleType;
+
+  // Returns the invalid handle value
+  static HandleType InvalidValue() {
+    return NULL;
+  }
+
+  // Returns true only if the given handle h is invalid
+  static bool IsValid(const HandleType& h) {
+    return h != InvalidValue();
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(BaseHandleTraitsT);
+};
+
+/**
+* Smart handle class.
+* Offers basic HANDLE functionality such as cast, attach/detach and automatic Close().
+*/
+template<class T, class Traits, class AlternateType = T>
+class HandleT {
+ public:
+  // Default constructor.
+  HandleT() : h_(Traits::InvalidValue()) {
+  }
+
+  // Constructor that assumes ownership of the supplied handle
+  explicit HandleT(T h) : h_(h) {
+  }
+
+  // Destructor calls @ref Close()
+  ~HandleT() {
+    Close();
+  }
+
+  // Assumes ownership of the supplied handle,
+  // potentially closing an already held handle.
+  void Attach(T h) {
+    Close();
+    h_ = h;
+  }
+
+  // Transfers ownership to the caller and sets the internal
+  // state to InvalidValue().
+  T Detach() {
+    T h = h_;
+    h_ = Traits::InvalidValue();
+    return h;
+  }
+
+  // Handle accessor
+  T handle() {
+    return h_;
+  }
+
+  // An alternate cast for the handle.
+  // This can be useful for GDI objects that are used
+  // in functions that e.g. accept both HGDIOBJ and HBITMAP.
+  AlternateType alt_type() {
+    return reinterpret_cast<AlternateType>(h_);
+  }
+
+  // Accesses the contained handle
+  operator T() {
+    return h_;
+  }
+
+  T& receive() {
+    ASSERT(!IsValid(), (L"Should only be used for out arguments"));
+    return h_;
+  }
+
+  // @returns true only if the handle is valid as depicted
+  //  by the traits class.
+  bool IsValid() {
+    return Traits::IsValid(h_);
+  }
+
+  // Closes the handle
+  void Close() {
+    if (Traits::IsValid(h_)) {
+      Traits::Close(h_);
+      h_ = Traits::InvalidValue();
+    }
+  }
+
+ protected:
+  T h_;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(HandleT);
+};
+
+
+/*
+* Traits class for a regular Win32 HANDLE.
+*/
+class HandleTraitsWin32Handle : public BaseHandleTraitsT<HANDLE> {
+ public:
+  // Calls FindClose to close the handle.
+  static bool Close(HandleType h) {
+    return (::CloseHandle(h) != false);
+  }
+
+  // Returns the invalid handle value
+  static HandleType InvalidValue() {
+    return NULL;  // note that INVALID_HANDLE_VALUE is also an invalid handle
+  }
+
+  // Returns true only if the given handle h is invalid
+  static bool IsValid(const HandleType& h) {
+    return h != InvalidValue() && h != INVALID_HANDLE_VALUE;
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsWin32Handle);
+};
+
+/*
+* Traits class for FindXXXFile handles.
+*/
+class HandleTraitsFindHandle : public BaseHandleTraitsT<HANDLE> {
+ public:
+  // Calls FindClose to close the handle.
+  static bool Close(HandleType h) {
+    return (::FindClose(h) != false);
+  }
+
+  // Returns the invalid handle value
+  static HandleType InvalidValue() {
+    return INVALID_HANDLE_VALUE;
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsFindHandle);
+};
+
+/*
+* Traits for an HMENU.
+*/
+class HandleTraitsHMenu : public BaseHandleTraitsT<HMENU> {
+ public:
+  // Calls DestroyMenu to destroy the menu.
+  static bool Close(HandleType h) {
+    return (::DestroyMenu(h) != FALSE);
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsHMenu);
+};
+
+/*
+* Traits for an HCRYPTKEY.
+*/
+class HandleTraitsHCryptKey : public BaseHandleTraitsT<HCRYPTKEY> {
+ public:
+  static bool Close(HandleType h) {
+    return (::CryptDestroyKey(h) != FALSE);
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsHCryptKey);
+};
+
+/*
+* Traits for an HCRYPTHASH.
+*/
+class HandleTraitsHCryptHash : public BaseHandleTraitsT<HCRYPTHASH> {
+ public:
+  static bool Close(HandleType h) {
+    return (::CryptDestroyHash(h) != FALSE);
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsHCryptHash);
+};
+
+/*
+ * Traits for LoadLibrary/FreeLibrary.
+ */
+class HandleTraitsLibrary : public BaseHandleTraitsT<HMODULE> {
+ public:
+  static bool Close(HandleType h) {
+    return (::FreeLibrary(h) != FALSE);
+  }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(HandleTraitsLibrary);
+};
+
+
+/*
+* Win32 handle types.  Add new ones here as you need them.
+* Note that GDI handle types should be kept in common/gdi_smart_ptr.h
+* rather than here.
+*/
+typedef HandleT<HANDLE, HandleTraitsWin32Handle> AutoHandle;
+typedef HandleT<HANDLE, HandleTraitsFindHandle> AutoFindHandle;
+typedef HandleT<HMENU, HandleTraitsHMenu> AutoHMenu;
+typedef HandleT<HCRYPTHASH, HandleTraitsHCryptHash> AutoHCryptHash;
+typedef HandleT<HCRYPTKEY, HandleTraitsHCryptKey> AutoHCryptKey;
+typedef HandleT<HINSTANCE, HandleTraitsLibrary> AutoLibrary;
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SMART_HANDLE_H_
diff --git a/common/sta.cc b/common/sta.cc
index af2e83b..cb3c59f 100644
--- a/common/sta.cc
+++ b/common/sta.cc
@@ -1,353 +1,353 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/sta.h"

-

-#include <atlbase.h>

-#include <atlwin.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/sta_call.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-namespace {

-

-class CallDispatcher;

-

-// ApartmentState maintains the state of the apartment. It keeps a reference

-// to a call dispatcher. The dispatcher is basically a window object that

-// handles user messages corresponding to each call.

-//

-// ApartmentState is a singleton. It's lifetime is controlled by the

-// 'InitializeApartment' and 'UnintializeApartment'.

-//

-// The current implementation is limited to the main STA. Creating multiple

-// apartments in a process is not possible.

-//

-// TODO(omaha): implement a simple reference counting of the threads to make

-// sure the all the calling threads have returned when the apt is destroyed.

-

-class ApartmentState {

- public:

-  ApartmentState(DWORD thread_id, CallDispatcher* call_disp)

-      : thread_id_(thread_id), call_dispatcher_(call_disp) {}

-

-  ~ApartmentState() {

-    ASSERT1(ref_cnt_ == 0);

-  }

-

-  // Initialize the state of the singleton.

-  static HRESULT Initialize(DWORD reserved);

-

-  // Uninitialize the state of the singleton.

-  static HRESULT Uninitialize();

-

-  // Accessors.

-  static ApartmentState* apartment_state() {

-    return apartment_state_;

-  }

-

-  CallDispatcher& call_dispatcher() const {

-    ASSERT(call_dispatcher_.get(),

-      (_T("'InitializeApartment' has not been called.")));

-    return *call_dispatcher_;

-  }

-

-  DWORD thread_id() const {

-    ASSERT(thread_id_,

-      (_T("'InitializeApartment' has not been called.")));

-    return thread_id_;

-  }

-

- private:

-  static int ref_cnt_;    // the reference count of init/uninit.

-

-  const DWORD thread_id_;   // thread that called the InitializeApartment

-  scoped_ptr<CallDispatcher> call_dispatcher_;

-

-  static ApartmentState* apartment_state_;    // the instance of the state

-  DISALLOW_EVIL_CONSTRUCTORS(ApartmentState);

-};

-

-

-// CallDispatcher uses functors to cross call from the caller's thread to

-// this apartment thread (main thread).

-class CallDispatcher

-    : public CWindowImpl<CallDispatcher,

-                         CWindow,

-                         CWinTraits<WS_OVERLAPPED, WS_EX_TOOLWINDOW> > {

- public:

-  explicit CallDispatcher(DWORD options);

-  ~CallDispatcher();

-

-  // Two-phase initialization

-  HRESULT Init();

-

-  // The initiator of the cross call.

-  HRESULT DoCrossApartmentCall(BaseFunctor* caller, void* presult);

-

- private:

-  static const UINT WM_METHOD_CALL = WM_USER + 0x100;

-  static const UINT WM_METHOD_CALL_COMPLETE = WM_USER + 0x101;

-

-  BEGIN_MSG_MAP(CallDispatcher)

-    MESSAGE_HANDLER(WM_METHOD_CALL, OnMethodCall)

-  END_MSG_MAP()

-

- private:

-  LRESULT OnMethodCall(UINT uMsg, WPARAM wParam,

-    LPARAM lParam, BOOL& bHandled);

-

-  DWORD options_;

-

-  // Currently only one option is supported for testing purposes.

-  // It testing mode, this option disables the cross-call mechanism and

-  // directly calls the functor in the same thread as the invoker.

-  static const DWORD kTestingMode = DWORD(-1);

-};

-

-// initialize the static data memebers

-ApartmentState* ApartmentState::apartment_state_ = 0;

-int ApartmentState::ref_cnt_ = 0;

-

-HRESULT ApartmentState::Initialize(DWORD reserved) {

-  CORE_LOG(L3, (_T("[ApartmentState::Initialize]")));

-  ASSERT(ref_cnt_ >= 0, (_T("Apartment Reference Counting")));

-  if (ref_cnt_ < 0) return E_UNEXPECTED;

-

-  DWORD thread_id = ::GetCurrentThreadId();

-  ASSERT1(thread_id);

-

-  if (ref_cnt_ > 0) {

-    ASSERT(apartment_state(), (_T("Apartment State is 0.")));

-    bool same_thread = thread_id == apartment_state()->thread_id();

-    // if initialized multiple times verify the thread identity just in case

-    ASSERT(same_thread, (_T("Wrong Thread.")));

-    if (!same_thread) return E_UNEXPECTED;

-    ++ref_cnt_;

-    return S_OK;

-  }

-

-  ASSERT1(ref_cnt_ == 0);

-

-  // do the initialization of the apartment

-  scoped_ptr<CallDispatcher> call_disp(new CallDispatcher(reserved));

-  RET_IF_FAILED(call_disp->Init());

-  scoped_ptr<ApartmentState> ap_state(

-    new ApartmentState(thread_id, call_disp.get()));

-

-  call_disp.release();

-  ApartmentState::apartment_state_ = ap_state.release();

-

-  ++ref_cnt_;

-  return S_OK;

-}

-

-HRESULT ApartmentState::Uninitialize() {

-  ASSERT(ref_cnt_ > 0, (_T("Apartment Reference Counting")));

-  if (ref_cnt_ <= 0) return E_UNEXPECTED;

-

-  DWORD thread_id = ::GetCurrentThreadId();

-  ASSERT1(thread_id);

-

-  ASSERT(apartment_state(), (_T("Apartment State is 0.")));

-  bool same_thread = thread_id == apartment_state()->thread_id();

-  // verify the thread identity just in case

-  ASSERT(same_thread, (_T("Wrong Thread.")));

-  if (!same_thread) return E_UNEXPECTED;

-

-  if (--ref_cnt_ == 0) {

-    delete ApartmentState::apartment_state();

-    ApartmentState::apartment_state_ = 0;

-  }

-

-  return S_OK;

-}

-

-CallDispatcher::CallDispatcher(DWORD options) : options_(options) {

-  // TODO(omaha): Log

-}

-

-CallDispatcher::~CallDispatcher() {

-  // TODO(omaha): Log

-  if (m_hWnd) {

-    DestroyWindow();

-  }

-}

-

-HRESULT CallDispatcher::Init() {

-  // Create a message-only window for the dispatcher. It is not visible,

-  // has no z-order, cannot be enumerated, and does not receive broadcast

-  // messages. The window simply dispatches messages.

-  const TCHAR kWndName[] = _T("{FFE21900-612E-44a9-8424-3FC71B382E61}");

-  HWND hwnd = Create(HWND_MESSAGE, NULL, kWndName);

-  return hwnd ? S_OK : HRESULT_FROM_WIN32(::GetLastError());

-}

-

-//

-LRESULT CallDispatcher::OnMethodCall(UINT, WPARAM wParam,

-                                     LPARAM result, BOOL&) {

-  CORE_LOG(L6, (_T("[CallDispatcher::OnMethodCall]")));

-

-  ASSERT1(wParam);

-  BaseFunctor& call = *reinterpret_cast<BaseFunctor*>(wParam);

-

-  // presult is non-zero if the method or function has a return type.

-  // presult is zero for void methods and functions.

-

-  void* presult = reinterpret_cast<void*>(result);

-

-  ASSERT(

-    ApartmentState::apartment_state()->thread_id() == ::GetCurrentThreadId(),

-    (_T("Wrong Thread")));

-

-  // the function object virtual call;

-  call(presult);

-

-  bool is_async = call.is_async();

-  // For async calls, do not post a message, because the caller will not be

-  // waiting for the call to complete.

-  if (!is_async &&

-      !::PostThreadMessage(call.thread_id(), WM_METHOD_CALL_COMPLETE, 0, 0)) {

-    DWORD error = ::GetLastError();

-    CORE_LOG(LEVEL_ERROR,

-        (_T("[CallDispatcher::OnMethodCall - PostThreadMessage][%d]"), error));

-    ASSERT(false, (_T("Failed to PostThreadMessage.")));

-

-    // TODO(omaha): raise here.

-  }

-

-  // DO NOT ACCESS THE CALL OBJECT FROM DOWN ON. IN THE CASE OF A SYNCHRONOUS

-  // CALL THE CALL OBJECT MAY HAVE ALREADY DESTROYED.

-

-  if (is_async) {

-    // Auto cleanup of the call object in the case of a async call.

-    delete &call;

-  }

-

-  CORE_LOG(L6, (_T("CallDispatcher::OnMethodCall returns.")));

-  return true;

-}

-

-//

-HRESULT CallDispatcher::DoCrossApartmentCall(BaseFunctor* call,

-                                             void* presult) {

-  CORE_LOG(L6, (_T("[CallDispatcher::DoCrossApartmentCall]")));

-

-  ASSERT(IsWindow(), (_T("The dispatcher must have a window.")));

-  bool is_async = call->is_async();

-  if (options_ == kTestingMode) {

-    (*call)(presult);

-    if (is_async) {

-      // We need to delete the functor as if we were the callee.

-      delete call;

-    }

-    return S_OK;

-  }

-

-  if (!is_async) {

-    // Usually it is a mistake to call a synchronous method from the main STA

-    // to the main STA.

-

-    DWORD thread_id = ApartmentState::apartment_state()->thread_id();

-    ASSERT(thread_id != ::GetCurrentThreadId(), (_T("Wrong Thread")));

-

-    ASSERT(GetWindowThreadID() != ::GetCurrentThreadId(),

-           (_T("DoCrossApartmentCall calling its own thread.")));

-  }

-

-  if (!PostMessage(WM_METHOD_CALL,

-                   reinterpret_cast<WPARAM>(call),

-                   reinterpret_cast<LPARAM>(presult))) {

-    DWORD err = ::GetLastError();

-    CORE_LOG(LEVEL_ERROR,

-        (_T("[CallDispatcher::DoCrossApartmentCall - PostMessage][%d]"), err));

-    ASSERT(false, (_T("Failed to PostMessage.")));

-

-    return HRESULT_FROM_WIN32(err);

-  }

-

-  // Once the call has been made, do not access the state of the functor as

-  // the other end might have already executed the call and delete the functor.

-  // This is true for asyncronous calls but it would not hurt for synchronous

-  // calls as well.

-  call = NULL;

-

-  if (is_async) {

-    // Do not wait for the call to complete. The call will complete at

-    // some time in the future and the call object is going to be cleaned up.

-    return S_OK;

-  }

-

-  // Pump all messages, waiting for WM_METHOD_CALL_COMPLETE or WM_QUIT.

-  MSG msg;

-  SetZero(msg);

-  int ret = 0;

-  while ((ret = ::GetMessage(&msg, 0, 0, 0)) != 0) {

-    if (ret == -1) {

-      DWORD error = ::GetLastError();

-      CORE_LOG(LEVEL_ERROR,

-               (_T("[CallDispatcher::DoCrossApartmentCall - GetMessage][%d]"),

-               error));

-      // TODO(omaha): raise here.

-    }

-

-    if (msg.message == WM_METHOD_CALL_COMPLETE) {

-      break;

-    }

-

-    ::DispatchMessage(&msg);

-  }

-

-  // Repost the WM_QUIT message to properly exit all message loops.

-  if (msg.message == WM_QUIT) {

-    ASSERT1(ret == 0);

-    ::PostQuitMessage(msg.wParam);

-  }

-

-  CORE_LOG(L6, (_T("CallDispatcher::DoCrossApartmentCall returns")));

-  return S_OK;

-}

-

-}  // namespace

-

-void BaseFunctor::DoInvoke(void* presult) {

-  ASSERT(ApartmentState::apartment_state(),

-    (_T("Did you forgot to call 'InitializeApartment'?")));

-

-  CallDispatcher& call_dispatcher =

-    ApartmentState::apartment_state()->call_dispatcher();

-

-  HRESULT hr = call_dispatcher.DoCrossApartmentCall(this, presult);

-

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("Failed to call across apartments.")));

-    // TODO(omaha): log, report, raise.

-  }

-}

-

-HRESULT InitializeApartment(DWORD reserved) {

-  return ApartmentState::Initialize(reserved);

-}

-

-HRESULT UninitializeApartment() {

-  return ApartmentState::Uninitialize();

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/sta.h"
+
+#include <atlbase.h>
+#include <atlwin.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/sta_call.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+namespace {
+
+class CallDispatcher;
+
+// ApartmentState maintains the state of the apartment. It keeps a reference
+// to a call dispatcher. The dispatcher is basically a window object that
+// handles user messages corresponding to each call.
+//
+// ApartmentState is a singleton. It's lifetime is controlled by the
+// 'InitializeApartment' and 'UnintializeApartment'.
+//
+// The current implementation is limited to the main STA. Creating multiple
+// apartments in a process is not possible.
+//
+// TODO(omaha): implement a simple reference counting of the threads to make
+// sure the all the calling threads have returned when the apt is destroyed.
+
+class ApartmentState {
+ public:
+  ApartmentState(DWORD thread_id, CallDispatcher* call_disp)
+      : thread_id_(thread_id), call_dispatcher_(call_disp) {}
+
+  ~ApartmentState() {
+    ASSERT1(ref_cnt_ == 0);
+  }
+
+  // Initialize the state of the singleton.
+  static HRESULT Initialize(DWORD reserved);
+
+  // Uninitialize the state of the singleton.
+  static HRESULT Uninitialize();
+
+  // Accessors.
+  static ApartmentState* apartment_state() {
+    return apartment_state_;
+  }
+
+  CallDispatcher& call_dispatcher() const {
+    ASSERT(call_dispatcher_.get(),
+      (_T("'InitializeApartment' has not been called.")));
+    return *call_dispatcher_;
+  }
+
+  DWORD thread_id() const {
+    ASSERT(thread_id_,
+      (_T("'InitializeApartment' has not been called.")));
+    return thread_id_;
+  }
+
+ private:
+  static int ref_cnt_;    // the reference count of init/uninit.
+
+  const DWORD thread_id_;   // thread that called the InitializeApartment
+  scoped_ptr<CallDispatcher> call_dispatcher_;
+
+  static ApartmentState* apartment_state_;    // the instance of the state
+  DISALLOW_EVIL_CONSTRUCTORS(ApartmentState);
+};
+
+
+// CallDispatcher uses functors to cross call from the caller's thread to
+// this apartment thread (main thread).
+class CallDispatcher
+    : public CWindowImpl<CallDispatcher,
+                         CWindow,
+                         CWinTraits<WS_OVERLAPPED, WS_EX_TOOLWINDOW> > {
+ public:
+  explicit CallDispatcher(DWORD options);
+  ~CallDispatcher();
+
+  // Two-phase initialization
+  HRESULT Init();
+
+  // The initiator of the cross call.
+  HRESULT DoCrossApartmentCall(BaseFunctor* caller, void* presult);
+
+ private:
+  static const UINT WM_METHOD_CALL = WM_USER + 0x100;
+  static const UINT WM_METHOD_CALL_COMPLETE = WM_USER + 0x101;
+
+  BEGIN_MSG_MAP(CallDispatcher)
+    MESSAGE_HANDLER(WM_METHOD_CALL, OnMethodCall)
+  END_MSG_MAP()
+
+ private:
+  LRESULT OnMethodCall(UINT uMsg, WPARAM wParam,
+    LPARAM lParam, BOOL& bHandled);
+
+  DWORD options_;
+
+  // Currently only one option is supported for testing purposes.
+  // It testing mode, this option disables the cross-call mechanism and
+  // directly calls the functor in the same thread as the invoker.
+  static const DWORD kTestingMode = DWORD(-1);
+};
+
+// initialize the static data memebers
+ApartmentState* ApartmentState::apartment_state_ = 0;
+int ApartmentState::ref_cnt_ = 0;
+
+HRESULT ApartmentState::Initialize(DWORD reserved) {
+  CORE_LOG(L3, (_T("[ApartmentState::Initialize]")));
+  ASSERT(ref_cnt_ >= 0, (_T("Apartment Reference Counting")));
+  if (ref_cnt_ < 0) return E_UNEXPECTED;
+
+  DWORD thread_id = ::GetCurrentThreadId();
+  ASSERT1(thread_id);
+
+  if (ref_cnt_ > 0) {
+    ASSERT(apartment_state(), (_T("Apartment State is 0.")));
+    bool same_thread = thread_id == apartment_state()->thread_id();
+    // if initialized multiple times verify the thread identity just in case
+    ASSERT(same_thread, (_T("Wrong Thread.")));
+    if (!same_thread) return E_UNEXPECTED;
+    ++ref_cnt_;
+    return S_OK;
+  }
+
+  ASSERT1(ref_cnt_ == 0);
+
+  // do the initialization of the apartment
+  scoped_ptr<CallDispatcher> call_disp(new CallDispatcher(reserved));
+  RET_IF_FAILED(call_disp->Init());
+  scoped_ptr<ApartmentState> ap_state(
+    new ApartmentState(thread_id, call_disp.get()));
+
+  call_disp.release();
+  ApartmentState::apartment_state_ = ap_state.release();
+
+  ++ref_cnt_;
+  return S_OK;
+}
+
+HRESULT ApartmentState::Uninitialize() {
+  ASSERT(ref_cnt_ > 0, (_T("Apartment Reference Counting")));
+  if (ref_cnt_ <= 0) return E_UNEXPECTED;
+
+  DWORD thread_id = ::GetCurrentThreadId();
+  ASSERT1(thread_id);
+
+  ASSERT(apartment_state(), (_T("Apartment State is 0.")));
+  bool same_thread = thread_id == apartment_state()->thread_id();
+  // verify the thread identity just in case
+  ASSERT(same_thread, (_T("Wrong Thread.")));
+  if (!same_thread) return E_UNEXPECTED;
+
+  if (--ref_cnt_ == 0) {
+    delete ApartmentState::apartment_state();
+    ApartmentState::apartment_state_ = 0;
+  }
+
+  return S_OK;
+}
+
+CallDispatcher::CallDispatcher(DWORD options) : options_(options) {
+  // TODO(omaha): Log
+}
+
+CallDispatcher::~CallDispatcher() {
+  // TODO(omaha): Log
+  if (m_hWnd) {
+    DestroyWindow();
+  }
+}
+
+HRESULT CallDispatcher::Init() {
+  // Create a message-only window for the dispatcher. It is not visible,
+  // has no z-order, cannot be enumerated, and does not receive broadcast
+  // messages. The window simply dispatches messages.
+  const TCHAR kWndName[] = _T("{FFE21900-612E-44a9-8424-3FC71B382E61}");
+  HWND hwnd = Create(HWND_MESSAGE, NULL, kWndName);
+  return hwnd ? S_OK : HRESULT_FROM_WIN32(::GetLastError());
+}
+
+//
+LRESULT CallDispatcher::OnMethodCall(UINT, WPARAM wParam,
+                                     LPARAM result, BOOL&) {
+  CORE_LOG(L6, (_T("[CallDispatcher::OnMethodCall]")));
+
+  ASSERT1(wParam);
+  BaseFunctor& call = *reinterpret_cast<BaseFunctor*>(wParam);
+
+  // presult is non-zero if the method or function has a return type.
+  // presult is zero for void methods and functions.
+
+  void* presult = reinterpret_cast<void*>(result);
+
+  ASSERT(
+    ApartmentState::apartment_state()->thread_id() == ::GetCurrentThreadId(),
+    (_T("Wrong Thread")));
+
+  // the function object virtual call;
+  call(presult);
+
+  bool is_async = call.is_async();
+  // For async calls, do not post a message, because the caller will not be
+  // waiting for the call to complete.
+  if (!is_async &&
+      !::PostThreadMessage(call.thread_id(), WM_METHOD_CALL_COMPLETE, 0, 0)) {
+    DWORD error = ::GetLastError();
+    CORE_LOG(LEVEL_ERROR,
+        (_T("[CallDispatcher::OnMethodCall - PostThreadMessage][%d]"), error));
+    ASSERT(false, (_T("Failed to PostThreadMessage.")));
+
+    // TODO(omaha): raise here.
+  }
+
+  // DO NOT ACCESS THE CALL OBJECT FROM DOWN ON. IN THE CASE OF A SYNCHRONOUS
+  // CALL THE CALL OBJECT MAY HAVE ALREADY DESTROYED.
+
+  if (is_async) {
+    // Auto cleanup of the call object in the case of a async call.
+    delete &call;
+  }
+
+  CORE_LOG(L6, (_T("CallDispatcher::OnMethodCall returns.")));
+  return true;
+}
+
+//
+HRESULT CallDispatcher::DoCrossApartmentCall(BaseFunctor* call,
+                                             void* presult) {
+  CORE_LOG(L6, (_T("[CallDispatcher::DoCrossApartmentCall]")));
+
+  ASSERT(IsWindow(), (_T("The dispatcher must have a window.")));
+  bool is_async = call->is_async();
+  if (options_ == kTestingMode) {
+    (*call)(presult);
+    if (is_async) {
+      // We need to delete the functor as if we were the callee.
+      delete call;
+    }
+    return S_OK;
+  }
+
+  if (!is_async) {
+    // Usually it is a mistake to call a synchronous method from the main STA
+    // to the main STA.
+
+    DWORD thread_id = ApartmentState::apartment_state()->thread_id();
+    ASSERT(thread_id != ::GetCurrentThreadId(), (_T("Wrong Thread")));
+
+    ASSERT(GetWindowThreadID() != ::GetCurrentThreadId(),
+           (_T("DoCrossApartmentCall calling its own thread.")));
+  }
+
+  if (!PostMessage(WM_METHOD_CALL,
+                   reinterpret_cast<WPARAM>(call),
+                   reinterpret_cast<LPARAM>(presult))) {
+    DWORD err = ::GetLastError();
+    CORE_LOG(LEVEL_ERROR,
+        (_T("[CallDispatcher::DoCrossApartmentCall - PostMessage][%d]"), err));
+    ASSERT(false, (_T("Failed to PostMessage.")));
+
+    return HRESULT_FROM_WIN32(err);
+  }
+
+  // Once the call has been made, do not access the state of the functor as
+  // the other end might have already executed the call and delete the functor.
+  // This is true for asyncronous calls but it would not hurt for synchronous
+  // calls as well.
+  call = NULL;
+
+  if (is_async) {
+    // Do not wait for the call to complete. The call will complete at
+    // some time in the future and the call object is going to be cleaned up.
+    return S_OK;
+  }
+
+  // Pump all messages, waiting for WM_METHOD_CALL_COMPLETE or WM_QUIT.
+  MSG msg;
+  SetZero(msg);
+  int ret = 0;
+  while ((ret = ::GetMessage(&msg, 0, 0, 0)) != 0) {
+    if (ret == -1) {
+      DWORD error = ::GetLastError();
+      CORE_LOG(LEVEL_ERROR,
+               (_T("[CallDispatcher::DoCrossApartmentCall - GetMessage][%d]"),
+               error));
+      // TODO(omaha): raise here.
+    }
+
+    if (msg.message == WM_METHOD_CALL_COMPLETE) {
+      break;
+    }
+
+    ::DispatchMessage(&msg);
+  }
+
+  // Repost the WM_QUIT message to properly exit all message loops.
+  if (msg.message == WM_QUIT) {
+    ASSERT1(ret == 0);
+    ::PostQuitMessage(msg.wParam);
+  }
+
+  CORE_LOG(L6, (_T("CallDispatcher::DoCrossApartmentCall returns")));
+  return S_OK;
+}
+
+}  // namespace
+
+void BaseFunctor::DoInvoke(void* presult) {
+  ASSERT(ApartmentState::apartment_state(),
+    (_T("Did you forgot to call 'InitializeApartment'?")));
+
+  CallDispatcher& call_dispatcher =
+    ApartmentState::apartment_state()->call_dispatcher();
+
+  HRESULT hr = call_dispatcher.DoCrossApartmentCall(this, presult);
+
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("Failed to call across apartments.")));
+    // TODO(omaha): log, report, raise.
+  }
+}
+
+HRESULT InitializeApartment(DWORD reserved) {
+  return ApartmentState::Initialize(reserved);
+}
+
+HRESULT UninitializeApartment() {
+  return ApartmentState::Uninitialize();
+}
+
+}  // namespace omaha
+
diff --git a/common/sta.h b/common/sta.h
index a18d4e6..76204d0 100644
--- a/common/sta.h
+++ b/common/sta.h
@@ -1,78 +1,78 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// STA initializes a custom non-COM Single Threaded Apartment to facilitate

-// calling of functions and object methods in the thread of the STA. This is

-// useful when creating a simple threading model based on a main thread and

-// several worker threads, especially for client components that have a UI or

-// use the COM STA models.

-//

-// The current implementation only supports initializing the main STA, which is

-// the STA created by the main thread of the process. This is usually the UI

-// thread. Having multiple STA in a process is not possible yet.

-//

-// This custom STA does not interfere with the COM STAs.

-//

-// In order for the STA to work properly, the STA thread must keep processing

-// messages and not block, just like in the COM STA case.

-

-#ifndef OMAHA_COMMON_STA_H__

-#define OMAHA_COMMON_STA_H__

-

-#include <windows.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/scoped_any.h"

-

-namespace omaha {

-

-// Initializes the STA apartment. The 'reserved' parameter must be 0.

-// InitializeApartment and UninitializeApartment are reference-counted.

-HRESULT InitializeApartment(DWORD reserved);

-

-// Uninitializes the STA apartment.

-HRESULT UninitializeApartment();

-

-// A scoped_sta smart pointer is provided to manage the calls to

-// InitializeApartment and UninitializeApartment.

-inline HRESULT smart_sta_init_helper(DWORD reserved) {

-  return InitializeApartment(reserved);

-}

-

-inline void smart_uninit_helper(HRESULT result) {

-  if (result == S_OK) {

-    VERIFY1(SUCCEEDED(UninitializeApartment()));

-  }

-}

-

-typedef close_fun<void (*)(HRESULT), smart_uninit_helper> close_sta;

-

-typedef value_const<HRESULT, E_UNEXPECTED> sta_not_init;

-

-typedef scoped_any<HRESULT, close_sta, sta_not_init> scoped_sta_close;

-

-struct scoped_sta {

-  explicit scoped_sta(DWORD reserved)

-      : result_(smart_sta_init_helper(reserved)) {}

-

-  HRESULT result() const { return get(result_); }

-

- private:

-  const scoped_sta_close result_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_STA_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// STA initializes a custom non-COM Single Threaded Apartment to facilitate
+// calling of functions and object methods in the thread of the STA. This is
+// useful when creating a simple threading model based on a main thread and
+// several worker threads, especially for client components that have a UI or
+// use the COM STA models.
+//
+// The current implementation only supports initializing the main STA, which is
+// the STA created by the main thread of the process. This is usually the UI
+// thread. Having multiple STA in a process is not possible yet.
+//
+// This custom STA does not interfere with the COM STAs.
+//
+// In order for the STA to work properly, the STA thread must keep processing
+// messages and not block, just like in the COM STA case.
+
+#ifndef OMAHA_COMMON_STA_H__
+#define OMAHA_COMMON_STA_H__
+
+#include <windows.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/scoped_any.h"
+
+namespace omaha {
+
+// Initializes the STA apartment. The 'reserved' parameter must be 0.
+// InitializeApartment and UninitializeApartment are reference-counted.
+HRESULT InitializeApartment(DWORD reserved);
+
+// Uninitializes the STA apartment.
+HRESULT UninitializeApartment();
+
+// A scoped_sta smart pointer is provided to manage the calls to
+// InitializeApartment and UninitializeApartment.
+inline HRESULT smart_sta_init_helper(DWORD reserved) {
+  return InitializeApartment(reserved);
+}
+
+inline void smart_uninit_helper(HRESULT result) {
+  if (result == S_OK) {
+    VERIFY1(SUCCEEDED(UninitializeApartment()));
+  }
+}
+
+typedef close_fun<void (*)(HRESULT), smart_uninit_helper> close_sta;
+
+typedef value_const<HRESULT, E_UNEXPECTED> sta_not_init;
+
+typedef scoped_any<HRESULT, close_sta, sta_not_init> scoped_sta_close;
+
+struct scoped_sta {
+  explicit scoped_sta(DWORD reserved)
+      : result_(smart_sta_init_helper(reserved)) {}
+
+  HRESULT result() const { return get(result_); }
+
+ private:
+  const scoped_sta_close result_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_STA_H__
+
diff --git a/common/sta_call.h b/common/sta_call.h
index 9a02a42..682b66f 100644
--- a/common/sta_call.h
+++ b/common/sta_call.h
@@ -1,1117 +1,1117 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// sta_call.h generics for cross apartment calling.

-//

-// The code is using compile-time and run-time polymorphism to create

-// type-safe call wrappers that can be used to cross call from a

-// worker thread to an STA thread. The current implementation only

-// supports calling the main STA.

-//

-// Functions as well as object methods can be called.

-//

-// Examples:

-// class X {

-//   public:

-//     int Add(int i, int j) { return i + j; }

-// };

-//

-//

-// namespace {

-//   int Add(long i, long j) { return i + j; }

-// }

-//

-// X x;

-// int sum = CallMethod(&x, X::Add, 10, 20);

-// int j = CallFunction(Add, -10, 10);

-//

-// The central piece of machinery is a hierarchy of functors. A functor is

-// instantiated by a function template (CallFunction or CallMethod) and its

-// 'Invoke' method gets called.

-// Calling 'Invoke' will send the functor using 'SendMessage'

-// to a window. The window message handler picks up the functor and

-// calls the functor virtual operator().

-// This virtual call is what actually calls the specified function or the

-// method, the only difference being that the call is now made in a thread

-// different than the thread that called 'Invoke'. There is a partial

-// specialization of the templates for void, so that void type is supported

-// as a return type.

-//

-//

-// !!! Limitations !!!

-//

-// There are a few important design and implementation limitations. They are

-// mostly related to template parameters ambiguities (T or T&) especially

-// for overloaded names or const types. The limitations are significant although

-// the code is useful enough as it is in most of the cases.

-// However, when using the code it is frustrating to discover that it does not

-// compile for obvious and useful cases, a constant reminder that a better

-// solution is to be seeked.

-//

-//

-// The implementation does not support calling all 'stdcall' calling convention.

-//

-// The design does not support calling functions or methods that use pass by

-// reference arguments: f(std::string&) .

-//

-// The design does not support well calling functions or methods that take

-// pointer to const types parameters : f(const std::string*) .

-//

-// The implementation does not support calling methods of const objects.

-//

-// To reduce the number of templates that get instantiated, the types of the

-// arguments of the call must match exactly the types of parameters of the

-// function or method . In some cases static_casts mey be required

-// at the point of the call. Example: CallMethod(f, static_cast<long>(10));

-

-#ifndef OMAHA_COMMON_STA_CALL_H__

-#define OMAHA_COMMON_STA_CALL_H__

-

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-

-namespace omaha {

-

-// C4347: 'function template' is called instead of 'function'

-#pragma warning(disable : 4347)

-

-// The Base Functor is the base of the functor hierarchy.

-class BaseFunctor {

- public:

-  explicit BaseFunctor(bool is_async) :

-      thread_id_(::GetCurrentThreadId()),

-      is_async_(is_async) {

-    CORE_LOG(L6, (_T("[BaseFunctor::BaseFunctor]")));

-  }

-

-  // Functors are polymorphic objects.

-  virtual ~BaseFunctor() {

-    CORE_LOG(L6, (_T("[BaseFunctor::~BaseFunctor]")));

-  }

-

-  // Abstract virtual function call operator. This is always called

-  // in the callee thread by the dispatcher of the apartment.

-  virtual void operator()(void* presult) = 0;

-

-  // The thread id of the calling thread.

-  DWORD thread_id() const { return thread_id_; }

-

-  bool is_async() const { return is_async_; }

-

- protected:

-

-  // Invoke is called by each of the derived functors. This is how

-  // the  cross thread invocation is made and the result of the invocation

-  // is retrieved. Invoke is always called in the caller thread.

-  template <typename R>

-  R Invoke() {

-    R r = R();      // ensure r is initialized even for primitive types.

-    if (!is_async_) {

-      DoInvoke(&r);

-    } else {

-      // We handle the async calls as if the call returns void.

-      DoInvoke(0);

-    }

-    return r;

-  }

-

-  // non-template method to be called by the derived functors

-  // specialized for void.

-  void Invoke() {

-    // When the argument of the invocation is 0, we are not

-    // interested in the result.

-    DoInvoke(0);

-  }

-

- private:

-  void DoInvoke(void* presult);   // Does the actual invocation.

-  DWORD thread_id_;               // The thread id of the calling thread.

-  bool is_async_;                 // True for async calls.

-

-  DISALLOW_EVIL_CONSTRUCTORS(BaseFunctor);

-};

-

-//

-// 0-ary method functor.

-//

-template <class T, typename R>

-class MethodFunctor0 : public BaseFunctor {

- public:

-  MethodFunctor0(bool is_async, T* pt, R (T::*pm)()) :

-      BaseFunctor(is_async), pobj_(pt), pm_(pm) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    if (presult) {

-      *static_cast<R*>(presult) = (pobj_->*pm_)();

-    } else {

-      (pobj_->*pm_)();

-    }

-  }

-

-  R Invoke() {

-    // Don't forget to call the base implementation.

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  T* pobj_;

-  R (T::*pm_)();

-};

-

-//

-// 0-ary partial specialization for void return types.

-//

-template <class T>

-class MethodFunctor0<T, void> : public BaseFunctor {

- public:

-  MethodFunctor0(bool is_async, T* pt, void (T::*pm)()) :

-      BaseFunctor(is_async), pobj_(pt), pm_(pm) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    // the actual call. There is no return value when the return type is void.

-    (pobj_->*pm_)();

-  }

-

-  // Bring in the name from the Base

-  using BaseFunctor::Invoke;

-

- private:

-  T* pobj_;

-  void (T::*pm_)();

-};

-

-//

-// 0-ary functor and specialization for void.

-//

-template <typename R>

-class Functor0 : public BaseFunctor {

- public:

-  Functor0(bool is_async, R (*pf)()) :

-      BaseFunctor(is_async), pf_(pf) {}

-

-  virtual void operator()(void* presult) {

-    if (presult) {

-      *static_cast<R*>(presult) = (*pf_)();

-    } else {

-      (*pf_)();

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  R (*pf_)();

-};

-

-template <>

-class Functor0<void> : public BaseFunctor {

- public:

-  Functor0(bool is_async, void (*pf)()) :

-      BaseFunctor(is_async), pf_(pf) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT1(!presult);

-    presult;  // unreferenced formal parameter

-

-    (*pf_)();

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  void (*pf_)();

-};

-

-

-//

-// 1-ary

-//

-template <class T, typename R, typename P>

-class MethodFunctor1 : public BaseFunctor {

- public:

-  MethodFunctor1(bool is_async, T* pt, R (T::*pm)(P), P p) :

-      BaseFunctor(is_async), pobj_(pt), pm_(pm), p_(p) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    if (presult) {

-      *static_cast<R*>(presult) = (pobj_->*pm_)(p_);

-    } else {

-      (pobj_->*pm_)(p_);

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  T* pobj_;

-  R (T::*pm_)(P);

-  P p_;

-};

-

-template <class T, typename P>

-class MethodFunctor1<T, void, P> : public BaseFunctor {

- public:

-  MethodFunctor1(bool is_async, T* pt, void (T::*pm)(P), P p) :

-      BaseFunctor(is_async), pobj_(pt), pm_(pm), p_(p) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    (pobj_->*pm_)(p_);

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  T* pobj_;

-  void (T::*pm_)(P);

-  P p_;

-};

-

-template <typename R, typename P1>

-class Functor1 : public BaseFunctor {

- public:

-  Functor1(bool is_async, R (*pf)(P1), P1 p1) :

-      BaseFunctor(is_async), pf_(pf), p1_(p1) {}

-

-  virtual void operator()(void* presult) {

-    if (presult) {

-      *static_cast<R*>(presult) = (*pf_)(p1_);

-    } else {

-      (*pf_)(p1_);

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  R (*pf_)(P1);

-  P1 p1_;

-};

-

-template <typename P1>

-class Functor1<void, P1> : public BaseFunctor {

- public:

-  Functor1(bool is_async, void (*pf)(P1), P1 p1) :

-      BaseFunctor(is_async), pf_(pf), p1_(p1) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    (*pf_)(p1_);

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  void (*pf_)(P1);

-  P1 p1_;

-};

-

-

-//

-// 2-ary

-//

-template <class T, typename R, typename P1, typename P2>

-class MethodFunctor2 : public BaseFunctor {

- public:

-  MethodFunctor2(bool is_async, T* pt, R (T::*pm)(P1, P2), P1 p1, P2 p2) :

-      BaseFunctor(is_async), pobj_(pt), pm_(pm), p1_(p1), p2_(p2) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    if (presult) {

-      *static_cast<R*>(presult) = (pobj_->*pm_)(p1_, p2_);

-    } else {

-      (pobj_->*pm_)(p1_, p2_);

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  T* pobj_;

-  R (T::*pm_)(P1, P2);

-  P1 p1_;

-  P2 p2_;

-};

-

-template <class T, typename P1, typename P2>

-class MethodFunctor2<T, void, P1, P2> : public BaseFunctor {

- public:

-  MethodFunctor2(bool is_async, T* pt, void (T::*pm)(P1, P2), P1 p1, P2 p2) :

-      BaseFunctor(is_async), pobj_(pt), pm_(pm), p1_(p1), p2_(p2) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    (pobj_->*pm_)(p1_, p2_);

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  T* pobj_;

-  void (T::*pm_)(P1, P2);

-  P1 p1_;

-  P2 p2_;

-};

-

-template <typename R, typename P1, typename P2>

-class Functor2 : public BaseFunctor {

- public:

-  Functor2(bool is_async, R (*pf)(P1, P2), P1 p1, P2 p2) :

-      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2) {}

-

-  virtual void operator()(void* presult) {

-    if (presult) {

-      *static_cast<R*>(presult) = pf_(p1_, p2_);

-    } else {

-      pf_(p1_, p2_);

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  R (*pf_)(P1, P2);

-  P1 p1_;

-  P2 p2_;

-};

-

-template <typename P1, typename P2>

-class Functor2<void, P1, P2> : public BaseFunctor {

- public:

-  Functor2(bool is_async, void (*pf)(P1, P2), P1 p1, P2 p2) :

-      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    (*pf_)(p1_, p2_);

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  void (*pf_)(P1, P2);

-  P1 p1_;

-  P2 p2_;

-};

-

-//

-// 3-ary

-//

-template <class T, typename R, typename P1, typename P2, typename P3>

-class MethodFunctor3 : public BaseFunctor {

- public:

-  MethodFunctor3(bool is_async,

-                 T* pt,

-                 R (T::*pm)(P1, P2, P3),

-                 P1 p1,

-                 P2 p2,

-                 P3 p3) :

-      BaseFunctor(is_async), pobj_(pt), pm_(pm), p1_(p1), p2_(p2), p3_(p3) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    if (presult) {

-      *static_cast<R*>(presult) = (pobj_->*pm_)(p1_, p2_, p3_);

-    } else {

-      (pobj_->*pm_)(p1_, p2_, p3_);

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  T* pobj_;

-  R (T::*pm_)(P1, P2, P3);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-};

-

-template <class T, typename P1, typename P2, typename P3>

-class MethodFunctor3<T, void, P1, P2, P3> : public BaseFunctor {

- public:

-  MethodFunctor3(bool is_async,

-                 T* pt,

-                 void (T::*pm)(P1, P2, P3),

-                 P1 p1,

-                 P2 p2,

-                 P3 p3) :

-      BaseFunctor(is_async), pobj_(pt), pm_(pm), p1_(p1), p2_(p2), p3_(p3) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    (pobj_->*pm_)(p1_, p2_, p3_);

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  T* pobj_;

-  void (T::*pm_)(P1, P2, P3);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-};

-

-

-template <typename R, typename P1, typename P2, typename P3>

-class Functor3 : public BaseFunctor {

- public:

-  Functor3(bool is_async, R (*pf)(P1, P2, P3), P1 p1, P2 p2, P3 p3) :

-      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2), p3_(p3) {}

-  virtual void operator()(void* presult) {

-    if (presult) {

-      *static_cast<R*>(presult) = (*pf_)(p1_, p2_, p3_);

-    } else {

-      (*pf_)(p1_, p2_, p3_);

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  R (*pf_)(P1, P2, P3);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-};

-

-template <typename P1, typename P2, typename P3>

-class Functor3<void, P1, P2, P3> : public BaseFunctor {

- public:

-  Functor3(bool is_async, void (*pf)(P1, P2, P3), P1 p1, P2 p2, P3 p3) :

-      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2), p3_(p3) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    (*pf_)(p1_, p2_, p3_);

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  void (*pf_)(P1, P2, P3);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-};

-

-//

-// 4-ary

-//

-template <class T,

-          typename R,

-          typename P1,

-          typename P2,

-          typename P3,

-          typename P4>

-class MethodFunctor4 : public BaseFunctor {

- public:

-  MethodFunctor4(bool is_async,

-                 T* pt,

-                 R (T::*pm)(P1, P2, P3, P4),

-                 P1 p1,

-                 P2 p2,

-                 P3 p3,

-                 P4 p4) :

-      BaseFunctor(is_async),

-      pobj_(pt),

-      pm_(pm),

-      p1_(p1),

-      p2_(p2),

-      p3_(p3),

-      p4_(p4) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    if (presult) {

-      *static_cast<R*>(presult) = (pobj_->*pm_)(p1_, p2_, p3_, p4_);

-    } else {

-      (pobj_->*pm_)(p1_, p2_, p3_, p4_);

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  T* pobj_;

-  R (T::*pm_)(P1, P2, P3, P4);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-  P4 p4_;

-};

-

-template <class T, typename P1, typename P2, typename P3, typename P4>

-class MethodFunctor4<T, void, P1, P2, P3, P4> : public BaseFunctor {

- public:

-  MethodFunctor4(bool is_async,

-                 T* pt,

-                 void (T::*pm)(P1, P2, P3, P4),

-                 P1 p1,

-                 P2 p2,

-                 P3 p3,

-                 P4 p4) :

-      BaseFunctor(is_async),

-      pobj_(pt),

-      pm_(pm),

-      p1_(p1),

-      p2_(p2),

-      p3_(p3),

-      p4_(p4) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    (pobj_->*pm_)(p1_, p2_, p3_, p4_);

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  T* pobj_;

-  void (T::*pm_)(P1, P2, P3, P4);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-  P4 p4_;

-};

-

-

-template <typename R, typename P1, typename P2, typename P3, typename P4>

-class Functor4 : public BaseFunctor {

- public:

-  Functor4(bool is_async, R (*pf)(P1, P2, P3, P4), P1 p1, P2 p2, P3 p3, P4 p4) :

-      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2), p3_(p3), p4_(p4) {}

-

-  virtual void operator()(void* presult) {

-    if (presult) {

-      *static_cast<R*>(presult) = (*pf_)(p1_, p2_, p3_, p4_);

-    } else {

-      (*pf_)(p1_, p2_, p3_, p4_);

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  R (*pf_)(P1, P2, P3, P4);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-  P4 p4_;

-};

-

-template <typename P1, typename P2, typename P3, typename P4>

-class Functor4<void, P1, P2, P3, P4> : public BaseFunctor {

- public:

-  Functor4(bool is_async,

-           void (*pf)(P1, P2, P3, P4),

-           P1 p1,

-           P2 p2,

-           P3 p3,

-           P4 p4) :

-      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2), p3_(p3), p4_(p4) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    (*pf_)(p1_, p2_, p3_, p4_);

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  void (*pf_)(P1, P2, P3, P4);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-  P4 p4_;

-};

-

-//

-// 5-ary

-//

-template <class T,

-          typename R,

-          typename P1,

-          typename P2,

-          typename P3,

-          typename P4,

-          typename P5>

-class MethodFunctor5 : public BaseFunctor {

- public:

-  MethodFunctor5(bool is_async,

-                 T* pt,

-                 R (T::*pm)(P1, P2, P3, P4, P5),

-                 P1 p1,

-                 P2 p2,

-                 P3 p3,

-                 P4 p4,

-                 P5 p5) :

-      BaseFunctor(is_async),

-      pobj_(pt),

-      pm_(pm),

-      p1_(p1),

-      p2_(p2),

-      p3_(p3),

-      p4_(p4),

-      p5_(p5) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    if (presult) {

-      *static_cast<R*>(presult) = (pobj_->*pm_)(p1_, p2_, p3_, p4_, p5_);

-    } else {

-      (pobj_->*pm_)(p1_, p2_, p3_, p4_, p5_);

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  T* pobj_;

-  R (T::*pm_)(P1, P2, P3, P4, P5);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-  P4 p4_;

-  P5 p5_;

-};

-

-template <class T,

-          typename P1,

-          typename P2,

-          typename P3,

-          typename P4,

-          typename P5>

-class MethodFunctor5<T, void, P1, P2, P3, P4, P5> : public BaseFunctor {

- public:

-  MethodFunctor5(bool is_async,

-                 T* pt,

-                 void (T::*pm)(P1, P2, P3, P4, P5),

-                 P1 p1,

-                 P2 p2,

-                 P3 p3,

-                 P4 p4,

-                 P5 p5) :

-      BaseFunctor(is_async),

-      pobj_(pt),

-      pm_(pm),

-      p1_(p1),

-      p2_(p2),

-      p3_(p3),

-      p4_(p4),

-      p5_(p5) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT(pobj_, (_T("Null object.")));

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    (pobj_->*pm_)(p1_, p2_, p3_, p4_, p5_);

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  T* pobj_;

-  void (T::*pm_)(P1, P2, P3, P4, P5);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-  P4 p4_;

-  P5 p5_;

-};

-

-template <typename R,

-          typename P1,

-          typename P2,

-          typename P3,

-          typename P4,

-          typename P5>

-class Functor5 : public BaseFunctor {

- public:

-  Functor5(bool is_async,

-           R (*pf)(P1, P2, P3, P4, P5),

-           P1 p1,

-           P2 p2,

-           P3 p3,

-           P4 p4,

-           P5 p5) :

-      BaseFunctor(is_async),

-      pf_(pf),

-      p1_(p1),

-      p2_(p2),

-      p3_(p3),

-      p4_(p4),

-      p5_(p5) {}

-  virtual void operator()(void* presult) {

-    if (presult) {

-      *static_cast<R*>(presult) = (*pf_)(p1_, p2_, p3_, p4_, p5_);

-    } else {

-      (*pf_)(p1_, p2_, p3_, p4_, p5_);

-    }

-  }

-

-  R Invoke() {

-    return BaseFunctor::Invoke<R>();

-  }

-

- private:

-  R (*pf_)(P1, P2, P3, P4, P5);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-  P4 p4_;

-  P5 p5_;

-};

-

-template <typename P1, typename P2, typename P3, typename P4, typename P5>

-class Functor5<void, P1, P2, P3, P4, P5> : public BaseFunctor {

- public:

-  Functor5(bool is_async,

-           void (*pf)(P1, P2, P3, P4, P5),

-           P1 p1,

-           P2 p2,

-           P3 p3,

-           P4 p4,

-           P5 p5) :

-      BaseFunctor(is_async),

-      pf_(pf),

-      p1_(p1),

-      p2_(p2),

-      p3_(p3),

-      p4_(p4),

-      p5_(p5) {}

-

-  virtual void operator()(void* presult) {

-    ASSERT1(!presult);

-    presult;  //  unreferenced formal parameter

-

-    (*pf_)(p1_, p2_, p3_, p4_, p5_);

-  }

-

-  using BaseFunctor::Invoke;

-

- private:

-  void (*pf_)(P1, P2, P3, P4, P5);

-  P1 p1_;

-  P2 p2_;

-  P3 p3_;

-  P4 p4_;

-  P5 p5_;

-};

-

-

-// This is what the clients of the STA code instantiate and call.

-//

-// Synchronous Callers.

-//

-template <class T, typename R>

-R CallMethod(T* object, R (T::*pm)()) {

-  return MethodFunctor0<T, R>(false, object, pm).Invoke();

-}

-

-template <typename R>

-R CallFunction(R (*pf)()) {

-  return Functor0<R>(false, pf).Invoke();

-}

-

-template <class T, typename R, typename P>

-R CallMethod(T* object, R (T::*pm)(P), P p) {

-  return MethodFunctor1<T, R, P>(false, object, pm, p).Invoke();

-}

-

-template <typename R, typename P>

-R CallFunction(R (*pf)(P), P p) {

-  return Functor1<R, P>(false, pf, p).Invoke();

-}

-

-template <class T, typename R, typename P1, typename P2>

-R CallMethod(T* object, R (T::*pm)(P1, P2), P1 p1, P2 p2) {

-  return MethodFunctor2<T, R, P1, P2>(false, object, pm, p1, p2).Invoke();

-}

-

-template <typename R, typename P1, typename P2>

-R CallFunction(R (*pf)(P1, P2), P1 p1, P2 p2) {

-  return Functor2<R, P1, P2>(false, pf, p1, p2).Invoke();

-}

-

-template <class T, typename R, typename P1, typename P2, typename P3>

-R CallMethod(T* object, R (T::*pm)(P1, P2, P3), P1 p1, P2 p2, P3 p3) {

-  return MethodFunctor3<T, R, P1, P2, P3>(false,

-                                          object, pm, p1, p2, p3).Invoke();

-}

-

-template <typename R, typename P1, typename P2, typename P3>

-R CallFunction(R (*pf)(P1, P2, P3), P1 p1, P2 p2, P3 p3) {

-  return Functor3<R, P1, P2, P3>(false, pf, p1, p2, p3).Invoke();

-}

-

-template <class T,

-          typename R,

-          typename P1,

-          typename P2,

-          typename P3,

-          typename P4>

-R CallMethod(T* object,

-             R (T::*pm)(P1, P2, P3, P4),

-             P1 p1,

-             P2 p2,

-             P3 p3,

-             P4 p4) {

-  return MethodFunctor4<T, R, P1, P2, P3, P4>(false,

-                                              object,

-                                              pm,

-                                              p1,

-                                              p2,

-                                              p3,

-                                              p4).Invoke();

-}

-

-template <typename R, typename P1, typename P2, typename P3, typename P4>

-R CallFunction(R (*pf)(P1, P2, P3, P4), P1 p1, P2 p2, P3 p3, P4 p4) {

-  return Functor4<R, P1, P2, P3, P4>(false, pf, p1, p2, p3, p4).Invoke();

-}

-

-template <class T,

-          typename R,

-          typename P1,

-          typename P2,

-          typename P3,

-          typename P4,

-          typename P5>

-R CallMethod(T* object,

-             R (T::*pm)(P1, P2, P3, P4, P5),

-             P1 p1,

-             P2 p2,

-             P3 p3,

-             P4 p4,

-             P5 p5) {

-  return MethodFunctor5<T, R, P1, P2, P3, P4, P5>(false,

-                                                  object,

-                                                  pm,

-                                                  p1,

-                                                  p2,

-                                                  p3,

-                                                  p4,

-                                                  p5).Invoke();

-}

-

-template <typename R,

-          typename P1,

-          typename P2,

-          typename P3,

-          typename P4,

-          typename P5>

-R CallFunction(R (*pf)(P1, P2, P3, P4, P5), P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {

-  return Functor5<R, P1, P2, P3, P4, P5>(false,

-                                         pf,

-                                         p1,

-                                         p2,

-                                         p3,

-                                         p4,

-                                         p5).Invoke();

-}

-

-//

-// Asynchronous Callers.

-//

-template <class T, typename R>

-void CallMethodAsync(T* object, R (T::*pm)()) {

-  scoped_ptr<MethodFunctor0<T, R> > fun(

-      new MethodFunctor0<T, R>(true, object, pm));

-  fun->Invoke();

-  fun.release();

-}

-

-template <typename R>

-void CallFunctionAsync(R (*pf)()) {

-  scoped_ptr<Functor0<R> > fun(new Functor0<R>(true, pf));

-  fun->Invoke();

-  fun.release();

-}

-

-template <class T, typename R, typename P>

-void CallMethodAsync(T* object, R (T::*pm)(P), P p) {

-  scoped_ptr<MethodFunctor1<T, R, P> > fun(

-      new MethodFunctor1<T, R, P>(true, object, pm, p));

-  fun->Invoke();

-  fun.release();

-}

-

-template <typename R, typename P>

-void CallFunctionAsync(R (*pf)(P), P p) {

-  scoped_ptr<Functor1<R, P> > fun(new Functor1<R, P>(true, pf, p));

-  fun->Invoke();

-  fun.release();

-}

-

-template <class T, typename R, typename P1, typename P2>

-void CallMethodAsync(T* object, R (T::*pm)(P1, P2), P1 p1, P2 p2) {

-  scoped_ptr<MethodFunctor2<T, R, P1, P2> > fun(

-      new MethodFunctor2<T, R, P1, P2>(true, object, pm, p1, p2));

-  fun->Invoke();

-  fun.release();

-}

-

-template <typename R, typename P1, typename P2>

-void CallFunctionAsync(R (*pf)(P1, P2), P1 p1, P2 p2) {

-  scoped_ptr<Functor2<R, P1, P2> > fun(

-      new Functor2<R, P1, P2>(true, pf, p1, p2));

-  fun->Invoke();

-  fun.release();

-}

-

-template <class T, typename R, typename P1, typename P2, typename P3>

-void CallMethodAsync(T* object, R (T::*pm)(P1, P2, P3), P1 p1, P2 p2, P3 p3) {

-  scoped_ptr<MethodFunctor3<T, R, P1, P2, P3> > fun(

-      new MethodFunctor3<T, R, P1, P2, P3>(true, object, pm, p1, p2, p3));

-  fun->Invoke();

-  fun.release();

-}

-

-template <typename R, typename P1, typename P2, typename P3>

-void CallFunctionAsync(R (*pf)(P1, P2, P3), P1 p1, P2 p2, P3 p3) {

-  scoped_ptr<Functor3<R, P1, P2, P3> > fun(

-      new Functor3<R, P1, P2, P3>(true, pf, p1, p2, p3));

-  fun->Invoke();

-  fun.release();

-}

-

-template <class T,

-          typename R,

-          typename P1,

-          typename P2,

-          typename P3,

-          typename P4>

-void CallMethodAsync(T* obj,

-                     R (T::*pm)(P1, P2, P3, P4),

-                     P1 p1,

-                     P2 p2,

-                     P3 p3,

-                     P4 p4) {

-  scoped_ptr<MethodFunctor4<T, R, P1, P2, P3, P4> > fun(

-      new MethodFunctor4<T, R, P1, P2, P3, P4>(true, obj, pm, p1, p2, p3, p4));

-  fun->Invoke();

-  fun.release();

-}

-

-template <typename R, typename P1, typename P2, typename P3, typename P4>

-void CallFunctionAsync(R (*pf)(P1, P2, P3, P4), P1 p1, P2 p2, P3 p3, P4 p4) {

-  scoped_ptr<Functor4<R, P1, P2, P3, P4> > fun(

-      new Functor4<R, P1, P2, P3, P4>(true, pf, p1, p2, p3, p4));

-  fun->Invoke();

-  fun.release();

-}

-

-template <class T,

-          typename R,

-          typename P1,

-          typename P2,

-          typename P3,

-          typename P4,

-          typename P5>

-void CallMethodAsync(T* object,

-                     R (T::*pm)(P1, P2, P3, P4, P5),

-                     P1 p1,

-                     P2 p2,

-                     P3 p3,

-                     P4 p4,

-                     P5 p5) {

-  scoped_ptr<MethodFunctor5<T, R, P1, P2, P3, P4, P5> > fun(

-      new MethodFunctor5<T, R, P1, P2, P3, P4, P5>(true,

-                                                   object,

-                                                   pm,

-                                                   p1,

-                                                   p2,

-                                                   p3,

-                                                   p4,

-                                                   p5));

-  fun->Invoke();

-  fun.release();

-}

-

-template <typename R,

-          typename P1,

-          typename P2,

-          typename P3,

-          typename P4,

-          typename P5>

-void CallFunctionAsync(R (*pf)(P1, P2, P3, P4, P5),

-                       P1 p1,

-                       P2 p2,

-                       P3 p3,

-                       P4 p4,

-                       P5 p5) {

-  scoped_ptr<Functor5<R, P1, P2, P3, P4, P5> > fun(

-      new Functor5<R, P1, P2, P3, P4, P5>(true, pf, p1, p2, p3, p4, p5));

-  fun->Invoke();

-  fun.release();

-}

-

-#pragma warning(default : 4347)

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_STA_CALL_H__

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// sta_call.h generics for cross apartment calling.
+//
+// The code is using compile-time and run-time polymorphism to create
+// type-safe call wrappers that can be used to cross call from a
+// worker thread to an STA thread. The current implementation only
+// supports calling the main STA.
+//
+// Functions as well as object methods can be called.
+//
+// Examples:
+// class X {
+//   public:
+//     int Add(int i, int j) { return i + j; }
+// };
+//
+//
+// namespace {
+//   int Add(long i, long j) { return i + j; }
+// }
+//
+// X x;
+// int sum = CallMethod(&x, X::Add, 10, 20);
+// int j = CallFunction(Add, -10, 10);
+//
+// The central piece of machinery is a hierarchy of functors. A functor is
+// instantiated by a function template (CallFunction or CallMethod) and its
+// 'Invoke' method gets called.
+// Calling 'Invoke' will send the functor using 'SendMessage'
+// to a window. The window message handler picks up the functor and
+// calls the functor virtual operator().
+// This virtual call is what actually calls the specified function or the
+// method, the only difference being that the call is now made in a thread
+// different than the thread that called 'Invoke'. There is a partial
+// specialization of the templates for void, so that void type is supported
+// as a return type.
+//
+//
+// !!! Limitations !!!
+//
+// There are a few important design and implementation limitations. They are
+// mostly related to template parameters ambiguities (T or T&) especially
+// for overloaded names or const types. The limitations are significant although
+// the code is useful enough as it is in most of the cases.
+// However, when using the code it is frustrating to discover that it does not
+// compile for obvious and useful cases, a constant reminder that a better
+// solution is to be seeked.
+//
+//
+// The implementation does not support calling all 'stdcall' calling convention.
+//
+// The design does not support calling functions or methods that use pass by
+// reference arguments: f(std::string&) .
+//
+// The design does not support well calling functions or methods that take
+// pointer to const types parameters : f(const std::string*) .
+//
+// The implementation does not support calling methods of const objects.
+//
+// To reduce the number of templates that get instantiated, the types of the
+// arguments of the call must match exactly the types of parameters of the
+// function or method . In some cases static_casts mey be required
+// at the point of the call. Example: CallMethod(f, static_cast<long>(10));
+
+#ifndef OMAHA_COMMON_STA_CALL_H__
+#define OMAHA_COMMON_STA_CALL_H__
+
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+
+namespace omaha {
+
+// C4347: 'function template' is called instead of 'function'
+#pragma warning(disable : 4347)
+
+// The Base Functor is the base of the functor hierarchy.
+class BaseFunctor {
+ public:
+  explicit BaseFunctor(bool is_async) :
+      thread_id_(::GetCurrentThreadId()),
+      is_async_(is_async) {
+    CORE_LOG(L6, (_T("[BaseFunctor::BaseFunctor]")));
+  }
+
+  // Functors are polymorphic objects.
+  virtual ~BaseFunctor() {
+    CORE_LOG(L6, (_T("[BaseFunctor::~BaseFunctor]")));
+  }
+
+  // Abstract virtual function call operator. This is always called
+  // in the callee thread by the dispatcher of the apartment.
+  virtual void operator()(void* presult) = 0;
+
+  // The thread id of the calling thread.
+  DWORD thread_id() const { return thread_id_; }
+
+  bool is_async() const { return is_async_; }
+
+ protected:
+
+  // Invoke is called by each of the derived functors. This is how
+  // the  cross thread invocation is made and the result of the invocation
+  // is retrieved. Invoke is always called in the caller thread.
+  template <typename R>
+  R Invoke() {
+    R r = R();      // ensure r is initialized even for primitive types.
+    if (!is_async_) {
+      DoInvoke(&r);
+    } else {
+      // We handle the async calls as if the call returns void.
+      DoInvoke(0);
+    }
+    return r;
+  }
+
+  // non-template method to be called by the derived functors
+  // specialized for void.
+  void Invoke() {
+    // When the argument of the invocation is 0, we are not
+    // interested in the result.
+    DoInvoke(0);
+  }
+
+ private:
+  void DoInvoke(void* presult);   // Does the actual invocation.
+  DWORD thread_id_;               // The thread id of the calling thread.
+  bool is_async_;                 // True for async calls.
+
+  DISALLOW_EVIL_CONSTRUCTORS(BaseFunctor);
+};
+
+//
+// 0-ary method functor.
+//
+template <class T, typename R>
+class MethodFunctor0 : public BaseFunctor {
+ public:
+  MethodFunctor0(bool is_async, T* pt, R (T::*pm)()) :
+      BaseFunctor(is_async), pobj_(pt), pm_(pm) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    if (presult) {
+      *static_cast<R*>(presult) = (pobj_->*pm_)();
+    } else {
+      (pobj_->*pm_)();
+    }
+  }
+
+  R Invoke() {
+    // Don't forget to call the base implementation.
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  T* pobj_;
+  R (T::*pm_)();
+};
+
+//
+// 0-ary partial specialization for void return types.
+//
+template <class T>
+class MethodFunctor0<T, void> : public BaseFunctor {
+ public:
+  MethodFunctor0(bool is_async, T* pt, void (T::*pm)()) :
+      BaseFunctor(is_async), pobj_(pt), pm_(pm) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    // the actual call. There is no return value when the return type is void.
+    (pobj_->*pm_)();
+  }
+
+  // Bring in the name from the Base
+  using BaseFunctor::Invoke;
+
+ private:
+  T* pobj_;
+  void (T::*pm_)();
+};
+
+//
+// 0-ary functor and specialization for void.
+//
+template <typename R>
+class Functor0 : public BaseFunctor {
+ public:
+  Functor0(bool is_async, R (*pf)()) :
+      BaseFunctor(is_async), pf_(pf) {}
+
+  virtual void operator()(void* presult) {
+    if (presult) {
+      *static_cast<R*>(presult) = (*pf_)();
+    } else {
+      (*pf_)();
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  R (*pf_)();
+};
+
+template <>
+class Functor0<void> : public BaseFunctor {
+ public:
+  Functor0(bool is_async, void (*pf)()) :
+      BaseFunctor(is_async), pf_(pf) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT1(!presult);
+    presult;  // unreferenced formal parameter
+
+    (*pf_)();
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  void (*pf_)();
+};
+
+
+//
+// 1-ary
+//
+template <class T, typename R, typename P>
+class MethodFunctor1 : public BaseFunctor {
+ public:
+  MethodFunctor1(bool is_async, T* pt, R (T::*pm)(P), P p) :
+      BaseFunctor(is_async), pobj_(pt), pm_(pm), p_(p) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    if (presult) {
+      *static_cast<R*>(presult) = (pobj_->*pm_)(p_);
+    } else {
+      (pobj_->*pm_)(p_);
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  T* pobj_;
+  R (T::*pm_)(P);
+  P p_;
+};
+
+template <class T, typename P>
+class MethodFunctor1<T, void, P> : public BaseFunctor {
+ public:
+  MethodFunctor1(bool is_async, T* pt, void (T::*pm)(P), P p) :
+      BaseFunctor(is_async), pobj_(pt), pm_(pm), p_(p) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    (pobj_->*pm_)(p_);
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  T* pobj_;
+  void (T::*pm_)(P);
+  P p_;
+};
+
+template <typename R, typename P1>
+class Functor1 : public BaseFunctor {
+ public:
+  Functor1(bool is_async, R (*pf)(P1), P1 p1) :
+      BaseFunctor(is_async), pf_(pf), p1_(p1) {}
+
+  virtual void operator()(void* presult) {
+    if (presult) {
+      *static_cast<R*>(presult) = (*pf_)(p1_);
+    } else {
+      (*pf_)(p1_);
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  R (*pf_)(P1);
+  P1 p1_;
+};
+
+template <typename P1>
+class Functor1<void, P1> : public BaseFunctor {
+ public:
+  Functor1(bool is_async, void (*pf)(P1), P1 p1) :
+      BaseFunctor(is_async), pf_(pf), p1_(p1) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    (*pf_)(p1_);
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  void (*pf_)(P1);
+  P1 p1_;
+};
+
+
+//
+// 2-ary
+//
+template <class T, typename R, typename P1, typename P2>
+class MethodFunctor2 : public BaseFunctor {
+ public:
+  MethodFunctor2(bool is_async, T* pt, R (T::*pm)(P1, P2), P1 p1, P2 p2) :
+      BaseFunctor(is_async), pobj_(pt), pm_(pm), p1_(p1), p2_(p2) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    if (presult) {
+      *static_cast<R*>(presult) = (pobj_->*pm_)(p1_, p2_);
+    } else {
+      (pobj_->*pm_)(p1_, p2_);
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  T* pobj_;
+  R (T::*pm_)(P1, P2);
+  P1 p1_;
+  P2 p2_;
+};
+
+template <class T, typename P1, typename P2>
+class MethodFunctor2<T, void, P1, P2> : public BaseFunctor {
+ public:
+  MethodFunctor2(bool is_async, T* pt, void (T::*pm)(P1, P2), P1 p1, P2 p2) :
+      BaseFunctor(is_async), pobj_(pt), pm_(pm), p1_(p1), p2_(p2) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    (pobj_->*pm_)(p1_, p2_);
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  T* pobj_;
+  void (T::*pm_)(P1, P2);
+  P1 p1_;
+  P2 p2_;
+};
+
+template <typename R, typename P1, typename P2>
+class Functor2 : public BaseFunctor {
+ public:
+  Functor2(bool is_async, R (*pf)(P1, P2), P1 p1, P2 p2) :
+      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2) {}
+
+  virtual void operator()(void* presult) {
+    if (presult) {
+      *static_cast<R*>(presult) = pf_(p1_, p2_);
+    } else {
+      pf_(p1_, p2_);
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  R (*pf_)(P1, P2);
+  P1 p1_;
+  P2 p2_;
+};
+
+template <typename P1, typename P2>
+class Functor2<void, P1, P2> : public BaseFunctor {
+ public:
+  Functor2(bool is_async, void (*pf)(P1, P2), P1 p1, P2 p2) :
+      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    (*pf_)(p1_, p2_);
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  void (*pf_)(P1, P2);
+  P1 p1_;
+  P2 p2_;
+};
+
+//
+// 3-ary
+//
+template <class T, typename R, typename P1, typename P2, typename P3>
+class MethodFunctor3 : public BaseFunctor {
+ public:
+  MethodFunctor3(bool is_async,
+                 T* pt,
+                 R (T::*pm)(P1, P2, P3),
+                 P1 p1,
+                 P2 p2,
+                 P3 p3) :
+      BaseFunctor(is_async), pobj_(pt), pm_(pm), p1_(p1), p2_(p2), p3_(p3) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    if (presult) {
+      *static_cast<R*>(presult) = (pobj_->*pm_)(p1_, p2_, p3_);
+    } else {
+      (pobj_->*pm_)(p1_, p2_, p3_);
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  T* pobj_;
+  R (T::*pm_)(P1, P2, P3);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+};
+
+template <class T, typename P1, typename P2, typename P3>
+class MethodFunctor3<T, void, P1, P2, P3> : public BaseFunctor {
+ public:
+  MethodFunctor3(bool is_async,
+                 T* pt,
+                 void (T::*pm)(P1, P2, P3),
+                 P1 p1,
+                 P2 p2,
+                 P3 p3) :
+      BaseFunctor(is_async), pobj_(pt), pm_(pm), p1_(p1), p2_(p2), p3_(p3) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    (pobj_->*pm_)(p1_, p2_, p3_);
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  T* pobj_;
+  void (T::*pm_)(P1, P2, P3);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+};
+
+
+template <typename R, typename P1, typename P2, typename P3>
+class Functor3 : public BaseFunctor {
+ public:
+  Functor3(bool is_async, R (*pf)(P1, P2, P3), P1 p1, P2 p2, P3 p3) :
+      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2), p3_(p3) {}
+  virtual void operator()(void* presult) {
+    if (presult) {
+      *static_cast<R*>(presult) = (*pf_)(p1_, p2_, p3_);
+    } else {
+      (*pf_)(p1_, p2_, p3_);
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  R (*pf_)(P1, P2, P3);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+};
+
+template <typename P1, typename P2, typename P3>
+class Functor3<void, P1, P2, P3> : public BaseFunctor {
+ public:
+  Functor3(bool is_async, void (*pf)(P1, P2, P3), P1 p1, P2 p2, P3 p3) :
+      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2), p3_(p3) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    (*pf_)(p1_, p2_, p3_);
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  void (*pf_)(P1, P2, P3);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+};
+
+//
+// 4-ary
+//
+template <class T,
+          typename R,
+          typename P1,
+          typename P2,
+          typename P3,
+          typename P4>
+class MethodFunctor4 : public BaseFunctor {
+ public:
+  MethodFunctor4(bool is_async,
+                 T* pt,
+                 R (T::*pm)(P1, P2, P3, P4),
+                 P1 p1,
+                 P2 p2,
+                 P3 p3,
+                 P4 p4) :
+      BaseFunctor(is_async),
+      pobj_(pt),
+      pm_(pm),
+      p1_(p1),
+      p2_(p2),
+      p3_(p3),
+      p4_(p4) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    if (presult) {
+      *static_cast<R*>(presult) = (pobj_->*pm_)(p1_, p2_, p3_, p4_);
+    } else {
+      (pobj_->*pm_)(p1_, p2_, p3_, p4_);
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  T* pobj_;
+  R (T::*pm_)(P1, P2, P3, P4);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+};
+
+template <class T, typename P1, typename P2, typename P3, typename P4>
+class MethodFunctor4<T, void, P1, P2, P3, P4> : public BaseFunctor {
+ public:
+  MethodFunctor4(bool is_async,
+                 T* pt,
+                 void (T::*pm)(P1, P2, P3, P4),
+                 P1 p1,
+                 P2 p2,
+                 P3 p3,
+                 P4 p4) :
+      BaseFunctor(is_async),
+      pobj_(pt),
+      pm_(pm),
+      p1_(p1),
+      p2_(p2),
+      p3_(p3),
+      p4_(p4) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    (pobj_->*pm_)(p1_, p2_, p3_, p4_);
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  T* pobj_;
+  void (T::*pm_)(P1, P2, P3, P4);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+};
+
+
+template <typename R, typename P1, typename P2, typename P3, typename P4>
+class Functor4 : public BaseFunctor {
+ public:
+  Functor4(bool is_async, R (*pf)(P1, P2, P3, P4), P1 p1, P2 p2, P3 p3, P4 p4) :
+      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2), p3_(p3), p4_(p4) {}
+
+  virtual void operator()(void* presult) {
+    if (presult) {
+      *static_cast<R*>(presult) = (*pf_)(p1_, p2_, p3_, p4_);
+    } else {
+      (*pf_)(p1_, p2_, p3_, p4_);
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  R (*pf_)(P1, P2, P3, P4);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+};
+
+template <typename P1, typename P2, typename P3, typename P4>
+class Functor4<void, P1, P2, P3, P4> : public BaseFunctor {
+ public:
+  Functor4(bool is_async,
+           void (*pf)(P1, P2, P3, P4),
+           P1 p1,
+           P2 p2,
+           P3 p3,
+           P4 p4) :
+      BaseFunctor(is_async), pf_(pf), p1_(p1), p2_(p2), p3_(p3), p4_(p4) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    (*pf_)(p1_, p2_, p3_, p4_);
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  void (*pf_)(P1, P2, P3, P4);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+};
+
+//
+// 5-ary
+//
+template <class T,
+          typename R,
+          typename P1,
+          typename P2,
+          typename P3,
+          typename P4,
+          typename P5>
+class MethodFunctor5 : public BaseFunctor {
+ public:
+  MethodFunctor5(bool is_async,
+                 T* pt,
+                 R (T::*pm)(P1, P2, P3, P4, P5),
+                 P1 p1,
+                 P2 p2,
+                 P3 p3,
+                 P4 p4,
+                 P5 p5) :
+      BaseFunctor(is_async),
+      pobj_(pt),
+      pm_(pm),
+      p1_(p1),
+      p2_(p2),
+      p3_(p3),
+      p4_(p4),
+      p5_(p5) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    if (presult) {
+      *static_cast<R*>(presult) = (pobj_->*pm_)(p1_, p2_, p3_, p4_, p5_);
+    } else {
+      (pobj_->*pm_)(p1_, p2_, p3_, p4_, p5_);
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  T* pobj_;
+  R (T::*pm_)(P1, P2, P3, P4, P5);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+  P5 p5_;
+};
+
+template <class T,
+          typename P1,
+          typename P2,
+          typename P3,
+          typename P4,
+          typename P5>
+class MethodFunctor5<T, void, P1, P2, P3, P4, P5> : public BaseFunctor {
+ public:
+  MethodFunctor5(bool is_async,
+                 T* pt,
+                 void (T::*pm)(P1, P2, P3, P4, P5),
+                 P1 p1,
+                 P2 p2,
+                 P3 p3,
+                 P4 p4,
+                 P5 p5) :
+      BaseFunctor(is_async),
+      pobj_(pt),
+      pm_(pm),
+      p1_(p1),
+      p2_(p2),
+      p3_(p3),
+      p4_(p4),
+      p5_(p5) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT(pobj_, (_T("Null object.")));
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    (pobj_->*pm_)(p1_, p2_, p3_, p4_, p5_);
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  T* pobj_;
+  void (T::*pm_)(P1, P2, P3, P4, P5);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+  P5 p5_;
+};
+
+template <typename R,
+          typename P1,
+          typename P2,
+          typename P3,
+          typename P4,
+          typename P5>
+class Functor5 : public BaseFunctor {
+ public:
+  Functor5(bool is_async,
+           R (*pf)(P1, P2, P3, P4, P5),
+           P1 p1,
+           P2 p2,
+           P3 p3,
+           P4 p4,
+           P5 p5) :
+      BaseFunctor(is_async),
+      pf_(pf),
+      p1_(p1),
+      p2_(p2),
+      p3_(p3),
+      p4_(p4),
+      p5_(p5) {}
+  virtual void operator()(void* presult) {
+    if (presult) {
+      *static_cast<R*>(presult) = (*pf_)(p1_, p2_, p3_, p4_, p5_);
+    } else {
+      (*pf_)(p1_, p2_, p3_, p4_, p5_);
+    }
+  }
+
+  R Invoke() {
+    return BaseFunctor::Invoke<R>();
+  }
+
+ private:
+  R (*pf_)(P1, P2, P3, P4, P5);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+  P5 p5_;
+};
+
+template <typename P1, typename P2, typename P3, typename P4, typename P5>
+class Functor5<void, P1, P2, P3, P4, P5> : public BaseFunctor {
+ public:
+  Functor5(bool is_async,
+           void (*pf)(P1, P2, P3, P4, P5),
+           P1 p1,
+           P2 p2,
+           P3 p3,
+           P4 p4,
+           P5 p5) :
+      BaseFunctor(is_async),
+      pf_(pf),
+      p1_(p1),
+      p2_(p2),
+      p3_(p3),
+      p4_(p4),
+      p5_(p5) {}
+
+  virtual void operator()(void* presult) {
+    ASSERT1(!presult);
+    presult;  //  unreferenced formal parameter
+
+    (*pf_)(p1_, p2_, p3_, p4_, p5_);
+  }
+
+  using BaseFunctor::Invoke;
+
+ private:
+  void (*pf_)(P1, P2, P3, P4, P5);
+  P1 p1_;
+  P2 p2_;
+  P3 p3_;
+  P4 p4_;
+  P5 p5_;
+};
+
+
+// This is what the clients of the STA code instantiate and call.
+//
+// Synchronous Callers.
+//
+template <class T, typename R>
+R CallMethod(T* object, R (T::*pm)()) {
+  return MethodFunctor0<T, R>(false, object, pm).Invoke();
+}
+
+template <typename R>
+R CallFunction(R (*pf)()) {
+  return Functor0<R>(false, pf).Invoke();
+}
+
+template <class T, typename R, typename P>
+R CallMethod(T* object, R (T::*pm)(P), P p) {
+  return MethodFunctor1<T, R, P>(false, object, pm, p).Invoke();
+}
+
+template <typename R, typename P>
+R CallFunction(R (*pf)(P), P p) {
+  return Functor1<R, P>(false, pf, p).Invoke();
+}
+
+template <class T, typename R, typename P1, typename P2>
+R CallMethod(T* object, R (T::*pm)(P1, P2), P1 p1, P2 p2) {
+  return MethodFunctor2<T, R, P1, P2>(false, object, pm, p1, p2).Invoke();
+}
+
+template <typename R, typename P1, typename P2>
+R CallFunction(R (*pf)(P1, P2), P1 p1, P2 p2) {
+  return Functor2<R, P1, P2>(false, pf, p1, p2).Invoke();
+}
+
+template <class T, typename R, typename P1, typename P2, typename P3>
+R CallMethod(T* object, R (T::*pm)(P1, P2, P3), P1 p1, P2 p2, P3 p3) {
+  return MethodFunctor3<T, R, P1, P2, P3>(false,
+                                          object, pm, p1, p2, p3).Invoke();
+}
+
+template <typename R, typename P1, typename P2, typename P3>
+R CallFunction(R (*pf)(P1, P2, P3), P1 p1, P2 p2, P3 p3) {
+  return Functor3<R, P1, P2, P3>(false, pf, p1, p2, p3).Invoke();
+}
+
+template <class T,
+          typename R,
+          typename P1,
+          typename P2,
+          typename P3,
+          typename P4>
+R CallMethod(T* object,
+             R (T::*pm)(P1, P2, P3, P4),
+             P1 p1,
+             P2 p2,
+             P3 p3,
+             P4 p4) {
+  return MethodFunctor4<T, R, P1, P2, P3, P4>(false,
+                                              object,
+                                              pm,
+                                              p1,
+                                              p2,
+                                              p3,
+                                              p4).Invoke();
+}
+
+template <typename R, typename P1, typename P2, typename P3, typename P4>
+R CallFunction(R (*pf)(P1, P2, P3, P4), P1 p1, P2 p2, P3 p3, P4 p4) {
+  return Functor4<R, P1, P2, P3, P4>(false, pf, p1, p2, p3, p4).Invoke();
+}
+
+template <class T,
+          typename R,
+          typename P1,
+          typename P2,
+          typename P3,
+          typename P4,
+          typename P5>
+R CallMethod(T* object,
+             R (T::*pm)(P1, P2, P3, P4, P5),
+             P1 p1,
+             P2 p2,
+             P3 p3,
+             P4 p4,
+             P5 p5) {
+  return MethodFunctor5<T, R, P1, P2, P3, P4, P5>(false,
+                                                  object,
+                                                  pm,
+                                                  p1,
+                                                  p2,
+                                                  p3,
+                                                  p4,
+                                                  p5).Invoke();
+}
+
+template <typename R,
+          typename P1,
+          typename P2,
+          typename P3,
+          typename P4,
+          typename P5>
+R CallFunction(R (*pf)(P1, P2, P3, P4, P5), P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+  return Functor5<R, P1, P2, P3, P4, P5>(false,
+                                         pf,
+                                         p1,
+                                         p2,
+                                         p3,
+                                         p4,
+                                         p5).Invoke();
+}
+
+//
+// Asynchronous Callers.
+//
+template <class T, typename R>
+void CallMethodAsync(T* object, R (T::*pm)()) {
+  scoped_ptr<MethodFunctor0<T, R> > fun(
+      new MethodFunctor0<T, R>(true, object, pm));
+  fun->Invoke();
+  fun.release();
+}
+
+template <typename R>
+void CallFunctionAsync(R (*pf)()) {
+  scoped_ptr<Functor0<R> > fun(new Functor0<R>(true, pf));
+  fun->Invoke();
+  fun.release();
+}
+
+template <class T, typename R, typename P>
+void CallMethodAsync(T* object, R (T::*pm)(P), P p) {
+  scoped_ptr<MethodFunctor1<T, R, P> > fun(
+      new MethodFunctor1<T, R, P>(true, object, pm, p));
+  fun->Invoke();
+  fun.release();
+}
+
+template <typename R, typename P>
+void CallFunctionAsync(R (*pf)(P), P p) {
+  scoped_ptr<Functor1<R, P> > fun(new Functor1<R, P>(true, pf, p));
+  fun->Invoke();
+  fun.release();
+}
+
+template <class T, typename R, typename P1, typename P2>
+void CallMethodAsync(T* object, R (T::*pm)(P1, P2), P1 p1, P2 p2) {
+  scoped_ptr<MethodFunctor2<T, R, P1, P2> > fun(
+      new MethodFunctor2<T, R, P1, P2>(true, object, pm, p1, p2));
+  fun->Invoke();
+  fun.release();
+}
+
+template <typename R, typename P1, typename P2>
+void CallFunctionAsync(R (*pf)(P1, P2), P1 p1, P2 p2) {
+  scoped_ptr<Functor2<R, P1, P2> > fun(
+      new Functor2<R, P1, P2>(true, pf, p1, p2));
+  fun->Invoke();
+  fun.release();
+}
+
+template <class T, typename R, typename P1, typename P2, typename P3>
+void CallMethodAsync(T* object, R (T::*pm)(P1, P2, P3), P1 p1, P2 p2, P3 p3) {
+  scoped_ptr<MethodFunctor3<T, R, P1, P2, P3> > fun(
+      new MethodFunctor3<T, R, P1, P2, P3>(true, object, pm, p1, p2, p3));
+  fun->Invoke();
+  fun.release();
+}
+
+template <typename R, typename P1, typename P2, typename P3>
+void CallFunctionAsync(R (*pf)(P1, P2, P3), P1 p1, P2 p2, P3 p3) {
+  scoped_ptr<Functor3<R, P1, P2, P3> > fun(
+      new Functor3<R, P1, P2, P3>(true, pf, p1, p2, p3));
+  fun->Invoke();
+  fun.release();
+}
+
+template <class T,
+          typename R,
+          typename P1,
+          typename P2,
+          typename P3,
+          typename P4>
+void CallMethodAsync(T* obj,
+                     R (T::*pm)(P1, P2, P3, P4),
+                     P1 p1,
+                     P2 p2,
+                     P3 p3,
+                     P4 p4) {
+  scoped_ptr<MethodFunctor4<T, R, P1, P2, P3, P4> > fun(
+      new MethodFunctor4<T, R, P1, P2, P3, P4>(true, obj, pm, p1, p2, p3, p4));
+  fun->Invoke();
+  fun.release();
+}
+
+template <typename R, typename P1, typename P2, typename P3, typename P4>
+void CallFunctionAsync(R (*pf)(P1, P2, P3, P4), P1 p1, P2 p2, P3 p3, P4 p4) {
+  scoped_ptr<Functor4<R, P1, P2, P3, P4> > fun(
+      new Functor4<R, P1, P2, P3, P4>(true, pf, p1, p2, p3, p4));
+  fun->Invoke();
+  fun.release();
+}
+
+template <class T,
+          typename R,
+          typename P1,
+          typename P2,
+          typename P3,
+          typename P4,
+          typename P5>
+void CallMethodAsync(T* object,
+                     R (T::*pm)(P1, P2, P3, P4, P5),
+                     P1 p1,
+                     P2 p2,
+                     P3 p3,
+                     P4 p4,
+                     P5 p5) {
+  scoped_ptr<MethodFunctor5<T, R, P1, P2, P3, P4, P5> > fun(
+      new MethodFunctor5<T, R, P1, P2, P3, P4, P5>(true,
+                                                   object,
+                                                   pm,
+                                                   p1,
+                                                   p2,
+                                                   p3,
+                                                   p4,
+                                                   p5));
+  fun->Invoke();
+  fun.release();
+}
+
+template <typename R,
+          typename P1,
+          typename P2,
+          typename P3,
+          typename P4,
+          typename P5>
+void CallFunctionAsync(R (*pf)(P1, P2, P3, P4, P5),
+                       P1 p1,
+                       P2 p2,
+                       P3 p3,
+                       P4 p4,
+                       P5 p5) {
+  scoped_ptr<Functor5<R, P1, P2, P3, P4, P5> > fun(
+      new Functor5<R, P1, P2, P3, P4, P5>(true, pf, p1, p2, p3, p4, p5));
+  fun->Invoke();
+  fun.release();
+}
+
+#pragma warning(default : 4347)
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_STA_CALL_H__
+
diff --git a/common/sta_unittest.cc b/common/sta_unittest.cc
index 8cfd6f8..1e52b68 100644
--- a/common/sta_unittest.cc
+++ b/common/sta_unittest.cc
@@ -1,288 +1,288 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include <atlstr.h>

-#include "omaha/common/sta.h"

-#include "omaha/common/sta_call.h"

-#include "omaha/common/thread.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-class X {

- public:

-  void f() {}

-  void f(int) {}

-  void f(unsigned int, X*) {}

-  void f(bool, char, long*) {}

-

-  static void g() {}

-  static void g(int) {}

-  static void g(unsigned int, X*) {}

-  static void g(bool, char, long*) {}

-};

-

-class Y {

- public:

-  HRESULT f() { return S_OK; }

-  HRESULT f(int) { return S_OK; }

-  HRESULT f(unsigned int, X*) { return S_OK; }

-  HRESULT f(bool, char, long*) { return S_OK; }

-

-  static HRESULT g() { return S_OK; }

-  static HRESULT g(int) { return S_OK; }

-  static HRESULT g(unsigned int, X*) { return S_OK; }

-  static HRESULT g(bool, char, long*) { return S_OK; }

-};

-

-class Z {

- public:

-  void f(char, signed char, unsigned char) {}

-

-  void f(Y*) {}

-  // void f(const Y*) {} // not supported !!!

-

-  void m() {}

-  void m() const {}

-};

-

-class Test {

- public:

-  int Add(int i, int j) { return i + j; }

-  void Add(int i, int j, int* sum) { *sum = i + j; }

-};

-

-int Add(long i, long j) { return i + j; }

-void Add(long i, long j, long* sum) { *sum = i + j; }

-

-void Print(const char*) {}

-void Print1(CString*) {}

-

-}  // namespace

-

-class CompileTest : public Runnable {

- protected:

-  virtual void Run();

-};

-

-void CompileTest::Run() {

-  X x;

-  Y y;

-

-  CallFunction(X::g);

-  CallFunction(X::g, 10);

-  CallFunction(X::g, static_cast<unsigned int>(10), &x);

-  CallFunction(X::g, true, 'a', static_cast<long*>(0));

-

-  CallFunction(Y::g);

-  CallFunction(Y::g, 10);

-  CallFunction(Y::g, static_cast<unsigned int>(10), &x);

-  CallFunction(Y::g, true, 'a', static_cast<long*>(0));

-

-  CallMethod(&x, &X::f);

-  CallMethod(&x, &X::f, 10);

-  CallMethod(&x, &X::f, static_cast<unsigned int>(10), &x);

-  CallMethod(&x, &X::f, true, 'a', static_cast<long*>(0));

-

-  CallMethod(&y, &Y::f);

-  CallMethod(&y, &Y::f, 20);

-  CallMethod(&y, &Y::f, static_cast<unsigned int>(10), &x);

-  CallMethod(&y, &Y::f, true, 'a', static_cast<long*>(0));

-

-  Z z;

-  CallMethod(&z,

-             &Z::f,

-             'a',

-             static_cast<signed char>('a'),

-             static_cast<unsigned char>('a'));

-

-

-  CallMethod(&z, &Z::f, &y);

-

-  // Does not compile: template parameter 'P' is ambiguous

-  // const Y cy;

-  // CallMethod(&z, &Z::f, &cy);

-

-  CallMethod(&z, &Z::m);

-

-  // Does not compile: template parameter 'T' is ambiguous

-  // const Z cz;

-  // CallMethod(&cz, &Z::m);

-

-  // Does not compile: cannot convert from 'const Z *' to 'Z *const '

-  // const Z cz;

-  // CallMethod<const Z, void>(&cz, &Z::m);

-

-  CString msg(_T("test"));

-  CallFunction(Print, "test");

-  CallFunction(Print1, &msg);

-}

-

-class RuntimeTest : public Runnable {

- protected:

-  virtual void Run();

-};

-

-void RuntimeTest::Run() {

-  Test test;

-  ASSERT_EQ(CallMethod(&test, &Test::Add, 10, 20), 30);

-

-  int sum(0);

-  CallMethod(&test, &Test::Add, -10, 20, &sum);

-  ASSERT_EQ(sum, 10);

-

-  {

-  ASSERT_EQ(CallFunction(Add, long(10), long(20)), 30);

-

-  long sum = 0;

-  CallFunction(Add, long(10), long(-20), &sum);

-  ASSERT_EQ(sum, -10);

-  }

-}

-

-

-class AsyncTest : public Runnable {

- protected:

-  virtual void Run();

-};

-

-void AsyncTest::Run() {

-  static X x;

-  static Y y;

-

-  CallFunctionAsync(X::g);

-  CallFunctionAsync(X::g, 10);

-  CallFunctionAsync(X::g, static_cast<unsigned int>(10), &x);

-  CallFunctionAsync(X::g, true, 'a', static_cast<long*>(0));

-

-  CallFunctionAsync(Y::g);

-  CallFunctionAsync(Y::g, 10);

-  CallFunctionAsync(Y::g, static_cast<unsigned int>(10), &x);

-  CallFunctionAsync(Y::g, true, 'a', static_cast<long*>(0));

-

-  CallMethodAsync(&x, &X::f);

-  CallMethodAsync(&x, &X::f, 10);

-  CallMethodAsync(&x, &X::f, static_cast<unsigned int>(10), &x);

-  CallMethodAsync(&x, &X::f, true, 'a', static_cast<long*>(0));

-

-  CallMethodAsync(&y, &Y::f);

-  CallMethodAsync(&y, &Y::f, 20);

-  CallMethodAsync(&y, &Y::f, static_cast<unsigned int>(10), &x);

-  CallMethodAsync(&y, &Y::f, true, 'a', static_cast<long*>(0));

-

-  static Z z;

-  CallMethodAsync(&z,

-                  &Z::f,

-                  'a',

-                  static_cast<signed char>('a'),

-                  static_cast<unsigned char>('a'));

-

-

-  CallMethodAsync(&z, &Z::f, &y);

-

-  // Does not compile: template parameter 'P' is ambiguous

-  // const Y cy;

-  // CallMethod(&z, &Z::f, &cy);

-

-  CallMethodAsync(&z, &Z::m);

-

-  // Does not compile: template parameter 'T' is ambiguous

-  // const Z cz;

-  // CallMethod(&cz, &Z::m);

-

-  // Does not compile: cannot convert from 'const Z *' to 'Z *const '

-  // const Z cz;

-  // CallMethod<const Z, void>(&cz, &Z::m);

-

-  CString msg(_T("test"));

-  CallFunctionAsync(Print, "test");

-  CallFunctionAsync(Print1, &msg);

-

-  WaitWithMessageLoopTimed(1000);

-}

-

-

-TEST(STATest, CompileTest) {

-  ASSERT_SUCCEEDED(InitializeApartment(0));

-

-  Thread t;

-  CompileTest compile_test;

-  t.Start(&compile_test);

-  EXPECT_TRUE(WaitWithMessageLoop(t.GetThreadHandle()));

-

-  ASSERT_SUCCEEDED(UninitializeApartment());

-}

-

-TEST(STATest, RuntimeTest) {

-  ASSERT_SUCCEEDED(InitializeApartment(0));

-

-  Thread t;

-  RuntimeTest runtime_test;

-  t.Start(&runtime_test);

-  EXPECT_TRUE(WaitWithMessageLoop(t.GetThreadHandle()));

-

-  ASSERT_SUCCEEDED(UninitializeApartment());

-}

-

-

-TEST(STATest, AsyncTest) {

-  ASSERT_SUCCEEDED(InitializeApartment(0));

-

-  Thread t;

-  AsyncTest async_test;

-  t.Start(&async_test);

-  EXPECT_TRUE(WaitWithMessageLoop(t.GetThreadHandle()));

-

-  ASSERT_SUCCEEDED(UninitializeApartment());

-}

-

-TEST(STATest, ApartmentRefCounting) {

-  // Check the reference counting is working.

-  ASSERT_SUCCEEDED(InitializeApartment(0));

-  ASSERT_SUCCEEDED(InitializeApartment(0));

-  ASSERT_SUCCEEDED(UninitializeApartment());

-  ASSERT_SUCCEEDED(UninitializeApartment());

-

-  // The call below will raise an assert in the the STA code.

-  ExpectAsserts expect_asserts;

-  ASSERT_EQ(E_UNEXPECTED, UninitializeApartment());

-}

-

-TEST(STATest, ScopedSTA) {

-  {

-    scoped_sta sta(0);

-    ASSERT_SUCCEEDED(sta.result());

-  }

-  {

-    scoped_sta sta(0);

-    ASSERT_SUCCEEDED(sta.result());

-  }

-  {

-    scoped_sta sta1(0);

-    scoped_sta sta2(0);

-    ASSERT_SUCCEEDED(sta1.result());

-    ASSERT_SUCCEEDED(sta2.result());

-  }

-

-  ExpectAsserts expect_asserts;

-  ASSERT_EQ(E_UNEXPECTED, UninitializeApartment());

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include <atlstr.h>
+#include "omaha/common/sta.h"
+#include "omaha/common/sta_call.h"
+#include "omaha/common/thread.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+class X {
+ public:
+  void f() {}
+  void f(int) {}
+  void f(unsigned int, X*) {}
+  void f(bool, char, long*) {}
+
+  static void g() {}
+  static void g(int) {}
+  static void g(unsigned int, X*) {}
+  static void g(bool, char, long*) {}
+};
+
+class Y {
+ public:
+  HRESULT f() { return S_OK; }
+  HRESULT f(int) { return S_OK; }
+  HRESULT f(unsigned int, X*) { return S_OK; }
+  HRESULT f(bool, char, long*) { return S_OK; }
+
+  static HRESULT g() { return S_OK; }
+  static HRESULT g(int) { return S_OK; }
+  static HRESULT g(unsigned int, X*) { return S_OK; }
+  static HRESULT g(bool, char, long*) { return S_OK; }
+};
+
+class Z {
+ public:
+  void f(char, signed char, unsigned char) {}
+
+  void f(Y*) {}
+  // void f(const Y*) {} // not supported !!!
+
+  void m() {}
+  void m() const {}
+};
+
+class Test {
+ public:
+  int Add(int i, int j) { return i + j; }
+  void Add(int i, int j, int* sum) { *sum = i + j; }
+};
+
+int Add(long i, long j) { return i + j; }
+void Add(long i, long j, long* sum) { *sum = i + j; }
+
+void Print(const char*) {}
+void Print1(CString*) {}
+
+}  // namespace
+
+class CompileTest : public Runnable {
+ protected:
+  virtual void Run();
+};
+
+void CompileTest::Run() {
+  X x;
+  Y y;
+
+  CallFunction(X::g);
+  CallFunction(X::g, 10);
+  CallFunction(X::g, static_cast<unsigned int>(10), &x);
+  CallFunction(X::g, true, 'a', static_cast<long*>(0));
+
+  CallFunction(Y::g);
+  CallFunction(Y::g, 10);
+  CallFunction(Y::g, static_cast<unsigned int>(10), &x);
+  CallFunction(Y::g, true, 'a', static_cast<long*>(0));
+
+  CallMethod(&x, &X::f);
+  CallMethod(&x, &X::f, 10);
+  CallMethod(&x, &X::f, static_cast<unsigned int>(10), &x);
+  CallMethod(&x, &X::f, true, 'a', static_cast<long*>(0));
+
+  CallMethod(&y, &Y::f);
+  CallMethod(&y, &Y::f, 20);
+  CallMethod(&y, &Y::f, static_cast<unsigned int>(10), &x);
+  CallMethod(&y, &Y::f, true, 'a', static_cast<long*>(0));
+
+  Z z;
+  CallMethod(&z,
+             &Z::f,
+             'a',
+             static_cast<signed char>('a'),
+             static_cast<unsigned char>('a'));
+
+
+  CallMethod(&z, &Z::f, &y);
+
+  // Does not compile: template parameter 'P' is ambiguous
+  // const Y cy;
+  // CallMethod(&z, &Z::f, &cy);
+
+  CallMethod(&z, &Z::m);
+
+  // Does not compile: template parameter 'T' is ambiguous
+  // const Z cz;
+  // CallMethod(&cz, &Z::m);
+
+  // Does not compile: cannot convert from 'const Z *' to 'Z *const '
+  // const Z cz;
+  // CallMethod<const Z, void>(&cz, &Z::m);
+
+  CString msg(_T("test"));
+  CallFunction(Print, "test");
+  CallFunction(Print1, &msg);
+}
+
+class RuntimeTest : public Runnable {
+ protected:
+  virtual void Run();
+};
+
+void RuntimeTest::Run() {
+  Test test;
+  ASSERT_EQ(CallMethod(&test, &Test::Add, 10, 20), 30);
+
+  int sum(0);
+  CallMethod(&test, &Test::Add, -10, 20, &sum);
+  ASSERT_EQ(sum, 10);
+
+  {
+  ASSERT_EQ(CallFunction(Add, long(10), long(20)), 30);
+
+  long sum = 0;
+  CallFunction(Add, long(10), long(-20), &sum);
+  ASSERT_EQ(sum, -10);
+  }
+}
+
+
+class AsyncTest : public Runnable {
+ protected:
+  virtual void Run();
+};
+
+void AsyncTest::Run() {
+  static X x;
+  static Y y;
+
+  CallFunctionAsync(X::g);
+  CallFunctionAsync(X::g, 10);
+  CallFunctionAsync(X::g, static_cast<unsigned int>(10), &x);
+  CallFunctionAsync(X::g, true, 'a', static_cast<long*>(0));
+
+  CallFunctionAsync(Y::g);
+  CallFunctionAsync(Y::g, 10);
+  CallFunctionAsync(Y::g, static_cast<unsigned int>(10), &x);
+  CallFunctionAsync(Y::g, true, 'a', static_cast<long*>(0));
+
+  CallMethodAsync(&x, &X::f);
+  CallMethodAsync(&x, &X::f, 10);
+  CallMethodAsync(&x, &X::f, static_cast<unsigned int>(10), &x);
+  CallMethodAsync(&x, &X::f, true, 'a', static_cast<long*>(0));
+
+  CallMethodAsync(&y, &Y::f);
+  CallMethodAsync(&y, &Y::f, 20);
+  CallMethodAsync(&y, &Y::f, static_cast<unsigned int>(10), &x);
+  CallMethodAsync(&y, &Y::f, true, 'a', static_cast<long*>(0));
+
+  static Z z;
+  CallMethodAsync(&z,
+                  &Z::f,
+                  'a',
+                  static_cast<signed char>('a'),
+                  static_cast<unsigned char>('a'));
+
+
+  CallMethodAsync(&z, &Z::f, &y);
+
+  // Does not compile: template parameter 'P' is ambiguous
+  // const Y cy;
+  // CallMethod(&z, &Z::f, &cy);
+
+  CallMethodAsync(&z, &Z::m);
+
+  // Does not compile: template parameter 'T' is ambiguous
+  // const Z cz;
+  // CallMethod(&cz, &Z::m);
+
+  // Does not compile: cannot convert from 'const Z *' to 'Z *const '
+  // const Z cz;
+  // CallMethod<const Z, void>(&cz, &Z::m);
+
+  CString msg(_T("test"));
+  CallFunctionAsync(Print, "test");
+  CallFunctionAsync(Print1, &msg);
+
+  WaitWithMessageLoopTimed(1000);
+}
+
+
+TEST(STATest, CompileTest) {
+  ASSERT_SUCCEEDED(InitializeApartment(0));
+
+  Thread t;
+  CompileTest compile_test;
+  t.Start(&compile_test);
+  EXPECT_TRUE(WaitWithMessageLoop(t.GetThreadHandle()));
+
+  ASSERT_SUCCEEDED(UninitializeApartment());
+}
+
+TEST(STATest, RuntimeTest) {
+  ASSERT_SUCCEEDED(InitializeApartment(0));
+
+  Thread t;
+  RuntimeTest runtime_test;
+  t.Start(&runtime_test);
+  EXPECT_TRUE(WaitWithMessageLoop(t.GetThreadHandle()));
+
+  ASSERT_SUCCEEDED(UninitializeApartment());
+}
+
+
+TEST(STATest, AsyncTest) {
+  ASSERT_SUCCEEDED(InitializeApartment(0));
+
+  Thread t;
+  AsyncTest async_test;
+  t.Start(&async_test);
+  EXPECT_TRUE(WaitWithMessageLoop(t.GetThreadHandle()));
+
+  ASSERT_SUCCEEDED(UninitializeApartment());
+}
+
+TEST(STATest, ApartmentRefCounting) {
+  // Check the reference counting is working.
+  ASSERT_SUCCEEDED(InitializeApartment(0));
+  ASSERT_SUCCEEDED(InitializeApartment(0));
+  ASSERT_SUCCEEDED(UninitializeApartment());
+  ASSERT_SUCCEEDED(UninitializeApartment());
+
+  // The call below will raise an assert in the the STA code.
+  ExpectAsserts expect_asserts;
+  ASSERT_EQ(E_UNEXPECTED, UninitializeApartment());
+}
+
+TEST(STATest, ScopedSTA) {
+  {
+    scoped_sta sta(0);
+    ASSERT_SUCCEEDED(sta.result());
+  }
+  {
+    scoped_sta sta(0);
+    ASSERT_SUCCEEDED(sta.result());
+  }
+  {
+    scoped_sta sta1(0);
+    scoped_sta sta2(0);
+    ASSERT_SUCCEEDED(sta1.result());
+    ASSERT_SUCCEEDED(sta2.result());
+  }
+
+  ExpectAsserts expect_asserts;
+  ASSERT_EQ(E_UNEXPECTED, UninitializeApartment());
+}
+
+}  // namespace omaha
+
diff --git a/common/static_assert.h b/common/static_assert.h
index 6bbac9f..b494742 100644
--- a/common/static_assert.h
+++ b/common/static_assert.h
@@ -1,45 +1,45 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// static_assert.h

-//

-// Compile-time asserts

-//

-// Based on the one from boost:

-// http://www.boost.org/boost/static_assert.hpp

-//

-// Usage:

-//

-// kStaticAssert(constant_boolean_expression);

-//

-// This can appear at file scope or within a block (anyplace a typedef

-// is OK).

-//

-// TODO(omaha): deprecate and replace with the static assert in base/basictypes

-#ifndef OMAHA_COMMON_STATIC_ASSERT_H_

-#define OMAHA_COMMON_STATIC_ASSERT_H_

-

-template <bool> struct STATIC_ASSERTION_FAILURE;

-

-template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };

-

-template<int> struct static_assert_test{};

-

-#define STATIC_ASSERT( B ) \

-typedef static_assert_test<\

-  sizeof(STATIC_ASSERTION_FAILURE< (bool)( B ) >)>\

-    static_assert_typedef_ ##  __LINE__

-

-#endif  // OMAHA_COMMON_STATIC_ASSERT_H_

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// static_assert.h
+//
+// Compile-time asserts
+//
+// Based on the one from boost:
+// http://www.boost.org/boost/static_assert.hpp
+//
+// Usage:
+//
+// kStaticAssert(constant_boolean_expression);
+//
+// This can appear at file scope or within a block (anyplace a typedef
+// is OK).
+//
+// TODO(omaha): deprecate and replace with the static assert in base/basictypes
+#ifndef OMAHA_COMMON_STATIC_ASSERT_H_
+#define OMAHA_COMMON_STATIC_ASSERT_H_
+
+template <bool> struct STATIC_ASSERTION_FAILURE;
+
+template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
+
+template<int> struct static_assert_test{};
+
+#define STATIC_ASSERT( B ) \
+typedef static_assert_test<\
+  sizeof(STATIC_ASSERTION_FAILURE< (bool)( B ) >)>\
+    static_assert_typedef_ ##  __LINE__
+
+#endif  // OMAHA_COMMON_STATIC_ASSERT_H_
diff --git a/common/store_watcher.h b/common/store_watcher.h
index 9300b86..d630540 100644
--- a/common/store_watcher.h
+++ b/common/store_watcher.h
@@ -1,59 +1,59 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// A simple interface for monitoring changes

-// happening to a store.

-//

-#ifndef OMAHA_COMMON_STORE_WATCHER_H_

-#define OMAHA_COMMON_STORE_WATCHER_H_

-

-#include "omaha/common/synchronized.h"

-

-namespace omaha {

-

-// Allows for monitoring changes happening to a store

-// (independant of what the underlying store is).

-class StoreWatcher {

- public:

-  StoreWatcher() {}

-  virtual ~StoreWatcher() {}

-

-  // Called to create/reset the event that gets signaled

-  // any time the store changes.  Access the created

-  // event using change_event().

-  virtual HRESULT EnsureEventSetup() = 0;

-

-  // Indicates if any changes have occured

-  bool HasChangeOccurred() const {

-    return IsHandleSignaled(change_event());

-  }

-

-  // Get the event that is signaled on store changes.

-  // Note:

-  //   * This event will remain constant until the class is destroyed.

-  //   * One should call EnsureEventSetup to set-up the event.

-  //   * The event is only signaled on the next change and remains signaled.

-  //     Do not call ::ResetEvent(). Call EnsureEventSetup() to reset

-  //     the event and wait for more changes.

-  virtual HANDLE change_event() const = 0;

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(StoreWatcher);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_STORE_WATCHER_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// A simple interface for monitoring changes
+// happening to a store.
+//
+#ifndef OMAHA_COMMON_STORE_WATCHER_H_
+#define OMAHA_COMMON_STORE_WATCHER_H_
+
+#include "omaha/common/synchronized.h"
+
+namespace omaha {
+
+// Allows for monitoring changes happening to a store
+// (independant of what the underlying store is).
+class StoreWatcher {
+ public:
+  StoreWatcher() {}
+  virtual ~StoreWatcher() {}
+
+  // Called to create/reset the event that gets signaled
+  // any time the store changes.  Access the created
+  // event using change_event().
+  virtual HRESULT EnsureEventSetup() = 0;
+
+  // Indicates if any changes have occured
+  bool HasChangeOccurred() const {
+    return IsHandleSignaled(change_event());
+  }
+
+  // Get the event that is signaled on store changes.
+  // Note:
+  //   * This event will remain constant until the class is destroyed.
+  //   * One should call EnsureEventSetup to set-up the event.
+  //   * The event is only signaled on the next change and remains signaled.
+  //     Do not call ::ResetEvent(). Call EnsureEventSetup() to reset
+  //     the event and wait for more changes.
+  virtual HANDLE change_event() const = 0;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(StoreWatcher);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_STORE_WATCHER_H_
diff --git a/common/string.cc b/common/string.cc
index 665ba2f..9e9b63d 100644
--- a/common/string.cc
+++ b/common/string.cc
@@ -1,3345 +1,3345 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/string.h"

-

-#include <wininet.h>        // For INTERNET_MAX_URL_LENGTH.

-#include <algorithm>

-#include <cstdlib>

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/localization.h"

-#include "omaha/common/logging.h"

-

-namespace omaha {

-

-namespace {

-// Testing shows that only the following ASCII characters are

-// considered spaces by GetStringTypeA: 9-13, 32, 160.

-// Rather than call GetStringTypeA with no locale, as we used to,

-// we look up the values directly in a precomputed array.

-

-SELECTANY byte spaces[256] = {

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  // 0-9

-  1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 10-19

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 20-29

-  0, 0, 1, 0, 0, 0, 0, 0, 0, 0,  // 30-39

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 40-49

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 50-59

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 60-69

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 70-79

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 80-89

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 90-99

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 100-109

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 110-119

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 120-129

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 130-139

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 140-149

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 150-159

-  1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 160-169

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 170-179

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 180-189

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 190-199

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 200-209

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 210-219

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 220-229

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 230-239

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 240-249

-  0, 0, 0, 0, 0, 1,              // 250-255

-};

-}  // namespace

-

-const TCHAR* const kFalse = _T("false");

-const TCHAR* const kTrue  = _T("true");

-

-bool IsSpaceW(WCHAR c) {

-  // GetStringTypeW considers these characters to be spaces:

-  // 9-13, 32, 133, 160, 5760, 8192-8203, 8232, 8233, 12288

-  if (c < 256)

-    return (c == 133 || IsSpaceA((char) (c & 0xff)));

-

-  return (c >= 8192 && c <= 8203) || c == 8232 ||

-    c == 8233 || c == 12288;

-}

-

-bool IsSpaceA(char c) {

-  return spaces[static_cast<unsigned char>(c)] == 1;

-}

-

-int TrimCString(CString &s) {

-  int len = Trim(s.GetBuffer());

-  s.ReleaseBufferSetLength(len);

-  return len;

-}

-

-void MakeLowerCString(CString & s) {

-  int len = s.GetLength();

-  String_FastToLower(s.GetBuffer());

-  s.ReleaseBufferSetLength(len);

-}

-

-int Trim(TCHAR *s) {

-  ASSERT(s, (L""));

-

-  // First find end of leading spaces

-  TCHAR *start = s;

-  while (*start) {

-    if (!IsSpace(*start))

-      break;

-    ++start;

-  }

-

-  // Now search for the end, remembering the start of the last spaces

-  TCHAR *end = start;

-  TCHAR *last_space = end;

-  while (*end) {

-    if (!IsSpace(*end))

-      last_space = end + 1;

-    ++end;

-  }

-

-  // Copy the part we want

-  int len = last_space - start;

-  // lint -e{802}  Conceivably passing a NULL pointer

-  memmove(s, start, len * sizeof(TCHAR));

-

-  // 0 terminate

-  s[len] = 0;

-

-  return len;

-}

-

-void TrimString(CString& s, const TCHAR* delimiters) {

-  s = s.Trim(delimiters);

-}

-

-// Strip the first token from the front of argument s.  A token is a

-// series of consecutive non-blank characters - unless the first

-// character is a double-quote ("), in that case the token is the full

-// quoted string

-CString StripFirstQuotedToken(const CString& s) {

-  const int npos = -1;

-

-  // Make a writeable copy

-  CString str(s);

-

-  // Trim any surrounding blanks (and tabs, for the heck of it)

-  TrimString(str, L" \t");

-

-  // Too short to have a second token

-  if (str.GetLength() <= 1)

-    return L"";

-

-  // What kind of token are we stripping?

-  if (str[0] == L'\"') {

-    // Remove leading quoting string

-    int i = str.Find(L"\"", 1);

-    if (i != npos)

-      i++;

-    return str.Mid(i);

-  } else {

-    // Remove leading token

-    int i = str.FindOneOf(L" \t");

-    if (i != npos)

-      i++;

-    return str.Mid(i);

-  }

-}

-

-// A block of text to separate lines, and back

-void TextToLines(const CString& text, const TCHAR* delimiter, std::vector<CString>* lines) {

-  ASSERT(delimiter, (L""));

-  ASSERT(lines, (L""));

-

-  size_t delimiter_len = ::lstrlen(delimiter);

-  int b = 0;

-  int e = 0;

-

-  for (b = 0; e != -1 && b < text.GetLength(); b = e + delimiter_len) {

-    e = text.Find(delimiter, b);

-    if (e != -1) {

-      ASSERT1(e - b > 0);

-      lines->push_back(text.Mid(b, e - b));

-    } else {

-      lines->push_back(text.Mid(b));

-    }

-  }

-}

-

-void LinesToText(const std::vector<CString>& lines, const TCHAR* delimiter, CString* text) {

-  ASSERT(delimiter, (L""));

-  ASSERT(text, (L""));

-

-  size_t delimiter_len = ::lstrlen(delimiter);

-  size_t len = 0;

-  for (size_t i = 0; i < lines.size(); ++i) {

-    len += lines[i].GetLength() + delimiter_len;

-  }

-  text->Empty();

-  text->Preallocate(len);

-  for (std::vector<CString>::size_type i = 0; i < lines.size(); ++i) {

-    text->Append(lines[i]);

-    if (delimiter_len) {

-      text->Append(delimiter);

-    }

-  }

-}

-

-int CleanupWhitespaceCString(CString &s) {

-  int len = CleanupWhitespace(s.GetBuffer());

-  s.ReleaseBufferSetLength(len);

-  return len;

-}

-

-int CleanupWhitespace(TCHAR *str) {

-  ASSERT(str, (L""));

-

-  TCHAR *src      = str;

-  TCHAR *dest     = str;

-  int    spaces   = 0;

-  bool   at_start = true;

-  while (true) {

-    // At end of string?

-    TCHAR c = *src;

-    if (0 == c)

-      break;

-

-    // Look for whitespace; copy it over if not whitespace

-    if (IsSpace(c)) {

-      ++spaces;

-    }

-    else {

-      *dest++ = c;

-      at_start = false;

-      spaces = 0;

-    }

-

-    // Write only first consecutive space (but skip space at start)

-    if (1 == spaces && !at_start)

-      *dest++ = ' ';

-

-    ++src;

-  }

-

-  // Remove trailing space, if any

-  if (dest > str && *(dest - 1) == L' ')

-    --dest;

-

-  // 0-terminate

-  *dest = 0;

-

-  return dest - str;

-}

-

-// Take 1 single hexadecimal "digit" (as a character) and return its decimal value

-// Returns -1 if given invalid hex digit

-int HexDigitToDec(const TCHAR digit) {

-  if (digit >= L'A' && digit <= L'F')

-    return 10 + (digit - L'A');

-  else if (digit >= L'a' && digit <= L'f')

-    return 10 + (digit - L'a');

-  else if (digit >= L'0' && digit <= L'9')

-    return (digit - L'0');

-  else

-    return -1;

-}

-

-// Convert the 2 hex chars at positions <pos> and <pos>+1 in <s> to a char (<char_out>)

-// Note: scanf was giving me troubles, so here's the manual version

-// Extracted char gets written to <char_out>, which must be allocated by

-// the caller; return true on success or false if parameters are incorrect

-// or string does not have 2 hex digits at the specified position

-// NOTE: <char_out> is NOT a string, just a pointer to a char for the result

-bool ExtractChar(const CString & s, int pos, unsigned char * char_out) {

-  // char_out may be NULL

-

-  if (s.GetLength() < pos + 1) {

-    return false;

-  }

-

-  if (pos < 0 || NULL == char_out) {

-    ASSERT(0, (_T("invalid params: pos<0 or char_out is NULL")));

-    return false;

-  }

-

-  TCHAR c1 = s.GetAt(pos);

-  TCHAR c2 = s.GetAt(pos+1);

-

-  int p1 = HexDigitToDec(c1);

-  int p2 = HexDigitToDec(c2);

-

-  if (p1 == -1 || p2 == -1) {

-    return false;

-  }

-

-  *char_out = (unsigned char)(p1 * 16 + p2);

-  return true;

-}

-

-WCHAR *ToWide (const char *s, int len) {

-    ASSERT (s, (L""));

-    WCHAR *w = new WCHAR [len+1]; if (!w) { return NULL; }

-    // int rc = MultiByteToWideChar (CP_ACP, 0, s.GetString(), (int)s.GetLength()+1, w, s.GetLength()+1);

-    // TODO(omaha): why would it ever be the case that rc > len?

-    int rc = MultiByteToWideChar (CP_ACP, 0, s, len, w, len);

-    if (rc > len) { delete [] w; return NULL; }

-    // ASSERT (rc <= len, (L""));

-    w[rc]=L'\0';

-    return w;

-}

-

-const byte *BufferContains (const byte *buf, uint32 buf_len, const byte *data, uint32 data_len) {

-  ASSERT(data, (L""));

-  ASSERT(buf, (L""));

-

-  for (uint32 i = 0; i < buf_len; i++) {

-    uint32 j = i;

-    uint32 k = 0;

-    uint32 len = 0;

-    while (j < buf_len && k < data_len && buf[j++] == data[k++]) { len++; }

-    if (len == data_len) { return buf + i; }

-  }

-  return 0;

-}

-

-// Converting the Ansi Multibyte String into unicode string. The multibyte

-// string is encoded using the specified codepage.

-// The code is pretty much like the U2W function, except the codepage can be

-// any valid windows CP.

-BOOL AnsiToWideString(const char *from, int length, UINT codepage, CString *to) {

-  ASSERT(from, (L""));

-  ASSERT(to, (L""));

-  ASSERT1(length >= -1);

-  // Figure out how long the string is

-  int req_chars = MultiByteToWideChar(codepage, 0, from, length, NULL, 0);

-

-  if (req_chars <= 0) {

-    UTIL_LOG(LEVEL_WARNING, (_T("MultiByteToWideChar Failed ")));

-    *to = AnsiToWideString(from, length);

-    return FALSE;

-  }

-

-  TCHAR *buffer = to->GetBufferSetLength(req_chars);

-  int conv_chars = MultiByteToWideChar(codepage, 0, from, length, buffer, req_chars);

-  if (conv_chars == 0) {

-    UTIL_LOG(LEVEL_WARNING, (_T("MultiByteToWideChar Failed ")));

-    to->ReleaseBuffer(0);

-    *to = AnsiToWideString(from, length);

-    return FALSE;

-  }

-

-  // Something truly horrible happened.

-  ASSERT (req_chars == conv_chars, (L"MBToWide returned unexpected value: GetLastError()=%d",GetLastError()));

-  // If length was inferred, conv_chars includes the null terminator.

-  // Adjust the length here to remove null termination,

-  // because we use the length-qualified CString constructor,

-  // which automatically adds null termination given an unterminated array.

-  if (-1 == length) { --conv_chars; }

-  to->ReleaseBuffer(conv_chars);

-  return TRUE;

-}

-

-// CStringW(const char* from) did not cast all character properly

-// so we write our own.

-CString AnsiToWideString(const char *from, int length) {

-  ASSERT(from, (L""));

-  ASSERT1(length >= -1);

-  if (length < 0)

-    length = strlen(from);

-  CString to;

-  TCHAR *buffer = to.GetBufferSetLength(length);

-  for (int i = 0; i < length; ++i)

-      buffer[i] = static_cast<UINT8>(from[i]);

-  to.ReleaseBuffer(length);

-  return to;

-}

-

-

-// Transform a unicode string into UTF8, as represented in an ASCII string

-CStringA WideToUtf8(const CString& w) {

-  // Add a cutoff. If it's all ascii, convert it directly

-  const TCHAR* input = static_cast<const TCHAR*>(w.GetString());

-  int input_len = w.GetLength(), i;

-  for (i = 0; i < input_len; ++i) {

-    if (input[i] > 127) {

-      break;

-    }

-  }

-

-  // If we made it to the end without breaking, then it's all ANSI, so do a quick convert

-  if (i == input_len) {

-    return WideToAnsiDirect(w);

-  }

-

-  // Figure out how long the string is

-  int req_bytes = ::WideCharToMultiByte(CP_UTF8, 0, w, -1, NULL, 0, NULL, NULL);

-

-  scoped_array<char> utf8_buffer(new char[req_bytes]);

-

-  int conv_bytes = ::WideCharToMultiByte(CP_UTF8, 0, w, -1, utf8_buffer.get(), req_bytes, NULL, NULL);

-  ASSERT1(req_bytes == conv_bytes);

-

-  // conv_bytes includes the null terminator, when we read this in, don't read the terminator

-  CStringA out(utf8_buffer.get(), conv_bytes - 1);

-

-  return out;

-}

-

-CString Utf8ToWideChar(const char* utf8, uint32 num_bytes) {

-  ASSERT1(utf8);

-  if (num_bytes == 0) {

-    // It's OK to use lstrlenA to count the number of characters in utf8 because

-    // UTF-8 encoding has the nice property of not having any embedded NULLs.

-    num_bytes = lstrlenA(utf8);

-  }

-

-  uint32 number_of_wide_chars = ::MultiByteToWideChar(CP_UTF8, 0, utf8, num_bytes, NULL, 0);

-  number_of_wide_chars += 1;  // make room for NULL terminator

-

-  CString ret_string;

-  TCHAR* buffer = ret_string.GetBuffer(number_of_wide_chars);

-  DWORD number_of_characters_copied = ::MultiByteToWideChar(CP_UTF8, 0, utf8, num_bytes, buffer, number_of_wide_chars);

-  ASSERT1(number_of_characters_copied == number_of_wide_chars - 1);

-  buffer[number_of_wide_chars - 1] = _T('\0');  // ensure there is a NULL terminator

-  ret_string.ReleaseBuffer();

-

-  // Strip the byte order marker if there is one in the document.

-  if (ret_string[0] == kUnicodeBom) {

-    ret_string = ret_string.Right(ret_string.GetLength() - 1);

-  }

-

-  if (number_of_characters_copied > 0) {

-    return ret_string;

-  }

-

-  // Failure case

-  return _T("");

-}

-

-CString Utf8BufferToWideChar(const std::vector<uint8>& buffer) {

-  CString result;

-  if (!buffer.empty()) {

-    result = Utf8ToWideChar(

-        reinterpret_cast<const char*>(&buffer.front()), buffer.size());

-  }

-  return result;

-}

-

-CString AbbreviateString (const CString & title, int32 max_len) {

-    ASSERT (max_len, (L""));

-    CString s(title);

-    TrimCString(s);  // remove whitespace at start/end

-    if (s.GetLength() > max_len) {

-        s = s.Left (max_len - 2);

-        CString orig(s);

-        // remove partial words

-        while (s.GetLength() > 1 && !IsSpace(s[s.GetLength()-1])) { s = s.Left (s.GetLength() - 1); }

-        // but not if it would make the string very short

-        if (s.GetLength() < max_len / 2) { s = orig; }

-        s += _T("..");

-        }

-

-    return s;

-}

-

-CString GetAbsoluteUri(const CString& uri) {

-  int i = String_FindString(uri, _T("://"));

-  if (i==-1) return uri;

-

-  // add trailing / if none exists

-  int j = String_FindChar(uri, L'/',i+3);

-  if (j==-1) return (uri+NOTRANSL(_T("/")));

-

-  // remove duplicate trailing slashes

-  int len = uri.GetLength();

-  if (len > 1 && uri.GetAt(len-1) == '/' && uri.GetAt(len-2) == '/') {

-    CString new_uri(uri);

-    int new_len = new_uri.GetLength();

-    while (new_len > 1 && new_uri.GetAt(new_len-1) == '/' && new_uri.GetAt(new_len-2) == '/') {

-      new_len--;

-      new_uri = new_uri.Left(new_len);

-    }

-    return new_uri;

-  }

-  else return uri;

-}

-

-// requires that input have a PROTOCOL (http://) for proper behavior

-// items with the "file" protocol are returned as is (what is the hostname in that case? C: ? doesn't make sense)

-// TODO(omaha): loosen requirement

-// includes http://, e.g. http://www.google.com/

-CString GetUriHostName(const CString& uri, bool strip_leading) {

-  if (String_StartsWith(uri,NOTRANSL(_T("file:")),true)) return uri;

-

-  // correct any "errors"

-  CString s(GetAbsoluteUri(uri));

-

-  // Strip the leading "www."

-  if (strip_leading)

-  {

-    int index_www = String_FindString(s, kStrLeadingWww);

-    if (index_www != -1)

-      ReplaceCString (s, kStrLeadingWww, _T(""));

-  }

-

-  int i = String_FindString(s, _T("://"));

-  if(i==-1) return uri;

-  int j = String_FindChar(s, L'/',i+3);

-  if(j==-1) return uri;

-  return s.Left(j+1);

-}

-

-// requires that input have a PROTOCOL (http://) for proper behavior

-// TODO(omaha): loosen requirement

-// removes the http:// and the extra slash '/' at the end.

-// http://www.google.com/ -> www.google.com (or google.com if strip_leading = true)

-CString GetUriHostNameHostOnly(const CString& uri, bool strip_leading) {

-  CString s(GetUriHostName(uri,strip_leading));

-

-  // remove protocol

-  int i = String_FindString (s, _T("://"));

-  if(i==-1) return s;

-  CString ss(s.Right (s.GetLength() - i-3));

-

-  // remove the last '/'

-  int j = ss.ReverseFind('/');

-  if (j == -1) return ss;

-  return ss.Left(j);

-}

-

-CString AbbreviateUri(const CString& uri, int32 max_len) {

-  ASSERT1(max_len);

-  ASSERT1(!uri.IsEmpty());

-

-  CString s(uri);

-  VERIFY1(String_FindString (s, _T("://")));

-

-  TrimCString(s);

-  // SKIP_LOC_BEGIN

-  RemoveFromStart (s, _T("ftp://"), false);

-  RemoveFromStart (s, _T("http://"), false);

-  RemoveFromStart (s, _T("https://"), false);

-  RemoveFromStart (s, _T("www."), false);

-  RemoveFromStart (s, _T("ftp."), false);

-  RemoveFromStart (s, _T("www-"), false);

-  RemoveFromStart (s, _T("ftp-"), false);

-  RemoveFromEnd (s, _T(".htm"));

-  RemoveFromEnd (s, _T(".html"));

-  RemoveFromEnd (s, _T(".asp"));

-  // SKIP_LOC_END

-  if (s.GetLength() > max_len) {

-    // try to keep the portion after the last /

-    int32 last_slash = s.ReverseFind ((TCHAR)'/');

-    CString after_last_slash;

-    if (last_slash == -1) { after_last_slash = _T(""); }

-    else { after_last_slash = s.Right (uri.GetLength() - last_slash - 1); }

-    if (after_last_slash.GetLength() > max_len / 2) {

-        after_last_slash = after_last_slash.Right (max_len / 2);

-    }

-    s = s.Left (max_len - after_last_slash.GetLength() - 2);

-    s += "..";

-    s += after_last_slash;

-  }

-  return s;

-}

-

-// normalized version of a URI intended to map duplicates to the same string

-// the normalized URI is not a valid URI

-CString NormalizeUri (const CString & uri) {

-  CString s(uri);

-  TrimCString(s);

-  MakeLowerCString(s);

-  // SKIP_LOC_BEGIN

-  ReplaceCString (s, _T(":80"), _T(""));

-

-  RemoveFromEnd (s, _T("/index.html"));

-  RemoveFromEnd (s, _T("/welcome.html"));  // old netscape standard

-  RemoveFromEnd (s, _T("/"));

-

-  RemoveFromStart (s, _T("ftp://"), false);

-  RemoveFromStart (s, _T("http://"), false);

-  RemoveFromStart (s, _T("https://"), false);

-  RemoveFromStart (s, _T("www."), false);

-  RemoveFromStart (s, _T("ftp."), false);

-  RemoveFromStart (s, _T("www-"), false);

-  RemoveFromStart (s, _T("ftp-"), false);

-

-  ReplaceCString (s, _T("/./"), _T("/"));

-  // SKIP_LOC_END

-

-  // TODO(omaha):

-  // fixup URLs like a/b/../../c

-  // while ($s =~ m!\/\.\.\!!) {

-  //    $s =~ s!/[^/]*/\.\./!/!;

-  //    }

-

-  // TODO(omaha):

-  // unescape characters

-  // Note from RFC1630:  "Sequences which start with a percent sign

-  // but are not followed by two hexadecimal characters are reserved

-  // for future extension"

-  // $str =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg if defined $str;

-

-  return s;

-}

-

-CString RemoveInternetProtocolHeader (const CString& url) {

-  int find_colon_slash_slash = String_FindString(url, NOTRANSL(L"://"));

-  if( find_colon_slash_slash != -1 ) {

-    // remove PROTOCOL://

-    return url.Right(url.GetLength() - find_colon_slash_slash - 3);

-  } else if (String_StartsWith(url, NOTRANSL(L"mailto:"), true)) {

-    // remove "mailto:"

-    return url.Right(url.GetLength() - 7);

-  } else {

-    // return as is

-    return url;

-  }

-}

-

-void RemoveFromStart (CString & s, const TCHAR* remove, bool ignore_case) {

-  ASSERT(remove, (L""));

-

-  // Remove the characters if it is the prefix

-  if (String_StartsWith(s, remove, ignore_case))

-    s.Delete(0, lstrlen(remove));

-}

-

-bool String_EndsWith(const TCHAR *str, const TCHAR *end_str, bool ignore_case) {

-  ASSERT(end_str, (L""));

-  ASSERT(str, (L""));

-

-  int str_len = lstrlen(str);

-  int end_len = lstrlen(end_str);

-

-  // Definitely false if the suffix is longer than the string

-  if (end_len > str_len)

-    return false;

-

-  const TCHAR *str_ptr = str + str_len;

-  const TCHAR *end_ptr = end_str + end_len;

-

-  while (end_ptr >= end_str) {

-    // Check for matching characters

-    TCHAR c1 = *str_ptr;

-    TCHAR c2 = *end_ptr;

-

-    if (ignore_case) {

-      c1 = Char_ToLower(c1);

-      c2 = Char_ToLower(c2);

-    }

-

-    if (c1 != c2)

-      return false;

-

-    --str_ptr;

-    --end_ptr;

-  }

-

-  // if we haven't failed out, it must be ok!

-  return true;

-}

-

-CString String_MakeEndWith(const TCHAR* str, const TCHAR* end_str, bool ignore_case) {

-  if (String_EndsWith(str, end_str, ignore_case)) {

-    return str;

-  } else {

-    CString r(str);

-    r += end_str;

-    return r;

-  }

-}

-

-void RemoveFromEnd (CString & s, const TCHAR* remove) {

-  ASSERT(remove, (L""));

-

-  // If the suffix is shorter than the string, don't bother

-  int remove_len = lstrlen(remove);

-  if (s.GetLength() < remove_len) return;

-

-  // If the suffix is equal

-  int suffix_begin = s.GetLength() - remove_len;

-  if (0 == lstrcmp(s.GetString() + suffix_begin, remove))

-    s.Delete(suffix_begin, remove_len);

-}

-

-CString ElideIfNeeded (const CString & input_string, int max_len, int min_len) {

-  ASSERT (min_len <= max_len, (L""));

-  ASSERT (max_len >= TSTR_SIZE(kEllipsis)+1, (L""));

-  ASSERT (min_len >= TSTR_SIZE(kEllipsis)+1, (L""));

-

-  CString s = input_string;

-

-  s.TrimRight();

-  if (s.GetLength() > max_len) {

-    int truncate_at = max_len - TSTR_SIZE(kEllipsis);

-    // find first space going backwards from character one after the truncation point

-    while (truncate_at >= min_len && !IsSpace(s.GetAt(truncate_at)))

-      truncate_at--;

-

-    // skip the space(s)

-    while (truncate_at >= min_len && IsSpace(s.GetAt(truncate_at)))

-      truncate_at--;

-

-    truncate_at++;

-

-    if (truncate_at <= min_len || truncate_at > (max_len - static_cast<int>(TSTR_SIZE(kEllipsis)))) {

-      // we weren't able to break at a word boundary, may as well use more of the string

-      truncate_at = max_len - TSTR_SIZE(kEllipsis);

-

-      // skip space(s)

-      while (truncate_at > 0 && IsSpace(s.GetAt(truncate_at-1)))

-        truncate_at--;

-    }

-

-    s = s.Left(truncate_at);

-    s += kEllipsis;

-  }

-

-  UTIL_LOG(L6, (L"elide (%d %d) %s -> %s", min_len, max_len, input_string, s));

-  return s;

-}

-

-// these functions untested

-// UTF8 parameter supported on XP/2000 only

-HRESULT AnsiToUTF8 (char * src, int src_len, char * dest, int *dest_len) {

-  ASSERT (dest_len, (L""));

-  ASSERT (dest, (L""));

-  ASSERT (src, (L""));

-

-  // First use MultiByteToWideChar(CP_UTF8, ...) to convert to Unicode

-  // then use WideCharToMultiByte to convert from Unicode to UTF8

-  WCHAR *unicode = new WCHAR [(src_len + 1) * sizeof (TCHAR)]; ASSERT (unicode, (L""));

-  int chars_written = MultiByteToWideChar (CP_ACP, 0, src, src_len, unicode, src_len);

-  ASSERT (chars_written == src_len, (L""));

-  char *unmappable = " ";

-  BOOL unmappable_characters = false;

-  *dest_len = WideCharToMultiByte (CP_UTF8, 0, unicode, chars_written, dest, *dest_len, unmappable, &unmappable_characters);

-  delete [] unicode;

-  return S_OK;

-}

-

-// Convert Wide to ANSI directly. Use only when it is all ANSI

-CStringA WideToAnsiDirect(const CString & in) {

-  int in_len = in.GetLength();

-  const TCHAR * in_buf = static_cast<const TCHAR*>(in.GetString());

-

-  CStringA out;

-  unsigned char * out_buf = (unsigned char *)out.GetBufferSetLength(in_len);

-

-  for(int i = 0; i < in_len; ++i)

-    out_buf[i] = static_cast<unsigned char>(in_buf[i]);

-

-  out.ReleaseBuffer(in_len);

-  return out;

-}

-

-HRESULT UCS2ToUTF8 (LPCWSTR src, int src_len, char * dest, int *dest_len) {

-  ASSERT(dest_len, (L""));

-  ASSERT(dest, (L""));

-

-  *dest_len = WideCharToMultiByte (CP_UTF8, 0, src, src_len, dest, *dest_len, NULL,NULL);

-  return S_OK;

-}

-

-HRESULT UTF8ToUCS2 (const char * src, int src_len, LPWSTR dest, int *dest_len) {

-  ASSERT (dest_len, (L""));

-  ASSERT (src, (L""));

-

-  *dest_len = MultiByteToWideChar (CP_UTF8, 0, src, src_len, dest, *dest_len);

-  ASSERT (*dest_len == src_len, (L""));

-  return S_OK;

-}

-

-HRESULT UTF8ToAnsi (char * src, int, char * dest, int *dest_len) {

-  ASSERT(dest_len, (L""));

-  ASSERT(dest, (L""));

-  ASSERT(src, (L""));

-

-  src; dest; dest_len;  // unreferenced formal parameter

-

-  // First use MultiByteToWideChar(CP_UTF8, ...) to convert to Unicode

-  // then use WideCharToMultiByte to convert from Unicode to ANSI

-  return E_FAIL;

-}

-

-// clean up a string so it can be included within a JavaScript string

-// mainly involves escaping characters

-CString SanitizeString(const CString & in, DWORD mode) {

-  CString out(in);

-

-  if (mode & kSanHtml) {

-    // SKIP_LOC_BEGIN

-    ReplaceCString(out, _T("&"), _T("&amp;"));

-    ReplaceCString(out, _T("<"), _T("&lt;"));

-    ReplaceCString(out, _T(">"), _T("&gt;"));

-    // SKIP_LOC_END

-  }

-

-  if ((mode & kSanXml) == kSanXml) {

-    // SKIP_LOC_BEGIN

-    ReplaceCString(out, _T("'"), _T("&apos;"));

-    ReplaceCString(out, _T("\""), _T("&quot;"));

-    // SKIP_LOC_END

-  }

-

-  // Note that this SAN_JAVASCRIPT and kSanXml should not be used together.

-  ASSERT ((mode & (kSanJs | kSanXml)) != (kSanJs | kSanXml), (L""));

-

-  if ((mode & kSanJs) == kSanJs) {

-    // SKIP_LOC_BEGIN

-    ReplaceCString(out, _T("\\"), _T("\\\\"));

-    ReplaceCString(out, _T("\'"), _T("\\\'"));

-    ReplaceCString(out, _T("\""), _T("\\\""));

-    ReplaceCString(out, _T("\n"), _T(" "));

-    ReplaceCString(out, _T("\t"), _T(" "));

-    // SKIP_LOC_END

-  }

-

-  if ((mode & kSanHtmlInput) == kSanHtmlInput) {

-    // SKIP_LOC_BEGIN

-    ReplaceCString(out, _T("\""), _T("&quot;"));

-    ReplaceCString(out, _T("'"), _T("&#39;"));

-    // SKIP_LOC_END

-  }

-

-  return out;

-}

-

-// Bolds the periods used for abbreviation.  Call this after HighlightTerms.

-CString BoldAbbreviationPeriods(const CString & in) {

-  CString out(in);

-  CString abbrev;

-  for (int i = 0; i < kAbbreviationPeriodLength; ++i)

-    abbrev += _T(".");

-  ReplaceCString(out, abbrev, NOTRANSL(_T("<b>")) + abbrev + NOTRANSL(_T("</b>")));

-  return out;

-}

-

-// Unescape a escaped sequence leading by a percentage symbol '%',

-// and converted the unescaped sequence (in UTF8) into unicode.

-// Inputs:  src is the input string.

-//          pos is the starting position.

-// Returns: true if a EOS(null) char was encounted.

-//          out contains the unescaped and converted unicode string.

-//          consumed_length is how many bytes in the src string have been

-//          unescaped.

-// We can avoid the expensive UTF8 conversion step if there are no higher

-// ansi characters So if there aren't any, just convert it ANSI-to-WIDE

-// directly, which is cheaper.

-inline bool UnescapeSequence(const CString &src, int pos,

-                             CStringW *out, int *consumed_length) {

-  ASSERT1(out);

-  ASSERT1(consumed_length);

-

-  int length = src.GetLength();

-  // (input_len - pos) / 3 is enough for un-escaping the (%xx)+ sequences.

-  int max_dst_length = (length - pos) / 3;

-  scoped_array<char> unescaped(new char[max_dst_length]);

-  char *buf = unescaped.get();

-  if (buf == NULL) {  // no enough space ???

-    *consumed_length = 0;

-    return false;

-  }

-  char *dst = buf;

-  bool is_utf8 = false;

-  // It is possible that there is a null character '\0' in the sequence.

-  // Because the CStringT does't support '\0' in it, we stop

-  // parsing the input string when it is encounted.

-  bool eos_encounted = false;

-  uint8 ch;

-  int s = pos;

-  while (s + 2 < length && src[s] == '%' && !eos_encounted &&

-         ExtractChar(src, s + 1, &ch)) {

-    if (ch != 0)

-      *dst++ = ch;

-    else

-      eos_encounted = true;

-    if (ch >= 128)

-      is_utf8 = true;

-    s += 3;

-  }

-

-  ASSERT1(dst <= buf + max_dst_length);  // just to make sure

-

-  *consumed_length = s - pos;

-  if (is_utf8)

-    AnsiToWideString(buf, dst - buf, CP_UTF8, out);

-  else

-    *out = AnsiToWideString(buf, dst - buf);

-  return eos_encounted;

-}

-

-// There is an encoding called "URL-encoding". This function takes a URL-encoded string

-// and converts it back to the original representation

-// example: "?q=moon+doggy_%25%5E%26&" = "moon doggy_%^&"

-CString Unencode(const CString &input) {

-  const int input_len = input.GetLength();

-  const TCHAR *src = input.GetString();

-  // input_len is enough for containing the unencoded string.

-  CString out;

-  TCHAR *head = out.GetBuffer(input_len);

-  TCHAR *dst = head;

-  int s = 0;

-  bool eos_encounted = false;

-  bool is_utf8 = false;

-  CStringW fragment;

-  int consumed_length = 0;

-  while (s < input_len && !eos_encounted) {

-    switch (src[s]) {

-      case '+' :

-        *dst++ = ' ';

-        ASSERT1(dst <= head + input_len);

-        ++s;

-        break;

-      case '%' :

-        eos_encounted =

-          UnescapeSequence(input, s, &fragment, &consumed_length);

-        if (consumed_length > 0) {

-          s += consumed_length;

-          ASSERT1(dst + fragment.GetLength() <= head + input_len);

-          for (int i = 0; i < fragment.GetLength(); ++i)

-            *dst++ = fragment[i];

-        } else {

-          *dst++ = src[s++];

-          ASSERT1(dst <= head + input_len);

-        }

-        break;

-      default:

-        *dst++ = src[s];

-        ASSERT1(dst <= head + input_len);

-        ++s;

-    }

-  }

-  int out_len = dst - head;

-  out.ReleaseBuffer(out_len);

-  return out;

-}

-

-CString GetTextInbetween(const CString &input, const CString &start, const CString &end) {

-  int start_index = String_FindString(input, start);

-  if (start_index == -1)

-    return L"";

-

-  start_index += start.GetLength();

-  int end_index = String_FindString(input, end, start_index);

-  if (end_index == -1)

-    return L"";

-

-  return input.Mid(start_index, end_index - start_index);

-}

-

-// Given a string, get the parameter and url-unencode it

-CString GetParam(const CString & input, const CString & key) {

-  CString my_key(_T("?"));

-  my_key.Append(key);

-  my_key += L'=';

-

-  return Unencode(GetTextInbetween(input, my_key, NOTRANSL(L"?")));

-}

-

-// Get an xml-like field from a string

-CString GetField (const CString & input, const CString & field) {

-  CString start_field(NOTRANSL(_T("<")));

-  start_field += field;

-  start_field += L'>';

-

-  int32 start = String_FindString(input, start_field);

-  if (start == -1) { return _T(""); }

-  start += 2 + lstrlen (field);

-

-  CString end_field(NOTRANSL(_T("</")));

-  end_field += field;

-  end_field += L'>';

-

-  int32 end = String_FindString(input, end_field);

-  if (end == -1) { return _T(""); }

-

-  return input.Mid (start, end - start);

-}

-

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

-// Finds a whole word match in the query.

-// If the word has non-spaces either before or after, it will not qualify as

-//   a match.  i.e. "pie!" is not a match because of the exclamation point.

-// TODO(omaha): Add parameter that will consider punctuation acceptable.

-//

-// Optionally will look for a colon at the end.

-// If not found, return -1.

-int FindWholeWordMatch (const CString &query,

-  const CString &word_to_match,

-  const bool end_with_colon,

-  const int index_begin) {

-  if (word_to_match.IsEmpty()) {

-    return -1;

-  }

-

-  int index_word_begin = index_begin;

-

-  // Keep going until we find a whole word match, or the string ends.

-  do {

-    index_word_begin = String_FindString (query, word_to_match, index_word_begin);

-

-    if (-1 == index_word_begin) {

-      return index_word_begin;

-    }

-

-    // If it's not a whole word match, keep going.

-    if (index_word_begin > 0 &&

-      !IsSpaceW (query[index_word_begin - 1])) {

-      goto LoopEnd;

-    }

-

-    if (end_with_colon) {

-      int index_colon = String_FindChar (query, L':', index_word_begin);

-

-      // If there is no colon in the string, return now.

-      if (-1 == index_colon) {

-        return -1;

-      }

-

-      // If there is text between the end of the word and the colon, keep going.

-      if (index_colon - index_word_begin != word_to_match.GetLength()) {

-        goto LoopEnd;

-      }

-    } else {

-      // If there are more chars left after this word/phrase, and

-      // they are not spaces, return.

-      if (query.GetLength() > index_word_begin + word_to_match.GetLength() &&

-        !IsSpaceW (query.GetAt (index_word_begin + word_to_match.GetLength()))) {

-        goto LoopEnd;

-      }

-    }

-

-    // It fits all the requirements, so return the index to the beginning of the word.

-    return index_word_begin;

-

-LoopEnd:

-    ++index_word_begin;

-

-  } while (-1 != index_word_begin);

-

-  return index_word_begin;

-}

-

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

-// Do whole-word replacement in "str".

-void ReplaceWholeWord (const CString &string_to_replace,

-  const CString &replacement,

-  const bool trim_whitespace,

-  CString *str) {

-  ASSERT (str, (L"ReplaceWholeWord"));

-

-  if (string_to_replace.IsEmpty() || str->IsEmpty()) {

-    return;

-  }

-

-  int index_str = 0;

-  do {

-    index_str = FindWholeWordMatch (*str, string_to_replace, false, index_str);

-

-    if (-1 != index_str) {

-      // Get the strings before and after, and trim whitespace.

-      CString str_before_word(str->Left (index_str));

-      if (trim_whitespace) {

-        str_before_word.TrimRight();

-      }

-

-      CString str_after_word(str->Mid (index_str + string_to_replace.GetLength()));

-      if (trim_whitespace) {

-        str_after_word.TrimLeft();

-      }

-

-      *str = str_before_word + replacement + str_after_word;

-      index_str += replacement.GetLength() + 1;

-    }

-  } while (index_str != -1);

-}

-

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

-// Reverse (big-endian<->little-endian) the shorts that make up

-// Unicode characters in a byte array of Unicode chars

-HRESULT ReverseUnicodeByteOrder(byte* unicode_string, int size_in_bytes) {

-  ASSERT (unicode_string, (L""));

-

-  // If odd # of bytes, just leave the last one alone

-  for (int i = 0; i < size_in_bytes - 1; i += 2) {

-    byte b = unicode_string[i];

-    unicode_string[i] = unicode_string[i+1];

-    unicode_string[i+1] = b;

-  }

-

-  return S_OK;

-}

-

-// case insensitive strstr

-// adapted from http://c.snippets.org/snip_lister.php?fname=stristr.c

-const char *stristr(const char *string, const char *pattern)

-{

-  ASSERT (pattern, (L""));

-  ASSERT (string, (L""));

-  ASSERT (string && pattern, (L""));

-  char *pattern_ptr, *string_ptr;

-  const char *start;

-

-  for (start = string; *start != 0; start++)

-  {

-    // find start of pattern in string

-    for ( ; ((*start!=0) && (String_ToUpperA(*start) != String_ToUpperA(*pattern))); start++)

-     ;

-    if (0 == *start)

-     return NULL;

-

-    pattern_ptr = (char *)pattern;

-    string_ptr = (char *)start;

-

-    while (String_ToUpperA(*string_ptr) == String_ToUpperA(*pattern_ptr))

-    {

-      string_ptr++;

-      pattern_ptr++;

-

-      // if end of pattern then pattern was found

-      if (0 == *pattern_ptr)

-        return (start);

-    }

-  }

-

-  return NULL;

-}

-

-// case insensitive Unicode strstr

-// adapted from http://c.snippets.org/snip_lister.php?fname=stristr.c

-const WCHAR *stristrW(const WCHAR *string, const WCHAR *pattern)

-{

-  ASSERT (pattern, (L""));

-  ASSERT (string, (L""));

-  ASSERT (string && pattern, (L""));

-  const WCHAR *start;

-

-  for (start = string; *start != 0; start++)

-  {

-    // find start of pattern in string

-    for ( ; ((*start!=0) && (String_ToUpper(*start) != String_ToUpper(*pattern))); start++)

-     ;

-    if (0 == *start)

-     return NULL;

-

-    const WCHAR *pattern_ptr = pattern;

-    const WCHAR *string_ptr = start;

-

-    while (String_ToUpper(*string_ptr) == String_ToUpper(*pattern_ptr))

-    {

-      string_ptr++;

-      pattern_ptr++;

-

-      // if end of pattern then pattern was found

-      if (0 == *pattern_ptr)

-        return (start);

-    }

-  }

-

-  return NULL;

-}

-

-// case sensitive Unicode strstr

-// adapted from http://c.snippets.org/snip_lister.php?fname=stristr.c

-const WCHAR *strstrW(const WCHAR *string, const WCHAR *pattern)

-{

-  ASSERT (pattern, (L""));

-  ASSERT (string, (L""));

-  ASSERT (string && pattern, (L""));

-  const WCHAR *start;

-

-  for (start = string; *start != 0; start++)

-  {

-    // find start of pattern in string

-    for ( ; ((*start!=0) && (*start != *pattern)); start++)

-     ;

-    if (0 == *start)

-     return NULL;

-

-    const WCHAR *pattern_ptr = pattern;

-    const WCHAR *string_ptr = start;

-

-    while (*string_ptr == *pattern_ptr)

-    {

-      string_ptr++;

-      pattern_ptr++;

-

-      // if end of pattern then pattern was found

-      if (0 == *pattern_ptr)

-        return (start);

-    }

-  }

-

-  return NULL;

-}

-

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

-// Helper function

-float GetLenWithWordWrap (const float len_so_far,

-  const float len_to_add,

-  const uint32 len_line) {

-  // lint -save -e414  Possible division by 0

-  ASSERT (len_line != 0, (L""));

-

-  float len_total = len_so_far + len_to_add;

-

-  // Figure out if we need to word wrap by seeing if adding the second

-  // string will cause us to span more lines than before.

-  uint32 num_lines_before = static_cast<uint32> (len_so_far / len_line);

-  uint32 num_lines_after = static_cast<uint32> (len_total / len_line);

-

-  // If it just barely fit onto the line, do not wrap to the next line.

-  if (num_lines_after > 0 && (len_total / len_line - num_lines_after == 0)) {

-    --num_lines_after;

-  }

-

-  if (num_lines_after > num_lines_before)  {

-    // Need to word wrap.

-    // lint -e{790}  Suspicious truncation

-    return num_lines_after * len_line + len_to_add;

-  }

-  else

-    return len_total;

-

-  // lint -restore

-}

-

-int CalculateBase64EscapedLen(int input_len, bool do_padding) {

-  // these formulae were copied from comments that used to go with the base64

-  // encoding functions

-  int intermediate_result = 8 * input_len + 5;

-  ASSERT(intermediate_result > 0,(L""));     // make sure we didn't overflow

-  int len = intermediate_result / 6;

-  if (do_padding) len = ((len + 3) / 4) * 4;

-  return len;

-}

-

-// Base64Escape does padding, so this calculation includes padding.

-int CalculateBase64EscapedLen(int input_len) {

-  return CalculateBase64EscapedLen(input_len, true);

-}

-

-// Base64Escape

-//   Largely based on b2a_base64 in google/docid_encryption.c

-//

-//

-int Base64EscapeInternal(const char *src, int szsrc,

-                         char *dest, int szdest, const char *base64,

-                         bool do_padding)

-{

-  ASSERT(base64, (L""));

-  ASSERT(dest, (L""));

-  ASSERT(src, (L""));

-

-  static const char kPad64 = '=';

-

-  if (szsrc <= 0) return 0;

-

-  char *cur_dest = dest;

-  const unsigned char *cur_src = reinterpret_cast<const unsigned char*>(src);

-

-  // Three bytes of data encodes to four characters of cyphertext.

-  // So we can pump through three-byte chunks atomically.

-  while (szsrc > 2) { /* keep going until we have less than 24 bits */

-    if( (szdest -= 4) < 0 ) return 0;

-    cur_dest[0] = base64[cur_src[0] >> 2];

-    cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];

-    cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)];

-    cur_dest[3] = base64[cur_src[2] & 0x3f];

-

-    cur_dest += 4;

-    cur_src += 3;

-    szsrc -= 3;

-  }

-

-  /* now deal with the tail (<=2 bytes) */

-  switch (szsrc) {

-case 0:

-  // Nothing left; nothing more to do.

-  break;

-case 1:

-  // One byte left: this encodes to two characters, and (optionally)

-  // two pad characters to round out the four-character cypherblock.

-  if( (szdest -= 2) < 0 ) return 0;

-  cur_dest[0] = base64[cur_src[0] >> 2];

-  cur_dest[1] = base64[(cur_src[0] & 0x03) << 4];

-  cur_dest += 2;

-  if (do_padding) {

-    if( (szdest -= 2) < 0 ) return 0;

-    cur_dest[0] = kPad64;

-    cur_dest[1] = kPad64;

-    cur_dest += 2;

-  }

-  break;

-case 2:

-  // Two bytes left: this encodes to three characters, and (optionally)

-  // one pad character to round out the four-character cypherblock.

-  if( (szdest -= 3) < 0 ) return 0;

-  cur_dest[0] = base64[cur_src[0] >> 2];

-  cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];

-  cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2];

-  cur_dest += 3;

-  if (do_padding) {

-    if( (szdest -= 1) < 0 ) return 0;

-    cur_dest[0] = kPad64;

-    cur_dest += 1;

-  }

-  break;

-default:

-  // Should not be reached: blocks of 3 bytes are handled

-  // in the while loop before this switch statement.

-  ASSERT(false, (L"Logic problem? szsrc = %S",szsrc));

-  break;

-  }

-  return (cur_dest - dest);

-}

-

-#define kBase64Chars  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

-

-#define kWebSafeBase64Chars "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"

-

-int Base64Escape(const char *src, int szsrc, char *dest, int szdest) {

-  ASSERT(dest, (L""));

-  ASSERT(src, (L""));

-

-  return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true);

-}

-int WebSafeBase64Escape(const char *src, int szsrc, char *dest,

-  int szdest, bool do_padding) {

-    ASSERT(dest, (L""));

-    ASSERT(src, (L""));

-

-    return Base64EscapeInternal(src, szsrc, dest, szdest,

-      kWebSafeBase64Chars, do_padding);

-  }

-

-void Base64Escape(const char *src, int szsrc,

-                  CStringA* dest, bool do_padding)

-{

-  ASSERT(src, (L""));

-  ASSERT(dest,(L""));

-  const int max_escaped_size = CalculateBase64EscapedLen(szsrc, do_padding);

-  dest->Empty();

-  const int escaped_len = Base64EscapeInternal(src, szsrc,

-      dest->GetBufferSetLength(max_escaped_size + 1), max_escaped_size + 1,

-    kBase64Chars,

-    do_padding);

-  ASSERT(max_escaped_size <= escaped_len,(L""));

-  dest->ReleaseBuffer(escaped_len);

-}

-

-void WebSafeBase64Escape(const char *src, int szsrc,

-                         CStringA *dest, bool do_padding)

-{

-  ASSERT(src, (L""));

-  ASSERT(dest,(L""));

-  const int max_escaped_size =

-    CalculateBase64EscapedLen(szsrc, do_padding);

-  dest->Empty();

-  const int escaped_len = Base64EscapeInternal(src, szsrc,

-    dest->GetBufferSetLength(max_escaped_size + 1), max_escaped_size + 1,

-    kWebSafeBase64Chars,

-    do_padding);

-  ASSERT(max_escaped_size <= escaped_len,(L""));

-  dest->ReleaseBuffer(escaped_len);

-}

-

-void WebSafeBase64Escape(const CStringA& src, CStringA* dest) {

-  ASSERT(dest,(L""));

-  int encoded_len = CalculateBase64EscapedLen(src.GetLength());

-  scoped_array<char> buf(new char[encoded_len]);

-  int len = WebSafeBase64Escape(src,src.GetLength(), buf.get(), encoded_len, false);

-  dest->SetString(buf.get(), len);

-}

-

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

-// int Base64Unescape() - base64 decoder

-//

-// Check out

-// http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for formal

-// description, but what we care about is that...

-//   Take the encoded stuff in groups of 4 characters and turn each

-//   character into a code 0 to 63 thus:

-//           A-Z map to 0 to 25

-//           a-z map to 26 to 51

-//           0-9 map to 52 to 61

-//           +(- for WebSafe) maps to 62

-//           /(_ for WebSafe) maps to 63

-//   There will be four numbers, all less than 64 which can be represented

-//   by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).

-//   Arrange the 6 digit binary numbers into three bytes as such:

-//   aaaaaabb bbbbcccc ccdddddd

-//   Equals signs (one or two) are used at the end of the encoded block to

-//   indicate that the text was not an integer multiple of three bytes long.

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

-int Base64UnescapeInternal(const char *src, int len_src,

-                           char *dest, int len_dest, const char* unbase64) {

-  ASSERT (unbase64, (L""));

-  ASSERT (src, (L""));

-

-  static const char kPad64 = '=';

-

-  int decode;

-  int destidx = 0;

-  int state = 0;

-  // Used an unsigned char, since ch is used as an array index (into unbase64).

-  unsigned char ch = 0;

-  while (len_src-- && (ch = *src++) != '\0')  {

-    if (IsSpaceA(ch))  // Skip whitespace

-      continue;

-

-    if (ch == kPad64)

-      break;

-

-    decode = unbase64[ch];

-    if (decode == 99)  // A non-base64 character

-      return (-1);

-

-    // Four cyphertext characters decode to three bytes.

-    // Therefore we can be in one of four states.

-    switch (state) {

-      case 0:

-        // We're at the beginning of a four-character cyphertext block.

-        // This sets the high six bits of the first byte of the

-        // plaintext block.

-        if (dest) {

-          if (destidx >= len_dest)

-            return (-1);

-          // lint -e{734} Loss of precision

-          dest[destidx] = static_cast<char>(decode << 2);

-        }

-        state = 1;

-        break;

-      case 1:

-        // We're one character into a four-character cyphertext block.

-        // This sets the low two bits of the first plaintext byte,

-        // and the high four bits of the second plaintext byte.

-        // However, if this is the end of data, and those four

-        // bits are zero, it could be that those four bits are

-        // leftovers from the encoding of data that had a length

-        // of one mod three.

-        if (dest) {

-          if (destidx >= len_dest)

-            return (-1);

-          // lint -e{734} Loss of precision

-          dest[destidx]   |=  decode >> 4;

-          if (destidx + 1 >= len_dest) {

-            if (0 != (decode & 0x0f))

-              return (-1);

-            else

-              ;

-          } else {

-            // lint -e{734} Loss of precision

-            dest[destidx+1] = static_cast<char>((decode & 0x0f) << 4);

-          }

-        }

-        destidx++;

-        state = 2;

-        break;

-      case 2:

-        // We're two characters into a four-character cyphertext block.

-        // This sets the low four bits of the second plaintext

-        // byte, and the high two bits of the third plaintext byte.

-        // However, if this is the end of data, and those two

-        // bits are zero, it could be that those two bits are

-        // leftovers from the encoding of data that had a length

-        // of two mod three.

-        if (dest) {

-          if (destidx >= len_dest)

-            return (-1);

-          // lint -e{734} Loss of precision

-          dest[destidx]   |=  decode >> 2;

-          if (destidx +1 >= len_dest) {

-            if (0 != (decode & 0x03))

-              return (-1);

-            else

-              ;

-          } else {

-            // lint -e{734} Loss of precision

-            dest[destidx+1] = static_cast<char>((decode & 0x03) << 6);

-          }

-        }

-        destidx++;

-        state = 3;

-        break;

-      case 3:

-        // We're at the last character of a four-character cyphertext block.

-        // This sets the low six bits of the third plaintext byte.

-        if (dest) {

-          if (destidx >= len_dest)

-            return (-1);

-          // lint -e{734} Loss of precision

-          dest[destidx] |= decode;

-        }

-        destidx++;

-        state = 0;

-        break;

-

-    default:

-      ASSERT (false, (L""));

-      break;

-    }

-  }

-

-  // We are done decoding Base-64 chars.  Let's see if we ended

-  //      on a byte boundary, and/or with erroneous trailing characters.

-  if (ch == kPad64) {               // We got a pad char

-    if ((state == 0) || (state == 1))

-      return (-1);  // Invalid '=' in first or second position

-    if (len_src == 0) {

-      if (state == 2)  // We run out of input but we still need another '='

-        return (-1);

-      // Otherwise, we are in state 3 and only need this '='

-    } else {

-      if (state == 2) {  // need another '='

-        while ((ch = *src++) != '\0' && (len_src-- > 0)) {

-          if (!IsSpaceA(ch))

-            break;

-        }

-        if (ch != kPad64)

-          return (-1);

-      }

-      // state = 1 or 2, check if all remain padding is space

-      while ((ch = *src++) != '\0' && (len_src-- > 0)) {

-        if (!IsSpaceA(ch))

-          return(-1);

-      }

-    }

-  } else {

-    // We ended by seeing the end of the string.  Make sure we

-    //      have no partial bytes lying around.  Note that we

-    //      do not require trailing '=', so states 2 and 3 are okay too.

-    if (state == 1)

-      return (-1);

-  }

-

-  return (destidx);

-}

-

-int Base64Unescape(const char *src, int len_src, char *dest, int len_dest) {

-  ASSERT(dest, (L""));

-  ASSERT(src, (L""));

-

-  static const char UnBase64[] = {

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      62/*+*/, 99,      99,      99,      63/*/ */,

-     52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,

-     60/*8*/, 61/*9*/, 99,      99,      99,      99,      99,      99,

-     99,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,

-      7/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,

-     15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,

-     23/*X*/, 24/*Y*/, 25/*Z*/, 99,      99,      99,      99,      99,

-     99,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,

-     33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,

-     41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,

-     49/*x*/, 50/*y*/, 51/*z*/, 99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99,

-     99,      99,      99,      99,      99,      99,      99,      99

-  };

-

-  // The above array was generated by the following code

-  // #include <sys/time.h>

-  // #include <stdlib.h>

-  // #include <string.h>

-  // main()

-  // {

-  //   static const char Base64[] =

-  //     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

-  //   char *pos;

-  //   int idx, i, j;

-  //   printf("    ");

-  //   for (i = 0; i < 255; i += 8) {

-  //     for (j = i; j < i + 8; j++) {

-  //       pos = strchr(Base64, j);

-  //       if ((pos == NULL) || (j == 0))

-  //         idx = 99;

-  //       else

-  //         idx = pos - Base64;

-  //       if (idx == 99)

-  //         printf(" %2d,     ", idx);

-  //       else

-  //         printf(" %2d/*%c*/,", idx, j);

-  //     }

-  //     printf("\n    ");

-  //   }

-  // }

-

-  return Base64UnescapeInternal(src, len_src, dest, len_dest, UnBase64);

-}

-

-int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) {

-  ASSERT(dest, (L""));

-  ASSERT(src, (L""));

-

-  static const char UnBase64[] = {

-    99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      62/*-*/, 99,      99,

-      52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,

-      60/*8*/, 61/*9*/, 99,      99,      99,      99,      99,      99,

-      99,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,

-      7/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,

-      15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,

-      23/*X*/, 24/*Y*/, 25/*Z*/, 99,      99,      99,      99,      63/*_*/,

-      99,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,

-      33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,

-      41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,

-      49/*x*/, 50/*y*/, 51/*z*/, 99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99,

-      99,      99,      99,      99,      99,      99,      99,      99

-  };

-  // The above array was generated by the following code

-  // #include <sys/time.h>

-  // #include <stdlib.h>

-  // #include <string.h>

-  // main()

-  // {

-  //   static const char Base64[] =

-  //     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

-  //   char *pos;

-  //   int idx, i, j;

-  //   printf("    ");

-  //   for (i = 0; i < 255; i += 8) {

-  //     for (j = i; j < i + 8; j++) {

-  //       pos = strchr(Base64, j);

-  //       if ((pos == NULL) || (j == 0))

-  //         idx = 99;

-  //       else

-  //         idx = pos - Base64;

-  //       if (idx == 99)

-  //         printf(" %2d,     ", idx);

-  //       else

-  //         printf(" %2d/*%c*/,", idx, j);

-  //     }

-  //     printf("\n    ");

-  //   }

-  // }

-

-  return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);

-}

-

-bool IsHexDigit (WCHAR c) {

-  return (((c >= L'a') && (c <= L'f'))

-     || ((c >= L'A') && (c <= L'F'))

-     || ((c >= L'0') && (c <= L'9')));

-}

-

-int HexDigitToInt (WCHAR c) {

-  return ((c >= L'a') ? ((c - L'a') + 10) :

-          (c >= L'A') ? ((c - L'A') + 10) :

-          (c - L'0'));

-}

-

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

-// int QuotedPrintableUnescape()

-//

-// Check out http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for

-// more details, only briefly implemented. But from the web...

-// Quoted-printable is an encoding method defined in the MIME

-// standard. It is used primarily to encode 8-bit text (such as text

-// that includes foreign characters) into 7-bit US ASCII, creating a

-// document that is mostly readable by humans, even in its encoded

-// form. All MIME compliant applications can decode quoted-printable

-// text, though they may not necessarily be able to properly display the

-// document as it was originally intended. As quoted-printable encoding

-// is implemented most commonly, printable ASCII characters (values 33

-// through 126, excluding 61), tabs and spaces that do not appear at the

-// end of lines, and end-of-line characters are not encoded. Other

-// characters are represented by an equal sign (=) immediately followed

-// by that character's hexadecimal value. Lines that are longer than 76

-// characters are shortened by line breaks, with the equal sign marking

-// where the breaks occurred.

-//

-// Update: we really want QuotedPrintableUnescape to conform to rfc2047,

-// which expands the q encoding. In particular, it specifices that _'s are

-// to be treated as spaces.

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

-int QuotedPrintableUnescape(const WCHAR *source, int slen,

-                            WCHAR *dest, int len_dest) {

-  ASSERT(dest, (L""));

-  ASSERT(source, (L""));

-

-  WCHAR* d = dest;

-  const WCHAR* p = source;

-

-  while (*p != '\0' && p < source+slen && d < dest+len_dest) {

-    switch (*p) {

-      case '=':

-        if (p == source+slen-1) {

-          // End of line, no need to print the =..

-          return (d-dest);

-        }

-        // if its valid, convert to hex and insert

-        if (p < source+slen-2 && IsHexDigit(p[1]) && IsHexDigit(p[2])) {

-          // lint -e{734} Loss of precision

-          *d++ = static_cast<WCHAR>(

-                    HexDigitToInt(p[1]) * 16 + HexDigitToInt(p[2]));

-          p += 3;

-        } else {

-          p++;

-        }

-        break;

-      case '_':   // According to rfc2047, _'s are to be treated as spaces

-        *d++ = ' '; p++;

-        break;

-      default:

-        *d++ = *p++;

-        break;

-    }

-  }

-  return (d-dest);

-}

-

-// TODO(omaha): currently set not to use IsCharUpper because that is relatively slow

-// this is used in the QUIB; consider if we need to use IsCharUpper or a replacement

-bool String_IsUpper(TCHAR c) {

-  return (c >= 'A' && c <= 'Z');

-  // return (IsCharUpper (c));

-}

-

-// Replacement for the CRT toupper(c)

-int String_ToUpper(int c) {

-  // If it's < 128, then convert is ourself, which is far cheaper than the system conversion

-  if (c < 128)

-    return String_ToUpperA(static_cast<char>(c));

-

-  TCHAR * p_c = reinterpret_cast<TCHAR *>(c);

-  int conv_c = reinterpret_cast<int>(::CharUpper(p_c));

-  return conv_c;

-}

-

-// Replacement for the CRT toupper(c)

-char String_ToUpperA(char c) {

-  if (c >= 'a' && c <= 'z') return (c - ('a' - 'A'));

-  return c;

-}

-

-void String_ToLower(TCHAR* str) {

-  ASSERT1(str);

-  ::CharLower(str);

-}

-

-void String_ToUpper(TCHAR* str) {

-  ASSERT1(str);

-  ::CharUpper(str);

-}

-

-// String comparison based on length

-// Replacement for the CRT strncmp(i)

-int String_StrNCmp(const TCHAR * str1, const TCHAR * str2, uint32 len, bool ignore_case) {

-  ASSERT(str2, (L""));

-  ASSERT(str1, (L""));

-

-  TCHAR c1, c2;

-

-  if (len == 0)

-    return 0;

-

-  // compare each char

-  // TODO(omaha): If we use a lot of case sensitive compares consider having 2 loops.

-  do {

-    c1 = *str1++;

-    c2 = *str2++;

-    if (ignore_case) {

-      c1 = (TCHAR)String_ToLowerChar((int)(c1));  // lint !e507  Suspicious truncation

-      c2 = (TCHAR)String_ToLowerChar((int)(c2));  // lint !e507

-    }

-  } while ( (--len) && c1 && (c1 == c2) );

-

-  return (int)(c1 - c2);

-}

-

-// TODO(omaha): Why do we introduce this behaviorial difference?

-// Replacement for strncpy() - except ALWAYS ends string with null

-TCHAR* String_StrNCpy(TCHAR* destination, const TCHAR* source, uint32 len) {

-  ASSERT (source, (L""));

-  ASSERT (destination, (L""));

-

-  TCHAR* result = destination;

-

-  ASSERT (0 != len, (L""));     // Too short a destination for even the null character

-

-  while (*source && len) {

-    *destination++ = *source++;

-    len--;

-  }

-

-  // If we ran out of space, back up one

-  if (0 == len) {

-    destination--;

-  }

-

-  // Null-terminate the string

-  *destination = _T('\0');

-

-  return result;

-}

-

-// check if a string starts with another string

-bool String_StartsWith(const TCHAR *str, const TCHAR *start_str,

-                            bool ignore_case) {

-  ASSERT(start_str, (L""));

-  ASSERT(str, (L""));

-

-  while (0 != *str) {

-    // Check for matching characters

-    TCHAR c1 = *str;

-    TCHAR c2 = *start_str;

-

-    // Reached the end of start_str?

-    if (0 == c2)

-      return true;

-

-    if (ignore_case) {

-      c1 = (TCHAR)String_ToLowerChar((int)(c1));  // lint !e507  Suspicious truncation

-      c2 = (TCHAR)String_ToLowerChar((int)(c2));  // lint !e507  Suspicious truncation

-    }

-

-    if (c1 != c2)

-      return false;

-

-    ++str;

-    ++start_str;

-  }

-

-  // If str is shorter than start_str, no match.  If equal size, match.

-  return 0 == *start_str;

-}

-

-// check if a string starts with another string

-bool String_StartsWithA(const char *str, const char *start_str, bool ignore_case) {

-  ASSERT(start_str, (L""));

-  ASSERT(str, (L""));

-

-  while (0 != *str) {

-    // Check for matching characters

-    char c1 = *str;

-    char c2 = *start_str;

-

-    // Reached the end of start_str?

-    if (0 == c2)

-      return true;

-

-    if (ignore_case) {

-      c1 = String_ToLowerCharAnsi(c1);

-      c2 = String_ToLowerCharAnsi(c2);

-    }

-

-    if (c1 != c2)

-      return false;

-

-    ++str;

-    ++start_str;

-  }

-

-  // If str is shorter than start_str, no match.  If equal size, match.

-  return 0 == *start_str;

-}

-

-// the wrapper version below actually increased code size as of 5/31/04

-// perhaps because the int64 version is larger and in some EXE/DLLs we only need the int32 version

-

-// converts a string to an int

-// Does not check for overflow

-// is the direct int32 version significantly faster for our usage?

-// int32 String_StringToInt(const TCHAR * str) {

-//    ASSERT(str, (L""));

-//    return static_cast<int32>(String_StringToInt64 (str));

-// }

-

-// converts a string to an int

-// Does not check for overflow

-int32 String_StringToInt(const TCHAR * str) {

-  ASSERT(str, (L""));

-

-  int c;              // current char

-  int32 total;         // current total

-  int sign;           // if '-', then negative, otherwise positive

-

-  // remove spaces

-  while ( *str == _T(' '))

-      ++str;

-

-  c = (int)*str++;

-  sign = c;           // save sign indication

-  if (c == _T('-') || c == _T('+'))

-      c = (int)*str++;    // skip sign

-

-  total = 0;

-

-  while ((c = String_CharToDigit(static_cast<TCHAR>(c))) != -1 ) {

-      total = 10 * total + c;     // accumulate digit

-      c = *str++;    // get next char

-  }

-

-  if (sign == '-')

-    return -total;

-  else

-    return total;   // return result, negated if necessary

-}

-

-// converts a string to an int64

-// Does not check for overflow

-int64 String_StringToInt64(const TCHAR * str) {

-  ASSERT(str, (L""));

-

-  int c;  // current char

-  int64 total;  // current total

-  int sign;

-

-  while (*str == ' ') ++str;  // skip space

-

-  c = (int)*str++;

-  sign = c;           /* save sign indication */

-  if (c == '-' || c == '+')

-    c = (int)*str++;

-

-  total = 0;

-

-  while ((c = String_CharToDigit(static_cast<TCHAR>(c))) != -1) {

-    total = 10 * total + c;     /* accumulate digit */

-    c = *str++;    /* get next char */

-  }

-

-  if (sign == '-')

-    return -total;

-  else

-    return total;

-}

-

-// A faster version of the ::CharLower command. We first check if all characters are in low ANSI

-// If so, we can convert it ourselves [which is about 10x faster]

-// Otherwise, ask the system to do it for us.

-TCHAR * String_FastToLower(TCHAR * str) {

-  ASSERT(str, (L""));

-

-  TCHAR * p = str;

-  while (*p) {

-    // If we can't process it ourselves, then do it with the API

-    if (*p > 127)

-      return ::CharLower(str);

-    ++p;

-  }

-

-  // If we're still here, do it ourselves

-  p = str;

-  while (*p) {

-    // Lower case it

-    if (*p >= L'A' && *p <= 'Z')

-      *p |= 0x20;

-    ++p;

-  }

-

-  return str;

-}

-

-// Convert a size_t to a CString

-CString sizet_to_str(const size_t & i) {

-  CString out;

-  out.Format(NOTRANSL(_T("%u")),i);

-  return out;

-}

-

-// Convert an int to a CString

-CString itostr(const int i) {

-  return String_Int64ToString(i, 10);

-}

-

-// Convert a uint to a CString

-CString itostr(const uint32 i) {

-  return String_Int64ToString(i, 10);

-}

-

-// converts an int to a string

-// Does not check for overflow

-CString String_Int64ToString(int64 value, int radix) {

-  ASSERT(radix > 0, (L""));

-

-  // Space big enough for it in binary, plus the sign

-  TCHAR temp[66];

-

-  bool negative = false;

-  if (value < 0) {

-    negative = true;

-    value = -value;

-  }

-

-  int pos = 0;

-

-  // Add digits in reverse order

-  do {

-    TCHAR digit = (TCHAR) (value % radix);

-    if (digit > 9)

-      temp[pos] = L'a' + digit - 10;

-    else

-      temp[pos] = L'0' + digit;

-

-    pos++;

-    value /= radix;

-  } while (value > 0);

-

-  if (negative)

-    temp[pos++] = L'-';

-

-  // Reverse it before making a CString out of it

-  int start = 0, end = pos - 1;

-  while (start < end) {

-    TCHAR t = temp[start];

-    temp[start] = temp[end];

-    temp[end] = t;

-

-    end--;

-    start++;

-  }

-

-  return CString(temp, pos);

-}

-

-// converts an uint64 to a string

-// Does not check for overflow

-CString String_Uint64ToString(uint64 value, int radix) {

-  ASSERT1(radix > 0);

-

-  CString ret;

-

-  const uint32 kMaxUint64Digits = 65;

-

-  // Space big enough for it in binary

-  TCHAR* temp = ret.GetBufferSetLength(kMaxUint64Digits);

-

-  int pos = 0;

-

-  // Add digits in reverse order

-  do {

-    TCHAR digit = static_cast<TCHAR>(value % radix);

-    if (digit > 9) {

-      temp[pos] = _T('a') + digit - 10;

-    } else {

-      temp[pos] = _T('0') + digit;

-    }

-

-    pos++;

-    value /= radix;

-  } while (value > 0 && pos < kMaxUint64Digits);

-

-  ret.ReleaseBuffer(pos);

-

-  // Reverse it before making a CString out of it

-  ret.MakeReverse();

-

-  return ret;

-}

-

-// converts an double to a string specifies the number of digits after

-// the decimal point

-CString String_DoubleToString(double value, int point_digits) {

-  int64 int_val = (int64) value;

-

-  // Deal with integer part

-  CString result(String_Int64ToString(int_val, 10));

-

-  if (point_digits > 0) {

-    result.AppendChar(L'.');

-

-    // get the fp digits

-    double rem_val = value - int_val;

-    if (rem_val < 0)

-      rem_val = -rem_val;

-

-    // multiply w/ the requested number of significant digits

-    // construct the string in place

-    for(int i=0; i<point_digits; i++) {

-      // TODO(omaha): I have seen 1.2 turn into 1.1999999999999, and generate that string.

-      // We should round better. For now, I'll add a quick fix to favor high

-      rem_val += 1e-12;

-      rem_val *= 10;

-      // Get the ones digit

-      int64 int_rem_dig = std::min(10LL, static_cast<int64>(rem_val));

-      result += static_cast<TCHAR>(int_rem_dig + L'0');

-      rem_val = rem_val - int_rem_dig;

-    }

-  }

-

-  return result;

-}

-

-double String_StringToDouble (const TCHAR *s) {

-  ASSERT(s, (L""));

-

-  double value, power;

-  int i = 0, sign;

-

-  while (IsSpaceW(s[i])) i++;

-

-  // get sign

-  sign = (s[i] == '-') ? -1 : 1;

-  if (s[i] == '+' || s[i] == '-') i++;

-

-  for (value = 0.0; s[i] >= '0' && s[i] <= '9'; i++)

-    value = 10.0 * value + (s[i] - '0');

-

-  if (s[i] == '.') i++;

-

-  for (power = 1.0; s[i] >= '0' && s[i] <= '9'; i++) {

-    value = 10.0 * value + (s[i] - '0');

-    power *= 10.0;

-  }

-

-  return sign * value / power;

-}

-

-// Converts a character to a digit

-// if the character is not a digit return -1 (same as CRT)

-int32 String_CharToDigit(const TCHAR c) {

-  return ((c) >= '0' && (c) <= '9' ? (c) - '0' : -1);

-}

-

-bool String_IsDigit (const TCHAR c) {

-  return ((c) >= '0' && (c) <= '9');

-}

-

-TCHAR String_DigitToChar(unsigned int n) {

-  ASSERT1(n < 10);

-  return static_cast<TCHAR>(_T('0') + n % 10);

-}

-

-// Returns true if an identifier character: letter, digit, or "_"

-bool String_IsIdentifierChar(const TCHAR c) {

-  return ((c >= _T('A') && c <= _T('Z')) ||

-          (c >= _T('a') && c <= _T('z')) ||

-          (c >= _T('0') && c <= _T('9')) ||

-          c == _T('_'));

-}

-

-// Returns true if the string has letters in it.

-// This is used by the keyword extractor to downweight numbers,

-// IDs (sequences of numbers like social security numbers), etc.

-bool String_HasAlphabetLetters (const TCHAR * str) {

-  ASSERT (str, (L""));

-

-  while (*str != '\0') {

-    // if (iswalpha (*str)) {

-    // Note that IsCharAlpha is slower but we want to avoid the CRT

-    if (IsCharAlpha (*str)) {

-      return true;

-    }

-    ++str;

-  }

-

-  return false;

-}

-

-CString String_LargeIntToApproximateString(uint64 value, bool base_ten, int* power) {

-  uint32 to_one_decimal;

-

-  uint32 gig         = base_ten ? 1000000000 : (1<<30);

-  uint32 gig_div_10  = base_ten ?  100000000 : (1<<30)/10;

-  uint32 meg         = base_ten ?    1000000 : (1<<20);

-  uint32 meg_div_10  = base_ten ?     100000 : (1<<20)/10;

-  uint32 kilo        = base_ten ?       1000 : (1<<10);

-  uint32 kilo_div_10 = base_ten ?        100 : (1<<10)/10;

-

-  if (value >= gig) {

-    if (power) *power = 3;

-    to_one_decimal = static_cast<uint32>(value / gig_div_10);

-  } else if (value >= meg) {

-    if (power) *power = 2;

-    to_one_decimal = static_cast<uint32>(value / meg_div_10);

-  } else if (value >= kilo) {

-    if (power) *power = 1;

-    to_one_decimal = static_cast<uint32>(value / kilo_div_10);

-  } else {

-    if (power) *power = 0;

-    return String_Int64ToString(static_cast<uint32>(value), 10 /*radix*/);

-  }

-

-  uint32 whole_part = to_one_decimal / 10;

-

-  if (whole_part < 10)

-    return Show(0.1 * static_cast<double>(to_one_decimal), 1);

-

-  return String_Int64ToString(whole_part, 10 /*radix*/);

-}

-

-int String_FindString(const TCHAR *s1, const TCHAR *s2) {

-  ASSERT(s2, (L""));

-  ASSERT(s1, (L""));

-

-  // Naive implementation, but still oodles better than ATL's implementation

-  // (which deals with variable character widths---we don't).

-

-  const TCHAR *found = _tcsstr(s1, s2);

-  if (NULL == found)

-    return -1;

-

-  return found - s1;

-}

-

-int String_FindString(const TCHAR *s1, const TCHAR *s2, int start_pos) {

-  ASSERT(s2, (L""));

-  ASSERT(s1, (L""));

-

-  // Naive implementation, but still oodles better than ATL's implementation

-  // (which deals with variable character widths---we don't).

-

-  int skip = start_pos;

-

-  const TCHAR *s = s1;

-  while (skip && *s) {

-    ++s;

-    --skip;

-  }

-  if (!(*s))

-    return -1;

-

-  const TCHAR *found = _tcsstr(s, s2);

-  if (NULL == found)

-    return -1;

-

-  return found - s1;

-}

-

-int String_FindChar(const TCHAR *str, const TCHAR c) {

-  ASSERT (str, (L""));

-  const TCHAR *s = str;

-  while (*s) {

-    if (*s == c)

-      return s - str;

-    ++s;

-  }

-

-  return -1;

-}

-

-// taken from wcsrchr, modified to behave in the CString way

-int String_ReverseFindChar(const TCHAR * str,TCHAR c) {

-  ASSERT (str, (L""));

-  TCHAR *start = (TCHAR *)str;

-

-  while (*str++)                       /* find end of string */

-    ;

-  /* search towards front */

-  while (--str != start && *str != (TCHAR)c)

-    ;

-

-  if (*str == (TCHAR)c)             /* found ? */

-    return( str - start );

-

-  return -1;

-}

-

-int String_FindChar(const TCHAR *str, const TCHAR c, int start_pos) {

-  ASSERT (str, (L""));

-  int n = 0;

-  const TCHAR *s = str;

-  while (*s) {

-    if (n++ >= start_pos && *s == c)

-      return s - str;

-    ++s;

-  }

-

-  return -1;

-}

-

-bool String_Contains(const TCHAR *s1, const TCHAR *s2) {

-  ASSERT(s2, (L""));

-  ASSERT(s1, (L""));

-

-  return -1 != String_FindString(s1, s2);

-}

-

-void String_ReplaceChar(TCHAR *str, TCHAR old_char, TCHAR new_char) {

-  ASSERT (str, (L""));

-  while (*str) {

-    if (*str == old_char)

-      *str = new_char;

-

-    ++str;

-  }

-}

-

-void String_ReplaceChar(CString & str, TCHAR old_char, TCHAR new_char) {

-  String_ReplaceChar (str.GetBuffer(), old_char, new_char);

-  str.ReleaseBuffer();

-}

-

-int ReplaceCString (CString & src, const TCHAR *from, const TCHAR *to) {

-  ASSERT(to, (L""));

-  ASSERT(from, (L""));

-

-  return ReplaceCString(src, from, lstrlen(from), to, lstrlen(to), kRepMax);

-}

-

-// A special version of the replace function which takes advantage of CString properties

-// to make it much faster when the string grows

-// 1) It will resize the string in place if possible. Even if it has to 'grow' the string

-// 2) It will cutoff after a maximum number of matches

-// 3) It expects sizing data to be passed to it

-int ReplaceCString (CString & src, const TCHAR *from, unsigned int from_len,

-                                   const TCHAR *to, unsigned int to_len,

-                                   unsigned int max_matches) {

-  ASSERT (from, (L""));

-  ASSERT (to, (L""));

-  ASSERT (from[0] != '\0', (L""));

-  int i = 0, j = 0;

-  unsigned int matches = 0;

-

-  // Keep track of the matches, it's easier than recalculating them

-  unsigned int match_pos_stack[kExpectedMaxReplaceMatches];

-

-  // We might need to dynamically allocate space for the matches

-  bool dynamic_allocate = false;

-  unsigned int * match_pos = (unsigned int*)match_pos_stack;

-  unsigned int max_match_size = kExpectedMaxReplaceMatches;

-

-  // Is the string getting bigger?

-  bool longer = to_len > from_len;

-

-  // don't compute the lengths unless we know we need to

-  int src_len = src.GetLength();

-  int cur_len = src_len;

-

-  // Trick: We temporarily add 1 extra character to the string. The first char from the from

-  // string. This way we can avoid searching for NULL, since we are guaranteed to find it

-  TCHAR * buffer = src.GetBufferSetLength(src_len+1);

-  const TCHAR from_0 = from[0];

-  buffer[src_len] = from[0];

-

-  while (i < cur_len) {

-    // If we have too many matches, then re-allocate to a dynamic buffer that is

-    // twice as big as the one we are currently using

-    if (longer && (matches == max_match_size)) {

-      // Double the buffer size, and copy it over

-      unsigned int * temp = new unsigned int[max_match_size * 2];

-      memcpy(temp, match_pos, matches * sizeof(unsigned int));

-      if (dynamic_allocate)

-        delete [] match_pos;  // lint !e424  Inappropriate deallocation

-      match_pos = temp;

-

-      max_match_size *= 2;

-      dynamic_allocate = true;

-    }

-

-    // If we have the maximum number of matches already, then stop

-    if (matches >= max_matches) {

-      break;

-    }

-

-    // For each potential match

-    // Note: oddly enough, this is the most expensive line in the function under normal usage. So I am optimizing the heck out of it

-    TCHAR * buf_ptr = buffer + i;

-    while (*buf_ptr != from_0) { ++buf_ptr; }

-    i = buf_ptr - buffer;

-

-    // We're done!

-    if (i >= cur_len)

-      break;

-

-    // buffer is not NULL terminated, we replaced the NULL above

-    while (i < cur_len && buffer[i] && buffer[i] == from[j]) {

-      ++i; ++j;

-      if (from[j] == '\0') {  // found match

-

-        if (!longer) {  // modify in place

-

-          memcpy ((byte *)(buffer+i) - (sizeof (TCHAR) * from_len), (byte *)to, sizeof (TCHAR) * to_len);

-          // if there are often a lot of replacements, it would be faster to create a new string instead

-          // of using memmove

-

-          // TODO(omaha): - memmove will cause n^2 behavior in strings with multiple matches since it will be moved many times...

-          if (to_len < from_len) { memmove ((byte *)(buffer+i) - (sizeof (TCHAR) * (from_len - to_len)),

-                                          (byte *)(buffer+i), (src_len - i + 1) * sizeof (TCHAR)); }

-

-          i -= (from_len - to_len);

-          cur_len -= (from_len - to_len);

-        }

-        else

-          match_pos[matches] = i - from_len;

-

-        ++matches;

-

-        break;

-      }

-    }

-

-    j = 0;

-  }

-

-  if (to_len <= from_len)

-    src_len -= matches * (from_len - to_len);

-

-  // if the new string is longer we do another pass now that we know how long the new string needs to be

-  if (matches && to_len > from_len) {

-    src.ReleaseBuffer(src_len);

-

-    int new_len = src_len + matches * (to_len - from_len);

-    buffer = src.GetBufferSetLength(new_len);

-

-    // It's easier to assemble it backwards...

-    int temp_end = new_len;

-    for(i = matches-1; i >= 0; --i) {

-      // Figure out where the trailing portion isthe trailing portion

-      int len = src_len - match_pos[i] - from_len;

-      int start  = match_pos[i] + from_len;

-      int dest   = temp_end - len;

-      memmove(buffer+dest, buffer+start, (len) * sizeof(TCHAR));

-

-      // copy the new item

-      memcpy(buffer + dest - to_len, to, to_len * sizeof(TCHAR));

-

-      // Update the pointers

-      temp_end = dest - to_len;

-      src_len = match_pos[i];

-

-    }

-    src_len = new_len;

-  }

-

-  src.ReleaseBuffer(src_len);

-  if (dynamic_allocate)

-    delete [] match_pos;  // lint !e673  Possibly inappropriate deallocation

-

-  return matches;

-}

-

-/*

-   The following 2 functions will do replacement on TCHAR* directly. They is currently unused.

-   Feel free to put it back if you need to.

-*/

-int ReplaceString (TCHAR *src, const TCHAR *from, const TCHAR *to, TCHAR **out, int *out_len) {

-  ASSERT(out_len, (L""));

-  ASSERT(out, (L""));

-  ASSERT(to, (L""));

-  ASSERT(from, (L""));

-  ASSERT(src, (L""));

-

-  bool created_new_string;

-  int matches = ReplaceStringMaybeInPlace (src, from, to, out, out_len, &created_new_string);

-  if (!created_new_string) {

-      *out = new TCHAR [(*out_len)+1];

-      if (!(*out)) { *out = src; return 0; }

-      _tcscpy_s(*out, *out_len + 1, src);

-  }

-

-  return matches;

-}

-

-int ReplaceStringMaybeInPlace (TCHAR *src, const TCHAR *from, const TCHAR *to, TCHAR **out, int *out_len, bool *created_new_string) {

-  ASSERT (created_new_string, (L""));

-  ASSERT (out_len, (L""));

-  ASSERT (src, (L""));

-  ASSERT (from, (L""));

-  ASSERT (to, (L""));

-  ASSERT (out, (L""));

-  ASSERT (from[0] != '\0', (L""));

-  int i = 0, j = 0;

-  int matches = 0;

-

-  // don't compute the lengths unless we know we need to

-  int from_len = -1, to_len = -1, src_len = -1;

-

-  *created_new_string = false;

-  *out = src;

-

-  while (src[i]) {

-    while (src[i] && src[i] != from[0]) { i++; }

-    while (src[i] && src[i] == from[j]) {

-      i++; j++;

-      if (from[j] == '\0') {  // found match

-        if (from_len == -1) {  // compute lengths if not known

-          from_len = lstrlen (from);

-          to_len = lstrlen (to);

-          src_len = lstrlen (src);

-        }

-

-        matches++;

-

-        if (to_len <= from_len) {  // modify in place

-          memcpy ((byte *)(src+i) - (sizeof (TCHAR) * from_len), (byte *)to, sizeof (TCHAR) * to_len);

-          // if there are often a lot of replacements, it would be faster to create a new string instead

-          // of using memmove

-          if (to_len < from_len) { memmove ((byte *)(src+i) - (sizeof (TCHAR) * (from_len - to_len)),

-                                            (byte *)(src+i), (src_len - i + 1) * sizeof (TCHAR)); }

-          i -= (from_len - to_len);

-        }

-

-        break;

-      }

-    }

-

-    j = 0;

-  }

-

-  *out_len = i;

-

-  // if the new string is longer we do another pass now that we know how long the new string needs to be

-  if (matches && to_len > from_len) {

-      ASSERT (src_len == i, (L""));

-      int new_len = src_len + matches * (to_len - from_len);

-      *out = new TCHAR [new_len+1];

-      if (!(*out)) { *out = src; *out_len = lstrlen (src); return 0; }

-      *created_new_string = true;

-      i = 0; j = 0; int k = 0;

-

-      while (src[i]) {

-          while (src[i] && src[i] != from[0]) {

-              (*out)[k++] = src[i++];

-          }

-          while (src[i] && src[i] == from[j]) {

-              (*out)[k++] = src[i++];

-              j++;

-

-              if (from[j] == '\0') {  // found match

-                  k -= from_len;

-                  ASSERT (k >= 0, (L""));

-                  memcpy ((byte *)((*out)+k), (byte *)to, sizeof (TCHAR) * to_len);

-                  k += to_len;

-                  break;

-              }

-          }

-

-          j = 0;

-      }

-

-      (*out)[k] = '\0';

-      ASSERT (k == new_len, (L""));

-      *out_len = new_len;

-  }

-

-  return matches;

-}

-

-/****************************************************************************

-* wcstol, wcstoul(nptr,endptr,ibase) - Convert ascii string to long un/signed int.

-*

-* modified from:

-*

-* wcstol.c - Contains C runtimes wcstol and wcstoul

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*   Purpose:

-*       Convert an ascii string to a long 32-bit value.  The base

-*       used for the caculations is supplied by the caller.  The base

-*       must be in the range 0, 2-36.  If a base of 0 is supplied, the

-*       ascii string must be examined to determine the base of the

-*       number:

-*           (a) First char = '0', second char = 'x' or 'X',

-*               use base 16.

-*           (b) First char = '0', use base 8

-*           (c) First char in range '1' - '9', use base 10.

-*

-*       If the 'endptr' value is non-NULL, then wcstol/wcstoul places

-*       a pointer to the terminating character in this value.

-*       See ANSI standard for details

-*

-*Entry:

-*       nptr == NEAR/FAR pointer to the start of string.

-*       endptr == NEAR/FAR pointer to the end of the string.

-*       ibase == integer base to use for the calculations.

-*

-*       string format: [whitespace] [sign] [0] [x] [digits/letters]

-*

-*Exit:

-*       Good return:

-*           result

-*

-*       Overflow return:

-*           wcstol -- LONG_MAX or LONG_MIN

-*           wcstoul -- ULONG_MAX

-*           wcstol/wcstoul -- errno == ERANGE

-*

-*       No digits or bad base return:

-*           0

-*           endptr = nptr*

-*

-*Exceptions:

-*       None.

-*

-*******************************************************************************/

-

-// flag values */

-#define kFlUnsigned   (1)       // wcstoul called */

-#define kFlNeg        (2)       // negative sign found */

-#define kFlOverflow   (4)       // overflow occured */

-#define kFlReaddigit  (8)       // we've read at least one correct digit */

-

-static unsigned long __cdecl wcstoxl (const wchar_t *nptr, wchar_t **endptr, int ibase, int flags) {

-  ASSERT(nptr, (L""));

-

-  const wchar_t *p;

-  wchar_t c;

-  unsigned long number;

-  unsigned digval;

-  unsigned long maxval;

-  // #ifdef _MT

-  // pthreadlocinfo ptloci = _getptd()->ptlocinfo;

-

-  // if ( ptloci != __ptlocinfo )

-  //    ptloci = __updatetlocinfo();

-  // #endif  // _MT */

-

-  p = nptr;           // p is our scanning pointer */

-  number = 0;         // start with zero */

-

-  c = *p++;           // read char */

-

-  // #ifdef _MT

-  //        while ( __iswspace_mt(ptloci, c) )

-  // #else  // _MT */

-  while (c == ' ')

-  //        while ( iswspace(c) )

-  // #endif  // _MT */

-      c = *p++;       // skip whitespace */

-

-  if (c == '-') {

-      flags |= kFlNeg;    // remember minus sign */

-      c = *p++;

-  }

-  else if (c == '+')

-      c = *p++;       // skip sign */

-

-  if (ibase < 0 || ibase == 1 || ibase > 36) {

-      // bad base! */

-      if (endptr)

-          // store beginning of string in endptr */

-          *endptr = const_cast<wchar_t *>(nptr);

-      return 0L;      // return 0 */

-  }

-  else if (ibase == 0) {

-      // determine base free-lance, based on first two chars of

-      // string */

-      if (String_CharToDigit(c) != 0)

-          ibase = 10;

-      else if (*p == L'x' || *p == L'X')

-          ibase = 16;

-      else

-          ibase = 8;

-  }

-

-  if (ibase == 16) {

-      // we might have 0x in front of number; remove if there */

-      if (String_CharToDigit(c) == 0 && (*p == L'x' || *p == L'X')) {

-          ++p;

-          c = *p++;   // advance past prefix */

-      }

-  }

-

-  // if our number exceeds this, we will overflow on multiply */

-  maxval = ULONG_MAX / ibase;

-

-  for (;;) {  // exit in middle of loop */

-

-      // convert c to value */

-      if ( (digval = String_CharToDigit(c)) != (unsigned) -1 )

-          ;

-      else if (c >= 'A' && c <= 'F') { digval = c - 'A' + 10; }

-      else if (c >= 'a' && c <= 'f') { digval = c - 'a' + 10; }

-      // else if ( __ascii_iswalpha(c))

-      //     digval = __ascii_towupper(c) - L'A' + 10;

-      else

-          break;

-

-      if (digval >= (unsigned)ibase)

-          break;      // exit loop if bad digit found */

-

-      // record the fact we have read one digit */

-      flags |= kFlReaddigit;

-

-      // we now need to compute number = number * base + digval,

-      // but we need to know if overflow occured.  This requires

-      // a tricky pre-check. */

-

-      if (number < maxval || (number == maxval &&

-      (unsigned long)digval <= ULONG_MAX % ibase)) {

-          // we won't overflow, go ahead and multiply */

-          number = number * ibase + digval;

-      }

-      else {

-          // we would have overflowed -- set the overflow flag */

-          flags |= kFlOverflow;

-      }

-

-      c = *p++;       // read next digit */

-  }

-

-  --p;                // point to place that stopped scan */

-

-  if (!(flags & kFlReaddigit)) {

-      // no number there; return 0 and point to beginning of string */

-      if (endptr)

-          // store beginning of string in endptr later on */

-          p = nptr;

-      number = 0L;        // return 0 */

-  }

-  // lint -save -e648 -e650  Overflow in -LONG_MIN

-#pragma warning(push)

-// C4287 : unsigned/negative constant mismatch.

-// The offending expression is number > -LONG_MIN. -LONG_MIN overflows and

-// technically -LONG_MIN == LONG_MIN == 0x80000000. It should actually

-// result in a compiler warning, such as C4307: integral constant overflow.

-// Anyway, in the expression (number > -LONG_MIN) the right operand is converted

-// to unsigned long, so the expression is actually evaluated as

-// number > 0x80000000UL. The code is probably correct but subtle, to say the

-// least.

-#pragma warning(disable : 4287)

-  else if ( (flags & kFlOverflow) ||

-        ( !(flags & kFlUnsigned) &&

-          ( ( (flags & kFlNeg) && (number > -LONG_MIN) ) ||

-            ( !(flags & kFlNeg) && (number > LONG_MAX) ) ) ) )

-  {

-      // overflow or signed overflow occurred */

-      // errno = ERANGE;

-      if ( flags & kFlUnsigned )

-          number = ULONG_MAX;

-      else if ( flags & kFlNeg )

-        // lint -e{648, 650}  Overflow in -LONG_MIN

-        number = (unsigned long)(-LONG_MIN);

-      else

-        number = LONG_MAX;

-  }

-#pragma warning(pop)

-  // lint -restore

-

-  if (endptr != NULL)

-      // store pointer to char that stopped the scan */

-      *endptr = const_cast<wchar_t *>(p);

-

-  if (flags & kFlNeg)

-      // negate result if there was a neg sign */

-      number = (unsigned long)(-(long)number);

-

-  return number;          // done. */

-}

-

-long __cdecl Wcstol (const wchar_t *nptr, wchar_t **endptr, int ibase) {

-  ASSERT(endptr, (L""));

-  ASSERT(nptr, (L""));

-

-  return (long) wcstoxl(nptr, endptr, ibase, 0);

-}

-

-unsigned long __cdecl Wcstoul (const wchar_t *nptr, wchar_t **endptr, int ibase) {

-  // endptr may be NULL

-  ASSERT(nptr, (L""));

-

-  return wcstoxl(nptr, endptr, ibase, kFlUnsigned);

-}

-

-// Functions on arrays of strings

-

-// Returns true iff s is in the array strings (case-insensitive compare)

-bool String_MemberOf(const TCHAR* const* strings, const TCHAR* s) {

-  ASSERT(s, (L""));

-  // strings may be NULL

-

-  const int s_length = lstrlen(s);

-  if (strings == NULL)

-    return false;

-  for (; *strings != NULL; strings++) {

-    if (0 == String_StrNCmp(*strings, s, s_length, true)) {

-      return true;      // Found equal string

-    }

-  }

-  return false;

-}

-

-// Returns index of s in the array of strings (or -1 for missing) (case-insensitive compare)

-int String_IndexOf(const TCHAR* const* strings, const TCHAR* s) {

-  ASSERT(s, (L""));

-  // strings may be NULL

-

-  const int s_length = lstrlen(s);

-  if (strings == NULL)

-    return -1;

-  for (int i = 0; *strings != NULL; i++, strings++) {

-    if (0 == String_StrNCmp(*strings, s, s_length, true)) {

-      return i;      // Found equal string

-    }

-  }

-  return -1;

-}

-

-// The internal format is a int64.

-time64 StringToTime(const CString & time) {

-  return static_cast<time64>(String_StringToInt64(time));

-}

-

-// See above comment from StringToTime.

-// Just show it as a INT64 for now

-// NOTE: this will truncating it to INT64, which may lop off some times in the future

-CString TimeToString(const time64 & time) {

-  return String_Int64ToString(static_cast<int64>(time), 10);

-}

-

-const TCHAR *FindStringASpaceStringB (const TCHAR *s, const TCHAR *a, const TCHAR *b) {

-  ASSERT(s, (L""));

-  ASSERT(a, (L""));

-  ASSERT(b, (L""));

-

-  const TCHAR *search_from = s;

-  const TCHAR *pos;

-  while (*search_from && (pos = stristrW (search_from, a)) != NULL) {

-      const TCHAR *start = pos;

-      pos += lstrlen(a);

-      search_from = pos;

-      while (*pos == ' ' || *pos == '\t') pos++;

-      if (!String_StrNCmp (pos, b, lstrlen(b), true)) return start;

-  }

-

-  return 0;

-}

-

-bool IsAlphaA (const char c) {

-  return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));

-}

-

-bool IsDigitA (const char c) {

-  return (c >= '0' && c <= '9');

-}

-

-void SafeStrCat (TCHAR *dest, const TCHAR *src, int dest_buffer_len) {

-  _tcscat_s(dest, dest_buffer_len, src);

-}

-

-// extracts next float in a string

-// skips any non-digit characters

-// return position after end of float

-const TCHAR *ExtractNextDouble (const TCHAR *s, double *f) {

-  ASSERT (f, (L""));

-  ASSERT (s, (L""));

-

-  CString num;

-  while (*s && !String_IsDigit (*s)) s++;

-  while (*s && (*s == '.' || String_IsDigit (*s))) { num += *s; s++; }

-  ASSERT (num.GetLength(), (L""));

-  *f = String_StringToDouble (num);

-  return s;

-}

-

-TCHAR *String_PathFindExtension(const TCHAR *path) {

-  ASSERT(path, (L""));

-

-  // Documentation says PathFindExtension string must be of max length

-  // MAX_PATH but a trusted tester hit the ASSERT and we don't really

-  // need it here, so commented out. We can't address where it is

-  // called because it's called from ATL code.

-  // ASSERT(lstrlen(path)<=MAX_PATH, (L""));

-

-  // point to terminating NULL

-  const TCHAR *ret = path + lstrlen(path);

-  const TCHAR *pos = ret;

-

-  while (--pos >= path) {

-    if (*pos == '.')

-      return const_cast<TCHAR *>(pos);

-  }

-

-  return const_cast<TCHAR *>(ret);

-}

-

-char String_ToLowerCharAnsi(char c) {

-  if (c >= 'A' && c <= 'Z') return (c + ('a' - 'A'));

-  return c;

-}

-

-int String_ToLowerChar(int c) {

-  // If it's < 128, then convert is ourself, which is far cheaper than the system conversion

-  if (c < 128)

-    return String_ToLowerCharAnsi(static_cast<char>(c));

-

-  return Char_ToLower(static_cast<TCHAR>(c));

-}

-

-

-bool String_PathRemoveFileSpec(TCHAR *path) {

-  ASSERT (path, (L""));

-

-  int len, pos;

-  len = pos = lstrlen (path);

-

-  // You might think that the SHLWAPI API does not change "c:\windows" -> "c:\"

-  // when c:\windows is a directory, but it does.

-

-  // If we don't want to match this weird API we can use the following to check

-  // for directories:

-

-  // Check if we are already a directory.

-  WIN32_FILE_ATTRIBUTE_DATA attrs;

-  // Failure (if file does not exist) is OK.

-  BOOL success = GetFileAttributesEx(path, GetFileExInfoStandard, &attrs);

-  UTIL_LOG(L4, (_T("[String_PathRemoveFileSpec][path %s][success %d][dir %d]"),

-                path,

-                success,

-                attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));

-  if (success && (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {

-    // Remove trailing backslash, if any.

-    if (path[pos-1] == '\\')

-      path[pos-1] = '\0';

-    return 1;

-  }

-

-  // Find last backslash.

-  while (pos && path[pos] != '\\') pos--;

-  if (!pos && path[pos] != '\\') return 0;

-

-  ASSERT (pos < len, (L""));

-

-  // The documentation says it removes backslash but it doesn't for c:\.

-  if (!pos || path[pos-1] == ':' || (pos == 1 && path[0] == '\\'))

-    // Keep the backslash in this case.

-    path[pos+1] = '\0';

-  else

-    path[pos] = '\0';

-

-  return 1;

-}

-

-void String_EndWithChar(TCHAR *str, TCHAR c) {

-  ASSERT (str, (L""));

-  int len = lstrlen(str);

-  if (len == 0 || str[len - 1] != c) {

-    str[len] = c;

-    str[len + 1] = 0;

-  }

-}

-

-bool StartsWithBOM(const TCHAR* string) {

-  ASSERT(string, (L""));

-  wchar_t c = string[0];

-  if (c == 0xFFFE || c == 0xFEFF)

-    return true;

-  else

-    return false;

-}

-

-const TCHAR* StringAfterBOM(const TCHAR* string) {

-  ASSERT(string, (L""));

-  return &string[StartsWithBOM(string) ? 1 : 0];

-}

-

-bool String_StringToDecimalIntChecked(const TCHAR* str, int* value) {

-  ASSERT1(str);

-  ASSERT1(value);

-

-  if (_set_errno(0)) {

-    return false;

-  }

-

-  TCHAR* end_ptr = NULL;

-  *value = _tcstol(str, &end_ptr, 10);

-  ASSERT1(end_ptr);

-

-  if (errno) {

-    ASSERT1(ERANGE == errno);

-    // Overflow or underflow.

-    return false;

-  } else if (*value == 0) {

-    // The value returned could be an error code. tcsltol returns

-    // zero when it cannot convert the string. However we need to

-    // distinguish a real zero. Thus check to see if end_ptr is not the start

-    // of the string (str is not an empty string) and is pointing to a '\0'.

-    // If not, we have an error.

-    if ((str == end_ptr) || (*end_ptr != '\0')) {

-      return false;

-    }

-  } else if (*end_ptr != '\0') {

-    // The end_ptr is pointing at a character that is

-    // not the end of the string. Only part of the string could be converted.

-    return false;

-  }

-

-  return true;

-}

-

-bool CLSIDToCString(const GUID& guid, CString* str) {

-  ASSERT(str, (L""));

-

-  LPOLESTR string_guid = NULL;

-  if (::StringFromCLSID(guid, &string_guid) != S_OK) {

-    return false;

-  }

-  *str = string_guid;

-  ::CoTaskMemFree(string_guid);

-

-  return true;

-}

-

-HRESULT String_StringToBool(const TCHAR* str, bool* value) {

-  ASSERT1(str);

-  ASSERT1(value);

-

-  // This method now performs a case-insentitive

-  // culture aware compare. We should however be ok as we are only comparing

-  // latin characters.

-  if (_tcsicmp(kFalse, str) == 0) {

-    *value = false;

-  } else if (_tcsicmp(kTrue, str) == 0) {

-    *value = true;

-  } else {

-    // we found another string. should error out.

-    return E_FAIL;

-  }

-  return S_OK;

-}

-

-HRESULT String_BoolToString(bool value, CString* string) {

-  ASSERT1(string);

-  *string = value ? kTrue : kFalse;

-  return S_OK;

-}

-

-// Escape and unescape strings (shlwapi-based implementation).

-// The intended usage for these APIs is escaping strings to make up

-// URLs, for example building query strings.

-//

-// Pass false to the flag segment_only to escape the url. This will not

-// cause the conversion of the # (%23), ? (%3F), and / (%2F) characters.

-

-// Characters that must be encoded include any characters that have no

-// corresponding graphic character in the US-ASCII coded character

-// set (hexadecimal 80-FF, which are not used in the US-ASCII coded character

-// set, and hexadecimal 00-1F and 7F, which are control characters),

-// blank spaces, "%" (which is used to encode other characters),

-// and unsafe characters (<, >, ", #, {, }, |, \, ^, ~, [, ], and ').

-//

-// The input and output strings can't be longer than INTERNET_MAX_URL_LENGTH

-

-HRESULT StringEscape(const CString& str_in,

-                     bool segment_only,

-                     CString* str_out) {

-  ASSERT1(str_out);

-  ASSERT1(str_in.GetLength() < INTERNET_MAX_URL_LENGTH);

-

-  DWORD buf_len = INTERNET_MAX_URL_LENGTH + 1;

-  HRESULT hr = ::UrlEscape(str_in, str_out->GetBufferSetLength(buf_len), &buf_len,

-    segment_only ? URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY : URL_ESCAPE_PERCENT);

-  if (SUCCEEDED(hr)) {

-    str_out->ReleaseBuffer();

-    ASSERT1(buf_len <= INTERNET_MAX_URL_LENGTH);

-  }

-  return hr;

-}

-

-HRESULT StringUnescape(const CString& str_in, CString* str_out) {

-  ASSERT1(str_out);

-  ASSERT1(str_in.GetLength() < INTERNET_MAX_URL_LENGTH);

-

-  DWORD buf_len = INTERNET_MAX_URL_LENGTH + 1;

-  HRESULT hr = ::UrlUnescape(const_cast<TCHAR*>(str_in.GetString()),

-    str_out->GetBufferSetLength(buf_len), &buf_len, 0);

-  if (SUCCEEDED(hr)) {

-    str_out->ReleaseBuffer(buf_len + 1);

-    ASSERT1(buf_len <= INTERNET_MAX_URL_LENGTH);

-  }

-  return hr;

-}

-

-bool String_StringToTristate(const TCHAR* str, Tristate* value) {

-  ASSERT1(str);

-  ASSERT1(value);

-

-  int numerical_value = 0;

-  if (!String_StringToDecimalIntChecked(str, &numerical_value)) {

-    return false;

-  }

-

-  switch (numerical_value) {

-    case 0:

-      *value = TRISTATE_FALSE;

-      break;

-    case 1:

-      *value = TRISTATE_TRUE;

-      break;

-    case 2:

-      *value = TRISTATE_NONE;

-      break;

-    default:

-      return false;

-  }

-

-  return true;

-}

-

-// Extracts the name and value from a string that contains a name/value pair.

-bool ParseNameValuePair(const CString& token,

-                        TCHAR separator,

-                        CString* name,

-                        CString* value) {

-  ASSERT1(name);

-  ASSERT1(value);

-

-  int separator_index = token.Find(separator);

-  if ((separator_index == -1) ||  // Not a name-value pair.

-      (separator_index == 0) ||  // No name was supplied.

-      (separator_index == (token.GetLength() - 1))) {  // No value was supplied.

-    return false;

-  }

-

-  *name = token.Left(separator_index);

-  *value = token.Right(token.GetLength() - separator_index - 1);

-

-  ASSERT1(token.GetLength() == name->GetLength() + value->GetLength() + 1);

-

-  // It's not possible for the name to contain the separator.

-  ASSERT1(-1 == name->Find(separator));

-  if (-1 != value->Find(separator)) {

-    // The value contains the separator.

-    return false;

-  }

-

-  return true;

-}

-

-bool SplitCommandLineInPlace(TCHAR *command_line,

-                             TCHAR **first_argument_parameter,

-                             TCHAR **remaining_arguments_parameter) {

-  if (!command_line ||

-      !first_argument_parameter ||

-      !remaining_arguments_parameter) {

-    return false;

-  }

-

-  TCHAR end_char;

-  TCHAR *&first_argument = *first_argument_parameter;

-  TCHAR *&remaining_arguments = *remaining_arguments_parameter;

-  if (_T('\"') == *command_line) {

-    end_char = _T('\"');

-    first_argument = remaining_arguments = command_line + 1;

-  } else {

-    end_char = _T(' ');

-    first_argument = remaining_arguments = command_line;

-  }

-  // Search for the end of the first argument

-  while (end_char != *remaining_arguments && '\0' != *remaining_arguments) {

-    ++remaining_arguments;

-  }

-  if (end_char == *remaining_arguments) {

-    *remaining_arguments = '\0';

-    do {

-      // Skip the spaces between the first argument and the remaining arguments.

-      ++remaining_arguments;

-    } while (_T(' ') == *remaining_arguments);

-  }

-  return true;

-}

-

-bool ContainsOnlyAsciiChars(const CString& str) {

-  for (int i = 0; i < str.GetLength(); ++i) {

-    if (str[i] > 0x7F) {

-      return false;

-    }

-  }

-  return true;

-}

-CString BytesToHex(const uint8* bytes, size_t num_bytes) {

-  CString result;

-  if (bytes) {

-    result.Preallocate(num_bytes * sizeof(TCHAR));

-    static const TCHAR* const kHexChars = _T("0123456789abcdef");

-    for (size_t i = 0; i != num_bytes; ++i) {

-      result.AppendChar(kHexChars[(bytes[i] >> 4)]);

-      result.AppendChar(kHexChars[(bytes[i] & 0xf)]);

-    }

-  }

-  return result;

-}

-

-CString BytesToHex(const std::vector<uint8>& bytes) {

-  CString result;

-  if (!bytes.empty()) {

-    result.SetString(BytesToHex(&bytes.front(), bytes.size()));

-  }

-  return result;

-}

-

-void JoinStrings(const std::vector<CString>& components,

-                 const TCHAR* delim,

-                 CString* result) {

-  ASSERT1(result);

-  result->Empty();

-

-  // Compute length so we can reserve memory.

-  size_t length = 0;

-  size_t delim_length = delim ? _tcslen(delim) : 0;

-  for (size_t i = 0; i != components.size(); ++i) {

-    if (i != 0) {

-      length += delim_length;

-    }

-    length += components[i].GetLength();

-  }

-

-  result->Preallocate(length);

-

-  for (size_t i = 0; i != components.size(); ++i) {

-    if (i != 0 && delim) {

-      result->Append(delim, delim_length);

-    }

-    result->Append(components[i]);

-  }

-}

-

-void JoinStringsInArray(const TCHAR* components[],

-                        int num_components,

-                        const TCHAR* delim,

-                        CString* result) {

-  ASSERT1(result);

-  result->Empty();

-

-  for (int i = 0; i != num_components; ++i) {

-    if (i != 0 && delim) {

-      result->Append(delim);

-    }

-    if (components[i]) {

-      result->Append(components[i]);

-    }

-  }

-}

-

-CString FormatResourceMessage(uint32 resource_id, ...) {

-  CString format;

-  const bool is_loaded = !!format.LoadString(resource_id);

-

-  if (!is_loaded) {

-    return CString();

-  }

-

-  va_list arg_list;

-  va_start(arg_list, resource_id);

-

-  CString formatted;

-  formatted.FormatMessageV(format, &arg_list);

-

-  va_end(arg_list);

-

-  return formatted;

-}

-

-CString FormatErrorCode(DWORD error_code) {

-  CString error_code_string;

-  if (FAILED(error_code)) {

-    error_code_string.Format(_T("0x%08x"), error_code);

-  } else {

-    error_code_string.Format(_T("%u"), error_code);

-  }

-  return error_code_string;

-}

-

-HRESULT WideStringToUtf8UrlEncodedString(const CString& str, CString* out) {

-  ASSERT1(out);

-

-  out->Empty();

-  if (str.IsEmpty()) {

-    return S_OK;

-  }

-

-  // Utf8 encode the Utf16 string first. Next urlencode it.

-  CStringA utf8str = WideToUtf8(str);

-  ASSERT1(!utf8str.IsEmpty());

-  DWORD buf_len = INTERNET_MAX_URL_LENGTH;

-  CStringA escaped_utf8_name;

-  HRESULT hr = ::UrlEscapeA(utf8str,

-                            CStrBufA(escaped_utf8_name, buf_len),

-                            &buf_len,

-                            0);

-  ASSERT1(buf_len <= INTERNET_MAX_URL_LENGTH);

-  ASSERT1(escaped_utf8_name.GetLength() == static_cast<int>(buf_len));

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[UrlEscapeA failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  *out = CString(escaped_utf8_name);

-  return S_OK;

-}

-

-HRESULT Utf8UrlEncodedStringToWideString(const CString& str, CString* out) {

-  ASSERT1(out);

-

-  out->Empty();

-  if (str.IsEmpty()) {

-    return S_OK;

-  }

-

-  // The value is a utf8 encoded url escaped string that is stored as a

-  // unicode string. Because of this, it should contain only ascii chars.

-  if (!ContainsOnlyAsciiChars(str)) {

-    UTIL_LOG(LE, (_T("[String contains non ascii chars]")));

-    return E_INVALIDARG;

-  }

-

-  CStringA escaped_utf8_val = WideToAnsiDirect(str);

-  DWORD buf_len = INTERNET_MAX_URL_LENGTH;

-  CStringA unescaped_val;

-  HRESULT hr = ::UrlUnescapeA(const_cast<char*>(escaped_utf8_val.GetString()),

-                              CStrBufA(unescaped_val, buf_len),

-                              &buf_len,

-                              0);

-  ASSERT1(unescaped_val.GetLength() == static_cast<int>(buf_len));

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[UrlUnescapeA failed][0x%08x]"), hr));

-    return hr;

-  }

-  ASSERT1(buf_len == static_cast<DWORD>(unescaped_val.GetLength()));

-  ASSERT1(buf_len <= INTERNET_MAX_URL_LENGTH);

-  CString app_name = Utf8ToWideChar(unescaped_val,

-                                    unescaped_val.GetLength());

-  if (app_name.IsEmpty()) {

-    return E_INVALIDARG;

-  }

-

-  *out = app_name;

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/string.h"
+
+#include <wininet.h>        // For INTERNET_MAX_URL_LENGTH.
+#include <algorithm>
+#include <cstdlib>
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/localization.h"
+#include "omaha/common/logging.h"
+
+namespace omaha {
+
+namespace {
+// Testing shows that only the following ASCII characters are
+// considered spaces by GetStringTypeA: 9-13, 32, 160.
+// Rather than call GetStringTypeA with no locale, as we used to,
+// we look up the values directly in a precomputed array.
+
+SELECTANY byte spaces[256] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  // 0-9
+  1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 10-19
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 20-29
+  0, 0, 1, 0, 0, 0, 0, 0, 0, 0,  // 30-39
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 40-49
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 50-59
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 60-69
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 70-79
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 80-89
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 90-99
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 100-109
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 110-119
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 120-129
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 130-139
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 140-149
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 150-159
+  1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 160-169
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 170-179
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 180-189
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 190-199
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 200-209
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 210-219
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 220-229
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 230-239
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 240-249
+  0, 0, 0, 0, 0, 1,              // 250-255
+};
+}  // namespace
+
+const TCHAR* const kFalse = _T("false");
+const TCHAR* const kTrue  = _T("true");
+
+bool IsSpaceW(WCHAR c) {
+  // GetStringTypeW considers these characters to be spaces:
+  // 9-13, 32, 133, 160, 5760, 8192-8203, 8232, 8233, 12288
+  if (c < 256)
+    return (c == 133 || IsSpaceA((char) (c & 0xff)));
+
+  return (c >= 8192 && c <= 8203) || c == 8232 ||
+    c == 8233 || c == 12288;
+}
+
+bool IsSpaceA(char c) {
+  return spaces[static_cast<unsigned char>(c)] == 1;
+}
+
+int TrimCString(CString &s) {
+  int len = Trim(s.GetBuffer());
+  s.ReleaseBufferSetLength(len);
+  return len;
+}
+
+void MakeLowerCString(CString & s) {
+  int len = s.GetLength();
+  String_FastToLower(s.GetBuffer());
+  s.ReleaseBufferSetLength(len);
+}
+
+int Trim(TCHAR *s) {
+  ASSERT(s, (L""));
+
+  // First find end of leading spaces
+  TCHAR *start = s;
+  while (*start) {
+    if (!IsSpace(*start))
+      break;
+    ++start;
+  }
+
+  // Now search for the end, remembering the start of the last spaces
+  TCHAR *end = start;
+  TCHAR *last_space = end;
+  while (*end) {
+    if (!IsSpace(*end))
+      last_space = end + 1;
+    ++end;
+  }
+
+  // Copy the part we want
+  int len = last_space - start;
+  // lint -e{802}  Conceivably passing a NULL pointer
+  memmove(s, start, len * sizeof(TCHAR));
+
+  // 0 terminate
+  s[len] = 0;
+
+  return len;
+}
+
+void TrimString(CString& s, const TCHAR* delimiters) {
+  s = s.Trim(delimiters);
+}
+
+// Strip the first token from the front of argument s.  A token is a
+// series of consecutive non-blank characters - unless the first
+// character is a double-quote ("), in that case the token is the full
+// quoted string
+CString StripFirstQuotedToken(const CString& s) {
+  const int npos = -1;
+
+  // Make a writeable copy
+  CString str(s);
+
+  // Trim any surrounding blanks (and tabs, for the heck of it)
+  TrimString(str, L" \t");
+
+  // Too short to have a second token
+  if (str.GetLength() <= 1)
+    return L"";
+
+  // What kind of token are we stripping?
+  if (str[0] == L'\"') {
+    // Remove leading quoting string
+    int i = str.Find(L"\"", 1);
+    if (i != npos)
+      i++;
+    return str.Mid(i);
+  } else {
+    // Remove leading token
+    int i = str.FindOneOf(L" \t");
+    if (i != npos)
+      i++;
+    return str.Mid(i);
+  }
+}
+
+// A block of text to separate lines, and back
+void TextToLines(const CString& text, const TCHAR* delimiter, std::vector<CString>* lines) {
+  ASSERT(delimiter, (L""));
+  ASSERT(lines, (L""));
+
+  size_t delimiter_len = ::lstrlen(delimiter);
+  int b = 0;
+  int e = 0;
+
+  for (b = 0; e != -1 && b < text.GetLength(); b = e + delimiter_len) {
+    e = text.Find(delimiter, b);
+    if (e != -1) {
+      ASSERT1(e - b > 0);
+      lines->push_back(text.Mid(b, e - b));
+    } else {
+      lines->push_back(text.Mid(b));
+    }
+  }
+}
+
+void LinesToText(const std::vector<CString>& lines, const TCHAR* delimiter, CString* text) {
+  ASSERT(delimiter, (L""));
+  ASSERT(text, (L""));
+
+  size_t delimiter_len = ::lstrlen(delimiter);
+  size_t len = 0;
+  for (size_t i = 0; i < lines.size(); ++i) {
+    len += lines[i].GetLength() + delimiter_len;
+  }
+  text->Empty();
+  text->Preallocate(len);
+  for (std::vector<CString>::size_type i = 0; i < lines.size(); ++i) {
+    text->Append(lines[i]);
+    if (delimiter_len) {
+      text->Append(delimiter);
+    }
+  }
+}
+
+int CleanupWhitespaceCString(CString &s) {
+  int len = CleanupWhitespace(s.GetBuffer());
+  s.ReleaseBufferSetLength(len);
+  return len;
+}
+
+int CleanupWhitespace(TCHAR *str) {
+  ASSERT(str, (L""));
+
+  TCHAR *src      = str;
+  TCHAR *dest     = str;
+  int    spaces   = 0;
+  bool   at_start = true;
+  while (true) {
+    // At end of string?
+    TCHAR c = *src;
+    if (0 == c)
+      break;
+
+    // Look for whitespace; copy it over if not whitespace
+    if (IsSpace(c)) {
+      ++spaces;
+    }
+    else {
+      *dest++ = c;
+      at_start = false;
+      spaces = 0;
+    }
+
+    // Write only first consecutive space (but skip space at start)
+    if (1 == spaces && !at_start)
+      *dest++ = ' ';
+
+    ++src;
+  }
+
+  // Remove trailing space, if any
+  if (dest > str && *(dest - 1) == L' ')
+    --dest;
+
+  // 0-terminate
+  *dest = 0;
+
+  return dest - str;
+}
+
+// Take 1 single hexadecimal "digit" (as a character) and return its decimal value
+// Returns -1 if given invalid hex digit
+int HexDigitToDec(const TCHAR digit) {
+  if (digit >= L'A' && digit <= L'F')
+    return 10 + (digit - L'A');
+  else if (digit >= L'a' && digit <= L'f')
+    return 10 + (digit - L'a');
+  else if (digit >= L'0' && digit <= L'9')
+    return (digit - L'0');
+  else
+    return -1;
+}
+
+// Convert the 2 hex chars at positions <pos> and <pos>+1 in <s> to a char (<char_out>)
+// Note: scanf was giving me troubles, so here's the manual version
+// Extracted char gets written to <char_out>, which must be allocated by
+// the caller; return true on success or false if parameters are incorrect
+// or string does not have 2 hex digits at the specified position
+// NOTE: <char_out> is NOT a string, just a pointer to a char for the result
+bool ExtractChar(const CString & s, int pos, unsigned char * char_out) {
+  // char_out may be NULL
+
+  if (s.GetLength() < pos + 1) {
+    return false;
+  }
+
+  if (pos < 0 || NULL == char_out) {
+    ASSERT(0, (_T("invalid params: pos<0 or char_out is NULL")));
+    return false;
+  }
+
+  TCHAR c1 = s.GetAt(pos);
+  TCHAR c2 = s.GetAt(pos+1);
+
+  int p1 = HexDigitToDec(c1);
+  int p2 = HexDigitToDec(c2);
+
+  if (p1 == -1 || p2 == -1) {
+    return false;
+  }
+
+  *char_out = (unsigned char)(p1 * 16 + p2);
+  return true;
+}
+
+WCHAR *ToWide (const char *s, int len) {
+    ASSERT (s, (L""));
+    WCHAR *w = new WCHAR [len+1]; if (!w) { return NULL; }
+    // int rc = MultiByteToWideChar (CP_ACP, 0, s.GetString(), (int)s.GetLength()+1, w, s.GetLength()+1);
+    // TODO(omaha): why would it ever be the case that rc > len?
+    int rc = MultiByteToWideChar (CP_ACP, 0, s, len, w, len);
+    if (rc > len) { delete [] w; return NULL; }
+    // ASSERT (rc <= len, (L""));
+    w[rc]=L'\0';
+    return w;
+}
+
+const byte *BufferContains (const byte *buf, uint32 buf_len, const byte *data, uint32 data_len) {
+  ASSERT(data, (L""));
+  ASSERT(buf, (L""));
+
+  for (uint32 i = 0; i < buf_len; i++) {
+    uint32 j = i;
+    uint32 k = 0;
+    uint32 len = 0;
+    while (j < buf_len && k < data_len && buf[j++] == data[k++]) { len++; }
+    if (len == data_len) { return buf + i; }
+  }
+  return 0;
+}
+
+// Converting the Ansi Multibyte String into unicode string. The multibyte
+// string is encoded using the specified codepage.
+// The code is pretty much like the U2W function, except the codepage can be
+// any valid windows CP.
+BOOL AnsiToWideString(const char *from, int length, UINT codepage, CString *to) {
+  ASSERT(from, (L""));
+  ASSERT(to, (L""));
+  ASSERT1(length >= -1);
+  // Figure out how long the string is
+  int req_chars = MultiByteToWideChar(codepage, 0, from, length, NULL, 0);
+
+  if (req_chars <= 0) {
+    UTIL_LOG(LEVEL_WARNING, (_T("MultiByteToWideChar Failed ")));
+    *to = AnsiToWideString(from, length);
+    return FALSE;
+  }
+
+  TCHAR *buffer = to->GetBufferSetLength(req_chars);
+  int conv_chars = MultiByteToWideChar(codepage, 0, from, length, buffer, req_chars);
+  if (conv_chars == 0) {
+    UTIL_LOG(LEVEL_WARNING, (_T("MultiByteToWideChar Failed ")));
+    to->ReleaseBuffer(0);
+    *to = AnsiToWideString(from, length);
+    return FALSE;
+  }
+
+  // Something truly horrible happened.
+  ASSERT (req_chars == conv_chars, (L"MBToWide returned unexpected value: GetLastError()=%d",GetLastError()));
+  // If length was inferred, conv_chars includes the null terminator.
+  // Adjust the length here to remove null termination,
+  // because we use the length-qualified CString constructor,
+  // which automatically adds null termination given an unterminated array.
+  if (-1 == length) { --conv_chars; }
+  to->ReleaseBuffer(conv_chars);
+  return TRUE;
+}
+
+// CStringW(const char* from) did not cast all character properly
+// so we write our own.
+CString AnsiToWideString(const char *from, int length) {
+  ASSERT(from, (L""));
+  ASSERT1(length >= -1);
+  if (length < 0)
+    length = strlen(from);
+  CString to;
+  TCHAR *buffer = to.GetBufferSetLength(length);
+  for (int i = 0; i < length; ++i)
+      buffer[i] = static_cast<UINT8>(from[i]);
+  to.ReleaseBuffer(length);
+  return to;
+}
+
+
+// Transform a unicode string into UTF8, as represented in an ASCII string
+CStringA WideToUtf8(const CString& w) {
+  // Add a cutoff. If it's all ascii, convert it directly
+  const TCHAR* input = static_cast<const TCHAR*>(w.GetString());
+  int input_len = w.GetLength(), i;
+  for (i = 0; i < input_len; ++i) {
+    if (input[i] > 127) {
+      break;
+    }
+  }
+
+  // If we made it to the end without breaking, then it's all ANSI, so do a quick convert
+  if (i == input_len) {
+    return WideToAnsiDirect(w);
+  }
+
+  // Figure out how long the string is
+  int req_bytes = ::WideCharToMultiByte(CP_UTF8, 0, w, -1, NULL, 0, NULL, NULL);
+
+  scoped_array<char> utf8_buffer(new char[req_bytes]);
+
+  int conv_bytes = ::WideCharToMultiByte(CP_UTF8, 0, w, -1, utf8_buffer.get(), req_bytes, NULL, NULL);
+  ASSERT1(req_bytes == conv_bytes);
+
+  // conv_bytes includes the null terminator, when we read this in, don't read the terminator
+  CStringA out(utf8_buffer.get(), conv_bytes - 1);
+
+  return out;
+}
+
+CString Utf8ToWideChar(const char* utf8, uint32 num_bytes) {
+  ASSERT1(utf8);
+  if (num_bytes == 0) {
+    // It's OK to use lstrlenA to count the number of characters in utf8 because
+    // UTF-8 encoding has the nice property of not having any embedded NULLs.
+    num_bytes = lstrlenA(utf8);
+  }
+
+  uint32 number_of_wide_chars = ::MultiByteToWideChar(CP_UTF8, 0, utf8, num_bytes, NULL, 0);
+  number_of_wide_chars += 1;  // make room for NULL terminator
+
+  CString ret_string;
+  TCHAR* buffer = ret_string.GetBuffer(number_of_wide_chars);
+  DWORD number_of_characters_copied = ::MultiByteToWideChar(CP_UTF8, 0, utf8, num_bytes, buffer, number_of_wide_chars);
+  ASSERT1(number_of_characters_copied == number_of_wide_chars - 1);
+  buffer[number_of_wide_chars - 1] = _T('\0');  // ensure there is a NULL terminator
+  ret_string.ReleaseBuffer();
+
+  // Strip the byte order marker if there is one in the document.
+  if (ret_string[0] == kUnicodeBom) {
+    ret_string = ret_string.Right(ret_string.GetLength() - 1);
+  }
+
+  if (number_of_characters_copied > 0) {
+    return ret_string;
+  }
+
+  // Failure case
+  return _T("");
+}
+
+CString Utf8BufferToWideChar(const std::vector<uint8>& buffer) {
+  CString result;
+  if (!buffer.empty()) {
+    result = Utf8ToWideChar(
+        reinterpret_cast<const char*>(&buffer.front()), buffer.size());
+  }
+  return result;
+}
+
+CString AbbreviateString (const CString & title, int32 max_len) {
+    ASSERT (max_len, (L""));
+    CString s(title);
+    TrimCString(s);  // remove whitespace at start/end
+    if (s.GetLength() > max_len) {
+        s = s.Left (max_len - 2);
+        CString orig(s);
+        // remove partial words
+        while (s.GetLength() > 1 && !IsSpace(s[s.GetLength()-1])) { s = s.Left (s.GetLength() - 1); }
+        // but not if it would make the string very short
+        if (s.GetLength() < max_len / 2) { s = orig; }
+        s += _T("..");
+        }
+
+    return s;
+}
+
+CString GetAbsoluteUri(const CString& uri) {
+  int i = String_FindString(uri, _T("://"));
+  if (i==-1) return uri;
+
+  // add trailing / if none exists
+  int j = String_FindChar(uri, L'/',i+3);
+  if (j==-1) return (uri+NOTRANSL(_T("/")));
+
+  // remove duplicate trailing slashes
+  int len = uri.GetLength();
+  if (len > 1 && uri.GetAt(len-1) == '/' && uri.GetAt(len-2) == '/') {
+    CString new_uri(uri);
+    int new_len = new_uri.GetLength();
+    while (new_len > 1 && new_uri.GetAt(new_len-1) == '/' && new_uri.GetAt(new_len-2) == '/') {
+      new_len--;
+      new_uri = new_uri.Left(new_len);
+    }
+    return new_uri;
+  }
+  else return uri;
+}
+
+// requires that input have a PROTOCOL (http://) for proper behavior
+// items with the "file" protocol are returned as is (what is the hostname in that case? C: ? doesn't make sense)
+// TODO(omaha): loosen requirement
+// includes http://, e.g. http://www.google.com/
+CString GetUriHostName(const CString& uri, bool strip_leading) {
+  if (String_StartsWith(uri,NOTRANSL(_T("file:")),true)) return uri;
+
+  // correct any "errors"
+  CString s(GetAbsoluteUri(uri));
+
+  // Strip the leading "www."
+  if (strip_leading)
+  {
+    int index_www = String_FindString(s, kStrLeadingWww);
+    if (index_www != -1)
+      ReplaceCString (s, kStrLeadingWww, _T(""));
+  }
+
+  int i = String_FindString(s, _T("://"));
+  if(i==-1) return uri;
+  int j = String_FindChar(s, L'/',i+3);
+  if(j==-1) return uri;
+  return s.Left(j+1);
+}
+
+// requires that input have a PROTOCOL (http://) for proper behavior
+// TODO(omaha): loosen requirement
+// removes the http:// and the extra slash '/' at the end.
+// http://www.google.com/ -> www.google.com (or google.com if strip_leading = true)
+CString GetUriHostNameHostOnly(const CString& uri, bool strip_leading) {
+  CString s(GetUriHostName(uri,strip_leading));
+
+  // remove protocol
+  int i = String_FindString (s, _T("://"));
+  if(i==-1) return s;
+  CString ss(s.Right (s.GetLength() - i-3));
+
+  // remove the last '/'
+  int j = ss.ReverseFind('/');
+  if (j == -1) return ss;
+  return ss.Left(j);
+}
+
+CString AbbreviateUri(const CString& uri, int32 max_len) {
+  ASSERT1(max_len);
+  ASSERT1(!uri.IsEmpty());
+
+  CString s(uri);
+  VERIFY1(String_FindString (s, _T("://")));
+
+  TrimCString(s);
+  // SKIP_LOC_BEGIN
+  RemoveFromStart (s, _T("ftp://"), false);
+  RemoveFromStart (s, _T("http://"), false);
+  RemoveFromStart (s, _T("https://"), false);
+  RemoveFromStart (s, _T("www."), false);
+  RemoveFromStart (s, _T("ftp."), false);
+  RemoveFromStart (s, _T("www-"), false);
+  RemoveFromStart (s, _T("ftp-"), false);
+  RemoveFromEnd (s, _T(".htm"));
+  RemoveFromEnd (s, _T(".html"));
+  RemoveFromEnd (s, _T(".asp"));
+  // SKIP_LOC_END
+  if (s.GetLength() > max_len) {
+    // try to keep the portion after the last /
+    int32 last_slash = s.ReverseFind ((TCHAR)'/');
+    CString after_last_slash;
+    if (last_slash == -1) { after_last_slash = _T(""); }
+    else { after_last_slash = s.Right (uri.GetLength() - last_slash - 1); }
+    if (after_last_slash.GetLength() > max_len / 2) {
+        after_last_slash = after_last_slash.Right (max_len / 2);
+    }
+    s = s.Left (max_len - after_last_slash.GetLength() - 2);
+    s += "..";
+    s += after_last_slash;
+  }
+  return s;
+}
+
+// normalized version of a URI intended to map duplicates to the same string
+// the normalized URI is not a valid URI
+CString NormalizeUri (const CString & uri) {
+  CString s(uri);
+  TrimCString(s);
+  MakeLowerCString(s);
+  // SKIP_LOC_BEGIN
+  ReplaceCString (s, _T(":80"), _T(""));
+
+  RemoveFromEnd (s, _T("/index.html"));
+  RemoveFromEnd (s, _T("/welcome.html"));  // old netscape standard
+  RemoveFromEnd (s, _T("/"));
+
+  RemoveFromStart (s, _T("ftp://"), false);
+  RemoveFromStart (s, _T("http://"), false);
+  RemoveFromStart (s, _T("https://"), false);
+  RemoveFromStart (s, _T("www."), false);
+  RemoveFromStart (s, _T("ftp."), false);
+  RemoveFromStart (s, _T("www-"), false);
+  RemoveFromStart (s, _T("ftp-"), false);
+
+  ReplaceCString (s, _T("/./"), _T("/"));
+  // SKIP_LOC_END
+
+  // TODO(omaha):
+  // fixup URLs like a/b/../../c
+  // while ($s =~ m!\/\.\.\!!) {
+  //    $s =~ s!/[^/]*/\.\./!/!;
+  //    }
+
+  // TODO(omaha):
+  // unescape characters
+  // Note from RFC1630:  "Sequences which start with a percent sign
+  // but are not followed by two hexadecimal characters are reserved
+  // for future extension"
+  // $str =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg if defined $str;
+
+  return s;
+}
+
+CString RemoveInternetProtocolHeader (const CString& url) {
+  int find_colon_slash_slash = String_FindString(url, NOTRANSL(L"://"));
+  if( find_colon_slash_slash != -1 ) {
+    // remove PROTOCOL://
+    return url.Right(url.GetLength() - find_colon_slash_slash - 3);
+  } else if (String_StartsWith(url, NOTRANSL(L"mailto:"), true)) {
+    // remove "mailto:"
+    return url.Right(url.GetLength() - 7);
+  } else {
+    // return as is
+    return url;
+  }
+}
+
+void RemoveFromStart (CString & s, const TCHAR* remove, bool ignore_case) {
+  ASSERT(remove, (L""));
+
+  // Remove the characters if it is the prefix
+  if (String_StartsWith(s, remove, ignore_case))
+    s.Delete(0, lstrlen(remove));
+}
+
+bool String_EndsWith(const TCHAR *str, const TCHAR *end_str, bool ignore_case) {
+  ASSERT(end_str, (L""));
+  ASSERT(str, (L""));
+
+  int str_len = lstrlen(str);
+  int end_len = lstrlen(end_str);
+
+  // Definitely false if the suffix is longer than the string
+  if (end_len > str_len)
+    return false;
+
+  const TCHAR *str_ptr = str + str_len;
+  const TCHAR *end_ptr = end_str + end_len;
+
+  while (end_ptr >= end_str) {
+    // Check for matching characters
+    TCHAR c1 = *str_ptr;
+    TCHAR c2 = *end_ptr;
+
+    if (ignore_case) {
+      c1 = Char_ToLower(c1);
+      c2 = Char_ToLower(c2);
+    }
+
+    if (c1 != c2)
+      return false;
+
+    --str_ptr;
+    --end_ptr;
+  }
+
+  // if we haven't failed out, it must be ok!
+  return true;
+}
+
+CString String_MakeEndWith(const TCHAR* str, const TCHAR* end_str, bool ignore_case) {
+  if (String_EndsWith(str, end_str, ignore_case)) {
+    return str;
+  } else {
+    CString r(str);
+    r += end_str;
+    return r;
+  }
+}
+
+void RemoveFromEnd (CString & s, const TCHAR* remove) {
+  ASSERT(remove, (L""));
+
+  // If the suffix is shorter than the string, don't bother
+  int remove_len = lstrlen(remove);
+  if (s.GetLength() < remove_len) return;
+
+  // If the suffix is equal
+  int suffix_begin = s.GetLength() - remove_len;
+  if (0 == lstrcmp(s.GetString() + suffix_begin, remove))
+    s.Delete(suffix_begin, remove_len);
+}
+
+CString ElideIfNeeded (const CString & input_string, int max_len, int min_len) {
+  ASSERT (min_len <= max_len, (L""));
+  ASSERT (max_len >= TSTR_SIZE(kEllipsis)+1, (L""));
+  ASSERT (min_len >= TSTR_SIZE(kEllipsis)+1, (L""));
+
+  CString s = input_string;
+
+  s.TrimRight();
+  if (s.GetLength() > max_len) {
+    int truncate_at = max_len - TSTR_SIZE(kEllipsis);
+    // find first space going backwards from character one after the truncation point
+    while (truncate_at >= min_len && !IsSpace(s.GetAt(truncate_at)))
+      truncate_at--;
+
+    // skip the space(s)
+    while (truncate_at >= min_len && IsSpace(s.GetAt(truncate_at)))
+      truncate_at--;
+
+    truncate_at++;
+
+    if (truncate_at <= min_len || truncate_at > (max_len - static_cast<int>(TSTR_SIZE(kEllipsis)))) {
+      // we weren't able to break at a word boundary, may as well use more of the string
+      truncate_at = max_len - TSTR_SIZE(kEllipsis);
+
+      // skip space(s)
+      while (truncate_at > 0 && IsSpace(s.GetAt(truncate_at-1)))
+        truncate_at--;
+    }
+
+    s = s.Left(truncate_at);
+    s += kEllipsis;
+  }
+
+  UTIL_LOG(L6, (L"elide (%d %d) %s -> %s", min_len, max_len, input_string, s));
+  return s;
+}
+
+// these functions untested
+// UTF8 parameter supported on XP/2000 only
+HRESULT AnsiToUTF8 (char * src, int src_len, char * dest, int *dest_len) {
+  ASSERT (dest_len, (L""));
+  ASSERT (dest, (L""));
+  ASSERT (src, (L""));
+
+  // First use MultiByteToWideChar(CP_UTF8, ...) to convert to Unicode
+  // then use WideCharToMultiByte to convert from Unicode to UTF8
+  WCHAR *unicode = new WCHAR [(src_len + 1) * sizeof (TCHAR)]; ASSERT (unicode, (L""));
+  int chars_written = MultiByteToWideChar (CP_ACP, 0, src, src_len, unicode, src_len);
+  ASSERT (chars_written == src_len, (L""));
+  char *unmappable = " ";
+  BOOL unmappable_characters = false;
+  *dest_len = WideCharToMultiByte (CP_UTF8, 0, unicode, chars_written, dest, *dest_len, unmappable, &unmappable_characters);
+  delete [] unicode;
+  return S_OK;
+}
+
+// Convert Wide to ANSI directly. Use only when it is all ANSI
+CStringA WideToAnsiDirect(const CString & in) {
+  int in_len = in.GetLength();
+  const TCHAR * in_buf = static_cast<const TCHAR*>(in.GetString());
+
+  CStringA out;
+  unsigned char * out_buf = (unsigned char *)out.GetBufferSetLength(in_len);
+
+  for(int i = 0; i < in_len; ++i)
+    out_buf[i] = static_cast<unsigned char>(in_buf[i]);
+
+  out.ReleaseBuffer(in_len);
+  return out;
+}
+
+HRESULT UCS2ToUTF8 (LPCWSTR src, int src_len, char * dest, int *dest_len) {
+  ASSERT(dest_len, (L""));
+  ASSERT(dest, (L""));
+
+  *dest_len = WideCharToMultiByte (CP_UTF8, 0, src, src_len, dest, *dest_len, NULL,NULL);
+  return S_OK;
+}
+
+HRESULT UTF8ToUCS2 (const char * src, int src_len, LPWSTR dest, int *dest_len) {
+  ASSERT (dest_len, (L""));
+  ASSERT (src, (L""));
+
+  *dest_len = MultiByteToWideChar (CP_UTF8, 0, src, src_len, dest, *dest_len);
+  ASSERT (*dest_len == src_len, (L""));
+  return S_OK;
+}
+
+HRESULT UTF8ToAnsi (char * src, int, char * dest, int *dest_len) {
+  ASSERT(dest_len, (L""));
+  ASSERT(dest, (L""));
+  ASSERT(src, (L""));
+
+  src; dest; dest_len;  // unreferenced formal parameter
+
+  // First use MultiByteToWideChar(CP_UTF8, ...) to convert to Unicode
+  // then use WideCharToMultiByte to convert from Unicode to ANSI
+  return E_FAIL;
+}
+
+// clean up a string so it can be included within a JavaScript string
+// mainly involves escaping characters
+CString SanitizeString(const CString & in, DWORD mode) {
+  CString out(in);
+
+  if (mode & kSanHtml) {
+    // SKIP_LOC_BEGIN
+    ReplaceCString(out, _T("&"), _T("&amp;"));
+    ReplaceCString(out, _T("<"), _T("&lt;"));
+    ReplaceCString(out, _T(">"), _T("&gt;"));
+    // SKIP_LOC_END
+  }
+
+  if ((mode & kSanXml) == kSanXml) {
+    // SKIP_LOC_BEGIN
+    ReplaceCString(out, _T("'"), _T("&apos;"));
+    ReplaceCString(out, _T("\""), _T("&quot;"));
+    // SKIP_LOC_END
+  }
+
+  // Note that this SAN_JAVASCRIPT and kSanXml should not be used together.
+  ASSERT ((mode & (kSanJs | kSanXml)) != (kSanJs | kSanXml), (L""));
+
+  if ((mode & kSanJs) == kSanJs) {
+    // SKIP_LOC_BEGIN
+    ReplaceCString(out, _T("\\"), _T("\\\\"));
+    ReplaceCString(out, _T("\'"), _T("\\\'"));
+    ReplaceCString(out, _T("\""), _T("\\\""));
+    ReplaceCString(out, _T("\n"), _T(" "));
+    ReplaceCString(out, _T("\t"), _T(" "));
+    // SKIP_LOC_END
+  }
+
+  if ((mode & kSanHtmlInput) == kSanHtmlInput) {
+    // SKIP_LOC_BEGIN
+    ReplaceCString(out, _T("\""), _T("&quot;"));
+    ReplaceCString(out, _T("'"), _T("&#39;"));
+    // SKIP_LOC_END
+  }
+
+  return out;
+}
+
+// Bolds the periods used for abbreviation.  Call this after HighlightTerms.
+CString BoldAbbreviationPeriods(const CString & in) {
+  CString out(in);
+  CString abbrev;
+  for (int i = 0; i < kAbbreviationPeriodLength; ++i)
+    abbrev += _T(".");
+  ReplaceCString(out, abbrev, NOTRANSL(_T("<b>")) + abbrev + NOTRANSL(_T("</b>")));
+  return out;
+}
+
+// Unescape a escaped sequence leading by a percentage symbol '%',
+// and converted the unescaped sequence (in UTF8) into unicode.
+// Inputs:  src is the input string.
+//          pos is the starting position.
+// Returns: true if a EOS(null) char was encounted.
+//          out contains the unescaped and converted unicode string.
+//          consumed_length is how many bytes in the src string have been
+//          unescaped.
+// We can avoid the expensive UTF8 conversion step if there are no higher
+// ansi characters So if there aren't any, just convert it ANSI-to-WIDE
+// directly, which is cheaper.
+inline bool UnescapeSequence(const CString &src, int pos,
+                             CStringW *out, int *consumed_length) {
+  ASSERT1(out);
+  ASSERT1(consumed_length);
+
+  int length = src.GetLength();
+  // (input_len - pos) / 3 is enough for un-escaping the (%xx)+ sequences.
+  int max_dst_length = (length - pos) / 3;
+  scoped_array<char> unescaped(new char[max_dst_length]);
+  char *buf = unescaped.get();
+  if (buf == NULL) {  // no enough space ???
+    *consumed_length = 0;
+    return false;
+  }
+  char *dst = buf;
+  bool is_utf8 = false;
+  // It is possible that there is a null character '\0' in the sequence.
+  // Because the CStringT does't support '\0' in it, we stop
+  // parsing the input string when it is encounted.
+  bool eos_encounted = false;
+  uint8 ch;
+  int s = pos;
+  while (s + 2 < length && src[s] == '%' && !eos_encounted &&
+         ExtractChar(src, s + 1, &ch)) {
+    if (ch != 0)
+      *dst++ = ch;
+    else
+      eos_encounted = true;
+    if (ch >= 128)
+      is_utf8 = true;
+    s += 3;
+  }
+
+  ASSERT1(dst <= buf + max_dst_length);  // just to make sure
+
+  *consumed_length = s - pos;
+  if (is_utf8)
+    AnsiToWideString(buf, dst - buf, CP_UTF8, out);
+  else
+    *out = AnsiToWideString(buf, dst - buf);
+  return eos_encounted;
+}
+
+// There is an encoding called "URL-encoding". This function takes a URL-encoded string
+// and converts it back to the original representation
+// example: "?q=moon+doggy_%25%5E%26&" = "moon doggy_%^&"
+CString Unencode(const CString &input) {
+  const int input_len = input.GetLength();
+  const TCHAR *src = input.GetString();
+  // input_len is enough for containing the unencoded string.
+  CString out;
+  TCHAR *head = out.GetBuffer(input_len);
+  TCHAR *dst = head;
+  int s = 0;
+  bool eos_encounted = false;
+  bool is_utf8 = false;
+  CStringW fragment;
+  int consumed_length = 0;
+  while (s < input_len && !eos_encounted) {
+    switch (src[s]) {
+      case '+' :
+        *dst++ = ' ';
+        ASSERT1(dst <= head + input_len);
+        ++s;
+        break;
+      case '%' :
+        eos_encounted =
+          UnescapeSequence(input, s, &fragment, &consumed_length);
+        if (consumed_length > 0) {
+          s += consumed_length;
+          ASSERT1(dst + fragment.GetLength() <= head + input_len);
+          for (int i = 0; i < fragment.GetLength(); ++i)
+            *dst++ = fragment[i];
+        } else {
+          *dst++ = src[s++];
+          ASSERT1(dst <= head + input_len);
+        }
+        break;
+      default:
+        *dst++ = src[s];
+        ASSERT1(dst <= head + input_len);
+        ++s;
+    }
+  }
+  int out_len = dst - head;
+  out.ReleaseBuffer(out_len);
+  return out;
+}
+
+CString GetTextInbetween(const CString &input, const CString &start, const CString &end) {
+  int start_index = String_FindString(input, start);
+  if (start_index == -1)
+    return L"";
+
+  start_index += start.GetLength();
+  int end_index = String_FindString(input, end, start_index);
+  if (end_index == -1)
+    return L"";
+
+  return input.Mid(start_index, end_index - start_index);
+}
+
+// Given a string, get the parameter and url-unencode it
+CString GetParam(const CString & input, const CString & key) {
+  CString my_key(_T("?"));
+  my_key.Append(key);
+  my_key += L'=';
+
+  return Unencode(GetTextInbetween(input, my_key, NOTRANSL(L"?")));
+}
+
+// Get an xml-like field from a string
+CString GetField (const CString & input, const CString & field) {
+  CString start_field(NOTRANSL(_T("<")));
+  start_field += field;
+  start_field += L'>';
+
+  int32 start = String_FindString(input, start_field);
+  if (start == -1) { return _T(""); }
+  start += 2 + lstrlen (field);
+
+  CString end_field(NOTRANSL(_T("</")));
+  end_field += field;
+  end_field += L'>';
+
+  int32 end = String_FindString(input, end_field);
+  if (end == -1) { return _T(""); }
+
+  return input.Mid (start, end - start);
+}
+
+// ------------------------------------------------------------
+// Finds a whole word match in the query.
+// If the word has non-spaces either before or after, it will not qualify as
+//   a match.  i.e. "pie!" is not a match because of the exclamation point.
+// TODO(omaha): Add parameter that will consider punctuation acceptable.
+//
+// Optionally will look for a colon at the end.
+// If not found, return -1.
+int FindWholeWordMatch (const CString &query,
+  const CString &word_to_match,
+  const bool end_with_colon,
+  const int index_begin) {
+  if (word_to_match.IsEmpty()) {
+    return -1;
+  }
+
+  int index_word_begin = index_begin;
+
+  // Keep going until we find a whole word match, or the string ends.
+  do {
+    index_word_begin = String_FindString (query, word_to_match, index_word_begin);
+
+    if (-1 == index_word_begin) {
+      return index_word_begin;
+    }
+
+    // If it's not a whole word match, keep going.
+    if (index_word_begin > 0 &&
+      !IsSpaceW (query[index_word_begin - 1])) {
+      goto LoopEnd;
+    }
+
+    if (end_with_colon) {
+      int index_colon = String_FindChar (query, L':', index_word_begin);
+
+      // If there is no colon in the string, return now.
+      if (-1 == index_colon) {
+        return -1;
+      }
+
+      // If there is text between the end of the word and the colon, keep going.
+      if (index_colon - index_word_begin != word_to_match.GetLength()) {
+        goto LoopEnd;
+      }
+    } else {
+      // If there are more chars left after this word/phrase, and
+      // they are not spaces, return.
+      if (query.GetLength() > index_word_begin + word_to_match.GetLength() &&
+        !IsSpaceW (query.GetAt (index_word_begin + word_to_match.GetLength()))) {
+        goto LoopEnd;
+      }
+    }
+
+    // It fits all the requirements, so return the index to the beginning of the word.
+    return index_word_begin;
+
+LoopEnd:
+    ++index_word_begin;
+
+  } while (-1 != index_word_begin);
+
+  return index_word_begin;
+}
+
+// --------------------------------------------------------
+// Do whole-word replacement in "str".
+void ReplaceWholeWord (const CString &string_to_replace,
+  const CString &replacement,
+  const bool trim_whitespace,
+  CString *str) {
+  ASSERT (str, (L"ReplaceWholeWord"));
+
+  if (string_to_replace.IsEmpty() || str->IsEmpty()) {
+    return;
+  }
+
+  int index_str = 0;
+  do {
+    index_str = FindWholeWordMatch (*str, string_to_replace, false, index_str);
+
+    if (-1 != index_str) {
+      // Get the strings before and after, and trim whitespace.
+      CString str_before_word(str->Left (index_str));
+      if (trim_whitespace) {
+        str_before_word.TrimRight();
+      }
+
+      CString str_after_word(str->Mid (index_str + string_to_replace.GetLength()));
+      if (trim_whitespace) {
+        str_after_word.TrimLeft();
+      }
+
+      *str = str_before_word + replacement + str_after_word;
+      index_str += replacement.GetLength() + 1;
+    }
+  } while (index_str != -1);
+}
+
+// --------------------------------------------------------
+// Reverse (big-endian<->little-endian) the shorts that make up
+// Unicode characters in a byte array of Unicode chars
+HRESULT ReverseUnicodeByteOrder(byte* unicode_string, int size_in_bytes) {
+  ASSERT (unicode_string, (L""));
+
+  // If odd # of bytes, just leave the last one alone
+  for (int i = 0; i < size_in_bytes - 1; i += 2) {
+    byte b = unicode_string[i];
+    unicode_string[i] = unicode_string[i+1];
+    unicode_string[i+1] = b;
+  }
+
+  return S_OK;
+}
+
+// case insensitive strstr
+// adapted from http://c.snippets.org/snip_lister.php?fname=stristr.c
+const char *stristr(const char *string, const char *pattern)
+{
+  ASSERT (pattern, (L""));
+  ASSERT (string, (L""));
+  ASSERT (string && pattern, (L""));
+  char *pattern_ptr, *string_ptr;
+  const char *start;
+
+  for (start = string; *start != 0; start++)
+  {
+    // find start of pattern in string
+    for ( ; ((*start!=0) && (String_ToUpperA(*start) != String_ToUpperA(*pattern))); start++)
+     ;
+    if (0 == *start)
+     return NULL;
+
+    pattern_ptr = (char *)pattern;
+    string_ptr = (char *)start;
+
+    while (String_ToUpperA(*string_ptr) == String_ToUpperA(*pattern_ptr))
+    {
+      string_ptr++;
+      pattern_ptr++;
+
+      // if end of pattern then pattern was found
+      if (0 == *pattern_ptr)
+        return (start);
+    }
+  }
+
+  return NULL;
+}
+
+// case insensitive Unicode strstr
+// adapted from http://c.snippets.org/snip_lister.php?fname=stristr.c
+const WCHAR *stristrW(const WCHAR *string, const WCHAR *pattern)
+{
+  ASSERT (pattern, (L""));
+  ASSERT (string, (L""));
+  ASSERT (string && pattern, (L""));
+  const WCHAR *start;
+
+  for (start = string; *start != 0; start++)
+  {
+    // find start of pattern in string
+    for ( ; ((*start!=0) && (String_ToUpper(*start) != String_ToUpper(*pattern))); start++)
+     ;
+    if (0 == *start)
+     return NULL;
+
+    const WCHAR *pattern_ptr = pattern;
+    const WCHAR *string_ptr = start;
+
+    while (String_ToUpper(*string_ptr) == String_ToUpper(*pattern_ptr))
+    {
+      string_ptr++;
+      pattern_ptr++;
+
+      // if end of pattern then pattern was found
+      if (0 == *pattern_ptr)
+        return (start);
+    }
+  }
+
+  return NULL;
+}
+
+// case sensitive Unicode strstr
+// adapted from http://c.snippets.org/snip_lister.php?fname=stristr.c
+const WCHAR *strstrW(const WCHAR *string, const WCHAR *pattern)
+{
+  ASSERT (pattern, (L""));
+  ASSERT (string, (L""));
+  ASSERT (string && pattern, (L""));
+  const WCHAR *start;
+
+  for (start = string; *start != 0; start++)
+  {
+    // find start of pattern in string
+    for ( ; ((*start!=0) && (*start != *pattern)); start++)
+     ;
+    if (0 == *start)
+     return NULL;
+
+    const WCHAR *pattern_ptr = pattern;
+    const WCHAR *string_ptr = start;
+
+    while (*string_ptr == *pattern_ptr)
+    {
+      string_ptr++;
+      pattern_ptr++;
+
+      // if end of pattern then pattern was found
+      if (0 == *pattern_ptr)
+        return (start);
+    }
+  }
+
+  return NULL;
+}
+
+// -------------------------------------------------------------------------
+// Helper function
+float GetLenWithWordWrap (const float len_so_far,
+  const float len_to_add,
+  const uint32 len_line) {
+  // lint -save -e414  Possible division by 0
+  ASSERT (len_line != 0, (L""));
+
+  float len_total = len_so_far + len_to_add;
+
+  // Figure out if we need to word wrap by seeing if adding the second
+  // string will cause us to span more lines than before.
+  uint32 num_lines_before = static_cast<uint32> (len_so_far / len_line);
+  uint32 num_lines_after = static_cast<uint32> (len_total / len_line);
+
+  // If it just barely fit onto the line, do not wrap to the next line.
+  if (num_lines_after > 0 && (len_total / len_line - num_lines_after == 0)) {
+    --num_lines_after;
+  }
+
+  if (num_lines_after > num_lines_before)  {
+    // Need to word wrap.
+    // lint -e{790}  Suspicious truncation
+    return num_lines_after * len_line + len_to_add;
+  }
+  else
+    return len_total;
+
+  // lint -restore
+}
+
+int CalculateBase64EscapedLen(int input_len, bool do_padding) {
+  // these formulae were copied from comments that used to go with the base64
+  // encoding functions
+  int intermediate_result = 8 * input_len + 5;
+  ASSERT(intermediate_result > 0,(L""));     // make sure we didn't overflow
+  int len = intermediate_result / 6;
+  if (do_padding) len = ((len + 3) / 4) * 4;
+  return len;
+}
+
+// Base64Escape does padding, so this calculation includes padding.
+int CalculateBase64EscapedLen(int input_len) {
+  return CalculateBase64EscapedLen(input_len, true);
+}
+
+// Base64Escape
+//   Largely based on b2a_base64 in google/docid_encryption.c
+//
+//
+int Base64EscapeInternal(const char *src, int szsrc,
+                         char *dest, int szdest, const char *base64,
+                         bool do_padding)
+{
+  ASSERT(base64, (L""));
+  ASSERT(dest, (L""));
+  ASSERT(src, (L""));
+
+  static const char kPad64 = '=';
+
+  if (szsrc <= 0) return 0;
+
+  char *cur_dest = dest;
+  const unsigned char *cur_src = reinterpret_cast<const unsigned char*>(src);
+
+  // Three bytes of data encodes to four characters of cyphertext.
+  // So we can pump through three-byte chunks atomically.
+  while (szsrc > 2) { /* keep going until we have less than 24 bits */
+    if( (szdest -= 4) < 0 ) return 0;
+    cur_dest[0] = base64[cur_src[0] >> 2];
+    cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
+    cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)];
+    cur_dest[3] = base64[cur_src[2] & 0x3f];
+
+    cur_dest += 4;
+    cur_src += 3;
+    szsrc -= 3;
+  }
+
+  /* now deal with the tail (<=2 bytes) */
+  switch (szsrc) {
+case 0:
+  // Nothing left; nothing more to do.
+  break;
+case 1:
+  // One byte left: this encodes to two characters, and (optionally)
+  // two pad characters to round out the four-character cypherblock.
+  if( (szdest -= 2) < 0 ) return 0;
+  cur_dest[0] = base64[cur_src[0] >> 2];
+  cur_dest[1] = base64[(cur_src[0] & 0x03) << 4];
+  cur_dest += 2;
+  if (do_padding) {
+    if( (szdest -= 2) < 0 ) return 0;
+    cur_dest[0] = kPad64;
+    cur_dest[1] = kPad64;
+    cur_dest += 2;
+  }
+  break;
+case 2:
+  // Two bytes left: this encodes to three characters, and (optionally)
+  // one pad character to round out the four-character cypherblock.
+  if( (szdest -= 3) < 0 ) return 0;
+  cur_dest[0] = base64[cur_src[0] >> 2];
+  cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
+  cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2];
+  cur_dest += 3;
+  if (do_padding) {
+    if( (szdest -= 1) < 0 ) return 0;
+    cur_dest[0] = kPad64;
+    cur_dest += 1;
+  }
+  break;
+default:
+  // Should not be reached: blocks of 3 bytes are handled
+  // in the while loop before this switch statement.
+  ASSERT(false, (L"Logic problem? szsrc = %S",szsrc));
+  break;
+  }
+  return (cur_dest - dest);
+}
+
+#define kBase64Chars  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+
+#define kWebSafeBase64Chars "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
+
+int Base64Escape(const char *src, int szsrc, char *dest, int szdest) {
+  ASSERT(dest, (L""));
+  ASSERT(src, (L""));
+
+  return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true);
+}
+int WebSafeBase64Escape(const char *src, int szsrc, char *dest,
+  int szdest, bool do_padding) {
+    ASSERT(dest, (L""));
+    ASSERT(src, (L""));
+
+    return Base64EscapeInternal(src, szsrc, dest, szdest,
+      kWebSafeBase64Chars, do_padding);
+  }
+
+void Base64Escape(const char *src, int szsrc,
+                  CStringA* dest, bool do_padding)
+{
+  ASSERT(src, (L""));
+  ASSERT(dest,(L""));
+  const int max_escaped_size = CalculateBase64EscapedLen(szsrc, do_padding);
+  dest->Empty();
+  const int escaped_len = Base64EscapeInternal(src, szsrc,
+      dest->GetBufferSetLength(max_escaped_size + 1), max_escaped_size + 1,
+    kBase64Chars,
+    do_padding);
+  ASSERT(max_escaped_size <= escaped_len,(L""));
+  dest->ReleaseBuffer(escaped_len);
+}
+
+void WebSafeBase64Escape(const char *src, int szsrc,
+                         CStringA *dest, bool do_padding)
+{
+  ASSERT(src, (L""));
+  ASSERT(dest,(L""));
+  const int max_escaped_size =
+    CalculateBase64EscapedLen(szsrc, do_padding);
+  dest->Empty();
+  const int escaped_len = Base64EscapeInternal(src, szsrc,
+    dest->GetBufferSetLength(max_escaped_size + 1), max_escaped_size + 1,
+    kWebSafeBase64Chars,
+    do_padding);
+  ASSERT(max_escaped_size <= escaped_len,(L""));
+  dest->ReleaseBuffer(escaped_len);
+}
+
+void WebSafeBase64Escape(const CStringA& src, CStringA* dest) {
+  ASSERT(dest,(L""));
+  int encoded_len = CalculateBase64EscapedLen(src.GetLength());
+  scoped_array<char> buf(new char[encoded_len]);
+  int len = WebSafeBase64Escape(src,src.GetLength(), buf.get(), encoded_len, false);
+  dest->SetString(buf.get(), len);
+}
+
+// ----------------------------------------------------------------------
+// int Base64Unescape() - base64 decoder
+//
+// Check out
+// http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for formal
+// description, but what we care about is that...
+//   Take the encoded stuff in groups of 4 characters and turn each
+//   character into a code 0 to 63 thus:
+//           A-Z map to 0 to 25
+//           a-z map to 26 to 51
+//           0-9 map to 52 to 61
+//           +(- for WebSafe) maps to 62
+//           /(_ for WebSafe) maps to 63
+//   There will be four numbers, all less than 64 which can be represented
+//   by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
+//   Arrange the 6 digit binary numbers into three bytes as such:
+//   aaaaaabb bbbbcccc ccdddddd
+//   Equals signs (one or two) are used at the end of the encoded block to
+//   indicate that the text was not an integer multiple of three bytes long.
+// ----------------------------------------------------------------------
+int Base64UnescapeInternal(const char *src, int len_src,
+                           char *dest, int len_dest, const char* unbase64) {
+  ASSERT (unbase64, (L""));
+  ASSERT (src, (L""));
+
+  static const char kPad64 = '=';
+
+  int decode;
+  int destidx = 0;
+  int state = 0;
+  // Used an unsigned char, since ch is used as an array index (into unbase64).
+  unsigned char ch = 0;
+  while (len_src-- && (ch = *src++) != '\0')  {
+    if (IsSpaceA(ch))  // Skip whitespace
+      continue;
+
+    if (ch == kPad64)
+      break;
+
+    decode = unbase64[ch];
+    if (decode == 99)  // A non-base64 character
+      return (-1);
+
+    // Four cyphertext characters decode to three bytes.
+    // Therefore we can be in one of four states.
+    switch (state) {
+      case 0:
+        // We're at the beginning of a four-character cyphertext block.
+        // This sets the high six bits of the first byte of the
+        // plaintext block.
+        if (dest) {
+          if (destidx >= len_dest)
+            return (-1);
+          // lint -e{734} Loss of precision
+          dest[destidx] = static_cast<char>(decode << 2);
+        }
+        state = 1;
+        break;
+      case 1:
+        // We're one character into a four-character cyphertext block.
+        // This sets the low two bits of the first plaintext byte,
+        // and the high four bits of the second plaintext byte.
+        // However, if this is the end of data, and those four
+        // bits are zero, it could be that those four bits are
+        // leftovers from the encoding of data that had a length
+        // of one mod three.
+        if (dest) {
+          if (destidx >= len_dest)
+            return (-1);
+          // lint -e{734} Loss of precision
+          dest[destidx]   |=  decode >> 4;
+          if (destidx + 1 >= len_dest) {
+            if (0 != (decode & 0x0f))
+              return (-1);
+            else
+              ;
+          } else {
+            // lint -e{734} Loss of precision
+            dest[destidx+1] = static_cast<char>((decode & 0x0f) << 4);
+          }
+        }
+        destidx++;
+        state = 2;
+        break;
+      case 2:
+        // We're two characters into a four-character cyphertext block.
+        // This sets the low four bits of the second plaintext
+        // byte, and the high two bits of the third plaintext byte.
+        // However, if this is the end of data, and those two
+        // bits are zero, it could be that those two bits are
+        // leftovers from the encoding of data that had a length
+        // of two mod three.
+        if (dest) {
+          if (destidx >= len_dest)
+            return (-1);
+          // lint -e{734} Loss of precision
+          dest[destidx]   |=  decode >> 2;
+          if (destidx +1 >= len_dest) {
+            if (0 != (decode & 0x03))
+              return (-1);
+            else
+              ;
+          } else {
+            // lint -e{734} Loss of precision
+            dest[destidx+1] = static_cast<char>((decode & 0x03) << 6);
+          }
+        }
+        destidx++;
+        state = 3;
+        break;
+      case 3:
+        // We're at the last character of a four-character cyphertext block.
+        // This sets the low six bits of the third plaintext byte.
+        if (dest) {
+          if (destidx >= len_dest)
+            return (-1);
+          // lint -e{734} Loss of precision
+          dest[destidx] |= decode;
+        }
+        destidx++;
+        state = 0;
+        break;
+
+    default:
+      ASSERT (false, (L""));
+      break;
+    }
+  }
+
+  // We are done decoding Base-64 chars.  Let's see if we ended
+  //      on a byte boundary, and/or with erroneous trailing characters.
+  if (ch == kPad64) {               // We got a pad char
+    if ((state == 0) || (state == 1))
+      return (-1);  // Invalid '=' in first or second position
+    if (len_src == 0) {
+      if (state == 2)  // We run out of input but we still need another '='
+        return (-1);
+      // Otherwise, we are in state 3 and only need this '='
+    } else {
+      if (state == 2) {  // need another '='
+        while ((ch = *src++) != '\0' && (len_src-- > 0)) {
+          if (!IsSpaceA(ch))
+            break;
+        }
+        if (ch != kPad64)
+          return (-1);
+      }
+      // state = 1 or 2, check if all remain padding is space
+      while ((ch = *src++) != '\0' && (len_src-- > 0)) {
+        if (!IsSpaceA(ch))
+          return(-1);
+      }
+    }
+  } else {
+    // We ended by seeing the end of the string.  Make sure we
+    //      have no partial bytes lying around.  Note that we
+    //      do not require trailing '=', so states 2 and 3 are okay too.
+    if (state == 1)
+      return (-1);
+  }
+
+  return (destidx);
+}
+
+int Base64Unescape(const char *src, int len_src, char *dest, int len_dest) {
+  ASSERT(dest, (L""));
+  ASSERT(src, (L""));
+
+  static const char UnBase64[] = {
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      62/*+*/, 99,      99,      99,      63/*/ */,
+     52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+     60/*8*/, 61/*9*/, 99,      99,      99,      99,      99,      99,
+     99,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+      7/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+     15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+     23/*X*/, 24/*Y*/, 25/*Z*/, 99,      99,      99,      99,      99,
+     99,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+     33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+     41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+     49/*x*/, 50/*y*/, 51/*z*/, 99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99,
+     99,      99,      99,      99,      99,      99,      99,      99
+  };
+
+  // The above array was generated by the following code
+  // #include <sys/time.h>
+  // #include <stdlib.h>
+  // #include <string.h>
+  // main()
+  // {
+  //   static const char Base64[] =
+  //     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  //   char *pos;
+  //   int idx, i, j;
+  //   printf("    ");
+  //   for (i = 0; i < 255; i += 8) {
+  //     for (j = i; j < i + 8; j++) {
+  //       pos = strchr(Base64, j);
+  //       if ((pos == NULL) || (j == 0))
+  //         idx = 99;
+  //       else
+  //         idx = pos - Base64;
+  //       if (idx == 99)
+  //         printf(" %2d,     ", idx);
+  //       else
+  //         printf(" %2d/*%c*/,", idx, j);
+  //     }
+  //     printf("\n    ");
+  //   }
+  // }
+
+  return Base64UnescapeInternal(src, len_src, dest, len_dest, UnBase64);
+}
+
+int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) {
+  ASSERT(dest, (L""));
+  ASSERT(src, (L""));
+
+  static const char UnBase64[] = {
+    99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      62/*-*/, 99,      99,
+      52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+      60/*8*/, 61/*9*/, 99,      99,      99,      99,      99,      99,
+      99,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+      7/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+      15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+      23/*X*/, 24/*Y*/, 25/*Z*/, 99,      99,      99,      99,      63/*_*/,
+      99,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+      33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+      41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+      49/*x*/, 50/*y*/, 51/*z*/, 99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99,
+      99,      99,      99,      99,      99,      99,      99,      99
+  };
+  // The above array was generated by the following code
+  // #include <sys/time.h>
+  // #include <stdlib.h>
+  // #include <string.h>
+  // main()
+  // {
+  //   static const char Base64[] =
+  //     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+  //   char *pos;
+  //   int idx, i, j;
+  //   printf("    ");
+  //   for (i = 0; i < 255; i += 8) {
+  //     for (j = i; j < i + 8; j++) {
+  //       pos = strchr(Base64, j);
+  //       if ((pos == NULL) || (j == 0))
+  //         idx = 99;
+  //       else
+  //         idx = pos - Base64;
+  //       if (idx == 99)
+  //         printf(" %2d,     ", idx);
+  //       else
+  //         printf(" %2d/*%c*/,", idx, j);
+  //     }
+  //     printf("\n    ");
+  //   }
+  // }
+
+  return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
+}
+
+bool IsHexDigit (WCHAR c) {
+  return (((c >= L'a') && (c <= L'f'))
+     || ((c >= L'A') && (c <= L'F'))
+     || ((c >= L'0') && (c <= L'9')));
+}
+
+int HexDigitToInt (WCHAR c) {
+  return ((c >= L'a') ? ((c - L'a') + 10) :
+          (c >= L'A') ? ((c - L'A') + 10) :
+          (c - L'0'));
+}
+
+// ----------------------------------------------------------------------
+// int QuotedPrintableUnescape()
+//
+// Check out http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for
+// more details, only briefly implemented. But from the web...
+// Quoted-printable is an encoding method defined in the MIME
+// standard. It is used primarily to encode 8-bit text (such as text
+// that includes foreign characters) into 7-bit US ASCII, creating a
+// document that is mostly readable by humans, even in its encoded
+// form. All MIME compliant applications can decode quoted-printable
+// text, though they may not necessarily be able to properly display the
+// document as it was originally intended. As quoted-printable encoding
+// is implemented most commonly, printable ASCII characters (values 33
+// through 126, excluding 61), tabs and spaces that do not appear at the
+// end of lines, and end-of-line characters are not encoded. Other
+// characters are represented by an equal sign (=) immediately followed
+// by that character's hexadecimal value. Lines that are longer than 76
+// characters are shortened by line breaks, with the equal sign marking
+// where the breaks occurred.
+//
+// Update: we really want QuotedPrintableUnescape to conform to rfc2047,
+// which expands the q encoding. In particular, it specifices that _'s are
+// to be treated as spaces.
+// ----------------------------------------------------------------------
+int QuotedPrintableUnescape(const WCHAR *source, int slen,
+                            WCHAR *dest, int len_dest) {
+  ASSERT(dest, (L""));
+  ASSERT(source, (L""));
+
+  WCHAR* d = dest;
+  const WCHAR* p = source;
+
+  while (*p != '\0' && p < source+slen && d < dest+len_dest) {
+    switch (*p) {
+      case '=':
+        if (p == source+slen-1) {
+          // End of line, no need to print the =..
+          return (d-dest);
+        }
+        // if its valid, convert to hex and insert
+        if (p < source+slen-2 && IsHexDigit(p[1]) && IsHexDigit(p[2])) {
+          // lint -e{734} Loss of precision
+          *d++ = static_cast<WCHAR>(
+                    HexDigitToInt(p[1]) * 16 + HexDigitToInt(p[2]));
+          p += 3;
+        } else {
+          p++;
+        }
+        break;
+      case '_':   // According to rfc2047, _'s are to be treated as spaces
+        *d++ = ' '; p++;
+        break;
+      default:
+        *d++ = *p++;
+        break;
+    }
+  }
+  return (d-dest);
+}
+
+// TODO(omaha): currently set not to use IsCharUpper because that is relatively slow
+// this is used in the QUIB; consider if we need to use IsCharUpper or a replacement
+bool String_IsUpper(TCHAR c) {
+  return (c >= 'A' && c <= 'Z');
+  // return (IsCharUpper (c));
+}
+
+// Replacement for the CRT toupper(c)
+int String_ToUpper(int c) {
+  // If it's < 128, then convert is ourself, which is far cheaper than the system conversion
+  if (c < 128)
+    return String_ToUpperA(static_cast<char>(c));
+
+  TCHAR * p_c = reinterpret_cast<TCHAR *>(c);
+  int conv_c = reinterpret_cast<int>(::CharUpper(p_c));
+  return conv_c;
+}
+
+// Replacement for the CRT toupper(c)
+char String_ToUpperA(char c) {
+  if (c >= 'a' && c <= 'z') return (c - ('a' - 'A'));
+  return c;
+}
+
+void String_ToLower(TCHAR* str) {
+  ASSERT1(str);
+  ::CharLower(str);
+}
+
+void String_ToUpper(TCHAR* str) {
+  ASSERT1(str);
+  ::CharUpper(str);
+}
+
+// String comparison based on length
+// Replacement for the CRT strncmp(i)
+int String_StrNCmp(const TCHAR * str1, const TCHAR * str2, uint32 len, bool ignore_case) {
+  ASSERT(str2, (L""));
+  ASSERT(str1, (L""));
+
+  TCHAR c1, c2;
+
+  if (len == 0)
+    return 0;
+
+  // compare each char
+  // TODO(omaha): If we use a lot of case sensitive compares consider having 2 loops.
+  do {
+    c1 = *str1++;
+    c2 = *str2++;
+    if (ignore_case) {
+      c1 = (TCHAR)String_ToLowerChar((int)(c1));  // lint !e507  Suspicious truncation
+      c2 = (TCHAR)String_ToLowerChar((int)(c2));  // lint !e507
+    }
+  } while ( (--len) && c1 && (c1 == c2) );
+
+  return (int)(c1 - c2);
+}
+
+// TODO(omaha): Why do we introduce this behaviorial difference?
+// Replacement for strncpy() - except ALWAYS ends string with null
+TCHAR* String_StrNCpy(TCHAR* destination, const TCHAR* source, uint32 len) {
+  ASSERT (source, (L""));
+  ASSERT (destination, (L""));
+
+  TCHAR* result = destination;
+
+  ASSERT (0 != len, (L""));     // Too short a destination for even the null character
+
+  while (*source && len) {
+    *destination++ = *source++;
+    len--;
+  }
+
+  // If we ran out of space, back up one
+  if (0 == len) {
+    destination--;
+  }
+
+  // Null-terminate the string
+  *destination = _T('\0');
+
+  return result;
+}
+
+// check if a string starts with another string
+bool String_StartsWith(const TCHAR *str, const TCHAR *start_str,
+                            bool ignore_case) {
+  ASSERT(start_str, (L""));
+  ASSERT(str, (L""));
+
+  while (0 != *str) {
+    // Check for matching characters
+    TCHAR c1 = *str;
+    TCHAR c2 = *start_str;
+
+    // Reached the end of start_str?
+    if (0 == c2)
+      return true;
+
+    if (ignore_case) {
+      c1 = (TCHAR)String_ToLowerChar((int)(c1));  // lint !e507  Suspicious truncation
+      c2 = (TCHAR)String_ToLowerChar((int)(c2));  // lint !e507  Suspicious truncation
+    }
+
+    if (c1 != c2)
+      return false;
+
+    ++str;
+    ++start_str;
+  }
+
+  // If str is shorter than start_str, no match.  If equal size, match.
+  return 0 == *start_str;
+}
+
+// check if a string starts with another string
+bool String_StartsWithA(const char *str, const char *start_str, bool ignore_case) {
+  ASSERT(start_str, (L""));
+  ASSERT(str, (L""));
+
+  while (0 != *str) {
+    // Check for matching characters
+    char c1 = *str;
+    char c2 = *start_str;
+
+    // Reached the end of start_str?
+    if (0 == c2)
+      return true;
+
+    if (ignore_case) {
+      c1 = String_ToLowerCharAnsi(c1);
+      c2 = String_ToLowerCharAnsi(c2);
+    }
+
+    if (c1 != c2)
+      return false;
+
+    ++str;
+    ++start_str;
+  }
+
+  // If str is shorter than start_str, no match.  If equal size, match.
+  return 0 == *start_str;
+}
+
+// the wrapper version below actually increased code size as of 5/31/04
+// perhaps because the int64 version is larger and in some EXE/DLLs we only need the int32 version
+
+// converts a string to an int
+// Does not check for overflow
+// is the direct int32 version significantly faster for our usage?
+// int32 String_StringToInt(const TCHAR * str) {
+//    ASSERT(str, (L""));
+//    return static_cast<int32>(String_StringToInt64 (str));
+// }
+
+// converts a string to an int
+// Does not check for overflow
+int32 String_StringToInt(const TCHAR * str) {
+  ASSERT(str, (L""));
+
+  int c;              // current char
+  int32 total;         // current total
+  int sign;           // if '-', then negative, otherwise positive
+
+  // remove spaces
+  while ( *str == _T(' '))
+      ++str;
+
+  c = (int)*str++;
+  sign = c;           // save sign indication
+  if (c == _T('-') || c == _T('+'))
+      c = (int)*str++;    // skip sign
+
+  total = 0;
+
+  while ((c = String_CharToDigit(static_cast<TCHAR>(c))) != -1 ) {
+      total = 10 * total + c;     // accumulate digit
+      c = *str++;    // get next char
+  }
+
+  if (sign == '-')
+    return -total;
+  else
+    return total;   // return result, negated if necessary
+}
+
+// converts a string to an int64
+// Does not check for overflow
+int64 String_StringToInt64(const TCHAR * str) {
+  ASSERT(str, (L""));
+
+  int c;  // current char
+  int64 total;  // current total
+  int sign;
+
+  while (*str == ' ') ++str;  // skip space
+
+  c = (int)*str++;
+  sign = c;           /* save sign indication */
+  if (c == '-' || c == '+')
+    c = (int)*str++;
+
+  total = 0;
+
+  while ((c = String_CharToDigit(static_cast<TCHAR>(c))) != -1) {
+    total = 10 * total + c;     /* accumulate digit */
+    c = *str++;    /* get next char */
+  }
+
+  if (sign == '-')
+    return -total;
+  else
+    return total;
+}
+
+// A faster version of the ::CharLower command. We first check if all characters are in low ANSI
+// If so, we can convert it ourselves [which is about 10x faster]
+// Otherwise, ask the system to do it for us.
+TCHAR * String_FastToLower(TCHAR * str) {
+  ASSERT(str, (L""));
+
+  TCHAR * p = str;
+  while (*p) {
+    // If we can't process it ourselves, then do it with the API
+    if (*p > 127)
+      return ::CharLower(str);
+    ++p;
+  }
+
+  // If we're still here, do it ourselves
+  p = str;
+  while (*p) {
+    // Lower case it
+    if (*p >= L'A' && *p <= 'Z')
+      *p |= 0x20;
+    ++p;
+  }
+
+  return str;
+}
+
+// Convert a size_t to a CString
+CString sizet_to_str(const size_t & i) {
+  CString out;
+  out.Format(NOTRANSL(_T("%u")),i);
+  return out;
+}
+
+// Convert an int to a CString
+CString itostr(const int i) {
+  return String_Int64ToString(i, 10);
+}
+
+// Convert a uint to a CString
+CString itostr(const uint32 i) {
+  return String_Int64ToString(i, 10);
+}
+
+// converts an int to a string
+// Does not check for overflow
+CString String_Int64ToString(int64 value, int radix) {
+  ASSERT(radix > 0, (L""));
+
+  // Space big enough for it in binary, plus the sign
+  TCHAR temp[66];
+
+  bool negative = false;
+  if (value < 0) {
+    negative = true;
+    value = -value;
+  }
+
+  int pos = 0;
+
+  // Add digits in reverse order
+  do {
+    TCHAR digit = (TCHAR) (value % radix);
+    if (digit > 9)
+      temp[pos] = L'a' + digit - 10;
+    else
+      temp[pos] = L'0' + digit;
+
+    pos++;
+    value /= radix;
+  } while (value > 0);
+
+  if (negative)
+    temp[pos++] = L'-';
+
+  // Reverse it before making a CString out of it
+  int start = 0, end = pos - 1;
+  while (start < end) {
+    TCHAR t = temp[start];
+    temp[start] = temp[end];
+    temp[end] = t;
+
+    end--;
+    start++;
+  }
+
+  return CString(temp, pos);
+}
+
+// converts an uint64 to a string
+// Does not check for overflow
+CString String_Uint64ToString(uint64 value, int radix) {
+  ASSERT1(radix > 0);
+
+  CString ret;
+
+  const uint32 kMaxUint64Digits = 65;
+
+  // Space big enough for it in binary
+  TCHAR* temp = ret.GetBufferSetLength(kMaxUint64Digits);
+
+  int pos = 0;
+
+  // Add digits in reverse order
+  do {
+    TCHAR digit = static_cast<TCHAR>(value % radix);
+    if (digit > 9) {
+      temp[pos] = _T('a') + digit - 10;
+    } else {
+      temp[pos] = _T('0') + digit;
+    }
+
+    pos++;
+    value /= radix;
+  } while (value > 0 && pos < kMaxUint64Digits);
+
+  ret.ReleaseBuffer(pos);
+
+  // Reverse it before making a CString out of it
+  ret.MakeReverse();
+
+  return ret;
+}
+
+// converts an double to a string specifies the number of digits after
+// the decimal point
+CString String_DoubleToString(double value, int point_digits) {
+  int64 int_val = (int64) value;
+
+  // Deal with integer part
+  CString result(String_Int64ToString(int_val, 10));
+
+  if (point_digits > 0) {
+    result.AppendChar(L'.');
+
+    // get the fp digits
+    double rem_val = value - int_val;
+    if (rem_val < 0)
+      rem_val = -rem_val;
+
+    // multiply w/ the requested number of significant digits
+    // construct the string in place
+    for(int i=0; i<point_digits; i++) {
+      // TODO(omaha): I have seen 1.2 turn into 1.1999999999999, and generate that string.
+      // We should round better. For now, I'll add a quick fix to favor high
+      rem_val += 1e-12;
+      rem_val *= 10;
+      // Get the ones digit
+      int64 int_rem_dig = std::min(10LL, static_cast<int64>(rem_val));
+      result += static_cast<TCHAR>(int_rem_dig + L'0');
+      rem_val = rem_val - int_rem_dig;
+    }
+  }
+
+  return result;
+}
+
+double String_StringToDouble (const TCHAR *s) {
+  ASSERT(s, (L""));
+
+  double value, power;
+  int i = 0, sign;
+
+  while (IsSpaceW(s[i])) i++;
+
+  // get sign
+  sign = (s[i] == '-') ? -1 : 1;
+  if (s[i] == '+' || s[i] == '-') i++;
+
+  for (value = 0.0; s[i] >= '0' && s[i] <= '9'; i++)
+    value = 10.0 * value + (s[i] - '0');
+
+  if (s[i] == '.') i++;
+
+  for (power = 1.0; s[i] >= '0' && s[i] <= '9'; i++) {
+    value = 10.0 * value + (s[i] - '0');
+    power *= 10.0;
+  }
+
+  return sign * value / power;
+}
+
+// Converts a character to a digit
+// if the character is not a digit return -1 (same as CRT)
+int32 String_CharToDigit(const TCHAR c) {
+  return ((c) >= '0' && (c) <= '9' ? (c) - '0' : -1);
+}
+
+bool String_IsDigit (const TCHAR c) {
+  return ((c) >= '0' && (c) <= '9');
+}
+
+TCHAR String_DigitToChar(unsigned int n) {
+  ASSERT1(n < 10);
+  return static_cast<TCHAR>(_T('0') + n % 10);
+}
+
+// Returns true if an identifier character: letter, digit, or "_"
+bool String_IsIdentifierChar(const TCHAR c) {
+  return ((c >= _T('A') && c <= _T('Z')) ||
+          (c >= _T('a') && c <= _T('z')) ||
+          (c >= _T('0') && c <= _T('9')) ||
+          c == _T('_'));
+}
+
+// Returns true if the string has letters in it.
+// This is used by the keyword extractor to downweight numbers,
+// IDs (sequences of numbers like social security numbers), etc.
+bool String_HasAlphabetLetters (const TCHAR * str) {
+  ASSERT (str, (L""));
+
+  while (*str != '\0') {
+    // if (iswalpha (*str)) {
+    // Note that IsCharAlpha is slower but we want to avoid the CRT
+    if (IsCharAlpha (*str)) {
+      return true;
+    }
+    ++str;
+  }
+
+  return false;
+}
+
+CString String_LargeIntToApproximateString(uint64 value, bool base_ten, int* power) {
+  uint32 to_one_decimal;
+
+  uint32 gig         = base_ten ? 1000000000 : (1<<30);
+  uint32 gig_div_10  = base_ten ?  100000000 : (1<<30)/10;
+  uint32 meg         = base_ten ?    1000000 : (1<<20);
+  uint32 meg_div_10  = base_ten ?     100000 : (1<<20)/10;
+  uint32 kilo        = base_ten ?       1000 : (1<<10);
+  uint32 kilo_div_10 = base_ten ?        100 : (1<<10)/10;
+
+  if (value >= gig) {
+    if (power) *power = 3;
+    to_one_decimal = static_cast<uint32>(value / gig_div_10);
+  } else if (value >= meg) {
+    if (power) *power = 2;
+    to_one_decimal = static_cast<uint32>(value / meg_div_10);
+  } else if (value >= kilo) {
+    if (power) *power = 1;
+    to_one_decimal = static_cast<uint32>(value / kilo_div_10);
+  } else {
+    if (power) *power = 0;
+    return String_Int64ToString(static_cast<uint32>(value), 10 /*radix*/);
+  }
+
+  uint32 whole_part = to_one_decimal / 10;
+
+  if (whole_part < 10)
+    return Show(0.1 * static_cast<double>(to_one_decimal), 1);
+
+  return String_Int64ToString(whole_part, 10 /*radix*/);
+}
+
+int String_FindString(const TCHAR *s1, const TCHAR *s2) {
+  ASSERT(s2, (L""));
+  ASSERT(s1, (L""));
+
+  // Naive implementation, but still oodles better than ATL's implementation
+  // (which deals with variable character widths---we don't).
+
+  const TCHAR *found = _tcsstr(s1, s2);
+  if (NULL == found)
+    return -1;
+
+  return found - s1;
+}
+
+int String_FindString(const TCHAR *s1, const TCHAR *s2, int start_pos) {
+  ASSERT(s2, (L""));
+  ASSERT(s1, (L""));
+
+  // Naive implementation, but still oodles better than ATL's implementation
+  // (which deals with variable character widths---we don't).
+
+  int skip = start_pos;
+
+  const TCHAR *s = s1;
+  while (skip && *s) {
+    ++s;
+    --skip;
+  }
+  if (!(*s))
+    return -1;
+
+  const TCHAR *found = _tcsstr(s, s2);
+  if (NULL == found)
+    return -1;
+
+  return found - s1;
+}
+
+int String_FindChar(const TCHAR *str, const TCHAR c) {
+  ASSERT (str, (L""));
+  const TCHAR *s = str;
+  while (*s) {
+    if (*s == c)
+      return s - str;
+    ++s;
+  }
+
+  return -1;
+}
+
+// taken from wcsrchr, modified to behave in the CString way
+int String_ReverseFindChar(const TCHAR * str,TCHAR c) {
+  ASSERT (str, (L""));
+  TCHAR *start = (TCHAR *)str;
+
+  while (*str++)                       /* find end of string */
+    ;
+  /* search towards front */
+  while (--str != start && *str != (TCHAR)c)
+    ;
+
+  if (*str == (TCHAR)c)             /* found ? */
+    return( str - start );
+
+  return -1;
+}
+
+int String_FindChar(const TCHAR *str, const TCHAR c, int start_pos) {
+  ASSERT (str, (L""));
+  int n = 0;
+  const TCHAR *s = str;
+  while (*s) {
+    if (n++ >= start_pos && *s == c)
+      return s - str;
+    ++s;
+  }
+
+  return -1;
+}
+
+bool String_Contains(const TCHAR *s1, const TCHAR *s2) {
+  ASSERT(s2, (L""));
+  ASSERT(s1, (L""));
+
+  return -1 != String_FindString(s1, s2);
+}
+
+void String_ReplaceChar(TCHAR *str, TCHAR old_char, TCHAR new_char) {
+  ASSERT (str, (L""));
+  while (*str) {
+    if (*str == old_char)
+      *str = new_char;
+
+    ++str;
+  }
+}
+
+void String_ReplaceChar(CString & str, TCHAR old_char, TCHAR new_char) {
+  String_ReplaceChar (str.GetBuffer(), old_char, new_char);
+  str.ReleaseBuffer();
+}
+
+int ReplaceCString (CString & src, const TCHAR *from, const TCHAR *to) {
+  ASSERT(to, (L""));
+  ASSERT(from, (L""));
+
+  return ReplaceCString(src, from, lstrlen(from), to, lstrlen(to), kRepMax);
+}
+
+// A special version of the replace function which takes advantage of CString properties
+// to make it much faster when the string grows
+// 1) It will resize the string in place if possible. Even if it has to 'grow' the string
+// 2) It will cutoff after a maximum number of matches
+// 3) It expects sizing data to be passed to it
+int ReplaceCString (CString & src, const TCHAR *from, unsigned int from_len,
+                                   const TCHAR *to, unsigned int to_len,
+                                   unsigned int max_matches) {
+  ASSERT (from, (L""));
+  ASSERT (to, (L""));
+  ASSERT (from[0] != '\0', (L""));
+  int i = 0, j = 0;
+  unsigned int matches = 0;
+
+  // Keep track of the matches, it's easier than recalculating them
+  unsigned int match_pos_stack[kExpectedMaxReplaceMatches];
+
+  // We might need to dynamically allocate space for the matches
+  bool dynamic_allocate = false;
+  unsigned int * match_pos = (unsigned int*)match_pos_stack;
+  unsigned int max_match_size = kExpectedMaxReplaceMatches;
+
+  // Is the string getting bigger?
+  bool longer = to_len > from_len;
+
+  // don't compute the lengths unless we know we need to
+  int src_len = src.GetLength();
+  int cur_len = src_len;
+
+  // Trick: We temporarily add 1 extra character to the string. The first char from the from
+  // string. This way we can avoid searching for NULL, since we are guaranteed to find it
+  TCHAR * buffer = src.GetBufferSetLength(src_len+1);
+  const TCHAR from_0 = from[0];
+  buffer[src_len] = from[0];
+
+  while (i < cur_len) {
+    // If we have too many matches, then re-allocate to a dynamic buffer that is
+    // twice as big as the one we are currently using
+    if (longer && (matches == max_match_size)) {
+      // Double the buffer size, and copy it over
+      unsigned int * temp = new unsigned int[max_match_size * 2];
+      memcpy(temp, match_pos, matches * sizeof(unsigned int));
+      if (dynamic_allocate)
+        delete [] match_pos;  // lint !e424  Inappropriate deallocation
+      match_pos = temp;
+
+      max_match_size *= 2;
+      dynamic_allocate = true;
+    }
+
+    // If we have the maximum number of matches already, then stop
+    if (matches >= max_matches) {
+      break;
+    }
+
+    // For each potential match
+    // Note: oddly enough, this is the most expensive line in the function under normal usage. So I am optimizing the heck out of it
+    TCHAR * buf_ptr = buffer + i;
+    while (*buf_ptr != from_0) { ++buf_ptr; }
+    i = buf_ptr - buffer;
+
+    // We're done!
+    if (i >= cur_len)
+      break;
+
+    // buffer is not NULL terminated, we replaced the NULL above
+    while (i < cur_len && buffer[i] && buffer[i] == from[j]) {
+      ++i; ++j;
+      if (from[j] == '\0') {  // found match
+
+        if (!longer) {  // modify in place
+
+          memcpy ((byte *)(buffer+i) - (sizeof (TCHAR) * from_len), (byte *)to, sizeof (TCHAR) * to_len);
+          // if there are often a lot of replacements, it would be faster to create a new string instead
+          // of using memmove
+
+          // TODO(omaha): - memmove will cause n^2 behavior in strings with multiple matches since it will be moved many times...
+          if (to_len < from_len) { memmove ((byte *)(buffer+i) - (sizeof (TCHAR) * (from_len - to_len)),
+                                          (byte *)(buffer+i), (src_len - i + 1) * sizeof (TCHAR)); }
+
+          i -= (from_len - to_len);
+          cur_len -= (from_len - to_len);
+        }
+        else
+          match_pos[matches] = i - from_len;
+
+        ++matches;
+
+        break;
+      }
+    }
+
+    j = 0;
+  }
+
+  if (to_len <= from_len)
+    src_len -= matches * (from_len - to_len);
+
+  // if the new string is longer we do another pass now that we know how long the new string needs to be
+  if (matches && to_len > from_len) {
+    src.ReleaseBuffer(src_len);
+
+    int new_len = src_len + matches * (to_len - from_len);
+    buffer = src.GetBufferSetLength(new_len);
+
+    // It's easier to assemble it backwards...
+    int temp_end = new_len;
+    for(i = matches-1; i >= 0; --i) {
+      // Figure out where the trailing portion isthe trailing portion
+      int len = src_len - match_pos[i] - from_len;
+      int start  = match_pos[i] + from_len;
+      int dest   = temp_end - len;
+      memmove(buffer+dest, buffer+start, (len) * sizeof(TCHAR));
+
+      // copy the new item
+      memcpy(buffer + dest - to_len, to, to_len * sizeof(TCHAR));
+
+      // Update the pointers
+      temp_end = dest - to_len;
+      src_len = match_pos[i];
+
+    }
+    src_len = new_len;
+  }
+
+  src.ReleaseBuffer(src_len);
+  if (dynamic_allocate)
+    delete [] match_pos;  // lint !e673  Possibly inappropriate deallocation
+
+  return matches;
+}
+
+/*
+   The following 2 functions will do replacement on TCHAR* directly. They is currently unused.
+   Feel free to put it back if you need to.
+*/
+int ReplaceString (TCHAR *src, const TCHAR *from, const TCHAR *to, TCHAR **out, int *out_len) {
+  ASSERT(out_len, (L""));
+  ASSERT(out, (L""));
+  ASSERT(to, (L""));
+  ASSERT(from, (L""));
+  ASSERT(src, (L""));
+
+  bool created_new_string;
+  int matches = ReplaceStringMaybeInPlace (src, from, to, out, out_len, &created_new_string);
+  if (!created_new_string) {
+      *out = new TCHAR [(*out_len)+1];
+      if (!(*out)) { *out = src; return 0; }
+      _tcscpy_s(*out, *out_len + 1, src);
+  }
+
+  return matches;
+}
+
+int ReplaceStringMaybeInPlace (TCHAR *src, const TCHAR *from, const TCHAR *to, TCHAR **out, int *out_len, bool *created_new_string) {
+  ASSERT (created_new_string, (L""));
+  ASSERT (out_len, (L""));
+  ASSERT (src, (L""));
+  ASSERT (from, (L""));
+  ASSERT (to, (L""));
+  ASSERT (out, (L""));
+  ASSERT (from[0] != '\0', (L""));
+  int i = 0, j = 0;
+  int matches = 0;
+
+  // don't compute the lengths unless we know we need to
+  int from_len = -1, to_len = -1, src_len = -1;
+
+  *created_new_string = false;
+  *out = src;
+
+  while (src[i]) {
+    while (src[i] && src[i] != from[0]) { i++; }
+    while (src[i] && src[i] == from[j]) {
+      i++; j++;
+      if (from[j] == '\0') {  // found match
+        if (from_len == -1) {  // compute lengths if not known
+          from_len = lstrlen (from);
+          to_len = lstrlen (to);
+          src_len = lstrlen (src);
+        }
+
+        matches++;
+
+        if (to_len <= from_len) {  // modify in place
+          memcpy ((byte *)(src+i) - (sizeof (TCHAR) * from_len), (byte *)to, sizeof (TCHAR) * to_len);
+          // if there are often a lot of replacements, it would be faster to create a new string instead
+          // of using memmove
+          if (to_len < from_len) { memmove ((byte *)(src+i) - (sizeof (TCHAR) * (from_len - to_len)),
+                                            (byte *)(src+i), (src_len - i + 1) * sizeof (TCHAR)); }
+          i -= (from_len - to_len);
+        }
+
+        break;
+      }
+    }
+
+    j = 0;
+  }
+
+  *out_len = i;
+
+  // if the new string is longer we do another pass now that we know how long the new string needs to be
+  if (matches && to_len > from_len) {
+      ASSERT (src_len == i, (L""));
+      int new_len = src_len + matches * (to_len - from_len);
+      *out = new TCHAR [new_len+1];
+      if (!(*out)) { *out = src; *out_len = lstrlen (src); return 0; }
+      *created_new_string = true;
+      i = 0; j = 0; int k = 0;
+
+      while (src[i]) {
+          while (src[i] && src[i] != from[0]) {
+              (*out)[k++] = src[i++];
+          }
+          while (src[i] && src[i] == from[j]) {
+              (*out)[k++] = src[i++];
+              j++;
+
+              if (from[j] == '\0') {  // found match
+                  k -= from_len;
+                  ASSERT (k >= 0, (L""));
+                  memcpy ((byte *)((*out)+k), (byte *)to, sizeof (TCHAR) * to_len);
+                  k += to_len;
+                  break;
+              }
+          }
+
+          j = 0;
+      }
+
+      (*out)[k] = '\0';
+      ASSERT (k == new_len, (L""));
+      *out_len = new_len;
+  }
+
+  return matches;
+}
+
+/****************************************************************************
+* wcstol, wcstoul(nptr,endptr,ibase) - Convert ascii string to long un/signed int.
+*
+* modified from:
+*
+* wcstol.c - Contains C runtimes wcstol and wcstoul
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*   Purpose:
+*       Convert an ascii string to a long 32-bit value.  The base
+*       used for the caculations is supplied by the caller.  The base
+*       must be in the range 0, 2-36.  If a base of 0 is supplied, the
+*       ascii string must be examined to determine the base of the
+*       number:
+*           (a) First char = '0', second char = 'x' or 'X',
+*               use base 16.
+*           (b) First char = '0', use base 8
+*           (c) First char in range '1' - '9', use base 10.
+*
+*       If the 'endptr' value is non-NULL, then wcstol/wcstoul places
+*       a pointer to the terminating character in this value.
+*       See ANSI standard for details
+*
+*Entry:
+*       nptr == NEAR/FAR pointer to the start of string.
+*       endptr == NEAR/FAR pointer to the end of the string.
+*       ibase == integer base to use for the calculations.
+*
+*       string format: [whitespace] [sign] [0] [x] [digits/letters]
+*
+*Exit:
+*       Good return:
+*           result
+*
+*       Overflow return:
+*           wcstol -- LONG_MAX or LONG_MIN
+*           wcstoul -- ULONG_MAX
+*           wcstol/wcstoul -- errno == ERANGE
+*
+*       No digits or bad base return:
+*           0
+*           endptr = nptr*
+*
+*Exceptions:
+*       None.
+*
+*******************************************************************************/
+
+// flag values */
+#define kFlUnsigned   (1)       // wcstoul called */
+#define kFlNeg        (2)       // negative sign found */
+#define kFlOverflow   (4)       // overflow occured */
+#define kFlReaddigit  (8)       // we've read at least one correct digit */
+
+static unsigned long __cdecl wcstoxl (const wchar_t *nptr, wchar_t **endptr, int ibase, int flags) {
+  ASSERT(nptr, (L""));
+
+  const wchar_t *p;
+  wchar_t c;
+  unsigned long number;
+  unsigned digval;
+  unsigned long maxval;
+  // #ifdef _MT
+  // pthreadlocinfo ptloci = _getptd()->ptlocinfo;
+
+  // if ( ptloci != __ptlocinfo )
+  //    ptloci = __updatetlocinfo();
+  // #endif  // _MT */
+
+  p = nptr;           // p is our scanning pointer */
+  number = 0;         // start with zero */
+
+  c = *p++;           // read char */
+
+  // #ifdef _MT
+  //        while ( __iswspace_mt(ptloci, c) )
+  // #else  // _MT */
+  while (c == ' ')
+  //        while ( iswspace(c) )
+  // #endif  // _MT */
+      c = *p++;       // skip whitespace */
+
+  if (c == '-') {
+      flags |= kFlNeg;    // remember minus sign */
+      c = *p++;
+  }
+  else if (c == '+')
+      c = *p++;       // skip sign */
+
+  if (ibase < 0 || ibase == 1 || ibase > 36) {
+      // bad base! */
+      if (endptr)
+          // store beginning of string in endptr */
+          *endptr = const_cast<wchar_t *>(nptr);
+      return 0L;      // return 0 */
+  }
+  else if (ibase == 0) {
+      // determine base free-lance, based on first two chars of
+      // string */
+      if (String_CharToDigit(c) != 0)
+          ibase = 10;
+      else if (*p == L'x' || *p == L'X')
+          ibase = 16;
+      else
+          ibase = 8;
+  }
+
+  if (ibase == 16) {
+      // we might have 0x in front of number; remove if there */
+      if (String_CharToDigit(c) == 0 && (*p == L'x' || *p == L'X')) {
+          ++p;
+          c = *p++;   // advance past prefix */
+      }
+  }
+
+  // if our number exceeds this, we will overflow on multiply */
+  maxval = ULONG_MAX / ibase;
+
+  for (;;) {  // exit in middle of loop */
+
+      // convert c to value */
+      if ( (digval = String_CharToDigit(c)) != (unsigned) -1 )
+          ;
+      else if (c >= 'A' && c <= 'F') { digval = c - 'A' + 10; }
+      else if (c >= 'a' && c <= 'f') { digval = c - 'a' + 10; }
+      // else if ( __ascii_iswalpha(c))
+      //     digval = __ascii_towupper(c) - L'A' + 10;
+      else
+          break;
+
+      if (digval >= (unsigned)ibase)
+          break;      // exit loop if bad digit found */
+
+      // record the fact we have read one digit */
+      flags |= kFlReaddigit;
+
+      // we now need to compute number = number * base + digval,
+      // but we need to know if overflow occured.  This requires
+      // a tricky pre-check. */
+
+      if (number < maxval || (number == maxval &&
+      (unsigned long)digval <= ULONG_MAX % ibase)) {
+          // we won't overflow, go ahead and multiply */
+          number = number * ibase + digval;
+      }
+      else {
+          // we would have overflowed -- set the overflow flag */
+          flags |= kFlOverflow;
+      }
+
+      c = *p++;       // read next digit */
+  }
+
+  --p;                // point to place that stopped scan */
+
+  if (!(flags & kFlReaddigit)) {
+      // no number there; return 0 and point to beginning of string */
+      if (endptr)
+          // store beginning of string in endptr later on */
+          p = nptr;
+      number = 0L;        // return 0 */
+  }
+  // lint -save -e648 -e650  Overflow in -LONG_MIN
+#pragma warning(push)
+// C4287 : unsigned/negative constant mismatch.
+// The offending expression is number > -LONG_MIN. -LONG_MIN overflows and
+// technically -LONG_MIN == LONG_MIN == 0x80000000. It should actually
+// result in a compiler warning, such as C4307: integral constant overflow.
+// Anyway, in the expression (number > -LONG_MIN) the right operand is converted
+// to unsigned long, so the expression is actually evaluated as
+// number > 0x80000000UL. The code is probably correct but subtle, to say the
+// least.
+#pragma warning(disable : 4287)
+  else if ( (flags & kFlOverflow) ||
+        ( !(flags & kFlUnsigned) &&
+          ( ( (flags & kFlNeg) && (number > -LONG_MIN) ) ||
+            ( !(flags & kFlNeg) && (number > LONG_MAX) ) ) ) )
+  {
+      // overflow or signed overflow occurred */
+      // errno = ERANGE;
+      if ( flags & kFlUnsigned )
+          number = ULONG_MAX;
+      else if ( flags & kFlNeg )
+        // lint -e{648, 650}  Overflow in -LONG_MIN
+        number = (unsigned long)(-LONG_MIN);
+      else
+        number = LONG_MAX;
+  }
+#pragma warning(pop)
+  // lint -restore
+
+  if (endptr != NULL)
+      // store pointer to char that stopped the scan */
+      *endptr = const_cast<wchar_t *>(p);
+
+  if (flags & kFlNeg)
+      // negate result if there was a neg sign */
+      number = (unsigned long)(-(long)number);
+
+  return number;          // done. */
+}
+
+long __cdecl Wcstol (const wchar_t *nptr, wchar_t **endptr, int ibase) {
+  ASSERT(endptr, (L""));
+  ASSERT(nptr, (L""));
+
+  return (long) wcstoxl(nptr, endptr, ibase, 0);
+}
+
+unsigned long __cdecl Wcstoul (const wchar_t *nptr, wchar_t **endptr, int ibase) {
+  // endptr may be NULL
+  ASSERT(nptr, (L""));
+
+  return wcstoxl(nptr, endptr, ibase, kFlUnsigned);
+}
+
+// Functions on arrays of strings
+
+// Returns true iff s is in the array strings (case-insensitive compare)
+bool String_MemberOf(const TCHAR* const* strings, const TCHAR* s) {
+  ASSERT(s, (L""));
+  // strings may be NULL
+
+  const int s_length = lstrlen(s);
+  if (strings == NULL)
+    return false;
+  for (; *strings != NULL; strings++) {
+    if (0 == String_StrNCmp(*strings, s, s_length, true)) {
+      return true;      // Found equal string
+    }
+  }
+  return false;
+}
+
+// Returns index of s in the array of strings (or -1 for missing) (case-insensitive compare)
+int String_IndexOf(const TCHAR* const* strings, const TCHAR* s) {
+  ASSERT(s, (L""));
+  // strings may be NULL
+
+  const int s_length = lstrlen(s);
+  if (strings == NULL)
+    return -1;
+  for (int i = 0; *strings != NULL; i++, strings++) {
+    if (0 == String_StrNCmp(*strings, s, s_length, true)) {
+      return i;      // Found equal string
+    }
+  }
+  return -1;
+}
+
+// The internal format is a int64.
+time64 StringToTime(const CString & time) {
+  return static_cast<time64>(String_StringToInt64(time));
+}
+
+// See above comment from StringToTime.
+// Just show it as a INT64 for now
+// NOTE: this will truncating it to INT64, which may lop off some times in the future
+CString TimeToString(const time64 & time) {
+  return String_Int64ToString(static_cast<int64>(time), 10);
+}
+
+const TCHAR *FindStringASpaceStringB (const TCHAR *s, const TCHAR *a, const TCHAR *b) {
+  ASSERT(s, (L""));
+  ASSERT(a, (L""));
+  ASSERT(b, (L""));
+
+  const TCHAR *search_from = s;
+  const TCHAR *pos;
+  while (*search_from && (pos = stristrW (search_from, a)) != NULL) {
+      const TCHAR *start = pos;
+      pos += lstrlen(a);
+      search_from = pos;
+      while (*pos == ' ' || *pos == '\t') pos++;
+      if (!String_StrNCmp (pos, b, lstrlen(b), true)) return start;
+  }
+
+  return 0;
+}
+
+bool IsAlphaA (const char c) {
+  return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
+}
+
+bool IsDigitA (const char c) {
+  return (c >= '0' && c <= '9');
+}
+
+void SafeStrCat (TCHAR *dest, const TCHAR *src, int dest_buffer_len) {
+  _tcscat_s(dest, dest_buffer_len, src);
+}
+
+// extracts next float in a string
+// skips any non-digit characters
+// return position after end of float
+const TCHAR *ExtractNextDouble (const TCHAR *s, double *f) {
+  ASSERT (f, (L""));
+  ASSERT (s, (L""));
+
+  CString num;
+  while (*s && !String_IsDigit (*s)) s++;
+  while (*s && (*s == '.' || String_IsDigit (*s))) { num += *s; s++; }
+  ASSERT (num.GetLength(), (L""));
+  *f = String_StringToDouble (num);
+  return s;
+}
+
+TCHAR *String_PathFindExtension(const TCHAR *path) {
+  ASSERT(path, (L""));
+
+  // Documentation says PathFindExtension string must be of max length
+  // MAX_PATH but a trusted tester hit the ASSERT and we don't really
+  // need it here, so commented out. We can't address where it is
+  // called because it's called from ATL code.
+  // ASSERT(lstrlen(path)<=MAX_PATH, (L""));
+
+  // point to terminating NULL
+  const TCHAR *ret = path + lstrlen(path);
+  const TCHAR *pos = ret;
+
+  while (--pos >= path) {
+    if (*pos == '.')
+      return const_cast<TCHAR *>(pos);
+  }
+
+  return const_cast<TCHAR *>(ret);
+}
+
+char String_ToLowerCharAnsi(char c) {
+  if (c >= 'A' && c <= 'Z') return (c + ('a' - 'A'));
+  return c;
+}
+
+int String_ToLowerChar(int c) {
+  // If it's < 128, then convert is ourself, which is far cheaper than the system conversion
+  if (c < 128)
+    return String_ToLowerCharAnsi(static_cast<char>(c));
+
+  return Char_ToLower(static_cast<TCHAR>(c));
+}
+
+
+bool String_PathRemoveFileSpec(TCHAR *path) {
+  ASSERT (path, (L""));
+
+  int len, pos;
+  len = pos = lstrlen (path);
+
+  // You might think that the SHLWAPI API does not change "c:\windows" -> "c:\"
+  // when c:\windows is a directory, but it does.
+
+  // If we don't want to match this weird API we can use the following to check
+  // for directories:
+
+  // Check if we are already a directory.
+  WIN32_FILE_ATTRIBUTE_DATA attrs;
+  // Failure (if file does not exist) is OK.
+  BOOL success = GetFileAttributesEx(path, GetFileExInfoStandard, &attrs);
+  UTIL_LOG(L4, (_T("[String_PathRemoveFileSpec][path %s][success %d][dir %d]"),
+                path,
+                success,
+                attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
+  if (success && (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+    // Remove trailing backslash, if any.
+    if (path[pos-1] == '\\')
+      path[pos-1] = '\0';
+    return 1;
+  }
+
+  // Find last backslash.
+  while (pos && path[pos] != '\\') pos--;
+  if (!pos && path[pos] != '\\') return 0;
+
+  ASSERT (pos < len, (L""));
+
+  // The documentation says it removes backslash but it doesn't for c:\.
+  if (!pos || path[pos-1] == ':' || (pos == 1 && path[0] == '\\'))
+    // Keep the backslash in this case.
+    path[pos+1] = '\0';
+  else
+    path[pos] = '\0';
+
+  return 1;
+}
+
+void String_EndWithChar(TCHAR *str, TCHAR c) {
+  ASSERT (str, (L""));
+  int len = lstrlen(str);
+  if (len == 0 || str[len - 1] != c) {
+    str[len] = c;
+    str[len + 1] = 0;
+  }
+}
+
+bool StartsWithBOM(const TCHAR* string) {
+  ASSERT(string, (L""));
+  wchar_t c = string[0];
+  if (c == 0xFFFE || c == 0xFEFF)
+    return true;
+  else
+    return false;
+}
+
+const TCHAR* StringAfterBOM(const TCHAR* string) {
+  ASSERT(string, (L""));
+  return &string[StartsWithBOM(string) ? 1 : 0];
+}
+
+bool String_StringToDecimalIntChecked(const TCHAR* str, int* value) {
+  ASSERT1(str);
+  ASSERT1(value);
+
+  if (_set_errno(0)) {
+    return false;
+  }
+
+  TCHAR* end_ptr = NULL;
+  *value = _tcstol(str, &end_ptr, 10);
+  ASSERT1(end_ptr);
+
+  if (errno) {
+    ASSERT1(ERANGE == errno);
+    // Overflow or underflow.
+    return false;
+  } else if (*value == 0) {
+    // The value returned could be an error code. tcsltol returns
+    // zero when it cannot convert the string. However we need to
+    // distinguish a real zero. Thus check to see if end_ptr is not the start
+    // of the string (str is not an empty string) and is pointing to a '\0'.
+    // If not, we have an error.
+    if ((str == end_ptr) || (*end_ptr != '\0')) {
+      return false;
+    }
+  } else if (*end_ptr != '\0') {
+    // The end_ptr is pointing at a character that is
+    // not the end of the string. Only part of the string could be converted.
+    return false;
+  }
+
+  return true;
+}
+
+bool CLSIDToCString(const GUID& guid, CString* str) {
+  ASSERT(str, (L""));
+
+  LPOLESTR string_guid = NULL;
+  if (::StringFromCLSID(guid, &string_guid) != S_OK) {
+    return false;
+  }
+  *str = string_guid;
+  ::CoTaskMemFree(string_guid);
+
+  return true;
+}
+
+HRESULT String_StringToBool(const TCHAR* str, bool* value) {
+  ASSERT1(str);
+  ASSERT1(value);
+
+  // This method now performs a case-insentitive
+  // culture aware compare. We should however be ok as we are only comparing
+  // latin characters.
+  if (_tcsicmp(kFalse, str) == 0) {
+    *value = false;
+  } else if (_tcsicmp(kTrue, str) == 0) {
+    *value = true;
+  } else {
+    // we found another string. should error out.
+    return E_FAIL;
+  }
+  return S_OK;
+}
+
+HRESULT String_BoolToString(bool value, CString* string) {
+  ASSERT1(string);
+  *string = value ? kTrue : kFalse;
+  return S_OK;
+}
+
+// Escape and unescape strings (shlwapi-based implementation).
+// The intended usage for these APIs is escaping strings to make up
+// URLs, for example building query strings.
+//
+// Pass false to the flag segment_only to escape the url. This will not
+// cause the conversion of the # (%23), ? (%3F), and / (%2F) characters.
+
+// Characters that must be encoded include any characters that have no
+// corresponding graphic character in the US-ASCII coded character
+// set (hexadecimal 80-FF, which are not used in the US-ASCII coded character
+// set, and hexadecimal 00-1F and 7F, which are control characters),
+// blank spaces, "%" (which is used to encode other characters),
+// and unsafe characters (<, >, ", #, {, }, |, \, ^, ~, [, ], and ').
+//
+// The input and output strings can't be longer than INTERNET_MAX_URL_LENGTH
+
+HRESULT StringEscape(const CString& str_in,
+                     bool segment_only,
+                     CString* str_out) {
+  ASSERT1(str_out);
+  ASSERT1(str_in.GetLength() < INTERNET_MAX_URL_LENGTH);
+
+  DWORD buf_len = INTERNET_MAX_URL_LENGTH + 1;
+  HRESULT hr = ::UrlEscape(str_in, str_out->GetBufferSetLength(buf_len), &buf_len,
+    segment_only ? URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY : URL_ESCAPE_PERCENT);
+  if (SUCCEEDED(hr)) {
+    str_out->ReleaseBuffer();
+    ASSERT1(buf_len <= INTERNET_MAX_URL_LENGTH);
+  }
+  return hr;
+}
+
+HRESULT StringUnescape(const CString& str_in, CString* str_out) {
+  ASSERT1(str_out);
+  ASSERT1(str_in.GetLength() < INTERNET_MAX_URL_LENGTH);
+
+  DWORD buf_len = INTERNET_MAX_URL_LENGTH + 1;
+  HRESULT hr = ::UrlUnescape(const_cast<TCHAR*>(str_in.GetString()),
+    str_out->GetBufferSetLength(buf_len), &buf_len, 0);
+  if (SUCCEEDED(hr)) {
+    str_out->ReleaseBuffer(buf_len + 1);
+    ASSERT1(buf_len <= INTERNET_MAX_URL_LENGTH);
+  }
+  return hr;
+}
+
+bool String_StringToTristate(const TCHAR* str, Tristate* value) {
+  ASSERT1(str);
+  ASSERT1(value);
+
+  int numerical_value = 0;
+  if (!String_StringToDecimalIntChecked(str, &numerical_value)) {
+    return false;
+  }
+
+  switch (numerical_value) {
+    case 0:
+      *value = TRISTATE_FALSE;
+      break;
+    case 1:
+      *value = TRISTATE_TRUE;
+      break;
+    case 2:
+      *value = TRISTATE_NONE;
+      break;
+    default:
+      return false;
+  }
+
+  return true;
+}
+
+// Extracts the name and value from a string that contains a name/value pair.
+bool ParseNameValuePair(const CString& token,
+                        TCHAR separator,
+                        CString* name,
+                        CString* value) {
+  ASSERT1(name);
+  ASSERT1(value);
+
+  int separator_index = token.Find(separator);
+  if ((separator_index == -1) ||  // Not a name-value pair.
+      (separator_index == 0) ||  // No name was supplied.
+      (separator_index == (token.GetLength() - 1))) {  // No value was supplied.
+    return false;
+  }
+
+  *name = token.Left(separator_index);
+  *value = token.Right(token.GetLength() - separator_index - 1);
+
+  ASSERT1(token.GetLength() == name->GetLength() + value->GetLength() + 1);
+
+  // It's not possible for the name to contain the separator.
+  ASSERT1(-1 == name->Find(separator));
+  if (-1 != value->Find(separator)) {
+    // The value contains the separator.
+    return false;
+  }
+
+  return true;
+}
+
+bool SplitCommandLineInPlace(TCHAR *command_line,
+                             TCHAR **first_argument_parameter,
+                             TCHAR **remaining_arguments_parameter) {
+  if (!command_line ||
+      !first_argument_parameter ||
+      !remaining_arguments_parameter) {
+    return false;
+  }
+
+  TCHAR end_char;
+  TCHAR *&first_argument = *first_argument_parameter;
+  TCHAR *&remaining_arguments = *remaining_arguments_parameter;
+  if (_T('\"') == *command_line) {
+    end_char = _T('\"');
+    first_argument = remaining_arguments = command_line + 1;
+  } else {
+    end_char = _T(' ');
+    first_argument = remaining_arguments = command_line;
+  }
+  // Search for the end of the first argument
+  while (end_char != *remaining_arguments && '\0' != *remaining_arguments) {
+    ++remaining_arguments;
+  }
+  if (end_char == *remaining_arguments) {
+    *remaining_arguments = '\0';
+    do {
+      // Skip the spaces between the first argument and the remaining arguments.
+      ++remaining_arguments;
+    } while (_T(' ') == *remaining_arguments);
+  }
+  return true;
+}
+
+bool ContainsOnlyAsciiChars(const CString& str) {
+  for (int i = 0; i < str.GetLength(); ++i) {
+    if (str[i] > 0x7F) {
+      return false;
+    }
+  }
+  return true;
+}
+CString BytesToHex(const uint8* bytes, size_t num_bytes) {
+  CString result;
+  if (bytes) {
+    result.Preallocate(num_bytes * sizeof(TCHAR));
+    static const TCHAR* const kHexChars = _T("0123456789abcdef");
+    for (size_t i = 0; i != num_bytes; ++i) {
+      result.AppendChar(kHexChars[(bytes[i] >> 4)]);
+      result.AppendChar(kHexChars[(bytes[i] & 0xf)]);
+    }
+  }
+  return result;
+}
+
+CString BytesToHex(const std::vector<uint8>& bytes) {
+  CString result;
+  if (!bytes.empty()) {
+    result.SetString(BytesToHex(&bytes.front(), bytes.size()));
+  }
+  return result;
+}
+
+void JoinStrings(const std::vector<CString>& components,
+                 const TCHAR* delim,
+                 CString* result) {
+  ASSERT1(result);
+  result->Empty();
+
+  // Compute length so we can reserve memory.
+  size_t length = 0;
+  size_t delim_length = delim ? _tcslen(delim) : 0;
+  for (size_t i = 0; i != components.size(); ++i) {
+    if (i != 0) {
+      length += delim_length;
+    }
+    length += components[i].GetLength();
+  }
+
+  result->Preallocate(length);
+
+  for (size_t i = 0; i != components.size(); ++i) {
+    if (i != 0 && delim) {
+      result->Append(delim, delim_length);
+    }
+    result->Append(components[i]);
+  }
+}
+
+void JoinStringsInArray(const TCHAR* components[],
+                        int num_components,
+                        const TCHAR* delim,
+                        CString* result) {
+  ASSERT1(result);
+  result->Empty();
+
+  for (int i = 0; i != num_components; ++i) {
+    if (i != 0 && delim) {
+      result->Append(delim);
+    }
+    if (components[i]) {
+      result->Append(components[i]);
+    }
+  }
+}
+
+CString FormatResourceMessage(uint32 resource_id, ...) {
+  CString format;
+  const bool is_loaded = !!format.LoadString(resource_id);
+
+  if (!is_loaded) {
+    return CString();
+  }
+
+  va_list arg_list;
+  va_start(arg_list, resource_id);
+
+  CString formatted;
+  formatted.FormatMessageV(format, &arg_list);
+
+  va_end(arg_list);
+
+  return formatted;
+}
+
+CString FormatErrorCode(DWORD error_code) {
+  CString error_code_string;
+  if (FAILED(error_code)) {
+    error_code_string.Format(_T("0x%08x"), error_code);
+  } else {
+    error_code_string.Format(_T("%u"), error_code);
+  }
+  return error_code_string;
+}
+
+HRESULT WideStringToUtf8UrlEncodedString(const CString& str, CString* out) {
+  ASSERT1(out);
+
+  out->Empty();
+  if (str.IsEmpty()) {
+    return S_OK;
+  }
+
+  // Utf8 encode the Utf16 string first. Next urlencode it.
+  CStringA utf8str = WideToUtf8(str);
+  ASSERT1(!utf8str.IsEmpty());
+  DWORD buf_len = INTERNET_MAX_URL_LENGTH;
+  CStringA escaped_utf8_name;
+  HRESULT hr = ::UrlEscapeA(utf8str,
+                            CStrBufA(escaped_utf8_name, buf_len),
+                            &buf_len,
+                            0);
+  ASSERT1(buf_len <= INTERNET_MAX_URL_LENGTH);
+  ASSERT1(escaped_utf8_name.GetLength() == static_cast<int>(buf_len));
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[UrlEscapeA failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  *out = CString(escaped_utf8_name);
+  return S_OK;
+}
+
+HRESULT Utf8UrlEncodedStringToWideString(const CString& str, CString* out) {
+  ASSERT1(out);
+
+  out->Empty();
+  if (str.IsEmpty()) {
+    return S_OK;
+  }
+
+  // The value is a utf8 encoded url escaped string that is stored as a
+  // unicode string. Because of this, it should contain only ascii chars.
+  if (!ContainsOnlyAsciiChars(str)) {
+    UTIL_LOG(LE, (_T("[String contains non ascii chars]")));
+    return E_INVALIDARG;
+  }
+
+  CStringA escaped_utf8_val = WideToAnsiDirect(str);
+  DWORD buf_len = INTERNET_MAX_URL_LENGTH;
+  CStringA unescaped_val;
+  HRESULT hr = ::UrlUnescapeA(const_cast<char*>(escaped_utf8_val.GetString()),
+                              CStrBufA(unescaped_val, buf_len),
+                              &buf_len,
+                              0);
+  ASSERT1(unescaped_val.GetLength() == static_cast<int>(buf_len));
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[UrlUnescapeA failed][0x%08x]"), hr));
+    return hr;
+  }
+  ASSERT1(buf_len == static_cast<DWORD>(unescaped_val.GetLength()));
+  ASSERT1(buf_len <= INTERNET_MAX_URL_LENGTH);
+  CString app_name = Utf8ToWideChar(unescaped_val,
+                                    unescaped_val.GetLength());
+  if (app_name.IsEmpty()) {
+    return E_INVALIDARG;
+  }
+
+  *out = app_name;
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/common/string.h b/common/string.h
index ccf105e..258aa1b 100644
--- a/common/string.h
+++ b/common/string.h
@@ -1,537 +1,537 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_STRING_H__

-#define OMAHA_COMMON_STRING_H__

-

-#include <windows.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-#define STR_SIZE(str) (arraysize(str)-1)  // number of characters in char array (only for single-byte string literals!!!)

-#define TSTR_SIZE(tstr) (arraysize(tstr)-1)  // like STR_SIZE but works on _T("string literal") ONLY!!!

-

-#define kEllipsis L".."

-

-// The number of replacements matches we expect, before we start allocating extra memory

-// to process it. This is an optimizing constant

-#define kExpectedMaxReplaceMatches 100

-

-// TODO(omaha): above each of these function names, we should

-// define what we expect the implementation to do. that way,

-// implementers will know what is desired. an example would probably

-// make things easiest.

-CString AbbreviateString (const CString & title, int32 max_len);

-CString AbbreviateUri (const CString & uri, int32 max_len);

-CString NormalizeUri (const CString & uri);

-

-// removes "http://", "ftp://", "mailto:" or "file://" (note that the "file" protocol is

-// like: "file:///~/calendar", this method removes only the first two slashes

-CString RemoveInternetProtocolHeader (const CString& url);

-

-void RemoveFromStart (CString & s, const TCHAR* remove, bool ignore_case);

-void RemoveFromEnd (CString & s, const TCHAR* remove);

-

-// Limit string to max length, truncating and adding ellipsis if needed

-// Attempts to not leave a partial word at the end, unless min_len is reached

-CString ElideIfNeeded (const CString & input_string, int max_len, int min_len);

-

-// The ability to clean up a string for relevant target audiences. Add flags accordingly

-

-// Sanitizes for insertion in an HTML document, uses the basic literals [<>&]

-#define kSanHtml 0x1

-

-// XML is the HTML replacements, and a few more

-#define kSanXml (kSanHtml | 0x2)

-

-// Javascript has a seperate set of encodings [which is a superset of HTML replacements]

-#define kSanJs (kSanHtml | 0x4)

-

-// For input fields on HTML documents

-#define kSanHtmlInput 0x8

-

-// TODO(omaha): be consistent on use of int/uint32/int32 for lengths

-

-// The input length of the string does not include the null terminator.

-// Caller deletes the returned buffer.

-WCHAR *ToWide (const char *s, int len);

-

-// returns pointer to data if found otherwise NULL

-const byte *BufferContains (const byte *buf, uint32 buf_len, const byte *data, uint32 data_len);

-

-// Given a string, 'protect' the characters that are invalid for a given mode

-// For instance, kSanHtml will replace < with the HTML literal equivalent

-// If kSanHtml is used, and bold_periods is true, then periods used for url abbreviation are bolded.

-// NOTE: If you call AbbreviateLinkForDisplay before this function, then there might be periods

-// used for abbreviation.  BoldAbbreviationPeriods should be called after HighlightTerms.

-CString SanitizeString(const CString & in, DWORD mode);

-

-// Bolds the periods used for abbreviation.  Call this after HighlightTerms.

-CString BoldAbbreviationPeriods(const CString & in);

-

-// Unencode a URL encoded string

-CString Unencode(const CString & input);

-

-CString GetTextInbetween(const CString &input, const CString &start, const CString &end);

-

-// Given a ? seperated string, extract a particular segment, and URL-Unencode it

-CString GetParam(const CString & input, const CString & key);

-

-// Given an XML style string, extract the contents of a <INPUT>...</INPUT> pair

-CString GetField (const CString & input, const CString & field);

-

-// Finds a whole word match in the query, followed by a ":".

-// If not found, return -1.

-//

-// Note: this is case sensitive.

-int FindWholeWordMatch (const CString &query,

-  const CString &word_to_match,

-  const bool end_with_colon,

-  const int index_begin);

-

-// Do whole-word replacement in "str".

-// This does not do partial matches (unlike CString::Replace),

-//   e.g.  CString::Replace will replace "ie" within "pie" and

-// this function will not.

-//

-// Note: this is case sensitive.

-void ReplaceWholeWord (const CString &string_to_replace,

-  const CString &replacement,

-  const bool trim_whitespace,

-  CString *str);

-

-// Convert Wide to ANSI directly. Use only when it is all ANSI

-CStringA WideToAnsiDirect(const CString & in);

-

-// Transform a unicode string into UTF8, used primarily by the webserver

-CStringA WideToUtf8(const CString& w);

-

-// Converts the UTF-8 encoded buffer to an in-memory Unicode (wide character)

-// string.

-// @param utf8 A non-NULL pointer to a UTF-8 encoded buffer that has at

-// least num_bytes valid characters.  If num_bytes is 0, the buffer must be

-// NULL-terminated.

-// @param num_bytes Number of bytes to process from utf8, or 0 if utf8 is

-// NULL-terminated and should be processed in its entirety.

-// @return The Unicode string represented by utf8 (or that part of it

-// specified by num_bytes).  If the UTF-8 representation of the string started

-// with a byte-order marker (BOM), it will be ignored and not included in the

-// returned string.  On failure, the function returns the empty string.

-CString Utf8ToWideChar(const char* utf8, uint32 num_bytes);

-CString Utf8BufferToWideChar(const std::vector<uint8>& buffer);

-

-// Dealing with Unicode BOM

-bool StartsWithBOM(const TCHAR* string);

-const TCHAR* StringAfterBOM(const TCHAR* string);

-

-// Convert an ANSI string into Widechar string, according to the specified

-// codepage. The input length can be -1, if the string is null terminated, and

-// the actual length will be used internally.

-BOOL AnsiToWideString(const char *from, int length, UINT codepage, CString *to);

-

-// Convert char to Wchar directly

-CString AnsiToWideString(const char *from, int length);

-

-// these functions untested

-// they should not be used unless tested

-// HRESULT AnsiToUTF8 (char * src, int src_len, char * dest, int *dest_len);

-// HRESULT UTF8ToAnsi (char * src, int src_len, char * dest, int *dest_len);

-// HRESULT UCS2ToUTF8 (LPCWSTR src, int src_len, char * dest, int *dest_len);

-// HRESULT UTF8ToUCS2 (char * src, int src_len, LPWSTR dest, int *dest_len);

-

-// "Absolute" is perhaps not the right term, this normalizes the Uri

-// given http://www.google.com changes to correct http://www.google.com/

-// given http://www.google.com// changes to correct http://www.google.com/

-// given http://www.google.com/home.html returns the same

-CString GetAbsoluteUri(const CString& uri);

-

-// Reverse (big-endian<->little-endian) the shorts that make up

-// Unicode characters in a byte array of Unicode chars

-HRESULT ReverseUnicodeByteOrder(byte* unicode_string, int size_in_bytes);

-

-// given http://google.com/bobby this returns http://google.com/

-// If strip_leading is specified, it will turn

-// http://www.google.com into http://google.com

-#define kStrLeadingWww _T("www.")

-// TODO(omaha): no default parameters

-CString GetUriHostName(const CString& uri, bool strip_leading = false);

-CString GetUriHostNameHostOnly(const CString& uri, bool strip_leading_www);

-

-const char *stristr(const char *string, const char *pattern);

-const WCHAR *stristrW(const WCHAR *string, const WCHAR *pattern);

-const WCHAR *strstrW(const WCHAR *string, const WCHAR *pattern);

-

-// Add len_to_add to len_so_far, assuming that if it exceeds the

-// length of the line, it will word wrap onto the next line.  Returns

-// the total length of all the lines summed together.

-float GetLenWithWordWrap (const float len_so_far,

-  const float len_to_add,

-  const uint32 len_line);

-

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

-// QuotedPrintableUnescape()

-//    Copies "src" to "dest", rewriting quoted printable escape sequences

-//    =XX to their ASCII equivalents. src is not null terminated, instead

-//    specify len. I recommend that slen<len_dest, but we honour len_dest

-//    anyway.

-//    RETURNS the length of dest.

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

-int QuotedPrintableUnescape(const WCHAR *src, int slen, WCHAR *dest, int len_dest);

-

-// Return the length to use for the output buffer given to the base64 escape

-// routines. Make sure to use the same value for do_padding in both.

-// This function may return incorrect results if given input_len values that

-// are extremely high, which should happen rarely.

-int CalculateBase64EscapedLen(int input_len, bool do_padding);

-// Use this version when calling Base64Escape without a do_padding arg.

-int CalculateBase64EscapedLen(int input_len);

-

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

-// Base64Escape()

-// WebSafeBase64Escape()

-//    Encode "src" to "dest" using base64 encoding.

-//    src is not null terminated, instead specify len.

-//    'dest' should have at least CalculateBase64EscapedLen() length.

-//    RETURNS the length of dest.

-//    The WebSafe variation use '-' instead of '+' and '_' instead of '/'

-//    so that we can place the out in the URL or cookies without having

-//    to escape them.  It also has an extra parameter "do_padding",

-//    which when set to false will prevent padding with "=".

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

-int Base64Escape(const char *src, int slen, char *dest, int szdest);

-int WebSafeBase64Escape(const char *src, int slen, char *dest,

-                        int szdest, bool do_padding);

-void WebSafeBase64Escape(const CStringA& src, CStringA* dest);

-

-void Base64Escape(const char *src, int szsrc,

-                  CStringA* dest, bool do_padding);

-void WebSafeBase64Escape(const char *src, int szsrc,

-                         CStringA* dest, bool do_padding);

-

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

-// Base64Unescape()

-//    Copies "src" to "dest", where src is in base64 and is written to its

-//    ASCII equivalents. src is not null terminated, instead specify len.

-//    I recommend that slen<len_dest, but we honour len_dest anyway.

-//    RETURNS the length of dest.

-//    The WebSafe variation use '-' instead of '+' and '_' instead of '/'.

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

-int Base64Unescape(const char *src, int slen, char *dest, int len_dest);

-int WebSafeBase64Unescape(const char *src, int slen, char *dest, int szdest);

-

-#ifdef UNICODE

-#define IsSpace IsSpaceW

-#else

-#define IsSpace IsSpaceA

-#endif

-

-bool IsSpaceW(WCHAR c);

-bool IsSpaceA(char c);

-

-// Remove all leading and trailing whitespace from s.

-// Returns the new length of the string (not including 0-terminator)

-int TrimCString(CString &s);

-int Trim(TCHAR *s);

-

-// Trims all characters in the delimiter string from both ends of the

-// string s

-void TrimString(CString& s, const TCHAR* delimiters);

-

-// Strip the first token from the front of argument s.  A token is a

-// series of consecutive non-blank characters - unless the first

-// character is a double-quote ("), in that case the token is the full

-// quoted string

-CString StripFirstQuotedToken(const CString& s);

-

-// A block of text to separate lines, and back

-void TextToLines(const CString& text, const TCHAR* delimiter, std::vector<CString>* lines);

-// (LinesToText puts a delimiter at the end of the last line too)

-void LinesToText(const std::vector<CString>& lines, const TCHAR* delimiter, CString* text);

-

-// Make a CString lower case

-void MakeLowerCString(CString & s);

-

-// Clean up the string: replace all whitespace with spaces, and

-// replace consecutive spaces with one.

-// Returns the new length of the string (not including 0-terminator)

-int CleanupWhitespaceCString(CString &s);

-int CleanupWhitespace(TCHAR *s);

-

-int HexDigitToInt (WCHAR c);

-bool IsHexDigit (WCHAR c);

-

-// Converts to lower, but does so much faster if the string is ANSI

-TCHAR * String_FastToLower(TCHAR * str);

-

-// Replacement for the CRT toupper(c)

-int String_ToUpper(int c);

-

-// Replacement for the CRT toupper(c)

-char String_ToUpperA(char c);

-

-// Converts str to lowercase in place.

-void String_ToLower(TCHAR* str);

-

-// Converts str to uppercase in place.

-void String_ToUpper(TCHAR* str);

-

-bool String_IsUpper(TCHAR c);

-

-// String comparison based on length

-// Replacement for the CRT strncmp(i)

-int String_StrNCmp(const TCHAR * str1, const TCHAR * str2, uint32 len, bool ignore_case);

-

-// Replacement for strncpy() - except ALWAYS ends string with null

-TCHAR* String_StrNCpy(TCHAR* destination, const TCHAR* source, uint32 len);

-

-// check if str starts with start_str

-bool String_StartsWith(const TCHAR *str, const TCHAR *start_str, bool ignore_case);

-

-// check if str starts with start_str, for char *

-bool String_StartsWithA(const char *str, const char *start_str, bool ignore_case);

-

-// check if str ends with end_str

-bool String_EndsWith(const TCHAR *str, const TCHAR *end_str, bool ignore_case);

-

-// If the input string str doesn't already end with the string end_str,

-// make it end with the string end_str.

-CString String_MakeEndWith(const TCHAR *str, const TCHAR* end_str, bool ignore_case);

-

-// converts an int to a string

-CString String_Int64ToString(int64 value, int radix);

-

-// converts an uint64 to a string

-CString String_Uint64ToString(uint64 value, int radix);

-

-// Convert numeric types to CString

-CString sizet_to_str(const size_t & i);

-CString itostr(const int i);

-CString itostr(const uint32 i);

-

-// converts a large number to an approximate value, like "1.2G" or "900M"

-// base_ten = true if based on powers of 10 (like disk space) otherwise based

-// on powers of two.  power = 0 for *10^0, 1 for *10^3 or 2^10, 2 for *10^6

-// or 2^20, and 3 for *10^9 or 2^30, in other words: no units, K, M, or G.

-CString String_LargeIntToApproximateString(uint64 value, bool base_ten, int* power);

-

-// converts a string to an  int

-// Does not check for overflow

-int32 String_StringToInt(const TCHAR * str);

-

-int64 String_StringToInt64(const TCHAR * str);

-

-// converts an double to a string

-// specifies the number of digits after the decimal point

-// TODO(omaha): Make this work for negative values

-CString String_DoubleToString(double value, int point_digits);

-

-// convert string to double

-double String_StringToDouble (const TCHAR *s);

-

-// Converts a character to a digit

-// if the character is not a digit return -1

-int32 String_CharToDigit(const TCHAR c);

-

-// returns true if ASCII digit

-bool String_IsDigit(const TCHAR c);

-

-// Converts the digit to a character.

-TCHAR String_DigitToChar(unsigned int n);

-

-// Returns true if an identifier character: letter, digit, or "_"

-bool String_IsIdentifierChar(const TCHAR c);

-

-// Returns true if the string has letters in it.

-// This is used by the keyword extractor to downweight numbers,

-// IDs (sequences of numbers like social security numbers), etc.

-bool String_HasAlphabetLetters (const TCHAR *str);

-

-// Return the index of the first occurrence of s2 in s1, or -1 if none.

-int String_FindString(const TCHAR *s1, const TCHAR *s2);

-int String_FindString(const TCHAR *s1, const TCHAR *s2, int start_pos);

-

-// Return the index of the first occurrence of c in s1, or -1 if none.

-int String_FindChar(const TCHAR *str, const TCHAR c);

-// start from index start_pos

-int String_FindChar(const TCHAR *str, const TCHAR c, int start_pos);

-

-// Return the index of the first occurrence of c in string, or -1 if none.

-int String_ReverseFindChar(const TCHAR * str, TCHAR c);

-

-bool String_Contains(const TCHAR *s1, const TCHAR *s2);

-

-// Replace old_char with new_char in str.

-void String_ReplaceChar(TCHAR *str, TCHAR old_char, TCHAR new_char);

-void String_ReplaceChar(CString & str, TCHAR old_char, TCHAR new_char);

-

-// Append the given character to the string if it doesn't already end with it.

-// There must be room in the string to append the character if necessary.

-void String_EndWithChar(TCHAR *str, TCHAR c);

-

-// A special version of the replace function which takes advantage of CString properties

-// to make it much faster when the string grows

-

-// NOTE: it CANNOT match more than kMaxReplaceMatches instances within the string

-// do not use this function if that is a possibility

-

-// The maximum number of replacements to perform. Essentially infinite

-#define kRepMax kUint32Max

-int ReplaceCString (CString & src, const TCHAR *from, unsigned int from_len,

-                                   const TCHAR *to, unsigned int to_len,

-                                   unsigned int max_matches);

-

-// replace from with to in src

-// on memory allocation error, returns the original string

-int ReplaceString (TCHAR *src, const TCHAR *from, const TCHAR *to, TCHAR **out, int *out_len);

-

-// replace from with to in src

-// will replace in place if length(to) <= length(from) and return *out == src

-// WILL CREATE NEW OUTPUT BUFFER OTHERWISE and set created_new_string to true

-// on memory allocation error, returns the original string

-int ReplaceStringMaybeInPlace (TCHAR *src, const TCHAR *from, const TCHAR *to, TCHAR **out, int *out_len, bool *created_new_string);

-

-// you really want to use the straight TCHAR version above. you know it

-// on memory allocation error, returns the original string

-int ReplaceCString (CString & src, const TCHAR *from, const TCHAR *to);

-

-long __cdecl Wcstol (const wchar_t *nptr, wchar_t **endptr, int ibase);

-unsigned long __cdecl Wcstoul (const wchar_t *nptr, wchar_t **endptr, int ibase);

-

-// Functions on arrays of strings

-

-// Returns true iff s is in the array strings (case-insensitive compare)

-bool String_MemberOf(const TCHAR* const* strings, const TCHAR* s);

-// Returns index of s in the array of strings (or -1 for missing) (case-insensitive compare)

-int String_IndexOf(const TCHAR* const* strings, const TCHAR* s);

-

-// Serializes a time64 to a string, and then loads it out again, this string it not for human consumption

-time64 StringToTime(const CString & time);

-CString TimeToString(const time64 & time);

-

-// looks for string A followed by any number of spaces/tabs followed by string b

-// returns starting position of a if found, NULL if not

-// case insensitive

-const TCHAR *FindStringASpaceStringB (const TCHAR *s, const TCHAR *a, const TCHAR *b);

-

-bool IsAlphaA (const char c);

-bool IsDigitA (const char c);

-

-// TODO(omaha): deprecate since we have secure CRT now.

-// dest_buffer_len includes the NULL

-// always NULL terminates

-// dest must be a valid string with length < dest_buffer_len

-void SafeStrCat (TCHAR *dest, const TCHAR *src, int dest_buffer_len);

-

-const TCHAR *ExtractNextDouble (const TCHAR *s, double *f);

-

-TCHAR *String_PathFindExtension(const TCHAR *path);

-

-inline TCHAR Char_ToLower(TCHAR c) {

-// C4302: truncation from 'type 1' to 'type 2'

-#pragma  warning(disable : 4302)

-  return reinterpret_cast<TCHAR>(::CharLower(reinterpret_cast<TCHAR*>(c)));

-#pragma warning(default : 4302)

-}

-

-// @returns the lowercase character (type is int to be consistent with the CRT)

-int String_ToLowerChar(int c);

-

-// Replacement for the CRT tolower(c)

-char String_ToLowerCharAnsi(char c);

-

-bool String_PathRemoveFileSpec(TCHAR *path);

-

-// Escapes and unescapes strings (shlwapi-based implementation).

-// The indended usage for these APIs is escaping strings to make up

-// URLs, for example building query strings.

-//

-// Pass false to the flag segment_only to escape the url. This will not

-// cause the conversion of the # (%23), ? (%3F), and / (%2F) characters.

-HRESULT StringEscape(const CString& str_in,

-                     bool segment_only,

-                     CString* str_out);

-

-HRESULT StringUnescape(const CString& str_in, CString* str_out);

-

-// Converts a string to an int, performs all the necessary

-// checks to ensure that the string is correct.

-// Tests for overflow and non-int strings.

-bool String_StringToDecimalIntChecked(const TCHAR* str, int* value);

-

-// Converts CLSID to a string.

-bool CLSIDToCString(const GUID& guid, CString* str);

-

-// Converts a string to a bool.

-HRESULT String_StringToBool(const TCHAR* str, bool* value);

-

-// Convert boolean to its string representation.

-HRESULT String_BoolToString(bool value, CString* string);

-

-// Converts a string to a Tristate enum.

-bool String_StringToTristate(const TCHAR* str, Tristate* value);

-

-// Extracts the name and value from a string that contains a name/value pair.

-bool ParseNameValuePair(const CString& token, TCHAR separator,

-                        CString* name, CString* value);

-

-// Splits a command line buffer into two parts in place:

-// first argument (which could be path to executable) and remaining arguments.

-// Note that the same pointer can be used for both command_line and

-// either of the remaining parameters.

-bool SplitCommandLineInPlace(TCHAR *command_line,

-                             TCHAR **first_argument,

-                             TCHAR **remaining_arguments);

-

-// Returns true if the unicode string only contains ascii values.

-bool ContainsOnlyAsciiChars(const CString& str);

-// Converts a buffer of bytes to a hex string.

-CString BytesToHex(const uint8* bytes, size_t num_bytes);

-

-// Converts a vector of bytes to a hex string.

-CString BytesToHex(const std::vector<uint8>& bytes);

-

-void JoinStrings(const std::vector<CString>& components,

-                 const TCHAR* delim,

-                 CString* result);

-

-void JoinStringsInArray(const TCHAR* components[],

-                        int num_components,

-                        const TCHAR* delim,

-                        CString* result);

-

-// Formats the specified message ID.

-// It is similar to CStringT::FormatMessage() but it returns an empty string

-// instead of throwing when the message ID cannot be loaded.

-CString FormatResourceMessage(uint32 resource_id, ...);

-

-// Formats an error code as an 8-digit HRESULT-style hex number or an unsigned

-// integer depending on whether it matches the HRESULT failure format.

-CString FormatErrorCode(DWORD error_code);

-

-// Converts the unicode string into a utf8 encoded, urlencoded string.

-// The resulting ascii string is returned in a wide CString.

-HRESULT WideStringToUtf8UrlEncodedString(const CString& str, CString* out);

-

-// Converts a string that is in the utf8 representation and is urlencoded

-// into a unicode string.

-HRESULT Utf8UrlEncodedStringToWideString(const CString& str, CString* out);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_STRING_H__

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_STRING_H__
+#define OMAHA_COMMON_STRING_H__
+
+#include <windows.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+#define STR_SIZE(str) (arraysize(str)-1)  // number of characters in char array (only for single-byte string literals!!!)
+#define TSTR_SIZE(tstr) (arraysize(tstr)-1)  // like STR_SIZE but works on _T("string literal") ONLY!!!
+
+#define kEllipsis L".."
+
+// The number of replacements matches we expect, before we start allocating extra memory
+// to process it. This is an optimizing constant
+#define kExpectedMaxReplaceMatches 100
+
+// TODO(omaha): above each of these function names, we should
+// define what we expect the implementation to do. that way,
+// implementers will know what is desired. an example would probably
+// make things easiest.
+CString AbbreviateString (const CString & title, int32 max_len);
+CString AbbreviateUri (const CString & uri, int32 max_len);
+CString NormalizeUri (const CString & uri);
+
+// removes "http://", "ftp://", "mailto:" or "file://" (note that the "file" protocol is
+// like: "file:///~/calendar", this method removes only the first two slashes
+CString RemoveInternetProtocolHeader (const CString& url);
+
+void RemoveFromStart (CString & s, const TCHAR* remove, bool ignore_case);
+void RemoveFromEnd (CString & s, const TCHAR* remove);
+
+// Limit string to max length, truncating and adding ellipsis if needed
+// Attempts to not leave a partial word at the end, unless min_len is reached
+CString ElideIfNeeded (const CString & input_string, int max_len, int min_len);
+
+// The ability to clean up a string for relevant target audiences. Add flags accordingly
+
+// Sanitizes for insertion in an HTML document, uses the basic literals [<>&]
+#define kSanHtml 0x1
+
+// XML is the HTML replacements, and a few more
+#define kSanXml (kSanHtml | 0x2)
+
+// Javascript has a seperate set of encodings [which is a superset of HTML replacements]
+#define kSanJs (kSanHtml | 0x4)
+
+// For input fields on HTML documents
+#define kSanHtmlInput 0x8
+
+// TODO(omaha): be consistent on use of int/uint32/int32 for lengths
+
+// The input length of the string does not include the null terminator.
+// Caller deletes the returned buffer.
+WCHAR *ToWide (const char *s, int len);
+
+// returns pointer to data if found otherwise NULL
+const byte *BufferContains (const byte *buf, uint32 buf_len, const byte *data, uint32 data_len);
+
+// Given a string, 'protect' the characters that are invalid for a given mode
+// For instance, kSanHtml will replace < with the HTML literal equivalent
+// If kSanHtml is used, and bold_periods is true, then periods used for url abbreviation are bolded.
+// NOTE: If you call AbbreviateLinkForDisplay before this function, then there might be periods
+// used for abbreviation.  BoldAbbreviationPeriods should be called after HighlightTerms.
+CString SanitizeString(const CString & in, DWORD mode);
+
+// Bolds the periods used for abbreviation.  Call this after HighlightTerms.
+CString BoldAbbreviationPeriods(const CString & in);
+
+// Unencode a URL encoded string
+CString Unencode(const CString & input);
+
+CString GetTextInbetween(const CString &input, const CString &start, const CString &end);
+
+// Given a ? seperated string, extract a particular segment, and URL-Unencode it
+CString GetParam(const CString & input, const CString & key);
+
+// Given an XML style string, extract the contents of a <INPUT>...</INPUT> pair
+CString GetField (const CString & input, const CString & field);
+
+// Finds a whole word match in the query, followed by a ":".
+// If not found, return -1.
+//
+// Note: this is case sensitive.
+int FindWholeWordMatch (const CString &query,
+  const CString &word_to_match,
+  const bool end_with_colon,
+  const int index_begin);
+
+// Do whole-word replacement in "str".
+// This does not do partial matches (unlike CString::Replace),
+//   e.g.  CString::Replace will replace "ie" within "pie" and
+// this function will not.
+//
+// Note: this is case sensitive.
+void ReplaceWholeWord (const CString &string_to_replace,
+  const CString &replacement,
+  const bool trim_whitespace,
+  CString *str);
+
+// Convert Wide to ANSI directly. Use only when it is all ANSI
+CStringA WideToAnsiDirect(const CString & in);
+
+// Transform a unicode string into UTF8, used primarily by the webserver
+CStringA WideToUtf8(const CString& w);
+
+// Converts the UTF-8 encoded buffer to an in-memory Unicode (wide character)
+// string.
+// @param utf8 A non-NULL pointer to a UTF-8 encoded buffer that has at
+// least num_bytes valid characters.  If num_bytes is 0, the buffer must be
+// NULL-terminated.
+// @param num_bytes Number of bytes to process from utf8, or 0 if utf8 is
+// NULL-terminated and should be processed in its entirety.
+// @return The Unicode string represented by utf8 (or that part of it
+// specified by num_bytes).  If the UTF-8 representation of the string started
+// with a byte-order marker (BOM), it will be ignored and not included in the
+// returned string.  On failure, the function returns the empty string.
+CString Utf8ToWideChar(const char* utf8, uint32 num_bytes);
+CString Utf8BufferToWideChar(const std::vector<uint8>& buffer);
+
+// Dealing with Unicode BOM
+bool StartsWithBOM(const TCHAR* string);
+const TCHAR* StringAfterBOM(const TCHAR* string);
+
+// Convert an ANSI string into Widechar string, according to the specified
+// codepage. The input length can be -1, if the string is null terminated, and
+// the actual length will be used internally.
+BOOL AnsiToWideString(const char *from, int length, UINT codepage, CString *to);
+
+// Convert char to Wchar directly
+CString AnsiToWideString(const char *from, int length);
+
+// these functions untested
+// they should not be used unless tested
+// HRESULT AnsiToUTF8 (char * src, int src_len, char * dest, int *dest_len);
+// HRESULT UTF8ToAnsi (char * src, int src_len, char * dest, int *dest_len);
+// HRESULT UCS2ToUTF8 (LPCWSTR src, int src_len, char * dest, int *dest_len);
+// HRESULT UTF8ToUCS2 (char * src, int src_len, LPWSTR dest, int *dest_len);
+
+// "Absolute" is perhaps not the right term, this normalizes the Uri
+// given http://www.google.com changes to correct http://www.google.com/
+// given http://www.google.com// changes to correct http://www.google.com/
+// given http://www.google.com/home.html returns the same
+CString GetAbsoluteUri(const CString& uri);
+
+// Reverse (big-endian<->little-endian) the shorts that make up
+// Unicode characters in a byte array of Unicode chars
+HRESULT ReverseUnicodeByteOrder(byte* unicode_string, int size_in_bytes);
+
+// given http://google.com/bobby this returns http://google.com/
+// If strip_leading is specified, it will turn
+// http://www.google.com into http://google.com
+#define kStrLeadingWww _T("www.")
+// TODO(omaha): no default parameters
+CString GetUriHostName(const CString& uri, bool strip_leading = false);
+CString GetUriHostNameHostOnly(const CString& uri, bool strip_leading_www);
+
+const char *stristr(const char *string, const char *pattern);
+const WCHAR *stristrW(const WCHAR *string, const WCHAR *pattern);
+const WCHAR *strstrW(const WCHAR *string, const WCHAR *pattern);
+
+// Add len_to_add to len_so_far, assuming that if it exceeds the
+// length of the line, it will word wrap onto the next line.  Returns
+// the total length of all the lines summed together.
+float GetLenWithWordWrap (const float len_so_far,
+  const float len_to_add,
+  const uint32 len_line);
+
+// ----------------------------------------------------------------------
+// QuotedPrintableUnescape()
+//    Copies "src" to "dest", rewriting quoted printable escape sequences
+//    =XX to their ASCII equivalents. src is not null terminated, instead
+//    specify len. I recommend that slen<len_dest, but we honour len_dest
+//    anyway.
+//    RETURNS the length of dest.
+// ----------------------------------------------------------------------
+int QuotedPrintableUnescape(const WCHAR *src, int slen, WCHAR *dest, int len_dest);
+
+// Return the length to use for the output buffer given to the base64 escape
+// routines. Make sure to use the same value for do_padding in both.
+// This function may return incorrect results if given input_len values that
+// are extremely high, which should happen rarely.
+int CalculateBase64EscapedLen(int input_len, bool do_padding);
+// Use this version when calling Base64Escape without a do_padding arg.
+int CalculateBase64EscapedLen(int input_len);
+
+// ----------------------------------------------------------------------
+// Base64Escape()
+// WebSafeBase64Escape()
+//    Encode "src" to "dest" using base64 encoding.
+//    src is not null terminated, instead specify len.
+//    'dest' should have at least CalculateBase64EscapedLen() length.
+//    RETURNS the length of dest.
+//    The WebSafe variation use '-' instead of '+' and '_' instead of '/'
+//    so that we can place the out in the URL or cookies without having
+//    to escape them.  It also has an extra parameter "do_padding",
+//    which when set to false will prevent padding with "=".
+// ----------------------------------------------------------------------
+int Base64Escape(const char *src, int slen, char *dest, int szdest);
+int WebSafeBase64Escape(const char *src, int slen, char *dest,
+                        int szdest, bool do_padding);
+void WebSafeBase64Escape(const CStringA& src, CStringA* dest);
+
+void Base64Escape(const char *src, int szsrc,
+                  CStringA* dest, bool do_padding);
+void WebSafeBase64Escape(const char *src, int szsrc,
+                         CStringA* dest, bool do_padding);
+
+// ----------------------------------------------------------------------
+// Base64Unescape()
+//    Copies "src" to "dest", where src is in base64 and is written to its
+//    ASCII equivalents. src is not null terminated, instead specify len.
+//    I recommend that slen<len_dest, but we honour len_dest anyway.
+//    RETURNS the length of dest.
+//    The WebSafe variation use '-' instead of '+' and '_' instead of '/'.
+// ----------------------------------------------------------------------
+int Base64Unescape(const char *src, int slen, char *dest, int len_dest);
+int WebSafeBase64Unescape(const char *src, int slen, char *dest, int szdest);
+
+#ifdef UNICODE
+#define IsSpace IsSpaceW
+#else
+#define IsSpace IsSpaceA
+#endif
+
+bool IsSpaceW(WCHAR c);
+bool IsSpaceA(char c);
+
+// Remove all leading and trailing whitespace from s.
+// Returns the new length of the string (not including 0-terminator)
+int TrimCString(CString &s);
+int Trim(TCHAR *s);
+
+// Trims all characters in the delimiter string from both ends of the
+// string s
+void TrimString(CString& s, const TCHAR* delimiters);
+
+// Strip the first token from the front of argument s.  A token is a
+// series of consecutive non-blank characters - unless the first
+// character is a double-quote ("), in that case the token is the full
+// quoted string
+CString StripFirstQuotedToken(const CString& s);
+
+// A block of text to separate lines, and back
+void TextToLines(const CString& text, const TCHAR* delimiter, std::vector<CString>* lines);
+// (LinesToText puts a delimiter at the end of the last line too)
+void LinesToText(const std::vector<CString>& lines, const TCHAR* delimiter, CString* text);
+
+// Make a CString lower case
+void MakeLowerCString(CString & s);
+
+// Clean up the string: replace all whitespace with spaces, and
+// replace consecutive spaces with one.
+// Returns the new length of the string (not including 0-terminator)
+int CleanupWhitespaceCString(CString &s);
+int CleanupWhitespace(TCHAR *s);
+
+int HexDigitToInt (WCHAR c);
+bool IsHexDigit (WCHAR c);
+
+// Converts to lower, but does so much faster if the string is ANSI
+TCHAR * String_FastToLower(TCHAR * str);
+
+// Replacement for the CRT toupper(c)
+int String_ToUpper(int c);
+
+// Replacement for the CRT toupper(c)
+char String_ToUpperA(char c);
+
+// Converts str to lowercase in place.
+void String_ToLower(TCHAR* str);
+
+// Converts str to uppercase in place.
+void String_ToUpper(TCHAR* str);
+
+bool String_IsUpper(TCHAR c);
+
+// String comparison based on length
+// Replacement for the CRT strncmp(i)
+int String_StrNCmp(const TCHAR * str1, const TCHAR * str2, uint32 len, bool ignore_case);
+
+// Replacement for strncpy() - except ALWAYS ends string with null
+TCHAR* String_StrNCpy(TCHAR* destination, const TCHAR* source, uint32 len);
+
+// check if str starts with start_str
+bool String_StartsWith(const TCHAR *str, const TCHAR *start_str, bool ignore_case);
+
+// check if str starts with start_str, for char *
+bool String_StartsWithA(const char *str, const char *start_str, bool ignore_case);
+
+// check if str ends with end_str
+bool String_EndsWith(const TCHAR *str, const TCHAR *end_str, bool ignore_case);
+
+// If the input string str doesn't already end with the string end_str,
+// make it end with the string end_str.
+CString String_MakeEndWith(const TCHAR *str, const TCHAR* end_str, bool ignore_case);
+
+// converts an int to a string
+CString String_Int64ToString(int64 value, int radix);
+
+// converts an uint64 to a string
+CString String_Uint64ToString(uint64 value, int radix);
+
+// Convert numeric types to CString
+CString sizet_to_str(const size_t & i);
+CString itostr(const int i);
+CString itostr(const uint32 i);
+
+// converts a large number to an approximate value, like "1.2G" or "900M"
+// base_ten = true if based on powers of 10 (like disk space) otherwise based
+// on powers of two.  power = 0 for *10^0, 1 for *10^3 or 2^10, 2 for *10^6
+// or 2^20, and 3 for *10^9 or 2^30, in other words: no units, K, M, or G.
+CString String_LargeIntToApproximateString(uint64 value, bool base_ten, int* power);
+
+// converts a string to an  int
+// Does not check for overflow
+int32 String_StringToInt(const TCHAR * str);
+
+int64 String_StringToInt64(const TCHAR * str);
+
+// converts an double to a string
+// specifies the number of digits after the decimal point
+// TODO(omaha): Make this work for negative values
+CString String_DoubleToString(double value, int point_digits);
+
+// convert string to double
+double String_StringToDouble (const TCHAR *s);
+
+// Converts a character to a digit
+// if the character is not a digit return -1
+int32 String_CharToDigit(const TCHAR c);
+
+// returns true if ASCII digit
+bool String_IsDigit(const TCHAR c);
+
+// Converts the digit to a character.
+TCHAR String_DigitToChar(unsigned int n);
+
+// Returns true if an identifier character: letter, digit, or "_"
+bool String_IsIdentifierChar(const TCHAR c);
+
+// Returns true if the string has letters in it.
+// This is used by the keyword extractor to downweight numbers,
+// IDs (sequences of numbers like social security numbers), etc.
+bool String_HasAlphabetLetters (const TCHAR *str);
+
+// Return the index of the first occurrence of s2 in s1, or -1 if none.
+int String_FindString(const TCHAR *s1, const TCHAR *s2);
+int String_FindString(const TCHAR *s1, const TCHAR *s2, int start_pos);
+
+// Return the index of the first occurrence of c in s1, or -1 if none.
+int String_FindChar(const TCHAR *str, const TCHAR c);
+// start from index start_pos
+int String_FindChar(const TCHAR *str, const TCHAR c, int start_pos);
+
+// Return the index of the first occurrence of c in string, or -1 if none.
+int String_ReverseFindChar(const TCHAR * str, TCHAR c);
+
+bool String_Contains(const TCHAR *s1, const TCHAR *s2);
+
+// Replace old_char with new_char in str.
+void String_ReplaceChar(TCHAR *str, TCHAR old_char, TCHAR new_char);
+void String_ReplaceChar(CString & str, TCHAR old_char, TCHAR new_char);
+
+// Append the given character to the string if it doesn't already end with it.
+// There must be room in the string to append the character if necessary.
+void String_EndWithChar(TCHAR *str, TCHAR c);
+
+// A special version of the replace function which takes advantage of CString properties
+// to make it much faster when the string grows
+
+// NOTE: it CANNOT match more than kMaxReplaceMatches instances within the string
+// do not use this function if that is a possibility
+
+// The maximum number of replacements to perform. Essentially infinite
+#define kRepMax kUint32Max
+int ReplaceCString (CString & src, const TCHAR *from, unsigned int from_len,
+                                   const TCHAR *to, unsigned int to_len,
+                                   unsigned int max_matches);
+
+// replace from with to in src
+// on memory allocation error, returns the original string
+int ReplaceString (TCHAR *src, const TCHAR *from, const TCHAR *to, TCHAR **out, int *out_len);
+
+// replace from with to in src
+// will replace in place if length(to) <= length(from) and return *out == src
+// WILL CREATE NEW OUTPUT BUFFER OTHERWISE and set created_new_string to true
+// on memory allocation error, returns the original string
+int ReplaceStringMaybeInPlace (TCHAR *src, const TCHAR *from, const TCHAR *to, TCHAR **out, int *out_len, bool *created_new_string);
+
+// you really want to use the straight TCHAR version above. you know it
+// on memory allocation error, returns the original string
+int ReplaceCString (CString & src, const TCHAR *from, const TCHAR *to);
+
+long __cdecl Wcstol (const wchar_t *nptr, wchar_t **endptr, int ibase);
+unsigned long __cdecl Wcstoul (const wchar_t *nptr, wchar_t **endptr, int ibase);
+
+// Functions on arrays of strings
+
+// Returns true iff s is in the array strings (case-insensitive compare)
+bool String_MemberOf(const TCHAR* const* strings, const TCHAR* s);
+// Returns index of s in the array of strings (or -1 for missing) (case-insensitive compare)
+int String_IndexOf(const TCHAR* const* strings, const TCHAR* s);
+
+// Serializes a time64 to a string, and then loads it out again, this string it not for human consumption
+time64 StringToTime(const CString & time);
+CString TimeToString(const time64 & time);
+
+// looks for string A followed by any number of spaces/tabs followed by string b
+// returns starting position of a if found, NULL if not
+// case insensitive
+const TCHAR *FindStringASpaceStringB (const TCHAR *s, const TCHAR *a, const TCHAR *b);
+
+bool IsAlphaA (const char c);
+bool IsDigitA (const char c);
+
+// TODO(omaha): deprecate since we have secure CRT now.
+// dest_buffer_len includes the NULL
+// always NULL terminates
+// dest must be a valid string with length < dest_buffer_len
+void SafeStrCat (TCHAR *dest, const TCHAR *src, int dest_buffer_len);
+
+const TCHAR *ExtractNextDouble (const TCHAR *s, double *f);
+
+TCHAR *String_PathFindExtension(const TCHAR *path);
+
+inline TCHAR Char_ToLower(TCHAR c) {
+// C4302: truncation from 'type 1' to 'type 2'
+#pragma  warning(disable : 4302)
+  return reinterpret_cast<TCHAR>(::CharLower(reinterpret_cast<TCHAR*>(c)));
+#pragma warning(default : 4302)
+}
+
+// @returns the lowercase character (type is int to be consistent with the CRT)
+int String_ToLowerChar(int c);
+
+// Replacement for the CRT tolower(c)
+char String_ToLowerCharAnsi(char c);
+
+bool String_PathRemoveFileSpec(TCHAR *path);
+
+// Escapes and unescapes strings (shlwapi-based implementation).
+// The indended usage for these APIs is escaping strings to make up
+// URLs, for example building query strings.
+//
+// Pass false to the flag segment_only to escape the url. This will not
+// cause the conversion of the # (%23), ? (%3F), and / (%2F) characters.
+HRESULT StringEscape(const CString& str_in,
+                     bool segment_only,
+                     CString* str_out);
+
+HRESULT StringUnescape(const CString& str_in, CString* str_out);
+
+// Converts a string to an int, performs all the necessary
+// checks to ensure that the string is correct.
+// Tests for overflow and non-int strings.
+bool String_StringToDecimalIntChecked(const TCHAR* str, int* value);
+
+// Converts CLSID to a string.
+bool CLSIDToCString(const GUID& guid, CString* str);
+
+// Converts a string to a bool.
+HRESULT String_StringToBool(const TCHAR* str, bool* value);
+
+// Convert boolean to its string representation.
+HRESULT String_BoolToString(bool value, CString* string);
+
+// Converts a string to a Tristate enum.
+bool String_StringToTristate(const TCHAR* str, Tristate* value);
+
+// Extracts the name and value from a string that contains a name/value pair.
+bool ParseNameValuePair(const CString& token, TCHAR separator,
+                        CString* name, CString* value);
+
+// Splits a command line buffer into two parts in place:
+// first argument (which could be path to executable) and remaining arguments.
+// Note that the same pointer can be used for both command_line and
+// either of the remaining parameters.
+bool SplitCommandLineInPlace(TCHAR *command_line,
+                             TCHAR **first_argument,
+                             TCHAR **remaining_arguments);
+
+// Returns true if the unicode string only contains ascii values.
+bool ContainsOnlyAsciiChars(const CString& str);
+// Converts a buffer of bytes to a hex string.
+CString BytesToHex(const uint8* bytes, size_t num_bytes);
+
+// Converts a vector of bytes to a hex string.
+CString BytesToHex(const std::vector<uint8>& bytes);
+
+void JoinStrings(const std::vector<CString>& components,
+                 const TCHAR* delim,
+                 CString* result);
+
+void JoinStringsInArray(const TCHAR* components[],
+                        int num_components,
+                        const TCHAR* delim,
+                        CString* result);
+
+// Formats the specified message ID.
+// It is similar to CStringT::FormatMessage() but it returns an empty string
+// instead of throwing when the message ID cannot be loaded.
+CString FormatResourceMessage(uint32 resource_id, ...);
+
+// Formats an error code as an 8-digit HRESULT-style hex number or an unsigned
+// integer depending on whether it matches the HRESULT failure format.
+CString FormatErrorCode(DWORD error_code);
+
+// Converts the unicode string into a utf8 encoded, urlencoded string.
+// The resulting ascii string is returned in a wide CString.
+HRESULT WideStringToUtf8UrlEncodedString(const CString& str, CString* out);
+
+// Converts a string that is in the utf8 representation and is urlencoded
+// into a unicode string.
+HRESULT Utf8UrlEncodedStringToWideString(const CString& str, CString* out);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_STRING_H__
diff --git a/common/string_unittest.cc b/common/string_unittest.cc
index 6574973..01d838b 100644
--- a/common/string_unittest.cc
+++ b/common/string_unittest.cc
@@ -1,1712 +1,1712 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/localization.h"

-#include "omaha/common/string.h"

-#include "omaha/common/time.h"

-#include "omaha/common/timer.h"

-#include "omaha/common/tr_rand.h"

-#include "omaha/goopdate/resources/goopdateres/goopdate.grh"

-#include "omaha/testing/resource.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(StringTest, IntToString) {

-  ASSERT_STREQ(String_Int64ToString(0, 10), L"0");

-  ASSERT_STREQ(String_Int64ToString(1, 10), L"1");

-  ASSERT_STREQ(String_Int64ToString(-1, 10), L"-1");

-  ASSERT_STREQ(String_Int64ToString(123456789, 10), L"123456789");

-  ASSERT_STREQ(String_Int64ToString(-123456789, 10), L"-123456789");

-  ASSERT_STREQ(String_Int64ToString(1234567890987654321, 10),

-               L"1234567890987654321");

-  ASSERT_STREQ(String_Int64ToString(-1234567890987654321, 10),

-               L"-1234567890987654321");

-  ASSERT_STREQ(String_Int64ToString(0xabcdef, 16), L"abcdef");

-  ASSERT_STREQ(String_Int64ToString(0x101fff, 16), L"101fff");

-  ASSERT_STREQ(String_Int64ToString(0x999999, 16), L"999999");

-  ASSERT_STREQ(String_Int64ToString(0x0, 16), L"0");

-

-  ASSERT_STREQ(String_Int64ToString(01234, 8), L"1234");

-  ASSERT_STREQ(String_Int64ToString(0, 8), L"0");

-  ASSERT_STREQ(String_Int64ToString(0777, 8), L"777");

-  ASSERT_STREQ(String_Int64ToString(0123456, 8), L"123456");

-

-  ASSERT_STREQ(String_Int64ToString(0, 2), L"0");

-  ASSERT_STREQ(String_Int64ToString(0xf, 2), L"1111");

-  ASSERT_STREQ(String_Int64ToString(0x5ad1, 2), L"101101011010001");

-  ASSERT_STREQ(String_Int64ToString(-1, 2), L"-1");

-}

-

-TEST(StringTest, UintToString) {

-  ASSERT_STREQ(String_Uint64ToString(0, 10), L"0");

-  ASSERT_STREQ(String_Uint64ToString(1, 10), L"1");

-  ASSERT_STREQ(String_Uint64ToString(123456789, 10), L"123456789");

-  ASSERT_STREQ(String_Uint64ToString(1234567890987654321, 10),

-               L"1234567890987654321");

-  ASSERT_STREQ(String_Uint64ToString(18446744073709551615, 10),

-               L"18446744073709551615");

-

-  ASSERT_STREQ(String_Uint64ToString(0xabcdef, 16), L"abcdef");

-  ASSERT_STREQ(String_Uint64ToString(0x101fff, 16), L"101fff");

-  ASSERT_STREQ(String_Uint64ToString(0x999999, 16), L"999999");

-  ASSERT_STREQ(String_Uint64ToString(0x0, 16), L"0");

-  ASSERT_STREQ(String_Uint64ToString(0xffffffffffffffff, 16), L"ffffffffffffffff");

-

-  ASSERT_STREQ(String_Uint64ToString(01234, 8), L"1234");

-  ASSERT_STREQ(String_Uint64ToString(0, 8), L"0");

-  ASSERT_STREQ(String_Uint64ToString(0777, 8), L"777");

-  ASSERT_STREQ(String_Uint64ToString(0123456, 8), L"123456");

-

-  ASSERT_STREQ(String_Uint64ToString(0, 2), L"0");

-  ASSERT_STREQ(String_Uint64ToString(0xf, 2), L"1111");

-  ASSERT_STREQ(String_Uint64ToString(0x5ad1, 2), L"101101011010001");

-}

-

-TEST(StringTest, DoubleToString) {

-  ASSERT_STREQ(String_DoubleToString(1.234, 1), L"1.2");

-  ASSERT_STREQ(String_DoubleToString(0.0, 0), L"0");

-  ASSERT_STREQ(String_DoubleToString(0.0, 2), L"0.00");

-  ASSERT_STREQ(String_DoubleToString(199.234, 2), L"199.23");

-  ASSERT_STREQ(String_DoubleToString(-199.234, 2), L"-199.23");

-  ASSERT_STREQ(String_DoubleToString(199.23490776, 5), L"199.23490");

-  ASSERT_STREQ(String_DoubleToString(-1.0001, 1), L"-1.0");

-  ASSERT_STREQ(String_DoubleToString(123456789.987654321, 3), L"123456789.987");

-}

-

-TEST(StringTest, StrNCpy) {

-  TCHAR * str1 = L"test str 1234";

-  TCHAR * str2 = L"test str 12";

-  TCHAR * str3 = L"Test StR 1234";

-

-  // check case sensitive

-  ASSERT_TRUE(0 == String_StrNCmp(str1, str2, 10, false));

-  ASSERT_TRUE(0 == String_StrNCmp(str1, str2, 11, false));

-

-  // check case in-sensitive

-  ASSERT_TRUE(0 == String_StrNCmp(str2, str3, 10, true));

-  ASSERT_TRUE(0 == String_StrNCmp(str2, str3, 11, true));

-}

-

-TEST(StringTest, StartsWith) {

-  ASSERT_TRUE(String_StartsWith(L"", L"", false));

-  ASSERT_TRUE(String_StartsWith(L"Joe", L"", false));

-  ASSERT_TRUE(String_StartsWith(L"Joe", L"J", false));

-  ASSERT_TRUE(String_StartsWith(L"Joe\\", L"J", false));

-  ASSERT_TRUE(String_StartsWith(L"Joe", L"Joe", false));

-  ASSERT_TRUE(String_StartsWith(L"The quick brown fox", L"The quic", false));

-  ASSERT_FALSE(String_StartsWith(L"", L"J", false));

-  ASSERT_FALSE(String_StartsWith(L"Joe", L"Joe2", false));

-  ASSERT_FALSE(String_StartsWith(L"The quick brown fox", L"The quiC", false));

-

-  ASSERT_TRUE(String_StartsWith(L"", L"", true));

-  ASSERT_TRUE(String_StartsWith(L"Joe", L"j", true));

-  ASSERT_TRUE(String_StartsWith(L"The quick brown fox", L"The quiC", true));

-}

-

-TEST(StringTest, StartsWithA) {

-  ASSERT_TRUE(String_StartsWithA("", "", false));

-  ASSERT_TRUE(String_StartsWithA("Joe", "", false));

-  ASSERT_TRUE(String_StartsWithA("Joe", "J", false));

-  ASSERT_TRUE(String_StartsWithA("Joe\\", "J", false));

-  ASSERT_TRUE(String_StartsWithA("Joe", "Joe", false));

-  ASSERT_TRUE(String_StartsWithA("The quick brown fox", "The quic", false));

-  ASSERT_FALSE(String_StartsWithA("", "J", false));

-  ASSERT_FALSE(String_StartsWithA("Joe", "Joe2", false));

-  ASSERT_FALSE(String_StartsWithA("The quick brown fox", "The quiC", false));

-

-  ASSERT_TRUE(String_StartsWithA("", "", true));

-  ASSERT_TRUE(String_StartsWithA("Joe", "j", true));

-  ASSERT_TRUE(String_StartsWithA("The quick brown fox", "The quiC", true));

-}

-

-TEST(StringTest, EndsWith) {

-  // Case sensitive

-

-  // Empty suffix

-  ASSERT_TRUE(String_EndsWith(L"", L"", false));

-  ASSERT_TRUE(String_EndsWith(L"Joe", L"", false));

-

-  // Partial suffix

-  ASSERT_TRUE(String_EndsWith(L"Joe", L"e", false));

-  ASSERT_TRUE(String_EndsWith(L"Joe\\", L"\\", false));

-  ASSERT_TRUE(String_EndsWith(L"The quick brown fox", L"n fox", false));

-

-  // Suffix == String

-  ASSERT_TRUE(String_EndsWith(L"Joe", L"Joe", false));

-  ASSERT_TRUE(String_EndsWith(L"The quick brown fox",

-                              L"The quick brown fox",

-                              false));

-

-  // Fail cases

-  ASSERT_FALSE(String_EndsWith(L"", L"J", false));

-  ASSERT_FALSE(String_EndsWith(L"Joe", L"Joe2", false));

-  ASSERT_FALSE(String_EndsWith(L"Joe", L"2Joe", false));

-  ASSERT_FALSE(String_EndsWith(L"The quick brown fox", L"n foX", false));

-

-  // Check case insensitive

-

-  // Empty suffix

-  ASSERT_TRUE(String_EndsWith(L"", L"", true));

-  ASSERT_TRUE(String_EndsWith(L"Joe", L"", true));

-

-  // Partial suffix

-  ASSERT_TRUE(String_EndsWith(L"Joe", L"E", true));

-  ASSERT_TRUE(String_EndsWith(L"The quick brown fox", L"n FOX", true));

-

-  // Suffix == String

-  ASSERT_TRUE(String_EndsWith(L"Joe", L"JOE", true));

-  ASSERT_TRUE(String_EndsWith(L"The quick brown fox",

-                              L"The quick brown FOX",

-                              true));

-

-  // Fail cases

-  ASSERT_FALSE(String_EndsWith(L"The quick brown fox", L"s", true));

-  ASSERT_FALSE(String_EndsWith(L"The quick brown fox", L"Xs", true));

-  ASSERT_FALSE(String_EndsWith(L"The quick brown fox", L"the brown foX", true));

-}

-

-TEST(StringTest, Unencode) {

-  // Normal, correct usage.

-  // char 0x25 is '%'

-  ASSERT_STREQ(Unencode(L"?q=moon+doggy_%25%5E%26"), L"?q=moon doggy_%^&");

-  ASSERT_STREQ(Unencode(L"%54%68%69%73+%69%73%09%61%20%74%65%73%74%0A"),

-               L"This is\ta test\n");

-  ASSERT_STREQ(Unencode(L"This+is%09a+test%0a"), L"This is\ta test\n");

-

-  // NULL char.

-  ASSERT_STREQ(Unencode(L"Terminated%00before+this"), L"Terminated");

-  ASSERT_STREQ(Unencode(L"invalid+%a%25"), L"invalid %a%");

-  ASSERT_STREQ(Unencode(L"invalid+%25%41%37"), L"invalid %A7");

-  ASSERT_STREQ(Unencode(L"not a symbol %RA"), L"not a symbol %RA");

-  ASSERT_STREQ(Unencode(L"%ag"), L"%ag");

-  ASSERT_STREQ(Unencode(L"dontdecode%dont"), L"dontdecode%dont");

-  ASSERT_STREQ(Unencode(L""), L"");

-  ASSERT_STREQ(Unencode(L"%1"), L"%1");

-  ASSERT_STREQ(Unencode(L"\x100"), L"\x100");

-  ASSERT_STREQ(Unencode(L"this is%20a%20wide%20char%20\x345"),

-               L"this is a wide char \x345");

-  ASSERT_STREQ(Unencode(L"a utf8 string %E7%BC%9c %E4%B8%8a = 2"),

-               L"a utf8 string \x7f1c \x4e0a = 2");

-}

-

-#if 0

-static const struct {

-  const char *ansi;

-  const TCHAR *wide;

-  UINT cp;

-} kAnsi2WideTests[] = {

-  { "\xc8\xae\xc1\xbe", L"\x72ac\x8f86", CP_GB2312},

-  { "\xa5\x69\xb1\x4e\xc2\xb2\xc5\xe9",

-    L"\x53ef\x5c07\x7c21\x9ad4", CP_BIG5},

-  { "\xE7\xBC\x96\xE4\xB8\x8B", L"\x7f16\x4e0b", CP_UTF8},

-  { "ascii", L"ascii", CP_GB2312},

-  { "\x3C\x20\xE7\xBC\x96", L"\x003c\x0020\x00E7\x00BC\x0096", 0 },

-};

-

-bool TestAnsiToWideString() {

-  for (size_t i = 0; i < arraysize(kAnsi2WideTests); ++i) {

-    CStringW out;

-    if (kAnsi2WideTests[i].cp == 0) {

-      out = AnsiToWideString(kAnsi2WideTests[i].ansi,

-                             strlen(kAnsi2WideTests[i].ansi));

-    } else {

-      AnsiToWideString(kAnsi2WideTests[i].ansi,

-                       strlen(kAnsi2WideTests[i].ansi),

-                       kAnsi2WideTests[i].cp, &out);

-    }

-    CHK(out == kAnsi2WideTests[i].wide);

-  }

-  return true;

-}

-#endif

-

-TEST(StringTest, Show) {

-  ASSERT_STREQ(Show(0), _T("0"));

-  ASSERT_STREQ(Show(1), _T("1"));

-  ASSERT_STREQ(Show(-1), _T("-1"));

-}

-

-

-// Test international strings.

-TEST(StringTest, International) {

-  CString tabs_by_lang[] = {

-      _T("Web    Prente    Groepe    Gids    "),                    // Afrikaans

-      _T("Web    Fotografitë    Grupet    Drejtoriumi    "),        // Albanian

-      // Amharic is missing, that doesn't show in normal windows fonts

-      _T("ويب    صور    مجموعات    الدليل     "),                    // Arabic

-      _T("Web   Şəkillər   Qruplar   Qovluq   "),                   // Azerbaijani

-      _T("Web   Irudiak   Taldeak   Direktorioa   "),               // Basque

-      _T("Ўэб    Малюнкі    Групы    Каталёг    "),                 // Belarusian

-      _T("Antorjal    Chitraboli    Gosthi    Bishoy-Talika    "),  // Bengali

-      _T("MakarJal    Chhaya    Jerow    Nirdeshika    "),          // Bihari

-      _T("Veb   Imeges   Gruoops   Durectury "),                    // Bork

-      _T("Internet    Slike    Grupe    Katalog    "),              // Bosnian

-      _T("Gwiad    Skeudennoù    Strolladoù    Roll    "),          // Breton

-      _T("Мрежата    Изображения    Групи    Директория    "),      // Bulgarian

-      _T("Web    Imatges    Grups    Directori    "),               // Catalan

-      _T("所有网站    图像    网上论坛    网页目录    "),                            // Chinese Simplified

-      _T("所有網頁    圖片    網上論壇    網頁目錄     "),                            // Chinese Traditional

-      _T("Web    Slike    Grupe    Imenik    "),                    // Croatian

-      _T("Web    Obrázky    Skupiny    Adresář    "),               // Czech

-      _T("Nettet    Billeder    Grupper    Katalog    "),           // Danish

-      _T("Het Internet    Afbeeldingen    Discussiegroepen    Gids    "),  // Dutch

-      _T("Web    Images    Gwoups    Diwectowy    "),               // Elmer

-      _T("Web    Images    Groups    News    Froogle    more »"),   // English

-      _T("TTT    Bildoj    Grupoj    Katalogo     "),               // Esperanto

-      _T("Veeb    Pildid    Grupid    Kataloog    "),               // Estonian

-      _T("Netið    Myndir    Bólkar    Øki    "),                   // Faroese

-      _T("Web    Mga Larawan    Mga Grupo    Direktoryo    "),      // Filipino

-      _T("Web    Kuvat    Keskusteluryhmät    Hakemisto    "),      // Finnish

-      _T("Web    Images    Groupes    Annuaire    Actualités    "),  // French

-      _T("Web   Printsjes   Diskusjegroepen   Directory   "),       // Frisian

-      _T("Web    Imaxes    Grupos    Directorio    "),              // Galician

-      _T("ინტერნეტი   სურათები   ჯგუფები   კატალოგი   "),                      // Georgian

-      _T("Web    Bilder    Groups    Verzeichnis    News    "),     // German

-      _T("Ιστός    Eικόνες    Ομάδες    Κατάλογος    "),            // Greek

-      _T("Ñanduti   Ta'anga   Atypy   Sãmbyhypy "),                 // Guarani

-      _T("jalu    Chhabi    Sangathan    Shabdakosh    "),          // Gujarati

-      _T("n0rM4L s33rCh    1|\\/|4935    6r00pZ    d1r3c70rY    "),  // Hacker

-      _T("אתרים ברשת    תמונות    קבוצות דיון    מדריך האתרים     "),  // Hebrew

-      _T("वेब    छवियाँ    समूह    निर्देशिका    "),                             // Hindi

-      _T("Web    Képek    Csoportok    Címtár    "),                // Hungarian

-      _T("Vefur    Myndir    Hópar    Flokkar    "),                // Icelandic

-      _T("Web    Gambar    Grup    Direktori    "),                 // Indonesian

-      _T("Web    Imagines    Gruppos    Catalogo  "),               // Interlingua

-      _T("An Gréasán    Íomhánna    Grúpaí    Eolaire    "),        // Irish

-      _T("Web    Immagini    Gruppi    Directory    News Novità!    "),  // Italian

-      _T("ウェブ    イメージ    グループ    ディレクトリ    "),                        // Japanese

-      _T("Web    Gambar - gambar    Paguyuban    Bagian    "),      // Javanese

-      _T("antharajAla    chitragaLu    gumpugaLu    Huduku vibhaagagaLu    "),  // Kannada

-      _T("Daqmey pat    naghmey beQ    ghommey    mem    "),        // Klingon

-      _T("웹 문서    이미지    뉴스그룹    디렉토리    "),                            // Klingon

-      _T("Желе   Суроттор   Группалар   Тизме   "),                 // Kyrgyz

-      _T("Tela   Imagines   Circuli   Index "),                     // Latin

-      _T("Internets    Attēli    Vēstkopas    Katalogs"),           // Latvian

-      _T("Internetas    Vaizdai    Grupės    Katalogas    "),       // Lithuanian

-      _T("Мрежа    Слики    Групи    Директориум    "),             // Macedonian

-      _T("Jaringan    Imej    Kumpulan    Direktori    "),          // Malay

-      _T("വെബ്    ചിത്രങ്ങള്    സംഘങ്ങള്    ഡയറക്ടറി    "),                     // Malayalam

-      _T("Web    Stampi    Gruppi    Direttorju    "),              // Maltese

-      _T("वेबशोध    चित्रशोध    ग्रूप्स    डिरेक्टरी    "),                          // Marathi

-      _T("वेब    तस्वीर    समूह    डाइरेक्टरी    "),                            // Nepali

-      _T("Nett    Bilder    Grupper    Katalog    "),               // Norwegian

-      _T("Veven    Bilete    Grupper    Katalog    "),              // Norwegian (Nynorsk)

-      _T("Ret    Imatges    Grops    Directori    "),               // Occitan

-      _T("web   chitra   goSThi   prasanga tAlikA "),               // Oriya

-      _T("وب    تصويرها    گروهها    فهرست     "),                  // Persian

-      _T("ebway    imagesyay    oupsgray    Irectoryday    "),      // P. Latin

-      _T("WWW    Grafika    Grupy dyskusyjne    Katalog   "),       // Polish

-      _T("Web    Imagens    Grupos    Diretório    "),              // Potruguese (Brazil)

-      _T("Web    Imagens    Grupos    Directório  "),               // Potruguese (Portugal)

-      _T("Web/Zaal    Tasveraan    Gutt    Directory    "),         // Punjabi

-      _T("Web    Imagini    Grupuri    Director    "),              // Romanian

-      _T("Веб    Картинки    Группы    Каталог  "),                 // Russian

-      _T("Lìon    Dealbhan    Cuantail    Eòlaire    "),            // Scots Gaelic

-      _T("Интернет    Слике    Групе    Каталог    "),              // Serbian

-      _T("Internet    Slike    Grupe    Spisak    "),               // Serbo-Croatian

-      _T("Web   Ponahalo   Dihlopha   Tshupetso "),                 // Sesotho

-      _T("WEB    Roopa    Kandayam    Namawaliya    "),             // Sinhalese

-      _T("Web    Obrázky    Skupiny    Katalóg    "),               // Slovak

-      _T("Internet    Slike    Skupine    Imenik    "),             // Slovenian

-      _T("La Web    Imágenes    Grupos    Directorio    News ¡Nuevo!    "),  // Spanish

-      _T("Web   Gambar   Grup   Direktori "),                       // Sudanese

-      _T("Mtandao    Picha    Vikundi    Orodha    "),              // Swahili

-      _T("Nätet    Bilder    Grupper    Kategori    "),             // Swedish

-      _T("வலை    படங்கள்    குழுக்கள்    விபரக்கோவை    "),          // Tamil

-      _T("వెబ్    చిత్రాలు    సమూహములు    darshini    "),                        // Telugu

-      _T("เว็บ    รูปภาพ    กลุ่มข่าว    สารบบเว็บ    "),                            // Thai

-      // Tigrinya is missing, that doesn't show in normal windows fonts

-      _T("Web    Grafikler    Gruplar    Dizin    "),               // Turkish

-      _T("Web   Suratlar   Toparlar   Düzine "),                    // Turkmen

-      _T("tintan   Nfonyin   Akuokuo   Krataa nhwemu "),            // Twi

-      _T("Веб    Зображення    Групи    Каталог    "),              // Ukrainian

-      _T("ويب    تصاوير    گروہ    فہرست         ")                           // Urdu

-      _T("To'r    Tasvirlar    Gruppalar    Papka    "),            // Uzbek

-      _T("Internet    Hình Ảnh    Nhóm    Thư Mục    "),            // Vietnamese

-      _T("Y We    Lluniau    Grwpiau    Cyfeiriadur    "),          // Welsh

-      _T("Web   Imifanekiso   Amaqela   Isilawuli "),               // Xhosa

-      _T("װעב    בילדער    גרופּעס    פּאַפּקע     "),                  // Yiddish

-      _T("I-web   Izithombe   Amaqembu   Uhlu lwamafayela   "),     // Zulu

-  };

-

-  int i = 0;

-  for(i = 0; i < arraysize(tabs_by_lang); ++i) {

-    // Get the cannonical lower version with ::CharLower

-    CString true_lower(tabs_by_lang[i]);

-    ::CharLower(true_lower.GetBuffer());

-    true_lower.ReleaseBuffer();

-

-    // Get the lower version with String_ToLower,

-    CString low_temp(tabs_by_lang[i]);

-    String_ToLower(low_temp.GetBuffer());

-    low_temp.ReleaseBuffer();

-

-    // make sure they match

-    ASSERT_STREQ(low_temp, true_lower);

-

-    // Now make sure they match letter by letter

-    for(int j = 0; j < tabs_by_lang[i].GetLength(); ++j) {

-      TCHAR cur_char = tabs_by_lang[i].GetAt(j);

-

-      TCHAR low1 = static_cast<TCHAR>(String_ToLowerChar(cur_char));

-

-      ASSERT_EQ(low1, true_lower.GetAt(j));

-      ASSERT_EQ(Char_ToLower(cur_char), true_lower.GetAt(j));

-

-      // Check the Ansi version if applicable

-      if (cur_char < 128)

-        ASSERT_EQ(String_ToLowerChar(static_cast<char>(cur_char)),

-                  true_lower.GetAt(j));

-    }

-

-    // Test out the CString conversion

-    CString temp(tabs_by_lang[i]);

-    MakeLowerCString(temp);

-    ASSERT_STREQ(temp, true_lower);

-

-    // Test out the fast version

-    temp = tabs_by_lang[i];

-    String_FastToLower(temp.GetBuffer());

-    temp.ReleaseBuffer();

-

-    ASSERT_STREQ(temp, true_lower);

-

-    // Make sure that the normal CString::Trim works the same as our fast one

-    CString trim_normal(tabs_by_lang[i]);

-    trim_normal.Trim();

-

-    CString trim_fast(tabs_by_lang[i]);

-    TrimCString(trim_fast);

-

-    ASSERT_STREQ(trim_normal, trim_fast);

-  }

-}

-

-void TestReplaceString (TCHAR *src, TCHAR *from, TCHAR *to, TCHAR *expected) {

-  ASSERT_TRUE(expected);

-  ASSERT_TRUE(to);

-  ASSERT_TRUE(from);

-  ASSERT_TRUE(src);

-

-  size_t new_src_size = _tcslen(src) + 1;

-  TCHAR* new_src = new TCHAR[new_src_size];

-

-  _tcscpy_s(new_src, new_src_size, src);

-

-  Timer tchar (false);

-  Timer tchar2 (false);

-  Timer cstring (false);

-  Timer orig_cstring (false);

-

-  // int iterations = 10000;

-  int iterations = 10;

-

-  int out_len;

-  TCHAR *out;

-

-  for (int i = 0; i < iterations; i++) {

-      _tcscpy_s(new_src, new_src_size, src);

-      bool created_new_string = false;

-

-      tchar.Start();

-      ReplaceString (new_src, from, to, &out, &out_len);

-      tchar.Stop();

-

-      ASSERT_STREQ(out, expected);

-      delete [] out;

-  }

-

-  for (int i = 0; i < iterations; i++) {

-      _tcscpy_s(new_src, new_src_size, src);

-      bool created_new_string = false;

-

-      tchar2.Start();

-      ReplaceStringMaybeInPlace (new_src, from, to, &out,

-                                 &out_len, &created_new_string);

-      tchar2.Stop();

-

-      ASSERT_STREQ(out, expected);

-      if (out != new_src) { delete [] out; }

-  }

-

-  for (int i = 0; i < iterations; i++) {

-      CString src_string(src);

-

-      orig_cstring.Start();

-      src_string.Replace (from, to);

-      orig_cstring.Stop();

-

-      ASSERT_STREQ(src_string, CString(expected));

-  }

-

-  for (int i = 0; i < iterations; i++) {

-      CString src_string(src);

-

-      cstring.Start();

-      ReplaceCString (src_string, from, to);

-      cstring.Stop();

-

-      ASSERT_STREQ(src_string, CString(expected));

-  }

-

-  delete [] new_src;

-}

-

-TEST(StringTest, ReplaceCString) {

-  CString t;

-  t = _T("a a a b ");

-  ReplaceCString(t, _T("a"), 1, _T("d"), 1, 5);

-  ASSERT_STREQ(_T("d d d b "), t);

-

-  t = _T("a a a b ");

-  ReplaceCString(t, _T("b"), 1, _T("d"), 1, 5);

-  ASSERT_STREQ(_T("a a a d "), t);

-

-  t = _T("a a a b ");

-  ReplaceCString(t, _T("a"), 1, _T("d"), 1, 1);

-  ASSERT_STREQ(_T("d a a b "), t);

-

-  t = _T("a a a b ");

-  ReplaceCString(t, _T("a"), 1, _T("dd"), 2, 5);

-  ASSERT_STREQ(_T("dd dd dd b "), t);

-

-  ReplaceCString(t, _T("dd"), 2, _T("dddd"), 4, 5);

-  ASSERT_STREQ(_T("dddd dddd dddd b "), t);

-

-  ReplaceCString(t, _T("dd"), 2, _T("dddd"), 4, 5);

-  ASSERT_STREQ(_T("dddddddd dddddddd dddddd b "), t);

-

-  ReplaceCString(t, _T("dddddddd"), 8, _T("dddd"), 4, 2);

-  ASSERT_STREQ(_T("dddd dddd dddddd b "), t);

-

-  ReplaceCString(t, _T("d"), 1, _T("a"), 1, 2);

-  ASSERT_STREQ(_T("aadd dddd dddddd b "), t);

-

-  ReplaceCString(t, _T("d d"), 3, _T("c"), 1, 2);

-  ASSERT_STREQ(_T("aadcddcddddd b "), t);

-

-  ReplaceCString(t, _T("c"), 1, _T("1234567890"), 10, 2);

-  ASSERT_STREQ(_T("aad1234567890dd1234567890ddddd b "), t);

-

-  ReplaceCString(t, _T("1"), 1, _T("1234567890"), 10, 2);

-  ASSERT_STREQ(_T("aad1234567890234567890dd1234567890234567890ddddd b "), t);

-

-  ReplaceCString(t, _T("1234567890"), 10, _T(""), 0, 2);

-  ASSERT_STREQ(_T("aad234567890dd234567890ddddd b "), t);

-

-  t = _T("a aa aa b ");

-  ReplaceCString(t, _T("aa"), 2, _T("b"), 1, 5);

-  ASSERT_STREQ(_T("a b b b "), t);

-

-  t = _T("moo a aa aa b ");

-  ReplaceCString(t, _T("aa"), 2, _T("b"), 1, 5);

-  ASSERT_STREQ(_T("moo a b b b "), t);

-

-  // Time to test some big strings

-  int test_sizes[] = {200, 500, 900, 10000};

-

-  int i;

-  for(i = 0; i < arraysize(test_sizes); ++i) {

-    CString in, out;

-    for(int j = 0; j < test_sizes[i]; ++j) {

-      in += L'a';

-      out += _T("bb");

-    }

-    CString bak_in(in);

-

-    // Make it a bit bigger

-    int times = ReplaceCString(in, _T("a"), 1, _T("bb"), 2, kRepMax);

-    ASSERT_EQ(times, test_sizes[i]);

-    ASSERT_EQ(out, in);

-

-    // Make it bigger still

-    times = ReplaceCString(in, _T("bb"), 2, _T("ccc"), 3, kRepMax);

-    ASSERT_EQ(times, test_sizes[i]);

-

-    // Same size swap

-    times = ReplaceCString(in, _T("c"), 1, _T("d"), 1, kRepMax);

-    ASSERT_EQ(times, test_sizes[i] * 3);

-

-    // Make it smaller again

-    times = ReplaceCString(in, _T("ddd"), 3, _T("a"), 1, kRepMax);

-    ASSERT_EQ(times, test_sizes[i]);

-    ASSERT_EQ(bak_in, in);

-  }

-}

-

-TEST(StringTest, GetField) {

-  CString s(_T("<a>a</a><b>123</b><c>aa\ndd</c>"));

-

-  CString a(GetField (s, L"a"));

-  ASSERT_STREQ(a, L"a");

-

-  CString b(GetField (s, L"b"));

-  ASSERT_STREQ(b, L"123");

-

-  CString c(GetField (s, L"c"));

-  ASSERT_STREQ(c, L"aa\ndd");

-}

-

-TEST(StringTest, String_HasAlphabetLetters) {

-  ASSERT_TRUE(String_HasAlphabetLetters (L"abc"));

-  ASSERT_TRUE(String_HasAlphabetLetters (L"X"));

-  ASSERT_TRUE(String_HasAlphabetLetters (L" pie "));

-  ASSERT_FALSE(String_HasAlphabetLetters (L"1"));

-  ASSERT_FALSE(String_HasAlphabetLetters (L"0"));

-  ASSERT_FALSE(String_HasAlphabetLetters (L"010"));

-  ASSERT_FALSE(String_HasAlphabetLetters (L"314-159"));

-  ASSERT_TRUE(String_HasAlphabetLetters (L"pie0"));

-}

-

-TEST(StringTest, String_LargeIntToApproximateString) {

-  int power;

-  ASSERT_TRUE(String_LargeIntToApproximateString(10LL, true, &power) == _T("10") && power == 0);

-  ASSERT_TRUE(String_LargeIntToApproximateString(99LL, true, &power) == _T("99") && power == 0);

-  ASSERT_TRUE(String_LargeIntToApproximateString(990LL, true, &power) == _T("990") && power == 0);

-  ASSERT_TRUE(String_LargeIntToApproximateString(999LL, true, &power) == _T("999") && power == 0);

-

-  ASSERT_TRUE(String_LargeIntToApproximateString(1000LL, true, &power) == _T("1.0") && power == 1);

-  ASSERT_TRUE(String_LargeIntToApproximateString(1200LL, true, &power) == _T("1.2") && power == 1);

-  ASSERT_TRUE(String_LargeIntToApproximateString(7500LL, true, &power) == _T("7.5") && power == 1);

-  ASSERT_TRUE(String_LargeIntToApproximateString(9900LL, true, &power) == _T("9.9") && power == 1);

-  ASSERT_TRUE(String_LargeIntToApproximateString(10000LL, true, &power) == _T("10") && power == 1);

-  ASSERT_TRUE(String_LargeIntToApproximateString(11000LL, true, &power) == _T("11") && power == 1);

-  ASSERT_TRUE(String_LargeIntToApproximateString(987654LL, true, &power) == _T("987") && power == 1);

-

-  ASSERT_TRUE(String_LargeIntToApproximateString(1000000LL, true, &power) == _T("1.0") && power == 2);

-  ASSERT_TRUE(String_LargeIntToApproximateString(1300000LL, true, &power) == _T("1.3") && power == 2);

-  ASSERT_TRUE(String_LargeIntToApproximateString(987654321LL, true, &power) == _T("987") && power == 2);

-

-  ASSERT_TRUE(String_LargeIntToApproximateString(1000000000LL, true, &power) == _T("1.0") && power == 3);

-  ASSERT_TRUE(String_LargeIntToApproximateString(1999999999LL, true, &power) == _T("1.9") && power == 3);

-  ASSERT_TRUE(String_LargeIntToApproximateString(20000000000LL, true, &power) == _T("20") && power == 3);

-  ASSERT_TRUE(String_LargeIntToApproximateString(1000000000000LL, true, &power) == _T("1000") && power == 3);

-  ASSERT_TRUE(String_LargeIntToApproximateString(12345678901234LL, true, &power) == _T("12345") && power == 3);

-

-  ASSERT_TRUE(String_LargeIntToApproximateString(1023LL, false, &power) == _T("1023") && power == 0);

-

-  ASSERT_TRUE(String_LargeIntToApproximateString(1024LL, false, &power) == _T("1.0") && power == 1);

-  ASSERT_TRUE(String_LargeIntToApproximateString(1134LL, false, &power) == _T("1.1") && power == 1);

-  ASSERT_TRUE(String_LargeIntToApproximateString(10240LL, false, &power) == _T("10") && power == 1);

-

-  ASSERT_TRUE(String_LargeIntToApproximateString(5242880LL, false, &power) == _T("5.0") && power == 2);

-

-  ASSERT_TRUE(String_LargeIntToApproximateString(1073741824LL, false, &power) == _T("1.0") && power == 3);

-  ASSERT_TRUE(String_LargeIntToApproximateString(17179869184LL, false, &power) == _T("16") && power == 3);

-}

-

-TEST(StringTest, FindWholeWordMatch) {

-  // words with spaces before / after

-  ASSERT_EQ(0, FindWholeWordMatch (L"pi", L"pi", false, 0));

-  ASSERT_EQ(1, FindWholeWordMatch (L" pi", L"pi", false, 0));

-  ASSERT_EQ(1, FindWholeWordMatch (L" pi ", L"pi", false, 0));

-  ASSERT_EQ(0, FindWholeWordMatch (L"pi ", L"pi", false, 0));

-

-  // partial matches

-  ASSERT_EQ(-1, FindWholeWordMatch (L"pie ", L"pi", false, 0));

-  ASSERT_EQ(-1, FindWholeWordMatch (L" pie ", L"pi", false, 0));

-  ASSERT_EQ(-1, FindWholeWordMatch (L"pie", L"pi", false, 0));

-  ASSERT_EQ(-1, FindWholeWordMatch (L" pie", L"pi", false, 0));

-

-  // partial match with non-alphanumeric chars

-  ASSERT_EQ(-1, FindWholeWordMatch (L" pumpkin_pie ", L"pie", false, 0));

-  ASSERT_EQ(-1, FindWholeWordMatch (L" pie_crust ", L"pie", false, 0));

-  ASSERT_EQ(-1, FindWholeWordMatch (L"tartar", L"tar", false, 0));

-  ASSERT_EQ(-1, FindWholeWordMatch (L"pie!", L"pie", false, 0));

-}

-

-TEST(StringTest, ReplaceWholeWord) {

-  CString str (L"pie");

-  ReplaceWholeWord (L"ie", L"..", false, &str);

-  ASSERT_STREQ(str, L"pie");

-

-  ReplaceWholeWord (L"pie", L"..", false, &str);

-  ASSERT_STREQ(str, L"..");

-

-  str = L"banana pie";

-  ReplaceWholeWord (L"pie", L"..", false, &str);

-  ASSERT_STREQ(str, L"banana ..");

-

-  str = L"banana pie";

-  ReplaceWholeWord (L"banana", L"..", false, &str);

-  ASSERT_STREQ(str, L".. pie");

-

-  str = L"banana pie";

-  ReplaceWholeWord (L"banana pie", L" .. ", false, &str);

-  ASSERT_STREQ(str, L" .. ");

-

-  str = L"banana pie";

-  ReplaceWholeWord (L"pi", L" .. ", false, &str);

-  ASSERT_STREQ(str, L"banana pie");

-

-  str = L"ishniferatsu";

-  ReplaceWholeWord (L"era", L" .. ", false, &str);

-  ASSERT_STREQ(str, L"ishniferatsu");

-

-  str = L"i i i hi ii i";

-  ReplaceWholeWord (L"i", L"you", false, &str);

-  ASSERT_STREQ(str, L"you you you hi ii you");

-

-  str = L"a nice cream cheese pie";

-  ReplaceWholeWord (L"cream cheese", L"..", false, &str);

-  ASSERT_STREQ(str, L"a nice .. pie");

-

-  // ---

-  // Test replacement with whitespace trimming

-

-  // Replace in the middle of the string.

-  str = L"a nice cream cheese pie";

-  ReplaceWholeWord (L"cream cheese", L"..", true, &str);

-  ASSERT_STREQ(str, L"a nice..pie");

-

-  // Replace in the beginning of the string.

-  str = L"a nice cream cheese pie";

-  ReplaceWholeWord (L"a nice", L"..", true, &str);

-  ASSERT_STREQ(str, L"..cream cheese pie");

-

-  // Replace in the end of the string.

-  str = L"a nice cream cheese pie";

-  ReplaceWholeWord (L"pie", L"..", true, &str);

-  ASSERT_STREQ(str, L"a nice cream cheese..");

-}

-

-

-TEST(StringTest, TestReplaceString) {

-  // timing for replace string, for the specific tests below shows:

-  //

-  // the TCHAR version is always faster than CRT CString::Replace

-  //

-  // the CString version is faster than CRT CString::Replace:

-  // - always if the replacement is shorter

-  // - if the source string is longer than ~60 characters if the replacement is

-  //   longer

-  //

-  // based on our current usage of CString::Replace, I expect the new CString

-  // version is faster on average than CRT CString::Replace

-  //

-  // non-CRT CString::Replace is much slower, so all of these should be much

-  // faster than that

-

-  TestReplaceString(L"that's what i changed -it was propagating the error code but i ..", L" .. ", L"<b> .. </b>", L"that's what i changed -it was propagating the error code but i ..");

-  TestReplaceString(L"news.com.url", L".url", L"", L"news.com");

-  TestReplaceString(L"news.com..url", L".url", L"", L"news.com.");

-  TestReplaceString(L"news.com.u.url", L".url", L"", L"news.com.u");

-  TestReplaceString(L"abanana pie banana", L"banana", L"c", L"ac pie c");

-  TestReplaceString(L"bananabananabanana", L"banana", L"c", L"ccc");

-  TestReplaceString(L"abanana pie banana", L"banana", L"cabanapie", L"acabanapie pie cabanapie");

-  TestReplaceString(L"bananabananabanana", L"banana", L"cabanapie", L"cabanapiecabanapiecabanapie");

-  TestReplaceString(L"banana pie banana pie", L"banana", L"c", L"c pie c pie");

-  TestReplaceString(L"banana pie banana pie", L"pie", L"z", L"banana z banana z");

-  TestReplaceString(L"banana pie banana pie", L"banana", L"bananacabana", L"bananacabana pie bananacabana pie");

-  TestReplaceString(L"banana pie banana pie", L"pie", L"pietie", L"banana pietie banana pietie");

-  TestReplaceString(L"banana pie banana pie", L"tie", L"pietie", L"banana pie banana pie");

-  TestReplaceString(L"banana pie banana pie banana pie banana pie banana pie", L"banana", L"bananacab", L"bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie");

-  TestReplaceString(L"banana pie banana pie banana pie banana pie banana pie banana pie banana pie", L"banana", L"bananacab", L"bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie");

-  TestReplaceString(L"banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie", L"banana", L"bananacab", L"bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie");

-  TestReplaceString(L"banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie", L"banana", L"bananacab", L"bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie");

-  TestReplaceString(L"banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie", L"banana", L"cab", L"cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie");

-  TestReplaceString(L"news", L"news", L"", L"");

-  TestReplaceString(L"&nbsp;", L"&nbsp;", L"", L"");

-  TestReplaceString(L"&nbsp;&nbsp;&nbsp;", L"&nbsp;", L"", L"");

-  TestReplaceString(L"&nbsp; &nbsp;&nbsp;", L"&nbsp;", L"", L" ");

-}

-

-

-TEST(StringTest, GetAbsoluteUri) {

-  ASSERT_STREQ(GetAbsoluteUri(L"http://www.google.com"),

-               L"http://www.google.com/");

-  ASSERT_STREQ(GetAbsoluteUri(L"http://www.google.com/"),

-               L"http://www.google.com/");

-  ASSERT_STREQ(GetAbsoluteUri(L"http://www.google.com//"),

-               L"http://www.google.com/");

-  ASSERT_STREQ(GetAbsoluteUri(L"http://www.google.com/test"),

-               L"http://www.google.com/test");

-}

-

-void TestTrim(const TCHAR *str, const TCHAR *result) {

-  ASSERT_TRUE(result);

-  ASSERT_TRUE(str);

-

-  size_t ptr_size = _tcslen(str) + 1;

-  TCHAR* ptr = new TCHAR[ptr_size];

-  _tcscpy_s(ptr, ptr_size, str);

-

-  int len = Trim(ptr);

-  ASSERT_STREQ(ptr, result);

-  ASSERT_EQ(len, lstrlen(result));

-

-  delete [] ptr;

-}

-

-TEST(StringTest, Trim) {

-  TestTrim(L"", L"");

-  TestTrim(L" ", L"");

-  TestTrim(L"\t", L"");

-  TestTrim(L"\n", L"");

-  TestTrim(L"\n\t    \t \n", L"");

-  TestTrim(L"    joe", L"joe");

-  TestTrim(L"joe      ", L"joe");

-  TestTrim(L"    joe      ", L"joe");

-  TestTrim(L"joe smith    ", L"joe smith");

-  TestTrim(L"     joe smith    ", L"joe smith");

-  TestTrim(L"     joe   smith    ", L"joe   smith");

-  TestTrim(L"     The quick brown fox,\tblah", L"The quick brown fox,\tblah");

-  TestTrim(L" \tblah\n    joe smith    ", L"blah\n    joe smith");

-}

-

-// IsSpaceA1 is much faster without the cache clearing (which is what happends

-// in release mode)

-// IsSpaceA1 is roughly the same speed as IsSpaceA2 with cache clearing (in

-// debug mode)

-// IsSpaceA3 is always much slower

-

-static const byte spacesA[256] = {

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  // 0-9

-  1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 10-19

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 20-29

-  0, 0, 1, 0, 0, 0, 0, 0, 0, 0,  // 30-39

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 40-49

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 50-59

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 60-69

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 70-79

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 80-89

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 90-99

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 100-109

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 110-119

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 120-129

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 130-139

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 140-149

-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 150-159

-  1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 160-169

-};

-

-bool IsSpaceA1(char c) {

-  return spacesA[c] == 1;

-}

-

-bool IsSpaceA2(char c) {

-  // return (c==32);

-  // if (c>32) { return 0; }

-  // most characters >32, check first for that case

-  if (c>32 && c!=160) { return 0; }

-  if (c==32) { return 1; }

-  if (c>=9&&c<=13) return 1; else return 0;

-}

-

-bool IsSpaceA3(char c) {

-  WORD result;

-  if (GetStringTypeA(0, CT_CTYPE1, &c, 1, &result)) {

-    return (0 != (result & C1_SPACE));

-  }

-  return false;

-}

-

-void TestIsSpace (char *s) {

-    ASSERT_TRUE(s);

-

-    Timer t1 (false);

-    Timer t2 (false);

-    Timer t3 (false);

-

-    // int iterations = 10000;

-    int iterations = 100;

-    int len = strlen (s);

-

-    // used to try to clear the processor cache

-    int dlen = 100000;

-    char *dummy = new char [dlen];

-    for (int i = 0; i < dlen; i++) {

-      dummy[i] = static_cast<char>(tr_rand() % 256);

-    }

-

-    int num_spaces = 0;

-    int n = iterations * len;

-    for (int i = 0; i < iterations; i++) {

-        t1.Start();

-        for (int j = 0; j < len; j++) {

-            num_spaces += IsSpaceA1 (s[j]);

-        }

-        t1.Stop();

-        // this cache clearing code gets optimized out in release mode

-        int d2 = 0;

-        for (int i = 0; i < dlen; i++) { d2 += dummy[i]; }

-    }

-

-    num_spaces = 0;

-    for (int i = 0; i < iterations; i++) {

-        t2.Start();

-        for (int j = 0; j < len; j++) {

-            num_spaces += IsSpaceA2 (s[j]);

-        }

-        t2.Stop();

-        int d2 = 0;

-        for (int i = 0; i < dlen; i++) { d2 += dummy[i]; }

-    }

-

-    num_spaces = 0;

-    for (int i = 0; i < iterations; i++) {

-        t3.Start();

-        for (int j = 0; j < len; j++) {

-            num_spaces += IsSpaceA3 (s[j]);

-        }

-        t3.Stop();

-        int d2 = 0;

-        for (int i = 0; i < dlen; i++) { d2 += dummy[i]; }

-    }

-}

-

-TEST(StringTest, IsSpace) {

-  TestIsSpace("banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie");

-  TestIsSpace("sdlfhdkgheorutsgj sdlj aoi oaj gldjg opre gdsfjng oate yhdnv ;zsj fpoe v;kjae hgpaieh dajlgn aegh avn WEIf h9243y 9814cu 902t7 9[-32 [O8W759 RC90817 V9pDAHc n( ny(7LKFJAOISF *&^*^%$$%#*&^(*_*)_^& 67% 796%&$*^$ 8)6 (^ 08&^ )*^ 9-7=90z& +(^ )^* %9%4386 $& (& &+ 7- &(_* ");

-}

-

-void TestCleanupWhitespace(const TCHAR *str, const TCHAR *result) {

-  ASSERT_TRUE(result);

-  ASSERT_TRUE(str);

-

-  size_t ptr_size = _tcslen(str) + 1;

-  TCHAR* ptr = new TCHAR[ptr_size];

-  _tcscpy_s(ptr, ptr_size, str);

-

-  int len = CleanupWhitespace(ptr);

-  ASSERT_STREQ(ptr, result);

-  ASSERT_EQ(len, lstrlen(result));

-

-  delete [] ptr;

-}

-

-TEST(StringTest, CleanupWhitespace) {

-  TestCleanupWhitespace(L"", L"");

-  TestCleanupWhitespace(L"a    ", L"a");

-  TestCleanupWhitespace(L"    a", L"a");

-  TestCleanupWhitespace(L" a   ", L"a");

-  TestCleanupWhitespace(L"\t\n\r a   ", L"a");

-  TestCleanupWhitespace(L"  \n   a  \t   \r ", L"a");

-  TestCleanupWhitespace(L"a      b", L"a b");

-  TestCleanupWhitespace(L"   a \t\n\r     b", L"a b");

-  TestCleanupWhitespace(L"   vool                 voop", L"vool voop");

-  TestCleanupWhitespace(L"thisisaverylongstringwithsometext",

-                        L"thisisaverylongstringwithsometext");

-  TestCleanupWhitespace(L"thisisavery   longstringwithsometext",

-                        L"thisisavery longstringwithsometext");

-}

-

-void TestWcstoul (TCHAR *string, int radix, unsigned long expected) {

-    ASSERT_TRUE(string);

-

-    wchar_t *ptr;

-    int v = Wcstoul (string, &ptr, radix);

-    ASSERT_EQ(v, expected);

-

-#ifdef DEBUG

-    int v2 = wcstoul (string, &ptr, radix);

-    ASSERT_EQ(v, v2);

-#endif

-}

-

-TEST(StringTest, Wcstoul) {

-  TestWcstoul(L"625", 16, 1573);

-  TestWcstoul(L" 625", 16, 1573);

-  TestWcstoul(L"a3", 16, 163);

-  TestWcstoul(L"A3", 16, 163);

-  TestWcstoul(L"  A3", 16, 163);

-  TestWcstoul(L" 12445", 10, 12445);

-  TestWcstoul(L"12445778", 10, 12445778);

-}

-

-TEST(StringTest, IsDigit) {

-  ASSERT_TRUE(String_IsDigit('0'));

-  ASSERT_TRUE(String_IsDigit('1'));

-  ASSERT_TRUE(String_IsDigit('2'));

-  ASSERT_TRUE(String_IsDigit('3'));

-  ASSERT_TRUE(String_IsDigit('4'));

-  ASSERT_TRUE(String_IsDigit('5'));

-  ASSERT_TRUE(String_IsDigit('6'));

-  ASSERT_TRUE(String_IsDigit('7'));

-  ASSERT_TRUE(String_IsDigit('8'));

-  ASSERT_TRUE(String_IsDigit('9'));

-  ASSERT_FALSE(String_IsDigit('a'));

-  ASSERT_FALSE(String_IsDigit('b'));

-  ASSERT_FALSE(String_IsDigit('z'));

-  ASSERT_FALSE(String_IsDigit('A'));

-  ASSERT_FALSE(String_IsDigit(' '));

-  ASSERT_FALSE(String_IsDigit('#'));

-}

-

-TEST(StringTest, IsUpper) {

-  ASSERT_FALSE(String_IsUpper('0'));

-  ASSERT_FALSE(String_IsUpper(' '));

-  ASSERT_FALSE(String_IsUpper('#'));

-  ASSERT_FALSE(String_IsUpper('a'));

-  ASSERT_FALSE(String_IsUpper('z'));

-  ASSERT_TRUE(String_IsUpper('A'));

-  ASSERT_TRUE(String_IsUpper('B'));

-  ASSERT_TRUE(String_IsUpper('C'));

-  ASSERT_TRUE(String_IsUpper('D'));

-  ASSERT_TRUE(String_IsUpper('H'));

-  ASSERT_TRUE(String_IsUpper('Y'));

-  ASSERT_TRUE(String_IsUpper('Z'));

-}

-

-TEST(StringTest, StringToDouble) {

-  ASSERT_DOUBLE_EQ(String_StringToDouble(L"625"), 625);

-  ASSERT_DOUBLE_EQ(String_StringToDouble(L"-625"), -625);

-  ASSERT_DOUBLE_EQ(String_StringToDouble(L"-6.25"), -6.25);

-  ASSERT_DOUBLE_EQ(String_StringToDouble(L"6.25"), 6.25);

-  ASSERT_DOUBLE_EQ(String_StringToDouble(L"0.00"), 0);

-  ASSERT_DOUBLE_EQ(String_StringToDouble(L" 55.1"), 55.1);

-  ASSERT_DOUBLE_EQ(String_StringToDouble(L" 55.001"), 55.001);

-  ASSERT_DOUBLE_EQ(String_StringToDouble(L"  1.001"), 1.001);

-}

-

-TEST(StringTest, StringToInt) {

-  ASSERT_EQ(String_StringToInt(L"625"), 625);

-  ASSERT_EQ(String_StringToInt(L"6"), 6);

-  ASSERT_EQ(String_StringToInt(L"0"), 0);

-  ASSERT_EQ(String_StringToInt(L" 122"), 122);

-  ASSERT_EQ(String_StringToInt(L"a"), 0);

-  ASSERT_EQ(String_StringToInt(L" a"), 0);

-}

-

-TEST(StringTest, StringToInt64) {

-  ASSERT_EQ(String_StringToInt64(L"119600064000000000"),

-            119600064000000000uI64);

-  ASSERT_EQ(String_StringToInt64(L" 119600064000000000"),

-            119600064000000000uI64);

-  ASSERT_EQ(String_StringToInt64(L"625"), 625);

-  ASSERT_EQ(String_StringToInt64(L"6"), 6);

-  ASSERT_EQ(String_StringToInt64(L"0"), 0);

-  ASSERT_EQ(String_StringToInt64(L" 122"), 122);

-  ASSERT_EQ(String_StringToInt64(L"a"), 0);

-  ASSERT_EQ(String_StringToInt64(L" a"), 0);

-}

-

-void TestEndWithChar(const TCHAR *s, char c, const TCHAR *expected) {

-  ASSERT_TRUE(expected);

-  ASSERT_TRUE(s);

-

-  TCHAR buf[5000];

-  _tcscpy(buf, s);

-  String_EndWithChar(buf, c);

-  ASSERT_STREQ(buf, expected);

-}

-

-TEST(StringTest, EndWithChar) {

-  TestEndWithChar(L"", L'a', L"a");

-  TestEndWithChar(L"", L'\\', L"\\");

-  TestEndWithChar(L"a", L'a', L"a");

-  TestEndWithChar(L"a", L'b', L"ab");

-  TestEndWithChar(L"abcdefghij", L'a', L"abcdefghija");

-  TestEndWithChar(L"abcdefghij", L'\\', L"abcdefghij\\");

-}

-

-TEST(StringTest, HexDigitToInt) {

-  ASSERT_EQ(HexDigitToInt(L'0'), 0);

-  ASSERT_EQ(HexDigitToInt(L'1'), 1);

-  ASSERT_EQ(HexDigitToInt(L'2'), 2);

-  ASSERT_EQ(HexDigitToInt(L'3'), 3);

-  ASSERT_EQ(HexDigitToInt(L'4'), 4);

-  ASSERT_EQ(HexDigitToInt(L'5'), 5);

-  ASSERT_EQ(HexDigitToInt(L'6'), 6);

-  ASSERT_EQ(HexDigitToInt(L'7'), 7);

-  ASSERT_EQ(HexDigitToInt(L'8'), 8);

-  ASSERT_EQ(HexDigitToInt(L'9'), 9);

-  ASSERT_EQ(HexDigitToInt(L'A'), 10);

-  ASSERT_EQ(HexDigitToInt(L'a'), 10);

-  ASSERT_EQ(HexDigitToInt(L'B'), 11);

-  ASSERT_EQ(HexDigitToInt(L'b'), 11);

-  ASSERT_EQ(HexDigitToInt(L'C'), 12);

-  ASSERT_EQ(HexDigitToInt(L'c'), 12);

-  ASSERT_EQ(HexDigitToInt(L'D'), 13);

-  ASSERT_EQ(HexDigitToInt(L'd'), 13);

-  ASSERT_EQ(HexDigitToInt(L'E'), 14);

-  ASSERT_EQ(HexDigitToInt(L'e'), 14);

-  ASSERT_EQ(HexDigitToInt(L'F'), 15);

-  ASSERT_EQ(HexDigitToInt(L'f'), 15);

-}

-

-TEST(StringTest, IsHexDigit) {

-  ASSERT_TRUE(IsHexDigit(L'0'));

-  ASSERT_TRUE(IsHexDigit(L'1'));

-  ASSERT_TRUE(IsHexDigit(L'2'));

-  ASSERT_TRUE(IsHexDigit(L'3'));

-  ASSERT_TRUE(IsHexDigit(L'4'));

-  ASSERT_TRUE(IsHexDigit(L'5'));

-  ASSERT_TRUE(IsHexDigit(L'6'));

-  ASSERT_TRUE(IsHexDigit(L'7'));

-  ASSERT_TRUE(IsHexDigit(L'8'));

-  ASSERT_TRUE(IsHexDigit(L'9'));

-  ASSERT_TRUE(IsHexDigit(L'a'));

-  ASSERT_TRUE(IsHexDigit(L'A'));

-  ASSERT_TRUE(IsHexDigit(L'b'));

-  ASSERT_TRUE(IsHexDigit(L'B'));

-  ASSERT_TRUE(IsHexDigit(L'c'));

-  ASSERT_TRUE(IsHexDigit(L'C'));

-  ASSERT_TRUE(IsHexDigit(L'd'));

-  ASSERT_TRUE(IsHexDigit(L'D'));

-  ASSERT_TRUE(IsHexDigit(L'e'));

-  ASSERT_TRUE(IsHexDigit(L'E'));

-  ASSERT_TRUE(IsHexDigit(L'f'));

-  ASSERT_TRUE(IsHexDigit(L'F'));

-

-  for(TCHAR digit = static_cast<TCHAR>(127); digit < 10000; ++digit) {

-    ASSERT_FALSE(IsHexDigit(digit));

-  }

-}

-

-TEST(StringTest, Remove) {

-  CString temp_remove;

-

-  // Remove everything

-  temp_remove = _T("ftp://");

-  RemoveFromStart (temp_remove, _T("ftp://"), false);

-  ASSERT_STREQ(temp_remove, _T(""));

-

-  // Remove all but 1 letter

-  temp_remove = _T("ftp://a");

-  RemoveFromStart (temp_remove, _T("ftp://"), false);

-  ASSERT_STREQ(temp_remove, _T("a"));

-

-  // Remove the first instance

-  temp_remove = _T("ftp://ftp://");

-  RemoveFromStart (temp_remove, _T("ftp://"), false);

-  ASSERT_STREQ(temp_remove, _T("ftp://"));

-

-  // Remove normal

-  temp_remove = _T("ftp://taz the tiger");

-  RemoveFromStart (temp_remove, _T("ftp://"), false);

-  ASSERT_STREQ(temp_remove, _T("taz the tiger"));

-

-  // Wrong prefix

-  temp_remove = _T("ftp:/taz the tiger");

-  RemoveFromStart (temp_remove, _T("ftp://"), false);

-  ASSERT_STREQ(temp_remove, _T("ftp:/taz the tiger"));

-

-  // Not long enough

-  temp_remove = _T("ftp:/");

-  RemoveFromStart (temp_remove, _T("ftp://"), false);

-  ASSERT_STREQ(temp_remove, _T("ftp:/"));

-

-  // Remove nothing

-  temp_remove = _T("ftp:/");

-  RemoveFromStart (temp_remove, _T(""), false);

-  ASSERT_STREQ(temp_remove, _T("ftp:/"));

-

-  // Remove 1 character

-  temp_remove = _T("ftp:/");

-  RemoveFromStart (temp_remove, _T("f"), false);

-  ASSERT_STREQ(temp_remove, _T("tp:/"));

-

-  // Wrong case

-  temp_remove = _T("ftp:/");

-  RemoveFromStart (temp_remove, _T("F"), false);

-  ASSERT_STREQ(temp_remove, _T("ftp:/"));

-

-  // Remove everything

-  temp_remove = _T(".edu");

-  RemoveFromEnd (temp_remove, _T(".edu"));

-  ASSERT_STREQ(temp_remove, _T(""));

-

-  // Remove all but 1 letter

-  temp_remove = _T("a.edu");

-  RemoveFromEnd(temp_remove, _T(".edu"));

-  ASSERT_STREQ(temp_remove, _T("a"));

-

-  // Remove the first instance

-  temp_remove = _T(".edu.edu");

-  RemoveFromEnd(temp_remove, _T(".edu"));

-  ASSERT_STREQ(temp_remove, _T(".edu"));

-

-  // Remove normal

-  temp_remove = _T("ftp://taz the tiger.edu");

-  RemoveFromEnd(temp_remove, _T(".edu"));

-  ASSERT_STREQ(temp_remove, _T("ftp://taz the tiger"));

-

-  // Wrong suffix

-  temp_remove = _T("ftp:/taz the tiger.edu");

-  RemoveFromEnd(temp_remove, _T("/edu"));

-  ASSERT_STREQ(temp_remove, _T("ftp:/taz the tiger.edu"));

-

-  // Not long enough

-  temp_remove = _T("edu");

-  RemoveFromEnd(temp_remove, _T(".edu"));

-  ASSERT_STREQ(temp_remove, _T("edu"));

-

-  // Remove nothing

-  temp_remove = _T(".edu");

-  RemoveFromEnd(temp_remove, _T(""));

-  ASSERT_STREQ(temp_remove, _T(".edu"));

-

-  // Remove 1 character

-  temp_remove = _T(".edu");

-  RemoveFromEnd(temp_remove, _T("u"));

-  ASSERT_STREQ(temp_remove, _T(".ed"));

-

-  // Wrong case

-  temp_remove = _T(".edu");

-  RemoveFromEnd(temp_remove, _T("U"));

-  ASSERT_STREQ(temp_remove, _T(".edu"));

-}

-

-TEST(StringTest, WideToAnsiDirect) {

-  CString temp_convert;

-  ASSERT_STREQ("", WideToAnsiDirect(_T("")));

-  ASSERT_STREQ("a", WideToAnsiDirect(_T("a")));

-  ASSERT_STREQ("moon doggy", WideToAnsiDirect(_T("moon doggy")));

-

-  // Generate a string of all characters 0-255.

-  const int kNumChars = 256;

-  TCHAR nasty_chars[kNumChars];

-  for (int i = 0; i < kNumChars; ++i) {

-    nasty_chars[i] = static_cast<TCHAR>(i);

-  }

-  CString temp(nasty_chars, kNumChars);

-

-  // Convert it and make sure it matches.

-  CStringA out = WideToAnsiDirect(temp);

-  ASSERT_EQ(out.GetLength(), kNumChars);

-  for (int i = 0; i < kNumChars; ++i) {

-    ASSERT_EQ(static_cast<unsigned char>(nasty_chars[i]),

-              static_cast<unsigned char>(out.GetAt(i)));

-  }

-}

-

-TEST(StringTest, FindStringASpaceStringB) {

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type: text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-TYPE: text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-TYPE: text/HTML", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-TYPE: text/HTML", L"content-type:", L"text/HTML"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-TYPE: text/HTML", L"content-TYPE:", L"text/HTML"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:  text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:   text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type: sdfjsldkgjsdg content-type:    text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type: content-type: sdfjsldkgjsdg content-type:    text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:content-type: sdfjsldkgjsdg content-type:    text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:content-type:    text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"test/html content-type:content-type:    text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:    text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:\ttext/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:\t text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"Content-Type:\t text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"aasd content-type: text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"aa content-TYPE: text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"text.html  content-TYPE: text/HTML", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"text/html content-TYPE: text/HTML", L"content-type:", L"text/HTML"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"AAAA content-TYPE: text/HTML", L"content-TYPE:", L"text/HTML"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:text/html AAAAA", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:  text/html", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:   text/htmlaaa", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:    text/html  asdsdg content-type", L"content-type:", L"text/html"));

-  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:\ttext/htmlconttent-type:te", L"content-type:", L"text/html"));

-

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:  a  text/html", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:  content-type:  a  text/html", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type: b text/html  content-type:  a  text/html", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:-text/html", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:\ntext/html", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:  a  TEXT/html", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:  a  html/text", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"a dss content-type:  a  text/html", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"text/html content-type:-text/html", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"text/html sdfsd fcontent-type:\ntext/html", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"AAAA content-type:  a  TEXT/html", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:  a  html/text AAA", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:content-type:", L"content-type:", L"text/html"));

-  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:content-type: content-type:", L"content-type:", L"text/html"));

-}

-

-TEST(StringTest, ElideIfNeeded) {

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 3, 3), L"1..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 4, 3), L"12..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 5, 3), L"123..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 6, 3), L"1234..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 7, 3), L"1234..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 8, 3), L"1234..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 9, 3), L"1234..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 10, 3), L"1234..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 11, 3), L"1234 6789..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 12, 3), L"1234 6789..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 13, 3), L"1234 6789..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 14, 3), L"1234 6789 1234");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 15, 3), L"1234 6789 1234");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 16, 3), L"1234 6789 1234");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 17, 3), L"1234 6789 1234");

-

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 7, 6), L"1234..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 8, 6), L"1234 6..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 9, 6), L"1234 67..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 10, 6), L"1234 678..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 11, 6), L"1234 6789..");

-  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 12, 6), L"1234 6789..");

-}

-

-TEST(StringTest, SafeStrCat) {

-  const int kDestLen = 7;

-  TCHAR dest[kDestLen];

-  lstrcpyn(dest, L"short", kDestLen);

-  ASSERT_LT(lstrlen(dest), kDestLen);

-

-  dest[kDestLen-1] = 'a';

-  lstrcpyn(dest, L"medium123", kDestLen);

-  ASSERT_EQ(dest[kDestLen - 1], '\0');

-  ASSERT_LT(lstrlen(dest), kDestLen);

-

-  lstrcpyn(dest, L"longerlonger", kDestLen);

-  ASSERT_EQ(dest[kDestLen - 1], '\0');

-  ASSERT_LT(lstrlen(dest), kDestLen);

-

-  lstrcpyn(dest, L"12", kDestLen);

-  SafeStrCat(dest, L"3456", kDestLen);

-  ASSERT_EQ(dest[kDestLen - 1], '\0');

-  ASSERT_LT(lstrlen(dest), kDestLen);

-}

-

-void TestPathFindExtension(const TCHAR *s) {

-  ASSERT_STREQ(String_PathFindExtension(s), PathFindExtension(s));

-}

-

-TEST(StringTest, TestPathFindExtension) {

-  TestPathFindExtension(L"c:\\test.tmp");

-  TestPathFindExtension(L"c:\\test.temp");

-  TestPathFindExtension(L"c:\\t\\e\\st.temp");

-  TestPathFindExtension(L"c:\\a.temp");

-  TestPathFindExtension(L"\\aaa\\a.temp");

-  TestPathFindExtension(L"\\a\\a.temp");

-  TestPathFindExtension(L"\\a\\a.temp");

-  TestPathFindExtension(L"\\a\\a.t....emp");

-  TestPathFindExtension(L"\\a.a.a...a\\a.t....emp");

-  TestPathFindExtension(L"\\a\\a\\bbbb\\ddddddddddddddd.temp");

-  TestPathFindExtension(L"\\a\\a\\bbbb\\ddddddddddddddd.te___124567mp");

-  TestPathFindExtension(L"\\a\\a\\bbbb\\ddddddd.dddddddd.te___124567mp");

-}

-

-TEST(StringTest, TextToLinesAndBack) {

-  const TCHAR sample_input[]  = L"Now is the time\r\nfor all good men\r\nto come to the aid of their country";

-  const TCHAR* sample_lines[] = { L"Now is the time", L"for all good men", L"to come to the aid of their country" };

-  const TCHAR sample_output1[] = L"Now is the time\nfor all good men\nto come to the aid of their country\n";

-  const TCHAR sample_output2[] = L"Now is the timefor all good mento come to the aid of their country";

-

-  CString text_in(sample_input);

-  std::vector<CString> lines;

-  CString text_out;

-

-  TextToLines(text_in, L"\r\n", &lines);

-  ASSERT_EQ(lines.size(), 3);

-  for (size_t i = 0; i < arraysize(sample_lines); ++i) {

-    ASSERT_TRUE(0 == lines[i].Compare(sample_lines[i]));

-  }

-  LinesToText(lines, L"\n", &text_out);

-  ASSERT_TRUE(0 == text_out.Compare(sample_output1));

-  LinesToText(lines, L"", &text_out);

-  ASSERT_TRUE(0 == text_out.Compare(sample_output2));

-}

-

-CString TrimStdString(const TCHAR* str) {

-  CString s(str);

-  TrimString(s, L" \t");

-  return s;

-}

-

-TEST(StringTest, TrimString) {

-  ASSERT_STREQ(L"abc", TrimStdString(L"abc"));

-  ASSERT_STREQ(L"abc", TrimStdString(L" abc "));

-  ASSERT_STREQ(L"a c", TrimStdString(L" a c  "));

-  ASSERT_STREQ(L"abc", TrimStdString(L" \tabc\t "));

-  ASSERT_STREQ(L"", TrimStdString(L""));

-  ASSERT_STREQ(L"", TrimStdString(L"   "));

-}

-

-TEST(StringTest, StripFirstQuotedToken) {

-  ASSERT_STREQ(StripFirstQuotedToken(L""), L"");

-  ASSERT_STREQ(StripFirstQuotedToken(L"a" ), L"");

-  ASSERT_STREQ(StripFirstQuotedToken(L"  a b  "), L"b");

-  ASSERT_STREQ(StripFirstQuotedToken(L"\"abc\" def"), L" def");

-  ASSERT_STREQ(StripFirstQuotedToken(L"  \"abc def\" ghi  "), L" ghi");

-  ASSERT_STREQ(StripFirstQuotedToken(L"\"abc\"   \"def\" "), L"   \"def\"");

-}

-

-TEST(StringTest, EscapeUnescape) {

-  CString original_str(_T("test <>\"#{}|\\^[]?%&/"));

-  CString escaped_str;

-  ASSERT_SUCCEEDED(StringEscape(original_str, true, &escaped_str));

-  ASSERT_STREQ(escaped_str,

-               _T("test%20%3C%3E%22%23%7B%7D%7C%5C%5E%5B%5D%3F%25%26%2F"));

-  CString unescaped_str;

-  ASSERT_SUCCEEDED(StringUnescape(escaped_str, &unescaped_str));

-  ASSERT_STREQ(original_str, unescaped_str);

-

-  original_str = _T("foo.test path?app=1");

-  ASSERT_SUCCEEDED(StringEscape(original_str, false, &escaped_str));

-  ASSERT_STREQ(escaped_str,

-               _T("foo.test%20path?app=1"));

-  ASSERT_SUCCEEDED(StringUnescape(escaped_str, &unescaped_str));

-  ASSERT_STREQ(original_str, unescaped_str);

-}

-

-TEST(StringTest, String_StringToDecimalIntChecked) {

-  int value = 0;

-

-  // This code before the first valid case verifies that errno is properly

-  // cleared and there are no dependencies on prior code.

-  EXPECT_EQ(0, _set_errno(ERANGE));

-

-  // Valid Cases

-  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("935"), &value));

-  EXPECT_EQ(value, 935);

-  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("-935"), &value));

-  EXPECT_EQ(value, -935);

-  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("0"), &value));

-  EXPECT_EQ(value, 0);

-  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("2147483647"), &value));

-  EXPECT_EQ(value, LONG_MAX);

-  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("-2147483648"), &value));

-  EXPECT_EQ(value, LONG_MIN);

-  EXPECT_TRUE(String_StringToDecimalIntChecked(_T(" 0"), &value));

-  EXPECT_EQ(value, 0);

-

-  // Failing Cases

-  EXPECT_FALSE(String_StringToDecimalIntChecked(_T(""), &value));

-  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("2147483648"), &value));

-  EXPECT_EQ(value, LONG_MAX);

-  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("-2147483649"), &value));

-  EXPECT_EQ(value, LONG_MIN);

-  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("0x935"), &value));

-  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("nine"), &value));

-  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("9nine"), &value));

-  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("nine9"), &value));

-

-  // A valid case after an overflow verifies that this method clears errno.

-  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("2147483648"), &value));

-  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("935"), &value));

-}

-TEST(StringTest, String_StringToTristate) {

-  Tristate value = TRISTATE_NONE;

-

-  // Valid Cases

-  EXPECT_TRUE(String_StringToTristate(_T("0"), &value));

-  EXPECT_EQ(value, TRISTATE_FALSE);

-  EXPECT_TRUE(String_StringToTristate(_T("1"), &value));

-  EXPECT_EQ(value, TRISTATE_TRUE);

-  EXPECT_TRUE(String_StringToTristate(_T("2"), &value));

-  EXPECT_EQ(value, TRISTATE_NONE);

-

-  // Invalid Cases

-  EXPECT_FALSE(String_StringToTristate(_T("-1"), &value));

-  EXPECT_FALSE(String_StringToTristate(_T("3"), &value));

-  EXPECT_FALSE(String_StringToTristate(_T(""), &value));

-}

-

-TEST(StringTest, ParseNameValuePair) {

-  CString name;

-  CString value;

-

-  // Valid Cases

-  EXPECT_TRUE(ParseNameValuePair(_T("xx=yyzz"), _T('='), &name, &value));

-  EXPECT_EQ(name, _T("xx"));

-  EXPECT_EQ(value, _T("yyzz"));

-  EXPECT_TRUE(ParseNameValuePair(_T("x=3?\\/\r\n "), _T('='), &name, &value));

-  EXPECT_EQ(name, _T("x"));

-  EXPECT_EQ(value, _T("3?\\/\r\n "));

-  EXPECT_TRUE(ParseNameValuePair(_T("3?google"), _T('?'), &name, &value));

-  EXPECT_EQ(name, _T("3"));

-  EXPECT_EQ(value, _T("google"));

-

-  // Invalid Cases

-  EXPECT_FALSE(ParseNameValuePair(_T(""), _T('='), &name, &value));

-  EXPECT_FALSE(ParseNameValuePair(_T(" "), _T('='), &name, &value));

-  EXPECT_FALSE(ParseNameValuePair(_T("="), _T('='), &name, &value));

-  EXPECT_FALSE(ParseNameValuePair(_T("x="), _T('='), &name, &value));

-  EXPECT_FALSE(ParseNameValuePair(_T("=y"), _T('='), &name, &value));

-  EXPECT_FALSE(ParseNameValuePair(_T("="), _T('='), &name, &value));

-  EXPECT_FALSE(ParseNameValuePair(_T("xxyyzz"), _T('='), &name, &value));

-  EXPECT_FALSE(ParseNameValuePair(_T("xx yyzz"), _T('='), &name, &value));

-  EXPECT_FALSE(ParseNameValuePair(_T("xx==yyzz"), _T('='), &name, &value));

-  EXPECT_FALSE(ParseNameValuePair(_T("xx=yy=zz"), _T('='), &name, &value));

-}

-

-TEST(StringTest, SplitCommandLineInPlace) {

-  const TCHAR * const test_long_paths[] = {

-    _T("c:\\Program Files\\Google\\App\\App.exe"),

-    _T("c:\\Program Files\\Google\\App\\Long Name App.exe"),

-  };

-  const TCHAR * const test_short_paths[] = {

-    _T("notepad.exe"),

-  };

-  const TCHAR * const test_arguments[] = {

-    _T("/a=\"some text\""),

-    _T("/a /b /c"),

-    _T(""),

-  };

-  TCHAR command_line[1024] = {};

-  TCHAR* path = NULL;

-  TCHAR* arguments = NULL;

-  for (int ii = 0; ii < ARRAYSIZE(test_arguments) ; ++ii) {

-    for (int jj = 0; jj < ARRAYSIZE(test_long_paths) ; ++jj) {

-      _snwprintf_s(command_line, ARRAYSIZE(command_line), _TRUNCATE,

-          _T("\"%s\" %s"), test_long_paths[jj], test_arguments[ii]);

-      EXPECT_EQ(true, SplitCommandLineInPlace(command_line, &path, &arguments));

-      EXPECT_STREQ(test_long_paths[jj], path);

-      EXPECT_STREQ(test_arguments[ii], arguments);

-    }

-    for (int kk = 0; kk < ARRAYSIZE(test_short_paths) ; ++kk) {

-      _snwprintf_s(command_line, ARRAYSIZE(command_line), _TRUNCATE,

-          _T("%s %s"), test_short_paths[kk], test_arguments[ii]);

-      EXPECT_EQ(true, SplitCommandLineInPlace(command_line, &path, &arguments));

-      EXPECT_STREQ(test_short_paths[kk], path);

-      EXPECT_STREQ(test_arguments[ii], arguments);

-    }

-  }

-}

-

-TEST(StringTest, ContainsOnlyAsciiChars) {

-  CString test(_T("hello worlr"));

-  ASSERT_TRUE(ContainsOnlyAsciiChars(test));

-

-  TCHAR non_ascii[] = {0x4345, 0x1234, 0x2000};

-  ASSERT_FALSE(ContainsOnlyAsciiChars(non_ascii));

-}

-TEST(StringTest, BytesToHex) {

-  EXPECT_STREQ(BytesToHex(NULL, 0), _T(""));

-  uint8 i = 0;

-  EXPECT_STREQ(BytesToHex(&i, sizeof(i)), _T("00"));

-  i = 0x7f;

-  EXPECT_STREQ(BytesToHex(&i, sizeof(i)), _T("7f"));

-  i = 0xff;

-  EXPECT_STREQ(BytesToHex(&i, sizeof(i)), _T("ff"));

-

-  // Assumes little-endian representation of integers.

-  const uint32 array[] = {0x67452301, 0xefcdab89};

-  EXPECT_STREQ(BytesToHex(reinterpret_cast<const uint8*>(array), sizeof(array)),

-               _T("0123456789abcdef"));

-

-  const uint8* first = reinterpret_cast<const uint8*>(array);

-  const uint8* last  = first + sizeof(array);

-  EXPECT_STREQ(BytesToHex(std::vector<uint8>(first, last)),

-               _T("0123456789abcdef"));

-}

-

-TEST(StringTest, JoinStrings) {

-  std::vector<CString> components;

-  const TCHAR* delim = _T("-");

-  CString result;

-

-  JoinStrings(components, delim, &result);

-  EXPECT_TRUE(result.IsEmpty());

-  JoinStrings(components, NULL, &result);

-  EXPECT_TRUE(result.IsEmpty());

-

-  components.push_back(CString(_T("foo")));

-  JoinStrings(components, delim, &result);

-  EXPECT_STREQ(result, (_T("foo")));

-  JoinStrings(components, NULL, &result);

-  EXPECT_STREQ(result, (_T("foo")));

-

-  components.push_back(CString(_T("bar")));

-  JoinStrings(components, delim, &result);

-  EXPECT_STREQ(result, (_T("foo-bar")));

-  JoinStrings(components, NULL, &result);

-  EXPECT_STREQ(result, (_T("foobar")));

-

-  components.push_back(CString(_T("baz")));

-  JoinStrings(components, delim, &result);

-  EXPECT_STREQ(result, (_T("foo-bar-baz")));

-  JoinStrings(components, NULL, &result);

-  EXPECT_STREQ(result, (_T("foobarbaz")));

-

-

-  JoinStringsInArray(NULL, 0, delim, &result);

-  EXPECT_TRUE(result.IsEmpty());

-  JoinStringsInArray(NULL, 0, NULL, &result);

-  EXPECT_TRUE(result.IsEmpty());

-

-  const TCHAR* array1[] = {_T("foo")};

-  JoinStringsInArray(array1, arraysize(array1), delim, &result);

-  EXPECT_STREQ(result, (_T("foo")));

-  JoinStringsInArray(array1, arraysize(array1), NULL, &result);

-  EXPECT_STREQ(result, (_T("foo")));

-

-  const TCHAR* array2[] = {_T("foo"), _T("bar")};

-  JoinStringsInArray(array2, arraysize(array2), delim, &result);

-  EXPECT_STREQ(result, (_T("foo-bar")));

-  JoinStringsInArray(array2, arraysize(array2), NULL, &result);

-  EXPECT_STREQ(result, (_T("foobar")));

-

-  const TCHAR* array3[] = {_T("foo"), _T("bar"), _T("baz")};

-  JoinStringsInArray(array3, arraysize(array3), delim, &result);

-  EXPECT_STREQ(result, (_T("foo-bar-baz")));

-  JoinStringsInArray(array3, arraysize(array3), NULL, &result);

-  EXPECT_STREQ(result, (_T("foobarbaz")));

-

-  const TCHAR* array_null_1[] = {NULL};

-  JoinStringsInArray(array_null_1, arraysize(array_null_1), delim, &result);

-  EXPECT_STREQ(result, (_T("")));

-

-  const TCHAR* array_null_2[] = {NULL, NULL};

-  JoinStringsInArray(array_null_2, arraysize(array_null_2), delim, &result);

-  EXPECT_STREQ(result, (_T("-")));

-}

-

-TEST(StringTest, String_ToUpper) {

-  // String_ToUpper is a wrapper over ::CharUpper.

-  TCHAR s[] = _T("foo");

-  String_ToUpper(s);

-  EXPECT_STREQ(s, _T("FOO"));

-}

-

-TEST(StringTest, FormatResourceMessage_Valid) {

-  EXPECT_STREQ(

-      _T("Thanks for installing Gears."),

-      FormatResourceMessage(IDS_APPLICATION_INSTALLED_SUCCESSFULLY,

-                            _T("Gears")));

-

-  EXPECT_STREQ(

-      _T("The installer encountered error 12345: Action failed."),

-      FormatResourceMessage(IDS_INSTALLER_FAILED_WITH_MESSAGE,

-                            _T("12345"),

-                            _T("Action failed.")));

-}

-

-TEST(StringTest, FormatResourceMessage_IdNotFound) {

-  EXPECT_STREQ(_T(""), FormatResourceMessage(100000, "foo", 9));

-}

-

-TEST(StringTest, FormatErrorCode) {

-  EXPECT_STREQ(_T("0xffffffff"), FormatErrorCode(static_cast<DWORD>(-1)));

-  EXPECT_STREQ(_T("0"), FormatErrorCode(0));

-  EXPECT_STREQ(_T("567"), FormatErrorCode(567));

-  EXPECT_STREQ(_T("2147483647"), FormatErrorCode(0x7fffffff));

-  EXPECT_STREQ(_T("0x80000000"), FormatErrorCode(0x80000000));

-  EXPECT_STREQ(_T("0x80000001"), FormatErrorCode(0x80000001));

-  EXPECT_STREQ(_T("0x8fffffff"), FormatErrorCode(0x8fffffff));

-}

-

-TEST(StringTest, Utf8BufferToWideChar) {

-  // Unicode Greek capital letters.

-  const TCHAR expected_string[] = {913, 914, 915, 916, 917, 918, 919, 920,

-                                   921, 922, 923, 924, 925, 926, 927, 928,

-                                   929, 931, 932, 933, 934, 935, 936, 937, 0};

-  // Greek capital letters UTF-8 encoded.

-  const char buffer[] = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ";

-  CString actual_string = Utf8BufferToWideChar(

-      std::vector<uint8>(buffer, buffer + arraysize(buffer)));

-  EXPECT_STREQ(expected_string, actual_string);

-

-  EXPECT_STREQ(_T(""), Utf8BufferToWideChar(std::vector<uint8>()));

-}

-

-TEST(StringTest, WideStringToUtf8UrlEncodedStringRoundTrip) {

-  CString unicode_string;

-  ASSERT_TRUE(unicode_string.LoadString(IDS_ESCAPE_TEST));

-

-  // Convert from unicode to a wide representation of utf8,url encoded string.

-  CString utf8encoded_str;

-  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_string,

-                                                            &utf8encoded_str));

-  ASSERT_FALSE(utf8encoded_str.IsEmpty());

-

-  // Reconvert from the utf8, url encoded string to the wide version.

-  CString out;

-  ASSERT_HRESULT_SUCCEEDED(Utf8UrlEncodedStringToWideString(utf8encoded_str,

-                                                            &out));

-  ASSERT_FALSE(out.IsEmpty());

-  ASSERT_STREQ(unicode_string, out);

-}

-

-TEST(StringTest, WideStringToUtf8UrlEncodedStringEmptyString) {

-  CString unicode_string;

-

-  // Convert from unicode to a wide representation of utf8,url encoded string.

-  CString utf8encoded_str;

-  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_string,

-                                                            &utf8encoded_str));

-  ASSERT_TRUE(utf8encoded_str.IsEmpty());

-}

-

-TEST(StringTest, WideStringToUtf8UrlEncodedStringSpaces) {

-  CString unicode_string(_T("   "));

-  CStringA expected("%20%20%20");

-  CString exp(expected);

-

-  // Convert from unicode to a wide representation of utf8,url encoded string.

-  CString utf8encoded_str;

-  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_string,

-                                                            &utf8encoded_str));

-  ASSERT_STREQ(exp, utf8encoded_str);

-}

-

-TEST(StringTest, WideStringToUtf8UrlEncodedStringTestString) {

-  CString unicode_string(_T("Test Str/ing&values=&*^%$#"));

-  CStringA ansi_exp("Test%20Str/ing%26values=%26*%5E%$#");

-  CString exp(ansi_exp);

-

-  // Convert from unicode to a wide representation of utf8,url encoded string.

-  CString utf8encoded_str;

-  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_string,

-                                                            &utf8encoded_str));

-  ASSERT_STREQ(exp, utf8encoded_str);

-}

-

-TEST(StringTest, WideStringToUtf8UrlEncodedStringSimpleTestString) {

-  CString unicode_string(_T("TestStr"));

-  CStringA ansi_exp("TestStr");

-  CString exp(ansi_exp);

-

-  // Convert from unicode to a wide representation of utf8,url encoded string.

-  CString utf8encoded_str;

-  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_string,

-                                                            &utf8encoded_str));

-  ASSERT_STREQ(exp, utf8encoded_str);

-}

-

-TEST(StringTest, Utf8UrlEncodedStringToWideStringEmpty) {

-  // Convert from wide representation of utf8,url encoded string to unicode.

-  CString unicode_string;

-  CString utf8encoded_str;

-  ASSERT_HRESULT_SUCCEEDED(Utf8UrlEncodedStringToWideString(utf8encoded_str,

-                                                            &unicode_string));

-  ASSERT_TRUE(unicode_string.IsEmpty());

-}

-

-TEST(StringTest, Utf8UrlEncodedStringToWideStringSpaces) {

-  CString exp(_T("   "));

-  CStringA utf8("%20%20%20");

-  CString utf8encoded_str(utf8);

-

-  // Convert from wide representation of utf8,url encoded string to unicode.

-  CString unicode_string;

-  ASSERT_HRESULT_SUCCEEDED(Utf8UrlEncodedStringToWideString(utf8encoded_str,

-                                                            &unicode_string));

-  ASSERT_STREQ(exp, unicode_string);

-}

-

-TEST(StringTest, Utf8UrlEncodedStringToWideStringSimpleString) {

-  CString exp(_T("TestStr"));

-  CStringA utf8("TestStr");

-  CString utf8encoded_str(utf8);

-

-  // Convert from wide representation of utf8,url encoded string to unicode.

-  CString unicode_string;

-  ASSERT_HRESULT_SUCCEEDED(Utf8UrlEncodedStringToWideString(utf8encoded_str,

-                                                            &unicode_string));

-  ASSERT_STREQ(exp, unicode_string);

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/localization.h"
+#include "omaha/common/string.h"
+#include "omaha/common/time.h"
+#include "omaha/common/timer.h"
+#include "omaha/common/tr_rand.h"
+#include "omaha/goopdate/resources/goopdateres/goopdate.grh"
+#include "omaha/testing/resource.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(StringTest, IntToString) {
+  ASSERT_STREQ(String_Int64ToString(0, 10), L"0");
+  ASSERT_STREQ(String_Int64ToString(1, 10), L"1");
+  ASSERT_STREQ(String_Int64ToString(-1, 10), L"-1");
+  ASSERT_STREQ(String_Int64ToString(123456789, 10), L"123456789");
+  ASSERT_STREQ(String_Int64ToString(-123456789, 10), L"-123456789");
+  ASSERT_STREQ(String_Int64ToString(1234567890987654321, 10),
+               L"1234567890987654321");
+  ASSERT_STREQ(String_Int64ToString(-1234567890987654321, 10),
+               L"-1234567890987654321");
+  ASSERT_STREQ(String_Int64ToString(0xabcdef, 16), L"abcdef");
+  ASSERT_STREQ(String_Int64ToString(0x101fff, 16), L"101fff");
+  ASSERT_STREQ(String_Int64ToString(0x999999, 16), L"999999");
+  ASSERT_STREQ(String_Int64ToString(0x0, 16), L"0");
+
+  ASSERT_STREQ(String_Int64ToString(01234, 8), L"1234");
+  ASSERT_STREQ(String_Int64ToString(0, 8), L"0");
+  ASSERT_STREQ(String_Int64ToString(0777, 8), L"777");
+  ASSERT_STREQ(String_Int64ToString(0123456, 8), L"123456");
+
+  ASSERT_STREQ(String_Int64ToString(0, 2), L"0");
+  ASSERT_STREQ(String_Int64ToString(0xf, 2), L"1111");
+  ASSERT_STREQ(String_Int64ToString(0x5ad1, 2), L"101101011010001");
+  ASSERT_STREQ(String_Int64ToString(-1, 2), L"-1");
+}
+
+TEST(StringTest, UintToString) {
+  ASSERT_STREQ(String_Uint64ToString(0, 10), L"0");
+  ASSERT_STREQ(String_Uint64ToString(1, 10), L"1");
+  ASSERT_STREQ(String_Uint64ToString(123456789, 10), L"123456789");
+  ASSERT_STREQ(String_Uint64ToString(1234567890987654321, 10),
+               L"1234567890987654321");
+  ASSERT_STREQ(String_Uint64ToString(18446744073709551615, 10),
+               L"18446744073709551615");
+
+  ASSERT_STREQ(String_Uint64ToString(0xabcdef, 16), L"abcdef");
+  ASSERT_STREQ(String_Uint64ToString(0x101fff, 16), L"101fff");
+  ASSERT_STREQ(String_Uint64ToString(0x999999, 16), L"999999");
+  ASSERT_STREQ(String_Uint64ToString(0x0, 16), L"0");
+  ASSERT_STREQ(String_Uint64ToString(0xffffffffffffffff, 16), L"ffffffffffffffff");
+
+  ASSERT_STREQ(String_Uint64ToString(01234, 8), L"1234");
+  ASSERT_STREQ(String_Uint64ToString(0, 8), L"0");
+  ASSERT_STREQ(String_Uint64ToString(0777, 8), L"777");
+  ASSERT_STREQ(String_Uint64ToString(0123456, 8), L"123456");
+
+  ASSERT_STREQ(String_Uint64ToString(0, 2), L"0");
+  ASSERT_STREQ(String_Uint64ToString(0xf, 2), L"1111");
+  ASSERT_STREQ(String_Uint64ToString(0x5ad1, 2), L"101101011010001");
+}
+
+TEST(StringTest, DoubleToString) {
+  ASSERT_STREQ(String_DoubleToString(1.234, 1), L"1.2");
+  ASSERT_STREQ(String_DoubleToString(0.0, 0), L"0");
+  ASSERT_STREQ(String_DoubleToString(0.0, 2), L"0.00");
+  ASSERT_STREQ(String_DoubleToString(199.234, 2), L"199.23");
+  ASSERT_STREQ(String_DoubleToString(-199.234, 2), L"-199.23");
+  ASSERT_STREQ(String_DoubleToString(199.23490776, 5), L"199.23490");
+  ASSERT_STREQ(String_DoubleToString(-1.0001, 1), L"-1.0");
+  ASSERT_STREQ(String_DoubleToString(123456789.987654321, 3), L"123456789.987");
+}
+
+TEST(StringTest, StrNCpy) {
+  TCHAR * str1 = L"test str 1234";
+  TCHAR * str2 = L"test str 12";
+  TCHAR * str3 = L"Test StR 1234";
+
+  // check case sensitive
+  ASSERT_TRUE(0 == String_StrNCmp(str1, str2, 10, false));
+  ASSERT_TRUE(0 == String_StrNCmp(str1, str2, 11, false));
+
+  // check case in-sensitive
+  ASSERT_TRUE(0 == String_StrNCmp(str2, str3, 10, true));
+  ASSERT_TRUE(0 == String_StrNCmp(str2, str3, 11, true));
+}
+
+TEST(StringTest, StartsWith) {
+  ASSERT_TRUE(String_StartsWith(L"", L"", false));
+  ASSERT_TRUE(String_StartsWith(L"Joe", L"", false));
+  ASSERT_TRUE(String_StartsWith(L"Joe", L"J", false));
+  ASSERT_TRUE(String_StartsWith(L"Joe\\", L"J", false));
+  ASSERT_TRUE(String_StartsWith(L"Joe", L"Joe", false));
+  ASSERT_TRUE(String_StartsWith(L"The quick brown fox", L"The quic", false));
+  ASSERT_FALSE(String_StartsWith(L"", L"J", false));
+  ASSERT_FALSE(String_StartsWith(L"Joe", L"Joe2", false));
+  ASSERT_FALSE(String_StartsWith(L"The quick brown fox", L"The quiC", false));
+
+  ASSERT_TRUE(String_StartsWith(L"", L"", true));
+  ASSERT_TRUE(String_StartsWith(L"Joe", L"j", true));
+  ASSERT_TRUE(String_StartsWith(L"The quick brown fox", L"The quiC", true));
+}
+
+TEST(StringTest, StartsWithA) {
+  ASSERT_TRUE(String_StartsWithA("", "", false));
+  ASSERT_TRUE(String_StartsWithA("Joe", "", false));
+  ASSERT_TRUE(String_StartsWithA("Joe", "J", false));
+  ASSERT_TRUE(String_StartsWithA("Joe\\", "J", false));
+  ASSERT_TRUE(String_StartsWithA("Joe", "Joe", false));
+  ASSERT_TRUE(String_StartsWithA("The quick brown fox", "The quic", false));
+  ASSERT_FALSE(String_StartsWithA("", "J", false));
+  ASSERT_FALSE(String_StartsWithA("Joe", "Joe2", false));
+  ASSERT_FALSE(String_StartsWithA("The quick brown fox", "The quiC", false));
+
+  ASSERT_TRUE(String_StartsWithA("", "", true));
+  ASSERT_TRUE(String_StartsWithA("Joe", "j", true));
+  ASSERT_TRUE(String_StartsWithA("The quick brown fox", "The quiC", true));
+}
+
+TEST(StringTest, EndsWith) {
+  // Case sensitive
+
+  // Empty suffix
+  ASSERT_TRUE(String_EndsWith(L"", L"", false));
+  ASSERT_TRUE(String_EndsWith(L"Joe", L"", false));
+
+  // Partial suffix
+  ASSERT_TRUE(String_EndsWith(L"Joe", L"e", false));
+  ASSERT_TRUE(String_EndsWith(L"Joe\\", L"\\", false));
+  ASSERT_TRUE(String_EndsWith(L"The quick brown fox", L"n fox", false));
+
+  // Suffix == String
+  ASSERT_TRUE(String_EndsWith(L"Joe", L"Joe", false));
+  ASSERT_TRUE(String_EndsWith(L"The quick brown fox",
+                              L"The quick brown fox",
+                              false));
+
+  // Fail cases
+  ASSERT_FALSE(String_EndsWith(L"", L"J", false));
+  ASSERT_FALSE(String_EndsWith(L"Joe", L"Joe2", false));
+  ASSERT_FALSE(String_EndsWith(L"Joe", L"2Joe", false));
+  ASSERT_FALSE(String_EndsWith(L"The quick brown fox", L"n foX", false));
+
+  // Check case insensitive
+
+  // Empty suffix
+  ASSERT_TRUE(String_EndsWith(L"", L"", true));
+  ASSERT_TRUE(String_EndsWith(L"Joe", L"", true));
+
+  // Partial suffix
+  ASSERT_TRUE(String_EndsWith(L"Joe", L"E", true));
+  ASSERT_TRUE(String_EndsWith(L"The quick brown fox", L"n FOX", true));
+
+  // Suffix == String
+  ASSERT_TRUE(String_EndsWith(L"Joe", L"JOE", true));
+  ASSERT_TRUE(String_EndsWith(L"The quick brown fox",
+                              L"The quick brown FOX",
+                              true));
+
+  // Fail cases
+  ASSERT_FALSE(String_EndsWith(L"The quick brown fox", L"s", true));
+  ASSERT_FALSE(String_EndsWith(L"The quick brown fox", L"Xs", true));
+  ASSERT_FALSE(String_EndsWith(L"The quick brown fox", L"the brown foX", true));
+}
+
+TEST(StringTest, Unencode) {
+  // Normal, correct usage.
+  // char 0x25 is '%'
+  ASSERT_STREQ(Unencode(L"?q=moon+doggy_%25%5E%26"), L"?q=moon doggy_%^&");
+  ASSERT_STREQ(Unencode(L"%54%68%69%73+%69%73%09%61%20%74%65%73%74%0A"),
+               L"This is\ta test\n");
+  ASSERT_STREQ(Unencode(L"This+is%09a+test%0a"), L"This is\ta test\n");
+
+  // NULL char.
+  ASSERT_STREQ(Unencode(L"Terminated%00before+this"), L"Terminated");
+  ASSERT_STREQ(Unencode(L"invalid+%a%25"), L"invalid %a%");
+  ASSERT_STREQ(Unencode(L"invalid+%25%41%37"), L"invalid %A7");
+  ASSERT_STREQ(Unencode(L"not a symbol %RA"), L"not a symbol %RA");
+  ASSERT_STREQ(Unencode(L"%ag"), L"%ag");
+  ASSERT_STREQ(Unencode(L"dontdecode%dont"), L"dontdecode%dont");
+  ASSERT_STREQ(Unencode(L""), L"");
+  ASSERT_STREQ(Unencode(L"%1"), L"%1");
+  ASSERT_STREQ(Unencode(L"\x100"), L"\x100");
+  ASSERT_STREQ(Unencode(L"this is%20a%20wide%20char%20\x345"),
+               L"this is a wide char \x345");
+  ASSERT_STREQ(Unencode(L"a utf8 string %E7%BC%9c %E4%B8%8a = 2"),
+               L"a utf8 string \x7f1c \x4e0a = 2");
+}
+
+#if 0
+static const struct {
+  const char *ansi;
+  const TCHAR *wide;
+  UINT cp;
+} kAnsi2WideTests[] = {
+  { "\xc8\xae\xc1\xbe", L"\x72ac\x8f86", CP_GB2312},
+  { "\xa5\x69\xb1\x4e\xc2\xb2\xc5\xe9",
+    L"\x53ef\x5c07\x7c21\x9ad4", CP_BIG5},
+  { "\xE7\xBC\x96\xE4\xB8\x8B", L"\x7f16\x4e0b", CP_UTF8},
+  { "ascii", L"ascii", CP_GB2312},
+  { "\x3C\x20\xE7\xBC\x96", L"\x003c\x0020\x00E7\x00BC\x0096", 0 },
+};
+
+bool TestAnsiToWideString() {
+  for (size_t i = 0; i < arraysize(kAnsi2WideTests); ++i) {
+    CStringW out;
+    if (kAnsi2WideTests[i].cp == 0) {
+      out = AnsiToWideString(kAnsi2WideTests[i].ansi,
+                             strlen(kAnsi2WideTests[i].ansi));
+    } else {
+      AnsiToWideString(kAnsi2WideTests[i].ansi,
+                       strlen(kAnsi2WideTests[i].ansi),
+                       kAnsi2WideTests[i].cp, &out);
+    }
+    CHK(out == kAnsi2WideTests[i].wide);
+  }
+  return true;
+}
+#endif
+
+TEST(StringTest, Show) {
+  ASSERT_STREQ(Show(0), _T("0"));
+  ASSERT_STREQ(Show(1), _T("1"));
+  ASSERT_STREQ(Show(-1), _T("-1"));
+}
+
+
+// Test international strings.
+TEST(StringTest, International) {
+  CString tabs_by_lang[] = {
+      _T("Web    Prente    Groepe    Gids    "),                    // Afrikaans
+      _T("Web    Fotografitë    Grupet    Drejtoriumi    "),        // Albanian
+      // Amharic is missing, that doesn't show in normal windows fonts
+      _T("ويب    صور    مجموعات    الدليل     "),                    // Arabic
+      _T("Web   Şəkillər   Qruplar   Qovluq   "),                   // Azerbaijani
+      _T("Web   Irudiak   Taldeak   Direktorioa   "),               // Basque
+      _T("Ўэб    Малюнкі    Групы    Каталёг    "),                 // Belarusian
+      _T("Antorjal    Chitraboli    Gosthi    Bishoy-Talika    "),  // Bengali
+      _T("MakarJal    Chhaya    Jerow    Nirdeshika    "),          // Bihari
+      _T("Veb   Imeges   Gruoops   Durectury "),                    // Bork
+      _T("Internet    Slike    Grupe    Katalog    "),              // Bosnian
+      _T("Gwiad    Skeudennoù    Strolladoù    Roll    "),          // Breton
+      _T("Мрежата    Изображения    Групи    Директория    "),      // Bulgarian
+      _T("Web    Imatges    Grups    Directori    "),               // Catalan
+      _T("所有网站    图像    网上论坛    网页目录    "),                            // Chinese Simplified
+      _T("所有網頁    圖片    網上論壇    網頁目錄     "),                            // Chinese Traditional
+      _T("Web    Slike    Grupe    Imenik    "),                    // Croatian
+      _T("Web    Obrázky    Skupiny    Adresář    "),               // Czech
+      _T("Nettet    Billeder    Grupper    Katalog    "),           // Danish
+      _T("Het Internet    Afbeeldingen    Discussiegroepen    Gids    "),  // Dutch
+      _T("Web    Images    Gwoups    Diwectowy    "),               // Elmer
+      _T("Web    Images    Groups    News    Froogle    more »"),   // English
+      _T("TTT    Bildoj    Grupoj    Katalogo     "),               // Esperanto
+      _T("Veeb    Pildid    Grupid    Kataloog    "),               // Estonian
+      _T("Netið    Myndir    Bólkar    Øki    "),                   // Faroese
+      _T("Web    Mga Larawan    Mga Grupo    Direktoryo    "),      // Filipino
+      _T("Web    Kuvat    Keskusteluryhmät    Hakemisto    "),      // Finnish
+      _T("Web    Images    Groupes    Annuaire    Actualités    "),  // French
+      _T("Web   Printsjes   Diskusjegroepen   Directory   "),       // Frisian
+      _T("Web    Imaxes    Grupos    Directorio    "),              // Galician
+      _T("ინტერნეტი   სურათები   ჯგუფები   კატალოგი   "),                      // Georgian
+      _T("Web    Bilder    Groups    Verzeichnis    News    "),     // German
+      _T("Ιστός    Eικόνες    Ομάδες    Κατάλογος    "),            // Greek
+      _T("Ñanduti   Ta'anga   Atypy   Sãmbyhypy "),                 // Guarani
+      _T("jalu    Chhabi    Sangathan    Shabdakosh    "),          // Gujarati
+      _T("n0rM4L s33rCh    1|\\/|4935    6r00pZ    d1r3c70rY    "),  // Hacker
+      _T("אתרים ברשת    תמונות    קבוצות דיון    מדריך האתרים     "),  // Hebrew
+      _T("वेब    छवियाँ    समूह    निर्देशिका    "),                             // Hindi
+      _T("Web    Képek    Csoportok    Címtár    "),                // Hungarian
+      _T("Vefur    Myndir    Hópar    Flokkar    "),                // Icelandic
+      _T("Web    Gambar    Grup    Direktori    "),                 // Indonesian
+      _T("Web    Imagines    Gruppos    Catalogo  "),               // Interlingua
+      _T("An Gréasán    Íomhánna    Grúpaí    Eolaire    "),        // Irish
+      _T("Web    Immagini    Gruppi    Directory    News Novità!    "),  // Italian
+      _T("ウェブ    イメージ    グループ    ディレクトリ    "),                        // Japanese
+      _T("Web    Gambar - gambar    Paguyuban    Bagian    "),      // Javanese
+      _T("antharajAla    chitragaLu    gumpugaLu    Huduku vibhaagagaLu    "),  // Kannada
+      _T("Daqmey pat    naghmey beQ    ghommey    mem    "),        // Klingon
+      _T("웹 문서    이미지    뉴스그룹    디렉토리    "),                            // Klingon
+      _T("Желе   Суроттор   Группалар   Тизме   "),                 // Kyrgyz
+      _T("Tela   Imagines   Circuli   Index "),                     // Latin
+      _T("Internets    Attēli    Vēstkopas    Katalogs"),           // Latvian
+      _T("Internetas    Vaizdai    Grupės    Katalogas    "),       // Lithuanian
+      _T("Мрежа    Слики    Групи    Директориум    "),             // Macedonian
+      _T("Jaringan    Imej    Kumpulan    Direktori    "),          // Malay
+      _T("വെബ്    ചിത്രങ്ങള്    സംഘങ്ങള്    ഡയറക്ടറി    "),                     // Malayalam
+      _T("Web    Stampi    Gruppi    Direttorju    "),              // Maltese
+      _T("वेबशोध    चित्रशोध    ग्रूप्स    डिरेक्टरी    "),                          // Marathi
+      _T("वेब    तस्वीर    समूह    डाइरेक्टरी    "),                            // Nepali
+      _T("Nett    Bilder    Grupper    Katalog    "),               // Norwegian
+      _T("Veven    Bilete    Grupper    Katalog    "),              // Norwegian (Nynorsk)
+      _T("Ret    Imatges    Grops    Directori    "),               // Occitan
+      _T("web   chitra   goSThi   prasanga tAlikA "),               // Oriya
+      _T("وب    تصويرها    گروهها    فهرست     "),                  // Persian
+      _T("ebway    imagesyay    oupsgray    Irectoryday    "),      // P. Latin
+      _T("WWW    Grafika    Grupy dyskusyjne    Katalog   "),       // Polish
+      _T("Web    Imagens    Grupos    Diretório    "),              // Potruguese (Brazil)
+      _T("Web    Imagens    Grupos    Directório  "),               // Potruguese (Portugal)
+      _T("Web/Zaal    Tasveraan    Gutt    Directory    "),         // Punjabi
+      _T("Web    Imagini    Grupuri    Director    "),              // Romanian
+      _T("Веб    Картинки    Группы    Каталог  "),                 // Russian
+      _T("Lìon    Dealbhan    Cuantail    Eòlaire    "),            // Scots Gaelic
+      _T("Интернет    Слике    Групе    Каталог    "),              // Serbian
+      _T("Internet    Slike    Grupe    Spisak    "),               // Serbo-Croatian
+      _T("Web   Ponahalo   Dihlopha   Tshupetso "),                 // Sesotho
+      _T("WEB    Roopa    Kandayam    Namawaliya    "),             // Sinhalese
+      _T("Web    Obrázky    Skupiny    Katalóg    "),               // Slovak
+      _T("Internet    Slike    Skupine    Imenik    "),             // Slovenian
+      _T("La Web    Imágenes    Grupos    Directorio    News ¡Nuevo!    "),  // Spanish
+      _T("Web   Gambar   Grup   Direktori "),                       // Sudanese
+      _T("Mtandao    Picha    Vikundi    Orodha    "),              // Swahili
+      _T("Nätet    Bilder    Grupper    Kategori    "),             // Swedish
+      _T("வலை    படங்கள்    குழுக்கள்    விபரக்கோவை    "),          // Tamil
+      _T("వెబ్    చిత్రాలు    సమూహములు    darshini    "),                        // Telugu
+      _T("เว็บ    รูปภาพ    กลุ่มข่าว    สารบบเว็บ    "),                            // Thai
+      // Tigrinya is missing, that doesn't show in normal windows fonts
+      _T("Web    Grafikler    Gruplar    Dizin    "),               // Turkish
+      _T("Web   Suratlar   Toparlar   Düzine "),                    // Turkmen
+      _T("tintan   Nfonyin   Akuokuo   Krataa nhwemu "),            // Twi
+      _T("Веб    Зображення    Групи    Каталог    "),              // Ukrainian
+      _T("ويب    تصاوير    گروہ    فہرست         ")                           // Urdu
+      _T("To'r    Tasvirlar    Gruppalar    Papka    "),            // Uzbek
+      _T("Internet    Hình Ảnh    Nhóm    Thư Mục    "),            // Vietnamese
+      _T("Y We    Lluniau    Grwpiau    Cyfeiriadur    "),          // Welsh
+      _T("Web   Imifanekiso   Amaqela   Isilawuli "),               // Xhosa
+      _T("װעב    בילדער    גרופּעס    פּאַפּקע     "),                  // Yiddish
+      _T("I-web   Izithombe   Amaqembu   Uhlu lwamafayela   "),     // Zulu
+  };
+
+  int i = 0;
+  for(i = 0; i < arraysize(tabs_by_lang); ++i) {
+    // Get the cannonical lower version with ::CharLower
+    CString true_lower(tabs_by_lang[i]);
+    ::CharLower(true_lower.GetBuffer());
+    true_lower.ReleaseBuffer();
+
+    // Get the lower version with String_ToLower,
+    CString low_temp(tabs_by_lang[i]);
+    String_ToLower(low_temp.GetBuffer());
+    low_temp.ReleaseBuffer();
+
+    // make sure they match
+    ASSERT_STREQ(low_temp, true_lower);
+
+    // Now make sure they match letter by letter
+    for(int j = 0; j < tabs_by_lang[i].GetLength(); ++j) {
+      TCHAR cur_char = tabs_by_lang[i].GetAt(j);
+
+      TCHAR low1 = static_cast<TCHAR>(String_ToLowerChar(cur_char));
+
+      ASSERT_EQ(low1, true_lower.GetAt(j));
+      ASSERT_EQ(Char_ToLower(cur_char), true_lower.GetAt(j));
+
+      // Check the Ansi version if applicable
+      if (cur_char < 128)
+        ASSERT_EQ(String_ToLowerChar(static_cast<char>(cur_char)),
+                  true_lower.GetAt(j));
+    }
+
+    // Test out the CString conversion
+    CString temp(tabs_by_lang[i]);
+    MakeLowerCString(temp);
+    ASSERT_STREQ(temp, true_lower);
+
+    // Test out the fast version
+    temp = tabs_by_lang[i];
+    String_FastToLower(temp.GetBuffer());
+    temp.ReleaseBuffer();
+
+    ASSERT_STREQ(temp, true_lower);
+
+    // Make sure that the normal CString::Trim works the same as our fast one
+    CString trim_normal(tabs_by_lang[i]);
+    trim_normal.Trim();
+
+    CString trim_fast(tabs_by_lang[i]);
+    TrimCString(trim_fast);
+
+    ASSERT_STREQ(trim_normal, trim_fast);
+  }
+}
+
+void TestReplaceString (TCHAR *src, TCHAR *from, TCHAR *to, TCHAR *expected) {
+  ASSERT_TRUE(expected);
+  ASSERT_TRUE(to);
+  ASSERT_TRUE(from);
+  ASSERT_TRUE(src);
+
+  size_t new_src_size = _tcslen(src) + 1;
+  TCHAR* new_src = new TCHAR[new_src_size];
+
+  _tcscpy_s(new_src, new_src_size, src);
+
+  Timer tchar (false);
+  Timer tchar2 (false);
+  Timer cstring (false);
+  Timer orig_cstring (false);
+
+  // int iterations = 10000;
+  int iterations = 10;
+
+  int out_len;
+  TCHAR *out;
+
+  for (int i = 0; i < iterations; i++) {
+      _tcscpy_s(new_src, new_src_size, src);
+      bool created_new_string = false;
+
+      tchar.Start();
+      ReplaceString (new_src, from, to, &out, &out_len);
+      tchar.Stop();
+
+      ASSERT_STREQ(out, expected);
+      delete [] out;
+  }
+
+  for (int i = 0; i < iterations; i++) {
+      _tcscpy_s(new_src, new_src_size, src);
+      bool created_new_string = false;
+
+      tchar2.Start();
+      ReplaceStringMaybeInPlace (new_src, from, to, &out,
+                                 &out_len, &created_new_string);
+      tchar2.Stop();
+
+      ASSERT_STREQ(out, expected);
+      if (out != new_src) { delete [] out; }
+  }
+
+  for (int i = 0; i < iterations; i++) {
+      CString src_string(src);
+
+      orig_cstring.Start();
+      src_string.Replace (from, to);
+      orig_cstring.Stop();
+
+      ASSERT_STREQ(src_string, CString(expected));
+  }
+
+  for (int i = 0; i < iterations; i++) {
+      CString src_string(src);
+
+      cstring.Start();
+      ReplaceCString (src_string, from, to);
+      cstring.Stop();
+
+      ASSERT_STREQ(src_string, CString(expected));
+  }
+
+  delete [] new_src;
+}
+
+TEST(StringTest, ReplaceCString) {
+  CString t;
+  t = _T("a a a b ");
+  ReplaceCString(t, _T("a"), 1, _T("d"), 1, 5);
+  ASSERT_STREQ(_T("d d d b "), t);
+
+  t = _T("a a a b ");
+  ReplaceCString(t, _T("b"), 1, _T("d"), 1, 5);
+  ASSERT_STREQ(_T("a a a d "), t);
+
+  t = _T("a a a b ");
+  ReplaceCString(t, _T("a"), 1, _T("d"), 1, 1);
+  ASSERT_STREQ(_T("d a a b "), t);
+
+  t = _T("a a a b ");
+  ReplaceCString(t, _T("a"), 1, _T("dd"), 2, 5);
+  ASSERT_STREQ(_T("dd dd dd b "), t);
+
+  ReplaceCString(t, _T("dd"), 2, _T("dddd"), 4, 5);
+  ASSERT_STREQ(_T("dddd dddd dddd b "), t);
+
+  ReplaceCString(t, _T("dd"), 2, _T("dddd"), 4, 5);
+  ASSERT_STREQ(_T("dddddddd dddddddd dddddd b "), t);
+
+  ReplaceCString(t, _T("dddddddd"), 8, _T("dddd"), 4, 2);
+  ASSERT_STREQ(_T("dddd dddd dddddd b "), t);
+
+  ReplaceCString(t, _T("d"), 1, _T("a"), 1, 2);
+  ASSERT_STREQ(_T("aadd dddd dddddd b "), t);
+
+  ReplaceCString(t, _T("d d"), 3, _T("c"), 1, 2);
+  ASSERT_STREQ(_T("aadcddcddddd b "), t);
+
+  ReplaceCString(t, _T("c"), 1, _T("1234567890"), 10, 2);
+  ASSERT_STREQ(_T("aad1234567890dd1234567890ddddd b "), t);
+
+  ReplaceCString(t, _T("1"), 1, _T("1234567890"), 10, 2);
+  ASSERT_STREQ(_T("aad1234567890234567890dd1234567890234567890ddddd b "), t);
+
+  ReplaceCString(t, _T("1234567890"), 10, _T(""), 0, 2);
+  ASSERT_STREQ(_T("aad234567890dd234567890ddddd b "), t);
+
+  t = _T("a aa aa b ");
+  ReplaceCString(t, _T("aa"), 2, _T("b"), 1, 5);
+  ASSERT_STREQ(_T("a b b b "), t);
+
+  t = _T("moo a aa aa b ");
+  ReplaceCString(t, _T("aa"), 2, _T("b"), 1, 5);
+  ASSERT_STREQ(_T("moo a b b b "), t);
+
+  // Time to test some big strings
+  int test_sizes[] = {200, 500, 900, 10000};
+
+  int i;
+  for(i = 0; i < arraysize(test_sizes); ++i) {
+    CString in, out;
+    for(int j = 0; j < test_sizes[i]; ++j) {
+      in += L'a';
+      out += _T("bb");
+    }
+    CString bak_in(in);
+
+    // Make it a bit bigger
+    int times = ReplaceCString(in, _T("a"), 1, _T("bb"), 2, kRepMax);
+    ASSERT_EQ(times, test_sizes[i]);
+    ASSERT_EQ(out, in);
+
+    // Make it bigger still
+    times = ReplaceCString(in, _T("bb"), 2, _T("ccc"), 3, kRepMax);
+    ASSERT_EQ(times, test_sizes[i]);
+
+    // Same size swap
+    times = ReplaceCString(in, _T("c"), 1, _T("d"), 1, kRepMax);
+    ASSERT_EQ(times, test_sizes[i] * 3);
+
+    // Make it smaller again
+    times = ReplaceCString(in, _T("ddd"), 3, _T("a"), 1, kRepMax);
+    ASSERT_EQ(times, test_sizes[i]);
+    ASSERT_EQ(bak_in, in);
+  }
+}
+
+TEST(StringTest, GetField) {
+  CString s(_T("<a>a</a><b>123</b><c>aa\ndd</c>"));
+
+  CString a(GetField (s, L"a"));
+  ASSERT_STREQ(a, L"a");
+
+  CString b(GetField (s, L"b"));
+  ASSERT_STREQ(b, L"123");
+
+  CString c(GetField (s, L"c"));
+  ASSERT_STREQ(c, L"aa\ndd");
+}
+
+TEST(StringTest, String_HasAlphabetLetters) {
+  ASSERT_TRUE(String_HasAlphabetLetters (L"abc"));
+  ASSERT_TRUE(String_HasAlphabetLetters (L"X"));
+  ASSERT_TRUE(String_HasAlphabetLetters (L" pie "));
+  ASSERT_FALSE(String_HasAlphabetLetters (L"1"));
+  ASSERT_FALSE(String_HasAlphabetLetters (L"0"));
+  ASSERT_FALSE(String_HasAlphabetLetters (L"010"));
+  ASSERT_FALSE(String_HasAlphabetLetters (L"314-159"));
+  ASSERT_TRUE(String_HasAlphabetLetters (L"pie0"));
+}
+
+TEST(StringTest, String_LargeIntToApproximateString) {
+  int power;
+  ASSERT_TRUE(String_LargeIntToApproximateString(10LL, true, &power) == _T("10") && power == 0);
+  ASSERT_TRUE(String_LargeIntToApproximateString(99LL, true, &power) == _T("99") && power == 0);
+  ASSERT_TRUE(String_LargeIntToApproximateString(990LL, true, &power) == _T("990") && power == 0);
+  ASSERT_TRUE(String_LargeIntToApproximateString(999LL, true, &power) == _T("999") && power == 0);
+
+  ASSERT_TRUE(String_LargeIntToApproximateString(1000LL, true, &power) == _T("1.0") && power == 1);
+  ASSERT_TRUE(String_LargeIntToApproximateString(1200LL, true, &power) == _T("1.2") && power == 1);
+  ASSERT_TRUE(String_LargeIntToApproximateString(7500LL, true, &power) == _T("7.5") && power == 1);
+  ASSERT_TRUE(String_LargeIntToApproximateString(9900LL, true, &power) == _T("9.9") && power == 1);
+  ASSERT_TRUE(String_LargeIntToApproximateString(10000LL, true, &power) == _T("10") && power == 1);
+  ASSERT_TRUE(String_LargeIntToApproximateString(11000LL, true, &power) == _T("11") && power == 1);
+  ASSERT_TRUE(String_LargeIntToApproximateString(987654LL, true, &power) == _T("987") && power == 1);
+
+  ASSERT_TRUE(String_LargeIntToApproximateString(1000000LL, true, &power) == _T("1.0") && power == 2);
+  ASSERT_TRUE(String_LargeIntToApproximateString(1300000LL, true, &power) == _T("1.3") && power == 2);
+  ASSERT_TRUE(String_LargeIntToApproximateString(987654321LL, true, &power) == _T("987") && power == 2);
+
+  ASSERT_TRUE(String_LargeIntToApproximateString(1000000000LL, true, &power) == _T("1.0") && power == 3);
+  ASSERT_TRUE(String_LargeIntToApproximateString(1999999999LL, true, &power) == _T("1.9") && power == 3);
+  ASSERT_TRUE(String_LargeIntToApproximateString(20000000000LL, true, &power) == _T("20") && power == 3);
+  ASSERT_TRUE(String_LargeIntToApproximateString(1000000000000LL, true, &power) == _T("1000") && power == 3);
+  ASSERT_TRUE(String_LargeIntToApproximateString(12345678901234LL, true, &power) == _T("12345") && power == 3);
+
+  ASSERT_TRUE(String_LargeIntToApproximateString(1023LL, false, &power) == _T("1023") && power == 0);
+
+  ASSERT_TRUE(String_LargeIntToApproximateString(1024LL, false, &power) == _T("1.0") && power == 1);
+  ASSERT_TRUE(String_LargeIntToApproximateString(1134LL, false, &power) == _T("1.1") && power == 1);
+  ASSERT_TRUE(String_LargeIntToApproximateString(10240LL, false, &power) == _T("10") && power == 1);
+
+  ASSERT_TRUE(String_LargeIntToApproximateString(5242880LL, false, &power) == _T("5.0") && power == 2);
+
+  ASSERT_TRUE(String_LargeIntToApproximateString(1073741824LL, false, &power) == _T("1.0") && power == 3);
+  ASSERT_TRUE(String_LargeIntToApproximateString(17179869184LL, false, &power) == _T("16") && power == 3);
+}
+
+TEST(StringTest, FindWholeWordMatch) {
+  // words with spaces before / after
+  ASSERT_EQ(0, FindWholeWordMatch (L"pi", L"pi", false, 0));
+  ASSERT_EQ(1, FindWholeWordMatch (L" pi", L"pi", false, 0));
+  ASSERT_EQ(1, FindWholeWordMatch (L" pi ", L"pi", false, 0));
+  ASSERT_EQ(0, FindWholeWordMatch (L"pi ", L"pi", false, 0));
+
+  // partial matches
+  ASSERT_EQ(-1, FindWholeWordMatch (L"pie ", L"pi", false, 0));
+  ASSERT_EQ(-1, FindWholeWordMatch (L" pie ", L"pi", false, 0));
+  ASSERT_EQ(-1, FindWholeWordMatch (L"pie", L"pi", false, 0));
+  ASSERT_EQ(-1, FindWholeWordMatch (L" pie", L"pi", false, 0));
+
+  // partial match with non-alphanumeric chars
+  ASSERT_EQ(-1, FindWholeWordMatch (L" pumpkin_pie ", L"pie", false, 0));
+  ASSERT_EQ(-1, FindWholeWordMatch (L" pie_crust ", L"pie", false, 0));
+  ASSERT_EQ(-1, FindWholeWordMatch (L"tartar", L"tar", false, 0));
+  ASSERT_EQ(-1, FindWholeWordMatch (L"pie!", L"pie", false, 0));
+}
+
+TEST(StringTest, ReplaceWholeWord) {
+  CString str (L"pie");
+  ReplaceWholeWord (L"ie", L"..", false, &str);
+  ASSERT_STREQ(str, L"pie");
+
+  ReplaceWholeWord (L"pie", L"..", false, &str);
+  ASSERT_STREQ(str, L"..");
+
+  str = L"banana pie";
+  ReplaceWholeWord (L"pie", L"..", false, &str);
+  ASSERT_STREQ(str, L"banana ..");
+
+  str = L"banana pie";
+  ReplaceWholeWord (L"banana", L"..", false, &str);
+  ASSERT_STREQ(str, L".. pie");
+
+  str = L"banana pie";
+  ReplaceWholeWord (L"banana pie", L" .. ", false, &str);
+  ASSERT_STREQ(str, L" .. ");
+
+  str = L"banana pie";
+  ReplaceWholeWord (L"pi", L" .. ", false, &str);
+  ASSERT_STREQ(str, L"banana pie");
+
+  str = L"ishniferatsu";
+  ReplaceWholeWord (L"era", L" .. ", false, &str);
+  ASSERT_STREQ(str, L"ishniferatsu");
+
+  str = L"i i i hi ii i";
+  ReplaceWholeWord (L"i", L"you", false, &str);
+  ASSERT_STREQ(str, L"you you you hi ii you");
+
+  str = L"a nice cream cheese pie";
+  ReplaceWholeWord (L"cream cheese", L"..", false, &str);
+  ASSERT_STREQ(str, L"a nice .. pie");
+
+  // ---
+  // Test replacement with whitespace trimming
+
+  // Replace in the middle of the string.
+  str = L"a nice cream cheese pie";
+  ReplaceWholeWord (L"cream cheese", L"..", true, &str);
+  ASSERT_STREQ(str, L"a nice..pie");
+
+  // Replace in the beginning of the string.
+  str = L"a nice cream cheese pie";
+  ReplaceWholeWord (L"a nice", L"..", true, &str);
+  ASSERT_STREQ(str, L"..cream cheese pie");
+
+  // Replace in the end of the string.
+  str = L"a nice cream cheese pie";
+  ReplaceWholeWord (L"pie", L"..", true, &str);
+  ASSERT_STREQ(str, L"a nice cream cheese..");
+}
+
+
+TEST(StringTest, TestReplaceString) {
+  // timing for replace string, for the specific tests below shows:
+  //
+  // the TCHAR version is always faster than CRT CString::Replace
+  //
+  // the CString version is faster than CRT CString::Replace:
+  // - always if the replacement is shorter
+  // - if the source string is longer than ~60 characters if the replacement is
+  //   longer
+  //
+  // based on our current usage of CString::Replace, I expect the new CString
+  // version is faster on average than CRT CString::Replace
+  //
+  // non-CRT CString::Replace is much slower, so all of these should be much
+  // faster than that
+
+  TestReplaceString(L"that's what i changed -it was propagating the error code but i ..", L" .. ", L"<b> .. </b>", L"that's what i changed -it was propagating the error code but i ..");
+  TestReplaceString(L"news.com.url", L".url", L"", L"news.com");
+  TestReplaceString(L"news.com..url", L".url", L"", L"news.com.");
+  TestReplaceString(L"news.com.u.url", L".url", L"", L"news.com.u");
+  TestReplaceString(L"abanana pie banana", L"banana", L"c", L"ac pie c");
+  TestReplaceString(L"bananabananabanana", L"banana", L"c", L"ccc");
+  TestReplaceString(L"abanana pie banana", L"banana", L"cabanapie", L"acabanapie pie cabanapie");
+  TestReplaceString(L"bananabananabanana", L"banana", L"cabanapie", L"cabanapiecabanapiecabanapie");
+  TestReplaceString(L"banana pie banana pie", L"banana", L"c", L"c pie c pie");
+  TestReplaceString(L"banana pie banana pie", L"pie", L"z", L"banana z banana z");
+  TestReplaceString(L"banana pie banana pie", L"banana", L"bananacabana", L"bananacabana pie bananacabana pie");
+  TestReplaceString(L"banana pie banana pie", L"pie", L"pietie", L"banana pietie banana pietie");
+  TestReplaceString(L"banana pie banana pie", L"tie", L"pietie", L"banana pie banana pie");
+  TestReplaceString(L"banana pie banana pie banana pie banana pie banana pie", L"banana", L"bananacab", L"bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie");
+  TestReplaceString(L"banana pie banana pie banana pie banana pie banana pie banana pie banana pie", L"banana", L"bananacab", L"bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie");
+  TestReplaceString(L"banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie", L"banana", L"bananacab", L"bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie");
+  TestReplaceString(L"banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie", L"banana", L"bananacab", L"bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie bananacab pie");
+  TestReplaceString(L"banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie", L"banana", L"cab", L"cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie cab pie");
+  TestReplaceString(L"news", L"news", L"", L"");
+  TestReplaceString(L"&nbsp;", L"&nbsp;", L"", L"");
+  TestReplaceString(L"&nbsp;&nbsp;&nbsp;", L"&nbsp;", L"", L"");
+  TestReplaceString(L"&nbsp; &nbsp;&nbsp;", L"&nbsp;", L"", L" ");
+}
+
+
+TEST(StringTest, GetAbsoluteUri) {
+  ASSERT_STREQ(GetAbsoluteUri(L"http://www.google.com"),
+               L"http://www.google.com/");
+  ASSERT_STREQ(GetAbsoluteUri(L"http://www.google.com/"),
+               L"http://www.google.com/");
+  ASSERT_STREQ(GetAbsoluteUri(L"http://www.google.com//"),
+               L"http://www.google.com/");
+  ASSERT_STREQ(GetAbsoluteUri(L"http://www.google.com/test"),
+               L"http://www.google.com/test");
+}
+
+void TestTrim(const TCHAR *str, const TCHAR *result) {
+  ASSERT_TRUE(result);
+  ASSERT_TRUE(str);
+
+  size_t ptr_size = _tcslen(str) + 1;
+  TCHAR* ptr = new TCHAR[ptr_size];
+  _tcscpy_s(ptr, ptr_size, str);
+
+  int len = Trim(ptr);
+  ASSERT_STREQ(ptr, result);
+  ASSERT_EQ(len, lstrlen(result));
+
+  delete [] ptr;
+}
+
+TEST(StringTest, Trim) {
+  TestTrim(L"", L"");
+  TestTrim(L" ", L"");
+  TestTrim(L"\t", L"");
+  TestTrim(L"\n", L"");
+  TestTrim(L"\n\t    \t \n", L"");
+  TestTrim(L"    joe", L"joe");
+  TestTrim(L"joe      ", L"joe");
+  TestTrim(L"    joe      ", L"joe");
+  TestTrim(L"joe smith    ", L"joe smith");
+  TestTrim(L"     joe smith    ", L"joe smith");
+  TestTrim(L"     joe   smith    ", L"joe   smith");
+  TestTrim(L"     The quick brown fox,\tblah", L"The quick brown fox,\tblah");
+  TestTrim(L" \tblah\n    joe smith    ", L"blah\n    joe smith");
+}
+
+// IsSpaceA1 is much faster without the cache clearing (which is what happends
+// in release mode)
+// IsSpaceA1 is roughly the same speed as IsSpaceA2 with cache clearing (in
+// debug mode)
+// IsSpaceA3 is always much slower
+
+static const byte spacesA[256] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  // 0-9
+  1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 10-19
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 20-29
+  0, 0, 1, 0, 0, 0, 0, 0, 0, 0,  // 30-39
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 40-49
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 50-59
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 60-69
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 70-79
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 80-89
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 90-99
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 100-109
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 110-119
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 120-129
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 130-139
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 140-149
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 150-159
+  1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 160-169
+};
+
+bool IsSpaceA1(char c) {
+  return spacesA[c] == 1;
+}
+
+bool IsSpaceA2(char c) {
+  // return (c==32);
+  // if (c>32) { return 0; }
+  // most characters >32, check first for that case
+  if (c>32 && c!=160) { return 0; }
+  if (c==32) { return 1; }
+  if (c>=9&&c<=13) return 1; else return 0;
+}
+
+bool IsSpaceA3(char c) {
+  WORD result;
+  if (GetStringTypeA(0, CT_CTYPE1, &c, 1, &result)) {
+    return (0 != (result & C1_SPACE));
+  }
+  return false;
+}
+
+void TestIsSpace (char *s) {
+    ASSERT_TRUE(s);
+
+    Timer t1 (false);
+    Timer t2 (false);
+    Timer t3 (false);
+
+    // int iterations = 10000;
+    int iterations = 100;
+    int len = strlen (s);
+
+    // used to try to clear the processor cache
+    int dlen = 100000;
+    char *dummy = new char [dlen];
+    for (int i = 0; i < dlen; i++) {
+      dummy[i] = static_cast<char>(tr_rand() % 256);
+    }
+
+    int num_spaces = 0;
+    int n = iterations * len;
+    for (int i = 0; i < iterations; i++) {
+        t1.Start();
+        for (int j = 0; j < len; j++) {
+            num_spaces += IsSpaceA1 (s[j]);
+        }
+        t1.Stop();
+        // this cache clearing code gets optimized out in release mode
+        int d2 = 0;
+        for (int i = 0; i < dlen; i++) { d2 += dummy[i]; }
+    }
+
+    num_spaces = 0;
+    for (int i = 0; i < iterations; i++) {
+        t2.Start();
+        for (int j = 0; j < len; j++) {
+            num_spaces += IsSpaceA2 (s[j]);
+        }
+        t2.Stop();
+        int d2 = 0;
+        for (int i = 0; i < dlen; i++) { d2 += dummy[i]; }
+    }
+
+    num_spaces = 0;
+    for (int i = 0; i < iterations; i++) {
+        t3.Start();
+        for (int j = 0; j < len; j++) {
+            num_spaces += IsSpaceA3 (s[j]);
+        }
+        t3.Stop();
+        int d2 = 0;
+        for (int i = 0; i < dlen; i++) { d2 += dummy[i]; }
+    }
+}
+
+TEST(StringTest, IsSpace) {
+  TestIsSpace("banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie banana pie");
+  TestIsSpace("sdlfhdkgheorutsgj sdlj aoi oaj gldjg opre gdsfjng oate yhdnv ;zsj fpoe v;kjae hgpaieh dajlgn aegh avn WEIf h9243y 9814cu 902t7 9[-32 [O8W759 RC90817 V9pDAHc n( ny(7LKFJAOISF *&^*^%$$%#*&^(*_*)_^& 67% 796%&$*^$ 8)6 (^ 08&^ )*^ 9-7=90z& +(^ )^* %9%4386 $& (& &+ 7- &(_* ");
+}
+
+void TestCleanupWhitespace(const TCHAR *str, const TCHAR *result) {
+  ASSERT_TRUE(result);
+  ASSERT_TRUE(str);
+
+  size_t ptr_size = _tcslen(str) + 1;
+  TCHAR* ptr = new TCHAR[ptr_size];
+  _tcscpy_s(ptr, ptr_size, str);
+
+  int len = CleanupWhitespace(ptr);
+  ASSERT_STREQ(ptr, result);
+  ASSERT_EQ(len, lstrlen(result));
+
+  delete [] ptr;
+}
+
+TEST(StringTest, CleanupWhitespace) {
+  TestCleanupWhitespace(L"", L"");
+  TestCleanupWhitespace(L"a    ", L"a");
+  TestCleanupWhitespace(L"    a", L"a");
+  TestCleanupWhitespace(L" a   ", L"a");
+  TestCleanupWhitespace(L"\t\n\r a   ", L"a");
+  TestCleanupWhitespace(L"  \n   a  \t   \r ", L"a");
+  TestCleanupWhitespace(L"a      b", L"a b");
+  TestCleanupWhitespace(L"   a \t\n\r     b", L"a b");
+  TestCleanupWhitespace(L"   vool                 voop", L"vool voop");
+  TestCleanupWhitespace(L"thisisaverylongstringwithsometext",
+                        L"thisisaverylongstringwithsometext");
+  TestCleanupWhitespace(L"thisisavery   longstringwithsometext",
+                        L"thisisavery longstringwithsometext");
+}
+
+void TestWcstoul (TCHAR *string, int radix, unsigned long expected) {
+    ASSERT_TRUE(string);
+
+    wchar_t *ptr;
+    int v = Wcstoul (string, &ptr, radix);
+    ASSERT_EQ(v, expected);
+
+#ifdef DEBUG
+    int v2 = wcstoul (string, &ptr, radix);
+    ASSERT_EQ(v, v2);
+#endif
+}
+
+TEST(StringTest, Wcstoul) {
+  TestWcstoul(L"625", 16, 1573);
+  TestWcstoul(L" 625", 16, 1573);
+  TestWcstoul(L"a3", 16, 163);
+  TestWcstoul(L"A3", 16, 163);
+  TestWcstoul(L"  A3", 16, 163);
+  TestWcstoul(L" 12445", 10, 12445);
+  TestWcstoul(L"12445778", 10, 12445778);
+}
+
+TEST(StringTest, IsDigit) {
+  ASSERT_TRUE(String_IsDigit('0'));
+  ASSERT_TRUE(String_IsDigit('1'));
+  ASSERT_TRUE(String_IsDigit('2'));
+  ASSERT_TRUE(String_IsDigit('3'));
+  ASSERT_TRUE(String_IsDigit('4'));
+  ASSERT_TRUE(String_IsDigit('5'));
+  ASSERT_TRUE(String_IsDigit('6'));
+  ASSERT_TRUE(String_IsDigit('7'));
+  ASSERT_TRUE(String_IsDigit('8'));
+  ASSERT_TRUE(String_IsDigit('9'));
+  ASSERT_FALSE(String_IsDigit('a'));
+  ASSERT_FALSE(String_IsDigit('b'));
+  ASSERT_FALSE(String_IsDigit('z'));
+  ASSERT_FALSE(String_IsDigit('A'));
+  ASSERT_FALSE(String_IsDigit(' '));
+  ASSERT_FALSE(String_IsDigit('#'));
+}
+
+TEST(StringTest, IsUpper) {
+  ASSERT_FALSE(String_IsUpper('0'));
+  ASSERT_FALSE(String_IsUpper(' '));
+  ASSERT_FALSE(String_IsUpper('#'));
+  ASSERT_FALSE(String_IsUpper('a'));
+  ASSERT_FALSE(String_IsUpper('z'));
+  ASSERT_TRUE(String_IsUpper('A'));
+  ASSERT_TRUE(String_IsUpper('B'));
+  ASSERT_TRUE(String_IsUpper('C'));
+  ASSERT_TRUE(String_IsUpper('D'));
+  ASSERT_TRUE(String_IsUpper('H'));
+  ASSERT_TRUE(String_IsUpper('Y'));
+  ASSERT_TRUE(String_IsUpper('Z'));
+}
+
+TEST(StringTest, StringToDouble) {
+  ASSERT_DOUBLE_EQ(String_StringToDouble(L"625"), 625);
+  ASSERT_DOUBLE_EQ(String_StringToDouble(L"-625"), -625);
+  ASSERT_DOUBLE_EQ(String_StringToDouble(L"-6.25"), -6.25);
+  ASSERT_DOUBLE_EQ(String_StringToDouble(L"6.25"), 6.25);
+  ASSERT_DOUBLE_EQ(String_StringToDouble(L"0.00"), 0);
+  ASSERT_DOUBLE_EQ(String_StringToDouble(L" 55.1"), 55.1);
+  ASSERT_DOUBLE_EQ(String_StringToDouble(L" 55.001"), 55.001);
+  ASSERT_DOUBLE_EQ(String_StringToDouble(L"  1.001"), 1.001);
+}
+
+TEST(StringTest, StringToInt) {
+  ASSERT_EQ(String_StringToInt(L"625"), 625);
+  ASSERT_EQ(String_StringToInt(L"6"), 6);
+  ASSERT_EQ(String_StringToInt(L"0"), 0);
+  ASSERT_EQ(String_StringToInt(L" 122"), 122);
+  ASSERT_EQ(String_StringToInt(L"a"), 0);
+  ASSERT_EQ(String_StringToInt(L" a"), 0);
+}
+
+TEST(StringTest, StringToInt64) {
+  ASSERT_EQ(String_StringToInt64(L"119600064000000000"),
+            119600064000000000uI64);
+  ASSERT_EQ(String_StringToInt64(L" 119600064000000000"),
+            119600064000000000uI64);
+  ASSERT_EQ(String_StringToInt64(L"625"), 625);
+  ASSERT_EQ(String_StringToInt64(L"6"), 6);
+  ASSERT_EQ(String_StringToInt64(L"0"), 0);
+  ASSERT_EQ(String_StringToInt64(L" 122"), 122);
+  ASSERT_EQ(String_StringToInt64(L"a"), 0);
+  ASSERT_EQ(String_StringToInt64(L" a"), 0);
+}
+
+void TestEndWithChar(const TCHAR *s, char c, const TCHAR *expected) {
+  ASSERT_TRUE(expected);
+  ASSERT_TRUE(s);
+
+  TCHAR buf[5000];
+  _tcscpy(buf, s);
+  String_EndWithChar(buf, c);
+  ASSERT_STREQ(buf, expected);
+}
+
+TEST(StringTest, EndWithChar) {
+  TestEndWithChar(L"", L'a', L"a");
+  TestEndWithChar(L"", L'\\', L"\\");
+  TestEndWithChar(L"a", L'a', L"a");
+  TestEndWithChar(L"a", L'b', L"ab");
+  TestEndWithChar(L"abcdefghij", L'a', L"abcdefghija");
+  TestEndWithChar(L"abcdefghij", L'\\', L"abcdefghij\\");
+}
+
+TEST(StringTest, HexDigitToInt) {
+  ASSERT_EQ(HexDigitToInt(L'0'), 0);
+  ASSERT_EQ(HexDigitToInt(L'1'), 1);
+  ASSERT_EQ(HexDigitToInt(L'2'), 2);
+  ASSERT_EQ(HexDigitToInt(L'3'), 3);
+  ASSERT_EQ(HexDigitToInt(L'4'), 4);
+  ASSERT_EQ(HexDigitToInt(L'5'), 5);
+  ASSERT_EQ(HexDigitToInt(L'6'), 6);
+  ASSERT_EQ(HexDigitToInt(L'7'), 7);
+  ASSERT_EQ(HexDigitToInt(L'8'), 8);
+  ASSERT_EQ(HexDigitToInt(L'9'), 9);
+  ASSERT_EQ(HexDigitToInt(L'A'), 10);
+  ASSERT_EQ(HexDigitToInt(L'a'), 10);
+  ASSERT_EQ(HexDigitToInt(L'B'), 11);
+  ASSERT_EQ(HexDigitToInt(L'b'), 11);
+  ASSERT_EQ(HexDigitToInt(L'C'), 12);
+  ASSERT_EQ(HexDigitToInt(L'c'), 12);
+  ASSERT_EQ(HexDigitToInt(L'D'), 13);
+  ASSERT_EQ(HexDigitToInt(L'd'), 13);
+  ASSERT_EQ(HexDigitToInt(L'E'), 14);
+  ASSERT_EQ(HexDigitToInt(L'e'), 14);
+  ASSERT_EQ(HexDigitToInt(L'F'), 15);
+  ASSERT_EQ(HexDigitToInt(L'f'), 15);
+}
+
+TEST(StringTest, IsHexDigit) {
+  ASSERT_TRUE(IsHexDigit(L'0'));
+  ASSERT_TRUE(IsHexDigit(L'1'));
+  ASSERT_TRUE(IsHexDigit(L'2'));
+  ASSERT_TRUE(IsHexDigit(L'3'));
+  ASSERT_TRUE(IsHexDigit(L'4'));
+  ASSERT_TRUE(IsHexDigit(L'5'));
+  ASSERT_TRUE(IsHexDigit(L'6'));
+  ASSERT_TRUE(IsHexDigit(L'7'));
+  ASSERT_TRUE(IsHexDigit(L'8'));
+  ASSERT_TRUE(IsHexDigit(L'9'));
+  ASSERT_TRUE(IsHexDigit(L'a'));
+  ASSERT_TRUE(IsHexDigit(L'A'));
+  ASSERT_TRUE(IsHexDigit(L'b'));
+  ASSERT_TRUE(IsHexDigit(L'B'));
+  ASSERT_TRUE(IsHexDigit(L'c'));
+  ASSERT_TRUE(IsHexDigit(L'C'));
+  ASSERT_TRUE(IsHexDigit(L'd'));
+  ASSERT_TRUE(IsHexDigit(L'D'));
+  ASSERT_TRUE(IsHexDigit(L'e'));
+  ASSERT_TRUE(IsHexDigit(L'E'));
+  ASSERT_TRUE(IsHexDigit(L'f'));
+  ASSERT_TRUE(IsHexDigit(L'F'));
+
+  for(TCHAR digit = static_cast<TCHAR>(127); digit < 10000; ++digit) {
+    ASSERT_FALSE(IsHexDigit(digit));
+  }
+}
+
+TEST(StringTest, Remove) {
+  CString temp_remove;
+
+  // Remove everything
+  temp_remove = _T("ftp://");
+  RemoveFromStart (temp_remove, _T("ftp://"), false);
+  ASSERT_STREQ(temp_remove, _T(""));
+
+  // Remove all but 1 letter
+  temp_remove = _T("ftp://a");
+  RemoveFromStart (temp_remove, _T("ftp://"), false);
+  ASSERT_STREQ(temp_remove, _T("a"));
+
+  // Remove the first instance
+  temp_remove = _T("ftp://ftp://");
+  RemoveFromStart (temp_remove, _T("ftp://"), false);
+  ASSERT_STREQ(temp_remove, _T("ftp://"));
+
+  // Remove normal
+  temp_remove = _T("ftp://taz the tiger");
+  RemoveFromStart (temp_remove, _T("ftp://"), false);
+  ASSERT_STREQ(temp_remove, _T("taz the tiger"));
+
+  // Wrong prefix
+  temp_remove = _T("ftp:/taz the tiger");
+  RemoveFromStart (temp_remove, _T("ftp://"), false);
+  ASSERT_STREQ(temp_remove, _T("ftp:/taz the tiger"));
+
+  // Not long enough
+  temp_remove = _T("ftp:/");
+  RemoveFromStart (temp_remove, _T("ftp://"), false);
+  ASSERT_STREQ(temp_remove, _T("ftp:/"));
+
+  // Remove nothing
+  temp_remove = _T("ftp:/");
+  RemoveFromStart (temp_remove, _T(""), false);
+  ASSERT_STREQ(temp_remove, _T("ftp:/"));
+
+  // Remove 1 character
+  temp_remove = _T("ftp:/");
+  RemoveFromStart (temp_remove, _T("f"), false);
+  ASSERT_STREQ(temp_remove, _T("tp:/"));
+
+  // Wrong case
+  temp_remove = _T("ftp:/");
+  RemoveFromStart (temp_remove, _T("F"), false);
+  ASSERT_STREQ(temp_remove, _T("ftp:/"));
+
+  // Remove everything
+  temp_remove = _T(".edu");
+  RemoveFromEnd (temp_remove, _T(".edu"));
+  ASSERT_STREQ(temp_remove, _T(""));
+
+  // Remove all but 1 letter
+  temp_remove = _T("a.edu");
+  RemoveFromEnd(temp_remove, _T(".edu"));
+  ASSERT_STREQ(temp_remove, _T("a"));
+
+  // Remove the first instance
+  temp_remove = _T(".edu.edu");
+  RemoveFromEnd(temp_remove, _T(".edu"));
+  ASSERT_STREQ(temp_remove, _T(".edu"));
+
+  // Remove normal
+  temp_remove = _T("ftp://taz the tiger.edu");
+  RemoveFromEnd(temp_remove, _T(".edu"));
+  ASSERT_STREQ(temp_remove, _T("ftp://taz the tiger"));
+
+  // Wrong suffix
+  temp_remove = _T("ftp:/taz the tiger.edu");
+  RemoveFromEnd(temp_remove, _T("/edu"));
+  ASSERT_STREQ(temp_remove, _T("ftp:/taz the tiger.edu"));
+
+  // Not long enough
+  temp_remove = _T("edu");
+  RemoveFromEnd(temp_remove, _T(".edu"));
+  ASSERT_STREQ(temp_remove, _T("edu"));
+
+  // Remove nothing
+  temp_remove = _T(".edu");
+  RemoveFromEnd(temp_remove, _T(""));
+  ASSERT_STREQ(temp_remove, _T(".edu"));
+
+  // Remove 1 character
+  temp_remove = _T(".edu");
+  RemoveFromEnd(temp_remove, _T("u"));
+  ASSERT_STREQ(temp_remove, _T(".ed"));
+
+  // Wrong case
+  temp_remove = _T(".edu");
+  RemoveFromEnd(temp_remove, _T("U"));
+  ASSERT_STREQ(temp_remove, _T(".edu"));
+}
+
+TEST(StringTest, WideToAnsiDirect) {
+  CString temp_convert;
+  ASSERT_STREQ("", WideToAnsiDirect(_T("")));
+  ASSERT_STREQ("a", WideToAnsiDirect(_T("a")));
+  ASSERT_STREQ("moon doggy", WideToAnsiDirect(_T("moon doggy")));
+
+  // Generate a string of all characters 0-255.
+  const int kNumChars = 256;
+  TCHAR nasty_chars[kNumChars];
+  for (int i = 0; i < kNumChars; ++i) {
+    nasty_chars[i] = static_cast<TCHAR>(i);
+  }
+  CString temp(nasty_chars, kNumChars);
+
+  // Convert it and make sure it matches.
+  CStringA out = WideToAnsiDirect(temp);
+  ASSERT_EQ(out.GetLength(), kNumChars);
+  for (int i = 0; i < kNumChars; ++i) {
+    ASSERT_EQ(static_cast<unsigned char>(nasty_chars[i]),
+              static_cast<unsigned char>(out.GetAt(i)));
+  }
+}
+
+TEST(StringTest, FindStringASpaceStringB) {
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type: text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-TYPE: text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-TYPE: text/HTML", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-TYPE: text/HTML", L"content-type:", L"text/HTML"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-TYPE: text/HTML", L"content-TYPE:", L"text/HTML"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:  text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:   text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type: sdfjsldkgjsdg content-type:    text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type: content-type: sdfjsldkgjsdg content-type:    text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:content-type: sdfjsldkgjsdg content-type:    text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:content-type:    text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"test/html content-type:content-type:    text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:    text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:\ttext/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:\t text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"Content-Type:\t text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"aasd content-type: text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"aa content-TYPE: text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"text.html  content-TYPE: text/HTML", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"text/html content-TYPE: text/HTML", L"content-type:", L"text/HTML"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"AAAA content-TYPE: text/HTML", L"content-TYPE:", L"text/HTML"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:text/html AAAAA", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:  text/html", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:   text/htmlaaa", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:    text/html  asdsdg content-type", L"content-type:", L"text/html"));
+  ASSERT_TRUE(FindStringASpaceStringB(L"content-type:\ttext/htmlconttent-type:te", L"content-type:", L"text/html"));
+
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:  a  text/html", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:  content-type:  a  text/html", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type: b text/html  content-type:  a  text/html", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:-text/html", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:\ntext/html", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:  a  TEXT/html", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:  a  html/text", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"a dss content-type:  a  text/html", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"text/html content-type:-text/html", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"text/html sdfsd fcontent-type:\ntext/html", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"AAAA content-type:  a  TEXT/html", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:  a  html/text AAA", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:content-type:", L"content-type:", L"text/html"));
+  ASSERT_FALSE(FindStringASpaceStringB(L"content-type:content-type: content-type:", L"content-type:", L"text/html"));
+}
+
+TEST(StringTest, ElideIfNeeded) {
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 3, 3), L"1..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 4, 3), L"12..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 5, 3), L"123..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 6, 3), L"1234..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 7, 3), L"1234..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 8, 3), L"1234..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 9, 3), L"1234..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 10, 3), L"1234..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 11, 3), L"1234 6789..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 12, 3), L"1234 6789..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 13, 3), L"1234 6789..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 14, 3), L"1234 6789 1234");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 15, 3), L"1234 6789 1234");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 16, 3), L"1234 6789 1234");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 17, 3), L"1234 6789 1234");
+
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 7, 6), L"1234..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 8, 6), L"1234 6..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 9, 6), L"1234 67..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 10, 6), L"1234 678..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 11, 6), L"1234 6789..");
+  ASSERT_STREQ(ElideIfNeeded(L"1234 6789 1234", 12, 6), L"1234 6789..");
+}
+
+TEST(StringTest, SafeStrCat) {
+  const int kDestLen = 7;
+  TCHAR dest[kDestLen];
+  lstrcpyn(dest, L"short", kDestLen);
+  ASSERT_LT(lstrlen(dest), kDestLen);
+
+  dest[kDestLen-1] = 'a';
+  lstrcpyn(dest, L"medium123", kDestLen);
+  ASSERT_EQ(dest[kDestLen - 1], '\0');
+  ASSERT_LT(lstrlen(dest), kDestLen);
+
+  lstrcpyn(dest, L"longerlonger", kDestLen);
+  ASSERT_EQ(dest[kDestLen - 1], '\0');
+  ASSERT_LT(lstrlen(dest), kDestLen);
+
+  lstrcpyn(dest, L"12", kDestLen);
+  SafeStrCat(dest, L"3456", kDestLen);
+  ASSERT_EQ(dest[kDestLen - 1], '\0');
+  ASSERT_LT(lstrlen(dest), kDestLen);
+}
+
+void TestPathFindExtension(const TCHAR *s) {
+  ASSERT_STREQ(String_PathFindExtension(s), PathFindExtension(s));
+}
+
+TEST(StringTest, TestPathFindExtension) {
+  TestPathFindExtension(L"c:\\test.tmp");
+  TestPathFindExtension(L"c:\\test.temp");
+  TestPathFindExtension(L"c:\\t\\e\\st.temp");
+  TestPathFindExtension(L"c:\\a.temp");
+  TestPathFindExtension(L"\\aaa\\a.temp");
+  TestPathFindExtension(L"\\a\\a.temp");
+  TestPathFindExtension(L"\\a\\a.temp");
+  TestPathFindExtension(L"\\a\\a.t....emp");
+  TestPathFindExtension(L"\\a.a.a...a\\a.t....emp");
+  TestPathFindExtension(L"\\a\\a\\bbbb\\ddddddddddddddd.temp");
+  TestPathFindExtension(L"\\a\\a\\bbbb\\ddddddddddddddd.te___124567mp");
+  TestPathFindExtension(L"\\a\\a\\bbbb\\ddddddd.dddddddd.te___124567mp");
+}
+
+TEST(StringTest, TextToLinesAndBack) {
+  const TCHAR sample_input[]  = L"Now is the time\r\nfor all good men\r\nto come to the aid of their country";
+  const TCHAR* sample_lines[] = { L"Now is the time", L"for all good men", L"to come to the aid of their country" };
+  const TCHAR sample_output1[] = L"Now is the time\nfor all good men\nto come to the aid of their country\n";
+  const TCHAR sample_output2[] = L"Now is the timefor all good mento come to the aid of their country";
+
+  CString text_in(sample_input);
+  std::vector<CString> lines;
+  CString text_out;
+
+  TextToLines(text_in, L"\r\n", &lines);
+  ASSERT_EQ(lines.size(), 3);
+  for (size_t i = 0; i < arraysize(sample_lines); ++i) {
+    ASSERT_TRUE(0 == lines[i].Compare(sample_lines[i]));
+  }
+  LinesToText(lines, L"\n", &text_out);
+  ASSERT_TRUE(0 == text_out.Compare(sample_output1));
+  LinesToText(lines, L"", &text_out);
+  ASSERT_TRUE(0 == text_out.Compare(sample_output2));
+}
+
+CString TrimStdString(const TCHAR* str) {
+  CString s(str);
+  TrimString(s, L" \t");
+  return s;
+}
+
+TEST(StringTest, TrimString) {
+  ASSERT_STREQ(L"abc", TrimStdString(L"abc"));
+  ASSERT_STREQ(L"abc", TrimStdString(L" abc "));
+  ASSERT_STREQ(L"a c", TrimStdString(L" a c  "));
+  ASSERT_STREQ(L"abc", TrimStdString(L" \tabc\t "));
+  ASSERT_STREQ(L"", TrimStdString(L""));
+  ASSERT_STREQ(L"", TrimStdString(L"   "));
+}
+
+TEST(StringTest, StripFirstQuotedToken) {
+  ASSERT_STREQ(StripFirstQuotedToken(L""), L"");
+  ASSERT_STREQ(StripFirstQuotedToken(L"a" ), L"");
+  ASSERT_STREQ(StripFirstQuotedToken(L"  a b  "), L"b");
+  ASSERT_STREQ(StripFirstQuotedToken(L"\"abc\" def"), L" def");
+  ASSERT_STREQ(StripFirstQuotedToken(L"  \"abc def\" ghi  "), L" ghi");
+  ASSERT_STREQ(StripFirstQuotedToken(L"\"abc\"   \"def\" "), L"   \"def\"");
+}
+
+TEST(StringTest, EscapeUnescape) {
+  CString original_str(_T("test <>\"#{}|\\^[]?%&/"));
+  CString escaped_str;
+  ASSERT_SUCCEEDED(StringEscape(original_str, true, &escaped_str));
+  ASSERT_STREQ(escaped_str,
+               _T("test%20%3C%3E%22%23%7B%7D%7C%5C%5E%5B%5D%3F%25%26%2F"));
+  CString unescaped_str;
+  ASSERT_SUCCEEDED(StringUnescape(escaped_str, &unescaped_str));
+  ASSERT_STREQ(original_str, unescaped_str);
+
+  original_str = _T("foo.test path?app=1");
+  ASSERT_SUCCEEDED(StringEscape(original_str, false, &escaped_str));
+  ASSERT_STREQ(escaped_str,
+               _T("foo.test%20path?app=1"));
+  ASSERT_SUCCEEDED(StringUnescape(escaped_str, &unescaped_str));
+  ASSERT_STREQ(original_str, unescaped_str);
+}
+
+TEST(StringTest, String_StringToDecimalIntChecked) {
+  int value = 0;
+
+  // This code before the first valid case verifies that errno is properly
+  // cleared and there are no dependencies on prior code.
+  EXPECT_EQ(0, _set_errno(ERANGE));
+
+  // Valid Cases
+  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("935"), &value));
+  EXPECT_EQ(value, 935);
+  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("-935"), &value));
+  EXPECT_EQ(value, -935);
+  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("0"), &value));
+  EXPECT_EQ(value, 0);
+  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("2147483647"), &value));
+  EXPECT_EQ(value, LONG_MAX);
+  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("-2147483648"), &value));
+  EXPECT_EQ(value, LONG_MIN);
+  EXPECT_TRUE(String_StringToDecimalIntChecked(_T(" 0"), &value));
+  EXPECT_EQ(value, 0);
+
+  // Failing Cases
+  EXPECT_FALSE(String_StringToDecimalIntChecked(_T(""), &value));
+  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("2147483648"), &value));
+  EXPECT_EQ(value, LONG_MAX);
+  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("-2147483649"), &value));
+  EXPECT_EQ(value, LONG_MIN);
+  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("0x935"), &value));
+  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("nine"), &value));
+  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("9nine"), &value));
+  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("nine9"), &value));
+
+  // A valid case after an overflow verifies that this method clears errno.
+  EXPECT_FALSE(String_StringToDecimalIntChecked(_T("2147483648"), &value));
+  EXPECT_TRUE(String_StringToDecimalIntChecked(_T("935"), &value));
+}
+TEST(StringTest, String_StringToTristate) {
+  Tristate value = TRISTATE_NONE;
+
+  // Valid Cases
+  EXPECT_TRUE(String_StringToTristate(_T("0"), &value));
+  EXPECT_EQ(value, TRISTATE_FALSE);
+  EXPECT_TRUE(String_StringToTristate(_T("1"), &value));
+  EXPECT_EQ(value, TRISTATE_TRUE);
+  EXPECT_TRUE(String_StringToTristate(_T("2"), &value));
+  EXPECT_EQ(value, TRISTATE_NONE);
+
+  // Invalid Cases
+  EXPECT_FALSE(String_StringToTristate(_T("-1"), &value));
+  EXPECT_FALSE(String_StringToTristate(_T("3"), &value));
+  EXPECT_FALSE(String_StringToTristate(_T(""), &value));
+}
+
+TEST(StringTest, ParseNameValuePair) {
+  CString name;
+  CString value;
+
+  // Valid Cases
+  EXPECT_TRUE(ParseNameValuePair(_T("xx=yyzz"), _T('='), &name, &value));
+  EXPECT_EQ(name, _T("xx"));
+  EXPECT_EQ(value, _T("yyzz"));
+  EXPECT_TRUE(ParseNameValuePair(_T("x=3?\\/\r\n "), _T('='), &name, &value));
+  EXPECT_EQ(name, _T("x"));
+  EXPECT_EQ(value, _T("3?\\/\r\n "));
+  EXPECT_TRUE(ParseNameValuePair(_T("3?google"), _T('?'), &name, &value));
+  EXPECT_EQ(name, _T("3"));
+  EXPECT_EQ(value, _T("google"));
+
+  // Invalid Cases
+  EXPECT_FALSE(ParseNameValuePair(_T(""), _T('='), &name, &value));
+  EXPECT_FALSE(ParseNameValuePair(_T(" "), _T('='), &name, &value));
+  EXPECT_FALSE(ParseNameValuePair(_T("="), _T('='), &name, &value));
+  EXPECT_FALSE(ParseNameValuePair(_T("x="), _T('='), &name, &value));
+  EXPECT_FALSE(ParseNameValuePair(_T("=y"), _T('='), &name, &value));
+  EXPECT_FALSE(ParseNameValuePair(_T("="), _T('='), &name, &value));
+  EXPECT_FALSE(ParseNameValuePair(_T("xxyyzz"), _T('='), &name, &value));
+  EXPECT_FALSE(ParseNameValuePair(_T("xx yyzz"), _T('='), &name, &value));
+  EXPECT_FALSE(ParseNameValuePair(_T("xx==yyzz"), _T('='), &name, &value));
+  EXPECT_FALSE(ParseNameValuePair(_T("xx=yy=zz"), _T('='), &name, &value));
+}
+
+TEST(StringTest, SplitCommandLineInPlace) {
+  const TCHAR * const test_long_paths[] = {
+    _T("c:\\Program Files\\Google\\App\\App.exe"),
+    _T("c:\\Program Files\\Google\\App\\Long Name App.exe"),
+  };
+  const TCHAR * const test_short_paths[] = {
+    _T("notepad.exe"),
+  };
+  const TCHAR * const test_arguments[] = {
+    _T("/a=\"some text\""),
+    _T("/a /b /c"),
+    _T(""),
+  };
+  TCHAR command_line[1024] = {};
+  TCHAR* path = NULL;
+  TCHAR* arguments = NULL;
+  for (int ii = 0; ii < ARRAYSIZE(test_arguments) ; ++ii) {
+    for (int jj = 0; jj < ARRAYSIZE(test_long_paths) ; ++jj) {
+      _snwprintf_s(command_line, ARRAYSIZE(command_line), _TRUNCATE,
+          _T("\"%s\" %s"), test_long_paths[jj], test_arguments[ii]);
+      EXPECT_EQ(true, SplitCommandLineInPlace(command_line, &path, &arguments));
+      EXPECT_STREQ(test_long_paths[jj], path);
+      EXPECT_STREQ(test_arguments[ii], arguments);
+    }
+    for (int kk = 0; kk < ARRAYSIZE(test_short_paths) ; ++kk) {
+      _snwprintf_s(command_line, ARRAYSIZE(command_line), _TRUNCATE,
+          _T("%s %s"), test_short_paths[kk], test_arguments[ii]);
+      EXPECT_EQ(true, SplitCommandLineInPlace(command_line, &path, &arguments));
+      EXPECT_STREQ(test_short_paths[kk], path);
+      EXPECT_STREQ(test_arguments[ii], arguments);
+    }
+  }
+}
+
+TEST(StringTest, ContainsOnlyAsciiChars) {
+  CString test(_T("hello worlr"));
+  ASSERT_TRUE(ContainsOnlyAsciiChars(test));
+
+  TCHAR non_ascii[] = {0x4345, 0x1234, 0x2000};
+  ASSERT_FALSE(ContainsOnlyAsciiChars(non_ascii));
+}
+TEST(StringTest, BytesToHex) {
+  EXPECT_STREQ(BytesToHex(NULL, 0), _T(""));
+  uint8 i = 0;
+  EXPECT_STREQ(BytesToHex(&i, sizeof(i)), _T("00"));
+  i = 0x7f;
+  EXPECT_STREQ(BytesToHex(&i, sizeof(i)), _T("7f"));
+  i = 0xff;
+  EXPECT_STREQ(BytesToHex(&i, sizeof(i)), _T("ff"));
+
+  // Assumes little-endian representation of integers.
+  const uint32 array[] = {0x67452301, 0xefcdab89};
+  EXPECT_STREQ(BytesToHex(reinterpret_cast<const uint8*>(array), sizeof(array)),
+               _T("0123456789abcdef"));
+
+  const uint8* first = reinterpret_cast<const uint8*>(array);
+  const uint8* last  = first + sizeof(array);
+  EXPECT_STREQ(BytesToHex(std::vector<uint8>(first, last)),
+               _T("0123456789abcdef"));
+}
+
+TEST(StringTest, JoinStrings) {
+  std::vector<CString> components;
+  const TCHAR* delim = _T("-");
+  CString result;
+
+  JoinStrings(components, delim, &result);
+  EXPECT_TRUE(result.IsEmpty());
+  JoinStrings(components, NULL, &result);
+  EXPECT_TRUE(result.IsEmpty());
+
+  components.push_back(CString(_T("foo")));
+  JoinStrings(components, delim, &result);
+  EXPECT_STREQ(result, (_T("foo")));
+  JoinStrings(components, NULL, &result);
+  EXPECT_STREQ(result, (_T("foo")));
+
+  components.push_back(CString(_T("bar")));
+  JoinStrings(components, delim, &result);
+  EXPECT_STREQ(result, (_T("foo-bar")));
+  JoinStrings(components, NULL, &result);
+  EXPECT_STREQ(result, (_T("foobar")));
+
+  components.push_back(CString(_T("baz")));
+  JoinStrings(components, delim, &result);
+  EXPECT_STREQ(result, (_T("foo-bar-baz")));
+  JoinStrings(components, NULL, &result);
+  EXPECT_STREQ(result, (_T("foobarbaz")));
+
+
+  JoinStringsInArray(NULL, 0, delim, &result);
+  EXPECT_TRUE(result.IsEmpty());
+  JoinStringsInArray(NULL, 0, NULL, &result);
+  EXPECT_TRUE(result.IsEmpty());
+
+  const TCHAR* array1[] = {_T("foo")};
+  JoinStringsInArray(array1, arraysize(array1), delim, &result);
+  EXPECT_STREQ(result, (_T("foo")));
+  JoinStringsInArray(array1, arraysize(array1), NULL, &result);
+  EXPECT_STREQ(result, (_T("foo")));
+
+  const TCHAR* array2[] = {_T("foo"), _T("bar")};
+  JoinStringsInArray(array2, arraysize(array2), delim, &result);
+  EXPECT_STREQ(result, (_T("foo-bar")));
+  JoinStringsInArray(array2, arraysize(array2), NULL, &result);
+  EXPECT_STREQ(result, (_T("foobar")));
+
+  const TCHAR* array3[] = {_T("foo"), _T("bar"), _T("baz")};
+  JoinStringsInArray(array3, arraysize(array3), delim, &result);
+  EXPECT_STREQ(result, (_T("foo-bar-baz")));
+  JoinStringsInArray(array3, arraysize(array3), NULL, &result);
+  EXPECT_STREQ(result, (_T("foobarbaz")));
+
+  const TCHAR* array_null_1[] = {NULL};
+  JoinStringsInArray(array_null_1, arraysize(array_null_1), delim, &result);
+  EXPECT_STREQ(result, (_T("")));
+
+  const TCHAR* array_null_2[] = {NULL, NULL};
+  JoinStringsInArray(array_null_2, arraysize(array_null_2), delim, &result);
+  EXPECT_STREQ(result, (_T("-")));
+}
+
+TEST(StringTest, String_ToUpper) {
+  // String_ToUpper is a wrapper over ::CharUpper.
+  TCHAR s[] = _T("foo");
+  String_ToUpper(s);
+  EXPECT_STREQ(s, _T("FOO"));
+}
+
+TEST(StringTest, FormatResourceMessage_Valid) {
+  EXPECT_STREQ(
+      _T("Thanks for installing Gears."),
+      FormatResourceMessage(IDS_APPLICATION_INSTALLED_SUCCESSFULLY,
+                            _T("Gears")));
+
+  EXPECT_STREQ(
+      _T("The installer encountered error 12345: Action failed."),
+      FormatResourceMessage(IDS_INSTALLER_FAILED_WITH_MESSAGE,
+                            _T("12345"),
+                            _T("Action failed.")));
+}
+
+TEST(StringTest, FormatResourceMessage_IdNotFound) {
+  EXPECT_STREQ(_T(""), FormatResourceMessage(100000, "foo", 9));
+}
+
+TEST(StringTest, FormatErrorCode) {
+  EXPECT_STREQ(_T("0xffffffff"), FormatErrorCode(static_cast<DWORD>(-1)));
+  EXPECT_STREQ(_T("0"), FormatErrorCode(0));
+  EXPECT_STREQ(_T("567"), FormatErrorCode(567));
+  EXPECT_STREQ(_T("2147483647"), FormatErrorCode(0x7fffffff));
+  EXPECT_STREQ(_T("0x80000000"), FormatErrorCode(0x80000000));
+  EXPECT_STREQ(_T("0x80000001"), FormatErrorCode(0x80000001));
+  EXPECT_STREQ(_T("0x8fffffff"), FormatErrorCode(0x8fffffff));
+}
+
+TEST(StringTest, Utf8BufferToWideChar) {
+  // Unicode Greek capital letters.
+  const TCHAR expected_string[] = {913, 914, 915, 916, 917, 918, 919, 920,
+                                   921, 922, 923, 924, 925, 926, 927, 928,
+                                   929, 931, 932, 933, 934, 935, 936, 937, 0};
+  // Greek capital letters UTF-8 encoded.
+  const char buffer[] = "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ";
+  CString actual_string = Utf8BufferToWideChar(
+      std::vector<uint8>(buffer, buffer + arraysize(buffer)));
+  EXPECT_STREQ(expected_string, actual_string);
+
+  EXPECT_STREQ(_T(""), Utf8BufferToWideChar(std::vector<uint8>()));
+}
+
+TEST(StringTest, WideStringToUtf8UrlEncodedStringRoundTrip) {
+  CString unicode_string;
+  ASSERT_TRUE(unicode_string.LoadString(IDS_ESCAPE_TEST));
+
+  // Convert from unicode to a wide representation of utf8,url encoded string.
+  CString utf8encoded_str;
+  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_string,
+                                                            &utf8encoded_str));
+  ASSERT_FALSE(utf8encoded_str.IsEmpty());
+
+  // Reconvert from the utf8, url encoded string to the wide version.
+  CString out;
+  ASSERT_HRESULT_SUCCEEDED(Utf8UrlEncodedStringToWideString(utf8encoded_str,
+                                                            &out));
+  ASSERT_FALSE(out.IsEmpty());
+  ASSERT_STREQ(unicode_string, out);
+}
+
+TEST(StringTest, WideStringToUtf8UrlEncodedStringEmptyString) {
+  CString unicode_string;
+
+  // Convert from unicode to a wide representation of utf8,url encoded string.
+  CString utf8encoded_str;
+  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_string,
+                                                            &utf8encoded_str));
+  ASSERT_TRUE(utf8encoded_str.IsEmpty());
+}
+
+TEST(StringTest, WideStringToUtf8UrlEncodedStringSpaces) {
+  CString unicode_string(_T("   "));
+  CStringA expected("%20%20%20");
+  CString exp(expected);
+
+  // Convert from unicode to a wide representation of utf8,url encoded string.
+  CString utf8encoded_str;
+  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_string,
+                                                            &utf8encoded_str));
+  ASSERT_STREQ(exp, utf8encoded_str);
+}
+
+TEST(StringTest, WideStringToUtf8UrlEncodedStringTestString) {
+  CString unicode_string(_T("Test Str/ing&values=&*^%$#"));
+  CStringA ansi_exp("Test%20Str/ing%26values=%26*%5E%$#");
+  CString exp(ansi_exp);
+
+  // Convert from unicode to a wide representation of utf8,url encoded string.
+  CString utf8encoded_str;
+  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_string,
+                                                            &utf8encoded_str));
+  ASSERT_STREQ(exp, utf8encoded_str);
+}
+
+TEST(StringTest, WideStringToUtf8UrlEncodedStringSimpleTestString) {
+  CString unicode_string(_T("TestStr"));
+  CStringA ansi_exp("TestStr");
+  CString exp(ansi_exp);
+
+  // Convert from unicode to a wide representation of utf8,url encoded string.
+  CString utf8encoded_str;
+  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_string,
+                                                            &utf8encoded_str));
+  ASSERT_STREQ(exp, utf8encoded_str);
+}
+
+TEST(StringTest, Utf8UrlEncodedStringToWideStringEmpty) {
+  // Convert from wide representation of utf8,url encoded string to unicode.
+  CString unicode_string;
+  CString utf8encoded_str;
+  ASSERT_HRESULT_SUCCEEDED(Utf8UrlEncodedStringToWideString(utf8encoded_str,
+                                                            &unicode_string));
+  ASSERT_TRUE(unicode_string.IsEmpty());
+}
+
+TEST(StringTest, Utf8UrlEncodedStringToWideStringSpaces) {
+  CString exp(_T("   "));
+  CStringA utf8("%20%20%20");
+  CString utf8encoded_str(utf8);
+
+  // Convert from wide representation of utf8,url encoded string to unicode.
+  CString unicode_string;
+  ASSERT_HRESULT_SUCCEEDED(Utf8UrlEncodedStringToWideString(utf8encoded_str,
+                                                            &unicode_string));
+  ASSERT_STREQ(exp, unicode_string);
+}
+
+TEST(StringTest, Utf8UrlEncodedStringToWideStringSimpleString) {
+  CString exp(_T("TestStr"));
+  CStringA utf8("TestStr");
+  CString utf8encoded_str(utf8);
+
+  // Convert from wide representation of utf8,url encoded string to unicode.
+  CString unicode_string;
+  ASSERT_HRESULT_SUCCEEDED(Utf8UrlEncodedStringToWideString(utf8encoded_str,
+                                                            &unicode_string));
+  ASSERT_STREQ(exp, unicode_string);
+}
+
+}  // namespace omaha
+
diff --git a/common/synchronized.cc b/common/synchronized.cc
index 999d369..926231e 100644
--- a/common/synchronized.cc
+++ b/common/synchronized.cc
@@ -1,504 +1,504 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines methods of classes used to encapsulate

-// the synchronization primitives.

-

-#include "omaha/common/synchronized.h"

-

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/system.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-typedef HANDLE WINAPI CreateMutexExFunction(

-  LPSECURITY_ATTRIBUTES attributes,

-  const WCHAR* name,

-  DWORD flags,

-  DWORD desired_access

-);

-

-#define CREATE_EVENT_MANUAL_RESET 0x01

-typedef HANDLE WINAPI CreateEventExFunction(

-  LPSECURITY_ATTRIBUTES attributes,

-  const WCHAR* name,

-  DWORD flags,

-  DWORD desired_access

-);

-

-CreateMutexExFunction* create_mutex_ex_function = NULL;

-CreateEventExFunction* create_event_ex_function = NULL;

-

-void EnsureCreateEx() {

-  if ((create_mutex_ex_function && create_event_ex_function) ||

-      !SystemInfo::IsRunningOnVistaOrLater()) {

-    return;

-  }

-

-  HMODULE kernel32_module = ::GetModuleHandle(_T("kernel32.dll"));

-  if (!kernel32_module) {

-    ASSERT(kernel32_module,

-           (_T("[GetModuleHandle error 0x%x]"), ::GetLastError()));

-    return;

-  }

-  GPA(kernel32_module, "CreateMutexExW", &create_mutex_ex_function);

-  ASSERT(create_mutex_ex_function,

-         (_T("[GPA error 0x%x]"), ::GetLastError()));

-

-  GPA(kernel32_module, "CreateEventExW", &create_event_ex_function);

-  ASSERT(create_event_ex_function,

-         (_T("[GPA error 0x%x]"), ::GetLastError()));

-}

-

-HANDLE CreateMutexWithSyncAccess(const TCHAR* name,

-                                 LPSECURITY_ATTRIBUTES lock_attributes) {

-  EnsureCreateEx();

-  if (create_mutex_ex_function) {

-    return create_mutex_ex_function(lock_attributes, name, 0,

-                                    SYNCHRONIZE |

-                                    MUTEX_MODIFY_STATE);  // for ReleaseMutex

-  }

-  return ::CreateMutex(lock_attributes, false, name);

-}

-

-HANDLE CreateEventWithSyncAccess(const TCHAR* name,

-                                 LPSECURITY_ATTRIBUTES event_attributes) {

-  EnsureCreateEx();

-  if (create_event_ex_function) {

-    return create_event_ex_function(event_attributes, name,

-                                    CREATE_EVENT_MANUAL_RESET,

-                                    SYNCHRONIZE |

-                                    EVENT_MODIFY_STATE);  // for Set/Reset, etc.

-  }

-  return ::CreateEvent(event_attributes, true, false, name);

-}

-

-// c-tor will take mutex.

-AutoSync::AutoSync(const Lockable *pLock)

-    : lock_(pLock),

-      first_time_(true) {

-  ASSERT(lock_, (L""));

-  VERIFY(lock_->Lock(), (L"Failed to lock in constructor"));

-}

-

-// c-tor will take mutex.

-AutoSync::AutoSync(const Lockable &rLock)

-    : lock_(&rLock),

-      first_time_(true) {

-  ASSERT(lock_, (L""));

-  VERIFY(lock_->Lock(), (L"Failed to lock in constructor"));

-}

-

-// d-tor will release mutex.

-AutoSync::~AutoSync() {

-  ASSERT(lock_, (L""));

-  VERIFY(lock_->Unlock(), (L"Failed to unlock in denstructor"));

-}

-

-// Allows to write the for loop of __mutexBlock macro

-bool AutoSync::FirstTime() {

-  if (first_time_) {

-     first_time_ = false;

-     return true;

-  }

-  return false;

-}

-

-// Constructor.

-GLock::GLock() : mutex_(NULL) {

-}

-

-bool GLock::InitializeWithSecAttr(const TCHAR* name,

-                                  LPSECURITY_ATTRIBUTES lock_attributes) {

-  ASSERT(!mutex_, (L""));

-

-#if defined(DEBUG) || defined(ASSERT_IN_RELEASE)

-  name_ = name;

-#endif

-

-  mutex_ = CreateMutexWithSyncAccess(name, lock_attributes);

-  return mutex_ != NULL;

-}

-

-// Create mutex return the status of creation. Sets to default DACL.

-bool GLock::Initialize(const TCHAR* name) {

-  return InitializeWithSecAttr(name, NULL);

-}

-

-// Clean up.

-GLock::~GLock() {

-  if (mutex_) {

-    VERIFY(::CloseHandle(mutex_), (_T("")));

-  }

-};

-

-// Wait until signaled.

-bool GLock::Lock() const {

-  return Lock(INFINITE);

-}

-

-bool GLock::Lock(DWORD dwMilliseconds) const {

-  ASSERT1(mutex_);

-

-  DWORD ret = ::WaitForSingleObject(mutex_, dwMilliseconds);

-  if (ret == WAIT_OBJECT_0) {

-    return true;

-  } else if (ret == WAIT_ABANDONED) {

-    UTIL_LOG(LE, (_T("[GLock::Lock - mutex was abandoned %s]"), name_));

-    return true;

-  }

-  return false;

-}

-

-// Release.

-bool GLock::Unlock() const {

-  ASSERT1(mutex_);

-

-  bool ret = (false != ::ReleaseMutex(mutex_));

-  ASSERT(ret, (_T("ReleaseMutex failed.  Err=%i"), ::GetLastError()));

-

-  return ret;

-}

-

-LLock::LLock() {

-  InitializeCriticalSection(&critical_section_);

-}

-

-LLock::~LLock() {

-  DeleteCriticalSection(&critical_section_);

-}

-

-bool LLock::Lock() const {

-  EnterCriticalSection(&critical_section_);

-  return true;

-}

-

-// not very precise funcion, but OK for our goals.

-bool LLock::Lock(DWORD wait_ms) const {

-  if (::TryEnterCriticalSection(&critical_section_))

-    return true;

-  DWORD ticks_at_the_begin_of_wait = GetTickCount();

-  do {

-    ::Sleep(0);

-    if (::TryEnterCriticalSection(&critical_section_)) {

-      return true;

-    }

-  } while (::GetTickCount() - ticks_at_the_begin_of_wait <  wait_ms);

-  return false;

-}

-

-bool LLock::Unlock() const {

-  LeaveCriticalSection(&critical_section_);

-  return true;

-}

-

-// Use this c-tor for interprocess gates.

-Gate::Gate(const TCHAR * event_name) : gate_(NULL) {

-  VERIFY(Initialize(event_name), (_T("")));

-}

-

-// Use this c-tor for in-process gates.

-Gate::Gate() : gate_(NULL) {

-  VERIFY(Initialize(NULL), (_T("")));

-}

-

-// clean up.

-Gate::~Gate() {

-  VERIFY(CloseHandle(gate_), (_T("")));

-}

-

-bool Gate::Initialize(const TCHAR * event_name) {

-  // event_name may be NULL

-  ASSERT1(gate_ == NULL);

-

-  // Create the event. The gate is initially closed.

-  // if this is in process gate we don't name event, otherwise we do.

-  // Created with default permissions.

-  gate_ = CreateEventWithSyncAccess(event_name, NULL);

-  return (NULL != gate_);

-}

-

-// Open the gate. Anyone can go through.

-bool Gate::Open() {

-  return FALSE != SetEvent(gate_);

-}

-

-// Shut the gate closed.

-bool Gate::Close() {

-  return FALSE != ResetEvent(gate_);

-}

-

-bool Gate::Wait(DWORD msec) {

-  return WAIT_OBJECT_0 == WaitForSingleObject(gate_, msec);

-}

-

-// Returns S_OK, and sets selected_gate to zero based index of the gate that

-// was opened

-// Returns E_FAIL if timeout occured or gate was abandoned.

-HRESULT Gate::WaitAny(Gate const * const *gates,

-                      int num_gates,

-                      DWORD msec,

-                      int *selected_gate) {

-  ASSERT1(selected_gate);

-  ASSERT1(gates);

-

-  return WaitMultipleHelper(gates, num_gates, msec, selected_gate, false);

-}

-

-// Returns S_OK if all gates were opened

-// Returns E_FAIL if timeout occured or gate was abandoned.

-HRESULT Gate::WaitAll(Gate const * const *gates, int num_gates, DWORD msec) {

-  ASSERT1(gates);

-

-  return WaitMultipleHelper(gates, num_gates, msec, NULL, true);

-}

-

-HRESULT Gate::WaitMultipleHelper(Gate const * const *gates,

-                                 int num_gates,

-                                 DWORD msec,

-                                 int *selected_gate,

-                                 bool wait_all) {

-  ASSERT1(gates);

-  ASSERT(num_gates > 0, (_T("There must be at least 1 gate")));

-

-  if ( num_gates <= 0 ) {

-    return E_FAIL;

-  }

-  HANDLE *gate_array = new HANDLE[ num_gates ];

-  ASSERT1(gate_array);

-  for ( int i = 0 ; i < num_gates ; ++i ) {

-    gate_array[ i ] = gates[ i ]->gate_;

-  }

-  DWORD res = WaitForMultipleObjects(num_gates,

-                                     gate_array,

-                                     wait_all ? TRUE : FALSE,

-                                     msec);

-  delete[] gate_array;

-

-#pragma warning(disable : 4296)

-// C4296: '>=' : expression is always true

-  if (WAIT_OBJECT_0 <= res && res < (WAIT_OBJECT_0 + num_gates)) {

-    if (selected_gate) {

-      *selected_gate = res - WAIT_OBJECT_0;

-    }

-    return S_OK;

-  }

-#pragma warning(default : 4296)

-  return E_FAIL;

-}

-

-bool WaitAllowRepaint(const Gate& gate, DWORD msec) {

-  DWORD wait = 0;

-  HANDLE gate_handle = gate;

-  while ((wait = ::MsgWaitForMultipleObjects(1,

-                                             &gate_handle,

-                                             FALSE,

-                                             msec,

-                                             QS_PAINT)) == WAIT_OBJECT_0 + 1) {

-    MSG msg;

-    if (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||

-        ::PeekMessage(&msg, NULL, WM_NCPAINT, WM_NCPAINT, PM_REMOVE)) {

-      ::TranslateMessage(&msg);

-      ::DispatchMessage(&msg);

-    }

-  }

-  return (wait == WAIT_OBJECT_0);

-}

-

-// SimpleLock

-// TODO(omaha): Replace InterlockedCompareExchange with

-// InterlockedCompareExchangeAcquire

-// and InterlockedDecrement with InterlockedDecrementRelease for Windows 2003

-

-bool SimpleLock::Lock() const {

-  while (1 == ::InterlockedCompareExchange(&lock_, 1, 0))

-    ::SleepEx(0, TRUE);

-  return true;

-}

-

-bool SimpleLock::Unlock() const {

-  ::InterlockedDecrement(&lock_);

-  return true;

-}

-

-// same with a delay in the loop to prevent CPU usage with significant

-// contention

-

-bool SimpleLockWithDelay::Lock() const {

-  while (1 == ::InterlockedCompareExchange(&lock_, 1, 0))

-    ::SleepEx(25, FALSE);

-  return true;

-}

-

-bool SimpleLockWithDelay::Unlock() const {

-  ::InterlockedDecrement(&lock_);

-  return true;

-}

-

-

-CriticalSection::CriticalSection()

-: number_entries_(0) {

-  InitializeCriticalSection(&critical_section_);

-}

-

-// allow only one thread to hold a lock

-CriticalSection::~CriticalSection() {

-  // we should not have to do anything in the destructor

-  ASSERT(!number_entries_, (_T("critical section destroyed while active")));

-  while (number_entries_) {

-    LeaveCriticalSection(&critical_section_);

-    number_entries_--;

-  }

-

-  DeleteCriticalSection(&critical_section_);

-}

-

-// enter the critical section

-// entries may be nested

-void CriticalSection::Enter() {

-  EnterCriticalSection(&critical_section_);

-  number_entries_++;

-}

-

-// exit the critical section

-// number of exits must match number of entries

-void CriticalSection::Exit() {

-  LeaveCriticalSection(&critical_section_);

-  number_entries_--;

-}

-

-// Take a CriticalSection and lock it

-SingleLock::SingleLock(CriticalSection * cs) {

-  ASSERT(cs, (L""));

-  critical_section_ = cs;

-  critical_section_->Enter();

-}

-

-// If we haven't freed it yet, do so now since we fell out of scope

-SingleLock::~SingleLock() {

-  if (critical_section_) {

-    critical_section_->Exit();

-    critical_section_ = NULL;

-  }

-}

-

-// Explicitly unlock

-HRESULT SingleLock::Unlock() {

-  // If they did not

-  if (critical_section_ == NULL)

-    return S_FALSE;

-

-  critical_section_->Exit();

-  critical_section_ = NULL;

-  return S_OK;

-}

-

-// Encapsulation for kernel Event. Initializes and destroys with it's lifetime

-void EventObj::Init(const TCHAR * event_name) {

-  ASSERT(event_name, (L""));

-

-  h_ = ::CreateEvent(NULL, false, false, event_name);

-  ASSERT1(h_);

-}

-

-EventObj::~EventObj() {

-  if (h_) {

-    VERIFY(CloseHandle(h_), (L""));

-    h_ = NULL;

-  }

-}

-

-BOOL EventObj::SetEvent() {

-  ASSERT(h_, (L""));

-  return ::SetEvent(h_);

-}

-

-// Is the given handle signaled?

-//

-// Typically used for events.

-bool IsHandleSignaled(HANDLE h) {

-  ASSERT(h != NULL &&

-         h != INVALID_HANDLE_VALUE, (_T("")));

-

-  DWORD result = ::WaitForSingleObject(h, 0);

-  if (result == WAIT_OBJECT_0) {

-    return true;

-  }

-

-  ASSERT(result == WAIT_TIMEOUT,

-         (_T("unexpected result value: %u (hr=0x%x)"),

-          result, HRESULTFromLastError()));

-  return false;

-}

-

-

-// Create an id for the events/mutexes that can be used at the given scope.

-// TODO(omaha): Error handling.

-void CreateSyncId(const TCHAR* id, SyncScope scope, CString* sync_id) {

-  ASSERT1(id);

-  ASSERT1(sync_id);

-

-  CString postfix;

-  switch (scope) {

-    default:

-      ASSERT1(false);

-      break;

-

-    case SYNC_LOCAL:

-      sync_id->SetString(_T("Local\\"));

-      // no postfix for local ids

-      break;

-

-    case SYNC_USER:

-    case SYNC_GLOBAL:

-      sync_id->SetString(_T("Global\\"));

-

-      if (scope == SYNC_GLOBAL) {

-        // (MSDN insists that you can create objects with the same name with the

-        // prefixes "Global\" and "Local\" in a system "running Terminal

-        // Services". And it also assures that XP when running Fast User

-        // Switching uses Terminal Services. But when you try to create two

-        // objects with the same name but in the different namespaces on an

-        // XP Pro workstation NOT running Fast User Switching you can't - you

-        // get ERROR_ALREADY_EXISTS. And the reason is that in the Object table,

-        // Global and Local are both symlinks to the same object directory.

-        // Yet every technique that you can use to interrogate the system on

-        // whether or not the system is "running Terminal Services" says that

-        // the system is, in fact, running Terminal Services.

-        // Which is exactly what you'd expect, yet you can't create the

-        // two objects with the same name in different workspaces.  So we change

-        // the name slightly.)

-        postfix.SetString(_T("_global"));

-      } else {

-        ASSERT1(scope == SYNC_USER);

-        // make the postfix the sid

-        VERIFY1(SUCCEEDED(omaha::user_info::GetCurrentUser(NULL,

-                                                           NULL,

-                                                           &postfix)));

-      }

-      break;

-  }

-

-  sync_id->Append(id);

-  sync_id->Append(postfix);

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines methods of classes used to encapsulate
+// the synchronization primitives.
+
+#include "omaha/common/synchronized.h"
+
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/system.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+typedef HANDLE WINAPI CreateMutexExFunction(
+  LPSECURITY_ATTRIBUTES attributes,
+  const WCHAR* name,
+  DWORD flags,
+  DWORD desired_access
+);
+
+#define CREATE_EVENT_MANUAL_RESET 0x01
+typedef HANDLE WINAPI CreateEventExFunction(
+  LPSECURITY_ATTRIBUTES attributes,
+  const WCHAR* name,
+  DWORD flags,
+  DWORD desired_access
+);
+
+CreateMutexExFunction* create_mutex_ex_function = NULL;
+CreateEventExFunction* create_event_ex_function = NULL;
+
+void EnsureCreateEx() {
+  if ((create_mutex_ex_function && create_event_ex_function) ||
+      !SystemInfo::IsRunningOnVistaOrLater()) {
+    return;
+  }
+
+  HMODULE kernel32_module = ::GetModuleHandle(_T("kernel32.dll"));
+  if (!kernel32_module) {
+    ASSERT(kernel32_module,
+           (_T("[GetModuleHandle error 0x%x]"), ::GetLastError()));
+    return;
+  }
+  GPA(kernel32_module, "CreateMutexExW", &create_mutex_ex_function);
+  ASSERT(create_mutex_ex_function,
+         (_T("[GPA error 0x%x]"), ::GetLastError()));
+
+  GPA(kernel32_module, "CreateEventExW", &create_event_ex_function);
+  ASSERT(create_event_ex_function,
+         (_T("[GPA error 0x%x]"), ::GetLastError()));
+}
+
+HANDLE CreateMutexWithSyncAccess(const TCHAR* name,
+                                 LPSECURITY_ATTRIBUTES lock_attributes) {
+  EnsureCreateEx();
+  if (create_mutex_ex_function) {
+    return create_mutex_ex_function(lock_attributes, name, 0,
+                                    SYNCHRONIZE |
+                                    MUTEX_MODIFY_STATE);  // for ReleaseMutex
+  }
+  return ::CreateMutex(lock_attributes, false, name);
+}
+
+HANDLE CreateEventWithSyncAccess(const TCHAR* name,
+                                 LPSECURITY_ATTRIBUTES event_attributes) {
+  EnsureCreateEx();
+  if (create_event_ex_function) {
+    return create_event_ex_function(event_attributes, name,
+                                    CREATE_EVENT_MANUAL_RESET,
+                                    SYNCHRONIZE |
+                                    EVENT_MODIFY_STATE);  // for Set/Reset, etc.
+  }
+  return ::CreateEvent(event_attributes, true, false, name);
+}
+
+// c-tor will take mutex.
+AutoSync::AutoSync(const Lockable *pLock)
+    : lock_(pLock),
+      first_time_(true) {
+  ASSERT(lock_, (L""));
+  VERIFY(lock_->Lock(), (L"Failed to lock in constructor"));
+}
+
+// c-tor will take mutex.
+AutoSync::AutoSync(const Lockable &rLock)
+    : lock_(&rLock),
+      first_time_(true) {
+  ASSERT(lock_, (L""));
+  VERIFY(lock_->Lock(), (L"Failed to lock in constructor"));
+}
+
+// d-tor will release mutex.
+AutoSync::~AutoSync() {
+  ASSERT(lock_, (L""));
+  VERIFY(lock_->Unlock(), (L"Failed to unlock in denstructor"));
+}
+
+// Allows to write the for loop of __mutexBlock macro
+bool AutoSync::FirstTime() {
+  if (first_time_) {
+     first_time_ = false;
+     return true;
+  }
+  return false;
+}
+
+// Constructor.
+GLock::GLock() : mutex_(NULL) {
+}
+
+bool GLock::InitializeWithSecAttr(const TCHAR* name,
+                                  LPSECURITY_ATTRIBUTES lock_attributes) {
+  ASSERT(!mutex_, (L""));
+
+#if defined(DEBUG) || defined(ASSERT_IN_RELEASE)
+  name_ = name;
+#endif
+
+  mutex_ = CreateMutexWithSyncAccess(name, lock_attributes);
+  return mutex_ != NULL;
+}
+
+// Create mutex return the status of creation. Sets to default DACL.
+bool GLock::Initialize(const TCHAR* name) {
+  return InitializeWithSecAttr(name, NULL);
+}
+
+// Clean up.
+GLock::~GLock() {
+  if (mutex_) {
+    VERIFY(::CloseHandle(mutex_), (_T("")));
+  }
+};
+
+// Wait until signaled.
+bool GLock::Lock() const {
+  return Lock(INFINITE);
+}
+
+bool GLock::Lock(DWORD dwMilliseconds) const {
+  ASSERT1(mutex_);
+
+  DWORD ret = ::WaitForSingleObject(mutex_, dwMilliseconds);
+  if (ret == WAIT_OBJECT_0) {
+    return true;
+  } else if (ret == WAIT_ABANDONED) {
+    UTIL_LOG(LE, (_T("[GLock::Lock - mutex was abandoned %s]"), name_));
+    return true;
+  }
+  return false;
+}
+
+// Release.
+bool GLock::Unlock() const {
+  ASSERT1(mutex_);
+
+  bool ret = (false != ::ReleaseMutex(mutex_));
+  ASSERT(ret, (_T("ReleaseMutex failed.  Err=%i"), ::GetLastError()));
+
+  return ret;
+}
+
+LLock::LLock() {
+  InitializeCriticalSection(&critical_section_);
+}
+
+LLock::~LLock() {
+  DeleteCriticalSection(&critical_section_);
+}
+
+bool LLock::Lock() const {
+  EnterCriticalSection(&critical_section_);
+  return true;
+}
+
+// not very precise funcion, but OK for our goals.
+bool LLock::Lock(DWORD wait_ms) const {
+  if (::TryEnterCriticalSection(&critical_section_))
+    return true;
+  DWORD ticks_at_the_begin_of_wait = GetTickCount();
+  do {
+    ::Sleep(0);
+    if (::TryEnterCriticalSection(&critical_section_)) {
+      return true;
+    }
+  } while (::GetTickCount() - ticks_at_the_begin_of_wait <  wait_ms);
+  return false;
+}
+
+bool LLock::Unlock() const {
+  LeaveCriticalSection(&critical_section_);
+  return true;
+}
+
+// Use this c-tor for interprocess gates.
+Gate::Gate(const TCHAR * event_name) : gate_(NULL) {
+  VERIFY(Initialize(event_name), (_T("")));
+}
+
+// Use this c-tor for in-process gates.
+Gate::Gate() : gate_(NULL) {
+  VERIFY(Initialize(NULL), (_T("")));
+}
+
+// clean up.
+Gate::~Gate() {
+  VERIFY(CloseHandle(gate_), (_T("")));
+}
+
+bool Gate::Initialize(const TCHAR * event_name) {
+  // event_name may be NULL
+  ASSERT1(gate_ == NULL);
+
+  // Create the event. The gate is initially closed.
+  // if this is in process gate we don't name event, otherwise we do.
+  // Created with default permissions.
+  gate_ = CreateEventWithSyncAccess(event_name, NULL);
+  return (NULL != gate_);
+}
+
+// Open the gate. Anyone can go through.
+bool Gate::Open() {
+  return FALSE != SetEvent(gate_);
+}
+
+// Shut the gate closed.
+bool Gate::Close() {
+  return FALSE != ResetEvent(gate_);
+}
+
+bool Gate::Wait(DWORD msec) {
+  return WAIT_OBJECT_0 == WaitForSingleObject(gate_, msec);
+}
+
+// Returns S_OK, and sets selected_gate to zero based index of the gate that
+// was opened
+// Returns E_FAIL if timeout occured or gate was abandoned.
+HRESULT Gate::WaitAny(Gate const * const *gates,
+                      int num_gates,
+                      DWORD msec,
+                      int *selected_gate) {
+  ASSERT1(selected_gate);
+  ASSERT1(gates);
+
+  return WaitMultipleHelper(gates, num_gates, msec, selected_gate, false);
+}
+
+// Returns S_OK if all gates were opened
+// Returns E_FAIL if timeout occured or gate was abandoned.
+HRESULT Gate::WaitAll(Gate const * const *gates, int num_gates, DWORD msec) {
+  ASSERT1(gates);
+
+  return WaitMultipleHelper(gates, num_gates, msec, NULL, true);
+}
+
+HRESULT Gate::WaitMultipleHelper(Gate const * const *gates,
+                                 int num_gates,
+                                 DWORD msec,
+                                 int *selected_gate,
+                                 bool wait_all) {
+  ASSERT1(gates);
+  ASSERT(num_gates > 0, (_T("There must be at least 1 gate")));
+
+  if ( num_gates <= 0 ) {
+    return E_FAIL;
+  }
+  HANDLE *gate_array = new HANDLE[ num_gates ];
+  ASSERT1(gate_array);
+  for ( int i = 0 ; i < num_gates ; ++i ) {
+    gate_array[ i ] = gates[ i ]->gate_;
+  }
+  DWORD res = WaitForMultipleObjects(num_gates,
+                                     gate_array,
+                                     wait_all ? TRUE : FALSE,
+                                     msec);
+  delete[] gate_array;
+
+#pragma warning(disable : 4296)
+// C4296: '>=' : expression is always true
+  if (WAIT_OBJECT_0 <= res && res < (WAIT_OBJECT_0 + num_gates)) {
+    if (selected_gate) {
+      *selected_gate = res - WAIT_OBJECT_0;
+    }
+    return S_OK;
+  }
+#pragma warning(default : 4296)
+  return E_FAIL;
+}
+
+bool WaitAllowRepaint(const Gate& gate, DWORD msec) {
+  DWORD wait = 0;
+  HANDLE gate_handle = gate;
+  while ((wait = ::MsgWaitForMultipleObjects(1,
+                                             &gate_handle,
+                                             FALSE,
+                                             msec,
+                                             QS_PAINT)) == WAIT_OBJECT_0 + 1) {
+    MSG msg;
+    if (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
+        ::PeekMessage(&msg, NULL, WM_NCPAINT, WM_NCPAINT, PM_REMOVE)) {
+      ::TranslateMessage(&msg);
+      ::DispatchMessage(&msg);
+    }
+  }
+  return (wait == WAIT_OBJECT_0);
+}
+
+// SimpleLock
+// TODO(omaha): Replace InterlockedCompareExchange with
+// InterlockedCompareExchangeAcquire
+// and InterlockedDecrement with InterlockedDecrementRelease for Windows 2003
+
+bool SimpleLock::Lock() const {
+  while (1 == ::InterlockedCompareExchange(&lock_, 1, 0))
+    ::SleepEx(0, TRUE);
+  return true;
+}
+
+bool SimpleLock::Unlock() const {
+  ::InterlockedDecrement(&lock_);
+  return true;
+}
+
+// same with a delay in the loop to prevent CPU usage with significant
+// contention
+
+bool SimpleLockWithDelay::Lock() const {
+  while (1 == ::InterlockedCompareExchange(&lock_, 1, 0))
+    ::SleepEx(25, FALSE);
+  return true;
+}
+
+bool SimpleLockWithDelay::Unlock() const {
+  ::InterlockedDecrement(&lock_);
+  return true;
+}
+
+
+CriticalSection::CriticalSection()
+: number_entries_(0) {
+  InitializeCriticalSection(&critical_section_);
+}
+
+// allow only one thread to hold a lock
+CriticalSection::~CriticalSection() {
+  // we should not have to do anything in the destructor
+  ASSERT(!number_entries_, (_T("critical section destroyed while active")));
+  while (number_entries_) {
+    LeaveCriticalSection(&critical_section_);
+    number_entries_--;
+  }
+
+  DeleteCriticalSection(&critical_section_);
+}
+
+// enter the critical section
+// entries may be nested
+void CriticalSection::Enter() {
+  EnterCriticalSection(&critical_section_);
+  number_entries_++;
+}
+
+// exit the critical section
+// number of exits must match number of entries
+void CriticalSection::Exit() {
+  LeaveCriticalSection(&critical_section_);
+  number_entries_--;
+}
+
+// Take a CriticalSection and lock it
+SingleLock::SingleLock(CriticalSection * cs) {
+  ASSERT(cs, (L""));
+  critical_section_ = cs;
+  critical_section_->Enter();
+}
+
+// If we haven't freed it yet, do so now since we fell out of scope
+SingleLock::~SingleLock() {
+  if (critical_section_) {
+    critical_section_->Exit();
+    critical_section_ = NULL;
+  }
+}
+
+// Explicitly unlock
+HRESULT SingleLock::Unlock() {
+  // If they did not
+  if (critical_section_ == NULL)
+    return S_FALSE;
+
+  critical_section_->Exit();
+  critical_section_ = NULL;
+  return S_OK;
+}
+
+// Encapsulation for kernel Event. Initializes and destroys with it's lifetime
+void EventObj::Init(const TCHAR * event_name) {
+  ASSERT(event_name, (L""));
+
+  h_ = ::CreateEvent(NULL, false, false, event_name);
+  ASSERT1(h_);
+}
+
+EventObj::~EventObj() {
+  if (h_) {
+    VERIFY(CloseHandle(h_), (L""));
+    h_ = NULL;
+  }
+}
+
+BOOL EventObj::SetEvent() {
+  ASSERT(h_, (L""));
+  return ::SetEvent(h_);
+}
+
+// Is the given handle signaled?
+//
+// Typically used for events.
+bool IsHandleSignaled(HANDLE h) {
+  ASSERT(h != NULL &&
+         h != INVALID_HANDLE_VALUE, (_T("")));
+
+  DWORD result = ::WaitForSingleObject(h, 0);
+  if (result == WAIT_OBJECT_0) {
+    return true;
+  }
+
+  ASSERT(result == WAIT_TIMEOUT,
+         (_T("unexpected result value: %u (hr=0x%x)"),
+          result, HRESULTFromLastError()));
+  return false;
+}
+
+
+// Create an id for the events/mutexes that can be used at the given scope.
+// TODO(omaha): Error handling.
+void CreateSyncId(const TCHAR* id, SyncScope scope, CString* sync_id) {
+  ASSERT1(id);
+  ASSERT1(sync_id);
+
+  CString postfix;
+  switch (scope) {
+    default:
+      ASSERT1(false);
+      break;
+
+    case SYNC_LOCAL:
+      sync_id->SetString(_T("Local\\"));
+      // no postfix for local ids
+      break;
+
+    case SYNC_USER:
+    case SYNC_GLOBAL:
+      sync_id->SetString(_T("Global\\"));
+
+      if (scope == SYNC_GLOBAL) {
+        // (MSDN insists that you can create objects with the same name with the
+        // prefixes "Global\" and "Local\" in a system "running Terminal
+        // Services". And it also assures that XP when running Fast User
+        // Switching uses Terminal Services. But when you try to create two
+        // objects with the same name but in the different namespaces on an
+        // XP Pro workstation NOT running Fast User Switching you can't - you
+        // get ERROR_ALREADY_EXISTS. And the reason is that in the Object table,
+        // Global and Local are both symlinks to the same object directory.
+        // Yet every technique that you can use to interrogate the system on
+        // whether or not the system is "running Terminal Services" says that
+        // the system is, in fact, running Terminal Services.
+        // Which is exactly what you'd expect, yet you can't create the
+        // two objects with the same name in different workspaces.  So we change
+        // the name slightly.)
+        postfix.SetString(_T("_global"));
+      } else {
+        ASSERT1(scope == SYNC_USER);
+        // make the postfix the sid
+        VERIFY1(SUCCEEDED(omaha::user_info::GetCurrentUser(NULL,
+                                                           NULL,
+                                                           &postfix)));
+      }
+      break;
+  }
+
+  sync_id->Append(id);
+  sync_id->Append(postfix);
+}
+
+}  // namespace omaha
+
diff --git a/common/synchronized.h b/common/synchronized.h
index d71cf0f..b280845 100644
--- a/common/synchronized.h
+++ b/common/synchronized.h
@@ -1,355 +1,355 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Declares some classes and macros to encapsulate

-// the synchronization primitives.

-

-// TODO(omaha): remove dependency on atlstr

-

-#ifndef OMAHA_COMMON_SYNCHRONIZED_H__

-#define OMAHA_COMMON_SYNCHRONIZED_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// This macros are used to create a unique name

-// We need to go through two steps of expansion.

-// Macro kMakeName1 will expand to string + number

-// and macro kMakeName1 will put them together to create

-// the unique name.

-#define MAKE_NAME2(x, y) x##y

-#define MAKE_NAME1(x, y) MAKE_NAME2(x, y)

-#define MAKE_NAME(x) MAKE_NAME1(x, __COUNTER__)

-

-// Declare the interface in implement mutual

-// exclusion. For in process mutual exclusion

-// simple critical sections can be used. For

-// interprocess mutual exclusion some named

-// kernel mode object will have to be used.

-struct Lockable {

-  virtual ~Lockable() {}

-  virtual bool Lock() const = 0;

-  virtual bool Unlock() const = 0;

-};

-

-// Scope based mutual exclusion. Locks

-// the object on construction and unlocks

-// during destruction. Very convinient to use

-// with the macros __mutexScope and __mutexBlock

-class AutoSync {

-  bool first_time_;

- public:

-  explicit AutoSync(const Lockable *pLock);

-  explicit AutoSync(const Lockable &rLock);

-  ~AutoSync();

-  // this function is only needed to use with

-  // the macro __mutexBlock

-  bool FirstTime();

- private:

-  const Lockable * lock_;

-  DISALLOW_EVIL_CONSTRUCTORS(AutoSync);

-};

-

-// the usaage:

-// class A : public Lockable {

-//

-//

-//

-//  void foo(){

-//   __mutexScope(this);

-// ......

-// .......

-// everything is synchronized till the end of the

-// function or the time it returns (from any place)

-// } // end foo.

-//

-// void bar() {

-// ......

-// ...... do something here.

-// ......

-//   __mutexBlock(this){

-//    .... do some other stuff

-//    ....

-//    ....

-//    } everything is synchronized till here

-//

-// }; // end class A

-

-//

-#define __mutexScope(lock) AutoSync MAKE_NAME(hiddenLock)(lock)

-#define __mutexBlock(lock) \

-    for (AutoSync hiddenLock(lock); hiddenLock.FirstTime(); )

-

-// GLock stands for global lock.

-// Implementaion of Lockable to allow mutual exclusion

-// between different processes.

-// For in-process mutual exclusion use LLock - local lock

-class GLock : public Lockable {

- public:

-  GLock();

-  virtual ~GLock();

-

-  // Create mutex return the status of creation.

-  // Takes a SECURITY_ATTRIBUTES structure.

-  bool InitializeWithSecAttr(const TCHAR* name,

-                             LPSECURITY_ATTRIBUTES lock_attributes);

-

-  // Create mutex return the status of creation. Sets to default DACL.

-  bool Initialize(const TCHAR* name);

-

-  virtual bool Lock() const;

-  virtual bool Lock(DWORD dwMilliseconds) const;

-  virtual bool Unlock() const;

-

- private:

-#if defined(DEBUG) || defined(ASSERT_IN_RELEASE)

-  CString name_;

-#endif

-  mutable HANDLE mutex_;

-  DISALLOW_EVIL_CONSTRUCTORS(GLock);

-};

-

-// FakeGLock looks like a GLock, but none of its methods do anything.

-// Only used with SharedMemoryPtr, in cases where locking is not required or

-// desired.

-class FakeGLock : public Lockable {

- public:

-  FakeGLock() {}

-  virtual ~FakeGLock() {}

-  bool InitializeWithSecAttr(const TCHAR*, LPSECURITY_ATTRIBUTES) {

-    return true;

-  }

-  bool Initialize(const TCHAR*) { return true; }

-  virtual bool Lock() const { return true; }

-  virtual bool Lock(DWORD) const { return true; }

-  virtual bool Unlock() const { return true; }

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(FakeGLock);

-};

-

-// LLock stands for local lock.

-// means works only inside the process.

-// use GLock - global lock for inter-process

-// guarded access to data.

-class LLock : public Lockable {

- public:

-  LLock();

-  virtual ~LLock();

-  virtual bool Lock() const;

-  virtual bool Lock(DWORD wait_ms) const;

-  virtual bool Unlock() const;

- private:

-  mutable CRITICAL_SECTION        critical_section_;

-  DISALLOW_EVIL_CONSTRUCTORS(LLock);

-};

-

-// A gate is a synchronization object used to either stop all

-// threads from proceeding through a point or to allow them all to proceed.

-class Gate {

- public:

-  // In process gate.

-  Gate();

-

-  // Interprocess gate.

-  explicit Gate(const TCHAR * event_name);

-

-  ~Gate();

-

-  // Open the gate.

-  bool Open();

-

-  // Close the gate.

-  bool Close();

-

-  // Wait to enter the gate.

-  bool Wait(DWORD msec);

-

-  // Conversion from the object to a HANDLE.

-  operator HANDLE() const {return gate_;}

-

-  // Returns S_OK, and sets selected_gate to zero based index of the gate that

-  // was opened.

-  // Returns E_FAIL if timeout occured or gate was abandoned.

-  static HRESULT WaitAny(Gate const * const *gates,

-                         int num_gates,

-                         DWORD msec,

-                         int *selected_gate);

-

-  // Returns S_OK if all gates were opened

-  // Returns E_FAIL if timeout occured or gate was abandoned.

-  static HRESULT WaitAll(Gate const * const *gates, int num_gates, DWORD msec);

-

- private:

-  bool Initialize(const TCHAR * event_name);

-  static HRESULT WaitMultipleHelper(Gate const * const *gates,

-                                    int num_gates,

-                                    DWORD msec,

-                                    int *selected_gate,

-                                    bool wait_all);

-  HANDLE gate_;

-  DISALLOW_EVIL_CONSTRUCTORS(Gate);

-};

-

-bool WaitAllowRepaint(const Gate& gate, DWORD msec);

-

-class AutoGateKeeper {

- public:

-  explicit AutoGateKeeper(Gate *gate) : gate_(gate) {

-    gate_->Open();

-  }

-  ~AutoGateKeeper() {

-    gate_->Close();

-  }

- private:

-  Gate *gate_;

-  DISALLOW_EVIL_CONSTRUCTORS(AutoGateKeeper);

-};

-

-// A very simple rather fast lock - if uncontested.  USE ONLY AS A GLOBAL OBJECT

-// (i.e., DECLARED AT FILE SCOPE or as a STATIC CLASS MEMBER) - this is not

-// enforced.  Uses interlocked instructions on an int to get a fast user-mode

-// lock.  (Locks the bus and does a couple of memory references so it isn't

-// free.)  Spin-waits to get the lock.  Has the advantage that it needs no

-// initialization - thus has no order-of-evaluation problems with respect to

-// other global objects.  Does not work (causes deadlock) if locked twice by

-// the same thread. (Has no constructor so is initialized to 0 by C++.

-// This is why it must be a global or static class member: it doesn't initialize

-// itself to 0.  This is also why it doesn't inherit from Lockable, which would

-// make it need to initialize a virtual table.)

-struct SimpleLock {

-  bool Lock() const;

-  bool Unlock() const;

- private:

-  mutable volatile long lock_;

-};

-

-struct SimpleLockWithDelay {

-  bool Lock() const;

-  bool Unlock() const;

- private:

-  mutable volatile long lock_;

-};

-

-class AutoSimpleLock {

- public:

-  explicit AutoSimpleLock(const SimpleLock& lock)

-      : lock_(lock) { lock_.Lock(); }

-  ~AutoSimpleLock() { lock_.Unlock(); }

- private:

-  const SimpleLock& lock_;

-  DISALLOW_EVIL_CONSTRUCTORS(AutoSimpleLock);

-};

-

-class AutoSimpleLockWithDelay {

- public:

-  explicit AutoSimpleLockWithDelay(const SimpleLockWithDelay& lock)

-      : lock_(lock) { lock_.Lock(); }

-  ~AutoSimpleLockWithDelay() { lock_.Unlock(); }

- private:

-  const SimpleLockWithDelay& lock_;

-  DISALLOW_EVIL_CONSTRUCTORS(AutoSimpleLockWithDelay);

-};

-

-

-// allow only one thread to hold a lock

-class CriticalSection {

- public:

-  CriticalSection();

-  ~CriticalSection();

-

-  void Enter();

-  void Exit();

-

- private:

-  CRITICAL_SECTION critical_section_;

-  uint32 number_entries_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(CriticalSection);

-};

-

-// A class that manages a CriticalSection with its lifetime, you pass

-// it one in the constructor and then it will either be freed in the

-// destructor or implicitly [but only once]

-class SingleLock {

- public:

-  // TODO(omaha): Not sure if immediately locking is a good idea;

-  // the API is asymmetrical (there's an Unlock but no Lock).

-

-  // Lock a critical section immediately

-  explicit SingleLock(CriticalSection * cs);

-

-  // If we have not explicitly unlocked it, this destructor will

-  ~SingleLock();

-

-  // Release the lock explicitly [should be called only once, after that

-  // does nothing. If we do not do so, the destructor will]

-  HRESULT Unlock();

-

- private:

-  CriticalSection * critical_section_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(SingleLock);

-};

-

-// Encapsulation for kernel Event. Initializes and destroys with it's lifetime

-class EventObj {

- public:

-  explicit EventObj(const TCHAR * event_name) {

-    Init(event_name);

-  }

-  ~EventObj();

-  void Init(const TCHAR * event_name);

-  BOOL SetEvent();

-  HANDLE GetHandle() { return h_; }

-

- private:

-  HANDLE h_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(EventObj);

-};

-

-// Is the given handle signaled?

-//

-// Typically used for events.

-bool IsHandleSignaled(HANDLE h);

-

-

-enum SyncScope {

-  // local to a session

-  SYNC_LOCAL,

-

-  // global scope but the name is decorated to make it unique for the user

-  SYNC_USER,

-

-  // a globally scoped name

-  SYNC_GLOBAL,

-};

-

-// Create an id for the events/mutexes that can be used at the given scope

-void CreateSyncId(const TCHAR* id, SyncScope scope, CString* sync_id);

-

-// If any place needs to create a mutex that multiple

-// processes need to access, use this.

-HANDLE CreateMutexWithSyncAccess(const TCHAR* name,

-                                 LPSECURITY_ATTRIBUTES lock_attributes);

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SYNCHRONIZED_H__

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Declares some classes and macros to encapsulate
+// the synchronization primitives.
+
+// TODO(omaha): remove dependency on atlstr
+
+#ifndef OMAHA_COMMON_SYNCHRONIZED_H__
+#define OMAHA_COMMON_SYNCHRONIZED_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// This macros are used to create a unique name
+// We need to go through two steps of expansion.
+// Macro kMakeName1 will expand to string + number
+// and macro kMakeName1 will put them together to create
+// the unique name.
+#define MAKE_NAME2(x, y) x##y
+#define MAKE_NAME1(x, y) MAKE_NAME2(x, y)
+#define MAKE_NAME(x) MAKE_NAME1(x, __COUNTER__)
+
+// Declare the interface in implement mutual
+// exclusion. For in process mutual exclusion
+// simple critical sections can be used. For
+// interprocess mutual exclusion some named
+// kernel mode object will have to be used.
+struct Lockable {
+  virtual ~Lockable() {}
+  virtual bool Lock() const = 0;
+  virtual bool Unlock() const = 0;
+};
+
+// Scope based mutual exclusion. Locks
+// the object on construction and unlocks
+// during destruction. Very convinient to use
+// with the macros __mutexScope and __mutexBlock
+class AutoSync {
+  bool first_time_;
+ public:
+  explicit AutoSync(const Lockable *pLock);
+  explicit AutoSync(const Lockable &rLock);
+  ~AutoSync();
+  // this function is only needed to use with
+  // the macro __mutexBlock
+  bool FirstTime();
+ private:
+  const Lockable * lock_;
+  DISALLOW_EVIL_CONSTRUCTORS(AutoSync);
+};
+
+// the usaage:
+// class A : public Lockable {
+//
+//
+//
+//  void foo(){
+//   __mutexScope(this);
+// ......
+// .......
+// everything is synchronized till the end of the
+// function or the time it returns (from any place)
+// } // end foo.
+//
+// void bar() {
+// ......
+// ...... do something here.
+// ......
+//   __mutexBlock(this){
+//    .... do some other stuff
+//    ....
+//    ....
+//    } everything is synchronized till here
+//
+// }; // end class A
+
+//
+#define __mutexScope(lock) AutoSync MAKE_NAME(hiddenLock)(lock)
+#define __mutexBlock(lock) \
+    for (AutoSync hiddenLock(lock); hiddenLock.FirstTime(); )
+
+// GLock stands for global lock.
+// Implementaion of Lockable to allow mutual exclusion
+// between different processes.
+// For in-process mutual exclusion use LLock - local lock
+class GLock : public Lockable {
+ public:
+  GLock();
+  virtual ~GLock();
+
+  // Create mutex return the status of creation.
+  // Takes a SECURITY_ATTRIBUTES structure.
+  bool InitializeWithSecAttr(const TCHAR* name,
+                             LPSECURITY_ATTRIBUTES lock_attributes);
+
+  // Create mutex return the status of creation. Sets to default DACL.
+  bool Initialize(const TCHAR* name);
+
+  virtual bool Lock() const;
+  virtual bool Lock(DWORD dwMilliseconds) const;
+  virtual bool Unlock() const;
+
+ private:
+#if defined(DEBUG) || defined(ASSERT_IN_RELEASE)
+  CString name_;
+#endif
+  mutable HANDLE mutex_;
+  DISALLOW_EVIL_CONSTRUCTORS(GLock);
+};
+
+// FakeGLock looks like a GLock, but none of its methods do anything.
+// Only used with SharedMemoryPtr, in cases where locking is not required or
+// desired.
+class FakeGLock : public Lockable {
+ public:
+  FakeGLock() {}
+  virtual ~FakeGLock() {}
+  bool InitializeWithSecAttr(const TCHAR*, LPSECURITY_ATTRIBUTES) {
+    return true;
+  }
+  bool Initialize(const TCHAR*) { return true; }
+  virtual bool Lock() const { return true; }
+  virtual bool Lock(DWORD) const { return true; }
+  virtual bool Unlock() const { return true; }
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(FakeGLock);
+};
+
+// LLock stands for local lock.
+// means works only inside the process.
+// use GLock - global lock for inter-process
+// guarded access to data.
+class LLock : public Lockable {
+ public:
+  LLock();
+  virtual ~LLock();
+  virtual bool Lock() const;
+  virtual bool Lock(DWORD wait_ms) const;
+  virtual bool Unlock() const;
+ private:
+  mutable CRITICAL_SECTION        critical_section_;
+  DISALLOW_EVIL_CONSTRUCTORS(LLock);
+};
+
+// A gate is a synchronization object used to either stop all
+// threads from proceeding through a point or to allow them all to proceed.
+class Gate {
+ public:
+  // In process gate.
+  Gate();
+
+  // Interprocess gate.
+  explicit Gate(const TCHAR * event_name);
+
+  ~Gate();
+
+  // Open the gate.
+  bool Open();
+
+  // Close the gate.
+  bool Close();
+
+  // Wait to enter the gate.
+  bool Wait(DWORD msec);
+
+  // Conversion from the object to a HANDLE.
+  operator HANDLE() const {return gate_;}
+
+  // Returns S_OK, and sets selected_gate to zero based index of the gate that
+  // was opened.
+  // Returns E_FAIL if timeout occured or gate was abandoned.
+  static HRESULT WaitAny(Gate const * const *gates,
+                         int num_gates,
+                         DWORD msec,
+                         int *selected_gate);
+
+  // Returns S_OK if all gates were opened
+  // Returns E_FAIL if timeout occured or gate was abandoned.
+  static HRESULT WaitAll(Gate const * const *gates, int num_gates, DWORD msec);
+
+ private:
+  bool Initialize(const TCHAR * event_name);
+  static HRESULT WaitMultipleHelper(Gate const * const *gates,
+                                    int num_gates,
+                                    DWORD msec,
+                                    int *selected_gate,
+                                    bool wait_all);
+  HANDLE gate_;
+  DISALLOW_EVIL_CONSTRUCTORS(Gate);
+};
+
+bool WaitAllowRepaint(const Gate& gate, DWORD msec);
+
+class AutoGateKeeper {
+ public:
+  explicit AutoGateKeeper(Gate *gate) : gate_(gate) {
+    gate_->Open();
+  }
+  ~AutoGateKeeper() {
+    gate_->Close();
+  }
+ private:
+  Gate *gate_;
+  DISALLOW_EVIL_CONSTRUCTORS(AutoGateKeeper);
+};
+
+// A very simple rather fast lock - if uncontested.  USE ONLY AS A GLOBAL OBJECT
+// (i.e., DECLARED AT FILE SCOPE or as a STATIC CLASS MEMBER) - this is not
+// enforced.  Uses interlocked instructions on an int to get a fast user-mode
+// lock.  (Locks the bus and does a couple of memory references so it isn't
+// free.)  Spin-waits to get the lock.  Has the advantage that it needs no
+// initialization - thus has no order-of-evaluation problems with respect to
+// other global objects.  Does not work (causes deadlock) if locked twice by
+// the same thread. (Has no constructor so is initialized to 0 by C++.
+// This is why it must be a global or static class member: it doesn't initialize
+// itself to 0.  This is also why it doesn't inherit from Lockable, which would
+// make it need to initialize a virtual table.)
+struct SimpleLock {
+  bool Lock() const;
+  bool Unlock() const;
+ private:
+  mutable volatile long lock_;
+};
+
+struct SimpleLockWithDelay {
+  bool Lock() const;
+  bool Unlock() const;
+ private:
+  mutable volatile long lock_;
+};
+
+class AutoSimpleLock {
+ public:
+  explicit AutoSimpleLock(const SimpleLock& lock)
+      : lock_(lock) { lock_.Lock(); }
+  ~AutoSimpleLock() { lock_.Unlock(); }
+ private:
+  const SimpleLock& lock_;
+  DISALLOW_EVIL_CONSTRUCTORS(AutoSimpleLock);
+};
+
+class AutoSimpleLockWithDelay {
+ public:
+  explicit AutoSimpleLockWithDelay(const SimpleLockWithDelay& lock)
+      : lock_(lock) { lock_.Lock(); }
+  ~AutoSimpleLockWithDelay() { lock_.Unlock(); }
+ private:
+  const SimpleLockWithDelay& lock_;
+  DISALLOW_EVIL_CONSTRUCTORS(AutoSimpleLockWithDelay);
+};
+
+
+// allow only one thread to hold a lock
+class CriticalSection {
+ public:
+  CriticalSection();
+  ~CriticalSection();
+
+  void Enter();
+  void Exit();
+
+ private:
+  CRITICAL_SECTION critical_section_;
+  uint32 number_entries_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(CriticalSection);
+};
+
+// A class that manages a CriticalSection with its lifetime, you pass
+// it one in the constructor and then it will either be freed in the
+// destructor or implicitly [but only once]
+class SingleLock {
+ public:
+  // TODO(omaha): Not sure if immediately locking is a good idea;
+  // the API is asymmetrical (there's an Unlock but no Lock).
+
+  // Lock a critical section immediately
+  explicit SingleLock(CriticalSection * cs);
+
+  // If we have not explicitly unlocked it, this destructor will
+  ~SingleLock();
+
+  // Release the lock explicitly [should be called only once, after that
+  // does nothing. If we do not do so, the destructor will]
+  HRESULT Unlock();
+
+ private:
+  CriticalSection * critical_section_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(SingleLock);
+};
+
+// Encapsulation for kernel Event. Initializes and destroys with it's lifetime
+class EventObj {
+ public:
+  explicit EventObj(const TCHAR * event_name) {
+    Init(event_name);
+  }
+  ~EventObj();
+  void Init(const TCHAR * event_name);
+  BOOL SetEvent();
+  HANDLE GetHandle() { return h_; }
+
+ private:
+  HANDLE h_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(EventObj);
+};
+
+// Is the given handle signaled?
+//
+// Typically used for events.
+bool IsHandleSignaled(HANDLE h);
+
+
+enum SyncScope {
+  // local to a session
+  SYNC_LOCAL,
+
+  // global scope but the name is decorated to make it unique for the user
+  SYNC_USER,
+
+  // a globally scoped name
+  SYNC_GLOBAL,
+};
+
+// Create an id for the events/mutexes that can be used at the given scope
+void CreateSyncId(const TCHAR* id, SyncScope scope, CString* sync_id);
+
+// If any place needs to create a mutex that multiple
+// processes need to access, use this.
+HANDLE CreateMutexWithSyncAccess(const TCHAR* name,
+                                 LPSECURITY_ATTRIBUTES lock_attributes);
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SYNCHRONIZED_H__
+
diff --git a/common/system.cc b/common/system.cc
index 06b8f51..41095f8 100644
--- a/common/system.cc
+++ b/common/system.cc
@@ -1,1033 +1,1033 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/system.h"

-

-#include <objidl.h>

-#include <psapi.h>

-#include <winioctl.h>

-#include <wtsapi32.h>

-#include "omaha/common/commands.h"

-#include "omaha/common/const_config.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/disk.h"

-#include "omaha/common/dynamic_link_kernel32.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/module_utils.h"

-#include "omaha/common/path.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-// Constant

-const TCHAR kNeedRebootHiddenFileSuffix[] = _T(".needreboot");

-

-HRESULT System::WaitForDiskActivity(const uint32 max_delay_milliseconds,

-                                    const uint32 sleep_time_ms,

-                                    uint32 *time_waited) {

-  ASSERT(time_waited, (L""));

-  uint32 sleep_time = sleep_time_ms;

-  if (sleep_time < 20) { sleep_time = 20; }

-  else if (sleep_time > 1000) { sleep_time = 1000; }

-  HRESULT r;

-  *time_waited = 0;

-  uint64 writes = 0;

-  uint64 new_writes = 0;

-  // get current counters

-  if (FAILED(r=GetDiskActivityCounters(NULL, &writes, NULL, NULL))) {

-    return r;

-  }

-

-  // wait until a write - reads may be cached

-  while (1) {

-    if (FAILED(r=GetDiskActivityCounters(NULL, &new_writes, NULL, NULL))) {

-      return r;

-    }

-    if (new_writes > writes) { return S_OK; }

-    if (*time_waited > max_delay_milliseconds) { return E_FAIL; }

-    SleepEx(sleep_time, TRUE);

-    *time_waited += sleep_time;

-  }

-}

-

-HRESULT System::GetDiskActivityCounters(uint64* reads,

-                                        uint64* writes,

-                                        uint64* bytes_read,

-                                        uint64* bytes_written) {

-  if (reads) {

-    *reads = 0;

-  }

-

-  if (writes) {

-    *writes = 0;

-  }

-

-  if (bytes_read) {

-    *bytes_read = 0;

-  }

-

-  if (bytes_written) {

-    *bytes_written = 0;

-  }

-

-  // Don't want to risk displaying UI errors here

-  DisableThreadErrorUI disable_error_dialog_box;

-

-  // for all drives

-  for (int drive = 0; ; drive++) {

-    struct _DISK_PERFORMANCE perf_data;

-    const int max_device_len = 50;

-

-    // check whether we can access this device

-    CString device_name;

-    device_name.Format(_T("\\\\.\\PhysicalDrive%d"), drive);

-    scoped_handle device(::CreateFile(device_name, 0,

-                                      FILE_SHARE_READ | FILE_SHARE_WRITE,

-                                      NULL, OPEN_EXISTING, 0, NULL));

-

-    if (get(device) == INVALID_HANDLE_VALUE) {

-      if (!drive) {

-        UTIL_LOG(LEVEL_ERROR, (_T("[Failed to access drive %i][0x%x]"),

-                               drive,

-                               HRESULTFromLastError()));

-      }

-      break;

-    }

-

-    // disk performance counters must be on (diskperf -y on older machines;

-    // defaults to on on newer windows)

-    DWORD size = 0;

-    if (::DeviceIoControl(get(device),

-                          IOCTL_DISK_PERFORMANCE,

-                          NULL,

-                          0,

-                          &perf_data,

-                          sizeof(_DISK_PERFORMANCE),

-                          &size,

-                          NULL)) {

-      if (reads) {

-        *reads += perf_data.ReadCount;

-      }

-

-      if (writes) {

-        *writes += perf_data.WriteCount;

-      }

-

-      if (bytes_read) {

-        *bytes_read += perf_data.BytesRead.QuadPart;

-      }

-

-      if (bytes_written) {

-        *bytes_written += perf_data.BytesWritten.QuadPart;

-      }

-    } else {

-      HRESULT hr = HRESULTFromLastError();

-      UTIL_LOG(LEVEL_ERROR,

-               (_T("[System::GetDiskActivityCounters - failed to ")

-                _T("DeviceIoControl][0x%x]"), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT System::GetDiskStatistics(const TCHAR* path,

-                                  uint64 *free_bytes_current_user,

-                                  uint64 *total_bytes_current_user,

-                                  uint64 *free_bytes_all_users) {

-  ASSERT1(path);

-  ASSERT1(free_bytes_current_user);

-  ASSERT1(total_bytes_current_user);

-  ASSERT1(free_bytes_all_users);

-  ASSERT1(sizeof(LARGE_INTEGER) == sizeof(uint64));  // NOLINT

-

-  DisableThreadErrorUI disable_error_dialog_box;

-

-  if (!::GetDiskFreeSpaceEx(

-           path,

-           reinterpret_cast<PULARGE_INTEGER>(free_bytes_current_user),

-           reinterpret_cast<PULARGE_INTEGER>(total_bytes_current_user),

-           reinterpret_cast<PULARGE_INTEGER>(free_bytes_all_users))) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[Failed to GetDiskFreeSpaceEx][%s][0x%x]"), path, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT System::GetProcessMemoryStatistics(uint64 *current_working_set,

-                                           uint64 *peak_working_set,

-                                           uint64 *min_working_set_size,

-                                           uint64 *max_working_set_size) {

-  HANDLE process_handle = GetCurrentProcess();

-  HRESULT hr = S_OK;

-

-  DWORD min_size(0), max_size(0);

-  if (GetProcessWorkingSetSize(process_handle, &min_size, &max_size)) {

-    UTIL_LOG(L2, (_T("working set %lu %lu"), min_size, max_size));

-    if (min_working_set_size) {

-      *min_working_set_size = min_size;

-    }

-    if (max_working_set_size) {

-      *max_working_set_size = max_size;

-    }

-  } else {

-    if (min_working_set_size) {

-      *min_working_set_size = 0;

-    }

-    if (max_working_set_size) {

-      *max_working_set_size = 0;

-    }

-    hr = E_FAIL;

-  }

-

-  if (current_working_set) { *current_working_set = 0; }

-  if (peak_working_set) { *peak_working_set = 0; }

-

-  // including this call (w/psapi.lib) adds 24k to the process memory

-  // according to task manager in one test, memory usage according to task

-  // manager increased by 4k after calling this

-  PROCESS_MEMORY_COUNTERS counters = { sizeof(counters), 0 };

-  if (GetProcessMemoryInfo(process_handle,

-                           &counters,

-                           sizeof(PROCESS_MEMORY_COUNTERS))) {

-    if (current_working_set) {

-      *current_working_set = counters.WorkingSetSize;

-    }

-    if (peak_working_set) {

-      *peak_working_set = counters.PeakWorkingSetSize;

-    }

-    UTIL_LOG(L2, (_T("current/peak working set %s %s"),

-                  String_Int64ToString(*current_working_set, 10),

-                  String_Int64ToString(*peak_working_set, 10)));

-  } else {

-    if (current_working_set) {

-      *current_working_set = 0;

-    }

-    if (peak_working_set) {

-      *peak_working_set = 0;

-    }

-    hr = E_FAIL;

-  }

-

-  return hr;

-}

-

-HRESULT System::MaxPhysicalMemoryAvailable(uint64* max_bytes) {

-  ASSERT1(max_bytes);

-

-  *max_bytes = 0;

-

-  uint32 memory_load_percentage = 0;

-  uint64 free_physical_memory = 0;

-

-  RET_IF_FAILED(System::GetGlobalMemoryStatistics(&memory_load_percentage,

-    &free_physical_memory, NULL, NULL, NULL, NULL, NULL));

-

-  UTIL_LOG(L4, (_T("mem load %u max physical memory available %s"),

-                memory_load_percentage,

-                String_Int64ToString(free_physical_memory, 10)));

-

-  *max_bytes = free_physical_memory;

-

-  return S_OK;

-}

-

-HRESULT System::GetGlobalMemoryStatistics(uint32 *memory_load_percentage,

-                                          uint64 *free_physical_memory,

-                                          uint64 *total_physical_memory,

-                                          uint64 *free_paged_memory,

-                                          uint64 *total_paged_memory,

-                                          uint64 *process_free_virtual_memory,

-                                          uint64 *process_total_virtual_mem) {

-  MEMORYSTATUSEX status;

-  status.dwLength = sizeof(status);

-  if (!GlobalMemoryStatusEx(&status)) {

-    UTIL_LOG(LEVEL_ERROR, (_T("memory status error %u"), GetLastError()));

-    return E_FAIL;

-  }

-  if (memory_load_percentage) { *memory_load_percentage = status.dwMemoryLoad; }

-  if (free_physical_memory) { *free_physical_memory = status.ullAvailPhys; }

-  if (total_physical_memory) { *total_physical_memory = status.ullTotalPhys; }

-  if (free_paged_memory) { *free_paged_memory = status.ullAvailPageFile; }

-  if (total_paged_memory) { *total_paged_memory = status.ullTotalPageFile; }

-  if (process_free_virtual_memory) {

-    *process_free_virtual_memory = status.ullAvailVirtual;

-  }

-  if (process_total_virtual_mem) {

-    *process_total_virtual_mem = status.ullTotalVirtual;

-  }

-  // GetPerformanceInfo;

-  return S_OK;

-}

-

-void System::FreeProcessWorkingSet() {

-  // -1,-1 is a special signal to the OS to temporarily trim the working set

-  // size to 0.  See MSDN for further information.

-  ::SetProcessWorkingSetSize(::GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1);

-}

-

-HRESULT System::SetThreadPriority(enum Priority priority) {

-  int pri;

-

-  switch (priority) {

-    case LOW: pri = THREAD_PRIORITY_BELOW_NORMAL; break;

-    case HIGH: pri = THREAD_PRIORITY_HIGHEST; break;

-    case NORMAL: pri = THREAD_PRIORITY_NORMAL; break;

-    case IDLE: pri = THREAD_PRIORITY_IDLE; break;

-    default: return E_FAIL;

-  }

-

-  if (::SetThreadPriority(GetCurrentThread(), pri)) {

-    return S_OK;

-  } else {

-    return E_FAIL;

-  }

-}

-

-HRESULT System::SetProcessPriority(enum Priority priority) {

-  DWORD pri = 0;

-  switch (priority) {

-    case LOW: pri = BELOW_NORMAL_PRIORITY_CLASS; break;

-    case HIGH: pri = ABOVE_NORMAL_PRIORITY_CLASS; break;

-    case NORMAL: pri = NORMAL_PRIORITY_CLASS; break;

-    case IDLE: return E_INVALIDARG;

-    default: return E_INVALIDARG;

-  }

-

-  DWORD pid = ::GetCurrentProcessId();

-

-  scoped_handle handle(::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid));

-  if (!valid(handle)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LE, (_T("[::OpenProcess failed][%u][0x%x]"), pid, hr));

-    return hr;

-  }

-

-  if (!::SetPriorityClass(get(handle), pri)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LE, (_T("[::SetPriorityClass failed][%u][0x%x]"), pid, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// start another process painlessly via ::CreateProcess. Use the

-// ShellExecuteProcessXXX variants instead of these methods where possible,

-// since ::ShellExecuteEx has better behavior on Windows Vista.

-// When using this method, avoid using process_name - see

-// http://blogs.msdn.com/oldnewthing/archive/2006/05/15/597984.aspx.

-HRESULT System::StartProcess(const TCHAR* process_name,

-                             TCHAR* command_line,

-                             PROCESS_INFORMATION* pi) {

-  ASSERT1(pi);

-  ASSERT1(command_line || process_name);

-  ASSERT(!process_name, (_T("Avoid using process_name. See method comment.")));

-

-  STARTUPINFO si = {sizeof(si), 0};

-

-  // Feedback cursor is off while the process is starting.

-  si.dwFlags = STARTF_FORCEOFFFEEDBACK;

-

-  UTIL_LOG(L3, (_T("[System::StartProcess][process %s][cmd %s]"),

-                process_name, command_line));

-

-  BOOL success = ::CreateProcess(

-      process_name,     // Module name

-      command_line,     // Command line

-      NULL,             // Process handle not inheritable

-      NULL,             // Thread handle not inheritable

-      FALSE,            // Set handle inheritance to FALSE

-      0,                // No creation flags

-      NULL,             // Use parent's environment block

-      NULL,             // Use parent's starting directory

-      &si,              // Pointer to STARTUPINFO structure

-      pi);              // Pointer to PROCESS_INFORMATION structure

-

-  if (!success) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[System::StartProcess][::CreateProcess failed][0x%x]"), hr));

-    return hr;

-  }

-

-  OPT_LOG(L1, (_T("[Started process][%u]"), pi->dwProcessId));

-

-  return S_OK;

-}

-

-// start another process painlessly via ::CreateProcess. Use the

-// ShellExecuteProcessXXX variants instead of these methods where possible,

-// since ::ShellExecuteEx has better behavior on Windows Vista.

-HRESULT System::StartProcessWithArgsAndInfo(const TCHAR *process_name,

-                                            const TCHAR *cmd_line_arguments,

-                                            PROCESS_INFORMATION *pi) {

-  ASSERT1(process_name && cmd_line_arguments && pi);

-

-  CString command_line(process_name);

-  EnclosePath(&command_line);

-  command_line.AppendChar(_T(' '));

-  command_line.Append(cmd_line_arguments);

-  return System::StartProcess(NULL, command_line.GetBuffer(), pi);

-}

-

-// start another process painlessly via ::CreateProcess. Use the

-// ShellExecuteProcessXXX variants instead of these methods where possible,

-// since ::ShellExecuteEx has better behavior on Windows Vista.

-HRESULT System::StartProcessWithArgs(const TCHAR *process_name,

-                                     const TCHAR *cmd_line_arguments) {

-  ASSERT1(process_name && cmd_line_arguments);

-  PROCESS_INFORMATION pi = {0};

-  HRESULT hr = System::StartProcessWithArgsAndInfo(process_name,

-                                                   cmd_line_arguments,

-                                                   &pi);

-  if (SUCCEEDED(hr)) {

-    ::CloseHandle(pi.hProcess);

-    ::CloseHandle(pi.hThread);

-  }

-  return hr;

-}

-

-// start another process painlessly via ::ShellExecuteEx. Use this method

-// instead of the StartProcessXXX methods that use ::CreateProcess where

-// possible, since ::ShellExecuteEx has better behavior on Windows Vista.

-//

-// ShellExecuteExEnsureParent displays the PID of the started process if it is

-// returned. It is only returned if the mask includes SEE_MASK_NOCLOSEPROCESS.

-// Therefore, we always set this flag and pass a handle. If the caller did not

-// request the handle, we close it.

-HRESULT System::ShellExecuteProcess(const TCHAR* file_name_to_execute,

-                                    const TCHAR* command_line_parameters,

-                                    HWND hwnd,

-                                    HANDLE* process_handle) {

-  ASSERT1(file_name_to_execute);

-

-  UTIL_LOG(L3, (_T("[System::ShellExecuteProcess]")

-                _T("[file_name_to_execute '%s' command_line_parameters '%s']"),

-                file_name_to_execute, command_line_parameters));

-

-  SHELLEXECUTEINFO sei = {0};

-  sei.cbSize = sizeof(sei);

-  // SEE_MASK_NOZONECHECKS is set below to work around a problem in systems that

-  // had Internet Explorer 7 Beta installed. See http://b/804674.

-  // This only works for Windows XP SP1 and later.

-  sei.fMask = SEE_MASK_NOCLOSEPROCESS |  // Set hProcess to process handle.

-              SEE_MASK_FLAG_NO_UI     |  // Do not display an error message box.

-              SEE_MASK_NOZONECHECKS   |  // Do not perform a zone check.

-              SEE_MASK_NOASYNC;          // Wait to complete before returning.

-  sei.lpVerb = _T("open");

-  sei.lpFile = file_name_to_execute;

-  sei.lpParameters = command_line_parameters;

-  sei.nShow = SW_SHOWNORMAL;

-  sei.hwnd = hwnd;

-

-  // Use ShellExecuteExEnsureParent to ensure that we always have a parent

-  // window. We need to use the HWND property to be acknowledged as a foreground

-  // application on Windows Vista. Otherwise, the elevation prompt will appear

-  // minimized on the taskbar.

-  if (!ShellExecuteExEnsureParent(&sei)) {

-    HRESULT hr(HRESULTFromLastError());

-    OPT_LOG(LEVEL_ERROR, (_T("[Failed to ::ShellExecuteEx][%s][%s][0x%08x]"),

-                          file_name_to_execute, command_line_parameters, hr));

-    return hr;

-  }

-

-  if (process_handle) {

-    *process_handle = sei.hProcess;

-  } else {

-    ::CloseHandle(sei.hProcess);

-  }

-

-  return S_OK;

-}

-

-// start another process painlessly via ::ShellExecuteEx. Use this method

-// instead of the StartProcessXXX methods that use ::CreateProcess where

-// possible, since ::ShellExecuteEx has better behavior on Windows Vista.

-HRESULT System::ShellExecuteCommandLine(const TCHAR* command_line_to_execute,

-                                        HWND hwnd,

-                                        HANDLE* process_handle) {

-  ASSERT1(command_line_to_execute);

-

-  CString exe;

-  CString args;

-

-  HRESULT hr = CommandParsingSimple::SplitExeAndArgs(command_line_to_execute,

-                                                     &exe,

-                                                     &args);

-

-  if (SUCCEEDED(hr)) {

-    hr = System::ShellExecuteProcess(exe, args, hwnd, process_handle);

-    if (FAILED(hr)) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[System::ShellExecuteProcess failed]")

-                             _T("[%s][%s][0x%08x]"), exe, args, hr));

-    }

-  }

-

-  return hr;

-}

-

-// returns the number of ms the system has had no user input

-int System::GetUserIdleTime() {

-  LASTINPUTINFO last_input_info;

-  last_input_info.cbSize = sizeof(LASTINPUTINFO);

-  // get time in windows ticks since system start of last activity

-  BOOL b = GetLastInputInfo(&last_input_info);

-  if (b == TRUE) {

-    return (GetTickCount()-last_input_info.dwTime);  // compute idle time

-  }

-  return 0;

-}

-

-bool System::IsUserIdle() {

-  // Only notify when the user has been idle less than this time

-  static int user_idle_threshold_ms = kUserIdleThresholdMs;

-

-  bool is_user_idle = (GetUserIdleTime() > user_idle_threshold_ms);

-  UTIL_LOG(L2, (_T("System::IsUserIdle() %s; user_idle_threshold_ms = %d"),

-                is_user_idle ? _T("TRUE") : _T("FALSE"),

-                user_idle_threshold_ms));

-  return is_user_idle;

-}

-

-bool System::IsUserBusy() {

-  // The user is busy typing or interacting with another application

-  // if the user is below the minimum threshold:

-  static int user_idle_min_threshold_ms = kUserIdleMinThresholdMs;

-  // The user is probably not paying attention

-  // if the user is above the maximum threshold:

-  static int user_idle_max_threshold_ms = kUserIdleMaxThresholdMs;

-

-  int user_idle_time = GetUserIdleTime();

-  bool is_user_busy = user_idle_time < user_idle_min_threshold_ms ||

-    user_idle_time > user_idle_max_threshold_ms;

-  UTIL_LOG(L2, (_T("[System::IsUserBusy() %s][user_idle_time = %d]")

-                _T("[user_idle_min_threshold_ms = %d]")

-                _T("[user_idle_max_threshold_ms = %d]"),

-                is_user_busy? _T("TRUE") : _T("FALSE"),

-                user_idle_time,

-                user_idle_min_threshold_ms,

-                user_idle_max_threshold_ms));

-  return is_user_busy;

-}

-

-bool System::IsScreensaverRunning() {

-  // NT 4.0 and below require testing OpenDesktop("screen-saver")

-  // We require W2K or better so we have an easier way

-  DWORD result = 0;

-  ::SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &result, 0);

-  bool is_screensaver_running = (result != FALSE);

-  UTIL_LOG(L2, (_T("System::IsScreensaverRunning() %s"),

-                is_screensaver_running? _T("TRUE") : _T("FALSE")));

-  return is_screensaver_running;

-}

-

-bool System::IsWorkstationLocked() {

-  bool is_workstation_locked = true;

-  HDESK inputdesk = ::OpenInputDesktop(0, 0, GENERIC_READ);

-  if (NULL != inputdesk)  {

-    TCHAR name[256];

-    DWORD needed = arraysize(name);

-    BOOL ok = ::GetUserObjectInformation(inputdesk,

-                                         UOI_NAME,

-                                         name,

-                                         sizeof(name),

-                                         &needed);

-    ::CloseDesktop(inputdesk);

-    if (ok) {

-      is_workstation_locked = (0 != lstrcmpi(name, NOTRANSL(_T("default"))));

-    }

-  }

-

-  UTIL_LOG(L2, (_T("System::IsWorkstationLocked() %s"),

-                is_workstation_locked? _T("TRUE") : _T("FALSE")));

-  return is_workstation_locked;

-}

-

-bool System::IsUserAway() {

-  return IsScreensaverRunning() || IsWorkstationLocked();

-}

-

-uint32 System::GetProcessHandleCount() {

-  typedef LONG (CALLBACK *Fun)(HANDLE, int32, PVOID, ULONG, PULONG);

-

-  // This new version of getting the number of open handles works on win2k.

-  HMODULE h = GetModuleHandle(_T("ntdll.dll"));

-  Fun NtQueryInformationProcess =

-      reinterpret_cast<Fun>(::GetProcAddress(h, "NtQueryInformationProcess"));

-

-  if (!NtQueryInformationProcess) {

-    UTIL_LOG(LEVEL_ERROR, (_T("[NtQueryInformationProcess failed][0x%x]"),

-                           HRESULTFromLastError()));

-    return 0;

-  }

-

-  DWORD count = 0;

-  VERIFY(NtQueryInformationProcess(GetCurrentProcess(),

-                                   kProcessHandleCount,

-                                   &count,

-                                   sizeof(count),

-                                   NULL) >= 0, (L""));

-

-  return count;

-}

-

-uint32 System::GetProcessHandleCountOld() {

-  typedef BOOL (CALLBACK * Fun)(HANDLE, PDWORD);

-

-  // GetProcessHandleCount not available on win2k

-  HMODULE handle = GetModuleHandle(_T("kernel32"));

-  Fun f = reinterpret_cast<Fun>(GetProcAddress(handle,

-                                               "GetProcessHandleCount"));

-

-  if (!f) return 0;

-

-  DWORD count = 0;

-  VERIFY((*f)(GetCurrentProcess(), &count), (L""));

-  return count;

-

-  //  DWORD GetGuiResources (HANDLE hProcess, DWORD uiFlags);

-  //  Parameters, hProcess

-  //  [in] Handle to the process. The handle must have the

-  //  PROCESS_QUERY_INFORMATION access right. For more information, see Process

-  //  Security and Access Rights.

-  //  uiFlags

-  //  [in] GUI object type. This parameter can be one of the following values.

-  //  Value          Meaning

-  //  GR_GDIOBJECTS  Return the count of GDI objects.

-  //  GR_USEROBJECTS Return the count of USER objects.

-}

-

-void System::GetGuiObjectCount(uint32 *gdi, uint32 *user) {

-  if (gdi) {

-    *gdi = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);

-  }

-  if (user) {

-    *user = GetGuiResources(GetCurrentProcess(), GR_USEROBJECTS);

-  }

-}

-

-HRESULT System::GetRebootCheckDummyFileName(const TCHAR* base_file,

-                                            CString* dummy_file) {

-  ASSERT1(dummy_file);

-

-  if (base_file && *base_file) {

-    ASSERT1(File::Exists(base_file));

-    dummy_file->SetString(base_file);

-  } else {

-    RET_IF_FAILED(GetModuleFileName(NULL, dummy_file));

-  }

-  dummy_file->Append(_T(".needreboot"));

-  return S_OK;

-}

-

-// Is the system being rebooted?

-bool System::IsRebooted(const TCHAR* base_file) {

-  CString dummy_file;

-  if (SUCCEEDED(GetRebootCheckDummyFileName(base_file, &dummy_file))) {

-    if (File::Exists(dummy_file)) {

-      // If the file exists but it is not found in the

-      // PendingFileRenameOperations, (probably becaused that this key is messed

-      // up and thus the system restart fails to delete the file), re-add it

-      if (!File::AreMovesPendingReboot(dummy_file, true)) {

-        File::MoveAfterReboot(dummy_file, NULL);

-      }

-      return false;

-    } else {

-      return true;

-    }

-  }

-  return false;

-}

-

-// Mark the system as reboot required

-HRESULT System::MarkAsRebootRequired(const TCHAR* base_file) {

-  // Create a dummy file if needed

-  CString dummy_file;

-  RET_IF_FAILED(GetRebootCheckDummyFileName(base_file, &dummy_file));

-  if (File::Exists(dummy_file)) {

-    return S_OK;

-  }

-

-  File file;

-  RET_IF_FAILED(file.Open(dummy_file, true, false));

-  RET_IF_FAILED(file.Close());

-

-  // Hide it

-  DWORD file_attr = ::GetFileAttributes(dummy_file);

-  if (file_attr == INVALID_FILE_ATTRIBUTES ||

-      !::SetFileAttributes(dummy_file, file_attr | FILE_ATTRIBUTE_HIDDEN)) {

-    return HRESULTFromLastError();

-  }

-

-  // Mark it as being deleted after reboot

-  return File::MoveAfterReboot(dummy_file, NULL);

-}

-

-// Unmark the system as reboot required

-HRESULT System::UnmarkAsRebootRequired(const TCHAR* base_file) {

-  CString dummy_file;

-  RET_IF_FAILED(GetRebootCheckDummyFileName(base_file, &dummy_file));

-

-  return File::RemoveFromMovesPendingReboot(dummy_file, false);

-}

-

-// Restart the computer

-HRESULT System::RestartComputer() {

-  RET_IF_FAILED(AdjustPrivilege(SE_SHUTDOWN_NAME, true));

-

-  if (!::ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION |

-                       SHTDN_REASON_MINOR_INSTALLATION |

-                       SHTDN_REASON_FLAG_PLANNED)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[System::RestartComputer - failed to")

-                           _T(" ExitWindowsEx][0x%x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// The implementation works on all Windows versions. On NT and XP the screen

-// saver is actually stored in registry at

-// HKEY_CURRENT_USER\Control Panel\Desktop\SCRNSAVE.EXE but the

-// GetPrivateProfileString call is automatically mapped to the registry

-HRESULT System::GetCurrentScreenSaver(CString* fileName) {

-  if (!fileName) return E_POINTER;

-

-  DWORD nChars = ::GetPrivateProfileString(_T("boot"),

-                                           _T("SCRNSAVE.EXE"),

-                                           _T(""),

-                                           fileName->GetBuffer(MAX_PATH),

-                                           MAX_PATH,

-                                           _T("system.ini"));

-  fileName->ReleaseBufferSetLength(nChars);

-

-  return S_OK;

-}

-

-// Create an instance of a COM Local Server class using either plain vanilla

-// CoCreateInstance, or using the Elevation moniker depending on the operating

-// system

-HRESULT System::CoCreateInstanceAsAdmin(HWND hwnd,

-                                        REFCLSID rclsid,

-                                        REFIID riid,

-                                        void** ppv) {

-  if (SystemInfo::IsRunningOnVistaOrLater()) {

-    // Use the Elevation Moniker to create the Install Manager in Windows Vista.

-    // If the UI is running in medium integrity, this will result in a

-    // elevation prompt

-

-    scoped_window hwnd_parent;

-

-    if (!hwnd) {

-      reset(hwnd_parent, CreateForegroundParentWindowForUAC());

-

-      if (!hwnd_parent) {

-        return HRESULTFromLastError();

-      }

-      // Use the newly created dummy window as the hwnd

-      hwnd = get(hwnd_parent);

-    }

-

-    CString moniker_name(_T("Elevation:Administrator!new:"));

-    moniker_name += GuidToString(rclsid);

-    BIND_OPTS3 bo;

-    SetZero(bo);

-    bo.cbStruct = sizeof(bo);

-    bo.hwnd = hwnd;

-    bo.dwClassContext = CLSCTX_LOCAL_SERVER;

-

-    return ::CoGetObject(moniker_name, &bo, riid, ppv);

-  } else {

-    // Use plain-vanilla ::CoCreateInstance()

-    return ::CoCreateInstance(rclsid, NULL, CLSCTX_LOCAL_SERVER, riid, ppv);

-  }

-}

-

-HRESULT System::IsPrivilegeEnabled(const TCHAR* privilege, bool* present) {

-  ASSERT1(privilege);

-  ASSERT1(present);

-

-  *present = false;

-

-  scoped_handle token;

-  if (!::OpenProcessToken(::GetCurrentProcess(),

-                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,

-                          address(token))) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[System::IsPrivilegeEnabled - failed to ")

-                           _T("OpenProcessToken][0x%x]"), hr));

-    return hr;

-  }

-

-  LUID luid = {0};

-  if (!::LookupPrivilegeValue(NULL, privilege, &luid)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[System::IsPrivilegeEnabled - failed to")

-                           _T("LookupPrivilegeValue][0x%x]"), hr));

-    return hr;

-  }

-

-  PRIVILEGE_SET required_privilege = {0};

-  required_privilege.PrivilegeCount = 1;

-  required_privilege.Control = PRIVILEGE_SET_ALL_NECESSARY;

-  required_privilege.Privilege[0].Luid = luid;

-

-  BOOL result = FALSE;

-  if (!::PrivilegeCheck(get(token), &required_privilege, &result)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[System::IsPrivilegeEnabled - failed to")

-                           _T("PrivilegeCheck][0x%x]"), hr));

-    return hr;

-  }

-

-  if (required_privilege.Privilege[0].Attributes &

-      SE_PRIVILEGE_USED_FOR_ACCESS) {

-    *present = true;

-  }

-

-  return S_OK;

-}

-

-// Attempts to adjust current process privileges.

-// Only process running with administrator privileges will succeed.

-HRESULT System::AdjustPrivilege(const TCHAR* privilege, bool enable) {

-  ASSERT1(privilege);

-

-  scoped_handle token;

-  if (!::OpenProcessToken(::GetCurrentProcess(),

-                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,

-                          address(token))) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[System::AdjustPrivilege - failed to ")

-                           _T("OpenProcessToken][0x%x]"), hr));

-    return hr;

-  }

-

-  LUID luid = {0};

-  if (!::LookupPrivilegeValue(NULL, privilege, &luid)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[System::AdjustPrivilege - failed to")

-                           _T("LookupPrivilegeValue][0x%x]"), hr));

-    return hr;

-  }

-

-  TOKEN_PRIVILEGES privs;

-  privs.PrivilegeCount = 1;

-  privs.Privileges[0].Luid = luid;

-  privs.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;

-

-  if (!::AdjustTokenPrivileges(get(token), FALSE, &privs, 0, NULL, 0)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[System::AdjustPrivilege - failed to ")

-                           _T("AdjustTokenPrivileges][0x%x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-DWORD System::WTSGetActiveConsoleSessionId()  {

-  typedef DWORD (* Fun)();

-

-  HINSTANCE hInst = ::GetModuleHandle(_T("kernel32.dll"));

-  ASSERT1(hInst);

-  Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(

-                                      hInst,

-                                      "WTSGetActiveConsoleSessionId"));

-  return !pfn ? kInvalidSessionId : (*pfn)();

-}

-

-// Get the session the current process is running under

-DWORD System::GetCurrentSessionId() {

-  DWORD session_id = kInvalidSessionId;

-  DWORD* session_id_ptr = NULL;

-  DWORD bytes_returned = 0;

-

-  if (::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,

-                                   WTS_CURRENT_SESSION,

-                                   WTSSessionId,

-                                   reinterpret_cast<LPTSTR*>(&session_id_ptr),

-                                   &bytes_returned)) {

-    ASSERT1(bytes_returned == sizeof(*session_id_ptr));

-    session_id = *session_id_ptr;

-    ::WTSFreeMemory(session_id_ptr);

-    UTIL_LOG(L6, (_T("[System::GetCurrentSessionId]")

-                  _T("[session_id from ::WTSQuerySessionInformation][%d]"),

-                  session_id));

-    return session_id;

-  }

-

-  // ::WTSQuerySessionInformation can fail if we are not running

-  // in a Terminal Services scenario, in which case, we use

-  // ::ProcessIdToSessionId()

-  if (::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id)) {

-    UTIL_LOG(L6,  (_T("[System::GetCurrentSessionId]")

-                   _T("[session_id from ::ProcessIdToSessionId][%d]"),

-                   session_id));

-    return session_id;

-  }

-

-  UTIL_LOG(LEVEL_ERROR,

-           (_T("[System::GetCurrentSessionId - both")

-            _T("::WTSQuerySessionInformation and ")

-            _T("::ProcessIdToSessionId failed][0x%x]"),

-            ::GetLastError()));

-

-  return kInvalidSessionId;

-}

-

-// Get the best guess as to the currently active session, or kInvalidSessionId

-// if there is no active session.

-DWORD System::GetActiveSessionId() {

-  // WTSGetActiveConsoleSessionId retrieves the Terminal Services session

-  // currently attached to the physical console.

-  DWORD active_session_id = WTSGetActiveConsoleSessionId();

-

-  if (IsSessionActive(active_session_id)) {

-    UTIL_LOG(L6, (_T("[System::GetActiveSessionId]")

-                  _T("[Active session id from ::WTSGetActiveConsoleSessionId]")

-                  _T("[%d]"), active_session_id));

-

-    return active_session_id;

-  }

-

-  // WTSGetActiveConsoleSessionId works for FUS, but it does not work for TS

-  // servers where the current active session is always the console. We then use

-  // a different method as below. We get all the sessions that are present on

-  // the system, to see if we can find an active session.

-  active_session_id = kInvalidSessionId;

-  WTS_SESSION_INFO* session_info = NULL;

-  DWORD num_sessions = 0;

-  if (::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1,

-                              &session_info, &num_sessions)) {

-    // Pick the first active session we can find

-    for (DWORD i = 0 ; i < num_sessions; ++i) {

-      if (session_info[i].State == WTSActive) {

-        // There is a user logged on to the WinStation associated with the

-        // session.

-        active_session_id = session_info[i].SessionId;

-        break;

-      }

-    }

-

-    ::WTSFreeMemory(session_info);

-    UTIL_LOG(L6, (_T("[System::GetActiveSessionId]")

-                  _T("[Active session id from ::WTSEnumerateSessions][0x%x]"),

-                  active_session_id));

-

-    return active_session_id;

-  }

-

-  UTIL_LOG(LEVEL_ERROR,

-           (_T("[System::GetActiveSessionId - ")

-           _T("Both ::WTSGetActiveConsoleSessionId and ::WTSEnumerateSessions ")

-           _T("failed][0x%x]"),

-           ::GetLastError()));

-

-  return kInvalidSessionId;

-}

-

-// Is there a user logged on and active in the specified session?

-bool System::IsSessionActive(DWORD session_id) {

-  if (kInvalidSessionId == session_id) {

-    return false;

-  }

-

-  WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;

-  WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;

-  DWORD bytes_returned = 0;

-  if (::WTSQuerySessionInformation(

-          WTS_CURRENT_SERVER_HANDLE,

-          session_id,

-          WTSConnectState,

-          reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),

-          &bytes_returned)) {

-    ASSERT1(bytes_returned == sizeof(*ptr_wts_connect_state));

-    wts_connect_state = *ptr_wts_connect_state;

-    ::WTSFreeMemory(ptr_wts_connect_state);

-

-    UTIL_LOG(L6, (_T("[System::IsSessionActive]")

-                  _T("[wts_connect_state %d]"), wts_connect_state));

-    return WTSActive == wts_connect_state;

-  }

-

-  UTIL_LOG(LE, (_T("[WTSQuerySessionInformation failed][0x%x]"),

-                ::GetLastError()));

-  return false;

-}

-

-// Is the current process running under WinSta0

-bool System::IsCurrentProcessInteractive() {

-  // Use a non-scoped handle, since a handle retrieved via

-  // ::GetProcessWindowStation() should not be closed.

-  HWINSTA handle_window_station(::GetProcessWindowStation());

-  DWORD len = 0;

-  CString str_window_station;

-

-  if (!handle_window_station || handle_window_station == INVALID_HANDLE_VALUE) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[System::IsCurrentProcessInteractive - ")

-              _T("::GetProcessWindowStation() failed (%d)]"),

-              ::GetLastError()));

-    return false;

-  }

-

-  if (!::GetUserObjectInformation(handle_window_station,

-                                  UOI_NAME,

-                                  CStrBuf(str_window_station, MAX_PATH),

-                                  MAX_PATH,

-                                  &len)) {

-    UTIL_LOG(LEVEL_ERROR,

-             (_T("[System::IsCurrentProcessInteractive - ")

-              _T("::GetUserObjectInfoformation(hWinSta) failed (%d)]"),

-              ::GetLastError()));

-    return false;

-  }

-

-  UTIL_LOG(L6, (_T("[System::IsCurrentProcessInteractive]")

-                _T("[WindowStation name][%s]"),

-                str_window_station));

-  return (str_window_station == _T("WinSta0"));

-}

-

-// is the current process running under WinSta0 for the currently active session

-bool System::IsCurrentProcessActiveAndInteractive() {

-  return IsSessionActive(GetCurrentSessionId()) &&

-         IsCurrentProcessInteractive();

-}

-

-bool System::IsRunningOnBatteries() {

-  SYSTEM_POWER_STATUS system_power_status = {0};

-  if (::GetSystemPowerStatus(&system_power_status)) {

-    bool has_battery = !(system_power_status.BatteryFlag & 128);

-    bool ac_status_offline = system_power_status.ACLineStatus == 0;

-    return ac_status_offline && has_battery;

-  }

-  return false;

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/system.h"
+
+#include <objidl.h>
+#include <psapi.h>
+#include <winioctl.h>
+#include <wtsapi32.h>
+#include "omaha/common/commands.h"
+#include "omaha/common/const_config.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/disk.h"
+#include "omaha/common/dynamic_link_kernel32.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/module_utils.h"
+#include "omaha/common/path.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+// Constant
+const TCHAR kNeedRebootHiddenFileSuffix[] = _T(".needreboot");
+
+HRESULT System::WaitForDiskActivity(const uint32 max_delay_milliseconds,
+                                    const uint32 sleep_time_ms,
+                                    uint32 *time_waited) {
+  ASSERT(time_waited, (L""));
+  uint32 sleep_time = sleep_time_ms;
+  if (sleep_time < 20) { sleep_time = 20; }
+  else if (sleep_time > 1000) { sleep_time = 1000; }
+  HRESULT r;
+  *time_waited = 0;
+  uint64 writes = 0;
+  uint64 new_writes = 0;
+  // get current counters
+  if (FAILED(r=GetDiskActivityCounters(NULL, &writes, NULL, NULL))) {
+    return r;
+  }
+
+  // wait until a write - reads may be cached
+  while (1) {
+    if (FAILED(r=GetDiskActivityCounters(NULL, &new_writes, NULL, NULL))) {
+      return r;
+    }
+    if (new_writes > writes) { return S_OK; }
+    if (*time_waited > max_delay_milliseconds) { return E_FAIL; }
+    SleepEx(sleep_time, TRUE);
+    *time_waited += sleep_time;
+  }
+}
+
+HRESULT System::GetDiskActivityCounters(uint64* reads,
+                                        uint64* writes,
+                                        uint64* bytes_read,
+                                        uint64* bytes_written) {
+  if (reads) {
+    *reads = 0;
+  }
+
+  if (writes) {
+    *writes = 0;
+  }
+
+  if (bytes_read) {
+    *bytes_read = 0;
+  }
+
+  if (bytes_written) {
+    *bytes_written = 0;
+  }
+
+  // Don't want to risk displaying UI errors here
+  DisableThreadErrorUI disable_error_dialog_box;
+
+  // for all drives
+  for (int drive = 0; ; drive++) {
+    struct _DISK_PERFORMANCE perf_data;
+    const int max_device_len = 50;
+
+    // check whether we can access this device
+    CString device_name;
+    device_name.Format(_T("\\\\.\\PhysicalDrive%d"), drive);
+    scoped_handle device(::CreateFile(device_name, 0,
+                                      FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                      NULL, OPEN_EXISTING, 0, NULL));
+
+    if (get(device) == INVALID_HANDLE_VALUE) {
+      if (!drive) {
+        UTIL_LOG(LEVEL_ERROR, (_T("[Failed to access drive %i][0x%x]"),
+                               drive,
+                               HRESULTFromLastError()));
+      }
+      break;
+    }
+
+    // disk performance counters must be on (diskperf -y on older machines;
+    // defaults to on on newer windows)
+    DWORD size = 0;
+    if (::DeviceIoControl(get(device),
+                          IOCTL_DISK_PERFORMANCE,
+                          NULL,
+                          0,
+                          &perf_data,
+                          sizeof(_DISK_PERFORMANCE),
+                          &size,
+                          NULL)) {
+      if (reads) {
+        *reads += perf_data.ReadCount;
+      }
+
+      if (writes) {
+        *writes += perf_data.WriteCount;
+      }
+
+      if (bytes_read) {
+        *bytes_read += perf_data.BytesRead.QuadPart;
+      }
+
+      if (bytes_written) {
+        *bytes_written += perf_data.BytesWritten.QuadPart;
+      }
+    } else {
+      HRESULT hr = HRESULTFromLastError();
+      UTIL_LOG(LEVEL_ERROR,
+               (_T("[System::GetDiskActivityCounters - failed to ")
+                _T("DeviceIoControl][0x%x]"), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT System::GetDiskStatistics(const TCHAR* path,
+                                  uint64 *free_bytes_current_user,
+                                  uint64 *total_bytes_current_user,
+                                  uint64 *free_bytes_all_users) {
+  ASSERT1(path);
+  ASSERT1(free_bytes_current_user);
+  ASSERT1(total_bytes_current_user);
+  ASSERT1(free_bytes_all_users);
+  ASSERT1(sizeof(LARGE_INTEGER) == sizeof(uint64));  // NOLINT
+
+  DisableThreadErrorUI disable_error_dialog_box;
+
+  if (!::GetDiskFreeSpaceEx(
+           path,
+           reinterpret_cast<PULARGE_INTEGER>(free_bytes_current_user),
+           reinterpret_cast<PULARGE_INTEGER>(total_bytes_current_user),
+           reinterpret_cast<PULARGE_INTEGER>(free_bytes_all_users))) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[Failed to GetDiskFreeSpaceEx][%s][0x%x]"), path, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT System::GetProcessMemoryStatistics(uint64 *current_working_set,
+                                           uint64 *peak_working_set,
+                                           uint64 *min_working_set_size,
+                                           uint64 *max_working_set_size) {
+  HANDLE process_handle = GetCurrentProcess();
+  HRESULT hr = S_OK;
+
+  DWORD min_size(0), max_size(0);
+  if (GetProcessWorkingSetSize(process_handle, &min_size, &max_size)) {
+    UTIL_LOG(L2, (_T("working set %lu %lu"), min_size, max_size));
+    if (min_working_set_size) {
+      *min_working_set_size = min_size;
+    }
+    if (max_working_set_size) {
+      *max_working_set_size = max_size;
+    }
+  } else {
+    if (min_working_set_size) {
+      *min_working_set_size = 0;
+    }
+    if (max_working_set_size) {
+      *max_working_set_size = 0;
+    }
+    hr = E_FAIL;
+  }
+
+  if (current_working_set) { *current_working_set = 0; }
+  if (peak_working_set) { *peak_working_set = 0; }
+
+  // including this call (w/psapi.lib) adds 24k to the process memory
+  // according to task manager in one test, memory usage according to task
+  // manager increased by 4k after calling this
+  PROCESS_MEMORY_COUNTERS counters = { sizeof(counters), 0 };
+  if (GetProcessMemoryInfo(process_handle,
+                           &counters,
+                           sizeof(PROCESS_MEMORY_COUNTERS))) {
+    if (current_working_set) {
+      *current_working_set = counters.WorkingSetSize;
+    }
+    if (peak_working_set) {
+      *peak_working_set = counters.PeakWorkingSetSize;
+    }
+    UTIL_LOG(L2, (_T("current/peak working set %s %s"),
+                  String_Int64ToString(*current_working_set, 10),
+                  String_Int64ToString(*peak_working_set, 10)));
+  } else {
+    if (current_working_set) {
+      *current_working_set = 0;
+    }
+    if (peak_working_set) {
+      *peak_working_set = 0;
+    }
+    hr = E_FAIL;
+  }
+
+  return hr;
+}
+
+HRESULT System::MaxPhysicalMemoryAvailable(uint64* max_bytes) {
+  ASSERT1(max_bytes);
+
+  *max_bytes = 0;
+
+  uint32 memory_load_percentage = 0;
+  uint64 free_physical_memory = 0;
+
+  RET_IF_FAILED(System::GetGlobalMemoryStatistics(&memory_load_percentage,
+    &free_physical_memory, NULL, NULL, NULL, NULL, NULL));
+
+  UTIL_LOG(L4, (_T("mem load %u max physical memory available %s"),
+                memory_load_percentage,
+                String_Int64ToString(free_physical_memory, 10)));
+
+  *max_bytes = free_physical_memory;
+
+  return S_OK;
+}
+
+HRESULT System::GetGlobalMemoryStatistics(uint32 *memory_load_percentage,
+                                          uint64 *free_physical_memory,
+                                          uint64 *total_physical_memory,
+                                          uint64 *free_paged_memory,
+                                          uint64 *total_paged_memory,
+                                          uint64 *process_free_virtual_memory,
+                                          uint64 *process_total_virtual_mem) {
+  MEMORYSTATUSEX status;
+  status.dwLength = sizeof(status);
+  if (!GlobalMemoryStatusEx(&status)) {
+    UTIL_LOG(LEVEL_ERROR, (_T("memory status error %u"), GetLastError()));
+    return E_FAIL;
+  }
+  if (memory_load_percentage) { *memory_load_percentage = status.dwMemoryLoad; }
+  if (free_physical_memory) { *free_physical_memory = status.ullAvailPhys; }
+  if (total_physical_memory) { *total_physical_memory = status.ullTotalPhys; }
+  if (free_paged_memory) { *free_paged_memory = status.ullAvailPageFile; }
+  if (total_paged_memory) { *total_paged_memory = status.ullTotalPageFile; }
+  if (process_free_virtual_memory) {
+    *process_free_virtual_memory = status.ullAvailVirtual;
+  }
+  if (process_total_virtual_mem) {
+    *process_total_virtual_mem = status.ullTotalVirtual;
+  }
+  // GetPerformanceInfo;
+  return S_OK;
+}
+
+void System::FreeProcessWorkingSet() {
+  // -1,-1 is a special signal to the OS to temporarily trim the working set
+  // size to 0.  See MSDN for further information.
+  ::SetProcessWorkingSetSize(::GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1);
+}
+
+HRESULT System::SetThreadPriority(enum Priority priority) {
+  int pri;
+
+  switch (priority) {
+    case LOW: pri = THREAD_PRIORITY_BELOW_NORMAL; break;
+    case HIGH: pri = THREAD_PRIORITY_HIGHEST; break;
+    case NORMAL: pri = THREAD_PRIORITY_NORMAL; break;
+    case IDLE: pri = THREAD_PRIORITY_IDLE; break;
+    default: return E_FAIL;
+  }
+
+  if (::SetThreadPriority(GetCurrentThread(), pri)) {
+    return S_OK;
+  } else {
+    return E_FAIL;
+  }
+}
+
+HRESULT System::SetProcessPriority(enum Priority priority) {
+  DWORD pri = 0;
+  switch (priority) {
+    case LOW: pri = BELOW_NORMAL_PRIORITY_CLASS; break;
+    case HIGH: pri = ABOVE_NORMAL_PRIORITY_CLASS; break;
+    case NORMAL: pri = NORMAL_PRIORITY_CLASS; break;
+    case IDLE: return E_INVALIDARG;
+    default: return E_INVALIDARG;
+  }
+
+  DWORD pid = ::GetCurrentProcessId();
+
+  scoped_handle handle(::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid));
+  if (!valid(handle)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LE, (_T("[::OpenProcess failed][%u][0x%x]"), pid, hr));
+    return hr;
+  }
+
+  if (!::SetPriorityClass(get(handle), pri)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LE, (_T("[::SetPriorityClass failed][%u][0x%x]"), pid, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// start another process painlessly via ::CreateProcess. Use the
+// ShellExecuteProcessXXX variants instead of these methods where possible,
+// since ::ShellExecuteEx has better behavior on Windows Vista.
+// When using this method, avoid using process_name - see
+// http://blogs.msdn.com/oldnewthing/archive/2006/05/15/597984.aspx.
+HRESULT System::StartProcess(const TCHAR* process_name,
+                             TCHAR* command_line,
+                             PROCESS_INFORMATION* pi) {
+  ASSERT1(pi);
+  ASSERT1(command_line || process_name);
+  ASSERT(!process_name, (_T("Avoid using process_name. See method comment.")));
+
+  STARTUPINFO si = {sizeof(si), 0};
+
+  // Feedback cursor is off while the process is starting.
+  si.dwFlags = STARTF_FORCEOFFFEEDBACK;
+
+  UTIL_LOG(L3, (_T("[System::StartProcess][process %s][cmd %s]"),
+                process_name, command_line));
+
+  BOOL success = ::CreateProcess(
+      process_name,     // Module name
+      command_line,     // Command line
+      NULL,             // Process handle not inheritable
+      NULL,             // Thread handle not inheritable
+      FALSE,            // Set handle inheritance to FALSE
+      0,                // No creation flags
+      NULL,             // Use parent's environment block
+      NULL,             // Use parent's starting directory
+      &si,              // Pointer to STARTUPINFO structure
+      pi);              // Pointer to PROCESS_INFORMATION structure
+
+  if (!success) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[System::StartProcess][::CreateProcess failed][0x%x]"), hr));
+    return hr;
+  }
+
+  OPT_LOG(L1, (_T("[Started process][%u]"), pi->dwProcessId));
+
+  return S_OK;
+}
+
+// start another process painlessly via ::CreateProcess. Use the
+// ShellExecuteProcessXXX variants instead of these methods where possible,
+// since ::ShellExecuteEx has better behavior on Windows Vista.
+HRESULT System::StartProcessWithArgsAndInfo(const TCHAR *process_name,
+                                            const TCHAR *cmd_line_arguments,
+                                            PROCESS_INFORMATION *pi) {
+  ASSERT1(process_name && cmd_line_arguments && pi);
+
+  CString command_line(process_name);
+  EnclosePath(&command_line);
+  command_line.AppendChar(_T(' '));
+  command_line.Append(cmd_line_arguments);
+  return System::StartProcess(NULL, command_line.GetBuffer(), pi);
+}
+
+// start another process painlessly via ::CreateProcess. Use the
+// ShellExecuteProcessXXX variants instead of these methods where possible,
+// since ::ShellExecuteEx has better behavior on Windows Vista.
+HRESULT System::StartProcessWithArgs(const TCHAR *process_name,
+                                     const TCHAR *cmd_line_arguments) {
+  ASSERT1(process_name && cmd_line_arguments);
+  PROCESS_INFORMATION pi = {0};
+  HRESULT hr = System::StartProcessWithArgsAndInfo(process_name,
+                                                   cmd_line_arguments,
+                                                   &pi);
+  if (SUCCEEDED(hr)) {
+    ::CloseHandle(pi.hProcess);
+    ::CloseHandle(pi.hThread);
+  }
+  return hr;
+}
+
+// start another process painlessly via ::ShellExecuteEx. Use this method
+// instead of the StartProcessXXX methods that use ::CreateProcess where
+// possible, since ::ShellExecuteEx has better behavior on Windows Vista.
+//
+// ShellExecuteExEnsureParent displays the PID of the started process if it is
+// returned. It is only returned if the mask includes SEE_MASK_NOCLOSEPROCESS.
+// Therefore, we always set this flag and pass a handle. If the caller did not
+// request the handle, we close it.
+HRESULT System::ShellExecuteProcess(const TCHAR* file_name_to_execute,
+                                    const TCHAR* command_line_parameters,
+                                    HWND hwnd,
+                                    HANDLE* process_handle) {
+  ASSERT1(file_name_to_execute);
+
+  UTIL_LOG(L3, (_T("[System::ShellExecuteProcess]")
+                _T("[file_name_to_execute '%s' command_line_parameters '%s']"),
+                file_name_to_execute, command_line_parameters));
+
+  SHELLEXECUTEINFO sei = {0};
+  sei.cbSize = sizeof(sei);
+  // SEE_MASK_NOZONECHECKS is set below to work around a problem in systems that
+  // had Internet Explorer 7 Beta installed. See http://b/804674.
+  // This only works for Windows XP SP1 and later.
+  sei.fMask = SEE_MASK_NOCLOSEPROCESS |  // Set hProcess to process handle.
+              SEE_MASK_FLAG_NO_UI     |  // Do not display an error message box.
+              SEE_MASK_NOZONECHECKS   |  // Do not perform a zone check.
+              SEE_MASK_NOASYNC;          // Wait to complete before returning.
+  sei.lpVerb = _T("open");
+  sei.lpFile = file_name_to_execute;
+  sei.lpParameters = command_line_parameters;
+  sei.nShow = SW_SHOWNORMAL;
+  sei.hwnd = hwnd;
+
+  // Use ShellExecuteExEnsureParent to ensure that we always have a parent
+  // window. We need to use the HWND property to be acknowledged as a foreground
+  // application on Windows Vista. Otherwise, the elevation prompt will appear
+  // minimized on the taskbar.
+  if (!ShellExecuteExEnsureParent(&sei)) {
+    HRESULT hr(HRESULTFromLastError());
+    OPT_LOG(LEVEL_ERROR, (_T("[Failed to ::ShellExecuteEx][%s][%s][0x%08x]"),
+                          file_name_to_execute, command_line_parameters, hr));
+    return hr;
+  }
+
+  if (process_handle) {
+    *process_handle = sei.hProcess;
+  } else {
+    ::CloseHandle(sei.hProcess);
+  }
+
+  return S_OK;
+}
+
+// start another process painlessly via ::ShellExecuteEx. Use this method
+// instead of the StartProcessXXX methods that use ::CreateProcess where
+// possible, since ::ShellExecuteEx has better behavior on Windows Vista.
+HRESULT System::ShellExecuteCommandLine(const TCHAR* command_line_to_execute,
+                                        HWND hwnd,
+                                        HANDLE* process_handle) {
+  ASSERT1(command_line_to_execute);
+
+  CString exe;
+  CString args;
+
+  HRESULT hr = CommandParsingSimple::SplitExeAndArgs(command_line_to_execute,
+                                                     &exe,
+                                                     &args);
+
+  if (SUCCEEDED(hr)) {
+    hr = System::ShellExecuteProcess(exe, args, hwnd, process_handle);
+    if (FAILED(hr)) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[System::ShellExecuteProcess failed]")
+                             _T("[%s][%s][0x%08x]"), exe, args, hr));
+    }
+  }
+
+  return hr;
+}
+
+// returns the number of ms the system has had no user input
+int System::GetUserIdleTime() {
+  LASTINPUTINFO last_input_info;
+  last_input_info.cbSize = sizeof(LASTINPUTINFO);
+  // get time in windows ticks since system start of last activity
+  BOOL b = GetLastInputInfo(&last_input_info);
+  if (b == TRUE) {
+    return (GetTickCount()-last_input_info.dwTime);  // compute idle time
+  }
+  return 0;
+}
+
+bool System::IsUserIdle() {
+  // Only notify when the user has been idle less than this time
+  static int user_idle_threshold_ms = kUserIdleThresholdMs;
+
+  bool is_user_idle = (GetUserIdleTime() > user_idle_threshold_ms);
+  UTIL_LOG(L2, (_T("System::IsUserIdle() %s; user_idle_threshold_ms = %d"),
+                is_user_idle ? _T("TRUE") : _T("FALSE"),
+                user_idle_threshold_ms));
+  return is_user_idle;
+}
+
+bool System::IsUserBusy() {
+  // The user is busy typing or interacting with another application
+  // if the user is below the minimum threshold:
+  static int user_idle_min_threshold_ms = kUserIdleMinThresholdMs;
+  // The user is probably not paying attention
+  // if the user is above the maximum threshold:
+  static int user_idle_max_threshold_ms = kUserIdleMaxThresholdMs;
+
+  int user_idle_time = GetUserIdleTime();
+  bool is_user_busy = user_idle_time < user_idle_min_threshold_ms ||
+    user_idle_time > user_idle_max_threshold_ms;
+  UTIL_LOG(L2, (_T("[System::IsUserBusy() %s][user_idle_time = %d]")
+                _T("[user_idle_min_threshold_ms = %d]")
+                _T("[user_idle_max_threshold_ms = %d]"),
+                is_user_busy? _T("TRUE") : _T("FALSE"),
+                user_idle_time,
+                user_idle_min_threshold_ms,
+                user_idle_max_threshold_ms));
+  return is_user_busy;
+}
+
+bool System::IsScreensaverRunning() {
+  // NT 4.0 and below require testing OpenDesktop("screen-saver")
+  // We require W2K or better so we have an easier way
+  DWORD result = 0;
+  ::SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &result, 0);
+  bool is_screensaver_running = (result != FALSE);
+  UTIL_LOG(L2, (_T("System::IsScreensaverRunning() %s"),
+                is_screensaver_running? _T("TRUE") : _T("FALSE")));
+  return is_screensaver_running;
+}
+
+bool System::IsWorkstationLocked() {
+  bool is_workstation_locked = true;
+  HDESK inputdesk = ::OpenInputDesktop(0, 0, GENERIC_READ);
+  if (NULL != inputdesk)  {
+    TCHAR name[256];
+    DWORD needed = arraysize(name);
+    BOOL ok = ::GetUserObjectInformation(inputdesk,
+                                         UOI_NAME,
+                                         name,
+                                         sizeof(name),
+                                         &needed);
+    ::CloseDesktop(inputdesk);
+    if (ok) {
+      is_workstation_locked = (0 != lstrcmpi(name, NOTRANSL(_T("default"))));
+    }
+  }
+
+  UTIL_LOG(L2, (_T("System::IsWorkstationLocked() %s"),
+                is_workstation_locked? _T("TRUE") : _T("FALSE")));
+  return is_workstation_locked;
+}
+
+bool System::IsUserAway() {
+  return IsScreensaverRunning() || IsWorkstationLocked();
+}
+
+uint32 System::GetProcessHandleCount() {
+  typedef LONG (CALLBACK *Fun)(HANDLE, int32, PVOID, ULONG, PULONG);
+
+  // This new version of getting the number of open handles works on win2k.
+  HMODULE h = GetModuleHandle(_T("ntdll.dll"));
+  Fun NtQueryInformationProcess =
+      reinterpret_cast<Fun>(::GetProcAddress(h, "NtQueryInformationProcess"));
+
+  if (!NtQueryInformationProcess) {
+    UTIL_LOG(LEVEL_ERROR, (_T("[NtQueryInformationProcess failed][0x%x]"),
+                           HRESULTFromLastError()));
+    return 0;
+  }
+
+  DWORD count = 0;
+  VERIFY(NtQueryInformationProcess(GetCurrentProcess(),
+                                   kProcessHandleCount,
+                                   &count,
+                                   sizeof(count),
+                                   NULL) >= 0, (L""));
+
+  return count;
+}
+
+uint32 System::GetProcessHandleCountOld() {
+  typedef BOOL (CALLBACK * Fun)(HANDLE, PDWORD);
+
+  // GetProcessHandleCount not available on win2k
+  HMODULE handle = GetModuleHandle(_T("kernel32"));
+  Fun f = reinterpret_cast<Fun>(GetProcAddress(handle,
+                                               "GetProcessHandleCount"));
+
+  if (!f) return 0;
+
+  DWORD count = 0;
+  VERIFY((*f)(GetCurrentProcess(), &count), (L""));
+  return count;
+
+  //  DWORD GetGuiResources (HANDLE hProcess, DWORD uiFlags);
+  //  Parameters, hProcess
+  //  [in] Handle to the process. The handle must have the
+  //  PROCESS_QUERY_INFORMATION access right. For more information, see Process
+  //  Security and Access Rights.
+  //  uiFlags
+  //  [in] GUI object type. This parameter can be one of the following values.
+  //  Value          Meaning
+  //  GR_GDIOBJECTS  Return the count of GDI objects.
+  //  GR_USEROBJECTS Return the count of USER objects.
+}
+
+void System::GetGuiObjectCount(uint32 *gdi, uint32 *user) {
+  if (gdi) {
+    *gdi = GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS);
+  }
+  if (user) {
+    *user = GetGuiResources(GetCurrentProcess(), GR_USEROBJECTS);
+  }
+}
+
+HRESULT System::GetRebootCheckDummyFileName(const TCHAR* base_file,
+                                            CString* dummy_file) {
+  ASSERT1(dummy_file);
+
+  if (base_file && *base_file) {
+    ASSERT1(File::Exists(base_file));
+    dummy_file->SetString(base_file);
+  } else {
+    RET_IF_FAILED(GetModuleFileName(NULL, dummy_file));
+  }
+  dummy_file->Append(_T(".needreboot"));
+  return S_OK;
+}
+
+// Is the system being rebooted?
+bool System::IsRebooted(const TCHAR* base_file) {
+  CString dummy_file;
+  if (SUCCEEDED(GetRebootCheckDummyFileName(base_file, &dummy_file))) {
+    if (File::Exists(dummy_file)) {
+      // If the file exists but it is not found in the
+      // PendingFileRenameOperations, (probably becaused that this key is messed
+      // up and thus the system restart fails to delete the file), re-add it
+      if (!File::AreMovesPendingReboot(dummy_file, true)) {
+        File::MoveAfterReboot(dummy_file, NULL);
+      }
+      return false;
+    } else {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Mark the system as reboot required
+HRESULT System::MarkAsRebootRequired(const TCHAR* base_file) {
+  // Create a dummy file if needed
+  CString dummy_file;
+  RET_IF_FAILED(GetRebootCheckDummyFileName(base_file, &dummy_file));
+  if (File::Exists(dummy_file)) {
+    return S_OK;
+  }
+
+  File file;
+  RET_IF_FAILED(file.Open(dummy_file, true, false));
+  RET_IF_FAILED(file.Close());
+
+  // Hide it
+  DWORD file_attr = ::GetFileAttributes(dummy_file);
+  if (file_attr == INVALID_FILE_ATTRIBUTES ||
+      !::SetFileAttributes(dummy_file, file_attr | FILE_ATTRIBUTE_HIDDEN)) {
+    return HRESULTFromLastError();
+  }
+
+  // Mark it as being deleted after reboot
+  return File::MoveAfterReboot(dummy_file, NULL);
+}
+
+// Unmark the system as reboot required
+HRESULT System::UnmarkAsRebootRequired(const TCHAR* base_file) {
+  CString dummy_file;
+  RET_IF_FAILED(GetRebootCheckDummyFileName(base_file, &dummy_file));
+
+  return File::RemoveFromMovesPendingReboot(dummy_file, false);
+}
+
+// Restart the computer
+HRESULT System::RestartComputer() {
+  RET_IF_FAILED(AdjustPrivilege(SE_SHUTDOWN_NAME, true));
+
+  if (!::ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_APPLICATION |
+                       SHTDN_REASON_MINOR_INSTALLATION |
+                       SHTDN_REASON_FLAG_PLANNED)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[System::RestartComputer - failed to")
+                           _T(" ExitWindowsEx][0x%x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// The implementation works on all Windows versions. On NT and XP the screen
+// saver is actually stored in registry at
+// HKEY_CURRENT_USER\Control Panel\Desktop\SCRNSAVE.EXE but the
+// GetPrivateProfileString call is automatically mapped to the registry
+HRESULT System::GetCurrentScreenSaver(CString* fileName) {
+  if (!fileName) return E_POINTER;
+
+  DWORD nChars = ::GetPrivateProfileString(_T("boot"),
+                                           _T("SCRNSAVE.EXE"),
+                                           _T(""),
+                                           fileName->GetBuffer(MAX_PATH),
+                                           MAX_PATH,
+                                           _T("system.ini"));
+  fileName->ReleaseBufferSetLength(nChars);
+
+  return S_OK;
+}
+
+// Create an instance of a COM Local Server class using either plain vanilla
+// CoCreateInstance, or using the Elevation moniker depending on the operating
+// system
+HRESULT System::CoCreateInstanceAsAdmin(HWND hwnd,
+                                        REFCLSID rclsid,
+                                        REFIID riid,
+                                        void** ppv) {
+  if (SystemInfo::IsRunningOnVistaOrLater()) {
+    // Use the Elevation Moniker to create the Install Manager in Windows Vista.
+    // If the UI is running in medium integrity, this will result in a
+    // elevation prompt
+
+    scoped_window hwnd_parent;
+
+    if (!hwnd) {
+      reset(hwnd_parent, CreateForegroundParentWindowForUAC());
+
+      if (!hwnd_parent) {
+        return HRESULTFromLastError();
+      }
+      // Use the newly created dummy window as the hwnd
+      hwnd = get(hwnd_parent);
+    }
+
+    CString moniker_name(_T("Elevation:Administrator!new:"));
+    moniker_name += GuidToString(rclsid);
+    BIND_OPTS3 bo;
+    SetZero(bo);
+    bo.cbStruct = sizeof(bo);
+    bo.hwnd = hwnd;
+    bo.dwClassContext = CLSCTX_LOCAL_SERVER;
+
+    return ::CoGetObject(moniker_name, &bo, riid, ppv);
+  } else {
+    // Use plain-vanilla ::CoCreateInstance()
+    return ::CoCreateInstance(rclsid, NULL, CLSCTX_LOCAL_SERVER, riid, ppv);
+  }
+}
+
+HRESULT System::IsPrivilegeEnabled(const TCHAR* privilege, bool* present) {
+  ASSERT1(privilege);
+  ASSERT1(present);
+
+  *present = false;
+
+  scoped_handle token;
+  if (!::OpenProcessToken(::GetCurrentProcess(),
+                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+                          address(token))) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[System::IsPrivilegeEnabled - failed to ")
+                           _T("OpenProcessToken][0x%x]"), hr));
+    return hr;
+  }
+
+  LUID luid = {0};
+  if (!::LookupPrivilegeValue(NULL, privilege, &luid)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[System::IsPrivilegeEnabled - failed to")
+                           _T("LookupPrivilegeValue][0x%x]"), hr));
+    return hr;
+  }
+
+  PRIVILEGE_SET required_privilege = {0};
+  required_privilege.PrivilegeCount = 1;
+  required_privilege.Control = PRIVILEGE_SET_ALL_NECESSARY;
+  required_privilege.Privilege[0].Luid = luid;
+
+  BOOL result = FALSE;
+  if (!::PrivilegeCheck(get(token), &required_privilege, &result)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[System::IsPrivilegeEnabled - failed to")
+                           _T("PrivilegeCheck][0x%x]"), hr));
+    return hr;
+  }
+
+  if (required_privilege.Privilege[0].Attributes &
+      SE_PRIVILEGE_USED_FOR_ACCESS) {
+    *present = true;
+  }
+
+  return S_OK;
+}
+
+// Attempts to adjust current process privileges.
+// Only process running with administrator privileges will succeed.
+HRESULT System::AdjustPrivilege(const TCHAR* privilege, bool enable) {
+  ASSERT1(privilege);
+
+  scoped_handle token;
+  if (!::OpenProcessToken(::GetCurrentProcess(),
+                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+                          address(token))) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[System::AdjustPrivilege - failed to ")
+                           _T("OpenProcessToken][0x%x]"), hr));
+    return hr;
+  }
+
+  LUID luid = {0};
+  if (!::LookupPrivilegeValue(NULL, privilege, &luid)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[System::AdjustPrivilege - failed to")
+                           _T("LookupPrivilegeValue][0x%x]"), hr));
+    return hr;
+  }
+
+  TOKEN_PRIVILEGES privs;
+  privs.PrivilegeCount = 1;
+  privs.Privileges[0].Luid = luid;
+  privs.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
+
+  if (!::AdjustTokenPrivileges(get(token), FALSE, &privs, 0, NULL, 0)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[System::AdjustPrivilege - failed to ")
+                           _T("AdjustTokenPrivileges][0x%x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+DWORD System::WTSGetActiveConsoleSessionId()  {
+  typedef DWORD (* Fun)();
+
+  HINSTANCE hInst = ::GetModuleHandle(_T("kernel32.dll"));
+  ASSERT1(hInst);
+  Fun pfn = reinterpret_cast<Fun>(::GetProcAddress(
+                                      hInst,
+                                      "WTSGetActiveConsoleSessionId"));
+  return !pfn ? kInvalidSessionId : (*pfn)();
+}
+
+// Get the session the current process is running under
+DWORD System::GetCurrentSessionId() {
+  DWORD session_id = kInvalidSessionId;
+  DWORD* session_id_ptr = NULL;
+  DWORD bytes_returned = 0;
+
+  if (::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
+                                   WTS_CURRENT_SESSION,
+                                   WTSSessionId,
+                                   reinterpret_cast<LPTSTR*>(&session_id_ptr),
+                                   &bytes_returned)) {
+    ASSERT1(bytes_returned == sizeof(*session_id_ptr));
+    session_id = *session_id_ptr;
+    ::WTSFreeMemory(session_id_ptr);
+    UTIL_LOG(L6, (_T("[System::GetCurrentSessionId]")
+                  _T("[session_id from ::WTSQuerySessionInformation][%d]"),
+                  session_id));
+    return session_id;
+  }
+
+  // ::WTSQuerySessionInformation can fail if we are not running
+  // in a Terminal Services scenario, in which case, we use
+  // ::ProcessIdToSessionId()
+  if (::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id)) {
+    UTIL_LOG(L6,  (_T("[System::GetCurrentSessionId]")
+                   _T("[session_id from ::ProcessIdToSessionId][%d]"),
+                   session_id));
+    return session_id;
+  }
+
+  UTIL_LOG(LEVEL_ERROR,
+           (_T("[System::GetCurrentSessionId - both")
+            _T("::WTSQuerySessionInformation and ")
+            _T("::ProcessIdToSessionId failed][0x%x]"),
+            ::GetLastError()));
+
+  return kInvalidSessionId;
+}
+
+// Get the best guess as to the currently active session, or kInvalidSessionId
+// if there is no active session.
+DWORD System::GetActiveSessionId() {
+  // WTSGetActiveConsoleSessionId retrieves the Terminal Services session
+  // currently attached to the physical console.
+  DWORD active_session_id = WTSGetActiveConsoleSessionId();
+
+  if (IsSessionActive(active_session_id)) {
+    UTIL_LOG(L6, (_T("[System::GetActiveSessionId]")
+                  _T("[Active session id from ::WTSGetActiveConsoleSessionId]")
+                  _T("[%d]"), active_session_id));
+
+    return active_session_id;
+  }
+
+  // WTSGetActiveConsoleSessionId works for FUS, but it does not work for TS
+  // servers where the current active session is always the console. We then use
+  // a different method as below. We get all the sessions that are present on
+  // the system, to see if we can find an active session.
+  active_session_id = kInvalidSessionId;
+  WTS_SESSION_INFO* session_info = NULL;
+  DWORD num_sessions = 0;
+  if (::WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1,
+                              &session_info, &num_sessions)) {
+    // Pick the first active session we can find
+    for (DWORD i = 0 ; i < num_sessions; ++i) {
+      if (session_info[i].State == WTSActive) {
+        // There is a user logged on to the WinStation associated with the
+        // session.
+        active_session_id = session_info[i].SessionId;
+        break;
+      }
+    }
+
+    ::WTSFreeMemory(session_info);
+    UTIL_LOG(L6, (_T("[System::GetActiveSessionId]")
+                  _T("[Active session id from ::WTSEnumerateSessions][0x%x]"),
+                  active_session_id));
+
+    return active_session_id;
+  }
+
+  UTIL_LOG(LEVEL_ERROR,
+           (_T("[System::GetActiveSessionId - ")
+           _T("Both ::WTSGetActiveConsoleSessionId and ::WTSEnumerateSessions ")
+           _T("failed][0x%x]"),
+           ::GetLastError()));
+
+  return kInvalidSessionId;
+}
+
+// Is there a user logged on and active in the specified session?
+bool System::IsSessionActive(DWORD session_id) {
+  if (kInvalidSessionId == session_id) {
+    return false;
+  }
+
+  WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;
+  WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;
+  DWORD bytes_returned = 0;
+  if (::WTSQuerySessionInformation(
+          WTS_CURRENT_SERVER_HANDLE,
+          session_id,
+          WTSConnectState,
+          reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),
+          &bytes_returned)) {
+    ASSERT1(bytes_returned == sizeof(*ptr_wts_connect_state));
+    wts_connect_state = *ptr_wts_connect_state;
+    ::WTSFreeMemory(ptr_wts_connect_state);
+
+    UTIL_LOG(L6, (_T("[System::IsSessionActive]")
+                  _T("[wts_connect_state %d]"), wts_connect_state));
+    return WTSActive == wts_connect_state;
+  }
+
+  UTIL_LOG(LE, (_T("[WTSQuerySessionInformation failed][0x%x]"),
+                ::GetLastError()));
+  return false;
+}
+
+// Is the current process running under WinSta0
+bool System::IsCurrentProcessInteractive() {
+  // Use a non-scoped handle, since a handle retrieved via
+  // ::GetProcessWindowStation() should not be closed.
+  HWINSTA handle_window_station(::GetProcessWindowStation());
+  DWORD len = 0;
+  CString str_window_station;
+
+  if (!handle_window_station || handle_window_station == INVALID_HANDLE_VALUE) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[System::IsCurrentProcessInteractive - ")
+              _T("::GetProcessWindowStation() failed (%d)]"),
+              ::GetLastError()));
+    return false;
+  }
+
+  if (!::GetUserObjectInformation(handle_window_station,
+                                  UOI_NAME,
+                                  CStrBuf(str_window_station, MAX_PATH),
+                                  MAX_PATH,
+                                  &len)) {
+    UTIL_LOG(LEVEL_ERROR,
+             (_T("[System::IsCurrentProcessInteractive - ")
+              _T("::GetUserObjectInfoformation(hWinSta) failed (%d)]"),
+              ::GetLastError()));
+    return false;
+  }
+
+  UTIL_LOG(L6, (_T("[System::IsCurrentProcessInteractive]")
+                _T("[WindowStation name][%s]"),
+                str_window_station));
+  return (str_window_station == _T("WinSta0"));
+}
+
+// is the current process running under WinSta0 for the currently active session
+bool System::IsCurrentProcessActiveAndInteractive() {
+  return IsSessionActive(GetCurrentSessionId()) &&
+         IsCurrentProcessInteractive();
+}
+
+bool System::IsRunningOnBatteries() {
+  SYSTEM_POWER_STATUS system_power_status = {0};
+  if (::GetSystemPowerStatus(&system_power_status)) {
+    bool has_battery = !(system_power_status.BatteryFlag & 128);
+    bool ac_status_offline = system_power_status.ACLineStatus == 0;
+    return ac_status_offline && has_battery;
+  }
+  return false;
+}
+
+}  // namespace omaha
+
diff --git a/common/system.h b/common/system.h
index cf898e9..017b042 100644
--- a/common/system.h
+++ b/common/system.h
@@ -1,223 +1,223 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// system functions for checking disk space / memory usage / etc.

-

-#ifndef OMAHA_COMMON_SYSTEM_H__

-#define OMAHA_COMMON_SYSTEM_H__

-

-#include <atlstr.h>

-#include <base/basictypes.h>

-

-namespace omaha {

-

-#define kMaxRegistryBackupWaitMs 3000

-#define kMaxRegistryRestoreWaitMs 30000

-

-// amount of time the user must have no input before we declare them idle

-// used by outlook addin, outlook_cap, and filecap.

-#define kUserIdleThresholdMs 30000

-

-// The user is busy typing or interacting with another application

-// if the user is below the minimum threshold.

-#define kUserIdleMinThresholdMs 30000

-

-// The user is probably not paying attention

-// if the user is above the maximum threshold.

-#define kUserIdleMaxThresholdMs 600000

-

-const DWORD kInvalidSessionId = 0xFFFFFFFF;

-

-class System {

-  public:

-

-    // disk activity.

-

-    // waits up to specified time for disk activity to occur; sleeps in

-    // increments of sleep_time.

-    static HRESULT WaitForDiskActivity(uint32 max_delay_milliseconds,

-                                       uint32 sleep_time_ms,

-                                       uint32 *time_waited);

-    // disk activity counters; may require admin on some machines? should return

-    // E_FAIL if so.

-    static HRESULT GetDiskActivityCounters(uint64 *reads,

-                                           uint64 *writes,

-                                           uint64 *bytes_read,

-                                           uint64 *bytes_written);

-

-    // disk statistics.

-

-    // disk total and free space.

-    // Path is either the root of a drive or an existing folder on a drive; the

-    // statistics are for that drive.

-    static HRESULT GetDiskStatistics(const TCHAR* path,

-                                     uint64 *free_bytes_current_user,

-                                     uint64 *total_bytes_current_user,

-                                     uint64 *free_bytes_all_users);

-

-    enum Priority {

-        LOW,

-        HIGH,

-        NORMAL,

-        IDLE

-    };

-

-    // functions to alter process/thread priority.

-    static HRESULT SetThreadPriority(enum Priority priority);

-    static HRESULT SetProcessPriority(enum Priority priority);

-

-    // The three functions below start background processes via ::CreateProcess.

-    // Use the ShellExecuteProcessXXX functions when starting foreground

-    // processes.

-    static HRESULT StartProcessWithArgs(const TCHAR *process_name,

-                                        const TCHAR *cmd_line_arguments);

-    static HRESULT StartProcessWithArgsAndInfo(const TCHAR *process_name,

-                                               const TCHAR *cmd_line_arguments,

-                                               PROCESS_INFORMATION *pi);

-    static HRESULT StartProcess(const TCHAR *process_name,

-                                TCHAR *command_line,

-                                PROCESS_INFORMATION *pi);

-

-

-    // start another process painlessly via ::ShellExecuteEx. Use this method

-    // instead of the StartProcessXXX methods that use ::CreateProcess where

-    // possible, since ::ShellExecuteEx has better behavior on Vista.

-    static HRESULT ShellExecuteProcess(const TCHAR* file_name_to_execute,

-                                       const TCHAR* command_line_parameters,

-                                       HWND hwnd,

-                                       HANDLE* process_handle);

-

-    // start another process painlessly via ::ShellExecuteEx. Use this method

-    // instead of the StartProcessXXX methods that use ::CreateProcess where

-    // possible, since ::ShellExecuteEx has better behavior on Vista.

-    static HRESULT ShellExecuteCommandLine(const TCHAR* command_line_to_execute,

-                                           HWND hwnd,

-                                           HANDLE* process_handle);

-

-    // memory statistics.

-

-    // max amount of memory that can be allocated without paging.

-    static HRESULT MaxPhysicalMemoryAvailable(uint64 *max_bytes);

-

-    // global memory stats

-    static HRESULT GetGlobalMemoryStatistics(

-                       uint32 *memory_load_percentage,

-                       uint64 *free_physical_memory,

-                       uint64 *total_physical_memory,

-                       uint64 *free_paged_memory,

-                       uint64 *total_paged_memory,

-                       uint64 *process_free_virtual_memory,

-                       uint64 *process_total_virtual_memory);

-

-    // process memory stats

-    static HRESULT GetProcessMemoryStatistics(uint64 *current_working_set,

-                                              uint64 *peak_working_set,

-                                              uint64 *min_working_set_size,

-                                              uint64 *max_working_set_size);

-

-    // TODO(omaha): determine if using this where we do with machines

-    // with slow disks causes noticeable slowdown

-

-    // reduce process working set - beware of possible negative performance

-    // implications - this function frees (to the page cache) all used pages,

-    // minimizing the working set - but could lead to additional page faults

-    // when the process continues. If the process continues soon enough the

-    // pages will still be in the page cache so they'll be relatively cheap

-    // soft page faults. This function is best used to reduce memory footprint

-    // when a component is about to go idle for "awhile".

-    static void FreeProcessWorkingSet();

-

-    // returns the number of ms the system has had no user input.

-    static int GetUserIdleTime();

-

-    // from ntddk.h, used as a parameter to get the process handle count.

-    static const int kProcessHandleCount = 20;

-    static uint32 GetProcessHandleCount();

-    static uint32 GetProcessHandleCountOld();

-

-    static void GetGuiObjectCount(uint32 *gdi, uint32 *user);

-

-    static bool IsUserIdle();

-    static bool IsUserBusy();

-    static bool IsScreensaverRunning();

-    static bool IsWorkstationLocked();

-    static bool IsUserAway();

-

-    // Is the system requiring reboot.

-    static bool IsRebooted(const TCHAR* base_file);

-

-    // Mark the system as reboot required.

-    static HRESULT MarkAsRebootRequired(const TCHAR* base_file);

-

-    // Unmark the system as reboot required.

-    static HRESULT UnmarkAsRebootRequired(const TCHAR* base_file);

-

-    // Restart the computer.

-    static HRESULT RestartComputer();

-

-    // Get the full path name of the screen saver program currently selected.

-    // If no screen saver is selected then "fileName" is empty.

-    static HRESULT GetCurrentScreenSaver(CString* fileName);

-

-    // Creates an instance of a COM Local Server class using either plain

-    // vanilla CoCreateInstance, or using the Elevation moniker depending on the

-    // operating system.

-    static HRESULT CoCreateInstanceAsAdmin(HWND hwnd,

-                                           REFCLSID rclsid,

-                                           REFIID riid,

-                                           void** ppv);

-

-    // Attempts to adjust current process privileges.

-    // Only process running with administrator privileges will succeed.

-    static HRESULT AdjustPrivilege(const TCHAR* privilege, bool enable);

-

-    // Checks if the given privilege is enabled for the current process.

-    static HRESULT IsPrivilegeEnabled(const TCHAR* privilege, bool* present);

-

-    // Dynamically links and calls ::WTSGetActiveConsoleSessionId(). Returns

-    // kInvalidSessionId if it cannot find the export in kernel32.dll.

-    static DWORD WTSGetActiveConsoleSessionId();

-

-    // Get the session the current process is running under.

-    static DWORD GetCurrentSessionId();

-

-    // Get the best guess as to the currently active session,

-    // or kInvalidSessionId if there is no active session.

-    static DWORD GetActiveSessionId();

-

-    // Is there a user logged on and active in the specified session?

-    static bool IsSessionActive(DWORD session_id);

-

-    // Is the current process running under WinSta0.

-    static bool IsCurrentProcessInteractive();

-

-    // is the current process running under WinSta0 for the currently active

-    // session.

-    static bool IsCurrentProcessActiveAndInteractive();

-

-    // Returns true if a system battery is detected and the AC line

-    // status is 'offline', otherwise it returns false.

-    static bool IsRunningOnBatteries();

-

-  private:

-    static HRESULT GetRebootCheckDummyFileName(const TCHAR* base_file,

-                                               CString* dummy_file);

-    DISALLOW_EVIL_CONSTRUCTORS(System);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SYSTEM_H__

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// system functions for checking disk space / memory usage / etc.
+
+#ifndef OMAHA_COMMON_SYSTEM_H__
+#define OMAHA_COMMON_SYSTEM_H__
+
+#include <atlstr.h>
+#include <base/basictypes.h>
+
+namespace omaha {
+
+#define kMaxRegistryBackupWaitMs 3000
+#define kMaxRegistryRestoreWaitMs 30000
+
+// amount of time the user must have no input before we declare them idle
+// used by outlook addin, outlook_cap, and filecap.
+#define kUserIdleThresholdMs 30000
+
+// The user is busy typing or interacting with another application
+// if the user is below the minimum threshold.
+#define kUserIdleMinThresholdMs 30000
+
+// The user is probably not paying attention
+// if the user is above the maximum threshold.
+#define kUserIdleMaxThresholdMs 600000
+
+const DWORD kInvalidSessionId = 0xFFFFFFFF;
+
+class System {
+  public:
+
+    // disk activity.
+
+    // waits up to specified time for disk activity to occur; sleeps in
+    // increments of sleep_time.
+    static HRESULT WaitForDiskActivity(uint32 max_delay_milliseconds,
+                                       uint32 sleep_time_ms,
+                                       uint32 *time_waited);
+    // disk activity counters; may require admin on some machines? should return
+    // E_FAIL if so.
+    static HRESULT GetDiskActivityCounters(uint64 *reads,
+                                           uint64 *writes,
+                                           uint64 *bytes_read,
+                                           uint64 *bytes_written);
+
+    // disk statistics.
+
+    // disk total and free space.
+    // Path is either the root of a drive or an existing folder on a drive; the
+    // statistics are for that drive.
+    static HRESULT GetDiskStatistics(const TCHAR* path,
+                                     uint64 *free_bytes_current_user,
+                                     uint64 *total_bytes_current_user,
+                                     uint64 *free_bytes_all_users);
+
+    enum Priority {
+        LOW,
+        HIGH,
+        NORMAL,
+        IDLE
+    };
+
+    // functions to alter process/thread priority.
+    static HRESULT SetThreadPriority(enum Priority priority);
+    static HRESULT SetProcessPriority(enum Priority priority);
+
+    // The three functions below start background processes via ::CreateProcess.
+    // Use the ShellExecuteProcessXXX functions when starting foreground
+    // processes.
+    static HRESULT StartProcessWithArgs(const TCHAR *process_name,
+                                        const TCHAR *cmd_line_arguments);
+    static HRESULT StartProcessWithArgsAndInfo(const TCHAR *process_name,
+                                               const TCHAR *cmd_line_arguments,
+                                               PROCESS_INFORMATION *pi);
+    static HRESULT StartProcess(const TCHAR *process_name,
+                                TCHAR *command_line,
+                                PROCESS_INFORMATION *pi);
+
+
+    // start another process painlessly via ::ShellExecuteEx. Use this method
+    // instead of the StartProcessXXX methods that use ::CreateProcess where
+    // possible, since ::ShellExecuteEx has better behavior on Vista.
+    static HRESULT ShellExecuteProcess(const TCHAR* file_name_to_execute,
+                                       const TCHAR* command_line_parameters,
+                                       HWND hwnd,
+                                       HANDLE* process_handle);
+
+    // start another process painlessly via ::ShellExecuteEx. Use this method
+    // instead of the StartProcessXXX methods that use ::CreateProcess where
+    // possible, since ::ShellExecuteEx has better behavior on Vista.
+    static HRESULT ShellExecuteCommandLine(const TCHAR* command_line_to_execute,
+                                           HWND hwnd,
+                                           HANDLE* process_handle);
+
+    // memory statistics.
+
+    // max amount of memory that can be allocated without paging.
+    static HRESULT MaxPhysicalMemoryAvailable(uint64 *max_bytes);
+
+    // global memory stats
+    static HRESULT GetGlobalMemoryStatistics(
+                       uint32 *memory_load_percentage,
+                       uint64 *free_physical_memory,
+                       uint64 *total_physical_memory,
+                       uint64 *free_paged_memory,
+                       uint64 *total_paged_memory,
+                       uint64 *process_free_virtual_memory,
+                       uint64 *process_total_virtual_memory);
+
+    // process memory stats
+    static HRESULT GetProcessMemoryStatistics(uint64 *current_working_set,
+                                              uint64 *peak_working_set,
+                                              uint64 *min_working_set_size,
+                                              uint64 *max_working_set_size);
+
+    // TODO(omaha): determine if using this where we do with machines
+    // with slow disks causes noticeable slowdown
+
+    // reduce process working set - beware of possible negative performance
+    // implications - this function frees (to the page cache) all used pages,
+    // minimizing the working set - but could lead to additional page faults
+    // when the process continues. If the process continues soon enough the
+    // pages will still be in the page cache so they'll be relatively cheap
+    // soft page faults. This function is best used to reduce memory footprint
+    // when a component is about to go idle for "awhile".
+    static void FreeProcessWorkingSet();
+
+    // returns the number of ms the system has had no user input.
+    static int GetUserIdleTime();
+
+    // from ntddk.h, used as a parameter to get the process handle count.
+    static const int kProcessHandleCount = 20;
+    static uint32 GetProcessHandleCount();
+    static uint32 GetProcessHandleCountOld();
+
+    static void GetGuiObjectCount(uint32 *gdi, uint32 *user);
+
+    static bool IsUserIdle();
+    static bool IsUserBusy();
+    static bool IsScreensaverRunning();
+    static bool IsWorkstationLocked();
+    static bool IsUserAway();
+
+    // Is the system requiring reboot.
+    static bool IsRebooted(const TCHAR* base_file);
+
+    // Mark the system as reboot required.
+    static HRESULT MarkAsRebootRequired(const TCHAR* base_file);
+
+    // Unmark the system as reboot required.
+    static HRESULT UnmarkAsRebootRequired(const TCHAR* base_file);
+
+    // Restart the computer.
+    static HRESULT RestartComputer();
+
+    // Get the full path name of the screen saver program currently selected.
+    // If no screen saver is selected then "fileName" is empty.
+    static HRESULT GetCurrentScreenSaver(CString* fileName);
+
+    // Creates an instance of a COM Local Server class using either plain
+    // vanilla CoCreateInstance, or using the Elevation moniker depending on the
+    // operating system.
+    static HRESULT CoCreateInstanceAsAdmin(HWND hwnd,
+                                           REFCLSID rclsid,
+                                           REFIID riid,
+                                           void** ppv);
+
+    // Attempts to adjust current process privileges.
+    // Only process running with administrator privileges will succeed.
+    static HRESULT AdjustPrivilege(const TCHAR* privilege, bool enable);
+
+    // Checks if the given privilege is enabled for the current process.
+    static HRESULT IsPrivilegeEnabled(const TCHAR* privilege, bool* present);
+
+    // Dynamically links and calls ::WTSGetActiveConsoleSessionId(). Returns
+    // kInvalidSessionId if it cannot find the export in kernel32.dll.
+    static DWORD WTSGetActiveConsoleSessionId();
+
+    // Get the session the current process is running under.
+    static DWORD GetCurrentSessionId();
+
+    // Get the best guess as to the currently active session,
+    // or kInvalidSessionId if there is no active session.
+    static DWORD GetActiveSessionId();
+
+    // Is there a user logged on and active in the specified session?
+    static bool IsSessionActive(DWORD session_id);
+
+    // Is the current process running under WinSta0.
+    static bool IsCurrentProcessInteractive();
+
+    // is the current process running under WinSta0 for the currently active
+    // session.
+    static bool IsCurrentProcessActiveAndInteractive();
+
+    // Returns true if a system battery is detected and the AC line
+    // status is 'offline', otherwise it returns false.
+    static bool IsRunningOnBatteries();
+
+  private:
+    static HRESULT GetRebootCheckDummyFileName(const TCHAR* base_file,
+                                               CString* dummy_file);
+    DISALLOW_EVIL_CONSTRUCTORS(System);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SYSTEM_H__
+
diff --git a/common/system_info.cc b/common/system_info.cc
index 238f2f4..830c94a 100644
--- a/common/system_info.cc
+++ b/common/system_info.cc
@@ -1,462 +1,462 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/system_info.h"

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-

-namespace omaha {

-

-bool SystemInfo::OSWinXPSP2OrLater() {

-  OSVersionType os_type(OS_WINDOWS_UNKNOWN);

-  DWORD sp(0);

-

-  HRESULT hr = CategorizeOS(&os_type, &sp);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("[CategorizeOS failed][0x%x]"), hr));

-    return false;

-  }

-

-  return ((os_type == SystemInfo::OS_WINDOWS_XP && sp >= 2) ||

-          os_type > SystemInfo::OS_WINDOWS_XP);

-}

-

-bool SystemInfo::IsRunningOnW2K() {

-  OSVERSIONINFO os_info = {0};

-  os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

-

-  if (!::GetVersionEx(&os_info)) {

-    ASSERT(false, (L"GetVersionEx"));

-    return false;

-  }

-

-  return os_info.dwMajorVersion == 5 && os_info.dwMinorVersion == 0;

-}

-

-bool SystemInfo::IsRunningOnXPOrLater() {

-  OSVersionType os_type(OS_WINDOWS_UNKNOWN);

-

-  HRESULT hr = CategorizeOS(&os_type, NULL);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr));

-    return false;

-  }

-

-  return os_type >= SystemInfo::OS_WINDOWS_XP;

-}

-

-bool SystemInfo::IsRunningOnXPSP1OrLater() {

-  OSVersionType os_type(OS_WINDOWS_UNKNOWN);

-  DWORD sp(0);

-

-  HRESULT hr = CategorizeOS(&os_type, &sp);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr));

-    return false;

-  }

-

-  return ((os_type == SystemInfo::OS_WINDOWS_XP && sp >= 1) ||

-          os_type > SystemInfo::OS_WINDOWS_XP);

-}

-

-

-bool SystemInfo::IsRunningOnVistaOrLater() {

-  OSVersionType os_type(OS_WINDOWS_UNKNOWN);

-  DWORD sp(0);

-

-  HRESULT hr = CategorizeOS(&os_type, &sp);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr));

-    return false;

-  }

-

-  return (os_type >= OS_WINDOWS_VISTA);

-}

-

-bool SystemInfo::IsRunningOnVistaRTM() {

-  OSVersionType os_type(OS_WINDOWS_UNKNOWN);

-  DWORD sp(0);

-

-  HRESULT hr = CategorizeOS(&os_type, &sp);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr));

-    return false;

-  }

-

-  return (os_type == SystemInfo::OS_WINDOWS_VISTA && sp == 0);

-}

-

-HRESULT SystemInfo::CategorizeOS(OSVersionType* os_ver, DWORD* sp) {

-  static OSVersionType os_ver_cached(OS_WINDOWS_UNKNOWN);

-  // Hopefully, Windows doesn't release a SP that's kUint32Max.

-  static DWORD sp_cached(kUint32Max);

-

-  ASSERT(os_ver, (L""));

-

-  if (sp) {

-    *sp = 0;

-  }

-

-  if (os_ver_cached == OS_WINDOWS_UNKNOWN || sp_cached == kUint32Max) {

-    // Use GetVersionEx to get OS and Service Pack information.

-    OSVERSIONINFOEX osviex;

-    ::ZeroMemory(&osviex, sizeof(OSVERSIONINFOEX));

-    osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

-    BOOL r = ::GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&osviex));

-

-    // If ::GetVersionEx fails when given an OSVERSIONINFOEX then we're running

-    // on NT4.0SP5 or earlier.

-    if (!r) {

-      os_ver_cached = OS_WINDOWS_9X_OR_NT;

-    } else {

-      switch (osviex.dwPlatformId) {

-        case VER_PLATFORM_WIN32_NT:

-          // Windows 7 beta 1 reports the same major version as Vista does.

-          if (osviex.dwMajorVersion == 6 && osviex.dwMinorVersion == 1) {

-            os_ver_cached = OS_WINDOWS_7;

-          } else if (osviex.dwMajorVersion == 6 && osviex.dwMinorVersion == 0) {

-            os_ver_cached = OS_WINDOWS_VISTA;

-          } else if (osviex.dwMajorVersion == 5 && osviex.dwMinorVersion == 2) {

-            os_ver_cached = OS_WINDOWS_SERVER_2003;

-          } else if (osviex.dwMajorVersion == 5 && osviex.dwMinorVersion == 1) {

-            os_ver_cached = OS_WINDOWS_XP;

-          } else if (osviex.dwMajorVersion == 5 && osviex.dwMinorVersion == 0) {

-            os_ver_cached = OS_WINDOWS_2000;

-          } else if (osviex.dwMajorVersion <= 4) {

-            os_ver_cached = OS_WINDOWS_9X_OR_NT;

-            break;

-          } else {

-            os_ver_cached = OS_WINDOWS_UNKNOWN;

-            break;

-          }

-          sp_cached = osviex.wServicePackMajor;

-          break;

-

-        case VER_PLATFORM_WIN32_WINDOWS:

-        case VER_PLATFORM_WIN32s:

-        default:

-          os_ver_cached = OS_WINDOWS_9X_OR_NT;

-          break;

-      }

-    }

-

-    UTIL_LOG(L1, (L"[CategorizeOS][version %s][service pack %d]",

-                  OSVersionTypeAsString(os_ver_cached),

-                  sp_cached));

-  }

-

-  ASSERT1(os_ver_cached != OS_WINDOWS_UNKNOWN && sp_cached != kUint32Max);

-

-  *os_ver = os_ver_cached;

-  if (sp) {

-    *sp = sp_cached;

-  }

-

-  return S_OK;

-}

-

-const wchar_t* SystemInfo::OSVersionTypeAsString(OSVersionType t) {

-  switch (t) {

-    case OS_WINDOWS_9X_OR_NT:    return L"OS_WINDOWS_9X_OR_NT";

-    case OS_WINDOWS_2000:        return L"OS_WINDOWS_2000";

-    case OS_WINDOWS_XP:          return L"OS_WINDOWS_XP";

-    case OS_WINDOWS_SERVER_2003: return L"OS_WINDOWS_SERVER_2003";

-    case OS_WINDOWS_UNKNOWN:     return L"OS_WINDOWS_UNKNOWN";

-    case OS_WINDOWS_VISTA:       return L"OS_WINDOWS_VISTA";

-    case OS_WINDOWS_7:           return L"OS_WINDOWS_7";

-    default:                     return L"<unknown>";

-  }

-}

-

-// The following code which names the operating system comes from MSDN article

-// "Getting the System Version"

-#define kNullChar (_T('\0'))

-bool SystemInfo::GetSystemVersion(int* major_version,

-                                  int* minor_version,

-                                  int* service_pack_major,

-                                  int* service_pack_minor,

-                                  TCHAR*  name_buf,

-                                  size_t name_buf_len) {

-  ASSERT1(major_version);

-  ASSERT1(minor_version);

-  ASSERT1(service_pack_major);

-  ASSERT1(service_pack_minor);

-  ASSERT1(name_buf);

-  ASSERT1(0 < name_buf_len);

-

-  // Clear the name to start with.

-  name_buf[0] = kNullChar;

-

-  DWORD buf_len = MAX_PATH;

-  TCHAR buffer[MAX_PATH];

-  TCHAR format_buffer[64];

-

-  buffer[0] = kNullChar;

-

-  OSVERSIONINFOEX osvi;

-  BOOL ver_info_exists;

-

-  // Try calling GetVersionEx using the OSVERSIONINFOEX structure.

-  // If that fails, try using the OSVERSIONINFO structure.

-  ::ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));

-  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

-

-  ver_info_exists = ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osvi));

-  if (!ver_info_exists) {

-    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

-    if (!::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osvi))) {

-      return false;

-    }

-  }

-

-  *major_version      = osvi.dwMajorVersion;

-  *minor_version      = osvi.dwMinorVersion;

-  *service_pack_major = osvi.wServicePackMajor;

-  *service_pack_minor = osvi.wServicePackMinor;

-

-  switch (osvi.dwPlatformId) {

-    // Test for the Windows NT product family.

-    case VER_PLATFORM_WIN32_NT:

-

-      // Test for the specific product family.

-      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {

-        SafeStrCat(buffer,

-                   _T("Microsoft Windows Server 2003 family, "),

-                   buf_len);

-      }

-

-      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {

-        SafeStrCat(buffer, _T("Microsoft Windows XP "), buf_len);

-      }

-

-      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {

-        SafeStrCat(buffer, _T("Microsoft Windows 2000 "), buf_len);

-      }

-

-      if (osvi.dwMajorVersion <= 4) {

-        SafeStrCat(buffer, _T("Microsoft Windows NT "), buf_len);

-      }

-

-      // Test for specific product on Windows NT 4.0 SP6 and later.

-      if (ver_info_exists) {

-        // Test for the workstation type.

-        if (osvi.wProductType == VER_NT_WORKSTATION) {

-          if (osvi.dwMajorVersion == 4) {

-            SafeStrCat(buffer, _T("Workstation 4.0 "), buf_len);

-          } else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {

-            SafeStrCat(buffer, _T("Home Edition "), buf_len);

-          } else {

-            SafeStrCat(buffer, _T("Professional "), buf_len);

-          }

-        } else if (osvi.wProductType == VER_NT_SERVER ||

-                   osvi.wProductType == VER_NT_DOMAIN_CONTROLLER) {

-          // server type.

-          if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {

-            if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {

-              SafeStrCat(buffer, _T("Datacenter Edition "), buf_len);

-            } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {

-              SafeStrCat(buffer, _T("Enterprise Edition "), buf_len);

-            } else if (osvi.wSuiteMask == VER_SUITE_BLADE) {

-              SafeStrCat(buffer, _T("Web Edition "), buf_len);

-            } else {

-              SafeStrCat(buffer, _T("Standard Edition "), buf_len);

-            }

-          } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {

-            if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {

-              SafeStrCat(buffer, _T("Datacenter Server "), buf_len);

-            } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {

-              SafeStrCat(buffer, _T("Advanced Server "), buf_len);

-            } else {

-              SafeStrCat(buffer, _T("Server "), buf_len);

-            }

-          } else {

-            // Windows NT 4.0.

-            if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {

-              SafeStrCat(buffer,

-                         _T("Server 4.0, Enterprise Edition "),

-                         buf_len);

-            } else {

-              SafeStrCat(buffer, _T("Server 4.0 "), buf_len);

-            }

-          }

-        }

-      } else {

-        // Test for specific product on Windows NT 4.0 SP5 and earlier.

-        HKEY hKey;

-        TCHAR product_type[64] = {0};

-        DWORD dwBufLen = arraysize(product_type);

-        LONG lRet;

-

-        // TODO(omaha): should we use the RegKey API for consistency.

-        lRet = ::RegOpenKeyEx(

-                   HKEY_LOCAL_MACHINE,

-                   _T("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),

-                   0,

-                   KEY_QUERY_VALUE,

-                   &hKey);

-        if (lRet != ERROR_SUCCESS) {

-          return false;

-        }

-

-        lRet = ::RegQueryValueEx(hKey,

-                                 _T("ProductType"),

-                                 NULL,

-                                 NULL,

-                                 reinterpret_cast<byte *>(product_type),

-                                 &dwBufLen);

-        if ((lRet != ERROR_SUCCESS) || (dwBufLen > arraysize(product_type))) {

-          return false;

-        }

-

-        ::RegCloseKey(hKey);

-

-        if (::lstrcmpi(_T("WINNT"), product_type) == 0) {

-          SafeStrCat(buffer, _T("Workstation "), buf_len);

-        }

-        if (::lstrcmpi(_T("LANMANNT"), product_type) == 0) {

-          SafeStrCat(buffer, _T("Server "), buf_len);

-        }

-        if (::lstrcmpi(_T("SERVERNT"), product_type) == 0) {

-          SafeStrCat(buffer, _T("Advanced Server "), buf_len);

-        }

-

-        ::wsprintf(format_buffer,

-                   _T("%d.%d "),

-                   osvi.dwMajorVersion,

-                   osvi.dwMinorVersion);

-        SafeStrCat(buffer, format_buffer, buf_len);

-      }

-

-      // Display service pack (if any) and build number.

-      if (osvi.dwMajorVersion == 4 &&

-          ::lstrcmpi(osvi.szCSDVersion, _T("Service Pack 6")) == 0) {

-        HKEY hKey;

-        LONG lRet;

-

-        // Test for SP6 versus SP6a.

-        lRet = ::RegOpenKeyEx(

-                   HKEY_LOCAL_MACHINE,

-                   _T("SOFTWARE\\Microsoft\\Windows NT\\")

-                       _T("CurrentVersion\\Hotfix\\Q246009"),

-                   0,

-                   KEY_QUERY_VALUE,

-                   &hKey);

-        if (lRet == ERROR_SUCCESS) {

-          ::wsprintf(format_buffer,

-                     _T("Service Pack 6a (Build %d)"),

-                     osvi.dwBuildNumber & 0xFFFF);

-          SafeStrCat(buffer, format_buffer, buf_len);

-        } else {

-          // Windows NT 4.0 prior to SP6a.

-          ::wsprintf(format_buffer, _T("%s (Build %d)"),

-                      osvi.szCSDVersion,

-                      osvi.dwBuildNumber & 0xFFFF);

-          SafeStrCat(buffer, format_buffer, buf_len);

-        }

-        ::RegCloseKey(hKey);

-      } else {

-        // Windows NT 3.51 and earlier or Windows 2000 and later.

-        ::wsprintf(format_buffer,

-                   _T("%s (Build %d)"),

-                   osvi.szCSDVersion,

-                   osvi.dwBuildNumber & 0xFFFF);

-        SafeStrCat(buffer, format_buffer, buf_len);

-      }

-

-      break;

-

-      // Test for the Windows 95 product family.

-    case VER_PLATFORM_WIN32_WINDOWS:

-

-      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {

-        SafeStrCat(buffer, _T("Microsoft Windows 95 "), buf_len);

-        if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') {

-          SafeStrCat(buffer, _T("OSR2 "), buf_len);

-        }

-      }

-

-      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {

-        SafeStrCat(buffer, _T("Microsoft Windows 98 "), buf_len);

-        if (osvi.szCSDVersion[1] == 'A') {

-          SafeStrCat(buffer, _T("SE "), buf_len);

-        }

-      }

-

-      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {

-        SafeStrCat(buffer,

-                   _T("Microsoft Windows Millennium Edition"),

-                   buf_len);

-      }

-      break;

-

-    case VER_PLATFORM_WIN32s:

-

-      SafeStrCat(buffer, _T("Microsoft Win32s"), buf_len);

-      break;

-

-  default:

-    SafeStrCat(buffer, _T("Unknown operating system"), buf_len);

-    break;

-  }

-  // SKIP_LOC_END

-

-  // Remove trailing space, if any.

-  DWORD buffer_len = ::lstrlen(buffer);

-  if (buffer[buffer_len-1] == kNullChar) {

-    buffer[buffer_len-1] = kNullChar;

-  }

-

-  // Copy to destination argument.

-  String_StrNCpy(name_buf, buffer, name_buf_len);

-

-  return true;

-}

-

-

-bool SystemInfo::IsRunningOn64Bit() {

-  static DWORD is64_cached(kUint32Max);

-

-  if (is64_cached == kUint32Max) {

-    typedef void (WINAPI * GetSystemInfoFunc)(LPSYSTEM_INFO);

-

-    HMODULE handle = ::GetModuleHandle(_T("kernel32"));

-    ASSERT1(handle);

-    GetSystemInfoFunc get_native_system_info =

-        reinterpret_cast<GetSystemInfoFunc>(::GetProcAddress(

-                                                handle,

-                                                "GetNativeSystemInfo"));

-

-    if (get_native_system_info != NULL) {

-      SYSTEM_INFO sys_info = {0};

-

-      get_native_system_info(&sys_info);

-

-      is64_cached =

-          sys_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;

-    } else {

-      // If we couldn't get the _native_ system info, then we must be on OS

-      // earlier than XP, so can't be 64-bit anyway.

-      is64_cached = 0;

-    }

-  }

-

-  return is64_cached != 0;

-}

-

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/system_info.h"
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+
+namespace omaha {
+
+bool SystemInfo::OSWinXPSP2OrLater() {
+  OSVersionType os_type(OS_WINDOWS_UNKNOWN);
+  DWORD sp(0);
+
+  HRESULT hr = CategorizeOS(&os_type, &sp);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("[CategorizeOS failed][0x%x]"), hr));
+    return false;
+  }
+
+  return ((os_type == SystemInfo::OS_WINDOWS_XP && sp >= 2) ||
+          os_type > SystemInfo::OS_WINDOWS_XP);
+}
+
+bool SystemInfo::IsRunningOnW2K() {
+  OSVERSIONINFO os_info = {0};
+  os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+  if (!::GetVersionEx(&os_info)) {
+    ASSERT(false, (L"GetVersionEx"));
+    return false;
+  }
+
+  return os_info.dwMajorVersion == 5 && os_info.dwMinorVersion == 0;
+}
+
+bool SystemInfo::IsRunningOnXPOrLater() {
+  OSVersionType os_type(OS_WINDOWS_UNKNOWN);
+
+  HRESULT hr = CategorizeOS(&os_type, NULL);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr));
+    return false;
+  }
+
+  return os_type >= SystemInfo::OS_WINDOWS_XP;
+}
+
+bool SystemInfo::IsRunningOnXPSP1OrLater() {
+  OSVersionType os_type(OS_WINDOWS_UNKNOWN);
+  DWORD sp(0);
+
+  HRESULT hr = CategorizeOS(&os_type, &sp);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr));
+    return false;
+  }
+
+  return ((os_type == SystemInfo::OS_WINDOWS_XP && sp >= 1) ||
+          os_type > SystemInfo::OS_WINDOWS_XP);
+}
+
+
+bool SystemInfo::IsRunningOnVistaOrLater() {
+  OSVersionType os_type(OS_WINDOWS_UNKNOWN);
+  DWORD sp(0);
+
+  HRESULT hr = CategorizeOS(&os_type, &sp);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr));
+    return false;
+  }
+
+  return (os_type >= OS_WINDOWS_VISTA);
+}
+
+bool SystemInfo::IsRunningOnVistaRTM() {
+  OSVersionType os_type(OS_WINDOWS_UNKNOWN);
+  DWORD sp(0);
+
+  HRESULT hr = CategorizeOS(&os_type, &sp);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("[Failed to get os type][0x%x]"), hr));
+    return false;
+  }
+
+  return (os_type == SystemInfo::OS_WINDOWS_VISTA && sp == 0);
+}
+
+HRESULT SystemInfo::CategorizeOS(OSVersionType* os_ver, DWORD* sp) {
+  static OSVersionType os_ver_cached(OS_WINDOWS_UNKNOWN);
+  // Hopefully, Windows doesn't release a SP that's kUint32Max.
+  static DWORD sp_cached(kUint32Max);
+
+  ASSERT(os_ver, (L""));
+
+  if (sp) {
+    *sp = 0;
+  }
+
+  if (os_ver_cached == OS_WINDOWS_UNKNOWN || sp_cached == kUint32Max) {
+    // Use GetVersionEx to get OS and Service Pack information.
+    OSVERSIONINFOEX osviex;
+    ::ZeroMemory(&osviex, sizeof(OSVERSIONINFOEX));
+    osviex.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+    BOOL r = ::GetVersionEx(reinterpret_cast<OSVERSIONINFO *>(&osviex));
+
+    // If ::GetVersionEx fails when given an OSVERSIONINFOEX then we're running
+    // on NT4.0SP5 or earlier.
+    if (!r) {
+      os_ver_cached = OS_WINDOWS_9X_OR_NT;
+    } else {
+      switch (osviex.dwPlatformId) {
+        case VER_PLATFORM_WIN32_NT:
+          // Windows 7 beta 1 reports the same major version as Vista does.
+          if (osviex.dwMajorVersion == 6 && osviex.dwMinorVersion == 1) {
+            os_ver_cached = OS_WINDOWS_7;
+          } else if (osviex.dwMajorVersion == 6 && osviex.dwMinorVersion == 0) {
+            os_ver_cached = OS_WINDOWS_VISTA;
+          } else if (osviex.dwMajorVersion == 5 && osviex.dwMinorVersion == 2) {
+            os_ver_cached = OS_WINDOWS_SERVER_2003;
+          } else if (osviex.dwMajorVersion == 5 && osviex.dwMinorVersion == 1) {
+            os_ver_cached = OS_WINDOWS_XP;
+          } else if (osviex.dwMajorVersion == 5 && osviex.dwMinorVersion == 0) {
+            os_ver_cached = OS_WINDOWS_2000;
+          } else if (osviex.dwMajorVersion <= 4) {
+            os_ver_cached = OS_WINDOWS_9X_OR_NT;
+            break;
+          } else {
+            os_ver_cached = OS_WINDOWS_UNKNOWN;
+            break;
+          }
+          sp_cached = osviex.wServicePackMajor;
+          break;
+
+        case VER_PLATFORM_WIN32_WINDOWS:
+        case VER_PLATFORM_WIN32s:
+        default:
+          os_ver_cached = OS_WINDOWS_9X_OR_NT;
+          break;
+      }
+    }
+
+    UTIL_LOG(L1, (L"[CategorizeOS][version %s][service pack %d]",
+                  OSVersionTypeAsString(os_ver_cached),
+                  sp_cached));
+  }
+
+  ASSERT1(os_ver_cached != OS_WINDOWS_UNKNOWN && sp_cached != kUint32Max);
+
+  *os_ver = os_ver_cached;
+  if (sp) {
+    *sp = sp_cached;
+  }
+
+  return S_OK;
+}
+
+const wchar_t* SystemInfo::OSVersionTypeAsString(OSVersionType t) {
+  switch (t) {
+    case OS_WINDOWS_9X_OR_NT:    return L"OS_WINDOWS_9X_OR_NT";
+    case OS_WINDOWS_2000:        return L"OS_WINDOWS_2000";
+    case OS_WINDOWS_XP:          return L"OS_WINDOWS_XP";
+    case OS_WINDOWS_SERVER_2003: return L"OS_WINDOWS_SERVER_2003";
+    case OS_WINDOWS_UNKNOWN:     return L"OS_WINDOWS_UNKNOWN";
+    case OS_WINDOWS_VISTA:       return L"OS_WINDOWS_VISTA";
+    case OS_WINDOWS_7:           return L"OS_WINDOWS_7";
+    default:                     return L"<unknown>";
+  }
+}
+
+// The following code which names the operating system comes from MSDN article
+// "Getting the System Version"
+#define kNullChar (_T('\0'))
+bool SystemInfo::GetSystemVersion(int* major_version,
+                                  int* minor_version,
+                                  int* service_pack_major,
+                                  int* service_pack_minor,
+                                  TCHAR*  name_buf,
+                                  size_t name_buf_len) {
+  ASSERT1(major_version);
+  ASSERT1(minor_version);
+  ASSERT1(service_pack_major);
+  ASSERT1(service_pack_minor);
+  ASSERT1(name_buf);
+  ASSERT1(0 < name_buf_len);
+
+  // Clear the name to start with.
+  name_buf[0] = kNullChar;
+
+  DWORD buf_len = MAX_PATH;
+  TCHAR buffer[MAX_PATH];
+  TCHAR format_buffer[64];
+
+  buffer[0] = kNullChar;
+
+  OSVERSIONINFOEX osvi;
+  BOOL ver_info_exists;
+
+  // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
+  // If that fails, try using the OSVERSIONINFO structure.
+  ::ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+
+  ver_info_exists = ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osvi));
+  if (!ver_info_exists) {
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+    if (!::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osvi))) {
+      return false;
+    }
+  }
+
+  *major_version      = osvi.dwMajorVersion;
+  *minor_version      = osvi.dwMinorVersion;
+  *service_pack_major = osvi.wServicePackMajor;
+  *service_pack_minor = osvi.wServicePackMinor;
+
+  switch (osvi.dwPlatformId) {
+    // Test for the Windows NT product family.
+    case VER_PLATFORM_WIN32_NT:
+
+      // Test for the specific product family.
+      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
+        SafeStrCat(buffer,
+                   _T("Microsoft Windows Server 2003 family, "),
+                   buf_len);
+      }
+
+      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
+        SafeStrCat(buffer, _T("Microsoft Windows XP "), buf_len);
+      }
+
+      if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
+        SafeStrCat(buffer, _T("Microsoft Windows 2000 "), buf_len);
+      }
+
+      if (osvi.dwMajorVersion <= 4) {
+        SafeStrCat(buffer, _T("Microsoft Windows NT "), buf_len);
+      }
+
+      // Test for specific product on Windows NT 4.0 SP6 and later.
+      if (ver_info_exists) {
+        // Test for the workstation type.
+        if (osvi.wProductType == VER_NT_WORKSTATION) {
+          if (osvi.dwMajorVersion == 4) {
+            SafeStrCat(buffer, _T("Workstation 4.0 "), buf_len);
+          } else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
+            SafeStrCat(buffer, _T("Home Edition "), buf_len);
+          } else {
+            SafeStrCat(buffer, _T("Professional "), buf_len);
+          }
+        } else if (osvi.wProductType == VER_NT_SERVER ||
+                   osvi.wProductType == VER_NT_DOMAIN_CONTROLLER) {
+          // server type.
+          if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
+            if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+              SafeStrCat(buffer, _T("Datacenter Edition "), buf_len);
+            } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+              SafeStrCat(buffer, _T("Enterprise Edition "), buf_len);
+            } else if (osvi.wSuiteMask == VER_SUITE_BLADE) {
+              SafeStrCat(buffer, _T("Web Edition "), buf_len);
+            } else {
+              SafeStrCat(buffer, _T("Standard Edition "), buf_len);
+            }
+          } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
+            if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
+              SafeStrCat(buffer, _T("Datacenter Server "), buf_len);
+            } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+              SafeStrCat(buffer, _T("Advanced Server "), buf_len);
+            } else {
+              SafeStrCat(buffer, _T("Server "), buf_len);
+            }
+          } else {
+            // Windows NT 4.0.
+            if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
+              SafeStrCat(buffer,
+                         _T("Server 4.0, Enterprise Edition "),
+                         buf_len);
+            } else {
+              SafeStrCat(buffer, _T("Server 4.0 "), buf_len);
+            }
+          }
+        }
+      } else {
+        // Test for specific product on Windows NT 4.0 SP5 and earlier.
+        HKEY hKey;
+        TCHAR product_type[64] = {0};
+        DWORD dwBufLen = arraysize(product_type);
+        LONG lRet;
+
+        // TODO(omaha): should we use the RegKey API for consistency.
+        lRet = ::RegOpenKeyEx(
+                   HKEY_LOCAL_MACHINE,
+                   _T("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
+                   0,
+                   KEY_QUERY_VALUE,
+                   &hKey);
+        if (lRet != ERROR_SUCCESS) {
+          return false;
+        }
+
+        lRet = ::RegQueryValueEx(hKey,
+                                 _T("ProductType"),
+                                 NULL,
+                                 NULL,
+                                 reinterpret_cast<byte *>(product_type),
+                                 &dwBufLen);
+        if ((lRet != ERROR_SUCCESS) || (dwBufLen > arraysize(product_type))) {
+          return false;
+        }
+
+        ::RegCloseKey(hKey);
+
+        if (::lstrcmpi(_T("WINNT"), product_type) == 0) {
+          SafeStrCat(buffer, _T("Workstation "), buf_len);
+        }
+        if (::lstrcmpi(_T("LANMANNT"), product_type) == 0) {
+          SafeStrCat(buffer, _T("Server "), buf_len);
+        }
+        if (::lstrcmpi(_T("SERVERNT"), product_type) == 0) {
+          SafeStrCat(buffer, _T("Advanced Server "), buf_len);
+        }
+
+        ::wsprintf(format_buffer,
+                   _T("%d.%d "),
+                   osvi.dwMajorVersion,
+                   osvi.dwMinorVersion);
+        SafeStrCat(buffer, format_buffer, buf_len);
+      }
+
+      // Display service pack (if any) and build number.
+      if (osvi.dwMajorVersion == 4 &&
+          ::lstrcmpi(osvi.szCSDVersion, _T("Service Pack 6")) == 0) {
+        HKEY hKey;
+        LONG lRet;
+
+        // Test for SP6 versus SP6a.
+        lRet = ::RegOpenKeyEx(
+                   HKEY_LOCAL_MACHINE,
+                   _T("SOFTWARE\\Microsoft\\Windows NT\\")
+                       _T("CurrentVersion\\Hotfix\\Q246009"),
+                   0,
+                   KEY_QUERY_VALUE,
+                   &hKey);
+        if (lRet == ERROR_SUCCESS) {
+          ::wsprintf(format_buffer,
+                     _T("Service Pack 6a (Build %d)"),
+                     osvi.dwBuildNumber & 0xFFFF);
+          SafeStrCat(buffer, format_buffer, buf_len);
+        } else {
+          // Windows NT 4.0 prior to SP6a.
+          ::wsprintf(format_buffer, _T("%s (Build %d)"),
+                      osvi.szCSDVersion,
+                      osvi.dwBuildNumber & 0xFFFF);
+          SafeStrCat(buffer, format_buffer, buf_len);
+        }
+        ::RegCloseKey(hKey);
+      } else {
+        // Windows NT 3.51 and earlier or Windows 2000 and later.
+        ::wsprintf(format_buffer,
+                   _T("%s (Build %d)"),
+                   osvi.szCSDVersion,
+                   osvi.dwBuildNumber & 0xFFFF);
+        SafeStrCat(buffer, format_buffer, buf_len);
+      }
+
+      break;
+
+      // Test for the Windows 95 product family.
+    case VER_PLATFORM_WIN32_WINDOWS:
+
+      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
+        SafeStrCat(buffer, _T("Microsoft Windows 95 "), buf_len);
+        if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') {
+          SafeStrCat(buffer, _T("OSR2 "), buf_len);
+        }
+      }
+
+      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
+        SafeStrCat(buffer, _T("Microsoft Windows 98 "), buf_len);
+        if (osvi.szCSDVersion[1] == 'A') {
+          SafeStrCat(buffer, _T("SE "), buf_len);
+        }
+      }
+
+      if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {
+        SafeStrCat(buffer,
+                   _T("Microsoft Windows Millennium Edition"),
+                   buf_len);
+      }
+      break;
+
+    case VER_PLATFORM_WIN32s:
+
+      SafeStrCat(buffer, _T("Microsoft Win32s"), buf_len);
+      break;
+
+  default:
+    SafeStrCat(buffer, _T("Unknown operating system"), buf_len);
+    break;
+  }
+  // SKIP_LOC_END
+
+  // Remove trailing space, if any.
+  DWORD buffer_len = ::lstrlen(buffer);
+  if (buffer[buffer_len-1] == kNullChar) {
+    buffer[buffer_len-1] = kNullChar;
+  }
+
+  // Copy to destination argument.
+  String_StrNCpy(name_buf, buffer, name_buf_len);
+
+  return true;
+}
+
+
+bool SystemInfo::IsRunningOn64Bit() {
+  static DWORD is64_cached(kUint32Max);
+
+  if (is64_cached == kUint32Max) {
+    typedef void (WINAPI * GetSystemInfoFunc)(LPSYSTEM_INFO);
+
+    HMODULE handle = ::GetModuleHandle(_T("kernel32"));
+    ASSERT1(handle);
+    GetSystemInfoFunc get_native_system_info =
+        reinterpret_cast<GetSystemInfoFunc>(::GetProcAddress(
+                                                handle,
+                                                "GetNativeSystemInfo"));
+
+    if (get_native_system_info != NULL) {
+      SYSTEM_INFO sys_info = {0};
+
+      get_native_system_info(&sys_info);
+
+      is64_cached =
+          sys_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64;
+    } else {
+      // If we couldn't get the _native_ system info, then we must be on OS
+      // earlier than XP, so can't be 64-bit anyway.
+      is64_cached = 0;
+    }
+  }
+
+  return is64_cached != 0;
+}
+
+
+}  // namespace omaha
+
diff --git a/common/system_info.h b/common/system_info.h
index 53d947f..2acba56 100644
--- a/common/system_info.h
+++ b/common/system_info.h
@@ -1,108 +1,108 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// TODO(omaha): this code should be updated according to code published by

-// Microsoft at http://msdn.microsoft.com/en-us/library/ms724429(VS.85).aspx.

-// We need a more rigorous clasification of versions.

-

-#ifndef OMAHA_COMMON_SYSTEM_INFO_H__

-#define OMAHA_COMMON_SYSTEM_INFO_H__

-

-#include <windows.h>

-#include <tchar.h>

-

-namespace omaha {

-

-// TODO(omaha): refactor to use a namespace.

-class SystemInfo {

- public:

-  // Find out if the OS is at least Windows 2000

-  // Service pack 4. If OS version is less than that

-  // will return false, all other cases true.

-  static bool OSWin2KSP4OrLater() {

-    // Use GetVersionEx to get OS and Service Pack information.

-    OSVERSIONINFOEX osviex;

-    ::ZeroMemory(&osviex, sizeof(osviex));

-    osviex.dwOSVersionInfoSize = sizeof(osviex);

-    BOOL success = ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osviex));

-    // If this failed we're on Win9X or a pre NT4SP6 OS.

-    if (!success) {

-      return false;

-    }

-

-    if (osviex.dwMajorVersion < 5) {

-      return false;

-    }

-    if (osviex.dwMajorVersion > 5) {

-      return true;    // way beyond Windows XP.

-    }

-    if (osviex.dwMinorVersion >= 1) {

-      return true;    // Windows XP or better.

-    }

-    if (osviex.wServicePackMajor >= 4) {

-      return true;    // Windows 2000 SP4.

-    }

-

-    return false;     // Windows 2000, < SP4.

-  }

-

-  // Returns true if the OS is at least XP SP2.

-  static bool OSWinXPSP2OrLater();

-

-  // CategorizeOS returns a categorization of what operating system is running,

-  // and the service pack level.

-  // NOTE: Please keep this in the order of increasing OS versions

-  enum OSVersionType {

-    OS_WINDOWS_UNKNOWN = 1,

-    OS_WINDOWS_9X_OR_NT,

-    OS_WINDOWS_2000,

-    OS_WINDOWS_XP,

-    OS_WINDOWS_SERVER_2003,

-    OS_WINDOWS_VISTA,

-    OS_WINDOWS_7

-  };

-  static HRESULT CategorizeOS(OSVersionType* os_version, DWORD* service_pack);

-  static const wchar_t* OSVersionTypeAsString(OSVersionType t);

-

-  // Returns true if the current operating system is Windows 2000.

-  static bool IsRunningOnW2K();

-

-  // Are we running on Windows XP or later.

-  static bool IsRunningOnXPOrLater();

-

-  // Are we running on Windows XP SP1 or later.

-  static bool IsRunningOnXPSP1OrLater();

-

-  // Are we running on Windows Vista or later.

-  static bool IsRunningOnVistaOrLater();

-

-  static bool IsRunningOnVistaRTM();

-

-  // Returns the version and the name of the operating system.

-  static bool GetSystemVersion(int* major_version,

-                               int* minor_version,

-                               int* service_pack_major,

-                               int* service_pack_minor,

-                               TCHAR* name_buf,

-                               size_t name_buf_len);

-

-  // Returns whether this is a 64-bit system.

-  static bool IsRunningOn64Bit();

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_SYSTEM_INFO_H__

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// TODO(omaha): this code should be updated according to code published by
+// Microsoft at http://msdn.microsoft.com/en-us/library/ms724429(VS.85).aspx.
+// We need a more rigorous clasification of versions.
+
+#ifndef OMAHA_COMMON_SYSTEM_INFO_H__
+#define OMAHA_COMMON_SYSTEM_INFO_H__
+
+#include <windows.h>
+#include <tchar.h>
+
+namespace omaha {
+
+// TODO(omaha): refactor to use a namespace.
+class SystemInfo {
+ public:
+  // Find out if the OS is at least Windows 2000
+  // Service pack 4. If OS version is less than that
+  // will return false, all other cases true.
+  static bool OSWin2KSP4OrLater() {
+    // Use GetVersionEx to get OS and Service Pack information.
+    OSVERSIONINFOEX osviex;
+    ::ZeroMemory(&osviex, sizeof(osviex));
+    osviex.dwOSVersionInfoSize = sizeof(osviex);
+    BOOL success = ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&osviex));
+    // If this failed we're on Win9X or a pre NT4SP6 OS.
+    if (!success) {
+      return false;
+    }
+
+    if (osviex.dwMajorVersion < 5) {
+      return false;
+    }
+    if (osviex.dwMajorVersion > 5) {
+      return true;    // way beyond Windows XP.
+    }
+    if (osviex.dwMinorVersion >= 1) {
+      return true;    // Windows XP or better.
+    }
+    if (osviex.wServicePackMajor >= 4) {
+      return true;    // Windows 2000 SP4.
+    }
+
+    return false;     // Windows 2000, < SP4.
+  }
+
+  // Returns true if the OS is at least XP SP2.
+  static bool OSWinXPSP2OrLater();
+
+  // CategorizeOS returns a categorization of what operating system is running,
+  // and the service pack level.
+  // NOTE: Please keep this in the order of increasing OS versions
+  enum OSVersionType {
+    OS_WINDOWS_UNKNOWN = 1,
+    OS_WINDOWS_9X_OR_NT,
+    OS_WINDOWS_2000,
+    OS_WINDOWS_XP,
+    OS_WINDOWS_SERVER_2003,
+    OS_WINDOWS_VISTA,
+    OS_WINDOWS_7
+  };
+  static HRESULT CategorizeOS(OSVersionType* os_version, DWORD* service_pack);
+  static const wchar_t* OSVersionTypeAsString(OSVersionType t);
+
+  // Returns true if the current operating system is Windows 2000.
+  static bool IsRunningOnW2K();
+
+  // Are we running on Windows XP or later.
+  static bool IsRunningOnXPOrLater();
+
+  // Are we running on Windows XP SP1 or later.
+  static bool IsRunningOnXPSP1OrLater();
+
+  // Are we running on Windows Vista or later.
+  static bool IsRunningOnVistaOrLater();
+
+  static bool IsRunningOnVistaRTM();
+
+  // Returns the version and the name of the operating system.
+  static bool GetSystemVersion(int* major_version,
+                               int* minor_version,
+                               int* service_pack_major,
+                               int* service_pack_minor,
+                               TCHAR* name_buf,
+                               size_t name_buf_len);
+
+  // Returns whether this is a 64-bit system.
+  static bool IsRunningOn64Bit();
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_SYSTEM_INFO_H__
+
diff --git a/common/system_info_unittest.cc b/common/system_info_unittest.cc
index 7709d9a..cadfe18 100644
--- a/common/system_info_unittest.cc
+++ b/common/system_info_unittest.cc
@@ -1,48 +1,48 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <atlstr.h>

-#include "omaha/common/system_info.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(SystemInfoTest, SystemInfo) {

-  SystemInfo::OSVersionType os_type = SystemInfo::OS_WINDOWS_UNKNOWN;

-  DWORD service_pack = 0;

-  ASSERT_SUCCEEDED(SystemInfo::CategorizeOS(&os_type, &service_pack));

-}

-

-TEST(SystemInfoTest, GetSystemVersion) {

-  int major_version(0);

-  int minor_version(0);

-  int service_pack_major(0);

-  int service_pack_minor(0);

-

-  CString name;

-  ASSERT_TRUE(SystemInfo::GetSystemVersion(&major_version,

-                                           &minor_version,

-                                           &service_pack_major,

-                                           &service_pack_minor,

-                                           CStrBuf(name, MAX_PATH),

-                                           MAX_PATH));

-  EXPECT_NE(0, major_version);

-  EXPECT_EQ(0, service_pack_minor);

-

-  EXPECT_FALSE(name.IsEmpty());

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <atlstr.h>
+#include "omaha/common/system_info.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(SystemInfoTest, SystemInfo) {
+  SystemInfo::OSVersionType os_type = SystemInfo::OS_WINDOWS_UNKNOWN;
+  DWORD service_pack = 0;
+  ASSERT_SUCCEEDED(SystemInfo::CategorizeOS(&os_type, &service_pack));
+}
+
+TEST(SystemInfoTest, GetSystemVersion) {
+  int major_version(0);
+  int minor_version(0);
+  int service_pack_major(0);
+  int service_pack_minor(0);
+
+  CString name;
+  ASSERT_TRUE(SystemInfo::GetSystemVersion(&major_version,
+                                           &minor_version,
+                                           &service_pack_major,
+                                           &service_pack_minor,
+                                           CStrBuf(name, MAX_PATH),
+                                           MAX_PATH));
+  EXPECT_NE(0, major_version);
+  EXPECT_EQ(0, service_pack_minor);
+
+  EXPECT_FALSE(name.IsEmpty());
+}
+
+}  // namespace omaha
+
diff --git a/common/system_unittest.cc b/common/system_unittest.cc
index b5dee9b..010f49c 100644
--- a/common/system_unittest.cc
+++ b/common/system_unittest.cc
@@ -1,73 +1,73 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// System unittest

-//

-// TODO(omaha): there are some untested functions: memory stats, thread

-// priorities, getdirsize (that's mine), backup/restore of registry trees.. not

-// sure how high priority it is to test these things but should probably be

-// added

-

-#include "omaha/common/system.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(SystemTest, System) {

-    uint32 time_waited = 0;

-    ASSERT_SUCCEEDED(System::WaitForDiskActivity(10000, 25, &time_waited));

-

-    uint64 free_bytes_current_user = 0;

-    uint64 total_bytes_current_user = 0;

-    uint64 free_bytes_all_users = 0;

-    ASSERT_SUCCEEDED(System::GetDiskStatistics(_T("C:\\"),

-                                               &free_bytes_current_user,

-                                               &total_bytes_current_user,

-                                               &free_bytes_all_users));

-

-    ASSERT_EQ(System::GetProcessHandleCount(),

-              System::GetProcessHandleCountOld());

-}

-

-// Assume the workstations and PULSE are not running on batteries. The test

-// fails on laptops running on batteries.

-TEST(SystemTest, IsRunningOnBatteries) {

-  ASSERT_FALSE(System::IsRunningOnBatteries());

-}

-

-TEST(SystemTest, GetProcessMemoryStatistics) {

-  uint64 current_working_set(0);

-  uint64 peak_working_set(0);

-  uint64 min_working_set_size(0);

-  uint64 max_working_set_size(0);

-  ASSERT_HRESULT_SUCCEEDED(

-    System::GetProcessMemoryStatistics(&current_working_set,

-                                       &peak_working_set,

-                                       &min_working_set_size,

-                                       &max_working_set_size));

-  EXPECT_LT(0, current_working_set);

-  EXPECT_LT(0, peak_working_set);

-  EXPECT_LT(0, min_working_set_size);

-  EXPECT_LT(0, max_working_set_size);

-}

-

-TEST(SystemTest, GetProcessHandleCount) {

-  DWORD handle_count(0);

-  ASSERT_TRUE(::GetProcessHandleCount(::GetCurrentProcess(), &handle_count));

-  EXPECT_LE(0u, handle_count);

-  EXPECT_EQ(handle_count, System::GetProcessHandleCount());

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// System unittest
+//
+// TODO(omaha): there are some untested functions: memory stats, thread
+// priorities, getdirsize (that's mine), backup/restore of registry trees.. not
+// sure how high priority it is to test these things but should probably be
+// added
+
+#include "omaha/common/system.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(SystemTest, System) {
+    uint32 time_waited = 0;
+    ASSERT_SUCCEEDED(System::WaitForDiskActivity(10000, 25, &time_waited));
+
+    uint64 free_bytes_current_user = 0;
+    uint64 total_bytes_current_user = 0;
+    uint64 free_bytes_all_users = 0;
+    ASSERT_SUCCEEDED(System::GetDiskStatistics(_T("C:\\"),
+                                               &free_bytes_current_user,
+                                               &total_bytes_current_user,
+                                               &free_bytes_all_users));
+
+    ASSERT_EQ(System::GetProcessHandleCount(),
+              System::GetProcessHandleCountOld());
+}
+
+// Assume the workstations and PULSE are not running on batteries. The test
+// fails on laptops running on batteries.
+TEST(SystemTest, IsRunningOnBatteries) {
+  ASSERT_FALSE(System::IsRunningOnBatteries());
+}
+
+TEST(SystemTest, GetProcessMemoryStatistics) {
+  uint64 current_working_set(0);
+  uint64 peak_working_set(0);
+  uint64 min_working_set_size(0);
+  uint64 max_working_set_size(0);
+  ASSERT_HRESULT_SUCCEEDED(
+    System::GetProcessMemoryStatistics(&current_working_set,
+                                       &peak_working_set,
+                                       &min_working_set_size,
+                                       &max_working_set_size));
+  EXPECT_LT(0, current_working_set);
+  EXPECT_LT(0, peak_working_set);
+  EXPECT_LT(0, min_working_set_size);
+  EXPECT_LT(0, max_working_set_size);
+}
+
+TEST(SystemTest, GetProcessHandleCount) {
+  DWORD handle_count(0);
+  ASSERT_TRUE(::GetProcessHandleCount(::GetCurrentProcess(), &handle_count));
+  EXPECT_LE(0u, handle_count);
+  EXPECT_EQ(handle_count, System::GetProcessHandleCount());
+}
+
+}  // namespace omaha
+
diff --git a/common/thread.cc b/common/thread.cc
index 4d19bf9..f7e743b 100644
--- a/common/thread.cc
+++ b/common/thread.cc
@@ -1,169 +1,169 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/thread.h"

-

-#include "omaha/common/debug.h"

-#include "omaha/common/exception_barrier.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/time.h"

-

-namespace omaha {

-

-// The system keeps an event associated with the thread message queue for a

-// while even after the thread is dead. It can appear as a handle leak in the

-// unit test but in fact it is not.

-

-Thread::Thread() : thread_id_(0), thread_(NULL) {

-}

-

-Thread::~Thread() {

-  if (thread_) {

-    VERIFY1(CloseHandle(thread_));

-  }

-  thread_ = NULL;

-}

-

-// This is the thread proc function as required by win32.

-DWORD __stdcall Thread::Prepare(void* this_pointer) {

-  ExceptionBarrier eb;

-

-  ASSERT1(this_pointer);

-  Thread   * this_thread =  reinterpret_cast<Thread*>(this_pointer);

-  Runnable * this_runner =  this_thread->runner_;

-

-  // Create a message queue. Our thread should have one.

-  MSG message = {0};

-  PeekMessage(&message, NULL, WM_USER, WM_USER, PM_NOREMOVE);

-

-  // Start method is waiting on this gate to be open in order

-  // to proceed. By opening gate we say: OK thread is running.

-  this_thread->start_gate_.Open();

-

-  // Now call the interface method. We are done.

-  UTIL_LOG(L4, (L"Thread::Prepare calling thread's Run()"));

-  this_runner->Run();

-

-  return 0;

-}

-

-// Starts the thread. It does not return until the thread is started.

-bool Thread::Start(Runnable* runner) {

-  ASSERT1(runner);

-

-  // Allow the thread object to be reused by cleaning its state up.

-  if (thread_) {

-    VERIFY1(CloseHandle(thread_));

-  }

-  start_gate_.Close();

-

-  runner_ = runner;

-  thread_ = CreateThread(NULL,              // default security attributes

-                         0,                 // use default stack size

-                         &Thread::Prepare,  // thread function

-                         this,              // argument to thread function

-                         0,                 // use default creation flags

-                         &thread_id_);      // returns the thread identifier

-  if (!thread_) {

-    return false;

-  }

-  // Wait until the newly created thread opens the gate for us.

-  return start_gate_.Wait(INFINITE);

-}

-

-DWORD Thread::GetThreadId() const {

-  return thread_id_;

-}

-

-HANDLE Thread::GetThreadHandle() const {

-  return thread_;

-}

-

-bool Thread::Suspend() {

-  return (static_cast<DWORD>(-1) != SuspendThread(thread_));

-}

-

-bool Thread::Resume() {

-  return (static_cast<DWORD>(-1) != ResumeThread(thread_));

-}

-

-bool Thread::Terminate(int exit_code) {

-  return TRUE == TerminateThread(thread_, exit_code);

-}

-

-bool Thread::SetPriority(int priority) {

-  return TRUE == SetThreadPriority(thread_, priority);

-}

-

-bool Thread::GetPriority(int* priority) const {

-  if (!priority) {

-    return false;

-  }

-  *priority = GetThreadPriority(thread_);

-  return THREAD_PRIORITY_ERROR_RETURN != *priority;

-}

-

-// Waits for handle to become signaled.

-bool Thread::WaitTillExit(DWORD msec) const {

-  if (!Running()) {

-    return true;

-  }

-  return WAIT_OBJECT_0 == WaitForSingleObject(thread_, msec);

-}

-

-// Checks if the thread is running.

-bool Thread::Running() const {

-  if (NULL == thread_) {

-    return false;

-  }

-  return WAIT_TIMEOUT == WaitForSingleObject(thread_, 0);

-}

-

-// Executes an APC request.

-void __stdcall Thread::APCProc(ULONG_PTR param) {

-  ApcInfo* pInfo = reinterpret_cast<ApcInfo*>(param);

-  if (pInfo) {

-    if (pInfo->receiver_) {

-      pInfo->receiver_->OnApc(pInfo->param_);

-    }

-    // Deallocates what was allocated in QueueApc.

-    delete pInfo;

-  }

-}

-

-// ApcReceiver wants to execute its OnApc function in the

-// context of this thread.

-bool Thread::QueueApc(ApcReceiver* receiver, ULONG_PTR param) {

-  ASSERT1(receiver);

-  if (!Running()) {

-    // No reason to queue anything to not running thread.

-    return true;

-  }

-

-  // This allocation will be freed in Thread::APCProc

-  ApcInfo* pInfo = new ApcInfo();

-  pInfo->receiver_ = receiver;

-  pInfo->param_    = param;

-  return 0 != QueueUserAPC(&Thread::APCProc,

-                           thread_,

-                           reinterpret_cast<ULONG_PTR>(pInfo));

-}

-

-bool Thread::PostMessage(UINT msg, WPARAM wparam, LPARAM lparam) {

-  return TRUE == PostThreadMessage(thread_id_, msg, wparam, lparam);

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/thread.h"
+
+#include "omaha/common/debug.h"
+#include "omaha/common/exception_barrier.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/time.h"
+
+namespace omaha {
+
+// The system keeps an event associated with the thread message queue for a
+// while even after the thread is dead. It can appear as a handle leak in the
+// unit test but in fact it is not.
+
+Thread::Thread() : thread_id_(0), thread_(NULL) {
+}
+
+Thread::~Thread() {
+  if (thread_) {
+    VERIFY1(CloseHandle(thread_));
+  }
+  thread_ = NULL;
+}
+
+// This is the thread proc function as required by win32.
+DWORD __stdcall Thread::Prepare(void* this_pointer) {
+  ExceptionBarrier eb;
+
+  ASSERT1(this_pointer);
+  Thread   * this_thread =  reinterpret_cast<Thread*>(this_pointer);
+  Runnable * this_runner =  this_thread->runner_;
+
+  // Create a message queue. Our thread should have one.
+  MSG message = {0};
+  PeekMessage(&message, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+
+  // Start method is waiting on this gate to be open in order
+  // to proceed. By opening gate we say: OK thread is running.
+  this_thread->start_gate_.Open();
+
+  // Now call the interface method. We are done.
+  UTIL_LOG(L4, (L"Thread::Prepare calling thread's Run()"));
+  this_runner->Run();
+
+  return 0;
+}
+
+// Starts the thread. It does not return until the thread is started.
+bool Thread::Start(Runnable* runner) {
+  ASSERT1(runner);
+
+  // Allow the thread object to be reused by cleaning its state up.
+  if (thread_) {
+    VERIFY1(CloseHandle(thread_));
+  }
+  start_gate_.Close();
+
+  runner_ = runner;
+  thread_ = CreateThread(NULL,              // default security attributes
+                         0,                 // use default stack size
+                         &Thread::Prepare,  // thread function
+                         this,              // argument to thread function
+                         0,                 // use default creation flags
+                         &thread_id_);      // returns the thread identifier
+  if (!thread_) {
+    return false;
+  }
+  // Wait until the newly created thread opens the gate for us.
+  return start_gate_.Wait(INFINITE);
+}
+
+DWORD Thread::GetThreadId() const {
+  return thread_id_;
+}
+
+HANDLE Thread::GetThreadHandle() const {
+  return thread_;
+}
+
+bool Thread::Suspend() {
+  return (static_cast<DWORD>(-1) != SuspendThread(thread_));
+}
+
+bool Thread::Resume() {
+  return (static_cast<DWORD>(-1) != ResumeThread(thread_));
+}
+
+bool Thread::Terminate(int exit_code) {
+  return TRUE == TerminateThread(thread_, exit_code);
+}
+
+bool Thread::SetPriority(int priority) {
+  return TRUE == SetThreadPriority(thread_, priority);
+}
+
+bool Thread::GetPriority(int* priority) const {
+  if (!priority) {
+    return false;
+  }
+  *priority = GetThreadPriority(thread_);
+  return THREAD_PRIORITY_ERROR_RETURN != *priority;
+}
+
+// Waits for handle to become signaled.
+bool Thread::WaitTillExit(DWORD msec) const {
+  if (!Running()) {
+    return true;
+  }
+  return WAIT_OBJECT_0 == WaitForSingleObject(thread_, msec);
+}
+
+// Checks if the thread is running.
+bool Thread::Running() const {
+  if (NULL == thread_) {
+    return false;
+  }
+  return WAIT_TIMEOUT == WaitForSingleObject(thread_, 0);
+}
+
+// Executes an APC request.
+void __stdcall Thread::APCProc(ULONG_PTR param) {
+  ApcInfo* pInfo = reinterpret_cast<ApcInfo*>(param);
+  if (pInfo) {
+    if (pInfo->receiver_) {
+      pInfo->receiver_->OnApc(pInfo->param_);
+    }
+    // Deallocates what was allocated in QueueApc.
+    delete pInfo;
+  }
+}
+
+// ApcReceiver wants to execute its OnApc function in the
+// context of this thread.
+bool Thread::QueueApc(ApcReceiver* receiver, ULONG_PTR param) {
+  ASSERT1(receiver);
+  if (!Running()) {
+    // No reason to queue anything to not running thread.
+    return true;
+  }
+
+  // This allocation will be freed in Thread::APCProc
+  ApcInfo* pInfo = new ApcInfo();
+  pInfo->receiver_ = receiver;
+  pInfo->param_    = param;
+  return 0 != QueueUserAPC(&Thread::APCProc,
+                           thread_,
+                           reinterpret_cast<ULONG_PTR>(pInfo));
+}
+
+bool Thread::PostMessage(UINT msg, WPARAM wparam, LPARAM lparam) {
+  return TRUE == PostThreadMessage(thread_id_, msg, wparam, lparam);
+}
+
+}  // namespace omaha
+
diff --git a/common/thread.h b/common/thread.h
index 4a4dabd..d2b149c 100644
--- a/common/thread.h
+++ b/common/thread.h
@@ -1,105 +1,105 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines interface Runnable and class Thread.

-//

-// Thread encapsulates win32 primitives of creating and

-// manipulating win32 threads.

-

-#ifndef OMAHA_COMMON_THREAD_H__

-#define OMAHA_COMMON_THREAD_H__

-

-#include "omaha/common/synchronized.h"

-

-namespace omaha {

-

-// Any class which requires part of its execution in a

-// separate thread should be derived from Runnable interface.

-// It can have member variable of type Thread. When the

-// thread needs to be launched one does something like that.

-//  A::func() {

-//    thread_.start(this);

-//  }

-

-class Runnable {

-  friend class Thread;

- protected:

-  Runnable() {}

-  virtual ~Runnable() {}

-  virtual void Run() = 0;

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(Runnable);

-};

-

-// Any class devived from this one will be able to call

-// Thread function QueueApc and have the function OnApc get

-// executed in context of this thread. Thread must be in alertable

-// state to be able to execute the apc function.

-class ApcReceiver {

-  friend class Thread;

- protected:

-  ApcReceiver() {}

-  virtual ~ApcReceiver() {}

-  virtual void OnApc(ULONG_PTR param) = 0;

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(ApcReceiver);

-};

-

-// This class encapsulates win32 thread management functions.

-class Thread {

- public:

-  Thread();

-  ~Thread();

-

-  bool Start(Runnable* runner);

-  bool Suspend();

-  bool Resume();

-  bool Terminate(int exit_code);

-  bool SetPriority(int priority);

-  bool GetPriority(int* priority) const;

-  DWORD GetThreadId() const;

-  HANDLE GetThreadHandle() const;

-

-  // Checks if the thread is running.

-  bool Running() const;

-

-  // Waits until thread exits.

-  bool WaitTillExit(DWORD msec) const;

-

-  // Queues an APC to the ApcReceiver.

-  bool QueueApc(ApcReceiver* receiver, ULONG_PTR param);

-

-  // Posts message to a thread.

-  bool PostMessage(UINT msg, WPARAM wparam, LPARAM lparam);

- private:

-  static DWORD __stdcall Prepare(void* thisPointer);      // Thread proc.

-  static void __stdcall APCProc(ULONG_PTR dwParam);

-

-  Runnable* runner_;     // Interface to work with.

-  HANDLE    thread_;

-  DWORD     thread_id_;

-  Gate start_gate_;     // Synchronizes the thread start.

-

-  struct ApcInfo {

-    ApcReceiver* receiver_;

-    ULONG_PTR    param_;

-  };

-

-  DISALLOW_EVIL_CONSTRUCTORS(Thread);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_THREAD_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines interface Runnable and class Thread.
+//
+// Thread encapsulates win32 primitives of creating and
+// manipulating win32 threads.
+
+#ifndef OMAHA_COMMON_THREAD_H__
+#define OMAHA_COMMON_THREAD_H__
+
+#include "omaha/common/synchronized.h"
+
+namespace omaha {
+
+// Any class which requires part of its execution in a
+// separate thread should be derived from Runnable interface.
+// It can have member variable of type Thread. When the
+// thread needs to be launched one does something like that.
+//  A::func() {
+//    thread_.start(this);
+//  }
+
+class Runnable {
+  friend class Thread;
+ protected:
+  Runnable() {}
+  virtual ~Runnable() {}
+  virtual void Run() = 0;
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(Runnable);
+};
+
+// Any class devived from this one will be able to call
+// Thread function QueueApc and have the function OnApc get
+// executed in context of this thread. Thread must be in alertable
+// state to be able to execute the apc function.
+class ApcReceiver {
+  friend class Thread;
+ protected:
+  ApcReceiver() {}
+  virtual ~ApcReceiver() {}
+  virtual void OnApc(ULONG_PTR param) = 0;
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(ApcReceiver);
+};
+
+// This class encapsulates win32 thread management functions.
+class Thread {
+ public:
+  Thread();
+  ~Thread();
+
+  bool Start(Runnable* runner);
+  bool Suspend();
+  bool Resume();
+  bool Terminate(int exit_code);
+  bool SetPriority(int priority);
+  bool GetPriority(int* priority) const;
+  DWORD GetThreadId() const;
+  HANDLE GetThreadHandle() const;
+
+  // Checks if the thread is running.
+  bool Running() const;
+
+  // Waits until thread exits.
+  bool WaitTillExit(DWORD msec) const;
+
+  // Queues an APC to the ApcReceiver.
+  bool QueueApc(ApcReceiver* receiver, ULONG_PTR param);
+
+  // Posts message to a thread.
+  bool PostMessage(UINT msg, WPARAM wparam, LPARAM lparam);
+ private:
+  static DWORD __stdcall Prepare(void* thisPointer);      // Thread proc.
+  static void __stdcall APCProc(ULONG_PTR dwParam);
+
+  Runnable* runner_;     // Interface to work with.
+  HANDLE    thread_;
+  DWORD     thread_id_;
+  Gate start_gate_;     // Synchronizes the thread start.
+
+  struct ApcInfo {
+    ApcReceiver* receiver_;
+    ULONG_PTR    param_;
+  };
+
+  DISALLOW_EVIL_CONSTRUCTORS(Thread);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_THREAD_H__
diff --git a/common/thread_pool.cc b/common/thread_pool.cc
index 2b9ea45..c0ae30b 100644
--- a/common/thread_pool.cc
+++ b/common/thread_pool.cc
@@ -1,124 +1,124 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/thread_pool.h"

-

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/exception_barrier.h"

-#include "omaha/common/logging.h"

-

-namespace omaha {

-

-namespace {

-

-// Context keeps track the information necessary to execute a work item

-// inside a thread pool thread.

-class Context {

- public:

-  Context(ThreadPool* pool, UserWorkItem* work_item)

-      : pool_(pool),

-        work_item_(work_item) {

-    ASSERT1(pool);

-    ASSERT1(work_item);

-  }

-

-  ThreadPool*   pool() const { return pool_; }

-  UserWorkItem* work_item() const { return work_item_; }

-

- private:

-  ThreadPool*   pool_;

-  UserWorkItem* work_item_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Context);

-};

-

-// Returns true if delta time since 'baseline' is greater or equal than

-// 'milisecs'. Note: GetTickCount wraps around every ~48 days.

-bool TimeHasElapsed(DWORD baseline, DWORD milisecs) {

-  DWORD current = ::GetTickCount();

-  DWORD wrap_bias = 0;

-  if (current < baseline) {

-    wrap_bias = static_cast<DWORD>(0xFFFFFFFF);

-  }

-  return (current - baseline + wrap_bias) >= milisecs ? true : false;

-}

-

-}   // namespace

-

-

-DWORD WINAPI ThreadPool::ThreadProc(void* param) {

-  ExceptionBarrier eb;

-  UTIL_LOG(L4, (_T("[ThreadPool::ThreadProc]")));

-  ASSERT1(param);

-  Context* context = static_cast<Context*>(param);

-  context->pool()->ProcessWorkItem(context->work_item());

-  delete context;

-  return 0;

-}

-

-ThreadPool::ThreadPool()

-    : work_item_count_(0),

-      shutdown_delay_(0) {

-  UTIL_LOG(L2, (_T("[ThreadPool::ThreadPool]")));

-}

-

-ThreadPool::~ThreadPool() {

-  UTIL_LOG(L2, (_T("[ThreadPool::~ThreadPool]")));

-  DWORD baseline_tick_count = ::GetTickCount();

-  if (::SetEvent(get(shutdown_event_))) {

-    while (work_item_count_ != 0) {

-      ::Sleep(1);

-      if (TimeHasElapsed(baseline_tick_count, shutdown_delay_)) {

-        UTIL_LOG(LE, (_T("[ThreadPool::~ThreadPool][timeout elapsed]")));

-        break;

-      }

-    }

-  }

-}

-

-HRESULT ThreadPool::Initialize(int shutdown_delay) {

-  shutdown_delay_ = shutdown_delay;

-  reset(shutdown_event_, ::CreateEvent(NULL, true, false, NULL));

-  return shutdown_event_ ? S_OK : HRESULTFromLastError();

-}

-

-void ThreadPool::ProcessWorkItem(UserWorkItem* work_item) {

-  ASSERT1(work_item);

-  work_item->Process();

-  delete work_item;

-  ::InterlockedDecrement(&work_item_count_);

-}

-

-HRESULT ThreadPool::QueueUserWorkItem(UserWorkItem* work_item, uint32 flags) {

-  UTIL_LOG(L4, (_T("[ThreadPool::QueueUserWorkItem]")));

-  ASSERT1(work_item);

-

-  scoped_ptr<Context> context(new Context(this, work_item));

-  work_item->set_shutdown_event(get(shutdown_event_));

-  ::InterlockedIncrement(&work_item_count_);

-  if (!::QueueUserWorkItem(&ThreadPool::ThreadProc, context.get(), flags)) {

-    ::InterlockedDecrement(&work_item_count_);

-    return HRESULTFromLastError();

-  }

-

-  // The thread pool has the ownership of the work item thereon.

-  context.release();

-  return S_OK;

-}

-

-}   // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/thread_pool.h"
+
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/exception_barrier.h"
+#include "omaha/common/logging.h"
+
+namespace omaha {
+
+namespace {
+
+// Context keeps track the information necessary to execute a work item
+// inside a thread pool thread.
+class Context {
+ public:
+  Context(ThreadPool* pool, UserWorkItem* work_item)
+      : pool_(pool),
+        work_item_(work_item) {
+    ASSERT1(pool);
+    ASSERT1(work_item);
+  }
+
+  ThreadPool*   pool() const { return pool_; }
+  UserWorkItem* work_item() const { return work_item_; }
+
+ private:
+  ThreadPool*   pool_;
+  UserWorkItem* work_item_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Context);
+};
+
+// Returns true if delta time since 'baseline' is greater or equal than
+// 'milisecs'. Note: GetTickCount wraps around every ~48 days.
+bool TimeHasElapsed(DWORD baseline, DWORD milisecs) {
+  DWORD current = ::GetTickCount();
+  DWORD wrap_bias = 0;
+  if (current < baseline) {
+    wrap_bias = static_cast<DWORD>(0xFFFFFFFF);
+  }
+  return (current - baseline + wrap_bias) >= milisecs ? true : false;
+}
+
+}   // namespace
+
+
+DWORD WINAPI ThreadPool::ThreadProc(void* param) {
+  ExceptionBarrier eb;
+  UTIL_LOG(L4, (_T("[ThreadPool::ThreadProc]")));
+  ASSERT1(param);
+  Context* context = static_cast<Context*>(param);
+  context->pool()->ProcessWorkItem(context->work_item());
+  delete context;
+  return 0;
+}
+
+ThreadPool::ThreadPool()
+    : work_item_count_(0),
+      shutdown_delay_(0) {
+  UTIL_LOG(L2, (_T("[ThreadPool::ThreadPool]")));
+}
+
+ThreadPool::~ThreadPool() {
+  UTIL_LOG(L2, (_T("[ThreadPool::~ThreadPool]")));
+  DWORD baseline_tick_count = ::GetTickCount();
+  if (::SetEvent(get(shutdown_event_))) {
+    while (work_item_count_ != 0) {
+      ::Sleep(1);
+      if (TimeHasElapsed(baseline_tick_count, shutdown_delay_)) {
+        UTIL_LOG(LE, (_T("[ThreadPool::~ThreadPool][timeout elapsed]")));
+        break;
+      }
+    }
+  }
+}
+
+HRESULT ThreadPool::Initialize(int shutdown_delay) {
+  shutdown_delay_ = shutdown_delay;
+  reset(shutdown_event_, ::CreateEvent(NULL, true, false, NULL));
+  return shutdown_event_ ? S_OK : HRESULTFromLastError();
+}
+
+void ThreadPool::ProcessWorkItem(UserWorkItem* work_item) {
+  ASSERT1(work_item);
+  work_item->Process();
+  delete work_item;
+  ::InterlockedDecrement(&work_item_count_);
+}
+
+HRESULT ThreadPool::QueueUserWorkItem(UserWorkItem* work_item, uint32 flags) {
+  UTIL_LOG(L4, (_T("[ThreadPool::QueueUserWorkItem]")));
+  ASSERT1(work_item);
+
+  scoped_ptr<Context> context(new Context(this, work_item));
+  work_item->set_shutdown_event(get(shutdown_event_));
+  ::InterlockedIncrement(&work_item_count_);
+  if (!::QueueUserWorkItem(&ThreadPool::ThreadProc, context.get(), flags)) {
+    ::InterlockedDecrement(&work_item_count_);
+    return HRESULTFromLastError();
+  }
+
+  // The thread pool has the ownership of the work item thereon.
+  context.release();
+  return S_OK;
+}
+
+}   // namespace omaha
+
diff --git a/common/thread_pool.h b/common/thread_pool.h
index 70585cd..abbdf28 100644
--- a/common/thread_pool.h
+++ b/common/thread_pool.h
@@ -1,88 +1,88 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_THREAD_POOL_H__

-#define OMAHA_COMMON_THREAD_POOL_H__

-

-#include <windows.h>

-#include "base/basictypes.h"

-#include "omaha/common/scoped_any.h"

-

-namespace omaha {

-

-class UserWorkItem {

- public:

-  UserWorkItem() : shutdown_event_(NULL) {}

-  virtual ~UserWorkItem() {}

-

-  // Template method interface

-  void Process() { DoProcess(); }

-

-  HANDLE shutdown_event() const { return shutdown_event_; }

-  void set_shutdown_event(HANDLE shutdown_event) {

-    shutdown_event_ = shutdown_event;

-  }

-

- private:

-  // Executes the work item.

-  virtual void DoProcess() = 0;

-

-  // It is the job of implementers to watch for the signaling of this event

-  // and shutdown correctly. This event is set when the thread pool is closing.

-  // Do not close this event as is owned by the thread pool.

-  HANDLE shutdown_event_;

-  DISALLOW_EVIL_CONSTRUCTORS(UserWorkItem);

-};

-

-class ThreadPool {

- public:

-  ThreadPool();

-

-  // The destructor might block for 'shutdown_delay'.

-  ~ThreadPool();

-

-  HRESULT Initialize(int shutdown_delay);

-

-  // Returns true if any work items are still in progress.

-  bool HasWorkItems() const { return (0 != work_item_count_); }

-

-  // Adds a work item to the queue. If the add fails the ownership of the

-  // work items remains with the caller.

-  HRESULT QueueUserWorkItem(UserWorkItem* work_item, uint32 flags);

-

- private:

-  // Calls UserWorkItem::Process() in the context of the worker thread.

-  void ProcessWorkItem(UserWorkItem* work_item);

-

-  // This is the thread callback required by the underlying windows API.

-  static DWORD WINAPI ThreadProc(void* context);

-

-  // Approximate number of work items in the pool.

-  volatile LONG work_item_count_;

-

-  // This event signals when the thread pool destructor is in progress.

-  scoped_event shutdown_event_;

-

-  // How many milliseconds to wait for the work items to finish when

-  // the thread pool is shutting down. The shutdown delay resolution is ~10ms.

-  int shutdown_delay_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(ThreadPool);

-};

-

-}   // namespace omaha

-

-#endif  // OMAHA_COMMON_THREAD_POOL_H__

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_THREAD_POOL_H__
+#define OMAHA_COMMON_THREAD_POOL_H__
+
+#include <windows.h>
+#include "base/basictypes.h"
+#include "omaha/common/scoped_any.h"
+
+namespace omaha {
+
+class UserWorkItem {
+ public:
+  UserWorkItem() : shutdown_event_(NULL) {}
+  virtual ~UserWorkItem() {}
+
+  // Template method interface
+  void Process() { DoProcess(); }
+
+  HANDLE shutdown_event() const { return shutdown_event_; }
+  void set_shutdown_event(HANDLE shutdown_event) {
+    shutdown_event_ = shutdown_event;
+  }
+
+ private:
+  // Executes the work item.
+  virtual void DoProcess() = 0;
+
+  // It is the job of implementers to watch for the signaling of this event
+  // and shutdown correctly. This event is set when the thread pool is closing.
+  // Do not close this event as is owned by the thread pool.
+  HANDLE shutdown_event_;
+  DISALLOW_EVIL_CONSTRUCTORS(UserWorkItem);
+};
+
+class ThreadPool {
+ public:
+  ThreadPool();
+
+  // The destructor might block for 'shutdown_delay'.
+  ~ThreadPool();
+
+  HRESULT Initialize(int shutdown_delay);
+
+  // Returns true if any work items are still in progress.
+  bool HasWorkItems() const { return (0 != work_item_count_); }
+
+  // Adds a work item to the queue. If the add fails the ownership of the
+  // work items remains with the caller.
+  HRESULT QueueUserWorkItem(UserWorkItem* work_item, uint32 flags);
+
+ private:
+  // Calls UserWorkItem::Process() in the context of the worker thread.
+  void ProcessWorkItem(UserWorkItem* work_item);
+
+  // This is the thread callback required by the underlying windows API.
+  static DWORD WINAPI ThreadProc(void* context);
+
+  // Approximate number of work items in the pool.
+  volatile LONG work_item_count_;
+
+  // This event signals when the thread pool destructor is in progress.
+  scoped_event shutdown_event_;
+
+  // How many milliseconds to wait for the work items to finish when
+  // the thread pool is shutting down. The shutdown delay resolution is ~10ms.
+  int shutdown_delay_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ThreadPool);
+};
+
+}   // namespace omaha
+
+#endif  // OMAHA_COMMON_THREAD_POOL_H__
+
diff --git a/common/thread_pool_unittest.cc b/common/thread_pool_unittest.cc
index 6b9f504..70deeca 100644
--- a/common/thread_pool_unittest.cc
+++ b/common/thread_pool_unittest.cc
@@ -1,118 +1,118 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/thread_pool.h"

-#include "omaha/common/timer.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-volatile LONG g_completed_count = 0;

-

-// Increments the global count by 1.

-class MyJob1 : public UserWorkItem {

- public:

-  MyJob1() {}

-

- private:

-  virtual void DoProcess() { ::InterlockedExchangeAdd(&g_completed_count, 1); }

-

-  DISALLOW_EVIL_CONSTRUCTORS(MyJob1);

-};

-

-// Increments the global count by 2.

-class MyJob2 : public UserWorkItem {

- public:

-  MyJob2() {}

-

- private:

-  virtual void DoProcess() { ::InterlockedExchangeAdd(&g_completed_count, 2); }

-

-  DISALLOW_EVIL_CONSTRUCTORS(MyJob2);

-};

-

-// Increments the global count by 3.

-class MyJob3 : public UserWorkItem {

- public:

-  MyJob3() {}

-

- private:

-  virtual void DoProcess() { ::InterlockedExchangeAdd(&g_completed_count, 3); }

-

-  DISALLOW_EVIL_CONSTRUCTORS(MyJob3);

-};

-

-HRESULT QueueMyJob1(ThreadPool* thread_pool) {

-  scoped_ptr<MyJob1> job(new MyJob1);

-  HRESULT hr = thread_pool->QueueUserWorkItem(job.get(), WT_EXECUTEDEFAULT);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  job.release();

-  return S_OK;

-}

-

-HRESULT QueueMyJob2(ThreadPool* thread_pool) {

-  scoped_ptr<MyJob2> job(new MyJob2);

-  HRESULT hr = thread_pool->QueueUserWorkItem(job.get(), WT_EXECUTEDEFAULT);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  job.release();

-  return S_OK;

-}

-

-HRESULT QueueMyJob3(ThreadPool* thread_pool) {

-  scoped_ptr<MyJob3> job(new MyJob3);

-  HRESULT hr = thread_pool->QueueUserWorkItem(job.get(), WT_EXECUTEDEFAULT);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  job.release();

-  return S_OK;

-}

-

-}   // namespace

-

-// Creates several jobs to increment a global counter by different values and

-// then it checks the value is correct.

-TEST(ThreadPoolTest, ThreadPool) {

-  const int kShutdownDelayMs = 0;

-  const int kNumJobsEachType = 100;

-

-  ThreadPool thread_pool;

-  ASSERT_HRESULT_SUCCEEDED(thread_pool.Initialize(kShutdownDelayMs));

-

-  for (int i = 0; i != kNumJobsEachType; ++i) {

-    EXPECT_HRESULT_SUCCEEDED(QueueMyJob1(&thread_pool));

-    EXPECT_HRESULT_SUCCEEDED(QueueMyJob2(&thread_pool));

-    EXPECT_HRESULT_SUCCEEDED(QueueMyJob3(&thread_pool));

-  }

-

-  const int kMaxWaitForJobsMs = 2000;

-  LowResTimer t(true);

-  while (thread_pool.HasWorkItems() &&

-         t.GetMilliseconds() < kMaxWaitForJobsMs) {

-    ::Sleep(100);

-  }

-  EXPECT_EQ(g_completed_count, 6 * kNumJobsEachType);

-}

-

-}   // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/thread_pool.h"
+#include "omaha/common/timer.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+volatile LONG g_completed_count = 0;
+
+// Increments the global count by 1.
+class MyJob1 : public UserWorkItem {
+ public:
+  MyJob1() {}
+
+ private:
+  virtual void DoProcess() { ::InterlockedExchangeAdd(&g_completed_count, 1); }
+
+  DISALLOW_EVIL_CONSTRUCTORS(MyJob1);
+};
+
+// Increments the global count by 2.
+class MyJob2 : public UserWorkItem {
+ public:
+  MyJob2() {}
+
+ private:
+  virtual void DoProcess() { ::InterlockedExchangeAdd(&g_completed_count, 2); }
+
+  DISALLOW_EVIL_CONSTRUCTORS(MyJob2);
+};
+
+// Increments the global count by 3.
+class MyJob3 : public UserWorkItem {
+ public:
+  MyJob3() {}
+
+ private:
+  virtual void DoProcess() { ::InterlockedExchangeAdd(&g_completed_count, 3); }
+
+  DISALLOW_EVIL_CONSTRUCTORS(MyJob3);
+};
+
+HRESULT QueueMyJob1(ThreadPool* thread_pool) {
+  scoped_ptr<MyJob1> job(new MyJob1);
+  HRESULT hr = thread_pool->QueueUserWorkItem(job.get(), WT_EXECUTEDEFAULT);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  job.release();
+  return S_OK;
+}
+
+HRESULT QueueMyJob2(ThreadPool* thread_pool) {
+  scoped_ptr<MyJob2> job(new MyJob2);
+  HRESULT hr = thread_pool->QueueUserWorkItem(job.get(), WT_EXECUTEDEFAULT);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  job.release();
+  return S_OK;
+}
+
+HRESULT QueueMyJob3(ThreadPool* thread_pool) {
+  scoped_ptr<MyJob3> job(new MyJob3);
+  HRESULT hr = thread_pool->QueueUserWorkItem(job.get(), WT_EXECUTEDEFAULT);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  job.release();
+  return S_OK;
+}
+
+}   // namespace
+
+// Creates several jobs to increment a global counter by different values and
+// then it checks the value is correct.
+TEST(ThreadPoolTest, ThreadPool) {
+  const int kShutdownDelayMs = 0;
+  const int kNumJobsEachType = 100;
+
+  ThreadPool thread_pool;
+  ASSERT_HRESULT_SUCCEEDED(thread_pool.Initialize(kShutdownDelayMs));
+
+  for (int i = 0; i != kNumJobsEachType; ++i) {
+    EXPECT_HRESULT_SUCCEEDED(QueueMyJob1(&thread_pool));
+    EXPECT_HRESULT_SUCCEEDED(QueueMyJob2(&thread_pool));
+    EXPECT_HRESULT_SUCCEEDED(QueueMyJob3(&thread_pool));
+  }
+
+  const int kMaxWaitForJobsMs = 2000;
+  LowResTimer t(true);
+  while (thread_pool.HasWorkItems() &&
+         t.GetMilliseconds() < kMaxWaitForJobsMs) {
+    ::Sleep(100);
+  }
+  EXPECT_EQ(g_completed_count, 6 * kNumJobsEachType);
+}
+
+}   // namespace omaha
+
diff --git a/common/time.cc b/common/time.cc
index 35b4135..ec17dbc 100644
--- a/common/time.cc
+++ b/common/time.cc
@@ -1,500 +1,500 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Time functions

-

-#include "omaha/common/time.h"

-

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-// Date Constants

-

-#define kNumOfDays 7

-#define kNumOfMonth 12

-

-static const TCHAR kRFC822_DateDelimiters[]    = _T(" ,:");

-static const TCHAR kRFC822_TimeDelimiter[]     = _T(":");

-SELECTANY const TCHAR* kRFC822_Day[kNumOfDays] = {

-  _T("Mon"),

-  _T("Tue"),

-  _T("Wed"),

-  _T("Thu"),

-  _T("Fri"),

-  _T("Sat"),

-  _T("Sun") };

-

-SELECTANY const TCHAR* kRFC822_Month[kNumOfMonth] = {

-  _T("Jan"),

-  _T("Feb"),

-  _T("Mar"),

-  _T("Apr"),

-  _T("May"),

-  _T("Jun"),

-  _T("Jul"),

-  _T("Aug"),

-  _T("Sep"),

-  _T("Oct"),

-  _T("Nov"),

-  _T("Dec") };

-

-struct TimeZoneInfo {

-  const TCHAR* zone_name;

-  int hour_dif;

-};

-

-SELECTANY TimeZoneInfo kRFC822_TimeZone[] = {

-  { _T("UT"),  0 },

-  { _T("GMT"), 0 },

-  { _T("EST"), -5 },

-  { _T("EDT"), -4 },

-  { _T("CST"), -6 },

-  { _T("CDT"), -5 },

-  { _T("MST"), -7 },

-  { _T("MDT"), -6 },

-  { _T("PST"), -8 },

-  { _T("PDT"), -7 },

-  { _T("A"),   -1 },  // Military time zones

-  { _T("B"),   -2 },

-  { _T("C"),   -3 },

-  { _T("D"),   -4 },

-  { _T("E"),   -5 },

-  { _T("F"),   -6 },

-  { _T("G"),   -7 },

-  { _T("H"),   -8 },

-  { _T("I"),   -9 },

-  { _T("K"),   -10 },

-  { _T("L"),   -11 },

-  { _T("M"),   -12 },

-  { _T("N"),    1 },

-  { _T("O"),    2 },

-  { _T("P"),    3 },

-  { _T("Q"),    4 },

-  { _T("R"),    5 },

-  { _T("S"),    6 },

-  { _T("T"),    7 },

-  { _T("U"),    8 },

-  { _T("V"),    9 },

-  { _T("W"),    10 },

-  { _T("X"),    11 },

-  { _T("Y"),    12 },

-  { _T("Z"),    0 },

-};

-

-SELECTANY const TCHAR *days[] =

-  { L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat" };

-

-SELECTANY const TCHAR *months[] = {

-  L"Jan",

-  L"Feb",

-  L"Mar",

-  L"Apr",

-  L"May",

-  L"Jun",

-  L"Jul",

-  L"Aug",

-  L"Sep",

-  L"Oct",

-  L"Nov",

-  L"Dec"

-};

-

-// NOTE: so long as the output is used internally only, no localization is

-// needed here.

-CString ConvertTimeToGMTString(const FILETIME *ft) {

-  ASSERT(ft, (L""));

-

-  CString s;

-  SYSTEMTIME st;

-  if (!FileTimeToSystemTime(ft, &st)) {

-    return L"";

-  }

-

-  // same as FormatGmt(_T("%a, %d %b %Y %H:%M:%S GMT"));

-  s.Format(NOTRANSL(L"%s, %02d %s %d %02d:%02d:%02d GMT"), days[st.wDayOfWeek],

-    st.wDay, months[st.wMonth-1], st.wYear, st.wHour, st.wMinute, st.wSecond);

-  return s;

-}

-

-time64 ConvertTime16ToTime64(uint16 time16) {

-  return time16 * kTimeGranularity + kStart100NsTime;

-}

-

-uint16 ConvertTime64ToTime16(time64 time) {

-  ASSERT1(time >= kStart100NsTime);

-

-  time64 t64 = (time - kStart100NsTime) / kTimeGranularity;

-  ASSERT1(t64 <= kTime16Max);

-

-  return static_cast<uint16>(t64);

-}

-

-time64 TimeTToTime64(const time_t& old_value) {

-  FILETIME file_time;

-  TimeTToFileTime(old_value, &file_time);

-  return FileTimeToTime64(file_time);

-}

-

-#ifdef _DEBUG

-void ComputeStartTime() {

-    SYSTEMTIME start_system_time = kStartSystemTime;

-    time64 start_100ns_time = SystemTimeToTime64(&start_system_time);

-    UTIL_LOG(L1, (_T("posting list starting time = %s\n"),

-                  String_Int64ToString(start_100ns_time, 10)));

-}

-#endif

-

-// Time management

-

-// Allow the unittest to override.

-static time64 time_override = 0;

-

-// #ifdef UNITTEST

-void SetTimeOverride(const time64 & time_new) {

-  time_override = time_new;

-}

-

-// #endif

-

-time64 GetCurrent100NSTime() {

-  if (time_override != 0)

-    return time_override;

-

-  // In order gte the 100ns time we shouldn't use SystemTime

-  // as it's granularity is 1 ms. Below is the correct implementation.

-  // On the other hand the system clock granularity is 15 ms, so we

-  // are not gaining much by having the timestamp in nano-sec

-  // If we decide to go with ms, divide "time64 time" by 10000

-  // SYSTEMTIME sys_time;

-  // GetLocalTime(&sys_time);

-  // return SystemTimeToTime64(&sys_time);

-

-  // get the current time in 100-nanoseconds intervals

-  FILETIME file_time;

-  ::GetSystemTimeAsFileTime(&file_time);

-

-  time64 time = FileTimeToTime64(file_time);

-  return time;

-}

-

-time64 SystemTimeToTime64(const SYSTEMTIME* sys_time) {

-  ASSERT1(sys_time);

-

-  FILETIME file_time;

-  SetZero(file_time);

-

-  if (!::SystemTimeToFileTime(sys_time, &file_time)) {

-    UTIL_LOG(LE,

-             (_T("[SystemTimeToTime64 - failed to SystemTimeToFileTime][0x%x]"),

-              HRESULTFromLastError()));

-    return 0;

-  }

-

-  return FileTimeToTime64(file_time);

-}

-

-// returns a value compatible with EXE/DLL timestamps

-// and the C time() function

-// NOTE: behavior is independent of wMilliseconds value

-int32 SystemTimeToInt32(const SYSTEMTIME *sys_time) {

-  ASSERT(sys_time, (L""));

-

-  time64 t64 = SystemTimeToTime64(sys_time);

-  int32 t32 = 0;

-

-  if (t64 != 0) {

-    t32 = Time64ToInt32(t64);

-  }

-  return t32;

-}

-

-int32 Time64ToInt32(const time64 & time) {

-  // convert to 32-bit format

-  // time() (32-bit) measures seconds since 1970/01/01 00:00:00 (UTC)

-  // FILETIME (64-bit) measures 100-ns intervals since 1601/01/01 00:00:00 (UTC)

-

-  // seconds between 1601 and 1970

-  time64 t32 = (time / kSecsTo100ns) -

-               ((time64(60*60*24) * time64(365*369 + 89)));

-  ASSERT(t32 == (t32 & 0x7FFFFFFF), (L""));  // make sure it fits

-

-  // cast at the end (avoids overflow/underflow when computing 32-bit value)

-  return static_cast<int32>(t32);

-}

-

-time64 Int32ToTime64(const int32 & time) {

-  // convert to 64-bit format

-  // time() (32-bit) measures seconds since 1970/01/01 00:00:00 (UTC)

-  // FILETIME (64-bit) measures 100-ns intervals since 1601/01/01 00:00:00 (UTC)

-

-  // seconds between 1601 and 1970

-  time64 t64 = (static_cast<time64>(time) +

-               (time64(60*60*24) * time64(365*369 + 89))) * kSecsTo100ns;

-  return t64;

-}

-

-// TODO(omaha): The next 2 functions can fail if FileTimeToLocalFileTime or

-// FileTimeToSystemTime fails.

-// Consider having it return a HRESULT. Right now if FileTimeToSystemTime fails,

-// it returns an undefined value.

-

-// Convert a uint to a genuine systemtime

-SYSTEMTIME Time64ToSystemTime(const time64& time) {

-  FILETIME file_time;

-  SetZero(file_time);

-  Time64ToFileTime(time, &file_time);

-

-  SYSTEMTIME sys_time;

-  SetZero(sys_time);

-  if (!FileTimeToSystemTime(&file_time, &sys_time)) {

-    UTIL_LOG(LE, (_T("[Time64ToSystemTime]")

-                  _T("[failed to FileTimeToSystemTime][0x%x]"),

-                  HRESULTFromLastError()));

-  }

-

-  return sys_time;

-}

-

-

-// Convert a uint to a genuine localtime

-// Should ONLY be used for display, since internally we use only UTC

-SYSTEMTIME Time64ToLocalTime(const time64& time) {

-  FILETIME file_time;

-  SetZero(file_time);

-  Time64ToFileTime(time, &file_time);

-

-  FILETIME local_file_time;

-  SetZero(local_file_time);

-  if (!FileTimeToLocalFileTime(&file_time, &local_file_time)) {

-    UTIL_LOG(LE, (_T("[Time64ToLocalTime]")

-                  _T("[failed to FileTimeToLocalFileTime][0x%x]"),

-                  HRESULTFromLastError()));

-  }

-

-  SYSTEMTIME local_time;

-  SetZero(local_time);

-  if (!FileTimeToSystemTime(&local_file_time, &local_time)) {

-    UTIL_LOG(LE, (_T("[Time64ToLocalTime]")

-                  _T("[failed to FileTimeToSystemTime][0x%x]"),

-                  HRESULTFromLastError()));

-  }

-

-  return local_time;

-}

-

-time64 FileTimeToTime64(const FILETIME & file_time) {

-  return static_cast<time64>(

-      file_time.dwHighDateTime) << 32 | file_time.dwLowDateTime;

-}

-

-void Time64ToFileTime(const time64 & time, FILETIME *ft) {

-  ASSERT(ft, (L""));

-

-  ft->dwHighDateTime = static_cast<DWORD>(time >> 32);

-  ft->dwLowDateTime = static_cast<DWORD>(time & 0xffffffff);

-}

-

-// Convert from FILETIME to time_t

-time_t FileTimeToTimeT(const FILETIME& file_time) {

-  return static_cast<time_t>(

-      (FileTimeToTime64(file_time) - kTimeTConvValue) / kSecsTo100ns);

-}

-

-// Convert from time_t to FILETIME

-void TimeTToFileTime(const time_t& time, FILETIME* file_time) {

-  ASSERT1(file_time);

-

-  LONGLONG ll = Int32x32To64(time, kSecsTo100ns) + kTimeTConvValue;

-  file_time->dwLowDateTime = static_cast<DWORD>(ll);

-  file_time->dwHighDateTime = static_cast<DWORD>(ll >> 32);

-}

-

-// Parses RFC 822 Date/Time format

-//    5.  DATE AND TIME SPECIFICATION

-//     5.1.  SYNTAX

-//

-//     date-time   =  [ day "," ] date time        ; dd mm yy

-//                                                 ;  hh:mm:ss zzz

-//     day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"

-//                 /  "Fri"  / "Sat" /  "Sun"

-//

-//     date        =  1*2DIGIT month 2DIGIT        ; day month year

-//                                                 ;  e.g. 20 Jun 82

-//

-//     month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"

-//                 /  "May"  /  "Jun" /  "Jul"  /  "Aug"

-//                 /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"

-//

-//     time        =  hour zone                    ; ANSI and Military

-//

-//     hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]

-//                                                 ; 00:00:00 - 23:59:59

-//

-//     zone        =  "UT"  / "GMT"                ; Universal Time

-//                                                 ; North American : UT

-//                 /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4

-//                 /  "CST" / "CDT"                ;  Central:  - 6/ - 5

-//                 /  "MST" / "MDT"                ;  Mountain: - 7/ - 6

-//                 /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7

-//                 /  1ALPHA                       ; Military: Z = UT;

-//                                                 ;  A:-1; (J not used)

-//                                                 ;  M:-12; N:+1; Y:+12

-//                 / ( ("+" / "-") 4DIGIT )        ; Local differential

-//                                                 ;  hours+min. (HHMM)

-// return local time if ret_local_time == true,

-// return time is GMT / UTC time otherwise

-bool RFC822DateToSystemTime(const TCHAR* str_RFC822_date,

-                            SYSTEMTIME* psys_time,

-                            bool ret_local_time) {

-  ASSERT(str_RFC822_date != NULL, (L""));

-  ASSERT(psys_time != NULL, (L""));

-

-  CString str_date = str_RFC822_date;

-  CString str_token;

-  int cur_pos = 0;

-

-  str_token= str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);

-  if (str_token == "")

-    return false;

-

-  int i = 0;

-  for (i = 0; i < kNumOfDays; i++) {

-    if (str_token == kRFC822_Day[i]) {

-      str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);

-      if (str_token == "")

-        return false;

-      break;

-    }

-  }

-

-  int day = String_StringToInt(str_token);

-  if (day < 0 || day > 31)

-    return false;

-

-  str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);

-  if (str_token == "")

-    return false;

-

-  int month = -1;

-  for (i = 0; i < kNumOfMonth; i++) {

-    if (str_token == kRFC822_Month[i]) {

-      month = i+1;  // month is 1 based number

-      break;

-    }

-  }

-  if (month == -1)  // month not found

-    return false;

-

-  str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);

-  if (str_token == "")

-    return false;

-

-  int year = String_StringToInt(str_token);

-  if (year < 100)  // two digit year format, convert to 1950 - 2050 range

-    if (year < 50)

-      year += 2000;

-    else

-      year += 1900;

-

-  str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);

-  if (str_token == "")

-    return false;

-

-  int hour = String_StringToInt(str_token);

-  if (hour < 0 || hour > 23)

-    return false;

-

-  str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);

-  if (str_token == "")

-    return false;

-

-  int minute = String_StringToInt(str_token);

-  if (minute < 0 || minute > 59)

-    return false;

-

-  str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);

-  if (str_token == "")

-    return false;

-

-  int second = 0;

-  // distingushed between XX:XX and XX:XX:XX time formats

-  if (str_token.GetLength() == 2 &&

-      String_IsDigit(str_token[0]) &&

-      String_IsDigit(str_token[1])) {

-    second = String_StringToInt(str_token);

-    if (second < 0 || second > 59)

-      return false;

-

-    str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);

-    if (str_token == "")

-      return false;

-  }

-

-  int bias = 0;

-  if (str_token[0] == '+' ||

-      str_token[0] == '-' ||

-      String_IsDigit(str_token[0])) {  // numeric format

-    int zone = String_StringToInt(str_token);

-

-    // zone is in HHMM format, need to convert to the number of minutes

-    bias = (zone / 100) * 60 + (zone % 100);

-  } else {  // text format

-    for (i = 0; i < sizeof(kRFC822_TimeZone) / sizeof(TimeZoneInfo); i++)

-      if (str_token == kRFC822_TimeZone[i].zone_name) {

-        bias = kRFC822_TimeZone[i].hour_dif * 60;

-        break;

-      }

-  }

-

-  SYSTEMTIME mail_time;

-  memset(&mail_time, 0, sizeof(mail_time));

-

-  mail_time.wYear   = static_cast<WORD>(year);

-  mail_time.wMonth  = static_cast<WORD>(month);

-  mail_time.wDay    = static_cast<WORD>(day);

-  mail_time.wHour   = static_cast<WORD>(hour);

-  mail_time.wMinute = static_cast<WORD>(minute);

-  mail_time.wSecond = static_cast<WORD>(second);

-

-  // TzSpecificLocalTimeToSystemTime() is incompatible with Win 2000,

-  // convert time manually here

-  time64 time_64 = SystemTimeToTime64(&mail_time);

-  time_64 = time_64 - (bias*kMinsTo100ns);

-

-  *psys_time = Time64ToSystemTime(time_64);

-

-  if (ret_local_time) {

-    TIME_ZONE_INFORMATION local_time_zone_info;

-    SYSTEMTIME universal_time = *psys_time;

-

-    if (GetTimeZoneInformation(&local_time_zone_info) == TIME_ZONE_ID_INVALID) {

-      return false;

-    }

-    if (!SystemTimeToTzSpecificLocalTime(&local_time_zone_info,

-                                    &universal_time,

-                                    psys_time)) {

-      return false;

-    }

-  }

-  return true;

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Time functions
+
+#include "omaha/common/time.h"
+
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+// Date Constants
+
+#define kNumOfDays 7
+#define kNumOfMonth 12
+
+static const TCHAR kRFC822_DateDelimiters[]    = _T(" ,:");
+static const TCHAR kRFC822_TimeDelimiter[]     = _T(":");
+SELECTANY const TCHAR* kRFC822_Day[kNumOfDays] = {
+  _T("Mon"),
+  _T("Tue"),
+  _T("Wed"),
+  _T("Thu"),
+  _T("Fri"),
+  _T("Sat"),
+  _T("Sun") };
+
+SELECTANY const TCHAR* kRFC822_Month[kNumOfMonth] = {
+  _T("Jan"),
+  _T("Feb"),
+  _T("Mar"),
+  _T("Apr"),
+  _T("May"),
+  _T("Jun"),
+  _T("Jul"),
+  _T("Aug"),
+  _T("Sep"),
+  _T("Oct"),
+  _T("Nov"),
+  _T("Dec") };
+
+struct TimeZoneInfo {
+  const TCHAR* zone_name;
+  int hour_dif;
+};
+
+SELECTANY TimeZoneInfo kRFC822_TimeZone[] = {
+  { _T("UT"),  0 },
+  { _T("GMT"), 0 },
+  { _T("EST"), -5 },
+  { _T("EDT"), -4 },
+  { _T("CST"), -6 },
+  { _T("CDT"), -5 },
+  { _T("MST"), -7 },
+  { _T("MDT"), -6 },
+  { _T("PST"), -8 },
+  { _T("PDT"), -7 },
+  { _T("A"),   -1 },  // Military time zones
+  { _T("B"),   -2 },
+  { _T("C"),   -3 },
+  { _T("D"),   -4 },
+  { _T("E"),   -5 },
+  { _T("F"),   -6 },
+  { _T("G"),   -7 },
+  { _T("H"),   -8 },
+  { _T("I"),   -9 },
+  { _T("K"),   -10 },
+  { _T("L"),   -11 },
+  { _T("M"),   -12 },
+  { _T("N"),    1 },
+  { _T("O"),    2 },
+  { _T("P"),    3 },
+  { _T("Q"),    4 },
+  { _T("R"),    5 },
+  { _T("S"),    6 },
+  { _T("T"),    7 },
+  { _T("U"),    8 },
+  { _T("V"),    9 },
+  { _T("W"),    10 },
+  { _T("X"),    11 },
+  { _T("Y"),    12 },
+  { _T("Z"),    0 },
+};
+
+SELECTANY const TCHAR *days[] =
+  { L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat" };
+
+SELECTANY const TCHAR *months[] = {
+  L"Jan",
+  L"Feb",
+  L"Mar",
+  L"Apr",
+  L"May",
+  L"Jun",
+  L"Jul",
+  L"Aug",
+  L"Sep",
+  L"Oct",
+  L"Nov",
+  L"Dec"
+};
+
+// NOTE: so long as the output is used internally only, no localization is
+// needed here.
+CString ConvertTimeToGMTString(const FILETIME *ft) {
+  ASSERT(ft, (L""));
+
+  CString s;
+  SYSTEMTIME st;
+  if (!FileTimeToSystemTime(ft, &st)) {
+    return L"";
+  }
+
+  // same as FormatGmt(_T("%a, %d %b %Y %H:%M:%S GMT"));
+  s.Format(NOTRANSL(L"%s, %02d %s %d %02d:%02d:%02d GMT"), days[st.wDayOfWeek],
+    st.wDay, months[st.wMonth-1], st.wYear, st.wHour, st.wMinute, st.wSecond);
+  return s;
+}
+
+time64 ConvertTime16ToTime64(uint16 time16) {
+  return time16 * kTimeGranularity + kStart100NsTime;
+}
+
+uint16 ConvertTime64ToTime16(time64 time) {
+  ASSERT1(time >= kStart100NsTime);
+
+  time64 t64 = (time - kStart100NsTime) / kTimeGranularity;
+  ASSERT1(t64 <= kTime16Max);
+
+  return static_cast<uint16>(t64);
+}
+
+time64 TimeTToTime64(const time_t& old_value) {
+  FILETIME file_time;
+  TimeTToFileTime(old_value, &file_time);
+  return FileTimeToTime64(file_time);
+}
+
+#ifdef _DEBUG
+void ComputeStartTime() {
+    SYSTEMTIME start_system_time = kStartSystemTime;
+    time64 start_100ns_time = SystemTimeToTime64(&start_system_time);
+    UTIL_LOG(L1, (_T("posting list starting time = %s\n"),
+                  String_Int64ToString(start_100ns_time, 10)));
+}
+#endif
+
+// Time management
+
+// Allow the unittest to override.
+static time64 time_override = 0;
+
+// #ifdef UNITTEST
+void SetTimeOverride(const time64 & time_new) {
+  time_override = time_new;
+}
+
+// #endif
+
+time64 GetCurrent100NSTime() {
+  if (time_override != 0)
+    return time_override;
+
+  // In order gte the 100ns time we shouldn't use SystemTime
+  // as it's granularity is 1 ms. Below is the correct implementation.
+  // On the other hand the system clock granularity is 15 ms, so we
+  // are not gaining much by having the timestamp in nano-sec
+  // If we decide to go with ms, divide "time64 time" by 10000
+  // SYSTEMTIME sys_time;
+  // GetLocalTime(&sys_time);
+  // return SystemTimeToTime64(&sys_time);
+
+  // get the current time in 100-nanoseconds intervals
+  FILETIME file_time;
+  ::GetSystemTimeAsFileTime(&file_time);
+
+  time64 time = FileTimeToTime64(file_time);
+  return time;
+}
+
+time64 SystemTimeToTime64(const SYSTEMTIME* sys_time) {
+  ASSERT1(sys_time);
+
+  FILETIME file_time;
+  SetZero(file_time);
+
+  if (!::SystemTimeToFileTime(sys_time, &file_time)) {
+    UTIL_LOG(LE,
+             (_T("[SystemTimeToTime64 - failed to SystemTimeToFileTime][0x%x]"),
+              HRESULTFromLastError()));
+    return 0;
+  }
+
+  return FileTimeToTime64(file_time);
+}
+
+// returns a value compatible with EXE/DLL timestamps
+// and the C time() function
+// NOTE: behavior is independent of wMilliseconds value
+int32 SystemTimeToInt32(const SYSTEMTIME *sys_time) {
+  ASSERT(sys_time, (L""));
+
+  time64 t64 = SystemTimeToTime64(sys_time);
+  int32 t32 = 0;
+
+  if (t64 != 0) {
+    t32 = Time64ToInt32(t64);
+  }
+  return t32;
+}
+
+int32 Time64ToInt32(const time64 & time) {
+  // convert to 32-bit format
+  // time() (32-bit) measures seconds since 1970/01/01 00:00:00 (UTC)
+  // FILETIME (64-bit) measures 100-ns intervals since 1601/01/01 00:00:00 (UTC)
+
+  // seconds between 1601 and 1970
+  time64 t32 = (time / kSecsTo100ns) -
+               ((time64(60*60*24) * time64(365*369 + 89)));
+  ASSERT(t32 == (t32 & 0x7FFFFFFF), (L""));  // make sure it fits
+
+  // cast at the end (avoids overflow/underflow when computing 32-bit value)
+  return static_cast<int32>(t32);
+}
+
+time64 Int32ToTime64(const int32 & time) {
+  // convert to 64-bit format
+  // time() (32-bit) measures seconds since 1970/01/01 00:00:00 (UTC)
+  // FILETIME (64-bit) measures 100-ns intervals since 1601/01/01 00:00:00 (UTC)
+
+  // seconds between 1601 and 1970
+  time64 t64 = (static_cast<time64>(time) +
+               (time64(60*60*24) * time64(365*369 + 89))) * kSecsTo100ns;
+  return t64;
+}
+
+// TODO(omaha): The next 2 functions can fail if FileTimeToLocalFileTime or
+// FileTimeToSystemTime fails.
+// Consider having it return a HRESULT. Right now if FileTimeToSystemTime fails,
+// it returns an undefined value.
+
+// Convert a uint to a genuine systemtime
+SYSTEMTIME Time64ToSystemTime(const time64& time) {
+  FILETIME file_time;
+  SetZero(file_time);
+  Time64ToFileTime(time, &file_time);
+
+  SYSTEMTIME sys_time;
+  SetZero(sys_time);
+  if (!FileTimeToSystemTime(&file_time, &sys_time)) {
+    UTIL_LOG(LE, (_T("[Time64ToSystemTime]")
+                  _T("[failed to FileTimeToSystemTime][0x%x]"),
+                  HRESULTFromLastError()));
+  }
+
+  return sys_time;
+}
+
+
+// Convert a uint to a genuine localtime
+// Should ONLY be used for display, since internally we use only UTC
+SYSTEMTIME Time64ToLocalTime(const time64& time) {
+  FILETIME file_time;
+  SetZero(file_time);
+  Time64ToFileTime(time, &file_time);
+
+  FILETIME local_file_time;
+  SetZero(local_file_time);
+  if (!FileTimeToLocalFileTime(&file_time, &local_file_time)) {
+    UTIL_LOG(LE, (_T("[Time64ToLocalTime]")
+                  _T("[failed to FileTimeToLocalFileTime][0x%x]"),
+                  HRESULTFromLastError()));
+  }
+
+  SYSTEMTIME local_time;
+  SetZero(local_time);
+  if (!FileTimeToSystemTime(&local_file_time, &local_time)) {
+    UTIL_LOG(LE, (_T("[Time64ToLocalTime]")
+                  _T("[failed to FileTimeToSystemTime][0x%x]"),
+                  HRESULTFromLastError()));
+  }
+
+  return local_time;
+}
+
+time64 FileTimeToTime64(const FILETIME & file_time) {
+  return static_cast<time64>(
+      file_time.dwHighDateTime) << 32 | file_time.dwLowDateTime;
+}
+
+void Time64ToFileTime(const time64 & time, FILETIME *ft) {
+  ASSERT(ft, (L""));
+
+  ft->dwHighDateTime = static_cast<DWORD>(time >> 32);
+  ft->dwLowDateTime = static_cast<DWORD>(time & 0xffffffff);
+}
+
+// Convert from FILETIME to time_t
+time_t FileTimeToTimeT(const FILETIME& file_time) {
+  return static_cast<time_t>(
+      (FileTimeToTime64(file_time) - kTimeTConvValue) / kSecsTo100ns);
+}
+
+// Convert from time_t to FILETIME
+void TimeTToFileTime(const time_t& time, FILETIME* file_time) {
+  ASSERT1(file_time);
+
+  LONGLONG ll = Int32x32To64(time, kSecsTo100ns) + kTimeTConvValue;
+  file_time->dwLowDateTime = static_cast<DWORD>(ll);
+  file_time->dwHighDateTime = static_cast<DWORD>(ll >> 32);
+}
+
+// Parses RFC 822 Date/Time format
+//    5.  DATE AND TIME SPECIFICATION
+//     5.1.  SYNTAX
+//
+//     date-time   =  [ day "," ] date time        ; dd mm yy
+//                                                 ;  hh:mm:ss zzz
+//     day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"
+//                 /  "Fri"  / "Sat" /  "Sun"
+//
+//     date        =  1*2DIGIT month 2DIGIT        ; day month year
+//                                                 ;  e.g. 20 Jun 82
+//
+//     month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"
+//                 /  "May"  /  "Jun" /  "Jul"  /  "Aug"
+//                 /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
+//
+//     time        =  hour zone                    ; ANSI and Military
+//
+//     hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]
+//                                                 ; 00:00:00 - 23:59:59
+//
+//     zone        =  "UT"  / "GMT"                ; Universal Time
+//                                                 ; North American : UT
+//                 /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4
+//                 /  "CST" / "CDT"                ;  Central:  - 6/ - 5
+//                 /  "MST" / "MDT"                ;  Mountain: - 7/ - 6
+//                 /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7
+//                 /  1ALPHA                       ; Military: Z = UT;
+//                                                 ;  A:-1; (J not used)
+//                                                 ;  M:-12; N:+1; Y:+12
+//                 / ( ("+" / "-") 4DIGIT )        ; Local differential
+//                                                 ;  hours+min. (HHMM)
+// return local time if ret_local_time == true,
+// return time is GMT / UTC time otherwise
+bool RFC822DateToSystemTime(const TCHAR* str_RFC822_date,
+                            SYSTEMTIME* psys_time,
+                            bool ret_local_time) {
+  ASSERT(str_RFC822_date != NULL, (L""));
+  ASSERT(psys_time != NULL, (L""));
+
+  CString str_date = str_RFC822_date;
+  CString str_token;
+  int cur_pos = 0;
+
+  str_token= str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);
+  if (str_token == "")
+    return false;
+
+  int i = 0;
+  for (i = 0; i < kNumOfDays; i++) {
+    if (str_token == kRFC822_Day[i]) {
+      str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);
+      if (str_token == "")
+        return false;
+      break;
+    }
+  }
+
+  int day = String_StringToInt(str_token);
+  if (day < 0 || day > 31)
+    return false;
+
+  str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);
+  if (str_token == "")
+    return false;
+
+  int month = -1;
+  for (i = 0; i < kNumOfMonth; i++) {
+    if (str_token == kRFC822_Month[i]) {
+      month = i+1;  // month is 1 based number
+      break;
+    }
+  }
+  if (month == -1)  // month not found
+    return false;
+
+  str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);
+  if (str_token == "")
+    return false;
+
+  int year = String_StringToInt(str_token);
+  if (year < 100)  // two digit year format, convert to 1950 - 2050 range
+    if (year < 50)
+      year += 2000;
+    else
+      year += 1900;
+
+  str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);
+  if (str_token == "")
+    return false;
+
+  int hour = String_StringToInt(str_token);
+  if (hour < 0 || hour > 23)
+    return false;
+
+  str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);
+  if (str_token == "")
+    return false;
+
+  int minute = String_StringToInt(str_token);
+  if (minute < 0 || minute > 59)
+    return false;
+
+  str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);
+  if (str_token == "")
+    return false;
+
+  int second = 0;
+  // distingushed between XX:XX and XX:XX:XX time formats
+  if (str_token.GetLength() == 2 &&
+      String_IsDigit(str_token[0]) &&
+      String_IsDigit(str_token[1])) {
+    second = String_StringToInt(str_token);
+    if (second < 0 || second > 59)
+      return false;
+
+    str_token = str_date.Tokenize(kRFC822_DateDelimiters, cur_pos);
+    if (str_token == "")
+      return false;
+  }
+
+  int bias = 0;
+  if (str_token[0] == '+' ||
+      str_token[0] == '-' ||
+      String_IsDigit(str_token[0])) {  // numeric format
+    int zone = String_StringToInt(str_token);
+
+    // zone is in HHMM format, need to convert to the number of minutes
+    bias = (zone / 100) * 60 + (zone % 100);
+  } else {  // text format
+    for (i = 0; i < sizeof(kRFC822_TimeZone) / sizeof(TimeZoneInfo); i++)
+      if (str_token == kRFC822_TimeZone[i].zone_name) {
+        bias = kRFC822_TimeZone[i].hour_dif * 60;
+        break;
+      }
+  }
+
+  SYSTEMTIME mail_time;
+  memset(&mail_time, 0, sizeof(mail_time));
+
+  mail_time.wYear   = static_cast<WORD>(year);
+  mail_time.wMonth  = static_cast<WORD>(month);
+  mail_time.wDay    = static_cast<WORD>(day);
+  mail_time.wHour   = static_cast<WORD>(hour);
+  mail_time.wMinute = static_cast<WORD>(minute);
+  mail_time.wSecond = static_cast<WORD>(second);
+
+  // TzSpecificLocalTimeToSystemTime() is incompatible with Win 2000,
+  // convert time manually here
+  time64 time_64 = SystemTimeToTime64(&mail_time);
+  time_64 = time_64 - (bias*kMinsTo100ns);
+
+  *psys_time = Time64ToSystemTime(time_64);
+
+  if (ret_local_time) {
+    TIME_ZONE_INFORMATION local_time_zone_info;
+    SYSTEMTIME universal_time = *psys_time;
+
+    if (GetTimeZoneInformation(&local_time_zone_info) == TIME_ZONE_ID_INVALID) {
+      return false;
+    }
+    if (!SystemTimeToTzSpecificLocalTime(&local_time_zone_info,
+                                    &universal_time,
+                                    psys_time)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace omaha
+
diff --git a/common/time.h b/common/time.h
index 9defc72..7b704da 100644
--- a/common/time.h
+++ b/common/time.h
@@ -1,146 +1,146 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Time functions

-

-#ifndef OMAHA_COMMON_TIME_H__

-#define OMAHA_COMMON_TIME_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "omaha/common/commontypes.h"

-

-namespace omaha {

-

-#define kMicrosecsTo100ns (10ULL)

-#define kMillisecsTo100ns (10000ULL)

-#define kSecsTo100ns (1000 * kMillisecsTo100ns)

-#define kMinsTo100ns (60 * kSecsTo100ns)

-#define kHoursTo100ns (60 * kMinsTo100ns)

-#define kDaysTo100ns (24 * kHoursTo100ns)

-

-// Jan 1 1980 was tuesday (day 2)

-#define kStartSystemTime {1980, 1, 2, 1, 0, 0, 0, 0}

-

-// this is Jan 1 1980 in time64

-#define kStart100NsTime (119600064000000000uI64)

-#define kTimeGranularity (kDaysTo100ns)

-

-// 2^15-1 because we use signed delta times

-#define kTime16Max ((1 << 15) - 1)

-

-// Constant value used in conversion between FILETIME and time_t

-// It is the time difference between January 1, 1601 and January 1, 1970

-#define kTimeTConvValue (116444736000000000)

-

-time64 ConvertTime16ToTime64(uint16 time16);

-uint16 ConvertTime64ToTime16(time64 time);

-

-#ifdef _DEBUG

-void ComputeStartTime();

-#endif

-

-uint64 GetCurrent100NSTime();

-

-// Note - these return 0 if we can't convert the time

-time64 SystemTimeToTime64(const SYSTEMTIME *sys_time);

-

-// Conversions to/from values compatible with

-// EXE/DLL timestamps and the C time() function

-// NOTE: behavior is independent of wMilliseconds value

-int32  SystemTimeToInt32(const SYSTEMTIME *sys_time);

-int32  Time64ToInt32(const time64 & time);

-time64 Int32ToTime64(const int32 & time);

-time64 TimeTToTime64(const time_t& old_value);

-

-// Returns the system time in GMT

-SYSTEMTIME Time64ToSystemTime(const time64 & time);

-

-// Returns the system time in the computer's time zone

-SYSTEMTIME Time64ToLocalTime(const time64 & time);

-

-// Returns the UTC (system) time given the local time

-SYSTEMTIME LocalTimeToSystemTime(const SYSTEMTIME *local_time);

-

-// This returns a standard formatted string that represents

-// the UTC time corresponding to 'ft'.  This is suitable for use

-// in e.g. HTTP headers.

-//

-// @note IMPORTANT!  This does not return a localized string - it's

-// always in English.  The string returned is intended for use in

-// machine-readable contexts, i.e. HTTP headers and thus should not

-// be localized.

-CString ConvertTimeToGMTString(const FILETIME *ft);

-

-// Convert to and from FileTime

-time64 FileTimeToTime64(const FILETIME & file_time);

-void Time64ToFileTime(const time64 & time, FILETIME *ft);

-

-void SetTimeOverride(const time64 & time_new);

-

-// Convert from FILETIME to time_t

-time_t FileTimeToTimeT(const FILETIME& file_time);

-

-// Convert from time_t to FILETIME

-void TimeTToFileTime(const time_t& time, FILETIME* file_time);

-

-// Parses RFC 822 Date/Time format

-//    5.  DATE AND TIME SPECIFICATION

-//     5.1.  SYNTAX

-//

-//     date-time   =  [ day "," ] date time        ; dd mm yy

-//                                                 ;  hh:mm:ss zzz

-//     day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"

-//                 /  "Fri"  / "Sat" /  "Sun"

-//

-//     date        =  1*2DIGIT month 2DIGIT        ; day month year

-//                                                 ;  e.g. 20 Jun 82

-//

-//     month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"

-//                 /  "May"  /  "Jun" /  "Jul"  /  "Aug"

-//                 /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"

-//

-//     time        =  hour zone                    ; ANSI and Military

-//

-//     hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]

-//                                                 ; 00:00:00 - 23:59:59

-//

-//     zone        =  "UT"  / "GMT"                ; Universal Time

-//                                                 ; North American : UT

-//                 /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4

-//                 /  "CST" / "CDT"                ;  Central:  - 6/ - 5

-//                 /  "MST" / "MDT"                ;  Mountain: - 7/ - 6

-//                 /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7

-//                 /  1ALPHA                       ; Military: Z = UT;

-//                                                 ;  A:-1; (J not used)

-//                                                 ;  M:-12; N:+1; Y:+12

-//                 / ( ("+" / "-") 4DIGIT )        ; Local differential

-//                                                 ;  hours+min. (HHMM)

-// return local time if ret_local_time == true,

-// return time is GMT / UTC time otherwise

-bool RFC822DateToSystemTime(const TCHAR* str_RFC822_date,

-                            SYSTEMTIME* psys_time,

-                            bool ret_local_time);

-

-// TODO(omaha): overlap in functionality with FileTimeToTime64. Consider

-// removing this one.

-inline int64 FileTimeToInt64(const FILETIME& filetime) {

-  LARGE_INTEGER large_int = {filetime.dwLowDateTime, filetime.dwHighDateTime};

-  return large_int.QuadPart;

-}

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_TIME_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Time functions
+
+#ifndef OMAHA_COMMON_TIME_H__
+#define OMAHA_COMMON_TIME_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "omaha/common/commontypes.h"
+
+namespace omaha {
+
+#define kMicrosecsTo100ns (10ULL)
+#define kMillisecsTo100ns (10000ULL)
+#define kSecsTo100ns (1000 * kMillisecsTo100ns)
+#define kMinsTo100ns (60 * kSecsTo100ns)
+#define kHoursTo100ns (60 * kMinsTo100ns)
+#define kDaysTo100ns (24 * kHoursTo100ns)
+
+// Jan 1 1980 was tuesday (day 2)
+#define kStartSystemTime {1980, 1, 2, 1, 0, 0, 0, 0}
+
+// this is Jan 1 1980 in time64
+#define kStart100NsTime (119600064000000000uI64)
+#define kTimeGranularity (kDaysTo100ns)
+
+// 2^15-1 because we use signed delta times
+#define kTime16Max ((1 << 15) - 1)
+
+// Constant value used in conversion between FILETIME and time_t
+// It is the time difference between January 1, 1601 and January 1, 1970
+#define kTimeTConvValue (116444736000000000)
+
+time64 ConvertTime16ToTime64(uint16 time16);
+uint16 ConvertTime64ToTime16(time64 time);
+
+#ifdef _DEBUG
+void ComputeStartTime();
+#endif
+
+uint64 GetCurrent100NSTime();
+
+// Note - these return 0 if we can't convert the time
+time64 SystemTimeToTime64(const SYSTEMTIME *sys_time);
+
+// Conversions to/from values compatible with
+// EXE/DLL timestamps and the C time() function
+// NOTE: behavior is independent of wMilliseconds value
+int32  SystemTimeToInt32(const SYSTEMTIME *sys_time);
+int32  Time64ToInt32(const time64 & time);
+time64 Int32ToTime64(const int32 & time);
+time64 TimeTToTime64(const time_t& old_value);
+
+// Returns the system time in GMT
+SYSTEMTIME Time64ToSystemTime(const time64 & time);
+
+// Returns the system time in the computer's time zone
+SYSTEMTIME Time64ToLocalTime(const time64 & time);
+
+// Returns the UTC (system) time given the local time
+SYSTEMTIME LocalTimeToSystemTime(const SYSTEMTIME *local_time);
+
+// This returns a standard formatted string that represents
+// the UTC time corresponding to 'ft'.  This is suitable for use
+// in e.g. HTTP headers.
+//
+// @note IMPORTANT!  This does not return a localized string - it's
+// always in English.  The string returned is intended for use in
+// machine-readable contexts, i.e. HTTP headers and thus should not
+// be localized.
+CString ConvertTimeToGMTString(const FILETIME *ft);
+
+// Convert to and from FileTime
+time64 FileTimeToTime64(const FILETIME & file_time);
+void Time64ToFileTime(const time64 & time, FILETIME *ft);
+
+void SetTimeOverride(const time64 & time_new);
+
+// Convert from FILETIME to time_t
+time_t FileTimeToTimeT(const FILETIME& file_time);
+
+// Convert from time_t to FILETIME
+void TimeTToFileTime(const time_t& time, FILETIME* file_time);
+
+// Parses RFC 822 Date/Time format
+//    5.  DATE AND TIME SPECIFICATION
+//     5.1.  SYNTAX
+//
+//     date-time   =  [ day "," ] date time        ; dd mm yy
+//                                                 ;  hh:mm:ss zzz
+//     day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"
+//                 /  "Fri"  / "Sat" /  "Sun"
+//
+//     date        =  1*2DIGIT month 2DIGIT        ; day month year
+//                                                 ;  e.g. 20 Jun 82
+//
+//     month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"
+//                 /  "May"  /  "Jun" /  "Jul"  /  "Aug"
+//                 /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
+//
+//     time        =  hour zone                    ; ANSI and Military
+//
+//     hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]
+//                                                 ; 00:00:00 - 23:59:59
+//
+//     zone        =  "UT"  / "GMT"                ; Universal Time
+//                                                 ; North American : UT
+//                 /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4
+//                 /  "CST" / "CDT"                ;  Central:  - 6/ - 5
+//                 /  "MST" / "MDT"                ;  Mountain: - 7/ - 6
+//                 /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7
+//                 /  1ALPHA                       ; Military: Z = UT;
+//                                                 ;  A:-1; (J not used)
+//                                                 ;  M:-12; N:+1; Y:+12
+//                 / ( ("+" / "-") 4DIGIT )        ; Local differential
+//                                                 ;  hours+min. (HHMM)
+// return local time if ret_local_time == true,
+// return time is GMT / UTC time otherwise
+bool RFC822DateToSystemTime(const TCHAR* str_RFC822_date,
+                            SYSTEMTIME* psys_time,
+                            bool ret_local_time);
+
+// TODO(omaha): overlap in functionality with FileTimeToTime64. Consider
+// removing this one.
+inline int64 FileTimeToInt64(const FILETIME& filetime) {
+  LARGE_INTEGER large_int = {filetime.dwLowDateTime, filetime.dwHighDateTime};
+  return large_int.QuadPart;
+}
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_TIME_H__
diff --git a/common/time_unittest.cc b/common/time_unittest.cc
index ab0bf2d..04318b6 100644
--- a/common/time_unittest.cc
+++ b/common/time_unittest.cc
@@ -1,189 +1,189 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Time unittest

-

-#include <atltime.h>

-

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Test generation of int32 time values (which uses Time64ToInt32 internally).

-TEST(TimeTest, SystemTimeToInt32NearEpoch) {

-  // Try a simple value near the start of int32 time.

-  SYSTEMTIME system_time = {1970,  // year

-                            1,     // month (1 == January)

-                            0,     // day of week (0 == Sunday)

-                            2,     // day of month

-                            0,     // hour

-                            0,     // minute

-                            0,     // second

-                            0};    // msec

-  system_time.wMilliseconds = 0;

-  int32 time1 = SystemTimeToInt32(&system_time);

-  system_time.wMilliseconds = 999;

-  int32 time2 = SystemTimeToInt32(&system_time);

-

-  // Make sure result is independent of milliseconds value.

-  ASSERT_EQ(time1, time2);

-

-  // 00:00:00 on 1970/01/02 should return the number of seconds in 1 day.

-  ASSERT_EQ(time1, (60*60*24));

-}

-

-// Test an empirical value taken from running dumpbin.exe on a DLL.

-// (IMPORTANT: ran this *after* setting machine's time zone to GMT,

-//  without daylight savings).

-// 40AEE7AA time date stamp Sat May 22 05:39:54 2004

-TEST(TimeTest, SystemTimeToInt32) {

-  SYSTEMTIME system_time = {2004, 5, 6, 22, 5, 39, 54, 0};

-  int32 time = SystemTimeToInt32(&system_time);

-  ASSERT_EQ(time, 0x40AEE7AA);

-}

-

-// Test conversion between int32 and time64 values.

-// By testing SystemTimeToInt32 above, we've already checked Time64ToInt32

-// against empirical values, so it's okay to simply test back-and-forth

-// conversion here.

-TEST(TimeTest, Conversion) {

-  // Simple checks when starting with int32 values, because time64 has more

-  // precision.

-  ASSERT_EQ(Time64ToInt32(Int32ToTime64(0x12345678)), 0x12345678);

-  ASSERT_EQ(Time64ToInt32(Int32ToTime64(INT_MAX)), INT_MAX);

-  ASSERT_EQ(Time64ToInt32(Int32ToTime64(0)), 0);

-

-  // Extra conversions when going opposite direction because int32 has less

-  // precision.

-  ASSERT_EQ(Int32ToTime64(Time64ToInt32(Int32ToTime64(0x12345678))),

-            Int32ToTime64(0x12345678));

-  ASSERT_EQ(Int32ToTime64(Time64ToInt32(Int32ToTime64(INT_MAX))),

-            Int32ToTime64(INT_MAX));

-  ASSERT_EQ(Int32ToTime64(Time64ToInt32(Int32ToTime64(0))),

-            Int32ToTime64(0));

-}

-

-void TimeToStringTest(FILETIME *ft, bool daylight_savings_time) {

-  CTime t(*ft, daylight_savings_time);

-  CString date1(t.FormatGmt(_T("%a, %d %b %Y %H:%M:%S GMT")));

-  CString date2(ConvertTimeToGMTString(ft));

-

-  ASSERT_STREQ(date1, date2);

-}

-

-TEST(TimeTest, TimeToStringTest) {

-  bool daylight_savings_time = false;

-  TIME_ZONE_INFORMATION tz;

-  if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_DAYLIGHT) {

-    daylight_savings_time = true;

-  }

-

-  FILETIME file_time;

-  ::GetSystemTimeAsFileTime(&file_time);

-  TimeToStringTest(&file_time, daylight_savings_time);

-

-  uint64 t = FileTimeToTime64(file_time);

-

-  // months

-  for (int i = 0; i < 13; i++) {

-    t += (24 * kHoursTo100ns) * 28;

-    Time64ToFileTime(t, &file_time);

-    TimeToStringTest(&file_time, daylight_savings_time);

-  }

-

-  // days

-  for (int i = 0; i < 30; i++) {

-    t += (24 * kHoursTo100ns);

-    Time64ToFileTime(t, &file_time);

-    TimeToStringTest(&file_time, daylight_savings_time);

-  }

-

-  // hours

-  for (int i = 0; i < 24; i++) {

-    t += (24 * kHoursTo100ns);

-    Time64ToFileTime(t, &file_time);

-    TimeToStringTest(&file_time, daylight_savings_time);

-  }

-}

-

-TEST(TimeTest, RFC822TimeParsing) {

-  SYSTEMTIME time = {0};

-  ASSERT_TRUE(RFC822DateToSystemTime(_T("Mon, 16 May 2005 15:44:18 -0700"),

-                                     &time,

-                                     false));

-  ASSERT_EQ(time.wYear , 2005);

-  ASSERT_EQ(time.wMonth , 5);

-  ASSERT_EQ(time.wDay , 16);

-  ASSERT_EQ(time.wHour , 22);

-  ASSERT_EQ(time.wMinute , 44);

-  ASSERT_EQ(time.wSecond , 18);

-

-  ASSERT_TRUE(RFC822DateToSystemTime(_T("Mon, 16 May 2005 15:44:18 -0700"),

-                                     &time,

-                                     true));

-  ASSERT_EQ(time.wYear , 2005);

-  ASSERT_EQ(time.wMonth , 5);

-  ASSERT_EQ(time.wDay , 16);

-  ASSERT_TRUE(time.wHour == 15 || time.wHour == 14);  // daylight saving time

-  ASSERT_EQ(time.wMinute , 44);

-  ASSERT_EQ(time.wSecond , 18);

-

-  ASSERT_TRUE(RFC822DateToSystemTime(_T("Tue, 17 May 2005 02:56:18 +0400"),

-                                     &time,

-                                     false));

-  ASSERT_EQ(time.wYear , 2005);

-  ASSERT_EQ(time.wMonth , 5);

-  ASSERT_EQ(time.wDay , 16);

-  ASSERT_EQ(time.wHour , 22);

-  ASSERT_EQ(time.wMinute , 56);

-  ASSERT_EQ(time.wSecond , 18);

-

-  ASSERT_TRUE(RFC822DateToSystemTime(_T("Tue, 17 May 2005 02:56:18 +0400"),

-                                     &time,

-                                     true));

-  ASSERT_EQ(time.wYear , 2005);

-  ASSERT_EQ(time.wMonth , 5);

-  ASSERT_EQ(time.wDay , 16);

-  ASSERT_TRUE(time.wHour == 15 || time.wHour == 14);  // daylight saving time

-  ASSERT_EQ(time.wMinute , 56);

-  ASSERT_EQ(time.wSecond , 18);

-}

-

-TEST(TimeTest, FileTimeToInt64) {

-  {

-  FILETIME file_time = {0};

-  EXPECT_EQ(0, FileTimeToInt64(file_time));

-  }

-

-  {

-  FILETIME file_time = {LONG_MAX, 0};

-  EXPECT_EQ(LONG_MAX, FileTimeToInt64(file_time));

-  }

-

-  {

-  FILETIME file_time = {ULONG_MAX, 0};

-  EXPECT_EQ(ULONG_MAX, FileTimeToInt64(file_time));

-  }

-

-  {

-  FILETIME file_time = {ULONG_MAX, ULONG_MAX};

-  EXPECT_EQ(kuint64max, FileTimeToInt64(file_time));

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Time unittest
+
+#include <atltime.h>
+
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Test generation of int32 time values (which uses Time64ToInt32 internally).
+TEST(TimeTest, SystemTimeToInt32NearEpoch) {
+  // Try a simple value near the start of int32 time.
+  SYSTEMTIME system_time = {1970,  // year
+                            1,     // month (1 == January)
+                            0,     // day of week (0 == Sunday)
+                            2,     // day of month
+                            0,     // hour
+                            0,     // minute
+                            0,     // second
+                            0};    // msec
+  system_time.wMilliseconds = 0;
+  int32 time1 = SystemTimeToInt32(&system_time);
+  system_time.wMilliseconds = 999;
+  int32 time2 = SystemTimeToInt32(&system_time);
+
+  // Make sure result is independent of milliseconds value.
+  ASSERT_EQ(time1, time2);
+
+  // 00:00:00 on 1970/01/02 should return the number of seconds in 1 day.
+  ASSERT_EQ(time1, (60*60*24));
+}
+
+// Test an empirical value taken from running dumpbin.exe on a DLL.
+// (IMPORTANT: ran this *after* setting machine's time zone to GMT,
+//  without daylight savings).
+// 40AEE7AA time date stamp Sat May 22 05:39:54 2004
+TEST(TimeTest, SystemTimeToInt32) {
+  SYSTEMTIME system_time = {2004, 5, 6, 22, 5, 39, 54, 0};
+  int32 time = SystemTimeToInt32(&system_time);
+  ASSERT_EQ(time, 0x40AEE7AA);
+}
+
+// Test conversion between int32 and time64 values.
+// By testing SystemTimeToInt32 above, we've already checked Time64ToInt32
+// against empirical values, so it's okay to simply test back-and-forth
+// conversion here.
+TEST(TimeTest, Conversion) {
+  // Simple checks when starting with int32 values, because time64 has more
+  // precision.
+  ASSERT_EQ(Time64ToInt32(Int32ToTime64(0x12345678)), 0x12345678);
+  ASSERT_EQ(Time64ToInt32(Int32ToTime64(INT_MAX)), INT_MAX);
+  ASSERT_EQ(Time64ToInt32(Int32ToTime64(0)), 0);
+
+  // Extra conversions when going opposite direction because int32 has less
+  // precision.
+  ASSERT_EQ(Int32ToTime64(Time64ToInt32(Int32ToTime64(0x12345678))),
+            Int32ToTime64(0x12345678));
+  ASSERT_EQ(Int32ToTime64(Time64ToInt32(Int32ToTime64(INT_MAX))),
+            Int32ToTime64(INT_MAX));
+  ASSERT_EQ(Int32ToTime64(Time64ToInt32(Int32ToTime64(0))),
+            Int32ToTime64(0));
+}
+
+void TimeToStringTest(FILETIME *ft, bool daylight_savings_time) {
+  CTime t(*ft, daylight_savings_time);
+  CString date1(t.FormatGmt(_T("%a, %d %b %Y %H:%M:%S GMT")));
+  CString date2(ConvertTimeToGMTString(ft));
+
+  ASSERT_STREQ(date1, date2);
+}
+
+TEST(TimeTest, TimeToStringTest) {
+  bool daylight_savings_time = false;
+  TIME_ZONE_INFORMATION tz;
+  if (GetTimeZoneInformation(&tz) == TIME_ZONE_ID_DAYLIGHT) {
+    daylight_savings_time = true;
+  }
+
+  FILETIME file_time;
+  ::GetSystemTimeAsFileTime(&file_time);
+  TimeToStringTest(&file_time, daylight_savings_time);
+
+  uint64 t = FileTimeToTime64(file_time);
+
+  // months
+  for (int i = 0; i < 13; i++) {
+    t += (24 * kHoursTo100ns) * 28;
+    Time64ToFileTime(t, &file_time);
+    TimeToStringTest(&file_time, daylight_savings_time);
+  }
+
+  // days
+  for (int i = 0; i < 30; i++) {
+    t += (24 * kHoursTo100ns);
+    Time64ToFileTime(t, &file_time);
+    TimeToStringTest(&file_time, daylight_savings_time);
+  }
+
+  // hours
+  for (int i = 0; i < 24; i++) {
+    t += (24 * kHoursTo100ns);
+    Time64ToFileTime(t, &file_time);
+    TimeToStringTest(&file_time, daylight_savings_time);
+  }
+}
+
+TEST(TimeTest, RFC822TimeParsing) {
+  SYSTEMTIME time = {0};
+  ASSERT_TRUE(RFC822DateToSystemTime(_T("Mon, 16 May 2005 15:44:18 -0700"),
+                                     &time,
+                                     false));
+  ASSERT_EQ(time.wYear , 2005);
+  ASSERT_EQ(time.wMonth , 5);
+  ASSERT_EQ(time.wDay , 16);
+  ASSERT_EQ(time.wHour , 22);
+  ASSERT_EQ(time.wMinute , 44);
+  ASSERT_EQ(time.wSecond , 18);
+
+  ASSERT_TRUE(RFC822DateToSystemTime(_T("Mon, 16 May 2005 15:44:18 -0700"),
+                                     &time,
+                                     true));
+  ASSERT_EQ(time.wYear , 2005);
+  ASSERT_EQ(time.wMonth , 5);
+  ASSERT_EQ(time.wDay , 16);
+  ASSERT_TRUE(time.wHour == 15 || time.wHour == 14);  // daylight saving time
+  ASSERT_EQ(time.wMinute , 44);
+  ASSERT_EQ(time.wSecond , 18);
+
+  ASSERT_TRUE(RFC822DateToSystemTime(_T("Tue, 17 May 2005 02:56:18 +0400"),
+                                     &time,
+                                     false));
+  ASSERT_EQ(time.wYear , 2005);
+  ASSERT_EQ(time.wMonth , 5);
+  ASSERT_EQ(time.wDay , 16);
+  ASSERT_EQ(time.wHour , 22);
+  ASSERT_EQ(time.wMinute , 56);
+  ASSERT_EQ(time.wSecond , 18);
+
+  ASSERT_TRUE(RFC822DateToSystemTime(_T("Tue, 17 May 2005 02:56:18 +0400"),
+                                     &time,
+                                     true));
+  ASSERT_EQ(time.wYear , 2005);
+  ASSERT_EQ(time.wMonth , 5);
+  ASSERT_EQ(time.wDay , 16);
+  ASSERT_TRUE(time.wHour == 15 || time.wHour == 14);  // daylight saving time
+  ASSERT_EQ(time.wMinute , 56);
+  ASSERT_EQ(time.wSecond , 18);
+}
+
+TEST(TimeTest, FileTimeToInt64) {
+  {
+  FILETIME file_time = {0};
+  EXPECT_EQ(0, FileTimeToInt64(file_time));
+  }
+
+  {
+  FILETIME file_time = {LONG_MAX, 0};
+  EXPECT_EQ(LONG_MAX, FileTimeToInt64(file_time));
+  }
+
+  {
+  FILETIME file_time = {ULONG_MAX, 0};
+  EXPECT_EQ(ULONG_MAX, FileTimeToInt64(file_time));
+  }
+
+  {
+  FILETIME file_time = {ULONG_MAX, ULONG_MAX};
+  EXPECT_EQ(kuint64max, FileTimeToInt64(file_time));
+  }
+}
+
+}  // namespace omaha
+
diff --git a/common/timer.cc b/common/timer.cc
index 1d6da4b..9f7690d 100644
--- a/common/timer.cc
+++ b/common/timer.cc
@@ -1,214 +1,214 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Timing

-

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/timer.h"

-

-namespace omaha {

-

-// LowResTimer class is implemented on top of ::GetTickCount.

-// ::GetTickCount wraps around every 49.7 days. The code can't handle

-// this condition so there is a small probability that something can go

-// wrong.

-LowResTimer::LowResTimer(bool running)

-    : running_(false), iterations_(0), elapsed_(0), start_(0) {

-  if (running) {

-    Start();

-  }

-}

-

-LowResTimer::~LowResTimer() {

-}

-

-void LowResTimer::Reset() {

-  elapsed_ = 0;

-  running_ = 0;

-  iterations_ = 0;

-}

-

-void LowResTimer::Start() {

-  ASSERT1(!running_);

-

-  start_ = ::GetTickCount();

-  running_ = 1;

-}

-

-uint32 LowResTimer::Stop() {

-  ASSERT1(running_);

-

-  uint32 stop = ::GetTickCount();

-  ASSERT1(stop >= start_);

-  uint32 diff = stop - start_;

-  elapsed_ += diff;

-  iterations_++;

-  running_ = 0;

-  return diff;

-}

-

-uint32 LowResTimer::GetMilliseconds() const {

-  uint32 running_time = 0;

-  if (running_) {

-    uint32 now = ::GetTickCount();

-    ASSERT1(now >= start_);

-    running_time = now - start_;

-  }

-  return elapsed_ + running_time;

-}

-

-// statics

-// get the frequency only once

-SELECTANY time64 Timer::count_freq_ = 0;

-

-Timer::Timer(bool running)

-    : running_(0), iterations_(0), elapsed_(0), start_(0), split_(0) {

-  // initialize only once

-  if (count_freq_ == 0) {

-    count_freq_ = GetRdtscFrequency();

-    if (count_freq_ <= 1) {

-       UTIL_LOG(LEVEL_ERROR,

-          (_T("[Timer::Timer - high-res counter not supported]")));

-       count_freq_ = 1;

-    }

-  }

-  if (running) {

-    Start();

-  }

-}

-

-Timer::~Timer() {

-}

-

-void Timer::Reset() {

-  elapsed_ = 0;

-  running_ = 0;

-  iterations_ = 0;

-}

-

-void Timer::Start() {

-  ASSERT1(!running_);

-

-  start_ = GetRdtscCounter();

-  split_ = start_;

-  running_ = 1;

-}

-

-void Timer::Split(double* split_time_ms, double* total_time_ms) {

-  ASSERT1(running_);

-

-  time64 now = GetRdtscCounter();

-  if (split_time_ms) {

-    *split_time_ms = PerfCountToNanoSeconds(now - split_)/ 1000000;

-  }

-  if (total_time_ms) {

-    *total_time_ms =

-        PerfCountToNanoSeconds(elapsed_ + (now - start_)) / 1000000;

-  }

-  split_ = now;

-}

-

-time64 Timer::Stop() {

-  ASSERT1(running_);

-

-  time64 stop = GetRdtscCounter();

-  time64 diff = stop - start_;

-  elapsed_ += diff;

-  iterations_++;

-  running_ = 0;

-  return diff;

-}

-

-double Timer::GetNanoseconds() const {

-  time64 running_time = 0;

-  if (running_) {

-    time64 now = GetRdtscCounter();

-    running_time = now - start_;

-  }

-  return PerfCountToNanoSeconds(elapsed_ + running_time);

-}

-

-#ifdef _DEBUG

-CString Timer::DebugString() const {

-  CString s;

-  double seconds = GetSeconds();

-  if (iterations_) {

-    s.Format(_T("%s sec %d iterations %s sec/iteration"),

-             String_DoubleToString(seconds, 3), iterations_,

-             String_DoubleToString(seconds/iterations_, 3));

-  } else {

-    s.Format(_T("%s sec"), String_DoubleToString(seconds, 3));

-  }

-  return s;

-}

-#endif

-

-// Computes the frequency (ticks/sec) for the CPU tick-count timer (RDTSC)

-// Don't call this function frequently, because computing the frequency is slow

-// (relatively).

-//

-// TODO(omaha): check return values, and return 0 on failure.

-// But hard to imagine a machine where our program will install/run but this

-// will fail.

-time64 Timer::GetRdtscFrequency() {

-  //

-  // Get elapsed RDTSC and elapsed QPC over same time period

-  //

-

-  // compute length of time period to measure

-  time64 freq_qpc = 0;  // ticks per second

-  QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&freq_qpc));

-

-  // fraction of second to run timers for; tradeoff b/w speed and accuracy;

-  // 1/1000 (1 msec) seems like good tradeoff

-  time64 interval_qpc = freq_qpc / 1000;

-

-  // get timer values over same time period

-  time64 begin_qpc = 0;

-  time64 end_qpc = 0;

-

-  QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&begin_qpc));

-

-  time64 begin_rdtsc = Timer::GetRdtscCounter();

-

-  // spin and protect against infinite loop, if QPC does something wacky

-  int count = 0;

-  const int count_max = 50000;

-  do {

-    QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&end_qpc));

-    ++count;

-  } while ((end_qpc - begin_qpc) < interval_qpc  &&  count < count_max);

-

-  QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&end_qpc));

-  time64 end_rdtsc = Timer::GetRdtscCounter();

-

-  ASSERT1(count < count_max);

-

-  //

-  // Compute RDTSC frequency from QPC frequency

-  //

-

-  time64 diff_qpc = end_qpc - begin_qpc;

-  time64 diff_rdtsc = end_rdtsc - begin_rdtsc;

-

-  time64 freq_rdtsc = freq_qpc * diff_rdtsc / diff_qpc;

-

-  return freq_rdtsc;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Timing
+
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/timer.h"
+
+namespace omaha {
+
+// LowResTimer class is implemented on top of ::GetTickCount.
+// ::GetTickCount wraps around every 49.7 days. The code can't handle
+// this condition so there is a small probability that something can go
+// wrong.
+LowResTimer::LowResTimer(bool running)
+    : running_(false), iterations_(0), elapsed_(0), start_(0) {
+  if (running) {
+    Start();
+  }
+}
+
+LowResTimer::~LowResTimer() {
+}
+
+void LowResTimer::Reset() {
+  elapsed_ = 0;
+  running_ = 0;
+  iterations_ = 0;
+}
+
+void LowResTimer::Start() {
+  ASSERT1(!running_);
+
+  start_ = ::GetTickCount();
+  running_ = 1;
+}
+
+uint32 LowResTimer::Stop() {
+  ASSERT1(running_);
+
+  uint32 stop = ::GetTickCount();
+  ASSERT1(stop >= start_);
+  uint32 diff = stop - start_;
+  elapsed_ += diff;
+  iterations_++;
+  running_ = 0;
+  return diff;
+}
+
+uint32 LowResTimer::GetMilliseconds() const {
+  uint32 running_time = 0;
+  if (running_) {
+    uint32 now = ::GetTickCount();
+    ASSERT1(now >= start_);
+    running_time = now - start_;
+  }
+  return elapsed_ + running_time;
+}
+
+// statics
+// get the frequency only once
+SELECTANY time64 Timer::count_freq_ = 0;
+
+Timer::Timer(bool running)
+    : running_(0), iterations_(0), elapsed_(0), start_(0), split_(0) {
+  // initialize only once
+  if (count_freq_ == 0) {
+    count_freq_ = GetRdtscFrequency();
+    if (count_freq_ <= 1) {
+       UTIL_LOG(LEVEL_ERROR,
+          (_T("[Timer::Timer - high-res counter not supported]")));
+       count_freq_ = 1;
+    }
+  }
+  if (running) {
+    Start();
+  }
+}
+
+Timer::~Timer() {
+}
+
+void Timer::Reset() {
+  elapsed_ = 0;
+  running_ = 0;
+  iterations_ = 0;
+}
+
+void Timer::Start() {
+  ASSERT1(!running_);
+
+  start_ = GetRdtscCounter();
+  split_ = start_;
+  running_ = 1;
+}
+
+void Timer::Split(double* split_time_ms, double* total_time_ms) {
+  ASSERT1(running_);
+
+  time64 now = GetRdtscCounter();
+  if (split_time_ms) {
+    *split_time_ms = PerfCountToNanoSeconds(now - split_)/ 1000000;
+  }
+  if (total_time_ms) {
+    *total_time_ms =
+        PerfCountToNanoSeconds(elapsed_ + (now - start_)) / 1000000;
+  }
+  split_ = now;
+}
+
+time64 Timer::Stop() {
+  ASSERT1(running_);
+
+  time64 stop = GetRdtscCounter();
+  time64 diff = stop - start_;
+  elapsed_ += diff;
+  iterations_++;
+  running_ = 0;
+  return diff;
+}
+
+double Timer::GetNanoseconds() const {
+  time64 running_time = 0;
+  if (running_) {
+    time64 now = GetRdtscCounter();
+    running_time = now - start_;
+  }
+  return PerfCountToNanoSeconds(elapsed_ + running_time);
+}
+
+#ifdef _DEBUG
+CString Timer::DebugString() const {
+  CString s;
+  double seconds = GetSeconds();
+  if (iterations_) {
+    s.Format(_T("%s sec %d iterations %s sec/iteration"),
+             String_DoubleToString(seconds, 3), iterations_,
+             String_DoubleToString(seconds/iterations_, 3));
+  } else {
+    s.Format(_T("%s sec"), String_DoubleToString(seconds, 3));
+  }
+  return s;
+}
+#endif
+
+// Computes the frequency (ticks/sec) for the CPU tick-count timer (RDTSC)
+// Don't call this function frequently, because computing the frequency is slow
+// (relatively).
+//
+// TODO(omaha): check return values, and return 0 on failure.
+// But hard to imagine a machine where our program will install/run but this
+// will fail.
+time64 Timer::GetRdtscFrequency() {
+  //
+  // Get elapsed RDTSC and elapsed QPC over same time period
+  //
+
+  // compute length of time period to measure
+  time64 freq_qpc = 0;  // ticks per second
+  QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&freq_qpc));
+
+  // fraction of second to run timers for; tradeoff b/w speed and accuracy;
+  // 1/1000 (1 msec) seems like good tradeoff
+  time64 interval_qpc = freq_qpc / 1000;
+
+  // get timer values over same time period
+  time64 begin_qpc = 0;
+  time64 end_qpc = 0;
+
+  QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&begin_qpc));
+
+  time64 begin_rdtsc = Timer::GetRdtscCounter();
+
+  // spin and protect against infinite loop, if QPC does something wacky
+  int count = 0;
+  const int count_max = 50000;
+  do {
+    QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&end_qpc));
+    ++count;
+  } while ((end_qpc - begin_qpc) < interval_qpc  &&  count < count_max);
+
+  QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&end_qpc));
+  time64 end_rdtsc = Timer::GetRdtscCounter();
+
+  ASSERT1(count < count_max);
+
+  //
+  // Compute RDTSC frequency from QPC frequency
+  //
+
+  time64 diff_qpc = end_qpc - begin_qpc;
+  time64 diff_rdtsc = end_rdtsc - begin_rdtsc;
+
+  time64 freq_rdtsc = freq_qpc * diff_rdtsc / diff_qpc;
+
+  return freq_rdtsc;
+}
+
+}  // namespace omaha
+
diff --git a/common/timer.h b/common/timer.h
index 60932e0..0ec6bee 100644
--- a/common/timer.h
+++ b/common/timer.h
@@ -1,186 +1,186 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Timing

-

-#ifndef OMAHA_COMMON_TIMER_H__

-#define OMAHA_COMMON_TIMER_H__

-

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-// Low resolution timer which can be used to time loops. The resolution depends

-// on the platform and can be expected to be about 10 ms on Windows 2000 and up.

-class LowResTimer {

- public:

-  explicit LowResTimer(bool running);

-  ~LowResTimer();

-

-  // LowResTimer keeps track of elapsed time, which can consist of multiple

-  // Start()-Stop() intervals.

-  void Start();

-

-  // Returns time between Start and Stop call and increments the time elapsed.

-  uint32 Stop();

-  void Reset();

-

-  // Return time in seconds, milliseconds.

-  double GetSeconds() const;

-  uint32 GetMilliseconds() const;

-

-  // Gets the number of iteration this timer was started/stopped.

-  uint32 GetIterations() const { return iterations_; }

-  bool IsRunning() const { return running_; }

-

- private:

-

-  bool running_;

-  uint32 start_;

-  uint32 elapsed_;

-  uint32 iterations_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(LowResTimer);

-};

-

-inline double LowResTimer::GetSeconds() const {

-  return static_cast<double>(GetMilliseconds()) / 1000;

-}

-

-// WARNING - Timer is implemented on top of RDTSC and

-// QueryPerformanceCounter which have undefined behavior when running

-// on multi-core, speedstep, bugs in HAL, certain chipsets, etc.

-// Do not use the Timer in production code where the execution flow

-// depends on timing. Timer is primarily intended to be used for

-// code profiling and performance measurements.

-class Timer {

- public:

-  explicit Timer(bool running);

-  ~Timer();

-

-  // Timer keeps track of elapsed time, which can consist of multiple

-  // Start()-Stop() intervals.

-  void Start();

-

-  // returns time for last split (elapsed time since Start() or time since

-  // last Split(), whichever came last) as well as total elapsed time.

-  void Split(double* split_time_ms, double* total_time_ms);

-

-  // returns time elapsed (in hi-res perf-counts) between Start and Stop call

-  // and increments the time elapsed_

-  time64 Stop();

-  void Reset();

-

-  // return time in seconds, milliseconds, etc.

-  double GetSeconds() const;

-  double GetMilliseconds() const;

-  double GetMicroseconds() const;

-  double GetNanoseconds() const;

-  time64 Get100Nanoseconds() const;

-

-  // TODO(omaha): Probably should have been a static method, or even

-  // standalone func convert the high-perf counter to nano-seconds

-  double PerfCountToNanoSeconds(time64 perf_count) const;

-

-  // get the number of iteration this timer was started/stopped

-  uint32 GetIterations() const { return iterations_; }

-  bool IsRunning() const { return running_; }

-

-  // useful funcs beyond just the Timer class

-  static time64 GetRdtscCounter();  // return perf-counter value

-  static time64 GetRdtscFrequency();  // return perf-counter frequency

-

-    // outputs total time, number of iterations, and the average time

-#ifdef _DEBUG

-  CString DebugString() const;

-#endif

-

- private:

-

-  bool running_;

-  time64 start_;

-  time64 split_;

-  time64 elapsed_;

-  uint32 iterations_;

-  static time64 count_freq_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Timer);

-};

-

-// lint -e{533}  Function should return a value

-// lint -e{31}   Redefinition of symbol

-__forceinline time64 Timer::GetRdtscCounter() { __asm rdtsc }

-

-inline double Timer::PerfCountToNanoSeconds(time64 perf_count) const {

-  return (static_cast<double>(perf_count) / static_cast<double>(count_freq_)) *

-         static_cast<double>(1000000000.0);

-}

-

-inline double Timer::GetSeconds() const {

-  return GetNanoseconds() / 1000000000;

-}

-

-inline double Timer::GetMilliseconds() const {

-  return GetNanoseconds() / 1000000;

-}

-

-inline double Timer::GetMicroseconds() const {

-  return GetNanoseconds() / 1000;

-}

-

-inline time64 Timer::Get100Nanoseconds() const {

-  return (time64) GetNanoseconds() / 100;

-}

-

-// Helper class which starts the timer in its constructor and stops it

-// in its destructor.  This prevents accidentally leaving the timer running

-// if a function has an early exit.

-//

-// Usage:

-//

-// class A {

-//   Timer timer_;

-//

-//   void foo(){

-//     TimerScope (timer_);

-//   ......

-//   }  // end foo

-//

-// Everything is timed till the end of the function or when it returns

-// from any place.

-

-class TimerScope {

- public:

-  explicit TimerScope(Timer *timer) : timer_(timer) {

-    if (timer_) {

-      timer_->Start();

-    }

-  }

-

-  ~TimerScope() {

-    if (timer_ && timer_->IsRunning()) {

-      timer_->Stop();

-    }

-  }

-

- private:

-  Timer *timer_;

-  DISALLOW_EVIL_CONSTRUCTORS(TimerScope);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_TIMER_H__

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Timing
+
+#ifndef OMAHA_COMMON_TIMER_H__
+#define OMAHA_COMMON_TIMER_H__
+
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+// Low resolution timer which can be used to time loops. The resolution depends
+// on the platform and can be expected to be about 10 ms on Windows 2000 and up.
+class LowResTimer {
+ public:
+  explicit LowResTimer(bool running);
+  ~LowResTimer();
+
+  // LowResTimer keeps track of elapsed time, which can consist of multiple
+  // Start()-Stop() intervals.
+  void Start();
+
+  // Returns time between Start and Stop call and increments the time elapsed.
+  uint32 Stop();
+  void Reset();
+
+  // Return time in seconds, milliseconds.
+  double GetSeconds() const;
+  uint32 GetMilliseconds() const;
+
+  // Gets the number of iteration this timer was started/stopped.
+  uint32 GetIterations() const { return iterations_; }
+  bool IsRunning() const { return running_; }
+
+ private:
+
+  bool running_;
+  uint32 start_;
+  uint32 elapsed_;
+  uint32 iterations_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(LowResTimer);
+};
+
+inline double LowResTimer::GetSeconds() const {
+  return static_cast<double>(GetMilliseconds()) / 1000;
+}
+
+// WARNING - Timer is implemented on top of RDTSC and
+// QueryPerformanceCounter which have undefined behavior when running
+// on multi-core, speedstep, bugs in HAL, certain chipsets, etc.
+// Do not use the Timer in production code where the execution flow
+// depends on timing. Timer is primarily intended to be used for
+// code profiling and performance measurements.
+class Timer {
+ public:
+  explicit Timer(bool running);
+  ~Timer();
+
+  // Timer keeps track of elapsed time, which can consist of multiple
+  // Start()-Stop() intervals.
+  void Start();
+
+  // returns time for last split (elapsed time since Start() or time since
+  // last Split(), whichever came last) as well as total elapsed time.
+  void Split(double* split_time_ms, double* total_time_ms);
+
+  // returns time elapsed (in hi-res perf-counts) between Start and Stop call
+  // and increments the time elapsed_
+  time64 Stop();
+  void Reset();
+
+  // return time in seconds, milliseconds, etc.
+  double GetSeconds() const;
+  double GetMilliseconds() const;
+  double GetMicroseconds() const;
+  double GetNanoseconds() const;
+  time64 Get100Nanoseconds() const;
+
+  // TODO(omaha): Probably should have been a static method, or even
+  // standalone func convert the high-perf counter to nano-seconds
+  double PerfCountToNanoSeconds(time64 perf_count) const;
+
+  // get the number of iteration this timer was started/stopped
+  uint32 GetIterations() const { return iterations_; }
+  bool IsRunning() const { return running_; }
+
+  // useful funcs beyond just the Timer class
+  static time64 GetRdtscCounter();  // return perf-counter value
+  static time64 GetRdtscFrequency();  // return perf-counter frequency
+
+    // outputs total time, number of iterations, and the average time
+#ifdef _DEBUG
+  CString DebugString() const;
+#endif
+
+ private:
+
+  bool running_;
+  time64 start_;
+  time64 split_;
+  time64 elapsed_;
+  uint32 iterations_;
+  static time64 count_freq_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Timer);
+};
+
+// lint -e{533}  Function should return a value
+// lint -e{31}   Redefinition of symbol
+__forceinline time64 Timer::GetRdtscCounter() { __asm rdtsc }
+
+inline double Timer::PerfCountToNanoSeconds(time64 perf_count) const {
+  return (static_cast<double>(perf_count) / static_cast<double>(count_freq_)) *
+         static_cast<double>(1000000000.0);
+}
+
+inline double Timer::GetSeconds() const {
+  return GetNanoseconds() / 1000000000;
+}
+
+inline double Timer::GetMilliseconds() const {
+  return GetNanoseconds() / 1000000;
+}
+
+inline double Timer::GetMicroseconds() const {
+  return GetNanoseconds() / 1000;
+}
+
+inline time64 Timer::Get100Nanoseconds() const {
+  return (time64) GetNanoseconds() / 100;
+}
+
+// Helper class which starts the timer in its constructor and stops it
+// in its destructor.  This prevents accidentally leaving the timer running
+// if a function has an early exit.
+//
+// Usage:
+//
+// class A {
+//   Timer timer_;
+//
+//   void foo(){
+//     TimerScope (timer_);
+//   ......
+//   }  // end foo
+//
+// Everything is timed till the end of the function or when it returns
+// from any place.
+
+class TimerScope {
+ public:
+  explicit TimerScope(Timer *timer) : timer_(timer) {
+    if (timer_) {
+      timer_->Start();
+    }
+  }
+
+  ~TimerScope() {
+    if (timer_ && timer_->IsRunning()) {
+      timer_->Stop();
+    }
+  }
+
+ private:
+  Timer *timer_;
+  DISALLOW_EVIL_CONSTRUCTORS(TimerScope);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_TIMER_H__
+
diff --git a/common/timer_unittest.cc b/common/timer_unittest.cc
index 1179e9d..01905ed 100644
--- a/common/timer_unittest.cc
+++ b/common/timer_unittest.cc
@@ -1,232 +1,232 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Timer unittest

-

-#include <cmath>

-#include "omaha/common/time.h"

-#include "omaha/common/timer.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// The accuracy of the unit test measurements is expected to be within 50 ms.

-// The error varies depending on how the unit test process gets scheduled.

-// The timer test is prone to failing when run by Pulse. Consider diabling the

-// test completely.

-const int kErrorMs = 50;

-

-// The tests that use the Timer class are flaky (see warning in timer.h),

-// and Timer isn't used in production Omaha code, so we leave out everything

-// but the LowResTimer test.

-#if 0

-

-class TimerTest : public testing::Test {

- protected:

-  // Set up a test so that we can measure the same time interval using the

-  // low and high resolution timers. If the difference between them is too

-  // big then we consider that the high resolution time is busted and we

-  // stop running the unit tests.

-  // The high resolution timer may have undefined behavior, see the header

-  // file for more comments.

-  static void SetUpTestCase() {

-    const int kSleepMs = 100;

-    const int kDiffMs = 1;

-    LowResTimer t(false);

-    Timer u(false);

-    t.Start();

-    u.Start();

-    ::Sleep(kSleepMs);

-    busted_ = abs(t.GetMilliseconds()- u.GetMilliseconds()) >= kErrorMs;

-  }

-

-  void PrintError() {

-    // This is going to print "Test Foo is busted but passed."

-    printf("is busted but ");

-  }

-

-  static bool busted_;

-};

-

-bool TimerTest::busted_ = false;

-

-#endif // #if 0

-

-TEST(TimerTest, LowResTimer) {

-  if (omaha::IsBuildSystem()) {

-    return;

-  }

-

-  LowResTimer t(false);

-

-  const int kSleep1 = 100;

-  t.Start();

-  ::Sleep(kSleep1);

-  uint32 elapsedMs = t.Stop();

-

-  // For the first run of the timer the elapsed value must be equal to

-  // the timer interval.

-  EXPECT_EQ(elapsedMs, t.GetMilliseconds());

-

-  // About 100 ms now.

-  EXPECT_NEAR(kSleep1, elapsedMs, kErrorMs);

-

-  // Test the accessors of different time units.

-  EXPECT_DOUBLE_EQ(t.GetSeconds() * 1000, t.GetMilliseconds());

-

-  const int kSleep2 = 10;

-  t.Start();

-  ::Sleep(kSleep2);

-  elapsedMs = t.Stop();

-  EXPECT_NEAR(kSleep2, elapsedMs, kErrorMs);

-

-  // About 110 ms now.

-  EXPECT_NEAR(kSleep1 + kSleep2, t.GetMilliseconds(), 2 * kErrorMs);

-

-  const int kSleep3 = 50;

-  t.Start();

-  ::Sleep(kSleep3);

-  elapsedMs = t.Stop();

-  EXPECT_NEAR(kSleep3, elapsedMs, kErrorMs);

-

-  // About 160 ms now.

-  EXPECT_NEAR(kSleep1 + kSleep2 + kSleep3, t.GetMilliseconds(), 3 * kErrorMs);

-

-  t.Reset();

-  EXPECT_EQ(0, t.GetMilliseconds());

-}

-

-// Tests disabled, see comment at top of file.

-#if 0

-// Test that values from RTDSC change quickly.

-TEST_F(TimerTest, RTDSC) {

-  uint32 last = 0;

-  for (int i = 0; i < 10; ++i) {

-    uint64 counter = Timer::GetRdtscCounter();

-    uint32 a = *(reinterpret_cast<uint32 *>(&counter));

-    ASSERT_NE(a, last);

-    last = a;

-  }

-}

-

-// Compare everything as ms units for uniformity.

-

-TEST_F(TimerTest, Timer) {

-  if (busted_) {

-    PrintError();

-    return;

-  }

-

-  Timer t(false);

-

-  const int kSleep1 = 100;

-  t.Start();

-  ::Sleep(kSleep1);

-  time64 elapsed = t.Stop();

-

-  // For the first run of the timer the elapsed value must be equal to

-  // the timer interval.

-  EXPECT_DOUBLE_EQ(t.PerfCountToNanoSeconds(elapsed) / 1000000,

-                   t.GetNanoseconds() / 1000000);

-

-  // About 100 ms now.

-  EXPECT_NEAR(kSleep1, t.PerfCountToNanoSeconds(elapsed) / 1000000, kErrorMs);

-

-  // Test the accessors of different time units.

-  EXPECT_DOUBLE_EQ(t.GetSeconds() * 1000, t.GetMilliseconds());

-  EXPECT_DOUBLE_EQ(t.GetMilliseconds() * 1000, t.GetMicroseconds());

-  EXPECT_DOUBLE_EQ(t.GetMicroseconds() * 1000, t.GetNanoseconds());

-

-  EXPECT_NEAR(t.Get100Nanoseconds() * 100.0, t.GetNanoseconds(), 100);

-

-  const int kSleep2 = 10;

-  t.Start();

-  ::Sleep(kSleep2);

-  elapsed = t.Stop();

-  EXPECT_NEAR(kSleep2, t.PerfCountToNanoSeconds(elapsed) / 1000000, kErrorMs);

-

-  // About 110 ms now.

-  EXPECT_NEAR(kSleep1 + kSleep2, t.GetMilliseconds(), 2 * kErrorMs);

-

-  const int kSleep3 = 50;

-  t.Start();

-  ::Sleep(kSleep3);

-  elapsed = t.Stop();

-  EXPECT_NEAR(kSleep3, t.PerfCountToNanoSeconds(elapsed) / 1000000, kErrorMs);

-

-  // About 160 ms now.

-  EXPECT_NEAR(kSleep1 + kSleep2 + kSleep3, t.GetMilliseconds(), 3 * kErrorMs);

-

-  t.Reset();

-  EXPECT_DOUBLE_EQ(0, t.GetMilliseconds());

-}

-

-TEST_F(TimerTest, TimerSplit) {

-  if (busted_) {

-    PrintError();

-    return;

-  }

-

-  const int kSleep1 = 50;

-  const int kSleep2 = 125;

-  const int kSleep3 = 25;

-

-  double split1(0), split2(0), split3(0);

-  double elapsed1(0), elapsed2(0);

-

-  Timer t(false);

-  t.Start();

-  ::Sleep(kSleep1);

-  t.Split(&split1, &elapsed1);

-  EXPECT_NEAR(split1, kSleep1, kErrorMs);

-  EXPECT_NEAR(elapsed1, kSleep1, kErrorMs);

-  EXPECT_DOUBLE_EQ(split1, elapsed1);

-

-  ::Sleep(kSleep2);

-  t.Split(&split2, &elapsed2);

-  EXPECT_NEAR(split2, kSleep2, kErrorMs);

-  EXPECT_DOUBLE_EQ(split1 + split2, elapsed2);

-

-  ::Sleep(kSleep3);

-  t.Split(&split3, NULL);

-  t.Stop();

-  EXPECT_NEAR(split3, kSleep3, kErrorMs);

-  EXPECT_NEAR(split1 + split2 + split3, t.GetMilliseconds(), kErrorMs);

-}

-

-// Time QueryPerformanceCounter

-TEST_F(TimerTest, QueryPerformanceCounter) {

-  if (busted_) {

-    PrintError();

-    return;

-  }

-

-  Timer t(false);

-  t.Start();

-

-  const int kIterations = 100;

-  LARGE_INTEGER count = {0};

-  for (int i = 0; i < kIterations; i++) {

-    ASSERT_TRUE(::QueryPerformanceCounter(&count));

-  }

-

-  t.Stop();

-

-  // Expect the call to take anywhere up to 1000 nano seconds.

-  EXPECT_NEAR(t.GetNanoseconds() / kIterations, 500, 500);

-}

-#endif // #if 0

-

-}  // namespace omaha

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Timer unittest
+
+#include <cmath>
+#include "omaha/common/time.h"
+#include "omaha/common/timer.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// The accuracy of the unit test measurements is expected to be within 50 ms.
+// The error varies depending on how the unit test process gets scheduled.
+// The timer test is prone to failing when run by Pulse. Consider diabling the
+// test completely.
+const int kErrorMs = 50;
+
+// The tests that use the Timer class are flaky (see warning in timer.h),
+// and Timer isn't used in production Omaha code, so we leave out everything
+// but the LowResTimer test.
+#if 0
+
+class TimerTest : public testing::Test {
+ protected:
+  // Set up a test so that we can measure the same time interval using the
+  // low and high resolution timers. If the difference between them is too
+  // big then we consider that the high resolution time is busted and we
+  // stop running the unit tests.
+  // The high resolution timer may have undefined behavior, see the header
+  // file for more comments.
+  static void SetUpTestCase() {
+    const int kSleepMs = 100;
+    const int kDiffMs = 1;
+    LowResTimer t(false);
+    Timer u(false);
+    t.Start();
+    u.Start();
+    ::Sleep(kSleepMs);
+    busted_ = abs(t.GetMilliseconds()- u.GetMilliseconds()) >= kErrorMs;
+  }
+
+  void PrintError() {
+    // This is going to print "Test Foo is busted but passed."
+    printf("is busted but ");
+  }
+
+  static bool busted_;
+};
+
+bool TimerTest::busted_ = false;
+
+#endif // #if 0
+
+TEST(TimerTest, LowResTimer) {
+  if (omaha::IsBuildSystem()) {
+    return;
+  }
+
+  LowResTimer t(false);
+
+  const int kSleep1 = 100;
+  t.Start();
+  ::Sleep(kSleep1);
+  uint32 elapsedMs = t.Stop();
+
+  // For the first run of the timer the elapsed value must be equal to
+  // the timer interval.
+  EXPECT_EQ(elapsedMs, t.GetMilliseconds());
+
+  // About 100 ms now.
+  EXPECT_NEAR(kSleep1, elapsedMs, kErrorMs);
+
+  // Test the accessors of different time units.
+  EXPECT_DOUBLE_EQ(t.GetSeconds() * 1000, t.GetMilliseconds());
+
+  const int kSleep2 = 10;
+  t.Start();
+  ::Sleep(kSleep2);
+  elapsedMs = t.Stop();
+  EXPECT_NEAR(kSleep2, elapsedMs, kErrorMs);
+
+  // About 110 ms now.
+  EXPECT_NEAR(kSleep1 + kSleep2, t.GetMilliseconds(), 2 * kErrorMs);
+
+  const int kSleep3 = 50;
+  t.Start();
+  ::Sleep(kSleep3);
+  elapsedMs = t.Stop();
+  EXPECT_NEAR(kSleep3, elapsedMs, kErrorMs);
+
+  // About 160 ms now.
+  EXPECT_NEAR(kSleep1 + kSleep2 + kSleep3, t.GetMilliseconds(), 3 * kErrorMs);
+
+  t.Reset();
+  EXPECT_EQ(0, t.GetMilliseconds());
+}
+
+// Tests disabled, see comment at top of file.
+#if 0
+// Test that values from RTDSC change quickly.
+TEST_F(TimerTest, RTDSC) {
+  uint32 last = 0;
+  for (int i = 0; i < 10; ++i) {
+    uint64 counter = Timer::GetRdtscCounter();
+    uint32 a = *(reinterpret_cast<uint32 *>(&counter));
+    ASSERT_NE(a, last);
+    last = a;
+  }
+}
+
+// Compare everything as ms units for uniformity.
+
+TEST_F(TimerTest, Timer) {
+  if (busted_) {
+    PrintError();
+    return;
+  }
+
+  Timer t(false);
+
+  const int kSleep1 = 100;
+  t.Start();
+  ::Sleep(kSleep1);
+  time64 elapsed = t.Stop();
+
+  // For the first run of the timer the elapsed value must be equal to
+  // the timer interval.
+  EXPECT_DOUBLE_EQ(t.PerfCountToNanoSeconds(elapsed) / 1000000,
+                   t.GetNanoseconds() / 1000000);
+
+  // About 100 ms now.
+  EXPECT_NEAR(kSleep1, t.PerfCountToNanoSeconds(elapsed) / 1000000, kErrorMs);
+
+  // Test the accessors of different time units.
+  EXPECT_DOUBLE_EQ(t.GetSeconds() * 1000, t.GetMilliseconds());
+  EXPECT_DOUBLE_EQ(t.GetMilliseconds() * 1000, t.GetMicroseconds());
+  EXPECT_DOUBLE_EQ(t.GetMicroseconds() * 1000, t.GetNanoseconds());
+
+  EXPECT_NEAR(t.Get100Nanoseconds() * 100.0, t.GetNanoseconds(), 100);
+
+  const int kSleep2 = 10;
+  t.Start();
+  ::Sleep(kSleep2);
+  elapsed = t.Stop();
+  EXPECT_NEAR(kSleep2, t.PerfCountToNanoSeconds(elapsed) / 1000000, kErrorMs);
+
+  // About 110 ms now.
+  EXPECT_NEAR(kSleep1 + kSleep2, t.GetMilliseconds(), 2 * kErrorMs);
+
+  const int kSleep3 = 50;
+  t.Start();
+  ::Sleep(kSleep3);
+  elapsed = t.Stop();
+  EXPECT_NEAR(kSleep3, t.PerfCountToNanoSeconds(elapsed) / 1000000, kErrorMs);
+
+  // About 160 ms now.
+  EXPECT_NEAR(kSleep1 + kSleep2 + kSleep3, t.GetMilliseconds(), 3 * kErrorMs);
+
+  t.Reset();
+  EXPECT_DOUBLE_EQ(0, t.GetMilliseconds());
+}
+
+TEST_F(TimerTest, TimerSplit) {
+  if (busted_) {
+    PrintError();
+    return;
+  }
+
+  const int kSleep1 = 50;
+  const int kSleep2 = 125;
+  const int kSleep3 = 25;
+
+  double split1(0), split2(0), split3(0);
+  double elapsed1(0), elapsed2(0);
+
+  Timer t(false);
+  t.Start();
+  ::Sleep(kSleep1);
+  t.Split(&split1, &elapsed1);
+  EXPECT_NEAR(split1, kSleep1, kErrorMs);
+  EXPECT_NEAR(elapsed1, kSleep1, kErrorMs);
+  EXPECT_DOUBLE_EQ(split1, elapsed1);
+
+  ::Sleep(kSleep2);
+  t.Split(&split2, &elapsed2);
+  EXPECT_NEAR(split2, kSleep2, kErrorMs);
+  EXPECT_DOUBLE_EQ(split1 + split2, elapsed2);
+
+  ::Sleep(kSleep3);
+  t.Split(&split3, NULL);
+  t.Stop();
+  EXPECT_NEAR(split3, kSleep3, kErrorMs);
+  EXPECT_NEAR(split1 + split2 + split3, t.GetMilliseconds(), kErrorMs);
+}
+
+// Time QueryPerformanceCounter
+TEST_F(TimerTest, QueryPerformanceCounter) {
+  if (busted_) {
+    PrintError();
+    return;
+  }
+
+  Timer t(false);
+  t.Start();
+
+  const int kIterations = 100;
+  LARGE_INTEGER count = {0};
+  for (int i = 0; i < kIterations; i++) {
+    ASSERT_TRUE(::QueryPerformanceCounter(&count));
+  }
+
+  t.Stop();
+
+  // Expect the call to take anywhere up to 1000 nano seconds.
+  EXPECT_NEAR(t.GetNanoseconds() / kIterations, 500, 500);
+}
+#endif // #if 0
+
+}  // namespace omaha
diff --git a/common/tr_rand.cc b/common/tr_rand.cc
index db169e4..2a532ad 100644
--- a/common/tr_rand.cc
+++ b/common/tr_rand.cc
@@ -1,39 +1,39 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-//

-// Simple pseudo-random number generator.

-// Not intended for anything but random-to-humans numbers.

-// Very fast, and has a period of 32768 for all seed values (including zero).

-// Returns values in the range 0..0xFFFF (inclusive).

-//

-

-#include "common/tr_rand.h"

-

-namespace omaha {

-

-static int rand_val = 0;

-

-void tr_srand(unsigned int seed) {

-  rand_val = seed & 0xFFFF;

-}

-

-int tr_rand() {

-  rand_val = ((rand_val * 75) + 1) & 0xFFFF;

-  return rand_val;

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+//
+// Simple pseudo-random number generator.
+// Not intended for anything but random-to-humans numbers.
+// Very fast, and has a period of 32768 for all seed values (including zero).
+// Returns values in the range 0..0xFFFF (inclusive).
+//
+
+#include "common/tr_rand.h"
+
+namespace omaha {
+
+static int rand_val = 0;
+
+void tr_srand(unsigned int seed) {
+  rand_val = seed & 0xFFFF;
+}
+
+int tr_rand() {
+  rand_val = ((rand_val * 75) + 1) & 0xFFFF;
+  return rand_val;
+}
+
+}  // namespace omaha
+
diff --git a/common/tr_rand.h b/common/tr_rand.h
index dbb035b..e7469f5 100644
--- a/common/tr_rand.h
+++ b/common/tr_rand.h
@@ -1,35 +1,35 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Simple pseudo-random number generator.

-// Not intended for anything but random-to-humans numbers.

-// Very fast, and has a period of 32768 for all seed values (including zero).

-// Returns values in the range 0..0xFFFF (inclusive).

-//

-

-#ifndef OMAHA_COMMON_TR_RAND_H_

-#define OMAHA_COMMON_TR_RAND_H_

-

-namespace omaha {

-

-#define kMaximumRandomValue 65535

-

-// Same prototypes as CRT srand/rand

-void tr_srand(unsigned int seed);

-int tr_rand();

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_TR_RAND_H_

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Simple pseudo-random number generator.
+// Not intended for anything but random-to-humans numbers.
+// Very fast, and has a period of 32768 for all seed values (including zero).
+// Returns values in the range 0..0xFFFF (inclusive).
+//
+
+#ifndef OMAHA_COMMON_TR_RAND_H_
+#define OMAHA_COMMON_TR_RAND_H_
+
+namespace omaha {
+
+#define kMaximumRandomValue 65535
+
+// Same prototypes as CRT srand/rand
+void tr_srand(unsigned int seed);
+int tr_rand();
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_TR_RAND_H_
diff --git a/common/tr_rand_unittest.cc b/common/tr_rand_unittest.cc
index 70cd281..682d254 100644
--- a/common/tr_rand_unittest.cc
+++ b/common/tr_rand_unittest.cc
@@ -1,66 +1,66 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-

-#include <cstring>

-#include "omaha/common/tr_rand.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(TRRandTest, TRRand) {

-  int min_period = +99999;

-  int max_period = -99999;

-

-  int min_period_at = -99999;

-  int max_period_at = -99999;

-

-  byte hits[65536] = {0};

-  memset(hits, 0, sizeof(hits));

-

-  // Compute minimum and maximum period by considering all possible seed values.

-  for (int seed = 0; seed < 65536; ++seed) {

-    // See if value is part of some known sequence we've traversed.

-    // If multiple values map to same next-val, this check could cause us to

-    // report a min_period that's too short. But a long min_period still

-    // indicates success.

-    if (hits[seed]) { continue; }

-

-    // Compute length of period starting at this seed.

-    tr_srand(seed);

-    int i = seed;

-    int period = 0;

-    do {

-      ++hits[i];

-      ++period;

-      i = tr_rand();

-      ASSERT_GE(i, 0);

-    } while (hits[i] == 0);

-

-    // Update stats.

-    if (period < min_period) {

-      min_period = period;

-      min_period_at = seed;

-    }

-    if (period > max_period) {

-      max_period = period;

-      max_period_at = seed;

-    }

-  }

-  ASSERT_GE(min_period, (0xFFFF / 2));

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+
+#include <cstring>
+#include "omaha/common/tr_rand.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(TRRandTest, TRRand) {
+  int min_period = +99999;
+  int max_period = -99999;
+
+  int min_period_at = -99999;
+  int max_period_at = -99999;
+
+  byte hits[65536] = {0};
+  memset(hits, 0, sizeof(hits));
+
+  // Compute minimum and maximum period by considering all possible seed values.
+  for (int seed = 0; seed < 65536; ++seed) {
+    // See if value is part of some known sequence we've traversed.
+    // If multiple values map to same next-val, this check could cause us to
+    // report a min_period that's too short. But a long min_period still
+    // indicates success.
+    if (hits[seed]) { continue; }
+
+    // Compute length of period starting at this seed.
+    tr_srand(seed);
+    int i = seed;
+    int period = 0;
+    do {
+      ++hits[i];
+      ++period;
+      i = tr_rand();
+      ASSERT_GE(i, 0);
+    } while (hits[i] == 0);
+
+    // Update stats.
+    if (period < min_period) {
+      min_period = period;
+      min_period_at = seed;
+    }
+    if (period > max_period) {
+      max_period = period;
+      max_period_at = seed;
+    }
+  }
+  ASSERT_GE(min_period, (0xFFFF / 2));
+}
+
+}  // namespace omaha
+
diff --git a/common/type_utils.h b/common/type_utils.h
index f05f6d3..edbd286 100644
--- a/common/type_utils.h
+++ b/common/type_utils.h
@@ -1,68 +1,68 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_TYPE_UTILS_H_

-#define OMAHA_COMMON_TYPE_UTILS_H_

-

-namespace omaha {

-

-//

-// Detecting convertibility and inheritence at compile time

-// (Extracted from: Modern C++ Design)

-//

-

-// Evaluates true if U inherites from T publically, or if T and U are same type

-#define SUPERSUBCLASS(T, U) \

-  (ConversionUtil<const U*, const T*>::exists && \

-  !ConversionUtil<const T*, const void*>::same_type)

-

-// Evaluates true only if U inherites from T publically

-#define SUPERSUBCLASS_STRICT(T, U) \

-  (SUPERSUBCLASS(T, U) && \

-  !ConversionUtil<const T, const U>::same_type)

-

-// Perform type test

-template <class T, class U>

-class ConversionUtil {

- private:

-  typedef char Small;

-  class Big {

-    char dummy[2];

-  };

-  static Small Test(U);

-  static Big Test(...);

-  static T MakeT();

-

- public:

-  // Tell whether there is ConversionUtil from T to U

-  enum { exists = sizeof(Test(MakeT())) == sizeof(Small) };

-

-  // Tells whether there are ConversionUtils between T and U in both directions

-  enum { exists_2way = exists && ConversionUtil<U, T>::exists };

-

-  // Tells whether there are same type

-  enum { same_type = false };

-};

-

-// Perform same type test through partial template specialization

-template<class T>

-class ConversionUtil<T, T> {

- public:

-  enum { exists = 1, exists_2way = 1, same_type = 1 };

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_TYPE_UTILS_H_

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_TYPE_UTILS_H_
+#define OMAHA_COMMON_TYPE_UTILS_H_
+
+namespace omaha {
+
+//
+// Detecting convertibility and inheritence at compile time
+// (Extracted from: Modern C++ Design)
+//
+
+// Evaluates true if U inherites from T publically, or if T and U are same type
+#define SUPERSUBCLASS(T, U) \
+  (ConversionUtil<const U*, const T*>::exists && \
+  !ConversionUtil<const T*, const void*>::same_type)
+
+// Evaluates true only if U inherites from T publically
+#define SUPERSUBCLASS_STRICT(T, U) \
+  (SUPERSUBCLASS(T, U) && \
+  !ConversionUtil<const T, const U>::same_type)
+
+// Perform type test
+template <class T, class U>
+class ConversionUtil {
+ private:
+  typedef char Small;
+  class Big {
+    char dummy[2];
+  };
+  static Small Test(U);
+  static Big Test(...);
+  static T MakeT();
+
+ public:
+  // Tell whether there is ConversionUtil from T to U
+  enum { exists = sizeof(Test(MakeT())) == sizeof(Small) };
+
+  // Tells whether there are ConversionUtils between T and U in both directions
+  enum { exists_2way = exists && ConversionUtil<U, T>::exists };
+
+  // Tells whether there are same type
+  enum { same_type = false };
+};
+
+// Perform same type test through partial template specialization
+template<class T>
+class ConversionUtil<T, T> {
+ public:
+  enum { exists = 1, exists_2way = 1, same_type = 1 };
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_TYPE_UTILS_H_
diff --git a/common/unittest_utils.cc b/common/unittest_utils.cc
index 757a9f4..a9927ab 100644
--- a/common/unittest_utils.cc
+++ b/common/unittest_utils.cc
@@ -1,124 +1,124 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// unittest_utils.cpp

-

-#include <windows.h>

-#include "omaha/common/unittest_utils.h"

-#include "omaha/common/string.h"

-#include "omaha/common/tr_rand.h"

-

-namespace omaha {

-

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

-// Unittest utils

-//

-

-int32 UnittestUtils::GetRandomInt32() {

-  int32 x = 0;

-

-  // rand() returns a value between 0x0000 and 0x7fff

-  // that's only 16 bits, so we shift by 16

-  // and since it's 0x7fff, we randomly flip the last bit

-

-  int32 a = tr_rand();

-  if (tr_rand() % 2 == 0) {

-    a = a | 0x8000;

-  }

-

-  int32 b = tr_rand();

-  if (tr_rand() % 2 == 0) {

-    b = b | 0x8000;

-  }

-

-  x = (x | a) << 16;

-  x = x | b;

-

-  return x;

-}

-

-int64 UnittestUtils::GetRandomInt64() {

-  int64 x = 0;

-

-  // rand() returns a value between 0x0000 and 0x7fff

-  // that's only 16 bits, so we shift by 16

-  // and since it's 0x7fff, we randomly flip the last bit

-

-  int32 a = tr_rand();

-  if (tr_rand() % 2 == 0) {

-    a = a | 0x8000;

-  }

-

-  int32 b = tr_rand();

-  if (tr_rand() % 2 == 0) {

-    b = b | 0x8000;

-  }

-

-  int32 c = tr_rand();

-  if (tr_rand() % 2 == 0) {

-    c = c | 0x8000;

-  }

-

-  int32 d = tr_rand();

-  if (tr_rand() % 2 == 0) {

-    d = d | 0x8000;

-  }

-

-  x = (x | a) << 16;

-  x = (x | b) << 16;

-  x = (x | c) << 16;

-  x = x | d;

-

-  return x;

-}

-

-char UnittestUtils::RandomPrintableCharacter() {

-  // +1 is to make it inclusive

-  return kMinASCIIPrintable +

-         (tr_rand() % (kMaxASCIIPrintable - kMinASCIIPrintable + 1));

-}

-

-CString UnittestUtils::CreateRandomString(uint32 length) {

-  CString cstr;

-  if (length > 0) {

-    char* rand_chars = new char[length];

-    if (rand_chars != NULL) {

-      for (uint32 i = 0; i < length; ++i) {

-        rand_chars[i] = RandomPrintableCharacter();

-      }

-

-      WCHAR* rand_wchars = ToWide(rand_chars, length);

-      cstr = rand_wchars;

-

-      delete[] rand_wchars;

-      delete[] rand_chars;

-      return cstr;

-    }

-  }

-  return cstr;

-}

-

-bool UnittestUtils::CreateRandomByteArray(uint32 length, byte out_bytes[]) {

-  if (length > 0) {

-      for (uint32 i = 0; i < length; ++i) {

-        out_bytes[i] = static_cast<byte>(tr_rand() % 256);

-      }

-      return true;

-  }

-  return false;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// unittest_utils.cpp
+
+#include <windows.h>
+#include "omaha/common/unittest_utils.h"
+#include "omaha/common/string.h"
+#include "omaha/common/tr_rand.h"
+
+namespace omaha {
+
+// ---------------------------------------------------
+// Unittest utils
+//
+
+int32 UnittestUtils::GetRandomInt32() {
+  int32 x = 0;
+
+  // rand() returns a value between 0x0000 and 0x7fff
+  // that's only 16 bits, so we shift by 16
+  // and since it's 0x7fff, we randomly flip the last bit
+
+  int32 a = tr_rand();
+  if (tr_rand() % 2 == 0) {
+    a = a | 0x8000;
+  }
+
+  int32 b = tr_rand();
+  if (tr_rand() % 2 == 0) {
+    b = b | 0x8000;
+  }
+
+  x = (x | a) << 16;
+  x = x | b;
+
+  return x;
+}
+
+int64 UnittestUtils::GetRandomInt64() {
+  int64 x = 0;
+
+  // rand() returns a value between 0x0000 and 0x7fff
+  // that's only 16 bits, so we shift by 16
+  // and since it's 0x7fff, we randomly flip the last bit
+
+  int32 a = tr_rand();
+  if (tr_rand() % 2 == 0) {
+    a = a | 0x8000;
+  }
+
+  int32 b = tr_rand();
+  if (tr_rand() % 2 == 0) {
+    b = b | 0x8000;
+  }
+
+  int32 c = tr_rand();
+  if (tr_rand() % 2 == 0) {
+    c = c | 0x8000;
+  }
+
+  int32 d = tr_rand();
+  if (tr_rand() % 2 == 0) {
+    d = d | 0x8000;
+  }
+
+  x = (x | a) << 16;
+  x = (x | b) << 16;
+  x = (x | c) << 16;
+  x = x | d;
+
+  return x;
+}
+
+char UnittestUtils::RandomPrintableCharacter() {
+  // +1 is to make it inclusive
+  return kMinASCIIPrintable +
+         (tr_rand() % (kMaxASCIIPrintable - kMinASCIIPrintable + 1));
+}
+
+CString UnittestUtils::CreateRandomString(uint32 length) {
+  CString cstr;
+  if (length > 0) {
+    char* rand_chars = new char[length];
+    if (rand_chars != NULL) {
+      for (uint32 i = 0; i < length; ++i) {
+        rand_chars[i] = RandomPrintableCharacter();
+      }
+
+      WCHAR* rand_wchars = ToWide(rand_chars, length);
+      cstr = rand_wchars;
+
+      delete[] rand_wchars;
+      delete[] rand_chars;
+      return cstr;
+    }
+  }
+  return cstr;
+}
+
+bool UnittestUtils::CreateRandomByteArray(uint32 length, byte out_bytes[]) {
+  if (length > 0) {
+      for (uint32 i = 0; i < length; ++i) {
+        out_bytes[i] = static_cast<byte>(tr_rand() % 256);
+      }
+      return true;
+  }
+  return false;
+}
+
+}  // namespace omaha
+
diff --git a/common/unittest_utils.h b/common/unittest_utils.h
index 9c65cbc..a7fc15c 100644
--- a/common/unittest_utils.h
+++ b/common/unittest_utils.h
@@ -1,62 +1,62 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// unittest_utils.h

-

-#ifndef OMAHA_COMMON_UNITTEST_UTILS_H__

-#define OMAHA_COMMON_UNITTEST_UTILS_H__

-

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-#define kMinASCIIPrintable  32

-#define kMaxASCIIPrintable  126

-

-// Overriden class that does work in unittests.

-class UnittestUtils {

- public:

-  // returns a random signed 32-bit integer

-  // not particularly fast, done by using rand() and shifting

-  static int32 GetRandomInt32();

-

-  // returns a random signed 64-bit integer

-  // not particularly fast, done by using rand() and shifting

-  static int64 GetRandomInt64();

-

-  // returns a random printable ASCII character

-  // characters range from kMinASCIIPrintable (32 = spacebar) to

-  // kMaxASCIIPrintable (126 = ~)

-  // see: http://www.asciitable.com

-  static char RandomPrintableCharacter();

-

-  // creates a string of random characters using RandomPrintableCharacter()

-  // characters are then converted to wide strings

-  // returns L"" if length = 0

-  static CString CreateRandomString(uint32 length);

-

-  // assumes out_bytes[] has length length

-  // fills out_bytes[] with random bytes

-  // returns NULL if length = 0

-  static bool CreateRandomByteArray(uint32 length, byte out_bytes[]);

-

- private:

-  DISALLOW_IMPLICIT_CONSTRUCTORS(UnittestUtils);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_UNITTEST_UTILS_H__

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// unittest_utils.h
+
+#ifndef OMAHA_COMMON_UNITTEST_UTILS_H__
+#define OMAHA_COMMON_UNITTEST_UTILS_H__
+
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+#define kMinASCIIPrintable  32
+#define kMaxASCIIPrintable  126
+
+// Overriden class that does work in unittests.
+class UnittestUtils {
+ public:
+  // returns a random signed 32-bit integer
+  // not particularly fast, done by using rand() and shifting
+  static int32 GetRandomInt32();
+
+  // returns a random signed 64-bit integer
+  // not particularly fast, done by using rand() and shifting
+  static int64 GetRandomInt64();
+
+  // returns a random printable ASCII character
+  // characters range from kMinASCIIPrintable (32 = spacebar) to
+  // kMaxASCIIPrintable (126 = ~)
+  // see: http://www.asciitable.com
+  static char RandomPrintableCharacter();
+
+  // creates a string of random characters using RandomPrintableCharacter()
+  // characters are then converted to wide strings
+  // returns L"" if length = 0
+  static CString CreateRandomString(uint32 length);
+
+  // assumes out_bytes[] has length length
+  // fills out_bytes[] with random bytes
+  // returns NULL if length = 0
+  static bool CreateRandomByteArray(uint32 length, byte out_bytes[]);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(UnittestUtils);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_UNITTEST_UTILS_H__
diff --git a/common/user_info.cc b/common/user_info.cc
index 59bc378..486ef27 100644
--- a/common/user_info.cc
+++ b/common/user_info.cc
@@ -1,87 +1,87 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/user_info.h"

-

-#include <windows.h>

-#include <security.h>

-#include <secext.h>

-#include <sddl.h>

-#include <lmcons.h>

-#include <atlsecurity.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/scoped_any.h"

-

-namespace omaha {

-

-namespace user_info {

-

-HRESULT GetCurrentUser(CString* name, CString* domain, CString* sid) {

-  CAccessToken token;

-  CSid current_sid;

-  if (!token.GetProcessToken(TOKEN_QUERY) || !token.GetUser(&current_sid)) {

-    HRESULT hr = HRESULTFromLastError();

-    ASSERT(false, (_T("[Failed to get current user sid[0x%x]"), hr));

-    return hr;

-  }

-

-  if (sid != NULL) {

-    *sid = current_sid.Sid();

-  }

-  if (name != NULL) {

-    *name = current_sid.AccountName();

-  }

-  if (domain != NULL) {

-    *domain = current_sid.Domain();

-  }

-  return S_OK;

-}

-

-HRESULT IsLocalSystemUser(bool* is_local_system, CString* user_sid) {

-  ASSERT1(is_local_system);

-

-  CString sid;

-  HRESULT hr = GetCurrentUser(NULL, NULL, &sid);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  *is_local_system = sid.CompareNoCase(kLocalSystemSid) == 0;

-  if (user_sid) {

-    user_sid->SetString(sid);

-  }

-  return S_OK;

-}

-

-HRESULT GetCurrentThreadUser(CString* sid) {

-  ASSERT1(sid);

-  CAccessToken access_token;

-  CSid user_sid;

-  if (access_token.GetThreadToken(TOKEN_READ) &&

-      access_token.GetUser(&user_sid)) {

-    sid->SetString(user_sid.Sid());

-    return S_OK;

-  } else {

-    return HRESULTFromLastError();

-  }

-}

-

-}  // namespace user_info

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/user_info.h"
+
+#include <windows.h>
+#include <security.h>
+#include <secext.h>
+#include <sddl.h>
+#include <lmcons.h>
+#include <atlsecurity.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/scoped_any.h"
+
+namespace omaha {
+
+namespace user_info {
+
+HRESULT GetCurrentUser(CString* name, CString* domain, CString* sid) {
+  CAccessToken token;
+  CSid current_sid;
+  if (!token.GetProcessToken(TOKEN_QUERY) || !token.GetUser(&current_sid)) {
+    HRESULT hr = HRESULTFromLastError();
+    ASSERT(false, (_T("[Failed to get current user sid[0x%x]"), hr));
+    return hr;
+  }
+
+  if (sid != NULL) {
+    *sid = current_sid.Sid();
+  }
+  if (name != NULL) {
+    *name = current_sid.AccountName();
+  }
+  if (domain != NULL) {
+    *domain = current_sid.Domain();
+  }
+  return S_OK;
+}
+
+HRESULT IsLocalSystemUser(bool* is_local_system, CString* user_sid) {
+  ASSERT1(is_local_system);
+
+  CString sid;
+  HRESULT hr = GetCurrentUser(NULL, NULL, &sid);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  *is_local_system = sid.CompareNoCase(kLocalSystemSid) == 0;
+  if (user_sid) {
+    user_sid->SetString(sid);
+  }
+  return S_OK;
+}
+
+HRESULT GetCurrentThreadUser(CString* sid) {
+  ASSERT1(sid);
+  CAccessToken access_token;
+  CSid user_sid;
+  if (access_token.GetThreadToken(TOKEN_READ) &&
+      access_token.GetUser(&user_sid)) {
+    sid->SetString(user_sid.Sid());
+    return S_OK;
+  } else {
+    return HRESULTFromLastError();
+  }
+}
+
+}  // namespace user_info
+
+}  // namespace omaha
+
diff --git a/common/user_info.h b/common/user_info.h
index 2d40c73..1df0427 100644
--- a/common/user_info.h
+++ b/common/user_info.h
@@ -1,49 +1,49 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Class UserInfo: Information related to the current user or other users on

-// this machine.

-//

-// TODO(omaha): seems we can merge this module with user_rights.

-

-#ifndef OMAHA_COMMON_USER_INFO_H__

-#define OMAHA_COMMON_USER_INFO_H__

-

-#include <atlstr.h>

-

-namespace omaha {

-

-namespace user_info {

-

-// Gets the user name, domain, and the sid associated with the access token

-// of the current process.

-HRESULT GetCurrentUser(CString* name, CString* domain, CString* sid);

-

-// Gets the user sid associated with the access token of the current thread if

-// the thread is impersonating. If the thread is not impersonating, the API

-// fails with ERROR_NO_TOKEN.

-HRESULT GetCurrentThreadUser(CString* sid);

-

-// TODO(omaha): deprecate weird API.

-// Looks at the current user SID and checks if it's the same as the

-// LocalSystem user.

-HRESULT IsLocalSystemUser(bool* is_local_system,

-                          CString* user_sid);     // optional.

-

-}  // namespace user_info

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_USER_INFO_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Class UserInfo: Information related to the current user or other users on
+// this machine.
+//
+// TODO(omaha): seems we can merge this module with user_rights.
+
+#ifndef OMAHA_COMMON_USER_INFO_H__
+#define OMAHA_COMMON_USER_INFO_H__
+
+#include <atlstr.h>
+
+namespace omaha {
+
+namespace user_info {
+
+// Gets the user name, domain, and the sid associated with the access token
+// of the current process.
+HRESULT GetCurrentUser(CString* name, CString* domain, CString* sid);
+
+// Gets the user sid associated with the access token of the current thread if
+// the thread is impersonating. If the thread is not impersonating, the API
+// fails with ERROR_NO_TOKEN.
+HRESULT GetCurrentThreadUser(CString* sid);
+
+// TODO(omaha): deprecate weird API.
+// Looks at the current user SID and checks if it's the same as the
+// LocalSystem user.
+HRESULT IsLocalSystemUser(bool* is_local_system,
+                          CString* user_sid);     // optional.
+
+}  // namespace user_info
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_USER_INFO_H__
diff --git a/common/user_info_unittest.cc b/common/user_info_unittest.cc
index 239c2ef..14588ad 100644
--- a/common/user_info_unittest.cc
+++ b/common/user_info_unittest.cc
@@ -1,50 +1,50 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/user_info.h"

-#include "omaha/testing/unit_test.h"

-

-// We can't make any assumption about the context the unit test runs, however

-// we expect the calls to succeed.

-namespace omaha {

-

-TEST(UserInfoTest, GetCurrentUser) {

-  CString name, domain, sid;

-  ASSERT_HRESULT_SUCCEEDED(user_info::GetCurrentUser(&name, &domain, &sid));

-}

-

-TEST(UserInfoTest, IsLocalSystemUser) {

-  bool is_system = false;

-  CString sid;

-  ASSERT_HRESULT_SUCCEEDED(user_info::IsLocalSystemUser(&is_system, &sid));

-}

-

-TEST(UserInfoTest, GetCurrentUserSid) {

-  CString name, domain, sid1;

-  ASSERT_HRESULT_SUCCEEDED(user_info::GetCurrentUser(&name, &domain, &sid1));

-  CString sid2;

-  ASSERT_HRESULT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &sid2));

-  ASSERT_STREQ(sid1, sid2);

-}

-

-// Expect the unit tests do not run impersonated.

-TEST(UserInfoTest, GetCurrentThreadUser) {

-  CString thread_sid;

-  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_NO_TOKEN),

-            user_info::GetCurrentThreadUser(&thread_sid));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/user_info.h"
+#include "omaha/testing/unit_test.h"
+
+// We can't make any assumption about the context the unit test runs, however
+// we expect the calls to succeed.
+namespace omaha {
+
+TEST(UserInfoTest, GetCurrentUser) {
+  CString name, domain, sid;
+  ASSERT_HRESULT_SUCCEEDED(user_info::GetCurrentUser(&name, &domain, &sid));
+}
+
+TEST(UserInfoTest, IsLocalSystemUser) {
+  bool is_system = false;
+  CString sid;
+  ASSERT_HRESULT_SUCCEEDED(user_info::IsLocalSystemUser(&is_system, &sid));
+}
+
+TEST(UserInfoTest, GetCurrentUserSid) {
+  CString name, domain, sid1;
+  ASSERT_HRESULT_SUCCEEDED(user_info::GetCurrentUser(&name, &domain, &sid1));
+  CString sid2;
+  ASSERT_HRESULT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &sid2));
+  ASSERT_STREQ(sid1, sid2);
+}
+
+// Expect the unit tests do not run impersonated.
+TEST(UserInfoTest, GetCurrentThreadUser) {
+  CString thread_sid;
+  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_NO_TOKEN),
+            user_info::GetCurrentThreadUser(&thread_sid));
+}
+
+}  // namespace omaha
+
diff --git a/common/user_rights.cc b/common/user_rights.cc
index cc49687..cf10673 100644
--- a/common/user_rights.cc
+++ b/common/user_rights.cc
@@ -1,195 +1,195 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/user_rights.h"

-#include <lm.h>

-#include <wtsapi32.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/vistautil.h"

-

-namespace omaha {

-

-bool UserRights::TokenIsAdmin(HANDLE token) {

-  return BelongsToGroup(token, DOMAIN_ALIAS_RID_ADMINS);

-}

-

-bool UserRights::UserIsAdmin() {

-  return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_ADMINS);

-}

-

-bool UserRights::UserIsUser() {

-  return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_USERS);

-}

-

-bool UserRights::UserIsPowerUser() {

-  return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_POWER_USERS);

-}

-

-bool UserRights::UserIsGuest() {

-  return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_GUESTS);

-}

-

-bool UserRights::BelongsToGroup(HANDLE token, int group_id) {

-  SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;

-  PSID group = NULL;

-

-  BOOL check = ::AllocateAndInitializeSid(&nt_authority,

-                                          2,

-                                          SECURITY_BUILTIN_DOMAIN_RID,

-                                          group_id,

-                                          0,

-                                          0,

-                                          0,

-                                          0,

-                                          0,

-                                          0,

-                                          &group);

-  if (check) {

-    if (!::CheckTokenMembership(token, group, &check)) {

-      check = false;

-    }

-    ::FreeSid(group);

-  }

-  return !!check;

-}

-

-bool UserRights::UserIsRestricted() {

-  scoped_handle token;

-  if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, address(token))) {

-    UTIL_LOG(LE, (_T("[UserRights::UserIsRestricted - OpenProcessToken failed]")

-                  _T("[0x%08x]"), HRESULTFromLastError()));

-    return true;

-  }

-

-  return !!::IsTokenRestricted(get(token));

-}

-

-bool UserRights::UserIsLowOrUntrustedIntegrity() {

-  if (SystemInfo::IsRunningOnVistaOrLater()) {

-    MANDATORY_LEVEL integrity_level = MandatoryLevelUntrusted;

-    if (FAILED(vista_util::GetProcessIntegrityLevel(0, &integrity_level)) ||

-        integrity_level == MandatoryLevelUntrusted ||

-        integrity_level == MandatoryLevelLow) {

-      return true;

-    }

-  }

-

-  return false;

-}

-

-HRESULT UserRights::UserIsLoggedOnInteractively(bool* is_logged_on) {

-  ASSERT1(is_logged_on);

-

-  *is_logged_on = false;

-

-  HRESULT hr = S_OK;

-

-  TCHAR* domain_name = NULL;

-  DWORD domain_name_len = 0;

-  if (!::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,

-                                    WTS_CURRENT_SESSION,

-                                    WTSDomainName,

-                                    &domain_name,

-                                    &domain_name_len)) {

-    hr = HRESULTFromLastError();

-    UTIL_LOG(LE, (_T("[WTSQuerySessionInformation failed][0x%08x]"), hr));

-    return hr;

-  }

-  ON_SCOPE_EXIT(::WTSFreeMemory, domain_name);

-

-  TCHAR* user_name = NULL;

-  DWORD user_name_len = 0;

-  if (!::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,

-                                    WTS_CURRENT_SESSION,

-                                    WTSUserName,

-                                    &user_name,

-                                    &user_name_len)) {

-    hr = HRESULTFromLastError();

-    UTIL_LOG(LE, (_T("[WTSQuerySessionInformation failed][0x%08x]"), hr));

-    return hr;

-  }

-  ON_SCOPE_EXIT(::WTSFreeMemory, user_name);

-

-  UTIL_LOG(L2, (_T("[ts domain=%s][ts user=%s]"), domain_name, user_name));

-

-  // Occasionally, the domain name and user name could not be retrieved when

-  // the program is started just at logon time.

-  if (!(domain_name && *domain_name && user_name && *user_name)) {

-    return E_FAIL;

-  }

-

-  // Get the user associated with the current process.

-  WKSTA_USER_INFO_1* user_info = NULL;

-  NET_API_STATUS status = ::NetWkstaUserGetInfo(

-                              NULL,

-                              1,

-                              reinterpret_cast<uint8**>(&user_info));

-  if (status != NERR_Success || user_info == NULL) {

-    UTIL_LOG(LE, (_T("[NetWkstaUserGetInfo failed][%u]"), status));

-    return HRESULT_FROM_WIN32(status);

-  }

-  ON_SCOPE_EXIT(::NetApiBufferFree, user_info);

-

-  UTIL_LOG(L2, (_T("[wks domain=%s][wks user=%s]"),

-                user_info->wkui1_logon_domain, user_info->wkui1_username));

-

-  *is_logged_on = _tcsicmp(user_info->wkui1_logon_domain, domain_name) == 0 &&

-                  _tcsicmp(user_info->wkui1_username, user_name) == 0;

-  return S_OK;

-}

-

-HRESULT UserRights::GetCallerToken(HANDLE* token) {

-  ASSERT1(token);

-

-  scoped_handle smart_token;

-  HRESULT hr = ::CoImpersonateClient();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = ::OpenThreadToken(::GetCurrentThread(),

-                         TOKEN_QUERY,

-                         true,

-                         address(smart_token)) ? S_OK : HRESULTFromLastError();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = ::CoRevertToSelf();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  *token = release(smart_token);

-  return S_OK;

-}

-

-bool UserRights::ImpersonateAndVerifyCallerIsAdmin() {

-  scoped_handle impersonated_token;

-  if (FAILED(GetCallerToken(address(impersonated_token)))) {

-    return false;

-  }

-  return TokenIsAdmin(get(impersonated_token));

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/user_rights.h"
+#include <lm.h>
+#include <wtsapi32.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/vistautil.h"
+
+namespace omaha {
+
+bool UserRights::TokenIsAdmin(HANDLE token) {
+  return BelongsToGroup(token, DOMAIN_ALIAS_RID_ADMINS);
+}
+
+bool UserRights::UserIsAdmin() {
+  return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_ADMINS);
+}
+
+bool UserRights::UserIsUser() {
+  return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_USERS);
+}
+
+bool UserRights::UserIsPowerUser() {
+  return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_POWER_USERS);
+}
+
+bool UserRights::UserIsGuest() {
+  return BelongsToGroup(NULL, DOMAIN_ALIAS_RID_GUESTS);
+}
+
+bool UserRights::BelongsToGroup(HANDLE token, int group_id) {
+  SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
+  PSID group = NULL;
+
+  BOOL check = ::AllocateAndInitializeSid(&nt_authority,
+                                          2,
+                                          SECURITY_BUILTIN_DOMAIN_RID,
+                                          group_id,
+                                          0,
+                                          0,
+                                          0,
+                                          0,
+                                          0,
+                                          0,
+                                          &group);
+  if (check) {
+    if (!::CheckTokenMembership(token, group, &check)) {
+      check = false;
+    }
+    ::FreeSid(group);
+  }
+  return !!check;
+}
+
+bool UserRights::UserIsRestricted() {
+  scoped_handle token;
+  if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, address(token))) {
+    UTIL_LOG(LE, (_T("[UserRights::UserIsRestricted - OpenProcessToken failed]")
+                  _T("[0x%08x]"), HRESULTFromLastError()));
+    return true;
+  }
+
+  return !!::IsTokenRestricted(get(token));
+}
+
+bool UserRights::UserIsLowOrUntrustedIntegrity() {
+  if (SystemInfo::IsRunningOnVistaOrLater()) {
+    MANDATORY_LEVEL integrity_level = MandatoryLevelUntrusted;
+    if (FAILED(vista_util::GetProcessIntegrityLevel(0, &integrity_level)) ||
+        integrity_level == MandatoryLevelUntrusted ||
+        integrity_level == MandatoryLevelLow) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+HRESULT UserRights::UserIsLoggedOnInteractively(bool* is_logged_on) {
+  ASSERT1(is_logged_on);
+
+  *is_logged_on = false;
+
+  HRESULT hr = S_OK;
+
+  TCHAR* domain_name = NULL;
+  DWORD domain_name_len = 0;
+  if (!::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
+                                    WTS_CURRENT_SESSION,
+                                    WTSDomainName,
+                                    &domain_name,
+                                    &domain_name_len)) {
+    hr = HRESULTFromLastError();
+    UTIL_LOG(LE, (_T("[WTSQuerySessionInformation failed][0x%08x]"), hr));
+    return hr;
+  }
+  ON_SCOPE_EXIT(::WTSFreeMemory, domain_name);
+
+  TCHAR* user_name = NULL;
+  DWORD user_name_len = 0;
+  if (!::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
+                                    WTS_CURRENT_SESSION,
+                                    WTSUserName,
+                                    &user_name,
+                                    &user_name_len)) {
+    hr = HRESULTFromLastError();
+    UTIL_LOG(LE, (_T("[WTSQuerySessionInformation failed][0x%08x]"), hr));
+    return hr;
+  }
+  ON_SCOPE_EXIT(::WTSFreeMemory, user_name);
+
+  UTIL_LOG(L2, (_T("[ts domain=%s][ts user=%s]"), domain_name, user_name));
+
+  // Occasionally, the domain name and user name could not be retrieved when
+  // the program is started just at logon time.
+  if (!(domain_name && *domain_name && user_name && *user_name)) {
+    return E_FAIL;
+  }
+
+  // Get the user associated with the current process.
+  WKSTA_USER_INFO_1* user_info = NULL;
+  NET_API_STATUS status = ::NetWkstaUserGetInfo(
+                              NULL,
+                              1,
+                              reinterpret_cast<uint8**>(&user_info));
+  if (status != NERR_Success || user_info == NULL) {
+    UTIL_LOG(LE, (_T("[NetWkstaUserGetInfo failed][%u]"), status));
+    return HRESULT_FROM_WIN32(status);
+  }
+  ON_SCOPE_EXIT(::NetApiBufferFree, user_info);
+
+  UTIL_LOG(L2, (_T("[wks domain=%s][wks user=%s]"),
+                user_info->wkui1_logon_domain, user_info->wkui1_username));
+
+  *is_logged_on = _tcsicmp(user_info->wkui1_logon_domain, domain_name) == 0 &&
+                  _tcsicmp(user_info->wkui1_username, user_name) == 0;
+  return S_OK;
+}
+
+HRESULT UserRights::GetCallerToken(HANDLE* token) {
+  ASSERT1(token);
+
+  scoped_handle smart_token;
+  HRESULT hr = ::CoImpersonateClient();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = ::OpenThreadToken(::GetCurrentThread(),
+                         TOKEN_QUERY,
+                         true,
+                         address(smart_token)) ? S_OK : HRESULTFromLastError();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = ::CoRevertToSelf();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  *token = release(smart_token);
+  return S_OK;
+}
+
+bool UserRights::ImpersonateAndVerifyCallerIsAdmin() {
+  scoped_handle impersonated_token;
+  if (FAILED(GetCallerToken(address(impersonated_token)))) {
+    return false;
+  }
+  return TokenIsAdmin(get(impersonated_token));
+}
+
+}  // namespace omaha
+
diff --git a/common/user_rights.h b/common/user_rights.h
index 4dd0276..24aa011 100644
--- a/common/user_rights.h
+++ b/common/user_rights.h
@@ -1,72 +1,72 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// This class finds out different user rights on the system.

-// For example it can find out if the user is an administrator.

-

-#ifndef OMAHA_COMMON_USER_RIGHTS_H__

-#define OMAHA_COMMON_USER_RIGHTS_H__

-

-#include <windows.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class UserRights {

- public:

-

-  // Returns true if token is a member of the local Administrators group.

-  static bool TokenIsAdmin(HANDLE token);

-

-  // Returns true if the user belongs to the local Administrators group.

-  static bool UserIsAdmin();

-

-  // Returns true if the user belongs to the Users group.

-  static bool UserIsUser();

-

-  // Returns true if the user belongs to the Power User group.

-  static bool UserIsPowerUser();

-

-  // Returns true if the user is a Guest.

-  static bool UserIsGuest();

-

-  // Returns true if the owner of the current process has a restricted token.

-  static bool UserIsRestricted();

-

-  // Returns true if the owner of the current process runs under low or

-  // untrusted integrity on Vista.

-  static bool UserIsLowOrUntrustedIntegrity();

-

-  // Returns true if the owner of the current process has an interactive

-  // session: console, terminal services, or fast user switching.

-  static HRESULT UserIsLoggedOnInteractively(bool* is_logged_on);

-

-  static HRESULT GetCallerToken(HANDLE* token);

-

-  static bool ImpersonateAndVerifyCallerIsAdmin();

-

-  // Returns true if the owner of the current process is the primary logon token

-  // for the current interactive session: console, terminal services, or fast

-  // user switching.

-  static bool BelongsToGroup(HANDLE token, int group_id);

-

- private:

-  DISALLOW_IMPLICIT_CONSTRUCTORS(UserRights);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_USER_RIGHTS_H__

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// This class finds out different user rights on the system.
+// For example it can find out if the user is an administrator.
+
+#ifndef OMAHA_COMMON_USER_RIGHTS_H__
+#define OMAHA_COMMON_USER_RIGHTS_H__
+
+#include <windows.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class UserRights {
+ public:
+
+  // Returns true if token is a member of the local Administrators group.
+  static bool TokenIsAdmin(HANDLE token);
+
+  // Returns true if the user belongs to the local Administrators group.
+  static bool UserIsAdmin();
+
+  // Returns true if the user belongs to the Users group.
+  static bool UserIsUser();
+
+  // Returns true if the user belongs to the Power User group.
+  static bool UserIsPowerUser();
+
+  // Returns true if the user is a Guest.
+  static bool UserIsGuest();
+
+  // Returns true if the owner of the current process has a restricted token.
+  static bool UserIsRestricted();
+
+  // Returns true if the owner of the current process runs under low or
+  // untrusted integrity on Vista.
+  static bool UserIsLowOrUntrustedIntegrity();
+
+  // Returns true if the owner of the current process has an interactive
+  // session: console, terminal services, or fast user switching.
+  static HRESULT UserIsLoggedOnInteractively(bool* is_logged_on);
+
+  static HRESULT GetCallerToken(HANDLE* token);
+
+  static bool ImpersonateAndVerifyCallerIsAdmin();
+
+  // Returns true if the owner of the current process is the primary logon token
+  // for the current interactive session: console, terminal services, or fast
+  // user switching.
+  static bool BelongsToGroup(HANDLE token, int group_id);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(UserRights);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_USER_RIGHTS_H__
+
diff --git a/common/user_rights_unittest.cc b/common/user_rights_unittest.cc
index f605480..f62374a 100644
--- a/common/user_rights_unittest.cc
+++ b/common/user_rights_unittest.cc
@@ -1,29 +1,29 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/testing/unit_test.h"

-#include "omaha/common/user_rights.h"

-

-namespace omaha {

-

-TEST(UserRightsTest, UserIsLoggedOnInteractively) {

-  bool is_logged_on(false);

-  EXPECT_HRESULT_SUCCEEDED(

-    UserRights::UserIsLoggedOnInteractively(&is_logged_on));

-  EXPECT_TRUE(is_logged_on);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/testing/unit_test.h"
+#include "omaha/common/user_rights.h"
+
+namespace omaha {
+
+TEST(UserRightsTest, UserIsLoggedOnInteractively) {
+  bool is_logged_on(false);
+  EXPECT_HRESULT_SUCCEEDED(
+    UserRights::UserIsLoggedOnInteractively(&is_logged_on));
+  EXPECT_TRUE(is_logged_on);
+}
+
+}  // namespace omaha
+
diff --git a/common/utils.cc b/common/utils.cc
index 3f9cc4d..9dd25c5 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -1,1927 +1,1927 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/utils.h"

-

-#include <ras.h>

-#include <regstr.h>

-#include <urlmon.h>

-#include <wincrypt.h>

-#include <ATLComTime.h>

-#include <atlpath.h>

-#include <map>

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/const_config.h"

-#include "omaha/common/const_timeouts.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/process.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/shell.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/time.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/user_rights.h"

-#include "omaha/common/vistautil.h"

-

-namespace omaha {

-

-namespace {

-

-// Private object namespaces for Vista processes.

-const TCHAR* const kGoopdateBoundaryDescriptor = _T("GoogleUpdate_BD");

-const TCHAR* const kGoopdatePrivateNamespace = _T("GoogleUpdate");

-const TCHAR* const kGoopdatePrivateNamespacePrefix = _T("GoogleUpdate\\");

-

-// Helper for IsPrivateNamespaceAvailable().

-// For simplicity, the handles opened here are leaked. We need these until

-// process exit, at which point they will be cleaned up automatically by the OS.

-bool EnsurePrivateNamespaceAvailable() {

-  HANDLE boundary_descriptor =

-      CreateBoundaryDescriptorWWrap(kGoopdateBoundaryDescriptor, 0);

-  if (NULL == boundary_descriptor) {

-    DWORD last_error(::GetLastError());

-    UTIL_LOG(LE, (_T("CreateBoundaryDescriptor failed[%d]"), last_error));

-    return false;

-  }

-

-  char sid[SECURITY_MAX_SID_SIZE] = {0};

-  DWORD size = sizeof(sid);

-  // Mark the boundary descriptor with the Admins Group SID. Consequently, all

-  // admins, including SYSTEM, will create objects in the same private

-  // namespace.

-  if (!::CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, sid, &size)) {

-    DWORD last_error(::GetLastError());

-    UTIL_LOG(LE, (_T("::CreateWellKnownSid failed[%d]"), last_error));

-    return false;

-  }

-  if (!AddSIDToBoundaryDescriptorWrap(&boundary_descriptor, sid)) {

-    DWORD last_error(::GetLastError());

-    UTIL_LOG(LE, (_T("AddSIDToBoundaryDescriptor fail[%d]"), last_error));

-    return false;

-  }

-

-  NamedObjectAttributes attr;

-  GetAdminDaclSecurityAttributes(&attr.sa, GENERIC_ALL);

-  // The private namespace created here will be used to create objects of the

-  // form "GoogleUpdate\xyz". As the article "Object Namespaces" on MSDN

-  // explains, these kernel objects are safe from squatting attacks from lower

-  // integrity processes.

-  HANDLE namespace_handle =

-      CreatePrivateNamespaceWWrap(&attr.sa,

-                                  boundary_descriptor,

-                                  kGoopdatePrivateNamespace);

-  if (namespace_handle) {

-    return true;

-  }

-  ASSERT(ERROR_ALREADY_EXISTS == ::GetLastError(),

-         (_T("CreatePrivateNamespaceW failed. %d"), ::GetLastError()));

-

-  // Another process has already created the namespace. Attempt to open.

-  namespace_handle = OpenPrivateNamespaceWWrap(boundary_descriptor,

-                                               kGoopdatePrivateNamespace);

-  if (namespace_handle || ::GetLastError() == ERROR_DUP_NAME) {

-    // ERROR_DUP_NAME indicates that we have called CreatePrivateNamespaceWWrap

-    // or OpenPrivateNamespaceWWrap before in the same process. Either way, we

-    // can now create objects prefixed with our private namespace.

-    return true;

-  }

-

-  ASSERT(namespace_handle, (_T("[Could not open private namespace][%d]"),

-                            ::GetLastError()));

-  return false;

-}

-

-}  // namespace

-

-// Returns 0 if an error occurs.

-ULONGLONG VersionFromString(const CString& s) {

-  int pos(0);

-  unsigned int quad[4] = {0, 0, 0, 0};

-

-  for (int i = 0; i < 4; ++i) {

-    CString q = s.Tokenize(_T("."), pos);

-    if (pos == -1) {

-      return 0;

-    }

-

-    int quad_value(0);

-    if (!String_StringToDecimalIntChecked(q, &quad_value)) {

-      return 0;

-    }

-

-    quad[i] = static_cast<unsigned int>(quad_value);

-

-    if (kuint16max < quad[i]) {

-      return 0;

-    }

-  }

-

-  if (s.GetLength() + 1 != pos) {

-    return 0;

-  }

-

-  return MAKEDLLVERULL(quad[0], quad[1], quad[2], quad[3]);

-}

-

-CString StringFromVersion(ULONGLONG version) {

-  const WORD version_major = HIWORD(version >> 32);

-  const WORD version_minor = LOWORD(version >> 32);

-  const WORD version_build = HIWORD(version);

-  const WORD version_patch = LOWORD(version);

-

-  CString version_string;

-  version_string.Format((_T("%u.%u.%u.%u")),

-                        version_major,

-                        version_minor,

-                        version_build,

-                        version_patch);

-  return version_string;

-}

-

-CString GetCurrentDir() {

-  TCHAR cur_dir[MAX_PATH] = {0};

-  if (!::GetCurrentDirectory(MAX_PATH, cur_dir)) {

-    return CString(_T('.'));

-  }

-  return CString(cur_dir);

-}

-

-HRESULT GetNewFileNameInDirectory(const CString& dir, CString* file_name) {

-  ASSERT1(file_name);

-

-  GUID guid = {0};

-  HRESULT hr = ::CoCreateGuid(&guid);

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_WARNING, (_T("[CoCreateGuid failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  CString guid_file_name = GuidToString(guid);

-  CPath file_path(dir);

-  file_path.Append(guid_file_name);

-

-  *file_name = static_cast<const TCHAR*>(file_path);

-  return S_OK;

-}

-

-// determines if a time is in the distant past, present, or future

-TimeCategory GetTimeCategory(const time64 system_time) {

-  time64 now = GetCurrent100NSTime();

-

-  // Times more than a few days in the future are wrong [I will allow a little

-  // leeway, since it could be set in another future time zone, or a program

-  // that likes UNC]]

-  if (system_time > (now + kDaysTo100ns * 5)) {

-    return FUTURE;

-  }

-

-  // times more than 40 years ago are wrong

-  if (system_time < (now - kDaysTo100ns * 365 * 40)) {

-    return PAST;

-  }

-

-  return PRESENT;

-}

-

-// Determine if a given time is probably valid

-bool IsValidTime(const time64 t) {

-  return (GetTimeCategory(t) == PRESENT);

-}

-

-LARGE_INTEGER MSto100NSRelative(DWORD ms) {

-  const __int64 convert_ms_to_100ns_units = 1000 /*ms/us*/ * 10 /*us/100ns*/;

-  __int64 timeout_100ns = static_cast<__int64>(ms) * convert_ms_to_100ns_units;

-  LARGE_INTEGER timeout = {0};

-  timeout.QuadPart = -timeout_100ns;

-  return timeout;

-}

-

-// Use of this method is unsafe. Be careful!

-// Local System and admins get GENERIC_ALL access. Authenticated non-admins get

-// non_admin_access_mask access.

-void GetEveryoneDaclSecurityAttributes(CSecurityAttributes* sec_attr,

-                                       ACCESS_MASK non_admin_access_mask) {

-  ASSERT1(sec_attr);

-

-  // Grant access to all users.

-  CDacl dacl;

-  dacl.AddAllowedAce(Sids::System(), GENERIC_ALL);

-  dacl.AddAllowedAce(Sids::Admins(), GENERIC_ALL);

-  dacl.AddAllowedAce(Sids::Interactive(), non_admin_access_mask);

-

-  CSecurityDesc security_descriptor;

-  security_descriptor.SetDacl(dacl);

-  security_descriptor.MakeAbsolute();

-

-  sec_attr->Set(security_descriptor);

-}

-

-void GetAdminDaclSecurityAttributes(CSecurityAttributes* sec_attr,

-                                    ACCESS_MASK accessmask) {

-  ASSERT1(sec_attr);

-  CDacl dacl;

-  dacl.AddAllowedAce(Sids::System(), accessmask);

-  dacl.AddAllowedAce(Sids::Admins(), accessmask);

-

-  CSecurityDesc security_descriptor;

-  security_descriptor.SetOwner(Sids::Admins());

-  security_descriptor.SetGroup(Sids::Admins());

-  security_descriptor.SetDacl(dacl);

-  security_descriptor.MakeAbsolute();

-

-  sec_attr->Set(security_descriptor);

-}

-

-// This function is not thread-safe.

-bool IsPrivateNamespaceAvailable(bool is_machine) {

-  static bool is_initialized = false;

-  static bool is_available = false;

-

-  if (!is_machine) {

-    // TODO(Omaha): From a security viewpoint, private namespaces do not add

-    // much value for the User Omaha. But from a uniformity perspective, makes

-    // sense to use for both.

-    return false;

-  }

-

-  if (is_initialized) {

-    return is_available;

-  }

-

-  if (!SystemInfo::IsRunningOnVistaOrLater()) {

-    is_available = false;

-    is_initialized = true;

-    return false;

-  }

-

-  is_available = EnsurePrivateNamespaceAvailable();

-  is_initialized = true;

-  return is_available;

-}

-

-

-void GetNamedObjectAttributes(const TCHAR* base_name,

-                              bool is_machine,

-                              NamedObjectAttributes* attr) {

-  ASSERT1(base_name);

-  ASSERT1(attr);

-

-  // TODO(Omaha): Enable this code after we have a better understanding of

-  // Private Object Namespaces.

-#if 0

-  if (IsPrivateNamespaceAvailable(is_machine)) {

-    attr->name = kGoopdatePrivateNamespacePrefix;

-  } else {

-    ASSERT1(!SystemInfo::IsRunningOnVistaOrLater());

-#endif

-

-  attr->name = omaha::kGlobalPrefix;

-

-  if (!is_machine) {

-    CString user_sid;

-    VERIFY1(SUCCEEDED(omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid)));

-    attr->name += user_sid;

-  } else {

-    // Grant access to administrators and system.

-    GetAdminDaclSecurityAttributes(&attr->sa, GENERIC_ALL);

-  }

-

-  attr->name += base_name;

-  UTIL_LOG(L1, (_T("[GetNamedObjectAttributes][named_object=%s]"), attr->name));

-}

-

-// For now, required_ace_flags is only supported for SE_REGISTRY_KEY objects.

-// INHERITED_ACE may be added to the read ACE flags, so it is excluded from

-// the comparison with required_ace_flags.

-HRESULT AddAllowedAce(const TCHAR* object_name,

-                      SE_OBJECT_TYPE object_type,

-                      const CSid& sid,

-                      ACCESS_MASK required_permissions,

-                      uint8 required_ace_flags) {

-  ASSERT1(SE_REGISTRY_KEY == object_type || !required_ace_flags);

-  ASSERT1(0 == (required_ace_flags & INHERITED_ACE));

-

-  CDacl dacl;

-  if (!AtlGetDacl(object_name, object_type, &dacl)) {

-    return HRESULTFromLastError();

-  }

-

-  int ace_count = dacl.GetAceCount();

-  for (int i = 0; i < ace_count; ++i) {

-    CSid sid_entry;

-    ACCESS_MASK existing_permissions = 0;

-    BYTE existing_ace_flags = 0;

-    dacl.GetAclEntry(i,

-                     &sid_entry,

-                     &existing_permissions,

-                     NULL,

-                     &existing_ace_flags);

-    if (sid_entry == sid &&

-        required_permissions == (existing_permissions & required_permissions) &&

-        required_ace_flags == (existing_ace_flags & ~INHERITED_ACE)) {

-      return S_OK;

-    }

-  }

-

-  if (!dacl.AddAllowedAce(sid, required_permissions, required_ace_flags) ||

-      !AtlSetDacl(object_name, object_type, dacl)) {

-    return HRESULTFromLastError();

-  }

-

-  return S_OK;

-}

-

-HRESULT CreateDir(const TCHAR* in_dir,

-                  LPSECURITY_ATTRIBUTES security_attr) {

-  ASSERT1(in_dir);

-  CString path;

-  if (!PathCanonicalize(CStrBuf(path, MAX_PATH), in_dir)) {

-    return E_FAIL;

-  }

-  // Standardize path on backslash so Find works.

-  path.Replace(_T('/'), _T('\\'));

-  int next_slash = path.Find(_T('\\'));

-  while (true) {

-    int len = 0;

-    if (next_slash == -1) {

-      len = path.GetLength();

-    } else {

-      len = next_slash;

-    }

-    CString dir(path.Left(len));

-    // The check for File::Exists should not be needed. However in certain

-    // cases, i.e. when the program is run from a n/w drive or from the

-    // root drive location, the first CreateDirectory fails with an

-    // E_ACCESSDENIED instead of a ALREADY_EXISTS. Hence we protect the call

-    // with the exists.

-    if (!File::Exists(dir)) {

-      if (!::CreateDirectory(dir, security_attr)) {

-        DWORD error = ::GetLastError();

-        if (ERROR_FILE_EXISTS != error && ERROR_ALREADY_EXISTS != error) {

-          return HRESULT_FROM_WIN32(error);

-        }

-      }

-    }

-    if (next_slash == -1) {

-      break;

-    }

-    next_slash = path.Find(_T('\\'), next_slash + 1);

-  }

-

-  return S_OK;

-}

-

-HRESULT GetFolderPath(int csidl, CString* path) {

-  if (!path) {

-    return E_INVALIDARG;

-  }

-

-  TCHAR buffer[MAX_PATH] = {0};

-  HRESULT hr = ::SHGetFolderPath(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, buffer);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  *path = buffer;

-  return S_OK;

-}

-

-// Delete directory files. If failed, try to schedule deletion at next reboot

-HRESULT DeleteDirectoryFiles(const TCHAR* dir_name) {

-  ASSERT1(dir_name);

-  return DeleteWildcardFiles(dir_name, _T("*"));

-}

-

-// Delete a set of wildcards within dir_name.

-// If unable to delete immediately, try to schedule deletion at next reboot

-HRESULT DeleteWildcardFiles(const TCHAR* dir_name, const TCHAR* wildcard_name) {

-  ASSERT1(dir_name);

-  ASSERT1(wildcard_name);

-

-  HRESULT hr = S_OK;

-

-  WIN32_FIND_DATA find_data;

-  SetZero(find_data);

-

-  CString find_file(dir_name);

-  find_file += _T('\\');

-  find_file += wildcard_name;

-

-  scoped_hfind hfind(::FindFirstFile(find_file, &find_data));

-  if (!hfind) {

-    if (::GetLastError() == ERROR_NO_MORE_FILES) {

-      return S_OK;

-    } else {

-      hr = HRESULTFromLastError();

-      UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")

-                             _T("[failed to get first file][0x%x]"), hr));

-      return hr;

-    }

-  }

-

-  do {

-    if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {

-      CString specific_file_name(dir_name);

-      specific_file_name += _T('\\');

-      specific_file_name += find_data.cFileName;

-      if (!::DeleteFile(specific_file_name)) {

-        if (!SUCCEEDED(hr = File::DeleteAfterReboot(specific_file_name))) {

-          UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")

-                                 _T("[failed to delete after reboot]")

-                                 _T("[%s][0x%x]"), specific_file_name, hr));

-        }

-      }

-    }

-  } while (::FindNextFile(get(hfind), &find_data));

-

-  if (::GetLastError() != ERROR_NO_MORE_FILES) {

-    hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")

-                           _T("[failed to get next file][0x%x]"), hr));

-  }

-

-  return hr;

-}

-

-// Delete directory and files within. If failed, try to schedule deletion at

-// next reboot

-// TODO(Omaha) - the code to delete the directory is complicated,

-// especially the way the result code is built from hr and hr1. I wonder if we

-// could simplify this by reimplementing it on top of SHFileOperation and

-// also save a few tens of bytes in the process.

-HRESULT DeleteDirectory(const TCHAR* dir_name) {

-  ASSERT1(dir_name);

-

-  if (!SafeDirectoryNameForDeletion(dir_name)) {

-    return E_FAIL;

-  }

-

-  // Make sure the directory exists (it is ok if it doesn't)

-  DWORD dir_attributes = ::GetFileAttributes(dir_name);

-  if (dir_attributes == INVALID_FILE_ATTRIBUTES) {

-    if (::GetLastError() == ERROR_FILE_NOT_FOUND)

-      return S_OK;  // Ok if directory is missing

-    else

-      return HRESULTFromLastError();

-  }

-  // Confirm it is a directory

-  if (!(dir_attributes & FILE_ATTRIBUTE_DIRECTORY)) {

-    return E_FAIL;

-  }

-

-  // Try to delete all files at best effort

-  // Return the first HRESULT error encountered

-

-  // First delete all the normal files

-  HRESULT hr = DeleteDirectoryFiles(dir_name);

-

-  // Recursively delete any subdirectories

-

-  WIN32_FIND_DATA find_data = {0};

-

-  CString find_file(dir_name);

-  find_file += _T("\\*");

-

-  // Note that the follows are enclosed in a block because we need to close the

-  // find handle before deleting the directorty itself

-  {

-    scoped_hfind hfind(::FindFirstFile(find_file, &find_data));

-    if (!hfind) {

-      if (::GetLastError() == ERROR_NO_MORE_FILES) {

-        return hr;

-      } else {

-        HRESULT hr1 = HRESULTFromLastError();

-        UTIL_LOG(LEVEL_ERROR, (_T("[DeleteDirectory]")

-                               _T("[failed to get first file][0x%x]"), hr1));

-        return SUCCEEDED(hr) ? hr1 : hr;

-      }

-    }

-

-    do {

-      if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {

-        if (String_StrNCmp(find_data.cFileName, _T("."), 2, false) == 0 ||

-            String_StrNCmp(find_data.cFileName, _T(".."), 3, false) == 0) {

-          continue;

-        }

-

-        CString sub_dir(dir_name);

-        sub_dir += _T("\\");

-        sub_dir += find_data.cFileName;

-        HRESULT hr1 = DeleteDirectory(sub_dir);

-        if (SUCCEEDED(hr) && FAILED(hr1)) {

-          hr = hr1;

-        }

-      }

-    }

-    while (::FindNextFile(get(hfind), &find_data));

-  }

-

-  // Delete the empty directory itself

-  if (!::RemoveDirectory(dir_name)) {

-    HRESULT hr1 = E_FAIL;

-    if (FAILED(hr1 = File::DeleteAfterReboot(dir_name))) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[DeleteDirectory]")

-                             _T("[failed to delete after reboot]")

-                             _T("[%s][0x%x]"), dir_name, hr1));

-    }

-

-    if (SUCCEEDED(hr) && FAILED(hr1)) {

-      hr = hr1;

-    }

-  }

-

-  return hr;

-}

-

-// Returns true if this directory name is 'safe' for deletion (doesn't contain

-// "..", doesn't specify a drive root)

-bool SafeDirectoryNameForDeletion(const TCHAR* dir_name) {

-  ASSERT1(dir_name);

-

-  // empty name isn't allowed

-  if (!(dir_name && *dir_name)) {

-    return false;

-  }

-

-  // require a character other than \/:. after the last :

-  // disallow anything with ".."

-  bool ok = false;

-  for (const TCHAR* s = dir_name; *s; ++s) {

-    if (*s != _T('\\') && *s != _T('/') && *s != _T(':') && *s != _T('.')) {

-      ok = true;

-    }

-    if (*s == _T('.') && s > dir_name && *(s-1) == _T('.')) {

-      return false;

-    }

-    if (*s == _T(':')) {

-      ok = false;

-    }

-  }

-  return ok;

-}

-

-// Utility function that deletes either a file or directory,

-// before or after reboot

-HRESULT DeleteBeforeOrAfterReboot(const TCHAR* targetname) {

-  if (!File::Exists(targetname)) {

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-

-  HRESULT hr = E_FAIL;

-  if (File::IsDirectory(targetname)) {

-    // DeleteDirectory will schedule deletion at next reboot if it cannot delete

-    // immediately.

-    hr = DeleteDirectory(targetname);

-  } else  {

-    hr = File::Remove(targetname);

-    // If failed, schedule deletion at next reboot

-    if (FAILED(hr)) {

-      UTIL_LOG(L1, (_T("[DeleteBeforeOrAfterReboot]")

-                    _T("[trying to delete %s after reboot]"), targetname));

-      hr = File::DeleteAfterReboot(targetname);

-    }

-  }

-

-  if (FAILED(hr)) {

-    UTIL_LOG(L1, (_T("[DeleteBeforeOrAfterReboot]")

-                  _T("[failed to delete %s]"), targetname));

-  }

-

-  return hr;

-}

-

-

-// Internal implementation of the safe version of getting size of all files in

-// a directory. It is able to abort the counting if one of the maximum criteria

-// is reached.

-HRESULT InternalSafeGetDirectorySize(const TCHAR* dir_name,

-                                     uint64* size,

-                                     HANDLE shutdown_event,

-                                     uint64 max_size,

-                                     int curr_file_count,

-                                     int max_file_count,

-                                     int curr_depth,

-                                     int max_depth,

-                                     DWORD end_time_ms) {

-  ASSERT1(dir_name && *dir_name);

-  ASSERT1(size);

-

-  CString dir_find_name = String_MakeEndWith(dir_name, _T("\\"), false);

-  dir_find_name += _T("*");

-  WIN32_FIND_DATA find_data = {0};

-  scoped_hfind hfind(::FindFirstFile(dir_find_name, &find_data));

-  if (!hfind) {

-    return ::GetLastError() == ERROR_NO_MORE_FILES ? S_OK :

-                                                     HRESULTFromLastError();

-  }

-

-  do {

-    // Bail out if shutting down

-    if (shutdown_event && IsHandleSignaled(shutdown_event)) {

-      return E_ABORT;

-    }

-

-    // Bail out if reaching maximum running time

-    if (end_time_ms && ::GetTickCount() >= end_time_ms) {

-      UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")

-                    _T("[reaching max running time][%s][%u]"),

-                    dir_name, end_time_ms));

-      return E_ABORT;

-    }

-

-    // Skip reparse point since it might be a hard link which could cause an

-    // infinite recursive directory loop.

-    if (find_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {

-      continue;

-    }

-

-    if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {

-      // Skip . and ..

-      if (String_StrNCmp(find_data.cFileName, _T("."), 2, false) == 0 ||

-          String_StrNCmp(find_data.cFileName, _T(".."), 3, false) == 0) {

-        continue;

-      }

-

-      // Bail out if reaching maximum depth

-      if (max_depth && curr_depth + 1 >= max_depth) {

-        UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")

-                      _T("[reaching max depth][%s][%u]"), dir_name, max_depth));

-        return E_ABORT;

-      }

-

-      // Walk over sub-directory

-      CString sub_dir_name = String_MakeEndWith(dir_name, _T("\\"), false);

-      sub_dir_name += find_data.cFileName;

-      RET_IF_FAILED(InternalSafeGetDirectorySize(sub_dir_name,

-                                                 size,

-                                                 shutdown_event,

-                                                 max_size,

-                                                 curr_file_count,

-                                                 max_file_count,

-                                                 curr_depth + 1,

-                                                 max_depth,

-                                                 end_time_ms));

-    } else {

-      // Bail out if reaching maximum number of files

-      ++curr_file_count;

-      if (max_file_count && curr_file_count >= max_file_count) {

-        UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")

-                      _T("[reaching max file count][%s][%u]"),

-                      dir_name, max_file_count));

-        return E_ABORT;

-      }

-

-      // Count the file size

-      uint64 file_size =

-          ((static_cast<uint64>((find_data.nFileSizeHigh)) << 32)) +

-          static_cast<uint64>(find_data.nFileSizeLow);

-      *size += file_size;

-

-      // Bail out if reaching maximum size

-      if (max_size && *size >= max_size) {

-        UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")

-                      _T("[reaching max size][%s][%u]"), dir_name, max_size));

-        return E_ABORT;

-      }

-    }

-  } while (::FindNextFile(get(hfind), &find_data));

-

-  return ::GetLastError() == ERROR_NO_MORE_FILES ? S_OK :

-                                                   HRESULTFromLastError();

-}

-

-// The safe version of getting size of all files in a directory

-// It is able to abort the counting if one of the maximum criteria is reached

-HRESULT SafeGetDirectorySize(const TCHAR* dir_name,

-                             uint64* size,

-                             HANDLE shutdown_event,

-                             uint64 max_size,

-                             int max_file_count,

-                             int max_depth,

-                             int max_running_time_ms) {

-  ASSERT1(dir_name && *dir_name);

-  ASSERT1(size);

-

-  *size = 0;

-

-  DWORD end_time = 0;

-  if (max_running_time_ms > 0) {

-    end_time = ::GetTickCount() + max_running_time_ms;

-  }

-  return InternalSafeGetDirectorySize(dir_name,

-                                      size,

-                                      shutdown_event,

-                                      max_size,

-                                      0,

-                                      max_file_count,

-                                      0,

-                                      max_depth,

-                                      end_time);

-}

-

-// Get size of all files in a directory

-HRESULT GetDirectorySize(const TCHAR* dir_name, uint64* size) {

-  ASSERT1(dir_name && *dir_name);

-  ASSERT1(size);

-  return SafeGetDirectorySize(dir_name, size, NULL, 0, 0, 0, 0);

-}

-

-// Handles the logic to determine the handle that was signaled

-// as a result of calling *WaitForMultipleObjects.

-HRESULT GetSignaledObjectPosition(uint32 cnt, DWORD res, uint32* pos) {

-  ASSERT1(pos);

-

-  if (res == WAIT_FAILED) {

-    return S_FALSE;

-  }

-

-#pragma warning(disable : 4296)

-  // C4296: '>=' : expression is always true

-  if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cnt)) {

-    *pos = res - WAIT_OBJECT_0;

-    return S_OK;

-  }

-#pragma warning(default : 4296)

-

-  if ((res >= WAIT_ABANDONED_0) && (res < WAIT_ABANDONED_0 + cnt)) {

-    *pos = res - WAIT_ABANDONED_0;

-    return S_OK;

-  }

-  return E_INVALIDARG;

-}

-

-// Supports all of the other WaitWithMessage* functions.

-//

-// Returns:

-//    S_OK when the message loop should continue.

-//    S_FALSE when it receives something that indicates the

-//      loop should quit.

-//    E_* only when GetMessage failed

-//

-// This function is not exposed outside of this file.  Only

-// friendly wrappers of it are.

-HRESULT WaitWithMessageLoopAnyInternal(

-    const HANDLE* phandles,

-    uint32 cnt,

-    uint32* pos,

-    MessageHandlerInternalInterface* message_handler) {

-  ASSERT1(pos && message_handler);

-  // cnt and phandles are either both zero or both not zero.

-  ASSERT1(!cnt == !phandles);

-

-  // Loop until an error happens or the wait is satisfied by a signaled

-  // object or an abandoned mutex.

-  for (;;) {

-    MSG msg = {0};

-

-    // Process the messages in the input queue.

-    while (::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {

-      BOOL ret = false;

-      if ((ret = ::GetMessage(&msg, NULL, 0, 0)) != 0) {

-        if (ret == -1) {

-          HRESULT hr = HRESULTFromLastError();

-          UTIL_LOG(LEVEL_ERROR,

-              (_T("[WaitWithMessageLoopAny - GetMessage failed][0x%08x]"), hr));

-          return hr;

-        }

-        message_handler->Process(&msg, &phandles, &cnt);

-      } else {

-        // We need to re-post the quit message we retrieved so that it could

-        // propagate to the outer layer. Otherwise, the program will seem to

-        // "get stuck" in its shutdown code.

-        ::PostQuitMessage(msg.wParam);

-        return S_FALSE;

-      }

-

-      // WaitForMultipleObjects fails if cnt == 0.

-      if (cnt) {

-        // Briefly check the state of the handle array to see if something

-        // has signaled as we processed a message.

-        ASSERT1(phandles);

-        DWORD res = ::WaitForMultipleObjects(cnt, phandles, false, 0);

-        ASSERT1(res != WAIT_FAILED);

-        HRESULT hr = GetSignaledObjectPosition(cnt, res, pos);

-        if (SUCCEEDED(hr)) {

-          return hr;

-        }

-      }

-    }

-

-    // The wait with message. It is satisfied by either the objects getting

-    // signaled or when messages enter the message queue.

-    // TODO(omaha): implementing timeout is a little bit tricky since we

-    // want the timeout on the handles only and the native API does not

-    // have this semantic.

-    //

-    // TODO(omaha): use a waitable timer to implement the timeout.

-    //

-    // When cnt is zero then the execution flow waits here until messages

-    // arrive in the input queue. Unlike WaitForMultipleObjects,

-    // MsgWaitForMultipleObjects does not error out when cnt == 0.

-    const DWORD timeout = INFINITE;

-    DWORD res(::MsgWaitForMultipleObjects(cnt, phandles, false, timeout,

-                                          QS_ALLINPUT));

-    ASSERT((res != WAIT_FAILED),

-           (_T("[MsgWaitForMultipleObjects returned WAIT_FAILED][%u]"),

-            ::GetLastError()));

-

-    ASSERT1(res != WAIT_TIMEOUT);

-

-    HRESULT hr = GetSignaledObjectPosition(cnt, res, pos);

-    if (SUCCEEDED(hr)) {

-      return hr;

-    }

-  }

-}

-

-// The simplest implementation of a message processor

-void BasicMessageHandler::Process(MSG* msg) {

-  ASSERT1(msg);

-  ::TranslateMessage(msg);

-  ::DispatchMessage(msg);

-}

-

-class BasicMessageHandlerInternal : public BasicMessageHandler,

-                                    public MessageHandlerInternalInterface {

- public:

-  BasicMessageHandlerInternal() {}

-  virtual void Process(MSG* msg, const HANDLE**, uint32*) {

-    BasicMessageHandler::Process(msg);

-  }

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(BasicMessageHandlerInternal);

-};

-

-

-bool WaitWithMessageLoopAny(const std::vector<HANDLE>& handles, uint32* pos) {

-  BasicMessageHandlerInternal msg_handler;

-  return WaitWithMessageLoopAnyInternal(&handles.front(), handles.size(), pos,

-                                        &msg_handler) != S_FALSE;

-}

-

-bool WaitWithMessageLoopAll(const std::vector<HANDLE>& handles) {

-  // make a copy of the vector, as objects must be removed from the

-  // wait array as they get signaled.

-  std::vector<HANDLE> h(handles);

-

-  // The function is mainly implemented in terms of WaitWithMessageLoopAny

-

-  // loop until all objects are signaled.

-  while (!h.empty()) {

-    uint32 pos(static_cast<uint32>(-1));

-    if (!WaitWithMessageLoopAny(h, &pos)) return false;

-    ASSERT1(pos < h.size());

-    h.erase(h.begin() + pos);   // remove the signaled object and loop

-  }

-

-  return true;

-}

-

-bool WaitWithMessageLoop(HANDLE h) {

-  BasicMessageHandlerInternal msg_handler;

-  uint32 pos(static_cast<uint32>(-1));

-  bool res =

-    WaitWithMessageLoopAnyInternal(&h, 1, &pos, &msg_handler) != S_FALSE;

-  if (res) {

-    // It's the first and the only handle that it is signaled.

-    ASSERT1(pos == 0);

-  }

-  return res;

-}

-

-// Wait with message loop for a certain period of time

-bool WaitWithMessageLoopTimed(DWORD ms) {

-  scoped_timer timer(::CreateWaitableTimer(NULL,

-                                           true,   // manual reset

-                                           NULL));

-  ASSERT1(get(timer));

-  LARGE_INTEGER timeout = MSto100NSRelative(ms);

-  BOOL timer_ok = ::SetWaitableTimer(get(timer),

-                                     &timeout,

-                                     0,

-                                     NULL,

-                                     NULL,

-                                     false);

-  ASSERT1(timer_ok);

-  return WaitWithMessageLoop(get(timer));

-}

-

-MessageLoopWithWait::MessageLoopWithWait() : message_handler_(NULL) {

-}

-

-void MessageLoopWithWait::set_message_handler(

-    MessageHandlerInterface* message_handler) {

-  message_handler_ = message_handler;

-}

-

-// The message loop and handle callback routine.

-HRESULT MessageLoopWithWait::Process() {

-  while (true) {

-    ASSERT1(callback_handles_.size() == callbacks_.size());

-

-    // The implementation allows for an empty array of handles. Taking the

-    // address of elements in an empty container is not allowed so we must

-    // deal with this case here.

-    size_t pos(0);

-    HRESULT hr = WaitWithMessageLoopAnyInternal(

-        callback_handles_.empty() ? NULL : &callback_handles_.front(),

-        callback_handles_.size(),

-        &pos,

-        this);

-

-    // In addition to E_*, S_FALSE should cause a return to happen here.

-    if (hr != S_OK) {

-      return hr;

-    }

-

-    ASSERT1(pos < callback_handles_.size());

-    ASSERT1(callback_handles_.size() == callbacks_.size());

-

-    HANDLE signaled_handle = callback_handles_[pos];

-    WaitCallbackInterface* callback_interface = callbacks_[pos];

-    RemoveHandleAt(pos);

-

-    if (!callback_interface->HandleSignaled(signaled_handle)) {

-      return S_OK;

-    }

-  }

-}

-

-// Handles one messgae and adjust the handles and cnt as appropriate after

-// handling the message.

-void MessageLoopWithWait::Process(MSG* msg, const HANDLE** handles,

-                                  uint32* cnt) {

-  ASSERT1(msg && handles && cnt);

-

-  if (message_handler_) {

-    message_handler_->Process(msg);

-  }

-

-  // Set the handles and count again because they may have changed

-  // while processing the message.

-  *handles = callback_handles_.empty() ? NULL : &callback_handles_.front();

-  *cnt = callback_handles_.size();

-}

-// Starts waiting on the given handle

-bool MessageLoopWithWait::RegisterWaitForSingleObject(

-    HANDLE handle, WaitCallbackInterface* callback) {

-  ASSERT1(callback_handles_.size() == callbacks_.size());

-  ASSERT1(callback != NULL);

-

-  if (callback_handles_.size() >= MAXIMUM_WAIT_OBJECTS - 1) {

-    return false;

-  }

-

-  // In case the user is registering a handle, that they previous added

-  // remove the previous one before adding it back into the array.

-  UnregisterWait(handle);

-  callback_handles_.push_back(handle);

-  callbacks_.push_back(callback);

-

-  ASSERT1(callback_handles_.size() == callbacks_.size());

-  return true;

-}

-

-// Finds the given handle and stops waiting on it

-bool MessageLoopWithWait::UnregisterWait(HANDLE handle) {

-  ASSERT1(callback_handles_.size() == callbacks_.size());

-

-  for (uint32 index = 0; index < callback_handles_.size() ; index++) {

-    if (callback_handles_[index] == handle) {

-      RemoveHandleAt(index);

-      return true;

-    }

-  }

-  return false;

-}

-

-// Removes the wait handle at the given position

-void MessageLoopWithWait::RemoveHandleAt(uint32 pos) {

-  ASSERT1(callback_handles_.size() == callbacks_.size());

-  ASSERT1(pos < callback_handles_.size());

-

-  callback_handles_.erase(callback_handles_.begin() + pos);

-  callbacks_.erase(callbacks_.begin() + pos);

-

-  ASSERT1(callback_handles_.size() == callbacks_.size());

-}

-

-HRESULT CallEntryPoint0(const TCHAR* dll_path,

-                        const char* function_name,

-                        HRESULT* result) {

-  ASSERT1(dll_path);

-  ASSERT1(::lstrlen(dll_path) > 0);

-  ASSERT1(function_name);

-  ASSERT1(::strlen(function_name) > 0);

-  ASSERT1(result);

-

-  scoped_library dll(::LoadLibrary(dll_path));

-  if (!dll) {

-    return HRESULTFromLastError();

-  }

-

-  HRESULT (*proc)() = reinterpret_cast<HRESULT (*)()>(

-      ::GetProcAddress(get(dll), function_name));

-  if (!proc) {

-    return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);

-  }

-

-  *result = (proc)();

-  return S_OK;

-}

-

-// Register a DLL

-HRESULT RegisterDll(const TCHAR* dll_path) {

-  HRESULT hr = S_OK;

-  HRESULT hr_call = CallEntryPoint0(dll_path, "DllRegisterServer", &hr);

-  if (SUCCEEDED(hr_call)) {

-    return hr;

-  }

-  return hr_call;

-}

-

-// Unregister a DLL

-HRESULT UnregisterDll(const TCHAR* dll_path) {

-  HRESULT hr = S_OK;

-  HRESULT hr_call = CallEntryPoint0(dll_path, "DllUnregisterServer", &hr);

-  if (SUCCEEDED(hr_call)) {

-    return hr;

-  }

-  return hr_call;

-}

-

-// Register/unregister an EXE

-HRESULT RegisterOrUnregisterExe(const TCHAR* exe_path, const TCHAR* cmd_line) {

-  ASSERT1(exe_path);

-  ASSERT1(cmd_line);

-

-  // cmd_line parameter really contains the arguments to be passed

-  // on the process creation command line.

-  PROCESS_INFORMATION pi = {0};

-  HRESULT hr = System::StartProcessWithArgsAndInfo(exe_path, cmd_line, &pi);

-  if (FAILED(hr)) {

-    UTIL_LOG(LEVEL_WARNING, (_T("[RegisterOrUnregisterExe]")

-                             _T("[failed to start process]")

-                             _T("[%s][%s][0x%08x]"), exe_path, cmd_line, hr));

-    return hr;

-  }

-  // Take ownership of the handles for clean up.

-  scoped_thread thread(pi.hThread);

-  scoped_process process(pi.hProcess);

-

-  // ATL COM servers return an HRESULT on exit. There is a case in which they

-  // return -1 which seems like a bug in ATL. It appears there is no

-  // documented convention on what a local server would return for errors.

-  // There is a possibility that a server would return Windows errors.

-

-  // Wait on the process to exit and return the exit code of the process.

-  DWORD result(::WaitForSingleObject(get(process), kRegisterExeTimeoutMs));

-  DWORD exit_code(0);

-  if (result == WAIT_OBJECT_0 &&

-      ::GetExitCodeProcess(get(process), &exit_code)) {

-    return static_cast<HRESULT>(exit_code);

-  } else {

-    return HRESULT_FROM_WIN32(ERROR_TIMEOUT);

-  }

-}

-

-// Register a COM Local Server

-HRESULT RegisterServer(const TCHAR* exe_path) {

-  return RegisterOrUnregisterExe(exe_path, _T("/RegServer"));

-}

-

-// Unregister a COM Local Server

-HRESULT UnregisterServer(const TCHAR* exe_path) {

-  return RegisterOrUnregisterExe(exe_path, _T("/UnregServer"));

-}

-

-// Register a Service

-HRESULT RegisterService(const TCHAR* exe_path) {

-  return RegisterOrUnregisterExe(exe_path, _T("/Service"));

-}

-

-// Unregister a Service

-HRESULT UnregisterService(const TCHAR* exe_path) {

-  // Unregistering a service is via UnregServer

-  return RegisterOrUnregisterExe(exe_path, _T("/UnregServer"));

-}

-

-// Adapted from gds installer/install/work_list.cpp: InstallServiceExecutable

-HRESULT RunService(const TCHAR* service_name) {

-  scoped_service manager(::OpenSCManager(NULL,  // local machine

-                                         NULL,  // ServicesActive database

-                                         STANDARD_RIGHTS_READ));

-  ASSERT1(get(manager));

-  if (!get(manager)) {

-    return HRESULTFromLastError();

-  }

-

-  scoped_service service(::OpenService(get(manager), service_name,

-                                       SERVICE_START));

-  ASSERT1(get(service));

-  if (!get(service)) {

-    return HRESULTFromLastError();

-  }

-

-  UTIL_LOG(L2, (_T("start service")));

-  if (!::StartService(get(service), 0, NULL)) {

-    return HRESULTFromLastError();

-  }

-  return S_OK;

-}

-

-

-HRESULT ReadEntireFile(const TCHAR* filepath,

-                       uint32 max_len,

-                       std::vector<byte>* buffer_out) {

-  return ReadEntireFileShareMode(filepath, max_len, 0, buffer_out);

-}

-

-HRESULT ReadEntireFileShareMode(const TCHAR* filepath,

-                                uint32 max_len,

-                                DWORD share_mode,

-                                std::vector<byte>* buffer_out) {

-  ASSERT1(filepath);

-  ASSERT1(buffer_out);

-

-  File file;

-  HRESULT hr = file.OpenShareMode(filepath, false, false, share_mode);

-  if (FAILED(hr)) {

-    // File missing.

-    return hr;

-  }

-

-  ON_SCOPE_EXIT_OBJ(file, &File::Close);

-

-  uint32 file_len = 0;

-  hr = file.GetLength(&file_len);

-  if (FAILED(hr)) {

-    // Should never happen

-    return hr;

-  }

-

-  if (max_len != 0 && file_len > max_len) {

-    // Too large to consider

-    return MEM_E_INVALID_SIZE;

-  }

-

-  if (file_len == 0) {

-    buffer_out->clear();

-    return S_OK;

-  }

-

-  int old_size = buffer_out->size();

-  buffer_out->resize(old_size + file_len);

-

-  uint32 bytes_read = 0;

-  hr = file.ReadFromStartOfFile(file_len,

-                                &(*buffer_out)[old_size],

-                                &bytes_read);

-  if (FAILED(hr)) {

-    // I/O error of some kind

-    return hr;

-  }

-

-  if (bytes_read != file_len) {

-    // Unexpected length. This could happen when reading a file someone else

-    // is writing to such as log files.

-    ASSERT1(false);

-    return E_UNEXPECTED;

-  }

-

-  // All's well that ends well

-  return S_OK;

-}

-

-HRESULT WriteEntireFile(const TCHAR * filepath,

-                        const std::vector<byte>& buffer_in) {

-  ASSERT1(filepath);

-

-  // File::WriteAt doesn't implement clear-on-open-for-write semantics,

-  // so just delete the file if it exists instead of writing into it.

-

-  if (File::Exists(filepath)) {

-    HRESULT hr = File::Remove(filepath);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  File file;

-  HRESULT hr = file.Open(filepath, true, false);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ON_SCOPE_EXIT_OBJ(file, &File::Close);

-

-  uint32 bytes_written = 0;

-  hr = file.WriteAt(0, &buffer_in.front(), buffer_in.size(), 0, &bytes_written);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (bytes_written != buffer_in.size()) {

-    // This shouldn't happen, caller needs to investigate what's up.

-    ASSERT1(false);

-    return E_UNEXPECTED;

-  }

-

-  return S_OK;

-}

-

-// Conversions between a byte stream and a std::string

-HRESULT BufferToString(const std::vector<byte>& buffer_in, CStringA* str_out) {

-  ASSERT1(str_out);

-  str_out->Append(reinterpret_cast<const char*>(&buffer_in.front()),

-                  buffer_in.size());

-  return S_OK;

-}

-

-HRESULT StringToBuffer(const CStringA& str_in, std::vector<byte>* buffer_out) {

-  ASSERT1(buffer_out);

-  buffer_out->assign(str_in.GetString(),

-                     str_in.GetString() + str_in.GetLength());

-  return S_OK;

-}

-

-HRESULT BufferToString(const std::vector<byte>& buffer_in, CString* str_out) {

-  ASSERT1(str_out);

-

-  size_t len2 = buffer_in.size();

-  ASSERT1(len2 % 2 == 0);

-  size_t len = len2 / 2;

-

-  str_out->Append(reinterpret_cast<const TCHAR*>(&buffer_in.front()), len);

-

-  return S_OK;

-}

-

-HRESULT StringToBuffer(const CString& str_in, std::vector<byte>* buffer_out) {

-  ASSERT1(buffer_out);

-

-  size_t len = str_in.GetLength();

-  size_t len2 = len * 2;

-

-  buffer_out->resize(len2);

-  ::memcpy(&buffer_out->front(), str_in.GetString(), len2);

-

-  return S_OK;

-}

-

-HRESULT RegSplitKeyvalueName(const CString& keyvalue_name,

-                             CString* key_name,

-                             CString* value_name) {

-  ASSERT1(key_name);

-  ASSERT1(value_name);

-

-  const TCHAR kDefault[] = _T("\\(default)");

-

-  if (String_EndsWith(keyvalue_name, _T("\\"), false)) {

-    key_name->SetString(keyvalue_name, keyvalue_name.GetLength() - 1);

-    value_name->Empty();

-  } else if (String_EndsWith(keyvalue_name, kDefault, true)) {

-    key_name->SetString(keyvalue_name,

-                        keyvalue_name.GetLength() - TSTR_SIZE(kDefault));

-    value_name->Empty();

-  } else {

-    int last_slash = String_ReverseFindChar(keyvalue_name, _T('\\'));

-    if (last_slash == -1) {

-      // No slash found - bizzare and wrong

-      return E_FAIL;

-    }

-    key_name->SetString(keyvalue_name, last_slash);

-    value_name->SetString(keyvalue_name.GetString() + last_slash + 1,

-                          keyvalue_name.GetLength() - last_slash - 1);

-  }

-

-  return S_OK;

-}

-

-HRESULT ExpandEnvLikeStrings(const TCHAR* src,

-                             const std::map<CString, CString>& keywords,

-                             CString* dest) {

-  ASSERT1(src);

-  ASSERT1(dest);

-

-  const TCHAR kMarker = _T('%');

-

-  dest->Empty();

-

-  // Loop while finding the marker in the string

-  HRESULT hr = S_OK;

-  int pos = 0;

-  int marker_pos1 = -1;

-  while ((marker_pos1 = String_FindChar(src, kMarker, pos)) != -1) {

-    // Try to find the right marker

-    int marker_pos2 = -1;

-    const TCHAR* s = src + marker_pos1 + 1;

-    for (; *s; ++s) {

-      if (*s == kMarker) {

-        marker_pos2 = s - src;

-        break;

-      }

-      if (!String_IsIdentifierChar(*s)) {

-        break;

-      }

-    }

-    if (marker_pos2 == -1) {

-      // Unmatched marker found, skip

-      dest->Append(src + pos, marker_pos1 - pos + 1);

-      pos = marker_pos1 + 1;

-      continue;

-    }

-

-    // Get the name - without the % markers on each end

-    CString name(src + marker_pos1 + 1, marker_pos2 - marker_pos1 - 1);

-

-    bool found = false;

-    for (std::map<CString, CString>::const_iterator it(keywords.begin());

-         it != keywords.end();

-         ++it) {

-      if (_tcsicmp(it->first, name) == 0) {

-        dest->Append(src + pos, marker_pos1 - pos);

-        dest->Append(it->second);

-        found = true;

-        break;

-      }

-    }

-    if (!found) {

-      // No mapping found

-      UTIL_LOG(LEVEL_ERROR, (_T("[ExpandEnvLikeStrings]")

-                             _T("[no mapping found for '%s' in '%s']"),

-                             name, src));

-      dest->Append(src + pos, marker_pos2 - pos + 1);

-      hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);

-    }

-

-    pos = marker_pos2 + 1;

-  }

-

-  int len = _tcslen(src);

-  if (pos < len) {

-    dest->Append(src + pos, len - pos);

-  }

-

-  return hr;

-}

-

-bool IsRegistryPath(const TCHAR* path) {

-  return String_StartsWith(path, _T("HKLM\\"), false) ||

-         String_StartsWith(path, _T("HKCU\\"), false) ||

-         String_StartsWith(path, _T("HKCR\\"), false) ||

-         String_StartsWith(path, _T("HKEY_LOCAL_MACHINE\\"), false) ||

-         String_StartsWith(path, _T("HKEY_CURRENT_USER\\"), false) ||

-         String_StartsWith(path, _T("HKEY_CLASSES_ROOT\\"), false);

-}

-

-bool IsUrl(const TCHAR* path) {

-  // Currently we only check for "http://" and "https://"

-  return String_StartsWith(path, kHttpProto, true) ||

-         String_StartsWith(path, kHttpsProto, true);

-}

-

-

-CString GuidToString(const GUID& guid) {

-  TCHAR guid_str[40] = {0};

-  VERIFY1(::StringFromGUID2(guid, guid_str, arraysize(guid_str)));

-  String_ToUpper(guid_str);

-  return guid_str;

-}

-

-// Helper function to convert string to GUID

-GUID StringToGuid(const CString& str) {

-  GUID guid(GUID_NULL);

-  if (!str.IsEmpty()) {

-    TCHAR* s = const_cast<TCHAR*>(str.GetString());

-    VERIFY(SUCCEEDED(::CLSIDFromString(s, &guid)), (_T("guid %s"), s));

-  }

-  return guid;

-}

-

-// Helper function to convert a variant containing a list of strings

-void VariantToStringList(VARIANT var, std::vector<CString>* list) {

-  ASSERT1(list);

-

-  list->clear();

-

-  ASSERT1(V_VT(&var) == VT_DISPATCH);

-  CComPtr<IDispatch> obj = V_DISPATCH(&var);

-  ASSERT1(obj);

-

-  CComVariant var_length;

-  VERIFY1(SUCCEEDED(obj.GetPropertyByName(_T("length"), &var_length)));

-  ASSERT1(V_VT(&var_length) == VT_I4);

-  int length = V_I4(&var_length);

-

-  for (int i = 0; i < length; ++i) {

-    CComVariant value;

-    VERIFY1(SUCCEEDED(obj.GetPropertyByName(itostr(i), &value)));

-    if (V_VT(&value) == VT_BSTR) {

-      list->push_back(V_BSTR(&value));

-    } else {

-      ASSERT1(false);

-    }

-  }

-}

-

-

-HRESULT GetCurrentProcessHandle(HANDLE* handle) {

-  ASSERT1(handle);

-  scoped_process real_handle;

-  HANDLE pseudo_handle = ::GetCurrentProcess();

-  bool res = ::DuplicateHandle(

-    pseudo_handle,         // this process pseudo-handle

-    pseudo_handle,         // handle to duplicate

-    pseudo_handle,         // the process receiving the handle

-    address(real_handle),  // this process real handle

-    0,                     // ignored

-    false,                 // don't inherit this handle

-    DUPLICATE_SAME_ACCESS) != 0;

-

-  *handle = NULL;

-  if (!res) {

-    return HRESULTFromLastError();

-  }

-  *handle = release(real_handle);

-  return S_OK;

-}

-

-

-// get a time64 value

-// NOTE: If the value is greater than the

-// max value, then SetValue will be called using the max_value.

-HRESULT GetLimitedTimeValue(const TCHAR* full_key_name, const TCHAR* value_name,

-                            time64 max_time, time64* value,

-                            bool* limited_value) {

-  ASSERT1(full_key_name);

-  ASSERT1(value);

-  STATIC_ASSERT(sizeof(time64) == sizeof(DWORD64));

-

-  if (limited_value) {

-    *limited_value = false;

-  }

-  HRESULT hr = RegKey::GetValue(full_key_name, value_name, value);

-  if (SUCCEEDED(hr) && *value > max_time) {

-    *value = max_time;

-

-    // Use a different hr for the setting of the value b/c

-    // the returned hr should reflect the success/failure of reading the key

-    HRESULT set_value_hr = RegKey::SetValue(full_key_name, value_name, *value);

-    ASSERT(SUCCEEDED(set_value_hr), (_T("[GetLimitedTimeValue - failed ")

-                                     _T("when setting a value][0x%x]"),

-                                     set_value_hr));

-    if (SUCCEEDED(set_value_hr) && limited_value) {

-      *limited_value = true;

-    }

-  }

-  return hr;

-}

-

-// get a time64 value trying reg keys successively if there is a

-// failure in getting a value.

-HRESULT GetLimitedTimeValues(const TCHAR* full_key_names[],

-                             int key_names_length,

-                             const TCHAR* value_name,

-                             time64 max_time,

-                             time64* value,

-                             bool* limited_value) {

-  ASSERT1(full_key_names);

-  ASSERT1(value);

-  ASSERT1(key_names_length > 0);

-

-  HRESULT hr = E_FAIL;

-  for (int i = 0; i < key_names_length; ++i) {

-    hr = GetLimitedTimeValue(full_key_names[i], value_name, max_time, value,

-                             limited_value);

-    if (SUCCEEDED(hr)) {

-      return hr;

-    }

-  }

-  return hr;

-}

-

-// Wininet.dll (and especially the version that comes with IE7, with 01/12/07

-// timestamp) incorrectly initializes Rasman.dll. As a result, there is a race

-// condition that causes double-free on a memory from process heap.

-// This causes memory corruption in the heap that may later produce a variety

-// of ill effects, most frequently a crash with a callstack that contains

-// wininet and rasman, or ntdll!RtlAllocHeap. The root cause is that

-// Rasapi32!LoadRasmanDllAndInit is not thread safe and can start very involved

-// process of initialization on 2 threads at the same time. It's a bug.

-// Solution: in the begining of the program, trigger synchronous load of

-// rasman dll. The easy way is to call a public ras api that does synchronous

-// initialization, which is what we do here.

-void EnsureRasmanLoaded() {

-  RASENTRYNAME ras_entry_name = {0};

-  DWORD size_bytes = sizeof(ras_entry_name);

-  DWORD number_of_entries = 0;

-  ras_entry_name.dwSize = size_bytes;

-  // we don't really need results of this method,

-  // it simply triggers RASAPI32!LoadRasmanDllAndInit() internally.

-  ::RasEnumEntries(NULL,

-                   NULL,

-                   &ras_entry_name,

-                   &size_bytes,

-                   &number_of_entries);

-}

-

-// Appends two reg keys. Handles the situation where there are traling

-// back slashes in one and leading back slashes in two.

-CString AppendRegKeyPath(const CString& one, const CString& two) {

-  CString leftpart(one);

-  int length = leftpart.GetLength();

-  int i = 0;

-  for (i = length - 1; i >= 0; --i) {

-    if (leftpart[i] != _T('\\')) {

-      break;

-    }

-  }

-  leftpart = leftpart.Left(i+1);

-

-  CString rightpart(two);

-  int lengthr = rightpart.GetLength();

-  for (i = 0; i < lengthr; ++i) {

-    if (rightpart[i] != _T('\\')) {

-      break;

-    }

-  }

-  rightpart = rightpart.Right(lengthr - i);

-

-  CString result;

-  result.Format(_T("%s\\%s"), leftpart, rightpart);

-  return result;

-}

-

-CString AppendRegKeyPath(const CString& one, const CString& two,

-                         const CString& three) {

-  CString result = AppendRegKeyPath(one, two);

-  result = AppendRegKeyPath(result, three);

-  return result;

-}

-

-

-HRESULT GetUserKeysFromHkeyUsers(std::vector<CString>* key_names) {

-  ASSERT1(key_names);

-  CORE_LOG(L3, (_T("[GetUserKeysFromHkeyUsers]")));

-

-  TCHAR user_key_name[MAX_PATH] = {0};

-  int i = 0;

-  while (::RegEnumKey(HKEY_USERS, i++, user_key_name, MAX_PATH) !=

-                      ERROR_NO_MORE_ITEMS) {

-        byte sid_buffer[SECURITY_MAX_SID_SIZE] = {0};

-    PSID sid = reinterpret_cast<PSID>(sid_buffer);

-    if (::ConvertStringSidToSid(user_key_name, &sid) != 0) {

-      // We could convert the string SID into a real SID. If not

-      // we just ignore.

-      DWORD size = MAX_PATH;

-      DWORD size_domain = MAX_PATH;

-      SID_NAME_USE sid_type = SidTypeComputer;

-      TCHAR user_name[MAX_PATH] = {0};

-      TCHAR domain_name[MAX_PATH] = {0};

-

-      if (::LookupAccountSid(NULL, sid, user_name, &size,

-                             domain_name, &size_domain, &sid_type) == 0) {

-        HRESULT hr = HRESULTFromLastError();

-        CORE_LOG(LEVEL_WARNING,

-            (_T("[GetUserKeysFromHkeyUsers LookupAccountSid] ")

-             _T(" failed [0x%08x]"),

-             hr));

-        continue;

-      }

-

-      if (sid_type == SidTypeUser) {

-        // Change the RunAs keys for the user goopdates to point to the

-        // machine install.

-        CString user_reg_key_name = AppendRegKeyPath(USERS_KEY, user_key_name);

-        key_names->push_back(user_reg_key_name);

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT IsSystemProcess(bool* is_system_process) {

-  CAccessToken current_process_token;

-  if (!current_process_token.GetProcessToken(TOKEN_QUERY,

-                                             ::GetCurrentProcess())) {

-    HRESULT hr = HRESULTFromLastError();

-    ASSERT(false, (_T("[CAccessToken::GetProcessToken 0x%x]"), hr));

-    return hr;

-  }

-  CSid logon_sid;

-  if (!current_process_token.GetUser(&logon_sid)) {

-    HRESULT hr = HRESULTFromLastError();

-    ASSERT(false, (_T("[CAccessToken::GetUser 0x%x]"), hr));

-    return hr;

-  }

-  *is_system_process = logon_sid == Sids::System();

-  return S_OK;

-}

-

-HRESULT IsUserLoggedOn(bool* is_logged_on) {

-  ASSERT1(is_logged_on);

-  bool is_local_system(false);

-  HRESULT hr = IsSystemProcess(&is_local_system);

-  if (SUCCEEDED(hr) && is_local_system) {

-    *is_logged_on = true;

-    return S_OK;

-  }

-  return UserRights::UserIsLoggedOnInteractively(is_logged_on);

-}

-

-bool IsClickOnceDisabled() {

-  CComPtr<IInternetZoneManager> zone_mgr;

-  HRESULT hr =  zone_mgr.CoCreateInstance(CLSID_InternetZoneManager);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[CreateInstance InternetZoneManager failed][0x%x]"), hr));

-    return true;

-  }

-

-  DWORD policy = URLPOLICY_DISALLOW;

-  size_t policy_size = sizeof(policy);

-  hr = zone_mgr->GetZoneActionPolicy(URLZONE_INTERNET,

-                                     URLACTION_MANAGED_UNSIGNED,

-                                     reinterpret_cast<BYTE*>(&policy),

-                                     policy_size,

-                                     URLZONEREG_DEFAULT);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[GetZoneActionPolicy failed][0x%x]"), hr));

-    return true;

-  }

-

-  return policy == URLPOLICY_DISALLOW;

-}

-

-// This function only uses kernel32, and it is safe to call from DllMain.

-HRESULT PinModuleIntoProcess(const CString& module_name) {

-  ASSERT1(!module_name.IsEmpty());

-  static HMODULE module_handle = NULL;

-  typedef BOOL (WINAPI *Fun)(DWORD flags,

-                             LPCWSTR module_name,

-                             HMODULE* module_handle);

-

-  HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));

-  ASSERT1(kernel_instance);

-  Fun pfn = NULL;

-  if (GPA(kernel_instance, "GetModuleHandleExW", &pfn)) {

-    if ((*pfn)(GET_MODULE_HANDLE_EX_FLAG_PIN, module_name, &module_handle)) {

-      return S_OK;

-    }

-    ASSERT(false, (_T("GetModuleHandleExW() failed [%d]"), ::GetLastError()));

-  }

-

-  module_handle = ::LoadLibrary(module_name);

-  ASSERT(NULL != module_handle, (_T("LoadLibrary [%d]"), ::GetLastError()));

-  if (NULL == module_handle) {

-    return HRESULTFromLastError();

-  }

-

-  return S_OK;

-}

-

-bool ShellExecuteExEnsureParent(LPSHELLEXECUTEINFO shell_exec_info) {

-  UTIL_LOG(L3, (_T("[ShellExecuteExEnsureParent]")));

-

-  ASSERT1(shell_exec_info);

-  bool shell_exec_succeeded(false);

-  DWORD last_error(ERROR_SUCCESS);

-

-  {

-    // hwnd_parent window is destroyed at the end of the scope when the

-    // destructor of scoped_window calls ::DestroyWindow.

-    scoped_window hwnd_parent;

-

-    if (!shell_exec_info->hwnd && vista_util::IsVistaOrLater()) {

-      reset(hwnd_parent, CreateForegroundParentWindowForUAC());

-

-      if (!hwnd_parent) {

-        last_error = ::GetLastError();

-        UTIL_LOG(LE, (_T("[CreateDummyOverlappedWindow failed]")));

-        // Restore last error in case the logging reset it.

-        ::SetLastError(last_error);

-        return false;

-      }

-

-      shell_exec_info->hwnd = get(hwnd_parent);

-

-      // If elevation is required on Vista, call ::SetForegroundWindow(). This

-      // will make sure that the elevation prompt, as well as the elevated

-      // process window comes up in the foreground. It will also ensure that in

-      // the case where the elevation prompt is cancelled, the error dialog

-      // shown from this process comes up in the foreground.

-      if (shell_exec_info->lpVerb &&

-          _tcsicmp(shell_exec_info->lpVerb, _T("runas")) == 0) {

-        if (!::SetForegroundWindow(get(hwnd_parent))) {

-          UTIL_LOG(LW, (_T("[SetForegroundWindow fail %d]"), ::GetLastError()));

-        }

-      }

-    }

-

-    shell_exec_succeeded = !!::ShellExecuteEx(shell_exec_info);

-

-    if (shell_exec_succeeded) {

-      if (shell_exec_info->hProcess) {

-        DWORD pid = Process::GetProcessIdFromHandle(shell_exec_info->hProcess);

-        OPT_LOG(L1, (_T("[Started process][%u]"), pid));

-        if (!::AllowSetForegroundWindow(pid)) {

-          UTIL_LOG(LW, (_T("[AllowSetForegroundWindow %d]"), ::GetLastError()));

-        }

-      } else {

-        OPT_LOG(L1, (_T("[Started process][PID unknown]")));

-      }

-    } else {

-      last_error = ::GetLastError();

-      UTIL_LOG(LE, (_T("[ShellExecuteEx fail][%s][%s][0x%08x]"),

-                    shell_exec_info->lpFile, shell_exec_info->lpParameters,

-                    last_error));

-    }

-  }

-

-  // The implicit ::DestroyWindow call from the scoped_window could have reset

-  // the last error, so restore it.

-  ::SetLastError(last_error);

-

-  return shell_exec_succeeded;

-}

-

-// Loads and unloads advapi32.dll for every call. If performance is an issue

-// consider keeping the dll always loaded and holding the pointer to the

-// RtlGenRandom in a static variable.

-// Use the function with care. While the function is documented, it may be

-// altered or made unavailable in future versions of the operating system.

-bool GenRandom(void* buffer, size_t buffer_length) {

-  ASSERT1(buffer);

-  scoped_library lib(::LoadLibrary(_T("ADVAPI32.DLL")));

-  if (lib) {

-    typedef BOOLEAN (APIENTRY *RtlGenRandomType)(void*, ULONG);

-    RtlGenRandomType rtl_gen_random = reinterpret_cast<RtlGenRandomType>(

-        ::GetProcAddress(get(lib), "SystemFunction036"));

-    return rtl_gen_random && rtl_gen_random(buffer, buffer_length);

-  }

-

-  // Use CAPI to generate randomness for systems which do not support

-  // RtlGenRandomType, for instance Windows 2000.

-  const uint32 kCspFlags = CRYPT_VERIFYCONTEXT | CRYPT_SILENT;

-  HCRYPTPROV csp = NULL;

-  if (::CryptAcquireContext(&csp, NULL, NULL, PROV_RSA_FULL, kCspFlags)) {

-    if (::CryptGenRandom(csp, buffer_length, static_cast<BYTE*>(buffer))) {

-      return true;

-    }

-  }

-  VERIFY1(::CryptReleaseContext(csp, 0));

-  return false;

-}

-

-// Assumes the path in command is properly enclosed if necessary.

-HRESULT ConfigureRunAtStartup(const CString& root_key_name,

-                              const CString& run_value_name,

-                              const CString& command,

-                              bool install) {

-  UTIL_LOG(L3, (_T("ConfigureRunAtStartup")));

-

-  const CString key_path = AppendRegKeyPath(root_key_name, REGSTR_PATH_RUN);

-  HRESULT hr(S_OK);

-

-  if (install) {

-    hr = RegKey::SetValue(key_path, run_value_name, command);

-  } else {

-    hr = RegKey::DeleteValue(key_path, run_value_name);

-  }

-

-  return hr;

-}

-

-HRESULT GetExePathFromCommandLine(const TCHAR* command_line,

-                                  CString* exe_path) {

-  ASSERT1(exe_path);

-  CString command_line_str(command_line);

-  command_line_str.Trim(_T(' '));

-  if (command_line_str.IsEmpty()) {

-    // ::CommandLineToArgvW parses the current process command line for blank

-    // strings. We do not want this behavior.

-    return E_INVALIDARG;

-  }

-

-  int argc = 0;

-  wchar_t** argv = ::CommandLineToArgvW(command_line_str, &argc);

-  if (argc == 0 || !argv) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LE, (_T("[::CommandLineToArgvW failed][0x%x]"), hr));

-    return hr;

-  }

-

-  *exe_path = argv[0];

-  ::LocalFree(argv);

-  exe_path->Trim(_T(' '));

-  ASSERT1(!exe_path->IsEmpty());

-  return S_OK;

-}

-

-// Tries to open the _MSIExecute mutex and tests its state. MSI sets the

-// mutex when processing sequence tables. This indicates MSI is busy.

-// The function returns S_OK if the mutex is not owned by MSI or the mutex has

-// not been created.

-HRESULT WaitForMSIExecute(int timeout_ms) {

-  const TCHAR* mutex_name = _T("Global\\_MSIExecute");

-  scoped_mutex mutex(::OpenMutex(SYNCHRONIZE, false, mutex_name));

-  if (!mutex) {

-    DWORD error = ::GetLastError();

-    return (error == ERROR_FILE_NOT_FOUND) ? S_OK : HRESULT_FROM_WIN32(error);

-  }

-  UTIL_LOG(L3, (_T("[Wait for _MSIExecute]")));

-  switch (::WaitForSingleObject(get(mutex), timeout_ms)) {

-    case WAIT_OBJECT_0:

-    case WAIT_ABANDONED:

-      VERIFY1(::ReleaseMutex(get(mutex)));

-      return S_OK;

-    case WAIT_TIMEOUT:

-      return HRESULT_FROM_WIN32(ERROR_TIMEOUT);

-    case WAIT_FAILED:

-      return HRESULTFromLastError();

-    default:

-      return E_FAIL;

-  }

-}

-

-CString GetEnvironmentVariableAsString(const TCHAR* name) {

-  CString value;

-  size_t value_length = ::GetEnvironmentVariable(name, NULL, 0);

-  if (value_length) {

-    VERIFY1(::GetEnvironmentVariable(name,

-                                     CStrBuf(value, value_length),

-                                     value_length));

-  }

-  return value;

-}

-

-// States are documented at

-// http://technet.microsoft.com/en-us/library/cc721913.aspx.

-bool IsWindowsInstalling() {

-  static const TCHAR kVistaSetupStateKey[] =

-      _T("Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\State");

-  static const TCHAR kImageStateValueName[] = _T("ImageState");

-  static const TCHAR kImageStateUnuseableValue[] =

-      _T("IMAGE_STATE_UNDEPLOYABLE");

-  static const TCHAR kImageStateGeneralAuditValue[] =

-      _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_AUDIT");

-  static const TCHAR kImageStateSpecialAuditValue[] =

-      _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_AUDIT");

-

-  static const TCHAR kXPSetupStateKey[] = _T("System\\Setup");

-  static const TCHAR kAuditFlagValueName[] = _T("AuditInProgress");

-

-  if (vista_util::IsVistaOrLater()) {

-    RegKey vista_setup_key;

-    HRESULT hr =

-        vista_setup_key.Open(HKEY_LOCAL_MACHINE, kVistaSetupStateKey, KEY_READ);

-    if (SUCCEEDED(hr)) {

-      CString state;

-      hr = vista_setup_key.GetValue(kImageStateValueName, &state);

-      if (SUCCEEDED(hr) &&

-          !state.IsEmpty() &&

-          (0 == state.CompareNoCase(kImageStateUnuseableValue) ||

-           0 == state.CompareNoCase(kImageStateGeneralAuditValue) ||

-           0 == state.CompareNoCase(kImageStateSpecialAuditValue)))

-        return true;  // Vista is still installing.

-    }

-  } else {

-    RegKey xp_setup_key;

-    HRESULT hr =

-        xp_setup_key.Open(HKEY_LOCAL_MACHINE, kXPSetupStateKey, KEY_READ);

-    if (SUCCEEDED(hr)) {

-      DWORD audit_flag(0);

-      hr = xp_setup_key.GetValue(kAuditFlagValueName, &audit_flag);

-      if (SUCCEEDED(hr) && 0 != audit_flag)

-        return true;  // XP is still installing.

-    }

-  }

-  return false;

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/utils.h"
+
+#include <ras.h>
+#include <regstr.h>
+#include <urlmon.h>
+#include <wincrypt.h>
+#include <ATLComTime.h>
+#include <atlpath.h>
+#include <map>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/const_config.h"
+#include "omaha/common/const_timeouts.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/process.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/shell.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/time.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/user_rights.h"
+#include "omaha/common/vistautil.h"
+
+namespace omaha {
+
+namespace {
+
+// Private object namespaces for Vista processes.
+const TCHAR* const kGoopdateBoundaryDescriptor = _T("GoogleUpdate_BD");
+const TCHAR* const kGoopdatePrivateNamespace = _T("GoogleUpdate");
+const TCHAR* const kGoopdatePrivateNamespacePrefix = _T("GoogleUpdate\\");
+
+// Helper for IsPrivateNamespaceAvailable().
+// For simplicity, the handles opened here are leaked. We need these until
+// process exit, at which point they will be cleaned up automatically by the OS.
+bool EnsurePrivateNamespaceAvailable() {
+  HANDLE boundary_descriptor =
+      CreateBoundaryDescriptorWWrap(kGoopdateBoundaryDescriptor, 0);
+  if (NULL == boundary_descriptor) {
+    DWORD last_error(::GetLastError());
+    UTIL_LOG(LE, (_T("CreateBoundaryDescriptor failed[%d]"), last_error));
+    return false;
+  }
+
+  char sid[SECURITY_MAX_SID_SIZE] = {0};
+  DWORD size = sizeof(sid);
+  // Mark the boundary descriptor with the Admins Group SID. Consequently, all
+  // admins, including SYSTEM, will create objects in the same private
+  // namespace.
+  if (!::CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, sid, &size)) {
+    DWORD last_error(::GetLastError());
+    UTIL_LOG(LE, (_T("::CreateWellKnownSid failed[%d]"), last_error));
+    return false;
+  }
+  if (!AddSIDToBoundaryDescriptorWrap(&boundary_descriptor, sid)) {
+    DWORD last_error(::GetLastError());
+    UTIL_LOG(LE, (_T("AddSIDToBoundaryDescriptor fail[%d]"), last_error));
+    return false;
+  }
+
+  NamedObjectAttributes attr;
+  GetAdminDaclSecurityAttributes(&attr.sa, GENERIC_ALL);
+  // The private namespace created here will be used to create objects of the
+  // form "GoogleUpdate\xyz". As the article "Object Namespaces" on MSDN
+  // explains, these kernel objects are safe from squatting attacks from lower
+  // integrity processes.
+  HANDLE namespace_handle =
+      CreatePrivateNamespaceWWrap(&attr.sa,
+                                  boundary_descriptor,
+                                  kGoopdatePrivateNamespace);
+  if (namespace_handle) {
+    return true;
+  }
+  ASSERT(ERROR_ALREADY_EXISTS == ::GetLastError(),
+         (_T("CreatePrivateNamespaceW failed. %d"), ::GetLastError()));
+
+  // Another process has already created the namespace. Attempt to open.
+  namespace_handle = OpenPrivateNamespaceWWrap(boundary_descriptor,
+                                               kGoopdatePrivateNamespace);
+  if (namespace_handle || ::GetLastError() == ERROR_DUP_NAME) {
+    // ERROR_DUP_NAME indicates that we have called CreatePrivateNamespaceWWrap
+    // or OpenPrivateNamespaceWWrap before in the same process. Either way, we
+    // can now create objects prefixed with our private namespace.
+    return true;
+  }
+
+  ASSERT(namespace_handle, (_T("[Could not open private namespace][%d]"),
+                            ::GetLastError()));
+  return false;
+}
+
+}  // namespace
+
+// Returns 0 if an error occurs.
+ULONGLONG VersionFromString(const CString& s) {
+  int pos(0);
+  unsigned int quad[4] = {0, 0, 0, 0};
+
+  for (int i = 0; i < 4; ++i) {
+    CString q = s.Tokenize(_T("."), pos);
+    if (pos == -1) {
+      return 0;
+    }
+
+    int quad_value(0);
+    if (!String_StringToDecimalIntChecked(q, &quad_value)) {
+      return 0;
+    }
+
+    quad[i] = static_cast<unsigned int>(quad_value);
+
+    if (kuint16max < quad[i]) {
+      return 0;
+    }
+  }
+
+  if (s.GetLength() + 1 != pos) {
+    return 0;
+  }
+
+  return MAKEDLLVERULL(quad[0], quad[1], quad[2], quad[3]);
+}
+
+CString StringFromVersion(ULONGLONG version) {
+  const WORD version_major = HIWORD(version >> 32);
+  const WORD version_minor = LOWORD(version >> 32);
+  const WORD version_build = HIWORD(version);
+  const WORD version_patch = LOWORD(version);
+
+  CString version_string;
+  version_string.Format((_T("%u.%u.%u.%u")),
+                        version_major,
+                        version_minor,
+                        version_build,
+                        version_patch);
+  return version_string;
+}
+
+CString GetCurrentDir() {
+  TCHAR cur_dir[MAX_PATH] = {0};
+  if (!::GetCurrentDirectory(MAX_PATH, cur_dir)) {
+    return CString(_T('.'));
+  }
+  return CString(cur_dir);
+}
+
+HRESULT GetNewFileNameInDirectory(const CString& dir, CString* file_name) {
+  ASSERT1(file_name);
+
+  GUID guid = {0};
+  HRESULT hr = ::CoCreateGuid(&guid);
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_WARNING, (_T("[CoCreateGuid failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  CString guid_file_name = GuidToString(guid);
+  CPath file_path(dir);
+  file_path.Append(guid_file_name);
+
+  *file_name = static_cast<const TCHAR*>(file_path);
+  return S_OK;
+}
+
+// determines if a time is in the distant past, present, or future
+TimeCategory GetTimeCategory(const time64 system_time) {
+  time64 now = GetCurrent100NSTime();
+
+  // Times more than a few days in the future are wrong [I will allow a little
+  // leeway, since it could be set in another future time zone, or a program
+  // that likes UNC]]
+  if (system_time > (now + kDaysTo100ns * 5)) {
+    return FUTURE;
+  }
+
+  // times more than 40 years ago are wrong
+  if (system_time < (now - kDaysTo100ns * 365 * 40)) {
+    return PAST;
+  }
+
+  return PRESENT;
+}
+
+// Determine if a given time is probably valid
+bool IsValidTime(const time64 t) {
+  return (GetTimeCategory(t) == PRESENT);
+}
+
+LARGE_INTEGER MSto100NSRelative(DWORD ms) {
+  const __int64 convert_ms_to_100ns_units = 1000 /*ms/us*/ * 10 /*us/100ns*/;
+  __int64 timeout_100ns = static_cast<__int64>(ms) * convert_ms_to_100ns_units;
+  LARGE_INTEGER timeout = {0};
+  timeout.QuadPart = -timeout_100ns;
+  return timeout;
+}
+
+// Use of this method is unsafe. Be careful!
+// Local System and admins get GENERIC_ALL access. Authenticated non-admins get
+// non_admin_access_mask access.
+void GetEveryoneDaclSecurityAttributes(CSecurityAttributes* sec_attr,
+                                       ACCESS_MASK non_admin_access_mask) {
+  ASSERT1(sec_attr);
+
+  // Grant access to all users.
+  CDacl dacl;
+  dacl.AddAllowedAce(Sids::System(), GENERIC_ALL);
+  dacl.AddAllowedAce(Sids::Admins(), GENERIC_ALL);
+  dacl.AddAllowedAce(Sids::Interactive(), non_admin_access_mask);
+
+  CSecurityDesc security_descriptor;
+  security_descriptor.SetDacl(dacl);
+  security_descriptor.MakeAbsolute();
+
+  sec_attr->Set(security_descriptor);
+}
+
+void GetAdminDaclSecurityAttributes(CSecurityAttributes* sec_attr,
+                                    ACCESS_MASK accessmask) {
+  ASSERT1(sec_attr);
+  CDacl dacl;
+  dacl.AddAllowedAce(Sids::System(), accessmask);
+  dacl.AddAllowedAce(Sids::Admins(), accessmask);
+
+  CSecurityDesc security_descriptor;
+  security_descriptor.SetOwner(Sids::Admins());
+  security_descriptor.SetGroup(Sids::Admins());
+  security_descriptor.SetDacl(dacl);
+  security_descriptor.MakeAbsolute();
+
+  sec_attr->Set(security_descriptor);
+}
+
+// This function is not thread-safe.
+bool IsPrivateNamespaceAvailable(bool is_machine) {
+  static bool is_initialized = false;
+  static bool is_available = false;
+
+  if (!is_machine) {
+    // TODO(Omaha): From a security viewpoint, private namespaces do not add
+    // much value for the User Omaha. But from a uniformity perspective, makes
+    // sense to use for both.
+    return false;
+  }
+
+  if (is_initialized) {
+    return is_available;
+  }
+
+  if (!SystemInfo::IsRunningOnVistaOrLater()) {
+    is_available = false;
+    is_initialized = true;
+    return false;
+  }
+
+  is_available = EnsurePrivateNamespaceAvailable();
+  is_initialized = true;
+  return is_available;
+}
+
+
+void GetNamedObjectAttributes(const TCHAR* base_name,
+                              bool is_machine,
+                              NamedObjectAttributes* attr) {
+  ASSERT1(base_name);
+  ASSERT1(attr);
+
+  // TODO(Omaha): Enable this code after we have a better understanding of
+  // Private Object Namespaces.
+#if 0
+  if (IsPrivateNamespaceAvailable(is_machine)) {
+    attr->name = kGoopdatePrivateNamespacePrefix;
+  } else {
+    ASSERT1(!SystemInfo::IsRunningOnVistaOrLater());
+#endif
+
+  attr->name = omaha::kGlobalPrefix;
+
+  if (!is_machine) {
+    CString user_sid;
+    VERIFY1(SUCCEEDED(omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid)));
+    attr->name += user_sid;
+  } else {
+    // Grant access to administrators and system.
+    GetAdminDaclSecurityAttributes(&attr->sa, GENERIC_ALL);
+  }
+
+  attr->name += base_name;
+  UTIL_LOG(L1, (_T("[GetNamedObjectAttributes][named_object=%s]"), attr->name));
+}
+
+// For now, required_ace_flags is only supported for SE_REGISTRY_KEY objects.
+// INHERITED_ACE may be added to the read ACE flags, so it is excluded from
+// the comparison with required_ace_flags.
+HRESULT AddAllowedAce(const TCHAR* object_name,
+                      SE_OBJECT_TYPE object_type,
+                      const CSid& sid,
+                      ACCESS_MASK required_permissions,
+                      uint8 required_ace_flags) {
+  ASSERT1(SE_REGISTRY_KEY == object_type || !required_ace_flags);
+  ASSERT1(0 == (required_ace_flags & INHERITED_ACE));
+
+  CDacl dacl;
+  if (!AtlGetDacl(object_name, object_type, &dacl)) {
+    return HRESULTFromLastError();
+  }
+
+  int ace_count = dacl.GetAceCount();
+  for (int i = 0; i < ace_count; ++i) {
+    CSid sid_entry;
+    ACCESS_MASK existing_permissions = 0;
+    BYTE existing_ace_flags = 0;
+    dacl.GetAclEntry(i,
+                     &sid_entry,
+                     &existing_permissions,
+                     NULL,
+                     &existing_ace_flags);
+    if (sid_entry == sid &&
+        required_permissions == (existing_permissions & required_permissions) &&
+        required_ace_flags == (existing_ace_flags & ~INHERITED_ACE)) {
+      return S_OK;
+    }
+  }
+
+  if (!dacl.AddAllowedAce(sid, required_permissions, required_ace_flags) ||
+      !AtlSetDacl(object_name, object_type, dacl)) {
+    return HRESULTFromLastError();
+  }
+
+  return S_OK;
+}
+
+HRESULT CreateDir(const TCHAR* in_dir,
+                  LPSECURITY_ATTRIBUTES security_attr) {
+  ASSERT1(in_dir);
+  CString path;
+  if (!PathCanonicalize(CStrBuf(path, MAX_PATH), in_dir)) {
+    return E_FAIL;
+  }
+  // Standardize path on backslash so Find works.
+  path.Replace(_T('/'), _T('\\'));
+  int next_slash = path.Find(_T('\\'));
+  while (true) {
+    int len = 0;
+    if (next_slash == -1) {
+      len = path.GetLength();
+    } else {
+      len = next_slash;
+    }
+    CString dir(path.Left(len));
+    // The check for File::Exists should not be needed. However in certain
+    // cases, i.e. when the program is run from a n/w drive or from the
+    // root drive location, the first CreateDirectory fails with an
+    // E_ACCESSDENIED instead of a ALREADY_EXISTS. Hence we protect the call
+    // with the exists.
+    if (!File::Exists(dir)) {
+      if (!::CreateDirectory(dir, security_attr)) {
+        DWORD error = ::GetLastError();
+        if (ERROR_FILE_EXISTS != error && ERROR_ALREADY_EXISTS != error) {
+          return HRESULT_FROM_WIN32(error);
+        }
+      }
+    }
+    if (next_slash == -1) {
+      break;
+    }
+    next_slash = path.Find(_T('\\'), next_slash + 1);
+  }
+
+  return S_OK;
+}
+
+HRESULT GetFolderPath(int csidl, CString* path) {
+  if (!path) {
+    return E_INVALIDARG;
+  }
+
+  TCHAR buffer[MAX_PATH] = {0};
+  HRESULT hr = ::SHGetFolderPath(NULL, csidl, NULL, SHGFP_TYPE_CURRENT, buffer);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  *path = buffer;
+  return S_OK;
+}
+
+// Delete directory files. If failed, try to schedule deletion at next reboot
+HRESULT DeleteDirectoryFiles(const TCHAR* dir_name) {
+  ASSERT1(dir_name);
+  return DeleteWildcardFiles(dir_name, _T("*"));
+}
+
+// Delete a set of wildcards within dir_name.
+// If unable to delete immediately, try to schedule deletion at next reboot
+HRESULT DeleteWildcardFiles(const TCHAR* dir_name, const TCHAR* wildcard_name) {
+  ASSERT1(dir_name);
+  ASSERT1(wildcard_name);
+
+  HRESULT hr = S_OK;
+
+  WIN32_FIND_DATA find_data;
+  SetZero(find_data);
+
+  CString find_file(dir_name);
+  find_file += _T('\\');
+  find_file += wildcard_name;
+
+  scoped_hfind hfind(::FindFirstFile(find_file, &find_data));
+  if (!hfind) {
+    if (::GetLastError() == ERROR_NO_MORE_FILES) {
+      return S_OK;
+    } else {
+      hr = HRESULTFromLastError();
+      UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")
+                             _T("[failed to get first file][0x%x]"), hr));
+      return hr;
+    }
+  }
+
+  do {
+    if (!(find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+      CString specific_file_name(dir_name);
+      specific_file_name += _T('\\');
+      specific_file_name += find_data.cFileName;
+      if (!::DeleteFile(specific_file_name)) {
+        if (!SUCCEEDED(hr = File::DeleteAfterReboot(specific_file_name))) {
+          UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")
+                                 _T("[failed to delete after reboot]")
+                                 _T("[%s][0x%x]"), specific_file_name, hr));
+        }
+      }
+    }
+  } while (::FindNextFile(get(hfind), &find_data));
+
+  if (::GetLastError() != ERROR_NO_MORE_FILES) {
+    hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[DeleteWildcardFiles]")
+                           _T("[failed to get next file][0x%x]"), hr));
+  }
+
+  return hr;
+}
+
+// Delete directory and files within. If failed, try to schedule deletion at
+// next reboot
+// TODO(Omaha) - the code to delete the directory is complicated,
+// especially the way the result code is built from hr and hr1. I wonder if we
+// could simplify this by reimplementing it on top of SHFileOperation and
+// also save a few tens of bytes in the process.
+HRESULT DeleteDirectory(const TCHAR* dir_name) {
+  ASSERT1(dir_name);
+
+  if (!SafeDirectoryNameForDeletion(dir_name)) {
+    return E_FAIL;
+  }
+
+  // Make sure the directory exists (it is ok if it doesn't)
+  DWORD dir_attributes = ::GetFileAttributes(dir_name);
+  if (dir_attributes == INVALID_FILE_ATTRIBUTES) {
+    if (::GetLastError() == ERROR_FILE_NOT_FOUND)
+      return S_OK;  // Ok if directory is missing
+    else
+      return HRESULTFromLastError();
+  }
+  // Confirm it is a directory
+  if (!(dir_attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+    return E_FAIL;
+  }
+
+  // Try to delete all files at best effort
+  // Return the first HRESULT error encountered
+
+  // First delete all the normal files
+  HRESULT hr = DeleteDirectoryFiles(dir_name);
+
+  // Recursively delete any subdirectories
+
+  WIN32_FIND_DATA find_data = {0};
+
+  CString find_file(dir_name);
+  find_file += _T("\\*");
+
+  // Note that the follows are enclosed in a block because we need to close the
+  // find handle before deleting the directorty itself
+  {
+    scoped_hfind hfind(::FindFirstFile(find_file, &find_data));
+    if (!hfind) {
+      if (::GetLastError() == ERROR_NO_MORE_FILES) {
+        return hr;
+      } else {
+        HRESULT hr1 = HRESULTFromLastError();
+        UTIL_LOG(LEVEL_ERROR, (_T("[DeleteDirectory]")
+                               _T("[failed to get first file][0x%x]"), hr1));
+        return SUCCEEDED(hr) ? hr1 : hr;
+      }
+    }
+
+    do {
+      if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+        if (String_StrNCmp(find_data.cFileName, _T("."), 2, false) == 0 ||
+            String_StrNCmp(find_data.cFileName, _T(".."), 3, false) == 0) {
+          continue;
+        }
+
+        CString sub_dir(dir_name);
+        sub_dir += _T("\\");
+        sub_dir += find_data.cFileName;
+        HRESULT hr1 = DeleteDirectory(sub_dir);
+        if (SUCCEEDED(hr) && FAILED(hr1)) {
+          hr = hr1;
+        }
+      }
+    }
+    while (::FindNextFile(get(hfind), &find_data));
+  }
+
+  // Delete the empty directory itself
+  if (!::RemoveDirectory(dir_name)) {
+    HRESULT hr1 = E_FAIL;
+    if (FAILED(hr1 = File::DeleteAfterReboot(dir_name))) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[DeleteDirectory]")
+                             _T("[failed to delete after reboot]")
+                             _T("[%s][0x%x]"), dir_name, hr1));
+    }
+
+    if (SUCCEEDED(hr) && FAILED(hr1)) {
+      hr = hr1;
+    }
+  }
+
+  return hr;
+}
+
+// Returns true if this directory name is 'safe' for deletion (doesn't contain
+// "..", doesn't specify a drive root)
+bool SafeDirectoryNameForDeletion(const TCHAR* dir_name) {
+  ASSERT1(dir_name);
+
+  // empty name isn't allowed
+  if (!(dir_name && *dir_name)) {
+    return false;
+  }
+
+  // require a character other than \/:. after the last :
+  // disallow anything with ".."
+  bool ok = false;
+  for (const TCHAR* s = dir_name; *s; ++s) {
+    if (*s != _T('\\') && *s != _T('/') && *s != _T(':') && *s != _T('.')) {
+      ok = true;
+    }
+    if (*s == _T('.') && s > dir_name && *(s-1) == _T('.')) {
+      return false;
+    }
+    if (*s == _T(':')) {
+      ok = false;
+    }
+  }
+  return ok;
+}
+
+// Utility function that deletes either a file or directory,
+// before or after reboot
+HRESULT DeleteBeforeOrAfterReboot(const TCHAR* targetname) {
+  if (!File::Exists(targetname)) {
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+
+  HRESULT hr = E_FAIL;
+  if (File::IsDirectory(targetname)) {
+    // DeleteDirectory will schedule deletion at next reboot if it cannot delete
+    // immediately.
+    hr = DeleteDirectory(targetname);
+  } else  {
+    hr = File::Remove(targetname);
+    // If failed, schedule deletion at next reboot
+    if (FAILED(hr)) {
+      UTIL_LOG(L1, (_T("[DeleteBeforeOrAfterReboot]")
+                    _T("[trying to delete %s after reboot]"), targetname));
+      hr = File::DeleteAfterReboot(targetname);
+    }
+  }
+
+  if (FAILED(hr)) {
+    UTIL_LOG(L1, (_T("[DeleteBeforeOrAfterReboot]")
+                  _T("[failed to delete %s]"), targetname));
+  }
+
+  return hr;
+}
+
+
+// Internal implementation of the safe version of getting size of all files in
+// a directory. It is able to abort the counting if one of the maximum criteria
+// is reached.
+HRESULT InternalSafeGetDirectorySize(const TCHAR* dir_name,
+                                     uint64* size,
+                                     HANDLE shutdown_event,
+                                     uint64 max_size,
+                                     int curr_file_count,
+                                     int max_file_count,
+                                     int curr_depth,
+                                     int max_depth,
+                                     DWORD end_time_ms) {
+  ASSERT1(dir_name && *dir_name);
+  ASSERT1(size);
+
+  CString dir_find_name = String_MakeEndWith(dir_name, _T("\\"), false);
+  dir_find_name += _T("*");
+  WIN32_FIND_DATA find_data = {0};
+  scoped_hfind hfind(::FindFirstFile(dir_find_name, &find_data));
+  if (!hfind) {
+    return ::GetLastError() == ERROR_NO_MORE_FILES ? S_OK :
+                                                     HRESULTFromLastError();
+  }
+
+  do {
+    // Bail out if shutting down
+    if (shutdown_event && IsHandleSignaled(shutdown_event)) {
+      return E_ABORT;
+    }
+
+    // Bail out if reaching maximum running time
+    if (end_time_ms && ::GetTickCount() >= end_time_ms) {
+      UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")
+                    _T("[reaching max running time][%s][%u]"),
+                    dir_name, end_time_ms));
+      return E_ABORT;
+    }
+
+    // Skip reparse point since it might be a hard link which could cause an
+    // infinite recursive directory loop.
+    if (find_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+      continue;
+    }
+
+    if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+      // Skip . and ..
+      if (String_StrNCmp(find_data.cFileName, _T("."), 2, false) == 0 ||
+          String_StrNCmp(find_data.cFileName, _T(".."), 3, false) == 0) {
+        continue;
+      }
+
+      // Bail out if reaching maximum depth
+      if (max_depth && curr_depth + 1 >= max_depth) {
+        UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")
+                      _T("[reaching max depth][%s][%u]"), dir_name, max_depth));
+        return E_ABORT;
+      }
+
+      // Walk over sub-directory
+      CString sub_dir_name = String_MakeEndWith(dir_name, _T("\\"), false);
+      sub_dir_name += find_data.cFileName;
+      RET_IF_FAILED(InternalSafeGetDirectorySize(sub_dir_name,
+                                                 size,
+                                                 shutdown_event,
+                                                 max_size,
+                                                 curr_file_count,
+                                                 max_file_count,
+                                                 curr_depth + 1,
+                                                 max_depth,
+                                                 end_time_ms));
+    } else {
+      // Bail out if reaching maximum number of files
+      ++curr_file_count;
+      if (max_file_count && curr_file_count >= max_file_count) {
+        UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")
+                      _T("[reaching max file count][%s][%u]"),
+                      dir_name, max_file_count));
+        return E_ABORT;
+      }
+
+      // Count the file size
+      uint64 file_size =
+          ((static_cast<uint64>((find_data.nFileSizeHigh)) << 32)) +
+          static_cast<uint64>(find_data.nFileSizeLow);
+      *size += file_size;
+
+      // Bail out if reaching maximum size
+      if (max_size && *size >= max_size) {
+        UTIL_LOG(L6, (_T("[InternalSafeGetDirectorySize]")
+                      _T("[reaching max size][%s][%u]"), dir_name, max_size));
+        return E_ABORT;
+      }
+    }
+  } while (::FindNextFile(get(hfind), &find_data));
+
+  return ::GetLastError() == ERROR_NO_MORE_FILES ? S_OK :
+                                                   HRESULTFromLastError();
+}
+
+// The safe version of getting size of all files in a directory
+// It is able to abort the counting if one of the maximum criteria is reached
+HRESULT SafeGetDirectorySize(const TCHAR* dir_name,
+                             uint64* size,
+                             HANDLE shutdown_event,
+                             uint64 max_size,
+                             int max_file_count,
+                             int max_depth,
+                             int max_running_time_ms) {
+  ASSERT1(dir_name && *dir_name);
+  ASSERT1(size);
+
+  *size = 0;
+
+  DWORD end_time = 0;
+  if (max_running_time_ms > 0) {
+    end_time = ::GetTickCount() + max_running_time_ms;
+  }
+  return InternalSafeGetDirectorySize(dir_name,
+                                      size,
+                                      shutdown_event,
+                                      max_size,
+                                      0,
+                                      max_file_count,
+                                      0,
+                                      max_depth,
+                                      end_time);
+}
+
+// Get size of all files in a directory
+HRESULT GetDirectorySize(const TCHAR* dir_name, uint64* size) {
+  ASSERT1(dir_name && *dir_name);
+  ASSERT1(size);
+  return SafeGetDirectorySize(dir_name, size, NULL, 0, 0, 0, 0);
+}
+
+// Handles the logic to determine the handle that was signaled
+// as a result of calling *WaitForMultipleObjects.
+HRESULT GetSignaledObjectPosition(uint32 cnt, DWORD res, uint32* pos) {
+  ASSERT1(pos);
+
+  if (res == WAIT_FAILED) {
+    return S_FALSE;
+  }
+
+#pragma warning(disable : 4296)
+  // C4296: '>=' : expression is always true
+  if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cnt)) {
+    *pos = res - WAIT_OBJECT_0;
+    return S_OK;
+  }
+#pragma warning(default : 4296)
+
+  if ((res >= WAIT_ABANDONED_0) && (res < WAIT_ABANDONED_0 + cnt)) {
+    *pos = res - WAIT_ABANDONED_0;
+    return S_OK;
+  }
+  return E_INVALIDARG;
+}
+
+// Supports all of the other WaitWithMessage* functions.
+//
+// Returns:
+//    S_OK when the message loop should continue.
+//    S_FALSE when it receives something that indicates the
+//      loop should quit.
+//    E_* only when GetMessage failed
+//
+// This function is not exposed outside of this file.  Only
+// friendly wrappers of it are.
+HRESULT WaitWithMessageLoopAnyInternal(
+    const HANDLE* phandles,
+    uint32 cnt,
+    uint32* pos,
+    MessageHandlerInternalInterface* message_handler) {
+  ASSERT1(pos && message_handler);
+  // cnt and phandles are either both zero or both not zero.
+  ASSERT1(!cnt == !phandles);
+
+  // Loop until an error happens or the wait is satisfied by a signaled
+  // object or an abandoned mutex.
+  for (;;) {
+    MSG msg = {0};
+
+    // Process the messages in the input queue.
+    while (::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE)) {
+      BOOL ret = false;
+      if ((ret = ::GetMessage(&msg, NULL, 0, 0)) != 0) {
+        if (ret == -1) {
+          HRESULT hr = HRESULTFromLastError();
+          UTIL_LOG(LEVEL_ERROR,
+              (_T("[WaitWithMessageLoopAny - GetMessage failed][0x%08x]"), hr));
+          return hr;
+        }
+        message_handler->Process(&msg, &phandles, &cnt);
+      } else {
+        // We need to re-post the quit message we retrieved so that it could
+        // propagate to the outer layer. Otherwise, the program will seem to
+        // "get stuck" in its shutdown code.
+        ::PostQuitMessage(msg.wParam);
+        return S_FALSE;
+      }
+
+      // WaitForMultipleObjects fails if cnt == 0.
+      if (cnt) {
+        // Briefly check the state of the handle array to see if something
+        // has signaled as we processed a message.
+        ASSERT1(phandles);
+        DWORD res = ::WaitForMultipleObjects(cnt, phandles, false, 0);
+        ASSERT1(res != WAIT_FAILED);
+        HRESULT hr = GetSignaledObjectPosition(cnt, res, pos);
+        if (SUCCEEDED(hr)) {
+          return hr;
+        }
+      }
+    }
+
+    // The wait with message. It is satisfied by either the objects getting
+    // signaled or when messages enter the message queue.
+    // TODO(omaha): implementing timeout is a little bit tricky since we
+    // want the timeout on the handles only and the native API does not
+    // have this semantic.
+    //
+    // TODO(omaha): use a waitable timer to implement the timeout.
+    //
+    // When cnt is zero then the execution flow waits here until messages
+    // arrive in the input queue. Unlike WaitForMultipleObjects,
+    // MsgWaitForMultipleObjects does not error out when cnt == 0.
+    const DWORD timeout = INFINITE;
+    DWORD res(::MsgWaitForMultipleObjects(cnt, phandles, false, timeout,
+                                          QS_ALLINPUT));
+    ASSERT((res != WAIT_FAILED),
+           (_T("[MsgWaitForMultipleObjects returned WAIT_FAILED][%u]"),
+            ::GetLastError()));
+
+    ASSERT1(res != WAIT_TIMEOUT);
+
+    HRESULT hr = GetSignaledObjectPosition(cnt, res, pos);
+    if (SUCCEEDED(hr)) {
+      return hr;
+    }
+  }
+}
+
+// The simplest implementation of a message processor
+void BasicMessageHandler::Process(MSG* msg) {
+  ASSERT1(msg);
+  ::TranslateMessage(msg);
+  ::DispatchMessage(msg);
+}
+
+class BasicMessageHandlerInternal : public BasicMessageHandler,
+                                    public MessageHandlerInternalInterface {
+ public:
+  BasicMessageHandlerInternal() {}
+  virtual void Process(MSG* msg, const HANDLE**, uint32*) {
+    BasicMessageHandler::Process(msg);
+  }
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(BasicMessageHandlerInternal);
+};
+
+
+bool WaitWithMessageLoopAny(const std::vector<HANDLE>& handles, uint32* pos) {
+  BasicMessageHandlerInternal msg_handler;
+  return WaitWithMessageLoopAnyInternal(&handles.front(), handles.size(), pos,
+                                        &msg_handler) != S_FALSE;
+}
+
+bool WaitWithMessageLoopAll(const std::vector<HANDLE>& handles) {
+  // make a copy of the vector, as objects must be removed from the
+  // wait array as they get signaled.
+  std::vector<HANDLE> h(handles);
+
+  // The function is mainly implemented in terms of WaitWithMessageLoopAny
+
+  // loop until all objects are signaled.
+  while (!h.empty()) {
+    uint32 pos(static_cast<uint32>(-1));
+    if (!WaitWithMessageLoopAny(h, &pos)) return false;
+    ASSERT1(pos < h.size());
+    h.erase(h.begin() + pos);   // remove the signaled object and loop
+  }
+
+  return true;
+}
+
+bool WaitWithMessageLoop(HANDLE h) {
+  BasicMessageHandlerInternal msg_handler;
+  uint32 pos(static_cast<uint32>(-1));
+  bool res =
+    WaitWithMessageLoopAnyInternal(&h, 1, &pos, &msg_handler) != S_FALSE;
+  if (res) {
+    // It's the first and the only handle that it is signaled.
+    ASSERT1(pos == 0);
+  }
+  return res;
+}
+
+// Wait with message loop for a certain period of time
+bool WaitWithMessageLoopTimed(DWORD ms) {
+  scoped_timer timer(::CreateWaitableTimer(NULL,
+                                           true,   // manual reset
+                                           NULL));
+  ASSERT1(get(timer));
+  LARGE_INTEGER timeout = MSto100NSRelative(ms);
+  BOOL timer_ok = ::SetWaitableTimer(get(timer),
+                                     &timeout,
+                                     0,
+                                     NULL,
+                                     NULL,
+                                     false);
+  ASSERT1(timer_ok);
+  return WaitWithMessageLoop(get(timer));
+}
+
+MessageLoopWithWait::MessageLoopWithWait() : message_handler_(NULL) {
+}
+
+void MessageLoopWithWait::set_message_handler(
+    MessageHandlerInterface* message_handler) {
+  message_handler_ = message_handler;
+}
+
+// The message loop and handle callback routine.
+HRESULT MessageLoopWithWait::Process() {
+  while (true) {
+    ASSERT1(callback_handles_.size() == callbacks_.size());
+
+    // The implementation allows for an empty array of handles. Taking the
+    // address of elements in an empty container is not allowed so we must
+    // deal with this case here.
+    size_t pos(0);
+    HRESULT hr = WaitWithMessageLoopAnyInternal(
+        callback_handles_.empty() ? NULL : &callback_handles_.front(),
+        callback_handles_.size(),
+        &pos,
+        this);
+
+    // In addition to E_*, S_FALSE should cause a return to happen here.
+    if (hr != S_OK) {
+      return hr;
+    }
+
+    ASSERT1(pos < callback_handles_.size());
+    ASSERT1(callback_handles_.size() == callbacks_.size());
+
+    HANDLE signaled_handle = callback_handles_[pos];
+    WaitCallbackInterface* callback_interface = callbacks_[pos];
+    RemoveHandleAt(pos);
+
+    if (!callback_interface->HandleSignaled(signaled_handle)) {
+      return S_OK;
+    }
+  }
+}
+
+// Handles one messgae and adjust the handles and cnt as appropriate after
+// handling the message.
+void MessageLoopWithWait::Process(MSG* msg, const HANDLE** handles,
+                                  uint32* cnt) {
+  ASSERT1(msg && handles && cnt);
+
+  if (message_handler_) {
+    message_handler_->Process(msg);
+  }
+
+  // Set the handles and count again because they may have changed
+  // while processing the message.
+  *handles = callback_handles_.empty() ? NULL : &callback_handles_.front();
+  *cnt = callback_handles_.size();
+}
+// Starts waiting on the given handle
+bool MessageLoopWithWait::RegisterWaitForSingleObject(
+    HANDLE handle, WaitCallbackInterface* callback) {
+  ASSERT1(callback_handles_.size() == callbacks_.size());
+  ASSERT1(callback != NULL);
+
+  if (callback_handles_.size() >= MAXIMUM_WAIT_OBJECTS - 1) {
+    return false;
+  }
+
+  // In case the user is registering a handle, that they previous added
+  // remove the previous one before adding it back into the array.
+  UnregisterWait(handle);
+  callback_handles_.push_back(handle);
+  callbacks_.push_back(callback);
+
+  ASSERT1(callback_handles_.size() == callbacks_.size());
+  return true;
+}
+
+// Finds the given handle and stops waiting on it
+bool MessageLoopWithWait::UnregisterWait(HANDLE handle) {
+  ASSERT1(callback_handles_.size() == callbacks_.size());
+
+  for (uint32 index = 0; index < callback_handles_.size() ; index++) {
+    if (callback_handles_[index] == handle) {
+      RemoveHandleAt(index);
+      return true;
+    }
+  }
+  return false;
+}
+
+// Removes the wait handle at the given position
+void MessageLoopWithWait::RemoveHandleAt(uint32 pos) {
+  ASSERT1(callback_handles_.size() == callbacks_.size());
+  ASSERT1(pos < callback_handles_.size());
+
+  callback_handles_.erase(callback_handles_.begin() + pos);
+  callbacks_.erase(callbacks_.begin() + pos);
+
+  ASSERT1(callback_handles_.size() == callbacks_.size());
+}
+
+HRESULT CallEntryPoint0(const TCHAR* dll_path,
+                        const char* function_name,
+                        HRESULT* result) {
+  ASSERT1(dll_path);
+  ASSERT1(::lstrlen(dll_path) > 0);
+  ASSERT1(function_name);
+  ASSERT1(::strlen(function_name) > 0);
+  ASSERT1(result);
+
+  scoped_library dll(::LoadLibrary(dll_path));
+  if (!dll) {
+    return HRESULTFromLastError();
+  }
+
+  HRESULT (*proc)() = reinterpret_cast<HRESULT (*)()>(
+      ::GetProcAddress(get(dll), function_name));
+  if (!proc) {
+    return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
+  }
+
+  *result = (proc)();
+  return S_OK;
+}
+
+// Register a DLL
+HRESULT RegisterDll(const TCHAR* dll_path) {
+  HRESULT hr = S_OK;
+  HRESULT hr_call = CallEntryPoint0(dll_path, "DllRegisterServer", &hr);
+  if (SUCCEEDED(hr_call)) {
+    return hr;
+  }
+  return hr_call;
+}
+
+// Unregister a DLL
+HRESULT UnregisterDll(const TCHAR* dll_path) {
+  HRESULT hr = S_OK;
+  HRESULT hr_call = CallEntryPoint0(dll_path, "DllUnregisterServer", &hr);
+  if (SUCCEEDED(hr_call)) {
+    return hr;
+  }
+  return hr_call;
+}
+
+// Register/unregister an EXE
+HRESULT RegisterOrUnregisterExe(const TCHAR* exe_path, const TCHAR* cmd_line) {
+  ASSERT1(exe_path);
+  ASSERT1(cmd_line);
+
+  // cmd_line parameter really contains the arguments to be passed
+  // on the process creation command line.
+  PROCESS_INFORMATION pi = {0};
+  HRESULT hr = System::StartProcessWithArgsAndInfo(exe_path, cmd_line, &pi);
+  if (FAILED(hr)) {
+    UTIL_LOG(LEVEL_WARNING, (_T("[RegisterOrUnregisterExe]")
+                             _T("[failed to start process]")
+                             _T("[%s][%s][0x%08x]"), exe_path, cmd_line, hr));
+    return hr;
+  }
+  // Take ownership of the handles for clean up.
+  scoped_thread thread(pi.hThread);
+  scoped_process process(pi.hProcess);
+
+  // ATL COM servers return an HRESULT on exit. There is a case in which they
+  // return -1 which seems like a bug in ATL. It appears there is no
+  // documented convention on what a local server would return for errors.
+  // There is a possibility that a server would return Windows errors.
+
+  // Wait on the process to exit and return the exit code of the process.
+  DWORD result(::WaitForSingleObject(get(process), kRegisterExeTimeoutMs));
+  DWORD exit_code(0);
+  if (result == WAIT_OBJECT_0 &&
+      ::GetExitCodeProcess(get(process), &exit_code)) {
+    return static_cast<HRESULT>(exit_code);
+  } else {
+    return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+  }
+}
+
+// Register a COM Local Server
+HRESULT RegisterServer(const TCHAR* exe_path) {
+  return RegisterOrUnregisterExe(exe_path, _T("/RegServer"));
+}
+
+// Unregister a COM Local Server
+HRESULT UnregisterServer(const TCHAR* exe_path) {
+  return RegisterOrUnregisterExe(exe_path, _T("/UnregServer"));
+}
+
+// Register a Service
+HRESULT RegisterService(const TCHAR* exe_path) {
+  return RegisterOrUnregisterExe(exe_path, _T("/Service"));
+}
+
+// Unregister a Service
+HRESULT UnregisterService(const TCHAR* exe_path) {
+  // Unregistering a service is via UnregServer
+  return RegisterOrUnregisterExe(exe_path, _T("/UnregServer"));
+}
+
+// Adapted from gds installer/install/work_list.cpp: InstallServiceExecutable
+HRESULT RunService(const TCHAR* service_name) {
+  scoped_service manager(::OpenSCManager(NULL,  // local machine
+                                         NULL,  // ServicesActive database
+                                         STANDARD_RIGHTS_READ));
+  ASSERT1(get(manager));
+  if (!get(manager)) {
+    return HRESULTFromLastError();
+  }
+
+  scoped_service service(::OpenService(get(manager), service_name,
+                                       SERVICE_START));
+  ASSERT1(get(service));
+  if (!get(service)) {
+    return HRESULTFromLastError();
+  }
+
+  UTIL_LOG(L2, (_T("start service")));
+  if (!::StartService(get(service), 0, NULL)) {
+    return HRESULTFromLastError();
+  }
+  return S_OK;
+}
+
+
+HRESULT ReadEntireFile(const TCHAR* filepath,
+                       uint32 max_len,
+                       std::vector<byte>* buffer_out) {
+  return ReadEntireFileShareMode(filepath, max_len, 0, buffer_out);
+}
+
+HRESULT ReadEntireFileShareMode(const TCHAR* filepath,
+                                uint32 max_len,
+                                DWORD share_mode,
+                                std::vector<byte>* buffer_out) {
+  ASSERT1(filepath);
+  ASSERT1(buffer_out);
+
+  File file;
+  HRESULT hr = file.OpenShareMode(filepath, false, false, share_mode);
+  if (FAILED(hr)) {
+    // File missing.
+    return hr;
+  }
+
+  ON_SCOPE_EXIT_OBJ(file, &File::Close);
+
+  uint32 file_len = 0;
+  hr = file.GetLength(&file_len);
+  if (FAILED(hr)) {
+    // Should never happen
+    return hr;
+  }
+
+  if (max_len != 0 && file_len > max_len) {
+    // Too large to consider
+    return MEM_E_INVALID_SIZE;
+  }
+
+  if (file_len == 0) {
+    buffer_out->clear();
+    return S_OK;
+  }
+
+  int old_size = buffer_out->size();
+  buffer_out->resize(old_size + file_len);
+
+  uint32 bytes_read = 0;
+  hr = file.ReadFromStartOfFile(file_len,
+                                &(*buffer_out)[old_size],
+                                &bytes_read);
+  if (FAILED(hr)) {
+    // I/O error of some kind
+    return hr;
+  }
+
+  if (bytes_read != file_len) {
+    // Unexpected length. This could happen when reading a file someone else
+    // is writing to such as log files.
+    ASSERT1(false);
+    return E_UNEXPECTED;
+  }
+
+  // All's well that ends well
+  return S_OK;
+}
+
+HRESULT WriteEntireFile(const TCHAR * filepath,
+                        const std::vector<byte>& buffer_in) {
+  ASSERT1(filepath);
+
+  // File::WriteAt doesn't implement clear-on-open-for-write semantics,
+  // so just delete the file if it exists instead of writing into it.
+
+  if (File::Exists(filepath)) {
+    HRESULT hr = File::Remove(filepath);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  File file;
+  HRESULT hr = file.Open(filepath, true, false);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ON_SCOPE_EXIT_OBJ(file, &File::Close);
+
+  uint32 bytes_written = 0;
+  hr = file.WriteAt(0, &buffer_in.front(), buffer_in.size(), 0, &bytes_written);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (bytes_written != buffer_in.size()) {
+    // This shouldn't happen, caller needs to investigate what's up.
+    ASSERT1(false);
+    return E_UNEXPECTED;
+  }
+
+  return S_OK;
+}
+
+// Conversions between a byte stream and a std::string
+HRESULT BufferToString(const std::vector<byte>& buffer_in, CStringA* str_out) {
+  ASSERT1(str_out);
+  str_out->Append(reinterpret_cast<const char*>(&buffer_in.front()),
+                  buffer_in.size());
+  return S_OK;
+}
+
+HRESULT StringToBuffer(const CStringA& str_in, std::vector<byte>* buffer_out) {
+  ASSERT1(buffer_out);
+  buffer_out->assign(str_in.GetString(),
+                     str_in.GetString() + str_in.GetLength());
+  return S_OK;
+}
+
+HRESULT BufferToString(const std::vector<byte>& buffer_in, CString* str_out) {
+  ASSERT1(str_out);
+
+  size_t len2 = buffer_in.size();
+  ASSERT1(len2 % 2 == 0);
+  size_t len = len2 / 2;
+
+  str_out->Append(reinterpret_cast<const TCHAR*>(&buffer_in.front()), len);
+
+  return S_OK;
+}
+
+HRESULT StringToBuffer(const CString& str_in, std::vector<byte>* buffer_out) {
+  ASSERT1(buffer_out);
+
+  size_t len = str_in.GetLength();
+  size_t len2 = len * 2;
+
+  buffer_out->resize(len2);
+  ::memcpy(&buffer_out->front(), str_in.GetString(), len2);
+
+  return S_OK;
+}
+
+HRESULT RegSplitKeyvalueName(const CString& keyvalue_name,
+                             CString* key_name,
+                             CString* value_name) {
+  ASSERT1(key_name);
+  ASSERT1(value_name);
+
+  const TCHAR kDefault[] = _T("\\(default)");
+
+  if (String_EndsWith(keyvalue_name, _T("\\"), false)) {
+    key_name->SetString(keyvalue_name, keyvalue_name.GetLength() - 1);
+    value_name->Empty();
+  } else if (String_EndsWith(keyvalue_name, kDefault, true)) {
+    key_name->SetString(keyvalue_name,
+                        keyvalue_name.GetLength() - TSTR_SIZE(kDefault));
+    value_name->Empty();
+  } else {
+    int last_slash = String_ReverseFindChar(keyvalue_name, _T('\\'));
+    if (last_slash == -1) {
+      // No slash found - bizzare and wrong
+      return E_FAIL;
+    }
+    key_name->SetString(keyvalue_name, last_slash);
+    value_name->SetString(keyvalue_name.GetString() + last_slash + 1,
+                          keyvalue_name.GetLength() - last_slash - 1);
+  }
+
+  return S_OK;
+}
+
+HRESULT ExpandEnvLikeStrings(const TCHAR* src,
+                             const std::map<CString, CString>& keywords,
+                             CString* dest) {
+  ASSERT1(src);
+  ASSERT1(dest);
+
+  const TCHAR kMarker = _T('%');
+
+  dest->Empty();
+
+  // Loop while finding the marker in the string
+  HRESULT hr = S_OK;
+  int pos = 0;
+  int marker_pos1 = -1;
+  while ((marker_pos1 = String_FindChar(src, kMarker, pos)) != -1) {
+    // Try to find the right marker
+    int marker_pos2 = -1;
+    const TCHAR* s = src + marker_pos1 + 1;
+    for (; *s; ++s) {
+      if (*s == kMarker) {
+        marker_pos2 = s - src;
+        break;
+      }
+      if (!String_IsIdentifierChar(*s)) {
+        break;
+      }
+    }
+    if (marker_pos2 == -1) {
+      // Unmatched marker found, skip
+      dest->Append(src + pos, marker_pos1 - pos + 1);
+      pos = marker_pos1 + 1;
+      continue;
+    }
+
+    // Get the name - without the % markers on each end
+    CString name(src + marker_pos1 + 1, marker_pos2 - marker_pos1 - 1);
+
+    bool found = false;
+    for (std::map<CString, CString>::const_iterator it(keywords.begin());
+         it != keywords.end();
+         ++it) {
+      if (_tcsicmp(it->first, name) == 0) {
+        dest->Append(src + pos, marker_pos1 - pos);
+        dest->Append(it->second);
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      // No mapping found
+      UTIL_LOG(LEVEL_ERROR, (_T("[ExpandEnvLikeStrings]")
+                             _T("[no mapping found for '%s' in '%s']"),
+                             name, src));
+      dest->Append(src + pos, marker_pos2 - pos + 1);
+      hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+    }
+
+    pos = marker_pos2 + 1;
+  }
+
+  int len = _tcslen(src);
+  if (pos < len) {
+    dest->Append(src + pos, len - pos);
+  }
+
+  return hr;
+}
+
+bool IsRegistryPath(const TCHAR* path) {
+  return String_StartsWith(path, _T("HKLM\\"), false) ||
+         String_StartsWith(path, _T("HKCU\\"), false) ||
+         String_StartsWith(path, _T("HKCR\\"), false) ||
+         String_StartsWith(path, _T("HKEY_LOCAL_MACHINE\\"), false) ||
+         String_StartsWith(path, _T("HKEY_CURRENT_USER\\"), false) ||
+         String_StartsWith(path, _T("HKEY_CLASSES_ROOT\\"), false);
+}
+
+bool IsUrl(const TCHAR* path) {
+  // Currently we only check for "http://" and "https://"
+  return String_StartsWith(path, kHttpProto, true) ||
+         String_StartsWith(path, kHttpsProto, true);
+}
+
+
+CString GuidToString(const GUID& guid) {
+  TCHAR guid_str[40] = {0};
+  VERIFY1(::StringFromGUID2(guid, guid_str, arraysize(guid_str)));
+  String_ToUpper(guid_str);
+  return guid_str;
+}
+
+// Helper function to convert string to GUID
+GUID StringToGuid(const CString& str) {
+  GUID guid(GUID_NULL);
+  if (!str.IsEmpty()) {
+    TCHAR* s = const_cast<TCHAR*>(str.GetString());
+    VERIFY(SUCCEEDED(::CLSIDFromString(s, &guid)), (_T("guid %s"), s));
+  }
+  return guid;
+}
+
+// Helper function to convert a variant containing a list of strings
+void VariantToStringList(VARIANT var, std::vector<CString>* list) {
+  ASSERT1(list);
+
+  list->clear();
+
+  ASSERT1(V_VT(&var) == VT_DISPATCH);
+  CComPtr<IDispatch> obj = V_DISPATCH(&var);
+  ASSERT1(obj);
+
+  CComVariant var_length;
+  VERIFY1(SUCCEEDED(obj.GetPropertyByName(_T("length"), &var_length)));
+  ASSERT1(V_VT(&var_length) == VT_I4);
+  int length = V_I4(&var_length);
+
+  for (int i = 0; i < length; ++i) {
+    CComVariant value;
+    VERIFY1(SUCCEEDED(obj.GetPropertyByName(itostr(i), &value)));
+    if (V_VT(&value) == VT_BSTR) {
+      list->push_back(V_BSTR(&value));
+    } else {
+      ASSERT1(false);
+    }
+  }
+}
+
+
+HRESULT GetCurrentProcessHandle(HANDLE* handle) {
+  ASSERT1(handle);
+  scoped_process real_handle;
+  HANDLE pseudo_handle = ::GetCurrentProcess();
+  bool res = ::DuplicateHandle(
+    pseudo_handle,         // this process pseudo-handle
+    pseudo_handle,         // handle to duplicate
+    pseudo_handle,         // the process receiving the handle
+    address(real_handle),  // this process real handle
+    0,                     // ignored
+    false,                 // don't inherit this handle
+    DUPLICATE_SAME_ACCESS) != 0;
+
+  *handle = NULL;
+  if (!res) {
+    return HRESULTFromLastError();
+  }
+  *handle = release(real_handle);
+  return S_OK;
+}
+
+
+// get a time64 value
+// NOTE: If the value is greater than the
+// max value, then SetValue will be called using the max_value.
+HRESULT GetLimitedTimeValue(const TCHAR* full_key_name, const TCHAR* value_name,
+                            time64 max_time, time64* value,
+                            bool* limited_value) {
+  ASSERT1(full_key_name);
+  ASSERT1(value);
+  STATIC_ASSERT(sizeof(time64) == sizeof(DWORD64));
+
+  if (limited_value) {
+    *limited_value = false;
+  }
+  HRESULT hr = RegKey::GetValue(full_key_name, value_name, value);
+  if (SUCCEEDED(hr) && *value > max_time) {
+    *value = max_time;
+
+    // Use a different hr for the setting of the value b/c
+    // the returned hr should reflect the success/failure of reading the key
+    HRESULT set_value_hr = RegKey::SetValue(full_key_name, value_name, *value);
+    ASSERT(SUCCEEDED(set_value_hr), (_T("[GetLimitedTimeValue - failed ")
+                                     _T("when setting a value][0x%x]"),
+                                     set_value_hr));
+    if (SUCCEEDED(set_value_hr) && limited_value) {
+      *limited_value = true;
+    }
+  }
+  return hr;
+}
+
+// get a time64 value trying reg keys successively if there is a
+// failure in getting a value.
+HRESULT GetLimitedTimeValues(const TCHAR* full_key_names[],
+                             int key_names_length,
+                             const TCHAR* value_name,
+                             time64 max_time,
+                             time64* value,
+                             bool* limited_value) {
+  ASSERT1(full_key_names);
+  ASSERT1(value);
+  ASSERT1(key_names_length > 0);
+
+  HRESULT hr = E_FAIL;
+  for (int i = 0; i < key_names_length; ++i) {
+    hr = GetLimitedTimeValue(full_key_names[i], value_name, max_time, value,
+                             limited_value);
+    if (SUCCEEDED(hr)) {
+      return hr;
+    }
+  }
+  return hr;
+}
+
+// Wininet.dll (and especially the version that comes with IE7, with 01/12/07
+// timestamp) incorrectly initializes Rasman.dll. As a result, there is a race
+// condition that causes double-free on a memory from process heap.
+// This causes memory corruption in the heap that may later produce a variety
+// of ill effects, most frequently a crash with a callstack that contains
+// wininet and rasman, or ntdll!RtlAllocHeap. The root cause is that
+// Rasapi32!LoadRasmanDllAndInit is not thread safe and can start very involved
+// process of initialization on 2 threads at the same time. It's a bug.
+// Solution: in the begining of the program, trigger synchronous load of
+// rasman dll. The easy way is to call a public ras api that does synchronous
+// initialization, which is what we do here.
+void EnsureRasmanLoaded() {
+  RASENTRYNAME ras_entry_name = {0};
+  DWORD size_bytes = sizeof(ras_entry_name);
+  DWORD number_of_entries = 0;
+  ras_entry_name.dwSize = size_bytes;
+  // we don't really need results of this method,
+  // it simply triggers RASAPI32!LoadRasmanDllAndInit() internally.
+  ::RasEnumEntries(NULL,
+                   NULL,
+                   &ras_entry_name,
+                   &size_bytes,
+                   &number_of_entries);
+}
+
+// Appends two reg keys. Handles the situation where there are traling
+// back slashes in one and leading back slashes in two.
+CString AppendRegKeyPath(const CString& one, const CString& two) {
+  CString leftpart(one);
+  int length = leftpart.GetLength();
+  int i = 0;
+  for (i = length - 1; i >= 0; --i) {
+    if (leftpart[i] != _T('\\')) {
+      break;
+    }
+  }
+  leftpart = leftpart.Left(i+1);
+
+  CString rightpart(two);
+  int lengthr = rightpart.GetLength();
+  for (i = 0; i < lengthr; ++i) {
+    if (rightpart[i] != _T('\\')) {
+      break;
+    }
+  }
+  rightpart = rightpart.Right(lengthr - i);
+
+  CString result;
+  result.Format(_T("%s\\%s"), leftpart, rightpart);
+  return result;
+}
+
+CString AppendRegKeyPath(const CString& one, const CString& two,
+                         const CString& three) {
+  CString result = AppendRegKeyPath(one, two);
+  result = AppendRegKeyPath(result, three);
+  return result;
+}
+
+
+HRESULT GetUserKeysFromHkeyUsers(std::vector<CString>* key_names) {
+  ASSERT1(key_names);
+  CORE_LOG(L3, (_T("[GetUserKeysFromHkeyUsers]")));
+
+  TCHAR user_key_name[MAX_PATH] = {0};
+  int i = 0;
+  while (::RegEnumKey(HKEY_USERS, i++, user_key_name, MAX_PATH) !=
+                      ERROR_NO_MORE_ITEMS) {
+        byte sid_buffer[SECURITY_MAX_SID_SIZE] = {0};
+    PSID sid = reinterpret_cast<PSID>(sid_buffer);
+    if (::ConvertStringSidToSid(user_key_name, &sid) != 0) {
+      // We could convert the string SID into a real SID. If not
+      // we just ignore.
+      DWORD size = MAX_PATH;
+      DWORD size_domain = MAX_PATH;
+      SID_NAME_USE sid_type = SidTypeComputer;
+      TCHAR user_name[MAX_PATH] = {0};
+      TCHAR domain_name[MAX_PATH] = {0};
+
+      if (::LookupAccountSid(NULL, sid, user_name, &size,
+                             domain_name, &size_domain, &sid_type) == 0) {
+        HRESULT hr = HRESULTFromLastError();
+        CORE_LOG(LEVEL_WARNING,
+            (_T("[GetUserKeysFromHkeyUsers LookupAccountSid] ")
+             _T(" failed [0x%08x]"),
+             hr));
+        continue;
+      }
+
+      if (sid_type == SidTypeUser) {
+        // Change the RunAs keys for the user goopdates to point to the
+        // machine install.
+        CString user_reg_key_name = AppendRegKeyPath(USERS_KEY, user_key_name);
+        key_names->push_back(user_reg_key_name);
+      }
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT IsSystemProcess(bool* is_system_process) {
+  CAccessToken current_process_token;
+  if (!current_process_token.GetProcessToken(TOKEN_QUERY,
+                                             ::GetCurrentProcess())) {
+    HRESULT hr = HRESULTFromLastError();
+    ASSERT(false, (_T("[CAccessToken::GetProcessToken 0x%x]"), hr));
+    return hr;
+  }
+  CSid logon_sid;
+  if (!current_process_token.GetUser(&logon_sid)) {
+    HRESULT hr = HRESULTFromLastError();
+    ASSERT(false, (_T("[CAccessToken::GetUser 0x%x]"), hr));
+    return hr;
+  }
+  *is_system_process = logon_sid == Sids::System();
+  return S_OK;
+}
+
+HRESULT IsUserLoggedOn(bool* is_logged_on) {
+  ASSERT1(is_logged_on);
+  bool is_local_system(false);
+  HRESULT hr = IsSystemProcess(&is_local_system);
+  if (SUCCEEDED(hr) && is_local_system) {
+    *is_logged_on = true;
+    return S_OK;
+  }
+  return UserRights::UserIsLoggedOnInteractively(is_logged_on);
+}
+
+bool IsClickOnceDisabled() {
+  CComPtr<IInternetZoneManager> zone_mgr;
+  HRESULT hr =  zone_mgr.CoCreateInstance(CLSID_InternetZoneManager);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[CreateInstance InternetZoneManager failed][0x%x]"), hr));
+    return true;
+  }
+
+  DWORD policy = URLPOLICY_DISALLOW;
+  size_t policy_size = sizeof(policy);
+  hr = zone_mgr->GetZoneActionPolicy(URLZONE_INTERNET,
+                                     URLACTION_MANAGED_UNSIGNED,
+                                     reinterpret_cast<BYTE*>(&policy),
+                                     policy_size,
+                                     URLZONEREG_DEFAULT);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[GetZoneActionPolicy failed][0x%x]"), hr));
+    return true;
+  }
+
+  return policy == URLPOLICY_DISALLOW;
+}
+
+// This function only uses kernel32, and it is safe to call from DllMain.
+HRESULT PinModuleIntoProcess(const CString& module_name) {
+  ASSERT1(!module_name.IsEmpty());
+  static HMODULE module_handle = NULL;
+  typedef BOOL (WINAPI *Fun)(DWORD flags,
+                             LPCWSTR module_name,
+                             HMODULE* module_handle);
+
+  HINSTANCE kernel_instance = ::GetModuleHandle(_T("kernel32.dll"));
+  ASSERT1(kernel_instance);
+  Fun pfn = NULL;
+  if (GPA(kernel_instance, "GetModuleHandleExW", &pfn)) {
+    if ((*pfn)(GET_MODULE_HANDLE_EX_FLAG_PIN, module_name, &module_handle)) {
+      return S_OK;
+    }
+    ASSERT(false, (_T("GetModuleHandleExW() failed [%d]"), ::GetLastError()));
+  }
+
+  module_handle = ::LoadLibrary(module_name);
+  ASSERT(NULL != module_handle, (_T("LoadLibrary [%d]"), ::GetLastError()));
+  if (NULL == module_handle) {
+    return HRESULTFromLastError();
+  }
+
+  return S_OK;
+}
+
+bool ShellExecuteExEnsureParent(LPSHELLEXECUTEINFO shell_exec_info) {
+  UTIL_LOG(L3, (_T("[ShellExecuteExEnsureParent]")));
+
+  ASSERT1(shell_exec_info);
+  bool shell_exec_succeeded(false);
+  DWORD last_error(ERROR_SUCCESS);
+
+  {
+    // hwnd_parent window is destroyed at the end of the scope when the
+    // destructor of scoped_window calls ::DestroyWindow.
+    scoped_window hwnd_parent;
+
+    if (!shell_exec_info->hwnd && vista_util::IsVistaOrLater()) {
+      reset(hwnd_parent, CreateForegroundParentWindowForUAC());
+
+      if (!hwnd_parent) {
+        last_error = ::GetLastError();
+        UTIL_LOG(LE, (_T("[CreateDummyOverlappedWindow failed]")));
+        // Restore last error in case the logging reset it.
+        ::SetLastError(last_error);
+        return false;
+      }
+
+      shell_exec_info->hwnd = get(hwnd_parent);
+
+      // If elevation is required on Vista, call ::SetForegroundWindow(). This
+      // will make sure that the elevation prompt, as well as the elevated
+      // process window comes up in the foreground. It will also ensure that in
+      // the case where the elevation prompt is cancelled, the error dialog
+      // shown from this process comes up in the foreground.
+      if (shell_exec_info->lpVerb &&
+          _tcsicmp(shell_exec_info->lpVerb, _T("runas")) == 0) {
+        if (!::SetForegroundWindow(get(hwnd_parent))) {
+          UTIL_LOG(LW, (_T("[SetForegroundWindow fail %d]"), ::GetLastError()));
+        }
+      }
+    }
+
+    shell_exec_succeeded = !!::ShellExecuteEx(shell_exec_info);
+
+    if (shell_exec_succeeded) {
+      if (shell_exec_info->hProcess) {
+        DWORD pid = Process::GetProcessIdFromHandle(shell_exec_info->hProcess);
+        OPT_LOG(L1, (_T("[Started process][%u]"), pid));
+        if (!::AllowSetForegroundWindow(pid)) {
+          UTIL_LOG(LW, (_T("[AllowSetForegroundWindow %d]"), ::GetLastError()));
+        }
+      } else {
+        OPT_LOG(L1, (_T("[Started process][PID unknown]")));
+      }
+    } else {
+      last_error = ::GetLastError();
+      UTIL_LOG(LE, (_T("[ShellExecuteEx fail][%s][%s][0x%08x]"),
+                    shell_exec_info->lpFile, shell_exec_info->lpParameters,
+                    last_error));
+    }
+  }
+
+  // The implicit ::DestroyWindow call from the scoped_window could have reset
+  // the last error, so restore it.
+  ::SetLastError(last_error);
+
+  return shell_exec_succeeded;
+}
+
+// Loads and unloads advapi32.dll for every call. If performance is an issue
+// consider keeping the dll always loaded and holding the pointer to the
+// RtlGenRandom in a static variable.
+// Use the function with care. While the function is documented, it may be
+// altered or made unavailable in future versions of the operating system.
+bool GenRandom(void* buffer, size_t buffer_length) {
+  ASSERT1(buffer);
+  scoped_library lib(::LoadLibrary(_T("ADVAPI32.DLL")));
+  if (lib) {
+    typedef BOOLEAN (APIENTRY *RtlGenRandomType)(void*, ULONG);
+    RtlGenRandomType rtl_gen_random = reinterpret_cast<RtlGenRandomType>(
+        ::GetProcAddress(get(lib), "SystemFunction036"));
+    return rtl_gen_random && rtl_gen_random(buffer, buffer_length);
+  }
+
+  // Use CAPI to generate randomness for systems which do not support
+  // RtlGenRandomType, for instance Windows 2000.
+  const uint32 kCspFlags = CRYPT_VERIFYCONTEXT | CRYPT_SILENT;
+  HCRYPTPROV csp = NULL;
+  if (::CryptAcquireContext(&csp, NULL, NULL, PROV_RSA_FULL, kCspFlags)) {
+    if (::CryptGenRandom(csp, buffer_length, static_cast<BYTE*>(buffer))) {
+      return true;
+    }
+  }
+  VERIFY1(::CryptReleaseContext(csp, 0));
+  return false;
+}
+
+// Assumes the path in command is properly enclosed if necessary.
+HRESULT ConfigureRunAtStartup(const CString& root_key_name,
+                              const CString& run_value_name,
+                              const CString& command,
+                              bool install) {
+  UTIL_LOG(L3, (_T("ConfigureRunAtStartup")));
+
+  const CString key_path = AppendRegKeyPath(root_key_name, REGSTR_PATH_RUN);
+  HRESULT hr(S_OK);
+
+  if (install) {
+    hr = RegKey::SetValue(key_path, run_value_name, command);
+  } else {
+    hr = RegKey::DeleteValue(key_path, run_value_name);
+  }
+
+  return hr;
+}
+
+HRESULT GetExePathFromCommandLine(const TCHAR* command_line,
+                                  CString* exe_path) {
+  ASSERT1(exe_path);
+  CString command_line_str(command_line);
+  command_line_str.Trim(_T(' '));
+  if (command_line_str.IsEmpty()) {
+    // ::CommandLineToArgvW parses the current process command line for blank
+    // strings. We do not want this behavior.
+    return E_INVALIDARG;
+  }
+
+  int argc = 0;
+  wchar_t** argv = ::CommandLineToArgvW(command_line_str, &argc);
+  if (argc == 0 || !argv) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LE, (_T("[::CommandLineToArgvW failed][0x%x]"), hr));
+    return hr;
+  }
+
+  *exe_path = argv[0];
+  ::LocalFree(argv);
+  exe_path->Trim(_T(' '));
+  ASSERT1(!exe_path->IsEmpty());
+  return S_OK;
+}
+
+// Tries to open the _MSIExecute mutex and tests its state. MSI sets the
+// mutex when processing sequence tables. This indicates MSI is busy.
+// The function returns S_OK if the mutex is not owned by MSI or the mutex has
+// not been created.
+HRESULT WaitForMSIExecute(int timeout_ms) {
+  const TCHAR* mutex_name = _T("Global\\_MSIExecute");
+  scoped_mutex mutex(::OpenMutex(SYNCHRONIZE, false, mutex_name));
+  if (!mutex) {
+    DWORD error = ::GetLastError();
+    return (error == ERROR_FILE_NOT_FOUND) ? S_OK : HRESULT_FROM_WIN32(error);
+  }
+  UTIL_LOG(L3, (_T("[Wait for _MSIExecute]")));
+  switch (::WaitForSingleObject(get(mutex), timeout_ms)) {
+    case WAIT_OBJECT_0:
+    case WAIT_ABANDONED:
+      VERIFY1(::ReleaseMutex(get(mutex)));
+      return S_OK;
+    case WAIT_TIMEOUT:
+      return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+    case WAIT_FAILED:
+      return HRESULTFromLastError();
+    default:
+      return E_FAIL;
+  }
+}
+
+CString GetEnvironmentVariableAsString(const TCHAR* name) {
+  CString value;
+  size_t value_length = ::GetEnvironmentVariable(name, NULL, 0);
+  if (value_length) {
+    VERIFY1(::GetEnvironmentVariable(name,
+                                     CStrBuf(value, value_length),
+                                     value_length));
+  }
+  return value;
+}
+
+// States are documented at
+// http://technet.microsoft.com/en-us/library/cc721913.aspx.
+bool IsWindowsInstalling() {
+  static const TCHAR kVistaSetupStateKey[] =
+      _T("Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\State");
+  static const TCHAR kImageStateValueName[] = _T("ImageState");
+  static const TCHAR kImageStateUnuseableValue[] =
+      _T("IMAGE_STATE_UNDEPLOYABLE");
+  static const TCHAR kImageStateGeneralAuditValue[] =
+      _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_AUDIT");
+  static const TCHAR kImageStateSpecialAuditValue[] =
+      _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_AUDIT");
+
+  static const TCHAR kXPSetupStateKey[] = _T("System\\Setup");
+  static const TCHAR kAuditFlagValueName[] = _T("AuditInProgress");
+
+  if (vista_util::IsVistaOrLater()) {
+    RegKey vista_setup_key;
+    HRESULT hr =
+        vista_setup_key.Open(HKEY_LOCAL_MACHINE, kVistaSetupStateKey, KEY_READ);
+    if (SUCCEEDED(hr)) {
+      CString state;
+      hr = vista_setup_key.GetValue(kImageStateValueName, &state);
+      if (SUCCEEDED(hr) &&
+          !state.IsEmpty() &&
+          (0 == state.CompareNoCase(kImageStateUnuseableValue) ||
+           0 == state.CompareNoCase(kImageStateGeneralAuditValue) ||
+           0 == state.CompareNoCase(kImageStateSpecialAuditValue)))
+        return true;  // Vista is still installing.
+    }
+  } else {
+    RegKey xp_setup_key;
+    HRESULT hr =
+        xp_setup_key.Open(HKEY_LOCAL_MACHINE, kXPSetupStateKey, KEY_READ);
+    if (SUCCEEDED(hr)) {
+      DWORD audit_flag(0);
+      hr = xp_setup_key.GetValue(kAuditFlagValueName, &audit_flag);
+      if (SUCCEEDED(hr) && 0 != audit_flag)
+        return true;  // XP is still installing.
+    }
+  }
+  return false;
+}
+
+}  // namespace omaha
+
diff --git a/common/utils.h b/common/utils.h
index 59b76df..1507f98 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -1,811 +1,811 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_UTILS_H__

-#define OMAHA_COMMON_UTILS_H__

-

-#include <windows.h>

-#include <accctrl.h>

-#include <aclapi.h>

-#include <sddl.h>

-#include <shellapi.h>

-#include <shlobj.h>

-#include <atlstr.h>

-#include <atlsecurity.h>

-#include <atlwin.h>

-#include <memory.h>

-#include <map>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/static_assert.h"

-#include "omaha/common/user_info.h"

-

-namespace omaha {

-

-// Determines whether to run ClickOnce components. This constant is not defined

-// in the SDK headers.

-#ifndef URLACTION_MANAGED_UNSIGNED

-#define URLACTION_MANAGED_UNSIGNED (0x00002004)

-#endif

-

-ULONGLONG VersionFromString(const CString& s);

-

-CString StringFromVersion(ULONGLONG version);

-

-// Gets current directory

-CString GetCurrentDir();

-

-// Creates a unique file name using a new guid. Does not check for

-// presence of this file in the directory.

-HRESULT GetNewFileNameInDirectory(const CString& dir, CString* file_name);

-

-// Use of this method is unsafe. Be careful!

-// Gets security attributes for a "everyone" (authenticated users) DACL.

-void GetEveryoneDaclSecurityAttributes(CSecurityAttributes* sec_attr,

-                                       ACCESS_MASK non_admin_access_mask);

-

-// Get security attributes containing a DACL that grant the ACCESS_MASK access

-// to admins and system.

-void GetAdminDaclSecurityAttributes(CSecurityAttributes* sec_attr,

-                                    ACCESS_MASK accessmask);

-

-// Merges an Allowed ACE into a named object. If the ACE already exists in the

-// DACL with the same permissions (or a superset) and the same ACE flags, the

-// merge is skipped.

-HRESULT AddAllowedAce(const TCHAR* object_name,

-                      SE_OBJECT_TYPE object_type,

-                      const CSid& sid,

-                      ACCESS_MASK required_permissions,

-                      uint8 required_ace_flags);

-

-struct NamedObjectAttributes {

-  CString name;

-  CSecurityAttributes sa;

-};

-

-// For machine and local system, the prefix would be "Global\G{obj_name}".

-// For user, the prefix would be "Global\G{user_sid}{obj_name}".

-// For machine objects, returns a security attributes that gives permissions to

-// both Admins and SYSTEM. This allows for cases where SYSTEM creates the named

-// object first. The default DACL for SYSTEM will not allow Admins access.

-void GetNamedObjectAttributes(const TCHAR* base_name,

-                              bool is_machine,

-                              NamedObjectAttributes* attr);

-

-// Returns true if the current process is running as SYSTEM.

-HRESULT IsSystemProcess(bool* is_system_process);

-

-// Returns true if the user of the current process is Local System or it has an

-// interactive session: console, terminal services, or fast user switching.

-HRESULT IsUserLoggedOn(bool* is_logged_on);

-

-// Returns true if URLACTION_MANAGED_UNSIGNED is disabled for the Internet zone

-// for the current user.

-bool IsClickOnceDisabled();

-

-// Wrapper around ::GetProcAddress().

-template <typename T>

-bool GPA(HMODULE module, const char* function_name, T* function_pointer) {

-  ASSERT1(module);

-  ASSERT1(function_name);

-  ASSERT1(function_pointer);

-

-  *function_pointer = reinterpret_cast<T>(::GetProcAddress(module,

-                                                           function_name));

-  if (NULL == *function_pointer) {

-    UTIL_LOG(LW, (_T("GetProcAddress failed [%s]"), CA2T(function_name)));

-  }

-  return NULL != *function_pointer;

-}

-

-#define GPA_WRAP(module,                                                    \

-                 function,                                                  \

-                 proto,                                                     \

-                 call,                                                      \

-                 calling_convention,                                        \

-                 result_type,                                               \

-                 result_error)                                              \

-typedef result_type (calling_convention *function##_pointer) proto;         \

-inline result_type function##Wrap proto {                                   \

-  HINSTANCE module_instance = ::GetModuleHandle(_T(#module));               \

-  ASSERT1(module_instance);                                                 \

-  if (!module_instance) {                                                   \

-    return result_error;                                                    \

-  }                                                                         \

-  function##_pointer fn = NULL;                                             \

-  return GPA(module_instance, #function, &fn) ? (*fn) call : result_error;  \

-}

-

-GPA_WRAP(kernel32.dll,

-         AttachConsole,

-         (DWORD process_id),

-         (process_id),

-         WINAPI,

-         BOOL,

-         0);

-

-// Private Object Namespaces for Vista and above. More information here:

-// http://msdn2.microsoft.com/en-us/library/ms684295(VS.85).aspx

-GPA_WRAP(kernel32.dll,

-         CreateBoundaryDescriptorW,

-         (LPCWSTR boundary_name, ULONG flags),

-         (boundary_name, flags),

-         WINAPI,

-         HANDLE,

-         NULL);

-GPA_WRAP(kernel32.dll,

-         AddSIDToBoundaryDescriptor,

-         (HANDLE* boundary_descriptor, PSID required_sid),

-         (boundary_descriptor, required_sid),

-         WINAPI,

-         BOOL,

-         FALSE);

-GPA_WRAP(kernel32.dll,

-         CreatePrivateNamespaceW,

-         (LPSECURITY_ATTRIBUTES private_namespace_attributes, LPVOID boundary_descriptor, LPCWSTR alias_prefix),  // NOLINT

-         (private_namespace_attributes, boundary_descriptor, alias_prefix),

-         WINAPI,

-         HANDLE,

-         NULL);

-GPA_WRAP(kernel32.dll,

-         OpenPrivateNamespaceW,

-         (LPVOID boundary_descriptor, LPCWSTR alias_prefix),

-         (boundary_descriptor, alias_prefix),

-         WINAPI,

-         HANDLE,

-         NULL);

-

-bool IsPrivateNamespaceAvailable();

-

-

-HRESULT PinModuleIntoProcess(const CString& module_name);

-

-// Creates a directory with default security.

-//   S_OK:    Created directory

-//   S_FALSE: Directory already existed

-//   E_FAIL:  Couldn't create

-HRESULT CreateDir(const TCHAR* dirname, LPSECURITY_ATTRIBUTES security_attr);

-

-// Gets the path for the specified special folder.

-HRESULT GetFolderPath(int csidl, CString* path);

-

-// Returns true if this directory name is 'safe' for deletion:

-//  - it doesn't contain ".."

-//  - it doesn't specify a drive root

-bool SafeDirectoryNameForDeletion(const TCHAR* dir_name);

-

-// Deletes a directory.

-HRESULT DeleteDirectory(const TCHAR* ir_name);

-

-// Deletes all files in a directory.

-HRESULT DeleteDirectoryFiles(const TCHAR* dir_name);

-

-// Deletes all files in a directory matching a wildcard.

-HRESULT DeleteWildcardFiles(const TCHAR* dir_name, const TCHAR* wildcard_name);

-

-// Deletes either a file or directory before or after reboot.

-HRESULT DeleteBeforeOrAfterReboot(const TCHAR* targetname);

-

-// Gets the size of all files in a directory.

-// Aborts counting if one of the maximum criteria is reached.

-HRESULT SafeGetDirectorySize(const TCHAR* dir_name,

-                             uint64* size,

-                             HANDLE shutdown_event,

-                             uint64 max_size,

-                             int max_depth,

-                             int max_file_count,

-                             int max_running_time_ms);

-

-// Gets size of all files in a directory.

-HRESULT GetDirectorySize(const TCHAR* dir_name, uint64* size);

-

-enum TimeCategory {

-  PAST = 0,  // older than 40 years from now

-  FUTURE,    // in the future by > 1 day

-  PRESENT,   // neither ANCIENT nor FUTURE

-};

-

-TimeCategory GetTimeCategory(time64 t);

-

-// Returns true if a given time is likely to be valid.

-bool IsValidTime(time64 t);

-

-// Gets a time64 value.

-// If the value is greater than the

-// max value, then SetValue will be called using the max_value.

-//

-//  Args:

-//   full_key_name:   the reg keyto read to get the time value.

-//   value_name:      the name for the reg key value to be read.

-//                    (may be NULL to get the default value)

-//   max_time:        the maximum value for the reg key.

-//   value:           the time value read.  May not be set on failure.

-//   limited_value:   true iff will be set if the value was

-//                    changed (and resaved). (NULL is allowable.)

-HRESULT GetLimitedTimeValue(const TCHAR* full_key_name,

-                            const TCHAR* value_name,

-                            time64 max_time,

-                            time64* value,

-                            bool* limited_value);

-

-// Gets a time64 value trying reg keys successively if there is a

-// failure in getting a value.

-//

-// Typically used when there is a user value and a default value if the

-// user has none.

-//

-//  Args:

-//   full_key_names:  a list of reg keys to try successively (starting

-//                    with index 0) to read to get the time value.  The

-//                    attempts stops as soon as there is a successful read or

-//                    when all keys have been tried.

-//   key_names_length: number of keys in full_key_names.

-//   value_name:      the name for the reg key value to be read.

-//                    (may be NULL to get the default value)

-//   max_time:        the maximum value for the reg key.

-//   value:           the time value read.  May not be set on failure.

-//   limited_value:   true iff will be set if the value was

-//                    changed (and resaved). (NULL is allowable.)

-HRESULT GetLimitedTimeValues(const TCHAR* full_key_names[],

-                             int key_names_length,

-                             const TCHAR* value_name,

-                             time64 max_time,

-                             time64* value,

-                             bool* limited_value);

-

-// Convert milliseconds to a relative time in units of 100ns, suitable for use

-// with waitable timers

-LARGE_INTEGER MSto100NSRelative(DWORD ms);

-

-// TODO(omaha): remove from public interface.

-inline void WINAPI NullAPCFunc(ULONG_PTR) {}

-

-// Forces rasman.dll load to avoid a crash in wininet.

-void EnsureRasmanLoaded();

-

-// Returns if the HRESULT argument is a COM error

-// TODO(omaha): use an ANONYMOUS_VARIABLE to avoid the situation in which the

-// macro gets called like RET_IF_FAILED(hr);

-// For now, use a quick fix hr -> __hr. Leading underscore names are not to be

-// used in application code.

-#define RET_IF_FAILED(x)    \

-    do {                    \

-      HRESULT __hr(x);      \

-      if (FAILED(__hr)) {   \

-        return __hr;        \

-      }                     \

-    } while (false)

-

-// return error if the first argument evaluates to false

-#define RET_IF_FALSE(x, err)  \

-  do {                        \

-    if (!(x)) {               \

-      return err;             \

-    }                         \

-  } while (false)

-

-// return false if the HRESULT argument is a COM error

-#define RET_FALSE_IF_FAILED(x)  \

-  do {                          \

-    if (FAILED(x)) {            \

-      return false;             \

-    }                           \

-  } while (false)

-

-// return true if the HRESULT argument is a COM error

-#define RET_TRUE_IF_FAILED(x)   \

-  do {                          \

-    if (FAILED(x)) {            \

-      return true;              \

-    }                           \

-  } while (false)

-

-// return if the HRESULT argument evaluates to FAILED - but also assert

-// if failed

-#define RET_IF_FAILED_ASSERT(x, msg) \

-    do {                             \

-      HRESULT hr(x);                 \

-      if (FAILED(hr)) {              \

-        ASSERT(false, msg);          \

-        return hr;                   \

-      }                              \

-    } while (false)

-

-

-// return if the HRESULT argument evaluates to FAILED - but also log an error

-// message if failed

-#define RET_IF_FAILED_LOG(x, cat, msg) \

-    do {                               \

-      HRESULT hr(x);                   \

-      if (FAILED(hr)) {                \

-        LC_LOG(cat, LEVEL_ERROR, msg); \

-        return hr;                     \

-      }                                \

-    } while (false)

-

-// return if the HRESULT argument evaluates to FAILED - but also REPORT an error

-// message if failed

-#define RET_IF_FAILED_REPORT(x, msg, n) \

-    do {                                \

-      HRESULT hr(x);                    \

-      if (FAILED(hr)) {                 \

-        REPORT(false, R_ERROR, msg, n); \

-        return hr;                      \

-      }                                 \

-    } while (false)

-

-// Initializes a POD to zero.

-// Using this function requires discipline. Don't use for types that have a

-// v-table or virtual bases.

-template <typename T>

-inline void SetZero(T& p) {   // NOLINT

-  // Guard against the easy mistake of

-  //    foo(int *p) { SetZero(p); } instead of

-  //                  SetZero(*p);

-  // which it should be.

-  STATIC_ASSERT(sizeof(p) != sizeof(void*));    // NOLINT

-

-  // A POD (plain old data) object has one of these data types:

-  // a fundamental type, union, struct, array,

-  // or class--with no constructor. PODs don't have virtual functions or

-  // virtual bases.

-

-  // Test to see if the type has constructors.

-  union CtorTest {

-      T t;

-      int i;

-  };

-

-  // TODO(omaha): There might be a way to test if the type has virtuals

-  // For now, if we zero a type with virtuals by mistake, it is going to crash

-  // predictable at run-time when the virtuals are called.

-

-  memset(&p, 0, sizeof(T));

-}

-

-inline void SecureSetZero(CString* p) {

-  ASSERT1(p);

-  if (!p->IsEmpty()) {

-    ::SecureZeroMemory(p->GetBufferSetLength(p->GetLength()),

-                       p->GetLength() * sizeof(TCHAR));

-    p->ReleaseBuffer();

-  }

-}

-

-inline void SecureSetZero(CComVariant* p) {

-  ASSERT1(p);

-  ASSERT1(V_VT(p) == VT_BSTR);

-  uint32 byte_len = ::SysStringByteLen(V_BSTR(p));

-  if (byte_len > 0) {

-    ::SecureZeroMemory(V_BSTR(p), byte_len);

-  }

-}

-

-// CreateForegroundParentWindowForUAC creates a WS_POPUP | WS_VISIBLE with zero

-// size, of the STATIC WNDCLASS. It uses the default running EXE module

-// handle for creation.

-//

-// A visible centered foreground window is needed as the parent in Windows 7 and

-// above, to allow the UAC prompt to come up in the foreground, centered.

-// Otherwise, the elevation prompt will be minimized on the taskbar. A zero size

-// window works. A plain vanilla WS_POPUP allows the window to be free of

-// adornments. WS_EX_TOOLWINDOW prevents the task bar from showing the

-// zero-sized window.

-//

-// Returns NULL on failure. Call ::GetLastError() to get extended error

-// information on failure.

-inline HWND CreateForegroundParentWindowForUAC() {

-  CWindow foreground_parent;

-  if (foreground_parent.Create(_T("STATIC"), NULL, NULL, NULL,

-                               WS_POPUP | WS_VISIBLE, WS_EX_TOOLWINDOW)) {

-    foreground_parent.CenterWindow(NULL);

-    ::SetForegroundWindow(foreground_parent);

-  }

-  return foreground_parent.Detach();

-}

-

-// TODO(omaha): move the definition and ShellExecuteExEnsureParent function

-// below into shell.h

-

-#if (NTDDI_VERSION < NTDDI_WINXPSP1)

-// This value is not defined in the header, but has no effect on older OSes.

-#define SEE_MASK_NOZONECHECKS      0x00800000

-#endif

-

-// ShellExecuteExEnsureParent is a wrapper around ::ShellExecuteEx.

-// It ensures that we always have a parent window. In elevation scenarios, we

-// need to use the HWND property to be acknowledged as a foreground application

-// on Windows Vista. Otherwise, the elevation prompt will appear minimized on

-// the taskbar The UAC elevation mechanism uses the HWND as part of determining

-// whether the elevation is a foreground elevation.

-//

-// A better place for this might be in the Process class. However, to

-// reduce dependencies for the stub, placing this in utils.

-//

-// Return values:

-//   ShellExecuteExEnsureParent returns TRUE on success, and FALSE on failure.

-//   Call ::GetLastError() to get the extended error information on failure.

-//

-// Args:

-//   shell_exec_info structure pointer, filled in, with an optional HWND.

-//   The structure is not validated. If the HWND is NULL, it creates one.

-bool ShellExecuteExEnsureParent(LPSHELLEXECUTEINFO shell_exec_info);

-

-//

-// Wait with a message loop.

-// Returns true if the wait completed successfully and false in case of an

-// error.

-//

-

-// Waits with a message loop until any of the synchronization objects is

-// signaled. Return the index of the object that satisfied the wait.

-bool WaitWithMessageLoopAny(const std::vector<HANDLE>& handles, uint32* pos);

-

-// Waits with message loop until all the synchronization objects are signaled.

-bool WaitWithMessageLoopAll(const std::vector<HANDLE>& handles);

-

-// Waits with message loop until the synchronization object is signaled.

-bool WaitWithMessageLoop(HANDLE h);

-

-// Waits with message loop for a certain period of time

-bool WaitWithMessageLoopTimed(DWORD ms);

-

-//

-// TODO(omaha): message handler classes should go in other module.

-//

-// Handles windows messages

-class MessageHandlerInterface {

- public:

-  virtual ~MessageHandlerInterface() {}

-  // Does the translate/dispatch for one window message

-  // msg is never NULL.

-  virtual void Process(MSG* msg) = 0;

-};

-

-// The simplest working implementation of a message handler.

-// It does TranslateMessage/DispatchMessage.

-class BasicMessageHandler : public MessageHandlerInterface {

- public:

-  BasicMessageHandler() {}

-  virtual void Process(MSG* msg);

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(BasicMessageHandler);

-};

-

-// An internal detail (used to handle messages

-// and adjust the handles/cnt as needed).

-class MessageHandlerInternalInterface {

- public:

-  virtual ~MessageHandlerInternalInterface() {}

-  // Does the translate/dispatch for one window message

-  // msg is never NULL and may change the handles and cnt (which are

-  // never NULL).

-  virtual void Process(MSG* msg, const HANDLE** handles, uint32* cnt) = 0;

-};

-

-// The callback for MessageLoopInterface::RegisterWaitForSingleObject

-class WaitCallbackInterface {

- public:

-  virtual ~WaitCallbackInterface() {}

-  // Return false from this method to terminate the message loop.

-  virtual bool HandleSignaled(HANDLE handle) = 0;

-};

-

-// This is similar to a threadpool interface

-// but this is done on the main message loop instead.

-//

-// Important: These method calls are *not* threadsafe and

-// should only be done on the message loop thread.

-class MessageLoopInterface {

- public:

-  virtual ~MessageLoopInterface() {}

-  // sets-up a callback for when the handle becomes signaled

-  //   * the callback happens on the main thread.

-  //   * the handle/callback is removed when

-  //     the callback is made.

-  //   * If the handle becomes invalid while it is being waited on,

-  //     the message loop will exit.

-  //   * If the handle has already been registered,

-  //     then adding it again will essentially replace the

-  //     previous callback with the new one.

-  virtual bool RegisterWaitForSingleObject(HANDLE handle,

-                                           WaitCallbackInterface* callback) = 0;

-

-  // stops watching for the handle to be signaled

-  virtual bool UnregisterWait(HANDLE handle) = 0;

-};

-

-// An implementation of the MessageLoopInterface

-class MessageLoopWithWait : public MessageLoopInterface,

-                            private MessageHandlerInternalInterface {

- public:

-  MessageLoopWithWait();

-

-  // This method needs to be called before the "Process()"

-  // method or else "Process()" will crash.

-  //

-  // Args:

-  //    message_handler: handles any messages that occur

-  //       *Note* It is the callers responsibility to keep

-  //       message_handler around while this class exists

-  //       and the *caller* should free message_handler

-  //       after that.

-  void set_message_handler(MessageHandlerInterface* message_handler);

-

-  // sets-up a callback for when the handle becomes signaled

-  virtual bool RegisterWaitForSingleObject(HANDLE handle,

-                                           WaitCallbackInterface* callback);

-

-  // stops watching for the handle to be signaled

-  virtual bool UnregisterWait(HANDLE handle);

-

-  // The message loop and handle callback routine

-  HRESULT Process();

-

- private:

-  // Handles one messgae and adjus tthe handles and cnt as appropriate after

-  // handling the message

-  virtual void Process(MSG* msg, const HANDLE** handles, uint32* cnt);

-

-  void RemoveHandleAt(uint32 pos);

-

-  MessageHandlerInterface* message_handler_;

-

-  // Handles that are checked for being signaled.

-  std::vector<HANDLE> callback_handles_;

-

-  // What to call when a handle is signaled.

-  std::vector<WaitCallbackInterface*> callbacks_;

-  DISALLOW_EVIL_CONSTRUCTORS(MessageLoopWithWait);

-};

-

-// Calls an entry point that may be exposed from a DLL

-//   It is an error if the DLL is missing or can't be loaded

-//   If the entry point is missing the error returned is

-//   ERROR_INVALID_FUNCTION (as an HRESULT).

-//   Otherwise, if the function is called successfully then

-//   CallEntryPoint0 return S_OK and the result parameter is set to the

-//   return value from the function call.

-HRESULT CallEntryPoint0(const TCHAR* dll_path,

-                        const char* function_name,

-                        HRESULT* result);

-

-// (Un)Registers a COM DLL with the system.  Returns S_FALSE if entry

-// point missing (so that it you can call (Un)RegisterDll on any DLL

-// without worrying whether the DLL is actually a COM server or not).

-HRESULT RegisterDll(const TCHAR* dll_path);

-HRESULT UnregisterDll(const TCHAR* dll_path);

-

-// (Un)Registers a COM Local Server with the system.

-HRESULT RegisterServer(const TCHAR* exe_path);

-HRESULT UnregisterServer(const TCHAR* exe_path);

-HRESULT RegisterOrUnregisterExe(const TCHAR* exe_path, const TCHAR* cmd_line);

-

-// (Un)Registers a COM Service with the system.

-HRESULT RegisterService(const TCHAR* exe_path);

-HRESULT UnregisterService(const TCHAR* exe_path);

-

-// Starts a service.

-HRESULT RunService(const TCHAR* service_name);

-

-// Read an entire file into a memory buffer. Use this function when you need

-// exclusive access to the file.

-// Returns MEM_E_INVALID_SIZE if the file size is larger than max_len (unless

-// max_len == 0, in which case it is ignored)

-HRESULT ReadEntireFile(const TCHAR* filepath,

-                       uint32 max_len,

-                       std::vector<byte>* buffer_out);

-

-// Allows specifying a sharing mode such as FILE_SHARE_READ. Otherwise,

-// this is identical to ReadEntireFile.

-HRESULT ReadEntireFileShareMode(const TCHAR* filepath,

-                                uint32 max_len,

-                                DWORD share_mode,

-                                std::vector<byte>* buffer_out);

-

-// Writes an entire file from a memory buffer

-HRESULT WriteEntireFile(const TCHAR * filepath,

-                        const std::vector<byte>& buffer_in);

-

-// Conversions between a byte stream and a std::string

-HRESULT BufferToString(const std::vector<byte>& buffer_in, CStringA* str_out);

-HRESULT BufferToString(const std::vector<byte>& buffer_in, CString* str_out);

-HRESULT StringToBuffer(const CStringA& str_in, std::vector<byte>* buffer_out);

-HRESULT StringToBuffer(const CString& str_in, std::vector<byte>* buffer_out);

-

-// Splits a "full regkey name" into a key name part and a value name part.

-// Handles "(default)" as a value name.  Treats a trailing "/" as "(default)".

-HRESULT RegSplitKeyvalueName(const CString& keyvalue_name,

-                             CString* key_name,

-                             CString* value_name);

-

-// Expands string with embedded special variables which are enclosed

-// in '%' pair. For example, "%PROGRAMFILES%\Google" expands to

-// "C:\Program Files\Google".

-// If any of the embedded variable can not be expanded, we will leave it intact

-// and return HRESULT_FROM_WIN32(ERROR_NOT_FOUND)

-HRESULT ExpandEnvLikeStrings(const TCHAR* src,

-                             const std::map<CString, CString>& keywords,

-                             CString* dest);

-

-// Returns true if the path represents a registry path.

-bool IsRegistryPath(const TCHAR* path);

-

-// Returns true if the path is a URL.

-bool IsUrl(const TCHAR* path);

-

-// Converts GUID to string.

-CString GuidToString(const GUID& guid);

-

-// Converts string to GUID.

-GUID StringToGuid(const CString& str);

-

-// Converts a variant containing a list of strings.

-void VariantToStringList(VARIANT var, std::vector<CString>* list);

-

-// Appends two registry key paths, takes care of extra separators in the

-// beginning or end of the key.

-CString AppendRegKeyPath(const CString& one, const CString& two);

-CString AppendRegKeyPath(const CString& one,

-                         const CString& two,

-                         const CString& three);

-

-// Returns the list of user keys that are present within the HKEY_USERS key

-// the method only returns the keys of the users and takes care of,

-// removing the well known sids. The returned values are the complete values

-// from the root of the registry

-HRESULT GetUserKeysFromHkeyUsers(std::vector<CString>* key_names);

-

-// Use when a function should be able to

-// be replaced with another implementation. Usually,

-// this is done for testing code only.

-//

-// Typical usage:

-//

-//  typedef bool BoolPreferenceFunctionType();

-//  CallInterceptor<BoolPreferenceFunctionType> should_send_stats_interceptor;

-//  BoolPreferenceFunctionType* ReplaceShouldSendStatsFunction(

-//      BoolPreferenceFunctionType* replacement) {

-//    return should_send_stats_interceptor.ReplaceFunction(replacement);

-//  }

-template <typename R>

-class CallInterceptor {

- public:

-  CallInterceptor() {

-    interceptor_ = NULL;

-  }

-

-  R* ReplaceFunction(R* replacement) {

-    R* old = interceptor_;

-    interceptor_ = replacement;

-    return old;

-  }

-

-  R* interceptor() {

-    return interceptor_;

-  }

-

- private:

-  R* interceptor_;

-  DISALLOW_EVIL_CONSTRUCTORS(CallInterceptor);

-};

-

-// Gets a handle of the current process. The handle is a real handle

-// and the caller must close it

-HRESULT GetCurrentProcessHandle(HANDLE* handle);

-

-// Helper class for an ATL module that registers a custom AccessPermission

-// to allow local calls from interactive users and the system account.

-// Derive from this class as well as CAtlModuleT (or a derivative).

-// Override RegisterAppId() and UnregisterAppId(), and delegate to the

-// corresponding functions in this class.

-template <class T>

-class LocalCallAccessPermissionHelper {

- public:

-  HRESULT RegisterAppId() throw() {

-    // Local call permissions allowed for Interactive Users and Local System

-    static LPCTSTR ALLOW_LOCAL_CALL_SDDL =

-        _T("O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)");

-

-    UTIL_LOG(L1, (_T("[LocalCallAccessPermissionHelper::RegisterAppId]")));

-

-    // First call the base ATL module implementation, so the AppId is registered

-    RET_IF_FAILED(T::UpdateRegistryAppId(TRUE));

-

-    // Next, write the AccessPermission value

-    RegKey key_app_id;

-    RET_IF_FAILED(key_app_id.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE));

-

-    RegKey key;

-    RET_IF_FAILED(key.Create(key_app_id.Key(), T::GetAppIdT()));

-    CSecurityDesc sd;

-    RET_IF_FALSE(sd.FromString(ALLOW_LOCAL_CALL_SDDL), HRESULTFromLastError());

-    RET_IF_FAILED(key.SetValue(

-        _T("AccessPermission"),

-        reinterpret_cast<const byte*>(sd.GetPSECURITY_DESCRIPTOR()),

-        sd.GetLength()));

-

-    UTIL_LOG(L1, (_T("[LocalCallAccessPermissionHelper::RegisterAppId]")

-                  _T("[succeeded]")));

-    return S_OK;

-  }

-

-  HRESULT UnregisterAppId() throw() {

-    // First remove the AccesPermission entry.

-    RegKey key_app_id;

-    RET_IF_FAILED(key_app_id.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE));

-

-    RegKey key;

-    RET_IF_FAILED(key.Open(key_app_id.Key(), T::GetAppIdT(), KEY_WRITE));

-    VERIFY1(SUCCEEDED(key.DeleteValue(_T("AccessPermission"))));

-

-    // Now, call the base ATL module implementation to unregister the AppId

-    RET_IF_FAILED(T::UpdateRegistryAppId(FALSE));

-

-    UTIL_LOG(L1, (_T("[LocalCallAccessPermissionHelper::UnregisterAppId'")

-                  _T("[succeeded]")));

-    return S_OK;

-  }

-};

-

-// Returns true if the argument is a guid.

-inline bool IsGuid(const TCHAR* s) {

-  if (!s) return false;

-  GUID guid = {0};

-  return SUCCEEDED(::CLSIDFromString(const_cast<TCHAR*>(s), &guid));

-}

-

-inline bool IsLocalSystemSid(const TCHAR* sid) {

-  ASSERT1(sid);

-  return _tcsicmp(sid, kLocalSystemSid) == 0;

-}

-

-// Fills a buffer with cryptographically random bytes.

-bool GenRandom(void* buffer, size_t buffer_length);

-

-// Deletes an object. The functor is useful in for_each algorithms.

-struct DeleteFun {

-  template <class T> void operator()(T ptr) { delete ptr; }

-};

-

-// Sets or clears the specified value in the Run key to the specified command.

-HRESULT ConfigureRunAtStartup(const CString& root_key_name,

-                              const CString& run_value_name,

-                              const CString& command,

-                              bool install);

-

-// Cracks a command line and returns the program name, which is the first

-// whitespace separated token.

-HRESULT GetExePathFromCommandLine(const TCHAR* command_line,

-                                  CString* exe_path);

-

-// Waits for MSI to complete, if MSI is busy installing or uninstalling apps.

-HRESULT WaitForMSIExecute(int timeout_ms);

-

-// Returns the value of the specified environment variable.

-CString GetEnvironmentVariableAsString(const TCHAR* name);

-

-// Returns true if the OS is installing (e.g., at an OEM factory).

-bool IsWindowsInstalling();

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_UTILS_H__

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_UTILS_H__
+#define OMAHA_COMMON_UTILS_H__
+
+#include <windows.h>
+#include <accctrl.h>
+#include <aclapi.h>
+#include <sddl.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <atlstr.h>
+#include <atlsecurity.h>
+#include <atlwin.h>
+#include <memory.h>
+#include <map>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/static_assert.h"
+#include "omaha/common/user_info.h"
+
+namespace omaha {
+
+// Determines whether to run ClickOnce components. This constant is not defined
+// in the SDK headers.
+#ifndef URLACTION_MANAGED_UNSIGNED
+#define URLACTION_MANAGED_UNSIGNED (0x00002004)
+#endif
+
+ULONGLONG VersionFromString(const CString& s);
+
+CString StringFromVersion(ULONGLONG version);
+
+// Gets current directory
+CString GetCurrentDir();
+
+// Creates a unique file name using a new guid. Does not check for
+// presence of this file in the directory.
+HRESULT GetNewFileNameInDirectory(const CString& dir, CString* file_name);
+
+// Use of this method is unsafe. Be careful!
+// Gets security attributes for a "everyone" (authenticated users) DACL.
+void GetEveryoneDaclSecurityAttributes(CSecurityAttributes* sec_attr,
+                                       ACCESS_MASK non_admin_access_mask);
+
+// Get security attributes containing a DACL that grant the ACCESS_MASK access
+// to admins and system.
+void GetAdminDaclSecurityAttributes(CSecurityAttributes* sec_attr,
+                                    ACCESS_MASK accessmask);
+
+// Merges an Allowed ACE into a named object. If the ACE already exists in the
+// DACL with the same permissions (or a superset) and the same ACE flags, the
+// merge is skipped.
+HRESULT AddAllowedAce(const TCHAR* object_name,
+                      SE_OBJECT_TYPE object_type,
+                      const CSid& sid,
+                      ACCESS_MASK required_permissions,
+                      uint8 required_ace_flags);
+
+struct NamedObjectAttributes {
+  CString name;
+  CSecurityAttributes sa;
+};
+
+// For machine and local system, the prefix would be "Global\G{obj_name}".
+// For user, the prefix would be "Global\G{user_sid}{obj_name}".
+// For machine objects, returns a security attributes that gives permissions to
+// both Admins and SYSTEM. This allows for cases where SYSTEM creates the named
+// object first. The default DACL for SYSTEM will not allow Admins access.
+void GetNamedObjectAttributes(const TCHAR* base_name,
+                              bool is_machine,
+                              NamedObjectAttributes* attr);
+
+// Returns true if the current process is running as SYSTEM.
+HRESULT IsSystemProcess(bool* is_system_process);
+
+// Returns true if the user of the current process is Local System or it has an
+// interactive session: console, terminal services, or fast user switching.
+HRESULT IsUserLoggedOn(bool* is_logged_on);
+
+// Returns true if URLACTION_MANAGED_UNSIGNED is disabled for the Internet zone
+// for the current user.
+bool IsClickOnceDisabled();
+
+// Wrapper around ::GetProcAddress().
+template <typename T>
+bool GPA(HMODULE module, const char* function_name, T* function_pointer) {
+  ASSERT1(module);
+  ASSERT1(function_name);
+  ASSERT1(function_pointer);
+
+  *function_pointer = reinterpret_cast<T>(::GetProcAddress(module,
+                                                           function_name));
+  if (NULL == *function_pointer) {
+    UTIL_LOG(LW, (_T("GetProcAddress failed [%s]"), CA2T(function_name)));
+  }
+  return NULL != *function_pointer;
+}
+
+#define GPA_WRAP(module,                                                    \
+                 function,                                                  \
+                 proto,                                                     \
+                 call,                                                      \
+                 calling_convention,                                        \
+                 result_type,                                               \
+                 result_error)                                              \
+typedef result_type (calling_convention *function##_pointer) proto;         \
+inline result_type function##Wrap proto {                                   \
+  HINSTANCE module_instance = ::GetModuleHandle(_T(#module));               \
+  ASSERT1(module_instance);                                                 \
+  if (!module_instance) {                                                   \
+    return result_error;                                                    \
+  }                                                                         \
+  function##_pointer fn = NULL;                                             \
+  return GPA(module_instance, #function, &fn) ? (*fn) call : result_error;  \
+}
+
+GPA_WRAP(kernel32.dll,
+         AttachConsole,
+         (DWORD process_id),
+         (process_id),
+         WINAPI,
+         BOOL,
+         0);
+
+// Private Object Namespaces for Vista and above. More information here:
+// http://msdn2.microsoft.com/en-us/library/ms684295(VS.85).aspx
+GPA_WRAP(kernel32.dll,
+         CreateBoundaryDescriptorW,
+         (LPCWSTR boundary_name, ULONG flags),
+         (boundary_name, flags),
+         WINAPI,
+         HANDLE,
+         NULL);
+GPA_WRAP(kernel32.dll,
+         AddSIDToBoundaryDescriptor,
+         (HANDLE* boundary_descriptor, PSID required_sid),
+         (boundary_descriptor, required_sid),
+         WINAPI,
+         BOOL,
+         FALSE);
+GPA_WRAP(kernel32.dll,
+         CreatePrivateNamespaceW,
+         (LPSECURITY_ATTRIBUTES private_namespace_attributes, LPVOID boundary_descriptor, LPCWSTR alias_prefix),  // NOLINT
+         (private_namespace_attributes, boundary_descriptor, alias_prefix),
+         WINAPI,
+         HANDLE,
+         NULL);
+GPA_WRAP(kernel32.dll,
+         OpenPrivateNamespaceW,
+         (LPVOID boundary_descriptor, LPCWSTR alias_prefix),
+         (boundary_descriptor, alias_prefix),
+         WINAPI,
+         HANDLE,
+         NULL);
+
+bool IsPrivateNamespaceAvailable();
+
+
+HRESULT PinModuleIntoProcess(const CString& module_name);
+
+// Creates a directory with default security.
+//   S_OK:    Created directory
+//   S_FALSE: Directory already existed
+//   E_FAIL:  Couldn't create
+HRESULT CreateDir(const TCHAR* dirname, LPSECURITY_ATTRIBUTES security_attr);
+
+// Gets the path for the specified special folder.
+HRESULT GetFolderPath(int csidl, CString* path);
+
+// Returns true if this directory name is 'safe' for deletion:
+//  - it doesn't contain ".."
+//  - it doesn't specify a drive root
+bool SafeDirectoryNameForDeletion(const TCHAR* dir_name);
+
+// Deletes a directory.
+HRESULT DeleteDirectory(const TCHAR* ir_name);
+
+// Deletes all files in a directory.
+HRESULT DeleteDirectoryFiles(const TCHAR* dir_name);
+
+// Deletes all files in a directory matching a wildcard.
+HRESULT DeleteWildcardFiles(const TCHAR* dir_name, const TCHAR* wildcard_name);
+
+// Deletes either a file or directory before or after reboot.
+HRESULT DeleteBeforeOrAfterReboot(const TCHAR* targetname);
+
+// Gets the size of all files in a directory.
+// Aborts counting if one of the maximum criteria is reached.
+HRESULT SafeGetDirectorySize(const TCHAR* dir_name,
+                             uint64* size,
+                             HANDLE shutdown_event,
+                             uint64 max_size,
+                             int max_depth,
+                             int max_file_count,
+                             int max_running_time_ms);
+
+// Gets size of all files in a directory.
+HRESULT GetDirectorySize(const TCHAR* dir_name, uint64* size);
+
+enum TimeCategory {
+  PAST = 0,  // older than 40 years from now
+  FUTURE,    // in the future by > 1 day
+  PRESENT,   // neither ANCIENT nor FUTURE
+};
+
+TimeCategory GetTimeCategory(time64 t);
+
+// Returns true if a given time is likely to be valid.
+bool IsValidTime(time64 t);
+
+// Gets a time64 value.
+// If the value is greater than the
+// max value, then SetValue will be called using the max_value.
+//
+//  Args:
+//   full_key_name:   the reg keyto read to get the time value.
+//   value_name:      the name for the reg key value to be read.
+//                    (may be NULL to get the default value)
+//   max_time:        the maximum value for the reg key.
+//   value:           the time value read.  May not be set on failure.
+//   limited_value:   true iff will be set if the value was
+//                    changed (and resaved). (NULL is allowable.)
+HRESULT GetLimitedTimeValue(const TCHAR* full_key_name,
+                            const TCHAR* value_name,
+                            time64 max_time,
+                            time64* value,
+                            bool* limited_value);
+
+// Gets a time64 value trying reg keys successively if there is a
+// failure in getting a value.
+//
+// Typically used when there is a user value and a default value if the
+// user has none.
+//
+//  Args:
+//   full_key_names:  a list of reg keys to try successively (starting
+//                    with index 0) to read to get the time value.  The
+//                    attempts stops as soon as there is a successful read or
+//                    when all keys have been tried.
+//   key_names_length: number of keys in full_key_names.
+//   value_name:      the name for the reg key value to be read.
+//                    (may be NULL to get the default value)
+//   max_time:        the maximum value for the reg key.
+//   value:           the time value read.  May not be set on failure.
+//   limited_value:   true iff will be set if the value was
+//                    changed (and resaved). (NULL is allowable.)
+HRESULT GetLimitedTimeValues(const TCHAR* full_key_names[],
+                             int key_names_length,
+                             const TCHAR* value_name,
+                             time64 max_time,
+                             time64* value,
+                             bool* limited_value);
+
+// Convert milliseconds to a relative time in units of 100ns, suitable for use
+// with waitable timers
+LARGE_INTEGER MSto100NSRelative(DWORD ms);
+
+// TODO(omaha): remove from public interface.
+inline void WINAPI NullAPCFunc(ULONG_PTR) {}
+
+// Forces rasman.dll load to avoid a crash in wininet.
+void EnsureRasmanLoaded();
+
+// Returns if the HRESULT argument is a COM error
+// TODO(omaha): use an ANONYMOUS_VARIABLE to avoid the situation in which the
+// macro gets called like RET_IF_FAILED(hr);
+// For now, use a quick fix hr -> __hr. Leading underscore names are not to be
+// used in application code.
+#define RET_IF_FAILED(x)    \
+    do {                    \
+      HRESULT __hr(x);      \
+      if (FAILED(__hr)) {   \
+        return __hr;        \
+      }                     \
+    } while (false)
+
+// return error if the first argument evaluates to false
+#define RET_IF_FALSE(x, err)  \
+  do {                        \
+    if (!(x)) {               \
+      return err;             \
+    }                         \
+  } while (false)
+
+// return false if the HRESULT argument is a COM error
+#define RET_FALSE_IF_FAILED(x)  \
+  do {                          \
+    if (FAILED(x)) {            \
+      return false;             \
+    }                           \
+  } while (false)
+
+// return true if the HRESULT argument is a COM error
+#define RET_TRUE_IF_FAILED(x)   \
+  do {                          \
+    if (FAILED(x)) {            \
+      return true;              \
+    }                           \
+  } while (false)
+
+// return if the HRESULT argument evaluates to FAILED - but also assert
+// if failed
+#define RET_IF_FAILED_ASSERT(x, msg) \
+    do {                             \
+      HRESULT hr(x);                 \
+      if (FAILED(hr)) {              \
+        ASSERT(false, msg);          \
+        return hr;                   \
+      }                              \
+    } while (false)
+
+
+// return if the HRESULT argument evaluates to FAILED - but also log an error
+// message if failed
+#define RET_IF_FAILED_LOG(x, cat, msg) \
+    do {                               \
+      HRESULT hr(x);                   \
+      if (FAILED(hr)) {                \
+        LC_LOG(cat, LEVEL_ERROR, msg); \
+        return hr;                     \
+      }                                \
+    } while (false)
+
+// return if the HRESULT argument evaluates to FAILED - but also REPORT an error
+// message if failed
+#define RET_IF_FAILED_REPORT(x, msg, n) \
+    do {                                \
+      HRESULT hr(x);                    \
+      if (FAILED(hr)) {                 \
+        REPORT(false, R_ERROR, msg, n); \
+        return hr;                      \
+      }                                 \
+    } while (false)
+
+// Initializes a POD to zero.
+// Using this function requires discipline. Don't use for types that have a
+// v-table or virtual bases.
+template <typename T>
+inline void SetZero(T& p) {   // NOLINT
+  // Guard against the easy mistake of
+  //    foo(int *p) { SetZero(p); } instead of
+  //                  SetZero(*p);
+  // which it should be.
+  STATIC_ASSERT(sizeof(p) != sizeof(void*));    // NOLINT
+
+  // A POD (plain old data) object has one of these data types:
+  // a fundamental type, union, struct, array,
+  // or class--with no constructor. PODs don't have virtual functions or
+  // virtual bases.
+
+  // Test to see if the type has constructors.
+  union CtorTest {
+      T t;
+      int i;
+  };
+
+  // TODO(omaha): There might be a way to test if the type has virtuals
+  // For now, if we zero a type with virtuals by mistake, it is going to crash
+  // predictable at run-time when the virtuals are called.
+
+  memset(&p, 0, sizeof(T));
+}
+
+inline void SecureSetZero(CString* p) {
+  ASSERT1(p);
+  if (!p->IsEmpty()) {
+    ::SecureZeroMemory(p->GetBufferSetLength(p->GetLength()),
+                       p->GetLength() * sizeof(TCHAR));
+    p->ReleaseBuffer();
+  }
+}
+
+inline void SecureSetZero(CComVariant* p) {
+  ASSERT1(p);
+  ASSERT1(V_VT(p) == VT_BSTR);
+  uint32 byte_len = ::SysStringByteLen(V_BSTR(p));
+  if (byte_len > 0) {
+    ::SecureZeroMemory(V_BSTR(p), byte_len);
+  }
+}
+
+// CreateForegroundParentWindowForUAC creates a WS_POPUP | WS_VISIBLE with zero
+// size, of the STATIC WNDCLASS. It uses the default running EXE module
+// handle for creation.
+//
+// A visible centered foreground window is needed as the parent in Windows 7 and
+// above, to allow the UAC prompt to come up in the foreground, centered.
+// Otherwise, the elevation prompt will be minimized on the taskbar. A zero size
+// window works. A plain vanilla WS_POPUP allows the window to be free of
+// adornments. WS_EX_TOOLWINDOW prevents the task bar from showing the
+// zero-sized window.
+//
+// Returns NULL on failure. Call ::GetLastError() to get extended error
+// information on failure.
+inline HWND CreateForegroundParentWindowForUAC() {
+  CWindow foreground_parent;
+  if (foreground_parent.Create(_T("STATIC"), NULL, NULL, NULL,
+                               WS_POPUP | WS_VISIBLE, WS_EX_TOOLWINDOW)) {
+    foreground_parent.CenterWindow(NULL);
+    ::SetForegroundWindow(foreground_parent);
+  }
+  return foreground_parent.Detach();
+}
+
+// TODO(omaha): move the definition and ShellExecuteExEnsureParent function
+// below into shell.h
+
+#if (NTDDI_VERSION < NTDDI_WINXPSP1)
+// This value is not defined in the header, but has no effect on older OSes.
+#define SEE_MASK_NOZONECHECKS      0x00800000
+#endif
+
+// ShellExecuteExEnsureParent is a wrapper around ::ShellExecuteEx.
+// It ensures that we always have a parent window. In elevation scenarios, we
+// need to use the HWND property to be acknowledged as a foreground application
+// on Windows Vista. Otherwise, the elevation prompt will appear minimized on
+// the taskbar The UAC elevation mechanism uses the HWND as part of determining
+// whether the elevation is a foreground elevation.
+//
+// A better place for this might be in the Process class. However, to
+// reduce dependencies for the stub, placing this in utils.
+//
+// Return values:
+//   ShellExecuteExEnsureParent returns TRUE on success, and FALSE on failure.
+//   Call ::GetLastError() to get the extended error information on failure.
+//
+// Args:
+//   shell_exec_info structure pointer, filled in, with an optional HWND.
+//   The structure is not validated. If the HWND is NULL, it creates one.
+bool ShellExecuteExEnsureParent(LPSHELLEXECUTEINFO shell_exec_info);
+
+//
+// Wait with a message loop.
+// Returns true if the wait completed successfully and false in case of an
+// error.
+//
+
+// Waits with a message loop until any of the synchronization objects is
+// signaled. Return the index of the object that satisfied the wait.
+bool WaitWithMessageLoopAny(const std::vector<HANDLE>& handles, uint32* pos);
+
+// Waits with message loop until all the synchronization objects are signaled.
+bool WaitWithMessageLoopAll(const std::vector<HANDLE>& handles);
+
+// Waits with message loop until the synchronization object is signaled.
+bool WaitWithMessageLoop(HANDLE h);
+
+// Waits with message loop for a certain period of time
+bool WaitWithMessageLoopTimed(DWORD ms);
+
+//
+// TODO(omaha): message handler classes should go in other module.
+//
+// Handles windows messages
+class MessageHandlerInterface {
+ public:
+  virtual ~MessageHandlerInterface() {}
+  // Does the translate/dispatch for one window message
+  // msg is never NULL.
+  virtual void Process(MSG* msg) = 0;
+};
+
+// The simplest working implementation of a message handler.
+// It does TranslateMessage/DispatchMessage.
+class BasicMessageHandler : public MessageHandlerInterface {
+ public:
+  BasicMessageHandler() {}
+  virtual void Process(MSG* msg);
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(BasicMessageHandler);
+};
+
+// An internal detail (used to handle messages
+// and adjust the handles/cnt as needed).
+class MessageHandlerInternalInterface {
+ public:
+  virtual ~MessageHandlerInternalInterface() {}
+  // Does the translate/dispatch for one window message
+  // msg is never NULL and may change the handles and cnt (which are
+  // never NULL).
+  virtual void Process(MSG* msg, const HANDLE** handles, uint32* cnt) = 0;
+};
+
+// The callback for MessageLoopInterface::RegisterWaitForSingleObject
+class WaitCallbackInterface {
+ public:
+  virtual ~WaitCallbackInterface() {}
+  // Return false from this method to terminate the message loop.
+  virtual bool HandleSignaled(HANDLE handle) = 0;
+};
+
+// This is similar to a threadpool interface
+// but this is done on the main message loop instead.
+//
+// Important: These method calls are *not* threadsafe and
+// should only be done on the message loop thread.
+class MessageLoopInterface {
+ public:
+  virtual ~MessageLoopInterface() {}
+  // sets-up a callback for when the handle becomes signaled
+  //   * the callback happens on the main thread.
+  //   * the handle/callback is removed when
+  //     the callback is made.
+  //   * If the handle becomes invalid while it is being waited on,
+  //     the message loop will exit.
+  //   * If the handle has already been registered,
+  //     then adding it again will essentially replace the
+  //     previous callback with the new one.
+  virtual bool RegisterWaitForSingleObject(HANDLE handle,
+                                           WaitCallbackInterface* callback) = 0;
+
+  // stops watching for the handle to be signaled
+  virtual bool UnregisterWait(HANDLE handle) = 0;
+};
+
+// An implementation of the MessageLoopInterface
+class MessageLoopWithWait : public MessageLoopInterface,
+                            private MessageHandlerInternalInterface {
+ public:
+  MessageLoopWithWait();
+
+  // This method needs to be called before the "Process()"
+  // method or else "Process()" will crash.
+  //
+  // Args:
+  //    message_handler: handles any messages that occur
+  //       *Note* It is the callers responsibility to keep
+  //       message_handler around while this class exists
+  //       and the *caller* should free message_handler
+  //       after that.
+  void set_message_handler(MessageHandlerInterface* message_handler);
+
+  // sets-up a callback for when the handle becomes signaled
+  virtual bool RegisterWaitForSingleObject(HANDLE handle,
+                                           WaitCallbackInterface* callback);
+
+  // stops watching for the handle to be signaled
+  virtual bool UnregisterWait(HANDLE handle);
+
+  // The message loop and handle callback routine
+  HRESULT Process();
+
+ private:
+  // Handles one messgae and adjus tthe handles and cnt as appropriate after
+  // handling the message
+  virtual void Process(MSG* msg, const HANDLE** handles, uint32* cnt);
+
+  void RemoveHandleAt(uint32 pos);
+
+  MessageHandlerInterface* message_handler_;
+
+  // Handles that are checked for being signaled.
+  std::vector<HANDLE> callback_handles_;
+
+  // What to call when a handle is signaled.
+  std::vector<WaitCallbackInterface*> callbacks_;
+  DISALLOW_EVIL_CONSTRUCTORS(MessageLoopWithWait);
+};
+
+// Calls an entry point that may be exposed from a DLL
+//   It is an error if the DLL is missing or can't be loaded
+//   If the entry point is missing the error returned is
+//   ERROR_INVALID_FUNCTION (as an HRESULT).
+//   Otherwise, if the function is called successfully then
+//   CallEntryPoint0 return S_OK and the result parameter is set to the
+//   return value from the function call.
+HRESULT CallEntryPoint0(const TCHAR* dll_path,
+                        const char* function_name,
+                        HRESULT* result);
+
+// (Un)Registers a COM DLL with the system.  Returns S_FALSE if entry
+// point missing (so that it you can call (Un)RegisterDll on any DLL
+// without worrying whether the DLL is actually a COM server or not).
+HRESULT RegisterDll(const TCHAR* dll_path);
+HRESULT UnregisterDll(const TCHAR* dll_path);
+
+// (Un)Registers a COM Local Server with the system.
+HRESULT RegisterServer(const TCHAR* exe_path);
+HRESULT UnregisterServer(const TCHAR* exe_path);
+HRESULT RegisterOrUnregisterExe(const TCHAR* exe_path, const TCHAR* cmd_line);
+
+// (Un)Registers a COM Service with the system.
+HRESULT RegisterService(const TCHAR* exe_path);
+HRESULT UnregisterService(const TCHAR* exe_path);
+
+// Starts a service.
+HRESULT RunService(const TCHAR* service_name);
+
+// Read an entire file into a memory buffer. Use this function when you need
+// exclusive access to the file.
+// Returns MEM_E_INVALID_SIZE if the file size is larger than max_len (unless
+// max_len == 0, in which case it is ignored)
+HRESULT ReadEntireFile(const TCHAR* filepath,
+                       uint32 max_len,
+                       std::vector<byte>* buffer_out);
+
+// Allows specifying a sharing mode such as FILE_SHARE_READ. Otherwise,
+// this is identical to ReadEntireFile.
+HRESULT ReadEntireFileShareMode(const TCHAR* filepath,
+                                uint32 max_len,
+                                DWORD share_mode,
+                                std::vector<byte>* buffer_out);
+
+// Writes an entire file from a memory buffer
+HRESULT WriteEntireFile(const TCHAR * filepath,
+                        const std::vector<byte>& buffer_in);
+
+// Conversions between a byte stream and a std::string
+HRESULT BufferToString(const std::vector<byte>& buffer_in, CStringA* str_out);
+HRESULT BufferToString(const std::vector<byte>& buffer_in, CString* str_out);
+HRESULT StringToBuffer(const CStringA& str_in, std::vector<byte>* buffer_out);
+HRESULT StringToBuffer(const CString& str_in, std::vector<byte>* buffer_out);
+
+// Splits a "full regkey name" into a key name part and a value name part.
+// Handles "(default)" as a value name.  Treats a trailing "/" as "(default)".
+HRESULT RegSplitKeyvalueName(const CString& keyvalue_name,
+                             CString* key_name,
+                             CString* value_name);
+
+// Expands string with embedded special variables which are enclosed
+// in '%' pair. For example, "%PROGRAMFILES%\Google" expands to
+// "C:\Program Files\Google".
+// If any of the embedded variable can not be expanded, we will leave it intact
+// and return HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
+HRESULT ExpandEnvLikeStrings(const TCHAR* src,
+                             const std::map<CString, CString>& keywords,
+                             CString* dest);
+
+// Returns true if the path represents a registry path.
+bool IsRegistryPath(const TCHAR* path);
+
+// Returns true if the path is a URL.
+bool IsUrl(const TCHAR* path);
+
+// Converts GUID to string.
+CString GuidToString(const GUID& guid);
+
+// Converts string to GUID.
+GUID StringToGuid(const CString& str);
+
+// Converts a variant containing a list of strings.
+void VariantToStringList(VARIANT var, std::vector<CString>* list);
+
+// Appends two registry key paths, takes care of extra separators in the
+// beginning or end of the key.
+CString AppendRegKeyPath(const CString& one, const CString& two);
+CString AppendRegKeyPath(const CString& one,
+                         const CString& two,
+                         const CString& three);
+
+// Returns the list of user keys that are present within the HKEY_USERS key
+// the method only returns the keys of the users and takes care of,
+// removing the well known sids. The returned values are the complete values
+// from the root of the registry
+HRESULT GetUserKeysFromHkeyUsers(std::vector<CString>* key_names);
+
+// Use when a function should be able to
+// be replaced with another implementation. Usually,
+// this is done for testing code only.
+//
+// Typical usage:
+//
+//  typedef bool BoolPreferenceFunctionType();
+//  CallInterceptor<BoolPreferenceFunctionType> should_send_stats_interceptor;
+//  BoolPreferenceFunctionType* ReplaceShouldSendStatsFunction(
+//      BoolPreferenceFunctionType* replacement) {
+//    return should_send_stats_interceptor.ReplaceFunction(replacement);
+//  }
+template <typename R>
+class CallInterceptor {
+ public:
+  CallInterceptor() {
+    interceptor_ = NULL;
+  }
+
+  R* ReplaceFunction(R* replacement) {
+    R* old = interceptor_;
+    interceptor_ = replacement;
+    return old;
+  }
+
+  R* interceptor() {
+    return interceptor_;
+  }
+
+ private:
+  R* interceptor_;
+  DISALLOW_EVIL_CONSTRUCTORS(CallInterceptor);
+};
+
+// Gets a handle of the current process. The handle is a real handle
+// and the caller must close it
+HRESULT GetCurrentProcessHandle(HANDLE* handle);
+
+// Helper class for an ATL module that registers a custom AccessPermission
+// to allow local calls from interactive users and the system account.
+// Derive from this class as well as CAtlModuleT (or a derivative).
+// Override RegisterAppId() and UnregisterAppId(), and delegate to the
+// corresponding functions in this class.
+template <class T>
+class LocalCallAccessPermissionHelper {
+ public:
+  HRESULT RegisterAppId() throw() {
+    // Local call permissions allowed for Interactive Users and Local System
+    static LPCTSTR ALLOW_LOCAL_CALL_SDDL =
+        _T("O:BAG:BAD:(A;;0x3;;;IU)(A;;0x3;;;SY)");
+
+    UTIL_LOG(L1, (_T("[LocalCallAccessPermissionHelper::RegisterAppId]")));
+
+    // First call the base ATL module implementation, so the AppId is registered
+    RET_IF_FAILED(T::UpdateRegistryAppId(TRUE));
+
+    // Next, write the AccessPermission value
+    RegKey key_app_id;
+    RET_IF_FAILED(key_app_id.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE));
+
+    RegKey key;
+    RET_IF_FAILED(key.Create(key_app_id.Key(), T::GetAppIdT()));
+    CSecurityDesc sd;
+    RET_IF_FALSE(sd.FromString(ALLOW_LOCAL_CALL_SDDL), HRESULTFromLastError());
+    RET_IF_FAILED(key.SetValue(
+        _T("AccessPermission"),
+        reinterpret_cast<const byte*>(sd.GetPSECURITY_DESCRIPTOR()),
+        sd.GetLength()));
+
+    UTIL_LOG(L1, (_T("[LocalCallAccessPermissionHelper::RegisterAppId]")
+                  _T("[succeeded]")));
+    return S_OK;
+  }
+
+  HRESULT UnregisterAppId() throw() {
+    // First remove the AccesPermission entry.
+    RegKey key_app_id;
+    RET_IF_FAILED(key_app_id.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE));
+
+    RegKey key;
+    RET_IF_FAILED(key.Open(key_app_id.Key(), T::GetAppIdT(), KEY_WRITE));
+    VERIFY1(SUCCEEDED(key.DeleteValue(_T("AccessPermission"))));
+
+    // Now, call the base ATL module implementation to unregister the AppId
+    RET_IF_FAILED(T::UpdateRegistryAppId(FALSE));
+
+    UTIL_LOG(L1, (_T("[LocalCallAccessPermissionHelper::UnregisterAppId'")
+                  _T("[succeeded]")));
+    return S_OK;
+  }
+};
+
+// Returns true if the argument is a guid.
+inline bool IsGuid(const TCHAR* s) {
+  if (!s) return false;
+  GUID guid = {0};
+  return SUCCEEDED(::CLSIDFromString(const_cast<TCHAR*>(s), &guid));
+}
+
+inline bool IsLocalSystemSid(const TCHAR* sid) {
+  ASSERT1(sid);
+  return _tcsicmp(sid, kLocalSystemSid) == 0;
+}
+
+// Fills a buffer with cryptographically random bytes.
+bool GenRandom(void* buffer, size_t buffer_length);
+
+// Deletes an object. The functor is useful in for_each algorithms.
+struct DeleteFun {
+  template <class T> void operator()(T ptr) { delete ptr; }
+};
+
+// Sets or clears the specified value in the Run key to the specified command.
+HRESULT ConfigureRunAtStartup(const CString& root_key_name,
+                              const CString& run_value_name,
+                              const CString& command,
+                              bool install);
+
+// Cracks a command line and returns the program name, which is the first
+// whitespace separated token.
+HRESULT GetExePathFromCommandLine(const TCHAR* command_line,
+                                  CString* exe_path);
+
+// Waits for MSI to complete, if MSI is busy installing or uninstalling apps.
+HRESULT WaitForMSIExecute(int timeout_ms);
+
+// Returns the value of the specified environment variable.
+CString GetEnvironmentVariableAsString(const TCHAR* name);
+
+// Returns true if the OS is installing (e.g., at an OEM factory).
+bool IsWindowsInstalling();
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_UTILS_H__
+
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
index 5185653..d28d815 100644
--- a/common/utils_unittest.cc
+++ b/common/utils_unittest.cc
@@ -1,590 +1,590 @@
-// Copyright 2003-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <ATLComTime.h>

-#include <atltypes.h>

-#include <atlwin.h>

-#include <map>

-#include <vector>

-#include "omaha/common/app_util.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/dynamic_link_kernel32.h"

-#include "omaha/common/file.h"

-#include "omaha/common/module_utils.h"

-#include "omaha/common/path.h"

-#include "omaha/common/shell.h"

-#include "omaha/common/string.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Make sure that the time functions work.

-TEST(UtilsTest, Time) {

-  // TODO(omaha): - add a test from string to time and back again.

-  // Further test the time converters.

-  time64 now = GetCurrent100NSTime();

-  ASSERT_TRUE(StringToTime(TimeToString(now)) == now);

-

-  // Test GetTimeCategory.

-  ASSERT_EQ(PAST,

-            GetTimeCategory(static_cast<time64>(0)));

-  ASSERT_EQ(PRESENT,

-            GetTimeCategory(static_cast<time64>(now)));

-  ASSERT_EQ(PRESENT,

-            GetTimeCategory(static_cast<time64>(now - kDaysTo100ns)));

-  ASSERT_EQ(PRESENT,

-            GetTimeCategory(static_cast<time64>(now - 365 * kDaysTo100ns)));

-  // A little bit in the future is also considered present.

-  ASSERT_EQ(PRESENT,

-            GetTimeCategory(static_cast<time64>(now + kDaysTo100ns)));

-  ASSERT_EQ(PRESENT,

-            GetTimeCategory(static_cast<time64>(

-                now - 30 * 365 * kDaysTo100ns)));

-  ASSERT_EQ(PAST,

-            GetTimeCategory(static_cast<time64>(

-                now - 50 * 365 * kDaysTo100ns)));

-  ASSERT_EQ(FUTURE,

-            GetTimeCategory(static_cast<time64>(now + kDaysTo100ns * 6)));

-  ASSERT_EQ(FUTURE,

-            GetTimeCategory(static_cast<time64>(now + 365 * kDaysTo100ns)));

-

-  // Test IsValidTime.

-  ASSERT_FALSE(IsValidTime(static_cast<time64>(0)));

-  ASSERT_TRUE(IsValidTime(static_cast<time64>(now)));

-  ASSERT_TRUE(IsValidTime(static_cast<time64>(now - 365 * kDaysTo100ns)));

-  ASSERT_TRUE(IsValidTime(static_cast<time64>(now - 10 * 365 * kDaysTo100ns)));

-  ASSERT_TRUE(IsValidTime(static_cast<time64>(now + kDaysTo100ns)));

-  ASSERT_FALSE(IsValidTime(static_cast<time64>(now - 50 * 365 * kDaysTo100ns)));

-  ASSERT_FALSE(IsValidTime(static_cast<time64>(now + 50 * 365 * kDaysTo100ns)));

-  ASSERT_FALSE(IsValidTime(static_cast<time64>(now + kDaysTo100ns * 6)));

-}

-

-TEST(UtilsTest, GetFolderPath_Success) {

-  CString path;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &path));

-  BOOL isWow64 = FALSE;

-  EXPECT_SUCCEEDED(Kernel32::IsWow64Process(GetCurrentProcess(), &isWow64));

-  CString expected_path = isWow64 ?

-      _T("C:\\Program Files (x86)") : _T("C:\\Program Files");

-  EXPECT_STREQ(expected_path, path);

-}

-

-TEST(UtilsTest, GetFolderPath_Errors) {

-  CString path;

-  EXPECT_EQ(E_INVALIDARG, GetFolderPath(0x7fff, &path));

-  EXPECT_TRUE(path.IsEmpty());

-  EXPECT_EQ(E_INVALIDARG, GetFolderPath(CSIDL_PROGRAM_FILES, NULL));

-}

-

-TEST(UtilsTest, CallEntryPoint0) {

-  HRESULT hr(E_FAIL);

-  ASSERT_FAILED(CallEntryPoint0(L"random-nonsense.dll", "foobar", &hr));

-}

-

-TEST(UtilsTest, ReadEntireFile) {

-  TCHAR directory[MAX_PATH] = {0};

-  ASSERT_TRUE(GetModuleDirectory(NULL, directory));

-  CString file_name;

-  file_name.AppendFormat(_T("%s\\declaration.txt"), directory);

-

-  std::vector<byte> buffer;

-  ASSERT_FAILED(ReadEntireFile(L"C:\\F00Bar\\ImaginaryFile", 0, &buffer));

-

-  ASSERT_SUCCEEDED(ReadEntireFile(file_name, 0, &buffer));

-  ASSERT_EQ(9405, buffer.size());

-  buffer.resize(0);

-  ASSERT_FAILED(ReadEntireFile(L"C:\\WINDOWS\\Greenstone.bmp", 1000, &buffer));

-}

-

-// TODO(omaha): Need a test for WriteEntireFile

-// TEST(UtilsTest, WriteEntireFile) {

-// }

-

-TEST(UtilsTest, RegSplitKeyvalueName) {

-  CString key_name, value_name;

-  ASSERT_SUCCEEDED(RegSplitKeyvalueName(CString(L"HKLM\\Foo\\"),

-                                        &key_name,

-                                        &value_name));

-  ASSERT_STREQ(key_name, L"HKLM\\Foo");

-  ASSERT_TRUE(value_name.IsEmpty());

-

-  ASSERT_SUCCEEDED(RegSplitKeyvalueName(CString(L"HKLM\\Foo\\(default)"),

-                                        &key_name,

-                                        &value_name));

-  ASSERT_STREQ(key_name, L"HKLM\\Foo");

-  ASSERT_TRUE(value_name.IsEmpty());

-

-  ASSERT_SUCCEEDED(RegSplitKeyvalueName(CString(L"HKLM\\Foo\\Bar"),

-                                        &key_name,

-                                        &value_name));

-  ASSERT_STREQ(key_name, L"HKLM\\Foo");

-  ASSERT_STREQ(value_name, L"Bar");

-}

-

-TEST(UtilsTest, ExpandEnvLikeStrings) {

-  std::map<CString, CString> mapping;

-  ASSERT_SUCCEEDED(Shell::GetSpecialFolderKeywordsMapping(&mapping));

-

-  CString out;

-  ASSERT_SUCCEEDED(ExpandEnvLikeStrings(

-      L"Foo%WINDOWS%Bar%SYSTEM%Zebra%WINDOWS%%SYSTEM%", mapping, &out));

-

-  // This should work, but CmpHelperSTRCASEEQ is not overloaded for wchars.

-  // ASSERT_STRCASEEQ(out, L"FooC:\\WINDOWSBarC:\\WINDOWS\\system32Zebra"

-  //                       L"C:\\WINDOWSC:\\WINDOWS\\system32");

-  ASSERT_EQ(out.CompareNoCase(L"FooC:\\WINDOWSBarC:\\WINDOWS\\system32Zebra"

-                              L"C:\\WINDOWSC:\\WINDOWS\\system32"),

-            0);

-  ASSERT_FAILED(ExpandEnvLikeStrings(L"Foo%WINDOWS%%BAR%Zebra", mapping, &out));

-}

-

-TEST(UtilsTest, GetCurrentProcessHandle) {

-  scoped_process proc;

-  ASSERT_SUCCEEDED(GetCurrentProcessHandle(address(proc)));

-  ASSERT_TRUE(valid(proc));

-}

-

-TEST(UtilsTest, IsGuid) {

-  ASSERT_FALSE(IsGuid(NULL));

-  ASSERT_FALSE(IsGuid(_T("")));

-  ASSERT_FALSE(IsGuid(_T("{}")));

-  ASSERT_FALSE(IsGuid(_T("a")));

-  ASSERT_FALSE(IsGuid(_T("CA3045BFA6B14fb8A0EFA615CEFE452C")));

-

-  // Missing {}

-  ASSERT_FALSE(IsGuid(_T("CA3045BF-A6B1-4fb8-A0EF-A615CEFE452C")));

-

-  // Invalid char X

-  ASSERT_FALSE(IsGuid(_T("{XA3045BF-A6B1-4fb8-A0EF-A615CEFE452C}")));

-

-  // Invalid binary char 0x200

-  ASSERT_FALSE(IsGuid(_T("{\0x200a3045bf-a6b1-4fb8-a0ef-a615cefe452c}")));

-

-  // Missing -

-  ASSERT_FALSE(IsGuid(_T("{CA3045BFA6B14fb8A0EFA615CEFE452C}")));

-

-  // Double quotes

-  ASSERT_FALSE(IsGuid(_T("\"{ca3045bf-a6b1-4fb8-a0ef-a615cefe452c}\"")));

-

-  ASSERT_TRUE(IsGuid(_T("{00000000-0000-0000-0000-000000000000}")));

-  ASSERT_TRUE(IsGuid(_T("{CA3045BF-A6B1-4fb8-A0EF-A615CEFE452C}")));

-  ASSERT_TRUE(IsGuid(_T("{ca3045bf-a6b1-4fb8-a0ef-a615cefe452c}")));

-}

-

-TEST(UtilsTest, VersionFromString_ValidVersion) {

-  EXPECT_EQ(MAKEDLLVERULL(42, 1, 21, 12345),

-            VersionFromString(_T("42.1.21.12345")));

-}

-

-TEST(UtilsTest, VersionFromString_VersionZero) {

-  EXPECT_EQ(0, VersionFromString(_T("0.0.0.0")));

-}

-

-TEST(UtilsTest, VersionFromString_VersionUpperLimits) {

-  EXPECT_EQ(MAKEDLLVERULL(0xffff, 0xffff, 0xffff, 0xffff),

-            VersionFromString(_T("65535.65535.65535.65535")));

-  EXPECT_EQ(0, VersionFromString(_T("65536.65536.65536.65536")));

-  EXPECT_EQ(0, VersionFromString(_T("1.2.65536.65536")));

-}

-

-TEST(UtilsTest, VersionFromString_IntegerOverflow) {

-  EXPECT_EQ(0, VersionFromString(_T("1.2.3.4294967296")));

-}

-

-TEST(UtilsTest, VersionFromString_NegativeVersion) {

-  EXPECT_EQ(0, VersionFromString(_T("1.2.3.-22")));

-}

-

-TEST(UtilsTest, VersionFromString_TooFewElements) {

-  EXPECT_EQ(0, VersionFromString(_T("1.1.1")));

-}

-

-TEST(UtilsTest, VersionFromString_ExtraPeriod) {

-  EXPECT_EQ(0, VersionFromString(_T("1.1.2.3.")));

-}

-

-TEST(UtilsTest, VersionFromString_TooManyElements) {

-  EXPECT_EQ(0, VersionFromString(_T("1.1.2.3.4")));

-}

-

-TEST(UtilsTest, VersionFromString_Char) {

-  EXPECT_EQ(0, VersionFromString(_T("1.B.3.4")));

-  EXPECT_EQ(0, VersionFromString(_T("1.2.3.B")));

-  EXPECT_EQ(0, VersionFromString(_T("1.2.3.9B")));

-}

-

-TEST(UtilsTest, StringFromVersion_ValidVersion) {

-  EXPECT_STREQ(_T("42.1.21.12345"),

-               StringFromVersion(MAKEDLLVERULL(42, 1, 21, 12345)));

-}

-

-TEST(UtilsTest, StringFromVersion_VersionZero) {

-  EXPECT_STREQ(_T("0.0.0.0"), StringFromVersion(0));

-}

-

-TEST(UtilsTest, StringFromVersion_VersionUpperLimits) {

-  EXPECT_STREQ(

-      _T("65535.65535.65535.65535"),

-      StringFromVersion(MAKEDLLVERULL(0xffff, 0xffff, 0xffff, 0xffff)));

-}

-

-TEST(UtilsTest, IsLocalSystemSid) {

-  EXPECT_TRUE(IsLocalSystemSid(kLocalSystemSid));

-  EXPECT_TRUE(IsLocalSystemSid(_T("S-1-5-18")));

-  EXPECT_TRUE(IsLocalSystemSid(_T("s-1-5-18")));

-

-  EXPECT_FALSE(IsLocalSystemSid(_T("")));

-  EXPECT_FALSE(IsLocalSystemSid(_T("S-1-5-17")));

-}

-

-// There is a very small probability the test could fail.

-TEST(UtilsTest, GenRandom) {

-  int random_int = 0;

-  EXPECT_TRUE(GenRandom(&random_int, sizeof(random_int)));

-  EXPECT_NE(random_int, 0);

-

-  int another_random_int = 0;

-  EXPECT_TRUE(GenRandom(&another_random_int, sizeof(another_random_int)));

-  EXPECT_NE(another_random_int, 0);

-

-  EXPECT_NE(random_int, another_random_int);

-}

-

-// Counts instances of the class.

-class Counter {

- public:

-  Counter() {

-    ++instance_count_;

-  }

-  ~Counter() {

-    --instance_count_;

-  }

-  static int instance_count() { return instance_count_; }

- private:

-  static int instance_count_;

-  DISALLOW_EVIL_CONSTRUCTORS(Counter);

-};

-

-int Counter::instance_count_ = 0;

-

-// Checks if the functor is actually calling the destructor of the type.

-TEST(UtilsTest, DeleteFun) {

-  EXPECT_EQ(Counter::instance_count(), 0);

-  Counter* counter = new Counter;

-  EXPECT_EQ(Counter::instance_count(), 1);

-  DeleteFun().operator()(counter);

-  EXPECT_EQ(Counter::instance_count(), 0);

-

-  // Checks if the template can be instantiated for some common built in types.

-  int* pointer_int = NULL;

-  DeleteFun().operator()(pointer_int);

-

-  const char* pointer_char = NULL;

-  DeleteFun().operator()(pointer_char);

-}

-

-TEST(UtilsTest, IsUserLoggedOn) {

-  bool is_logged_on(false);

-  ASSERT_HRESULT_SUCCEEDED(IsUserLoggedOn(&is_logged_on));

-  ASSERT_TRUE(is_logged_on);

-}

-

-TEST(UtilsTest, IsClickOnceDisabled) {

-  EXPECT_FALSE(IsClickOnceDisabled());

-}

-

-TEST(UtilsTest, ConfigureRunAtStartup) {

-  const TCHAR kRunKeyPath[] =

-      _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");

-

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideRegistryHives(kRegistryHiveOverrideRoot);

-

-  EXPECT_FALSE(RegKey::HasKey(kRunKeyPath));

-

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            ConfigureRunAtStartup(USER_KEY_NAME, _T("FooApp"),

-                                  _T("\"foo.exe\""), false));

-  EXPECT_FALSE(RegKey::HasKey(kRunKeyPath));

-

-  EXPECT_SUCCEEDED(ConfigureRunAtStartup(USER_KEY_NAME, _T("FooApp"),

-                                         _T("\"C:\\foo.exe\" /x"), true));

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kRunKeyPath, _T("FooApp"), &value));

-  EXPECT_STREQ(_T("\"C:\\foo.exe\" /x"), value);

-

-  EXPECT_SUCCEEDED(ConfigureRunAtStartup(USER_KEY_NAME, _T("FooApp"),

-                                         _T("\"foo.exe\""), false));

-  EXPECT_FALSE(RegKey::HasValue(kRunKeyPath, _T("FooApp")));

-  EXPECT_TRUE(RegKey::HasKey(kRunKeyPath));

-

-  RestoreRegistryHives();

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-TEST(UtilsTest, ValidPath) {

-  CString cmd_line =

-      _T("\"C:\\Program Files\\Internet Explorer\\iexplore.exe\" -nohome");

-  CString exe_path;

-  EXPECT_SUCCEEDED(GetExePathFromCommandLine(cmd_line, &exe_path));

-  EXPECT_STREQ(_T("C:\\Program Files\\Internet Explorer\\iexplore.exe"),

-               exe_path);

-}

-

-TEST(UtilsTest, InvalidPath) {

-  CString cmd_line = _T("");

-  CString exe_path;

-  EXPECT_FAILED(GetExePathFromCommandLine(cmd_line, &exe_path));

-  EXPECT_TRUE(exe_path.IsEmpty());

-}

-

-TEST(UtilsTest, PinModuleIntoProcess) {

-  const TCHAR module_name[] = _T("icmp.dll");

-  const void* kNullModule = NULL;

-

-  // The module should not be loaded at this time.

-  EXPECT_EQ(kNullModule, ::GetModuleHandle(module_name));

-

-  // Loads and unloads the module.

-  {

-    scoped_library module(::LoadLibrary(module_name));

-    EXPECT_TRUE(module);

-    EXPECT_NE(kNullModule, ::GetModuleHandle(module_name));

-  }

-  EXPECT_EQ(kNullModule, ::GetModuleHandle(module_name));

-

-  // Loads, pins, and unloads the module.

-  {

-    scoped_library module(::LoadLibrary(module_name));

-    EXPECT_TRUE(module);

-    EXPECT_NE(kNullModule, ::GetModuleHandle(module_name));

-    PinModuleIntoProcess(module_name);

-  }

-  EXPECT_NE(kNullModule, ::GetModuleHandle(module_name));

-}

-

-// Assumes Windows is installed on the C: drive.

-TEST(UtilsTest, GetEnvironmentVariableAsString) {

-  EXPECT_STREQ(_T("C:"), GetEnvironmentVariableAsString(_T("SystemDrive")));

-  EXPECT_STREQ(_T("Windows_NT"), GetEnvironmentVariableAsString(_T("OS")));

-  EXPECT_STREQ(_T(""), GetEnvironmentVariableAsString(_T("FOO")));

-}

-

-TEST(UtilsTest, IsWindowsInstalling_Normal) {

-  EXPECT_FALSE(IsWindowsInstalling());

-}

-

-TEST(UtilsTest, IsWindowsInstalling_Installing_Vista_InvalidValues) {

-  if (!vista_util::IsVistaOrLater()) {

-    return;

-  }

-

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideRegistryHives(kRegistryHiveOverrideRoot);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("")));

-  EXPECT_FALSE(IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("foo")));

-  EXPECT_FALSE(IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      static_cast<DWORD>(1)));

-  ExpectAsserts expect_asserts;  // RegKey asserts because value type is wrong.

-  EXPECT_FALSE(IsWindowsInstalling());

-

-  RestoreRegistryHives();

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-TEST(UtilsTest, IsWindowsInstalling_Installing_Vista_ValidStates) {

-  if (!vista_util::IsVistaOrLater()) {

-    return;

-  }

-

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideRegistryHives(kRegistryHiveOverrideRoot);

-

-  // These states return false in the original implementation.

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_COMPLETE")));

-  EXPECT_FALSE(IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE")));

-  EXPECT_FALSE(IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_OOBE")));

-  EXPECT_FALSE(IsWindowsInstalling());

-

-  // These states are specified in the original implementation.

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_UNDEPLOYABLE")));

-  EXPECT_TRUE(IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_AUDIT")));

-  EXPECT_TRUE(IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_AUDIT")));

-  EXPECT_TRUE(IsWindowsInstalling());

-

-  RestoreRegistryHives();

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-TEST(UtilsTest, AddAllowedAce) {

-  CString test_file_path = ConcatenatePath(

-      app_util::GetCurrentModuleDirectory(), _T("TestAddAllowedAce.exe"));

-  EXPECT_SUCCEEDED(File::Remove(test_file_path));

-

-  EXPECT_SUCCEEDED(File::Copy(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("GoogleUpdate.exe")),

-      test_file_path,

-      false));

-

-  CDacl dacl;

-  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));

-  const int original_ace_count = dacl.GetAceCount();

-

-  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,

-                                 SE_FILE_OBJECT,

-                                 Sids::Dialup(),

-                                 FILE_GENERIC_READ,

-                                 0));

-

-  dacl.SetEmpty();

-  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));

-  EXPECT_EQ(original_ace_count + 1, dacl.GetAceCount());

-

-  // Add the same access. No ACE is added.

-  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,

-                                 SE_FILE_OBJECT,

-                                 Sids::Dialup(),

-                                 FILE_GENERIC_READ,

-                                 0));

-  dacl.SetEmpty();

-  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));

-  EXPECT_EQ(original_ace_count + 1, dacl.GetAceCount());

-

-  // Add a subset of the existing access. No ACE is added.

-  EXPECT_EQ(FILE_READ_ATTRIBUTES, FILE_GENERIC_READ & FILE_READ_ATTRIBUTES);

-  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,

-                                 SE_FILE_OBJECT,

-                                 Sids::Dialup(),

-                                 FILE_READ_ATTRIBUTES,

-                                 0));

-  dacl.SetEmpty();

-  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));

-  EXPECT_EQ(original_ace_count + 1, dacl.GetAceCount());

-

-  // Add more access. An ACE is added.

-  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,

-                                 SE_FILE_OBJECT,

-                                 Sids::Dialup(),

-                                 FILE_ALL_ACCESS,

-                                 0));

-  dacl.SetEmpty();

-  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));

-  EXPECT_EQ(original_ace_count + 2, dacl.GetAceCount());

-

-  // TODO(omaha): An assert occurs because the ACE flags are being used on a

-  // file object. Add a new test to use a registry key.

-  ExpectAsserts expect_asserts;

-

-  // Different ACE flags. An ACE is added.

-  const BYTE kTestAce = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;

-  const BYTE kTestAceSubset = CONTAINER_INHERIT_ACE;

-  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,

-                                 SE_FILE_OBJECT,

-                                 Sids::Dialup(),

-                                 FILE_ALL_ACCESS,

-                                 kTestAce));

-  dacl.SetEmpty();

-  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));

-  EXPECT_EQ(original_ace_count + 3, dacl.GetAceCount());

-

-  // Subset of existing ACE flags. An ACE is added because flags must be exact.

-  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,

-                                 SE_FILE_OBJECT,

-                                 Sids::Dialup(),

-                                 FILE_ALL_ACCESS,

-                                 kTestAceSubset));

-  dacl.SetEmpty();

-  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));

-  EXPECT_EQ(original_ace_count + 4, dacl.GetAceCount());

-

-  // Same flags. An ACE should not be added because all values match.

-  // TODO(omaha): This does not work, possibly because the object is a file.

-  // Try the test using a registry key.

-  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,

-                                 SE_FILE_OBJECT,

-                                 Sids::Dialup(),

-                                 FILE_ALL_ACCESS,

-                                 kTestAceSubset));

-  dacl.SetEmpty();

-  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));

-  EXPECT_EQ(original_ace_count + 5, dacl.GetAceCount());

-

-  EXPECT_SUCCEEDED(File::Remove(test_file_path));

-}

-

-TEST(UtilsTest, CreateForegroundParentWindowForUAC) {

-  CWindow foreground_parent;

-  foreground_parent.Attach(CreateForegroundParentWindowForUAC());

-  EXPECT_TRUE(foreground_parent.IsWindow());

-  EXPECT_TRUE(foreground_parent.IsWindowVisible());

-

-  CRect foreground_rect;

-  EXPECT_TRUE(foreground_parent.GetWindowRect(&foreground_rect));

-  EXPECT_EQ(0, foreground_rect.Width());

-  EXPECT_EQ(0, foreground_rect.Height());

-

-  EXPECT_TRUE((WS_POPUP | WS_VISIBLE) & foreground_parent.GetStyle());

-  EXPECT_TRUE(WS_EX_TOOLWINDOW & foreground_parent.GetExStyle());

-

-  EXPECT_TRUE(foreground_parent.DestroyWindow());

-}

-

-}  // namespace omaha

-

+// Copyright 2003-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <ATLComTime.h>
+#include <atltypes.h>
+#include <atlwin.h>
+#include <map>
+#include <vector>
+#include "omaha/common/app_util.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/dynamic_link_kernel32.h"
+#include "omaha/common/file.h"
+#include "omaha/common/module_utils.h"
+#include "omaha/common/path.h"
+#include "omaha/common/shell.h"
+#include "omaha/common/string.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Make sure that the time functions work.
+TEST(UtilsTest, Time) {
+  // TODO(omaha): - add a test from string to time and back again.
+  // Further test the time converters.
+  time64 now = GetCurrent100NSTime();
+  ASSERT_TRUE(StringToTime(TimeToString(now)) == now);
+
+  // Test GetTimeCategory.
+  ASSERT_EQ(PAST,
+            GetTimeCategory(static_cast<time64>(0)));
+  ASSERT_EQ(PRESENT,
+            GetTimeCategory(static_cast<time64>(now)));
+  ASSERT_EQ(PRESENT,
+            GetTimeCategory(static_cast<time64>(now - kDaysTo100ns)));
+  ASSERT_EQ(PRESENT,
+            GetTimeCategory(static_cast<time64>(now - 365 * kDaysTo100ns)));
+  // A little bit in the future is also considered present.
+  ASSERT_EQ(PRESENT,
+            GetTimeCategory(static_cast<time64>(now + kDaysTo100ns)));
+  ASSERT_EQ(PRESENT,
+            GetTimeCategory(static_cast<time64>(
+                now - 30 * 365 * kDaysTo100ns)));
+  ASSERT_EQ(PAST,
+            GetTimeCategory(static_cast<time64>(
+                now - 50 * 365 * kDaysTo100ns)));
+  ASSERT_EQ(FUTURE,
+            GetTimeCategory(static_cast<time64>(now + kDaysTo100ns * 6)));
+  ASSERT_EQ(FUTURE,
+            GetTimeCategory(static_cast<time64>(now + 365 * kDaysTo100ns)));
+
+  // Test IsValidTime.
+  ASSERT_FALSE(IsValidTime(static_cast<time64>(0)));
+  ASSERT_TRUE(IsValidTime(static_cast<time64>(now)));
+  ASSERT_TRUE(IsValidTime(static_cast<time64>(now - 365 * kDaysTo100ns)));
+  ASSERT_TRUE(IsValidTime(static_cast<time64>(now - 10 * 365 * kDaysTo100ns)));
+  ASSERT_TRUE(IsValidTime(static_cast<time64>(now + kDaysTo100ns)));
+  ASSERT_FALSE(IsValidTime(static_cast<time64>(now - 50 * 365 * kDaysTo100ns)));
+  ASSERT_FALSE(IsValidTime(static_cast<time64>(now + 50 * 365 * kDaysTo100ns)));
+  ASSERT_FALSE(IsValidTime(static_cast<time64>(now + kDaysTo100ns * 6)));
+}
+
+TEST(UtilsTest, GetFolderPath_Success) {
+  CString path;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &path));
+  BOOL isWow64 = FALSE;
+  EXPECT_SUCCEEDED(Kernel32::IsWow64Process(GetCurrentProcess(), &isWow64));
+  CString expected_path = isWow64 ?
+      _T("C:\\Program Files (x86)") : _T("C:\\Program Files");
+  EXPECT_STREQ(expected_path, path);
+}
+
+TEST(UtilsTest, GetFolderPath_Errors) {
+  CString path;
+  EXPECT_EQ(E_INVALIDARG, GetFolderPath(0x7fff, &path));
+  EXPECT_TRUE(path.IsEmpty());
+  EXPECT_EQ(E_INVALIDARG, GetFolderPath(CSIDL_PROGRAM_FILES, NULL));
+}
+
+TEST(UtilsTest, CallEntryPoint0) {
+  HRESULT hr(E_FAIL);
+  ASSERT_FAILED(CallEntryPoint0(L"random-nonsense.dll", "foobar", &hr));
+}
+
+TEST(UtilsTest, ReadEntireFile) {
+  TCHAR directory[MAX_PATH] = {0};
+  ASSERT_TRUE(GetModuleDirectory(NULL, directory));
+  CString file_name;
+  file_name.AppendFormat(_T("%s\\declaration.txt"), directory);
+
+  std::vector<byte> buffer;
+  ASSERT_FAILED(ReadEntireFile(L"C:\\F00Bar\\ImaginaryFile", 0, &buffer));
+
+  ASSERT_SUCCEEDED(ReadEntireFile(file_name, 0, &buffer));
+  ASSERT_EQ(9405, buffer.size());
+  buffer.resize(0);
+  ASSERT_FAILED(ReadEntireFile(L"C:\\WINDOWS\\Greenstone.bmp", 1000, &buffer));
+}
+
+// TODO(omaha): Need a test for WriteEntireFile
+// TEST(UtilsTest, WriteEntireFile) {
+// }
+
+TEST(UtilsTest, RegSplitKeyvalueName) {
+  CString key_name, value_name;
+  ASSERT_SUCCEEDED(RegSplitKeyvalueName(CString(L"HKLM\\Foo\\"),
+                                        &key_name,
+                                        &value_name));
+  ASSERT_STREQ(key_name, L"HKLM\\Foo");
+  ASSERT_TRUE(value_name.IsEmpty());
+
+  ASSERT_SUCCEEDED(RegSplitKeyvalueName(CString(L"HKLM\\Foo\\(default)"),
+                                        &key_name,
+                                        &value_name));
+  ASSERT_STREQ(key_name, L"HKLM\\Foo");
+  ASSERT_TRUE(value_name.IsEmpty());
+
+  ASSERT_SUCCEEDED(RegSplitKeyvalueName(CString(L"HKLM\\Foo\\Bar"),
+                                        &key_name,
+                                        &value_name));
+  ASSERT_STREQ(key_name, L"HKLM\\Foo");
+  ASSERT_STREQ(value_name, L"Bar");
+}
+
+TEST(UtilsTest, ExpandEnvLikeStrings) {
+  std::map<CString, CString> mapping;
+  ASSERT_SUCCEEDED(Shell::GetSpecialFolderKeywordsMapping(&mapping));
+
+  CString out;
+  ASSERT_SUCCEEDED(ExpandEnvLikeStrings(
+      L"Foo%WINDOWS%Bar%SYSTEM%Zebra%WINDOWS%%SYSTEM%", mapping, &out));
+
+  // This should work, but CmpHelperSTRCASEEQ is not overloaded for wchars.
+  // ASSERT_STRCASEEQ(out, L"FooC:\\WINDOWSBarC:\\WINDOWS\\system32Zebra"
+  //                       L"C:\\WINDOWSC:\\WINDOWS\\system32");
+  ASSERT_EQ(out.CompareNoCase(L"FooC:\\WINDOWSBarC:\\WINDOWS\\system32Zebra"
+                              L"C:\\WINDOWSC:\\WINDOWS\\system32"),
+            0);
+  ASSERT_FAILED(ExpandEnvLikeStrings(L"Foo%WINDOWS%%BAR%Zebra", mapping, &out));
+}
+
+TEST(UtilsTest, GetCurrentProcessHandle) {
+  scoped_process proc;
+  ASSERT_SUCCEEDED(GetCurrentProcessHandle(address(proc)));
+  ASSERT_TRUE(valid(proc));
+}
+
+TEST(UtilsTest, IsGuid) {
+  ASSERT_FALSE(IsGuid(NULL));
+  ASSERT_FALSE(IsGuid(_T("")));
+  ASSERT_FALSE(IsGuid(_T("{}")));
+  ASSERT_FALSE(IsGuid(_T("a")));
+  ASSERT_FALSE(IsGuid(_T("CA3045BFA6B14fb8A0EFA615CEFE452C")));
+
+  // Missing {}
+  ASSERT_FALSE(IsGuid(_T("CA3045BF-A6B1-4fb8-A0EF-A615CEFE452C")));
+
+  // Invalid char X
+  ASSERT_FALSE(IsGuid(_T("{XA3045BF-A6B1-4fb8-A0EF-A615CEFE452C}")));
+
+  // Invalid binary char 0x200
+  ASSERT_FALSE(IsGuid(_T("{\0x200a3045bf-a6b1-4fb8-a0ef-a615cefe452c}")));
+
+  // Missing -
+  ASSERT_FALSE(IsGuid(_T("{CA3045BFA6B14fb8A0EFA615CEFE452C}")));
+
+  // Double quotes
+  ASSERT_FALSE(IsGuid(_T("\"{ca3045bf-a6b1-4fb8-a0ef-a615cefe452c}\"")));
+
+  ASSERT_TRUE(IsGuid(_T("{00000000-0000-0000-0000-000000000000}")));
+  ASSERT_TRUE(IsGuid(_T("{CA3045BF-A6B1-4fb8-A0EF-A615CEFE452C}")));
+  ASSERT_TRUE(IsGuid(_T("{ca3045bf-a6b1-4fb8-a0ef-a615cefe452c}")));
+}
+
+TEST(UtilsTest, VersionFromString_ValidVersion) {
+  EXPECT_EQ(MAKEDLLVERULL(42, 1, 21, 12345),
+            VersionFromString(_T("42.1.21.12345")));
+}
+
+TEST(UtilsTest, VersionFromString_VersionZero) {
+  EXPECT_EQ(0, VersionFromString(_T("0.0.0.0")));
+}
+
+TEST(UtilsTest, VersionFromString_VersionUpperLimits) {
+  EXPECT_EQ(MAKEDLLVERULL(0xffff, 0xffff, 0xffff, 0xffff),
+            VersionFromString(_T("65535.65535.65535.65535")));
+  EXPECT_EQ(0, VersionFromString(_T("65536.65536.65536.65536")));
+  EXPECT_EQ(0, VersionFromString(_T("1.2.65536.65536")));
+}
+
+TEST(UtilsTest, VersionFromString_IntegerOverflow) {
+  EXPECT_EQ(0, VersionFromString(_T("1.2.3.4294967296")));
+}
+
+TEST(UtilsTest, VersionFromString_NegativeVersion) {
+  EXPECT_EQ(0, VersionFromString(_T("1.2.3.-22")));
+}
+
+TEST(UtilsTest, VersionFromString_TooFewElements) {
+  EXPECT_EQ(0, VersionFromString(_T("1.1.1")));
+}
+
+TEST(UtilsTest, VersionFromString_ExtraPeriod) {
+  EXPECT_EQ(0, VersionFromString(_T("1.1.2.3.")));
+}
+
+TEST(UtilsTest, VersionFromString_TooManyElements) {
+  EXPECT_EQ(0, VersionFromString(_T("1.1.2.3.4")));
+}
+
+TEST(UtilsTest, VersionFromString_Char) {
+  EXPECT_EQ(0, VersionFromString(_T("1.B.3.4")));
+  EXPECT_EQ(0, VersionFromString(_T("1.2.3.B")));
+  EXPECT_EQ(0, VersionFromString(_T("1.2.3.9B")));
+}
+
+TEST(UtilsTest, StringFromVersion_ValidVersion) {
+  EXPECT_STREQ(_T("42.1.21.12345"),
+               StringFromVersion(MAKEDLLVERULL(42, 1, 21, 12345)));
+}
+
+TEST(UtilsTest, StringFromVersion_VersionZero) {
+  EXPECT_STREQ(_T("0.0.0.0"), StringFromVersion(0));
+}
+
+TEST(UtilsTest, StringFromVersion_VersionUpperLimits) {
+  EXPECT_STREQ(
+      _T("65535.65535.65535.65535"),
+      StringFromVersion(MAKEDLLVERULL(0xffff, 0xffff, 0xffff, 0xffff)));
+}
+
+TEST(UtilsTest, IsLocalSystemSid) {
+  EXPECT_TRUE(IsLocalSystemSid(kLocalSystemSid));
+  EXPECT_TRUE(IsLocalSystemSid(_T("S-1-5-18")));
+  EXPECT_TRUE(IsLocalSystemSid(_T("s-1-5-18")));
+
+  EXPECT_FALSE(IsLocalSystemSid(_T("")));
+  EXPECT_FALSE(IsLocalSystemSid(_T("S-1-5-17")));
+}
+
+// There is a very small probability the test could fail.
+TEST(UtilsTest, GenRandom) {
+  int random_int = 0;
+  EXPECT_TRUE(GenRandom(&random_int, sizeof(random_int)));
+  EXPECT_NE(random_int, 0);
+
+  int another_random_int = 0;
+  EXPECT_TRUE(GenRandom(&another_random_int, sizeof(another_random_int)));
+  EXPECT_NE(another_random_int, 0);
+
+  EXPECT_NE(random_int, another_random_int);
+}
+
+// Counts instances of the class.
+class Counter {
+ public:
+  Counter() {
+    ++instance_count_;
+  }
+  ~Counter() {
+    --instance_count_;
+  }
+  static int instance_count() { return instance_count_; }
+ private:
+  static int instance_count_;
+  DISALLOW_EVIL_CONSTRUCTORS(Counter);
+};
+
+int Counter::instance_count_ = 0;
+
+// Checks if the functor is actually calling the destructor of the type.
+TEST(UtilsTest, DeleteFun) {
+  EXPECT_EQ(Counter::instance_count(), 0);
+  Counter* counter = new Counter;
+  EXPECT_EQ(Counter::instance_count(), 1);
+  DeleteFun().operator()(counter);
+  EXPECT_EQ(Counter::instance_count(), 0);
+
+  // Checks if the template can be instantiated for some common built in types.
+  int* pointer_int = NULL;
+  DeleteFun().operator()(pointer_int);
+
+  const char* pointer_char = NULL;
+  DeleteFun().operator()(pointer_char);
+}
+
+TEST(UtilsTest, IsUserLoggedOn) {
+  bool is_logged_on(false);
+  ASSERT_HRESULT_SUCCEEDED(IsUserLoggedOn(&is_logged_on));
+  ASSERT_TRUE(is_logged_on);
+}
+
+TEST(UtilsTest, IsClickOnceDisabled) {
+  EXPECT_FALSE(IsClickOnceDisabled());
+}
+
+TEST(UtilsTest, ConfigureRunAtStartup) {
+  const TCHAR kRunKeyPath[] =
+      _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");
+
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideRegistryHives(kRegistryHiveOverrideRoot);
+
+  EXPECT_FALSE(RegKey::HasKey(kRunKeyPath));
+
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            ConfigureRunAtStartup(USER_KEY_NAME, _T("FooApp"),
+                                  _T("\"foo.exe\""), false));
+  EXPECT_FALSE(RegKey::HasKey(kRunKeyPath));
+
+  EXPECT_SUCCEEDED(ConfigureRunAtStartup(USER_KEY_NAME, _T("FooApp"),
+                                         _T("\"C:\\foo.exe\" /x"), true));
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kRunKeyPath, _T("FooApp"), &value));
+  EXPECT_STREQ(_T("\"C:\\foo.exe\" /x"), value);
+
+  EXPECT_SUCCEEDED(ConfigureRunAtStartup(USER_KEY_NAME, _T("FooApp"),
+                                         _T("\"foo.exe\""), false));
+  EXPECT_FALSE(RegKey::HasValue(kRunKeyPath, _T("FooApp")));
+  EXPECT_TRUE(RegKey::HasKey(kRunKeyPath));
+
+  RestoreRegistryHives();
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+TEST(UtilsTest, ValidPath) {
+  CString cmd_line =
+      _T("\"C:\\Program Files\\Internet Explorer\\iexplore.exe\" -nohome");
+  CString exe_path;
+  EXPECT_SUCCEEDED(GetExePathFromCommandLine(cmd_line, &exe_path));
+  EXPECT_STREQ(_T("C:\\Program Files\\Internet Explorer\\iexplore.exe"),
+               exe_path);
+}
+
+TEST(UtilsTest, InvalidPath) {
+  CString cmd_line = _T("");
+  CString exe_path;
+  EXPECT_FAILED(GetExePathFromCommandLine(cmd_line, &exe_path));
+  EXPECT_TRUE(exe_path.IsEmpty());
+}
+
+TEST(UtilsTest, PinModuleIntoProcess) {
+  const TCHAR module_name[] = _T("icmp.dll");
+  const void* kNullModule = NULL;
+
+  // The module should not be loaded at this time.
+  EXPECT_EQ(kNullModule, ::GetModuleHandle(module_name));
+
+  // Loads and unloads the module.
+  {
+    scoped_library module(::LoadLibrary(module_name));
+    EXPECT_TRUE(module);
+    EXPECT_NE(kNullModule, ::GetModuleHandle(module_name));
+  }
+  EXPECT_EQ(kNullModule, ::GetModuleHandle(module_name));
+
+  // Loads, pins, and unloads the module.
+  {
+    scoped_library module(::LoadLibrary(module_name));
+    EXPECT_TRUE(module);
+    EXPECT_NE(kNullModule, ::GetModuleHandle(module_name));
+    PinModuleIntoProcess(module_name);
+  }
+  EXPECT_NE(kNullModule, ::GetModuleHandle(module_name));
+}
+
+// Assumes Windows is installed on the C: drive.
+TEST(UtilsTest, GetEnvironmentVariableAsString) {
+  EXPECT_STREQ(_T("C:"), GetEnvironmentVariableAsString(_T("SystemDrive")));
+  EXPECT_STREQ(_T("Windows_NT"), GetEnvironmentVariableAsString(_T("OS")));
+  EXPECT_STREQ(_T(""), GetEnvironmentVariableAsString(_T("FOO")));
+}
+
+TEST(UtilsTest, IsWindowsInstalling_Normal) {
+  EXPECT_FALSE(IsWindowsInstalling());
+}
+
+TEST(UtilsTest, IsWindowsInstalling_Installing_Vista_InvalidValues) {
+  if (!vista_util::IsVistaOrLater()) {
+    return;
+  }
+
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideRegistryHives(kRegistryHiveOverrideRoot);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("")));
+  EXPECT_FALSE(IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("foo")));
+  EXPECT_FALSE(IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      static_cast<DWORD>(1)));
+  ExpectAsserts expect_asserts;  // RegKey asserts because value type is wrong.
+  EXPECT_FALSE(IsWindowsInstalling());
+
+  RestoreRegistryHives();
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+TEST(UtilsTest, IsWindowsInstalling_Installing_Vista_ValidStates) {
+  if (!vista_util::IsVistaOrLater()) {
+    return;
+  }
+
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideRegistryHives(kRegistryHiveOverrideRoot);
+
+  // These states return false in the original implementation.
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_COMPLETE")));
+  EXPECT_FALSE(IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE")));
+  EXPECT_FALSE(IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_OOBE")));
+  EXPECT_FALSE(IsWindowsInstalling());
+
+  // These states are specified in the original implementation.
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_UNDEPLOYABLE")));
+  EXPECT_TRUE(IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_AUDIT")));
+  EXPECT_TRUE(IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_AUDIT")));
+  EXPECT_TRUE(IsWindowsInstalling());
+
+  RestoreRegistryHives();
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+TEST(UtilsTest, AddAllowedAce) {
+  CString test_file_path = ConcatenatePath(
+      app_util::GetCurrentModuleDirectory(), _T("TestAddAllowedAce.exe"));
+  EXPECT_SUCCEEDED(File::Remove(test_file_path));
+
+  EXPECT_SUCCEEDED(File::Copy(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("GoogleUpdate.exe")),
+      test_file_path,
+      false));
+
+  CDacl dacl;
+  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));
+  const int original_ace_count = dacl.GetAceCount();
+
+  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,
+                                 SE_FILE_OBJECT,
+                                 Sids::Dialup(),
+                                 FILE_GENERIC_READ,
+                                 0));
+
+  dacl.SetEmpty();
+  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));
+  EXPECT_EQ(original_ace_count + 1, dacl.GetAceCount());
+
+  // Add the same access. No ACE is added.
+  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,
+                                 SE_FILE_OBJECT,
+                                 Sids::Dialup(),
+                                 FILE_GENERIC_READ,
+                                 0));
+  dacl.SetEmpty();
+  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));
+  EXPECT_EQ(original_ace_count + 1, dacl.GetAceCount());
+
+  // Add a subset of the existing access. No ACE is added.
+  EXPECT_EQ(FILE_READ_ATTRIBUTES, FILE_GENERIC_READ & FILE_READ_ATTRIBUTES);
+  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,
+                                 SE_FILE_OBJECT,
+                                 Sids::Dialup(),
+                                 FILE_READ_ATTRIBUTES,
+                                 0));
+  dacl.SetEmpty();
+  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));
+  EXPECT_EQ(original_ace_count + 1, dacl.GetAceCount());
+
+  // Add more access. An ACE is added.
+  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,
+                                 SE_FILE_OBJECT,
+                                 Sids::Dialup(),
+                                 FILE_ALL_ACCESS,
+                                 0));
+  dacl.SetEmpty();
+  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));
+  EXPECT_EQ(original_ace_count + 2, dacl.GetAceCount());
+
+  // TODO(omaha): An assert occurs because the ACE flags are being used on a
+  // file object. Add a new test to use a registry key.
+  ExpectAsserts expect_asserts;
+
+  // Different ACE flags. An ACE is added.
+  const BYTE kTestAce = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
+  const BYTE kTestAceSubset = CONTAINER_INHERIT_ACE;
+  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,
+                                 SE_FILE_OBJECT,
+                                 Sids::Dialup(),
+                                 FILE_ALL_ACCESS,
+                                 kTestAce));
+  dacl.SetEmpty();
+  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));
+  EXPECT_EQ(original_ace_count + 3, dacl.GetAceCount());
+
+  // Subset of existing ACE flags. An ACE is added because flags must be exact.
+  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,
+                                 SE_FILE_OBJECT,
+                                 Sids::Dialup(),
+                                 FILE_ALL_ACCESS,
+                                 kTestAceSubset));
+  dacl.SetEmpty();
+  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));
+  EXPECT_EQ(original_ace_count + 4, dacl.GetAceCount());
+
+  // Same flags. An ACE should not be added because all values match.
+  // TODO(omaha): This does not work, possibly because the object is a file.
+  // Try the test using a registry key.
+  EXPECT_SUCCEEDED(AddAllowedAce(test_file_path,
+                                 SE_FILE_OBJECT,
+                                 Sids::Dialup(),
+                                 FILE_ALL_ACCESS,
+                                 kTestAceSubset));
+  dacl.SetEmpty();
+  EXPECT_TRUE(AtlGetDacl(test_file_path, SE_FILE_OBJECT, &dacl));
+  EXPECT_EQ(original_ace_count + 5, dacl.GetAceCount());
+
+  EXPECT_SUCCEEDED(File::Remove(test_file_path));
+}
+
+TEST(UtilsTest, CreateForegroundParentWindowForUAC) {
+  CWindow foreground_parent;
+  foreground_parent.Attach(CreateForegroundParentWindowForUAC());
+  EXPECT_TRUE(foreground_parent.IsWindow());
+  EXPECT_TRUE(foreground_parent.IsWindowVisible());
+
+  CRect foreground_rect;
+  EXPECT_TRUE(foreground_parent.GetWindowRect(&foreground_rect));
+  EXPECT_EQ(0, foreground_rect.Width());
+  EXPECT_EQ(0, foreground_rect.Height());
+
+  EXPECT_TRUE((WS_POPUP | WS_VISIBLE) & foreground_parent.GetStyle());
+  EXPECT_TRUE(WS_EX_TOOLWINDOW & foreground_parent.GetExStyle());
+
+  EXPECT_TRUE(foreground_parent.DestroyWindow());
+}
+
+}  // namespace omaha
+
diff --git a/common/vista_utils.cc b/common/vista_utils.cc
index 5e0a694..f052983 100644
--- a/common/vista_utils.cc
+++ b/common/vista_utils.cc
@@ -1,482 +1,482 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/vista_utils.h"

-

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/const_utils.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/proc_utils.h"

-#include "omaha/common/process.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/smart_handle.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/system.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/user_rights.h"

-#include "omaha/common/utils.h"

-

-#define LOW_INTEGRITY_SDDL_SACL_A     NOTRANSL("S:(ML;;NW;;;LW)")

-#define LOW_INTEGRITY_SID_W           NOTRANSL(L"S-1-16-4096")

-

-namespace omaha {

-

-namespace vista {

-

-namespace {

-

-// TODO(Omaha): Unit test for this method.

-HRESULT RunAsUser(const CString& command_line,

-                  HANDLE user_token,

-                  bool run_as_current_user) {

-  if (INVALID_HANDLE_VALUE == user_token) {

-    return E_INVALIDARG;

-  }

-

-  CString cmd(command_line);

-

-  STARTUPINFO startup_info = { sizeof(startup_info) };

-  PROCESS_INFORMATION process_info = {0};

-

-  DWORD creation_flags(0);

-  void* environment_block(NULL);

-  ON_SCOPE_EXIT(::DestroyEnvironmentBlock, environment_block);

-  if (::CreateEnvironmentBlock(&environment_block, user_token, FALSE)) {

-    creation_flags |= CREATE_UNICODE_ENVIRONMENT;

-  } else {

-    ASSERT(false, (_T("::CreateEnvironmentBlock failed %d"), ::GetLastError()));

-    environment_block = NULL;

-  }

-

-  // ::CreateProcessAsUser() does not work unless the caller is SYSTEM. Does not

-  // matter if the user token is for the current user.

-  BOOL success = run_as_current_user ?

-      ::CreateProcess(0, CStrBuf(cmd, MAX_PATH), 0, 0, false, creation_flags,

-                      environment_block, 0, &startup_info, &process_info) :

-      ::CreateProcessAsUser(user_token, 0, CStrBuf(cmd, MAX_PATH), 0, 0, false,

-                            creation_flags, environment_block, 0, &startup_info,

-                            &process_info);

-

-  if (!success) {

-    HRESULT hr(HRESULTFromLastError());

-    UTIL_LOG(LE, (_T("[RunAsUser failed][cmd=%s][hresult=0x%x]"), cmd, hr));

-    return hr;

-  }

-

-  VERIFY1(::CloseHandle(process_info.hThread));

-  VERIFY1(::CloseHandle(process_info.hProcess));

-

-  return S_OK;

-}

-

-}  // namespace

-

-bool IsProcessProtected() {

-  if (!SystemInfo::IsRunningOnVistaOrLater()) {

-    return false;

-  }

-

-  AutoHandle token;

-  VERIFY1(::OpenProcessToken(GetCurrentProcess(),

-                             TOKEN_QUERY | TOKEN_QUERY_SOURCE,

-                             &token.receive()));

-

-  // Get the Integrity level.

-  DWORD length_needed;

-  BOOL b = ::GetTokenInformation(token,

-                                 TokenIntegrityLevel,

-                                 NULL,

-                                 0,

-                                 &length_needed);

-  ASSERT1(b == FALSE);

-  if (b) {

-    return false;

-  }

-

-  // The first call to GetTokenInformation is just to get the buffer size

-  if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {

-    return false;

-  }

-

-  scoped_ptr<TOKEN_MANDATORY_LABEL> integration_level;

-

-  integration_level.reset(reinterpret_cast<TOKEN_MANDATORY_LABEL*>(

-      new char[length_needed]));

-  if (integration_level.get() == NULL) {

-    return false;

-  }

-

-  if (!::GetTokenInformation(token,

-                             TokenIntegrityLevel,

-                             integration_level.get(),

-                             length_needed,

-                             &length_needed)) {

-    return false;

-  }

-

-  wchar_t* sid_str = NULL;

-  VERIFY1(::ConvertSidToStringSid(integration_level->Label.Sid, &sid_str));

-  bool ret = ::lstrcmpW(sid_str, LOW_INTEGRITY_SID_W) == 0;

-  ::LocalFree(sid_str);

-

-  return ret;

-}

-

-HRESULT AllowProtectedProcessAccessToSharedObject(const TCHAR* name) {

-  if (!SystemInfo::IsRunningOnVistaOrLater()) {

-    return S_FALSE;

-  }

-

-  ASSERT1(name != NULL);

-

-  PSECURITY_DESCRIPTOR psd = NULL;

-  VERIFY1(::ConvertStringSecurityDescriptorToSecurityDescriptorA(

-              LOW_INTEGRITY_SDDL_SACL_A,

-              SDDL_REVISION_1,

-              &psd,

-              NULL));

-

-  BOOL sacl_present = FALSE;

-  BOOL sacl_defaulted = FALSE;

-  PACL sacl = NULL;

-  VERIFY1(::GetSecurityDescriptorSacl(psd,

-                                      &sacl_present,

-                                      &sacl,

-                                      &sacl_defaulted));

-

-  DWORD ret = ::SetNamedSecurityInfoW(const_cast<TCHAR*>(name),

-                                      SE_KERNEL_OBJECT,

-                                      LABEL_SECURITY_INFORMATION,

-                                      NULL,

-                                      NULL,

-                                      NULL,

-                                      sacl);

-

-  ::LocalFree(psd);

-

-  return HRESULT_FROM_WIN32(ret);

-}

-

-HRESULT RunAsCurrentUser(const CString& command_line) {

-  scoped_handle token;

-  if (!::OpenProcessToken(::GetCurrentProcess(),

-                          TOKEN_QUERY | TOKEN_DUPLICATE,

-                          address(token))) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LE, (_T("[RunAsCurrentUser: OpenProcessToken failed][0x%x]"), hr));

-    return hr;

-  }

-

-  return RunAsUser(command_line, get(token), true);

-}

-

-static HRESULT StartInternetExplorerAsUser(HANDLE user_token,

-                                           const CString& options) {

-  // Internet Explorer path

-  CString ie_file_path;

-  HRESULT result = RegKey::GetValue(kRegKeyIeClass,

-                                    kRegValueIeClass,

-                                    &ie_file_path);

-  ASSERT1(SUCCEEDED(result));

-

-  if (SUCCEEDED(result)) {

-    CString command_line(ie_file_path);

-    command_line += _T(' ');

-    command_line += options;

-    UTIL_LOG(L5, (_T("[StartInternetExplorerAsUser]")

-                  _T("[Running IExplore with command line][%s]"),

-                  command_line));

-    result = RunAsUser(command_line, user_token, false);

-  }

-  return result;

-}

-

-//

-// Constants used by RestartIEUser()

-//

-// The IEUser executable name

-const TCHAR* kIEUser = _T("IEUSER.EXE");

-

-// The maximum number of simultaneous

-// logged on users in FUS that we support

-const int kMaximumUsers = 16;

-

-

-// Restart IEUser processs. This is to allow for

-// IEUser.exe to refresh it's ElevationPolicy cache. Due to a bug

-// within IE7, IEUser.exe does not refresh it's cache unless it

-// is restarted in the manner below. If the cache is not refreshed

-// IEUser does not respect any new ElevationPolicies that a fresh

-// setup program installs for an ActiveX control or BHO. This code

-// is adapted from Toolbar.

-HRESULT RestartIEUser() {

-  // Use the service to restart IEUser.

-  // This allows us to restart IEUser for:

-  //   (a) Multiple users for the first-install case

-  //       (we currently only restart IEUser for the current interactive user)

-  //   (b) Even if we are started in an elevated mode

-

-  if (!SystemInfo::IsRunningOnVistaOrLater()) {

-    UTIL_LOG(L5, (_T("[RestartIEUser - not running on Vista - Exiting]")));

-    return S_OK;

-  }

-

-  // The restart should be attempted from the system account

-  bool is_system_process = false;

-  if (FAILED(IsSystemProcess(&is_system_process)) || !is_system_process) {

-    ASSERT1(false);

-    return E_ACCESSDENIED;

-  }

-

-  // Get the list of users currently running IEUser.exe processes.

-  scoped_handle ieuser_users[kMaximumUsers];

-  int number_of_users = 0;

-  Process::GetUsersOfProcesses(kIEUser, kMaximumUsers, ieuser_users,

-                               &number_of_users);

-

-  UTIL_LOG(L5, (_T("[RestartIEUser]")

-                _T("[number_of_users running IEUser %d]"), number_of_users));

-

-  if (!number_of_users) {

-    UTIL_LOG(L5, (_T("[RestartIEUser][No IEUser processes running]")));

-    return S_OK;

-  }

-

-  // Kill current IEUser processes.

-  ProcessTerminator pt(kIEUser);

-  const int kKillWaitTimeoutMs = 5000;

-  bool found = false;

-  const int kill_method = (ProcessTerminator::KILL_METHOD_4_TERMINATE_PROCESS);

-

-  RET_IF_FAILED(pt.KillTheProcess(kKillWaitTimeoutMs,

-                                  &found,

-                                  kill_method,

-                                  false));

-

-  // Restart them.

-  HRESULT result = S_OK;

-  for (int i = 0; i < number_of_users; i++) {

-    // To start a new ieuser.exe, simply start iexplore.exe as a normal user

-    // The -embedding prevents IE from opening a window

-    HRESULT restart_result = StartInternetExplorerAsUser(get(ieuser_users[i]),

-                                                         _T("-embedding"));

-    if (FAILED(restart_result)) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[StartInternetExplorerAsUser failed][0x%x]"),

-                             restart_result));

-      result = restart_result;

-    }

-  }

-

-  return result;

-}

-

-HRESULT GetExplorerPidForCurrentUserOrSession(uint32* pid) {

-  ASSERT1(pid);

-  std::vector<uint32> pids;

-  HRESULT hr = GetProcessPidsForActiveUserOrSession(kExplorer, &pids);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[Did not find explorer.exe processes][0x%x]"), hr));

-    return hr;

-  }

-

-  CORE_LOG(L1, (_T("[Found %u instance(s) of explorer.exe]"), pids.size()));

-

-  *pid = pids[0];   // Return only the first instance of explorer.exe.

-  return S_OK;

-}

-

-HRESULT GetExplorerTokenForLoggedInUser(HANDLE* token) {

-  UTIL_LOG(L3, (_T("[GetExplorerTokenForLoggedInUser]")));

-  ASSERT1(token);

-

-  // TODO(omaha): One can set the windows shell to be other than

-  // explorer.exe, handle this case. One way to handle this is to

-  // read the regkey

-  // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon

-  // The only problem with this is it can be overriden with the user reg keys.

-  // Need to figure out a method to do this.

-  // Also consider using the interactive user before picking the first explorer

-  // process i.e. the active user.

-  std::vector<uint32> processes;

-  DWORD flags = EXCLUDE_CURRENT_PROCESS;

-  std::vector<CString> command_lines;

-  CString explorer_file_name(kExplorer);

-  CString user_sid;

-

-  HRESULT hr = Process::FindProcesses(flags,

-                                      explorer_file_name,

-                                      true,

-                                      user_sid,

-                                      command_lines,

-                                      &processes);

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_ERROR, (_T("[FindProcesses failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  std::vector<uint32>::const_iterator iter = processes.begin();

-  for (; iter != processes.end(); ++iter) {

-    uint32 explorer_pid = *iter;

-    scoped_handle exp(::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,

-                                    false,

-                                    explorer_pid));

-    if (exp) {

-      if (::OpenProcessToken(get(exp),

-                             TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_IMPERSONATE,

-                             token)) {

-        // TODO(omaha): Consider using the GetWindowsAccountDomainSid

-        // method here. This method returns the domain SID associated

-        // with the passed in SID. This allows us to detect if the user is a

-        // domain user. We should prefer domain users over normal users,

-        // as in corporate environments, these users will be more likely to

-        // allow to be tunneled through a proxy.

-        return S_OK;

-      } else {

-        hr = HRESULTFromLastError();

-        CORE_LOG(LEVEL_WARNING, (_T("[OpenProcessToken failed][0x%08x]"), hr));

-      }

-    } else {

-      hr = HRESULTFromLastError();

-      CORE_LOG(LEVEL_WARNING, (_T("[OpenProcess failed][0x%08x]"), hr));

-    }

-  }

-

-  return hr;

-}

-

-HRESULT GetPidsInSession(const TCHAR* exe_name,

-                         const TCHAR* user_sid,

-                         DWORD session_id,

-                         std::vector<uint32>* pids) {

-  ASSERT1(pids);

-  ASSERT1(exe_name);

-  ASSERT1(*exe_name);

-  UTIL_LOG(L3, (_T("[GetPidsInSession][%s][sid=%s][session=%d]"),

-                exe_name, user_sid, session_id));

-

-  pids->clear();

-

-  DWORD flags = EXCLUDE_CURRENT_PROCESS;

-  if (user_sid != NULL) {

-    flags |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER;

-  }

-  std::vector<CString> command_lines;

-  HRESULT hr = Process::FindProcessesInSession(session_id,

-                                               flags,

-                                               exe_name,

-                                               true,

-                                               user_sid,

-                                               command_lines,

-                                               pids);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  return pids->empty() ? HRESULT_FROM_WIN32(ERROR_NOT_FOUND) : S_OK;

-}

-

-HRESULT GetProcessPidsForActiveUserOrSession(const TCHAR* exe_name,

-                                             std::vector<uint32>* pids) {

-  bool is_system = false;

-  HRESULT hr = IsSystemProcess(&is_system);

-  if (FAILED(hr)) {

-    NET_LOG(LE, (_T("[IsSystemProcess failed][0x%x]"), hr));

-    return hr;

-  }

-

-  if (is_system) {

-    return vista::GetPidsInSession(exe_name,

-                                   NULL,

-                                   System::GetActiveSessionId(),

-                                   pids);

-  }

-

-  CString user_sid;

-  // If this call fails, we are still ok.

-  omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid);

-  DWORD current_session = System::GetCurrentSessionId();

-  if (FAILED(vista::GetPidsInSession(exe_name,

-                                     user_sid,

-                                     current_session,

-                                     pids))) {

-    // In the case of RunAs, the processes may be under a different identity

-    // than the current sid. So if we are unable to find a process under the

-    // current user's sid, we search for processes running in the current

-    // session regardless of the sid they are running under.

-    return vista::GetPidsInSession(exe_name,

-                                   NULL,

-                                   current_session,

-                                   pids);

-  }

-

-  return S_OK;

-}

-

-

-

-HRESULT StartProcessWithTokenOfProcess(uint32 pid,

-                                       const CString& command_line) {

-  UTIL_LOG(L5, (_T("[StartProcessWithTokenOfProcess]")

-                _T("[pid %u][command_line '%s']"), pid, command_line));

-

-  // Get the token from process.

-  scoped_handle user_token;

-  HRESULT hr = Process::GetImpersonationToken(pid, address(user_token));

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_ERROR, (_T("[GetImpersonationToken failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Start process using the token.

-  UTIL_LOG(L5, (_T("[StartProcessWithTokenOfProcess][Running process %s]"),

-                command_line));

-  hr = RunAsUser(command_line, get(user_token), false);

-

-  if (FAILED(hr)) {

-    UTIL_LOG(LEVEL_ERROR,

-      (_T("[Vista::StartProcessWithTokenOfProcess - RunAsUser failed][0x%x]"),

-      hr));

-  }

-

-  return hr;

-}

-

-HRESULT GetLoggedOnUserToken(HANDLE* token) {

-  ASSERT1(token);

-  *token = NULL;

-

-  uint32 pid = 0;

-  HRESULT hr = GetExplorerPidForCurrentUserOrSession(&pid);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  hr = Process::GetImpersonationToken(pid, token);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ASSERT1(*token);

-  return S_OK;

-}

-

-}  // namespace vista

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/vista_utils.h"
+
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/const_utils.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/proc_utils.h"
+#include "omaha/common/process.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/smart_handle.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/system.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/user_rights.h"
+#include "omaha/common/utils.h"
+
+#define LOW_INTEGRITY_SDDL_SACL_A     NOTRANSL("S:(ML;;NW;;;LW)")
+#define LOW_INTEGRITY_SID_W           NOTRANSL(L"S-1-16-4096")
+
+namespace omaha {
+
+namespace vista {
+
+namespace {
+
+// TODO(Omaha): Unit test for this method.
+HRESULT RunAsUser(const CString& command_line,
+                  HANDLE user_token,
+                  bool run_as_current_user) {
+  if (INVALID_HANDLE_VALUE == user_token) {
+    return E_INVALIDARG;
+  }
+
+  CString cmd(command_line);
+
+  STARTUPINFO startup_info = { sizeof(startup_info) };
+  PROCESS_INFORMATION process_info = {0};
+
+  DWORD creation_flags(0);
+  void* environment_block(NULL);
+  ON_SCOPE_EXIT(::DestroyEnvironmentBlock, environment_block);
+  if (::CreateEnvironmentBlock(&environment_block, user_token, FALSE)) {
+    creation_flags |= CREATE_UNICODE_ENVIRONMENT;
+  } else {
+    ASSERT(false, (_T("::CreateEnvironmentBlock failed %d"), ::GetLastError()));
+    environment_block = NULL;
+  }
+
+  // ::CreateProcessAsUser() does not work unless the caller is SYSTEM. Does not
+  // matter if the user token is for the current user.
+  BOOL success = run_as_current_user ?
+      ::CreateProcess(0, CStrBuf(cmd, MAX_PATH), 0, 0, false, creation_flags,
+                      environment_block, 0, &startup_info, &process_info) :
+      ::CreateProcessAsUser(user_token, 0, CStrBuf(cmd, MAX_PATH), 0, 0, false,
+                            creation_flags, environment_block, 0, &startup_info,
+                            &process_info);
+
+  if (!success) {
+    HRESULT hr(HRESULTFromLastError());
+    UTIL_LOG(LE, (_T("[RunAsUser failed][cmd=%s][hresult=0x%x]"), cmd, hr));
+    return hr;
+  }
+
+  VERIFY1(::CloseHandle(process_info.hThread));
+  VERIFY1(::CloseHandle(process_info.hProcess));
+
+  return S_OK;
+}
+
+}  // namespace
+
+bool IsProcessProtected() {
+  if (!SystemInfo::IsRunningOnVistaOrLater()) {
+    return false;
+  }
+
+  AutoHandle token;
+  VERIFY1(::OpenProcessToken(GetCurrentProcess(),
+                             TOKEN_QUERY | TOKEN_QUERY_SOURCE,
+                             &token.receive()));
+
+  // Get the Integrity level.
+  DWORD length_needed;
+  BOOL b = ::GetTokenInformation(token,
+                                 TokenIntegrityLevel,
+                                 NULL,
+                                 0,
+                                 &length_needed);
+  ASSERT1(b == FALSE);
+  if (b) {
+    return false;
+  }
+
+  // The first call to GetTokenInformation is just to get the buffer size
+  if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+    return false;
+  }
+
+  scoped_ptr<TOKEN_MANDATORY_LABEL> integration_level;
+
+  integration_level.reset(reinterpret_cast<TOKEN_MANDATORY_LABEL*>(
+      new char[length_needed]));
+  if (integration_level.get() == NULL) {
+    return false;
+  }
+
+  if (!::GetTokenInformation(token,
+                             TokenIntegrityLevel,
+                             integration_level.get(),
+                             length_needed,
+                             &length_needed)) {
+    return false;
+  }
+
+  wchar_t* sid_str = NULL;
+  VERIFY1(::ConvertSidToStringSid(integration_level->Label.Sid, &sid_str));
+  bool ret = ::lstrcmpW(sid_str, LOW_INTEGRITY_SID_W) == 0;
+  ::LocalFree(sid_str);
+
+  return ret;
+}
+
+HRESULT AllowProtectedProcessAccessToSharedObject(const TCHAR* name) {
+  if (!SystemInfo::IsRunningOnVistaOrLater()) {
+    return S_FALSE;
+  }
+
+  ASSERT1(name != NULL);
+
+  PSECURITY_DESCRIPTOR psd = NULL;
+  VERIFY1(::ConvertStringSecurityDescriptorToSecurityDescriptorA(
+              LOW_INTEGRITY_SDDL_SACL_A,
+              SDDL_REVISION_1,
+              &psd,
+              NULL));
+
+  BOOL sacl_present = FALSE;
+  BOOL sacl_defaulted = FALSE;
+  PACL sacl = NULL;
+  VERIFY1(::GetSecurityDescriptorSacl(psd,
+                                      &sacl_present,
+                                      &sacl,
+                                      &sacl_defaulted));
+
+  DWORD ret = ::SetNamedSecurityInfoW(const_cast<TCHAR*>(name),
+                                      SE_KERNEL_OBJECT,
+                                      LABEL_SECURITY_INFORMATION,
+                                      NULL,
+                                      NULL,
+                                      NULL,
+                                      sacl);
+
+  ::LocalFree(psd);
+
+  return HRESULT_FROM_WIN32(ret);
+}
+
+HRESULT RunAsCurrentUser(const CString& command_line) {
+  scoped_handle token;
+  if (!::OpenProcessToken(::GetCurrentProcess(),
+                          TOKEN_QUERY | TOKEN_DUPLICATE,
+                          address(token))) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LE, (_T("[RunAsCurrentUser: OpenProcessToken failed][0x%x]"), hr));
+    return hr;
+  }
+
+  return RunAsUser(command_line, get(token), true);
+}
+
+static HRESULT StartInternetExplorerAsUser(HANDLE user_token,
+                                           const CString& options) {
+  // Internet Explorer path
+  CString ie_file_path;
+  HRESULT result = RegKey::GetValue(kRegKeyIeClass,
+                                    kRegValueIeClass,
+                                    &ie_file_path);
+  ASSERT1(SUCCEEDED(result));
+
+  if (SUCCEEDED(result)) {
+    CString command_line(ie_file_path);
+    command_line += _T(' ');
+    command_line += options;
+    UTIL_LOG(L5, (_T("[StartInternetExplorerAsUser]")
+                  _T("[Running IExplore with command line][%s]"),
+                  command_line));
+    result = RunAsUser(command_line, user_token, false);
+  }
+  return result;
+}
+
+//
+// Constants used by RestartIEUser()
+//
+// The IEUser executable name
+const TCHAR* kIEUser = _T("IEUSER.EXE");
+
+// The maximum number of simultaneous
+// logged on users in FUS that we support
+const int kMaximumUsers = 16;
+
+
+// Restart IEUser processs. This is to allow for
+// IEUser.exe to refresh it's ElevationPolicy cache. Due to a bug
+// within IE7, IEUser.exe does not refresh it's cache unless it
+// is restarted in the manner below. If the cache is not refreshed
+// IEUser does not respect any new ElevationPolicies that a fresh
+// setup program installs for an ActiveX control or BHO. This code
+// is adapted from Toolbar.
+HRESULT RestartIEUser() {
+  // Use the service to restart IEUser.
+  // This allows us to restart IEUser for:
+  //   (a) Multiple users for the first-install case
+  //       (we currently only restart IEUser for the current interactive user)
+  //   (b) Even if we are started in an elevated mode
+
+  if (!SystemInfo::IsRunningOnVistaOrLater()) {
+    UTIL_LOG(L5, (_T("[RestartIEUser - not running on Vista - Exiting]")));
+    return S_OK;
+  }
+
+  // The restart should be attempted from the system account
+  bool is_system_process = false;
+  if (FAILED(IsSystemProcess(&is_system_process)) || !is_system_process) {
+    ASSERT1(false);
+    return E_ACCESSDENIED;
+  }
+
+  // Get the list of users currently running IEUser.exe processes.
+  scoped_handle ieuser_users[kMaximumUsers];
+  int number_of_users = 0;
+  Process::GetUsersOfProcesses(kIEUser, kMaximumUsers, ieuser_users,
+                               &number_of_users);
+
+  UTIL_LOG(L5, (_T("[RestartIEUser]")
+                _T("[number_of_users running IEUser %d]"), number_of_users));
+
+  if (!number_of_users) {
+    UTIL_LOG(L5, (_T("[RestartIEUser][No IEUser processes running]")));
+    return S_OK;
+  }
+
+  // Kill current IEUser processes.
+  ProcessTerminator pt(kIEUser);
+  const int kKillWaitTimeoutMs = 5000;
+  bool found = false;
+  const int kill_method = (ProcessTerminator::KILL_METHOD_4_TERMINATE_PROCESS);
+
+  RET_IF_FAILED(pt.KillTheProcess(kKillWaitTimeoutMs,
+                                  &found,
+                                  kill_method,
+                                  false));
+
+  // Restart them.
+  HRESULT result = S_OK;
+  for (int i = 0; i < number_of_users; i++) {
+    // To start a new ieuser.exe, simply start iexplore.exe as a normal user
+    // The -embedding prevents IE from opening a window
+    HRESULT restart_result = StartInternetExplorerAsUser(get(ieuser_users[i]),
+                                                         _T("-embedding"));
+    if (FAILED(restart_result)) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[StartInternetExplorerAsUser failed][0x%x]"),
+                             restart_result));
+      result = restart_result;
+    }
+  }
+
+  return result;
+}
+
+HRESULT GetExplorerPidForCurrentUserOrSession(uint32* pid) {
+  ASSERT1(pid);
+  std::vector<uint32> pids;
+  HRESULT hr = GetProcessPidsForActiveUserOrSession(kExplorer, &pids);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[Did not find explorer.exe processes][0x%x]"), hr));
+    return hr;
+  }
+
+  CORE_LOG(L1, (_T("[Found %u instance(s) of explorer.exe]"), pids.size()));
+
+  *pid = pids[0];   // Return only the first instance of explorer.exe.
+  return S_OK;
+}
+
+HRESULT GetExplorerTokenForLoggedInUser(HANDLE* token) {
+  UTIL_LOG(L3, (_T("[GetExplorerTokenForLoggedInUser]")));
+  ASSERT1(token);
+
+  // TODO(omaha): One can set the windows shell to be other than
+  // explorer.exe, handle this case. One way to handle this is to
+  // read the regkey
+  // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
+  // The only problem with this is it can be overriden with the user reg keys.
+  // Need to figure out a method to do this.
+  // Also consider using the interactive user before picking the first explorer
+  // process i.e. the active user.
+  std::vector<uint32> processes;
+  DWORD flags = EXCLUDE_CURRENT_PROCESS;
+  std::vector<CString> command_lines;
+  CString explorer_file_name(kExplorer);
+  CString user_sid;
+
+  HRESULT hr = Process::FindProcesses(flags,
+                                      explorer_file_name,
+                                      true,
+                                      user_sid,
+                                      command_lines,
+                                      &processes);
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_ERROR, (_T("[FindProcesses failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  std::vector<uint32>::const_iterator iter = processes.begin();
+  for (; iter != processes.end(); ++iter) {
+    uint32 explorer_pid = *iter;
+    scoped_handle exp(::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
+                                    false,
+                                    explorer_pid));
+    if (exp) {
+      if (::OpenProcessToken(get(exp),
+                             TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_IMPERSONATE,
+                             token)) {
+        // TODO(omaha): Consider using the GetWindowsAccountDomainSid
+        // method here. This method returns the domain SID associated
+        // with the passed in SID. This allows us to detect if the user is a
+        // domain user. We should prefer domain users over normal users,
+        // as in corporate environments, these users will be more likely to
+        // allow to be tunneled through a proxy.
+        return S_OK;
+      } else {
+        hr = HRESULTFromLastError();
+        CORE_LOG(LEVEL_WARNING, (_T("[OpenProcessToken failed][0x%08x]"), hr));
+      }
+    } else {
+      hr = HRESULTFromLastError();
+      CORE_LOG(LEVEL_WARNING, (_T("[OpenProcess failed][0x%08x]"), hr));
+    }
+  }
+
+  return hr;
+}
+
+HRESULT GetPidsInSession(const TCHAR* exe_name,
+                         const TCHAR* user_sid,
+                         DWORD session_id,
+                         std::vector<uint32>* pids) {
+  ASSERT1(pids);
+  ASSERT1(exe_name);
+  ASSERT1(*exe_name);
+  UTIL_LOG(L3, (_T("[GetPidsInSession][%s][sid=%s][session=%d]"),
+                exe_name, user_sid, session_id));
+
+  pids->clear();
+
+  DWORD flags = EXCLUDE_CURRENT_PROCESS;
+  if (user_sid != NULL) {
+    flags |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
+  }
+  std::vector<CString> command_lines;
+  HRESULT hr = Process::FindProcessesInSession(session_id,
+                                               flags,
+                                               exe_name,
+                                               true,
+                                               user_sid,
+                                               command_lines,
+                                               pids);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  return pids->empty() ? HRESULT_FROM_WIN32(ERROR_NOT_FOUND) : S_OK;
+}
+
+HRESULT GetProcessPidsForActiveUserOrSession(const TCHAR* exe_name,
+                                             std::vector<uint32>* pids) {
+  bool is_system = false;
+  HRESULT hr = IsSystemProcess(&is_system);
+  if (FAILED(hr)) {
+    NET_LOG(LE, (_T("[IsSystemProcess failed][0x%x]"), hr));
+    return hr;
+  }
+
+  if (is_system) {
+    return vista::GetPidsInSession(exe_name,
+                                   NULL,
+                                   System::GetActiveSessionId(),
+                                   pids);
+  }
+
+  CString user_sid;
+  // If this call fails, we are still ok.
+  omaha::user_info::GetCurrentUser(NULL, NULL, &user_sid);
+  DWORD current_session = System::GetCurrentSessionId();
+  if (FAILED(vista::GetPidsInSession(exe_name,
+                                     user_sid,
+                                     current_session,
+                                     pids))) {
+    // In the case of RunAs, the processes may be under a different identity
+    // than the current sid. So if we are unable to find a process under the
+    // current user's sid, we search for processes running in the current
+    // session regardless of the sid they are running under.
+    return vista::GetPidsInSession(exe_name,
+                                   NULL,
+                                   current_session,
+                                   pids);
+  }
+
+  return S_OK;
+}
+
+
+
+HRESULT StartProcessWithTokenOfProcess(uint32 pid,
+                                       const CString& command_line) {
+  UTIL_LOG(L5, (_T("[StartProcessWithTokenOfProcess]")
+                _T("[pid %u][command_line '%s']"), pid, command_line));
+
+  // Get the token from process.
+  scoped_handle user_token;
+  HRESULT hr = Process::GetImpersonationToken(pid, address(user_token));
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_ERROR, (_T("[GetImpersonationToken failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Start process using the token.
+  UTIL_LOG(L5, (_T("[StartProcessWithTokenOfProcess][Running process %s]"),
+                command_line));
+  hr = RunAsUser(command_line, get(user_token), false);
+
+  if (FAILED(hr)) {
+    UTIL_LOG(LEVEL_ERROR,
+      (_T("[Vista::StartProcessWithTokenOfProcess - RunAsUser failed][0x%x]"),
+      hr));
+  }
+
+  return hr;
+}
+
+HRESULT GetLoggedOnUserToken(HANDLE* token) {
+  ASSERT1(token);
+  *token = NULL;
+
+  uint32 pid = 0;
+  HRESULT hr = GetExplorerPidForCurrentUserOrSession(&pid);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  hr = Process::GetImpersonationToken(pid, token);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ASSERT1(*token);
+  return S_OK;
+}
+
+}  // namespace vista
+
+}  // namespace omaha
+
diff --git a/common/vista_utils.h b/common/vista_utils.h
index bd8b23d..8592d32 100644
--- a/common/vista_utils.h
+++ b/common/vista_utils.h
@@ -1,101 +1,101 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_VISTA_UTILS_H__

-#define OMAHA_COMMON_VISTA_UTILS_H__

-

-#include <windows.h>

-#include <aclapi.h>

-#include <sddl.h>

-#include <userenv.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// Constants.

-const TCHAR* const kExplorer = _T("EXPLORER.EXE");

-const TCHAR* const kIExplore = _T("IEXPLORE.EXE");

-

-namespace vista {

-

-// Returns true if the current process is running in 'protected mode'.

-bool IsProcessProtected();

-

-// Allows processes that run under protected mode access to a shared kernel

-// object such as mapped memory.

-//

-// Returns S_OK if successful, S_FALSE if not running on vista, or an

-// error value.

-HRESULT AllowProtectedProcessAccessToSharedObject(const TCHAR* name);

-

-// Restarts IEUser process if we can. This is to allow for

-// IEUser.exe to refresh it's ElevationPolicy cache. Due to a bug

-// within IE7, IEUser.exe does not refresh it's cache unless it

-// is restarted in the manner below. If the cache is not refreshed

-// IEUser does not respect any new ElevationPolicies that a fresh

-// setup program installs for an ActiveX control or BHO. This code

-// is adapted from Toolbar.

-HRESULT RestartIEUser();

-

-// TODO(Omaha): Move these to a different utils file, since these are not

-// Vista-specific.

-// TODO(Omaha): rename for consistency with

-// GetProcessPidsForActiveUserOrSession.

-//

-// Gets current user's explorer.exe pid. If that fails, gets the pid of any

-// explorer.exe running in the current session.

-HRESULT GetExplorerPidForCurrentUserOrSession(uint32* pid);

-

-// Returns the TOKEN of the explorer process of any user that is logged in.

-HRESULT GetExplorerTokenForLoggedInUser(HANDLE* token);

-

-// Retrieves a primary token for one of the logged on users. The logged on

-// user is either the current user or a user logged on in the same session as

-// the current user. The caller must close the token handle.

-HRESULT GetLoggedOnUserToken(HANDLE* token);

-

-// Get PIDs for the processes running with the specified executable, user_sid,

-// and session_id. user_sid can be blank, in which case, the search will

-// encompass all processes with the given name in session_id. The session

-// always has to be a valid session, hence the name GetPidsInSession().

-HRESULT GetPidsInSession(const TCHAR* exe_name,

-                         const TCHAR* user_sid,

-                         DWORD session_id,

-                         std::vector<uint32>* pids);

-

-// Get the handle of exe_name running under the active user or active session.

-// If the call is made from the SYSTEM account, returns PIDs for exe_name

-// in the currently active user session. If the call is made from a user account

-// returns PIDs for that user, or if that cannot be found, in the current

-// session.

-HRESULT GetProcessPidsForActiveUserOrSession(const TCHAR* exe_name,

-                                             std::vector<uint32>* pids);

-

-// Starts process with the token obtained from the specified process.

-HRESULT StartProcessWithTokenOfProcess(uint32 pid,

-                                       const CString& command_line);

-

-// Runs the command on behalf of the current user. Creates a fresh environment

-// block based on the user's token.

-HRESULT RunAsCurrentUser(const CString& command_line);

-

-}  // namespace vista

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_VISTA_UTILS_H__

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_VISTA_UTILS_H__
+#define OMAHA_COMMON_VISTA_UTILS_H__
+
+#include <windows.h>
+#include <aclapi.h>
+#include <sddl.h>
+#include <userenv.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// Constants.
+const TCHAR* const kExplorer = _T("EXPLORER.EXE");
+const TCHAR* const kIExplore = _T("IEXPLORE.EXE");
+
+namespace vista {
+
+// Returns true if the current process is running in 'protected mode'.
+bool IsProcessProtected();
+
+// Allows processes that run under protected mode access to a shared kernel
+// object such as mapped memory.
+//
+// Returns S_OK if successful, S_FALSE if not running on vista, or an
+// error value.
+HRESULT AllowProtectedProcessAccessToSharedObject(const TCHAR* name);
+
+// Restarts IEUser process if we can. This is to allow for
+// IEUser.exe to refresh it's ElevationPolicy cache. Due to a bug
+// within IE7, IEUser.exe does not refresh it's cache unless it
+// is restarted in the manner below. If the cache is not refreshed
+// IEUser does not respect any new ElevationPolicies that a fresh
+// setup program installs for an ActiveX control or BHO. This code
+// is adapted from Toolbar.
+HRESULT RestartIEUser();
+
+// TODO(Omaha): Move these to a different utils file, since these are not
+// Vista-specific.
+// TODO(Omaha): rename for consistency with
+// GetProcessPidsForActiveUserOrSession.
+//
+// Gets current user's explorer.exe pid. If that fails, gets the pid of any
+// explorer.exe running in the current session.
+HRESULT GetExplorerPidForCurrentUserOrSession(uint32* pid);
+
+// Returns the TOKEN of the explorer process of any user that is logged in.
+HRESULT GetExplorerTokenForLoggedInUser(HANDLE* token);
+
+// Retrieves a primary token for one of the logged on users. The logged on
+// user is either the current user or a user logged on in the same session as
+// the current user. The caller must close the token handle.
+HRESULT GetLoggedOnUserToken(HANDLE* token);
+
+// Get PIDs for the processes running with the specified executable, user_sid,
+// and session_id. user_sid can be blank, in which case, the search will
+// encompass all processes with the given name in session_id. The session
+// always has to be a valid session, hence the name GetPidsInSession().
+HRESULT GetPidsInSession(const TCHAR* exe_name,
+                         const TCHAR* user_sid,
+                         DWORD session_id,
+                         std::vector<uint32>* pids);
+
+// Get the handle of exe_name running under the active user or active session.
+// If the call is made from the SYSTEM account, returns PIDs for exe_name
+// in the currently active user session. If the call is made from a user account
+// returns PIDs for that user, or if that cannot be found, in the current
+// session.
+HRESULT GetProcessPidsForActiveUserOrSession(const TCHAR* exe_name,
+                                             std::vector<uint32>* pids);
+
+// Starts process with the token obtained from the specified process.
+HRESULT StartProcessWithTokenOfProcess(uint32 pid,
+                                       const CString& command_line);
+
+// Runs the command on behalf of the current user. Creates a fresh environment
+// block based on the user's token.
+HRESULT RunAsCurrentUser(const CString& command_line);
+
+}  // namespace vista
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_VISTA_UTILS_H__
+
diff --git a/common/vista_utils_unittest.cc b/common/vista_utils_unittest.cc
index 4b6c7f1..06230cb 100644
--- a/common/vista_utils_unittest.cc
+++ b/common/vista_utils_unittest.cc
@@ -1,63 +1,63 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/app_util.h"

-#include "omaha/common/path.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vista_utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace vista {

-

-// Exercises RunAsUser() with explorer token. For Vista, the call to

-// StartProcessWithTokenOfProcess() will succeed only if the caller is SYSTEM.

-TEST(VistaUtilsTest, StartProcessWithExplorerTokenTest) {

-  CString path = ConcatenatePath(app_util::GetSystemDir(), _T("cmd.exe"));

-  EnclosePath(&path);

-  path += _T(" /c exit 702");

-  uint32 pid(0);

-  EXPECT_SUCCEEDED(GetExplorerPidForCurrentUserOrSession(&pid));

-

-  HRESULT hr = StartProcessWithTokenOfProcess(pid, path);

-  if (!vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(hr);

-    return;

-  }

-

-  bool is_system = false;

-  EXPECT_SUCCEEDED(IsSystemProcess(&is_system));

-  if (is_system) {

-    EXPECT_SUCCEEDED(hr);

-    return;

-  }

-

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PRIVILEGE_NOT_HELD), hr);

-}

-

-// Exercises RunAsUser() with current user token.

-TEST(VistaUtilsTest, RunAsCurrentUserTest) {

-  CString path = ConcatenatePath(app_util::GetSystemDir(), _T("cmd.exe"));

-  EnclosePath(&path);

-  path += _T(" /c exit 702");

-  EXPECT_SUCCEEDED(vista::RunAsCurrentUser(path));

-}

-

-}  // namespace vista

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/app_util.h"
+#include "omaha/common/path.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vista_utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace vista {
+
+// Exercises RunAsUser() with explorer token. For Vista, the call to
+// StartProcessWithTokenOfProcess() will succeed only if the caller is SYSTEM.
+TEST(VistaUtilsTest, StartProcessWithExplorerTokenTest) {
+  CString path = ConcatenatePath(app_util::GetSystemDir(), _T("cmd.exe"));
+  EnclosePath(&path);
+  path += _T(" /c exit 702");
+  uint32 pid(0);
+  EXPECT_SUCCEEDED(GetExplorerPidForCurrentUserOrSession(&pid));
+
+  HRESULT hr = StartProcessWithTokenOfProcess(pid, path);
+  if (!vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(hr);
+    return;
+  }
+
+  bool is_system = false;
+  EXPECT_SUCCEEDED(IsSystemProcess(&is_system));
+  if (is_system) {
+    EXPECT_SUCCEEDED(hr);
+    return;
+  }
+
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PRIVILEGE_NOT_HELD), hr);
+}
+
+// Exercises RunAsUser() with current user token.
+TEST(VistaUtilsTest, RunAsCurrentUserTest) {
+  CString path = ConcatenatePath(app_util::GetSystemDir(), _T("cmd.exe"));
+  EnclosePath(&path);
+  path += _T(" /c exit 702");
+  EXPECT_SUCCEEDED(vista::RunAsCurrentUser(path));
+}
+
+}  // namespace vista
+
+}  // namespace omaha
+
diff --git a/common/vistautil.cc b/common/vistautil.cc
index 4ed9d61..0d4bc6b 100644
--- a/common/vistautil.cc
+++ b/common/vistautil.cc
@@ -1,512 +1,512 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/vistautil.h"

-

-#include <accctrl.h>

-#include <Aclapi.h>

-#include <Sddl.h>

-#include <ShellAPI.h>

-#include <shlobj.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/process.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vista_utils.h"

-#include "omaha/third_party/smartany/scoped_any.h"

-

-namespace omaha {

-

-namespace vista_util {

-

-static SID_IDENTIFIER_AUTHORITY mandatory_label_auth =

-    SECURITY_MANDATORY_LABEL_AUTHORITY;

-

-

-static HRESULT GetSidIntegrityLevel(PSID sid, MANDATORY_LEVEL* level) {

-  if (!IsValidSid(sid))

-    return E_FAIL;

-

-  SID_IDENTIFIER_AUTHORITY* authority = GetSidIdentifierAuthority(sid);

-  if (!authority)

-    return E_FAIL;

-

-  if (memcmp(authority, &mandatory_label_auth,

-      sizeof(SID_IDENTIFIER_AUTHORITY)))

-    return E_FAIL;

-

-  PUCHAR count = GetSidSubAuthorityCount(sid);

-  if (!count || *count != 1)

-    return E_FAIL;

-

-  DWORD* rid = GetSidSubAuthority(sid, 0);

-  if (!rid)

-    return E_FAIL;

-

-  if ((*rid & 0xFFF) != 0 || *rid > SECURITY_MANDATORY_PROTECTED_PROCESS_RID)

-    return E_FAIL;

-

-  *level = static_cast<MANDATORY_LEVEL>(*rid >> 12);

-  return S_OK;

-}

-

-// Will return S_FALSE and MandatoryLevelMedium if the acl is NULL

-static HRESULT GetAclIntegrityLevel(PACL acl, MANDATORY_LEVEL* level,

-    bool* and_children) {

-  *level = MandatoryLevelMedium;

-  if (and_children)

-    *and_children = false;

-  if (!acl) {

-    // This is the default label value if the acl was empty

-    return S_FALSE;

-  }

-

-  SYSTEM_MANDATORY_LABEL_ACE* mandatory_label_ace;

-  if (!GetAce(acl, 0, reinterpret_cast<void**>(&mandatory_label_ace)))

-    return S_FALSE;

-

-  if (mandatory_label_ace->Header.AceType != SYSTEM_MANDATORY_LABEL_ACE_TYPE)

-    return S_FALSE;

-

-  if (!(mandatory_label_ace->Mask & SYSTEM_MANDATORY_LABEL_NO_WRITE_UP)) {

-    // I have found that if this flag is not set, a low integrity label doesn't

-    // prevent writes from being virtualized.  MS provides zero documentation.

-    // I just did an MSDN search, a Google search, and a search of the Beta

-    // Vista SDKs, and no docs. TODO(omaha): Check docs again periodically.

-    // For now, act as if no label was set, and default to medium.

-    return S_FALSE;

-  }

-

-  if (and_children) {

-    *and_children = ((mandatory_label_ace->Header.AceFlags &

-        (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE))

-        == (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE));

-  }

-

-  return GetSidIntegrityLevel(reinterpret_cast<SID*>(&mandatory_label_ace->

-      SidStart), level);

-}

-

-// If successful, the caller needs to free the ACL using LocalFree()

-// on failure, returns NULL

-static ACL* CreateMandatoryLabelAcl(MANDATORY_LEVEL level, bool and_children) {

-  int ace_size = sizeof(SYSTEM_MANDATORY_LABEL_ACE)

-      - sizeof(DWORD) + GetSidLengthRequired(1);

-  int acl_size = sizeof(ACL) + ace_size;

-

-  ACL* acl = reinterpret_cast<ACL*>(LocalAlloc(LPTR, acl_size));

-  if (!acl)

-    return NULL;

-

-  bool failed = true;

-  if (InitializeAcl(acl, acl_size, ACL_REVISION)) {

-    if (level > 0) {

-      SYSTEM_MANDATORY_LABEL_ACE* ace = reinterpret_cast<

-          SYSTEM_MANDATORY_LABEL_ACE*>(LocalAlloc(LPTR, ace_size));

-      if (ace) {

-        ace->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE;

-        ace->Header.AceFlags = and_children ?

-            (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE) : 0;

-        ace->Header.AceSize = static_cast<WORD>(ace_size);

-        ace->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP;

-

-        SID* sid = reinterpret_cast<SID*>(&ace->SidStart);

-

-        if (InitializeSid(sid, &mandatory_label_auth, 1)) {

-          *GetSidSubAuthority(sid, 0) = static_cast<DWORD>(level) << 12;

-          failed = !AddAce(acl, ACL_REVISION, 0, ace, ace_size);

-        }

-        LocalFree(ace);

-      }

-    }

-  }

-  if (failed) {

-    LocalFree(acl);

-    acl = NULL;

-  }

-  return acl;

-}

-

-

-TCHAR* AllocFullRegPath(HKEY root, const TCHAR* subkey) {

-  if (!subkey)

-    return NULL;

-

-  const TCHAR* root_string;

-

-  if (root == HKEY_CURRENT_USER)

-    root_string = _T("CURRENT_USER\\");

-  else if (root == HKEY_LOCAL_MACHINE)

-    root_string = _T("MACHINE\\");

-  else if (root == HKEY_CLASSES_ROOT)

-    root_string = _T("CLASSES_ROOT\\");

-  else if (root == HKEY_USERS)

-    root_string = _T("USERS\\");

-  else

-    return NULL;

-

-  size_t root_size = _tcslen(root_string);

-  size_t size = root_size + _tcslen(subkey) + 1;

-  TCHAR* result = reinterpret_cast<TCHAR*>(LocalAlloc(LPTR,

-      size * sizeof(TCHAR)));

-  if (!result)

-    return NULL;

-

-  memcpy(result, root_string, size * sizeof(TCHAR));

-  memcpy(result + root_size, subkey, (1 + size - root_size) * sizeof(TCHAR));

-  return result;

-}

-

-

-bool IsUserNonElevatedAdmin() {

-  // If pre-Vista return false;

-  if (!IsVistaOrLater()) {

-    return false;

-  }

-

-  bool non_elevated_admin = false;

-  scoped_handle token;

-  if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_READ, address(token))) {

-    TOKEN_ELEVATION_TYPE elevation_type = TokenElevationTypeDefault;

-    DWORD infoLen = 0;

-    if (::GetTokenInformation(get(token),

-                              TokenElevationType,

-                              reinterpret_cast<void*>(&elevation_type),

-                              sizeof(elevation_type),

-                              &infoLen)) {

-      if (elevation_type == TokenElevationTypeLimited) {

-        non_elevated_admin = true;

-      }

-    }

-  }

-

-  return non_elevated_admin;

-}

-

-bool IsUserAdmin() {

-  // Determine if the user is part of the adminstators group. This will return

-  // true in case of XP and 2K if the user belongs to admin group. In case of

-  // Vista, it only returns true if the admin is running elevated.

-  SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;

-  PSID administrators_group = NULL;

-  BOOL result = ::AllocateAndInitializeSid(&nt_authority,

-                                           2,

-                                           SECURITY_BUILTIN_DOMAIN_RID,

-                                           DOMAIN_ALIAS_RID_ADMINS,

-                                           0, 0, 0, 0, 0, 0,

-                                           &administrators_group);

-  if (result) {

-    if (!::CheckTokenMembership(NULL, administrators_group, &result)) {

-      result = false;

-    }

-    ::FreeSid(administrators_group);

-  }

-  return !!result;

-}

-

-bool IsVistaOrLater() {

-  static bool known = false;

-  static bool is_vista = false;

-  if (!known) {

-    OSVERSIONINFOEX osvi = { 0 };

-    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

-    osvi.dwMajorVersion = 6;

-    DWORDLONG conditional = 0;

-    VER_SET_CONDITION(conditional, VER_MAJORVERSION, VER_GREATER_EQUAL);

-    is_vista = !!VerifyVersionInfo(&osvi, VER_MAJORVERSION, conditional);

-    // If the Win32 API failed for some other reason, callers may incorrectly

-    // perform non-Vista operations. Assert we don't see any other failures.

-    ASSERT1(is_vista || ERROR_OLD_WIN_VERSION == ::GetLastError());

-    known = true;

-  }

-  return is_vista;

-}

-

-bool IsUserRunningSplitToken() {

-  if (!IsVistaOrLater()) {

-    return false;

-  }

-

-  scoped_handle process_token;

-  if (!::OpenProcessToken(GetCurrentProcess(),

-                          TOKEN_QUERY,

-                          address(process_token))) {

-    HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());

-    UTIL_LOG(L1, (_T("[OpenProcessToken failed][0x%x]"), hr));

-    return false;

-  }

-

-  TOKEN_ELEVATION_TYPE elevation_type = TokenElevationTypeDefault;

-  DWORD size_returned = 0;

-  if (!::GetTokenInformation(get(process_token),

-                             TokenElevationType,

-                             &elevation_type,

-                             sizeof(elevation_type),

-                             &size_returned)) {

-    HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());

-    UTIL_LOG(L1, (_T("[GetTokenInformation failed][0x%x]"), hr));

-    return false;

-  }

-

-  return (elevation_type == TokenElevationTypeFull ||

-          elevation_type == TokenElevationTypeLimited);

-}

-

-bool IsUACDisabled() {

-  if (!IsVistaOrLater()) {

-    return false;

-  }

-

-  if (IsUserRunningSplitToken()) {

-    // Split token indicates that UAC is on.

-    return false;

-  }

-

-  const TCHAR* key_name = _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\")

-                          _T("CurrentVersion\\Policies\\System");

-

-  DWORD val = 1;    // Assume UAC is enabled.

-  return SUCCEEDED(RegKey::GetValue(key_name, _T("EnableLUA"), &val)) && !val;

-}

-

-

-HRESULT RunElevated(const TCHAR* file_path,

-                    const TCHAR* parameters,

-                    int show_window,

-                    DWORD* exit_code) {

-  OPT_LOG(L1, (_T("[Running elevated][%s][%s]"), file_path, parameters));

-

-  SHELLEXECUTEINFO shell_execute_info;

-  shell_execute_info.cbSize = sizeof(SHELLEXECUTEINFO);

-  shell_execute_info.fMask = SEE_MASK_FLAG_NO_UI     |

-                             SEE_MASK_NOZONECHECKS   |

-                             SEE_MASK_NOASYNC;

-  if (exit_code != NULL) {

-    shell_execute_info.fMask |= SEE_MASK_NOCLOSEPROCESS;

-  }

-  shell_execute_info.hProcess = NULL;

-  shell_execute_info.hwnd = NULL;

-  shell_execute_info.lpVerb = L"runas";

-  shell_execute_info.lpFile = file_path;

-  shell_execute_info.lpParameters = parameters;

-  shell_execute_info.lpDirectory = NULL;

-  shell_execute_info.nShow = show_window;

-  shell_execute_info.hInstApp = NULL;

-

-  if (!ShellExecuteExEnsureParent(&shell_execute_info)) {

-    return AtlHresultFromLastError();

-  }

-

-  scoped_process process(shell_execute_info.hProcess);

-

-  // Wait for the end of the spawned process, if needed

-  if (exit_code) {

-    WaitForSingleObject(get(process), INFINITE);

-    VERIFY1(GetExitCodeProcess(get(process), exit_code));

-    UTIL_LOG(L1, (_T("[Elevated process exited][PID: %u][exit code: %u]"),

-                  Process::GetProcessIdFromHandle(get(process)), *exit_code));

-  } else {

-    UTIL_LOG(L1, (_T("[Elevated process exited][PID: %u]"),

-                  Process::GetProcessIdFromHandle(get(process))));

-  }

-

-  return S_OK;

-}

-

-

-HRESULT GetProcessIntegrityLevel(DWORD process_id, MANDATORY_LEVEL* level) {

-  if (!IsVistaOrLater())

-    return E_NOTIMPL;

-

-  if (process_id == 0)

-    process_id = GetCurrentProcessId();

-

-  HRESULT result = E_FAIL;

-  HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process_id);

-  if (process != NULL) {

-    HANDLE current_token;

-    if (OpenProcessToken(process,

-                         TOKEN_QUERY | TOKEN_QUERY_SOURCE,

-                         &current_token)) {

-      DWORD label_size = 0;

-      TOKEN_MANDATORY_LABEL* label;

-      GetTokenInformation(current_token, TokenIntegrityLevel,

-          NULL, 0, &label_size);

-      if (label_size && (label = reinterpret_cast<TOKEN_MANDATORY_LABEL*>

-          (LocalAlloc(LPTR, label_size))) != NULL) {

-        if (GetTokenInformation(current_token, TokenIntegrityLevel,

-            label, label_size, &label_size)) {

-          result = GetSidIntegrityLevel(label->Label.Sid, level);

-        }

-        LocalFree(label);

-      }

-      CloseHandle(current_token);

-    }

-    CloseHandle(process);

-  }

-  return result;

-}

-

-

-HRESULT GetFileOrFolderIntegrityLevel(const TCHAR* file,

-    MANDATORY_LEVEL* level, bool* and_children) {

-  if (!IsVistaOrLater())

-    return E_NOTIMPL;

-

-  PSECURITY_DESCRIPTOR descriptor;

-  PACL acl = NULL;

-

-  DWORD result = GetNamedSecurityInfo(const_cast<TCHAR*>(file), SE_FILE_OBJECT,

-      LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &acl, &descriptor);

-  if (result != ERROR_SUCCESS)

-    return HRESULT_FROM_WIN32(result);

-

-  HRESULT hr = GetAclIntegrityLevel(acl, level, and_children);

-  LocalFree(descriptor);

-  return hr;

-}

-

-

-HRESULT SetFileOrFolderIntegrityLevel(const TCHAR* file,

-    MANDATORY_LEVEL level, bool and_children) {

-  if (!IsVistaOrLater())

-    return E_NOTIMPL;

-

-  ACL* acl = CreateMandatoryLabelAcl(level, and_children);

-  if (!acl)

-    return E_FAIL;

-

-  DWORD result = SetNamedSecurityInfo(const_cast<TCHAR*>(file), SE_FILE_OBJECT,

-      LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, acl);

-  LocalFree(acl);

-  return HRESULT_FROM_WIN32(result);

-}

-

-

-HRESULT GetRegKeyIntegrityLevel(HKEY root, const TCHAR* subkey,

-    MANDATORY_LEVEL* level, bool* and_children) {

-  if (!IsVistaOrLater())

-    return E_NOTIMPL;

-

-  TCHAR* reg_path = AllocFullRegPath(root, subkey);

-  if (!reg_path)

-    return E_FAIL;

-

-  PSECURITY_DESCRIPTOR descriptor;

-  PACL acl = NULL;

-

-  DWORD result = GetNamedSecurityInfo(reg_path, SE_REGISTRY_KEY,

-      LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &acl, &descriptor);

-  if (result != ERROR_SUCCESS) {

-    LocalFree(reg_path);

-    return HRESULT_FROM_WIN32(result);

-  }

-

-  HRESULT hr = GetAclIntegrityLevel(acl, level, and_children);

-  LocalFree(descriptor);

-  LocalFree(reg_path);

-  return hr;

-}

-

-

-HRESULT SetRegKeyIntegrityLevel(HKEY root, const TCHAR* subkey,

-    MANDATORY_LEVEL level, bool and_children) {

-  if (!IsVistaOrLater())

-    return E_NOTIMPL;

-

-  TCHAR* reg_path = AllocFullRegPath(root, subkey);

-  if (!reg_path)

-    return E_FAIL;

-

-  ACL* acl = CreateMandatoryLabelAcl(level, and_children);

-  if (!acl) {

-    LocalFree(reg_path);

-    return E_FAIL;

-  }

-

-  DWORD result = SetNamedSecurityInfo(reg_path, SE_REGISTRY_KEY,

-      LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, acl);

-  LocalFree(acl);

-  LocalFree(reg_path);

-  return HRESULT_FROM_WIN32(result);

-}

-

-

-CSecurityDesc* BuildSecurityDescriptor(const TCHAR* sddl_sacl,

-                                       ACCESS_MASK mask) {

-  if (!IsVistaOrLater()) {

-    return NULL;

-  }

-

-  scoped_ptr<CSecurityDesc> security_descriptor(new CSecurityDesc);

-  security_descriptor->FromString(sddl_sacl);

-

-  // Fill out the rest of the security descriptor from the process token.

-  CAccessToken token;

-  if (!token.GetProcessToken(TOKEN_QUERY)) {

-    return NULL;

-  }

-

-  // The owner.

-  CSid sid_owner;

-  if (!token.GetOwner(&sid_owner)) {

-    return NULL;

-  }

-  security_descriptor->SetOwner(sid_owner);

-

-  // The group.

-  CSid sid_group;

-  if (!token.GetPrimaryGroup(&sid_group)) {

-    return NULL;

-  }

-  security_descriptor->SetGroup(sid_group);

-

-  // The discretionary access control list.

-  CDacl dacl;

-  if (!token.GetDefaultDacl(&dacl)) {

-    return NULL;

-  }

-

-  // Add an access control entry mask for the current user.

-  // This is what grants this user access from lower integrity levels.

-  CSid sid_user;

-  if (!token.GetUser(&sid_user)) {

-    return NULL;

-  }

-

-  if (!dacl.AddAllowedAce(sid_user, mask)) {

-    return NULL;

-  }

-

-  // Lastly, save the dacl to this descriptor.

-  security_descriptor->SetDacl(dacl);

-  return security_descriptor.release();

-};

-

-CSecurityDesc* CreateLowIntegritySecurityDesc(ACCESS_MASK mask) {

-  return BuildSecurityDescriptor(LOW_INTEGRITY_SDDL_SACL, mask);

-}

-

-CSecurityDesc* CreateMediumIntegritySecurityDesc(ACCESS_MASK mask) {

-  return BuildSecurityDescriptor(MEDIUM_INTEGRITY_SDDL_SACL, mask);

-}

-

-}  // namespace vista_util

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/vistautil.h"
+
+#include <accctrl.h>
+#include <Aclapi.h>
+#include <Sddl.h>
+#include <ShellAPI.h>
+#include <shlobj.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/process.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vista_utils.h"
+#include "omaha/third_party/smartany/scoped_any.h"
+
+namespace omaha {
+
+namespace vista_util {
+
+static SID_IDENTIFIER_AUTHORITY mandatory_label_auth =
+    SECURITY_MANDATORY_LABEL_AUTHORITY;
+
+
+static HRESULT GetSidIntegrityLevel(PSID sid, MANDATORY_LEVEL* level) {
+  if (!IsValidSid(sid))
+    return E_FAIL;
+
+  SID_IDENTIFIER_AUTHORITY* authority = GetSidIdentifierAuthority(sid);
+  if (!authority)
+    return E_FAIL;
+
+  if (memcmp(authority, &mandatory_label_auth,
+      sizeof(SID_IDENTIFIER_AUTHORITY)))
+    return E_FAIL;
+
+  PUCHAR count = GetSidSubAuthorityCount(sid);
+  if (!count || *count != 1)
+    return E_FAIL;
+
+  DWORD* rid = GetSidSubAuthority(sid, 0);
+  if (!rid)
+    return E_FAIL;
+
+  if ((*rid & 0xFFF) != 0 || *rid > SECURITY_MANDATORY_PROTECTED_PROCESS_RID)
+    return E_FAIL;
+
+  *level = static_cast<MANDATORY_LEVEL>(*rid >> 12);
+  return S_OK;
+}
+
+// Will return S_FALSE and MandatoryLevelMedium if the acl is NULL
+static HRESULT GetAclIntegrityLevel(PACL acl, MANDATORY_LEVEL* level,
+    bool* and_children) {
+  *level = MandatoryLevelMedium;
+  if (and_children)
+    *and_children = false;
+  if (!acl) {
+    // This is the default label value if the acl was empty
+    return S_FALSE;
+  }
+
+  SYSTEM_MANDATORY_LABEL_ACE* mandatory_label_ace;
+  if (!GetAce(acl, 0, reinterpret_cast<void**>(&mandatory_label_ace)))
+    return S_FALSE;
+
+  if (mandatory_label_ace->Header.AceType != SYSTEM_MANDATORY_LABEL_ACE_TYPE)
+    return S_FALSE;
+
+  if (!(mandatory_label_ace->Mask & SYSTEM_MANDATORY_LABEL_NO_WRITE_UP)) {
+    // I have found that if this flag is not set, a low integrity label doesn't
+    // prevent writes from being virtualized.  MS provides zero documentation.
+    // I just did an MSDN search, a Google search, and a search of the Beta
+    // Vista SDKs, and no docs. TODO(omaha): Check docs again periodically.
+    // For now, act as if no label was set, and default to medium.
+    return S_FALSE;
+  }
+
+  if (and_children) {
+    *and_children = ((mandatory_label_ace->Header.AceFlags &
+        (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE))
+        == (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE));
+  }
+
+  return GetSidIntegrityLevel(reinterpret_cast<SID*>(&mandatory_label_ace->
+      SidStart), level);
+}
+
+// If successful, the caller needs to free the ACL using LocalFree()
+// on failure, returns NULL
+static ACL* CreateMandatoryLabelAcl(MANDATORY_LEVEL level, bool and_children) {
+  int ace_size = sizeof(SYSTEM_MANDATORY_LABEL_ACE)
+      - sizeof(DWORD) + GetSidLengthRequired(1);
+  int acl_size = sizeof(ACL) + ace_size;
+
+  ACL* acl = reinterpret_cast<ACL*>(LocalAlloc(LPTR, acl_size));
+  if (!acl)
+    return NULL;
+
+  bool failed = true;
+  if (InitializeAcl(acl, acl_size, ACL_REVISION)) {
+    if (level > 0) {
+      SYSTEM_MANDATORY_LABEL_ACE* ace = reinterpret_cast<
+          SYSTEM_MANDATORY_LABEL_ACE*>(LocalAlloc(LPTR, ace_size));
+      if (ace) {
+        ace->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE;
+        ace->Header.AceFlags = and_children ?
+            (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE) : 0;
+        ace->Header.AceSize = static_cast<WORD>(ace_size);
+        ace->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP;
+
+        SID* sid = reinterpret_cast<SID*>(&ace->SidStart);
+
+        if (InitializeSid(sid, &mandatory_label_auth, 1)) {
+          *GetSidSubAuthority(sid, 0) = static_cast<DWORD>(level) << 12;
+          failed = !AddAce(acl, ACL_REVISION, 0, ace, ace_size);
+        }
+        LocalFree(ace);
+      }
+    }
+  }
+  if (failed) {
+    LocalFree(acl);
+    acl = NULL;
+  }
+  return acl;
+}
+
+
+TCHAR* AllocFullRegPath(HKEY root, const TCHAR* subkey) {
+  if (!subkey)
+    return NULL;
+
+  const TCHAR* root_string;
+
+  if (root == HKEY_CURRENT_USER)
+    root_string = _T("CURRENT_USER\\");
+  else if (root == HKEY_LOCAL_MACHINE)
+    root_string = _T("MACHINE\\");
+  else if (root == HKEY_CLASSES_ROOT)
+    root_string = _T("CLASSES_ROOT\\");
+  else if (root == HKEY_USERS)
+    root_string = _T("USERS\\");
+  else
+    return NULL;
+
+  size_t root_size = _tcslen(root_string);
+  size_t size = root_size + _tcslen(subkey) + 1;
+  TCHAR* result = reinterpret_cast<TCHAR*>(LocalAlloc(LPTR,
+      size * sizeof(TCHAR)));
+  if (!result)
+    return NULL;
+
+  memcpy(result, root_string, size * sizeof(TCHAR));
+  memcpy(result + root_size, subkey, (1 + size - root_size) * sizeof(TCHAR));
+  return result;
+}
+
+
+bool IsUserNonElevatedAdmin() {
+  // If pre-Vista return false;
+  if (!IsVistaOrLater()) {
+    return false;
+  }
+
+  bool non_elevated_admin = false;
+  scoped_handle token;
+  if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_READ, address(token))) {
+    TOKEN_ELEVATION_TYPE elevation_type = TokenElevationTypeDefault;
+    DWORD infoLen = 0;
+    if (::GetTokenInformation(get(token),
+                              TokenElevationType,
+                              reinterpret_cast<void*>(&elevation_type),
+                              sizeof(elevation_type),
+                              &infoLen)) {
+      if (elevation_type == TokenElevationTypeLimited) {
+        non_elevated_admin = true;
+      }
+    }
+  }
+
+  return non_elevated_admin;
+}
+
+bool IsUserAdmin() {
+  // Determine if the user is part of the adminstators group. This will return
+  // true in case of XP and 2K if the user belongs to admin group. In case of
+  // Vista, it only returns true if the admin is running elevated.
+  SID_IDENTIFIER_AUTHORITY nt_authority = SECURITY_NT_AUTHORITY;
+  PSID administrators_group = NULL;
+  BOOL result = ::AllocateAndInitializeSid(&nt_authority,
+                                           2,
+                                           SECURITY_BUILTIN_DOMAIN_RID,
+                                           DOMAIN_ALIAS_RID_ADMINS,
+                                           0, 0, 0, 0, 0, 0,
+                                           &administrators_group);
+  if (result) {
+    if (!::CheckTokenMembership(NULL, administrators_group, &result)) {
+      result = false;
+    }
+    ::FreeSid(administrators_group);
+  }
+  return !!result;
+}
+
+bool IsVistaOrLater() {
+  static bool known = false;
+  static bool is_vista = false;
+  if (!known) {
+    OSVERSIONINFOEX osvi = { 0 };
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+    osvi.dwMajorVersion = 6;
+    DWORDLONG conditional = 0;
+    VER_SET_CONDITION(conditional, VER_MAJORVERSION, VER_GREATER_EQUAL);
+    is_vista = !!VerifyVersionInfo(&osvi, VER_MAJORVERSION, conditional);
+    // If the Win32 API failed for some other reason, callers may incorrectly
+    // perform non-Vista operations. Assert we don't see any other failures.
+    ASSERT1(is_vista || ERROR_OLD_WIN_VERSION == ::GetLastError());
+    known = true;
+  }
+  return is_vista;
+}
+
+bool IsUserRunningSplitToken() {
+  if (!IsVistaOrLater()) {
+    return false;
+  }
+
+  scoped_handle process_token;
+  if (!::OpenProcessToken(GetCurrentProcess(),
+                          TOKEN_QUERY,
+                          address(process_token))) {
+    HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());
+    UTIL_LOG(L1, (_T("[OpenProcessToken failed][0x%x]"), hr));
+    return false;
+  }
+
+  TOKEN_ELEVATION_TYPE elevation_type = TokenElevationTypeDefault;
+  DWORD size_returned = 0;
+  if (!::GetTokenInformation(get(process_token),
+                             TokenElevationType,
+                             &elevation_type,
+                             sizeof(elevation_type),
+                             &size_returned)) {
+    HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());
+    UTIL_LOG(L1, (_T("[GetTokenInformation failed][0x%x]"), hr));
+    return false;
+  }
+
+  return (elevation_type == TokenElevationTypeFull ||
+          elevation_type == TokenElevationTypeLimited);
+}
+
+bool IsUACDisabled() {
+  if (!IsVistaOrLater()) {
+    return false;
+  }
+
+  if (IsUserRunningSplitToken()) {
+    // Split token indicates that UAC is on.
+    return false;
+  }
+
+  const TCHAR* key_name = _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\")
+                          _T("CurrentVersion\\Policies\\System");
+
+  DWORD val = 1;    // Assume UAC is enabled.
+  return SUCCEEDED(RegKey::GetValue(key_name, _T("EnableLUA"), &val)) && !val;
+}
+
+
+HRESULT RunElevated(const TCHAR* file_path,
+                    const TCHAR* parameters,
+                    int show_window,
+                    DWORD* exit_code) {
+  OPT_LOG(L1, (_T("[Running elevated][%s][%s]"), file_path, parameters));
+
+  SHELLEXECUTEINFO shell_execute_info;
+  shell_execute_info.cbSize = sizeof(SHELLEXECUTEINFO);
+  shell_execute_info.fMask = SEE_MASK_FLAG_NO_UI     |
+                             SEE_MASK_NOZONECHECKS   |
+                             SEE_MASK_NOASYNC;
+  if (exit_code != NULL) {
+    shell_execute_info.fMask |= SEE_MASK_NOCLOSEPROCESS;
+  }
+  shell_execute_info.hProcess = NULL;
+  shell_execute_info.hwnd = NULL;
+  shell_execute_info.lpVerb = L"runas";
+  shell_execute_info.lpFile = file_path;
+  shell_execute_info.lpParameters = parameters;
+  shell_execute_info.lpDirectory = NULL;
+  shell_execute_info.nShow = show_window;
+  shell_execute_info.hInstApp = NULL;
+
+  if (!ShellExecuteExEnsureParent(&shell_execute_info)) {
+    return AtlHresultFromLastError();
+  }
+
+  scoped_process process(shell_execute_info.hProcess);
+
+  // Wait for the end of the spawned process, if needed
+  if (exit_code) {
+    WaitForSingleObject(get(process), INFINITE);
+    VERIFY1(GetExitCodeProcess(get(process), exit_code));
+    UTIL_LOG(L1, (_T("[Elevated process exited][PID: %u][exit code: %u]"),
+                  Process::GetProcessIdFromHandle(get(process)), *exit_code));
+  } else {
+    UTIL_LOG(L1, (_T("[Elevated process exited][PID: %u]"),
+                  Process::GetProcessIdFromHandle(get(process))));
+  }
+
+  return S_OK;
+}
+
+
+HRESULT GetProcessIntegrityLevel(DWORD process_id, MANDATORY_LEVEL* level) {
+  if (!IsVistaOrLater())
+    return E_NOTIMPL;
+
+  if (process_id == 0)
+    process_id = GetCurrentProcessId();
+
+  HRESULT result = E_FAIL;
+  HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process_id);
+  if (process != NULL) {
+    HANDLE current_token;
+    if (OpenProcessToken(process,
+                         TOKEN_QUERY | TOKEN_QUERY_SOURCE,
+                         &current_token)) {
+      DWORD label_size = 0;
+      TOKEN_MANDATORY_LABEL* label;
+      GetTokenInformation(current_token, TokenIntegrityLevel,
+          NULL, 0, &label_size);
+      if (label_size && (label = reinterpret_cast<TOKEN_MANDATORY_LABEL*>
+          (LocalAlloc(LPTR, label_size))) != NULL) {
+        if (GetTokenInformation(current_token, TokenIntegrityLevel,
+            label, label_size, &label_size)) {
+          result = GetSidIntegrityLevel(label->Label.Sid, level);
+        }
+        LocalFree(label);
+      }
+      CloseHandle(current_token);
+    }
+    CloseHandle(process);
+  }
+  return result;
+}
+
+
+HRESULT GetFileOrFolderIntegrityLevel(const TCHAR* file,
+    MANDATORY_LEVEL* level, bool* and_children) {
+  if (!IsVistaOrLater())
+    return E_NOTIMPL;
+
+  PSECURITY_DESCRIPTOR descriptor;
+  PACL acl = NULL;
+
+  DWORD result = GetNamedSecurityInfo(const_cast<TCHAR*>(file), SE_FILE_OBJECT,
+      LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &acl, &descriptor);
+  if (result != ERROR_SUCCESS)
+    return HRESULT_FROM_WIN32(result);
+
+  HRESULT hr = GetAclIntegrityLevel(acl, level, and_children);
+  LocalFree(descriptor);
+  return hr;
+}
+
+
+HRESULT SetFileOrFolderIntegrityLevel(const TCHAR* file,
+    MANDATORY_LEVEL level, bool and_children) {
+  if (!IsVistaOrLater())
+    return E_NOTIMPL;
+
+  ACL* acl = CreateMandatoryLabelAcl(level, and_children);
+  if (!acl)
+    return E_FAIL;
+
+  DWORD result = SetNamedSecurityInfo(const_cast<TCHAR*>(file), SE_FILE_OBJECT,
+      LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, acl);
+  LocalFree(acl);
+  return HRESULT_FROM_WIN32(result);
+}
+
+
+HRESULT GetRegKeyIntegrityLevel(HKEY root, const TCHAR* subkey,
+    MANDATORY_LEVEL* level, bool* and_children) {
+  if (!IsVistaOrLater())
+    return E_NOTIMPL;
+
+  TCHAR* reg_path = AllocFullRegPath(root, subkey);
+  if (!reg_path)
+    return E_FAIL;
+
+  PSECURITY_DESCRIPTOR descriptor;
+  PACL acl = NULL;
+
+  DWORD result = GetNamedSecurityInfo(reg_path, SE_REGISTRY_KEY,
+      LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &acl, &descriptor);
+  if (result != ERROR_SUCCESS) {
+    LocalFree(reg_path);
+    return HRESULT_FROM_WIN32(result);
+  }
+
+  HRESULT hr = GetAclIntegrityLevel(acl, level, and_children);
+  LocalFree(descriptor);
+  LocalFree(reg_path);
+  return hr;
+}
+
+
+HRESULT SetRegKeyIntegrityLevel(HKEY root, const TCHAR* subkey,
+    MANDATORY_LEVEL level, bool and_children) {
+  if (!IsVistaOrLater())
+    return E_NOTIMPL;
+
+  TCHAR* reg_path = AllocFullRegPath(root, subkey);
+  if (!reg_path)
+    return E_FAIL;
+
+  ACL* acl = CreateMandatoryLabelAcl(level, and_children);
+  if (!acl) {
+    LocalFree(reg_path);
+    return E_FAIL;
+  }
+
+  DWORD result = SetNamedSecurityInfo(reg_path, SE_REGISTRY_KEY,
+      LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, acl);
+  LocalFree(acl);
+  LocalFree(reg_path);
+  return HRESULT_FROM_WIN32(result);
+}
+
+
+CSecurityDesc* BuildSecurityDescriptor(const TCHAR* sddl_sacl,
+                                       ACCESS_MASK mask) {
+  if (!IsVistaOrLater()) {
+    return NULL;
+  }
+
+  scoped_ptr<CSecurityDesc> security_descriptor(new CSecurityDesc);
+  security_descriptor->FromString(sddl_sacl);
+
+  // Fill out the rest of the security descriptor from the process token.
+  CAccessToken token;
+  if (!token.GetProcessToken(TOKEN_QUERY)) {
+    return NULL;
+  }
+
+  // The owner.
+  CSid sid_owner;
+  if (!token.GetOwner(&sid_owner)) {
+    return NULL;
+  }
+  security_descriptor->SetOwner(sid_owner);
+
+  // The group.
+  CSid sid_group;
+  if (!token.GetPrimaryGroup(&sid_group)) {
+    return NULL;
+  }
+  security_descriptor->SetGroup(sid_group);
+
+  // The discretionary access control list.
+  CDacl dacl;
+  if (!token.GetDefaultDacl(&dacl)) {
+    return NULL;
+  }
+
+  // Add an access control entry mask for the current user.
+  // This is what grants this user access from lower integrity levels.
+  CSid sid_user;
+  if (!token.GetUser(&sid_user)) {
+    return NULL;
+  }
+
+  if (!dacl.AddAllowedAce(sid_user, mask)) {
+    return NULL;
+  }
+
+  // Lastly, save the dacl to this descriptor.
+  security_descriptor->SetDacl(dacl);
+  return security_descriptor.release();
+};
+
+CSecurityDesc* CreateLowIntegritySecurityDesc(ACCESS_MASK mask) {
+  return BuildSecurityDescriptor(LOW_INTEGRITY_SDDL_SACL, mask);
+}
+
+CSecurityDesc* CreateMediumIntegritySecurityDesc(ACCESS_MASK mask) {
+  return BuildSecurityDescriptor(MEDIUM_INTEGRITY_SDDL_SACL, mask);
+}
+
+}  // namespace vista_util
+
+}  // namespace omaha
+
diff --git a/common/vistautil.h b/common/vistautil.h
index 1a156db..0a7a3cc 100644
--- a/common/vistautil.h
+++ b/common/vistautil.h
@@ -1,131 +1,131 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_VISTAUTIL_H__

-#define OMAHA_COMMON_VISTAUTIL_H__

-

-#include <windows.h>

-#include <tchar.h>

-#include <accctrl.h>

-#include <Aclapi.h>

-#include <Sddl.h>

-#include <WinNT.h>

-#include <atlsecurity.h>

-

-namespace omaha {

-

-// SACLs are normally used for auditing, but Vista also uses them to

-// determine integrity levels.

-// For more info, http://www.google.com/search?q=SDDL+for+Mandatory+Labels

-// S = SACL

-// ML = Mandatory label (aka integrity level)

-// NW = No write up (integrity levels less than low cannot gain access)

-// LW = Low Integrity Level (What IE normally runs in)

-

-// The LABEL_SECURITY_INFORMATION SDDL SACL for medium integrity.

-#define MEDIUM_INTEGRITY_SDDL_SACL _T("S:(ML;;NW;;;ME)")

-

-// The LABEL_SECURITY_INFORMATION SDDL SACL for low integrity.

-#define LOW_INTEGRITY_SDDL_SACL    _T("S:(ML;;NW;;;LW)")

-

-namespace vista_util {

-

-// This is fast, since it caches the answer after first run.

-bool IsVistaOrLater();

-

-// Is the user running on Vista or later with a split-token.

-bool IsUserRunningSplitToken();

-

-// Returns true if the user has the reg key for disabling UAC policy at startup

-// set.

-bool IsUACDisabled();

-

-// Returns true if the process is running under credentials of an user

-// belonging to the admin group in case of pre-Vista and in case Vista

-// returns true if the user is running as an elevated admin.

-bool IsUserAdmin();

-

-// Returns true if the user is running as a non-elevated admin in case of

-// Vista. In case of XP always returns false.

-bool IsUserNonElevatedAdmin();

-

-// Determine the mandatory level of a process

-//   processID, the process to query, or (0) to use the current process

-//   On Vista, level should alwys be filled in with either

-//     MandatoryLevelLow (IE)

-//     MandatoryLevelMedium(user), or

-//     MandatoryLevelHigh( Elevated Admin)

-//   On error, level remains unchanged

-HRESULT GetProcessIntegrityLevel(DWORD processID, MANDATORY_LEVEL* level);

-

-// Elevated processes need to be careful how they launch child processes

-// to avoid having them inherit too many credentials or not being able to

-// elevate their own IE processes normally.  Microsoft's advice from

-// http://msdn.microsoft.com/library/en-us/ietechcol/dnwebgen/protectedmode.asp

-// will launch a low integrity IE, but that IE cannot elevate properly since

-// it was running from the wrong token. The best method I can gather is to find

-// an existing process on the machine running at normal user rights, and launch

-// this process impersonating that token rather than trying to adjust token

-// privileges of the elevated token.  TODO(omaha): Implement and test this.

-HRESULT CreateProcessAsNormalUserFromElevatedAdmin(const TCHAR* commandline,

-    STARTUPINFO* startup_info, PROCESS_INFORMATION* process_info);

-

-// Starts a new elevated process. file_path specifies the program to be run.

-// If exit_code is not null, the function waits until the spawned process has

-// completed. The exit code of the process is returned therein.

-// If exit_code is null, the function will return after spawning the program

-// and will not wait for completion.

-// show_window is one of the SW_* constants to specify howw the windows is

-// opened.

-HRESULT RunElevated(const TCHAR* file_path, const TCHAR* parameters,

-    int show_window, DWORD* exit_code);

-

-// If there is no specific integrity level defined, return S_FALSE (1) and set

-// level to MandatoryLevelMedium (the Vista default)

-HRESULT GetFileOrFolderIntegrityLevel(const TCHAR* file,

-    MANDATORY_LEVEL* level, bool* and_children);

-

-// A level of MandatoryLevelUntrusted (0) will remove the integrity level for

-// this file and all children

-HRESULT SetFileOrFolderIntegrityLevel(const TCHAR* file,

-    MANDATORY_LEVEL level, bool and_children);

-

-// If there is no specific integrity level defined, return S_FALSE (1) and set

-// level to MandatoryLevelMedium (the Vista default)

-// root must be one of the 4 pre-defined roots: HKLM, HKCU, HKCR, HCU

-HRESULT GetRegKeyIntegrityLevel(HKEY root, const TCHAR* subkey,

-    MANDATORY_LEVEL* level, bool* and_children);

-

-// A level of MandatoryLevelUntrusted (0) will remove the integrity label

-// root must be one of the 4 pre-defined roots: HKLM, HKCU, HKCR, HCU

-HRESULT SetRegKeyIntegrityLevel(HKEY root, const TCHAR* subkey,

-    MANDATORY_LEVEL level, bool and_children);

-

-// Creates a security descriptor that can be used to make an object accessible

-// from the specified integrity level. When not running on Windows Vista or

-// in case of errors, the function returns NULL, which results in using

-// the default security descriptor.

-// The caller must take ownership of the returned security descriptor.

-// Mask will be added as an allowed ACE of the DACL.

-// For example, use MUTEX_ALL_ACCESS for shared mutexes.

-CSecurityDesc* CreateLowIntegritySecurityDesc(ACCESS_MASK mask);

-CSecurityDesc* CreateMediumIntegritySecurityDesc(ACCESS_MASK mask);

-

-}  // namespace vista_util

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_VISTAUTIL_H__

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_VISTAUTIL_H__
+#define OMAHA_COMMON_VISTAUTIL_H__
+
+#include <windows.h>
+#include <tchar.h>
+#include <accctrl.h>
+#include <Aclapi.h>
+#include <Sddl.h>
+#include <WinNT.h>
+#include <atlsecurity.h>
+
+namespace omaha {
+
+// SACLs are normally used for auditing, but Vista also uses them to
+// determine integrity levels.
+// For more info, http://www.google.com/search?q=SDDL+for+Mandatory+Labels
+// S = SACL
+// ML = Mandatory label (aka integrity level)
+// NW = No write up (integrity levels less than low cannot gain access)
+// LW = Low Integrity Level (What IE normally runs in)
+
+// The LABEL_SECURITY_INFORMATION SDDL SACL for medium integrity.
+#define MEDIUM_INTEGRITY_SDDL_SACL _T("S:(ML;;NW;;;ME)")
+
+// The LABEL_SECURITY_INFORMATION SDDL SACL for low integrity.
+#define LOW_INTEGRITY_SDDL_SACL    _T("S:(ML;;NW;;;LW)")
+
+namespace vista_util {
+
+// This is fast, since it caches the answer after first run.
+bool IsVistaOrLater();
+
+// Is the user running on Vista or later with a split-token.
+bool IsUserRunningSplitToken();
+
+// Returns true if the user has the reg key for disabling UAC policy at startup
+// set.
+bool IsUACDisabled();
+
+// Returns true if the process is running under credentials of an user
+// belonging to the admin group in case of pre-Vista and in case Vista
+// returns true if the user is running as an elevated admin.
+bool IsUserAdmin();
+
+// Returns true if the user is running as a non-elevated admin in case of
+// Vista. In case of XP always returns false.
+bool IsUserNonElevatedAdmin();
+
+// Determine the mandatory level of a process
+//   processID, the process to query, or (0) to use the current process
+//   On Vista, level should alwys be filled in with either
+//     MandatoryLevelLow (IE)
+//     MandatoryLevelMedium(user), or
+//     MandatoryLevelHigh( Elevated Admin)
+//   On error, level remains unchanged
+HRESULT GetProcessIntegrityLevel(DWORD processID, MANDATORY_LEVEL* level);
+
+// Elevated processes need to be careful how they launch child processes
+// to avoid having them inherit too many credentials or not being able to
+// elevate their own IE processes normally.  Microsoft's advice from
+// http://msdn.microsoft.com/library/en-us/ietechcol/dnwebgen/protectedmode.asp
+// will launch a low integrity IE, but that IE cannot elevate properly since
+// it was running from the wrong token. The best method I can gather is to find
+// an existing process on the machine running at normal user rights, and launch
+// this process impersonating that token rather than trying to adjust token
+// privileges of the elevated token.  TODO(omaha): Implement and test this.
+HRESULT CreateProcessAsNormalUserFromElevatedAdmin(const TCHAR* commandline,
+    STARTUPINFO* startup_info, PROCESS_INFORMATION* process_info);
+
+// Starts a new elevated process. file_path specifies the program to be run.
+// If exit_code is not null, the function waits until the spawned process has
+// completed. The exit code of the process is returned therein.
+// If exit_code is null, the function will return after spawning the program
+// and will not wait for completion.
+// show_window is one of the SW_* constants to specify howw the windows is
+// opened.
+HRESULT RunElevated(const TCHAR* file_path, const TCHAR* parameters,
+    int show_window, DWORD* exit_code);
+
+// If there is no specific integrity level defined, return S_FALSE (1) and set
+// level to MandatoryLevelMedium (the Vista default)
+HRESULT GetFileOrFolderIntegrityLevel(const TCHAR* file,
+    MANDATORY_LEVEL* level, bool* and_children);
+
+// A level of MandatoryLevelUntrusted (0) will remove the integrity level for
+// this file and all children
+HRESULT SetFileOrFolderIntegrityLevel(const TCHAR* file,
+    MANDATORY_LEVEL level, bool and_children);
+
+// If there is no specific integrity level defined, return S_FALSE (1) and set
+// level to MandatoryLevelMedium (the Vista default)
+// root must be one of the 4 pre-defined roots: HKLM, HKCU, HKCR, HCU
+HRESULT GetRegKeyIntegrityLevel(HKEY root, const TCHAR* subkey,
+    MANDATORY_LEVEL* level, bool* and_children);
+
+// A level of MandatoryLevelUntrusted (0) will remove the integrity label
+// root must be one of the 4 pre-defined roots: HKLM, HKCU, HKCR, HCU
+HRESULT SetRegKeyIntegrityLevel(HKEY root, const TCHAR* subkey,
+    MANDATORY_LEVEL level, bool and_children);
+
+// Creates a security descriptor that can be used to make an object accessible
+// from the specified integrity level. When not running on Windows Vista or
+// in case of errors, the function returns NULL, which results in using
+// the default security descriptor.
+// The caller must take ownership of the returned security descriptor.
+// Mask will be added as an allowed ACE of the DACL.
+// For example, use MUTEX_ALL_ACCESS for shared mutexes.
+CSecurityDesc* CreateLowIntegritySecurityDesc(ACCESS_MASK mask);
+CSecurityDesc* CreateMediumIntegritySecurityDesc(ACCESS_MASK mask);
+
+}  // namespace vista_util
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_VISTAUTIL_H__
+
diff --git a/common/vistautil_unittest.cc b/common/vistautil_unittest.cc
index 877296e..17934d8 100644
--- a/common/vistautil_unittest.cc
+++ b/common/vistautil_unittest.cc
@@ -1,41 +1,41 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <shlobj.h>

-#include "omaha/common/vistautil.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace vista_util {

-

-TEST(VistaUtilTest, IsUserAdmin) {

-  bool is_admin = !!::IsUserAnAdmin();

-  EXPECT_EQ(is_admin, vista_util::IsUserAdmin());

-}

-

-// Tests the code returns false if not Vista or later.

-TEST(VistaUtilTest, IsUACDisabled) {

-  bool is_uac_disabled = IsUACDisabled();

-  bool is_vista_or_later = vista_util::IsVistaOrLater();

-  if (!is_vista_or_later) {

-    EXPECT_FALSE(is_uac_disabled);

-  }

-}

-

-}  // namespace vista_util

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <shlobj.h>
+#include "omaha/common/vistautil.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace vista_util {
+
+TEST(VistaUtilTest, IsUserAdmin) {
+  bool is_admin = !!::IsUserAnAdmin();
+  EXPECT_EQ(is_admin, vista_util::IsUserAdmin());
+}
+
+// Tests the code returns false if not Vista or later.
+TEST(VistaUtilTest, IsUACDisabled) {
+  bool is_uac_disabled = IsUACDisabled();
+  bool is_vista_or_later = vista_util::IsVistaOrLater();
+  if (!is_vista_or_later) {
+    EXPECT_FALSE(is_uac_disabled);
+  }
+}
+
+}  // namespace vista_util
+
+}  // namespace omaha
+
diff --git a/common/window_utils.cc b/common/window_utils.cc
index 4e29b4c..1a97ac2 100644
--- a/common/window_utils.cc
+++ b/common/window_utils.cc
@@ -1,112 +1,112 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/window_utils.h"

-

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-

-namespace omaha {

-

-namespace {

-

-struct FindProcessWindowsRecord {

-  uint32 process_id;

-  uint32 window_flags;

-  CSimpleArray<HWND>* windows;

-};

-

-BOOL CALLBACK FindProcessWindowsEnumProc(HWND hwnd, LPARAM lparam) {

-  FindProcessWindowsRecord* enum_record =

-      reinterpret_cast<FindProcessWindowsRecord*>(lparam);

-  ASSERT1(enum_record);

-

-  DWORD process_id = 0;

-  ::GetWindowThreadProcessId(hwnd, &process_id);

-

-  // Only count this window if it is in the right process

-  // and it satisfies all specified window requirements.

-  if (enum_record->process_id != process_id) {

-    return true;

-  }

-  if ((enum_record->window_flags & kWindowMustBeTopLevel) &&

-      ::GetParent(hwnd)) {

-    return true;

-  }

-

-  if ((enum_record->window_flags & kWindowMustHaveSysMenu) &&

-      !(GetWindowLong(hwnd, GWL_STYLE) & WS_SYSMENU)) {

-    return true;

-  }

-

-  if ((enum_record->window_flags & kWindowMustBeVisible) &&

-      !::IsWindowVisible(hwnd)) {

-    return true;

-  }

-

-  enum_record->windows->Add(hwnd);

-  return true;

-}

-

-}  // namespace

-

-bool WindowUtils::FindProcessWindows(uint32 process_id,

-                                     uint32 window_flags,

-                                     CSimpleArray<HWND>* windows) {

-  ASSERT1(windows);

-  windows->RemoveAll();

-  FindProcessWindowsRecord enum_record = {0};

-  enum_record.process_id = process_id;

-  enum_record.window_flags = window_flags;

-  enum_record.windows = windows;

-  ::EnumWindows(FindProcessWindowsEnumProc,

-                reinterpret_cast<LPARAM>(&enum_record));

-  int num_windows = enum_record.windows->GetSize();

-  return num_windows > 0;

-}

-

-void WindowUtils::MakeWindowForeground(HWND wnd) {

-  if (!IsWindowVisible(wnd)) {

-    // If the window is hidden and we call SetWindowPos with SWP_SHOWWINDOW

-    // then the window will be visible.

-    // If the caller wants it visible they should do it themselves first.

-    return;

-  }

-  if (!SetWindowPos(wnd,

-                    HWND_TOP,

-                    0,

-                    0,

-                    0,

-                    0,

-                    SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW)) {

-    UTIL_LOG(LE, (_T("[WindowUtils::MakeWindowForeground]")

-                  _T("[SetWindowPos failed][0x%08x]"), HRESULTFromLastError()));

-  }

-}

-

-bool WindowUtils::IsMainWindow(HWND wnd) {

-  return NULL == ::GetParent(wnd) && IsWindowVisible(wnd);

-}

-

-bool WindowUtils::HasSystemMenu(HWND wnd) {

-  return (GetWindowLong(wnd, GWL_STYLE) & WS_SYSMENU) != 0;

-}

-

-}  // namespace omaha

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/window_utils.h"
+
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+
+namespace omaha {
+
+namespace {
+
+struct FindProcessWindowsRecord {
+  uint32 process_id;
+  uint32 window_flags;
+  CSimpleArray<HWND>* windows;
+};
+
+BOOL CALLBACK FindProcessWindowsEnumProc(HWND hwnd, LPARAM lparam) {
+  FindProcessWindowsRecord* enum_record =
+      reinterpret_cast<FindProcessWindowsRecord*>(lparam);
+  ASSERT1(enum_record);
+
+  DWORD process_id = 0;
+  ::GetWindowThreadProcessId(hwnd, &process_id);
+
+  // Only count this window if it is in the right process
+  // and it satisfies all specified window requirements.
+  if (enum_record->process_id != process_id) {
+    return true;
+  }
+  if ((enum_record->window_flags & kWindowMustBeTopLevel) &&
+      ::GetParent(hwnd)) {
+    return true;
+  }
+
+  if ((enum_record->window_flags & kWindowMustHaveSysMenu) &&
+      !(GetWindowLong(hwnd, GWL_STYLE) & WS_SYSMENU)) {
+    return true;
+  }
+
+  if ((enum_record->window_flags & kWindowMustBeVisible) &&
+      !::IsWindowVisible(hwnd)) {
+    return true;
+  }
+
+  enum_record->windows->Add(hwnd);
+  return true;
+}
+
+}  // namespace
+
+bool WindowUtils::FindProcessWindows(uint32 process_id,
+                                     uint32 window_flags,
+                                     CSimpleArray<HWND>* windows) {
+  ASSERT1(windows);
+  windows->RemoveAll();
+  FindProcessWindowsRecord enum_record = {0};
+  enum_record.process_id = process_id;
+  enum_record.window_flags = window_flags;
+  enum_record.windows = windows;
+  ::EnumWindows(FindProcessWindowsEnumProc,
+                reinterpret_cast<LPARAM>(&enum_record));
+  int num_windows = enum_record.windows->GetSize();
+  return num_windows > 0;
+}
+
+void WindowUtils::MakeWindowForeground(HWND wnd) {
+  if (!IsWindowVisible(wnd)) {
+    // If the window is hidden and we call SetWindowPos with SWP_SHOWWINDOW
+    // then the window will be visible.
+    // If the caller wants it visible they should do it themselves first.
+    return;
+  }
+  if (!SetWindowPos(wnd,
+                    HWND_TOP,
+                    0,
+                    0,
+                    0,
+                    0,
+                    SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW)) {
+    UTIL_LOG(LE, (_T("[WindowUtils::MakeWindowForeground]")
+                  _T("[SetWindowPos failed][0x%08x]"), HRESULTFromLastError()));
+  }
+}
+
+bool WindowUtils::IsMainWindow(HWND wnd) {
+  return NULL == ::GetParent(wnd) && IsWindowVisible(wnd);
+}
+
+bool WindowUtils::HasSystemMenu(HWND wnd) {
+  return (GetWindowLong(wnd, GWL_STYLE) & WS_SYSMENU) != 0;
+}
+
+}  // namespace omaha
+
diff --git a/common/window_utils.h b/common/window_utils.h
index 8607e26..4f95ca8 100644
--- a/common/window_utils.h
+++ b/common/window_utils.h
@@ -1,55 +1,55 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_COMMON_WINDOW_UTILS_H__

-#define OMAHA_COMMON_WINDOW_UTILS_H__

-

-#include <atlcoll.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// Flags for window requirements.

-const uint32 kWindowMustBeTopLevel  =  0x00000001;

-const uint32 kWindowMustHaveSysMenu =  0x00000002;

-const uint32 kWindowMustBeVisible   =  0x00000004;

-

-class WindowUtils {

- public:

-  // Finds all the primary windows owned by the given process. For the

-  // purposes of this function, primary windows are top-level, have a system

-  // menu, and are visible.

-  static bool FindProcessWindows(uint32 process_id,

-                                 uint32 window_flags,

-                                 CSimpleArray<HWND>* windows);

-

-  // Forces the window to the foreground.

-  static void MakeWindowForeground(HWND wnd);

-

-  // Returns true if the window is the "main window" of a process:

-  // if it's Visible, and Top Level

-  static bool IsMainWindow(HWND wnd);

-

-  // Returns true if the window has a System Menu

-  static bool HasSystemMenu(HWND wnd);

-

- private:

-  DISALLOW_IMPLICIT_CONSTRUCTORS(WindowUtils);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_WINDOW_UTILS_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_COMMON_WINDOW_UTILS_H__
+#define OMAHA_COMMON_WINDOW_UTILS_H__
+
+#include <atlcoll.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// Flags for window requirements.
+const uint32 kWindowMustBeTopLevel  =  0x00000001;
+const uint32 kWindowMustHaveSysMenu =  0x00000002;
+const uint32 kWindowMustBeVisible   =  0x00000004;
+
+class WindowUtils {
+ public:
+  // Finds all the primary windows owned by the given process. For the
+  // purposes of this function, primary windows are top-level, have a system
+  // menu, and are visible.
+  static bool FindProcessWindows(uint32 process_id,
+                                 uint32 window_flags,
+                                 CSimpleArray<HWND>* windows);
+
+  // Forces the window to the foreground.
+  static void MakeWindowForeground(HWND wnd);
+
+  // Returns true if the window is the "main window" of a process:
+  // if it's Visible, and Top Level
+  static bool IsMainWindow(HWND wnd);
+
+  // Returns true if the window has a System Menu
+  static bool HasSystemMenu(HWND wnd);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(WindowUtils);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_WINDOW_UTILS_H__
diff --git a/common/wmi_query.cc b/common/wmi_query.cc
index a70228d..64c5f62 100644
--- a/common/wmi_query.cc
+++ b/common/wmi_query.cc
@@ -1,204 +1,204 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/wmi_query.h"

-

-#include <atlcomcli.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-WmiQuery::WmiQuery() : at_end_(true) {

-}

-

-WmiQuery::~WmiQuery() {

-}

-

-HRESULT WmiQuery::Connect(const TCHAR* resource) {

-  UTIL_LOG(L6, (_T("[WmiQuery::Connect][resource=%s]"), resource));

-  ASSERT1(resource && *resource);

-

-  CComBSTR object_path;

-  HRESULT hr = object_path.Append(resource);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = wbem_.CoCreateInstance(__uuidof(WbemLocator));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Connect to WMI through the IWbemLocator::ConnectServer method. This

-  // call can block up to 2 minutes on XP or indefinitely on Windows 2000 if

-  // the server is broken.

-  hr = wbem_->ConnectServer(object_path,                      // object path

-                            NULL,                             // username

-                            NULL,                             // password

-                            NULL,                             // locale

-                            WBEM_FLAG_CONNECT_USE_MAX_WAIT,   // security flags

-                            NULL,                             // authority

-                            0,                                // context

-                            &service_);                       // namespace

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Set security levels on the proxy.

-  hr = ::CoSetProxyBlanket(service_,

-                           RPC_C_AUTHN_WINNT,

-                           RPC_C_AUTHZ_NONE,

-                           NULL,

-                           RPC_C_AUTHN_LEVEL_CALL,

-                           RPC_C_IMP_LEVEL_IMPERSONATE,

-                           NULL,

-                           EOAC_NONE);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT WmiQuery::Query(const TCHAR* query) {

-  UTIL_LOG(L6, (_T("[WmiQuery::Query][query=%s]"), query));

-  ASSERT1(query && *query);

-

-  CComBSTR query_language, query_string;

-  HRESULT hr = query_language.Append(_T("WQL"));

-  if (FAILED(hr)) {

-    return hr;

-  }

-  hr = query_string.Append(query);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  uint32 flags = WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY;

-  hr = service_->ExecQuery(query_language,

-                           query_string,

-                           flags,

-                           NULL,

-                           &enumerator_);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  at_end_ = false;

-  return Next();

-}

-

-HRESULT WmiQuery::Next() {

-  UTIL_LOG(L6, (_T("[WmiQuery::Next]")));

-

-  ASSERT1(!at_end_);

-

-  ULONG ret = 0;

-  HRESULT hr = enumerator_->Next(WBEM_INFINITE, 1, &obj_, &ret);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  at_end_ = ret == 0;

-  return S_OK;

-}

-

-bool WmiQuery::AtEnd() {

-  return at_end_;

-}

-

-HRESULT WmiQuery::GetValue(const TCHAR* name, CComVariant* value) {

-  ASSERT1(name && *name);

-  ASSERT1(value);

-  ASSERT1(!at_end_ && obj_);

-

-  value->Clear();

-

-  CComBSTR name_string;

-  HRESULT hr = name_string.Append(name);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  hr = obj_->Get(name_string, 0, value, 0, 0);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT WmiQuery::GetValue(const TCHAR* name, CString* value) {

-  ASSERT1(name && *name);

-  ASSERT1(value);

-

-  CComVariant var;

-  HRESULT hr = GetValue(name, &var);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ASSERT1(V_VT(&var) == VT_BSTR);

-  value->SetString(var.bstrVal);

-  return S_OK;

-}

-

-HRESULT WmiQuery::GetValue(const TCHAR* name, bool* value) {

-  ASSERT1(name && *name);

-  ASSERT1(value);

-

-  CComVariant var;

-  HRESULT hr = GetValue(name, &var);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ASSERT1(V_VT(&var) == VT_BOOL);

-  *value = var.boolVal != 0;

-  return S_OK;

-}

-

-HRESULT WmiQuery::GetValue(const TCHAR* name, int* value) {

-  ASSERT1(name && *name);

-  ASSERT1(value);

-

-  CComVariant var;

-  HRESULT hr = GetValue(name, &var);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ASSERT1(V_VT(&var) == VT_I4);

-  *value = var.lVal;

-  return S_OK;

-}

-

-HRESULT WmiQuery::GetValue(const TCHAR* name, uint32* value) {

-  ASSERT1(name && *name);

-  ASSERT1(value);

-

-  CComVariant var;

-  HRESULT hr = GetValue(name, &var);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ASSERT1(V_VT(&var) == VT_UI4);

-  *value = var.ulVal;

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/wmi_query.h"
+
+#include <atlcomcli.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+WmiQuery::WmiQuery() : at_end_(true) {
+}
+
+WmiQuery::~WmiQuery() {
+}
+
+HRESULT WmiQuery::Connect(const TCHAR* resource) {
+  UTIL_LOG(L6, (_T("[WmiQuery::Connect][resource=%s]"), resource));
+  ASSERT1(resource && *resource);
+
+  CComBSTR object_path;
+  HRESULT hr = object_path.Append(resource);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = wbem_.CoCreateInstance(__uuidof(WbemLocator));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Connect to WMI through the IWbemLocator::ConnectServer method. This
+  // call can block up to 2 minutes on XP or indefinitely on Windows 2000 if
+  // the server is broken.
+  hr = wbem_->ConnectServer(object_path,                      // object path
+                            NULL,                             // username
+                            NULL,                             // password
+                            NULL,                             // locale
+                            WBEM_FLAG_CONNECT_USE_MAX_WAIT,   // security flags
+                            NULL,                             // authority
+                            0,                                // context
+                            &service_);                       // namespace
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Set security levels on the proxy.
+  hr = ::CoSetProxyBlanket(service_,
+                           RPC_C_AUTHN_WINNT,
+                           RPC_C_AUTHZ_NONE,
+                           NULL,
+                           RPC_C_AUTHN_LEVEL_CALL,
+                           RPC_C_IMP_LEVEL_IMPERSONATE,
+                           NULL,
+                           EOAC_NONE);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT WmiQuery::Query(const TCHAR* query) {
+  UTIL_LOG(L6, (_T("[WmiQuery::Query][query=%s]"), query));
+  ASSERT1(query && *query);
+
+  CComBSTR query_language, query_string;
+  HRESULT hr = query_language.Append(_T("WQL"));
+  if (FAILED(hr)) {
+    return hr;
+  }
+  hr = query_string.Append(query);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  uint32 flags = WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY;
+  hr = service_->ExecQuery(query_language,
+                           query_string,
+                           flags,
+                           NULL,
+                           &enumerator_);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  at_end_ = false;
+  return Next();
+}
+
+HRESULT WmiQuery::Next() {
+  UTIL_LOG(L6, (_T("[WmiQuery::Next]")));
+
+  ASSERT1(!at_end_);
+
+  ULONG ret = 0;
+  HRESULT hr = enumerator_->Next(WBEM_INFINITE, 1, &obj_, &ret);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  at_end_ = ret == 0;
+  return S_OK;
+}
+
+bool WmiQuery::AtEnd() {
+  return at_end_;
+}
+
+HRESULT WmiQuery::GetValue(const TCHAR* name, CComVariant* value) {
+  ASSERT1(name && *name);
+  ASSERT1(value);
+  ASSERT1(!at_end_ && obj_);
+
+  value->Clear();
+
+  CComBSTR name_string;
+  HRESULT hr = name_string.Append(name);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  hr = obj_->Get(name_string, 0, value, 0, 0);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT WmiQuery::GetValue(const TCHAR* name, CString* value) {
+  ASSERT1(name && *name);
+  ASSERT1(value);
+
+  CComVariant var;
+  HRESULT hr = GetValue(name, &var);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ASSERT1(V_VT(&var) == VT_BSTR);
+  value->SetString(var.bstrVal);
+  return S_OK;
+}
+
+HRESULT WmiQuery::GetValue(const TCHAR* name, bool* value) {
+  ASSERT1(name && *name);
+  ASSERT1(value);
+
+  CComVariant var;
+  HRESULT hr = GetValue(name, &var);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ASSERT1(V_VT(&var) == VT_BOOL);
+  *value = var.boolVal != 0;
+  return S_OK;
+}
+
+HRESULT WmiQuery::GetValue(const TCHAR* name, int* value) {
+  ASSERT1(name && *name);
+  ASSERT1(value);
+
+  CComVariant var;
+  HRESULT hr = GetValue(name, &var);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ASSERT1(V_VT(&var) == VT_I4);
+  *value = var.lVal;
+  return S_OK;
+}
+
+HRESULT WmiQuery::GetValue(const TCHAR* name, uint32* value) {
+  ASSERT1(name && *name);
+  ASSERT1(value);
+
+  CComVariant var;
+  HRESULT hr = GetValue(name, &var);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ASSERT1(V_VT(&var) == VT_UI4);
+  *value = var.ulVal;
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/common/wmi_query.h b/common/wmi_query.h
index 71f4ed2..c631056 100644
--- a/common/wmi_query.h
+++ b/common/wmi_query.h
@@ -1,65 +1,65 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_COMMON_WMI_QUERY_H_

-#define OMAHA_COMMON_WMI_QUERY_H_

-

-#include <windows.h>

-#include <wbemidl.h>

-#include <atlbase.h>

-#include <atlcomcli.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class WmiQuery {

- public:

-  WmiQuery();

-  ~WmiQuery();

-

-  // Connects to the server to get WMI service.

-  HRESULT Connect(const TCHAR* resource);

-

-  // Queries the service.

-  HRESULT Query(const TCHAR* query);

-

-  // Reads the next row.

-  HRESULT Next();

-

-  // Returns true at the end.

-  bool AtEnd();

-

-  // Gets the value of the named property.

-  HRESULT GetValue(const TCHAR* name, CComVariant* value);

-  HRESULT GetValue(const TCHAR* name, CString* value);

-  HRESULT GetValue(const TCHAR* name, bool* value);

-  HRESULT GetValue(const TCHAR* name, int* value);

-  HRESULT GetValue(const TCHAR* name, uint32* value);

-

- private:

-  CComPtr<IWbemLocator> wbem_;

-  CComPtr<IWbemServices> service_;

-  CComPtr<IEnumWbemClassObject> enumerator_;

-  CComPtr<IWbemClassObject> obj_;

-  bool at_end_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(WmiQuery);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_WMI_QUERY_H_

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_COMMON_WMI_QUERY_H_
+#define OMAHA_COMMON_WMI_QUERY_H_
+
+#include <windows.h>
+#include <wbemidl.h>
+#include <atlbase.h>
+#include <atlcomcli.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class WmiQuery {
+ public:
+  WmiQuery();
+  ~WmiQuery();
+
+  // Connects to the server to get WMI service.
+  HRESULT Connect(const TCHAR* resource);
+
+  // Queries the service.
+  HRESULT Query(const TCHAR* query);
+
+  // Reads the next row.
+  HRESULT Next();
+
+  // Returns true at the end.
+  bool AtEnd();
+
+  // Gets the value of the named property.
+  HRESULT GetValue(const TCHAR* name, CComVariant* value);
+  HRESULT GetValue(const TCHAR* name, CString* value);
+  HRESULT GetValue(const TCHAR* name, bool* value);
+  HRESULT GetValue(const TCHAR* name, int* value);
+  HRESULT GetValue(const TCHAR* name, uint32* value);
+
+ private:
+  CComPtr<IWbemLocator> wbem_;
+  CComPtr<IWbemServices> service_;
+  CComPtr<IEnumWbemClassObject> enumerator_;
+  CComPtr<IWbemClassObject> obj_;
+  bool at_end_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(WmiQuery);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_WMI_QUERY_H_
+
diff --git a/common/wmi_query_unittest.cc b/common/wmi_query_unittest.cc
index caab897..83aaa4a 100644
--- a/common/wmi_query_unittest.cc
+++ b/common/wmi_query_unittest.cc
@@ -1,42 +1,42 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/wmi_query.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(WmiQueryTest, WmiQuery) {

-  WmiQuery wq;

-  ASSERT_HRESULT_SUCCEEDED(wq.Connect(_T("root\\CIMV2")));

-  ASSERT_HRESULT_SUCCEEDED(wq.Query(_T("select * from Win32_OperatingSystem")));

-

-  CString manufacturer;

-  EXPECT_HRESULT_SUCCEEDED(wq.GetValue(_T("Manufacturer"), &manufacturer));

-  EXPECT_STREQ(_T("Microsoft Corporation"), manufacturer);

-

-  // Expect a retail build of the OS.

-  bool is_debug(true);

-  EXPECT_HRESULT_SUCCEEDED(wq.GetValue(_T("Debug"), &is_debug));

-  EXPECT_FALSE(is_debug);

-

-  int max_number_of_processes(0);

-  EXPECT_HRESULT_SUCCEEDED(wq.GetValue(_T("MaxNumberOfProcesses"),

-                           &max_number_of_processes));

-  EXPECT_EQ(-1, max_number_of_processes);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/wmi_query.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(WmiQueryTest, WmiQuery) {
+  WmiQuery wq;
+  ASSERT_HRESULT_SUCCEEDED(wq.Connect(_T("root\\CIMV2")));
+  ASSERT_HRESULT_SUCCEEDED(wq.Query(_T("select * from Win32_OperatingSystem")));
+
+  CString manufacturer;
+  EXPECT_HRESULT_SUCCEEDED(wq.GetValue(_T("Manufacturer"), &manufacturer));
+  EXPECT_STREQ(_T("Microsoft Corporation"), manufacturer);
+
+  // Expect a retail build of the OS.
+  bool is_debug(true);
+  EXPECT_HRESULT_SUCCEEDED(wq.GetValue(_T("Debug"), &is_debug));
+  EXPECT_FALSE(is_debug);
+
+  int max_number_of_processes(0);
+  EXPECT_HRESULT_SUCCEEDED(wq.GetValue(_T("MaxNumberOfProcesses"),
+                           &max_number_of_processes));
+  EXPECT_EQ(-1, max_number_of_processes);
+}
+
+}  // namespace omaha
+
diff --git a/common/wtl_atlapp_wrapper.h b/common/wtl_atlapp_wrapper.h
index 12cb68f..17b0227 100644
--- a/common/wtl_atlapp_wrapper.h
+++ b/common/wtl_atlapp_wrapper.h
@@ -1,36 +1,36 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Use this header instead of using WTL's atlapp.h directly.

-//

-// WTL80 uses deprecated _vswprintf calls which may be unsafe. Disables the

-// deprecation warning until WTL is fully compatible with VC 9.0.

-//

-// WTL80 uses min and max macros, which are disabled in the build. The work

-// around is to use std::min and std::max.

-

-#include <algorithm>

-using std::min;

-using std::max;

-

-#pragma warning(push)

-#pragma warning(disable : 4265 4996)

-// 4265: class has virtual functions, but destructor is not virtual

-// 4996: 'function' was declared deprecated

-

-#include <atlapp.h>

-

-#pragma warning(pop)

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Use this header instead of using WTL's atlapp.h directly.
+//
+// WTL80 uses deprecated _vswprintf calls which may be unsafe. Disables the
+// deprecation warning until WTL is fully compatible with VC 9.0.
+//
+// WTL80 uses min and max macros, which are disabled in the build. The work
+// around is to use std::min and std::max.
+
+#include <algorithm>
+using std::min;
+using std::max;
+
+#pragma warning(push)
+#pragma warning(disable : 4265 4996)
+// 4265: class has virtual functions, but destructor is not virtual
+// 4996: 'function' was declared deprecated
+
+#include <atlapp.h>
+
+#pragma warning(pop)
+
diff --git a/common/xml_utils.cc b/common/xml_utils.cc
index d4b33fd..4320da9 100644
--- a/common/xml_utils.cc
+++ b/common/xml_utils.cc
@@ -1,602 +1,602 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// xml_utils.cpp

-//

-// Utilities for working with XML files via MSXML.

-

-#include "omaha/common/xml_utils.h"

-

-#include <msxml2.h>

-#include <atlsafe.h>

-#include <vector>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-XMLFQName::XMLFQName() {}

-

-XMLFQName::XMLFQName(const TCHAR* u, const TCHAR* b)

-    : uri(u && ::_tcslen(u) ? u : 0),

-      base(b && ::_tcslen(b) ? b : 0) {}

-

-XMLFQName::~XMLFQName() {}

-

-HRESULT CoCreateSafeDOMDocument(IXMLDOMDocument** my_xmldoc) {

-  ASSERT1(my_xmldoc && !*my_xmldoc);

-  if (!my_xmldoc) {

-    UTIL_LOG(LE, (L"[CoCreateSafeDOMDocument E_INVALIDARG]"));

-    return E_INVALIDARG;

-  }

-  *my_xmldoc = NULL;

-  CComPtr<IXMLDOMDocument> xml_doc;

-  HRESULT hr = xml_doc.CoCreateInstance(__uuidof(DOMDocument2));

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[xml_doc.CoCreateInstance failed][0x%x]"), hr));

-    return hr;

-  }

-  ASSERT1(xml_doc);

-  hr = xml_doc->put_resolveExternals(VARIANT_FALSE);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[put_resolveExternals failed][0x%x]"), hr));

-    return hr;

-  }

-  *my_xmldoc = xml_doc.Detach();

-  return S_OK;

-}

-

-HRESULT LoadXMLFromFile(const TCHAR* xmlfile,

-                        bool preserve_whitespace,

-                        IXMLDOMDocument** xmldoc) {

-  ASSERT1(xmlfile);

-  ASSERT1(xmldoc);

-  ASSERT1(!*xmldoc);

-

-  *xmldoc = NULL;

-  CComPtr<IXMLDOMDocument> my_xmldoc;

-  HRESULT hr = CoCreateSafeDOMDocument(&my_xmldoc);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[CoCreateSafeDOMDocument failed][0x%x]"), hr));

-    return hr;

-  }

-  hr = my_xmldoc->put_preserveWhiteSpace(VARIANT_BOOL(preserve_whitespace));

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[put_preserveWhiteSpace failed][0x%x]"), hr));

-    return hr;

-  }

-  CComBSTR my_xmlfile(xmlfile);

-  VARIANT_BOOL is_successful(VARIANT_FALSE);

-  hr = my_xmldoc->load(CComVariant(my_xmlfile), &is_successful);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[my_xmldoc->load failed][0x%x]"), hr));

-    return hr;

-  }

-  if (!is_successful) {

-    CComPtr<IXMLDOMParseError> error;

-    CString error_message;

-    hr = GetXMLParseError(my_xmldoc, &error);

-    if (FAILED(hr)) {

-      UTIL_LOG(LE, (_T("[GetXMLParseError failed][0x%x]"), hr));

-      return hr;

-    }

-    ASSERT1(error);

-    HRESULT error_code = 0;

-    hr = InterpretXMLParseError(error, &error_code, &error_message);

-    if (FAILED(hr)) {

-      UTIL_LOG(LE, (_T("[InterpretXMLParseError failed][0x%x]"), hr));

-      return hr;

-    }

-    UTIL_LOG(LE, (L"[LoadXMLFromFile '%s'][parse error: %s]",

-                  xmlfile, error_message));

-    ASSERT1(FAILED(error_code));

-    return FAILED(error_code) ? error_code : CI_E_XML_LOAD_ERROR;

-  }

-  *xmldoc = my_xmldoc.Detach();

-  return S_OK;

-}

-

-HRESULT LoadXMLFromMemory(const TCHAR* xmlstring,

-                          bool preserve_whitespace,

-                          IXMLDOMDocument** xmldoc) {

-  ASSERT1(xmlstring);

-  ASSERT1(xmldoc);

-  ASSERT1(!*xmldoc);

-

-  *xmldoc = NULL;

-  CComPtr<IXMLDOMDocument> my_xmldoc;

-  RET_IF_FAILED(CoCreateSafeDOMDocument(&my_xmldoc));

-  RET_IF_FAILED(my_xmldoc->put_preserveWhiteSpace(

-                               VARIANT_BOOL(preserve_whitespace)));

-  CComBSTR xmlmemory(xmlstring);

-  VARIANT_BOOL is_successful(VARIANT_FALSE);

-  RET_IF_FAILED(my_xmldoc->loadXML(xmlmemory, &is_successful));

-  if (!is_successful) {

-    CComPtr<IXMLDOMParseError> error;

-    CString error_message;

-    RET_IF_FAILED(GetXMLParseError(my_xmldoc, &error));

-    ASSERT1(error);

-    HRESULT error_code = 0;

-    RET_IF_FAILED(InterpretXMLParseError(error, &error_code, &error_message));

-    UTIL_LOG(LE, (L"[LoadXMLFromMemory][parse error: %s]", error_message));

-    ASSERT1(FAILED(error_code));

-    return FAILED(error_code) ? error_code : CI_E_XML_LOAD_ERROR;

-  }

-  *xmldoc = my_xmldoc.Detach();

-  return S_OK;

-}

-

-HRESULT LoadXMLFromRawData(const std::vector<byte>& xmldata,

-                           bool preserve_whitespace,

-                           IXMLDOMDocument** xmldoc) {

-  ASSERT1(xmldoc);

-  ASSERT1(!*xmldoc);

-

-  *xmldoc = NULL;

-  CComPtr<IXMLDOMDocument> my_xmldoc;

-  RET_IF_FAILED(CoCreateSafeDOMDocument(&my_xmldoc));

-  RET_IF_FAILED(my_xmldoc->put_preserveWhiteSpace(

-                              VARIANT_BOOL(preserve_whitespace)));

-

-  CComSafeArray<byte> xmlsa;

-  xmlsa.Add(xmldata.size(), &xmldata.front());

-  CComVariant xmlvar(xmlsa);

-

-  VARIANT_BOOL is_successful(VARIANT_FALSE);

-  RET_IF_FAILED(my_xmldoc->load(xmlvar, &is_successful));

-  if (!is_successful) {

-    CComPtr<IXMLDOMParseError> error;

-    CString error_message;

-    RET_IF_FAILED(GetXMLParseError(my_xmldoc, &error));

-    ASSERT1(error);

-    HRESULT error_code = 0;

-    RET_IF_FAILED(InterpretXMLParseError(error, &error_code, &error_message));

-    UTIL_LOG(LE, (_T("[LoadXMLFromRawData][parse error: %s]"), error_message));

-    ASSERT1(FAILED(error_code));

-    return FAILED(error_code) ? error_code : CI_E_XML_LOAD_ERROR;

-  }

-  *xmldoc = my_xmldoc.Detach();

-  return S_OK;

-}

-

-HRESULT SaveXMLToFile(IXMLDOMDocument* xmldoc, const TCHAR* xmlfile) {

-  ASSERT1(xmldoc);

-  ASSERT1(xmlfile);

-

-  CComBSTR my_xmlfile(xmlfile);

-  RET_IF_FAILED(xmldoc->save(CComVariant(my_xmlfile)));

-  return S_OK;

-}

-

-HRESULT SaveXMLToMemory(IXMLDOMDocument* xmldoc, CString* xmlstring) {

-  ASSERT1(xmldoc);

-  ASSERT1(xmlstring);

-

-  CComBSTR xmlmemory;

-  RET_IF_FAILED(xmldoc->get_xml(&xmlmemory));

-  *xmlstring = xmlmemory;

-

-  return S_OK;

-}

-

-HRESULT CanonicalizeXML(const TCHAR* xmlstring, CString* canonical_xmlstring) {

-  ASSERT1(xmlstring);

-  ASSERT1(canonical_xmlstring);

-

-  // Round-trip through MSXML, having it strip whitespace.

-

-  CComPtr<IXMLDOMDocument> xmldoc;

-  RET_IF_FAILED(CoCreateSafeDOMDocument(&xmldoc));

-  RET_IF_FAILED(xmldoc->put_preserveWhiteSpace(VARIANT_FALSE));

-  {

-    CComBSTR xmlmemory(StringAfterBOM(xmlstring));

-    VARIANT_BOOL is_successful(VARIANT_FALSE);

-    RET_IF_FAILED(xmldoc->loadXML(xmlmemory, &is_successful));

-    if (!is_successful) {

-      CComPtr<IXMLDOMParseError> error;

-      CString error_message;

-      RET_IF_FAILED(GetXMLParseError(xmldoc, &error));

-      ASSERT1(error);

-      HRESULT error_code = 0;

-      RET_IF_FAILED(InterpretXMLParseError(error, &error_code, &error_message));

-      UTIL_LOG(LE, (L"[CanonicalizeXML][parse error: %s]", error_message));

-      ASSERT1(FAILED(error_code));

-      return FAILED(error_code) ? error_code : CI_E_XML_LOAD_ERROR;

-    }

-  }

-  std::vector<CString> lines;

-  {

-    CComBSTR xmlmemory2;

-    RET_IF_FAILED(xmldoc->get_xml(&xmlmemory2));

-    TextToLines(CString(xmlmemory2), L"\r\n", &lines);

-  }

-  {

-    for (size_t i = 0; i < lines.size(); ++i) {

-      TrimString(lines[i], L" \t");

-    }

-    LinesToText(lines, L"", canonical_xmlstring);

-  }

-

-  return S_OK;

-}

-

-bool operator==(const XMLFQName& u, const XMLFQName& v) {

-  if (u.uri && v.uri) {

-    // Both uris are non-null -> compare all the components.

-    return !_tcscmp(u.uri, v.uri) && !_tcscmp(u.base, v.base);

-  } else if (!u.uri && !v.uri) {

-    // Both uris are null -> only compare the base names.

-    return !_tcscmp(u.base ? u.base : __T(""), v.base ? v.base : __T(""));

-  } else {

-    // Either uri is null -> the names are in different namespaces.

-    return false;

-  }

-}

-

-bool operator!=(const XMLFQName& u, const XMLFQName& v) {

-  return !(u == v);

-}

-

-bool operator<(const XMLFQName& u, const XMLFQName &v) {

-  if (u.uri && v.uri) {

-    return (_tcscmp(u.uri, v.uri) < 0) ||

-            ((_tcscmp(u.uri, v.uri) == 0) && (_tcscmp(u.base, v.base) < 0));

-  } else if (!u.uri && !v.uri) {

-    return _tcscmp(u.base, v.base) < 0;

-  } else {

-    return false;

-  }

-}

-

-bool operator>(const XMLFQName& u, const XMLFQName& v) {

-  return v < u;

-}

-

-bool operator<=(const XMLFQName& u, const XMLFQName& v) {

-  return !(v < u);

-}

-

-bool operator>=(const XMLFQName& u, const XMLFQName& v) {

-  return !(u < v);

-}

-

-bool EqualXMLName(const XMLFQName& u, const XMLFQName& v) {

-  return u == v;

-}

-

-// msxml returns a null uri for nodes that don't belong to a namespace.

-bool EqualXMLName(IXMLDOMNode* pnode, const XMLFQName& u) {

-  CComBSTR name;

-  CComBSTR uri;

-  if (FAILED(pnode->get_baseName(&name)) ||

-      FAILED(pnode->get_namespaceURI(&uri))) {

-    return false;

-  }

-  return EqualXMLName(XMLFQName(uri, name), u);

-}

-

-inline bool EqualXMLName(const XMLFQName& u, IXMLDOMNode* pnode) {

-  return EqualXMLName(pnode, u);

-}

-

-HRESULT GetXMLFQName(IXMLDOMNode* node, XMLFQName* name) {

-  ASSERT1(node);

-  ASSERT1(name);

-

-  CComBSTR basename, uri;

-  RET_IF_FAILED(node->get_baseName(&basename));

-  RET_IF_FAILED(node->get_namespaceURI(&uri));

-  *name = XMLFQName(uri, basename);

-  return S_OK;

-}

-

-CString XMLFQNameToString(const XMLFQName& fqname) {

-  CString name;

-  if (fqname.uri) {

-    name += fqname.uri;

-    name += L":";

-  }

-  if (fqname.base) {

-    name += fqname.base;

-  }

-  return name;

-}

-

-CString NodeToString(IXMLDOMNode* pnode) {

-  ASSERT1(pnode);

-

-  XMLFQName node_name;

-  if (SUCCEEDED(GetXMLFQName(pnode, &node_name))) {

-    return XMLFQNameToString(node_name);

-  }

-  return L"";

-}

-

-HRESULT CreateXMLNode(IXMLDOMDocument* xmldoc,

-                      int node_type,

-                      const TCHAR* node_name,

-                      const TCHAR* namespace_uri,

-                      const TCHAR* text,

-                      IXMLDOMNode** node_out) {

-  ASSERT1(xmldoc);

-  ASSERT1(node_name);

-  // namespace_uri can be NULL

-  // text can be NULL

-  ASSERT1(node_out);

-  ASSERT1(!*node_out);

-

-  *node_out = NULL;

-  CComPtr<IXMLDOMNode> new_node;

-  CComBSTR node_name_string, namespace_uri_string;

-  RET_IF_FAILED(node_name_string.Append(node_name));

-  RET_IF_FAILED(namespace_uri_string.Append(namespace_uri));

-  RET_IF_FAILED(xmldoc->createNode(CComVariant(node_type),

-                                   node_name_string,

-                                   namespace_uri_string,

-                                   &new_node));

-  ASSERT1(new_node);

-

-  // If any text was supplied, put it in the node

-  if (text && text[0]) {

-    RET_IF_FAILED(new_node->put_text(CComBSTR(text)));

-  }

-

-  *node_out = new_node.Detach();

-  return S_OK;

-}

-

-HRESULT AppendXMLNode(IXMLDOMNode* xmlnode, IXMLDOMNode* new_child) {

-  ASSERT1(xmlnode);

-  ASSERT1(new_child);

-

-  CComPtr<IXMLDOMNode> useless;

-  RET_IF_FAILED(xmlnode->appendChild(new_child, &useless));

-  return S_OK;

-}

-

-HRESULT AppendXMLNode(IXMLDOMNode* xmlnode, const TCHAR* text) {

-  ASSERT1(xmlnode);

-  // text can be NULL

-

-  if (text && text[0]) {

-    CComPtr<IXMLDOMDocument> xml_doc;

-    CComPtr<IXMLDOMText> text_node;

-    RET_IF_FAILED(xmlnode->get_ownerDocument(&xml_doc));

-    ASSERT1(xml_doc);

-    RET_IF_FAILED(xml_doc->createTextNode(CComBSTR(text), &text_node));

-    RET_IF_FAILED(AppendXMLNode(xmlnode, text_node));

-  }

-  return S_OK;

-}

-

-HRESULT AddXMLAttributeNode(IXMLDOMNode* xmlnode, IXMLDOMAttribute* new_child) {

-  ASSERT1(xmlnode);

-  ASSERT1(new_child);

-

-  CComPtr<IXMLDOMNamedNodeMap> attributes;

-  CComPtr<IXMLDOMNode> useless;

-  RET_IF_FAILED(xmlnode->get_attributes(&attributes));

-  RET_IF_FAILED(attributes->setNamedItem(new_child, &useless));

-  return S_OK;

-}

-

-HRESULT AddXMLAttributeNode(IXMLDOMElement* xmlelement,

-                            const TCHAR* attribute_name,

-                            const TCHAR* attribute_value) {

-  ASSERT1(xmlelement);

-  ASSERT1(attribute_name);

-  // attribute_value can be NULL

-

-  RET_IF_FAILED(xmlelement->setAttribute(CComBSTR(attribute_name),

-                                         CComVariant(attribute_value)));

-  return S_OK;

-}

-

-HRESULT AddXMLAttributeNode(IXMLDOMNode* xmlnode,

-                            const TCHAR* attribute_namespace,

-                            const TCHAR* attribute_name,

-                            const TCHAR* attribute_value) {

-  ASSERT1(xmlnode);

-  ASSERT1(attribute_name);

-  // attribute_namespace can be NULL

-  // attribute_value can be NULL

-

-  CComPtr<IXMLDOMDocument> xmldoc;

-  RET_IF_FAILED(xmlnode->get_ownerDocument(&xmldoc));

-  ASSERT1(xmldoc);

-

-  CComPtr<IXMLDOMNode> attribute_node;

-  RET_IF_FAILED(CreateXMLNode(xmldoc,

-                              NODE_ATTRIBUTE,

-                              attribute_name,

-                              attribute_namespace,

-                              attribute_value,

-                              &attribute_node));

-  CComQIPtr<IXMLDOMAttribute> attribute(attribute_node);

-  ASSERT1(attribute);

-  RET_IF_FAILED(AddXMLAttributeNode(xmlnode, attribute));

-  return S_OK;

-}

-

-HRESULT RemoveXMLChildrenByName(IXMLDOMNode* xmlnode, const XMLFQName& name) {

-  ASSERT1(xmlnode);

-

-  CComPtr<IXMLDOMNodeList> node_list;

-  RET_IF_FAILED(xmlnode->get_childNodes(&node_list));

-  ASSERT1(node_list);

-

-  bool found = false;

-  do {

-    found = false;

-    long count = 0;   // NOLINT

-    RET_IF_FAILED(node_list->get_length(&count));

-    RET_IF_FAILED(node_list->reset());

-

-    for (int i = 0; i < count; ++i) {

-      CComPtr<IXMLDOMNode> child_node, useless;

-      RET_IF_FAILED(node_list->get_item(i, &child_node));

-      ASSERT1(child_node);

-      if (EqualXMLName(child_node, name)) {

-        RET_IF_FAILED(xmlnode->removeChild(child_node, &useless));

-        // Start loop over: the list is "alive" and changes when you remove a

-        // node from it. Yes this seems to be n^2 but in fact we expect at

-        // most one each of <Hash> and/or <Size> nodes.

-        found = true;

-        break;

-      }

-    }

-  } while (found);

-

-  return S_OK;

-}

-

-HRESULT GetXMLChildByName(IXMLDOMElement* xmlnode,

-                          const TCHAR* child_name,

-                          IXMLDOMNode** xmlchild) {

-  ASSERT1(xmlnode);

-  ASSERT1(child_name);

-  ASSERT1(xmlchild);

-  ASSERT1(!*xmlchild);

-

-  *xmlchild = NULL;

-  CComPtr<IXMLDOMNodeList> node_list;

-  long node_list_length = 0;    // NOLINT

-  RET_IF_FAILED(xmlnode->getElementsByTagName(CComBSTR(child_name),

-                                              &node_list));

-  ASSERT1(node_list);

-  RET_IF_FAILED(node_list->get_length(&node_list_length));

-  if (node_list_length <= 0) {

-    return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);

-  }

-  // Should only be one child node with name we're looking for.

-  if (node_list_length > 1) {

-    return CI_E_INVALID_MANIFEST;

-  }

-  RET_IF_FAILED(node_list->reset());

-  RET_IF_FAILED(node_list->get_item(0, xmlchild));

-  ASSERT1(*xmlchild);

-  return S_OK;

-}

-

-HRESULT InsertXMLBeforeItem(IXMLDOMNode* xmlnode,

-                            IXMLDOMNode* new_child,

-                            size_t item_number) {

-  ASSERT1(xmlnode);

-  ASSERT1(new_child);

-

-  CComPtr<IXMLDOMNodeList> child_list;

-  CComPtr<IXMLDOMNode> refchild, useless;

-

-  RET_IF_FAILED(xmlnode->get_childNodes(&child_list));

-  ASSERT1(child_list);

-  RET_IF_FAILED(child_list->get_item(item_number, &refchild));

-  ASSERT1(refchild);

-  RET_IF_FAILED(xmlnode->insertBefore(new_child,

-                                      CComVariant(refchild),

-                                      &useless));

-  return S_OK;

-}

-

-HRESULT GetXMLParseError(IXMLDOMDocument* xmldoc,

-                         IXMLDOMParseError** parse_error) {

-  ASSERT1(xmldoc);

-  ASSERT1(parse_error);

-  ASSERT1(!*parse_error);

-

-  *parse_error = NULL;

-  CComPtr<IXMLDOMParseError> error;

-  RET_IF_FAILED(xmldoc->get_parseError(&error));

-  HRESULT error_code = 0;

-  HRESULT hr = error->get_errorCode(&error_code);

-  if (hr == S_OK) {

-    *parse_error = error.Detach();

-    return S_OK;

-  } else if (hr == S_FALSE) {

-    // No parse error

-    return S_FALSE;

-  } else {

-    return hr;

-  }

-}

-

-HRESULT InterpretXMLParseError(IXMLDOMParseError* parse_error,

-                               HRESULT* error_code,

-                               CString* message) {

-  ASSERT1(parse_error);

-  ASSERT1(error_code);

-  ASSERT1(message);

-

-  long line = 0;      // NOLINT

-  long char_pos = 0;  // NOLINT

-  CComBSTR src_text, reason;

-  RET_IF_FAILED(parse_error->get_errorCode(error_code));

-  RET_IF_FAILED(parse_error->get_line(&line));

-  RET_IF_FAILED(parse_error->get_linepos(&char_pos));

-  RET_IF_FAILED(parse_error->get_srcText(&src_text));

-  RET_IF_FAILED(parse_error->get_reason(&reason));

-

-  // Wild guess.

-  size_t size_estimate = src_text.Length() + reason.Length() + 100;

-

-  // TODO(omaha): think about replacing this call to _snwprintf with a

-  // safestring function.

-  std::vector<TCHAR> s(size_estimate);

-  _snwprintf_s(&s.front(), size_estimate, _TRUNCATE,

-               L"%d(%d) : error 0x%08lx: %s\n  %s",

-               line, char_pos, *error_code,

-               reason ? reason : L"",

-               src_text ? src_text : L"<no source text>");

-  // _snwprintf doesn't terminate the string with a null if

-  // the formatted string fills the entire buffer.

-  s[s.size()- 1] = L'\0';

-  *message = &s.front();

-  return S_OK;

-}

-

-HRESULT GetNumChildren(IXMLDOMNode* node, int* num_children) {

-  ASSERT1(node);

-  ASSERT1(num_children);

-

-  *num_children = 0;

-  CComPtr<IXMLDOMNodeList> children;

-  RET_IF_FAILED(node->get_childNodes(&children));

-  ASSERT1(children);

-

-  long len = 0;   // NOLINT

-  RET_IF_FAILED(children->get_length(&len));

-  *num_children = len;

-  return S_OK;

-}

-

-int GetNumAttributes(IXMLDOMNode* node) {

-  ASSERT1(node);

-

-  CComPtr<IXMLDOMNamedNodeMap> attr_map;

-  if (FAILED(node->get_attributes(&attr_map))) {

-    return 0;

-  }

-  ASSERT1(attr_map);

-  long len = 0;   // NOLINT

-  if (FAILED(attr_map->get_length(&len))) {

-    return 0;

-  }

-  return len;

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// xml_utils.cpp
+//
+// Utilities for working with XML files via MSXML.
+
+#include "omaha/common/xml_utils.h"
+
+#include <msxml2.h>
+#include <atlsafe.h>
+#include <vector>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+XMLFQName::XMLFQName() {}
+
+XMLFQName::XMLFQName(const TCHAR* u, const TCHAR* b)
+    : uri(u && ::_tcslen(u) ? u : 0),
+      base(b && ::_tcslen(b) ? b : 0) {}
+
+XMLFQName::~XMLFQName() {}
+
+HRESULT CoCreateSafeDOMDocument(IXMLDOMDocument** my_xmldoc) {
+  ASSERT1(my_xmldoc && !*my_xmldoc);
+  if (!my_xmldoc) {
+    UTIL_LOG(LE, (L"[CoCreateSafeDOMDocument E_INVALIDARG]"));
+    return E_INVALIDARG;
+  }
+  *my_xmldoc = NULL;
+  CComPtr<IXMLDOMDocument> xml_doc;
+  HRESULT hr = xml_doc.CoCreateInstance(__uuidof(DOMDocument2));
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[xml_doc.CoCreateInstance failed][0x%x]"), hr));
+    return hr;
+  }
+  ASSERT1(xml_doc);
+  hr = xml_doc->put_resolveExternals(VARIANT_FALSE);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[put_resolveExternals failed][0x%x]"), hr));
+    return hr;
+  }
+  *my_xmldoc = xml_doc.Detach();
+  return S_OK;
+}
+
+HRESULT LoadXMLFromFile(const TCHAR* xmlfile,
+                        bool preserve_whitespace,
+                        IXMLDOMDocument** xmldoc) {
+  ASSERT1(xmlfile);
+  ASSERT1(xmldoc);
+  ASSERT1(!*xmldoc);
+
+  *xmldoc = NULL;
+  CComPtr<IXMLDOMDocument> my_xmldoc;
+  HRESULT hr = CoCreateSafeDOMDocument(&my_xmldoc);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[CoCreateSafeDOMDocument failed][0x%x]"), hr));
+    return hr;
+  }
+  hr = my_xmldoc->put_preserveWhiteSpace(VARIANT_BOOL(preserve_whitespace));
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[put_preserveWhiteSpace failed][0x%x]"), hr));
+    return hr;
+  }
+  CComBSTR my_xmlfile(xmlfile);
+  VARIANT_BOOL is_successful(VARIANT_FALSE);
+  hr = my_xmldoc->load(CComVariant(my_xmlfile), &is_successful);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[my_xmldoc->load failed][0x%x]"), hr));
+    return hr;
+  }
+  if (!is_successful) {
+    CComPtr<IXMLDOMParseError> error;
+    CString error_message;
+    hr = GetXMLParseError(my_xmldoc, &error);
+    if (FAILED(hr)) {
+      UTIL_LOG(LE, (_T("[GetXMLParseError failed][0x%x]"), hr));
+      return hr;
+    }
+    ASSERT1(error);
+    HRESULT error_code = 0;
+    hr = InterpretXMLParseError(error, &error_code, &error_message);
+    if (FAILED(hr)) {
+      UTIL_LOG(LE, (_T("[InterpretXMLParseError failed][0x%x]"), hr));
+      return hr;
+    }
+    UTIL_LOG(LE, (L"[LoadXMLFromFile '%s'][parse error: %s]",
+                  xmlfile, error_message));
+    ASSERT1(FAILED(error_code));
+    return FAILED(error_code) ? error_code : CI_E_XML_LOAD_ERROR;
+  }
+  *xmldoc = my_xmldoc.Detach();
+  return S_OK;
+}
+
+HRESULT LoadXMLFromMemory(const TCHAR* xmlstring,
+                          bool preserve_whitespace,
+                          IXMLDOMDocument** xmldoc) {
+  ASSERT1(xmlstring);
+  ASSERT1(xmldoc);
+  ASSERT1(!*xmldoc);
+
+  *xmldoc = NULL;
+  CComPtr<IXMLDOMDocument> my_xmldoc;
+  RET_IF_FAILED(CoCreateSafeDOMDocument(&my_xmldoc));
+  RET_IF_FAILED(my_xmldoc->put_preserveWhiteSpace(
+                               VARIANT_BOOL(preserve_whitespace)));
+  CComBSTR xmlmemory(xmlstring);
+  VARIANT_BOOL is_successful(VARIANT_FALSE);
+  RET_IF_FAILED(my_xmldoc->loadXML(xmlmemory, &is_successful));
+  if (!is_successful) {
+    CComPtr<IXMLDOMParseError> error;
+    CString error_message;
+    RET_IF_FAILED(GetXMLParseError(my_xmldoc, &error));
+    ASSERT1(error);
+    HRESULT error_code = 0;
+    RET_IF_FAILED(InterpretXMLParseError(error, &error_code, &error_message));
+    UTIL_LOG(LE, (L"[LoadXMLFromMemory][parse error: %s]", error_message));
+    ASSERT1(FAILED(error_code));
+    return FAILED(error_code) ? error_code : CI_E_XML_LOAD_ERROR;
+  }
+  *xmldoc = my_xmldoc.Detach();
+  return S_OK;
+}
+
+HRESULT LoadXMLFromRawData(const std::vector<byte>& xmldata,
+                           bool preserve_whitespace,
+                           IXMLDOMDocument** xmldoc) {
+  ASSERT1(xmldoc);
+  ASSERT1(!*xmldoc);
+
+  *xmldoc = NULL;
+  CComPtr<IXMLDOMDocument> my_xmldoc;
+  RET_IF_FAILED(CoCreateSafeDOMDocument(&my_xmldoc));
+  RET_IF_FAILED(my_xmldoc->put_preserveWhiteSpace(
+                              VARIANT_BOOL(preserve_whitespace)));
+
+  CComSafeArray<byte> xmlsa;
+  xmlsa.Add(xmldata.size(), &xmldata.front());
+  CComVariant xmlvar(xmlsa);
+
+  VARIANT_BOOL is_successful(VARIANT_FALSE);
+  RET_IF_FAILED(my_xmldoc->load(xmlvar, &is_successful));
+  if (!is_successful) {
+    CComPtr<IXMLDOMParseError> error;
+    CString error_message;
+    RET_IF_FAILED(GetXMLParseError(my_xmldoc, &error));
+    ASSERT1(error);
+    HRESULT error_code = 0;
+    RET_IF_FAILED(InterpretXMLParseError(error, &error_code, &error_message));
+    UTIL_LOG(LE, (_T("[LoadXMLFromRawData][parse error: %s]"), error_message));
+    ASSERT1(FAILED(error_code));
+    return FAILED(error_code) ? error_code : CI_E_XML_LOAD_ERROR;
+  }
+  *xmldoc = my_xmldoc.Detach();
+  return S_OK;
+}
+
+HRESULT SaveXMLToFile(IXMLDOMDocument* xmldoc, const TCHAR* xmlfile) {
+  ASSERT1(xmldoc);
+  ASSERT1(xmlfile);
+
+  CComBSTR my_xmlfile(xmlfile);
+  RET_IF_FAILED(xmldoc->save(CComVariant(my_xmlfile)));
+  return S_OK;
+}
+
+HRESULT SaveXMLToMemory(IXMLDOMDocument* xmldoc, CString* xmlstring) {
+  ASSERT1(xmldoc);
+  ASSERT1(xmlstring);
+
+  CComBSTR xmlmemory;
+  RET_IF_FAILED(xmldoc->get_xml(&xmlmemory));
+  *xmlstring = xmlmemory;
+
+  return S_OK;
+}
+
+HRESULT CanonicalizeXML(const TCHAR* xmlstring, CString* canonical_xmlstring) {
+  ASSERT1(xmlstring);
+  ASSERT1(canonical_xmlstring);
+
+  // Round-trip through MSXML, having it strip whitespace.
+
+  CComPtr<IXMLDOMDocument> xmldoc;
+  RET_IF_FAILED(CoCreateSafeDOMDocument(&xmldoc));
+  RET_IF_FAILED(xmldoc->put_preserveWhiteSpace(VARIANT_FALSE));
+  {
+    CComBSTR xmlmemory(StringAfterBOM(xmlstring));
+    VARIANT_BOOL is_successful(VARIANT_FALSE);
+    RET_IF_FAILED(xmldoc->loadXML(xmlmemory, &is_successful));
+    if (!is_successful) {
+      CComPtr<IXMLDOMParseError> error;
+      CString error_message;
+      RET_IF_FAILED(GetXMLParseError(xmldoc, &error));
+      ASSERT1(error);
+      HRESULT error_code = 0;
+      RET_IF_FAILED(InterpretXMLParseError(error, &error_code, &error_message));
+      UTIL_LOG(LE, (L"[CanonicalizeXML][parse error: %s]", error_message));
+      ASSERT1(FAILED(error_code));
+      return FAILED(error_code) ? error_code : CI_E_XML_LOAD_ERROR;
+    }
+  }
+  std::vector<CString> lines;
+  {
+    CComBSTR xmlmemory2;
+    RET_IF_FAILED(xmldoc->get_xml(&xmlmemory2));
+    TextToLines(CString(xmlmemory2), L"\r\n", &lines);
+  }
+  {
+    for (size_t i = 0; i < lines.size(); ++i) {
+      TrimString(lines[i], L" \t");
+    }
+    LinesToText(lines, L"", canonical_xmlstring);
+  }
+
+  return S_OK;
+}
+
+bool operator==(const XMLFQName& u, const XMLFQName& v) {
+  if (u.uri && v.uri) {
+    // Both uris are non-null -> compare all the components.
+    return !_tcscmp(u.uri, v.uri) && !_tcscmp(u.base, v.base);
+  } else if (!u.uri && !v.uri) {
+    // Both uris are null -> only compare the base names.
+    return !_tcscmp(u.base ? u.base : __T(""), v.base ? v.base : __T(""));
+  } else {
+    // Either uri is null -> the names are in different namespaces.
+    return false;
+  }
+}
+
+bool operator!=(const XMLFQName& u, const XMLFQName& v) {
+  return !(u == v);
+}
+
+bool operator<(const XMLFQName& u, const XMLFQName &v) {
+  if (u.uri && v.uri) {
+    return (_tcscmp(u.uri, v.uri) < 0) ||
+            ((_tcscmp(u.uri, v.uri) == 0) && (_tcscmp(u.base, v.base) < 0));
+  } else if (!u.uri && !v.uri) {
+    return _tcscmp(u.base, v.base) < 0;
+  } else {
+    return false;
+  }
+}
+
+bool operator>(const XMLFQName& u, const XMLFQName& v) {
+  return v < u;
+}
+
+bool operator<=(const XMLFQName& u, const XMLFQName& v) {
+  return !(v < u);
+}
+
+bool operator>=(const XMLFQName& u, const XMLFQName& v) {
+  return !(u < v);
+}
+
+bool EqualXMLName(const XMLFQName& u, const XMLFQName& v) {
+  return u == v;
+}
+
+// msxml returns a null uri for nodes that don't belong to a namespace.
+bool EqualXMLName(IXMLDOMNode* pnode, const XMLFQName& u) {
+  CComBSTR name;
+  CComBSTR uri;
+  if (FAILED(pnode->get_baseName(&name)) ||
+      FAILED(pnode->get_namespaceURI(&uri))) {
+    return false;
+  }
+  return EqualXMLName(XMLFQName(uri, name), u);
+}
+
+inline bool EqualXMLName(const XMLFQName& u, IXMLDOMNode* pnode) {
+  return EqualXMLName(pnode, u);
+}
+
+HRESULT GetXMLFQName(IXMLDOMNode* node, XMLFQName* name) {
+  ASSERT1(node);
+  ASSERT1(name);
+
+  CComBSTR basename, uri;
+  RET_IF_FAILED(node->get_baseName(&basename));
+  RET_IF_FAILED(node->get_namespaceURI(&uri));
+  *name = XMLFQName(uri, basename);
+  return S_OK;
+}
+
+CString XMLFQNameToString(const XMLFQName& fqname) {
+  CString name;
+  if (fqname.uri) {
+    name += fqname.uri;
+    name += L":";
+  }
+  if (fqname.base) {
+    name += fqname.base;
+  }
+  return name;
+}
+
+CString NodeToString(IXMLDOMNode* pnode) {
+  ASSERT1(pnode);
+
+  XMLFQName node_name;
+  if (SUCCEEDED(GetXMLFQName(pnode, &node_name))) {
+    return XMLFQNameToString(node_name);
+  }
+  return L"";
+}
+
+HRESULT CreateXMLNode(IXMLDOMDocument* xmldoc,
+                      int node_type,
+                      const TCHAR* node_name,
+                      const TCHAR* namespace_uri,
+                      const TCHAR* text,
+                      IXMLDOMNode** node_out) {
+  ASSERT1(xmldoc);
+  ASSERT1(node_name);
+  // namespace_uri can be NULL
+  // text can be NULL
+  ASSERT1(node_out);
+  ASSERT1(!*node_out);
+
+  *node_out = NULL;
+  CComPtr<IXMLDOMNode> new_node;
+  CComBSTR node_name_string, namespace_uri_string;
+  RET_IF_FAILED(node_name_string.Append(node_name));
+  RET_IF_FAILED(namespace_uri_string.Append(namespace_uri));
+  RET_IF_FAILED(xmldoc->createNode(CComVariant(node_type),
+                                   node_name_string,
+                                   namespace_uri_string,
+                                   &new_node));
+  ASSERT1(new_node);
+
+  // If any text was supplied, put it in the node
+  if (text && text[0]) {
+    RET_IF_FAILED(new_node->put_text(CComBSTR(text)));
+  }
+
+  *node_out = new_node.Detach();
+  return S_OK;
+}
+
+HRESULT AppendXMLNode(IXMLDOMNode* xmlnode, IXMLDOMNode* new_child) {
+  ASSERT1(xmlnode);
+  ASSERT1(new_child);
+
+  CComPtr<IXMLDOMNode> useless;
+  RET_IF_FAILED(xmlnode->appendChild(new_child, &useless));
+  return S_OK;
+}
+
+HRESULT AppendXMLNode(IXMLDOMNode* xmlnode, const TCHAR* text) {
+  ASSERT1(xmlnode);
+  // text can be NULL
+
+  if (text && text[0]) {
+    CComPtr<IXMLDOMDocument> xml_doc;
+    CComPtr<IXMLDOMText> text_node;
+    RET_IF_FAILED(xmlnode->get_ownerDocument(&xml_doc));
+    ASSERT1(xml_doc);
+    RET_IF_FAILED(xml_doc->createTextNode(CComBSTR(text), &text_node));
+    RET_IF_FAILED(AppendXMLNode(xmlnode, text_node));
+  }
+  return S_OK;
+}
+
+HRESULT AddXMLAttributeNode(IXMLDOMNode* xmlnode, IXMLDOMAttribute* new_child) {
+  ASSERT1(xmlnode);
+  ASSERT1(new_child);
+
+  CComPtr<IXMLDOMNamedNodeMap> attributes;
+  CComPtr<IXMLDOMNode> useless;
+  RET_IF_FAILED(xmlnode->get_attributes(&attributes));
+  RET_IF_FAILED(attributes->setNamedItem(new_child, &useless));
+  return S_OK;
+}
+
+HRESULT AddXMLAttributeNode(IXMLDOMElement* xmlelement,
+                            const TCHAR* attribute_name,
+                            const TCHAR* attribute_value) {
+  ASSERT1(xmlelement);
+  ASSERT1(attribute_name);
+  // attribute_value can be NULL
+
+  RET_IF_FAILED(xmlelement->setAttribute(CComBSTR(attribute_name),
+                                         CComVariant(attribute_value)));
+  return S_OK;
+}
+
+HRESULT AddXMLAttributeNode(IXMLDOMNode* xmlnode,
+                            const TCHAR* attribute_namespace,
+                            const TCHAR* attribute_name,
+                            const TCHAR* attribute_value) {
+  ASSERT1(xmlnode);
+  ASSERT1(attribute_name);
+  // attribute_namespace can be NULL
+  // attribute_value can be NULL
+
+  CComPtr<IXMLDOMDocument> xmldoc;
+  RET_IF_FAILED(xmlnode->get_ownerDocument(&xmldoc));
+  ASSERT1(xmldoc);
+
+  CComPtr<IXMLDOMNode> attribute_node;
+  RET_IF_FAILED(CreateXMLNode(xmldoc,
+                              NODE_ATTRIBUTE,
+                              attribute_name,
+                              attribute_namespace,
+                              attribute_value,
+                              &attribute_node));
+  CComQIPtr<IXMLDOMAttribute> attribute(attribute_node);
+  ASSERT1(attribute);
+  RET_IF_FAILED(AddXMLAttributeNode(xmlnode, attribute));
+  return S_OK;
+}
+
+HRESULT RemoveXMLChildrenByName(IXMLDOMNode* xmlnode, const XMLFQName& name) {
+  ASSERT1(xmlnode);
+
+  CComPtr<IXMLDOMNodeList> node_list;
+  RET_IF_FAILED(xmlnode->get_childNodes(&node_list));
+  ASSERT1(node_list);
+
+  bool found = false;
+  do {
+    found = false;
+    long count = 0;   // NOLINT
+    RET_IF_FAILED(node_list->get_length(&count));
+    RET_IF_FAILED(node_list->reset());
+
+    for (int i = 0; i < count; ++i) {
+      CComPtr<IXMLDOMNode> child_node, useless;
+      RET_IF_FAILED(node_list->get_item(i, &child_node));
+      ASSERT1(child_node);
+      if (EqualXMLName(child_node, name)) {
+        RET_IF_FAILED(xmlnode->removeChild(child_node, &useless));
+        // Start loop over: the list is "alive" and changes when you remove a
+        // node from it. Yes this seems to be n^2 but in fact we expect at
+        // most one each of <Hash> and/or <Size> nodes.
+        found = true;
+        break;
+      }
+    }
+  } while (found);
+
+  return S_OK;
+}
+
+HRESULT GetXMLChildByName(IXMLDOMElement* xmlnode,
+                          const TCHAR* child_name,
+                          IXMLDOMNode** xmlchild) {
+  ASSERT1(xmlnode);
+  ASSERT1(child_name);
+  ASSERT1(xmlchild);
+  ASSERT1(!*xmlchild);
+
+  *xmlchild = NULL;
+  CComPtr<IXMLDOMNodeList> node_list;
+  long node_list_length = 0;    // NOLINT
+  RET_IF_FAILED(xmlnode->getElementsByTagName(CComBSTR(child_name),
+                                              &node_list));
+  ASSERT1(node_list);
+  RET_IF_FAILED(node_list->get_length(&node_list_length));
+  if (node_list_length <= 0) {
+    return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
+  }
+  // Should only be one child node with name we're looking for.
+  if (node_list_length > 1) {
+    return CI_E_INVALID_MANIFEST;
+  }
+  RET_IF_FAILED(node_list->reset());
+  RET_IF_FAILED(node_list->get_item(0, xmlchild));
+  ASSERT1(*xmlchild);
+  return S_OK;
+}
+
+HRESULT InsertXMLBeforeItem(IXMLDOMNode* xmlnode,
+                            IXMLDOMNode* new_child,
+                            size_t item_number) {
+  ASSERT1(xmlnode);
+  ASSERT1(new_child);
+
+  CComPtr<IXMLDOMNodeList> child_list;
+  CComPtr<IXMLDOMNode> refchild, useless;
+
+  RET_IF_FAILED(xmlnode->get_childNodes(&child_list));
+  ASSERT1(child_list);
+  RET_IF_FAILED(child_list->get_item(item_number, &refchild));
+  ASSERT1(refchild);
+  RET_IF_FAILED(xmlnode->insertBefore(new_child,
+                                      CComVariant(refchild),
+                                      &useless));
+  return S_OK;
+}
+
+HRESULT GetXMLParseError(IXMLDOMDocument* xmldoc,
+                         IXMLDOMParseError** parse_error) {
+  ASSERT1(xmldoc);
+  ASSERT1(parse_error);
+  ASSERT1(!*parse_error);
+
+  *parse_error = NULL;
+  CComPtr<IXMLDOMParseError> error;
+  RET_IF_FAILED(xmldoc->get_parseError(&error));
+  HRESULT error_code = 0;
+  HRESULT hr = error->get_errorCode(&error_code);
+  if (hr == S_OK) {
+    *parse_error = error.Detach();
+    return S_OK;
+  } else if (hr == S_FALSE) {
+    // No parse error
+    return S_FALSE;
+  } else {
+    return hr;
+  }
+}
+
+HRESULT InterpretXMLParseError(IXMLDOMParseError* parse_error,
+                               HRESULT* error_code,
+                               CString* message) {
+  ASSERT1(parse_error);
+  ASSERT1(error_code);
+  ASSERT1(message);
+
+  long line = 0;      // NOLINT
+  long char_pos = 0;  // NOLINT
+  CComBSTR src_text, reason;
+  RET_IF_FAILED(parse_error->get_errorCode(error_code));
+  RET_IF_FAILED(parse_error->get_line(&line));
+  RET_IF_FAILED(parse_error->get_linepos(&char_pos));
+  RET_IF_FAILED(parse_error->get_srcText(&src_text));
+  RET_IF_FAILED(parse_error->get_reason(&reason));
+
+  // Wild guess.
+  size_t size_estimate = src_text.Length() + reason.Length() + 100;
+
+  // TODO(omaha): think about replacing this call to _snwprintf with a
+  // safestring function.
+  std::vector<TCHAR> s(size_estimate);
+  _snwprintf_s(&s.front(), size_estimate, _TRUNCATE,
+               L"%d(%d) : error 0x%08lx: %s\n  %s",
+               line, char_pos, *error_code,
+               reason ? reason : L"",
+               src_text ? src_text : L"<no source text>");
+  // _snwprintf doesn't terminate the string with a null if
+  // the formatted string fills the entire buffer.
+  s[s.size()- 1] = L'\0';
+  *message = &s.front();
+  return S_OK;
+}
+
+HRESULT GetNumChildren(IXMLDOMNode* node, int* num_children) {
+  ASSERT1(node);
+  ASSERT1(num_children);
+
+  *num_children = 0;
+  CComPtr<IXMLDOMNodeList> children;
+  RET_IF_FAILED(node->get_childNodes(&children));
+  ASSERT1(children);
+
+  long len = 0;   // NOLINT
+  RET_IF_FAILED(children->get_length(&len));
+  *num_children = len;
+  return S_OK;
+}
+
+int GetNumAttributes(IXMLDOMNode* node) {
+  ASSERT1(node);
+
+  CComPtr<IXMLDOMNamedNodeMap> attr_map;
+  if (FAILED(node->get_attributes(&attr_map))) {
+    return 0;
+  }
+  ASSERT1(attr_map);
+  long len = 0;   // NOLINT
+  if (FAILED(attr_map->get_length(&len))) {
+    return 0;
+  }
+  return len;
+}
+
+}  // namespace omaha
+
diff --git a/common/xml_utils.h b/common/xml_utils.h
index dd9c708..8ccb397 100644
--- a/common/xml_utils.h
+++ b/common/xml_utils.h
@@ -1,221 +1,221 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// xml_utils.h

-//

-// Utilities for working with XML files via MSXML.

-

-#ifndef OMAHA_COMMON_XML_UTILS_H__

-#define OMAHA_COMMON_XML_UTILS_H__

-

-#include <windows.h>

-#include <objbase.h>

-#include <msxml.h>

-#include <atlstr.h>

-#include <utility>

-#include <vector>

-

-namespace omaha {

-

-// Creates a DOMDocument that disallows external definitions to be included and

-// resolved as part of the XML document stream at parse time.

-HRESULT CoCreateSafeDOMDocument(IXMLDOMDocument** my_xmldoc);

-

-// xmlfile can be any specified encoding.

-HRESULT LoadXMLFromFile(const TCHAR* xmlfile,

-                        bool preserve_whitespace,

-                        IXMLDOMDocument** xmldoc);

-

-// xmlstring must be UTF-16 or UCS-2.

-HRESULT LoadXMLFromMemory(const TCHAR* xmlstring,

-                          bool preserve_whitespace,

-                          IXMLDOMDocument** xmldoc);

-

-// xmldata can be any raw data supported by xml parser

-HRESULT LoadXMLFromRawData(const std::vector<byte>& xmldata,

-                           bool preserve_whitespace,

-                           IXMLDOMDocument** xmldoc);

-

-// xmlfile is in encoding specified in the XML document.

-HRESULT SaveXMLToFile(IXMLDOMDocument* xmldoc, const TCHAR * xmlfile);

-

-// xmlstring is in UCS-2

-HRESULT SaveXMLToMemory(IXMLDOMDocument* xmldoc, CString* xmlstring);

-

-// Canonicalizes the XML string so you can compute a signature on it.

-// This is not the official canonicalization but a cheaper scheme which

-// depends on the whitespace stripping capability of MSXML.

-//

-// xmlstring is in UTF-16 or UCS-2

-HRESULT CanonicalizeXML(const TCHAR* xmlstring, CString* canonical_xmlstring);

-

-

-// Dealing with element/attribute names: the combination of a base name

-// and a namespace URI is a fully-qualified XML name, or: XMLFQName.

-

-// We can't just typedef a std::pair because we need proper comparison operators

-// in case we want to stick a XMLFQName into a standard collection.

-struct XMLFQName {

-  XMLFQName();

-  XMLFQName(const TCHAR* u, const TCHAR* b);

-  ~XMLFQName();

-

-  CString uri;

-  CString base;

-};

-

-bool operator==(const XMLFQName& u, const XMLFQName& v);

-bool operator!=(const XMLFQName& u, const XMLFQName& v);

-bool operator< (const XMLFQName& u, const XMLFQName& v);

-bool operator> (const XMLFQName& u, const XMLFQName& v);

-bool operator<=(const XMLFQName& u, const XMLFQName& v);

-bool operator>=(const XMLFQName& u, const XMLFQName& v);

-

-bool EqualXMLName(const XMLFQName& u, const XMLFQName& v);

-bool EqualXMLName(IXMLDOMNode* pnode, const XMLFQName& u);

-bool EqualXMLName(const XMLFQName& u, IXMLDOMNode* pnode);

-

-// Returns the FQ name from the node.

-HRESULT GetXMLFQName(IXMLDOMNode* node, XMLFQName* name);

-

-// Returns a string version of an XMLFQName suitable for debugging use.

-CString XMLFQNameToString(const XMLFQName& fqname);

-

-// Returns a string version of a node's name suitable for debugging use.

-CString NodeToString(IXMLDOMNode* pnode);

-

-//

-// Routines for dealing with fragments of DOM trees.

-//

-// Creates an XMLDOMNode of the given type with a given name and optional text.

-HRESULT CreateXMLNode(IXMLDOMDocument* xmldoc,

-                      int node_type,

-                      const TCHAR* node_name,

-                      const TCHAR* namespace_uri,

-                      const TCHAR* text,

-                      IXMLDOMNode** node_out);

-

-// Adds newchild as a child node of xmlnode after all existing children.

-HRESULT AppendXMLNode(IXMLDOMNode* xmlnode, IXMLDOMNode* new_child);

-

-// Adds text as a child node of xmlnode after all existing children.

-HRESULT AppendXMLNode(IXMLDOMNode* xmlnode, const TCHAR* text);

-

-// Adds newchild as an attribute node of xmlnode replacing existing

-// attribute with same name.

-HRESULT AddXMLAttributeNode(IXMLDOMNode* xmlnode, IXMLDOMAttribute* new_child);

-

-// Adds name/value pair as an attribute node of xmlnode replacing

-// existing attribute with same name.

-HRESULT AddXMLAttributeNode(IXMLDOMElement* xmlelement,

-                            const TCHAR* attribute_name,

-                            const TCHAR* attribute_value);

-

-// Adds name/value pair as an attribute node of xmlnode replacing

-// existing attribute with same name.

-// Can add attributes to nodes other than IXMLDOMElement.

-// Can add attributes with non-null namespaces.

-HRESULT AddXMLAttributeNode(IXMLDOMNode* xmlnode,

-                            const TCHAR* attribute_namespace,

-                            const TCHAR* attribute_name,

-                            const TCHAR* attribute_value);

-

-// Removes all children of the given node that have the specified name.

-HRESULT RemoveXMLChildrenByName(IXMLDOMNode* xmlnode, const XMLFQName& name);

-

-// Gets a child of a given node by name

-HRESULT GetXMLChildByName(IXMLDOMElement* xmlnode,

-                          const TCHAR* child_name,

-                          IXMLDOMNode** xmlchild);

-

-// Adds newchild as a child node of xmlnode, before the exiting

-// child item_number.

-HRESULT InsertXMLBeforeItem(IXMLDOMNode* xmlnode,

-                            IXMLDOMNode* new_child,

-                            size_t item_number);

-

-// Gets parse error information after a failed load.

-HRESULT GetXMLParseError(IXMLDOMDocument* xmldoc,

-                         IXMLDOMParseError** parse_error);

-

-// Interprets parse error.

-HRESULT InterpretXMLParseError(IXMLDOMParseError* parse_error,

-                               HRESULT* error_code,

-                               CString* message);

-

-// Gets the number of children of this node.

-HRESULT GetNumChildren(IXMLDOMNode* pnode, int* num_children);

-

-// Gets the number of attributes of this node.

-int GetNumAttributes(IXMLDOMNode* pnode);

-

-// Maps over a list of XML DOM nodes of some kind, executing a function

-// against each attribute in the list. Passes a cookie along to each

-// function call useful for accumulating results.

-// Template class List is usually a IXMLDOMNodeList or a IXMLDOMNamedNodeMap.

-template <class List, class Cookie>

-HRESULT ForEachNodeInList(List list,

-                          HRESULT (*fun)(CComPtr<IXMLDOMNode>, Cookie),

-                          Cookie cookie) {

-  ASSERT1(list);  // List assumed to be a pointer type or smart pointer type

-  ASSERT1(fun);

-

-  long len = 0;   // NOLINT

-  RET_IF_FAILED(list->get_length(&len));

-  for (long i = 0; i != len; ++i) {   // NOLINT

-    CComPtr<IXMLDOMNode> pnode;

-    RET_IF_FAILED(list->get_item(i, &pnode));

-    ASSERT1(pnode);

-    RET_IF_FAILED(fun(pnode, cookie));

-  }

-  return S_OK;

-}

-

-// Maps over the attributes of a node, executing a function against each

-// attribute. Passes a cookie along to each function call.

-template <typename Cookie>

-HRESULT ForEachAttribute(CComPtr<IXMLDOMNode> pnode,

-                         HRESULT (*fun)(CComPtr<IXMLDOMNode>, Cookie),

-                         Cookie cookie) {

-  ASSERT1(pnode);

-  ASSERT1(fun);

-

-  CComPtr<IXMLDOMNamedNodeMap> attr_list;

-  RET_IF_FAILED(pnode->get_attributes(&attr_list));

-  ASSERT1(attr_list);

-  RET_IF_FAILED(ForEachNodeInList(attr_list, fun, cookie));

-  return S_OK;

-}

-

-// Maps over the children nodes of a node, executing a function against

-// each child node. Passes a cookie along to each function call.

-template <typename Cookie>

-HRESULT ForEachChildNode(CComPtr<IXMLDOMNode> pnode,

-                         HRESULT (*fun)(CComPtr<IXMLDOMNode>, Cookie),

-                         Cookie cookie) {

-  ASSERT1(pnode);

-  ASSERT1(fun);

-

-  CComPtr<IXMLDOMNodeList> child_list;

-  RET_IF_FAILED(pnode->get_childNodes(&child_list));

-  ASSERT1(child_list);

-  RET_IF_FAILED(ForEachNodeInList(child_list, fun, cookie));

-  return S_OK;

-}

-

-}  // namespace omaha

-

-#endif  // OMAHA_COMMON_XML_UTILS_H__

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// xml_utils.h
+//
+// Utilities for working with XML files via MSXML.
+
+#ifndef OMAHA_COMMON_XML_UTILS_H__
+#define OMAHA_COMMON_XML_UTILS_H__
+
+#include <windows.h>
+#include <objbase.h>
+#include <msxml.h>
+#include <atlstr.h>
+#include <utility>
+#include <vector>
+
+namespace omaha {
+
+// Creates a DOMDocument that disallows external definitions to be included and
+// resolved as part of the XML document stream at parse time.
+HRESULT CoCreateSafeDOMDocument(IXMLDOMDocument** my_xmldoc);
+
+// xmlfile can be any specified encoding.
+HRESULT LoadXMLFromFile(const TCHAR* xmlfile,
+                        bool preserve_whitespace,
+                        IXMLDOMDocument** xmldoc);
+
+// xmlstring must be UTF-16 or UCS-2.
+HRESULT LoadXMLFromMemory(const TCHAR* xmlstring,
+                          bool preserve_whitespace,
+                          IXMLDOMDocument** xmldoc);
+
+// xmldata can be any raw data supported by xml parser
+HRESULT LoadXMLFromRawData(const std::vector<byte>& xmldata,
+                           bool preserve_whitespace,
+                           IXMLDOMDocument** xmldoc);
+
+// xmlfile is in encoding specified in the XML document.
+HRESULT SaveXMLToFile(IXMLDOMDocument* xmldoc, const TCHAR * xmlfile);
+
+// xmlstring is in UCS-2
+HRESULT SaveXMLToMemory(IXMLDOMDocument* xmldoc, CString* xmlstring);
+
+// Canonicalizes the XML string so you can compute a signature on it.
+// This is not the official canonicalization but a cheaper scheme which
+// depends on the whitespace stripping capability of MSXML.
+//
+// xmlstring is in UTF-16 or UCS-2
+HRESULT CanonicalizeXML(const TCHAR* xmlstring, CString* canonical_xmlstring);
+
+
+// Dealing with element/attribute names: the combination of a base name
+// and a namespace URI is a fully-qualified XML name, or: XMLFQName.
+
+// We can't just typedef a std::pair because we need proper comparison operators
+// in case we want to stick a XMLFQName into a standard collection.
+struct XMLFQName {
+  XMLFQName();
+  XMLFQName(const TCHAR* u, const TCHAR* b);
+  ~XMLFQName();
+
+  CString uri;
+  CString base;
+};
+
+bool operator==(const XMLFQName& u, const XMLFQName& v);
+bool operator!=(const XMLFQName& u, const XMLFQName& v);
+bool operator< (const XMLFQName& u, const XMLFQName& v);
+bool operator> (const XMLFQName& u, const XMLFQName& v);
+bool operator<=(const XMLFQName& u, const XMLFQName& v);
+bool operator>=(const XMLFQName& u, const XMLFQName& v);
+
+bool EqualXMLName(const XMLFQName& u, const XMLFQName& v);
+bool EqualXMLName(IXMLDOMNode* pnode, const XMLFQName& u);
+bool EqualXMLName(const XMLFQName& u, IXMLDOMNode* pnode);
+
+// Returns the FQ name from the node.
+HRESULT GetXMLFQName(IXMLDOMNode* node, XMLFQName* name);
+
+// Returns a string version of an XMLFQName suitable for debugging use.
+CString XMLFQNameToString(const XMLFQName& fqname);
+
+// Returns a string version of a node's name suitable for debugging use.
+CString NodeToString(IXMLDOMNode* pnode);
+
+//
+// Routines for dealing with fragments of DOM trees.
+//
+// Creates an XMLDOMNode of the given type with a given name and optional text.
+HRESULT CreateXMLNode(IXMLDOMDocument* xmldoc,
+                      int node_type,
+                      const TCHAR* node_name,
+                      const TCHAR* namespace_uri,
+                      const TCHAR* text,
+                      IXMLDOMNode** node_out);
+
+// Adds newchild as a child node of xmlnode after all existing children.
+HRESULT AppendXMLNode(IXMLDOMNode* xmlnode, IXMLDOMNode* new_child);
+
+// Adds text as a child node of xmlnode after all existing children.
+HRESULT AppendXMLNode(IXMLDOMNode* xmlnode, const TCHAR* text);
+
+// Adds newchild as an attribute node of xmlnode replacing existing
+// attribute with same name.
+HRESULT AddXMLAttributeNode(IXMLDOMNode* xmlnode, IXMLDOMAttribute* new_child);
+
+// Adds name/value pair as an attribute node of xmlnode replacing
+// existing attribute with same name.
+HRESULT AddXMLAttributeNode(IXMLDOMElement* xmlelement,
+                            const TCHAR* attribute_name,
+                            const TCHAR* attribute_value);
+
+// Adds name/value pair as an attribute node of xmlnode replacing
+// existing attribute with same name.
+// Can add attributes to nodes other than IXMLDOMElement.
+// Can add attributes with non-null namespaces.
+HRESULT AddXMLAttributeNode(IXMLDOMNode* xmlnode,
+                            const TCHAR* attribute_namespace,
+                            const TCHAR* attribute_name,
+                            const TCHAR* attribute_value);
+
+// Removes all children of the given node that have the specified name.
+HRESULT RemoveXMLChildrenByName(IXMLDOMNode* xmlnode, const XMLFQName& name);
+
+// Gets a child of a given node by name
+HRESULT GetXMLChildByName(IXMLDOMElement* xmlnode,
+                          const TCHAR* child_name,
+                          IXMLDOMNode** xmlchild);
+
+// Adds newchild as a child node of xmlnode, before the exiting
+// child item_number.
+HRESULT InsertXMLBeforeItem(IXMLDOMNode* xmlnode,
+                            IXMLDOMNode* new_child,
+                            size_t item_number);
+
+// Gets parse error information after a failed load.
+HRESULT GetXMLParseError(IXMLDOMDocument* xmldoc,
+                         IXMLDOMParseError** parse_error);
+
+// Interprets parse error.
+HRESULT InterpretXMLParseError(IXMLDOMParseError* parse_error,
+                               HRESULT* error_code,
+                               CString* message);
+
+// Gets the number of children of this node.
+HRESULT GetNumChildren(IXMLDOMNode* pnode, int* num_children);
+
+// Gets the number of attributes of this node.
+int GetNumAttributes(IXMLDOMNode* pnode);
+
+// Maps over a list of XML DOM nodes of some kind, executing a function
+// against each attribute in the list. Passes a cookie along to each
+// function call useful for accumulating results.
+// Template class List is usually a IXMLDOMNodeList or a IXMLDOMNamedNodeMap.
+template <class List, class Cookie>
+HRESULT ForEachNodeInList(List list,
+                          HRESULT (*fun)(CComPtr<IXMLDOMNode>, Cookie),
+                          Cookie cookie) {
+  ASSERT1(list);  // List assumed to be a pointer type or smart pointer type
+  ASSERT1(fun);
+
+  long len = 0;   // NOLINT
+  RET_IF_FAILED(list->get_length(&len));
+  for (long i = 0; i != len; ++i) {   // NOLINT
+    CComPtr<IXMLDOMNode> pnode;
+    RET_IF_FAILED(list->get_item(i, &pnode));
+    ASSERT1(pnode);
+    RET_IF_FAILED(fun(pnode, cookie));
+  }
+  return S_OK;
+}
+
+// Maps over the attributes of a node, executing a function against each
+// attribute. Passes a cookie along to each function call.
+template <typename Cookie>
+HRESULT ForEachAttribute(CComPtr<IXMLDOMNode> pnode,
+                         HRESULT (*fun)(CComPtr<IXMLDOMNode>, Cookie),
+                         Cookie cookie) {
+  ASSERT1(pnode);
+  ASSERT1(fun);
+
+  CComPtr<IXMLDOMNamedNodeMap> attr_list;
+  RET_IF_FAILED(pnode->get_attributes(&attr_list));
+  ASSERT1(attr_list);
+  RET_IF_FAILED(ForEachNodeInList(attr_list, fun, cookie));
+  return S_OK;
+}
+
+// Maps over the children nodes of a node, executing a function against
+// each child node. Passes a cookie along to each function call.
+template <typename Cookie>
+HRESULT ForEachChildNode(CComPtr<IXMLDOMNode> pnode,
+                         HRESULT (*fun)(CComPtr<IXMLDOMNode>, Cookie),
+                         Cookie cookie) {
+  ASSERT1(pnode);
+  ASSERT1(fun);
+
+  CComPtr<IXMLDOMNodeList> child_list;
+  RET_IF_FAILED(pnode->get_childNodes(&child_list));
+  ASSERT1(child_list);
+  RET_IF_FAILED(ForEachNodeInList(child_list, fun, cookie));
+  return S_OK;
+}
+
+}  // namespace omaha
+
+#endif  // OMAHA_COMMON_XML_UTILS_H__
+
diff --git a/common/xml_utils_unittest.cc b/common/xml_utils_unittest.cc
index ff2d217..2d66c78 100644
--- a/common/xml_utils_unittest.cc
+++ b/common/xml_utils_unittest.cc
@@ -1,120 +1,120 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "omaha/common/file.h"

-#include "omaha/common/module_utils.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/xml_utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-const TCHAR kTestXMLFile[] = _T("manifest.xml");

-const TCHAR kTempXMLFile[] = _T("foobar.xml");

-

-const XMLFQName fqLowNoURI(NULL, _T("Bar"));

-const XMLFQName fqLowNoURI2(NULL, _T("Bar"));

-const XMLFQName fqHighNoURI(NULL, _T("Foo"));

-const XMLFQName fqLowURI(_T("Zebra"), _T("Bar"));

-const XMLFQName fqLowURI2(_T("Zebra"), _T("Bar"));

-const XMLFQName fqHighURI(_T("Zebra"), _T("Foo"));

-const XMLFQName fqDifferentURI(_T("Xray"), _T("Bar"));

-

-TEST(XmlUtilsTest, XMLFQName) {

-  ASSERT_TRUE(fqLowNoURI == fqLowNoURI2);

-  ASSERT_TRUE(fqHighNoURI == fqHighNoURI);

-  ASSERT_TRUE(fqLowNoURI != fqHighNoURI);

-  ASSERT_TRUE(fqLowNoURI != fqLowURI);

-  ASSERT_TRUE(fqLowNoURI < fqHighNoURI);

-  ASSERT_TRUE(fqLowNoURI <= fqHighNoURI);

-  ASSERT_TRUE(fqHighNoURI > fqLowNoURI);

-  ASSERT_TRUE(fqHighNoURI >= fqLowNoURI);

-  ASSERT_TRUE(fqLowURI == fqLowURI2);

-  ASSERT_TRUE(fqHighURI == fqHighURI);

-  ASSERT_TRUE(fqLowURI != fqHighURI);

-  ASSERT_TRUE(fqLowURI < fqHighURI);

-  ASSERT_TRUE(fqLowURI <= fqHighURI);

-  ASSERT_TRUE(fqHighURI > fqLowURI);

-  ASSERT_TRUE(fqHighURI >= fqLowURI);

-  ASSERT_TRUE(fqLowURI != fqDifferentURI);

-}

-

-TEST(XmlUtilsTest, LoadSave) {

-  scoped_co_init co_init;

-

-  // Get some directory and file names to start with.

-  TCHAR directory[MAX_PATH] = {0};

-  ASSERT_TRUE(GetModuleDirectory(NULL, directory));

-  CString test_file;

-  test_file.AppendFormat(_T("%s\\%s"), directory, kTestXMLFile);

-

-  TCHAR temp_path[MAX_PATH] = {0};

-  ASSERT_TRUE(::GetTempPath(MAX_PATH, temp_path));

-  CString temp_file;

-  temp_file.AppendFormat(_T("%s%s"), temp_path, kTempXMLFile);

-

-  // Test loading and storing to a file.

-  CComPtr<IXMLDOMDocument> xmldoc;

-  ASSERT_SUCCEEDED(LoadXMLFromFile(test_file, true, &xmldoc));

-  ASSERT_TRUE(xmldoc);

-  ASSERT_SUCCEEDED(SaveXMLToFile(xmldoc, temp_file));

-

-  // Test loading and storing to memory.

-  // The input must be Unicode but our test file is UTF-8 - so read

-  // it and convert it to Unicode.

-  std::vector<byte> buffer_utf8;

-  ASSERT_SUCCEEDED(ReadEntireFile(temp_file, 0, &buffer_utf8));

-  int len(::MultiByteToWideChar(CP_UTF8,

-                                0, /*flags*/

-                                reinterpret_cast<const char*>(&buffer_utf8[0]),

-                                buffer_utf8.size(),

-                                NULL,

-                                0));

-  std::vector<wchar_t> buffer_unicode(len+1);

-  int len2(::MultiByteToWideChar(CP_UTF8,

-                                 0, /*flags*/

-                                 reinterpret_cast<const char*>(&buffer_utf8[0]),

-                                 buffer_utf8.size(),

-                                 &buffer_unicode[0],

-                                 len));

-  ASSERT_EQ(len, len2);

-  buffer_unicode[len] = 0;  // null terminate the unicode string.

-

-  // Now round-trip the load from memory and save to memory.

-  CComPtr<IXMLDOMDocument> xmldoc2;

-  ASSERT_SUCCEEDED(LoadXMLFromMemory(&buffer_unicode.front(), true, &xmldoc2));

-  ASSERT_TRUE(xmldoc2);

-  CString xmlmemory;

-  ASSERT_SUCCEEDED(SaveXMLToMemory(xmldoc2, &xmlmemory));

-

-  // Now compare that the result of the round-trip is the same as the input.

-  CString input(&buffer_unicode.front());

-  CString output(xmlmemory);

-  // Except must first remove the " encoding="UTF-8"" attribute from the

-  // input string.

-  ReplaceCString(input, L" encoding=\"UTF-8\"", L"");

-  ASSERT_STREQ(input, output);

-

-  // Clean up.

-  ASSERT_SUCCEEDED(File::Remove(temp_file));

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "omaha/common/file.h"
+#include "omaha/common/module_utils.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/xml_utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+const TCHAR kTestXMLFile[] = _T("manifest.xml");
+const TCHAR kTempXMLFile[] = _T("foobar.xml");
+
+const XMLFQName fqLowNoURI(NULL, _T("Bar"));
+const XMLFQName fqLowNoURI2(NULL, _T("Bar"));
+const XMLFQName fqHighNoURI(NULL, _T("Foo"));
+const XMLFQName fqLowURI(_T("Zebra"), _T("Bar"));
+const XMLFQName fqLowURI2(_T("Zebra"), _T("Bar"));
+const XMLFQName fqHighURI(_T("Zebra"), _T("Foo"));
+const XMLFQName fqDifferentURI(_T("Xray"), _T("Bar"));
+
+TEST(XmlUtilsTest, XMLFQName) {
+  ASSERT_TRUE(fqLowNoURI == fqLowNoURI2);
+  ASSERT_TRUE(fqHighNoURI == fqHighNoURI);
+  ASSERT_TRUE(fqLowNoURI != fqHighNoURI);
+  ASSERT_TRUE(fqLowNoURI != fqLowURI);
+  ASSERT_TRUE(fqLowNoURI < fqHighNoURI);
+  ASSERT_TRUE(fqLowNoURI <= fqHighNoURI);
+  ASSERT_TRUE(fqHighNoURI > fqLowNoURI);
+  ASSERT_TRUE(fqHighNoURI >= fqLowNoURI);
+  ASSERT_TRUE(fqLowURI == fqLowURI2);
+  ASSERT_TRUE(fqHighURI == fqHighURI);
+  ASSERT_TRUE(fqLowURI != fqHighURI);
+  ASSERT_TRUE(fqLowURI < fqHighURI);
+  ASSERT_TRUE(fqLowURI <= fqHighURI);
+  ASSERT_TRUE(fqHighURI > fqLowURI);
+  ASSERT_TRUE(fqHighURI >= fqLowURI);
+  ASSERT_TRUE(fqLowURI != fqDifferentURI);
+}
+
+TEST(XmlUtilsTest, LoadSave) {
+  scoped_co_init co_init;
+
+  // Get some directory and file names to start with.
+  TCHAR directory[MAX_PATH] = {0};
+  ASSERT_TRUE(GetModuleDirectory(NULL, directory));
+  CString test_file;
+  test_file.AppendFormat(_T("%s\\%s"), directory, kTestXMLFile);
+
+  TCHAR temp_path[MAX_PATH] = {0};
+  ASSERT_TRUE(::GetTempPath(MAX_PATH, temp_path));
+  CString temp_file;
+  temp_file.AppendFormat(_T("%s%s"), temp_path, kTempXMLFile);
+
+  // Test loading and storing to a file.
+  CComPtr<IXMLDOMDocument> xmldoc;
+  ASSERT_SUCCEEDED(LoadXMLFromFile(test_file, true, &xmldoc));
+  ASSERT_TRUE(xmldoc);
+  ASSERT_SUCCEEDED(SaveXMLToFile(xmldoc, temp_file));
+
+  // Test loading and storing to memory.
+  // The input must be Unicode but our test file is UTF-8 - so read
+  // it and convert it to Unicode.
+  std::vector<byte> buffer_utf8;
+  ASSERT_SUCCEEDED(ReadEntireFile(temp_file, 0, &buffer_utf8));
+  int len(::MultiByteToWideChar(CP_UTF8,
+                                0, /*flags*/
+                                reinterpret_cast<const char*>(&buffer_utf8[0]),
+                                buffer_utf8.size(),
+                                NULL,
+                                0));
+  std::vector<wchar_t> buffer_unicode(len+1);
+  int len2(::MultiByteToWideChar(CP_UTF8,
+                                 0, /*flags*/
+                                 reinterpret_cast<const char*>(&buffer_utf8[0]),
+                                 buffer_utf8.size(),
+                                 &buffer_unicode[0],
+                                 len));
+  ASSERT_EQ(len, len2);
+  buffer_unicode[len] = 0;  // null terminate the unicode string.
+
+  // Now round-trip the load from memory and save to memory.
+  CComPtr<IXMLDOMDocument> xmldoc2;
+  ASSERT_SUCCEEDED(LoadXMLFromMemory(&buffer_unicode.front(), true, &xmldoc2));
+  ASSERT_TRUE(xmldoc2);
+  CString xmlmemory;
+  ASSERT_SUCCEEDED(SaveXMLToMemory(xmldoc2, &xmlmemory));
+
+  // Now compare that the result of the round-trip is the same as the input.
+  CString input(&buffer_unicode.front());
+  CString output(xmlmemory);
+  // Except must first remove the " encoding="UTF-8"" attribute from the
+  // input string.
+  ReplaceCString(input, L" encoding=\"UTF-8\"", L"");
+  ASSERT_STREQ(input, output);
+
+  // Clean up.
+  ASSERT_SUCCEEDED(File::Remove(temp_file));
+}
+
+}  // namespace omaha
+
diff --git a/core/build.scons b/core/build.scons
index cb8c87f..d22364f 100644
--- a/core/build.scons
+++ b/core/build.scons
@@ -1,41 +1,41 @@
-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-inputs = [

-    'core.cc',

-    'core_metrics.cc',

-    'crash_handler.cc',

-    'google_update_core.cc',

-    'legacy_manifest_handler.cc',

-    'scheduler.cc',

-    'system_monitor.cc',

-    ]

-

-# Create a local clone, so the parent environment is

-# unaffected by changes made here.

-local_env = env.Clone()

-

-local_env['CPPPATH'] += [

-    '$MAIN_DIR/third_party/breakpad/src/',

-

-    # Need to look in output dir to find .h files generated by midl compiler.

-    # This also allows Hammer to understand dependencies between this subdir

-    # and the .idl files in the goopdate folder.

-    '$OBJ_ROOT',

-    ]

-

-local_env.ComponentLibrary('core', inputs)

+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+inputs = [
+    'core.cc',
+    'core_metrics.cc',
+    'crash_handler.cc',
+    'google_update_core.cc',
+    'legacy_manifest_handler.cc',
+    'scheduler.cc',
+    'system_monitor.cc',
+    ]
+
+# Create a local clone, so the parent environment is
+# unaffected by changes made here.
+local_env = env.Clone()
+
+local_env['CPPPATH'] += [
+    '$MAIN_DIR/third_party/breakpad/src/',
+
+    # Need to look in output dir to find .h files generated by midl compiler.
+    # This also allows Hammer to understand dependencies between this subdir
+    # and the .idl files in the goopdate folder.
+    '$OBJ_ROOT',
+    ]
+
+local_env.ComponentLibrary('core', inputs)
diff --git a/core/core.cc b/core/core.cc
index ad360fd..e865517 100644
--- a/core/core.cc
+++ b/core/core.cc
@@ -1,548 +1,548 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// Core is the long-lived Omaha process. It runs one instance for the

-// machine and one instance for each user session, including console and TS

-// sessions.

-// If the same user is logged in multiple times, only one core process will

-// be running.

-

-#include "omaha/core/core.h"

-#include <lmsname.h>

-#include <atlsecurity.h>

-#include <algorithm>

-#include <map>

-#include <string>

-#include <vector>

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/module_utils.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reactor.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/service_utils.h"

-#include "omaha/common/shutdown_handler.h"

-#include "omaha/common/system.h"

-#include "omaha/common/time.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/core/core_metrics.h"

-#include "omaha/core/legacy_manifest_handler.h"

-#include "omaha/core/scheduler.h"

-#include "omaha/core/system_monitor.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/crash.h"

-#include "omaha/goopdate/program_instance.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/stats_uploader.h"

-

-namespace omaha {

-

-Core::Core()

-    : is_system_(false),

-      is_crash_handler_enabled_(false),

-      main_thread_id_(0) {

-  CORE_LOG(L1, (_T("[Core::Core]")));

-}

-

-Core::~Core() {

-  CORE_LOG(L1, (_T("[Core::~Core]")));

-  scheduler_.reset(NULL);

-  system_monitor_.reset(NULL);

-}

-

-// We always return S_OK, because the core can be invoked from the system

-// scheduler, and the scheduler does not work well if the process returns

-// an error. We do not depend on the return values from the Core elsewhere.

-HRESULT Core::Main(bool is_system, bool is_crash_handler_enabled) {

-  HRESULT hr = DoMain(is_system, is_crash_handler_enabled);

-  if (FAILED(hr)) {

-    OPT_LOG(LW, (_T("[Core::DoMain failed][0x%x]"), hr));

-  }

-

-  return S_OK;

-}

-

-bool Core::AreScheduledTasksHealthy() const {

-  if (!ServiceUtils::IsServiceRunning(SERVICE_SCHEDULE)) {

-    ++metric_core_run_task_scheduler_not_running;

-    CORE_LOG(LE, (_T("[Task Scheduler Service is not running]")));

-    return false;

-  }

-

-  if (!goopdate_utils::IsInstalledGoopdateTaskUA(is_system_)) {

-    ++metric_core_run_scheduled_task_missing;

-    CORE_LOG(LE, (_T("[UA Task not installed]")));

-    return false;

-  }

-

-  if (goopdate_utils::IsDisabledGoopdateTaskUA(is_system_)) {

-    ++metric_core_run_scheduled_task_disabled;

-    CORE_LOG(LE, (_T("[UA Task disabled]")));

-    return false;

-  }

-

-  HRESULT ua_task_last_exit_code =

-      goopdate_utils::GetExitCodeGoopdateTaskUA(is_system_);

-

-  if (ua_task_last_exit_code == SCHED_S_TASK_HAS_NOT_RUN &&

-      !ConfigManager::Is24HoursSinceInstall(is_system_)) {

-    // Not 24 hours yet since install or update. Let us give the UA task the

-    // benefit of the doubt, and assume all is well for right now.

-    CORE_LOG(L3, (_T("[Not yet 24 hours since install/update]")));

-    ua_task_last_exit_code = S_OK;

-  }

-

-  metric_core_run_scheduled_task_exit_code = ua_task_last_exit_code;

-

-  if (S_OK != ua_task_last_exit_code) {

-    CORE_LOG(LE, (_T("[UA Task exit code][0x%x]"), ua_task_last_exit_code));

-    return false;

-  }

-

-  return true;

-}

-

-bool Core::IsServiceHealthy() const {

-  if (!is_system_) {

-    return true;

-  }

-

-  if (!goopdate_utils::IsServiceInstalled()) {

-    ++metric_core_run_service_missing;

-    CORE_LOG(LE, (_T("[GoogleUpdate Service is not installed]")));

-    return false;

-  }

-

-  if (ServiceUtils::IsServiceDisabled(

-      ConfigManager::GetCurrentServiceName())) {

-    ++metric_core_run_service_disabled;

-    CORE_LOG(LE, (_T("[GoogleUpdate Service is disabled]")));

-    return false;

-  }

-

-  return true;

-}

-

-bool Core::IsCheckingForUpdates() const {

-  if (!ConfigManager::Is24HoursSinceInstall(is_system_)) {

-    CORE_LOG(L3, (_T("[Not yet 24 hours since install/update]")));

-    return true;

-  }

-

-  ConfigManager* cm = ConfigManager::Instance();

-  const int k14DaysSec = 14 * 24 * 60 * 60;

-

-  if (cm->GetTimeSinceLastCheckedSec(is_system_) >= k14DaysSec) {

-    ++metric_core_run_not_checking_for_updates;

-    CORE_LOG(LE, (_T("[LastChecked older than 14 days]")));

-    return false;

-  }

-

-  return true;

-}

-

-// The Core will run all the time under the following conditions:

-//

-// * the task scheduler is not running, or

-// * the UA task is not installed, or

-// * the UA task is disabled, or

-// * the last exit code for the UA task is non-zero, or

-// * LastChecked time is older than 14 days.

-//

-// Under these conditions, Omaha uses the built-in scheduler hosted by the core

-// and it keeps the core running.

-//

-// In addition, for the machine GoogleUpdate, the Core will run all the time if

-// the service is not installed, or is disabled. In this case, Omaha uses the

-// elevator interface hosted by the core, and this keeps the core running.

-bool Core::ShouldRunForever() const {

-  // The methods are being called individually to enable metrics capture.

-  bool are_scheduled_tasks_healthy(AreScheduledTasksHealthy());

-  bool is_service_healthy(IsServiceHealthy());

-  bool is_checking_for_updates(IsCheckingForUpdates());

-

-  return !are_scheduled_tasks_healthy ||

-         !is_service_healthy ||

-         !is_checking_for_updates;

-}

-

-

-HRESULT Core::DoMain(bool is_system, bool is_crash_handler_enabled) {

-  main_thread_id_ = ::GetCurrentThreadId();

-  is_system_ = is_system;

-  is_crash_handler_enabled_ = is_crash_handler_enabled;

-

-  if (ConfigManager::Instance()->IsOemInstalling(is_system_)) {

-    // Exit immediately while an OEM is installing Windows. This prevents cores

-    // or update workers from being started by the Scheduled Task or other means

-    // before the system is sealed.

-    OPT_LOG(L1, (_T("[Exiting because an OEM is installing Windows]")));

-    ASSERT1(is_system_);

-    return S_OK;

-  }

-

-  // Do a code red check as soon as possible.

-  StartCodeRed();

-

-  CORE_LOG(L2, (_T("[IsGoogler %d]"), ConfigManager::Instance()->IsGoogler()));

-

-  NamedObjectAttributes single_core_attr;

-  GetNamedObjectAttributes(kCoreSingleInstance, is_system, &single_core_attr);

-  ProgramInstance instance(single_core_attr.name);

-  bool is_already_running = !instance.EnsureSingleInstance();

-  if (is_already_running) {

-    OPT_LOG(L1, (_T("[another core instance is already running]")));

-    return S_OK;

-  }

-

-  // TODO(omaha): the user Omaha core should run at medium integrity level and

-  // it should deelevate itself if it does not, see bug 1549842.

-

-  // Clean up the initial install directory and ignore the errors.

-  HRESULT hr = CleanUpInitialManifestDirectory();

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[CleanUpInitialManifestDirectory failed][0x%08x]"), hr));

-  }

-

-  // Start the crash handler if necessary.

-  if (is_crash_handler_enabled_) {

-    HRESULT hr = StartCrashHandler();

-    if (FAILED(hr)) {

-      OPT_LOG(LW, (_T("[Failed to start crash handler][0x%08x]"), hr));

-    }

-  }

-

-  if (!ShouldRunForever()) {

-    return S_OK;

-  }

-

-  // TODO(Omaha): Delay starting update worker when run at startup.

-  StartUpdateWorkerInternal();

-

-  // Force the main thread to create a message queue so any future WM_QUIT

-  // message posted by the ShutdownHandler will be received. If the main

-  // thread does not have a message queue, the message can be lost.

-  MSG msg = {0};

-  ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

-

-  reactor_.reset(new Reactor);

-  shutdown_handler_.reset(new ShutdownHandler);

-  hr = shutdown_handler_->Initialize(reactor_.get(), this, is_system_);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (!is_system_) {

-    // We watch the legacy manifest install directory only if we are the

-    // user core. The omaha1 -> omaha2 machine hand off occurs using the

-    // /UI cmd line switch.

-    VERIFY1(SUCCEEDED(InitializeManifestDirectoryWatcher()));

-  }

-

-  scheduler_.reset(new Scheduler(*this));

-  hr = scheduler_->Initialize();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  system_monitor_.reset(new SystemMonitor(is_system_));

-  VERIFY1(SUCCEEDED(system_monitor_->Initialize(true)));

-  system_monitor_->set_observer(this);

-

-  if (is_system_) {

-     VERIFY(SUCCEEDED(RegisterCoreProxy()),

-            (_T("The core may have been started when the registered version ")

-             _T("of Google Update does not exist or one is not registered.")));

-  }

-

-  // Start processing messages and events from the system.

-  hr = DoRun();

-

-  if (is_system) {

-    UnregisterCoreProxy();

-  }

-

-  return hr;

-}

-

-// Signals the core to shutdown. The shutdown method is called by a thread

-// running in the thread pool. It posts a WM_QUIT to the main thread, which

-// causes it to break out of the message loop. If the message can't be posted,

-// it terminates the process unconditionally.

-HRESULT Core::Shutdown() {

-  return ShutdownInternal();

-}

-

-HRESULT Core::ShutdownInternal() const {

-  OPT_LOG(L1, (_T("[Google Update is shutting down...]")));

-  ASSERT1(::GetCurrentThreadId() != main_thread_id_);

-  if (::PostThreadMessage(main_thread_id_, WM_QUIT, 0, 0)) {

-    return S_OK;

-  }

-

-  ASSERT(false, (_T("Failed to post WM_QUIT")));

-  uint32 exit_code = static_cast<uint32>(E_ABORT);

-  VERIFY1(::TerminateProcess(::GetCurrentProcess(), exit_code));

-  return S_OK;

-}

-

-void Core::LastCheckedDeleted() {

-  OPT_LOG(L1, (_T("[Core::LastCheckedDeleted]")));

-  VERIFY1(SUCCEEDED(StartUpdateWorker()));

-}

-

-void Core::NoRegisteredClients() {

-  OPT_LOG(L1, (_T("[Core::NoRegisteredClients]")));

-  VERIFY1(SUCCEEDED(StartUpdateWorker()));

-}

-

-HRESULT Core::DoRun() {

-  OPT_LOG(L1, (_T("[Core::DoRun]")));

-

-  // Trim the process working set to minimum. It does not need a more complex

-  // algorithm for now. Likely the working set will increase slightly over time

-  // as the core is handling events.

-  VERIFY1(::SetProcessWorkingSetSize(::GetCurrentProcess(),

-                                     static_cast<uint32>(-1),

-                                     static_cast<uint32>(-1)));

-  return DoHandleEvents();

-}

-

-HRESULT Core::DoHandleEvents() {

-  CORE_LOG(L1, (_T("[Core::DoHandleEvents]")));

-  MSG msg = {0};

-  int result = 0;

-  while ((result = ::GetMessage(&msg, 0, 0, 0)) != 0) {

-    ::DispatchMessage(&msg);

-    if (result == -1) {

-      break;

-    }

-  }

-  CORE_LOG(L3, (_T("[GetMessage returned %d]"), result));

-  return (result != -1) ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT Core::StartUpdateWorker() const {

-  if (!ShouldRunForever()) {

-    return ShutdownInternal();

-  }

-

-  return StartUpdateWorkerInternal();

-}

-

-HRESULT Core::StartUpdateWorkerInternal() const {

-  // The uninstall check is tentative. There are stronger checks, protected

-  // by locks, which are done by the worker process.

-  size_t num_clients(0);

-  const bool is_uninstall =

-      FAILED(goopdate_utils::GetNumClients(is_system_, &num_clients)) ||

-      num_clients <= 1;

-

-  CORE_LOG(L2, (_T("[Core::StartUpdateWorker][%u]"), num_clients));

-

-  CString exe_path = goopdate_utils::BuildGoogleUpdateExePath(is_system_);

-  CommandLineBuilder builder(COMMANDLINE_MODE_UA);

-  builder.set_install_source(kCmdLineInstallSourceCore);

-  builder.set_is_uninstall_set(is_uninstall);

-  CString cmd_line = builder.GetCommandLineArgs();

-  HRESULT hr = System::StartProcessWithArgs(exe_path, cmd_line);

-  if (SUCCEEDED(hr)) {

-    ++metric_core_worker_succeeded;

-  } else {

-    CORE_LOG(LE, (_T("[can't start update worker][0x%08x]"), hr));

-  }

-  ++metric_core_worker_total;

-  return hr;

-}

-

-HRESULT Core::StartCodeRed() const {

-  if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueNoCodeRedCheck)) {

-    CORE_LOG(LW, (_T("[Code Red is disabled for this system]")));

-    return E_ABORT;

-  }

-

-  CORE_LOG(L2, (_T("[Core::StartCodeRed]")));

-

-  CString exe_path = goopdate_utils::BuildGoogleUpdateExePath(is_system_);

-  CommandLineBuilder builder(COMMANDLINE_MODE_CODE_RED_CHECK);

-  CString cmd_line = builder.GetCommandLineArgs();

-  HRESULT hr = System::StartProcessWithArgs(exe_path, cmd_line);

-  if (SUCCEEDED(hr)) {

-    ++metric_core_cr_succeeded;

-  } else {

-    CORE_LOG(LE, (_T("[can't start Code Red worker][0x%08x]"), hr));

-  }

-  ++metric_core_cr_total;

-  return hr;

-}

-

-HRESULT Core::StartCrashHandler() const {

-  CORE_LOG(L2, (_T("[Core::StartCrashHandler]")));

-

-  CString exe_path = goopdate_utils::BuildGoogleUpdateServicesPath(is_system_);

-  CommandLineBuilder builder(COMMANDLINE_MODE_CRASH_HANDLER);

-  CString cmd_line = builder.GetCommandLineArgs();

-  HRESULT hr = System::StartProcessWithArgs(exe_path, cmd_line);

-  if (SUCCEEDED(hr)) {

-    ++metric_core_start_crash_handler_succeeded;

-  } else {

-    CORE_LOG(LE, (_T("[can't start Crash Handler][0x%08x]"), hr));

-  }

-  ++metric_core_start_crash_handler_total;

-  return hr;

-}

-

-HRESULT Core::InitializeManifestDirectoryWatcher() {

-  // We watch the legacy manifest install directory only if we are the

-  // user core. The omaha1 -> omaha2 machine hand off occurs using the

-  // /UI cmd line switch.

-  legacy_manifest_handler_.reset(new LegacyManifestHandler());

-  return legacy_manifest_handler_->Initialize(this);

-}

-

-HRESULT Core::StartInstallWorker() {

-  // Get all the manifests that are present in the handoff directory.

-  CString manifest_dir =

-      ConfigManager::Instance()->GetUserInitialManifestStorageDir();

-  std::vector<CString> manifests;

-  HRESULT hr = File::GetWildcards(manifest_dir, _T("*.gup"), &manifests);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  std::vector<CString>::iterator it;

-  for (it = manifests.begin(); it != manifests.end(); ++it) {

-    // Launch the worker using /UIUser manifest_file.

-    CString filename = *it;

-    EnclosePath(&filename);

-

-    CommandLineBuilder builder(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF);

-    builder.set_legacy_manifest_path(filename);

-    CString cmd_line = builder.GetCommandLineArgs();

-    HRESULT hr_ret = goopdate_utils::StartGoogleUpdateWithArgs(is_system_,

-                                                               cmd_line,

-                                                               NULL);

-    if (FAILED(hr_ret)) {

-      OPT_LOG(LE, (_T("[StartGoogleUpdateWithArgs failed][0x%08x]"), hr_ret));

-      hr = hr_ret;

-    }

-  }

-

-  return hr;

-}

-

-HRESULT Core::CleanUpInitialManifestDirectory() {

-  CORE_LOG(L2, (_T("[CleanUpInitialManifestDirectory]")));

-

-  const CString dir =

-      ConfigManager::Instance()->GetUserInitialManifestStorageDir();

-  if (dir.IsEmpty()) {

-    return GOOPDATE_E_CORE_INTERNAL_ERROR;

-  }

-  return DeleteDirectoryFiles(dir);

-}

-

-void Core::AggregateMetrics() const {

-  CORE_LOG(L2, (_T("[aggregate core metrics]")));

-  CollectMetrics();

-  VERIFY1(SUCCEEDED(omaha::AggregateMetrics(is_system_)));

-}

-

-// Collects: working set, peak working set, handle count, process uptime,

-// user disk free space on the current drive, process kernel time, and process

-// user time.

-void Core::CollectMetrics() const {

-  uint64 working_set(0), peak_working_set(0);

-  VERIFY1(SUCCEEDED(System::GetProcessMemoryStatistics(&working_set,

-                                                       &peak_working_set,

-                                                       NULL,

-                                                       NULL)));

-  metric_core_working_set      = working_set;

-  metric_core_peak_working_set = peak_working_set;

-

-  metric_core_handle_count = System::GetProcessHandleCount();

-

-  FILETIME now = {0};

-  FILETIME creation_time = {0};

-  FILETIME exit_time = {0};

-  FILETIME kernel_time = {0};

-  FILETIME user_time = {0};

-

-  ::GetSystemTimeAsFileTime(&now);

-

-  VERIFY1(::GetProcessTimes(::GetCurrentProcess(),

-                            &creation_time,

-                            &exit_time,

-                            &kernel_time,

-                            &user_time));

-

-  ASSERT1(FileTimeToInt64(now) >= FileTimeToInt64(creation_time));

-  uint64 uptime_100ns = FileTimeToInt64(now) - FileTimeToInt64(creation_time);

-

-  metric_core_uptime_ms      = uptime_100ns / kMillisecsTo100ns;

-  metric_core_kernel_time_ms = FileTimeToInt64(kernel_time) / kMillisecsTo100ns;

-  metric_core_user_time_ms   = FileTimeToInt64(user_time) / kMillisecsTo100ns;

-

-  uint64 free_bytes_current_user(0);

-  uint64 total_bytes_current_user(0);

-  uint64 free_bytes_all_users(0);

-

-  CString directory_name(app_util::GetCurrentModuleDirectory());

-  VERIFY1(SUCCEEDED(System::GetDiskStatistics(directory_name,

-                                              &free_bytes_current_user,

-                                              &total_bytes_current_user,

-                                              &free_bytes_all_users)));

-  metric_core_disk_space_available = free_bytes_current_user;

-}

-

-HRESULT Core::RegisterCoreProxy() {

-  CComObjectNoLock<GoogleUpdateCore>* google_update_core =

-      new CComObjectNoLock<GoogleUpdateCore>;

-

-  CDacl dacl;

-  dacl.AddAllowedAce(Sids::System(), GENERIC_ALL);

-  dacl.AddAllowedAce(Sids::Users(), GENERIC_READ);

-  CSecurityDesc sd;

-  sd.SetDacl(dacl);

-  sd.MakeAbsolute();

-

-  SharedMemoryAttributes attr(kGoogleUpdateCoreSharedMemoryName, sd);

-  google_update_core_proxy_.reset(new GoogleUpdateCoreProxy(false, &attr));

-

-#if DEBUG

-  // The core interface should be registered only once.

-  CComPtr<IGoogleUpdateCore> core_interface;

-  HRESULT hr = google_update_core_proxy_->GetObject(&core_interface);

-  ASSERT1(FAILED(hr) || !core_interface);

-#endif

-

-  return google_update_core_proxy_->RegisterObject(google_update_core);

-}

-

-void Core::UnregisterCoreProxy() {

-  if (google_update_core_proxy_.get()) {

-    google_update_core_proxy_->RevokeObject();

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// Core is the long-lived Omaha process. It runs one instance for the
+// machine and one instance for each user session, including console and TS
+// sessions.
+// If the same user is logged in multiple times, only one core process will
+// be running.
+
+#include "omaha/core/core.h"
+#include <lmsname.h>
+#include <atlsecurity.h>
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/module_utils.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reactor.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/service_utils.h"
+#include "omaha/common/shutdown_handler.h"
+#include "omaha/common/system.h"
+#include "omaha/common/time.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/core/core_metrics.h"
+#include "omaha/core/legacy_manifest_handler.h"
+#include "omaha/core/scheduler.h"
+#include "omaha/core/system_monitor.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/crash.h"
+#include "omaha/goopdate/program_instance.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/stats_uploader.h"
+
+namespace omaha {
+
+Core::Core()
+    : is_system_(false),
+      is_crash_handler_enabled_(false),
+      main_thread_id_(0) {
+  CORE_LOG(L1, (_T("[Core::Core]")));
+}
+
+Core::~Core() {
+  CORE_LOG(L1, (_T("[Core::~Core]")));
+  scheduler_.reset(NULL);
+  system_monitor_.reset(NULL);
+}
+
+// We always return S_OK, because the core can be invoked from the system
+// scheduler, and the scheduler does not work well if the process returns
+// an error. We do not depend on the return values from the Core elsewhere.
+HRESULT Core::Main(bool is_system, bool is_crash_handler_enabled) {
+  HRESULT hr = DoMain(is_system, is_crash_handler_enabled);
+  if (FAILED(hr)) {
+    OPT_LOG(LW, (_T("[Core::DoMain failed][0x%x]"), hr));
+  }
+
+  return S_OK;
+}
+
+bool Core::AreScheduledTasksHealthy() const {
+  if (!ServiceUtils::IsServiceRunning(SERVICE_SCHEDULE)) {
+    ++metric_core_run_task_scheduler_not_running;
+    CORE_LOG(LE, (_T("[Task Scheduler Service is not running]")));
+    return false;
+  }
+
+  if (!goopdate_utils::IsInstalledGoopdateTaskUA(is_system_)) {
+    ++metric_core_run_scheduled_task_missing;
+    CORE_LOG(LE, (_T("[UA Task not installed]")));
+    return false;
+  }
+
+  if (goopdate_utils::IsDisabledGoopdateTaskUA(is_system_)) {
+    ++metric_core_run_scheduled_task_disabled;
+    CORE_LOG(LE, (_T("[UA Task disabled]")));
+    return false;
+  }
+
+  HRESULT ua_task_last_exit_code =
+      goopdate_utils::GetExitCodeGoopdateTaskUA(is_system_);
+
+  if (ua_task_last_exit_code == SCHED_S_TASK_HAS_NOT_RUN &&
+      !ConfigManager::Is24HoursSinceInstall(is_system_)) {
+    // Not 24 hours yet since install or update. Let us give the UA task the
+    // benefit of the doubt, and assume all is well for right now.
+    CORE_LOG(L3, (_T("[Not yet 24 hours since install/update]")));
+    ua_task_last_exit_code = S_OK;
+  }
+
+  metric_core_run_scheduled_task_exit_code = ua_task_last_exit_code;
+
+  if (S_OK != ua_task_last_exit_code) {
+    CORE_LOG(LE, (_T("[UA Task exit code][0x%x]"), ua_task_last_exit_code));
+    return false;
+  }
+
+  return true;
+}
+
+bool Core::IsServiceHealthy() const {
+  if (!is_system_) {
+    return true;
+  }
+
+  if (!goopdate_utils::IsServiceInstalled()) {
+    ++metric_core_run_service_missing;
+    CORE_LOG(LE, (_T("[GoogleUpdate Service is not installed]")));
+    return false;
+  }
+
+  if (ServiceUtils::IsServiceDisabled(
+      ConfigManager::GetCurrentServiceName())) {
+    ++metric_core_run_service_disabled;
+    CORE_LOG(LE, (_T("[GoogleUpdate Service is disabled]")));
+    return false;
+  }
+
+  return true;
+}
+
+bool Core::IsCheckingForUpdates() const {
+  if (!ConfigManager::Is24HoursSinceInstall(is_system_)) {
+    CORE_LOG(L3, (_T("[Not yet 24 hours since install/update]")));
+    return true;
+  }
+
+  ConfigManager* cm = ConfigManager::Instance();
+  const int k14DaysSec = 14 * 24 * 60 * 60;
+
+  if (cm->GetTimeSinceLastCheckedSec(is_system_) >= k14DaysSec) {
+    ++metric_core_run_not_checking_for_updates;
+    CORE_LOG(LE, (_T("[LastChecked older than 14 days]")));
+    return false;
+  }
+
+  return true;
+}
+
+// The Core will run all the time under the following conditions:
+//
+// * the task scheduler is not running, or
+// * the UA task is not installed, or
+// * the UA task is disabled, or
+// * the last exit code for the UA task is non-zero, or
+// * LastChecked time is older than 14 days.
+//
+// Under these conditions, Omaha uses the built-in scheduler hosted by the core
+// and it keeps the core running.
+//
+// In addition, for the machine GoogleUpdate, the Core will run all the time if
+// the service is not installed, or is disabled. In this case, Omaha uses the
+// elevator interface hosted by the core, and this keeps the core running.
+bool Core::ShouldRunForever() const {
+  // The methods are being called individually to enable metrics capture.
+  bool are_scheduled_tasks_healthy(AreScheduledTasksHealthy());
+  bool is_service_healthy(IsServiceHealthy());
+  bool is_checking_for_updates(IsCheckingForUpdates());
+
+  return !are_scheduled_tasks_healthy ||
+         !is_service_healthy ||
+         !is_checking_for_updates;
+}
+
+
+HRESULT Core::DoMain(bool is_system, bool is_crash_handler_enabled) {
+  main_thread_id_ = ::GetCurrentThreadId();
+  is_system_ = is_system;
+  is_crash_handler_enabled_ = is_crash_handler_enabled;
+
+  if (ConfigManager::Instance()->IsOemInstalling(is_system_)) {
+    // Exit immediately while an OEM is installing Windows. This prevents cores
+    // or update workers from being started by the Scheduled Task or other means
+    // before the system is sealed.
+    OPT_LOG(L1, (_T("[Exiting because an OEM is installing Windows]")));
+    ASSERT1(is_system_);
+    return S_OK;
+  }
+
+  // Do a code red check as soon as possible.
+  StartCodeRed();
+
+  CORE_LOG(L2, (_T("[IsGoogler %d]"), ConfigManager::Instance()->IsGoogler()));
+
+  NamedObjectAttributes single_core_attr;
+  GetNamedObjectAttributes(kCoreSingleInstance, is_system, &single_core_attr);
+  ProgramInstance instance(single_core_attr.name);
+  bool is_already_running = !instance.EnsureSingleInstance();
+  if (is_already_running) {
+    OPT_LOG(L1, (_T("[another core instance is already running]")));
+    return S_OK;
+  }
+
+  // TODO(omaha): the user Omaha core should run at medium integrity level and
+  // it should deelevate itself if it does not, see bug 1549842.
+
+  // Clean up the initial install directory and ignore the errors.
+  HRESULT hr = CleanUpInitialManifestDirectory();
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[CleanUpInitialManifestDirectory failed][0x%08x]"), hr));
+  }
+
+  // Start the crash handler if necessary.
+  if (is_crash_handler_enabled_) {
+    HRESULT hr = StartCrashHandler();
+    if (FAILED(hr)) {
+      OPT_LOG(LW, (_T("[Failed to start crash handler][0x%08x]"), hr));
+    }
+  }
+
+  if (!ShouldRunForever()) {
+    return S_OK;
+  }
+
+  // TODO(Omaha): Delay starting update worker when run at startup.
+  StartUpdateWorkerInternal();
+
+  // Force the main thread to create a message queue so any future WM_QUIT
+  // message posted by the ShutdownHandler will be received. If the main
+  // thread does not have a message queue, the message can be lost.
+  MSG msg = {0};
+  ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+
+  reactor_.reset(new Reactor);
+  shutdown_handler_.reset(new ShutdownHandler);
+  hr = shutdown_handler_->Initialize(reactor_.get(), this, is_system_);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (!is_system_) {
+    // We watch the legacy manifest install directory only if we are the
+    // user core. The omaha1 -> omaha2 machine hand off occurs using the
+    // /UI cmd line switch.
+    VERIFY1(SUCCEEDED(InitializeManifestDirectoryWatcher()));
+  }
+
+  scheduler_.reset(new Scheduler(*this));
+  hr = scheduler_->Initialize();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  system_monitor_.reset(new SystemMonitor(is_system_));
+  VERIFY1(SUCCEEDED(system_monitor_->Initialize(true)));
+  system_monitor_->set_observer(this);
+
+  if (is_system_) {
+     VERIFY(SUCCEEDED(RegisterCoreProxy()),
+            (_T("The core may have been started when the registered version ")
+             _T("of Google Update does not exist or one is not registered.")));
+  }
+
+  // Start processing messages and events from the system.
+  hr = DoRun();
+
+  if (is_system) {
+    UnregisterCoreProxy();
+  }
+
+  return hr;
+}
+
+// Signals the core to shutdown. The shutdown method is called by a thread
+// running in the thread pool. It posts a WM_QUIT to the main thread, which
+// causes it to break out of the message loop. If the message can't be posted,
+// it terminates the process unconditionally.
+HRESULT Core::Shutdown() {
+  return ShutdownInternal();
+}
+
+HRESULT Core::ShutdownInternal() const {
+  OPT_LOG(L1, (_T("[Google Update is shutting down...]")));
+  ASSERT1(::GetCurrentThreadId() != main_thread_id_);
+  if (::PostThreadMessage(main_thread_id_, WM_QUIT, 0, 0)) {
+    return S_OK;
+  }
+
+  ASSERT(false, (_T("Failed to post WM_QUIT")));
+  uint32 exit_code = static_cast<uint32>(E_ABORT);
+  VERIFY1(::TerminateProcess(::GetCurrentProcess(), exit_code));
+  return S_OK;
+}
+
+void Core::LastCheckedDeleted() {
+  OPT_LOG(L1, (_T("[Core::LastCheckedDeleted]")));
+  VERIFY1(SUCCEEDED(StartUpdateWorker()));
+}
+
+void Core::NoRegisteredClients() {
+  OPT_LOG(L1, (_T("[Core::NoRegisteredClients]")));
+  VERIFY1(SUCCEEDED(StartUpdateWorker()));
+}
+
+HRESULT Core::DoRun() {
+  OPT_LOG(L1, (_T("[Core::DoRun]")));
+
+  // Trim the process working set to minimum. It does not need a more complex
+  // algorithm for now. Likely the working set will increase slightly over time
+  // as the core is handling events.
+  VERIFY1(::SetProcessWorkingSetSize(::GetCurrentProcess(),
+                                     static_cast<uint32>(-1),
+                                     static_cast<uint32>(-1)));
+  return DoHandleEvents();
+}
+
+HRESULT Core::DoHandleEvents() {
+  CORE_LOG(L1, (_T("[Core::DoHandleEvents]")));
+  MSG msg = {0};
+  int result = 0;
+  while ((result = ::GetMessage(&msg, 0, 0, 0)) != 0) {
+    ::DispatchMessage(&msg);
+    if (result == -1) {
+      break;
+    }
+  }
+  CORE_LOG(L3, (_T("[GetMessage returned %d]"), result));
+  return (result != -1) ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT Core::StartUpdateWorker() const {
+  if (!ShouldRunForever()) {
+    return ShutdownInternal();
+  }
+
+  return StartUpdateWorkerInternal();
+}
+
+HRESULT Core::StartUpdateWorkerInternal() const {
+  // The uninstall check is tentative. There are stronger checks, protected
+  // by locks, which are done by the worker process.
+  size_t num_clients(0);
+  const bool is_uninstall =
+      FAILED(goopdate_utils::GetNumClients(is_system_, &num_clients)) ||
+      num_clients <= 1;
+
+  CORE_LOG(L2, (_T("[Core::StartUpdateWorker][%u]"), num_clients));
+
+  CString exe_path = goopdate_utils::BuildGoogleUpdateExePath(is_system_);
+  CommandLineBuilder builder(COMMANDLINE_MODE_UA);
+  builder.set_install_source(kCmdLineInstallSourceCore);
+  builder.set_is_uninstall_set(is_uninstall);
+  CString cmd_line = builder.GetCommandLineArgs();
+  HRESULT hr = System::StartProcessWithArgs(exe_path, cmd_line);
+  if (SUCCEEDED(hr)) {
+    ++metric_core_worker_succeeded;
+  } else {
+    CORE_LOG(LE, (_T("[can't start update worker][0x%08x]"), hr));
+  }
+  ++metric_core_worker_total;
+  return hr;
+}
+
+HRESULT Core::StartCodeRed() const {
+  if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueNoCodeRedCheck)) {
+    CORE_LOG(LW, (_T("[Code Red is disabled for this system]")));
+    return E_ABORT;
+  }
+
+  CORE_LOG(L2, (_T("[Core::StartCodeRed]")));
+
+  CString exe_path = goopdate_utils::BuildGoogleUpdateExePath(is_system_);
+  CommandLineBuilder builder(COMMANDLINE_MODE_CODE_RED_CHECK);
+  CString cmd_line = builder.GetCommandLineArgs();
+  HRESULT hr = System::StartProcessWithArgs(exe_path, cmd_line);
+  if (SUCCEEDED(hr)) {
+    ++metric_core_cr_succeeded;
+  } else {
+    CORE_LOG(LE, (_T("[can't start Code Red worker][0x%08x]"), hr));
+  }
+  ++metric_core_cr_total;
+  return hr;
+}
+
+HRESULT Core::StartCrashHandler() const {
+  CORE_LOG(L2, (_T("[Core::StartCrashHandler]")));
+
+  CString exe_path = goopdate_utils::BuildGoogleUpdateServicesPath(is_system_);
+  CommandLineBuilder builder(COMMANDLINE_MODE_CRASH_HANDLER);
+  CString cmd_line = builder.GetCommandLineArgs();
+  HRESULT hr = System::StartProcessWithArgs(exe_path, cmd_line);
+  if (SUCCEEDED(hr)) {
+    ++metric_core_start_crash_handler_succeeded;
+  } else {
+    CORE_LOG(LE, (_T("[can't start Crash Handler][0x%08x]"), hr));
+  }
+  ++metric_core_start_crash_handler_total;
+  return hr;
+}
+
+HRESULT Core::InitializeManifestDirectoryWatcher() {
+  // We watch the legacy manifest install directory only if we are the
+  // user core. The omaha1 -> omaha2 machine hand off occurs using the
+  // /UI cmd line switch.
+  legacy_manifest_handler_.reset(new LegacyManifestHandler());
+  return legacy_manifest_handler_->Initialize(this);
+}
+
+HRESULT Core::StartInstallWorker() {
+  // Get all the manifests that are present in the handoff directory.
+  CString manifest_dir =
+      ConfigManager::Instance()->GetUserInitialManifestStorageDir();
+  std::vector<CString> manifests;
+  HRESULT hr = File::GetWildcards(manifest_dir, _T("*.gup"), &manifests);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  std::vector<CString>::iterator it;
+  for (it = manifests.begin(); it != manifests.end(); ++it) {
+    // Launch the worker using /UIUser manifest_file.
+    CString filename = *it;
+    EnclosePath(&filename);
+
+    CommandLineBuilder builder(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF);
+    builder.set_legacy_manifest_path(filename);
+    CString cmd_line = builder.GetCommandLineArgs();
+    HRESULT hr_ret = goopdate_utils::StartGoogleUpdateWithArgs(is_system_,
+                                                               cmd_line,
+                                                               NULL);
+    if (FAILED(hr_ret)) {
+      OPT_LOG(LE, (_T("[StartGoogleUpdateWithArgs failed][0x%08x]"), hr_ret));
+      hr = hr_ret;
+    }
+  }
+
+  return hr;
+}
+
+HRESULT Core::CleanUpInitialManifestDirectory() {
+  CORE_LOG(L2, (_T("[CleanUpInitialManifestDirectory]")));
+
+  const CString dir =
+      ConfigManager::Instance()->GetUserInitialManifestStorageDir();
+  if (dir.IsEmpty()) {
+    return GOOPDATE_E_CORE_INTERNAL_ERROR;
+  }
+  return DeleteDirectoryFiles(dir);
+}
+
+void Core::AggregateMetrics() const {
+  CORE_LOG(L2, (_T("[aggregate core metrics]")));
+  CollectMetrics();
+  VERIFY1(SUCCEEDED(omaha::AggregateMetrics(is_system_)));
+}
+
+// Collects: working set, peak working set, handle count, process uptime,
+// user disk free space on the current drive, process kernel time, and process
+// user time.
+void Core::CollectMetrics() const {
+  uint64 working_set(0), peak_working_set(0);
+  VERIFY1(SUCCEEDED(System::GetProcessMemoryStatistics(&working_set,
+                                                       &peak_working_set,
+                                                       NULL,
+                                                       NULL)));
+  metric_core_working_set      = working_set;
+  metric_core_peak_working_set = peak_working_set;
+
+  metric_core_handle_count = System::GetProcessHandleCount();
+
+  FILETIME now = {0};
+  FILETIME creation_time = {0};
+  FILETIME exit_time = {0};
+  FILETIME kernel_time = {0};
+  FILETIME user_time = {0};
+
+  ::GetSystemTimeAsFileTime(&now);
+
+  VERIFY1(::GetProcessTimes(::GetCurrentProcess(),
+                            &creation_time,
+                            &exit_time,
+                            &kernel_time,
+                            &user_time));
+
+  ASSERT1(FileTimeToInt64(now) >= FileTimeToInt64(creation_time));
+  uint64 uptime_100ns = FileTimeToInt64(now) - FileTimeToInt64(creation_time);
+
+  metric_core_uptime_ms      = uptime_100ns / kMillisecsTo100ns;
+  metric_core_kernel_time_ms = FileTimeToInt64(kernel_time) / kMillisecsTo100ns;
+  metric_core_user_time_ms   = FileTimeToInt64(user_time) / kMillisecsTo100ns;
+
+  uint64 free_bytes_current_user(0);
+  uint64 total_bytes_current_user(0);
+  uint64 free_bytes_all_users(0);
+
+  CString directory_name(app_util::GetCurrentModuleDirectory());
+  VERIFY1(SUCCEEDED(System::GetDiskStatistics(directory_name,
+                                              &free_bytes_current_user,
+                                              &total_bytes_current_user,
+                                              &free_bytes_all_users)));
+  metric_core_disk_space_available = free_bytes_current_user;
+}
+
+HRESULT Core::RegisterCoreProxy() {
+  CComObjectNoLock<GoogleUpdateCore>* google_update_core =
+      new CComObjectNoLock<GoogleUpdateCore>;
+
+  CDacl dacl;
+  dacl.AddAllowedAce(Sids::System(), GENERIC_ALL);
+  dacl.AddAllowedAce(Sids::Users(), GENERIC_READ);
+  CSecurityDesc sd;
+  sd.SetDacl(dacl);
+  sd.MakeAbsolute();
+
+  SharedMemoryAttributes attr(kGoogleUpdateCoreSharedMemoryName, sd);
+  google_update_core_proxy_.reset(new GoogleUpdateCoreProxy(false, &attr));
+
+#if DEBUG
+  // The core interface should be registered only once.
+  CComPtr<IGoogleUpdateCore> core_interface;
+  HRESULT hr = google_update_core_proxy_->GetObject(&core_interface);
+  ASSERT1(FAILED(hr) || !core_interface);
+#endif
+
+  return google_update_core_proxy_->RegisterObject(google_update_core);
+}
+
+void Core::UnregisterCoreProxy() {
+  if (google_update_core_proxy_.get()) {
+    google_update_core_proxy_->RevokeObject();
+  }
+}
+
+}  // namespace omaha
+
diff --git a/core/core.h b/core/core.h
index 24cb8b2..6cff074 100644
--- a/core/core.h
+++ b/core/core.h
@@ -1,128 +1,128 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-// Core uses a reactor design pattern to register event handlers for kernel

-// events, demultiplex them, and transfer control to the respective event

-// handlers.

-

-#ifndef OMAHA_CORE_CORE_H_

-#define OMAHA_CORE_CORE_H_

-

-#include <atlbase.h>

-#include <atlsecurity.h>

-#include <atlstr.h>

-#include <string>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/shutdown_callback.h"

-#include "omaha/core/google_update_core.h"

-#include "omaha/core/system_monitor.h"

-

-namespace omaha {

-

-class Reactor;

-class Scheduler;

-class ShutdownHandler;

-class LegacyManifestHandler;

-

-class Core

-    : public ShutdownCallback,

-      public SystemMonitorObserver {

- public:

-  Core();

-  virtual ~Core();

-

-  // Executes the instance entry point with given parameters.

-  HRESULT Main(bool is_system, bool is_crash_handler_enabled);

-

-  // Starts an update worker process if the Core is meant to run all the time.

-  // If not, causes the Core to exit the process.

-  HRESULT StartUpdateWorker() const;

-

-  // Starts a code red process.

-  HRESULT StartCodeRed() const;

-

-  // Starts an install worker process.

-  HRESULT StartInstallWorker();

-

-  // Starts the crash handler.

-  HRESULT StartCrashHandler() const;

-

-  // Aggregates the core metrics.

-  void AggregateMetrics() const;

-

-  Reactor* reactor() const { return reactor_.get(); }

-  bool is_system() const { return is_system_; }

-

- private:

-

-  HRESULT DoMain(bool is_system, bool is_crash_handler_enabled);

-

-  // Starts an update worker process.

-  HRESULT StartUpdateWorkerInternal() const;

-

-  bool AreScheduledTasksHealthy() const;

-  bool IsServiceHealthy() const;

-  bool IsCheckingForUpdates() const;

-  bool ShouldRunForever() const;

-

-  // ShutdownCallback interface.

-  // Signals the core to stop handling events and exit.

-  virtual HRESULT Shutdown();

-  virtual HRESULT ShutdownInternal() const;

-

-  // SystemMonitorObserver interface.

-  virtual void LastCheckedDeleted();

-  virtual void NoRegisteredClients();

-

-  HRESULT DoRun();

-  HRESULT DoHandleEvents();

-  HRESULT CleanUpInitialManifestDirectory();

-  HRESULT InitializeManifestDirectoryWatcher();

-

-  // Makes available the COM interface implemented by the core.

-  HRESULT RegisterCoreProxy();

-

-  // Revokes the COM interface.

-  void UnregisterCoreProxy();

-

-  // Collects ambient core metrics.

-  void CollectMetrics()const;

-

-  bool is_system_;

-

-  // True if the core has to kickoff the crash handler.

-  bool is_crash_handler_enabled_;

-

-  DWORD main_thread_id_;        // The id of the thread that runs Core::Main.

-

-  scoped_ptr<Reactor>               reactor_;

-  scoped_ptr<ShutdownHandler>       shutdown_handler_;

-  scoped_ptr<LegacyManifestHandler> legacy_manifest_handler_;

-  scoped_ptr<Scheduler>             scheduler_;

-  scoped_ptr<SystemMonitor>         system_monitor_;

-  scoped_ptr<GoogleUpdateCoreProxy> google_update_core_proxy_;

-

-  friend class CoreUtilsTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Core);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_CORE_CORE_H_

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+// Core uses a reactor design pattern to register event handlers for kernel
+// events, demultiplex them, and transfer control to the respective event
+// handlers.
+
+#ifndef OMAHA_CORE_CORE_H_
+#define OMAHA_CORE_CORE_H_
+
+#include <atlbase.h>
+#include <atlsecurity.h>
+#include <atlstr.h>
+#include <string>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/shutdown_callback.h"
+#include "omaha/core/google_update_core.h"
+#include "omaha/core/system_monitor.h"
+
+namespace omaha {
+
+class Reactor;
+class Scheduler;
+class ShutdownHandler;
+class LegacyManifestHandler;
+
+class Core
+    : public ShutdownCallback,
+      public SystemMonitorObserver {
+ public:
+  Core();
+  virtual ~Core();
+
+  // Executes the instance entry point with given parameters.
+  HRESULT Main(bool is_system, bool is_crash_handler_enabled);
+
+  // Starts an update worker process if the Core is meant to run all the time.
+  // If not, causes the Core to exit the process.
+  HRESULT StartUpdateWorker() const;
+
+  // Starts a code red process.
+  HRESULT StartCodeRed() const;
+
+  // Starts an install worker process.
+  HRESULT StartInstallWorker();
+
+  // Starts the crash handler.
+  HRESULT StartCrashHandler() const;
+
+  // Aggregates the core metrics.
+  void AggregateMetrics() const;
+
+  Reactor* reactor() const { return reactor_.get(); }
+  bool is_system() const { return is_system_; }
+
+ private:
+
+  HRESULT DoMain(bool is_system, bool is_crash_handler_enabled);
+
+  // Starts an update worker process.
+  HRESULT StartUpdateWorkerInternal() const;
+
+  bool AreScheduledTasksHealthy() const;
+  bool IsServiceHealthy() const;
+  bool IsCheckingForUpdates() const;
+  bool ShouldRunForever() const;
+
+  // ShutdownCallback interface.
+  // Signals the core to stop handling events and exit.
+  virtual HRESULT Shutdown();
+  virtual HRESULT ShutdownInternal() const;
+
+  // SystemMonitorObserver interface.
+  virtual void LastCheckedDeleted();
+  virtual void NoRegisteredClients();
+
+  HRESULT DoRun();
+  HRESULT DoHandleEvents();
+  HRESULT CleanUpInitialManifestDirectory();
+  HRESULT InitializeManifestDirectoryWatcher();
+
+  // Makes available the COM interface implemented by the core.
+  HRESULT RegisterCoreProxy();
+
+  // Revokes the COM interface.
+  void UnregisterCoreProxy();
+
+  // Collects ambient core metrics.
+  void CollectMetrics()const;
+
+  bool is_system_;
+
+  // True if the core has to kickoff the crash handler.
+  bool is_crash_handler_enabled_;
+
+  DWORD main_thread_id_;        // The id of the thread that runs Core::Main.
+
+  scoped_ptr<Reactor>               reactor_;
+  scoped_ptr<ShutdownHandler>       shutdown_handler_;
+  scoped_ptr<LegacyManifestHandler> legacy_manifest_handler_;
+  scoped_ptr<Scheduler>             scheduler_;
+  scoped_ptr<SystemMonitor>         system_monitor_;
+  scoped_ptr<GoogleUpdateCoreProxy> google_update_core_proxy_;
+
+  friend class CoreUtilsTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Core);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_CORE_CORE_H_
+
diff --git a/core/core_metrics.cc b/core/core_metrics.cc
index e83c0d4..4ad285a 100644
--- a/core/core_metrics.cc
+++ b/core/core_metrics.cc
@@ -1,51 +1,51 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/core/core_metrics.h"

-

-namespace omaha {

-

-DEFINE_METRIC_integer(core_working_set);

-DEFINE_METRIC_integer(core_peak_working_set);

-

-DEFINE_METRIC_integer(core_handle_count);

-

-DEFINE_METRIC_integer(core_uptime_ms);

-DEFINE_METRIC_integer(core_kernel_time_ms);

-DEFINE_METRIC_integer(core_user_time_ms);

-

-DEFINE_METRIC_integer(core_disk_space_available);

-

-DEFINE_METRIC_count(core_worker_total);

-DEFINE_METRIC_count(core_worker_succeeded);

-DEFINE_METRIC_count(core_cr_total);

-DEFINE_METRIC_count(core_cr_succeeded);

-

-DEFINE_METRIC_integer(core_cr_expected_timer_interval_ms);

-DEFINE_METRIC_integer(core_cr_actual_timer_interval_ms);

-

-DEFINE_METRIC_count(core_start_crash_handler_total);

-DEFINE_METRIC_count(core_start_crash_handler_succeeded);

-

-DEFINE_METRIC_count(core_run_not_checking_for_updates);

-DEFINE_METRIC_count(core_run_task_scheduler_not_running);

-DEFINE_METRIC_count(core_run_scheduled_task_missing);

-DEFINE_METRIC_count(core_run_scheduled_task_disabled);

-DEFINE_METRIC_count(core_run_service_missing);

-DEFINE_METRIC_count(core_run_service_disabled);

-DEFINE_METRIC_integer(core_run_scheduled_task_exit_code);

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/core/core_metrics.h"
+
+namespace omaha {
+
+DEFINE_METRIC_integer(core_working_set);
+DEFINE_METRIC_integer(core_peak_working_set);
+
+DEFINE_METRIC_integer(core_handle_count);
+
+DEFINE_METRIC_integer(core_uptime_ms);
+DEFINE_METRIC_integer(core_kernel_time_ms);
+DEFINE_METRIC_integer(core_user_time_ms);
+
+DEFINE_METRIC_integer(core_disk_space_available);
+
+DEFINE_METRIC_count(core_worker_total);
+DEFINE_METRIC_count(core_worker_succeeded);
+DEFINE_METRIC_count(core_cr_total);
+DEFINE_METRIC_count(core_cr_succeeded);
+
+DEFINE_METRIC_integer(core_cr_expected_timer_interval_ms);
+DEFINE_METRIC_integer(core_cr_actual_timer_interval_ms);
+
+DEFINE_METRIC_count(core_start_crash_handler_total);
+DEFINE_METRIC_count(core_start_crash_handler_succeeded);
+
+DEFINE_METRIC_count(core_run_not_checking_for_updates);
+DEFINE_METRIC_count(core_run_task_scheduler_not_running);
+DEFINE_METRIC_count(core_run_scheduled_task_missing);
+DEFINE_METRIC_count(core_run_scheduled_task_disabled);
+DEFINE_METRIC_count(core_run_service_missing);
+DEFINE_METRIC_count(core_run_service_disabled);
+DEFINE_METRIC_integer(core_run_scheduled_task_exit_code);
+
+}  // namespace omaha
+
diff --git a/core/core_metrics.h b/core/core_metrics.h
index 2317055..f00af1b 100644
--- a/core/core_metrics.h
+++ b/core/core_metrics.h
@@ -1,68 +1,68 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// Declares the usage metrics used by core module.

-

-#ifndef OMAHA_CORE_CORE_METRICS_H_

-#define OMAHA_CORE_CORE_METRICS_H_

-

-#include "omaha/statsreport/metrics.h"

-

-namespace omaha {

-

-// Core process working set and peak working set.

-DECLARE_METRIC_integer(core_working_set);

-DECLARE_METRIC_integer(core_peak_working_set);

-

-// Core process handle count.

-DECLARE_METRIC_integer(core_handle_count);

-

-// Core process uptime, kernel, and user times.

-DECLARE_METRIC_integer(core_uptime_ms);

-DECLARE_METRIC_integer(core_kernel_time_ms);

-DECLARE_METRIC_integer(core_user_time_ms);

-

-// How much free space is availble on the current drive where Omaha is

-// installed.

-DECLARE_METRIC_integer(core_disk_space_available);

-

-// How many worker and code red processes are started by the core.

-DECLARE_METRIC_count(core_worker_total);

-DECLARE_METRIC_count(core_worker_succeeded);

-DECLARE_METRIC_count(core_cr_total);

-DECLARE_METRIC_count(core_cr_succeeded);

-

-// The period of code red checks.

-DECLARE_METRIC_integer(core_cr_expected_timer_interval_ms);

-DECLARE_METRIC_integer(core_cr_actual_timer_interval_ms);

-

-// How many times StartCrashHandler() was called.

-DECLARE_METRIC_count(core_start_crash_handler_total);

-// How many times StartCrashHandler() succeeded.

-DECLARE_METRIC_count(core_start_crash_handler_succeeded);

-

-// Service and scheduled task metrics.

-DECLARE_METRIC_count(core_run_not_checking_for_updates);

-DECLARE_METRIC_count(core_run_task_scheduler_not_running);

-DECLARE_METRIC_count(core_run_scheduled_task_missing);

-DECLARE_METRIC_count(core_run_scheduled_task_disabled);

-DECLARE_METRIC_count(core_run_service_missing);

-DECLARE_METRIC_count(core_run_service_disabled);

-DECLARE_METRIC_integer(core_run_scheduled_task_exit_code);

-

-}  // namespace omaha

-

-#endif  // OMAHA_CORE_CORE_METRICS_H_

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// Declares the usage metrics used by core module.
+
+#ifndef OMAHA_CORE_CORE_METRICS_H_
+#define OMAHA_CORE_CORE_METRICS_H_
+
+#include "omaha/statsreport/metrics.h"
+
+namespace omaha {
+
+// Core process working set and peak working set.
+DECLARE_METRIC_integer(core_working_set);
+DECLARE_METRIC_integer(core_peak_working_set);
+
+// Core process handle count.
+DECLARE_METRIC_integer(core_handle_count);
+
+// Core process uptime, kernel, and user times.
+DECLARE_METRIC_integer(core_uptime_ms);
+DECLARE_METRIC_integer(core_kernel_time_ms);
+DECLARE_METRIC_integer(core_user_time_ms);
+
+// How much free space is availble on the current drive where Omaha is
+// installed.
+DECLARE_METRIC_integer(core_disk_space_available);
+
+// How many worker and code red processes are started by the core.
+DECLARE_METRIC_count(core_worker_total);
+DECLARE_METRIC_count(core_worker_succeeded);
+DECLARE_METRIC_count(core_cr_total);
+DECLARE_METRIC_count(core_cr_succeeded);
+
+// The period of code red checks.
+DECLARE_METRIC_integer(core_cr_expected_timer_interval_ms);
+DECLARE_METRIC_integer(core_cr_actual_timer_interval_ms);
+
+// How many times StartCrashHandler() was called.
+DECLARE_METRIC_count(core_start_crash_handler_total);
+// How many times StartCrashHandler() succeeded.
+DECLARE_METRIC_count(core_start_crash_handler_succeeded);
+
+// Service and scheduled task metrics.
+DECLARE_METRIC_count(core_run_not_checking_for_updates);
+DECLARE_METRIC_count(core_run_task_scheduler_not_running);
+DECLARE_METRIC_count(core_run_scheduled_task_missing);
+DECLARE_METRIC_count(core_run_scheduled_task_disabled);
+DECLARE_METRIC_count(core_run_service_missing);
+DECLARE_METRIC_count(core_run_service_disabled);
+DECLARE_METRIC_integer(core_run_scheduled_task_exit_code);
+
+}  // namespace omaha
+
+#endif  // OMAHA_CORE_CORE_METRICS_H_
+
diff --git a/core/core_unittest.cc b/core/core_unittest.cc
index 8051080..9795dd2 100644
--- a/core/core_unittest.cc
+++ b/core/core_unittest.cc
@@ -1,217 +1,217 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/error.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/thread.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/core/core.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/setup/setup_service.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/application_manager.h"

-

-namespace omaha {

-

-namespace {

-

-// Runs the core on a different thread. Since the core captures the thread id

-// in its constructor, the core instance must be created on this thread, not

-// on the main thread.

-class CoreRunner : public Runnable {

- public:

-  explicit CoreRunner(bool is_machine) : is_machine_(is_machine) {}

-  virtual ~CoreRunner() {}

-

- private:

-  virtual void Run() {

-    Core core;

-    core.Main(is_machine_, true);         // Run the crash handler.

-  }

-

-  bool is_machine_;

-  DISALLOW_EVIL_CONSTRUCTORS(CoreRunner);

-};

-

-}  // namespace

-

-class CoreTest : public testing::Test {

- public:

-  CoreTest() : is_machine_(false) {}

-

-  virtual void SetUp() {

-    ASSERT_HRESULT_SUCCEEDED(IsSystemProcess(&is_machine_));

-

-    ConfigManager::Instance()->SetLastCheckedTime(is_machine_, 10);

-

-    NamedObjectAttributes attr;

-    GetNamedObjectAttributes(kShutdownEvent, is_machine_, &attr);

-    reset(shutdown_event_, ::CreateEvent(&attr.sa, true, false, attr.name));

-    ASSERT_TRUE(shutdown_event_);

-  }

-

-  virtual void TearDown() {

-  }

-

-  HRESULT SignalShutdownEvent() {

-    EXPECT_TRUE(valid(shutdown_event_));

-    return ::SetEvent(get(shutdown_event_)) ? S_OK : HRESULTFromLastError();

-  }

-

-  HRESULT ResetShutdownEvent() {

-    EXPECT_TRUE(valid(shutdown_event_));

-    return ::ResetEvent(get(shutdown_event_)) ? S_OK : HRESULTFromLastError();

-  }

-

- protected:

-  bool is_machine_;

-  scoped_event shutdown_event_;

-};

-

-// Tests the core shutdown mechanism.

-TEST_F(CoreTest, Shutdown) {

-  // Signal existing core instances to shutdown, otherwise new instances

-  // can't start.

-  ASSERT_HRESULT_SUCCEEDED(SignalShutdownEvent());

-  ::Sleep(0);

-  ASSERT_HRESULT_SUCCEEDED(ResetShutdownEvent());

-

-  // Start a thread to run the core, signal the core to exit, and wait a while

-  // for the thread to exit. Terminate the thread if it is still running.

-  Thread thread;

-  CoreRunner core_runner(is_machine_);

-  EXPECT_TRUE(thread.Start(&core_runner));

-

-  // Give the core a little time to run before signaling it to exit.

-  ::Sleep(100);

-  EXPECT_HRESULT_SUCCEEDED(SignalShutdownEvent());

-  EXPECT_TRUE(thread.WaitTillExit(2000));

-  if (thread.Running()) {

-    thread.Terminate(-1);

-  }

-  EXPECT_HRESULT_SUCCEEDED(ResetShutdownEvent());

-}

-

-class CoreUtilsTest : public testing::Test {

- public:

-  CoreUtilsTest() : is_machine_(vista_util::IsUserAdmin()) {}

-

-  virtual void SetUp() {

-    core_.is_system_ = is_machine_;

-  }

-

-  virtual void TearDown() {

-  }

-

-  bool AreScheduledTasksHealthy() {

-    return core_.AreScheduledTasksHealthy();

-  }

-

-  bool IsServiceHealthy() {

-    return core_.IsServiceHealthy();

-  }

-

-  bool IsCheckingForUpdates() {

-    return core_.IsCheckingForUpdates();

-  }

-

-  static HRESULT DoInstallService(const TCHAR* service_cmd_line,

-                                  const TCHAR* desc) {

-    return SetupService::DoInstallService(service_cmd_line, desc);

-  }

-

-  static HRESULT DeleteServices() {

-    return SetupService::DeleteServices();

-  }

-

-  Core core_;

-  bool is_machine_;

-};

-

-TEST_F(CoreUtilsTest, AreScheduledTasksHealthy) {

-  EXPECT_SUCCEEDED(goopdate_utils::UninstallGoopdateTasks(is_machine_));

-  EXPECT_FALSE(AreScheduledTasksHealthy());

-

-  CString task_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                      _T("LongRunningSilent.exe"));

-  EXPECT_SUCCEEDED(goopdate_utils::InstallGoopdateTasks(task_path,

-                                                        is_machine_));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-  const int k12HourPeriodSec = 12 * 60 * 60;

-  const DWORD first_install_12 = now - k12HourPeriodSec;

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      ConfigManager::Instance()->registry_client_state_goopdate(is_machine_),

-      kRegValueInstallTimeSec,

-      first_install_12));

-  EXPECT_TRUE(AreScheduledTasksHealthy());

-

-  EXPECT_SUCCEEDED(goopdate_utils::UninstallGoopdateTasks(is_machine_));

-}

-

-TEST_F(CoreUtilsTest, IsServiceHealthy) {

-  if (!is_machine_) {

-    EXPECT_TRUE(IsServiceHealthy());

-    return;

-  }

-

-  EXPECT_SUCCEEDED(DeleteServices());

-  EXPECT_FALSE(IsServiceHealthy());

-

-  CString service_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                         _T("LongRunningSilent.exe"));

-  EXPECT_SUCCEEDED(DoInstallService(service_path, _T(" ")));

-  EXPECT_TRUE(IsServiceHealthy());

-

-  EXPECT_SUCCEEDED(DeleteServices());

-}

-

-TEST_F(CoreUtilsTest, IsCheckingForUpdates) {

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-  const int k12HourPeriodSec = 12 * 60 * 60;

-  const DWORD first_install_12_hours_back = now - k12HourPeriodSec;

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      ConfigManager::Instance()->registry_client_state_goopdate(is_machine_),

-      kRegValueInstallTimeSec,

-      first_install_12_hours_back));

-

-  ConfigManager::Instance()->SetLastCheckedTime(is_machine_, 10);

-  EXPECT_TRUE(IsCheckingForUpdates());

-

-  const int k48HourPeriodSec = 48 * 60 * 60;

-  const DWORD first_install_48_hours_back = now - k48HourPeriodSec;

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      ConfigManager::Instance()->registry_client_state_goopdate(is_machine_),

-      kRegValueInstallTimeSec,

-      first_install_48_hours_back));

-  EXPECT_FALSE(IsCheckingForUpdates());

-

-  AppManager app_manager(is_machine_);

-  EXPECT_SUCCEEDED(app_manager.UpdateLastChecked());

-  EXPECT_TRUE(IsCheckingForUpdates());

-

-  const int k15DaysPeriodSec = 15 * 24 * 60 * 60;

-  const DWORD last_checked_15_days_back = now - k15DaysPeriodSec;

-  ConfigManager::Instance()->SetLastCheckedTime(is_machine_,

-                                                last_checked_15_days_back);

-  EXPECT_FALSE(IsCheckingForUpdates());

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/error.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/thread.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/core/core.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/setup/setup_service.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/application_manager.h"
+
+namespace omaha {
+
+namespace {
+
+// Runs the core on a different thread. Since the core captures the thread id
+// in its constructor, the core instance must be created on this thread, not
+// on the main thread.
+class CoreRunner : public Runnable {
+ public:
+  explicit CoreRunner(bool is_machine) : is_machine_(is_machine) {}
+  virtual ~CoreRunner() {}
+
+ private:
+  virtual void Run() {
+    Core core;
+    core.Main(is_machine_, true);         // Run the crash handler.
+  }
+
+  bool is_machine_;
+  DISALLOW_EVIL_CONSTRUCTORS(CoreRunner);
+};
+
+}  // namespace
+
+class CoreTest : public testing::Test {
+ public:
+  CoreTest() : is_machine_(false) {}
+
+  virtual void SetUp() {
+    ASSERT_HRESULT_SUCCEEDED(IsSystemProcess(&is_machine_));
+
+    ConfigManager::Instance()->SetLastCheckedTime(is_machine_, 10);
+
+    NamedObjectAttributes attr;
+    GetNamedObjectAttributes(kShutdownEvent, is_machine_, &attr);
+    reset(shutdown_event_, ::CreateEvent(&attr.sa, true, false, attr.name));
+    ASSERT_TRUE(shutdown_event_);
+  }
+
+  virtual void TearDown() {
+  }
+
+  HRESULT SignalShutdownEvent() {
+    EXPECT_TRUE(valid(shutdown_event_));
+    return ::SetEvent(get(shutdown_event_)) ? S_OK : HRESULTFromLastError();
+  }
+
+  HRESULT ResetShutdownEvent() {
+    EXPECT_TRUE(valid(shutdown_event_));
+    return ::ResetEvent(get(shutdown_event_)) ? S_OK : HRESULTFromLastError();
+  }
+
+ protected:
+  bool is_machine_;
+  scoped_event shutdown_event_;
+};
+
+// Tests the core shutdown mechanism.
+TEST_F(CoreTest, Shutdown) {
+  // Signal existing core instances to shutdown, otherwise new instances
+  // can't start.
+  ASSERT_HRESULT_SUCCEEDED(SignalShutdownEvent());
+  ::Sleep(0);
+  ASSERT_HRESULT_SUCCEEDED(ResetShutdownEvent());
+
+  // Start a thread to run the core, signal the core to exit, and wait a while
+  // for the thread to exit. Terminate the thread if it is still running.
+  Thread thread;
+  CoreRunner core_runner(is_machine_);
+  EXPECT_TRUE(thread.Start(&core_runner));
+
+  // Give the core a little time to run before signaling it to exit.
+  ::Sleep(100);
+  EXPECT_HRESULT_SUCCEEDED(SignalShutdownEvent());
+  EXPECT_TRUE(thread.WaitTillExit(2000));
+  if (thread.Running()) {
+    thread.Terminate(-1);
+  }
+  EXPECT_HRESULT_SUCCEEDED(ResetShutdownEvent());
+}
+
+class CoreUtilsTest : public testing::Test {
+ public:
+  CoreUtilsTest() : is_machine_(vista_util::IsUserAdmin()) {}
+
+  virtual void SetUp() {
+    core_.is_system_ = is_machine_;
+  }
+
+  virtual void TearDown() {
+  }
+
+  bool AreScheduledTasksHealthy() {
+    return core_.AreScheduledTasksHealthy();
+  }
+
+  bool IsServiceHealthy() {
+    return core_.IsServiceHealthy();
+  }
+
+  bool IsCheckingForUpdates() {
+    return core_.IsCheckingForUpdates();
+  }
+
+  static HRESULT DoInstallService(const TCHAR* service_cmd_line,
+                                  const TCHAR* desc) {
+    return SetupService::DoInstallService(service_cmd_line, desc);
+  }
+
+  static HRESULT DeleteServices() {
+    return SetupService::DeleteServices();
+  }
+
+  Core core_;
+  bool is_machine_;
+};
+
+TEST_F(CoreUtilsTest, AreScheduledTasksHealthy) {
+  EXPECT_SUCCEEDED(goopdate_utils::UninstallGoopdateTasks(is_machine_));
+  EXPECT_FALSE(AreScheduledTasksHealthy());
+
+  CString task_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                      _T("LongRunningSilent.exe"));
+  EXPECT_SUCCEEDED(goopdate_utils::InstallGoopdateTasks(task_path,
+                                                        is_machine_));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+  const int k12HourPeriodSec = 12 * 60 * 60;
+  const DWORD first_install_12 = now - k12HourPeriodSec;
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      ConfigManager::Instance()->registry_client_state_goopdate(is_machine_),
+      kRegValueInstallTimeSec,
+      first_install_12));
+  EXPECT_TRUE(AreScheduledTasksHealthy());
+
+  EXPECT_SUCCEEDED(goopdate_utils::UninstallGoopdateTasks(is_machine_));
+}
+
+TEST_F(CoreUtilsTest, IsServiceHealthy) {
+  if (!is_machine_) {
+    EXPECT_TRUE(IsServiceHealthy());
+    return;
+  }
+
+  EXPECT_SUCCEEDED(DeleteServices());
+  EXPECT_FALSE(IsServiceHealthy());
+
+  CString service_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                         _T("LongRunningSilent.exe"));
+  EXPECT_SUCCEEDED(DoInstallService(service_path, _T(" ")));
+  EXPECT_TRUE(IsServiceHealthy());
+
+  EXPECT_SUCCEEDED(DeleteServices());
+}
+
+TEST_F(CoreUtilsTest, IsCheckingForUpdates) {
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+  const int k12HourPeriodSec = 12 * 60 * 60;
+  const DWORD first_install_12_hours_back = now - k12HourPeriodSec;
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      ConfigManager::Instance()->registry_client_state_goopdate(is_machine_),
+      kRegValueInstallTimeSec,
+      first_install_12_hours_back));
+
+  ConfigManager::Instance()->SetLastCheckedTime(is_machine_, 10);
+  EXPECT_TRUE(IsCheckingForUpdates());
+
+  const int k48HourPeriodSec = 48 * 60 * 60;
+  const DWORD first_install_48_hours_back = now - k48HourPeriodSec;
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      ConfigManager::Instance()->registry_client_state_goopdate(is_machine_),
+      kRegValueInstallTimeSec,
+      first_install_48_hours_back));
+  EXPECT_FALSE(IsCheckingForUpdates());
+
+  AppManager app_manager(is_machine_);
+  EXPECT_SUCCEEDED(app_manager.UpdateLastChecked());
+  EXPECT_TRUE(IsCheckingForUpdates());
+
+  const int k15DaysPeriodSec = 15 * 24 * 60 * 60;
+  const DWORD last_checked_15_days_back = now - k15DaysPeriodSec;
+  ConfigManager::Instance()->SetLastCheckedTime(is_machine_,
+                                                last_checked_15_days_back);
+  EXPECT_FALSE(IsCheckingForUpdates());
+}
+
+}  // namespace omaha
+
diff --git a/core/crash_handler.cc b/core/crash_handler.cc
index 9050561..cf87b2c 100644
--- a/core/crash_handler.cc
+++ b/core/crash_handler.cc
@@ -1,132 +1,132 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// The CrashHandler is a long-lived Omaha process. It runs one instance for the

-// machine and one instance for each user session, including console and TS

-// sessions. If the user has turned off crash reporting, this process will not

-// run.

-

-#include "omaha/core/crash_handler.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reactor.h"

-#include "omaha/common/shutdown_handler.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/crash.h"

-#include "omaha/goopdate/program_instance.h"

-

-namespace omaha {

-

-CrashHandler::CrashHandler()

-    : is_system_(false),

-      main_thread_id_(0) {

-  CORE_LOG(L1, (_T("[CrashHandler::CrashHandler]")));

-}

-

-CrashHandler::~CrashHandler() {

-  CORE_LOG(L1, (_T("[CrashHandler::~CrashHandler]")));

-  Crash::StopServer();

-}

-

-HRESULT CrashHandler::Main(bool is_system) {

-  if (!ConfigManager::Instance()->CanCollectStats(is_system)) {

-    return S_OK;

-  }

-

-  main_thread_id_ = ::GetCurrentThreadId();

-  is_system_ = is_system;

-

-  NamedObjectAttributes single_CrashHandler_attr;

-  GetNamedObjectAttributes(kCrashHandlerSingleInstance,

-                           is_system,

-                           &single_CrashHandler_attr);

-  ProgramInstance instance(single_CrashHandler_attr.name);

-  bool is_already_running = !instance.EnsureSingleInstance();

-  if (is_already_running) {

-    OPT_LOG(L1, (_T("[another CrashHandler instance is already running]")));

-    return S_OK;

-  }

-

-  // Start the crash handler.

-  HRESULT hr = Crash::StartServer();

-  if (FAILED(hr)) {

-    OPT_LOG(LW, (_T("[Failed to start crash handler][0x%08x]"), hr));

-  }

-

-  // Force the main thread to create a message queue so any future WM_QUIT

-  // message posted by the ShutdownHandler will be received. If the main

-  // thread does not have a message queue, the message can be lost.

-  MSG msg = {0};

-  ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);

-

-  reactor_.reset(new Reactor);

-  shutdown_handler_.reset(new ShutdownHandler);

-  hr = shutdown_handler_->Initialize(reactor_.get(), this, is_system_);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Start processing messages and events from the system.

-  return DoRun();

-}

-

-// Signals the CrashHandler to shutdown. The shutdown method is called by a

-// thread running in the thread pool. It posts a WM_QUIT to the main thread,

-// which causes it to break out of the message loop. If the message can't be

-// posted, it terminates the process unconditionally.

-HRESULT CrashHandler::Shutdown() {

-  OPT_LOG(L1, (_T("[CrashHandler::Shutdown]")));

-  ASSERT1(::GetCurrentThreadId() != main_thread_id_);

-  if (::PostThreadMessage(main_thread_id_, WM_QUIT, 0, 0)) {

-    return S_OK;

-  }

-

-  ASSERT(false, (_T("Failed to post WM_QUIT")));

-  uint32 exit_code = static_cast<uint32>(E_ABORT);

-  VERIFY1(::TerminateProcess(::GetCurrentProcess(), exit_code));

-  return S_OK;

-}

-

-HRESULT CrashHandler::DoRun() {

-  OPT_LOG(L1, (_T("[CrashHandler::DoRun]")));

-

-  // Trim the process working set to minimum. It does not need a more complex

-  // algorithm for now. Likely the working set will increase slightly over time

-  // as the CrashHandler is handling events.

-  VERIFY1(::SetProcessWorkingSetSize(::GetCurrentProcess(),

-                                     static_cast<uint32>(-1),

-                                     static_cast<uint32>(-1)));

-  return DoHandleEvents();

-}

-

-HRESULT CrashHandler::DoHandleEvents() {

-  CORE_LOG(L1, (_T("[CrashHandler::DoHandleEvents]")));

-  MSG msg = {0};

-  int result = 0;

-  while ((result = ::GetMessage(&msg, 0, 0, 0)) != 0) {

-    ::DispatchMessage(&msg);

-    if (result == -1) {

-      break;

-    }

-  }

-  CORE_LOG(L3, (_T("[GetMessage returned %d]"), result));

-  return (result != -1) ? S_OK : HRESULTFromLastError();

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// The CrashHandler is a long-lived Omaha process. It runs one instance for the
+// machine and one instance for each user session, including console and TS
+// sessions. If the user has turned off crash reporting, this process will not
+// run.
+
+#include "omaha/core/crash_handler.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reactor.h"
+#include "omaha/common/shutdown_handler.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/crash.h"
+#include "omaha/goopdate/program_instance.h"
+
+namespace omaha {
+
+CrashHandler::CrashHandler()
+    : is_system_(false),
+      main_thread_id_(0) {
+  CORE_LOG(L1, (_T("[CrashHandler::CrashHandler]")));
+}
+
+CrashHandler::~CrashHandler() {
+  CORE_LOG(L1, (_T("[CrashHandler::~CrashHandler]")));
+  Crash::StopServer();
+}
+
+HRESULT CrashHandler::Main(bool is_system) {
+  if (!ConfigManager::Instance()->CanCollectStats(is_system)) {
+    return S_OK;
+  }
+
+  main_thread_id_ = ::GetCurrentThreadId();
+  is_system_ = is_system;
+
+  NamedObjectAttributes single_CrashHandler_attr;
+  GetNamedObjectAttributes(kCrashHandlerSingleInstance,
+                           is_system,
+                           &single_CrashHandler_attr);
+  ProgramInstance instance(single_CrashHandler_attr.name);
+  bool is_already_running = !instance.EnsureSingleInstance();
+  if (is_already_running) {
+    OPT_LOG(L1, (_T("[another CrashHandler instance is already running]")));
+    return S_OK;
+  }
+
+  // Start the crash handler.
+  HRESULT hr = Crash::StartServer();
+  if (FAILED(hr)) {
+    OPT_LOG(LW, (_T("[Failed to start crash handler][0x%08x]"), hr));
+  }
+
+  // Force the main thread to create a message queue so any future WM_QUIT
+  // message posted by the ShutdownHandler will be received. If the main
+  // thread does not have a message queue, the message can be lost.
+  MSG msg = {0};
+  ::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+
+  reactor_.reset(new Reactor);
+  shutdown_handler_.reset(new ShutdownHandler);
+  hr = shutdown_handler_->Initialize(reactor_.get(), this, is_system_);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Start processing messages and events from the system.
+  return DoRun();
+}
+
+// Signals the CrashHandler to shutdown. The shutdown method is called by a
+// thread running in the thread pool. It posts a WM_QUIT to the main thread,
+// which causes it to break out of the message loop. If the message can't be
+// posted, it terminates the process unconditionally.
+HRESULT CrashHandler::Shutdown() {
+  OPT_LOG(L1, (_T("[CrashHandler::Shutdown]")));
+  ASSERT1(::GetCurrentThreadId() != main_thread_id_);
+  if (::PostThreadMessage(main_thread_id_, WM_QUIT, 0, 0)) {
+    return S_OK;
+  }
+
+  ASSERT(false, (_T("Failed to post WM_QUIT")));
+  uint32 exit_code = static_cast<uint32>(E_ABORT);
+  VERIFY1(::TerminateProcess(::GetCurrentProcess(), exit_code));
+  return S_OK;
+}
+
+HRESULT CrashHandler::DoRun() {
+  OPT_LOG(L1, (_T("[CrashHandler::DoRun]")));
+
+  // Trim the process working set to minimum. It does not need a more complex
+  // algorithm for now. Likely the working set will increase slightly over time
+  // as the CrashHandler is handling events.
+  VERIFY1(::SetProcessWorkingSetSize(::GetCurrentProcess(),
+                                     static_cast<uint32>(-1),
+                                     static_cast<uint32>(-1)));
+  return DoHandleEvents();
+}
+
+HRESULT CrashHandler::DoHandleEvents() {
+  CORE_LOG(L1, (_T("[CrashHandler::DoHandleEvents]")));
+  MSG msg = {0};
+  int result = 0;
+  while ((result = ::GetMessage(&msg, 0, 0, 0)) != 0) {
+    ::DispatchMessage(&msg);
+    if (result == -1) {
+      break;
+    }
+  }
+  CORE_LOG(L3, (_T("[GetMessage returned %d]"), result));
+  return (result != -1) ? S_OK : HRESULTFromLastError();
+}
+
+}  // namespace omaha
+
diff --git a/core/crash_handler.h b/core/crash_handler.h
index fd504ea..cff0563 100644
--- a/core/crash_handler.h
+++ b/core/crash_handler.h
@@ -1,66 +1,66 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_CORE_CRASH_HANDLER_H_

-#define OMAHA_CORE_CRASH_HANDLER_H_

-

-#include <windows.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/shutdown_callback.h"

-#include "third_party/breakpad/src/client/windows/crash_generation/client_info.h"

-#include "third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.h"

-

-namespace omaha {

-

-class Reactor;

-class ShutdownHandler;

-

-class CrashHandler : public ShutdownCallback {

- public:

-  CrashHandler();

-  virtual ~CrashHandler();

-

-  // Executes the instance entry point with given parameters.

-  HRESULT Main(bool is_system);

-

-  Reactor* reactor() const { return reactor_.get(); }

-  bool is_system() const { return is_system_; }

-

- private:

-  typedef google_breakpad::CrashGenerationServer CrashGenerationServer;

-

-  // ShutdownCallback interface.

-  // Signals the CrashHandler to stop handling events and exit.

-  virtual HRESULT Shutdown();

-

-  HRESULT DoRun();

-  HRESULT DoHandleEvents();

-

-  bool is_system_;

-

-  DWORD main_thread_id_;  // The id of the thread that runs CrashHandler::Main.

-

-  scoped_ptr<Reactor>               reactor_;

-  scoped_ptr<ShutdownHandler>       shutdown_handler_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(CrashHandler);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_CORE_CRASH_HANDLER_H_

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_CORE_CRASH_HANDLER_H_
+#define OMAHA_CORE_CRASH_HANDLER_H_
+
+#include <windows.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/shutdown_callback.h"
+#include "third_party/breakpad/src/client/windows/crash_generation/client_info.h"
+#include "third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.h"
+
+namespace omaha {
+
+class Reactor;
+class ShutdownHandler;
+
+class CrashHandler : public ShutdownCallback {
+ public:
+  CrashHandler();
+  virtual ~CrashHandler();
+
+  // Executes the instance entry point with given parameters.
+  HRESULT Main(bool is_system);
+
+  Reactor* reactor() const { return reactor_.get(); }
+  bool is_system() const { return is_system_; }
+
+ private:
+  typedef google_breakpad::CrashGenerationServer CrashGenerationServer;
+
+  // ShutdownCallback interface.
+  // Signals the CrashHandler to stop handling events and exit.
+  virtual HRESULT Shutdown();
+
+  HRESULT DoRun();
+  HRESULT DoHandleEvents();
+
+  bool is_system_;
+
+  DWORD main_thread_id_;  // The id of the thread that runs CrashHandler::Main.
+
+  scoped_ptr<Reactor>               reactor_;
+  scoped_ptr<ShutdownHandler>       shutdown_handler_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(CrashHandler);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_CORE_CRASH_HANDLER_H_
+
diff --git a/core/google_update_core.cc b/core/google_update_core.cc
index 43f1bab..58ad6f2 100644
--- a/core/google_update_core.cc
+++ b/core/google_update_core.cc
@@ -1,153 +1,153 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/core/google_update_core.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/exception_barrier.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/system.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/config_manager.h"

-

-namespace omaha {

-

-GoogleUpdateCore::GoogleUpdateCore() {

-  CORE_LOG(L3, (_T("[GoogleUpdateCore::GoogleUpdateCore]")));

-}

-

-GoogleUpdateCore::~GoogleUpdateCore() {

-  CORE_LOG(L3, (_T("[GoogleUpdateCore::~GoogleUpdateCore]")));

-}

-

-STDMETHODIMP GoogleUpdateCore::LaunchCmdElevated(const WCHAR* app_guid,

-                                                 const WCHAR* cmd_id,

-                                                 DWORD caller_proc_id,

-                                                 ULONG_PTR* proc_handle) {

-  CORE_LOG(L3, (_T("[GoogleUpdateCore::LaunchCmdElevated]")

-                _T("[app %s][cmd %s][pid %d]"),

-                app_guid, cmd_id, caller_proc_id));

-

-  ExceptionBarrier barrier;

-

-  ASSERT1(app_guid);

-  ASSERT1(cmd_id);

-  ASSERT1(proc_handle);

-

-  if (!(IsGuid(app_guid) && cmd_id && _tcslen(cmd_id) && proc_handle)) {

-    return E_INVALIDARG;

-  }

-

-  scoped_process caller_proc_handle;

-  HRESULT hr = OpenCallerProcessHandle(caller_proc_id,

-                                       address(caller_proc_handle));

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[failed to open caller's handle][0x%x]"), hr));

-    return hr;

-  }

-

-  CString cmd(GetCommandToLaunch(app_guid, cmd_id));

-  CORE_LOG(L3, (_T("[GoogleUpdateCore::LaunchCmdElevated][cmd %s]"), cmd));

-  if (cmd.IsEmpty()) {

-    return GOOPDATE_E_CORE_MISSING_CMD;

-  }

-  return LaunchCmd(&cmd, get(caller_proc_handle), proc_handle);

-}

-

-HRESULT GoogleUpdateCore::OpenCallerProcessHandle(DWORD proc_id,

-                                                  HANDLE* proc_handle) {

-  ASSERT1(proc_handle);

-  *proc_handle = NULL;

-

-  HRESULT hr = ::CoImpersonateClient();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ON_SCOPE_EXIT(::CoRevertToSelf);

-

-  *proc_handle = ::OpenProcess(PROCESS_DUP_HANDLE, false, proc_id);

-  return *proc_handle ? S_OK : HRESULTFromLastError();

-}

-

-CString GoogleUpdateCore::GetCommandToLaunch(const TCHAR* app_guid,

-                                             const TCHAR* cmd_id) {

-  CString cmd_line;

-  if (!app_guid || !cmd_id) {

-    return cmd_line;

-  }

-

-  ConfigManager* config_manager = ConfigManager::Instance();

-  CString clients_key_name = config_manager->machine_registry_clients();

-  CString app_key_name = AppendRegKeyPath(clients_key_name, app_guid);

-

-  RegKey::GetValue(app_key_name, cmd_id, &cmd_line);

-  return cmd_line;

-}

-

-HRESULT GoogleUpdateCore::LaunchCmd(CString* cmd,

-                                    HANDLE caller_proc_handle,

-                                    ULONG_PTR* proc_handle) {

-  if (!cmd || !caller_proc_handle || !proc_handle) {

-    return E_INVALIDARG;

-  }

-

-  *proc_handle = NULL;

-  HRESULT hr = S_OK;

-

-  // This is a pseudo handle that must not be closed.

-  HANDLE this_process_handle = ::GetCurrentProcess();

-

-  PROCESS_INFORMATION pi = {0};

-  hr = System::StartProcess(NULL, cmd->GetBuffer(), &pi);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[failed to launch cmd][%s][0x%08x]"), *cmd, hr));

-    return hr;

-  }

-

-  // DuplicateHandle call will close the source handle regardless of any error

-  // status returned.

-  ASSERT1(pi.hProcess);

-  VERIFY1(::CloseHandle(pi.hThread));

-

-  scoped_process duplicate_proc_handle;

-

-  DWORD desired_access = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;

-  bool res = ::DuplicateHandle(

-      this_process_handle,             // Current process.

-      pi.hProcess,                     // Process handle to duplicate.

-      caller_proc_handle,              // Process receiving the handle.

-      address(duplicate_proc_handle),  // Duplicated handle.

-      desired_access,                  // Access requested for the new handle.

-      false,                           // Don't inherit the new handle.

-      DUPLICATE_CLOSE_SOURCE) != 0;    // Closes the source handle.

-  if (!res) {

-    hr = HRESULTFromLastError();

-    CORE_LOG(LE, (_T("[failed to duplicate the handle][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Transfer the ownership of the new handle to the caller. The caller must

-  // close this handle.

-  *proc_handle = reinterpret_cast<ULONG_PTR>(release(duplicate_proc_handle));

-

-  return S_OK;

-}

-

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/core/google_update_core.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/exception_barrier.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/system.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/config_manager.h"
+
+namespace omaha {
+
+GoogleUpdateCore::GoogleUpdateCore() {
+  CORE_LOG(L3, (_T("[GoogleUpdateCore::GoogleUpdateCore]")));
+}
+
+GoogleUpdateCore::~GoogleUpdateCore() {
+  CORE_LOG(L3, (_T("[GoogleUpdateCore::~GoogleUpdateCore]")));
+}
+
+STDMETHODIMP GoogleUpdateCore::LaunchCmdElevated(const WCHAR* app_guid,
+                                                 const WCHAR* cmd_id,
+                                                 DWORD caller_proc_id,
+                                                 ULONG_PTR* proc_handle) {
+  CORE_LOG(L3, (_T("[GoogleUpdateCore::LaunchCmdElevated]")
+                _T("[app %s][cmd %s][pid %d]"),
+                app_guid, cmd_id, caller_proc_id));
+
+  ExceptionBarrier barrier;
+
+  ASSERT1(app_guid);
+  ASSERT1(cmd_id);
+  ASSERT1(proc_handle);
+
+  if (!(IsGuid(app_guid) && cmd_id && _tcslen(cmd_id) && proc_handle)) {
+    return E_INVALIDARG;
+  }
+
+  scoped_process caller_proc_handle;
+  HRESULT hr = OpenCallerProcessHandle(caller_proc_id,
+                                       address(caller_proc_handle));
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[failed to open caller's handle][0x%x]"), hr));
+    return hr;
+  }
+
+  CString cmd(GetCommandToLaunch(app_guid, cmd_id));
+  CORE_LOG(L3, (_T("[GoogleUpdateCore::LaunchCmdElevated][cmd %s]"), cmd));
+  if (cmd.IsEmpty()) {
+    return GOOPDATE_E_CORE_MISSING_CMD;
+  }
+  return LaunchCmd(&cmd, get(caller_proc_handle), proc_handle);
+}
+
+HRESULT GoogleUpdateCore::OpenCallerProcessHandle(DWORD proc_id,
+                                                  HANDLE* proc_handle) {
+  ASSERT1(proc_handle);
+  *proc_handle = NULL;
+
+  HRESULT hr = ::CoImpersonateClient();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ON_SCOPE_EXIT(::CoRevertToSelf);
+
+  *proc_handle = ::OpenProcess(PROCESS_DUP_HANDLE, false, proc_id);
+  return *proc_handle ? S_OK : HRESULTFromLastError();
+}
+
+CString GoogleUpdateCore::GetCommandToLaunch(const TCHAR* app_guid,
+                                             const TCHAR* cmd_id) {
+  CString cmd_line;
+  if (!app_guid || !cmd_id) {
+    return cmd_line;
+  }
+
+  ConfigManager* config_manager = ConfigManager::Instance();
+  CString clients_key_name = config_manager->machine_registry_clients();
+  CString app_key_name = AppendRegKeyPath(clients_key_name, app_guid);
+
+  RegKey::GetValue(app_key_name, cmd_id, &cmd_line);
+  return cmd_line;
+}
+
+HRESULT GoogleUpdateCore::LaunchCmd(CString* cmd,
+                                    HANDLE caller_proc_handle,
+                                    ULONG_PTR* proc_handle) {
+  if (!cmd || !caller_proc_handle || !proc_handle) {
+    return E_INVALIDARG;
+  }
+
+  *proc_handle = NULL;
+  HRESULT hr = S_OK;
+
+  // This is a pseudo handle that must not be closed.
+  HANDLE this_process_handle = ::GetCurrentProcess();
+
+  PROCESS_INFORMATION pi = {0};
+  hr = System::StartProcess(NULL, cmd->GetBuffer(), &pi);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[failed to launch cmd][%s][0x%08x]"), *cmd, hr));
+    return hr;
+  }
+
+  // DuplicateHandle call will close the source handle regardless of any error
+  // status returned.
+  ASSERT1(pi.hProcess);
+  VERIFY1(::CloseHandle(pi.hThread));
+
+  scoped_process duplicate_proc_handle;
+
+  DWORD desired_access = PROCESS_QUERY_INFORMATION | SYNCHRONIZE;
+  bool res = ::DuplicateHandle(
+      this_process_handle,             // Current process.
+      pi.hProcess,                     // Process handle to duplicate.
+      caller_proc_handle,              // Process receiving the handle.
+      address(duplicate_proc_handle),  // Duplicated handle.
+      desired_access,                  // Access requested for the new handle.
+      false,                           // Don't inherit the new handle.
+      DUPLICATE_CLOSE_SOURCE) != 0;    // Closes the source handle.
+  if (!res) {
+    hr = HRESULTFromLastError();
+    CORE_LOG(LE, (_T("[failed to duplicate the handle][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Transfer the ownership of the new handle to the caller. The caller must
+  // close this handle.
+  *proc_handle = reinterpret_cast<ULONG_PTR>(release(duplicate_proc_handle));
+
+  return S_OK;
+}
+
+
+}  // namespace omaha
+
diff --git a/core/google_update_core.h b/core/google_update_core.h
index 43eea4a..d6f19ed 100644
--- a/core/google_update_core.h
+++ b/core/google_update_core.h
@@ -1,87 +1,87 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_CORE_GOOGLE_UPDATE_CORE_H_

-#define OMAHA_CORE_GOOGLE_UPDATE_CORE_H_

-

-#include <windows.h>

-#include <atlbase.h>

-#include <atlcom.h>

-#include <atlstr.h>

-#include "omaha/common/atlregmapex.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/goopdate/google_update_proxy.h"

-#include "omaha/goopdate/resource.h"

-

-// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".

-#include "goopdate/google_update_idl.h"

-

-namespace omaha {

-

-// TODO(omaha): might need to synchronize on the GoogleUpdateCoreProxy.

-typedef SharedMemoryProxy<IGoogleUpdateCore, FakeGLock> GoogleUpdateCoreProxy;

-

-class ATL_NO_VTABLE GoogleUpdateCore

-    : public CComObjectRootEx<CComMultiThreadModel>,

-      public CComCoClass<GoogleUpdateCore>,

-      public IGoogleUpdateCore {

- public:

-  GoogleUpdateCore();

-  virtual ~GoogleUpdateCore();

-

-  DECLARE_NOT_AGGREGATABLE(GoogleUpdateCore)

-  DECLARE_PROTECT_FINAL_CONSTRUCT()

-  DECLARE_REGISTRY_RESOURCEID_EX(IDR_GOOGLE_UPDATE_CORE_CLASS)

-

-  // C4640: construction of local static object is not thread-safe

-  #pragma warning(disable : 4640)

-  BEGIN_REGISTRY_MAP()

-    REGMAP_ENTRY(_T("PROGID"),      _T("GoogleUpdate.CoreClass"))

-    REGMAP_ENTRY(_T("VERSION"),     _T("1"))

-    REGMAP_ENTRY(_T("NAME"),        _T("GoogleUpdateCoreClass"))

-    REGMAP_ENTRY(_T("DESCRIPTION"), _T("Google Update Core Class"))

-    REGMAP_UUID(_T("CLSID"),        __uuidof(GoogleUpdateCoreClass))

-  END_REGISTRY_MAP()

-

-  // C4505: unreferenced IUnknown local functions have been removed

-  #pragma warning(disable : 4505)

-  BEGIN_COM_MAP(GoogleUpdateCore)

-    COM_INTERFACE_ENTRY(IGoogleUpdateCore)

-  END_COM_MAP()

-

-  // Launches a command line elevated.

-  STDMETHOD(LaunchCmdElevated)(const WCHAR* app_guid,

-                               const WCHAR* cmd_id,

-                               DWORD caller_proc_id,

-                               ULONG_PTR* proc_handle);

- private:

-  // If the COM caller has permissions for process proc_id, opens and returns

-  // the process handle.

-  static HRESULT OpenCallerProcessHandle(DWORD proc_id, HANDLE* proc_handle);

-

-  static CString GetCommandToLaunch(const TCHAR* app_guid, const TCHAR* cmd_id);

-

-  static HRESULT LaunchCmd(CString* cmd,

-                           HANDLE caller_proc_handle,

-                           ULONG_PTR* proc_handle);

-

-  friend class GoogleUpdateCoreTest;

-  DISALLOW_EVIL_CONSTRUCTORS(GoogleUpdateCore);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_CORE_GOOGLE_UPDATE_CORE_H_

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_CORE_GOOGLE_UPDATE_CORE_H_
+#define OMAHA_CORE_GOOGLE_UPDATE_CORE_H_
+
+#include <windows.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlstr.h>
+#include "omaha/common/atlregmapex.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/goopdate/google_update_proxy.h"
+#include "omaha/goopdate/resource.h"
+
+// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".
+#include "goopdate/google_update_idl.h"
+
+namespace omaha {
+
+// TODO(omaha): might need to synchronize on the GoogleUpdateCoreProxy.
+typedef SharedMemoryProxy<IGoogleUpdateCore, FakeGLock> GoogleUpdateCoreProxy;
+
+class ATL_NO_VTABLE GoogleUpdateCore
+    : public CComObjectRootEx<CComMultiThreadModel>,
+      public CComCoClass<GoogleUpdateCore>,
+      public IGoogleUpdateCore {
+ public:
+  GoogleUpdateCore();
+  virtual ~GoogleUpdateCore();
+
+  DECLARE_NOT_AGGREGATABLE(GoogleUpdateCore)
+  DECLARE_PROTECT_FINAL_CONSTRUCT()
+  DECLARE_REGISTRY_RESOURCEID_EX(IDR_GOOGLE_UPDATE_CORE_CLASS)
+
+  // C4640: construction of local static object is not thread-safe
+  #pragma warning(disable : 4640)
+  BEGIN_REGISTRY_MAP()
+    REGMAP_ENTRY(_T("PROGID"),      _T("GoogleUpdate.CoreClass"))
+    REGMAP_ENTRY(_T("VERSION"),     _T("1"))
+    REGMAP_ENTRY(_T("NAME"),        _T("GoogleUpdateCoreClass"))
+    REGMAP_ENTRY(_T("DESCRIPTION"), _T("Google Update Core Class"))
+    REGMAP_UUID(_T("CLSID"),        __uuidof(GoogleUpdateCoreClass))
+  END_REGISTRY_MAP()
+
+  // C4505: unreferenced IUnknown local functions have been removed
+  #pragma warning(disable : 4505)
+  BEGIN_COM_MAP(GoogleUpdateCore)
+    COM_INTERFACE_ENTRY(IGoogleUpdateCore)
+  END_COM_MAP()
+
+  // Launches a command line elevated.
+  STDMETHOD(LaunchCmdElevated)(const WCHAR* app_guid,
+                               const WCHAR* cmd_id,
+                               DWORD caller_proc_id,
+                               ULONG_PTR* proc_handle);
+ private:
+  // If the COM caller has permissions for process proc_id, opens and returns
+  // the process handle.
+  static HRESULT OpenCallerProcessHandle(DWORD proc_id, HANDLE* proc_handle);
+
+  static CString GetCommandToLaunch(const TCHAR* app_guid, const TCHAR* cmd_id);
+
+  static HRESULT LaunchCmd(CString* cmd,
+                           HANDLE caller_proc_handle,
+                           ULONG_PTR* proc_handle);
+
+  friend class GoogleUpdateCoreTest;
+  DISALLOW_EVIL_CONSTRUCTORS(GoogleUpdateCore);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_CORE_GOOGLE_UPDATE_CORE_H_
+
diff --git a/core/google_update_core_unittest.cc b/core/google_update_core_unittest.cc
index 91c4981..a93a86c 100644
--- a/core/google_update_core_unittest.cc
+++ b/core/google_update_core_unittest.cc
@@ -1,438 +1,438 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/error.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/system.h"

-#include "omaha/common/vistautil.h"

-

-#include "omaha/core/google_update_core.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/google_update_proxy.h"

-#include "omaha/setup/setup_service.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class GoogleUpdateCoreTest : public testing::Test {

- protected:

-  GoogleUpdateCoreTest() {

-    GUID proxy_clsid = PROXY_CLSID_IS;

-    proxy_guid_ = CW2A(GuidToString(proxy_clsid));

-

-    regedit_uninstall_string_.Format(

-        "Windows Registry Editor Version 5.00\r\n"

-        "\r\n"

-        "[-HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\Clients\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT

-        "\r\n"

-        "[-HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\ClientState\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT

-        "\r\n"

-        "[-HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\network\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT

-        "\r\n"

-        "[-HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Interface\\{909489C2-85A6-4322-AA56-D25278649D67}]\r\n"  // NOLINT

-        "\r\n"

-        "[-HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\%s]\r\n"

-        "\r\n"

-

-        // Registration for the user must be cleared too since COM looks up HKCR

-        // and that resolves to either HKCU or HKLM classes.

-        "[-HKEY_CURRENT_USER\\SOFTWARE\\Classes\\Interface\\{909489C2-85A6-4322-AA56-D25278649D67}]\r\n"  // NOLINT

-        "\r\n"

-        "[-HKEY_CURRENT_USER\\SOFTWARE\\Classes\\CLSID\\%s]\r\n"

-        "\r\n",

-        proxy_guid_, proxy_guid_);

-  }

-

-  virtual void SetUp() {

-    if (!vista_util::IsUserAdmin()) {

-      return;

-    }

-    System::AdjustPrivilege(SE_DEBUG_NAME, true);

-    TerminateAllGoogleUpdateProcesses();

-    SetupRegistry();

-  }

-

-  virtual void TearDown() {

-    if (!vista_util::IsUserAdmin()) {

-      return;

-    }

-    TerminateAllGoogleUpdateProcesses();

-    TeardownRegistry();

-  }

-

-  CString GetCommandToLaunch(const TCHAR* app_guid, const TCHAR* cmd_id) {

-    return GoogleUpdateCore::GetCommandToLaunch(app_guid, cmd_id);

-  }

-

-  HRESULT LaunchCmd(CString* cmd,

-                    HANDLE caller_proc_handle,

-                    ULONG_PTR* proc_handle) {

-    return GoogleUpdateCore::LaunchCmd(cmd, caller_proc_handle, proc_handle);

-  }

-

-  // Starts the core and waits for it to register its shared memory section.

-  HANDLE StartCore();

-

-  // Creates the COM registration required by the test.

-  void SetupRegistry();

-

-  // Cleans up the COM registration.

-  void TeardownRegistry();

-

-  void DoLaunchCmdElevatedTests(IUnknown* core_object);

-

-  // The guid of the proxy code. This is a build constant.

-  CStringA proxy_guid_;

-

-  CStringA regedit_uninstall_string_;

-};

-

-void WriteRegeditDataToRegistry(const CStringA& regedit_data) {

-  EXPECT_TRUE(regedit_data.GetLength());

-

-  CString temp_file;

-  EXPECT_TRUE(::GetTempFileName(app_util::GetModuleDirectory(NULL),

-                                _T("reg"),

-                                0,

-                                CStrBuf(temp_file, MAX_PATH)));

-

-  CString reg_file_path = temp_file + _T(".reg");

-  scoped_hfile file_handle(::CreateFile(reg_file_path,

-                                        GENERIC_WRITE,

-                                        FILE_SHARE_READ,

-                                        NULL,

-                                        CREATE_ALWAYS,

-                                        FILE_ATTRIBUTE_NORMAL,

-                                        NULL));

-  EXPECT_TRUE(file_handle);

-  DWORD bytes_written = 0;

-  EXPECT_TRUE(::WriteFile(get(file_handle),

-                          regedit_data,

-                          regedit_data.GetLength(),

-                          &bytes_written,

-                          NULL));

-  EXPECT_TRUE(bytes_written);

-  reset(file_handle);

-

-  CString regedit_path(_T("regedit.exe"));

-  CString cmd_line;

-  cmd_line.Format(_T("/s \"%s\""), reg_file_path);

-

-  if (vista_util::IsUserAdmin()) {

-    EXPECT_SUCCEEDED(RegisterOrUnregisterExe(regedit_path, cmd_line));

-  } else {

-    // Elevate RegEdit.exe for medium integrity users on Vista and above.

-    DWORD exit_code(0);

-    EXPECT_SUCCEEDED(vista_util::RunElevated(regedit_path,

-                                             cmd_line,

-                                             SW_SHOWNORMAL,

-                                             &exit_code));

-    EXPECT_EQ(0, exit_code);

-  }

-

-  EXPECT_TRUE(::DeleteFile(temp_file));

-  EXPECT_TRUE(::DeleteFile(reg_file_path));

-}

-

-void GoogleUpdateCoreTest::SetupRegistry() {

-  CStringA regedit_data(regedit_uninstall_string_);

-

-  CString unittest_dir = app_util::GetModuleDirectory(NULL);

-  CStringA goopdate_dll(CW2A(ConcatenatePath(unittest_dir, kGoopdateDllName)));

-  goopdate_dll.Replace("\\", "\\\\");

-

-  regedit_data.AppendFormat(

-      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Interface\\{909489C2-85A6-4322-AA56-D25278649D67}]\r\n"  // NOLINT

-      "@=\"IGoogleUpdateCore\"\r\n"

-      "\r\n"

-      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Interface\\{909489C2-85A6-4322-AA56-D25278649D67}\\NumMethods]\r\n"  // NOLINT

-      "@=\"%d\"\r\n"

-      "\r\n"

-      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Interface\\{909489C2-85A6-4322-AA56-D25278649D67}\\ProxyStubClsid32]\r\n"  // NOLINT

-      "@=\"%s\"\r\n"

-      "\r\n"

-      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\%s]\r\n"

-      "@=\"PSFactoryBuffer\"\r\n"

-      "\r\n"

-      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\%s\\InProcServer32]\r\n"

-      "@=\"%s\"\r\n"

-      "\"ThreadingModel\"=\"Both\"\r\n"

-      "\r\n",

-      4, proxy_guid_, proxy_guid_, proxy_guid_, goopdate_dll);

-

-      // Create one mock client so that core does not try to start an

-      // uninstall worker when the unit test is manipulating the clients key.

-      // And create entries to satisfy Setup::CheckInstallStateConsistency().

-  regedit_data.Append(

-      "[HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\Clients\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT

-      "\"fc\"=\"fc /?\"\r\n"

-      "\r\n"

-      "[HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\network\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT

-      "\r\n"

-      "[HKEY_LOCAL_MACHINE\\Software\\Google\\Update]\r\n"

-      "\"path\"=\"blah\"\r\n"

-      "\r\n"

-      "[HKEY_LOCAL_MACHINE\\Software\\Google\\Update]\r\n"

-      "\"version\"=\"0.0.0.1\"\r\n"

-      "\r\n"

-      "[HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\ClientState\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT

-      "\"pv\"=\"0.0.0.1\"\r\n"

-      "\r\n");

-

-  WriteRegeditDataToRegistry(regedit_data);

-}

-

-void GoogleUpdateCoreTest::TeardownRegistry() {

-  WriteRegeditDataToRegistry(regedit_uninstall_string_);

-}

-

-HANDLE GoogleUpdateCoreTest::StartCore() {

-  CString unittest_dir = app_util::GetModuleDirectory(NULL);

-  CString google_update = ConcatenatePath(unittest_dir, kGoopdateFileName);

-  EnclosePath(&google_update);

-  HANDLE handle = NULL;

-  LaunchProcessAsSystem(google_update + _T(" /c"), &handle);

-  EXPECT_TRUE(handle != NULL);

-  if (!handle) {

-    return NULL;

-  }

-

-  // Give the core some time to start and register its shared memory section.

-  // Sometimes psexec is slow to start the machine core, so give it some

-  // time to run.

-  size_t count(0), kMaxCount(10);

-  while (count++ < kMaxCount) {

-    const TCHAR* shmem_name = kGoogleUpdateCoreSharedMemoryName;

-    scoped_file_mapping shmem_handle(::OpenFileMapping(FILE_MAP_READ,

-                                                       false,

-                                                       shmem_name));

-    if (shmem_handle) {

-      // Sleep for a short duration to allow the Core process to register the

-      // COM object in the shared memory.

-      ::Sleep(100);

-      break;

-    }

-

-    ::Sleep(1000);

-  }

-

-  return handle;

-}

-

-void GoogleUpdateCoreTest::DoLaunchCmdElevatedTests(IUnknown* core_object) {

-  CComQIPtr<IGoogleUpdateCore> google_update_core = core_object;

-  EXPECT_TRUE(google_update_core != NULL);

-  if (!google_update_core) {

-    return;

-  }

-

-  ULONG_PTR proc_handle = 0;

-  DWORD caller_proc_id = ::GetCurrentProcessId();

-

-  // Returns ERROR_BAD_IMPERSONATION_LEVEL when explicit security blanket is not

-  // set.

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_BAD_IMPERSONATION_LEVEL),

-            google_update_core->LaunchCmdElevated(kGoogleUpdateAppId,

-                                                  _T("cmd"),

-                                                  caller_proc_id,

-                                                  &proc_handle));

-  EXPECT_EQ(0, proc_handle);

-

-  // Sets a security blanket that will allow the server to impersonate the

-  // client.

-  EXPECT_SUCCEEDED(::CoSetProxyBlanket(google_update_core,

-      RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL,

-      RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL,

-      EOAC_DEFAULT));

-

-  // Returns GOOPDATE_E_CORE_MISSING_CMD when the command is missing in

-  // the registry.

-  EXPECT_EQ(GOOPDATE_E_CORE_MISSING_CMD,

-            google_update_core->LaunchCmdElevated(kGoogleUpdateAppId,

-                                                  _T("cmd"),

-                                                  caller_proc_id,

-                                                  &proc_handle));

-  EXPECT_EQ(0, proc_handle);

-

-  // Returns E_INVALIDARG when the app_guid is not a guid.

-  EXPECT_EQ(E_INVALIDARG,

-            google_update_core->LaunchCmdElevated(_T("noguid"),

-                                                  _T("cmd"),

-                                                  caller_proc_id,

-                                                  &proc_handle));

-

-  EXPECT_SUCCEEDED(google_update_core->LaunchCmdElevated(kGoogleUpdateAppId,

-                                                         _T("fc"),

-                                                         caller_proc_id,

-                                                         &proc_handle));

-  EXPECT_NE(0, proc_handle);

-

-  // TODO(Omaha): Perhaps attempt some negative tests here, either by testing

-  // the permissions on the handle explicitly, or by attempting VM operations or

-  // such on the process handle, since it's a serious security issue if the

-  // handle permissions are too wide.

-  HANDLE handle = reinterpret_cast<HANDLE>(proc_handle);

-  EXPECT_NE(WAIT_FAILED, ::WaitForSingleObject(handle, 10000));

-  EXPECT_TRUE(::CloseHandle(handle));

-}

-

-TEST_F(GoogleUpdateCoreTest, LaunchCmdElevated_CoreNotRunning) {

-  if (!vista_util::IsUserAdmin()) {

-    SUCCEED() << "\tTest did not run because the user is not an admin.";

-    return;

-  }

-

-  SharedMemoryAttributes attr(kGoogleUpdateCoreSharedMemoryName,

-                              CSecurityDesc());

-  GoogleUpdateCoreProxy google_update_core_proxy(true, &attr);

-  CComPtr<IGoogleUpdateCore> google_update_core;

-  EXPECT_FAILED(google_update_core_proxy.GetObject(&google_update_core));

-}

-

-TEST_F(GoogleUpdateCoreTest, LaunchCmdElevated) {

-  if (!vista_util::IsUserAdmin()) {

-    SUCCEED() << "\tTest did not run because the user is not an admin.";

-    return;

-  }

-

-  // Start the machine instance of the core.

-  StartCore();

-

-  // Get the proxy for the core interface.

-  SharedMemoryAttributes attr(kGoogleUpdateCoreSharedMemoryName,

-                              CSecurityDesc());

-  GoogleUpdateCoreProxy google_update_core_proxy(true, &attr);

-  CComPtr<IGoogleUpdateCore> google_update_core;

-

-  EXPECT_SUCCEEDED(google_update_core_proxy.GetObject(&google_update_core));

-  EXPECT_TRUE(google_update_core != NULL);

-

-  DoLaunchCmdElevatedTests(google_update_core);

-}

-

-TEST_F(GoogleUpdateCoreTest, GetCommandToLaunch) {

-  if (!vista_util::IsUserAdmin()) {

-    SUCCEED() << "\tTest did not run because the user is not an admin.";

-    return;

-  }

-  EXPECT_STREQ(_T(""), GetCommandToLaunch(NULL, _T("foo")));

-  EXPECT_STREQ(_T(""), GetCommandToLaunch(_T("bar"), NULL));

-

-  CString cmd = GetCommandToLaunch(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-                                   _T("cmd"));

-  EXPECT_STREQ(_T(""), cmd);

-

-  const TCHAR* key_name = _T("HKLM\\Software\\Google\\Update\\Clients\\")

-                          _T("{430FD4D0-B729-4F61-AA34-91526481799D}");

-  EXPECT_SUCCEEDED(RegKey::SetValue(key_name, _T("cmd"), _T("foobar")));

-

-  cmd = GetCommandToLaunch(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-                           _T("cmd"));

-  EXPECT_STREQ(_T("foobar"), cmd);

-}

-

-TEST_F(GoogleUpdateCoreTest, LaunchCmd) {

-  if (!vista_util::IsUserAdmin()) {

-    SUCCEED() << "\tTest did not run because the user is not an admin.";

-    return;

-  }

-  ULONG_PTR proc_handle = 0;

-  scoped_process caller_proc_handle(::OpenProcess(PROCESS_DUP_HANDLE,

-                                                  false,

-                                                  ::GetCurrentProcessId()));

-  EXPECT_TRUE(caller_proc_handle);

-

-  CString cmd = _T("cmd /c \"dir > nul\"");

-  EXPECT_SUCCEEDED(LaunchCmd(&cmd, get(caller_proc_handle), &proc_handle));

-

-  EXPECT_NE(0, proc_handle);

-

-  HANDLE handle = reinterpret_cast<HANDLE>(proc_handle);

-  EXPECT_NE(WAIT_FAILED, ::WaitForSingleObject(handle, 10000));

-  EXPECT_TRUE(::CloseHandle(handle));

-}

-

-class GoogleUpdateCoreServiceTest : public GoogleUpdateCoreTest {

- protected:

-  virtual void SetUp() {

-    SetupRegistry();

-    RegisterOrUnregisterService(true);

-  }

-

-  virtual void TearDown() {

-    RegisterOrUnregisterService(false);

-    TeardownRegistry();

-  }

-

-  void RegisterOrUnregisterService(bool reg);

-};

-

-void GoogleUpdateCoreServiceTest::RegisterOrUnregisterService(bool reg) {

-  CString unittest_dir = app_util::GetModuleDirectory(NULL);

-  CString service_path = ConcatenatePath(unittest_dir, kServiceFileName);

-  EnclosePath(&service_path);

-

-  CommandLineBuilder builder(reg ? COMMANDLINE_MODE_SERVICE_REGISTER :

-                                   COMMANDLINE_MODE_SERVICE_UNREGISTER);

-  CString cmd_line = builder.GetCommandLineArgs();

-  if (vista_util::IsUserAdmin()) {

-    EXPECT_SUCCEEDED(RegisterOrUnregisterExe(service_path, cmd_line));

-    return;

-  }

-

-  // Elevate for medium integrity users on Vista and above.

-  DWORD exit_code(S_OK);

-  EXPECT_SUCCEEDED(vista_util::RunElevated(service_path,

-                                           cmd_line,

-                                           SW_SHOWNORMAL,

-                                           &exit_code));

-  EXPECT_SUCCEEDED(exit_code);

-}

-

-TEST_F(GoogleUpdateCoreServiceTest, LaunchCmdElevated_ServiceNotRunning) {

-  CComPtr<IUnknown> service_com;

-  EXPECT_SUCCEEDED(

-      service_com.CoCreateInstance(__uuidof(GoogleUpdateCoreClass)));

-

-  DoLaunchCmdElevatedTests(service_com);

-

-  service_com.Release();

-}

-

-TEST_F(GoogleUpdateCoreServiceTest, LaunchCmdElevated_ServiceRunning) {

-  if (!vista_util::IsUserAdmin()) {

-    SUCCEED() << "\tTest did not run because the user is not an admin.";

-    return;

-  }

-  EXPECT_SUCCEEDED(SetupService::StartService());

-  CComPtr<IUnknown> service_com;

-  EXPECT_SUCCEEDED(

-      service_com.CoCreateInstance(__uuidof(GoogleUpdateCoreClass)));

-

-  DoLaunchCmdElevatedTests(service_com);

-

-  service_com.Release();

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/error.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/system.h"
+#include "omaha/common/vistautil.h"
+
+#include "omaha/core/google_update_core.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/google_update_proxy.h"
+#include "omaha/setup/setup_service.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class GoogleUpdateCoreTest : public testing::Test {
+ protected:
+  GoogleUpdateCoreTest() {
+    GUID proxy_clsid = PROXY_CLSID_IS;
+    proxy_guid_ = CW2A(GuidToString(proxy_clsid));
+
+    regedit_uninstall_string_.Format(
+        "Windows Registry Editor Version 5.00\r\n"
+        "\r\n"
+        "[-HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\Clients\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT
+        "\r\n"
+        "[-HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\ClientState\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT
+        "\r\n"
+        "[-HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\network\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT
+        "\r\n"
+        "[-HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Interface\\{909489C2-85A6-4322-AA56-D25278649D67}]\r\n"  // NOLINT
+        "\r\n"
+        "[-HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\%s]\r\n"
+        "\r\n"
+
+        // Registration for the user must be cleared too since COM looks up HKCR
+        // and that resolves to either HKCU or HKLM classes.
+        "[-HKEY_CURRENT_USER\\SOFTWARE\\Classes\\Interface\\{909489C2-85A6-4322-AA56-D25278649D67}]\r\n"  // NOLINT
+        "\r\n"
+        "[-HKEY_CURRENT_USER\\SOFTWARE\\Classes\\CLSID\\%s]\r\n"
+        "\r\n",
+        proxy_guid_, proxy_guid_);
+  }
+
+  virtual void SetUp() {
+    if (!vista_util::IsUserAdmin()) {
+      return;
+    }
+    System::AdjustPrivilege(SE_DEBUG_NAME, true);
+    TerminateAllGoogleUpdateProcesses();
+    SetupRegistry();
+  }
+
+  virtual void TearDown() {
+    if (!vista_util::IsUserAdmin()) {
+      return;
+    }
+    TerminateAllGoogleUpdateProcesses();
+    TeardownRegistry();
+  }
+
+  CString GetCommandToLaunch(const TCHAR* app_guid, const TCHAR* cmd_id) {
+    return GoogleUpdateCore::GetCommandToLaunch(app_guid, cmd_id);
+  }
+
+  HRESULT LaunchCmd(CString* cmd,
+                    HANDLE caller_proc_handle,
+                    ULONG_PTR* proc_handle) {
+    return GoogleUpdateCore::LaunchCmd(cmd, caller_proc_handle, proc_handle);
+  }
+
+  // Starts the core and waits for it to register its shared memory section.
+  HANDLE StartCore();
+
+  // Creates the COM registration required by the test.
+  void SetupRegistry();
+
+  // Cleans up the COM registration.
+  void TeardownRegistry();
+
+  void DoLaunchCmdElevatedTests(IUnknown* core_object);
+
+  // The guid of the proxy code. This is a build constant.
+  CStringA proxy_guid_;
+
+  CStringA regedit_uninstall_string_;
+};
+
+void WriteRegeditDataToRegistry(const CStringA& regedit_data) {
+  EXPECT_TRUE(regedit_data.GetLength());
+
+  CString temp_file;
+  EXPECT_TRUE(::GetTempFileName(app_util::GetModuleDirectory(NULL),
+                                _T("reg"),
+                                0,
+                                CStrBuf(temp_file, MAX_PATH)));
+
+  CString reg_file_path = temp_file + _T(".reg");
+  scoped_hfile file_handle(::CreateFile(reg_file_path,
+                                        GENERIC_WRITE,
+                                        FILE_SHARE_READ,
+                                        NULL,
+                                        CREATE_ALWAYS,
+                                        FILE_ATTRIBUTE_NORMAL,
+                                        NULL));
+  EXPECT_TRUE(file_handle);
+  DWORD bytes_written = 0;
+  EXPECT_TRUE(::WriteFile(get(file_handle),
+                          regedit_data,
+                          regedit_data.GetLength(),
+                          &bytes_written,
+                          NULL));
+  EXPECT_TRUE(bytes_written);
+  reset(file_handle);
+
+  CString regedit_path(_T("regedit.exe"));
+  CString cmd_line;
+  cmd_line.Format(_T("/s \"%s\""), reg_file_path);
+
+  if (vista_util::IsUserAdmin()) {
+    EXPECT_SUCCEEDED(RegisterOrUnregisterExe(regedit_path, cmd_line));
+  } else {
+    // Elevate RegEdit.exe for medium integrity users on Vista and above.
+    DWORD exit_code(0);
+    EXPECT_SUCCEEDED(vista_util::RunElevated(regedit_path,
+                                             cmd_line,
+                                             SW_SHOWNORMAL,
+                                             &exit_code));
+    EXPECT_EQ(0, exit_code);
+  }
+
+  EXPECT_TRUE(::DeleteFile(temp_file));
+  EXPECT_TRUE(::DeleteFile(reg_file_path));
+}
+
+void GoogleUpdateCoreTest::SetupRegistry() {
+  CStringA regedit_data(regedit_uninstall_string_);
+
+  CString unittest_dir = app_util::GetModuleDirectory(NULL);
+  CStringA goopdate_dll(CW2A(ConcatenatePath(unittest_dir, kGoopdateDllName)));
+  goopdate_dll.Replace("\\", "\\\\");
+
+  regedit_data.AppendFormat(
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Interface\\{909489C2-85A6-4322-AA56-D25278649D67}]\r\n"  // NOLINT
+      "@=\"IGoogleUpdateCore\"\r\n"
+      "\r\n"
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Interface\\{909489C2-85A6-4322-AA56-D25278649D67}\\NumMethods]\r\n"  // NOLINT
+      "@=\"%d\"\r\n"
+      "\r\n"
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\Interface\\{909489C2-85A6-4322-AA56-D25278649D67}\\ProxyStubClsid32]\r\n"  // NOLINT
+      "@=\"%s\"\r\n"
+      "\r\n"
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\%s]\r\n"
+      "@=\"PSFactoryBuffer\"\r\n"
+      "\r\n"
+      "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\CLSID\\%s\\InProcServer32]\r\n"
+      "@=\"%s\"\r\n"
+      "\"ThreadingModel\"=\"Both\"\r\n"
+      "\r\n",
+      4, proxy_guid_, proxy_guid_, proxy_guid_, goopdate_dll);
+
+      // Create one mock client so that core does not try to start an
+      // uninstall worker when the unit test is manipulating the clients key.
+      // And create entries to satisfy Setup::CheckInstallStateConsistency().
+  regedit_data.Append(
+      "[HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\Clients\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT
+      "\"fc\"=\"fc /?\"\r\n"
+      "\r\n"
+      "[HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\network\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT
+      "\r\n"
+      "[HKEY_LOCAL_MACHINE\\Software\\Google\\Update]\r\n"
+      "\"path\"=\"blah\"\r\n"
+      "\r\n"
+      "[HKEY_LOCAL_MACHINE\\Software\\Google\\Update]\r\n"
+      "\"version\"=\"0.0.0.1\"\r\n"
+      "\r\n"
+      "[HKEY_LOCAL_MACHINE\\Software\\Google\\Update\\ClientState\\{430FD4D0-B729-4F61-AA34-91526481799D}]\r\n"  // NOLINT
+      "\"pv\"=\"0.0.0.1\"\r\n"
+      "\r\n");
+
+  WriteRegeditDataToRegistry(regedit_data);
+}
+
+void GoogleUpdateCoreTest::TeardownRegistry() {
+  WriteRegeditDataToRegistry(regedit_uninstall_string_);
+}
+
+HANDLE GoogleUpdateCoreTest::StartCore() {
+  CString unittest_dir = app_util::GetModuleDirectory(NULL);
+  CString google_update = ConcatenatePath(unittest_dir, kGoopdateFileName);
+  EnclosePath(&google_update);
+  HANDLE handle = NULL;
+  LaunchProcessAsSystem(google_update + _T(" /c"), &handle);
+  EXPECT_TRUE(handle != NULL);
+  if (!handle) {
+    return NULL;
+  }
+
+  // Give the core some time to start and register its shared memory section.
+  // Sometimes psexec is slow to start the machine core, so give it some
+  // time to run.
+  size_t count(0), kMaxCount(10);
+  while (count++ < kMaxCount) {
+    const TCHAR* shmem_name = kGoogleUpdateCoreSharedMemoryName;
+    scoped_file_mapping shmem_handle(::OpenFileMapping(FILE_MAP_READ,
+                                                       false,
+                                                       shmem_name));
+    if (shmem_handle) {
+      // Sleep for a short duration to allow the Core process to register the
+      // COM object in the shared memory.
+      ::Sleep(100);
+      break;
+    }
+
+    ::Sleep(1000);
+  }
+
+  return handle;
+}
+
+void GoogleUpdateCoreTest::DoLaunchCmdElevatedTests(IUnknown* core_object) {
+  CComQIPtr<IGoogleUpdateCore> google_update_core = core_object;
+  EXPECT_TRUE(google_update_core != NULL);
+  if (!google_update_core) {
+    return;
+  }
+
+  ULONG_PTR proc_handle = 0;
+  DWORD caller_proc_id = ::GetCurrentProcessId();
+
+  // Returns ERROR_BAD_IMPERSONATION_LEVEL when explicit security blanket is not
+  // set.
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_BAD_IMPERSONATION_LEVEL),
+            google_update_core->LaunchCmdElevated(kGoogleUpdateAppId,
+                                                  _T("cmd"),
+                                                  caller_proc_id,
+                                                  &proc_handle));
+  EXPECT_EQ(0, proc_handle);
+
+  // Sets a security blanket that will allow the server to impersonate the
+  // client.
+  EXPECT_SUCCEEDED(::CoSetProxyBlanket(google_update_core,
+      RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL,
+      RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL,
+      EOAC_DEFAULT));
+
+  // Returns GOOPDATE_E_CORE_MISSING_CMD when the command is missing in
+  // the registry.
+  EXPECT_EQ(GOOPDATE_E_CORE_MISSING_CMD,
+            google_update_core->LaunchCmdElevated(kGoogleUpdateAppId,
+                                                  _T("cmd"),
+                                                  caller_proc_id,
+                                                  &proc_handle));
+  EXPECT_EQ(0, proc_handle);
+
+  // Returns E_INVALIDARG when the app_guid is not a guid.
+  EXPECT_EQ(E_INVALIDARG,
+            google_update_core->LaunchCmdElevated(_T("noguid"),
+                                                  _T("cmd"),
+                                                  caller_proc_id,
+                                                  &proc_handle));
+
+  EXPECT_SUCCEEDED(google_update_core->LaunchCmdElevated(kGoogleUpdateAppId,
+                                                         _T("fc"),
+                                                         caller_proc_id,
+                                                         &proc_handle));
+  EXPECT_NE(0, proc_handle);
+
+  // TODO(Omaha): Perhaps attempt some negative tests here, either by testing
+  // the permissions on the handle explicitly, or by attempting VM operations or
+  // such on the process handle, since it's a serious security issue if the
+  // handle permissions are too wide.
+  HANDLE handle = reinterpret_cast<HANDLE>(proc_handle);
+  EXPECT_NE(WAIT_FAILED, ::WaitForSingleObject(handle, 10000));
+  EXPECT_TRUE(::CloseHandle(handle));
+}
+
+TEST_F(GoogleUpdateCoreTest, LaunchCmdElevated_CoreNotRunning) {
+  if (!vista_util::IsUserAdmin()) {
+    SUCCEED() << "\tTest did not run because the user is not an admin.";
+    return;
+  }
+
+  SharedMemoryAttributes attr(kGoogleUpdateCoreSharedMemoryName,
+                              CSecurityDesc());
+  GoogleUpdateCoreProxy google_update_core_proxy(true, &attr);
+  CComPtr<IGoogleUpdateCore> google_update_core;
+  EXPECT_FAILED(google_update_core_proxy.GetObject(&google_update_core));
+}
+
+TEST_F(GoogleUpdateCoreTest, LaunchCmdElevated) {
+  if (!vista_util::IsUserAdmin()) {
+    SUCCEED() << "\tTest did not run because the user is not an admin.";
+    return;
+  }
+
+  // Start the machine instance of the core.
+  StartCore();
+
+  // Get the proxy for the core interface.
+  SharedMemoryAttributes attr(kGoogleUpdateCoreSharedMemoryName,
+                              CSecurityDesc());
+  GoogleUpdateCoreProxy google_update_core_proxy(true, &attr);
+  CComPtr<IGoogleUpdateCore> google_update_core;
+
+  EXPECT_SUCCEEDED(google_update_core_proxy.GetObject(&google_update_core));
+  EXPECT_TRUE(google_update_core != NULL);
+
+  DoLaunchCmdElevatedTests(google_update_core);
+}
+
+TEST_F(GoogleUpdateCoreTest, GetCommandToLaunch) {
+  if (!vista_util::IsUserAdmin()) {
+    SUCCEED() << "\tTest did not run because the user is not an admin.";
+    return;
+  }
+  EXPECT_STREQ(_T(""), GetCommandToLaunch(NULL, _T("foo")));
+  EXPECT_STREQ(_T(""), GetCommandToLaunch(_T("bar"), NULL));
+
+  CString cmd = GetCommandToLaunch(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+                                   _T("cmd"));
+  EXPECT_STREQ(_T(""), cmd);
+
+  const TCHAR* key_name = _T("HKLM\\Software\\Google\\Update\\Clients\\")
+                          _T("{430FD4D0-B729-4F61-AA34-91526481799D}");
+  EXPECT_SUCCEEDED(RegKey::SetValue(key_name, _T("cmd"), _T("foobar")));
+
+  cmd = GetCommandToLaunch(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+                           _T("cmd"));
+  EXPECT_STREQ(_T("foobar"), cmd);
+}
+
+TEST_F(GoogleUpdateCoreTest, LaunchCmd) {
+  if (!vista_util::IsUserAdmin()) {
+    SUCCEED() << "\tTest did not run because the user is not an admin.";
+    return;
+  }
+  ULONG_PTR proc_handle = 0;
+  scoped_process caller_proc_handle(::OpenProcess(PROCESS_DUP_HANDLE,
+                                                  false,
+                                                  ::GetCurrentProcessId()));
+  EXPECT_TRUE(caller_proc_handle);
+
+  CString cmd = _T("cmd /c \"dir > nul\"");
+  EXPECT_SUCCEEDED(LaunchCmd(&cmd, get(caller_proc_handle), &proc_handle));
+
+  EXPECT_NE(0, proc_handle);
+
+  HANDLE handle = reinterpret_cast<HANDLE>(proc_handle);
+  EXPECT_NE(WAIT_FAILED, ::WaitForSingleObject(handle, 10000));
+  EXPECT_TRUE(::CloseHandle(handle));
+}
+
+class GoogleUpdateCoreServiceTest : public GoogleUpdateCoreTest {
+ protected:
+  virtual void SetUp() {
+    SetupRegistry();
+    RegisterOrUnregisterService(true);
+  }
+
+  virtual void TearDown() {
+    RegisterOrUnregisterService(false);
+    TeardownRegistry();
+  }
+
+  void RegisterOrUnregisterService(bool reg);
+};
+
+void GoogleUpdateCoreServiceTest::RegisterOrUnregisterService(bool reg) {
+  CString unittest_dir = app_util::GetModuleDirectory(NULL);
+  CString service_path = ConcatenatePath(unittest_dir, kServiceFileName);
+  EnclosePath(&service_path);
+
+  CommandLineBuilder builder(reg ? COMMANDLINE_MODE_SERVICE_REGISTER :
+                                   COMMANDLINE_MODE_SERVICE_UNREGISTER);
+  CString cmd_line = builder.GetCommandLineArgs();
+  if (vista_util::IsUserAdmin()) {
+    EXPECT_SUCCEEDED(RegisterOrUnregisterExe(service_path, cmd_line));
+    return;
+  }
+
+  // Elevate for medium integrity users on Vista and above.
+  DWORD exit_code(S_OK);
+  EXPECT_SUCCEEDED(vista_util::RunElevated(service_path,
+                                           cmd_line,
+                                           SW_SHOWNORMAL,
+                                           &exit_code));
+  EXPECT_SUCCEEDED(exit_code);
+}
+
+TEST_F(GoogleUpdateCoreServiceTest, LaunchCmdElevated_ServiceNotRunning) {
+  CComPtr<IUnknown> service_com;
+  EXPECT_SUCCEEDED(
+      service_com.CoCreateInstance(__uuidof(GoogleUpdateCoreClass)));
+
+  DoLaunchCmdElevatedTests(service_com);
+
+  service_com.Release();
+}
+
+TEST_F(GoogleUpdateCoreServiceTest, LaunchCmdElevated_ServiceRunning) {
+  if (!vista_util::IsUserAdmin()) {
+    SUCCEED() << "\tTest did not run because the user is not an admin.";
+    return;
+  }
+  EXPECT_SUCCEEDED(SetupService::StartService());
+  CComPtr<IUnknown> service_com;
+  EXPECT_SUCCEEDED(
+      service_com.CoCreateInstance(__uuidof(GoogleUpdateCoreClass)));
+
+  DoLaunchCmdElevatedTests(service_com);
+
+  service_com.Release();
+}
+
+}  // namespace omaha
+
diff --git a/core/legacy_manifest_handler.cc b/core/legacy_manifest_handler.cc
index be7f5bb..fd8371f 100644
--- a/core/legacy_manifest_handler.cc
+++ b/core/legacy_manifest_handler.cc
@@ -1,92 +1,92 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/core/legacy_manifest_handler.h"

-

-#include <atlsecurity.h>

-#include <atlstr.h>

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reactor.h"

-#include "omaha/core/core.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-

-namespace omaha {

-

-LegacyManifestHandler::LegacyManifestHandler()

-    : core_(NULL),

-      reactor_(NULL) {

-  CORE_LOG(L3, (_T("[LegacyManifestHandler::LegacyManifestHandler]")));

-}

-

-LegacyManifestHandler::~LegacyManifestHandler() {

-  CORE_LOG(L3, (_T("[LegacyManifestHandler::~LegacyManifestHandler]")));

-  ASSERT1(reactor_);

-  ASSERT1(dir_watcher_.get());

-  VERIFY1(SUCCEEDED(reactor_->UnregisterHandle(dir_watcher_->change_event())));

-}

-

-HRESULT LegacyManifestHandler::Initialize(Core* core) {

-  CORE_LOG(L3, (_T("[LegacyManifestHandler::Initialize]")));

-  ASSERT1(core);

-  ASSERT1(!core->is_system());

-  core_ = core;

-

-  reactor_ = core_->reactor();

-  ASSERT1(reactor_);

-

-  CString dir = ConfigManager::Instance()->GetUserInitialManifestStorageDir();

-  dir_watcher_.reset(new FileWatcher(dir,

-                                     false,

-                                     FILE_NOTIFY_CHANGE_FILE_NAME));

-  ASSERT1(dir_watcher_.get());

-  HRESULT hr = dir_watcher_->EnsureEventSetup();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = reactor_->RegisterHandle(dir_watcher_->change_event(), this, 0);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return S_OK;

-}

-

-void LegacyManifestHandler::HandleEvent(HANDLE handle) {

-  UNREFERENCED_PARAMETER(handle);

-  ASSERT1(handle == dir_watcher_->change_event());

-  CORE_LOG(L1, (_T("[Got an omaha1 manifest handoff event.]")));

-

-  // Set up the watcher again.

-  ASSERT1(dir_watcher_.get());

-  HRESULT hr = dir_watcher_->EnsureEventSetup();

-  if (FAILED(hr)) {

-    // Ignore the error and handle the current event.

-    // It is possible to not be able to register the file watcher in case

-    // omaha is being uninstalled.

-    CORE_LOG(L1, (_T("Could not recreate the file watcher")));

-  }

-  VERIFY1(SUCCEEDED(reactor_->RegisterHandle(dir_watcher_->change_event())));

-

-  ASSERT1(core_);

-  core_->StartInstallWorker();

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/core/legacy_manifest_handler.h"
+
+#include <atlsecurity.h>
+#include <atlstr.h>
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reactor.h"
+#include "omaha/core/core.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+
+namespace omaha {
+
+LegacyManifestHandler::LegacyManifestHandler()
+    : core_(NULL),
+      reactor_(NULL) {
+  CORE_LOG(L3, (_T("[LegacyManifestHandler::LegacyManifestHandler]")));
+}
+
+LegacyManifestHandler::~LegacyManifestHandler() {
+  CORE_LOG(L3, (_T("[LegacyManifestHandler::~LegacyManifestHandler]")));
+  ASSERT1(reactor_);
+  ASSERT1(dir_watcher_.get());
+  VERIFY1(SUCCEEDED(reactor_->UnregisterHandle(dir_watcher_->change_event())));
+}
+
+HRESULT LegacyManifestHandler::Initialize(Core* core) {
+  CORE_LOG(L3, (_T("[LegacyManifestHandler::Initialize]")));
+  ASSERT1(core);
+  ASSERT1(!core->is_system());
+  core_ = core;
+
+  reactor_ = core_->reactor();
+  ASSERT1(reactor_);
+
+  CString dir = ConfigManager::Instance()->GetUserInitialManifestStorageDir();
+  dir_watcher_.reset(new FileWatcher(dir,
+                                     false,
+                                     FILE_NOTIFY_CHANGE_FILE_NAME));
+  ASSERT1(dir_watcher_.get());
+  HRESULT hr = dir_watcher_->EnsureEventSetup();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = reactor_->RegisterHandle(dir_watcher_->change_event(), this, 0);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return S_OK;
+}
+
+void LegacyManifestHandler::HandleEvent(HANDLE handle) {
+  UNREFERENCED_PARAMETER(handle);
+  ASSERT1(handle == dir_watcher_->change_event());
+  CORE_LOG(L1, (_T("[Got an omaha1 manifest handoff event.]")));
+
+  // Set up the watcher again.
+  ASSERT1(dir_watcher_.get());
+  HRESULT hr = dir_watcher_->EnsureEventSetup();
+  if (FAILED(hr)) {
+    // Ignore the error and handle the current event.
+    // It is possible to not be able to register the file watcher in case
+    // omaha is being uninstalled.
+    CORE_LOG(L1, (_T("Could not recreate the file watcher")));
+  }
+  VERIFY1(SUCCEEDED(reactor_->RegisterHandle(dir_watcher_->change_event())));
+
+  ASSERT1(core_);
+  core_->StartInstallWorker();
+}
+
+}  // namespace omaha
+
diff --git a/core/legacy_manifest_handler.h b/core/legacy_manifest_handler.h
index 1085ae8..a387dd3 100644
--- a/core/legacy_manifest_handler.h
+++ b/core/legacy_manifest_handler.h
@@ -1,53 +1,53 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// LegacyManifestHandler monitors the user manifest directory for manifest

-// files that are copied there by omaha1.

-

-#ifndef OMAHA_CORE_LEGACY_MANIFEST_HANDLER_H__

-#define OMAHA_CORE_LEGACY_MANIFEST_HANDLER_H__

-

-#include <windows.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/event_handler.h"

-#include "omaha/common/file.h"

-

-namespace omaha {

-

-class Reactor;

-class Core;

-

-class LegacyManifestHandler : public EventHandler {

- public:

-  LegacyManifestHandler();

-  ~LegacyManifestHandler();

-

-  HRESULT Initialize(Core* core);

-

-  virtual void HandleEvent(HANDLE handle);

-

- private:

-  scoped_ptr<FileWatcher> dir_watcher_;

-  Reactor* reactor_;

-  Core* core_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(LegacyManifestHandler);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_CORE_LEGACY_MANIFEST_HANDLER_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// LegacyManifestHandler monitors the user manifest directory for manifest
+// files that are copied there by omaha1.
+
+#ifndef OMAHA_CORE_LEGACY_MANIFEST_HANDLER_H__
+#define OMAHA_CORE_LEGACY_MANIFEST_HANDLER_H__
+
+#include <windows.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/event_handler.h"
+#include "omaha/common/file.h"
+
+namespace omaha {
+
+class Reactor;
+class Core;
+
+class LegacyManifestHandler : public EventHandler {
+ public:
+  LegacyManifestHandler();
+  ~LegacyManifestHandler();
+
+  HRESULT Initialize(Core* core);
+
+  virtual void HandleEvent(HANDLE handle);
+
+ private:
+  scoped_ptr<FileWatcher> dir_watcher_;
+  Reactor* reactor_;
+  Core* core_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(LegacyManifestHandler);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_CORE_LEGACY_MANIFEST_HANDLER_H__
+
diff --git a/core/scheduler.cc b/core/scheduler.cc
index 3930ef9..8394072 100644
--- a/core/scheduler.cc
+++ b/core/scheduler.cc
@@ -1,129 +1,129 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/core/scheduler.h"

-#include <algorithm>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/highres_timer-win32.h"

-#include "omaha/common/queue_timer.h"

-#include "omaha/core/core.h"

-#include "omaha/core/core_metrics.h"

-#include "omaha/goopdate/config_manager.h"

-

-namespace omaha {

-

-Scheduler::Scheduler(const Core& core)

-    : core_(core) {

-  CORE_LOG(L1, (_T("[Scheduler::Scheduler]")));

-}

-

-Scheduler::~Scheduler() {

-  CORE_LOG(L1, (_T("[Scheduler::~Scheduler]")));

-

-  if (update_timer_.get()) {

-    update_timer_.reset(NULL);

-  }

-

-  if (code_red_timer_.get()) {

-    code_red_timer_.reset(NULL);

-  }

-

-  if (timer_queue_) {

-    // The destructor blocks on deleting the timer queue and it waits for

-    // all timer callbacks to complete.

-    ::DeleteTimerQueueEx(timer_queue_, INVALID_HANDLE_VALUE);

-  }

-}

-

-HRESULT Scheduler::Initialize() {

-  CORE_LOG(L1, (_T("[Scheduler::Initialize]")));

-

-  timer_queue_ = ::CreateTimerQueue();

-  if (!timer_queue_) {

-    return HRESULTFromLastError();

-  }

-

-  cr_debug_timer_.reset(new HighresTimer);

-

-  update_timer_.reset(new QueueTimer(timer_queue_,

-                                     &Scheduler::TimerCallback,

-                                     this));

-  code_red_timer_.reset(new QueueTimer(timer_queue_,

-                                       &Scheduler::TimerCallback,

-                                       this));

-

-  ConfigManager* config_manager = ConfigManager::Instance();

-  int cr_timer_interval_ms = config_manager->GetCodeRedTimerIntervalMs();

-  VERIFY1(SUCCEEDED(ScheduleCodeRedTimer(cr_timer_interval_ms)));

-

-  int au_timer_interval_ms = config_manager->GetUpdateWorkerStartUpDelayMs();

-  VERIFY1(SUCCEEDED(ScheduleUpdateTimer(au_timer_interval_ms)));

-

-  return S_OK;

-}

-

-void Scheduler::TimerCallback(QueueTimer* timer) {

-  ASSERT1(timer);

-  Scheduler* scheduler = static_cast<Scheduler*>(timer->ctx());

-  ASSERT1(scheduler);

-  scheduler->HandleCallback(timer);

-}

-

-// First, do the useful work and then reschedule the timer. Otherwise, it is

-// possible that timer notifications overlap, and the timer can't be further

-// rescheduled: http://b/1228095

-void Scheduler::HandleCallback(QueueTimer* timer) {

-  ConfigManager* config_manager = ConfigManager::Instance();

-  if (update_timer_.get() == timer) {

-    core_.StartUpdateWorker();

-    int au_timer_interval_ms = config_manager->GetAutoUpdateTimerIntervalMs();

-    VERIFY1(SUCCEEDED(ScheduleUpdateTimer(au_timer_interval_ms)));

-  } else if (code_red_timer_.get() == timer) {

-    core_.StartCodeRed();

-    int actual_time_ms = static_cast<int>(cr_debug_timer_->GetElapsedMs());

-    metric_core_cr_actual_timer_interval_ms = actual_time_ms;

-    CORE_LOG(L3, (_T("[code red actual period][%d ms]"), actual_time_ms));

-    int cr_timer_interval_ms = config_manager->GetCodeRedTimerIntervalMs();

-    VERIFY1(SUCCEEDED(ScheduleCodeRedTimer(cr_timer_interval_ms)));

-  } else {

-    ASSERT1(false);

-  }

-

-  // Since core is a long lived process, aggregate its metrics once in a while.

-  core_.AggregateMetrics();

-}

-

-HRESULT Scheduler::ScheduleUpdateTimer(int interval_ms) {

-  HRESULT hr = update_timer_->Start(interval_ms, 0, WT_EXECUTEONLYONCE);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[can't start update queue timer][0x%08x]"), hr));

-  }

-  return hr;

-}

-

-HRESULT Scheduler::ScheduleCodeRedTimer(int interval_ms) {

-  metric_core_cr_expected_timer_interval_ms = interval_ms;

-  cr_debug_timer_->Start();

-  HRESULT hr = code_red_timer_->Start(interval_ms, 0, WT_EXECUTEONLYONCE);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[can't start Code Red queue timer][0x%08x]"), hr));

-  }

-  return hr;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/core/scheduler.h"
+#include <algorithm>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/highres_timer-win32.h"
+#include "omaha/common/queue_timer.h"
+#include "omaha/core/core.h"
+#include "omaha/core/core_metrics.h"
+#include "omaha/goopdate/config_manager.h"
+
+namespace omaha {
+
+Scheduler::Scheduler(const Core& core)
+    : core_(core) {
+  CORE_LOG(L1, (_T("[Scheduler::Scheduler]")));
+}
+
+Scheduler::~Scheduler() {
+  CORE_LOG(L1, (_T("[Scheduler::~Scheduler]")));
+
+  if (update_timer_.get()) {
+    update_timer_.reset(NULL);
+  }
+
+  if (code_red_timer_.get()) {
+    code_red_timer_.reset(NULL);
+  }
+
+  if (timer_queue_) {
+    // The destructor blocks on deleting the timer queue and it waits for
+    // all timer callbacks to complete.
+    ::DeleteTimerQueueEx(timer_queue_, INVALID_HANDLE_VALUE);
+  }
+}
+
+HRESULT Scheduler::Initialize() {
+  CORE_LOG(L1, (_T("[Scheduler::Initialize]")));
+
+  timer_queue_ = ::CreateTimerQueue();
+  if (!timer_queue_) {
+    return HRESULTFromLastError();
+  }
+
+  cr_debug_timer_.reset(new HighresTimer);
+
+  update_timer_.reset(new QueueTimer(timer_queue_,
+                                     &Scheduler::TimerCallback,
+                                     this));
+  code_red_timer_.reset(new QueueTimer(timer_queue_,
+                                       &Scheduler::TimerCallback,
+                                       this));
+
+  ConfigManager* config_manager = ConfigManager::Instance();
+  int cr_timer_interval_ms = config_manager->GetCodeRedTimerIntervalMs();
+  VERIFY1(SUCCEEDED(ScheduleCodeRedTimer(cr_timer_interval_ms)));
+
+  int au_timer_interval_ms = config_manager->GetUpdateWorkerStartUpDelayMs();
+  VERIFY1(SUCCEEDED(ScheduleUpdateTimer(au_timer_interval_ms)));
+
+  return S_OK;
+}
+
+void Scheduler::TimerCallback(QueueTimer* timer) {
+  ASSERT1(timer);
+  Scheduler* scheduler = static_cast<Scheduler*>(timer->ctx());
+  ASSERT1(scheduler);
+  scheduler->HandleCallback(timer);
+}
+
+// First, do the useful work and then reschedule the timer. Otherwise, it is
+// possible that timer notifications overlap, and the timer can't be further
+// rescheduled: http://b/1228095
+void Scheduler::HandleCallback(QueueTimer* timer) {
+  ConfigManager* config_manager = ConfigManager::Instance();
+  if (update_timer_.get() == timer) {
+    core_.StartUpdateWorker();
+    int au_timer_interval_ms = config_manager->GetAutoUpdateTimerIntervalMs();
+    VERIFY1(SUCCEEDED(ScheduleUpdateTimer(au_timer_interval_ms)));
+  } else if (code_red_timer_.get() == timer) {
+    core_.StartCodeRed();
+    int actual_time_ms = static_cast<int>(cr_debug_timer_->GetElapsedMs());
+    metric_core_cr_actual_timer_interval_ms = actual_time_ms;
+    CORE_LOG(L3, (_T("[code red actual period][%d ms]"), actual_time_ms));
+    int cr_timer_interval_ms = config_manager->GetCodeRedTimerIntervalMs();
+    VERIFY1(SUCCEEDED(ScheduleCodeRedTimer(cr_timer_interval_ms)));
+  } else {
+    ASSERT1(false);
+  }
+
+  // Since core is a long lived process, aggregate its metrics once in a while.
+  core_.AggregateMetrics();
+}
+
+HRESULT Scheduler::ScheduleUpdateTimer(int interval_ms) {
+  HRESULT hr = update_timer_->Start(interval_ms, 0, WT_EXECUTEONLYONCE);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[can't start update queue timer][0x%08x]"), hr));
+  }
+  return hr;
+}
+
+HRESULT Scheduler::ScheduleCodeRedTimer(int interval_ms) {
+  metric_core_cr_expected_timer_interval_ms = interval_ms;
+  cr_debug_timer_->Start();
+  HRESULT hr = code_red_timer_->Start(interval_ms, 0, WT_EXECUTEONLYONCE);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[can't start Code Red queue timer][0x%08x]"), hr));
+  }
+  return hr;
+}
+
+}  // namespace omaha
+
diff --git a/core/scheduler.h b/core/scheduler.h
index 6f1514b..88ea5c8 100644
--- a/core/scheduler.h
+++ b/core/scheduler.h
@@ -1,63 +1,63 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// TODO(omaha): consider using a waitable timer registered with the reactor. It

-// seems a lot less code than using the QueueTimer class.

-

-#ifndef OMAHA_CORE_SCHEDULER_H__

-#define OMAHA_CORE_SCHEDULER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-

-namespace omaha {

-

-class Core;

-class HighresTimer;

-class QueueTimer;

-

-class Scheduler {

- public:

-  explicit Scheduler(const Core& core);

-  ~Scheduler();

-

-  // Starts the scheduler.

-  HRESULT Initialize();

-

- private:

-  static void TimerCallback(QueueTimer* timer);

-  void HandleCallback(QueueTimer* timer);

-  HRESULT ScheduleUpdateTimer(int interval_ms);

-  HRESULT ScheduleCodeRedTimer(int interval_ms);

-

-  const Core& core_;

-  HANDLE timer_queue_;

-  scoped_ptr<QueueTimer> update_timer_;

-  scoped_ptr<QueueTimer> code_red_timer_;

-

-  // Measures the actual time interval between code red events for debugging

-  // purposes. The timer is started when a code red alarm is set and then,

-  // the value of the timer is read when the alarm goes off.

-  scoped_ptr<HighresTimer> cr_debug_timer_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Scheduler);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_CORE_SCHEDULER_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// TODO(omaha): consider using a waitable timer registered with the reactor. It
+// seems a lot less code than using the QueueTimer class.
+
+#ifndef OMAHA_CORE_SCHEDULER_H__
+#define OMAHA_CORE_SCHEDULER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+
+namespace omaha {
+
+class Core;
+class HighresTimer;
+class QueueTimer;
+
+class Scheduler {
+ public:
+  explicit Scheduler(const Core& core);
+  ~Scheduler();
+
+  // Starts the scheduler.
+  HRESULT Initialize();
+
+ private:
+  static void TimerCallback(QueueTimer* timer);
+  void HandleCallback(QueueTimer* timer);
+  HRESULT ScheduleUpdateTimer(int interval_ms);
+  HRESULT ScheduleCodeRedTimer(int interval_ms);
+
+  const Core& core_;
+  HANDLE timer_queue_;
+  scoped_ptr<QueueTimer> update_timer_;
+  scoped_ptr<QueueTimer> code_red_timer_;
+
+  // Measures the actual time interval between code red events for debugging
+  // purposes. The timer is started when a code red alarm is set and then,
+  // the value of the timer is read when the alarm goes off.
+  scoped_ptr<HighresTimer> cr_debug_timer_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Scheduler);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_CORE_SCHEDULER_H__
+
diff --git a/core/system_monitor.cc b/core/system_monitor.cc
index edbfc52..1520268 100644
--- a/core/system_monitor.cc
+++ b/core/system_monitor.cc
@@ -1,144 +1,144 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/core/system_monitor.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-

-namespace omaha {

-

-SystemMonitor::SystemMonitor(bool is_machine)

-    : is_machine_(is_machine) {

-  ::InterlockedExchangePointer(reinterpret_cast<void**>(&observer_), NULL);

-}

-

-SystemMonitor::~SystemMonitor() {

-  if (m_hWnd) {

-    VERIFY1(DestroyWindow());

-  }

-}

-

-HRESULT SystemMonitor::Initialize(bool monitor_registry) {

-  if (monitor_registry) {

-    registry_monitor_.reset(new RegistryMonitor);

-    if (SUCCEEDED(registry_monitor_->Initialize())) {

-      HKEY root_key = is_machine_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

-      VERIFY1(SUCCEEDED(registry_monitor_->MonitorValue(

-          root_key,

-          GOOPDATE_MAIN_KEY,

-          kRegValueLastChecked,

-          REG_DWORD,

-          RegistryValueChangeCallback,

-          this)));

-      VERIFY1(SUCCEEDED(registry_monitor_->MonitorKey(

-          root_key,

-          GOOPDATE_REG_RELATIVE_CLIENTS,

-          RegistryKeyChangeCallback,

-          this)));

-      VERIFY1(SUCCEEDED(registry_monitor_->StartMonitoring()));

-    }

-  }

-

-  // Create a window to receive broadcast messages.

-  const TCHAR kWindowTitle[] = _T("{2D905E07-FC38-4b89-83E1-931D3630937F}");

-  VERIFY1(Create(NULL, NULL, kWindowTitle));

-  return S_OK;

-}

-

-LRESULT SystemMonitor::OnPowerBroadcast(UINT, WPARAM wparam,

-                                        LPARAM, BOOL& handled) {

-  CORE_LOG(L3, (_T("[SystemMonitor::OnPowerBroadcast][wparam %d]"), wparam));

-  UNREFERENCED_PARAMETER(wparam);

-  handled = true;

-  return 0;

-}

-

-LRESULT SystemMonitor::OnEndSession(UINT, WPARAM wparam,

-                                    LPARAM lparam, BOOL& handled) {

-  CORE_LOG(L3, (_T("[SystemMonitor::OnEndSession][wparam %d][lparam %x]"),

-                wparam, lparam));

-  UNREFERENCED_PARAMETER(wparam);

-  UNREFERENCED_PARAMETER(lparam);

-  handled = true;

-  return 0;

-}

-

-LRESULT SystemMonitor::OnQueryEndSession(UINT, WPARAM,

-                                         LPARAM lparam, BOOL& handled) {

-  CORE_LOG(L3, (_T("[SystemMonitor::OnQueryEndSession][lparam %x]"), lparam));

-  UNREFERENCED_PARAMETER(lparam);

-  handled = true;

-  return TRUE;

-}

-

-LRESULT SystemMonitor::OnWTSSessionChange(UINT, WPARAM wparam,

-                                          LPARAM lparam, BOOL& handled) {

-  CORE_LOG(L3, (_T("[SystemMonitor::OnWTSSessionChange][wparam %x][lparam %d]"),

-                wparam, lparam));

-  UNREFERENCED_PARAMETER(wparam);

-  UNREFERENCED_PARAMETER(lparam);

-  handled = true;

-  return 0;

-}

-

-void SystemMonitor::RegistryValueChangeCallback(const TCHAR* key_name,

-                                                const TCHAR* value_name,

-                                                RegistryChangeType change_type,

-                                                const void* new_value_data,

-                                                void* user_data) {

-  ASSERT1(key_name);

-  ASSERT1(value_name);

-  ASSERT1(user_data);

-

-  ASSERT1(_tcscmp(value_name, kRegValueLastChecked) == 0);

-

-  UNREFERENCED_PARAMETER(key_name);

-  UNREFERENCED_PARAMETER(value_name);

-  UNREFERENCED_PARAMETER(new_value_data);

-

-  SystemMonitor* system_monitor = static_cast<SystemMonitor*>(user_data);

-  if (change_type == REGISTRY_CHANGE_TYPE_DELETE &&

-      system_monitor->observer_) {

-    system_monitor->observer_->LastCheckedDeleted();

-  }

-}

-

-void SystemMonitor::RegistryKeyChangeCallback(const TCHAR* key_name,

-                                              void* user_data) {

-  ASSERT1(key_name);

-  ASSERT1(user_data);

-

-  UNREFERENCED_PARAMETER(key_name);

-  ASSERT1(_tcscmp(key_name, GOOPDATE_REG_RELATIVE_CLIENTS) == 0);

-

-  SystemMonitor* system_monitor = static_cast<SystemMonitor*>(user_data);

-  if (!system_monitor->observer_) {

-    return;

-  }

-

-  const bool is_machine = system_monitor->is_machine_;

-  size_t num_clients(0);

-  if (SUCCEEDED(goopdate_utils::GetNumClients(is_machine, &num_clients)) &&

-      num_clients <= 1) {

-    system_monitor->observer_->NoRegisteredClients();

-  }

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/core/system_monitor.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+
+namespace omaha {
+
+SystemMonitor::SystemMonitor(bool is_machine)
+    : is_machine_(is_machine) {
+  ::InterlockedExchangePointer(reinterpret_cast<void**>(&observer_), NULL);
+}
+
+SystemMonitor::~SystemMonitor() {
+  if (m_hWnd) {
+    VERIFY1(DestroyWindow());
+  }
+}
+
+HRESULT SystemMonitor::Initialize(bool monitor_registry) {
+  if (monitor_registry) {
+    registry_monitor_.reset(new RegistryMonitor);
+    if (SUCCEEDED(registry_monitor_->Initialize())) {
+      HKEY root_key = is_machine_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+      VERIFY1(SUCCEEDED(registry_monitor_->MonitorValue(
+          root_key,
+          GOOPDATE_MAIN_KEY,
+          kRegValueLastChecked,
+          REG_DWORD,
+          RegistryValueChangeCallback,
+          this)));
+      VERIFY1(SUCCEEDED(registry_monitor_->MonitorKey(
+          root_key,
+          GOOPDATE_REG_RELATIVE_CLIENTS,
+          RegistryKeyChangeCallback,
+          this)));
+      VERIFY1(SUCCEEDED(registry_monitor_->StartMonitoring()));
+    }
+  }
+
+  // Create a window to receive broadcast messages.
+  const TCHAR kWindowTitle[] = _T("{2D905E07-FC38-4b89-83E1-931D3630937F}");
+  VERIFY1(Create(NULL, NULL, kWindowTitle));
+  return S_OK;
+}
+
+LRESULT SystemMonitor::OnPowerBroadcast(UINT, WPARAM wparam,
+                                        LPARAM, BOOL& handled) {
+  CORE_LOG(L3, (_T("[SystemMonitor::OnPowerBroadcast][wparam %d]"), wparam));
+  UNREFERENCED_PARAMETER(wparam);
+  handled = true;
+  return 0;
+}
+
+LRESULT SystemMonitor::OnEndSession(UINT, WPARAM wparam,
+                                    LPARAM lparam, BOOL& handled) {
+  CORE_LOG(L3, (_T("[SystemMonitor::OnEndSession][wparam %d][lparam %x]"),
+                wparam, lparam));
+  UNREFERENCED_PARAMETER(wparam);
+  UNREFERENCED_PARAMETER(lparam);
+  handled = true;
+  return 0;
+}
+
+LRESULT SystemMonitor::OnQueryEndSession(UINT, WPARAM,
+                                         LPARAM lparam, BOOL& handled) {
+  CORE_LOG(L3, (_T("[SystemMonitor::OnQueryEndSession][lparam %x]"), lparam));
+  UNREFERENCED_PARAMETER(lparam);
+  handled = true;
+  return TRUE;
+}
+
+LRESULT SystemMonitor::OnWTSSessionChange(UINT, WPARAM wparam,
+                                          LPARAM lparam, BOOL& handled) {
+  CORE_LOG(L3, (_T("[SystemMonitor::OnWTSSessionChange][wparam %x][lparam %d]"),
+                wparam, lparam));
+  UNREFERENCED_PARAMETER(wparam);
+  UNREFERENCED_PARAMETER(lparam);
+  handled = true;
+  return 0;
+}
+
+void SystemMonitor::RegistryValueChangeCallback(const TCHAR* key_name,
+                                                const TCHAR* value_name,
+                                                RegistryChangeType change_type,
+                                                const void* new_value_data,
+                                                void* user_data) {
+  ASSERT1(key_name);
+  ASSERT1(value_name);
+  ASSERT1(user_data);
+
+  ASSERT1(_tcscmp(value_name, kRegValueLastChecked) == 0);
+
+  UNREFERENCED_PARAMETER(key_name);
+  UNREFERENCED_PARAMETER(value_name);
+  UNREFERENCED_PARAMETER(new_value_data);
+
+  SystemMonitor* system_monitor = static_cast<SystemMonitor*>(user_data);
+  if (change_type == REGISTRY_CHANGE_TYPE_DELETE &&
+      system_monitor->observer_) {
+    system_monitor->observer_->LastCheckedDeleted();
+  }
+}
+
+void SystemMonitor::RegistryKeyChangeCallback(const TCHAR* key_name,
+                                              void* user_data) {
+  ASSERT1(key_name);
+  ASSERT1(user_data);
+
+  UNREFERENCED_PARAMETER(key_name);
+  ASSERT1(_tcscmp(key_name, GOOPDATE_REG_RELATIVE_CLIENTS) == 0);
+
+  SystemMonitor* system_monitor = static_cast<SystemMonitor*>(user_data);
+  if (!system_monitor->observer_) {
+    return;
+  }
+
+  const bool is_machine = system_monitor->is_machine_;
+  size_t num_clients(0);
+  if (SUCCEEDED(goopdate_utils::GetNumClients(is_machine, &num_clients)) &&
+      num_clients <= 1) {
+    system_monitor->observer_->NoRegisteredClients();
+  }
+}
+
+}  // namespace omaha
diff --git a/core/system_monitor.h b/core/system_monitor.h
index 5affddc..d27a762 100644
--- a/core/system_monitor.h
+++ b/core/system_monitor.h
@@ -1,98 +1,98 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// SystemMonitor receives session messages and power management messages.

-

-#ifndef OMAHA_CORE_SYSTEM_MONITOR_H_

-#define OMAHA_CORE_SYSTEM_MONITOR_H_

-

-#include <atlbase.h>

-#include <atlwin.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/registry_monitor_manager.h"

-

-namespace omaha {

-

-class SystemMonitorObserver {

- public:

-  virtual ~SystemMonitorObserver() {}

-

-  // Called when 'LastChecked' registry value is deleted.

-  virtual void LastCheckedDeleted() = 0;

-

-  // Called when there are no other clients that are registered besides Omaha.

-  virtual void NoRegisteredClients() = 0;

-};

-

-class SystemMonitor

-    : public CWindowImpl<SystemMonitor,

-                         CWindow,

-                         CWinTraits<WS_OVERLAPPED, WS_EX_TOOLWINDOW> > {

- public:

-  explicit SystemMonitor(bool is_machine);

-  ~SystemMonitor();

-

-  HRESULT Initialize(bool monitor_registry);

-

-  void set_observer(SystemMonitorObserver* observer) {

-    ::InterlockedExchangePointer(reinterpret_cast<void**>(&observer_),

-                                 observer);

-  }

-

-  BEGIN_MSG_MAP(SystemMonitor)

-    MESSAGE_HANDLER(WM_POWERBROADCAST,    OnPowerBroadcast)

-    MESSAGE_HANDLER(WM_QUERYENDSESSION,   OnQueryEndSession)

-    MESSAGE_HANDLER(WM_ENDSESSION,        OnEndSession)

-    MESSAGE_HANDLER(WM_WTSSESSION_CHANGE, OnWTSSessionChange)

-  END_MSG_MAP()

-

- private:

-  // Notifies the system monitor that a power-management event has occurred.

-  LRESULT OnPowerBroadcast(UINT msg, WPARAM wparam,

-                           LPARAM lparam, BOOL& handled);

-

-  // Notifies the system monitor a shutdown has been requested.

-  LRESULT OnQueryEndSession(UINT msg, WPARAM wparam,

-                            LPARAM lparam, BOOL& handled);

-

-  // Notifies the system monitor whether the session is ending.

-  LRESULT OnEndSession(UINT msg, WPARAM wparam,

-                       LPARAM lparam, BOOL& handled);

-

-  // Notifies the system monitor about changes in the session state.

-  LRESULT OnWTSSessionChange(UINT msg, WPARAM wparam,

-                             LPARAM lparam, BOOL& handled);

-

-  static void RegistryValueChangeCallback(const TCHAR* key_name,

-                                          const TCHAR* value_name,

-                                          RegistryChangeType change_type,

-                                          const void* new_value_data,

-                                          void* user_data);

-

-  static void RegistryKeyChangeCallback(const TCHAR* key_name,

-                                        void* user_data);

-

-  scoped_ptr<RegistryMonitor> registry_monitor_;

-  bool is_machine_;

-  SystemMonitorObserver* observer_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(SystemMonitor);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_CORE_SYSTEM_MONITOR_H_

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// SystemMonitor receives session messages and power management messages.
+
+#ifndef OMAHA_CORE_SYSTEM_MONITOR_H_
+#define OMAHA_CORE_SYSTEM_MONITOR_H_
+
+#include <atlbase.h>
+#include <atlwin.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/registry_monitor_manager.h"
+
+namespace omaha {
+
+class SystemMonitorObserver {
+ public:
+  virtual ~SystemMonitorObserver() {}
+
+  // Called when 'LastChecked' registry value is deleted.
+  virtual void LastCheckedDeleted() = 0;
+
+  // Called when there are no other clients that are registered besides Omaha.
+  virtual void NoRegisteredClients() = 0;
+};
+
+class SystemMonitor
+    : public CWindowImpl<SystemMonitor,
+                         CWindow,
+                         CWinTraits<WS_OVERLAPPED, WS_EX_TOOLWINDOW> > {
+ public:
+  explicit SystemMonitor(bool is_machine);
+  ~SystemMonitor();
+
+  HRESULT Initialize(bool monitor_registry);
+
+  void set_observer(SystemMonitorObserver* observer) {
+    ::InterlockedExchangePointer(reinterpret_cast<void**>(&observer_),
+                                 observer);
+  }
+
+  BEGIN_MSG_MAP(SystemMonitor)
+    MESSAGE_HANDLER(WM_POWERBROADCAST,    OnPowerBroadcast)
+    MESSAGE_HANDLER(WM_QUERYENDSESSION,   OnQueryEndSession)
+    MESSAGE_HANDLER(WM_ENDSESSION,        OnEndSession)
+    MESSAGE_HANDLER(WM_WTSSESSION_CHANGE, OnWTSSessionChange)
+  END_MSG_MAP()
+
+ private:
+  // Notifies the system monitor that a power-management event has occurred.
+  LRESULT OnPowerBroadcast(UINT msg, WPARAM wparam,
+                           LPARAM lparam, BOOL& handled);
+
+  // Notifies the system monitor a shutdown has been requested.
+  LRESULT OnQueryEndSession(UINT msg, WPARAM wparam,
+                            LPARAM lparam, BOOL& handled);
+
+  // Notifies the system monitor whether the session is ending.
+  LRESULT OnEndSession(UINT msg, WPARAM wparam,
+                       LPARAM lparam, BOOL& handled);
+
+  // Notifies the system monitor about changes in the session state.
+  LRESULT OnWTSSessionChange(UINT msg, WPARAM wparam,
+                             LPARAM lparam, BOOL& handled);
+
+  static void RegistryValueChangeCallback(const TCHAR* key_name,
+                                          const TCHAR* value_name,
+                                          RegistryChangeType change_type,
+                                          const void* new_value_data,
+                                          void* user_data);
+
+  static void RegistryKeyChangeCallback(const TCHAR* key_name,
+                                        void* user_data);
+
+  scoped_ptr<RegistryMonitor> registry_monitor_;
+  bool is_machine_;
+  SystemMonitorObserver* observer_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(SystemMonitor);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_CORE_SYSTEM_MONITOR_H_
+
diff --git a/core/system_monitor_unittest.cc b/core/system_monitor_unittest.cc
index 184ee09..c68727a 100644
--- a/core/system_monitor_unittest.cc
+++ b/core/system_monitor_unittest.cc
@@ -1,135 +1,135 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/constants.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/core/system_monitor.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class SystemMonitorTest

-    : public testing::Test,

-      public SystemMonitorObserver {

- protected:

-  virtual void SetUp() {

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-    OverrideRegistryHives(kRegistryHiveOverrideRoot);

-    gate_.reset(new Gate);

-  }

-

-  virtual void TearDown() {

-    gate_.reset();

-    RestoreRegistryHives();

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-  }

-

-  // SystemMonitorObserver interface.

-  virtual void LastCheckedDeleted() {

-    gate_->Open();

-  }

-

-  virtual void NoRegisteredClients() {

-    gate_->Open();

-  }

-

-  void MonitorLastCheckedTest(bool is_machine);

-  void MonitorClientsTest(bool is_machine);

-

-  scoped_ptr<Gate> gate_;

-};

-

-void SystemMonitorTest::MonitorLastCheckedTest(bool is_machine) {

-  const TCHAR* key_name = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE;

-  DWORD last_checked_value(1);

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(key_name,

-                                            kRegValueLastChecked,

-                                            last_checked_value));

-  SystemMonitor system_monitor(is_machine);

-  system_monitor.set_observer(this);

-  ASSERT_HRESULT_SUCCEEDED(system_monitor.Initialize(true));

-

-  // Trigger the callback first time.

-  EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteValue(key_name,

-                                               kRegValueLastChecked));

-  EXPECT_TRUE(gate_->Wait(1000));

-  EXPECT_FALSE(RegKey::HasValue(key_name, kRegValueLastChecked));

-

-  // Trigger the callback second time.

-  last_checked_value = 2;

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(key_name,

-                                            kRegValueLastChecked,

-                                            last_checked_value));

-

-  // It takes a while for the registry monitor to detect the changes. There are

-  // two changes here: setting and deleting the values.

-  ::Sleep(50);

-  EXPECT_TRUE(gate_->Close());

-  EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteValue(key_name,

-                                               kRegValueLastChecked));

-  EXPECT_TRUE(gate_->Wait(1000));

-  EXPECT_FALSE(RegKey::HasValue(key_name, kRegValueLastChecked));

-}

-

-void SystemMonitorTest::MonitorClientsTest(bool is_machine) {

-  const TCHAR* key_name = is_machine ? MACHINE_REG_CLIENTS : USER_REG_CLIENTS;

-  const TCHAR guid[] = _T("{4AAF2315-B7C8-4633-A1BA-884EFAB755F7}");

-

-  CString app_guid = ConcatenatePath(key_name, guid);

-  CString omaha_guid = ConcatenatePath(key_name, kGoogleUpdateAppId);

-  const TCHAR* keys_to_create[] = { app_guid, omaha_guid };

-  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKeys(keys_to_create,

-                                              arraysize(keys_to_create)));

-

-  SystemMonitor system_monitor(is_machine);

-  system_monitor.set_observer(this);

-  EXPECT_HRESULT_SUCCEEDED(system_monitor.Initialize(true));

-

-  EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteKey(keys_to_create[0], true));

-  EXPECT_TRUE(gate_->Wait(1000));

-}

-

-TEST_F(SystemMonitorTest, SystemMonitor) {

-  SystemMonitor system_monitor(false);

-  ASSERT_HRESULT_SUCCEEDED(system_monitor.Initialize(false));

-  EXPECT_EQ(0, system_monitor.SendMessage(WM_POWERBROADCAST, 0, 0));

-  EXPECT_EQ(TRUE, system_monitor.SendMessage(WM_QUERYENDSESSION, 0, 0));

-  EXPECT_EQ(0, system_monitor.SendMessage(WM_ENDSESSION, 0, 0));

-  EXPECT_EQ(0, system_monitor.SendMessage(WM_WTSSESSION_CHANGE, 0, 0));

-}

-

-// Tests the callback gets called when the "LastChecked" is deleted and

-// the value is not recreated automatically by the monitor.

-TEST_F(SystemMonitorTest, DeleteLastChecked_User) {

-  MonitorLastCheckedTest(false);

-}

-

-TEST_F(SystemMonitorTest, DeleteLastChecked_Machine) {

-  MonitorLastCheckedTest(true);

-}

-

-TEST_F(SystemMonitorTest, MonitorClients_User) {

-  MonitorClientsTest(false);

-}

-

-TEST_F(SystemMonitorTest, MonitorClients_Machine) {

-  MonitorClientsTest(true);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/constants.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/core/system_monitor.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class SystemMonitorTest
+    : public testing::Test,
+      public SystemMonitorObserver {
+ protected:
+  virtual void SetUp() {
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+    OverrideRegistryHives(kRegistryHiveOverrideRoot);
+    gate_.reset(new Gate);
+  }
+
+  virtual void TearDown() {
+    gate_.reset();
+    RestoreRegistryHives();
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+  }
+
+  // SystemMonitorObserver interface.
+  virtual void LastCheckedDeleted() {
+    gate_->Open();
+  }
+
+  virtual void NoRegisteredClients() {
+    gate_->Open();
+  }
+
+  void MonitorLastCheckedTest(bool is_machine);
+  void MonitorClientsTest(bool is_machine);
+
+  scoped_ptr<Gate> gate_;
+};
+
+void SystemMonitorTest::MonitorLastCheckedTest(bool is_machine) {
+  const TCHAR* key_name = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
+  DWORD last_checked_value(1);
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(key_name,
+                                            kRegValueLastChecked,
+                                            last_checked_value));
+  SystemMonitor system_monitor(is_machine);
+  system_monitor.set_observer(this);
+  ASSERT_HRESULT_SUCCEEDED(system_monitor.Initialize(true));
+
+  // Trigger the callback first time.
+  EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteValue(key_name,
+                                               kRegValueLastChecked));
+  EXPECT_TRUE(gate_->Wait(1000));
+  EXPECT_FALSE(RegKey::HasValue(key_name, kRegValueLastChecked));
+
+  // Trigger the callback second time.
+  last_checked_value = 2;
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(key_name,
+                                            kRegValueLastChecked,
+                                            last_checked_value));
+
+  // It takes a while for the registry monitor to detect the changes. There are
+  // two changes here: setting and deleting the values.
+  ::Sleep(50);
+  EXPECT_TRUE(gate_->Close());
+  EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteValue(key_name,
+                                               kRegValueLastChecked));
+  EXPECT_TRUE(gate_->Wait(1000));
+  EXPECT_FALSE(RegKey::HasValue(key_name, kRegValueLastChecked));
+}
+
+void SystemMonitorTest::MonitorClientsTest(bool is_machine) {
+  const TCHAR* key_name = is_machine ? MACHINE_REG_CLIENTS : USER_REG_CLIENTS;
+  const TCHAR guid[] = _T("{4AAF2315-B7C8-4633-A1BA-884EFAB755F7}");
+
+  CString app_guid = ConcatenatePath(key_name, guid);
+  CString omaha_guid = ConcatenatePath(key_name, kGoogleUpdateAppId);
+  const TCHAR* keys_to_create[] = { app_guid, omaha_guid };
+  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKeys(keys_to_create,
+                                              arraysize(keys_to_create)));
+
+  SystemMonitor system_monitor(is_machine);
+  system_monitor.set_observer(this);
+  EXPECT_HRESULT_SUCCEEDED(system_monitor.Initialize(true));
+
+  EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteKey(keys_to_create[0], true));
+  EXPECT_TRUE(gate_->Wait(1000));
+}
+
+TEST_F(SystemMonitorTest, SystemMonitor) {
+  SystemMonitor system_monitor(false);
+  ASSERT_HRESULT_SUCCEEDED(system_monitor.Initialize(false));
+  EXPECT_EQ(0, system_monitor.SendMessage(WM_POWERBROADCAST, 0, 0));
+  EXPECT_EQ(TRUE, system_monitor.SendMessage(WM_QUERYENDSESSION, 0, 0));
+  EXPECT_EQ(0, system_monitor.SendMessage(WM_ENDSESSION, 0, 0));
+  EXPECT_EQ(0, system_monitor.SendMessage(WM_WTSSESSION_CHANGE, 0, 0));
+}
+
+// Tests the callback gets called when the "LastChecked" is deleted and
+// the value is not recreated automatically by the monitor.
+TEST_F(SystemMonitorTest, DeleteLastChecked_User) {
+  MonitorLastCheckedTest(false);
+}
+
+TEST_F(SystemMonitorTest, DeleteLastChecked_Machine) {
+  MonitorLastCheckedTest(true);
+}
+
+TEST_F(SystemMonitorTest, MonitorClients_User) {
+  MonitorClientsTest(false);
+}
+
+TEST_F(SystemMonitorTest, MonitorClients_Machine) {
+  MonitorClientsTest(true);
+}
+
+}  // namespace omaha
+
diff --git a/data/GoogleUpdate.ini b/data/GoogleUpdate.ini
index 8987aa1..404a1b9 100644
--- a/data/GoogleUpdate.ini
+++ b/data/GoogleUpdate.ini
@@ -1,6 +1,6 @@
-[LoggingLevel]

-LC_OPT=1

-

-[LoggingSettings]

-EnableLogging=1

-; MaxLogFileSize=1000000

+[LoggingLevel]
+LC_OPT=1
+
+[LoggingSettings]
+EnableLogging=1
+; MaxLogFileSize=1000000
diff --git a/data/manifest.xml b/data/manifest.xml
index f48ad0b..46f9e47 100644
--- a/data/manifest.xml
+++ b/data/manifest.xml
@@ -1,64 +1,64 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<!--Sample XML file generated by XMLSPY v2004 rel. 3 U (http://www.xmlspy.com)-->

-<Manifest ci:ver="1.0" ci:timestamp="aaaa" xmlns="http://www.google.com/ci/manifest" xmlns:ci="http://www.google.com/ci/manifest">

-  <App id="001" sig="abcd">

-    <Lang>EN-US</Lang>

-    <DisplayName>Google Toolbar</DisplayName>

-    <CreationDate>October 27, 2005</CreationDate>

-    <Ver>2.0</Ver>

-    <Description>Take the power of Google with you anywhere on the web.</Description>

-    <Logo>http://www.google.com/toolbar-logo.gif</Logo>

-    <MoreInfoUrl>http://toolbar.google.com</MoreInfoUrl>

-    <CodeBase>http://gpdl.google.com/GoogleEarth.exe</CodeBase>

-    <CodeBase file="setup.iss">http://gpdl.google.com/GoogleEarthSetup.iss</CodeBase>

-    <Size>476304</Size>

-    <Hash>JustTesting</Hash>

-    <CodeBase2>http://gpdl.google.com/GoogleEarthPatch.exe</CodeBase2>

-    <Size2>21391</Size2>

-    <Hash2>JustTesting2</Hash2>

-    <MinRequiredVersion>1.0</MinRequiredVersion>

-    <MinRecommendedVersion>1.0</MinRecommendedVersion>

-    <Versions>

-      <Version>

-        <ProductCode>HKLM\Software\Adobe\Acrobat Reader\7.0\Installer\ENU_GUID</ProductCode>

-        <AppPath>HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\</AppPath>

-      </Version>

-      <Version>

-        <ProductCode>HKLM\Software\Adobe\Acrobat Reader\6.0\Installer\ENU_GUID</ProductCode>

-        <AppPath>HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\</AppPath>

-      </Version>

-      <Version>

-        <ProductCode>Adobe Acrobat 5.0</ProductCode>

-        <AppPath>HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\</AppPath>

-      </Version>

-      <Version>

-        <ProductCode>Adobe Acrobat 4.0</ProductCode>

-        <AppPath>HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\</AppPath>

-      </Version>

-    </Versions>

-    <UsageStatsSwitch on="/u" off="/-u" />

-    <GoogleApp>1</GoogleApp>

-    <AltCommandLineParameters>-bundle=GCDR /nods /notb -silent /noshortcut</AltCommandLineParameters>

-    <AltVisualCommandLineParameters>-bundle=GCDR /nods /notb</AltVisualCommandLineParameters>

-    <WhatsNewUrl>http://earth.google.com/earth4.html</WhatsNewUrl>

-    <MinAutoupdateVersion>4.0.0.0</MinAutoupdateVersion>

-    <FlowMappings>

-      <Flow name="RegularPack">-bundle=GPCK /noshortcut</Flow>

-      <Flow name="EarthInt" replace="1">-bundle=GCDR</Flow>

-      <Flow name="OEM" replace="false">-o -r:%OEMBRAND%</Flow>

-    </FlowMappings>

-  </App>

-  <App id="002" sig="1234">

-    <Lang>En-US</Lang>

-    <DisplayName>Google Desktop Search</DisplayName>

-    <Ver>1.0</Ver>

-    <CreationDate>October 27, 2005</CreationDate>

-    <Description>Search your own computer.</Description>

-    <Logo>http://www.google.com/desktop-logo.gif</Logo>

-    <MoreInfoUrl>http://desktop.google.com</MoreInfoUrl>

-    <CodeBase>http://dl.google.com/desktop/GoogleDesktopSearchSetup.exe</CodeBase>

-    <Size>740456</Size>

-    <Hash>JustTesting</Hash>

-    <GoogleApp>false</GoogleApp> 

-  </App>

-</Manifest>

+<?xml version="1.0" encoding="UTF-8"?>
+<!--Sample XML file generated by XMLSPY v2004 rel. 3 U (http://www.xmlspy.com)-->
+<Manifest ci:ver="1.0" ci:timestamp="aaaa" xmlns="http://www.google.com/ci/manifest" xmlns:ci="http://www.google.com/ci/manifest">
+  <App id="001" sig="abcd">
+    <Lang>EN-US</Lang>
+    <DisplayName>Google Toolbar</DisplayName>
+    <CreationDate>October 27, 2005</CreationDate>
+    <Ver>2.0</Ver>
+    <Description>Take the power of Google with you anywhere on the web.</Description>
+    <Logo>http://www.google.com/toolbar-logo.gif</Logo>
+    <MoreInfoUrl>http://toolbar.google.com</MoreInfoUrl>
+    <CodeBase>http://gpdl.google.com/GoogleEarth.exe</CodeBase>
+    <CodeBase file="setup.iss">http://gpdl.google.com/GoogleEarthSetup.iss</CodeBase>
+    <Size>476304</Size>
+    <Hash>JustTesting</Hash>
+    <CodeBase2>http://gpdl.google.com/GoogleEarthPatch.exe</CodeBase2>
+    <Size2>21391</Size2>
+    <Hash2>JustTesting2</Hash2>
+    <MinRequiredVersion>1.0</MinRequiredVersion>
+    <MinRecommendedVersion>1.0</MinRecommendedVersion>
+    <Versions>
+      <Version>
+        <ProductCode>HKLM\Software\Adobe\Acrobat Reader\7.0\Installer\ENU_GUID</ProductCode>
+        <AppPath>HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\</AppPath>
+      </Version>
+      <Version>
+        <ProductCode>HKLM\Software\Adobe\Acrobat Reader\6.0\Installer\ENU_GUID</ProductCode>
+        <AppPath>HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\</AppPath>
+      </Version>
+      <Version>
+        <ProductCode>Adobe Acrobat 5.0</ProductCode>
+        <AppPath>HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\</AppPath>
+      </Version>
+      <Version>
+        <ProductCode>Adobe Acrobat 4.0</ProductCode>
+        <AppPath>HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\AcroRd32.exe\</AppPath>
+      </Version>
+    </Versions>
+    <UsageStatsSwitch on="/u" off="/-u" />
+    <GoogleApp>1</GoogleApp>
+    <AltCommandLineParameters>-bundle=GCDR /nods /notb -silent /noshortcut</AltCommandLineParameters>
+    <AltVisualCommandLineParameters>-bundle=GCDR /nods /notb</AltVisualCommandLineParameters>
+    <WhatsNewUrl>http://earth.google.com/earth4.html</WhatsNewUrl>
+    <MinAutoupdateVersion>4.0.0.0</MinAutoupdateVersion>
+    <FlowMappings>
+      <Flow name="RegularPack">-bundle=GPCK /noshortcut</Flow>
+      <Flow name="EarthInt" replace="1">-bundle=GCDR</Flow>
+      <Flow name="OEM" replace="false">-o -r:%OEMBRAND%</Flow>
+    </FlowMappings>
+  </App>
+  <App id="002" sig="1234">
+    <Lang>En-US</Lang>
+    <DisplayName>Google Desktop Search</DisplayName>
+    <Ver>1.0</Ver>
+    <CreationDate>October 27, 2005</CreationDate>
+    <Description>Search your own computer.</Description>
+    <Logo>http://www.google.com/desktop-logo.gif</Logo>
+    <MoreInfoUrl>http://desktop.google.com</MoreInfoUrl>
+    <CodeBase>http://dl.google.com/desktop/GoogleDesktopSearchSetup.exe</CodeBase>
+    <Size>740456</Size>
+    <Hash>JustTesting</Hash>
+    <GoogleApp>false</GoogleApp> 
+  </App>
+</Manifest>
diff --git a/data/omaha.ini b/data/omaha.ini
index 9577e60..fa4c1c6 100644
--- a/data/omaha.ini
+++ b/data/omaha.ini
@@ -1,18 +1,18 @@
-[LoggingLevel]

-LC_UTIL=0

-LC_SERVICE=3

-LC_CORE=3

-

-[LoggingSettings]

-EnableLogging=1

-ShowTime=1

-LogToFile=1

-AppendToFile=1

-LogToStdOut=0

-LogToOutputDebug=1

-LogFilePath=omaha.log

-

-[DebugSettings]

-SkipServerReport=1

-NoSendDumpToServer=1

-NoSendStackToServer=1

+[LoggingLevel]
+LC_UTIL=0
+LC_SERVICE=3
+LC_CORE=3
+
+[LoggingSettings]
+EnableLogging=1
+ShowTime=1
+LogToFile=1
+AppendToFile=1
+LogToStdOut=0
+LogToOutputDebug=1
+LogFilePath=omaha.log
+
+[DebugSettings]
+SkipServerReport=1
+NoSendDumpToServer=1
+NoSendStackToServer=1
diff --git a/data/seed_manifest.xml b/data/seed_manifest.xml
index 852a11b..b840bba 100644
--- a/data/seed_manifest.xml
+++ b/data/seed_manifest.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<gupdate protocol="3.0" signature="" xmlns="http://www.google.com/update2/install">

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9937}" needsadmin="false" appname="Test App" lang="en-US"/>

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9938}" needsadmin="false" appname="Test App" lang="en-US" browser="0"/>

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9939}" needsadmin="false" appname="Test App" lang="en-US"  browser="1"/>

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9940}" needsadmin="false" appname="Test App" lang="en-US" browser="2"/>

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9941}" needsadmin="false" appname="Test App" lang="en-US" browser="3"/>

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9942}" needsadmin="false" appname="Test App" lang="en-US" browser="4"/>

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9943}" needsadmin="false" appname="Test App" lang="en-US" browser="5"/>

-</gupdate>

+<?xml version="1.0" encoding="UTF-8"?>
+<gupdate protocol="3.0" signature="" xmlns="http://www.google.com/update2/install">
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9937}" needsadmin="false" appname="Test App" lang="en-US"/>
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9938}" needsadmin="false" appname="Test App" lang="en-US" browser="0"/>
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9939}" needsadmin="false" appname="Test App" lang="en-US"  browser="1"/>
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9940}" needsadmin="false" appname="Test App" lang="en-US" browser="2"/>
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9941}" needsadmin="false" appname="Test App" lang="en-US" browser="3"/>
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9942}" needsadmin="false" appname="Test App" lang="en-US" browser="4"/>
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9943}" needsadmin="false" appname="Test App" lang="en-US" browser="5"/>
+</gupdate>
diff --git a/data/seed_manifest_v1.xml b/data/seed_manifest_v1.xml
index edc58bd..39011e5 100644
--- a/data/seed_manifest_v1.xml
+++ b/data/seed_manifest_v1.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<responses ver="1.0" signature="" xmlns="http://www.google.com/omaha/response">

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9937}" needsadmin="false"/>

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9938}" needsadmin="false"/>

-</responses>

+<?xml version="1.0" encoding="UTF-8"?>
+<responses ver="1.0" signature="" xmlns="http://www.google.com/omaha/response">
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9937}" needsadmin="false"/>
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9938}" needsadmin="false"/>
+</responses>
diff --git a/data/seed_manifest_v9.xml b/data/seed_manifest_v9.xml
index 0b234dc..c10ec67 100644
--- a/data/seed_manifest_v9.xml
+++ b/data/seed_manifest_v9.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<gupdate protocol="9.0" signature="" xmlns="http://www.google.com/update2/install">

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9937}" needsadmin="false" appname="Test App" language="en-US"/>

-<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9938}" needsadmin="false" appname="Test App" language="en-US"/>

-</gupdate>

+<?xml version="1.0" encoding="UTF-8"?>
+<gupdate protocol="9.0" signature="" xmlns="http://www.google.com/update2/install">
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9937}" needsadmin="false" appname="Test App" language="en-US"/>
+<install appguid="{D6B08267-B440-4c85-9F79-E195E80D9938}" needsadmin="false" appname="Test App" language="en-US"/>
+</gupdate>
diff --git a/data/seed_manifest_with_args.xml b/data/seed_manifest_with_args.xml
index 1d99e2a..19afafc 100644
--- a/data/seed_manifest_with_args.xml
+++ b/data/seed_manifest_with_args.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<gupdate protocol="2.0" signature="" xmlns="http://www.google.com/update2/install">

-  <install appguid="{283EAF47-8817-4c2b-A801-AD1FADFB7BAA}" needsadmin="true" iid="{874E4D29-8671-40C8-859F-4DECA4819999}" client="someclient" ap="1.0-dev"/>

-</gupdate>

+<?xml version="1.0" encoding="UTF-8"?>
+<gupdate protocol="2.0" signature="" xmlns="http://www.google.com/update2/install">
+  <install appguid="{283EAF47-8817-4c2b-A801-AD1FADFB7BAA}" needsadmin="true" iid="{874E4D29-8671-40C8-859F-4DECA4819999}" client="someclient" ap="1.0-dev"/>
+</gupdate>
diff --git a/data/server_manifest.xml b/data/server_manifest.xml
index ff9c06b..0f1a903 100644
--- a/data/server_manifest.xml
+++ b/data/server_manifest.xml
@@ -1,47 +1,47 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">

-<app appid="{D6B08267-B440-4C85-9F79-E195E80D9937}" status="ok">

-  <updatecheck status="ok"

-               codebase="http://dl.google.com/foo/1.0.101.0/test_foo_v1.0.101.0.msi"

-               size="80896"

-               hash="6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="

-               needsadmin="true"

-               successurl="http://testsuccessurl.com"

-               terminateallbrowsers="true"

-               onsuccess="exitsilently"/>

-  <data index="verboselogging" name="install" status="ok">

-  {

-    "distribution": {

-      "verbose_logging": true

-    }

-  }

-  </data>

-  <data index="skipfirstrun" name="install" status="ok">{

-    "distribution": {

-      "skip_first_run_ui": true,

-    }

-  }

-  </data>

-  <ping status="ok"/>

-</app>

-<app appid="{D6B08267-B440-4C85-9F79-E195E80D9936}" status="ok">

-  <updatecheck status="noupdate"/>

-  <ping status="ok"/>

-</app>

-<app appid="{104844D6-7DDA-460B-89F0-FBF8AFDD0A67}" status="ok">

-  <updatecheck status="ok"

-               codebase="http://dl.google.com/foo/1.0.102.0/user_foo_v1.0.102.0.msi"

-               size="630152"

-               hash="/XzRh1rpwqrDr6ashpmQnYZIzDI="

-               needsadmin="false"

-               arguments="/install"

-               unknownfeature="Tests behavior if server supports features client does not."/>

-  <ping status="ok"/>

-</app>

-<app appid="{884a01d9-fb67-430a-b491-28f960dd7309}" status="restricted"></app>

-<app appid="{8CF15C17-7BB5-433a-8E6C-C018D79D00B1}" status="ok">

-  <updatecheck status="error-osnotsupported"

-               errorurl="http://foo.google.com/support/article.py?id=12345&amp;hl=es-419&amp;os=5.1"/>

-  <ping status="ok"/>

-</app>

-</gupdate>

+<?xml version="1.0" encoding="UTF-8"?>
+<gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">
+<app appid="{D6B08267-B440-4C85-9F79-E195E80D9937}" status="ok">
+  <updatecheck status="ok"
+               codebase="http://dl.google.com/foo/1.0.101.0/test_foo_v1.0.101.0.msi"
+               size="80896"
+               hash="6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="
+               needsadmin="true"
+               successurl="http://testsuccessurl.com"
+               terminateallbrowsers="true"
+               onsuccess="exitsilently"/>
+  <data index="verboselogging" name="install" status="ok">
+  {
+    "distribution": {
+      "verbose_logging": true
+    }
+  }
+  </data>
+  <data index="skipfirstrun" name="install" status="ok">{
+    "distribution": {
+      "skip_first_run_ui": true,
+    }
+  }
+  </data>
+  <ping status="ok"/>
+</app>
+<app appid="{D6B08267-B440-4C85-9F79-E195E80D9936}" status="ok">
+  <updatecheck status="noupdate"/>
+  <ping status="ok"/>
+</app>
+<app appid="{104844D6-7DDA-460B-89F0-FBF8AFDD0A67}" status="ok">
+  <updatecheck status="ok"
+               codebase="http://dl.google.com/foo/1.0.102.0/user_foo_v1.0.102.0.msi"
+               size="630152"
+               hash="/XzRh1rpwqrDr6ashpmQnYZIzDI="
+               needsadmin="false"
+               arguments="/install"
+               unknownfeature="Tests behavior if server supports features client does not."/>
+  <ping status="ok"/>
+</app>
+<app appid="{884a01d9-fb67-430a-b491-28f960dd7309}" status="restricted"></app>
+<app appid="{8CF15C17-7BB5-433a-8E6C-C018D79D00B1}" status="ok">
+  <updatecheck status="error-osnotsupported"
+               errorurl="http://foo.google.com/support/article.py?id=12345&amp;hl=es-419&amp;os=5.1"/>
+  <ping status="ok"/>
+</app>
+</gupdate>
diff --git a/data/server_manifest_components.xml b/data/server_manifest_components.xml
index 813fb6f..4ce4bc1 100644
--- a/data/server_manifest_components.xml
+++ b/data/server_manifest_components.xml
@@ -1,55 +1,55 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">

-  <app appid="{D6B08267-B440-4C85-9F79-E195E80D9937}" status="ok">

-    <updatecheck status="ok"

-                 codebase="http://dl.google.com/foo/1.0.101.0/test_foo_v1.0.101.0.msi"

-                 size="80896"

-                 hash="6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="

-                 needsadmin="true"

-                 successurl="http://testsuccessurl.com"

-                 terminateallbrowsers="true"

-                 onsuccess="exitsilently"/>

-    <ping status="ok"/>

-    <components>

-      <component appid="{65C42695-84A0-41C4-B70F-D2786F674592}" status="ok">

-        <updatecheck status="ok"

-                     codebase="http://dl.google.com/foo/set_comp1.msi"

-                     size="66324"

-                     hash="6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="/>

-      </component>

-      <component appid="{B318029C-3607-48EB-8DBB-33E8BA17BAF1}" status="noupdate"/>

-      <component appid="{D76AE6FC-1633-4131-B782-896804795DCB}" status="ok">

-        <updatecheck status="ok"

-                     codebase="http://tools.google.com/happy/some_comp_inst.msi"

-                     size="829984"

-                     hash="6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="/>

-      </component>

-      <component appid="{67A52AEE-6E9F-4411-B425-F210B962CD6F}" status="noupdate"/>

-    </components>

-  </app>

-  <app appid="{D6B08267-B440-4C85-9F79-E195E80D9936}" status="ok">

-    <updatecheck status="noupdate"/>

-    <components>

-      <component appid="{115493D4-6B38-4314-81B7-26B61F1766A9}" status="ok">

-        <updatecheck status="ok"

-                     codebase="http://foo.google.com/bar/something.exe"

-                     size="12345"

-                     hash="some_hash_value"/>

-      </component>

-    </components>

-    <rlz status="ok"/>

-    <ping status="ok"/>

-  </app>

-  <app appid="{104844D6-7DDA-460B-89F0-FBF8AFDD0A67}" status="ok">

-    <updatecheck status="ok"

-                 codebase="http://dl.google.com/foo/1.0.102.0/user_foo_v1.0.102.0.msi"

-                 size="630152"

-                 hash="/XzRh1rpwqrDr6ashpmQnYZIzDI="

-                 needsadmin="false"

-                 arguments="/install"/>

-    <rlz parameter="1O1GGLGN__"/>

-    <ping status="ok"/>

-  </app>

-  <app appid="{884a01d9-fb67-430a-b491-28f960dd7309}" status="restricted"></app>

-</gupdate>

-

+<?xml version="1.0" encoding="UTF-8"?>
+<gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">
+  <app appid="{D6B08267-B440-4C85-9F79-E195E80D9937}" status="ok">
+    <updatecheck status="ok"
+                 codebase="http://dl.google.com/foo/1.0.101.0/test_foo_v1.0.101.0.msi"
+                 size="80896"
+                 hash="6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="
+                 needsadmin="true"
+                 successurl="http://testsuccessurl.com"
+                 terminateallbrowsers="true"
+                 onsuccess="exitsilently"/>
+    <ping status="ok"/>
+    <components>
+      <component appid="{65C42695-84A0-41C4-B70F-D2786F674592}" status="ok">
+        <updatecheck status="ok"
+                     codebase="http://dl.google.com/foo/set_comp1.msi"
+                     size="66324"
+                     hash="6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="/>
+      </component>
+      <component appid="{B318029C-3607-48EB-8DBB-33E8BA17BAF1}" status="noupdate"/>
+      <component appid="{D76AE6FC-1633-4131-B782-896804795DCB}" status="ok">
+        <updatecheck status="ok"
+                     codebase="http://tools.google.com/happy/some_comp_inst.msi"
+                     size="829984"
+                     hash="6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="/>
+      </component>
+      <component appid="{67A52AEE-6E9F-4411-B425-F210B962CD6F}" status="noupdate"/>
+    </components>
+  </app>
+  <app appid="{D6B08267-B440-4C85-9F79-E195E80D9936}" status="ok">
+    <updatecheck status="noupdate"/>
+    <components>
+      <component appid="{115493D4-6B38-4314-81B7-26B61F1766A9}" status="ok">
+        <updatecheck status="ok"
+                     codebase="http://foo.google.com/bar/something.exe"
+                     size="12345"
+                     hash="some_hash_value"/>
+      </component>
+    </components>
+    <rlz status="ok"/>
+    <ping status="ok"/>
+  </app>
+  <app appid="{104844D6-7DDA-460B-89F0-FBF8AFDD0A67}" status="ok">
+    <updatecheck status="ok"
+                 codebase="http://dl.google.com/foo/1.0.102.0/user_foo_v1.0.102.0.msi"
+                 size="630152"
+                 hash="/XzRh1rpwqrDr6ashpmQnYZIzDI="
+                 needsadmin="false"
+                 arguments="/install"/>
+    <rlz parameter="1O1GGLGN__"/>
+    <ping status="ok"/>
+  </app>
+  <app appid="{884a01d9-fb67-430a-b491-28f960dd7309}" status="restricted"></app>
+</gupdate>
+
diff --git a/data/server_manifest_one_app.xml b/data/server_manifest_one_app.xml
index 0d17a79..3b3fd6b 100644
--- a/data/server_manifest_one_app.xml
+++ b/data/server_manifest_one_app.xml
@@ -1,21 +1,21 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">

-<app appid="{CDABE316-39CD-43BA-8440-6D1E0547AEE6}" status="ok">

-  <updatecheck status="ok"

-               codebase="http://dl.google.com/foo/1.0.101.0/foo_installer.exe"

-               size="82128"

-               hash="U4gBMUVwIPQners8SriHpHaWEKk="

-               needsadmin="true"

-               successurl="http://testsuccessurl.com"

-               onsuccess="exitsilentlyonlaunchcmd"

-               terminateallbrowsers="true"/>

-  <data index="verboselogging" name="install" status="ok">

-  {

-    "distribution": {

-      "verbose_logging": true

-    }

-  }

-  </data>

-  <ping status="ok"/>

-</app>

-</gupdate>

+<?xml version="1.0" encoding="UTF-8"?>
+<gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">
+<app appid="{CDABE316-39CD-43BA-8440-6D1E0547AEE6}" status="ok">
+  <updatecheck status="ok"
+               codebase="http://dl.google.com/foo/1.0.101.0/foo_installer.exe"
+               size="82128"
+               hash="U4gBMUVwIPQners8SriHpHaWEKk="
+               needsadmin="true"
+               successurl="http://testsuccessurl.com"
+               onsuccess="exitsilentlyonlaunchcmd"
+               terminateallbrowsers="true"/>
+  <data index="verboselogging" name="install" status="ok">
+  {
+    "distribution": {
+      "verbose_logging": true
+    }
+  }
+  </data>
+  <ping status="ok"/>
+</app>
+</gupdate>
diff --git a/enterprise/build.scons b/enterprise/build.scons
index 4bda4ab..73c77d7 100644
--- a/enterprise/build.scons
+++ b/enterprise/build.scons
@@ -1,47 +1,47 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-import os

-from enterprise import public_apps

-from enterprise import generate_group_policy_template

-

-Import('env')

-

-# Build the Group Policy template (.adm) file.

-

-_adm_contents = generate_group_policy_template.GenerateGroupPolicyTemplate(

-    public_apps.EXTERNAL_APPS)

-

-def _WriteAdmFile(target, source, env):

-  f = open(env.File(target[0]).abspath, 'w')

-  f.write(env['write_data'])

-  f.close()

-  return 0

-

-adm_output = env.Command(

-    target='$STAGING_DIR/GoogleUpdate.adm',

-    source=[],

-    action=_WriteAdmFile,

-    write_data=_adm_contents

-)

-

-# Force the ADM file to rebuild whenever the script or public_apps data change.

-env.Depends(adm_output,

-            ['generate_group_policy_template.py', 'public_apps.py'])

-

-if not env.Bit('official_installers'):

-  env.BuildSConscript('installer')

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+import os
+from enterprise import public_apps
+from enterprise import generate_group_policy_template
+
+Import('env')
+
+# Build the Group Policy template (.adm) file.
+
+_adm_contents = generate_group_policy_template.GenerateGroupPolicyTemplate(
+    public_apps.EXTERNAL_APPS)
+
+def _WriteAdmFile(target, source, env):
+  f = open(env.File(target[0]).abspath, 'w')
+  f.write(env['write_data'])
+  f.close()
+  return 0
+
+adm_output = env.Command(
+    target='$STAGING_DIR/GoogleUpdate.adm',
+    source=[],
+    action=_WriteAdmFile,
+    write_data=_adm_contents
+)
+
+# Force the ADM file to rebuild whenever the script or public_apps data change.
+env.Depends(adm_output,
+            ['generate_group_policy_template.py', 'public_apps.py'])
+
+if not env.Bit('official_installers'):
+  env.BuildSConscript('installer')
diff --git a/enterprise/const_group_policy.h b/enterprise/const_group_policy.h
index be60718..d639673 100644
--- a/enterprise/const_group_policy.h
+++ b/enterprise/const_group_policy.h
@@ -1,49 +1,49 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_ENTERPRISE_CONST_GROUP_POLICY_H__

-#define OMAHA_ENTERPRISE_CONST_GROUP_POLICY_H__

-

-#include <tchar.h>

-#include "omaha/common/constants.h"

-

-namespace omaha {

-

-// Key containing Google Update Group Policy settings. All policies are in HKLM.

-const TCHAR* const kRegKeyGoopdateGroupPolicy =

-    MACHINE_KEY GOOPDATE_POLICIES_RELATIVE;

-

-// Preferences Categroy.

-const TCHAR* const kRegValueAutoUpdateCheckPeriodOverrideMinutes =

-    _T("AutoUpdateCheckPeriodMinutes");

-

-// Applications Categroy.

-// The prefix strings have the app's GUID appended to them.

-const TCHAR* const kRegValueInstallAppsDefault  = _T("InstallDefault");

-const TCHAR* const kRegValueInstallAppPrefix    = _T("Install");

-const TCHAR* const kRegValueUpdateAppsDefault   = _T("UpdateDefault");

-const TCHAR* const kRegValueUpdateAppPrefix     = _T("Update");

-

-const bool kInstallPolicyDefault    = true;

-const bool kUpdatePolicyDefault     = true;

-

-const int kPolicyDisabled           = 0;

-const int kPolicyEnabled            = 1;

-const int kPolicyManualUpdatesOnly  = 2;

-

-}  // namespace omaha

-

-#endif  // OMAHA_ENTERPRISE_CONST_GROUP_POLICY_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_ENTERPRISE_CONST_GROUP_POLICY_H__
+#define OMAHA_ENTERPRISE_CONST_GROUP_POLICY_H__
+
+#include <tchar.h>
+#include "omaha/common/constants.h"
+
+namespace omaha {
+
+// Key containing Google Update Group Policy settings. All policies are in HKLM.
+const TCHAR* const kRegKeyGoopdateGroupPolicy =
+    MACHINE_KEY GOOPDATE_POLICIES_RELATIVE;
+
+// Preferences Categroy.
+const TCHAR* const kRegValueAutoUpdateCheckPeriodOverrideMinutes =
+    _T("AutoUpdateCheckPeriodMinutes");
+
+// Applications Categroy.
+// The prefix strings have the app's GUID appended to them.
+const TCHAR* const kRegValueInstallAppsDefault  = _T("InstallDefault");
+const TCHAR* const kRegValueInstallAppPrefix    = _T("Install");
+const TCHAR* const kRegValueUpdateAppsDefault   = _T("UpdateDefault");
+const TCHAR* const kRegValueUpdateAppPrefix     = _T("Update");
+
+const bool kInstallPolicyDefault    = true;
+const bool kUpdatePolicyDefault     = true;
+
+const int kPolicyDisabled           = 0;
+const int kPolicyEnabled            = 1;
+const int kPolicyManualUpdatesOnly  = 2;
+
+}  // namespace omaha
+
+#endif  // OMAHA_ENTERPRISE_CONST_GROUP_POLICY_H__
+
diff --git a/enterprise/generate_group_policy_template.py b/enterprise/generate_group_policy_template.py
index cd66da7..9cca309 100644
--- a/enterprise/generate_group_policy_template.py
+++ b/enterprise/generate_group_policy_template.py
@@ -1,406 +1,406 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-"""Generates a Group Policy template file for Google Update policies.

-

-This script only works on Windows because gpedit.msc requires Windows-style

-line endings (\r\n).

-

-To unit test this module, just run the file from the command line.

-"""

-

-import filecmp

-import os

-import sys

-

-

-HORIZONTAL_RULE = ';%s\n' % ('-' * 78)

-MAIN_POLICY_KEY = "Software\Policies\Google\Update"

-

-# pylint: disable-msg=C6004

-HEADER = """\

-CLASS MACHINE

-  CATEGORY !!Cat_Google

-    CATEGORY !!Cat_GoogleUpdate

-      KEYNAME \"""" + MAIN_POLICY_KEY + """\"

-      EXPLAIN !!Explain_GoogleUpdate

-"""

-

-PREFERENCES = """

-      CATEGORY !!Cat_Preferences

-        KEYNAME \"""" + MAIN_POLICY_KEY + """\"

-        EXPLAIN !!Explain_Preferences

-

-        POLICY !!Pol_AutoUpdateCheckPeriod

-          #if version >= 4

-            SUPPORTED !!Sup_GoogleUpdate1_2_145_5

-          #endif

-          EXPLAIN !!Explain_AutoUpdateCheckPeriod

-          PART !!Part_AutoUpdateCheckPeriod NUMERIC

-            VALUENAME AutoUpdateCheckPeriodMinutes

-            DEFAULT 1400  ; 23 hours 20 minutes.

-            MIN 60

-            MAX 43200     ; 30 days.

-            SPIN 60       ; Increment in hour chunks.

-          END PART

-          PART !!Part_DisableAllAutoUpdateChecks CHECKBOX

-            VALUENAME DisableAutoUpdateChecksCheckboxValue  ; Required, unused.

-            ACTIONLISTON

-              ; Writes over Part_AutoUpdateCheckPeriod. Assumes this runs last.

-              VALUENAME AutoUpdateCheckPeriodMinutes VALUE NUMERIC 0

-            END ACTIONLISTON

-            ACTIONLISTOFF

-              ; Do nothing. Let Part_AutoUpdateCheckPeriod take effect.

-            END ACTIONLISTOFF

-            VALUEOFF  NUMERIC 0

-            VALUEON   NUMERIC 1

-          END PART

-        END POLICY

-

-      END CATEGORY  ; Preferences

-"""

-

-APPLICATIONS_HEADER = """

-      CATEGORY !!Cat_Applications

-        KEYNAME \"""" + MAIN_POLICY_KEY + """\"

-        EXPLAIN !!Explain_Applications

-"""

-

-UPDATE_POLICY_ITEMLIST = """\

-            ITEMLIST

-              NAME  !!Name_AutomaticUpdates

-              VALUE NUMERIC 1

-              NAME  !!Name_ManualUpdates

-              VALUE NUMERIC 2

-              NAME  !!Name_UpdatesDisabled

-              VALUE NUMERIC 0

-            END ITEMLIST

-            REQUIRED"""

-

-APPLICATION_DEFAULTS = ("""

-        POLICY !!Pol_DefaultAllowInstallation

-          #if version >= 4

-            SUPPORTED !!Sup_GoogleUpdate1_2_145_5

-          #endif

-          EXPLAIN !!Explain_DefaultAllowInstallation

-          VALUENAME InstallDefault

-          VALUEOFF  NUMERIC 0

-          VALUEON   NUMERIC 1

-        END POLICY

-

-        POLICY !!Pol_DefaultUpdatePolicy

-          #if version >= 4

-            SUPPORTED !!Sup_GoogleUpdate1_2_145_5

-          #endif

-          EXPLAIN !!Explain_DefaultUpdatePolicy

-          PART !!Part_UpdatePolicy DROPDOWNLIST

-            VALUENAME UpdateDefault

-""" +

-UPDATE_POLICY_ITEMLIST + """

-          END PART

-        END POLICY

-""")

-

-APP_POLICIES_TEMPLATE = ("""

-        CATEGORY !!Cat_$AppLegalId$

-          KEYNAME \"""" + MAIN_POLICY_KEY + """\"

-

-          POLICY !!Pol_AllowInstallation

-            #if version >= 4

-              SUPPORTED !!Sup_GoogleUpdate1_2_145_5

-            #endif

-            EXPLAIN !!Explain_Install$AppLegalId$

-            VALUENAME Install$AppGuid$

-            VALUEOFF  NUMERIC 0

-            VALUEON   NUMERIC 1

-          END POLICY

-

-          POLICY !!Pol_UpdatePolicy

-            #if version >= 4

-              SUPPORTED !!Sup_GoogleUpdate1_2_145_5

-            #endif

-            EXPLAIN !!Explain_AutoUpdate$AppLegalId$

-            PART !!Part_UpdatePolicy DROPDOWNLIST

-              VALUENAME Update$AppGuid$

-""" +

-UPDATE_POLICY_ITEMLIST.replace('            ', '              ') + """

-            END PART

-          END POLICY

-

-        END CATEGORY  ; $AppName$

-""")

-

-APPLICATIONS_FOOTER = """

-      END CATEGORY  ; Applications

-

-    END CATEGORY  ; GoogleUpdate

-

-  END CATEGORY  ; Google

-"""

-

-# Policy names that are used in multiple locations.

-ALLOW_INSTALLATION_POLICY = 'Allow installation'

-DEFAULT_ALLOW_INSTALLATION_POLICY = ALLOW_INSTALLATION_POLICY + ' default'

-UPDATE_POLICY = 'Update policy override'

-DEFAULT_UPDATE_POLICY = UPDATE_POLICY + ' default'

-

-# Update policy options that are used in multiple locations.

-AUTOMATIC_UPDATES = 'Automatic silent updates'

-MANUAL_UPDATES = 'Manual updates only'

-UPDATES_DISABLED = 'Updates disabled'

-

-# Category names that are used in multiple locations.

-PREFERENCES_CATEGORY = 'Preferences'

-APPLICATIONS_CATEGORY = 'Applications'

-

-# The captions for update policy were selected such that they appear in order of

-# decreasing preference when organized alphabetically in gpedit.

-STRINGS_HEADER_AND_COMMON = ('\n' +

-HORIZONTAL_RULE +

-"""

-[strings]

-Sup_GoogleUpdate1_2_145_5=At least Google Update 1.2.145.5

-

-Cat_Google=Google

-Cat_GoogleUpdate=Google Update

-Cat_Preferences=""" + PREFERENCES_CATEGORY + """

-Cat_Applications=""" + APPLICATIONS_CATEGORY + """

-

-Pol_AutoUpdateCheckPeriod=Auto-update check period override

-Pol_DefaultAllowInstallation=""" + DEFAULT_ALLOW_INSTALLATION_POLICY + """

-Pol_AllowInstallation=""" + ALLOW_INSTALLATION_POLICY + """

-Pol_DefaultUpdatePolicy=""" + DEFAULT_UPDATE_POLICY + """

-Pol_UpdatePolicy=""" + UPDATE_POLICY + """

-

-Part_AutoUpdateCheckPeriod=Minutes between update checks

-Part_DisableAllAutoUpdateChecks=Disable all auto-update checks (not recommended)

-Part_UpdatePolicy=Policy

-

-Name_AutomaticUpdates=""" + AUTOMATIC_UPDATES + """ (recommended)

-Name_ManualUpdates=""" + MANUAL_UPDATES + """

-Name_UpdatesDisabled=""" + UPDATES_DISABLED + """

-

-""")

-

-STRINGS_APP_NAME_TEMPLATE = """\

-Cat_$AppLegalId$=$AppName$

-"""

-

-# pylint: disable-msg=C6310

-# pylint: disable-msg=C6013

-

-# "application's" should be preceeded by a different word in different contexts.

-# The word is specified by replacing the $PreApplicationWord$ token.

-STRINGS_UPDATE_POLICY_OPTIONS = """\

-    \\n\\nOptions:\\

-    \\n - """ + AUTOMATIC_UPDATES + """: Updates are automatically applied when they are found via the periodic update check.\\

-    \\n - """ + MANUAL_UPDATES + """: Updates are only applied when the user does a manual update check. (Not all apps provide an interface for this.)\\

-    \\n - """ + UPDATES_DISABLED + """: Never apply updates.\\

-    \\n\\nIf you select manual updates, you should periodically check for updates using $PreApplicationWord$ application's manual update mechanism if available. If you disable updates, you should periodically check for updates and distribute them to users."""

-

-STRINGS_COMMON_EXPLANATIONS = ("""

-Explain_GoogleUpdate=Policies to control the installation and updating of Google applications that use Google Update/Google Installer.

-

-""" +

-HORIZONTAL_RULE +

-'; ' + PREFERENCES_CATEGORY + '\n' +

-HORIZONTAL_RULE + """

-Explain_Preferences=General policies for Google Update.

-

-Explain_AutoUpdateCheckPeriod=Minimum number of minutes between automatic update checks.

-

-""" +

-HORIZONTAL_RULE +

-'; ' + APPLICATIONS_CATEGORY + '\n' +

-HORIZONTAL_RULE + """

-Explain_Applications=Policies for individual applications.\\

-    \\n\\nAn updated ADM template will be required to support Google applications released in the future.

-

-Explain_DefaultAllowInstallation=Specifies the default behavior for whether Google software can be installed using Google Update/Google Installer.\\

-    \\n\\nCan be overridden by the \"""" + ALLOW_INSTALLATION_POLICY + """\" for individual applications.\\

-    \\n\\nOnly affects installation of Google software using Google Update/Google Installer. Cannot prevent running the application installer directly or installation of Google software that does not use Google Update/Google Installer for installation.

-

-Explain_DefaultUpdatePolicy=Specifies the default policy for software updates from Google.\\

-    \\n\\nCan be overridden by the \"""" + UPDATE_POLICY + """\" for individual applications.\\

-""" +

-STRINGS_UPDATE_POLICY_OPTIONS.replace('$PreApplicationWord$', 'each') + """\\

-    \\n\\nOnly affects updates for Google software that uses Google Update for updates. Does not prevent auto-updates of Google software that does not use Google Update for updates.\\

-    \\n\\nUpdates for Google Update are not affected by this setting; Google Update will continue to update itself while it is installed.\\

-    \\n\\nWARNING: Disabing updates will also prevent updates of any new Google applications released in the future, possibly including dependencies for future versions of installed applications.

-

-""" +

-HORIZONTAL_RULE +

-'; Individual Applications\n' +

-HORIZONTAL_RULE)

-

-STRINGS_APP_POLICY_EXPLANATIONS_TEMPLATE = ("""

-; $AppName$

-Explain_Install$AppLegalId$=Specifies whether $AppName$ can be installed using Google Update/Google Installer.\\

-    \\n\\nIf this policy is not configured, $AppName$ can be installed as specified by \"""" + DEFAULT_ALLOW_INSTALLATION_POLICY + """\".

-

-Explain_AutoUpdate$AppLegalId$=Specifies how Google Update handles available $AppName$ updates from Google.\\

-    \\n\\nIf this policy is not configured, Google Update handles available updates as specified by \"""" + DEFAULT_UPDATE_POLICY + """\".\\

-""" +

-STRINGS_UPDATE_POLICY_OPTIONS.replace('$PreApplicationWord$', 'the') + '$AppUpdateExplainExtra$\n')

-

-# pylint: enable-msg=C6013

-# pylint: enable-msg=C6310

-# pylint: enable-msg=C6004

-

-

-def GenerateGroupPolicyTemplate(apps):

-  """Generates a Group Policy template (ADM format)for the specified apps.

-

-  Args:

-    apps: A list of tuples containing information about each app.

-        Each element of the list is a tuple of:

-          * app name

-          * app ID

-          * optional string to append to the auto-update explanation

-            - Should start with a space or double new line (\n\n).

-    target_path: Output path of the .ADM template file.

-

-  Returns:

-    String containing the contents of the .ADM file.

-  """

-

-  def _CreateLegalIdentifier(input_string):

-    """Converts input_string to a legal identifier for ADM files.

-

-    Changes some characters that do not necessarily cause problems and may not

-    handle all cases.

-

-    Args:

-      input_string: Text to convert to a legal identifier.

-

-    Returns:

-      String containing a legal identifier based on input_string.

-    """

-

-    # pylint: disable-msg=C6004

-    return (input_string.replace(' ', '')

-                        .replace('&', '')

-                        .replace('=', '')

-                        .replace(';', '')

-                        .replace(',', '')

-                        .replace('.', '')

-                        .replace('?', '')

-                        .replace('=', '')

-                        .replace(';', '')

-                        .replace("'", '')

-                        .replace('"', '')

-                        .replace('\\', '')

-                        .replace('/', '')

-                        .replace('(', '')

-                        .replace(')', '')

-                        .replace('[', '')

-                        .replace(']', '')

-                        .replace('{', '')

-                        .replace('}', '')

-                        .replace('-', '')

-                        .replace('!', '')

-                        .replace('@', '')

-                        .replace('#', '')

-                        .replace('$', '')

-                        .replace('%', '')

-                        .replace('^', '')

-                        .replace('*', '')

-                        .replace('+', ''))

-    # pylint: enable-msg=C6004

-

-  def _WriteTemplateForApp(template, app):

-    """Writes the text for the specified app based on the template.

-

-    Replaces $AppName$, $AppLegalId$, $AppGuid$, and $AppUpdateExplainExtra$.

-

-    Args:

-      template: text to process and write.

-      app: tuple containing information about the app.

-

-    Returns:

-      String containing a copy of the template populated with app-specific

-      strings.

-    """

-

-    (app_name, app_guid, update_explain_extra) = app

-    # pylint: disable-msg=C6004

-    return (template.replace('$AppName$', app_name)

-                    .replace('$AppLegalId$', _CreateLegalIdentifier(app_name))

-                    .replace('$AppGuid$', app_guid)

-                    .replace('$AppUpdateExplainExtra$', update_explain_extra)

-           )

-    # pylint: enable-msg=C6004

-

-  def _WriteTemplateForAllApps(template, apps):

-    """Writes a copy of the template for each of the specified apps.

-

-    Args:

-      template: text to process and write.

-      apps: list of tuples containing information about the apps.

-

-    Returns:

-      String containing concatenated copies of the template for each app in

-      apps, each populated with the appropriate app-specific strings.

-    """

-

-    content = [_WriteTemplateForApp(template, app) for app in apps]

-    return ''.join(content)

-

-  target_contents = [

-      HEADER,

-      PREFERENCES,

-      APPLICATIONS_HEADER,

-      APPLICATION_DEFAULTS,

-      _WriteTemplateForAllApps(APP_POLICIES_TEMPLATE, apps),

-      APPLICATIONS_FOOTER,

-      STRINGS_HEADER_AND_COMMON,

-      _WriteTemplateForAllApps(STRINGS_APP_NAME_TEMPLATE, apps),

-      STRINGS_COMMON_EXPLANATIONS,

-      _WriteTemplateForAllApps(STRINGS_APP_POLICY_EXPLANATIONS_TEMPLATE, apps),

-      ]

-

-  return ''.join(target_contents)

-

-

-# Run a unit test when the module is run directly.

-if __name__ == '__main__':

-  TEST_APPS = [

-      ('Google Chrome',

-       '{8A69D345-D564-463C-AFF1-A69D9E530F96}',

-       ' Check http://www.google.com/chrome/.'),

-      ('Google Earth',

-       '{74AF07D8-FB8F-4D51-8AC7-927721D56EBB}',

-       ' Check http://earth.google.com/.'),

-      ]

-  TEST_GOLD_FILENAME = 'test_gold.adm'

-  TEST_OUTPUT_FILENAME = 'test_out.adm'

-

-  module_dir = os.path.abspath(os.path.dirname(__file__))

-  gold_path = os.path.join(module_dir, TEST_GOLD_FILENAME)

-  output_path = os.path.join(module_dir, TEST_OUTPUT_FILENAME)

-

-  test_target_contents = GenerateGroupPolicyTemplate(TEST_APPS)

-

-  target = open(output_path, 'wt')

-  target.write(test_target_contents)

-  target.close()

-

-  if filecmp.cmp(gold_path, output_path, shallow=False):

-    print 'PASS: Contents equal.'

-  else:

-    print 'FAIL: Contents not equal.'

-    sys.exit(-1)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+"""Generates a Group Policy template file for Google Update policies.
+
+This script only works on Windows because gpedit.msc requires Windows-style
+line endings (\r\n).
+
+To unit test this module, just run the file from the command line.
+"""
+
+import filecmp
+import os
+import sys
+
+
+HORIZONTAL_RULE = ';%s\n' % ('-' * 78)
+MAIN_POLICY_KEY = "Software\Policies\Google\Update"
+
+# pylint: disable-msg=C6004
+HEADER = """\
+CLASS MACHINE
+  CATEGORY !!Cat_Google
+    CATEGORY !!Cat_GoogleUpdate
+      KEYNAME \"""" + MAIN_POLICY_KEY + """\"
+      EXPLAIN !!Explain_GoogleUpdate
+"""
+
+PREFERENCES = """
+      CATEGORY !!Cat_Preferences
+        KEYNAME \"""" + MAIN_POLICY_KEY + """\"
+        EXPLAIN !!Explain_Preferences
+
+        POLICY !!Pol_AutoUpdateCheckPeriod
+          #if version >= 4
+            SUPPORTED !!Sup_GoogleUpdate1_2_145_5
+          #endif
+          EXPLAIN !!Explain_AutoUpdateCheckPeriod
+          PART !!Part_AutoUpdateCheckPeriod NUMERIC
+            VALUENAME AutoUpdateCheckPeriodMinutes
+            DEFAULT 1400  ; 23 hours 20 minutes.
+            MIN 60
+            MAX 43200     ; 30 days.
+            SPIN 60       ; Increment in hour chunks.
+          END PART
+          PART !!Part_DisableAllAutoUpdateChecks CHECKBOX
+            VALUENAME DisableAutoUpdateChecksCheckboxValue  ; Required, unused.
+            ACTIONLISTON
+              ; Writes over Part_AutoUpdateCheckPeriod. Assumes this runs last.
+              VALUENAME AutoUpdateCheckPeriodMinutes VALUE NUMERIC 0
+            END ACTIONLISTON
+            ACTIONLISTOFF
+              ; Do nothing. Let Part_AutoUpdateCheckPeriod take effect.
+            END ACTIONLISTOFF
+            VALUEOFF  NUMERIC 0
+            VALUEON   NUMERIC 1
+          END PART
+        END POLICY
+
+      END CATEGORY  ; Preferences
+"""
+
+APPLICATIONS_HEADER = """
+      CATEGORY !!Cat_Applications
+        KEYNAME \"""" + MAIN_POLICY_KEY + """\"
+        EXPLAIN !!Explain_Applications
+"""
+
+UPDATE_POLICY_ITEMLIST = """\
+            ITEMLIST
+              NAME  !!Name_AutomaticUpdates
+              VALUE NUMERIC 1
+              NAME  !!Name_ManualUpdates
+              VALUE NUMERIC 2
+              NAME  !!Name_UpdatesDisabled
+              VALUE NUMERIC 0
+            END ITEMLIST
+            REQUIRED"""
+
+APPLICATION_DEFAULTS = ("""
+        POLICY !!Pol_DefaultAllowInstallation
+          #if version >= 4
+            SUPPORTED !!Sup_GoogleUpdate1_2_145_5
+          #endif
+          EXPLAIN !!Explain_DefaultAllowInstallation
+          VALUENAME InstallDefault
+          VALUEOFF  NUMERIC 0
+          VALUEON   NUMERIC 1
+        END POLICY
+
+        POLICY !!Pol_DefaultUpdatePolicy
+          #if version >= 4
+            SUPPORTED !!Sup_GoogleUpdate1_2_145_5
+          #endif
+          EXPLAIN !!Explain_DefaultUpdatePolicy
+          PART !!Part_UpdatePolicy DROPDOWNLIST
+            VALUENAME UpdateDefault
+""" +
+UPDATE_POLICY_ITEMLIST + """
+          END PART
+        END POLICY
+""")
+
+APP_POLICIES_TEMPLATE = ("""
+        CATEGORY !!Cat_$AppLegalId$
+          KEYNAME \"""" + MAIN_POLICY_KEY + """\"
+
+          POLICY !!Pol_AllowInstallation
+            #if version >= 4
+              SUPPORTED !!Sup_GoogleUpdate1_2_145_5
+            #endif
+            EXPLAIN !!Explain_Install$AppLegalId$
+            VALUENAME Install$AppGuid$
+            VALUEOFF  NUMERIC 0
+            VALUEON   NUMERIC 1
+          END POLICY
+
+          POLICY !!Pol_UpdatePolicy
+            #if version >= 4
+              SUPPORTED !!Sup_GoogleUpdate1_2_145_5
+            #endif
+            EXPLAIN !!Explain_AutoUpdate$AppLegalId$
+            PART !!Part_UpdatePolicy DROPDOWNLIST
+              VALUENAME Update$AppGuid$
+""" +
+UPDATE_POLICY_ITEMLIST.replace('            ', '              ') + """
+            END PART
+          END POLICY
+
+        END CATEGORY  ; $AppName$
+""")
+
+APPLICATIONS_FOOTER = """
+      END CATEGORY  ; Applications
+
+    END CATEGORY  ; GoogleUpdate
+
+  END CATEGORY  ; Google
+"""
+
+# Policy names that are used in multiple locations.
+ALLOW_INSTALLATION_POLICY = 'Allow installation'
+DEFAULT_ALLOW_INSTALLATION_POLICY = ALLOW_INSTALLATION_POLICY + ' default'
+UPDATE_POLICY = 'Update policy override'
+DEFAULT_UPDATE_POLICY = UPDATE_POLICY + ' default'
+
+# Update policy options that are used in multiple locations.
+AUTOMATIC_UPDATES = 'Automatic silent updates'
+MANUAL_UPDATES = 'Manual updates only'
+UPDATES_DISABLED = 'Updates disabled'
+
+# Category names that are used in multiple locations.
+PREFERENCES_CATEGORY = 'Preferences'
+APPLICATIONS_CATEGORY = 'Applications'
+
+# The captions for update policy were selected such that they appear in order of
+# decreasing preference when organized alphabetically in gpedit.
+STRINGS_HEADER_AND_COMMON = ('\n' +
+HORIZONTAL_RULE +
+"""
+[strings]
+Sup_GoogleUpdate1_2_145_5=At least Google Update 1.2.145.5
+
+Cat_Google=Google
+Cat_GoogleUpdate=Google Update
+Cat_Preferences=""" + PREFERENCES_CATEGORY + """
+Cat_Applications=""" + APPLICATIONS_CATEGORY + """
+
+Pol_AutoUpdateCheckPeriod=Auto-update check period override
+Pol_DefaultAllowInstallation=""" + DEFAULT_ALLOW_INSTALLATION_POLICY + """
+Pol_AllowInstallation=""" + ALLOW_INSTALLATION_POLICY + """
+Pol_DefaultUpdatePolicy=""" + DEFAULT_UPDATE_POLICY + """
+Pol_UpdatePolicy=""" + UPDATE_POLICY + """
+
+Part_AutoUpdateCheckPeriod=Minutes between update checks
+Part_DisableAllAutoUpdateChecks=Disable all auto-update checks (not recommended)
+Part_UpdatePolicy=Policy
+
+Name_AutomaticUpdates=""" + AUTOMATIC_UPDATES + """ (recommended)
+Name_ManualUpdates=""" + MANUAL_UPDATES + """
+Name_UpdatesDisabled=""" + UPDATES_DISABLED + """
+
+""")
+
+STRINGS_APP_NAME_TEMPLATE = """\
+Cat_$AppLegalId$=$AppName$
+"""
+
+# pylint: disable-msg=C6310
+# pylint: disable-msg=C6013
+
+# "application's" should be preceeded by a different word in different contexts.
+# The word is specified by replacing the $PreApplicationWord$ token.
+STRINGS_UPDATE_POLICY_OPTIONS = """\
+    \\n\\nOptions:\\
+    \\n - """ + AUTOMATIC_UPDATES + """: Updates are automatically applied when they are found via the periodic update check.\\
+    \\n - """ + MANUAL_UPDATES + """: Updates are only applied when the user does a manual update check. (Not all apps provide an interface for this.)\\
+    \\n - """ + UPDATES_DISABLED + """: Never apply updates.\\
+    \\n\\nIf you select manual updates, you should periodically check for updates using $PreApplicationWord$ application's manual update mechanism if available. If you disable updates, you should periodically check for updates and distribute them to users."""
+
+STRINGS_COMMON_EXPLANATIONS = ("""
+Explain_GoogleUpdate=Policies to control the installation and updating of Google applications that use Google Update/Google Installer.
+
+""" +
+HORIZONTAL_RULE +
+'; ' + PREFERENCES_CATEGORY + '\n' +
+HORIZONTAL_RULE + """
+Explain_Preferences=General policies for Google Update.
+
+Explain_AutoUpdateCheckPeriod=Minimum number of minutes between automatic update checks.
+
+""" +
+HORIZONTAL_RULE +
+'; ' + APPLICATIONS_CATEGORY + '\n' +
+HORIZONTAL_RULE + """
+Explain_Applications=Policies for individual applications.\\
+    \\n\\nAn updated ADM template will be required to support Google applications released in the future.
+
+Explain_DefaultAllowInstallation=Specifies the default behavior for whether Google software can be installed using Google Update/Google Installer.\\
+    \\n\\nCan be overridden by the \"""" + ALLOW_INSTALLATION_POLICY + """\" for individual applications.\\
+    \\n\\nOnly affects installation of Google software using Google Update/Google Installer. Cannot prevent running the application installer directly or installation of Google software that does not use Google Update/Google Installer for installation.
+
+Explain_DefaultUpdatePolicy=Specifies the default policy for software updates from Google.\\
+    \\n\\nCan be overridden by the \"""" + UPDATE_POLICY + """\" for individual applications.\\
+""" +
+STRINGS_UPDATE_POLICY_OPTIONS.replace('$PreApplicationWord$', 'each') + """\\
+    \\n\\nOnly affects updates for Google software that uses Google Update for updates. Does not prevent auto-updates of Google software that does not use Google Update for updates.\\
+    \\n\\nUpdates for Google Update are not affected by this setting; Google Update will continue to update itself while it is installed.\\
+    \\n\\nWARNING: Disabing updates will also prevent updates of any new Google applications released in the future, possibly including dependencies for future versions of installed applications.
+
+""" +
+HORIZONTAL_RULE +
+'; Individual Applications\n' +
+HORIZONTAL_RULE)
+
+STRINGS_APP_POLICY_EXPLANATIONS_TEMPLATE = ("""
+; $AppName$
+Explain_Install$AppLegalId$=Specifies whether $AppName$ can be installed using Google Update/Google Installer.\\
+    \\n\\nIf this policy is not configured, $AppName$ can be installed as specified by \"""" + DEFAULT_ALLOW_INSTALLATION_POLICY + """\".
+
+Explain_AutoUpdate$AppLegalId$=Specifies how Google Update handles available $AppName$ updates from Google.\\
+    \\n\\nIf this policy is not configured, Google Update handles available updates as specified by \"""" + DEFAULT_UPDATE_POLICY + """\".\\
+""" +
+STRINGS_UPDATE_POLICY_OPTIONS.replace('$PreApplicationWord$', 'the') + '$AppUpdateExplainExtra$\n')
+
+# pylint: enable-msg=C6013
+# pylint: enable-msg=C6310
+# pylint: enable-msg=C6004
+
+
+def GenerateGroupPolicyTemplate(apps):
+  """Generates a Group Policy template (ADM format)for the specified apps.
+
+  Args:
+    apps: A list of tuples containing information about each app.
+        Each element of the list is a tuple of:
+          * app name
+          * app ID
+          * optional string to append to the auto-update explanation
+            - Should start with a space or double new line (\n\n).
+    target_path: Output path of the .ADM template file.
+
+  Returns:
+    String containing the contents of the .ADM file.
+  """
+
+  def _CreateLegalIdentifier(input_string):
+    """Converts input_string to a legal identifier for ADM files.
+
+    Changes some characters that do not necessarily cause problems and may not
+    handle all cases.
+
+    Args:
+      input_string: Text to convert to a legal identifier.
+
+    Returns:
+      String containing a legal identifier based on input_string.
+    """
+
+    # pylint: disable-msg=C6004
+    return (input_string.replace(' ', '')
+                        .replace('&', '')
+                        .replace('=', '')
+                        .replace(';', '')
+                        .replace(',', '')
+                        .replace('.', '')
+                        .replace('?', '')
+                        .replace('=', '')
+                        .replace(';', '')
+                        .replace("'", '')
+                        .replace('"', '')
+                        .replace('\\', '')
+                        .replace('/', '')
+                        .replace('(', '')
+                        .replace(')', '')
+                        .replace('[', '')
+                        .replace(']', '')
+                        .replace('{', '')
+                        .replace('}', '')
+                        .replace('-', '')
+                        .replace('!', '')
+                        .replace('@', '')
+                        .replace('#', '')
+                        .replace('$', '')
+                        .replace('%', '')
+                        .replace('^', '')
+                        .replace('*', '')
+                        .replace('+', ''))
+    # pylint: enable-msg=C6004
+
+  def _WriteTemplateForApp(template, app):
+    """Writes the text for the specified app based on the template.
+
+    Replaces $AppName$, $AppLegalId$, $AppGuid$, and $AppUpdateExplainExtra$.
+
+    Args:
+      template: text to process and write.
+      app: tuple containing information about the app.
+
+    Returns:
+      String containing a copy of the template populated with app-specific
+      strings.
+    """
+
+    (app_name, app_guid, update_explain_extra) = app
+    # pylint: disable-msg=C6004
+    return (template.replace('$AppName$', app_name)
+                    .replace('$AppLegalId$', _CreateLegalIdentifier(app_name))
+                    .replace('$AppGuid$', app_guid)
+                    .replace('$AppUpdateExplainExtra$', update_explain_extra)
+           )
+    # pylint: enable-msg=C6004
+
+  def _WriteTemplateForAllApps(template, apps):
+    """Writes a copy of the template for each of the specified apps.
+
+    Args:
+      template: text to process and write.
+      apps: list of tuples containing information about the apps.
+
+    Returns:
+      String containing concatenated copies of the template for each app in
+      apps, each populated with the appropriate app-specific strings.
+    """
+
+    content = [_WriteTemplateForApp(template, app) for app in apps]
+    return ''.join(content)
+
+  target_contents = [
+      HEADER,
+      PREFERENCES,
+      APPLICATIONS_HEADER,
+      APPLICATION_DEFAULTS,
+      _WriteTemplateForAllApps(APP_POLICIES_TEMPLATE, apps),
+      APPLICATIONS_FOOTER,
+      STRINGS_HEADER_AND_COMMON,
+      _WriteTemplateForAllApps(STRINGS_APP_NAME_TEMPLATE, apps),
+      STRINGS_COMMON_EXPLANATIONS,
+      _WriteTemplateForAllApps(STRINGS_APP_POLICY_EXPLANATIONS_TEMPLATE, apps),
+      ]
+
+  return ''.join(target_contents)
+
+
+# Run a unit test when the module is run directly.
+if __name__ == '__main__':
+  TEST_APPS = [
+      ('Google Chrome',
+       '{8A69D345-D564-463C-AFF1-A69D9E530F96}',
+       ' Check http://www.google.com/chrome/.'),
+      ('Google Earth',
+       '{74AF07D8-FB8F-4D51-8AC7-927721D56EBB}',
+       ' Check http://earth.google.com/.'),
+      ]
+  TEST_GOLD_FILENAME = 'test_gold.adm'
+  TEST_OUTPUT_FILENAME = 'test_out.adm'
+
+  module_dir = os.path.abspath(os.path.dirname(__file__))
+  gold_path = os.path.join(module_dir, TEST_GOLD_FILENAME)
+  output_path = os.path.join(module_dir, TEST_OUTPUT_FILENAME)
+
+  test_target_contents = GenerateGroupPolicyTemplate(TEST_APPS)
+
+  target = open(output_path, 'wt')
+  target.write(test_target_contents)
+  target.close()
+
+  if filecmp.cmp(gold_path, output_path, shallow=False):
+    print 'PASS: Contents equal.'
+  else:
+    print 'FAIL: Contents not equal.'
+    sys.exit(-1)
diff --git a/enterprise/installer/build.scons b/enterprise/installer/build.scons
index 297e63e..4f7b696 100644
--- a/enterprise/installer/build.scons
+++ b/enterprise/installer/build.scons
@@ -1,171 +1,171 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-""" Build enterprise installers examples.

-

-  This file contains the product-specific information for building an

-  MSI for remote installation in the enterprise. Product teams should only

-  need to modify this file.

-  APPTEAMS:

-  There are two ways to build such an MSI depending on whether the product's

-  installer is or contains an MSI.

-"""

-

-Import('env')

-

-from enterprise.installer import build_enterprise_installer

-

-

-# APPTEAMS: Change this value to False.

-# Build the installer using build rules specific to Google Update builds.

-BUILDING_WITH_GOOGLE_UPDATE = True

-

-# APPTEAMS:

-# Note about versions: Each released build needs to have a different Build

-# number in the version "Major.Minor.Build.Qfe". The Qfe is ignored by MSI and

-# only increasing it may cause both the old and new versions of the this MSI

-# to exist side-by-side (http://msdn.microsoft.com/en-us/library/aa370859.aspx).

-

-# APPTEAMS: May be able to use this to get the version instead of explicitly

-# specifying it in the table below.

-# v = env['product_version'][0]

-# PRODUCT_VERSION = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-#

-# Applications with EXE installers

-#

-# Use this section to build an MSI that contains Google Update and a product's

-# EXE installer. The EXE may not use an MSI installer internally.

-# MSI installers cannot be wrapped in this way because nested MSI installs are

-# discouraged, problematic, and deprecated from WiX.

-

-# APPTEAMS: Make appropriate call to BuildEnterpriseInstaller(). Example below.

-

-# This sample:

-#  * Builds multiple "products" (each product is actually a different version).

-#    Products are specified in an array of structures, which specify the values

-#    for each product.

-#  * Builds multiple pre-tagged brands and ap values for each "product."

-def _BuildSampleForTest():

-  ENTERPRISE_INSTALLER_PRODUCTS = [

-    ('Save Arguments', '0.1.2.0', '{7DD1EF7B-D075-47c0-BD51-F624ED87CCF0}',

-     '&brand=mkfi',

-     '$MAIN_DIR/testing/unittest_support/SaveArguments.exe',

-     '/install 0.1.2.0', '/donotregister', '/uninstall 0.1.2.0',

-      'SaveArguments_Enterprise_Installer_0.1.2.0'),

-    ('Save Arguments', '0.1.3.0', '{7DD1EF7B-D075-47c0-BD51-F624ED87CCF0}',

-     '&brand=mkfi',

-     '$MAIN_DIR/testing/unittest_support/SaveArguments.exe',

-     '/install 0.1.3.0', '/donotregister', '/uninstall 0.1.3.0',

-     'SaveArguments_Enterprise_Installer_0.1.3.0'),

-    ]

-

-  # Example of calling BuildEnterpriseInstaller with multiple brands and ap

-  # value combinations for each product.

-  BRAND_AP_COMBINATIONS = [

-    ('FOOB', 'foobar'),

-    #('ENTA', 'enterprise'),

-    #('ENTB', 'enterprise'),

-  ]

-

-  # Omaha only: Build the enterprise installer for each version of Omaha.

-  first = True

-  for _ in env['product_version']:

-    if first:

-      first = False

-      prefix = ''

-    else:

-      prefix = 'TEST_'

-

-    for combo in BRAND_AP_COMBINATIONS:

-      for product in ENTERPRISE_INSTALLER_PRODUCTS:

-        (product_name, product_version, product_guid,

-         product_custom_params,

-         product_installer_path,

-         product_installer_install_command,

-         product_installer_disable_update_registration_arg,

-         product_installer_uninstall_command,

-         msi_base_name) = product

-

-        product_custom_params = '&brand=' + combo[0] + '&ap=' + combo[1]

-

-        build_enterprise_installer.BuildEnterpriseInstaller(

-            env,

-            product_name, product_version, product_guid,

-            product_custom_params,

-            product_installer_path,

-            product_installer_install_command,

-            product_installer_disable_update_registration_arg,

-            product_installer_uninstall_command,

-            prefix + msi_base_name + '_' + combo[0],

-            '$MAIN_DIR/enterprise/installer',

-            '$STAGING_DIR/%sGoogleUpdateSetup.exe' % prefix,

-            is_using_google_update_1_2_171_or_later=True

-        )

-

-# Builds a sample enterprise installer based on a standalone installer.

-def _BuildSampleStandaloneForTest():

-  # Omaha only: Build the enterprise installer for each version of Omaha.

-  first = True

-  for _ in env['product_version']:

-    if first:

-      first = False

-      prefix = ''

-    else:

-      prefix = 'TEST_'

-

-    msi_base_name = 'TestFoo_Standalone_Enterprise_Installer_1.0.101.0'

-    BRAND = 'ENTC'

-    AP = 'enterprise-C'

-    product_custom_params = '&brand=' + BRAND + '&ap=' + AP

-

-    # TODO(omaha): Use a standalone installer that does not wrap an MSI. This

-    # mechanism is not intended to be used for apps that use MSI installers.

-    # As is, Omaha tries to install the MSI but fails because the Windows

-    # Installer is busy. It takes a long time to fail because Omaha retries.

-    # TODO(omaha): This is a bad example because it uses MSI. See above.

-    product_uninstall = 'msiexec /x {EE93BF87-0CDD-3F0B-A4D6-3B3A1C54E3FA}'

-

-    build_enterprise_installer.BuildEnterpriseInstallerFromStandaloneInstaller(

-        env,

-        'Test Foo',

-        '1.0.101.0',

-        '{D6B08267-B440-4c85-9F79-E195E80D9937}',

-        product_custom_params,

-        '$STAGING_DIR/%sUNOFFICIAL_TestFoo.exe' % prefix,

-        product_uninstall,

-        prefix + msi_base_name + '_' + BRAND,

-        '$MAIN_DIR/enterprise/installer'

-    )

-

-if BUILDING_WITH_GOOGLE_UPDATE:

-  _BuildSampleForTest()

-  _BuildSampleStandaloneForTest()

-

-

-#

-# Applications with MSI installers

-#

-# To bundle Google Update with a product that has an MSI installer:

-#  * Build a .wixobj that contains the Google Update installation fragment

-#    by calling BuildGoogleUpdateFragment().

-#  * Include the ComponentGoogleUpdate component in the appropriate feature in

-#    the product's WiX code.

-#

-# For an example, see instances of "enterprise" in the following files:

-#  omaha/test/test_foo.wxs.xml

-#  omaha/test/build.scons

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+""" Build enterprise installers examples.
+
+  This file contains the product-specific information for building an
+  MSI for remote installation in the enterprise. Product teams should only
+  need to modify this file.
+  APPTEAMS:
+  There are two ways to build such an MSI depending on whether the product's
+  installer is or contains an MSI.
+"""
+
+Import('env')
+
+from enterprise.installer import build_enterprise_installer
+
+
+# APPTEAMS: Change this value to False.
+# Build the installer using build rules specific to Google Update builds.
+BUILDING_WITH_GOOGLE_UPDATE = True
+
+# APPTEAMS:
+# Note about versions: Each released build needs to have a different Build
+# number in the version "Major.Minor.Build.Qfe". The Qfe is ignored by MSI and
+# only increasing it may cause both the old and new versions of the this MSI
+# to exist side-by-side (http://msdn.microsoft.com/en-us/library/aa370859.aspx).
+
+# APPTEAMS: May be able to use this to get the version instead of explicitly
+# specifying it in the table below.
+# v = env['product_version'][0]
+# PRODUCT_VERSION = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+#
+# Applications with EXE installers
+#
+# Use this section to build an MSI that contains Google Update and a product's
+# EXE installer. The EXE may not use an MSI installer internally.
+# MSI installers cannot be wrapped in this way because nested MSI installs are
+# discouraged, problematic, and deprecated from WiX.
+
+# APPTEAMS: Make appropriate call to BuildEnterpriseInstaller(). Example below.
+
+# This sample:
+#  * Builds multiple "products" (each product is actually a different version).
+#    Products are specified in an array of structures, which specify the values
+#    for each product.
+#  * Builds multiple pre-tagged brands and ap values for each "product."
+def _BuildSampleForTest():
+  ENTERPRISE_INSTALLER_PRODUCTS = [
+    ('Save Arguments', '0.1.2.0', '{7DD1EF7B-D075-47c0-BD51-F624ED87CCF0}',
+     '&brand=mkfi',
+     '$MAIN_DIR/testing/unittest_support/SaveArguments.exe',
+     '/install 0.1.2.0', '/donotregister', '/uninstall 0.1.2.0',
+      'SaveArguments_Enterprise_Installer_0.1.2.0'),
+    ('Save Arguments', '0.1.3.0', '{7DD1EF7B-D075-47c0-BD51-F624ED87CCF0}',
+     '&brand=mkfi',
+     '$MAIN_DIR/testing/unittest_support/SaveArguments.exe',
+     '/install 0.1.3.0', '/donotregister', '/uninstall 0.1.3.0',
+     'SaveArguments_Enterprise_Installer_0.1.3.0'),
+    ]
+
+  # Example of calling BuildEnterpriseInstaller with multiple brands and ap
+  # value combinations for each product.
+  BRAND_AP_COMBINATIONS = [
+    ('FOOB', 'foobar'),
+    #('ENTA', 'enterprise'),
+    #('ENTB', 'enterprise'),
+  ]
+
+  # Omaha only: Build the enterprise installer for each version of Omaha.
+  first = True
+  for _ in env['product_version']:
+    if first:
+      first = False
+      prefix = ''
+    else:
+      prefix = 'TEST_'
+
+    for combo in BRAND_AP_COMBINATIONS:
+      for product in ENTERPRISE_INSTALLER_PRODUCTS:
+        (product_name, product_version, product_guid,
+         product_custom_params,
+         product_installer_path,
+         product_installer_install_command,
+         product_installer_disable_update_registration_arg,
+         product_installer_uninstall_command,
+         msi_base_name) = product
+
+        product_custom_params = '&brand=' + combo[0] + '&ap=' + combo[1]
+
+        build_enterprise_installer.BuildEnterpriseInstaller(
+            env,
+            product_name, product_version, product_guid,
+            product_custom_params,
+            product_installer_path,
+            product_installer_install_command,
+            product_installer_disable_update_registration_arg,
+            product_installer_uninstall_command,
+            prefix + msi_base_name + '_' + combo[0],
+            '$MAIN_DIR/enterprise/installer',
+            '$STAGING_DIR/%sGoogleUpdateSetup.exe' % prefix,
+            is_using_google_update_1_2_171_or_later=True
+        )
+
+# Builds a sample enterprise installer based on a standalone installer.
+def _BuildSampleStandaloneForTest():
+  # Omaha only: Build the enterprise installer for each version of Omaha.
+  first = True
+  for _ in env['product_version']:
+    if first:
+      first = False
+      prefix = ''
+    else:
+      prefix = 'TEST_'
+
+    msi_base_name = 'TestFoo_Standalone_Enterprise_Installer_1.0.101.0'
+    BRAND = 'ENTC'
+    AP = 'enterprise-C'
+    product_custom_params = '&brand=' + BRAND + '&ap=' + AP
+
+    # TODO(omaha): Use a standalone installer that does not wrap an MSI. This
+    # mechanism is not intended to be used for apps that use MSI installers.
+    # As is, Omaha tries to install the MSI but fails because the Windows
+    # Installer is busy. It takes a long time to fail because Omaha retries.
+    # TODO(omaha): This is a bad example because it uses MSI. See above.
+    product_uninstall = 'msiexec /x {EE93BF87-0CDD-3F0B-A4D6-3B3A1C54E3FA}'
+
+    build_enterprise_installer.BuildEnterpriseInstallerFromStandaloneInstaller(
+        env,
+        'Test Foo',
+        '1.0.101.0',
+        '{D6B08267-B440-4c85-9F79-E195E80D9937}',
+        product_custom_params,
+        '$STAGING_DIR/%sUNOFFICIAL_TestFoo.exe' % prefix,
+        product_uninstall,
+        prefix + msi_base_name + '_' + BRAND,
+        '$MAIN_DIR/enterprise/installer'
+    )
+
+if BUILDING_WITH_GOOGLE_UPDATE:
+  _BuildSampleForTest()
+  _BuildSampleStandaloneForTest()
+
+
+#
+# Applications with MSI installers
+#
+# To bundle Google Update with a product that has an MSI installer:
+#  * Build a .wixobj that contains the Google Update installation fragment
+#    by calling BuildGoogleUpdateFragment().
+#  * Include the ComponentGoogleUpdate component in the appropriate feature in
+#    the product's WiX code.
+#
+# For an example, see instances of "enterprise" in the following files:
+#  omaha/test/test_foo.wxs.xml
+#  omaha/test/build.scons
diff --git a/enterprise/installer/build_enterprise_installer.py b/enterprise/installer/build_enterprise_installer.py
index 6305b46..f58d026 100644
--- a/enterprise/installer/build_enterprise_installer.py
+++ b/enterprise/installer/build_enterprise_installer.py
@@ -1,387 +1,387 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-"""Build an installer for use in enterprise situations.

-

-  This module contains the functionality required to build enterprise

-  installers (msi's) for Omaha's various customers.

-

-  The supplied wxs templates need to have an XML extension because SCons

-  tries to apply WiX building rules to any input file with the .wxs suffix.

-

-  BuildGoogleUpdateFragment(): Build an update fragment into a .wixobj.

-  GenerateNameBasedGUID(): Generate a GUID based on the names supplied.

-  BuildEnterpriseInstaller(): Build an msi installer for use in enterprises.

-"""

-

-import binascii

-import md5

-

-_GOOGLE_UPDATE_NAMESPACE_GUID = 'BE19B3E4502845af8B3E67A99FCDCFB1'

-

-def BuildGoogleUpdateFragment(env,

-                              metainstaller_path,

-                              product_name,

-                              product_version,

-                              product_guid,

-                              product_custom_params,

-                              wixobj_base_name,

-                              google_update_wxs_template_path,

-                              is_using_google_update_1_2_171_or_later=False):

-  """Build an update fragment into a WiX object.

-

-    Takes a supplied wix fragment, and turns it into a .wixobj object for later

-    inclusion into an msi.

-

-  Args:

-    env: environment to build with

-    metainstaller_path: path to the Omaha metainstaller to include

-    product_name: name of the product the fragment is being built for

-    product_guid: Omaha application ID of the product the fragment is being

-        built for

-    product_custom_params: custom values to be appended to the Omaha tag

-    wixobj_base_name: root of name for the wixobj

-    google_update_wxs_template_path: path to the fragment source

-    product_version: product version to be installed

-

-  Returns:

-    Output object for the built wixobj.

-

-  Raises:

-    Nothing.

-  """

-

-  product_name_legal_identifier = product_name.replace(' ', '')

-

-  intermediate_base_name = wixobj_base_name + '_google_update_fragment'

-

-  copy_target = env.Command(

-      target=intermediate_base_name + '.wxs',

-      source=google_update_wxs_template_path,

-      action='@copy /y $SOURCE $TARGET',

-  )

-

-  wix_defines = [

-      '-dProductName="%s"' % product_name,

-      '-dProductNameLegalIdentifier="%s"' % product_name_legal_identifier,

-      '-dProductVersion=' + product_version,

-      '-dProductGuid="%s"' % product_guid,

-      '-dProductCustomParams="%s"' % product_custom_params,

-      '-dGoogleUpdateMetainstallerPath="%s"' % (

-          env.File(metainstaller_path).abspath),

-      ]

-

-  if is_using_google_update_1_2_171_or_later:

-    wix_defines += [

-        '-dUsingGoogleUpdate_1_2_171_OrLater=1'

-        ]

-

-  wixobj_output = env.Command(

-      target=intermediate_base_name + '.wixobj',

-      source=copy_target,

-      action='@candle.exe -nologo -out $TARGET $SOURCE ' + ' '.join(wix_defines)

-  )

-

-  # Force a rebuild of the .wixobj file when the metainstaller changes.

-  # Does not necessarily force rebuild of the MSI because hash does not change.

-  env.Depends(wixobj_output, metainstaller_path)

-

-  return wixobj_output

-

-

-def _BuildMsiForExe(env,

-                    enterprise_installer_dir,

-                    product_name,

-                    product_version,

-                    product_installer_path,

-                    product_installer_install_command,

-                    product_installer_disable_update_registration_arg,

-                    product_installer_uninstall_command,

-                    msi_base_name,

-                    google_update_wixobj_output,

-                    metainstaller_path):

-  # metainstaller_path: path to the Omaha metainstaller. Should be same file

-  #     used for google_update_wixobj_output. Used only to force rebuilds.

-

-  product_name_legal_identifier = product_name.replace(' ', '')

-  msi_name = msi_base_name + '.msi'

-

-  omaha_installer_namespace = binascii.a2b_hex(_GOOGLE_UPDATE_NAMESPACE_GUID)

-

-  # Include the .msi filename in the Product Code generation because "the

-  # product code must be changed if... the name of the .msi file has been

-  # changed" according to http://msdn.microsoft.com/en-us/library/aa367850.aspx.

-  msi_product_id = GenerateNameBasedGUID(

-      omaha_installer_namespace,

-      'Product %s %s' % (product_name, msi_base_name)

-  )

-  msi_upgradecode_guid = GenerateNameBasedGUID(

-      omaha_installer_namespace,

-      'Upgrade ' + product_name

-  )

-

-  copy_target = env.Command(

-      target= msi_base_name + '.wxs',

-      source=enterprise_installer_dir + '/enterprise_installer.wxs.xml',

-      action='@copy /y $SOURCE $TARGET',

-  )

-

-  wix_env = env.Clone()

-  wix_env.Append(

-      WIXCANDLEFLAGS = [

-          '-dProductName=' + product_name,

-          '-dProductNameLegalIdentifier=' + product_name_legal_identifier,

-          '-dProductVersion=' + product_version,

-          '-dProductInstallerPath=' + env.File(product_installer_path).abspath,

-          '-dProductInstallerInstallCommand=' +

-              product_installer_install_command,

-          '-dProductInstallerDisableUpdateRegistrationArg=' +

-              product_installer_disable_update_registration_arg,

-          '-dProductInstallerUninstallCommand=' +

-              product_installer_uninstall_command,

-          '-dMsiProductId=' + msi_product_id,

-          '-dMsiUpgradeCode=' + msi_upgradecode_guid,

-          ],

-  )

-

-  wix_output = wix_env.WiX(

-      target='unsigned_' + msi_name,

-      source=[copy_target, google_update_wixobj_output],

-  )

-

-  # Force a rebuild when the installer or metainstaller changes.

-  # The metainstaller change does not get passed through even though the .wixobj

-  # file is rebuilt because the hash of the .wixobj does not change.

-  wix_env.Depends(wix_output,

-                  [product_installer_path, metainstaller_path])

-

-  sign_output = wix_env.SignedBinary(

-      target=msi_name,

-      source=wix_output,

-  )

-

-  env.Replicate('$STAGING_DIR', sign_output)

-

-

-def GenerateNameBasedGUID(namespace, name):

-  """Generate a GUID based on the names supplied.

-

-    Follows a methodology recommended in Section 4.3 of RFC 4122 to generate

-    a "name-based UUID," which basically means that you want to control the

-    inputs to the GUID so that you can generate the same valid GUID each time

-    given the same inputs.

-

-    Args:

-      namespace: First part of identifier used to generate GUID

-      name: Second part of identifier used to generate GUID

-

-    Returns:

-      String representation of the generated GUID.

-

-    Raises:

-      Nothing.

-  """

-

-  # Generate 128 unique bits.

-  mymd5 = md5.new()

-  mymd5.update(namespace + name)

-  hash = mymd5.digest()

-

-  # Set various reserved bits to make this a valid GUID.

-

-  # "Set the four most significant bits (bits 12 through 15) of the

-  # time_hi_and_version field to the appropriate 4-bit version number

-  # from Section 4.1.3."

-  version = ord(hash[6])

-  version = 0x30 | (version & 0x0f)

-

-  # "Set the two most significant bits (bits 6 and 7) of the

-  # clock_seq_hi_and_reserved to zero and one, respectively."

-  clock_seq_hi_and_reserved = ord(hash[8])

-  clock_seq_hi_and_reserved = 0x80 | (clock_seq_hi_and_reserved & 0x3f)

-

-  return (

-      '%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x' % (

-      ord(hash[0]), ord(hash[1]), ord(hash[2]), ord(hash[3]), ord(hash[4]),

-      ord(hash[5]), version, ord(hash[7]), clock_seq_hi_and_reserved,

-      ord(hash[9]), ord(hash[10]), ord(hash[11]), ord(hash[12]), ord(hash[13]),

-      ord(hash[14]), ord(hash[15])))

-

-

-def BuildEnterpriseInstaller(env,

-                             product_name,

-                             product_version,

-                             product_guid,

-                             product_custom_params,

-                             product_installer_path,

-                             product_installer_install_command,

-                             product_installer_disable_update_registration_arg,

-                             product_installer_uninstall_command,

-                             msi_base_name,

-                             enterprise_installer_dir,

-                             metainstaller_path,

-                             is_using_google_update_1_2_171_or_later=False):

-  """Build an installer for use in enterprise situations.

-

-    Builds an msi using the supplied details and binaries. This msi is

-    intended to enable enterprise installation scenarios.

-

-  Args:

-    env: environment to build with

-    product_name: name of the product being built

-    product_version: product version to be installed

-    product_guid: product's Omaha application ID

-    product_custom_params: custom values to be appended to the Omaha tag

-    product_installer_path: path to specific product installer

-    product_installer_install_command: command line args used to run product

-        installer in 'install' mode

-    product_installer_disable_update_registration_arg: command line args used

-        to run product installer in 'do not register' mode

-    product_installer_uninstall_command: command line args used to run product

-        installer in 'uninstall' mode

-    msi_base_name: root of name for the msi

-    enterprise_installer_dir: path to dir which contains

-        enterprise_installer.wxs.xml

-    metainstaller_path: path to the Omaha metainstaller to include

-

-  Returns:

-    Nothing.

-

-  Raises:

-    Nothing.

-  """

-

-  google_update_wixobj_output = BuildGoogleUpdateFragment(

-      env,

-      metainstaller_path,

-      product_name,

-      product_version,

-      product_guid,

-      product_custom_params,

-      msi_base_name,

-      enterprise_installer_dir + '/google_update_installer_fragment.wxs.xml',

-      is_using_google_update_1_2_171_or_later)

-

-  _BuildMsiForExe(

-      env,

-      enterprise_installer_dir,

-      product_name,

-      product_version,

-      product_installer_path,

-      product_installer_install_command,

-      product_installer_disable_update_registration_arg,

-      product_installer_uninstall_command,

-      msi_base_name,

-      google_update_wixobj_output,

-      metainstaller_path)

-

-def BuildEnterpriseInstallerFromStandaloneInstaller(

-    env,

-    product_name,

-    product_version,

-    product_guid,

-    product_custom_params,

-    standalone_installer_path,

-    product_uninstall_command_line,

-    msi_base_name,

-    enterprise_installer_dir):

-  """Build an installer for use in enterprise situations.

-

-    Builds an msi around the supplied standalone installer. This msi is

-    intended to enable enterprise installation scenarios while being as close

-    to a normal install as possible. It does not suffer from the separation of

-    Omaha and application install like the other methods do.

-

-    This method only works for installers that do not use an MSI.

-

-  Args:

-    env: environment to build with

-    product_name: name of the product being built

-    product_version: product version to be installed

-    product_guid: product's Omaha application ID

-    product_custom_params: custom values to be appended to the Omaha tag

-    standalone_installer_path: path to product's standalone installer

-    product_uninstall_command_line: command line used to uninstall the product;

-        will be executed directly.

-        TODO(omaha): Change this to quiet_uninstall_args and append to uninstall

-        string found in registry. Requires a custom action DLL.

-    msi_base_name: root of name for the msi

-    enterprise_installer_dir: path to dir which contains

-        enterprise_standalone_installer.wxs.xml

-

-  Returns:

-    Nothing.

-

-  Raises:

-    Nothing.

-  """

-  product_name_legal_identifier = product_name.replace(' ', '')

-  msi_name = msi_base_name + '.msi'

-

-  omaha_installer_namespace = binascii.a2b_hex(_GOOGLE_UPDATE_NAMESPACE_GUID)

-

-  # Include the .msi filename in the Product Code generation because "the

-  # product code must be changed if... the name of the .msi file has been

-  # changed" according to http://msdn.microsoft.com/en-us/library/aa367850.aspx.

-  msi_product_id = GenerateNameBasedGUID(

-      omaha_installer_namespace,

-      'Product %s %s' % (product_name, msi_base_name)

-  )

-  msi_upgradecode_guid = GenerateNameBasedGUID(

-      omaha_installer_namespace,

-      'Upgrade ' + product_name

-  )

-

-  copy_target = env.Command(

-      target= msi_base_name + '.wxs',

-      source=(enterprise_installer_dir +

-              '/enterprise_standalone_installer.wxs.xml'),

-      action='@copy /y $SOURCE $TARGET',

-  )

-

-  wix_env = env.Clone()

-  wix_env.Append(

-      WIXCANDLEFLAGS = [

-          '-dProductName=' + product_name,

-          '-dProductNameLegalIdentifier=' + product_name_legal_identifier,

-          '-dProductVersion=' + product_version,

-          '-dProductGuid="%s"' % product_guid,

-          '-dProductCustomParams="%s"' % product_custom_params,

-          '-dStandaloneInstallerPath=' + (

-              env.File(standalone_installer_path).abspath),

-          '-dProductUninstallCommandLine=' + product_uninstall_command_line,

-          '-dMsiProductId=' + msi_product_id,

-          '-dMsiUpgradeCode=' + msi_upgradecode_guid,

-          ],

-  )

-

-  wix_output = wix_env.WiX(

-      target='unsigned_' + msi_name,

-      source=[copy_target],

-  )

-

-  # Force a rebuild when the standalone installer changes.

-  # The metainstaller change does not get passed through even though the .wixobj

-  # file is rebuilt because the hash of the .wixobj does not change.

-  wix_env.Depends(wix_output, standalone_installer_path)

-

-  sign_output = wix_env.SignedBinary(

-      target=msi_name,

-      source=wix_output,

-  )

-

-  env.Replicate('$STAGING_DIR', sign_output)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+"""Build an installer for use in enterprise situations.
+
+  This module contains the functionality required to build enterprise
+  installers (msi's) for Omaha's various customers.
+
+  The supplied wxs templates need to have an XML extension because SCons
+  tries to apply WiX building rules to any input file with the .wxs suffix.
+
+  BuildGoogleUpdateFragment(): Build an update fragment into a .wixobj.
+  GenerateNameBasedGUID(): Generate a GUID based on the names supplied.
+  BuildEnterpriseInstaller(): Build an msi installer for use in enterprises.
+"""
+
+import binascii
+import md5
+
+_GOOGLE_UPDATE_NAMESPACE_GUID = 'BE19B3E4502845af8B3E67A99FCDCFB1'
+
+def BuildGoogleUpdateFragment(env,
+                              metainstaller_path,
+                              product_name,
+                              product_version,
+                              product_guid,
+                              product_custom_params,
+                              wixobj_base_name,
+                              google_update_wxs_template_path,
+                              is_using_google_update_1_2_171_or_later=False):
+  """Build an update fragment into a WiX object.
+
+    Takes a supplied wix fragment, and turns it into a .wixobj object for later
+    inclusion into an msi.
+
+  Args:
+    env: environment to build with
+    metainstaller_path: path to the Omaha metainstaller to include
+    product_name: name of the product the fragment is being built for
+    product_guid: Omaha application ID of the product the fragment is being
+        built for
+    product_custom_params: custom values to be appended to the Omaha tag
+    wixobj_base_name: root of name for the wixobj
+    google_update_wxs_template_path: path to the fragment source
+    product_version: product version to be installed
+
+  Returns:
+    Output object for the built wixobj.
+
+  Raises:
+    Nothing.
+  """
+
+  product_name_legal_identifier = product_name.replace(' ', '')
+
+  intermediate_base_name = wixobj_base_name + '_google_update_fragment'
+
+  copy_target = env.Command(
+      target=intermediate_base_name + '.wxs',
+      source=google_update_wxs_template_path,
+      action='@copy /y $SOURCE $TARGET',
+  )
+
+  wix_defines = [
+      '-dProductName="%s"' % product_name,
+      '-dProductNameLegalIdentifier="%s"' % product_name_legal_identifier,
+      '-dProductVersion=' + product_version,
+      '-dProductGuid="%s"' % product_guid,
+      '-dProductCustomParams="%s"' % product_custom_params,
+      '-dGoogleUpdateMetainstallerPath="%s"' % (
+          env.File(metainstaller_path).abspath),
+      ]
+
+  if is_using_google_update_1_2_171_or_later:
+    wix_defines += [
+        '-dUsingGoogleUpdate_1_2_171_OrLater=1'
+        ]
+
+  wixobj_output = env.Command(
+      target=intermediate_base_name + '.wixobj',
+      source=copy_target,
+      action='@candle.exe -nologo -out $TARGET $SOURCE ' + ' '.join(wix_defines)
+  )
+
+  # Force a rebuild of the .wixobj file when the metainstaller changes.
+  # Does not necessarily force rebuild of the MSI because hash does not change.
+  env.Depends(wixobj_output, metainstaller_path)
+
+  return wixobj_output
+
+
+def _BuildMsiForExe(env,
+                    enterprise_installer_dir,
+                    product_name,
+                    product_version,
+                    product_installer_path,
+                    product_installer_install_command,
+                    product_installer_disable_update_registration_arg,
+                    product_installer_uninstall_command,
+                    msi_base_name,
+                    google_update_wixobj_output,
+                    metainstaller_path):
+  # metainstaller_path: path to the Omaha metainstaller. Should be same file
+  #     used for google_update_wixobj_output. Used only to force rebuilds.
+
+  product_name_legal_identifier = product_name.replace(' ', '')
+  msi_name = msi_base_name + '.msi'
+
+  omaha_installer_namespace = binascii.a2b_hex(_GOOGLE_UPDATE_NAMESPACE_GUID)
+
+  # Include the .msi filename in the Product Code generation because "the
+  # product code must be changed if... the name of the .msi file has been
+  # changed" according to http://msdn.microsoft.com/en-us/library/aa367850.aspx.
+  msi_product_id = GenerateNameBasedGUID(
+      omaha_installer_namespace,
+      'Product %s %s' % (product_name, msi_base_name)
+  )
+  msi_upgradecode_guid = GenerateNameBasedGUID(
+      omaha_installer_namespace,
+      'Upgrade ' + product_name
+  )
+
+  copy_target = env.Command(
+      target= msi_base_name + '.wxs',
+      source=enterprise_installer_dir + '/enterprise_installer.wxs.xml',
+      action='@copy /y $SOURCE $TARGET',
+  )
+
+  wix_env = env.Clone()
+  wix_env.Append(
+      WIXCANDLEFLAGS = [
+          '-dProductName=' + product_name,
+          '-dProductNameLegalIdentifier=' + product_name_legal_identifier,
+          '-dProductVersion=' + product_version,
+          '-dProductInstallerPath=' + env.File(product_installer_path).abspath,
+          '-dProductInstallerInstallCommand=' +
+              product_installer_install_command,
+          '-dProductInstallerDisableUpdateRegistrationArg=' +
+              product_installer_disable_update_registration_arg,
+          '-dProductInstallerUninstallCommand=' +
+              product_installer_uninstall_command,
+          '-dMsiProductId=' + msi_product_id,
+          '-dMsiUpgradeCode=' + msi_upgradecode_guid,
+          ],
+  )
+
+  wix_output = wix_env.WiX(
+      target='unsigned_' + msi_name,
+      source=[copy_target, google_update_wixobj_output],
+  )
+
+  # Force a rebuild when the installer or metainstaller changes.
+  # The metainstaller change does not get passed through even though the .wixobj
+  # file is rebuilt because the hash of the .wixobj does not change.
+  wix_env.Depends(wix_output,
+                  [product_installer_path, metainstaller_path])
+
+  sign_output = wix_env.SignedBinary(
+      target=msi_name,
+      source=wix_output,
+  )
+
+  env.Replicate('$STAGING_DIR', sign_output)
+
+
+def GenerateNameBasedGUID(namespace, name):
+  """Generate a GUID based on the names supplied.
+
+    Follows a methodology recommended in Section 4.3 of RFC 4122 to generate
+    a "name-based UUID," which basically means that you want to control the
+    inputs to the GUID so that you can generate the same valid GUID each time
+    given the same inputs.
+
+    Args:
+      namespace: First part of identifier used to generate GUID
+      name: Second part of identifier used to generate GUID
+
+    Returns:
+      String representation of the generated GUID.
+
+    Raises:
+      Nothing.
+  """
+
+  # Generate 128 unique bits.
+  mymd5 = md5.new()
+  mymd5.update(namespace + name)
+  hash = mymd5.digest()
+
+  # Set various reserved bits to make this a valid GUID.
+
+  # "Set the four most significant bits (bits 12 through 15) of the
+  # time_hi_and_version field to the appropriate 4-bit version number
+  # from Section 4.1.3."
+  version = ord(hash[6])
+  version = 0x30 | (version & 0x0f)
+
+  # "Set the two most significant bits (bits 6 and 7) of the
+  # clock_seq_hi_and_reserved to zero and one, respectively."
+  clock_seq_hi_and_reserved = ord(hash[8])
+  clock_seq_hi_and_reserved = 0x80 | (clock_seq_hi_and_reserved & 0x3f)
+
+  return (
+      '%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x' % (
+      ord(hash[0]), ord(hash[1]), ord(hash[2]), ord(hash[3]), ord(hash[4]),
+      ord(hash[5]), version, ord(hash[7]), clock_seq_hi_and_reserved,
+      ord(hash[9]), ord(hash[10]), ord(hash[11]), ord(hash[12]), ord(hash[13]),
+      ord(hash[14]), ord(hash[15])))
+
+
+def BuildEnterpriseInstaller(env,
+                             product_name,
+                             product_version,
+                             product_guid,
+                             product_custom_params,
+                             product_installer_path,
+                             product_installer_install_command,
+                             product_installer_disable_update_registration_arg,
+                             product_installer_uninstall_command,
+                             msi_base_name,
+                             enterprise_installer_dir,
+                             metainstaller_path,
+                             is_using_google_update_1_2_171_or_later=False):
+  """Build an installer for use in enterprise situations.
+
+    Builds an msi using the supplied details and binaries. This msi is
+    intended to enable enterprise installation scenarios.
+
+  Args:
+    env: environment to build with
+    product_name: name of the product being built
+    product_version: product version to be installed
+    product_guid: product's Omaha application ID
+    product_custom_params: custom values to be appended to the Omaha tag
+    product_installer_path: path to specific product installer
+    product_installer_install_command: command line args used to run product
+        installer in 'install' mode
+    product_installer_disable_update_registration_arg: command line args used
+        to run product installer in 'do not register' mode
+    product_installer_uninstall_command: command line args used to run product
+        installer in 'uninstall' mode
+    msi_base_name: root of name for the msi
+    enterprise_installer_dir: path to dir which contains
+        enterprise_installer.wxs.xml
+    metainstaller_path: path to the Omaha metainstaller to include
+
+  Returns:
+    Nothing.
+
+  Raises:
+    Nothing.
+  """
+
+  google_update_wixobj_output = BuildGoogleUpdateFragment(
+      env,
+      metainstaller_path,
+      product_name,
+      product_version,
+      product_guid,
+      product_custom_params,
+      msi_base_name,
+      enterprise_installer_dir + '/google_update_installer_fragment.wxs.xml',
+      is_using_google_update_1_2_171_or_later)
+
+  _BuildMsiForExe(
+      env,
+      enterprise_installer_dir,
+      product_name,
+      product_version,
+      product_installer_path,
+      product_installer_install_command,
+      product_installer_disable_update_registration_arg,
+      product_installer_uninstall_command,
+      msi_base_name,
+      google_update_wixobj_output,
+      metainstaller_path)
+
+def BuildEnterpriseInstallerFromStandaloneInstaller(
+    env,
+    product_name,
+    product_version,
+    product_guid,
+    product_custom_params,
+    standalone_installer_path,
+    product_uninstall_command_line,
+    msi_base_name,
+    enterprise_installer_dir):
+  """Build an installer for use in enterprise situations.
+
+    Builds an msi around the supplied standalone installer. This msi is
+    intended to enable enterprise installation scenarios while being as close
+    to a normal install as possible. It does not suffer from the separation of
+    Omaha and application install like the other methods do.
+
+    This method only works for installers that do not use an MSI.
+
+  Args:
+    env: environment to build with
+    product_name: name of the product being built
+    product_version: product version to be installed
+    product_guid: product's Omaha application ID
+    product_custom_params: custom values to be appended to the Omaha tag
+    standalone_installer_path: path to product's standalone installer
+    product_uninstall_command_line: command line used to uninstall the product;
+        will be executed directly.
+        TODO(omaha): Change this to quiet_uninstall_args and append to uninstall
+        string found in registry. Requires a custom action DLL.
+    msi_base_name: root of name for the msi
+    enterprise_installer_dir: path to dir which contains
+        enterprise_standalone_installer.wxs.xml
+
+  Returns:
+    Nothing.
+
+  Raises:
+    Nothing.
+  """
+  product_name_legal_identifier = product_name.replace(' ', '')
+  msi_name = msi_base_name + '.msi'
+
+  omaha_installer_namespace = binascii.a2b_hex(_GOOGLE_UPDATE_NAMESPACE_GUID)
+
+  # Include the .msi filename in the Product Code generation because "the
+  # product code must be changed if... the name of the .msi file has been
+  # changed" according to http://msdn.microsoft.com/en-us/library/aa367850.aspx.
+  msi_product_id = GenerateNameBasedGUID(
+      omaha_installer_namespace,
+      'Product %s %s' % (product_name, msi_base_name)
+  )
+  msi_upgradecode_guid = GenerateNameBasedGUID(
+      omaha_installer_namespace,
+      'Upgrade ' + product_name
+  )
+
+  copy_target = env.Command(
+      target= msi_base_name + '.wxs',
+      source=(enterprise_installer_dir +
+              '/enterprise_standalone_installer.wxs.xml'),
+      action='@copy /y $SOURCE $TARGET',
+  )
+
+  wix_env = env.Clone()
+  wix_env.Append(
+      WIXCANDLEFLAGS = [
+          '-dProductName=' + product_name,
+          '-dProductNameLegalIdentifier=' + product_name_legal_identifier,
+          '-dProductVersion=' + product_version,
+          '-dProductGuid="%s"' % product_guid,
+          '-dProductCustomParams="%s"' % product_custom_params,
+          '-dStandaloneInstallerPath=' + (
+              env.File(standalone_installer_path).abspath),
+          '-dProductUninstallCommandLine=' + product_uninstall_command_line,
+          '-dMsiProductId=' + msi_product_id,
+          '-dMsiUpgradeCode=' + msi_upgradecode_guid,
+          ],
+  )
+
+  wix_output = wix_env.WiX(
+      target='unsigned_' + msi_name,
+      source=[copy_target],
+  )
+
+  # Force a rebuild when the standalone installer changes.
+  # The metainstaller change does not get passed through even though the .wixobj
+  # file is rebuilt because the hash of the .wixobj does not change.
+  wix_env.Depends(wix_output, standalone_installer_path)
+
+  sign_output = wix_env.SignedBinary(
+      target=msi_name,
+      source=wix_output,
+  )
+
+  env.Replicate('$STAGING_DIR', sign_output)
diff --git a/enterprise/installer/enterprise_installer.wxs.xml b/enterprise/installer/enterprise_installer.wxs.xml
index 1bcf55c..b1e0b72 100644
--- a/enterprise/installer/enterprise_installer.wxs.xml
+++ b/enterprise/installer/enterprise_installer.wxs.xml
@@ -1,132 +1,132 @@
-<?xml version='1.0' encoding='windows-1252'?>

-<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>

-  <?define CompanyFullName = 'Google, Inc.'?>

-  <?define Copyright = 'Copyright 2007-2009 Google Inc.'?>

-

-  <Product

-    Id='$(var.MsiProductId)'

-    Name='$(var.ProductName)'

-    Language='1033'

-    Codepage='1252'

-    UpgradeCode='$(var.MsiUpgradeCode)'

-    Version='$(var.ProductVersion)'

-    Manufacturer='$(var.CompanyFullName)'>

-

-    <Package

-      Id='*'

-      Description='$(var.ProductName) Installer'

-      Comments='$(var.Copyright)'

-      Manufacturer='$(var.CompanyFullName)'

-      Languages='1033'

-      SummaryCodepage='1252'

-      InstallerVersion='150'

-      InstallPrivileges='elevated'

-      Compressed='yes' />

-

-    <Upgrade Id='$(var.MsiUpgradeCode)'>

-      <UpgradeVersion Property='UPGRADING'

-                      OnlyDetect='no'

-                      Minimum='0.0.0.0' IncludeMinimum='yes'

-                      Maximum='$(var.ProductVersion)' IncludeMaximum='no' />

-      <UpgradeVersion Property='NEWERVERSIONDETECTED' 

-                      OnlyDetect='yes'

-                      Minimum='$(var.ProductVersion)' IncludeMinimum='yes' />

-    </Upgrade>

-

-    <!-- Per-machine installation - make sure product appears for all users. -->

-    <Property Id='ALLUSERS' Value='1' />

-

-    <!-- Hide the Add/Remove Programs entry.

-         The application installer should have its own entry. -->

-    <Property Id='ARPSYSTEMCOMPONENT' Value='1' />

-

-    <UI>

-      <Error Id='4000'>A newer version of the $(var.ProductName) enterprise installer is already installed.</Error>

-    </UI>

-

-    <!-- Eliminates "warning LGHT1076 : ICE71: The Media table has no entries."

-    -->

-    <Media Id='1' />

-

-    <Directory Id='TARGETDIR' Name='SourceDir'>

-      <Directory Id='ProgramFilesFolder'>

-      </Directory>

-    </Directory>

-

-

-    <Binary Id='$(var.ProductNameLegalIdentifier)Installer'

-            SourceFile='$(var.ProductInstallerPath)' />

-

-

-    <Feature Id='Complete' Level='1'>

-      <ComponentRef Id='ComponentGoogleUpdate' />

-    </Feature>

-

-    <CustomAction Id='NewerVersionError' Error='4000'/>

-

-    <CustomAction Id='SetInstallerInstallCommandProperty'

-      Property='FullProductInstallerInstallCommand'

-      Value='$(var.ProductInstallerInstallCommand)'

-      Execute='immediate'

-      Return='check' />

-    <CustomAction 

-      Id='AppendDisableUpdateRegistrationArgToInstallerInstallCommandProperty'

-      Property='FullProductInstallerInstallCommand'

-      Value='[FullProductInstallerInstallCommand]

-             $(var.ProductInstallerDisableUpdateRegistrationArg)'

-      Execute='immediate'

-      Return='check' />

-    <CustomAction Id='Install$(var.ProductNameLegalIdentifier)'

-      BinaryKey='$(var.ProductNameLegalIdentifier)Installer'

-      Impersonate='no'

-      Execute='deferred'

-      ExeCommand='[FullProductInstallerInstallCommand]'

-      Return='check' />

-    <CustomAction Id='Uninstall$(var.ProductNameLegalIdentifier)'

-      BinaryKey='$(var.ProductNameLegalIdentifier)Installer'

-      Impersonate='no'

-      Execute='deferred'

-      ExeCommand='$(var.ProductInstallerUninstallCommand)'

-      Return='check' />

-

-    <InstallExecuteSequence>

-      <RemoveExistingProducts After='InstallValidate' />

-

-      <Custom Action='NewerVersionError' After='FindRelatedProducts'>

-        NEWERVERSIONDETECTED

-      </Custom>

-

-      <!-- Any operations that rely on values, such as brand and usagestats, in

-           ClientState should not run until after

-           InstallGoogleUpdateAndRegister. This is sequenced before InstallFiles

-           so that can be used as well. -->

-      <!-- TODO(omaha): Support Rollback? Need to determine whether Product

-           was installed before installing it and only add the rollback then.

-      <Custom Action='Rollback$(var.ProductNameLegalIdentifier)'

-              After='InstallFiles'>

-        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT $(var.ProductNameLegalIdentifier)_INSTALLED)

-      </Custom>

-      Change After='InstallFiles' below to

-      After='Rollback$(var.ProductNameLegalIdentifier)'. -->

-      <Custom Action='SetInstallerInstallCommandProperty'

-              After='InstallFiles'>

-        (($ComponentGoogleUpdate>2) OR REINSTALL)

-      </Custom>

-      <Custom Action='AppendDisableUpdateRegistrationArgToInstallerInstallCommandProperty'

-              After='SetInstallerInstallCommandProperty'>

-        (($ComponentGoogleUpdate>2) OR REINSTALL) AND DISABLE_UPDATES

-      </Custom>

-      <Custom Action='Install$(var.ProductNameLegalIdentifier)'

-              After='AppendDisableUpdateRegistrationArgToInstallerInstallCommandProperty'>

-        (($ComponentGoogleUpdate>2) OR REINSTALL)

-      </Custom>

-

-      <Custom Action='Uninstall$(var.ProductNameLegalIdentifier)'

-              Before='RemoveFiles'>

-        $ComponentGoogleUpdate=2

-      </Custom>

-

-    </InstallExecuteSequence>

-

-  </Product>

-</Wix>

+<?xml version='1.0' encoding='windows-1252'?>
+<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
+  <?define CompanyFullName = 'Google, Inc.'?>
+  <?define Copyright = 'Copyright 2007-2009 Google Inc.'?>
+
+  <Product
+    Id='$(var.MsiProductId)'
+    Name='$(var.ProductName)'
+    Language='1033'
+    Codepage='1252'
+    UpgradeCode='$(var.MsiUpgradeCode)'
+    Version='$(var.ProductVersion)'
+    Manufacturer='$(var.CompanyFullName)'>
+
+    <Package
+      Id='*'
+      Description='$(var.ProductName) Installer'
+      Comments='$(var.Copyright)'
+      Manufacturer='$(var.CompanyFullName)'
+      Languages='1033'
+      SummaryCodepage='1252'
+      InstallerVersion='150'
+      InstallPrivileges='elevated'
+      Compressed='yes' />
+
+    <Upgrade Id='$(var.MsiUpgradeCode)'>
+      <UpgradeVersion Property='UPGRADING'
+                      OnlyDetect='no'
+                      Minimum='0.0.0.0' IncludeMinimum='yes'
+                      Maximum='$(var.ProductVersion)' IncludeMaximum='no' />
+      <UpgradeVersion Property='NEWERVERSIONDETECTED' 
+                      OnlyDetect='yes'
+                      Minimum='$(var.ProductVersion)' IncludeMinimum='yes' />
+    </Upgrade>
+
+    <!-- Per-machine installation - make sure product appears for all users. -->
+    <Property Id='ALLUSERS' Value='1' />
+
+    <!-- Hide the Add/Remove Programs entry.
+         The application installer should have its own entry. -->
+    <Property Id='ARPSYSTEMCOMPONENT' Value='1' />
+
+    <UI>
+      <Error Id='4000'>A newer version of the $(var.ProductName) enterprise installer is already installed.</Error>
+    </UI>
+
+    <!-- Eliminates "warning LGHT1076 : ICE71: The Media table has no entries."
+    -->
+    <Media Id='1' />
+
+    <Directory Id='TARGETDIR' Name='SourceDir'>
+      <Directory Id='ProgramFilesFolder'>
+      </Directory>
+    </Directory>
+
+
+    <Binary Id='$(var.ProductNameLegalIdentifier)Installer'
+            SourceFile='$(var.ProductInstallerPath)' />
+
+
+    <Feature Id='Complete' Level='1'>
+      <ComponentRef Id='ComponentGoogleUpdate' />
+    </Feature>
+
+    <CustomAction Id='NewerVersionError' Error='4000'/>
+
+    <CustomAction Id='SetInstallerInstallCommandProperty'
+      Property='FullProductInstallerInstallCommand'
+      Value='$(var.ProductInstallerInstallCommand)'
+      Execute='immediate'
+      Return='check' />
+    <CustomAction 
+      Id='AppendDisableUpdateRegistrationArgToInstallerInstallCommandProperty'
+      Property='FullProductInstallerInstallCommand'
+      Value='[FullProductInstallerInstallCommand]
+             $(var.ProductInstallerDisableUpdateRegistrationArg)'
+      Execute='immediate'
+      Return='check' />
+    <CustomAction Id='Install$(var.ProductNameLegalIdentifier)'
+      BinaryKey='$(var.ProductNameLegalIdentifier)Installer'
+      Impersonate='no'
+      Execute='deferred'
+      ExeCommand='[FullProductInstallerInstallCommand]'
+      Return='check' />
+    <CustomAction Id='Uninstall$(var.ProductNameLegalIdentifier)'
+      BinaryKey='$(var.ProductNameLegalIdentifier)Installer'
+      Impersonate='no'
+      Execute='deferred'
+      ExeCommand='$(var.ProductInstallerUninstallCommand)'
+      Return='check' />
+
+    <InstallExecuteSequence>
+      <RemoveExistingProducts After='InstallValidate' />
+
+      <Custom Action='NewerVersionError' After='FindRelatedProducts'>
+        NEWERVERSIONDETECTED
+      </Custom>
+
+      <!-- Any operations that rely on values, such as brand and usagestats, in
+           ClientState should not run until after
+           InstallGoogleUpdateAndRegister. This is sequenced before InstallFiles
+           so that can be used as well. -->
+      <!-- TODO(omaha): Support Rollback? Need to determine whether Product
+           was installed before installing it and only add the rollback then.
+      <Custom Action='Rollback$(var.ProductNameLegalIdentifier)'
+              After='InstallFiles'>
+        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT $(var.ProductNameLegalIdentifier)_INSTALLED)
+      </Custom>
+      Change After='InstallFiles' below to
+      After='Rollback$(var.ProductNameLegalIdentifier)'. -->
+      <Custom Action='SetInstallerInstallCommandProperty'
+              After='InstallFiles'>
+        (($ComponentGoogleUpdate>2) OR REINSTALL)
+      </Custom>
+      <Custom Action='AppendDisableUpdateRegistrationArgToInstallerInstallCommandProperty'
+              After='SetInstallerInstallCommandProperty'>
+        (($ComponentGoogleUpdate>2) OR REINSTALL) AND DISABLE_UPDATES
+      </Custom>
+      <Custom Action='Install$(var.ProductNameLegalIdentifier)'
+              After='AppendDisableUpdateRegistrationArgToInstallerInstallCommandProperty'>
+        (($ComponentGoogleUpdate>2) OR REINSTALL)
+      </Custom>
+
+      <Custom Action='Uninstall$(var.ProductNameLegalIdentifier)'
+              Before='RemoveFiles'>
+        $ComponentGoogleUpdate=2
+      </Custom>
+
+    </InstallExecuteSequence>
+
+  </Product>
+</Wix>
diff --git a/enterprise/installer/enterprise_standalone_installer.wxs.xml b/enterprise/installer/enterprise_standalone_installer.wxs.xml
index 1975b24..67899a4 100644
--- a/enterprise/installer/enterprise_standalone_installer.wxs.xml
+++ b/enterprise/installer/enterprise_standalone_installer.wxs.xml
@@ -1,165 +1,165 @@
-<?xml version='1.0' encoding='windows-1252'?>

-<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>

-  <?define CompanyFullName = 'Google, Inc.'?>

-  <?define Copyright = 'Copyright 2007-2009 Google Inc.'?>

-  <?define UpdateKeyPath = 'SOFTWARE\Google\Update' ?>

-

-  <Product

-    Id='$(var.MsiProductId)'

-    Name='$(var.ProductName)'

-    Language='1033'

-    Codepage='1252'

-    UpgradeCode='$(var.MsiUpgradeCode)'

-    Version='$(var.ProductVersion)'

-    Manufacturer='$(var.CompanyFullName)'>

-

-    <Package

-      Id='*'

-      Description='$(var.ProductName) Installer'

-      Comments='$(var.Copyright)'

-      Manufacturer='$(var.CompanyFullName)'

-      Languages='1033'

-      SummaryCodepage='1252'

-      InstallerVersion='150'

-      InstallPrivileges='elevated'

-      Compressed='yes' />

-

-    <Upgrade Id='$(var.MsiUpgradeCode)'>

-      <UpgradeVersion Property='UPGRADING'

-                      OnlyDetect='no'

-                      Minimum='0.0.0.0' IncludeMinimum='yes'

-                      Maximum='$(var.ProductVersion)' IncludeMaximum='no' />

-      <UpgradeVersion Property='NEWERVERSIONDETECTED' 

-                      OnlyDetect='yes'

-                      Minimum='$(var.ProductVersion)' IncludeMinimum='yes' />

-    </Upgrade>

-

-    <!-- Per-machine installation - make sure product appears for all users. -->

-    <Property Id='ALLUSERS' Value='1' />

-

-    <!-- Hide the Add/Remove Programs entry.

-         The application installer should have its own entry. -->

-    <Property Id='ARPSYSTEMCOMPONENT' Value='1' />

-

-    <UI>

-      <Error Id='4000'>A newer version of the $(var.ProductName) enterprise installer is already installed.</Error>

-    </UI>

-

-    <!-- Eliminates "warning LGHT1076 : ICE71: The Media table has no entries."

-    -->

-    <Media Id='1' />

-

-    <Directory Id='TARGETDIR' Name='SourceDir'>

-      <Directory Id='ProgramFilesFolder'>

-        <Directory Id='GoogleProgramDir' Name='Google'>

-          <Directory Id='UpdateDir' Name='Update'>

-

-            <Component Id='ProductClientState'

-                       Guid='6B528A57-0CD8-4b26-85F8-1CA05523B8F1'>

-              <RegistryValue Id='NonEmptyComponent' Action='write'

-                             Root='HKLM'

-                             Key='$(var.UpdateKeyPath)\ClientState\$(var.ProductGuid)'

-                             Name='EnterpriseInstall' Type='string' Value='$(var.ProductVersion)' />

-            </Component>

-

-          </Directory>

-        </Directory>

-      </Directory>

-    </Directory>

-

-    <Feature Id='Complete' Level='1'>

-      <ComponentRef Id='ProductClientState' />

-    </Feature>

-

-    <!--TODO(omaha): Add "Standalone" after fixing the ProductName issue

-        in standalone_installer.py.-->

-    <Binary Id='$(var.ProductNameLegalIdentifier)Installer'

-            SourceFile='$(var.StandaloneInstallerPath)' />

-

-    <CustomAction Id='NewerVersionError' Error='4000'/>

-

-    <CustomAction Id='SetProductTagProperty'

-      Property='ProductTag'

-      Value='appguid=$(var.ProductGuid)&amp;appname=$(var.ProductName)&amp;needsAdmin=True'

-      Execute='immediate'

-      Return='check' />

-    <CustomAction Id='AppendCustomParamsToProductTagProperty'

-      Property='ProductTag'

-      Value='[ProductTag]$(var.ProductCustomParams)'

-      Execute='immediate'

-      Return='check' />

-    <CustomAction Id='AppendBrandToProductTagProperty'

-      Property='ProductTag'

-      Value='[ProductTag]&amp;brand=[BRAND]'

-      Execute='immediate'

-      Return='check' />

-    <CustomAction Id='DoInstall'

-      BinaryKey='$(var.ProductNameLegalIdentifier)Installer'

-      Impersonate='no'

-      Execute='deferred'

-      ExeCommand='/silent /install "[ProductTag]" /installsource enterprisemsi'

-      Return='check' />

-

-    <CustomAction Id='SetProductUninstallExe'

-      Property='ProductUninstallExeProperty'

-      Value='[SystemFolder]cmd.exe' />

-    <CustomAction Id='Uninstall$(var.ProductNameLegalIdentifier)'

-      Impersonate='no'

-      Execute='deferred'

-      Property='ProductUninstallExeProperty'

-      ExeCommand='/c $(var.ProductUninstallCommandLine)'

-      Return='check' />

-

-    <InstallExecuteSequence>

-      <RemoveExistingProducts After='InstallValidate' />

-

-      <Custom Action='NewerVersionError' After='FindRelatedProducts'>

-        NEWERVERSIONDETECTED

-      </Custom>

-

-      <!-- Build tag property. -->

-      <Custom Action='SetProductTagProperty'

-              Before='AppendCustomParamsToProductTagProperty'>

-        (($ProductClientState>2) OR REINSTALL)

-      </Custom>

-      <Custom Action='AppendCustomParamsToProductTagProperty'

-              Before='AppendBrandToProductTagProperty'>

-        (($ProductClientState>2) OR REINSTALL)

-      </Custom>

-      <Custom Action='AppendBrandToProductTagProperty'

-              Before='DoInstall'>

-        (($ProductClientState>2) OR REINSTALL) AND (BRAND &lt;&gt; "")

-      </Custom>

-

-      <!-- TODO(omaha): Support Rollback? I do not think so because there are

-           very few cases where the app could be installed but Omaha would

-           report a failure. If we support rollback, need to determine whether

-           Product was installed before and only add the rollback then.

-      <Custom Action='Rollback$(var.ProductNameLegalIdentifier)'

-              After='InstallFiles'>

-        (($ProductClientState>2) OR REINSTALL) AND (NOT $(var.ProductNameLegalIdentifier)_INSTALLED)

-      </Custom>

-      Change After='InstallFiles' below to

-      After='Rollback$(var.ProductNameLegalIdentifier)'. -->

-

-      <Custom Action='DoInstall'

-              After='InstallFiles'>

-        (($ProductClientState>2) OR REINSTALL)

-      </Custom>

-

-      <Custom Action='SetProductUninstallExe'

-              Before='Uninstall$(var.ProductNameLegalIdentifier)'>

-        $ProductClientState=2

-      </Custom>

-      <Custom Action='Uninstall$(var.ProductNameLegalIdentifier)'

-              Before='RemoveFiles'>

-        $ProductClientState=2

-      </Custom>

-

-      <!-- Google Update will uninstall itself if the product is the only app it

-           so no need to have an uninstall operation. -->

-

-    </InstallExecuteSequence>

-

-  </Product>

-</Wix>

+<?xml version='1.0' encoding='windows-1252'?>
+<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
+  <?define CompanyFullName = 'Google, Inc.'?>
+  <?define Copyright = 'Copyright 2007-2009 Google Inc.'?>
+  <?define UpdateKeyPath = 'SOFTWARE\Google\Update' ?>
+
+  <Product
+    Id='$(var.MsiProductId)'
+    Name='$(var.ProductName)'
+    Language='1033'
+    Codepage='1252'
+    UpgradeCode='$(var.MsiUpgradeCode)'
+    Version='$(var.ProductVersion)'
+    Manufacturer='$(var.CompanyFullName)'>
+
+    <Package
+      Id='*'
+      Description='$(var.ProductName) Installer'
+      Comments='$(var.Copyright)'
+      Manufacturer='$(var.CompanyFullName)'
+      Languages='1033'
+      SummaryCodepage='1252'
+      InstallerVersion='150'
+      InstallPrivileges='elevated'
+      Compressed='yes' />
+
+    <Upgrade Id='$(var.MsiUpgradeCode)'>
+      <UpgradeVersion Property='UPGRADING'
+                      OnlyDetect='no'
+                      Minimum='0.0.0.0' IncludeMinimum='yes'
+                      Maximum='$(var.ProductVersion)' IncludeMaximum='no' />
+      <UpgradeVersion Property='NEWERVERSIONDETECTED' 
+                      OnlyDetect='yes'
+                      Minimum='$(var.ProductVersion)' IncludeMinimum='yes' />
+    </Upgrade>
+
+    <!-- Per-machine installation - make sure product appears for all users. -->
+    <Property Id='ALLUSERS' Value='1' />
+
+    <!-- Hide the Add/Remove Programs entry.
+         The application installer should have its own entry. -->
+    <Property Id='ARPSYSTEMCOMPONENT' Value='1' />
+
+    <UI>
+      <Error Id='4000'>A newer version of the $(var.ProductName) enterprise installer is already installed.</Error>
+    </UI>
+
+    <!-- Eliminates "warning LGHT1076 : ICE71: The Media table has no entries."
+    -->
+    <Media Id='1' />
+
+    <Directory Id='TARGETDIR' Name='SourceDir'>
+      <Directory Id='ProgramFilesFolder'>
+        <Directory Id='GoogleProgramDir' Name='Google'>
+          <Directory Id='UpdateDir' Name='Update'>
+
+            <Component Id='ProductClientState'
+                       Guid='6B528A57-0CD8-4b26-85F8-1CA05523B8F1'>
+              <RegistryValue Id='NonEmptyComponent' Action='write'
+                             Root='HKLM'
+                             Key='$(var.UpdateKeyPath)\ClientState\$(var.ProductGuid)'
+                             Name='EnterpriseInstall' Type='string' Value='$(var.ProductVersion)' />
+            </Component>
+
+          </Directory>
+        </Directory>
+      </Directory>
+    </Directory>
+
+    <Feature Id='Complete' Level='1'>
+      <ComponentRef Id='ProductClientState' />
+    </Feature>
+
+    <!--TODO(omaha): Add "Standalone" after fixing the ProductName issue
+        in standalone_installer.py.-->
+    <Binary Id='$(var.ProductNameLegalIdentifier)Installer'
+            SourceFile='$(var.StandaloneInstallerPath)' />
+
+    <CustomAction Id='NewerVersionError' Error='4000'/>
+
+    <CustomAction Id='SetProductTagProperty'
+      Property='ProductTag'
+      Value='appguid=$(var.ProductGuid)&amp;appname=$(var.ProductName)&amp;needsAdmin=True'
+      Execute='immediate'
+      Return='check' />
+    <CustomAction Id='AppendCustomParamsToProductTagProperty'
+      Property='ProductTag'
+      Value='[ProductTag]$(var.ProductCustomParams)'
+      Execute='immediate'
+      Return='check' />
+    <CustomAction Id='AppendBrandToProductTagProperty'
+      Property='ProductTag'
+      Value='[ProductTag]&amp;brand=[BRAND]'
+      Execute='immediate'
+      Return='check' />
+    <CustomAction Id='DoInstall'
+      BinaryKey='$(var.ProductNameLegalIdentifier)Installer'
+      Impersonate='no'
+      Execute='deferred'
+      ExeCommand='/silent /install "[ProductTag]" /installsource enterprisemsi'
+      Return='check' />
+
+    <CustomAction Id='SetProductUninstallExe'
+      Property='ProductUninstallExeProperty'
+      Value='[SystemFolder]cmd.exe' />
+    <CustomAction Id='Uninstall$(var.ProductNameLegalIdentifier)'
+      Impersonate='no'
+      Execute='deferred'
+      Property='ProductUninstallExeProperty'
+      ExeCommand='/c $(var.ProductUninstallCommandLine)'
+      Return='check' />
+
+    <InstallExecuteSequence>
+      <RemoveExistingProducts After='InstallValidate' />
+
+      <Custom Action='NewerVersionError' After='FindRelatedProducts'>
+        NEWERVERSIONDETECTED
+      </Custom>
+
+      <!-- Build tag property. -->
+      <Custom Action='SetProductTagProperty'
+              Before='AppendCustomParamsToProductTagProperty'>
+        (($ProductClientState>2) OR REINSTALL)
+      </Custom>
+      <Custom Action='AppendCustomParamsToProductTagProperty'
+              Before='AppendBrandToProductTagProperty'>
+        (($ProductClientState>2) OR REINSTALL)
+      </Custom>
+      <Custom Action='AppendBrandToProductTagProperty'
+              Before='DoInstall'>
+        (($ProductClientState>2) OR REINSTALL) AND (BRAND &lt;&gt; "")
+      </Custom>
+
+      <!-- TODO(omaha): Support Rollback? I do not think so because there are
+           very few cases where the app could be installed but Omaha would
+           report a failure. If we support rollback, need to determine whether
+           Product was installed before and only add the rollback then.
+      <Custom Action='Rollback$(var.ProductNameLegalIdentifier)'
+              After='InstallFiles'>
+        (($ProductClientState>2) OR REINSTALL) AND (NOT $(var.ProductNameLegalIdentifier)_INSTALLED)
+      </Custom>
+      Change After='InstallFiles' below to
+      After='Rollback$(var.ProductNameLegalIdentifier)'. -->
+
+      <Custom Action='DoInstall'
+              After='InstallFiles'>
+        (($ProductClientState>2) OR REINSTALL)
+      </Custom>
+
+      <Custom Action='SetProductUninstallExe'
+              Before='Uninstall$(var.ProductNameLegalIdentifier)'>
+        $ProductClientState=2
+      </Custom>
+      <Custom Action='Uninstall$(var.ProductNameLegalIdentifier)'
+              Before='RemoveFiles'>
+        $ProductClientState=2
+      </Custom>
+
+      <!-- Google Update will uninstall itself if the product is the only app it
+           so no need to have an uninstall operation. -->
+
+    </InstallExecuteSequence>
+
+  </Product>
+</Wix>
diff --git a/enterprise/installer/google_update_installer_fragment.wxs.xml b/enterprise/installer/google_update_installer_fragment.wxs.xml
index b133be3..994d48c 100644
--- a/enterprise/installer/google_update_installer_fragment.wxs.xml
+++ b/enterprise/installer/google_update_installer_fragment.wxs.xml
@@ -1,117 +1,117 @@
-<?xml version='1.0' encoding='windows-1252'?>

-<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>

-  <?define UpdateKeyPath = 'SOFTWARE\Google\Update' ?>

-

-  <!-- This fragment assumes machine install (ALLUSER=1). -->

-

-  <Fragment Id='FragmentGoogleUpdate' >

-    <!-- Detect whether product is already registered with Google Update. -->

-    <Property Id='PRODUCT_REGISTERED_VERSION'>

-      <RegistrySearch Id='$(var.ProductNameLegalIdentifier)RegistrationSearch'

-                      Root='HKLM'

-                      Key='$(var.UpdateKeyPath)\Clients\$(var.ProductGuid)'

-                      Name='pv' Type='raw' />

-    </Property>

-

-    <Binary Id='GoogleUpdateSetup'

-            SourceFile='$(var.GoogleUpdateMetainstallerPath)' />

-

-    <!-- This fragment needs a component that can be referenced.

-         Components must be in Directory[Ref] elements and cannot be empty.

-         Thus, we have a registry value write that has no effect.

-         To avoid multiple Directory elements with the 'ProgramFilesFolder' Id,

-         assume that the product MSI has defined a it and reference it here. -->

-    <DirectoryRef Id='ProgramFilesFolder'>

-      <Directory Id='GoogleProgramDir' Name='Google'>

-        <Directory Id='UpdateDir' Name='Update'>

-

-          <Component Id='ComponentGoogleUpdate'

-                     Guid='6B528A57-0CD8-4b26-85F8-1CA05523B8F1'>

-            <?ifdef UsingGoogleUpdate_1_2_171_OrLater?>

-            <RegistryValue Id='NonEmptyComponent' Action='write'

-                           Root='HKLM'

-                           Key='$(var.UpdateKeyPath)\ClientState\$(var.ProductGuid)'

-                           Name='EnterpriseInstall' Type='string' Value='$(var.ProductVersion)' />

-            <?else?>

-            <RegistryValue Id='NonEmptyComponent' Action='write'

-                           Root='HKLM'

-                           Key='$(var.UpdateKeyPath)\ClientState\$(var.ProductGuid)'

-                           Name='EnterpriseInstall' Type='integer' Value='1' />

-            <?endif?>

-          </Component>

-

-        </Directory>

-      </Directory>

-    </DirectoryRef>

-

-    <CustomAction Id='SetProductTagProperty'

-      Property='ProductTag'

-      Value='appguid=$(var.ProductGuid)&amp;appname=$(var.ProductName)&amp;needsAdmin=True'

-      Execute='immediate'

-      Return='check' />

-    <CustomAction Id='AppendCustomParamsToProductTagProperty'

-      Property='ProductTag'

-      Value='[ProductTag]$(var.ProductCustomParams)'

-      Execute='immediate'

-      Return='check' />

-    <CustomAction Id='AppendBrandToProductTagProperty'

-      Property='ProductTag'

-      Value='[ProductTag]&amp;brand=[BRAND]'

-      Execute='immediate'

-      Return='check' />

-    <CustomAction Id='RollbackGoogleUpdateRegistration'

-      BinaryKey='GoogleUpdateSetup'

-      Impersonate='no'

-      Execute='rollback'

-      ExeCommand='/unregisterproduct "[ProductTag]"'

-      Return='check' />

-    <?ifdef UsingGoogleUpdate_1_2_171_OrLater?>

-    <CustomAction Id='InstallGoogleUpdateAndRegister'

-      BinaryKey='GoogleUpdateSetup'

-      Impersonate='no'

-      Execute='deferred'

-      ExeCommand='/registerproduct "[ProductTag]" /installsource enterprisemsi'

-      Return='check' />

-    <?else?>

-    <CustomAction Id='InstallGoogleUpdateAndRegister'

-      BinaryKey='GoogleUpdateSetup'

-      Impersonate='no'

-      Execute='deferred'

-      ExeCommand='/registerproduct "[ProductTag]"'

-      Return='check' />

-    <?endif?>

-

-    <InstallExecuteSequence>

-      <!-- Build tag property. -->

-      <Custom Action='SetProductTagProperty'

-              Before='AppendCustomParamsToProductTagProperty'>

-        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT DISABLE_UPDATES)

-      </Custom>

-      <Custom Action='AppendCustomParamsToProductTagProperty'

-              Before='AppendBrandToProductTagProperty'>

-        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT DISABLE_UPDATES)

-      </Custom>

-      <Custom Action='AppendBrandToProductTagProperty'

-              Before='RollbackGoogleUpdateRegistration'>

-        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT DISABLE_UPDATES) AND (BRAND &lt;&gt; "")

-      </Custom>

-

-      <!-- Install Google Update before 'InstallFiles' so that brand, etc. will

-           be present when the product is installed. -->

-      <Custom Action='RollbackGoogleUpdateRegistration'

-              Before='InstallGoogleUpdateAndRegister'

-              >

-        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT DISABLE_UPDATES) AND (PRODUCT_REGISTERED_VERSION = "")

-      </Custom>

-      <Custom Action='InstallGoogleUpdateAndRegister'

-              Before='InstallFiles'>

-        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT DISABLE_UPDATES)

-      </Custom>

-

-      <!-- Google Update will uninstall itself if the product is the only app it

-           so no need to have an uninstall operation. -->

-

-    </InstallExecuteSequence>

-

-  </Fragment>

-</Wix>

+<?xml version='1.0' encoding='windows-1252'?>
+<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
+  <?define UpdateKeyPath = 'SOFTWARE\Google\Update' ?>
+
+  <!-- This fragment assumes machine install (ALLUSER=1). -->
+
+  <Fragment Id='FragmentGoogleUpdate' >
+    <!-- Detect whether product is already registered with Google Update. -->
+    <Property Id='PRODUCT_REGISTERED_VERSION'>
+      <RegistrySearch Id='$(var.ProductNameLegalIdentifier)RegistrationSearch'
+                      Root='HKLM'
+                      Key='$(var.UpdateKeyPath)\Clients\$(var.ProductGuid)'
+                      Name='pv' Type='raw' />
+    </Property>
+
+    <Binary Id='GoogleUpdateSetup'
+            SourceFile='$(var.GoogleUpdateMetainstallerPath)' />
+
+    <!-- This fragment needs a component that can be referenced.
+         Components must be in Directory[Ref] elements and cannot be empty.
+         Thus, we have a registry value write that has no effect.
+         To avoid multiple Directory elements with the 'ProgramFilesFolder' Id,
+         assume that the product MSI has defined a it and reference it here. -->
+    <DirectoryRef Id='ProgramFilesFolder'>
+      <Directory Id='GoogleProgramDir' Name='Google'>
+        <Directory Id='UpdateDir' Name='Update'>
+
+          <Component Id='ComponentGoogleUpdate'
+                     Guid='6B528A57-0CD8-4b26-85F8-1CA05523B8F1'>
+            <?ifdef UsingGoogleUpdate_1_2_171_OrLater?>
+            <RegistryValue Id='NonEmptyComponent' Action='write'
+                           Root='HKLM'
+                           Key='$(var.UpdateKeyPath)\ClientState\$(var.ProductGuid)'
+                           Name='EnterpriseInstall' Type='string' Value='$(var.ProductVersion)' />
+            <?else?>
+            <RegistryValue Id='NonEmptyComponent' Action='write'
+                           Root='HKLM'
+                           Key='$(var.UpdateKeyPath)\ClientState\$(var.ProductGuid)'
+                           Name='EnterpriseInstall' Type='integer' Value='1' />
+            <?endif?>
+          </Component>
+
+        </Directory>
+      </Directory>
+    </DirectoryRef>
+
+    <CustomAction Id='SetProductTagProperty'
+      Property='ProductTag'
+      Value='appguid=$(var.ProductGuid)&amp;appname=$(var.ProductName)&amp;needsAdmin=True'
+      Execute='immediate'
+      Return='check' />
+    <CustomAction Id='AppendCustomParamsToProductTagProperty'
+      Property='ProductTag'
+      Value='[ProductTag]$(var.ProductCustomParams)'
+      Execute='immediate'
+      Return='check' />
+    <CustomAction Id='AppendBrandToProductTagProperty'
+      Property='ProductTag'
+      Value='[ProductTag]&amp;brand=[BRAND]'
+      Execute='immediate'
+      Return='check' />
+    <CustomAction Id='RollbackGoogleUpdateRegistration'
+      BinaryKey='GoogleUpdateSetup'
+      Impersonate='no'
+      Execute='rollback'
+      ExeCommand='/unregisterproduct "[ProductTag]"'
+      Return='check' />
+    <?ifdef UsingGoogleUpdate_1_2_171_OrLater?>
+    <CustomAction Id='InstallGoogleUpdateAndRegister'
+      BinaryKey='GoogleUpdateSetup'
+      Impersonate='no'
+      Execute='deferred'
+      ExeCommand='/registerproduct "[ProductTag]" /installsource enterprisemsi'
+      Return='check' />
+    <?else?>
+    <CustomAction Id='InstallGoogleUpdateAndRegister'
+      BinaryKey='GoogleUpdateSetup'
+      Impersonate='no'
+      Execute='deferred'
+      ExeCommand='/registerproduct "[ProductTag]"'
+      Return='check' />
+    <?endif?>
+
+    <InstallExecuteSequence>
+      <!-- Build tag property. -->
+      <Custom Action='SetProductTagProperty'
+              Before='AppendCustomParamsToProductTagProperty'>
+        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT DISABLE_UPDATES)
+      </Custom>
+      <Custom Action='AppendCustomParamsToProductTagProperty'
+              Before='AppendBrandToProductTagProperty'>
+        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT DISABLE_UPDATES)
+      </Custom>
+      <Custom Action='AppendBrandToProductTagProperty'
+              Before='RollbackGoogleUpdateRegistration'>
+        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT DISABLE_UPDATES) AND (BRAND &lt;&gt; "")
+      </Custom>
+
+      <!-- Install Google Update before 'InstallFiles' so that brand, etc. will
+           be present when the product is installed. -->
+      <Custom Action='RollbackGoogleUpdateRegistration'
+              Before='InstallGoogleUpdateAndRegister'
+              >
+        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT DISABLE_UPDATES) AND (PRODUCT_REGISTERED_VERSION = "")
+      </Custom>
+      <Custom Action='InstallGoogleUpdateAndRegister'
+              Before='InstallFiles'>
+        (($ComponentGoogleUpdate>2) OR REINSTALL) AND (NOT DISABLE_UPDATES)
+      </Custom>
+
+      <!-- Google Update will uninstall itself if the product is the only app it
+           so no need to have an uninstall operation. -->
+
+    </InstallExecuteSequence>
+
+  </Fragment>
+</Wix>
diff --git a/enterprise/public_apps.py b/enterprise/public_apps.py
index 1746b87..aa50382 100644
--- a/enterprise/public_apps.py
+++ b/enterprise/public_apps.py
@@ -1,70 +1,70 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-"""Contains the list of supported apps that have been publicly announced.

-

-This file is used in the creation of GoogleUpdate.adm.

-"""

-

-# Specifies the list of supported apps that have been publicly announced.

-# The list is used to create app-specific entries in the Group Policy template.

-# Each element of the list is a tuple of:

-# (app name, app ID, optional string to append to the auto-update explanation).

-# The auto-update explanation should start with a space or double new line

-# (\n\n)

-# PLEASE KEEP THE LIST ALPHABETIZED BY APP NAME.

-EXTERNAL_APPS = [

-    ('Gears',

-     '{283EAF47-8817-4C2B-A801-AD1FADFB7BAA}',

-     ' Check http://gears.google.com/.'),

-    ('Google Advertising Cookie Opt-out Plugin',

-     '{ADDE8406-A0F3-4AC2-8878-ADC0BD37BD86}',

-     'Check http://www.google.com/ads/preferences/plugin/.'),

-    ('Google Apps',

-     '{C4D65027-B96A-49A5-B13C-4E7FAFD2FB7B}',

-     ''),

-    ('Google Chrome',

-     '{8A69D345-D564-463C-AFF1-A69D9E530F96}',

-     ' Check http://www.google.com/chrome/.'),

-    ('Google Earth',

-     '{74AF07D8-FB8F-4D51-8AC7-927721D56EBB}',

-     ' Check http://earth.google.com/.'),

-    ('Google Earth (per-user install)',

-     '{0A52903D-0FBF-439A-93E4-CB609A2F63DB}',

-     ' Check http://earth.google.com/.'),

-    ('Google Earth Plugin',

-     '{2BF2CA35-CCAF-4E58-BAB7-4163BFA03B88}',

-     ' Check http://code.google.com/apis/earth/.'),

-    ('Google Earth Pro',

-     '{65E60E95-0DE9-43FF-9F3F-4F7D2DFF04B5}',

-     ' Check http://earth.google.com/enterprise/earth_pro.html.'),

-    ('Google Email Uploader',

-     '{84F41014-78F2-4EBF-AF9B-8D7D12FCC37B}',

-     ' Check http://mail.google.com/mail/help/email_uploader.html.'),

-    ('Google Talk Labs Edition',

-     '{7C9D2019-25AD-4F9B-B4C4-F0F537A9626E}',

-     ' Check http://www.google.com/talk/labsedition/.'),

-    ('Google Talk Plugin (Voice and Video Chat)',

-     '{D0AB2EBC-931B-4013-9FEB-C9C4C2225C8C}',

-     ' Check http://mail.google.com/videochat.'),

-    ('O3D',

-     '{70308795-045C-42DA-8F4E-D452381A7459}',

-     'Check http://code.google.com/apis/o3d/.'),

-    ('O3D Extras',

-     '{34B2805D-C72C-4F81-AED5-5A22D1E092F1}',

-     ''),

-    ]

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+"""Contains the list of supported apps that have been publicly announced.
+
+This file is used in the creation of GoogleUpdate.adm.
+"""
+
+# Specifies the list of supported apps that have been publicly announced.
+# The list is used to create app-specific entries in the Group Policy template.
+# Each element of the list is a tuple of:
+# (app name, app ID, optional string to append to the auto-update explanation).
+# The auto-update explanation should start with a space or double new line
+# (\n\n)
+# PLEASE KEEP THE LIST ALPHABETIZED BY APP NAME.
+EXTERNAL_APPS = [
+    ('Gears',
+     '{283EAF47-8817-4C2B-A801-AD1FADFB7BAA}',
+     ' Check http://gears.google.com/.'),
+    ('Google Advertising Cookie Opt-out Plugin',
+     '{ADDE8406-A0F3-4AC2-8878-ADC0BD37BD86}',
+     'Check http://www.google.com/ads/preferences/plugin/.'),
+    ('Google Apps',
+     '{C4D65027-B96A-49A5-B13C-4E7FAFD2FB7B}',
+     ''),
+    ('Google Chrome',
+     '{8A69D345-D564-463C-AFF1-A69D9E530F96}',
+     ' Check http://www.google.com/chrome/.'),
+    ('Google Earth',
+     '{74AF07D8-FB8F-4D51-8AC7-927721D56EBB}',
+     ' Check http://earth.google.com/.'),
+    ('Google Earth (per-user install)',
+     '{0A52903D-0FBF-439A-93E4-CB609A2F63DB}',
+     ' Check http://earth.google.com/.'),
+    ('Google Earth Plugin',
+     '{2BF2CA35-CCAF-4E58-BAB7-4163BFA03B88}',
+     ' Check http://code.google.com/apis/earth/.'),
+    ('Google Earth Pro',
+     '{65E60E95-0DE9-43FF-9F3F-4F7D2DFF04B5}',
+     ' Check http://earth.google.com/enterprise/earth_pro.html.'),
+    ('Google Email Uploader',
+     '{84F41014-78F2-4EBF-AF9B-8D7D12FCC37B}',
+     ' Check http://mail.google.com/mail/help/email_uploader.html.'),
+    ('Google Talk Labs Edition',
+     '{7C9D2019-25AD-4F9B-B4C4-F0F537A9626E}',
+     ' Check http://www.google.com/talk/labsedition/.'),
+    ('Google Talk Plugin (Voice and Video Chat)',
+     '{D0AB2EBC-931B-4013-9FEB-C9C4C2225C8C}',
+     ' Check http://mail.google.com/videochat.'),
+    ('O3D',
+     '{70308795-045C-42DA-8F4E-D452381A7459}',
+     'Check http://code.google.com/apis/o3d/.'),
+    ('O3D Extras',
+     '{34B2805D-C72C-4F81-AED5-5A22D1E092F1}',
+     ''),
+    ]
diff --git a/google_update/GoogleUpdate.manifest b/google_update/GoogleUpdate.manifest
index beea4e6..1cf9856 100644
--- a/google_update/GoogleUpdate.manifest
+++ b/google_update/GoogleUpdate.manifest
@@ -1,22 +1,22 @@
-<?xml version="1.0" encoding="utf-8"?>

-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

-  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">

-    <security>

-      <requestedPrivileges>

-        <requestedExecutionLevel level="asInvoker" />

-      </requestedPrivileges>

-    </security>

-  </trustInfo>

-  <dependency>

-    <dependentAssembly>

-        <assemblyIdentity

-            type="win32"

-            name="Microsoft.Windows.Common-Controls"

-            version="6.0.0.0"

-            processorArchitecture="X86"

-            publicKeyToken="6595b64144ccf1df"

-            language="*"

-        />

-    </dependentAssembly>

-  </dependency>

-</assembly>

+<?xml version="1.0" encoding="utf-8"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+  <dependency>
+    <dependentAssembly>
+        <assemblyIdentity
+            type="win32"
+            name="Microsoft.Windows.Common-Controls"
+            version="6.0.0.0"
+            processorArchitecture="X86"
+            publicKeyToken="6595b64144ccf1df"
+            language="*"
+        />
+    </dependentAssembly>
+  </dependency>
+</assembly>
diff --git a/google_update/bin/Readme.txt b/google_update/bin/Readme.txt
index b02f6c8..b30b79f 100644
--- a/google_update/bin/Readme.txt
+++ b/google_update/bin/Readme.txt
@@ -1,9 +1,9 @@
-This directory contains the saved "constant" version of the GoogleUpdate.exe

-shell. Using the same executable avoids firewall prompts in some cases when

-updating Google Update.

-

-This shell can only be used with goopdate.dll files that have been signed with

-the real certificate.

-

-When updating the shell, also change the expected version in

-..\google_update_unittest.cc.

+This directory contains the saved "constant" version of the GoogleUpdate.exe
+shell. Using the same executable avoids firewall prompts in some cases when
+updating Google Update.
+
+This shell can only be used with goopdate.dll files that have been signed with
+the real certificate.
+
+When updating the shell, also change the expected version in
+..\google_update_unittest.cc.
diff --git a/google_update/build.scons b/google_update/build.scons
index d6b8661..2ab5db3 100644
--- a/google_update/build.scons
+++ b/google_update/build.scons
@@ -1,153 +1,153 @@
-#!/usr/bin/python2.4

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-# We always build the shell as GoogleUpdate_built.exe.

-# For official builds, we copy the saved constant shell to the output directory.

-# For unofficial builds, we copy the built shell.

-# Otherwise, the goopdate.dll certificate check fails.

-#

-# Changes to this executable will not appear in offical builds until they are

-# included in an offical build and the resulting file is checked in to the

-# saved constant shell location.

-

-

-Import('env')

-

-# Only build the first version. We don't need a test version.

-v = env['product_version'][0]

-version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-# The shell contains languages not supported by the rest of Omaha.

-# This is intended to allow us to add languages in the future without releasing

-# a new shell.

-# 'userdefault' addresses apps that don't look up the resource for the OS

-# language. See http://b/1328652.

-

-shell_languages = list(env['languages'])

-

-additional_shell_languages = [

-    'userdefault',

-    'zh-HK',

-    ]

-

-if 1 < len(shell_languages):

-  shell_languages += additional_shell_languages

-

-

-exe_env = env.Clone()

-

-# TODO(omaha): While there is a precompile.h, it does not actually use PCH.

-exe_env.Append(

-    CCFLAGS = [

-        '/wd4548',

-        '/wd4917',

-        '/wd4265',

-        '/FIgoogle_update/precompile.h',

-        ],

-    LIBS = [

-        'delayimp.lib',

-        'advapi32.lib',

-        'crypt32.lib',

-        'kernel32.lib',

-        'ole32.lib',

-        'shell32.lib',

-        'shlwapi.lib',

-        'user32.lib',

-        'wintrust.lib',

-        ('atls.lib', 'atlsd.lib')[exe_env.Bit('debug')],

-        ('libcmt.lib', 'libcmtd.lib')[exe_env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[exe_env.Bit('debug')],

-        ],

-    LINKFLAGS = [

-        '/NODEFAULTLIB',

-        '/MERGE:.rdata=.text'

-        '/DELAYLOAD:advapi32.dll',

-        '/DELAYLOAD:crypt32.dll',

-        '/DELAYLOAD:shell32.dll',

-        '/DELAYLOAD:shlwapi.dll',

-        '/DELAYLOAD:user32.dll',

-        '/DELAYLOAD:wintrust.dll',

-

-        # Forces the dependency on ole32.lib.

-        '/INCLUDE:_CoCreateGuid@4',

-        ],

-    RCFLAGS = [

-        '/DVERSION_MAJOR=%d' % v[0],

-        '/DVERSION_MINOR=%d' % v[1],

-        '/DVERSION_BUILD=%d' % v[2],

-        '/DVERSION_PATCH=%d' % v[3],

-        '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,

-        ],

-)

-

-

-exe_inputs = [

-    'winmain.cc',

-     '../common/signaturevalidator.cc',

-     exe_env.RES('resource.rc'),

-     ]

-

-# Compile .rc files, then add the resulting .res files to the exe inputs.

-for language in shell_languages:

-  exe_inputs += exe_env.RES('generated_resources_%s.rc' % language)

-

-# Force a rebuild when the version changes. The en file should be enough to

-# rebuild all languages.

-Depends(exe_env['OBJ_ROOT'] + '/google_update/generated_resources_en.res',

-    exe_env['MAIN_DIR'] + '/VERSION')

-

-# Need to add custom suffix to avoid target conflict with

-# common/signaturevalidator.obj

-exe_env['OBJSUFFIX'] = '_gu' + exe_env['OBJSUFFIX']

-

-

-# We disable runtime stack check to avoid increasing the code size.

-# There is a compiler pragma to programmatically disable the stack checks

-# but for some reason it did not work.

-exe_env.FilterOut(CPPFLAGS = ['/GS'])

-

-# Disable stack checks for VC80. Stack checks are on by default.

-if exe_env['msc_ver'] >= 1400:

-  exe_env['CCFLAGS'] += ['/GS-']

-

-unsigned_exe_output = exe_env.ComponentProgram(

-    prog_name='GoogleUpdate_unsigned.exe',

-    source=exe_inputs,

-)

-

-sign_output = env.SignedBinary(

-    target='GoogleUpdate_signed.exe',

-    source=unsigned_exe_output,

-)

-

-env.Replicate('$STAGING_DIR', sign_output)

-

-# Official builds should always use the checked in constant shell unless they

-# are being built with the test certificate, in which case the saved constant

-# shell would fail to validate the certificates in the build.

-if env.Bit('build_server') and not env.Bit('test_certificate'):

-  # Copy the constant shell from its checked in location.

-  source_shell = ('$MAIN_DIR/google_update/bin/%s/GoogleUpdate.exe' %

-      ('opt', 'dbg')[env.Bit('debug')])

-else:

-  # Use the version we just built.

-  source_shell = sign_output[0]

-

-env.Replicate('$STAGING_DIR', source_shell, REPLICATE_REPLACE=[('_signed', '')])

-env.Replicate(target='$STAGING_DIR',

-              source=sign_output[0],

-              REPLICATE_REPLACE=[('GoogleUpdate_signed', 'GoogleCrashHandler')]

-)

+#!/usr/bin/python2.4
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+# We always build the shell as GoogleUpdate_built.exe.
+# For official builds, we copy the saved constant shell to the output directory.
+# For unofficial builds, we copy the built shell.
+# Otherwise, the goopdate.dll certificate check fails.
+#
+# Changes to this executable will not appear in offical builds until they are
+# included in an offical build and the resulting file is checked in to the
+# saved constant shell location.
+
+
+Import('env')
+
+# Only build the first version. We don't need a test version.
+v = env['product_version'][0]
+version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+# The shell contains languages not supported by the rest of Omaha.
+# This is intended to allow us to add languages in the future without releasing
+# a new shell.
+# 'userdefault' addresses apps that don't look up the resource for the OS
+# language. See http://b/1328652.
+
+shell_languages = list(env['languages'])
+
+additional_shell_languages = [
+    'userdefault',
+    'zh-HK',
+    ]
+
+if 1 < len(shell_languages):
+  shell_languages += additional_shell_languages
+
+
+exe_env = env.Clone()
+
+# TODO(omaha): While there is a precompile.h, it does not actually use PCH.
+exe_env.Append(
+    CCFLAGS = [
+        '/wd4548',
+        '/wd4917',
+        '/wd4265',
+        '/FIgoogle_update/precompile.h',
+        ],
+    LIBS = [
+        'delayimp.lib',
+        'advapi32.lib',
+        'crypt32.lib',
+        'kernel32.lib',
+        'ole32.lib',
+        'shell32.lib',
+        'shlwapi.lib',
+        'user32.lib',
+        'wintrust.lib',
+        ('atls.lib', 'atlsd.lib')[exe_env.Bit('debug')],
+        ('libcmt.lib', 'libcmtd.lib')[exe_env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[exe_env.Bit('debug')],
+        ],
+    LINKFLAGS = [
+        '/NODEFAULTLIB',
+        '/MERGE:.rdata=.text'
+        '/DELAYLOAD:advapi32.dll',
+        '/DELAYLOAD:crypt32.dll',
+        '/DELAYLOAD:shell32.dll',
+        '/DELAYLOAD:shlwapi.dll',
+        '/DELAYLOAD:user32.dll',
+        '/DELAYLOAD:wintrust.dll',
+
+        # Forces the dependency on ole32.lib.
+        '/INCLUDE:_CoCreateGuid@4',
+        ],
+    RCFLAGS = [
+        '/DVERSION_MAJOR=%d' % v[0],
+        '/DVERSION_MINOR=%d' % v[1],
+        '/DVERSION_BUILD=%d' % v[2],
+        '/DVERSION_PATCH=%d' % v[3],
+        '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,
+        ],
+)
+
+
+exe_inputs = [
+    'winmain.cc',
+     '../common/signaturevalidator.cc',
+     exe_env.RES('resource.rc'),
+     ]
+
+# Compile .rc files, then add the resulting .res files to the exe inputs.
+for language in shell_languages:
+  exe_inputs += exe_env.RES('generated_resources_%s.rc' % language)
+
+# Force a rebuild when the version changes. The en file should be enough to
+# rebuild all languages.
+Depends(exe_env['OBJ_ROOT'] + '/google_update/generated_resources_en.res',
+    exe_env['MAIN_DIR'] + '/VERSION')
+
+# Need to add custom suffix to avoid target conflict with
+# common/signaturevalidator.obj
+exe_env['OBJSUFFIX'] = '_gu' + exe_env['OBJSUFFIX']
+
+
+# We disable runtime stack check to avoid increasing the code size.
+# There is a compiler pragma to programmatically disable the stack checks
+# but for some reason it did not work.
+exe_env.FilterOut(CPPFLAGS = ['/GS'])
+
+# Disable stack checks for VC80. Stack checks are on by default.
+if exe_env['msc_ver'] >= 1400:
+  exe_env['CCFLAGS'] += ['/GS-']
+
+unsigned_exe_output = exe_env.ComponentProgram(
+    prog_name='GoogleUpdate_unsigned.exe',
+    source=exe_inputs,
+)
+
+sign_output = env.SignedBinary(
+    target='GoogleUpdate_signed.exe',
+    source=unsigned_exe_output,
+)
+
+env.Replicate('$STAGING_DIR', sign_output)
+
+# Official builds should always use the checked in constant shell unless they
+# are being built with the test certificate, in which case the saved constant
+# shell would fail to validate the certificates in the build.
+if env.Bit('build_server') and not env.Bit('test_certificate'):
+  # Copy the constant shell from its checked in location.
+  source_shell = ('$MAIN_DIR/google_update/bin/%s/GoogleUpdate.exe' %
+      ('opt', 'dbg')[env.Bit('debug')])
+else:
+  # Use the version we just built.
+  source_shell = sign_output[0]
+
+env.Replicate('$STAGING_DIR', source_shell, REPLICATE_REPLACE=[('_signed', '')])
+env.Replicate(target='$STAGING_DIR',
+              source=sign_output[0],
+              REPLICATE_REPLACE=[('GoogleUpdate_signed', 'GoogleCrashHandler')]
+)
diff --git a/google_update/google_update.grh b/google_update/google_update.grh
index 71e0e72..6623270 100644
--- a/google_update/google_update.grh
+++ b/google_update/google_update.grh
@@ -1,23 +1,23 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// This file is automatically generated by GRIT.  Do not edit.

-// Built on Mon Apr 06 11:33:31 2009

-

-#ifndef RESOURCE_734604429686__

-#define RESOURCE_734604429686__

-

-

-

-#endif // RESOURCE_734604429686__

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// This file is automatically generated by GRIT.  Do not edit.
+// Built on Mon Apr 06 11:33:31 2009
+
+#ifndef RESOURCE_734604429686__
+#define RESOURCE_734604429686__
+
+
+
+#endif // RESOURCE_734604429686__
diff --git a/google_update/google_update_unittest.cc b/google_update/google_update_unittest.cc
index fb7791a..d01f60f 100644
--- a/google_update/google_update_unittest.cc
+++ b/google_update/google_update_unittest.cc
@@ -1,45 +1,45 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <atlpath.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/file.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(GoogleUpdateTest, ShellVersion) {

-  CPath actual_shell_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(actual_shell_path.Append(kGoopdateFileName));

-

-  ASSERT_TRUE(File::Exists(actual_shell_path));

-  const ULONGLONG actual_shell_version =

-      app_util::GetVersionFromFile(actual_shell_path);

-

-  EXPECT_TRUE(actual_shell_version);

-#if TEST_CERTIFICATE

-  EXPECT_EQ(OMAHA_BUILD_VERSION, actual_shell_version);

-  EXPECT_STREQ(OMAHA_BUILD_VERSION_STRING,

-               StringFromVersion(actual_shell_version));

-#else

-  // This version must be updated whenever the saved shell is updated.

-  EXPECT_STREQ(_T("1.2.131.7"), StringFromVersion(actual_shell_version));

-#endif

-}

-

-}  // namespace omaha

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <atlpath.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/file.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(GoogleUpdateTest, ShellVersion) {
+  CPath actual_shell_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(actual_shell_path.Append(kGoopdateFileName));
+
+  ASSERT_TRUE(File::Exists(actual_shell_path));
+  const ULONGLONG actual_shell_version =
+      app_util::GetVersionFromFile(actual_shell_path);
+
+  EXPECT_TRUE(actual_shell_version);
+#if TEST_CERTIFICATE
+  EXPECT_EQ(OMAHA_BUILD_VERSION, actual_shell_version);
+  EXPECT_STREQ(OMAHA_BUILD_VERSION_STRING,
+               StringFromVersion(actual_shell_version));
+#else
+  // This version must be updated whenever the saved shell is updated.
+  EXPECT_STREQ(_T("1.2.131.7"), StringFromVersion(actual_shell_version));
+#endif
+}
+
+}  // namespace omaha
diff --git a/google_update/precompile.h b/google_update/precompile.h
index 56c03d0..8f30f0c 100644
--- a/google_update/precompile.h
+++ b/google_update/precompile.h
@@ -1,35 +1,35 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOGLE_UPDATE_PRECOMPILE_H__

-#define OMAHA_GOOGLE_UPDATE_PRECOMPILE_H__

-

-#pragma runtime_checks("", off)

-

-#ifndef WIN32_LEAN_AND_MEAN

-#define WIN32_LEAN_AND_MEAN

-#endif

-

-#include <windows.h>

-#include <shlwapi.h>

-#include <tchar.h>

-

-#pragma warning(push)

-// C4310: cast truncates constant value

-#pragma warning(disable : 4310)

-#include "base/basictypes.h"

-#pragma warning(pop)

-

-#endif  // OMAHA_GOOGLE_UPDATE_PRECOMPILE_H__

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOGLE_UPDATE_PRECOMPILE_H__
+#define OMAHA_GOOGLE_UPDATE_PRECOMPILE_H__
+
+#pragma runtime_checks("", off)
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+#include <shlwapi.h>
+#include <tchar.h>
+
+#pragma warning(push)
+// C4310: cast truncates constant value
+#pragma warning(disable : 4310)
+#include "base/basictypes.h"
+#pragma warning(pop)
+
+#endif  // OMAHA_GOOGLE_UPDATE_PRECOMPILE_H__
diff --git a/google_update/resource.h b/google_update/resource.h
index 1a1b7a3..d2e8802 100644
--- a/google_update/resource.h
+++ b/google_update/resource.h
@@ -1,22 +1,22 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOGLE_UPDATE_RESOURCE_H_

-#define OMAHA_GOOGLE_UPDATE_RESOURCE_H_

-

-// Icons.

-#define IDI_APP                         101

-

-#endif // OMAHA_GOOGLE_UPDATE_RESOURCE_H_

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOGLE_UPDATE_RESOURCE_H_
+#define OMAHA_GOOGLE_UPDATE_RESOURCE_H_
+
+// Icons.
+#define IDI_APP                         101
+
+#endif // OMAHA_GOOGLE_UPDATE_RESOURCE_H_
diff --git a/google_update/resource.rc b/google_update/resource.rc
index 4b631a0..5a35419 100644
--- a/google_update/resource.rc
+++ b/google_update/resource.rc
@@ -1,27 +1,27 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "resource.h"

-#include "afxres.h"

-

-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

-#pragma code_page(1252)

-

-1 RT_MANIFEST "GoogleUpdate.manifest"

-

-// Icon with lowest ID value placed first to ensure application icon

-// remains consistent on all systems.

-IDI_APP                 ICON                    "omaha/goopdate/goopdate.ico"

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "resource.h"
+#include "afxres.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+1 RT_MANIFEST "GoogleUpdate.manifest"
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_APP                 ICON                    "omaha/goopdate/goopdate.ico"
+
diff --git a/google_update/version.rc b/google_update/version.rc
index d15c3a8..c74e5ba 100644
--- a/google_update/version.rc
+++ b/google_update/version.rc
@@ -1,57 +1,57 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <afxres.h>

-

-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

-

-VS_VERSION_INFO VERSIONINFO

- FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- FILEFLAGSMASK 0x17L

-#ifdef _DEBUG

- FILEFLAGS 0x1L

-#else

- FILEFLAGS 0x0L

-#endif

- FILEOS 0x4L

- FILETYPE 0x0L

- FILESUBTYPE 0x0L

-BEGIN

-    BLOCK "StringFileInfo"

-    BEGIN

-        BLOCK "[GRITVERLANGCHARSETHEX]"

-        BEGIN

-            VALUE "CompanyName", "Google Inc."

-            VALUE "FileDescription", "Google Installer"

-            VALUE "FileVersion", VERSION_NUMBER_STRING

-            VALUE "InternalName", "Google Update"

-            VALUE "LegalCopyright", "Copyright 2007-2009 Google Inc."

-            VALUE "OriginalFilename", "GoogleUpdate.exe"

-            VALUE "ProductName", "Google Update"

-            VALUE "ProductVersion", VERSION_NUMBER_STRING

-#ifdef _DEBUG

-            VALUE "Debug", ""

-#endif

-#if !OFFICIAL_BUILD

-            VALUE "Privatebuild", ""

-#endif

-        END

-    END

-    BLOCK "VarFileInfo"

-    BEGIN

-        VALUE "Translation",  [GRITVERLANGID], [GRITVERCHARSETID]

-    END

-END

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <afxres.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "[GRITVERLANGCHARSETHEX]"
+        BEGIN
+            VALUE "CompanyName", "Google Inc."
+            VALUE "FileDescription", "Google Installer"
+            VALUE "FileVersion", VERSION_NUMBER_STRING
+            VALUE "InternalName", "Google Update"
+            VALUE "LegalCopyright", "Copyright 2007-2009 Google Inc."
+            VALUE "OriginalFilename", "GoogleUpdate.exe"
+            VALUE "ProductName", "Google Update"
+            VALUE "ProductVersion", VERSION_NUMBER_STRING
+#ifdef _DEBUG
+            VALUE "Debug", ""
+#endif
+#if !OFFICIAL_BUILD
+            VALUE "Privatebuild", ""
+#endif
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation",  [GRITVERLANGID], [GRITVERCHARSETID]
+    END
+END
diff --git a/google_update/winmain.cc b/google_update/winmain.cc
index d892b4c..1d36f39 100644
--- a/google_update/winmain.cc
+++ b/google_update/winmain.cc
@@ -1,298 +1,298 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// This is a small shell that loads a DLL calls its well known entry point.

-// The intention is to only depend on OS mechanisms and avoid the LIBC

-// dependency completely.

-// This indirection is done primarily to:

-// Play nicely with software firewalls. Most firewalls watch the executable

-// module making network requests and we do not want them to notify the user

-// after we've updated the program. The DLL can change independently of the

-// shell and we expect the shell to remain unchanged most of the time.

-//

-// Changes to this executable will not appear in offical builds until they are

-// included in an offical build and the resulting file is checked in to the

-// saved shell location.

-

-// Disable the RTC checks because this shell doesn't build with a CRT.

-#pragma runtime_checks("", off)

-

-#ifndef WIN32_LEAN_AND_MEAN

-#define WIN32_LEAN_AND_MEAN

-#endif

-

-#include <windows.h>

-#include <shlobj.h>

-#include <shlwapi.h>

-#include <tchar.h>

-

-#include <atlbase.h>

-#include <atlpath.h>

-#include <atlstr.h>

-

-#include "omaha/common/constants.h"

-#include "omaha/common/error.h"

-#include "omaha/common/signaturevalidator.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/main.h"

-

-namespace omaha {

-

-// Disable the stack checks to keep the code size down.

-// The check_stack pragma did not really work. The stack checks had to be

-// disabled in the mk_file.

-#pragma check_stack()

-

-// Have to define this here since this is used in signaturevalidator.cpp.

-// This is defined in error.cc, but that pulls in debug.cpp which has a lot

-// of additional dependencies we don't want.  Not worth it for just this

-// function.

-HRESULT HRESULTFromLastError() {

-  DWORD error_code = ::GetLastError();

-  return (error_code != NO_ERROR) ? HRESULT_FROM_WIN32(error_code) : E_FAIL;

-}

-

-// Adapted from File::Exists in file.cpp.

-bool FileExists(const TCHAR* file_name) {

-  if (!file_name || !*file_name) {

-    return false;

-  }

-

-  WIN32_FILE_ATTRIBUTE_DATA attrs = {0};

-  return 0 != ::GetFileAttributesEx(file_name, ::GetFileExInfoStandard, &attrs);

-}

-

-bool IsVistaOrLater() {

-  static bool known = false;

-  static bool is_vista = false;

-  if (!known) {

-    OSVERSIONINFOEX osvi = {0};

-    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

-    osvi.dwMajorVersion = 6;

-    DWORDLONG conditional = 0;

-    VER_SET_CONDITION(conditional, VER_MAJORVERSION, VER_GREATER_EQUAL);

-    is_vista = !!::VerifyVersionInfo(&osvi, VER_MAJORVERSION, conditional);

-    known = true;

-  }

-  return is_vista;

-}

-

-bool IsRunningFromProgramFilesDirectory() {

-  // Get the HMODULE for the current process.

-  HMODULE module_handle = ::GetModuleHandle(NULL);

-  if (!module_handle) {

-    return false;

-  }

-

-  // Get the full path to the module based on the HMODULE.

-  CString module_path;

-  DWORD result = ::GetModuleFileName(module_handle,

-                                     module_path.GetBufferSetLength(MAX_PATH),

-                                     MAX_PATH);

-  module_handle = NULL;

-

-  if (result == 0) {

-    return false;

-  }

-

-  // Get the directory of the current process without the filename.

-  CPath path_temp(module_path);

-  path_temp.RemoveFileSpec();

-  module_path = static_cast<CString>(path_temp);

-

-  // Get the directory to %ProgramFiles%.

-  TCHAR folder_path_buffer[MAX_PATH] = {0};

-  HRESULT hr = ::SHGetFolderPath(NULL,

-                                 CSIDL_PROGRAM_FILES,

-                                 NULL,

-                                 SHGFP_TYPE_CURRENT,

-                                 folder_path_buffer);

-  if (FAILED(hr)) {

-    return false;

-  }

-

-  // Append the google/update install path onto %ProgramFiles%.

-  CString folder_path = folder_path_buffer;

-  if (!::PathAppend(CStrBuf(folder_path, MAX_PATH),

-                    OMAHA_REL_GOOPDATE_INSTALL_DIR)) {

-    return false;

-  }

-

-  folder_path.MakeLower();

-  module_path.MakeLower();

-

-  // Check if module_path starts with folder_path.

-  return (module_path.Find(folder_path) == 0);

-}

-

-// If we're not running from program files and we're running as an elevated

-// user on Vista, we need to validate the signature of goopdate.dll before

-// loading it.

-HRESULT VerifySignatureIfNecessary(const TCHAR* file_path,

-                                   bool is_running_from_program_files) {

-  if (is_running_from_program_files ||

-      !IsVistaOrLater() ||

-      !::IsUserAnAdmin()) {

-    return S_OK;

-  }

-

-  // Verify the Authenticode signature but use only the local cache for

-  // revocation checks.

-  HRESULT hr = VerifySignature(file_path, false);

-#if TEST_CERTIFICATE

-  // The chain of trust will not validate on builds signed with the test

-  // certificate.

-  if (CERT_E_UNTRUSTEDROOT == hr) {

-    hr = S_OK;

-  }

-#endif

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Verify that there is a Google certificate and that it has not expired.

-  if (!VerifySigneeIsGoogle(file_path)) {

-    return GOOGLEUPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED;

-  }

-

-  return S_OK;

-}

-

-HRESULT GetRegisteredVersion(bool is_machine, CString* version) {

-  HKEY key = NULL;

-  LONG res = ::RegOpenKeyEx(is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,

-                            GOOPDATE_REG_RELATIVE_CLIENTS GOOPDATE_APP_ID,

-                            0,

-                            KEY_READ,

-                            &key);

-  if (ERROR_SUCCESS != res) {

-    return HRESULT_FROM_WIN32(res);

-  }

-

-  DWORD type = 0;

-  DWORD version_length = 50;

-  res = ::SHQueryValueEx(key,

-                         omaha::kRegValueProductVersion,

-                         NULL,

-                         &type,

-                         CStrBuf(*version, version_length),

-                         &version_length);

-  if (ERROR_SUCCESS != res) {

-    return HRESULT_FROM_WIN32(res);

-  }

-

-  if (REG_SZ != type) {

-    return E_UNEXPECTED;

-  }

-

-  return S_OK;

-}

-

-HRESULT GetDllPath(HINSTANCE instance, bool is_machine, CString* dll_path) {

-  TCHAR base_path[MAX_PATH] = {0};

-  TCHAR path[MAX_PATH] = {0};

-

-  if (!::GetModuleFileName(instance, base_path, arraysize(base_path))) {

-    return HRESULTFromLastError();

-  }

-  ::PathRemoveFileSpec(base_path);

-

-  // Try the side-by-side DLL first.

-  _tcscpy_s(path, arraysize(path), base_path);

-  if (!::PathAppend(path, omaha::kGoopdateDllName)) {

-    return HRESULTFromLastError();

-  }

-  if (FileExists(path)) {

-    *dll_path = path;

-    return S_OK;

-  }

-

-  // Try the version subdirectory.

-  _tcscpy_s(path, arraysize(path), base_path);

-  CString version;

-  HRESULT hr = GetRegisteredVersion(is_machine, &version);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (!::PathAppend(path, version)) {

-    return HRESULTFromLastError();

-  }

-  if (!::PathAppend(path, omaha::kGoopdateDllName)) {

-    return HRESULTFromLastError();

-  }

-  if (!FileExists(path)) {

-    return GOOGLEUPDATE_E_DLL_NOT_FOUND;

-  }

-

-  *dll_path = path;

-  return S_OK;

-}

-

-}  // namespace omaha

-

-// Algorithm:

-//  * Looks for goopdate.dll in the current directory.

-//  * If it is not found, looks for goopdate.dll in a version subdirectory based

-//    on the version found in the registry.

-//  * Verifies the signature of the goopdate.dll file.

-//  * Loads the DLL and calls the entry point.

-int WINAPI _tWinMain(HINSTANCE instance,

-                     HINSTANCE,

-                     LPTSTR,

-                     int cmd_show) {

-  bool is_running_from_program_files =

-      omaha::IsRunningFromProgramFilesDirectory();

-

-  // We assume here that running from program files means we should check

-  // the machine install version and otherwise we should check the user

-  // version. This should be true in all end user cases except for initial

-  // installs from the temp directory and OneClick cross-installs. In both

-  // cases, the DLL should be in the same directory so we should not get here.

-  // For developer use cases, the DLL should also be in the same directory.

-  bool is_machine = is_running_from_program_files;

-

-  CString dll_path;

-  HRESULT hr = omaha::GetDllPath(instance, is_machine, &dll_path);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = omaha::VerifySignatureIfNecessary(dll_path,

-                                         is_running_from_program_files);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  HMODULE module(::LoadLibraryEx(dll_path, NULL, 0));

-  if (!module) {

-    return omaha::HRESULTFromLastError();

-  }

-

-  DllEntry dll_entry = reinterpret_cast<DllEntry>(

-      ::GetProcAddress(module, omaha::kGoopdateDllEntryAnsi));

-  if (dll_entry) {

-    // We must send in GetCommandLine() and not cmd_line because the command

-    // line parsing code expects to have the program name as the first argument

-    // and cmd_line does not provide this.

-    hr = dll_entry(::GetCommandLine(), cmd_show);

-  } else {

-    hr = E_FAIL;

-  }

-

-  ::FreeLibrary(module);

-

-  return hr;

-}

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// This is a small shell that loads a DLL calls its well known entry point.
+// The intention is to only depend on OS mechanisms and avoid the LIBC
+// dependency completely.
+// This indirection is done primarily to:
+// Play nicely with software firewalls. Most firewalls watch the executable
+// module making network requests and we do not want them to notify the user
+// after we've updated the program. The DLL can change independently of the
+// shell and we expect the shell to remain unchanged most of the time.
+//
+// Changes to this executable will not appear in offical builds until they are
+// included in an offical build and the resulting file is checked in to the
+// saved shell location.
+
+// Disable the RTC checks because this shell doesn't build with a CRT.
+#pragma runtime_checks("", off)
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <tchar.h>
+
+#include <atlbase.h>
+#include <atlpath.h>
+#include <atlstr.h>
+
+#include "omaha/common/constants.h"
+#include "omaha/common/error.h"
+#include "omaha/common/signaturevalidator.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/main.h"
+
+namespace omaha {
+
+// Disable the stack checks to keep the code size down.
+// The check_stack pragma did not really work. The stack checks had to be
+// disabled in the mk_file.
+#pragma check_stack()
+
+// Have to define this here since this is used in signaturevalidator.cpp.
+// This is defined in error.cc, but that pulls in debug.cpp which has a lot
+// of additional dependencies we don't want.  Not worth it for just this
+// function.
+HRESULT HRESULTFromLastError() {
+  DWORD error_code = ::GetLastError();
+  return (error_code != NO_ERROR) ? HRESULT_FROM_WIN32(error_code) : E_FAIL;
+}
+
+// Adapted from File::Exists in file.cpp.
+bool FileExists(const TCHAR* file_name) {
+  if (!file_name || !*file_name) {
+    return false;
+  }
+
+  WIN32_FILE_ATTRIBUTE_DATA attrs = {0};
+  return 0 != ::GetFileAttributesEx(file_name, ::GetFileExInfoStandard, &attrs);
+}
+
+bool IsVistaOrLater() {
+  static bool known = false;
+  static bool is_vista = false;
+  if (!known) {
+    OSVERSIONINFOEX osvi = {0};
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+    osvi.dwMajorVersion = 6;
+    DWORDLONG conditional = 0;
+    VER_SET_CONDITION(conditional, VER_MAJORVERSION, VER_GREATER_EQUAL);
+    is_vista = !!::VerifyVersionInfo(&osvi, VER_MAJORVERSION, conditional);
+    known = true;
+  }
+  return is_vista;
+}
+
+bool IsRunningFromProgramFilesDirectory() {
+  // Get the HMODULE for the current process.
+  HMODULE module_handle = ::GetModuleHandle(NULL);
+  if (!module_handle) {
+    return false;
+  }
+
+  // Get the full path to the module based on the HMODULE.
+  CString module_path;
+  DWORD result = ::GetModuleFileName(module_handle,
+                                     module_path.GetBufferSetLength(MAX_PATH),
+                                     MAX_PATH);
+  module_handle = NULL;
+
+  if (result == 0) {
+    return false;
+  }
+
+  // Get the directory of the current process without the filename.
+  CPath path_temp(module_path);
+  path_temp.RemoveFileSpec();
+  module_path = static_cast<CString>(path_temp);
+
+  // Get the directory to %ProgramFiles%.
+  TCHAR folder_path_buffer[MAX_PATH] = {0};
+  HRESULT hr = ::SHGetFolderPath(NULL,
+                                 CSIDL_PROGRAM_FILES,
+                                 NULL,
+                                 SHGFP_TYPE_CURRENT,
+                                 folder_path_buffer);
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  // Append the google/update install path onto %ProgramFiles%.
+  CString folder_path = folder_path_buffer;
+  if (!::PathAppend(CStrBuf(folder_path, MAX_PATH),
+                    OMAHA_REL_GOOPDATE_INSTALL_DIR)) {
+    return false;
+  }
+
+  folder_path.MakeLower();
+  module_path.MakeLower();
+
+  // Check if module_path starts with folder_path.
+  return (module_path.Find(folder_path) == 0);
+}
+
+// If we're not running from program files and we're running as an elevated
+// user on Vista, we need to validate the signature of goopdate.dll before
+// loading it.
+HRESULT VerifySignatureIfNecessary(const TCHAR* file_path,
+                                   bool is_running_from_program_files) {
+  if (is_running_from_program_files ||
+      !IsVistaOrLater() ||
+      !::IsUserAnAdmin()) {
+    return S_OK;
+  }
+
+  // Verify the Authenticode signature but use only the local cache for
+  // revocation checks.
+  HRESULT hr = VerifySignature(file_path, false);
+#if TEST_CERTIFICATE
+  // The chain of trust will not validate on builds signed with the test
+  // certificate.
+  if (CERT_E_UNTRUSTEDROOT == hr) {
+    hr = S_OK;
+  }
+#endif
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Verify that there is a Google certificate and that it has not expired.
+  if (!VerifySigneeIsGoogle(file_path)) {
+    return GOOGLEUPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED;
+  }
+
+  return S_OK;
+}
+
+HRESULT GetRegisteredVersion(bool is_machine, CString* version) {
+  HKEY key = NULL;
+  LONG res = ::RegOpenKeyEx(is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
+                            GOOPDATE_REG_RELATIVE_CLIENTS GOOPDATE_APP_ID,
+                            0,
+                            KEY_READ,
+                            &key);
+  if (ERROR_SUCCESS != res) {
+    return HRESULT_FROM_WIN32(res);
+  }
+
+  DWORD type = 0;
+  DWORD version_length = 50;
+  res = ::SHQueryValueEx(key,
+                         omaha::kRegValueProductVersion,
+                         NULL,
+                         &type,
+                         CStrBuf(*version, version_length),
+                         &version_length);
+  if (ERROR_SUCCESS != res) {
+    return HRESULT_FROM_WIN32(res);
+  }
+
+  if (REG_SZ != type) {
+    return E_UNEXPECTED;
+  }
+
+  return S_OK;
+}
+
+HRESULT GetDllPath(HINSTANCE instance, bool is_machine, CString* dll_path) {
+  TCHAR base_path[MAX_PATH] = {0};
+  TCHAR path[MAX_PATH] = {0};
+
+  if (!::GetModuleFileName(instance, base_path, arraysize(base_path))) {
+    return HRESULTFromLastError();
+  }
+  ::PathRemoveFileSpec(base_path);
+
+  // Try the side-by-side DLL first.
+  _tcscpy_s(path, arraysize(path), base_path);
+  if (!::PathAppend(path, omaha::kGoopdateDllName)) {
+    return HRESULTFromLastError();
+  }
+  if (FileExists(path)) {
+    *dll_path = path;
+    return S_OK;
+  }
+
+  // Try the version subdirectory.
+  _tcscpy_s(path, arraysize(path), base_path);
+  CString version;
+  HRESULT hr = GetRegisteredVersion(is_machine, &version);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (!::PathAppend(path, version)) {
+    return HRESULTFromLastError();
+  }
+  if (!::PathAppend(path, omaha::kGoopdateDllName)) {
+    return HRESULTFromLastError();
+  }
+  if (!FileExists(path)) {
+    return GOOGLEUPDATE_E_DLL_NOT_FOUND;
+  }
+
+  *dll_path = path;
+  return S_OK;
+}
+
+}  // namespace omaha
+
+// Algorithm:
+//  * Looks for goopdate.dll in the current directory.
+//  * If it is not found, looks for goopdate.dll in a version subdirectory based
+//    on the version found in the registry.
+//  * Verifies the signature of the goopdate.dll file.
+//  * Loads the DLL and calls the entry point.
+int WINAPI _tWinMain(HINSTANCE instance,
+                     HINSTANCE,
+                     LPTSTR,
+                     int cmd_show) {
+  bool is_running_from_program_files =
+      omaha::IsRunningFromProgramFilesDirectory();
+
+  // We assume here that running from program files means we should check
+  // the machine install version and otherwise we should check the user
+  // version. This should be true in all end user cases except for initial
+  // installs from the temp directory and OneClick cross-installs. In both
+  // cases, the DLL should be in the same directory so we should not get here.
+  // For developer use cases, the DLL should also be in the same directory.
+  bool is_machine = is_running_from_program_files;
+
+  CString dll_path;
+  HRESULT hr = omaha::GetDllPath(instance, is_machine, &dll_path);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = omaha::VerifySignatureIfNecessary(dll_path,
+                                         is_running_from_program_files);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  HMODULE module(::LoadLibraryEx(dll_path, NULL, 0));
+  if (!module) {
+    return omaha::HRESULTFromLastError();
+  }
+
+  DllEntry dll_entry = reinterpret_cast<DllEntry>(
+      ::GetProcAddress(module, omaha::kGoopdateDllEntryAnsi));
+  if (dll_entry) {
+    // We must send in GetCommandLine() and not cmd_line because the command
+    // line parsing code expects to have the program name as the first argument
+    // and cmd_line does not provide this.
+    hr = dll_entry(::GetCommandLine(), cmd_show);
+  } else {
+    hr = E_FAIL;
+  }
+
+  ::FreeLibrary(module);
+
+  return hr;
+}
+
diff --git a/goopdate/browser_launcher.cc b/goopdate/browser_launcher.cc
index 6986c00..480b5ba 100644
--- a/goopdate/browser_launcher.cc
+++ b/goopdate/browser_launcher.cc
@@ -1,118 +1,118 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/goopdate/browser_launcher.h"

-

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/exception_barrier.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/system.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/core/google_update_core.h"

-#include "omaha/goopdate/google_update_proxy.h"

-

-namespace omaha {

-

-ProcessLauncher::ProcessLauncher() {}

-

-ProcessLauncher::~ProcessLauncher() {}

-

-STDMETHODIMP ProcessLauncher::LaunchCmdLine(const TCHAR* cmd_line) {

-  CORE_LOG(L1, (_T("[ProcessLauncher::LaunchCmdLine][%s]"), cmd_line));

-  // The exception barrier is needed, because any exceptions that are thrown

-  // in this method will get caught by the COM run time. We compile with

-  // exceptions off, and do not expect to throw any exceptions. This barrier

-  // will treat an exception in this method as a unhandled exception.

-  ExceptionBarrier barrier;

-  if (cmd_line == NULL) {

-    return E_INVALIDARG;

-  }

-  return System::ShellExecuteCommandLine(cmd_line, NULL, NULL);

-}

-

-STDMETHODIMP ProcessLauncher::LaunchBrowser(DWORD type, const TCHAR* url) {

-  CORE_LOG(L1, (_T("[ProcessLauncher::LaunchBrowser][%d][%s]"), type, url));

-  // The exception barrier is needed, because any exceptions that are thrown

-  // in this method will get caught by the COM run time. We compile with

-  // exceptions off, and do not expect to throw any exceptions. This barrier

-  // will treat an exception in this method as a unhandled exception.

-  ExceptionBarrier barrier;

-  if (type >= BROWSER_MAX || url == NULL) {

-    return E_INVALIDARG;

-  }

-  return ShellExecuteBrowser(static_cast<BrowserType>(type), url);

-}

-

-// This method delegates to the internal interface exposed by the system

-// service, and if the service cannot be installed, exposed by the core.

-// When starting, if the service is not installed, the core registers a proxy

-// for its interface in shared memory.

-//

-// Non elevated callers can request a command to be run elevated.

-// The command must be registered before by elevated code to prevent

-// launching untrusted commands. The security of the command is based on

-// having the correct registry ACLs for the machine Omaha registry.

-STDMETHODIMP ProcessLauncher::LaunchCmdElevated(const WCHAR* app_guid,

-                                                const WCHAR* cmd_id,

-                                                DWORD caller_proc_id,

-                                                ULONG_PTR* proc_handle) {

-  CORE_LOG(L3, (_T("[ProcessLauncher::LaunchCmdElevated]")

-                _T("[app %s][cmd %s][pid %d]"),

-                app_guid, cmd_id, caller_proc_id));

-

-  ExceptionBarrier barrier;

-

-  ASSERT1(app_guid);

-  ASSERT1(cmd_id);

-  ASSERT1(proc_handle);

-

-  CComPtr<IGoogleUpdateCore> google_update_core;

-  HRESULT hr =

-      google_update_core.CoCreateInstance(__uuidof(GoogleUpdateCoreClass));

-

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[CoCreate GoogleUpdateCoreClass failed][0x%x]"), hr));

-

-    SharedMemoryAttributes attr(kGoogleUpdateCoreSharedMemoryName,

-                                CSecurityDesc());

-    GoogleUpdateCoreProxy google_update_core_proxy(true, &attr);

-    hr = google_update_core_proxy.GetObject(&google_update_core);

-    if (FAILED(hr)) {

-      CORE_LOG(LE, (_T("[GetObject for IGoogleUpdateCore failed][0x%x]"), hr));

-      return hr;

-    }

-  }

-  if (!google_update_core) {

-    CORE_LOG(LE, (_T("[IGoogleUpdateCore is null]")));

-    return E_UNEXPECTED;

-  }

-  hr = ::CoSetProxyBlanket(google_update_core, RPC_C_AUTHN_DEFAULT,

-      RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL, RPC_C_AUTHN_LEVEL_DEFAULT,

-      RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_DEFAULT);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return google_update_core->LaunchCmdElevated(app_guid,

-                                               cmd_id,

-                                               caller_proc_id,

-                                               proc_handle);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/goopdate/browser_launcher.h"
+
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/exception_barrier.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/system.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/core/google_update_core.h"
+#include "omaha/goopdate/google_update_proxy.h"
+
+namespace omaha {
+
+ProcessLauncher::ProcessLauncher() {}
+
+ProcessLauncher::~ProcessLauncher() {}
+
+STDMETHODIMP ProcessLauncher::LaunchCmdLine(const TCHAR* cmd_line) {
+  CORE_LOG(L1, (_T("[ProcessLauncher::LaunchCmdLine][%s]"), cmd_line));
+  // The exception barrier is needed, because any exceptions that are thrown
+  // in this method will get caught by the COM run time. We compile with
+  // exceptions off, and do not expect to throw any exceptions. This barrier
+  // will treat an exception in this method as a unhandled exception.
+  ExceptionBarrier barrier;
+  if (cmd_line == NULL) {
+    return E_INVALIDARG;
+  }
+  return System::ShellExecuteCommandLine(cmd_line, NULL, NULL);
+}
+
+STDMETHODIMP ProcessLauncher::LaunchBrowser(DWORD type, const TCHAR* url) {
+  CORE_LOG(L1, (_T("[ProcessLauncher::LaunchBrowser][%d][%s]"), type, url));
+  // The exception barrier is needed, because any exceptions that are thrown
+  // in this method will get caught by the COM run time. We compile with
+  // exceptions off, and do not expect to throw any exceptions. This barrier
+  // will treat an exception in this method as a unhandled exception.
+  ExceptionBarrier barrier;
+  if (type >= BROWSER_MAX || url == NULL) {
+    return E_INVALIDARG;
+  }
+  return ShellExecuteBrowser(static_cast<BrowserType>(type), url);
+}
+
+// This method delegates to the internal interface exposed by the system
+// service, and if the service cannot be installed, exposed by the core.
+// When starting, if the service is not installed, the core registers a proxy
+// for its interface in shared memory.
+//
+// Non elevated callers can request a command to be run elevated.
+// The command must be registered before by elevated code to prevent
+// launching untrusted commands. The security of the command is based on
+// having the correct registry ACLs for the machine Omaha registry.
+STDMETHODIMP ProcessLauncher::LaunchCmdElevated(const WCHAR* app_guid,
+                                                const WCHAR* cmd_id,
+                                                DWORD caller_proc_id,
+                                                ULONG_PTR* proc_handle) {
+  CORE_LOG(L3, (_T("[ProcessLauncher::LaunchCmdElevated]")
+                _T("[app %s][cmd %s][pid %d]"),
+                app_guid, cmd_id, caller_proc_id));
+
+  ExceptionBarrier barrier;
+
+  ASSERT1(app_guid);
+  ASSERT1(cmd_id);
+  ASSERT1(proc_handle);
+
+  CComPtr<IGoogleUpdateCore> google_update_core;
+  HRESULT hr =
+      google_update_core.CoCreateInstance(__uuidof(GoogleUpdateCoreClass));
+
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[CoCreate GoogleUpdateCoreClass failed][0x%x]"), hr));
+
+    SharedMemoryAttributes attr(kGoogleUpdateCoreSharedMemoryName,
+                                CSecurityDesc());
+    GoogleUpdateCoreProxy google_update_core_proxy(true, &attr);
+    hr = google_update_core_proxy.GetObject(&google_update_core);
+    if (FAILED(hr)) {
+      CORE_LOG(LE, (_T("[GetObject for IGoogleUpdateCore failed][0x%x]"), hr));
+      return hr;
+    }
+  }
+  if (!google_update_core) {
+    CORE_LOG(LE, (_T("[IGoogleUpdateCore is null]")));
+    return E_UNEXPECTED;
+  }
+  hr = ::CoSetProxyBlanket(google_update_core, RPC_C_AUTHN_DEFAULT,
+      RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL, RPC_C_AUTHN_LEVEL_DEFAULT,
+      RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_DEFAULT);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return google_update_core->LaunchCmdElevated(app_guid,
+                                               cmd_id,
+                                               caller_proc_id,
+                                               proc_handle);
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/browser_launcher.h b/goopdate/browser_launcher.h
index fa6a505..ae1bce6 100644
--- a/goopdate/browser_launcher.h
+++ b/goopdate/browser_launcher.h
@@ -1,101 +1,101 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Contains ProcessLauncher class to launch a process using a COM interface. The

-// COM object is typically created by the caller as a medium integrity object

-// impersonating the identity of the active user. This is to allow for launching

-// a medium-integrity process from a high-integrity process.

-

-// TODO(omaha): consider renaming of the source files to match their purpose.

-

-#ifndef OMAHA_GOOPDATE_BROWSER_LAUNCHER_H__

-#define OMAHA_GOOPDATE_BROWSER_LAUNCHER_H__

-

-#include <windows.h>

-#include <atlbase.h>

-#include <atlcom.h>

-#include <atlstr.h>

-#include "omaha/common/atlregmapex.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource.h"

-

-// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".

-#include "goopdate/google_update_idl.h"

-

-namespace omaha {

-

-const TCHAR* const kThreadingBoth = _T("Both");

-const TCHAR* const kTlbVersion    = _T("1.0");

-const TCHAR* const kProcessWorkerProgId =

-    _T("GoogleUpdateProcessLauncher");

-const TCHAR* const kProcessWorkerDescription =

-    _T("Google Update Process Launcher Class");

-

-class ATL_NO_VTABLE ProcessLauncher

-    : public CComObjectRootEx<CComMultiThreadModel>,

-      public CComCoClass<ProcessLauncher, &__uuidof(ProcessLauncherClass)>,

-      public IProcessLauncher {

- public:

-  ProcessLauncher();

-  virtual ~ProcessLauncher();

-

-  DECLARE_NOT_AGGREGATABLE(ProcessLauncher)

-  DECLARE_PROTECT_FINAL_CONSTRUCT()

-

-  DECLARE_REGISTRY_RESOURCEID_EX(IDR_GOOGLE_UPDATE_WORKER_CLASS)

-

-  #pragma warning(push)

-  // C4640: construction of local static object is not thread-safe

-  #pragma warning(disable : 4640)

-  BEGIN_REGISTRY_MAP()

-    REGMAP_ENTRY(_T("HKROOT"),       goopdate_utils::GetHKRoot())

-    REGMAP_ENTRY(_T("THREADING"),    kThreadingBoth)

-    REGMAP_EXE_MODULE(_T("MODULE"))

-    REGMAP_ENTRY(_T("VERSION"),      kTlbVersion)

-    REGMAP_ENTRY(_T("PROGID"),       kProcessWorkerProgId)

-    REGMAP_ENTRY(_T("DESCRIPTION"),  kProcessWorkerDescription)

-    REGMAP_UUID(_T("CLSID"),         __uuidof(ProcessLauncherClass))

-    REGMAP_UUID(_T("LIBID"),         LIBID_GoogleUpdateLib)

-  END_REGISTRY_MAP()

-  #pragma warning(pop)

-

-  // C4505: unreferenced IUnknown local functions have been removed

-  #pragma warning(disable : 4505)

-  BEGIN_COM_MAP(ProcessLauncher)

-    COM_INTERFACE_ENTRY(IProcessLauncher)

-  END_COM_MAP()

-

-  // Launches a command line at medium integrity.

-  STDMETHOD(LaunchCmdLine)(const TCHAR* cmd_line);

-

-  // Launches the appropriate browser.

-  STDMETHOD(LaunchBrowser)(DWORD type, const TCHAR* url);

-

-  // Launches a command line elevated.

-  STDMETHOD(LaunchCmdElevated)(const WCHAR* app_guid,

-                               const WCHAR* cmd_id,

-                               DWORD caller_proc_id,

-                               ULONG_PTR* proc_handle);

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(ProcessLauncher);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_BROWSER_LAUNCHER_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Contains ProcessLauncher class to launch a process using a COM interface. The
+// COM object is typically created by the caller as a medium integrity object
+// impersonating the identity of the active user. This is to allow for launching
+// a medium-integrity process from a high-integrity process.
+
+// TODO(omaha): consider renaming of the source files to match their purpose.
+
+#ifndef OMAHA_GOOPDATE_BROWSER_LAUNCHER_H__
+#define OMAHA_GOOPDATE_BROWSER_LAUNCHER_H__
+
+#include <windows.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlstr.h>
+#include "omaha/common/atlregmapex.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource.h"
+
+// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".
+#include "goopdate/google_update_idl.h"
+
+namespace omaha {
+
+const TCHAR* const kThreadingBoth = _T("Both");
+const TCHAR* const kTlbVersion    = _T("1.0");
+const TCHAR* const kProcessWorkerProgId =
+    _T("GoogleUpdateProcessLauncher");
+const TCHAR* const kProcessWorkerDescription =
+    _T("Google Update Process Launcher Class");
+
+class ATL_NO_VTABLE ProcessLauncher
+    : public CComObjectRootEx<CComMultiThreadModel>,
+      public CComCoClass<ProcessLauncher, &__uuidof(ProcessLauncherClass)>,
+      public IProcessLauncher {
+ public:
+  ProcessLauncher();
+  virtual ~ProcessLauncher();
+
+  DECLARE_NOT_AGGREGATABLE(ProcessLauncher)
+  DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+  DECLARE_REGISTRY_RESOURCEID_EX(IDR_GOOGLE_UPDATE_WORKER_CLASS)
+
+  #pragma warning(push)
+  // C4640: construction of local static object is not thread-safe
+  #pragma warning(disable : 4640)
+  BEGIN_REGISTRY_MAP()
+    REGMAP_ENTRY(_T("HKROOT"),       goopdate_utils::GetHKRoot())
+    REGMAP_ENTRY(_T("THREADING"),    kThreadingBoth)
+    REGMAP_EXE_MODULE(_T("MODULE"))
+    REGMAP_ENTRY(_T("VERSION"),      kTlbVersion)
+    REGMAP_ENTRY(_T("PROGID"),       kProcessWorkerProgId)
+    REGMAP_ENTRY(_T("DESCRIPTION"),  kProcessWorkerDescription)
+    REGMAP_UUID(_T("CLSID"),         __uuidof(ProcessLauncherClass))
+    REGMAP_UUID(_T("LIBID"),         LIBID_GoogleUpdateLib)
+  END_REGISTRY_MAP()
+  #pragma warning(pop)
+
+  // C4505: unreferenced IUnknown local functions have been removed
+  #pragma warning(disable : 4505)
+  BEGIN_COM_MAP(ProcessLauncher)
+    COM_INTERFACE_ENTRY(IProcessLauncher)
+  END_COM_MAP()
+
+  // Launches a command line at medium integrity.
+  STDMETHOD(LaunchCmdLine)(const TCHAR* cmd_line);
+
+  // Launches the appropriate browser.
+  STDMETHOD(LaunchBrowser)(DWORD type, const TCHAR* url);
+
+  // Launches a command line elevated.
+  STDMETHOD(LaunchCmdElevated)(const WCHAR* app_guid,
+                               const WCHAR* cmd_id,
+                               DWORD caller_proc_id,
+                               ULONG_PTR* proc_handle);
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(ProcessLauncher);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_BROWSER_LAUNCHER_H__
+
diff --git a/goopdate/build.scons b/goopdate/build.scons
index 7653fdf..096df7d 100644
--- a/goopdate/build.scons
+++ b/goopdate/build.scons
@@ -1,237 +1,237 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-#

-# Build Goopdate library

-#

-midl_env = env.Clone()

-midl_env.Tool('midl')

-midl_env['MIDLFLAGS'] += [

-    '/Oicf',  # generate optimized stubless proxy/stub code

-    ]

-

-# Compile the .idl file into .c & .h files

-midl_env.TypeLibrary('google_update_idl.idl')

-

-

-gd_env = env.Clone()

-

-# Need to look in output dir to find .h files generated by midl compiler.

-gd_env['CPPPATH'] += [

-    '$OBJ_ROOT',

-    '$MAIN_DIR/third_party/breakpad/src/',

-    ]

-

-target_name = 'goopdate_dll.lib'

-

-gd_inputs = [

-    #'browser_ping.cc',

-    'browser_launcher.cc',

-    'command_line.cc',

-    'command_line_builder.cc',

-    'command_line_parser.cc',

-    'command_line_validator.cc',

-    'config_manager.cc',

-    'crash.cc',

-    'extra_args_parser.cc',

-    'event_logger.cc',

-    'google_update.cc',

-    'goopdate.cc',

-    'goopdate_command_line_validator.cc',

-    'goopdate_helper.cc',

-    'goopdate_metrics.cc',

-    'goopdate_utils.cc',

-    'goopdate_xml_parser.cc',

-    'program_instance.cc',

-    'request.cc',

-    'stats_uploader.cc',

-    'resource_manager.cc',

-    'ui_displayed_event.cc',

-    'webplugin_utils.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  gd_inputs += gd_env.EnablePrecompile(target_name)

-

-# Compile the library.

-gd_env.ComponentLibrary(target_name, gd_inputs)

-

-

-#

-# Build Goopdate proxy/stub library separately, because it is not compatible

-# with precompiled headers.

-#

-no_precomp_env = env.Clone()

-no_precomp_env['CPPPATH'] += ['$OBJ_ROOT']

-no_precomp_env.ComponentLibrary('google_update_ps', 'google_update_idl_datax.c')

-

-

-# Add languages that have version resources but are not fully supported.

-translated_languages = list(env['languages'])

-if 1 < len(translated_languages):

-  translated_languages += [

-      'userdefault',

-      'zh-HK',

-      ]

-

-#

-# Build Goopdate DLL

-#

-_first = True

-for v in env['product_version']:

-  temp_env = env.Clone(COMPONENT_STATIC=False)

-

-  if _first:

-    _first = False

-    prefix = ''

-  else:

-    prefix = 'TEST_'

-    temp_env['OBJPREFIX'] = temp_env.subst('test/$OBJPREFIX')

-

-  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-  temp_env.Append(

-      CPPPATH = [

-          '$MAIN_DIR/third_party/breakpad/src/',

-          ],

-

-      # Do not add static dependencies on system import libraries. Prefer delay

-      # loading when possible. When running as 'core', only what is necessary

-      # must be loaded in the memory space.

-      LIBS = [

-          '$LIB_DIR/breakpad.lib',

-          '$LIB_DIR/common.lib',

-          '$LIB_DIR/core.lib',

-          '$LIB_DIR/goopdate_dll.lib',

-          '$LIB_DIR/google_update_ps.lib',

-          '$LIB_DIR/google_update_recovery.lib',

-          '$LIB_DIR/logging.lib',

-          '$LIB_DIR/net.lib',

-          '$LIB_DIR/repair_goopdate.lib',

-          '$LIB_DIR/security.lib',

-          '$LIB_DIR/service.lib',

-          '$LIB_DIR/setup.lib',

-          '$LIB_DIR/statsreport.lib',

-          '$LIB_DIR/worker.lib',

-          ('atls.lib', 'atlsd.lib')[temp_env.Bit('debug')],

-          ('libcmt.lib', 'libcmtd.lib')[temp_env.Bit('debug')],

-          ('libcpmt.lib', 'libcpmtd.lib')[temp_env.Bit('debug')],

-          'comctl32.lib',

-          'crypt32.lib',

-          'delayimp.lib',

-          'iphlpapi.lib',

-          'netapi32.lib',

-          'msi.lib',

-          'mstask.lib',

-          'psapi.lib',

-          'rasapi32.lib',

-          'rpcns4.lib',

-          'rpcrt4.lib',

-          'shlwapi.lib',

-          'version.lib',

-          'urlmon.lib',

-          'userenv.lib',

-          'wininet.lib',

-          'wintrust.lib',

-          'ws2_32.lib',

-          'wtsapi32.lib',

-          ],

-      LINKFLAGS = [

-          '/DELAYLOAD:comctl32.dll',

-          '/DELAYLOAD:crypt32.dll',

-          '/DELAYLOAD:iphlpapi.dll',

-          '/DELAYLOAD:msi.dll',

-          '/DELAYLOAD:oleaut32.dll',

-          '/DELAYLOAD:psapi.dll',

-          '/DELAYLOAD:rasapi32.dll',

-          '/DELAYLOAD:shell32.dll',

-          '/DELAYLOAD:shlwapi.dll',

-          '/DELAYLOAD:urlmon.dll',

-          '/DELAYLOAD:userenv.dll',

-          '/DELAYLOAD:version.dll',

-          '/DELAYLOAD:wininet.dll',

-          '/DELAYLOAD:wintrust.dll',

-          '/DELAYLOAD:wtsapi32.dll',

-

-          # Forces the dependency on ws2_32.lib.

-          '/INCLUDE:_WSAStartup@8',

-

-          # TODO(Omaha) - Choose a rebase address which does not conflict

-          # with other DLLs loaded in our process. For now, we just picked

-          # an arbitrary address.

-          '/BASE:0x18000000',

-          ],

-      RCFLAGS = [

-          '/DVERSION_MAJOR=%d' % v[0],

-          '/DVERSION_MINOR=%d' % v[1],

-          '/DVERSION_BUILD=%d' % v[2],

-          '/DVERSION_PATCH=%d' % v[3],

-          '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,

-

-          # goopdate.dll is resource neutral.

-          '/DLANGAUGE_STRING=\\"en\\"',

-          ],

-  )

-

-  version_res = temp_env.RES(

-      target=prefix + 'goopdate_version.res',

-      source='goopdate_version.rc'

-  )

-

-  # Force a rebuild when the version changes.

-  env.Depends(version_res, '$MAIN_DIR/VERSION')

-

-  target_name = prefix + 'goopdate_unsigned.dll'

-

-  # main.cc is included here because the linker gets confused if we try to

-  # create a DLL without an entry point. There's probably a more accurate

-  # description of the problem and thus a different solution, but this worked.

-  inputs = [

-      'goopdate.def',

-      'main.cc',

-      temp_env.RES(prefix + 'goopdate.res', 'goopdate.rc'),

-      version_res,

-      ]

-  if env.Bit('use_precompiled_headers'):

-    inputs += temp_env.EnablePrecompile(target_name)

-

-  for language in translated_languages:

-    lang_base_name = 'goopdate_dll/generated_resources_' + language

-    inputs += temp_env.RES(

-        target='resources/%s.res' % (prefix + lang_base_name),

-        source='resources/%s.rc' % lang_base_name,

-    )

-

-  unsigned_dll = temp_env.ComponentLibrary(

-      lib_name=target_name,

-      source=inputs,

-  )

-

-  signed_dll = temp_env.SignedBinary(

-      target=prefix + 'goopdate.dll',

-      source=unsigned_dll,

-  )

-

-  env.Replicate('$STAGING_DIR', signed_dll)

-  env.Replicate('$STAGING_DIR', [f for f in unsigned_dll if f.suffix == '.pdb'])

-

-

-# Build all the resource dlls.

-env.BuildSConscript('resources')

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+#
+# Build Goopdate library
+#
+midl_env = env.Clone()
+midl_env.Tool('midl')
+midl_env['MIDLFLAGS'] += [
+    '/Oicf',  # generate optimized stubless proxy/stub code
+    ]
+
+# Compile the .idl file into .c & .h files
+midl_env.TypeLibrary('google_update_idl.idl')
+
+
+gd_env = env.Clone()
+
+# Need to look in output dir to find .h files generated by midl compiler.
+gd_env['CPPPATH'] += [
+    '$OBJ_ROOT',
+    '$MAIN_DIR/third_party/breakpad/src/',
+    ]
+
+target_name = 'goopdate_dll.lib'
+
+gd_inputs = [
+    #'browser_ping.cc',
+    'browser_launcher.cc',
+    'command_line.cc',
+    'command_line_builder.cc',
+    'command_line_parser.cc',
+    'command_line_validator.cc',
+    'config_manager.cc',
+    'crash.cc',
+    'extra_args_parser.cc',
+    'event_logger.cc',
+    'google_update.cc',
+    'goopdate.cc',
+    'goopdate_command_line_validator.cc',
+    'goopdate_helper.cc',
+    'goopdate_metrics.cc',
+    'goopdate_utils.cc',
+    'goopdate_xml_parser.cc',
+    'program_instance.cc',
+    'request.cc',
+    'stats_uploader.cc',
+    'resource_manager.cc',
+    'ui_displayed_event.cc',
+    'webplugin_utils.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  gd_inputs += gd_env.EnablePrecompile(target_name)
+
+# Compile the library.
+gd_env.ComponentLibrary(target_name, gd_inputs)
+
+
+#
+# Build Goopdate proxy/stub library separately, because it is not compatible
+# with precompiled headers.
+#
+no_precomp_env = env.Clone()
+no_precomp_env['CPPPATH'] += ['$OBJ_ROOT']
+no_precomp_env.ComponentLibrary('google_update_ps', 'google_update_idl_datax.c')
+
+
+# Add languages that have version resources but are not fully supported.
+translated_languages = list(env['languages'])
+if 1 < len(translated_languages):
+  translated_languages += [
+      'userdefault',
+      'zh-HK',
+      ]
+
+#
+# Build Goopdate DLL
+#
+_first = True
+for v in env['product_version']:
+  temp_env = env.Clone(COMPONENT_STATIC=False)
+
+  if _first:
+    _first = False
+    prefix = ''
+  else:
+    prefix = 'TEST_'
+    temp_env['OBJPREFIX'] = temp_env.subst('test/$OBJPREFIX')
+
+  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+  temp_env.Append(
+      CPPPATH = [
+          '$MAIN_DIR/third_party/breakpad/src/',
+          ],
+
+      # Do not add static dependencies on system import libraries. Prefer delay
+      # loading when possible. When running as 'core', only what is necessary
+      # must be loaded in the memory space.
+      LIBS = [
+          '$LIB_DIR/breakpad.lib',
+          '$LIB_DIR/common.lib',
+          '$LIB_DIR/core.lib',
+          '$LIB_DIR/goopdate_dll.lib',
+          '$LIB_DIR/google_update_ps.lib',
+          '$LIB_DIR/google_update_recovery.lib',
+          '$LIB_DIR/logging.lib',
+          '$LIB_DIR/net.lib',
+          '$LIB_DIR/repair_goopdate.lib',
+          '$LIB_DIR/security.lib',
+          '$LIB_DIR/service.lib',
+          '$LIB_DIR/setup.lib',
+          '$LIB_DIR/statsreport.lib',
+          '$LIB_DIR/worker.lib',
+          ('atls.lib', 'atlsd.lib')[temp_env.Bit('debug')],
+          ('libcmt.lib', 'libcmtd.lib')[temp_env.Bit('debug')],
+          ('libcpmt.lib', 'libcpmtd.lib')[temp_env.Bit('debug')],
+          'comctl32.lib',
+          'crypt32.lib',
+          'delayimp.lib',
+          'iphlpapi.lib',
+          'netapi32.lib',
+          'msi.lib',
+          'mstask.lib',
+          'psapi.lib',
+          'rasapi32.lib',
+          'rpcns4.lib',
+          'rpcrt4.lib',
+          'shlwapi.lib',
+          'version.lib',
+          'urlmon.lib',
+          'userenv.lib',
+          'wininet.lib',
+          'wintrust.lib',
+          'ws2_32.lib',
+          'wtsapi32.lib',
+          ],
+      LINKFLAGS = [
+          '/DELAYLOAD:comctl32.dll',
+          '/DELAYLOAD:crypt32.dll',
+          '/DELAYLOAD:iphlpapi.dll',
+          '/DELAYLOAD:msi.dll',
+          '/DELAYLOAD:oleaut32.dll',
+          '/DELAYLOAD:psapi.dll',
+          '/DELAYLOAD:rasapi32.dll',
+          '/DELAYLOAD:shell32.dll',
+          '/DELAYLOAD:shlwapi.dll',
+          '/DELAYLOAD:urlmon.dll',
+          '/DELAYLOAD:userenv.dll',
+          '/DELAYLOAD:version.dll',
+          '/DELAYLOAD:wininet.dll',
+          '/DELAYLOAD:wintrust.dll',
+          '/DELAYLOAD:wtsapi32.dll',
+
+          # Forces the dependency on ws2_32.lib.
+          '/INCLUDE:_WSAStartup@8',
+
+          # TODO(Omaha) - Choose a rebase address which does not conflict
+          # with other DLLs loaded in our process. For now, we just picked
+          # an arbitrary address.
+          '/BASE:0x18000000',
+          ],
+      RCFLAGS = [
+          '/DVERSION_MAJOR=%d' % v[0],
+          '/DVERSION_MINOR=%d' % v[1],
+          '/DVERSION_BUILD=%d' % v[2],
+          '/DVERSION_PATCH=%d' % v[3],
+          '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,
+
+          # goopdate.dll is resource neutral.
+          '/DLANGAUGE_STRING=\\"en\\"',
+          ],
+  )
+
+  version_res = temp_env.RES(
+      target=prefix + 'goopdate_version.res',
+      source='goopdate_version.rc'
+  )
+
+  # Force a rebuild when the version changes.
+  env.Depends(version_res, '$MAIN_DIR/VERSION')
+
+  target_name = prefix + 'goopdate_unsigned.dll'
+
+  # main.cc is included here because the linker gets confused if we try to
+  # create a DLL without an entry point. There's probably a more accurate
+  # description of the problem and thus a different solution, but this worked.
+  inputs = [
+      'goopdate.def',
+      'main.cc',
+      temp_env.RES(prefix + 'goopdate.res', 'goopdate.rc'),
+      version_res,
+      ]
+  if env.Bit('use_precompiled_headers'):
+    inputs += temp_env.EnablePrecompile(target_name)
+
+  for language in translated_languages:
+    lang_base_name = 'goopdate_dll/generated_resources_' + language
+    inputs += temp_env.RES(
+        target='resources/%s.res' % (prefix + lang_base_name),
+        source='resources/%s.rc' % lang_base_name,
+    )
+
+  unsigned_dll = temp_env.ComponentLibrary(
+      lib_name=target_name,
+      source=inputs,
+  )
+
+  signed_dll = temp_env.SignedBinary(
+      target=prefix + 'goopdate.dll',
+      source=unsigned_dll,
+  )
+
+  env.Replicate('$STAGING_DIR', signed_dll)
+  env.Replicate('$STAGING_DIR', [f for f in unsigned_dll if f.suffix == '.pdb'])
+
+
+# Build all the resource dlls.
+env.BuildSConscript('resources')
diff --git a/goopdate/command_line.cc b/goopdate/command_line.cc
index 4f9eb3c..29650f5 100644
--- a/goopdate/command_line.cc
+++ b/goopdate/command_line.cc
@@ -1,86 +1,86 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/command_line.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/goopdate/command_line_parser.h"

-#include "omaha/goopdate/goopdate_command_line_validator.h"

-

-namespace omaha {

-

-// Returns a pointer to the second token in the cmd_line parameter or an

-// empty string. See the implementation in vc7\crt\src\wincmdln.c

-//

-// TODO(omaha): consider moving this function into the tiny shell, as it

-// is logically part of our modified runtime environment.

-TCHAR* GetCmdLineTail(const TCHAR* cmd_line) {

-  ASSERT1(cmd_line);

-  bool in_quote = false;

-

-  // Skip past program name (first token in command line).

-  // Check for and handle quoted program name.

-

-  while ((*cmd_line > _T(' ')) ||

-         (*cmd_line && in_quote)) {

-    // Flip the in_quote if current character is '"'.

-    if (*cmd_line == _T('"')) {

-      in_quote = !in_quote;

-    }

-    ++cmd_line;

-  }

-

-  // Skip past any white space preceeding the second token.

-  while (*cmd_line && (*cmd_line <= _T(' '))) {

-    cmd_line++;

-  }

-

-  return const_cast<TCHAR*>(cmd_line);

-}

-

-// Assumption: The metainstaller has verified that space ' ' and

-// double quote '"' characters do not appear in the "extra" arguments.

-// This is important so that attackers can't create tags that provide a valid

-// extra argument string followed by other commands.

-HRESULT ParseCommandLine(const TCHAR* cmd_line, CommandLineArgs* args) {

-  ASSERT1(cmd_line);

-  ASSERT1(args);

-  CORE_LOG(L3, (_T("[ParseCommandLine][%s]"), cmd_line));

-

-  CommandLineParser parser;

-  HRESULT hr = parser.ParseFromString(cmd_line);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ParseCommandLine][ParseFromString failed][0x%x]"), hr));

-    return hr;

-  }

-

-  GoopdateCommandLineValidator validator;

-  hr = validator.Setup();

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ParseCommandLine][Validator Setup failed][0x%x]"), hr));

-    return hr;

-  }

-

-  hr = validator.Validate(&parser, args);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ParseCommandLine][Validate failed][0x%x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/command_line.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/goopdate/command_line_parser.h"
+#include "omaha/goopdate/goopdate_command_line_validator.h"
+
+namespace omaha {
+
+// Returns a pointer to the second token in the cmd_line parameter or an
+// empty string. See the implementation in vc7\crt\src\wincmdln.c
+//
+// TODO(omaha): consider moving this function into the tiny shell, as it
+// is logically part of our modified runtime environment.
+TCHAR* GetCmdLineTail(const TCHAR* cmd_line) {
+  ASSERT1(cmd_line);
+  bool in_quote = false;
+
+  // Skip past program name (first token in command line).
+  // Check for and handle quoted program name.
+
+  while ((*cmd_line > _T(' ')) ||
+         (*cmd_line && in_quote)) {
+    // Flip the in_quote if current character is '"'.
+    if (*cmd_line == _T('"')) {
+      in_quote = !in_quote;
+    }
+    ++cmd_line;
+  }
+
+  // Skip past any white space preceeding the second token.
+  while (*cmd_line && (*cmd_line <= _T(' '))) {
+    cmd_line++;
+  }
+
+  return const_cast<TCHAR*>(cmd_line);
+}
+
+// Assumption: The metainstaller has verified that space ' ' and
+// double quote '"' characters do not appear in the "extra" arguments.
+// This is important so that attackers can't create tags that provide a valid
+// extra argument string followed by other commands.
+HRESULT ParseCommandLine(const TCHAR* cmd_line, CommandLineArgs* args) {
+  ASSERT1(cmd_line);
+  ASSERT1(args);
+  CORE_LOG(L3, (_T("[ParseCommandLine][%s]"), cmd_line));
+
+  CommandLineParser parser;
+  HRESULT hr = parser.ParseFromString(cmd_line);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ParseCommandLine][ParseFromString failed][0x%x]"), hr));
+    return hr;
+  }
+
+  GoopdateCommandLineValidator validator;
+  hr = validator.Setup();
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ParseCommandLine][Validator Setup failed][0x%x]"), hr));
+    return hr;
+  }
+
+  hr = validator.Validate(&parser, args);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ParseCommandLine][Validate failed][0x%x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/command_line.h b/goopdate/command_line.h
index f69cf00..d410553 100644
--- a/goopdate/command_line.h
+++ b/goopdate/command_line.h
@@ -1,139 +1,139 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// TODO(omaha): consider making all what can be passed on the command line

-// "arguments". Our terminology to separate them in commands and options is not

-// consistent.

-

-#ifndef OMAHA_GOOPDATE_COMMAND_LINE_H__

-#define OMAHA_GOOPDATE_COMMAND_LINE_H__

-

-#include <tchar.h>

-#include <atlstr.h>

-#include <vector>

-#include "omaha/common/constants.h"

-#include "omaha/common/browser_utils.h"

-

-namespace omaha {

-

-// Replacement for the C runtime function to process the command line.

-// The first token of the command line in Windows is the process name.

-// What gets passed to WinMain by the C runtime must not include the first

-// token. Since our tiny shell does not use the C runtime we must handle

-// the command line by ourselves.

-TCHAR* GetCmdLineTail(const TCHAR* cmd_line);

-

-struct CommandLineAppArgs {

-  CommandLineAppArgs()

-      : app_guid(GUID_NULL),

-        needs_admin(false) {}

-

-  GUID app_guid;

-  CString app_name;

-  bool needs_admin;

-  CString ap;

-  CString tt_token;

-  CString encoded_installer_data;

-  CString install_data_index;

-};

-

-// Values may be sent in pings or stats. Do not remove or reuse existing values.

-typedef enum CommandLineMode {

-  COMMANDLINE_MODE_UNKNOWN = 0,

-  COMMANDLINE_MODE_NOARGS = 1,  // See GoopdateCommandLineValidator.

-  COMMANDLINE_MODE_CORE = 2,

-  COMMANDLINE_MODE_SERVICE = 3,

-  COMMANDLINE_MODE_REGSERVER = 4,

-  COMMANDLINE_MODE_UNREGSERVER = 5,

-  COMMANDLINE_MODE_NETDIAGS = 6,

-  COMMANDLINE_MODE_CRASH = 7,

-  COMMANDLINE_MODE_REPORTCRASH = 8,

-  COMMANDLINE_MODE_INSTALL = 9,

-  COMMANDLINE_MODE_UPDATE = 10,

-  COMMANDLINE_MODE_IG = 11,

-  COMMANDLINE_MODE_HANDOFF_INSTALL = 12,

-  COMMANDLINE_MODE_UG = 13,

-  COMMANDLINE_MODE_UA = 14,

-  COMMANDLINE_MODE_RECOVER = 15,

-  COMMANDLINE_MODE_WEBPLUGIN = 16,

-  COMMANDLINE_MODE_CODE_RED_CHECK = 17,

-  COMMANDLINE_MODE_COMSERVER = 18,

-  COMMANDLINE_MODE_LEGACYUI = 19,

-  COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF = 20,

-  COMMANDLINE_MODE_REGISTER_PRODUCT = 21,

-  COMMANDLINE_MODE_UNREGISTER_PRODUCT = 22,

-  COMMANDLINE_MODE_SERVICE_REGISTER = 23,

-  COMMANDLINE_MODE_SERVICE_UNREGISTER = 24,

-  COMMANDLINE_MODE_CRASH_HANDLER = 25,

-};

-

-struct CommandLineExtraArgs {

-  CommandLineExtraArgs()

-      : installation_id(GUID_NULL),

-        browser_type(BROWSER_UNKNOWN),

-        usage_stats_enable(TRISTATE_NONE) {}

-

-  GUID installation_id;

-  CString brand_code;

-  CString client_id;

-  CString referral_id;

-  CString language;

-  BrowserType browser_type;

-  Tristate usage_stats_enable;

-

-  std::vector<CommandLineAppArgs> apps;

-};

-

-struct CommandLineArgs {

-  CommandLineArgs()

-      : mode(COMMANDLINE_MODE_UNKNOWN),

-        is_interactive_set(false),

-        is_machine_set(false),

-        is_crash_handler_disabled(false),

-        is_install_elevated(false),

-        is_silent_set(false),

-        is_eula_required_set(false),

-        is_offline_set(false),

-        is_oem_set(false),

-        is_uninstall_set(false) {}

-

-  CommandLineMode mode;

-  bool is_interactive_set;

-  bool is_machine_set;

-  bool is_crash_handler_disabled;

-  bool is_install_elevated;

-  bool is_silent_set;

-  bool is_eula_required_set;

-  bool is_offline_set;

-  bool is_oem_set;

-  bool is_uninstall_set;

-  CString extra_args_str;

-  CString app_args_str;

-  CString install_source;

-  CString crash_filename;

-  CString custom_info_filename;

-  CString legacy_manifest_path;

-  CString webplugin_urldomain;

-  CString webplugin_args;

-  CString code_red_metainstaller_path;

-  CommandLineExtraArgs extra;

-};

-

-// Parses the goopdate command line.

-HRESULT ParseCommandLine(const TCHAR* cmd_line, CommandLineArgs* args);

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_COMMAND_LINE_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// TODO(omaha): consider making all what can be passed on the command line
+// "arguments". Our terminology to separate them in commands and options is not
+// consistent.
+
+#ifndef OMAHA_GOOPDATE_COMMAND_LINE_H__
+#define OMAHA_GOOPDATE_COMMAND_LINE_H__
+
+#include <tchar.h>
+#include <atlstr.h>
+#include <vector>
+#include "omaha/common/constants.h"
+#include "omaha/common/browser_utils.h"
+
+namespace omaha {
+
+// Replacement for the C runtime function to process the command line.
+// The first token of the command line in Windows is the process name.
+// What gets passed to WinMain by the C runtime must not include the first
+// token. Since our tiny shell does not use the C runtime we must handle
+// the command line by ourselves.
+TCHAR* GetCmdLineTail(const TCHAR* cmd_line);
+
+struct CommandLineAppArgs {
+  CommandLineAppArgs()
+      : app_guid(GUID_NULL),
+        needs_admin(false) {}
+
+  GUID app_guid;
+  CString app_name;
+  bool needs_admin;
+  CString ap;
+  CString tt_token;
+  CString encoded_installer_data;
+  CString install_data_index;
+};
+
+// Values may be sent in pings or stats. Do not remove or reuse existing values.
+typedef enum CommandLineMode {
+  COMMANDLINE_MODE_UNKNOWN = 0,
+  COMMANDLINE_MODE_NOARGS = 1,  // See GoopdateCommandLineValidator.
+  COMMANDLINE_MODE_CORE = 2,
+  COMMANDLINE_MODE_SERVICE = 3,
+  COMMANDLINE_MODE_REGSERVER = 4,
+  COMMANDLINE_MODE_UNREGSERVER = 5,
+  COMMANDLINE_MODE_NETDIAGS = 6,
+  COMMANDLINE_MODE_CRASH = 7,
+  COMMANDLINE_MODE_REPORTCRASH = 8,
+  COMMANDLINE_MODE_INSTALL = 9,
+  COMMANDLINE_MODE_UPDATE = 10,
+  COMMANDLINE_MODE_IG = 11,
+  COMMANDLINE_MODE_HANDOFF_INSTALL = 12,
+  COMMANDLINE_MODE_UG = 13,
+  COMMANDLINE_MODE_UA = 14,
+  COMMANDLINE_MODE_RECOVER = 15,
+  COMMANDLINE_MODE_WEBPLUGIN = 16,
+  COMMANDLINE_MODE_CODE_RED_CHECK = 17,
+  COMMANDLINE_MODE_COMSERVER = 18,
+  COMMANDLINE_MODE_LEGACYUI = 19,
+  COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF = 20,
+  COMMANDLINE_MODE_REGISTER_PRODUCT = 21,
+  COMMANDLINE_MODE_UNREGISTER_PRODUCT = 22,
+  COMMANDLINE_MODE_SERVICE_REGISTER = 23,
+  COMMANDLINE_MODE_SERVICE_UNREGISTER = 24,
+  COMMANDLINE_MODE_CRASH_HANDLER = 25,
+};
+
+struct CommandLineExtraArgs {
+  CommandLineExtraArgs()
+      : installation_id(GUID_NULL),
+        browser_type(BROWSER_UNKNOWN),
+        usage_stats_enable(TRISTATE_NONE) {}
+
+  GUID installation_id;
+  CString brand_code;
+  CString client_id;
+  CString referral_id;
+  CString language;
+  BrowserType browser_type;
+  Tristate usage_stats_enable;
+
+  std::vector<CommandLineAppArgs> apps;
+};
+
+struct CommandLineArgs {
+  CommandLineArgs()
+      : mode(COMMANDLINE_MODE_UNKNOWN),
+        is_interactive_set(false),
+        is_machine_set(false),
+        is_crash_handler_disabled(false),
+        is_install_elevated(false),
+        is_silent_set(false),
+        is_eula_required_set(false),
+        is_offline_set(false),
+        is_oem_set(false),
+        is_uninstall_set(false) {}
+
+  CommandLineMode mode;
+  bool is_interactive_set;
+  bool is_machine_set;
+  bool is_crash_handler_disabled;
+  bool is_install_elevated;
+  bool is_silent_set;
+  bool is_eula_required_set;
+  bool is_offline_set;
+  bool is_oem_set;
+  bool is_uninstall_set;
+  CString extra_args_str;
+  CString app_args_str;
+  CString install_source;
+  CString crash_filename;
+  CString custom_info_filename;
+  CString legacy_manifest_path;
+  CString webplugin_urldomain;
+  CString webplugin_args;
+  CString code_red_metainstaller_path;
+  CommandLineExtraArgs extra;
+};
+
+// Parses the goopdate command line.
+HRESULT ParseCommandLine(const TCHAR* cmd_line, CommandLineArgs* args);
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_COMMAND_LINE_H__
diff --git a/goopdate/command_line_builder.cc b/goopdate/command_line_builder.cc
index 5f72889..9de2f7d 100644
--- a/goopdate/command_line_builder.cc
+++ b/goopdate/command_line_builder.cc
@@ -1,506 +1,506 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/command_line_builder.h"

-

-#include <shellapi.h>

-

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/const_goopdate.h"

-

-namespace omaha {

-

-CommandLineBuilder::CommandLineBuilder(CommandLineMode mode)

-    : mode_(mode),

-      is_interactive_set_(false),

-      is_machine_set_(false),

-      is_silent_set_(false),

-      is_eula_required_set_(false),

-      is_offline_set_(false),

-      is_uninstall_set_(false) {

-}

-

-CommandLineBuilder::~CommandLineBuilder() {

-}

-

-void CommandLineBuilder::set_is_interactive_set(bool is_interactive_set) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_REPORTCRASH);

-  is_interactive_set_ = is_interactive_set;

-}

-

-void CommandLineBuilder::set_is_machine_set(bool is_machine_set) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_UG ||

-          mode_ == COMMANDLINE_MODE_REPORTCRASH);

-  is_machine_set_ = is_machine_set;

-}

-

-void CommandLineBuilder::set_is_silent_set(bool is_silent_set) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_INSTALL ||

-          mode_ == COMMANDLINE_MODE_IG ||

-          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL);

-  is_silent_set_ = is_silent_set;

-}

-

-void CommandLineBuilder::set_is_eula_required_set(bool is_eula_required_set) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_INSTALL ||

-          mode_ == COMMANDLINE_MODE_IG ||

-          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL);

-  is_eula_required_set_ = is_eula_required_set;

-}

-

-void CommandLineBuilder::set_is_offline_set(bool is_offline_set) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_IG ||

-          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL);

-  is_offline_set_ = is_offline_set;

-}

-

-void CommandLineBuilder::set_is_uninstall_set(bool is_uninstall_set) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_UA);

-  is_uninstall_set_ = is_uninstall_set;

-}

-

-void CommandLineBuilder::set_extra_args(const CString& extra_args) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_INSTALL ||

-          mode_ == COMMANDLINE_MODE_IG ||

-          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL ||

-          mode_ == COMMANDLINE_MODE_REGISTER_PRODUCT ||

-          mode_ == COMMANDLINE_MODE_UNREGISTER_PRODUCT);

-  extra_args_ = extra_args;

-}

-

-void CommandLineBuilder::set_app_args(const CString& app_args) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_INSTALL ||

-          mode_ == COMMANDLINE_MODE_IG ||

-          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL);

-  app_args_ = app_args;

-}

-

-void CommandLineBuilder::set_install_source(const CString& install_source) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_WEBPLUGIN ||

-          mode_ == COMMANDLINE_MODE_INSTALL ||

-          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL ||

-          mode_ == COMMANDLINE_MODE_IG ||

-          mode_ == COMMANDLINE_MODE_UA);

-  install_source_ = install_source;

-}

-

-void CommandLineBuilder::set_crash_filename(const CString& crash_filename) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_REPORTCRASH);

-  crash_filename_ = crash_filename;

-}

-

-void CommandLineBuilder::set_custom_info_filename(

-    const CString& custom_info_filename) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_REPORTCRASH);

-  custom_info_filename_ = custom_info_filename;

-}

-

-void CommandLineBuilder::set_legacy_manifest_path(

-    const CString& legacy_manifest_path) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_LEGACYUI ||

-          mode_ == COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF);

-  legacy_manifest_path_ = legacy_manifest_path;

-}

-

-void CommandLineBuilder::set_webplugin_url_domain(

-    const CString& webplugin_url_domain) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_WEBPLUGIN);

-  webplugin_url_domain_ = webplugin_url_domain;

-}

-

-void CommandLineBuilder::set_webplugin_args(const CString& webplugin_args) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_WEBPLUGIN);

-  webplugin_args_ = webplugin_args;

-}

-

-void CommandLineBuilder::set_code_red_metainstaller_path(

-    const CString& code_red_metainstaller_path) {

-  ASSERT1(mode_ == COMMANDLINE_MODE_RECOVER);

-  code_red_metainstaller_path_ = code_red_metainstaller_path;

-}

-

-CString CommandLineBuilder::GetCommandLineArgs() const {

-  CString cmd_line_args;

-

-  switch (mode_) {

-    case COMMANDLINE_MODE_NOARGS:

-      cmd_line_args.Empty();

-      break;

-    case COMMANDLINE_MODE_CORE:

-      cmd_line_args = GetCore();

-      break;

-    case COMMANDLINE_MODE_CRASH_HANDLER:

-      cmd_line_args = GetCrashHandler();

-      break;

-    case COMMANDLINE_MODE_SERVICE:

-      cmd_line_args = GetService();

-      break;

-    case COMMANDLINE_MODE_SERVICE_REGISTER:

-      cmd_line_args = GetServiceRegister();

-      break;

-    case COMMANDLINE_MODE_SERVICE_UNREGISTER:

-      cmd_line_args = GetServiceUnregister();

-      break;

-    case COMMANDLINE_MODE_REGSERVER:

-      cmd_line_args = GetRegServer();

-      break;

-    case COMMANDLINE_MODE_UNREGSERVER:

-      cmd_line_args = GetUnregServer();

-      break;

-    case COMMANDLINE_MODE_NETDIAGS:

-      cmd_line_args = GetNetDiags();

-      break;

-    case COMMANDLINE_MODE_CRASH:

-      cmd_line_args = GetCrash();

-      break;

-    case COMMANDLINE_MODE_REPORTCRASH:

-      cmd_line_args = GetReportCrash();

-      break;

-    case COMMANDLINE_MODE_INSTALL:

-      cmd_line_args = GetInstall();

-      break;

-    case COMMANDLINE_MODE_UPDATE:

-      cmd_line_args = GetUpdate();

-      break;

-    case COMMANDLINE_MODE_IG:

-      cmd_line_args = GetIG();

-      break;

-    case COMMANDLINE_MODE_HANDOFF_INSTALL:

-      cmd_line_args = GetHandoffInstall();

-      break;

-    case COMMANDLINE_MODE_UG:

-      cmd_line_args = GetUG();

-      break;

-    case COMMANDLINE_MODE_UA:

-      cmd_line_args = GetUA();

-      break;

-    case COMMANDLINE_MODE_RECOVER:

-      cmd_line_args = GetRecover();

-      break;

-    case COMMANDLINE_MODE_WEBPLUGIN:

-      cmd_line_args = GetWebPlugin();

-      break;

-    case COMMANDLINE_MODE_CODE_RED_CHECK:

-      cmd_line_args = GetCodeRedCheck();

-      break;

-    case COMMANDLINE_MODE_COMSERVER:

-      cmd_line_args = GetComServer();

-      break;

-    case COMMANDLINE_MODE_LEGACYUI:

-      // No one in Omaha 2 should be using this mode.  It's only for

-      // compatibility with previous versions.

-      ASSERT1(false);

-      break;

-    case COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF:

-      cmd_line_args = GetLegacyHandoff();

-      break;

-    case COMMANDLINE_MODE_REGISTER_PRODUCT:

-      cmd_line_args = GetRegisterProduct();

-      break;

-    case COMMANDLINE_MODE_UNREGISTER_PRODUCT:

-      cmd_line_args = GetUnregisterProduct();

-      break;

-    case COMMANDLINE_MODE_UNKNOWN:

-    default:

-      ASSERT1(false);

-      break;

-  }

-

-#ifdef _DEBUG

-  CString full_command_line;

-  full_command_line.Format(_T("gu.exe %s"), cmd_line_args);

-  CommandLineArgs args;

-  ASSERT1(SUCCEEDED(ParseCommandLine(full_command_line, &args)));

-#endif

-

-  return cmd_line_args;

-}

-

-CString CommandLineBuilder::GetCommandLine(const CString& program_name) const {

-  // Do not pass the results of the the /update builder to GoogleUpdate.exe.

-  // The command line for /update is intended to be passed to a metainstaller.

-  // See GetUpdate() for more information.

-  ASSERT1(COMMANDLINE_MODE_UPDATE != mode_ ||

-          -1 == program_name.Find(kGoopdateFileName));

-

-  // Always enclose the program name in double quotes.

-  CString enclosed_program_name(program_name);

-  EnclosePath(&enclosed_program_name);

-  CString cmd_line;

-  cmd_line.Format(_T("%s %s"), enclosed_program_name, GetCommandLineArgs());

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetSingleSwitch(const CString& switch_name) const {

-  CString cmd_line;

-  cmd_line.Format(_T("/%s"), switch_name);

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetCore() const {

-  return GetSingleSwitch(kCmdLineCore);

-}

-

-CString CommandLineBuilder::GetCrashHandler() const {

-  return GetSingleSwitch(kCmdLineCrashHandler);

-}

-

-CString CommandLineBuilder::GetService() const {

-  return GetSingleSwitch(kCmdLineService);

-}

-

-CString CommandLineBuilder::GetServiceRegister() const {

-  return GetSingleSwitch(kCmdLineRegisterService);

-}

-

-CString CommandLineBuilder::GetServiceUnregister() const {

-  return GetSingleSwitch(kCmdLineUnregisterService);

-}

-

-CString CommandLineBuilder::GetRegServer() const {

-  return GetSingleSwitch(kCmdRegServer);

-}

-

-CString CommandLineBuilder::GetUnregServer() const {

-  return GetSingleSwitch(kCmdUnregServer);

-}

-

-CString CommandLineBuilder::GetNetDiags() const {

-  return GetSingleSwitch(kCmdLineNetDiags);

-}

-

-CString CommandLineBuilder::GetCrash() const {

-  CString cmd_line = GetSingleSwitch(kCmdLineCrash);

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetReportCrash() const {

-  ASSERT1(!crash_filename_.IsEmpty());

-  if (crash_filename_.IsEmpty()) {

-    return CString();

-  }

-  CString cmd_line = GetSingleSwitch(kCmdLineReport);

-  if (is_interactive_set_) {

-    cmd_line.AppendFormat(_T(" /%s"), kCmdLineInteractive);

-  }

-  CString enclosed_crash_filename_(crash_filename_);

-  EnclosePath(&enclosed_crash_filename_);

-  cmd_line.AppendFormat(_T(" %s"), enclosed_crash_filename_);

-  if (is_machine_set()) {

-    cmd_line.AppendFormat(_T(" /%s"), kCmdLineMachine);

-  }

-

-  if (!custom_info_filename_.IsEmpty()) {

-    CString enclosed_custom_info_filename_(custom_info_filename_);

-    EnclosePath(&enclosed_custom_info_filename_);

-    cmd_line.AppendFormat(_T(" /%s %s"),

-                          kCmdLineCustomInfoFileName,

-                          enclosed_custom_info_filename_);

-  }

-

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetExtraAndAppArgs(

-    const TCHAR* extra_switch_name) const {

-  ASSERT1(extra_switch_name && *extra_switch_name);

-  ASSERT1(!extra_args_.IsEmpty());

-  if (extra_args_.IsEmpty()) {

-    return CString();

-  }

-

-  CString cmd_line;

-  CString enclosed_extra_args_(extra_args_);

-  EnclosePath(&enclosed_extra_args_);

-  cmd_line.Format(_T("/%s %s"), extra_switch_name, enclosed_extra_args_);

-

-  if (!app_args_.IsEmpty()) {

-    CString enclosed_app_args = app_args_;

-    EnclosePath(&enclosed_app_args);

-    cmd_line.AppendFormat(_T(" /%s %s"), kCmdLineAppArgs, enclosed_app_args);

-  }

-

-  return cmd_line;

-}

-

-// Does not support /oem or /eularequired because we would never build that

-// internally.

-CString CommandLineBuilder::GetInstall() const {

-  CString cmd_line(GetExtraAndAppArgs(kCmdLineInstall));

-  if (cmd_line.IsEmpty()) {

-    return CString();

-  }

-

-  if (!install_source_.IsEmpty()) {

-    cmd_line.AppendFormat(_T(" /%s %s"),

-                          kCmdLineInstallSource,

-                          install_source_);

-  }

-  if (is_silent_set_) {

-    cmd_line.AppendFormat(_T(" /%s"), kCmdLineSilent);

-  }

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetUpdate() const {

-  CString cmd_line;

-  cmd_line.Format(_T("/%s"), kCmdLineUpdate);

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetIG() const {

-  CString cmd_line(GetExtraAndAppArgs(kCmdLineFinishGoogleUpdateInstall));

-  if (cmd_line.IsEmpty()) {

-    return CString();

-  }

-

-  if (!install_source_.IsEmpty()) {

-    cmd_line.AppendFormat(_T(" /%s %s"),

-                          kCmdLineInstallSource,

-                          install_source_);

-  }

-  if (is_silent_set_) {

-    cmd_line.AppendFormat(_T(" /%s"), kCmdLineSilent);

-  }

-  if (is_eula_required_set_) {

-    cmd_line.AppendFormat(_T(" /%s"), kCmdLineEulaRequired);

-  }

-  if (is_offline_set_) {

-    cmd_line.AppendFormat(_T(" /%s"), kCmdLineOfflineInstall);

-  }

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetHandoffInstall() const {

-  CString cmd_line(GetExtraAndAppArgs(kCmdLineAppHandoffInstall));

-  if (cmd_line.IsEmpty()) {

-    return CString();

-  }

-

-  if (!install_source_.IsEmpty()) {

-    cmd_line.AppendFormat(_T(" /%s %s"),

-                          kCmdLineInstallSource,

-                          install_source_);

-  }

-  if (is_silent_set_) {

-    cmd_line.AppendFormat(_T(" /%s"), kCmdLineSilent);

-  }

-  if (is_eula_required_set_) {

-    cmd_line.AppendFormat(_T(" /%s"), kCmdLineEulaRequired);

-  }

-  if (is_offline_set_) {

-    cmd_line.AppendFormat(_T(" /%s"), kCmdLineOfflineInstall);

-  }

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetUG() const {

-  CString cmd_line;

-  if (is_machine_set_) {

-    cmd_line.Format(_T("/%s /%s"),

-                    kCmdLineFinishGoogleUpdateUpdate,

-                    kCmdLineMachine);

-  } else {

-    cmd_line.Format(_T("/%s"), kCmdLineFinishGoogleUpdateUpdate);

-  }

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetUA() const {

-  ASSERT1(!install_source_.IsEmpty());

-  if (install_source_.IsEmpty()) {

-    return CString();

-  }

-

-  CString cmd_line(GetSingleSwitch(kCmdLineUpdateApps));

-  cmd_line.AppendFormat(_T(" /%s %s"), kCmdLineInstallSource, install_source_);

-

-  if (is_uninstall_set_) {

-    cmd_line.AppendFormat(_T(" /%s"), kCmdLineUninstall);

-  }

-

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetRecover() const {

-  ASSERT1(!code_red_metainstaller_path_.IsEmpty());

-  if (code_red_metainstaller_path_.IsEmpty()) {

-    return CString();

-  }

-  CString cmd_line;

-  cmd_line.Format(_T("/%s %s"), kCmdLineRecover, code_red_metainstaller_path_);

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetWebPlugin() const {

-  ASSERT1(!webplugin_url_domain_.IsEmpty());

-  ASSERT1(!webplugin_args_.IsEmpty());

-  ASSERT1(!install_source_.IsEmpty());

-  if (webplugin_url_domain_.IsEmpty() ||

-      webplugin_args_.IsEmpty() ||

-      install_source_.IsEmpty()) {

-    return CString();

-  }

-  CString cmd_line;

-  CString enclosed_webplugin_url_domain_(webplugin_url_domain_);

-  CString enclosed_webplugin_args_(webplugin_args_);

-  EnclosePath(&enclosed_webplugin_url_domain_);

-  EnclosePath(&enclosed_webplugin_args_);

-  // TODO(omaha): Do we want this to handle the urlencoding for us?

-  cmd_line.Format(_T("/%s %s %s /%s %s"),

-                  kCmdLineWebPlugin,

-                  enclosed_webplugin_url_domain_,

-                  enclosed_webplugin_args_,

-                  kCmdLineInstallSource,

-                  install_source_);

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetCodeRedCheck() const {

-  return GetSingleSwitch(kCmdLineCodeRedCheck);

-}

-

-CString CommandLineBuilder::GetComServer() const {

-  return kCmdLineComServerDash;

-}

-

-CString CommandLineBuilder::GetLegacyHandoff() const {

-  ASSERT1(!legacy_manifest_path_.IsEmpty());

-  if (legacy_manifest_path_.IsEmpty()) {

-    return CString();

-  }

-  CString cmd_line;

-  cmd_line.Format(_T("/%s %s"),

-                  kCmdLineLegacyUserManifest,

-                  legacy_manifest_path_);

-  return cmd_line;

-}

-

-CString CommandLineBuilder::GetRegisterProduct() const {

-  ASSERT1(app_args_.IsEmpty());

-  return GetExtraAndAppArgs(kCmdLineRegisterProduct);

-}

-

-CString CommandLineBuilder::GetUnregisterProduct() const {

-  ASSERT1(app_args_.IsEmpty());

-  return GetExtraAndAppArgs(kCmdLineUnregisterProduct);

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/command_line_builder.h"
+
+#include <shellapi.h>
+
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/const_goopdate.h"
+
+namespace omaha {
+
+CommandLineBuilder::CommandLineBuilder(CommandLineMode mode)
+    : mode_(mode),
+      is_interactive_set_(false),
+      is_machine_set_(false),
+      is_silent_set_(false),
+      is_eula_required_set_(false),
+      is_offline_set_(false),
+      is_uninstall_set_(false) {
+}
+
+CommandLineBuilder::~CommandLineBuilder() {
+}
+
+void CommandLineBuilder::set_is_interactive_set(bool is_interactive_set) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_REPORTCRASH);
+  is_interactive_set_ = is_interactive_set;
+}
+
+void CommandLineBuilder::set_is_machine_set(bool is_machine_set) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_UG ||
+          mode_ == COMMANDLINE_MODE_REPORTCRASH);
+  is_machine_set_ = is_machine_set;
+}
+
+void CommandLineBuilder::set_is_silent_set(bool is_silent_set) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_INSTALL ||
+          mode_ == COMMANDLINE_MODE_IG ||
+          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL);
+  is_silent_set_ = is_silent_set;
+}
+
+void CommandLineBuilder::set_is_eula_required_set(bool is_eula_required_set) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_INSTALL ||
+          mode_ == COMMANDLINE_MODE_IG ||
+          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL);
+  is_eula_required_set_ = is_eula_required_set;
+}
+
+void CommandLineBuilder::set_is_offline_set(bool is_offline_set) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_IG ||
+          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL);
+  is_offline_set_ = is_offline_set;
+}
+
+void CommandLineBuilder::set_is_uninstall_set(bool is_uninstall_set) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_UA);
+  is_uninstall_set_ = is_uninstall_set;
+}
+
+void CommandLineBuilder::set_extra_args(const CString& extra_args) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_INSTALL ||
+          mode_ == COMMANDLINE_MODE_IG ||
+          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL ||
+          mode_ == COMMANDLINE_MODE_REGISTER_PRODUCT ||
+          mode_ == COMMANDLINE_MODE_UNREGISTER_PRODUCT);
+  extra_args_ = extra_args;
+}
+
+void CommandLineBuilder::set_app_args(const CString& app_args) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_INSTALL ||
+          mode_ == COMMANDLINE_MODE_IG ||
+          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL);
+  app_args_ = app_args;
+}
+
+void CommandLineBuilder::set_install_source(const CString& install_source) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_WEBPLUGIN ||
+          mode_ == COMMANDLINE_MODE_INSTALL ||
+          mode_ == COMMANDLINE_MODE_HANDOFF_INSTALL ||
+          mode_ == COMMANDLINE_MODE_IG ||
+          mode_ == COMMANDLINE_MODE_UA);
+  install_source_ = install_source;
+}
+
+void CommandLineBuilder::set_crash_filename(const CString& crash_filename) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_REPORTCRASH);
+  crash_filename_ = crash_filename;
+}
+
+void CommandLineBuilder::set_custom_info_filename(
+    const CString& custom_info_filename) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_REPORTCRASH);
+  custom_info_filename_ = custom_info_filename;
+}
+
+void CommandLineBuilder::set_legacy_manifest_path(
+    const CString& legacy_manifest_path) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_LEGACYUI ||
+          mode_ == COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF);
+  legacy_manifest_path_ = legacy_manifest_path;
+}
+
+void CommandLineBuilder::set_webplugin_url_domain(
+    const CString& webplugin_url_domain) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_WEBPLUGIN);
+  webplugin_url_domain_ = webplugin_url_domain;
+}
+
+void CommandLineBuilder::set_webplugin_args(const CString& webplugin_args) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_WEBPLUGIN);
+  webplugin_args_ = webplugin_args;
+}
+
+void CommandLineBuilder::set_code_red_metainstaller_path(
+    const CString& code_red_metainstaller_path) {
+  ASSERT1(mode_ == COMMANDLINE_MODE_RECOVER);
+  code_red_metainstaller_path_ = code_red_metainstaller_path;
+}
+
+CString CommandLineBuilder::GetCommandLineArgs() const {
+  CString cmd_line_args;
+
+  switch (mode_) {
+    case COMMANDLINE_MODE_NOARGS:
+      cmd_line_args.Empty();
+      break;
+    case COMMANDLINE_MODE_CORE:
+      cmd_line_args = GetCore();
+      break;
+    case COMMANDLINE_MODE_CRASH_HANDLER:
+      cmd_line_args = GetCrashHandler();
+      break;
+    case COMMANDLINE_MODE_SERVICE:
+      cmd_line_args = GetService();
+      break;
+    case COMMANDLINE_MODE_SERVICE_REGISTER:
+      cmd_line_args = GetServiceRegister();
+      break;
+    case COMMANDLINE_MODE_SERVICE_UNREGISTER:
+      cmd_line_args = GetServiceUnregister();
+      break;
+    case COMMANDLINE_MODE_REGSERVER:
+      cmd_line_args = GetRegServer();
+      break;
+    case COMMANDLINE_MODE_UNREGSERVER:
+      cmd_line_args = GetUnregServer();
+      break;
+    case COMMANDLINE_MODE_NETDIAGS:
+      cmd_line_args = GetNetDiags();
+      break;
+    case COMMANDLINE_MODE_CRASH:
+      cmd_line_args = GetCrash();
+      break;
+    case COMMANDLINE_MODE_REPORTCRASH:
+      cmd_line_args = GetReportCrash();
+      break;
+    case COMMANDLINE_MODE_INSTALL:
+      cmd_line_args = GetInstall();
+      break;
+    case COMMANDLINE_MODE_UPDATE:
+      cmd_line_args = GetUpdate();
+      break;
+    case COMMANDLINE_MODE_IG:
+      cmd_line_args = GetIG();
+      break;
+    case COMMANDLINE_MODE_HANDOFF_INSTALL:
+      cmd_line_args = GetHandoffInstall();
+      break;
+    case COMMANDLINE_MODE_UG:
+      cmd_line_args = GetUG();
+      break;
+    case COMMANDLINE_MODE_UA:
+      cmd_line_args = GetUA();
+      break;
+    case COMMANDLINE_MODE_RECOVER:
+      cmd_line_args = GetRecover();
+      break;
+    case COMMANDLINE_MODE_WEBPLUGIN:
+      cmd_line_args = GetWebPlugin();
+      break;
+    case COMMANDLINE_MODE_CODE_RED_CHECK:
+      cmd_line_args = GetCodeRedCheck();
+      break;
+    case COMMANDLINE_MODE_COMSERVER:
+      cmd_line_args = GetComServer();
+      break;
+    case COMMANDLINE_MODE_LEGACYUI:
+      // No one in Omaha 2 should be using this mode.  It's only for
+      // compatibility with previous versions.
+      ASSERT1(false);
+      break;
+    case COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF:
+      cmd_line_args = GetLegacyHandoff();
+      break;
+    case COMMANDLINE_MODE_REGISTER_PRODUCT:
+      cmd_line_args = GetRegisterProduct();
+      break;
+    case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
+      cmd_line_args = GetUnregisterProduct();
+      break;
+    case COMMANDLINE_MODE_UNKNOWN:
+    default:
+      ASSERT1(false);
+      break;
+  }
+
+#ifdef _DEBUG
+  CString full_command_line;
+  full_command_line.Format(_T("gu.exe %s"), cmd_line_args);
+  CommandLineArgs args;
+  ASSERT1(SUCCEEDED(ParseCommandLine(full_command_line, &args)));
+#endif
+
+  return cmd_line_args;
+}
+
+CString CommandLineBuilder::GetCommandLine(const CString& program_name) const {
+  // Do not pass the results of the the /update builder to GoogleUpdate.exe.
+  // The command line for /update is intended to be passed to a metainstaller.
+  // See GetUpdate() for more information.
+  ASSERT1(COMMANDLINE_MODE_UPDATE != mode_ ||
+          -1 == program_name.Find(kGoopdateFileName));
+
+  // Always enclose the program name in double quotes.
+  CString enclosed_program_name(program_name);
+  EnclosePath(&enclosed_program_name);
+  CString cmd_line;
+  cmd_line.Format(_T("%s %s"), enclosed_program_name, GetCommandLineArgs());
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetSingleSwitch(const CString& switch_name) const {
+  CString cmd_line;
+  cmd_line.Format(_T("/%s"), switch_name);
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetCore() const {
+  return GetSingleSwitch(kCmdLineCore);
+}
+
+CString CommandLineBuilder::GetCrashHandler() const {
+  return GetSingleSwitch(kCmdLineCrashHandler);
+}
+
+CString CommandLineBuilder::GetService() const {
+  return GetSingleSwitch(kCmdLineService);
+}
+
+CString CommandLineBuilder::GetServiceRegister() const {
+  return GetSingleSwitch(kCmdLineRegisterService);
+}
+
+CString CommandLineBuilder::GetServiceUnregister() const {
+  return GetSingleSwitch(kCmdLineUnregisterService);
+}
+
+CString CommandLineBuilder::GetRegServer() const {
+  return GetSingleSwitch(kCmdRegServer);
+}
+
+CString CommandLineBuilder::GetUnregServer() const {
+  return GetSingleSwitch(kCmdUnregServer);
+}
+
+CString CommandLineBuilder::GetNetDiags() const {
+  return GetSingleSwitch(kCmdLineNetDiags);
+}
+
+CString CommandLineBuilder::GetCrash() const {
+  CString cmd_line = GetSingleSwitch(kCmdLineCrash);
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetReportCrash() const {
+  ASSERT1(!crash_filename_.IsEmpty());
+  if (crash_filename_.IsEmpty()) {
+    return CString();
+  }
+  CString cmd_line = GetSingleSwitch(kCmdLineReport);
+  if (is_interactive_set_) {
+    cmd_line.AppendFormat(_T(" /%s"), kCmdLineInteractive);
+  }
+  CString enclosed_crash_filename_(crash_filename_);
+  EnclosePath(&enclosed_crash_filename_);
+  cmd_line.AppendFormat(_T(" %s"), enclosed_crash_filename_);
+  if (is_machine_set()) {
+    cmd_line.AppendFormat(_T(" /%s"), kCmdLineMachine);
+  }
+
+  if (!custom_info_filename_.IsEmpty()) {
+    CString enclosed_custom_info_filename_(custom_info_filename_);
+    EnclosePath(&enclosed_custom_info_filename_);
+    cmd_line.AppendFormat(_T(" /%s %s"),
+                          kCmdLineCustomInfoFileName,
+                          enclosed_custom_info_filename_);
+  }
+
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetExtraAndAppArgs(
+    const TCHAR* extra_switch_name) const {
+  ASSERT1(extra_switch_name && *extra_switch_name);
+  ASSERT1(!extra_args_.IsEmpty());
+  if (extra_args_.IsEmpty()) {
+    return CString();
+  }
+
+  CString cmd_line;
+  CString enclosed_extra_args_(extra_args_);
+  EnclosePath(&enclosed_extra_args_);
+  cmd_line.Format(_T("/%s %s"), extra_switch_name, enclosed_extra_args_);
+
+  if (!app_args_.IsEmpty()) {
+    CString enclosed_app_args = app_args_;
+    EnclosePath(&enclosed_app_args);
+    cmd_line.AppendFormat(_T(" /%s %s"), kCmdLineAppArgs, enclosed_app_args);
+  }
+
+  return cmd_line;
+}
+
+// Does not support /oem or /eularequired because we would never build that
+// internally.
+CString CommandLineBuilder::GetInstall() const {
+  CString cmd_line(GetExtraAndAppArgs(kCmdLineInstall));
+  if (cmd_line.IsEmpty()) {
+    return CString();
+  }
+
+  if (!install_source_.IsEmpty()) {
+    cmd_line.AppendFormat(_T(" /%s %s"),
+                          kCmdLineInstallSource,
+                          install_source_);
+  }
+  if (is_silent_set_) {
+    cmd_line.AppendFormat(_T(" /%s"), kCmdLineSilent);
+  }
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetUpdate() const {
+  CString cmd_line;
+  cmd_line.Format(_T("/%s"), kCmdLineUpdate);
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetIG() const {
+  CString cmd_line(GetExtraAndAppArgs(kCmdLineFinishGoogleUpdateInstall));
+  if (cmd_line.IsEmpty()) {
+    return CString();
+  }
+
+  if (!install_source_.IsEmpty()) {
+    cmd_line.AppendFormat(_T(" /%s %s"),
+                          kCmdLineInstallSource,
+                          install_source_);
+  }
+  if (is_silent_set_) {
+    cmd_line.AppendFormat(_T(" /%s"), kCmdLineSilent);
+  }
+  if (is_eula_required_set_) {
+    cmd_line.AppendFormat(_T(" /%s"), kCmdLineEulaRequired);
+  }
+  if (is_offline_set_) {
+    cmd_line.AppendFormat(_T(" /%s"), kCmdLineOfflineInstall);
+  }
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetHandoffInstall() const {
+  CString cmd_line(GetExtraAndAppArgs(kCmdLineAppHandoffInstall));
+  if (cmd_line.IsEmpty()) {
+    return CString();
+  }
+
+  if (!install_source_.IsEmpty()) {
+    cmd_line.AppendFormat(_T(" /%s %s"),
+                          kCmdLineInstallSource,
+                          install_source_);
+  }
+  if (is_silent_set_) {
+    cmd_line.AppendFormat(_T(" /%s"), kCmdLineSilent);
+  }
+  if (is_eula_required_set_) {
+    cmd_line.AppendFormat(_T(" /%s"), kCmdLineEulaRequired);
+  }
+  if (is_offline_set_) {
+    cmd_line.AppendFormat(_T(" /%s"), kCmdLineOfflineInstall);
+  }
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetUG() const {
+  CString cmd_line;
+  if (is_machine_set_) {
+    cmd_line.Format(_T("/%s /%s"),
+                    kCmdLineFinishGoogleUpdateUpdate,
+                    kCmdLineMachine);
+  } else {
+    cmd_line.Format(_T("/%s"), kCmdLineFinishGoogleUpdateUpdate);
+  }
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetUA() const {
+  ASSERT1(!install_source_.IsEmpty());
+  if (install_source_.IsEmpty()) {
+    return CString();
+  }
+
+  CString cmd_line(GetSingleSwitch(kCmdLineUpdateApps));
+  cmd_line.AppendFormat(_T(" /%s %s"), kCmdLineInstallSource, install_source_);
+
+  if (is_uninstall_set_) {
+    cmd_line.AppendFormat(_T(" /%s"), kCmdLineUninstall);
+  }
+
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetRecover() const {
+  ASSERT1(!code_red_metainstaller_path_.IsEmpty());
+  if (code_red_metainstaller_path_.IsEmpty()) {
+    return CString();
+  }
+  CString cmd_line;
+  cmd_line.Format(_T("/%s %s"), kCmdLineRecover, code_red_metainstaller_path_);
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetWebPlugin() const {
+  ASSERT1(!webplugin_url_domain_.IsEmpty());
+  ASSERT1(!webplugin_args_.IsEmpty());
+  ASSERT1(!install_source_.IsEmpty());
+  if (webplugin_url_domain_.IsEmpty() ||
+      webplugin_args_.IsEmpty() ||
+      install_source_.IsEmpty()) {
+    return CString();
+  }
+  CString cmd_line;
+  CString enclosed_webplugin_url_domain_(webplugin_url_domain_);
+  CString enclosed_webplugin_args_(webplugin_args_);
+  EnclosePath(&enclosed_webplugin_url_domain_);
+  EnclosePath(&enclosed_webplugin_args_);
+  // TODO(omaha): Do we want this to handle the urlencoding for us?
+  cmd_line.Format(_T("/%s %s %s /%s %s"),
+                  kCmdLineWebPlugin,
+                  enclosed_webplugin_url_domain_,
+                  enclosed_webplugin_args_,
+                  kCmdLineInstallSource,
+                  install_source_);
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetCodeRedCheck() const {
+  return GetSingleSwitch(kCmdLineCodeRedCheck);
+}
+
+CString CommandLineBuilder::GetComServer() const {
+  return kCmdLineComServerDash;
+}
+
+CString CommandLineBuilder::GetLegacyHandoff() const {
+  ASSERT1(!legacy_manifest_path_.IsEmpty());
+  if (legacy_manifest_path_.IsEmpty()) {
+    return CString();
+  }
+  CString cmd_line;
+  cmd_line.Format(_T("/%s %s"),
+                  kCmdLineLegacyUserManifest,
+                  legacy_manifest_path_);
+  return cmd_line;
+}
+
+CString CommandLineBuilder::GetRegisterProduct() const {
+  ASSERT1(app_args_.IsEmpty());
+  return GetExtraAndAppArgs(kCmdLineRegisterProduct);
+}
+
+CString CommandLineBuilder::GetUnregisterProduct() const {
+  ASSERT1(app_args_.IsEmpty());
+  return GetExtraAndAppArgs(kCmdLineUnregisterProduct);
+}
+
+}  // namespace omaha
diff --git a/goopdate/command_line_builder.h b/goopdate/command_line_builder.h
index f030d5a..569da7d 100644
--- a/goopdate/command_line_builder.h
+++ b/goopdate/command_line_builder.h
@@ -1,141 +1,141 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_COMMAND_LINE_BUILDER_H__

-#define OMAHA_GOOPDATE_COMMAND_LINE_BUILDER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-

-#include "base/basictypes.h"

-#include "omaha/goopdate/command_line.h"

-

-namespace omaha {

-

-// This class builds a GoogleUpdate.exe command line and makes sure it's

-// valid against the GoopdateCommandLineValidator.

-class CommandLineBuilder {

- public:

-  explicit CommandLineBuilder(CommandLineMode mode);

-  ~CommandLineBuilder();

-

-  CommandLineMode mode() const { return mode_; }

-

-  bool is_interactive_set() const { return is_interactive_set_; }

-  void set_is_interactive_set(bool is_interactive_set);

-

-  bool is_machine_set() const { return is_machine_set_; }

-  void set_is_machine_set(bool is_machine_set);

-

-  bool is_silent_set() const { return is_silent_set_; }

-  void set_is_silent_set(bool is_silent_set);

-

-  bool is_eula_required_set() const { return is_eula_required_set_; }

-  void set_is_eula_required_set(bool is_eula_required_set);

-

-  bool is_offline_set() const { return is_offline_set_; }

-  void set_is_offline_set(bool is_offline_set);

-

-  bool is_uninstall_set() const { return is_uninstall_set_; }

-  void set_is_uninstall_set(bool is_uninstall_set);

-

-  CString extra_args() const { return extra_args_; }

-  void set_extra_args(const CString& extra_args);

-

-  CString app_args() const { return app_args_; }

-  void set_app_args(const CString& app_args);

-

-  CString install_source() const { return install_source_; }

-  void set_install_source(const CString& install_source);

-

-  CString crash_filename() const { return crash_filename_; }

-  void set_crash_filename(const CString& crash_filename);

-

-  CString custom_info_filename() const { return custom_info_filename_; }

-  void set_custom_info_filename(const CString& custom_info_filename);

-

-  CString legacy_manifest_path() const { return legacy_manifest_path_; }

-  void set_legacy_manifest_path(const CString& legacy_manifest_path);

-

-  CString webplugin_url_domain() const { return webplugin_url_domain_; }

-  void set_webplugin_url_domain(const CString& webplugin_url_domain);

-

-  CString webplugin_args() const { return webplugin_args_; }

-  void set_webplugin_args(const CString& webplugin_args);

-

-  CString code_red_metainstaller_path() const {

-    return code_red_metainstaller_path_;

-  }

-  void set_code_red_metainstaller_path(

-      const CString& code_red_metainstaller_path);

-

-  // Outputs the proper command line string for the properties that are set.

-  // If the properties aren't in a valid combination, function will assert.

-  CString GetCommandLineArgs()  const;

-

-  CString GetCommandLine(const CString& program_name) const;

-

- private:

-  CString GetSingleSwitch(const CString& switch_name) const;

-  CString GetExtraAndAppArgs(const TCHAR* extra_switch_name) const;

-

-  CString GetCore() const;

-  CString GetCrashHandler() const;

-  CString GetService() const;

-  CString GetServiceRegister() const;

-  CString GetServiceUnregister() const;

-  CString GetRegServer() const;

-  CString GetUnregServer() const;

-  CString GetNetDiags() const;

-  CString GetCrash() const;

-  CString GetReportCrash() const;

-  CString GetInstall() const;

-  CString GetUpdate() const;

-  CString GetIG() const;

-  CString GetHandoffInstall() const;

-  CString GetUG() const;

-  CString GetUA() const;

-  CString GetRecover() const;

-  CString GetWebPlugin() const;

-  CString GetCodeRedCheck() const;

-  CString GetComServer() const;

-  CString GetLegacyHandoff() const;

-  CString GetRegisterProduct() const;

-  CString GetUnregisterProduct() const;

-

-  const CommandLineMode mode_;

-  bool is_interactive_set_;

-  bool is_machine_set_;

-  bool is_silent_set_;

-  bool is_eula_required_set_;

-  bool is_offline_set_;

-  bool is_uninstall_set_;

-  CString extra_args_;

-  CString app_args_;

-  CString install_source_;

-  CString crash_filename_;

-  CString custom_info_filename_;

-  CString legacy_manifest_path_;

-  CString webplugin_url_domain_;

-  CString webplugin_args_;

-  CString code_red_metainstaller_path_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(CommandLineBuilder);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_COMMAND_LINE_BUILDER_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_COMMAND_LINE_BUILDER_H__
+#define OMAHA_GOOPDATE_COMMAND_LINE_BUILDER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+
+#include "base/basictypes.h"
+#include "omaha/goopdate/command_line.h"
+
+namespace omaha {
+
+// This class builds a GoogleUpdate.exe command line and makes sure it's
+// valid against the GoopdateCommandLineValidator.
+class CommandLineBuilder {
+ public:
+  explicit CommandLineBuilder(CommandLineMode mode);
+  ~CommandLineBuilder();
+
+  CommandLineMode mode() const { return mode_; }
+
+  bool is_interactive_set() const { return is_interactive_set_; }
+  void set_is_interactive_set(bool is_interactive_set);
+
+  bool is_machine_set() const { return is_machine_set_; }
+  void set_is_machine_set(bool is_machine_set);
+
+  bool is_silent_set() const { return is_silent_set_; }
+  void set_is_silent_set(bool is_silent_set);
+
+  bool is_eula_required_set() const { return is_eula_required_set_; }
+  void set_is_eula_required_set(bool is_eula_required_set);
+
+  bool is_offline_set() const { return is_offline_set_; }
+  void set_is_offline_set(bool is_offline_set);
+
+  bool is_uninstall_set() const { return is_uninstall_set_; }
+  void set_is_uninstall_set(bool is_uninstall_set);
+
+  CString extra_args() const { return extra_args_; }
+  void set_extra_args(const CString& extra_args);
+
+  CString app_args() const { return app_args_; }
+  void set_app_args(const CString& app_args);
+
+  CString install_source() const { return install_source_; }
+  void set_install_source(const CString& install_source);
+
+  CString crash_filename() const { return crash_filename_; }
+  void set_crash_filename(const CString& crash_filename);
+
+  CString custom_info_filename() const { return custom_info_filename_; }
+  void set_custom_info_filename(const CString& custom_info_filename);
+
+  CString legacy_manifest_path() const { return legacy_manifest_path_; }
+  void set_legacy_manifest_path(const CString& legacy_manifest_path);
+
+  CString webplugin_url_domain() const { return webplugin_url_domain_; }
+  void set_webplugin_url_domain(const CString& webplugin_url_domain);
+
+  CString webplugin_args() const { return webplugin_args_; }
+  void set_webplugin_args(const CString& webplugin_args);
+
+  CString code_red_metainstaller_path() const {
+    return code_red_metainstaller_path_;
+  }
+  void set_code_red_metainstaller_path(
+      const CString& code_red_metainstaller_path);
+
+  // Outputs the proper command line string for the properties that are set.
+  // If the properties aren't in a valid combination, function will assert.
+  CString GetCommandLineArgs()  const;
+
+  CString GetCommandLine(const CString& program_name) const;
+
+ private:
+  CString GetSingleSwitch(const CString& switch_name) const;
+  CString GetExtraAndAppArgs(const TCHAR* extra_switch_name) const;
+
+  CString GetCore() const;
+  CString GetCrashHandler() const;
+  CString GetService() const;
+  CString GetServiceRegister() const;
+  CString GetServiceUnregister() const;
+  CString GetRegServer() const;
+  CString GetUnregServer() const;
+  CString GetNetDiags() const;
+  CString GetCrash() const;
+  CString GetReportCrash() const;
+  CString GetInstall() const;
+  CString GetUpdate() const;
+  CString GetIG() const;
+  CString GetHandoffInstall() const;
+  CString GetUG() const;
+  CString GetUA() const;
+  CString GetRecover() const;
+  CString GetWebPlugin() const;
+  CString GetCodeRedCheck() const;
+  CString GetComServer() const;
+  CString GetLegacyHandoff() const;
+  CString GetRegisterProduct() const;
+  CString GetUnregisterProduct() const;
+
+  const CommandLineMode mode_;
+  bool is_interactive_set_;
+  bool is_machine_set_;
+  bool is_silent_set_;
+  bool is_eula_required_set_;
+  bool is_offline_set_;
+  bool is_uninstall_set_;
+  CString extra_args_;
+  CString app_args_;
+  CString install_source_;
+  CString crash_filename_;
+  CString custom_info_filename_;
+  CString legacy_manifest_path_;
+  CString webplugin_url_domain_;
+  CString webplugin_args_;
+  CString code_red_metainstaller_path_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(CommandLineBuilder);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_COMMAND_LINE_BUILDER_H__
+
diff --git a/goopdate/command_line_builder_unittest.cc b/goopdate/command_line_builder_unittest.cc
index 9c65429..4504c24 100644
--- a/goopdate/command_line_builder_unittest.cc
+++ b/goopdate/command_line_builder_unittest.cc
@@ -1,514 +1,514 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(CommandLineBuilder, BuildUnknown) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UNKNOWN);

-  ExpectAsserts expect_asserts;

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildNoArgs) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_NOARGS);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildCore) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_CORE);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/c"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildService) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_SERVICE);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/svc"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildRegServer) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REGSERVER);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/regserver"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildUnregServer) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UNREGSERVER);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/unregserver"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildNetDiags) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_NETDIAGS);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/netdiags"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildCrashNoFilename) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_CRASH);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/crash"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildReportCrash) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  ExpectAsserts expect_asserts;  // Missing filename.

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildReportCrashWithFilename) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  builder.set_crash_filename(_T("foo.dmp"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/report \"foo.dmp\""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildReportCrashWithFilenameMachine) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  builder.set_crash_filename(_T("foo.dmp"));

-  builder.set_is_machine_set(true);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/report \"foo.dmp\" /machine"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildReportCrashWithEnclosedFilename) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  builder.set_crash_filename(_T("\"foo.dmp\""));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/report \"foo.dmp\""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildReportCrashWithCustomInfo) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  ExpectAsserts expect_asserts;  // Missing filename.

-  builder.set_custom_info_filename(_T("foo.txt"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildReportCrashWithFileanameWithCustomInfo) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  builder.set_crash_filename(_T("foo.dmp"));

-  builder.set_custom_info_filename(_T("foo.txt"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/report \"foo.dmp\" /custom_info_filename \"foo.txt\""),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildReportCrashWithFileanameWithCustomInfoMachine) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  builder.set_crash_filename(_T("foo.dmp"));

-  builder.set_custom_info_filename(_T("foo.txt"));

-  builder.set_is_machine_set(true);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(

-      _T("/report \"foo.dmp\" /machine /custom_info_filename \"foo.txt\""),

-      cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildReportCrashWithEnclosedFileanameWithCustomInfo) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  builder.set_crash_filename(_T("\"foo.dmp\""));

-  builder.set_custom_info_filename(_T("\"foo.txt\""));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/report \"foo.dmp\" /custom_info_filename \"foo.txt\""),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildReportCrashInteractiveWithFilename) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  builder.set_crash_filename(_T("foo.dmp"));

-  builder.set_is_interactive_set(true);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/report /i \"foo.dmp\""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildReportCrashMachineInteractiveWithFilename) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  builder.set_crash_filename(_T("foo.dmp"));

-  builder.set_is_machine_set(true);

-  builder.set_is_interactive_set(true);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/report /i \"foo.dmp\" /machine"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildInstall) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL);

-  ExpectAsserts expect_asserts;  // Missing parameters.

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildInstallWithExtraArgs) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/install \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\""),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildInstallWithExtraArgsSilent) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  builder.set_is_silent_set(true);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/install \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\" /silent"),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildUpdate) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UPDATE);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/update"), cmd_line);

-}

-

-// The /update builder works when not used with GoogleUpdate.exe.

-TEST(CommandLineBuilder, BuildUpdateAndGetCommandLineWithNonGoogleUpdateExe) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UPDATE);

-  CString cmd_line = builder.GetCommandLine(_T("C:\\GoogleUpdateSetup_en.exe"));

-  EXPECT_STREQ(_T("\"C:\\GoogleUpdateSetup_en.exe\" /update"), cmd_line);

-}

-

-// The /update builder should not be used with GoogleUpdate.exe directly.

-TEST(CommandLineBuilder, BuildUpdateAndGetCommandLineWithGoogleUpdateExe) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UPDATE);

-  ExpectAsserts expect_asserts;

-  CString cmd_line = builder.GetCommandLine(_T("C:\\GoogleUpdate.exe"));

-  EXPECT_STREQ(_T("\"C:\\GoogleUpdate.exe\" /update"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildLegacyManifestHandoff) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF);

-  ExpectAsserts expect_asserts;

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildLegacyManifestHandoffWithManifest) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF);

-  builder.set_legacy_manifest_path(_T("foo.gup"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/uiuser foo.gup"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildLegacyUi) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_LEGACYUI);

-  ExpectAsserts expect_asserts;  // Not a supported type to build.

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildComServer) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_COMSERVER);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("-Embedding"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildCodeRedCheck) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_CODE_RED_CHECK);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/cr"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildWebPlugin) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_WEBPLUGIN);

-  ExpectAsserts expect_asserts;

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildWebPluginWithUrlArgsAndInstallSource) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_WEBPLUGIN);

-  builder.set_webplugin_args(_T("piargs"));

-  builder.set_webplugin_url_domain(_T("http://www.google.com/"));

-  builder.set_install_source(_T("oneclick"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/pi \"http://www.google.com/\" \"piargs\"")

-               _T(" /installsource oneclick"),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildRecover) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_RECOVER);

-  ExpectAsserts expect_asserts;

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildRecoverWithMIPath) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_RECOVER);

-  builder.set_code_red_metainstaller_path(_T("foo.exe"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/recover foo.exe"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildUA) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UA);

-  ExpectAsserts expect_asserts;

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildUAWithInstallSource) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UA);

-  builder.set_install_source(_T("blah"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/ua /installsource blah"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildUAWithInstallSourceAndUninstall) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UA);

-  builder.set_install_source(_T("blah"));

-  builder.set_is_uninstall_set(true);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/ua /installsource blah /uninstall"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildUG) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UG);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/ug"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildUGWithMachine) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UG);

-  builder.set_is_machine_set(true);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/ug /machine"), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildHandoffInstall) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);

-  ExpectAsserts expect_asserts;  // Missing extra args.

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildHandoffInstallWithExtraArgs) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/handoff \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\""),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildHandoffInstallWithExtraArgsOffline) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  builder.set_install_source(_T("offline"));

-  builder.set_is_offline_set(true);

-

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/handoff \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")

-               _T(" /installsource offline")

-               _T(" /offlineinstall"),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildHandoffInstallWithExtraArgsSilentOffline) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  builder.set_install_source(_T("offline"));

-  builder.set_is_silent_set(true);

-  builder.set_is_offline_set(true);

-

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/handoff \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")

-               _T(" /installsource offline")

-               _T(" /silent /offlineinstall"),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildHandoffWithAppArgsSilentOffline) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  builder.set_app_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                       _T("installerdata=foobar%45"));

-  builder.set_install_source(_T("offline"));

-  builder.set_is_silent_set(true);

-  builder.set_is_offline_set(true);

-

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/handoff \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")

-               _T(" /appargs \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("installerdata=foobar%45\"")

-               _T(" /installsource offline")

-               _T(" /silent /offlineinstall"),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildHandoffWithAppArgsSilentOfflineEulaRequired) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  builder.set_app_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                       _T("installerdata=foobar%45"));

-  builder.set_install_source(_T("offline"));

-  builder.set_is_silent_set(true);

-  builder.set_is_eula_required_set(true);

-  builder.set_is_offline_set(true);

-

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/handoff \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")

-               _T(" /appargs \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("installerdata=foobar%45\"")

-               _T(" /installsource offline")

-               _T(" /silent /eularequired /offlineinstall"),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildIG) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_IG);

-  ExpectAsserts expect_asserts;

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T(""), cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildIGWithExtraArgs) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_IG);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/ig \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\""),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildIGWithExtraArgsOffline) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_IG);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  builder.set_install_source(_T("offline"));

-  builder.set_is_offline_set(true);

-

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/ig \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")

-               _T(" /installsource offline")

-               _T(" /offlineinstall"),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildIGWithExtraArgsOfflineSilent) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_IG);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  builder.set_install_source(_T("offline"));

-  builder.set_is_silent_set(true);

-  builder.set_is_offline_set(true);

-

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/ig \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")

-               _T(" /installsource offline")

-               _T(" /silent /offlineinstall"),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildIGWithAppArgsSilentOffline) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_IG);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  builder.set_app_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                       _T("installerdata=foobar%45"));

-  builder.set_install_source(_T("offline"));

-  builder.set_is_silent_set(true);

-  builder.set_is_offline_set(true);

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/ig \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")

-               _T(" /appargs \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("installerdata=foobar%45\"")

-               _T(" /installsource offline")

-               _T(" /silent /offlineinstall"),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildIGWithAppArgsSilentOfflineEulaRequired) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_IG);

-  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                         _T("appname=YouTubeUploader&needsadmin=False&")

-                         _T("lang=en"));

-  builder.set_app_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                       _T("installerdata=foobar%45"));

-  builder.set_install_source(_T("offline"));

-  builder.set_is_silent_set(true);

-  builder.set_is_eula_required_set(true);

-  builder.set_is_offline_set(true);

-

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/ig \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")

-               _T(" /appargs \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-               _T("installerdata=foobar%45\"")

-               _T(" /installsource offline")

-               _T(" /silent /eularequired /offlineinstall"),

-               cmd_line);

-}

-TEST(CommandLineBuilder, BuildRegisterProduct) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_REGISTER_PRODUCT);

-  builder.set_extra_args(_T("appguid={7DD3DAE3-87F1-4CFE-8BF4-452C74421401}&")

-                         _T("appname=Google Toolbar&needsadmin=True&")

-                         _T("lang=en"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/registerproduct ")

-               _T("\"appguid={7DD3DAE3-87F1-4CFE-8BF4-452C74421401}&")

-               _T("appname=Google Toolbar&needsadmin=True&lang=en\""),

-               cmd_line);

-}

-

-TEST(CommandLineBuilder, BuildUnregisterProduc) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_UNREGISTER_PRODUCT);

-  builder.set_extra_args(_T("appguid={7DD3DAE3-87F1-4CFE-8BF4-452C74421401}&")

-                         _T("needsadmin=True&lang=en"));

-  CString cmd_line = builder.GetCommandLineArgs();

-  EXPECT_STREQ(_T("/unregisterproduct ")

-               _T("\"appguid={7DD3DAE3-87F1-4CFE-8BF4-452C74421401}&")

-               _T("needsadmin=True&lang=en\""),

-               cmd_line);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(CommandLineBuilder, BuildUnknown) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UNKNOWN);
+  ExpectAsserts expect_asserts;
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildNoArgs) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_NOARGS);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildCore) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_CORE);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/c"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildService) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_SERVICE);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/svc"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildRegServer) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REGSERVER);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/regserver"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildUnregServer) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UNREGSERVER);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/unregserver"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildNetDiags) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_NETDIAGS);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/netdiags"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildCrashNoFilename) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_CRASH);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/crash"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildReportCrash) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  ExpectAsserts expect_asserts;  // Missing filename.
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildReportCrashWithFilename) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  builder.set_crash_filename(_T("foo.dmp"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/report \"foo.dmp\""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildReportCrashWithFilenameMachine) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  builder.set_crash_filename(_T("foo.dmp"));
+  builder.set_is_machine_set(true);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/report \"foo.dmp\" /machine"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildReportCrashWithEnclosedFilename) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  builder.set_crash_filename(_T("\"foo.dmp\""));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/report \"foo.dmp\""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildReportCrashWithCustomInfo) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  ExpectAsserts expect_asserts;  // Missing filename.
+  builder.set_custom_info_filename(_T("foo.txt"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildReportCrashWithFileanameWithCustomInfo) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  builder.set_crash_filename(_T("foo.dmp"));
+  builder.set_custom_info_filename(_T("foo.txt"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/report \"foo.dmp\" /custom_info_filename \"foo.txt\""),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildReportCrashWithFileanameWithCustomInfoMachine) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  builder.set_crash_filename(_T("foo.dmp"));
+  builder.set_custom_info_filename(_T("foo.txt"));
+  builder.set_is_machine_set(true);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(
+      _T("/report \"foo.dmp\" /machine /custom_info_filename \"foo.txt\""),
+      cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildReportCrashWithEnclosedFileanameWithCustomInfo) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  builder.set_crash_filename(_T("\"foo.dmp\""));
+  builder.set_custom_info_filename(_T("\"foo.txt\""));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/report \"foo.dmp\" /custom_info_filename \"foo.txt\""),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildReportCrashInteractiveWithFilename) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  builder.set_crash_filename(_T("foo.dmp"));
+  builder.set_is_interactive_set(true);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/report /i \"foo.dmp\""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildReportCrashMachineInteractiveWithFilename) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  builder.set_crash_filename(_T("foo.dmp"));
+  builder.set_is_machine_set(true);
+  builder.set_is_interactive_set(true);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/report /i \"foo.dmp\" /machine"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildInstall) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL);
+  ExpectAsserts expect_asserts;  // Missing parameters.
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildInstallWithExtraArgs) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/install \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\""),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildInstallWithExtraArgsSilent) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  builder.set_is_silent_set(true);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/install \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\" /silent"),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildUpdate) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UPDATE);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/update"), cmd_line);
+}
+
+// The /update builder works when not used with GoogleUpdate.exe.
+TEST(CommandLineBuilder, BuildUpdateAndGetCommandLineWithNonGoogleUpdateExe) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UPDATE);
+  CString cmd_line = builder.GetCommandLine(_T("C:\\GoogleUpdateSetup_en.exe"));
+  EXPECT_STREQ(_T("\"C:\\GoogleUpdateSetup_en.exe\" /update"), cmd_line);
+}
+
+// The /update builder should not be used with GoogleUpdate.exe directly.
+TEST(CommandLineBuilder, BuildUpdateAndGetCommandLineWithGoogleUpdateExe) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UPDATE);
+  ExpectAsserts expect_asserts;
+  CString cmd_line = builder.GetCommandLine(_T("C:\\GoogleUpdate.exe"));
+  EXPECT_STREQ(_T("\"C:\\GoogleUpdate.exe\" /update"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildLegacyManifestHandoff) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF);
+  ExpectAsserts expect_asserts;
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildLegacyManifestHandoffWithManifest) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF);
+  builder.set_legacy_manifest_path(_T("foo.gup"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/uiuser foo.gup"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildLegacyUi) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_LEGACYUI);
+  ExpectAsserts expect_asserts;  // Not a supported type to build.
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildComServer) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_COMSERVER);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("-Embedding"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildCodeRedCheck) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_CODE_RED_CHECK);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/cr"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildWebPlugin) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_WEBPLUGIN);
+  ExpectAsserts expect_asserts;
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildWebPluginWithUrlArgsAndInstallSource) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_WEBPLUGIN);
+  builder.set_webplugin_args(_T("piargs"));
+  builder.set_webplugin_url_domain(_T("http://www.google.com/"));
+  builder.set_install_source(_T("oneclick"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/pi \"http://www.google.com/\" \"piargs\"")
+               _T(" /installsource oneclick"),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildRecover) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_RECOVER);
+  ExpectAsserts expect_asserts;
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildRecoverWithMIPath) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_RECOVER);
+  builder.set_code_red_metainstaller_path(_T("foo.exe"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/recover foo.exe"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildUA) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UA);
+  ExpectAsserts expect_asserts;
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildUAWithInstallSource) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UA);
+  builder.set_install_source(_T("blah"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/ua /installsource blah"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildUAWithInstallSourceAndUninstall) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UA);
+  builder.set_install_source(_T("blah"));
+  builder.set_is_uninstall_set(true);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/ua /installsource blah /uninstall"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildUG) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UG);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/ug"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildUGWithMachine) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UG);
+  builder.set_is_machine_set(true);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/ug /machine"), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildHandoffInstall) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);
+  ExpectAsserts expect_asserts;  // Missing extra args.
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildHandoffInstallWithExtraArgs) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/handoff \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\""),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildHandoffInstallWithExtraArgsOffline) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  builder.set_install_source(_T("offline"));
+  builder.set_is_offline_set(true);
+
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/handoff \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")
+               _T(" /installsource offline")
+               _T(" /offlineinstall"),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildHandoffInstallWithExtraArgsSilentOffline) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  builder.set_install_source(_T("offline"));
+  builder.set_is_silent_set(true);
+  builder.set_is_offline_set(true);
+
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/handoff \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")
+               _T(" /installsource offline")
+               _T(" /silent /offlineinstall"),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildHandoffWithAppArgsSilentOffline) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  builder.set_app_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                       _T("installerdata=foobar%45"));
+  builder.set_install_source(_T("offline"));
+  builder.set_is_silent_set(true);
+  builder.set_is_offline_set(true);
+
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/handoff \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")
+               _T(" /appargs \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("installerdata=foobar%45\"")
+               _T(" /installsource offline")
+               _T(" /silent /offlineinstall"),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildHandoffWithAppArgsSilentOfflineEulaRequired) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  builder.set_app_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                       _T("installerdata=foobar%45"));
+  builder.set_install_source(_T("offline"));
+  builder.set_is_silent_set(true);
+  builder.set_is_eula_required_set(true);
+  builder.set_is_offline_set(true);
+
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/handoff \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")
+               _T(" /appargs \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("installerdata=foobar%45\"")
+               _T(" /installsource offline")
+               _T(" /silent /eularequired /offlineinstall"),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildIG) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_IG);
+  ExpectAsserts expect_asserts;
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T(""), cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildIGWithExtraArgs) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_IG);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/ig \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\""),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildIGWithExtraArgsOffline) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_IG);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  builder.set_install_source(_T("offline"));
+  builder.set_is_offline_set(true);
+
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/ig \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")
+               _T(" /installsource offline")
+               _T(" /offlineinstall"),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildIGWithExtraArgsOfflineSilent) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_IG);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  builder.set_install_source(_T("offline"));
+  builder.set_is_silent_set(true);
+  builder.set_is_offline_set(true);
+
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/ig \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")
+               _T(" /installsource offline")
+               _T(" /silent /offlineinstall"),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildIGWithAppArgsSilentOffline) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_IG);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  builder.set_app_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                       _T("installerdata=foobar%45"));
+  builder.set_install_source(_T("offline"));
+  builder.set_is_silent_set(true);
+  builder.set_is_offline_set(true);
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/ig \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")
+               _T(" /appargs \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("installerdata=foobar%45\"")
+               _T(" /installsource offline")
+               _T(" /silent /offlineinstall"),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildIGWithAppArgsSilentOfflineEulaRequired) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_IG);
+  builder.set_extra_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                         _T("appname=YouTubeUploader&needsadmin=False&")
+                         _T("lang=en"));
+  builder.set_app_args(_T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                       _T("installerdata=foobar%45"));
+  builder.set_install_source(_T("offline"));
+  builder.set_is_silent_set(true);
+  builder.set_is_eula_required_set(true);
+  builder.set_is_offline_set(true);
+
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/ig \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")
+               _T(" /appargs \"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+               _T("installerdata=foobar%45\"")
+               _T(" /installsource offline")
+               _T(" /silent /eularequired /offlineinstall"),
+               cmd_line);
+}
+TEST(CommandLineBuilder, BuildRegisterProduct) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_REGISTER_PRODUCT);
+  builder.set_extra_args(_T("appguid={7DD3DAE3-87F1-4CFE-8BF4-452C74421401}&")
+                         _T("appname=Google Toolbar&needsadmin=True&")
+                         _T("lang=en"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/registerproduct ")
+               _T("\"appguid={7DD3DAE3-87F1-4CFE-8BF4-452C74421401}&")
+               _T("appname=Google Toolbar&needsadmin=True&lang=en\""),
+               cmd_line);
+}
+
+TEST(CommandLineBuilder, BuildUnregisterProduc) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_UNREGISTER_PRODUCT);
+  builder.set_extra_args(_T("appguid={7DD3DAE3-87F1-4CFE-8BF4-452C74421401}&")
+                         _T("needsadmin=True&lang=en"));
+  CString cmd_line = builder.GetCommandLineArgs();
+  EXPECT_STREQ(_T("/unregisterproduct ")
+               _T("\"appguid={7DD3DAE3-87F1-4CFE-8BF4-452C74421401}&")
+               _T("needsadmin=True&lang=en\""),
+               cmd_line);
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/command_line_parser-internal.h b/goopdate/command_line_parser-internal.h
index ccddba9..5bdc9a6 100644
--- a/goopdate/command_line_parser-internal.h
+++ b/goopdate/command_line_parser-internal.h
@@ -1,77 +1,77 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_COMMAND_LINE_PARSER_INTERNAL_H_

-#define OMAHA_GOOPDATE_COMMAND_LINE_PARSER_INTERNAL_H_

-

-#include <windows.h>

-#include <map>

-#include <vector>

-

-namespace omaha {

-

-namespace internal {

-

-// Repository for switches and corresponding switch arguments for a command

-// line.

-class CommandLineParserArgs {

- public:

-  CommandLineParserArgs() {}

-  ~CommandLineParserArgs() {}

-

-  typedef std::vector<CString> StringVector;

-  typedef StringVector::const_iterator StringVectorIter;

-  typedef std::map<CString, StringVector > SwitchAndArgumentsMap;

-  typedef SwitchAndArgumentsMap::const_iterator SwitchAndArgumentsMapIter;

-

-  // Gets the number of switches in the parsed command line.  Will return 0 for

-  // count if a parse has not occurred.

-  int GetSwitchCount() const;

-

-  // Returns the switch at a particular index.

-  // This is meant for iteration only and is not guaranteed to be in the order

-  // of the switches in the parsed command line.

-  HRESULT GetSwitchNameAtIndex(int index, CString* switch_name) const;

-

-  // Returns true if a switch with the name switch_name is found.

-  bool HasSwitch(const CString& switch_name) const;

-

-  // Returns the number of arguments for switch_name.  Will fail if switch_name

-  // is not a valid switch.

-  HRESULT GetSwitchArgumentCount(const CString& switch_name, int* count) const;

-

-  // Returns the value of a switch argument at the specified offset.

-  // Fails if switch_name is not a valid switch.

-  HRESULT GetSwitchArgumentValue(const CString& switch_name,

-                                 int argument_index,

-                                 CString* argument_value) const;

-

-  void Reset();

-  HRESULT AddSwitch(const CString& switch_name);

-  HRESULT AddSwitchArgument(const CString& switch_name,

-                            const CString& argument_value);

-

- private:

-  SwitchAndArgumentsMap switch_arguments_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(CommandLineParserArgs);

-};

-

-}  // namespace internal

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_COMMAND_LINE_PARSER_INTERNAL_H_

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_COMMAND_LINE_PARSER_INTERNAL_H_
+#define OMAHA_GOOPDATE_COMMAND_LINE_PARSER_INTERNAL_H_
+
+#include <windows.h>
+#include <map>
+#include <vector>
+
+namespace omaha {
+
+namespace internal {
+
+// Repository for switches and corresponding switch arguments for a command
+// line.
+class CommandLineParserArgs {
+ public:
+  CommandLineParserArgs() {}
+  ~CommandLineParserArgs() {}
+
+  typedef std::vector<CString> StringVector;
+  typedef StringVector::const_iterator StringVectorIter;
+  typedef std::map<CString, StringVector > SwitchAndArgumentsMap;
+  typedef SwitchAndArgumentsMap::const_iterator SwitchAndArgumentsMapIter;
+
+  // Gets the number of switches in the parsed command line.  Will return 0 for
+  // count if a parse has not occurred.
+  int GetSwitchCount() const;
+
+  // Returns the switch at a particular index.
+  // This is meant for iteration only and is not guaranteed to be in the order
+  // of the switches in the parsed command line.
+  HRESULT GetSwitchNameAtIndex(int index, CString* switch_name) const;
+
+  // Returns true if a switch with the name switch_name is found.
+  bool HasSwitch(const CString& switch_name) const;
+
+  // Returns the number of arguments for switch_name.  Will fail if switch_name
+  // is not a valid switch.
+  HRESULT GetSwitchArgumentCount(const CString& switch_name, int* count) const;
+
+  // Returns the value of a switch argument at the specified offset.
+  // Fails if switch_name is not a valid switch.
+  HRESULT GetSwitchArgumentValue(const CString& switch_name,
+                                 int argument_index,
+                                 CString* argument_value) const;
+
+  void Reset();
+  HRESULT AddSwitch(const CString& switch_name);
+  HRESULT AddSwitchArgument(const CString& switch_name,
+                            const CString& argument_value);
+
+ private:
+  SwitchAndArgumentsMap switch_arguments_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(CommandLineParserArgs);
+};
+
+}  // namespace internal
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_COMMAND_LINE_PARSER_INTERNAL_H_
+
diff --git a/goopdate/command_line_parser.cc b/goopdate/command_line_parser.cc
index 1f6d3ca..66e9d3f 100644
--- a/goopdate/command_line_parser.cc
+++ b/goopdate/command_line_parser.cc
@@ -1,377 +1,377 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/command_line_parser.h"

-

-#include <shellapi.h>

-

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-

-namespace omaha {

-

-namespace internal {

-

-void CommandLineParserArgs::Reset() {

-  switch_arguments_.clear();

-}

-

-// Assumes switch_name is already lower case.

-HRESULT CommandLineParserArgs::AddSwitch(const CString& switch_name) {

-  ASSERT1(CString(switch_name).MakeLower().Compare(switch_name) == 0);

-  if (switch_arguments_.find(switch_name) != switch_arguments_.end()) {

-    return E_INVALIDARG;

-  }

-

-  StringVector string_vector;

-  switch_arguments_[switch_name] = string_vector;

-  return S_OK;

-}

-

-// Assumes switch_name is already lower case.

-HRESULT CommandLineParserArgs::AddSwitchArgument(const CString& switch_name,

-                                                 const CString& value) {

-  ASSERT1(CString(switch_name).MakeLower().Compare(switch_name) == 0);

-  ASSERT1(!switch_name.IsEmpty());

-  if (switch_name.IsEmpty()) {

-    // We don't have a switch yet, so this is just a base argument.

-    // Example command line:  "foo.exe myarg /someswitch"

-    // Here, myarg would be a base argument.

-    // TODO(omaha): base_args_.push_back(switch_name_str);

-    return E_INVALIDARG;

-  }

-

-  SwitchAndArgumentsMap::iterator iter = switch_arguments_.find(switch_name);

-  if (iter == switch_arguments_.end()) {

-    return E_UNEXPECTED;

-  }

-  (*iter).second.push_back(value);

-

-  return S_OK;

-}

-

-int CommandLineParserArgs::GetSwitchCount() const {

-  return switch_arguments_.size();

-}

-

-bool CommandLineParserArgs::HasSwitch(const CString& switch_name) const {

-  CString switch_name_lower = switch_name;

-  switch_name_lower.MakeLower();

-  return switch_arguments_.find(switch_name_lower) != switch_arguments_.end();

-}

-

-// The value at a particular index may change if switch_names are added

-// since we're using a map underneath.  But this keeps us from having to write

-// an interator and expose it externally.

-HRESULT CommandLineParserArgs::GetSwitchNameAtIndex(int index,

-                                                    CString* name) const {

-  ASSERT1(name);

-

-  if (index >= static_cast<int>(switch_arguments_.size())) {

-    return E_INVALIDARG;

-  }

-

-  SwitchAndArgumentsMapIter iter = switch_arguments_.begin();

-  for (int i = 0; i < index; ++i) {

-    ++iter;

-  }

-

-  *name = (*iter).first;

-

-  return S_OK;

-}

-

-HRESULT CommandLineParserArgs::GetSwitchArgumentCount(

-            const CString& switch_name, int* count) const {

-  ASSERT1(count);

-

-  CString switch_name_lower = switch_name;

-  switch_name_lower.MakeLower();

-

-  SwitchAndArgumentsMapIter iter = switch_arguments_.find(switch_name_lower);

-  if (iter == switch_arguments_.end()) {

-    return E_INVALIDARG;

-  }

-

-  *count = (*iter).second.size();

-  return S_OK;

-}

-

-HRESULT CommandLineParserArgs::GetSwitchArgumentValue(

-    const CString& switch_name,

-    int argument_index,

-    CString* argument_value) const {

-  ASSERT1(argument_value);

-

-  CString switch_name_lower = switch_name;

-  switch_name_lower.MakeLower();

-

-  int count = 0;

-  HRESULT hr = GetSwitchArgumentCount(switch_name_lower, &count);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (argument_index >= count) {

-    return E_INVALIDARG;

-  }

-

-  SwitchAndArgumentsMapIter iter = switch_arguments_.find(switch_name_lower);

-  if (iter == switch_arguments_.end()) {

-    return E_INVALIDARG;

-  }

-

-  *argument_value = (*iter).second[argument_index];

-  return S_OK;

-}

-

-}  // namespace internal

-

-CommandLineParser::CommandLineParser() {

-}

-

-CommandLineParser::~CommandLineParser() {

-}

-

-HRESULT CommandLineParser::ParseFromString(const wchar_t* command_line) {

-  CString command_line_str(command_line);

-  command_line_str.Trim(_T(" "));

-

-  int argc = 0;

-  wchar_t** argv = ::CommandLineToArgvW(command_line_str, &argc);

-  if (!argv) {

-    return HRESULTFromLastError();

-  }

-

-  HRESULT hr = ParseFromArgv(argc, argv);

-  ::LocalFree(argv);

-  return hr;

-}

-

-// TODO(Omaha): Move the rule parser into a separate class.

-// TODO(Omaha): Fail the regular command parser if [/ switch is passed.

-// ParseFromArgv parses either a rule or a command line.

-//

-// Rules have required and optional parameters. An example of a rule is:

-//     "gu.exe /install <extraargs> [/oem [/appargs <appargs> [/silent"

-// This creates a rule for a command line that requires "/install" for the rule

-// to match. The other parameters are optional, indicated by prefixes of "[/".

-//

-// Command lines do not use "[/", and use "/" for all parameters.

-// A command line that looks like this:

-//     "gu.exe /install <extraargs> /oem /appargs <appargs>"

-// will match the rule above.

-HRESULT CommandLineParser::ParseFromArgv(int argc, wchar_t** argv) {

-  if (argc == 0 || !argv) {

-    return E_INVALIDARG;

-  }

-

-  CORE_LOG(L5, (_T("[CommandLineParser::ParseFromArgv][argc=%d]"), argc));

-

-  Reset();

-

-  if (argc == 1) {

-    // We only have the program name.  So, we're done parsing.

-    ASSERT1(!IsSwitch(argv[0]));

-    return S_OK;

-  }

-

-  CString current_switch_name;

-  bool is_optional_switch = false;

-

-  // Start parsing at the first argument after the program name (index 1).

-  for (int i = 1; i < argc; ++i) {

-    HRESULT hr = S_OK;

-    CString token = argv[i];

-    token.Trim(_T(" "));

-    CORE_LOG(L5, (_T("[Parsing arg][i=%d][argv[i]=%s]"), i, token));

-    if (IsSwitch(token)) {

-      hr = StripSwitchNameFromArgv(token, &current_switch_name);

-      if (FAILED(hr)) {

-        return hr;

-      }

-      hr = AddSwitch(current_switch_name);

-      if (FAILED(hr)) {

-        CORE_LOG(LE, (_T("[AddSwitch failed][%s][0x%x]"),

-                      current_switch_name, hr));

-        return hr;

-      }

-      is_optional_switch = false;

-    } else if (IsOptionalSwitch(token)) {

-      hr = StripOptionalSwitchNameFromArgv(token, &current_switch_name);

-      if (FAILED(hr)) {

-        return hr;

-      }

-      hr = AddOptionalSwitch(current_switch_name);

-      if (FAILED(hr)) {

-        CORE_LOG(LE, (_T("[AddOptionalSwitch failed][%s][0x%x]"),

-                      current_switch_name, hr));

-        return hr;

-      }

-      is_optional_switch = true;

-    } else {

-      hr = is_optional_switch ?

-          AddOptionalSwitchArgument(current_switch_name, token) :

-          AddSwitchArgument(current_switch_name, token);

-

-      if (FAILED(hr)) {

-        CORE_LOG(LE, (_T("[Adding switch argument failed][%d][%s][%s][0x%x]"),

-                      is_optional_switch, current_switch_name, token, hr));

-        return hr;

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-bool CommandLineParser::IsSwitch(const CString& param) const {

-  // Switches must have a prefix (/) or (-), and at least one character.

-  if (param.GetLength() < 2) {

-    return false;

-  }

-

-  // All switches must start with / or -, and not contain any spaces.

-  // Since the argv parser strips out the enclosing quotes around an argument,

-  // we need to handle the following cases properly:

-  // * foo.exe /switch arg     -- /switch is a switch, arg is an arg

-  // * foo.exe /switch "/x y"  -- /switch is a switch, '/x y' is an arg and it

-  //   will get here _without_ the quotes.

-  // If param_str starts with / and contains no spaces, then it's a switch.

-  return ((param[0] == _T('/')) || (param[0] == _T('-'))) &&

-          (param.Find(_T(" ")) == -1) &&

-          (param.Find(_T("%20")) == -1);

-}

-

-bool CommandLineParser::IsOptionalSwitch(const CString& param) const {

-  // Optional switches must have a prefix ([/) or ([-), and at least one

-  // character.

-  return param[0] == _T('[') && IsSwitch(param.Right(param.GetLength() - 1));

-}

-

-HRESULT CommandLineParser::StripSwitchNameFromArgv(const CString& param,

-                                                   CString* switch_name) {

-  ASSERT1(switch_name);

-

-  if (!IsSwitch(param)) {

-    return E_INVALIDARG;

-  }

-

-  *switch_name = param.Right(param.GetLength() - 1);

-  switch_name->Trim(_T(" "));

-  switch_name->MakeLower();

-  return S_OK;

-}

-

-HRESULT CommandLineParser::StripOptionalSwitchNameFromArgv(const CString& param,

-                                                           CString* name) {

-  ASSERT1(name);

-

-  if (!IsOptionalSwitch(param)) {

-    return E_INVALIDARG;

-  }

-

-  return StripSwitchNameFromArgv(param.Right(param.GetLength() - 1), name);

-}

-

-void CommandLineParser::Reset() {

-  required_args_.Reset();

-  optional_args_.Reset();

-}

-

-HRESULT CommandLineParser::AddSwitch(const CString& switch_name) {

-  ASSERT1(switch_name == CString(switch_name).MakeLower());

-  return required_args_.AddSwitch(switch_name);

-}

-

-HRESULT CommandLineParser::AddSwitchArgument(const CString& switch_name,

-                                             const CString& argument_value) {

-  ASSERT1(switch_name == CString(switch_name).MakeLower());

-  return required_args_.AddSwitchArgument(switch_name, argument_value);

-}

-

-int CommandLineParser::GetSwitchCount() const {

-  return required_args_.GetSwitchCount();

-}

-

-bool CommandLineParser::HasSwitch(const CString& switch_name) const {

-  return required_args_.HasSwitch(switch_name);

-}

-

-// The value at a particular index may change if switch_names are added

-// since we're using a map underneath.  But this keeps us from having to write

-// an interator and expose it externally.

-HRESULT CommandLineParser::GetSwitchNameAtIndex(int index,

-                                                CString* switch_name) const {

-  return required_args_.GetSwitchNameAtIndex(index, switch_name);

-}

-

-HRESULT CommandLineParser::GetSwitchArgumentCount(const CString& switch_name,

-                                                  int* count) const {

-  return required_args_.GetSwitchArgumentCount(switch_name, count);

-}

-

-HRESULT CommandLineParser::GetSwitchArgumentValue(

-    const CString& switch_name,

-    int argument_index,

-    CString* argument_value) const {

-  return required_args_.GetSwitchArgumentValue(switch_name,

-                                               argument_index,

-                                               argument_value);

-}

-

-HRESULT CommandLineParser::AddOptionalSwitch(const CString& switch_name) {

-  ASSERT1(switch_name == CString(switch_name).MakeLower());

-  return optional_args_.AddSwitch(switch_name);

-}

-

-HRESULT CommandLineParser::AddOptionalSwitchArgument(const CString& switch_name,

-                                                     const CString& value) {

-  ASSERT1(switch_name == CString(switch_name).MakeLower());

-  return optional_args_.AddSwitchArgument(switch_name, value);

-}

-

-int CommandLineParser::GetOptionalSwitchCount() const {

-  return optional_args_.GetSwitchCount();

-}

-

-bool CommandLineParser::HasOptionalSwitch(const CString& switch_name) const {

-  return optional_args_.HasSwitch(switch_name);

-}

-

-// The value at a particular index may change if switch_names are added

-// since we're using a map underneath.  But this keeps us from having to write

-// an interator and expose it externally.

-HRESULT CommandLineParser::GetOptionalSwitchNameAtIndex(int index,

-                                                        CString* name) const {

-  return optional_args_.GetSwitchNameAtIndex(index, name);

-}

-

-HRESULT CommandLineParser::GetOptionalSwitchArgumentCount(const CString& name,

-                                                          int* count) const {

-  return optional_args_.GetSwitchArgumentCount(name, count);

-}

-

-HRESULT CommandLineParser::GetOptionalSwitchArgumentValue(const CString& name,

-                                                          int argument_index,

-                                                          CString* val) const {

-  return optional_args_.GetSwitchArgumentValue(name,

-                                               argument_index,

-                                               val);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/command_line_parser.h"
+
+#include <shellapi.h>
+
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+
+namespace omaha {
+
+namespace internal {
+
+void CommandLineParserArgs::Reset() {
+  switch_arguments_.clear();
+}
+
+// Assumes switch_name is already lower case.
+HRESULT CommandLineParserArgs::AddSwitch(const CString& switch_name) {
+  ASSERT1(CString(switch_name).MakeLower().Compare(switch_name) == 0);
+  if (switch_arguments_.find(switch_name) != switch_arguments_.end()) {
+    return E_INVALIDARG;
+  }
+
+  StringVector string_vector;
+  switch_arguments_[switch_name] = string_vector;
+  return S_OK;
+}
+
+// Assumes switch_name is already lower case.
+HRESULT CommandLineParserArgs::AddSwitchArgument(const CString& switch_name,
+                                                 const CString& value) {
+  ASSERT1(CString(switch_name).MakeLower().Compare(switch_name) == 0);
+  ASSERT1(!switch_name.IsEmpty());
+  if (switch_name.IsEmpty()) {
+    // We don't have a switch yet, so this is just a base argument.
+    // Example command line:  "foo.exe myarg /someswitch"
+    // Here, myarg would be a base argument.
+    // TODO(omaha): base_args_.push_back(switch_name_str);
+    return E_INVALIDARG;
+  }
+
+  SwitchAndArgumentsMap::iterator iter = switch_arguments_.find(switch_name);
+  if (iter == switch_arguments_.end()) {
+    return E_UNEXPECTED;
+  }
+  (*iter).second.push_back(value);
+
+  return S_OK;
+}
+
+int CommandLineParserArgs::GetSwitchCount() const {
+  return switch_arguments_.size();
+}
+
+bool CommandLineParserArgs::HasSwitch(const CString& switch_name) const {
+  CString switch_name_lower = switch_name;
+  switch_name_lower.MakeLower();
+  return switch_arguments_.find(switch_name_lower) != switch_arguments_.end();
+}
+
+// The value at a particular index may change if switch_names are added
+// since we're using a map underneath.  But this keeps us from having to write
+// an interator and expose it externally.
+HRESULT CommandLineParserArgs::GetSwitchNameAtIndex(int index,
+                                                    CString* name) const {
+  ASSERT1(name);
+
+  if (index >= static_cast<int>(switch_arguments_.size())) {
+    return E_INVALIDARG;
+  }
+
+  SwitchAndArgumentsMapIter iter = switch_arguments_.begin();
+  for (int i = 0; i < index; ++i) {
+    ++iter;
+  }
+
+  *name = (*iter).first;
+
+  return S_OK;
+}
+
+HRESULT CommandLineParserArgs::GetSwitchArgumentCount(
+            const CString& switch_name, int* count) const {
+  ASSERT1(count);
+
+  CString switch_name_lower = switch_name;
+  switch_name_lower.MakeLower();
+
+  SwitchAndArgumentsMapIter iter = switch_arguments_.find(switch_name_lower);
+  if (iter == switch_arguments_.end()) {
+    return E_INVALIDARG;
+  }
+
+  *count = (*iter).second.size();
+  return S_OK;
+}
+
+HRESULT CommandLineParserArgs::GetSwitchArgumentValue(
+    const CString& switch_name,
+    int argument_index,
+    CString* argument_value) const {
+  ASSERT1(argument_value);
+
+  CString switch_name_lower = switch_name;
+  switch_name_lower.MakeLower();
+
+  int count = 0;
+  HRESULT hr = GetSwitchArgumentCount(switch_name_lower, &count);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (argument_index >= count) {
+    return E_INVALIDARG;
+  }
+
+  SwitchAndArgumentsMapIter iter = switch_arguments_.find(switch_name_lower);
+  if (iter == switch_arguments_.end()) {
+    return E_INVALIDARG;
+  }
+
+  *argument_value = (*iter).second[argument_index];
+  return S_OK;
+}
+
+}  // namespace internal
+
+CommandLineParser::CommandLineParser() {
+}
+
+CommandLineParser::~CommandLineParser() {
+}
+
+HRESULT CommandLineParser::ParseFromString(const wchar_t* command_line) {
+  CString command_line_str(command_line);
+  command_line_str.Trim(_T(" "));
+
+  int argc = 0;
+  wchar_t** argv = ::CommandLineToArgvW(command_line_str, &argc);
+  if (!argv) {
+    return HRESULTFromLastError();
+  }
+
+  HRESULT hr = ParseFromArgv(argc, argv);
+  ::LocalFree(argv);
+  return hr;
+}
+
+// TODO(Omaha): Move the rule parser into a separate class.
+// TODO(Omaha): Fail the regular command parser if [/ switch is passed.
+// ParseFromArgv parses either a rule or a command line.
+//
+// Rules have required and optional parameters. An example of a rule is:
+//     "gu.exe /install <extraargs> [/oem [/appargs <appargs> [/silent"
+// This creates a rule for a command line that requires "/install" for the rule
+// to match. The other parameters are optional, indicated by prefixes of "[/".
+//
+// Command lines do not use "[/", and use "/" for all parameters.
+// A command line that looks like this:
+//     "gu.exe /install <extraargs> /oem /appargs <appargs>"
+// will match the rule above.
+HRESULT CommandLineParser::ParseFromArgv(int argc, wchar_t** argv) {
+  if (argc == 0 || !argv) {
+    return E_INVALIDARG;
+  }
+
+  CORE_LOG(L5, (_T("[CommandLineParser::ParseFromArgv][argc=%d]"), argc));
+
+  Reset();
+
+  if (argc == 1) {
+    // We only have the program name.  So, we're done parsing.
+    ASSERT1(!IsSwitch(argv[0]));
+    return S_OK;
+  }
+
+  CString current_switch_name;
+  bool is_optional_switch = false;
+
+  // Start parsing at the first argument after the program name (index 1).
+  for (int i = 1; i < argc; ++i) {
+    HRESULT hr = S_OK;
+    CString token = argv[i];
+    token.Trim(_T(" "));
+    CORE_LOG(L5, (_T("[Parsing arg][i=%d][argv[i]=%s]"), i, token));
+    if (IsSwitch(token)) {
+      hr = StripSwitchNameFromArgv(token, &current_switch_name);
+      if (FAILED(hr)) {
+        return hr;
+      }
+      hr = AddSwitch(current_switch_name);
+      if (FAILED(hr)) {
+        CORE_LOG(LE, (_T("[AddSwitch failed][%s][0x%x]"),
+                      current_switch_name, hr));
+        return hr;
+      }
+      is_optional_switch = false;
+    } else if (IsOptionalSwitch(token)) {
+      hr = StripOptionalSwitchNameFromArgv(token, &current_switch_name);
+      if (FAILED(hr)) {
+        return hr;
+      }
+      hr = AddOptionalSwitch(current_switch_name);
+      if (FAILED(hr)) {
+        CORE_LOG(LE, (_T("[AddOptionalSwitch failed][%s][0x%x]"),
+                      current_switch_name, hr));
+        return hr;
+      }
+      is_optional_switch = true;
+    } else {
+      hr = is_optional_switch ?
+          AddOptionalSwitchArgument(current_switch_name, token) :
+          AddSwitchArgument(current_switch_name, token);
+
+      if (FAILED(hr)) {
+        CORE_LOG(LE, (_T("[Adding switch argument failed][%d][%s][%s][0x%x]"),
+                      is_optional_switch, current_switch_name, token, hr));
+        return hr;
+      }
+    }
+  }
+
+  return S_OK;
+}
+
+bool CommandLineParser::IsSwitch(const CString& param) const {
+  // Switches must have a prefix (/) or (-), and at least one character.
+  if (param.GetLength() < 2) {
+    return false;
+  }
+
+  // All switches must start with / or -, and not contain any spaces.
+  // Since the argv parser strips out the enclosing quotes around an argument,
+  // we need to handle the following cases properly:
+  // * foo.exe /switch arg     -- /switch is a switch, arg is an arg
+  // * foo.exe /switch "/x y"  -- /switch is a switch, '/x y' is an arg and it
+  //   will get here _without_ the quotes.
+  // If param_str starts with / and contains no spaces, then it's a switch.
+  return ((param[0] == _T('/')) || (param[0] == _T('-'))) &&
+          (param.Find(_T(" ")) == -1) &&
+          (param.Find(_T("%20")) == -1);
+}
+
+bool CommandLineParser::IsOptionalSwitch(const CString& param) const {
+  // Optional switches must have a prefix ([/) or ([-), and at least one
+  // character.
+  return param[0] == _T('[') && IsSwitch(param.Right(param.GetLength() - 1));
+}
+
+HRESULT CommandLineParser::StripSwitchNameFromArgv(const CString& param,
+                                                   CString* switch_name) {
+  ASSERT1(switch_name);
+
+  if (!IsSwitch(param)) {
+    return E_INVALIDARG;
+  }
+
+  *switch_name = param.Right(param.GetLength() - 1);
+  switch_name->Trim(_T(" "));
+  switch_name->MakeLower();
+  return S_OK;
+}
+
+HRESULT CommandLineParser::StripOptionalSwitchNameFromArgv(const CString& param,
+                                                           CString* name) {
+  ASSERT1(name);
+
+  if (!IsOptionalSwitch(param)) {
+    return E_INVALIDARG;
+  }
+
+  return StripSwitchNameFromArgv(param.Right(param.GetLength() - 1), name);
+}
+
+void CommandLineParser::Reset() {
+  required_args_.Reset();
+  optional_args_.Reset();
+}
+
+HRESULT CommandLineParser::AddSwitch(const CString& switch_name) {
+  ASSERT1(switch_name == CString(switch_name).MakeLower());
+  return required_args_.AddSwitch(switch_name);
+}
+
+HRESULT CommandLineParser::AddSwitchArgument(const CString& switch_name,
+                                             const CString& argument_value) {
+  ASSERT1(switch_name == CString(switch_name).MakeLower());
+  return required_args_.AddSwitchArgument(switch_name, argument_value);
+}
+
+int CommandLineParser::GetSwitchCount() const {
+  return required_args_.GetSwitchCount();
+}
+
+bool CommandLineParser::HasSwitch(const CString& switch_name) const {
+  return required_args_.HasSwitch(switch_name);
+}
+
+// The value at a particular index may change if switch_names are added
+// since we're using a map underneath.  But this keeps us from having to write
+// an interator and expose it externally.
+HRESULT CommandLineParser::GetSwitchNameAtIndex(int index,
+                                                CString* switch_name) const {
+  return required_args_.GetSwitchNameAtIndex(index, switch_name);
+}
+
+HRESULT CommandLineParser::GetSwitchArgumentCount(const CString& switch_name,
+                                                  int* count) const {
+  return required_args_.GetSwitchArgumentCount(switch_name, count);
+}
+
+HRESULT CommandLineParser::GetSwitchArgumentValue(
+    const CString& switch_name,
+    int argument_index,
+    CString* argument_value) const {
+  return required_args_.GetSwitchArgumentValue(switch_name,
+                                               argument_index,
+                                               argument_value);
+}
+
+HRESULT CommandLineParser::AddOptionalSwitch(const CString& switch_name) {
+  ASSERT1(switch_name == CString(switch_name).MakeLower());
+  return optional_args_.AddSwitch(switch_name);
+}
+
+HRESULT CommandLineParser::AddOptionalSwitchArgument(const CString& switch_name,
+                                                     const CString& value) {
+  ASSERT1(switch_name == CString(switch_name).MakeLower());
+  return optional_args_.AddSwitchArgument(switch_name, value);
+}
+
+int CommandLineParser::GetOptionalSwitchCount() const {
+  return optional_args_.GetSwitchCount();
+}
+
+bool CommandLineParser::HasOptionalSwitch(const CString& switch_name) const {
+  return optional_args_.HasSwitch(switch_name);
+}
+
+// The value at a particular index may change if switch_names are added
+// since we're using a map underneath.  But this keeps us from having to write
+// an interator and expose it externally.
+HRESULT CommandLineParser::GetOptionalSwitchNameAtIndex(int index,
+                                                        CString* name) const {
+  return optional_args_.GetSwitchNameAtIndex(index, name);
+}
+
+HRESULT CommandLineParser::GetOptionalSwitchArgumentCount(const CString& name,
+                                                          int* count) const {
+  return optional_args_.GetSwitchArgumentCount(name, count);
+}
+
+HRESULT CommandLineParser::GetOptionalSwitchArgumentValue(const CString& name,
+                                                          int argument_index,
+                                                          CString* val) const {
+  return optional_args_.GetSwitchArgumentValue(name,
+                                               argument_index,
+                                               val);
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/command_line_parser.h b/goopdate/command_line_parser.h
index 342cf2a..196d5af 100644
--- a/goopdate/command_line_parser.h
+++ b/goopdate/command_line_parser.h
@@ -1,109 +1,109 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_COMMAND_LINE_PARSER_H__

-#define OMAHA_GOOPDATE_COMMAND_LINE_PARSER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-

-#include <map>

-#include <vector>

-

-#include "base/basictypes.h"

-#include "goopdate/command_line_parser-internal.h"

-

-namespace omaha {

-

-// This class will parse a command line either from a string or in argc/argv

-// format.  It then provides information about the parsed command line.

-// When passing the string, make sure it includes the program name as the first

-// argument.

-// A "switch" is an argument preceded by "/".  Each switch can take 0..n

-// arguments.

-// Example:  foo.exe /sw a "b b" /sw2 /sw3

-// * foo.exe is the program name

-// * sw, sw2, and sw3 are switches.

-// * a and 'b b' (without the quotes) are the arguments to the sw switch.

-// * sw has 2 arguments and sw2 and sw3 have no arguments.

-class CommandLineParser {

- public:

-  CommandLineParser();

-  ~CommandLineParser();

-

-  // Parses the command line from a string.  Must include the program name (e.g.

-  // foo.exe) as the first value in the command line.

-  HRESULT ParseFromString(const wchar_t* command_line);

-

-  // Parses the command line form argc/argv syntax.  Makes the assumption that

-  // argv[0] is the program name (e.g. foo.exe).

-  HRESULT ParseFromArgv(int argc, wchar_t** argv);

-

-  // TODO(Omaha): Name these methods "Required".

-  // Gets the number of required switches in the parsed command line.

-  int GetSwitchCount() const;

-

-  // Returns the required switch at a particular index.

-  HRESULT GetSwitchNameAtIndex(int index, CString* switch_name) const;

-

-  // Returns true if a required switch with the name switch_name is found.

-  bool HasSwitch(const CString& switch_name) const;

-

-  // Returns the number of required arguments for required switch switch_name.

-  HRESULT GetSwitchArgumentCount(const CString& switch_name,

-                                 int* count) const;

-

-  // Returns the value of a required switch argument at the specified offset.

-  HRESULT GetSwitchArgumentValue(const CString& switch_name,

-                                 int argument_index,

-                                 CString* argument_value) const;

-

-  // Functions that have the same functionality as the above functions,

-  // except they operate on the optional switches.

-  int GetOptionalSwitchCount() const;

-  bool HasOptionalSwitch(const CString& switch_name) const;

-  HRESULT GetOptionalSwitchNameAtIndex(int index, CString* switch_name) const;

-  HRESULT GetOptionalSwitchArgumentCount(const CString& switch_name,

-                                         int* count) const;

-  HRESULT GetOptionalSwitchArgumentValue(

-      const CString& switch_name,

-      int argument_index,

-      CString* argument_value) const;

-

- private:

-  bool IsSwitch(const CString& param) const;

-  HRESULT StripSwitchNameFromArgv(const CString& param, CString* switch_name);

-  bool IsOptionalSwitch(const CString& param) const;

-  HRESULT StripOptionalSwitchNameFromArgv(const CString& param, CString* name);

-

-  void Reset();

-

-  HRESULT AddSwitch(const CString& switch_name);

-  HRESULT AddSwitchArgument(const CString& switch_name,

-                            const CString& argument_value);

-  HRESULT AddOptionalSwitch(const CString& switch_name);

-  HRESULT AddOptionalSwitchArgument(const CString& switch_name,

-                                    const CString& argument_value);

-

-  internal::CommandLineParserArgs required_args_;

-  internal::CommandLineParserArgs optional_args_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(CommandLineParser);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_COMMAND_LINE_PARSER_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_COMMAND_LINE_PARSER_H__
+#define OMAHA_GOOPDATE_COMMAND_LINE_PARSER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+
+#include <map>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "goopdate/command_line_parser-internal.h"
+
+namespace omaha {
+
+// This class will parse a command line either from a string or in argc/argv
+// format.  It then provides information about the parsed command line.
+// When passing the string, make sure it includes the program name as the first
+// argument.
+// A "switch" is an argument preceded by "/".  Each switch can take 0..n
+// arguments.
+// Example:  foo.exe /sw a "b b" /sw2 /sw3
+// * foo.exe is the program name
+// * sw, sw2, and sw3 are switches.
+// * a and 'b b' (without the quotes) are the arguments to the sw switch.
+// * sw has 2 arguments and sw2 and sw3 have no arguments.
+class CommandLineParser {
+ public:
+  CommandLineParser();
+  ~CommandLineParser();
+
+  // Parses the command line from a string.  Must include the program name (e.g.
+  // foo.exe) as the first value in the command line.
+  HRESULT ParseFromString(const wchar_t* command_line);
+
+  // Parses the command line form argc/argv syntax.  Makes the assumption that
+  // argv[0] is the program name (e.g. foo.exe).
+  HRESULT ParseFromArgv(int argc, wchar_t** argv);
+
+  // TODO(Omaha): Name these methods "Required".
+  // Gets the number of required switches in the parsed command line.
+  int GetSwitchCount() const;
+
+  // Returns the required switch at a particular index.
+  HRESULT GetSwitchNameAtIndex(int index, CString* switch_name) const;
+
+  // Returns true if a required switch with the name switch_name is found.
+  bool HasSwitch(const CString& switch_name) const;
+
+  // Returns the number of required arguments for required switch switch_name.
+  HRESULT GetSwitchArgumentCount(const CString& switch_name,
+                                 int* count) const;
+
+  // Returns the value of a required switch argument at the specified offset.
+  HRESULT GetSwitchArgumentValue(const CString& switch_name,
+                                 int argument_index,
+                                 CString* argument_value) const;
+
+  // Functions that have the same functionality as the above functions,
+  // except they operate on the optional switches.
+  int GetOptionalSwitchCount() const;
+  bool HasOptionalSwitch(const CString& switch_name) const;
+  HRESULT GetOptionalSwitchNameAtIndex(int index, CString* switch_name) const;
+  HRESULT GetOptionalSwitchArgumentCount(const CString& switch_name,
+                                         int* count) const;
+  HRESULT GetOptionalSwitchArgumentValue(
+      const CString& switch_name,
+      int argument_index,
+      CString* argument_value) const;
+
+ private:
+  bool IsSwitch(const CString& param) const;
+  HRESULT StripSwitchNameFromArgv(const CString& param, CString* switch_name);
+  bool IsOptionalSwitch(const CString& param) const;
+  HRESULT StripOptionalSwitchNameFromArgv(const CString& param, CString* name);
+
+  void Reset();
+
+  HRESULT AddSwitch(const CString& switch_name);
+  HRESULT AddSwitchArgument(const CString& switch_name,
+                            const CString& argument_value);
+  HRESULT AddOptionalSwitch(const CString& switch_name);
+  HRESULT AddOptionalSwitchArgument(const CString& switch_name,
+                                    const CString& argument_value);
+
+  internal::CommandLineParserArgs required_args_;
+  internal::CommandLineParserArgs optional_args_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(CommandLineParser);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_COMMAND_LINE_PARSER_H__
+
diff --git a/goopdate/command_line_parser_unittest.cc b/goopdate/command_line_parser_unittest.cc
index a8d876e..be730e9 100644
--- a/goopdate/command_line_parser_unittest.cc
+++ b/goopdate/command_line_parser_unittest.cc
@@ -1,161 +1,161 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/command_line_parser.h"

-

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// This will succeed since the CommandLineToArgvW function returns the

-// path to the current executable file if it's passed the empty string.

-TEST(CommandLineParserTest, ParseNullString) {

-  CommandLineParser parser;

-  EXPECT_SUCCEEDED(parser.ParseFromString(NULL));

-  EXPECT_EQ(0, parser.GetSwitchCount());

-}

-

-// This will succeed since the CommandLineToArgvW function returns the

-// path to the current executable file if it's passed the empty string.

-TEST(CommandLineParserTest, ParseEmptyString) {

-  CommandLineParser parser;

-  EXPECT_SUCCEEDED(parser.ParseFromString(_T("")));

-  EXPECT_EQ(0, parser.GetSwitchCount());

-}

-

-// This will succeed since the CommandLineToArgvW function returns the

-// path to the current executable file if it's passed the empty string.

-TEST(CommandLineParserTest, ParseSpacesOnlyString) {

-  CommandLineParser parser;

-  EXPECT_SUCCEEDED(parser.ParseFromString(_T("    ")));

-}

-

-TEST(CommandLineParserTest, ParseNullArgv) {

-  CommandLineParser parser;

-  EXPECT_FAILED(parser.ParseFromArgv(0, NULL));

-}

-

-TEST(CommandLineParserTest, CallFunctionsBeforeParse) {

-  CommandLineParser parser;

-  int arg_count = 0;

-  CString arg_value;

-  EXPECT_FALSE(parser.HasSwitch(_T("foo")));

-  EXPECT_EQ(0, parser.GetSwitchCount());

-  EXPECT_FAILED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));

-  EXPECT_FAILED(parser.GetSwitchArgumentValue(_T("foo"), 0, &arg_value));

-}

-

-TEST(CommandLineParserTest, ParseProgramNameOnly) {

-  CommandLineParser parser;

-  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe")));

-  EXPECT_EQ(0, parser.GetSwitchCount());

-}

-

-TEST(CommandLineParserTest, ValidateSwitchMixedCase) {

-  CommandLineParser parser;

-  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /FooP")));

-  EXPECT_EQ(1, parser.GetSwitchCount());

-  EXPECT_TRUE(parser.HasSwitch(_T("foop")));

-  EXPECT_TRUE(parser.HasSwitch(_T("FooP")));

-  EXPECT_TRUE(parser.HasSwitch(_T("fOOp")));

-  EXPECT_TRUE(parser.HasSwitch(_T("FOOP")));

-  EXPECT_FALSE(parser.HasSwitch(_T("blAH")));

-}

-

-TEST(CommandLineParserTest, ParseOneSwitchNoArgs) {

-  CommandLineParser parser;

-  int arg_count = 0;

-  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /foo")));

-  EXPECT_EQ(1, parser.GetSwitchCount());

-  EXPECT_TRUE(parser.HasSwitch(_T("foo")));

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));

-  EXPECT_EQ(0, arg_count);

-}

-

-TEST(CommandLineParserTest, ParseOneSwitchOneArg) {

-  CommandLineParser parser;

-  int arg_count = 0;

-  CString arg_value;

-  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /foo bar")));

-  EXPECT_EQ(1, parser.GetSwitchCount());

-  EXPECT_TRUE(parser.HasSwitch(_T("foo")));

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));

-  EXPECT_EQ(1, arg_count);

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("foo"), 0, &arg_value));

-  EXPECT_STREQ(_T("bar"), arg_value);

-}

-

-TEST(CommandLineParserTest, ParseOneSwitchTwoArgs) {

-  CommandLineParser parser;

-  int arg_count = 0;

-  CString arg_value;

-  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /foo bar baz")));

-  EXPECT_EQ(1, parser.GetSwitchCount());

-  EXPECT_TRUE(parser.HasSwitch(_T("foo")));

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));

-  EXPECT_EQ(2, arg_count);

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("foo"), 0, &arg_value));

-  EXPECT_STREQ(_T("bar"), arg_value);

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("foo"), 1, &arg_value));

-  EXPECT_STREQ(_T("baz"), arg_value);

-}

-

-TEST(CommandLineParserTest, ParseTwoSwitchesNoArgs) {

-  CommandLineParser parser;

-  int arg_count = 0;

-  CString arg_value;

-  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /foo /bar")));

-  EXPECT_EQ(2, parser.GetSwitchCount());

-  EXPECT_TRUE(parser.HasSwitch(_T("foo")));

-  EXPECT_TRUE(parser.HasSwitch(_T("bar")));

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));

-  EXPECT_EQ(0, arg_count);

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("bar"), &arg_count));

-  EXPECT_EQ(0, arg_count);

-}

-

-TEST(CommandLineParserTest, ParseTwoSwitchesOneArgNoArg) {

-  CommandLineParser parser;

-  int arg_count = 0;

-  CString arg_value;

-  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /foo blech /bar")));

-  EXPECT_EQ(2, parser.GetSwitchCount());

-  EXPECT_TRUE(parser.HasSwitch(_T("foo")));

-  EXPECT_TRUE(parser.HasSwitch(_T("bar")));

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));

-  EXPECT_EQ(1, arg_count);

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("foo"), 0, &arg_value));

-  EXPECT_STREQ(_T("blech"), arg_value);

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("bar"), &arg_count));

-  EXPECT_EQ(0, arg_count);

-}

-

-TEST(CommandLineParserTest, ParseArgInQuotesWithLeadingSlash) {

-  CommandLineParser parser;

-  int arg_count = 0;

-  CString arg_value;

-  EXPECT_SUCCEEDED(parser.ParseFromString(_T("f.exe /pi \"arg\" \"/sw x\"")));

-  EXPECT_EQ(1, parser.GetSwitchCount());

-  EXPECT_TRUE(parser.HasSwitch(_T("pi")));

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("pi"), &arg_count));

-  EXPECT_EQ(2, arg_count);

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("pi"), 0, &arg_value));

-  EXPECT_STREQ(_T("arg"), arg_value);

-  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("pi"), 1, &arg_value));

-  EXPECT_STREQ(_T("/sw x"), arg_value);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/command_line_parser.h"
+
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// This will succeed since the CommandLineToArgvW function returns the
+// path to the current executable file if it's passed the empty string.
+TEST(CommandLineParserTest, ParseNullString) {
+  CommandLineParser parser;
+  EXPECT_SUCCEEDED(parser.ParseFromString(NULL));
+  EXPECT_EQ(0, parser.GetSwitchCount());
+}
+
+// This will succeed since the CommandLineToArgvW function returns the
+// path to the current executable file if it's passed the empty string.
+TEST(CommandLineParserTest, ParseEmptyString) {
+  CommandLineParser parser;
+  EXPECT_SUCCEEDED(parser.ParseFromString(_T("")));
+  EXPECT_EQ(0, parser.GetSwitchCount());
+}
+
+// This will succeed since the CommandLineToArgvW function returns the
+// path to the current executable file if it's passed the empty string.
+TEST(CommandLineParserTest, ParseSpacesOnlyString) {
+  CommandLineParser parser;
+  EXPECT_SUCCEEDED(parser.ParseFromString(_T("    ")));
+}
+
+TEST(CommandLineParserTest, ParseNullArgv) {
+  CommandLineParser parser;
+  EXPECT_FAILED(parser.ParseFromArgv(0, NULL));
+}
+
+TEST(CommandLineParserTest, CallFunctionsBeforeParse) {
+  CommandLineParser parser;
+  int arg_count = 0;
+  CString arg_value;
+  EXPECT_FALSE(parser.HasSwitch(_T("foo")));
+  EXPECT_EQ(0, parser.GetSwitchCount());
+  EXPECT_FAILED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));
+  EXPECT_FAILED(parser.GetSwitchArgumentValue(_T("foo"), 0, &arg_value));
+}
+
+TEST(CommandLineParserTest, ParseProgramNameOnly) {
+  CommandLineParser parser;
+  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe")));
+  EXPECT_EQ(0, parser.GetSwitchCount());
+}
+
+TEST(CommandLineParserTest, ValidateSwitchMixedCase) {
+  CommandLineParser parser;
+  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /FooP")));
+  EXPECT_EQ(1, parser.GetSwitchCount());
+  EXPECT_TRUE(parser.HasSwitch(_T("foop")));
+  EXPECT_TRUE(parser.HasSwitch(_T("FooP")));
+  EXPECT_TRUE(parser.HasSwitch(_T("fOOp")));
+  EXPECT_TRUE(parser.HasSwitch(_T("FOOP")));
+  EXPECT_FALSE(parser.HasSwitch(_T("blAH")));
+}
+
+TEST(CommandLineParserTest, ParseOneSwitchNoArgs) {
+  CommandLineParser parser;
+  int arg_count = 0;
+  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /foo")));
+  EXPECT_EQ(1, parser.GetSwitchCount());
+  EXPECT_TRUE(parser.HasSwitch(_T("foo")));
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));
+  EXPECT_EQ(0, arg_count);
+}
+
+TEST(CommandLineParserTest, ParseOneSwitchOneArg) {
+  CommandLineParser parser;
+  int arg_count = 0;
+  CString arg_value;
+  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /foo bar")));
+  EXPECT_EQ(1, parser.GetSwitchCount());
+  EXPECT_TRUE(parser.HasSwitch(_T("foo")));
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));
+  EXPECT_EQ(1, arg_count);
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("foo"), 0, &arg_value));
+  EXPECT_STREQ(_T("bar"), arg_value);
+}
+
+TEST(CommandLineParserTest, ParseOneSwitchTwoArgs) {
+  CommandLineParser parser;
+  int arg_count = 0;
+  CString arg_value;
+  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /foo bar baz")));
+  EXPECT_EQ(1, parser.GetSwitchCount());
+  EXPECT_TRUE(parser.HasSwitch(_T("foo")));
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));
+  EXPECT_EQ(2, arg_count);
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("foo"), 0, &arg_value));
+  EXPECT_STREQ(_T("bar"), arg_value);
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("foo"), 1, &arg_value));
+  EXPECT_STREQ(_T("baz"), arg_value);
+}
+
+TEST(CommandLineParserTest, ParseTwoSwitchesNoArgs) {
+  CommandLineParser parser;
+  int arg_count = 0;
+  CString arg_value;
+  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /foo /bar")));
+  EXPECT_EQ(2, parser.GetSwitchCount());
+  EXPECT_TRUE(parser.HasSwitch(_T("foo")));
+  EXPECT_TRUE(parser.HasSwitch(_T("bar")));
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));
+  EXPECT_EQ(0, arg_count);
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("bar"), &arg_count));
+  EXPECT_EQ(0, arg_count);
+}
+
+TEST(CommandLineParserTest, ParseTwoSwitchesOneArgNoArg) {
+  CommandLineParser parser;
+  int arg_count = 0;
+  CString arg_value;
+  EXPECT_SUCCEEDED(parser.ParseFromString(_T("myprog.exe /foo blech /bar")));
+  EXPECT_EQ(2, parser.GetSwitchCount());
+  EXPECT_TRUE(parser.HasSwitch(_T("foo")));
+  EXPECT_TRUE(parser.HasSwitch(_T("bar")));
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("foo"), &arg_count));
+  EXPECT_EQ(1, arg_count);
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("foo"), 0, &arg_value));
+  EXPECT_STREQ(_T("blech"), arg_value);
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("bar"), &arg_count));
+  EXPECT_EQ(0, arg_count);
+}
+
+TEST(CommandLineParserTest, ParseArgInQuotesWithLeadingSlash) {
+  CommandLineParser parser;
+  int arg_count = 0;
+  CString arg_value;
+  EXPECT_SUCCEEDED(parser.ParseFromString(_T("f.exe /pi \"arg\" \"/sw x\"")));
+  EXPECT_EQ(1, parser.GetSwitchCount());
+  EXPECT_TRUE(parser.HasSwitch(_T("pi")));
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentCount(_T("pi"), &arg_count));
+  EXPECT_EQ(2, arg_count);
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("pi"), 0, &arg_value));
+  EXPECT_STREQ(_T("arg"), arg_value);
+  EXPECT_SUCCEEDED(parser.GetSwitchArgumentValue(_T("pi"), 1, &arg_value));
+  EXPECT_STREQ(_T("/sw x"), arg_value);
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/command_line_unittest.cc b/goopdate/command_line_unittest.cc
index 6cddbd5..eb5ddf0 100644
--- a/goopdate/command_line_unittest.cc
+++ b/goopdate/command_line_unittest.cc
@@ -1,1315 +1,1315 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/error.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/net/http_client.h"

-#include "omaha/testing/resource.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Used by extra_args_parser_unittest.cc.

-void VerifyCommandLineExtraArgs(const CommandLineExtraArgs& expected_val,

-                                const CommandLineExtraArgs& actual_val);

-

-namespace {

-

-#define YOUTUBEUPLOADEREN_TAG_WITHOUT_QUOTES \

-    _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&") \

-    _T("appname=YouTubeUploader&needsadmin=False&lang=en")

-

-#define YOUTUBEUPLOADEREN_APP_ARGS_WITHOUT_QUOTES \

-    _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&") \

-    _T("installerdata=YouTube%20Uploader%20Data")

-

-#define YOUTUBEUPLOADEREN_TAG \

-    _T("\"") YOUTUBEUPLOADEREN_TAG_WITHOUT_QUOTES _T("\"")

-

-#define YOUTUBEUPLOADEREN_APP_ARGS \

-    _T("\"") YOUTUBEUPLOADEREN_APP_ARGS_WITHOUT_QUOTES _T("\"")

-

-void VerifyCommandLineArgs(const CommandLineArgs& expected,

-                           const CommandLineArgs& actual) {

-  EXPECT_EQ(expected.mode, actual.mode);

-

-  EXPECT_EQ(expected.is_interactive_set, actual.is_interactive_set);

-  EXPECT_EQ(expected.is_machine_set, actual.is_machine_set);

-  EXPECT_EQ(expected.is_install_elevated, actual.is_install_elevated);

-  EXPECT_EQ(expected.is_silent_set, actual.is_silent_set);

-  EXPECT_EQ(expected.is_eula_required_set, actual.is_eula_required_set);

-  EXPECT_EQ(expected.is_offline_set, actual.is_offline_set);

-  EXPECT_EQ(expected.is_oem_set, actual.is_oem_set);

-  EXPECT_EQ(expected.is_uninstall_set, actual.is_uninstall_set);

-

-  EXPECT_STREQ(expected.extra_args_str, actual.extra_args_str);

-  EXPECT_STREQ(expected.app_args_str, actual.app_args_str);

-  EXPECT_STREQ(expected.install_source, actual.install_source);

-  EXPECT_STREQ(expected.crash_filename, actual.crash_filename);

-  EXPECT_STREQ(expected.custom_info_filename, actual.custom_info_filename);

-  EXPECT_STREQ(expected.legacy_manifest_path, actual.legacy_manifest_path);

-  EXPECT_STREQ(expected.webplugin_urldomain, actual.webplugin_urldomain);

-  EXPECT_STREQ(expected.webplugin_args, actual.webplugin_args);

-  EXPECT_STREQ(expected.code_red_metainstaller_path,

-               actual.code_red_metainstaller_path);

-

-  VerifyCommandLineExtraArgs(expected.extra, actual.extra);

-}

-

-void VerifyArgsWithSingleYouTubeUploaderEnApp(

-    const CommandLineArgs& expected_without_app,

-    const CommandLineArgs& actual,

-    bool expect_app_args,

-    bool expect_language) {

-  CommandLineArgs expected(expected_without_app);

-

-  const GUID expected_guid = {0xA4F7B07B, 0xB9BD, 0x4A33,

-                              {0xB1, 0x36, 0x96, 0xD2, 0xAD, 0xFB, 0x60, 0xCB}};

-  CommandLineAppArgs app_args;

-  app_args.app_guid = expected_guid;

-  app_args.app_name = _T("YouTubeUploader");

-  app_args.needs_admin = false;

-  if (expected.extra_args_str.IsEmpty()) {

-    expected.extra_args_str = YOUTUBEUPLOADEREN_TAG_WITHOUT_QUOTES;

-  }

-  if (expect_language) {

-    expected.extra.language = _T("en");

-  }

-  if (expect_app_args) {

-    expected.app_args_str =

-        YOUTUBEUPLOADEREN_APP_ARGS_WITHOUT_QUOTES;

-    app_args.encoded_installer_data = _T("YouTube%20Uploader%20Data");

-  }

-

-  expected.extra.apps.push_back(app_args);

-  VerifyCommandLineArgs(expected, actual);

-}

-

-}  // namespace

-

-void VerifyCommandLineExtraArgs(const CommandLineExtraArgs& expected_val,

-                                const CommandLineExtraArgs& actual_val) {

-  EXPECT_EQ(expected_val.apps.size(), actual_val.apps.size());

-

-  EXPECT_STREQ(GuidToString(expected_val.installation_id),

-               GuidToString(actual_val.installation_id));

-  EXPECT_STREQ(expected_val.brand_code, actual_val.brand_code);

-  EXPECT_STREQ(expected_val.client_id, actual_val.client_id);

-  EXPECT_STREQ(expected_val.referral_id, actual_val.referral_id);

-  EXPECT_EQ(expected_val.browser_type, actual_val.browser_type);

-  EXPECT_EQ(expected_val.usage_stats_enable, actual_val.usage_stats_enable);

-  EXPECT_STREQ(expected_val.language, actual_val.language);

-

-  for (size_t i = 0; i < actual_val.apps.size(); ++i) {

-    CommandLineAppArgs expected = expected_val.apps[i];

-    CommandLineAppArgs actual = actual_val.apps[i];

-

-    EXPECT_STREQ(GuidToString(expected.app_guid),

-                 GuidToString(actual.app_guid));

-    EXPECT_STREQ(expected.app_name, actual.app_name);

-    EXPECT_EQ(expected.needs_admin, actual.needs_admin);

-    EXPECT_STREQ(expected.ap, actual.ap);

-    EXPECT_STREQ(expected.tt_token, actual.tt_token);

-    EXPECT_STREQ(expected.encoded_installer_data,

-                 actual.encoded_installer_data);

-    EXPECT_STREQ(expected.install_data_index, actual.install_data_index);

-  }

-}

-

-class CommandLineTest : public testing::Test {

- protected:

-  CommandLineArgs args_;

-  CommandLineArgs expected_;

-};

-

-TEST(CommandLineSimpleTest, GetCmdLineTail1) {

-  EXPECT_STREQ(_T(""),  GetCmdLineTail(_T("")));

-}

-

-TEST(CommandLineSimpleTest, GetCmdLineTail2) {

-  EXPECT_STREQ(_T(""), GetCmdLineTail(_T("a")));

-}

-TEST(CommandLineSimpleTest, GetCmdLineTail3) {

-  EXPECT_STREQ(_T(""), GetCmdLineTail(_T("goopdate.exe")));

-}

-

-TEST(CommandLineSimpleTest, GetCmdLineTail4) {

-  // Double quotes.

-  EXPECT_STREQ(_T(""), GetCmdLineTail(_T("\"Google Update.exe\"")));

-}

-

-TEST(CommandLineSimpleTest, GetCmdLineTail5) {

-  // Argument.

-  EXPECT_STREQ(_T("foobar"), GetCmdLineTail(_T("goopdate.exe foobar")));

-}

-

-TEST(CommandLineSimpleTest, GetCmdLineTail6) {

-  // Double quotes and argument.

-  EXPECT_STREQ(_T("foobar"),

-               GetCmdLineTail(_T("\"Google Update.exe\" foobar")));

-}

-

-TEST(CommandLineSimpleTest, GetCmdLineTail7) {

-  // Double quotes and inner double quote and argument.

-  EXPECT_STREQ(_T("foobar"),

-               GetCmdLineTail(_T("\"Google\"\" Update.exe\" foobar")));

-}

-

-TEST(CommandLineSimpleTest, GetCmdLineTail8) {

-  // Double quotes and two arguments.

-  EXPECT_STREQ(_T("foo bar"),

-               GetCmdLineTail(_T("\"Google Update.exe\" foo bar")));

-}

-

-TEST(CommandLineSimpleTest, GetCmdLineTail9) {

-  // Double quotes and one argument with quotes.

-  EXPECT_STREQ(_T("\"foo bar\""),

-               GetCmdLineTail(_T("\"Google Update.exe\" \"foo bar\"")));

-}

-

-TEST(CommandLineSimpleTest, GetCmdLineTail10) {

-  // \t as white space.

-  EXPECT_STREQ(_T("foo bar"),

-               GetCmdLineTail(_T("\"Google Update.exe\"\tfoo bar")));

-}

-

-TEST(CommandLineSimpleTest, GetCmdLineTail11) {

-  // Trailing space.

-  EXPECT_STREQ(_T("foo bar "),

-               GetCmdLineTail(_T("\"Google Update.exe\" foo bar ")));

-}

-

-//

-// This block contains the positive test cases for each of the command lines.

-// If you add a new command line parameter permutation, add a test case here.

-//

-

-// TODO(omaha): Add some negative failure cases to the command lines (like

-// /install without "extraargs").

-

-// TODO(omaha): This is an Omaha1 back-compat issue.  Omaha2 should _never_

-// call googleupdate.exe with no arguments.  So when we stop supporting Omaha1

-// handoffs we should remove this support.

-  // Parse empty command line.

-TEST_F(CommandLineTest, ParseCommandLine_Empty) {

-  const TCHAR* kCmdLine = _T("");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_NOARGS;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path>

-// Remember that by convention the OS is passing us the program executable

-// name as the first token in the command line and the parsing code skips that.

-TEST_F(CommandLineTest, ParseCommandLine_ProgramNameOnly) {

-  const TCHAR* kCmdLine = _T("goopdate.exe");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_NOARGS;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /svc

-TEST_F(CommandLineTest, ParseCommandLine_Svc) {

-  const TCHAR* kCmdLine = _T("\"C:\\Program Files\\Google\\Common\\Update\\")

-                           _T("1.0.18.0\\goopdate.exe\" /svc");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_SERVICE;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> -Embedding. The -Embedding text is injected via COM.

-TEST_F(CommandLineTest, ParseCommandLine_Server) {

-  const TCHAR* kCmdLine = _T("goopdate.exe -Embedding");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_COMSERVER;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /install "extraargs"

-TEST_F(CommandLineTest, ParseCommandLine_Install) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /install ")

-      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False&")

-      _T("appguid={C7A9A2F5-C4F9-42d3-8A8B-55086A205468}&")

-      _T("appname=TestApp&needsadmin=true&lang=en\"");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-

-  expected_.extra_args_str = _T("appguid=")

-                            _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                            _T("appname=YouTubeUploader&needsadmin=False&")

-                            _T("appguid=")

-                            _T("{C7A9A2F5-C4F9-42d3-8A8B-55086A205468}&")

-                            _T("appname=TestApp&needsadmin=true&lang=en");

-  CommandLineAppArgs app_args;

-  const GUID expected_guid = {0xA4F7B07B, 0xB9BD, 0x4A33,

-                              {0xB1, 0x36, 0x96, 0xD2, 0xAD, 0xFB, 0x60, 0xCB}};

-  app_args.app_guid = expected_guid;

-  app_args.app_name = _T("YouTubeUploader");

-  app_args.needs_admin = false;

-  expected_.extra.apps.push_back(app_args);

-

-  CommandLineAppArgs app_args1;

-  app_args1.app_guid =

-      StringToGuid(_T("{C7A9A2F5-C4F9-42d3-8A8B-55086A205468}"));

-  app_args1.app_name = _T("TestApp");

-  app_args1.needs_admin = true;

-  expected_.extra.apps.push_back(app_args1);

-  expected_.extra.language = _T("en");

-

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /install "extraargs" /oem

-TEST_F(CommandLineTest, ParseCommandLine_InstallWithOem) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /oem");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_oem_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /install "extraargs" [/oem

-// This tests how we handle a switch with a bracket, which represents optional

-// parameters in a rule, when it appears in an actual command line.

-TEST_F(CommandLineTest, ParseCommandLine_InstallWithOemIgnored) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" [/oem");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_oem_set = false;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /install "extraargs" /appargs <appargs>

-TEST_F(CommandLineTest, ParseCommandLine_InstallWithAppArgs) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS;

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /install "extraargs" /oem /appargs <appargs>

-TEST_F(CommandLineTest, ParseCommandLine_InstallWithOemAppArgs) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /oem")

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS;

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_oem_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /install "extraargs" /appargs <appargs> /silent

-TEST_F(CommandLineTest, ParseCommandLine_InstallWithAppArgsSilent) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /silent");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_silent_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /install "extraargs" /oem /appargs <appargs> /silent

-TEST_F(CommandLineTest, ParseCommandLine_InstallWithOemAppArgsSilent) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /oem")

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /silent");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_oem_set = true;

-  expected_.is_silent_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse:

-//  <path> /install "extraargs" /oem /appargs <appargs> /silent /eularequired

-TEST_F(CommandLineTest,

-       ParseCommandLine_InstallWithOemAppArgsSilentEulaRequired) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-      _T(" /oem")

-      _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-      _T(" /silent")

-      _T(" /eularequired");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_oem_set = true;

-  expected_.is_silent_set = true;

-  expected_.is_eula_required_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /install "extraargs" /eularequired

-TEST_F(CommandLineTest, ParseCommandLine_InstallEulaRequired) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-      _T(" /eularequired");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_eula_required_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /install "extraargs" /oem /installsource oneclick

-TEST_F(CommandLineTest, ParseCommandLine_InstallWithOemAndSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /oem")

-                          _T(" /installsource oneclick");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_oem_set = true;

-  expected_.install_source = _T("oneclick");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /install "extraargs" /installsource oneclick

-TEST_F(CommandLineTest, ParseCommandLine_InstallWithSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installsource oneclick");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.install_source = _T("oneclick");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /install "extraargs" /silent

-TEST_F(CommandLineTest, ParseCommandLine_InstallSilent) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /silent");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_silent_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /install "extraargs" /silent /oem

-TEST_F(CommandLineTest, ParseCommandLine_InstallSilentWithOem) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /silent")

-                          _T(" /oem");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_silent_set = true;

-  expected_.is_oem_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /install "extraargs" /installsource oneclick /silent

-TEST_F(CommandLineTest, ParseCommandLine_InstallSilentWithSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installsource oneclick")

-                          _T(" /silent");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.install_source = _T("oneclick");

-  expected_.is_silent_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /install "extraargs" /installelevated

-TEST_F(CommandLineTest, ParseCommandLine_InstallElevated) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installelevated");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_install_elevated = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /install "extraargs" /installelevated /installsource oneclick

-TEST_F(CommandLineTest, ParseCommandLine_InstallElevatedWithSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installelevated /installsource oneclick");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.is_install_elevated = true;

-  expected_.install_source = _T("oneclick");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /ig "extraargs"

-TEST_F(CommandLineTest, ParseCommandLine_Ig) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG;

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /ig "extraargs" /offlineinstall

-// While legal, this command line is not supported.

-TEST_F(CommandLineTest, ParseCommandLine_IgOfflineWithoutInstallSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /ig "extraargs" /installsource oneclick

-TEST_F(CommandLineTest, ParseCommandLine_IgWithSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installsource oneclick");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.install_source = _T("oneclick");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /ig "extraargs" /installsource offline /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_IgWithSourceOffline) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installsource offline /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.install_source = _T("offline");

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /ig "extraargs" /appargs <appargs>

-//               /installsource offline /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_IgWithAppArgsSourceOffline) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /installsource offline /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.install_source = _T("offline");

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /ig "extraargs" /silent

-TEST_F(CommandLineTest, ParseCommandLine_IgSilent) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /silent");

-

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.is_silent_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /ig "extraargs" /silent /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_IgSilentOfflineWithoutInstallSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /silent")

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.is_silent_set = true;

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /ig "extraargs" /installsource oneclick /silent

-TEST_F(CommandLineTest, ParseCommandLine_IgSilentWithSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installsource oneclick")

-                          _T(" /silent");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.install_source = _T("oneclick");

-  expected_.is_silent_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /ig "extraargs" /installsource oneclick /silent /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_IgSilentWithSourceOffline) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installsource oneclick")

-                          _T(" /silent")

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.install_source = _T("oneclick");

-  expected_.is_silent_set = true;

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /ig "extraargs" /appargs <appargs>

-TEST_F(CommandLineTest, ParseCommandLine_IgWithAppArgs) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS;

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /ig "extraargs" /appargs <appargs> /silent

-TEST_F(CommandLineTest, ParseCommandLine_IgSilentWithAppArgs) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /silent");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.is_silent_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /ig "extraargs" /appargs <appargs> /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_IgWithAppArgsOffline) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /ig "extraargs" /appargs <appargs> /silent /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_IgSilentWithAppArgsOffline) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /silent")

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.is_silent_set = true;

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /ig "extraargs" /appargs <appargs>

-//               /installsource offline /silent /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_IgSilentWithAppArgsSourceOffline) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /installsource offline")

-                          _T(" /silent")

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.install_source = _T("offline");

-  expected_.is_silent_set = true;

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /ig "extraargs" /appargs <appargs>

-//               /installsource offline /silent /offlineinstall /eularequired

-TEST_F(CommandLineTest,

-       ParseCommandLine_IgSilentWithAppArgsSourceOfflineEulaRequired) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /installsource offline")

-                          _T(" /silent")

-                          _T(" /offlineinstall")

-                          _T(" /eularequired");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.install_source = _T("offline");

-  expected_.is_silent_set = true;

-  expected_.is_offline_set = true;

-  expected_.is_eula_required_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /ig "extraargs" /eularequired

-TEST_F(CommandLineTest, ParseCommandLine_IgEulaRequired) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /eularequired");

-

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_IG;

-  expected_.is_eula_required_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /handoff "extraargs"

-TEST_F(CommandLineTest, ParseCommandLine_Handoff) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG;

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /handoff "extraargs" /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_HandoffOfflineWithoutInstallSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /handoff "extraargs" /installsource "asd"

-TEST_F(CommandLineTest, ParseCommandLine_HandoffWithSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installsource oneclick");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.install_source = _T("oneclick");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /handoff "extraargs" /installsource offline /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_HandoffWithSourceOffline) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installsource offline")

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.install_source = _T("offline");

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /handoff "extraargs" /appargs <appargs>

-//               /installsource offline /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_HandoffWithAppArgsSourceOffline) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /installsource offline /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.install_source = _T("offline");

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /handoff "extraargs" /silent

-TEST_F(CommandLineTest, ParseCommandLine_HandoffSilent) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /silent");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.is_silent_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /handoff "extraargs" /silent /offlineinstall

-TEST_F(CommandLineTest,

-       ParseCommandLine_HandoffSilentOfflineWithoutInstallSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /silent")

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.is_silent_set = true;

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /handoff "extraargs" /installsource "asd" /silent

-TEST_F(CommandLineTest, ParseCommandLine_HandoffSilentWithSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installsource oneclick")

-                          _T(" /silent");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.install_source = _T("oneclick");

-  expected_.is_silent_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse:

-//   <path> /handoff "extraargs" /installsource offline /silent /offlineinstall

-TEST_F(CommandLineTest, ParseCommandLine_HandoffSilentWithSourceOffline) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /installsource offline")

-                          _T(" /silent")

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.install_source = _T("offline");

-  expected_.is_silent_set = true;

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /handoff "extraargs" /appargs <appargs>

-TEST_F(CommandLineTest, ParseCommandLine_HandoffWithAppArgs) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS;

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /handoff "extraargs" /appargs <appargs> /silent

-TEST_F(CommandLineTest, ParseCommandLine_HandoffSilentWithAppArgs) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /silent");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.is_silent_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /handoff "extraargs" /appargs <appargs>

-//               /installsource offline /silent /offlineinstall

-TEST_F(CommandLineTest,

-       ParseCommandLine_HandoffSilentWithAppArgsSourceOffline) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /installsource offline")

-                          _T(" /silent")

-                          _T(" /offlineinstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.install_source = _T("offline");

-  expected_.is_silent_set = true;

-  expected_.is_offline_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /handoff "extraargs" /appargs <appargs>

-//               /installsource offline /silent /offlineinstall /eularequired

-TEST_F(CommandLineTest,

-       ParseCommandLine_HandoffSilentWithAppArgsSourceOfflineEulaRequired) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS

-                          _T(" /installsource offline")

-                          _T(" /silent")

-                          _T(" /offlineinstall")

-                          _T(" /eularequired");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.install_source = _T("offline");

-  expected_.is_silent_set = true;

-  expected_.is_offline_set = true;

-  expected_.is_eula_required_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);

-}

-

-// Parse: <path> /handoff "extraargs" /eularequired

-TEST_F(CommandLineTest, ParseCommandLine_HandoffEulaRequired) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG

-                          _T(" /eularequired");

-

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.is_eula_required_set = true;

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /ug

-TEST_F(CommandLineTest, ParseCommandLine_Ug) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ug");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_UG;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /ua

-TEST_F(CommandLineTest, ParseCommandLine_UaNoInstallSource) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ua");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_UA;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /ua /installsource core

-TEST_F(CommandLineTest, ParseCommandLine_Ua) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ua /installsource core");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_UA;

-  expected_.install_source = _T("core");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /ua /installsource core /uninstall

-TEST_F(CommandLineTest, ParseCommandLine_UaWithUninstall) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ua /installsource core /uninstall");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_UA;

-  expected_.install_source = _T("core");

-  expected_.is_uninstall_set = true;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /update

-TEST_F(CommandLineTest, ParseCommandLine_Update) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /update");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_UPDATE;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /netdiags

-TEST_F(CommandLineTest, ParseCommandLine_NetDiags) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /netdiags");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_NETDIAGS;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /regserver

-TEST_F(CommandLineTest, ParseCommandLine_Regserver) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /regserver");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_REGSERVER;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /unregserver

-TEST_F(CommandLineTest, ParseCommandLine_Unregserver) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /unregserver");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_UNREGSERVER;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /registerproduct

-TEST_F(CommandLineTest, ParseCommandLine_RegisterProduct) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /registerproduct ")

-      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False\"");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_REGISTER_PRODUCT;

-  expected_.extra_args_str = _T("appguid=")

-                            _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                            _T("appname=YouTubeUploader&needsadmin=False");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, false);

-}

-

-// Parse: <path> /registerproduct /installsource enterprisemsi

-TEST_F(CommandLineTest, ParseCommandLine_RegisterProductWithInstallSource) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /registerproduct ")

-      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False\"")

-      _T(" /installsource enterprisemsi");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-  expected_.mode = COMMANDLINE_MODE_REGISTER_PRODUCT;

-  expected_.install_source = _T("enterprisemsi");

-  expected_.extra_args_str = _T("appguid=")

-                            _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                            _T("appname=YouTubeUploader&needsadmin=False");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, false);

-}

-

-// Parse: <path> /unregisterproduct

-TEST_F(CommandLineTest, ParseCommandLine_UnregisterProduct) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /unregisterproduct ")

-      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False\"");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_UNREGISTER_PRODUCT;

-  expected_.extra_args_str = _T("appguid=")

-                            _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-                            _T("appname=YouTubeUploader&needsadmin=False");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, false);

-}

-

-// Parse: <path> /c

-TEST_F(CommandLineTest, ParseCommandLine_Core) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /c");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_CORE;

-  expected_.is_crash_handler_disabled = false;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /c /nocrashserver

-TEST_F(CommandLineTest, ParseCommandLine_CoreNoCrashHandler) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /c /nocrashserver");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_CORE;

-  expected_.is_crash_handler_disabled = true;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /crash

-TEST_F(CommandLineTest, ParseCommandLine_Crash) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /crash");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_CRASH;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /report crash_file

-TEST_F(CommandLineTest, ParseCommandLine_Report) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /report C:\\foo\\crash.dmp");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_REPORTCRASH;

-  expected_.crash_filename = _T("C:\\foo\\crash.dmp");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /report crash_file /machine

-TEST_F(CommandLineTest, ParseCommandLine_ReportMachine) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /report C:\\foo\\crash.dmp /machine");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_REPORTCRASH;

-  expected_.crash_filename = _T("C:\\foo\\crash.dmp");

-  expected_.is_machine_set = true;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /report crash_file

-TEST_F(CommandLineTest, ParseCommandLine_ReportWithCustomInfo) {

-  const TCHAR* kCmdLine =

-    _T("goopdate.exe /report C:\\foo.dmp /custom_info_filename C:\\foo.txt");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_REPORTCRASH;

-  expected_.crash_filename = _T("C:\\foo.dmp");

-  expected_.custom_info_filename = _T("C:\\foo.txt");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /report /i crash_file

-TEST_F(CommandLineTest, ParseCommandLine_ReportInteractive) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /report /i C:\\foo\\crash.dmp");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_REPORTCRASH;

-  expected_.is_interactive_set = true;

-  expected_.crash_filename = _T("C:\\foo\\crash.dmp");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-// Parse: <path> /report /i crash_file /machine

-TEST_F(CommandLineTest, ParseCommandLine_ReportMachineInteractive) {

-  const TCHAR*

-      kCmdLine = _T("goopdate.exe /report /i C:\\foo\\crash.dmp /machine");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_REPORTCRASH;

-  expected_.is_machine_set = true;

-  expected_.is_interactive_set = true;

-  expected_.crash_filename = _T("C:\\foo\\crash.dmp");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-TEST_F(CommandLineTest, ParseCommandLine_CodeRedCheck) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /cr");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_CODE_RED_CHECK;

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-TEST_F(CommandLineTest, ParseCommandLine_WebPlugin) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /pi \"http://gears.google.com/\" ")

-                          _T("\"/install foo\" /installsource oneclick ");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_WEBPLUGIN;

-  expected_.webplugin_urldomain = _T("http://gears.google.com/");

-  expected_.webplugin_args = _T("/install foo");

-  expected_.install_source = _T("oneclick");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-TEST_F(CommandLineTest, ParseCommandLine_WebPluginUrlEscaped) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /pi \"http://gears.google.com/\" ")

-                          _T("\"/install%20foo\" /installsource oneclick ");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_WEBPLUGIN;

-  expected_.webplugin_urldomain = _T("http://gears.google.com/");

-  expected_.webplugin_args = _T("/install foo");

-  expected_.install_source = _T("oneclick");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-TEST_F(CommandLineTest, ParseCommandLine_WebPluginTestStringTrim) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /pi ")

-                          _T("\"  http://gears.google.com/   \"  ")

-                          _T("\"/install foo\" /installsource oneclick ");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_WEBPLUGIN;

-  expected_.webplugin_urldomain = _T("http://gears.google.com/");

-  expected_.webplugin_args = _T("/install foo");

-  expected_.install_source = _T("oneclick");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-TEST_F(CommandLineTest, ParseCommandLine_UiNoLanguage) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ui \"manifestfilename.xml\"");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_LEGACYUI;

-  expected_.legacy_manifest_path = _T("manifestfilename.xml");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-TEST_F(CommandLineTest, ParseCommandLine_UiWithLanguage) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /ui /lang fr \"manifestfilename.xml\"");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_LEGACYUI;

-  expected_.legacy_manifest_path = _T("manifestfilename.xml");

-  expected_.extra.language = _T("fr");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-TEST_F(CommandLineTest, ParseCommandLine_UiUser) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /uiuser file.gup");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF;

-  expected_.legacy_manifest_path = _T("file.gup");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-TEST_F(CommandLineTest, ParseCommandLine_Recover) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /recover repairfile.exe");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_RECOVER;

-  expected_.code_red_metainstaller_path = _T("repairfile.exe");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-TEST_F(CommandLineTest, ParseCommandLine_RecoverMachine) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /recover /machine repfile.exe");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_RECOVER;

-  expected_.is_machine_set = true;

-  expected_.code_red_metainstaller_path = _T("repfile.exe");

-  VerifyCommandLineArgs(expected_, args_);

-}

-

-//

-// These are additional failure cases against the command line parsing.

-// Everything from here on down should fail ParseCommandLine().

-//

-

-

-// Parse: <path> manifest_file

-TEST_F(CommandLineTest, ParseCommandLine_GoopdateJustArg) {

-  const TCHAR* kCmdLine = _T("goopdate.exe \"foo bar\"");

-  ExpectAsserts expect_asserts;

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-// Parse: <path> /install manifest_file manifest_file

-// Fails since this is an invalid command line set.

-TEST_F(CommandLineTest, ParseCommandLine_Invalid) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install \"foo bar\" foobar");

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-// Parse: <path> /recover

-TEST_F(CommandLineTest, Recover_WithoutFile) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /recover");

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-// Parse: <path> /machine

-TEST_F(CommandLineTest, MachineWithoutRecover) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /machine");

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-TEST_F(CommandLineTest, ExtraArgsHasDoubleQuoteInTheMiddle) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /install \"some_\"file\"");

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-TEST_F(CommandLineTest, CommandsNotSeparatedBySpaces) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /recover/machine");

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-TEST_F(CommandLineTest, CommandsDoNotHaveForwardSlashes) {

-  const TCHAR* kCmdLine = _T("goopdate.exe recover machine");

-  ExpectAsserts expect_asserts;

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-TEST_F(CommandLineTest, UnknownParameter) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /someunknowncommand");

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-TEST_F(CommandLineTest, UiWithLangNoLanguage) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /ui /lang \"manifestfilename.xml\"");

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-TEST_F(CommandLineTest, WebPluginInstallSourceInvalid_IncorrectValue) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /installsource invalid /pi ")

-                          _T("\"  http://gears.google.com/   \"  ");

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-TEST_F(CommandLineTest, WebPluginInstallSourceInvalid_Empty) {

-  const TCHAR* kCmdLine = _T("goopdate.exe /installsource /pi ")

-                          _T("\"  http://gears.google.com/   \"  ");

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-// Parse: <path> /handoff "extraargs" /lang "en"

-TEST_F(CommandLineTest, ParseCommandLine_HandoffLegacy) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /handoff ")

-      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False\"")

-      _T(" /lang en");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.extra_args_str =

-      _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /handoff "extraargs" /installsource "asd" /lang "en"

-TEST_F(CommandLineTest, ParseCommandLine_HandoffWithSourceLegacy) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /handoff ")

-      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False\"")

-      _T(" /installsource oneclick /lang en");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.install_source = _T("oneclick");

-  expected_.extra_args_str =

-      _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /handoff "extraargs" /installsource "oneclick" /lang "en"

-TEST_F(CommandLineTest, ParseCommandLine_HandoffWithSourceLegacyBoth) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /handoff ")

-      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")

-      _T(" /installsource oneclick /lang en");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  expected_.install_source = _T("oneclick");

-  expected_.extra_args_str =

-      _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False&lang=en");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-// Parse: <path> /install "extraargs" /lang en

-TEST_F(CommandLineTest, ParseCommandLine_InstallLegacy) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /install ")

-      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False&")

-      _T("appguid={C7A9A2F5-C4F9-42d3-8A8B-55086A205468}&")

-      _T("appname=TestApp&needsadmin=true\" /lang en");

-  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));

-}

-

-// Parse: <path> /install "extraargs" /installsource oneclick /lang en

-TEST_F(CommandLineTest, ParseCommandLine_InstallWithSourceLegacy) {

-  const TCHAR* kCmdLine =

-      _T("goopdate.exe /install ")

-      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False\"")

-      _T(" /installsource oneclick /lang en");

-  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));

-

-  expected_.mode = COMMANDLINE_MODE_INSTALL;

-  expected_.install_source = _T("oneclick");

-  expected_.extra_args_str =

-      _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")

-      _T("appname=YouTubeUploader&needsadmin=False");

-  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/error.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/net/http_client.h"
+#include "omaha/testing/resource.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Used by extra_args_parser_unittest.cc.
+void VerifyCommandLineExtraArgs(const CommandLineExtraArgs& expected_val,
+                                const CommandLineExtraArgs& actual_val);
+
+namespace {
+
+#define YOUTUBEUPLOADEREN_TAG_WITHOUT_QUOTES \
+    _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&") \
+    _T("appname=YouTubeUploader&needsadmin=False&lang=en")
+
+#define YOUTUBEUPLOADEREN_APP_ARGS_WITHOUT_QUOTES \
+    _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&") \
+    _T("installerdata=YouTube%20Uploader%20Data")
+
+#define YOUTUBEUPLOADEREN_TAG \
+    _T("\"") YOUTUBEUPLOADEREN_TAG_WITHOUT_QUOTES _T("\"")
+
+#define YOUTUBEUPLOADEREN_APP_ARGS \
+    _T("\"") YOUTUBEUPLOADEREN_APP_ARGS_WITHOUT_QUOTES _T("\"")
+
+void VerifyCommandLineArgs(const CommandLineArgs& expected,
+                           const CommandLineArgs& actual) {
+  EXPECT_EQ(expected.mode, actual.mode);
+
+  EXPECT_EQ(expected.is_interactive_set, actual.is_interactive_set);
+  EXPECT_EQ(expected.is_machine_set, actual.is_machine_set);
+  EXPECT_EQ(expected.is_install_elevated, actual.is_install_elevated);
+  EXPECT_EQ(expected.is_silent_set, actual.is_silent_set);
+  EXPECT_EQ(expected.is_eula_required_set, actual.is_eula_required_set);
+  EXPECT_EQ(expected.is_offline_set, actual.is_offline_set);
+  EXPECT_EQ(expected.is_oem_set, actual.is_oem_set);
+  EXPECT_EQ(expected.is_uninstall_set, actual.is_uninstall_set);
+
+  EXPECT_STREQ(expected.extra_args_str, actual.extra_args_str);
+  EXPECT_STREQ(expected.app_args_str, actual.app_args_str);
+  EXPECT_STREQ(expected.install_source, actual.install_source);
+  EXPECT_STREQ(expected.crash_filename, actual.crash_filename);
+  EXPECT_STREQ(expected.custom_info_filename, actual.custom_info_filename);
+  EXPECT_STREQ(expected.legacy_manifest_path, actual.legacy_manifest_path);
+  EXPECT_STREQ(expected.webplugin_urldomain, actual.webplugin_urldomain);
+  EXPECT_STREQ(expected.webplugin_args, actual.webplugin_args);
+  EXPECT_STREQ(expected.code_red_metainstaller_path,
+               actual.code_red_metainstaller_path);
+
+  VerifyCommandLineExtraArgs(expected.extra, actual.extra);
+}
+
+void VerifyArgsWithSingleYouTubeUploaderEnApp(
+    const CommandLineArgs& expected_without_app,
+    const CommandLineArgs& actual,
+    bool expect_app_args,
+    bool expect_language) {
+  CommandLineArgs expected(expected_without_app);
+
+  const GUID expected_guid = {0xA4F7B07B, 0xB9BD, 0x4A33,
+                              {0xB1, 0x36, 0x96, 0xD2, 0xAD, 0xFB, 0x60, 0xCB}};
+  CommandLineAppArgs app_args;
+  app_args.app_guid = expected_guid;
+  app_args.app_name = _T("YouTubeUploader");
+  app_args.needs_admin = false;
+  if (expected.extra_args_str.IsEmpty()) {
+    expected.extra_args_str = YOUTUBEUPLOADEREN_TAG_WITHOUT_QUOTES;
+  }
+  if (expect_language) {
+    expected.extra.language = _T("en");
+  }
+  if (expect_app_args) {
+    expected.app_args_str =
+        YOUTUBEUPLOADEREN_APP_ARGS_WITHOUT_QUOTES;
+    app_args.encoded_installer_data = _T("YouTube%20Uploader%20Data");
+  }
+
+  expected.extra.apps.push_back(app_args);
+  VerifyCommandLineArgs(expected, actual);
+}
+
+}  // namespace
+
+void VerifyCommandLineExtraArgs(const CommandLineExtraArgs& expected_val,
+                                const CommandLineExtraArgs& actual_val) {
+  EXPECT_EQ(expected_val.apps.size(), actual_val.apps.size());
+
+  EXPECT_STREQ(GuidToString(expected_val.installation_id),
+               GuidToString(actual_val.installation_id));
+  EXPECT_STREQ(expected_val.brand_code, actual_val.brand_code);
+  EXPECT_STREQ(expected_val.client_id, actual_val.client_id);
+  EXPECT_STREQ(expected_val.referral_id, actual_val.referral_id);
+  EXPECT_EQ(expected_val.browser_type, actual_val.browser_type);
+  EXPECT_EQ(expected_val.usage_stats_enable, actual_val.usage_stats_enable);
+  EXPECT_STREQ(expected_val.language, actual_val.language);
+
+  for (size_t i = 0; i < actual_val.apps.size(); ++i) {
+    CommandLineAppArgs expected = expected_val.apps[i];
+    CommandLineAppArgs actual = actual_val.apps[i];
+
+    EXPECT_STREQ(GuidToString(expected.app_guid),
+                 GuidToString(actual.app_guid));
+    EXPECT_STREQ(expected.app_name, actual.app_name);
+    EXPECT_EQ(expected.needs_admin, actual.needs_admin);
+    EXPECT_STREQ(expected.ap, actual.ap);
+    EXPECT_STREQ(expected.tt_token, actual.tt_token);
+    EXPECT_STREQ(expected.encoded_installer_data,
+                 actual.encoded_installer_data);
+    EXPECT_STREQ(expected.install_data_index, actual.install_data_index);
+  }
+}
+
+class CommandLineTest : public testing::Test {
+ protected:
+  CommandLineArgs args_;
+  CommandLineArgs expected_;
+};
+
+TEST(CommandLineSimpleTest, GetCmdLineTail1) {
+  EXPECT_STREQ(_T(""),  GetCmdLineTail(_T("")));
+}
+
+TEST(CommandLineSimpleTest, GetCmdLineTail2) {
+  EXPECT_STREQ(_T(""), GetCmdLineTail(_T("a")));
+}
+TEST(CommandLineSimpleTest, GetCmdLineTail3) {
+  EXPECT_STREQ(_T(""), GetCmdLineTail(_T("goopdate.exe")));
+}
+
+TEST(CommandLineSimpleTest, GetCmdLineTail4) {
+  // Double quotes.
+  EXPECT_STREQ(_T(""), GetCmdLineTail(_T("\"Google Update.exe\"")));
+}
+
+TEST(CommandLineSimpleTest, GetCmdLineTail5) {
+  // Argument.
+  EXPECT_STREQ(_T("foobar"), GetCmdLineTail(_T("goopdate.exe foobar")));
+}
+
+TEST(CommandLineSimpleTest, GetCmdLineTail6) {
+  // Double quotes and argument.
+  EXPECT_STREQ(_T("foobar"),
+               GetCmdLineTail(_T("\"Google Update.exe\" foobar")));
+}
+
+TEST(CommandLineSimpleTest, GetCmdLineTail7) {
+  // Double quotes and inner double quote and argument.
+  EXPECT_STREQ(_T("foobar"),
+               GetCmdLineTail(_T("\"Google\"\" Update.exe\" foobar")));
+}
+
+TEST(CommandLineSimpleTest, GetCmdLineTail8) {
+  // Double quotes and two arguments.
+  EXPECT_STREQ(_T("foo bar"),
+               GetCmdLineTail(_T("\"Google Update.exe\" foo bar")));
+}
+
+TEST(CommandLineSimpleTest, GetCmdLineTail9) {
+  // Double quotes and one argument with quotes.
+  EXPECT_STREQ(_T("\"foo bar\""),
+               GetCmdLineTail(_T("\"Google Update.exe\" \"foo bar\"")));
+}
+
+TEST(CommandLineSimpleTest, GetCmdLineTail10) {
+  // \t as white space.
+  EXPECT_STREQ(_T("foo bar"),
+               GetCmdLineTail(_T("\"Google Update.exe\"\tfoo bar")));
+}
+
+TEST(CommandLineSimpleTest, GetCmdLineTail11) {
+  // Trailing space.
+  EXPECT_STREQ(_T("foo bar "),
+               GetCmdLineTail(_T("\"Google Update.exe\" foo bar ")));
+}
+
+//
+// This block contains the positive test cases for each of the command lines.
+// If you add a new command line parameter permutation, add a test case here.
+//
+
+// TODO(omaha): Add some negative failure cases to the command lines (like
+// /install without "extraargs").
+
+// TODO(omaha): This is an Omaha1 back-compat issue.  Omaha2 should _never_
+// call googleupdate.exe with no arguments.  So when we stop supporting Omaha1
+// handoffs we should remove this support.
+  // Parse empty command line.
+TEST_F(CommandLineTest, ParseCommandLine_Empty) {
+  const TCHAR* kCmdLine = _T("");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_NOARGS;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path>
+// Remember that by convention the OS is passing us the program executable
+// name as the first token in the command line and the parsing code skips that.
+TEST_F(CommandLineTest, ParseCommandLine_ProgramNameOnly) {
+  const TCHAR* kCmdLine = _T("goopdate.exe");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_NOARGS;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /svc
+TEST_F(CommandLineTest, ParseCommandLine_Svc) {
+  const TCHAR* kCmdLine = _T("\"C:\\Program Files\\Google\\Common\\Update\\")
+                           _T("1.0.18.0\\goopdate.exe\" /svc");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_SERVICE;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> -Embedding. The -Embedding text is injected via COM.
+TEST_F(CommandLineTest, ParseCommandLine_Server) {
+  const TCHAR* kCmdLine = _T("goopdate.exe -Embedding");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_COMSERVER;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /install "extraargs"
+TEST_F(CommandLineTest, ParseCommandLine_Install) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /install ")
+      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False&")
+      _T("appguid={C7A9A2F5-C4F9-42d3-8A8B-55086A205468}&")
+      _T("appname=TestApp&needsadmin=true&lang=en\"");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+
+  expected_.extra_args_str = _T("appguid=")
+                            _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                            _T("appname=YouTubeUploader&needsadmin=False&")
+                            _T("appguid=")
+                            _T("{C7A9A2F5-C4F9-42d3-8A8B-55086A205468}&")
+                            _T("appname=TestApp&needsadmin=true&lang=en");
+  CommandLineAppArgs app_args;
+  const GUID expected_guid = {0xA4F7B07B, 0xB9BD, 0x4A33,
+                              {0xB1, 0x36, 0x96, 0xD2, 0xAD, 0xFB, 0x60, 0xCB}};
+  app_args.app_guid = expected_guid;
+  app_args.app_name = _T("YouTubeUploader");
+  app_args.needs_admin = false;
+  expected_.extra.apps.push_back(app_args);
+
+  CommandLineAppArgs app_args1;
+  app_args1.app_guid =
+      StringToGuid(_T("{C7A9A2F5-C4F9-42d3-8A8B-55086A205468}"));
+  app_args1.app_name = _T("TestApp");
+  app_args1.needs_admin = true;
+  expected_.extra.apps.push_back(app_args1);
+  expected_.extra.language = _T("en");
+
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /install "extraargs" /oem
+TEST_F(CommandLineTest, ParseCommandLine_InstallWithOem) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /oem");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_oem_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /install "extraargs" [/oem
+// This tests how we handle a switch with a bracket, which represents optional
+// parameters in a rule, when it appears in an actual command line.
+TEST_F(CommandLineTest, ParseCommandLine_InstallWithOemIgnored) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" [/oem");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_oem_set = false;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /install "extraargs" /appargs <appargs>
+TEST_F(CommandLineTest, ParseCommandLine_InstallWithAppArgs) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS;
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /install "extraargs" /oem /appargs <appargs>
+TEST_F(CommandLineTest, ParseCommandLine_InstallWithOemAppArgs) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /oem")
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS;
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_oem_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /install "extraargs" /appargs <appargs> /silent
+TEST_F(CommandLineTest, ParseCommandLine_InstallWithAppArgsSilent) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /silent");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_silent_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /install "extraargs" /oem /appargs <appargs> /silent
+TEST_F(CommandLineTest, ParseCommandLine_InstallWithOemAppArgsSilent) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /oem")
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /silent");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_oem_set = true;
+  expected_.is_silent_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse:
+//  <path> /install "extraargs" /oem /appargs <appargs> /silent /eularequired
+TEST_F(CommandLineTest,
+       ParseCommandLine_InstallWithOemAppArgsSilentEulaRequired) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+      _T(" /oem")
+      _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+      _T(" /silent")
+      _T(" /eularequired");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_oem_set = true;
+  expected_.is_silent_set = true;
+  expected_.is_eula_required_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /install "extraargs" /eularequired
+TEST_F(CommandLineTest, ParseCommandLine_InstallEulaRequired) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+      _T(" /eularequired");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_eula_required_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /install "extraargs" /oem /installsource oneclick
+TEST_F(CommandLineTest, ParseCommandLine_InstallWithOemAndSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /oem")
+                          _T(" /installsource oneclick");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_oem_set = true;
+  expected_.install_source = _T("oneclick");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /install "extraargs" /installsource oneclick
+TEST_F(CommandLineTest, ParseCommandLine_InstallWithSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installsource oneclick");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.install_source = _T("oneclick");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /install "extraargs" /silent
+TEST_F(CommandLineTest, ParseCommandLine_InstallSilent) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /silent");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_silent_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /install "extraargs" /silent /oem
+TEST_F(CommandLineTest, ParseCommandLine_InstallSilentWithOem) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /silent")
+                          _T(" /oem");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_silent_set = true;
+  expected_.is_oem_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /install "extraargs" /installsource oneclick /silent
+TEST_F(CommandLineTest, ParseCommandLine_InstallSilentWithSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installsource oneclick")
+                          _T(" /silent");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.install_source = _T("oneclick");
+  expected_.is_silent_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /install "extraargs" /installelevated
+TEST_F(CommandLineTest, ParseCommandLine_InstallElevated) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installelevated");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_install_elevated = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /install "extraargs" /installelevated /installsource oneclick
+TEST_F(CommandLineTest, ParseCommandLine_InstallElevatedWithSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installelevated /installsource oneclick");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.is_install_elevated = true;
+  expected_.install_source = _T("oneclick");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /ig "extraargs"
+TEST_F(CommandLineTest, ParseCommandLine_Ig) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG;
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /ig "extraargs" /offlineinstall
+// While legal, this command line is not supported.
+TEST_F(CommandLineTest, ParseCommandLine_IgOfflineWithoutInstallSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /ig "extraargs" /installsource oneclick
+TEST_F(CommandLineTest, ParseCommandLine_IgWithSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installsource oneclick");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.install_source = _T("oneclick");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /ig "extraargs" /installsource offline /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_IgWithSourceOffline) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installsource offline /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.install_source = _T("offline");
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /ig "extraargs" /appargs <appargs>
+//               /installsource offline /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_IgWithAppArgsSourceOffline) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /installsource offline /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.install_source = _T("offline");
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /ig "extraargs" /silent
+TEST_F(CommandLineTest, ParseCommandLine_IgSilent) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /silent");
+
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.is_silent_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /ig "extraargs" /silent /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_IgSilentOfflineWithoutInstallSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /silent")
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.is_silent_set = true;
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /ig "extraargs" /installsource oneclick /silent
+TEST_F(CommandLineTest, ParseCommandLine_IgSilentWithSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installsource oneclick")
+                          _T(" /silent");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.install_source = _T("oneclick");
+  expected_.is_silent_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /ig "extraargs" /installsource oneclick /silent /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_IgSilentWithSourceOffline) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installsource oneclick")
+                          _T(" /silent")
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.install_source = _T("oneclick");
+  expected_.is_silent_set = true;
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /ig "extraargs" /appargs <appargs>
+TEST_F(CommandLineTest, ParseCommandLine_IgWithAppArgs) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS;
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /ig "extraargs" /appargs <appargs> /silent
+TEST_F(CommandLineTest, ParseCommandLine_IgSilentWithAppArgs) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /silent");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.is_silent_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /ig "extraargs" /appargs <appargs> /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_IgWithAppArgsOffline) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /ig "extraargs" /appargs <appargs> /silent /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_IgSilentWithAppArgsOffline) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /silent")
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.is_silent_set = true;
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /ig "extraargs" /appargs <appargs>
+//               /installsource offline /silent /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_IgSilentWithAppArgsSourceOffline) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /installsource offline")
+                          _T(" /silent")
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.install_source = _T("offline");
+  expected_.is_silent_set = true;
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /ig "extraargs" /appargs <appargs>
+//               /installsource offline /silent /offlineinstall /eularequired
+TEST_F(CommandLineTest,
+       ParseCommandLine_IgSilentWithAppArgsSourceOfflineEulaRequired) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /installsource offline")
+                          _T(" /silent")
+                          _T(" /offlineinstall")
+                          _T(" /eularequired");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.install_source = _T("offline");
+  expected_.is_silent_set = true;
+  expected_.is_offline_set = true;
+  expected_.is_eula_required_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /ig "extraargs" /eularequired
+TEST_F(CommandLineTest, ParseCommandLine_IgEulaRequired) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ig ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /eularequired");
+
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_IG;
+  expected_.is_eula_required_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /handoff "extraargs"
+TEST_F(CommandLineTest, ParseCommandLine_Handoff) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG;
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /handoff "extraargs" /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_HandoffOfflineWithoutInstallSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /handoff "extraargs" /installsource "asd"
+TEST_F(CommandLineTest, ParseCommandLine_HandoffWithSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installsource oneclick");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.install_source = _T("oneclick");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /handoff "extraargs" /installsource offline /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_HandoffWithSourceOffline) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installsource offline")
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.install_source = _T("offline");
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /handoff "extraargs" /appargs <appargs>
+//               /installsource offline /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_HandoffWithAppArgsSourceOffline) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /installsource offline /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.install_source = _T("offline");
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /handoff "extraargs" /silent
+TEST_F(CommandLineTest, ParseCommandLine_HandoffSilent) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /silent");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.is_silent_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /handoff "extraargs" /silent /offlineinstall
+TEST_F(CommandLineTest,
+       ParseCommandLine_HandoffSilentOfflineWithoutInstallSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /silent")
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.is_silent_set = true;
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /handoff "extraargs" /installsource "asd" /silent
+TEST_F(CommandLineTest, ParseCommandLine_HandoffSilentWithSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installsource oneclick")
+                          _T(" /silent");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.install_source = _T("oneclick");
+  expected_.is_silent_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse:
+//   <path> /handoff "extraargs" /installsource offline /silent /offlineinstall
+TEST_F(CommandLineTest, ParseCommandLine_HandoffSilentWithSourceOffline) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /installsource offline")
+                          _T(" /silent")
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.install_source = _T("offline");
+  expected_.is_silent_set = true;
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /handoff "extraargs" /appargs <appargs>
+TEST_F(CommandLineTest, ParseCommandLine_HandoffWithAppArgs) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS;
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /handoff "extraargs" /appargs <appargs> /silent
+TEST_F(CommandLineTest, ParseCommandLine_HandoffSilentWithAppArgs) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /silent");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.is_silent_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /handoff "extraargs" /appargs <appargs>
+//               /installsource offline /silent /offlineinstall
+TEST_F(CommandLineTest,
+       ParseCommandLine_HandoffSilentWithAppArgsSourceOffline) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /installsource offline")
+                          _T(" /silent")
+                          _T(" /offlineinstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.install_source = _T("offline");
+  expected_.is_silent_set = true;
+  expected_.is_offline_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /handoff "extraargs" /appargs <appargs>
+//               /installsource offline /silent /offlineinstall /eularequired
+TEST_F(CommandLineTest,
+       ParseCommandLine_HandoffSilentWithAppArgsSourceOfflineEulaRequired) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /appargs ") YOUTUBEUPLOADEREN_APP_ARGS
+                          _T(" /installsource offline")
+                          _T(" /silent")
+                          _T(" /offlineinstall")
+                          _T(" /eularequired");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.install_source = _T("offline");
+  expected_.is_silent_set = true;
+  expected_.is_offline_set = true;
+  expected_.is_eula_required_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, true, true);
+}
+
+// Parse: <path> /handoff "extraargs" /eularequired
+TEST_F(CommandLineTest, ParseCommandLine_HandoffEulaRequired) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /handoff ") YOUTUBEUPLOADEREN_TAG
+                          _T(" /eularequired");
+
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.is_eula_required_set = true;
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /ug
+TEST_F(CommandLineTest, ParseCommandLine_Ug) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ug");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_UG;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /ua
+TEST_F(CommandLineTest, ParseCommandLine_UaNoInstallSource) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ua");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_UA;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /ua /installsource core
+TEST_F(CommandLineTest, ParseCommandLine_Ua) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ua /installsource core");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_UA;
+  expected_.install_source = _T("core");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /ua /installsource core /uninstall
+TEST_F(CommandLineTest, ParseCommandLine_UaWithUninstall) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ua /installsource core /uninstall");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_UA;
+  expected_.install_source = _T("core");
+  expected_.is_uninstall_set = true;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /update
+TEST_F(CommandLineTest, ParseCommandLine_Update) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /update");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_UPDATE;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /netdiags
+TEST_F(CommandLineTest, ParseCommandLine_NetDiags) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /netdiags");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_NETDIAGS;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /regserver
+TEST_F(CommandLineTest, ParseCommandLine_Regserver) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /regserver");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_REGSERVER;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /unregserver
+TEST_F(CommandLineTest, ParseCommandLine_Unregserver) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /unregserver");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_UNREGSERVER;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /registerproduct
+TEST_F(CommandLineTest, ParseCommandLine_RegisterProduct) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /registerproduct ")
+      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False\"");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_REGISTER_PRODUCT;
+  expected_.extra_args_str = _T("appguid=")
+                            _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                            _T("appname=YouTubeUploader&needsadmin=False");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, false);
+}
+
+// Parse: <path> /registerproduct /installsource enterprisemsi
+TEST_F(CommandLineTest, ParseCommandLine_RegisterProductWithInstallSource) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /registerproduct ")
+      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False\"")
+      _T(" /installsource enterprisemsi");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+  expected_.mode = COMMANDLINE_MODE_REGISTER_PRODUCT;
+  expected_.install_source = _T("enterprisemsi");
+  expected_.extra_args_str = _T("appguid=")
+                            _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                            _T("appname=YouTubeUploader&needsadmin=False");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, false);
+}
+
+// Parse: <path> /unregisterproduct
+TEST_F(CommandLineTest, ParseCommandLine_UnregisterProduct) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /unregisterproduct ")
+      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False\"");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_UNREGISTER_PRODUCT;
+  expected_.extra_args_str = _T("appguid=")
+                            _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+                            _T("appname=YouTubeUploader&needsadmin=False");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, false);
+}
+
+// Parse: <path> /c
+TEST_F(CommandLineTest, ParseCommandLine_Core) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /c");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_CORE;
+  expected_.is_crash_handler_disabled = false;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /c /nocrashserver
+TEST_F(CommandLineTest, ParseCommandLine_CoreNoCrashHandler) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /c /nocrashserver");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_CORE;
+  expected_.is_crash_handler_disabled = true;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /crash
+TEST_F(CommandLineTest, ParseCommandLine_Crash) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /crash");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_CRASH;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /report crash_file
+TEST_F(CommandLineTest, ParseCommandLine_Report) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /report C:\\foo\\crash.dmp");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_REPORTCRASH;
+  expected_.crash_filename = _T("C:\\foo\\crash.dmp");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /report crash_file /machine
+TEST_F(CommandLineTest, ParseCommandLine_ReportMachine) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /report C:\\foo\\crash.dmp /machine");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_REPORTCRASH;
+  expected_.crash_filename = _T("C:\\foo\\crash.dmp");
+  expected_.is_machine_set = true;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /report crash_file
+TEST_F(CommandLineTest, ParseCommandLine_ReportWithCustomInfo) {
+  const TCHAR* kCmdLine =
+    _T("goopdate.exe /report C:\\foo.dmp /custom_info_filename C:\\foo.txt");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_REPORTCRASH;
+  expected_.crash_filename = _T("C:\\foo.dmp");
+  expected_.custom_info_filename = _T("C:\\foo.txt");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /report /i crash_file
+TEST_F(CommandLineTest, ParseCommandLine_ReportInteractive) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /report /i C:\\foo\\crash.dmp");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_REPORTCRASH;
+  expected_.is_interactive_set = true;
+  expected_.crash_filename = _T("C:\\foo\\crash.dmp");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+// Parse: <path> /report /i crash_file /machine
+TEST_F(CommandLineTest, ParseCommandLine_ReportMachineInteractive) {
+  const TCHAR*
+      kCmdLine = _T("goopdate.exe /report /i C:\\foo\\crash.dmp /machine");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_REPORTCRASH;
+  expected_.is_machine_set = true;
+  expected_.is_interactive_set = true;
+  expected_.crash_filename = _T("C:\\foo\\crash.dmp");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+TEST_F(CommandLineTest, ParseCommandLine_CodeRedCheck) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /cr");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_CODE_RED_CHECK;
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+TEST_F(CommandLineTest, ParseCommandLine_WebPlugin) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /pi \"http://gears.google.com/\" ")
+                          _T("\"/install foo\" /installsource oneclick ");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_WEBPLUGIN;
+  expected_.webplugin_urldomain = _T("http://gears.google.com/");
+  expected_.webplugin_args = _T("/install foo");
+  expected_.install_source = _T("oneclick");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+TEST_F(CommandLineTest, ParseCommandLine_WebPluginUrlEscaped) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /pi \"http://gears.google.com/\" ")
+                          _T("\"/install%20foo\" /installsource oneclick ");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_WEBPLUGIN;
+  expected_.webplugin_urldomain = _T("http://gears.google.com/");
+  expected_.webplugin_args = _T("/install foo");
+  expected_.install_source = _T("oneclick");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+TEST_F(CommandLineTest, ParseCommandLine_WebPluginTestStringTrim) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /pi ")
+                          _T("\"  http://gears.google.com/   \"  ")
+                          _T("\"/install foo\" /installsource oneclick ");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_WEBPLUGIN;
+  expected_.webplugin_urldomain = _T("http://gears.google.com/");
+  expected_.webplugin_args = _T("/install foo");
+  expected_.install_source = _T("oneclick");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+TEST_F(CommandLineTest, ParseCommandLine_UiNoLanguage) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ui \"manifestfilename.xml\"");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_LEGACYUI;
+  expected_.legacy_manifest_path = _T("manifestfilename.xml");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+TEST_F(CommandLineTest, ParseCommandLine_UiWithLanguage) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /ui /lang fr \"manifestfilename.xml\"");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_LEGACYUI;
+  expected_.legacy_manifest_path = _T("manifestfilename.xml");
+  expected_.extra.language = _T("fr");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+TEST_F(CommandLineTest, ParseCommandLine_UiUser) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /uiuser file.gup");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF;
+  expected_.legacy_manifest_path = _T("file.gup");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+TEST_F(CommandLineTest, ParseCommandLine_Recover) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /recover repairfile.exe");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_RECOVER;
+  expected_.code_red_metainstaller_path = _T("repairfile.exe");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+TEST_F(CommandLineTest, ParseCommandLine_RecoverMachine) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /recover /machine repfile.exe");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_RECOVER;
+  expected_.is_machine_set = true;
+  expected_.code_red_metainstaller_path = _T("repfile.exe");
+  VerifyCommandLineArgs(expected_, args_);
+}
+
+//
+// These are additional failure cases against the command line parsing.
+// Everything from here on down should fail ParseCommandLine().
+//
+
+
+// Parse: <path> manifest_file
+TEST_F(CommandLineTest, ParseCommandLine_GoopdateJustArg) {
+  const TCHAR* kCmdLine = _T("goopdate.exe \"foo bar\"");
+  ExpectAsserts expect_asserts;
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+// Parse: <path> /install manifest_file manifest_file
+// Fails since this is an invalid command line set.
+TEST_F(CommandLineTest, ParseCommandLine_Invalid) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install \"foo bar\" foobar");
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+// Parse: <path> /recover
+TEST_F(CommandLineTest, Recover_WithoutFile) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /recover");
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+// Parse: <path> /machine
+TEST_F(CommandLineTest, MachineWithoutRecover) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /machine");
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+TEST_F(CommandLineTest, ExtraArgsHasDoubleQuoteInTheMiddle) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /install \"some_\"file\"");
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+TEST_F(CommandLineTest, CommandsNotSeparatedBySpaces) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /recover/machine");
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+TEST_F(CommandLineTest, CommandsDoNotHaveForwardSlashes) {
+  const TCHAR* kCmdLine = _T("goopdate.exe recover machine");
+  ExpectAsserts expect_asserts;
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+TEST_F(CommandLineTest, UnknownParameter) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /someunknowncommand");
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+TEST_F(CommandLineTest, UiWithLangNoLanguage) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /ui /lang \"manifestfilename.xml\"");
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+TEST_F(CommandLineTest, WebPluginInstallSourceInvalid_IncorrectValue) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /installsource invalid /pi ")
+                          _T("\"  http://gears.google.com/   \"  ");
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+TEST_F(CommandLineTest, WebPluginInstallSourceInvalid_Empty) {
+  const TCHAR* kCmdLine = _T("goopdate.exe /installsource /pi ")
+                          _T("\"  http://gears.google.com/   \"  ");
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+// Parse: <path> /handoff "extraargs" /lang "en"
+TEST_F(CommandLineTest, ParseCommandLine_HandoffLegacy) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /handoff ")
+      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False\"")
+      _T(" /lang en");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.extra_args_str =
+      _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /handoff "extraargs" /installsource "asd" /lang "en"
+TEST_F(CommandLineTest, ParseCommandLine_HandoffWithSourceLegacy) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /handoff ")
+      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False\"")
+      _T(" /installsource oneclick /lang en");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.install_source = _T("oneclick");
+  expected_.extra_args_str =
+      _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /handoff "extraargs" /installsource "oneclick" /lang "en"
+TEST_F(CommandLineTest, ParseCommandLine_HandoffWithSourceLegacyBoth) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /handoff ")
+      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")
+      _T(" /installsource oneclick /lang en");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  expected_.install_source = _T("oneclick");
+  expected_.extra_args_str =
+      _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False&lang=en");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+// Parse: <path> /install "extraargs" /lang en
+TEST_F(CommandLineTest, ParseCommandLine_InstallLegacy) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /install ")
+      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False&")
+      _T("appguid={C7A9A2F5-C4F9-42d3-8A8B-55086A205468}&")
+      _T("appname=TestApp&needsadmin=true\" /lang en");
+  EXPECT_FAILED(ParseCommandLine(kCmdLine, &args_));
+}
+
+// Parse: <path> /install "extraargs" /installsource oneclick /lang en
+TEST_F(CommandLineTest, ParseCommandLine_InstallWithSourceLegacy) {
+  const TCHAR* kCmdLine =
+      _T("goopdate.exe /install ")
+      _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False\"")
+      _T(" /installsource oneclick /lang en");
+  EXPECT_SUCCEEDED(ParseCommandLine(kCmdLine, &args_));
+
+  expected_.mode = COMMANDLINE_MODE_INSTALL;
+  expected_.install_source = _T("oneclick");
+  expected_.extra_args_str =
+      _T("appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&")
+      _T("appname=YouTubeUploader&needsadmin=False");
+  VerifyArgsWithSingleYouTubeUploaderEnApp(expected_, args_, false, true);
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/command_line_validator.cc b/goopdate/command_line_validator.cc
index 58006bc..4e11746 100644
--- a/goopdate/command_line_validator.cc
+++ b/goopdate/command_line_validator.cc
@@ -1,256 +1,256 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/command_line_validator.h"

-

-#include <atlbase.h>

-

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/command_line_parser.h"

-

-namespace omaha {

-

-CommandLineValidator::CommandLineValidator() : scenario_sequence_number_(0) {

-}

-

-CommandLineValidator::~CommandLineValidator() {

-  Clear();

-}

-

-HRESULT CommandLineValidator::CreateScenario(const CString& scenario_name) {

-  if (scenarios_.find(scenario_name) != scenarios_.end()) {

-    return E_INVALIDARG;

-  }

-

-  ScenarioParameters scenario_parameters;

-  scenarios_[scenario_name] = scenario_parameters;

-  return S_OK;

-}

-

-// TODO(Omaha): Instead of creating the scenario in the map then populating it,

-// which requires these methods to know about the map, verify the scenario

-// exists, etc. - why not build the scenario then add it to the map? That seems

-// more straightforward.

-HRESULT CommandLineValidator::AddScenarioParameter(

-    const CString& scenario_name,

-    const CString& switch_name,

-    int num_required_parameters) {

-  MapScenariosIter iter = scenarios_.find(scenario_name);

-  if (iter == scenarios_.end()) {

-    return E_INVALIDARG;

-  }

-

-  ScenarioParameter* scenario_parameter =

-      new ScenarioParameter(switch_name, num_required_parameters);

-  (*iter).second.required.push_back(scenario_parameter);

-  return S_OK;

-}

-

-HRESULT CommandLineValidator::AddOptionalScenarioParameter(

-    const CString& scenario_name,

-    const CString& switch_name,

-    int num_required_parameters) {

-  MapScenariosIter iter = scenarios_.find(scenario_name);

-  if (iter == scenarios_.end()) {

-    return E_INVALIDARG;

-  }

-

-  ScenarioParameter* scenario_parameter =

-      new ScenarioParameter(switch_name, num_required_parameters);

-  (*iter).second.optional.push_back(scenario_parameter);

-  return S_OK;

-}

-

-HRESULT CommandLineValidator::CreateScenarioFromCmdLine(

-    const CString& command_line,

-    CString* scenario_name) {

-  ASSERT1(scenario_name);

-

-  CommandLineParser parser;

-  HRESULT hr = parser.ParseFromString(command_line);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Generate a unique scenario name.

-  CString scenario_name_str;

-  do {

-    ++scenario_sequence_number_;

-    scenario_name_str.Format(_T("scenario_%d"), scenario_sequence_number_);

-  } while (scenarios_.find(scenario_name_str) != scenarios_.end());

-

-  CreateScenario(scenario_name_str);

-

-  int switch_count = parser.GetSwitchCount();

-  for (int idx_switch = 0; idx_switch < switch_count; ++idx_switch) {

-    CString switch_name;

-    hr = parser.GetSwitchNameAtIndex(idx_switch, &switch_name);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    int arg_count = 0;

-    hr = parser.GetSwitchArgumentCount(switch_name, &arg_count);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    hr = AddScenarioParameter(scenario_name_str, switch_name, arg_count);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  switch_count = parser.GetOptionalSwitchCount();

-  for (int idx_switch = 0; idx_switch < switch_count; ++idx_switch) {

-    CString switch_name;

-    hr = parser.GetOptionalSwitchNameAtIndex(idx_switch, &switch_name);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    int arg_count = 0;

-    hr = parser.GetOptionalSwitchArgumentCount(switch_name, &arg_count);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    hr = AddOptionalScenarioParameter(scenario_name_str,

-                                      switch_name,

-                                      arg_count);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  *scenario_name = scenario_name_str;

-

-  return S_OK;

-}

-

-HRESULT CommandLineValidator::Validate(

-    const CommandLineParser& command_line_parser,

-    CString* scenario_name) const {

-  // Attempt to verify the data within the command_line_parser against each of

-  // the scenarios.

-  MapScenariosConstIter scenarios_iter;

-  for (scenarios_iter = scenarios_.begin();

-       scenarios_iter != scenarios_.end();

-       ++scenarios_iter) {

-    // Make sure we have a match for the number of switches in this scenario.

-    int parser_switch_count = command_line_parser.GetSwitchCount();

-    int scenario_required_switch_count =

-        (*scenarios_iter).second.required.size();

-    int scenario_optional_switch_count =

-        (*scenarios_iter).second.optional.size();

-

-    if (parser_switch_count < scenario_required_switch_count ||

-        parser_switch_count > scenario_required_switch_count +

-                              scenario_optional_switch_count) {

-      continue;

-    }

-

-    if (DoesScenarioMatch(command_line_parser, (*scenarios_iter).second)) {

-      *scenario_name = (*scenarios_iter).first;

-      return S_OK;

-    }

-  }

-

-  return GOOGLEUPDATE_COMMANDLINE_E_NO_SCENARIO_HANDLER_MATCHED;

-}

-

-bool CommandLineValidator::DoesScenarioMatch(

-    const CommandLineParser& command_line_parser,

-    const ScenarioParameters& scenario_parameters) const {

-  // Make sure that each switch matches with the right number of arguments.

-  ScenarioParameterVectorConstIter parameter_iter;

-  for (parameter_iter = scenario_parameters.required.begin();

-       parameter_iter != scenario_parameters.required.end();

-       ++parameter_iter) {

-    CString current_switch_name = (*parameter_iter)->switch_name_;

-    // This would probably allow duplicate switches (i.e. /c /c) in a command

-    // line.

-    if (!command_line_parser.HasSwitch(current_switch_name)) {

-      return false;

-    }

-

-    int arg_count = 0;

-    HRESULT hr = command_line_parser.GetSwitchArgumentCount(current_switch_name,

-                                                            &arg_count);

-    if (FAILED(hr)) {

-      return false;

-    }

-

-    int switch_arg_count = (*parameter_iter)->num_required_parameters_;

-    if (arg_count != switch_arg_count) {

-      return false;

-    }

-  }

-

-  int parser_optional_switch_count = command_line_parser.GetSwitchCount() -

-                                     scenario_parameters.required.size();

-  for (parameter_iter = scenario_parameters.optional.begin();

-       parser_optional_switch_count != 0 &&

-           parameter_iter != scenario_parameters.optional.end();

-       ++parameter_iter) {

-    CString current_switch_name = (*parameter_iter)->switch_name_;

-    // This would probably allow duplicate optional switches (i.e. /oem /oem) in

-    // a command line.

-    if (!command_line_parser.HasSwitch(current_switch_name)) {

-      continue;

-    }

-

-    int arg_count = 0;

-    HRESULT hr = command_line_parser.GetSwitchArgumentCount(current_switch_name,

-                                                            &arg_count);

-    if (FAILED(hr)) {

-      return false;

-    }

-

-    int switch_arg_count = (*parameter_iter)->num_required_parameters_;

-    if (arg_count != switch_arg_count) {

-      return false;

-    }

-    --parser_optional_switch_count;

-  }

-

-  return parser_optional_switch_count == 0;

-}

-

-void CommandLineValidator::Clear() {

-  MapScenariosIter scenarios_iter;

-  for (scenarios_iter = scenarios_.begin();

-       scenarios_iter != scenarios_.end();

-       ++scenarios_iter) {

-    ScenarioParameterVectorIter param_iter;

-    for (param_iter = (*scenarios_iter).second.required.begin();

-         param_iter != (*scenarios_iter).second.required.end();

-         ++param_iter) {

-      delete *param_iter;

-    }

-    for (param_iter = (*scenarios_iter).second.optional.begin();

-         param_iter != (*scenarios_iter).second.optional.end();

-         ++param_iter) {

-      delete *param_iter;

-    }

-  }

-  scenarios_.clear();

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/command_line_validator.h"
+
+#include <atlbase.h>
+
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/command_line_parser.h"
+
+namespace omaha {
+
+CommandLineValidator::CommandLineValidator() : scenario_sequence_number_(0) {
+}
+
+CommandLineValidator::~CommandLineValidator() {
+  Clear();
+}
+
+HRESULT CommandLineValidator::CreateScenario(const CString& scenario_name) {
+  if (scenarios_.find(scenario_name) != scenarios_.end()) {
+    return E_INVALIDARG;
+  }
+
+  ScenarioParameters scenario_parameters;
+  scenarios_[scenario_name] = scenario_parameters;
+  return S_OK;
+}
+
+// TODO(Omaha): Instead of creating the scenario in the map then populating it,
+// which requires these methods to know about the map, verify the scenario
+// exists, etc. - why not build the scenario then add it to the map? That seems
+// more straightforward.
+HRESULT CommandLineValidator::AddScenarioParameter(
+    const CString& scenario_name,
+    const CString& switch_name,
+    int num_required_parameters) {
+  MapScenariosIter iter = scenarios_.find(scenario_name);
+  if (iter == scenarios_.end()) {
+    return E_INVALIDARG;
+  }
+
+  ScenarioParameter* scenario_parameter =
+      new ScenarioParameter(switch_name, num_required_parameters);
+  (*iter).second.required.push_back(scenario_parameter);
+  return S_OK;
+}
+
+HRESULT CommandLineValidator::AddOptionalScenarioParameter(
+    const CString& scenario_name,
+    const CString& switch_name,
+    int num_required_parameters) {
+  MapScenariosIter iter = scenarios_.find(scenario_name);
+  if (iter == scenarios_.end()) {
+    return E_INVALIDARG;
+  }
+
+  ScenarioParameter* scenario_parameter =
+      new ScenarioParameter(switch_name, num_required_parameters);
+  (*iter).second.optional.push_back(scenario_parameter);
+  return S_OK;
+}
+
+HRESULT CommandLineValidator::CreateScenarioFromCmdLine(
+    const CString& command_line,
+    CString* scenario_name) {
+  ASSERT1(scenario_name);
+
+  CommandLineParser parser;
+  HRESULT hr = parser.ParseFromString(command_line);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Generate a unique scenario name.
+  CString scenario_name_str;
+  do {
+    ++scenario_sequence_number_;
+    scenario_name_str.Format(_T("scenario_%d"), scenario_sequence_number_);
+  } while (scenarios_.find(scenario_name_str) != scenarios_.end());
+
+  CreateScenario(scenario_name_str);
+
+  int switch_count = parser.GetSwitchCount();
+  for (int idx_switch = 0; idx_switch < switch_count; ++idx_switch) {
+    CString switch_name;
+    hr = parser.GetSwitchNameAtIndex(idx_switch, &switch_name);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    int arg_count = 0;
+    hr = parser.GetSwitchArgumentCount(switch_name, &arg_count);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    hr = AddScenarioParameter(scenario_name_str, switch_name, arg_count);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  switch_count = parser.GetOptionalSwitchCount();
+  for (int idx_switch = 0; idx_switch < switch_count; ++idx_switch) {
+    CString switch_name;
+    hr = parser.GetOptionalSwitchNameAtIndex(idx_switch, &switch_name);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    int arg_count = 0;
+    hr = parser.GetOptionalSwitchArgumentCount(switch_name, &arg_count);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    hr = AddOptionalScenarioParameter(scenario_name_str,
+                                      switch_name,
+                                      arg_count);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  *scenario_name = scenario_name_str;
+
+  return S_OK;
+}
+
+HRESULT CommandLineValidator::Validate(
+    const CommandLineParser& command_line_parser,
+    CString* scenario_name) const {
+  // Attempt to verify the data within the command_line_parser against each of
+  // the scenarios.
+  MapScenariosConstIter scenarios_iter;
+  for (scenarios_iter = scenarios_.begin();
+       scenarios_iter != scenarios_.end();
+       ++scenarios_iter) {
+    // Make sure we have a match for the number of switches in this scenario.
+    int parser_switch_count = command_line_parser.GetSwitchCount();
+    int scenario_required_switch_count =
+        (*scenarios_iter).second.required.size();
+    int scenario_optional_switch_count =
+        (*scenarios_iter).second.optional.size();
+
+    if (parser_switch_count < scenario_required_switch_count ||
+        parser_switch_count > scenario_required_switch_count +
+                              scenario_optional_switch_count) {
+      continue;
+    }
+
+    if (DoesScenarioMatch(command_line_parser, (*scenarios_iter).second)) {
+      *scenario_name = (*scenarios_iter).first;
+      return S_OK;
+    }
+  }
+
+  return GOOGLEUPDATE_COMMANDLINE_E_NO_SCENARIO_HANDLER_MATCHED;
+}
+
+bool CommandLineValidator::DoesScenarioMatch(
+    const CommandLineParser& command_line_parser,
+    const ScenarioParameters& scenario_parameters) const {
+  // Make sure that each switch matches with the right number of arguments.
+  ScenarioParameterVectorConstIter parameter_iter;
+  for (parameter_iter = scenario_parameters.required.begin();
+       parameter_iter != scenario_parameters.required.end();
+       ++parameter_iter) {
+    CString current_switch_name = (*parameter_iter)->switch_name_;
+    // This would probably allow duplicate switches (i.e. /c /c) in a command
+    // line.
+    if (!command_line_parser.HasSwitch(current_switch_name)) {
+      return false;
+    }
+
+    int arg_count = 0;
+    HRESULT hr = command_line_parser.GetSwitchArgumentCount(current_switch_name,
+                                                            &arg_count);
+    if (FAILED(hr)) {
+      return false;
+    }
+
+    int switch_arg_count = (*parameter_iter)->num_required_parameters_;
+    if (arg_count != switch_arg_count) {
+      return false;
+    }
+  }
+
+  int parser_optional_switch_count = command_line_parser.GetSwitchCount() -
+                                     scenario_parameters.required.size();
+  for (parameter_iter = scenario_parameters.optional.begin();
+       parser_optional_switch_count != 0 &&
+           parameter_iter != scenario_parameters.optional.end();
+       ++parameter_iter) {
+    CString current_switch_name = (*parameter_iter)->switch_name_;
+    // This would probably allow duplicate optional switches (i.e. /oem /oem) in
+    // a command line.
+    if (!command_line_parser.HasSwitch(current_switch_name)) {
+      continue;
+    }
+
+    int arg_count = 0;
+    HRESULT hr = command_line_parser.GetSwitchArgumentCount(current_switch_name,
+                                                            &arg_count);
+    if (FAILED(hr)) {
+      return false;
+    }
+
+    int switch_arg_count = (*parameter_iter)->num_required_parameters_;
+    if (arg_count != switch_arg_count) {
+      return false;
+    }
+    --parser_optional_switch_count;
+  }
+
+  return parser_optional_switch_count == 0;
+}
+
+void CommandLineValidator::Clear() {
+  MapScenariosIter scenarios_iter;
+  for (scenarios_iter = scenarios_.begin();
+       scenarios_iter != scenarios_.end();
+       ++scenarios_iter) {
+    ScenarioParameterVectorIter param_iter;
+    for (param_iter = (*scenarios_iter).second.required.begin();
+         param_iter != (*scenarios_iter).second.required.end();
+         ++param_iter) {
+      delete *param_iter;
+    }
+    for (param_iter = (*scenarios_iter).second.optional.begin();
+         param_iter != (*scenarios_iter).second.optional.end();
+         ++param_iter) {
+      delete *param_iter;
+    }
+  }
+  scenarios_.clear();
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/command_line_validator.h b/goopdate/command_line_validator.h
index b2cfd30..027a865 100644
--- a/goopdate/command_line_validator.h
+++ b/goopdate/command_line_validator.h
@@ -1,108 +1,108 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_GOOPDATE_COMMAND_LINE_VALIDATOR_H__

-#define OMAHA_GOOPDATE_COMMAND_LINE_VALIDATOR_H__

-

-#include <windows.h>

-#include <atlstr.h>

-

-#include <map>

-#include <vector>

-

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class CommandLineParser;

-

-// This class allows creation of scenarios for command line combinations and

-// then provides a mechanism to validate a command line against those scenarios

-// to determine if there's a match.

-class CommandLineValidator {

- public:

-  class ScenarioParameter {

-   public:

-    ScenarioParameter(const TCHAR* switch_name, int num_required_parameters)

-      : switch_name_(switch_name),

-        num_required_parameters_(num_required_parameters) {

-    }

-    ~ScenarioParameter() {}

-

-    CString switch_name_;

-    int num_required_parameters_;

-

-   private:

-    DISALLOW_EVIL_CONSTRUCTORS(ScenarioParameter);

-  };

-

-  typedef std::vector<ScenarioParameter*> ScenarioParameterVector;

-  typedef ScenarioParameterVector::iterator ScenarioParameterVectorIter;

-  typedef ScenarioParameterVector::const_iterator

-      ScenarioParameterVectorConstIter;

-

-  struct ScenarioParameters {

-   public:

-    ScenarioParameterVector required;

-    ScenarioParameterVector optional;

-  };

-

-  typedef std::map<CString, ScenarioParameters> MapScenarios;

-  typedef MapScenarios::iterator MapScenariosIter;

-  typedef MapScenarios::const_iterator MapScenariosConstIter;

-

-  CommandLineValidator();

-  ~CommandLineValidator();

-

-  void Clear();

-

-  // Parses a command line rule and builds a scenario from it.  Returns a

-  // generated scenario name.

-  // Rules have required and optional parameters. An example of a rule is:

-  //     "gu.exe /install <extraargs> [/oem [/appargs <appargs> [/silent"

-  HRESULT CreateScenarioFromCmdLine(const CString& command_line,

-                                    CString* scenario_name);

-

-  // Validates a CommandLineParser against all scenarios.  If a match, returns

-  // S_OK and the scenario_name.  Fails if not a match.

-  // command_line_parser must already be compiled before calling.

-  HRESULT Validate(const CommandLineParser& command_line_parser,

-                   CString* scenario_name) const;

-

-  // Creates a scenario by name.

-  HRESULT CreateScenario(const CString& scenario_name);

-

-  // Adds a switch and its parameter count to an existing scenario.

-  HRESULT AddScenarioParameter(const CString& scenario_name,

-                               const CString& switch_name,

-                               int num_required_parameters);

-  HRESULT AddOptionalScenarioParameter(const CString& scenario_name,

-                                       const CString& switch_name,

-                                       int num_required_parameters);

-

- private:

-  bool DoesScenarioMatch(const CommandLineParser& command_line_parser,

-                         const ScenarioParameters& scenario_parameters) const;

-

-  int scenario_sequence_number_;

-  MapScenarios scenarios_;

-  DISALLOW_EVIL_CONSTRUCTORS(CommandLineValidator);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_COMMAND_LINE_VALIDATOR_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_GOOPDATE_COMMAND_LINE_VALIDATOR_H__
+#define OMAHA_GOOPDATE_COMMAND_LINE_VALIDATOR_H__
+
+#include <windows.h>
+#include <atlstr.h>
+
+#include <map>
+#include <vector>
+
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class CommandLineParser;
+
+// This class allows creation of scenarios for command line combinations and
+// then provides a mechanism to validate a command line against those scenarios
+// to determine if there's a match.
+class CommandLineValidator {
+ public:
+  class ScenarioParameter {
+   public:
+    ScenarioParameter(const TCHAR* switch_name, int num_required_parameters)
+      : switch_name_(switch_name),
+        num_required_parameters_(num_required_parameters) {
+    }
+    ~ScenarioParameter() {}
+
+    CString switch_name_;
+    int num_required_parameters_;
+
+   private:
+    DISALLOW_EVIL_CONSTRUCTORS(ScenarioParameter);
+  };
+
+  typedef std::vector<ScenarioParameter*> ScenarioParameterVector;
+  typedef ScenarioParameterVector::iterator ScenarioParameterVectorIter;
+  typedef ScenarioParameterVector::const_iterator
+      ScenarioParameterVectorConstIter;
+
+  struct ScenarioParameters {
+   public:
+    ScenarioParameterVector required;
+    ScenarioParameterVector optional;
+  };
+
+  typedef std::map<CString, ScenarioParameters> MapScenarios;
+  typedef MapScenarios::iterator MapScenariosIter;
+  typedef MapScenarios::const_iterator MapScenariosConstIter;
+
+  CommandLineValidator();
+  ~CommandLineValidator();
+
+  void Clear();
+
+  // Parses a command line rule and builds a scenario from it.  Returns a
+  // generated scenario name.
+  // Rules have required and optional parameters. An example of a rule is:
+  //     "gu.exe /install <extraargs> [/oem [/appargs <appargs> [/silent"
+  HRESULT CreateScenarioFromCmdLine(const CString& command_line,
+                                    CString* scenario_name);
+
+  // Validates a CommandLineParser against all scenarios.  If a match, returns
+  // S_OK and the scenario_name.  Fails if not a match.
+  // command_line_parser must already be compiled before calling.
+  HRESULT Validate(const CommandLineParser& command_line_parser,
+                   CString* scenario_name) const;
+
+  // Creates a scenario by name.
+  HRESULT CreateScenario(const CString& scenario_name);
+
+  // Adds a switch and its parameter count to an existing scenario.
+  HRESULT AddScenarioParameter(const CString& scenario_name,
+                               const CString& switch_name,
+                               int num_required_parameters);
+  HRESULT AddOptionalScenarioParameter(const CString& scenario_name,
+                                       const CString& switch_name,
+                                       int num_required_parameters);
+
+ private:
+  bool DoesScenarioMatch(const CommandLineParser& command_line_parser,
+                         const ScenarioParameters& scenario_parameters) const;
+
+  int scenario_sequence_number_;
+  MapScenarios scenarios_;
+  DISALLOW_EVIL_CONSTRUCTORS(CommandLineValidator);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_COMMAND_LINE_VALIDATOR_H__
+
diff --git a/goopdate/command_line_validator_unittest.cc b/goopdate/command_line_validator_unittest.cc
index e6ee3d9..60ab516 100644
--- a/goopdate/command_line_validator_unittest.cc
+++ b/goopdate/command_line_validator_unittest.cc
@@ -1,130 +1,130 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/command_line_validator.h"

-

-#include "omaha/goopdate/command_line_parser.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-const TCHAR* kScenario1Name = _T("core");

-const TCHAR* kScenario2Name = _T("SomeScenario");

-const TCHAR* kScenario3Name = _T("OtherMechanism");

-

-const TCHAR* kScenario1CmdLine = _T("program.exe /lang foo");

-const TCHAR* kScenario2CmdLine = _T("program.exe /install x y /service");

-const TCHAR* kScenario3CmdLine = _T("prog.exe /install x y /service /lang en");

-

-const TCHAR* kLangSwitch = _T("lang");

-const int kLangSwitchArgCount = 1;

-const TCHAR* kInstallSwitch = _T("install");

-const int kInstallSwitchArgCount = 2;

-const TCHAR* kServiceSwitch = _T("service");

-const int kServiceSwitchArgCount = 0;

-

-class CommandLineValidatorTest : public testing::Test {

- public:

-

- protected:

-  CommandLineValidatorTest() {

-  }

-

-  virtual void SetUp() {

-    scenario_match_name_.Empty();

-

-    // This validator only has one scenario.

-    validator1_.Clear();

-    // "program.exe /lang foo"

-    validator1_.CreateScenario(kScenario1Name);

-    validator1_.AddScenarioParameter(kScenario1Name,

-                                     kLangSwitch,

-                                     kLangSwitchArgCount);

-

-    // This validator has three scenarios.

-    validator2_.Clear();

-    // "program.exe /lang foo"

-    validator2_.CreateScenario(kScenario1Name);

-    validator2_.AddScenarioParameter(kScenario1Name,

-                                     kLangSwitch,

-                                     kLangSwitchArgCount);

-

-    // "program.exe /install x y /service"

-    validator2_.CreateScenario(kScenario2Name);

-    validator2_.AddScenarioParameter(kScenario2Name,

-                                     kInstallSwitch,

-                                     kInstallSwitchArgCount);

-    validator2_.AddScenarioParameter(kScenario2Name,

-                                     kServiceSwitch,

-                                     kServiceSwitchArgCount);

-

-    // "program.exe /install x y /service /lang en"

-    validator2_.CreateScenario(kScenario3Name);

-    validator2_.AddScenarioParameter(kScenario3Name,

-                                     kInstallSwitch,

-                                     kInstallSwitchArgCount);

-    validator2_.AddScenarioParameter(kScenario3Name,

-                                     kServiceSwitch,

-                                     kServiceSwitchArgCount);

-    validator2_.AddScenarioParameter(kScenario3Name,

-                                     kLangSwitch,

-                                     kLangSwitchArgCount);

-  }

-

-  virtual void TearDown() {

-  }

-

-  CommandLineValidator validator1_;

-  CommandLineValidator validator2_;

-  CommandLineParser parser_;

-  CString scenario_match_name_;

-};

-

-TEST_F(CommandLineValidatorTest, BasicScenarioPass) {

-  EXPECT_SUCCEEDED(parser_.ParseFromString(kScenario1CmdLine));

-  EXPECT_SUCCEEDED(validator1_.Validate(parser_, &scenario_match_name_));

-  EXPECT_STREQ(kScenario1Name, scenario_match_name_);

-}

-

-TEST_F(CommandLineValidatorTest, BasicScenarioFail) {

-  EXPECT_SUCCEEDED(parser_.ParseFromString(_T("goopdate.exe /something bad")));

-  EXPECT_FAILED(validator1_.Validate(parser_, &scenario_match_name_));

-}

-

-TEST_F(CommandLineValidatorTest, Scenario1PassMulti) {

-  EXPECT_SUCCEEDED(parser_.ParseFromString(kScenario1CmdLine));

-  EXPECT_SUCCEEDED(validator2_.Validate(parser_, &scenario_match_name_));

-  EXPECT_STREQ(kScenario1Name, scenario_match_name_);

-}

-

-TEST_F(CommandLineValidatorTest, Scenario2PassMulti) {

-  EXPECT_SUCCEEDED(parser_.ParseFromString(kScenario2CmdLine));

-  EXPECT_SUCCEEDED(validator2_.Validate(parser_, &scenario_match_name_));

-  EXPECT_STREQ(kScenario2Name, scenario_match_name_);

-}

-

-TEST_F(CommandLineValidatorTest, Scenario3PassMulti) {

-  EXPECT_SUCCEEDED(parser_.ParseFromString(kScenario3CmdLine));

-  EXPECT_SUCCEEDED(validator2_.Validate(parser_, &scenario_match_name_));

-  EXPECT_STREQ(kScenario3Name, scenario_match_name_);

-}

-

-TEST_F(CommandLineValidatorTest, ScenarioFailMulti) {

-  EXPECT_SUCCEEDED(parser_.ParseFromString(_T("Goopdate.exe /fail me /here")));

-  EXPECT_FAILED(validator2_.Validate(parser_, &scenario_match_name_));

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/command_line_validator.h"
+
+#include "omaha/goopdate/command_line_parser.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+const TCHAR* kScenario1Name = _T("core");
+const TCHAR* kScenario2Name = _T("SomeScenario");
+const TCHAR* kScenario3Name = _T("OtherMechanism");
+
+const TCHAR* kScenario1CmdLine = _T("program.exe /lang foo");
+const TCHAR* kScenario2CmdLine = _T("program.exe /install x y /service");
+const TCHAR* kScenario3CmdLine = _T("prog.exe /install x y /service /lang en");
+
+const TCHAR* kLangSwitch = _T("lang");
+const int kLangSwitchArgCount = 1;
+const TCHAR* kInstallSwitch = _T("install");
+const int kInstallSwitchArgCount = 2;
+const TCHAR* kServiceSwitch = _T("service");
+const int kServiceSwitchArgCount = 0;
+
+class CommandLineValidatorTest : public testing::Test {
+ public:
+
+ protected:
+  CommandLineValidatorTest() {
+  }
+
+  virtual void SetUp() {
+    scenario_match_name_.Empty();
+
+    // This validator only has one scenario.
+    validator1_.Clear();
+    // "program.exe /lang foo"
+    validator1_.CreateScenario(kScenario1Name);
+    validator1_.AddScenarioParameter(kScenario1Name,
+                                     kLangSwitch,
+                                     kLangSwitchArgCount);
+
+    // This validator has three scenarios.
+    validator2_.Clear();
+    // "program.exe /lang foo"
+    validator2_.CreateScenario(kScenario1Name);
+    validator2_.AddScenarioParameter(kScenario1Name,
+                                     kLangSwitch,
+                                     kLangSwitchArgCount);
+
+    // "program.exe /install x y /service"
+    validator2_.CreateScenario(kScenario2Name);
+    validator2_.AddScenarioParameter(kScenario2Name,
+                                     kInstallSwitch,
+                                     kInstallSwitchArgCount);
+    validator2_.AddScenarioParameter(kScenario2Name,
+                                     kServiceSwitch,
+                                     kServiceSwitchArgCount);
+
+    // "program.exe /install x y /service /lang en"
+    validator2_.CreateScenario(kScenario3Name);
+    validator2_.AddScenarioParameter(kScenario3Name,
+                                     kInstallSwitch,
+                                     kInstallSwitchArgCount);
+    validator2_.AddScenarioParameter(kScenario3Name,
+                                     kServiceSwitch,
+                                     kServiceSwitchArgCount);
+    validator2_.AddScenarioParameter(kScenario3Name,
+                                     kLangSwitch,
+                                     kLangSwitchArgCount);
+  }
+
+  virtual void TearDown() {
+  }
+
+  CommandLineValidator validator1_;
+  CommandLineValidator validator2_;
+  CommandLineParser parser_;
+  CString scenario_match_name_;
+};
+
+TEST_F(CommandLineValidatorTest, BasicScenarioPass) {
+  EXPECT_SUCCEEDED(parser_.ParseFromString(kScenario1CmdLine));
+  EXPECT_SUCCEEDED(validator1_.Validate(parser_, &scenario_match_name_));
+  EXPECT_STREQ(kScenario1Name, scenario_match_name_);
+}
+
+TEST_F(CommandLineValidatorTest, BasicScenarioFail) {
+  EXPECT_SUCCEEDED(parser_.ParseFromString(_T("goopdate.exe /something bad")));
+  EXPECT_FAILED(validator1_.Validate(parser_, &scenario_match_name_));
+}
+
+TEST_F(CommandLineValidatorTest, Scenario1PassMulti) {
+  EXPECT_SUCCEEDED(parser_.ParseFromString(kScenario1CmdLine));
+  EXPECT_SUCCEEDED(validator2_.Validate(parser_, &scenario_match_name_));
+  EXPECT_STREQ(kScenario1Name, scenario_match_name_);
+}
+
+TEST_F(CommandLineValidatorTest, Scenario2PassMulti) {
+  EXPECT_SUCCEEDED(parser_.ParseFromString(kScenario2CmdLine));
+  EXPECT_SUCCEEDED(validator2_.Validate(parser_, &scenario_match_name_));
+  EXPECT_STREQ(kScenario2Name, scenario_match_name_);
+}
+
+TEST_F(CommandLineValidatorTest, Scenario3PassMulti) {
+  EXPECT_SUCCEEDED(parser_.ParseFromString(kScenario3CmdLine));
+  EXPECT_SUCCEEDED(validator2_.Validate(parser_, &scenario_match_name_));
+  EXPECT_STREQ(kScenario3Name, scenario_match_name_);
+}
+
+TEST_F(CommandLineValidatorTest, ScenarioFailMulti) {
+  EXPECT_SUCCEEDED(parser_.ParseFromString(_T("Goopdate.exe /fail me /here")));
+  EXPECT_FAILED(validator2_.Validate(parser_, &scenario_match_name_));
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/config_manager.cc b/goopdate/config_manager.cc
index 1f16b10..36825c8 100644
--- a/goopdate/config_manager.cc
+++ b/goopdate/config_manager.cc
@@ -1,872 +1,872 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/config_manager.h"

-#include <lm.h>

-#include <shlobj.h>

-#include <shlwapi.h>

-#include <wininet.h>

-#include <atlstr.h>

-#include <math.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/service_utils.h"

-#include "omaha/common/string.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/enterprise/const_group_policy.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource.h"

-

-namespace omaha {

-

-namespace {

-

-HRESULT GetDir(int csidl,

-               const CString& path_tail,

-               bool create_dir,

-               CString* dir) {

-  ASSERT1(dir);

-

-  CString path;

-  HRESULT hr = GetFolderPath(csidl | CSIDL_FLAG_DONT_VERIFY, &path);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (!::PathAppend(CStrBuf(path, MAX_PATH), path_tail)) {

-    return GOOPDATE_E_PATH_APPEND_FAILED;

-  }

-  dir->SetString(path);

-

-  // Try to create the directory. Continue if the directory can't be created.

-  if (create_dir) {

-    hr = CreateDir(path, NULL);

-    if (FAILED(hr)) {

-      CORE_LOG(LE, (_T("[GetDir failed to create dir][%s][0x%08x]"), path, hr));

-    }

-  }

-  return S_OK;

-}

-

-// The app-specific value overrides the disable all value so read the former

-// first. If it doesn't exist, read the "disable all" value.

-bool GetEffectivePolicyForApp(const TCHAR* apps_default_value_name,

-                              const TCHAR* app_prefix_name,

-                              const GUID& app_guid,

-                              DWORD* effective_policy) {

-  ASSERT1(apps_default_value_name);

-  ASSERT1(app_prefix_name);

-  ASSERT1(effective_policy);

-

-  CString app_value_name(app_prefix_name);

-  app_value_name.Append(GuidToString(app_guid));

-

-  HRESULT hr = RegKey::GetValue(kRegKeyGoopdateGroupPolicy,

-                                app_value_name,

-                                effective_policy);

-  if (SUCCEEDED(hr)) {

-    return true;

-  } else {

-    CORE_LOG(L4, (_T("[Failed to read Group Policy value][%s]"),

-                  app_value_name));

-  }

-

-  hr = RegKey::GetValue(kRegKeyGoopdateGroupPolicy,

-                        apps_default_value_name,

-                        effective_policy);

-  if (SUCCEEDED(hr)) {

-    return true;

-  } else {

-    CORE_LOG(L4, (_T("[Failed to read Group Policy value][%s]"),

-                  apps_default_value_name));

-  }

-

-  return false;

-}

-

-// Gets the raw update check period override value in seconds from the registry.

-// The value must be processed for limits and overflow before using.

-// Checks UpdateDev and Group Policy.

-// Returns true if either override was successefully read.

-bool GetLastCheckPeriodSecFromRegistry(DWORD* period_sec) {

-  ASSERT1(period_sec);

-

-  DWORD update_dev_sec = 0;

-  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                 kRegValueLastCheckPeriodSec,

-                                 &update_dev_sec))) {

-    CORE_LOG(L5, (_T("['LastCheckPeriodSec' override %d]"), update_dev_sec));

-    *period_sec = update_dev_sec;

-    return true;

-  }

-

-  DWORD group_policy_minutes = 0;

-  if (SUCCEEDED(RegKey::GetValue(kRegKeyGoopdateGroupPolicy,

-                                 kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                                 &group_policy_minutes))) {

-    CORE_LOG(L5, (_T("[Group Policy check period override %d]"),

-                  group_policy_minutes));

-

-

-    *period_sec = (group_policy_minutes > UINT_MAX / 60) ?

-                  UINT_MAX :

-                  group_policy_minutes * 60;

-

-    return true;

-  }

-

-  return false;

-}

-

-}  // namespace

-

-LLock ConfigManager::lock_;

-ConfigManager* ConfigManager::config_manager_ = NULL;

-

-ConfigManager* ConfigManager::Instance() {

-  __mutexScope(lock_);

-  if (!config_manager_) {

-    config_manager_ = new ConfigManager();

-  }

-  return config_manager_;

-}

-

-void ConfigManager::DeleteInstance() {

-  delete config_manager_;

-}

-

-CString ConfigManager::GetUserDownloadStorageDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,

-                           CString(OMAHA_REL_DOWNLOAD_STORAGE_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-CString ConfigManager::GetUserOfflineStorageDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,

-                           CString(OMAHA_REL_OFFLINE_STORAGE_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-CString ConfigManager::GetUserInitialManifestStorageDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,

-                           CString(OMAHA_REL_INITIAL_MANIFEST_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-CString ConfigManager::GetUserGoopdateInstallDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,

-                           CString(OMAHA_REL_GOOPDATE_INSTALL_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-bool ConfigManager::IsRunningFromUserGoopdateInstallDir() const {

-  CString path;

-  HRESULT hr = GetDir(CSIDL_LOCAL_APPDATA,

-                      CString(OMAHA_REL_GOOPDATE_INSTALL_DIR),

-                      false,

-                      &path);

-  if (FAILED(hr)) {

-    return false;

-  }

-

-  return (String_StrNCmp(path,

-                         app_util::GetCurrentModuleDirectory(),

-                         path.GetLength(),

-                         true) == 0);

-}

-

-CString ConfigManager::GetUserCrashReportsDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,

-                           CString(OMAHA_REL_CRASH_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-CString ConfigManager::GetMachineCrashReportsDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES,

-                           CString(OMAHA_REL_CRASH_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-CString ConfigManager::GetMachineDownloadStorageDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_COMMON_APPDATA,

-                           CString(OMAHA_REL_DOWNLOAD_STORAGE_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-CString ConfigManager::GetMachineSecureDownloadStorageDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES,

-                           CString(OMAHA_REL_DOWNLOAD_STORAGE_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-CString ConfigManager::GetMachineSecureOfflineStorageDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES,

-                           CString(OMAHA_REL_OFFLINE_STORAGE_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-CString ConfigManager::GetTempDownloadDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,

-                           CString(OMAHA_REL_TEMP_DOWNLOAD_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-CString ConfigManager::GetMachineGoopdateInstallDir() const {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES,

-                           CString(OMAHA_REL_GOOPDATE_INSTALL_DIR),

-                           true,

-                           &path)));

-  return path;

-}

-

-bool ConfigManager::IsRunningFromMachineGoopdateInstallDir() const {

-  CString path;

-  HRESULT hr = GetDir(CSIDL_PROGRAM_FILES,

-                      CString(OMAHA_REL_GOOPDATE_INSTALL_DIR),

-                      false,

-                      &path);

-  if (FAILED(hr)) {

-    return false;

-  }

-

-  return (String_StrNCmp(path,

-                         app_util::GetCurrentModuleDirectory(),

-                         path.GetLength(),

-                         true) == 0);

-}

-

-// TODO(omaha): create a generic way to override configuration parameters.

-//

-// Overrides PingUrl in debug builds.

-HRESULT ConfigManager::GetPingUrl(CString* url) const {

-  ASSERT1(url);

-

-#ifdef DEBUG

-  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                 kRegValueNamePingUrl,

-                                 url))) {

-    CORE_LOG(L5, (_T("['ping url' override %s]"), *url));

-    return S_OK;

-  }

-#endif

-

-  *url = kUrlPing;

-  return S_OK;

-}

-

-// Overrides Url (update check url) in debug builds.

-HRESULT ConfigManager::GetUpdateCheckUrl(CString* url) const {

-  ASSERT1(url);

-

-#ifdef DEBUG

-  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                 kRegValueNameUrl,

-                                 url))) {

-    CORE_LOG(L5, (_T("['url' override %s]"), *url));

-    return S_OK;

-  }

-#endif

-

-  *url = kUrlUpdateCheck;

-  return S_OK;

-}

-

-HRESULT ConfigManager::GetWebPluginCheckUrl(CString* url) const {

-  ASSERT1(url);

-

-#ifdef DEBUG

-  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                 kRegValueNameWebPluginUrl,

-                                 url))) {

-    CORE_LOG(L5, (_T("['webplugin url' override %s]"), *url));

-    return S_OK;

-  }

-#endif

-  *url = kUrlWebPluginCheck;

-  return S_OK;

-}

-

-// Returns the override from the registry locations if present. Otherwise,

-// returns the default value.

-// Default value is different value for Googlers, to make update checks more

-// aggresive.

-// Ensures returned value is between kMinLastCheckPeriodSec and INT_MAX except

-// when the override is 0, which indicates updates are disabled.

-int ConfigManager::GetLastCheckPeriodSec(bool* is_overridden) const {

-  ASSERT1(is_overridden);

-  DWORD registry_period_sec = 0;

-  *is_overridden = GetLastCheckPeriodSecFromRegistry(&registry_period_sec);

-  if (*is_overridden) {

-    if (0 == registry_period_sec) {

-      return 0;

-    }

-    const int period_sec = registry_period_sec > INT_MAX ?

-                           INT_MAX :

-                           static_cast<int>(registry_period_sec);

-

-    if (period_sec < kMinLastCheckPeriodSec) {

-      return kMinLastCheckPeriodSec;

-    }

-    return period_sec;

-  }

-

-  // Returns a lower value for Googlers.

-  if (IsGoogler()) {

-    return kLastCheckPeriodGooglerSec;

-  }

-

-  return kLastCheckPeriodSec;

-}

-

-// All time values are in seconds.

-int ConfigManager::GetTimeSinceLastCheckedSec(bool is_machine) const {

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-  const uint32 last_checked = GetLastCheckedTime(is_machine);

-  if (now < last_checked) {

-    CORE_LOG(LW, (_T("[possible time warp detected]")

-                  _T("[now %u][last checked %u]"), now, last_checked));

-  }

-  const int time_difference = abs(static_cast<int>(now - last_checked));

-  bool is_period_overridden = false;

-  CORE_LOG(L3, (_T("[now %u][last checked %u][update interval %u]")

-                _T("[time difference %u]"),

-                now, last_checked, GetLastCheckPeriodSec(&is_period_overridden),

-                time_difference));

-  return time_difference;

-}

-

-DWORD ConfigManager::GetLastCheckedTime(bool is_machine) const {

-  const TCHAR* reg_update_key = is_machine ? MACHINE_REG_UPDATE:

-                                             USER_REG_UPDATE;

-  DWORD last_checked_time = 0;

-  if (SUCCEEDED(RegKey::GetValue(reg_update_key,

-                                 kRegValueLastChecked,

-                                 &last_checked_time))) {

-    return last_checked_time;

-  }

-  return 0;

-}

-

-HRESULT ConfigManager::SetLastCheckedTime(bool is_machine, DWORD time) const {

-  const TCHAR* reg_update_key = is_machine ? MACHINE_REG_UPDATE:

-                                             USER_REG_UPDATE;

-  return RegKey::SetValue(reg_update_key, kRegValueLastChecked, time);

-}

-

-DWORD ConfigManager::GetInstallTime(bool is_machine) {

-  const CString client_state_key_name =

-      ConfigManager::Instance()->registry_client_state_goopdate(is_machine);

-  DWORD update_time(0);

-  if (SUCCEEDED(RegKey::GetValue(client_state_key_name,

-                                 kRegValueLastUpdateTimeSec,

-                                 &update_time))) {

-    return update_time;

-  }

-

-  DWORD install_time(0);

-  if (SUCCEEDED(RegKey::GetValue(client_state_key_name,

-                                 kRegValueInstallTimeSec,

-                                 &install_time))) {

-    return install_time;

-  }

-

-  return 0;

-}

-

-bool ConfigManager::Is24HoursSinceInstall(bool is_machine) {

-  const int kDaySec = 24 * 60 * 60;

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  const uint32 install_time = GetInstallTime(is_machine);

-  if (now < install_time) {

-    CORE_LOG(LW, (_T("[Incorrect clock time detected]")

-                  _T("[now %u][install_time %u]"), now, install_time));

-  }

-  const int time_difference = abs(static_cast<int>(now - install_time));

-  return time_difference >= kDaySec;

-}

-

-bool ConfigManager::CanCollectStats(bool is_machine) const {

-  if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueForceUsageStats)) {

-    return true;

-  }

-

-  // TODO(omaha): This should actually be iterating over registered products

-  // rather than present ClientState keys. These are identical in most cases.

-  const TCHAR* state_key_name = registry_client_state(is_machine);

-

-  RegKey state_key;

-  HRESULT hr = state_key.Open(state_key_name, KEY_READ);

-  if (FAILED(hr)) {

-    return false;

-  }

-

-  int num_sub_keys = state_key.GetSubkeyCount();

-  for (int i = 0; i < num_sub_keys; ++i) {

-    CString sub_key_name;

-    if (FAILED(state_key.GetSubkeyNameAt(i, &sub_key_name))) {

-      continue;

-    }

-

-    if (goopdate_utils::AreAppUsageStatsEnabled(is_machine, sub_key_name)) {

-      return true;

-    }

-  }

-

-  return false;

-}

-

-// Overrides OverInstall in debug builds.

-bool ConfigManager::CanOverInstall() const {

-#ifdef DEBUG

-  DWORD value = 0;

-  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                 kRegValueNameOverInstall,

-                                 &value))) {

-    CORE_LOG(L5, (_T("['OverInstall' override %d]"), value));

-    return value != 0;

-  }

-#endif

-  return !OFFICIAL_BUILD;

-}

-

-// Overrides AuCheckPeriodMs. Implements a lower bound value. Returns INT_MAX

-// if the registry value exceeds INT_MAX.

-int ConfigManager::GetAutoUpdateTimerIntervalMs() const {

-  DWORD interval(0);

-  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                 kRegValueAuCheckPeriodMs,

-                                 &interval))) {

-    int ret_val = 0;

-    if (interval > INT_MAX) {

-      ret_val = INT_MAX;

-    } else if (interval < kMinAUCheckPeriodMs) {

-      ret_val = kMinAUCheckPeriodMs;

-    } else {

-      ret_val = interval;

-    }

-    ASSERT1(ret_val >= kMinAUCheckPeriodMs);

-    CORE_LOG(L5, (_T("['AuCheckPeriodMs' override %d]"), interval));

-    return ret_val;

-  }

-

-  // Returns a lower value for Googlers.

-  if (IsGoogler()) {

-    return kAUCheckPeriodGooglerMs;

-  }

-

-  return kAUCheckPeriodMs;

-}

-

-int ConfigManager::GetUpdateWorkerStartUpDelayMs() const {

-  int au_timer_interval_ms = GetAutoUpdateTimerIntervalMs();

-

-  // If the AuCheckPeriod is overriden then use that as the delay.

-  if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueAuCheckPeriodMs)) {

-    return au_timer_interval_ms;

-  }

-

-  int random_delay = 0;

-  if (!GenRandom(&random_delay, sizeof(random_delay))) {

-    return au_timer_interval_ms;

-  }

-

-  // Scale the au_check_period number to be between

-  // kUpdateTimerStartupDelayMinMs and kUpdateTimerStartupDelayMaxMs.

-  int scale = kUpdateTimerStartupDelayMaxMs - kUpdateTimerStartupDelayMinMs;

-  ASSERT1(scale >= 0);

-

-  int random_addition = abs(random_delay) % scale;

-  ASSERT1(random_addition < scale);

-

-  au_timer_interval_ms = kUpdateTimerStartupDelayMinMs + random_addition;

-  ASSERT1(au_timer_interval_ms >= kUpdateTimerStartupDelayMinMs &&

-          au_timer_interval_ms <= kUpdateTimerStartupDelayMaxMs);

-

-  return au_timer_interval_ms;

-}

-

-// Overrides CodeRedCheckPeriodMs. Implements a lower bound value. Returns

-// INT_MAX if the registry value exceeds INT_MAX.

-int ConfigManager::GetCodeRedTimerIntervalMs() const {

-  DWORD interval(0);

-  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                 kRegValueCrCheckPeriodMs,

-                                 &interval))) {

-    int ret_val = 0;

-    if (interval > INT_MAX) {

-      ret_val = INT_MAX;

-    } else if (interval < kMinCodeRedCheckPeriodMs) {

-      ret_val = kMinCodeRedCheckPeriodMs;

-    } else {

-      ret_val = interval;

-    }

-    ASSERT1(ret_val >= kMinCodeRedCheckPeriodMs);

-    CORE_LOG(L5, (_T("['CrCheckPeriodMs' override %d]"), interval));

-    return ret_val;

-  }

-  return kCodeRedCheckPeriodMs;

-}

-

-// Returns true if logging is enabled for the event type.

-// Logging of errors and warnings is enabled by default.

-bool ConfigManager::CanLogEvents(WORD event_type) const {

-  const TCHAR* reg_update_key = MACHINE_REG_UPDATE_DEV;

-  DWORD log_events_level = LOG_EVENT_LEVEL_NONE;

-  if (SUCCEEDED(RegKey::GetValue(reg_update_key,

-                                 kRegValueEventLogLevel,

-                                 &log_events_level))) {

-    switch (log_events_level) {

-      case LOG_EVENT_LEVEL_ALL:

-        return true;

-      case LOG_EVENT_LEVEL_WARN_AND_ERROR:

-        return event_type == EVENTLOG_ERROR_TYPE ||

-               event_type == EVENTLOG_WARNING_TYPE;

-      case LOG_EVENT_LEVEL_NONE:

-      default:

-        return false;

-    }

-  }

-

-  return event_type == EVENTLOG_ERROR_TYPE ||

-         event_type == EVENTLOG_WARNING_TYPE;

-}

-

-CString ConfigManager::GetTestSource() const {

-  CString test_source;

-  HRESULT hr = RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                kRegValueTestSource,

-                                &test_source);

-  if (SUCCEEDED(hr)) {

-    if (test_source.IsEmpty()) {

-      test_source = kRegValueTestSourceAuto;

-    }

-    return test_source;

-  }

-

-  DWORD interval = 0;

-  hr = RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                        kRegValueAuCheckPeriodMs,

-                        &interval);

-  if (SUCCEEDED(hr)) {

-    return kRegValueTestSourceAuto;

-  }

-

-#if defined(DEBUG) || !OFFICIAL_BUILD

-  test_source = kRegValueTestSourceAuto;

-#endif

-

-  return test_source;

-}

-

-// Reads the current value under HKLM/HKCU\Google\Update\value_name. Returns

-// default_val if value_name does not exist.

-CString GetCurrentVersionedName(bool is_machine,

-                                const TCHAR* value_name,

-                                const TCHAR* default_val) {

-  CORE_LOG(L3, (_T("[ConfigManager::GetCurrentVersionedName]")));

-  ASSERT1(value_name && *value_name);

-  ASSERT1(default_val && *default_val);

-

-  const TCHAR* key_name = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE;

-  CString name;

-  HRESULT hr(RegKey::GetValue(key_name, value_name, &name));

-  if (FAILED(hr)) {

-    CORE_LOG(L4, (_T("[GetValue failed][%s][0x%x][Using default name][%s]"),

-                  value_name, hr, default_val));

-    name = default_val;

-  }

-

-  CORE_LOG(L3, (_T("[Versioned Name][%s]"), name));

-  return name;

-}

-

-// Creates a unique name of the form "{prefix}1c9b3d6baf90df3" and stores it in

-// the registry under HKLM/HKCU\Google\Update\value_name. Subsequent

-// invocations of GetCurrentTaskName() will return this new value.

-HRESULT CreateAndSetVersionedNameInRegistry(bool is_machine,

-                                            const TCHAR* prefix,

-                                            const TCHAR* value_name) {

-  ASSERT1(prefix && *prefix);

-  ASSERT1(value_name && *value_name);

-

-  CString name(ServiceInstall::GenerateServiceName(prefix));

-  CORE_LOG(L3, (_T("Versioned name[%s][%s][%s]"), prefix, value_name, name));

-

-  const TCHAR* key_name = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE;

-  return RegKey::SetValue(key_name, value_name, name);

-}

-

-CString ConfigManager::GetCurrentTaskNameCore(bool is_machine) {

-  CORE_LOG(L3, (_T("[GetCurrentTaskNameCore[%d]"), is_machine));

-

-  CString default_name(goopdate_utils::GetDefaultGoopdateTaskName(

-                                           is_machine,

-                                           COMMANDLINE_MODE_CORE));

-  return GetCurrentVersionedName(is_machine, kRegValueTaskNameC, default_name);

-}

-

-HRESULT ConfigManager::CreateAndSetVersionedTaskNameCoreInRegistry(

-    bool is_machine) {

-  CORE_LOG(L3, (_T("CreateAndSetVersionedTaskNameCoreInRegistry[%d]"),

-                is_machine));

-

-  CString default_name(goopdate_utils::GetDefaultGoopdateTaskName(

-                                           is_machine,

-                                           COMMANDLINE_MODE_CORE));

-  return CreateAndSetVersionedNameInRegistry(is_machine,

-                                             default_name,

-                                             kRegValueTaskNameC);

-}

-

-CString ConfigManager::GetCurrentTaskNameUA(bool is_machine) {

-  CORE_LOG(L3, (_T("[GetCurrentTaskNameUA[%d]"), is_machine));

-

-  CString default_name(goopdate_utils::GetDefaultGoopdateTaskName(

-                                           is_machine,

-                                           COMMANDLINE_MODE_UA));

-  return GetCurrentVersionedName(is_machine, kRegValueTaskNameUA, default_name);

-}

-

-HRESULT ConfigManager::CreateAndSetVersionedTaskNameUAInRegistry(bool machine) {

-  CORE_LOG(L3, (_T("CreateAndSetVersionedTaskNameUAInRegistry[%d]"), machine));

-

-  CString default_name(goopdate_utils::GetDefaultGoopdateTaskName(

-                                           machine,

-                                           COMMANDLINE_MODE_UA));

-  return CreateAndSetVersionedNameInRegistry(machine,

-                                             default_name,

-                                             kRegValueTaskNameUA);

-}

-

-CString ConfigManager::GetCurrentServiceName() {

-  CORE_LOG(L3, (_T("[ConfigManager::GetCurrentServiceName]")));

-  return GetCurrentVersionedName(true,

-                                 kRegValueServiceName,

-                                 kLegacyServiceName);

-}

-

-CString ConfigManager::GetCurrentServiceDisplayName() {

-  CORE_LOG(L3, (_T("[ConfigManager::GetCurrentServiceDisplayName]")));

-  CString display_name;

-  VERIFY1(display_name.LoadString(IDS_SERVICE_DISPLAY_NAME));

-  display_name.AppendFormat(_T(" (%s)"), GetCurrentServiceName());

-  return display_name;

-}

-

-HRESULT ConfigManager::CreateAndSetVersionedServiceNameInRegistry() {

-  CORE_LOG(L3, (_T("CreateAndSetVersionedServiceNameInRegistry")));

-  return CreateAndSetVersionedNameInRegistry(true,

-                                             kServicePrefix,

-                                             kRegValueServiceName);

-}

-

-HRESULT ConfigManager::GetNetConfig(CString* net_config) {

-  ASSERT1(net_config);

-  CString val;

-  HRESULT hr = RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                kRegValueNetConfig,

-                                &val);

-  if (SUCCEEDED(hr)) {

-    *net_config = val;

-  }

-  return hr;

-}

-

-// Returns false if running in the context of an OEM install or waiting for a

-// EULA to be accepted.

-bool ConfigManager::CanUseNetwork(bool is_machine) const {

-  DWORD eula_accepted(0);

-  HRESULT hr = RegKey::GetValue(registry_update(is_machine),

-                                kRegValueOmahaEulaAccepted,

-                                &eula_accepted);

-  if (SUCCEEDED(hr) && 0 == eula_accepted) {

-    CORE_LOG(L3, (_T("[CanUseNetwork][eulaaccepted=0][false]")));

-    return false;

-  }

-

-  if (IsOemInstalling(is_machine)) {

-    CORE_LOG(L3, (_T("[CanUseNetwork][OEM installing][false]")));

-    return false;

-  }

-

-  return true;

-}

-

-// Always returns false if !is_machine. This prevents ever blocking per-user

-// instances.

-// Returns true if in audit mode and OEM install time is present. Requiring the

-// OEM install time prevents ever blocking non-OEM installs from updating.

-// Also returns true if less than kMinOemModeMs since the OEM install.

-bool ConfigManager::IsOemInstalling(bool is_machine) const {

-  if (!is_machine) {

-    return false;

-  }

-

-  DWORD oem_install_time_seconds = 0;

-  if (FAILED(RegKey::GetValue(MACHINE_REG_UPDATE,

-                              kRegValueOemInstallTimeSec,

-                              &oem_install_time_seconds))) {

-    CORE_LOG(L3, (_T("[IsOemInstalling][OemInstallTime not found][false]")));

-    return false;

-  }

-

-  if (IsWindowsInstalling()) {

-    CORE_LOG(L3, (_T("[IsOemInstalling][IsWindowsInstalling][true]")));

-    return true;

-  }

-

-  const uint32 now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  if (now_seconds < oem_install_time_seconds) {

-    CORE_LOG(LW, (_T("[possible time warp detected][now %u][last checked %u]"),

-                  now_seconds, oem_install_time_seconds));

-  }

-  const int time_difference_seconds =

-      abs(static_cast<int>(now_seconds - oem_install_time_seconds));

-

-  ASSERT1(0 <= time_difference_seconds);

-  const uint32 kMinOemModeSeconds = kMinOemModeMs / kMsPerSec;

-  const bool result = time_difference_seconds < kMinOemModeSeconds ? true :

-                                                                     false;

-

-  CORE_LOG(L3, (_T("[now %u][OEM install time %u][time difference %u][%d]"),

-                now_seconds, oem_install_time_seconds, time_difference_seconds,

-                result));

-  return result;

-}

-

-// USE IsOemInstalling() INSTEAD in most cases.

-bool ConfigManager::IsWindowsInstalling() const {

-#if !OFFICIAL_BUILD

-  DWORD value = 0;

-  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                 kRegValueNameWindowsInstalling,

-                                 &value))) {

-    CORE_LOG(L3, (_T("['WindowsInstalling' override %d]"), value));

-    return value != 0;

-  }

-#endif

-

-  return omaha::IsWindowsInstalling();

-}

-

-// Checks if the computer name ends with .google.com or the netbios domain is

-// google.

-bool ConfigManager::IsGoogler() const {

-  CORE_LOG(L4, (_T("[ConfigManager::IsGoogler]")));

-  TCHAR dns_name[INTERNET_MAX_HOST_NAME_LENGTH] = {0};

-  DWORD dns_name_size(arraysize(dns_name));

-  if (::GetComputerNameEx(ComputerNameDnsFullyQualified,

-                          dns_name, &dns_name_size)) {

-     CORE_LOG(L4, (_T("[dns name %s]"), dns_name));

-     if (String_EndsWith(dns_name, _T(".google.com"), true)) {

-       return true;

-     }

-  }

-

-  WKSTA_INFO_100* info = NULL;

-  int kInformationLevel = 100;

-  NET_API_STATUS status = ::NetWkstaGetInfo(NULL,

-                                            kInformationLevel,

-                                            reinterpret_cast<BYTE**>(&info));

-  ON_SCOPE_EXIT(::NetApiBufferFree, info);

-  if (status == NERR_Success) {

-    CORE_LOG(L4, (_T("[netbios name %s]"), info->wki100_langroup));

-    if (info->wki100_langroup &&

-        _tcsicmp(info->wki100_langroup, _T("google")) == 0) {

-      return true;

-    }

-  }

-  return false;

-}

-

-bool ConfigManager::CanInstallApp(const GUID& app_guid) const {

-  // Google Update should never be checking whether it can install itself.

-  ASSERT1(!::IsEqualGUID(kGoopdateGuid, app_guid));

-

-  DWORD effective_policy = 0;

-  if (!GetEffectivePolicyForApp(kRegValueInstallAppsDefault,

-                                kRegValueInstallAppPrefix,

-                                app_guid,

-                                &effective_policy)) {

-    return kInstallPolicyDefault;

-  }

-

-  return kPolicyDisabled != effective_policy;

-}

-

-// Self-updates cannot be disabled.

-bool ConfigManager::CanUpdateApp(const GUID& app_guid,

-                                 bool is_manual) const {

-  if (::IsEqualGUID(kGoopdateGuid, app_guid)) {

-    return true;

-  }

-

-  DWORD effective_policy = 0;

-  if (!GetEffectivePolicyForApp(kRegValueUpdateAppsDefault,

-                                kRegValueUpdateAppPrefix,

-                                app_guid,

-                                &effective_policy)) {

-    return kUpdatePolicyDefault;

-  }

-

-  if (kPolicyDisabled == effective_policy) {

-    return false;

-  }

-  if ((kPolicyManualUpdatesOnly == effective_policy) && !is_manual) {

-    return false;

-  }

-

-  return kUpdatePolicyDefault;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/config_manager.h"
+#include <lm.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <wininet.h>
+#include <atlstr.h>
+#include <math.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/service_utils.h"
+#include "omaha/common/string.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/enterprise/const_group_policy.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource.h"
+
+namespace omaha {
+
+namespace {
+
+HRESULT GetDir(int csidl,
+               const CString& path_tail,
+               bool create_dir,
+               CString* dir) {
+  ASSERT1(dir);
+
+  CString path;
+  HRESULT hr = GetFolderPath(csidl | CSIDL_FLAG_DONT_VERIFY, &path);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (!::PathAppend(CStrBuf(path, MAX_PATH), path_tail)) {
+    return GOOPDATE_E_PATH_APPEND_FAILED;
+  }
+  dir->SetString(path);
+
+  // Try to create the directory. Continue if the directory can't be created.
+  if (create_dir) {
+    hr = CreateDir(path, NULL);
+    if (FAILED(hr)) {
+      CORE_LOG(LE, (_T("[GetDir failed to create dir][%s][0x%08x]"), path, hr));
+    }
+  }
+  return S_OK;
+}
+
+// The app-specific value overrides the disable all value so read the former
+// first. If it doesn't exist, read the "disable all" value.
+bool GetEffectivePolicyForApp(const TCHAR* apps_default_value_name,
+                              const TCHAR* app_prefix_name,
+                              const GUID& app_guid,
+                              DWORD* effective_policy) {
+  ASSERT1(apps_default_value_name);
+  ASSERT1(app_prefix_name);
+  ASSERT1(effective_policy);
+
+  CString app_value_name(app_prefix_name);
+  app_value_name.Append(GuidToString(app_guid));
+
+  HRESULT hr = RegKey::GetValue(kRegKeyGoopdateGroupPolicy,
+                                app_value_name,
+                                effective_policy);
+  if (SUCCEEDED(hr)) {
+    return true;
+  } else {
+    CORE_LOG(L4, (_T("[Failed to read Group Policy value][%s]"),
+                  app_value_name));
+  }
+
+  hr = RegKey::GetValue(kRegKeyGoopdateGroupPolicy,
+                        apps_default_value_name,
+                        effective_policy);
+  if (SUCCEEDED(hr)) {
+    return true;
+  } else {
+    CORE_LOG(L4, (_T("[Failed to read Group Policy value][%s]"),
+                  apps_default_value_name));
+  }
+
+  return false;
+}
+
+// Gets the raw update check period override value in seconds from the registry.
+// The value must be processed for limits and overflow before using.
+// Checks UpdateDev and Group Policy.
+// Returns true if either override was successefully read.
+bool GetLastCheckPeriodSecFromRegistry(DWORD* period_sec) {
+  ASSERT1(period_sec);
+
+  DWORD update_dev_sec = 0;
+  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                 kRegValueLastCheckPeriodSec,
+                                 &update_dev_sec))) {
+    CORE_LOG(L5, (_T("['LastCheckPeriodSec' override %d]"), update_dev_sec));
+    *period_sec = update_dev_sec;
+    return true;
+  }
+
+  DWORD group_policy_minutes = 0;
+  if (SUCCEEDED(RegKey::GetValue(kRegKeyGoopdateGroupPolicy,
+                                 kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                                 &group_policy_minutes))) {
+    CORE_LOG(L5, (_T("[Group Policy check period override %d]"),
+                  group_policy_minutes));
+
+
+    *period_sec = (group_policy_minutes > UINT_MAX / 60) ?
+                  UINT_MAX :
+                  group_policy_minutes * 60;
+
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+LLock ConfigManager::lock_;
+ConfigManager* ConfigManager::config_manager_ = NULL;
+
+ConfigManager* ConfigManager::Instance() {
+  __mutexScope(lock_);
+  if (!config_manager_) {
+    config_manager_ = new ConfigManager();
+  }
+  return config_manager_;
+}
+
+void ConfigManager::DeleteInstance() {
+  delete config_manager_;
+}
+
+CString ConfigManager::GetUserDownloadStorageDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,
+                           CString(OMAHA_REL_DOWNLOAD_STORAGE_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+CString ConfigManager::GetUserOfflineStorageDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,
+                           CString(OMAHA_REL_OFFLINE_STORAGE_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+CString ConfigManager::GetUserInitialManifestStorageDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,
+                           CString(OMAHA_REL_INITIAL_MANIFEST_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+CString ConfigManager::GetUserGoopdateInstallDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,
+                           CString(OMAHA_REL_GOOPDATE_INSTALL_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+bool ConfigManager::IsRunningFromUserGoopdateInstallDir() const {
+  CString path;
+  HRESULT hr = GetDir(CSIDL_LOCAL_APPDATA,
+                      CString(OMAHA_REL_GOOPDATE_INSTALL_DIR),
+                      false,
+                      &path);
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  return (String_StrNCmp(path,
+                         app_util::GetCurrentModuleDirectory(),
+                         path.GetLength(),
+                         true) == 0);
+}
+
+CString ConfigManager::GetUserCrashReportsDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,
+                           CString(OMAHA_REL_CRASH_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+CString ConfigManager::GetMachineCrashReportsDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES,
+                           CString(OMAHA_REL_CRASH_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+CString ConfigManager::GetMachineDownloadStorageDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_COMMON_APPDATA,
+                           CString(OMAHA_REL_DOWNLOAD_STORAGE_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+CString ConfigManager::GetMachineSecureDownloadStorageDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES,
+                           CString(OMAHA_REL_DOWNLOAD_STORAGE_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+CString ConfigManager::GetMachineSecureOfflineStorageDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES,
+                           CString(OMAHA_REL_OFFLINE_STORAGE_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+CString ConfigManager::GetTempDownloadDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_LOCAL_APPDATA,
+                           CString(OMAHA_REL_TEMP_DOWNLOAD_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+CString ConfigManager::GetMachineGoopdateInstallDir() const {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES,
+                           CString(OMAHA_REL_GOOPDATE_INSTALL_DIR),
+                           true,
+                           &path)));
+  return path;
+}
+
+bool ConfigManager::IsRunningFromMachineGoopdateInstallDir() const {
+  CString path;
+  HRESULT hr = GetDir(CSIDL_PROGRAM_FILES,
+                      CString(OMAHA_REL_GOOPDATE_INSTALL_DIR),
+                      false,
+                      &path);
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  return (String_StrNCmp(path,
+                         app_util::GetCurrentModuleDirectory(),
+                         path.GetLength(),
+                         true) == 0);
+}
+
+// TODO(omaha): create a generic way to override configuration parameters.
+//
+// Overrides PingUrl in debug builds.
+HRESULT ConfigManager::GetPingUrl(CString* url) const {
+  ASSERT1(url);
+
+#ifdef DEBUG
+  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                 kRegValueNamePingUrl,
+                                 url))) {
+    CORE_LOG(L5, (_T("['ping url' override %s]"), *url));
+    return S_OK;
+  }
+#endif
+
+  *url = kUrlPing;
+  return S_OK;
+}
+
+// Overrides Url (update check url) in debug builds.
+HRESULT ConfigManager::GetUpdateCheckUrl(CString* url) const {
+  ASSERT1(url);
+
+#ifdef DEBUG
+  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                 kRegValueNameUrl,
+                                 url))) {
+    CORE_LOG(L5, (_T("['url' override %s]"), *url));
+    return S_OK;
+  }
+#endif
+
+  *url = kUrlUpdateCheck;
+  return S_OK;
+}
+
+HRESULT ConfigManager::GetWebPluginCheckUrl(CString* url) const {
+  ASSERT1(url);
+
+#ifdef DEBUG
+  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                 kRegValueNameWebPluginUrl,
+                                 url))) {
+    CORE_LOG(L5, (_T("['webplugin url' override %s]"), *url));
+    return S_OK;
+  }
+#endif
+  *url = kUrlWebPluginCheck;
+  return S_OK;
+}
+
+// Returns the override from the registry locations if present. Otherwise,
+// returns the default value.
+// Default value is different value for Googlers, to make update checks more
+// aggresive.
+// Ensures returned value is between kMinLastCheckPeriodSec and INT_MAX except
+// when the override is 0, which indicates updates are disabled.
+int ConfigManager::GetLastCheckPeriodSec(bool* is_overridden) const {
+  ASSERT1(is_overridden);
+  DWORD registry_period_sec = 0;
+  *is_overridden = GetLastCheckPeriodSecFromRegistry(&registry_period_sec);
+  if (*is_overridden) {
+    if (0 == registry_period_sec) {
+      return 0;
+    }
+    const int period_sec = registry_period_sec > INT_MAX ?
+                           INT_MAX :
+                           static_cast<int>(registry_period_sec);
+
+    if (period_sec < kMinLastCheckPeriodSec) {
+      return kMinLastCheckPeriodSec;
+    }
+    return period_sec;
+  }
+
+  // Returns a lower value for Googlers.
+  if (IsGoogler()) {
+    return kLastCheckPeriodGooglerSec;
+  }
+
+  return kLastCheckPeriodSec;
+}
+
+// All time values are in seconds.
+int ConfigManager::GetTimeSinceLastCheckedSec(bool is_machine) const {
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+  const uint32 last_checked = GetLastCheckedTime(is_machine);
+  if (now < last_checked) {
+    CORE_LOG(LW, (_T("[possible time warp detected]")
+                  _T("[now %u][last checked %u]"), now, last_checked));
+  }
+  const int time_difference = abs(static_cast<int>(now - last_checked));
+  bool is_period_overridden = false;
+  CORE_LOG(L3, (_T("[now %u][last checked %u][update interval %u]")
+                _T("[time difference %u]"),
+                now, last_checked, GetLastCheckPeriodSec(&is_period_overridden),
+                time_difference));
+  return time_difference;
+}
+
+DWORD ConfigManager::GetLastCheckedTime(bool is_machine) const {
+  const TCHAR* reg_update_key = is_machine ? MACHINE_REG_UPDATE:
+                                             USER_REG_UPDATE;
+  DWORD last_checked_time = 0;
+  if (SUCCEEDED(RegKey::GetValue(reg_update_key,
+                                 kRegValueLastChecked,
+                                 &last_checked_time))) {
+    return last_checked_time;
+  }
+  return 0;
+}
+
+HRESULT ConfigManager::SetLastCheckedTime(bool is_machine, DWORD time) const {
+  const TCHAR* reg_update_key = is_machine ? MACHINE_REG_UPDATE:
+                                             USER_REG_UPDATE;
+  return RegKey::SetValue(reg_update_key, kRegValueLastChecked, time);
+}
+
+DWORD ConfigManager::GetInstallTime(bool is_machine) {
+  const CString client_state_key_name =
+      ConfigManager::Instance()->registry_client_state_goopdate(is_machine);
+  DWORD update_time(0);
+  if (SUCCEEDED(RegKey::GetValue(client_state_key_name,
+                                 kRegValueLastUpdateTimeSec,
+                                 &update_time))) {
+    return update_time;
+  }
+
+  DWORD install_time(0);
+  if (SUCCEEDED(RegKey::GetValue(client_state_key_name,
+                                 kRegValueInstallTimeSec,
+                                 &install_time))) {
+    return install_time;
+  }
+
+  return 0;
+}
+
+bool ConfigManager::Is24HoursSinceInstall(bool is_machine) {
+  const int kDaySec = 24 * 60 * 60;
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  const uint32 install_time = GetInstallTime(is_machine);
+  if (now < install_time) {
+    CORE_LOG(LW, (_T("[Incorrect clock time detected]")
+                  _T("[now %u][install_time %u]"), now, install_time));
+  }
+  const int time_difference = abs(static_cast<int>(now - install_time));
+  return time_difference >= kDaySec;
+}
+
+bool ConfigManager::CanCollectStats(bool is_machine) const {
+  if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueForceUsageStats)) {
+    return true;
+  }
+
+  // TODO(omaha): This should actually be iterating over registered products
+  // rather than present ClientState keys. These are identical in most cases.
+  const TCHAR* state_key_name = registry_client_state(is_machine);
+
+  RegKey state_key;
+  HRESULT hr = state_key.Open(state_key_name, KEY_READ);
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  int num_sub_keys = state_key.GetSubkeyCount();
+  for (int i = 0; i < num_sub_keys; ++i) {
+    CString sub_key_name;
+    if (FAILED(state_key.GetSubkeyNameAt(i, &sub_key_name))) {
+      continue;
+    }
+
+    if (goopdate_utils::AreAppUsageStatsEnabled(is_machine, sub_key_name)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// Overrides OverInstall in debug builds.
+bool ConfigManager::CanOverInstall() const {
+#ifdef DEBUG
+  DWORD value = 0;
+  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                 kRegValueNameOverInstall,
+                                 &value))) {
+    CORE_LOG(L5, (_T("['OverInstall' override %d]"), value));
+    return value != 0;
+  }
+#endif
+  return !OFFICIAL_BUILD;
+}
+
+// Overrides AuCheckPeriodMs. Implements a lower bound value. Returns INT_MAX
+// if the registry value exceeds INT_MAX.
+int ConfigManager::GetAutoUpdateTimerIntervalMs() const {
+  DWORD interval(0);
+  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                 kRegValueAuCheckPeriodMs,
+                                 &interval))) {
+    int ret_val = 0;
+    if (interval > INT_MAX) {
+      ret_val = INT_MAX;
+    } else if (interval < kMinAUCheckPeriodMs) {
+      ret_val = kMinAUCheckPeriodMs;
+    } else {
+      ret_val = interval;
+    }
+    ASSERT1(ret_val >= kMinAUCheckPeriodMs);
+    CORE_LOG(L5, (_T("['AuCheckPeriodMs' override %d]"), interval));
+    return ret_val;
+  }
+
+  // Returns a lower value for Googlers.
+  if (IsGoogler()) {
+    return kAUCheckPeriodGooglerMs;
+  }
+
+  return kAUCheckPeriodMs;
+}
+
+int ConfigManager::GetUpdateWorkerStartUpDelayMs() const {
+  int au_timer_interval_ms = GetAutoUpdateTimerIntervalMs();
+
+  // If the AuCheckPeriod is overriden then use that as the delay.
+  if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueAuCheckPeriodMs)) {
+    return au_timer_interval_ms;
+  }
+
+  int random_delay = 0;
+  if (!GenRandom(&random_delay, sizeof(random_delay))) {
+    return au_timer_interval_ms;
+  }
+
+  // Scale the au_check_period number to be between
+  // kUpdateTimerStartupDelayMinMs and kUpdateTimerStartupDelayMaxMs.
+  int scale = kUpdateTimerStartupDelayMaxMs - kUpdateTimerStartupDelayMinMs;
+  ASSERT1(scale >= 0);
+
+  int random_addition = abs(random_delay) % scale;
+  ASSERT1(random_addition < scale);
+
+  au_timer_interval_ms = kUpdateTimerStartupDelayMinMs + random_addition;
+  ASSERT1(au_timer_interval_ms >= kUpdateTimerStartupDelayMinMs &&
+          au_timer_interval_ms <= kUpdateTimerStartupDelayMaxMs);
+
+  return au_timer_interval_ms;
+}
+
+// Overrides CodeRedCheckPeriodMs. Implements a lower bound value. Returns
+// INT_MAX if the registry value exceeds INT_MAX.
+int ConfigManager::GetCodeRedTimerIntervalMs() const {
+  DWORD interval(0);
+  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                 kRegValueCrCheckPeriodMs,
+                                 &interval))) {
+    int ret_val = 0;
+    if (interval > INT_MAX) {
+      ret_val = INT_MAX;
+    } else if (interval < kMinCodeRedCheckPeriodMs) {
+      ret_val = kMinCodeRedCheckPeriodMs;
+    } else {
+      ret_val = interval;
+    }
+    ASSERT1(ret_val >= kMinCodeRedCheckPeriodMs);
+    CORE_LOG(L5, (_T("['CrCheckPeriodMs' override %d]"), interval));
+    return ret_val;
+  }
+  return kCodeRedCheckPeriodMs;
+}
+
+// Returns true if logging is enabled for the event type.
+// Logging of errors and warnings is enabled by default.
+bool ConfigManager::CanLogEvents(WORD event_type) const {
+  const TCHAR* reg_update_key = MACHINE_REG_UPDATE_DEV;
+  DWORD log_events_level = LOG_EVENT_LEVEL_NONE;
+  if (SUCCEEDED(RegKey::GetValue(reg_update_key,
+                                 kRegValueEventLogLevel,
+                                 &log_events_level))) {
+    switch (log_events_level) {
+      case LOG_EVENT_LEVEL_ALL:
+        return true;
+      case LOG_EVENT_LEVEL_WARN_AND_ERROR:
+        return event_type == EVENTLOG_ERROR_TYPE ||
+               event_type == EVENTLOG_WARNING_TYPE;
+      case LOG_EVENT_LEVEL_NONE:
+      default:
+        return false;
+    }
+  }
+
+  return event_type == EVENTLOG_ERROR_TYPE ||
+         event_type == EVENTLOG_WARNING_TYPE;
+}
+
+CString ConfigManager::GetTestSource() const {
+  CString test_source;
+  HRESULT hr = RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                kRegValueTestSource,
+                                &test_source);
+  if (SUCCEEDED(hr)) {
+    if (test_source.IsEmpty()) {
+      test_source = kRegValueTestSourceAuto;
+    }
+    return test_source;
+  }
+
+  DWORD interval = 0;
+  hr = RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                        kRegValueAuCheckPeriodMs,
+                        &interval);
+  if (SUCCEEDED(hr)) {
+    return kRegValueTestSourceAuto;
+  }
+
+#if defined(DEBUG) || !OFFICIAL_BUILD
+  test_source = kRegValueTestSourceAuto;
+#endif
+
+  return test_source;
+}
+
+// Reads the current value under HKLM/HKCU\Google\Update\value_name. Returns
+// default_val if value_name does not exist.
+CString GetCurrentVersionedName(bool is_machine,
+                                const TCHAR* value_name,
+                                const TCHAR* default_val) {
+  CORE_LOG(L3, (_T("[ConfigManager::GetCurrentVersionedName]")));
+  ASSERT1(value_name && *value_name);
+  ASSERT1(default_val && *default_val);
+
+  const TCHAR* key_name = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
+  CString name;
+  HRESULT hr(RegKey::GetValue(key_name, value_name, &name));
+  if (FAILED(hr)) {
+    CORE_LOG(L4, (_T("[GetValue failed][%s][0x%x][Using default name][%s]"),
+                  value_name, hr, default_val));
+    name = default_val;
+  }
+
+  CORE_LOG(L3, (_T("[Versioned Name][%s]"), name));
+  return name;
+}
+
+// Creates a unique name of the form "{prefix}1c9b3d6baf90df3" and stores it in
+// the registry under HKLM/HKCU\Google\Update\value_name. Subsequent
+// invocations of GetCurrentTaskName() will return this new value.
+HRESULT CreateAndSetVersionedNameInRegistry(bool is_machine,
+                                            const TCHAR* prefix,
+                                            const TCHAR* value_name) {
+  ASSERT1(prefix && *prefix);
+  ASSERT1(value_name && *value_name);
+
+  CString name(ServiceInstall::GenerateServiceName(prefix));
+  CORE_LOG(L3, (_T("Versioned name[%s][%s][%s]"), prefix, value_name, name));
+
+  const TCHAR* key_name = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE;
+  return RegKey::SetValue(key_name, value_name, name);
+}
+
+CString ConfigManager::GetCurrentTaskNameCore(bool is_machine) {
+  CORE_LOG(L3, (_T("[GetCurrentTaskNameCore[%d]"), is_machine));
+
+  CString default_name(goopdate_utils::GetDefaultGoopdateTaskName(
+                                           is_machine,
+                                           COMMANDLINE_MODE_CORE));
+  return GetCurrentVersionedName(is_machine, kRegValueTaskNameC, default_name);
+}
+
+HRESULT ConfigManager::CreateAndSetVersionedTaskNameCoreInRegistry(
+    bool is_machine) {
+  CORE_LOG(L3, (_T("CreateAndSetVersionedTaskNameCoreInRegistry[%d]"),
+                is_machine));
+
+  CString default_name(goopdate_utils::GetDefaultGoopdateTaskName(
+                                           is_machine,
+                                           COMMANDLINE_MODE_CORE));
+  return CreateAndSetVersionedNameInRegistry(is_machine,
+                                             default_name,
+                                             kRegValueTaskNameC);
+}
+
+CString ConfigManager::GetCurrentTaskNameUA(bool is_machine) {
+  CORE_LOG(L3, (_T("[GetCurrentTaskNameUA[%d]"), is_machine));
+
+  CString default_name(goopdate_utils::GetDefaultGoopdateTaskName(
+                                           is_machine,
+                                           COMMANDLINE_MODE_UA));
+  return GetCurrentVersionedName(is_machine, kRegValueTaskNameUA, default_name);
+}
+
+HRESULT ConfigManager::CreateAndSetVersionedTaskNameUAInRegistry(bool machine) {
+  CORE_LOG(L3, (_T("CreateAndSetVersionedTaskNameUAInRegistry[%d]"), machine));
+
+  CString default_name(goopdate_utils::GetDefaultGoopdateTaskName(
+                                           machine,
+                                           COMMANDLINE_MODE_UA));
+  return CreateAndSetVersionedNameInRegistry(machine,
+                                             default_name,
+                                             kRegValueTaskNameUA);
+}
+
+CString ConfigManager::GetCurrentServiceName() {
+  CORE_LOG(L3, (_T("[ConfigManager::GetCurrentServiceName]")));
+  return GetCurrentVersionedName(true,
+                                 kRegValueServiceName,
+                                 kLegacyServiceName);
+}
+
+CString ConfigManager::GetCurrentServiceDisplayName() {
+  CORE_LOG(L3, (_T("[ConfigManager::GetCurrentServiceDisplayName]")));
+  CString display_name;
+  VERIFY1(display_name.LoadString(IDS_SERVICE_DISPLAY_NAME));
+  display_name.AppendFormat(_T(" (%s)"), GetCurrentServiceName());
+  return display_name;
+}
+
+HRESULT ConfigManager::CreateAndSetVersionedServiceNameInRegistry() {
+  CORE_LOG(L3, (_T("CreateAndSetVersionedServiceNameInRegistry")));
+  return CreateAndSetVersionedNameInRegistry(true,
+                                             kServicePrefix,
+                                             kRegValueServiceName);
+}
+
+HRESULT ConfigManager::GetNetConfig(CString* net_config) {
+  ASSERT1(net_config);
+  CString val;
+  HRESULT hr = RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                kRegValueNetConfig,
+                                &val);
+  if (SUCCEEDED(hr)) {
+    *net_config = val;
+  }
+  return hr;
+}
+
+// Returns false if running in the context of an OEM install or waiting for a
+// EULA to be accepted.
+bool ConfigManager::CanUseNetwork(bool is_machine) const {
+  DWORD eula_accepted(0);
+  HRESULT hr = RegKey::GetValue(registry_update(is_machine),
+                                kRegValueOmahaEulaAccepted,
+                                &eula_accepted);
+  if (SUCCEEDED(hr) && 0 == eula_accepted) {
+    CORE_LOG(L3, (_T("[CanUseNetwork][eulaaccepted=0][false]")));
+    return false;
+  }
+
+  if (IsOemInstalling(is_machine)) {
+    CORE_LOG(L3, (_T("[CanUseNetwork][OEM installing][false]")));
+    return false;
+  }
+
+  return true;
+}
+
+// Always returns false if !is_machine. This prevents ever blocking per-user
+// instances.
+// Returns true if in audit mode and OEM install time is present. Requiring the
+// OEM install time prevents ever blocking non-OEM installs from updating.
+// Also returns true if less than kMinOemModeMs since the OEM install.
+bool ConfigManager::IsOemInstalling(bool is_machine) const {
+  if (!is_machine) {
+    return false;
+  }
+
+  DWORD oem_install_time_seconds = 0;
+  if (FAILED(RegKey::GetValue(MACHINE_REG_UPDATE,
+                              kRegValueOemInstallTimeSec,
+                              &oem_install_time_seconds))) {
+    CORE_LOG(L3, (_T("[IsOemInstalling][OemInstallTime not found][false]")));
+    return false;
+  }
+
+  if (IsWindowsInstalling()) {
+    CORE_LOG(L3, (_T("[IsOemInstalling][IsWindowsInstalling][true]")));
+    return true;
+  }
+
+  const uint32 now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  if (now_seconds < oem_install_time_seconds) {
+    CORE_LOG(LW, (_T("[possible time warp detected][now %u][last checked %u]"),
+                  now_seconds, oem_install_time_seconds));
+  }
+  const int time_difference_seconds =
+      abs(static_cast<int>(now_seconds - oem_install_time_seconds));
+
+  ASSERT1(0 <= time_difference_seconds);
+  const uint32 kMinOemModeSeconds = kMinOemModeMs / kMsPerSec;
+  const bool result = time_difference_seconds < kMinOemModeSeconds ? true :
+                                                                     false;
+
+  CORE_LOG(L3, (_T("[now %u][OEM install time %u][time difference %u][%d]"),
+                now_seconds, oem_install_time_seconds, time_difference_seconds,
+                result));
+  return result;
+}
+
+// USE IsOemInstalling() INSTEAD in most cases.
+bool ConfigManager::IsWindowsInstalling() const {
+#if !OFFICIAL_BUILD
+  DWORD value = 0;
+  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                 kRegValueNameWindowsInstalling,
+                                 &value))) {
+    CORE_LOG(L3, (_T("['WindowsInstalling' override %d]"), value));
+    return value != 0;
+  }
+#endif
+
+  return omaha::IsWindowsInstalling();
+}
+
+// Checks if the computer name ends with .google.com or the netbios domain is
+// google.
+bool ConfigManager::IsGoogler() const {
+  CORE_LOG(L4, (_T("[ConfigManager::IsGoogler]")));
+  TCHAR dns_name[INTERNET_MAX_HOST_NAME_LENGTH] = {0};
+  DWORD dns_name_size(arraysize(dns_name));
+  if (::GetComputerNameEx(ComputerNameDnsFullyQualified,
+                          dns_name, &dns_name_size)) {
+     CORE_LOG(L4, (_T("[dns name %s]"), dns_name));
+     if (String_EndsWith(dns_name, _T(".google.com"), true)) {
+       return true;
+     }
+  }
+
+  WKSTA_INFO_100* info = NULL;
+  int kInformationLevel = 100;
+  NET_API_STATUS status = ::NetWkstaGetInfo(NULL,
+                                            kInformationLevel,
+                                            reinterpret_cast<BYTE**>(&info));
+  ON_SCOPE_EXIT(::NetApiBufferFree, info);
+  if (status == NERR_Success) {
+    CORE_LOG(L4, (_T("[netbios name %s]"), info->wki100_langroup));
+    if (info->wki100_langroup &&
+        _tcsicmp(info->wki100_langroup, _T("google")) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool ConfigManager::CanInstallApp(const GUID& app_guid) const {
+  // Google Update should never be checking whether it can install itself.
+  ASSERT1(!::IsEqualGUID(kGoopdateGuid, app_guid));
+
+  DWORD effective_policy = 0;
+  if (!GetEffectivePolicyForApp(kRegValueInstallAppsDefault,
+                                kRegValueInstallAppPrefix,
+                                app_guid,
+                                &effective_policy)) {
+    return kInstallPolicyDefault;
+  }
+
+  return kPolicyDisabled != effective_policy;
+}
+
+// Self-updates cannot be disabled.
+bool ConfigManager::CanUpdateApp(const GUID& app_guid,
+                                 bool is_manual) const {
+  if (::IsEqualGUID(kGoopdateGuid, app_guid)) {
+    return true;
+  }
+
+  DWORD effective_policy = 0;
+  if (!GetEffectivePolicyForApp(kRegValueUpdateAppsDefault,
+                                kRegValueUpdateAppPrefix,
+                                app_guid,
+                                &effective_policy)) {
+    return kUpdatePolicyDefault;
+  }
+
+  if (kPolicyDisabled == effective_policy) {
+    return false;
+  }
+  if ((kPolicyManualUpdatesOnly == effective_policy) && !is_manual) {
+    return false;
+  }
+
+  return kUpdatePolicyDefault;
+}
+
+}  // namespace omaha
diff --git a/goopdate/config_manager.h b/goopdate/config_manager.h
index c8aa4d1..89c1f90 100644
--- a/goopdate/config_manager.h
+++ b/goopdate/config_manager.h
@@ -1,268 +1,268 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The configuration manager that is used to provide the locations of the

-// directory and the registration entries that are to be used by goopdate.

-

-// TODO(omaha): consider removing some of the functions below and have a

-// parameter is_machine instead. This is consistent with the rest of the code

-// and it reduces the number of functions in the public interface.

-

-#ifndef OMAHA_GOOPDATE_CONFIG_MANAGER_H__

-#define OMAHA_GOOPDATE_CONFIG_MANAGER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/synchronized.h"

-

-namespace omaha {

-

-class ConfigManager {

- public:

-  const TCHAR* user_registry_clients() const { return USER_REG_CLIENTS; }

-  const TCHAR* user_registry_clients_goopdate() const {

-    return USER_REG_CLIENTS_GOOPDATE;

-  }

-  const TCHAR* user_registry_client_state() const {

-    return USER_REG_CLIENT_STATE;

-  }

-  const TCHAR* user_registry_client_state_goopdate() const {

-    return USER_REG_CLIENT_STATE_GOOPDATE;

-  }

-  const TCHAR* user_registry_update() const { return USER_REG_UPDATE; }

-  const TCHAR* user_registry_google() const { return USER_REG_GOOGLE; }

-

-  const TCHAR* machine_registry_clients() const { return MACHINE_REG_CLIENTS; }

-  const TCHAR* machine_registry_clients_goopdate() const {

-    return MACHINE_REG_CLIENTS_GOOPDATE;

-  }

-  const TCHAR* machine_registry_client_state() const {

-    return MACHINE_REG_CLIENT_STATE;

-  }

-  const TCHAR* machine_registry_client_state_goopdate() const {

-    return MACHINE_REG_CLIENT_STATE_GOOPDATE;

-  }

-  const TCHAR* machine_registry_client_state_medium() const {

-    return MACHINE_REG_CLIENT_STATE_MEDIUM;

-  }

-  const TCHAR* machine_registry_update() const { return MACHINE_REG_UPDATE; }

-  const TCHAR* machine_registry_google() const { return MACHINE_REG_GOOGLE; }

-

-  const TCHAR* registry_clients(bool is_machine) const {

-    return is_machine ? machine_registry_clients() : user_registry_clients();

-  }

-  const TCHAR* registry_clients_goopdate(bool is_machine) const {

-    return is_machine ? machine_registry_clients_goopdate() :

-                        user_registry_clients_goopdate();

-  }

-  const TCHAR* registry_client_state(bool is_machine) const {

-    return is_machine ? machine_registry_client_state() :

-                        user_registry_client_state();

-  }

-  const TCHAR* registry_client_state_goopdate(bool is_machine) const {

-    return is_machine ? machine_registry_client_state_goopdate() :

-                        user_registry_client_state_goopdate();

-  }

-  const TCHAR* registry_update(bool is_machine) const {

-    return is_machine ? machine_registry_update() : user_registry_update();

-  }

-  const TCHAR* registry_google(bool is_machine) const {

-    return is_machine ? machine_registry_google() : user_registry_google();

-  }

-

-  // Gets the temporary download dir for the current thread token:

-  // %UserProfile%/AppData/Local/Temp/Downloads

-  CString GetTempDownloadDir() const;

-

-  // Creates download data dir:

-  // %UserProfile%/Application Data/Google/Update/Downloads

-  CString GetUserDownloadStorageDir() const;

-

-  // Creates offline data dir:

-  // %UserProfile%/Application Data/Google/Update/Offline

-  CString GetUserOfflineStorageDir() const;

-

-  // Creates initial manifest download dir:

-  // %UserProfile%/Application Data/Google/Update/Manifests/Initial

-  CString GetUserInitialManifestStorageDir() const;

-

-  // Creates goopdate install dir:

-  // %UserProfile%/Application Data/Google/Update

-  CString GetUserGoopdateInstallDir() const;

-

-  // Checks if the running program is executing from the User Goopdate dir.

-  bool IsRunningFromUserGoopdateInstallDir() const;

-

-  // Creates crash reports dir:

-  // %UserProfile%/Local Settings/Application Data/Google/CrashReports

-  CString GetUserCrashReportsDir() const;

-

-  // Creates crash reports dir: %ProgramFiles%/Google/CrashReports

-  CString GetMachineCrashReportsDir() const;

-

-  // TODO(omaha): this is legacy Omaha1. Remove later.

-  // Creates machine download data dir:

-  // %All Users%/Google/Update/Downloads

-  // This is the directory where all the machine downloads are initially

-  // downloaded to. This is needed as the download could have occured as

-  // a user who does not have permission to the machine download location.

-  CString GetMachineDownloadStorageDir() const;

-

-  // Creates machine download data dir:

-  // %ProgramFiles%/Google/Update/Downloads

-  // This is the directory where the installs for machine goopdate are copied

-  // to once the download has succeeded.

-  CString GetMachineSecureDownloadStorageDir() const;

-

-  // Creates machine offline data dir:

-  // %ProgramFiles%/Google/Update/Offline

-  CString GetMachineSecureOfflineStorageDir() const;

-

-  // Creates machine Gogole Update install dir:

-  // %ProgramFiles%/Google/Update

-  CString GetMachineGoopdateInstallDir() const;

-

-  // Checks if the running program is executing from the User Goopdate dir.

-  bool IsRunningFromMachineGoopdateInstallDir() const;

-

-  // Returns the service endpoint where the install/update/uninstall pings

-  // are being sent.

-  HRESULT GetPingUrl(CString* url) const;

-

-  // Returns the service endpoint where the manifest requests and update

-  // checks are being sent.

-  HRESULT GetUpdateCheckUrl(CString* url) const;

-

-  // Returns the service endpoint where the webplugin parameters

-  // are being sent for validation.

-  HRESULT GetWebPluginCheckUrl(CString* url) const;

-

-  // Returns the time interval between update checks in seconds.

-  // 0 indicates updates are disabled.

-  int GetLastCheckPeriodSec(bool* is_overridden) const;

-

-  // Returns the number of seconds since the last successful update check.

-  int GetTimeSinceLastCheckedSec(bool is_machine) const;

-

-  // Gets and sets the last time a successful server update check was made.

-  DWORD GetLastCheckedTime(bool is_machine) const;

-  HRESULT SetLastCheckedTime(bool is_machine, DWORD time) const;

-

-  // Checks registry to see if user has enabled us to collect anonymous

-  // usage stats.

-  bool CanCollectStats(bool is_machine) const;

-

-  // Returns true if over-installing with the same version is allowed.

-  bool CanOverInstall() const;

-

-  // Returns the Autoupdate timer interval. This is the frequency of the

-  // auto update timer run by the core.

-  int GetAutoUpdateTimerIntervalMs() const;

-

-  // Returns the wait time in ms to start the first worker.

-  int GetUpdateWorkerStartUpDelayMs() const;

-

-  // Returns the Code Red timer interval. This is the frequency of the

-  // code red timer run by the core.

-  int GetCodeRedTimerIntervalMs() const;

-

-  // Returns true if event logging to the Windows Event Log is enabled.

-  bool CanLogEvents(WORD event_type) const;

-

-  // Retrieves TestSource which is to be set on dev, qa, and prober machines.

-  CString GetTestSource() const;

-

-  // Returns true if it is okay to do update checks and send pings.

-  bool CanUseNetwork(bool is_machine) const;

-

-  // Returns true if running in the context of an OEM install.

-  // !CanUseNetwork() may be more appropriate.

-  bool IsOemInstalling(bool is_machine) const;

-

-  // Returns true if running in Windows Audit mode (OEM install).

-  // USE IsOemInstalling() INSTEAD in most cases.

-  bool IsWindowsInstalling() const;

-

-  // Returns true if the user is considered a Googler.

-  bool IsGoogler() const;

-

-  // Returns true if installation of the specified app is allowed.

-  bool CanInstallApp(const GUID& app_guid) const;

-

-  // Returns true if updates are allowed for the specified app.

-  bool CanUpdateApp(const GUID& app_guid, bool is_manual) const;

-

-  // Gets the current name, say "GoogleUpdateTaskMachineCore", of the

-  // GoogleUpdateCore scheduled task, either from the registry, or a default

-  // value if there is no registration.

-  static CString GetCurrentTaskNameCore(bool is_machine);

-

-  // Creates a unique name, say "GoogleUpdateTaskMachineCore1c9b3d6baf90df3", of

-  // the GoogleUpdateCore scheduled task, and stores it in the registry.

-  // Subsequent invocations of GetCurrentTaskNameCore() will return this new

-  // value.

-  static HRESULT CreateAndSetVersionedTaskNameCoreInRegistry(bool machine);

-

-  // Gets the current name, say "GoogleUpdateTaskMachineUA", of the

-  // GoogleUpdateUA scheduled task, either from the registry, or a default value

-  // if there is no registration.

-  static CString GetCurrentTaskNameUA(bool is_machine);

-

-  // Creates a unique name, say "GoogleUpdateTaskMachineUA1c9b3d6baf90df3", of

-  // the GoogleUpdateUA scheduled task, and stores it in the registry.

-  // Subsequent invocations of GetCurrentTaskNameUA() will return this new

-  // value.

-  static HRESULT CreateAndSetVersionedTaskNameUAInRegistry(bool machine);

-

-  // Gets the current name, say "gupdate", of the goopdate system service,

-  // either from the registry, or a default value if there is no registration.

-  static CString GetCurrentServiceName();

-

-  // Gets the current name and description of goopdate service.

-  static CString GetCurrentServiceDisplayName();

-

-  // Creates a unique versioned string and sets the version of goopdate service

-  // in the registry. Subsequent invocations of GetCurrentServiceName() will

-  // return this new value.

-  static HRESULT CreateAndSetVersionedServiceNameInRegistry();

-

-  // Returns the network configuration override as a string.

-  static HRESULT GetNetConfig(CString* configuration_override);

-

-  // Gets the time when Goopdate was last updated or installed.

-  static DWORD GetInstallTime(bool is_machine);

-

-  // Returns true if it has been more than 24 hours since Goopdate was updated

-  // or installed.

-  static bool Is24HoursSinceInstall(bool is_machine);

-

-  static ConfigManager* Instance();

-  static void DeleteInstance();

-

- private:

-  ConfigManager() {}

-

-  static LLock lock_;

-  static ConfigManager* config_manager_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(ConfigManager);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_CONFIG_MANAGER_H__

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The configuration manager that is used to provide the locations of the
+// directory and the registration entries that are to be used by goopdate.
+
+// TODO(omaha): consider removing some of the functions below and have a
+// parameter is_machine instead. This is consistent with the rest of the code
+// and it reduces the number of functions in the public interface.
+
+#ifndef OMAHA_GOOPDATE_CONFIG_MANAGER_H__
+#define OMAHA_GOOPDATE_CONFIG_MANAGER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/synchronized.h"
+
+namespace omaha {
+
+class ConfigManager {
+ public:
+  const TCHAR* user_registry_clients() const { return USER_REG_CLIENTS; }
+  const TCHAR* user_registry_clients_goopdate() const {
+    return USER_REG_CLIENTS_GOOPDATE;
+  }
+  const TCHAR* user_registry_client_state() const {
+    return USER_REG_CLIENT_STATE;
+  }
+  const TCHAR* user_registry_client_state_goopdate() const {
+    return USER_REG_CLIENT_STATE_GOOPDATE;
+  }
+  const TCHAR* user_registry_update() const { return USER_REG_UPDATE; }
+  const TCHAR* user_registry_google() const { return USER_REG_GOOGLE; }
+
+  const TCHAR* machine_registry_clients() const { return MACHINE_REG_CLIENTS; }
+  const TCHAR* machine_registry_clients_goopdate() const {
+    return MACHINE_REG_CLIENTS_GOOPDATE;
+  }
+  const TCHAR* machine_registry_client_state() const {
+    return MACHINE_REG_CLIENT_STATE;
+  }
+  const TCHAR* machine_registry_client_state_goopdate() const {
+    return MACHINE_REG_CLIENT_STATE_GOOPDATE;
+  }
+  const TCHAR* machine_registry_client_state_medium() const {
+    return MACHINE_REG_CLIENT_STATE_MEDIUM;
+  }
+  const TCHAR* machine_registry_update() const { return MACHINE_REG_UPDATE; }
+  const TCHAR* machine_registry_google() const { return MACHINE_REG_GOOGLE; }
+
+  const TCHAR* registry_clients(bool is_machine) const {
+    return is_machine ? machine_registry_clients() : user_registry_clients();
+  }
+  const TCHAR* registry_clients_goopdate(bool is_machine) const {
+    return is_machine ? machine_registry_clients_goopdate() :
+                        user_registry_clients_goopdate();
+  }
+  const TCHAR* registry_client_state(bool is_machine) const {
+    return is_machine ? machine_registry_client_state() :
+                        user_registry_client_state();
+  }
+  const TCHAR* registry_client_state_goopdate(bool is_machine) const {
+    return is_machine ? machine_registry_client_state_goopdate() :
+                        user_registry_client_state_goopdate();
+  }
+  const TCHAR* registry_update(bool is_machine) const {
+    return is_machine ? machine_registry_update() : user_registry_update();
+  }
+  const TCHAR* registry_google(bool is_machine) const {
+    return is_machine ? machine_registry_google() : user_registry_google();
+  }
+
+  // Gets the temporary download dir for the current thread token:
+  // %UserProfile%/AppData/Local/Temp/Downloads
+  CString GetTempDownloadDir() const;
+
+  // Creates download data dir:
+  // %UserProfile%/Application Data/Google/Update/Downloads
+  CString GetUserDownloadStorageDir() const;
+
+  // Creates offline data dir:
+  // %UserProfile%/Application Data/Google/Update/Offline
+  CString GetUserOfflineStorageDir() const;
+
+  // Creates initial manifest download dir:
+  // %UserProfile%/Application Data/Google/Update/Manifests/Initial
+  CString GetUserInitialManifestStorageDir() const;
+
+  // Creates goopdate install dir:
+  // %UserProfile%/Application Data/Google/Update
+  CString GetUserGoopdateInstallDir() const;
+
+  // Checks if the running program is executing from the User Goopdate dir.
+  bool IsRunningFromUserGoopdateInstallDir() const;
+
+  // Creates crash reports dir:
+  // %UserProfile%/Local Settings/Application Data/Google/CrashReports
+  CString GetUserCrashReportsDir() const;
+
+  // Creates crash reports dir: %ProgramFiles%/Google/CrashReports
+  CString GetMachineCrashReportsDir() const;
+
+  // TODO(omaha): this is legacy Omaha1. Remove later.
+  // Creates machine download data dir:
+  // %All Users%/Google/Update/Downloads
+  // This is the directory where all the machine downloads are initially
+  // downloaded to. This is needed as the download could have occured as
+  // a user who does not have permission to the machine download location.
+  CString GetMachineDownloadStorageDir() const;
+
+  // Creates machine download data dir:
+  // %ProgramFiles%/Google/Update/Downloads
+  // This is the directory where the installs for machine goopdate are copied
+  // to once the download has succeeded.
+  CString GetMachineSecureDownloadStorageDir() const;
+
+  // Creates machine offline data dir:
+  // %ProgramFiles%/Google/Update/Offline
+  CString GetMachineSecureOfflineStorageDir() const;
+
+  // Creates machine Gogole Update install dir:
+  // %ProgramFiles%/Google/Update
+  CString GetMachineGoopdateInstallDir() const;
+
+  // Checks if the running program is executing from the User Goopdate dir.
+  bool IsRunningFromMachineGoopdateInstallDir() const;
+
+  // Returns the service endpoint where the install/update/uninstall pings
+  // are being sent.
+  HRESULT GetPingUrl(CString* url) const;
+
+  // Returns the service endpoint where the manifest requests and update
+  // checks are being sent.
+  HRESULT GetUpdateCheckUrl(CString* url) const;
+
+  // Returns the service endpoint where the webplugin parameters
+  // are being sent for validation.
+  HRESULT GetWebPluginCheckUrl(CString* url) const;
+
+  // Returns the time interval between update checks in seconds.
+  // 0 indicates updates are disabled.
+  int GetLastCheckPeriodSec(bool* is_overridden) const;
+
+  // Returns the number of seconds since the last successful update check.
+  int GetTimeSinceLastCheckedSec(bool is_machine) const;
+
+  // Gets and sets the last time a successful server update check was made.
+  DWORD GetLastCheckedTime(bool is_machine) const;
+  HRESULT SetLastCheckedTime(bool is_machine, DWORD time) const;
+
+  // Checks registry to see if user has enabled us to collect anonymous
+  // usage stats.
+  bool CanCollectStats(bool is_machine) const;
+
+  // Returns true if over-installing with the same version is allowed.
+  bool CanOverInstall() const;
+
+  // Returns the Autoupdate timer interval. This is the frequency of the
+  // auto update timer run by the core.
+  int GetAutoUpdateTimerIntervalMs() const;
+
+  // Returns the wait time in ms to start the first worker.
+  int GetUpdateWorkerStartUpDelayMs() const;
+
+  // Returns the Code Red timer interval. This is the frequency of the
+  // code red timer run by the core.
+  int GetCodeRedTimerIntervalMs() const;
+
+  // Returns true if event logging to the Windows Event Log is enabled.
+  bool CanLogEvents(WORD event_type) const;
+
+  // Retrieves TestSource which is to be set on dev, qa, and prober machines.
+  CString GetTestSource() const;
+
+  // Returns true if it is okay to do update checks and send pings.
+  bool CanUseNetwork(bool is_machine) const;
+
+  // Returns true if running in the context of an OEM install.
+  // !CanUseNetwork() may be more appropriate.
+  bool IsOemInstalling(bool is_machine) const;
+
+  // Returns true if running in Windows Audit mode (OEM install).
+  // USE IsOemInstalling() INSTEAD in most cases.
+  bool IsWindowsInstalling() const;
+
+  // Returns true if the user is considered a Googler.
+  bool IsGoogler() const;
+
+  // Returns true if installation of the specified app is allowed.
+  bool CanInstallApp(const GUID& app_guid) const;
+
+  // Returns true if updates are allowed for the specified app.
+  bool CanUpdateApp(const GUID& app_guid, bool is_manual) const;
+
+  // Gets the current name, say "GoogleUpdateTaskMachineCore", of the
+  // GoogleUpdateCore scheduled task, either from the registry, or a default
+  // value if there is no registration.
+  static CString GetCurrentTaskNameCore(bool is_machine);
+
+  // Creates a unique name, say "GoogleUpdateTaskMachineCore1c9b3d6baf90df3", of
+  // the GoogleUpdateCore scheduled task, and stores it in the registry.
+  // Subsequent invocations of GetCurrentTaskNameCore() will return this new
+  // value.
+  static HRESULT CreateAndSetVersionedTaskNameCoreInRegistry(bool machine);
+
+  // Gets the current name, say "GoogleUpdateTaskMachineUA", of the
+  // GoogleUpdateUA scheduled task, either from the registry, or a default value
+  // if there is no registration.
+  static CString GetCurrentTaskNameUA(bool is_machine);
+
+  // Creates a unique name, say "GoogleUpdateTaskMachineUA1c9b3d6baf90df3", of
+  // the GoogleUpdateUA scheduled task, and stores it in the registry.
+  // Subsequent invocations of GetCurrentTaskNameUA() will return this new
+  // value.
+  static HRESULT CreateAndSetVersionedTaskNameUAInRegistry(bool machine);
+
+  // Gets the current name, say "gupdate", of the goopdate system service,
+  // either from the registry, or a default value if there is no registration.
+  static CString GetCurrentServiceName();
+
+  // Gets the current name and description of goopdate service.
+  static CString GetCurrentServiceDisplayName();
+
+  // Creates a unique versioned string and sets the version of goopdate service
+  // in the registry. Subsequent invocations of GetCurrentServiceName() will
+  // return this new value.
+  static HRESULT CreateAndSetVersionedServiceNameInRegistry();
+
+  // Returns the network configuration override as a string.
+  static HRESULT GetNetConfig(CString* configuration_override);
+
+  // Gets the time when Goopdate was last updated or installed.
+  static DWORD GetInstallTime(bool is_machine);
+
+  // Returns true if it has been more than 24 hours since Goopdate was updated
+  // or installed.
+  static bool Is24HoursSinceInstall(bool is_machine);
+
+  static ConfigManager* Instance();
+  static void DeleteInstance();
+
+ private:
+  ConfigManager() {}
+
+  static LLock lock_;
+  static ConfigManager* config_manager_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ConfigManager);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_CONFIG_MANAGER_H__
+
diff --git a/goopdate/config_manager_unittest.cc b/goopdate/config_manager_unittest.cc
index f931bc0..c9be387 100644
--- a/goopdate/config_manager_unittest.cc
+++ b/goopdate/config_manager_unittest.cc
@@ -1,1891 +1,1891 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <limits.h>

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/file.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-#define APP_GUID1 _T("{6762F466-8863-424f-817C-5757931F346E}")

-const TCHAR* const kAppGuid1 = APP_GUID1;

-const TCHAR* const kAppMachineClientStatePath1 =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\") APP_GUID1;

-const TCHAR* const kAppUserClientStatePath1 =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\") APP_GUID1;

-const TCHAR* const kAppMachineClientStateMediumPath1 =

-    _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\") APP_GUID1;

-

-#define APP_GUID2 _T("{8A0FDD16-D4B7-4167-893F-1386F2A2F0FB}")

-const TCHAR* const kAppGuid2 = APP_GUID2;

-const TCHAR* const kAppMachineClientStatePath2 =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\") APP_GUID2;

-const TCHAR* const kAppUserClientStatePath2 =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\") APP_GUID2;

-

-const TCHAR* const kPolicyKey =

-    _T("HKLM\\Software\\Policies\\Google\\Update\\");

-const TCHAR* const kInstallPolicyApp1 = _T("Install") APP_GUID1;

-const TCHAR* const kInstallPolicyApp2 = _T("Install") APP_GUID2;

-const TCHAR* const kUpdatePolicyApp1 = _T("Update") APP_GUID1;

-const TCHAR* const kUpdatePolicyApp2 = _T("Update") APP_GUID2;

-

-// Helper to write policies to the registry. Eliminates ambiguity of which

-// overload of SetValue to use without the need for static_cast.

-HRESULT SetPolicy(const TCHAR* policy_name, DWORD value) {

-  return RegKey::SetValue(kPolicyKey, policy_name, value);

-}

-

-}  // namespace

-

-class ConfigManagerNoOverrideTest : public testing::Test {

- protected:

-  ConfigManagerNoOverrideTest()

-      : cm_(ConfigManager::Instance()) {

-  }

-

-  bool CanInstallApp(const TCHAR* guid) {

-    return cm_->CanInstallApp(StringToGuid(guid));

-  }

-

-  bool CanUpdateApp(const TCHAR* guid, bool is_manual) {

-    return cm_->CanUpdateApp(StringToGuid(guid), is_manual);

-  }

-

-  ConfigManager* cm_;

-};

-

-class ConfigManagerTest : public ConfigManagerNoOverrideTest {

- protected:

-  ConfigManagerTest()

-      : hive_override_key_name_(kRegistryHiveOverrideRoot) {

-  }

-

-  virtual void SetUp() {

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    OverrideRegistryHives(hive_override_key_name_);

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    EXPECT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-  }

-

-  void CanCollectStatsHelper(bool is_machine);

-  void CanCollectStatsIgnoresOppositeHiveHelper(bool is_machine);

-  HRESULT SetFirstInstallTime(bool is_machine, DWORD time);

-  HRESULT DeleteFirstInstallTime(bool is_machine);

-  HRESULT SetUpdateTime(bool is_machine, DWORD time);

-  HRESULT DeleteUpdateTime(bool is_machine);

-

-  CString hive_override_key_name_;

-};

-

-void ConfigManagerTest::CanCollectStatsHelper(bool is_machine) {

-  const TCHAR* app1_state_key_name = is_machine ? kAppMachineClientStatePath1 :

-                                                  kAppUserClientStatePath1;

-

-  EXPECT_FALSE(cm_->CanCollectStats(is_machine));

-

-  // Test the 'UsageStats' override.

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueForceUsageStats,

-                                    _T("")));

-  EXPECT_TRUE(cm_->CanCollectStats(is_machine));

-  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,

-                                       kRegValueForceUsageStats));

-

-  DWORD val = 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(app1_state_key_name,

-                                    _T("usagestats"),

-                                    val));

-  EXPECT_TRUE(cm_->CanCollectStats(is_machine));

-

-  val = 2;  // invalid value

-  EXPECT_SUCCEEDED(RegKey::SetValue(app1_state_key_name,

-                                    _T("usagestats"),

-                                    val));

-  EXPECT_FALSE(cm_->CanCollectStats(is_machine));

-

-  val = 0;

-  EXPECT_SUCCEEDED(RegKey::SetValue(app1_state_key_name,

-                                    _T("usagestats"),

-                                    val));

-  EXPECT_FALSE(cm_->CanCollectStats(is_machine));

-

-  // One 0 and one 1 results in true. The alphabetical order of the GUIDs is

-  // important assuming GetSubkeyNameAt returns subkeys in alphabetical order.

-  const TCHAR* app2_state_key_name = is_machine ? kAppMachineClientStatePath2 :

-                                                  kAppUserClientStatePath2;

-  val = 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(app2_state_key_name,

-                                    _T("usagestats"),

-                                    val));

-  EXPECT_TRUE(cm_->CanCollectStats(is_machine));

-}

-

-void ConfigManagerTest::CanCollectStatsIgnoresOppositeHiveHelper(

-    bool is_machine) {

-  const TCHAR* app1_state_key_name = is_machine ? kAppMachineClientStatePath1 :

-                                                  kAppUserClientStatePath1;

-

-  EXPECT_FALSE(cm_->CanCollectStats(is_machine));

-

-  DWORD val = 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(app1_state_key_name,

-                                    _T("usagestats"),

-                                    val));

-  EXPECT_TRUE(cm_->CanCollectStats(is_machine));

-  EXPECT_FALSE(cm_->CanCollectStats(!is_machine));

-}

-

-HRESULT ConfigManagerTest::SetFirstInstallTime(bool is_machine, DWORD time) {

-  return RegKey::SetValue(cm_->registry_client_state_goopdate(is_machine),

-                          kRegValueInstallTimeSec,

-                          time);

-}

-

-HRESULT ConfigManagerTest::DeleteFirstInstallTime(bool is_machine) {

-  if (!RegKey::HasValue(cm_->registry_client_state_goopdate(is_machine),

-                        kRegValueInstallTimeSec)) {

-    return S_OK;

-  }

-

-  return RegKey::DeleteValue(cm_->registry_client_state_goopdate(is_machine),

-                             kRegValueInstallTimeSec);

-}

-

-HRESULT ConfigManagerTest::SetUpdateTime(bool is_machine, DWORD time) {

-  return RegKey::SetValue(cm_->registry_client_state_goopdate(is_machine),

-                          kRegValueLastUpdateTimeSec,

-                          time);

-}

-

-HRESULT ConfigManagerTest::DeleteUpdateTime(bool is_machine) {

-  if (!RegKey::HasValue(cm_->registry_client_state_goopdate(is_machine),

-                        kRegValueLastUpdateTimeSec)) {

-    return S_OK;

-  }

-

-  return RegKey::DeleteValue(cm_->registry_client_state_goopdate(is_machine),

-                             kRegValueLastUpdateTimeSec);

-}

-

-TEST_F(ConfigManagerNoOverrideTest, RegistryKeys) {

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\Clients\\"),

-               cm_->user_registry_clients());

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\Clients\\"),

-               cm_->machine_registry_clients());

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\Clients\\"),

-               cm_->registry_clients(false));

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\Clients\\"),

-               cm_->registry_clients(true));

-

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\Clients\\")

-               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-               cm_->user_registry_clients_goopdate());

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\Clients\\")

-               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-               cm_->machine_registry_clients_goopdate());

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\Clients\\")

-               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-               cm_->registry_clients_goopdate(false));

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\Clients\\")

-               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-               cm_->registry_clients_goopdate(true));

-

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\ClientState\\"),

-               cm_->user_registry_client_state());

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientState\\"),

-               cm_->machine_registry_client_state());

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\ClientState\\"),

-               cm_->registry_client_state(false));

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientState\\"),

-               cm_->registry_client_state(true));

-

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\ClientState\\")

-               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-               cm_->user_registry_client_state_goopdate());

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientState\\")

-               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-               cm_->machine_registry_client_state_goopdate());

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\ClientState\\")

-               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-               cm_->registry_client_state_goopdate(false));

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientState\\")

-               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-               cm_->registry_client_state_goopdate(true));

-

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\"),

-               cm_->machine_registry_client_state_medium());

-

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\"),

-               cm_->user_registry_update());

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\"),

-               cm_->machine_registry_update());

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\"),

-               cm_->registry_update(false));

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\"),

-               cm_->registry_update(true));

-

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\"),

-               cm_->user_registry_google());

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\"),

-               cm_->machine_registry_google());

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\"),

-               cm_->registry_google(false));

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\"),

-               cm_->registry_google(true));

-}

-

-TEST_F(ConfigManagerNoOverrideTest, GetUserCrashReportsDir) {

-  const CString expected_path = GetGoogleUserPath() + _T("CrashReports");

-  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));

-  EXPECT_STREQ(expected_path, cm_->GetUserCrashReportsDir());

-  EXPECT_TRUE(File::Exists(expected_path));

-}

-

-// Should run before the subdirectory tests to ensure the directory is created.

-TEST_F(ConfigManagerNoOverrideTest, GetUserGoopdateInstallDir) {

-  const CString expected_path = GetGoogleUserPath() + _T("Update");

-  EXPECT_STREQ(expected_path, cm_->GetUserGoopdateInstallDir());

-  EXPECT_TRUE(File::Exists(expected_path));

-}

-

-TEST_F(ConfigManagerNoOverrideTest, GetDownloadStorage) {

-  const CString expected_path = GetGoogleUpdateUserPath() + _T("Download");

-  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));

-  EXPECT_STREQ(expected_path, cm_->GetUserDownloadStorageDir());

-  EXPECT_TRUE(File::Exists(expected_path));

-}

-

-TEST_F(ConfigManagerNoOverrideTest, GetUserDownloadStorageDir) {

-  const CString expected_path = GetGoogleUpdateUserPath() + _T("Download");

-  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));

-  EXPECT_STREQ(expected_path, cm_->GetUserDownloadStorageDir());

-  EXPECT_TRUE(File::Exists(expected_path));

-}

-

-TEST_F(ConfigManagerNoOverrideTest, GetUserOfflineStorageDir) {

-  const CString expected_path = GetGoogleUpdateUserPath() + _T("Offline");

-  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));

-  EXPECT_STREQ(expected_path, cm_->GetUserOfflineStorageDir());

-  EXPECT_TRUE(File::Exists(expected_path));

-}

-

-TEST_F(ConfigManagerNoOverrideTest, IsRunningFromUserGoopdateInstallDir) {

-  EXPECT_FALSE(cm_->IsRunningFromUserGoopdateInstallDir());

-}

-

-TEST_F(ConfigManagerNoOverrideTest, GetMachineCrashReportsDir) {

-  CString program_files;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files));

-  const CString expected_path = program_files + _T("\\Google\\CrashReports");

-  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));

-  EXPECT_STREQ(expected_path, cm_->GetMachineCrashReportsDir());

-  EXPECT_TRUE(File::Exists(expected_path) || !vista_util::IsUserAdmin());

-}

-

-// Should run before the subdirectory tests to ensure the directory is created.

-TEST_F(ConfigManagerNoOverrideTest, GetMachineGoopdateInstallDir) {

-  CString expected_path = GetGoogleUpdateMachinePath();

-  EXPECT_STREQ(expected_path, cm_->GetMachineGoopdateInstallDir());

-  EXPECT_TRUE(File::Exists(expected_path) || !vista_util::IsUserAdmin());

-}

-

-TEST_F(ConfigManagerNoOverrideTest, GetMachineSecureDownloadStorageDir) {

-  CString expected_path = GetGoogleUpdateMachinePath() + _T("\\Download");

-  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));

-  EXPECT_STREQ(expected_path, cm_->GetMachineSecureDownloadStorageDir());

-  EXPECT_TRUE(File::Exists(expected_path) || !vista_util::IsUserAdmin());

-}

-

-TEST_F(ConfigManagerNoOverrideTest, GetMachineSecureOfflineStorageDir) {

-  CString expected_path = GetGoogleUpdateMachinePath() + _T("\\Offline");

-  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));

-  EXPECT_STREQ(expected_path, cm_->GetMachineSecureOfflineStorageDir());

-  EXPECT_TRUE(File::Exists(expected_path) || !vista_util::IsUserAdmin());

-}

-

-TEST_F(ConfigManagerNoOverrideTest, IsRunningFromMachineGoopdateInstallDir) {

-  EXPECT_FALSE(cm_->IsRunningFromMachineGoopdateInstallDir());

-}

-

-// Tests the GetUpdateCheckUrl override.

-TEST_F(ConfigManagerTest, GetUpdateCheckUrl) {

-  CString url;

-  EXPECT_SUCCEEDED(cm_->GetUpdateCheckUrl(&url));

-  EXPECT_STREQ(url, kUrlUpdateCheck);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueNameUrl,

-                                    _T("http://foo/")));

-  url.Empty();

-  EXPECT_TRUE(url.IsEmpty());

-  EXPECT_SUCCEEDED(cm_->GetUpdateCheckUrl(&url));

-#ifdef DEBUG

-  EXPECT_STREQ(url, _T("http://foo/"));

-#else

-  EXPECT_STREQ(url, kUrlUpdateCheck);

-#endif

-}

-

-// Tests the GetPingUrl override.

-TEST_F(ConfigManagerTest, GetPingUrl) {

-  CString url;

-  EXPECT_SUCCEEDED(cm_->GetPingUrl(&url));

-  EXPECT_STREQ(url, kUrlPing);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueNamePingUrl,

-                                    _T("http://bar/")));

-  url.Empty();

-  EXPECT_TRUE(url.IsEmpty());

-  EXPECT_SUCCEEDED(cm_->GetPingUrl(&url));

-#ifdef DEBUG

-  EXPECT_STREQ(url, _T("http://bar/"));

-#else

-  EXPECT_STREQ(url, kUrlPing);

-#endif

-}

-

-// Tests LastCheckPeriodSec override.

-TEST_F(ConfigManagerTest, GetLastCheckPeriodSec_Default) {

-  bool is_overridden = true;

-  if (cm_->IsGoogler()) {

-    EXPECT_EQ(kLastCheckPeriodGooglerSec,

-              cm_->GetLastCheckPeriodSec(&is_overridden));

-  } else {

-    EXPECT_EQ(kLastCheckPeriodSec, cm_->GetLastCheckPeriodSec(&is_overridden));

-  }

-  EXPECT_FALSE(is_overridden);

-}

-

-TEST_F(ConfigManagerTest, GetLastCheckPeriodSec_UpdateDevOverride) {

-  // Zero is a special value meaning disabled.

-  DWORD val = 0;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueLastCheckPeriodSec,

-                                    val));

-  bool is_overridden = false;

-  EXPECT_EQ(0, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-

-  val = kMinLastCheckPeriodSec - 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueLastCheckPeriodSec,

-                                    val));

-  is_overridden = false;

-  EXPECT_EQ(kMinLastCheckPeriodSec, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-

-  val = INT_MAX + static_cast<uint32>(1);

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueLastCheckPeriodSec,

-                                    val));

-  is_overridden = false;

-  EXPECT_EQ(INT_MAX, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-

-  val = 1000;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueLastCheckPeriodSec,

-                                    val));

-  is_overridden = false;

-  EXPECT_EQ(1000, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-

-  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,

-                                       kRegValueLastCheckPeriodSec));

-  is_overridden = true;

-  if (cm_->IsGoogler()) {

-    EXPECT_EQ(kLastCheckPeriodGooglerSec,

-              cm_->GetLastCheckPeriodSec(&is_overridden));

-  } else {

-    EXPECT_EQ(kLastCheckPeriodSec, cm_->GetLastCheckPeriodSec(&is_overridden));

-  }

-  EXPECT_FALSE(is_overridden);

-}

-

-TEST_F(ConfigManagerTest, GetLastCheckPeriodSec_GroupPolicyOverride) {

-  const DWORD kOverrideMinutes = 16000;

-  const DWORD kExpectedSeconds = kOverrideMinutes * 60;

-  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),

-                             kOverrideMinutes));

-  bool is_overridden = false;

-  EXPECT_EQ(kExpectedSeconds, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-}

-

-TEST_F(ConfigManagerTest, GetLastCheckPeriodSec_GroupPolicyOverride_TooLow) {

-  const DWORD kOverrideMinutes = 1;

-  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),

-                             kOverrideMinutes));

-  bool is_overridden = false;

-  EXPECT_EQ(kMinLastCheckPeriodSec, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-}

-

-TEST_F(ConfigManagerTest, GetLastCheckPeriodSec_GroupPolicyOverride_Zero) {

-  const DWORD kOverrideMinutes = 0;

-  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),

-                             kOverrideMinutes));

-  bool is_overridden = false;

-  EXPECT_EQ(0, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-}

-

-TEST_F(ConfigManagerTest,

-       GetLastCheckPeriodSec_GroupPolicyOverride_Overflow_SecondsConversion) {

-  const DWORD kOverrideMinutes = UINT_MAX;

-  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),

-                             kOverrideMinutes));

-  bool is_overridden = false;

-  EXPECT_EQ(INT_MAX, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-

-  const DWORD kOverrideMinutes2 = INT_MAX + static_cast<uint32>(1);

-  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),

-                             kOverrideMinutes2));

-  is_overridden = false;

-  EXPECT_EQ(INT_MAX, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-

-  const DWORD kOverrideMinutes3 = 0xf0000000;

-  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),

-                             kOverrideMinutes3));

-  is_overridden = false;

-  EXPECT_EQ(INT_MAX, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-}

-

-// Overflow the integer but not the minutes to seconds conversion.

-TEST_F(ConfigManagerTest,

-       GetLastCheckPeriodSec_GroupPolicyOverride_Overflow_Int) {

-  const DWORD kOverrideMinutes = UINT_MAX / 60;

-  EXPECT_GT(UINT_MAX, kOverrideMinutes);

-

-  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),

-                             kOverrideMinutes));

-  bool is_overridden = false;

-  EXPECT_EQ(INT_MAX, cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-}

-

-// UpdateDev takes precedence over the Group Policy override.

-TEST_F(ConfigManagerTest,

-       GetLastCheckPeriodSec_GroupPolicyAndUpdateDevOverrides) {

-  const DWORD kGroupPolicyOverrideMinutes = 100;

-  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),

-                             kGroupPolicyOverrideMinutes));

-  const DWORD kUpdateDevOverrideSeconds = 70;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueLastCheckPeriodSec,

-                                    kUpdateDevOverrideSeconds));

-

-  bool is_overridden = false;

-  EXPECT_EQ(kUpdateDevOverrideSeconds,

-            cm_->GetLastCheckPeriodSec(&is_overridden));

-  EXPECT_TRUE(is_overridden);

-}

-

-// Legacy location is not checked.

-TEST_F(ConfigManagerTest, CanCollectStats_LegacyLocationAndName) {

-  DWORD val = 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kLegacyRegValueCollectUsageStats,

-                                    val));

-  EXPECT_FALSE(cm_->CanCollectStats(true));

-}

-

-TEST_F(ConfigManagerTest, CanCollectStats_LegacyLocationNewName) {

-  DWORD val = 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("usagestats"),

-                                    val));

-  EXPECT_FALSE(cm_->CanCollectStats(true));

-}

-

-TEST_F(ConfigManagerTest, CanCollectStats_MachineOnly) {

-  CanCollectStatsHelper(true);

-}

-

-TEST_F(ConfigManagerTest, CanCollectStats_UserOnly) {

-  CanCollectStatsHelper(false);

-}

-

-// This tests that the legacy conversion is honored.

-TEST_F(ConfigManagerTest, CanCollectStats_GoopdateGuidIsChecked) {

-  EXPECT_FALSE(cm_->CanCollectStats(true));

-

-  DWORD val = 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("usagestats"),

-                                    val));

-  EXPECT_TRUE(cm_->CanCollectStats(true));

-}

-

-TEST_F(ConfigManagerTest, CanCollectStats_MachineIgnoresUser) {

-  CanCollectStatsIgnoresOppositeHiveHelper(true);

-}

-

-TEST_F(ConfigManagerTest, CanCollectStats_UserIgnoresMachine) {

-  CanCollectStatsIgnoresOppositeHiveHelper(false);

-}

-// Unfortunately, the app's ClientStateMedium key is not checked if there is no

-// corresponding ClientState key.

-TEST_F(ConfigManagerTest,

-       CanCollectStats_Machine_ClientStateMediumOnly_AppClientStateKeyMissing) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath1,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(cm_->CanCollectStats(true));

-}

-

-TEST_F(ConfigManagerTest,

-       CanCollectStats_Machine_ClientStateMediumOnly_AppClientStateKeyExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath1));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath1,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(cm_->CanCollectStats(true));

-}

-

-TEST_F(ConfigManagerTest,

-       CanCollectStats_Machine_ClientStateMediumInvalid) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath1));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath1,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(2)));

-  EXPECT_FALSE(cm_->CanCollectStats(true));

-}

-

-TEST_F(ConfigManagerTest, CanCollectStats_User_ClientStateMediumOnly) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath1));

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKCU\\Software\\Google\\Update\\ClientStateMedium\\") APP_GUID1,

-      _T("usagestats"),

-      static_cast<DWORD>(1)));

-  EXPECT_FALSE(cm_->CanCollectStats(false));

-}

-

-TEST_F(ConfigManagerTest,

-       CanCollectStats_Machine_ClientStateZeroClientStateMediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath1,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(cm_->CanCollectStats(true));

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath1,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(cm_->CanCollectStats(true));

-}

-

-TEST_F(ConfigManagerTest,

-       CanCollectStats_Machine_ClientStateOneClientStateMediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath1,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(cm_->CanCollectStats(true));

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath1,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(cm_->CanCollectStats(true));

-}

-

-// Tests OverInstall override.

-TEST_F(ConfigManagerTest, CanOverInstall) {

-  EXPECT_EQ(cm_->CanOverInstall(), !OFFICIAL_BUILD);

-

-  DWORD val = 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueNameOverInstall,

-                                    val));

-#ifdef DEBUG

-  EXPECT_TRUE(cm_->CanOverInstall());

-#else

-  EXPECT_EQ(!OFFICIAL_BUILD, cm_->CanOverInstall());

-#endif

-

-  val = 0;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueNameOverInstall,

-                                    val));

-#ifdef DEBUG

-  EXPECT_FALSE(cm_->CanOverInstall());

-#else

-  EXPECT_EQ(!OFFICIAL_BUILD, cm_->CanOverInstall());

-#endif

-}

-

-// Tests AuCheckPeriodMs override.

-TEST_F(ConfigManagerTest, GetAutoUpdateTimerIntervalMs) {

-  EXPECT_EQ(cm_->IsGoogler() ? kAUCheckPeriodGooglerMs :

-                               kAUCheckPeriodMs,

-            cm_->GetAutoUpdateTimerIntervalMs());

-

-  DWORD val = 0;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueAuCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(kMinAUCheckPeriodMs, cm_->GetAutoUpdateTimerIntervalMs());

-

-  val = kMinAUCheckPeriodMs - 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueAuCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(kMinAUCheckPeriodMs, cm_->GetAutoUpdateTimerIntervalMs());

-

-  val = 30000;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueAuCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(val, cm_->GetAutoUpdateTimerIntervalMs());

-

-  val = INT_MAX;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueAuCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(val, cm_->GetAutoUpdateTimerIntervalMs());

-

-  // Tests overflow with large positive numbers.

-  val = INT_MAX;

-  ++val;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueAuCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(INT_MAX, cm_->GetAutoUpdateTimerIntervalMs());

-

-  val = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueAuCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(INT_MAX, cm_->GetAutoUpdateTimerIntervalMs());

-}

-

-// Tests CrCheckPeriodMs override.

-TEST_F(ConfigManagerTest, GetCodeRedTimerIntervalMs) {

-  EXPECT_EQ(kCodeRedCheckPeriodMs, cm_->GetCodeRedTimerIntervalMs());

-

-  DWORD val = 0;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueCrCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(kMinCodeRedCheckPeriodMs, cm_->GetCodeRedTimerIntervalMs());

-

-  val = kMinCodeRedCheckPeriodMs - 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueCrCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(kMinCodeRedCheckPeriodMs, cm_->GetCodeRedTimerIntervalMs());

-

-  val = 60000;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueCrCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(val, cm_->GetCodeRedTimerIntervalMs());

-

-  val = INT_MAX;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueCrCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(val, cm_->GetCodeRedTimerIntervalMs());

-

-  // Tests overflow with large positive numbers.

-  val = INT_MAX;

-  ++val;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueCrCheckPeriodMs,

-                                    val));

-  EXPECT_EQ(INT_MAX, cm_->GetCodeRedTimerIntervalMs());

-

-  val = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                      kRegValueCrCheckPeriodMs,

-                                      val));

-  EXPECT_EQ(INT_MAX, cm_->GetCodeRedTimerIntervalMs());

-}

-

-// Tests CanLogEvents override.

-TEST_F(ConfigManagerTest, CanLogEvents_WithOutOverride) {

-  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_SUCCESS));

-  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_ERROR_TYPE));

-  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_WARNING_TYPE));

-  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_INFORMATION_TYPE));

-  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_AUDIT_SUCCESS));

-  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_AUDIT_FAILURE));

-}

-

-TEST_F(ConfigManagerTest, CanLogEvents) {

-  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_INFORMATION_TYPE));

-

-  DWORD val = LOG_EVENT_LEVEL_ALL;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueEventLogLevel,

-                                    val));

-  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_SUCCESS));

-  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_ERROR_TYPE));

-  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_WARNING_TYPE));

-  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_INFORMATION_TYPE));

-  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_AUDIT_SUCCESS));

-  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_AUDIT_FAILURE));

-

-  val = LOG_EVENT_LEVEL_WARN_AND_ERROR;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueEventLogLevel,

-                                    val));

-  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_SUCCESS));

-  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_ERROR_TYPE));

-  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_WARNING_TYPE));

-  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_INFORMATION_TYPE));

-  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_AUDIT_SUCCESS));

-  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_AUDIT_FAILURE));

-}

-

-// Tests GetTestSource override.

-TEST_F(ConfigManagerTest, GetTestSource_Dev) {

-  CString expected_value;

-#if DEBUG || !OFFICIAL_BUILD

-  expected_value = kRegValueTestSourceAuto;

-#endif

-

-  CString test_source = cm_->GetTestSource();

-  EXPECT_STREQ(expected_value, test_source);

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueTestSource,

-                                   _T("dev")));

-  test_source = cm_->GetTestSource();

-  EXPECT_STREQ(_T("dev"), test_source);

-}

-

-TEST_F(ConfigManagerTest, GetTestSource_EmptyRegKey) {

-  CString expected_value;

-

-#if DEBUG || !OFFICIAL_BUILD

-  expected_value = kRegValueTestSourceAuto;

-#endif

-

-  CString test_source = cm_->GetTestSource();

-  EXPECT_STREQ(expected_value, test_source);

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueTestSource,

-                                   _T("")));

-  test_source = cm_->GetTestSource();

-  EXPECT_STREQ(kRegValueTestSourceAuto, test_source);

-}

-

-//

-// CanUseNetwork tests.

-//

-

-// Covers UpdateEulaAccepted case.

-TEST_F(ConfigManagerTest, CanUseNetwork_Machine_Normal) {

-  EXPECT_TRUE(cm_->CanUseNetwork(true));

-}

-

-// Covers UpdateEulaAccepted case.

-TEST_F(ConfigManagerTest, CanUseNetwork_User_Normal) {

-  EXPECT_TRUE(cm_->CanUseNetwork(false));

-}

-

-// These cover the not OEM install mode cases.

-TEST_F(ConfigManagerTest, CanUseNetwork_Machine_UpdateEulaNotAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(cm_->CanUseNetwork(true));

-}

-

-TEST_F(ConfigManagerTest,

-       CanUseNetwork_Machine_UpdateEulaNotAccepted_AppEulaAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath1,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(cm_->CanUseNetwork(true));

-}

-

-TEST_F(ConfigManagerTest, CanUseNetwork_Machine_AppEulaNotAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath1,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_TRUE(cm_->CanUseNetwork(true));

-}

-

-TEST_F(ConfigManagerTest, CanUseNetwork_Machine_AppEulaAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath1,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(cm_->CanUseNetwork(true));

-}

-

-TEST_F(ConfigManagerTest, CanUseNetwork_Machine_UserUpdateEulaNotAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_TRUE(cm_->CanUseNetwork(true));

-}

-

-TEST_F(ConfigManagerTest, CanUseNetwork_User_UpdateEulaNotAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(cm_->CanUseNetwork(false));

-}

-

-TEST_F(ConfigManagerTest,

-       CanUseNetwork_User_UpdateEulaNotAccepted_AppEulaAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath1,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(cm_->CanUseNetwork(false));

-}

-

-TEST_F(ConfigManagerTest, CanUseNetwork_User_AppEulaNotAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath1,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_TRUE(cm_->CanUseNetwork(false));

-}

-

-TEST_F(ConfigManagerTest, CanUseNetwork_User_AppEulaAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath1,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(cm_->CanUseNetwork(false));

-}

-

-TEST_F(ConfigManagerTest, CanUseNetwork_User_MachineUpdateEulaNotAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_TRUE(cm_->CanUseNetwork(false));

-}

-

-

-// Covers UpdateEulaAccepted case.

-TEST_F(ConfigManagerTest,

-       CanUseNetwork_Machine_OemInstallTimeNow_NotAuditMode) {

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-

-  EXPECT_FALSE(cm_->CanUseNetwork(true));

-}

-

-TEST_F(ConfigManagerTest,

-       CanUseNetwork_Machine_OemInstallTimeNow_NotAuditMode_UpdateEulaNotAccepted) {  //NOLINT

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_FALSE(cm_->CanUseNetwork(true));

-}

-

-// These cover the EULA accepted cases.

-TEST_F(ConfigManagerTest,

-       CanUseNetwork_Machine_OemInstallTime73HoursAgo_NotAuditMode) {

-  const DWORD kDesiredDifferenceSeconds = 73 * 60 * 60;  // 73 hours.

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_GT(now_seconds, kDesiredDifferenceSeconds);

-  const DWORD install_time_seconds = now_seconds - kDesiredDifferenceSeconds;

-  EXPECT_LT(install_time_seconds, now_seconds);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    install_time_seconds));

-  EXPECT_FALSE(cm_->IsOemInstalling(true));

-

-  EXPECT_TRUE(cm_->CanUseNetwork(true));

-}

-

-TEST_F(ConfigManagerTest, CanUseNetwork_User_OemInstallTimeNow_AuditMode) {

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_FALSE(cm_->IsOemInstalling(false));

-

-  EXPECT_TRUE(cm_->CanUseNetwork(false));

-}

-

-TEST_F(ConfigManagerTest, CanUseNetwork_User_OemInstallTimeNow_AuditMode_UpdateEulaNotAccepted) {  //NOLINT

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_FALSE(cm_->IsOemInstalling(false));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_FALSE(cm_->CanUseNetwork(false));

-}

-

-//

-// IsOemInstalling tests.

-//

-

-TEST_F(ConfigManagerTest, IsOemInstalling_Machine_Normal) {

-  EXPECT_FALSE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest, IsOemInstalling_User_Normal) {

-  EXPECT_FALSE(cm_->IsOemInstalling(false));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTimeNow_NotAuditMode) {

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest, IsOemInstalling_Machine_OemInstallTimeNow_AuditMode) {

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTime71HoursAgo_NotAuditMode) {

-  const DWORD kDesiredDifferenceSeconds = 71 * 60 * 60;  // 71 hours.

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_GT(now_seconds, kDesiredDifferenceSeconds);

-  const DWORD install_time_seconds = now_seconds - kDesiredDifferenceSeconds;

-  EXPECT_LT(install_time_seconds, now_seconds);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    install_time_seconds));

-

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTime71HoursAgo_AuditMode) {

-  const DWORD kDesiredDifferenceSeconds = 71 * 60 * 60;  // 71 hours.

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_GT(now_seconds, kDesiredDifferenceSeconds);

-  const DWORD install_time_seconds = now_seconds - kDesiredDifferenceSeconds;

-  EXPECT_LT(install_time_seconds, now_seconds);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    install_time_seconds));

-

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTime73HoursAgo_NotAuditMode) {

-  const DWORD kDesiredDifferenceSeconds = 73 * 60 * 60;  // 73 hours.

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_GT(now_seconds, kDesiredDifferenceSeconds);

-  const DWORD install_time_seconds = now_seconds - kDesiredDifferenceSeconds;

-  EXPECT_LT(install_time_seconds, now_seconds);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    install_time_seconds));

-

-  EXPECT_FALSE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTime73HoursAgo_AuditMode) {

-  const DWORD kDesiredDifferenceSeconds = 73 * 60 * 60;  // 73 hours.

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_GT(now_seconds, kDesiredDifferenceSeconds);

-  const DWORD install_time_seconds = now_seconds - kDesiredDifferenceSeconds;

-  EXPECT_LT(install_time_seconds, now_seconds);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    install_time_seconds));

-

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTime71HoursInFuture_NotAuditMode) {

-  const DWORD kDesiredDifferenceSeconds = 71 * 60 * 60;  // 71 hours.

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  const DWORD install_time_seconds = now_seconds + kDesiredDifferenceSeconds;

-  EXPECT_GT(install_time_seconds, now_seconds);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    install_time_seconds));

-

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTime71HoursInFuture_AuditMode) {

-  const DWORD kDesiredDifferenceSeconds = 71 * 60 * 60;  // 71 hours.

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  const DWORD install_time_seconds = now_seconds + kDesiredDifferenceSeconds;

-  EXPECT_GT(install_time_seconds, now_seconds);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    install_time_seconds));

-

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTime73HoursInFuture_NotAuditMode) {

-  const DWORD kDesiredDifferenceSeconds = 73 * 60 * 60;  // 73 hours.

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  const DWORD install_time_seconds = now_seconds + kDesiredDifferenceSeconds;

-  EXPECT_GT(install_time_seconds, now_seconds);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    install_time_seconds));

-

-  EXPECT_FALSE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTime73HoursInFuture_AuditMode) {

-  const DWORD kDesiredDifferenceSeconds = 73 * 60 * 60;  // 73 hours.

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  const DWORD install_time_seconds = now_seconds + kDesiredDifferenceSeconds;

-  EXPECT_GT(install_time_seconds, now_seconds);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    install_time_seconds));

-

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTimeZero_NotAuditMode) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_FALSE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTimeZero_AuditMode) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    static_cast<DWORD>(0)));

-

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_TRUE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTimeWrongType_NotAuditMode) {

-  const uint32 now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  const CString now_string = itostr(now_seconds);

-  EXPECT_FALSE(now_string.IsEmpty());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_string));

-

-  EXPECT_FALSE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_Machine_OemInstallTimeWrongType_AuditMode) {

-  const uint32 now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  const CString now_string = itostr(now_seconds);

-  EXPECT_FALSE(now_string.IsEmpty());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_string));

-

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_FALSE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest, IsOemInstalling_Machine_NoOemInstallTime_AuditMode) {

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_FALSE(cm_->IsOemInstalling(true));

-}

-

-TEST_F(ConfigManagerTest,

-       IsOemInstalling_User_OemInstallTimeNow_NotAuditMode) {

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-

-  EXPECT_FALSE(cm_->IsOemInstalling(false));

-}

-

-TEST_F(ConfigManagerTest, IsOemInstalling_User_OemInstallTimeNow_AuditMode) {

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-

-  if (vista_util::IsVistaOrLater()) {

-    EXPECT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_FALSE(cm_->IsOemInstalling(false));

-}

-

-// TODO(omaha): Figure out a way to test the result.

-TEST_F(ConfigManagerTest, IsGoogler) {

-  cm_->IsGoogler();

-}

-

-TEST_F(ConfigManagerTest, IsWindowsInstalling_Normal) {

-  EXPECT_FALSE(cm_->IsWindowsInstalling());

-}

-

-TEST_F(ConfigManagerTest, IsWindowsInstalling_Installing_Vista_InvalidValues) {

-  if (!vista_util::IsVistaOrLater()) {

-    return;

-  }

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("")));

-  EXPECT_FALSE(cm_->IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("foo")));

-  EXPECT_FALSE(cm_->IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      static_cast<DWORD>(1)));

-  ExpectAsserts expect_asserts;  // RegKey asserts because value type is wrong.

-  EXPECT_FALSE(cm_->IsWindowsInstalling());

-}

-

-TEST_F(ConfigManagerTest, IsWindowsInstalling_Installing_Vista_ValidStates) {

-  if (!vista_util::IsVistaOrLater()) {

-    return;

-  }

-

-  // These states return false in the original implementation.

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_COMPLETE")));

-  EXPECT_FALSE(cm_->IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE")));

-  EXPECT_FALSE(cm_->IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_OOBE")));

-  EXPECT_FALSE(cm_->IsWindowsInstalling());

-

-  // These states are specified in the original implementation.

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_UNDEPLOYABLE")));

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_AUDIT")));

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-      _T("ImageState"),

-      _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_AUDIT")));

-  EXPECT_TRUE(cm_->IsWindowsInstalling());

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_NoGroupPolicy) {

-  EXPECT_TRUE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_DifferentAppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp2, 0));

-  EXPECT_TRUE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_NoDefaultValue_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 0));

-  EXPECT_FALSE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_NoDefaultValue_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 1));

-  EXPECT_TRUE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_NoDefaultValue_AppInvalid) {

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 2));

-  EXPECT_TRUE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_DefaultDisabled_NoAppValue) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 0));

-  EXPECT_FALSE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_DefaultDisabled_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 0));

-  EXPECT_FALSE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_DefaultDisabled_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 1));

-  EXPECT_TRUE(CanInstallApp(kAppGuid1));

-}

-

-// Invalid value defaulting to true overrides the InstallDefault disable.

-TEST_F(ConfigManagerTest, CanInstallApp_DefaultDisabled_AppInvalid) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 2));

-  EXPECT_TRUE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_DefaultEnabled_NoAppValue) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 1));

-  EXPECT_TRUE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_DefaultEnabled_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 0));

-  EXPECT_FALSE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_DefaultEnabled_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 1));

-  EXPECT_TRUE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanInstallApp_DefaultEnabled_AppInvalid) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 2));

-  EXPECT_TRUE(CanInstallApp(kAppGuid1));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_NoGroupPolicy) {

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DifferentAppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 0));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DifferentAppManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 2));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_NoDefaultValue_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_NoDefaultValue_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_NoDefaultValue_AppManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultDisabled_NoAppValue) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultDisabled_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultDisabled_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultDisabled_AppManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));

-}

-

-// Invalid value defaulting to true overrides the UpdateDefault disable.

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultDisabled_AppInvalid) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultEnabled_NoAppValue) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultEnabled_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultEnabled_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultEnabled_AppManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultEnabled_AppInvalid) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultManualOnly_NoAppValue) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultManualOnly_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultManualOnly_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultManualOnly_AppManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultManualOnly_AppInvalid) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultInvalid_NoAppValue) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 3));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_GoogleUpdate_DefaultDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-                           false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_GoogleUpdate_DefaultManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-                           false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Auto_GoogleUpdate_AppDisabled) {

-  EXPECT_SUCCEEDED(

-      SetPolicy(_T("Update{430FD4D0-B729-4F61-AA34-91526481799D}"), 0));

-  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"),

-                           false));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_NoGroupPolicy) {

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DifferentAppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 0));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DifferentAppManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 2));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_NoDefaultValue_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_NoDefaultValue_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_NoDefaultValue_AppManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultDisabled_NoAppValue) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultDisabled_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultDisabled_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultDisabled_AppManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-// Invalid value defaulting to true overrides the UpdateDefault disable.

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultDisabled_AppInvalid) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultEnabled_NoAppValue) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultEnabled_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultEnabled_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultEnabled_AppManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultEnabled_AppInvalid) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultManualOnly_NoAppValue) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultManualOnly_AppDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));

-  EXPECT_FALSE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultManualOnly_AppEnabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultManualOnly_AppManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Maual_DefaultManualOnly_AppInvalid) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultInvalid_NoAppValue) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 3));

-  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_GoogleUpdate_DefaultDisabled) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));

-  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"), true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_GoogleUpdate_DefaultManualOnly) {

-  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));

-  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"), true));

-}

-

-TEST_F(ConfigManagerTest, CanUpdateApp_Manual_GoogleUpdate_AppDisabled) {

-  EXPECT_SUCCEEDED(

-      SetPolicy(_T("Update{430FD4D0-B729-4F61-AA34-91526481799D}"), 0));

-  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"), true));

-}

-

-TEST_F(ConfigManagerTest, LastCheckedTime) {

-  DWORD time = 500;

-  EXPECT_SUCCEEDED(cm_->SetLastCheckedTime(true, time));

-  EXPECT_EQ(time, cm_->GetLastCheckedTime(true));

-

-  time = 77003;

-  EXPECT_SUCCEEDED(cm_->SetLastCheckedTime(false, time));

-  EXPECT_EQ(time, cm_->GetLastCheckedTime(false));

-}

-

-// Tests GetDir indirectly.

-TEST_F(ConfigManagerTest, GetDir) {

-  RestoreRegistryHives();

-

-  CString user_install_dir = cm_->GetUserGoopdateInstallDir();

-  CString user_profile;

-  ASSERT_NE(0, ::GetEnvironmentVariable(_T("USERPROFILE"),

-                                        CStrBuf(user_profile, MAX_PATH),

-                                        MAX_PATH));

-  ASSERT_TRUE(String_StartsWith(user_install_dir, user_profile, true));

-}

-

-TEST_F(ConfigManagerTest, GetUpdateWorkerStartUpDelayMs_Repeated) {

-  if (!SystemInfo::IsRunningOnXPOrLater()) {

-    std::wcout << _T("\tTest did not run because GenRandom breaks on Windows ")

-               << _T("2000 if the registry keys are overridden.") << std::endl;

-    return;

-  }

-

-  // Test the UpdateDelay multiple times.

-  for (int i = 0; i < 10; ++i) {

-    int random = cm_->GetUpdateWorkerStartUpDelayMs();

-    EXPECT_GE(random, kUpdateTimerStartupDelayMinMs);

-    EXPECT_LE(random, kUpdateTimerStartupDelayMaxMs);

-  }

-}

-

-TEST_F(ConfigManagerTest, GetUpdateWorkerStartUpDelayMs) {

-  if (!SystemInfo::IsRunningOnXPOrLater()) {

-    std::wcout << _T("\tTest did not run because GenRandom breaks on Windows ")

-               << _T("2000 if the registry keys are overridden.") << std::endl;

-    return;

-  }

-

-  int random = cm_->GetUpdateWorkerStartUpDelayMs();

-  EXPECT_GE(random, kUpdateTimerStartupDelayMinMs);

-  EXPECT_LE(random, kUpdateTimerStartupDelayMaxMs);

-

-  int num_times_to_try_for_diff_number = 3;

-  // We run the method num_times_to_try_for_diff_number times to make

-  // sure that at least one of these returns a number that is different

-  // from the one that is returned above. This is needed, since the

-  // method returns a number between kUpdateTimerStartupDelayMinMs and

-  // kUpdateTimerStartupDelayMaxMs.

-  // If this fails a lot we should disable the if check below.

-  bool found_one_not_equal = false;

-  for (int i = 0; i < num_times_to_try_for_diff_number; ++i) {

-    int random_compare = cm_->GetUpdateWorkerStartUpDelayMs();

-

-    EXPECT_GE(random_compare, kUpdateTimerStartupDelayMinMs);

-    EXPECT_LE(random_compare, kUpdateTimerStartupDelayMaxMs);

-

-    if (random_compare != random) {

-      found_one_not_equal = true;

-      break;

-    }

-  }

-

-  EXPECT_TRUE(found_one_not_equal);

-}

-

-TEST_F(ConfigManagerTest, GetUpdateWorkerStartUpDelayMs_Override) {

-  // Test that the initial delay time to launch a worker can be overriden.

-  DWORD val = 3320;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueAuCheckPeriodMs,

-                                    val));

-

-  int random = cm_->GetUpdateWorkerStartUpDelayMs();

-  EXPECT_EQ(val, random);

-}

-

-TEST_F(ConfigManagerTest, GetTimeSinceLastCheckedSec_User) {

-  // First, there is no value present in the registry.

-  uint32 now_sec = Time64ToInt32(GetCurrent100NSTime());

-  int time_since_last_checked_sec = cm_->GetTimeSinceLastCheckedSec(false);

-  EXPECT_EQ(now_sec, time_since_last_checked_sec);

-

-  // Second, write the 'now' time.

-  EXPECT_HRESULT_SUCCEEDED(cm_->SetLastCheckedTime(false, now_sec));

-  time_since_last_checked_sec = cm_->GetTimeSinceLastCheckedSec(false);

-  EXPECT_EQ(0, time_since_last_checked_sec);

-}

-

-TEST_F(ConfigManagerTest, GetTimeSinceLastCheckedSec_Machine) {

-  uint32 now_sec = Time64ToInt32(GetCurrent100NSTime());

-  int time_since_last_checked_sec = cm_->GetTimeSinceLastCheckedSec(true);

-  EXPECT_EQ(now_sec, time_since_last_checked_sec);

-

-  EXPECT_HRESULT_SUCCEEDED(cm_->SetLastCheckedTime(true, now_sec));

-  time_since_last_checked_sec = cm_->GetTimeSinceLastCheckedSec(true);

-  EXPECT_EQ(0, time_since_last_checked_sec);

-}

-

-TEST_F(ConfigManagerTest, GetNetConfig) {

-  CString actual_value;

-  EXPECT_HRESULT_FAILED(cm_->GetNetConfig(&actual_value));

-

-  const CString expected_value = _T("proxy:8080");

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueNetConfig,

-                                    expected_value));

-

-  EXPECT_HRESULT_SUCCEEDED(cm_->GetNetConfig(&actual_value));

-  EXPECT_STREQ(expected_value, actual_value);

-}

-

-TEST_F(ConfigManagerTest, GetInstallTime) {

-  EXPECT_SUCCEEDED(DeleteUpdateTime(false));

-  EXPECT_SUCCEEDED(DeleteFirstInstallTime(false));

-  EXPECT_EQ(0, ConfigManager::GetInstallTime(false));

-

-  DWORD time = 500;

-  EXPECT_SUCCEEDED(SetFirstInstallTime(false, time));

-  EXPECT_EQ(time, ConfigManager::GetInstallTime(false));

-

-  time = 1000;

-  EXPECT_SUCCEEDED(SetUpdateTime(false, time));

-  EXPECT_EQ(time, ConfigManager::GetInstallTime(false));

-

-  EXPECT_SUCCEEDED(DeleteFirstInstallTime(false));

-  EXPECT_EQ(time, ConfigManager::GetInstallTime(false));

-}

-

-TEST_F(ConfigManagerTest, Is24HoursSinceInstall) {

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-  const int k12HourPeriodSec = 12 * 60 * 60;

-  const int k48HourPeriodSec = 48 * 60 * 60;

-

-  const uint32 first_install_12 = now - k12HourPeriodSec;

-  const uint32 first_install_48 = now - k48HourPeriodSec;

-

-  EXPECT_SUCCEEDED(SetFirstInstallTime(false, first_install_12));

-  EXPECT_FALSE(ConfigManager::Is24HoursSinceInstall(false));

-

-  EXPECT_SUCCEEDED(SetFirstInstallTime(false, first_install_48));

-  EXPECT_TRUE(ConfigManager::Is24HoursSinceInstall(false));

-

-  EXPECT_SUCCEEDED(SetUpdateTime(false, first_install_12));

-  EXPECT_FALSE(ConfigManager::Is24HoursSinceInstall(false));

-

-  EXPECT_SUCCEEDED(SetUpdateTime(false, first_install_48));

-  EXPECT_TRUE(ConfigManager::Is24HoursSinceInstall(false));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <limits.h>
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/file.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+#define APP_GUID1 _T("{6762F466-8863-424f-817C-5757931F346E}")
+const TCHAR* const kAppGuid1 = APP_GUID1;
+const TCHAR* const kAppMachineClientStatePath1 =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\") APP_GUID1;
+const TCHAR* const kAppUserClientStatePath1 =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\") APP_GUID1;
+const TCHAR* const kAppMachineClientStateMediumPath1 =
+    _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\") APP_GUID1;
+
+#define APP_GUID2 _T("{8A0FDD16-D4B7-4167-893F-1386F2A2F0FB}")
+const TCHAR* const kAppGuid2 = APP_GUID2;
+const TCHAR* const kAppMachineClientStatePath2 =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\") APP_GUID2;
+const TCHAR* const kAppUserClientStatePath2 =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\") APP_GUID2;
+
+const TCHAR* const kPolicyKey =
+    _T("HKLM\\Software\\Policies\\Google\\Update\\");
+const TCHAR* const kInstallPolicyApp1 = _T("Install") APP_GUID1;
+const TCHAR* const kInstallPolicyApp2 = _T("Install") APP_GUID2;
+const TCHAR* const kUpdatePolicyApp1 = _T("Update") APP_GUID1;
+const TCHAR* const kUpdatePolicyApp2 = _T("Update") APP_GUID2;
+
+// Helper to write policies to the registry. Eliminates ambiguity of which
+// overload of SetValue to use without the need for static_cast.
+HRESULT SetPolicy(const TCHAR* policy_name, DWORD value) {
+  return RegKey::SetValue(kPolicyKey, policy_name, value);
+}
+
+}  // namespace
+
+class ConfigManagerNoOverrideTest : public testing::Test {
+ protected:
+  ConfigManagerNoOverrideTest()
+      : cm_(ConfigManager::Instance()) {
+  }
+
+  bool CanInstallApp(const TCHAR* guid) {
+    return cm_->CanInstallApp(StringToGuid(guid));
+  }
+
+  bool CanUpdateApp(const TCHAR* guid, bool is_manual) {
+    return cm_->CanUpdateApp(StringToGuid(guid), is_manual);
+  }
+
+  ConfigManager* cm_;
+};
+
+class ConfigManagerTest : public ConfigManagerNoOverrideTest {
+ protected:
+  ConfigManagerTest()
+      : hive_override_key_name_(kRegistryHiveOverrideRoot) {
+  }
+
+  virtual void SetUp() {
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    OverrideRegistryHives(hive_override_key_name_);
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    EXPECT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+  }
+
+  void CanCollectStatsHelper(bool is_machine);
+  void CanCollectStatsIgnoresOppositeHiveHelper(bool is_machine);
+  HRESULT SetFirstInstallTime(bool is_machine, DWORD time);
+  HRESULT DeleteFirstInstallTime(bool is_machine);
+  HRESULT SetUpdateTime(bool is_machine, DWORD time);
+  HRESULT DeleteUpdateTime(bool is_machine);
+
+  CString hive_override_key_name_;
+};
+
+void ConfigManagerTest::CanCollectStatsHelper(bool is_machine) {
+  const TCHAR* app1_state_key_name = is_machine ? kAppMachineClientStatePath1 :
+                                                  kAppUserClientStatePath1;
+
+  EXPECT_FALSE(cm_->CanCollectStats(is_machine));
+
+  // Test the 'UsageStats' override.
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueForceUsageStats,
+                                    _T("")));
+  EXPECT_TRUE(cm_->CanCollectStats(is_machine));
+  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,
+                                       kRegValueForceUsageStats));
+
+  DWORD val = 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(app1_state_key_name,
+                                    _T("usagestats"),
+                                    val));
+  EXPECT_TRUE(cm_->CanCollectStats(is_machine));
+
+  val = 2;  // invalid value
+  EXPECT_SUCCEEDED(RegKey::SetValue(app1_state_key_name,
+                                    _T("usagestats"),
+                                    val));
+  EXPECT_FALSE(cm_->CanCollectStats(is_machine));
+
+  val = 0;
+  EXPECT_SUCCEEDED(RegKey::SetValue(app1_state_key_name,
+                                    _T("usagestats"),
+                                    val));
+  EXPECT_FALSE(cm_->CanCollectStats(is_machine));
+
+  // One 0 and one 1 results in true. The alphabetical order of the GUIDs is
+  // important assuming GetSubkeyNameAt returns subkeys in alphabetical order.
+  const TCHAR* app2_state_key_name = is_machine ? kAppMachineClientStatePath2 :
+                                                  kAppUserClientStatePath2;
+  val = 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(app2_state_key_name,
+                                    _T("usagestats"),
+                                    val));
+  EXPECT_TRUE(cm_->CanCollectStats(is_machine));
+}
+
+void ConfigManagerTest::CanCollectStatsIgnoresOppositeHiveHelper(
+    bool is_machine) {
+  const TCHAR* app1_state_key_name = is_machine ? kAppMachineClientStatePath1 :
+                                                  kAppUserClientStatePath1;
+
+  EXPECT_FALSE(cm_->CanCollectStats(is_machine));
+
+  DWORD val = 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(app1_state_key_name,
+                                    _T("usagestats"),
+                                    val));
+  EXPECT_TRUE(cm_->CanCollectStats(is_machine));
+  EXPECT_FALSE(cm_->CanCollectStats(!is_machine));
+}
+
+HRESULT ConfigManagerTest::SetFirstInstallTime(bool is_machine, DWORD time) {
+  return RegKey::SetValue(cm_->registry_client_state_goopdate(is_machine),
+                          kRegValueInstallTimeSec,
+                          time);
+}
+
+HRESULT ConfigManagerTest::DeleteFirstInstallTime(bool is_machine) {
+  if (!RegKey::HasValue(cm_->registry_client_state_goopdate(is_machine),
+                        kRegValueInstallTimeSec)) {
+    return S_OK;
+  }
+
+  return RegKey::DeleteValue(cm_->registry_client_state_goopdate(is_machine),
+                             kRegValueInstallTimeSec);
+}
+
+HRESULT ConfigManagerTest::SetUpdateTime(bool is_machine, DWORD time) {
+  return RegKey::SetValue(cm_->registry_client_state_goopdate(is_machine),
+                          kRegValueLastUpdateTimeSec,
+                          time);
+}
+
+HRESULT ConfigManagerTest::DeleteUpdateTime(bool is_machine) {
+  if (!RegKey::HasValue(cm_->registry_client_state_goopdate(is_machine),
+                        kRegValueLastUpdateTimeSec)) {
+    return S_OK;
+  }
+
+  return RegKey::DeleteValue(cm_->registry_client_state_goopdate(is_machine),
+                             kRegValueLastUpdateTimeSec);
+}
+
+TEST_F(ConfigManagerNoOverrideTest, RegistryKeys) {
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\Clients\\"),
+               cm_->user_registry_clients());
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\Clients\\"),
+               cm_->machine_registry_clients());
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\Clients\\"),
+               cm_->registry_clients(false));
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\Clients\\"),
+               cm_->registry_clients(true));
+
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\Clients\\")
+               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+               cm_->user_registry_clients_goopdate());
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\Clients\\")
+               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+               cm_->machine_registry_clients_goopdate());
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\Clients\\")
+               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+               cm_->registry_clients_goopdate(false));
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\Clients\\")
+               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+               cm_->registry_clients_goopdate(true));
+
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\ClientState\\"),
+               cm_->user_registry_client_state());
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientState\\"),
+               cm_->machine_registry_client_state());
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\ClientState\\"),
+               cm_->registry_client_state(false));
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientState\\"),
+               cm_->registry_client_state(true));
+
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\ClientState\\")
+               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+               cm_->user_registry_client_state_goopdate());
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientState\\")
+               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+               cm_->machine_registry_client_state_goopdate());
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\ClientState\\")
+               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+               cm_->registry_client_state_goopdate(false));
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientState\\")
+               _T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+               cm_->registry_client_state_goopdate(true));
+
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\"),
+               cm_->machine_registry_client_state_medium());
+
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\"),
+               cm_->user_registry_update());
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\"),
+               cm_->machine_registry_update());
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\"),
+               cm_->registry_update(false));
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\"),
+               cm_->registry_update(true));
+
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\"),
+               cm_->user_registry_google());
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\"),
+               cm_->machine_registry_google());
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\"),
+               cm_->registry_google(false));
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\"),
+               cm_->registry_google(true));
+}
+
+TEST_F(ConfigManagerNoOverrideTest, GetUserCrashReportsDir) {
+  const CString expected_path = GetGoogleUserPath() + _T("CrashReports");
+  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));
+  EXPECT_STREQ(expected_path, cm_->GetUserCrashReportsDir());
+  EXPECT_TRUE(File::Exists(expected_path));
+}
+
+// Should run before the subdirectory tests to ensure the directory is created.
+TEST_F(ConfigManagerNoOverrideTest, GetUserGoopdateInstallDir) {
+  const CString expected_path = GetGoogleUserPath() + _T("Update");
+  EXPECT_STREQ(expected_path, cm_->GetUserGoopdateInstallDir());
+  EXPECT_TRUE(File::Exists(expected_path));
+}
+
+TEST_F(ConfigManagerNoOverrideTest, GetDownloadStorage) {
+  const CString expected_path = GetGoogleUpdateUserPath() + _T("Download");
+  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));
+  EXPECT_STREQ(expected_path, cm_->GetUserDownloadStorageDir());
+  EXPECT_TRUE(File::Exists(expected_path));
+}
+
+TEST_F(ConfigManagerNoOverrideTest, GetUserDownloadStorageDir) {
+  const CString expected_path = GetGoogleUpdateUserPath() + _T("Download");
+  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));
+  EXPECT_STREQ(expected_path, cm_->GetUserDownloadStorageDir());
+  EXPECT_TRUE(File::Exists(expected_path));
+}
+
+TEST_F(ConfigManagerNoOverrideTest, GetUserOfflineStorageDir) {
+  const CString expected_path = GetGoogleUpdateUserPath() + _T("Offline");
+  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));
+  EXPECT_STREQ(expected_path, cm_->GetUserOfflineStorageDir());
+  EXPECT_TRUE(File::Exists(expected_path));
+}
+
+TEST_F(ConfigManagerNoOverrideTest, IsRunningFromUserGoopdateInstallDir) {
+  EXPECT_FALSE(cm_->IsRunningFromUserGoopdateInstallDir());
+}
+
+TEST_F(ConfigManagerNoOverrideTest, GetMachineCrashReportsDir) {
+  CString program_files;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files));
+  const CString expected_path = program_files + _T("\\Google\\CrashReports");
+  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));
+  EXPECT_STREQ(expected_path, cm_->GetMachineCrashReportsDir());
+  EXPECT_TRUE(File::Exists(expected_path) || !vista_util::IsUserAdmin());
+}
+
+// Should run before the subdirectory tests to ensure the directory is created.
+TEST_F(ConfigManagerNoOverrideTest, GetMachineGoopdateInstallDir) {
+  CString expected_path = GetGoogleUpdateMachinePath();
+  EXPECT_STREQ(expected_path, cm_->GetMachineGoopdateInstallDir());
+  EXPECT_TRUE(File::Exists(expected_path) || !vista_util::IsUserAdmin());
+}
+
+TEST_F(ConfigManagerNoOverrideTest, GetMachineSecureDownloadStorageDir) {
+  CString expected_path = GetGoogleUpdateMachinePath() + _T("\\Download");
+  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));
+  EXPECT_STREQ(expected_path, cm_->GetMachineSecureDownloadStorageDir());
+  EXPECT_TRUE(File::Exists(expected_path) || !vista_util::IsUserAdmin());
+}
+
+TEST_F(ConfigManagerNoOverrideTest, GetMachineSecureOfflineStorageDir) {
+  CString expected_path = GetGoogleUpdateMachinePath() + _T("\\Offline");
+  EXPECT_SUCCEEDED(DeleteDirectory(expected_path));
+  EXPECT_STREQ(expected_path, cm_->GetMachineSecureOfflineStorageDir());
+  EXPECT_TRUE(File::Exists(expected_path) || !vista_util::IsUserAdmin());
+}
+
+TEST_F(ConfigManagerNoOverrideTest, IsRunningFromMachineGoopdateInstallDir) {
+  EXPECT_FALSE(cm_->IsRunningFromMachineGoopdateInstallDir());
+}
+
+// Tests the GetUpdateCheckUrl override.
+TEST_F(ConfigManagerTest, GetUpdateCheckUrl) {
+  CString url;
+  EXPECT_SUCCEEDED(cm_->GetUpdateCheckUrl(&url));
+  EXPECT_STREQ(url, kUrlUpdateCheck);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueNameUrl,
+                                    _T("http://foo/")));
+  url.Empty();
+  EXPECT_TRUE(url.IsEmpty());
+  EXPECT_SUCCEEDED(cm_->GetUpdateCheckUrl(&url));
+#ifdef DEBUG
+  EXPECT_STREQ(url, _T("http://foo/"));
+#else
+  EXPECT_STREQ(url, kUrlUpdateCheck);
+#endif
+}
+
+// Tests the GetPingUrl override.
+TEST_F(ConfigManagerTest, GetPingUrl) {
+  CString url;
+  EXPECT_SUCCEEDED(cm_->GetPingUrl(&url));
+  EXPECT_STREQ(url, kUrlPing);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueNamePingUrl,
+                                    _T("http://bar/")));
+  url.Empty();
+  EXPECT_TRUE(url.IsEmpty());
+  EXPECT_SUCCEEDED(cm_->GetPingUrl(&url));
+#ifdef DEBUG
+  EXPECT_STREQ(url, _T("http://bar/"));
+#else
+  EXPECT_STREQ(url, kUrlPing);
+#endif
+}
+
+// Tests LastCheckPeriodSec override.
+TEST_F(ConfigManagerTest, GetLastCheckPeriodSec_Default) {
+  bool is_overridden = true;
+  if (cm_->IsGoogler()) {
+    EXPECT_EQ(kLastCheckPeriodGooglerSec,
+              cm_->GetLastCheckPeriodSec(&is_overridden));
+  } else {
+    EXPECT_EQ(kLastCheckPeriodSec, cm_->GetLastCheckPeriodSec(&is_overridden));
+  }
+  EXPECT_FALSE(is_overridden);
+}
+
+TEST_F(ConfigManagerTest, GetLastCheckPeriodSec_UpdateDevOverride) {
+  // Zero is a special value meaning disabled.
+  DWORD val = 0;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueLastCheckPeriodSec,
+                                    val));
+  bool is_overridden = false;
+  EXPECT_EQ(0, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+
+  val = kMinLastCheckPeriodSec - 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueLastCheckPeriodSec,
+                                    val));
+  is_overridden = false;
+  EXPECT_EQ(kMinLastCheckPeriodSec, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+
+  val = INT_MAX + static_cast<uint32>(1);
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueLastCheckPeriodSec,
+                                    val));
+  is_overridden = false;
+  EXPECT_EQ(INT_MAX, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+
+  val = 1000;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueLastCheckPeriodSec,
+                                    val));
+  is_overridden = false;
+  EXPECT_EQ(1000, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+
+  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,
+                                       kRegValueLastCheckPeriodSec));
+  is_overridden = true;
+  if (cm_->IsGoogler()) {
+    EXPECT_EQ(kLastCheckPeriodGooglerSec,
+              cm_->GetLastCheckPeriodSec(&is_overridden));
+  } else {
+    EXPECT_EQ(kLastCheckPeriodSec, cm_->GetLastCheckPeriodSec(&is_overridden));
+  }
+  EXPECT_FALSE(is_overridden);
+}
+
+TEST_F(ConfigManagerTest, GetLastCheckPeriodSec_GroupPolicyOverride) {
+  const DWORD kOverrideMinutes = 16000;
+  const DWORD kExpectedSeconds = kOverrideMinutes * 60;
+  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),
+                             kOverrideMinutes));
+  bool is_overridden = false;
+  EXPECT_EQ(kExpectedSeconds, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+}
+
+TEST_F(ConfigManagerTest, GetLastCheckPeriodSec_GroupPolicyOverride_TooLow) {
+  const DWORD kOverrideMinutes = 1;
+  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),
+                             kOverrideMinutes));
+  bool is_overridden = false;
+  EXPECT_EQ(kMinLastCheckPeriodSec, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+}
+
+TEST_F(ConfigManagerTest, GetLastCheckPeriodSec_GroupPolicyOverride_Zero) {
+  const DWORD kOverrideMinutes = 0;
+  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),
+                             kOverrideMinutes));
+  bool is_overridden = false;
+  EXPECT_EQ(0, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+}
+
+TEST_F(ConfigManagerTest,
+       GetLastCheckPeriodSec_GroupPolicyOverride_Overflow_SecondsConversion) {
+  const DWORD kOverrideMinutes = UINT_MAX;
+  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),
+                             kOverrideMinutes));
+  bool is_overridden = false;
+  EXPECT_EQ(INT_MAX, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+
+  const DWORD kOverrideMinutes2 = INT_MAX + static_cast<uint32>(1);
+  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),
+                             kOverrideMinutes2));
+  is_overridden = false;
+  EXPECT_EQ(INT_MAX, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+
+  const DWORD kOverrideMinutes3 = 0xf0000000;
+  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),
+                             kOverrideMinutes3));
+  is_overridden = false;
+  EXPECT_EQ(INT_MAX, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+}
+
+// Overflow the integer but not the minutes to seconds conversion.
+TEST_F(ConfigManagerTest,
+       GetLastCheckPeriodSec_GroupPolicyOverride_Overflow_Int) {
+  const DWORD kOverrideMinutes = UINT_MAX / 60;
+  EXPECT_GT(UINT_MAX, kOverrideMinutes);
+
+  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),
+                             kOverrideMinutes));
+  bool is_overridden = false;
+  EXPECT_EQ(INT_MAX, cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+}
+
+// UpdateDev takes precedence over the Group Policy override.
+TEST_F(ConfigManagerTest,
+       GetLastCheckPeriodSec_GroupPolicyAndUpdateDevOverrides) {
+  const DWORD kGroupPolicyOverrideMinutes = 100;
+  EXPECT_SUCCEEDED(SetPolicy(_T("AutoUpdateCheckPeriodMinutes"),
+                             kGroupPolicyOverrideMinutes));
+  const DWORD kUpdateDevOverrideSeconds = 70;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueLastCheckPeriodSec,
+                                    kUpdateDevOverrideSeconds));
+
+  bool is_overridden = false;
+  EXPECT_EQ(kUpdateDevOverrideSeconds,
+            cm_->GetLastCheckPeriodSec(&is_overridden));
+  EXPECT_TRUE(is_overridden);
+}
+
+// Legacy location is not checked.
+TEST_F(ConfigManagerTest, CanCollectStats_LegacyLocationAndName) {
+  DWORD val = 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kLegacyRegValueCollectUsageStats,
+                                    val));
+  EXPECT_FALSE(cm_->CanCollectStats(true));
+}
+
+TEST_F(ConfigManagerTest, CanCollectStats_LegacyLocationNewName) {
+  DWORD val = 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("usagestats"),
+                                    val));
+  EXPECT_FALSE(cm_->CanCollectStats(true));
+}
+
+TEST_F(ConfigManagerTest, CanCollectStats_MachineOnly) {
+  CanCollectStatsHelper(true);
+}
+
+TEST_F(ConfigManagerTest, CanCollectStats_UserOnly) {
+  CanCollectStatsHelper(false);
+}
+
+// This tests that the legacy conversion is honored.
+TEST_F(ConfigManagerTest, CanCollectStats_GoopdateGuidIsChecked) {
+  EXPECT_FALSE(cm_->CanCollectStats(true));
+
+  DWORD val = 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("usagestats"),
+                                    val));
+  EXPECT_TRUE(cm_->CanCollectStats(true));
+}
+
+TEST_F(ConfigManagerTest, CanCollectStats_MachineIgnoresUser) {
+  CanCollectStatsIgnoresOppositeHiveHelper(true);
+}
+
+TEST_F(ConfigManagerTest, CanCollectStats_UserIgnoresMachine) {
+  CanCollectStatsIgnoresOppositeHiveHelper(false);
+}
+// Unfortunately, the app's ClientStateMedium key is not checked if there is no
+// corresponding ClientState key.
+TEST_F(ConfigManagerTest,
+       CanCollectStats_Machine_ClientStateMediumOnly_AppClientStateKeyMissing) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath1,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(cm_->CanCollectStats(true));
+}
+
+TEST_F(ConfigManagerTest,
+       CanCollectStats_Machine_ClientStateMediumOnly_AppClientStateKeyExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath1));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath1,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(cm_->CanCollectStats(true));
+}
+
+TEST_F(ConfigManagerTest,
+       CanCollectStats_Machine_ClientStateMediumInvalid) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath1));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath1,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(2)));
+  EXPECT_FALSE(cm_->CanCollectStats(true));
+}
+
+TEST_F(ConfigManagerTest, CanCollectStats_User_ClientStateMediumOnly) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath1));
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKCU\\Software\\Google\\Update\\ClientStateMedium\\") APP_GUID1,
+      _T("usagestats"),
+      static_cast<DWORD>(1)));
+  EXPECT_FALSE(cm_->CanCollectStats(false));
+}
+
+TEST_F(ConfigManagerTest,
+       CanCollectStats_Machine_ClientStateZeroClientStateMediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath1,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(cm_->CanCollectStats(true));
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath1,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(cm_->CanCollectStats(true));
+}
+
+TEST_F(ConfigManagerTest,
+       CanCollectStats_Machine_ClientStateOneClientStateMediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath1,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(cm_->CanCollectStats(true));
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath1,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(cm_->CanCollectStats(true));
+}
+
+// Tests OverInstall override.
+TEST_F(ConfigManagerTest, CanOverInstall) {
+  EXPECT_EQ(cm_->CanOverInstall(), !OFFICIAL_BUILD);
+
+  DWORD val = 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueNameOverInstall,
+                                    val));
+#ifdef DEBUG
+  EXPECT_TRUE(cm_->CanOverInstall());
+#else
+  EXPECT_EQ(!OFFICIAL_BUILD, cm_->CanOverInstall());
+#endif
+
+  val = 0;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueNameOverInstall,
+                                    val));
+#ifdef DEBUG
+  EXPECT_FALSE(cm_->CanOverInstall());
+#else
+  EXPECT_EQ(!OFFICIAL_BUILD, cm_->CanOverInstall());
+#endif
+}
+
+// Tests AuCheckPeriodMs override.
+TEST_F(ConfigManagerTest, GetAutoUpdateTimerIntervalMs) {
+  EXPECT_EQ(cm_->IsGoogler() ? kAUCheckPeriodGooglerMs :
+                               kAUCheckPeriodMs,
+            cm_->GetAutoUpdateTimerIntervalMs());
+
+  DWORD val = 0;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueAuCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(kMinAUCheckPeriodMs, cm_->GetAutoUpdateTimerIntervalMs());
+
+  val = kMinAUCheckPeriodMs - 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueAuCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(kMinAUCheckPeriodMs, cm_->GetAutoUpdateTimerIntervalMs());
+
+  val = 30000;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueAuCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(val, cm_->GetAutoUpdateTimerIntervalMs());
+
+  val = INT_MAX;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueAuCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(val, cm_->GetAutoUpdateTimerIntervalMs());
+
+  // Tests overflow with large positive numbers.
+  val = INT_MAX;
+  ++val;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueAuCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(INT_MAX, cm_->GetAutoUpdateTimerIntervalMs());
+
+  val = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueAuCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(INT_MAX, cm_->GetAutoUpdateTimerIntervalMs());
+}
+
+// Tests CrCheckPeriodMs override.
+TEST_F(ConfigManagerTest, GetCodeRedTimerIntervalMs) {
+  EXPECT_EQ(kCodeRedCheckPeriodMs, cm_->GetCodeRedTimerIntervalMs());
+
+  DWORD val = 0;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueCrCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(kMinCodeRedCheckPeriodMs, cm_->GetCodeRedTimerIntervalMs());
+
+  val = kMinCodeRedCheckPeriodMs - 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueCrCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(kMinCodeRedCheckPeriodMs, cm_->GetCodeRedTimerIntervalMs());
+
+  val = 60000;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueCrCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(val, cm_->GetCodeRedTimerIntervalMs());
+
+  val = INT_MAX;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueCrCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(val, cm_->GetCodeRedTimerIntervalMs());
+
+  // Tests overflow with large positive numbers.
+  val = INT_MAX;
+  ++val;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueCrCheckPeriodMs,
+                                    val));
+  EXPECT_EQ(INT_MAX, cm_->GetCodeRedTimerIntervalMs());
+
+  val = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                      kRegValueCrCheckPeriodMs,
+                                      val));
+  EXPECT_EQ(INT_MAX, cm_->GetCodeRedTimerIntervalMs());
+}
+
+// Tests CanLogEvents override.
+TEST_F(ConfigManagerTest, CanLogEvents_WithOutOverride) {
+  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_SUCCESS));
+  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_ERROR_TYPE));
+  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_WARNING_TYPE));
+  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_INFORMATION_TYPE));
+  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_AUDIT_SUCCESS));
+  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_AUDIT_FAILURE));
+}
+
+TEST_F(ConfigManagerTest, CanLogEvents) {
+  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_INFORMATION_TYPE));
+
+  DWORD val = LOG_EVENT_LEVEL_ALL;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueEventLogLevel,
+                                    val));
+  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_SUCCESS));
+  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_ERROR_TYPE));
+  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_WARNING_TYPE));
+  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_INFORMATION_TYPE));
+  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_AUDIT_SUCCESS));
+  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_AUDIT_FAILURE));
+
+  val = LOG_EVENT_LEVEL_WARN_AND_ERROR;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueEventLogLevel,
+                                    val));
+  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_SUCCESS));
+  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_ERROR_TYPE));
+  EXPECT_TRUE(cm_->CanLogEvents(EVENTLOG_WARNING_TYPE));
+  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_INFORMATION_TYPE));
+  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_AUDIT_SUCCESS));
+  EXPECT_FALSE(cm_->CanLogEvents(EVENTLOG_AUDIT_FAILURE));
+}
+
+// Tests GetTestSource override.
+TEST_F(ConfigManagerTest, GetTestSource_Dev) {
+  CString expected_value;
+#if DEBUG || !OFFICIAL_BUILD
+  expected_value = kRegValueTestSourceAuto;
+#endif
+
+  CString test_source = cm_->GetTestSource();
+  EXPECT_STREQ(expected_value, test_source);
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueTestSource,
+                                   _T("dev")));
+  test_source = cm_->GetTestSource();
+  EXPECT_STREQ(_T("dev"), test_source);
+}
+
+TEST_F(ConfigManagerTest, GetTestSource_EmptyRegKey) {
+  CString expected_value;
+
+#if DEBUG || !OFFICIAL_BUILD
+  expected_value = kRegValueTestSourceAuto;
+#endif
+
+  CString test_source = cm_->GetTestSource();
+  EXPECT_STREQ(expected_value, test_source);
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueTestSource,
+                                   _T("")));
+  test_source = cm_->GetTestSource();
+  EXPECT_STREQ(kRegValueTestSourceAuto, test_source);
+}
+
+//
+// CanUseNetwork tests.
+//
+
+// Covers UpdateEulaAccepted case.
+TEST_F(ConfigManagerTest, CanUseNetwork_Machine_Normal) {
+  EXPECT_TRUE(cm_->CanUseNetwork(true));
+}
+
+// Covers UpdateEulaAccepted case.
+TEST_F(ConfigManagerTest, CanUseNetwork_User_Normal) {
+  EXPECT_TRUE(cm_->CanUseNetwork(false));
+}
+
+// These cover the not OEM install mode cases.
+TEST_F(ConfigManagerTest, CanUseNetwork_Machine_UpdateEulaNotAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(cm_->CanUseNetwork(true));
+}
+
+TEST_F(ConfigManagerTest,
+       CanUseNetwork_Machine_UpdateEulaNotAccepted_AppEulaAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath1,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(cm_->CanUseNetwork(true));
+}
+
+TEST_F(ConfigManagerTest, CanUseNetwork_Machine_AppEulaNotAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath1,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_TRUE(cm_->CanUseNetwork(true));
+}
+
+TEST_F(ConfigManagerTest, CanUseNetwork_Machine_AppEulaAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath1,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(cm_->CanUseNetwork(true));
+}
+
+TEST_F(ConfigManagerTest, CanUseNetwork_Machine_UserUpdateEulaNotAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_TRUE(cm_->CanUseNetwork(true));
+}
+
+TEST_F(ConfigManagerTest, CanUseNetwork_User_UpdateEulaNotAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(cm_->CanUseNetwork(false));
+}
+
+TEST_F(ConfigManagerTest,
+       CanUseNetwork_User_UpdateEulaNotAccepted_AppEulaAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath1,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(cm_->CanUseNetwork(false));
+}
+
+TEST_F(ConfigManagerTest, CanUseNetwork_User_AppEulaNotAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath1,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_TRUE(cm_->CanUseNetwork(false));
+}
+
+TEST_F(ConfigManagerTest, CanUseNetwork_User_AppEulaAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath1,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(cm_->CanUseNetwork(false));
+}
+
+TEST_F(ConfigManagerTest, CanUseNetwork_User_MachineUpdateEulaNotAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_TRUE(cm_->CanUseNetwork(false));
+}
+
+
+// Covers UpdateEulaAccepted case.
+TEST_F(ConfigManagerTest,
+       CanUseNetwork_Machine_OemInstallTimeNow_NotAuditMode) {
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+
+  EXPECT_FALSE(cm_->CanUseNetwork(true));
+}
+
+TEST_F(ConfigManagerTest,
+       CanUseNetwork_Machine_OemInstallTimeNow_NotAuditMode_UpdateEulaNotAccepted) {  //NOLINT
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_FALSE(cm_->CanUseNetwork(true));
+}
+
+// These cover the EULA accepted cases.
+TEST_F(ConfigManagerTest,
+       CanUseNetwork_Machine_OemInstallTime73HoursAgo_NotAuditMode) {
+  const DWORD kDesiredDifferenceSeconds = 73 * 60 * 60;  // 73 hours.
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_GT(now_seconds, kDesiredDifferenceSeconds);
+  const DWORD install_time_seconds = now_seconds - kDesiredDifferenceSeconds;
+  EXPECT_LT(install_time_seconds, now_seconds);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    install_time_seconds));
+  EXPECT_FALSE(cm_->IsOemInstalling(true));
+
+  EXPECT_TRUE(cm_->CanUseNetwork(true));
+}
+
+TEST_F(ConfigManagerTest, CanUseNetwork_User_OemInstallTimeNow_AuditMode) {
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_FALSE(cm_->IsOemInstalling(false));
+
+  EXPECT_TRUE(cm_->CanUseNetwork(false));
+}
+
+TEST_F(ConfigManagerTest, CanUseNetwork_User_OemInstallTimeNow_AuditMode_UpdateEulaNotAccepted) {  //NOLINT
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_FALSE(cm_->IsOemInstalling(false));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_FALSE(cm_->CanUseNetwork(false));
+}
+
+//
+// IsOemInstalling tests.
+//
+
+TEST_F(ConfigManagerTest, IsOemInstalling_Machine_Normal) {
+  EXPECT_FALSE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest, IsOemInstalling_User_Normal) {
+  EXPECT_FALSE(cm_->IsOemInstalling(false));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTimeNow_NotAuditMode) {
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest, IsOemInstalling_Machine_OemInstallTimeNow_AuditMode) {
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTime71HoursAgo_NotAuditMode) {
+  const DWORD kDesiredDifferenceSeconds = 71 * 60 * 60;  // 71 hours.
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_GT(now_seconds, kDesiredDifferenceSeconds);
+  const DWORD install_time_seconds = now_seconds - kDesiredDifferenceSeconds;
+  EXPECT_LT(install_time_seconds, now_seconds);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    install_time_seconds));
+
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTime71HoursAgo_AuditMode) {
+  const DWORD kDesiredDifferenceSeconds = 71 * 60 * 60;  // 71 hours.
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_GT(now_seconds, kDesiredDifferenceSeconds);
+  const DWORD install_time_seconds = now_seconds - kDesiredDifferenceSeconds;
+  EXPECT_LT(install_time_seconds, now_seconds);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    install_time_seconds));
+
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTime73HoursAgo_NotAuditMode) {
+  const DWORD kDesiredDifferenceSeconds = 73 * 60 * 60;  // 73 hours.
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_GT(now_seconds, kDesiredDifferenceSeconds);
+  const DWORD install_time_seconds = now_seconds - kDesiredDifferenceSeconds;
+  EXPECT_LT(install_time_seconds, now_seconds);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    install_time_seconds));
+
+  EXPECT_FALSE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTime73HoursAgo_AuditMode) {
+  const DWORD kDesiredDifferenceSeconds = 73 * 60 * 60;  // 73 hours.
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_GT(now_seconds, kDesiredDifferenceSeconds);
+  const DWORD install_time_seconds = now_seconds - kDesiredDifferenceSeconds;
+  EXPECT_LT(install_time_seconds, now_seconds);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    install_time_seconds));
+
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTime71HoursInFuture_NotAuditMode) {
+  const DWORD kDesiredDifferenceSeconds = 71 * 60 * 60;  // 71 hours.
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  const DWORD install_time_seconds = now_seconds + kDesiredDifferenceSeconds;
+  EXPECT_GT(install_time_seconds, now_seconds);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    install_time_seconds));
+
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTime71HoursInFuture_AuditMode) {
+  const DWORD kDesiredDifferenceSeconds = 71 * 60 * 60;  // 71 hours.
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  const DWORD install_time_seconds = now_seconds + kDesiredDifferenceSeconds;
+  EXPECT_GT(install_time_seconds, now_seconds);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    install_time_seconds));
+
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTime73HoursInFuture_NotAuditMode) {
+  const DWORD kDesiredDifferenceSeconds = 73 * 60 * 60;  // 73 hours.
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  const DWORD install_time_seconds = now_seconds + kDesiredDifferenceSeconds;
+  EXPECT_GT(install_time_seconds, now_seconds);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    install_time_seconds));
+
+  EXPECT_FALSE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTime73HoursInFuture_AuditMode) {
+  const DWORD kDesiredDifferenceSeconds = 73 * 60 * 60;  // 73 hours.
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  const DWORD install_time_seconds = now_seconds + kDesiredDifferenceSeconds;
+  EXPECT_GT(install_time_seconds, now_seconds);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    install_time_seconds));
+
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTimeZero_NotAuditMode) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_FALSE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTimeZero_AuditMode) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    static_cast<DWORD>(0)));
+
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_TRUE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTimeWrongType_NotAuditMode) {
+  const uint32 now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  const CString now_string = itostr(now_seconds);
+  EXPECT_FALSE(now_string.IsEmpty());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_string));
+
+  EXPECT_FALSE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_Machine_OemInstallTimeWrongType_AuditMode) {
+  const uint32 now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  const CString now_string = itostr(now_seconds);
+  EXPECT_FALSE(now_string.IsEmpty());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_string));
+
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_FALSE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest, IsOemInstalling_Machine_NoOemInstallTime_AuditMode) {
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_FALSE(cm_->IsOemInstalling(true));
+}
+
+TEST_F(ConfigManagerTest,
+       IsOemInstalling_User_OemInstallTimeNow_NotAuditMode) {
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+
+  EXPECT_FALSE(cm_->IsOemInstalling(false));
+}
+
+TEST_F(ConfigManagerTest, IsOemInstalling_User_OemInstallTimeNow_AuditMode) {
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+
+  if (vista_util::IsVistaOrLater()) {
+    EXPECT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    EXPECT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_FALSE(cm_->IsOemInstalling(false));
+}
+
+// TODO(omaha): Figure out a way to test the result.
+TEST_F(ConfigManagerTest, IsGoogler) {
+  cm_->IsGoogler();
+}
+
+TEST_F(ConfigManagerTest, IsWindowsInstalling_Normal) {
+  EXPECT_FALSE(cm_->IsWindowsInstalling());
+}
+
+TEST_F(ConfigManagerTest, IsWindowsInstalling_Installing_Vista_InvalidValues) {
+  if (!vista_util::IsVistaOrLater()) {
+    return;
+  }
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("")));
+  EXPECT_FALSE(cm_->IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("foo")));
+  EXPECT_FALSE(cm_->IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      static_cast<DWORD>(1)));
+  ExpectAsserts expect_asserts;  // RegKey asserts because value type is wrong.
+  EXPECT_FALSE(cm_->IsWindowsInstalling());
+}
+
+TEST_F(ConfigManagerTest, IsWindowsInstalling_Installing_Vista_ValidStates) {
+  if (!vista_util::IsVistaOrLater()) {
+    return;
+  }
+
+  // These states return false in the original implementation.
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_COMPLETE")));
+  EXPECT_FALSE(cm_->IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_OOBE")));
+  EXPECT_FALSE(cm_->IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_OOBE")));
+  EXPECT_FALSE(cm_->IsWindowsInstalling());
+
+  // These states are specified in the original implementation.
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_UNDEPLOYABLE")));
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_GENERALIZE_RESEAL_TO_AUDIT")));
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+      _T("ImageState"),
+      _T("IMAGE_STATE_SPECIALIZE_RESEAL_TO_AUDIT")));
+  EXPECT_TRUE(cm_->IsWindowsInstalling());
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_NoGroupPolicy) {
+  EXPECT_TRUE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_DifferentAppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp2, 0));
+  EXPECT_TRUE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_NoDefaultValue_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 0));
+  EXPECT_FALSE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_NoDefaultValue_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 1));
+  EXPECT_TRUE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_NoDefaultValue_AppInvalid) {
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 2));
+  EXPECT_TRUE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_DefaultDisabled_NoAppValue) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 0));
+  EXPECT_FALSE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_DefaultDisabled_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 0));
+  EXPECT_FALSE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_DefaultDisabled_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 1));
+  EXPECT_TRUE(CanInstallApp(kAppGuid1));
+}
+
+// Invalid value defaulting to true overrides the InstallDefault disable.
+TEST_F(ConfigManagerTest, CanInstallApp_DefaultDisabled_AppInvalid) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 2));
+  EXPECT_TRUE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_DefaultEnabled_NoAppValue) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 1));
+  EXPECT_TRUE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_DefaultEnabled_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 0));
+  EXPECT_FALSE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_DefaultEnabled_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 1));
+  EXPECT_TRUE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanInstallApp_DefaultEnabled_AppInvalid) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("InstallDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp1, 2));
+  EXPECT_TRUE(CanInstallApp(kAppGuid1));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_NoGroupPolicy) {
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DifferentAppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 0));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DifferentAppManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 2));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_NoDefaultValue_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_NoDefaultValue_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_NoDefaultValue_AppManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultDisabled_NoAppValue) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultDisabled_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultDisabled_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultDisabled_AppManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));
+}
+
+// Invalid value defaulting to true overrides the UpdateDefault disable.
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultDisabled_AppInvalid) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultEnabled_NoAppValue) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultEnabled_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultEnabled_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultEnabled_AppManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultEnabled_AppInvalid) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultManualOnly_NoAppValue) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultManualOnly_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultManualOnly_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultManualOnly_AppManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultManualOnly_AppInvalid) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_DefaultInvalid_NoAppValue) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 3));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_GoogleUpdate_DefaultDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+                           false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_GoogleUpdate_DefaultManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+                           false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Auto_GoogleUpdate_AppDisabled) {
+  EXPECT_SUCCEEDED(
+      SetPolicy(_T("Update{430FD4D0-B729-4F61-AA34-91526481799D}"), 0));
+  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"),
+                           false));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_NoGroupPolicy) {
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DifferentAppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 0));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DifferentAppManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 2));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_NoDefaultValue_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_NoDefaultValue_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_NoDefaultValue_AppManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultDisabled_NoAppValue) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultDisabled_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultDisabled_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultDisabled_AppManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+// Invalid value defaulting to true overrides the UpdateDefault disable.
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultDisabled_AppInvalid) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultEnabled_NoAppValue) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultEnabled_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultEnabled_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultEnabled_AppManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultEnabled_AppInvalid) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 1));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultManualOnly_NoAppValue) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultManualOnly_AppDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 0));
+  EXPECT_FALSE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultManualOnly_AppEnabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 1));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultManualOnly_AppManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 2));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Maual_DefaultManualOnly_AppInvalid) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp1, 3));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_DefaultInvalid_NoAppValue) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 3));
+  EXPECT_TRUE(CanUpdateApp(kAppGuid1, true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_GoogleUpdate_DefaultDisabled) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 0));
+  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"), true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_GoogleUpdate_DefaultManualOnly) {
+  EXPECT_SUCCEEDED(SetPolicy(_T("UpdateDefault"), 2));
+  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"), true));
+}
+
+TEST_F(ConfigManagerTest, CanUpdateApp_Manual_GoogleUpdate_AppDisabled) {
+  EXPECT_SUCCEEDED(
+      SetPolicy(_T("Update{430FD4D0-B729-4F61-AA34-91526481799D}"), 0));
+  EXPECT_TRUE(CanUpdateApp(_T("{430FD4D0-B729-4F61-AA34-91526481799D}"), true));
+}
+
+TEST_F(ConfigManagerTest, LastCheckedTime) {
+  DWORD time = 500;
+  EXPECT_SUCCEEDED(cm_->SetLastCheckedTime(true, time));
+  EXPECT_EQ(time, cm_->GetLastCheckedTime(true));
+
+  time = 77003;
+  EXPECT_SUCCEEDED(cm_->SetLastCheckedTime(false, time));
+  EXPECT_EQ(time, cm_->GetLastCheckedTime(false));
+}
+
+// Tests GetDir indirectly.
+TEST_F(ConfigManagerTest, GetDir) {
+  RestoreRegistryHives();
+
+  CString user_install_dir = cm_->GetUserGoopdateInstallDir();
+  CString user_profile;
+  ASSERT_NE(0, ::GetEnvironmentVariable(_T("USERPROFILE"),
+                                        CStrBuf(user_profile, MAX_PATH),
+                                        MAX_PATH));
+  ASSERT_TRUE(String_StartsWith(user_install_dir, user_profile, true));
+}
+
+TEST_F(ConfigManagerTest, GetUpdateWorkerStartUpDelayMs_Repeated) {
+  if (!SystemInfo::IsRunningOnXPOrLater()) {
+    std::wcout << _T("\tTest did not run because GenRandom breaks on Windows ")
+               << _T("2000 if the registry keys are overridden.") << std::endl;
+    return;
+  }
+
+  // Test the UpdateDelay multiple times.
+  for (int i = 0; i < 10; ++i) {
+    int random = cm_->GetUpdateWorkerStartUpDelayMs();
+    EXPECT_GE(random, kUpdateTimerStartupDelayMinMs);
+    EXPECT_LE(random, kUpdateTimerStartupDelayMaxMs);
+  }
+}
+
+TEST_F(ConfigManagerTest, GetUpdateWorkerStartUpDelayMs) {
+  if (!SystemInfo::IsRunningOnXPOrLater()) {
+    std::wcout << _T("\tTest did not run because GenRandom breaks on Windows ")
+               << _T("2000 if the registry keys are overridden.") << std::endl;
+    return;
+  }
+
+  int random = cm_->GetUpdateWorkerStartUpDelayMs();
+  EXPECT_GE(random, kUpdateTimerStartupDelayMinMs);
+  EXPECT_LE(random, kUpdateTimerStartupDelayMaxMs);
+
+  int num_times_to_try_for_diff_number = 3;
+  // We run the method num_times_to_try_for_diff_number times to make
+  // sure that at least one of these returns a number that is different
+  // from the one that is returned above. This is needed, since the
+  // method returns a number between kUpdateTimerStartupDelayMinMs and
+  // kUpdateTimerStartupDelayMaxMs.
+  // If this fails a lot we should disable the if check below.
+  bool found_one_not_equal = false;
+  for (int i = 0; i < num_times_to_try_for_diff_number; ++i) {
+    int random_compare = cm_->GetUpdateWorkerStartUpDelayMs();
+
+    EXPECT_GE(random_compare, kUpdateTimerStartupDelayMinMs);
+    EXPECT_LE(random_compare, kUpdateTimerStartupDelayMaxMs);
+
+    if (random_compare != random) {
+      found_one_not_equal = true;
+      break;
+    }
+  }
+
+  EXPECT_TRUE(found_one_not_equal);
+}
+
+TEST_F(ConfigManagerTest, GetUpdateWorkerStartUpDelayMs_Override) {
+  // Test that the initial delay time to launch a worker can be overriden.
+  DWORD val = 3320;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueAuCheckPeriodMs,
+                                    val));
+
+  int random = cm_->GetUpdateWorkerStartUpDelayMs();
+  EXPECT_EQ(val, random);
+}
+
+TEST_F(ConfigManagerTest, GetTimeSinceLastCheckedSec_User) {
+  // First, there is no value present in the registry.
+  uint32 now_sec = Time64ToInt32(GetCurrent100NSTime());
+  int time_since_last_checked_sec = cm_->GetTimeSinceLastCheckedSec(false);
+  EXPECT_EQ(now_sec, time_since_last_checked_sec);
+
+  // Second, write the 'now' time.
+  EXPECT_HRESULT_SUCCEEDED(cm_->SetLastCheckedTime(false, now_sec));
+  time_since_last_checked_sec = cm_->GetTimeSinceLastCheckedSec(false);
+  EXPECT_EQ(0, time_since_last_checked_sec);
+}
+
+TEST_F(ConfigManagerTest, GetTimeSinceLastCheckedSec_Machine) {
+  uint32 now_sec = Time64ToInt32(GetCurrent100NSTime());
+  int time_since_last_checked_sec = cm_->GetTimeSinceLastCheckedSec(true);
+  EXPECT_EQ(now_sec, time_since_last_checked_sec);
+
+  EXPECT_HRESULT_SUCCEEDED(cm_->SetLastCheckedTime(true, now_sec));
+  time_since_last_checked_sec = cm_->GetTimeSinceLastCheckedSec(true);
+  EXPECT_EQ(0, time_since_last_checked_sec);
+}
+
+TEST_F(ConfigManagerTest, GetNetConfig) {
+  CString actual_value;
+  EXPECT_HRESULT_FAILED(cm_->GetNetConfig(&actual_value));
+
+  const CString expected_value = _T("proxy:8080");
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueNetConfig,
+                                    expected_value));
+
+  EXPECT_HRESULT_SUCCEEDED(cm_->GetNetConfig(&actual_value));
+  EXPECT_STREQ(expected_value, actual_value);
+}
+
+TEST_F(ConfigManagerTest, GetInstallTime) {
+  EXPECT_SUCCEEDED(DeleteUpdateTime(false));
+  EXPECT_SUCCEEDED(DeleteFirstInstallTime(false));
+  EXPECT_EQ(0, ConfigManager::GetInstallTime(false));
+
+  DWORD time = 500;
+  EXPECT_SUCCEEDED(SetFirstInstallTime(false, time));
+  EXPECT_EQ(time, ConfigManager::GetInstallTime(false));
+
+  time = 1000;
+  EXPECT_SUCCEEDED(SetUpdateTime(false, time));
+  EXPECT_EQ(time, ConfigManager::GetInstallTime(false));
+
+  EXPECT_SUCCEEDED(DeleteFirstInstallTime(false));
+  EXPECT_EQ(time, ConfigManager::GetInstallTime(false));
+}
+
+TEST_F(ConfigManagerTest, Is24HoursSinceInstall) {
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+  const int k12HourPeriodSec = 12 * 60 * 60;
+  const int k48HourPeriodSec = 48 * 60 * 60;
+
+  const uint32 first_install_12 = now - k12HourPeriodSec;
+  const uint32 first_install_48 = now - k48HourPeriodSec;
+
+  EXPECT_SUCCEEDED(SetFirstInstallTime(false, first_install_12));
+  EXPECT_FALSE(ConfigManager::Is24HoursSinceInstall(false));
+
+  EXPECT_SUCCEEDED(SetFirstInstallTime(false, first_install_48));
+  EXPECT_TRUE(ConfigManager::Is24HoursSinceInstall(false));
+
+  EXPECT_SUCCEEDED(SetUpdateTime(false, first_install_12));
+  EXPECT_FALSE(ConfigManager::Is24HoursSinceInstall(false));
+
+  EXPECT_SUCCEEDED(SetUpdateTime(false, first_install_48));
+  EXPECT_TRUE(ConfigManager::Is24HoursSinceInstall(false));
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/const_goopdate.h b/goopdate/const_goopdate.h
index dd2e2cf..9b7a2c8 100644
--- a/goopdate/const_goopdate.h
+++ b/goopdate/const_goopdate.h
@@ -1,169 +1,169 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Goopdate constants - Reduces dependencies on goopdate.h for names that

-// are needed outside Goopdate.

-//

-// TODO(omaha): it appears that the string constants below are not

-// optimized out the program image even if not used. Figure out why they still

-// show up in the tiny shell in optimized builds.

-

-#ifndef OMAHA_GOOPDATE_CONST_GOOPDATE_H__

-#define OMAHA_GOOPDATE_CONST_GOOPDATE_H__

-

-#include <tchar.h>

-

-namespace omaha {

-

-// The enumeration of the events. Some of the events are used in IPC,

-// these are named events, the rest are not named. Of the named events there

-// are two types the global and the local events.

-// Global Events:

-// The events which are global are indicated with the Global suffix in the

-// enum. These events have the Global prefix attached to the event name and

-// are used for IPC across terminal server sessions, these events are used

-// as barriers, i.e. all waiting threads are release on these events.

-// Local Events:

-// The local counter parts of these events have the Local prefix attached

-// to their names, and dont have any suffix in the enum names. The local events

-// are used to release only one thread, this works as we know that there is

-// only one user goopdate process in a user session and one machine goopdate.

-// The local events also have the user sid added to the event name. This is to

-// work around a bug in win2K and on XP where in case of TS, the event names

-// will collide, inspite of the name changes.

-enum GoopdateEvents {

-  EVENT_INVALID = -1,

-  EVENT_KILL_MESSAGE_LOOP = 0,

-  EVENT_UPDATE_TIMER,

-  EVENT_NEW_MANIFEST,          // Used in IPC.

-  EVENT_QUIET_MODE,            // Used in IPC.

-  EVENT_LEGACY_QUIET_MODE,     // Only used to shut down pre-i18n goopdates.

-  EVENT_CODE_RED_TIMER,

-};

-

-// Using extern or intern linkage for these strings yields the same code size

-// for the executable DLL.

-

-

-// Registry values read from the Clients key for transmitting custom install

-// errors, messages, etc. On an update, the InstallerXXX values are renamed to

-// LastInstallerXXX values. The LastInstallerXXX values remain around until the

-// next update.

-const TCHAR* const kRegValueInstallerResult = _T("InstallerResult");

-const TCHAR* const kRegValueInstallerError  = _T("InstallerError");

-const TCHAR* const kRegValueInstallerResultUIString =

-    _T("InstallerResultUIString");

-const TCHAR* const kRegValueInstallerSuccessLaunchCmdLine =

-    _T("InstallerSuccessLaunchCmdLine");

-const TCHAR* const kRegValueLastInstallerResult =

-    _T("LastInstallerResult");

-const TCHAR* const kRegValueLastInstallerError =

-    _T("LastInstallerError");

-const TCHAR* const kRegValueLastInstallerResultUIString =

-    _T("LastInstallerResultUIString");

-const TCHAR* const kRegValueLastInstallerSuccessLaunchCmdLine =

-    _T("LastInstallerSuccessLaunchCmdLine");

-

-// Registry subkey in an app's Clients key that contains its components.

-const TCHAR* const kComponentsRegKeyName     = _T("Components");

-

-// Registry values read from the Clients key and stored in the ClientState key.

-const TCHAR* const kRegValueLanguage         = _T("lang");

-const TCHAR* const kRegValueAppName          = _T("name");

-const TCHAR* const kRegValueProductVersion   = _T("pv");

-

-// Registry values stored in the ClientState key.

-const TCHAR* const kRegValueAdditionalParams = _T("ap");

-const TCHAR* const kRegValueBrandCode        = _T("brand");

-const TCHAR* const kRegValueBrowser          = _T("browser");

-const TCHAR* const kRegValueClientId         = _T("client");

-const TCHAR* const kRegValueDidRun           = _T("dr");

-const TCHAR* const kRegValueInstallationId   = _T("iid");

-const TCHAR* const kRegValueOemInstall       = _T("oeminstall");

-const TCHAR* const kRegValueReferralId       = _T("referral");

-

-// Registry values stored in the ClientState key related to Omaha's actions.

-// A "successful check" means "noupdate" received from the server or an update

-// was successfully applied.

-const TCHAR* const kRegValueInstallTimeSec          = _T("InstallTime");

-const TCHAR* const kRegValueLastSuccessfulCheckSec  = _T("LastCheckSuccess");

-const TCHAR* const kRegValueLastUpdateTimeSec       = _T("UpdateTime");

-

-// Registry values stored in the ClientState or ClientStateMedium keys.

-// Use accessor methods rather than reading them directly.

-const TCHAR* const kRegValueEulaAccepted     = _T("eulaaccepted");

-const TCHAR* const kRegValueUsageStats       = _T("usagestats");

-

-// Registry values stored in the ClientState key for Omaha's internal use.

-const TCHAR* const kRegValueTTToken               = _T("tttoken");

-const TCHAR* const kRegValueUpdateAvailableCount  = _T("UpdateAvailableCount");

-const TCHAR* const kRegValueUpdateAvailableSince  = _T("UpdateAvailableSince");

-

-// Registry values stored in the Update key.

-const TCHAR* const kRegValueOmahaEulaAccepted     = _T("eulaaccepted");

-const TCHAR* const kRegValueServiceName           = _T("gupdate_service_name");

-const TCHAR* const kRegValueTaskNameC             = _T("gupdate_task_name_c");

-const TCHAR* const kRegValueTaskNameUA            = _T("gupdate_task_name_ua");

-const TCHAR* const kRegValueLastChecked           = _T("LastChecked");

-const TCHAR* const kRegValueMachineId             = _T("mi");

-const TCHAR* const kRegValueOemInstallTimeSec     = _T("OemInstallTime");

-const TCHAR* const kRegValueInstalledPath         = _T("path");

-const TCHAR* const kRegValueUserId                = _T("ui");

-const TCHAR* const kRegValueSelfUpdateExtraCode1  = _T("UpdateCode1");

-const TCHAR* const kRegValueSelfUpdateErrorCode   = _T("UpdateError");

-const TCHAR* const kRegValueSelfUpdateVersion     = _T("UpdateVersion");

-const TCHAR* const kRegValueInstalledVersion      = _T("version");

-

-// TODO(omaha): Remove with legacy Omaha 1 support.

-// Used to allow current builds to read opt-in values from previous builds.

-// This is deprecated in favor of kRegValueUsageStats.

-const TCHAR* const kLegacyRegValueCollectUsageStats = _T("CollectUsageStats");

-

-const TCHAR* const kLegacyServiceName           = _T("gupdate");

-const TCHAR* const kServicePrefix               = _T("gupdate");

-

-const TCHAR* const kScheduledTaskNameUserPrefix = _T("GoogleUpdateTaskUser");

-const TCHAR* const kScheduledTaskNameMachinePrefix =

-    _T("GoogleUpdateTaskMachine");

-const TCHAR* const kScheduledTaskNameCoreSuffix = _T("Core");

-const TCHAR* const kScheduledTaskNameUASuffix   = _T("UA");

-

-// TODO(omaha): make these two below the same symbol.

-const TCHAR* const kServiceFileName              = _T("GoogleUpdate.exe");

-const TCHAR* const kGoopdateFileName             = _T("GoogleUpdate.exe");

-const TCHAR* const kGoopdateCrashHandlerFileName = _T("GoogleCrashHandler.exe");

-const TCHAR* const kGoopdateDllName              = _T("goopdate.dll");

-const TCHAR* const kGoopdateResourceDllName      = _T("goopdateres_%s.dll");

-const TCHAR* const kGoopdateResDllFindPattern    = _T("goopdateres_*.dll");

-const char*  const kGoopdateDllEntryAnsi         = "DllEntry";

-

-

-// Event Id's used for reporting in the event log.

-// Crash Report events.

-const int kCrashReportEventId        = 1;

-const int kCrashUploadEventId        = 2;

-

-// Update Check events.

-const int kUpdateCheckEventId        = 11;

-const int kUpdateEventId             = 12;

-const int kUninstallEventId          = 13;

-const int kWorkerStartEventId        = 14;

-

-// Network Request events.

-const int kNetworkRequestEventId     = 20;

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_CONST_GOOPDATE_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Goopdate constants - Reduces dependencies on goopdate.h for names that
+// are needed outside Goopdate.
+//
+// TODO(omaha): it appears that the string constants below are not
+// optimized out the program image even if not used. Figure out why they still
+// show up in the tiny shell in optimized builds.
+
+#ifndef OMAHA_GOOPDATE_CONST_GOOPDATE_H__
+#define OMAHA_GOOPDATE_CONST_GOOPDATE_H__
+
+#include <tchar.h>
+
+namespace omaha {
+
+// The enumeration of the events. Some of the events are used in IPC,
+// these are named events, the rest are not named. Of the named events there
+// are two types the global and the local events.
+// Global Events:
+// The events which are global are indicated with the Global suffix in the
+// enum. These events have the Global prefix attached to the event name and
+// are used for IPC across terminal server sessions, these events are used
+// as barriers, i.e. all waiting threads are release on these events.
+// Local Events:
+// The local counter parts of these events have the Local prefix attached
+// to their names, and dont have any suffix in the enum names. The local events
+// are used to release only one thread, this works as we know that there is
+// only one user goopdate process in a user session and one machine goopdate.
+// The local events also have the user sid added to the event name. This is to
+// work around a bug in win2K and on XP where in case of TS, the event names
+// will collide, inspite of the name changes.
+enum GoopdateEvents {
+  EVENT_INVALID = -1,
+  EVENT_KILL_MESSAGE_LOOP = 0,
+  EVENT_UPDATE_TIMER,
+  EVENT_NEW_MANIFEST,          // Used in IPC.
+  EVENT_QUIET_MODE,            // Used in IPC.
+  EVENT_LEGACY_QUIET_MODE,     // Only used to shut down pre-i18n goopdates.
+  EVENT_CODE_RED_TIMER,
+};
+
+// Using extern or intern linkage for these strings yields the same code size
+// for the executable DLL.
+
+
+// Registry values read from the Clients key for transmitting custom install
+// errors, messages, etc. On an update, the InstallerXXX values are renamed to
+// LastInstallerXXX values. The LastInstallerXXX values remain around until the
+// next update.
+const TCHAR* const kRegValueInstallerResult = _T("InstallerResult");
+const TCHAR* const kRegValueInstallerError  = _T("InstallerError");
+const TCHAR* const kRegValueInstallerResultUIString =
+    _T("InstallerResultUIString");
+const TCHAR* const kRegValueInstallerSuccessLaunchCmdLine =
+    _T("InstallerSuccessLaunchCmdLine");
+const TCHAR* const kRegValueLastInstallerResult =
+    _T("LastInstallerResult");
+const TCHAR* const kRegValueLastInstallerError =
+    _T("LastInstallerError");
+const TCHAR* const kRegValueLastInstallerResultUIString =
+    _T("LastInstallerResultUIString");
+const TCHAR* const kRegValueLastInstallerSuccessLaunchCmdLine =
+    _T("LastInstallerSuccessLaunchCmdLine");
+
+// Registry subkey in an app's Clients key that contains its components.
+const TCHAR* const kComponentsRegKeyName     = _T("Components");
+
+// Registry values read from the Clients key and stored in the ClientState key.
+const TCHAR* const kRegValueLanguage         = _T("lang");
+const TCHAR* const kRegValueAppName          = _T("name");
+const TCHAR* const kRegValueProductVersion   = _T("pv");
+
+// Registry values stored in the ClientState key.
+const TCHAR* const kRegValueAdditionalParams = _T("ap");
+const TCHAR* const kRegValueBrandCode        = _T("brand");
+const TCHAR* const kRegValueBrowser          = _T("browser");
+const TCHAR* const kRegValueClientId         = _T("client");
+const TCHAR* const kRegValueDidRun           = _T("dr");
+const TCHAR* const kRegValueInstallationId   = _T("iid");
+const TCHAR* const kRegValueOemInstall       = _T("oeminstall");
+const TCHAR* const kRegValueReferralId       = _T("referral");
+
+// Registry values stored in the ClientState key related to Omaha's actions.
+// A "successful check" means "noupdate" received from the server or an update
+// was successfully applied.
+const TCHAR* const kRegValueInstallTimeSec          = _T("InstallTime");
+const TCHAR* const kRegValueLastSuccessfulCheckSec  = _T("LastCheckSuccess");
+const TCHAR* const kRegValueLastUpdateTimeSec       = _T("UpdateTime");
+
+// Registry values stored in the ClientState or ClientStateMedium keys.
+// Use accessor methods rather than reading them directly.
+const TCHAR* const kRegValueEulaAccepted     = _T("eulaaccepted");
+const TCHAR* const kRegValueUsageStats       = _T("usagestats");
+
+// Registry values stored in the ClientState key for Omaha's internal use.
+const TCHAR* const kRegValueTTToken               = _T("tttoken");
+const TCHAR* const kRegValueUpdateAvailableCount  = _T("UpdateAvailableCount");
+const TCHAR* const kRegValueUpdateAvailableSince  = _T("UpdateAvailableSince");
+
+// Registry values stored in the Update key.
+const TCHAR* const kRegValueOmahaEulaAccepted     = _T("eulaaccepted");
+const TCHAR* const kRegValueServiceName           = _T("gupdate_service_name");
+const TCHAR* const kRegValueTaskNameC             = _T("gupdate_task_name_c");
+const TCHAR* const kRegValueTaskNameUA            = _T("gupdate_task_name_ua");
+const TCHAR* const kRegValueLastChecked           = _T("LastChecked");
+const TCHAR* const kRegValueMachineId             = _T("mi");
+const TCHAR* const kRegValueOemInstallTimeSec     = _T("OemInstallTime");
+const TCHAR* const kRegValueInstalledPath         = _T("path");
+const TCHAR* const kRegValueUserId                = _T("ui");
+const TCHAR* const kRegValueSelfUpdateExtraCode1  = _T("UpdateCode1");
+const TCHAR* const kRegValueSelfUpdateErrorCode   = _T("UpdateError");
+const TCHAR* const kRegValueSelfUpdateVersion     = _T("UpdateVersion");
+const TCHAR* const kRegValueInstalledVersion      = _T("version");
+
+// TODO(omaha): Remove with legacy Omaha 1 support.
+// Used to allow current builds to read opt-in values from previous builds.
+// This is deprecated in favor of kRegValueUsageStats.
+const TCHAR* const kLegacyRegValueCollectUsageStats = _T("CollectUsageStats");
+
+const TCHAR* const kLegacyServiceName           = _T("gupdate");
+const TCHAR* const kServicePrefix               = _T("gupdate");
+
+const TCHAR* const kScheduledTaskNameUserPrefix = _T("GoogleUpdateTaskUser");
+const TCHAR* const kScheduledTaskNameMachinePrefix =
+    _T("GoogleUpdateTaskMachine");
+const TCHAR* const kScheduledTaskNameCoreSuffix = _T("Core");
+const TCHAR* const kScheduledTaskNameUASuffix   = _T("UA");
+
+// TODO(omaha): make these two below the same symbol.
+const TCHAR* const kServiceFileName              = _T("GoogleUpdate.exe");
+const TCHAR* const kGoopdateFileName             = _T("GoogleUpdate.exe");
+const TCHAR* const kGoopdateCrashHandlerFileName = _T("GoogleCrashHandler.exe");
+const TCHAR* const kGoopdateDllName              = _T("goopdate.dll");
+const TCHAR* const kGoopdateResourceDllName      = _T("goopdateres_%s.dll");
+const TCHAR* const kGoopdateResDllFindPattern    = _T("goopdateres_*.dll");
+const char*  const kGoopdateDllEntryAnsi         = "DllEntry";
+
+
+// Event Id's used for reporting in the event log.
+// Crash Report events.
+const int kCrashReportEventId        = 1;
+const int kCrashUploadEventId        = 2;
+
+// Update Check events.
+const int kUpdateCheckEventId        = 11;
+const int kUpdateEventId             = 12;
+const int kUninstallEventId          = 13;
+const int kWorkerStartEventId        = 14;
+
+// Network Request events.
+const int kNetworkRequestEventId     = 20;
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_CONST_GOOPDATE_H__
diff --git a/goopdate/crash.cc b/goopdate/crash.cc
index d160c5b..3a39ca5 100644
--- a/goopdate/crash.cc
+++ b/goopdate/crash.cc
@@ -1,1035 +1,1035 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// TODO(omaha): for reliability sake, the code that sets up the exception

-// handler should be very minimalist and not call so much outside of this

-// module. One idea is to split the crash module in two: one minimalist part

-// responsible for setting up the exception handler and one that is uploading

-// the crash.

-

-#include "omaha/goopdate/crash.h"

-

-#include <windows.h>

-#include <shlwapi.h>

-#include <atlbase.h>

-#include <atlstr.h>

-#include <cmath>

-#include <map>

-#include <string>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/exception_barrier.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/module_utils.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/event_logger.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/goopdate_metrics.h"

-#include "omaha/goopdate/stats_uploader.h"

-#include "third_party/breakpad/src/client/windows/common/ipc_protocol.h"

-#include "third_party/breakpad/src/client/windows/crash_generation/client_info.h"

-#include "third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.h"

-#include "third_party/breakpad/src/client/windows/sender/crash_report_sender.h"

-

-using google_breakpad::ClientInfo;

-using google_breakpad::CrashGenerationServer;

-using google_breakpad::CrashReportSender;

-using google_breakpad::CustomClientInfo;

-using google_breakpad::ExceptionHandler;

-using google_breakpad::ReportResult;

-

-namespace omaha {

-

-const TCHAR kPipeNamePrefix[] = _T("\\\\.\\pipe\\GoogleCrashServices");

-

-const ACCESS_MASK kPipeAccessMask = FILE_READ_ATTRIBUTES  |

-                                    FILE_READ_DATA        |

-                                    FILE_WRITE_ATTRIBUTES |

-                                    FILE_WRITE_DATA       |

-                                    SYNCHRONIZE;

-

-CString Crash::module_filename_;

-CString Crash::crash_dir_;

-CString Crash::checkpoint_file_;

-CString Crash::guid_;

-CString Crash::version_postfix_  = kCrashVersionPostfixString;

-CString Crash::crash_report_url_ = kUrlCrashReport;

-int Crash::max_reports_per_day_  = kCrashReportMaxReportsPerDay;

-ExceptionHandler* Crash::exception_handler_ = NULL;

-CrashGenerationServer* Crash::crash_server_ = NULL;

-

-bool Crash::is_machine_ = false;

-const TCHAR* const Crash::kDefaultProductName = _T("Google Error Reporting");

-

-HRESULT Crash::Initialize(bool is_machine) {

-  is_machine_ = is_machine;

-

-  HRESULT hr = GetModuleFileName(NULL, &module_filename_);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = InitializeCrashDir();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(!crash_dir_.IsEmpty());

-  CORE_LOG(L2, (_T("[crash dir %s]"), crash_dir_));

-

-  // The checkpoint file maintains state information for the crash report

-  // client, such as the number of reports per day successfully sent.

-  checkpoint_file_ = ConcatenatePath(crash_dir_, _T("checkpoint"));

-  if (checkpoint_file_.IsEmpty()) {

-    return GOOPDATE_E_PATH_APPEND_FAILED;

-  }

-

-  return S_OK;

-}

-

-HRESULT Crash::InstallCrashHandler(bool is_machine) {

-  CORE_LOG(L3, (_T("[Crash::InstallCrashHandler][is_machine %d]"), is_machine));

-

-  HRESULT hr = Initialize(is_machine);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[failed to initialize Crash][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Only installs the exception handler if the process is not a crash report

-  // process. If the crash reporter crashes as well, this results in an

-  // infinite loop.

-  bool is_crash_report_process = false;

-  if (FAILED(IsCrashReportProcess(&is_crash_report_process)) ||

-      is_crash_report_process) {

-    return S_OK;

-  }

-

-  // Allocate this instance dynamically so that it is going to be

-  // around until the process terminates. Technically, this instance "leaks",

-  // but this is actually the correct behavior.

-  if (exception_handler_) {

-    delete exception_handler_;

-  }

-  exception_handler_ = new ExceptionHandler(crash_dir_.GetString(),

-                                            NULL,

-                                            &Crash::MinidumpCallback,

-                                            NULL,

-                                            ExceptionHandler::HANDLER_ALL);

-

-  // Breakpad does not get the exceptions that are not propagated to the

-  // UnhandledExceptionFilter. This is the case where we crashed on a stack

-  // which we do not own, such as an RPC stack. To get these exceptions we

-  // initialize a static ExceptionBarrier object.

-  ExceptionBarrier::set_handler(&Crash::EBHandler);

-

-  CORE_LOG(L2, (_T("[exception handler has been installed]")));

-  return S_OK;

-}

-

-void Crash::UninstallCrashHandler() {

-  ExceptionBarrier::set_handler(NULL);

-  delete exception_handler_;

-  exception_handler_ = NULL;

-

-  CORE_LOG(L2, (_T("[exception handler has been uninstalled]")));

-}

-

-HRESULT Crash::CrashHandler(bool is_machine,

-                            const google_breakpad::ClientInfo& client_info,

-                            const CString& crash_filename) {

-  // Count the number of crashes requested by applications.

-  ++metric_oop_crashes_requested;

-

-  // GoogleCrashHandler.exe is only aggregating metrics at process exit. Since

-  // GoogleCrashHandler.exe is long-running however, we hardly ever exit. As a

-  // consequence, oop_crashes_requested will be reported very infrequently. This

-  // call below will do additional aggregation of metrics, so that we can report

-  // metric_oop_crashes_requested in a timely manner.

-  VERIFY1(SUCCEEDED(AggregateMetrics(is_machine)));

-

-  DWORD pid = client_info.pid();

-  OPT_LOG(L1, (_T("[client requested dump][pid %d]"), pid));

-

-  ASSERT1(!crash_filename.IsEmpty());

-  if (crash_filename.IsEmpty()) {

-    OPT_LOG(L1, (_T("[no crash file]")));

-    return E_UNEXPECTED;

-  }

-

-  CString custom_info_filename;

-  HRESULT hr = CreateCustomInfoFile(crash_filename,

-                                    client_info.GetCustomInfo(),

-                                    &custom_info_filename);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[CreateCustomInfoFile failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Start a sender process to handle the crash.

-  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-  builder.set_crash_filename(crash_filename);

-  builder.set_custom_info_filename(custom_info_filename);

-  builder.set_is_machine_set(is_machine);

-  CString cmd_line = builder.GetCommandLine(module_filename_);

-  hr = StartSenderWithCommandLine(&cmd_line);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[StartSenderWithCommandLine failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  OPT_LOG(L1, (_T("[client dump handled][pid %d]"), pid));

-  return S_OK;

-}

-

-// The implementation must be as simple as possible and use only the

-// resources it needs to start a reporter process and then exit.

-bool Crash::MinidumpCallback(const wchar_t* dump_path,

-                             const wchar_t* minidump_id,

-                             void*,

-                             EXCEPTION_POINTERS*,

-                             MDRawAssertionInfo*,

-                             bool succeeded) {

-  if (succeeded && *dump_path && *minidump_id) {

-    // We need a way to see if the crash happens while we are installing

-    // something. This is a tough spot to be doing anything at all since

-    // we've been handling a crash.

-    // TODO(omaha): redesign a better mechanism.

-    bool is_interactive = Crash::IsInteractive();

-

-    // TODO(omaha): format a command line without extra memory allocations.

-    CString crash_filename;

-    crash_filename.Format(_T("%s\\%s.dmp"), dump_path, minidump_id);

-    EnclosePath(&crash_filename);

-

-    // CommandLineBuilder escapes the program name before returning the

-    // command line to the caller.

-    CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);

-    builder.set_is_interactive_set(is_interactive);

-    builder.set_crash_filename(crash_filename);

-    builder.set_is_machine_set(is_machine_);

-    CString cmd_line = builder.GetCommandLine(module_filename_);

-

-    // Set an environment variable which the crash reporter process will

-    // inherit. We don't want to install a crash handler for the reporter

-    // process to avoid an infinite loop in the case the reporting process

-    // crashes also. When the reporting process begins execution, the presence

-    // of this environment variable is tested, and the crash handler will not be

-    // installed.

-    if (::SetEnvironmentVariable(kNoCrashHandlerEnvVariableName, (_T("1")))) {

-      STARTUPINFO si = {sizeof(si)};

-      PROCESS_INFORMATION pi = {0};

-      if (::CreateProcess(NULL,

-                          cmd_line.GetBuffer(),

-                          NULL,

-                          NULL,

-                          false,

-                          0,

-                          NULL,

-                          NULL,

-                          &si,

-                          &pi)) {

-        ::CloseHandle(pi.hProcess);

-        ::CloseHandle(pi.hThread);

-      }

-    }

-  }

-

-  // There are two ways to stop execution of the current process: ExitProcess

-  // and TerminateProcess. Calling ExitProcess results in calling the

-  // destructors of the static objects before the process exits.

-  // TerminateProcess unconditionally stops the process so no user mode code

-  // executes beyond this point.

-  ::TerminateProcess(::GetCurrentProcess(),

-                     static_cast<UINT>(GOOPDATE_E_CRASH));

-  return true;

-}

-

-HRESULT Crash::StartSenderWithCommandLine(CString* cmd_line) {

-  TCHAR* env_vars = ::GetEnvironmentStrings();

-  if (env_vars == NULL) {

-    return HRESULTFromLastError();

-  }

-

-  // Add an environment variable to the crash reporter process to indicate it

-  // not to install a crash handler. This avoids an infinite loop in the case

-  // the reporting process crashes also. When the reporting process begins

-  // execution, the presence of this environment variable is tested, and the

-  // crash handler will not be installed.

-  CString new_var;

-  new_var.Append(kNoCrashHandlerEnvVariableName);

-  new_var.Append(_T("=1"));

-

-  // Compute the length of environment variables string. The format of the

-  // string is Name1=Value1\0Name2=Value2\0Name3=Value3\0\0.

-  const TCHAR* current = env_vars;

-  size_t env_vars_char_count = 0;

-  while (*current) {

-    size_t sub_length = _tcslen(current) + 1;

-    env_vars_char_count += sub_length;

-    current += sub_length;

-  }

-  // Add one to length to count the trailing NULL character marking the end of

-  // all environment variables.

-  ++env_vars_char_count;

-

-  // Copy the new environment variable and the existing variables in a new

-  // buffer.

-  size_t new_var_char_count = new_var.GetLength() + 1;

-  scoped_array<TCHAR> new_env_vars(

-      new TCHAR[env_vars_char_count + new_var_char_count]);

-  size_t new_var_byte_count = new_var_char_count * sizeof(TCHAR);

-  memcpy(new_env_vars.get(),

-         static_cast<const TCHAR*>(new_var),

-         new_var_byte_count);

-  size_t env_vars_byte_count = env_vars_char_count * sizeof(TCHAR);

-  memcpy(new_env_vars.get() + new_var_char_count,

-         env_vars,

-         env_vars_byte_count);

-  ::FreeEnvironmentStrings(env_vars);

-

-  STARTUPINFO si = {sizeof(si)};

-  PROCESS_INFORMATION pi = {0};

-  if (!::CreateProcess(NULL,

-                       cmd_line->GetBuffer(),

-                       NULL,

-                       NULL,

-                       false,

-                       CREATE_UNICODE_ENVIRONMENT,

-                       new_env_vars.get(),

-                       NULL,

-                       &si,

-                       &pi)) {

-    return ::GetLastError();

-  }

-

-  ::CloseHandle(pi.hProcess);

-  ::CloseHandle(pi.hThread);

-  return S_OK;

-}

-

-HRESULT Crash::CreateCustomInfoFile(const CString& dump_file,

-                                    const CustomClientInfo& custom_client_info,

-                                    CString* custom_info_filepath) {

-  // Since goopdate_utils::WriteNameValuePairsToFile is implemented in terms

-  // of WritePrivateProfile API, relative paths are relative to the Windows

-  // directory instead of the current directory of the process.

-  ASSERT(!::PathIsRelative(dump_file), (_T("Path must be absolute")));

-

-  // Determine the path for custom info file.

-  CString filepath = GetPathRemoveExtension(dump_file);

-  filepath.AppendFormat(_T(".txt"));

-

-  // Create a map of name/value pairs from custom client info.

-  std::map<CString, CString> custom_info_map;

-  for (int i = 0; i < custom_client_info.count; ++i) {

-    custom_info_map[custom_client_info.entries[i].name] =

-                    custom_client_info.entries[i].value;

-  }

-

-  HRESULT hr = goopdate_utils::WriteNameValuePairsToFile(filepath,

-                                                         kCustomClientInfoGroup,

-                                                         custom_info_map);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  *custom_info_filepath = filepath;

-  return S_OK;

-}

-

-// Backs up the crash and uploads it if allowed to.

-HRESULT Crash::DoSendCrashReport(bool can_upload,

-                                 bool is_out_of_process,

-                                 const CString& crash_filename,

-                                 const ParameterMap& parameters,

-                                 CString* report_id) {

-  ASSERT1(!crash_filename.IsEmpty());

-  ASSERT1(report_id);

-  report_id->Empty();

-

-  if (!File::Exists(crash_filename)) {

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-

-  CString product_name = GetProductName(parameters);

-  VERIFY1(SUCCEEDED(SaveLastCrash(crash_filename, product_name)));

-

-  HRESULT hr = S_OK;

-  if (can_upload) {

-    hr = UploadCrash(is_out_of_process, crash_filename, parameters, report_id);

-  }

-

-  return hr;

-}

-

-HRESULT Crash::UploadCrash(bool is_out_of_process,

-                           const CString& crash_filename,

-                           const ParameterMap& parameters,

-                           CString* report_id) {

-  ASSERT1(report_id);

-  report_id->Empty();

-

-  // Calling this avoids crashes in WinINet. See: http://b/1258692

-  EnsureRasmanLoaded();

-

-  ASSERT1(!crash_dir_.IsEmpty());

-  ASSERT1(!checkpoint_file_.IsEmpty());

-

-  // Do best effort to send the crash. If it can't communicate with the backend,

-  // it retries a few times over a few hours time interval.

-  HRESULT hr = S_OK;

-  for (int i = 0; i != kCrashReportAttempts; ++i) {

-    std::wstring report_code;

-    CrashReportSender sender(checkpoint_file_.GetString());

-    sender.set_max_reports_per_day(max_reports_per_day_);

-    CORE_LOG(L2, (_T("[Uploading crash report]")

-                  _T("[%s][%s]"), crash_report_url_, crash_filename));

-    ASSERT1(!crash_report_url_.IsEmpty());

-    ReportResult res = sender.SendCrashReport(crash_report_url_.GetString(),

-                                              parameters,

-                                              crash_filename.GetString(),

-                                              &report_code);

-    switch (res) {

-      case google_breakpad::RESULT_SUCCEEDED:

-        report_id->SetString(report_code.c_str());

-        hr = S_OK;

-        break;

-

-      case google_breakpad::RESULT_FAILED:

-        OPT_LOG(L2, (_T("[Crash report failed but it will retry sending]")));

-        ::Sleep(kCrashReportResendPeriodMs);

-        hr = E_FAIL;

-        break;

-

-      case google_breakpad::RESULT_REJECTED:

-        hr = GOOPDATE_E_CRASH_REJECTED;

-        break;

-

-      case google_breakpad::RESULT_THROTTLED:

-        hr = GOOPDATE_E_CRASH_THROTTLED;

-        break;

-

-      default:

-        hr = E_FAIL;

-        break;

-    };

-

-    // Continue the retry loop only when it could not contact the server.

-    if (res != google_breakpad::RESULT_FAILED) {

-      break;

-    }

-  }

-

-  // The event source for the out-of-process crashes is the product name.

-  // Therefore, in the event of an out-of-process crash, the log entry

-  // appears to be generated by the product that crashed.

-  CString product_name = is_out_of_process ? GetProductName(parameters) :

-                                             kAppName;

-  CString event_text;

-  uint16 event_type(0);

-  if (!report_id->IsEmpty()) {

-    event_type = EVENTLOG_INFORMATION_TYPE;

-    event_text.Format(_T("Crash uploaded. Id=%s."), *report_id);

-  } else {

-    ASSERT1(FAILED(hr));

-    event_type = EVENTLOG_WARNING_TYPE;

-    event_text.Format(_T("Crash not uploaded. Error=0x%x."), hr);

-  }

-  VERIFY1(SUCCEEDED(Crash::Log(event_type,

-                               kCrashUploadEventId,

-                               product_name,

-                               event_text)));

-

-  UpdateCrashUploadMetrics(is_out_of_process, hr);

-

-  return hr;

-}

-

-HRESULT Crash::SaveLastCrash(const CString& crash_filename,

-                             const CString& product_name) {

-  if (product_name.IsEmpty()) {

-    return E_INVALIDARG;

-  }

-  CString tmp;

-  tmp.Format(_T("%s-last.dmp"), product_name);

-  CString save_filename = ConcatenatePath(crash_dir_, tmp);

-  if (save_filename.IsEmpty()) {

-    return GOOPDATE_E_PATH_APPEND_FAILED;

-  }

-

-  CORE_LOG(L2, (_T("[Crash::SaveLastCrash]")

-                 _T("[to %s][from %s]"), save_filename, crash_filename));

-

-  return ::CopyFile(crash_filename,

-                    save_filename,

-                    false) ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT Crash::CleanStaleCrashes() {

-  CORE_LOG(L3, (_T("[Crash::CleanStaleCrashes]")));

-

-  // ??- sequence is a c++ trigraph corresponding to a ~. Escape it.

-  const TCHAR kWildCards[] = _T("???????\?-???\?-???\?-???\?-????????????.dmp");

-  std::vector<CString> crash_files;

-  HRESULT hr = File::GetWildcards(crash_dir_, kWildCards, &crash_files);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  time64 now = GetCurrent100NSTime();

-  for (size_t i = 0; i != crash_files.size(); ++i) {

-    CORE_LOG(L3, (_T("[found crash file][%s]"), crash_files[i]));

-    FILETIME creation_time = {0};

-    if (SUCCEEDED(File::GetFileTime(crash_files[i],

-                                    &creation_time,

-                                    NULL,

-                                    NULL))) {

-      double time_diff =

-          static_cast<double>(now - FileTimeToTime64(creation_time));

-      if (abs(time_diff) >= kDaysTo100ns) {

-        VERIFY1(::DeleteFile(crash_files[i]));

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT Crash::Report(bool can_upload_in_process,

-                      const CString& crash_filename,

-                      const CString& custom_info_filename,

-                      const CString& lang) {

-  const bool is_out_of_process = !custom_info_filename.IsEmpty();

-  HRESULT hr = S_OK;

-  if (is_out_of_process) {

-    hr = ReportProductCrash(true, crash_filename, custom_info_filename, lang);

-    ::DeleteFile(custom_info_filename);

-  } else {

-    hr = ReportGoogleUpdateCrash(can_upload_in_process,

-                                 crash_filename,

-                                 custom_info_filename,

-                                 lang);

-  }

-  ::DeleteFile(crash_filename);

-  CleanStaleCrashes();

-  return hr;

-}

-

-HRESULT Crash::ReportGoogleUpdateCrash(bool can_upload,

-                                       const CString& crash_filename,

-                                       const CString& custom_info_filename,

-                                       const CString& lang) {

-  OPT_LOG(L1, (_T("[Crash::ReportGoogleUpdateCrash]")));

-

-  UNREFERENCED_PARAMETER(custom_info_filename);

-

-  CString guid = is_machine_ ?

-                 goopdate_utils::GetPersistentMachineId() :

-                 goopdate_utils::GetPersistentUserId(USER_KEY_NAME);

-

-  // If someone has set a guid then use it instead of the user or the

-  // machine id. This is usually the case of a unit test where for the

-  // sake of aggregating the crashes we use the same guid.

-  if (!guid_.IsEmpty()) {

-    guid = guid_;

-  }

-

-  // Build the map of additional parameters to report along with the crash.

-  CString ver(GetVersionString() + version_postfix_);

-

-  ParameterMap parameters;

-  parameters[_T("prod")] = _T("Update2");

-  parameters[_T("ver")]  = ver;

-  parameters[_T("guid")] = guid;

-  parameters[_T("lang")] = lang;

-

-  CString event_text;

-  event_text.Format(

-      _T("Google Update has encountered a fatal error.\r\n")

-      _T("ver=%s;lang=%s;id=%s;is_machine=%d;upload=%d;minidump=%s"),

-      ver, lang, guid, is_machine_, can_upload ? 1 : 0, crash_filename);

-  VERIFY1(SUCCEEDED(Crash::Log(EVENTLOG_ERROR_TYPE,

-                               kCrashReportEventId,

-                               kAppName,

-                               event_text)));

-

-  ++metric_crashes_total;

-

-  CString report_id;

-  return DoSendCrashReport(can_upload,

-                           false,             // Google Update crash.

-                           crash_filename,

-                           parameters,

-                           &report_id);

-}

-

-HRESULT Crash::ReportProductCrash(bool can_upload,

-                                  const CString& crash_filename,

-                                  const CString& custom_info_filename,

-                                  const CString& lang) {

-  OPT_LOG(L1, (_T("[Crash::ReportProductCrash]")));

-

-  UNREFERENCED_PARAMETER(lang);

-

-  // All product crashes must be uploaded.

-  ASSERT1(can_upload);

-

-  // Count the number of crashes the sender was requested to handle.

-  ++metric_oop_crashes_total;

-

-  std::map<CString, CString> parameters_temp;

-  HRESULT hr = goopdate_utils::ReadNameValuePairsFromFile(

-      custom_info_filename,

-      kCustomClientInfoGroup,

-      &parameters_temp);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ParameterMap parameters;

-  std::map<CString, CString>::const_iterator iter;

-  for (iter = parameters_temp.begin(); iter != parameters_temp.end(); ++iter) {

-    parameters[iter->first.GetString()] = iter->second.GetString();

-  }

-

-  CString report_id;

-  return hr = DoSendCrashReport(can_upload,

-                                true,                  // Out of process crash.

-                                crash_filename,

-                                parameters,

-                                &report_id);

-}

-

-void __stdcall Crash::EBHandler(EXCEPTION_POINTERS* ptrs) {

-  if (exception_handler_) {

-    exception_handler_->WriteMinidumpForException(ptrs);

-  }

-}

-

-HRESULT Crash::GetExceptionInfo(const CString& crash_filename,

-                                MINIDUMP_EXCEPTION* ex_info) {

-  ASSERT1(ex_info);

-  ASSERT1(!crash_filename.IsEmpty());

-

-  // Dynamically link with the dbghelp to avoid runtime resource bloat.

-  scoped_library dbghelp(::LoadLibrary(_T("dbghelp.dll")));

-  if (!dbghelp) {

-    return HRESULTFromLastError();

-  }

-

-  typedef BOOL (WINAPI *MiniDumpReadDumpStreamFun)(void* base_of_dump,

-                                                   ULONG stream_number,

-                                                   MINIDUMP_DIRECTORY* dir,

-                                                   void** stream_pointer,

-                                                   ULONG* stream_size);

-

-  MiniDumpReadDumpStreamFun minidump_read_dump_stream =

-      reinterpret_cast<MiniDumpReadDumpStreamFun>(::GetProcAddress(get(dbghelp),

-                                                  "MiniDumpReadDumpStream"));

-  ASSERT1(minidump_read_dump_stream);

-  if (!minidump_read_dump_stream) {

-    return HRESULTFromLastError();

-  }

-

-  // The minidump file must be mapped in memory before reading the streams.

-  scoped_hfile file(::CreateFile(crash_filename,

-                                 GENERIC_READ,

-                                 FILE_SHARE_READ,

-                                 NULL,

-                                 OPEN_EXISTING,

-                                 FILE_ATTRIBUTE_READONLY,

-                                 NULL));

-  ASSERT1(file);

-  if (!file) {

-    return HRESULTFromLastError();

-  }

-  scoped_file_mapping file_mapping(::CreateFileMapping(get(file),

-                                                       NULL,

-                                                       PAGE_READONLY,

-                                                       0,

-                                                       0,

-                                                       NULL));

-  if (!file_mapping) {

-    return HRESULTFromLastError();

-  }

-  scoped_file_view base_of_dump(::MapViewOfFile(get(file_mapping),

-                                                FILE_MAP_READ,

-                                                0,

-                                                0,

-                                                0));

-  if (!base_of_dump) {

-    return HRESULTFromLastError();

-  }

-

-  // Read the exception stream and pick up the exception record.

-  MINIDUMP_DIRECTORY minidump_directory = {0};

-  void* stream_pointer = NULL;

-  ULONG stream_size = 0;

-  bool result = !!(*minidump_read_dump_stream)(get(base_of_dump),

-                                               ExceptionStream,

-                                               &minidump_directory,

-                                               &stream_pointer,

-                                               &stream_size);

-  if (!result) {

-    return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);

-  }

-  MINIDUMP_EXCEPTION_STREAM* exception_stream =

-      static_cast<MINIDUMP_EXCEPTION_STREAM*>(stream_pointer);

-  ASSERT1(stream_pointer);

-  ASSERT1(stream_size);

-

-  *ex_info = exception_stream->ExceptionRecord;

-  return S_OK;

-}

-

-bool Crash::IsInteractive() {

-  bool result = false;

-  ::EnumWindows(&Crash::EnumWindowsCallback, reinterpret_cast<LPARAM>(&result));

-  return result;

-}

-

-// Finds if the given window is in the current process.

-BOOL CALLBACK Crash::EnumWindowsCallback(HWND hwnd, LPARAM param) {

-  DWORD pid = 0;

-  ::GetWindowThreadProcessId(hwnd, &pid);

-  if (::IsWindowVisible(hwnd) && pid == ::GetCurrentProcessId() && param) {

-    *reinterpret_cast<bool*>(param) = true;

-    return false;

-  }

-  return true;

-}

-

-HRESULT Crash::InitializeCrashDir() {

-  crash_dir_.Empty();

-  ConfigManager* cm = ConfigManager::Instance();

-  CString dir = is_machine_ ? cm->GetMachineCrashReportsDir() :

-                              cm->GetUserCrashReportsDir();

-

-  if (is_machine_ && !dir.IsEmpty()) {

-    HRESULT hr = InitializeDirSecurity(&dir);

-    if (FAILED(hr)) {

-      CORE_LOG(LW, (_T("[failed to initialize crash dir security][0x%x]"), hr));

-      ::RemoveDirectory(dir);

-    }

-  }

-

-  // Use the temporary directory of the process if the crash directory can't be

-  // initialized for any reason. Users can't read files in other users'

-  // temporary directories so the temp dir is good option to still have

-  // crash handling.

-  if (dir.IsEmpty()) {

-    dir = app_util::GetTempDir();

-  }

-

-  if (dir.IsEmpty()) {

-    return GOOPDATE_E_CRASH_NO_DIR;

-  }

-

-  crash_dir_ = dir;

-  return S_OK;

-}

-

-HRESULT Crash::InitializeDirSecurity(CString* dir) {

-  ASSERT1(dir);

-

-  // Users can only read permissions on the crash dir.

-  CDacl dacl;

-  const uint8 kAceFlags = SUB_CONTAINERS_AND_OBJECTS_INHERIT;

-  if (!dacl.AddAllowedAce(Sids::System(), GENERIC_ALL, kAceFlags) ||

-      !dacl.AddAllowedAce(Sids::Admins(), GENERIC_ALL, kAceFlags) ||

-      !dacl.AddAllowedAce(Sids::Users(), READ_CONTROL, kAceFlags)) {

-    return GOOPDATE_E_CRASH_SECURITY_FAILED;

-  }

-

-  SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION |

-                            PROTECTED_DACL_SECURITY_INFORMATION;

-  DWORD error = ::SetNamedSecurityInfo(dir->GetBuffer(),

-                                       SE_FILE_OBJECT,

-                                       si,

-                                       NULL,

-                                       NULL,

-                                       const_cast<ACL*>(dacl.GetPACL()),

-                                       NULL);

-  if (error != ERROR_SUCCESS) {

-    return HRESULT_FROM_WIN32(error);

-  }

-  return S_OK;

-}

-

-// Checks for the presence of an environment variable. We are not interested

-// in the value of the variable but only in its presence.

-HRESULT Crash::IsCrashReportProcess(bool* is_crash_report_process) {

-  ASSERT1(is_crash_report_process);

-  if (::GetEnvironmentVariable(kNoCrashHandlerEnvVariableName, NULL, 0)) {

-    *is_crash_report_process = true;

-    return S_OK;

-  } else {

-    DWORD error(::GetLastError());

-    *is_crash_report_process = false;

-    return error == ERROR_ENVVAR_NOT_FOUND ? S_OK : HRESULT_FROM_WIN32(error);

-  }

-}

-

-HRESULT Crash::Log(uint16 type,

-                   uint32 id,

-                   const TCHAR* source,

-                   const TCHAR* description) {

-  ASSERT1(source);

-  ASSERT1(description);

-  return EventLogger::ReportEvent(source,

-                                  type,

-                                  0,            // Category.

-                                  id,

-                                  1,            // Number of strings.

-                                  &description,

-                                  0,            // Raw data size.

-                                  NULL);        // Raw data.

-}

-

-CString Crash::GetProductName(const ParameterMap& parameters) {

-  // The crash is logged using the value of 'prod' if available or

-  // a default constant string otherwise.

-  CString product_name;

-  ParameterMap::const_iterator it = parameters.find(_T("prod"));

-  const bool is_found = it != parameters.end() && !it->second.empty();

-  return is_found ? it->second.c_str() : kDefaultProductName;

-}

-

-void Crash::UpdateCrashUploadMetrics(bool is_out_of_process, HRESULT hr) {

-  switch (hr) {

-    case S_OK:

-      if (is_out_of_process) {

-        ++metric_oop_crashes_uploaded;

-      } else {

-        ++metric_crashes_uploaded;

-      }

-      break;

-

-    case E_FAIL:

-      if (is_out_of_process) {

-        ++metric_oop_crashes_failed;

-      } else {

-        ++metric_crashes_failed;

-      }

-      break;

-

-    case GOOPDATE_E_CRASH_THROTTLED:

-      if (is_out_of_process) {

-        ++metric_oop_crashes_throttled;

-      } else {

-        ++metric_crashes_throttled;

-      }

-      break;

-

-    case GOOPDATE_E_CRASH_REJECTED:

-      if (is_out_of_process) {

-        ++metric_oop_crashes_rejected;

-      } else {

-        ++metric_crashes_rejected;

-      }

-      break;

-

-    default:

-      ASSERT1(false);

-      break;

-  }

-}

-

-int Crash::CrashNow() {

-#ifdef DEBUG

-  CORE_LOG(LEVEL_ERROR, (_T("[Crash::CrashNow]")));

-  int foo = 10;

-  int bar = foo - 10;

-  int baz = foo / bar;

-  return baz;

-#else

-  return 0;

-#endif

-}

-

-bool Crash::BuildPipeSecurityAttributes(CSecurityAttributes* sa) {

-  ASSERT1(sa);

-

-  CDacl dacl;

-  CAccessToken current_token;

-  if (!current_token.GetEffectiveToken(TOKEN_QUERY)) {

-    OPT_LOG(LE, (_T("[Failed to get current thread token]")));

-    return false;

-  }

-

-  if (!current_token.GetDefaultDacl(&dacl)) {

-    OPT_LOG(LE, (_T("[Failed to get default DACL]")));

-    return false;

-  }

-

-  if (!dacl.AddAllowedAce(ATL::Sids::Users(), kPipeAccessMask)) {

-    OPT_LOG(LE, (_T("[Failed to setup pipe security]")));

-    return false;

-  }

-

-  if (!dacl.AddDeniedAce(ATL::Sids::Network(), FILE_ALL_ACCESS)) {

-    OPT_LOG(LE, (_T("[Failed to setup pipe security]")));

-    return false;

-  }

-

-  ATL::CSecurityDesc sd;

-  sd.SetDacl(dacl);

-  sa->Set(sd);

-

-#ifdef _DEBUG

-  // Print SDDL for debugging.

-  CString sddl;

-  sd.ToString(&sddl);

-  CORE_LOG(L1, (_T("[Pipe security SDDL][%s]"), sddl));

-#endif

-

-  return true;

-}

-

-bool Crash::BuildCrashDirSecurityAttributes(CSecurityAttributes* sa) {

-  ASSERT1(sa);

-

-  CDacl dacl;

-  CAccessToken current_token;

-

-  if (!current_token.GetEffectiveToken(TOKEN_QUERY)) {

-    OPT_LOG(LE, (_T("[Failed to get current thread token]")));

-    return false;

-  }

-

-  if (!current_token.GetDefaultDacl(&dacl)) {

-    OPT_LOG(LE, (_T("[Failed to get default DACL]")));

-    return false;

-  }

-

-  CSecurityDesc sd;

-  sd.SetDacl(dacl);

-  // Prevent the security settings on the parent folder of CrashReports folder

-  // from being inherited by children of CrashReports folder.

-  sd.SetControl(SE_DACL_PROTECTED, SE_DACL_PROTECTED);

-  sa->Set(sd);

-

-#ifdef _DEBUG

-  // Print SDDL for debugging.

-  CString sddl;

-  sd.ToString(&sddl);

-  CORE_LOG(L1, (_T("[Folder security SDDL][%s]"), sddl));

-#endif

-

-  return true;

-}

-

-HRESULT Crash::StartServer() {

-  CORE_LOG(L1, (_T("[Crash::StartServer]")));

-  ++metric_crash_start_server_total;

-

-  std::wstring dump_path(crash_dir_);

-

-  // Append the current user's sid to the pipe name so that machine and

-  // user instances of the crash server open different pipes.

-  CString user_sid;

-  HRESULT hr = user_info::GetCurrentUser(NULL, NULL, &user_sid);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Failed to get SID for current user][0x%08x]"), hr));

-    return hr;

-  }

-  CString pipe_name(kPipeNamePrefix);

-  pipe_name.AppendFormat(_T("\\%s"), user_sid);

-

-  CSecurityAttributes pipe_sec_attrs;

-

-  // If running as machine, use custom security attributes on the pipe to

-  // allow all users on the local machine to connect to it.

-  // If running as user, the default security descriptor for the

-  // pipe grants full control to the system account, administrators,

-  // and the creator owner. However, when running elevated, the creator

-  // owner is not given full rights. In this case, only elevated users can

-  // connect to the pipe. This is not the desired behavior.

-  if (is_machine_ && !BuildPipeSecurityAttributes(&pipe_sec_attrs)) {

-    return GOOPDATE_E_CRASH_SECURITY_FAILED;

-  }

-

-  scoped_ptr<CrashGenerationServer> crash_server(

-      new CrashGenerationServer(std::wstring(pipe_name),

-                                &pipe_sec_attrs,

-                                ClientConnectedCallback, NULL,

-                                ClientCrashedCallback, NULL,

-                                ClientExitedCallback, NULL,

-                                true, &dump_path));

-

-  if (!crash_server->Start()) {

-    CORE_LOG(LE, (_T("[CrashServer::Start failed]")));

-    return GOOPDATE_E_CRASH_START_SERVER_FAILED;

-  }

-

-  crash_server_ = crash_server.release();

-

-  ++metric_crash_start_server_succeeded;

-  return S_OK;

-}

-

-void Crash::StopServer() {

-  CORE_LOG(L1, (_T("[Crash::StopServer]")));

-  delete crash_server_;

-  crash_server_ = NULL;

-}

-

-

-void _cdecl Crash::ClientConnectedCallback(void* context,

-                                           const ClientInfo* client_info) {

-  ASSERT1(!context);

-  ASSERT1(client_info);

-  UNREFERENCED_PARAMETER(context);

-  OPT_LOG(L1, (_T("[Client connected][%d]"), client_info->pid()));

-}

-

-void _cdecl Crash::ClientCrashedCallback(void* context,

-                                         const ClientInfo* client_info,

-                                         const std::wstring* dump_path) {

-  ASSERT1(!context);

-  ASSERT1(client_info);

-  UNREFERENCED_PARAMETER(context);

-  OPT_LOG(L1, (_T("[Client crashed][%d]"), client_info->pid()));

-

-  CString crash_filename(dump_path ? dump_path->c_str() : NULL);

-  HRESULT hr = Crash::CrashHandler(is_machine_, *client_info, crash_filename);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[CrashHandler failed][0x%08x]"), hr));

-  }

-}

-

-void _cdecl Crash::ClientExitedCallback(void* context,

-                                        const ClientInfo* client_info) {

-  ASSERT1(!context);

-  ASSERT1(client_info);

-  UNREFERENCED_PARAMETER(context);

-  OPT_LOG(L1, (_T("[Client exited][%d]"), client_info->pid()));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// TODO(omaha): for reliability sake, the code that sets up the exception
+// handler should be very minimalist and not call so much outside of this
+// module. One idea is to split the crash module in two: one minimalist part
+// responsible for setting up the exception handler and one that is uploading
+// the crash.
+
+#include "omaha/goopdate/crash.h"
+
+#include <windows.h>
+#include <shlwapi.h>
+#include <atlbase.h>
+#include <atlstr.h>
+#include <cmath>
+#include <map>
+#include <string>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/exception_barrier.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/module_utils.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/event_logger.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/goopdate_metrics.h"
+#include "omaha/goopdate/stats_uploader.h"
+#include "third_party/breakpad/src/client/windows/common/ipc_protocol.h"
+#include "third_party/breakpad/src/client/windows/crash_generation/client_info.h"
+#include "third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.h"
+#include "third_party/breakpad/src/client/windows/sender/crash_report_sender.h"
+
+using google_breakpad::ClientInfo;
+using google_breakpad::CrashGenerationServer;
+using google_breakpad::CrashReportSender;
+using google_breakpad::CustomClientInfo;
+using google_breakpad::ExceptionHandler;
+using google_breakpad::ReportResult;
+
+namespace omaha {
+
+const TCHAR kPipeNamePrefix[] = _T("\\\\.\\pipe\\GoogleCrashServices");
+
+const ACCESS_MASK kPipeAccessMask = FILE_READ_ATTRIBUTES  |
+                                    FILE_READ_DATA        |
+                                    FILE_WRITE_ATTRIBUTES |
+                                    FILE_WRITE_DATA       |
+                                    SYNCHRONIZE;
+
+CString Crash::module_filename_;
+CString Crash::crash_dir_;
+CString Crash::checkpoint_file_;
+CString Crash::guid_;
+CString Crash::version_postfix_  = kCrashVersionPostfixString;
+CString Crash::crash_report_url_ = kUrlCrashReport;
+int Crash::max_reports_per_day_  = kCrashReportMaxReportsPerDay;
+ExceptionHandler* Crash::exception_handler_ = NULL;
+CrashGenerationServer* Crash::crash_server_ = NULL;
+
+bool Crash::is_machine_ = false;
+const TCHAR* const Crash::kDefaultProductName = _T("Google Error Reporting");
+
+HRESULT Crash::Initialize(bool is_machine) {
+  is_machine_ = is_machine;
+
+  HRESULT hr = GetModuleFileName(NULL, &module_filename_);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = InitializeCrashDir();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(!crash_dir_.IsEmpty());
+  CORE_LOG(L2, (_T("[crash dir %s]"), crash_dir_));
+
+  // The checkpoint file maintains state information for the crash report
+  // client, such as the number of reports per day successfully sent.
+  checkpoint_file_ = ConcatenatePath(crash_dir_, _T("checkpoint"));
+  if (checkpoint_file_.IsEmpty()) {
+    return GOOPDATE_E_PATH_APPEND_FAILED;
+  }
+
+  return S_OK;
+}
+
+HRESULT Crash::InstallCrashHandler(bool is_machine) {
+  CORE_LOG(L3, (_T("[Crash::InstallCrashHandler][is_machine %d]"), is_machine));
+
+  HRESULT hr = Initialize(is_machine);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[failed to initialize Crash][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Only installs the exception handler if the process is not a crash report
+  // process. If the crash reporter crashes as well, this results in an
+  // infinite loop.
+  bool is_crash_report_process = false;
+  if (FAILED(IsCrashReportProcess(&is_crash_report_process)) ||
+      is_crash_report_process) {
+    return S_OK;
+  }
+
+  // Allocate this instance dynamically so that it is going to be
+  // around until the process terminates. Technically, this instance "leaks",
+  // but this is actually the correct behavior.
+  if (exception_handler_) {
+    delete exception_handler_;
+  }
+  exception_handler_ = new ExceptionHandler(crash_dir_.GetString(),
+                                            NULL,
+                                            &Crash::MinidumpCallback,
+                                            NULL,
+                                            ExceptionHandler::HANDLER_ALL);
+
+  // Breakpad does not get the exceptions that are not propagated to the
+  // UnhandledExceptionFilter. This is the case where we crashed on a stack
+  // which we do not own, such as an RPC stack. To get these exceptions we
+  // initialize a static ExceptionBarrier object.
+  ExceptionBarrier::set_handler(&Crash::EBHandler);
+
+  CORE_LOG(L2, (_T("[exception handler has been installed]")));
+  return S_OK;
+}
+
+void Crash::UninstallCrashHandler() {
+  ExceptionBarrier::set_handler(NULL);
+  delete exception_handler_;
+  exception_handler_ = NULL;
+
+  CORE_LOG(L2, (_T("[exception handler has been uninstalled]")));
+}
+
+HRESULT Crash::CrashHandler(bool is_machine,
+                            const google_breakpad::ClientInfo& client_info,
+                            const CString& crash_filename) {
+  // Count the number of crashes requested by applications.
+  ++metric_oop_crashes_requested;
+
+  // GoogleCrashHandler.exe is only aggregating metrics at process exit. Since
+  // GoogleCrashHandler.exe is long-running however, we hardly ever exit. As a
+  // consequence, oop_crashes_requested will be reported very infrequently. This
+  // call below will do additional aggregation of metrics, so that we can report
+  // metric_oop_crashes_requested in a timely manner.
+  VERIFY1(SUCCEEDED(AggregateMetrics(is_machine)));
+
+  DWORD pid = client_info.pid();
+  OPT_LOG(L1, (_T("[client requested dump][pid %d]"), pid));
+
+  ASSERT1(!crash_filename.IsEmpty());
+  if (crash_filename.IsEmpty()) {
+    OPT_LOG(L1, (_T("[no crash file]")));
+    return E_UNEXPECTED;
+  }
+
+  CString custom_info_filename;
+  HRESULT hr = CreateCustomInfoFile(crash_filename,
+                                    client_info.GetCustomInfo(),
+                                    &custom_info_filename);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[CreateCustomInfoFile failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Start a sender process to handle the crash.
+  CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+  builder.set_crash_filename(crash_filename);
+  builder.set_custom_info_filename(custom_info_filename);
+  builder.set_is_machine_set(is_machine);
+  CString cmd_line = builder.GetCommandLine(module_filename_);
+  hr = StartSenderWithCommandLine(&cmd_line);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[StartSenderWithCommandLine failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  OPT_LOG(L1, (_T("[client dump handled][pid %d]"), pid));
+  return S_OK;
+}
+
+// The implementation must be as simple as possible and use only the
+// resources it needs to start a reporter process and then exit.
+bool Crash::MinidumpCallback(const wchar_t* dump_path,
+                             const wchar_t* minidump_id,
+                             void*,
+                             EXCEPTION_POINTERS*,
+                             MDRawAssertionInfo*,
+                             bool succeeded) {
+  if (succeeded && *dump_path && *minidump_id) {
+    // We need a way to see if the crash happens while we are installing
+    // something. This is a tough spot to be doing anything at all since
+    // we've been handling a crash.
+    // TODO(omaha): redesign a better mechanism.
+    bool is_interactive = Crash::IsInteractive();
+
+    // TODO(omaha): format a command line without extra memory allocations.
+    CString crash_filename;
+    crash_filename.Format(_T("%s\\%s.dmp"), dump_path, minidump_id);
+    EnclosePath(&crash_filename);
+
+    // CommandLineBuilder escapes the program name before returning the
+    // command line to the caller.
+    CommandLineBuilder builder(COMMANDLINE_MODE_REPORTCRASH);
+    builder.set_is_interactive_set(is_interactive);
+    builder.set_crash_filename(crash_filename);
+    builder.set_is_machine_set(is_machine_);
+    CString cmd_line = builder.GetCommandLine(module_filename_);
+
+    // Set an environment variable which the crash reporter process will
+    // inherit. We don't want to install a crash handler for the reporter
+    // process to avoid an infinite loop in the case the reporting process
+    // crashes also. When the reporting process begins execution, the presence
+    // of this environment variable is tested, and the crash handler will not be
+    // installed.
+    if (::SetEnvironmentVariable(kNoCrashHandlerEnvVariableName, (_T("1")))) {
+      STARTUPINFO si = {sizeof(si)};
+      PROCESS_INFORMATION pi = {0};
+      if (::CreateProcess(NULL,
+                          cmd_line.GetBuffer(),
+                          NULL,
+                          NULL,
+                          false,
+                          0,
+                          NULL,
+                          NULL,
+                          &si,
+                          &pi)) {
+        ::CloseHandle(pi.hProcess);
+        ::CloseHandle(pi.hThread);
+      }
+    }
+  }
+
+  // There are two ways to stop execution of the current process: ExitProcess
+  // and TerminateProcess. Calling ExitProcess results in calling the
+  // destructors of the static objects before the process exits.
+  // TerminateProcess unconditionally stops the process so no user mode code
+  // executes beyond this point.
+  ::TerminateProcess(::GetCurrentProcess(),
+                     static_cast<UINT>(GOOPDATE_E_CRASH));
+  return true;
+}
+
+HRESULT Crash::StartSenderWithCommandLine(CString* cmd_line) {
+  TCHAR* env_vars = ::GetEnvironmentStrings();
+  if (env_vars == NULL) {
+    return HRESULTFromLastError();
+  }
+
+  // Add an environment variable to the crash reporter process to indicate it
+  // not to install a crash handler. This avoids an infinite loop in the case
+  // the reporting process crashes also. When the reporting process begins
+  // execution, the presence of this environment variable is tested, and the
+  // crash handler will not be installed.
+  CString new_var;
+  new_var.Append(kNoCrashHandlerEnvVariableName);
+  new_var.Append(_T("=1"));
+
+  // Compute the length of environment variables string. The format of the
+  // string is Name1=Value1\0Name2=Value2\0Name3=Value3\0\0.
+  const TCHAR* current = env_vars;
+  size_t env_vars_char_count = 0;
+  while (*current) {
+    size_t sub_length = _tcslen(current) + 1;
+    env_vars_char_count += sub_length;
+    current += sub_length;
+  }
+  // Add one to length to count the trailing NULL character marking the end of
+  // all environment variables.
+  ++env_vars_char_count;
+
+  // Copy the new environment variable and the existing variables in a new
+  // buffer.
+  size_t new_var_char_count = new_var.GetLength() + 1;
+  scoped_array<TCHAR> new_env_vars(
+      new TCHAR[env_vars_char_count + new_var_char_count]);
+  size_t new_var_byte_count = new_var_char_count * sizeof(TCHAR);
+  memcpy(new_env_vars.get(),
+         static_cast<const TCHAR*>(new_var),
+         new_var_byte_count);
+  size_t env_vars_byte_count = env_vars_char_count * sizeof(TCHAR);
+  memcpy(new_env_vars.get() + new_var_char_count,
+         env_vars,
+         env_vars_byte_count);
+  ::FreeEnvironmentStrings(env_vars);
+
+  STARTUPINFO si = {sizeof(si)};
+  PROCESS_INFORMATION pi = {0};
+  if (!::CreateProcess(NULL,
+                       cmd_line->GetBuffer(),
+                       NULL,
+                       NULL,
+                       false,
+                       CREATE_UNICODE_ENVIRONMENT,
+                       new_env_vars.get(),
+                       NULL,
+                       &si,
+                       &pi)) {
+    return ::GetLastError();
+  }
+
+  ::CloseHandle(pi.hProcess);
+  ::CloseHandle(pi.hThread);
+  return S_OK;
+}
+
+HRESULT Crash::CreateCustomInfoFile(const CString& dump_file,
+                                    const CustomClientInfo& custom_client_info,
+                                    CString* custom_info_filepath) {
+  // Since goopdate_utils::WriteNameValuePairsToFile is implemented in terms
+  // of WritePrivateProfile API, relative paths are relative to the Windows
+  // directory instead of the current directory of the process.
+  ASSERT(!::PathIsRelative(dump_file), (_T("Path must be absolute")));
+
+  // Determine the path for custom info file.
+  CString filepath = GetPathRemoveExtension(dump_file);
+  filepath.AppendFormat(_T(".txt"));
+
+  // Create a map of name/value pairs from custom client info.
+  std::map<CString, CString> custom_info_map;
+  for (int i = 0; i < custom_client_info.count; ++i) {
+    custom_info_map[custom_client_info.entries[i].name] =
+                    custom_client_info.entries[i].value;
+  }
+
+  HRESULT hr = goopdate_utils::WriteNameValuePairsToFile(filepath,
+                                                         kCustomClientInfoGroup,
+                                                         custom_info_map);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  *custom_info_filepath = filepath;
+  return S_OK;
+}
+
+// Backs up the crash and uploads it if allowed to.
+HRESULT Crash::DoSendCrashReport(bool can_upload,
+                                 bool is_out_of_process,
+                                 const CString& crash_filename,
+                                 const ParameterMap& parameters,
+                                 CString* report_id) {
+  ASSERT1(!crash_filename.IsEmpty());
+  ASSERT1(report_id);
+  report_id->Empty();
+
+  if (!File::Exists(crash_filename)) {
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+
+  CString product_name = GetProductName(parameters);
+  VERIFY1(SUCCEEDED(SaveLastCrash(crash_filename, product_name)));
+
+  HRESULT hr = S_OK;
+  if (can_upload) {
+    hr = UploadCrash(is_out_of_process, crash_filename, parameters, report_id);
+  }
+
+  return hr;
+}
+
+HRESULT Crash::UploadCrash(bool is_out_of_process,
+                           const CString& crash_filename,
+                           const ParameterMap& parameters,
+                           CString* report_id) {
+  ASSERT1(report_id);
+  report_id->Empty();
+
+  // Calling this avoids crashes in WinINet. See: http://b/1258692
+  EnsureRasmanLoaded();
+
+  ASSERT1(!crash_dir_.IsEmpty());
+  ASSERT1(!checkpoint_file_.IsEmpty());
+
+  // Do best effort to send the crash. If it can't communicate with the backend,
+  // it retries a few times over a few hours time interval.
+  HRESULT hr = S_OK;
+  for (int i = 0; i != kCrashReportAttempts; ++i) {
+    std::wstring report_code;
+    CrashReportSender sender(checkpoint_file_.GetString());
+    sender.set_max_reports_per_day(max_reports_per_day_);
+    CORE_LOG(L2, (_T("[Uploading crash report]")
+                  _T("[%s][%s]"), crash_report_url_, crash_filename));
+    ASSERT1(!crash_report_url_.IsEmpty());
+    ReportResult res = sender.SendCrashReport(crash_report_url_.GetString(),
+                                              parameters,
+                                              crash_filename.GetString(),
+                                              &report_code);
+    switch (res) {
+      case google_breakpad::RESULT_SUCCEEDED:
+        report_id->SetString(report_code.c_str());
+        hr = S_OK;
+        break;
+
+      case google_breakpad::RESULT_FAILED:
+        OPT_LOG(L2, (_T("[Crash report failed but it will retry sending]")));
+        ::Sleep(kCrashReportResendPeriodMs);
+        hr = E_FAIL;
+        break;
+
+      case google_breakpad::RESULT_REJECTED:
+        hr = GOOPDATE_E_CRASH_REJECTED;
+        break;
+
+      case google_breakpad::RESULT_THROTTLED:
+        hr = GOOPDATE_E_CRASH_THROTTLED;
+        break;
+
+      default:
+        hr = E_FAIL;
+        break;
+    };
+
+    // Continue the retry loop only when it could not contact the server.
+    if (res != google_breakpad::RESULT_FAILED) {
+      break;
+    }
+  }
+
+  // The event source for the out-of-process crashes is the product name.
+  // Therefore, in the event of an out-of-process crash, the log entry
+  // appears to be generated by the product that crashed.
+  CString product_name = is_out_of_process ? GetProductName(parameters) :
+                                             kAppName;
+  CString event_text;
+  uint16 event_type(0);
+  if (!report_id->IsEmpty()) {
+    event_type = EVENTLOG_INFORMATION_TYPE;
+    event_text.Format(_T("Crash uploaded. Id=%s."), *report_id);
+  } else {
+    ASSERT1(FAILED(hr));
+    event_type = EVENTLOG_WARNING_TYPE;
+    event_text.Format(_T("Crash not uploaded. Error=0x%x."), hr);
+  }
+  VERIFY1(SUCCEEDED(Crash::Log(event_type,
+                               kCrashUploadEventId,
+                               product_name,
+                               event_text)));
+
+  UpdateCrashUploadMetrics(is_out_of_process, hr);
+
+  return hr;
+}
+
+HRESULT Crash::SaveLastCrash(const CString& crash_filename,
+                             const CString& product_name) {
+  if (product_name.IsEmpty()) {
+    return E_INVALIDARG;
+  }
+  CString tmp;
+  tmp.Format(_T("%s-last.dmp"), product_name);
+  CString save_filename = ConcatenatePath(crash_dir_, tmp);
+  if (save_filename.IsEmpty()) {
+    return GOOPDATE_E_PATH_APPEND_FAILED;
+  }
+
+  CORE_LOG(L2, (_T("[Crash::SaveLastCrash]")
+                 _T("[to %s][from %s]"), save_filename, crash_filename));
+
+  return ::CopyFile(crash_filename,
+                    save_filename,
+                    false) ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT Crash::CleanStaleCrashes() {
+  CORE_LOG(L3, (_T("[Crash::CleanStaleCrashes]")));
+
+  // ??- sequence is a c++ trigraph corresponding to a ~. Escape it.
+  const TCHAR kWildCards[] = _T("???????\?-???\?-???\?-???\?-????????????.dmp");
+  std::vector<CString> crash_files;
+  HRESULT hr = File::GetWildcards(crash_dir_, kWildCards, &crash_files);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  time64 now = GetCurrent100NSTime();
+  for (size_t i = 0; i != crash_files.size(); ++i) {
+    CORE_LOG(L3, (_T("[found crash file][%s]"), crash_files[i]));
+    FILETIME creation_time = {0};
+    if (SUCCEEDED(File::GetFileTime(crash_files[i],
+                                    &creation_time,
+                                    NULL,
+                                    NULL))) {
+      double time_diff =
+          static_cast<double>(now - FileTimeToTime64(creation_time));
+      if (abs(time_diff) >= kDaysTo100ns) {
+        VERIFY1(::DeleteFile(crash_files[i]));
+      }
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT Crash::Report(bool can_upload_in_process,
+                      const CString& crash_filename,
+                      const CString& custom_info_filename,
+                      const CString& lang) {
+  const bool is_out_of_process = !custom_info_filename.IsEmpty();
+  HRESULT hr = S_OK;
+  if (is_out_of_process) {
+    hr = ReportProductCrash(true, crash_filename, custom_info_filename, lang);
+    ::DeleteFile(custom_info_filename);
+  } else {
+    hr = ReportGoogleUpdateCrash(can_upload_in_process,
+                                 crash_filename,
+                                 custom_info_filename,
+                                 lang);
+  }
+  ::DeleteFile(crash_filename);
+  CleanStaleCrashes();
+  return hr;
+}
+
+HRESULT Crash::ReportGoogleUpdateCrash(bool can_upload,
+                                       const CString& crash_filename,
+                                       const CString& custom_info_filename,
+                                       const CString& lang) {
+  OPT_LOG(L1, (_T("[Crash::ReportGoogleUpdateCrash]")));
+
+  UNREFERENCED_PARAMETER(custom_info_filename);
+
+  CString guid = is_machine_ ?
+                 goopdate_utils::GetPersistentMachineId() :
+                 goopdate_utils::GetPersistentUserId(USER_KEY_NAME);
+
+  // If someone has set a guid then use it instead of the user or the
+  // machine id. This is usually the case of a unit test where for the
+  // sake of aggregating the crashes we use the same guid.
+  if (!guid_.IsEmpty()) {
+    guid = guid_;
+  }
+
+  // Build the map of additional parameters to report along with the crash.
+  CString ver(GetVersionString() + version_postfix_);
+
+  ParameterMap parameters;
+  parameters[_T("prod")] = _T("Update2");
+  parameters[_T("ver")]  = ver;
+  parameters[_T("guid")] = guid;
+  parameters[_T("lang")] = lang;
+
+  CString event_text;
+  event_text.Format(
+      _T("Google Update has encountered a fatal error.\r\n")
+      _T("ver=%s;lang=%s;id=%s;is_machine=%d;upload=%d;minidump=%s"),
+      ver, lang, guid, is_machine_, can_upload ? 1 : 0, crash_filename);
+  VERIFY1(SUCCEEDED(Crash::Log(EVENTLOG_ERROR_TYPE,
+                               kCrashReportEventId,
+                               kAppName,
+                               event_text)));
+
+  ++metric_crashes_total;
+
+  CString report_id;
+  return DoSendCrashReport(can_upload,
+                           false,             // Google Update crash.
+                           crash_filename,
+                           parameters,
+                           &report_id);
+}
+
+HRESULT Crash::ReportProductCrash(bool can_upload,
+                                  const CString& crash_filename,
+                                  const CString& custom_info_filename,
+                                  const CString& lang) {
+  OPT_LOG(L1, (_T("[Crash::ReportProductCrash]")));
+
+  UNREFERENCED_PARAMETER(lang);
+
+  // All product crashes must be uploaded.
+  ASSERT1(can_upload);
+
+  // Count the number of crashes the sender was requested to handle.
+  ++metric_oop_crashes_total;
+
+  std::map<CString, CString> parameters_temp;
+  HRESULT hr = goopdate_utils::ReadNameValuePairsFromFile(
+      custom_info_filename,
+      kCustomClientInfoGroup,
+      &parameters_temp);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ParameterMap parameters;
+  std::map<CString, CString>::const_iterator iter;
+  for (iter = parameters_temp.begin(); iter != parameters_temp.end(); ++iter) {
+    parameters[iter->first.GetString()] = iter->second.GetString();
+  }
+
+  CString report_id;
+  return hr = DoSendCrashReport(can_upload,
+                                true,                  // Out of process crash.
+                                crash_filename,
+                                parameters,
+                                &report_id);
+}
+
+void __stdcall Crash::EBHandler(EXCEPTION_POINTERS* ptrs) {
+  if (exception_handler_) {
+    exception_handler_->WriteMinidumpForException(ptrs);
+  }
+}
+
+HRESULT Crash::GetExceptionInfo(const CString& crash_filename,
+                                MINIDUMP_EXCEPTION* ex_info) {
+  ASSERT1(ex_info);
+  ASSERT1(!crash_filename.IsEmpty());
+
+  // Dynamically link with the dbghelp to avoid runtime resource bloat.
+  scoped_library dbghelp(::LoadLibrary(_T("dbghelp.dll")));
+  if (!dbghelp) {
+    return HRESULTFromLastError();
+  }
+
+  typedef BOOL (WINAPI *MiniDumpReadDumpStreamFun)(void* base_of_dump,
+                                                   ULONG stream_number,
+                                                   MINIDUMP_DIRECTORY* dir,
+                                                   void** stream_pointer,
+                                                   ULONG* stream_size);
+
+  MiniDumpReadDumpStreamFun minidump_read_dump_stream =
+      reinterpret_cast<MiniDumpReadDumpStreamFun>(::GetProcAddress(get(dbghelp),
+                                                  "MiniDumpReadDumpStream"));
+  ASSERT1(minidump_read_dump_stream);
+  if (!minidump_read_dump_stream) {
+    return HRESULTFromLastError();
+  }
+
+  // The minidump file must be mapped in memory before reading the streams.
+  scoped_hfile file(::CreateFile(crash_filename,
+                                 GENERIC_READ,
+                                 FILE_SHARE_READ,
+                                 NULL,
+                                 OPEN_EXISTING,
+                                 FILE_ATTRIBUTE_READONLY,
+                                 NULL));
+  ASSERT1(file);
+  if (!file) {
+    return HRESULTFromLastError();
+  }
+  scoped_file_mapping file_mapping(::CreateFileMapping(get(file),
+                                                       NULL,
+                                                       PAGE_READONLY,
+                                                       0,
+                                                       0,
+                                                       NULL));
+  if (!file_mapping) {
+    return HRESULTFromLastError();
+  }
+  scoped_file_view base_of_dump(::MapViewOfFile(get(file_mapping),
+                                                FILE_MAP_READ,
+                                                0,
+                                                0,
+                                                0));
+  if (!base_of_dump) {
+    return HRESULTFromLastError();
+  }
+
+  // Read the exception stream and pick up the exception record.
+  MINIDUMP_DIRECTORY minidump_directory = {0};
+  void* stream_pointer = NULL;
+  ULONG stream_size = 0;
+  bool result = !!(*minidump_read_dump_stream)(get(base_of_dump),
+                                               ExceptionStream,
+                                               &minidump_directory,
+                                               &stream_pointer,
+                                               &stream_size);
+  if (!result) {
+    return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+  }
+  MINIDUMP_EXCEPTION_STREAM* exception_stream =
+      static_cast<MINIDUMP_EXCEPTION_STREAM*>(stream_pointer);
+  ASSERT1(stream_pointer);
+  ASSERT1(stream_size);
+
+  *ex_info = exception_stream->ExceptionRecord;
+  return S_OK;
+}
+
+bool Crash::IsInteractive() {
+  bool result = false;
+  ::EnumWindows(&Crash::EnumWindowsCallback, reinterpret_cast<LPARAM>(&result));
+  return result;
+}
+
+// Finds if the given window is in the current process.
+BOOL CALLBACK Crash::EnumWindowsCallback(HWND hwnd, LPARAM param) {
+  DWORD pid = 0;
+  ::GetWindowThreadProcessId(hwnd, &pid);
+  if (::IsWindowVisible(hwnd) && pid == ::GetCurrentProcessId() && param) {
+    *reinterpret_cast<bool*>(param) = true;
+    return false;
+  }
+  return true;
+}
+
+HRESULT Crash::InitializeCrashDir() {
+  crash_dir_.Empty();
+  ConfigManager* cm = ConfigManager::Instance();
+  CString dir = is_machine_ ? cm->GetMachineCrashReportsDir() :
+                              cm->GetUserCrashReportsDir();
+
+  if (is_machine_ && !dir.IsEmpty()) {
+    HRESULT hr = InitializeDirSecurity(&dir);
+    if (FAILED(hr)) {
+      CORE_LOG(LW, (_T("[failed to initialize crash dir security][0x%x]"), hr));
+      ::RemoveDirectory(dir);
+    }
+  }
+
+  // Use the temporary directory of the process if the crash directory can't be
+  // initialized for any reason. Users can't read files in other users'
+  // temporary directories so the temp dir is good option to still have
+  // crash handling.
+  if (dir.IsEmpty()) {
+    dir = app_util::GetTempDir();
+  }
+
+  if (dir.IsEmpty()) {
+    return GOOPDATE_E_CRASH_NO_DIR;
+  }
+
+  crash_dir_ = dir;
+  return S_OK;
+}
+
+HRESULT Crash::InitializeDirSecurity(CString* dir) {
+  ASSERT1(dir);
+
+  // Users can only read permissions on the crash dir.
+  CDacl dacl;
+  const uint8 kAceFlags = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
+  if (!dacl.AddAllowedAce(Sids::System(), GENERIC_ALL, kAceFlags) ||
+      !dacl.AddAllowedAce(Sids::Admins(), GENERIC_ALL, kAceFlags) ||
+      !dacl.AddAllowedAce(Sids::Users(), READ_CONTROL, kAceFlags)) {
+    return GOOPDATE_E_CRASH_SECURITY_FAILED;
+  }
+
+  SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION |
+                            PROTECTED_DACL_SECURITY_INFORMATION;
+  DWORD error = ::SetNamedSecurityInfo(dir->GetBuffer(),
+                                       SE_FILE_OBJECT,
+                                       si,
+                                       NULL,
+                                       NULL,
+                                       const_cast<ACL*>(dacl.GetPACL()),
+                                       NULL);
+  if (error != ERROR_SUCCESS) {
+    return HRESULT_FROM_WIN32(error);
+  }
+  return S_OK;
+}
+
+// Checks for the presence of an environment variable. We are not interested
+// in the value of the variable but only in its presence.
+HRESULT Crash::IsCrashReportProcess(bool* is_crash_report_process) {
+  ASSERT1(is_crash_report_process);
+  if (::GetEnvironmentVariable(kNoCrashHandlerEnvVariableName, NULL, 0)) {
+    *is_crash_report_process = true;
+    return S_OK;
+  } else {
+    DWORD error(::GetLastError());
+    *is_crash_report_process = false;
+    return error == ERROR_ENVVAR_NOT_FOUND ? S_OK : HRESULT_FROM_WIN32(error);
+  }
+}
+
+HRESULT Crash::Log(uint16 type,
+                   uint32 id,
+                   const TCHAR* source,
+                   const TCHAR* description) {
+  ASSERT1(source);
+  ASSERT1(description);
+  return EventLogger::ReportEvent(source,
+                                  type,
+                                  0,            // Category.
+                                  id,
+                                  1,            // Number of strings.
+                                  &description,
+                                  0,            // Raw data size.
+                                  NULL);        // Raw data.
+}
+
+CString Crash::GetProductName(const ParameterMap& parameters) {
+  // The crash is logged using the value of 'prod' if available or
+  // a default constant string otherwise.
+  CString product_name;
+  ParameterMap::const_iterator it = parameters.find(_T("prod"));
+  const bool is_found = it != parameters.end() && !it->second.empty();
+  return is_found ? it->second.c_str() : kDefaultProductName;
+}
+
+void Crash::UpdateCrashUploadMetrics(bool is_out_of_process, HRESULT hr) {
+  switch (hr) {
+    case S_OK:
+      if (is_out_of_process) {
+        ++metric_oop_crashes_uploaded;
+      } else {
+        ++metric_crashes_uploaded;
+      }
+      break;
+
+    case E_FAIL:
+      if (is_out_of_process) {
+        ++metric_oop_crashes_failed;
+      } else {
+        ++metric_crashes_failed;
+      }
+      break;
+
+    case GOOPDATE_E_CRASH_THROTTLED:
+      if (is_out_of_process) {
+        ++metric_oop_crashes_throttled;
+      } else {
+        ++metric_crashes_throttled;
+      }
+      break;
+
+    case GOOPDATE_E_CRASH_REJECTED:
+      if (is_out_of_process) {
+        ++metric_oop_crashes_rejected;
+      } else {
+        ++metric_crashes_rejected;
+      }
+      break;
+
+    default:
+      ASSERT1(false);
+      break;
+  }
+}
+
+int Crash::CrashNow() {
+#ifdef DEBUG
+  CORE_LOG(LEVEL_ERROR, (_T("[Crash::CrashNow]")));
+  int foo = 10;
+  int bar = foo - 10;
+  int baz = foo / bar;
+  return baz;
+#else
+  return 0;
+#endif
+}
+
+bool Crash::BuildPipeSecurityAttributes(CSecurityAttributes* sa) {
+  ASSERT1(sa);
+
+  CDacl dacl;
+  CAccessToken current_token;
+  if (!current_token.GetEffectiveToken(TOKEN_QUERY)) {
+    OPT_LOG(LE, (_T("[Failed to get current thread token]")));
+    return false;
+  }
+
+  if (!current_token.GetDefaultDacl(&dacl)) {
+    OPT_LOG(LE, (_T("[Failed to get default DACL]")));
+    return false;
+  }
+
+  if (!dacl.AddAllowedAce(ATL::Sids::Users(), kPipeAccessMask)) {
+    OPT_LOG(LE, (_T("[Failed to setup pipe security]")));
+    return false;
+  }
+
+  if (!dacl.AddDeniedAce(ATL::Sids::Network(), FILE_ALL_ACCESS)) {
+    OPT_LOG(LE, (_T("[Failed to setup pipe security]")));
+    return false;
+  }
+
+  ATL::CSecurityDesc sd;
+  sd.SetDacl(dacl);
+  sa->Set(sd);
+
+#ifdef _DEBUG
+  // Print SDDL for debugging.
+  CString sddl;
+  sd.ToString(&sddl);
+  CORE_LOG(L1, (_T("[Pipe security SDDL][%s]"), sddl));
+#endif
+
+  return true;
+}
+
+bool Crash::BuildCrashDirSecurityAttributes(CSecurityAttributes* sa) {
+  ASSERT1(sa);
+
+  CDacl dacl;
+  CAccessToken current_token;
+
+  if (!current_token.GetEffectiveToken(TOKEN_QUERY)) {
+    OPT_LOG(LE, (_T("[Failed to get current thread token]")));
+    return false;
+  }
+
+  if (!current_token.GetDefaultDacl(&dacl)) {
+    OPT_LOG(LE, (_T("[Failed to get default DACL]")));
+    return false;
+  }
+
+  CSecurityDesc sd;
+  sd.SetDacl(dacl);
+  // Prevent the security settings on the parent folder of CrashReports folder
+  // from being inherited by children of CrashReports folder.
+  sd.SetControl(SE_DACL_PROTECTED, SE_DACL_PROTECTED);
+  sa->Set(sd);
+
+#ifdef _DEBUG
+  // Print SDDL for debugging.
+  CString sddl;
+  sd.ToString(&sddl);
+  CORE_LOG(L1, (_T("[Folder security SDDL][%s]"), sddl));
+#endif
+
+  return true;
+}
+
+HRESULT Crash::StartServer() {
+  CORE_LOG(L1, (_T("[Crash::StartServer]")));
+  ++metric_crash_start_server_total;
+
+  std::wstring dump_path(crash_dir_);
+
+  // Append the current user's sid to the pipe name so that machine and
+  // user instances of the crash server open different pipes.
+  CString user_sid;
+  HRESULT hr = user_info::GetCurrentUser(NULL, NULL, &user_sid);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Failed to get SID for current user][0x%08x]"), hr));
+    return hr;
+  }
+  CString pipe_name(kPipeNamePrefix);
+  pipe_name.AppendFormat(_T("\\%s"), user_sid);
+
+  CSecurityAttributes pipe_sec_attrs;
+
+  // If running as machine, use custom security attributes on the pipe to
+  // allow all users on the local machine to connect to it.
+  // If running as user, the default security descriptor for the
+  // pipe grants full control to the system account, administrators,
+  // and the creator owner. However, when running elevated, the creator
+  // owner is not given full rights. In this case, only elevated users can
+  // connect to the pipe. This is not the desired behavior.
+  if (is_machine_ && !BuildPipeSecurityAttributes(&pipe_sec_attrs)) {
+    return GOOPDATE_E_CRASH_SECURITY_FAILED;
+  }
+
+  scoped_ptr<CrashGenerationServer> crash_server(
+      new CrashGenerationServer(std::wstring(pipe_name),
+                                &pipe_sec_attrs,
+                                ClientConnectedCallback, NULL,
+                                ClientCrashedCallback, NULL,
+                                ClientExitedCallback, NULL,
+                                true, &dump_path));
+
+  if (!crash_server->Start()) {
+    CORE_LOG(LE, (_T("[CrashServer::Start failed]")));
+    return GOOPDATE_E_CRASH_START_SERVER_FAILED;
+  }
+
+  crash_server_ = crash_server.release();
+
+  ++metric_crash_start_server_succeeded;
+  return S_OK;
+}
+
+void Crash::StopServer() {
+  CORE_LOG(L1, (_T("[Crash::StopServer]")));
+  delete crash_server_;
+  crash_server_ = NULL;
+}
+
+
+void _cdecl Crash::ClientConnectedCallback(void* context,
+                                           const ClientInfo* client_info) {
+  ASSERT1(!context);
+  ASSERT1(client_info);
+  UNREFERENCED_PARAMETER(context);
+  OPT_LOG(L1, (_T("[Client connected][%d]"), client_info->pid()));
+}
+
+void _cdecl Crash::ClientCrashedCallback(void* context,
+                                         const ClientInfo* client_info,
+                                         const std::wstring* dump_path) {
+  ASSERT1(!context);
+  ASSERT1(client_info);
+  UNREFERENCED_PARAMETER(context);
+  OPT_LOG(L1, (_T("[Client crashed][%d]"), client_info->pid()));
+
+  CString crash_filename(dump_path ? dump_path->c_str() : NULL);
+  HRESULT hr = Crash::CrashHandler(is_machine_, *client_info, crash_filename);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[CrashHandler failed][0x%08x]"), hr));
+  }
+}
+
+void _cdecl Crash::ClientExitedCallback(void* context,
+                                        const ClientInfo* client_info) {
+  ASSERT1(!context);
+  ASSERT1(client_info);
+  UNREFERENCED_PARAMETER(context);
+  OPT_LOG(L1, (_T("[Client exited][%d]"), client_info->pid()));
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/crash.h b/goopdate/crash.h
index beb6390..404309b 100644
--- a/goopdate/crash.h
+++ b/goopdate/crash.h
@@ -1,281 +1,281 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_CRASH_H__

-#define OMAHA_GOOPDATE_CRASH_H__

-

-#include <windows.h>

-#include <dbghelp.h>

-#include <atlsecurity.h>

-#include <atlstr.h>

-#include <map>

-#include "base/basictypes.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "third_party/gtest/include/gtest/gtest_prod.h"

-#include "third_party/breakpad/src/client/windows/crash_generation/client_info.h"

-#include "third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.h"

-#include "third_party/breakpad/src/client/windows/handler/exception_handler.h"

-

-namespace omaha {

-

-// Annotates the version reported along with the crash.

-const TCHAR* const kCrashVersionPostfixString =

-  _T("")

-#if !OFFICIAL_BUILD

-  _T(".private")

-#endif

-#if DEBUG

-  _T(".debug")

-#endif

-#if UNITTEST

-  _T(".ut")

-#endif

-;  // NOLINT

-

-// Official builds can only send a few crashes per day. Debug builds including

-// all build modes for unit tests send unlimited number of crashes.

-const int kCrashReportMaxReportsPerDay =

-#if OFFICIAL_BUILD && !defined(UNITTEST)

-                                         5;

-#else

-                                         0x7fffffff;

-#endif

-

-const TCHAR* const kNoCrashHandlerEnvVariableName =

-    _T("GOOGLE_UPDATE_NO_CRASH_HANDLER");

-

-// TODO(omaha): refactor so this is not a static class.

-// TODO(omaha): rename class name to better indicate its funtionality.

-class Crash {

- public:

-  typedef std::map<std::wstring, std::wstring> ParameterMap;

-

-  // Installs and uninstalls Breakpad exception handler. Calling the

-  // functions from DllMain results in undefined behavior, including

-  // deadlocks.

-  static HRESULT InstallCrashHandler(bool is_machine);

-  static void UninstallCrashHandler();

-

-  // Starts the server to listen for out-of-process crashes.

-  static HRESULT StartServer();

-

-  // Stops the crash server.

-  static void StopServer();

-

-  // Generates a divide by zero to trigger Breakpad dump in non-ship builds.

-  static int CrashNow();

-

-  // Handles out-of-process crash requests.

-  static HRESULT CrashHandler(bool is_machine,

-                              const google_breakpad::ClientInfo& client_info,

-                              const CString& crash_filename);

-

-  // Reports a crash, uploads it is out of process or can_upload_in_process is

-  // true, saves a copy of the crash, and deletes the crash file.

-  static HRESULT Report(bool can_upload_in_process,

-                        const CString& crash_filename,

-                        const CString& custom_info_filename,

-                        const CString& lang);

-

-  // Sets a version string which is appended to the 'ver' parameter sent

-  // with the crash report.

-  static void set_version_postfix(const TCHAR* version_postfix) {

-    version_postfix_ = version_postfix;

-  }

-

-  // Sets the guid to be reported. If not set, it uses the machine/user guid.

-  static void set_guid(const TCHAR* guid) { guid_ = guid; }

-

-  // Sets how many reports can be sent until the crash report sender starts

-  // rejecting and discarding crashes.

-  static void set_max_reports_per_day(int max_reports_per_day) {

-    max_reports_per_day_ = max_reports_per_day;

-  }

-

-  static void set_crash_report_url(const TCHAR* crash_report_url) {

-    crash_report_url_ = crash_report_url;

-  }

-

-  static bool is_machine() { return is_machine_; }

-

- private:

-

-  static HRESULT Initialize(bool is_machine);

-

-  // Reports a crash of Google Update. Does not delete the crash file.

-  static HRESULT ReportGoogleUpdateCrash(bool can_upload,

-                                         const CString& crash_filename,

-                                         const CString& custom_info_filename,

-                                         const CString& lang);

-

-  // Reports an out-of-process crash on behalf of another product. Does not

-  // delete the crash file.

-  static HRESULT ReportProductCrash(bool can_upload,

-                                    const CString& crash_filename,

-                                    const CString& custom_info_filename,

-                                    const CString& lang);

-

-  // Initializes the crash directory. Creates the directory if it does not

-  // exist.

-  static HRESULT InitializeCrashDir();

-

-  static HRESULT InitializeDirSecurity(CString* dir);

-

-  // Returns true if the current process is reporting an exception.

-  static HRESULT IsCrashReportProcess(bool* is_crash_report_process);

-

-  // Logs an entry in the Windows Event Log for the specified source.

-  static HRESULT Log(uint16 type,

-                     uint32 id,

-                     const TCHAR* source,

-                     const TCHAR* description);

-

-  // Starts the sender process with the environment variables setup such that

-  // the sender process doesn't register crash filter to avoid potential

-  // recursive crashes problem.

-  static HRESULT StartSenderWithCommandLine(CString* cmd_line);

-

-  // Creates a text file that contains name/value pairs of custom information.

-  // The text file is created in the same directory as the given dump file, but

-  // with a .txt extension. Stores the path of the text file created in the

-  // custom_info_filepath parameter.

-  // TODO(omaha): Move this functionality to breakpad. All the information

-  // needed to write custom information file is known when the dump is generated

-  // and hence breakpad could as easily create the text file.

-  static HRESULT CreateCustomInfoFile(

-      const CString& dump_file,

-      const google_breakpad::CustomClientInfo& client_info,

-      CString* custom_info_filepath);

-

-  // Sends a crash report. If sent successfully, report_id contains the

-  // report id generated by the crash server.

-  static HRESULT DoSendCrashReport(bool can_upload,

-                                   bool is_out_of_process,

-                                   const CString& crash_filename,

-                                   const ParameterMap& parameters,

-                                   CString* report_id);

-

-  // Callback function to run after the minidump has been written.

-  static bool MinidumpCallback(const wchar_t* dump_path,

-                               const wchar_t* minidump_id,

-                               void* context,

-                               EXCEPTION_POINTERS* exinfo,

-                               MDRawAssertionInfo* assertion,

-                               bool succeeded);

-

-  // Returns true if the crash has happened in an Omaha process which

-  // has a top level window up.

-  static bool IsInteractive();

-

-  // Returns the "prod" product name if found in the map or a default,

-  // constant string otherwise.

-  static CString GetProductName(const ParameterMap& parameters);

-

-  // Updates the crash metrics after uploading the crash.

-  static void UpdateCrashUploadMetrics(bool is_out_of_process, HRESULT hr);

-

-  // Uploads the crash, logs the result of the crash upload, and updates

-  // the crash metrics.

-  static HRESULT UploadCrash(bool is_out_of_process,

-                             const CString& crash_filename,

-                             const ParameterMap& parameters,

-                             CString* report_id);

-

-  // Creates a back up copy of the current crash for future debugging use cases.

-  static HRESULT SaveLastCrash(const CString& crash_filename,

-                               const CString& product_name);

-

-  // Cleans up stale crashes from the crash dir. Curently, crashes older than

-  // 1 day are deleted.

-  static HRESULT CleanStaleCrashes();

-

-  // Retrieves the minidump exception information from the minidump file.

-  static HRESULT GetExceptionInfo(const CString& crash_filename,

-                                  MINIDUMP_EXCEPTION* ex_info);

-

-  // Receives a top-level window and sets the param to true if the window

-  // belongs to this process.

-  static BOOL CALLBACK EnumWindowsCallback(HWND hwnd, LPARAM param);

-

-  // Callback function to run when an exception is passing through an

-  // exception barrier.

-  static void __stdcall EBHandler(EXCEPTION_POINTERS* ptrs);

-

-  // Callback function to run when a new client connects to the crash server.

-  static void _cdecl ClientConnectedCallback(

-      void* context,

-      const google_breakpad::ClientInfo* client_info);

-

-  // Callback function to run when a client signals a crash to the crash server.

-  static void _cdecl ClientCrashedCallback(

-      void* context,

-      const google_breakpad::ClientInfo* client_info,

-      const std::wstring* dump_path);

-

-  // Callback function to run when a client disconnects from the crash server.

-  static void _cdecl ClientExitedCallback(

-      void* context,

-      const google_breakpad::ClientInfo* client_info);

-

-  // Builds a security attribute to allow all users to connect to the

-  // crash server named pipe, when the server is running as system.

-  static bool BuildPipeSecurityAttributes(CSecurityAttributes* sa);

-

-  // Builds a security attribute to allow full control for the Local System

-  // account and read/execute for the Administrators group, when the crash

-  // handler is running as Local System.

-  static bool BuildCrashDirSecurityAttributes(CSecurityAttributes* sa);

-

-  // TODO(omaha): fix static instances of class type not allowed.

-  static CString module_filename_;

-  static CString Crash::crash_dir_;

-  static CString Crash::checkpoint_file_;

-  static CString version_postfix_;

-  static CString guid_;

-  static CString crash_report_url_;

-  static int max_reports_per_day_;

-  static google_breakpad::ExceptionHandler* exception_handler_;

-  static google_breakpad::CrashGenerationServer* crash_server_;

-

-  static bool is_machine_;

-

-  static const int kCrashReportAttempts       = 3;

-  static const int kCrashReportResendPeriodMs = 1 * 60 * 60 * 1000;  // 1 hour.

-

-  // Default string to report out-of-process crashes with in the case

-  // 'prod' information is not available.

-  static const TCHAR* const kDefaultProductName;

-

-  friend class CrashTest;

-

-  FRIEND_TEST(CrashTest, CleanStaleCrashes);

-  FRIEND_TEST(CrashTest, CreateCustomInfoFile);

-  FRIEND_TEST(CrashTest, GetExceptionInfo);

-  FRIEND_TEST(CrashTest, GetProductName);

-  FRIEND_TEST(CrashTest, InstallCrashHandler);

-  FRIEND_TEST(CrashTest, IsCrashReportProcess);

-  FRIEND_TEST(CrashTest, Report_OmahaCrash);

-  FRIEND_TEST(CrashTest, Report_ProductCrash);

-  FRIEND_TEST(CrashTest, SaveLastCrash);

-  FRIEND_TEST(CrashTest, StartServer);

-  FRIEND_TEST(CrashTest, WriteMinidump);

-

-  DISALLOW_IMPLICIT_CONSTRUCTORS(Crash);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_CRASH_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_CRASH_H__
+#define OMAHA_GOOPDATE_CRASH_H__
+
+#include <windows.h>
+#include <dbghelp.h>
+#include <atlsecurity.h>
+#include <atlstr.h>
+#include <map>
+#include "base/basictypes.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "third_party/gtest/include/gtest/gtest_prod.h"
+#include "third_party/breakpad/src/client/windows/crash_generation/client_info.h"
+#include "third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.h"
+#include "third_party/breakpad/src/client/windows/handler/exception_handler.h"
+
+namespace omaha {
+
+// Annotates the version reported along with the crash.
+const TCHAR* const kCrashVersionPostfixString =
+  _T("")
+#if !OFFICIAL_BUILD
+  _T(".private")
+#endif
+#if DEBUG
+  _T(".debug")
+#endif
+#if UNITTEST
+  _T(".ut")
+#endif
+;  // NOLINT
+
+// Official builds can only send a few crashes per day. Debug builds including
+// all build modes for unit tests send unlimited number of crashes.
+const int kCrashReportMaxReportsPerDay =
+#if OFFICIAL_BUILD && !defined(UNITTEST)
+                                         5;
+#else
+                                         0x7fffffff;
+#endif
+
+const TCHAR* const kNoCrashHandlerEnvVariableName =
+    _T("GOOGLE_UPDATE_NO_CRASH_HANDLER");
+
+// TODO(omaha): refactor so this is not a static class.
+// TODO(omaha): rename class name to better indicate its funtionality.
+class Crash {
+ public:
+  typedef std::map<std::wstring, std::wstring> ParameterMap;
+
+  // Installs and uninstalls Breakpad exception handler. Calling the
+  // functions from DllMain results in undefined behavior, including
+  // deadlocks.
+  static HRESULT InstallCrashHandler(bool is_machine);
+  static void UninstallCrashHandler();
+
+  // Starts the server to listen for out-of-process crashes.
+  static HRESULT StartServer();
+
+  // Stops the crash server.
+  static void StopServer();
+
+  // Generates a divide by zero to trigger Breakpad dump in non-ship builds.
+  static int CrashNow();
+
+  // Handles out-of-process crash requests.
+  static HRESULT CrashHandler(bool is_machine,
+                              const google_breakpad::ClientInfo& client_info,
+                              const CString& crash_filename);
+
+  // Reports a crash, uploads it is out of process or can_upload_in_process is
+  // true, saves a copy of the crash, and deletes the crash file.
+  static HRESULT Report(bool can_upload_in_process,
+                        const CString& crash_filename,
+                        const CString& custom_info_filename,
+                        const CString& lang);
+
+  // Sets a version string which is appended to the 'ver' parameter sent
+  // with the crash report.
+  static void set_version_postfix(const TCHAR* version_postfix) {
+    version_postfix_ = version_postfix;
+  }
+
+  // Sets the guid to be reported. If not set, it uses the machine/user guid.
+  static void set_guid(const TCHAR* guid) { guid_ = guid; }
+
+  // Sets how many reports can be sent until the crash report sender starts
+  // rejecting and discarding crashes.
+  static void set_max_reports_per_day(int max_reports_per_day) {
+    max_reports_per_day_ = max_reports_per_day;
+  }
+
+  static void set_crash_report_url(const TCHAR* crash_report_url) {
+    crash_report_url_ = crash_report_url;
+  }
+
+  static bool is_machine() { return is_machine_; }
+
+ private:
+
+  static HRESULT Initialize(bool is_machine);
+
+  // Reports a crash of Google Update. Does not delete the crash file.
+  static HRESULT ReportGoogleUpdateCrash(bool can_upload,
+                                         const CString& crash_filename,
+                                         const CString& custom_info_filename,
+                                         const CString& lang);
+
+  // Reports an out-of-process crash on behalf of another product. Does not
+  // delete the crash file.
+  static HRESULT ReportProductCrash(bool can_upload,
+                                    const CString& crash_filename,
+                                    const CString& custom_info_filename,
+                                    const CString& lang);
+
+  // Initializes the crash directory. Creates the directory if it does not
+  // exist.
+  static HRESULT InitializeCrashDir();
+
+  static HRESULT InitializeDirSecurity(CString* dir);
+
+  // Returns true if the current process is reporting an exception.
+  static HRESULT IsCrashReportProcess(bool* is_crash_report_process);
+
+  // Logs an entry in the Windows Event Log for the specified source.
+  static HRESULT Log(uint16 type,
+                     uint32 id,
+                     const TCHAR* source,
+                     const TCHAR* description);
+
+  // Starts the sender process with the environment variables setup such that
+  // the sender process doesn't register crash filter to avoid potential
+  // recursive crashes problem.
+  static HRESULT StartSenderWithCommandLine(CString* cmd_line);
+
+  // Creates a text file that contains name/value pairs of custom information.
+  // The text file is created in the same directory as the given dump file, but
+  // with a .txt extension. Stores the path of the text file created in the
+  // custom_info_filepath parameter.
+  // TODO(omaha): Move this functionality to breakpad. All the information
+  // needed to write custom information file is known when the dump is generated
+  // and hence breakpad could as easily create the text file.
+  static HRESULT CreateCustomInfoFile(
+      const CString& dump_file,
+      const google_breakpad::CustomClientInfo& client_info,
+      CString* custom_info_filepath);
+
+  // Sends a crash report. If sent successfully, report_id contains the
+  // report id generated by the crash server.
+  static HRESULT DoSendCrashReport(bool can_upload,
+                                   bool is_out_of_process,
+                                   const CString& crash_filename,
+                                   const ParameterMap& parameters,
+                                   CString* report_id);
+
+  // Callback function to run after the minidump has been written.
+  static bool MinidumpCallback(const wchar_t* dump_path,
+                               const wchar_t* minidump_id,
+                               void* context,
+                               EXCEPTION_POINTERS* exinfo,
+                               MDRawAssertionInfo* assertion,
+                               bool succeeded);
+
+  // Returns true if the crash has happened in an Omaha process which
+  // has a top level window up.
+  static bool IsInteractive();
+
+  // Returns the "prod" product name if found in the map or a default,
+  // constant string otherwise.
+  static CString GetProductName(const ParameterMap& parameters);
+
+  // Updates the crash metrics after uploading the crash.
+  static void UpdateCrashUploadMetrics(bool is_out_of_process, HRESULT hr);
+
+  // Uploads the crash, logs the result of the crash upload, and updates
+  // the crash metrics.
+  static HRESULT UploadCrash(bool is_out_of_process,
+                             const CString& crash_filename,
+                             const ParameterMap& parameters,
+                             CString* report_id);
+
+  // Creates a back up copy of the current crash for future debugging use cases.
+  static HRESULT SaveLastCrash(const CString& crash_filename,
+                               const CString& product_name);
+
+  // Cleans up stale crashes from the crash dir. Curently, crashes older than
+  // 1 day are deleted.
+  static HRESULT CleanStaleCrashes();
+
+  // Retrieves the minidump exception information from the minidump file.
+  static HRESULT GetExceptionInfo(const CString& crash_filename,
+                                  MINIDUMP_EXCEPTION* ex_info);
+
+  // Receives a top-level window and sets the param to true if the window
+  // belongs to this process.
+  static BOOL CALLBACK EnumWindowsCallback(HWND hwnd, LPARAM param);
+
+  // Callback function to run when an exception is passing through an
+  // exception barrier.
+  static void __stdcall EBHandler(EXCEPTION_POINTERS* ptrs);
+
+  // Callback function to run when a new client connects to the crash server.
+  static void _cdecl ClientConnectedCallback(
+      void* context,
+      const google_breakpad::ClientInfo* client_info);
+
+  // Callback function to run when a client signals a crash to the crash server.
+  static void _cdecl ClientCrashedCallback(
+      void* context,
+      const google_breakpad::ClientInfo* client_info,
+      const std::wstring* dump_path);
+
+  // Callback function to run when a client disconnects from the crash server.
+  static void _cdecl ClientExitedCallback(
+      void* context,
+      const google_breakpad::ClientInfo* client_info);
+
+  // Builds a security attribute to allow all users to connect to the
+  // crash server named pipe, when the server is running as system.
+  static bool BuildPipeSecurityAttributes(CSecurityAttributes* sa);
+
+  // Builds a security attribute to allow full control for the Local System
+  // account and read/execute for the Administrators group, when the crash
+  // handler is running as Local System.
+  static bool BuildCrashDirSecurityAttributes(CSecurityAttributes* sa);
+
+  // TODO(omaha): fix static instances of class type not allowed.
+  static CString module_filename_;
+  static CString Crash::crash_dir_;
+  static CString Crash::checkpoint_file_;
+  static CString version_postfix_;
+  static CString guid_;
+  static CString crash_report_url_;
+  static int max_reports_per_day_;
+  static google_breakpad::ExceptionHandler* exception_handler_;
+  static google_breakpad::CrashGenerationServer* crash_server_;
+
+  static bool is_machine_;
+
+  static const int kCrashReportAttempts       = 3;
+  static const int kCrashReportResendPeriodMs = 1 * 60 * 60 * 1000;  // 1 hour.
+
+  // Default string to report out-of-process crashes with in the case
+  // 'prod' information is not available.
+  static const TCHAR* const kDefaultProductName;
+
+  friend class CrashTest;
+
+  FRIEND_TEST(CrashTest, CleanStaleCrashes);
+  FRIEND_TEST(CrashTest, CreateCustomInfoFile);
+  FRIEND_TEST(CrashTest, GetExceptionInfo);
+  FRIEND_TEST(CrashTest, GetProductName);
+  FRIEND_TEST(CrashTest, InstallCrashHandler);
+  FRIEND_TEST(CrashTest, IsCrashReportProcess);
+  FRIEND_TEST(CrashTest, Report_OmahaCrash);
+  FRIEND_TEST(CrashTest, Report_ProductCrash);
+  FRIEND_TEST(CrashTest, SaveLastCrash);
+  FRIEND_TEST(CrashTest, StartServer);
+  FRIEND_TEST(CrashTest, WriteMinidump);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Crash);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_CRASH_H__
+
diff --git a/goopdate/crash_unittest.cc b/goopdate/crash_unittest.cc
index 2beed63..f71fd20 100644
--- a/goopdate/crash_unittest.cc
+++ b/goopdate/crash_unittest.cc
@@ -1,298 +1,298 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <string>

-#include "omaha/goopdate/crash.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/file.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/time.h"

-#include "omaha/testing/unit_test.h"

-

-// TODO(omaha): Modify the tests to avoid writing files to the staging

-// directory, which should not be modified after building.

-

-using google_breakpad::ClientInfo;

-using google_breakpad::CustomClientInfo;

-using google_breakpad::CustomInfoEntry;

-using google_breakpad::ExceptionHandler;

-

-namespace omaha {

-

-class CrashTest : public testing::Test {

- protected:

-  // Initialize the crash reporting for the machine case. The user case is

-  // simpler and specific tests can reinitialize for the user case if needed.

-  virtual void SetUp() {

-    module_dir_ = app_util::GetModuleDirectory(NULL);

-    EXPECT_HRESULT_SUCCEEDED(Crash::Initialize(true));

-  }

-

-  virtual void TearDown() {

-    EXPECT_HRESULT_SUCCEEDED(DeleteDirectory(Crash::crash_dir_));

-  }

-

-  static void CallbackHelper(const wchar_t* dump_path,

-                             const wchar_t* minidump_id) {

-    CString crash_filename;

-    crash_filename.Format(_T("%s\\%s.dmp"), dump_path, minidump_id);

-    Crash::set_max_reports_per_day(omaha::kCrashReportMaxReportsPerDay);

-    Crash::set_version_postfix(omaha::kCrashVersionPostfixString);

-    Crash::set_guid(_T("UNIT_TEST"));

-    Crash::set_crash_report_url(kUrlCrashReport);

-    EXPECT_SUCCEEDED(Crash::Report(true, crash_filename, CString(), false));

-  }

-

-  static bool MinidumpCallback(const wchar_t* dump_path,

-                               const wchar_t* minidump_id,

-                               void* context,

-                               EXCEPTION_POINTERS*,

-                               MDRawAssertionInfo*,

-                               bool succeeded) {

-    EXPECT_TRUE(dump_path);

-    EXPECT_TRUE(minidump_id);

-    EXPECT_TRUE(!context);

-    EXPECT_SUCCEEDED(succeeded);

-

-    CallbackHelper(dump_path, minidump_id);

-    return true;

-  }

-

-  CString module_dir_;

-};

-

-TEST_F(CrashTest, CreateCustomInfoFile) {

-  CustomInfoEntry info_entry(_T("foo"), _T("bar"));

-  CustomClientInfo custom_client_info = {&info_entry, 1};

-

-  CString crash_filename, custom_info_filename;

-  crash_filename.Format(_T("%s\\%s"), module_dir_, _T("minidump.dmp"));

-  custom_info_filename.Format(_T("%s\\%s"), module_dir_, _T("minidump.txt"));

-

-  CString actual_custom_info_filepath;

-  EXPECT_SUCCEEDED(Crash::CreateCustomInfoFile(crash_filename,

-                                               custom_client_info,

-                                               &actual_custom_info_filepath));

-  EXPECT_STREQ(custom_info_filename, actual_custom_info_filepath);

-  EXPECT_TRUE(File::Exists(actual_custom_info_filepath));

-  EXPECT_TRUE(::DeleteFile(actual_custom_info_filepath));

-

-  // Tests an invalid file name.

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INVALID_NAME),

-            Crash::CreateCustomInfoFile(_T("C:\\\"minidump.dmp"),

-                                        custom_client_info,

-                                        &actual_custom_info_filepath));

-}

-

-// Tests sending an Omaha crash.

-TEST_F(CrashTest, Report_OmahaCrash) {

-  CString crash_filename, custom_info_filename;

-  crash_filename.Format(_T("%s\\%s"), module_dir_, _T("minidump.dmp"));

-

-  ::DeleteFile(crash_filename);

-

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            Crash::Report(true, crash_filename, _T(""), _T("")));

-

-  // Copy the minidump and the corresponding info file.

-  CString test_dir;

-  test_dir.Format(_T("%s\\unittest_support"), module_dir_);

-  ASSERT_SUCCEEDED(File::CopyWildcards(test_dir,          // From.

-                                       module_dir_,       // To.

-                                       _T("minidump.*"),

-                                       true));

-

-  ASSERT_TRUE(File::Exists(crash_filename));

-

-  ASSERT_SUCCEEDED(Crash::Report(true, crash_filename, _T(""), _T("")));

-

-  // The crash artifacts should be deleted after the crash is reported.

-  EXPECT_FALSE(File::Exists(crash_filename));

-}

-

-// Tests sending an out-of-process crash.

-// This test will write an entry with the source "Update2" in the Event Log.

-TEST_F(CrashTest, Report_ProductCrash) {

-  CString crash_filename, custom_info_filename;

-  crash_filename.Format(_T("%s\\%s"), module_dir_, _T("minidump.dmp"));

-  custom_info_filename.Format(_T("%s\\%s"), module_dir_, _T("minidump.txt"));

-

-  ::DeleteFile(crash_filename);

-  ::DeleteFile(custom_info_filename);

-

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            Crash::Report(true, crash_filename, custom_info_filename, _T("")));

-

-  // Copy the minidump and the corresponding info file.

-  CString test_dir;

-  test_dir.Format(_T("%s\\unittest_support"), module_dir_);

-  ASSERT_SUCCEEDED(File::CopyWildcards(test_dir,          // From.

-                                       module_dir_,       // To.

-                                       _T("minidump.*"),

-                                       true));

-

-  ASSERT_TRUE(File::Exists(crash_filename));

-  ASSERT_TRUE(File::Exists(custom_info_filename));

-

-  ASSERT_SUCCEEDED(Crash::Report(true, crash_filename,

-                                 custom_info_filename, _T("")));

-

-  // The crash artifacts should be deleted after the crash is reported.

-  EXPECT_FALSE(File::Exists(crash_filename));

-  EXPECT_FALSE(File::Exists(custom_info_filename));

-}

-

-// Tests generation of a minidump and uploading it to the staging server.

-TEST_F(CrashTest, WriteMinidump) {

-  ASSERT_TRUE(!Crash::crash_dir_.IsEmpty());

-  ASSERT_TRUE(ExceptionHandler::WriteMinidump(Crash::crash_dir_.GetString(),

-                                              &MinidumpCallback,

-                                              NULL));

-}

-

-// Tests the retrieval of the exception information from an existing minidump.

-TEST_F(CrashTest, GetExceptionInfo) {

-  const TCHAR kMiniDumpFilename[] = _T("minidump.dmp");

-  const uint32 kExceptionAddress  = 0x10001240;

-  const uint32 kExceptionCode     = 0xc0000005;

-

-  CString filename;

-  filename.AppendFormat(_T("%s\\unittest_support\\%s"),

-                        module_dir_, kMiniDumpFilename);

-  MINIDUMP_EXCEPTION ex_info = {0};

-  ASSERT_SUCCEEDED(Crash::GetExceptionInfo(filename, &ex_info));

-  EXPECT_EQ(ex_info.ExceptionAddress, kExceptionAddress);

-  EXPECT_EQ(ex_info.ExceptionCode, kExceptionCode);

-}

-

-TEST_F(CrashTest, IsCrashReportProcess) {

-  // Clear the environment variable.

-  ::SetEnvironmentVariable(kNoCrashHandlerEnvVariableName, NULL);

-

-  bool is_crash_report_process = false;

-  EXPECT_SUCCEEDED(Crash::IsCrashReportProcess(&is_crash_report_process));

-  EXPECT_FALSE(is_crash_report_process);

-

-  EXPECT_TRUE(::SetEnvironmentVariable(kNoCrashHandlerEnvVariableName,

-              _T("1")));

-  is_crash_report_process = false;

-  EXPECT_SUCCEEDED(Crash::IsCrashReportProcess(&is_crash_report_process));

-  EXPECT_TRUE(is_crash_report_process);

-

-  // Clear the environment variable.

-  EXPECT_TRUE(::SetEnvironmentVariable(kNoCrashHandlerEnvVariableName, NULL));

-}

-

-TEST_F(CrashTest, GetProductName) {

-  Crash::ParameterMap parameters;

-  EXPECT_STREQ(_T("Google Error Reporting"), Crash::GetProductName(parameters));

-

-  parameters[_T("prod")] = _T("Update2");

-  EXPECT_STREQ(_T("Update2"), Crash::GetProductName(parameters));

-}

-

-TEST_F(CrashTest, SaveLastCrash) {

-  // Copy a test file into the module directory to use as a crash file.

-  const TCHAR kMiniDumpFilename[] = _T("minidump.dmp");

-

-  CString test_file;    // The unit test support file.

-  CString crash_file;   // The crash file to be backed up.

-

-  test_file.AppendFormat(_T("%s\\unittest_support\\%s"),

-                         module_dir_, kMiniDumpFilename);

-  crash_file.AppendFormat(_T("%s\\%s"), Crash::crash_dir_, kMiniDumpFilename);

-  EXPECT_TRUE(File::Exists(test_file));

-  EXPECT_TRUE(::CopyFile(test_file, crash_file, false));

-  EXPECT_TRUE(File::Exists(crash_file));

-

-  EXPECT_HRESULT_SUCCEEDED(Crash::SaveLastCrash(crash_file, _T("test")));

-

-  CString saved_crash_file;  // The name of backup crash file.

-  saved_crash_file.AppendFormat(_T("%s\\test-last.dmp"), Crash::crash_dir_);

-  EXPECT_TRUE(File::Exists(saved_crash_file));

-

-  EXPECT_TRUE(::DeleteFile(saved_crash_file));

-}

-

-TEST_F(CrashTest, StartServer) {

-  // Terminate all processes to avoid conflicts on the crash services pipe.

-  TerminateAllGoogleUpdateProcesses();

-

-  EXPECT_HRESULT_SUCCEEDED(Crash::StartServer());

-

-  // Try opening the crash services pipe.

-  CString user_sid;

-  EXPECT_HRESULT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid));

-  CString pipe_name;

-  pipe_name.AppendFormat(_T("\\\\.\\pipe\\GoogleCrashServices\\%s"), user_sid);

-  scoped_pipe pipe_handle(::CreateFile(pipe_name,

-                                       GENERIC_READ | GENERIC_WRITE,

-                                       FILE_SHARE_READ | FILE_SHARE_WRITE,

-                                       NULL,

-                                       OPEN_EXISTING,

-                                       0,

-                                       NULL));

-  EXPECT_TRUE(pipe_handle);

-

-  Crash::StopServer();

-}

-

-TEST_F(CrashTest, CleanStaleCrashes) {

-  // Copy a test file into the module directory to use as a crash file.

-  const TCHAR kMiniDumpFilename[] = _T("minidump.dmp");

-

-  CString test_file;    // The unit test support file.

-  CString crash_file;   // The crash file to be backed up.

-

-  test_file.AppendFormat(_T("%s\\unittest_support\\%s"),

-                         module_dir_, kMiniDumpFilename);

-  crash_file.AppendFormat(_T("%s\\%s.dmp"),

-                          Crash::crash_dir_,

-                          _T("5695F1E0-95BD-4bc2-99C0-E9DCC0AC5274"));

-  EXPECT_TRUE(File::Exists(test_file));

-  EXPECT_TRUE(::CopyFile(test_file, crash_file, false));

-  EXPECT_TRUE(File::Exists(crash_file));

-

-  FILETIME time_created = {0};

-  time64 now = GetCurrent100NSTime();

-

-  // Create a time value 23 hours in the past. Expect the crash file remains.

-  Time64ToFileTime(now - 23 * kHoursTo100ns, &time_created);

-  EXPECT_HRESULT_SUCCEEDED(File::SetFileTime(crash_file, &time_created,

-                                             NULL, NULL));

-  Crash::CleanStaleCrashes();

-  EXPECT_TRUE(File::Exists(crash_file));

-

-  // Create a time value 25 hours in the past. Expect the crash file is deleted.

-  Time64ToFileTime(now - 25 * kHoursTo100ns, &time_created);

-  EXPECT_HRESULT_SUCCEEDED(File::SetFileTime(crash_file, &time_created,

-                                             NULL, NULL));

-  Crash::CleanStaleCrashes();

-  EXPECT_FALSE(File::Exists(crash_file));

-}

-

-// Installs and uninstalls the crash handler in the user case.

-TEST_F(CrashTest, InstallCrashHandler) {

-  EXPECT_HRESULT_SUCCEEDED(Crash::InstallCrashHandler(false));

-  Crash::UninstallCrashHandler();

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <string>
+#include "omaha/goopdate/crash.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/file.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/time.h"
+#include "omaha/testing/unit_test.h"
+
+// TODO(omaha): Modify the tests to avoid writing files to the staging
+// directory, which should not be modified after building.
+
+using google_breakpad::ClientInfo;
+using google_breakpad::CustomClientInfo;
+using google_breakpad::CustomInfoEntry;
+using google_breakpad::ExceptionHandler;
+
+namespace omaha {
+
+class CrashTest : public testing::Test {
+ protected:
+  // Initialize the crash reporting for the machine case. The user case is
+  // simpler and specific tests can reinitialize for the user case if needed.
+  virtual void SetUp() {
+    module_dir_ = app_util::GetModuleDirectory(NULL);
+    EXPECT_HRESULT_SUCCEEDED(Crash::Initialize(true));
+  }
+
+  virtual void TearDown() {
+    EXPECT_HRESULT_SUCCEEDED(DeleteDirectory(Crash::crash_dir_));
+  }
+
+  static void CallbackHelper(const wchar_t* dump_path,
+                             const wchar_t* minidump_id) {
+    CString crash_filename;
+    crash_filename.Format(_T("%s\\%s.dmp"), dump_path, minidump_id);
+    Crash::set_max_reports_per_day(omaha::kCrashReportMaxReportsPerDay);
+    Crash::set_version_postfix(omaha::kCrashVersionPostfixString);
+    Crash::set_guid(_T("UNIT_TEST"));
+    Crash::set_crash_report_url(kUrlCrashReport);
+    EXPECT_SUCCEEDED(Crash::Report(true, crash_filename, CString(), false));
+  }
+
+  static bool MinidumpCallback(const wchar_t* dump_path,
+                               const wchar_t* minidump_id,
+                               void* context,
+                               EXCEPTION_POINTERS*,
+                               MDRawAssertionInfo*,
+                               bool succeeded) {
+    EXPECT_TRUE(dump_path);
+    EXPECT_TRUE(minidump_id);
+    EXPECT_TRUE(!context);
+    EXPECT_SUCCEEDED(succeeded);
+
+    CallbackHelper(dump_path, minidump_id);
+    return true;
+  }
+
+  CString module_dir_;
+};
+
+TEST_F(CrashTest, CreateCustomInfoFile) {
+  CustomInfoEntry info_entry(_T("foo"), _T("bar"));
+  CustomClientInfo custom_client_info = {&info_entry, 1};
+
+  CString crash_filename, custom_info_filename;
+  crash_filename.Format(_T("%s\\%s"), module_dir_, _T("minidump.dmp"));
+  custom_info_filename.Format(_T("%s\\%s"), module_dir_, _T("minidump.txt"));
+
+  CString actual_custom_info_filepath;
+  EXPECT_SUCCEEDED(Crash::CreateCustomInfoFile(crash_filename,
+                                               custom_client_info,
+                                               &actual_custom_info_filepath));
+  EXPECT_STREQ(custom_info_filename, actual_custom_info_filepath);
+  EXPECT_TRUE(File::Exists(actual_custom_info_filepath));
+  EXPECT_TRUE(::DeleteFile(actual_custom_info_filepath));
+
+  // Tests an invalid file name.
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INVALID_NAME),
+            Crash::CreateCustomInfoFile(_T("C:\\\"minidump.dmp"),
+                                        custom_client_info,
+                                        &actual_custom_info_filepath));
+}
+
+// Tests sending an Omaha crash.
+TEST_F(CrashTest, Report_OmahaCrash) {
+  CString crash_filename, custom_info_filename;
+  crash_filename.Format(_T("%s\\%s"), module_dir_, _T("minidump.dmp"));
+
+  ::DeleteFile(crash_filename);
+
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            Crash::Report(true, crash_filename, _T(""), _T("")));
+
+  // Copy the minidump and the corresponding info file.
+  CString test_dir;
+  test_dir.Format(_T("%s\\unittest_support"), module_dir_);
+  ASSERT_SUCCEEDED(File::CopyWildcards(test_dir,          // From.
+                                       module_dir_,       // To.
+                                       _T("minidump.*"),
+                                       true));
+
+  ASSERT_TRUE(File::Exists(crash_filename));
+
+  ASSERT_SUCCEEDED(Crash::Report(true, crash_filename, _T(""), _T("")));
+
+  // The crash artifacts should be deleted after the crash is reported.
+  EXPECT_FALSE(File::Exists(crash_filename));
+}
+
+// Tests sending an out-of-process crash.
+// This test will write an entry with the source "Update2" in the Event Log.
+TEST_F(CrashTest, Report_ProductCrash) {
+  CString crash_filename, custom_info_filename;
+  crash_filename.Format(_T("%s\\%s"), module_dir_, _T("minidump.dmp"));
+  custom_info_filename.Format(_T("%s\\%s"), module_dir_, _T("minidump.txt"));
+
+  ::DeleteFile(crash_filename);
+  ::DeleteFile(custom_info_filename);
+
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            Crash::Report(true, crash_filename, custom_info_filename, _T("")));
+
+  // Copy the minidump and the corresponding info file.
+  CString test_dir;
+  test_dir.Format(_T("%s\\unittest_support"), module_dir_);
+  ASSERT_SUCCEEDED(File::CopyWildcards(test_dir,          // From.
+                                       module_dir_,       // To.
+                                       _T("minidump.*"),
+                                       true));
+
+  ASSERT_TRUE(File::Exists(crash_filename));
+  ASSERT_TRUE(File::Exists(custom_info_filename));
+
+  ASSERT_SUCCEEDED(Crash::Report(true, crash_filename,
+                                 custom_info_filename, _T("")));
+
+  // The crash artifacts should be deleted after the crash is reported.
+  EXPECT_FALSE(File::Exists(crash_filename));
+  EXPECT_FALSE(File::Exists(custom_info_filename));
+}
+
+// Tests generation of a minidump and uploading it to the staging server.
+TEST_F(CrashTest, WriteMinidump) {
+  ASSERT_TRUE(!Crash::crash_dir_.IsEmpty());
+  ASSERT_TRUE(ExceptionHandler::WriteMinidump(Crash::crash_dir_.GetString(),
+                                              &MinidumpCallback,
+                                              NULL));
+}
+
+// Tests the retrieval of the exception information from an existing minidump.
+TEST_F(CrashTest, GetExceptionInfo) {
+  const TCHAR kMiniDumpFilename[] = _T("minidump.dmp");
+  const uint32 kExceptionAddress  = 0x10001240;
+  const uint32 kExceptionCode     = 0xc0000005;
+
+  CString filename;
+  filename.AppendFormat(_T("%s\\unittest_support\\%s"),
+                        module_dir_, kMiniDumpFilename);
+  MINIDUMP_EXCEPTION ex_info = {0};
+  ASSERT_SUCCEEDED(Crash::GetExceptionInfo(filename, &ex_info));
+  EXPECT_EQ(ex_info.ExceptionAddress, kExceptionAddress);
+  EXPECT_EQ(ex_info.ExceptionCode, kExceptionCode);
+}
+
+TEST_F(CrashTest, IsCrashReportProcess) {
+  // Clear the environment variable.
+  ::SetEnvironmentVariable(kNoCrashHandlerEnvVariableName, NULL);
+
+  bool is_crash_report_process = false;
+  EXPECT_SUCCEEDED(Crash::IsCrashReportProcess(&is_crash_report_process));
+  EXPECT_FALSE(is_crash_report_process);
+
+  EXPECT_TRUE(::SetEnvironmentVariable(kNoCrashHandlerEnvVariableName,
+              _T("1")));
+  is_crash_report_process = false;
+  EXPECT_SUCCEEDED(Crash::IsCrashReportProcess(&is_crash_report_process));
+  EXPECT_TRUE(is_crash_report_process);
+
+  // Clear the environment variable.
+  EXPECT_TRUE(::SetEnvironmentVariable(kNoCrashHandlerEnvVariableName, NULL));
+}
+
+TEST_F(CrashTest, GetProductName) {
+  Crash::ParameterMap parameters;
+  EXPECT_STREQ(_T("Google Error Reporting"), Crash::GetProductName(parameters));
+
+  parameters[_T("prod")] = _T("Update2");
+  EXPECT_STREQ(_T("Update2"), Crash::GetProductName(parameters));
+}
+
+TEST_F(CrashTest, SaveLastCrash) {
+  // Copy a test file into the module directory to use as a crash file.
+  const TCHAR kMiniDumpFilename[] = _T("minidump.dmp");
+
+  CString test_file;    // The unit test support file.
+  CString crash_file;   // The crash file to be backed up.
+
+  test_file.AppendFormat(_T("%s\\unittest_support\\%s"),
+                         module_dir_, kMiniDumpFilename);
+  crash_file.AppendFormat(_T("%s\\%s"), Crash::crash_dir_, kMiniDumpFilename);
+  EXPECT_TRUE(File::Exists(test_file));
+  EXPECT_TRUE(::CopyFile(test_file, crash_file, false));
+  EXPECT_TRUE(File::Exists(crash_file));
+
+  EXPECT_HRESULT_SUCCEEDED(Crash::SaveLastCrash(crash_file, _T("test")));
+
+  CString saved_crash_file;  // The name of backup crash file.
+  saved_crash_file.AppendFormat(_T("%s\\test-last.dmp"), Crash::crash_dir_);
+  EXPECT_TRUE(File::Exists(saved_crash_file));
+
+  EXPECT_TRUE(::DeleteFile(saved_crash_file));
+}
+
+TEST_F(CrashTest, StartServer) {
+  // Terminate all processes to avoid conflicts on the crash services pipe.
+  TerminateAllGoogleUpdateProcesses();
+
+  EXPECT_HRESULT_SUCCEEDED(Crash::StartServer());
+
+  // Try opening the crash services pipe.
+  CString user_sid;
+  EXPECT_HRESULT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid));
+  CString pipe_name;
+  pipe_name.AppendFormat(_T("\\\\.\\pipe\\GoogleCrashServices\\%s"), user_sid);
+  scoped_pipe pipe_handle(::CreateFile(pipe_name,
+                                       GENERIC_READ | GENERIC_WRITE,
+                                       FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                       NULL,
+                                       OPEN_EXISTING,
+                                       0,
+                                       NULL));
+  EXPECT_TRUE(pipe_handle);
+
+  Crash::StopServer();
+}
+
+TEST_F(CrashTest, CleanStaleCrashes) {
+  // Copy a test file into the module directory to use as a crash file.
+  const TCHAR kMiniDumpFilename[] = _T("minidump.dmp");
+
+  CString test_file;    // The unit test support file.
+  CString crash_file;   // The crash file to be backed up.
+
+  test_file.AppendFormat(_T("%s\\unittest_support\\%s"),
+                         module_dir_, kMiniDumpFilename);
+  crash_file.AppendFormat(_T("%s\\%s.dmp"),
+                          Crash::crash_dir_,
+                          _T("5695F1E0-95BD-4bc2-99C0-E9DCC0AC5274"));
+  EXPECT_TRUE(File::Exists(test_file));
+  EXPECT_TRUE(::CopyFile(test_file, crash_file, false));
+  EXPECT_TRUE(File::Exists(crash_file));
+
+  FILETIME time_created = {0};
+  time64 now = GetCurrent100NSTime();
+
+  // Create a time value 23 hours in the past. Expect the crash file remains.
+  Time64ToFileTime(now - 23 * kHoursTo100ns, &time_created);
+  EXPECT_HRESULT_SUCCEEDED(File::SetFileTime(crash_file, &time_created,
+                                             NULL, NULL));
+  Crash::CleanStaleCrashes();
+  EXPECT_TRUE(File::Exists(crash_file));
+
+  // Create a time value 25 hours in the past. Expect the crash file is deleted.
+  Time64ToFileTime(now - 25 * kHoursTo100ns, &time_created);
+  EXPECT_HRESULT_SUCCEEDED(File::SetFileTime(crash_file, &time_created,
+                                             NULL, NULL));
+  Crash::CleanStaleCrashes();
+  EXPECT_FALSE(File::Exists(crash_file));
+}
+
+// Installs and uninstalls the crash handler in the user case.
+TEST_F(CrashTest, InstallCrashHandler) {
+  EXPECT_HRESULT_SUCCEEDED(Crash::InstallCrashHandler(false));
+  Crash::UninstallCrashHandler();
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/event_logger.cc b/goopdate/event_logger.cc
index 63878ed..ad03c35 100644
--- a/goopdate/event_logger.cc
+++ b/goopdate/event_logger.cc
@@ -1,201 +1,201 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/goopdate/event_logger.h"

-

-#include <sddl.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/user_info.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource_manager.h"

-

-namespace omaha {

-

-void LogEventHelper(WORD type, DWORD id, size_t count, const TCHAR** strings,

-                    const TCHAR* ctx) {

-  ASSERT1(count <= kint16max);

-  if (!ConfigManager::Instance()->CanLogEvents(type)) {

-    return;

-  }

-

-  // Include the circular logging buffer in the event log if the type is a

-  // warning or an error.

-  CStringA data(ctx);

-  CString context = GetLogging()->GetHistory();

-  if (!context.IsEmpty()) {

-    data.AppendFormat("\n[More context: %S]", context);

-  }

-

-  HRESULT hr = EventLogger::ReportEvent(EventLogger::kSourceName,

-                                        type,

-                                        EventLogger::kDefaultCategory,

-                                        id,

-                                        static_cast<WORD>(count),

-                                        strings,

-                                        data.GetLength(),

-                                        data.GetBuffer());

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[Failed to log event][0x%08x]"), hr));

-  }

-}

-

-CString BuildEventSourceRegistryKeyName(const TCHAR* src_name) {

-  ASSERT1(src_name);

-  CString key_name;

-  key_name.Format(_T("HKLM\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\")

-                  _T("Application\\%s"),

-                  src_name);

-  return key_name;

-}

-

-HRESULT EventLogger::AddEventSource(const TCHAR* src_name,

-                                    const TCHAR* msg_dll_path) {

-  ASSERT1(src_name);

-  if (!src_name) return E_INVALIDARG;

-  ASSERT1(msg_dll_path);

-  if (!msg_dll_path) return E_INVALIDARG;

-

-  // Create the event source as a subkey of the "Application" log.

-  RegKey reg_key;

-  HRESULT hr = reg_key.Create(BuildEventSourceRegistryKeyName(src_name));

-  if (FAILED(hr)) return hr;

-

-  // Set the name of the message file. RegKey class can't set REG_EXPAND_SZ

-  // values so we must use the low level OS call.

-  int result = ::RegSetValueEx(reg_key.Key(),

-                               _T("EventMessageFile"),

-                               0,

-                               REG_EXPAND_SZ,

-                               reinterpret_cast<const byte*>(msg_dll_path),

-                               (_tcslen(msg_dll_path) + 1) * sizeof(TCHAR));

-  if (result != ERROR_SUCCESS) return HRESULT_FROM_WIN32(result);

-

-  // Set the supported event types.

-  DWORD types = EVENTLOG_ERROR_TYPE |

-                EVENTLOG_WARNING_TYPE |

-                EVENTLOG_INFORMATION_TYPE;

-  hr = reg_key.SetValue(_T("TypesSupported"), types);

-  if (FAILED(hr)) return hr;

-

-  return S_OK;

-}

-

-HRESULT EventLogger::RemoveEventSource(const TCHAR* src_name) {

-  ASSERT1(src_name);

-  if (!src_name) return E_INVALIDARG;

-

-  // RegKey::DeleteKey  returns S_FALSE when attempting to delete

-  // a key that is not there.

-  HRESULT hr = RegKey::DeleteKey(BuildEventSourceRegistryKeyName(src_name),

-                                 false);

-  return SUCCEEDED(hr) ? S_OK : hr;

-}

-

-

-HRESULT EventLogger::ReportEvent(const TCHAR* src_name,

-                                 WORD type,

-                                 WORD category,

-                                 DWORD id,

-                                 WORD count,

-                                 const TCHAR** strings,

-                                 size_t buf_size,

-                                 void* buffer) {

-  ASSERT1(src_name);

-  ASSERT1(type == EVENTLOG_SUCCESS ||

-          type == EVENTLOG_ERROR_TYPE ||

-          type == EVENTLOG_WARNING_TYPE ||

-          type == EVENTLOG_INFORMATION_TYPE);

-

-  //  Opens the log on the local computer.

-  HANDLE hlog = ::RegisterEventSource(NULL, src_name);

-  if (!hlog) {

-    return HRESULTFromLastError();

-  }

-

-  // Best effort to get the sid for the current user. The event logging

-  // provides for logging the sid at no cost so that the user shows up

-  // in the event log.

-  CString sid_string;

-  VERIFY1(SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &sid_string)));

-  PSID psid = NULL;

-  if (!sid_string.IsEmpty()) {

-    VERIFY1(::ConvertStringSidToSid(sid_string, &psid));

-    ASSERT1(psid);

-  }

-

-  HRESULT hr = E_FAIL;

-  if (::ReportEvent(hlog,       // Event log handle.

-                    type,       // Event type.

-                    category,   // Event category.

-                    id,         // Event identifier.

-                    psid,       // User security identifier.

-                    count,      // Number of substitution strings.

-                    buf_size,   // Size of binary data.

-                    strings,    // Pointer to strings.

-                    buffer)) {  // Binary data.

-    hr = S_OK;

-  } else {

-    hr = HRESULTFromLastError();

-  }

-

-  ::LocalFree(psid);

-  VERIFY1(::DeregisterEventSource(hlog));

-  return hr;

-}

-

-// TODO(omaha): When we do i18n later on, decide if the string below needs

-// translation or not. On one hand this string makes it to the event viewer, on

-// the other hand the same string is used to register an event log for an

-// application in registry. We do not expect the mapping to change when the user

-// changes languages, however we may decide to do so.

-const TCHAR* const EventLogger::kSourceName = _T("Google Update");

-

-void GoogleUpdateLogEvent::WriteEvent() {

-  ASSERT1(!event_desc_.IsEmpty());

-  ASSERT1(type_ != 0);

-  ASSERT1(id_ != 0);

-

-  DWORD pid(::GetCurrentProcessId());

-  CString ver;

-  goopdate_utils::GetVerFromRegistry(is_machine_, kGoogleUpdateAppId, &ver);

-

-  CString lang = ResourceManager::GetDefaultUserLanguage();

-

-  const ConfigManager& cm = *ConfigManager::Instance();

-  CString msg;

-  msg.Format(_T("\n%s.\npid=%d, ver=%s, lang=%s, machine=%d, extern=%d"),

-             event_desc_, pid, ver, lang, is_machine_, !cm.IsGoogler());

-#if DEBUG

-  msg.Append(_T(", debug"));

-#endif

-#if !OFFICIAL_BUILD

-  msg.Append(_T(", private"));

-#endif

-

-  if (!event_text_.IsEmpty()) {

-    msg.AppendFormat(_T("\n%s"), event_text_);

-  }

-

-  LogEvent(static_cast<WORD>(type_), id_, msg);

-}

-

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/goopdate/event_logger.h"
+
+#include <sddl.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/user_info.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource_manager.h"
+
+namespace omaha {
+
+void LogEventHelper(WORD type, DWORD id, size_t count, const TCHAR** strings,
+                    const TCHAR* ctx) {
+  ASSERT1(count <= kint16max);
+  if (!ConfigManager::Instance()->CanLogEvents(type)) {
+    return;
+  }
+
+  // Include the circular logging buffer in the event log if the type is a
+  // warning or an error.
+  CStringA data(ctx);
+  CString context = GetLogging()->GetHistory();
+  if (!context.IsEmpty()) {
+    data.AppendFormat("\n[More context: %S]", context);
+  }
+
+  HRESULT hr = EventLogger::ReportEvent(EventLogger::kSourceName,
+                                        type,
+                                        EventLogger::kDefaultCategory,
+                                        id,
+                                        static_cast<WORD>(count),
+                                        strings,
+                                        data.GetLength(),
+                                        data.GetBuffer());
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[Failed to log event][0x%08x]"), hr));
+  }
+}
+
+CString BuildEventSourceRegistryKeyName(const TCHAR* src_name) {
+  ASSERT1(src_name);
+  CString key_name;
+  key_name.Format(_T("HKLM\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\")
+                  _T("Application\\%s"),
+                  src_name);
+  return key_name;
+}
+
+HRESULT EventLogger::AddEventSource(const TCHAR* src_name,
+                                    const TCHAR* msg_dll_path) {
+  ASSERT1(src_name);
+  if (!src_name) return E_INVALIDARG;
+  ASSERT1(msg_dll_path);
+  if (!msg_dll_path) return E_INVALIDARG;
+
+  // Create the event source as a subkey of the "Application" log.
+  RegKey reg_key;
+  HRESULT hr = reg_key.Create(BuildEventSourceRegistryKeyName(src_name));
+  if (FAILED(hr)) return hr;
+
+  // Set the name of the message file. RegKey class can't set REG_EXPAND_SZ
+  // values so we must use the low level OS call.
+  int result = ::RegSetValueEx(reg_key.Key(),
+                               _T("EventMessageFile"),
+                               0,
+                               REG_EXPAND_SZ,
+                               reinterpret_cast<const byte*>(msg_dll_path),
+                               (_tcslen(msg_dll_path) + 1) * sizeof(TCHAR));
+  if (result != ERROR_SUCCESS) return HRESULT_FROM_WIN32(result);
+
+  // Set the supported event types.
+  DWORD types = EVENTLOG_ERROR_TYPE |
+                EVENTLOG_WARNING_TYPE |
+                EVENTLOG_INFORMATION_TYPE;
+  hr = reg_key.SetValue(_T("TypesSupported"), types);
+  if (FAILED(hr)) return hr;
+
+  return S_OK;
+}
+
+HRESULT EventLogger::RemoveEventSource(const TCHAR* src_name) {
+  ASSERT1(src_name);
+  if (!src_name) return E_INVALIDARG;
+
+  // RegKey::DeleteKey  returns S_FALSE when attempting to delete
+  // a key that is not there.
+  HRESULT hr = RegKey::DeleteKey(BuildEventSourceRegistryKeyName(src_name),
+                                 false);
+  return SUCCEEDED(hr) ? S_OK : hr;
+}
+
+
+HRESULT EventLogger::ReportEvent(const TCHAR* src_name,
+                                 WORD type,
+                                 WORD category,
+                                 DWORD id,
+                                 WORD count,
+                                 const TCHAR** strings,
+                                 size_t buf_size,
+                                 void* buffer) {
+  ASSERT1(src_name);
+  ASSERT1(type == EVENTLOG_SUCCESS ||
+          type == EVENTLOG_ERROR_TYPE ||
+          type == EVENTLOG_WARNING_TYPE ||
+          type == EVENTLOG_INFORMATION_TYPE);
+
+  //  Opens the log on the local computer.
+  HANDLE hlog = ::RegisterEventSource(NULL, src_name);
+  if (!hlog) {
+    return HRESULTFromLastError();
+  }
+
+  // Best effort to get the sid for the current user. The event logging
+  // provides for logging the sid at no cost so that the user shows up
+  // in the event log.
+  CString sid_string;
+  VERIFY1(SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &sid_string)));
+  PSID psid = NULL;
+  if (!sid_string.IsEmpty()) {
+    VERIFY1(::ConvertStringSidToSid(sid_string, &psid));
+    ASSERT1(psid);
+  }
+
+  HRESULT hr = E_FAIL;
+  if (::ReportEvent(hlog,       // Event log handle.
+                    type,       // Event type.
+                    category,   // Event category.
+                    id,         // Event identifier.
+                    psid,       // User security identifier.
+                    count,      // Number of substitution strings.
+                    buf_size,   // Size of binary data.
+                    strings,    // Pointer to strings.
+                    buffer)) {  // Binary data.
+    hr = S_OK;
+  } else {
+    hr = HRESULTFromLastError();
+  }
+
+  ::LocalFree(psid);
+  VERIFY1(::DeregisterEventSource(hlog));
+  return hr;
+}
+
+// TODO(omaha): When we do i18n later on, decide if the string below needs
+// translation or not. On one hand this string makes it to the event viewer, on
+// the other hand the same string is used to register an event log for an
+// application in registry. We do not expect the mapping to change when the user
+// changes languages, however we may decide to do so.
+const TCHAR* const EventLogger::kSourceName = _T("Google Update");
+
+void GoogleUpdateLogEvent::WriteEvent() {
+  ASSERT1(!event_desc_.IsEmpty());
+  ASSERT1(type_ != 0);
+  ASSERT1(id_ != 0);
+
+  DWORD pid(::GetCurrentProcessId());
+  CString ver;
+  goopdate_utils::GetVerFromRegistry(is_machine_, kGoogleUpdateAppId, &ver);
+
+  CString lang = ResourceManager::GetDefaultUserLanguage();
+
+  const ConfigManager& cm = *ConfigManager::Instance();
+  CString msg;
+  msg.Format(_T("\n%s.\npid=%d, ver=%s, lang=%s, machine=%d, extern=%d"),
+             event_desc_, pid, ver, lang, is_machine_, !cm.IsGoogler());
+#if DEBUG
+  msg.Append(_T(", debug"));
+#endif
+#if !OFFICIAL_BUILD
+  msg.Append(_T(", private"));
+#endif
+
+  if (!event_text_.IsEmpty()) {
+    msg.AppendFormat(_T("\n%s"), event_text_);
+  }
+
+  LogEvent(static_cast<WORD>(type_), id_, msg);
+}
+
+
+}  // namespace omaha
+
diff --git a/goopdate/event_logger.h b/goopdate/event_logger.h
index f32f279..a8fd394 100644
--- a/goopdate/event_logger.h
+++ b/goopdate/event_logger.h
@@ -1,148 +1,148 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Event Logger provides a simple mechanism to log events to Windows

-// Event Log. A few overloads are defined to simplify logging by reducing

-// the number of parameters that must be provided. The overloads are

-// implemented in terms of the EventLogger class.

-//

-// The event logging works in both debug and optimized builds. This is not

-// a substitute for the debug log. Instead it is a way to provide some level

-// of transparency into what Google Update is doing at runtime and to help

-// diagnosing end user issues.

-//

-// Familiarity with Windows Event Log is helpful in understanding how

-// these wrappers are to be used. Windows Event Log uses localized strings

-// in a message file and it substitutes string insterts that correspond to

-// formatting characters in the message string. In addtion, the log is able

-// to record raw data, herein provided by a context string, which may be

-// useful to provide some context around the formatted message.

-

-// TODO(omaha): Provide some control for the verbosity level in the log.

-// TODO(omaha): Perhaps there is a better way to define the overloaded

-// wrappers below. I chose a compromise between the easy of use while not

-// mixing up different string parameters that have different meanings.

-

-#ifndef OMAHA_GOOPDATE_EVENT_LOGGER_H__

-#define OMAHA_GOOPDATE_EVENT_LOGGER_H__

-

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-void LogEventHelper(WORD type, DWORD id, size_t count, const TCHAR** strings,

-                    const TCHAR* ctx);

-

-// Logs an event to the Application log

-inline void LogEvent(WORD type, DWORD id) {

-  LogEventHelper(type, id, 0, NULL, NULL);

-}

-

-inline void LogEvent(WORD type, DWORD id, const TCHAR* s) {

-  const TCHAR* strings[] = {s};

-  LogEventHelper(type, id, arraysize(strings), strings, NULL);

-}

-

-inline void LogEvent(WORD type, DWORD id, const TCHAR* s1, const TCHAR* s2) {

-  const TCHAR* strings[] = {s1, s2};

-  LogEventHelper(type, id, arraysize(strings), strings, NULL);

-}

-

-inline void LogEvent(WORD type, DWORD id, const TCHAR* s1, const TCHAR* s2,

-                     const TCHAR* s3) {

-  const TCHAR* strings[] = {s1, s2, s3};

-  LogEventHelper(type, id, arraysize(strings), strings, NULL);

-}

-

-// Logs an event to the Application log with a context string.

-inline void LogEventContext(WORD type, DWORD id, const TCHAR* ctx) {

-  LogEventHelper(type, id, 0, NULL, ctx);

-}

-

-inline void LogEventContext(WORD type, DWORD id, const TCHAR* s,

-                            const TCHAR* ctx) {

-  const TCHAR* strings[] = {s};

-  LogEventHelper(type, id, arraysize(strings), strings, ctx);

-}

-

-inline void LogEventContext(WORD type, DWORD id, const TCHAR* s1,

-                            const TCHAR* s2, const TCHAR* ctx) {

-  const TCHAR* strings[] = {s1, s2};

-  LogEventHelper(type, id, arraysize(strings), strings, ctx);

-}

-

-inline void LogEventContext(WORD type, DWORD id, const TCHAR* s1,

-                            const TCHAR* s2, const TCHAR* s3,

-                            const TCHAR* ctx) {

-  const TCHAR* strings[] = {s1, s2, s3};

-  LogEventHelper(type, id, arraysize(strings), strings, ctx);

-}

-

-class EventLogger {

- public:

-  // Creates an event source for the "Application" log so that EventViewer can

-  // map event identifier codes to message strings.

-  static HRESULT AddEventSource(

-      const TCHAR* src_name,       // Event source name.

-      const TCHAR* msg_dll_path);  // Path for message DLL.

-

-  static HRESULT RemoveEventSource(

-      const TCHAR* src_name);      // Event source name.

-

-  // Writes an entry at the end of event log that contains the source name.

-  static HRESULT ReportEvent(

-      const TCHAR* src_name,       // Event source name.

-      WORD type,                   // Type of the event to be logged.

-      WORD category,               // Event category.

-      DWORD id,                    // Event identifier.

-      WORD count,                  // Count of insert strings.

-      const TCHAR** strings,       // Insert strings.

-      size_t buf_size,             // Size of binary data to append.

-      void* buffer);               // Buffer containing the binary data.

-

-  // Default name for the event source.

-  static const TCHAR* const kSourceName;

-

-  // Default event category.

-  static const WORD kDefaultCategory = 0;

-};

-

-class GoogleUpdateLogEvent {

- public:

-  GoogleUpdateLogEvent(int type, int id, bool is_machine)

-      : type_(type),

-        id_(id),

-        is_machine_(is_machine) {}

-  GoogleUpdateLogEvent() : type_(0), id_(0), is_machine_(false) {}

-  ~GoogleUpdateLogEvent() {}

-  void WriteEvent();

-  void set_event_desc(const CString& desc) { event_desc_ = desc; }

-  void set_event_text(const CString& text) { event_text_ = text; }

-

- private:

-  CString event_desc_;

-  CString event_text_;

-  int type_;

-  int id_;

-  bool is_machine_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(GoogleUpdateLogEvent);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_EVENT_LOGGER_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Event Logger provides a simple mechanism to log events to Windows
+// Event Log. A few overloads are defined to simplify logging by reducing
+// the number of parameters that must be provided. The overloads are
+// implemented in terms of the EventLogger class.
+//
+// The event logging works in both debug and optimized builds. This is not
+// a substitute for the debug log. Instead it is a way to provide some level
+// of transparency into what Google Update is doing at runtime and to help
+// diagnosing end user issues.
+//
+// Familiarity with Windows Event Log is helpful in understanding how
+// these wrappers are to be used. Windows Event Log uses localized strings
+// in a message file and it substitutes string insterts that correspond to
+// formatting characters in the message string. In addtion, the log is able
+// to record raw data, herein provided by a context string, which may be
+// useful to provide some context around the formatted message.
+
+// TODO(omaha): Provide some control for the verbosity level in the log.
+// TODO(omaha): Perhaps there is a better way to define the overloaded
+// wrappers below. I chose a compromise between the easy of use while not
+// mixing up different string parameters that have different meanings.
+
+#ifndef OMAHA_GOOPDATE_EVENT_LOGGER_H__
+#define OMAHA_GOOPDATE_EVENT_LOGGER_H__
+
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+void LogEventHelper(WORD type, DWORD id, size_t count, const TCHAR** strings,
+                    const TCHAR* ctx);
+
+// Logs an event to the Application log
+inline void LogEvent(WORD type, DWORD id) {
+  LogEventHelper(type, id, 0, NULL, NULL);
+}
+
+inline void LogEvent(WORD type, DWORD id, const TCHAR* s) {
+  const TCHAR* strings[] = {s};
+  LogEventHelper(type, id, arraysize(strings), strings, NULL);
+}
+
+inline void LogEvent(WORD type, DWORD id, const TCHAR* s1, const TCHAR* s2) {
+  const TCHAR* strings[] = {s1, s2};
+  LogEventHelper(type, id, arraysize(strings), strings, NULL);
+}
+
+inline void LogEvent(WORD type, DWORD id, const TCHAR* s1, const TCHAR* s2,
+                     const TCHAR* s3) {
+  const TCHAR* strings[] = {s1, s2, s3};
+  LogEventHelper(type, id, arraysize(strings), strings, NULL);
+}
+
+// Logs an event to the Application log with a context string.
+inline void LogEventContext(WORD type, DWORD id, const TCHAR* ctx) {
+  LogEventHelper(type, id, 0, NULL, ctx);
+}
+
+inline void LogEventContext(WORD type, DWORD id, const TCHAR* s,
+                            const TCHAR* ctx) {
+  const TCHAR* strings[] = {s};
+  LogEventHelper(type, id, arraysize(strings), strings, ctx);
+}
+
+inline void LogEventContext(WORD type, DWORD id, const TCHAR* s1,
+                            const TCHAR* s2, const TCHAR* ctx) {
+  const TCHAR* strings[] = {s1, s2};
+  LogEventHelper(type, id, arraysize(strings), strings, ctx);
+}
+
+inline void LogEventContext(WORD type, DWORD id, const TCHAR* s1,
+                            const TCHAR* s2, const TCHAR* s3,
+                            const TCHAR* ctx) {
+  const TCHAR* strings[] = {s1, s2, s3};
+  LogEventHelper(type, id, arraysize(strings), strings, ctx);
+}
+
+class EventLogger {
+ public:
+  // Creates an event source for the "Application" log so that EventViewer can
+  // map event identifier codes to message strings.
+  static HRESULT AddEventSource(
+      const TCHAR* src_name,       // Event source name.
+      const TCHAR* msg_dll_path);  // Path for message DLL.
+
+  static HRESULT RemoveEventSource(
+      const TCHAR* src_name);      // Event source name.
+
+  // Writes an entry at the end of event log that contains the source name.
+  static HRESULT ReportEvent(
+      const TCHAR* src_name,       // Event source name.
+      WORD type,                   // Type of the event to be logged.
+      WORD category,               // Event category.
+      DWORD id,                    // Event identifier.
+      WORD count,                  // Count of insert strings.
+      const TCHAR** strings,       // Insert strings.
+      size_t buf_size,             // Size of binary data to append.
+      void* buffer);               // Buffer containing the binary data.
+
+  // Default name for the event source.
+  static const TCHAR* const kSourceName;
+
+  // Default event category.
+  static const WORD kDefaultCategory = 0;
+};
+
+class GoogleUpdateLogEvent {
+ public:
+  GoogleUpdateLogEvent(int type, int id, bool is_machine)
+      : type_(type),
+        id_(id),
+        is_machine_(is_machine) {}
+  GoogleUpdateLogEvent() : type_(0), id_(0), is_machine_(false) {}
+  ~GoogleUpdateLogEvent() {}
+  void WriteEvent();
+  void set_event_desc(const CString& desc) { event_desc_ = desc; }
+  void set_event_text(const CString& text) { event_text_ = text; }
+
+ private:
+  CString event_desc_;
+  CString event_text_;
+  int type_;
+  int id_;
+  bool is_machine_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(GoogleUpdateLogEvent);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_EVENT_LOGGER_H__
+
diff --git a/goopdate/event_logger_unittest.cc b/goopdate/event_logger_unittest.cc
index 3f912b8..4a080f4 100644
--- a/goopdate/event_logger_unittest.cc
+++ b/goopdate/event_logger_unittest.cc
@@ -1,207 +1,207 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include <stdio.h>

-#include <stdarg.h>

-

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/error.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/event_logger.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class EventLoggerTest : public testing::Test {

- protected:

-  virtual void SetUp() {

-    EXPECT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-    OverrideRegistryHives(kRegistryHiveOverrideRoot);

-

-    // Enable logging of events.

-    DWORD log_events = LOG_EVENT_LEVEL_ALL;

-    EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                      kRegValueEventLogLevel, log_events));

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    EXPECT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-  }

-

-  // Reads the topmost event log record.

-  HRESULT ReadLastEventLogRecord(const TCHAR* src_name,

-                                 EVENTLOGRECORD* rec) {

-    if (!(rec && src_name)) return E_INVALIDARG;

-    HANDLE hlog = ::OpenEventLog(NULL, src_name);

-    if (!hlog) {

-      return HRESULTFromLastError();

-    }

-    HRESULT hr = E_FAIL;

-    DWORD bytes_read(0), bytes_needed(0);

-    DWORD read_flags = EVENTLOG_BACKWARDS_READ | EVENTLOG_SEQUENTIAL_READ;

-    if (::ReadEventLog(hlog,              // Event log handle.

-                       read_flags,        // Reverse chronological order.

-                       0,                 // Not used.

-                       rec,               // Read buffer.

-                       rec->Length,       // Size of read buffer.

-                       &bytes_read,       // Number of bytes read.

-                       &bytes_needed)) {  // Number of bytes required.

-      hr = S_OK;

-    } else {

-      hr = HRESULTFromLastError();

-    }

-    ::CloseEventLog(hlog);

-    return hr;

-  }

-};

-

-TEST_F(EventLoggerTest, AddEventSource) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  // Registers the "Google Update" event source for the "Application" log

-  EXPECT_SUCCEEDED(EventLogger::AddEventSource(EventLogger::kSourceName,

-                                               _T("path")));

-

-  const TCHAR key_name[] = _T("HKLM\\SYSTEM\\CurrentControlSet\\Services\\")

-                           _T("EventLog\\Application\\Google Update");

-  EXPECT_TRUE(RegKey::HasKey(key_name));

-

-  CString s;

-  EXPECT_SUCCEEDED(RegKey::GetValue(key_name, _T("EventMessageFile"), &s));

-  EXPECT_STREQ(s.GetString(), _T("path"));

-

-  DWORD types(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(key_name, _T("TypesSupported"), &types));

-  EXPECT_EQ(types,

-      EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE);

-

-  // Removes the "OmahaUnitTest" event source.

-  EXPECT_SUCCEEDED(EventLogger::RemoveEventSource(EventLogger::kSourceName));

-  EXPECT_FALSE(RegKey::HasKey(key_name));

-  EXPECT_TRUE(RegKey::HasKey(

-      _T("HKLM\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application")));

-}

-

-TEST_F(EventLoggerTest, ReportEvent) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  EXPECT_SUCCEEDED(EventLogger::AddEventSource(EventLogger::kSourceName,

-                                               _T("path")));

-

-  const TCHAR* strings[] = {_T("foo"), _T("bar")};

-  byte buf[] = {0xaa, 0x55, 0};

-

-  const int kEventId = 100;

-  EXPECT_SUCCEEDED(EventLogger::ReportEvent(EventLogger::kSourceName,

-                                            EVENTLOG_WARNING_TYPE,

-                                            0,

-                                            kEventId,

-                                            arraysize(strings),

-                                            strings,

-                                            arraysize(buf),

-                                            buf));

-  // Read the record at the top to do a brief sanity check.

-  const size_t kBufferSize = 1024 * 64;

-  byte buffer[kBufferSize] = {0};

-  EVENTLOGRECORD* rec = reinterpret_cast<EVENTLOGRECORD*>(buffer);

-  rec->Length = kBufferSize;

-  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));

-  EXPECT_EQ(rec->EventID, kEventId);

-  EXPECT_EQ(rec->EventType, EVENTLOG_WARNING_TYPE);

-  EXPECT_EQ(rec->EventCategory, 0);

-  EXPECT_EQ(rec->NumStrings, 2);

-  const TCHAR* src = reinterpret_cast<const TCHAR*>(

-      reinterpret_cast<byte*>(rec) + sizeof EVENTLOGRECORD);

-  EXPECT_STREQ(src, EventLogger::kSourceName);

-  const TCHAR* s2 = (LPTSTR) ((LPBYTE) rec + rec->StringOffset);

-  EXPECT_SUCCEEDED(EventLogger::RemoveEventSource(EventLogger::kSourceName));

-}

-

-TEST_F(EventLoggerTest, LogEvent_LoggingDisabled) {

-  // Disable logging.

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueEventLogLevel,

-                                    static_cast<DWORD>(0)));

-

-  const size_t kBufferSize = 1024 * 64;

-  byte buffer[kBufferSize] = {0};

-  EVENTLOGRECORD* rec = reinterpret_cast<EVENTLOGRECORD*>(buffer);

-  rec->Length = kBufferSize;

-  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));

-  int record_number = rec->RecordNumber;

-

-  // Logging is disabled, expect no event is logged.

-  LogEvent(EVENTLOG_INFORMATION_TYPE, 10);

-  rec->Length = kBufferSize;

-  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));

-  EXPECT_EQ(record_number, rec->RecordNumber);

-}

-

-TEST_F(EventLoggerTest, LogEvent) {

-  const size_t kBufferSize = 1024 * 64;

-  byte buffer[kBufferSize] = {0};

-  EVENTLOGRECORD* rec = reinterpret_cast<EVENTLOGRECORD*>(buffer);

-

-  LogEvent(EVENTLOG_INFORMATION_TYPE, 10);

-  rec->Length = kBufferSize;

-  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));

-  EXPECT_EQ(10, rec->EventID);

-

-  LogEvent(EVENTLOG_INFORMATION_TYPE, 11, _T("s1"));

-  rec->Length = kBufferSize;

-  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));

-  EXPECT_EQ(11, rec->EventID);

-

-  LogEvent(EVENTLOG_INFORMATION_TYPE, 12, _T("s1"), _T("s2"));

-  rec->Length = kBufferSize;

-  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));

-  EXPECT_EQ(12, rec->EventID);

-}

-

-TEST_F(EventLoggerTest, LogEventContext) {

-  const size_t kBufferSize = 1024 * 64;

-  byte buffer[kBufferSize] = {0};

-  EVENTLOGRECORD* rec = reinterpret_cast<EVENTLOGRECORD*>(buffer);

-

-  LogEventContext(EVENTLOG_INFORMATION_TYPE, 20, _T("foo"));

-  rec->Length = kBufferSize;

-  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));

-  EXPECT_EQ(20, rec->EventID);

-

-  LogEventContext(EVENTLOG_INFORMATION_TYPE, 21, _T("s1"), _T("bar"));

-  rec->Length = kBufferSize;

-  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));

-  EXPECT_EQ(21, rec->EventID);

-

-  LogEventContext(EVENTLOG_INFORMATION_TYPE, 22,

-                  _T("s1"), _T("s2"), _T("foobar"));

-  rec->Length = kBufferSize;

-  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));

-  EXPECT_EQ(22, rec->EventID);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/error.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/event_logger.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class EventLoggerTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    EXPECT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+    OverrideRegistryHives(kRegistryHiveOverrideRoot);
+
+    // Enable logging of events.
+    DWORD log_events = LOG_EVENT_LEVEL_ALL;
+    EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                      kRegValueEventLogLevel, log_events));
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    EXPECT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+  }
+
+  // Reads the topmost event log record.
+  HRESULT ReadLastEventLogRecord(const TCHAR* src_name,
+                                 EVENTLOGRECORD* rec) {
+    if (!(rec && src_name)) return E_INVALIDARG;
+    HANDLE hlog = ::OpenEventLog(NULL, src_name);
+    if (!hlog) {
+      return HRESULTFromLastError();
+    }
+    HRESULT hr = E_FAIL;
+    DWORD bytes_read(0), bytes_needed(0);
+    DWORD read_flags = EVENTLOG_BACKWARDS_READ | EVENTLOG_SEQUENTIAL_READ;
+    if (::ReadEventLog(hlog,              // Event log handle.
+                       read_flags,        // Reverse chronological order.
+                       0,                 // Not used.
+                       rec,               // Read buffer.
+                       rec->Length,       // Size of read buffer.
+                       &bytes_read,       // Number of bytes read.
+                       &bytes_needed)) {  // Number of bytes required.
+      hr = S_OK;
+    } else {
+      hr = HRESULTFromLastError();
+    }
+    ::CloseEventLog(hlog);
+    return hr;
+  }
+};
+
+TEST_F(EventLoggerTest, AddEventSource) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  // Registers the "Google Update" event source for the "Application" log
+  EXPECT_SUCCEEDED(EventLogger::AddEventSource(EventLogger::kSourceName,
+                                               _T("path")));
+
+  const TCHAR key_name[] = _T("HKLM\\SYSTEM\\CurrentControlSet\\Services\\")
+                           _T("EventLog\\Application\\Google Update");
+  EXPECT_TRUE(RegKey::HasKey(key_name));
+
+  CString s;
+  EXPECT_SUCCEEDED(RegKey::GetValue(key_name, _T("EventMessageFile"), &s));
+  EXPECT_STREQ(s.GetString(), _T("path"));
+
+  DWORD types(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(key_name, _T("TypesSupported"), &types));
+  EXPECT_EQ(types,
+      EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE);
+
+  // Removes the "OmahaUnitTest" event source.
+  EXPECT_SUCCEEDED(EventLogger::RemoveEventSource(EventLogger::kSourceName));
+  EXPECT_FALSE(RegKey::HasKey(key_name));
+  EXPECT_TRUE(RegKey::HasKey(
+      _T("HKLM\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application")));
+}
+
+TEST_F(EventLoggerTest, ReportEvent) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  EXPECT_SUCCEEDED(EventLogger::AddEventSource(EventLogger::kSourceName,
+                                               _T("path")));
+
+  const TCHAR* strings[] = {_T("foo"), _T("bar")};
+  byte buf[] = {0xaa, 0x55, 0};
+
+  const int kEventId = 100;
+  EXPECT_SUCCEEDED(EventLogger::ReportEvent(EventLogger::kSourceName,
+                                            EVENTLOG_WARNING_TYPE,
+                                            0,
+                                            kEventId,
+                                            arraysize(strings),
+                                            strings,
+                                            arraysize(buf),
+                                            buf));
+  // Read the record at the top to do a brief sanity check.
+  const size_t kBufferSize = 1024 * 64;
+  byte buffer[kBufferSize] = {0};
+  EVENTLOGRECORD* rec = reinterpret_cast<EVENTLOGRECORD*>(buffer);
+  rec->Length = kBufferSize;
+  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));
+  EXPECT_EQ(rec->EventID, kEventId);
+  EXPECT_EQ(rec->EventType, EVENTLOG_WARNING_TYPE);
+  EXPECT_EQ(rec->EventCategory, 0);
+  EXPECT_EQ(rec->NumStrings, 2);
+  const TCHAR* src = reinterpret_cast<const TCHAR*>(
+      reinterpret_cast<byte*>(rec) + sizeof EVENTLOGRECORD);
+  EXPECT_STREQ(src, EventLogger::kSourceName);
+  const TCHAR* s2 = (LPTSTR) ((LPBYTE) rec + rec->StringOffset);
+  EXPECT_SUCCEEDED(EventLogger::RemoveEventSource(EventLogger::kSourceName));
+}
+
+TEST_F(EventLoggerTest, LogEvent_LoggingDisabled) {
+  // Disable logging.
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueEventLogLevel,
+                                    static_cast<DWORD>(0)));
+
+  const size_t kBufferSize = 1024 * 64;
+  byte buffer[kBufferSize] = {0};
+  EVENTLOGRECORD* rec = reinterpret_cast<EVENTLOGRECORD*>(buffer);
+  rec->Length = kBufferSize;
+  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));
+  int record_number = rec->RecordNumber;
+
+  // Logging is disabled, expect no event is logged.
+  LogEvent(EVENTLOG_INFORMATION_TYPE, 10);
+  rec->Length = kBufferSize;
+  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));
+  EXPECT_EQ(record_number, rec->RecordNumber);
+}
+
+TEST_F(EventLoggerTest, LogEvent) {
+  const size_t kBufferSize = 1024 * 64;
+  byte buffer[kBufferSize] = {0};
+  EVENTLOGRECORD* rec = reinterpret_cast<EVENTLOGRECORD*>(buffer);
+
+  LogEvent(EVENTLOG_INFORMATION_TYPE, 10);
+  rec->Length = kBufferSize;
+  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));
+  EXPECT_EQ(10, rec->EventID);
+
+  LogEvent(EVENTLOG_INFORMATION_TYPE, 11, _T("s1"));
+  rec->Length = kBufferSize;
+  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));
+  EXPECT_EQ(11, rec->EventID);
+
+  LogEvent(EVENTLOG_INFORMATION_TYPE, 12, _T("s1"), _T("s2"));
+  rec->Length = kBufferSize;
+  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));
+  EXPECT_EQ(12, rec->EventID);
+}
+
+TEST_F(EventLoggerTest, LogEventContext) {
+  const size_t kBufferSize = 1024 * 64;
+  byte buffer[kBufferSize] = {0};
+  EVENTLOGRECORD* rec = reinterpret_cast<EVENTLOGRECORD*>(buffer);
+
+  LogEventContext(EVENTLOG_INFORMATION_TYPE, 20, _T("foo"));
+  rec->Length = kBufferSize;
+  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));
+  EXPECT_EQ(20, rec->EventID);
+
+  LogEventContext(EVENTLOG_INFORMATION_TYPE, 21, _T("s1"), _T("bar"));
+  rec->Length = kBufferSize;
+  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));
+  EXPECT_EQ(21, rec->EventID);
+
+  LogEventContext(EVENTLOG_INFORMATION_TYPE, 22,
+                  _T("s1"), _T("s2"), _T("foobar"));
+  rec->Length = kBufferSize;
+  EXPECT_SUCCEEDED(ReadLastEventLogRecord(EventLogger::kSourceName, rec));
+  EXPECT_EQ(22, rec->EventID);
+}
+
+}  // namespace omaha
diff --git a/goopdate/extra_args_parser.cc b/goopdate/extra_args_parser.cc
index 3793ee6..3987856 100644
--- a/goopdate/extra_args_parser.cc
+++ b/goopdate/extra_args_parser.cc
@@ -1,239 +1,239 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/extra_args_parser.h"

-

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/goopdate_utils.h"

-

-namespace omaha {

-

-// TODO(omaha): There is no enforcement of required or optional values of

-// the extra arguments. Come up with a way to enforce this.

-HRESULT ExtraArgsParser::Parse(const TCHAR* extra_args,

-                               const TCHAR* app_args,

-                               CommandLineExtraArgs* args) {

-  // TODO(omaha): If we prefix extra_args with '/' and replace all '=' with ' '

-  // and all & with '/' then we should be able to use the CommandLineParser

-  // class to pull out the values here.  We'd need to define scenarios for all

-  // permutations of ExtraArgs, but this shouldn't be difficult to get the right

-  // ones.

-  HRESULT hr = Validate(extra_args);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  first_app_ = true;

-  int pos = 0;

-  CString input_str(extra_args);

-  CString token = input_str.Tokenize(kExtraArgsSeparators, pos);

-  while (!token.IsEmpty()) {

-    CORE_LOG(L2, (_T("[ExtraArgsParser::Parse][token=%s]"), token));

-    hr = HandleToken(token, args);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    // Continue parsing

-    token = input_str.Tokenize(kExtraArgsSeparators, pos);

-  }

-

-  // Save the arguments for the last application.

-  args->apps.push_back(cur_extra_app_args_);

-  return ParseAppArgs(app_args, args);

-}

-

-HRESULT ExtraArgsParser::ParseAppArgs(const TCHAR* app_args,

-                                      CommandLineExtraArgs* args) {

-  if (!app_args || !*app_args) {

-    return S_OK;

-  }

-

-  HRESULT hr = Validate(app_args);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  int cur_app_args_index = -1;

-  int pos = 0;

-  CString input_str = app_args;

-  CString token = input_str.Tokenize(kExtraArgsSeparators, pos);

-  while (!token.IsEmpty()) {

-    CORE_LOG(L2, (_T("[ExtraArgsParser::ParseAppArgs][token=%s]"), token));

-    hr = HandleAppArgsToken(token, args, &cur_app_args_index);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    token = input_str.Tokenize(kExtraArgsSeparators, pos);

-  }

-

-  return S_OK;

-}

-

-HRESULT ExtraArgsParser::Validate(const TCHAR* extra_args) {

-  CString extra_args_str(extra_args);

-  if (extra_args_str.IsEmpty()) {

-    return E_INVALIDARG;

-  }

-

-  if (-1 != extra_args_str.FindOneOf(kDisallowedCharsInExtraArgs)) {

-    // A '/' was found in the "extra" arguments or "extra" arguments were

-    // not specified before the next command.

-    return E_INVALIDARG;

-  }

-

-  return S_OK;

-}

-

-// Handles tokens from the extra arguments string.

-HRESULT ExtraArgsParser::HandleToken(const CString& token,

-                                     CommandLineExtraArgs* args) {

-  CString name;

-  CString value;

-  if (!ParseNameValuePair(token, kNameValueSeparatorChar, &name, &value)) {

-    return E_INVALIDARG;

-  }

-

-  // The first set of args apply to all apps. They may occur at any point, but

-  // only the last occurrence is recorded.

-  if (name.CompareNoCase(kExtraArgInstallationId) == 0) {

-    ASSERT1(!value.IsEmpty());

-    if (FAILED(::CLSIDFromString(const_cast<TCHAR*>(value.GetString()),

-                                 &args->installation_id))) {

-      return E_INVALIDARG;

-    }

-  } else if (name.CompareNoCase(kExtraArgBrandCode) == 0) {

-    if (value.GetLength() > kBrandIdLength) {

-      return E_INVALIDARG;

-    }

-    args->brand_code = value;

-  } else if (name.CompareNoCase(kExtraArgClientId) == 0) {

-    args->client_id = value;

-  } else if (name.CompareNoCase(kExtraArgReferralId) == 0) {

-    args->referral_id = value;

-  } else if (name.CompareNoCase(kExtraArgBrowserType) == 0) {

-    BrowserType type = BROWSER_UNKNOWN;

-    if (SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(value, &type))) {

-      args->browser_type = type;

-    }

-  } else if (name.CompareNoCase(kExtraArgLanguage) == 0) {

-    if (value.GetLength() > kLangMaxLength) {

-      return E_INVALIDARG;

-    }

-    // Even if we don't support the language, we want to pass it to the

-    // installer. Omaha will pick its language later. See http://b/1336966.

-    args->language = value;

-  } else if (name.CompareNoCase(kExtraArgUsageStats) == 0) {

-    if (!String_StringToTristate(value, &args->usage_stats_enable)) {

-      return E_INVALIDARG;

-    }

-

-    // The following args are per app.

-  } else if (name.CompareNoCase(kExtraArgAdditionalParameters) == 0) {

-    cur_extra_app_args_.ap = value;

-  } else if (name.CompareNoCase(kExtraArgTTToken) == 0) {

-    cur_extra_app_args_.tt_token = value;

-  } else if (name.CompareNoCase(kExtraArgAppGuid) == 0) {

-    if (!first_app_) {

-      // Save the arguments for the application we have been processing.

-      args->apps.push_back(cur_extra_app_args_);

-    }

-    cur_extra_app_args_ = CommandLineAppArgs();

-

-    cur_extra_app_args_.app_guid = StringToGuid(value);

-    if (cur_extra_app_args_.app_guid == GUID_NULL) {

-      return E_INVALIDARG;

-    }

-    first_app_ = false;

-  } else if (name.CompareNoCase(kExtraArgAppName) == 0) {

-    if (value.GetLength() > kMaxAppNameLength) {

-      return E_INVALIDARG;

-    }

-    CString trimmed_val = value.Trim();

-    if (trimmed_val.IsEmpty()) {

-      return E_INVALIDARG;

-    }

-

-    // The value is a utf8 encoded url escaped string that is stored as a

-    // unicode string, convert it into a wide string.

-    CString app_name;

-    HRESULT hr = Utf8UrlEncodedStringToWideString(trimmed_val, &app_name);

-    if (FAILED(hr)) {

-      return hr;

-    }

-    cur_extra_app_args_.app_name = app_name;

-  } else if (name.CompareNoCase(kExtraArgNeedsAdmin) == 0) {

-    if (FAILED(String_StringToBool(value, &cur_extra_app_args_.needs_admin))) {

-      return E_INVALIDARG;

-    }

-  } else if (name.CompareNoCase(kExtraArgInstallDataIndex) == 0) {

-    cur_extra_app_args_.install_data_index = value;

-  } else {

-    // Unrecognized token

-    return E_INVALIDARG;

-  }

-

-  return S_OK;

-}

-

-// Handles tokens from the app arguments string.

-HRESULT ExtraArgsParser::HandleAppArgsToken(const CString& token,

-                                            CommandLineExtraArgs* args,

-                                            int* cur_app_args_index) {

-  ASSERT1(args);

-  ASSERT1(cur_app_args_index);

-  ASSERT1(*cur_app_args_index < static_cast<int>(args->apps.size()));

-

-  CString name;

-  CString value;

-  if (!ParseNameValuePair(token, kNameValueSeparatorChar, &name, &value)) {

-    return E_INVALIDARG;

-  }

-

-  if (name.CompareNoCase(kExtraArgAppGuid) == 0) {

-    *cur_app_args_index = -1;

-    for (size_t i = 0; i < args->apps.size(); ++i) {

-      if (!value.CompareNoCase(GuidToString(args->apps[i].app_guid))) {

-        *cur_app_args_index = i;

-        break;

-      }

-    }

-

-    if (-1 == *cur_app_args_index) {

-      return E_INVALIDARG;

-    }

-  } else if (name.CompareNoCase(kExtraArgInstallerData) == 0) {

-    if (-1 == *cur_app_args_index) {

-      return E_INVALIDARG;

-    }

-    args->apps[*cur_app_args_index].encoded_installer_data = value;

-  } else {

-    // Unrecognized token

-    return E_INVALIDARG;

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/extra_args_parser.h"
+
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/goopdate_utils.h"
+
+namespace omaha {
+
+// TODO(omaha): There is no enforcement of required or optional values of
+// the extra arguments. Come up with a way to enforce this.
+HRESULT ExtraArgsParser::Parse(const TCHAR* extra_args,
+                               const TCHAR* app_args,
+                               CommandLineExtraArgs* args) {
+  // TODO(omaha): If we prefix extra_args with '/' and replace all '=' with ' '
+  // and all & with '/' then we should be able to use the CommandLineParser
+  // class to pull out the values here.  We'd need to define scenarios for all
+  // permutations of ExtraArgs, but this shouldn't be difficult to get the right
+  // ones.
+  HRESULT hr = Validate(extra_args);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  first_app_ = true;
+  int pos = 0;
+  CString input_str(extra_args);
+  CString token = input_str.Tokenize(kExtraArgsSeparators, pos);
+  while (!token.IsEmpty()) {
+    CORE_LOG(L2, (_T("[ExtraArgsParser::Parse][token=%s]"), token));
+    hr = HandleToken(token, args);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    // Continue parsing
+    token = input_str.Tokenize(kExtraArgsSeparators, pos);
+  }
+
+  // Save the arguments for the last application.
+  args->apps.push_back(cur_extra_app_args_);
+  return ParseAppArgs(app_args, args);
+}
+
+HRESULT ExtraArgsParser::ParseAppArgs(const TCHAR* app_args,
+                                      CommandLineExtraArgs* args) {
+  if (!app_args || !*app_args) {
+    return S_OK;
+  }
+
+  HRESULT hr = Validate(app_args);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  int cur_app_args_index = -1;
+  int pos = 0;
+  CString input_str = app_args;
+  CString token = input_str.Tokenize(kExtraArgsSeparators, pos);
+  while (!token.IsEmpty()) {
+    CORE_LOG(L2, (_T("[ExtraArgsParser::ParseAppArgs][token=%s]"), token));
+    hr = HandleAppArgsToken(token, args, &cur_app_args_index);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    token = input_str.Tokenize(kExtraArgsSeparators, pos);
+  }
+
+  return S_OK;
+}
+
+HRESULT ExtraArgsParser::Validate(const TCHAR* extra_args) {
+  CString extra_args_str(extra_args);
+  if (extra_args_str.IsEmpty()) {
+    return E_INVALIDARG;
+  }
+
+  if (-1 != extra_args_str.FindOneOf(kDisallowedCharsInExtraArgs)) {
+    // A '/' was found in the "extra" arguments or "extra" arguments were
+    // not specified before the next command.
+    return E_INVALIDARG;
+  }
+
+  return S_OK;
+}
+
+// Handles tokens from the extra arguments string.
+HRESULT ExtraArgsParser::HandleToken(const CString& token,
+                                     CommandLineExtraArgs* args) {
+  CString name;
+  CString value;
+  if (!ParseNameValuePair(token, kNameValueSeparatorChar, &name, &value)) {
+    return E_INVALIDARG;
+  }
+
+  // The first set of args apply to all apps. They may occur at any point, but
+  // only the last occurrence is recorded.
+  if (name.CompareNoCase(kExtraArgInstallationId) == 0) {
+    ASSERT1(!value.IsEmpty());
+    if (FAILED(::CLSIDFromString(const_cast<TCHAR*>(value.GetString()),
+                                 &args->installation_id))) {
+      return E_INVALIDARG;
+    }
+  } else if (name.CompareNoCase(kExtraArgBrandCode) == 0) {
+    if (value.GetLength() > kBrandIdLength) {
+      return E_INVALIDARG;
+    }
+    args->brand_code = value;
+  } else if (name.CompareNoCase(kExtraArgClientId) == 0) {
+    args->client_id = value;
+  } else if (name.CompareNoCase(kExtraArgReferralId) == 0) {
+    args->referral_id = value;
+  } else if (name.CompareNoCase(kExtraArgBrowserType) == 0) {
+    BrowserType type = BROWSER_UNKNOWN;
+    if (SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(value, &type))) {
+      args->browser_type = type;
+    }
+  } else if (name.CompareNoCase(kExtraArgLanguage) == 0) {
+    if (value.GetLength() > kLangMaxLength) {
+      return E_INVALIDARG;
+    }
+    // Even if we don't support the language, we want to pass it to the
+    // installer. Omaha will pick its language later. See http://b/1336966.
+    args->language = value;
+  } else if (name.CompareNoCase(kExtraArgUsageStats) == 0) {
+    if (!String_StringToTristate(value, &args->usage_stats_enable)) {
+      return E_INVALIDARG;
+    }
+
+    // The following args are per app.
+  } else if (name.CompareNoCase(kExtraArgAdditionalParameters) == 0) {
+    cur_extra_app_args_.ap = value;
+  } else if (name.CompareNoCase(kExtraArgTTToken) == 0) {
+    cur_extra_app_args_.tt_token = value;
+  } else if (name.CompareNoCase(kExtraArgAppGuid) == 0) {
+    if (!first_app_) {
+      // Save the arguments for the application we have been processing.
+      args->apps.push_back(cur_extra_app_args_);
+    }
+    cur_extra_app_args_ = CommandLineAppArgs();
+
+    cur_extra_app_args_.app_guid = StringToGuid(value);
+    if (cur_extra_app_args_.app_guid == GUID_NULL) {
+      return E_INVALIDARG;
+    }
+    first_app_ = false;
+  } else if (name.CompareNoCase(kExtraArgAppName) == 0) {
+    if (value.GetLength() > kMaxAppNameLength) {
+      return E_INVALIDARG;
+    }
+    CString trimmed_val = value.Trim();
+    if (trimmed_val.IsEmpty()) {
+      return E_INVALIDARG;
+    }
+
+    // The value is a utf8 encoded url escaped string that is stored as a
+    // unicode string, convert it into a wide string.
+    CString app_name;
+    HRESULT hr = Utf8UrlEncodedStringToWideString(trimmed_val, &app_name);
+    if (FAILED(hr)) {
+      return hr;
+    }
+    cur_extra_app_args_.app_name = app_name;
+  } else if (name.CompareNoCase(kExtraArgNeedsAdmin) == 0) {
+    if (FAILED(String_StringToBool(value, &cur_extra_app_args_.needs_admin))) {
+      return E_INVALIDARG;
+    }
+  } else if (name.CompareNoCase(kExtraArgInstallDataIndex) == 0) {
+    cur_extra_app_args_.install_data_index = value;
+  } else {
+    // Unrecognized token
+    return E_INVALIDARG;
+  }
+
+  return S_OK;
+}
+
+// Handles tokens from the app arguments string.
+HRESULT ExtraArgsParser::HandleAppArgsToken(const CString& token,
+                                            CommandLineExtraArgs* args,
+                                            int* cur_app_args_index) {
+  ASSERT1(args);
+  ASSERT1(cur_app_args_index);
+  ASSERT1(*cur_app_args_index < static_cast<int>(args->apps.size()));
+
+  CString name;
+  CString value;
+  if (!ParseNameValuePair(token, kNameValueSeparatorChar, &name, &value)) {
+    return E_INVALIDARG;
+  }
+
+  if (name.CompareNoCase(kExtraArgAppGuid) == 0) {
+    *cur_app_args_index = -1;
+    for (size_t i = 0; i < args->apps.size(); ++i) {
+      if (!value.CompareNoCase(GuidToString(args->apps[i].app_guid))) {
+        *cur_app_args_index = i;
+        break;
+      }
+    }
+
+    if (-1 == *cur_app_args_index) {
+      return E_INVALIDARG;
+    }
+  } else if (name.CompareNoCase(kExtraArgInstallerData) == 0) {
+    if (-1 == *cur_app_args_index) {
+      return E_INVALIDARG;
+    }
+    args->apps[*cur_app_args_index].encoded_installer_data = value;
+  } else {
+    // Unrecognized token
+    return E_INVALIDARG;
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/extra_args_parser.h b/goopdate/extra_args_parser.h
index 72cb686..106a20a 100644
--- a/goopdate/extra_args_parser.h
+++ b/goopdate/extra_args_parser.h
@@ -1,61 +1,61 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_EXTRA_ARGS_PARSER_H__

-#define OMAHA_GOOPDATE_EXTRA_ARGS_PARSER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "omaha/goopdate/command_line.h"

-

-namespace omaha {

-

-// This class handles tokenizing and parsing the ExtraArgs portion of the

-// command line.

-// The format of the extra arguments is as follows:

-// appguid={}&.....appguid={}....

-// appguid has to be the first value of the extra arguments.

-// Each appguid defines one product.

-class ExtraArgsParser {

- public:

-  ExtraArgsParser() : first_app_(false) {}

-

-  // Parses args->extra_args into other values of args.

-  HRESULT Parse(const TCHAR* extra_args,

-                const TCHAR* app_args,

-                CommandLineExtraArgs* args);

-

- private:

-  HRESULT ParseAppArgs(const TCHAR* app_args, CommandLineExtraArgs* args);

-

-  // Performs validation against extra_args and if it's valid, stores the

-  // extra_args value into args->extra_args.

-  HRESULT Validate(const TCHAR* extra_args);

-  HRESULT HandleToken(const CString& token, CommandLineExtraArgs* args);

-  HRESULT HandleAppArgsToken(const CString& token,

-                             CommandLineExtraArgs* args,

-                             int* cur_app_args_index);

-

-  CommandLineAppArgs cur_extra_app_args_;

-  bool first_app_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(ExtraArgsParser);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_EXTRA_ARGS_PARSER_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_EXTRA_ARGS_PARSER_H__
+#define OMAHA_GOOPDATE_EXTRA_ARGS_PARSER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "omaha/goopdate/command_line.h"
+
+namespace omaha {
+
+// This class handles tokenizing and parsing the ExtraArgs portion of the
+// command line.
+// The format of the extra arguments is as follows:
+// appguid={}&.....appguid={}....
+// appguid has to be the first value of the extra arguments.
+// Each appguid defines one product.
+class ExtraArgsParser {
+ public:
+  ExtraArgsParser() : first_app_(false) {}
+
+  // Parses args->extra_args into other values of args.
+  HRESULT Parse(const TCHAR* extra_args,
+                const TCHAR* app_args,
+                CommandLineExtraArgs* args);
+
+ private:
+  HRESULT ParseAppArgs(const TCHAR* app_args, CommandLineExtraArgs* args);
+
+  // Performs validation against extra_args and if it's valid, stores the
+  // extra_args value into args->extra_args.
+  HRESULT Validate(const TCHAR* extra_args);
+  HRESULT HandleToken(const CString& token, CommandLineExtraArgs* args);
+  HRESULT HandleAppArgsToken(const CString& token,
+                             CommandLineExtraArgs* args,
+                             int* cur_app_args_index);
+
+  CommandLineAppArgs cur_extra_app_args_;
+  bool first_app_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ExtraArgsParser);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_EXTRA_ARGS_PARSER_H__
+
diff --git a/goopdate/extra_args_parser_unittest.cc b/goopdate/extra_args_parser_unittest.cc
index 1fe388d..55bc013 100644
--- a/goopdate/extra_args_parser_unittest.cc
+++ b/goopdate/extra_args_parser_unittest.cc
@@ -1,1304 +1,1304 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/extra_args_parser.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource_manager.h"

-#include "omaha/net/http_client.h"

-#include "omaha/testing/resource.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-extern void VerifyCommandLineArgs(const CommandLineArgs& expected,

-                                  const CommandLineArgs& actual);

-

-extern void VerifyCommandLineExtraArgs(const CommandLineExtraArgs& expected,

-                                       const CommandLineExtraArgs& actual);

-

-void VerifyBrowserType(const CommandLineExtraArgs& args,

-                       const CString& app_guid,

-                       BrowserType type) {

-  CommandLineAppArgs app_args;

-  app_args.app_guid = StringToGuid(app_guid);

-

-  CommandLineExtraArgs expected;

-  expected.browser_type = type;

-  expected.apps.push_back(app_args);

-

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-void VerifyExtraArgsHaveSpecificValues(

-         const CommandLineExtraArgs& args,

-         const CString& app_guid,

-         Tristate expected_usage_stats_enable,

-         const GUID& expected_installation_id,

-         const CString& expected_brand_code,

-         const CString& expected_client_id,

-         const CString& expected_referral_id,

-         const CString& expected_ap,

-         const CString& expected_tt,

-         const CString& expected_encoded_installer_data,

-         const CString& expected_install_data_index) {

-  CommandLineAppArgs app_args;

-  app_args.app_guid = StringToGuid(app_guid);

-  app_args.ap = expected_ap;

-  app_args.tt_token = expected_tt;

-  app_args.encoded_installer_data = expected_encoded_installer_data;

-  app_args.install_data_index = expected_install_data_index;

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-  expected.installation_id = expected_installation_id;

-  expected.brand_code = expected_brand_code;

-  expected.client_id = expected_client_id;

-  expected.referral_id = expected_referral_id;

-  expected.usage_stats_enable = expected_usage_stats_enable;

-

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppName1) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")

-                       _T("appname1=Hello");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppName2) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")

-                       _T("appname= ");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppName3) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-

-  CString app_guid = _T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}");

-  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")

-                       _T("appname=Test");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-

-  app_args.app_name = _T("Test");

-  app_args.app_guid = StringToGuid(app_guid);

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppName4) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")

-                       _T("appname=Test App");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-  app_args.app_guid =

-      StringToGuid(_T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}"));

-  app_args.app_name = _T("Test App");

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppName5) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")

-                       _T("appname= T Ap p ");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-  app_args.app_guid =

-      StringToGuid(_T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}"));

-  app_args.app_name = _T("T Ap p");

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppName6) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")

-                       _T("appname= T Ap p");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-  app_args.app_guid =

-      StringToGuid(_T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}"));

-  app_args.app_name = _T("T Ap p");

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppName7) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  // The size of the application name is limited to 512 wide chars.

-  CString str(_T('a'), 513);

-  CString extra_args;

-  extra_args.Format(_T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")

-                    _T("appname=%s"), str);

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppNameUnicode) {

-  // Read the non-ascii string from the resources, and convert

-  // it into a utf8 encoded, url escaped string.

-  CString non_ascii_name;

-  ASSERT_TRUE(non_ascii_name.LoadString(IDS_ESCAPE_TEST));

-

-  CString wide_tag;

-  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(non_ascii_name,

-                                                            &wide_tag));

-

-  ExtraArgsParser parser;

-  CommandLineExtraArgs args;

-  CString extra_args;

-  extra_args.Format(_T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")

-                    _T("appname=%s"), wide_tag);

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-  app_args.app_name = non_ascii_name;

-  app_args.app_guid =

-      StringToGuid(_T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}"));

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppNameUnicode2) {

-  // Read the non-ascii string from the resources, and convert

-  // it into a utf8 encoded, url escaped string.

-  CString non_ascii_name;

-  ASSERT_TRUE(non_ascii_name.LoadString(IDS_ESCAPE_TEST1));

-

-  CString escaped(_T("%E0%A4%B8%E0%A5%8D%E0%A4%A5%E0%A4%BE%E0%A4%AA%E0%A4%BF")

-                  _T("%E0%A4%A4%20%E0%A4%95%E0%A4%B0%20%E0%A4%B0%E0%A4%B9%E0")

-                  _T("%A4%BE%20%E0%A4%B9%E0%A5%88%E0%A5%A4"));

-

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-

-  CString extra_args;

-  extra_args.Format(_T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")

-                    _T("appname=%s"), escaped);

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-  app_args.app_name = non_ascii_name;

-  app_args.app_guid =

-      StringToGuid(_T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}"));

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppGuid1) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid1=Hello");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAppGuid2) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("")

-                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-  const GUID guid = {0x8617EE50, 0xF91C, 0x4DC1,

-                          {0xB9, 0x37, 0x09, 0x69, 0xEE, 0xF5, 0x9B, 0x0B}};

-  app_args.app_guid = guid;

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin1) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("needsadmin=Hello");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin2) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("needsadmin= ");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin3) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("")

-                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("needsadmin=True");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-  app_args.needs_admin = true;

-  app_args.app_guid =

-      StringToGuid(_T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"));

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin4) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("")

-                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("needsadmin=true");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-  app_args.needs_admin = true;

-  app_args.app_guid =

-      StringToGuid(_T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"));

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin5) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("")

-                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("needsadmin=False");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-  app_args.needs_admin = false;

-  app_args.app_guid =

-      StringToGuid(_T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"));

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin6) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("")

-                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("needsadmin=false");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CommandLineAppArgs app_args;

-  app_args.needs_admin = false;

-  app_args.app_guid =

-      StringToGuid(_T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"));

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(app_args);

-

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-//

-// Test the handling of the contents of the extra arguments.

-//

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAssignmentOnly) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("=");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsExtraAssignment1) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1=");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsExtraAssignment2) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("=usagestats=1");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsExtraAssignment3) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1&=");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsExtraAssignment4) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("=&usagestats=1");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsValueWithoutName) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("=hello");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-

-// Also tests ending extra arguments with '='.

-TEST(ExtraArgsParserTest, ExtraArgumentsNameWithoutValue) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsNameWithoutValueBeforeNextArgument) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("")

-                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=&client=hello");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest,

-     ExtraArgumentsNameWithoutArgumentSeparatorAfterIntValue) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("")

-                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1client=hello");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest,

-     ExtraArgumentsNameWithoutArgumentSeparatorAfterStringValue) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("")

-                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=yesclient=hello");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsHaveDoubleAmpersand) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("")

-                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1&&client=hello");

-

-  CString app_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                     _T("installerdata=foobar");

-

-  // Ideally, this would flag an error.

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, app_args, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_TRUE,

-      GUID_NULL,

-      _T(""),

-      _T("hello"),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T("foobar"),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsAmpersandOnly) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("&");

-

-  // Ideally, this would flag an error.

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_NONE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsBeginInAmpersand) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("&appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1");

-

-  // Ideally, this would flag an error.

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_TRUE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsEndInAmpersand) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("&appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1&");

-

-  // Ideally, this would flag an error.

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_TRUE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsEmptyString) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceOnly1) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T(" ");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceOnly2) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\t");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceOnly3) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\r");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceOnly4) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\n");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceOnly5) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\r\n");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-

-//

-// Test the parsing of the extra command and its arguments into a string.

-//

-

-TEST(ExtraArgsParserTest, ExtraArgumentsOneValid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("&appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_TRUE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsTwoValid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("&appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1&client=hello");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_TRUE,

-      GUID_NULL,

-      _T(""),

-      _T("hello"),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsHaveSwitchInTheMiddle) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1/other_value=9");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsHaveDoubleQuoteInTheMiddle) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1\"/other_value=9");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest,

-       ExtraArgumentsHaveDoubleQuoteInTheMiddleAndNoForwardSlash) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1\"other_value=9");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsHaveSpaceAndForwardSlashBeforeQuote) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1 /other_value=9");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsHaveForwardSlashBeforeQuote) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1/other_value=9");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsSpecifiedTwice) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1\" \"client=10");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceBeforeArgs1) {

-  CommandLineExtraArgs args;

-  // TODO(omaha): This one passes now due to different whitespace

-  // handling.  Remove it?  Is this really a problem to have?

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T(" usagestats=1");

-  ExtraArgsParser parser;

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceBeforeArgs2) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\tappguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceBeforeArgs3) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\rappguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceBeforeArgs4) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\nappguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}")

-                       _T("&usagestats=1");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceBeforeArgs5) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\r\nusagestats=1");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsForwardSlash1) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("/");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsForwardSlash2) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("/ appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsBackwardSlash1) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\\");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsBackwardSlash2) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\\appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ExtraArgumentsBackwardSlash3) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("\\ appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-//

-// Test specific extra commands.

-//

-

-TEST(ExtraArgsParserTest, UsageStatsOutsideExtraCommand) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("/usagestats");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, UsageStatsOn) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=1");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_TRUE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, UsageStatsOff) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=0");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_FALSE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-// This commandline has no effect, but it's permitted.

-TEST(ExtraArgsParserTest, UsageStatsNone) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=2");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_NONE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, UsageStatsInvalidPositiveValue) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=3");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, UsageStatsInvalidNegativeValue) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=-1");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, UsageStatsValueIsString) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("usagestats=true");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, InstallationGuidValid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("iid={98CEC468-9429-4984-AEDE-4F53C6A14869}");

-  const GUID expected_guid = {0x98CEC468, 0x9429, 0x4984,

-                              {0xAE, 0xDE, 0x4F, 0x53, 0xC6, 0xA1, 0x48, 0x69}};

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_NONE,

-      expected_guid,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, InstallationGuidMissingBraces) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("iid=98CEC468-9429-4984-AEDE-4F53C6A14869");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, InstallationGuidMissingDashes) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("iid=98CEC46894294984AEDE4F53C6A14869");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, InstallationGuidMissingCharacter) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("iid=98CEC468-9429-4984-AEDE-4F53C6A1486");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, InstallationGuidIsString) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("iid=hello");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, RlzNotSupported) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("rlz=hithere");

-

-  EXPECT_EQ(E_INVALIDARG, parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, BrandCodeValid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("brand=GOOG");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_NONE,

-      GUID_NULL,

-      _T("GOOG"),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, BrandCodeTooLong) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("brand=CHMI\xe3\x83\xbb");

-

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, ClientIdValid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("client=some_partner");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_NONE,

-      GUID_NULL,

-      _T(""),

-      _T("some_partner"),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, ReferralIdValid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("referral=ABCD123");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_NONE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T("ABCD123"),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, ApValid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("ap=developer");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_NONE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T("developer"),

-      _T(""),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, TTValid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("tttoken=7839g93");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_NONE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T("7839g93"),

-      _T(""),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, AppArgsValid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("tttoken=7839g93");

-

-  CString app_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                     _T("installerdata=%E0%A4foobar");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, app_args, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_NONE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T("7839g93"),

-      _T("%E0%A4foobar"),

-      _T(""));

-}

-

-TEST(ExtraArgsParserTest, AppArgsInvalidAppGuid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("tttoken=7839g93");

-

-  CString app_args = _T("appguid={E135384F-85A2-4328-B07D-2CF70313D505}&")

-                     _T("installerdata=%E0%A4foobar");

-

-  EXPECT_EQ(E_INVALIDARG, parser.Parse(extra_args, app_args, &args));

-}

-

-TEST(ExtraArgsParserTest, AppArgsInvalidAttribute) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("tttoken=7839g93");

-

-  CString app_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                     _T("tttoken=foobar");

-

-  EXPECT_EQ(E_INVALIDARG, parser.Parse(extra_args, app_args, &args));

-}

-

-TEST(ExtraArgsParserTest, InstallerDataNotAllowedInExtraArgs) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("appname=TestApp2&")

-                       _T("needsadmin=true&")

-                       _T("installerdata=Hello%20World");

-

-  EXPECT_EQ(E_INVALIDARG, parser.Parse(extra_args, NULL, &args));

-}

-

-TEST(ExtraArgsParserTest, InstallDataIndexValid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("installdataindex=foobar");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyExtraArgsHaveSpecificValues(

-      args,

-      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-      TRISTATE_NONE,

-      GUID_NULL,

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T(""),

-      _T("foobar"));

-}

-

-TEST(ExtraArgsParserTest, BrowserTypeValid_0) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("browser=0");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyBrowserType(args,

-                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-                    BROWSER_UNKNOWN);

-}

-

-TEST(ExtraArgsParserTest, BrowserTypeValid_1) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("browser=1");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyBrowserType(args,

-                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-                    BROWSER_DEFAULT);

-}

-

-TEST(ExtraArgsParserTest, BrowserTypeValid_2) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("browser=2");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyBrowserType(args,

-                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-                    BROWSER_IE);

-}

-

-TEST(ExtraArgsParserTest, BrowserTypeValid_3) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("browser=3");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyBrowserType(args,

-                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-                    BROWSER_FIREFOX);

-}

-

-TEST(ExtraArgsParserTest, BrowserTypeValid_4) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("browser=4");

-

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  VerifyBrowserType(args,

-                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-                    BROWSER_CHROME);

-}

-

-TEST(ExtraArgsParserTest, BrowserTypeInvalid) {

-  EXPECT_EQ(5, BROWSER_MAX) <<

-      _T("Browser type may have been added. Add new Valid_n test and change ")

-      _T("browser values in extra args strings below.");

-

-  CommandLineExtraArgs args1;

-  ExtraArgsParser parser1;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("browser=5");

-

-  EXPECT_SUCCEEDED(parser1.Parse(extra_args, NULL, &args1));

-  VerifyBrowserType(args1,

-                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-                    BROWSER_UNKNOWN);

-

-  CommandLineExtraArgs args2;

-  ExtraArgsParser parser2;

-  extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-               _T("browser=9");

-

-  EXPECT_SUCCEEDED(parser2.Parse(extra_args, NULL, &args2));

-  VerifyBrowserType(args2,

-                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),

-                    BROWSER_UNKNOWN);

-}

-

-TEST(ExtraArgsParserTest, ValidLang) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("lang=en");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  EXPECT_STREQ(_T("en"), args.language);

-}

-

-// Language must be passed even if not supported. See http://b/1336966.

-TEST(ExtraArgsParserTest, UnsupportedLang) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("lang=foobar");

-  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-  EXPECT_STREQ(_T("foobar"), args.language);

-}

-

-TEST(ExtraArgsParserTest, LangTooLong) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("lang=morethan10chars");

-  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));

-}

-

-//

-// Test multiple applications in the extra arguments

-//

-TEST(ExtraArgsParserTestMultipleEntries, TestNotStartingWithAppGuid) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appname=TestApp&")

-                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("appname=TestApp&")

-                       _T("appname=false&")

-                       _T("iid={98CEC468-9429-4984-AEDE-4F53C6A14869}&")

-                       _T("ap=test_ap&")

-                       _T("tttoken=foobar&")

-                       _T("usagestats=1&")

-                       _T("browser=2&");

-  EXPECT_HRESULT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-}

-

-// This also tests that the last occurrence of a global extra arg is the one

-// that is saved.

-TEST(ExtraArgsParserTestMultipleEntries, ThreeApplications) {

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                       _T("appname=TestApp&")

-                       _T("needsadmin=false&")

-                       _T("iid={98CEC468-9429-4984-AEDE-4F53C6A14869}&")

-                       _T("ap=test_ap&")

-                       _T("tttoken=foobar&")

-                       _T("usagestats=1&")

-                       _T("browser=2&")

-                       _T("brand=GOOG&")

-                       _T("client=_some_client&")

-                       _T("referral=A123456789&")

-                       _T("appguid={5E46DE36-737D-4271-91C1-C062F9FE21D9}&")

-                       _T("appname=TestApp2&")

-                       _T("needsadmin=true&")

-                       _T("iid={98CEC468-9429-4984-AEDE-4F53C6A14869}&")

-                       _T("ap=test_ap2&")

-                       _T("tttoken=foobar2&")

-                       _T("usagestats=0&")

-                       _T("browser=3&")

-                       _T("brand=g00g&")

-                       _T("client=_different_client&")

-                       _T("appguid={5F46DE36-737D-4271-91C1-C062F9FE21D9}&")

-                       _T("appname=TestApp3");

-

-  CString app_args = _T("appguid={5F46DE36-737D-4271-91C1-C062F9FE21D9}&")

-                     _T("installerdata=installerdata_app3&")

-                     _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")

-                     _T("installerdata=installerdata_app1");

-

-  EXPECT_HRESULT_SUCCEEDED(parser.Parse(extra_args, app_args, &args));

-

-  CommandLineAppArgs input1;

-  input1.app_guid = StringToGuid(_T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"));

-  input1.app_name = _T("TestApp");

-  input1.needs_admin = false;

-  input1.ap = _T("test_ap");

-  input1.tt_token = _T("foobar");

-  input1.encoded_installer_data = _T("installerdata_app1");

-

-  CommandLineAppArgs input2;

-  input2.app_guid = StringToGuid(_T("{5E46DE36-737D-4271-91C1-C062F9FE21D9}"));

-  input2.app_name = _T("TestApp2");

-  input2.needs_admin = true;

-  input2.ap = _T("test_ap2");

-  input2.tt_token = _T("foobar2");

-

-  CommandLineAppArgs input3;

-  input3.app_guid = StringToGuid(_T("{5F46DE36-737D-4271-91C1-C062F9FE21D9}"));

-  input3.app_name = _T("TestApp3");

-  input3.encoded_installer_data = _T("installerdata_app3");

-

-  CommandLineExtraArgs expected;

-  expected.apps.push_back(input1);

-  expected.apps.push_back(input2);

-  expected.apps.push_back(input3);

-  expected.installation_id = StringToGuid(

-      _T("{98CEC468-9429-4984-AEDE-4F53C6A14869}"));

-  expected.brand_code = _T("g00g");

-  expected.client_id = _T("_different_client");

-  expected.referral_id = _T("A123456789");

-  expected.browser_type = BROWSER_FIREFOX;

-  expected.usage_stats_enable = TRISTATE_FALSE;

-

-  VerifyCommandLineExtraArgs(expected, args);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/extra_args_parser.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource_manager.h"
+#include "omaha/net/http_client.h"
+#include "omaha/testing/resource.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+extern void VerifyCommandLineArgs(const CommandLineArgs& expected,
+                                  const CommandLineArgs& actual);
+
+extern void VerifyCommandLineExtraArgs(const CommandLineExtraArgs& expected,
+                                       const CommandLineExtraArgs& actual);
+
+void VerifyBrowserType(const CommandLineExtraArgs& args,
+                       const CString& app_guid,
+                       BrowserType type) {
+  CommandLineAppArgs app_args;
+  app_args.app_guid = StringToGuid(app_guid);
+
+  CommandLineExtraArgs expected;
+  expected.browser_type = type;
+  expected.apps.push_back(app_args);
+
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+void VerifyExtraArgsHaveSpecificValues(
+         const CommandLineExtraArgs& args,
+         const CString& app_guid,
+         Tristate expected_usage_stats_enable,
+         const GUID& expected_installation_id,
+         const CString& expected_brand_code,
+         const CString& expected_client_id,
+         const CString& expected_referral_id,
+         const CString& expected_ap,
+         const CString& expected_tt,
+         const CString& expected_encoded_installer_data,
+         const CString& expected_install_data_index) {
+  CommandLineAppArgs app_args;
+  app_args.app_guid = StringToGuid(app_guid);
+  app_args.ap = expected_ap;
+  app_args.tt_token = expected_tt;
+  app_args.encoded_installer_data = expected_encoded_installer_data;
+  app_args.install_data_index = expected_install_data_index;
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+  expected.installation_id = expected_installation_id;
+  expected.brand_code = expected_brand_code;
+  expected.client_id = expected_client_id;
+  expected.referral_id = expected_referral_id;
+  expected.usage_stats_enable = expected_usage_stats_enable;
+
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppName1) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")
+                       _T("appname1=Hello");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppName2) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")
+                       _T("appname= ");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppName3) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+
+  CString app_guid = _T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}");
+  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")
+                       _T("appname=Test");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+
+  app_args.app_name = _T("Test");
+  app_args.app_guid = StringToGuid(app_guid);
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppName4) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")
+                       _T("appname=Test App");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+  app_args.app_guid =
+      StringToGuid(_T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}"));
+  app_args.app_name = _T("Test App");
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppName5) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")
+                       _T("appname= T Ap p ");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+  app_args.app_guid =
+      StringToGuid(_T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}"));
+  app_args.app_name = _T("T Ap p");
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppName6) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")
+                       _T("appname= T Ap p");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+  app_args.app_guid =
+      StringToGuid(_T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}"));
+  app_args.app_name = _T("T Ap p");
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppName7) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  // The size of the application name is limited to 512 wide chars.
+  CString str(_T('a'), 513);
+  CString extra_args;
+  extra_args.Format(_T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")
+                    _T("appname=%s"), str);
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppNameUnicode) {
+  // Read the non-ascii string from the resources, and convert
+  // it into a utf8 encoded, url escaped string.
+  CString non_ascii_name;
+  ASSERT_TRUE(non_ascii_name.LoadString(IDS_ESCAPE_TEST));
+
+  CString wide_tag;
+  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(non_ascii_name,
+                                                            &wide_tag));
+
+  ExtraArgsParser parser;
+  CommandLineExtraArgs args;
+  CString extra_args;
+  extra_args.Format(_T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")
+                    _T("appname=%s"), wide_tag);
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+  app_args.app_name = non_ascii_name;
+  app_args.app_guid =
+      StringToGuid(_T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}"));
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppNameUnicode2) {
+  // Read the non-ascii string from the resources, and convert
+  // it into a utf8 encoded, url escaped string.
+  CString non_ascii_name;
+  ASSERT_TRUE(non_ascii_name.LoadString(IDS_ESCAPE_TEST1));
+
+  CString escaped(_T("%E0%A4%B8%E0%A5%8D%E0%A4%A5%E0%A4%BE%E0%A4%AA%E0%A4%BF")
+                  _T("%E0%A4%A4%20%E0%A4%95%E0%A4%B0%20%E0%A4%B0%E0%A4%B9%E0")
+                  _T("%A4%BE%20%E0%A4%B9%E0%A5%88%E0%A5%A4"));
+
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+
+  CString extra_args;
+  extra_args.Format(_T("appguid={D0324988-DA8A-49e5-BCE5-925FCD04EAB7}&")
+                    _T("appname=%s"), escaped);
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+  app_args.app_name = non_ascii_name;
+  app_args.app_guid =
+      StringToGuid(_T("{D0324988-DA8A-49e5-BCE5-925FCD04EAB7}"));
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppGuid1) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid1=Hello");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAppGuid2) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("")
+                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+  const GUID guid = {0x8617EE50, 0xF91C, 0x4DC1,
+                          {0xB9, 0x37, 0x09, 0x69, 0xEE, 0xF5, 0x9B, 0x0B}};
+  app_args.app_guid = guid;
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin1) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("needsadmin=Hello");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin2) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("needsadmin= ");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin3) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("")
+                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("needsadmin=True");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+  app_args.needs_admin = true;
+  app_args.app_guid =
+      StringToGuid(_T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"));
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin4) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("")
+                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("needsadmin=true");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+  app_args.needs_admin = true;
+  app_args.app_guid =
+      StringToGuid(_T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"));
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin5) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("")
+                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("needsadmin=False");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+  app_args.needs_admin = false;
+  app_args.app_guid =
+      StringToGuid(_T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"));
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsNeedsAdmin6) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("")
+                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("needsadmin=false");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CommandLineAppArgs app_args;
+  app_args.needs_admin = false;
+  app_args.app_guid =
+      StringToGuid(_T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"));
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(app_args);
+
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+//
+// Test the handling of the contents of the extra arguments.
+//
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAssignmentOnly) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("=");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsExtraAssignment1) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1=");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsExtraAssignment2) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("=usagestats=1");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsExtraAssignment3) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1&=");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsExtraAssignment4) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("=&usagestats=1");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsValueWithoutName) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("=hello");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+
+// Also tests ending extra arguments with '='.
+TEST(ExtraArgsParserTest, ExtraArgumentsNameWithoutValue) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsNameWithoutValueBeforeNextArgument) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("")
+                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=&client=hello");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest,
+     ExtraArgumentsNameWithoutArgumentSeparatorAfterIntValue) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("")
+                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1client=hello");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest,
+     ExtraArgumentsNameWithoutArgumentSeparatorAfterStringValue) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("")
+                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=yesclient=hello");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsHaveDoubleAmpersand) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("")
+                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1&&client=hello");
+
+  CString app_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                     _T("installerdata=foobar");
+
+  // Ideally, this would flag an error.
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, app_args, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_TRUE,
+      GUID_NULL,
+      _T(""),
+      _T("hello"),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T("foobar"),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsAmpersandOnly) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("&");
+
+  // Ideally, this would flag an error.
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_NONE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsBeginInAmpersand) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("&appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1");
+
+  // Ideally, this would flag an error.
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_TRUE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsEndInAmpersand) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("&appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1&");
+
+  // Ideally, this would flag an error.
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_TRUE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsEmptyString) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceOnly1) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T(" ");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceOnly2) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\t");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceOnly3) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\r");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceOnly4) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\n");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceOnly5) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\r\n");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+
+//
+// Test the parsing of the extra command and its arguments into a string.
+//
+
+TEST(ExtraArgsParserTest, ExtraArgumentsOneValid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("&appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_TRUE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsTwoValid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("&appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1&client=hello");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_TRUE,
+      GUID_NULL,
+      _T(""),
+      _T("hello"),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsHaveSwitchInTheMiddle) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1/other_value=9");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsHaveDoubleQuoteInTheMiddle) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1\"/other_value=9");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest,
+       ExtraArgumentsHaveDoubleQuoteInTheMiddleAndNoForwardSlash) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1\"other_value=9");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsHaveSpaceAndForwardSlashBeforeQuote) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1 /other_value=9");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsHaveForwardSlashBeforeQuote) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1/other_value=9");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsSpecifiedTwice) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1\" \"client=10");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceBeforeArgs1) {
+  CommandLineExtraArgs args;
+  // TODO(omaha): This one passes now due to different whitespace
+  // handling.  Remove it?  Is this really a problem to have?
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T(" usagestats=1");
+  ExtraArgsParser parser;
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceBeforeArgs2) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\tappguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceBeforeArgs3) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\rappguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceBeforeArgs4) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\nappguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}")
+                       _T("&usagestats=1");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsWhiteSpaceBeforeArgs5) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\r\nusagestats=1");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsForwardSlash1) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("/");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsForwardSlash2) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("/ appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsBackwardSlash1) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\\");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsBackwardSlash2) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\\appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ExtraArgumentsBackwardSlash3) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("\\ appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+//
+// Test specific extra commands.
+//
+
+TEST(ExtraArgsParserTest, UsageStatsOutsideExtraCommand) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("/usagestats");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, UsageStatsOn) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=1");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_TRUE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, UsageStatsOff) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=0");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_FALSE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+// This commandline has no effect, but it's permitted.
+TEST(ExtraArgsParserTest, UsageStatsNone) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=2");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_NONE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, UsageStatsInvalidPositiveValue) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=3");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, UsageStatsInvalidNegativeValue) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=-1");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, UsageStatsValueIsString) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("usagestats=true");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, InstallationGuidValid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("iid={98CEC468-9429-4984-AEDE-4F53C6A14869}");
+  const GUID expected_guid = {0x98CEC468, 0x9429, 0x4984,
+                              {0xAE, 0xDE, 0x4F, 0x53, 0xC6, 0xA1, 0x48, 0x69}};
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_NONE,
+      expected_guid,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, InstallationGuidMissingBraces) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("iid=98CEC468-9429-4984-AEDE-4F53C6A14869");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, InstallationGuidMissingDashes) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("iid=98CEC46894294984AEDE4F53C6A14869");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, InstallationGuidMissingCharacter) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("iid=98CEC468-9429-4984-AEDE-4F53C6A1486");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, InstallationGuidIsString) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("iid=hello");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, RlzNotSupported) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("rlz=hithere");
+
+  EXPECT_EQ(E_INVALIDARG, parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, BrandCodeValid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("brand=GOOG");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_NONE,
+      GUID_NULL,
+      _T("GOOG"),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, BrandCodeTooLong) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("brand=CHMI\xe3\x83\xbb");
+
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, ClientIdValid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("client=some_partner");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_NONE,
+      GUID_NULL,
+      _T(""),
+      _T("some_partner"),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, ReferralIdValid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("referral=ABCD123");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_NONE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T("ABCD123"),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, ApValid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("ap=developer");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_NONE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T("developer"),
+      _T(""),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, TTValid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("tttoken=7839g93");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_NONE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T("7839g93"),
+      _T(""),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, AppArgsValid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("tttoken=7839g93");
+
+  CString app_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                     _T("installerdata=%E0%A4foobar");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, app_args, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_NONE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T("7839g93"),
+      _T("%E0%A4foobar"),
+      _T(""));
+}
+
+TEST(ExtraArgsParserTest, AppArgsInvalidAppGuid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("tttoken=7839g93");
+
+  CString app_args = _T("appguid={E135384F-85A2-4328-B07D-2CF70313D505}&")
+                     _T("installerdata=%E0%A4foobar");
+
+  EXPECT_EQ(E_INVALIDARG, parser.Parse(extra_args, app_args, &args));
+}
+
+TEST(ExtraArgsParserTest, AppArgsInvalidAttribute) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("tttoken=7839g93");
+
+  CString app_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                     _T("tttoken=foobar");
+
+  EXPECT_EQ(E_INVALIDARG, parser.Parse(extra_args, app_args, &args));
+}
+
+TEST(ExtraArgsParserTest, InstallerDataNotAllowedInExtraArgs) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("appname=TestApp2&")
+                       _T("needsadmin=true&")
+                       _T("installerdata=Hello%20World");
+
+  EXPECT_EQ(E_INVALIDARG, parser.Parse(extra_args, NULL, &args));
+}
+
+TEST(ExtraArgsParserTest, InstallDataIndexValid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("installdataindex=foobar");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyExtraArgsHaveSpecificValues(
+      args,
+      _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+      TRISTATE_NONE,
+      GUID_NULL,
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T(""),
+      _T("foobar"));
+}
+
+TEST(ExtraArgsParserTest, BrowserTypeValid_0) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("browser=0");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyBrowserType(args,
+                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+                    BROWSER_UNKNOWN);
+}
+
+TEST(ExtraArgsParserTest, BrowserTypeValid_1) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("browser=1");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyBrowserType(args,
+                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+                    BROWSER_DEFAULT);
+}
+
+TEST(ExtraArgsParserTest, BrowserTypeValid_2) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("browser=2");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyBrowserType(args,
+                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+                    BROWSER_IE);
+}
+
+TEST(ExtraArgsParserTest, BrowserTypeValid_3) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("browser=3");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyBrowserType(args,
+                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+                    BROWSER_FIREFOX);
+}
+
+TEST(ExtraArgsParserTest, BrowserTypeValid_4) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("browser=4");
+
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  VerifyBrowserType(args,
+                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+                    BROWSER_CHROME);
+}
+
+TEST(ExtraArgsParserTest, BrowserTypeInvalid) {
+  EXPECT_EQ(5, BROWSER_MAX) <<
+      _T("Browser type may have been added. Add new Valid_n test and change ")
+      _T("browser values in extra args strings below.");
+
+  CommandLineExtraArgs args1;
+  ExtraArgsParser parser1;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("browser=5");
+
+  EXPECT_SUCCEEDED(parser1.Parse(extra_args, NULL, &args1));
+  VerifyBrowserType(args1,
+                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+                    BROWSER_UNKNOWN);
+
+  CommandLineExtraArgs args2;
+  ExtraArgsParser parser2;
+  extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+               _T("browser=9");
+
+  EXPECT_SUCCEEDED(parser2.Parse(extra_args, NULL, &args2));
+  VerifyBrowserType(args2,
+                    _T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"),
+                    BROWSER_UNKNOWN);
+}
+
+TEST(ExtraArgsParserTest, ValidLang) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("lang=en");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  EXPECT_STREQ(_T("en"), args.language);
+}
+
+// Language must be passed even if not supported. See http://b/1336966.
+TEST(ExtraArgsParserTest, UnsupportedLang) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("lang=foobar");
+  EXPECT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+  EXPECT_STREQ(_T("foobar"), args.language);
+}
+
+TEST(ExtraArgsParserTest, LangTooLong) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("lang=morethan10chars");
+  EXPECT_FAILED(parser.Parse(extra_args, NULL, &args));
+}
+
+//
+// Test multiple applications in the extra arguments
+//
+TEST(ExtraArgsParserTestMultipleEntries, TestNotStartingWithAppGuid) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appname=TestApp&")
+                       _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("appname=TestApp&")
+                       _T("appname=false&")
+                       _T("iid={98CEC468-9429-4984-AEDE-4F53C6A14869}&")
+                       _T("ap=test_ap&")
+                       _T("tttoken=foobar&")
+                       _T("usagestats=1&")
+                       _T("browser=2&");
+  EXPECT_HRESULT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+}
+
+// This also tests that the last occurrence of a global extra arg is the one
+// that is saved.
+TEST(ExtraArgsParserTestMultipleEntries, ThreeApplications) {
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  CString extra_args = _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                       _T("appname=TestApp&")
+                       _T("needsadmin=false&")
+                       _T("iid={98CEC468-9429-4984-AEDE-4F53C6A14869}&")
+                       _T("ap=test_ap&")
+                       _T("tttoken=foobar&")
+                       _T("usagestats=1&")
+                       _T("browser=2&")
+                       _T("brand=GOOG&")
+                       _T("client=_some_client&")
+                       _T("referral=A123456789&")
+                       _T("appguid={5E46DE36-737D-4271-91C1-C062F9FE21D9}&")
+                       _T("appname=TestApp2&")
+                       _T("needsadmin=true&")
+                       _T("iid={98CEC468-9429-4984-AEDE-4F53C6A14869}&")
+                       _T("ap=test_ap2&")
+                       _T("tttoken=foobar2&")
+                       _T("usagestats=0&")
+                       _T("browser=3&")
+                       _T("brand=g00g&")
+                       _T("client=_different_client&")
+                       _T("appguid={5F46DE36-737D-4271-91C1-C062F9FE21D9}&")
+                       _T("appname=TestApp3");
+
+  CString app_args = _T("appguid={5F46DE36-737D-4271-91C1-C062F9FE21D9}&")
+                     _T("installerdata=installerdata_app3&")
+                     _T("appguid={8617EE50-F91C-4DC1-B937-0969EEF59B0B}&")
+                     _T("installerdata=installerdata_app1");
+
+  EXPECT_HRESULT_SUCCEEDED(parser.Parse(extra_args, app_args, &args));
+
+  CommandLineAppArgs input1;
+  input1.app_guid = StringToGuid(_T("{8617EE50-F91C-4DC1-B937-0969EEF59B0B}"));
+  input1.app_name = _T("TestApp");
+  input1.needs_admin = false;
+  input1.ap = _T("test_ap");
+  input1.tt_token = _T("foobar");
+  input1.encoded_installer_data = _T("installerdata_app1");
+
+  CommandLineAppArgs input2;
+  input2.app_guid = StringToGuid(_T("{5E46DE36-737D-4271-91C1-C062F9FE21D9}"));
+  input2.app_name = _T("TestApp2");
+  input2.needs_admin = true;
+  input2.ap = _T("test_ap2");
+  input2.tt_token = _T("foobar2");
+
+  CommandLineAppArgs input3;
+  input3.app_guid = StringToGuid(_T("{5F46DE36-737D-4271-91C1-C062F9FE21D9}"));
+  input3.app_name = _T("TestApp3");
+  input3.encoded_installer_data = _T("installerdata_app3");
+
+  CommandLineExtraArgs expected;
+  expected.apps.push_back(input1);
+  expected.apps.push_back(input2);
+  expected.apps.push_back(input3);
+  expected.installation_id = StringToGuid(
+      _T("{98CEC468-9429-4984-AEDE-4F53C6A14869}"));
+  expected.brand_code = _T("g00g");
+  expected.client_id = _T("_different_client");
+  expected.referral_id = _T("A123456789");
+  expected.browser_type = BROWSER_FIREFOX;
+  expected.usage_stats_enable = TRISTATE_FALSE;
+
+  VerifyCommandLineExtraArgs(expected, args);
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/google_update.cc b/goopdate/google_update.cc
index 083c616..a33b11a 100644
--- a/goopdate/google_update.cc
+++ b/goopdate/google_update.cc
@@ -1,167 +1,167 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Contains the ATL exe server used for OnDemand, as well as the ProcessLauncher

-// server used to launch a process.

-// The ProcessLauncher server is to be used only by the machine google update.

-// The idea is that the machine Google Update is elevated and launching

-// a process, say a browser, from that elevated process. This will cause the

-// browser to run elevated, which is a bad idea.

-// What is needed is the ability to run medium integrity processes from a

-// high integrity process. This can be done in two ways:

-// 1. Create a service and expose some form of IPC. A service is required

-//    because admins (even elevated) cannot call CreateProcessAsUser. Admins

-//    do not posess the required privilege. However the local system account

-//    has this privilege to call CreateProcessAsUser and hence can be used to

-//    start the browser with the token of a medium integrity process.

-// 2. Create a COM local server. Impersonate a medium integrity user in the

-//    client. Fortunately the impersonation works, then create instance the COM

-//    local server. If the COM security is set to use DYNAMIC_CLOAKING, then

-//    the local server will be created using the thread credentials, allowing

-//    the COM local server to be launched as medium integrity.

-// This class implements the second method listed above.

-// The server listens to the machine google update's shut down event.

-

-#include "omaha/goopdate/google_update.h"

-

-#include <windows.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/event_handler.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/reactor.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/google_update_idl_datax.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/worker/worker.h"

-

-namespace omaha {

-

-GoogleUpdate::GoogleUpdate() {}

-

-GoogleUpdate::~GoogleUpdate() {}

-

-HRESULT GoogleUpdate::Main() {

-  // Disable the delay on shutdown mechanism inside ATL.

-  m_bDelayShutdown = false;

-  return CAtlExeModuleT<GoogleUpdate>::WinMain(0);

-}

-

-bool ShouldRegisterClsid(const CLSID& clsid) {

-  bool is_machine = goopdate_utils::IsRunningFromOfficialGoopdateDir(true);

-

-  // Machine-only CLSIDs.

-  if (IsEqualGUID(clsid, __uuidof(ProcessLauncherClass)) ||

-      IsEqualGUID(clsid, __uuidof(OnDemandMachineAppsClass))) {

-    return is_machine;

-  }

-

-  // User-only CLSIDs.

-  if (IsEqualGUID(clsid, __uuidof(OnDemandUserAppsClass))) {

-    return !is_machine;

-  }

-

-  // Unknown CLSIDs.

-  ASSERT(false, (_T("[Unknown CLSID][%s]"), GuidToString(clsid)));

-  return false;

-}

-

-HRESULT GoogleUpdate::RegisterClassObjects(DWORD, DWORD) throw() {

-  HRESULT hr = S_FALSE;

-  for (_ATL_OBJMAP_ENTRY** entry = _AtlComModule.m_ppAutoObjMapFirst;

-       entry < _AtlComModule.m_ppAutoObjMapLast && SUCCEEDED(hr);

-       entry++) {

-    if (*entry != NULL && ShouldRegisterClsid(*(*entry)->pclsid)) {

-      hr = (*entry)->RegisterClassObject(CLSCTX_LOCAL_SERVER,

-                                           REGCLS_SINGLEUSE | REGCLS_SUSPENDED);

-    }

-  }

-

-  return hr;

-}

-HRESULT GoogleUpdate::RevokeClassObjects() throw() {

-    return AtlComModuleRevokeClassObjects(&_AtlComModule);

-}

-

-HRESULT RegisterOrUnregisterExe(bool is_register) {

-  HRESULT hr = S_FALSE;

-  for (_ATL_OBJMAP_ENTRY** entry = _AtlComModule.m_ppAutoObjMapFirst;

-       entry < _AtlComModule.m_ppAutoObjMapLast && SUCCEEDED(hr);

-       entry++) {

-    if (*entry != NULL) {

-      const CLSID& clsid = *(*entry)->pclsid;

-      if (!ShouldRegisterClsid(clsid)) {

-        continue;

-      }

-

-      hr = is_register ? _AtlComModule.RegisterServer(false, &clsid) :

-                         _AtlComModule.UnregisterServer(false, &clsid);

-      ASSERT(SUCCEEDED(hr), (_T("[RegisterOrUnregisterExe fail][%d][0x%x][%s]"),

-                             is_register, hr, GuidToString(clsid)));

-    }

-  }

-

-  return hr;

-}

-

-HRESULT RegisterOrUnregisterProxy(bool is_register) {

-  HRESULT hr = is_register ? PrxDllRegisterServer() : PrxDllUnregisterServer();

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[RegisterOrUnregisterProxy failed][%d][0x%x]"),

-                  is_register, hr));

-  }

-  return hr;

-}

-

-HRESULT GoogleUpdate::RegisterServer(BOOL, const CLSID*) throw() {

-  HRESULT hr = goopdate_utils::RegisterOrUnregisterModule(

-      true, &RegisterOrUnregisterProxy);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return goopdate_utils::RegisterOrUnregisterModule(true,

-                                                    &RegisterOrUnregisterExe);

-}

-

-HRESULT GoogleUpdate::UnregisterServer(BOOL, const CLSID*) throw() {

-  HRESULT hr = goopdate_utils::RegisterOrUnregisterModule(

-      false, &RegisterOrUnregisterExe);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return goopdate_utils::RegisterOrUnregisterModule(false,

-                                                    &RegisterOrUnregisterProxy);

-}

-

-HRESULT GoogleUpdate::PreMessageLoop(int show_cmd) throw() {

-  bool is_machine = goopdate_utils::IsRunningFromOfficialGoopdateDir(true);

-  worker_.reset(new Worker(is_machine));

-  return CAtlExeModuleT<GoogleUpdate>::PreMessageLoop(show_cmd);

-}

-

-HRESULT GoogleUpdate::PostMessageLoop() throw() {

-  HRESULT hr = CAtlExeModuleT<GoogleUpdate>::PostMessageLoop();

-  worker_.reset();

-  return hr;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Contains the ATL exe server used for OnDemand, as well as the ProcessLauncher
+// server used to launch a process.
+// The ProcessLauncher server is to be used only by the machine google update.
+// The idea is that the machine Google Update is elevated and launching
+// a process, say a browser, from that elevated process. This will cause the
+// browser to run elevated, which is a bad idea.
+// What is needed is the ability to run medium integrity processes from a
+// high integrity process. This can be done in two ways:
+// 1. Create a service and expose some form of IPC. A service is required
+//    because admins (even elevated) cannot call CreateProcessAsUser. Admins
+//    do not posess the required privilege. However the local system account
+//    has this privilege to call CreateProcessAsUser and hence can be used to
+//    start the browser with the token of a medium integrity process.
+// 2. Create a COM local server. Impersonate a medium integrity user in the
+//    client. Fortunately the impersonation works, then create instance the COM
+//    local server. If the COM security is set to use DYNAMIC_CLOAKING, then
+//    the local server will be created using the thread credentials, allowing
+//    the COM local server to be launched as medium integrity.
+// This class implements the second method listed above.
+// The server listens to the machine google update's shut down event.
+
+#include "omaha/goopdate/google_update.h"
+
+#include <windows.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/event_handler.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/reactor.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/google_update_idl_datax.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/worker/worker.h"
+
+namespace omaha {
+
+GoogleUpdate::GoogleUpdate() {}
+
+GoogleUpdate::~GoogleUpdate() {}
+
+HRESULT GoogleUpdate::Main() {
+  // Disable the delay on shutdown mechanism inside ATL.
+  m_bDelayShutdown = false;
+  return CAtlExeModuleT<GoogleUpdate>::WinMain(0);
+}
+
+bool ShouldRegisterClsid(const CLSID& clsid) {
+  bool is_machine = goopdate_utils::IsRunningFromOfficialGoopdateDir(true);
+
+  // Machine-only CLSIDs.
+  if (IsEqualGUID(clsid, __uuidof(ProcessLauncherClass)) ||
+      IsEqualGUID(clsid, __uuidof(OnDemandMachineAppsClass))) {
+    return is_machine;
+  }
+
+  // User-only CLSIDs.
+  if (IsEqualGUID(clsid, __uuidof(OnDemandUserAppsClass))) {
+    return !is_machine;
+  }
+
+  // Unknown CLSIDs.
+  ASSERT(false, (_T("[Unknown CLSID][%s]"), GuidToString(clsid)));
+  return false;
+}
+
+HRESULT GoogleUpdate::RegisterClassObjects(DWORD, DWORD) throw() {
+  HRESULT hr = S_FALSE;
+  for (_ATL_OBJMAP_ENTRY** entry = _AtlComModule.m_ppAutoObjMapFirst;
+       entry < _AtlComModule.m_ppAutoObjMapLast && SUCCEEDED(hr);
+       entry++) {
+    if (*entry != NULL && ShouldRegisterClsid(*(*entry)->pclsid)) {
+      hr = (*entry)->RegisterClassObject(CLSCTX_LOCAL_SERVER,
+                                           REGCLS_SINGLEUSE | REGCLS_SUSPENDED);
+    }
+  }
+
+  return hr;
+}
+HRESULT GoogleUpdate::RevokeClassObjects() throw() {
+    return AtlComModuleRevokeClassObjects(&_AtlComModule);
+}
+
+HRESULT RegisterOrUnregisterExe(bool is_register) {
+  HRESULT hr = S_FALSE;
+  for (_ATL_OBJMAP_ENTRY** entry = _AtlComModule.m_ppAutoObjMapFirst;
+       entry < _AtlComModule.m_ppAutoObjMapLast && SUCCEEDED(hr);
+       entry++) {
+    if (*entry != NULL) {
+      const CLSID& clsid = *(*entry)->pclsid;
+      if (!ShouldRegisterClsid(clsid)) {
+        continue;
+      }
+
+      hr = is_register ? _AtlComModule.RegisterServer(false, &clsid) :
+                         _AtlComModule.UnregisterServer(false, &clsid);
+      ASSERT(SUCCEEDED(hr), (_T("[RegisterOrUnregisterExe fail][%d][0x%x][%s]"),
+                             is_register, hr, GuidToString(clsid)));
+    }
+  }
+
+  return hr;
+}
+
+HRESULT RegisterOrUnregisterProxy(bool is_register) {
+  HRESULT hr = is_register ? PrxDllRegisterServer() : PrxDllUnregisterServer();
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[RegisterOrUnregisterProxy failed][%d][0x%x]"),
+                  is_register, hr));
+  }
+  return hr;
+}
+
+HRESULT GoogleUpdate::RegisterServer(BOOL, const CLSID*) throw() {
+  HRESULT hr = goopdate_utils::RegisterOrUnregisterModule(
+      true, &RegisterOrUnregisterProxy);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return goopdate_utils::RegisterOrUnregisterModule(true,
+                                                    &RegisterOrUnregisterExe);
+}
+
+HRESULT GoogleUpdate::UnregisterServer(BOOL, const CLSID*) throw() {
+  HRESULT hr = goopdate_utils::RegisterOrUnregisterModule(
+      false, &RegisterOrUnregisterExe);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return goopdate_utils::RegisterOrUnregisterModule(false,
+                                                    &RegisterOrUnregisterProxy);
+}
+
+HRESULT GoogleUpdate::PreMessageLoop(int show_cmd) throw() {
+  bool is_machine = goopdate_utils::IsRunningFromOfficialGoopdateDir(true);
+  worker_.reset(new Worker(is_machine));
+  return CAtlExeModuleT<GoogleUpdate>::PreMessageLoop(show_cmd);
+}
+
+HRESULT GoogleUpdate::PostMessageLoop() throw() {
+  HRESULT hr = CAtlExeModuleT<GoogleUpdate>::PostMessageLoop();
+  worker_.reset();
+  return hr;
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/google_update.h b/goopdate/google_update.h
index d9c4802..a2e494c 100644
--- a/goopdate/google_update.h
+++ b/goopdate/google_update.h
@@ -1,65 +1,65 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Contains GoogleUpdate class which is the ATL exe module for the local

-// server that allows launching of the browser at medium integrity.

-

-#ifndef OMAHA_GOOPDATE_GOOGLE_UPDATE_H__

-#define OMAHA_GOOPDATE_GOOGLE_UPDATE_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/atlregmapex.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/goopdate/resource.h"

-

-// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".

-#include "goopdate/google_update_idl.h"

-

-namespace omaha {

-

-class Worker;

-

-class GoogleUpdate : public CAtlExeModuleT<GoogleUpdate> {

- public:

-  // We do not register the AppID, because it is not needed, and because it

-  // would be one more thing to redirect for HKCU registration.

-

-  GoogleUpdate();

-  ~GoogleUpdate();

-  HRESULT RegisterClassObjects(DWORD cls_ctx, DWORD flags) throw();

-  HRESULT RevokeClassObjects() throw();

-

-  // The base ATL classes have an implicit dependency on the second parameter

-  // to RegisterServer and UnregisterServer having a default value.

-  HRESULT RegisterServer(BOOL register_tlb, const CLSID* id = NULL) throw();

-  HRESULT UnregisterServer(BOOL unregister_tlb, const CLSID* id = NULL) throw();

-  HRESULT PreMessageLoop(int show_cmd) throw();

-  HRESULT PostMessageLoop() throw();

-  HRESULT Main();

-

-  Worker* worker() { return worker_.get(); }

- private:

-  scoped_ptr<Worker> worker_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(GoogleUpdate);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_GOOGLE_UPDATE_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Contains GoogleUpdate class which is the ATL exe module for the local
+// server that allows launching of the browser at medium integrity.
+
+#ifndef OMAHA_GOOPDATE_GOOGLE_UPDATE_H__
+#define OMAHA_GOOPDATE_GOOGLE_UPDATE_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/atlregmapex.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/goopdate/resource.h"
+
+// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".
+#include "goopdate/google_update_idl.h"
+
+namespace omaha {
+
+class Worker;
+
+class GoogleUpdate : public CAtlExeModuleT<GoogleUpdate> {
+ public:
+  // We do not register the AppID, because it is not needed, and because it
+  // would be one more thing to redirect for HKCU registration.
+
+  GoogleUpdate();
+  ~GoogleUpdate();
+  HRESULT RegisterClassObjects(DWORD cls_ctx, DWORD flags) throw();
+  HRESULT RevokeClassObjects() throw();
+
+  // The base ATL classes have an implicit dependency on the second parameter
+  // to RegisterServer and UnregisterServer having a default value.
+  HRESULT RegisterServer(BOOL register_tlb, const CLSID* id = NULL) throw();
+  HRESULT UnregisterServer(BOOL unregister_tlb, const CLSID* id = NULL) throw();
+  HRESULT PreMessageLoop(int show_cmd) throw();
+  HRESULT PostMessageLoop() throw();
+  HRESULT Main();
+
+  Worker* worker() { return worker_.get(); }
+ private:
+  scoped_ptr<Worker> worker_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(GoogleUpdate);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_GOOGLE_UPDATE_H__
+
diff --git a/goopdate/google_update_idl.idl b/goopdate/google_update_idl.idl
index f66be43..7140aa4 100644
--- a/goopdate/google_update_idl.idl
+++ b/goopdate/google_update_idl.idl
@@ -1,239 +1,239 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The proxy clsid #defined as PROXY_CLSID_IS in mk_common needs to be changed

-// anytime any interface below changes, or if a new interface is added.

-

-import "oaidl.idl";

-import "ocidl.idl";

-

-[

-  object,

-  uuid(5B25A8DC-1780-4178-A629-6BE8B8DEFAA2),

-  oleautomation,

-  nonextensible,

-  pointer_default(unique)

-]

-interface IBrowserHttpRequest2 : IUnknown {

-  // This method will send request/data from the browser process.

-  // @param url                     URL where request will be send.

-  // @param post_data               POST data, if any. Can be NULL.

-  // @param request_headers         HTTP request headers, if any. Can be NULL.

-  // @param response_headers_needed HTTP response headers that are needed.

-  //                                Should be one of the values listed here:

-  //                                    http://msdn.microsoft.com/aa385351.aspx

-  //                                The input is a SAFEARRAY of DWORD. Can be a

-  //                                VT_EMPTY.

-  // @param response_headers        HTTP response headers, returned as SAFEARRAY

-  //                                of BSTR. The values corresponding one-to-one

-  //                                with the response_headers_needed values. Can

-  //                                be NULL if response_headers_needed==VT_EMPTY

-  // @param response_code           HTTP response code.

-  // @param cache_filename          Cache file that contains the response data.

-  HRESULT Send([in] BSTR url,

-               [in] BSTR post_data,

-               [in] BSTR request_headers,

-               [in] VARIANT response_headers_needed,

-               [out] VARIANT* response_headers,

-               [out] DWORD* response_code,

-               [out] BSTR* cache_filename);

-};

-

-[

-  object,

-  oleautomation,

-  uuid(128C2DA6-2BC0-44c0-B3F6-4EC22E647964),

-  helpstring("Google Update IProcessLauncher Interface"),

-  pointer_default(unique)

-]

-interface IProcessLauncher : IUnknown {

-  // @param cmd_line The full command line to execute.

-  HRESULT LaunchCmdLine([in, string] const WCHAR* cmd_line);

-

-  // @param browser_type The browser to start.

-  // @param url The url to launch the browser with.

-  HRESULT LaunchBrowser([in] DWORD browser_type,

-                        [in, string] const WCHAR* url);

-

-  // @param app_id Unique id to identify the calling client application

-  // @param event_id Unique id for the command

-  // @param caller_proc_id The process id of the calling process

-  // @param proc_handle The process handle valid in the caller's context

-  HRESULT LaunchCmdElevated([in, string] const WCHAR* app_guid,

-                            [in, string] const WCHAR* cmd_id,

-                            [in] DWORD caller_proc_id,

-                            [out] ULONG_PTR* proc_handle);

-};

-

-typedef enum {

-  COMPLETION_CODE_SUCCESS = 1,

-  COMPLETION_CODE_SUCCESS_CLOSE_UI,

-  COMPLETION_CODE_ERROR,

-  COMPLETION_CODE_RESTART_ALL_BROWSERS,

-  COMPLETION_CODE_REBOOT,

-  COMPLETION_CODE_RESTART_BROWSER,

-  COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY,

-  COMPLETION_CODE_REBOOT_NOTICE_ONLY,

-  COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY,

-  COMPLETION_CODE_RUN_COMMAND,

-} CompletionCodes;

-

-[

-  object,

-  oleautomation,

-  uuid(1C642CED-CA3B-4013-A9DF-CA6CE5FF6503),

-  helpstring("GoogleUpdate UI-specific events Interface"),

-  pointer_default(unique)

-]

-interface IProgressWndEvents : IUnknown {

-  // The UI is closing down. The user has clicked on either the "X" or the

-  // other buttons of the UI to close the window.

-  HRESULT DoClose();

-

-  // Pause has been clicked on.

-  HRESULT DoPause();

-

-  // Resume has been clicked on.

-  HRESULT DoResume();

-

-  // RestartBrowsers button has been clicked on.

-  HRESULT DoRestartBrowsers();

-

-  // Reboot button has been clicked on.

-  HRESULT DoReboot();

-

-  // Launch Browser.

-  HRESULT DoLaunchBrowser([in, string] const WCHAR* url);

-};

-

-

-[

-  object,

-  oleautomation,

-  uuid(49D7563B-2DDB-4831-88C8-768A53833837),

-  helpstring("IJobObserver Interface"),

-  pointer_default(unique)

-]

-interface IJobObserver : IUnknown {

-  HRESULT OnShow();

-  HRESULT OnCheckingForUpdate();

-  HRESULT OnUpdateAvailable([in, string] const WCHAR* version_string);

-  HRESULT OnWaitingToDownload();

-  HRESULT OnDownloading([in] int time_remaining_ms, [in] int pos);

-  HRESULT OnWaitingToInstall();

-  HRESULT OnInstalling();

-  HRESULT OnPause();

-  HRESULT OnComplete([in] CompletionCodes code,

-                     [in, string] const WCHAR* reserved);

-  HRESULT SetEventSink([in] IProgressWndEvents* ui_sink);

-};

-

-[

-  object,

-  oleautomation,

-  uuid(31AC3F11-E5EA-4a85-8A3D-8E095A39C27B),

-  helpstring("IGoogleUpdate Interface"),

-  pointer_default(unique)

-]

-interface IGoogleUpdate : IUnknown {

-  // @param guid The guid for the app to be updated.

-  // @param observer The eventing interface.

-  HRESULT CheckForUpdate([in, string] const WCHAR* guid,

-                         [in] IJobObserver* observer);

-

-  // @param guid The guid for the app to be updated.

-  // @param observer The eventing interface.

-  HRESULT Update([in, string] const WCHAR* guid,

-                 [in] IJobObserver* observer);

-};

-

-// IGoogleUpdateCore is an internal Omaha interface.

-[

-  object,

-  oleautomation,

-  uuid(909489C2-85A6-4322-AA56-D25278649D67),

-  helpstring("Google Update Core Interface"),

-  pointer_default(unique)

-]

-interface IGoogleUpdateCore : IUnknown

-{

-  // Runs a command elevated.

-  //

-  // @param app_id Unique id to identify the calling client application

-  // @param event_id Unique id for the command

-  // @param caller_proc_id The process id of the calling process

-  // @param proc_handle The process handle valid in the caller's context

-  HRESULT LaunchCmdElevated([in, string] const WCHAR* app_guid,

-                            [in, string] const WCHAR* cmd_id,

-                            [in] DWORD caller_proc_id,

-                            [out] ULONG_PTR* proc_handle);

-};

-

-[

-  uuid(7E6CD20B-8688-4960-96D9-B979471577B8),

-  version(1.0),

-  helpstring("Google Update Type Library")

-]

-library GoogleUpdateLib {

-  importlib("stdole2.tlb");

-  [

-    uuid(ABC01078-F197-4b0b-ADBC-CFE684B39C82),

-    helpstring("ProcessLauncherClass Class")

-  ]

-  coclass ProcessLauncherClass {

-    [default] interface IProcessLauncher;

-  }

-

-  // This coclass declaration exists only for the purpose of forcing

-  // ::RegisterTypeLib() to register the interfaces within. This is

-  // required so that we can marshal/unmarshal the interfaces using the TypeLib

-  // marshaler.

-  [

-    uuid(9564861C-3469-4c9a-956A-74D5690790E6),

-    helpstring("InterfaceRegistrar Class")

-  ]

-  coclass InterfaceRegistrar {

-    [default] interface IBrowserHttpRequest2;

-    interface IJobObserver;

-    interface IProgressWndEvents;

-  }

-

-  [

-    uuid(2F0E2680-9FF5-43c0-B76E-114A56E93598),

-    helpstring("OnDemand updates for per-user applications.")

-  ]

-  coclass OnDemandUserAppsClass {

-    [default] interface IGoogleUpdate;

-  }

-

-  [

-    uuid(6F8BD55B-E83D-4a47-85BE-81FFA8057A69),

-    helpstring("OnDemand updates for per-machine applications.")

-  ]

-  coclass OnDemandMachineAppsClass {

-    [default] interface IGoogleUpdate;

-  }

-

-  [

-    uuid(E225E692-4B47-4777-9BED-4FD7FE257F0E),

-    helpstring("GoogleUpdateCore Class")

-  ]

-  coclass GoogleUpdateCoreClass

-  {

-    [default] interface IGoogleUpdateCore;

-  }

-

-};

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The proxy clsid #defined as PROXY_CLSID_IS in mk_common needs to be changed
+// anytime any interface below changes, or if a new interface is added.
+
+import "oaidl.idl";
+import "ocidl.idl";
+
+[
+  object,
+  uuid(5B25A8DC-1780-4178-A629-6BE8B8DEFAA2),
+  oleautomation,
+  nonextensible,
+  pointer_default(unique)
+]
+interface IBrowserHttpRequest2 : IUnknown {
+  // This method will send request/data from the browser process.
+  // @param url                     URL where request will be send.
+  // @param post_data               POST data, if any. Can be NULL.
+  // @param request_headers         HTTP request headers, if any. Can be NULL.
+  // @param response_headers_needed HTTP response headers that are needed.
+  //                                Should be one of the values listed here:
+  //                                    http://msdn.microsoft.com/aa385351.aspx
+  //                                The input is a SAFEARRAY of DWORD. Can be a
+  //                                VT_EMPTY.
+  // @param response_headers        HTTP response headers, returned as SAFEARRAY
+  //                                of BSTR. The values corresponding one-to-one
+  //                                with the response_headers_needed values. Can
+  //                                be NULL if response_headers_needed==VT_EMPTY
+  // @param response_code           HTTP response code.
+  // @param cache_filename          Cache file that contains the response data.
+  HRESULT Send([in] BSTR url,
+               [in] BSTR post_data,
+               [in] BSTR request_headers,
+               [in] VARIANT response_headers_needed,
+               [out] VARIANT* response_headers,
+               [out] DWORD* response_code,
+               [out] BSTR* cache_filename);
+};
+
+[
+  object,
+  oleautomation,
+  uuid(128C2DA6-2BC0-44c0-B3F6-4EC22E647964),
+  helpstring("Google Update IProcessLauncher Interface"),
+  pointer_default(unique)
+]
+interface IProcessLauncher : IUnknown {
+  // @param cmd_line The full command line to execute.
+  HRESULT LaunchCmdLine([in, string] const WCHAR* cmd_line);
+
+  // @param browser_type The browser to start.
+  // @param url The url to launch the browser with.
+  HRESULT LaunchBrowser([in] DWORD browser_type,
+                        [in, string] const WCHAR* url);
+
+  // @param app_id Unique id to identify the calling client application
+  // @param event_id Unique id for the command
+  // @param caller_proc_id The process id of the calling process
+  // @param proc_handle The process handle valid in the caller's context
+  HRESULT LaunchCmdElevated([in, string] const WCHAR* app_guid,
+                            [in, string] const WCHAR* cmd_id,
+                            [in] DWORD caller_proc_id,
+                            [out] ULONG_PTR* proc_handle);
+};
+
+typedef enum {
+  COMPLETION_CODE_SUCCESS = 1,
+  COMPLETION_CODE_SUCCESS_CLOSE_UI,
+  COMPLETION_CODE_ERROR,
+  COMPLETION_CODE_RESTART_ALL_BROWSERS,
+  COMPLETION_CODE_REBOOT,
+  COMPLETION_CODE_RESTART_BROWSER,
+  COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY,
+  COMPLETION_CODE_REBOOT_NOTICE_ONLY,
+  COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY,
+  COMPLETION_CODE_RUN_COMMAND,
+} CompletionCodes;
+
+[
+  object,
+  oleautomation,
+  uuid(1C642CED-CA3B-4013-A9DF-CA6CE5FF6503),
+  helpstring("GoogleUpdate UI-specific events Interface"),
+  pointer_default(unique)
+]
+interface IProgressWndEvents : IUnknown {
+  // The UI is closing down. The user has clicked on either the "X" or the
+  // other buttons of the UI to close the window.
+  HRESULT DoClose();
+
+  // Pause has been clicked on.
+  HRESULT DoPause();
+
+  // Resume has been clicked on.
+  HRESULT DoResume();
+
+  // RestartBrowsers button has been clicked on.
+  HRESULT DoRestartBrowsers();
+
+  // Reboot button has been clicked on.
+  HRESULT DoReboot();
+
+  // Launch Browser.
+  HRESULT DoLaunchBrowser([in, string] const WCHAR* url);
+};
+
+
+[
+  object,
+  oleautomation,
+  uuid(49D7563B-2DDB-4831-88C8-768A53833837),
+  helpstring("IJobObserver Interface"),
+  pointer_default(unique)
+]
+interface IJobObserver : IUnknown {
+  HRESULT OnShow();
+  HRESULT OnCheckingForUpdate();
+  HRESULT OnUpdateAvailable([in, string] const WCHAR* version_string);
+  HRESULT OnWaitingToDownload();
+  HRESULT OnDownloading([in] int time_remaining_ms, [in] int pos);
+  HRESULT OnWaitingToInstall();
+  HRESULT OnInstalling();
+  HRESULT OnPause();
+  HRESULT OnComplete([in] CompletionCodes code,
+                     [in, string] const WCHAR* reserved);
+  HRESULT SetEventSink([in] IProgressWndEvents* ui_sink);
+};
+
+[
+  object,
+  oleautomation,
+  uuid(31AC3F11-E5EA-4a85-8A3D-8E095A39C27B),
+  helpstring("IGoogleUpdate Interface"),
+  pointer_default(unique)
+]
+interface IGoogleUpdate : IUnknown {
+  // @param guid The guid for the app to be updated.
+  // @param observer The eventing interface.
+  HRESULT CheckForUpdate([in, string] const WCHAR* guid,
+                         [in] IJobObserver* observer);
+
+  // @param guid The guid for the app to be updated.
+  // @param observer The eventing interface.
+  HRESULT Update([in, string] const WCHAR* guid,
+                 [in] IJobObserver* observer);
+};
+
+// IGoogleUpdateCore is an internal Omaha interface.
+[
+  object,
+  oleautomation,
+  uuid(909489C2-85A6-4322-AA56-D25278649D67),
+  helpstring("Google Update Core Interface"),
+  pointer_default(unique)
+]
+interface IGoogleUpdateCore : IUnknown
+{
+  // Runs a command elevated.
+  //
+  // @param app_id Unique id to identify the calling client application
+  // @param event_id Unique id for the command
+  // @param caller_proc_id The process id of the calling process
+  // @param proc_handle The process handle valid in the caller's context
+  HRESULT LaunchCmdElevated([in, string] const WCHAR* app_guid,
+                            [in, string] const WCHAR* cmd_id,
+                            [in] DWORD caller_proc_id,
+                            [out] ULONG_PTR* proc_handle);
+};
+
+[
+  uuid(7E6CD20B-8688-4960-96D9-B979471577B8),
+  version(1.0),
+  helpstring("Google Update Type Library")
+]
+library GoogleUpdateLib {
+  importlib("stdole2.tlb");
+  [
+    uuid(ABC01078-F197-4b0b-ADBC-CFE684B39C82),
+    helpstring("ProcessLauncherClass Class")
+  ]
+  coclass ProcessLauncherClass {
+    [default] interface IProcessLauncher;
+  }
+
+  // This coclass declaration exists only for the purpose of forcing
+  // ::RegisterTypeLib() to register the interfaces within. This is
+  // required so that we can marshal/unmarshal the interfaces using the TypeLib
+  // marshaler.
+  [
+    uuid(9564861C-3469-4c9a-956A-74D5690790E6),
+    helpstring("InterfaceRegistrar Class")
+  ]
+  coclass InterfaceRegistrar {
+    [default] interface IBrowserHttpRequest2;
+    interface IJobObserver;
+    interface IProgressWndEvents;
+  }
+
+  [
+    uuid(2F0E2680-9FF5-43c0-B76E-114A56E93598),
+    helpstring("OnDemand updates for per-user applications.")
+  ]
+  coclass OnDemandUserAppsClass {
+    [default] interface IGoogleUpdate;
+  }
+
+  [
+    uuid(6F8BD55B-E83D-4a47-85BE-81FFA8057A69),
+    helpstring("OnDemand updates for per-machine applications.")
+  ]
+  coclass OnDemandMachineAppsClass {
+    [default] interface IGoogleUpdate;
+  }
+
+  [
+    uuid(E225E692-4B47-4777-9BED-4FD7FE257F0E),
+    helpstring("GoogleUpdateCore Class")
+  ]
+  coclass GoogleUpdateCoreClass
+  {
+    [default] interface IGoogleUpdateCore;
+  }
+
+};
+
diff --git a/goopdate/google_update_idl_datax.c b/goopdate/google_update_idl_datax.c
index 0078194..5f3c91e 100644
--- a/goopdate/google_update_idl_datax.c
+++ b/goopdate/google_update_idl_datax.c
@@ -1,41 +1,41 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// google_update_idl_datax.c: Wrapper for the MIDL-generated proxy/stub.

-

-#pragma warning(push)

-// C4255: no function prototype given: converting '()' to '(void)'

-#pragma warning(disable : 4255)

-// C4152: nonstandard extension, function/data pointer conversion in expression

-#pragma warning(disable : 4152)

-

-#define REGISTER_PROXY_DLL

-#define USE_STUBLESS_PROXY

-#define ENTRY_PREFIX      Prx

-

-// Undefine the __purecall provided by rpcproxy.h so that it does not conflict

-// with the libc definition.

-#include <rpcproxy.h>

-#ifdef DLLDUMMYPURECALL

-#undef DLLDUMMYPURECALL

-#define DLLDUMMYPURECALL

-#endif

-

-#include "goopdate/google_update_idl_data.c"

-#include "goopdate/google_update_idl_p.c"

-

-#pragma warning(pop)

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// google_update_idl_datax.c: Wrapper for the MIDL-generated proxy/stub.
+
+#pragma warning(push)
+// C4255: no function prototype given: converting '()' to '(void)'
+#pragma warning(disable : 4255)
+// C4152: nonstandard extension, function/data pointer conversion in expression
+#pragma warning(disable : 4152)
+
+#define REGISTER_PROXY_DLL
+#define USE_STUBLESS_PROXY
+#define ENTRY_PREFIX      Prx
+
+// Undefine the __purecall provided by rpcproxy.h so that it does not conflict
+// with the libc definition.
+#include <rpcproxy.h>
+#ifdef DLLDUMMYPURECALL
+#undef DLLDUMMYPURECALL
+#define DLLDUMMYPURECALL
+#endif
+
+#include "goopdate/google_update_idl_data.c"
+#include "goopdate/google_update_idl_p.c"
+
+#pragma warning(pop)
+
diff --git a/goopdate/google_update_idl_datax.h b/goopdate/google_update_idl_datax.h
index 3695cdb..3cb26af 100644
--- a/goopdate/google_update_idl_datax.h
+++ b/goopdate/google_update_idl_datax.h
@@ -1,32 +1,32 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// google_update_idl_datax.h: Declarations for the MIDL-generated entry points

-// for the proxy/stub.

-

-#ifndef OMAHA_GOOPDATE_GOOGLE_UPDATE_IDL_DATAX_H_

-#define OMAHA_GOOPDATE_GOOGLE_UPDATE_IDL_DATAX_H_

-

-extern "C" {

-  BOOL WINAPI PrxDllMain(HINSTANCE instance, DWORD reason, LPVOID res);

-  STDAPI PrxDllCanUnloadNow();

-  STDAPI PrxDllGetClassObject(REFCLSID refclsid, REFIID refiid, LPVOID* ptr);

-  STDAPI PrxDllRegisterServer();

-  STDAPI PrxDllUnregisterServer();

-}

-

-#endif  // OMAHA_GOOPDATE_GOOGLE_UPDATE_IDL_DATAX_H_

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// google_update_idl_datax.h: Declarations for the MIDL-generated entry points
+// for the proxy/stub.
+
+#ifndef OMAHA_GOOPDATE_GOOGLE_UPDATE_IDL_DATAX_H_
+#define OMAHA_GOOPDATE_GOOGLE_UPDATE_IDL_DATAX_H_
+
+extern "C" {
+  BOOL WINAPI PrxDllMain(HINSTANCE instance, DWORD reason, LPVOID res);
+  STDAPI PrxDllCanUnloadNow();
+  STDAPI PrxDllGetClassObject(REFCLSID refclsid, REFIID refiid, LPVOID* ptr);
+  STDAPI PrxDllRegisterServer();
+  STDAPI PrxDllUnregisterServer();
+}
+
+#endif  // OMAHA_GOOPDATE_GOOGLE_UPDATE_IDL_DATAX_H_
+
diff --git a/goopdate/google_update_proxy.h b/goopdate/google_update_proxy.h
index 14bd3cf..668702e 100644
--- a/goopdate/google_update_proxy.h
+++ b/goopdate/google_update_proxy.h
@@ -1,225 +1,225 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines SharedMemoryProxy to encapsulate marshaling and unmarshaling of

-// IGoogleUpdate and other interface pointers across process boundaries.

-//

-// TODO(omaha): seems possible to make it general purpose and move it to common.

-#ifndef OMAHA_GOOPDATE_GOOGLE_UPDATE_PROXY_H__

-#define OMAHA_GOOPDATE_GOOGLE_UPDATE_PROXY_H__

-

-#include <atlbase.h>

-#include <atlsecurity.h>

-#include "base/basictypes.h"

-#include "goopdate/google_update_idl.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/shared_memory_ptr.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-

-namespace omaha {

-

-// Constants

-const size_t kMaxSizeInterfaceMarshalData = 256;

-const TCHAR* const kBrowserHttpRequestShareName = _T("IBrowserRequest2_");

-

-struct InterfaceMarshalData {

-  void InitializeSharedData(const CString&) {

-    SetZero(data_);

-    size_ = 0;

-  }

-  size_t size_;

-  uint8 data_[kMaxSizeInterfaceMarshalData];

-};

-

-class SharedMemoryAttributes {

- public:

-  SharedMemoryAttributes(const TCHAR* shared_memory_name,

-                         const CSecurityDesc& security_attributes)

-      : shared_memory_name_(shared_memory_name),

-        security_attributes_(security_attributes) {

-  }

-  const CString& GetSharedMemoryName() { return shared_memory_name_; }

-  LPSECURITY_ATTRIBUTES GetSecurityAttributes() {

-    return &security_attributes_;

-  }

-

- private:

-  CString shared_memory_name_;

-  CSecurityAttributes security_attributes_;

-  DISALLOW_EVIL_CONSTRUCTORS(SharedMemoryAttributes);

-};

-

-extern SharedMemoryAttributes low_integrity_attributes;

-extern SharedMemoryAttributes high_integrity_attributes;

-

-template <typename InterfaceType, typename LockType>

-class SharedMemoryProxy {

- public:

-  SharedMemoryProxy(bool read_only, SharedMemoryAttributes* attributes)

-      : shared_memory_ptr_(attributes->GetSharedMemoryName(),

-                           attributes->GetSecurityAttributes(),

-                           NULL,

-                           read_only) {

-    CORE_LOG(L3, (_T("[SharedMemoryProxy::SharedMemoryProxy]")));

-  }

-

-  ~SharedMemoryProxy() {

-    CORE_LOG(L3, (_T("[SharedMemoryProxy::~SharedMemoryProxy]")));

-  }

-

-  HRESULT GetObject(InterfaceType** interface_ptr) {

-    ASSERT1(interface_ptr);

-    ASSERT1(*interface_ptr == NULL);

-

-    CORE_LOG(L3, (_T("[SharedMemoryProxy::GetObject]")));

-

-    return UnmarshalInterface(interface_ptr);

-  }

-

-  HRESULT RegisterObject(InterfaceType* interface_ptr) {

-    ASSERT1(interface_ptr);

-    CORE_LOG(L3, (_T("[SharedMemoryProxy::RegisterObject]")));

-

-    return MarshalInterface(interface_ptr);

-  }

-

-  HRESULT RevokeObject() {

-    CORE_LOG(L3, (_T("[SharedMemoryProxy::RevokeObject]")));

-

-    if (!shared_memory_ptr_) {

-      OPT_LOG(LEVEL_ERROR, (_T("[Shared memory ptr error]")));

-      return GOOPDATE_E_INVALID_SHARED_MEMORY_PTR;

-    }

-

-    shared_memory_ptr_->size_ = 0;

-    SetZero(shared_memory_ptr_->data_);

-

-    return S_OK;

-  }

-

- private:

-  // Helpers.

-  HRESULT MarshalInterface(InterfaceType* interface_ptr) {

-    CORE_LOG(L3, (_T("[SharedMemoryProxy::MarshalInterface]")));

-

-    if (!shared_memory_ptr_) {

-      OPT_LOG(LEVEL_ERROR, (_T("[Shared memory ptr error]")));

-      return GOOPDATE_E_INVALID_SHARED_MEMORY_PTR;

-    }

-

-    // Marshal the interface.

-    scoped_hglobal hglobal(::GlobalAlloc(GHND, 0));

-    if (!valid(hglobal)) {

-      OPT_LOG(LEVEL_ERROR, (_T("[GlobalAlloc failed]")));

-      return E_OUTOFMEMORY;

-    }

-

-    CComPtr<IStream> stream;

-    HRESULT hr = ::CreateStreamOnHGlobal(get(hglobal), false, &stream);

-    if (FAILED(hr)) {

-      OPT_LOG(LEVEL_ERROR, (_T("[CreateStreamOnHGlobal failed][0x%08x]"), hr));

-      return hr;

-    }

-

-    // MSHLFLAGS_TABLEWEAK results in CO_E_OBJNOTREG if unmarshaling multiple

-    // times, so using MSHLFLAGS_TABLESTRONG.

-    hr = ::CoMarshalInterface(stream,

-                              __uuidof(InterfaceType),

-                              interface_ptr,

-                              MSHCTX_LOCAL,

-                              NULL,

-                              MSHLFLAGS_TABLESTRONG);

-    if (FAILED(hr)) {

-      OPT_LOG(LEVEL_ERROR, (_T("[CoMarshalInterface failed][0x%08x]"), hr));

-      return hr;

-    }

-

-    // Copy out the marshaled data.

-    STATSTG stat = {0};

-    hr = stream->Stat(&stat, STATFLAG_NONAME);

-    if (FAILED(hr)) {

-      OPT_LOG(LEVEL_ERROR, (_T("[IStream::Stat failed][0x%08x]"), hr));

-      return hr;

-    }

-    int64 size = static_cast<int64>(stat.cbSize.QuadPart);

-    if (!size || size > kMaxSizeInterfaceMarshalData) {

-      OPT_LOG(LEVEL_ERROR, (_T("[Bad size][%I64d]"), size));

-      return GOOPDATE_E_INVALID_INTERFACE_MARSHAL_SIZE;

-    }

-

-    byte* data = reinterpret_cast<byte*>(::GlobalLock(get(hglobal)));

-    if (!data) {

-      return HRESULTFromLastError();

-    }

-    memcpy(shared_memory_ptr_->data_, data, stat.cbSize.LowPart);

-    shared_memory_ptr_->size_ = stat.cbSize.LowPart;

-

-    ::GlobalUnlock(get(hglobal));

-

-    return S_OK;

-  }

-

-  HRESULT UnmarshalInterface(InterfaceType** interface_ptr) {

-    CORE_LOG(L3, (_T("[SharedMemoryProxy::UnmarshalInterface]")));

-

-    if (!shared_memory_ptr_) {

-      OPT_LOG(LEVEL_ERROR, (_T("[Shared memory ptr error]")));

-      return GOOPDATE_E_INVALID_SHARED_MEMORY_PTR;

-    }

-

-    size_t size = shared_memory_ptr_->size_;

-    if (!size || size > kMaxSizeInterfaceMarshalData) {

-      CORE_LOG(LEVEL_ERROR, (_T("[bad size][%d]"), size));

-      return GOOPDATE_E_INVALID_INTERFACE_MARSHAL_SIZE;

-    }

-

-    // Unmarshal the interface.

-    scoped_hglobal hglobal(::GlobalAlloc(GPTR, size));

-    if (!valid(hglobal)) {

-      OPT_LOG(LEVEL_ERROR, (_T("[GlobalAlloc failed]")));

-      return E_OUTOFMEMORY;

-    }

-    memcpy(get(hglobal), shared_memory_ptr_->data_, size);

-

-    CComPtr<IStream> stream;

-    HRESULT hr = ::CreateStreamOnHGlobal(get(hglobal), false, &stream);

-    if (FAILED(hr)) {

-      OPT_LOG(LEVEL_ERROR, (_T("[CreateStreamOnHGlobal failed][0x%08x]"), hr));

-      return hr;

-    }

-

-    hr = ::CoUnmarshalInterface(stream,

-                                __uuidof(InterfaceType),

-                                reinterpret_cast<void **>(interface_ptr));

-    if (FAILED(hr)) {

-      OPT_LOG(LEVEL_ERROR, (_T("[CoUnmarshalInterface failed][0x%08x]"), hr));

-      return hr;

-    }

-

-    return S_OK;

-  }

-

-  SharedMemoryPtr<LockType, InterfaceMarshalData> shared_memory_ptr_;

-  DISALLOW_EVIL_CONSTRUCTORS(SharedMemoryProxy);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_GOOGLE_UPDATE_PROXY_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines SharedMemoryProxy to encapsulate marshaling and unmarshaling of
+// IGoogleUpdate and other interface pointers across process boundaries.
+//
+// TODO(omaha): seems possible to make it general purpose and move it to common.
+#ifndef OMAHA_GOOPDATE_GOOGLE_UPDATE_PROXY_H__
+#define OMAHA_GOOPDATE_GOOGLE_UPDATE_PROXY_H__
+
+#include <atlbase.h>
+#include <atlsecurity.h>
+#include "base/basictypes.h"
+#include "goopdate/google_update_idl.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/shared_memory_ptr.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+
+namespace omaha {
+
+// Constants
+const size_t kMaxSizeInterfaceMarshalData = 256;
+const TCHAR* const kBrowserHttpRequestShareName = _T("IBrowserRequest2_");
+
+struct InterfaceMarshalData {
+  void InitializeSharedData(const CString&) {
+    SetZero(data_);
+    size_ = 0;
+  }
+  size_t size_;
+  uint8 data_[kMaxSizeInterfaceMarshalData];
+};
+
+class SharedMemoryAttributes {
+ public:
+  SharedMemoryAttributes(const TCHAR* shared_memory_name,
+                         const CSecurityDesc& security_attributes)
+      : shared_memory_name_(shared_memory_name),
+        security_attributes_(security_attributes) {
+  }
+  const CString& GetSharedMemoryName() { return shared_memory_name_; }
+  LPSECURITY_ATTRIBUTES GetSecurityAttributes() {
+    return &security_attributes_;
+  }
+
+ private:
+  CString shared_memory_name_;
+  CSecurityAttributes security_attributes_;
+  DISALLOW_EVIL_CONSTRUCTORS(SharedMemoryAttributes);
+};
+
+extern SharedMemoryAttributes low_integrity_attributes;
+extern SharedMemoryAttributes high_integrity_attributes;
+
+template <typename InterfaceType, typename LockType>
+class SharedMemoryProxy {
+ public:
+  SharedMemoryProxy(bool read_only, SharedMemoryAttributes* attributes)
+      : shared_memory_ptr_(attributes->GetSharedMemoryName(),
+                           attributes->GetSecurityAttributes(),
+                           NULL,
+                           read_only) {
+    CORE_LOG(L3, (_T("[SharedMemoryProxy::SharedMemoryProxy]")));
+  }
+
+  ~SharedMemoryProxy() {
+    CORE_LOG(L3, (_T("[SharedMemoryProxy::~SharedMemoryProxy]")));
+  }
+
+  HRESULT GetObject(InterfaceType** interface_ptr) {
+    ASSERT1(interface_ptr);
+    ASSERT1(*interface_ptr == NULL);
+
+    CORE_LOG(L3, (_T("[SharedMemoryProxy::GetObject]")));
+
+    return UnmarshalInterface(interface_ptr);
+  }
+
+  HRESULT RegisterObject(InterfaceType* interface_ptr) {
+    ASSERT1(interface_ptr);
+    CORE_LOG(L3, (_T("[SharedMemoryProxy::RegisterObject]")));
+
+    return MarshalInterface(interface_ptr);
+  }
+
+  HRESULT RevokeObject() {
+    CORE_LOG(L3, (_T("[SharedMemoryProxy::RevokeObject]")));
+
+    if (!shared_memory_ptr_) {
+      OPT_LOG(LEVEL_ERROR, (_T("[Shared memory ptr error]")));
+      return GOOPDATE_E_INVALID_SHARED_MEMORY_PTR;
+    }
+
+    shared_memory_ptr_->size_ = 0;
+    SetZero(shared_memory_ptr_->data_);
+
+    return S_OK;
+  }
+
+ private:
+  // Helpers.
+  HRESULT MarshalInterface(InterfaceType* interface_ptr) {
+    CORE_LOG(L3, (_T("[SharedMemoryProxy::MarshalInterface]")));
+
+    if (!shared_memory_ptr_) {
+      OPT_LOG(LEVEL_ERROR, (_T("[Shared memory ptr error]")));
+      return GOOPDATE_E_INVALID_SHARED_MEMORY_PTR;
+    }
+
+    // Marshal the interface.
+    scoped_hglobal hglobal(::GlobalAlloc(GHND, 0));
+    if (!valid(hglobal)) {
+      OPT_LOG(LEVEL_ERROR, (_T("[GlobalAlloc failed]")));
+      return E_OUTOFMEMORY;
+    }
+
+    CComPtr<IStream> stream;
+    HRESULT hr = ::CreateStreamOnHGlobal(get(hglobal), false, &stream);
+    if (FAILED(hr)) {
+      OPT_LOG(LEVEL_ERROR, (_T("[CreateStreamOnHGlobal failed][0x%08x]"), hr));
+      return hr;
+    }
+
+    // MSHLFLAGS_TABLEWEAK results in CO_E_OBJNOTREG if unmarshaling multiple
+    // times, so using MSHLFLAGS_TABLESTRONG.
+    hr = ::CoMarshalInterface(stream,
+                              __uuidof(InterfaceType),
+                              interface_ptr,
+                              MSHCTX_LOCAL,
+                              NULL,
+                              MSHLFLAGS_TABLESTRONG);
+    if (FAILED(hr)) {
+      OPT_LOG(LEVEL_ERROR, (_T("[CoMarshalInterface failed][0x%08x]"), hr));
+      return hr;
+    }
+
+    // Copy out the marshaled data.
+    STATSTG stat = {0};
+    hr = stream->Stat(&stat, STATFLAG_NONAME);
+    if (FAILED(hr)) {
+      OPT_LOG(LEVEL_ERROR, (_T("[IStream::Stat failed][0x%08x]"), hr));
+      return hr;
+    }
+    int64 size = static_cast<int64>(stat.cbSize.QuadPart);
+    if (!size || size > kMaxSizeInterfaceMarshalData) {
+      OPT_LOG(LEVEL_ERROR, (_T("[Bad size][%I64d]"), size));
+      return GOOPDATE_E_INVALID_INTERFACE_MARSHAL_SIZE;
+    }
+
+    byte* data = reinterpret_cast<byte*>(::GlobalLock(get(hglobal)));
+    if (!data) {
+      return HRESULTFromLastError();
+    }
+    memcpy(shared_memory_ptr_->data_, data, stat.cbSize.LowPart);
+    shared_memory_ptr_->size_ = stat.cbSize.LowPart;
+
+    ::GlobalUnlock(get(hglobal));
+
+    return S_OK;
+  }
+
+  HRESULT UnmarshalInterface(InterfaceType** interface_ptr) {
+    CORE_LOG(L3, (_T("[SharedMemoryProxy::UnmarshalInterface]")));
+
+    if (!shared_memory_ptr_) {
+      OPT_LOG(LEVEL_ERROR, (_T("[Shared memory ptr error]")));
+      return GOOPDATE_E_INVALID_SHARED_MEMORY_PTR;
+    }
+
+    size_t size = shared_memory_ptr_->size_;
+    if (!size || size > kMaxSizeInterfaceMarshalData) {
+      CORE_LOG(LEVEL_ERROR, (_T("[bad size][%d]"), size));
+      return GOOPDATE_E_INVALID_INTERFACE_MARSHAL_SIZE;
+    }
+
+    // Unmarshal the interface.
+    scoped_hglobal hglobal(::GlobalAlloc(GPTR, size));
+    if (!valid(hglobal)) {
+      OPT_LOG(LEVEL_ERROR, (_T("[GlobalAlloc failed]")));
+      return E_OUTOFMEMORY;
+    }
+    memcpy(get(hglobal), shared_memory_ptr_->data_, size);
+
+    CComPtr<IStream> stream;
+    HRESULT hr = ::CreateStreamOnHGlobal(get(hglobal), false, &stream);
+    if (FAILED(hr)) {
+      OPT_LOG(LEVEL_ERROR, (_T("[CreateStreamOnHGlobal failed][0x%08x]"), hr));
+      return hr;
+    }
+
+    hr = ::CoUnmarshalInterface(stream,
+                                __uuidof(InterfaceType),
+                                reinterpret_cast<void **>(interface_ptr));
+    if (FAILED(hr)) {
+      OPT_LOG(LEVEL_ERROR, (_T("[CoUnmarshalInterface failed][0x%08x]"), hr));
+      return hr;
+    }
+
+    return S_OK;
+  }
+
+  SharedMemoryPtr<LockType, InterfaceMarshalData> shared_memory_ptr_;
+  DISALLOW_EVIL_CONSTRUCTORS(SharedMemoryProxy);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_GOOGLE_UPDATE_PROXY_H__
+
diff --git a/goopdate/goopdate-internal.h b/goopdate/goopdate-internal.h
index 0ef074f..e20b104 100644
--- a/goopdate/goopdate-internal.h
+++ b/goopdate/goopdate-internal.h
@@ -1,33 +1,33 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_GOOPDATE_INTERNAL_H_

-#define OMAHA_GOOPDATE_GOOPDATE_INTERNAL_H_

-

-#include <windows.h>

-

-namespace omaha {

-

-namespace internal {

-

-// Marks Google Update's EULA as accepted if an app EULA has been accepted.

-HRESULT PromoteAppEulaAccepted(bool is_machine);

-

-}  // namespace internal

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_GOOPDATE_INTERNAL_H_

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_GOOPDATE_INTERNAL_H_
+#define OMAHA_GOOPDATE_GOOPDATE_INTERNAL_H_
+
+#include <windows.h>
+
+namespace omaha {
+
+namespace internal {
+
+// Marks Google Update's EULA as accepted if an app EULA has been accepted.
+HRESULT PromoteAppEulaAccepted(bool is_machine);
+
+}  // namespace internal
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_GOOPDATE_INTERNAL_H_
+
diff --git a/goopdate/goopdate.cc b/goopdate/goopdate.cc
index ad44867..4c1a0d1 100644
--- a/goopdate/goopdate.cc
+++ b/goopdate/goopdate.cc
@@ -1,1195 +1,1195 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// For interactive instances, do not access the network before displaying the

-// UI. This provides a better user experience - quick UI - when the network is

-// slow. It is also required to ensure that UI displayed event is signaled

-// before potentially waiting on a firewall prompt.

-//

-// Debugging notes:

-//  * Omaha (and app) initial install:

-//   * File install can be debugged with the following command arguments:

-//      /install "appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&appname=Google%20Chrome&needsadmin=False&lang=en"  // NOLINT

-//      /install "appguid={283EAF47-8817-4c2b-A801-AD1FADFB7BAA}&appname=Gears&needsadmin=True&lang=en"  // NOLINT

-//   * If elevation is required, another instance is launched. Run elevated to

-//     continue debugging.

-//   * Once the initial files have been copied, another instance is launched

-//     from the installed location. To continue debugging, use the following

-//     command arguments:

-//      /ig "appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&appname=Google%20Chrome&needsadmin=False&lang=en"  // NOLINT

-//      /ig "appguid={283EAF47-8817-4c2b-A801-AD1FADFB7BAA}&appname=Gears&needsadmin=True&lang=en"  // NOLINT

-//  * App hand-off initial install or over-install:

-//      /handoff "appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&appname=Google%20Chrome&needsadmin=False&lang=en"  // NOLINT

-//      /handoff "appguid={283EAF47-8817-4c2b-A801-AD1FADFB7BAA}&appname=Gears&needsadmin=True&lang=en"  // NOLINT

-//  * Silent install:

-//   * Add "/silent" to any of the above command lines (not to the tag).

-//  * Google Update self-update:

-//   * File install can be debugged with the following command arguments:

-//      /update

-//   * Once the initial files have been copied, another instance is launched

-//     from the installed location. To continue debugging, use the following

-//     command arguments:

-//      /ug

-//  * Update check for apps that need it:

-//      /ua

-//  * Legacy hand-off install (Occurs from the machine install location)

-//   * First /UI /lang en legacy_manifest_path

-//   * This then launches a worker with:

-//      /handoff "appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&appname=YouTube Uploader&needsadmin=False" /lang en  // NOLINT

-//  * Core:

-//      /c

-//  * Cod Red check:

-//      /cr

-//  * Cod Red repair:

-//   * Determining whether to elevate and non-elevated file install can be

-//     debugged with the following command arguments:

-//      /recover [/machine]

-//   * Once the initial files have been copied, another instance is launched

-//     from the installed location. To continue debugging, use the following

-//     command arguments:

-//      /ug [/machine]

-//  * OneClick:

-//      /pi "http://www.google.com/" "/install%20%22appguid=%7B8A69D345-D564-463C-AFF1-A69D9E530F96%7D%26lang=en%26appname=Google%2520Chrome%26needsadmin=false" /installsource oneclick  // NOLINT

-

-#include "omaha/goopdate/goopdate.h"

-

-#include <atlstr.h>

-#include <new>

-#include "base/scoped_ptr.h"

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/google_update_recovery.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/module_utils.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/proc_utils.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/core/core.h"

-#include "omaha/core/crash_handler.h"

-#include "omaha/goopdate/browser_launcher.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/crash.h"

-#include "omaha/goopdate/goopdate_helper.h"

-#include "omaha/goopdate/google_update.h"

-#include "omaha/goopdate/goopdate_metrics.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/goopdate_xml_parser.h"

-#include "omaha/goopdate/goopdate-internal.h"

-#include "omaha/goopdate/stats_uploader.h"

-#include "omaha/goopdate/webplugin_utils.h"

-#include "omaha/net/net_diags.h"

-#include "omaha/net/browser_request.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/bits_request.h"

-#include "omaha/net/simple_request.h"

-#include "omaha/recovery/repair_exe/repair_goopdate.h"

-#include "omaha/service/service_main.h"

-#include "omaha/setup/setup.h"

-#include "omaha/setup/setup_service.h"

-#include "omaha/worker/app_request_data.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/application_manager.h"

-#include "omaha/worker/ping.h"

-#include "omaha/worker/worker.h"

-#include "omaha/worker/worker_com_wrapper.h"

-#include "omaha/worker/worker_event_logger.h"

-#include "third_party/breakpad/src/client/windows/sender/crash_report_sender.h"

-#include "third_party/breakpad/src/client/windows/handler/exception_handler.h"

-

-// Generated by MIDL into $OBJ_ROOT/goopdate.

-#include "goopdate/google_update_idl.h"

-

-namespace omaha {

-

-namespace {

-

-#if DEBUG

-const TCHAR* const kBuildType = _T("dbg");

-#else

-const TCHAR* const kBuildType = _T("opt");

-#endif

-

-#if OFFICIAL_BUILD

-const TCHAR* const kOfficialBuild = _T("official");

-#else

-const TCHAR* const kOfficialBuild = _T("dev");

-#endif

-

-}  // namespace

-

-namespace detail {

-

-class GoopdateImpl {

- public:

-  GoopdateImpl(Goopdate* goopdate, bool is_local_system);

-  ~GoopdateImpl();

-

-  HRESULT Main(HINSTANCE instance, const TCHAR* cmd_line, int cmd_show);

-

-  bool is_local_system() const { return is_local_system_; }

-

-  CommandLineArgs args() const { return args_; }

-  CString cmd_line() const { return cmd_line_; }

-

- private:

-  HRESULT DoMain(HINSTANCE instance, const TCHAR* cmd_line, int cmd_show);

-

-  // Returns whether a process is a machine process.

-  // Does not determine whether the process has the appropriate privileges.

-  bool IsMachineProcess();

-

-  HRESULT LoadResourceDllIfNecessary(CommandLineMode mode,

-                                     const CString& resource_dir);

-

-  HRESULT SetUsageStatsEnable();

-

-  // Handles error conditions by showing UI.

-  HRESULT HandleError(HRESULT hr);

-

-  // Handles response to /pi command.

-  HRESULT HandleWebPlugin();

-

-  // Handles responses to /cr command.

-  HRESULT HandleCodeRedCheck();

-

-  // Handles /ui command.

-  HRESULT HandleLegacyUI();

-

-  // Handles /report command.

-  HRESULT HandleReportCrash();

-

-  // Handles /uiuser command.

-  HRESULT HandleLegacyManifestHandoff();

-

-  // Download Callback for Code Red.

-  static HRESULT CodeRedDownloadCallback(const TCHAR* url,

-                                         const TCHAR* file_path,

-                                         void*);

-  HRESULT DoWorker();

-

-  // Generates a divide by zero to trigger breakpad dump.

-  // Is only enabled in debug builds.

-  HRESULT DoCrash();

-

-  // Register a product with Goopdate and install Goopdate.

-  HRESULT DoRegisterProduct();

-

-  // Does the work for DoRegisterProduct().

-  HRESULT DoRegisterProductHelper(bool is_machine,

-                                  AppManager* app_manager,

-                                  AppData* app_data);

-

-  // Unregister a product from Goopdate.

-  HRESULT DoUnregisterProduct();

-

-  // Setup phase1 for self update.

-  HRESULT DoSelfUpdate();

-

-  // Setup phase2 for self update.

-  HRESULT DoCompleteSelfUpdate();

-

-  // Handles the recover command in Google Update.

-  HRESULT DoRecover();

-

-  // Uninstalls Google Update if a /install process failed to install itself

-  // or the app and there are no other apps registered.

-  HRESULT UninstallIfNecessary();

-

-  // Called by operator new or operator new[] when they cannot satisfy

-  // a request for additional storage.

-  static void OutOfMemoryHandler();

-

-  HINSTANCE module_instance_;  // Current module instance.

-  CString cmd_line_;           // Command line, as provided by the OS.

-  int cmd_show_;

-

-  CommandLineArgs args_;       // Command line options and flags.

-

-  // True if the process belongs to a machine Omaha "session".

-  bool is_machine_;

-  bool is_local_system_;       // True if running as LOCAL_SYSTEM.

-  CString this_version_;       // Version of this Goopdate DLL.

-

-  // True if Omaha has been uninstalled by the Worker.

-  bool has_uninstalled_;

-

-  // Language identifier for the current user locale.

-  CString user_default_language_id_;

-

-  scoped_ptr<ResourceManager> resource_manager_;

-  Goopdate* goopdate_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(GoopdateImpl);

-};

-

-GoopdateImpl::GoopdateImpl(Goopdate* goopdate, bool is_local_system)

-    : module_instance_(NULL),

-      cmd_show_(0),

-      is_machine_(false),

-      is_local_system_(is_local_system),

-      has_uninstalled_(false),

-      goopdate_(goopdate) {

-  ASSERT1(goopdate);

-  // The command line needs to be parsed to accurately determine if the

-  // current process is a machine process or not. Use the value of

-  // is_local_system until that.

-  is_machine_ = is_local_system_;

-

-  // Install an error-handling mechanism which gets called when new operator

-  // fails to allocate memory.

-  VERIFY1(set_new_handler(&GoopdateImpl::OutOfMemoryHandler) == 0);

-

-  // Install the exception handler.

-  VERIFY1(SUCCEEDED(Crash::InstallCrashHandler(is_machine_)));

-

-  // Initialize the global metrics collection.

-  stats_report::g_global_metrics.Initialize();

-}

-

-GoopdateImpl::~GoopdateImpl() {

-  CORE_LOG(L2, (_T("[GoopdateImpl::~GoopdateImpl]")));

-

-  // Bug 994348 does not repro anymore.

-  // If the assert fires, clean up the key, and fix the code if we have unit

-  // tests or application code that create the key.

-  ASSERT(!RegKey::HasKey(_T("HKEY_USERS\\.DEFAULT\\Software\\Google\\Update")),

-         (_T("This assert has fired because it has found the registry key at ")

-          _T("'HKEY_USERS\\.DEFAULT\\Software\\Google\\Update'. ")

-          _T("Please delete the key and report to omaha-core team if ")

-          _T("the assert fires again.")));

-

-  // The global metrics collection must be uninitialized before the metrics

-  // destructors are called.

-  stats_report::g_global_metrics.Uninitialize();

-

-  // Uninstall the exception handler. Program crashes are handled by Windows

-  // Error Reporting (WER) beyond this point.

-  Crash::UninstallCrashHandler();

-

-  // Reset the new handler.

-  set_new_handler(NULL);

-

-  // This check must be the last thing before exiting the process.

-  if (COMMANDLINE_MODE_INSTALL == args_.mode && args_.is_oem_set ||

-      ConfigManager::Instance()->IsOemInstalling(is_machine_)) {

-    // During an OEM install, there should be no persistent IDs.

-    ASSERT1(!RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueMachineId));

-    ASSERT1(!RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueUserId));

-

-    ASSERT1(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueOemInstallTimeSec) ||

-            !is_machine_ ||

-            !vista_util::IsUserAdmin() ||

-            !ConfigManager::Instance()->IsWindowsInstalling());

-  }

-}

-

-HRESULT GoopdateImpl::HandleError(HRESULT hr) {

-  // TODO(Omaha): An error dialog should ideally be shown for all

-  // errors that Main encounters. This will require a bit of work to

-  // ensure that we do not end up showing multiple dialogs, that we

-  // have resources to show a localized error message, that we show

-  // a message correctly even if we have not parsed the command line,

-  // or encounter an error in command line parsing, etc.

-

-#pragma warning(push)

-// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by

-// a case label.

-#pragma warning(disable : 4061)

-  switch (args_.mode) {

-    case COMMANDLINE_MODE_HANDOFF_INSTALL:

-    case COMMANDLINE_MODE_IG:

-    case COMMANDLINE_MODE_INSTALL: {

-      CString primary_app_name;

-      ASSERT1(!args_.extra.apps.empty());

-      if (!args_.extra.apps.empty()) {

-        primary_app_name = args_.extra.apps[0].app_name;

-      }

-

-      CString error_text;

-      switch (hr) {

-        // TODO(omaha): It would be nice if we could display this in the full

-        // UI so we can provide a link to the Help Center.

-        case OMAHA_NET_E_WINHTTP_NOT_AVAILABLE:

-          error_text.FormatMessage(IDS_WINDOWS_IS_NOT_UP_TO_DATE,

-                                   primary_app_name);

-          break;

-        default:

-          error_text.FormatMessage(IDS_SETUP_FAILED, hr);

-          break;

-      }

-

-      if (!args_.is_silent_set) {

-        goopdate_utils::DisplayErrorInMessageBox(error_text, primary_app_name);

-      }

-      return S_OK;

-    }

-

-    default:

-      return E_NOTIMPL;

-  }

-#pragma warning(pop)

-}

-

-HRESULT GoopdateImpl::Main(HINSTANCE instance,

-                           const TCHAR* cmd_line,

-                           int cmd_show) {

-  HRESULT hr = DoMain(instance, cmd_line, cmd_show);

-

-  CORE_LOG(L2, (_T("[has_uninstalled is %d]"), has_uninstalled_));

-

-  // For install processes, verify the Google Update EULA has been accepted and

-  // we can use the network unless a) the command line specifies EULA is

-  // required or b) in OEM installing mode, which also prevents network use.

-  if ((COMMANDLINE_MODE_INSTALL == args_.mode ||

-       COMMANDLINE_MODE_IG == args_.mode ||

-       COMMANDLINE_MODE_HANDOFF_INSTALL == args_.mode) &&

-       SUCCEEDED(hr)) {

-    ASSERT1(ConfigManager::Instance()->CanUseNetwork(is_machine_) ||

-            ConfigManager::Instance()->IsOemInstalling(is_machine_) ||

-            args_.is_eula_required_set);

-  }

-

-  // In the /install case, clean up if Google Update and/or app install did not

-  // complete successfully.

-  // Only aggregate the metrics if there is no chance that Google Update has

-  // or may be uninstalled and the process has the appropriate permissions.

-  // Uninstall will aggregate and report the metrics as appropriate.

-  bool did_install_uninstall_fail = false;

-  if (COMMANDLINE_MODE_INSTALL == args_.mode) {

-    did_install_uninstall_fail = FAILED(UninstallIfNecessary());

-  } else if (!has_uninstalled_) {

-    if (args_.mode == COMMANDLINE_MODE_UA) {

-      VERIFY1(SUCCEEDED(AggregateAndReportMetrics(is_machine_, false)));

-    } else if (!is_machine_ || vista_util::IsUserAdmin()) {

-      VERIFY1(SUCCEEDED(AggregateMetrics(is_machine_)));

-    }

-  }

-

-  // Uninitializing the network configuration must happen after reporting the

-  // metrics. The call succeeds even if the network has not been initialized

-  // due to errors up the execution path.

-  NetworkConfig::DeleteInstance();

-

-  if (COMMANDLINE_MODE_INSTALL == args_.mode &&

-      args_.is_oem_set &&

-      SUCCEEDED(hr) &&

-      !ConfigManager::Instance()->IsOemInstalling(is_machine_)) {

-    ASSERT1(false);

-    hr = GOOPDATE_E_OEM_INSTALL_SUCCEEDED_BUT_NOT_IN_OEM_INSTALLING_MODE;

-  }

-

-  // Verify that Google Update is either completely installed or uninstalled.

-  // Do not check in the following cases:

-  // * Modes that may exit during Setup, during uninstall, or while Omaha

-  //   is partially installed.

-  // * The mode is unknown, which means the args were not be parsed.

-  // * /cr instance, which may exit after Omaha is uninstalled.

-  // * /install instance that would not have called Setup.Uninstall().

-  // * /install instance when Uninstall failed for some reason since the

-  //   the consistency check may expect the wrong state.

-  if (COMMANDLINE_MODE_REGSERVER != args_.mode &&

-      COMMANDLINE_MODE_UNREGSERVER != args_.mode &&

-      COMMANDLINE_MODE_COMSERVER != args_.mode &&

-      COMMANDLINE_MODE_CODE_RED_CHECK != args_.mode &&

-      COMMANDLINE_MODE_SERVICE_REGISTER != args_.mode &&

-      COMMANDLINE_MODE_SERVICE_UNREGISTER != args_.mode &&

-      COMMANDLINE_MODE_UNKNOWN != args_.mode &&

-      !(COMMANDLINE_MODE_INSTALL == args_.mode &&

-        is_machine_ &&

-        !vista_util::IsUserAdmin()) &&

-      !did_install_uninstall_fail) {

-    Setup::CheckInstallStateConsistency(is_machine_);

-  }

-

-  return hr;

-}

-

-HRESULT GoopdateImpl::DoMain(HINSTANCE instance,

-                             const TCHAR* cmd_line,

-                             int cmd_show) {

-  module_instance_ = instance;

-  cmd_line_ = cmd_line;

-  cmd_show_ = cmd_show;

-

-  // The system terminates the process without displaying a retry dialog box

-  // for the user. GoogleUpdate has no user state to be saved, therefore

-  // prompting the user is meaningless.

-  VERIFY1(SUCCEEDED(SetProcessSilentShutdown()));

-

-  int major_version(0);

-  int minor_version(0);

-  int service_pack_major(0);

-  int service_pack_minor(0);

-  TCHAR name[MAX_PATH] = {0};

-  VERIFY1(SystemInfo::GetSystemVersion(&major_version,

-                                       &minor_version,

-                                       &service_pack_major,

-                                       &service_pack_minor,

-                                       name,

-                                       arraysize(name)));

-  metric_windows_major_version    = major_version;

-  metric_windows_minor_version    = minor_version;

-  metric_windows_sp_major_version = service_pack_major;

-  metric_windows_sp_minor_version = service_pack_minor;

-

-  InitializeVersionFromModule(module_instance_);

-  this_version_ = GetVersionString();

-

-  TCHAR path[MAX_PATH] = {0};

-  VERIFY1(::GetModuleFileName(instance, path, MAX_PATH));

-  OPT_LOG(L1, (_T("[%s][version %s][%s][%s]"),

-               path, this_version_, kBuildType, kOfficialBuild));

-

-  CORE_LOG(L2,

-      (_T("[is system %d][elevated admin %d][non-elevated admin %d]"),

-       is_local_system_,

-       vista_util::IsUserAdmin(),

-       vista_util::IsUserNonElevatedAdmin()));

-

-  HRESULT hr = omaha::ParseCommandLine(cmd_line, &args_);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[Parse cmd line failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  // IsMachineProcess requires the command line be parsed first.

-  is_machine_ = IsMachineProcess();

-  CORE_LOG(L2, (_T("[is machine %d]"), is_machine_));

-

-  // After parsing the command line, reinstall the crash handler to match the

-  // state of the process.

-  if (is_machine_ != Crash::is_machine()) {

-    VERIFY1(SUCCEEDED(Crash::InstallCrashHandler(is_machine_)));

-  }

-

-  // Set the current directory to be the one that the DLL was launched from.

-  TCHAR module_directory[MAX_PATH] = {0};

-  if (!GetModuleDirectory(instance, module_directory)) {

-     return HRESULTFromLastError();

-  }

-  if (!::SetCurrentDirectory(module_directory)) {

-    return HRESULTFromLastError();

-  }

-  OPT_LOG(L3, (_T("[Current dir][%s]"), module_directory));

-

-  // Set the usage stats as soon as possible, which is after the command line

-  // has been parsed, so that we can report crashes and other stats.

-  VERIFY1(SUCCEEDED(SetUsageStatsEnable()));

-

-  VERIFY1(SUCCEEDED(internal::PromoteAppEulaAccepted(is_machine_)));

-

-  hr = LoadResourceDllIfNecessary(args_.mode, module_directory);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[LoadResourceDllIfNecessary failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  user_default_language_id_ = ResourceManager::GetDefaultUserLanguage();

-

-#pragma warning(push)

-// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by

-// a case label.

-#pragma warning(disable : 4061)

-  // Save the mode on the stack for post-mortem debugging purposes.

-  volatile CommandLineMode mode = args_.mode;

-  switch (args_.mode) {

-    // Delegate to the service or the core. Both have reliability requirements

-    // and resource constraints. Generally speaking, they do not use COM nor

-    // networking code.

-    case COMMANDLINE_MODE_SERVICE:

-      return omaha::ServiceModule().Main(cmd_show);

-

-    case COMMANDLINE_MODE_SERVICE_REGISTER:

-      return SetupService::InstallService(app_util::GetModulePath(NULL));

-

-    case COMMANDLINE_MODE_SERVICE_UNREGISTER:

-      return SetupService::UninstallService();

-

-    default: {

-      scoped_co_init init_com_apt(COINIT_MULTITHREADED);

-      hr = init_com_apt.hresult();

-      if (FAILED(hr)) {

-        return hr;

-      }

-      hr = ::CoInitializeSecurity(

-          NULL,

-          -1,

-          NULL,   // Let COM choose what authentication services to register.

-          NULL,

-          RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  // Data integrity and encryption.

-          RPC_C_IMP_LEVEL_IDENTIFY,       // Only allow a server to identify.

-          NULL,

-          EOAC_DYNAMIC_CLOAKING,

-          NULL);

-      if (FAILED(hr)) {

-        return hr;

-      }

-

-      switch (args_.mode) {

-        case COMMANDLINE_MODE_CORE:

-          return omaha::Core().Main(is_local_system_,

-                                    !args_.is_crash_handler_disabled);

-

-        case COMMANDLINE_MODE_CRASH_HANDLER:

-          return omaha::CrashHandler().Main(is_local_system_);

-

-        case COMMANDLINE_MODE_NOARGS:

-          // TODO(omaha): Supported only for legacy Compatibility. Error out

-          // when legacy handoff support is removed as Omaha should not be

-          // called without arguments otherwise.

-          return S_OK;

-

-        case COMMANDLINE_MODE_LEGACYUI:

-          return HandleLegacyUI();

-

-        case COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF:

-          return HandleLegacyManifestHandoff();

-

-        case COMMANDLINE_MODE_UNREGISTER_PRODUCT:

-          return DoUnregisterProduct();

-

-        default: {

-          hr = goopdate_utils::ConfigureNetwork(

-              is_machine_ && vista_util::IsUserAdmin(),

-              is_local_system_);

-          if (FAILED(hr)) {

-            VERIFY1(SUCCEEDED(HandleError(hr)));

-            return hr;

-          }

-

-          switch (args_.mode) {

-            case COMMANDLINE_MODE_WEBPLUGIN:

-              return HandleWebPlugin();

-

-            case COMMANDLINE_MODE_CODE_RED_CHECK:

-              return HandleCodeRedCheck();

-

-            case COMMANDLINE_MODE_NETDIAGS:

-              return NetDiags().Main();

-

-            case COMMANDLINE_MODE_REGISTER_PRODUCT:

-              return DoRegisterProduct();

-

-            case COMMANDLINE_MODE_UPDATE:

-              return DoSelfUpdate();

-

-            case COMMANDLINE_MODE_UG:

-              return DoCompleteSelfUpdate();

-

-            case COMMANDLINE_MODE_RECOVER:

-              return DoRecover();

-

-            case COMMANDLINE_MODE_HANDOFF_INSTALL:

-            case COMMANDLINE_MODE_IG:

-            case COMMANDLINE_MODE_INSTALL:

-            case COMMANDLINE_MODE_UA:

-              return DoWorker();

-            case COMMANDLINE_MODE_CRASH:

-              return DoCrash();

-

-            case COMMANDLINE_MODE_REPORTCRASH:

-              return HandleReportCrash();

-

-            case COMMANDLINE_MODE_REGSERVER:

-            case COMMANDLINE_MODE_UNREGSERVER:

-            case COMMANDLINE_MODE_COMSERVER:

-              return omaha::GoogleUpdate().Main();

-

-            default:

-              // We have a COMMANDLINE_MODE_ that isn't being handled.

-              ASSERT1(false);

-              OPT_LOG(LE, (_T("[Command line has unhandled mode]")));

-              return E_UNEXPECTED;

-          }

-        }

-      }

-    }

-  }

-#pragma warning(pop)

-}

-

-bool GoopdateImpl::IsMachineProcess() {

-  Tristate needs_admin(TRISTATE_NONE);

-  if (!args_.extra.apps.empty()) {

-    needs_admin = args_.extra.apps[0].needs_admin ? TRISTATE_TRUE :

-                                                    TRISTATE_FALSE;

-  }

-

-  return goopdate_utils::IsMachineProcess(

-      args_.mode,

-      goopdate_utils::IsRunningFromOfficialGoopdateDir(true),

-      is_local_system_,

-      args_.is_machine_set,

-      needs_admin);

-}

-

-

-HRESULT GoopdateImpl::HandleReportCrash() {

-  // Catch exceptions to avoid reporting crashes when handling a crash.

-  // TODO(omaha): maybe let Windows handle the crashes when reporting crashes

-  // in certain interactive modes.

-  HRESULT hr = S_OK;

-  __try {

-    // Crashes are uploaded always in the out-of-process case. This is handled

-    // in Crash::Report().

-    // Google Update crashes are uploaded only for for the users that have opted

-    // in, when network use is allowed, and from systems that are not

-    // development or test.

-    // All GoogleUpdate crashes are logged in the Windows event log for

-    // applications, unless the logging is disabled by the administrator.

-    const bool can_upload_in_process =

-        ConfigManager::Instance()->CanCollectStats(is_machine_) &&

-        ConfigManager::Instance()->CanUseNetwork(is_machine_) &&

-        !goopdate_utils::IsTestSource();

-    hr = Crash::Report(can_upload_in_process,

-                       args_.crash_filename,

-                       args_.custom_info_filename,

-                       user_default_language_id_);

-  }

-  __except(EXCEPTION_EXECUTE_HANDLER) {

-    hr = E_FAIL;

-  }

-  return hr;

-}

-

-HRESULT GoopdateImpl::HandleLegacyManifestHandoff() {

-  // TODO(omaha): Once the core supports metric aggregation, move this metric

-  // to LegacyManifestHandler::HandleEvent().

-  ++metric_handoff_legacy_user;

-

-  // The user core launches the is_legacy_user_manifest_cmd worker to

-  // process the manifest file that is dropped into the initial manifest

-  // directory by the omaha1 installers.

-  if (!goopdate_utils::IsRunningFromOfficialGoopdateDir(false)) {

-    // TODO(omaha): If the /UI process fails the legacy installer will

-    // not display anything to the user. We might have to launch UI here.

-    ASSERT1(false);

-    return E_FAIL;

-  }

-

-  return goopdate_utils::HandleLegacyManifestHandoff(

-      args_.legacy_manifest_path,

-      false);

-}

-

-HRESULT GoopdateImpl::HandleLegacyUI() {

-  ++metric_handoff_legacy_machine;

-

-  // A omaha1 installer does a handoff install using

-  // the /UI switch. The format of the command line is as follows:

-  // /UI /lang <lang> manfest_filename or /UI legacy_manifest_path

-  // The legacy installer should have elevated and we should

-  // be running from the program files directory since this command can

-  // only be passed to a registered, machine omaha.

-  if (!vista_util::IsUserAdmin() ||

-      !goopdate_utils::IsRunningFromOfficialGoopdateDir(true)) {

-    // TODO(omaha): If the /UI process fails the legacy installer will

-    // not display anything to the user. We might have to launch UI here.

-    ASSERT1(false);

-    return E_FAIL;

-  }

-

-  // We ignore the /lang switch that is passed on the cmd line,

-  // since we get the language from the manifest file and pass that to the

-  // worker.

-  return goopdate_utils::HandleLegacyManifestHandoff(

-      args_.legacy_manifest_path, true);

-}

-

-// The resource dll is loaded only in the following cases:

-// 1. Initial setup: /install

-// 2. Google Update and app install: /ig

-// 3. Handoff install: /handoff

-// 4. App update worker: /ua

-// 5. Self-Update: /ug

-HRESULT GoopdateImpl::LoadResourceDllIfNecessary(CommandLineMode mode,

-                                                 const CString& resource_dir) {

-  switch (mode) {

-    case COMMANDLINE_MODE_INSTALL:          // has UI on errors

-    case COMMANDLINE_MODE_IG:               // has UI

-    case COMMANDLINE_MODE_HANDOFF_INSTALL:  // has UI

-    case COMMANDLINE_MODE_UG:               // TODO(omaha): Why is it loaded?

-    case COMMANDLINE_MODE_UA:               // Worker, etc. load strings.

-    case COMMANDLINE_MODE_COMSERVER:        // Returns strings to caller.

-    case COMMANDLINE_MODE_SERVICE_REGISTER:

-    case COMMANDLINE_MODE_SERVICE_UNREGISTER:

-      // Load the resource DLL for these modes.

-      break;

-    case COMMANDLINE_MODE_UNKNOWN:

-    case COMMANDLINE_MODE_NOARGS:

-    case COMMANDLINE_MODE_CORE:

-    case COMMANDLINE_MODE_CRASH_HANDLER:

-    case COMMANDLINE_MODE_SERVICE:

-    case COMMANDLINE_MODE_REGSERVER:

-    case COMMANDLINE_MODE_UNREGSERVER:

-    case COMMANDLINE_MODE_NETDIAGS:

-    case COMMANDLINE_MODE_CRASH:

-    case COMMANDLINE_MODE_REPORTCRASH:

-    case COMMANDLINE_MODE_UPDATE:

-    case COMMANDLINE_MODE_RECOVER:

-    case COMMANDLINE_MODE_WEBPLUGIN:

-    case COMMANDLINE_MODE_CODE_RED_CHECK:

-    case COMMANDLINE_MODE_LEGACYUI:

-    case COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF:

-    case COMMANDLINE_MODE_REGISTER_PRODUCT:

-    case COMMANDLINE_MODE_UNREGISTER_PRODUCT:

-    default:

-      // Thse modes do not need the resource DLL.

-      return S_OK;

-  }

-

-  resource_manager_.reset(new ResourceManager(is_machine_, resource_dir));

-

-  HRESULT hr = resource_manager_->LoadResourceDll(args_.extra.language);

-  if (FAILED(hr)) {

-    ++metric_load_resource_dll_failed;

-    ASSERT(false, (_T("LoadResourceDll failed with 0x%08x"), hr));

-  }

-  return hr;

-}

-

-// Writes the information for the primary app to enable Omaha to send usage

-// stats now. It will be set for each app in the args when they are installed.

-HRESULT GoopdateImpl::SetUsageStatsEnable() {

-  if (COMMANDLINE_MODE_UPDATE == args_.mode) {

-    VERIFY1(SUCCEEDED(

-        goopdate_utils::ConvertLegacyUsageStats(is_machine_)));

-  }

-

-  if (args_.extra.apps.empty()) {

-    return S_OK;

-  }

-

-  HRESULT hr = goopdate_utils::SetUsageStatsEnable(

-      args_.extra.apps[0].needs_admin,

-      GuidToString(args_.extra.apps[0].app_guid),

-      args_.extra.usage_stats_enable);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[SetUsageStatsEnable failed][0x%08x]"), hr));

-

-    if ((HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr) &&

-        args_.extra.apps[0].needs_admin &&

-        !vista_util::IsUserAdmin()) {

-      CORE_LOG(L3, (_T("[Process does not have permission to HKLM]")));

-      return S_OK;

-    }

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT GoopdateImpl::HandleCodeRedCheck() {

-  CORE_LOG(L2, (_T("[GoopdateImpl::HandleCodeRedCheck]")));

-  ++metric_cr_process_total;

-

-  // Call the utils method instead of member method because we want to execute

-  // as little code as possible.

-  bool is_machine = goopdate_utils::IsMachineProcess(args_.mode,

-                                                     false,   // machine dir

-                                                     is_local_system_,

-                                                     args_.is_machine_set,

-                                                     TRISTATE_NONE);

-  ASSERT1(IsMachineProcess() == is_machine);

-

-  if (!ConfigManager::Instance()->CanUseNetwork(is_machine)) {

-    CORE_LOG(L1,

-             (_T("[Code Red check not sent because network use prohibited]")));

-    return GOOPDATE_E_CANNOT_USE_NETWORK;

-  }

-

-  HRESULT hr = FixGoogleUpdate(kGoogleUpdateAppId,

-                               this_version_,

-                               _T(""),     // Goopdate doesn't have a language.

-                               is_machine,

-                               &GoopdateImpl::CodeRedDownloadCallback,

-                               NULL);

-  CORE_LOG(L2, (_T("[FixGoogleUpdate returned 0x%08x]"), hr));

-  return S_OK;

-}

-

-// Returns S_OK when the download of the Code Red file succeeds and E_FAIL

-// otherwise.

-HRESULT GoopdateImpl::CodeRedDownloadCallback(const TCHAR* url,

-                                              const TCHAR* file_path,

-                                              void*) {

-  ++metric_cr_callback_total;

-

-  NetworkConfig& network_config = NetworkConfig::Instance();

-  NetworkRequest network_request(network_config.session());

-

-  network_request.AddHttpRequest(new SimpleRequest);

-

-  // BITS takes the job to BG_JOB_STATE_TRANSIENT_ERROR when the server returns

-  // 204. After the "no progress time out", the BITS job errors out. Since

-  // BITS follows the WinHTTP in the fallback chain, the code is expected to

-  // execute only if WinHTTP fails to get a response from the server.

-

-  // Assumes the caller is not logged on if the function failed.

-  // BITS transfers files only when the job owner is logged on.

-  bool is_logged_on(false);

-  HRESULT hr = IsUserLoggedOn(&is_logged_on);

-  ASSERT1(SUCCEEDED(hr) || !is_logged_on);

-  if (is_logged_on) {

-    BitsRequest* bits_request(new BitsRequest);

-    bits_request->set_minimum_retry_delay(60);

-    bits_request->set_no_progress_timeout(15);

-    network_request.AddHttpRequest(bits_request);

-  }

-

-  network_request.AddHttpRequest(new BrowserRequest);

-  hr = network_request.DownloadFile(CString(url), CString(file_path));

-  if (FAILED(hr)) {

-    return E_FAIL;

-  }

-

-  switch (network_request.http_status_code()) {

-    case HTTP_STATUS_OK:

-      ++metric_cr_callback_status_200;

-      return S_OK;

-    case HTTP_STATUS_NO_CONTENT:

-      ++metric_cr_callback_status_204;

-      return E_FAIL;

-    default:

-      ++metric_cr_callback_status_other;

-      return E_FAIL;

-  }

-}

-

-// Until bug 1135173 is fixed:

-// Running a OneClick cross-install at the same time as Setup has undefined

-// behavior. If Setup wins the race to the lock, it may delete the files that

-// the cross-install wants to copy. Also, since the plugin and /plugin instance

-// do not check the Setup Lock, they may try to invoke a version that is being

-// installed, removed, or rolled back.

-

-// If we're called with the /webplugin command, we need to handle it and exit.

-// This is called from the browser and the command line arguments come from the

-// website so we need to be restrictive of what we let past. If everything from

-// the plugin is valid, we'll relaunch goopdate with the proper commands.

-HRESULT GoopdateImpl::HandleWebPlugin() {

-  return webplugin_utils::DoOneClickInstall(args_);

-}

-

-HRESULT GoopdateImpl::DoCompleteSelfUpdate() {

-  OPT_LOG(L1, (_T("[GoopdateImpl::DoCompleteSelfUpdate]")));

-  // TODO(omaha): The use of is_machine_set is very non-intuituve.

-  // It is used only for machine repair situations when elevation is required

-  // in vista or in case of XP. For all other cases this is not used and plain

-  // /update is used to invoke recovery.

-  // Another consequence of this is that in some cases we run

-  // the full Omaha update logic i.e. ShouldInstall etc for recovery.

-  // Consider making recovery not go through all this code.

-  OPT_LOG(L1, (_T("[self update][is_machine=%d]"), is_machine_));

-

-  Ping ping;

-  return FinishGoogleUpdateInstall(args_,

-                                   is_machine_,

-                                   true,

-                                   &ping,

-                                   NULL);

-}

-

-// Calls DoRegisterProductHelper and sends a ping with the result.

-// TODO(omaha): Use a more common code flow with normal installs or remove

-// registerproduct altogether when redesigning Omaha.

-HRESULT GoopdateImpl::DoRegisterProduct() {

-  OPT_LOG(L1, (_T("[GoopdateImpl::DoRegisterProduct]")));

-

-  ASSERT1(!goopdate_utils::IsRunningFromOfficialGoopdateDir(false) &&

-          !goopdate_utils::IsRunningFromOfficialGoopdateDir(true));

-

-  ASSERT1(!args_.extra.apps.empty());

-  // TODO(omaha): Support bundles. Only supports one app currently.

-  ASSERT1(1 == args_.extra.apps.size());

-  bool extra_needs_admin = args_.extra.apps[0].needs_admin;

-

-  AppManager app_manager(extra_needs_admin);

-  ProductDataVector products;

-  app_manager.ConvertCommandLineToProductData(args_, &products);

-  AppData app_data = products[0].app_data();

-

-  HRESULT hr = DoRegisterProductHelper(extra_needs_admin,

-                                       &app_manager,

-                                       &app_data);

-

-  const PingEvent::Results event_result = SUCCEEDED(hr) ?

-                                          PingEvent::EVENT_RESULT_SUCCESS :

-                                          PingEvent::EVENT_RESULT_ERROR;

-

-  AppRequestData app_request_data(app_data);

-  PingEvent ping_event(PingEvent::EVENT_REGISTER_PRODUCT_COMPLETE,

-                       event_result,

-                       hr,  // error code

-                       0,  // extra code 1

-                       app_data.previous_version());

-  app_request_data.AddPingEvent(ping_event);

-  AppRequest app_request(app_request_data);

-  Request request(extra_needs_admin);

-  request.AddAppRequest(app_request);

-

-  Ping ping;

-  ping.SendPing(&request);

-

-  return hr;

-}

-

-HRESULT GoopdateImpl::DoRegisterProductHelper(bool is_machine,

-                                              AppManager* app_manager,

-                                              AppData* app_data) {

-  ASSERT1(app_data);

-  ASSERT1(app_manager);

-  // Ensure we're running as elevated admin if needs_admin is true.

-  if (is_machine && !vista_util::IsUserAdmin()) {

-    CORE_LOG(LE, (_T("[DoRegisterProduct][needs admin & user not admin]")));

-    return GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP;

-  }

-

-  // Get product GUID from args and register it in CLIENTS.

-  HRESULT hr = app_manager->RegisterProduct(args_.extra.apps[0].app_guid,

-                                            args_.extra.apps[0].app_name);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[AppManager::RegisterProduct failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  Setup setup(is_machine, &args_);

-  hr = setup.InstallSelfSilently();

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[Setup::InstallSelfSilently failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Populate the app's ClientState key.

-  VERIFY1(SUCCEEDED(app_manager->WritePreInstallData(*app_data)));

-  VERIFY1(SUCCEEDED(app_manager->InitializeApplicationState(app_data)));

-

-  return S_OK;

-}

-

-HRESULT GoopdateImpl::DoUnregisterProduct() {

-  bool extra_needs_admin = args_.extra.apps[0].needs_admin;

-

-  // Ensure we're running as elevated admin if needs_admin is true.

-  if (extra_needs_admin && !vista_util::IsUserAdmin()) {

-    CORE_LOG(LE, (_T("[DoUnregisterProduct][needs admin & user not admin]")));

-    return GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP;

-  }

-

-  AppManager app_manager(extra_needs_admin);

-  HRESULT hr = app_manager.UnregisterProduct(args_.extra.apps[0].app_guid);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[AppManager::UnregisterProduct failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT GoopdateImpl::DoSelfUpdate() {

-  OPT_LOG(L1, (_T("[GoopdateImpl::DoSelfUpdate]")));

-

-  Setup setup(is_machine_, &args_);

-  HRESULT hr = setup.UpdateSelfSilently();

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[Setup::UpdateSelfSilently failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// Attempts to launch the repair file elevated using the MSP. If elevation is

-// not needed or fails, attempts to install without elevating.

-// The code_red_metainstaller_path arg is the repair file.

-HRESULT GoopdateImpl::DoRecover() {

-  OPT_LOG(L1, (_T("[GoopdateImpl::DoRecover()]")));

-

-  CommandLineBuilder builder(COMMANDLINE_MODE_UPDATE);

-

-  HRESULT hr = S_OK;

-  if (LaunchRepairFileElevated(is_machine_,

-                               args_.code_red_metainstaller_path,

-                               builder.GetCommandLineArgs(),

-                               &hr)) {

-    ASSERT1(SUCCEEDED(hr));

-    return S_OK;

-  }

-

-  if (FAILED(hr)) {

-    OPT_LOG(LW, (_T("[LaunchRepairFileElevated failed][0x%08x]"), hr));

-  }

-

-  Setup setup(is_machine_, &args_);

-  hr = setup.RepairSilently();

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Non-elevated repair failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// Clears the EULA flag in the handoff instance in case an older installer that

-// does not know about the EULA flag is used to launch the install.

-// Failing to clear flag fails installation because this would prevent updates.

-HRESULT GoopdateImpl::DoWorker() {

-  if (COMMANDLINE_MODE_HANDOFF_INSTALL == args_.mode &&

-      !args_.is_eula_required_set) {

-    HRESULT hr = Setup::SetEulaAccepted(is_machine_);

-    if (FAILED(hr)) {

-      CORE_LOG(LE, (_T("[Setup::SetEulaAccepted failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  omaha::Worker worker(is_machine_);

-  HRESULT hr = worker.Main(goopdate_);

-  has_uninstalled_ = worker.has_uninstalled();

-

-  // The UA worker always returns S_OK. UA can be launched by the scheduled task

-  // or the core, neither of which wait for a return code. On Vista, returning

-  // an error code from the scheduled task reportedly causes issues with the

-  // task scheduler in rare cases, so returning S_OK helps with that as well.

-  if (args_.mode == COMMANDLINE_MODE_UA) {

-    return S_OK;

-  }

-

-  return hr;

-}

-

-HRESULT GoopdateImpl::DoCrash() {

-#if DEBUG

-  return static_cast<HRESULT>(Crash::CrashNow());

-#else

-  return S_OK;

-#endif

-}

-

-// In dbg builds, also checks the post conditions of a /install process to

-// ensure that the registry is correctly populated or has been cleaned up.

-HRESULT GoopdateImpl::UninstallIfNecessary() {

-  ASSERT1(COMMANDLINE_MODE_INSTALL == args_.mode);

-  ASSERT(!has_uninstalled_, (_T("Worker doesn't uninstall in /install mode")));

-

-  if (is_machine_ && !vista_util::IsUserAdmin()) {

-    // The non-elevated instance, so do not try to uninstall.

-    ASSERT1(!args_.is_install_elevated);

-    return S_OK;

-  } else {

-    CORE_LOG(L2, (_T("[GoopdateImpl::Main /install][Uninstall if necessary]")));

-    // COM must be initialized in order to uninstall the scheduled task(s).

-    scoped_co_init init_com_apt(COINIT_MULTITHREADED);

-    Setup setup(is_machine_, &args_);

-    return setup.Uninstall();

-  }

-}

-

-void GoopdateImpl::OutOfMemoryHandler() {

-  ::RaiseException(EXCEPTION_ACCESS_VIOLATION,

-                   EXCEPTION_NONCONTINUABLE,

-                   0,

-                   NULL);

-}

-

-}  // namespace detail

-

-namespace internal {

-

-// Returns early if Google Update's EULA is already accepted, as indicated by

-// the lack of eulaaccepted in the Update key.

-// The apps' values are not modified or deleted.

-HRESULT PromoteAppEulaAccepted(bool is_machine) {

-  const TCHAR* update_key_name =

-      ConfigManager::Instance()->registry_update(is_machine);

-  if (!RegKey::HasValue(update_key_name, kRegValueOmahaEulaAccepted)) {

-    return S_OK;

-  }

-

-  const TCHAR* state_key_name =

-      ConfigManager::Instance()->registry_client_state(is_machine);

-

-  RegKey state_key;

-  HRESULT hr = state_key.Open(state_key_name, KEY_READ);

-  if (FAILED(hr)) {

-    if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) {

-      return S_FALSE;

-    }

-    return hr;

-  }

-

-  // TODO(omaha): This should actually be iterating over registered products

-  // rather than present ClientState keys. These are identical in most cases.

-  int num_sub_keys = state_key.GetSubkeyCount();

-  for (int i = 0; i < num_sub_keys; ++i) {

-    CString sub_key_name;

-    if (FAILED(state_key.GetSubkeyNameAt(i, &sub_key_name))) {

-      continue;

-    }

-

-    if (goopdate_utils::IsAppEulaAccepted(is_machine, sub_key_name, true)) {

-      ASSERT1(kGoogleUpdateAppId != sub_key_name);

-      return Setup::SetEulaAccepted(is_machine);

-    }

-  }

-

-  return S_OK;

-}

-

-}  // namespace internal

-

-Goopdate::Goopdate(bool is_local_system) {

-  CORE_LOG(L2, (_T("[Goopdate::Goopdate]")));

-  impl_.reset(new detail::GoopdateImpl(this, is_local_system));

-}

-

-Goopdate::~Goopdate() {

-  CORE_LOG(L2, (_T("[Goopdate::~Goopdate]")));

-}

-

-HRESULT Goopdate::Main(HINSTANCE instance,

-                       const TCHAR* cmd_line,

-                       int cmd_show) {

-  return impl_->Main(instance, cmd_line, cmd_show);

-}

-

-bool Goopdate::is_local_system() const {

-  return impl_->is_local_system();

-}

-

-CommandLineArgs Goopdate::args() const {

-  return impl_->args();

-}

-

-CString Goopdate::cmd_line() const {

-  return impl_->cmd_line();

-}

-

-OBJECT_ENTRY_AUTO(__uuidof(ProcessLauncherClass), ProcessLauncher)

-OBJECT_ENTRY_AUTO(__uuidof(OnDemandUserAppsClass), OnDemandCOMClass)

-OBJECT_ENTRY_AUTO(__uuidof(OnDemandMachineAppsClass), OnDemandCOMClassMachine)

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// For interactive instances, do not access the network before displaying the
+// UI. This provides a better user experience - quick UI - when the network is
+// slow. It is also required to ensure that UI displayed event is signaled
+// before potentially waiting on a firewall prompt.
+//
+// Debugging notes:
+//  * Omaha (and app) initial install:
+//   * File install can be debugged with the following command arguments:
+//      /install "appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&appname=Google%20Chrome&needsadmin=False&lang=en"  // NOLINT
+//      /install "appguid={283EAF47-8817-4c2b-A801-AD1FADFB7BAA}&appname=Gears&needsadmin=True&lang=en"  // NOLINT
+//   * If elevation is required, another instance is launched. Run elevated to
+//     continue debugging.
+//   * Once the initial files have been copied, another instance is launched
+//     from the installed location. To continue debugging, use the following
+//     command arguments:
+//      /ig "appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&appname=Google%20Chrome&needsadmin=False&lang=en"  // NOLINT
+//      /ig "appguid={283EAF47-8817-4c2b-A801-AD1FADFB7BAA}&appname=Gears&needsadmin=True&lang=en"  // NOLINT
+//  * App hand-off initial install or over-install:
+//      /handoff "appguid={8A69D345-D564-463C-AFF1-A69D9E530F96}&appname=Google%20Chrome&needsadmin=False&lang=en"  // NOLINT
+//      /handoff "appguid={283EAF47-8817-4c2b-A801-AD1FADFB7BAA}&appname=Gears&needsadmin=True&lang=en"  // NOLINT
+//  * Silent install:
+//   * Add "/silent" to any of the above command lines (not to the tag).
+//  * Google Update self-update:
+//   * File install can be debugged with the following command arguments:
+//      /update
+//   * Once the initial files have been copied, another instance is launched
+//     from the installed location. To continue debugging, use the following
+//     command arguments:
+//      /ug
+//  * Update check for apps that need it:
+//      /ua
+//  * Legacy hand-off install (Occurs from the machine install location)
+//   * First /UI /lang en legacy_manifest_path
+//   * This then launches a worker with:
+//      /handoff "appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&appname=YouTube Uploader&needsadmin=False" /lang en  // NOLINT
+//  * Core:
+//      /c
+//  * Cod Red check:
+//      /cr
+//  * Cod Red repair:
+//   * Determining whether to elevate and non-elevated file install can be
+//     debugged with the following command arguments:
+//      /recover [/machine]
+//   * Once the initial files have been copied, another instance is launched
+//     from the installed location. To continue debugging, use the following
+//     command arguments:
+//      /ug [/machine]
+//  * OneClick:
+//      /pi "http://www.google.com/" "/install%20%22appguid=%7B8A69D345-D564-463C-AFF1-A69D9E530F96%7D%26lang=en%26appname=Google%2520Chrome%26needsadmin=false" /installsource oneclick  // NOLINT
+
+#include "omaha/goopdate/goopdate.h"
+
+#include <atlstr.h>
+#include <new>
+#include "base/scoped_ptr.h"
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/google_update_recovery.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/module_utils.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/proc_utils.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/core/core.h"
+#include "omaha/core/crash_handler.h"
+#include "omaha/goopdate/browser_launcher.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/crash.h"
+#include "omaha/goopdate/goopdate_helper.h"
+#include "omaha/goopdate/google_update.h"
+#include "omaha/goopdate/goopdate_metrics.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/goopdate_xml_parser.h"
+#include "omaha/goopdate/goopdate-internal.h"
+#include "omaha/goopdate/stats_uploader.h"
+#include "omaha/goopdate/webplugin_utils.h"
+#include "omaha/net/net_diags.h"
+#include "omaha/net/browser_request.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/bits_request.h"
+#include "omaha/net/simple_request.h"
+#include "omaha/recovery/repair_exe/repair_goopdate.h"
+#include "omaha/service/service_main.h"
+#include "omaha/setup/setup.h"
+#include "omaha/setup/setup_service.h"
+#include "omaha/worker/app_request_data.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/application_manager.h"
+#include "omaha/worker/ping.h"
+#include "omaha/worker/worker.h"
+#include "omaha/worker/worker_com_wrapper.h"
+#include "omaha/worker/worker_event_logger.h"
+#include "third_party/breakpad/src/client/windows/sender/crash_report_sender.h"
+#include "third_party/breakpad/src/client/windows/handler/exception_handler.h"
+
+// Generated by MIDL into $OBJ_ROOT/goopdate.
+#include "goopdate/google_update_idl.h"
+
+namespace omaha {
+
+namespace {
+
+#if DEBUG
+const TCHAR* const kBuildType = _T("dbg");
+#else
+const TCHAR* const kBuildType = _T("opt");
+#endif
+
+#if OFFICIAL_BUILD
+const TCHAR* const kOfficialBuild = _T("official");
+#else
+const TCHAR* const kOfficialBuild = _T("dev");
+#endif
+
+}  // namespace
+
+namespace detail {
+
+class GoopdateImpl {
+ public:
+  GoopdateImpl(Goopdate* goopdate, bool is_local_system);
+  ~GoopdateImpl();
+
+  HRESULT Main(HINSTANCE instance, const TCHAR* cmd_line, int cmd_show);
+
+  bool is_local_system() const { return is_local_system_; }
+
+  CommandLineArgs args() const { return args_; }
+  CString cmd_line() const { return cmd_line_; }
+
+ private:
+  HRESULT DoMain(HINSTANCE instance, const TCHAR* cmd_line, int cmd_show);
+
+  // Returns whether a process is a machine process.
+  // Does not determine whether the process has the appropriate privileges.
+  bool IsMachineProcess();
+
+  HRESULT LoadResourceDllIfNecessary(CommandLineMode mode,
+                                     const CString& resource_dir);
+
+  HRESULT SetUsageStatsEnable();
+
+  // Handles error conditions by showing UI.
+  HRESULT HandleError(HRESULT hr);
+
+  // Handles response to /pi command.
+  HRESULT HandleWebPlugin();
+
+  // Handles responses to /cr command.
+  HRESULT HandleCodeRedCheck();
+
+  // Handles /ui command.
+  HRESULT HandleLegacyUI();
+
+  // Handles /report command.
+  HRESULT HandleReportCrash();
+
+  // Handles /uiuser command.
+  HRESULT HandleLegacyManifestHandoff();
+
+  // Download Callback for Code Red.
+  static HRESULT CodeRedDownloadCallback(const TCHAR* url,
+                                         const TCHAR* file_path,
+                                         void*);
+  HRESULT DoWorker();
+
+  // Generates a divide by zero to trigger breakpad dump.
+  // Is only enabled in debug builds.
+  HRESULT DoCrash();
+
+  // Register a product with Goopdate and install Goopdate.
+  HRESULT DoRegisterProduct();
+
+  // Does the work for DoRegisterProduct().
+  HRESULT DoRegisterProductHelper(bool is_machine,
+                                  AppManager* app_manager,
+                                  AppData* app_data);
+
+  // Unregister a product from Goopdate.
+  HRESULT DoUnregisterProduct();
+
+  // Setup phase1 for self update.
+  HRESULT DoSelfUpdate();
+
+  // Setup phase2 for self update.
+  HRESULT DoCompleteSelfUpdate();
+
+  // Handles the recover command in Google Update.
+  HRESULT DoRecover();
+
+  // Uninstalls Google Update if a /install process failed to install itself
+  // or the app and there are no other apps registered.
+  HRESULT UninstallIfNecessary();
+
+  // Called by operator new or operator new[] when they cannot satisfy
+  // a request for additional storage.
+  static void OutOfMemoryHandler();
+
+  HINSTANCE module_instance_;  // Current module instance.
+  CString cmd_line_;           // Command line, as provided by the OS.
+  int cmd_show_;
+
+  CommandLineArgs args_;       // Command line options and flags.
+
+  // True if the process belongs to a machine Omaha "session".
+  bool is_machine_;
+  bool is_local_system_;       // True if running as LOCAL_SYSTEM.
+  CString this_version_;       // Version of this Goopdate DLL.
+
+  // True if Omaha has been uninstalled by the Worker.
+  bool has_uninstalled_;
+
+  // Language identifier for the current user locale.
+  CString user_default_language_id_;
+
+  scoped_ptr<ResourceManager> resource_manager_;
+  Goopdate* goopdate_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(GoopdateImpl);
+};
+
+GoopdateImpl::GoopdateImpl(Goopdate* goopdate, bool is_local_system)
+    : module_instance_(NULL),
+      cmd_show_(0),
+      is_machine_(false),
+      is_local_system_(is_local_system),
+      has_uninstalled_(false),
+      goopdate_(goopdate) {
+  ASSERT1(goopdate);
+  // The command line needs to be parsed to accurately determine if the
+  // current process is a machine process or not. Use the value of
+  // is_local_system until that.
+  is_machine_ = is_local_system_;
+
+  // Install an error-handling mechanism which gets called when new operator
+  // fails to allocate memory.
+  VERIFY1(set_new_handler(&GoopdateImpl::OutOfMemoryHandler) == 0);
+
+  // Install the exception handler.
+  VERIFY1(SUCCEEDED(Crash::InstallCrashHandler(is_machine_)));
+
+  // Initialize the global metrics collection.
+  stats_report::g_global_metrics.Initialize();
+}
+
+GoopdateImpl::~GoopdateImpl() {
+  CORE_LOG(L2, (_T("[GoopdateImpl::~GoopdateImpl]")));
+
+  // Bug 994348 does not repro anymore.
+  // If the assert fires, clean up the key, and fix the code if we have unit
+  // tests or application code that create the key.
+  ASSERT(!RegKey::HasKey(_T("HKEY_USERS\\.DEFAULT\\Software\\Google\\Update")),
+         (_T("This assert has fired because it has found the registry key at ")
+          _T("'HKEY_USERS\\.DEFAULT\\Software\\Google\\Update'. ")
+          _T("Please delete the key and report to omaha-core team if ")
+          _T("the assert fires again.")));
+
+  // The global metrics collection must be uninitialized before the metrics
+  // destructors are called.
+  stats_report::g_global_metrics.Uninitialize();
+
+  // Uninstall the exception handler. Program crashes are handled by Windows
+  // Error Reporting (WER) beyond this point.
+  Crash::UninstallCrashHandler();
+
+  // Reset the new handler.
+  set_new_handler(NULL);
+
+  // This check must be the last thing before exiting the process.
+  if (COMMANDLINE_MODE_INSTALL == args_.mode && args_.is_oem_set ||
+      ConfigManager::Instance()->IsOemInstalling(is_machine_)) {
+    // During an OEM install, there should be no persistent IDs.
+    ASSERT1(!RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueMachineId));
+    ASSERT1(!RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueUserId));
+
+    ASSERT1(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueOemInstallTimeSec) ||
+            !is_machine_ ||
+            !vista_util::IsUserAdmin() ||
+            !ConfigManager::Instance()->IsWindowsInstalling());
+  }
+}
+
+HRESULT GoopdateImpl::HandleError(HRESULT hr) {
+  // TODO(Omaha): An error dialog should ideally be shown for all
+  // errors that Main encounters. This will require a bit of work to
+  // ensure that we do not end up showing multiple dialogs, that we
+  // have resources to show a localized error message, that we show
+  // a message correctly even if we have not parsed the command line,
+  // or encounter an error in command line parsing, etc.
+
+#pragma warning(push)
+// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by
+// a case label.
+#pragma warning(disable : 4061)
+  switch (args_.mode) {
+    case COMMANDLINE_MODE_HANDOFF_INSTALL:
+    case COMMANDLINE_MODE_IG:
+    case COMMANDLINE_MODE_INSTALL: {
+      CString primary_app_name;
+      ASSERT1(!args_.extra.apps.empty());
+      if (!args_.extra.apps.empty()) {
+        primary_app_name = args_.extra.apps[0].app_name;
+      }
+
+      CString error_text;
+      switch (hr) {
+        // TODO(omaha): It would be nice if we could display this in the full
+        // UI so we can provide a link to the Help Center.
+        case OMAHA_NET_E_WINHTTP_NOT_AVAILABLE:
+          error_text.FormatMessage(IDS_WINDOWS_IS_NOT_UP_TO_DATE,
+                                   primary_app_name);
+          break;
+        default:
+          error_text.FormatMessage(IDS_SETUP_FAILED, hr);
+          break;
+      }
+
+      if (!args_.is_silent_set) {
+        goopdate_utils::DisplayErrorInMessageBox(error_text, primary_app_name);
+      }
+      return S_OK;
+    }
+
+    default:
+      return E_NOTIMPL;
+  }
+#pragma warning(pop)
+}
+
+HRESULT GoopdateImpl::Main(HINSTANCE instance,
+                           const TCHAR* cmd_line,
+                           int cmd_show) {
+  HRESULT hr = DoMain(instance, cmd_line, cmd_show);
+
+  CORE_LOG(L2, (_T("[has_uninstalled is %d]"), has_uninstalled_));
+
+  // For install processes, verify the Google Update EULA has been accepted and
+  // we can use the network unless a) the command line specifies EULA is
+  // required or b) in OEM installing mode, which also prevents network use.
+  if ((COMMANDLINE_MODE_INSTALL == args_.mode ||
+       COMMANDLINE_MODE_IG == args_.mode ||
+       COMMANDLINE_MODE_HANDOFF_INSTALL == args_.mode) &&
+       SUCCEEDED(hr)) {
+    ASSERT1(ConfigManager::Instance()->CanUseNetwork(is_machine_) ||
+            ConfigManager::Instance()->IsOemInstalling(is_machine_) ||
+            args_.is_eula_required_set);
+  }
+
+  // In the /install case, clean up if Google Update and/or app install did not
+  // complete successfully.
+  // Only aggregate the metrics if there is no chance that Google Update has
+  // or may be uninstalled and the process has the appropriate permissions.
+  // Uninstall will aggregate and report the metrics as appropriate.
+  bool did_install_uninstall_fail = false;
+  if (COMMANDLINE_MODE_INSTALL == args_.mode) {
+    did_install_uninstall_fail = FAILED(UninstallIfNecessary());
+  } else if (!has_uninstalled_) {
+    if (args_.mode == COMMANDLINE_MODE_UA) {
+      VERIFY1(SUCCEEDED(AggregateAndReportMetrics(is_machine_, false)));
+    } else if (!is_machine_ || vista_util::IsUserAdmin()) {
+      VERIFY1(SUCCEEDED(AggregateMetrics(is_machine_)));
+    }
+  }
+
+  // Uninitializing the network configuration must happen after reporting the
+  // metrics. The call succeeds even if the network has not been initialized
+  // due to errors up the execution path.
+  NetworkConfig::DeleteInstance();
+
+  if (COMMANDLINE_MODE_INSTALL == args_.mode &&
+      args_.is_oem_set &&
+      SUCCEEDED(hr) &&
+      !ConfigManager::Instance()->IsOemInstalling(is_machine_)) {
+    ASSERT1(false);
+    hr = GOOPDATE_E_OEM_INSTALL_SUCCEEDED_BUT_NOT_IN_OEM_INSTALLING_MODE;
+  }
+
+  // Verify that Google Update is either completely installed or uninstalled.
+  // Do not check in the following cases:
+  // * Modes that may exit during Setup, during uninstall, or while Omaha
+  //   is partially installed.
+  // * The mode is unknown, which means the args were not be parsed.
+  // * /cr instance, which may exit after Omaha is uninstalled.
+  // * /install instance that would not have called Setup.Uninstall().
+  // * /install instance when Uninstall failed for some reason since the
+  //   the consistency check may expect the wrong state.
+  if (COMMANDLINE_MODE_REGSERVER != args_.mode &&
+      COMMANDLINE_MODE_UNREGSERVER != args_.mode &&
+      COMMANDLINE_MODE_COMSERVER != args_.mode &&
+      COMMANDLINE_MODE_CODE_RED_CHECK != args_.mode &&
+      COMMANDLINE_MODE_SERVICE_REGISTER != args_.mode &&
+      COMMANDLINE_MODE_SERVICE_UNREGISTER != args_.mode &&
+      COMMANDLINE_MODE_UNKNOWN != args_.mode &&
+      !(COMMANDLINE_MODE_INSTALL == args_.mode &&
+        is_machine_ &&
+        !vista_util::IsUserAdmin()) &&
+      !did_install_uninstall_fail) {
+    Setup::CheckInstallStateConsistency(is_machine_);
+  }
+
+  return hr;
+}
+
+HRESULT GoopdateImpl::DoMain(HINSTANCE instance,
+                             const TCHAR* cmd_line,
+                             int cmd_show) {
+  module_instance_ = instance;
+  cmd_line_ = cmd_line;
+  cmd_show_ = cmd_show;
+
+  // The system terminates the process without displaying a retry dialog box
+  // for the user. GoogleUpdate has no user state to be saved, therefore
+  // prompting the user is meaningless.
+  VERIFY1(SUCCEEDED(SetProcessSilentShutdown()));
+
+  int major_version(0);
+  int minor_version(0);
+  int service_pack_major(0);
+  int service_pack_minor(0);
+  TCHAR name[MAX_PATH] = {0};
+  VERIFY1(SystemInfo::GetSystemVersion(&major_version,
+                                       &minor_version,
+                                       &service_pack_major,
+                                       &service_pack_minor,
+                                       name,
+                                       arraysize(name)));
+  metric_windows_major_version    = major_version;
+  metric_windows_minor_version    = minor_version;
+  metric_windows_sp_major_version = service_pack_major;
+  metric_windows_sp_minor_version = service_pack_minor;
+
+  InitializeVersionFromModule(module_instance_);
+  this_version_ = GetVersionString();
+
+  TCHAR path[MAX_PATH] = {0};
+  VERIFY1(::GetModuleFileName(instance, path, MAX_PATH));
+  OPT_LOG(L1, (_T("[%s][version %s][%s][%s]"),
+               path, this_version_, kBuildType, kOfficialBuild));
+
+  CORE_LOG(L2,
+      (_T("[is system %d][elevated admin %d][non-elevated admin %d]"),
+       is_local_system_,
+       vista_util::IsUserAdmin(),
+       vista_util::IsUserNonElevatedAdmin()));
+
+  HRESULT hr = omaha::ParseCommandLine(cmd_line, &args_);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[Parse cmd line failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  // IsMachineProcess requires the command line be parsed first.
+  is_machine_ = IsMachineProcess();
+  CORE_LOG(L2, (_T("[is machine %d]"), is_machine_));
+
+  // After parsing the command line, reinstall the crash handler to match the
+  // state of the process.
+  if (is_machine_ != Crash::is_machine()) {
+    VERIFY1(SUCCEEDED(Crash::InstallCrashHandler(is_machine_)));
+  }
+
+  // Set the current directory to be the one that the DLL was launched from.
+  TCHAR module_directory[MAX_PATH] = {0};
+  if (!GetModuleDirectory(instance, module_directory)) {
+     return HRESULTFromLastError();
+  }
+  if (!::SetCurrentDirectory(module_directory)) {
+    return HRESULTFromLastError();
+  }
+  OPT_LOG(L3, (_T("[Current dir][%s]"), module_directory));
+
+  // Set the usage stats as soon as possible, which is after the command line
+  // has been parsed, so that we can report crashes and other stats.
+  VERIFY1(SUCCEEDED(SetUsageStatsEnable()));
+
+  VERIFY1(SUCCEEDED(internal::PromoteAppEulaAccepted(is_machine_)));
+
+  hr = LoadResourceDllIfNecessary(args_.mode, module_directory);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[LoadResourceDllIfNecessary failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  user_default_language_id_ = ResourceManager::GetDefaultUserLanguage();
+
+#pragma warning(push)
+// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by
+// a case label.
+#pragma warning(disable : 4061)
+  // Save the mode on the stack for post-mortem debugging purposes.
+  volatile CommandLineMode mode = args_.mode;
+  switch (args_.mode) {
+    // Delegate to the service or the core. Both have reliability requirements
+    // and resource constraints. Generally speaking, they do not use COM nor
+    // networking code.
+    case COMMANDLINE_MODE_SERVICE:
+      return omaha::ServiceModule().Main(cmd_show);
+
+    case COMMANDLINE_MODE_SERVICE_REGISTER:
+      return SetupService::InstallService(app_util::GetModulePath(NULL));
+
+    case COMMANDLINE_MODE_SERVICE_UNREGISTER:
+      return SetupService::UninstallService();
+
+    default: {
+      scoped_co_init init_com_apt(COINIT_MULTITHREADED);
+      hr = init_com_apt.hresult();
+      if (FAILED(hr)) {
+        return hr;
+      }
+      hr = ::CoInitializeSecurity(
+          NULL,
+          -1,
+          NULL,   // Let COM choose what authentication services to register.
+          NULL,
+          RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  // Data integrity and encryption.
+          RPC_C_IMP_LEVEL_IDENTIFY,       // Only allow a server to identify.
+          NULL,
+          EOAC_DYNAMIC_CLOAKING,
+          NULL);
+      if (FAILED(hr)) {
+        return hr;
+      }
+
+      switch (args_.mode) {
+        case COMMANDLINE_MODE_CORE:
+          return omaha::Core().Main(is_local_system_,
+                                    !args_.is_crash_handler_disabled);
+
+        case COMMANDLINE_MODE_CRASH_HANDLER:
+          return omaha::CrashHandler().Main(is_local_system_);
+
+        case COMMANDLINE_MODE_NOARGS:
+          // TODO(omaha): Supported only for legacy Compatibility. Error out
+          // when legacy handoff support is removed as Omaha should not be
+          // called without arguments otherwise.
+          return S_OK;
+
+        case COMMANDLINE_MODE_LEGACYUI:
+          return HandleLegacyUI();
+
+        case COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF:
+          return HandleLegacyManifestHandoff();
+
+        case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
+          return DoUnregisterProduct();
+
+        default: {
+          hr = goopdate_utils::ConfigureNetwork(
+              is_machine_ && vista_util::IsUserAdmin(),
+              is_local_system_);
+          if (FAILED(hr)) {
+            VERIFY1(SUCCEEDED(HandleError(hr)));
+            return hr;
+          }
+
+          switch (args_.mode) {
+            case COMMANDLINE_MODE_WEBPLUGIN:
+              return HandleWebPlugin();
+
+            case COMMANDLINE_MODE_CODE_RED_CHECK:
+              return HandleCodeRedCheck();
+
+            case COMMANDLINE_MODE_NETDIAGS:
+              return NetDiags().Main();
+
+            case COMMANDLINE_MODE_REGISTER_PRODUCT:
+              return DoRegisterProduct();
+
+            case COMMANDLINE_MODE_UPDATE:
+              return DoSelfUpdate();
+
+            case COMMANDLINE_MODE_UG:
+              return DoCompleteSelfUpdate();
+
+            case COMMANDLINE_MODE_RECOVER:
+              return DoRecover();
+
+            case COMMANDLINE_MODE_HANDOFF_INSTALL:
+            case COMMANDLINE_MODE_IG:
+            case COMMANDLINE_MODE_INSTALL:
+            case COMMANDLINE_MODE_UA:
+              return DoWorker();
+            case COMMANDLINE_MODE_CRASH:
+              return DoCrash();
+
+            case COMMANDLINE_MODE_REPORTCRASH:
+              return HandleReportCrash();
+
+            case COMMANDLINE_MODE_REGSERVER:
+            case COMMANDLINE_MODE_UNREGSERVER:
+            case COMMANDLINE_MODE_COMSERVER:
+              return omaha::GoogleUpdate().Main();
+
+            default:
+              // We have a COMMANDLINE_MODE_ that isn't being handled.
+              ASSERT1(false);
+              OPT_LOG(LE, (_T("[Command line has unhandled mode]")));
+              return E_UNEXPECTED;
+          }
+        }
+      }
+    }
+  }
+#pragma warning(pop)
+}
+
+bool GoopdateImpl::IsMachineProcess() {
+  Tristate needs_admin(TRISTATE_NONE);
+  if (!args_.extra.apps.empty()) {
+    needs_admin = args_.extra.apps[0].needs_admin ? TRISTATE_TRUE :
+                                                    TRISTATE_FALSE;
+  }
+
+  return goopdate_utils::IsMachineProcess(
+      args_.mode,
+      goopdate_utils::IsRunningFromOfficialGoopdateDir(true),
+      is_local_system_,
+      args_.is_machine_set,
+      needs_admin);
+}
+
+
+HRESULT GoopdateImpl::HandleReportCrash() {
+  // Catch exceptions to avoid reporting crashes when handling a crash.
+  // TODO(omaha): maybe let Windows handle the crashes when reporting crashes
+  // in certain interactive modes.
+  HRESULT hr = S_OK;
+  __try {
+    // Crashes are uploaded always in the out-of-process case. This is handled
+    // in Crash::Report().
+    // Google Update crashes are uploaded only for for the users that have opted
+    // in, when network use is allowed, and from systems that are not
+    // development or test.
+    // All GoogleUpdate crashes are logged in the Windows event log for
+    // applications, unless the logging is disabled by the administrator.
+    const bool can_upload_in_process =
+        ConfigManager::Instance()->CanCollectStats(is_machine_) &&
+        ConfigManager::Instance()->CanUseNetwork(is_machine_) &&
+        !goopdate_utils::IsTestSource();
+    hr = Crash::Report(can_upload_in_process,
+                       args_.crash_filename,
+                       args_.custom_info_filename,
+                       user_default_language_id_);
+  }
+  __except(EXCEPTION_EXECUTE_HANDLER) {
+    hr = E_FAIL;
+  }
+  return hr;
+}
+
+HRESULT GoopdateImpl::HandleLegacyManifestHandoff() {
+  // TODO(omaha): Once the core supports metric aggregation, move this metric
+  // to LegacyManifestHandler::HandleEvent().
+  ++metric_handoff_legacy_user;
+
+  // The user core launches the is_legacy_user_manifest_cmd worker to
+  // process the manifest file that is dropped into the initial manifest
+  // directory by the omaha1 installers.
+  if (!goopdate_utils::IsRunningFromOfficialGoopdateDir(false)) {
+    // TODO(omaha): If the /UI process fails the legacy installer will
+    // not display anything to the user. We might have to launch UI here.
+    ASSERT1(false);
+    return E_FAIL;
+  }
+
+  return goopdate_utils::HandleLegacyManifestHandoff(
+      args_.legacy_manifest_path,
+      false);
+}
+
+HRESULT GoopdateImpl::HandleLegacyUI() {
+  ++metric_handoff_legacy_machine;
+
+  // A omaha1 installer does a handoff install using
+  // the /UI switch. The format of the command line is as follows:
+  // /UI /lang <lang> manfest_filename or /UI legacy_manifest_path
+  // The legacy installer should have elevated and we should
+  // be running from the program files directory since this command can
+  // only be passed to a registered, machine omaha.
+  if (!vista_util::IsUserAdmin() ||
+      !goopdate_utils::IsRunningFromOfficialGoopdateDir(true)) {
+    // TODO(omaha): If the /UI process fails the legacy installer will
+    // not display anything to the user. We might have to launch UI here.
+    ASSERT1(false);
+    return E_FAIL;
+  }
+
+  // We ignore the /lang switch that is passed on the cmd line,
+  // since we get the language from the manifest file and pass that to the
+  // worker.
+  return goopdate_utils::HandleLegacyManifestHandoff(
+      args_.legacy_manifest_path, true);
+}
+
+// The resource dll is loaded only in the following cases:
+// 1. Initial setup: /install
+// 2. Google Update and app install: /ig
+// 3. Handoff install: /handoff
+// 4. App update worker: /ua
+// 5. Self-Update: /ug
+HRESULT GoopdateImpl::LoadResourceDllIfNecessary(CommandLineMode mode,
+                                                 const CString& resource_dir) {
+  switch (mode) {
+    case COMMANDLINE_MODE_INSTALL:          // has UI on errors
+    case COMMANDLINE_MODE_IG:               // has UI
+    case COMMANDLINE_MODE_HANDOFF_INSTALL:  // has UI
+    case COMMANDLINE_MODE_UG:               // TODO(omaha): Why is it loaded?
+    case COMMANDLINE_MODE_UA:               // Worker, etc. load strings.
+    case COMMANDLINE_MODE_COMSERVER:        // Returns strings to caller.
+    case COMMANDLINE_MODE_SERVICE_REGISTER:
+    case COMMANDLINE_MODE_SERVICE_UNREGISTER:
+      // Load the resource DLL for these modes.
+      break;
+    case COMMANDLINE_MODE_UNKNOWN:
+    case COMMANDLINE_MODE_NOARGS:
+    case COMMANDLINE_MODE_CORE:
+    case COMMANDLINE_MODE_CRASH_HANDLER:
+    case COMMANDLINE_MODE_SERVICE:
+    case COMMANDLINE_MODE_REGSERVER:
+    case COMMANDLINE_MODE_UNREGSERVER:
+    case COMMANDLINE_MODE_NETDIAGS:
+    case COMMANDLINE_MODE_CRASH:
+    case COMMANDLINE_MODE_REPORTCRASH:
+    case COMMANDLINE_MODE_UPDATE:
+    case COMMANDLINE_MODE_RECOVER:
+    case COMMANDLINE_MODE_WEBPLUGIN:
+    case COMMANDLINE_MODE_CODE_RED_CHECK:
+    case COMMANDLINE_MODE_LEGACYUI:
+    case COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF:
+    case COMMANDLINE_MODE_REGISTER_PRODUCT:
+    case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
+    default:
+      // Thse modes do not need the resource DLL.
+      return S_OK;
+  }
+
+  resource_manager_.reset(new ResourceManager(is_machine_, resource_dir));
+
+  HRESULT hr = resource_manager_->LoadResourceDll(args_.extra.language);
+  if (FAILED(hr)) {
+    ++metric_load_resource_dll_failed;
+    ASSERT(false, (_T("LoadResourceDll failed with 0x%08x"), hr));
+  }
+  return hr;
+}
+
+// Writes the information for the primary app to enable Omaha to send usage
+// stats now. It will be set for each app in the args when they are installed.
+HRESULT GoopdateImpl::SetUsageStatsEnable() {
+  if (COMMANDLINE_MODE_UPDATE == args_.mode) {
+    VERIFY1(SUCCEEDED(
+        goopdate_utils::ConvertLegacyUsageStats(is_machine_)));
+  }
+
+  if (args_.extra.apps.empty()) {
+    return S_OK;
+  }
+
+  HRESULT hr = goopdate_utils::SetUsageStatsEnable(
+      args_.extra.apps[0].needs_admin,
+      GuidToString(args_.extra.apps[0].app_guid),
+      args_.extra.usage_stats_enable);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[SetUsageStatsEnable failed][0x%08x]"), hr));
+
+    if ((HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr) &&
+        args_.extra.apps[0].needs_admin &&
+        !vista_util::IsUserAdmin()) {
+      CORE_LOG(L3, (_T("[Process does not have permission to HKLM]")));
+      return S_OK;
+    }
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT GoopdateImpl::HandleCodeRedCheck() {
+  CORE_LOG(L2, (_T("[GoopdateImpl::HandleCodeRedCheck]")));
+  ++metric_cr_process_total;
+
+  // Call the utils method instead of member method because we want to execute
+  // as little code as possible.
+  bool is_machine = goopdate_utils::IsMachineProcess(args_.mode,
+                                                     false,   // machine dir
+                                                     is_local_system_,
+                                                     args_.is_machine_set,
+                                                     TRISTATE_NONE);
+  ASSERT1(IsMachineProcess() == is_machine);
+
+  if (!ConfigManager::Instance()->CanUseNetwork(is_machine)) {
+    CORE_LOG(L1,
+             (_T("[Code Red check not sent because network use prohibited]")));
+    return GOOPDATE_E_CANNOT_USE_NETWORK;
+  }
+
+  HRESULT hr = FixGoogleUpdate(kGoogleUpdateAppId,
+                               this_version_,
+                               _T(""),     // Goopdate doesn't have a language.
+                               is_machine,
+                               &GoopdateImpl::CodeRedDownloadCallback,
+                               NULL);
+  CORE_LOG(L2, (_T("[FixGoogleUpdate returned 0x%08x]"), hr));
+  return S_OK;
+}
+
+// Returns S_OK when the download of the Code Red file succeeds and E_FAIL
+// otherwise.
+HRESULT GoopdateImpl::CodeRedDownloadCallback(const TCHAR* url,
+                                              const TCHAR* file_path,
+                                              void*) {
+  ++metric_cr_callback_total;
+
+  NetworkConfig& network_config = NetworkConfig::Instance();
+  NetworkRequest network_request(network_config.session());
+
+  network_request.AddHttpRequest(new SimpleRequest);
+
+  // BITS takes the job to BG_JOB_STATE_TRANSIENT_ERROR when the server returns
+  // 204. After the "no progress time out", the BITS job errors out. Since
+  // BITS follows the WinHTTP in the fallback chain, the code is expected to
+  // execute only if WinHTTP fails to get a response from the server.
+
+  // Assumes the caller is not logged on if the function failed.
+  // BITS transfers files only when the job owner is logged on.
+  bool is_logged_on(false);
+  HRESULT hr = IsUserLoggedOn(&is_logged_on);
+  ASSERT1(SUCCEEDED(hr) || !is_logged_on);
+  if (is_logged_on) {
+    BitsRequest* bits_request(new BitsRequest);
+    bits_request->set_minimum_retry_delay(60);
+    bits_request->set_no_progress_timeout(15);
+    network_request.AddHttpRequest(bits_request);
+  }
+
+  network_request.AddHttpRequest(new BrowserRequest);
+  hr = network_request.DownloadFile(CString(url), CString(file_path));
+  if (FAILED(hr)) {
+    return E_FAIL;
+  }
+
+  switch (network_request.http_status_code()) {
+    case HTTP_STATUS_OK:
+      ++metric_cr_callback_status_200;
+      return S_OK;
+    case HTTP_STATUS_NO_CONTENT:
+      ++metric_cr_callback_status_204;
+      return E_FAIL;
+    default:
+      ++metric_cr_callback_status_other;
+      return E_FAIL;
+  }
+}
+
+// Until bug 1135173 is fixed:
+// Running a OneClick cross-install at the same time as Setup has undefined
+// behavior. If Setup wins the race to the lock, it may delete the files that
+// the cross-install wants to copy. Also, since the plugin and /plugin instance
+// do not check the Setup Lock, they may try to invoke a version that is being
+// installed, removed, or rolled back.
+
+// If we're called with the /webplugin command, we need to handle it and exit.
+// This is called from the browser and the command line arguments come from the
+// website so we need to be restrictive of what we let past. If everything from
+// the plugin is valid, we'll relaunch goopdate with the proper commands.
+HRESULT GoopdateImpl::HandleWebPlugin() {
+  return webplugin_utils::DoOneClickInstall(args_);
+}
+
+HRESULT GoopdateImpl::DoCompleteSelfUpdate() {
+  OPT_LOG(L1, (_T("[GoopdateImpl::DoCompleteSelfUpdate]")));
+  // TODO(omaha): The use of is_machine_set is very non-intuituve.
+  // It is used only for machine repair situations when elevation is required
+  // in vista or in case of XP. For all other cases this is not used and plain
+  // /update is used to invoke recovery.
+  // Another consequence of this is that in some cases we run
+  // the full Omaha update logic i.e. ShouldInstall etc for recovery.
+  // Consider making recovery not go through all this code.
+  OPT_LOG(L1, (_T("[self update][is_machine=%d]"), is_machine_));
+
+  Ping ping;
+  return FinishGoogleUpdateInstall(args_,
+                                   is_machine_,
+                                   true,
+                                   &ping,
+                                   NULL);
+}
+
+// Calls DoRegisterProductHelper and sends a ping with the result.
+// TODO(omaha): Use a more common code flow with normal installs or remove
+// registerproduct altogether when redesigning Omaha.
+HRESULT GoopdateImpl::DoRegisterProduct() {
+  OPT_LOG(L1, (_T("[GoopdateImpl::DoRegisterProduct]")));
+
+  ASSERT1(!goopdate_utils::IsRunningFromOfficialGoopdateDir(false) &&
+          !goopdate_utils::IsRunningFromOfficialGoopdateDir(true));
+
+  ASSERT1(!args_.extra.apps.empty());
+  // TODO(omaha): Support bundles. Only supports one app currently.
+  ASSERT1(1 == args_.extra.apps.size());
+  bool extra_needs_admin = args_.extra.apps[0].needs_admin;
+
+  AppManager app_manager(extra_needs_admin);
+  ProductDataVector products;
+  app_manager.ConvertCommandLineToProductData(args_, &products);
+  AppData app_data = products[0].app_data();
+
+  HRESULT hr = DoRegisterProductHelper(extra_needs_admin,
+                                       &app_manager,
+                                       &app_data);
+
+  const PingEvent::Results event_result = SUCCEEDED(hr) ?
+                                          PingEvent::EVENT_RESULT_SUCCESS :
+                                          PingEvent::EVENT_RESULT_ERROR;
+
+  AppRequestData app_request_data(app_data);
+  PingEvent ping_event(PingEvent::EVENT_REGISTER_PRODUCT_COMPLETE,
+                       event_result,
+                       hr,  // error code
+                       0,  // extra code 1
+                       app_data.previous_version());
+  app_request_data.AddPingEvent(ping_event);
+  AppRequest app_request(app_request_data);
+  Request request(extra_needs_admin);
+  request.AddAppRequest(app_request);
+
+  Ping ping;
+  ping.SendPing(&request);
+
+  return hr;
+}
+
+HRESULT GoopdateImpl::DoRegisterProductHelper(bool is_machine,
+                                              AppManager* app_manager,
+                                              AppData* app_data) {
+  ASSERT1(app_data);
+  ASSERT1(app_manager);
+  // Ensure we're running as elevated admin if needs_admin is true.
+  if (is_machine && !vista_util::IsUserAdmin()) {
+    CORE_LOG(LE, (_T("[DoRegisterProduct][needs admin & user not admin]")));
+    return GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP;
+  }
+
+  // Get product GUID from args and register it in CLIENTS.
+  HRESULT hr = app_manager->RegisterProduct(args_.extra.apps[0].app_guid,
+                                            args_.extra.apps[0].app_name);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[AppManager::RegisterProduct failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  Setup setup(is_machine, &args_);
+  hr = setup.InstallSelfSilently();
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[Setup::InstallSelfSilently failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Populate the app's ClientState key.
+  VERIFY1(SUCCEEDED(app_manager->WritePreInstallData(*app_data)));
+  VERIFY1(SUCCEEDED(app_manager->InitializeApplicationState(app_data)));
+
+  return S_OK;
+}
+
+HRESULT GoopdateImpl::DoUnregisterProduct() {
+  bool extra_needs_admin = args_.extra.apps[0].needs_admin;
+
+  // Ensure we're running as elevated admin if needs_admin is true.
+  if (extra_needs_admin && !vista_util::IsUserAdmin()) {
+    CORE_LOG(LE, (_T("[DoUnregisterProduct][needs admin & user not admin]")));
+    return GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP;
+  }
+
+  AppManager app_manager(extra_needs_admin);
+  HRESULT hr = app_manager.UnregisterProduct(args_.extra.apps[0].app_guid);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[AppManager::UnregisterProduct failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT GoopdateImpl::DoSelfUpdate() {
+  OPT_LOG(L1, (_T("[GoopdateImpl::DoSelfUpdate]")));
+
+  Setup setup(is_machine_, &args_);
+  HRESULT hr = setup.UpdateSelfSilently();
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[Setup::UpdateSelfSilently failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// Attempts to launch the repair file elevated using the MSP. If elevation is
+// not needed or fails, attempts to install without elevating.
+// The code_red_metainstaller_path arg is the repair file.
+HRESULT GoopdateImpl::DoRecover() {
+  OPT_LOG(L1, (_T("[GoopdateImpl::DoRecover()]")));
+
+  CommandLineBuilder builder(COMMANDLINE_MODE_UPDATE);
+
+  HRESULT hr = S_OK;
+  if (LaunchRepairFileElevated(is_machine_,
+                               args_.code_red_metainstaller_path,
+                               builder.GetCommandLineArgs(),
+                               &hr)) {
+    ASSERT1(SUCCEEDED(hr));
+    return S_OK;
+  }
+
+  if (FAILED(hr)) {
+    OPT_LOG(LW, (_T("[LaunchRepairFileElevated failed][0x%08x]"), hr));
+  }
+
+  Setup setup(is_machine_, &args_);
+  hr = setup.RepairSilently();
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Non-elevated repair failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// Clears the EULA flag in the handoff instance in case an older installer that
+// does not know about the EULA flag is used to launch the install.
+// Failing to clear flag fails installation because this would prevent updates.
+HRESULT GoopdateImpl::DoWorker() {
+  if (COMMANDLINE_MODE_HANDOFF_INSTALL == args_.mode &&
+      !args_.is_eula_required_set) {
+    HRESULT hr = Setup::SetEulaAccepted(is_machine_);
+    if (FAILED(hr)) {
+      CORE_LOG(LE, (_T("[Setup::SetEulaAccepted failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  omaha::Worker worker(is_machine_);
+  HRESULT hr = worker.Main(goopdate_);
+  has_uninstalled_ = worker.has_uninstalled();
+
+  // The UA worker always returns S_OK. UA can be launched by the scheduled task
+  // or the core, neither of which wait for a return code. On Vista, returning
+  // an error code from the scheduled task reportedly causes issues with the
+  // task scheduler in rare cases, so returning S_OK helps with that as well.
+  if (args_.mode == COMMANDLINE_MODE_UA) {
+    return S_OK;
+  }
+
+  return hr;
+}
+
+HRESULT GoopdateImpl::DoCrash() {
+#if DEBUG
+  return static_cast<HRESULT>(Crash::CrashNow());
+#else
+  return S_OK;
+#endif
+}
+
+// In dbg builds, also checks the post conditions of a /install process to
+// ensure that the registry is correctly populated or has been cleaned up.
+HRESULT GoopdateImpl::UninstallIfNecessary() {
+  ASSERT1(COMMANDLINE_MODE_INSTALL == args_.mode);
+  ASSERT(!has_uninstalled_, (_T("Worker doesn't uninstall in /install mode")));
+
+  if (is_machine_ && !vista_util::IsUserAdmin()) {
+    // The non-elevated instance, so do not try to uninstall.
+    ASSERT1(!args_.is_install_elevated);
+    return S_OK;
+  } else {
+    CORE_LOG(L2, (_T("[GoopdateImpl::Main /install][Uninstall if necessary]")));
+    // COM must be initialized in order to uninstall the scheduled task(s).
+    scoped_co_init init_com_apt(COINIT_MULTITHREADED);
+    Setup setup(is_machine_, &args_);
+    return setup.Uninstall();
+  }
+}
+
+void GoopdateImpl::OutOfMemoryHandler() {
+  ::RaiseException(EXCEPTION_ACCESS_VIOLATION,
+                   EXCEPTION_NONCONTINUABLE,
+                   0,
+                   NULL);
+}
+
+}  // namespace detail
+
+namespace internal {
+
+// Returns early if Google Update's EULA is already accepted, as indicated by
+// the lack of eulaaccepted in the Update key.
+// The apps' values are not modified or deleted.
+HRESULT PromoteAppEulaAccepted(bool is_machine) {
+  const TCHAR* update_key_name =
+      ConfigManager::Instance()->registry_update(is_machine);
+  if (!RegKey::HasValue(update_key_name, kRegValueOmahaEulaAccepted)) {
+    return S_OK;
+  }
+
+  const TCHAR* state_key_name =
+      ConfigManager::Instance()->registry_client_state(is_machine);
+
+  RegKey state_key;
+  HRESULT hr = state_key.Open(state_key_name, KEY_READ);
+  if (FAILED(hr)) {
+    if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) {
+      return S_FALSE;
+    }
+    return hr;
+  }
+
+  // TODO(omaha): This should actually be iterating over registered products
+  // rather than present ClientState keys. These are identical in most cases.
+  int num_sub_keys = state_key.GetSubkeyCount();
+  for (int i = 0; i < num_sub_keys; ++i) {
+    CString sub_key_name;
+    if (FAILED(state_key.GetSubkeyNameAt(i, &sub_key_name))) {
+      continue;
+    }
+
+    if (goopdate_utils::IsAppEulaAccepted(is_machine, sub_key_name, true)) {
+      ASSERT1(kGoogleUpdateAppId != sub_key_name);
+      return Setup::SetEulaAccepted(is_machine);
+    }
+  }
+
+  return S_OK;
+}
+
+}  // namespace internal
+
+Goopdate::Goopdate(bool is_local_system) {
+  CORE_LOG(L2, (_T("[Goopdate::Goopdate]")));
+  impl_.reset(new detail::GoopdateImpl(this, is_local_system));
+}
+
+Goopdate::~Goopdate() {
+  CORE_LOG(L2, (_T("[Goopdate::~Goopdate]")));
+}
+
+HRESULT Goopdate::Main(HINSTANCE instance,
+                       const TCHAR* cmd_line,
+                       int cmd_show) {
+  return impl_->Main(instance, cmd_line, cmd_show);
+}
+
+bool Goopdate::is_local_system() const {
+  return impl_->is_local_system();
+}
+
+CommandLineArgs Goopdate::args() const {
+  return impl_->args();
+}
+
+CString Goopdate::cmd_line() const {
+  return impl_->cmd_line();
+}
+
+OBJECT_ENTRY_AUTO(__uuidof(ProcessLauncherClass), ProcessLauncher)
+OBJECT_ENTRY_AUTO(__uuidof(OnDemandUserAppsClass), OnDemandCOMClass)
+OBJECT_ENTRY_AUTO(__uuidof(OnDemandMachineAppsClass), OnDemandCOMClassMachine)
+
+}  // namespace omaha
diff --git a/goopdate/goopdate.def b/goopdate/goopdate.def
index b482c64..174440b 100644
--- a/goopdate/goopdate.def
+++ b/goopdate/goopdate.def
@@ -1,21 +1,21 @@
-; Copyright 2003-2009 Google Inc.

-;

-; Licensed under the Apache License, Version 2.0 (the "License");

-; you may not use this file except in compliance with the License.

-; You may obtain a copy of the License at

-;

-;      http:;www.apache.org/licenses/LICENSE-2.0

-;

-; Unless required by applicable law or agreed to in writing, software

-; distributed under the License is distributed on an "AS IS" BASIS,

-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-; See the License for the specific language governing permissions and

-; limitations under the License.

-; ========================================================================

-

-

-EXPORTS

-  DllEntry            PRIVATE

-  DllCanUnloadNow     PRIVATE

-  DllGetClassObject   PRIVATE

-

+; Copyright 2003-2009 Google Inc.
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http:;www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+; ========================================================================
+
+
+EXPORTS
+  DllEntry            PRIVATE
+  DllCanUnloadNow     PRIVATE
+  DllGetClassObject   PRIVATE
+
diff --git a/goopdate/goopdate.h b/goopdate/goopdate.h
index a7ab014..84863fa 100644
--- a/goopdate/goopdate.h
+++ b/goopdate/goopdate.h
@@ -1,59 +1,59 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_GOOPDATE_GOOPDATE_H__

-#define OMAHA_GOOPDATE_GOOPDATE_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-

-namespace omaha {

-

-namespace detail {

-

-class GoopdateImpl;

-

-}  // namespace detail

-

-struct CommandLineArgs;

-class ConfigManager;

-class ResourceManager;

-

-class Goopdate {

- public:

-  explicit Goopdate(bool is_local_system);

-  ~Goopdate();

-

-  // Runs the entry point for the application.

-  HRESULT Main(HINSTANCE instance, const TCHAR* cmd_line, int cmd_show);

-

-  bool is_local_system() const;

-  CommandLineArgs args() const;

-  CString cmd_line() const;

-

- private:

-  // Uses pimpl idiom to minimize dependencies on implementation details.

-  scoped_ptr<detail::GoopdateImpl> impl_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Goopdate);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_GOOPDATE_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_GOOPDATE_GOOPDATE_H__
+#define OMAHA_GOOPDATE_GOOPDATE_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+
+namespace omaha {
+
+namespace detail {
+
+class GoopdateImpl;
+
+}  // namespace detail
+
+struct CommandLineArgs;
+class ConfigManager;
+class ResourceManager;
+
+class Goopdate {
+ public:
+  explicit Goopdate(bool is_local_system);
+  ~Goopdate();
+
+  // Runs the entry point for the application.
+  HRESULT Main(HINSTANCE instance, const TCHAR* cmd_line, int cmd_show);
+
+  bool is_local_system() const;
+  CommandLineArgs args() const;
+  CString cmd_line() const;
+
+ private:
+  // Uses pimpl idiom to minimize dependencies on implementation details.
+  scoped_ptr<detail::GoopdateImpl> impl_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Goopdate);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_GOOPDATE_H__
+
diff --git a/goopdate/goopdate.rc b/goopdate/goopdate.rc
index faff6ae..1b4e1c6 100644
--- a/goopdate/goopdate.rc
+++ b/goopdate/goopdate.rc
@@ -1,27 +1,27 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <afxres.h>

-#include "omaha/goopdate/resource.h"

-

-LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT

-IDR_GOOGLE_UPDATE_WORKER_CLASS          REGISTRY "omaha/common/generic_reg_file_local_server.rgs"

-IDR_GOOGLE_UPDATE_WORKER_CLASS_MACHINE  REGISTRY "omaha/common/generic_reg_file_elevation_localserver.rgs"

-

-IDR_GOOGLE_UPDATE_SERVICE_APPID         REGISTRY "omaha/common/generic_reg_file_appid.rgs"

-IDR_GOOGLE_UPDATE_CORE_CLASS            REGISTRY "omaha/common/generic_reg_file_localservice.rgs"

-

-IDI_ELEVATION_MONIKER_ICON              ICON "omaha/goopdate/goopdate.ico"

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <afxres.h>
+#include "omaha/goopdate/resource.h"
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT
+IDR_GOOGLE_UPDATE_WORKER_CLASS          REGISTRY "omaha/common/generic_reg_file_local_server.rgs"
+IDR_GOOGLE_UPDATE_WORKER_CLASS_MACHINE  REGISTRY "omaha/common/generic_reg_file_elevation_localserver.rgs"
+
+IDR_GOOGLE_UPDATE_SERVICE_APPID         REGISTRY "omaha/common/generic_reg_file_appid.rgs"
+IDR_GOOGLE_UPDATE_CORE_CLASS            REGISTRY "omaha/common/generic_reg_file_localservice.rgs"
+
+IDI_ELEVATION_MONIKER_ICON              ICON "omaha/goopdate/goopdate.ico"
+
diff --git a/goopdate/goopdate_command_line_validator.cc b/goopdate/goopdate_command_line_validator.cc
index 388054b..25393f0 100644
--- a/goopdate/goopdate_command_line_validator.cc
+++ b/goopdate/goopdate_command_line_validator.cc
@@ -1,536 +1,536 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/goopdate_command_line_validator.h"

-

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/command_line_parser.h"

-#include "omaha/goopdate/command_line_validator.h"

-#include "omaha/goopdate/extra_args_parser.h"

-

-namespace omaha {

-

-GoopdateCommandLineValidator::GoopdateCommandLineValidator() {

-}

-

-GoopdateCommandLineValidator::~GoopdateCommandLineValidator() {

-}

-

-HRESULT GoopdateCommandLineValidator::Setup() {

-  validator_.reset(new CommandLineValidator);

-

-  CString cmd_line;

-

-  // gu.exe

-  cmd_line.Empty();

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnNoArgs);

-

-  // gu.exe /c [/nocrashserver

-  cmd_line.Format(_T("/%s [/%s"), kCmdLineCore, kCmdLineNoCrashHandler);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnCore);

-

-  // gu.exe /crashhandler

-  cmd_line.Format(_T("/%s"), kCmdLineCrashHandler);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnCrashHandler);

-

-  // gu.exe /svc

-  cmd_line.Format(_T("/%s"), kCmdLineService);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnService);

-

-  // gu.exe /regsvc

-  cmd_line.Format(_T("/%s"), kCmdLineRegisterService);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnServiceRegister);

-

-  // gu.exe /unregsvc

-  cmd_line.Format(_T("/%s"), kCmdLineUnregisterService);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnServiceUnregister);

-

-  // gu.exe /regserver

-  cmd_line.Format(_T("/%s"), kCmdRegServer);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnRegServer);

-

-  // gu.exe /unregserver

-  cmd_line.Format(_T("/%s"), kCmdUnregServer);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUnregServer);

-

-  // gu.exe /netdiags

-  cmd_line.Format(_T("/%s"), kCmdLineNetDiags);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnNetDiags);

-

-  // gu.exe /crash

-  cmd_line.Format(_T("/%s"), kCmdLineCrash);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnCrash);

-

-  // gu.exe -Embedding. The -Embedding text is injected via COM.

-  CreateScenario(kCmdLineComServerDash,

-                 &GoopdateCommandLineValidator::OnComServer);

-

-  // gu.exe /install <extraargs> [/appargs <appargs> [/installsource source

-  //        [/silent [/eularequired [/oem [/installelevated

-  cmd_line.Format(_T("/%s extra [/%s appargs [/%s src [/%s [/%s [/%s [/%s"),

-                  kCmdLineInstall,

-                  kCmdLineAppArgs,

-                  kCmdLineInstallSource,

-                  kCmdLineSilent,

-                  kCmdLineEulaRequired,

-                  kCmdLineOem,

-                  kCmdLineInstallElevated);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnInstall);

-

-  // gu.exe /update

-  cmd_line.Format(_T("/%s"), kCmdLineUpdate);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUpdate);

-

-  // gu.exe /ig <extraargs> [/appargs <appargs> [/installsource source

-  //        [/silent [/eularequired [/offlineinstall

-  cmd_line.Format(_T("/%s extraargs [/%s appargs [/%s source [/%s [/%s [/%s"),

-                  kCmdLineFinishGoogleUpdateInstall,

-                  kCmdLineAppArgs,

-                  kCmdLineInstallSource,

-                  kCmdLineSilent,

-                  kCmdLineEulaRequired,

-                  kCmdLineOfflineInstall);

-  CreateScenario(cmd_line,

-                 &GoopdateCommandLineValidator::OnFinishInstallGoopdate);

-

-  // gu.exe /handoff <extraargs> [/appargs <appargs> [/installsource source

-  //        [/silent [/eularequired [/offlineinstall

-  cmd_line.Format(_T("/%s extra [/%s appargs [/%s source [/%s [/%s [/%s"),

-                  kCmdLineAppHandoffInstall,

-                  kCmdLineAppArgs,

-                  kCmdLineInstallSource,

-                  kCmdLineSilent,

-                  kCmdLineEulaRequired,

-                  kCmdLineOfflineInstall);

-  CreateScenario(cmd_line,

-                 &GoopdateCommandLineValidator::OnInstallHandoffWorker);

-

-  // gu.exe /ua [/installsource source [/uninstall

-  cmd_line.Format(_T("/%s [/%s source [/%s"),

-                  kCmdLineUpdateApps, kCmdLineInstallSource, kCmdLineUninstall);

-  CreateScenario(cmd_line,

-                 &GoopdateCommandLineValidator::OnUpdateApps);

-

-  // gu.exe /ug [/machine

-  cmd_line.Format(_T("/%s [/%s"),

-                  kCmdLineFinishGoogleUpdateUpdate, kCmdLineMachine);

-  CreateScenario(cmd_line,

-                 &GoopdateCommandLineValidator::OnFinishUpdateGoopdate);

-

-  // gu.exe /report <crash_filename> [/machine

-  //        [/custom_info <custom_info_filename>

-  cmd_line.Format(_T("/%s filename [/%s [/%s customfilename"),

-                  kCmdLineReport,

-                  kCmdLineMachine,

-                  kCmdLineCustomInfoFileName);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnReportCrash);

-

-  // gu.exe /report /i <crash_filename> [/machine

-  cmd_line.Format(_T("/%s /%s filename [/%s"),

-                  kCmdLineReport,

-                  kCmdLineInteractive,

-                  kCmdLineMachine);

-  CreateScenario(cmd_line,

-                 &GoopdateCommandLineValidator::OnReportCrashInteractive);

-

-  // gu.exe /pi <domainurl> <args> /installsource oneclick

-  cmd_line.Format(_T("/%s domainurl args /%s oneclick"),

-                  kCmdLineWebPlugin,

-                  kCmdLineInstallSource);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnWebPlugin);

-

-  // gu.exe /cr

-  cmd_line.Format(_T("/%s"), kCmdLineCodeRedCheck);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnCodeRed);

-

-  // gu.exe /recover <repair_file>

-  cmd_line.Format(_T("/%s repairfile"), kCmdLineRecover);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnRecover);

-

-  // gu.exe /recover /machine <repair_file>

-  cmd_line.Format(_T("/%s /%s repairfile"), kCmdLineRecover, kCmdLineMachine);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnRecoverMachine);

-

-  // gu.exe /registerproduct "extraargs" [/installsource source

-  cmd_line.Format(_T("/%s extraargs [/%s source"),

-                  kCmdLineRegisterProduct,

-                  kCmdLineInstallSource);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnRegisterProduct);

-

-  // gu.exe /unregisterproduct "extraargs"

-  cmd_line.Format(_T("/%s extraargs"), kCmdLineUnregisterProduct);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUnregisterProduct);

-

-  //

-  // Legacy support command lines.

-  //

-

-  // gu.exe /uiuser <manifestfilename>

-  cmd_line.Format(_T("/%s filename"),

-                  kCmdLineLegacyUserManifest);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUiUserManifest);

-

-  // TODO(omaha):  Can we remove this case or is it here for back compat?

-  // gu.exe /ui /lang en <manifestfilename>

-  cmd_line.Format(_T("/%s /%s en filename"),

-                  kCmdLineLegacyUi,

-                  kCmdLineLegacyLang);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUiLangManifest);

-

-  // gu.exe /ui <manifestfilename>

-  cmd_line.Format(_T("/%s filename"), kCmdLineLegacyUi);

-  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUiManifest);

-

-  // gu.exe /handoff <extraargs> /lang <en> [/installsource source

-  cmd_line.Format(_T("/%s extraargs /%s en [/%s source"),

-                  kCmdLineAppHandoffInstall,

-                  kCmdLineLegacyLang,

-                  kCmdLineInstallSource);

-  CreateScenario(cmd_line,

-                 &GoopdateCommandLineValidator::OnInstallHandoffWorkerLegacy);

-

-  // gu.exe /install <extraargs> /installsource source /lang en.

-  cmd_line.Format(_T("/%s extraargs /%s source /%s en"),

-                  kCmdLineInstall, kCmdLineInstallSource, kCmdLineLegacyLang);

-  CreateScenario(cmd_line,

-                 &GoopdateCommandLineValidator::OnInstallWithSourceLegacy);

-  return S_OK;

-}

-

-// TODO(Omaha): Add check that each scenario is unique and does not overlap an

-// existing one in DBG builds.

-HRESULT GoopdateCommandLineValidator::Validate(const CommandLineParser* parser,

-                                               CommandLineArgs* args) {

-  ASSERT1(parser);

-  ASSERT1(args);

-

-  parser_ = parser;

-  args_ = args;

-

-  CString scenario_name;

-  HRESULT hr = validator_->Validate(*parser_, &scenario_name);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[GoopdateCommandLineValidator::Validate Failed][0x%x]"),

-                  hr));

-    return hr;

-  }

-

-  MapScenarioHandlersIter iter = scenario_handlers_.find(scenario_name);

-  if (iter == scenario_handlers_.end()) {

-    ASSERT1(false);

-    return GOOGLEUPDATE_COMMANDLINE_E_NO_SCENARIO_HANDLER;

-  }

-

-  ScenarioHandler handler = (*iter).second;

-  return (this->*handler)();

-}

-

-void GoopdateCommandLineValidator::CreateScenario(const TCHAR* cmd_line,

-                                                  ScenarioHandler handler) {

-  // Prepend the program name onto the cmd_line.

-  CString scenario_cmd_line;

-  scenario_cmd_line.Format(_T("prog.exe %s"), cmd_line);

-

-  CString scenario_name;

-  validator_->CreateScenarioFromCmdLine(scenario_cmd_line, &scenario_name);

-  // TODO(omaha): Make sure it doesn't already exist.

-  scenario_handlers_[scenario_name] = handler;

-}

-

-HRESULT GoopdateCommandLineValidator::GetExtraAndAppArgs(const CString& name) {

-  HRESULT hr = parser_->GetSwitchArgumentValue(name,

-                                               0,

-                                               &args_->extra_args_str);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = parser_->GetSwitchArgumentValue(kCmdLineAppArgs,

-                                       0,

-                                       &args_->app_args_str);

-  if (FAILED(hr)) {

-    args_->app_args_str.Empty();

-  }

-

-  ExtraArgsParser extra_args_parser;

-  return extra_args_parser.Parse(args_->extra_args_str,

-                                 args_->app_args_str,

-                                 &(args_->extra));

-}

-

-HRESULT GoopdateCommandLineValidator::OnNoArgs() {

-  args_->mode = COMMANDLINE_MODE_NOARGS;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnCore() {

-  args_->mode = COMMANDLINE_MODE_CORE;

-  args_->is_crash_handler_disabled = parser_->HasSwitch(kCmdLineNoCrashHandler);

-

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnCrashHandler() {

-  args_->mode = COMMANDLINE_MODE_CRASH_HANDLER;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnService() {

-  args_->mode = COMMANDLINE_MODE_SERVICE;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnServiceRegister() {

-  args_->mode = COMMANDLINE_MODE_SERVICE_REGISTER;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnServiceUnregister() {

-  args_->mode = COMMANDLINE_MODE_SERVICE_UNREGISTER;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnRegServer() {

-  args_->mode = COMMANDLINE_MODE_REGSERVER;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnUnregServer() {

-  args_->mode = COMMANDLINE_MODE_UNREGSERVER;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnNetDiags() {

-  args_->mode = COMMANDLINE_MODE_NETDIAGS;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnCrash() {

-  args_->mode = COMMANDLINE_MODE_CRASH;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnComServer() {

-  args_->mode = COMMANDLINE_MODE_COMSERVER;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnInstall() {

-  args_->mode = COMMANDLINE_MODE_INSTALL;

-  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,

-                                  0,

-                                  &(args_->install_source));

-  args_->is_silent_set = parser_->HasSwitch(kCmdLineSilent);

-  args_->is_eula_required_set = parser_->HasSwitch(kCmdLineEulaRequired);

-  args_->is_oem_set = parser_->HasSwitch(kCmdLineOem);

-  args_->is_install_elevated = parser_->HasSwitch(kCmdLineInstallElevated);

-  return GetExtraAndAppArgs(kCmdLineInstall);

-}

-

-HRESULT GoopdateCommandLineValidator::OnInstallWithSourceLegacy() {

-  args_->mode = COMMANDLINE_MODE_INSTALL;

-  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,

-                                  0,

-                                  &(args_->install_source));

-  parser_->GetSwitchArgumentValue(kCmdLineLegacyLang,

-                                  0,

-                                  &(args_->extra.language));

-  return GetExtraAndAppArgs(kCmdLineInstall);

-}

-

-HRESULT GoopdateCommandLineValidator::OnUpdate() {

-  args_->mode = COMMANDLINE_MODE_UPDATE;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnInstallHandoffWorker() {

-  args_->mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,

-                                  0,

-                                  &(args_->install_source));

-  args_->is_silent_set = parser_->HasSwitch(kCmdLineSilent);

-  args_->is_eula_required_set = parser_->HasSwitch(kCmdLineEulaRequired);

-  args_->is_offline_set = parser_->HasSwitch(kCmdLineOfflineInstall);

-  return GetExtraAndAppArgs(kCmdLineAppHandoffInstall);

-}

-

-HRESULT GoopdateCommandLineValidator::OnInstallHandoffWorkerLegacy() {

-  args_->mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  HRESULT hr = GetExtraAndAppArgs(kCmdLineAppHandoffInstall);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,

-                                  0,

-                                  &(args_->install_source));

-  return parser_->GetSwitchArgumentValue(kCmdLineLegacyLang,

-                                         0,

-                                         &(args_->extra.language));

-}

-

-HRESULT GoopdateCommandLineValidator::OnUpdateApps() {

-  args_->mode = COMMANDLINE_MODE_UA;

-  args_->is_uninstall_set = parser_->HasSwitch(kCmdLineUninstall);

-  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,

-                                  0,

-                                  &(args_->install_source));

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnFinishInstallGoopdate() {

-  args_->mode = COMMANDLINE_MODE_IG;

-  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,

-                                  0,

-                                  &(args_->install_source));

-  args_->is_silent_set = parser_->HasSwitch(kCmdLineSilent);

-  args_->is_eula_required_set = parser_->HasSwitch(kCmdLineEulaRequired);

-  args_->is_offline_set = parser_->HasSwitch(kCmdLineOfflineInstall);

-  return GetExtraAndAppArgs(kCmdLineFinishGoogleUpdateInstall);

-}

-

-HRESULT GoopdateCommandLineValidator::OnFinishUpdateGoopdate() {

-  args_->mode = COMMANDLINE_MODE_UG;

-  args_->is_machine_set = parser_->HasSwitch(kCmdLineMachine);

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnReportCrash() {

-  args_->mode = COMMANDLINE_MODE_REPORTCRASH;

-  args_->is_machine_set = parser_->HasSwitch(kCmdLineMachine);

-  parser_->GetSwitchArgumentValue(kCmdLineCustomInfoFileName,

-                                  0,

-                                  &(args_->custom_info_filename));

-  return parser_->GetSwitchArgumentValue(kCmdLineReport,

-                                         0,

-                                         &(args_->crash_filename));

-}

-

-HRESULT GoopdateCommandLineValidator::OnReportCrashInteractive() {

-  args_->mode = COMMANDLINE_MODE_REPORTCRASH;

-  args_->is_interactive_set = true;

-  args_->is_machine_set = parser_->HasSwitch(kCmdLineMachine);

-  return parser_->GetSwitchArgumentValue(kCmdLineInteractive,

-                                         0,

-                                         &(args_->crash_filename));

-}

-

-HRESULT GoopdateCommandLineValidator::OnUiManifest() {

-  args_->mode = COMMANDLINE_MODE_LEGACYUI;

-  return parser_->GetSwitchArgumentValue(kCmdLineLegacyUi,

-                                         0,

-                                         &(args_->legacy_manifest_path));

-}

-

-HRESULT GoopdateCommandLineValidator::OnUiLangManifest() {

-  args_->mode = COMMANDLINE_MODE_LEGACYUI;

-  HRESULT hr = parser_->GetSwitchArgumentValue(kCmdLineLegacyLang,

-                                               0,

-                                               &(args_->extra.language));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return parser_->GetSwitchArgumentValue(kCmdLineLegacyLang,

-                                         1,

-                                         &(args_->legacy_manifest_path));

-}

-

-HRESULT GoopdateCommandLineValidator::OnUiUserManifest() {

-  args_->mode = COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF;

-  return parser_->GetSwitchArgumentValue(kCmdLineLegacyUserManifest,

-                                         0,

-                                         &(args_->legacy_manifest_path));

-}

-

-HRESULT GoopdateCommandLineValidator::OnWebPlugin() {

-  HRESULT hr = parser_->GetSwitchArgumentValue(kCmdLineInstallSource,

-                                               0,

-                                               &(args_->install_source));

-  if (FAILED(hr)) {

-    return hr;

-  }

-  // Validate install_source value.

-  args_->install_source.MakeLower();

-  if (args_->install_source.Compare(kCmdLineInstallSource_OneClick) != 0) {

-    args_->install_source.Empty();

-    return E_INVALIDARG;

-  }

-

-  args_->mode = COMMANDLINE_MODE_WEBPLUGIN;

-

-  CString urldomain;

-  hr = parser_->GetSwitchArgumentValue(kCmdLineWebPlugin,

-                                       0,

-                                       &urldomain);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  hr = StringUnescape(urldomain, &(args_->webplugin_urldomain));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString webplugin_args;

-  hr = parser_->GetSwitchArgumentValue(kCmdLineWebPlugin,

-                                       1,

-                                       &webplugin_args);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  return StringUnescape(webplugin_args, &(args_->webplugin_args));

-}

-

-HRESULT GoopdateCommandLineValidator::OnCodeRed() {

-  args_->mode = COMMANDLINE_MODE_CODE_RED_CHECK;

-  return S_OK;

-}

-

-HRESULT GoopdateCommandLineValidator::OnRecover() {

-  args_->mode = COMMANDLINE_MODE_RECOVER;

-  return parser_->GetSwitchArgumentValue(

-      kCmdLineRecover,

-      0,

-      &(args_->code_red_metainstaller_path));

-}

-

-HRESULT GoopdateCommandLineValidator::OnRecoverMachine() {

-  args_->mode = COMMANDLINE_MODE_RECOVER;

-  args_->is_machine_set = true;

-  return parser_->GetSwitchArgumentValue(

-      kCmdLineMachine,

-      0,

-      &(args_->code_red_metainstaller_path));

-}

-

-HRESULT GoopdateCommandLineValidator::OnRegisterProduct() {

-  args_->mode = COMMANDLINE_MODE_REGISTER_PRODUCT;

-  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,

-                                  0,

-                                  &(args_->install_source));

-  return GetExtraAndAppArgs(kCmdLineRegisterProduct);

-}

-

-HRESULT GoopdateCommandLineValidator::OnUnregisterProduct() {

-  args_->mode = COMMANDLINE_MODE_UNREGISTER_PRODUCT;

-  return GetExtraAndAppArgs(kCmdLineUnregisterProduct);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/goopdate_command_line_validator.h"
+
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/command_line_parser.h"
+#include "omaha/goopdate/command_line_validator.h"
+#include "omaha/goopdate/extra_args_parser.h"
+
+namespace omaha {
+
+GoopdateCommandLineValidator::GoopdateCommandLineValidator() {
+}
+
+GoopdateCommandLineValidator::~GoopdateCommandLineValidator() {
+}
+
+HRESULT GoopdateCommandLineValidator::Setup() {
+  validator_.reset(new CommandLineValidator);
+
+  CString cmd_line;
+
+  // gu.exe
+  cmd_line.Empty();
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnNoArgs);
+
+  // gu.exe /c [/nocrashserver
+  cmd_line.Format(_T("/%s [/%s"), kCmdLineCore, kCmdLineNoCrashHandler);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnCore);
+
+  // gu.exe /crashhandler
+  cmd_line.Format(_T("/%s"), kCmdLineCrashHandler);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnCrashHandler);
+
+  // gu.exe /svc
+  cmd_line.Format(_T("/%s"), kCmdLineService);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnService);
+
+  // gu.exe /regsvc
+  cmd_line.Format(_T("/%s"), kCmdLineRegisterService);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnServiceRegister);
+
+  // gu.exe /unregsvc
+  cmd_line.Format(_T("/%s"), kCmdLineUnregisterService);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnServiceUnregister);
+
+  // gu.exe /regserver
+  cmd_line.Format(_T("/%s"), kCmdRegServer);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnRegServer);
+
+  // gu.exe /unregserver
+  cmd_line.Format(_T("/%s"), kCmdUnregServer);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUnregServer);
+
+  // gu.exe /netdiags
+  cmd_line.Format(_T("/%s"), kCmdLineNetDiags);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnNetDiags);
+
+  // gu.exe /crash
+  cmd_line.Format(_T("/%s"), kCmdLineCrash);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnCrash);
+
+  // gu.exe -Embedding. The -Embedding text is injected via COM.
+  CreateScenario(kCmdLineComServerDash,
+                 &GoopdateCommandLineValidator::OnComServer);
+
+  // gu.exe /install <extraargs> [/appargs <appargs> [/installsource source
+  //        [/silent [/eularequired [/oem [/installelevated
+  cmd_line.Format(_T("/%s extra [/%s appargs [/%s src [/%s [/%s [/%s [/%s"),
+                  kCmdLineInstall,
+                  kCmdLineAppArgs,
+                  kCmdLineInstallSource,
+                  kCmdLineSilent,
+                  kCmdLineEulaRequired,
+                  kCmdLineOem,
+                  kCmdLineInstallElevated);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnInstall);
+
+  // gu.exe /update
+  cmd_line.Format(_T("/%s"), kCmdLineUpdate);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUpdate);
+
+  // gu.exe /ig <extraargs> [/appargs <appargs> [/installsource source
+  //        [/silent [/eularequired [/offlineinstall
+  cmd_line.Format(_T("/%s extraargs [/%s appargs [/%s source [/%s [/%s [/%s"),
+                  kCmdLineFinishGoogleUpdateInstall,
+                  kCmdLineAppArgs,
+                  kCmdLineInstallSource,
+                  kCmdLineSilent,
+                  kCmdLineEulaRequired,
+                  kCmdLineOfflineInstall);
+  CreateScenario(cmd_line,
+                 &GoopdateCommandLineValidator::OnFinishInstallGoopdate);
+
+  // gu.exe /handoff <extraargs> [/appargs <appargs> [/installsource source
+  //        [/silent [/eularequired [/offlineinstall
+  cmd_line.Format(_T("/%s extra [/%s appargs [/%s source [/%s [/%s [/%s"),
+                  kCmdLineAppHandoffInstall,
+                  kCmdLineAppArgs,
+                  kCmdLineInstallSource,
+                  kCmdLineSilent,
+                  kCmdLineEulaRequired,
+                  kCmdLineOfflineInstall);
+  CreateScenario(cmd_line,
+                 &GoopdateCommandLineValidator::OnInstallHandoffWorker);
+
+  // gu.exe /ua [/installsource source [/uninstall
+  cmd_line.Format(_T("/%s [/%s source [/%s"),
+                  kCmdLineUpdateApps, kCmdLineInstallSource, kCmdLineUninstall);
+  CreateScenario(cmd_line,
+                 &GoopdateCommandLineValidator::OnUpdateApps);
+
+  // gu.exe /ug [/machine
+  cmd_line.Format(_T("/%s [/%s"),
+                  kCmdLineFinishGoogleUpdateUpdate, kCmdLineMachine);
+  CreateScenario(cmd_line,
+                 &GoopdateCommandLineValidator::OnFinishUpdateGoopdate);
+
+  // gu.exe /report <crash_filename> [/machine
+  //        [/custom_info <custom_info_filename>
+  cmd_line.Format(_T("/%s filename [/%s [/%s customfilename"),
+                  kCmdLineReport,
+                  kCmdLineMachine,
+                  kCmdLineCustomInfoFileName);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnReportCrash);
+
+  // gu.exe /report /i <crash_filename> [/machine
+  cmd_line.Format(_T("/%s /%s filename [/%s"),
+                  kCmdLineReport,
+                  kCmdLineInteractive,
+                  kCmdLineMachine);
+  CreateScenario(cmd_line,
+                 &GoopdateCommandLineValidator::OnReportCrashInteractive);
+
+  // gu.exe /pi <domainurl> <args> /installsource oneclick
+  cmd_line.Format(_T("/%s domainurl args /%s oneclick"),
+                  kCmdLineWebPlugin,
+                  kCmdLineInstallSource);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnWebPlugin);
+
+  // gu.exe /cr
+  cmd_line.Format(_T("/%s"), kCmdLineCodeRedCheck);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnCodeRed);
+
+  // gu.exe /recover <repair_file>
+  cmd_line.Format(_T("/%s repairfile"), kCmdLineRecover);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnRecover);
+
+  // gu.exe /recover /machine <repair_file>
+  cmd_line.Format(_T("/%s /%s repairfile"), kCmdLineRecover, kCmdLineMachine);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnRecoverMachine);
+
+  // gu.exe /registerproduct "extraargs" [/installsource source
+  cmd_line.Format(_T("/%s extraargs [/%s source"),
+                  kCmdLineRegisterProduct,
+                  kCmdLineInstallSource);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnRegisterProduct);
+
+  // gu.exe /unregisterproduct "extraargs"
+  cmd_line.Format(_T("/%s extraargs"), kCmdLineUnregisterProduct);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUnregisterProduct);
+
+  //
+  // Legacy support command lines.
+  //
+
+  // gu.exe /uiuser <manifestfilename>
+  cmd_line.Format(_T("/%s filename"),
+                  kCmdLineLegacyUserManifest);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUiUserManifest);
+
+  // TODO(omaha):  Can we remove this case or is it here for back compat?
+  // gu.exe /ui /lang en <manifestfilename>
+  cmd_line.Format(_T("/%s /%s en filename"),
+                  kCmdLineLegacyUi,
+                  kCmdLineLegacyLang);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUiLangManifest);
+
+  // gu.exe /ui <manifestfilename>
+  cmd_line.Format(_T("/%s filename"), kCmdLineLegacyUi);
+  CreateScenario(cmd_line, &GoopdateCommandLineValidator::OnUiManifest);
+
+  // gu.exe /handoff <extraargs> /lang <en> [/installsource source
+  cmd_line.Format(_T("/%s extraargs /%s en [/%s source"),
+                  kCmdLineAppHandoffInstall,
+                  kCmdLineLegacyLang,
+                  kCmdLineInstallSource);
+  CreateScenario(cmd_line,
+                 &GoopdateCommandLineValidator::OnInstallHandoffWorkerLegacy);
+
+  // gu.exe /install <extraargs> /installsource source /lang en.
+  cmd_line.Format(_T("/%s extraargs /%s source /%s en"),
+                  kCmdLineInstall, kCmdLineInstallSource, kCmdLineLegacyLang);
+  CreateScenario(cmd_line,
+                 &GoopdateCommandLineValidator::OnInstallWithSourceLegacy);
+  return S_OK;
+}
+
+// TODO(Omaha): Add check that each scenario is unique and does not overlap an
+// existing one in DBG builds.
+HRESULT GoopdateCommandLineValidator::Validate(const CommandLineParser* parser,
+                                               CommandLineArgs* args) {
+  ASSERT1(parser);
+  ASSERT1(args);
+
+  parser_ = parser;
+  args_ = args;
+
+  CString scenario_name;
+  HRESULT hr = validator_->Validate(*parser_, &scenario_name);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[GoopdateCommandLineValidator::Validate Failed][0x%x]"),
+                  hr));
+    return hr;
+  }
+
+  MapScenarioHandlersIter iter = scenario_handlers_.find(scenario_name);
+  if (iter == scenario_handlers_.end()) {
+    ASSERT1(false);
+    return GOOGLEUPDATE_COMMANDLINE_E_NO_SCENARIO_HANDLER;
+  }
+
+  ScenarioHandler handler = (*iter).second;
+  return (this->*handler)();
+}
+
+void GoopdateCommandLineValidator::CreateScenario(const TCHAR* cmd_line,
+                                                  ScenarioHandler handler) {
+  // Prepend the program name onto the cmd_line.
+  CString scenario_cmd_line;
+  scenario_cmd_line.Format(_T("prog.exe %s"), cmd_line);
+
+  CString scenario_name;
+  validator_->CreateScenarioFromCmdLine(scenario_cmd_line, &scenario_name);
+  // TODO(omaha): Make sure it doesn't already exist.
+  scenario_handlers_[scenario_name] = handler;
+}
+
+HRESULT GoopdateCommandLineValidator::GetExtraAndAppArgs(const CString& name) {
+  HRESULT hr = parser_->GetSwitchArgumentValue(name,
+                                               0,
+                                               &args_->extra_args_str);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = parser_->GetSwitchArgumentValue(kCmdLineAppArgs,
+                                       0,
+                                       &args_->app_args_str);
+  if (FAILED(hr)) {
+    args_->app_args_str.Empty();
+  }
+
+  ExtraArgsParser extra_args_parser;
+  return extra_args_parser.Parse(args_->extra_args_str,
+                                 args_->app_args_str,
+                                 &(args_->extra));
+}
+
+HRESULT GoopdateCommandLineValidator::OnNoArgs() {
+  args_->mode = COMMANDLINE_MODE_NOARGS;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnCore() {
+  args_->mode = COMMANDLINE_MODE_CORE;
+  args_->is_crash_handler_disabled = parser_->HasSwitch(kCmdLineNoCrashHandler);
+
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnCrashHandler() {
+  args_->mode = COMMANDLINE_MODE_CRASH_HANDLER;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnService() {
+  args_->mode = COMMANDLINE_MODE_SERVICE;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnServiceRegister() {
+  args_->mode = COMMANDLINE_MODE_SERVICE_REGISTER;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnServiceUnregister() {
+  args_->mode = COMMANDLINE_MODE_SERVICE_UNREGISTER;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnRegServer() {
+  args_->mode = COMMANDLINE_MODE_REGSERVER;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnUnregServer() {
+  args_->mode = COMMANDLINE_MODE_UNREGSERVER;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnNetDiags() {
+  args_->mode = COMMANDLINE_MODE_NETDIAGS;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnCrash() {
+  args_->mode = COMMANDLINE_MODE_CRASH;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnComServer() {
+  args_->mode = COMMANDLINE_MODE_COMSERVER;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnInstall() {
+  args_->mode = COMMANDLINE_MODE_INSTALL;
+  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,
+                                  0,
+                                  &(args_->install_source));
+  args_->is_silent_set = parser_->HasSwitch(kCmdLineSilent);
+  args_->is_eula_required_set = parser_->HasSwitch(kCmdLineEulaRequired);
+  args_->is_oem_set = parser_->HasSwitch(kCmdLineOem);
+  args_->is_install_elevated = parser_->HasSwitch(kCmdLineInstallElevated);
+  return GetExtraAndAppArgs(kCmdLineInstall);
+}
+
+HRESULT GoopdateCommandLineValidator::OnInstallWithSourceLegacy() {
+  args_->mode = COMMANDLINE_MODE_INSTALL;
+  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,
+                                  0,
+                                  &(args_->install_source));
+  parser_->GetSwitchArgumentValue(kCmdLineLegacyLang,
+                                  0,
+                                  &(args_->extra.language));
+  return GetExtraAndAppArgs(kCmdLineInstall);
+}
+
+HRESULT GoopdateCommandLineValidator::OnUpdate() {
+  args_->mode = COMMANDLINE_MODE_UPDATE;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnInstallHandoffWorker() {
+  args_->mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,
+                                  0,
+                                  &(args_->install_source));
+  args_->is_silent_set = parser_->HasSwitch(kCmdLineSilent);
+  args_->is_eula_required_set = parser_->HasSwitch(kCmdLineEulaRequired);
+  args_->is_offline_set = parser_->HasSwitch(kCmdLineOfflineInstall);
+  return GetExtraAndAppArgs(kCmdLineAppHandoffInstall);
+}
+
+HRESULT GoopdateCommandLineValidator::OnInstallHandoffWorkerLegacy() {
+  args_->mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  HRESULT hr = GetExtraAndAppArgs(kCmdLineAppHandoffInstall);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,
+                                  0,
+                                  &(args_->install_source));
+  return parser_->GetSwitchArgumentValue(kCmdLineLegacyLang,
+                                         0,
+                                         &(args_->extra.language));
+}
+
+HRESULT GoopdateCommandLineValidator::OnUpdateApps() {
+  args_->mode = COMMANDLINE_MODE_UA;
+  args_->is_uninstall_set = parser_->HasSwitch(kCmdLineUninstall);
+  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,
+                                  0,
+                                  &(args_->install_source));
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnFinishInstallGoopdate() {
+  args_->mode = COMMANDLINE_MODE_IG;
+  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,
+                                  0,
+                                  &(args_->install_source));
+  args_->is_silent_set = parser_->HasSwitch(kCmdLineSilent);
+  args_->is_eula_required_set = parser_->HasSwitch(kCmdLineEulaRequired);
+  args_->is_offline_set = parser_->HasSwitch(kCmdLineOfflineInstall);
+  return GetExtraAndAppArgs(kCmdLineFinishGoogleUpdateInstall);
+}
+
+HRESULT GoopdateCommandLineValidator::OnFinishUpdateGoopdate() {
+  args_->mode = COMMANDLINE_MODE_UG;
+  args_->is_machine_set = parser_->HasSwitch(kCmdLineMachine);
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnReportCrash() {
+  args_->mode = COMMANDLINE_MODE_REPORTCRASH;
+  args_->is_machine_set = parser_->HasSwitch(kCmdLineMachine);
+  parser_->GetSwitchArgumentValue(kCmdLineCustomInfoFileName,
+                                  0,
+                                  &(args_->custom_info_filename));
+  return parser_->GetSwitchArgumentValue(kCmdLineReport,
+                                         0,
+                                         &(args_->crash_filename));
+}
+
+HRESULT GoopdateCommandLineValidator::OnReportCrashInteractive() {
+  args_->mode = COMMANDLINE_MODE_REPORTCRASH;
+  args_->is_interactive_set = true;
+  args_->is_machine_set = parser_->HasSwitch(kCmdLineMachine);
+  return parser_->GetSwitchArgumentValue(kCmdLineInteractive,
+                                         0,
+                                         &(args_->crash_filename));
+}
+
+HRESULT GoopdateCommandLineValidator::OnUiManifest() {
+  args_->mode = COMMANDLINE_MODE_LEGACYUI;
+  return parser_->GetSwitchArgumentValue(kCmdLineLegacyUi,
+                                         0,
+                                         &(args_->legacy_manifest_path));
+}
+
+HRESULT GoopdateCommandLineValidator::OnUiLangManifest() {
+  args_->mode = COMMANDLINE_MODE_LEGACYUI;
+  HRESULT hr = parser_->GetSwitchArgumentValue(kCmdLineLegacyLang,
+                                               0,
+                                               &(args_->extra.language));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return parser_->GetSwitchArgumentValue(kCmdLineLegacyLang,
+                                         1,
+                                         &(args_->legacy_manifest_path));
+}
+
+HRESULT GoopdateCommandLineValidator::OnUiUserManifest() {
+  args_->mode = COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF;
+  return parser_->GetSwitchArgumentValue(kCmdLineLegacyUserManifest,
+                                         0,
+                                         &(args_->legacy_manifest_path));
+}
+
+HRESULT GoopdateCommandLineValidator::OnWebPlugin() {
+  HRESULT hr = parser_->GetSwitchArgumentValue(kCmdLineInstallSource,
+                                               0,
+                                               &(args_->install_source));
+  if (FAILED(hr)) {
+    return hr;
+  }
+  // Validate install_source value.
+  args_->install_source.MakeLower();
+  if (args_->install_source.Compare(kCmdLineInstallSource_OneClick) != 0) {
+    args_->install_source.Empty();
+    return E_INVALIDARG;
+  }
+
+  args_->mode = COMMANDLINE_MODE_WEBPLUGIN;
+
+  CString urldomain;
+  hr = parser_->GetSwitchArgumentValue(kCmdLineWebPlugin,
+                                       0,
+                                       &urldomain);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  hr = StringUnescape(urldomain, &(args_->webplugin_urldomain));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString webplugin_args;
+  hr = parser_->GetSwitchArgumentValue(kCmdLineWebPlugin,
+                                       1,
+                                       &webplugin_args);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  return StringUnescape(webplugin_args, &(args_->webplugin_args));
+}
+
+HRESULT GoopdateCommandLineValidator::OnCodeRed() {
+  args_->mode = COMMANDLINE_MODE_CODE_RED_CHECK;
+  return S_OK;
+}
+
+HRESULT GoopdateCommandLineValidator::OnRecover() {
+  args_->mode = COMMANDLINE_MODE_RECOVER;
+  return parser_->GetSwitchArgumentValue(
+      kCmdLineRecover,
+      0,
+      &(args_->code_red_metainstaller_path));
+}
+
+HRESULT GoopdateCommandLineValidator::OnRecoverMachine() {
+  args_->mode = COMMANDLINE_MODE_RECOVER;
+  args_->is_machine_set = true;
+  return parser_->GetSwitchArgumentValue(
+      kCmdLineMachine,
+      0,
+      &(args_->code_red_metainstaller_path));
+}
+
+HRESULT GoopdateCommandLineValidator::OnRegisterProduct() {
+  args_->mode = COMMANDLINE_MODE_REGISTER_PRODUCT;
+  parser_->GetSwitchArgumentValue(kCmdLineInstallSource,
+                                  0,
+                                  &(args_->install_source));
+  return GetExtraAndAppArgs(kCmdLineRegisterProduct);
+}
+
+HRESULT GoopdateCommandLineValidator::OnUnregisterProduct() {
+  args_->mode = COMMANDLINE_MODE_UNREGISTER_PRODUCT;
+  return GetExtraAndAppArgs(kCmdLineUnregisterProduct);
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/goopdate_command_line_validator.h b/goopdate/goopdate_command_line_validator.h
index cbcd560..aad133f 100644
--- a/goopdate/goopdate_command_line_validator.h
+++ b/goopdate/goopdate_command_line_validator.h
@@ -1,98 +1,98 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_GOOPDATE_COMMAND_LINE_VALIDATOR_H__

-#define OMAHA_GOOPDATE_GOOPDATE_COMMAND_LINE_VALIDATOR_H__

-

-#include <windows.h>

-#include <atlstr.h>

-

-#include <map>

-

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-

-namespace omaha {

-

-struct CommandLineArgs;

-class CommandLineParser;

-class CommandLineValidator;

-

-// Validates all of the command line permutations for googleupdate.exe.

-class GoopdateCommandLineValidator {

- public:

-  typedef HRESULT (GoopdateCommandLineValidator::*ScenarioHandler)();

-  typedef std::map<CString, ScenarioHandler> MapScenarioHandlers;

-  typedef MapScenarioHandlers::iterator MapScenarioHandlersIter;

-

-  GoopdateCommandLineValidator();

-  ~GoopdateCommandLineValidator();

-

-  // Sets up the scenarios.

-  HRESULT Setup();

-

-  // Validates a pre-parsed parser against the scenarios and returns a

-  // CommandLineArgs structure filled in with the proper values.

-  HRESULT Validate(const CommandLineParser* parser, CommandLineArgs* args);

-

- private:

-  // Specific command-line scenario handlers.

-  HRESULT OnNoArgs();

-  HRESULT OnCore();

-  HRESULT OnCrashHandler();

-  HRESULT OnService();

-  HRESULT OnServiceRegister();

-  HRESULT OnServiceUnregister();

-  HRESULT OnRegServer();

-  HRESULT OnUnregServer();

-  HRESULT OnNetDiags();

-  HRESULT OnCrash();

-  HRESULT OnComServer();

-  HRESULT OnInstall();

-  HRESULT OnInstallWithSourceLegacy();

-  HRESULT OnUpdate();

-  HRESULT OnInstallHandoffWorker();

-  HRESULT OnInstallHandoffWorkerLegacy();

-  HRESULT OnUpdateApps();

-  HRESULT OnFinishInstallGoopdate();

-  HRESULT OnFinishUpdateGoopdate();

-  HRESULT OnReportCrash();

-  HRESULT OnReportCrashInteractive();

-  HRESULT OnUiManifest();

-  HRESULT OnUiLangManifest();

-  HRESULT OnUiUserManifest();

-  HRESULT OnWebPlugin();

-  HRESULT OnCodeRed();

-  HRESULT OnRecover();

-  HRESULT OnRecoverMachine();

-  HRESULT OnRegisterProduct();

-  HRESULT OnUnregisterProduct();

-

-  void CreateScenario(const TCHAR* cmd_line, ScenarioHandler handler);

-

-  HRESULT GetExtraAndAppArgs(const CString& switch_name);

-

-  const CommandLineParser* parser_;

-  CommandLineArgs* args_;

-  scoped_ptr<CommandLineValidator> validator_;

-  MapScenarioHandlers scenario_handlers_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(GoopdateCommandLineValidator);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_GOOPDATE_COMMAND_LINE_VALIDATOR_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_GOOPDATE_COMMAND_LINE_VALIDATOR_H__
+#define OMAHA_GOOPDATE_GOOPDATE_COMMAND_LINE_VALIDATOR_H__
+
+#include <windows.h>
+#include <atlstr.h>
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+
+namespace omaha {
+
+struct CommandLineArgs;
+class CommandLineParser;
+class CommandLineValidator;
+
+// Validates all of the command line permutations for googleupdate.exe.
+class GoopdateCommandLineValidator {
+ public:
+  typedef HRESULT (GoopdateCommandLineValidator::*ScenarioHandler)();
+  typedef std::map<CString, ScenarioHandler> MapScenarioHandlers;
+  typedef MapScenarioHandlers::iterator MapScenarioHandlersIter;
+
+  GoopdateCommandLineValidator();
+  ~GoopdateCommandLineValidator();
+
+  // Sets up the scenarios.
+  HRESULT Setup();
+
+  // Validates a pre-parsed parser against the scenarios and returns a
+  // CommandLineArgs structure filled in with the proper values.
+  HRESULT Validate(const CommandLineParser* parser, CommandLineArgs* args);
+
+ private:
+  // Specific command-line scenario handlers.
+  HRESULT OnNoArgs();
+  HRESULT OnCore();
+  HRESULT OnCrashHandler();
+  HRESULT OnService();
+  HRESULT OnServiceRegister();
+  HRESULT OnServiceUnregister();
+  HRESULT OnRegServer();
+  HRESULT OnUnregServer();
+  HRESULT OnNetDiags();
+  HRESULT OnCrash();
+  HRESULT OnComServer();
+  HRESULT OnInstall();
+  HRESULT OnInstallWithSourceLegacy();
+  HRESULT OnUpdate();
+  HRESULT OnInstallHandoffWorker();
+  HRESULT OnInstallHandoffWorkerLegacy();
+  HRESULT OnUpdateApps();
+  HRESULT OnFinishInstallGoopdate();
+  HRESULT OnFinishUpdateGoopdate();
+  HRESULT OnReportCrash();
+  HRESULT OnReportCrashInteractive();
+  HRESULT OnUiManifest();
+  HRESULT OnUiLangManifest();
+  HRESULT OnUiUserManifest();
+  HRESULT OnWebPlugin();
+  HRESULT OnCodeRed();
+  HRESULT OnRecover();
+  HRESULT OnRecoverMachine();
+  HRESULT OnRegisterProduct();
+  HRESULT OnUnregisterProduct();
+
+  void CreateScenario(const TCHAR* cmd_line, ScenarioHandler handler);
+
+  HRESULT GetExtraAndAppArgs(const CString& switch_name);
+
+  const CommandLineParser* parser_;
+  CommandLineArgs* args_;
+  scoped_ptr<CommandLineValidator> validator_;
+  MapScenarioHandlers scenario_handlers_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(GoopdateCommandLineValidator);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_GOOPDATE_COMMAND_LINE_VALIDATOR_H__
+
diff --git a/goopdate/goopdate_helper.cc b/goopdate/goopdate_helper.cc
index ee27fc6..1fc6291 100644
--- a/goopdate/goopdate_helper.cc
+++ b/goopdate/goopdate_helper.cc
@@ -1,110 +1,110 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-

-#include <windows.h>

-

-#include "omaha/goopdate/goopdate_helper.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/resource.h"

-#include "omaha/setup/setup.h"

-#include "omaha/worker/application_manager.h"

-#include "omaha/worker/job_observer.h"

-#include "omaha/worker/ping_utils.h"

-#include "omaha/worker/worker_metrics.h"

-

-namespace omaha {

-

-// job_observer can be NULL.

-HRESULT FinishGoogleUpdateInstall(const CommandLineArgs& args,

-                                  bool is_machine,

-                                  bool is_self_update,

-                                  Ping* ping,

-                                  JobObserver* job_observer) {

-  CORE_LOG(L2, (_T("[FinishGoogleUpdateInstall]")));

-  ASSERT1(args.mode == COMMANDLINE_MODE_IG ||

-          args.mode == COMMANDLINE_MODE_UG);

-  ASSERT1(ping);

-

-  // Get the previous version before updating it.

-  AppManager app_manager(is_machine);

-  ProductData product_data;

-  HRESULT hr = app_manager.ReadProductDataFromStore(kGoopdateGuid,

-                                                    &product_data);

-  if (FAILED(hr)) {

-    CORE_LOG(L2, (_T("[ReadProductDataFromStore failed][0x%08x]"), hr));

-  }

-  const CString& previous_version = product_data.app_data().previous_version();

-

-  // Send a ping for the "start" of Setup. This is actually the start of setup

-  // phase 2. We can't ping at the true beginning of Setup because we can't

-  // ping from the temp directory.

-  HRESULT hr_ping = ping_utils::SendGoopdatePing(

-      is_machine,

-      args.extra,

-      is_self_update ? PingEvent::EVENT_SETUP_UPDATE_BEGIN :

-                       PingEvent::EVENT_SETUP_INSTALL_BEGIN,

-      S_OK,

-      0,

-      NULL,

-      ping);

-  if (FAILED(hr_ping)) {

-    CORE_LOG(LW, (_T("[SendSetupPing(started) failed][0x%08x]"), hr_ping));

-  }

-

-  Setup setup(is_machine, &args);

-  hr = setup.SetupGoogleUpdate();

-  // Do not return until the ping is sent.

-

-  if (SUCCEEDED(hr)) {

-    CORE_LOG(L1, (_T("[Setup successfully completed]")));

-    // All Omaha installs are "offline" because there is no update check.

-    app_manager.RecordSuccessfulInstall(GUID_NULL,

-                                        kGoopdateGuid,

-                                        is_self_update,

-                                        !is_self_update);  // is_offline

-

-    if (is_self_update) {

-      ++metric_worker_self_updates_succeeded;

-    }

-  } else {

-    CORE_LOG(LE, (_T("[Setup::SetupGoogleUpdate failed][0x%08x]"), hr));

-

-    if (job_observer) {

-      ASSERT1(!is_self_update);

-      CString message;

-      message.FormatMessage(IDS_SETUP_FAILED, hr);

-      job_observer->OnComplete(COMPLETION_CODE_ERROR, message, hr);

-    }

-  }

-

-  // Send a ping to report Setup has completed.

-  hr_ping = ping_utils::SendPostSetupPing(hr,

-                                          setup.extra_code1(),

-                                          previous_version,

-                                          is_machine,

-                                          is_self_update,

-                                          args.extra,

-                                          ping);

-  if (FAILED(hr_ping)) {

-    CORE_LOG(LW, (_T("[SendSetupPing(completed) failed][0x%08x]"), hr_ping));

-  }

-

-  return hr;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+
+#include <windows.h>
+
+#include "omaha/goopdate/goopdate_helper.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/resource.h"
+#include "omaha/setup/setup.h"
+#include "omaha/worker/application_manager.h"
+#include "omaha/worker/job_observer.h"
+#include "omaha/worker/ping_utils.h"
+#include "omaha/worker/worker_metrics.h"
+
+namespace omaha {
+
+// job_observer can be NULL.
+HRESULT FinishGoogleUpdateInstall(const CommandLineArgs& args,
+                                  bool is_machine,
+                                  bool is_self_update,
+                                  Ping* ping,
+                                  JobObserver* job_observer) {
+  CORE_LOG(L2, (_T("[FinishGoogleUpdateInstall]")));
+  ASSERT1(args.mode == COMMANDLINE_MODE_IG ||
+          args.mode == COMMANDLINE_MODE_UG);
+  ASSERT1(ping);
+
+  // Get the previous version before updating it.
+  AppManager app_manager(is_machine);
+  ProductData product_data;
+  HRESULT hr = app_manager.ReadProductDataFromStore(kGoopdateGuid,
+                                                    &product_data);
+  if (FAILED(hr)) {
+    CORE_LOG(L2, (_T("[ReadProductDataFromStore failed][0x%08x]"), hr));
+  }
+  const CString& previous_version = product_data.app_data().previous_version();
+
+  // Send a ping for the "start" of Setup. This is actually the start of setup
+  // phase 2. We can't ping at the true beginning of Setup because we can't
+  // ping from the temp directory.
+  HRESULT hr_ping = ping_utils::SendGoopdatePing(
+      is_machine,
+      args.extra,
+      is_self_update ? PingEvent::EVENT_SETUP_UPDATE_BEGIN :
+                       PingEvent::EVENT_SETUP_INSTALL_BEGIN,
+      S_OK,
+      0,
+      NULL,
+      ping);
+  if (FAILED(hr_ping)) {
+    CORE_LOG(LW, (_T("[SendSetupPing(started) failed][0x%08x]"), hr_ping));
+  }
+
+  Setup setup(is_machine, &args);
+  hr = setup.SetupGoogleUpdate();
+  // Do not return until the ping is sent.
+
+  if (SUCCEEDED(hr)) {
+    CORE_LOG(L1, (_T("[Setup successfully completed]")));
+    // All Omaha installs are "offline" because there is no update check.
+    app_manager.RecordSuccessfulInstall(GUID_NULL,
+                                        kGoopdateGuid,
+                                        is_self_update,
+                                        !is_self_update);  // is_offline
+
+    if (is_self_update) {
+      ++metric_worker_self_updates_succeeded;
+    }
+  } else {
+    CORE_LOG(LE, (_T("[Setup::SetupGoogleUpdate failed][0x%08x]"), hr));
+
+    if (job_observer) {
+      ASSERT1(!is_self_update);
+      CString message;
+      message.FormatMessage(IDS_SETUP_FAILED, hr);
+      job_observer->OnComplete(COMPLETION_CODE_ERROR, message, hr);
+    }
+  }
+
+  // Send a ping to report Setup has completed.
+  hr_ping = ping_utils::SendPostSetupPing(hr,
+                                          setup.extra_code1(),
+                                          previous_version,
+                                          is_machine,
+                                          is_self_update,
+                                          args.extra,
+                                          ping);
+  if (FAILED(hr_ping)) {
+    CORE_LOG(LW, (_T("[SendSetupPing(completed) failed][0x%08x]"), hr_ping));
+  }
+
+  return hr;
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/goopdate_helper.h b/goopdate/goopdate_helper.h
index b36c563..11f3ee2 100644
--- a/goopdate/goopdate_helper.h
+++ b/goopdate/goopdate_helper.h
@@ -1,39 +1,39 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_GOOPDATE_HELPER_H__

-#define OMAHA_GOOPDATE_GOOPDATE_HELPER_H__

-

-#include <windows.h>

-

-

-namespace omaha {

-

-class JobObserver;

-class Ping;

-struct CommandLineArgs;

-

-// Sends the GoopdateStartedPing, calls setup to finish setup and sends

-// the finish setup complete ping.

-HRESULT FinishGoogleUpdateInstall(const CommandLineArgs& args,

-                                  bool is_machine,

-                                  bool is_self_update,

-                                  Ping* ping,

-                                  JobObserver* job_observer);

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_GOOPDATE_HELPER_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_GOOPDATE_HELPER_H__
+#define OMAHA_GOOPDATE_GOOPDATE_HELPER_H__
+
+#include <windows.h>
+
+
+namespace omaha {
+
+class JobObserver;
+class Ping;
+struct CommandLineArgs;
+
+// Sends the GoopdateStartedPing, calls setup to finish setup and sends
+// the finish setup complete ping.
+HRESULT FinishGoogleUpdateInstall(const CommandLineArgs& args,
+                                  bool is_machine,
+                                  bool is_self_update,
+                                  Ping* ping,
+                                  JobObserver* job_observer);
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_GOOPDATE_HELPER_H__
+
diff --git a/goopdate/goopdate_metrics.cc b/goopdate/goopdate_metrics.cc
index 0e0013d..4854e16 100644
--- a/goopdate/goopdate_metrics.cc
+++ b/goopdate/goopdate_metrics.cc
@@ -1,52 +1,52 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/goopdate_metrics.h"

-

-namespace omaha {

-

-DEFINE_METRIC_integer(windows_major_version);

-DEFINE_METRIC_integer(windows_minor_version);

-DEFINE_METRIC_integer(windows_sp_major_version);

-DEFINE_METRIC_integer(windows_sp_minor_version);

-

-DEFINE_METRIC_count(handoff_legacy_user);

-DEFINE_METRIC_count(handoff_legacy_machine);

-DEFINE_METRIC_count(handoff_legacy_10);

-DEFINE_METRIC_count(handoff_legacy_11);

-

-DEFINE_METRIC_count(crashes_total);

-DEFINE_METRIC_count(crashes_uploaded);

-DEFINE_METRIC_count(crashes_throttled);

-DEFINE_METRIC_count(crashes_rejected);

-DEFINE_METRIC_count(crashes_failed);

-DEFINE_METRIC_count(oop_crashes_requested);

-DEFINE_METRIC_count(oop_crashes_total);

-DEFINE_METRIC_count(oop_crashes_uploaded);

-DEFINE_METRIC_count(oop_crashes_throttled);

-DEFINE_METRIC_count(oop_crashes_rejected);

-DEFINE_METRIC_count(oop_crashes_failed);

-DEFINE_METRIC_count(crash_start_server_total);

-DEFINE_METRIC_count(crash_start_server_succeeded);

-

-DEFINE_METRIC_count(cr_process_total);

-DEFINE_METRIC_count(cr_callback_total);

-DEFINE_METRIC_count(cr_callback_status_200);

-DEFINE_METRIC_count(cr_callback_status_204);

-DEFINE_METRIC_count(cr_callback_status_other);

-

-DEFINE_METRIC_count(load_resource_dll_failed);

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/goopdate_metrics.h"
+
+namespace omaha {
+
+DEFINE_METRIC_integer(windows_major_version);
+DEFINE_METRIC_integer(windows_minor_version);
+DEFINE_METRIC_integer(windows_sp_major_version);
+DEFINE_METRIC_integer(windows_sp_minor_version);
+
+DEFINE_METRIC_count(handoff_legacy_user);
+DEFINE_METRIC_count(handoff_legacy_machine);
+DEFINE_METRIC_count(handoff_legacy_10);
+DEFINE_METRIC_count(handoff_legacy_11);
+
+DEFINE_METRIC_count(crashes_total);
+DEFINE_METRIC_count(crashes_uploaded);
+DEFINE_METRIC_count(crashes_throttled);
+DEFINE_METRIC_count(crashes_rejected);
+DEFINE_METRIC_count(crashes_failed);
+DEFINE_METRIC_count(oop_crashes_requested);
+DEFINE_METRIC_count(oop_crashes_total);
+DEFINE_METRIC_count(oop_crashes_uploaded);
+DEFINE_METRIC_count(oop_crashes_throttled);
+DEFINE_METRIC_count(oop_crashes_rejected);
+DEFINE_METRIC_count(oop_crashes_failed);
+DEFINE_METRIC_count(crash_start_server_total);
+DEFINE_METRIC_count(crash_start_server_succeeded);
+
+DEFINE_METRIC_count(cr_process_total);
+DEFINE_METRIC_count(cr_callback_total);
+DEFINE_METRIC_count(cr_callback_status_200);
+DEFINE_METRIC_count(cr_callback_status_204);
+DEFINE_METRIC_count(cr_callback_status_other);
+
+DEFINE_METRIC_count(load_resource_dll_failed);
+
+}  // namespace omaha
diff --git a/goopdate/goopdate_metrics.h b/goopdate/goopdate_metrics.h
index b3ba0d1..7bce7f4 100644
--- a/goopdate/goopdate_metrics.h
+++ b/goopdate/goopdate_metrics.h
@@ -1,87 +1,87 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// Declares the usage metrics used by goopdate module.

-

-#ifndef OMAHA_GOOPDATE_GOOPDATE_METRICS_H_

-#define OMAHA_GOOPDATE_GOOPDATE_METRICS_H_

-

-#include "omaha/statsreport/metrics.h"

-

-namespace omaha {

-

-DECLARE_METRIC_integer(windows_major_version);

-DECLARE_METRIC_integer(windows_minor_version);

-DECLARE_METRIC_integer(windows_sp_major_version);

-DECLARE_METRIC_integer(windows_sp_minor_version);

-

-// How many times we received a user/machine legacy handoff from an Omaha 1.0.x

-// or 1.1.x metainstaller. These are determined early on in the handoff process

-// whereas the 1.0 and 1.1 metrics are not determined until the XML is parsed so

-// the version metrics may not sum up to the user/machine sum if errors occur.

-DECLARE_METRIC_count(handoff_legacy_user);

-DECLARE_METRIC_count(handoff_legacy_machine);

-// How many times we received a handoff from an Omaha 1.0.x metainstaller.

-DECLARE_METRIC_count(handoff_legacy_10);

-// How many times we received a handoff from an Omaha 1.1.x metainstaller.

-DECLARE_METRIC_count(handoff_legacy_11);

-

-// Crash metrics.

-//

-// A crash can be handled in one of the following ways: uploaded, rejected by

-// the server, rejected by the client due to metering, or failed for other

-// reasons, such as the sender could not communicate with the crash server.

-

-// In process crash reporting metrics.

-DECLARE_METRIC_count(crashes_total);

-DECLARE_METRIC_count(crashes_uploaded);

-DECLARE_METRIC_count(crashes_throttled);

-DECLARE_METRIC_count(crashes_rejected);

-DECLARE_METRIC_count(crashes_failed);

-

-// Out of process crash reporting metrics.

-// The number of crashes requested by the applications should be close to the

-// total number of crashes handled by Omaha.

-DECLARE_METRIC_count(oop_crashes_requested);

-DECLARE_METRIC_count(oop_crashes_total);

-DECLARE_METRIC_count(oop_crashes_uploaded);

-DECLARE_METRIC_count(oop_crashes_throttled);

-DECLARE_METRIC_count(oop_crashes_rejected);

-DECLARE_METRIC_count(oop_crashes_failed);

-

-// How many times StartCrashServer() was called.

-DECLARE_METRIC_count(crash_start_server_total);

-// How many times StartCrashServer() succeeded.

-DECLARE_METRIC_count(crash_start_server_succeeded);

-

-// How many times the Code Red check process was launched.

-DECLARE_METRIC_count(cr_process_total);

-// How many times the Code Red download callback was called.

-DECLARE_METRIC_count(cr_callback_total);

-// How many times the Code Red download callback received 200 - OK.

-DECLARE_METRIC_count(cr_callback_status_200);

-// How many times the Code Red download callback received 204 - no content.

-DECLARE_METRIC_count(cr_callback_status_204);

-// How many times the Code Red download callback received some other status.

-// Only incremented if DownloadFile() succeeded.

-DECLARE_METRIC_count(cr_callback_status_other);

-

-// How many times GoopdateImpl::LoadResourceDll() failed to load the resource

-// DLL. Does not include modes that do not need the DLL.

-DECLARE_METRIC_count(load_resource_dll_failed);

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_GOOPDATE_METRICS_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// Declares the usage metrics used by goopdate module.
+
+#ifndef OMAHA_GOOPDATE_GOOPDATE_METRICS_H_
+#define OMAHA_GOOPDATE_GOOPDATE_METRICS_H_
+
+#include "omaha/statsreport/metrics.h"
+
+namespace omaha {
+
+DECLARE_METRIC_integer(windows_major_version);
+DECLARE_METRIC_integer(windows_minor_version);
+DECLARE_METRIC_integer(windows_sp_major_version);
+DECLARE_METRIC_integer(windows_sp_minor_version);
+
+// How many times we received a user/machine legacy handoff from an Omaha 1.0.x
+// or 1.1.x metainstaller. These are determined early on in the handoff process
+// whereas the 1.0 and 1.1 metrics are not determined until the XML is parsed so
+// the version metrics may not sum up to the user/machine sum if errors occur.
+DECLARE_METRIC_count(handoff_legacy_user);
+DECLARE_METRIC_count(handoff_legacy_machine);
+// How many times we received a handoff from an Omaha 1.0.x metainstaller.
+DECLARE_METRIC_count(handoff_legacy_10);
+// How many times we received a handoff from an Omaha 1.1.x metainstaller.
+DECLARE_METRIC_count(handoff_legacy_11);
+
+// Crash metrics.
+//
+// A crash can be handled in one of the following ways: uploaded, rejected by
+// the server, rejected by the client due to metering, or failed for other
+// reasons, such as the sender could not communicate with the crash server.
+
+// In process crash reporting metrics.
+DECLARE_METRIC_count(crashes_total);
+DECLARE_METRIC_count(crashes_uploaded);
+DECLARE_METRIC_count(crashes_throttled);
+DECLARE_METRIC_count(crashes_rejected);
+DECLARE_METRIC_count(crashes_failed);
+
+// Out of process crash reporting metrics.
+// The number of crashes requested by the applications should be close to the
+// total number of crashes handled by Omaha.
+DECLARE_METRIC_count(oop_crashes_requested);
+DECLARE_METRIC_count(oop_crashes_total);
+DECLARE_METRIC_count(oop_crashes_uploaded);
+DECLARE_METRIC_count(oop_crashes_throttled);
+DECLARE_METRIC_count(oop_crashes_rejected);
+DECLARE_METRIC_count(oop_crashes_failed);
+
+// How many times StartCrashServer() was called.
+DECLARE_METRIC_count(crash_start_server_total);
+// How many times StartCrashServer() succeeded.
+DECLARE_METRIC_count(crash_start_server_succeeded);
+
+// How many times the Code Red check process was launched.
+DECLARE_METRIC_count(cr_process_total);
+// How many times the Code Red download callback was called.
+DECLARE_METRIC_count(cr_callback_total);
+// How many times the Code Red download callback received 200 - OK.
+DECLARE_METRIC_count(cr_callback_status_200);
+// How many times the Code Red download callback received 204 - no content.
+DECLARE_METRIC_count(cr_callback_status_204);
+// How many times the Code Red download callback received some other status.
+// Only incremented if DownloadFile() succeeded.
+DECLARE_METRIC_count(cr_callback_status_other);
+
+// How many times GoopdateImpl::LoadResourceDll() failed to load the resource
+// DLL. Does not include modes that do not need the DLL.
+DECLARE_METRIC_count(load_resource_dll_failed);
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_GOOPDATE_METRICS_H_
diff --git a/goopdate/goopdate_unittest.cc b/goopdate/goopdate_unittest.cc
index 360de84..97b82ef 100644
--- a/goopdate/goopdate_unittest.cc
+++ b/goopdate/goopdate_unittest.cc
@@ -1,656 +1,656 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/constants.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/goopdate/goopdate-internal.h"

-#include "omaha/testing/unit_test.h"

-

-namespace {

-

-const TCHAR* const kAppMachineClientStatePath =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{19BE47E4-CF32-48c1-94C4-046507F6A8A6}\\");

-const TCHAR* const kApp2MachineClientStatePath =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{553B2D8C-E6A7-43ed-ACC9-A8BA5D34395F}\\");

-const TCHAR* const kAppUserClientStatePath =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\")

-    _T("{19BE47E4-CF32-48c1-94C4-046507F6A8A6}\\");

-const TCHAR* const kApp2UserClientStatePath =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\")

-    _T("{553B2D8C-E6A7-43ed-ACC9-A8BA5D34395F}\\");

-

-const TCHAR* const kAppMachineClientStateMediumPath =

-    _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\")

-    _T("{19BE47E4-CF32-48c1-94C4-046507F6A8A6}\\");

-

-}  // namespace

-

-namespace omaha {

-

-class GoopdateRegistryProtectedTest : public testing::Test {

- protected:

-  GoopdateRegistryProtectedTest()

-      : hive_override_key_name_(kRegistryHiveOverrideRoot) {

-  }

-

-  CString hive_override_key_name_;

-

-  virtual void SetUp() {

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    OverrideRegistryHives(hive_override_key_name_);

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-  }

-};

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateKeyDoesNotExist_NoAppKeys) {

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateValueDoesNotExist_NoAppKeys) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateValueDoesNotExist_AppKeyNoValue) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateValueDoesNotExist_AppValueZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_NoAppKeys) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_EQ(S_FALSE, internal::PromoteAppEulaAccepted(true));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_AppKeyNoValue) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_AppValueZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_AppValueOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-}

-

-// Unfortunately, the app's ClientStateMedium key is not checked if there is no

-// corresponding ClientState key.

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_OnlyMediumAppValueOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  // The ClientStateMedium was not checked, so eulaaccepted = 0 still exists.

-  EXPECT_TRUE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(0, value);

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_MediumAppValueOneAndStateKey) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-}

-

-// The ClientStateMedium 1 is copied over the ClientState 0.

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_AppZeroAppMediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-}

-

-// The ClientStateMedium 0 is ignored and not copied.

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_AppOneAppMediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_FirstAppZeroSecondAppOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2MachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kApp2MachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_FirstAppNoValueSecondAppOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2MachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kApp2MachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-}

-

-// Asserts because this is an unexpected case.

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_UpdateClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  ExpectAsserts expect_asserts;

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateZero_UserAppOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppUserClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateOne_AppZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// The fact that the value is deleted also tells us that the method continued

-// processing because the value existed even though the value was not zero.

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_Machine_UpdateOne_AppOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));

-

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateKeyDoesNotExist_NoAppKeys) {

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateValueDoesNotExist_NoAppKeys) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateValueDoesNotExist_AppKeyNoValue) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateValueDoesNotExist_AppValueZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateZero_NoAppKeys) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_EQ(S_FALSE, internal::PromoteAppEulaAccepted(false));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateZero_AppKeyNoValue) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateZero_AppValueZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppUserClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateZero_FirstAppZeroSecondAppOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2UserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppUserClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kApp2UserClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateZero_FirstAppNoValueSecondAppOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2UserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kApp2UserClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-}

-

-// Asserts because this is an unexpected case.

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateZero_UpdateClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  ExpectAsserts expect_asserts;

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateOne_AppZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppUserClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// The fact that the value is deleted also tells us that the method continued

-// processing because the value existed even though the value was not zero.

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateOne_AppOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppUserClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-}

-

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateZero_MachineAppOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-}

-

-// ClientStateMedium is not used.

-TEST_F(GoopdateRegistryProtectedTest,

-       PromoteAppEulaAccepted_User_UpdateZero_MediumAppValueOneAndStateKey) {

-  const TCHAR* const kAppUserClientStateMediumPath =

-      _T("HKCU\\Software\\Google\\Update\\ClientStateMedium\\")

-      _T("{19BE47E4-CF32-48c1-94C4-046507F6A8A6}\\");

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));

-

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(0, value);

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    &value));

-  EXPECT_EQ(1, value);

-}

-

-}  // namespace omaha

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/constants.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/goopdate/goopdate-internal.h"
+#include "omaha/testing/unit_test.h"
+
+namespace {
+
+const TCHAR* const kAppMachineClientStatePath =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{19BE47E4-CF32-48c1-94C4-046507F6A8A6}\\");
+const TCHAR* const kApp2MachineClientStatePath =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{553B2D8C-E6A7-43ed-ACC9-A8BA5D34395F}\\");
+const TCHAR* const kAppUserClientStatePath =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\")
+    _T("{19BE47E4-CF32-48c1-94C4-046507F6A8A6}\\");
+const TCHAR* const kApp2UserClientStatePath =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\")
+    _T("{553B2D8C-E6A7-43ed-ACC9-A8BA5D34395F}\\");
+
+const TCHAR* const kAppMachineClientStateMediumPath =
+    _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\")
+    _T("{19BE47E4-CF32-48c1-94C4-046507F6A8A6}\\");
+
+}  // namespace
+
+namespace omaha {
+
+class GoopdateRegistryProtectedTest : public testing::Test {
+ protected:
+  GoopdateRegistryProtectedTest()
+      : hive_override_key_name_(kRegistryHiveOverrideRoot) {
+  }
+
+  CString hive_override_key_name_;
+
+  virtual void SetUp() {
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    OverrideRegistryHives(hive_override_key_name_);
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+  }
+};
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateKeyDoesNotExist_NoAppKeys) {
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateValueDoesNotExist_NoAppKeys) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateValueDoesNotExist_AppKeyNoValue) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateValueDoesNotExist_AppValueZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_NoAppKeys) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_EQ(S_FALSE, internal::PromoteAppEulaAccepted(true));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_AppKeyNoValue) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_AppValueZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_AppValueOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+}
+
+// Unfortunately, the app's ClientStateMedium key is not checked if there is no
+// corresponding ClientState key.
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_OnlyMediumAppValueOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  // The ClientStateMedium was not checked, so eulaaccepted = 0 still exists.
+  EXPECT_TRUE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(0, value);
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_MediumAppValueOneAndStateKey) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+}
+
+// The ClientStateMedium 1 is copied over the ClientState 0.
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_AppZeroAppMediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+}
+
+// The ClientStateMedium 0 is ignored and not copied.
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_AppOneAppMediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_FirstAppZeroSecondAppOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2MachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kApp2MachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_FirstAppNoValueSecondAppOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2MachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kApp2MachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+}
+
+// Asserts because this is an unexpected case.
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_UpdateClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  ExpectAsserts expect_asserts;
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateZero_UserAppOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppUserClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateOne_AppZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// The fact that the value is deleted also tells us that the method continued
+// processing because the value existed even though the value was not zero.
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_Machine_UpdateOne_AppOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(true));
+
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateKeyDoesNotExist_NoAppKeys) {
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateValueDoesNotExist_NoAppKeys) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateValueDoesNotExist_AppKeyNoValue) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateValueDoesNotExist_AppValueZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateZero_NoAppKeys) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_EQ(S_FALSE, internal::PromoteAppEulaAccepted(false));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateZero_AppKeyNoValue) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateZero_AppValueZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppUserClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateZero_FirstAppZeroSecondAppOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2UserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppUserClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kApp2UserClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateZero_FirstAppNoValueSecondAppOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2UserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kApp2UserClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+}
+
+// Asserts because this is an unexpected case.
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateZero_UpdateClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  ExpectAsserts expect_asserts;
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateOne_AppZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppUserClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// The fact that the value is deleted also tells us that the method continued
+// processing because the value existed even though the value was not zero.
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateOne_AppOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppUserClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+}
+
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateZero_MachineAppOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(kAppMachineClientStatePath, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+}
+
+// ClientStateMedium is not used.
+TEST_F(GoopdateRegistryProtectedTest,
+       PromoteAppEulaAccepted_User_UpdateZero_MediumAppValueOneAndStateKey) {
+  const TCHAR* const kAppUserClientStateMediumPath =
+      _T("HKCU\\Software\\Google\\Update\\ClientStateMedium\\")
+      _T("{19BE47E4-CF32-48c1-94C4-046507F6A8A6}\\");
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(internal::PromoteAppEulaAccepted(false));
+
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(0, value);
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    &value));
+  EXPECT_EQ(1, value);
+}
+
+}  // namespace omaha
diff --git a/goopdate/goopdate_utils-internal.h b/goopdate/goopdate_utils-internal.h
index bd40b81..049977c 100644
--- a/goopdate/goopdate_utils-internal.h
+++ b/goopdate/goopdate_utils-internal.h
@@ -1,63 +1,63 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_GOOPDATE_UTILS_INTERNAL_H__

-#define OMAHA_GOOPDATE_GOOPDATE_UTILS_INTERNAL_H__

-

-namespace omaha {

-

-namespace goopdate_utils {

-

-namespace internal {

-

-// Installs a scheduled task. The task will run as either as SYSTEM or the

-// current user. The task will be triggered at each user logon, and/or

-// fixed intervals.

-HRESULT InstallScheduledTask(const TCHAR* task_name,

-                             const TCHAR* task_path,

-                             const TCHAR* task_parameters,

-                             const TCHAR* task_comment,

-                             bool is_machine,

-                             bool create_logon_trigger,

-                             bool create_daily_trigger,

-                             bool create_hourly_trigger);

-

-// Deletes a scheduled task.

-HRESULT UninstallScheduledTask(const TCHAR* task_name);

-

-// Deletes all scheduled tasks with the given prefix.

-HRESULT UninstallScheduledTasks(const TCHAR* task_prefix);

-

-// Runs a scheduled task immediately.

-HRESULT StartScheduledTask(const TCHAR* task_name);

-

-// Returns true if the scheduled task exists.

-bool IsInstalledScheduledTask(const TCHAR* task_name);

-

-// Returns a status code on success. List of status codes at

-// http://msdn2.microsoft.com/en-us/library/aa381263.aspx

-HRESULT GetScheduledTaskStatus(const TCHAR* task_name);

-

-// Stops the task if it is already running.

-HRESULT StopScheduledTask(const TCHAR* task_name);

-

-}  // namespace internal

-

-}  // namespace goopdate_utils

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_GOOPDATE_UTILS_INTERNAL_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_GOOPDATE_UTILS_INTERNAL_H__
+#define OMAHA_GOOPDATE_GOOPDATE_UTILS_INTERNAL_H__
+
+namespace omaha {
+
+namespace goopdate_utils {
+
+namespace internal {
+
+// Installs a scheduled task. The task will run as either as SYSTEM or the
+// current user. The task will be triggered at each user logon, and/or
+// fixed intervals.
+HRESULT InstallScheduledTask(const TCHAR* task_name,
+                             const TCHAR* task_path,
+                             const TCHAR* task_parameters,
+                             const TCHAR* task_comment,
+                             bool is_machine,
+                             bool create_logon_trigger,
+                             bool create_daily_trigger,
+                             bool create_hourly_trigger);
+
+// Deletes a scheduled task.
+HRESULT UninstallScheduledTask(const TCHAR* task_name);
+
+// Deletes all scheduled tasks with the given prefix.
+HRESULT UninstallScheduledTasks(const TCHAR* task_prefix);
+
+// Runs a scheduled task immediately.
+HRESULT StartScheduledTask(const TCHAR* task_name);
+
+// Returns true if the scheduled task exists.
+bool IsInstalledScheduledTask(const TCHAR* task_name);
+
+// Returns a status code on success. List of status codes at
+// http://msdn2.microsoft.com/en-us/library/aa381263.aspx
+HRESULT GetScheduledTaskStatus(const TCHAR* task_name);
+
+// Stops the task if it is already running.
+HRESULT StopScheduledTask(const TCHAR* task_name);
+
+}  // namespace internal
+
+}  // namespace goopdate_utils
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_GOOPDATE_UTILS_INTERNAL_H__
+
diff --git a/goopdate/goopdate_utils.cc b/goopdate/goopdate_utils.cc
index a11e78a..e7f40d7 100644
--- a/goopdate/goopdate_utils.cc
+++ b/goopdate/goopdate_utils.cc
@@ -1,2973 +1,2973 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines: GoopdateUtils, helper functions for goopdate.

-

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/goopdate_utils-internal.h"

-

-#include <windows.h>

-#include <corerror.h>

-#include <lmcons.h>

-#include <atlpath.h>

-#include <atlsecurity.h>

-#include <map>

-#include <utility>

-#include <vector>

-#include "omaha/common/app_util.h"

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/const_utils.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/path.h"

-#include "omaha/common/proc_utils.h"

-#include "omaha/common/process.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/scoped_impersonation.h"

-#include "omaha/common/scoped_ptr_cotask.h"

-#include "omaha/common/service_utils.h"

-#include "omaha/common/shell.h"

-#include "omaha/common/signatures.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/time.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/common/vista_utils.h"

-#include "omaha/common/window_utils.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/event_logger.h"

-#include "omaha/goopdate/goopdate_xml_parser.h"

-#include "omaha/goopdate/resources/goopdateres/goopdate.grh"

-#include "omaha/goopdate/stats_uploader.h"

-#include "omaha/goopdate/update_response.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/network_request.h"

-

-// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".

-#include "goopdate/google_update_idl.h"

-// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".

-#include "goopdate/google_update_idl_i.c"

-

-namespace omaha {

-

-namespace goopdate_utils {

-

-namespace {

-

-const int kApplicationGuidOffset = 38;

-const int kTerminateBrowserTimeoutMs = 60000;

-

-const TCHAR* const kTrue = _T("true");

-const TCHAR* const kFalse = _T("false");

-

-// Query element name-value pair.

-typedef std::pair<CString, CString> QueryElement;

-

-// Builds a query string from the provided name-value pairs.

-// The string begins with a '&' and ends with the last value.

-// query must be empty.

-HRESULT BuildQueryString(const std::vector<QueryElement>& elements,

-                         CString* query) {

-  ASSERT1(query);

-

-  if (elements.empty() || !query->IsEmpty()) {

-    return E_INVALIDARG;

-  }

-

-  for (size_t i = 0; i < elements.size(); ++i) {

-    CString escaped_str;

-    HRESULT hr = StringEscape(elements[i].second, false, &escaped_str);

-    if (FAILED(hr)) {

-      CORE_LOG(LEVEL_WARNING, (_T("[StringEscape failed][0x%08x]"), hr));

-      return hr;

-    }

-

-    CString element;

-    element.Format(_T("%s%=%s&"), elements[i].first, escaped_str);

-    query->Append(element);

-  }

-

-  ASSERT1(!query->IsEmpty());

-  if (_T('&') == query->GetAt(query->GetLength() - 1)) {

-    query->Truncate(query->GetLength() - 1);

-  }

-

-  return S_OK;

-}

-

-bool IsMachineProcessWithoutPrivileges(bool is_machine_process) {

-  return is_machine_process && !vista_util::IsUserAdmin();

-}

-

-HRESULT LaunchImpersonatedCmdLine(const CString& cmd_line) {

-  scoped_handle impersonation_token;

-  HRESULT hr = vista::GetLoggedOnUserToken(address(impersonation_token));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  scoped_impersonation impersonate_user(get(impersonation_token));

-  hr = HRESULT_FROM_WIN32(impersonate_user.result());

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CComPtr<IProcessLauncher> launcher;

-  hr = launcher.CoCreateInstance(CLSID_ProcessLauncherClass,

-                                 NULL,

-                                 CLSCTX_LOCAL_SERVER);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return launcher->LaunchCmdLine(cmd_line);

-}

-

-HRESULT LaunchImpersonatedBrowser(BrowserType type, const CString& url) {

-  scoped_handle impersonation_token;

-  HRESULT hr = vista::GetLoggedOnUserToken(address(impersonation_token));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  scoped_impersonation impersonate_user(get(impersonation_token));

-  hr = HRESULT_FROM_WIN32(impersonate_user.result());

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CComPtr<IProcessLauncher> launcher;

-  hr = launcher.CoCreateInstance(CLSID_ProcessLauncherClass,

-                                 NULL,

-                                 CLSCTX_LOCAL_SERVER);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return launcher->LaunchBrowser(type, url);

-}

-

-// Returns an ID stored in the key_name hive with the name value_name.

-// Creates the ID in this location if it does not already exist.

-// During OEM installs, deletes any existing ID and returns a special value.

-// IsOemInstalling needs to know whether this is a machine instance but this

-// method does not know. Therefore, we use key_name. This isn't perfect, but

-// the worst that can happen is that the special value is returned for the

-// machine ID in a user instance when in "OEM mode". User instances shouldn't

-// be running in user mode, so this should never happen.

-// Ideally, we would use !CanUseNetwork instead, but this requires knowing the

-// actual value of is_machine.

-CString CreatePersistentId(const CString& key_name,

-                           const CString& value_name) {

-  const bool oem_installing_is_machine = MACHINE_KEY_NAME == key_name;

-  if (ConfigManager::Instance()->IsOemInstalling(oem_installing_is_machine)) {

-    const CString key_path = AppendRegKeyPath(key_name, GOOPDATE_MAIN_KEY);

-    RegKey::DeleteValue(key_path, value_name);

-    return _T("{00000000-03AA-03AA-03AA-000000000000}");

-  }

-

-  CString id;

-  if (SUCCEEDED(ReadPersistentId(key_name, value_name, &id))) {

-    return id;

-  }

-

-  GUID guid = GUID_NULL;

-  RegKey update_key;

-  const CString key_path = AppendRegKeyPath(key_name, GOOPDATE_MAIN_KEY);

-  if (SUCCEEDED(::CoCreateGuid(&guid))) {

-    const int guid_len = kApplicationGuidOffset;

-    TCHAR guid_string[guid_len + 1] = { _T('\0') };

-    if (::StringFromGUID2(guid, guid_string, guid_len + 1) > 0) {

-      if (SUCCEEDED(update_key.Create(key_path))) {

-        if (SUCCEEDED(update_key.SetValue(value_name, guid_string))) {

-          id = guid_string;

-        }

-      }

-    }

-  }

-  return id;

-}

-

-}  // namespace

-

-namespace internal {

-

-bool IsInstalledScheduledTask(const TCHAR* task_name) {

-  ASSERT1(task_name && *task_name);

-

-  CComPtr<ITaskScheduler> scheduler;

-  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                          NULL,

-                                          CLSCTX_INPROC_SERVER);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));

-    return false;

-  }

-

-  CComPtr<ITask> task;

-  hr = scheduler->Activate(task_name,

-                           __uuidof(ITask),

-                           reinterpret_cast<IUnknown**>(&task));

-

-  CORE_LOG(L3, (_T("[IsInstalledScheduledTask returned][0x%x]"), hr));

-  return COR_E_FILENOTFOUND == hr ? false : true;

-}

-

-HRESULT GetScheduledTaskStatus(const TCHAR* task_name) {

-  ASSERT1(task_name && *task_name);

-

-  CComPtr<ITaskScheduler> scheduler;

-  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                          NULL,

-                                          CLSCTX_INPROC_SERVER);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));

-    return hr;

-  }

-

-  CComPtr<ITask> task;

-  hr = scheduler->Activate(task_name,

-                           __uuidof(ITask),

-                           reinterpret_cast<IUnknown**>(&task));

-

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[GetScheduledTaskStatus: Activate failed][0x%x]"), hr));

-    return hr;

-  }

-

-  HRESULT task_status(S_OK);

-  hr = task->GetStatus(&task_status);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITask.GetStatus failed 0x%x"), hr));

-    return hr;

-  }

-

-  return task_status;

-}

-

-HRESULT GetScheduledTaskExitCode(const TCHAR* task_name) {

-  ASSERT1(task_name && *task_name);

-

-  CComPtr<ITaskScheduler> scheduler;

-  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                          NULL,

-                                          CLSCTX_INPROC_SERVER);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));

-    return hr;

-  }

-

-  CComPtr<ITask> task;

-  hr = scheduler->Activate(task_name,

-                           __uuidof(ITask),

-                           reinterpret_cast<IUnknown**>(&task));

-

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ITask.Activate failed][0x%x]"), hr));

-    return hr;

-  }

-

-  DWORD exit_code(0);

-  hr = task->GetExitCode(&exit_code);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("ITask.GetExitCode failed 0x%x"), hr));

-    return hr;

-  }

-

-  return hr == SCHED_S_TASK_HAS_NOT_RUN ? hr : exit_code;

-}

-

-HRESULT StartScheduledTask(const TCHAR* task_name) {

-  ASSERT1(task_name && *task_name);

-

-  if (GetScheduledTaskStatus(task_name) == SCHED_S_TASK_RUNNING) {

-    return S_OK;

-  }

-

-  CComPtr<ITaskScheduler> scheduler;

-  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                          NULL,

-                                          CLSCTX_INPROC_SERVER);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));

-    return hr;

-  }

-

-  CComPtr<ITask> task;

-  hr = scheduler->Activate(task_name,

-                           __uuidof(ITask),

-                           reinterpret_cast<IUnknown**>(&task));

-

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.Activate failed 0x%x"), hr));

-    return hr;

-  }

-

-  hr = task->Run();

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITask.Run failed 0x%x"), hr));

-    return hr;

-  }

-

-  return hr;

-}

-

-HRESULT StopScheduledTask(const TCHAR* task_name) {

-  ASSERT1(task_name && *task_name);

-

-  if (GetScheduledTaskStatus(task_name) != SCHED_S_TASK_RUNNING) {

-    return S_OK;

-  }

-

-  CComPtr<ITaskScheduler> scheduler;

-  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                          NULL,

-                                          CLSCTX_INPROC_SERVER);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));

-    return hr;

-  }

-

-  CComPtr<ITask> task;

-  hr = scheduler->Activate(task_name,

-                           __uuidof(ITask),

-                           reinterpret_cast<IUnknown**>(&task));

-

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.Activate failed 0x%x"), hr));

-    return hr;

-  }

-

-  hr = task->Terminate();

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITask.Run failed 0x%x"), hr));

-    return hr;

-  }

-

-  return hr;

-}

-

-HRESULT CreateLogonTrigger(ITask* task) {

-  ASSERT1(task);

-

-  CComPtr<ITaskTrigger> trigger;

-  WORD index = 0;

-

-  // Create a trigger to run on every user logon.

-  HRESULT hr = task->CreateTrigger(&index, &trigger);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITask.CreateTrigger failed 0x%x"), hr));

-    return hr;

-  }

-

-  TASK_TRIGGER trigger_config = {0};

-  trigger_config.cbTriggerSize = sizeof(trigger_config);

-  // These are required parameters. A past start date is good.

-  trigger_config.wBeginDay = 1;

-  trigger_config.wBeginMonth = 1;

-  trigger_config.wBeginYear = 1999;

-

-  // Run on every user logon.

-  trigger_config.TriggerType = TASK_EVENT_TRIGGER_AT_LOGON;

-

-  hr = trigger->SetTrigger(&trigger_config);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskTrigger.SetTrigger failed 0x%x"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT CreatePeriodicTrigger(ITask* task, bool create_hourly_trigger) {

-  ASSERT1(task);

-

-  CComPtr<ITaskTrigger> trigger;

-  WORD index = 0;

-

-  // Create a trigger to run every day.

-  HRESULT hr = task->CreateTrigger(&index, &trigger);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITask.CreateTrigger failed 0x%x"), hr));

-    return hr;

-  }

-

-  // Start time set to 5 minutes from the current time.

-  time64 start_time = GetCurrent100NSTime() + (5 * kMinsTo100ns);

-  SYSTEMTIME sys_time = Time64ToSystemTime(start_time);

-  SYSTEMTIME locale_time = {0};

-  hr = SystemTimeToTzSpecificLocalTime(NULL, &sys_time, &locale_time);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("SystemTimeToTzSpecificLocalTime failed 0x%x"), hr));

-    return hr;

-  }

-

-  TASK_TRIGGER trigger_config = {0};

-  trigger_config.cbTriggerSize = sizeof(trigger_config);

-  trigger_config.wBeginYear = locale_time.wYear;

-  trigger_config.wBeginMonth = locale_time.wMonth;

-  trigger_config.wBeginDay = locale_time.wDay;

-  trigger_config.wStartHour = locale_time.wHour;

-  trigger_config.wStartMinute = locale_time.wMinute;

-

-  trigger_config.TriggerType = TASK_TIME_TRIGGER_DAILY;

-  trigger_config.Type.Daily.DaysInterval = 1;  // every 1 day

-

-  if (create_hourly_trigger) {

-    // The task will be run daily at 24 hour intervals. And the task will be

-    // repeated every au_timer_interval_minutes within a single 24 hour

-    // interval.

-    const DWORD kTaskTrigger24HoursDuration = 24 * 60;

-    int au_timer_interval_minutes =

-        ConfigManager::Instance()->GetAutoUpdateTimerIntervalMs() / (60 * 1000);

-    ASSERT1(au_timer_interval_minutes > 0 &&

-            au_timer_interval_minutes < kTaskTrigger24HoursDuration);

-

-    trigger_config.MinutesDuration = kTaskTrigger24HoursDuration;

-    trigger_config.MinutesInterval = au_timer_interval_minutes;

-  }

-

-  hr = trigger->SetTrigger(&trigger_config);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskTrigger.SetTrigger failed 0x%x"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT CreateScheduledTask(ITask* task,

-                            const TCHAR* task_path,

-                            const TCHAR* task_parameters,

-                            const TCHAR* task_comment,

-                            bool is_machine,

-                            bool create_logon_trigger,

-                            bool create_daily_trigger,

-                            bool create_hourly_trigger) {

-  ASSERT1(task);

-  ASSERT1(task_path && *task_path);

-  ASSERT1(task_parameters);

-  ASSERT1(task_comment && *task_comment);

-  ASSERT1(create_logon_trigger || create_daily_trigger);

-  ASSERT1(!create_logon_trigger || (create_logon_trigger && is_machine));

-  ASSERT1(!create_hourly_trigger ||

-          (create_hourly_trigger && create_daily_trigger));

-

-  CORE_LOG(L3, (_T("CreateScheduledTask[%s][%s][%d]"),

-                task_path, task_parameters, is_machine));

-

-  HRESULT hr = task->SetApplicationName(task_path);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITask.SetApplicationName failed 0x%x"), hr));

-    return hr;

-  }

-

-  hr = task->SetParameters(task_parameters);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITask.SetParameters failed 0x%x"), hr));

-    return hr;

-  }

-

-  hr = task->SetComment(task_comment);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITask.SetComment failed 0x%x"), hr));

-    return hr;

-  }

-

-  if (is_machine) {

-    // Run using SYSTEM credentials, by passing in an empty username string.

-    hr = task->SetAccountInformation(_T(""), NULL);

-  } else {

-    // Run as current user.

-    // For the user task, we set TASK_FLAG_RUN_ONLY_IF_LOGGED_ON, so that we do

-    // not need the user password for task creation.

-    hr = task->SetFlags(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON);

-    if (FAILED(hr)) {

-      ASSERT(false, (_T("ITask.SetFlags failed 0x%x"), hr));

-      return hr;

-    }

-

-    CString user_name;

-    DWORD buffer_size = UNLEN + 1;

-    if (!::GetUserName(CStrBuf(user_name, buffer_size), &buffer_size)) {

-      hr = HRESULTFromLastError();

-      ASSERT(false, (_T("::GetUserName failed 0x%x"), hr));

-      return hr;

-    }

-    hr = task->SetAccountInformation(user_name, NULL);

-  }

-

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITask.SetAccountInformation failed 0x%x"), hr));

-    return hr;

-  }

-

-  // The default is to run for a finite number of days. We want to run

-  // indefinitely.

-  // Due to a bug introduced in Vista, and propogated to Windows 7, setting the

-  // MaxRunTime to INFINITE results in the task only running for 72 hours. For

-  // these operating systems, setting the RunTime to "INFINITE - 1" gets the

-  // desired behavior of allowing an "infinite" run of the task.

-  DWORD max_time = INFINITE - (SystemInfo::IsRunningOnVistaOrLater() ? 1 : 0);

-  hr = task->SetMaxRunTime(max_time);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITask.SetMaxRunTime failed 0x%x"), hr));

-    return hr;

-  }

-

-  CComPtr<ITaskTrigger> trigger;

-  WORD index = 0;

-

-  if (create_logon_trigger && is_machine) {

-    // Create a trigger to run on every user logon. Non-admin users are not able

-    // to create logon triggers, so we create only for machine.

-    hr = CreateLogonTrigger(task);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  if (create_daily_trigger) {

-    hr = CreatePeriodicTrigger(task, create_hourly_trigger);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  // Save task.

-  CComQIPtr<IPersistFile> persist(task);

-  if (!persist) {

-    hr = E_NOINTERFACE;

-    ASSERT(false, (_T("ITask.QueryInterface IPersistFile failed 0x%x"), hr));

-    return hr;

-  }

-

-  hr = persist->Save(NULL, TRUE);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("IPersistFile.Save failed 0x%x"), hr));

-    return hr;

-  }

-

-  if (is_machine) {

-    return S_OK;

-  }

-

-  // Adjust privileges to explicitly allow the current user to be able to

-  // manipulate this task. User applications, and consequently, Omaha, can be

-  // installed in an elevated mode. This can happen, for instance, if the user

-  // installs on XP, then upgrades to Vista. Or chooses "Run as Administrator"

-  // when running the meta-installer on Vista. Subsequently, Omaha running at

-  // medium integrity needs to be able to manipulate the installed task.

-  scoped_ptr_cotask<OLECHAR> job_file;

-  hr = persist->GetCurFile(address(job_file));

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("IPersistFile.GetCurFile failed 0x%x"), hr));

-    return hr;

-  }

-

-  persist.Release();

-

-  CAccessToken token;

-  CSid current_sid;

-  if (!token.GetEffectiveToken(TOKEN_QUERY) || !token.GetUser(&current_sid)) {

-    hr = HRESULTFromLastError();

-    ASSERT(false, (_T("[Failed to get current user sid[0x%x]"), hr));

-    return hr;

-  }

-

-  hr = AddAllowedAce(job_file.get(),

-                     SE_FILE_OBJECT,

-                     current_sid,

-                     FILE_ALL_ACCESS,

-                     0);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("Could not adjust DACL[%s][0x%x]"), job_file.get(), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT UpgradeScheduledTask(const TCHAR* task_name,

-                             const TCHAR* task_path,

-                             const TCHAR* task_parameters,

-                             const TCHAR* task_comment,

-                             bool is_machine,

-                             bool create_logon_trigger,

-                             bool create_daily_trigger,

-                             bool create_hourly_trigger) {

-  ASSERT1(task_name && *task_name);

-  ASSERT1(IsInstalledScheduledTask(task_name));

-

-  CORE_LOG(L3, (_T("UpgradeScheduledTask[%s][%s][%s][%d]"),

-                task_name, task_path, task_parameters, is_machine));

-

-  // TODO(Omaha): Perhaps pass the ITaskScheduler around where possible.

-  CComPtr<ITaskScheduler> scheduler;

-  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                          NULL,

-                                          CLSCTX_INPROC_SERVER);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));

-    return hr;

-  }

-

-  CComPtr<ITask> task;

-  hr = scheduler->Activate(task_name,

-                           __uuidof(ITask),

-                           reinterpret_cast<IUnknown**>(&task));

-

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("UpgradeScheduledTask: Activate failed[0x%x]"), hr));

-    return hr;

-  }

-

-  // Delete existing triggers. CreateScheduledTask() will recreate them anew.

-  WORD trigger_count(0);

-  hr = task->GetTriggerCount(&trigger_count);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.GetTriggerCount failed 0x%x"), hr));

-    return hr;

-  }

-

-  for (int i = 0; i < trigger_count; ++i) {

-    hr = task->DeleteTrigger(0);

-    if (FAILED(hr)) {

-      ASSERT(false, (_T("ITaskScheduler.DeleteTrigger failed 0x%x"), hr));

-      return hr;

-    }

-  }

-

-  return CreateScheduledTask(task,

-                             task_path,

-                             task_parameters,

-                             task_comment,

-                             is_machine,

-                             create_logon_trigger,

-                             create_daily_trigger,

-                             create_hourly_trigger);

-}

-

-// TODO(Omaha): Change the apis to avoid specifying hourly and daily triggers.

-HRESULT InstallScheduledTask(const TCHAR* task_name,

-                             const TCHAR* task_path,

-                             const TCHAR* task_parameters,

-                             const TCHAR* task_comment,

-                             bool is_machine,

-                             bool create_logon_trigger,

-                             bool create_daily_trigger,

-                             bool create_hourly_trigger) {

-  if (IsInstalledScheduledTask(task_name)) {

-    return UpgradeScheduledTask(task_name,

-                                task_path,

-                                task_parameters,

-                                task_comment,

-                                is_machine,

-                                create_logon_trigger,

-                                create_daily_trigger,

-                                create_hourly_trigger);

-  }

-

-  CComPtr<ITaskScheduler> scheduler;

-  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                          NULL,

-                                          CLSCTX_INPROC_SERVER);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));

-    return hr;

-  }

-

-  CComPtr<ITask> task;

-  hr = scheduler->NewWorkItem(task_name,

-                              CLSID_CTask,

-                              __uuidof(ITask),

-                              reinterpret_cast<IUnknown**>(&task));

-

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.NewWorkItem failed 0x%x"), hr));

-    return hr;

-  }

-

-  return CreateScheduledTask(task,

-                             task_path,

-                             task_parameters,

-                             task_comment,

-                             is_machine,

-                             create_logon_trigger,

-                             create_daily_trigger,

-                             create_hourly_trigger);

-}

-

-HRESULT UninstallScheduledTask(const TCHAR* task_name) {

-  ASSERT1(task_name && *task_name);

-

-  CComPtr<ITaskScheduler> scheduler;

-  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                          NULL,

-                                          CLSCTX_INPROC_SERVER);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));

-    return hr;

-  }

-

-  // Stop the task before deleting it. Ignore return value.

-  VERIFY1(SUCCEEDED(StopScheduledTask(task_name)));

-

-  // delete the task.

-  hr = scheduler->Delete(task_name);

-  if (FAILED(hr) && COR_E_FILENOTFOUND != hr) {

-    CORE_LOG(LE, (_T("GetScheduledTaskStatus: Delete failed[0x%x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT UninstallScheduledTasks(const TCHAR* task_prefix) {

-  ASSERT1(task_prefix && *task_prefix);

-

-  CComPtr<ITaskScheduler> scheduler;

-  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                          NULL,

-                                          CLSCTX_INPROC_SERVER);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));

-    return hr;

-  }

-

-  CComPtr<IEnumWorkItems> enum_items;

-  hr = scheduler->Enum(&enum_items);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("ITaskScheduler.Enum failed 0x%x"), hr));

-    return hr;

-  }

-

-  TCHAR** task_names = NULL;

-  DWORD task_count = 0;

-  while (enum_items->Next(1, &task_names, &task_count) == S_OK) {

-    ASSERT1(task_count == 1);

-    scoped_co_task_ptr task_names_guard(task_names);

-    scoped_co_task_ptr task_name_guard(task_names[0]);

-

-    if (String_StartsWith(task_names[0], task_prefix, true)) {

-      UninstallScheduledTask(task_names[0]);

-    }

-  }

-

-  return S_OK;

-}

-

-// Returns the task name Omaha used to install in Omaha 1.2.x.

-CString GetOmaha1LegacyTaskName(bool is_machine) {

-  const TCHAR* const kLegacyOmaha1TaskNameMachine = _T("GoogleUpdateTask");

-  const TCHAR* const kLegacyOmaha1TaskNameUser = _T("GoogleUpdateTaskUser");

-  return is_machine ? kLegacyOmaha1TaskNameMachine : kLegacyOmaha1TaskNameUser;

-}

-

-// Returns the task name Omaha used to install in Omaha 2 before the

-// "GoogleUpdate.exe does not run all the time" refactoring.

-CString GetOmaha2LegacyTaskName(bool is_machine) {

-  const TCHAR* kLegacyOmaha2TaskNameUserPrefix = _T("GoogleUpdateTaskUser");

-  const TCHAR* kLegacyOmaha2TaskNameMachine = _T("GoogleUpdateTaskMachine");

-  if (is_machine) {

-    return kLegacyOmaha2TaskNameMachine;

-  }

-

-  CString task_name_user = kLegacyOmaha2TaskNameUserPrefix;

-  CString user_sid;

-  VERIFY1(SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid)));

-  task_name_user += user_sid;

-  return task_name_user;

-}

-

-}  // namespace internal

-

-CString GetAppClientsKey(bool is_machine, const CString& app_guid) {

-  return AppendRegKeyPath(

-      ConfigManager::Instance()->registry_clients(is_machine),

-      app_guid);

-}

-

-CString GetAppClientStateKey(bool is_machine, const CString& app_guid) {

-  return AppendRegKeyPath(

-      ConfigManager::Instance()->registry_client_state(is_machine),

-      app_guid);

-}

-

-CString GetAppClientStateMediumKey(bool is_machine, const CString& app_guid) {

-  ASSERT1(is_machine);

-  UNREFERENCED_PARAMETER(is_machine);

-  return AppendRegKeyPath(

-      ConfigManager::Instance()->machine_registry_client_state_medium(),

-      app_guid);

-}

-

-// Returns the application registration location given the user SID.

-CString GetUserAllAppsStatePath(const CString& user_sid) {

-  return AppendRegKeyPath(USERS_KEY, user_sid,

-                          GOOPDATE_REG_RELATIVE_CLIENT_STATE);

-}

-

-// Returns the application state path for a user given the user SID.

-CString GetUserAllAppsRegPath(const CString& user_sid) {

-  return AppendRegKeyPath(USERS_KEY, user_sid, GOOPDATE_REG_RELATIVE_CLIENTS);

-}

-

-// Returns the application state path for a particular user and for the

-// given application id.

-CString GetUserAppStatePath(const CString& user_sid,

-                            const CString& app_guid) {

-  return AppendRegKeyPath(GetUserAllAppsStatePath(user_sid), app_guid);

-}

-

-// Returns the application registrration path for a particular user

-// and for the given application id.

-CString GetUserAppRegPath(const CString& user_sid,

-                          const CString& app_guid) {

-  return AppendRegKeyPath(GetUserAllAppsRegPath(user_sid), app_guid);

-}

-

-CString BuildGoogleUpdateExeDir(bool is_machine) {

-  ConfigManager& cm = *ConfigManager::Instance();

-  return is_machine ? cm.GetMachineGoopdateInstallDir() :

-                      cm.GetUserGoopdateInstallDir();

-}

-

-CString BuildGoogleUpdateExePath(bool is_machine) {

-  CORE_LOG(L3, (_T("[BuildGoogleUpdateExePath][%d]"), is_machine));

-

-  CPath full_file_path(BuildGoogleUpdateExeDir(is_machine));

-  VERIFY1(full_file_path.Append(kGoopdateFileName));

-

-  return full_file_path;

-}

-

-CString BuildGoogleUpdateServicesPath(bool is_machine) {

-  CORE_LOG(L3, (_T("[BuildGoogleUpdateServicesPath][%d]"), is_machine));

-

-  CPath full_file_path(

-      goopdate_utils::BuildInstallDirectory(is_machine, GetVersionString()));

-  VERIFY1(full_file_path.Append(kGoopdateCrashHandlerFileName));

-

-  return full_file_path;

-}

-

-HRESULT StartElevatedSelfWithArgsAndWait(const TCHAR* args) {

-  ASSERT1(args);

-  CORE_LOG(L3, (_T("[StartElevatedSelfWithArgsAndWait]")));

-

-  // Get the process executable.

-  TCHAR filename[MAX_PATH] = {0};

-  if (::GetModuleFileName(NULL, filename, MAX_PATH) == 0) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LEVEL_ERROR, (_T("[GetModuleFileName failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Launch self elevated and wait.

-  DWORD exit_code = 0;

-  CORE_LOG(L1,

-      (_T("[RunElevated filename='%s'][arguments='%s']"), filename, args));

-  // According to the MSDN documentation for ::ShowWindow: "nCmdShow. This

-  // parameter is ignored the first time an application calls ShowWindow, if

-  // the program that launched the application provides a STARTUPINFO

-  // structure.". We want to force showing the UI window. So we pass in

-  // SW_SHOWNORMAL.

-  HRESULT hr = vista_util::RunElevated(filename,

-                                       args,

-                                       SW_SHOWNORMAL,

-                                       &exit_code);

-  CORE_LOG(L2, (_T("[elevated instance exit code][%u]"), exit_code));

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_ERROR, (_T("[RunElevated failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT StartGoogleUpdateWithArgs(bool is_machine,

-                                  const TCHAR* args,

-                                  HANDLE* process) {

-  CORE_LOG(L3, (_T("[StartGoogleUpdateWithArgs][%d][%s]"),

-                is_machine, args ? args : _T("")));

-

-  CString exe_path = BuildGoogleUpdateExePath(is_machine);

-

-  CORE_LOG(L3, (_T("[command line][%s][%s]"), exe_path, args ? args : _T("")));

-

-  HRESULT hr = System::ShellExecuteProcess(exe_path, args, NULL, process);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[can't start process][%s][0x%08x]"), exe_path, hr));

-    return hr;

-  }

-  return S_OK;

-}

-

-bool IsRunningFromOfficialGoopdateDir(bool is_machine) {

-  const ConfigManager& cm = *ConfigManager::Instance();

-  bool is_official_dir = is_machine ?

-                         cm.IsRunningFromMachineGoopdateInstallDir() :

-                         cm.IsRunningFromUserGoopdateInstallDir();

-  CORE_LOG(L3, (_T("[running from official dir][%d]"), is_official_dir));

-  return is_official_dir;

-}

-

-CString GetHKRoot() {

-  return IsRunningFromOfficialGoopdateDir(true) ? _T("HKLM") : _T("HKCU");

-}

-

-HRESULT InitializeSecurity() {

-  // Creates a security descriptor in absolute format and includes the owner

-  // and the primary group.  We grant access to admins and system.

-  CSecurityDesc security_descriptor;

-  if (SystemInfo::IsRunningOnVistaOrLater()) {

-    // To allow for low-integrity IE to call into IGoogleUpdate.

-    security_descriptor.FromString(LOW_INTEGRITY_SDDL_SACL);

-  }

-  security_descriptor.SetOwner(Sids::Admins());

-  security_descriptor.SetGroup(Sids::Admins());

-  CDacl dacl;

-  dacl.AddAllowedAce(Sids::System(), COM_RIGHTS_EXECUTE);

-  dacl.AddAllowedAce(Sids::Admins(), COM_RIGHTS_EXECUTE);

-  dacl.AddAllowedAce(Sids::AuthenticatedUser(), COM_RIGHTS_EXECUTE);

-

-  security_descriptor.SetDacl(dacl);

-  security_descriptor.MakeAbsolute();

-

-  SECURITY_DESCRIPTOR* sd = const_cast<SECURITY_DESCRIPTOR*>(

-      security_descriptor.GetPSECURITY_DESCRIPTOR());

-

-  return ::CoInitializeSecurity(

-      sd,

-      -1,

-      NULL,   // Let COM choose what authentication services to register.

-      NULL,

-      RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  // Data integrity and encryption.

-      RPC_C_IMP_LEVEL_IDENTIFY,       // Only allow a server to identify.

-      NULL,

-      EOAC_DYNAMIC_CLOAKING | EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL,

-      NULL);

-}

-

-// This is only used for legacy handoff support.

-CString GetProductName(const CString& app_guid) {

-  const TCHAR* product_name = NULL;

-  const TCHAR gears_guid[]   = _T("{283EAF47-8817-4c2b-A801-AD1FADFB7BAA}");

-  const TCHAR google_talk_plugin[]  =

-      _T("{D0AB2EBC-931B-4013-9FEB-C9C4C2225C8C}");

-  const TCHAR youtube_uploader_guid[] =

-      _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}");

-

-  if (app_guid.CompareNoCase(gears_guid) == 0) {

-    product_name = _T("Gears");

-  } else if (app_guid.CompareNoCase(google_talk_plugin) == 0) {

-      product_name = _T("Google Talk Plugin");

-  } else if (app_guid.CompareNoCase(youtube_uploader_guid) == 0) {

-      product_name = _T("YouTube Uploader");

-  } else {

-      product_name = _T("Google App");

-  }

-  return product_name;

-}

-

-HRESULT ReadPersistentId(const CString& key_name,

-                         const CString& value_name,

-                         CString* id) {

-  ASSERT1(id);

-  CString key_path = AppendRegKeyPath(key_name, GOOPDATE_MAIN_KEY);

-  return RegKey::GetValue(key_path, value_name, id);

-}

-

-CString GetPersistentUserId(const CString& key_name) {

-  return CreatePersistentId(key_name, kRegValueUserId);

-}

-

-CString GetPersistentMachineId() {

-  return CreatePersistentId(MACHINE_KEY_NAME, kRegValueMachineId);

-}

-

-HRESULT BuildHttpGetString(const CString& url,

-                           DWORD error_code,

-                           DWORD extra_code1,

-                           DWORD extra_code2,

-                           const CString& app_guid,

-                           const CString& goopdate_version,

-                           bool is_machine,

-                           const CString& language,

-                           const CString& source_id,

-                           CString* get_request) {

-  ASSERT1(get_request);

-  if (url.IsEmpty()) {

-    return E_INVALIDARG;

-  }

-  ASSERT1(_T('?') == url.GetAt(url.GetLength() - 1) ||

-          _T('&') == url.GetAt(url.GetLength() - 1));

-

-  CString errorcode_str;

-  CString extracode1_str;

-  CString extracode2_str;

-  errorcode_str.Format(_T("0x%08x"), error_code);

-  extracode1_str.Format(_T("0x%08x"), extra_code1);

-  extracode2_str.Format(_T("%u"), extra_code2);

-

-  CString os_version;

-  CString service_pack;

-  HRESULT hr = GetOSInfo(&os_version, &service_pack);

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_WARNING, (_T("[GetOSInfo failed][0x%08x]"), hr));

-  }

-  CString mid = GetPersistentMachineId();

-  CString uid = GetPersistentUserId(is_machine ? MACHINE_KEY_NAME :

-                                                 USER_KEY_NAME);

-  CString iid;

-  CString state_key_name = GetAppClientStateKey(is_machine, app_guid);

-  // Ignore the return value because it may not exist.

-  RegKey::GetValue(state_key_name, kRegValueInstallationId, &iid);

-

-  std::vector<QueryElement> elements;

-  elements.push_back(QueryElement(_T("hl"), language));

-  elements.push_back(QueryElement(_T("errorcode"), errorcode_str));

-  elements.push_back(QueryElement(_T("extracode1"), extracode1_str));

-  elements.push_back(QueryElement(_T("extracode2"), extracode2_str));

-  elements.push_back(QueryElement(_T("app"), app_guid));

-  elements.push_back(QueryElement(_T("guver"), goopdate_version));

-  elements.push_back(QueryElement(_T("ismachine"),

-                                  is_machine ? _T("1") : _T("0")));

-  elements.push_back(QueryElement(_T("os"), os_version));

-  elements.push_back(QueryElement(_T("sp"), service_pack));

-  elements.push_back(QueryElement(_T("mid"), mid));

-  elements.push_back(QueryElement(_T("uid"), uid));

-  elements.push_back(QueryElement(_T("iid"), iid));

-  elements.push_back(QueryElement(_T("source"), source_id));

-

-  CString test_source = ConfigManager::Instance()->GetTestSource();

-  if (!test_source.IsEmpty()) {

-    elements.push_back(QueryElement(_T("testsource"), test_source));

-  }

-

-  CString query;

-  hr = BuildQueryString(elements, &query);

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_WARNING, (_T("[BuildQueryString failed][0x%08x]"), hr));

-    return hr;

-  }

-  get_request->Format(_T("%s%s"), url, query);

-

-  // The length should be smaller than the maximum allowed get length.

-  ASSERT1(get_request->GetLength() <= INTERNET_MAX_URL_LENGTH);

-  if (get_request->GetLength() > INTERNET_MAX_URL_LENGTH) {

-    return E_FAIL;

-  }

-

-  return S_OK;

-}

-

-HRESULT RedirectHKCR(bool is_machine) {

-  RegKey classes_key;

-  HRESULT hr = classes_key.Open(is_machine ?

-                                HKEY_LOCAL_MACHINE :

-                                HKEY_CURRENT_USER,

-                                _T("Software\\Classes"),

-                                KEY_ALL_ACCESS);

-  if (FAILED(hr)) {

-    ASSERT(FALSE, (_T("RedirectHKCR - key.Open(%d) fail %d"), is_machine, hr));

-    return hr;

-  }

-

-  LONG result = ::RegOverridePredefKey(HKEY_CLASSES_ROOT, classes_key.Key());

-  if (result != ERROR_SUCCESS) {

-    ASSERT(false, (_T("RedirectHKCR - RegOverridePredefKey fail %d"), result));

-    return HRESULT_FROM_WIN32(result);

-  }

-

-  return S_OK;

-}

-

-HRESULT RemoveRedirectHKCR() {

-  LONG result = ::RegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);

-  if (result != ERROR_SUCCESS) {

-    ASSERT(FALSE, (_T("RemoveRedirectHKCR - RegOverridePredefKey %d"), result));

-    return HRESULT_FROM_WIN32(result);

-  }

-

-  return S_OK;

-}

-

-HRESULT RegisterTypeLib(bool is_admin,

-                        const CComBSTR& path,

-                        ITypeLib* type_lib) {

-  // Typelib registration.

-  CORE_LOG(L3, (_T("[Registering TypeLib]")));

-  HRESULT hr = S_OK;

-  if (!is_admin &&

-      SUCCEEDED(goopdate_utils::RegisterTypeLibForUser(type_lib, path, NULL))) {

-    return S_OK;

-  }

-

-  // For Admin cases, we use ::RegisterTypeLib().

-  // For platforms where ::RegisterTypeLibForUser is not available, we register

-  // with ::RegisterTypeLib, and rely on HKCR=>HKCU redirection.

-  hr = ::RegisterTypeLib(type_lib, path, NULL);

-  ASSERT(SUCCEEDED(hr), (_T("[TypeLib registration failed][0x%08x]"), hr));

-  return hr;

-}

-

-HRESULT UnRegisterTypeLib(bool is_admin, const CComBSTR&, ITypeLib* type_lib) {

-  // Typelib unregistration.

-  CORE_LOG(L3, (_T("[Unregistering Typelib]")));

-  TLIBATTR* tlib_attr = NULL;

-  HRESULT hr = type_lib->GetLibAttr(&tlib_attr);

-  ASSERT(SUCCEEDED(hr), (_T("[GetLibAttr failed][0x%08x]"), hr));

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ON_SCOPE_EXIT_OBJ(*type_lib, &ITypeLib::ReleaseTLibAttr, tlib_attr);

-

-  if (!is_admin &&

-      SUCCEEDED(goopdate_utils::UnRegisterTypeLibForUser(

-          tlib_attr->guid,

-          tlib_attr->wMajorVerNum,

-          tlib_attr->wMinorVerNum,

-          tlib_attr->lcid,

-          tlib_attr->syskind))) {

-    return S_OK;

-  }

-

-  // For Admin cases, we use ::UnRegisterTypeLib().

-  // For platforms where ::UnRegisterTypeLibForUser is not available, we

-  // unregister with ::UnRegisterTypeLib, and rely on HKCR=>HKCU redirection.

-  hr = ::UnRegisterTypeLib(tlib_attr->guid,

-                           tlib_attr->wMajorVerNum,

-                           tlib_attr->wMinorVerNum,

-                           tlib_attr->lcid,

-                           tlib_attr->syskind);

-

-  // We assert before the check for TYPE_E_REGISTRYACCESS below because we want

-  // to catch the case where we're trying to unregister more than once because

-  // that would be a bug.

-  ASSERT(SUCCEEDED(hr),

-         (_T("[UnRegisterTypeLib failed.  ")

-          _T("This is likely a multiple unregister bug.][0x%08x]"), hr));

-

-  // If you try to unregister a type library that's already unregistered,

-  // it will return with this failure, which is OK.

-  if (hr == TYPE_E_REGISTRYACCESS) {

-    hr = S_OK;

-  }

-

-  return hr;

-}

-

-HRESULT RegisterOrUnregisterModule(bool register_server,

-                                   RegisterOrUnregisterFunction registrar) {

-  ASSERT1(registrar);

-

-  bool is_machine = IsRunningFromOfficialGoopdateDir(true);

-  // ATL by default registers the control to HKCR and we want to register

-  // either in HKLM, or in HKCU, depending on whether we are laying down

-  // the system googleupdate, or the user googleupdate.

-  // We solve this for the user goopdate case by:

-  // * Having the RGS file take a HKROOT parameter that translates to either

-  //   HKLM or HKCU.

-  // * Redirecting HKCR to HKCU\software\classes, for a user installation, to

-  //   cover Proxy registration.

-  // For the machine case, we still redirect HKCR to HKLM\\Software\\Classes,

-  // to ensure that Proxy registration happens in HKLM.

-  HRESULT hr = RedirectHKCR(is_machine);

-  ASSERT1(SUCCEEDED(hr));

-  if (FAILED(hr)) {

-    return hr;

-  }

-  // We need to stop redirecting at the end of this function.

-  ON_SCOPE_EXIT(RemoveRedirectHKCR);

-

-  hr = (*registrar)(register_server);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[RegisterOrUnregisterModule failed][%d][0x%08x]"),

-                  register_server, hr));

-    ASSERT1(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr && !register_server);

-  }

-

-  return hr;

-}

-

-HRESULT RegisterOrUnregisterModuleWithTypelib(

-    bool register_server,

-    RegisterOrUnregisterFunction registrar) {

-  ASSERT1(registrar);

-

-  bool is_machine = IsRunningFromOfficialGoopdateDir(true);

-  // By default, ATL registers the control to HKCR and we want to register

-  // either in HKLM, or in HKCU, depending on whether we are laying down

-  // the machine googleupdate, or the user googleupdate.

-  // We solve this for the user goopdate case by:

-  // * Having the RGS file take a HKROOT parameter that translates to either

-  //   HKLM or HKCU.

-  // * Redirecting HKCR to HKCU\software\classes, for a user installation, to

-  //   cover AppId and TypeLib registration

-  // * All the above makes ATL work correctly for 2K/XP. However on Win2K3

-  //   and Vista, redirection does not work by itself, because in these

-  //   platforms, RegisterTypeLib writes explicitly to HKLM\Software\Classes.

-  //   We need to specifically call the new RegisterTypeLibForUser() API.

-  //   So, we do that as well.

-  // For the machine case, we still redirect HKCR to HKLM\\Software\\Classes,

-  // because otherwise RegisterTypeLib ends up overwriting HKCU if the key

-  // already exists in HKCU.

-  HRESULT hr = RedirectHKCR(is_machine);

-  ASSERT1(SUCCEEDED(hr));

-  if (FAILED(hr)) {

-    return hr;

-  }

-  // We need to stop redirecting at the end of this function.

-  ON_SCOPE_EXIT(RemoveRedirectHKCR);

-

-  // load the type library.

-  CComPtr<ITypeLib> type_lib;

-  CComBSTR path;

-  hr = ::AtlLoadTypeLib(_AtlBaseModule.GetModuleInstance(), NULL, &path,

-                        &type_lib);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("[AtlLoadTypeLib failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (register_server) {

-    hr = (*registrar)(register_server);

-    if (FAILED(hr)) {

-      ASSERT(false, (_T("[Module registration failed][0x%08x]"), hr));

-      return hr;

-    }

-

-    return RegisterTypeLib(is_machine, path, type_lib);

-  } else {

-    hr = UnRegisterTypeLib(is_machine, path, type_lib);

-    if (FAILED(hr)) {

-      ASSERT(false, (_T("[UnRegisterTypeLib failed][0x%08x]"), hr));

-      return hr;

-    }

-

-    return (*registrar)(register_server);

-  }

-}

-

-HRESULT RegisterTypeLibForUser(ITypeLib* lib,

-                               OLECHAR* path,

-                               OLECHAR* help_dir) {

-  CORE_LOG(L3, (_T("[RegisterTypeLibForUser]")));

-  ASSERT1(lib);

-  ASSERT1(path);

-  // help_dir can be NULL.

-

-  const TCHAR* library_name = _T("oleaut32.dll");

-  scoped_library module(static_cast<HINSTANCE>(::LoadLibrary(library_name)));

-  if (!module) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LEVEL_ERROR,

-        (_T("[LoadLibrary failed][%s][0x%08x]"), library_name, hr));

-    return hr;

-  }

-

-  // RegisterTypeLibForUser function from oleaut32.dll.

-  typedef HRESULT(__stdcall *PF)(ITypeLib*, OLECHAR*, OLECHAR*);

-

-  const char* function_name = "RegisterTypeLibForUser";

-  PF fp = reinterpret_cast<PF>(::GetProcAddress(get(module), function_name));

-  if (!fp) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LEVEL_ERROR,

-             (_T("[GetProcAddress failed][%s][0x%08x]"),

-              function_name, library_name, hr));

-    return hr;

-  }

-

-  CORE_LOG(L3, (_T("[Calling RegisterTypelibForUser in oleaut]")));

-  HRESULT hr = fp(lib, path, help_dir);

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_ERROR, (_T("[regtypelib_for_user failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT UnRegisterTypeLibForUser(REFGUID lib_id,

-                                 WORD major_ver_num,

-                                 WORD minor_ver_num,

-                                 LCID lcid,

-                                 SYSKIND syskind) {

-  CORE_LOG(L3, (_T("[UnRegisterTypeLibForUser]")));

-

-  const TCHAR* library_name = _T("oleaut32.dll");

-  scoped_library module(static_cast<HINSTANCE>(::LoadLibrary(library_name)));

-  if (!module) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LEVEL_ERROR,

-        (_T("[LoadLibrary failed][%s][0x%08x]"), library_name, hr));

-    return hr;

-  }

-

-  // UnRegisterTypeLibForUser function from oleaut32.dll.

-  typedef HRESULT (__stdcall *PF)(REFGUID, WORD, WORD, LCID, SYSKIND);

-

-  const char* function_name = "UnRegisterTypeLibForUser";

-  PF fp = reinterpret_cast<PF>(::GetProcAddress(get(module), function_name));

-  if (!fp) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LEVEL_ERROR,

-             (_T("[GetProcAddress failed][%s][0x%08x]"),

-              function_name, library_name, hr));

-    return hr;

-  }

-

-  CORE_LOG(L3, (_T("[Calling UnRegisterTypeLibForUser in oleaut]")));

-  HRESULT hr = fp(lib_id, major_ver_num, minor_ver_num, lcid, syskind);

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_ERROR, (_T("[unregtypelib_for_user failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// This method assumes that the caller has permissions to open

-// the process token of the user's explorer.exe process.

-HRESULT GetImpersonationToken(bool is_interactive,

-                              uint32 explorer_pid,

-                              HANDLE* out_token) {

-  CORE_LOG(L3, (_T("[GetImpersonationToken]")));

-  ASSERT1(out_token);

-

-  // If the job is an interactive job, then we can use the explorer pid

-  // that is passed in for impersonation. If this is an

-  // update job, then we need to get a list of all the logged on users

-  // and pick one to perform the impersonation.

-  // TODO(omaha): Try to use the token of the user that is a domain account,

-  // since we are trying to solve the integrated proxy authentication issue.

-  // One way to do this might be to try the GetWindowsAccountDomainSid API.

-  if (is_interactive) {

-    scoped_handle exp(::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,

-                                    false, explorer_pid));

-    if (!exp) {

-      HRESULT hr = HRESULTFromLastError();

-      CORE_LOG(LEVEL_ERROR, (_T("[OpenProcess failed][0x%08x]"), hr));

-      return hr;

-    }

-

-    if (!::OpenProcessToken(get(exp),

-                            TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,

-                            out_token)) {

-      HRESULT hr = HRESULTFromLastError();

-      CORE_LOG(LEVEL_ERROR, (_T("[OpenProcessToken failed][0x%08x]"), hr));

-      return hr;

-    }

-  } else {

-    HRESULT hr = vista::GetExplorerTokenForLoggedInUser(out_token);

-    if (FAILED(hr)) {

-      CORE_LOG(LEVEL_ERROR, (_T("[GetExplorerTokenForLoggedInUser failed]")

-                             _T("[0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT UndoImpersonation(bool impersonated) {

-  CORE_LOG(L3, (_T("[UndoImpersonation]")));

-

-  if (impersonated && !::RevertToSelf()) {

-    // TODO(omaha): For now we assume that this never fails, change this

-    // impersonation to occur on a different thread, so that even if this fails,

-    // we can simply kill the thread.

-    // If this function call fails, we have a problem. We need to shut down the

-    // googleupdate process, since we are now running the system googleupdate

-    // as the user, and a number of assumptions about the code will fail.

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LEVEL_ERROR, (_T("[RevertToSelf failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT ImpersonateUser(bool is_interactive, uint32 explorer_pid) {

-  CORE_LOG(L3, (_T("[ImpersonateUser]")));

-

-  HANDLE handle = NULL;

-  HRESULT hr = GetImpersonationToken(is_interactive, explorer_pid, &handle);

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_ERROR, (_T("[GetImpersonationToken failed][0x%08x]"), hr));

-    return hr;

-  }

-  ASSERT1(handle);

-

-  // TODO(omaha): The impersonation will fail if the user is running on a

-  // Win2K SP3 or earlier, or WinXP SP1 or earlier. This is because the

-  // seImpersonateProvilage is needed to call this method, and this privilege

-  // does not exist in these systems.

-  // One way to work around this would be to launch a separate process

-  // using CreateProcessAsUser on these systems.

-  scoped_handle token(handle);

-  if (!::ImpersonateLoggedOnUser(get(token))) {

-    hr = HRESULTFromLastError();

-    CORE_LOG(LEVEL_ERROR, (_T("[ImpersonateLoggedOnUser failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// The EULA is assumed to be accepted unless eualaccepted=0 in the ClientState

-// key. For machine apps in this case, eulaccepted=1 in ClientStateMedium also

-// indicates acceptance and the value in ClientState is updated.

-bool IsAppEulaAccepted(bool is_machine,

-                       const CString& app_guid,

-                       bool require_explicit_acceptance) {

-  const CString state_key = GetAppClientStateKey(is_machine, app_guid);

-

-  DWORD eula_accepted = 0;

-  if (SUCCEEDED(RegKey::GetValue(state_key,

-                                 kRegValueEulaAccepted,

-                                 &eula_accepted))) {

-    if (0 != eula_accepted) {

-      return true;

-    }

-  } else {

-    if (!require_explicit_acceptance) {

-      return true;

-    }

-  }

-

-  if (!is_machine) {

-    return false;

-  }

-

-  eula_accepted = 0;

-  if (SUCCEEDED(RegKey::GetValue(

-                    GetAppClientStateMediumKey(is_machine, app_guid),

-                    kRegValueEulaAccepted,

-                    &eula_accepted))) {

-    if (0 == eula_accepted) {

-      return false;

-    }

-  } else {

-    return false;

-  }

-

-  VERIFY1(SUCCEEDED(RegKey::SetValue(state_key,

-                                     kRegValueEulaAccepted,

-                                     eula_accepted)));

-  return true;

-}

-

-// Does not need to set ClientStateMedium.

-HRESULT SetAppEulaNotAccepted(bool is_machine, const CString& app_guid) {

-  return RegKey::SetValue(GetAppClientStateKey(is_machine, app_guid),

-                          kRegValueEulaAccepted,

-                          static_cast<DWORD>(0));

-}

-

-// Deletes eulaaccepted from ClientState and ClientStateMedium.

-HRESULT ClearAppEulaNotAccepted(bool is_machine, const CString& app_guid) {

-  const CString state_key = GetAppClientStateKey(is_machine, app_guid);

-  if (RegKey::HasKey(state_key)) {

-    HRESULT hr = RegKey::DeleteValue(state_key, kRegValueEulaAccepted);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  if (!is_machine) {

-    return S_OK;

-  }

-

-  const CString state_medium_key =

-      GetAppClientStateMediumKey(is_machine, app_guid);

-  if (RegKey::HasKey(state_medium_key)) {

-    HRESULT hr = RegKey::DeleteValue(state_medium_key, kRegValueEulaAccepted);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-// For machine apps, ClientStateMedium takes precedence.

-// Does not propogate the ClientStateMedium value to ClientState.

-bool AreAppUsageStatsEnabled(bool is_machine, const CString& app_guid) {

-  if (is_machine) {

-    DWORD stats_enabled = 0;

-    if (SUCCEEDED(RegKey::GetValue(GetAppClientStateMediumKey(is_machine,

-                                                              app_guid),

-                                   kRegValueUsageStats,

-                                   &stats_enabled))) {

-      return (TRISTATE_TRUE == stats_enabled);

-    }

-  }

-

-  DWORD stats_enabled = 0;

-  if (SUCCEEDED(RegKey::GetValue(GetAppClientStateKey(is_machine, app_guid),

-                              kRegValueUsageStats,

-                              &stats_enabled))) {

-    return (TRISTATE_TRUE == stats_enabled);

-  }

-

-  return false;

-}

-

-// Does nothing if usage_stats_enable is TRISTATE_NONE.

-// For machine apps, clears ClientStateMedium because the app may be reading it

-// if present.

-HRESULT SetUsageStatsEnable(bool is_machine,

-                            const CString& app_guid,

-                            Tristate usage_stats_enable) {

-  if (TRISTATE_NONE == usage_stats_enable) {

-    return S_OK;

-  }

-

-  const DWORD stats_enabled = (TRISTATE_TRUE == usage_stats_enable) ? 1 : 0;

-

-  HRESULT hr = RegKey::SetValue(GetAppClientStateKey(is_machine, app_guid),

-                                kRegValueUsageStats,

-                                stats_enabled);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[Failed to set usagestats][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (!is_machine) {

-    return S_OK;

-  }

-

-  const CString state_medium_key =

-      GetAppClientStateMediumKey(is_machine, app_guid);

-  if (RegKey::HasKey(state_medium_key)) {

-    hr = RegKey::DeleteValue(state_medium_key, kRegValueUsageStats);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-// Writes usagestats in Google Update's ClientState key. This is the only case

-// in which usagestats is written to Google Update's ClientState key. Normally,

-// we write to the ClientState key(s) for the specific app(s).

-HRESULT ConvertLegacyUsageStats(bool is_machine) {

-  DWORD existing_usage_stats(0);

-

-  ConfigManager& config_mgr = *ConfigManager::Instance();

-  const CString legacy_key_name = config_mgr.registry_update(is_machine);

-  if (FAILED(RegKey::GetValue(legacy_key_name,

-                              kLegacyRegValueCollectUsageStats,

-                              &existing_usage_stats))) {

-    return S_OK;

-  }

-

-  const CString new_key_name = GetAppClientStateKey(is_machine,

-                                                    kGoogleUpdateAppId);

-  HRESULT hr = RegKey::SetValue(new_key_name,

-                                kRegValueUsageStats,

-                                existing_usage_stats);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  VERIFY1(SUCCEEDED(RegKey::DeleteValue(legacy_key_name,

-                                        kLegacyRegValueCollectUsageStats)));

-  return S_OK;

-}

-

-CString GetDefaultGoopdateTaskName(bool is_machine, CommandLineMode mode) {

-  ASSERT1(mode == COMMANDLINE_MODE_CORE || mode == COMMANDLINE_MODE_UA);

-

-  CString task_name;

-  if (is_machine) {

-    task_name = kScheduledTaskNameMachinePrefix;

-  } else {

-    task_name = kScheduledTaskNameUserPrefix;

-    CString user_sid;

-    VERIFY1(SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid)));

-    task_name += user_sid;

-  }

-

-  task_name += (mode == COMMANDLINE_MODE_CORE) ? kScheduledTaskNameCoreSuffix :

-                                                 kScheduledTaskNameUASuffix;

-  return task_name;

-}

-

-HRESULT InstallGoopdateTaskForMode(const TCHAR* task_path,

-                                   bool is_machine,

-                                   CommandLineMode mode) {

-  ASSERT1(mode == COMMANDLINE_MODE_CORE || mode == COMMANDLINE_MODE_UA);

-

-  CommandLineBuilder builder(mode);

-  if (mode == COMMANDLINE_MODE_UA) {

-    builder.set_install_source(kCmdLineInstallSourceScheduler);

-  }

-

-  CString task_description;

-  VERIFY1(task_description.LoadString(IDS_SCHEDULED_TASK_DESCRIPTION));

-

-  CString task_name(mode == COMMANDLINE_MODE_CORE ?

-                    ConfigManager::GetCurrentTaskNameCore(is_machine) :

-                    ConfigManager::GetCurrentTaskNameUA(is_machine));

-  if (internal::IsInstalledScheduledTask(task_name)) {

-    HRESULT hr = internal::InstallScheduledTask(task_name,

-                                                task_path,

-                                                builder.GetCommandLineArgs(),

-                                                task_description,

-                                                is_machine,

-                                                mode == COMMANDLINE_MODE_CORE &&

-                                                is_machine,

-                                                true,

-                                                mode == COMMANDLINE_MODE_UA);

-

-    if (SUCCEEDED(hr)) {

-      return hr;

-    }

-

-    // Try to uninstall the task that we failed to upgrade. Then create a new

-    // task name, and fall through to install that.

-    internal::UninstallScheduledTask(task_name);

-    if (mode == COMMANDLINE_MODE_CORE) {

-      VERIFY1(SUCCEEDED(

-      ConfigManager::CreateAndSetVersionedTaskNameCoreInRegistry(is_machine)));

-      task_name = ConfigManager::GetCurrentTaskNameCore(is_machine);

-    } else {

-      VERIFY1(SUCCEEDED(

-      ConfigManager::CreateAndSetVersionedTaskNameUAInRegistry(is_machine)));

-      task_name = ConfigManager::GetCurrentTaskNameUA(is_machine);

-    }

-    ASSERT1(!internal::IsInstalledScheduledTask(task_name));

-  }

-

-  return internal::InstallScheduledTask(task_name,

-                                        task_path,

-                                        builder.GetCommandLineArgs(),

-                                        task_description,

-                                        is_machine,

-                                        mode == COMMANDLINE_MODE_CORE &&

-                                        is_machine,

-                                        true,

-                                        mode == COMMANDLINE_MODE_UA);

-}

-

-HRESULT InstallGoopdateTasks(const TCHAR* task_path, bool is_machine) {

-  HRESULT hr = InstallGoopdateTaskForMode(task_path,

-                                          is_machine,

-                                          COMMANDLINE_MODE_CORE);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return InstallGoopdateTaskForMode(task_path, is_machine, COMMANDLINE_MODE_UA);

-}

-

-HRESULT UninstallGoopdateTasks(bool is_machine) {

-  VERIFY1(SUCCEEDED(internal::UninstallScheduledTask(

-      ConfigManager::GetCurrentTaskNameCore(is_machine))));

-  VERIFY1(SUCCEEDED(internal::UninstallScheduledTask(

-      ConfigManager::GetCurrentTaskNameUA(is_machine))));

-

-  // Try to uninstall any tasks that we failed to update during a previous

-  // overinstall. It is possible that we fail to uninstall these again here.

-  VERIFY1(SUCCEEDED(internal::UninstallScheduledTasks(

-      goopdate_utils::GetDefaultGoopdateTaskName(is_machine,

-                                                 COMMANDLINE_MODE_CORE))));

-  VERIFY1(SUCCEEDED(internal::UninstallScheduledTasks(

-      goopdate_utils::GetDefaultGoopdateTaskName(is_machine,

-                                                 COMMANDLINE_MODE_UA))));

-  return S_OK;

-}

-

-HRESULT UninstallLegacyGoopdateTasks(bool is_machine) {

-  const CString& legacy_omaha1_task =

-      internal::GetOmaha1LegacyTaskName(is_machine);

-  VERIFY1(SUCCEEDED(internal::UninstallScheduledTask(legacy_omaha1_task)));

-

-  const CString& legacy_omaha2_task =

-      internal::GetOmaha2LegacyTaskName(is_machine);

-  VERIFY1(SUCCEEDED(internal::UninstallScheduledTask(legacy_omaha2_task)));

-

-  return S_OK;

-}

-

-HRESULT StartGoopdateTaskCore(bool is_machine) {

-  return internal::StartScheduledTask(

-             ConfigManager::GetCurrentTaskNameCore(is_machine));

-}

-

-bool IsInstalledGoopdateTaskUA(bool is_machine) {

-  return internal::IsInstalledScheduledTask(

-                             ConfigManager::GetCurrentTaskNameUA(is_machine));

-}

-

-bool IsDisabledGoopdateTaskUA(bool is_machine) {

-  const CString& task_name(ConfigManager::GetCurrentTaskNameUA(is_machine));

-  return internal::GetScheduledTaskStatus(task_name) == SCHED_S_TASK_DISABLED;

-}

-

-HRESULT GetExitCodeGoopdateTaskUA(bool is_machine) {

-  const CString& task_name(ConfigManager::GetCurrentTaskNameUA(is_machine));

-  return internal::GetScheduledTaskExitCode(task_name);

-}

-

-HRESULT GetClientsStringValueFromRegistry(bool is_machine,

-                                          const CString& app_guid,

-                                          const CString& value_name,

-                                          CString* value) {

-  CORE_LOG(L3, (_T("[GetClientsStringValueFromRegistry][%d][%s][%s]"),

-                is_machine, app_guid, value_name));

-

-  ASSERT1(value);

-

-  CString app_client_key_name = GetAppClientsKey(is_machine, app_guid);

-

-  return RegKey::GetValue(app_client_key_name, value_name, value);

-}

-

-HRESULT GetVerFromRegistry(bool is_machine,

-                           const CString& app_guid,

-                           CString* version) {

-  ASSERT1(version);

-  return GetClientsStringValueFromRegistry(is_machine,

-                                           app_guid,

-                                           kRegValueProductVersion,

-                                           version);

-}

-

-HRESULT TerminateAllBrowsers(

-    BrowserType type,

-    TerminateBrowserResult* browser_res,

-    TerminateBrowserResult* default_res) {

-  UTIL_LOG(L3, (_T("[TerminateAllBrowsers][%d]"), type));

-  ASSERT1(default_res);

-  ASSERT1(browser_res);

-

-  if (type == BROWSER_UNKNOWN ||

-      type == BROWSER_DEFAULT ||

-      type >= BROWSER_MAX) {

-    ASSERT1(false);

-    return E_INVALIDARG;

-  }

-

-  const BrowserType kFirstBrowser = BROWSER_IE;

-  const int kNumSupportedBrowsers = BROWSER_MAX - kFirstBrowser;

-

-  BrowserType default_type = BROWSER_UNKNOWN;

-  HRESULT hr = GetDefaultBrowserType(&default_type);

-  if (FAILED(hr)) {

-    UTIL_LOG(LW, (_T("[GetDefaultBrowserType failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  TerminateBrowserResult terminate_results[kNumSupportedBrowsers];

-

-  for (int browser = 0; browser < kNumSupportedBrowsers; ++browser) {

-    const BrowserType browser_type =

-        static_cast<BrowserType>(kFirstBrowser + browser);

-    hr = TerminateBrowserProcess(browser_type,

-                                 CString(),

-                                 0,

-                                 &terminate_results[browser].found);

-    if (FAILED(hr)) {

-      UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][%u][0x%08x]"),

-                    browser_type, hr));

-    }

-  }

-

-  // Now wait for the all browser instances to die.

-  // TODO(omaha): Wait for all processes at once rather than waiting for

-  // (kTerminateBrowserTimeoutMs * # supported browsers) ms.

-  for (int browser = 0; browser < kNumSupportedBrowsers; ++browser) {

-    const BrowserType browser_type =

-        static_cast<BrowserType>(kFirstBrowser + browser);

-    hr = WaitForBrowserToDie(browser_type,

-                             CString(),

-                             kTerminateBrowserTimeoutMs);

-    if (FAILED(hr)) {

-      UTIL_LOG(LW, (_T("[WaitForBrowserToDie failed][%u][0x%08x]"),

-                    browser_type, hr));

-    } else {

-      terminate_results[browser].could_terminate = true;

-    }

-  }

-

-  *browser_res = terminate_results[type - kFirstBrowser];

-  *default_res = terminate_results[default_type - kFirstBrowser];

-

-  return S_OK;

-}

-

-// default_type can be BROWSER_UNKNOWN.

-// If browsers that must be closed could not be terminated, false is returned.

-// This method and TerminateBrowserProcesses assume the user did not shutdown

-// the specified browser. They restart and shutdown, respectively, the default

-// browser when the specified browser is not found. The reason for this may have

-// been that the the specified (stamped) browser could be in a bad state on the

-// machine and trying to start it would fail.

-// This may also be required to support hosted cases (i.e. AOL and Maxthon).

-// TODO(omaha): If we assume the stamped browser is okay, check whether the

-// specified browser is installed rather than relying on whether the browser was

-// running. It is perfectly valid for the browser to not be running.

-// TODO(omaha): Why not try the default browser if browsers that require

-// shutdown failed to terminate.

-bool GetBrowserToRestart(BrowserType type,

-                         BrowserType default_type,

-                         const TerminateBrowserResult& res,

-                         const TerminateBrowserResult& def_res,

-                         BrowserType* browser_type) {

-  ASSERT1(browser_type);

-  ASSERT1(type != BROWSER_UNKNOWN &&

-          type != BROWSER_DEFAULT &&

-          type < BROWSER_MAX);

-  ASSERT1(default_type != BROWSER_DEFAULT && default_type < BROWSER_MAX);

-  UTIL_LOG(L3, (_T("[GetBrowserToRestart][%d]"), type));

-

-  *browser_type = BROWSER_UNKNOWN;

-

-  if (res.found) {

-    switch (type) {

-      case BROWSER_IE:

-        *browser_type = BROWSER_IE;

-        return true;

-      case BROWSER_FIREFOX:   // Only one process.

-      case BROWSER_CHROME:    // One process per plug-in, even for upgrades.

-        if (res.could_terminate) {

-          *browser_type = type;

-          return true;

-        }

-        return false;

-      case BROWSER_UNKNOWN:

-      case BROWSER_DEFAULT:

-      case BROWSER_MAX:

-      default:

-        break;

-    }

-  }

-

-  // We did not find the browser that we wanted to restart. Hence we need to

-  // determine if we could shutdown the default browser.

-  switch (default_type) {

-    case BROWSER_IE:

-      *browser_type = BROWSER_IE;

-      return true;

-    case BROWSER_FIREFOX:

-    case BROWSER_CHROME:

-      if (!def_res.found || def_res.found && def_res.could_terminate) {

-        *browser_type = default_type;

-        return true;

-      }

-      break;

-    case BROWSER_UNKNOWN:

-    case BROWSER_DEFAULT:

-    case BROWSER_MAX:

-    default:

-      break;

-  }

-

-  return false;

-}

-

-// See the comments about the default browser above GetBrowserToRestart.

-HRESULT TerminateBrowserProcesses(BrowserType type,

-                                  TerminateBrowserResult* browser_res,

-                                  TerminateBrowserResult* default_res) {

-  UTIL_LOG(L3, (_T("[TerminateBrowserProcesses][%d]"), type));

-  ASSERT1(browser_res);

-  ASSERT1(default_res);

-

-  browser_res->could_terminate = false;

-  default_res->could_terminate = false;

-

-  if (type == BROWSER_UNKNOWN ||

-      type == BROWSER_DEFAULT ||

-      type >= BROWSER_MAX) {

-    ASSERT1(false);

-    return E_UNEXPECTED;

-  }

-

-  CString sid;

-  HRESULT hr = user_info::GetCurrentUser(NULL, NULL, &sid);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[GetCurrentUser failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = TerminateBrowserProcess(type,

-                               sid,

-                               kTerminateBrowserTimeoutMs,

-                               &browser_res->found);

-  if (FAILED(hr)) {

-    UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][0x%08x]"), hr));

-  } else {

-    browser_res->could_terminate = true;

-  }

-

-  // Since no instances of the browser type exist, we try to find and kill

-  // all instances of the default browser.

-  if (!browser_res->found) {

-    // We dont want to try and terminate the default browser, if it is the

-    // same as the browser that we tried above.

-

-    BrowserType default_type = BROWSER_UNKNOWN;

-    hr = GetDefaultBrowserType(&default_type);

-    if (FAILED(hr)) {

-      UTIL_LOG(LW, (_T("[GetDefaultBrowserType failed][0x%08x]"), hr));

-    }

-

-    UTIL_LOG(L3, (_T("[Trying to kill the default browser %d]"), default_type));

-    if (default_type != type) {

-      hr = TerminateBrowserProcess(BROWSER_DEFAULT,

-                                   sid,

-                                   kTerminateBrowserTimeoutMs,

-                                   &default_res->found);

-      if (FAILED(hr)) {

-        UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][0x%08x]"), hr));

-      } else {

-        default_res->could_terminate = true;

-      }

-    }

-  }

-

-  return hr;

-}

-

-HRESULT StartBrowserWithProcessToken(bool is_machine,

-                                     BrowserType type,

-                                     const CString& url,

-                                     uint32 explorer_pid) {

-  UTIL_LOG(L3, (_T("[StartBrowserWithProcessToken.]")

-                _T("[is_machine = %d][type = %d]"), is_machine, type));

-

-  // In case of machine goopdate we need to CreateProcessAsUser, else we ask

-  // the shell to create a new browser process.

-  if (is_machine) {

-    CString browser_path;

-    HRESULT hr = GetBrowserImagePath(type, &browser_path);

-    if (FAILED(hr)) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[GetBrowserImagePath failed.][0x%08x]"), hr));

-      return hr;

-    }

-    ASSERT1(!browser_path.IsEmpty());

-

-    CString command_line;

-    EnclosePath(&browser_path);

-    command_line.Format(_T("%s %s"), browser_path, url);

-    UTIL_LOG(L3, (_T("[Executing command line %s.]"), command_line));

-    hr = vista::StartProcessWithTokenOfProcess(explorer_pid, command_line);

-    if (FAILED(hr)) {

-      UTIL_LOG(LW, (_T("[StartProcessWithTokenOfProcess failed][0x%08x]"), hr));

-      return hr;

-    }

-  } else {

-    return ShellExecuteBrowser(type, url);

-  }

-

-  return S_OK;

-}

-

-HRESULT GetBrowserImagePathFromProcess(BrowserType type,

-                                       uint32 explorer_pid,

-                                       CString* path) {

-  ASSERT1(path);

-

-  if (type == BROWSER_UNKNOWN || type >= BROWSER_MAX) {

-    ASSERT1(false);

-    return E_UNEXPECTED;

-  }

-

-  if (type == BROWSER_DEFAULT) {

-    return GetDefaultBrowserPath(path);

-  }

-

-  CString user_sid;

-  HRESULT hr = Process::GetProcessOwner(explorer_pid, &user_sid);

-  if (FAILED(hr)) {

-    UTIL_LOG(LEVEL_WARNING, (_T("[GetProcessOwner failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  CString browser_name;

-  hr = BrowserTypeToProcessName(type, &browser_name);

-  if (FAILED(hr)) {

-    UTIL_LOG(LW, (_T("[BrowserTypeToProcessName failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = Process::GetImagePath(browser_name, user_sid, path);

-  if (FAILED(hr)) {

-    UTIL_LOG(LW, (_T("[GetImagePath failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT ConvertStringToBrowserType(const CString& text, BrowserType* type) {

-  ASSERT1(type != NULL);

-

-  if (text.GetLength() != 1) {

-    return GOOPDATEUTILS_E_BROWSERTYPE;

-  }

-

-  int browser_type = 0;

-  if (!String_StringToDecimalIntChecked(text, &browser_type)) {

-    return GOOPDATEUTILS_E_BROWSERTYPE;

-  }

-

-  if (browser_type >= BROWSER_MAX) {

-    return GOOPDATEUTILS_E_BROWSERTYPE;

-  }

-

-  *type = static_cast<BrowserType>(browser_type);

-  return S_OK;

-}

-

-CString ConvertBrowserTypeToString(BrowserType type) {

-  CString text = itostr(static_cast<int>(type));

-  ASSERT1(!text.IsEmpty());

-  return text;

-}

-

-bool IsServiceInstalled() {

-  return ServiceInstall::IsServiceInstalled(

-                             ConfigManager::GetCurrentServiceName());

-}

-

-HRESULT GetOSInfo(CString* os_version, CString* service_pack) {

-  ASSERT1(os_version);

-  ASSERT1(service_pack);

-

-  OSVERSIONINFO os_version_info = { 0 };

-  os_version_info.dwOSVersionInfoSize = sizeof(os_version_info);

-  if (!::GetVersionEx(&os_version_info)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LW, (_T("[GetVersionEx failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  os_version->Format(_T("%d.%d"),

-                     os_version_info.dwMajorVersion,

-                     os_version_info.dwMinorVersion);

-  *service_pack = os_version_info.szCSDVersion;

-  return S_OK;

-}

-

-// We have a mechanism to display a help center page asking users for help

-// debugging crashes.

-HRESULT ShowUserCrashPage(const CString& language,

-                          uint64 address,

-                          uint32 code) {

-  const TCHAR* const kCrashSourceId = _T("crash");

-

-  CString url;

-  HRESULT hr = BuildHttpGetString(kUrlMoreInformation,

-                                  code,

-                                  static_cast<DWORD>(address),

-                                  0,

-                                  kGoogleUpdateAppId,

-                                  GetVersionString(),

-                                  false,

-                                  language,

-                                  kCrashSourceId,

-                                  &url);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  return ShellExecuteBrowser(BROWSER_DEFAULT, url);

-}

-

-CPath BuildInstallDirectory(bool is_machine, const CString& version) {

-  ConfigManager& cm = *ConfigManager::Instance();

-  CPath install_dir(is_machine ? cm.GetMachineGoopdateInstallDir() :

-                                 cm.GetUserGoopdateInstallDir());

-  VERIFY1(install_dir.Append(version));

-

-  return install_dir;

-}

-

-HRESULT LaunchCmdLine(const CString& cmd_line) {

-  bool run_with_lower_privileges = vista_util::IsUserRunningSplitToken() &&

-                                   vista_util::IsUserAdmin();

-

-  return run_with_lower_privileges ?

-             LaunchImpersonatedCmdLine(cmd_line) :

-             System::ShellExecuteCommandLine(cmd_line, NULL, NULL);

-}

-

-HRESULT LaunchBrowser(BrowserType type, const CString& url) {

-  bool run_with_lower_privileges = vista_util::IsUserRunningSplitToken() &&

-                                   vista_util::IsUserAdmin();

-

-  if (run_with_lower_privileges) {

-    // Other than having a service launch the browser using CreateProcessAsUser,

-    // there is no easy solution if we are unable to launch the browser

-    // impersonated.

-    return LaunchImpersonatedBrowser(type, url);

-  }

-

-  HRESULT hr = ShellExecuteBrowser(type, url);

-  if (FAILED(hr)) {

-    UTIL_LOG(LW, (_T("[ShellExecuteBrowser failed][0x%x]"), hr));

-  }

-  return hr;

-}

-

-// This method formats all the data that is present inside the UpdateResponse

-// in the form of the extra arguments command line.

-// The values that are converted include:

-// appguid, appname (will not be present in pre-I18N builds.), needsadmin

-// iid, ap, browser; values not used in pre-I18N builds are not supported.

-HRESULT ConvertResponseDataToExtraArgs(const UpdateResponseData& response_data,

-                                       CString* extra) {

-  ASSERT1(extra);

-  *extra = _T("");

-

-  // Append the application guid.

-  if (response_data.guid() == GUID_NULL) {

-    // The guid should always be present.

-    return E_INVALIDARG;

-  }

-  CString str_guid = GuidToString(response_data.guid());

-  ASSERT1(!str_guid.IsEmpty());

-  extra->AppendFormat(_T("%s=%s"), kExtraArgAppGuid, str_guid);

-

-  // Convert the application name into the command line format. In case of

-  // pre-I18N installers, the name is not known to the installer, hence if

-  // the name is empty we use a hard coded name.

-  CString product_name;

-  if (!response_data.app_name().IsEmpty()) {

-    HRESULT hr = WideStringToUtf8UrlEncodedString(response_data.app_name(),

-                                                  &product_name);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  } else {

-    product_name = GetProductName(str_guid);

-  }

-  ASSERT1(!product_name.IsEmpty());

-  extra->AppendFormat(_T("&%s=%s"), kExtraArgAppName, product_name);

-

-  // Append needs admin.

-  CString needs_admin_str;

-  HRESULT hr = ConvertNeedsAdminToString(response_data.needs_admin(),

-                                         &needs_admin_str);

-

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(!needs_admin_str.IsEmpty());

-  extra->AppendFormat(_T("&%s=%s"), kExtraArgNeedsAdmin, needs_admin_str);

-

-  if (response_data.installation_id() != GUID_NULL) {

-    CString str_installationid = GuidToString(response_data.installation_id());

-    extra->AppendFormat(_T("&%s=%s"), kExtraArgInstallationId,

-                        str_installationid);

-  }

-  // Append the browser tag.

-  if (response_data.browser_type() != BROWSER_UNKNOWN) {

-    CString browser_type =

-        ConvertBrowserTypeToString(response_data.browser_type());

-    extra->AppendFormat(_T("&%s=%s"), kExtraArgBrowserType, browser_type);

-  }

-

-  // Append ap tag.

-  if (!response_data.ap().IsEmpty()) {

-    extra->AppendFormat(_T("&%s=%s"),

-                        kExtraArgAdditionalParameters,

-                        response_data.ap());

-  }

-

-  // Append TT tag.

-  if (!response_data.tt_token().IsEmpty()) {

-    extra->AppendFormat(_T("&%s=%s"),

-                        kExtraArgTTToken,

-                        response_data.tt_token());

-  }

-

-  return S_OK;

-}

-

-HRESULT ConvertNeedsAdminToString(NeedsAdmin needs_admin, CString* text) {

-  ASSERT1(text);

-  switch (needs_admin) {

-    case omaha::NEEDS_ADMIN_YES:

-      *text = kTrue;

-      break;

-    case omaha::NEEDS_ADMIN_NO:

-      *text = kFalse;

-      break;

-    default:

-      return E_INVALIDARG;

-  }

-

-  return S_OK;

-}

-

-HRESULT ConvertStringToNeedsAdmin(const CString& text, NeedsAdmin* admin) {

-  ASSERT1(admin);

-  if (_tcsicmp(text, kTrue) == 0) {

-    *admin = omaha::NEEDS_ADMIN_YES;

-  } else if (_tcsicmp(text, kFalse) == 0) {

-    *admin = omaha::NEEDS_ADMIN_NO;

-  } else {

-    return GOOPDATEXML_E_NEEDSADMIN;

-  }

-

-  return S_OK;

-}

-

-HRESULT HandleLegacyManifestHandoff(const CString& manifest_filename,

-                                    bool is_machine) {

-  OPT_LOG(L1, (_T("[HandleLegacyManifestHandoff]")));

-

-  // Read the manifest file.

-  CString xml_contents;

-  HRESULT hr = GoopdateXmlParser::LoadXmlFileToMemory(manifest_filename,

-                                                      &xml_contents);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Could not load manifest file to memory][%s][0x%08x]"),

-                 manifest_filename, hr));

-    // There is something wrong with the file. Move the file to a .bad file.

-    CString bad(manifest_filename);

-    bad.Append(_T(".bad"));

-    File::Move(manifest_filename, bad, true);

-    return hr;

-  }

-  VERIFY1(SUCCEEDED(File::Remove(manifest_filename)));

-

-  // Parse the manifest.

-  UpdateResponses responses;

-  hr = GoopdateXmlParser::ParseManifestString(xml_contents, &responses);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Could not parse manifest][%s]"), manifest_filename));

-    return hr;

-  }

-  ASSERT1(!responses.empty());

-

-  // We we support one application in legacy Omaha.

-  ASSERT1(1 == responses.size());

-  UpdateResponses::const_iterator iter = responses.begin();

-  const UpdateResponse& response = (*iter).second;

-  if (response.update_response_data().needs_admin() ==

-      NEEDS_ADMIN_YES && !is_machine) {

-    return GOOPDATE_E_NON_ADMINS_CANNOT_INSTALL_ADMIN;

-  }

-

-  // Convert the contents of the manifest file into the extraargs command line

-  // format which is the standard omaha2 worker command line.

-  // We re-launch the worker with the new command line instead of handling the

-  // legacy handoff right here, as this allows the other parts of setup

-  // and worker to only know about the new command line and not have to deal

-  // with the legacy commandline. One place where setup and the worker

-  // get simplified because of this is during search for processes with

-  // needsadmin=true.

-  CString extra_args;

-  hr = ConvertResponseDataToExtraArgs(response.update_response_data(),

-                                      &extra_args);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[ConvertResponseDataToExtraArgs failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  // /handoff "extraargs"

-  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);

-  builder.set_extra_args(extra_args);

-  CString cmd_line = builder.GetCommandLineArgs();

-

-  hr = StartGoogleUpdateWithArgs(is_machine, cmd_line, NULL);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[StartGoogleUpdateWithArgs failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// This method does a very specific job of searching for install workers,

-// for the user and machine omaha. It also includes the on-demand updates COM

-// server, because we treat it similar to interactive installs.

-//

-// In machine case we search in all the accounts since the install worker can be

-// running in any admin account and the machine update worker runs as SYSTEM.

-// In the user case, we only search the user's account.

-// In both cases, the Needsadmin command line parameter is checked for

-// true/false in the machine/user case, respectively.

-//

-// Only adds processes to the input vector; does not clear it.

-//

-// TODO(omaha): For now we search for the needs_admin=true in the command

-// line to determine a machine install. Another option of identifying omaha's

-// is to use the presence of a named mutex. So the user omaha will create

-// Global\<sid>\Mutex and the machine will create Global\Mutex, in here then

-// we can test for the presence of the name to decide if an interactive

-// omaha is running.

-// TODO(omaha): Consider further filtering the processes based on whether

-// the owner is elevated in case of machine omaha.

-HRESULT GetInstallWorkerProcesses(bool is_machine,

-                                  std::vector<uint32>* processes) {

-  ASSERT1(processes);

-

-  CString user_sid;

-  DWORD flags = EXCLUDE_CURRENT_PROCESS |

-                INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;

-

-  std::vector<CString> command_lines;

-  CString command_line_to_include;

-  command_line_to_include.Format(_T("/%s"), kCmdLineAppHandoffInstall);

-  command_lines.push_back(command_line_to_include);

-  command_line_to_include.Format(_T("/%s"), kCmdLineFinishGoogleUpdateInstall);

-  command_lines.push_back(command_line_to_include);

-  command_lines.push_back(kCmdLineComServerDash);

-

-  if (!is_machine) {

-    // Search only the same sid as the current user.

-    flags |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER;

-

-    HRESULT hr = user_info::GetCurrentUser(NULL, NULL, &user_sid);

-    if (FAILED(hr)) {

-      CORE_LOG(LE, (_T("[GetCurrentUser failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  std::vector<uint32> all_install_worker_processes;

-  HRESULT hr = Process::FindProcesses(flags,

-                                      kGoopdateFileName,

-                                      true,

-                                      user_sid,

-                                      command_lines,

-                                      &all_install_worker_processes);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  CString needsadmin_arg;

-  needsadmin_arg.Format(_T("%s=%s"), kExtraArgNeedsAdmin, is_machine ?

-                                                          _T("True") :

-                                                          _T("False"));

-  needsadmin_arg.MakeLower();

-

-  CString official_path;

-  hr = GetFolderPath(is_machine ? CSIDL_PROGRAM_FILES : CSIDL_LOCAL_APPDATA,

-                     &official_path);

-  ASSERT1(SUCCEEDED(hr));

-  ASSERT1(!official_path.IsEmpty());

-

-  for (size_t i = 0; i < all_install_worker_processes.size(); ++i) {

-    CString cmd_line;

-    const uint32 process = all_install_worker_processes[i];

-    if (SUCCEEDED(Process::GetCommandLine(process, &cmd_line))) {

-      cmd_line.MakeLower();

-      // TODO(omaha): FindProcess method does not allow regex's to be specified

-      // along with the include command line. Change Process to allow this.

-      if (cmd_line.Find(needsadmin_arg) != -1) {

-        CORE_LOG(L4, (_T("[Including process][%s]"), cmd_line));

-        processes->push_back(process);

-      }

-

-      // The -Embedding does not have a needsAdmin. Decide whether to include it

-      // if it matches the official path for the requested instance type.

-      CString exe_path;

-      if (cmd_line.Find(kCmdLineComServerDash) != -1 &&

-          SUCCEEDED(GetExePathFromCommandLine(cmd_line, &exe_path)) &&

-          String_StrNCmp(official_path, exe_path, official_path.GetLength(),

-                         true) == 0) {

-        CORE_LOG(L4, (_T("[Including process][%s]"), cmd_line));

-        processes->push_back(process);

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-// The event name saved to the environment variable does not contain the

-// decoration added by GetNamedObjectAttributes.

-HRESULT CreateUniqueEventInEnvironment(const CString& var_name,

-                                       bool is_machine,

-                                       HANDLE* unique_event) {

-  ASSERT1(unique_event);

-

-  GUID event_guid = GUID_NULL;

-  HRESULT hr = ::CoCreateGuid(&event_guid);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[::CoCreateGuid failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  CString event_name(GuidToString(event_guid));

-  NamedObjectAttributes attr;

-  GetNamedObjectAttributes(event_name, is_machine, &attr);

-

-  hr = CreateEvent(&attr, unique_event);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[CreateEvent failed in CreateUniqueEventInEnvironment]"),

-                  _T("[%s][0x%08x]"), var_name, hr));

-    return hr;

-  }

-

-  CORE_LOG(L3, (_T("[created unique event][%s][%s]"), var_name, event_name));

-

-  if (!::SetEnvironmentVariable(var_name, event_name)) {

-    DWORD error = ::GetLastError();

-    CORE_LOG(LE, (_T("[::SetEnvironmentVariable failed][%d]"), error));

-    return HRESULT_FROM_WIN32(error);

-  }

-

-  return S_OK;

-}

-

-HRESULT OpenUniqueEventFromEnvironment(const CString& var_name,

-                                       bool is_machine,

-                                       HANDLE* unique_event) {

-  ASSERT1(unique_event);

-

-  TCHAR event_name[MAX_PATH] = {0};

-  if (!::GetEnvironmentVariable(var_name, event_name, arraysize(event_name))) {

-    DWORD error = ::GetLastError();

-    CORE_LOG(LW, (_T("[Failed to read environment variable][%s][%d]"),

-                  var_name, error));

-    return HRESULT_FROM_WIN32(error);

-  }

-

-  CORE_LOG(L3, (_T("[read unique event][%s][%s]"), var_name, event_name));

-

-  NamedObjectAttributes attr;

-  GetNamedObjectAttributes(event_name, is_machine, &attr);

-  *unique_event = ::OpenEvent(EVENT_ALL_ACCESS, false, attr.name);

-

-  if (!*unique_event) {

-    DWORD error = ::GetLastError();

-    CORE_LOG(LW, (_T("[::OpenEvent failed][%s][%d]"), attr.name, error));

-    return HRESULT_FROM_WIN32(error);

-  }

-

-  return S_OK;

-}

-

-// The caller is responsible for reseting the event and closing the handle.

-HRESULT CreateEvent(NamedObjectAttributes* event_attr, HANDLE* event_handle) {

-  ASSERT1(event_handle);

-  ASSERT1(event_attr);

-  ASSERT1(!event_attr->name.IsEmpty());

-  *event_handle = ::CreateEvent(&event_attr->sa,

-                                true,   // manual reset

-                                false,  // not signaled

-                                event_attr->name);

-

-  if (!*event_handle) {

-    DWORD error = ::GetLastError();

-    CORE_LOG(LEVEL_ERROR, (_T("[::SetEvent failed][%d]"), error));

-    return HRESULT_FROM_WIN32(error);

-  }

-

-  return S_OK;

-}

-

-HRESULT ConfigureNetwork(bool is_machine, bool is_local_system) {

-  CORE_LOG(L3, (_T("[goopdate_utils::ConfigureNetwork]")));

-  scoped_handle impersonation_token;

-  if (is_local_system) {

-    // Get an impersonation token corresponding to a primary

-    // token for any of the logged on users.

-    vista::GetLoggedOnUserToken(address(impersonation_token));

-  }

-  NetworkConfig& network_config = NetworkConfig::Instance();

-  HRESULT hr = network_config.Initialize(is_machine, get(impersonation_token));

-  if (FAILED(hr)) {

-    NET_LOG(LE, (_T("[NetworkConfig::Initialize() failed][0x%x]"), hr));

-    return hr;

-  }

-

-  // The NetworkConfig singleton owns the impersonation token.

-  release(impersonation_token);

-

-  // Detecting the default browser requires impersonation so that calling code

-  // running as system is able to detect user proxy settings.

-  HANDLE token = network_config.session().impersonation_token;

-  scoped_impersonation impersonate_user(token);

-  if (token) {

-    DWORD result = impersonate_user.result();

-    ASSERT(result == ERROR_SUCCESS, (_T("impersonation failed %d"), result));

-  }

-  network_config.Add(new GoogleProxyDetector(MACHINE_REG_UPDATE_DEV));

-  BrowserType browser_type(BROWSER_UNKNOWN);

-  GetDefaultBrowserType(&browser_type);

-  if (browser_type == BROWSER_FIREFOX) {

-    network_config.Add(new FirefoxProxyDetector());

-  }

-  // There is no Chrome detector because it uses the same proxy settings as IE.

-  network_config.Add(new IEProxyDetector());

-  network_config.Add(new DefaultProxyDetector);

-

-  // Use a global network configuration override if available.

-  ConfigManager* config_manager = ConfigManager::Instance();

-  CString net_config;

-  if (SUCCEEDED(config_manager->GetNetConfig(&net_config))) {

-    Config configuration_override = NetworkConfig::ParseNetConfig(net_config);

-    network_config.SetConfigurationOverride(&configuration_override);

-  }

-

-  return S_OK;

-}

-

-bool IsTestSource() {

-  return !ConfigManager::Instance()->GetTestSource().IsEmpty();

-}

-

-HRESULT ReadNameValuePairsFromFile(const CString& file_path,

-                                   const CString& group_name,

-                                   std::map<CString, CString>* pairs) {

-  ASSERT1(pairs);

-

-  if (!File::Exists(file_path)) {

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-

-  pairs->clear();

-

-  TCHAR str_buf[32768] = {0};

-

-  // Retrieve all key names in the section requested.

-  DWORD buf_count = ::GetPrivateProfileString(group_name,

-                                              NULL,

-                                              NULL,

-                                              str_buf,

-                                              arraysize(str_buf),

-                                              file_path);

-

-  DWORD offset = 0;

-  while (offset < buf_count) {

-    TCHAR val_buf[1024] = {0};

-    CString current_key = &(str_buf[offset]);

-    DWORD val_count = ::GetPrivateProfileString(group_name,

-                                                current_key,

-                                                NULL,

-                                                val_buf,

-                                                arraysize(val_buf),

-                                                file_path);

-    (*pairs)[current_key] = val_buf;

-    offset += current_key.GetLength() + 1;

-  }

-

-  return S_OK;

-}

-

-HRESULT WriteNameValuePairsToFile(const CString& file_path,

-                                  const CString& group_name,

-                                  const std::map<CString, CString>& pairs) {

-  std::map<CString, CString>::const_iterator it = pairs.begin();

-  for (; it != pairs.end(); ++it) {

-    if (!::WritePrivateProfileString(group_name,

-                                     it->first,

-                                     it->second,

-                                     file_path)) {

-      return HRESULTFromLastError();

-    }

-  }

-

-  return S_OK;

-}

-

-// Google Update does not have a referral_id. Everything else is the same as for

-// apps.

-HRESULT SetGoogleUpdateBranding(const CString& client_state_key_path,

-                                const CString& brand_code,

-                                const CString& client_id) {

-  HRESULT hr(SetAppBranding(client_state_key_path,

-                            brand_code,

-                            client_id,

-                            CString()));

-

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  RegKey state_key;

-  hr = state_key.Open(client_state_key_path);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Legacy support for older versions that do not write the FirstInstallTime.

-  // This code ensures that FirstInstallTime always has a valid non-zero value.

-  DWORD install_time(0);

-  if (FAILED(state_key.GetValue(kRegValueInstallTimeSec, &install_time)) ||

-      !install_time) {

-    const DWORD now = Time64ToInt32(GetCurrent100NSTime());

-    VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueInstallTimeSec, now)));

-    SETUP_LOG(L3, (_T("[InstallTime missing. Setting it here.][%u]"), now));

-  }

-

-  return S_OK;

-}

-

-// Branding information is only written if a brand code is not already present.

-// We should only write it if this is the first install of Omaha to avoid giving

-// undue credit to a later installer source. Writing a default brand code

-// prevents future branded installations from setting their brand.

-// As suggested by PSO, there is no default client ID.

-// Assumes the specified Client State key has been created.

-HRESULT SetAppBranding(const CString& client_state_key_path,

-                       const CString& brand_code,

-                       const CString& client_id,

-                       const CString& referral_id) {

-  SETUP_LOG(L3, (_T("[goopdate_utils::SetAppBranding][%s][%s][%s][%s]"),

-                 client_state_key_path, brand_code, client_id, referral_id));

-

-  if (brand_code.GetLength() > kBrandIdLength) {

-    return E_INVALIDARG;

-  }

-

-  RegKey state_key;

-  HRESULT hr = state_key.Open(client_state_key_path);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString existing_brand_code;

-  hr = state_key.GetValue(kRegValueBrandCode, &existing_brand_code);

-  if (!existing_brand_code.IsEmpty()) {

-    ASSERT1(SUCCEEDED(hr));

-    if (existing_brand_code.GetLength() > kBrandIdLength) {

-      // Bug 1358852: Brand code garbled with one click.

-      VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueBrandCode,

-                            existing_brand_code.Left(kBrandIdLength))));

-    }

-    return S_OK;

-  }

-

-  const TCHAR* brand_code_to_write = brand_code.IsEmpty() ?

-                                     kDefaultGoogleUpdateBrandCode :

-                                     brand_code;

-  hr = state_key.SetValue(kRegValueBrandCode, brand_code_to_write);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (!client_id.IsEmpty()) {

-    hr = state_key.SetValue(kRegValueClientId, client_id);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  if (!referral_id.IsEmpty()) {

-    hr = state_key.SetValue(kRegValueReferralId, referral_id);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  const DWORD now = Time64ToInt32(GetCurrent100NSTime());

-  VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueInstallTimeSec, now)));

-

-  return S_OK;

-}

-

-bool IsAppInstallWorkerRunning(bool is_machine) {

-  CORE_LOG(L3, (_T("[IsAppInstallWorkerRunning][%d]"), is_machine));

-  std::vector<uint32> processes;

-  VERIFY1(SUCCEEDED(GetInstallWorkerProcesses(is_machine, &processes)));

-  return !processes.empty();

-}

-

-// TODO(omaha): needs_admin is only used for one case. Can we avoid it?

-bool IsMachineProcess(CommandLineMode mode,

-                      bool is_running_from_official_machine_directory,

-                      bool is_local_system,

-                      bool is_machine_override,

-                      Tristate needs_admin) {

-  switch (mode) {

-    // These "install" operations may not be running from the installed

-    // location.

-    case COMMANDLINE_MODE_INSTALL:

-    case COMMANDLINE_MODE_IG:

-    case COMMANDLINE_MODE_HANDOFF_INSTALL:

-    case COMMANDLINE_MODE_REGISTER_PRODUCT:

-    case COMMANDLINE_MODE_UNREGISTER_PRODUCT:

-      ASSERT1(TRISTATE_NONE != needs_admin);

-      return TRISTATE_TRUE == needs_admin;

-

-    // The following is a Code Red repair executable, which runs from temp dir.

-    case COMMANDLINE_MODE_RECOVER:

-      return is_machine_override;

-

-    // The following are all user-initiated installs with UI.

-    // They always run as the user for both user and machine installs.

-    // Silent installs for Pack should go here too.

-    case COMMANDLINE_MODE_NOARGS:  // Legacy install

-    case COMMANDLINE_MODE_LEGACYUI:

-    case COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF:

-      return is_running_from_official_machine_directory;

-

-    // The following always runs as the user and may provide UI for on-demand

-    // installs and browser launches.

-    // The install location determines user vs. machine.

-    case COMMANDLINE_MODE_COMSERVER:

-      return is_running_from_official_machine_directory;

-

-    // The following always runs as the user and is user-initiated.

-    case COMMANDLINE_MODE_WEBPLUGIN:

-      // The install location determines user vs. machine.

-      // This may not be the desired value when doing a cross-install or using

-      // the opposite plugin (i.e. user plugin is often used before the machine

-      // one).

-      return is_running_from_official_machine_directory;

-

-    // The following all run silently as the user for user installs or Local

-    // System for machine installs.

-    case COMMANDLINE_MODE_UPDATE:

-    case COMMANDLINE_MODE_UA:

-    case COMMANDLINE_MODE_CODE_RED_CHECK:

-      return is_local_system;

-

-    // The following normally runs silently as the user for user installs or

-    // Local System for machine installs. When launched by recovery it can also

-    // a machine instance can also be running as an elevated admin.

-    case COMMANDLINE_MODE_UG:

-      return is_machine_override || is_local_system;

-

-    // The following runs silently as the user for user installs or Local System

-    // for machine installs.

-    case COMMANDLINE_MODE_CORE:

-    case COMMANDLINE_MODE_CRASH_HANDLER:

-      return is_local_system;

-

-    // The following runs silently as Local System.

-    case COMMANDLINE_MODE_SERVICE:

-      ASSERT1(is_local_system);

-      return is_local_system;

-

-    // The following run as machine for all installs.

-    case COMMANDLINE_MODE_SERVICE_REGISTER:

-    case COMMANDLINE_MODE_SERVICE_UNREGISTER:

-      return true;

-

-    // The crashing process determines whether it was a machine or user omaha

-    // and correctly sets the /machine switch.

-    case COMMANDLINE_MODE_REPORTCRASH:

-      return is_machine_override;

-

-    // The following all run silently as the user for all installs.

-    case COMMANDLINE_MODE_REGSERVER:

-    case COMMANDLINE_MODE_UNREGSERVER:

-      return is_running_from_official_machine_directory;

-

-    // The following are miscellaneous modes that we do not expect to be running

-    // in the wild.

-    case COMMANDLINE_MODE_UNKNOWN:

-    case COMMANDLINE_MODE_NETDIAGS:

-    case COMMANDLINE_MODE_CRASH:

-    default:

-      return is_running_from_official_machine_directory;

-  }

-}

-

-// Returns true if the version does not begin with "1.0." or "1.1.".

-bool IsGoogleUpdate2OrLater(const CString& version) {

-  const ULONGLONG kFirstOmaha2Version = MAKEDLLVERULL(1, 2, 0, 0);

-  ULONGLONG version_number = VersionFromString(version);

-  ASSERT1(0 != version_number);

-

-  if (kFirstOmaha2Version <= version_number) {

-    return true;

-  }

-

-  return false;

-}

-

-bool FormatMessageForNetworkError(HRESULT error,

-                                  const CString app_name,

-                                  CString* msg) {

-  ASSERT1(msg);

-

-  switch (error) {

-    case GOOPDATE_E_NO_NETWORK:

-      msg->FormatMessage(IDS_NO_NETWORK_PRESENT_ERROR,

-                         kGoopdateFileName,

-                         error);

-      break;

-    case GOOPDATE_E_NETWORK_UNAUTHORIZED:

-      msg->FormatMessage(IDS_ERROR_HTTPSTATUS_UNAUTHORIZED, app_name, error);

-      break;

-    case GOOPDATE_E_NETWORK_FORBIDDEN:

-      msg->FormatMessage(IDS_ERROR_HTTPSTATUS_FORBIDDEN, app_name, error);

-      break;

-    case GOOPDATE_E_NETWORK_PROXYAUTHREQUIRED:

-      msg->FormatMessage(IDS_ERROR_HTTPSTATUS_PROXY_AUTH_REQUIRED,

-                         app_name,

-                         error);

-      break;

-    default:

-      msg->FormatMessage(IDS_NO_NETWORK_PRESENT_ERROR,

-                         kGoopdateFileName,

-                         error);

-      return false;

-  }

-

-  return true;

-}

-

-void AddNetworkRequestDataToEventLog(NetworkRequest* network_request,

-                                     HRESULT hr) {

-  ASSERT1(network_request);

-

-  CString msg;

-  msg.Format(_T("Network Request Error.\r\n")

-             _T("Error: 0x%x. Http status code: %d.\r\n%s"),

-             hr, network_request->http_status_code(), network_request->trace());

-

-  LogEvent(static_cast<WORD>(EVENTLOG_ERROR_TYPE), kNetworkRequestEventId, msg);

-}

-

-HRESULT WriteInstallerDataToTempFile(const CString& installer_data,

-                                     CString* installer_data_file_path) {

-  ASSERT1(installer_data_file_path);

-

-  // TODO(omaha): consider eliminating the special case and simply create an

-  // empty file.

-  CORE_LOG(L2, (_T("[WriteInstallerDataToTempFile][data=%s]"), installer_data));

-  if (installer_data.IsEmpty()) {

-    return S_FALSE;

-  }

-

-  CString temp_file;

-  if (!::GetTempFileName(app_util::GetTempDir(),

-                         _T("gui"),

-                         0,

-                         CStrBuf(temp_file, MAX_PATH))) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LE, (_T("[::GetTempFileName failed][0x08%x]"), hr));

-    return hr;

-  }

-

-  scoped_handle file_handle(::CreateFile(temp_file,

-                                         GENERIC_WRITE,

-                                         FILE_SHARE_READ,

-                                         NULL,

-                                         CREATE_ALWAYS,

-                                         FILE_ATTRIBUTE_NORMAL,

-                                         NULL));

-  if (!file_handle) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LE, (_T("[::CreateFile failed][0x08%x]"), hr));

-    return hr;

-  }

-

-  CStringA installer_data_utf8_bom;

-  installer_data_utf8_bom.Format("%c%c%c%s",

-                                 0xEF, 0xBB, 0xBF, WideToUtf8(installer_data));

-  DWORD bytes_written = 0;

-  if (!::WriteFile(get(file_handle),

-                   installer_data_utf8_bom,

-                   installer_data_utf8_bom.GetLength(),

-                   &bytes_written,

-                   NULL)) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LE, (_T("[::WriteFile failed][0x08%x]"), hr));

-    return hr;

-  }

-

-  *installer_data_file_path = temp_file;

-  return S_OK;

-}

-

-HRESULT GetNumClients(bool is_machine, size_t* num_clients) {

-  ASSERT1(num_clients);

-  RegKey reg_key;

-  HKEY root_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

-  HRESULT hr = reg_key.Open(root_key, GOOPDATE_REG_RELATIVE_CLIENTS, KEY_READ);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  DWORD num_subkeys(0);

-  LONG error = ::RegQueryInfoKey(reg_key.Key(), NULL, NULL, NULL, &num_subkeys,

-                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL);

-  if (error != ERROR_SUCCESS) {

-    return HRESULT_FROM_WIN32(error);

-  }

-  *num_clients = num_subkeys;

-  return S_OK;

-}

-

-HRESULT ValidateDownloadedFile(const CString& file_name,

-                               const CString& hash,

-                               uint32 size) {

-  CORE_LOG(L3, (_T("[ValidateDownloadedFile][%s][%s][%u]"),

-                file_name, hash, size));

-  ASSERT1(File::Exists(file_name));

-

-  std::vector<CString> files;

-  files.push_back(file_name);

-  HRESULT hr = AuthenticateFiles(files, hash);

-  if (SUCCEEDED(hr)) {

-    return hr;

-  }

-

-  uint32 file_size(0);

-  if (FAILED(File::GetFileSizeUnopen(file_name, &file_size))) {

-    return hr;

-  }

-

-  if (0 == file_size) {

-    return GOOPDATEDOWNLOAD_E_FILE_SIZE_ZERO;

-  } else if (file_size < size) {

-    return GOOPDATEDOWNLOAD_E_FILE_SIZE_SMALLER;

-  } else if (file_size > size) {

-    return GOOPDATEDOWNLOAD_E_FILE_SIZE_LARGER;

-  }

-

-  ASSERT1(size == file_size);

-  return hr;

-}

-

-// Make sure this is not a silent process before calling this method.

-// Uses primary_app_name in the title if provided, otherwise displays a generic

-// title.

-void DisplayErrorInMessageBox(const CString& error_text,

-                              const CString& primary_app_name) {

-  CString msg_box_title;

-  if (primary_app_name.IsEmpty()) {

-    VERIFY1(msg_box_title.LoadString(IDS_GENERIC_INSTALLER_DISPLAY_NAME));

-  } else {

-    msg_box_title.FormatMessage(IDS_WINDOW_TITLE, primary_app_name);

-  }

-  VERIFY1(IDOK == ::MessageBox(NULL, error_text, msg_box_title, MB_OK));

-}

-

-}  // namespace goopdate_utils

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines: GoopdateUtils, helper functions for goopdate.
+
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/goopdate_utils-internal.h"
+
+#include <windows.h>
+#include <corerror.h>
+#include <lmcons.h>
+#include <atlpath.h>
+#include <atlsecurity.h>
+#include <map>
+#include <utility>
+#include <vector>
+#include "omaha/common/app_util.h"
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/const_utils.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/path.h"
+#include "omaha/common/proc_utils.h"
+#include "omaha/common/process.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/scoped_impersonation.h"
+#include "omaha/common/scoped_ptr_cotask.h"
+#include "omaha/common/service_utils.h"
+#include "omaha/common/shell.h"
+#include "omaha/common/signatures.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/time.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/common/vista_utils.h"
+#include "omaha/common/window_utils.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/event_logger.h"
+#include "omaha/goopdate/goopdate_xml_parser.h"
+#include "omaha/goopdate/resources/goopdateres/goopdate.grh"
+#include "omaha/goopdate/stats_uploader.h"
+#include "omaha/goopdate/update_response.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/network_request.h"
+
+// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".
+#include "goopdate/google_update_idl.h"
+// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".
+#include "goopdate/google_update_idl_i.c"
+
+namespace omaha {
+
+namespace goopdate_utils {
+
+namespace {
+
+const int kApplicationGuidOffset = 38;
+const int kTerminateBrowserTimeoutMs = 60000;
+
+const TCHAR* const kTrue = _T("true");
+const TCHAR* const kFalse = _T("false");
+
+// Query element name-value pair.
+typedef std::pair<CString, CString> QueryElement;
+
+// Builds a query string from the provided name-value pairs.
+// The string begins with a '&' and ends with the last value.
+// query must be empty.
+HRESULT BuildQueryString(const std::vector<QueryElement>& elements,
+                         CString* query) {
+  ASSERT1(query);
+
+  if (elements.empty() || !query->IsEmpty()) {
+    return E_INVALIDARG;
+  }
+
+  for (size_t i = 0; i < elements.size(); ++i) {
+    CString escaped_str;
+    HRESULT hr = StringEscape(elements[i].second, false, &escaped_str);
+    if (FAILED(hr)) {
+      CORE_LOG(LEVEL_WARNING, (_T("[StringEscape failed][0x%08x]"), hr));
+      return hr;
+    }
+
+    CString element;
+    element.Format(_T("%s%=%s&"), elements[i].first, escaped_str);
+    query->Append(element);
+  }
+
+  ASSERT1(!query->IsEmpty());
+  if (_T('&') == query->GetAt(query->GetLength() - 1)) {
+    query->Truncate(query->GetLength() - 1);
+  }
+
+  return S_OK;
+}
+
+bool IsMachineProcessWithoutPrivileges(bool is_machine_process) {
+  return is_machine_process && !vista_util::IsUserAdmin();
+}
+
+HRESULT LaunchImpersonatedCmdLine(const CString& cmd_line) {
+  scoped_handle impersonation_token;
+  HRESULT hr = vista::GetLoggedOnUserToken(address(impersonation_token));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  scoped_impersonation impersonate_user(get(impersonation_token));
+  hr = HRESULT_FROM_WIN32(impersonate_user.result());
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CComPtr<IProcessLauncher> launcher;
+  hr = launcher.CoCreateInstance(CLSID_ProcessLauncherClass,
+                                 NULL,
+                                 CLSCTX_LOCAL_SERVER);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return launcher->LaunchCmdLine(cmd_line);
+}
+
+HRESULT LaunchImpersonatedBrowser(BrowserType type, const CString& url) {
+  scoped_handle impersonation_token;
+  HRESULT hr = vista::GetLoggedOnUserToken(address(impersonation_token));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  scoped_impersonation impersonate_user(get(impersonation_token));
+  hr = HRESULT_FROM_WIN32(impersonate_user.result());
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CComPtr<IProcessLauncher> launcher;
+  hr = launcher.CoCreateInstance(CLSID_ProcessLauncherClass,
+                                 NULL,
+                                 CLSCTX_LOCAL_SERVER);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return launcher->LaunchBrowser(type, url);
+}
+
+// Returns an ID stored in the key_name hive with the name value_name.
+// Creates the ID in this location if it does not already exist.
+// During OEM installs, deletes any existing ID and returns a special value.
+// IsOemInstalling needs to know whether this is a machine instance but this
+// method does not know. Therefore, we use key_name. This isn't perfect, but
+// the worst that can happen is that the special value is returned for the
+// machine ID in a user instance when in "OEM mode". User instances shouldn't
+// be running in user mode, so this should never happen.
+// Ideally, we would use !CanUseNetwork instead, but this requires knowing the
+// actual value of is_machine.
+CString CreatePersistentId(const CString& key_name,
+                           const CString& value_name) {
+  const bool oem_installing_is_machine = MACHINE_KEY_NAME == key_name;
+  if (ConfigManager::Instance()->IsOemInstalling(oem_installing_is_machine)) {
+    const CString key_path = AppendRegKeyPath(key_name, GOOPDATE_MAIN_KEY);
+    RegKey::DeleteValue(key_path, value_name);
+    return _T("{00000000-03AA-03AA-03AA-000000000000}");
+  }
+
+  CString id;
+  if (SUCCEEDED(ReadPersistentId(key_name, value_name, &id))) {
+    return id;
+  }
+
+  GUID guid = GUID_NULL;
+  RegKey update_key;
+  const CString key_path = AppendRegKeyPath(key_name, GOOPDATE_MAIN_KEY);
+  if (SUCCEEDED(::CoCreateGuid(&guid))) {
+    const int guid_len = kApplicationGuidOffset;
+    TCHAR guid_string[guid_len + 1] = { _T('\0') };
+    if (::StringFromGUID2(guid, guid_string, guid_len + 1) > 0) {
+      if (SUCCEEDED(update_key.Create(key_path))) {
+        if (SUCCEEDED(update_key.SetValue(value_name, guid_string))) {
+          id = guid_string;
+        }
+      }
+    }
+  }
+  return id;
+}
+
+}  // namespace
+
+namespace internal {
+
+bool IsInstalledScheduledTask(const TCHAR* task_name) {
+  ASSERT1(task_name && *task_name);
+
+  CComPtr<ITaskScheduler> scheduler;
+  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                          NULL,
+                                          CLSCTX_INPROC_SERVER);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));
+    return false;
+  }
+
+  CComPtr<ITask> task;
+  hr = scheduler->Activate(task_name,
+                           __uuidof(ITask),
+                           reinterpret_cast<IUnknown**>(&task));
+
+  CORE_LOG(L3, (_T("[IsInstalledScheduledTask returned][0x%x]"), hr));
+  return COR_E_FILENOTFOUND == hr ? false : true;
+}
+
+HRESULT GetScheduledTaskStatus(const TCHAR* task_name) {
+  ASSERT1(task_name && *task_name);
+
+  CComPtr<ITaskScheduler> scheduler;
+  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                          NULL,
+                                          CLSCTX_INPROC_SERVER);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));
+    return hr;
+  }
+
+  CComPtr<ITask> task;
+  hr = scheduler->Activate(task_name,
+                           __uuidof(ITask),
+                           reinterpret_cast<IUnknown**>(&task));
+
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[GetScheduledTaskStatus: Activate failed][0x%x]"), hr));
+    return hr;
+  }
+
+  HRESULT task_status(S_OK);
+  hr = task->GetStatus(&task_status);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITask.GetStatus failed 0x%x"), hr));
+    return hr;
+  }
+
+  return task_status;
+}
+
+HRESULT GetScheduledTaskExitCode(const TCHAR* task_name) {
+  ASSERT1(task_name && *task_name);
+
+  CComPtr<ITaskScheduler> scheduler;
+  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                          NULL,
+                                          CLSCTX_INPROC_SERVER);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));
+    return hr;
+  }
+
+  CComPtr<ITask> task;
+  hr = scheduler->Activate(task_name,
+                           __uuidof(ITask),
+                           reinterpret_cast<IUnknown**>(&task));
+
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ITask.Activate failed][0x%x]"), hr));
+    return hr;
+  }
+
+  DWORD exit_code(0);
+  hr = task->GetExitCode(&exit_code);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("ITask.GetExitCode failed 0x%x"), hr));
+    return hr;
+  }
+
+  return hr == SCHED_S_TASK_HAS_NOT_RUN ? hr : exit_code;
+}
+
+HRESULT StartScheduledTask(const TCHAR* task_name) {
+  ASSERT1(task_name && *task_name);
+
+  if (GetScheduledTaskStatus(task_name) == SCHED_S_TASK_RUNNING) {
+    return S_OK;
+  }
+
+  CComPtr<ITaskScheduler> scheduler;
+  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                          NULL,
+                                          CLSCTX_INPROC_SERVER);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));
+    return hr;
+  }
+
+  CComPtr<ITask> task;
+  hr = scheduler->Activate(task_name,
+                           __uuidof(ITask),
+                           reinterpret_cast<IUnknown**>(&task));
+
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.Activate failed 0x%x"), hr));
+    return hr;
+  }
+
+  hr = task->Run();
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITask.Run failed 0x%x"), hr));
+    return hr;
+  }
+
+  return hr;
+}
+
+HRESULT StopScheduledTask(const TCHAR* task_name) {
+  ASSERT1(task_name && *task_name);
+
+  if (GetScheduledTaskStatus(task_name) != SCHED_S_TASK_RUNNING) {
+    return S_OK;
+  }
+
+  CComPtr<ITaskScheduler> scheduler;
+  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                          NULL,
+                                          CLSCTX_INPROC_SERVER);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));
+    return hr;
+  }
+
+  CComPtr<ITask> task;
+  hr = scheduler->Activate(task_name,
+                           __uuidof(ITask),
+                           reinterpret_cast<IUnknown**>(&task));
+
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.Activate failed 0x%x"), hr));
+    return hr;
+  }
+
+  hr = task->Terminate();
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITask.Run failed 0x%x"), hr));
+    return hr;
+  }
+
+  return hr;
+}
+
+HRESULT CreateLogonTrigger(ITask* task) {
+  ASSERT1(task);
+
+  CComPtr<ITaskTrigger> trigger;
+  WORD index = 0;
+
+  // Create a trigger to run on every user logon.
+  HRESULT hr = task->CreateTrigger(&index, &trigger);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITask.CreateTrigger failed 0x%x"), hr));
+    return hr;
+  }
+
+  TASK_TRIGGER trigger_config = {0};
+  trigger_config.cbTriggerSize = sizeof(trigger_config);
+  // These are required parameters. A past start date is good.
+  trigger_config.wBeginDay = 1;
+  trigger_config.wBeginMonth = 1;
+  trigger_config.wBeginYear = 1999;
+
+  // Run on every user logon.
+  trigger_config.TriggerType = TASK_EVENT_TRIGGER_AT_LOGON;
+
+  hr = trigger->SetTrigger(&trigger_config);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskTrigger.SetTrigger failed 0x%x"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT CreatePeriodicTrigger(ITask* task, bool create_hourly_trigger) {
+  ASSERT1(task);
+
+  CComPtr<ITaskTrigger> trigger;
+  WORD index = 0;
+
+  // Create a trigger to run every day.
+  HRESULT hr = task->CreateTrigger(&index, &trigger);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITask.CreateTrigger failed 0x%x"), hr));
+    return hr;
+  }
+
+  // Start time set to 5 minutes from the current time.
+  time64 start_time = GetCurrent100NSTime() + (5 * kMinsTo100ns);
+  SYSTEMTIME sys_time = Time64ToSystemTime(start_time);
+  SYSTEMTIME locale_time = {0};
+  hr = SystemTimeToTzSpecificLocalTime(NULL, &sys_time, &locale_time);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("SystemTimeToTzSpecificLocalTime failed 0x%x"), hr));
+    return hr;
+  }
+
+  TASK_TRIGGER trigger_config = {0};
+  trigger_config.cbTriggerSize = sizeof(trigger_config);
+  trigger_config.wBeginYear = locale_time.wYear;
+  trigger_config.wBeginMonth = locale_time.wMonth;
+  trigger_config.wBeginDay = locale_time.wDay;
+  trigger_config.wStartHour = locale_time.wHour;
+  trigger_config.wStartMinute = locale_time.wMinute;
+
+  trigger_config.TriggerType = TASK_TIME_TRIGGER_DAILY;
+  trigger_config.Type.Daily.DaysInterval = 1;  // every 1 day
+
+  if (create_hourly_trigger) {
+    // The task will be run daily at 24 hour intervals. And the task will be
+    // repeated every au_timer_interval_minutes within a single 24 hour
+    // interval.
+    const DWORD kTaskTrigger24HoursDuration = 24 * 60;
+    int au_timer_interval_minutes =
+        ConfigManager::Instance()->GetAutoUpdateTimerIntervalMs() / (60 * 1000);
+    ASSERT1(au_timer_interval_minutes > 0 &&
+            au_timer_interval_minutes < kTaskTrigger24HoursDuration);
+
+    trigger_config.MinutesDuration = kTaskTrigger24HoursDuration;
+    trigger_config.MinutesInterval = au_timer_interval_minutes;
+  }
+
+  hr = trigger->SetTrigger(&trigger_config);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskTrigger.SetTrigger failed 0x%x"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT CreateScheduledTask(ITask* task,
+                            const TCHAR* task_path,
+                            const TCHAR* task_parameters,
+                            const TCHAR* task_comment,
+                            bool is_machine,
+                            bool create_logon_trigger,
+                            bool create_daily_trigger,
+                            bool create_hourly_trigger) {
+  ASSERT1(task);
+  ASSERT1(task_path && *task_path);
+  ASSERT1(task_parameters);
+  ASSERT1(task_comment && *task_comment);
+  ASSERT1(create_logon_trigger || create_daily_trigger);
+  ASSERT1(!create_logon_trigger || (create_logon_trigger && is_machine));
+  ASSERT1(!create_hourly_trigger ||
+          (create_hourly_trigger && create_daily_trigger));
+
+  CORE_LOG(L3, (_T("CreateScheduledTask[%s][%s][%d]"),
+                task_path, task_parameters, is_machine));
+
+  HRESULT hr = task->SetApplicationName(task_path);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITask.SetApplicationName failed 0x%x"), hr));
+    return hr;
+  }
+
+  hr = task->SetParameters(task_parameters);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITask.SetParameters failed 0x%x"), hr));
+    return hr;
+  }
+
+  hr = task->SetComment(task_comment);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITask.SetComment failed 0x%x"), hr));
+    return hr;
+  }
+
+  if (is_machine) {
+    // Run using SYSTEM credentials, by passing in an empty username string.
+    hr = task->SetAccountInformation(_T(""), NULL);
+  } else {
+    // Run as current user.
+    // For the user task, we set TASK_FLAG_RUN_ONLY_IF_LOGGED_ON, so that we do
+    // not need the user password for task creation.
+    hr = task->SetFlags(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON);
+    if (FAILED(hr)) {
+      ASSERT(false, (_T("ITask.SetFlags failed 0x%x"), hr));
+      return hr;
+    }
+
+    CString user_name;
+    DWORD buffer_size = UNLEN + 1;
+    if (!::GetUserName(CStrBuf(user_name, buffer_size), &buffer_size)) {
+      hr = HRESULTFromLastError();
+      ASSERT(false, (_T("::GetUserName failed 0x%x"), hr));
+      return hr;
+    }
+    hr = task->SetAccountInformation(user_name, NULL);
+  }
+
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITask.SetAccountInformation failed 0x%x"), hr));
+    return hr;
+  }
+
+  // The default is to run for a finite number of days. We want to run
+  // indefinitely.
+  // Due to a bug introduced in Vista, and propogated to Windows 7, setting the
+  // MaxRunTime to INFINITE results in the task only running for 72 hours. For
+  // these operating systems, setting the RunTime to "INFINITE - 1" gets the
+  // desired behavior of allowing an "infinite" run of the task.
+  DWORD max_time = INFINITE - (SystemInfo::IsRunningOnVistaOrLater() ? 1 : 0);
+  hr = task->SetMaxRunTime(max_time);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITask.SetMaxRunTime failed 0x%x"), hr));
+    return hr;
+  }
+
+  CComPtr<ITaskTrigger> trigger;
+  WORD index = 0;
+
+  if (create_logon_trigger && is_machine) {
+    // Create a trigger to run on every user logon. Non-admin users are not able
+    // to create logon triggers, so we create only for machine.
+    hr = CreateLogonTrigger(task);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  if (create_daily_trigger) {
+    hr = CreatePeriodicTrigger(task, create_hourly_trigger);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  // Save task.
+  CComQIPtr<IPersistFile> persist(task);
+  if (!persist) {
+    hr = E_NOINTERFACE;
+    ASSERT(false, (_T("ITask.QueryInterface IPersistFile failed 0x%x"), hr));
+    return hr;
+  }
+
+  hr = persist->Save(NULL, TRUE);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("IPersistFile.Save failed 0x%x"), hr));
+    return hr;
+  }
+
+  if (is_machine) {
+    return S_OK;
+  }
+
+  // Adjust privileges to explicitly allow the current user to be able to
+  // manipulate this task. User applications, and consequently, Omaha, can be
+  // installed in an elevated mode. This can happen, for instance, if the user
+  // installs on XP, then upgrades to Vista. Or chooses "Run as Administrator"
+  // when running the meta-installer on Vista. Subsequently, Omaha running at
+  // medium integrity needs to be able to manipulate the installed task.
+  scoped_ptr_cotask<OLECHAR> job_file;
+  hr = persist->GetCurFile(address(job_file));
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("IPersistFile.GetCurFile failed 0x%x"), hr));
+    return hr;
+  }
+
+  persist.Release();
+
+  CAccessToken token;
+  CSid current_sid;
+  if (!token.GetEffectiveToken(TOKEN_QUERY) || !token.GetUser(&current_sid)) {
+    hr = HRESULTFromLastError();
+    ASSERT(false, (_T("[Failed to get current user sid[0x%x]"), hr));
+    return hr;
+  }
+
+  hr = AddAllowedAce(job_file.get(),
+                     SE_FILE_OBJECT,
+                     current_sid,
+                     FILE_ALL_ACCESS,
+                     0);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("Could not adjust DACL[%s][0x%x]"), job_file.get(), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT UpgradeScheduledTask(const TCHAR* task_name,
+                             const TCHAR* task_path,
+                             const TCHAR* task_parameters,
+                             const TCHAR* task_comment,
+                             bool is_machine,
+                             bool create_logon_trigger,
+                             bool create_daily_trigger,
+                             bool create_hourly_trigger) {
+  ASSERT1(task_name && *task_name);
+  ASSERT1(IsInstalledScheduledTask(task_name));
+
+  CORE_LOG(L3, (_T("UpgradeScheduledTask[%s][%s][%s][%d]"),
+                task_name, task_path, task_parameters, is_machine));
+
+  // TODO(Omaha): Perhaps pass the ITaskScheduler around where possible.
+  CComPtr<ITaskScheduler> scheduler;
+  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                          NULL,
+                                          CLSCTX_INPROC_SERVER);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));
+    return hr;
+  }
+
+  CComPtr<ITask> task;
+  hr = scheduler->Activate(task_name,
+                           __uuidof(ITask),
+                           reinterpret_cast<IUnknown**>(&task));
+
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("UpgradeScheduledTask: Activate failed[0x%x]"), hr));
+    return hr;
+  }
+
+  // Delete existing triggers. CreateScheduledTask() will recreate them anew.
+  WORD trigger_count(0);
+  hr = task->GetTriggerCount(&trigger_count);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.GetTriggerCount failed 0x%x"), hr));
+    return hr;
+  }
+
+  for (int i = 0; i < trigger_count; ++i) {
+    hr = task->DeleteTrigger(0);
+    if (FAILED(hr)) {
+      ASSERT(false, (_T("ITaskScheduler.DeleteTrigger failed 0x%x"), hr));
+      return hr;
+    }
+  }
+
+  return CreateScheduledTask(task,
+                             task_path,
+                             task_parameters,
+                             task_comment,
+                             is_machine,
+                             create_logon_trigger,
+                             create_daily_trigger,
+                             create_hourly_trigger);
+}
+
+// TODO(Omaha): Change the apis to avoid specifying hourly and daily triggers.
+HRESULT InstallScheduledTask(const TCHAR* task_name,
+                             const TCHAR* task_path,
+                             const TCHAR* task_parameters,
+                             const TCHAR* task_comment,
+                             bool is_machine,
+                             bool create_logon_trigger,
+                             bool create_daily_trigger,
+                             bool create_hourly_trigger) {
+  if (IsInstalledScheduledTask(task_name)) {
+    return UpgradeScheduledTask(task_name,
+                                task_path,
+                                task_parameters,
+                                task_comment,
+                                is_machine,
+                                create_logon_trigger,
+                                create_daily_trigger,
+                                create_hourly_trigger);
+  }
+
+  CComPtr<ITaskScheduler> scheduler;
+  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                          NULL,
+                                          CLSCTX_INPROC_SERVER);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));
+    return hr;
+  }
+
+  CComPtr<ITask> task;
+  hr = scheduler->NewWorkItem(task_name,
+                              CLSID_CTask,
+                              __uuidof(ITask),
+                              reinterpret_cast<IUnknown**>(&task));
+
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.NewWorkItem failed 0x%x"), hr));
+    return hr;
+  }
+
+  return CreateScheduledTask(task,
+                             task_path,
+                             task_parameters,
+                             task_comment,
+                             is_machine,
+                             create_logon_trigger,
+                             create_daily_trigger,
+                             create_hourly_trigger);
+}
+
+HRESULT UninstallScheduledTask(const TCHAR* task_name) {
+  ASSERT1(task_name && *task_name);
+
+  CComPtr<ITaskScheduler> scheduler;
+  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                          NULL,
+                                          CLSCTX_INPROC_SERVER);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));
+    return hr;
+  }
+
+  // Stop the task before deleting it. Ignore return value.
+  VERIFY1(SUCCEEDED(StopScheduledTask(task_name)));
+
+  // delete the task.
+  hr = scheduler->Delete(task_name);
+  if (FAILED(hr) && COR_E_FILENOTFOUND != hr) {
+    CORE_LOG(LE, (_T("GetScheduledTaskStatus: Delete failed[0x%x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT UninstallScheduledTasks(const TCHAR* task_prefix) {
+  ASSERT1(task_prefix && *task_prefix);
+
+  CComPtr<ITaskScheduler> scheduler;
+  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                          NULL,
+                                          CLSCTX_INPROC_SERVER);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.CoCreateInstance failed 0x%x"), hr));
+    return hr;
+  }
+
+  CComPtr<IEnumWorkItems> enum_items;
+  hr = scheduler->Enum(&enum_items);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("ITaskScheduler.Enum failed 0x%x"), hr));
+    return hr;
+  }
+
+  TCHAR** task_names = NULL;
+  DWORD task_count = 0;
+  while (enum_items->Next(1, &task_names, &task_count) == S_OK) {
+    ASSERT1(task_count == 1);
+    scoped_co_task_ptr task_names_guard(task_names);
+    scoped_co_task_ptr task_name_guard(task_names[0]);
+
+    if (String_StartsWith(task_names[0], task_prefix, true)) {
+      UninstallScheduledTask(task_names[0]);
+    }
+  }
+
+  return S_OK;
+}
+
+// Returns the task name Omaha used to install in Omaha 1.2.x.
+CString GetOmaha1LegacyTaskName(bool is_machine) {
+  const TCHAR* const kLegacyOmaha1TaskNameMachine = _T("GoogleUpdateTask");
+  const TCHAR* const kLegacyOmaha1TaskNameUser = _T("GoogleUpdateTaskUser");
+  return is_machine ? kLegacyOmaha1TaskNameMachine : kLegacyOmaha1TaskNameUser;
+}
+
+// Returns the task name Omaha used to install in Omaha 2 before the
+// "GoogleUpdate.exe does not run all the time" refactoring.
+CString GetOmaha2LegacyTaskName(bool is_machine) {
+  const TCHAR* kLegacyOmaha2TaskNameUserPrefix = _T("GoogleUpdateTaskUser");
+  const TCHAR* kLegacyOmaha2TaskNameMachine = _T("GoogleUpdateTaskMachine");
+  if (is_machine) {
+    return kLegacyOmaha2TaskNameMachine;
+  }
+
+  CString task_name_user = kLegacyOmaha2TaskNameUserPrefix;
+  CString user_sid;
+  VERIFY1(SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid)));
+  task_name_user += user_sid;
+  return task_name_user;
+}
+
+}  // namespace internal
+
+CString GetAppClientsKey(bool is_machine, const CString& app_guid) {
+  return AppendRegKeyPath(
+      ConfigManager::Instance()->registry_clients(is_machine),
+      app_guid);
+}
+
+CString GetAppClientStateKey(bool is_machine, const CString& app_guid) {
+  return AppendRegKeyPath(
+      ConfigManager::Instance()->registry_client_state(is_machine),
+      app_guid);
+}
+
+CString GetAppClientStateMediumKey(bool is_machine, const CString& app_guid) {
+  ASSERT1(is_machine);
+  UNREFERENCED_PARAMETER(is_machine);
+  return AppendRegKeyPath(
+      ConfigManager::Instance()->machine_registry_client_state_medium(),
+      app_guid);
+}
+
+// Returns the application registration location given the user SID.
+CString GetUserAllAppsStatePath(const CString& user_sid) {
+  return AppendRegKeyPath(USERS_KEY, user_sid,
+                          GOOPDATE_REG_RELATIVE_CLIENT_STATE);
+}
+
+// Returns the application state path for a user given the user SID.
+CString GetUserAllAppsRegPath(const CString& user_sid) {
+  return AppendRegKeyPath(USERS_KEY, user_sid, GOOPDATE_REG_RELATIVE_CLIENTS);
+}
+
+// Returns the application state path for a particular user and for the
+// given application id.
+CString GetUserAppStatePath(const CString& user_sid,
+                            const CString& app_guid) {
+  return AppendRegKeyPath(GetUserAllAppsStatePath(user_sid), app_guid);
+}
+
+// Returns the application registrration path for a particular user
+// and for the given application id.
+CString GetUserAppRegPath(const CString& user_sid,
+                          const CString& app_guid) {
+  return AppendRegKeyPath(GetUserAllAppsRegPath(user_sid), app_guid);
+}
+
+CString BuildGoogleUpdateExeDir(bool is_machine) {
+  ConfigManager& cm = *ConfigManager::Instance();
+  return is_machine ? cm.GetMachineGoopdateInstallDir() :
+                      cm.GetUserGoopdateInstallDir();
+}
+
+CString BuildGoogleUpdateExePath(bool is_machine) {
+  CORE_LOG(L3, (_T("[BuildGoogleUpdateExePath][%d]"), is_machine));
+
+  CPath full_file_path(BuildGoogleUpdateExeDir(is_machine));
+  VERIFY1(full_file_path.Append(kGoopdateFileName));
+
+  return full_file_path;
+}
+
+CString BuildGoogleUpdateServicesPath(bool is_machine) {
+  CORE_LOG(L3, (_T("[BuildGoogleUpdateServicesPath][%d]"), is_machine));
+
+  CPath full_file_path(
+      goopdate_utils::BuildInstallDirectory(is_machine, GetVersionString()));
+  VERIFY1(full_file_path.Append(kGoopdateCrashHandlerFileName));
+
+  return full_file_path;
+}
+
+HRESULT StartElevatedSelfWithArgsAndWait(const TCHAR* args) {
+  ASSERT1(args);
+  CORE_LOG(L3, (_T("[StartElevatedSelfWithArgsAndWait]")));
+
+  // Get the process executable.
+  TCHAR filename[MAX_PATH] = {0};
+  if (::GetModuleFileName(NULL, filename, MAX_PATH) == 0) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LEVEL_ERROR, (_T("[GetModuleFileName failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Launch self elevated and wait.
+  DWORD exit_code = 0;
+  CORE_LOG(L1,
+      (_T("[RunElevated filename='%s'][arguments='%s']"), filename, args));
+  // According to the MSDN documentation for ::ShowWindow: "nCmdShow. This
+  // parameter is ignored the first time an application calls ShowWindow, if
+  // the program that launched the application provides a STARTUPINFO
+  // structure.". We want to force showing the UI window. So we pass in
+  // SW_SHOWNORMAL.
+  HRESULT hr = vista_util::RunElevated(filename,
+                                       args,
+                                       SW_SHOWNORMAL,
+                                       &exit_code);
+  CORE_LOG(L2, (_T("[elevated instance exit code][%u]"), exit_code));
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_ERROR, (_T("[RunElevated failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT StartGoogleUpdateWithArgs(bool is_machine,
+                                  const TCHAR* args,
+                                  HANDLE* process) {
+  CORE_LOG(L3, (_T("[StartGoogleUpdateWithArgs][%d][%s]"),
+                is_machine, args ? args : _T("")));
+
+  CString exe_path = BuildGoogleUpdateExePath(is_machine);
+
+  CORE_LOG(L3, (_T("[command line][%s][%s]"), exe_path, args ? args : _T("")));
+
+  HRESULT hr = System::ShellExecuteProcess(exe_path, args, NULL, process);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[can't start process][%s][0x%08x]"), exe_path, hr));
+    return hr;
+  }
+  return S_OK;
+}
+
+bool IsRunningFromOfficialGoopdateDir(bool is_machine) {
+  const ConfigManager& cm = *ConfigManager::Instance();
+  bool is_official_dir = is_machine ?
+                         cm.IsRunningFromMachineGoopdateInstallDir() :
+                         cm.IsRunningFromUserGoopdateInstallDir();
+  CORE_LOG(L3, (_T("[running from official dir][%d]"), is_official_dir));
+  return is_official_dir;
+}
+
+CString GetHKRoot() {
+  return IsRunningFromOfficialGoopdateDir(true) ? _T("HKLM") : _T("HKCU");
+}
+
+HRESULT InitializeSecurity() {
+  // Creates a security descriptor in absolute format and includes the owner
+  // and the primary group.  We grant access to admins and system.
+  CSecurityDesc security_descriptor;
+  if (SystemInfo::IsRunningOnVistaOrLater()) {
+    // To allow for low-integrity IE to call into IGoogleUpdate.
+    security_descriptor.FromString(LOW_INTEGRITY_SDDL_SACL);
+  }
+  security_descriptor.SetOwner(Sids::Admins());
+  security_descriptor.SetGroup(Sids::Admins());
+  CDacl dacl;
+  dacl.AddAllowedAce(Sids::System(), COM_RIGHTS_EXECUTE);
+  dacl.AddAllowedAce(Sids::Admins(), COM_RIGHTS_EXECUTE);
+  dacl.AddAllowedAce(Sids::AuthenticatedUser(), COM_RIGHTS_EXECUTE);
+
+  security_descriptor.SetDacl(dacl);
+  security_descriptor.MakeAbsolute();
+
+  SECURITY_DESCRIPTOR* sd = const_cast<SECURITY_DESCRIPTOR*>(
+      security_descriptor.GetPSECURITY_DESCRIPTOR());
+
+  return ::CoInitializeSecurity(
+      sd,
+      -1,
+      NULL,   // Let COM choose what authentication services to register.
+      NULL,
+      RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  // Data integrity and encryption.
+      RPC_C_IMP_LEVEL_IDENTIFY,       // Only allow a server to identify.
+      NULL,
+      EOAC_DYNAMIC_CLOAKING | EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL,
+      NULL);
+}
+
+// This is only used for legacy handoff support.
+CString GetProductName(const CString& app_guid) {
+  const TCHAR* product_name = NULL;
+  const TCHAR gears_guid[]   = _T("{283EAF47-8817-4c2b-A801-AD1FADFB7BAA}");
+  const TCHAR google_talk_plugin[]  =
+      _T("{D0AB2EBC-931B-4013-9FEB-C9C4C2225C8C}");
+  const TCHAR youtube_uploader_guid[] =
+      _T("{A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}");
+
+  if (app_guid.CompareNoCase(gears_guid) == 0) {
+    product_name = _T("Gears");
+  } else if (app_guid.CompareNoCase(google_talk_plugin) == 0) {
+      product_name = _T("Google Talk Plugin");
+  } else if (app_guid.CompareNoCase(youtube_uploader_guid) == 0) {
+      product_name = _T("YouTube Uploader");
+  } else {
+      product_name = _T("Google App");
+  }
+  return product_name;
+}
+
+HRESULT ReadPersistentId(const CString& key_name,
+                         const CString& value_name,
+                         CString* id) {
+  ASSERT1(id);
+  CString key_path = AppendRegKeyPath(key_name, GOOPDATE_MAIN_KEY);
+  return RegKey::GetValue(key_path, value_name, id);
+}
+
+CString GetPersistentUserId(const CString& key_name) {
+  return CreatePersistentId(key_name, kRegValueUserId);
+}
+
+CString GetPersistentMachineId() {
+  return CreatePersistentId(MACHINE_KEY_NAME, kRegValueMachineId);
+}
+
+HRESULT BuildHttpGetString(const CString& url,
+                           DWORD error_code,
+                           DWORD extra_code1,
+                           DWORD extra_code2,
+                           const CString& app_guid,
+                           const CString& goopdate_version,
+                           bool is_machine,
+                           const CString& language,
+                           const CString& source_id,
+                           CString* get_request) {
+  ASSERT1(get_request);
+  if (url.IsEmpty()) {
+    return E_INVALIDARG;
+  }
+  ASSERT1(_T('?') == url.GetAt(url.GetLength() - 1) ||
+          _T('&') == url.GetAt(url.GetLength() - 1));
+
+  CString errorcode_str;
+  CString extracode1_str;
+  CString extracode2_str;
+  errorcode_str.Format(_T("0x%08x"), error_code);
+  extracode1_str.Format(_T("0x%08x"), extra_code1);
+  extracode2_str.Format(_T("%u"), extra_code2);
+
+  CString os_version;
+  CString service_pack;
+  HRESULT hr = GetOSInfo(&os_version, &service_pack);
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_WARNING, (_T("[GetOSInfo failed][0x%08x]"), hr));
+  }
+  CString mid = GetPersistentMachineId();
+  CString uid = GetPersistentUserId(is_machine ? MACHINE_KEY_NAME :
+                                                 USER_KEY_NAME);
+  CString iid;
+  CString state_key_name = GetAppClientStateKey(is_machine, app_guid);
+  // Ignore the return value because it may not exist.
+  RegKey::GetValue(state_key_name, kRegValueInstallationId, &iid);
+
+  std::vector<QueryElement> elements;
+  elements.push_back(QueryElement(_T("hl"), language));
+  elements.push_back(QueryElement(_T("errorcode"), errorcode_str));
+  elements.push_back(QueryElement(_T("extracode1"), extracode1_str));
+  elements.push_back(QueryElement(_T("extracode2"), extracode2_str));
+  elements.push_back(QueryElement(_T("app"), app_guid));
+  elements.push_back(QueryElement(_T("guver"), goopdate_version));
+  elements.push_back(QueryElement(_T("ismachine"),
+                                  is_machine ? _T("1") : _T("0")));
+  elements.push_back(QueryElement(_T("os"), os_version));
+  elements.push_back(QueryElement(_T("sp"), service_pack));
+  elements.push_back(QueryElement(_T("mid"), mid));
+  elements.push_back(QueryElement(_T("uid"), uid));
+  elements.push_back(QueryElement(_T("iid"), iid));
+  elements.push_back(QueryElement(_T("source"), source_id));
+
+  CString test_source = ConfigManager::Instance()->GetTestSource();
+  if (!test_source.IsEmpty()) {
+    elements.push_back(QueryElement(_T("testsource"), test_source));
+  }
+
+  CString query;
+  hr = BuildQueryString(elements, &query);
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_WARNING, (_T("[BuildQueryString failed][0x%08x]"), hr));
+    return hr;
+  }
+  get_request->Format(_T("%s%s"), url, query);
+
+  // The length should be smaller than the maximum allowed get length.
+  ASSERT1(get_request->GetLength() <= INTERNET_MAX_URL_LENGTH);
+  if (get_request->GetLength() > INTERNET_MAX_URL_LENGTH) {
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+HRESULT RedirectHKCR(bool is_machine) {
+  RegKey classes_key;
+  HRESULT hr = classes_key.Open(is_machine ?
+                                HKEY_LOCAL_MACHINE :
+                                HKEY_CURRENT_USER,
+                                _T("Software\\Classes"),
+                                KEY_ALL_ACCESS);
+  if (FAILED(hr)) {
+    ASSERT(FALSE, (_T("RedirectHKCR - key.Open(%d) fail %d"), is_machine, hr));
+    return hr;
+  }
+
+  LONG result = ::RegOverridePredefKey(HKEY_CLASSES_ROOT, classes_key.Key());
+  if (result != ERROR_SUCCESS) {
+    ASSERT(false, (_T("RedirectHKCR - RegOverridePredefKey fail %d"), result));
+    return HRESULT_FROM_WIN32(result);
+  }
+
+  return S_OK;
+}
+
+HRESULT RemoveRedirectHKCR() {
+  LONG result = ::RegOverridePredefKey(HKEY_CLASSES_ROOT, NULL);
+  if (result != ERROR_SUCCESS) {
+    ASSERT(FALSE, (_T("RemoveRedirectHKCR - RegOverridePredefKey %d"), result));
+    return HRESULT_FROM_WIN32(result);
+  }
+
+  return S_OK;
+}
+
+HRESULT RegisterTypeLib(bool is_admin,
+                        const CComBSTR& path,
+                        ITypeLib* type_lib) {
+  // Typelib registration.
+  CORE_LOG(L3, (_T("[Registering TypeLib]")));
+  HRESULT hr = S_OK;
+  if (!is_admin &&
+      SUCCEEDED(goopdate_utils::RegisterTypeLibForUser(type_lib, path, NULL))) {
+    return S_OK;
+  }
+
+  // For Admin cases, we use ::RegisterTypeLib().
+  // For platforms where ::RegisterTypeLibForUser is not available, we register
+  // with ::RegisterTypeLib, and rely on HKCR=>HKCU redirection.
+  hr = ::RegisterTypeLib(type_lib, path, NULL);
+  ASSERT(SUCCEEDED(hr), (_T("[TypeLib registration failed][0x%08x]"), hr));
+  return hr;
+}
+
+HRESULT UnRegisterTypeLib(bool is_admin, const CComBSTR&, ITypeLib* type_lib) {
+  // Typelib unregistration.
+  CORE_LOG(L3, (_T("[Unregistering Typelib]")));
+  TLIBATTR* tlib_attr = NULL;
+  HRESULT hr = type_lib->GetLibAttr(&tlib_attr);
+  ASSERT(SUCCEEDED(hr), (_T("[GetLibAttr failed][0x%08x]"), hr));
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ON_SCOPE_EXIT_OBJ(*type_lib, &ITypeLib::ReleaseTLibAttr, tlib_attr);
+
+  if (!is_admin &&
+      SUCCEEDED(goopdate_utils::UnRegisterTypeLibForUser(
+          tlib_attr->guid,
+          tlib_attr->wMajorVerNum,
+          tlib_attr->wMinorVerNum,
+          tlib_attr->lcid,
+          tlib_attr->syskind))) {
+    return S_OK;
+  }
+
+  // For Admin cases, we use ::UnRegisterTypeLib().
+  // For platforms where ::UnRegisterTypeLibForUser is not available, we
+  // unregister with ::UnRegisterTypeLib, and rely on HKCR=>HKCU redirection.
+  hr = ::UnRegisterTypeLib(tlib_attr->guid,
+                           tlib_attr->wMajorVerNum,
+                           tlib_attr->wMinorVerNum,
+                           tlib_attr->lcid,
+                           tlib_attr->syskind);
+
+  // We assert before the check for TYPE_E_REGISTRYACCESS below because we want
+  // to catch the case where we're trying to unregister more than once because
+  // that would be a bug.
+  ASSERT(SUCCEEDED(hr),
+         (_T("[UnRegisterTypeLib failed.  ")
+          _T("This is likely a multiple unregister bug.][0x%08x]"), hr));
+
+  // If you try to unregister a type library that's already unregistered,
+  // it will return with this failure, which is OK.
+  if (hr == TYPE_E_REGISTRYACCESS) {
+    hr = S_OK;
+  }
+
+  return hr;
+}
+
+HRESULT RegisterOrUnregisterModule(bool register_server,
+                                   RegisterOrUnregisterFunction registrar) {
+  ASSERT1(registrar);
+
+  bool is_machine = IsRunningFromOfficialGoopdateDir(true);
+  // ATL by default registers the control to HKCR and we want to register
+  // either in HKLM, or in HKCU, depending on whether we are laying down
+  // the system googleupdate, or the user googleupdate.
+  // We solve this for the user goopdate case by:
+  // * Having the RGS file take a HKROOT parameter that translates to either
+  //   HKLM or HKCU.
+  // * Redirecting HKCR to HKCU\software\classes, for a user installation, to
+  //   cover Proxy registration.
+  // For the machine case, we still redirect HKCR to HKLM\\Software\\Classes,
+  // to ensure that Proxy registration happens in HKLM.
+  HRESULT hr = RedirectHKCR(is_machine);
+  ASSERT1(SUCCEEDED(hr));
+  if (FAILED(hr)) {
+    return hr;
+  }
+  // We need to stop redirecting at the end of this function.
+  ON_SCOPE_EXIT(RemoveRedirectHKCR);
+
+  hr = (*registrar)(register_server);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[RegisterOrUnregisterModule failed][%d][0x%08x]"),
+                  register_server, hr));
+    ASSERT1(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr && !register_server);
+  }
+
+  return hr;
+}
+
+HRESULT RegisterOrUnregisterModuleWithTypelib(
+    bool register_server,
+    RegisterOrUnregisterFunction registrar) {
+  ASSERT1(registrar);
+
+  bool is_machine = IsRunningFromOfficialGoopdateDir(true);
+  // By default, ATL registers the control to HKCR and we want to register
+  // either in HKLM, or in HKCU, depending on whether we are laying down
+  // the machine googleupdate, or the user googleupdate.
+  // We solve this for the user goopdate case by:
+  // * Having the RGS file take a HKROOT parameter that translates to either
+  //   HKLM or HKCU.
+  // * Redirecting HKCR to HKCU\software\classes, for a user installation, to
+  //   cover AppId and TypeLib registration
+  // * All the above makes ATL work correctly for 2K/XP. However on Win2K3
+  //   and Vista, redirection does not work by itself, because in these
+  //   platforms, RegisterTypeLib writes explicitly to HKLM\Software\Classes.
+  //   We need to specifically call the new RegisterTypeLibForUser() API.
+  //   So, we do that as well.
+  // For the machine case, we still redirect HKCR to HKLM\\Software\\Classes,
+  // because otherwise RegisterTypeLib ends up overwriting HKCU if the key
+  // already exists in HKCU.
+  HRESULT hr = RedirectHKCR(is_machine);
+  ASSERT1(SUCCEEDED(hr));
+  if (FAILED(hr)) {
+    return hr;
+  }
+  // We need to stop redirecting at the end of this function.
+  ON_SCOPE_EXIT(RemoveRedirectHKCR);
+
+  // load the type library.
+  CComPtr<ITypeLib> type_lib;
+  CComBSTR path;
+  hr = ::AtlLoadTypeLib(_AtlBaseModule.GetModuleInstance(), NULL, &path,
+                        &type_lib);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("[AtlLoadTypeLib failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (register_server) {
+    hr = (*registrar)(register_server);
+    if (FAILED(hr)) {
+      ASSERT(false, (_T("[Module registration failed][0x%08x]"), hr));
+      return hr;
+    }
+
+    return RegisterTypeLib(is_machine, path, type_lib);
+  } else {
+    hr = UnRegisterTypeLib(is_machine, path, type_lib);
+    if (FAILED(hr)) {
+      ASSERT(false, (_T("[UnRegisterTypeLib failed][0x%08x]"), hr));
+      return hr;
+    }
+
+    return (*registrar)(register_server);
+  }
+}
+
+HRESULT RegisterTypeLibForUser(ITypeLib* lib,
+                               OLECHAR* path,
+                               OLECHAR* help_dir) {
+  CORE_LOG(L3, (_T("[RegisterTypeLibForUser]")));
+  ASSERT1(lib);
+  ASSERT1(path);
+  // help_dir can be NULL.
+
+  const TCHAR* library_name = _T("oleaut32.dll");
+  scoped_library module(static_cast<HINSTANCE>(::LoadLibrary(library_name)));
+  if (!module) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LEVEL_ERROR,
+        (_T("[LoadLibrary failed][%s][0x%08x]"), library_name, hr));
+    return hr;
+  }
+
+  // RegisterTypeLibForUser function from oleaut32.dll.
+  typedef HRESULT(__stdcall *PF)(ITypeLib*, OLECHAR*, OLECHAR*);
+
+  const char* function_name = "RegisterTypeLibForUser";
+  PF fp = reinterpret_cast<PF>(::GetProcAddress(get(module), function_name));
+  if (!fp) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LEVEL_ERROR,
+             (_T("[GetProcAddress failed][%s][0x%08x]"),
+              function_name, library_name, hr));
+    return hr;
+  }
+
+  CORE_LOG(L3, (_T("[Calling RegisterTypelibForUser in oleaut]")));
+  HRESULT hr = fp(lib, path, help_dir);
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_ERROR, (_T("[regtypelib_for_user failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT UnRegisterTypeLibForUser(REFGUID lib_id,
+                                 WORD major_ver_num,
+                                 WORD minor_ver_num,
+                                 LCID lcid,
+                                 SYSKIND syskind) {
+  CORE_LOG(L3, (_T("[UnRegisterTypeLibForUser]")));
+
+  const TCHAR* library_name = _T("oleaut32.dll");
+  scoped_library module(static_cast<HINSTANCE>(::LoadLibrary(library_name)));
+  if (!module) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LEVEL_ERROR,
+        (_T("[LoadLibrary failed][%s][0x%08x]"), library_name, hr));
+    return hr;
+  }
+
+  // UnRegisterTypeLibForUser function from oleaut32.dll.
+  typedef HRESULT (__stdcall *PF)(REFGUID, WORD, WORD, LCID, SYSKIND);
+
+  const char* function_name = "UnRegisterTypeLibForUser";
+  PF fp = reinterpret_cast<PF>(::GetProcAddress(get(module), function_name));
+  if (!fp) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LEVEL_ERROR,
+             (_T("[GetProcAddress failed][%s][0x%08x]"),
+              function_name, library_name, hr));
+    return hr;
+  }
+
+  CORE_LOG(L3, (_T("[Calling UnRegisterTypeLibForUser in oleaut]")));
+  HRESULT hr = fp(lib_id, major_ver_num, minor_ver_num, lcid, syskind);
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_ERROR, (_T("[unregtypelib_for_user failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// This method assumes that the caller has permissions to open
+// the process token of the user's explorer.exe process.
+HRESULT GetImpersonationToken(bool is_interactive,
+                              uint32 explorer_pid,
+                              HANDLE* out_token) {
+  CORE_LOG(L3, (_T("[GetImpersonationToken]")));
+  ASSERT1(out_token);
+
+  // If the job is an interactive job, then we can use the explorer pid
+  // that is passed in for impersonation. If this is an
+  // update job, then we need to get a list of all the logged on users
+  // and pick one to perform the impersonation.
+  // TODO(omaha): Try to use the token of the user that is a domain account,
+  // since we are trying to solve the integrated proxy authentication issue.
+  // One way to do this might be to try the GetWindowsAccountDomainSid API.
+  if (is_interactive) {
+    scoped_handle exp(::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
+                                    false, explorer_pid));
+    if (!exp) {
+      HRESULT hr = HRESULTFromLastError();
+      CORE_LOG(LEVEL_ERROR, (_T("[OpenProcess failed][0x%08x]"), hr));
+      return hr;
+    }
+
+    if (!::OpenProcessToken(get(exp),
+                            TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
+                            out_token)) {
+      HRESULT hr = HRESULTFromLastError();
+      CORE_LOG(LEVEL_ERROR, (_T("[OpenProcessToken failed][0x%08x]"), hr));
+      return hr;
+    }
+  } else {
+    HRESULT hr = vista::GetExplorerTokenForLoggedInUser(out_token);
+    if (FAILED(hr)) {
+      CORE_LOG(LEVEL_ERROR, (_T("[GetExplorerTokenForLoggedInUser failed]")
+                             _T("[0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT UndoImpersonation(bool impersonated) {
+  CORE_LOG(L3, (_T("[UndoImpersonation]")));
+
+  if (impersonated && !::RevertToSelf()) {
+    // TODO(omaha): For now we assume that this never fails, change this
+    // impersonation to occur on a different thread, so that even if this fails,
+    // we can simply kill the thread.
+    // If this function call fails, we have a problem. We need to shut down the
+    // googleupdate process, since we are now running the system googleupdate
+    // as the user, and a number of assumptions about the code will fail.
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LEVEL_ERROR, (_T("[RevertToSelf failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT ImpersonateUser(bool is_interactive, uint32 explorer_pid) {
+  CORE_LOG(L3, (_T("[ImpersonateUser]")));
+
+  HANDLE handle = NULL;
+  HRESULT hr = GetImpersonationToken(is_interactive, explorer_pid, &handle);
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_ERROR, (_T("[GetImpersonationToken failed][0x%08x]"), hr));
+    return hr;
+  }
+  ASSERT1(handle);
+
+  // TODO(omaha): The impersonation will fail if the user is running on a
+  // Win2K SP3 or earlier, or WinXP SP1 or earlier. This is because the
+  // seImpersonateProvilage is needed to call this method, and this privilege
+  // does not exist in these systems.
+  // One way to work around this would be to launch a separate process
+  // using CreateProcessAsUser on these systems.
+  scoped_handle token(handle);
+  if (!::ImpersonateLoggedOnUser(get(token))) {
+    hr = HRESULTFromLastError();
+    CORE_LOG(LEVEL_ERROR, (_T("[ImpersonateLoggedOnUser failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// The EULA is assumed to be accepted unless eualaccepted=0 in the ClientState
+// key. For machine apps in this case, eulaccepted=1 in ClientStateMedium also
+// indicates acceptance and the value in ClientState is updated.
+bool IsAppEulaAccepted(bool is_machine,
+                       const CString& app_guid,
+                       bool require_explicit_acceptance) {
+  const CString state_key = GetAppClientStateKey(is_machine, app_guid);
+
+  DWORD eula_accepted = 0;
+  if (SUCCEEDED(RegKey::GetValue(state_key,
+                                 kRegValueEulaAccepted,
+                                 &eula_accepted))) {
+    if (0 != eula_accepted) {
+      return true;
+    }
+  } else {
+    if (!require_explicit_acceptance) {
+      return true;
+    }
+  }
+
+  if (!is_machine) {
+    return false;
+  }
+
+  eula_accepted = 0;
+  if (SUCCEEDED(RegKey::GetValue(
+                    GetAppClientStateMediumKey(is_machine, app_guid),
+                    kRegValueEulaAccepted,
+                    &eula_accepted))) {
+    if (0 == eula_accepted) {
+      return false;
+    }
+  } else {
+    return false;
+  }
+
+  VERIFY1(SUCCEEDED(RegKey::SetValue(state_key,
+                                     kRegValueEulaAccepted,
+                                     eula_accepted)));
+  return true;
+}
+
+// Does not need to set ClientStateMedium.
+HRESULT SetAppEulaNotAccepted(bool is_machine, const CString& app_guid) {
+  return RegKey::SetValue(GetAppClientStateKey(is_machine, app_guid),
+                          kRegValueEulaAccepted,
+                          static_cast<DWORD>(0));
+}
+
+// Deletes eulaaccepted from ClientState and ClientStateMedium.
+HRESULT ClearAppEulaNotAccepted(bool is_machine, const CString& app_guid) {
+  const CString state_key = GetAppClientStateKey(is_machine, app_guid);
+  if (RegKey::HasKey(state_key)) {
+    HRESULT hr = RegKey::DeleteValue(state_key, kRegValueEulaAccepted);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  if (!is_machine) {
+    return S_OK;
+  }
+
+  const CString state_medium_key =
+      GetAppClientStateMediumKey(is_machine, app_guid);
+  if (RegKey::HasKey(state_medium_key)) {
+    HRESULT hr = RegKey::DeleteValue(state_medium_key, kRegValueEulaAccepted);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+// For machine apps, ClientStateMedium takes precedence.
+// Does not propogate the ClientStateMedium value to ClientState.
+bool AreAppUsageStatsEnabled(bool is_machine, const CString& app_guid) {
+  if (is_machine) {
+    DWORD stats_enabled = 0;
+    if (SUCCEEDED(RegKey::GetValue(GetAppClientStateMediumKey(is_machine,
+                                                              app_guid),
+                                   kRegValueUsageStats,
+                                   &stats_enabled))) {
+      return (TRISTATE_TRUE == stats_enabled);
+    }
+  }
+
+  DWORD stats_enabled = 0;
+  if (SUCCEEDED(RegKey::GetValue(GetAppClientStateKey(is_machine, app_guid),
+                              kRegValueUsageStats,
+                              &stats_enabled))) {
+    return (TRISTATE_TRUE == stats_enabled);
+  }
+
+  return false;
+}
+
+// Does nothing if usage_stats_enable is TRISTATE_NONE.
+// For machine apps, clears ClientStateMedium because the app may be reading it
+// if present.
+HRESULT SetUsageStatsEnable(bool is_machine,
+                            const CString& app_guid,
+                            Tristate usage_stats_enable) {
+  if (TRISTATE_NONE == usage_stats_enable) {
+    return S_OK;
+  }
+
+  const DWORD stats_enabled = (TRISTATE_TRUE == usage_stats_enable) ? 1 : 0;
+
+  HRESULT hr = RegKey::SetValue(GetAppClientStateKey(is_machine, app_guid),
+                                kRegValueUsageStats,
+                                stats_enabled);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[Failed to set usagestats][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (!is_machine) {
+    return S_OK;
+  }
+
+  const CString state_medium_key =
+      GetAppClientStateMediumKey(is_machine, app_guid);
+  if (RegKey::HasKey(state_medium_key)) {
+    hr = RegKey::DeleteValue(state_medium_key, kRegValueUsageStats);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+// Writes usagestats in Google Update's ClientState key. This is the only case
+// in which usagestats is written to Google Update's ClientState key. Normally,
+// we write to the ClientState key(s) for the specific app(s).
+HRESULT ConvertLegacyUsageStats(bool is_machine) {
+  DWORD existing_usage_stats(0);
+
+  ConfigManager& config_mgr = *ConfigManager::Instance();
+  const CString legacy_key_name = config_mgr.registry_update(is_machine);
+  if (FAILED(RegKey::GetValue(legacy_key_name,
+                              kLegacyRegValueCollectUsageStats,
+                              &existing_usage_stats))) {
+    return S_OK;
+  }
+
+  const CString new_key_name = GetAppClientStateKey(is_machine,
+                                                    kGoogleUpdateAppId);
+  HRESULT hr = RegKey::SetValue(new_key_name,
+                                kRegValueUsageStats,
+                                existing_usage_stats);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  VERIFY1(SUCCEEDED(RegKey::DeleteValue(legacy_key_name,
+                                        kLegacyRegValueCollectUsageStats)));
+  return S_OK;
+}
+
+CString GetDefaultGoopdateTaskName(bool is_machine, CommandLineMode mode) {
+  ASSERT1(mode == COMMANDLINE_MODE_CORE || mode == COMMANDLINE_MODE_UA);
+
+  CString task_name;
+  if (is_machine) {
+    task_name = kScheduledTaskNameMachinePrefix;
+  } else {
+    task_name = kScheduledTaskNameUserPrefix;
+    CString user_sid;
+    VERIFY1(SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid)));
+    task_name += user_sid;
+  }
+
+  task_name += (mode == COMMANDLINE_MODE_CORE) ? kScheduledTaskNameCoreSuffix :
+                                                 kScheduledTaskNameUASuffix;
+  return task_name;
+}
+
+HRESULT InstallGoopdateTaskForMode(const TCHAR* task_path,
+                                   bool is_machine,
+                                   CommandLineMode mode) {
+  ASSERT1(mode == COMMANDLINE_MODE_CORE || mode == COMMANDLINE_MODE_UA);
+
+  CommandLineBuilder builder(mode);
+  if (mode == COMMANDLINE_MODE_UA) {
+    builder.set_install_source(kCmdLineInstallSourceScheduler);
+  }
+
+  CString task_description;
+  VERIFY1(task_description.LoadString(IDS_SCHEDULED_TASK_DESCRIPTION));
+
+  CString task_name(mode == COMMANDLINE_MODE_CORE ?
+                    ConfigManager::GetCurrentTaskNameCore(is_machine) :
+                    ConfigManager::GetCurrentTaskNameUA(is_machine));
+  if (internal::IsInstalledScheduledTask(task_name)) {
+    HRESULT hr = internal::InstallScheduledTask(task_name,
+                                                task_path,
+                                                builder.GetCommandLineArgs(),
+                                                task_description,
+                                                is_machine,
+                                                mode == COMMANDLINE_MODE_CORE &&
+                                                is_machine,
+                                                true,
+                                                mode == COMMANDLINE_MODE_UA);
+
+    if (SUCCEEDED(hr)) {
+      return hr;
+    }
+
+    // Try to uninstall the task that we failed to upgrade. Then create a new
+    // task name, and fall through to install that.
+    internal::UninstallScheduledTask(task_name);
+    if (mode == COMMANDLINE_MODE_CORE) {
+      VERIFY1(SUCCEEDED(
+      ConfigManager::CreateAndSetVersionedTaskNameCoreInRegistry(is_machine)));
+      task_name = ConfigManager::GetCurrentTaskNameCore(is_machine);
+    } else {
+      VERIFY1(SUCCEEDED(
+      ConfigManager::CreateAndSetVersionedTaskNameUAInRegistry(is_machine)));
+      task_name = ConfigManager::GetCurrentTaskNameUA(is_machine);
+    }
+    ASSERT1(!internal::IsInstalledScheduledTask(task_name));
+  }
+
+  return internal::InstallScheduledTask(task_name,
+                                        task_path,
+                                        builder.GetCommandLineArgs(),
+                                        task_description,
+                                        is_machine,
+                                        mode == COMMANDLINE_MODE_CORE &&
+                                        is_machine,
+                                        true,
+                                        mode == COMMANDLINE_MODE_UA);
+}
+
+HRESULT InstallGoopdateTasks(const TCHAR* task_path, bool is_machine) {
+  HRESULT hr = InstallGoopdateTaskForMode(task_path,
+                                          is_machine,
+                                          COMMANDLINE_MODE_CORE);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return InstallGoopdateTaskForMode(task_path, is_machine, COMMANDLINE_MODE_UA);
+}
+
+HRESULT UninstallGoopdateTasks(bool is_machine) {
+  VERIFY1(SUCCEEDED(internal::UninstallScheduledTask(
+      ConfigManager::GetCurrentTaskNameCore(is_machine))));
+  VERIFY1(SUCCEEDED(internal::UninstallScheduledTask(
+      ConfigManager::GetCurrentTaskNameUA(is_machine))));
+
+  // Try to uninstall any tasks that we failed to update during a previous
+  // overinstall. It is possible that we fail to uninstall these again here.
+  VERIFY1(SUCCEEDED(internal::UninstallScheduledTasks(
+      goopdate_utils::GetDefaultGoopdateTaskName(is_machine,
+                                                 COMMANDLINE_MODE_CORE))));
+  VERIFY1(SUCCEEDED(internal::UninstallScheduledTasks(
+      goopdate_utils::GetDefaultGoopdateTaskName(is_machine,
+                                                 COMMANDLINE_MODE_UA))));
+  return S_OK;
+}
+
+HRESULT UninstallLegacyGoopdateTasks(bool is_machine) {
+  const CString& legacy_omaha1_task =
+      internal::GetOmaha1LegacyTaskName(is_machine);
+  VERIFY1(SUCCEEDED(internal::UninstallScheduledTask(legacy_omaha1_task)));
+
+  const CString& legacy_omaha2_task =
+      internal::GetOmaha2LegacyTaskName(is_machine);
+  VERIFY1(SUCCEEDED(internal::UninstallScheduledTask(legacy_omaha2_task)));
+
+  return S_OK;
+}
+
+HRESULT StartGoopdateTaskCore(bool is_machine) {
+  return internal::StartScheduledTask(
+             ConfigManager::GetCurrentTaskNameCore(is_machine));
+}
+
+bool IsInstalledGoopdateTaskUA(bool is_machine) {
+  return internal::IsInstalledScheduledTask(
+                             ConfigManager::GetCurrentTaskNameUA(is_machine));
+}
+
+bool IsDisabledGoopdateTaskUA(bool is_machine) {
+  const CString& task_name(ConfigManager::GetCurrentTaskNameUA(is_machine));
+  return internal::GetScheduledTaskStatus(task_name) == SCHED_S_TASK_DISABLED;
+}
+
+HRESULT GetExitCodeGoopdateTaskUA(bool is_machine) {
+  const CString& task_name(ConfigManager::GetCurrentTaskNameUA(is_machine));
+  return internal::GetScheduledTaskExitCode(task_name);
+}
+
+HRESULT GetClientsStringValueFromRegistry(bool is_machine,
+                                          const CString& app_guid,
+                                          const CString& value_name,
+                                          CString* value) {
+  CORE_LOG(L3, (_T("[GetClientsStringValueFromRegistry][%d][%s][%s]"),
+                is_machine, app_guid, value_name));
+
+  ASSERT1(value);
+
+  CString app_client_key_name = GetAppClientsKey(is_machine, app_guid);
+
+  return RegKey::GetValue(app_client_key_name, value_name, value);
+}
+
+HRESULT GetVerFromRegistry(bool is_machine,
+                           const CString& app_guid,
+                           CString* version) {
+  ASSERT1(version);
+  return GetClientsStringValueFromRegistry(is_machine,
+                                           app_guid,
+                                           kRegValueProductVersion,
+                                           version);
+}
+
+HRESULT TerminateAllBrowsers(
+    BrowserType type,
+    TerminateBrowserResult* browser_res,
+    TerminateBrowserResult* default_res) {
+  UTIL_LOG(L3, (_T("[TerminateAllBrowsers][%d]"), type));
+  ASSERT1(default_res);
+  ASSERT1(browser_res);
+
+  if (type == BROWSER_UNKNOWN ||
+      type == BROWSER_DEFAULT ||
+      type >= BROWSER_MAX) {
+    ASSERT1(false);
+    return E_INVALIDARG;
+  }
+
+  const BrowserType kFirstBrowser = BROWSER_IE;
+  const int kNumSupportedBrowsers = BROWSER_MAX - kFirstBrowser;
+
+  BrowserType default_type = BROWSER_UNKNOWN;
+  HRESULT hr = GetDefaultBrowserType(&default_type);
+  if (FAILED(hr)) {
+    UTIL_LOG(LW, (_T("[GetDefaultBrowserType failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  TerminateBrowserResult terminate_results[kNumSupportedBrowsers];
+
+  for (int browser = 0; browser < kNumSupportedBrowsers; ++browser) {
+    const BrowserType browser_type =
+        static_cast<BrowserType>(kFirstBrowser + browser);
+    hr = TerminateBrowserProcess(browser_type,
+                                 CString(),
+                                 0,
+                                 &terminate_results[browser].found);
+    if (FAILED(hr)) {
+      UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][%u][0x%08x]"),
+                    browser_type, hr));
+    }
+  }
+
+  // Now wait for the all browser instances to die.
+  // TODO(omaha): Wait for all processes at once rather than waiting for
+  // (kTerminateBrowserTimeoutMs * # supported browsers) ms.
+  for (int browser = 0; browser < kNumSupportedBrowsers; ++browser) {
+    const BrowserType browser_type =
+        static_cast<BrowserType>(kFirstBrowser + browser);
+    hr = WaitForBrowserToDie(browser_type,
+                             CString(),
+                             kTerminateBrowserTimeoutMs);
+    if (FAILED(hr)) {
+      UTIL_LOG(LW, (_T("[WaitForBrowserToDie failed][%u][0x%08x]"),
+                    browser_type, hr));
+    } else {
+      terminate_results[browser].could_terminate = true;
+    }
+  }
+
+  *browser_res = terminate_results[type - kFirstBrowser];
+  *default_res = terminate_results[default_type - kFirstBrowser];
+
+  return S_OK;
+}
+
+// default_type can be BROWSER_UNKNOWN.
+// If browsers that must be closed could not be terminated, false is returned.
+// This method and TerminateBrowserProcesses assume the user did not shutdown
+// the specified browser. They restart and shutdown, respectively, the default
+// browser when the specified browser is not found. The reason for this may have
+// been that the the specified (stamped) browser could be in a bad state on the
+// machine and trying to start it would fail.
+// This may also be required to support hosted cases (i.e. AOL and Maxthon).
+// TODO(omaha): If we assume the stamped browser is okay, check whether the
+// specified browser is installed rather than relying on whether the browser was
+// running. It is perfectly valid for the browser to not be running.
+// TODO(omaha): Why not try the default browser if browsers that require
+// shutdown failed to terminate.
+bool GetBrowserToRestart(BrowserType type,
+                         BrowserType default_type,
+                         const TerminateBrowserResult& res,
+                         const TerminateBrowserResult& def_res,
+                         BrowserType* browser_type) {
+  ASSERT1(browser_type);
+  ASSERT1(type != BROWSER_UNKNOWN &&
+          type != BROWSER_DEFAULT &&
+          type < BROWSER_MAX);
+  ASSERT1(default_type != BROWSER_DEFAULT && default_type < BROWSER_MAX);
+  UTIL_LOG(L3, (_T("[GetBrowserToRestart][%d]"), type));
+
+  *browser_type = BROWSER_UNKNOWN;
+
+  if (res.found) {
+    switch (type) {
+      case BROWSER_IE:
+        *browser_type = BROWSER_IE;
+        return true;
+      case BROWSER_FIREFOX:   // Only one process.
+      case BROWSER_CHROME:    // One process per plug-in, even for upgrades.
+        if (res.could_terminate) {
+          *browser_type = type;
+          return true;
+        }
+        return false;
+      case BROWSER_UNKNOWN:
+      case BROWSER_DEFAULT:
+      case BROWSER_MAX:
+      default:
+        break;
+    }
+  }
+
+  // We did not find the browser that we wanted to restart. Hence we need to
+  // determine if we could shutdown the default browser.
+  switch (default_type) {
+    case BROWSER_IE:
+      *browser_type = BROWSER_IE;
+      return true;
+    case BROWSER_FIREFOX:
+    case BROWSER_CHROME:
+      if (!def_res.found || def_res.found && def_res.could_terminate) {
+        *browser_type = default_type;
+        return true;
+      }
+      break;
+    case BROWSER_UNKNOWN:
+    case BROWSER_DEFAULT:
+    case BROWSER_MAX:
+    default:
+      break;
+  }
+
+  return false;
+}
+
+// See the comments about the default browser above GetBrowserToRestart.
+HRESULT TerminateBrowserProcesses(BrowserType type,
+                                  TerminateBrowserResult* browser_res,
+                                  TerminateBrowserResult* default_res) {
+  UTIL_LOG(L3, (_T("[TerminateBrowserProcesses][%d]"), type));
+  ASSERT1(browser_res);
+  ASSERT1(default_res);
+
+  browser_res->could_terminate = false;
+  default_res->could_terminate = false;
+
+  if (type == BROWSER_UNKNOWN ||
+      type == BROWSER_DEFAULT ||
+      type >= BROWSER_MAX) {
+    ASSERT1(false);
+    return E_UNEXPECTED;
+  }
+
+  CString sid;
+  HRESULT hr = user_info::GetCurrentUser(NULL, NULL, &sid);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[GetCurrentUser failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = TerminateBrowserProcess(type,
+                               sid,
+                               kTerminateBrowserTimeoutMs,
+                               &browser_res->found);
+  if (FAILED(hr)) {
+    UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][0x%08x]"), hr));
+  } else {
+    browser_res->could_terminate = true;
+  }
+
+  // Since no instances of the browser type exist, we try to find and kill
+  // all instances of the default browser.
+  if (!browser_res->found) {
+    // We dont want to try and terminate the default browser, if it is the
+    // same as the browser that we tried above.
+
+    BrowserType default_type = BROWSER_UNKNOWN;
+    hr = GetDefaultBrowserType(&default_type);
+    if (FAILED(hr)) {
+      UTIL_LOG(LW, (_T("[GetDefaultBrowserType failed][0x%08x]"), hr));
+    }
+
+    UTIL_LOG(L3, (_T("[Trying to kill the default browser %d]"), default_type));
+    if (default_type != type) {
+      hr = TerminateBrowserProcess(BROWSER_DEFAULT,
+                                   sid,
+                                   kTerminateBrowserTimeoutMs,
+                                   &default_res->found);
+      if (FAILED(hr)) {
+        UTIL_LOG(LW, (_T("[TerminateBrowserProcess failed][0x%08x]"), hr));
+      } else {
+        default_res->could_terminate = true;
+      }
+    }
+  }
+
+  return hr;
+}
+
+HRESULT StartBrowserWithProcessToken(bool is_machine,
+                                     BrowserType type,
+                                     const CString& url,
+                                     uint32 explorer_pid) {
+  UTIL_LOG(L3, (_T("[StartBrowserWithProcessToken.]")
+                _T("[is_machine = %d][type = %d]"), is_machine, type));
+
+  // In case of machine goopdate we need to CreateProcessAsUser, else we ask
+  // the shell to create a new browser process.
+  if (is_machine) {
+    CString browser_path;
+    HRESULT hr = GetBrowserImagePath(type, &browser_path);
+    if (FAILED(hr)) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[GetBrowserImagePath failed.][0x%08x]"), hr));
+      return hr;
+    }
+    ASSERT1(!browser_path.IsEmpty());
+
+    CString command_line;
+    EnclosePath(&browser_path);
+    command_line.Format(_T("%s %s"), browser_path, url);
+    UTIL_LOG(L3, (_T("[Executing command line %s.]"), command_line));
+    hr = vista::StartProcessWithTokenOfProcess(explorer_pid, command_line);
+    if (FAILED(hr)) {
+      UTIL_LOG(LW, (_T("[StartProcessWithTokenOfProcess failed][0x%08x]"), hr));
+      return hr;
+    }
+  } else {
+    return ShellExecuteBrowser(type, url);
+  }
+
+  return S_OK;
+}
+
+HRESULT GetBrowserImagePathFromProcess(BrowserType type,
+                                       uint32 explorer_pid,
+                                       CString* path) {
+  ASSERT1(path);
+
+  if (type == BROWSER_UNKNOWN || type >= BROWSER_MAX) {
+    ASSERT1(false);
+    return E_UNEXPECTED;
+  }
+
+  if (type == BROWSER_DEFAULT) {
+    return GetDefaultBrowserPath(path);
+  }
+
+  CString user_sid;
+  HRESULT hr = Process::GetProcessOwner(explorer_pid, &user_sid);
+  if (FAILED(hr)) {
+    UTIL_LOG(LEVEL_WARNING, (_T("[GetProcessOwner failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  CString browser_name;
+  hr = BrowserTypeToProcessName(type, &browser_name);
+  if (FAILED(hr)) {
+    UTIL_LOG(LW, (_T("[BrowserTypeToProcessName failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = Process::GetImagePath(browser_name, user_sid, path);
+  if (FAILED(hr)) {
+    UTIL_LOG(LW, (_T("[GetImagePath failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT ConvertStringToBrowserType(const CString& text, BrowserType* type) {
+  ASSERT1(type != NULL);
+
+  if (text.GetLength() != 1) {
+    return GOOPDATEUTILS_E_BROWSERTYPE;
+  }
+
+  int browser_type = 0;
+  if (!String_StringToDecimalIntChecked(text, &browser_type)) {
+    return GOOPDATEUTILS_E_BROWSERTYPE;
+  }
+
+  if (browser_type >= BROWSER_MAX) {
+    return GOOPDATEUTILS_E_BROWSERTYPE;
+  }
+
+  *type = static_cast<BrowserType>(browser_type);
+  return S_OK;
+}
+
+CString ConvertBrowserTypeToString(BrowserType type) {
+  CString text = itostr(static_cast<int>(type));
+  ASSERT1(!text.IsEmpty());
+  return text;
+}
+
+bool IsServiceInstalled() {
+  return ServiceInstall::IsServiceInstalled(
+                             ConfigManager::GetCurrentServiceName());
+}
+
+HRESULT GetOSInfo(CString* os_version, CString* service_pack) {
+  ASSERT1(os_version);
+  ASSERT1(service_pack);
+
+  OSVERSIONINFO os_version_info = { 0 };
+  os_version_info.dwOSVersionInfoSize = sizeof(os_version_info);
+  if (!::GetVersionEx(&os_version_info)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LW, (_T("[GetVersionEx failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  os_version->Format(_T("%d.%d"),
+                     os_version_info.dwMajorVersion,
+                     os_version_info.dwMinorVersion);
+  *service_pack = os_version_info.szCSDVersion;
+  return S_OK;
+}
+
+// We have a mechanism to display a help center page asking users for help
+// debugging crashes.
+HRESULT ShowUserCrashPage(const CString& language,
+                          uint64 address,
+                          uint32 code) {
+  const TCHAR* const kCrashSourceId = _T("crash");
+
+  CString url;
+  HRESULT hr = BuildHttpGetString(kUrlMoreInformation,
+                                  code,
+                                  static_cast<DWORD>(address),
+                                  0,
+                                  kGoogleUpdateAppId,
+                                  GetVersionString(),
+                                  false,
+                                  language,
+                                  kCrashSourceId,
+                                  &url);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  return ShellExecuteBrowser(BROWSER_DEFAULT, url);
+}
+
+CPath BuildInstallDirectory(bool is_machine, const CString& version) {
+  ConfigManager& cm = *ConfigManager::Instance();
+  CPath install_dir(is_machine ? cm.GetMachineGoopdateInstallDir() :
+                                 cm.GetUserGoopdateInstallDir());
+  VERIFY1(install_dir.Append(version));
+
+  return install_dir;
+}
+
+HRESULT LaunchCmdLine(const CString& cmd_line) {
+  bool run_with_lower_privileges = vista_util::IsUserRunningSplitToken() &&
+                                   vista_util::IsUserAdmin();
+
+  return run_with_lower_privileges ?
+             LaunchImpersonatedCmdLine(cmd_line) :
+             System::ShellExecuteCommandLine(cmd_line, NULL, NULL);
+}
+
+HRESULT LaunchBrowser(BrowserType type, const CString& url) {
+  bool run_with_lower_privileges = vista_util::IsUserRunningSplitToken() &&
+                                   vista_util::IsUserAdmin();
+
+  if (run_with_lower_privileges) {
+    // Other than having a service launch the browser using CreateProcessAsUser,
+    // there is no easy solution if we are unable to launch the browser
+    // impersonated.
+    return LaunchImpersonatedBrowser(type, url);
+  }
+
+  HRESULT hr = ShellExecuteBrowser(type, url);
+  if (FAILED(hr)) {
+    UTIL_LOG(LW, (_T("[ShellExecuteBrowser failed][0x%x]"), hr));
+  }
+  return hr;
+}
+
+// This method formats all the data that is present inside the UpdateResponse
+// in the form of the extra arguments command line.
+// The values that are converted include:
+// appguid, appname (will not be present in pre-I18N builds.), needsadmin
+// iid, ap, browser; values not used in pre-I18N builds are not supported.
+HRESULT ConvertResponseDataToExtraArgs(const UpdateResponseData& response_data,
+                                       CString* extra) {
+  ASSERT1(extra);
+  *extra = _T("");
+
+  // Append the application guid.
+  if (response_data.guid() == GUID_NULL) {
+    // The guid should always be present.
+    return E_INVALIDARG;
+  }
+  CString str_guid = GuidToString(response_data.guid());
+  ASSERT1(!str_guid.IsEmpty());
+  extra->AppendFormat(_T("%s=%s"), kExtraArgAppGuid, str_guid);
+
+  // Convert the application name into the command line format. In case of
+  // pre-I18N installers, the name is not known to the installer, hence if
+  // the name is empty we use a hard coded name.
+  CString product_name;
+  if (!response_data.app_name().IsEmpty()) {
+    HRESULT hr = WideStringToUtf8UrlEncodedString(response_data.app_name(),
+                                                  &product_name);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  } else {
+    product_name = GetProductName(str_guid);
+  }
+  ASSERT1(!product_name.IsEmpty());
+  extra->AppendFormat(_T("&%s=%s"), kExtraArgAppName, product_name);
+
+  // Append needs admin.
+  CString needs_admin_str;
+  HRESULT hr = ConvertNeedsAdminToString(response_data.needs_admin(),
+                                         &needs_admin_str);
+
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(!needs_admin_str.IsEmpty());
+  extra->AppendFormat(_T("&%s=%s"), kExtraArgNeedsAdmin, needs_admin_str);
+
+  if (response_data.installation_id() != GUID_NULL) {
+    CString str_installationid = GuidToString(response_data.installation_id());
+    extra->AppendFormat(_T("&%s=%s"), kExtraArgInstallationId,
+                        str_installationid);
+  }
+  // Append the browser tag.
+  if (response_data.browser_type() != BROWSER_UNKNOWN) {
+    CString browser_type =
+        ConvertBrowserTypeToString(response_data.browser_type());
+    extra->AppendFormat(_T("&%s=%s"), kExtraArgBrowserType, browser_type);
+  }
+
+  // Append ap tag.
+  if (!response_data.ap().IsEmpty()) {
+    extra->AppendFormat(_T("&%s=%s"),
+                        kExtraArgAdditionalParameters,
+                        response_data.ap());
+  }
+
+  // Append TT tag.
+  if (!response_data.tt_token().IsEmpty()) {
+    extra->AppendFormat(_T("&%s=%s"),
+                        kExtraArgTTToken,
+                        response_data.tt_token());
+  }
+
+  return S_OK;
+}
+
+HRESULT ConvertNeedsAdminToString(NeedsAdmin needs_admin, CString* text) {
+  ASSERT1(text);
+  switch (needs_admin) {
+    case omaha::NEEDS_ADMIN_YES:
+      *text = kTrue;
+      break;
+    case omaha::NEEDS_ADMIN_NO:
+      *text = kFalse;
+      break;
+    default:
+      return E_INVALIDARG;
+  }
+
+  return S_OK;
+}
+
+HRESULT ConvertStringToNeedsAdmin(const CString& text, NeedsAdmin* admin) {
+  ASSERT1(admin);
+  if (_tcsicmp(text, kTrue) == 0) {
+    *admin = omaha::NEEDS_ADMIN_YES;
+  } else if (_tcsicmp(text, kFalse) == 0) {
+    *admin = omaha::NEEDS_ADMIN_NO;
+  } else {
+    return GOOPDATEXML_E_NEEDSADMIN;
+  }
+
+  return S_OK;
+}
+
+HRESULT HandleLegacyManifestHandoff(const CString& manifest_filename,
+                                    bool is_machine) {
+  OPT_LOG(L1, (_T("[HandleLegacyManifestHandoff]")));
+
+  // Read the manifest file.
+  CString xml_contents;
+  HRESULT hr = GoopdateXmlParser::LoadXmlFileToMemory(manifest_filename,
+                                                      &xml_contents);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Could not load manifest file to memory][%s][0x%08x]"),
+                 manifest_filename, hr));
+    // There is something wrong with the file. Move the file to a .bad file.
+    CString bad(manifest_filename);
+    bad.Append(_T(".bad"));
+    File::Move(manifest_filename, bad, true);
+    return hr;
+  }
+  VERIFY1(SUCCEEDED(File::Remove(manifest_filename)));
+
+  // Parse the manifest.
+  UpdateResponses responses;
+  hr = GoopdateXmlParser::ParseManifestString(xml_contents, &responses);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Could not parse manifest][%s]"), manifest_filename));
+    return hr;
+  }
+  ASSERT1(!responses.empty());
+
+  // We we support one application in legacy Omaha.
+  ASSERT1(1 == responses.size());
+  UpdateResponses::const_iterator iter = responses.begin();
+  const UpdateResponse& response = (*iter).second;
+  if (response.update_response_data().needs_admin() ==
+      NEEDS_ADMIN_YES && !is_machine) {
+    return GOOPDATE_E_NON_ADMINS_CANNOT_INSTALL_ADMIN;
+  }
+
+  // Convert the contents of the manifest file into the extraargs command line
+  // format which is the standard omaha2 worker command line.
+  // We re-launch the worker with the new command line instead of handling the
+  // legacy handoff right here, as this allows the other parts of setup
+  // and worker to only know about the new command line and not have to deal
+  // with the legacy commandline. One place where setup and the worker
+  // get simplified because of this is during search for processes with
+  // needsadmin=true.
+  CString extra_args;
+  hr = ConvertResponseDataToExtraArgs(response.update_response_data(),
+                                      &extra_args);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[ConvertResponseDataToExtraArgs failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  // /handoff "extraargs"
+  CommandLineBuilder builder(COMMANDLINE_MODE_HANDOFF_INSTALL);
+  builder.set_extra_args(extra_args);
+  CString cmd_line = builder.GetCommandLineArgs();
+
+  hr = StartGoogleUpdateWithArgs(is_machine, cmd_line, NULL);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[StartGoogleUpdateWithArgs failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// This method does a very specific job of searching for install workers,
+// for the user and machine omaha. It also includes the on-demand updates COM
+// server, because we treat it similar to interactive installs.
+//
+// In machine case we search in all the accounts since the install worker can be
+// running in any admin account and the machine update worker runs as SYSTEM.
+// In the user case, we only search the user's account.
+// In both cases, the Needsadmin command line parameter is checked for
+// true/false in the machine/user case, respectively.
+//
+// Only adds processes to the input vector; does not clear it.
+//
+// TODO(omaha): For now we search for the needs_admin=true in the command
+// line to determine a machine install. Another option of identifying omaha's
+// is to use the presence of a named mutex. So the user omaha will create
+// Global\<sid>\Mutex and the machine will create Global\Mutex, in here then
+// we can test for the presence of the name to decide if an interactive
+// omaha is running.
+// TODO(omaha): Consider further filtering the processes based on whether
+// the owner is elevated in case of machine omaha.
+HRESULT GetInstallWorkerProcesses(bool is_machine,
+                                  std::vector<uint32>* processes) {
+  ASSERT1(processes);
+
+  CString user_sid;
+  DWORD flags = EXCLUDE_CURRENT_PROCESS |
+                INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
+
+  std::vector<CString> command_lines;
+  CString command_line_to_include;
+  command_line_to_include.Format(_T("/%s"), kCmdLineAppHandoffInstall);
+  command_lines.push_back(command_line_to_include);
+  command_line_to_include.Format(_T("/%s"), kCmdLineFinishGoogleUpdateInstall);
+  command_lines.push_back(command_line_to_include);
+  command_lines.push_back(kCmdLineComServerDash);
+
+  if (!is_machine) {
+    // Search only the same sid as the current user.
+    flags |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
+
+    HRESULT hr = user_info::GetCurrentUser(NULL, NULL, &user_sid);
+    if (FAILED(hr)) {
+      CORE_LOG(LE, (_T("[GetCurrentUser failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  std::vector<uint32> all_install_worker_processes;
+  HRESULT hr = Process::FindProcesses(flags,
+                                      kGoopdateFileName,
+                                      true,
+                                      user_sid,
+                                      command_lines,
+                                      &all_install_worker_processes);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  CString needsadmin_arg;
+  needsadmin_arg.Format(_T("%s=%s"), kExtraArgNeedsAdmin, is_machine ?
+                                                          _T("True") :
+                                                          _T("False"));
+  needsadmin_arg.MakeLower();
+
+  CString official_path;
+  hr = GetFolderPath(is_machine ? CSIDL_PROGRAM_FILES : CSIDL_LOCAL_APPDATA,
+                     &official_path);
+  ASSERT1(SUCCEEDED(hr));
+  ASSERT1(!official_path.IsEmpty());
+
+  for (size_t i = 0; i < all_install_worker_processes.size(); ++i) {
+    CString cmd_line;
+    const uint32 process = all_install_worker_processes[i];
+    if (SUCCEEDED(Process::GetCommandLine(process, &cmd_line))) {
+      cmd_line.MakeLower();
+      // TODO(omaha): FindProcess method does not allow regex's to be specified
+      // along with the include command line. Change Process to allow this.
+      if (cmd_line.Find(needsadmin_arg) != -1) {
+        CORE_LOG(L4, (_T("[Including process][%s]"), cmd_line));
+        processes->push_back(process);
+      }
+
+      // The -Embedding does not have a needsAdmin. Decide whether to include it
+      // if it matches the official path for the requested instance type.
+      CString exe_path;
+      if (cmd_line.Find(kCmdLineComServerDash) != -1 &&
+          SUCCEEDED(GetExePathFromCommandLine(cmd_line, &exe_path)) &&
+          String_StrNCmp(official_path, exe_path, official_path.GetLength(),
+                         true) == 0) {
+        CORE_LOG(L4, (_T("[Including process][%s]"), cmd_line));
+        processes->push_back(process);
+      }
+    }
+  }
+
+  return S_OK;
+}
+
+// The event name saved to the environment variable does not contain the
+// decoration added by GetNamedObjectAttributes.
+HRESULT CreateUniqueEventInEnvironment(const CString& var_name,
+                                       bool is_machine,
+                                       HANDLE* unique_event) {
+  ASSERT1(unique_event);
+
+  GUID event_guid = GUID_NULL;
+  HRESULT hr = ::CoCreateGuid(&event_guid);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[::CoCreateGuid failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  CString event_name(GuidToString(event_guid));
+  NamedObjectAttributes attr;
+  GetNamedObjectAttributes(event_name, is_machine, &attr);
+
+  hr = CreateEvent(&attr, unique_event);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[CreateEvent failed in CreateUniqueEventInEnvironment]"),
+                  _T("[%s][0x%08x]"), var_name, hr));
+    return hr;
+  }
+
+  CORE_LOG(L3, (_T("[created unique event][%s][%s]"), var_name, event_name));
+
+  if (!::SetEnvironmentVariable(var_name, event_name)) {
+    DWORD error = ::GetLastError();
+    CORE_LOG(LE, (_T("[::SetEnvironmentVariable failed][%d]"), error));
+    return HRESULT_FROM_WIN32(error);
+  }
+
+  return S_OK;
+}
+
+HRESULT OpenUniqueEventFromEnvironment(const CString& var_name,
+                                       bool is_machine,
+                                       HANDLE* unique_event) {
+  ASSERT1(unique_event);
+
+  TCHAR event_name[MAX_PATH] = {0};
+  if (!::GetEnvironmentVariable(var_name, event_name, arraysize(event_name))) {
+    DWORD error = ::GetLastError();
+    CORE_LOG(LW, (_T("[Failed to read environment variable][%s][%d]"),
+                  var_name, error));
+    return HRESULT_FROM_WIN32(error);
+  }
+
+  CORE_LOG(L3, (_T("[read unique event][%s][%s]"), var_name, event_name));
+
+  NamedObjectAttributes attr;
+  GetNamedObjectAttributes(event_name, is_machine, &attr);
+  *unique_event = ::OpenEvent(EVENT_ALL_ACCESS, false, attr.name);
+
+  if (!*unique_event) {
+    DWORD error = ::GetLastError();
+    CORE_LOG(LW, (_T("[::OpenEvent failed][%s][%d]"), attr.name, error));
+    return HRESULT_FROM_WIN32(error);
+  }
+
+  return S_OK;
+}
+
+// The caller is responsible for reseting the event and closing the handle.
+HRESULT CreateEvent(NamedObjectAttributes* event_attr, HANDLE* event_handle) {
+  ASSERT1(event_handle);
+  ASSERT1(event_attr);
+  ASSERT1(!event_attr->name.IsEmpty());
+  *event_handle = ::CreateEvent(&event_attr->sa,
+                                true,   // manual reset
+                                false,  // not signaled
+                                event_attr->name);
+
+  if (!*event_handle) {
+    DWORD error = ::GetLastError();
+    CORE_LOG(LEVEL_ERROR, (_T("[::SetEvent failed][%d]"), error));
+    return HRESULT_FROM_WIN32(error);
+  }
+
+  return S_OK;
+}
+
+HRESULT ConfigureNetwork(bool is_machine, bool is_local_system) {
+  CORE_LOG(L3, (_T("[goopdate_utils::ConfigureNetwork]")));
+  scoped_handle impersonation_token;
+  if (is_local_system) {
+    // Get an impersonation token corresponding to a primary
+    // token for any of the logged on users.
+    vista::GetLoggedOnUserToken(address(impersonation_token));
+  }
+  NetworkConfig& network_config = NetworkConfig::Instance();
+  HRESULT hr = network_config.Initialize(is_machine, get(impersonation_token));
+  if (FAILED(hr)) {
+    NET_LOG(LE, (_T("[NetworkConfig::Initialize() failed][0x%x]"), hr));
+    return hr;
+  }
+
+  // The NetworkConfig singleton owns the impersonation token.
+  release(impersonation_token);
+
+  // Detecting the default browser requires impersonation so that calling code
+  // running as system is able to detect user proxy settings.
+  HANDLE token = network_config.session().impersonation_token;
+  scoped_impersonation impersonate_user(token);
+  if (token) {
+    DWORD result = impersonate_user.result();
+    ASSERT(result == ERROR_SUCCESS, (_T("impersonation failed %d"), result));
+  }
+  network_config.Add(new GoogleProxyDetector(MACHINE_REG_UPDATE_DEV));
+  BrowserType browser_type(BROWSER_UNKNOWN);
+  GetDefaultBrowserType(&browser_type);
+  if (browser_type == BROWSER_FIREFOX) {
+    network_config.Add(new FirefoxProxyDetector());
+  }
+  // There is no Chrome detector because it uses the same proxy settings as IE.
+  network_config.Add(new IEProxyDetector());
+  network_config.Add(new DefaultProxyDetector);
+
+  // Use a global network configuration override if available.
+  ConfigManager* config_manager = ConfigManager::Instance();
+  CString net_config;
+  if (SUCCEEDED(config_manager->GetNetConfig(&net_config))) {
+    Config configuration_override = NetworkConfig::ParseNetConfig(net_config);
+    network_config.SetConfigurationOverride(&configuration_override);
+  }
+
+  return S_OK;
+}
+
+bool IsTestSource() {
+  return !ConfigManager::Instance()->GetTestSource().IsEmpty();
+}
+
+HRESULT ReadNameValuePairsFromFile(const CString& file_path,
+                                   const CString& group_name,
+                                   std::map<CString, CString>* pairs) {
+  ASSERT1(pairs);
+
+  if (!File::Exists(file_path)) {
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+
+  pairs->clear();
+
+  TCHAR str_buf[32768] = {0};
+
+  // Retrieve all key names in the section requested.
+  DWORD buf_count = ::GetPrivateProfileString(group_name,
+                                              NULL,
+                                              NULL,
+                                              str_buf,
+                                              arraysize(str_buf),
+                                              file_path);
+
+  DWORD offset = 0;
+  while (offset < buf_count) {
+    TCHAR val_buf[1024] = {0};
+    CString current_key = &(str_buf[offset]);
+    DWORD val_count = ::GetPrivateProfileString(group_name,
+                                                current_key,
+                                                NULL,
+                                                val_buf,
+                                                arraysize(val_buf),
+                                                file_path);
+    (*pairs)[current_key] = val_buf;
+    offset += current_key.GetLength() + 1;
+  }
+
+  return S_OK;
+}
+
+HRESULT WriteNameValuePairsToFile(const CString& file_path,
+                                  const CString& group_name,
+                                  const std::map<CString, CString>& pairs) {
+  std::map<CString, CString>::const_iterator it = pairs.begin();
+  for (; it != pairs.end(); ++it) {
+    if (!::WritePrivateProfileString(group_name,
+                                     it->first,
+                                     it->second,
+                                     file_path)) {
+      return HRESULTFromLastError();
+    }
+  }
+
+  return S_OK;
+}
+
+// Google Update does not have a referral_id. Everything else is the same as for
+// apps.
+HRESULT SetGoogleUpdateBranding(const CString& client_state_key_path,
+                                const CString& brand_code,
+                                const CString& client_id) {
+  HRESULT hr(SetAppBranding(client_state_key_path,
+                            brand_code,
+                            client_id,
+                            CString()));
+
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  RegKey state_key;
+  hr = state_key.Open(client_state_key_path);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Legacy support for older versions that do not write the FirstInstallTime.
+  // This code ensures that FirstInstallTime always has a valid non-zero value.
+  DWORD install_time(0);
+  if (FAILED(state_key.GetValue(kRegValueInstallTimeSec, &install_time)) ||
+      !install_time) {
+    const DWORD now = Time64ToInt32(GetCurrent100NSTime());
+    VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueInstallTimeSec, now)));
+    SETUP_LOG(L3, (_T("[InstallTime missing. Setting it here.][%u]"), now));
+  }
+
+  return S_OK;
+}
+
+// Branding information is only written if a brand code is not already present.
+// We should only write it if this is the first install of Omaha to avoid giving
+// undue credit to a later installer source. Writing a default brand code
+// prevents future branded installations from setting their brand.
+// As suggested by PSO, there is no default client ID.
+// Assumes the specified Client State key has been created.
+HRESULT SetAppBranding(const CString& client_state_key_path,
+                       const CString& brand_code,
+                       const CString& client_id,
+                       const CString& referral_id) {
+  SETUP_LOG(L3, (_T("[goopdate_utils::SetAppBranding][%s][%s][%s][%s]"),
+                 client_state_key_path, brand_code, client_id, referral_id));
+
+  if (brand_code.GetLength() > kBrandIdLength) {
+    return E_INVALIDARG;
+  }
+
+  RegKey state_key;
+  HRESULT hr = state_key.Open(client_state_key_path);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString existing_brand_code;
+  hr = state_key.GetValue(kRegValueBrandCode, &existing_brand_code);
+  if (!existing_brand_code.IsEmpty()) {
+    ASSERT1(SUCCEEDED(hr));
+    if (existing_brand_code.GetLength() > kBrandIdLength) {
+      // Bug 1358852: Brand code garbled with one click.
+      VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueBrandCode,
+                            existing_brand_code.Left(kBrandIdLength))));
+    }
+    return S_OK;
+  }
+
+  const TCHAR* brand_code_to_write = brand_code.IsEmpty() ?
+                                     kDefaultGoogleUpdateBrandCode :
+                                     brand_code;
+  hr = state_key.SetValue(kRegValueBrandCode, brand_code_to_write);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (!client_id.IsEmpty()) {
+    hr = state_key.SetValue(kRegValueClientId, client_id);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  if (!referral_id.IsEmpty()) {
+    hr = state_key.SetValue(kRegValueReferralId, referral_id);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  const DWORD now = Time64ToInt32(GetCurrent100NSTime());
+  VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueInstallTimeSec, now)));
+
+  return S_OK;
+}
+
+bool IsAppInstallWorkerRunning(bool is_machine) {
+  CORE_LOG(L3, (_T("[IsAppInstallWorkerRunning][%d]"), is_machine));
+  std::vector<uint32> processes;
+  VERIFY1(SUCCEEDED(GetInstallWorkerProcesses(is_machine, &processes)));
+  return !processes.empty();
+}
+
+// TODO(omaha): needs_admin is only used for one case. Can we avoid it?
+bool IsMachineProcess(CommandLineMode mode,
+                      bool is_running_from_official_machine_directory,
+                      bool is_local_system,
+                      bool is_machine_override,
+                      Tristate needs_admin) {
+  switch (mode) {
+    // These "install" operations may not be running from the installed
+    // location.
+    case COMMANDLINE_MODE_INSTALL:
+    case COMMANDLINE_MODE_IG:
+    case COMMANDLINE_MODE_HANDOFF_INSTALL:
+    case COMMANDLINE_MODE_REGISTER_PRODUCT:
+    case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
+      ASSERT1(TRISTATE_NONE != needs_admin);
+      return TRISTATE_TRUE == needs_admin;
+
+    // The following is a Code Red repair executable, which runs from temp dir.
+    case COMMANDLINE_MODE_RECOVER:
+      return is_machine_override;
+
+    // The following are all user-initiated installs with UI.
+    // They always run as the user for both user and machine installs.
+    // Silent installs for Pack should go here too.
+    case COMMANDLINE_MODE_NOARGS:  // Legacy install
+    case COMMANDLINE_MODE_LEGACYUI:
+    case COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF:
+      return is_running_from_official_machine_directory;
+
+    // The following always runs as the user and may provide UI for on-demand
+    // installs and browser launches.
+    // The install location determines user vs. machine.
+    case COMMANDLINE_MODE_COMSERVER:
+      return is_running_from_official_machine_directory;
+
+    // The following always runs as the user and is user-initiated.
+    case COMMANDLINE_MODE_WEBPLUGIN:
+      // The install location determines user vs. machine.
+      // This may not be the desired value when doing a cross-install or using
+      // the opposite plugin (i.e. user plugin is often used before the machine
+      // one).
+      return is_running_from_official_machine_directory;
+
+    // The following all run silently as the user for user installs or Local
+    // System for machine installs.
+    case COMMANDLINE_MODE_UPDATE:
+    case COMMANDLINE_MODE_UA:
+    case COMMANDLINE_MODE_CODE_RED_CHECK:
+      return is_local_system;
+
+    // The following normally runs silently as the user for user installs or
+    // Local System for machine installs. When launched by recovery it can also
+    // a machine instance can also be running as an elevated admin.
+    case COMMANDLINE_MODE_UG:
+      return is_machine_override || is_local_system;
+
+    // The following runs silently as the user for user installs or Local System
+    // for machine installs.
+    case COMMANDLINE_MODE_CORE:
+    case COMMANDLINE_MODE_CRASH_HANDLER:
+      return is_local_system;
+
+    // The following runs silently as Local System.
+    case COMMANDLINE_MODE_SERVICE:
+      ASSERT1(is_local_system);
+      return is_local_system;
+
+    // The following run as machine for all installs.
+    case COMMANDLINE_MODE_SERVICE_REGISTER:
+    case COMMANDLINE_MODE_SERVICE_UNREGISTER:
+      return true;
+
+    // The crashing process determines whether it was a machine or user omaha
+    // and correctly sets the /machine switch.
+    case COMMANDLINE_MODE_REPORTCRASH:
+      return is_machine_override;
+
+    // The following all run silently as the user for all installs.
+    case COMMANDLINE_MODE_REGSERVER:
+    case COMMANDLINE_MODE_UNREGSERVER:
+      return is_running_from_official_machine_directory;
+
+    // The following are miscellaneous modes that we do not expect to be running
+    // in the wild.
+    case COMMANDLINE_MODE_UNKNOWN:
+    case COMMANDLINE_MODE_NETDIAGS:
+    case COMMANDLINE_MODE_CRASH:
+    default:
+      return is_running_from_official_machine_directory;
+  }
+}
+
+// Returns true if the version does not begin with "1.0." or "1.1.".
+bool IsGoogleUpdate2OrLater(const CString& version) {
+  const ULONGLONG kFirstOmaha2Version = MAKEDLLVERULL(1, 2, 0, 0);
+  ULONGLONG version_number = VersionFromString(version);
+  ASSERT1(0 != version_number);
+
+  if (kFirstOmaha2Version <= version_number) {
+    return true;
+  }
+
+  return false;
+}
+
+bool FormatMessageForNetworkError(HRESULT error,
+                                  const CString app_name,
+                                  CString* msg) {
+  ASSERT1(msg);
+
+  switch (error) {
+    case GOOPDATE_E_NO_NETWORK:
+      msg->FormatMessage(IDS_NO_NETWORK_PRESENT_ERROR,
+                         kGoopdateFileName,
+                         error);
+      break;
+    case GOOPDATE_E_NETWORK_UNAUTHORIZED:
+      msg->FormatMessage(IDS_ERROR_HTTPSTATUS_UNAUTHORIZED, app_name, error);
+      break;
+    case GOOPDATE_E_NETWORK_FORBIDDEN:
+      msg->FormatMessage(IDS_ERROR_HTTPSTATUS_FORBIDDEN, app_name, error);
+      break;
+    case GOOPDATE_E_NETWORK_PROXYAUTHREQUIRED:
+      msg->FormatMessage(IDS_ERROR_HTTPSTATUS_PROXY_AUTH_REQUIRED,
+                         app_name,
+                         error);
+      break;
+    default:
+      msg->FormatMessage(IDS_NO_NETWORK_PRESENT_ERROR,
+                         kGoopdateFileName,
+                         error);
+      return false;
+  }
+
+  return true;
+}
+
+void AddNetworkRequestDataToEventLog(NetworkRequest* network_request,
+                                     HRESULT hr) {
+  ASSERT1(network_request);
+
+  CString msg;
+  msg.Format(_T("Network Request Error.\r\n")
+             _T("Error: 0x%x. Http status code: %d.\r\n%s"),
+             hr, network_request->http_status_code(), network_request->trace());
+
+  LogEvent(static_cast<WORD>(EVENTLOG_ERROR_TYPE), kNetworkRequestEventId, msg);
+}
+
+HRESULT WriteInstallerDataToTempFile(const CString& installer_data,
+                                     CString* installer_data_file_path) {
+  ASSERT1(installer_data_file_path);
+
+  // TODO(omaha): consider eliminating the special case and simply create an
+  // empty file.
+  CORE_LOG(L2, (_T("[WriteInstallerDataToTempFile][data=%s]"), installer_data));
+  if (installer_data.IsEmpty()) {
+    return S_FALSE;
+  }
+
+  CString temp_file;
+  if (!::GetTempFileName(app_util::GetTempDir(),
+                         _T("gui"),
+                         0,
+                         CStrBuf(temp_file, MAX_PATH))) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LE, (_T("[::GetTempFileName failed][0x08%x]"), hr));
+    return hr;
+  }
+
+  scoped_handle file_handle(::CreateFile(temp_file,
+                                         GENERIC_WRITE,
+                                         FILE_SHARE_READ,
+                                         NULL,
+                                         CREATE_ALWAYS,
+                                         FILE_ATTRIBUTE_NORMAL,
+                                         NULL));
+  if (!file_handle) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LE, (_T("[::CreateFile failed][0x08%x]"), hr));
+    return hr;
+  }
+
+  CStringA installer_data_utf8_bom;
+  installer_data_utf8_bom.Format("%c%c%c%s",
+                                 0xEF, 0xBB, 0xBF, WideToUtf8(installer_data));
+  DWORD bytes_written = 0;
+  if (!::WriteFile(get(file_handle),
+                   installer_data_utf8_bom,
+                   installer_data_utf8_bom.GetLength(),
+                   &bytes_written,
+                   NULL)) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LE, (_T("[::WriteFile failed][0x08%x]"), hr));
+    return hr;
+  }
+
+  *installer_data_file_path = temp_file;
+  return S_OK;
+}
+
+HRESULT GetNumClients(bool is_machine, size_t* num_clients) {
+  ASSERT1(num_clients);
+  RegKey reg_key;
+  HKEY root_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+  HRESULT hr = reg_key.Open(root_key, GOOPDATE_REG_RELATIVE_CLIENTS, KEY_READ);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  DWORD num_subkeys(0);
+  LONG error = ::RegQueryInfoKey(reg_key.Key(), NULL, NULL, NULL, &num_subkeys,
+                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+  if (error != ERROR_SUCCESS) {
+    return HRESULT_FROM_WIN32(error);
+  }
+  *num_clients = num_subkeys;
+  return S_OK;
+}
+
+HRESULT ValidateDownloadedFile(const CString& file_name,
+                               const CString& hash,
+                               uint32 size) {
+  CORE_LOG(L3, (_T("[ValidateDownloadedFile][%s][%s][%u]"),
+                file_name, hash, size));
+  ASSERT1(File::Exists(file_name));
+
+  std::vector<CString> files;
+  files.push_back(file_name);
+  HRESULT hr = AuthenticateFiles(files, hash);
+  if (SUCCEEDED(hr)) {
+    return hr;
+  }
+
+  uint32 file_size(0);
+  if (FAILED(File::GetFileSizeUnopen(file_name, &file_size))) {
+    return hr;
+  }
+
+  if (0 == file_size) {
+    return GOOPDATEDOWNLOAD_E_FILE_SIZE_ZERO;
+  } else if (file_size < size) {
+    return GOOPDATEDOWNLOAD_E_FILE_SIZE_SMALLER;
+  } else if (file_size > size) {
+    return GOOPDATEDOWNLOAD_E_FILE_SIZE_LARGER;
+  }
+
+  ASSERT1(size == file_size);
+  return hr;
+}
+
+// Make sure this is not a silent process before calling this method.
+// Uses primary_app_name in the title if provided, otherwise displays a generic
+// title.
+void DisplayErrorInMessageBox(const CString& error_text,
+                              const CString& primary_app_name) {
+  CString msg_box_title;
+  if (primary_app_name.IsEmpty()) {
+    VERIFY1(msg_box_title.LoadString(IDS_GENERIC_INSTALLER_DISPLAY_NAME));
+  } else {
+    msg_box_title.FormatMessage(IDS_WINDOW_TITLE, primary_app_name);
+  }
+  VERIFY1(IDOK == ::MessageBox(NULL, error_text, msg_box_title, MB_OK));
+}
+
+}  // namespace goopdate_utils
+
+}  // namespace omaha
+
diff --git a/goopdate/goopdate_utils.h b/goopdate/goopdate_utils.h
index abfca83..6bbe950 100644
--- a/goopdate/goopdate_utils.h
+++ b/goopdate/goopdate_utils.h
@@ -1,421 +1,421 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines: GoopdateUtils, helper functions for goopdate.

-//

-// TODO(omaha): move to namespace.

-

-#ifndef OMAHA_GOOPDATE_GOOPDATE_UTILS_H__

-#define OMAHA_GOOPDATE_GOOPDATE_UTILS_H__

-

-#include <mstask.h>

-#include <oaidl.h>

-#include <atlcomcli.h>

-#include <atlpath.h>

-#include <atlstr.h>

-#include <map>

-#include <vector>

-#include "omaha/common/constants.h"

-#include "omaha/common/shell.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/request.h"

-#include "omaha/goopdate/update_response.h"

-

-struct NamedObjectAttributes;

-

-namespace omaha {

-

-class UpdateResponse;

-class NetworkRequest;

-

-// TODO(omaha): Move all browser related functions into browser_utils.

-// Represents the Result of an attempt to terminate the browser.

-struct TerminateBrowserResult {

-  TerminateBrowserResult()

-      : found(false),

-        could_terminate(false) {

-  }

-

-  TerminateBrowserResult(bool f, bool terminate)

-      : found(f),

-        could_terminate(terminate) {

-  }

-

-  bool found;

-  bool could_terminate;

-};

-

-// Utility functions for goopdate.

-namespace goopdate_utils {

-

-typedef HRESULT (*RegisterOrUnregisterFunction)(bool is_register);

-

-// Returns the application registration path for the specified app.

-CString GetAppClientsKey(bool is_machine, const CString& app_guid);

-

-// Returns the application state path for the specified app.

-CString GetAppClientStateKey(bool is_machine, const CString& app_guid);

-

-// Returns the medium integrity application state path for the specified app.

-CString GetAppClientStateMediumKey(bool is_machine, const CString& app_guid);

-

-// Returns the application state path for a user given the user SID.

-CString GetUserAllAppsStatePath(const CString& user_sid);

-

-// Returns the application registration location given the user SID.

-CString GetUserAllAppsRegPath(const CString& user_sid);

-

-// Returns the application state path for a particular user and for the

-// given application id.

-CString GetUserAppStatePath(const CString& user_sid,

-                            const CString& app_guid);

-

-// Returns the application registration path for a particular user

-// and for the given application id.

-CString GetUserAppRegPath(const CString& user_sid,

-                          const CString& app_guid);

-

-// Builds the directory of the Google Update executable.

-CString BuildGoogleUpdateExeDir(bool is_machine);

-

-// Builds the path of the Google Update version found in the registry. The

-// command line is of the form "<install location>\googleupdate.exe"

-CString BuildGoogleUpdateExePath(bool is_machine);

-

-CString BuildGoogleUpdateServicesPath(bool is_machine);

-

-// Returns true if the currently executing binary is running from the

-// Machine/User Goopdate directory, or a directory under it.

-bool IsRunningFromOfficialGoopdateDir(bool is_machine);

-

-// If running the installed machine instance, returns HKLM. Else returns HKCU.

-CString GetHKRoot();

-

-// Starts an instance of the Google Update version found in the registry.

-// Only use to start interactive processes because it uses ::ShellExecuteEx().

-// args can be NULL.

-// process can be NULL. If not NULL, caller is responsible for closing handle.

-HRESULT StartGoogleUpdateWithArgs(bool is_machine,

-                                  const TCHAR* args,

-                                  HANDLE* process);

-

-// Starts self in an elevated mode using the "Runas" verb.

-HRESULT StartElevatedSelfWithArgsAndWait(const TCHAR* args);

-

-// Registers security and sets the security values for the GoogleUpdate

-// process when running as a COM server.

-HRESULT InitializeSecurity();

-

-// GetProductName is temporary and must be removed after the TT release.

-// Gets the product name for a app guid.

-CString GetProductName(const CString& app_guid);

-

-// Returns the userId that is stored in the registry. If the user id is

-// not present in the registry, then the id is generated and saved in the

-// registry for future use.

-CString GetPersistentUserId(const CString& key_name);

-

-// Returns the machine id that is stored in the registry. If there is no

-// machine id in the registry, then it creates one and stores in the

-// registry.

-CString GetPersistentMachineId();

-

-// Returns true if it is a development or test machine.

-bool IsTestSource();

-

-// Creates the query string based on the passed url and arguments.

-// url must end in a '?' or '&'.

-HRESULT BuildHttpGetString(const CString& url,

-                           DWORD error_code,

-                           DWORD extra_code1,

-                           DWORD extra_code2,

-                           const CString& product_guid,

-                           const CString& goopdate_version,

-                           bool is_machine,

-                           const CString& language,

-                           const CString& source_id,

-                           CString* get_request);

-

-HRESULT RedirectHKCR(bool is_machine);

-

-HRESULT RemoveRedirectHKCR();

-

-HRESULT RegisterTypeLib(bool is_admin,

-                        const CComBSTR& path,

-                        ITypeLib* type_lib);

-HRESULT UnRegisterTypeLib(bool is_admin,

-                          const CComBSTR&,

-                          ITypeLib* type_lib);

-

-HRESULT RegisterOrUnregisterModule(bool register_server,

-                                   RegisterOrUnregisterFunction registrar);

-

-HRESULT RegisterOrUnregisterModuleWithTypelib(

-    bool register_server,

-    RegisterOrUnregisterFunction registrar);

-

-// Registers the typelib that is passed in.

-// Wrapper for the RegisterTypeLibForUser that is defined in the

-// Vista oleaut32. Uses GetProcAddress to call into the method.

-HRESULT RegisterTypeLibForUser(ITypeLib* lib,

-                               OLECHAR* path,

-                               OLECHAR* help_dir);

-

-// Unregisters the typelib that is passed in.

-// Wrapper for the UnRegisterTypeLibForUser in Vista ole. Uses GetProcAddress

-// to call into the real method.

-HRESULT UnRegisterTypeLibForUser(REFGUID lib_id,

-                                 WORD major_ver_num,

-                                 WORD minor_ver_num,

-                                 LCID lcid,

-                                 SYSKIND syskind);

-

-// Impersonates the user in case of interactive installs, and

-// the logged in user in case of non-interactive updates.

-HRESULT ImpersonateUser(bool is_interactive, uint32 explorer_pid);

-

-// Reverts the calling thread to self if impersonated.

-HRESULT UndoImpersonation(bool impersonated);

-

-// Returns the user's token either from the request or from the logged on

-// user's explorer process.

-HRESULT GetImpersonationToken(bool is_interactive,

-                              uint32 explorer_pid,

-                              HANDLE* out_token);

-

-// Returns whether the EULA is accepted for the app.

-bool IsAppEulaAccepted(bool is_machine,

-                       const CString& app_guid,

-                       bool require_explicit_acceptance);

-

-// Sets eulaaccepted=0 in the app's ClientState.

-HRESULT SetAppEulaNotAccepted(bool is_machine, const CString& app_guid);

-

-// Clears any eulaaccepted=0 values for the app.

-HRESULT ClearAppEulaNotAccepted(bool is_machine, const CString& app_guid);

-

-// Determines whether usage stats are enabled for a specific app.

-bool AreAppUsageStatsEnabled(bool is_machine, const CString& app_guid);

-

-// Configures Omaha's collection of usage stats and crash reports.

-HRESULT SetUsageStatsEnable(bool is_machine,

-                            const CString& app_guid,

-                            Tristate usage_stats_enable);

-

-// Copies legacy usage stats value to the new name and location then deletes

-// the old value.

-// TODO(omaha): Remove along with legacy Omaha 1.

-HRESULT ConvertLegacyUsageStats(bool is_machine);

-

-//

-// Scheduled Task methods.

-

-// This method will return the default scheduled task name. This default value

-// is also used as the prefix for generating unique task names.

-CString GetDefaultGoopdateTaskName(bool is_machine, CommandLineMode mode);

-HRESULT InstallGoopdateTasks(const TCHAR* task_path, bool is_machine);

-HRESULT UninstallGoopdateTasks(bool is_machine);

-HRESULT UninstallLegacyGoopdateTasks(bool is_machine);

-HRESULT StartGoopdateTaskCore(bool is_machine);

-bool IsInstalledGoopdateTaskUA(bool is_machine);

-bool IsDisabledGoopdateTaskUA(bool is_machine);

-HRESULT GetExitCodeGoopdateTaskUA(bool is_machine);

-

-// Gets the specified value from the registry for the application.

-HRESULT GetClientsStringValueFromRegistry(bool is_machine,

-                                          const CString& app_guid,

-                                          const CString& value_name,

-                                          CString* value);

-

-// Gets the application's version from the registry.

-HRESULT GetVerFromRegistry(bool is_machine,

-                           const CString& app_guid,

-                           CString* version);

-

-// Returns the absolute path of the browser image.

-HRESULT GetBrowserImagePathFromProcess(BrowserType type,

-                                       uint32 explorer_pid,

-                                       CString* path);

-

-// Terminates all browser processes for the current user.

-HRESULT TerminateBrowserProcesses(BrowserType type,

-                                  TerminateBrowserResult* browser_res,

-                                  TerminateBrowserResult* default_res);

-

-// Terminates both firefox and IE instances.

-HRESULT TerminateAllBrowsers(BrowserType type,

-                             TerminateBrowserResult* browser_res,

-                             TerminateBrowserResult* default_res);

-

-

-// Starts an instance of the browser. The explorer_pid indicates the user to

-// launch the browser as, in case of machine goopdate.

-HRESULT StartBrowserWithProcessToken(bool is_machine,

-                                     BrowserType type,

-                                     const CString& url,

-                                     uint32 explorer_pid);

-

-// Converts from string to the BrowserType enum.

-HRESULT ConvertStringToBrowserType(const CString& text, BrowserType* type);

-

-// Converts from BrowserType to string.

-CString ConvertBrowserTypeToString(BrowserType type);

-

-// Converts a string to the needs admin enum. Takes care of case.

-HRESULT ConvertStringToNeedsAdmin(const CString& text, NeedsAdmin* admin);

-

-// Converts the NeedsAdmin to a string.

-HRESULT ConvertNeedsAdminToString(NeedsAdmin needs_admin, CString* text);

-

-// Returns the browser to restart.

-bool GetBrowserToRestart(BrowserType type,

-                         BrowserType default_type,

-                         const TerminateBrowserResult& res,

-                         const TerminateBrowserResult& def_res,

-                         BrowserType* browser_type);

-

-// Returns whether the Goopdate service is installed.

-bool IsServiceInstalled();

-

-// Reads the value of the persistent id.

-HRESULT ReadPersistentId(const CString& key_name,

-                         const CString& value_name,

-                         CString* id);

-

-// Obtains the OS version and service pack.

-HRESULT GetOSInfo(CString* os_version, CString* service_pack);

-

-// Starts the default browser and navigates to a help center page

-// corresponding to the address and the exception code of the crash.

-HRESULT ShowUserCrashPage(const CString& language,

-                          uint64 address,

-                          uint32 code);

-

-// Returns the install directory for the specified version.

-CPath BuildInstallDirectory(bool is_machine, const CString& version);

-

-// Launches the browser. On Vista and later, for a machine install, this method

-// will launch the browser at medium/low integrity, by impersonating the medium

-// integrity token of the active user.

-HRESULT LaunchBrowser(BrowserType type, const CString& url);

-

-// Launches the command line. On Vista and later, for a machine install, this

-// method will launch the process at medium/low integrity, by impersonating the

-// medium integrity token of the active user.

-HRESULT LaunchCmdLine(const CString& cmd_line);

-

-// Converts the data contained in the response to the extra argument format.

-HRESULT ConvertResponseDataToExtraArgs(const UpdateResponseData& response,

-                                       CString* extra);

-

-// Converts the manifest_filename parameter to extra args and starts

-// an omaha2 install worker from the install directory.

-HRESULT HandleLegacyManifestHandoff(const CString& manifest_filename,

-                                    bool is_machine);

-

-// Gets a list of install worker processes relevant to user/machine instances.

-HRESULT GetInstallWorkerProcesses(bool is_machine,

-                                  std::vector<uint32>* processes);

-

-// Creates a unique event name and stores it in the specified environment var.

-HRESULT CreateUniqueEventInEnvironment(const CString& var_name,

-                                       bool is_machine,

-                                       HANDLE* unique_event);

-

-// Obtains a unique event name from specified environment var and opens it.

-HRESULT OpenUniqueEventFromEnvironment(const CString& var_name,

-                                       bool is_machine,

-                                       HANDLE* unique_event);

-

-// Creates an event based on the provided attributes.

-HRESULT CreateEvent(NamedObjectAttributes* event_attr, HANDLE* event_handle);

-

-// Initializes the network stack and adds the proxy detectors.

-HRESULT ConfigureNetwork(bool is_machine, bool is_local_system);

-

-HRESULT ReadNameValuePairsFromFile(const CString& file_path,

-                                   const CString& group_name,

-                                   std::map<CString, CString>* pairs);

-

-HRESULT WriteNameValuePairsToFile(const CString& file_path,

-                                  const CString& group_name,

-                                  const std::map<CString, CString>& pairs);

-

-// Writes branding information for Google Update in the registry if it does not

-// already exist. Otherwise, the information remains unchanged.

-// Writes a default Omaha-specific brand code if one is not specified in args.

-HRESULT SetGoogleUpdateBranding(const CString& client_state_key_path,

-                                const CString& brand_code,

-                                const CString& client_id);

-

-

-// Writes branding information for apps in the registry if it does not

-// already exist. Otherwise, the information remains unchanged.

-// Writes a default Omaha-specific brand code if one is not specified in args.

-HRESULT SetAppBranding(const CString& client_state_key_path,

-                       const CString& brand_code,

-                       const CString& client_id,

-                       const CString& referral_id);

-

-// Returns true is any of the install workers is running.

-bool IsAppInstallWorkerRunning(bool is_machine);

-

-// Returns whether a process is a machine process.

-// Does not determine whether the process has the appropriate privileges.

-bool IsMachineProcess(

-    CommandLineMode mode,

-    bool is_running_from_official_machine_directory,

-    bool is_local_system,  // Whether process is running as local system.

-    bool is_machine_override,  // True if machine cmd line override specified.

-    Tristate needs_admin);  // needsadmin value for primary app if present.

-

-// Returns whether the version is an "Omaha 2" version or later.

-bool IsGoogleUpdate2OrLater(const CString& version);

-

-// Formats an error message for network errors. Returns true if the error has

-// a specific message. Otherwise, formats a generic network connection message

-// and returns false.

-bool FormatMessageForNetworkError(HRESULT error,

-                                  const CString app_name,

-                                  CString* msg);

-

-// Adds details about the network_request to the event log as an error.

-void AddNetworkRequestDataToEventLog(NetworkRequest* network_request,

-                                     HRESULT hr);

-

-// Converts the installer_data value to UTF8. Then writes this UTF8 data

-// prefixed with the UTF8 BOM of EF BB BF to a temp file. Returns the path to

-// temp file that was created.  The returned path will be quote-enclosed by

-// EnclosePath().

-HRESULT WriteInstallerDataToTempFile(const CString& installer_data,

-                                     CString* installer_data_file_path);

-

-// Returns the number of clients registered under the "Clients" sub key.

-HRESULT GetNumClients(bool is_machine, size_t* num_clients);

-

-// Validates the hash of the file. If the hash does not match, checks the size

-// to determine whether the problem was corruption or file size.

-HRESULT ValidateDownloadedFile(const CString& file_name,

-                               const CString& hash,

-                               uint32 size);

-

-void DisplayErrorInMessageBox(const CString& error_text,

-                              const CString& primary_app_name);

-

-}  // namespace goopdate_utils

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_GOOPDATE_UTILS_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines: GoopdateUtils, helper functions for goopdate.
+//
+// TODO(omaha): move to namespace.
+
+#ifndef OMAHA_GOOPDATE_GOOPDATE_UTILS_H__
+#define OMAHA_GOOPDATE_GOOPDATE_UTILS_H__
+
+#include <mstask.h>
+#include <oaidl.h>
+#include <atlcomcli.h>
+#include <atlpath.h>
+#include <atlstr.h>
+#include <map>
+#include <vector>
+#include "omaha/common/constants.h"
+#include "omaha/common/shell.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/request.h"
+#include "omaha/goopdate/update_response.h"
+
+struct NamedObjectAttributes;
+
+namespace omaha {
+
+class UpdateResponse;
+class NetworkRequest;
+
+// TODO(omaha): Move all browser related functions into browser_utils.
+// Represents the Result of an attempt to terminate the browser.
+struct TerminateBrowserResult {
+  TerminateBrowserResult()
+      : found(false),
+        could_terminate(false) {
+  }
+
+  TerminateBrowserResult(bool f, bool terminate)
+      : found(f),
+        could_terminate(terminate) {
+  }
+
+  bool found;
+  bool could_terminate;
+};
+
+// Utility functions for goopdate.
+namespace goopdate_utils {
+
+typedef HRESULT (*RegisterOrUnregisterFunction)(bool is_register);
+
+// Returns the application registration path for the specified app.
+CString GetAppClientsKey(bool is_machine, const CString& app_guid);
+
+// Returns the application state path for the specified app.
+CString GetAppClientStateKey(bool is_machine, const CString& app_guid);
+
+// Returns the medium integrity application state path for the specified app.
+CString GetAppClientStateMediumKey(bool is_machine, const CString& app_guid);
+
+// Returns the application state path for a user given the user SID.
+CString GetUserAllAppsStatePath(const CString& user_sid);
+
+// Returns the application registration location given the user SID.
+CString GetUserAllAppsRegPath(const CString& user_sid);
+
+// Returns the application state path for a particular user and for the
+// given application id.
+CString GetUserAppStatePath(const CString& user_sid,
+                            const CString& app_guid);
+
+// Returns the application registration path for a particular user
+// and for the given application id.
+CString GetUserAppRegPath(const CString& user_sid,
+                          const CString& app_guid);
+
+// Builds the directory of the Google Update executable.
+CString BuildGoogleUpdateExeDir(bool is_machine);
+
+// Builds the path of the Google Update version found in the registry. The
+// command line is of the form "<install location>\googleupdate.exe"
+CString BuildGoogleUpdateExePath(bool is_machine);
+
+CString BuildGoogleUpdateServicesPath(bool is_machine);
+
+// Returns true if the currently executing binary is running from the
+// Machine/User Goopdate directory, or a directory under it.
+bool IsRunningFromOfficialGoopdateDir(bool is_machine);
+
+// If running the installed machine instance, returns HKLM. Else returns HKCU.
+CString GetHKRoot();
+
+// Starts an instance of the Google Update version found in the registry.
+// Only use to start interactive processes because it uses ::ShellExecuteEx().
+// args can be NULL.
+// process can be NULL. If not NULL, caller is responsible for closing handle.
+HRESULT StartGoogleUpdateWithArgs(bool is_machine,
+                                  const TCHAR* args,
+                                  HANDLE* process);
+
+// Starts self in an elevated mode using the "Runas" verb.
+HRESULT StartElevatedSelfWithArgsAndWait(const TCHAR* args);
+
+// Registers security and sets the security values for the GoogleUpdate
+// process when running as a COM server.
+HRESULT InitializeSecurity();
+
+// GetProductName is temporary and must be removed after the TT release.
+// Gets the product name for a app guid.
+CString GetProductName(const CString& app_guid);
+
+// Returns the userId that is stored in the registry. If the user id is
+// not present in the registry, then the id is generated and saved in the
+// registry for future use.
+CString GetPersistentUserId(const CString& key_name);
+
+// Returns the machine id that is stored in the registry. If there is no
+// machine id in the registry, then it creates one and stores in the
+// registry.
+CString GetPersistentMachineId();
+
+// Returns true if it is a development or test machine.
+bool IsTestSource();
+
+// Creates the query string based on the passed url and arguments.
+// url must end in a '?' or '&'.
+HRESULT BuildHttpGetString(const CString& url,
+                           DWORD error_code,
+                           DWORD extra_code1,
+                           DWORD extra_code2,
+                           const CString& product_guid,
+                           const CString& goopdate_version,
+                           bool is_machine,
+                           const CString& language,
+                           const CString& source_id,
+                           CString* get_request);
+
+HRESULT RedirectHKCR(bool is_machine);
+
+HRESULT RemoveRedirectHKCR();
+
+HRESULT RegisterTypeLib(bool is_admin,
+                        const CComBSTR& path,
+                        ITypeLib* type_lib);
+HRESULT UnRegisterTypeLib(bool is_admin,
+                          const CComBSTR&,
+                          ITypeLib* type_lib);
+
+HRESULT RegisterOrUnregisterModule(bool register_server,
+                                   RegisterOrUnregisterFunction registrar);
+
+HRESULT RegisterOrUnregisterModuleWithTypelib(
+    bool register_server,
+    RegisterOrUnregisterFunction registrar);
+
+// Registers the typelib that is passed in.
+// Wrapper for the RegisterTypeLibForUser that is defined in the
+// Vista oleaut32. Uses GetProcAddress to call into the method.
+HRESULT RegisterTypeLibForUser(ITypeLib* lib,
+                               OLECHAR* path,
+                               OLECHAR* help_dir);
+
+// Unregisters the typelib that is passed in.
+// Wrapper for the UnRegisterTypeLibForUser in Vista ole. Uses GetProcAddress
+// to call into the real method.
+HRESULT UnRegisterTypeLibForUser(REFGUID lib_id,
+                                 WORD major_ver_num,
+                                 WORD minor_ver_num,
+                                 LCID lcid,
+                                 SYSKIND syskind);
+
+// Impersonates the user in case of interactive installs, and
+// the logged in user in case of non-interactive updates.
+HRESULT ImpersonateUser(bool is_interactive, uint32 explorer_pid);
+
+// Reverts the calling thread to self if impersonated.
+HRESULT UndoImpersonation(bool impersonated);
+
+// Returns the user's token either from the request or from the logged on
+// user's explorer process.
+HRESULT GetImpersonationToken(bool is_interactive,
+                              uint32 explorer_pid,
+                              HANDLE* out_token);
+
+// Returns whether the EULA is accepted for the app.
+bool IsAppEulaAccepted(bool is_machine,
+                       const CString& app_guid,
+                       bool require_explicit_acceptance);
+
+// Sets eulaaccepted=0 in the app's ClientState.
+HRESULT SetAppEulaNotAccepted(bool is_machine, const CString& app_guid);
+
+// Clears any eulaaccepted=0 values for the app.
+HRESULT ClearAppEulaNotAccepted(bool is_machine, const CString& app_guid);
+
+// Determines whether usage stats are enabled for a specific app.
+bool AreAppUsageStatsEnabled(bool is_machine, const CString& app_guid);
+
+// Configures Omaha's collection of usage stats and crash reports.
+HRESULT SetUsageStatsEnable(bool is_machine,
+                            const CString& app_guid,
+                            Tristate usage_stats_enable);
+
+// Copies legacy usage stats value to the new name and location then deletes
+// the old value.
+// TODO(omaha): Remove along with legacy Omaha 1.
+HRESULT ConvertLegacyUsageStats(bool is_machine);
+
+//
+// Scheduled Task methods.
+
+// This method will return the default scheduled task name. This default value
+// is also used as the prefix for generating unique task names.
+CString GetDefaultGoopdateTaskName(bool is_machine, CommandLineMode mode);
+HRESULT InstallGoopdateTasks(const TCHAR* task_path, bool is_machine);
+HRESULT UninstallGoopdateTasks(bool is_machine);
+HRESULT UninstallLegacyGoopdateTasks(bool is_machine);
+HRESULT StartGoopdateTaskCore(bool is_machine);
+bool IsInstalledGoopdateTaskUA(bool is_machine);
+bool IsDisabledGoopdateTaskUA(bool is_machine);
+HRESULT GetExitCodeGoopdateTaskUA(bool is_machine);
+
+// Gets the specified value from the registry for the application.
+HRESULT GetClientsStringValueFromRegistry(bool is_machine,
+                                          const CString& app_guid,
+                                          const CString& value_name,
+                                          CString* value);
+
+// Gets the application's version from the registry.
+HRESULT GetVerFromRegistry(bool is_machine,
+                           const CString& app_guid,
+                           CString* version);
+
+// Returns the absolute path of the browser image.
+HRESULT GetBrowserImagePathFromProcess(BrowserType type,
+                                       uint32 explorer_pid,
+                                       CString* path);
+
+// Terminates all browser processes for the current user.
+HRESULT TerminateBrowserProcesses(BrowserType type,
+                                  TerminateBrowserResult* browser_res,
+                                  TerminateBrowserResult* default_res);
+
+// Terminates both firefox and IE instances.
+HRESULT TerminateAllBrowsers(BrowserType type,
+                             TerminateBrowserResult* browser_res,
+                             TerminateBrowserResult* default_res);
+
+
+// Starts an instance of the browser. The explorer_pid indicates the user to
+// launch the browser as, in case of machine goopdate.
+HRESULT StartBrowserWithProcessToken(bool is_machine,
+                                     BrowserType type,
+                                     const CString& url,
+                                     uint32 explorer_pid);
+
+// Converts from string to the BrowserType enum.
+HRESULT ConvertStringToBrowserType(const CString& text, BrowserType* type);
+
+// Converts from BrowserType to string.
+CString ConvertBrowserTypeToString(BrowserType type);
+
+// Converts a string to the needs admin enum. Takes care of case.
+HRESULT ConvertStringToNeedsAdmin(const CString& text, NeedsAdmin* admin);
+
+// Converts the NeedsAdmin to a string.
+HRESULT ConvertNeedsAdminToString(NeedsAdmin needs_admin, CString* text);
+
+// Returns the browser to restart.
+bool GetBrowserToRestart(BrowserType type,
+                         BrowserType default_type,
+                         const TerminateBrowserResult& res,
+                         const TerminateBrowserResult& def_res,
+                         BrowserType* browser_type);
+
+// Returns whether the Goopdate service is installed.
+bool IsServiceInstalled();
+
+// Reads the value of the persistent id.
+HRESULT ReadPersistentId(const CString& key_name,
+                         const CString& value_name,
+                         CString* id);
+
+// Obtains the OS version and service pack.
+HRESULT GetOSInfo(CString* os_version, CString* service_pack);
+
+// Starts the default browser and navigates to a help center page
+// corresponding to the address and the exception code of the crash.
+HRESULT ShowUserCrashPage(const CString& language,
+                          uint64 address,
+                          uint32 code);
+
+// Returns the install directory for the specified version.
+CPath BuildInstallDirectory(bool is_machine, const CString& version);
+
+// Launches the browser. On Vista and later, for a machine install, this method
+// will launch the browser at medium/low integrity, by impersonating the medium
+// integrity token of the active user.
+HRESULT LaunchBrowser(BrowserType type, const CString& url);
+
+// Launches the command line. On Vista and later, for a machine install, this
+// method will launch the process at medium/low integrity, by impersonating the
+// medium integrity token of the active user.
+HRESULT LaunchCmdLine(const CString& cmd_line);
+
+// Converts the data contained in the response to the extra argument format.
+HRESULT ConvertResponseDataToExtraArgs(const UpdateResponseData& response,
+                                       CString* extra);
+
+// Converts the manifest_filename parameter to extra args and starts
+// an omaha2 install worker from the install directory.
+HRESULT HandleLegacyManifestHandoff(const CString& manifest_filename,
+                                    bool is_machine);
+
+// Gets a list of install worker processes relevant to user/machine instances.
+HRESULT GetInstallWorkerProcesses(bool is_machine,
+                                  std::vector<uint32>* processes);
+
+// Creates a unique event name and stores it in the specified environment var.
+HRESULT CreateUniqueEventInEnvironment(const CString& var_name,
+                                       bool is_machine,
+                                       HANDLE* unique_event);
+
+// Obtains a unique event name from specified environment var and opens it.
+HRESULT OpenUniqueEventFromEnvironment(const CString& var_name,
+                                       bool is_machine,
+                                       HANDLE* unique_event);
+
+// Creates an event based on the provided attributes.
+HRESULT CreateEvent(NamedObjectAttributes* event_attr, HANDLE* event_handle);
+
+// Initializes the network stack and adds the proxy detectors.
+HRESULT ConfigureNetwork(bool is_machine, bool is_local_system);
+
+HRESULT ReadNameValuePairsFromFile(const CString& file_path,
+                                   const CString& group_name,
+                                   std::map<CString, CString>* pairs);
+
+HRESULT WriteNameValuePairsToFile(const CString& file_path,
+                                  const CString& group_name,
+                                  const std::map<CString, CString>& pairs);
+
+// Writes branding information for Google Update in the registry if it does not
+// already exist. Otherwise, the information remains unchanged.
+// Writes a default Omaha-specific brand code if one is not specified in args.
+HRESULT SetGoogleUpdateBranding(const CString& client_state_key_path,
+                                const CString& brand_code,
+                                const CString& client_id);
+
+
+// Writes branding information for apps in the registry if it does not
+// already exist. Otherwise, the information remains unchanged.
+// Writes a default Omaha-specific brand code if one is not specified in args.
+HRESULT SetAppBranding(const CString& client_state_key_path,
+                       const CString& brand_code,
+                       const CString& client_id,
+                       const CString& referral_id);
+
+// Returns true is any of the install workers is running.
+bool IsAppInstallWorkerRunning(bool is_machine);
+
+// Returns whether a process is a machine process.
+// Does not determine whether the process has the appropriate privileges.
+bool IsMachineProcess(
+    CommandLineMode mode,
+    bool is_running_from_official_machine_directory,
+    bool is_local_system,  // Whether process is running as local system.
+    bool is_machine_override,  // True if machine cmd line override specified.
+    Tristate needs_admin);  // needsadmin value for primary app if present.
+
+// Returns whether the version is an "Omaha 2" version or later.
+bool IsGoogleUpdate2OrLater(const CString& version);
+
+// Formats an error message for network errors. Returns true if the error has
+// a specific message. Otherwise, formats a generic network connection message
+// and returns false.
+bool FormatMessageForNetworkError(HRESULT error,
+                                  const CString app_name,
+                                  CString* msg);
+
+// Adds details about the network_request to the event log as an error.
+void AddNetworkRequestDataToEventLog(NetworkRequest* network_request,
+                                     HRESULT hr);
+
+// Converts the installer_data value to UTF8. Then writes this UTF8 data
+// prefixed with the UTF8 BOM of EF BB BF to a temp file. Returns the path to
+// temp file that was created.  The returned path will be quote-enclosed by
+// EnclosePath().
+HRESULT WriteInstallerDataToTempFile(const CString& installer_data,
+                                     CString* installer_data_file_path);
+
+// Returns the number of clients registered under the "Clients" sub key.
+HRESULT GetNumClients(bool is_machine, size_t* num_clients);
+
+// Validates the hash of the file. If the hash does not match, checks the size
+// to determine whether the problem was corruption or file size.
+HRESULT ValidateDownloadedFile(const CString& file_name,
+                               const CString& hash,
+                               uint32 size);
+
+void DisplayErrorInMessageBox(const CString& error_text,
+                              const CString& primary_app_name);
+
+}  // namespace goopdate_utils
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_GOOPDATE_UTILS_H__
diff --git a/goopdate/goopdate_utils_unittest.cc b/goopdate/goopdate_utils_unittest.cc
index 9dd1877..6ac733f 100644
--- a/goopdate/goopdate_utils_unittest.cc
+++ b/goopdate/goopdate_utils_unittest.cc
@@ -1,4820 +1,4820 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <atlpath.h>

-#include <atlsecurity.h>

-#include <atlstr.h>

-#include <map>

-#include <vector>

-#include "omaha/common/app_util.h"

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/const_utils.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_ptr_cotask.h"

-#include "omaha/common/string.h"

-#include "omaha/common/time.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/common/vista_utils.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/extra_args_parser.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/goopdate_utils-internal.h"

-#include "omaha/testing/resource.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-#define DUMMY_CLSID  _T("{6FC94136-0D4C-450e-99C2-BCDA72A9C8F0}")

-const TCHAR* hkcr_key_name = _T("HKCR\\CLSID\\") DUMMY_CLSID;

-const TCHAR* hklm_key_name = _T("HKLM\\Software\\Classes\\CLSID\\")

-                             DUMMY_CLSID;

-const TCHAR* hkcu_key_name = _T("HKCU\\Software\\Classes\\CLSID\\")

-                             DUMMY_CLSID;

-

-#define APP_GUID _T("{B7BAF788-9D64-49c3-AFDC-B336AB12F332}")

-const TCHAR* const kAppGuid = APP_GUID;

-const TCHAR* const kAppMachineClientStatePath =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\") APP_GUID;

-const TCHAR* const kAppUserClientStatePath =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\") APP_GUID;

-const TCHAR* const kAppMachineClientStateMediumPath =

-    _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\") APP_GUID;

-

-// This should never exist. This contant is only used to verify it is not used.

-const TCHAR* const kAppUserClientStateMediumPath =

-    _T("HKCU\\Software\\Google\\Update\\ClientStateMedium\\") APP_GUID;

-

-// Constants used in the scheduled task tests.

-const int kMaxWaitForProcessMs              = 5000;

-const int kWaitForProcessIntervalMs         = 100;

-const int kMaxWaitForProcessIterations      =

-    kMaxWaitForProcessMs / kWaitForProcessIntervalMs;

-

-// Verifies that one of the expected OS strings was found in the url.

-// Returns the position along with the length of the OS string.

-int VerifyOSInUrl(const CString& url, int* length) {

-  ASSERT1(length);

-  *length = 0;

-

-  // The strings are in descending version order to avoid breaking on a

-  // substring of the version we are looking for.

-  const TCHAR* kExpectedOsStrings[] = {_T("6.0&sp=Service%20Pack%201"),

-                                       _T("6.0&sp="),

-                                       _T("5.2&sp=Service%20Pack%202"),

-                                       _T("5.2&sp=Service%20Pack%201"),

-                                       _T("5.1&sp=Service%20Pack%203"),

-                                       _T("5.1&sp=Service%20Pack%202"),

-                                      };

-

-  bool found = false;

-  int this_pos = 0;

-

-  for (int i = 0; i < arraysize(kExpectedOsStrings); ++i) {

-    this_pos = url.Find(kExpectedOsStrings[i]);

-    if (-1 != this_pos) {

-      found = true;

-      *length = _tcslen(kExpectedOsStrings[i]);

-      break;

-    }

-  }

-

-  EXPECT_TRUE(found);

-  return this_pos;

-}

-

-}  // namespace

-

-namespace goopdate_utils {

-

-namespace internal {

-

-TEST(GoopdateUtilsTest, ScheduledTasks) {

-  const TCHAR kSchedTestTaskName[]            = _T("TestScheduledTask");

-  const TCHAR kScheduledTaskExecutable[]      = _T("netstat.exe");

-  const TCHAR kScheduledTaskParameters[]      = _T("20");

-  const TCHAR kSchedTestTaskComment[]         = _T("Google Test Task");

-

-  CString task_path = ConcatenatePath(app_util::GetSystemDir(),

-                                      kScheduledTaskExecutable);

-  // Install/uninstall.

-  EXPECT_SUCCEEDED(InstallScheduledTask(kSchedTestTaskName,

-                                        task_path,

-                                        _T(""),

-                                        kSchedTestTaskComment,

-                                        vista_util::IsUserAdmin(),

-                                        vista_util::IsUserAdmin(),

-                                        true,

-                                        true));

-  EXPECT_SUCCEEDED(UninstallScheduledTask(kSchedTestTaskName));

-

-  // Calling InstallScheduledTask twice should succeed.

-  for (int i = 0; i < 2; ++i) {

-    EXPECT_SUCCEEDED(InstallScheduledTask(kSchedTestTaskName,

-                                          task_path,

-                                          _T(""),

-                                          kSchedTestTaskComment,

-                                          vista_util::IsUserAdmin(),

-                                          vista_util::IsUserAdmin(),

-                                          true,

-                                          true));

-  }

-

-  // "Upgrade" to a new version, which now has parameters.

-  EXPECT_SUCCEEDED(InstallScheduledTask(kSchedTestTaskName,

-                                        task_path,

-                                        kScheduledTaskParameters,

-                                        kSchedTestTaskComment,

-                                        vista_util::IsUserAdmin(),

-                                        vista_util::IsUserAdmin(),

-                                        true,

-                                        true));

-

-  // Start and stop.

-  EXPECT_SUCCEEDED(StartScheduledTask(kSchedTestTaskName));

-  HRESULT hr = E_FAIL;

-  for (int tries = 0;

-       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_RUNNING != hr;

-       ++tries) {

-    ::Sleep(kWaitForProcessIntervalMs);

-    hr = GetScheduledTaskStatus(kSchedTestTaskName);

-  }

-  EXPECT_EQ(SCHED_S_TASK_RUNNING, hr);

-

-  // Without a wait in between the start and stop, stop failed intermittently.

-  ::Sleep(500);

-

-  EXPECT_SUCCEEDED(StopScheduledTask(kSchedTestTaskName));

-  hr = SCHED_S_TASK_RUNNING;

-  for (int tries = 0;

-       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_RUNNING == hr;

-       ++tries) {

-    ::Sleep(kWaitForProcessIntervalMs);

-    hr = GetScheduledTaskStatus(kSchedTestTaskName);

-  }

-  EXPECT_NE(SCHED_S_TASK_RUNNING, hr);

-

-  // Finally, uninstall.

-  EXPECT_SUCCEEDED(UninstallScheduledTask(kSchedTestTaskName));

-}

-

-}  // namespace internal

-

-static void Cleanup() {

-  ASSERT_SUCCEEDED(goopdate_utils::RemoveRedirectHKCR());

-

-  RegKey::DeleteKey(hkcr_key_name, true);

-  RegKey::DeleteKey(hklm_key_name, true);

-  RegKey::DeleteKey(hkcu_key_name, true);

-}

-

-static void TestGetBrowserToRestart(BrowserType stamped,

-                                    bool found1,

-                                    bool killed1,

-                                    BrowserType def_browser,

-                                    bool found2,

-                                    bool killed2,

-                                    BrowserType expected) {

-  TerminateBrowserResult res(found1, killed1);

-  TerminateBrowserResult def(found2, killed2);

-

-  BrowserType type = BROWSER_UNKNOWN;

-  if (expected == BROWSER_UNKNOWN) {

-    EXPECT_FALSE(goopdate_utils::GetBrowserToRestart(stamped,

-                                                     def_browser,

-                                                     res,

-                                                     def,

-                                                     &type))

-        << _T("stamped: ") << stamped << _T(" ") << found1 << _T(" ") << killed1

-        << _T("   default: ") << def_browser << _T(" ") << found2 << _T(" ")

-        << killed2;

-  } else {

-    EXPECT_TRUE(goopdate_utils::GetBrowserToRestart(stamped,

-                                                    def_browser,

-                                                    res,

-                                                    def,

-                                                    &type))

-        << _T("stamped: ") << stamped << _T(" ") << found1 << _T(" ") << killed1

-        << _T("   default: ") << def_browser << _T(" ") << found2 << _T(" ")

-        << killed2;

-  }

-  EXPECT_EQ(expected, type)

-      << _T("stamped: ") << stamped << _T(" ") << found1 << _T(" ") << killed1

-      << _T("   default: ") << def_browser << _T(" ") << found2 << _T(" ")

-      << killed2;

-}

-

-TEST(GoopdateUtilsTest, GetAppClientsKey) {

-  const TCHAR kAppGuid[] = _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}");

-

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\Clients\\")

-               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),

-               goopdate_utils::GetAppClientsKey(false, kAppGuid));

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\Clients\\")

-               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),

-               goopdate_utils::GetAppClientsKey(true, kAppGuid));

-}

-

-TEST(GoopdateUtilsTest, GetAppClientStateKey) {

-  const TCHAR kAppGuid[] = _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}");

-

-  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\ClientState\\")

-               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),

-               goopdate_utils::GetAppClientStateKey(false, kAppGuid));

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientState\\")

-               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),

-               goopdate_utils::GetAppClientStateKey(true, kAppGuid));

-}

-

-// This is an invalid case and causes an assert. Always returns HKLM path.

-TEST(GoopdateUtilsTest, GetAppClientStateMediumKey_User) {

-  const TCHAR kAppGuid[] = _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}");

-  ExpectAsserts expect_asserts;

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\")

-               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),

-               goopdate_utils::GetAppClientStateMediumKey(false, kAppGuid));

-}

-

-TEST(GoopdateUtilsTest, GetAppClientStateMediumKey_Machine) {

-  const TCHAR kAppGuid[] = _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}");

-  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\")

-               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),

-               goopdate_utils::GetAppClientStateMediumKey(true, kAppGuid));

-}

-

-// This is an invalid case and causes an assert.

-TEST(GoopdateUtilsTest, GetAppClientStateMediumKey_UserAndMachineAreSame) {

-  const TCHAR kAppGuid[] = _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}");

-  ExpectAsserts expect_asserts;

-  EXPECT_STREQ(goopdate_utils::GetAppClientStateMediumKey(true, kAppGuid),

-               goopdate_utils::GetAppClientStateMediumKey(false, kAppGuid));

-}

-

-TEST(GoopdateUtilsTest, TerminateAllBrowsers_BrowserUnknown) {

-  TerminateBrowserResult browser_res;

-  TerminateBrowserResult default_res;

-  ExpectAsserts expect_asserts;

-  EXPECT_EQ(E_INVALIDARG, goopdate_utils::TerminateAllBrowsers(BROWSER_UNKNOWN,

-                                                               &browser_res,

-                                                               &default_res));

-}

-

-TEST(GoopdateUtilsTest, TerminateAllBrowsers_BrowserDefault) {

-  TerminateBrowserResult browser_res;

-  TerminateBrowserResult default_res;

-  ExpectAsserts expect_asserts;

-  EXPECT_EQ(E_INVALIDARG, goopdate_utils::TerminateAllBrowsers(BROWSER_DEFAULT,

-                                                               &browser_res,

-                                                               &default_res));

-}

-

-TEST(GoopdateUtilsTest, TerminateAllBrowsers_BrowserMax) {

-  TerminateBrowserResult browser_res;

-  TerminateBrowserResult default_res;

-  ExpectAsserts expect_asserts;

-  EXPECT_EQ(E_INVALIDARG, goopdate_utils::TerminateAllBrowsers(BROWSER_MAX,

-                                                               &browser_res,

-                                                               &default_res));

-}

-

-// TerminateAllBrowsers is not tested with valid browser values because the

-// tests would terminate developers' browsers.

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedUnknown) {

-  ExpectAsserts expect_asserts;

-  TestGetBrowserToRestart(BROWSER_UNKNOWN, false, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_UNKNOWN, true, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_DefaultUnknown) {

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedAndDefaultUnknown) {

-  ExpectAsserts expect_asserts;

-  TestGetBrowserToRestart(BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_UNKNOWN, true, false,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedDefault) {

-  ExpectAsserts expect_asserts;

-  TestGetBrowserToRestart(BROWSER_DEFAULT, false, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_DEFAULT, true, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_DefaultDefault) {

-  ExpectAsserts expect_asserts;

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_DEFAULT, false, false,

-                          BROWSER_UNKNOWN);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedAndDefaultDefault) {

-  ExpectAsserts expect_asserts;

-  TestGetBrowserToRestart(BROWSER_DEFAULT, false, false,

-                          BROWSER_DEFAULT, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_DEFAULT, true, false,

-                          BROWSER_DEFAULT, false, false,

-                          BROWSER_UNKNOWN);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedMax) {

-  ExpectAsserts expect_asserts;

-  TestGetBrowserToRestart(BROWSER_MAX, false, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_MAX, true, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_DefaultMax) {

-  ExpectAsserts expect_asserts;

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_MAX, false, false,

-                          BROWSER_UNKNOWN);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedAndDefaultMax) {

-  ExpectAsserts expect_asserts;

-  TestGetBrowserToRestart(BROWSER_MAX, false, false,

-                          BROWSER_MAX, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_MAX, true, false,

-                          BROWSER_MAX, false, false,

-                          BROWSER_UNKNOWN);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeIE_DefaultIE) {

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_IE, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_IE, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_IE, true, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_IE, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_IE, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_IE, true, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_IE, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_IE, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_IE, true, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_IE, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_IE, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_IE, true, true,

-                          BROWSER_IE);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeIE_DefaultFirefox) {

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_IE);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeIE_DefaultChrome) {

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_IE);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeIE_DefaultUnknown) {

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, false,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, false, true,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, false,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_IE, true, true,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_IE);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeFirefox_DefaultIE) {

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_IE, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_IE, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_IE, true, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_IE, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_IE, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_IE, true, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_IE, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_IE, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_IE, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_IE, false, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_IE, false, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_IE, true, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_IE, true, true,

-                          BROWSER_FIREFOX);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeFirefox_DefaultFirefox) {

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeFirefox_DefaultChrome) {

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_FIREFOX);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeFirefox_DefaultUnknown) {

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_FIREFOX);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeChrome_DefaultIE) {

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_IE, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_IE, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_IE, true, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_IE, false, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_IE, false, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_IE, true, false,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_IE, true, true,

-                          BROWSER_IE);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_IE, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_IE, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_IE, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_IE, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_IE, false, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_IE, false, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_IE, true, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_IE, true, true,

-                          BROWSER_CHROME);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeChrome_DefaultFirefox) {

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_FIREFOX);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_FIREFOX, false, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_FIREFOX, false, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_FIREFOX, true, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_FIREFOX, true, true,

-                          BROWSER_CHROME);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeChrome_DefaultChrome) {

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_CHROME, false, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_CHROME, false, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_CHROME, true, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_CHROME, true, true,

-                          BROWSER_CHROME);

-}

-

-TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeChrome_DefaultUnknown) {

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, false,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, false, true,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, false,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_UNKNOWN);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_UNKNOWN, false, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_UNKNOWN, false, true,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_UNKNOWN, true, false,

-                          BROWSER_CHROME);

-  TestGetBrowserToRestart(BROWSER_CHROME, true, true,

-                          BROWSER_UNKNOWN, true, true,

-                          BROWSER_CHROME);

-}

-

-TEST(GoopdateUtilsTest, ConvertStringToBrowserType) {

-  BrowserType type = BROWSER_UNKNOWN;

-  ASSERT_SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(_T("0"), &type));

-  ASSERT_EQ(BROWSER_UNKNOWN, type);

-

-  ASSERT_SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(_T("1"), &type));

-  ASSERT_EQ(BROWSER_DEFAULT, type);

-

-  ASSERT_SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(_T("2"), &type));

-  ASSERT_EQ(BROWSER_IE, type);

-

-  ASSERT_SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(_T("3"), &type));

-  ASSERT_EQ(BROWSER_FIREFOX, type);

-

-  ASSERT_SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(_T("4"), &type));

-  ASSERT_EQ(BROWSER_CHROME, type);

-

-  ASSERT_FAILED(goopdate_utils::ConvertStringToBrowserType(_T("5"), &type));

-  ASSERT_FAILED(goopdate_utils::ConvertStringToBrowserType(_T("asdf"), &type));

-  ASSERT_FAILED(goopdate_utils::ConvertStringToBrowserType(_T("234"), &type));

-  ASSERT_FAILED(goopdate_utils::ConvertStringToBrowserType(_T("-1"), &type));

-}

-

-TEST(GoopdateUtilsTest, RedirectHKCRTest) {

-  RegKey key;

-  Cleanup();

-

-  if (vista_util::IsUserAdmin()) {

-    // Only run this part of the test for Admins, because non-admins cannot

-    // write to HKLM.

-

-    // Without redirection, a HKCR write should write HKLM\Software\Classes,

-    // assuming that the key does not already exist in HKCU.

-    ASSERT_SUCCEEDED(key.Create(hkcr_key_name));

-    ASSERT_TRUE(RegKey::HasKey(hklm_key_name));

-    ASSERT_FALSE(RegKey::HasKey(hkcu_key_name));

-

-    Cleanup();

-

-    ASSERT_SUCCEEDED(goopdate_utils::RedirectHKCR(true));

-

-    // With HKLM redirection, a HKCR write should write HKLM\Software\Classes.

-    ASSERT_SUCCEEDED(key.Create(hkcr_key_name));

-    ASSERT_TRUE(RegKey::HasKey(hklm_key_name));

-    ASSERT_FALSE(RegKey::HasKey(hkcu_key_name));

-

-    Cleanup();

-  } else {

-    std::wcout << _T("\tPart of this test did not run because the user ")

-                  _T("is not an admin.") << std::endl;

-  }

-

-  ASSERT_SUCCEEDED(goopdate_utils::RedirectHKCR(false));

-

-  // With HKCU redirection, a HKCR write should write HKCU\Software\Classes.

-  ASSERT_SUCCEEDED(key.Create(hkcr_key_name));

-  ASSERT_FALSE(RegKey::HasKey(hklm_key_name));

-  ASSERT_TRUE(RegKey::HasKey(hkcu_key_name));

-

-  ASSERT_SUCCEEDED(goopdate_utils::RemoveRedirectHKCR());

-

-  if (vista_util::IsUserAdmin()) {

-    // Without redirection, the following HKCR writes should write

-    // HKCU\Software\Classes.

-    // This is because the key already exists in HKCU from the writes above.

-    ASSERT_SUCCEEDED(key.Create(hkcr_key_name));

-    ASSERT_FALSE(RegKey::HasKey(hklm_key_name));

-    ASSERT_TRUE(RegKey::HasKey(hkcu_key_name));

-  } else {

-    std::wcout << _T("\tPart of this test did not run because the user ")

-                  _T("is not an admin.") << std::endl;

-  }

-

-  Cleanup();

-}

-

-TEST(GoopdateUtilsTest, GetImpersonationTokenNotInteractivePid0) {

-  HANDLE token = NULL;

-  ASSERT_SUCCEEDED(goopdate_utils::GetImpersonationToken(false, 0, &token));

-  ASSERT_TRUE(token != NULL);

-  ASSERT_TRUE(::CloseHandle(token));

-  token = NULL;

-}

-

-TEST(GoopdateUtilsTest, GetImpersonationTokenNotInteractiveRealPid) {

-  HANDLE token = NULL;

-  DWORD pid = ::GetCurrentProcessId();

-  ASSERT_SUCCEEDED(goopdate_utils::GetImpersonationToken(false, pid, &token));

-  ASSERT_TRUE(token != NULL);

-  ASSERT_TRUE(::CloseHandle(token));

-  token = NULL;

-}

-

-TEST(GoopdateUtilsTest, GetImpersonationTokenInteractiveValidPid) {

-  HANDLE token = NULL;

-  DWORD pid = ::GetCurrentProcessId();

-  ASSERT_SUCCEEDED(goopdate_utils::GetImpersonationToken(true, pid, &token));

-  ASSERT_TRUE(token != NULL);

-  ASSERT_TRUE(::CloseHandle(token));

-}

-

-TEST(GoopdateUtilsTest, GetImpersonationTokenInteractiveInvalidPid) {

-  HANDLE token = NULL;

-  ASSERT_EQ(E_INVALIDARG,

-            goopdate_utils::GetImpersonationToken(true, 0, &token));

-  ASSERT_TRUE(token == NULL);

-}

-

-TEST(GoopdateUtilsTest, ImpersonateUser) {

-  DWORD pid = ::GetCurrentProcessId();

-

-  if (vista_util::IsUserAdmin()) {

-    ASSERT_SUCCEEDED(goopdate_utils::ImpersonateUser(false, 0));

-    ASSERT_SUCCEEDED(goopdate_utils::UndoImpersonation(true));

-

-    ASSERT_SUCCEEDED(goopdate_utils::ImpersonateUser(false, pid));

-    ASSERT_SUCCEEDED(goopdate_utils::UndoImpersonation(true));

-

-    ASSERT_SUCCEEDED(goopdate_utils::ImpersonateUser(true, pid));

-    ASSERT_SUCCEEDED(goopdate_utils::UndoImpersonation(true));

-

-    ASSERT_EQ(E_INVALIDARG, goopdate_utils::ImpersonateUser(true, 0));

-  } else {

-    std::wcout << _T("\tThis test did not run because the user ")

-                  _T("is not an admin.") << std::endl;

-  }

-}

-

-TEST(GoopdateUtilsTest, GoopdateTasks) {

-  CString task_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                      _T("LongRunningSilent.exe"));

-  // Install/uninstall.

-  EXPECT_SUCCEEDED(InstallGoopdateTasks(task_path,

-                                        vista_util::IsUserAdmin()));

-  EXPECT_SUCCEEDED(UninstallGoopdateTasks(vista_util::IsUserAdmin()));

-

-  // Calling InstallGoopdateTask twice should succeed.

-  for (int i = 0; i < 2; ++i) {

-    EXPECT_SUCCEEDED(InstallGoopdateTasks(task_path,

-                                          vista_util::IsUserAdmin()));

-  }

-

-  // Start and stop.

-  EXPECT_SUCCEEDED(StartGoopdateTaskCore(vista_util::IsUserAdmin()));

-  HRESULT hr = E_FAIL;

-  for (int tries = 0;

-       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_RUNNING != hr;

-       ++tries) {

-    ::Sleep(kWaitForProcessIntervalMs);

-    hr = internal::GetScheduledTaskStatus(

-        ConfigManager::GetCurrentTaskNameCore(vista_util::IsUserAdmin()));

-  }

-  EXPECT_EQ(SCHED_S_TASK_RUNNING, hr);

-

-  // Without a wait in between the start and stop, stop failed intermittently.

-  ::Sleep(500);

-

-  EXPECT_SUCCEEDED(internal::StopScheduledTask(

-      ConfigManager::GetCurrentTaskNameCore(vista_util::IsUserAdmin())));

-  hr = SCHED_S_TASK_RUNNING;

-  for (int tries = 0;

-       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_RUNNING == hr;

-       ++tries) {

-    ::Sleep(kWaitForProcessIntervalMs);

-    hr = internal::GetScheduledTaskStatus(

-        ConfigManager::GetCurrentTaskNameCore(vista_util::IsUserAdmin()));

-  }

-  EXPECT_NE(SCHED_S_TASK_RUNNING, hr);

-

-  // Finally, uninstall.

-  EXPECT_SUCCEEDED(UninstallGoopdateTasks(vista_util::IsUserAdmin()));

-}

-

-TEST(GoopdateUtilsTest, GoopdateTaskInUseOverinstall) {

-  CString task_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                      _T("LongRunningSilent.exe"));

-  EXPECT_SUCCEEDED(InstallGoopdateTasks(task_path,

-                                        vista_util::IsUserAdmin()));

-

-  CString original_task_name(

-      ConfigManager::GetCurrentTaskNameCore(vista_util::IsUserAdmin()));

-

-  // Open the file underlying the current task in exclusive mode, so that

-  // InstallGoopdateTasks() is forced to create a new task.

-  CComPtr<ITaskScheduler> scheduler;

-  EXPECT_SUCCEEDED(scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                              NULL,

-                                              CLSCTX_INPROC_SERVER));

-  CComPtr<ITask> task;

-  EXPECT_SUCCEEDED(scheduler->Activate(original_task_name,

-                                       __uuidof(ITask),

-                                       reinterpret_cast<IUnknown**>(&task)));

-  CComQIPtr<IPersistFile> persist(task);

-  EXPECT_TRUE(persist);

-  scoped_ptr_cotask<OLECHAR> job_file;

-  EXPECT_SUCCEEDED(persist->GetCurFile(address(job_file)));

-  persist.Release();

-

-  File file;

-  EXPECT_SUCCEEDED(file.OpenShareMode(job_file.get(), false, false, 0));

-

-  EXPECT_SUCCEEDED(InstallGoopdateTasks(task_path,

-                                        vista_util::IsUserAdmin()));

-  CString new_task_name(

-      ConfigManager::GetCurrentTaskNameCore(vista_util::IsUserAdmin()));

-  EXPECT_STRNE(original_task_name, new_task_name);

-

-  // Cleanup.

-  file.Close();

-  EXPECT_SUCCEEDED(UninstallGoopdateTasks(vista_util::IsUserAdmin()));

-}

-

-TEST(GoopdateUtilsTest, GetExitCodeGoopdateTaskUA) {

-  CString task_path = ConcatenatePath(

-                          app_util::GetCurrentModuleDirectory(),

-                          _T("unittest_support\\SaveArguments.exe"));

-  EXPECT_SUCCEEDED(InstallGoopdateTasks(task_path,

-                                        vista_util::IsUserAdmin()));

-  EXPECT_EQ(SCHED_S_TASK_HAS_NOT_RUN,

-            GetExitCodeGoopdateTaskUA(vista_util::IsUserAdmin()));

-

-  EXPECT_SUCCEEDED(internal::StartScheduledTask(

-      ConfigManager::GetCurrentTaskNameUA(vista_util::IsUserAdmin())));

-

-  HRESULT hr = SCHED_S_TASK_HAS_NOT_RUN;

-  for (int tries = 0;

-       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_HAS_NOT_RUN == hr;

-       ++tries) {

-    ::Sleep(kWaitForProcessIntervalMs);

-    hr = internal::GetScheduledTaskStatus(

-        ConfigManager::GetCurrentTaskNameUA(vista_util::IsUserAdmin()));

-  }

-

-  hr = SCHED_S_TASK_RUNNING;

-  for (int tries = 0;

-       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_RUNNING == hr;

-       ++tries) {

-    ::Sleep(kWaitForProcessIntervalMs);

-    hr = internal::GetScheduledTaskStatus(

-        ConfigManager::GetCurrentTaskNameUA(vista_util::IsUserAdmin()));

-  }

-

-  EXPECT_NE(SCHED_S_TASK_RUNNING, hr);

-  EXPECT_EQ(S_OK, GetExitCodeGoopdateTaskUA(vista_util::IsUserAdmin()));

-

-  EXPECT_SUCCEEDED(File::Remove(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("unittest_support\\saved_arguments.txt"))));

-  EXPECT_SUCCEEDED(UninstallGoopdateTasks(vista_util::IsUserAdmin()));

-}

-

-TEST(GoopdateUtilsTest, GetOSInfo) {

-  const TCHAR kXpOSVersion[] = _T("5.1");

-  const TCHAR k2003OSVersion[] = _T("5.2");

-  const TCHAR kVistaOSVersion[] = _T("6.0");

-  const TCHAR kNoSp[] = _T("");

-  const TCHAR kSp1[] = _T("Service Pack 1");

-  const TCHAR kSp2[] = _T("Service Pack 2");

-  const TCHAR kSp3[] = _T("Service Pack 3");

-

-  CString os_version;

-  CString service_pack;

-  EXPECT_SUCCEEDED(goopdate_utils::GetOSInfo(&os_version, &service_pack));

-

-  EXPECT_TRUE((kXpOSVersion == os_version && kSp2 == service_pack) ||

-              (kXpOSVersion == os_version && kSp3 == service_pack) ||

-              (k2003OSVersion == os_version && kSp1 == service_pack) ||

-              (k2003OSVersion == os_version && kSp2 == service_pack) ||

-              (kVistaOSVersion == os_version && kNoSp == service_pack) ||

-              (kVistaOSVersion == os_version && kSp1 == service_pack));

-}

-

-class GoopdateUtilsRegistryProtectedTest : public testing::Test {

- protected:

-  GoopdateUtilsRegistryProtectedTest()

-      : hive_override_key_name_(kRegistryHiveOverrideRoot) {

-  }

-

-  CString hive_override_key_name_;

-

-  virtual void SetUp() {

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    OverrideRegistryHives(hive_override_key_name_);

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-  }

-};

-

-// Some methods used by goopdate_utils rely on registry entries that are

-// overridden in the registry, so we need to write it.

-class GoopdateUtilsRegistryProtectedWithMachineFolderPathsTest

-    : public GoopdateUtilsRegistryProtectedTest {

- protected:

-  virtual void SetUp() {

-    const TCHAR kWindowsCurrentVersionKeyPath[] =

-        _T("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion");

-    const TCHAR kProgramFilesDirValueName[] = _T("ProgramFilesDir");

-    const TCHAR kProgramFilesPath[] = _T("C:\\Program Files");

-

-    GoopdateUtilsRegistryProtectedTest::SetUp();

-    ASSERT_SUCCEEDED(RegKey::SetValue(kWindowsCurrentVersionKeyPath,

-                                      kProgramFilesDirValueName,

-                                      kProgramFilesPath));

-  }

-};

-

-// Some methods used by goopdate_utils rely on registry entries that are

-// overridden in the registry, so we need to write it.

-class GoopdateUtilsRegistryProtectedWithUserFolderPathsTest

-    : public GoopdateUtilsRegistryProtectedTest {

- protected:

-  virtual void SetUp() {

-  const TCHAR kUserShellKeyPath[] =

-        _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\")

-        _T("User Shell Folders");

-    const TCHAR kLocalAppDataValueDirName[] = _T("Local AppData");

-    const TCHAR kLocalAppDataPath[] =

-        _T("%USERPROFILE%\\Local Settings\\Application Data");

-

-    GoopdateUtilsRegistryProtectedTest::SetUp();

-    ASSERT_SUCCEEDED(RegKey::SetValueExpandSZ(kUserShellKeyPath,

-                                              kLocalAppDataValueDirName,

-                                              kLocalAppDataPath));

-  }

-};

-

-// pv should be ignored.

-TEST_F(GoopdateUtilsRegistryProtectedWithMachineFolderPathsTest,

-       BuildGoogleUpdateExePath_MachineVersionFound) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  CString path = goopdate_utils::BuildGoogleUpdateExePath(true);

-  CString program_files_path;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files_path));

-  EXPECT_STREQ(program_files_path + _T("\\Google\\Update\\GoogleUpdate.exe"),

-               path);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedWithMachineFolderPathsTest,

-       BuildGoogleUpdateExePath_MachineVersionNotFound) {

-  // Test when the key doesn't exist.

-  CString path = goopdate_utils::BuildGoogleUpdateExePath(true);

-  CString program_files_path;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files_path));

-  EXPECT_STREQ(program_files_path + _T("\\Google\\Update\\GoogleUpdate.exe"),

-               path);

-

-  // Test when the key exists but the value doesn't.

-  ASSERT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENTS_GOOPDATE));

-  path = goopdate_utils::BuildGoogleUpdateExePath(true);

-  EXPECT_STREQ(program_files_path + _T("\\Google\\Update\\GoogleUpdate.exe"),

-               path);

-}

-

-// pv should be ignored.

-TEST_F(GoopdateUtilsRegistryProtectedWithUserFolderPathsTest,

-       BuildGoogleUpdateExePath_UserVersionFound) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  CString path = goopdate_utils::BuildGoogleUpdateExePath(false);

-

-  CString user_appdata;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_LOCAL_APPDATA, &user_appdata));

-  CString expected_path;

-  expected_path.Format(_T("%s\\Google\\Update\\GoogleUpdate.exe"),

-                       user_appdata);

-  EXPECT_STREQ(expected_path, path);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedWithUserFolderPathsTest,

-       BuildGoogleUpdateExePath_UserVersionNotFound) {

-  CString user_appdata;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_LOCAL_APPDATA, &user_appdata));

-  CString expected_path;

-  expected_path.Format(_T("%s\\Google\\Update\\GoogleUpdate.exe"),

-                       user_appdata);

-

-  // Test when the key doesn't exist.

-  CString path = goopdate_utils::BuildGoogleUpdateExePath(false);

-  EXPECT_STREQ(expected_path, path);

-

-  // Test when the key exists but the value doesn't.

-  ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENTS_GOOPDATE));

-  path = goopdate_utils::BuildGoogleUpdateExePath(false);

-  EXPECT_STREQ(expected_path, path);

-}

-

-// The version is no longer used by StartGoogleUpdateWithArgs, so the return

-// value depends on whether program_files\Google\Update\GoogleUpdate.exe exists.

-TEST_F(GoopdateUtilsRegistryProtectedWithMachineFolderPathsTest,

-       StartGoogleUpdateWithArgs_MachineVersionVersionDoesNotExist) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  const TCHAR* kArgs = _T("/foo");

-  HRESULT hr = goopdate_utils::StartGoogleUpdateWithArgs(true, kArgs, NULL);

-  EXPECT_TRUE(S_OK == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);

-}

-

-// The version is no longer used by StartGoogleUpdateWithArgs, so the return

-// value depends on whether <user_folder>\Google\Update\GoogleUpdate.exe exists.

-// Also tests NULL args parameter

-TEST_F(GoopdateUtilsRegistryProtectedWithUserFolderPathsTest,

-       StartGoogleUpdateWithArgs_UserVersionVersionDoesNotExist) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  HRESULT hr = goopdate_utils::StartGoogleUpdateWithArgs(false, NULL, NULL);

-  EXPECT_TRUE(S_OK == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, GetPersistentUserId_User) {

-  CString id;

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(USER_KEY_NAME,

-                                                 kRegValueUserId,

-                                                 &id));

-

-  CString uid = goopdate_utils::GetPersistentUserId(USER_KEY_NAME);

-  EXPECT_FALSE(uid.IsEmpty());

-

-  EXPECT_SUCCEEDED(goopdate_utils::ReadPersistentId(USER_KEY_NAME,

-                                                    kRegValueUserId,

-                                                    &id));

-  EXPECT_STREQ(uid, id);

-

-  uid = goopdate_utils::GetPersistentUserId(USER_KEY_NAME);

-  EXPECT_STREQ(uid, id);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, GetPersistentUserId_Machine) {

-  CString id;

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                 kRegValueUserId,

-                                                 &id));

-

-  CString uid = goopdate_utils::GetPersistentUserId(MACHINE_KEY_NAME);

-  EXPECT_FALSE(uid.IsEmpty());

-

-  EXPECT_SUCCEEDED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                    kRegValueUserId,

-                                                    &id));

-  EXPECT_STREQ(uid, id);

-

-  uid = goopdate_utils::GetPersistentUserId(MACHINE_KEY_NAME);

-  EXPECT_STREQ(uid, id);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, GetPersistentMachineId_Machine) {

-  // Initially there is no machine id.

-  CString id;

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                 kRegValueMachineId,

-                                                 &id));

-  // Call the test method.

-  CString mid = goopdate_utils::GetPersistentMachineId();

-  EXPECT_FALSE(mid.IsEmpty());

-

-  // Ensure that the value is written in the registry.

-  EXPECT_SUCCEEDED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                    kRegValueMachineId,

-                                                    &id));

-  EXPECT_STREQ(mid, id);

-

-  // Call the method again.

-  mid = goopdate_utils::GetPersistentMachineId();

-

-  // Ensure that the same id is returned.

-  EXPECT_STREQ(mid, id);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, GetPersistentMachineId_User1) {

-  // Initially there is no machine id.

-  CString id;

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                 kRegValueMachineId,

-                                                 &id));

-  SID* sid_val = NULL;

-  ASSERT_TRUE(::ConvertStringSidToSid(_T("S-1-1-0"),

-                                      reinterpret_cast<PSID*>(&sid_val)));

-  ASSERT_TRUE(sid_val != NULL);

-

-  // Create the update key.

-  RegKey mid_key;

-  EXPECT_SUCCEEDED(mid_key.Create(HKEY_LOCAL_MACHINE, GOOPDATE_MAIN_KEY));

-  CDacl dacl;

-  ASSERT_TRUE(AtlGetDacl(mid_key.Key(), SE_REGISTRY_KEY, &dacl));

-  ASSERT_TRUE(dacl.AddDeniedAce(*sid_val, KEY_SET_VALUE));

-  EXPECT_SUCCEEDED(mid_key.Close());

-

-  // Now set the key permissions to not allow anyone to write.

-  EXPECT_SUCCEEDED(mid_key.Open(HKEY_LOCAL_MACHINE, GOOPDATE_MAIN_KEY));

-  ASSERT_TRUE(AtlSetDacl(mid_key.Key(), SE_REGISTRY_KEY, dacl, 0));

-

-  // Call the test method.

-  CString mid = goopdate_utils::GetPersistentMachineId();

-  ASSERT_TRUE(mid.IsEmpty());

-

-  // Ensure that the value Could not be written to the registry.

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                 kRegValueMachineId,

-                                                 &id));

-  ASSERT_TRUE(id.IsEmpty());

-

-  ASSERT_TRUE(dacl.RemoveAces(*sid_val));

-  ASSERT_TRUE(AtlSetDacl(mid_key.Key(), SE_REGISTRY_KEY, dacl, 0));

-  EXPECT_SUCCEEDED(mid_key.Close());

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, GetPersistentMachineId_User2) {

-  // Test simulates the situation where a machine goopdate is already running

-  // and a user goopdate is run next.

-

-  // Initially there is no machine id.

-  CString id;

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                 kRegValueMachineId,

-                                                 &id));

-

-  CString mid = goopdate_utils::GetPersistentMachineId();

-  EXPECT_FALSE(mid.IsEmpty());

-

-  // Ensure that the value Could not be written to the registry.

-  EXPECT_SUCCEEDED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                kRegValueMachineId,

-                                                &id));

-  EXPECT_STREQ(id, mid);

-

-  // Now set the permissions on the registry key such that we cannot write to

-  // it. We should however be able to read from it.

-  SID* sid_val = NULL;

-  ASSERT_TRUE(::ConvertStringSidToSid(_T("S-1-1-0"),

-                                      reinterpret_cast<PSID*>(&sid_val)));

-  ASSERT_TRUE(sid_val != NULL);

-

-  RegKey mid_key;

-  EXPECT_SUCCEEDED(mid_key.Open(HKEY_LOCAL_MACHINE, GOOPDATE_MAIN_KEY));

-  CDacl dacl;

-  ASSERT_TRUE(AtlGetDacl(mid_key.Key(), SE_REGISTRY_KEY, &dacl));

-  ASSERT_TRUE(dacl.AddDeniedAce(*sid_val, KEY_SET_VALUE));

-  ASSERT_TRUE(AtlSetDacl(mid_key.Key(), SE_REGISTRY_KEY, dacl, 0));

-

-  // Call the test method.

-  mid = goopdate_utils::GetPersistentMachineId();

-  EXPECT_FALSE(mid.IsEmpty());

-  EXPECT_STREQ(mid, id);

-

-  ASSERT_TRUE(dacl.RemoveAces(*sid_val));

-  ASSERT_TRUE(AtlSetDacl(mid_key.Key(), SE_REGISTRY_KEY, dacl, 0));

-  EXPECT_SUCCEEDED(mid_key.Close());

-}

-

-// New Unique ID is created and stored.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       GetPersistentUserId_OemInstalling_User) {

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-  ASSERT_TRUE(ConfigManager::Instance()->IsOemInstalling(true));

-

-  CString id;

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(USER_KEY_NAME,

-                                                 kRegValueUserId,

-                                                 &id));

-

-  CString uid = goopdate_utils::GetPersistentUserId(USER_KEY_NAME);

-  EXPECT_FALSE(uid.IsEmpty());

-

-  EXPECT_SUCCEEDED(goopdate_utils::ReadPersistentId(USER_KEY_NAME,

-                                                    kRegValueUserId,

-                                                    &id));

-  EXPECT_STREQ(uid, id);

-

-  uid = goopdate_utils::GetPersistentUserId(USER_KEY_NAME);

-  EXPECT_STREQ(uid, id);

-}

-

-// Special value is returned but not stored.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       GetPersistentUserId_OemInstalling_Machine) {

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-  ASSERT_TRUE(ConfigManager::Instance()->IsOemInstalling(true));

-

-  CString id;

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                 kRegValueUserId,

-                                                 &id));

-

-  CString uid = goopdate_utils::GetPersistentUserId(MACHINE_KEY_NAME);

-  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), uid);

-

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                 kRegValueUserId,

-                                                 &id));

-

-  uid = goopdate_utils::GetPersistentUserId(MACHINE_KEY_NAME);

-  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), uid);

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueUserId));

-

-  // Test the case where the value already exists.

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      MACHINE_REG_UPDATE,

-      kRegValueUserId,

-      _T("{12345678-1234-1234-1234-123456789abcd}")));

-  uid = goopdate_utils::GetPersistentUserId(MACHINE_KEY_NAME);

-  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), uid);

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueUserId));

-}

-

-// Special value is returned but not stored.

-// There is no difference between user and machine instances.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       GetPersistentMachineId_OemInstalling_Machine) {

-  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now_seconds));

-  ASSERT_TRUE(ConfigManager::Instance()->IsOemInstalling(true));

-

-  CString id;

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                 kRegValueMachineId,

-                                                 &id));

-

-  CString mid = goopdate_utils::GetPersistentMachineId();

-  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), mid);

-

-  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,

-                                                 kRegValueMachineId,

-                                                 &id));

-

-  mid = goopdate_utils::GetPersistentMachineId();

-  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), mid);

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueMachineId));

-

-  // Test the case where the value already exists.

-  EXPECT_SUCCEEDED(RegKey::SetValue(

-      MACHINE_REG_UPDATE,

-      kRegValueMachineId,

-      _T("{12345678-1234-1234-1234-123456789abcd}")));

-  mid = goopdate_utils::GetPersistentMachineId();

-  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), mid);

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueMachineId));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_NoKey) {

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_ClientStateExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_ClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_ClientStateNegativeOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(-1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_ClientStateZero_MediumNotExist) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_ClientStateZero_MediumExists) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStateMediumPath));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_ClientStateZero_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-    IsAppEulaAccepted_Machine_NotExplicit_ClientStateZero_MediumNegativeOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(-1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// Also tests that user values are not used.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_ClientStateZero_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// ClientStateMedium does not override ClientState.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_ClientStateOne_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// Implicitly accepted because of the absence of eualaccepted=0.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_ClientStateNotExist_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// Implicitly accepted because of the absence of eualaccepted=0.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_NotExplicit_ClientStateNotExist_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_NoKey) {

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateNegativeOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(-1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateZero_MediumNotExist) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateZero_MediumExists) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStateMediumPath));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateZero_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateZero_MediumNegativeOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(-1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// Also tests that user values are not used.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateZero_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// ClientStateMedium does not override ClientState.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateOne_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateNotExist_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_Machine_Explicit_ClientStateNotExist_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// ClientStateMedium is not supported for user apps.

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_NoKey) {

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateNegativeOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(-1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_EQ(-1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateZero_MediumNotExist) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateZero_MediumExists) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStateMediumPath));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateZero_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateZero_MediumNegativeOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(-1)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(-1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// Also tests that machine values are not used.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateZero_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// ClientStateMedium is not used.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateOne_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// Implicitly accepted because of the absence of eualaccepted=0.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateNotExist_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// Implicitly accepted because of the absence of eualaccepted=0.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_NotExplicit_ClientStateNotExist_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_Explicit_NoKey) {

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, true));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_Explicit_ClientStateExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, true));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_Explicit_ClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, true));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_Explicit_ClientStateNotExist_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, true));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       IsAppEulaAccepted_User_Explicit_ClientStateNotExist_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, true));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_Machine_NoKey) {

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_Machine_ClientStateExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_Machine_ClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_Machine_ClientStateZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_Machine_ClientStateZero_ClientStateMediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// Also tests that user values are not affected.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_Machine_ClientStateZero_ClientStateMediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_User_NoKey) {

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_User_ClientStateExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_User_ClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_User_ClientStateZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_User_ClientStateZero_ClientStateMediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-// Also tests that machine values are not affected.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppEulaNotAccepted_User_ClientStateZero_ClientStateMediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_Machine_NoKey) {

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_Machine_ClientStateExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_Machine_ClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_Machine_ClientStateZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_Machine_ClientStateZero_ClientStateMediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-}

-

-// Also tests that user values are not affected.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_Machine_ClientStateNone_ClientStateMediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));

-  EXPECT_EQ(0,

-            GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0,

-            GetDwordValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_User_NoKey) {

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_User_ClientStateExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_User_ClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_User_ClientStateZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_User_ClientStateZero_ClientStateMediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0,

-            GetDwordValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-}

-

-// Also tests that machine values are not affected.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       ClearAppEulaNotAccepted_User_ClientStateNone_ClientStateMediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0,

-            GetDwordValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));

-  EXPECT_EQ(0,

-            GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("eulaaccepted")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_NoKey) {

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_ClientStateExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_ClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_ClientStateNegativeOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(-1)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_ClientStateZero_MediumNotExist) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_ClientStateZero_MediumExists) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStateMediumPath));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));

-}

-

-// ClientStateMedium overrides ClientState.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_ClientStateZero_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-    AreAppUsageStatsEnabled_Machine_ClientStateZero_MediumNegativeOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(-1)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_ClientStateZero_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-// ClientStateMedium overrides ClientState.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_ClientStateOne_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_ClientStateNotExist_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_ClientStateNotExist_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-// User does not affect machine.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_Machine_UserOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-// ClientStateMedium is not supported for user apps.

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_NoKey) {

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateExists) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_TRUE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateNegativeOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(-1)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_EQ(-1, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateZero_MediumNotExist) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateZero_MediumExists) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStateMediumPath));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));

-}

-

-// ClientStateMedium is not used.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateZero_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateZero_MediumNegativeOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(-1)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_EQ(-1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateZero_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-// ClientStateMedium is not used.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateOne_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_TRUE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateNotExist_MediumOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_ClientStateNotExist_MediumZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-// Machine does not affect user.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       AreAppUsageStatsEnabled_User_MachineOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStatePath, _T("usagestats")));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));

-  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,

-                             _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetUsageStatsEnable_VerifyLegacyLocationNotSet) {

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_TRUE));

-

-  ASSERT_TRUE(RegKey::HasKey(MACHINE_REG_UPDATE));

-  ASSERT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE,

-                                kLegacyRegValueCollectUsageStats));

-  ASSERT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetUsageStatsEnable_Machine_Off) {

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_FALSE));

-

-  ASSERT_TRUE(RegKey::HasKey(kAppMachineClientStatePath));

-  ASSERT_TRUE(RegKey::HasValue(kAppMachineClientStatePath,

-                               _T("usagestats")));

-  ASSERT_FALSE(RegKey::HasKey(kAppUserClientStatePath));

-

-  DWORD enable_value = 1;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(0, enable_value);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetUsageStatsEnable_User_Off) {

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(false, kAppGuid, TRISTATE_FALSE));

-

-  ASSERT_TRUE(RegKey::HasKey(kAppUserClientStatePath));

-  ASSERT_TRUE(RegKey::HasValue(kAppUserClientStatePath,

-                               _T("usagestats")));

-  ASSERT_FALSE(RegKey::HasKey(kAppMachineClientStatePath));

-

-  DWORD enable_value = 1;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(0, enable_value);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetUsageStatsEnable_Machine_On) {

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_TRUE));

-

-  ASSERT_TRUE(RegKey::HasKey(kAppMachineClientStatePath));

-  ASSERT_TRUE(RegKey::HasValue(kAppMachineClientStatePath,

-                               _T("usagestats")));

-  ASSERT_FALSE(RegKey::HasKey(kAppUserClientStatePath));

-

-  DWORD enable_value = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(1, enable_value);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetUsageStatsEnable_User_On) {

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(false, kAppGuid, TRISTATE_TRUE));

-

-  ASSERT_TRUE(RegKey::HasKey(kAppUserClientStatePath));

-  ASSERT_TRUE(RegKey::HasValue(kAppUserClientStatePath,

-                               _T("usagestats")));

-  ASSERT_FALSE(RegKey::HasKey(kAppMachineClientStatePath));

-

-  DWORD enable_value = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(1, enable_value);

-}

-

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetUsageStatsEnable_Machine_None) {

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_NONE));

-  ASSERT_FALSE(RegKey::HasKey(MACHINE_REG_UPDATE));

-  ASSERT_FALSE(RegKey::HasKey(USER_REG_UPDATE));

-

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(false, kAppGuid, TRISTATE_NONE));

-  ASSERT_FALSE(RegKey::HasKey(USER_REG_UPDATE));

-  ASSERT_FALSE(RegKey::HasKey(MACHINE_REG_UPDATE));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetUsageStatsEnable_Machine_Overwrite) {

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_FALSE));

-

-  ASSERT_TRUE(RegKey::HasKey(kAppMachineClientStatePath));

-  ASSERT_TRUE(RegKey::HasValue(kAppMachineClientStatePath,

-                               _T("usagestats")));

-  ASSERT_FALSE(RegKey::HasKey(kAppUserClientStatePath));

-

-  DWORD enable_value = 1;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(0, enable_value);

-

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_TRUE));

-

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(1, enable_value);

-

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_FALSE));

-

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(0, enable_value);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetUsageStatsEnable_Machine_NoneDoesNotOverwrite) {

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_FALSE));

-

-  ASSERT_TRUE(RegKey::HasKey(kAppMachineClientStatePath));

-  ASSERT_TRUE(RegKey::HasValue(kAppMachineClientStatePath,

-                               _T("usagestats")));

-  ASSERT_FALSE(RegKey::HasKey(kAppUserClientStatePath));

-

-  DWORD enable_value = 1;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(0, enable_value);

-

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_NONE));

-

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(0, enable_value);

-

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_TRUE));

-

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(1, enable_value);

-

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_NONE));

-

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(1, enable_value);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetUsageStatsEnable_Machine_ClientStateMediumCleared) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_TRUE));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_FALSE));

-  EXPECT_FALSE(

-      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetUsageStatsEnable_Machine_NoneDoesNotClearClientStateMedium) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_NONE));

-

-  DWORD enable_value = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(1, enable_value);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetUsageStatsEnable_User_ClientStateMediumNotCleared) {

-  // User and machine values should not be cleared.

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(0)));

-

-  // True does not clear them.

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(false, kAppGuid, TRISTATE_TRUE));

-  DWORD enable_value = 1;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(0, enable_value);

-  enable_value = 1;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(0, enable_value);

-

-  // False does not clear them.

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetUsageStatsEnable(false, kAppGuid, TRISTATE_FALSE));

-  enable_value = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStateMediumPath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(1, enable_value);

-  enable_value = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(1, enable_value);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, ConvertLegacyUsageStats_NotPresent) {

-  EXPECT_SUCCEEDED(goopdate_utils::ConvertLegacyUsageStats(true));

-  ASSERT_FALSE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, ConvertLegacyUsageStats_Present) {

-  DWORD val = 1;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kLegacyRegValueCollectUsageStats,

-                                    val));

-

-  EXPECT_SUCCEEDED(goopdate_utils::ConvertLegacyUsageStats(true));

-

-  ASSERT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));

-  ASSERT_TRUE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                               _T("usagestats")));

-

-  DWORD enable_value = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("usagestats"),

-                                    &enable_value));

-  EXPECT_EQ(1, enable_value);

-

-  ASSERT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE,

-                               kLegacyRegValueCollectUsageStats));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, GetClientsStringValueFromRegistry) {

-  CString value;

-

-  // Test IsMachine = true

-  const TCHAR* dummy_machine_clients_key = MACHINE_REG_CLIENTS DUMMY_CLSID;

-

-  ASSERT_FALSE(RegKey::HasKey(dummy_machine_clients_key));

-  EXPECT_FAILED(goopdate_utils::GetClientsStringValueFromRegistry(

-                                    true, DUMMY_CLSID, _T("name"), &value));

-  ASSERT_SUCCEEDED(RegKey::DeleteKey(dummy_machine_clients_key));

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(dummy_machine_clients_key,

-                                    _T("name"),

-                                    _T("dummy")));

-  EXPECT_SUCCEEDED(goopdate_utils::GetClientsStringValueFromRegistry(

-                                      true, DUMMY_CLSID, _T("name"), &value));

-  EXPECT_EQ(_T("dummy"), value);

-

-  // Test IsMachine = false

-  const TCHAR* dummy_user_clients_key = USER_REG_CLIENTS DUMMY_CLSID;

-

-  ASSERT_FALSE(RegKey::HasKey(dummy_user_clients_key));

-  EXPECT_FAILED(goopdate_utils::GetClientsStringValueFromRegistry(

-                                   false, DUMMY_CLSID, _T("name"), &value));

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(dummy_user_clients_key,

-                                    _T("name"),

-                                    _T("dummy2")));

-  EXPECT_SUCCEEDED(goopdate_utils::GetClientsStringValueFromRegistry(

-                                      false, DUMMY_CLSID, _T("name"), &value));

-  EXPECT_EQ(_T("dummy2"), value);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, GetVerFromRegistry) {

-  CString version;

-

-  // Test IsMachine = true

-  const TCHAR* dummy_machine_clients_key = MACHINE_REG_CLIENTS DUMMY_CLSID;

-

-  ASSERT_FALSE(RegKey::HasKey(dummy_machine_clients_key));

-  EXPECT_FAILED(goopdate_utils::GetVerFromRegistry(true,

-                                                   DUMMY_CLSID,

-                                                   &version));

-  ASSERT_SUCCEEDED(RegKey::DeleteKey(dummy_machine_clients_key));

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(dummy_machine_clients_key,

-                                    _T("pv"),

-                                    _T("1.0.101.0")));

-  EXPECT_SUCCEEDED(goopdate_utils::GetVerFromRegistry(true,

-                                                      DUMMY_CLSID,

-                                                      &version));

-  EXPECT_EQ(_T("1.0.101.0"), version);

-

-  // Test IsMachine = false

-  const TCHAR* dummy_user_clients_key = USER_REG_CLIENTS DUMMY_CLSID;

-

-  ASSERT_FALSE(RegKey::HasKey(dummy_user_clients_key));

-  EXPECT_FAILED(goopdate_utils::GetVerFromRegistry(false,

-                                                   DUMMY_CLSID,

-                                                   &version));

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(dummy_user_clients_key,

-                                    _T("pv"),

-                                    _T("1.0.102.0")));

-  EXPECT_SUCCEEDED(goopdate_utils::GetVerFromRegistry(false,

-                                                      DUMMY_CLSID,

-                                                      &version));

-  EXPECT_EQ(_T("1.0.102.0"), version);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       BuildHttpGetString_MachineNoTestSource) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(

-                       MACHINE_REG_UPDATE,

-                       kRegValueMachineId,

-                       _T("{39980C99-CDD5-43A0-93C7-69D90C124729}")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(

-                       MACHINE_REG_UPDATE,

-                       kRegValueUserId,

-                       _T("{75521B9F-3EA4-49E8-BC61-E6BDCFEDF6F6}")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(

-                       MACHINE_REG_CLIENT_STATE APP_GUID,

-                       kRegValueInstallationId,

-                       _T("{0F973A20-C484-462b-952C-5D9A459E3326}")));

-

-  CString expected_str_before_os(

-      _T("http://www.google.com/hello.py?code=123&")

-      _T("hl=en&errorcode=0x0000000a&extracode1=0x00000016&extracode2=0&")

-      _T("app=%7BB7BAF788-9D64-49c3-AFDC-B336AB12F332%7D&")

-      _T("guver=1.0.51.0&ismachine=1&os="));

-  CString expected_str_after_os(

-      _T("&mid=%7B39980C99-CDD5-43A0-93C7-69D90C124729%7D")

-      _T("&uid=%7B75521B9F-3EA4-49E8-BC61-E6BDCFEDF6F6%7D")

-      _T("&iid=%7B0F973A20-C484-462b-952C-5D9A459E3326%7D&source=click"));

-  bool expected_test_source = false;

-

-#if defined(DEBUG) || !OFFICIAL_BUILD

-  // TestSource is always set for these builds. It may be set for opt official

-  // builds but this is not guaranteed.

-  expected_str_after_os.Append(_T("&testsource="));

-  expected_test_source = true;

-#endif

-

-  CString url_req;

-  EXPECT_SUCCEEDED(goopdate_utils::BuildHttpGetString(

-      _T("http://www.google.com/hello.py?code=123&"),

-      10,

-      22,

-      0,

-      APP_GUID,

-      _T("1.0.51.0"),

-      true,

-      _T("en"),

-      _T("click"),

-      &url_req));

-  EXPECT_LE(expected_str_before_os.GetLength(), url_req.GetLength());

-  EXPECT_EQ(0, url_req.Find(expected_str_before_os));

-

-  int os_fragment_len = 0;

-  EXPECT_EQ(expected_str_before_os.GetLength(),

-            VerifyOSInUrl(url_req, &os_fragment_len));

-

-  EXPECT_EQ(expected_str_before_os.GetLength() + os_fragment_len,

-            url_req.Find(expected_str_after_os));

-

-  if (expected_test_source) {

-    CString expected_testsource_str =

-        ConfigManager::Instance()->GetTestSource();

-    int expected_testsource_start = expected_str_before_os.GetLength() +

-                                    os_fragment_len +

-                                    expected_str_after_os.GetLength();

-    EXPECT_EQ(expected_testsource_start, url_req.Find(expected_testsource_str));

-    EXPECT_EQ(expected_testsource_start + expected_testsource_str.GetLength(),

-              url_req.GetLength());

-  } else {

-    EXPECT_EQ(expected_str_before_os.GetLength() +

-              os_fragment_len +

-              expected_str_after_os.GetLength(),

-              url_req.GetLength());

-

-    EXPECT_EQ(-1, url_req.Find(_T("testsource")));

-  }

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       BuildHttpGetString_UserWithTestSource) {

-  #define APP_GUID _T("{B7BAF788-9D64-49c3-AFDC-B336AB12F332}")

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(

-                       MACHINE_REG_UPDATE,

-                       kRegValueMachineId,

-                       _T("{39980C99-CDD5-43A0-93C7-69D90C124729}")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(

-                       USER_REG_UPDATE,

-                       kRegValueUserId,

-                       _T("{75521B9F-3EA4-49E8-BC61-E6BDCFEDF6F6}")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(

-                       USER_REG_CLIENT_STATE APP_GUID,

-                       kRegValueInstallationId,

-                       _T("{0F973A20-C484-462b-952C-5D9A459E3326}")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueTestSource,

-                                    _T("dev")));

-

-  const CString expected_str_before_os(

-      _T("http://www.google.com/hello.py?")

-      _T("hl=de&errorcode=0xffffffff&extracode1=0x00000000&extracode2=99&")

-      _T("app=%7BB7BAF788-9D64-49c3-AFDC-B336AB12F332%7D&")

-      _T("guver=foo%20bar&ismachine=0&os="));

-  const CString expected_str_after_os(

-      _T("&mid=%7B39980C99-CDD5-43A0-93C7-69D90C124729%7D")

-      _T("&uid=%7B75521B9F-3EA4-49E8-BC61-E6BDCFEDF6F6%7D")

-      _T("&iid=%7B0F973A20-C484-462b-952C-5D9A459E3326%7D&source=clack")

-      _T("&testsource="));

-

-  CString url_req;

-  EXPECT_SUCCEEDED(goopdate_utils::BuildHttpGetString(

-      _T("http://www.google.com/hello.py?"),

-      0xffffffff,

-      0,

-      99,

-      APP_GUID,

-      _T("foo bar"),

-      false,

-      _T("de"),

-      _T("clack"),

-      &url_req));

-  EXPECT_LE(expected_str_before_os.GetLength(), url_req.GetLength());

-  EXPECT_EQ(0, url_req.Find(expected_str_before_os));

-

-  int os_fragment_len = 0;

-  EXPECT_EQ(expected_str_before_os.GetLength(),

-            VerifyOSInUrl(url_req, &os_fragment_len));

-

-  EXPECT_EQ(expected_str_before_os.GetLength() + os_fragment_len,

-            url_req.Find(expected_str_after_os));

-

-  const CString expected_testsource_str = _T("dev");

-

-  int expected_testsource_start = expected_str_before_os.GetLength() +

-                                  os_fragment_len +

-                                  expected_str_after_os.GetLength();

-  EXPECT_EQ(expected_testsource_start, url_req.Find(expected_testsource_str));

-  EXPECT_EQ(expected_testsource_start + expected_testsource_str.GetLength(),

-            url_req.GetLength());

-}

-

-// MID and UID automatically get generated when they are read, so it is not

-// possible for them to be empty. IID is emtpy if not present.

-TEST_F(GoopdateUtilsRegistryProtectedTest, BuildHttpGetString_NoMidUidIid) {

-  CString url_req;

-  EXPECT_SUCCEEDED(goopdate_utils::BuildHttpGetString(

-      _T("http://www.google.com/hello.py?"),

-      0xffffffff,

-      0,

-      99,

-      _T("{B7BAF788-9D64-49c3-AFDC-B336AB12F332}"),

-      _T("foo bar"),

-      true,

-      _T("en"),

-      _T("cluck"),

-      &url_req));

-

-  // Check for the GUID brackets and end of string as appropriate.

-  EXPECT_NE(-1, url_req.Find(_T("&mid=%7B")));

-  EXPECT_NE(-1, url_req.Find(_T("%7D&uid=%7B")));

-

-  CString expected_test_src;

-#if defined(DEBUG) || !OFFICIAL_BUILD

-  expected_test_src = _T("&testsource=auto");

-#endif

-  const CString expected_iid_str(_T("%7D&iid=&source=cluck"));

-  EXPECT_EQ(url_req.GetLength() -

-            expected_iid_str.GetLength() -

-            expected_test_src.GetLength(),

-            url_req.Find(expected_iid_str));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, GetNumClients) {

-  size_t num_clients(0);

-

-  // Fails when no "Clients" key.

-  EXPECT_HRESULT_FAILED(GetNumClients(true, &num_clients));

-  EXPECT_HRESULT_FAILED(GetNumClients(false, &num_clients));

-

-  // Tests no subkeys.

-  const TCHAR* keys_to_create[] = { MACHINE_REG_CLIENTS, USER_REG_CLIENTS };

-  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKeys(keys_to_create,

-                                              arraysize(keys_to_create)));

-  EXPECT_HRESULT_SUCCEEDED(GetNumClients(true, &num_clients));

-  EXPECT_EQ(0, num_clients);

-  EXPECT_HRESULT_SUCCEEDED(GetNumClients(false, &num_clients));

-  EXPECT_EQ(0, num_clients);

-

-  // Subkeys should be counted. Values should not be counted.

-  RegKey machine_key;

-  EXPECT_HRESULT_SUCCEEDED(machine_key.Open(HKEY_LOCAL_MACHINE,

-                                            GOOPDATE_REG_RELATIVE_CLIENTS));

-  EXPECT_HRESULT_SUCCEEDED(machine_key.SetValue(_T("name"), _T("value")));

-  EXPECT_HRESULT_SUCCEEDED(GetNumClients(true, &num_clients));

-  EXPECT_EQ(0, num_clients);

-

-  const TCHAR* app_id = _T("{AA5523E3-40C0-4b85-B074-4BBA09559CCD}");

-  EXPECT_HRESULT_SUCCEEDED(machine_key.Create(machine_key.Key(), app_id));

-  EXPECT_HRESULT_SUCCEEDED(GetNumClients(true, &num_clients));

-  EXPECT_EQ(1, num_clients);

-

-  // Tests user scenario.

-  RegKey user_key;

-  EXPECT_HRESULT_SUCCEEDED(user_key.Open(HKEY_CURRENT_USER,

-                                         GOOPDATE_REG_RELATIVE_CLIENTS));

-  EXPECT_HRESULT_SUCCEEDED(user_key.SetValue(_T("name"), _T("value")));

-  EXPECT_HRESULT_SUCCEEDED(GetNumClients(false, &num_clients));

-  EXPECT_EQ(0, num_clients);

-

-  EXPECT_HRESULT_SUCCEEDED(user_key.Create(user_key.Key(), app_id));

-  EXPECT_HRESULT_SUCCEEDED(GetNumClients(false, &num_clients));

-  EXPECT_EQ(1, num_clients);

-}

-

-TEST(GoopdateUtilsTest, BuildInstallDirectory_Machine) {

-  const CPath dir = goopdate_utils::BuildInstallDirectory(true, _T("1.2.3.0"));

-  CString program_files_path;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files_path));

-  EXPECT_STREQ(program_files_path + _T("\\Google\\Update\\1.2.3.0"), dir);

-}

-

-TEST(GoopdateUtilsTest, BuildInstallDirectory_User) {

-  CPath expected_path(GetGoogleUpdateUserPath());

-  expected_path.Append(_T("4.5.6.7"));

-  EXPECT_STREQ(expected_path,

-               goopdate_utils::BuildInstallDirectory(false, _T("4.5.6.7")));

-}

-

-TEST(GoopdateUtilsTest, ConvertBrowserTypeToString) {

-  for (int i = 0; i < BROWSER_MAX; ++i) {

-    CString str_type = goopdate_utils::ConvertBrowserTypeToString(

-        static_cast<BrowserType>(i));

-    BrowserType type = BROWSER_UNKNOWN;

-    ASSERT_HRESULT_SUCCEEDED(

-        goopdate_utils::ConvertStringToBrowserType(str_type, &type));

-    ASSERT_EQ(static_cast<int>(type), i);

-  }

-}

-

-void CompareArgsAndUpdateResponseData(const UpdateResponseData& response_data,

-                                      const CString& app_name,

-                                      const CommandLineExtraArgs& args) {

-  ASSERT_STREQ(GuidToString(response_data.guid()),

-               GuidToString(args.apps[0].app_guid));

-  ASSERT_STREQ(app_name, args.apps[0].app_name);

-  ASSERT_EQ(response_data.needs_admin() == NEEDS_ADMIN_YES ? true : false,

-            args.apps[0].needs_admin);

-  ASSERT_STREQ(response_data.ap(), args.apps[0].ap);

-  ASSERT_STREQ(response_data.tt_token(), args.apps[0].tt_token);

-

-  ASSERT_EQ(GuidToString(response_data.installation_id()),

-            GuidToString(args.installation_id));

-  ASSERT_TRUE(args.brand_code.IsEmpty());

-  ASSERT_TRUE(args.client_id.IsEmpty());

-  ASSERT_TRUE(args.referral_id.IsEmpty());

-  ASSERT_EQ(response_data.browser_type(), args.browser_type);

-  ASSERT_EQ(TRISTATE_NONE, args.usage_stats_enable);

-}

-

-TEST(GoopdateUtilsTest, ConvertResponseDataToExtraArgsRequired) {

-  // These unit tests create an update response and then call the test method,

-  // to create the command line. Next the command line is parsed using the

-  // command line class and the results are validated.

-  UpdateResponseData input;

-  input.set_guid(StringToGuid(_T("{8B59B82E-5543-4807-8590-84BF484AE2F6}")));

-

-  CString unicode_name;

-  ASSERT_TRUE(unicode_name.LoadString(IDS_ESCAPE_TEST));

-  CString encoded_name;

-  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_name,

-                                                            &encoded_name));

-  input.set_app_name(encoded_name);

-  input.set_needs_admin(NEEDS_ADMIN_YES);

-

-  CString extra_args;

-  ASSERT_HRESULT_SUCCEEDED(

-      goopdate_utils::ConvertResponseDataToExtraArgs(input, &extra_args));

-

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  ASSERT_HRESULT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CompareArgsAndUpdateResponseData(input, unicode_name, args);

-}

-

-

-TEST(GoopdateUtilsTest, ConvertResponseDataToExtraArgsAll) {

-  UpdateResponseData input;

-  input.set_guid(StringToGuid(_T("{8B59B82E-5543-4807-8590-84BF484AE2F6}")));

-

-  CString unicode_name;

-  ASSERT_TRUE(unicode_name.LoadString(IDS_ESCAPE_TEST));

-  CString encoded_name;

-  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_name,

-                                                            &encoded_name));

-  input.set_app_name(encoded_name);

-  input.set_needs_admin(NEEDS_ADMIN_YES);

-  input.set_installation_id(

-      StringToGuid(_T("{E314A405-FCC5-4ed1-BFA4-CBC22F1873BF}")));

-  input.set_ap(_T("Test_ap"));

-  input.set_tt_token(_T("Test_tt_token"));

-  input.set_browser_type(BROWSER_IE);

-

-  CString extra_args;

-  ASSERT_HRESULT_SUCCEEDED(

-      goopdate_utils::ConvertResponseDataToExtraArgs(input, &extra_args));

-

-  CommandLineExtraArgs args;

-  ExtraArgsParser parser;

-  ASSERT_HRESULT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));

-

-  CompareArgsAndUpdateResponseData(input, unicode_name, args);

-}

-

-TEST(GoopdateUtilsTest, UniqueEventInEnvironment_User) {

-  const TCHAR* kEnvVarName = _T("SOME_ENV_VAR_FOR_TEST");

-  scoped_event created_event;

-  scoped_event opened_event;

-

-  ASSERT_HRESULT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(

-      kEnvVarName,

-      false,

-      address(created_event)));

-  ASSERT_TRUE(created_event);

-  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(created_event), 0));

-

-  TCHAR event_name[MAX_PATH] = {0};

-  EXPECT_TRUE(

-      ::GetEnvironmentVariable(kEnvVarName, event_name, arraysize(event_name)));

-

-  ASSERT_HRESULT_SUCCEEDED(goopdate_utils::OpenUniqueEventFromEnvironment(

-      kEnvVarName,

-      false,

-      address(opened_event)));

-  ASSERT_TRUE(opened_event);

-

-  EXPECT_TRUE(::SetEvent(get(opened_event)));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(created_event), 0));

-

-  EXPECT_TRUE(::SetEnvironmentVariable(kEnvVarName, NULL));

-}

-

-TEST(GoopdateUtilsTest, UniqueEventInEnvironment_Machine) {

-  const TCHAR* kEnvVarName = _T("OTHER_ENV_VAR_FOR_TEST");

-  scoped_event created_event;

-  scoped_event opened_event;

-  TCHAR event_name[MAX_PATH] = {0};

-

-  if (!vista_util::IsUserAdmin()) {

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INVALID_OWNER),

-              goopdate_utils::CreateUniqueEventInEnvironment(

-                  kEnvVarName,

-                  true,

-                  address(created_event)));

-    EXPECT_FALSE(created_event);

-

-    EXPECT_FALSE(::GetEnvironmentVariable(kEnvVarName,

-                                          event_name,

-                                          arraysize(event_name)));

-    return;

-  }

-

-  ASSERT_HRESULT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(

-      kEnvVarName,

-      true,

-      address(created_event)));

-  ASSERT_TRUE(created_event);

-  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(created_event), 0));

-

-  EXPECT_TRUE(

-      ::GetEnvironmentVariable(kEnvVarName, event_name, arraysize(event_name)));

-

-  ASSERT_HRESULT_SUCCEEDED(goopdate_utils::OpenUniqueEventFromEnvironment(

-      kEnvVarName,

-      true,

-      address(opened_event)));

-  ASSERT_TRUE(opened_event);

-

-  EXPECT_TRUE(::SetEvent(get(opened_event)));

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(created_event), 0));

-

-  EXPECT_TRUE(::SetEnvironmentVariable(kEnvVarName, NULL));

-}

-

-TEST(GoopdateUtilsTest, UniqueEventInEnvironment_UserMachineMismatch) {

-  const TCHAR* kEnvVarName = _T("ENV_VAR_FOR_MIXED_TEST");

-  scoped_event created_event;

-  scoped_event opened_event;

-

-  ASSERT_HRESULT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(

-      kEnvVarName,

-      false,

-      address(created_event)));

-  ASSERT_TRUE(created_event);

-  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(created_event), 0));

-

-  TCHAR event_name[MAX_PATH] = {0};

-  EXPECT_TRUE(

-      ::GetEnvironmentVariable(kEnvVarName, event_name, arraysize(event_name)));

-

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            goopdate_utils::OpenUniqueEventFromEnvironment(

-                kEnvVarName,

-                true,

-                address(opened_event)));

-

-  EXPECT_TRUE(::SetEnvironmentVariable(kEnvVarName, NULL));

-}

-

-TEST(GoopdateUtilsTest, OpenUniqueEventFromEnvironment_EnvVarDoesNotExist) {

-  const TCHAR* kEnvVarName = _T("ANOTHER_ENV_VAR_FOR_TEST");

-  scoped_event opened_event;

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND),

-            goopdate_utils::OpenUniqueEventFromEnvironment(

-                kEnvVarName,

-                false,

-                address(opened_event)));

-}

-

-TEST(GoopdateUtilsTest, OpenUniqueEventFromEnvironment_EventDoesNotExist) {

-  const TCHAR* kEnvVarName = _T("YET_ANOTHER_ENV_VAR_FOR_TEST");

-

-  EXPECT_TRUE(::SetEnvironmentVariable(kEnvVarName, _T("foo")));

-

-  scoped_event opened_event;

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-              goopdate_utils::OpenUniqueEventFromEnvironment(

-                  kEnvVarName,

-                  false,

-                  address(opened_event)));

-

-  EXPECT_TRUE(::SetEnvironmentVariable(kEnvVarName, NULL));

-}

-

-

-CString GetTempFile() {

-  TCHAR temp_path[MAX_PATH] = {0};

-  TCHAR temp_file[MAX_PATH] = {0};

-

-  EXPECT_LT(::GetTempPath(arraysize(temp_path), temp_path),

-            arraysize(temp_path));

-  EXPECT_NE(0, ::GetTempFileName(temp_path, _T("ut_"), 0, temp_file));

-  return CString(temp_file);

-}

-

-typedef std::map<CString, CString> StringMap;

-typedef StringMap::const_iterator StringMapIter;

-

-TEST(GoopdateUtilsTest, ReadNameValuePairsFromFileTest_MissingFile) {

-  CString temp_file = GetTempFile();

-  ::DeleteFile(temp_file);

-

-  ASSERT_FALSE(File::Exists(temp_file));

-

-  StringMap pairs_read;

-  ASSERT_FAILED(goopdate_utils::ReadNameValuePairsFromFile(temp_file,

-                                                           _T("my_group"),

-                                                           &pairs_read));

-  ASSERT_EQ(0, pairs_read.size());

-}

-

-TEST(GoopdateUtilsTest, ReadNameValuePairsFromFileTest_ReadEmpty) {

-  CString temp_file = GetTempFile();

-  File file_write;

-  EXPECT_SUCCEEDED(file_write.Open(temp_file, true, false));

-  file_write.Close();

-

-  StringMap pairs_read;

-  ASSERT_SUCCEEDED(goopdate_utils::ReadNameValuePairsFromFile(temp_file,

-                                                              _T("my_group"),

-                                                              &pairs_read));

-  ASSERT_EQ(0, pairs_read.size());

-}

-

-void ValidateStringMapEquality(const StringMap& expected,

-                               const StringMap& actual) {

-  ASSERT_EQ(expected.size(), actual.size());

-

-  StringMapIter it_expected = expected.begin();

-  for (; it_expected != expected.end(); ++it_expected) {

-    StringMapIter it_actual = actual.find(it_expected->first);

-    ASSERT_TRUE(it_actual != actual.end());

-    ASSERT_STREQ(it_expected->second, it_actual->second);

-  }

-}

-

-TEST(GoopdateUtilsTest, ReadNameValuePairsFromFileTest_ReadOnePair) {

-  CString group = _T("my_group");

-

-  StringMap pairs_write;

-  pairs_write[_T("some_name")] = _T("some_value");

-

-  CString temp_file = GetTempFile();

-  ASSERT_SUCCEEDED(goopdate_utils::WriteNameValuePairsToFile(temp_file,

-                                                             group,

-                                                             pairs_write));

-  ASSERT_TRUE(File::Exists(temp_file));

-

-  StringMap pairs_read;

-  ASSERT_SUCCEEDED(goopdate_utils::ReadNameValuePairsFromFile(temp_file,

-                                                              group,

-                                                              &pairs_read));

-

-  ValidateStringMapEquality(pairs_write, pairs_read);

-}

-

-TEST(GoopdateUtilsTest, ReadNameValuePairsFromFileTest_ReadManyPairs) {

-  CString group = _T("my_group");

-

-  StringMap pairs_write;

-  const int kCountPairs = 10;

-  for (int i = 1; i <= kCountPairs; ++i) {

-    CString name;

-    name.Format(_T("name%d"), i);

-    CString value;

-    value.Format(_T("value%d"), i);

-    pairs_write[name] = value;

-  }

-

-  CString temp_file = GetTempFile();

-  ASSERT_SUCCEEDED(goopdate_utils::WriteNameValuePairsToFile(temp_file,

-                                                             group,

-                                                             pairs_write));

-  ASSERT_TRUE(File::Exists(temp_file));

-

-  StringMap pairs_read;

-  ASSERT_SUCCEEDED(goopdate_utils::ReadNameValuePairsFromFile(temp_file,

-                                                              group,

-                                                              &pairs_read));

-

-  ValidateStringMapEquality(pairs_write, pairs_read);

-}

-

-// This test verifies that InstallTime is created afresh for Omaha if it does

-// not exist, and even if the brand code is already set.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetGoogleUpdateBranding_BrandAlreadyExistsAllEmpty) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("EFGH")));

-

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetGoogleUpdateBranding(kAppMachineClientStatePath,

-                                              _T(""),

-                                              _T("")));

-

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("EFGH"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueClientId,

-                             &value));

-  DWORD install_time = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-}

-

-// This test verifies that InstallTime remains unchanged for Omaha if it already

-// exists and the brand code is already set.

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetGoogleUpdateBranding_AllAlreadyExistAllEmpty) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("EFGH")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    _T("existing_partner")));

-  const DWORD kInstallTime = 1234567890;

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    kInstallTime));

-

-  EXPECT_SUCCEEDED(

-      goopdate_utils::SetGoogleUpdateBranding(kAppMachineClientStatePath,

-                                              _T(""),

-                                              _T("")));

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("EFGH"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("existing_partner"), value);

-  EXPECT_EQ(kInstallTime,

-            GetDwordValue(kAppMachineClientStatePath, kRegValueInstallTimeSec));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_KeyDoesNotExist) {

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                           _T("ABCD"),

-                                           _T("some_partner"),

-                                           _T("referrer")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_AllEmpty) {

-  ASSERT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T(""),

-                                                  _T(""),

-                                                  _T("")));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("GGLS"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueClientId,

-                             &value));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD install_time = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_BrandCodeOnly) {

-  ASSERT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T("ABCD"),

-                                                  _T(""),

-                                                  _T("")));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("ABCD"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueClientId,

-                             &value));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD install_time = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_BrandCodeTooLong) {

-  EXPECT_EQ(E_INVALIDARG, goopdate_utils::SetAppBranding(

-                                              kAppMachineClientStatePath,

-                                              _T("CHMGon.href)}"),

-                                              _T(""),

-                                              _T("")));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_ClientIdOnly) {

-  ASSERT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T(""),

-                                                  _T("some_partner"),

-                                                  _T("")));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("GGLS"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("some_partner"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD install_time = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_AllValid) {

-  ASSERT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T("ABCD"),

-                                                  _T("some_partner"),

-                                                  _T("referrer")));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("ABCD"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("some_partner"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueReferralId,

-                                    &value));

-  EXPECT_STREQ(_T("referrer"), value);

-  DWORD install_time(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_BrandAlreadyExistsAllEmpty) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("EFGH")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T(""),

-                                                  _T(""),

-                                                  _T("")));

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("EFGH"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueClientId,

-                             &value));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD dword_value(0);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueInstallTimeSec,

-                             &dword_value));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_BrandAlreadyExistsBrandCodeOnly) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("EFGH")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T("ABCD"),

-                                                  _T(""),

-                                                  _T("")));

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("EFGH"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueClientId,

-                             &value));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD dword_value(0);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueInstallTimeSec,

-                             &dword_value));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_ExistingBrandTooLong) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("CHMG4CUTNt")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T("ABCD"),

-                                                  _T(""),

-                                                  _T("")));

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("CHMG"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueClientId,

-                             &value));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD dword_value(0);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueInstallTimeSec,

-                             &dword_value));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_BrandAlreadyExistsCliendIdOnly) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("EFGH")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T(""),

-                                                  _T("some_partner"),

-                                                  _T("")));

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("EFGH"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueClientId,

-                             &value));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD dword_value(0);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueInstallTimeSec,

-                             &dword_value));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_BrandAlreadyExistsBothValid) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("EFGH")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T("ABCD"),

-                                                  _T("some_partner"),

-                                                  _T("")));

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("EFGH"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueClientId,

-                             &value));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD dword_value(0);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueInstallTimeSec,

-                             &dword_value));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_ClientIdAlreadyExistsAllEmtpy) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    _T("existing_partner")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T(""),

-                                                  _T(""),

-                                                  _T("")));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("GGLS"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("existing_partner"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD install_time = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_ClientIdAlreadyExistsBrandCodeOnly) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    _T("existing_partner")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T("ABCE"),

-                                                  _T(""),

-                                                  _T("")));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("ABCE"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("existing_partner"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD install_time = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_ClientIdAlreadyExistsCliendIdOnly) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    _T("existing_partner")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T(""),

-                                                  _T("some_partner"),

-                                                  _T("")));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("GGLS"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("some_partner"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD install_time = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_ClientIdAlreadyExistsBothValid) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    _T("existing_partner")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T("ABCD"),

-                                                  _T("some_partner"),

-                                                  _T("")));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("ABCD"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("some_partner"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD install_time = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_AllAlreadyExistAllEmpty) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("EFGH")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    _T("existing_partner")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueReferralId,

-                                    __T("existingreferrerid")));

-  const DWORD kInstallTime = 1234567890;

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    kInstallTime));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T(""),

-                                                  _T(""),

-                                                  _T("")));

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("EFGH"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("existing_partner"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueReferralId,

-                                    &value));

-  EXPECT_STREQ(__T("existingreferrerid"), value);

-  EXPECT_EQ(kInstallTime,

-            GetDwordValue(kAppMachineClientStatePath, kRegValueInstallTimeSec));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_AllAlreadyExistBrandCodeOnly) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("EFGH")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    _T("existing_partner")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueReferralId,

-                                    __T("existingreferrerid")));

-  const DWORD kInstallTime = 1234567890;

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    kInstallTime));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T("ABCD"),

-                                                  _T(""),

-                                                  _T("")));

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("EFGH"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("existing_partner"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueReferralId,

-                                    &value));

-  EXPECT_STREQ(__T("existingreferrerid"), value);

-  EXPECT_EQ(kInstallTime,

-            GetDwordValue(kAppMachineClientStatePath, kRegValueInstallTimeSec));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_BothAlreadyExistCliendIdOnly) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("EFGH")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    _T("existing_partner")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueReferralId,

-                                    __T("existingreferrerid")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T(""),

-                                                  _T("some_partner"),

-                                                  _T("")));

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("EFGH"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("existing_partner"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueReferralId,

-                                    &value));

-  EXPECT_STREQ(__T("existingreferrerid"), value);

-  DWORD dword_value(0);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueInstallTimeSec,

-                             &dword_value));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_BothAlreadyExistBothValid) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    _T("EFGH")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    _T("existing_partner")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueReferralId,

-                                    _T("existingreferrerid")));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T("ABCD"),

-                                                  _T("some_partner"),

-                                                  _T("")));

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("EFGH"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueClientId,

-                                    &value));

-  EXPECT_STREQ(_T("existing_partner"), value);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueReferralId,

-                                    &value));

-  EXPECT_STREQ(_T("existingreferrerid"), value);

-  DWORD dword_value(0);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueInstallTimeSec,

-                             &dword_value));

-}

-

-TEST_F(GoopdateUtilsRegistryProtectedTest,

-       SetAppBranding_InstallTimeAlreadyExistsBrandCodeOnly) {

-  const DWORD kExistingInstallTime = 1234567890;

-  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    kExistingInstallTime));

-

-  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,

-                                                  _T("ABCE"),

-                                                  _T(""),

-                                                  _T("")));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueBrandCode,

-                                    &value));

-  EXPECT_STREQ(_T("ABCE"), value);

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueClientId,

-                             &value));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            RegKey::GetValue(kAppMachineClientStatePath,

-                             kRegValueReferralId,

-                             &value));

-  DWORD install_time = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                                    kRegValueInstallTimeSec,

-                                    &install_time));

-  EXPECT_NE(kExistingInstallTime, install_time);

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-}

-

-//

-// IsMachineProcess tests.

-//

-

-class GoopdateUtilsIsMachineProcessTest : public testing::Test {

- protected:

-  bool FromMachineDirHelper(CommandLineMode mode) {

-    return goopdate_utils::IsMachineProcess(mode,

-                                            true,

-                                            false,

-                                            false,

-                                            TRISTATE_NONE);

-  }

-

-  bool IsLocalSystemHelper(CommandLineMode mode) {

-    return goopdate_utils::IsMachineProcess(mode,

-                                            false,

-                                            true,

-                                            false,

-                                            TRISTATE_NONE);

-  }

-

-  bool MachineOverrideHelper(CommandLineMode mode) {

-    return goopdate_utils::IsMachineProcess(mode,

-                                            false,

-                                            false,

-                                            true,

-                                            TRISTATE_NONE);

-  }

-

-  bool NeedsAdminFalseHelper(CommandLineMode mode) {

-    return goopdate_utils::IsMachineProcess(mode,

-                                            false,

-                                            false,

-                                            false,

-                                            TRISTATE_FALSE);

-  }

-

-  bool NeedsAdminTrueHelper(CommandLineMode mode) {

-    return goopdate_utils::IsMachineProcess(mode,

-                                            false,

-                                            false,

-                                            false,

-                                            TRISTATE_TRUE);

-  }

-};

-

-TEST_F(GoopdateUtilsIsMachineProcessTest,

-       IsMachineProcess_MachineDirOnly) {

-  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_UNKNOWN));

-  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_NOARGS));

-  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_CORE));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_SERVICE));

-  }

-  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_REGSERVER));

-  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_UNREGSERVER));

-  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_NETDIAGS));

-  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_CRASH));

-  // TODO(omaha): Change to machine.

-  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_REPORTCRASH));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_INSTALL));

-  }

-  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_UPDATE));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_IG));

-    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_HANDOFF_INSTALL));

-  }

-  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_UG));

-  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_UA));

-  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_RECOVER));

-  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_WEBPLUGIN));

-  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_CODE_RED_CHECK));

-  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_COMSERVER));

-  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_LEGACYUI));

-  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_REGISTER_PRODUCT));

-  }

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_UNREGISTER_PRODUCT));

-  }

-  EXPECT_TRUE(FromMachineDirHelper(

-      static_cast<CommandLineMode>(

-          COMMANDLINE_MODE_CRASH_HANDLER + 1)));

-}

-

-TEST_F(GoopdateUtilsIsMachineProcessTest,

-       IsMachineProcess_IsLocalSystemOnly) {

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_UNKNOWN));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_NOARGS));

-  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_CORE));

-  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_SERVICE));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_REGSERVER));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_UNREGSERVER));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_NETDIAGS));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_CRASH));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_REPORTCRASH));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_INSTALL));

-  }

-  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_UPDATE));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_IG));

-    EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_HANDOFF_INSTALL));

-  }

-  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_UG));

-  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_UA));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_RECOVER));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_WEBPLUGIN));

-  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_CODE_RED_CHECK));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_COMSERVER));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_LEGACYUI));

-  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_REGISTER_PRODUCT));

-  }

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_UNREGISTER_PRODUCT));

-  }

-  EXPECT_FALSE(IsLocalSystemHelper(

-      static_cast<CommandLineMode>(

-          COMMANDLINE_MODE_CRASH_HANDLER + 1)));

-}

-

-TEST_F(GoopdateUtilsIsMachineProcessTest,

-       IsMachineProcess_MachineOverrideOnly) {

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_UNKNOWN));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_NOARGS));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_CORE));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_SERVICE));

-  }

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_REGSERVER));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_UNREGSERVER));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_NETDIAGS));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_CRASH));

-  EXPECT_TRUE(MachineOverrideHelper(COMMANDLINE_MODE_REPORTCRASH));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_INSTALL));

-  }

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_UPDATE));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_IG));

-    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_HANDOFF_INSTALL));

-  }

-  EXPECT_TRUE(MachineOverrideHelper(COMMANDLINE_MODE_UG));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_UA));

-  EXPECT_TRUE(MachineOverrideHelper(COMMANDLINE_MODE_RECOVER));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_WEBPLUGIN));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_CODE_RED_CHECK));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_COMSERVER));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_LEGACYUI));

-  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_REGISTER_PRODUCT));

-  }

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_UNREGISTER_PRODUCT));

-  }

-  EXPECT_FALSE(MachineOverrideHelper(

-      static_cast<CommandLineMode>(

-          COMMANDLINE_MODE_CRASH_HANDLER + 1)));

-}

-

-TEST_F(GoopdateUtilsIsMachineProcessTest,

-       IsMachineProcess_NeedsAdminFalseOnly) {

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UNKNOWN));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_NOARGS));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_CORE));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_SERVICE));

-  }

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_REGSERVER));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UNREGSERVER));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_NETDIAGS));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_CRASH));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_REPORTCRASH));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_INSTALL));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UPDATE));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_IG));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_HANDOFF_INSTALL));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UG));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UA));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_RECOVER));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_WEBPLUGIN));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_CODE_RED_CHECK));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_COMSERVER));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_LEGACYUI));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_REGISTER_PRODUCT));

-  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UNREGISTER_PRODUCT));

-  EXPECT_FALSE(NeedsAdminFalseHelper(

-      static_cast<CommandLineMode>(

-          COMMANDLINE_MODE_CRASH_HANDLER + 1)));

-}

-

-TEST_F(GoopdateUtilsIsMachineProcessTest,

-       IsMachineProcess_NeedsAdminTrueOnly) {

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UNKNOWN));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_NOARGS));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_CORE));

-  {

-    ExpectAsserts expect_asserts;

-    EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_SERVICE));

-  }

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_REGSERVER));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UNREGSERVER));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_NETDIAGS));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_CRASH));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_REPORTCRASH));

-  EXPECT_TRUE(NeedsAdminTrueHelper(COMMANDLINE_MODE_INSTALL));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UPDATE));

-  EXPECT_TRUE(NeedsAdminTrueHelper(COMMANDLINE_MODE_IG));

-  EXPECT_TRUE(NeedsAdminTrueHelper(COMMANDLINE_MODE_HANDOFF_INSTALL));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UG));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UA));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_RECOVER));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_WEBPLUGIN));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_CODE_RED_CHECK));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_COMSERVER));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_LEGACYUI));

-  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF));

-  EXPECT_TRUE(NeedsAdminTrueHelper(COMMANDLINE_MODE_REGISTER_PRODUCT));

-  EXPECT_TRUE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UNREGISTER_PRODUCT));

-  EXPECT_FALSE(NeedsAdminTrueHelper(

-      static_cast<CommandLineMode>(

-          COMMANDLINE_MODE_CRASH_HANDLER + 1)));

-}

-

-TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_LegacyVersions) {

-  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.0.0.0")));

-  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.103.9")));

-  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.65535.65535")));

-}

-

-TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_Omaha2AndLater) {

-  EXPECT_TRUE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.2.0.0")));

-  EXPECT_TRUE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.2.0111.2222")));

-  EXPECT_TRUE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.3.456.7890")));

-  EXPECT_TRUE(goopdate_utils::IsGoogleUpdate2OrLater(_T("2.0.0.0")));

-}

-

-TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_VersionZero) {

-  ExpectAsserts expect_asserts;

-  EXPECT_FALSE(

-      goopdate_utils::IsGoogleUpdate2OrLater(_T("0.0.0.0")));

-}

-

-TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_VersionUpperLimits) {

-  EXPECT_TRUE(

-      goopdate_utils::IsGoogleUpdate2OrLater(_T("65535.65535.65535.65535")));

-

-  ExpectAsserts expect_asserts;

-  EXPECT_FALSE(

-      goopdate_utils::IsGoogleUpdate2OrLater(_T("65536.65536.65536.65536")));

-  EXPECT_FALSE(

-      goopdate_utils::IsGoogleUpdate2OrLater(_T("1.2.65536.65536")));

-  EXPECT_FALSE(

-      goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.65536.65536")));

-}

-

-TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_TooFewElements) {

-  ExpectAsserts expect_asserts;

-  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.1")));

-}

-

-TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_ExtraPeriod) {

-  ExpectAsserts expect_asserts;

-  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.2.3.")));

-}

-

-TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_TooManyElements) {

-  ExpectAsserts expect_asserts;

-  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.2.3.4")));

-}

-

-TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_Char) {

-  ExpectAsserts expect_asserts;

-  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.B.3.4")));

-  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.2.3.B")));

-  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.2.3.9B")));

-}

-

-TEST(GoopdateUtilsTest, FormatMessageForNetworkError) {

-  const TCHAR* const kTestAppName = _T("Test App");

-  CString message;

-  EXPECT_EQ(true, FormatMessageForNetworkError(GOOPDATE_E_NO_NETWORK,

-                                               kTestAppName,

-                                               &message));

-  EXPECT_STREQ(

-      _T("Installation failed. Ensure that your computer is connected to the ")

-      _T("Internet and that your firewall allows GoogleUpdate.exe to connect ")

-      _T("and then try again. Error code = 0x80040801."),

-      message);

-

-  EXPECT_EQ(true, FormatMessageForNetworkError(GOOPDATE_E_NETWORK_UNAUTHORIZED,

-                                               kTestAppName,

-                                               &message));

-  EXPECT_STREQ(

-      _T("The Test App installer could not connect to the Internet because of ")

-      _T("an HTTP 401 Unauthorized response. This is likely a proxy ")

-      _T("configuration issue.  Please configure the proxy server to allow ")

-      _T("network access and try again or contact your network administrator. ")

-      _T("Error code = 0x80042191"),

-      message);

-

-  EXPECT_EQ(true, FormatMessageForNetworkError(GOOPDATE_E_NETWORK_FORBIDDEN,

-                                               kTestAppName,

-                                               &message));

-  EXPECT_STREQ(

-      _T("The Test App installer could not connect to the Internet because of ")

-      _T("an HTTP 403 Forbidden response. This is likely a proxy ")

-      _T("configuration issue.  Please configure the proxy server to allow ")

-      _T("network access and try again or contact your network administrator. ")

-      _T("Error code = 0x80042193"),

-      message);

-

-  EXPECT_EQ(true,

-            FormatMessageForNetworkError(GOOPDATE_E_NETWORK_PROXYAUTHREQUIRED,

-                                         kTestAppName,

-                                         &message));

-  EXPECT_STREQ(

-      _T("The Test App installer could not connect to the Internet because a ")

-      _T("proxy server required user authentication. Please configure the ")

-      _T("proxy server to allow network access and try again or contact your ")

-      _T("network administrator. Error code = 0x80042197"),

-      message);

-

-  EXPECT_EQ(false, FormatMessageForNetworkError(E_FAIL,

-                                                kTestAppName,

-                                                &message));

-  EXPECT_STREQ(

-      _T("Installation failed. Ensure that your computer is connected to the ")

-      _T("Internet and that your firewall allows GoogleUpdate.exe to connect ")

-      _T("and then try again. Error code = 0x80004005."),

-      message);

-}

-

-TEST(GoopdateUtilsTest, WriteInstallerDataToTempFile) {

-  CStringA utf8_bom;

-  utf8_bom.Format("%c%c%c", 0xEF, 0xBB, 0xBF);

-

-  std::vector<CString> list_installer_data;

-

-  list_installer_data.push_back(_T(""));

-  list_installer_data.push_back(_T("hello\n"));

-  list_installer_data.push_back(_T("good bye"));

-  list_installer_data.push_back(_T("  there  you\n     go "));

-  list_installer_data.push_back(_T("\"http://foo.bar.org/?q=stuff&h=other\""));

-  list_installer_data.push_back(_T("foo\r\nbar\n"));

-  list_installer_data.push_back(_T("foo\n\rbar"));    // LFCR is not recognized.

-

-  std::vector<CStringA> expected_installer_data;

-  expected_installer_data.push_back("");

-  expected_installer_data.push_back("hello\n");

-  expected_installer_data.push_back("good bye");

-  expected_installer_data.push_back("  there  you\n     go ");

-  expected_installer_data.push_back("\"http://foo.bar.org/?q=stuff&h=other\"");

-  expected_installer_data.push_back("foo\r\nbar\n");

-  expected_installer_data.push_back("foo\n\rbar");

-

-  ASSERT_EQ(expected_installer_data.size(), list_installer_data.size());

-

-  for (size_t i = 0; i < list_installer_data.size(); ++i) {

-    CString installer_data = list_installer_data[i];

-    SCOPED_TRACE(installer_data);

-

-    CString file_path;

-    HRESULT hr = goopdate_utils::WriteInstallerDataToTempFile(

-        installer_data,

-        &file_path);

-    EXPECT_SUCCEEDED(hr);

-

-    // TODO(omaha): consider eliminating the special case.

-    // WriteInstallerDataToTempFile() will return S_FALSE with "" data.

-    if (S_OK == hr) {

-      File file;

-      const int kBufferLen = 1000;

-      std::vector<byte> data_line(kBufferLen);

-      EXPECT_SUCCEEDED(file.Open(file_path, false, false));

-      uint32 bytes_read(0);

-      EXPECT_SUCCEEDED(file.Read(data_line.size(),

-                                 &data_line.front(),

-                                 &bytes_read));

-      data_line.resize(bytes_read);

-      data_line.push_back(0);

-      EXPECT_STREQ(utf8_bom + expected_installer_data[i],

-                   reinterpret_cast<const char*>(&data_line.front()));

-      EXPECT_SUCCEEDED(file.Close());

-    } else {

-      EXPECT_TRUE(installer_data.IsEmpty());

-    }

-  }

-}

-

-TEST(GoopdateUtilsTest, GetDefaultGoopdateTaskName_Core_Machine) {

-  CString expected_task_name(kScheduledTaskNameMachinePrefix);

-  expected_task_name += kScheduledTaskNameCoreSuffix;

-

-  EXPECT_STREQ(

-      expected_task_name,

-      goopdate_utils::GetDefaultGoopdateTaskName(true, COMMANDLINE_MODE_CORE));

-}

-

-TEST(GoopdateUtilsTest, GetDefaultGoopdateTaskName_Core_User) {

-  CString expected_task_name_user = kScheduledTaskNameUserPrefix;

-  CString user_sid;

-  EXPECT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid));

-  expected_task_name_user += user_sid;

-  expected_task_name_user += kScheduledTaskNameCoreSuffix;

-  EXPECT_STREQ(

-      expected_task_name_user,

-      goopdate_utils::GetDefaultGoopdateTaskName(false, COMMANDLINE_MODE_CORE));

-}

-

-TEST(GoopdateUtilsTest, GetDefaultGoopdateTaskName_UA_Machine) {

-  CString expected_task_name(kScheduledTaskNameMachinePrefix);

-  expected_task_name += kScheduledTaskNameUASuffix;

-

-  EXPECT_STREQ(

-      expected_task_name,

-      goopdate_utils::GetDefaultGoopdateTaskName(true, COMMANDLINE_MODE_UA));

-}

-

-TEST(GoopdateUtilsTest, GetDefaultGoopdateTaskName_UA_User) {

-  CString expected_task_name_user = kScheduledTaskNameUserPrefix;

-  CString user_sid;

-  EXPECT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid));

-  expected_task_name_user += user_sid;

-  expected_task_name_user += kScheduledTaskNameUASuffix;

-  EXPECT_STREQ(

-      expected_task_name_user,

-      goopdate_utils::GetDefaultGoopdateTaskName(false, COMMANDLINE_MODE_UA));

-}

-

-}  // namespace goopdate_utils

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <atlpath.h>
+#include <atlsecurity.h>
+#include <atlstr.h>
+#include <map>
+#include <vector>
+#include "omaha/common/app_util.h"
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/const_utils.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_ptr_cotask.h"
+#include "omaha/common/string.h"
+#include "omaha/common/time.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/common/vista_utils.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/extra_args_parser.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/goopdate_utils-internal.h"
+#include "omaha/testing/resource.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+#define DUMMY_CLSID  _T("{6FC94136-0D4C-450e-99C2-BCDA72A9C8F0}")
+const TCHAR* hkcr_key_name = _T("HKCR\\CLSID\\") DUMMY_CLSID;
+const TCHAR* hklm_key_name = _T("HKLM\\Software\\Classes\\CLSID\\")
+                             DUMMY_CLSID;
+const TCHAR* hkcu_key_name = _T("HKCU\\Software\\Classes\\CLSID\\")
+                             DUMMY_CLSID;
+
+#define APP_GUID _T("{B7BAF788-9D64-49c3-AFDC-B336AB12F332}")
+const TCHAR* const kAppGuid = APP_GUID;
+const TCHAR* const kAppMachineClientStatePath =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\") APP_GUID;
+const TCHAR* const kAppUserClientStatePath =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\") APP_GUID;
+const TCHAR* const kAppMachineClientStateMediumPath =
+    _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\") APP_GUID;
+
+// This should never exist. This contant is only used to verify it is not used.
+const TCHAR* const kAppUserClientStateMediumPath =
+    _T("HKCU\\Software\\Google\\Update\\ClientStateMedium\\") APP_GUID;
+
+// Constants used in the scheduled task tests.
+const int kMaxWaitForProcessMs              = 5000;
+const int kWaitForProcessIntervalMs         = 100;
+const int kMaxWaitForProcessIterations      =
+    kMaxWaitForProcessMs / kWaitForProcessIntervalMs;
+
+// Verifies that one of the expected OS strings was found in the url.
+// Returns the position along with the length of the OS string.
+int VerifyOSInUrl(const CString& url, int* length) {
+  ASSERT1(length);
+  *length = 0;
+
+  // The strings are in descending version order to avoid breaking on a
+  // substring of the version we are looking for.
+  const TCHAR* kExpectedOsStrings[] = {_T("6.0&sp=Service%20Pack%201"),
+                                       _T("6.0&sp="),
+                                       _T("5.2&sp=Service%20Pack%202"),
+                                       _T("5.2&sp=Service%20Pack%201"),
+                                       _T("5.1&sp=Service%20Pack%203"),
+                                       _T("5.1&sp=Service%20Pack%202"),
+                                      };
+
+  bool found = false;
+  int this_pos = 0;
+
+  for (int i = 0; i < arraysize(kExpectedOsStrings); ++i) {
+    this_pos = url.Find(kExpectedOsStrings[i]);
+    if (-1 != this_pos) {
+      found = true;
+      *length = _tcslen(kExpectedOsStrings[i]);
+      break;
+    }
+  }
+
+  EXPECT_TRUE(found);
+  return this_pos;
+}
+
+}  // namespace
+
+namespace goopdate_utils {
+
+namespace internal {
+
+TEST(GoopdateUtilsTest, ScheduledTasks) {
+  const TCHAR kSchedTestTaskName[]            = _T("TestScheduledTask");
+  const TCHAR kScheduledTaskExecutable[]      = _T("netstat.exe");
+  const TCHAR kScheduledTaskParameters[]      = _T("20");
+  const TCHAR kSchedTestTaskComment[]         = _T("Google Test Task");
+
+  CString task_path = ConcatenatePath(app_util::GetSystemDir(),
+                                      kScheduledTaskExecutable);
+  // Install/uninstall.
+  EXPECT_SUCCEEDED(InstallScheduledTask(kSchedTestTaskName,
+                                        task_path,
+                                        _T(""),
+                                        kSchedTestTaskComment,
+                                        vista_util::IsUserAdmin(),
+                                        vista_util::IsUserAdmin(),
+                                        true,
+                                        true));
+  EXPECT_SUCCEEDED(UninstallScheduledTask(kSchedTestTaskName));
+
+  // Calling InstallScheduledTask twice should succeed.
+  for (int i = 0; i < 2; ++i) {
+    EXPECT_SUCCEEDED(InstallScheduledTask(kSchedTestTaskName,
+                                          task_path,
+                                          _T(""),
+                                          kSchedTestTaskComment,
+                                          vista_util::IsUserAdmin(),
+                                          vista_util::IsUserAdmin(),
+                                          true,
+                                          true));
+  }
+
+  // "Upgrade" to a new version, which now has parameters.
+  EXPECT_SUCCEEDED(InstallScheduledTask(kSchedTestTaskName,
+                                        task_path,
+                                        kScheduledTaskParameters,
+                                        kSchedTestTaskComment,
+                                        vista_util::IsUserAdmin(),
+                                        vista_util::IsUserAdmin(),
+                                        true,
+                                        true));
+
+  // Start and stop.
+  EXPECT_SUCCEEDED(StartScheduledTask(kSchedTestTaskName));
+  HRESULT hr = E_FAIL;
+  for (int tries = 0;
+       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_RUNNING != hr;
+       ++tries) {
+    ::Sleep(kWaitForProcessIntervalMs);
+    hr = GetScheduledTaskStatus(kSchedTestTaskName);
+  }
+  EXPECT_EQ(SCHED_S_TASK_RUNNING, hr);
+
+  // Without a wait in between the start and stop, stop failed intermittently.
+  ::Sleep(500);
+
+  EXPECT_SUCCEEDED(StopScheduledTask(kSchedTestTaskName));
+  hr = SCHED_S_TASK_RUNNING;
+  for (int tries = 0;
+       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_RUNNING == hr;
+       ++tries) {
+    ::Sleep(kWaitForProcessIntervalMs);
+    hr = GetScheduledTaskStatus(kSchedTestTaskName);
+  }
+  EXPECT_NE(SCHED_S_TASK_RUNNING, hr);
+
+  // Finally, uninstall.
+  EXPECT_SUCCEEDED(UninstallScheduledTask(kSchedTestTaskName));
+}
+
+}  // namespace internal
+
+static void Cleanup() {
+  ASSERT_SUCCEEDED(goopdate_utils::RemoveRedirectHKCR());
+
+  RegKey::DeleteKey(hkcr_key_name, true);
+  RegKey::DeleteKey(hklm_key_name, true);
+  RegKey::DeleteKey(hkcu_key_name, true);
+}
+
+static void TestGetBrowserToRestart(BrowserType stamped,
+                                    bool found1,
+                                    bool killed1,
+                                    BrowserType def_browser,
+                                    bool found2,
+                                    bool killed2,
+                                    BrowserType expected) {
+  TerminateBrowserResult res(found1, killed1);
+  TerminateBrowserResult def(found2, killed2);
+
+  BrowserType type = BROWSER_UNKNOWN;
+  if (expected == BROWSER_UNKNOWN) {
+    EXPECT_FALSE(goopdate_utils::GetBrowserToRestart(stamped,
+                                                     def_browser,
+                                                     res,
+                                                     def,
+                                                     &type))
+        << _T("stamped: ") << stamped << _T(" ") << found1 << _T(" ") << killed1
+        << _T("   default: ") << def_browser << _T(" ") << found2 << _T(" ")
+        << killed2;
+  } else {
+    EXPECT_TRUE(goopdate_utils::GetBrowserToRestart(stamped,
+                                                    def_browser,
+                                                    res,
+                                                    def,
+                                                    &type))
+        << _T("stamped: ") << stamped << _T(" ") << found1 << _T(" ") << killed1
+        << _T("   default: ") << def_browser << _T(" ") << found2 << _T(" ")
+        << killed2;
+  }
+  EXPECT_EQ(expected, type)
+      << _T("stamped: ") << stamped << _T(" ") << found1 << _T(" ") << killed1
+      << _T("   default: ") << def_browser << _T(" ") << found2 << _T(" ")
+      << killed2;
+}
+
+TEST(GoopdateUtilsTest, GetAppClientsKey) {
+  const TCHAR kAppGuid[] = _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}");
+
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\Clients\\")
+               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),
+               goopdate_utils::GetAppClientsKey(false, kAppGuid));
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\Clients\\")
+               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),
+               goopdate_utils::GetAppClientsKey(true, kAppGuid));
+}
+
+TEST(GoopdateUtilsTest, GetAppClientStateKey) {
+  const TCHAR kAppGuid[] = _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}");
+
+  EXPECT_STREQ(_T("HKCU\\Software\\Google\\Update\\ClientState\\")
+               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),
+               goopdate_utils::GetAppClientStateKey(false, kAppGuid));
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientState\\")
+               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),
+               goopdate_utils::GetAppClientStateKey(true, kAppGuid));
+}
+
+// This is an invalid case and causes an assert. Always returns HKLM path.
+TEST(GoopdateUtilsTest, GetAppClientStateMediumKey_User) {
+  const TCHAR kAppGuid[] = _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}");
+  ExpectAsserts expect_asserts;
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\")
+               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),
+               goopdate_utils::GetAppClientStateMediumKey(false, kAppGuid));
+}
+
+TEST(GoopdateUtilsTest, GetAppClientStateMediumKey_Machine) {
+  const TCHAR kAppGuid[] = _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}");
+  EXPECT_STREQ(_T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\")
+               _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}"),
+               goopdate_utils::GetAppClientStateMediumKey(true, kAppGuid));
+}
+
+// This is an invalid case and causes an assert.
+TEST(GoopdateUtilsTest, GetAppClientStateMediumKey_UserAndMachineAreSame) {
+  const TCHAR kAppGuid[] = _T("{F998D7E0-0CD3-434e-96B9-B8D3A295C3FB}");
+  ExpectAsserts expect_asserts;
+  EXPECT_STREQ(goopdate_utils::GetAppClientStateMediumKey(true, kAppGuid),
+               goopdate_utils::GetAppClientStateMediumKey(false, kAppGuid));
+}
+
+TEST(GoopdateUtilsTest, TerminateAllBrowsers_BrowserUnknown) {
+  TerminateBrowserResult browser_res;
+  TerminateBrowserResult default_res;
+  ExpectAsserts expect_asserts;
+  EXPECT_EQ(E_INVALIDARG, goopdate_utils::TerminateAllBrowsers(BROWSER_UNKNOWN,
+                                                               &browser_res,
+                                                               &default_res));
+}
+
+TEST(GoopdateUtilsTest, TerminateAllBrowsers_BrowserDefault) {
+  TerminateBrowserResult browser_res;
+  TerminateBrowserResult default_res;
+  ExpectAsserts expect_asserts;
+  EXPECT_EQ(E_INVALIDARG, goopdate_utils::TerminateAllBrowsers(BROWSER_DEFAULT,
+                                                               &browser_res,
+                                                               &default_res));
+}
+
+TEST(GoopdateUtilsTest, TerminateAllBrowsers_BrowserMax) {
+  TerminateBrowserResult browser_res;
+  TerminateBrowserResult default_res;
+  ExpectAsserts expect_asserts;
+  EXPECT_EQ(E_INVALIDARG, goopdate_utils::TerminateAllBrowsers(BROWSER_MAX,
+                                                               &browser_res,
+                                                               &default_res));
+}
+
+// TerminateAllBrowsers is not tested with valid browser values because the
+// tests would terminate developers' browsers.
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedUnknown) {
+  ExpectAsserts expect_asserts;
+  TestGetBrowserToRestart(BROWSER_UNKNOWN, false, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_UNKNOWN, true, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_DefaultUnknown) {
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedAndDefaultUnknown) {
+  ExpectAsserts expect_asserts;
+  TestGetBrowserToRestart(BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_UNKNOWN, true, false,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedDefault) {
+  ExpectAsserts expect_asserts;
+  TestGetBrowserToRestart(BROWSER_DEFAULT, false, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_DEFAULT, true, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_DefaultDefault) {
+  ExpectAsserts expect_asserts;
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_DEFAULT, false, false,
+                          BROWSER_UNKNOWN);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedAndDefaultDefault) {
+  ExpectAsserts expect_asserts;
+  TestGetBrowserToRestart(BROWSER_DEFAULT, false, false,
+                          BROWSER_DEFAULT, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_DEFAULT, true, false,
+                          BROWSER_DEFAULT, false, false,
+                          BROWSER_UNKNOWN);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedMax) {
+  ExpectAsserts expect_asserts;
+  TestGetBrowserToRestart(BROWSER_MAX, false, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_MAX, true, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_DefaultMax) {
+  ExpectAsserts expect_asserts;
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_MAX, false, false,
+                          BROWSER_UNKNOWN);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_StampedAndDefaultMax) {
+  ExpectAsserts expect_asserts;
+  TestGetBrowserToRestart(BROWSER_MAX, false, false,
+                          BROWSER_MAX, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_MAX, true, false,
+                          BROWSER_MAX, false, false,
+                          BROWSER_UNKNOWN);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeIE_DefaultIE) {
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_IE, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_IE, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_IE, true, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_IE, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_IE, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_IE, true, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_IE, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_IE, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_IE, true, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_IE, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_IE, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_IE, true, true,
+                          BROWSER_IE);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeIE_DefaultFirefox) {
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_IE);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeIE_DefaultChrome) {
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_IE);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeIE_DefaultUnknown) {
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, false,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, false, true,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, false,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_IE, true, true,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_IE);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeFirefox_DefaultIE) {
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_IE, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_IE, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_IE, true, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_IE, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_IE, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_IE, true, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_IE, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_IE, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_IE, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_IE, false, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_IE, false, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_IE, true, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_IE, true, true,
+                          BROWSER_FIREFOX);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeFirefox_DefaultFirefox) {
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeFirefox_DefaultChrome) {
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_FIREFOX);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeFirefox_DefaultUnknown) {
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, false,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, false, true,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_FIREFOX, true, true,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_FIREFOX);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeChrome_DefaultIE) {
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_IE, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_IE, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_IE, true, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_IE, false, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_IE, false, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_IE, true, false,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_IE, true, true,
+                          BROWSER_IE);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_IE, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_IE, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_IE, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_IE, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_IE, false, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_IE, false, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_IE, true, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_IE, true, true,
+                          BROWSER_CHROME);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeChrome_DefaultFirefox) {
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_FIREFOX);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_FIREFOX, false, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_FIREFOX, false, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_FIREFOX, true, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_FIREFOX, true, true,
+                          BROWSER_CHROME);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeChrome_DefaultChrome) {
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_CHROME, false, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_CHROME, false, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_CHROME, true, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_CHROME, true, true,
+                          BROWSER_CHROME);
+}
+
+TEST(GoopdateUtilsTest, GetBrowserToRestart_TypeChrome_DefaultUnknown) {
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, false,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, false, true,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, false,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_UNKNOWN);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_UNKNOWN, false, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_UNKNOWN, false, true,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_UNKNOWN, true, false,
+                          BROWSER_CHROME);
+  TestGetBrowserToRestart(BROWSER_CHROME, true, true,
+                          BROWSER_UNKNOWN, true, true,
+                          BROWSER_CHROME);
+}
+
+TEST(GoopdateUtilsTest, ConvertStringToBrowserType) {
+  BrowserType type = BROWSER_UNKNOWN;
+  ASSERT_SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(_T("0"), &type));
+  ASSERT_EQ(BROWSER_UNKNOWN, type);
+
+  ASSERT_SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(_T("1"), &type));
+  ASSERT_EQ(BROWSER_DEFAULT, type);
+
+  ASSERT_SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(_T("2"), &type));
+  ASSERT_EQ(BROWSER_IE, type);
+
+  ASSERT_SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(_T("3"), &type));
+  ASSERT_EQ(BROWSER_FIREFOX, type);
+
+  ASSERT_SUCCEEDED(goopdate_utils::ConvertStringToBrowserType(_T("4"), &type));
+  ASSERT_EQ(BROWSER_CHROME, type);
+
+  ASSERT_FAILED(goopdate_utils::ConvertStringToBrowserType(_T("5"), &type));
+  ASSERT_FAILED(goopdate_utils::ConvertStringToBrowserType(_T("asdf"), &type));
+  ASSERT_FAILED(goopdate_utils::ConvertStringToBrowserType(_T("234"), &type));
+  ASSERT_FAILED(goopdate_utils::ConvertStringToBrowserType(_T("-1"), &type));
+}
+
+TEST(GoopdateUtilsTest, RedirectHKCRTest) {
+  RegKey key;
+  Cleanup();
+
+  if (vista_util::IsUserAdmin()) {
+    // Only run this part of the test for Admins, because non-admins cannot
+    // write to HKLM.
+
+    // Without redirection, a HKCR write should write HKLM\Software\Classes,
+    // assuming that the key does not already exist in HKCU.
+    ASSERT_SUCCEEDED(key.Create(hkcr_key_name));
+    ASSERT_TRUE(RegKey::HasKey(hklm_key_name));
+    ASSERT_FALSE(RegKey::HasKey(hkcu_key_name));
+
+    Cleanup();
+
+    ASSERT_SUCCEEDED(goopdate_utils::RedirectHKCR(true));
+
+    // With HKLM redirection, a HKCR write should write HKLM\Software\Classes.
+    ASSERT_SUCCEEDED(key.Create(hkcr_key_name));
+    ASSERT_TRUE(RegKey::HasKey(hklm_key_name));
+    ASSERT_FALSE(RegKey::HasKey(hkcu_key_name));
+
+    Cleanup();
+  } else {
+    std::wcout << _T("\tPart of this test did not run because the user ")
+                  _T("is not an admin.") << std::endl;
+  }
+
+  ASSERT_SUCCEEDED(goopdate_utils::RedirectHKCR(false));
+
+  // With HKCU redirection, a HKCR write should write HKCU\Software\Classes.
+  ASSERT_SUCCEEDED(key.Create(hkcr_key_name));
+  ASSERT_FALSE(RegKey::HasKey(hklm_key_name));
+  ASSERT_TRUE(RegKey::HasKey(hkcu_key_name));
+
+  ASSERT_SUCCEEDED(goopdate_utils::RemoveRedirectHKCR());
+
+  if (vista_util::IsUserAdmin()) {
+    // Without redirection, the following HKCR writes should write
+    // HKCU\Software\Classes.
+    // This is because the key already exists in HKCU from the writes above.
+    ASSERT_SUCCEEDED(key.Create(hkcr_key_name));
+    ASSERT_FALSE(RegKey::HasKey(hklm_key_name));
+    ASSERT_TRUE(RegKey::HasKey(hkcu_key_name));
+  } else {
+    std::wcout << _T("\tPart of this test did not run because the user ")
+                  _T("is not an admin.") << std::endl;
+  }
+
+  Cleanup();
+}
+
+TEST(GoopdateUtilsTest, GetImpersonationTokenNotInteractivePid0) {
+  HANDLE token = NULL;
+  ASSERT_SUCCEEDED(goopdate_utils::GetImpersonationToken(false, 0, &token));
+  ASSERT_TRUE(token != NULL);
+  ASSERT_TRUE(::CloseHandle(token));
+  token = NULL;
+}
+
+TEST(GoopdateUtilsTest, GetImpersonationTokenNotInteractiveRealPid) {
+  HANDLE token = NULL;
+  DWORD pid = ::GetCurrentProcessId();
+  ASSERT_SUCCEEDED(goopdate_utils::GetImpersonationToken(false, pid, &token));
+  ASSERT_TRUE(token != NULL);
+  ASSERT_TRUE(::CloseHandle(token));
+  token = NULL;
+}
+
+TEST(GoopdateUtilsTest, GetImpersonationTokenInteractiveValidPid) {
+  HANDLE token = NULL;
+  DWORD pid = ::GetCurrentProcessId();
+  ASSERT_SUCCEEDED(goopdate_utils::GetImpersonationToken(true, pid, &token));
+  ASSERT_TRUE(token != NULL);
+  ASSERT_TRUE(::CloseHandle(token));
+}
+
+TEST(GoopdateUtilsTest, GetImpersonationTokenInteractiveInvalidPid) {
+  HANDLE token = NULL;
+  ASSERT_EQ(E_INVALIDARG,
+            goopdate_utils::GetImpersonationToken(true, 0, &token));
+  ASSERT_TRUE(token == NULL);
+}
+
+TEST(GoopdateUtilsTest, ImpersonateUser) {
+  DWORD pid = ::GetCurrentProcessId();
+
+  if (vista_util::IsUserAdmin()) {
+    ASSERT_SUCCEEDED(goopdate_utils::ImpersonateUser(false, 0));
+    ASSERT_SUCCEEDED(goopdate_utils::UndoImpersonation(true));
+
+    ASSERT_SUCCEEDED(goopdate_utils::ImpersonateUser(false, pid));
+    ASSERT_SUCCEEDED(goopdate_utils::UndoImpersonation(true));
+
+    ASSERT_SUCCEEDED(goopdate_utils::ImpersonateUser(true, pid));
+    ASSERT_SUCCEEDED(goopdate_utils::UndoImpersonation(true));
+
+    ASSERT_EQ(E_INVALIDARG, goopdate_utils::ImpersonateUser(true, 0));
+  } else {
+    std::wcout << _T("\tThis test did not run because the user ")
+                  _T("is not an admin.") << std::endl;
+  }
+}
+
+TEST(GoopdateUtilsTest, GoopdateTasks) {
+  CString task_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                      _T("LongRunningSilent.exe"));
+  // Install/uninstall.
+  EXPECT_SUCCEEDED(InstallGoopdateTasks(task_path,
+                                        vista_util::IsUserAdmin()));
+  EXPECT_SUCCEEDED(UninstallGoopdateTasks(vista_util::IsUserAdmin()));
+
+  // Calling InstallGoopdateTask twice should succeed.
+  for (int i = 0; i < 2; ++i) {
+    EXPECT_SUCCEEDED(InstallGoopdateTasks(task_path,
+                                          vista_util::IsUserAdmin()));
+  }
+
+  // Start and stop.
+  EXPECT_SUCCEEDED(StartGoopdateTaskCore(vista_util::IsUserAdmin()));
+  HRESULT hr = E_FAIL;
+  for (int tries = 0;
+       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_RUNNING != hr;
+       ++tries) {
+    ::Sleep(kWaitForProcessIntervalMs);
+    hr = internal::GetScheduledTaskStatus(
+        ConfigManager::GetCurrentTaskNameCore(vista_util::IsUserAdmin()));
+  }
+  EXPECT_EQ(SCHED_S_TASK_RUNNING, hr);
+
+  // Without a wait in between the start and stop, stop failed intermittently.
+  ::Sleep(500);
+
+  EXPECT_SUCCEEDED(internal::StopScheduledTask(
+      ConfigManager::GetCurrentTaskNameCore(vista_util::IsUserAdmin())));
+  hr = SCHED_S_TASK_RUNNING;
+  for (int tries = 0;
+       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_RUNNING == hr;
+       ++tries) {
+    ::Sleep(kWaitForProcessIntervalMs);
+    hr = internal::GetScheduledTaskStatus(
+        ConfigManager::GetCurrentTaskNameCore(vista_util::IsUserAdmin()));
+  }
+  EXPECT_NE(SCHED_S_TASK_RUNNING, hr);
+
+  // Finally, uninstall.
+  EXPECT_SUCCEEDED(UninstallGoopdateTasks(vista_util::IsUserAdmin()));
+}
+
+TEST(GoopdateUtilsTest, GoopdateTaskInUseOverinstall) {
+  CString task_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                      _T("LongRunningSilent.exe"));
+  EXPECT_SUCCEEDED(InstallGoopdateTasks(task_path,
+                                        vista_util::IsUserAdmin()));
+
+  CString original_task_name(
+      ConfigManager::GetCurrentTaskNameCore(vista_util::IsUserAdmin()));
+
+  // Open the file underlying the current task in exclusive mode, so that
+  // InstallGoopdateTasks() is forced to create a new task.
+  CComPtr<ITaskScheduler> scheduler;
+  EXPECT_SUCCEEDED(scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                              NULL,
+                                              CLSCTX_INPROC_SERVER));
+  CComPtr<ITask> task;
+  EXPECT_SUCCEEDED(scheduler->Activate(original_task_name,
+                                       __uuidof(ITask),
+                                       reinterpret_cast<IUnknown**>(&task)));
+  CComQIPtr<IPersistFile> persist(task);
+  EXPECT_TRUE(persist);
+  scoped_ptr_cotask<OLECHAR> job_file;
+  EXPECT_SUCCEEDED(persist->GetCurFile(address(job_file)));
+  persist.Release();
+
+  File file;
+  EXPECT_SUCCEEDED(file.OpenShareMode(job_file.get(), false, false, 0));
+
+  EXPECT_SUCCEEDED(InstallGoopdateTasks(task_path,
+                                        vista_util::IsUserAdmin()));
+  CString new_task_name(
+      ConfigManager::GetCurrentTaskNameCore(vista_util::IsUserAdmin()));
+  EXPECT_STRNE(original_task_name, new_task_name);
+
+  // Cleanup.
+  file.Close();
+  EXPECT_SUCCEEDED(UninstallGoopdateTasks(vista_util::IsUserAdmin()));
+}
+
+TEST(GoopdateUtilsTest, GetExitCodeGoopdateTaskUA) {
+  CString task_path = ConcatenatePath(
+                          app_util::GetCurrentModuleDirectory(),
+                          _T("unittest_support\\SaveArguments.exe"));
+  EXPECT_SUCCEEDED(InstallGoopdateTasks(task_path,
+                                        vista_util::IsUserAdmin()));
+  EXPECT_EQ(SCHED_S_TASK_HAS_NOT_RUN,
+            GetExitCodeGoopdateTaskUA(vista_util::IsUserAdmin()));
+
+  EXPECT_SUCCEEDED(internal::StartScheduledTask(
+      ConfigManager::GetCurrentTaskNameUA(vista_util::IsUserAdmin())));
+
+  HRESULT hr = SCHED_S_TASK_HAS_NOT_RUN;
+  for (int tries = 0;
+       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_HAS_NOT_RUN == hr;
+       ++tries) {
+    ::Sleep(kWaitForProcessIntervalMs);
+    hr = internal::GetScheduledTaskStatus(
+        ConfigManager::GetCurrentTaskNameUA(vista_util::IsUserAdmin()));
+  }
+
+  hr = SCHED_S_TASK_RUNNING;
+  for (int tries = 0;
+       tries < kMaxWaitForProcessIterations && SCHED_S_TASK_RUNNING == hr;
+       ++tries) {
+    ::Sleep(kWaitForProcessIntervalMs);
+    hr = internal::GetScheduledTaskStatus(
+        ConfigManager::GetCurrentTaskNameUA(vista_util::IsUserAdmin()));
+  }
+
+  EXPECT_NE(SCHED_S_TASK_RUNNING, hr);
+  EXPECT_EQ(S_OK, GetExitCodeGoopdateTaskUA(vista_util::IsUserAdmin()));
+
+  EXPECT_SUCCEEDED(File::Remove(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("unittest_support\\saved_arguments.txt"))));
+  EXPECT_SUCCEEDED(UninstallGoopdateTasks(vista_util::IsUserAdmin()));
+}
+
+TEST(GoopdateUtilsTest, GetOSInfo) {
+  const TCHAR kXpOSVersion[] = _T("5.1");
+  const TCHAR k2003OSVersion[] = _T("5.2");
+  const TCHAR kVistaOSVersion[] = _T("6.0");
+  const TCHAR kNoSp[] = _T("");
+  const TCHAR kSp1[] = _T("Service Pack 1");
+  const TCHAR kSp2[] = _T("Service Pack 2");
+  const TCHAR kSp3[] = _T("Service Pack 3");
+
+  CString os_version;
+  CString service_pack;
+  EXPECT_SUCCEEDED(goopdate_utils::GetOSInfo(&os_version, &service_pack));
+
+  EXPECT_TRUE((kXpOSVersion == os_version && kSp2 == service_pack) ||
+              (kXpOSVersion == os_version && kSp3 == service_pack) ||
+              (k2003OSVersion == os_version && kSp1 == service_pack) ||
+              (k2003OSVersion == os_version && kSp2 == service_pack) ||
+              (kVistaOSVersion == os_version && kNoSp == service_pack) ||
+              (kVistaOSVersion == os_version && kSp1 == service_pack));
+}
+
+class GoopdateUtilsRegistryProtectedTest : public testing::Test {
+ protected:
+  GoopdateUtilsRegistryProtectedTest()
+      : hive_override_key_name_(kRegistryHiveOverrideRoot) {
+  }
+
+  CString hive_override_key_name_;
+
+  virtual void SetUp() {
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    OverrideRegistryHives(hive_override_key_name_);
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+  }
+};
+
+// Some methods used by goopdate_utils rely on registry entries that are
+// overridden in the registry, so we need to write it.
+class GoopdateUtilsRegistryProtectedWithMachineFolderPathsTest
+    : public GoopdateUtilsRegistryProtectedTest {
+ protected:
+  virtual void SetUp() {
+    const TCHAR kWindowsCurrentVersionKeyPath[] =
+        _T("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion");
+    const TCHAR kProgramFilesDirValueName[] = _T("ProgramFilesDir");
+    const TCHAR kProgramFilesPath[] = _T("C:\\Program Files");
+
+    GoopdateUtilsRegistryProtectedTest::SetUp();
+    ASSERT_SUCCEEDED(RegKey::SetValue(kWindowsCurrentVersionKeyPath,
+                                      kProgramFilesDirValueName,
+                                      kProgramFilesPath));
+  }
+};
+
+// Some methods used by goopdate_utils rely on registry entries that are
+// overridden in the registry, so we need to write it.
+class GoopdateUtilsRegistryProtectedWithUserFolderPathsTest
+    : public GoopdateUtilsRegistryProtectedTest {
+ protected:
+  virtual void SetUp() {
+  const TCHAR kUserShellKeyPath[] =
+        _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\")
+        _T("User Shell Folders");
+    const TCHAR kLocalAppDataValueDirName[] = _T("Local AppData");
+    const TCHAR kLocalAppDataPath[] =
+        _T("%USERPROFILE%\\Local Settings\\Application Data");
+
+    GoopdateUtilsRegistryProtectedTest::SetUp();
+    ASSERT_SUCCEEDED(RegKey::SetValueExpandSZ(kUserShellKeyPath,
+                                              kLocalAppDataValueDirName,
+                                              kLocalAppDataPath));
+  }
+};
+
+// pv should be ignored.
+TEST_F(GoopdateUtilsRegistryProtectedWithMachineFolderPathsTest,
+       BuildGoogleUpdateExePath_MachineVersionFound) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  CString path = goopdate_utils::BuildGoogleUpdateExePath(true);
+  CString program_files_path;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files_path));
+  EXPECT_STREQ(program_files_path + _T("\\Google\\Update\\GoogleUpdate.exe"),
+               path);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedWithMachineFolderPathsTest,
+       BuildGoogleUpdateExePath_MachineVersionNotFound) {
+  // Test when the key doesn't exist.
+  CString path = goopdate_utils::BuildGoogleUpdateExePath(true);
+  CString program_files_path;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files_path));
+  EXPECT_STREQ(program_files_path + _T("\\Google\\Update\\GoogleUpdate.exe"),
+               path);
+
+  // Test when the key exists but the value doesn't.
+  ASSERT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENTS_GOOPDATE));
+  path = goopdate_utils::BuildGoogleUpdateExePath(true);
+  EXPECT_STREQ(program_files_path + _T("\\Google\\Update\\GoogleUpdate.exe"),
+               path);
+}
+
+// pv should be ignored.
+TEST_F(GoopdateUtilsRegistryProtectedWithUserFolderPathsTest,
+       BuildGoogleUpdateExePath_UserVersionFound) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  CString path = goopdate_utils::BuildGoogleUpdateExePath(false);
+
+  CString user_appdata;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_LOCAL_APPDATA, &user_appdata));
+  CString expected_path;
+  expected_path.Format(_T("%s\\Google\\Update\\GoogleUpdate.exe"),
+                       user_appdata);
+  EXPECT_STREQ(expected_path, path);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedWithUserFolderPathsTest,
+       BuildGoogleUpdateExePath_UserVersionNotFound) {
+  CString user_appdata;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_LOCAL_APPDATA, &user_appdata));
+  CString expected_path;
+  expected_path.Format(_T("%s\\Google\\Update\\GoogleUpdate.exe"),
+                       user_appdata);
+
+  // Test when the key doesn't exist.
+  CString path = goopdate_utils::BuildGoogleUpdateExePath(false);
+  EXPECT_STREQ(expected_path, path);
+
+  // Test when the key exists but the value doesn't.
+  ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENTS_GOOPDATE));
+  path = goopdate_utils::BuildGoogleUpdateExePath(false);
+  EXPECT_STREQ(expected_path, path);
+}
+
+// The version is no longer used by StartGoogleUpdateWithArgs, so the return
+// value depends on whether program_files\Google\Update\GoogleUpdate.exe exists.
+TEST_F(GoopdateUtilsRegistryProtectedWithMachineFolderPathsTest,
+       StartGoogleUpdateWithArgs_MachineVersionVersionDoesNotExist) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  const TCHAR* kArgs = _T("/foo");
+  HRESULT hr = goopdate_utils::StartGoogleUpdateWithArgs(true, kArgs, NULL);
+  EXPECT_TRUE(S_OK == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);
+}
+
+// The version is no longer used by StartGoogleUpdateWithArgs, so the return
+// value depends on whether <user_folder>\Google\Update\GoogleUpdate.exe exists.
+// Also tests NULL args parameter
+TEST_F(GoopdateUtilsRegistryProtectedWithUserFolderPathsTest,
+       StartGoogleUpdateWithArgs_UserVersionVersionDoesNotExist) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  HRESULT hr = goopdate_utils::StartGoogleUpdateWithArgs(false, NULL, NULL);
+  EXPECT_TRUE(S_OK == hr || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, GetPersistentUserId_User) {
+  CString id;
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(USER_KEY_NAME,
+                                                 kRegValueUserId,
+                                                 &id));
+
+  CString uid = goopdate_utils::GetPersistentUserId(USER_KEY_NAME);
+  EXPECT_FALSE(uid.IsEmpty());
+
+  EXPECT_SUCCEEDED(goopdate_utils::ReadPersistentId(USER_KEY_NAME,
+                                                    kRegValueUserId,
+                                                    &id));
+  EXPECT_STREQ(uid, id);
+
+  uid = goopdate_utils::GetPersistentUserId(USER_KEY_NAME);
+  EXPECT_STREQ(uid, id);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, GetPersistentUserId_Machine) {
+  CString id;
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                 kRegValueUserId,
+                                                 &id));
+
+  CString uid = goopdate_utils::GetPersistentUserId(MACHINE_KEY_NAME);
+  EXPECT_FALSE(uid.IsEmpty());
+
+  EXPECT_SUCCEEDED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                    kRegValueUserId,
+                                                    &id));
+  EXPECT_STREQ(uid, id);
+
+  uid = goopdate_utils::GetPersistentUserId(MACHINE_KEY_NAME);
+  EXPECT_STREQ(uid, id);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, GetPersistentMachineId_Machine) {
+  // Initially there is no machine id.
+  CString id;
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                 kRegValueMachineId,
+                                                 &id));
+  // Call the test method.
+  CString mid = goopdate_utils::GetPersistentMachineId();
+  EXPECT_FALSE(mid.IsEmpty());
+
+  // Ensure that the value is written in the registry.
+  EXPECT_SUCCEEDED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                    kRegValueMachineId,
+                                                    &id));
+  EXPECT_STREQ(mid, id);
+
+  // Call the method again.
+  mid = goopdate_utils::GetPersistentMachineId();
+
+  // Ensure that the same id is returned.
+  EXPECT_STREQ(mid, id);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, GetPersistentMachineId_User1) {
+  // Initially there is no machine id.
+  CString id;
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                 kRegValueMachineId,
+                                                 &id));
+  SID* sid_val = NULL;
+  ASSERT_TRUE(::ConvertStringSidToSid(_T("S-1-1-0"),
+                                      reinterpret_cast<PSID*>(&sid_val)));
+  ASSERT_TRUE(sid_val != NULL);
+
+  // Create the update key.
+  RegKey mid_key;
+  EXPECT_SUCCEEDED(mid_key.Create(HKEY_LOCAL_MACHINE, GOOPDATE_MAIN_KEY));
+  CDacl dacl;
+  ASSERT_TRUE(AtlGetDacl(mid_key.Key(), SE_REGISTRY_KEY, &dacl));
+  ASSERT_TRUE(dacl.AddDeniedAce(*sid_val, KEY_SET_VALUE));
+  EXPECT_SUCCEEDED(mid_key.Close());
+
+  // Now set the key permissions to not allow anyone to write.
+  EXPECT_SUCCEEDED(mid_key.Open(HKEY_LOCAL_MACHINE, GOOPDATE_MAIN_KEY));
+  ASSERT_TRUE(AtlSetDacl(mid_key.Key(), SE_REGISTRY_KEY, dacl, 0));
+
+  // Call the test method.
+  CString mid = goopdate_utils::GetPersistentMachineId();
+  ASSERT_TRUE(mid.IsEmpty());
+
+  // Ensure that the value Could not be written to the registry.
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                 kRegValueMachineId,
+                                                 &id));
+  ASSERT_TRUE(id.IsEmpty());
+
+  ASSERT_TRUE(dacl.RemoveAces(*sid_val));
+  ASSERT_TRUE(AtlSetDacl(mid_key.Key(), SE_REGISTRY_KEY, dacl, 0));
+  EXPECT_SUCCEEDED(mid_key.Close());
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, GetPersistentMachineId_User2) {
+  // Test simulates the situation where a machine goopdate is already running
+  // and a user goopdate is run next.
+
+  // Initially there is no machine id.
+  CString id;
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                 kRegValueMachineId,
+                                                 &id));
+
+  CString mid = goopdate_utils::GetPersistentMachineId();
+  EXPECT_FALSE(mid.IsEmpty());
+
+  // Ensure that the value Could not be written to the registry.
+  EXPECT_SUCCEEDED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                kRegValueMachineId,
+                                                &id));
+  EXPECT_STREQ(id, mid);
+
+  // Now set the permissions on the registry key such that we cannot write to
+  // it. We should however be able to read from it.
+  SID* sid_val = NULL;
+  ASSERT_TRUE(::ConvertStringSidToSid(_T("S-1-1-0"),
+                                      reinterpret_cast<PSID*>(&sid_val)));
+  ASSERT_TRUE(sid_val != NULL);
+
+  RegKey mid_key;
+  EXPECT_SUCCEEDED(mid_key.Open(HKEY_LOCAL_MACHINE, GOOPDATE_MAIN_KEY));
+  CDacl dacl;
+  ASSERT_TRUE(AtlGetDacl(mid_key.Key(), SE_REGISTRY_KEY, &dacl));
+  ASSERT_TRUE(dacl.AddDeniedAce(*sid_val, KEY_SET_VALUE));
+  ASSERT_TRUE(AtlSetDacl(mid_key.Key(), SE_REGISTRY_KEY, dacl, 0));
+
+  // Call the test method.
+  mid = goopdate_utils::GetPersistentMachineId();
+  EXPECT_FALSE(mid.IsEmpty());
+  EXPECT_STREQ(mid, id);
+
+  ASSERT_TRUE(dacl.RemoveAces(*sid_val));
+  ASSERT_TRUE(AtlSetDacl(mid_key.Key(), SE_REGISTRY_KEY, dacl, 0));
+  EXPECT_SUCCEEDED(mid_key.Close());
+}
+
+// New Unique ID is created and stored.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       GetPersistentUserId_OemInstalling_User) {
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+  ASSERT_TRUE(ConfigManager::Instance()->IsOemInstalling(true));
+
+  CString id;
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(USER_KEY_NAME,
+                                                 kRegValueUserId,
+                                                 &id));
+
+  CString uid = goopdate_utils::GetPersistentUserId(USER_KEY_NAME);
+  EXPECT_FALSE(uid.IsEmpty());
+
+  EXPECT_SUCCEEDED(goopdate_utils::ReadPersistentId(USER_KEY_NAME,
+                                                    kRegValueUserId,
+                                                    &id));
+  EXPECT_STREQ(uid, id);
+
+  uid = goopdate_utils::GetPersistentUserId(USER_KEY_NAME);
+  EXPECT_STREQ(uid, id);
+}
+
+// Special value is returned but not stored.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       GetPersistentUserId_OemInstalling_Machine) {
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+  ASSERT_TRUE(ConfigManager::Instance()->IsOemInstalling(true));
+
+  CString id;
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                 kRegValueUserId,
+                                                 &id));
+
+  CString uid = goopdate_utils::GetPersistentUserId(MACHINE_KEY_NAME);
+  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), uid);
+
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                 kRegValueUserId,
+                                                 &id));
+
+  uid = goopdate_utils::GetPersistentUserId(MACHINE_KEY_NAME);
+  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), uid);
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueUserId));
+
+  // Test the case where the value already exists.
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      MACHINE_REG_UPDATE,
+      kRegValueUserId,
+      _T("{12345678-1234-1234-1234-123456789abcd}")));
+  uid = goopdate_utils::GetPersistentUserId(MACHINE_KEY_NAME);
+  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), uid);
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueUserId));
+}
+
+// Special value is returned but not stored.
+// There is no difference between user and machine instances.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       GetPersistentMachineId_OemInstalling_Machine) {
+  const DWORD now_seconds = Time64ToInt32(GetCurrent100NSTime());
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now_seconds));
+  ASSERT_TRUE(ConfigManager::Instance()->IsOemInstalling(true));
+
+  CString id;
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                 kRegValueMachineId,
+                                                 &id));
+
+  CString mid = goopdate_utils::GetPersistentMachineId();
+  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), mid);
+
+  EXPECT_FAILED(goopdate_utils::ReadPersistentId(MACHINE_KEY_NAME,
+                                                 kRegValueMachineId,
+                                                 &id));
+
+  mid = goopdate_utils::GetPersistentMachineId();
+  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), mid);
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueMachineId));
+
+  // Test the case where the value already exists.
+  EXPECT_SUCCEEDED(RegKey::SetValue(
+      MACHINE_REG_UPDATE,
+      kRegValueMachineId,
+      _T("{12345678-1234-1234-1234-123456789abcd}")));
+  mid = goopdate_utils::GetPersistentMachineId();
+  EXPECT_STREQ(_T("{00000000-03AA-03AA-03AA-000000000000}"), mid);
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueMachineId));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_NoKey) {
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_ClientStateExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_ClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_ClientStateNegativeOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(-1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_ClientStateZero_MediumNotExist) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_ClientStateZero_MediumExists) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStateMediumPath));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_ClientStateZero_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+    IsAppEulaAccepted_Machine_NotExplicit_ClientStateZero_MediumNegativeOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(-1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// Also tests that user values are not used.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_ClientStateZero_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// ClientStateMedium does not override ClientState.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_ClientStateOne_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// Implicitly accepted because of the absence of eualaccepted=0.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_ClientStateNotExist_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// Implicitly accepted because of the absence of eualaccepted=0.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_NotExplicit_ClientStateNotExist_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, false));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_NoKey) {
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateNegativeOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(-1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateZero_MediumNotExist) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateZero_MediumExists) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStateMediumPath));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateZero_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateZero_MediumNegativeOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(-1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// Also tests that user values are not used.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateZero_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// ClientStateMedium does not override ClientState.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateOne_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateNotExist_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_Machine_Explicit_ClientStateNotExist_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(true, kAppGuid, true));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// ClientStateMedium is not supported for user apps.
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_NoKey) {
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateNegativeOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(-1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_EQ(-1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateZero_MediumNotExist) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateZero_MediumExists) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStateMediumPath));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateZero_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateZero_MediumNegativeOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(-1)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(-1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// Also tests that machine values are not used.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateZero_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// ClientStateMedium is not used.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateOne_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// Implicitly accepted because of the absence of eualaccepted=0.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateNotExist_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// Implicitly accepted because of the absence of eualaccepted=0.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_NotExplicit_ClientStateNotExist_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, false));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_Explicit_NoKey) {
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, true));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_Explicit_ClientStateExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, true));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_Explicit_ClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, true));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_Explicit_ClientStateNotExist_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, true));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       IsAppEulaAccepted_User_Explicit_ClientStateNotExist_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::IsAppEulaAccepted(false, kAppGuid, true));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_Machine_NoKey) {
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_Machine_ClientStateExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_Machine_ClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_Machine_ClientStateZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_Machine_ClientStateZero_ClientStateMediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// Also tests that user values are not affected.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_Machine_ClientStateZero_ClientStateMediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_User_NoKey) {
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_User_ClientStateExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_User_ClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_User_ClientStateZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_User_ClientStateZero_ClientStateMediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+// Also tests that machine values are not affected.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppEulaNotAccepted_User_ClientStateZero_ClientStateMediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_Machine_NoKey) {
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_Machine_ClientStateExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_Machine_ClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_Machine_ClientStateZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_Machine_ClientStateZero_ClientStateMediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+}
+
+// Also tests that user values are not affected.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_Machine_ClientStateNone_ClientStateMediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("eulaaccepted")));
+  EXPECT_EQ(0,
+            GetDwordValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0,
+            GetDwordValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_User_NoKey) {
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_User_ClientStateExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_User_ClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_User_ClientStateZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_User_ClientStateZero_ClientStateMediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0,
+            GetDwordValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+}
+
+// Also tests that machine values are not affected.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       ClearAppEulaNotAccepted_User_ClientStateNone_ClientStateMediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(goopdate_utils::ClearAppEulaNotAccepted(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0,
+            GetDwordValue(kAppUserClientStateMediumPath, _T("eulaaccepted")));
+  EXPECT_EQ(0,
+            GetDwordValue(kAppMachineClientStatePath, _T("eulaaccepted")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("eulaaccepted")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_NoKey) {
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_ClientStateExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_ClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_ClientStateNegativeOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(-1)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_ClientStateZero_MediumNotExist) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_ClientStateZero_MediumExists) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStateMediumPath));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));
+}
+
+// ClientStateMedium overrides ClientState.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_ClientStateZero_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+    AreAppUsageStatsEnabled_Machine_ClientStateZero_MediumNegativeOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(-1)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_EQ(-1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_ClientStateZero_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+// ClientStateMedium overrides ClientState.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_ClientStateOne_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_ClientStateNotExist_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_ClientStateNotExist_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_EQ(0, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+// User does not affect machine.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_Machine_UserOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(true, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+// ClientStateMedium is not supported for user apps.
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_NoKey) {
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateExists) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStatePath));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_TRUE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateNegativeOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(-1)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_EQ(-1, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateZero_MediumNotExist) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateZero_MediumExists) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kAppUserClientStateMediumPath));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));
+}
+
+// ClientStateMedium is not used.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateZero_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateZero_MediumNegativeOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(-1)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_EQ(-1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateZero_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+// ClientStateMedium is not used.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateOne_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_TRUE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateNotExist_MediumOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_EQ(1, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_ClientStateNotExist_MediumZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_EQ(0, GetDwordValue(kAppUserClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+// Machine does not affect user.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       AreAppUsageStatsEnabled_User_MachineOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_FALSE(goopdate_utils::AreAppUsageStatsEnabled(false, kAppGuid));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStatePath, _T("usagestats")));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppUserClientStateMediumPath, _T("usagestats")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStatePath, _T("usagestats")));
+  EXPECT_EQ(1, GetDwordValue(kAppMachineClientStateMediumPath,
+                             _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetUsageStatsEnable_VerifyLegacyLocationNotSet) {
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_TRUE));
+
+  ASSERT_TRUE(RegKey::HasKey(MACHINE_REG_UPDATE));
+  ASSERT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE,
+                                kLegacyRegValueCollectUsageStats));
+  ASSERT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetUsageStatsEnable_Machine_Off) {
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_FALSE));
+
+  ASSERT_TRUE(RegKey::HasKey(kAppMachineClientStatePath));
+  ASSERT_TRUE(RegKey::HasValue(kAppMachineClientStatePath,
+                               _T("usagestats")));
+  ASSERT_FALSE(RegKey::HasKey(kAppUserClientStatePath));
+
+  DWORD enable_value = 1;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(0, enable_value);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetUsageStatsEnable_User_Off) {
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(false, kAppGuid, TRISTATE_FALSE));
+
+  ASSERT_TRUE(RegKey::HasKey(kAppUserClientStatePath));
+  ASSERT_TRUE(RegKey::HasValue(kAppUserClientStatePath,
+                               _T("usagestats")));
+  ASSERT_FALSE(RegKey::HasKey(kAppMachineClientStatePath));
+
+  DWORD enable_value = 1;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(0, enable_value);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetUsageStatsEnable_Machine_On) {
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_TRUE));
+
+  ASSERT_TRUE(RegKey::HasKey(kAppMachineClientStatePath));
+  ASSERT_TRUE(RegKey::HasValue(kAppMachineClientStatePath,
+                               _T("usagestats")));
+  ASSERT_FALSE(RegKey::HasKey(kAppUserClientStatePath));
+
+  DWORD enable_value = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(1, enable_value);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetUsageStatsEnable_User_On) {
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(false, kAppGuid, TRISTATE_TRUE));
+
+  ASSERT_TRUE(RegKey::HasKey(kAppUserClientStatePath));
+  ASSERT_TRUE(RegKey::HasValue(kAppUserClientStatePath,
+                               _T("usagestats")));
+  ASSERT_FALSE(RegKey::HasKey(kAppMachineClientStatePath));
+
+  DWORD enable_value = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(1, enable_value);
+}
+
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetUsageStatsEnable_Machine_None) {
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_NONE));
+  ASSERT_FALSE(RegKey::HasKey(MACHINE_REG_UPDATE));
+  ASSERT_FALSE(RegKey::HasKey(USER_REG_UPDATE));
+
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(false, kAppGuid, TRISTATE_NONE));
+  ASSERT_FALSE(RegKey::HasKey(USER_REG_UPDATE));
+  ASSERT_FALSE(RegKey::HasKey(MACHINE_REG_UPDATE));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetUsageStatsEnable_Machine_Overwrite) {
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_FALSE));
+
+  ASSERT_TRUE(RegKey::HasKey(kAppMachineClientStatePath));
+  ASSERT_TRUE(RegKey::HasValue(kAppMachineClientStatePath,
+                               _T("usagestats")));
+  ASSERT_FALSE(RegKey::HasKey(kAppUserClientStatePath));
+
+  DWORD enable_value = 1;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(0, enable_value);
+
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_TRUE));
+
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(1, enable_value);
+
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_FALSE));
+
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(0, enable_value);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetUsageStatsEnable_Machine_NoneDoesNotOverwrite) {
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_FALSE));
+
+  ASSERT_TRUE(RegKey::HasKey(kAppMachineClientStatePath));
+  ASSERT_TRUE(RegKey::HasValue(kAppMachineClientStatePath,
+                               _T("usagestats")));
+  ASSERT_FALSE(RegKey::HasKey(kAppUserClientStatePath));
+
+  DWORD enable_value = 1;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(0, enable_value);
+
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_NONE));
+
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(0, enable_value);
+
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_TRUE));
+
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(1, enable_value);
+
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_NONE));
+
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(1, enable_value);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetUsageStatsEnable_Machine_ClientStateMediumCleared) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_TRUE));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_FALSE));
+  EXPECT_FALSE(
+      RegKey::HasValue(kAppMachineClientStateMediumPath, _T("usagestats")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetUsageStatsEnable_Machine_NoneDoesNotClearClientStateMedium) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(true, kAppGuid, TRISTATE_NONE));
+
+  DWORD enable_value = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(1, enable_value);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetUsageStatsEnable_User_ClientStateMediumNotCleared) {
+  // User and machine values should not be cleared.
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(0)));
+
+  // True does not clear them.
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(false, kAppGuid, TRISTATE_TRUE));
+  DWORD enable_value = 1;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(0, enable_value);
+  enable_value = 1;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(0, enable_value);
+
+  // False does not clear them.
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetUsageStatsEnable(false, kAppGuid, TRISTATE_FALSE));
+  enable_value = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStateMediumPath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(1, enable_value);
+  enable_value = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStateMediumPath,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(1, enable_value);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, ConvertLegacyUsageStats_NotPresent) {
+  EXPECT_SUCCEEDED(goopdate_utils::ConvertLegacyUsageStats(true));
+  ASSERT_FALSE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, ConvertLegacyUsageStats_Present) {
+  DWORD val = 1;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kLegacyRegValueCollectUsageStats,
+                                    val));
+
+  EXPECT_SUCCEEDED(goopdate_utils::ConvertLegacyUsageStats(true));
+
+  ASSERT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));
+  ASSERT_TRUE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                               _T("usagestats")));
+
+  DWORD enable_value = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("usagestats"),
+                                    &enable_value));
+  EXPECT_EQ(1, enable_value);
+
+  ASSERT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE,
+                               kLegacyRegValueCollectUsageStats));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, GetClientsStringValueFromRegistry) {
+  CString value;
+
+  // Test IsMachine = true
+  const TCHAR* dummy_machine_clients_key = MACHINE_REG_CLIENTS DUMMY_CLSID;
+
+  ASSERT_FALSE(RegKey::HasKey(dummy_machine_clients_key));
+  EXPECT_FAILED(goopdate_utils::GetClientsStringValueFromRegistry(
+                                    true, DUMMY_CLSID, _T("name"), &value));
+  ASSERT_SUCCEEDED(RegKey::DeleteKey(dummy_machine_clients_key));
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(dummy_machine_clients_key,
+                                    _T("name"),
+                                    _T("dummy")));
+  EXPECT_SUCCEEDED(goopdate_utils::GetClientsStringValueFromRegistry(
+                                      true, DUMMY_CLSID, _T("name"), &value));
+  EXPECT_EQ(_T("dummy"), value);
+
+  // Test IsMachine = false
+  const TCHAR* dummy_user_clients_key = USER_REG_CLIENTS DUMMY_CLSID;
+
+  ASSERT_FALSE(RegKey::HasKey(dummy_user_clients_key));
+  EXPECT_FAILED(goopdate_utils::GetClientsStringValueFromRegistry(
+                                   false, DUMMY_CLSID, _T("name"), &value));
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(dummy_user_clients_key,
+                                    _T("name"),
+                                    _T("dummy2")));
+  EXPECT_SUCCEEDED(goopdate_utils::GetClientsStringValueFromRegistry(
+                                      false, DUMMY_CLSID, _T("name"), &value));
+  EXPECT_EQ(_T("dummy2"), value);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, GetVerFromRegistry) {
+  CString version;
+
+  // Test IsMachine = true
+  const TCHAR* dummy_machine_clients_key = MACHINE_REG_CLIENTS DUMMY_CLSID;
+
+  ASSERT_FALSE(RegKey::HasKey(dummy_machine_clients_key));
+  EXPECT_FAILED(goopdate_utils::GetVerFromRegistry(true,
+                                                   DUMMY_CLSID,
+                                                   &version));
+  ASSERT_SUCCEEDED(RegKey::DeleteKey(dummy_machine_clients_key));
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(dummy_machine_clients_key,
+                                    _T("pv"),
+                                    _T("1.0.101.0")));
+  EXPECT_SUCCEEDED(goopdate_utils::GetVerFromRegistry(true,
+                                                      DUMMY_CLSID,
+                                                      &version));
+  EXPECT_EQ(_T("1.0.101.0"), version);
+
+  // Test IsMachine = false
+  const TCHAR* dummy_user_clients_key = USER_REG_CLIENTS DUMMY_CLSID;
+
+  ASSERT_FALSE(RegKey::HasKey(dummy_user_clients_key));
+  EXPECT_FAILED(goopdate_utils::GetVerFromRegistry(false,
+                                                   DUMMY_CLSID,
+                                                   &version));
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(dummy_user_clients_key,
+                                    _T("pv"),
+                                    _T("1.0.102.0")));
+  EXPECT_SUCCEEDED(goopdate_utils::GetVerFromRegistry(false,
+                                                      DUMMY_CLSID,
+                                                      &version));
+  EXPECT_EQ(_T("1.0.102.0"), version);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       BuildHttpGetString_MachineNoTestSource) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(
+                       MACHINE_REG_UPDATE,
+                       kRegValueMachineId,
+                       _T("{39980C99-CDD5-43A0-93C7-69D90C124729}")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(
+                       MACHINE_REG_UPDATE,
+                       kRegValueUserId,
+                       _T("{75521B9F-3EA4-49E8-BC61-E6BDCFEDF6F6}")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(
+                       MACHINE_REG_CLIENT_STATE APP_GUID,
+                       kRegValueInstallationId,
+                       _T("{0F973A20-C484-462b-952C-5D9A459E3326}")));
+
+  CString expected_str_before_os(
+      _T("http://www.google.com/hello.py?code=123&")
+      _T("hl=en&errorcode=0x0000000a&extracode1=0x00000016&extracode2=0&")
+      _T("app=%7BB7BAF788-9D64-49c3-AFDC-B336AB12F332%7D&")
+      _T("guver=1.0.51.0&ismachine=1&os="));
+  CString expected_str_after_os(
+      _T("&mid=%7B39980C99-CDD5-43A0-93C7-69D90C124729%7D")
+      _T("&uid=%7B75521B9F-3EA4-49E8-BC61-E6BDCFEDF6F6%7D")
+      _T("&iid=%7B0F973A20-C484-462b-952C-5D9A459E3326%7D&source=click"));
+  bool expected_test_source = false;
+
+#if defined(DEBUG) || !OFFICIAL_BUILD
+  // TestSource is always set for these builds. It may be set for opt official
+  // builds but this is not guaranteed.
+  expected_str_after_os.Append(_T("&testsource="));
+  expected_test_source = true;
+#endif
+
+  CString url_req;
+  EXPECT_SUCCEEDED(goopdate_utils::BuildHttpGetString(
+      _T("http://www.google.com/hello.py?code=123&"),
+      10,
+      22,
+      0,
+      APP_GUID,
+      _T("1.0.51.0"),
+      true,
+      _T("en"),
+      _T("click"),
+      &url_req));
+  EXPECT_LE(expected_str_before_os.GetLength(), url_req.GetLength());
+  EXPECT_EQ(0, url_req.Find(expected_str_before_os));
+
+  int os_fragment_len = 0;
+  EXPECT_EQ(expected_str_before_os.GetLength(),
+            VerifyOSInUrl(url_req, &os_fragment_len));
+
+  EXPECT_EQ(expected_str_before_os.GetLength() + os_fragment_len,
+            url_req.Find(expected_str_after_os));
+
+  if (expected_test_source) {
+    CString expected_testsource_str =
+        ConfigManager::Instance()->GetTestSource();
+    int expected_testsource_start = expected_str_before_os.GetLength() +
+                                    os_fragment_len +
+                                    expected_str_after_os.GetLength();
+    EXPECT_EQ(expected_testsource_start, url_req.Find(expected_testsource_str));
+    EXPECT_EQ(expected_testsource_start + expected_testsource_str.GetLength(),
+              url_req.GetLength());
+  } else {
+    EXPECT_EQ(expected_str_before_os.GetLength() +
+              os_fragment_len +
+              expected_str_after_os.GetLength(),
+              url_req.GetLength());
+
+    EXPECT_EQ(-1, url_req.Find(_T("testsource")));
+  }
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       BuildHttpGetString_UserWithTestSource) {
+  #define APP_GUID _T("{B7BAF788-9D64-49c3-AFDC-B336AB12F332}")
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(
+                       MACHINE_REG_UPDATE,
+                       kRegValueMachineId,
+                       _T("{39980C99-CDD5-43A0-93C7-69D90C124729}")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(
+                       USER_REG_UPDATE,
+                       kRegValueUserId,
+                       _T("{75521B9F-3EA4-49E8-BC61-E6BDCFEDF6F6}")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(
+                       USER_REG_CLIENT_STATE APP_GUID,
+                       kRegValueInstallationId,
+                       _T("{0F973A20-C484-462b-952C-5D9A459E3326}")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueTestSource,
+                                    _T("dev")));
+
+  const CString expected_str_before_os(
+      _T("http://www.google.com/hello.py?")
+      _T("hl=de&errorcode=0xffffffff&extracode1=0x00000000&extracode2=99&")
+      _T("app=%7BB7BAF788-9D64-49c3-AFDC-B336AB12F332%7D&")
+      _T("guver=foo%20bar&ismachine=0&os="));
+  const CString expected_str_after_os(
+      _T("&mid=%7B39980C99-CDD5-43A0-93C7-69D90C124729%7D")
+      _T("&uid=%7B75521B9F-3EA4-49E8-BC61-E6BDCFEDF6F6%7D")
+      _T("&iid=%7B0F973A20-C484-462b-952C-5D9A459E3326%7D&source=clack")
+      _T("&testsource="));
+
+  CString url_req;
+  EXPECT_SUCCEEDED(goopdate_utils::BuildHttpGetString(
+      _T("http://www.google.com/hello.py?"),
+      0xffffffff,
+      0,
+      99,
+      APP_GUID,
+      _T("foo bar"),
+      false,
+      _T("de"),
+      _T("clack"),
+      &url_req));
+  EXPECT_LE(expected_str_before_os.GetLength(), url_req.GetLength());
+  EXPECT_EQ(0, url_req.Find(expected_str_before_os));
+
+  int os_fragment_len = 0;
+  EXPECT_EQ(expected_str_before_os.GetLength(),
+            VerifyOSInUrl(url_req, &os_fragment_len));
+
+  EXPECT_EQ(expected_str_before_os.GetLength() + os_fragment_len,
+            url_req.Find(expected_str_after_os));
+
+  const CString expected_testsource_str = _T("dev");
+
+  int expected_testsource_start = expected_str_before_os.GetLength() +
+                                  os_fragment_len +
+                                  expected_str_after_os.GetLength();
+  EXPECT_EQ(expected_testsource_start, url_req.Find(expected_testsource_str));
+  EXPECT_EQ(expected_testsource_start + expected_testsource_str.GetLength(),
+            url_req.GetLength());
+}
+
+// MID and UID automatically get generated when they are read, so it is not
+// possible for them to be empty. IID is emtpy if not present.
+TEST_F(GoopdateUtilsRegistryProtectedTest, BuildHttpGetString_NoMidUidIid) {
+  CString url_req;
+  EXPECT_SUCCEEDED(goopdate_utils::BuildHttpGetString(
+      _T("http://www.google.com/hello.py?"),
+      0xffffffff,
+      0,
+      99,
+      _T("{B7BAF788-9D64-49c3-AFDC-B336AB12F332}"),
+      _T("foo bar"),
+      true,
+      _T("en"),
+      _T("cluck"),
+      &url_req));
+
+  // Check for the GUID brackets and end of string as appropriate.
+  EXPECT_NE(-1, url_req.Find(_T("&mid=%7B")));
+  EXPECT_NE(-1, url_req.Find(_T("%7D&uid=%7B")));
+
+  CString expected_test_src;
+#if defined(DEBUG) || !OFFICIAL_BUILD
+  expected_test_src = _T("&testsource=auto");
+#endif
+  const CString expected_iid_str(_T("%7D&iid=&source=cluck"));
+  EXPECT_EQ(url_req.GetLength() -
+            expected_iid_str.GetLength() -
+            expected_test_src.GetLength(),
+            url_req.Find(expected_iid_str));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, GetNumClients) {
+  size_t num_clients(0);
+
+  // Fails when no "Clients" key.
+  EXPECT_HRESULT_FAILED(GetNumClients(true, &num_clients));
+  EXPECT_HRESULT_FAILED(GetNumClients(false, &num_clients));
+
+  // Tests no subkeys.
+  const TCHAR* keys_to_create[] = { MACHINE_REG_CLIENTS, USER_REG_CLIENTS };
+  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKeys(keys_to_create,
+                                              arraysize(keys_to_create)));
+  EXPECT_HRESULT_SUCCEEDED(GetNumClients(true, &num_clients));
+  EXPECT_EQ(0, num_clients);
+  EXPECT_HRESULT_SUCCEEDED(GetNumClients(false, &num_clients));
+  EXPECT_EQ(0, num_clients);
+
+  // Subkeys should be counted. Values should not be counted.
+  RegKey machine_key;
+  EXPECT_HRESULT_SUCCEEDED(machine_key.Open(HKEY_LOCAL_MACHINE,
+                                            GOOPDATE_REG_RELATIVE_CLIENTS));
+  EXPECT_HRESULT_SUCCEEDED(machine_key.SetValue(_T("name"), _T("value")));
+  EXPECT_HRESULT_SUCCEEDED(GetNumClients(true, &num_clients));
+  EXPECT_EQ(0, num_clients);
+
+  const TCHAR* app_id = _T("{AA5523E3-40C0-4b85-B074-4BBA09559CCD}");
+  EXPECT_HRESULT_SUCCEEDED(machine_key.Create(machine_key.Key(), app_id));
+  EXPECT_HRESULT_SUCCEEDED(GetNumClients(true, &num_clients));
+  EXPECT_EQ(1, num_clients);
+
+  // Tests user scenario.
+  RegKey user_key;
+  EXPECT_HRESULT_SUCCEEDED(user_key.Open(HKEY_CURRENT_USER,
+                                         GOOPDATE_REG_RELATIVE_CLIENTS));
+  EXPECT_HRESULT_SUCCEEDED(user_key.SetValue(_T("name"), _T("value")));
+  EXPECT_HRESULT_SUCCEEDED(GetNumClients(false, &num_clients));
+  EXPECT_EQ(0, num_clients);
+
+  EXPECT_HRESULT_SUCCEEDED(user_key.Create(user_key.Key(), app_id));
+  EXPECT_HRESULT_SUCCEEDED(GetNumClients(false, &num_clients));
+  EXPECT_EQ(1, num_clients);
+}
+
+TEST(GoopdateUtilsTest, BuildInstallDirectory_Machine) {
+  const CPath dir = goopdate_utils::BuildInstallDirectory(true, _T("1.2.3.0"));
+  CString program_files_path;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files_path));
+  EXPECT_STREQ(program_files_path + _T("\\Google\\Update\\1.2.3.0"), dir);
+}
+
+TEST(GoopdateUtilsTest, BuildInstallDirectory_User) {
+  CPath expected_path(GetGoogleUpdateUserPath());
+  expected_path.Append(_T("4.5.6.7"));
+  EXPECT_STREQ(expected_path,
+               goopdate_utils::BuildInstallDirectory(false, _T("4.5.6.7")));
+}
+
+TEST(GoopdateUtilsTest, ConvertBrowserTypeToString) {
+  for (int i = 0; i < BROWSER_MAX; ++i) {
+    CString str_type = goopdate_utils::ConvertBrowserTypeToString(
+        static_cast<BrowserType>(i));
+    BrowserType type = BROWSER_UNKNOWN;
+    ASSERT_HRESULT_SUCCEEDED(
+        goopdate_utils::ConvertStringToBrowserType(str_type, &type));
+    ASSERT_EQ(static_cast<int>(type), i);
+  }
+}
+
+void CompareArgsAndUpdateResponseData(const UpdateResponseData& response_data,
+                                      const CString& app_name,
+                                      const CommandLineExtraArgs& args) {
+  ASSERT_STREQ(GuidToString(response_data.guid()),
+               GuidToString(args.apps[0].app_guid));
+  ASSERT_STREQ(app_name, args.apps[0].app_name);
+  ASSERT_EQ(response_data.needs_admin() == NEEDS_ADMIN_YES ? true : false,
+            args.apps[0].needs_admin);
+  ASSERT_STREQ(response_data.ap(), args.apps[0].ap);
+  ASSERT_STREQ(response_data.tt_token(), args.apps[0].tt_token);
+
+  ASSERT_EQ(GuidToString(response_data.installation_id()),
+            GuidToString(args.installation_id));
+  ASSERT_TRUE(args.brand_code.IsEmpty());
+  ASSERT_TRUE(args.client_id.IsEmpty());
+  ASSERT_TRUE(args.referral_id.IsEmpty());
+  ASSERT_EQ(response_data.browser_type(), args.browser_type);
+  ASSERT_EQ(TRISTATE_NONE, args.usage_stats_enable);
+}
+
+TEST(GoopdateUtilsTest, ConvertResponseDataToExtraArgsRequired) {
+  // These unit tests create an update response and then call the test method,
+  // to create the command line. Next the command line is parsed using the
+  // command line class and the results are validated.
+  UpdateResponseData input;
+  input.set_guid(StringToGuid(_T("{8B59B82E-5543-4807-8590-84BF484AE2F6}")));
+
+  CString unicode_name;
+  ASSERT_TRUE(unicode_name.LoadString(IDS_ESCAPE_TEST));
+  CString encoded_name;
+  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_name,
+                                                            &encoded_name));
+  input.set_app_name(encoded_name);
+  input.set_needs_admin(NEEDS_ADMIN_YES);
+
+  CString extra_args;
+  ASSERT_HRESULT_SUCCEEDED(
+      goopdate_utils::ConvertResponseDataToExtraArgs(input, &extra_args));
+
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  ASSERT_HRESULT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CompareArgsAndUpdateResponseData(input, unicode_name, args);
+}
+
+
+TEST(GoopdateUtilsTest, ConvertResponseDataToExtraArgsAll) {
+  UpdateResponseData input;
+  input.set_guid(StringToGuid(_T("{8B59B82E-5543-4807-8590-84BF484AE2F6}")));
+
+  CString unicode_name;
+  ASSERT_TRUE(unicode_name.LoadString(IDS_ESCAPE_TEST));
+  CString encoded_name;
+  ASSERT_HRESULT_SUCCEEDED(WideStringToUtf8UrlEncodedString(unicode_name,
+                                                            &encoded_name));
+  input.set_app_name(encoded_name);
+  input.set_needs_admin(NEEDS_ADMIN_YES);
+  input.set_installation_id(
+      StringToGuid(_T("{E314A405-FCC5-4ed1-BFA4-CBC22F1873BF}")));
+  input.set_ap(_T("Test_ap"));
+  input.set_tt_token(_T("Test_tt_token"));
+  input.set_browser_type(BROWSER_IE);
+
+  CString extra_args;
+  ASSERT_HRESULT_SUCCEEDED(
+      goopdate_utils::ConvertResponseDataToExtraArgs(input, &extra_args));
+
+  CommandLineExtraArgs args;
+  ExtraArgsParser parser;
+  ASSERT_HRESULT_SUCCEEDED(parser.Parse(extra_args, NULL, &args));
+
+  CompareArgsAndUpdateResponseData(input, unicode_name, args);
+}
+
+TEST(GoopdateUtilsTest, UniqueEventInEnvironment_User) {
+  const TCHAR* kEnvVarName = _T("SOME_ENV_VAR_FOR_TEST");
+  scoped_event created_event;
+  scoped_event opened_event;
+
+  ASSERT_HRESULT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(
+      kEnvVarName,
+      false,
+      address(created_event)));
+  ASSERT_TRUE(created_event);
+  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(created_event), 0));
+
+  TCHAR event_name[MAX_PATH] = {0};
+  EXPECT_TRUE(
+      ::GetEnvironmentVariable(kEnvVarName, event_name, arraysize(event_name)));
+
+  ASSERT_HRESULT_SUCCEEDED(goopdate_utils::OpenUniqueEventFromEnvironment(
+      kEnvVarName,
+      false,
+      address(opened_event)));
+  ASSERT_TRUE(opened_event);
+
+  EXPECT_TRUE(::SetEvent(get(opened_event)));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(created_event), 0));
+
+  EXPECT_TRUE(::SetEnvironmentVariable(kEnvVarName, NULL));
+}
+
+TEST(GoopdateUtilsTest, UniqueEventInEnvironment_Machine) {
+  const TCHAR* kEnvVarName = _T("OTHER_ENV_VAR_FOR_TEST");
+  scoped_event created_event;
+  scoped_event opened_event;
+  TCHAR event_name[MAX_PATH] = {0};
+
+  if (!vista_util::IsUserAdmin()) {
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INVALID_OWNER),
+              goopdate_utils::CreateUniqueEventInEnvironment(
+                  kEnvVarName,
+                  true,
+                  address(created_event)));
+    EXPECT_FALSE(created_event);
+
+    EXPECT_FALSE(::GetEnvironmentVariable(kEnvVarName,
+                                          event_name,
+                                          arraysize(event_name)));
+    return;
+  }
+
+  ASSERT_HRESULT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(
+      kEnvVarName,
+      true,
+      address(created_event)));
+  ASSERT_TRUE(created_event);
+  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(created_event), 0));
+
+  EXPECT_TRUE(
+      ::GetEnvironmentVariable(kEnvVarName, event_name, arraysize(event_name)));
+
+  ASSERT_HRESULT_SUCCEEDED(goopdate_utils::OpenUniqueEventFromEnvironment(
+      kEnvVarName,
+      true,
+      address(opened_event)));
+  ASSERT_TRUE(opened_event);
+
+  EXPECT_TRUE(::SetEvent(get(opened_event)));
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(created_event), 0));
+
+  EXPECT_TRUE(::SetEnvironmentVariable(kEnvVarName, NULL));
+}
+
+TEST(GoopdateUtilsTest, UniqueEventInEnvironment_UserMachineMismatch) {
+  const TCHAR* kEnvVarName = _T("ENV_VAR_FOR_MIXED_TEST");
+  scoped_event created_event;
+  scoped_event opened_event;
+
+  ASSERT_HRESULT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(
+      kEnvVarName,
+      false,
+      address(created_event)));
+  ASSERT_TRUE(created_event);
+  EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(created_event), 0));
+
+  TCHAR event_name[MAX_PATH] = {0};
+  EXPECT_TRUE(
+      ::GetEnvironmentVariable(kEnvVarName, event_name, arraysize(event_name)));
+
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            goopdate_utils::OpenUniqueEventFromEnvironment(
+                kEnvVarName,
+                true,
+                address(opened_event)));
+
+  EXPECT_TRUE(::SetEnvironmentVariable(kEnvVarName, NULL));
+}
+
+TEST(GoopdateUtilsTest, OpenUniqueEventFromEnvironment_EnvVarDoesNotExist) {
+  const TCHAR* kEnvVarName = _T("ANOTHER_ENV_VAR_FOR_TEST");
+  scoped_event opened_event;
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND),
+            goopdate_utils::OpenUniqueEventFromEnvironment(
+                kEnvVarName,
+                false,
+                address(opened_event)));
+}
+
+TEST(GoopdateUtilsTest, OpenUniqueEventFromEnvironment_EventDoesNotExist) {
+  const TCHAR* kEnvVarName = _T("YET_ANOTHER_ENV_VAR_FOR_TEST");
+
+  EXPECT_TRUE(::SetEnvironmentVariable(kEnvVarName, _T("foo")));
+
+  scoped_event opened_event;
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+              goopdate_utils::OpenUniqueEventFromEnvironment(
+                  kEnvVarName,
+                  false,
+                  address(opened_event)));
+
+  EXPECT_TRUE(::SetEnvironmentVariable(kEnvVarName, NULL));
+}
+
+
+CString GetTempFile() {
+  TCHAR temp_path[MAX_PATH] = {0};
+  TCHAR temp_file[MAX_PATH] = {0};
+
+  EXPECT_LT(::GetTempPath(arraysize(temp_path), temp_path),
+            arraysize(temp_path));
+  EXPECT_NE(0, ::GetTempFileName(temp_path, _T("ut_"), 0, temp_file));
+  return CString(temp_file);
+}
+
+typedef std::map<CString, CString> StringMap;
+typedef StringMap::const_iterator StringMapIter;
+
+TEST(GoopdateUtilsTest, ReadNameValuePairsFromFileTest_MissingFile) {
+  CString temp_file = GetTempFile();
+  ::DeleteFile(temp_file);
+
+  ASSERT_FALSE(File::Exists(temp_file));
+
+  StringMap pairs_read;
+  ASSERT_FAILED(goopdate_utils::ReadNameValuePairsFromFile(temp_file,
+                                                           _T("my_group"),
+                                                           &pairs_read));
+  ASSERT_EQ(0, pairs_read.size());
+}
+
+TEST(GoopdateUtilsTest, ReadNameValuePairsFromFileTest_ReadEmpty) {
+  CString temp_file = GetTempFile();
+  File file_write;
+  EXPECT_SUCCEEDED(file_write.Open(temp_file, true, false));
+  file_write.Close();
+
+  StringMap pairs_read;
+  ASSERT_SUCCEEDED(goopdate_utils::ReadNameValuePairsFromFile(temp_file,
+                                                              _T("my_group"),
+                                                              &pairs_read));
+  ASSERT_EQ(0, pairs_read.size());
+}
+
+void ValidateStringMapEquality(const StringMap& expected,
+                               const StringMap& actual) {
+  ASSERT_EQ(expected.size(), actual.size());
+
+  StringMapIter it_expected = expected.begin();
+  for (; it_expected != expected.end(); ++it_expected) {
+    StringMapIter it_actual = actual.find(it_expected->first);
+    ASSERT_TRUE(it_actual != actual.end());
+    ASSERT_STREQ(it_expected->second, it_actual->second);
+  }
+}
+
+TEST(GoopdateUtilsTest, ReadNameValuePairsFromFileTest_ReadOnePair) {
+  CString group = _T("my_group");
+
+  StringMap pairs_write;
+  pairs_write[_T("some_name")] = _T("some_value");
+
+  CString temp_file = GetTempFile();
+  ASSERT_SUCCEEDED(goopdate_utils::WriteNameValuePairsToFile(temp_file,
+                                                             group,
+                                                             pairs_write));
+  ASSERT_TRUE(File::Exists(temp_file));
+
+  StringMap pairs_read;
+  ASSERT_SUCCEEDED(goopdate_utils::ReadNameValuePairsFromFile(temp_file,
+                                                              group,
+                                                              &pairs_read));
+
+  ValidateStringMapEquality(pairs_write, pairs_read);
+}
+
+TEST(GoopdateUtilsTest, ReadNameValuePairsFromFileTest_ReadManyPairs) {
+  CString group = _T("my_group");
+
+  StringMap pairs_write;
+  const int kCountPairs = 10;
+  for (int i = 1; i <= kCountPairs; ++i) {
+    CString name;
+    name.Format(_T("name%d"), i);
+    CString value;
+    value.Format(_T("value%d"), i);
+    pairs_write[name] = value;
+  }
+
+  CString temp_file = GetTempFile();
+  ASSERT_SUCCEEDED(goopdate_utils::WriteNameValuePairsToFile(temp_file,
+                                                             group,
+                                                             pairs_write));
+  ASSERT_TRUE(File::Exists(temp_file));
+
+  StringMap pairs_read;
+  ASSERT_SUCCEEDED(goopdate_utils::ReadNameValuePairsFromFile(temp_file,
+                                                              group,
+                                                              &pairs_read));
+
+  ValidateStringMapEquality(pairs_write, pairs_read);
+}
+
+// This test verifies that InstallTime is created afresh for Omaha if it does
+// not exist, and even if the brand code is already set.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetGoogleUpdateBranding_BrandAlreadyExistsAllEmpty) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("EFGH")));
+
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetGoogleUpdateBranding(kAppMachineClientStatePath,
+                                              _T(""),
+                                              _T("")));
+
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("EFGH"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueClientId,
+                             &value));
+  DWORD install_time = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+}
+
+// This test verifies that InstallTime remains unchanged for Omaha if it already
+// exists and the brand code is already set.
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetGoogleUpdateBranding_AllAlreadyExistAllEmpty) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("EFGH")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    _T("existing_partner")));
+  const DWORD kInstallTime = 1234567890;
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    kInstallTime));
+
+  EXPECT_SUCCEEDED(
+      goopdate_utils::SetGoogleUpdateBranding(kAppMachineClientStatePath,
+                                              _T(""),
+                                              _T("")));
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("EFGH"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("existing_partner"), value);
+  EXPECT_EQ(kInstallTime,
+            GetDwordValue(kAppMachineClientStatePath, kRegValueInstallTimeSec));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_KeyDoesNotExist) {
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                           _T("ABCD"),
+                                           _T("some_partner"),
+                                           _T("referrer")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_AllEmpty) {
+  ASSERT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T(""),
+                                                  _T(""),
+                                                  _T("")));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("GGLS"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueClientId,
+                             &value));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD install_time = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_BrandCodeOnly) {
+  ASSERT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T("ABCD"),
+                                                  _T(""),
+                                                  _T("")));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("ABCD"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueClientId,
+                             &value));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD install_time = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_BrandCodeTooLong) {
+  EXPECT_EQ(E_INVALIDARG, goopdate_utils::SetAppBranding(
+                                              kAppMachineClientStatePath,
+                                              _T("CHMGon.href)}"),
+                                              _T(""),
+                                              _T("")));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_ClientIdOnly) {
+  ASSERT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T(""),
+                                                  _T("some_partner"),
+                                                  _T("")));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("GGLS"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("some_partner"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD install_time = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest, SetAppBranding_AllValid) {
+  ASSERT_SUCCEEDED(RegKey::CreateKey(kAppMachineClientStatePath));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T("ABCD"),
+                                                  _T("some_partner"),
+                                                  _T("referrer")));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("ABCD"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("some_partner"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueReferralId,
+                                    &value));
+  EXPECT_STREQ(_T("referrer"), value);
+  DWORD install_time(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_BrandAlreadyExistsAllEmpty) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("EFGH")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T(""),
+                                                  _T(""),
+                                                  _T("")));
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("EFGH"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueClientId,
+                             &value));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD dword_value(0);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueInstallTimeSec,
+                             &dword_value));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_BrandAlreadyExistsBrandCodeOnly) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("EFGH")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T("ABCD"),
+                                                  _T(""),
+                                                  _T("")));
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("EFGH"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueClientId,
+                             &value));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD dword_value(0);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueInstallTimeSec,
+                             &dword_value));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_ExistingBrandTooLong) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("CHMG4CUTNt")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T("ABCD"),
+                                                  _T(""),
+                                                  _T("")));
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("CHMG"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueClientId,
+                             &value));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD dword_value(0);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueInstallTimeSec,
+                             &dword_value));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_BrandAlreadyExistsCliendIdOnly) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("EFGH")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T(""),
+                                                  _T("some_partner"),
+                                                  _T("")));
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("EFGH"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueClientId,
+                             &value));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD dword_value(0);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueInstallTimeSec,
+                             &dword_value));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_BrandAlreadyExistsBothValid) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("EFGH")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T("ABCD"),
+                                                  _T("some_partner"),
+                                                  _T("")));
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("EFGH"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueClientId,
+                             &value));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD dword_value(0);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueInstallTimeSec,
+                             &dword_value));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_ClientIdAlreadyExistsAllEmtpy) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    _T("existing_partner")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T(""),
+                                                  _T(""),
+                                                  _T("")));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("GGLS"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("existing_partner"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD install_time = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_ClientIdAlreadyExistsBrandCodeOnly) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    _T("existing_partner")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T("ABCE"),
+                                                  _T(""),
+                                                  _T("")));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("ABCE"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("existing_partner"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD install_time = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_ClientIdAlreadyExistsCliendIdOnly) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    _T("existing_partner")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T(""),
+                                                  _T("some_partner"),
+                                                  _T("")));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("GGLS"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("some_partner"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD install_time = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_ClientIdAlreadyExistsBothValid) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    _T("existing_partner")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T("ABCD"),
+                                                  _T("some_partner"),
+                                                  _T("")));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("ABCD"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("some_partner"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD install_time = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_AllAlreadyExistAllEmpty) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("EFGH")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    _T("existing_partner")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueReferralId,
+                                    __T("existingreferrerid")));
+  const DWORD kInstallTime = 1234567890;
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    kInstallTime));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T(""),
+                                                  _T(""),
+                                                  _T("")));
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("EFGH"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("existing_partner"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueReferralId,
+                                    &value));
+  EXPECT_STREQ(__T("existingreferrerid"), value);
+  EXPECT_EQ(kInstallTime,
+            GetDwordValue(kAppMachineClientStatePath, kRegValueInstallTimeSec));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_AllAlreadyExistBrandCodeOnly) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("EFGH")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    _T("existing_partner")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueReferralId,
+                                    __T("existingreferrerid")));
+  const DWORD kInstallTime = 1234567890;
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    kInstallTime));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T("ABCD"),
+                                                  _T(""),
+                                                  _T("")));
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("EFGH"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("existing_partner"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueReferralId,
+                                    &value));
+  EXPECT_STREQ(__T("existingreferrerid"), value);
+  EXPECT_EQ(kInstallTime,
+            GetDwordValue(kAppMachineClientStatePath, kRegValueInstallTimeSec));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_BothAlreadyExistCliendIdOnly) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("EFGH")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    _T("existing_partner")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueReferralId,
+                                    __T("existingreferrerid")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T(""),
+                                                  _T("some_partner"),
+                                                  _T("")));
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("EFGH"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("existing_partner"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueReferralId,
+                                    &value));
+  EXPECT_STREQ(__T("existingreferrerid"), value);
+  DWORD dword_value(0);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueInstallTimeSec,
+                             &dword_value));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_BothAlreadyExistBothValid) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    _T("EFGH")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    _T("existing_partner")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueReferralId,
+                                    _T("existingreferrerid")));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T("ABCD"),
+                                                  _T("some_partner"),
+                                                  _T("")));
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("EFGH"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueClientId,
+                                    &value));
+  EXPECT_STREQ(_T("existing_partner"), value);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueReferralId,
+                                    &value));
+  EXPECT_STREQ(_T("existingreferrerid"), value);
+  DWORD dword_value(0);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueInstallTimeSec,
+                             &dword_value));
+}
+
+TEST_F(GoopdateUtilsRegistryProtectedTest,
+       SetAppBranding_InstallTimeAlreadyExistsBrandCodeOnly) {
+  const DWORD kExistingInstallTime = 1234567890;
+  ASSERT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    kExistingInstallTime));
+
+  EXPECT_SUCCEEDED(goopdate_utils::SetAppBranding(kAppMachineClientStatePath,
+                                                  _T("ABCE"),
+                                                  _T(""),
+                                                  _T("")));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueBrandCode,
+                                    &value));
+  EXPECT_STREQ(_T("ABCE"), value);
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueClientId,
+                             &value));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            RegKey::GetValue(kAppMachineClientStatePath,
+                             kRegValueReferralId,
+                             &value));
+  DWORD install_time = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                                    kRegValueInstallTimeSec,
+                                    &install_time));
+  EXPECT_NE(kExistingInstallTime, install_time);
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+}
+
+//
+// IsMachineProcess tests.
+//
+
+class GoopdateUtilsIsMachineProcessTest : public testing::Test {
+ protected:
+  bool FromMachineDirHelper(CommandLineMode mode) {
+    return goopdate_utils::IsMachineProcess(mode,
+                                            true,
+                                            false,
+                                            false,
+                                            TRISTATE_NONE);
+  }
+
+  bool IsLocalSystemHelper(CommandLineMode mode) {
+    return goopdate_utils::IsMachineProcess(mode,
+                                            false,
+                                            true,
+                                            false,
+                                            TRISTATE_NONE);
+  }
+
+  bool MachineOverrideHelper(CommandLineMode mode) {
+    return goopdate_utils::IsMachineProcess(mode,
+                                            false,
+                                            false,
+                                            true,
+                                            TRISTATE_NONE);
+  }
+
+  bool NeedsAdminFalseHelper(CommandLineMode mode) {
+    return goopdate_utils::IsMachineProcess(mode,
+                                            false,
+                                            false,
+                                            false,
+                                            TRISTATE_FALSE);
+  }
+
+  bool NeedsAdminTrueHelper(CommandLineMode mode) {
+    return goopdate_utils::IsMachineProcess(mode,
+                                            false,
+                                            false,
+                                            false,
+                                            TRISTATE_TRUE);
+  }
+};
+
+TEST_F(GoopdateUtilsIsMachineProcessTest,
+       IsMachineProcess_MachineDirOnly) {
+  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_UNKNOWN));
+  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_NOARGS));
+  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_CORE));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_SERVICE));
+  }
+  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_REGSERVER));
+  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_UNREGSERVER));
+  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_NETDIAGS));
+  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_CRASH));
+  // TODO(omaha): Change to machine.
+  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_REPORTCRASH));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_INSTALL));
+  }
+  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_UPDATE));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_IG));
+    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_HANDOFF_INSTALL));
+  }
+  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_UG));
+  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_UA));
+  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_RECOVER));
+  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_WEBPLUGIN));
+  EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_CODE_RED_CHECK));
+  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_COMSERVER));
+  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_LEGACYUI));
+  EXPECT_TRUE(FromMachineDirHelper(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_REGISTER_PRODUCT));
+  }
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(FromMachineDirHelper(COMMANDLINE_MODE_UNREGISTER_PRODUCT));
+  }
+  EXPECT_TRUE(FromMachineDirHelper(
+      static_cast<CommandLineMode>(
+          COMMANDLINE_MODE_CRASH_HANDLER + 1)));
+}
+
+TEST_F(GoopdateUtilsIsMachineProcessTest,
+       IsMachineProcess_IsLocalSystemOnly) {
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_UNKNOWN));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_NOARGS));
+  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_CORE));
+  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_SERVICE));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_REGSERVER));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_UNREGSERVER));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_NETDIAGS));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_CRASH));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_REPORTCRASH));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_INSTALL));
+  }
+  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_UPDATE));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_IG));
+    EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_HANDOFF_INSTALL));
+  }
+  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_UG));
+  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_UA));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_RECOVER));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_WEBPLUGIN));
+  EXPECT_TRUE(IsLocalSystemHelper(COMMANDLINE_MODE_CODE_RED_CHECK));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_COMSERVER));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_LEGACYUI));
+  EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_REGISTER_PRODUCT));
+  }
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(IsLocalSystemHelper(COMMANDLINE_MODE_UNREGISTER_PRODUCT));
+  }
+  EXPECT_FALSE(IsLocalSystemHelper(
+      static_cast<CommandLineMode>(
+          COMMANDLINE_MODE_CRASH_HANDLER + 1)));
+}
+
+TEST_F(GoopdateUtilsIsMachineProcessTest,
+       IsMachineProcess_MachineOverrideOnly) {
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_UNKNOWN));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_NOARGS));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_CORE));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_SERVICE));
+  }
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_REGSERVER));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_UNREGSERVER));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_NETDIAGS));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_CRASH));
+  EXPECT_TRUE(MachineOverrideHelper(COMMANDLINE_MODE_REPORTCRASH));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_INSTALL));
+  }
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_UPDATE));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_IG));
+    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_HANDOFF_INSTALL));
+  }
+  EXPECT_TRUE(MachineOverrideHelper(COMMANDLINE_MODE_UG));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_UA));
+  EXPECT_TRUE(MachineOverrideHelper(COMMANDLINE_MODE_RECOVER));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_WEBPLUGIN));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_CODE_RED_CHECK));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_COMSERVER));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_LEGACYUI));
+  EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_REGISTER_PRODUCT));
+  }
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(MachineOverrideHelper(COMMANDLINE_MODE_UNREGISTER_PRODUCT));
+  }
+  EXPECT_FALSE(MachineOverrideHelper(
+      static_cast<CommandLineMode>(
+          COMMANDLINE_MODE_CRASH_HANDLER + 1)));
+}
+
+TEST_F(GoopdateUtilsIsMachineProcessTest,
+       IsMachineProcess_NeedsAdminFalseOnly) {
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UNKNOWN));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_NOARGS));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_CORE));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_SERVICE));
+  }
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_REGSERVER));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UNREGSERVER));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_NETDIAGS));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_CRASH));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_REPORTCRASH));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_INSTALL));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UPDATE));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_IG));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_HANDOFF_INSTALL));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UG));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UA));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_RECOVER));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_WEBPLUGIN));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_CODE_RED_CHECK));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_COMSERVER));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_LEGACYUI));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_REGISTER_PRODUCT));
+  EXPECT_FALSE(NeedsAdminFalseHelper(COMMANDLINE_MODE_UNREGISTER_PRODUCT));
+  EXPECT_FALSE(NeedsAdminFalseHelper(
+      static_cast<CommandLineMode>(
+          COMMANDLINE_MODE_CRASH_HANDLER + 1)));
+}
+
+TEST_F(GoopdateUtilsIsMachineProcessTest,
+       IsMachineProcess_NeedsAdminTrueOnly) {
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UNKNOWN));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_NOARGS));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_CORE));
+  {
+    ExpectAsserts expect_asserts;
+    EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_SERVICE));
+  }
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_REGSERVER));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UNREGSERVER));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_NETDIAGS));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_CRASH));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_REPORTCRASH));
+  EXPECT_TRUE(NeedsAdminTrueHelper(COMMANDLINE_MODE_INSTALL));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UPDATE));
+  EXPECT_TRUE(NeedsAdminTrueHelper(COMMANDLINE_MODE_IG));
+  EXPECT_TRUE(NeedsAdminTrueHelper(COMMANDLINE_MODE_HANDOFF_INSTALL));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UG));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UA));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_RECOVER));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_WEBPLUGIN));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_CODE_RED_CHECK));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_COMSERVER));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_LEGACYUI));
+  EXPECT_FALSE(NeedsAdminTrueHelper(COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF));
+  EXPECT_TRUE(NeedsAdminTrueHelper(COMMANDLINE_MODE_REGISTER_PRODUCT));
+  EXPECT_TRUE(NeedsAdminTrueHelper(COMMANDLINE_MODE_UNREGISTER_PRODUCT));
+  EXPECT_FALSE(NeedsAdminTrueHelper(
+      static_cast<CommandLineMode>(
+          COMMANDLINE_MODE_CRASH_HANDLER + 1)));
+}
+
+TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_LegacyVersions) {
+  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.0.0.0")));
+  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.103.9")));
+  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.65535.65535")));
+}
+
+TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_Omaha2AndLater) {
+  EXPECT_TRUE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.2.0.0")));
+  EXPECT_TRUE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.2.0111.2222")));
+  EXPECT_TRUE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.3.456.7890")));
+  EXPECT_TRUE(goopdate_utils::IsGoogleUpdate2OrLater(_T("2.0.0.0")));
+}
+
+TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_VersionZero) {
+  ExpectAsserts expect_asserts;
+  EXPECT_FALSE(
+      goopdate_utils::IsGoogleUpdate2OrLater(_T("0.0.0.0")));
+}
+
+TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_VersionUpperLimits) {
+  EXPECT_TRUE(
+      goopdate_utils::IsGoogleUpdate2OrLater(_T("65535.65535.65535.65535")));
+
+  ExpectAsserts expect_asserts;
+  EXPECT_FALSE(
+      goopdate_utils::IsGoogleUpdate2OrLater(_T("65536.65536.65536.65536")));
+  EXPECT_FALSE(
+      goopdate_utils::IsGoogleUpdate2OrLater(_T("1.2.65536.65536")));
+  EXPECT_FALSE(
+      goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.65536.65536")));
+}
+
+TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_TooFewElements) {
+  ExpectAsserts expect_asserts;
+  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.1")));
+}
+
+TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_ExtraPeriod) {
+  ExpectAsserts expect_asserts;
+  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.2.3.")));
+}
+
+TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_TooManyElements) {
+  ExpectAsserts expect_asserts;
+  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.1.2.3.4")));
+}
+
+TEST(GoopdateUtilsTest, IsGoogleUpdate2OrLater_Char) {
+  ExpectAsserts expect_asserts;
+  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.B.3.4")));
+  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.2.3.B")));
+  EXPECT_FALSE(goopdate_utils::IsGoogleUpdate2OrLater(_T("1.2.3.9B")));
+}
+
+TEST(GoopdateUtilsTest, FormatMessageForNetworkError) {
+  const TCHAR* const kTestAppName = _T("Test App");
+  CString message;
+  EXPECT_EQ(true, FormatMessageForNetworkError(GOOPDATE_E_NO_NETWORK,
+                                               kTestAppName,
+                                               &message));
+  EXPECT_STREQ(
+      _T("Installation failed. Ensure that your computer is connected to the ")
+      _T("Internet and that your firewall allows GoogleUpdate.exe to connect ")
+      _T("and then try again. Error code = 0x80040801."),
+      message);
+
+  EXPECT_EQ(true, FormatMessageForNetworkError(GOOPDATE_E_NETWORK_UNAUTHORIZED,
+                                               kTestAppName,
+                                               &message));
+  EXPECT_STREQ(
+      _T("The Test App installer could not connect to the Internet because of ")
+      _T("an HTTP 401 Unauthorized response. This is likely a proxy ")
+      _T("configuration issue.  Please configure the proxy server to allow ")
+      _T("network access and try again or contact your network administrator. ")
+      _T("Error code = 0x80042191"),
+      message);
+
+  EXPECT_EQ(true, FormatMessageForNetworkError(GOOPDATE_E_NETWORK_FORBIDDEN,
+                                               kTestAppName,
+                                               &message));
+  EXPECT_STREQ(
+      _T("The Test App installer could not connect to the Internet because of ")
+      _T("an HTTP 403 Forbidden response. This is likely a proxy ")
+      _T("configuration issue.  Please configure the proxy server to allow ")
+      _T("network access and try again or contact your network administrator. ")
+      _T("Error code = 0x80042193"),
+      message);
+
+  EXPECT_EQ(true,
+            FormatMessageForNetworkError(GOOPDATE_E_NETWORK_PROXYAUTHREQUIRED,
+                                         kTestAppName,
+                                         &message));
+  EXPECT_STREQ(
+      _T("The Test App installer could not connect to the Internet because a ")
+      _T("proxy server required user authentication. Please configure the ")
+      _T("proxy server to allow network access and try again or contact your ")
+      _T("network administrator. Error code = 0x80042197"),
+      message);
+
+  EXPECT_EQ(false, FormatMessageForNetworkError(E_FAIL,
+                                                kTestAppName,
+                                                &message));
+  EXPECT_STREQ(
+      _T("Installation failed. Ensure that your computer is connected to the ")
+      _T("Internet and that your firewall allows GoogleUpdate.exe to connect ")
+      _T("and then try again. Error code = 0x80004005."),
+      message);
+}
+
+TEST(GoopdateUtilsTest, WriteInstallerDataToTempFile) {
+  CStringA utf8_bom;
+  utf8_bom.Format("%c%c%c", 0xEF, 0xBB, 0xBF);
+
+  std::vector<CString> list_installer_data;
+
+  list_installer_data.push_back(_T(""));
+  list_installer_data.push_back(_T("hello\n"));
+  list_installer_data.push_back(_T("good bye"));
+  list_installer_data.push_back(_T("  there  you\n     go "));
+  list_installer_data.push_back(_T("\"http://foo.bar.org/?q=stuff&h=other\""));
+  list_installer_data.push_back(_T("foo\r\nbar\n"));
+  list_installer_data.push_back(_T("foo\n\rbar"));    // LFCR is not recognized.
+
+  std::vector<CStringA> expected_installer_data;
+  expected_installer_data.push_back("");
+  expected_installer_data.push_back("hello\n");
+  expected_installer_data.push_back("good bye");
+  expected_installer_data.push_back("  there  you\n     go ");
+  expected_installer_data.push_back("\"http://foo.bar.org/?q=stuff&h=other\"");
+  expected_installer_data.push_back("foo\r\nbar\n");
+  expected_installer_data.push_back("foo\n\rbar");
+
+  ASSERT_EQ(expected_installer_data.size(), list_installer_data.size());
+
+  for (size_t i = 0; i < list_installer_data.size(); ++i) {
+    CString installer_data = list_installer_data[i];
+    SCOPED_TRACE(installer_data);
+
+    CString file_path;
+    HRESULT hr = goopdate_utils::WriteInstallerDataToTempFile(
+        installer_data,
+        &file_path);
+    EXPECT_SUCCEEDED(hr);
+
+    // TODO(omaha): consider eliminating the special case.
+    // WriteInstallerDataToTempFile() will return S_FALSE with "" data.
+    if (S_OK == hr) {
+      File file;
+      const int kBufferLen = 1000;
+      std::vector<byte> data_line(kBufferLen);
+      EXPECT_SUCCEEDED(file.Open(file_path, false, false));
+      uint32 bytes_read(0);
+      EXPECT_SUCCEEDED(file.Read(data_line.size(),
+                                 &data_line.front(),
+                                 &bytes_read));
+      data_line.resize(bytes_read);
+      data_line.push_back(0);
+      EXPECT_STREQ(utf8_bom + expected_installer_data[i],
+                   reinterpret_cast<const char*>(&data_line.front()));
+      EXPECT_SUCCEEDED(file.Close());
+    } else {
+      EXPECT_TRUE(installer_data.IsEmpty());
+    }
+  }
+}
+
+TEST(GoopdateUtilsTest, GetDefaultGoopdateTaskName_Core_Machine) {
+  CString expected_task_name(kScheduledTaskNameMachinePrefix);
+  expected_task_name += kScheduledTaskNameCoreSuffix;
+
+  EXPECT_STREQ(
+      expected_task_name,
+      goopdate_utils::GetDefaultGoopdateTaskName(true, COMMANDLINE_MODE_CORE));
+}
+
+TEST(GoopdateUtilsTest, GetDefaultGoopdateTaskName_Core_User) {
+  CString expected_task_name_user = kScheduledTaskNameUserPrefix;
+  CString user_sid;
+  EXPECT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid));
+  expected_task_name_user += user_sid;
+  expected_task_name_user += kScheduledTaskNameCoreSuffix;
+  EXPECT_STREQ(
+      expected_task_name_user,
+      goopdate_utils::GetDefaultGoopdateTaskName(false, COMMANDLINE_MODE_CORE));
+}
+
+TEST(GoopdateUtilsTest, GetDefaultGoopdateTaskName_UA_Machine) {
+  CString expected_task_name(kScheduledTaskNameMachinePrefix);
+  expected_task_name += kScheduledTaskNameUASuffix;
+
+  EXPECT_STREQ(
+      expected_task_name,
+      goopdate_utils::GetDefaultGoopdateTaskName(true, COMMANDLINE_MODE_UA));
+}
+
+TEST(GoopdateUtilsTest, GetDefaultGoopdateTaskName_UA_User) {
+  CString expected_task_name_user = kScheduledTaskNameUserPrefix;
+  CString user_sid;
+  EXPECT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid));
+  expected_task_name_user += user_sid;
+  expected_task_name_user += kScheduledTaskNameUASuffix;
+  EXPECT_STREQ(
+      expected_task_name_user,
+      goopdate_utils::GetDefaultGoopdateTaskName(false, COMMANDLINE_MODE_UA));
+}
+
+}  // namespace goopdate_utils
+
+}  // namespace omaha
+
diff --git a/goopdate/goopdate_version.rc b/goopdate/goopdate_version.rc
index 5204869..a119018 100644
--- a/goopdate/goopdate_version.rc
+++ b/goopdate/goopdate_version.rc
@@ -1,75 +1,75 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <afxres.h>

-

-// TODO(omaha): using this as a common resource for the activex/nsplugin as

-// well as goopdate. Need to clean this up a bit.

-// For example, I've changed the FILEFLAGSMASK to 0x3FL (which appears to be

-// "standard" at least amongst plugins), not sure why it's 0x17L in here.

-// Also, the "040904e4" (for codepage 1252 Ansi Latin) is required for

-// the netscape plugin stuff to see the MIMETYPE value in the resource block.

-// However, this resource file WAS using "040904B0" (codepage 1200 which is

-// unicode little endian).  Not sure why we're using that or if we really

-// need it to be that value.

-

-// TODO(omaha): FileDescription is what shows up in "about:plugins" for

-// Mozilla. Format the description to include the url of the project.

-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

-

-VS_VERSION_INFO VERSIONINFO

- FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

-// FILEFLAGSMASK 0x17L

- FILEFLAGSMASK 0x3FL

-// #ifdef _DEBUG

-// FILEFLAGS 0x1L

-//#else

- FILEFLAGS 0x0L

-//#endif

- FILEOS 0x4L

- FILETYPE 0x0L

- FILESUBTYPE 0x0L

-BEGIN

-    BLOCK "StringFileInfo"

-    BEGIN

-        BLOCK "040904e4"

-        BEGIN

-            VALUE "CompanyName", "Google Inc."

-            VALUE "FileDescription", "Google Update"

-            VALUE "FileVersion", VERSION_NUMBER_STRING

-            VALUE "InternalName", "Google Update"

-            VALUE "LegalCopyright", "Copyright 2007-2009 Google Inc."

-            VALUE "OriginalFilename", "GoogleUpdate"

-            VALUE "ProductName", "Google Update"

-            VALUE "ProductVersion", VERSION_NUMBER_STRING

-#ifdef _DEBUG

-            VALUE "Debug", ""

-#endif

-#if !OFFICIAL_BUILD

-            VALUE "Privatebuild", ""

-#endif

-

-    #ifdef MIME_TYPE

-            VALUE "MIMEType",         MIME_TYPE

-    #endif

-

-        END

-    END

-    BLOCK "VarFileInfo"

-    BEGIN

-        VALUE "Translation", 0x409, 1252

-    END

-END

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <afxres.h>
+
+// TODO(omaha): using this as a common resource for the activex/nsplugin as
+// well as goopdate. Need to clean this up a bit.
+// For example, I've changed the FILEFLAGSMASK to 0x3FL (which appears to be
+// "standard" at least amongst plugins), not sure why it's 0x17L in here.
+// Also, the "040904e4" (for codepage 1252 Ansi Latin) is required for
+// the netscape plugin stuff to see the MIMETYPE value in the resource block.
+// However, this resource file WAS using "040904B0" (codepage 1200 which is
+// unicode little endian).  Not sure why we're using that or if we really
+// need it to be that value.
+
+// TODO(omaha): FileDescription is what shows up in "about:plugins" for
+// Mozilla. Format the description to include the url of the project.
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+// FILEFLAGSMASK 0x17L
+ FILEFLAGSMASK 0x3FL
+// #ifdef _DEBUG
+// FILEFLAGS 0x1L
+//#else
+ FILEFLAGS 0x0L
+//#endif
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "CompanyName", "Google Inc."
+            VALUE "FileDescription", "Google Update"
+            VALUE "FileVersion", VERSION_NUMBER_STRING
+            VALUE "InternalName", "Google Update"
+            VALUE "LegalCopyright", "Copyright 2007-2009 Google Inc."
+            VALUE "OriginalFilename", "GoogleUpdate"
+            VALUE "ProductName", "Google Update"
+            VALUE "ProductVersion", VERSION_NUMBER_STRING
+#ifdef _DEBUG
+            VALUE "Debug", ""
+#endif
+#if !OFFICIAL_BUILD
+            VALUE "Privatebuild", ""
+#endif
+
+    #ifdef MIME_TYPE
+            VALUE "MIMEType",         MIME_TYPE
+    #endif
+
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252
+    END
+END
diff --git a/goopdate/goopdate_xml_parser.cc b/goopdate/goopdate_xml_parser.cc
index 9e8feb8..12f6a08 100644
--- a/goopdate/goopdate_xml_parser.cc
+++ b/goopdate/goopdate_xml_parser.cc
@@ -1,1541 +1,1541 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// goopdate_xml_parser for parsing the xml manifest files that are compiled

-// into the meta-installer and sent by the auto-update server.

-

-#include "omaha/goopdate/goopdate_xml_parser.h"

-

-#include <stdlib.h>

-#include <msxml2.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/error.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/xml_utils.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/goopdate_metrics.h"

-#include "omaha/goopdate/goopdate_utils.h"

-

-namespace omaha {

-

-namespace {

-

-// Loads the specified document and obtains the DOM and Element interfaces.

-HRESULT GetDocumentDomAndElement(const CString& file_name,

-                                 IXMLDOMDocument** document,

-                                 IXMLDOMElement** document_element) {

-  CORE_LOG(L3, (_T("[GetDocumentDomAndElement]")));

-  ASSERT1(document);

-  ASSERT1(document_element);

-

-  HRESULT hr = LoadXMLFromFile(file_name, true, document);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[LoadXMLFromFile failed][0x%x]"), hr));

-    return hr;

-  }

-

-  hr = (*document)->get_documentElement(document_element);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[get_documentElement failed][0x%x]"), hr));

-    return hr;

-  }

-  if (!*document_element) {  // Protect against msxml S_FALSE return.

-    CORE_LOG(LE, (_T("[*document_element is NULL]")));

-    return E_FAIL;

-  }

-

-  return S_OK;

-}

-

-// Loads the specified document and obtains the DOM interface.

-HRESULT GetDocumentElement(const CString& file_name,

-                           IXMLDOMElement** document_element) {

-  CComPtr<IXMLDOMDocument> document;

-  return GetDocumentDomAndElement(file_name, &document, document_element);

-}

-

-}  // namespace

-

-

-const int kGuidLen = 38;

-CString GoopdateXmlParser::seed_protocol_version;

-

-// Constants for creating the xml request.

-namespace Xml {

-  const TCHAR* const kHeaderText =

-    _T("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

-  const TCHAR* const kProcessingText =

-    _T("version=\"1.0\" encoding=\"UTF-8\"");

-

-  namespace Namespace {

-    const TCHAR* const kRequest = _T("http://www.google.com/update2/request");

-    const TCHAR* const kResponse = _T("http://www.google.com/update2/response");

-    const TCHAR* const kSeed = _T("http://www.google.com/update2/install");

-  }

-  namespace Element {

-    const TCHAR* const kXml = _T("xml");

-    const TCHAR* const kRequests = _T("gupdate");

-    const TCHAR* const kOmahaVersion = _T("updaterversion");

-    const TCHAR* const kOs = _T("os");

-    const TCHAR* const kApp = _T("app");

-    const TCHAR* const kUpdateCheck = _T("updatecheck");

-    const TCHAR* const kPing = _T("ping");

-    const TCHAR* const kEvent = _T("event");

-    const TCHAR* const kComponents = _T("components");

-    const TCHAR* const kComponent = _T("component");

-

-    const TCHAR* const kResponses = _T("gupdate");

-    const TCHAR* const kData = _T("data");

-

-    const TCHAR* const kInstall = _T("install");

-    const TCHAR* const kResponse = _T("response");

-    const TCHAR* const kNameValue = _T("attr");

-  }

-  namespace Attribute {

-    const TCHAR* const kActive = _T("active");

-    const TCHAR* const kAdditionalParameter = _T("ap");

-    const TCHAR* const kAppGuid = _T("appguid");

-    const TCHAR* const kApplicationName = _T("appname");

-    const TCHAR* const kAppId = _T("appid");

-    const TCHAR* const kArguments = _T("arguments");

-    const TCHAR* const kBrandCode = _T("brand");

-    const TCHAR* const kBrowserType = _T("browser");

-    const TCHAR* const kClientId = _T("client");

-    const TCHAR* const kCodebase = _T("codebase");

-    const TCHAR* const kCountry = _T("country");

-    const TCHAR* const kErrorCode = _T("errorcode");

-    const TCHAR* const kEventResult = _T("eventresult");

-    const TCHAR* const kEventType = _T("eventtype");

-    const TCHAR* const kErrorUrl = _T("errorurl");

-    const TCHAR* const kExtraCode1 = _T("extracode1");

-    const TCHAR* const kHash = _T("hash");

-    const TCHAR* const kIndex = _T("index");

-    const TCHAR* const kInstalledAgeDays = _T("installage");

-    const TCHAR* const kIsMachine = _T("ismachine");

-    const TCHAR* const kInstallationId = _T("iid");

-    const TCHAR* const kInstallSource = _T("installsource");

-    const TCHAR* const kLang = _T("lang");

-    const TCHAR* const kMachineId = _T("machineid");

-    const TCHAR* const kName = _T("name");

-    const TCHAR* const kNeedsAdmin = _T("needsadmin");

-    const TCHAR* const kParameter = _T("parameter");

-    const TCHAR* const kPeriodOverrideSec = _T("periodoverridesec");

-    const TCHAR* const kPlatform = _T("platform");

-    const TCHAR* const kPreviousVersion = _T("previousversion");

-    const TCHAR* const kProtocol = _T("protocol");

-    const TCHAR* const kRequestId  = _T("requestid");

-    const TCHAR* const kServicePack = _T("sp");

-    const TCHAR* const kSessionId = _T("sessionid");

-    const TCHAR* const kSignature = _T("signature");

-    const TCHAR* const kSize = _T("size");

-    const TCHAR* const kStatus = _T("status");

-    const TCHAR* const kSuccessAction = _T("onsuccess");

-    const TCHAR* const kSuccessUrl = _T("successurl");

-    const TCHAR* const kTag = _T("tag");

-    const TCHAR* const kTestSource = _T("testsource");

-    const TCHAR* const kTerminateAllBrowsers = _T("terminateallbrowsers");

-    const TCHAR* const kTTToken = _T("tttoken");

-    const TCHAR* const kUpdateDisabled = _T("updatedisabled");

-    const TCHAR* const kUserId = _T("userid");

-    const TCHAR* const kVersion = _T("version");

-    const TCHAR* const kXmlns = _T("xmlns");

-  }

-

-  namespace Value {

-    const TCHAR* const kRequestType = _T("UpdateRequest");

-    const TCHAR* const kProtocol = _T("2.0");

-    const TCHAR* const kVersion2 = _T("2.0");

-    const TCHAR* const kVersion3 = _T("3.0");

-    const TCHAR* const kTrue = _T("true");

-    const TCHAR* const kFalse = _T("false");

-    const TCHAR* const kStatusError = _T("error");

-    const TCHAR* const kSuccessActionDefault = _T("default");

-    const TCHAR* const kSuccessActionExitSilently = _T("exitsilently");

-    const TCHAR* const kSuccessActionExitSilentlyOnLaunchCmd =

-        _T("exitsilentlyonlaunchcmd");

-

-    const TCHAR* const kStatusOk = kResponseStatusOkValue;

-    const TCHAR* const kInstallData = _T("install");

-  }

-}

-

-SuccessfulInstallAction GoopdateXmlParser::ConvertStringToSuccessAction(

-    const CString& text) {

-  if (text.IsEmpty() ||

-      _tcsicmp(text, Xml::Value::kSuccessActionDefault) == 0) {

-    return SUCCESS_ACTION_DEFAULT;

-  } else if (_tcsicmp(text, Xml::Value::kSuccessActionExitSilently) == 0) {

-    return SUCCESS_ACTION_EXIT_SILENTLY;

-  } else if (_tcsicmp(text,

-                      Xml::Value::kSuccessActionExitSilentlyOnLaunchCmd) == 0) {

-    return SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD;

-  } else {

-    ASSERT(false, (_T("[Unrecognized success action][%s]"), text));

-    // Use the default action. This allows Omaha to be forward-compatible with

-    // new SuccessActions, meaning older versions will not fail if a config

-    // uses a new action.

-    return SUCCESS_ACTION_DEFAULT;

-  }

-}

-

-// Implementation of the GoopdateXmlParser.

-HRESULT GoopdateXmlParser::ReadBooleanAttribute(IXMLDOMNode* node,

-                                                const TCHAR* attr_name,

-                                                bool* value) {

-  CORE_LOG(L3, (_T("[ReadBooleanAttribute][%s]"), attr_name));

-  ASSERT1(node != NULL);

-  ASSERT1(attr_name != NULL);

-  ASSERT1(value != NULL);

-

-  CComBSTR node_value;

-  HRESULT hr = ReadAttribute(node, attr_name, &node_value);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ReadAttribute failed][%s][0x%x]"), attr_name, hr));

-    return hr;

-  }

-

-  hr = String_StringToBool(static_cast<TCHAR*>(node_value),

-                           value);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[String_StringToBool failed][0x%x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::ReadIntAttribute(IXMLDOMNode* node,

-                                            const TCHAR* attr_name,

-                                            int* value) {

-  CORE_LOG(L3, (_T("[ReadIntAttribute][%s]"), attr_name));

-  ASSERT1(node != NULL);

-  ASSERT1(attr_name != NULL);

-  ASSERT1(value != NULL);

-

-  CComBSTR node_value;

-  HRESULT hr = ReadAttribute(node, attr_name, &node_value);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ReadAttribute failed][%s][0x%x]"), attr_name, hr));

-    return hr;

-  }

-

-  if (!String_StringToDecimalIntChecked(

-          static_cast<const TCHAR*>(node_value), value)) {

-          return GOOPDATEXML_E_STRTOUINT;

-  }

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::ReadGuidAttribute(IXMLDOMNode* node,

-                                             const TCHAR* attr_name,

-                                             GUID* value) {

-  CORE_LOG(L3, (_T("[ReadGuidAttribute][%s]"), attr_name));

-  ASSERT1(node != NULL);

-  ASSERT1(attr_name != NULL);

-  ASSERT1(value != NULL);

-

-  CComBSTR node_value;

-  HRESULT hr = ReadAttribute(node, attr_name, &node_value);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ReadAttribute failed][%s][0x%x]"), attr_name, hr));

-    return hr;

-  }

-

-  hr = ::CLSIDFromString(static_cast<TCHAR*>(node_value), value);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[CLSIDFromString failed][0x%x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::ReadStringAttribute(IXMLDOMNode* node,

-                                               const TCHAR* attr_name,

-                                               CString* value) {

-  CORE_LOG(L3, (_T("[ReadStringAttribute][%s]"), attr_name));

-  ASSERT1(node != NULL);

-  ASSERT1(attr_name != NULL);

-  ASSERT1(value != NULL);

-

-  CComBSTR node_value;

-  HRESULT hr = ReadAttribute(node, attr_name, &node_value);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ReadAttribute failed][%s][0x%x]"), attr_name, hr));

-    return hr;

-  }

-

-  // Will extract the underlying string.

-  *value = static_cast<TCHAR*>(node_value);

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::ReadAttribute(IXMLDOMNode* node,

-                                         const TCHAR* attr_name,

-                                         BSTR* value) {

-  CORE_LOG(L4, (_T("[ReadAttribute][%s]"), attr_name));

-  ASSERT1(node != NULL);

-  ASSERT1(attr_name != NULL);

-  ASSERT1(value != NULL);

-

-  // First read the attributes.

-  CComPtr<IXMLDOMNamedNodeMap> attributes;

-  HRESULT hr = node->get_attributes(&attributes);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[get_attributes failed][0x%x]"), hr));

-    return hr;

-  }

-

-  if (!attributes) {

-    CORE_LOG(LE, (_T("[Msxml S_FALSE return.]")));

-    return E_FAIL;  // Protect against msxml S_FALSE return.

-  }

-

-  CComPtr<IXMLDOMNode> attribute_node;

-  CComVariant node_value;

-  CComBSTR temp_attr_name(attr_name);

-

-  // Get the attribute using a named node.

-  hr = attributes->getNamedItem(static_cast<BSTR>(temp_attr_name),

-                                &attribute_node);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[getNamedItem failed][0x%x]"), hr));

-    return hr;

-  }

-

-  if (!attribute_node) {

-    CORE_LOG(LE, (_T("[Msxml S_FALSE return.]")));

-    return E_FAIL;  // Protect against msxml S_FALSE return.

-  }

-

-  hr = attribute_node->get_nodeValue(&node_value);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[get_nodeValue failed][0x%x]"), hr));

-    return hr;

-  }

-

-  if (node_value.vt == VT_EMPTY) {

-    CORE_LOG(LE, (_T("[node_value.vt == VT_EMPTY]")));

-    return E_FAIL;

-  }

-

-  // Extract the variant into a BSTR.

-  node_value.CopyTo(value);

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::ReadStringValue(IXMLDOMNode* node,

-                                           CString* value) {

-  CORE_LOG(L4, (_T("[ReadStringValue]")));

-  ASSERT1(node != NULL);

-  ASSERT1(value != NULL);

-

-  CComPtr<IXMLDOMNodeList> child_nodes;

-  HRESULT hr = node->get_childNodes(&child_nodes);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[get_childNodes failed][0x%x]"), hr));

-    return hr;

-  }

-  if (!child_nodes) {

-    CORE_LOG(LE, (_T("[Msxml S_FALSE return.]")));

-    return E_FAIL;  // Protect against msxml S_FALSE return.

-  }

-

-  long count = 0;  // NOLINT

-  hr = child_nodes->get_length(&count);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ASSERT(count == 1, (_T("count: %u"), count));

-  CComPtr<IXMLDOMNode> child_node;

-  hr = child_nodes->nextNode(&child_node);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  DOMNodeType type = NODE_INVALID;

-  hr = child_node->get_nodeType(&type);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[get_nodeType failed][0x%x]"), hr));

-    return hr;

-  }

-

-  if (type != NODE_TEXT) {

-    CORE_LOG(LE, (_T("[Invalid nodeType][%d]"), type));

-    return E_INVALIDARG;

-  }

-

-  CComVariant node_value;

-  hr = child_node->get_nodeValue(&node_value);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[get_nodeValue failed][0x%x]"), hr));

-    return hr;

-  }

-

-  if (node_value.vt != VT_BSTR) {

-    CORE_LOG(LE, (_T("[node_value.vt != VT_BSTR][%d]"), node_value.vt));

-    return E_INVALIDARG;

-  }

-

-  *value = V_BSTR(&node_value);

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::ReadUpdateResponse(IXMLDOMNode* node,

-                                              UpdateResponse* response) {

-  CORE_LOG(L4, (_T("[ReadUpdateResponse]")));

-  ASSERT1(node != NULL);

-  ASSERT1(response != NULL);

-

-  UpdateResponseData response_data;

-

-  // Read GUID first since we need the GUID even on errors in order

-  // to remove the corresponding request from the jobs list.

-  GUID guid = {0};

-  HRESULT hr = ReadGuidAttribute(node, Xml::Attribute::kAppId, &guid);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ReadGuidAttribute failed][0x%x]"), hr));

-    return hr;

-  }

-  response_data.set_guid(guid);

-

-  CString str;

-  // Any response status but "ok" for the "app" element stops the "parsing".

-  hr = ReadStringAttribute(node, Xml::Attribute::kStatus, &str);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ReadStringAttribute failed][0x%x]"), hr));

-    return hr;

-  }

-  if (str != Xml::Value::kStatusOk) {

-    response_data.set_status(str);

-    response->set_update_response_data(response_data);

-    return S_OK;

-  }

-

-  // Now try and read the children nodes of the response.

-  CComPtr<IXMLDOMNodeList> child_nodes;

-  // Get all the children of the document.

-  hr = node->get_childNodes(&child_nodes);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[get_childNodes failed][0x%x]"), hr));

-    return hr;

-  }

-  if (!child_nodes) {

-    CORE_LOG(LE, (_T("[Msxml S_FALSE return.]")));

-    return E_FAIL;  // Protect against msxml S_FALSE return.

-  }

-

-  // Go over all the children and handle the children. We ignore all the

-  // children that we do not understand. Note that we expect the nodes that

-  // we want to be present. Although we are not enforcing this for now.

-  CComPtr<IXMLDOMNode> child_node;

-  while (child_nodes->nextNode(&child_node) != S_FALSE) {

-    XMLFQName node_name;

-    hr = GetXMLFQName(child_node, &node_name);

-    if (FAILED(hr)) {

-      CORE_LOG(LE, (_T("[GetXMLFQName failed][0x%x]"), hr));

-      return hr;

-    }

-

-    if (node_name.base == Xml::Element::kUpdateCheck) {

-      hr = ReadStringAttribute(child_node, Xml::Attribute::kTTToken, &str);

-      if (SUCCEEDED(hr) && !str.IsEmpty()) {

-        response_data.set_tt_token(str);

-      }

-

-      hr = ReadStringAttribute(child_node, Xml::Attribute::kStatus, &str);

-      if (FAILED(hr)) { return hr; }

-      response_data.set_status(str);

-

-      if (str == Xml::Value::kStatusOk) {

-        int size = 0;

-        hr = ReadIntAttribute(child_node, Xml::Attribute::kSize, &size);

-        if (FAILED(hr)) { return hr; }

-        if (size < 0) {

-          return GOOPDATEXML_E_STRTOUINT;

-        }

-        response_data.set_size(size);

-

-        hr = ReadStringAttribute(child_node, Xml::Attribute::kHash, &str);

-        if (FAILED(hr)) { return hr; }

-        response_data.set_hash(str);

-

-        hr = ReadStringAttribute(child_node, Xml::Attribute::kCodebase, &str);

-        if (FAILED(hr)) { return hr; }

-        response_data.set_url(str);

-

-        hr = ReadStringAttribute(child_node, Xml::Attribute::kNeedsAdmin, &str);

-        if (FAILED(hr)) { return hr; }

-        NeedsAdmin needs_admin;

-        hr = goopdate_utils::ConvertStringToNeedsAdmin(str, &needs_admin);

-        if (FAILED(hr)) { return hr; }

-        response_data.set_needs_admin(needs_admin);

-

-        hr = ReadStringAttribute(child_node, Xml::Attribute::kArguments, &str);

-        // arguments is optional

-        if (SUCCEEDED(hr)) {

-          response_data.set_arguments(str);

-        }

-

-        hr = ReadStringAttribute(child_node, Xml::Attribute::kSuccessUrl, &str);

-        if (SUCCEEDED(hr)) {

-          response_data.set_success_url(str);

-        }

-

-        bool terminate_all_browsers = false;

-        hr = ReadBooleanAttribute(child_node,

-                                  Xml::Attribute::kTerminateAllBrowsers,

-                                  &terminate_all_browsers);

-        if (SUCCEEDED(hr)) {

-          response_data.set_terminate_all_browsers(terminate_all_browsers);

-        }

-

-        hr = ReadStringAttribute(child_node,

-                                 Xml::Attribute::kSuccessAction,

-                                 &str);

-        if (SUCCEEDED(hr)) {

-          response_data.set_success_action(ConvertStringToSuccessAction(str));

-        }

-

-        // If no version exists in the server response, we will still indicate

-        // when an update is available. However, we will not provide version

-        // information to any JobObserver.

-        hr = ReadStringAttribute(child_node,

-                                 Xml::Attribute::kVersion,

-                                 &str);

-        if (SUCCEEDED(hr)) {

-          response_data.set_version(str);

-        }

-      }

-

-      // Always look for the error URL because it is used in errors.

-      hr = ReadStringAttribute(child_node, Xml::Attribute::kErrorUrl, &str);

-      if (SUCCEEDED(hr)) {

-        response_data.set_error_url(str);

-      }

-    } else if (node_name.base == Xml::Element::kData) {

-      hr = ReadStringAttribute(child_node, Xml::Attribute::kStatus, &str);

-      if (FAILED(hr)) {

-        return hr;

-      }

-

-      if (str == Xml::Value::kStatusOk) {

-        // <data name="install" index="foo" status="ok">foo bar</data>.

-        hr = ReadStringAttribute(child_node, Xml::Attribute::kName, &str);

-        if (FAILED(hr)) {

-          return hr;

-        }

-        if (str.CompareNoCase(Xml::Value::kInstallData)) {

-          CORE_LOG(LW, (_T("[Skipping unsupported data][%s]"), str));

-          continue;

-        }

-

-        CString install_data_index;

-        hr = ReadStringAttribute(child_node,

-                                 Xml::Attribute::kIndex,

-                                 &install_data_index);

-        if (FAILED(hr)) {

-          return hr;

-        }

-

-        CString install_data;

-        hr = ReadStringValue(child_node, &install_data);

-        if (FAILED(hr)) {

-          return hr;

-        }

-        response_data.SetInstallData(install_data_index, install_data);

-      }

-    } else if (node_name.base == Xml::Element::kPing) {

-      // nothing to do here (yet)

-    } else if (node_name.base == Xml::Element::kEvent) {

-      // nothing to do here (yet)

-    } else if (node_name.base == Xml::Element::kComponents) {

-      VERIFY1(SUCCEEDED(ReadComponentsResponses(child_node, response)));

-    }

-    child_node = NULL;

-  }

-

-  response->set_update_response_data(response_data);

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::ReadComponentsResponses(IXMLDOMNode* node,

-                                                   UpdateResponse* response) {

-  CORE_LOG(L4, (_T("[ReadComponentsResponses]")));

-  ASSERT1(node);

-  ASSERT1(response);

-

-  CComPtr<IXMLDOMNodeList> child_nodes;

-  HRESULT hr = node->get_childNodes(&child_nodes);

-  if (FAILED(hr)) { return hr; }

-  // If S_FALSE, then there are no children components.

-  if (S_FALSE == hr) { return S_OK; }

-

-  CComPtr<IXMLDOMNode> child_node;

-  while (child_nodes->nextNode(&child_node) != S_FALSE) {

-    XMLFQName node_name;

-    hr = GetXMLFQName(child_node, &node_name);

-    if (FAILED(hr)) { return hr; }

-

-    if (node_name.base == Xml::Element::kComponent) {

-      UpdateResponseData component_response_data;

-      hr = ReadComponentResponseData(child_node, &component_response_data);

-      if (FAILED(hr)) { return hr; }

-      response->AddComponentResponseData(component_response_data);

-    } else {

-      ASSERT1(false);

-    }

-

-    child_node = NULL;

-  }

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::ReadComponentResponseData(

-    IXMLDOMNode* node,

-    UpdateResponseData* response_data) {

-  CORE_LOG(L4, (_T("[ReadComponentsResponseData]")));

-  // TODO(omaha): consolidate component/product parsing. They have several

-  // similar attributes.

-  // Read GUID first since we need the GUID even on errors in order to remove

-  // the corresponding request from the jobs list.

-  GUID guid = {0};

-  HRESULT hr = ReadGuidAttribute(node, Xml::Attribute::kAppId, &guid);

-  if (FAILED(hr)) { return hr; }

-  response_data->set_guid(guid);

-

-  // Any response status but "ok" for the "app" element stops the "parsing".

-  CString str;

-  hr = ReadStringAttribute(node, Xml::Attribute::kStatus, &str);

-  if (FAILED(hr)) { return hr; }

-  if (str != Xml::Value::kStatusOk) {

-    response_data->set_status(str);

-    return S_OK;

-  }

-

-  // Now try and read the children nodes of the response.

-  CComPtr<IXMLDOMNodeList> child_nodes;

-  // Get all the children of the document.

-  hr = node->get_childNodes(&child_nodes);

-  if (FAILED(hr)) { return hr; }

-  if (!child_nodes) { return E_FAIL; }  // Protect against msxml S_FALSE return.

-

-  // Go over all the children and handle the children. We ignore all the

-  // children that we do not understand. Note that we expect the nodes that

-  // we want to be present. Although we are not enforcing this for now.

-  CComPtr<IXMLDOMNode> child_node;

-  while (child_nodes->nextNode(&child_node) != S_FALSE) {

-    XMLFQName node_name;

-    hr = GetXMLFQName(child_node, &node_name);

-    if (FAILED(hr)) { return hr; }

-

-    if (node_name.base == Xml::Element::kUpdateCheck) {

-      hr = ReadStringAttribute(child_node, Xml::Attribute::kStatus, &str);

-      if (FAILED(hr)) { return hr; }

-      response_data->set_status(str);

-      // TODO(omaha):  Check why we have kStatusOk at both levels of the XML

-      // (same for product parsing) and consolidate/remove as necessary.

-      if (str == Xml::Value::kStatusOk) {

-        int size = 0;

-        hr = ReadIntAttribute(child_node, Xml::Attribute::kSize, &size);

-        if (FAILED(hr)) { return hr; }

-        if (size < 0) {

-          return GOOPDATEXML_E_STRTOUINT;

-        }

-        response_data->set_size(size);

-

-        hr = ReadStringAttribute(child_node, Xml::Attribute::kHash, &str);

-        if (FAILED(hr)) { return hr; }

-        response_data->set_hash(str);

-

-        hr = ReadStringAttribute(child_node, Xml::Attribute::kCodebase, &str);

-        if (FAILED(hr)) { return hr; }

-        response_data->set_url(str);

-

-        hr = ReadStringAttribute(child_node, Xml::Attribute::kArguments, &str);

-        // arguments is optional

-        if (SUCCEEDED(hr)) {

-          response_data->set_arguments(str);

-        }

-      }

-    } else {

-      ASSERT1(false);

-    }

-

-    child_node = NULL;

-  }

-

-  return S_OK;

-}

-

-// This exists only to support handoffs from 1.0.x and 1.1.x metainstallers.

-HRESULT GoopdateXmlParser::ReadInstallElement(

-    IXMLDOMNode* node,

-    UpdateResponseData* response_data) {

-  ASSERT1(node);

-  ASSERT1(response_data);

-

-  HRESULT hr = ReadRequiredInstallAttributes(node, response_data);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return ReadOptionalInstallAttributes(node, response_data);

-}

-

-// This exists only to support handoffs from 1.0.x and 1.1.x metainstallers.

-HRESULT GoopdateXmlParser::ReadRequiredInstallAttributes(

-    IXMLDOMNode* node,

-    UpdateResponseData* response_data) {

-  ASSERT1(node);

-  ASSERT1(response_data);

-

-  // Read the guid and whether the application needs admin. Both the attributes

-  // are required.

-  GUID guid_value = {0};

-  HRESULT hr = ReadGuidAttribute(node, Xml::Attribute::kAppGuid,

-                                 &guid_value);

-  if (FAILED(hr)) { return hr; }

-

-  response_data->set_guid(guid_value);

-

-  CString needs_admin_str;

-  hr = ReadStringAttribute(node, Xml::Attribute::kNeedsAdmin,

-                           &needs_admin_str);

-  if (FAILED(hr)) { return hr; }

-

-  NeedsAdmin needs_admin;

-  hr = goopdate_utils::ConvertStringToNeedsAdmin(needs_admin_str, &needs_admin);

-  if (FAILED(hr)) { return hr; }

-

-  response_data->set_needs_admin(needs_admin);

-

-  // We only read the language and the application name from the seed manifest

-  // if the version of the seed manifest is greater than 2.0.

-  if (String_StringToDouble(seed_protocol_version) >

-      String_StringToDouble(Xml::Value::kVersion2)) {

-    ++metric_handoff_legacy_11;

-

-    CString app_name;

-    hr = ReadStringAttribute(node, Xml::Attribute::kApplicationName, &app_name);

-    if (FAILED(hr)) { return hr; }

-    response_data->set_app_name(app_name);

-

-    CString language;

-    hr = ReadStringAttribute(node, Xml::Attribute::kLang, &language);

-    if (FAILED(hr)) { return hr; }

-    response_data->set_language(language);

-  } else {

-    ++metric_handoff_legacy_10;

-  }

-

-  return S_OK;

-}

-

-// Since all of these attributes are optional, read failures do not cause this

-// method to fail.

-// This exists only to support handoffs from 1.0.x and 1.1.x metainstallers.

-HRESULT GoopdateXmlParser::ReadOptionalInstallAttributes(

-    IXMLDOMNode* node,

-    UpdateResponseData* response_data) {

-  ASSERT1(node);

-  ASSERT1(response_data);

-

-  CString iid;

-  HRESULT hr = ReadStringAttribute(node, Xml::Attribute::kInstallationId, &iid);

-  if (SUCCEEDED(hr)) {

-    response_data->set_installation_id(StringToGuid(iid));

-  }

-

-  CString ap;

-  hr = ReadStringAttribute(node, Xml::Attribute::kAdditionalParameter, &ap);

-  if (SUCCEEDED(hr)) {

-    response_data->set_ap(ap);

-  }

-

-  CString browser_type;

-  hr = ReadStringAttribute(node, Xml::Attribute::kBrowserType, &browser_type);

-  if (SUCCEEDED(hr)) {

-    BrowserType type = BROWSER_UNKNOWN;

-    hr = goopdate_utils::ConvertStringToBrowserType(browser_type, &type);

-    if (SUCCEEDED(hr)) {

-      response_data->set_browser_type(type);

-    }

-  }

-

-  return S_OK;

-}

-

-// Assumes all higher level validity checks have been done

-HRESULT GoopdateXmlParser::ReadUpdateResponses(

-    IXMLDOMNode* node,

-    UpdateResponses* responses) {

-  ASSERT1(node != NULL);

-  ASSERT1(responses != NULL);

-

-  CComPtr<IXMLDOMNodeList> child_nodes;

-  // Get all the children of the Node.

-  HRESULT hr = node->get_childNodes(&child_nodes);

-  if (FAILED(hr)) { return hr; }

-  if (!child_nodes) { return E_FAIL; }  // Protect against msxml S_FALSE return.

-

-  // Go Over all the children and read each of them. we will ignore ones that

-  // we dont understand.

-  hr = child_nodes->reset();

-  if (FAILED(hr)) { return hr; }

-

-  CComPtr<IXMLDOMNode> child_node;

-  while (child_nodes->nextNode(&child_node) != S_FALSE) {

-    XMLFQName child_node_name;

-    hr = GetXMLFQName(child_node, &child_node_name);

-    if (FAILED(hr)) { return hr; }

-

-    if (child_node_name.base == Xml::Element::kApp) {

-      // we got a response we should read that in.

-      UpdateResponse response;

-      hr = ReadUpdateResponse(child_node, &response);

-      if (FAILED(hr)) { return hr; }

-

-      const GUID& response_guid = response.update_response_data().guid();

-      ASSERT1(responses->find(response_guid) == responses->end());

-      (*responses)[response_guid] = response;

-    }

-    child_node = NULL;

-  }

-  return S_OK;

-}

-

-// This exists only to support handoffs from 1.0.x and 1.1.x metainstallers.

-HRESULT GoopdateXmlParser::ReadSeedInstalls(IXMLDOMNode* node,

-                                            UpdateResponses* responses) {

-  ASSERT1(node != NULL);

-  ASSERT1(responses != NULL);

-

-  CComPtr<IXMLDOMNodeList> child_nodes;

-  // Get all the children of the Node.

-  HRESULT hr = node->get_childNodes(&child_nodes);

-  if (FAILED(hr)) { return hr; }

-  if (!child_nodes) { return E_FAIL; }  // Protect against msxml S_FALSE return.

-

-  // Go Over all the children and read each of them. Since seed files are

-  // always of a version <= to this code, error if we run into a child we don't

-  // recognize.

-  hr = child_nodes->reset();

-  if (FAILED(hr)) { return hr; }

-

-  CComPtr<IXMLDOMNode> child_node;

-  while (child_nodes->nextNode(&child_node) != S_FALSE) {

-    XMLFQName child_node_name;

-    hr = GetXMLFQName(child_node, &child_node_name);

-    if (FAILED(hr)) { return hr; }

-

-    if (child_node_name.base == Xml::Element::kInstall) {

-      // We found an install node. We should read that in.

-      UpdateResponseData response_data;

-      hr = ReadInstallElement(child_node, &response_data);

-      if (FAILED(hr)) { return hr; }

-

-      UpdateResponse response(response_data);

-      const GUID& response_guid =  response.update_response_data().guid();

-      ASSERT1(responses->find(response_guid) == responses->end());

-      (*responses)[response_guid] = response;

-

-      child_node = NULL;

-    } else {

-      child_node = NULL;

-      return E_FAIL;

-    }

-  }

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::GetProtocolVersion(IXMLDOMElement* document_element,

-                                              CString* version) {

-  ASSERT1(document_element);

-  ASSERT1(version);

-

-  CString protocol_version;

-  return ReadStringAttribute(document_element,

-                             Xml::Attribute::kProtocol,

-                             version);

-}

-

-HRESULT GoopdateXmlParser::VerifyElementProtocolCompatibility(

-    IXMLDOMElement* document_element,

-    const CString& expected_version) {

-  ASSERT1(document_element);

-

-  CString protocol_version;

-  HRESULT hr = GetProtocolVersion(document_element, &protocol_version);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return VerifyProtocolCompatibility(protocol_version, expected_version);

-}

-

-// Returns GOOPDATEXML_E_XMLVERSION when the actual_ver is not between

-// the start_ver and the end_ver, both inclusive.

-HRESULT GoopdateXmlParser::VerifyProtocolRange(const CString& actual_ver,

-                                               const CString& start_ver,

-                                               const CString& end_ver) {

-  const double version = String_StringToDouble(actual_ver);

-  const double start = String_StringToDouble(start_ver);

-  const double end = String_StringToDouble(end_ver);

-  if (version < start || version > end) {

-    return GOOPDATEXML_E_XMLVERSION;

-  }

-

-  return S_OK;

-}

-

-// Verify that the protocol version is one we understand.  We accept

-// all version numbers where major version is the same as kExpectedVersion

-// which are greater than or equal to kExpectedVersion. In other words,

-// we handle future minor version number increases which should be

-// compatible.

-HRESULT GoopdateXmlParser::VerifyProtocolCompatibility(

-    const CString& actual_version,

-    const CString& expected_version) {

-  if (_tcscmp(actual_version, expected_version) != 0) {

-    const double version = String_StringToDouble(actual_version);

-    const double expected = String_StringToDouble(expected_version);

-    if (expected > version) {

-      return GOOPDATEXML_E_XMLVERSION;

-    }

-    const int version_major = static_cast<int>(version);

-    const int expected_major = static_cast<int>(expected);

-    if (version_major != expected_major) {

-      return GOOPDATEXML_E_XMLVERSION;

-    }

-  }

-

-  return S_OK;

-}

-

-// Currently, this method only validates the name and protocol version.

-HRESULT GoopdateXmlParser::ValidateResponseElement(

-    IXMLDOMElement* document_element) {

-  CComBSTR root_name;

-  HRESULT hr = document_element->get_baseName(&root_name);

-  if (FAILED(hr)) { return hr; }

-  XMLFQName doc_element_name(Xml::Namespace::kResponse, root_name);

-  if (doc_element_name.base != Xml::Element::kResponses) {

-    return GOOPDATEXML_E_RESPONSESNODE;

-  }

-

-  return VerifyElementProtocolCompatibility(document_element,

-                                            Xml::Value::kVersion2);

-}

-

-HRESULT GoopdateXmlParser::ParseManifestFile(const CString& file_name,

-                                             UpdateResponses* responses) {

-  if (responses == NULL) {

-    return E_INVALIDARG;

-  }

-

-  CComPtr<IXMLDOMElement> document_element;

-  HRESULT hr = GetDocumentElement(file_name, &document_element);

-  if (FAILED(hr)) { return hr; }

-

-  return ParseManifest(document_element, responses);

-}

-

-HRESULT GoopdateXmlParser::ParseManifestString(

-    const TCHAR* manifest,

-    UpdateResponses* responses) {

-  ASSERT1(manifest);

-  ASSERT1(responses);

-  CComPtr<IXMLDOMDocument> document;

-  HRESULT hr = LoadXMLFromMemory(manifest, false, &document);

-  if (FAILED(hr)) { return hr; }

-

-  CComPtr<IXMLDOMElement> document_element;

-  hr = document->get_documentElement(&document_element);

-  if (FAILED(hr)) { return hr; }

-  if (!document_element) {  // Protect against msxml S_FALSE return.

-    return E_FAIL;

-  }

-

-  return ParseManifest(document_element, responses);

-}

-

-HRESULT GoopdateXmlParser::ParseManifest(IXMLDOMElement* manifest,

-                                         UpdateResponses* responses) {

-  ASSERT1(manifest);

-  ASSERT1(responses);

-

-  CComBSTR uri;

-  HRESULT hr = manifest->get_namespaceURI(&uri);

-  if (FAILED(hr)) { return hr; }

-

-  if (uri == Xml::Namespace::kResponse) {

-    hr = ValidateResponseElement(manifest);

-    if (FAILED(hr)) { return hr; }

-

-    hr = ReadUpdateResponses(manifest, responses);

-    if (FAILED(hr)) { return hr; }

-  } else if (uri == Xml::Namespace::kSeed) {

-    // TODO(omaha): We should probably verify the name too.

-    hr = GetProtocolVersion(manifest, &seed_protocol_version);

-    if (FAILED(hr)) { return hr; }

-

-    hr = VerifyProtocolRange(seed_protocol_version,

-                             Xml::Value::kVersion2,

-                             Xml::Value::kVersion3);

-    if (FAILED(hr)) { return hr; }

-

-    hr = ReadSeedInstalls(manifest, responses);

-    if (FAILED(hr)) { return hr; }

-  } else {

-    return GOOPDATEXML_E_UNEXPECTED_URI;

-  }

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::CreateRequestElement(

-    const TCHAR* xml_element_name,

-    const CString& value,

-    IXMLDOMDocument* document,

-    IXMLDOMNode** request_element) {

-

-  ASSERT1(xml_element_name != NULL);

-  ASSERT1(document != NULL);

-  ASSERT1(request_element != NULL);

-

-  // request element names get o: prepended to avoid a size explosion where

-  // the namespace attribute gets automatically added to every element by

-  // msxml

-  CString name;

-  name.Format(_T("o:%s"), xml_element_name);

-

-  HRESULT hr = CreateXMLNode(document,

-                             NODE_ELEMENT,

-                             name,

-                             Xml::Namespace::kRequest,

-                             value,

-                             request_element);

-  return hr;

-}

-

-HRESULT GoopdateXmlParser::CreateAndAddRequestElement(

-    const TCHAR* xml_element_name,

-    const CString& value,

-    IXMLDOMDocument* document,

-    IXMLDOMNode* parent) {

-

-  ASSERT1(xml_element_name != NULL);

-  ASSERT1(document != NULL);

-  ASSERT1(parent != NULL);

-

-  CComPtr<IXMLDOMNode> element;

-  HRESULT hr = CreateRequestElement(xml_element_name,

-                                    value,

-                                    document,

-                                    &element);

-  if (FAILED(hr)) { return hr; }

-

-  hr = parent->appendChild(element, NULL);

-  if (FAILED(hr)) { return hr; }

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::AddAttributesToNode(

-    const CString& namespace_uri,

-    const std::vector<XMLNameValuePair>& attributes,

-    IXMLDOMNode* element) {

-  ASSERT1(element != NULL);

-  HRESULT hr;

-  for (size_t i = 0; i < attributes.size(); ++i) {

-    hr = AddXMLAttributeNode(element,

-                             namespace_uri,

-                             attributes[i].first,

-                             attributes[i].second);

-    if (FAILED(hr)) { return hr; }

-  }

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::CreateAppRequestElementHelper(

-    const AppRequest& app_request,

-    IXMLDOMDocument* document,

-    IXMLDOMNode** app_element) {

-  ASSERT1(app_element);

-  ASSERT1(document);

-

-  const AppData& app_data = app_request.request_data().app_data();

-

-  // Create the request node.

-  HRESULT hr = CreateRequestElement(Xml::Element::kApp,

-                                    _T(""),

-                                    document,

-                                    app_element);

-  if (FAILED(hr)) { return hr; }

-

-  // Add the appid to the app node.

-  // appid=""       // The application Id.

-  const int guid_len = kGuidLen;

-  TCHAR guid_str[guid_len + 1] = { _T('\0') };

-  if (StringFromGUID2(app_data.app_guid(), guid_str, guid_len + 1) <= 0) {

-    return E_FAIL;

-  }

-  if (FAILED(hr)) { return hr; }

-

-  // Saves about 600 bytes of code size by creating and destroying the

-  // array inside of the statement block.

-  {

-    // Create the list of attributes and the values that need to be added.

-    const XMLNameValuePair elements[] = {

-        std::make_pair(Xml::Attribute::kAppId, guid_str),

-        std::make_pair(Xml::Attribute::kVersion, app_data.version()),

-        std::make_pair(Xml::Attribute::kLang, app_data.language()),

-        std::make_pair(Xml::Attribute::kBrandCode, app_data.brand_code()),

-        std::make_pair(Xml::Attribute::kClientId, app_data.client_id())

-    };

-

-    for (size_t i = 0; i < arraysize(elements); ++i) {

-      hr = AddXMLAttributeNode(*app_element,

-                               Xml::Namespace::kRequest,

-                               elements[i].first,

-                               elements[i].second);

-      if (FAILED(hr)) { return hr; }

-    }

-  }

-

-  if (0 != app_data.install_time_diff_sec()) {

-    const int kSecondsPerDay = 24 * kSecondsPerHour;

-    int installed_full_days = app_data.install_time_diff_sec() / kSecondsPerDay;

-    hr = AddXMLAttributeNode(*app_element,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kInstalledAgeDays,

-                             itostr(installed_full_days));

-    if (FAILED(hr)) { return hr; }

-  }

-

-  if (GUID_NULL != app_data.iid()) {

-    hr = AddXMLAttributeNode(*app_element,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kInstallationId,

-                             GuidToString(app_data.iid()));

-    if (FAILED(hr)) { return hr; }

-  }

-

-  if (!app_data.install_source().IsEmpty()) {

-    hr = AddXMLAttributeNode(*app_element,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kInstallSource,

-                             app_data.install_source());

-    if (FAILED(hr)) { return hr; }

-  }

-

-  // Create and add component elements to the app element.

-  if (app_request.num_components() > 0) {

-    CComPtr<IXMLDOMNode> components_node;

-    hr = CreateRequestElement(Xml::Element::kComponents,

-                              _T(""),

-                              document,

-                              &components_node);

-    if (FAILED(hr)) { return hr; }

-

-    hr = (*app_element)->appendChild(components_node, NULL);

-    if (FAILED(hr)) { return hr; }

-

-    AppRequestDataVector::const_iterator it;

-    for (it = app_request.components_begin();

-         it != app_request.components_end();

-         ++it) {

-      const AppRequestData& component_request_data = *it;

-      const AppData& component_app_data = component_request_data.app_data();

-      CComPtr<IXMLDOMNode> component_node;

-      hr = CreateRequestElement(Xml::Element::kComponent,

-                                _T(""),

-                                document,

-                                &component_node);

-      if (FAILED(hr)) { return hr; }

-

-      hr = AddXMLAttributeNode(component_node,

-                               Xml::Namespace::kRequest,

-                               Xml::Attribute::kAppId,

-                               GuidToString(component_app_data.app_guid()));

-      if (FAILED(hr)) { return hr; }

-

-      hr = AddXMLAttributeNode(component_node,

-                               Xml::Namespace::kRequest,

-                               Xml::Attribute::kVersion,

-                               component_app_data.version());

-      if (FAILED(hr)) { return hr; }

-

-      hr = components_node->appendChild(component_node, NULL);

-      if (FAILED(hr)) { return hr; }

-

-      // TODO(omaha):  Create and add event elements to the component element

-      // by traversing the ping_events within component_request_data.

-      // Probably want to make the PingEvent traversal from below into a

-      // separate function.

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::CreateUpdateAppRequestElement(

-    const AppRequest& app_request,

-    IXMLDOMDocument* document,

-    IXMLDOMNode** app_element) {

-  HRESULT hr = CreateAppRequestElementHelper(app_request,

-                                             document,

-                                             app_element);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  const AppData& app_data = app_request.request_data().app_data();

-

-  // update check element

-  CComPtr<IXMLDOMNode> update_check;

-  hr = CreateRequestElement(Xml::Element::kUpdateCheck,

-                            _T(""),

-                            document,

-                            &update_check);

-  if (FAILED(hr)) { return hr; }

-

-  if (app_data.is_update_disabled()) {

-    hr = AddXMLAttributeNode(update_check,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kUpdateDisabled,

-                             Xml::Value::kTrue);

-    if (FAILED(hr)) { return hr; }

-  }

-

-  // tag is optional

-  if (!app_data.ap().IsEmpty()) {

-    hr = AddXMLAttributeNode(update_check,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kTag,

-                             app_data.ap());

-    if (FAILED(hr)) { return hr; }

-  }

-

-  // Add the Trusted Tester token under the "updatecheck" element.

-  if (!app_data.tt_token().IsEmpty()) {

-    hr = AddXMLAttributeNode(update_check,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kTTToken,

-                             app_data.tt_token());

-    if (FAILED(hr)) { return hr; }

-  }

-

-  hr = (*app_element)->appendChild(update_check, NULL);

-  if (FAILED(hr)) { return hr; }

-

-  if (!app_data.install_data_index().IsEmpty()) {

-    // data element.

-    CComPtr<IXMLDOMNode> install_data;

-    hr = CreateRequestElement(Xml::Element::kData,

-                              _T(""),

-                              document,

-                              &install_data);

-    if (FAILED(hr)) { return hr; }

-

-    hr = AddXMLAttributeNode(install_data,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kName,

-                             Xml::Value::kInstallData);

-    if (FAILED(hr)) { return hr; }

-

-    hr = AddXMLAttributeNode(install_data,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kIndex,

-                             app_data.install_data_index());

-    if (FAILED(hr)) { return hr; }

-

-    hr = (*app_element)->appendChild(install_data, NULL);

-    if (FAILED(hr)) { return hr; }

-  }

-

-  AppData::ActiveStates active = app_data.did_run();

-  if (active != AppData::ACTIVE_UNKNOWN) {

-    // didrun element. The server calls it "ping" for legacy reasons.

-    CComPtr<IXMLDOMNode> ping;

-    hr = CreateRequestElement(Xml::Element::kPing,

-                              _T(""),

-                              document,

-                              &ping);

-    if (FAILED(hr)) { return hr; }

-

-    const TCHAR* active_str(active == AppData::ACTIVE_RUN ?

-                            _T("1") :

-                            _T("0"));

-    hr = AddXMLAttributeNode(ping,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kActive,

-                             active_str);

-    if (FAILED(hr)) { return hr; }

-

-    hr = (*app_element)->appendChild(ping, NULL);

-    if (FAILED(hr)) { return hr; }

-  }

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::CreatePingAppRequestElement(

-    const AppRequest& app_request,

-    IXMLDOMDocument* document,

-    IXMLDOMNode** app_element) {

-  HRESULT hr = CreateAppRequestElementHelper(app_request,

-                                             document,

-                                             app_element);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // create and add Ping elements to the app element. Server calls ping elements

-  // "event" elements for legacy reasons.

-  std::vector<PingEvent>::const_iterator it;

-  for (it = app_request.request_data().ping_events_begin();

-       it != app_request.request_data().ping_events_end();

-       ++it) {

-    const PingEvent& app_event = *it;

-    CComPtr<IXMLDOMNode> ev;

-    hr = CreateRequestElement(Xml::Element::kEvent,

-                              _T(""),

-                              document,

-                              &ev);

-    if (FAILED(hr)) { return hr; }

-    CString str;

-    str.Format(_T("%d"), app_event.event_type());

-    hr = AddXMLAttributeNode(ev,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kEventType,

-                             str);

-    if (FAILED(hr)) { return hr; }

-    str.Format(_T("%d"), app_event.event_result());

-    hr = AddXMLAttributeNode(ev,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kEventResult,

-                             str);

-    if (FAILED(hr)) { return hr; }

-    str.Format(_T("%d"), app_event.error_code());

-    hr = AddXMLAttributeNode(ev,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kErrorCode,

-                             str);

-    if (FAILED(hr)) { return hr; }

-    str.Format(_T("%d"), app_event.extra_code1());

-    hr = AddXMLAttributeNode(ev,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kExtraCode1,

-                             str);

-    if (FAILED(hr)) { return hr; }

-    str = app_event.previous_version();

-    if (!str.IsEmpty()) {

-      hr = AddXMLAttributeNode(ev,

-                               Xml::Namespace::kRequest,

-                               Xml::Attribute::kPreviousVersion,

-                               str);

-      if (FAILED(hr)) { return hr; }

-    }

-

-    hr = (*app_element)->appendChild(ev, NULL);

-    if (FAILED(hr)) { return hr; }

-  }

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::GenerateRequest(const Request& req,

-                                           bool is_update_check,

-                                           CString* request_buffer) {

-  CORE_LOG(L3, (_T("[GenerateRequest]")));

-  ASSERT1(request_buffer);

-  if (!request_buffer) {

-    return E_INVALIDARG;

-  }

-

-  // Create the XML document.

-  CComPtr<IXMLDOMDocument> document;

-  HRESULT hr = CoCreateSafeDOMDocument(&document);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[CoCreateSafeDOMDocument failed][0x%x]"), hr));

-    return hr;

-  }

-

-  // Create the AppRequests Element.

-  CComPtr<IXMLDOMNode> update_requests;

-  hr = CreateRequestElement(Xml::Element::kRequests,

-                            _T(""),

-                            document,

-                            &update_requests);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[CreateRequestElement failed][0x%x]"), hr));

-    return hr;

-  }

-

-  // Add the update requests node to the document.

-  CComPtr<IXMLDOMElement> update_requests_node;

-  hr = update_requests->QueryInterface(&update_requests_node);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[update_requests->QueryInterface][0x%x]"), hr));

-    return hr;

-  }

-  hr = document->putref_documentElement(update_requests_node);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[putref_documentElement failed][0x%x]"), hr));

-    return hr;

-  }

-

-  // add attributes to the top element:

-  // * protocol - protocol version

-  // * version - omaha version

-  // * machineid - per machine guid

-  // * userid - per user guid

-  // * testsource - test source

-  // * requestid - Unique request id

-  hr = AddXMLAttributeNode(update_requests,

-                           Xml::Namespace::kRequest,

-                           Xml::Attribute::kProtocol,

-                           Xml::Value::kProtocol);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[AddXMLAttributeNode failed][0x%x]"), hr));

-    return hr;

-  }

-  hr = AddXMLAttributeNode(update_requests,

-                           Xml::Namespace::kRequest,

-                           Xml::Attribute::kVersion,

-                           req.version());

-  if (FAILED(hr)) { return hr; }

-  hr = AddXMLAttributeNode(update_requests,

-                           Xml::Namespace::kRequest,

-                           Xml::Attribute::kIsMachine,

-                           req.is_machine() ? _T("1") : _T("0"));

-  if (FAILED(hr)) { return hr; }

-  hr = AddXMLAttributeNode(update_requests,

-                           Xml::Namespace::kRequest,

-                           Xml::Attribute::kMachineId,

-                           req.machine_id());

-  if (FAILED(hr)) { return hr; }

-  hr = AddXMLAttributeNode(update_requests,

-                           Xml::Namespace::kRequest,

-                           Xml::Attribute::kUserId,

-                           req.user_id());

-  if (FAILED(hr)) { return hr; }

-  if (!req.test_source().IsEmpty()) {

-    hr = AddXMLAttributeNode(update_requests,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kTestSource,

-                             req.test_source());

-    if (FAILED(hr)) { return hr; }

-  }

-  if (!req.request_id().IsEmpty()) {

-    hr = AddXMLAttributeNode(update_requests,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kRequestId,

-                             req.request_id());

-    if (FAILED(hr)) { return hr; }

-  }

-

-  bool is_period_overridden = false;

-  const int check_period_sec =

-      ConfigManager::Instance()->GetLastCheckPeriodSec(&is_period_overridden);

-  if (is_period_overridden) {

-    hr = AddXMLAttributeNode(update_requests,

-                             Xml::Namespace::kRequest,

-                             Xml::Attribute::kPeriodOverrideSec,

-                             itostr(check_period_sec));

-    ASSERT1(SUCCEEDED(hr));

-  }

-

-  // Create os elements and add to the requests element.

-  CComPtr<IXMLDOMNode> os_element;

-  hr = CreateRequestElement(Xml::Element::kOs, _T(""), document, &os_element);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[CreateRequestElement failed][0x%x]"), hr));

-    return hr;

-  }

-  hr = AddXMLAttributeNode(os_element,

-                           Xml::Namespace::kRequest,

-                           Xml::Attribute::kPlatform,

-                           kPlatformWin);

-  hr = AddXMLAttributeNode(os_element,

-                           Xml::Namespace::kRequest,

-                           Xml::Attribute::kVersion,

-                           req.os_version());

-  hr = AddXMLAttributeNode(os_element,

-                           Xml::Namespace::kRequest,

-                           Xml::Attribute::kServicePack,

-                           req.os_service_pack());

-  if (FAILED(hr)) { return hr; }

-  hr = update_requests->appendChild(os_element, NULL);

-  if (FAILED(hr)) { return hr; }

-

-  // Create and add request's to the requests node.

-  AppRequestVector::const_iterator i;

-  for (i = req.app_requests_begin(); i != req.app_requests_end(); ++i) {

-    const AppRequest& app_request = *i;

-    // Create each of the request elements and add to the requests element.

-    CComPtr<IXMLDOMNode> request_element;

-    hr = is_update_check ?

-         CreateUpdateAppRequestElement(app_request,

-                                       document,

-                                       &request_element) :

-         CreatePingAppRequestElement(app_request,

-                                     document,

-                                     &request_element);

-    if (FAILED(hr)) { return hr; }

-

-    // Add the update request node to the AppRequests node.

-    hr = update_requests->appendChild(request_element, NULL);

-    if (FAILED(hr)) { return hr; }

-  }

-

-  // Extract the string out of the DOM, and add the initial processing

-  // instruction. We cannot use the xml processing instruction as the get_xml

-  // method returns utf-16 encoded string which causes the utf-8 marker to be

-  // removed. We will convert to utf-8 before the actual save.

-  CComBSTR xml_value(Xml::kHeaderText);

-  CComBSTR xml_body;

-  document->get_xml(&xml_body);

-  xml_value += xml_body;

-

-  *request_buffer = static_cast<TCHAR*>(xml_value);

-

-  return S_OK;

-}

-

-HRESULT GoopdateXmlParser::LoadXmlFileToMemory(const CString& file_name,

-                                               CString* buffer) {

-  ASSERT1(buffer);

-

-  CComPtr<IXMLDOMDocument> document;

-  HRESULT hr = LoadXMLFromFile(file_name, false, &document);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return SaveXMLToMemory(document, buffer);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// goopdate_xml_parser for parsing the xml manifest files that are compiled
+// into the meta-installer and sent by the auto-update server.
+
+#include "omaha/goopdate/goopdate_xml_parser.h"
+
+#include <stdlib.h>
+#include <msxml2.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/error.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/xml_utils.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/goopdate_metrics.h"
+#include "omaha/goopdate/goopdate_utils.h"
+
+namespace omaha {
+
+namespace {
+
+// Loads the specified document and obtains the DOM and Element interfaces.
+HRESULT GetDocumentDomAndElement(const CString& file_name,
+                                 IXMLDOMDocument** document,
+                                 IXMLDOMElement** document_element) {
+  CORE_LOG(L3, (_T("[GetDocumentDomAndElement]")));
+  ASSERT1(document);
+  ASSERT1(document_element);
+
+  HRESULT hr = LoadXMLFromFile(file_name, true, document);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[LoadXMLFromFile failed][0x%x]"), hr));
+    return hr;
+  }
+
+  hr = (*document)->get_documentElement(document_element);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[get_documentElement failed][0x%x]"), hr));
+    return hr;
+  }
+  if (!*document_element) {  // Protect against msxml S_FALSE return.
+    CORE_LOG(LE, (_T("[*document_element is NULL]")));
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+// Loads the specified document and obtains the DOM interface.
+HRESULT GetDocumentElement(const CString& file_name,
+                           IXMLDOMElement** document_element) {
+  CComPtr<IXMLDOMDocument> document;
+  return GetDocumentDomAndElement(file_name, &document, document_element);
+}
+
+}  // namespace
+
+
+const int kGuidLen = 38;
+CString GoopdateXmlParser::seed_protocol_version;
+
+// Constants for creating the xml request.
+namespace Xml {
+  const TCHAR* const kHeaderText =
+    _T("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+  const TCHAR* const kProcessingText =
+    _T("version=\"1.0\" encoding=\"UTF-8\"");
+
+  namespace Namespace {
+    const TCHAR* const kRequest = _T("http://www.google.com/update2/request");
+    const TCHAR* const kResponse = _T("http://www.google.com/update2/response");
+    const TCHAR* const kSeed = _T("http://www.google.com/update2/install");
+  }
+  namespace Element {
+    const TCHAR* const kXml = _T("xml");
+    const TCHAR* const kRequests = _T("gupdate");
+    const TCHAR* const kOmahaVersion = _T("updaterversion");
+    const TCHAR* const kOs = _T("os");
+    const TCHAR* const kApp = _T("app");
+    const TCHAR* const kUpdateCheck = _T("updatecheck");
+    const TCHAR* const kPing = _T("ping");
+    const TCHAR* const kEvent = _T("event");
+    const TCHAR* const kComponents = _T("components");
+    const TCHAR* const kComponent = _T("component");
+
+    const TCHAR* const kResponses = _T("gupdate");
+    const TCHAR* const kData = _T("data");
+
+    const TCHAR* const kInstall = _T("install");
+    const TCHAR* const kResponse = _T("response");
+    const TCHAR* const kNameValue = _T("attr");
+  }
+  namespace Attribute {
+    const TCHAR* const kActive = _T("active");
+    const TCHAR* const kAdditionalParameter = _T("ap");
+    const TCHAR* const kAppGuid = _T("appguid");
+    const TCHAR* const kApplicationName = _T("appname");
+    const TCHAR* const kAppId = _T("appid");
+    const TCHAR* const kArguments = _T("arguments");
+    const TCHAR* const kBrandCode = _T("brand");
+    const TCHAR* const kBrowserType = _T("browser");
+    const TCHAR* const kClientId = _T("client");
+    const TCHAR* const kCodebase = _T("codebase");
+    const TCHAR* const kCountry = _T("country");
+    const TCHAR* const kErrorCode = _T("errorcode");
+    const TCHAR* const kEventResult = _T("eventresult");
+    const TCHAR* const kEventType = _T("eventtype");
+    const TCHAR* const kErrorUrl = _T("errorurl");
+    const TCHAR* const kExtraCode1 = _T("extracode1");
+    const TCHAR* const kHash = _T("hash");
+    const TCHAR* const kIndex = _T("index");
+    const TCHAR* const kInstalledAgeDays = _T("installage");
+    const TCHAR* const kIsMachine = _T("ismachine");
+    const TCHAR* const kInstallationId = _T("iid");
+    const TCHAR* const kInstallSource = _T("installsource");
+    const TCHAR* const kLang = _T("lang");
+    const TCHAR* const kMachineId = _T("machineid");
+    const TCHAR* const kName = _T("name");
+    const TCHAR* const kNeedsAdmin = _T("needsadmin");
+    const TCHAR* const kParameter = _T("parameter");
+    const TCHAR* const kPeriodOverrideSec = _T("periodoverridesec");
+    const TCHAR* const kPlatform = _T("platform");
+    const TCHAR* const kPreviousVersion = _T("previousversion");
+    const TCHAR* const kProtocol = _T("protocol");
+    const TCHAR* const kRequestId  = _T("requestid");
+    const TCHAR* const kServicePack = _T("sp");
+    const TCHAR* const kSessionId = _T("sessionid");
+    const TCHAR* const kSignature = _T("signature");
+    const TCHAR* const kSize = _T("size");
+    const TCHAR* const kStatus = _T("status");
+    const TCHAR* const kSuccessAction = _T("onsuccess");
+    const TCHAR* const kSuccessUrl = _T("successurl");
+    const TCHAR* const kTag = _T("tag");
+    const TCHAR* const kTestSource = _T("testsource");
+    const TCHAR* const kTerminateAllBrowsers = _T("terminateallbrowsers");
+    const TCHAR* const kTTToken = _T("tttoken");
+    const TCHAR* const kUpdateDisabled = _T("updatedisabled");
+    const TCHAR* const kUserId = _T("userid");
+    const TCHAR* const kVersion = _T("version");
+    const TCHAR* const kXmlns = _T("xmlns");
+  }
+
+  namespace Value {
+    const TCHAR* const kRequestType = _T("UpdateRequest");
+    const TCHAR* const kProtocol = _T("2.0");
+    const TCHAR* const kVersion2 = _T("2.0");
+    const TCHAR* const kVersion3 = _T("3.0");
+    const TCHAR* const kTrue = _T("true");
+    const TCHAR* const kFalse = _T("false");
+    const TCHAR* const kStatusError = _T("error");
+    const TCHAR* const kSuccessActionDefault = _T("default");
+    const TCHAR* const kSuccessActionExitSilently = _T("exitsilently");
+    const TCHAR* const kSuccessActionExitSilentlyOnLaunchCmd =
+        _T("exitsilentlyonlaunchcmd");
+
+    const TCHAR* const kStatusOk = kResponseStatusOkValue;
+    const TCHAR* const kInstallData = _T("install");
+  }
+}
+
+SuccessfulInstallAction GoopdateXmlParser::ConvertStringToSuccessAction(
+    const CString& text) {
+  if (text.IsEmpty() ||
+      _tcsicmp(text, Xml::Value::kSuccessActionDefault) == 0) {
+    return SUCCESS_ACTION_DEFAULT;
+  } else if (_tcsicmp(text, Xml::Value::kSuccessActionExitSilently) == 0) {
+    return SUCCESS_ACTION_EXIT_SILENTLY;
+  } else if (_tcsicmp(text,
+                      Xml::Value::kSuccessActionExitSilentlyOnLaunchCmd) == 0) {
+    return SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD;
+  } else {
+    ASSERT(false, (_T("[Unrecognized success action][%s]"), text));
+    // Use the default action. This allows Omaha to be forward-compatible with
+    // new SuccessActions, meaning older versions will not fail if a config
+    // uses a new action.
+    return SUCCESS_ACTION_DEFAULT;
+  }
+}
+
+// Implementation of the GoopdateXmlParser.
+HRESULT GoopdateXmlParser::ReadBooleanAttribute(IXMLDOMNode* node,
+                                                const TCHAR* attr_name,
+                                                bool* value) {
+  CORE_LOG(L3, (_T("[ReadBooleanAttribute][%s]"), attr_name));
+  ASSERT1(node != NULL);
+  ASSERT1(attr_name != NULL);
+  ASSERT1(value != NULL);
+
+  CComBSTR node_value;
+  HRESULT hr = ReadAttribute(node, attr_name, &node_value);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ReadAttribute failed][%s][0x%x]"), attr_name, hr));
+    return hr;
+  }
+
+  hr = String_StringToBool(static_cast<TCHAR*>(node_value),
+                           value);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[String_StringToBool failed][0x%x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::ReadIntAttribute(IXMLDOMNode* node,
+                                            const TCHAR* attr_name,
+                                            int* value) {
+  CORE_LOG(L3, (_T("[ReadIntAttribute][%s]"), attr_name));
+  ASSERT1(node != NULL);
+  ASSERT1(attr_name != NULL);
+  ASSERT1(value != NULL);
+
+  CComBSTR node_value;
+  HRESULT hr = ReadAttribute(node, attr_name, &node_value);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ReadAttribute failed][%s][0x%x]"), attr_name, hr));
+    return hr;
+  }
+
+  if (!String_StringToDecimalIntChecked(
+          static_cast<const TCHAR*>(node_value), value)) {
+          return GOOPDATEXML_E_STRTOUINT;
+  }
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::ReadGuidAttribute(IXMLDOMNode* node,
+                                             const TCHAR* attr_name,
+                                             GUID* value) {
+  CORE_LOG(L3, (_T("[ReadGuidAttribute][%s]"), attr_name));
+  ASSERT1(node != NULL);
+  ASSERT1(attr_name != NULL);
+  ASSERT1(value != NULL);
+
+  CComBSTR node_value;
+  HRESULT hr = ReadAttribute(node, attr_name, &node_value);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ReadAttribute failed][%s][0x%x]"), attr_name, hr));
+    return hr;
+  }
+
+  hr = ::CLSIDFromString(static_cast<TCHAR*>(node_value), value);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[CLSIDFromString failed][0x%x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::ReadStringAttribute(IXMLDOMNode* node,
+                                               const TCHAR* attr_name,
+                                               CString* value) {
+  CORE_LOG(L3, (_T("[ReadStringAttribute][%s]"), attr_name));
+  ASSERT1(node != NULL);
+  ASSERT1(attr_name != NULL);
+  ASSERT1(value != NULL);
+
+  CComBSTR node_value;
+  HRESULT hr = ReadAttribute(node, attr_name, &node_value);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ReadAttribute failed][%s][0x%x]"), attr_name, hr));
+    return hr;
+  }
+
+  // Will extract the underlying string.
+  *value = static_cast<TCHAR*>(node_value);
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::ReadAttribute(IXMLDOMNode* node,
+                                         const TCHAR* attr_name,
+                                         BSTR* value) {
+  CORE_LOG(L4, (_T("[ReadAttribute][%s]"), attr_name));
+  ASSERT1(node != NULL);
+  ASSERT1(attr_name != NULL);
+  ASSERT1(value != NULL);
+
+  // First read the attributes.
+  CComPtr<IXMLDOMNamedNodeMap> attributes;
+  HRESULT hr = node->get_attributes(&attributes);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[get_attributes failed][0x%x]"), hr));
+    return hr;
+  }
+
+  if (!attributes) {
+    CORE_LOG(LE, (_T("[Msxml S_FALSE return.]")));
+    return E_FAIL;  // Protect against msxml S_FALSE return.
+  }
+
+  CComPtr<IXMLDOMNode> attribute_node;
+  CComVariant node_value;
+  CComBSTR temp_attr_name(attr_name);
+
+  // Get the attribute using a named node.
+  hr = attributes->getNamedItem(static_cast<BSTR>(temp_attr_name),
+                                &attribute_node);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[getNamedItem failed][0x%x]"), hr));
+    return hr;
+  }
+
+  if (!attribute_node) {
+    CORE_LOG(LE, (_T("[Msxml S_FALSE return.]")));
+    return E_FAIL;  // Protect against msxml S_FALSE return.
+  }
+
+  hr = attribute_node->get_nodeValue(&node_value);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[get_nodeValue failed][0x%x]"), hr));
+    return hr;
+  }
+
+  if (node_value.vt == VT_EMPTY) {
+    CORE_LOG(LE, (_T("[node_value.vt == VT_EMPTY]")));
+    return E_FAIL;
+  }
+
+  // Extract the variant into a BSTR.
+  node_value.CopyTo(value);
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::ReadStringValue(IXMLDOMNode* node,
+                                           CString* value) {
+  CORE_LOG(L4, (_T("[ReadStringValue]")));
+  ASSERT1(node != NULL);
+  ASSERT1(value != NULL);
+
+  CComPtr<IXMLDOMNodeList> child_nodes;
+  HRESULT hr = node->get_childNodes(&child_nodes);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[get_childNodes failed][0x%x]"), hr));
+    return hr;
+  }
+  if (!child_nodes) {
+    CORE_LOG(LE, (_T("[Msxml S_FALSE return.]")));
+    return E_FAIL;  // Protect against msxml S_FALSE return.
+  }
+
+  long count = 0;  // NOLINT
+  hr = child_nodes->get_length(&count);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ASSERT(count == 1, (_T("count: %u"), count));
+  CComPtr<IXMLDOMNode> child_node;
+  hr = child_nodes->nextNode(&child_node);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  DOMNodeType type = NODE_INVALID;
+  hr = child_node->get_nodeType(&type);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[get_nodeType failed][0x%x]"), hr));
+    return hr;
+  }
+
+  if (type != NODE_TEXT) {
+    CORE_LOG(LE, (_T("[Invalid nodeType][%d]"), type));
+    return E_INVALIDARG;
+  }
+
+  CComVariant node_value;
+  hr = child_node->get_nodeValue(&node_value);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[get_nodeValue failed][0x%x]"), hr));
+    return hr;
+  }
+
+  if (node_value.vt != VT_BSTR) {
+    CORE_LOG(LE, (_T("[node_value.vt != VT_BSTR][%d]"), node_value.vt));
+    return E_INVALIDARG;
+  }
+
+  *value = V_BSTR(&node_value);
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::ReadUpdateResponse(IXMLDOMNode* node,
+                                              UpdateResponse* response) {
+  CORE_LOG(L4, (_T("[ReadUpdateResponse]")));
+  ASSERT1(node != NULL);
+  ASSERT1(response != NULL);
+
+  UpdateResponseData response_data;
+
+  // Read GUID first since we need the GUID even on errors in order
+  // to remove the corresponding request from the jobs list.
+  GUID guid = {0};
+  HRESULT hr = ReadGuidAttribute(node, Xml::Attribute::kAppId, &guid);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ReadGuidAttribute failed][0x%x]"), hr));
+    return hr;
+  }
+  response_data.set_guid(guid);
+
+  CString str;
+  // Any response status but "ok" for the "app" element stops the "parsing".
+  hr = ReadStringAttribute(node, Xml::Attribute::kStatus, &str);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ReadStringAttribute failed][0x%x]"), hr));
+    return hr;
+  }
+  if (str != Xml::Value::kStatusOk) {
+    response_data.set_status(str);
+    response->set_update_response_data(response_data);
+    return S_OK;
+  }
+
+  // Now try and read the children nodes of the response.
+  CComPtr<IXMLDOMNodeList> child_nodes;
+  // Get all the children of the document.
+  hr = node->get_childNodes(&child_nodes);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[get_childNodes failed][0x%x]"), hr));
+    return hr;
+  }
+  if (!child_nodes) {
+    CORE_LOG(LE, (_T("[Msxml S_FALSE return.]")));
+    return E_FAIL;  // Protect against msxml S_FALSE return.
+  }
+
+  // Go over all the children and handle the children. We ignore all the
+  // children that we do not understand. Note that we expect the nodes that
+  // we want to be present. Although we are not enforcing this for now.
+  CComPtr<IXMLDOMNode> child_node;
+  while (child_nodes->nextNode(&child_node) != S_FALSE) {
+    XMLFQName node_name;
+    hr = GetXMLFQName(child_node, &node_name);
+    if (FAILED(hr)) {
+      CORE_LOG(LE, (_T("[GetXMLFQName failed][0x%x]"), hr));
+      return hr;
+    }
+
+    if (node_name.base == Xml::Element::kUpdateCheck) {
+      hr = ReadStringAttribute(child_node, Xml::Attribute::kTTToken, &str);
+      if (SUCCEEDED(hr) && !str.IsEmpty()) {
+        response_data.set_tt_token(str);
+      }
+
+      hr = ReadStringAttribute(child_node, Xml::Attribute::kStatus, &str);
+      if (FAILED(hr)) { return hr; }
+      response_data.set_status(str);
+
+      if (str == Xml::Value::kStatusOk) {
+        int size = 0;
+        hr = ReadIntAttribute(child_node, Xml::Attribute::kSize, &size);
+        if (FAILED(hr)) { return hr; }
+        if (size < 0) {
+          return GOOPDATEXML_E_STRTOUINT;
+        }
+        response_data.set_size(size);
+
+        hr = ReadStringAttribute(child_node, Xml::Attribute::kHash, &str);
+        if (FAILED(hr)) { return hr; }
+        response_data.set_hash(str);
+
+        hr = ReadStringAttribute(child_node, Xml::Attribute::kCodebase, &str);
+        if (FAILED(hr)) { return hr; }
+        response_data.set_url(str);
+
+        hr = ReadStringAttribute(child_node, Xml::Attribute::kNeedsAdmin, &str);
+        if (FAILED(hr)) { return hr; }
+        NeedsAdmin needs_admin;
+        hr = goopdate_utils::ConvertStringToNeedsAdmin(str, &needs_admin);
+        if (FAILED(hr)) { return hr; }
+        response_data.set_needs_admin(needs_admin);
+
+        hr = ReadStringAttribute(child_node, Xml::Attribute::kArguments, &str);
+        // arguments is optional
+        if (SUCCEEDED(hr)) {
+          response_data.set_arguments(str);
+        }
+
+        hr = ReadStringAttribute(child_node, Xml::Attribute::kSuccessUrl, &str);
+        if (SUCCEEDED(hr)) {
+          response_data.set_success_url(str);
+        }
+
+        bool terminate_all_browsers = false;
+        hr = ReadBooleanAttribute(child_node,
+                                  Xml::Attribute::kTerminateAllBrowsers,
+                                  &terminate_all_browsers);
+        if (SUCCEEDED(hr)) {
+          response_data.set_terminate_all_browsers(terminate_all_browsers);
+        }
+
+        hr = ReadStringAttribute(child_node,
+                                 Xml::Attribute::kSuccessAction,
+                                 &str);
+        if (SUCCEEDED(hr)) {
+          response_data.set_success_action(ConvertStringToSuccessAction(str));
+        }
+
+        // If no version exists in the server response, we will still indicate
+        // when an update is available. However, we will not provide version
+        // information to any JobObserver.
+        hr = ReadStringAttribute(child_node,
+                                 Xml::Attribute::kVersion,
+                                 &str);
+        if (SUCCEEDED(hr)) {
+          response_data.set_version(str);
+        }
+      }
+
+      // Always look for the error URL because it is used in errors.
+      hr = ReadStringAttribute(child_node, Xml::Attribute::kErrorUrl, &str);
+      if (SUCCEEDED(hr)) {
+        response_data.set_error_url(str);
+      }
+    } else if (node_name.base == Xml::Element::kData) {
+      hr = ReadStringAttribute(child_node, Xml::Attribute::kStatus, &str);
+      if (FAILED(hr)) {
+        return hr;
+      }
+
+      if (str == Xml::Value::kStatusOk) {
+        // <data name="install" index="foo" status="ok">foo bar</data>.
+        hr = ReadStringAttribute(child_node, Xml::Attribute::kName, &str);
+        if (FAILED(hr)) {
+          return hr;
+        }
+        if (str.CompareNoCase(Xml::Value::kInstallData)) {
+          CORE_LOG(LW, (_T("[Skipping unsupported data][%s]"), str));
+          continue;
+        }
+
+        CString install_data_index;
+        hr = ReadStringAttribute(child_node,
+                                 Xml::Attribute::kIndex,
+                                 &install_data_index);
+        if (FAILED(hr)) {
+          return hr;
+        }
+
+        CString install_data;
+        hr = ReadStringValue(child_node, &install_data);
+        if (FAILED(hr)) {
+          return hr;
+        }
+        response_data.SetInstallData(install_data_index, install_data);
+      }
+    } else if (node_name.base == Xml::Element::kPing) {
+      // nothing to do here (yet)
+    } else if (node_name.base == Xml::Element::kEvent) {
+      // nothing to do here (yet)
+    } else if (node_name.base == Xml::Element::kComponents) {
+      VERIFY1(SUCCEEDED(ReadComponentsResponses(child_node, response)));
+    }
+    child_node = NULL;
+  }
+
+  response->set_update_response_data(response_data);
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::ReadComponentsResponses(IXMLDOMNode* node,
+                                                   UpdateResponse* response) {
+  CORE_LOG(L4, (_T("[ReadComponentsResponses]")));
+  ASSERT1(node);
+  ASSERT1(response);
+
+  CComPtr<IXMLDOMNodeList> child_nodes;
+  HRESULT hr = node->get_childNodes(&child_nodes);
+  if (FAILED(hr)) { return hr; }
+  // If S_FALSE, then there are no children components.
+  if (S_FALSE == hr) { return S_OK; }
+
+  CComPtr<IXMLDOMNode> child_node;
+  while (child_nodes->nextNode(&child_node) != S_FALSE) {
+    XMLFQName node_name;
+    hr = GetXMLFQName(child_node, &node_name);
+    if (FAILED(hr)) { return hr; }
+
+    if (node_name.base == Xml::Element::kComponent) {
+      UpdateResponseData component_response_data;
+      hr = ReadComponentResponseData(child_node, &component_response_data);
+      if (FAILED(hr)) { return hr; }
+      response->AddComponentResponseData(component_response_data);
+    } else {
+      ASSERT1(false);
+    }
+
+    child_node = NULL;
+  }
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::ReadComponentResponseData(
+    IXMLDOMNode* node,
+    UpdateResponseData* response_data) {
+  CORE_LOG(L4, (_T("[ReadComponentsResponseData]")));
+  // TODO(omaha): consolidate component/product parsing. They have several
+  // similar attributes.
+  // Read GUID first since we need the GUID even on errors in order to remove
+  // the corresponding request from the jobs list.
+  GUID guid = {0};
+  HRESULT hr = ReadGuidAttribute(node, Xml::Attribute::kAppId, &guid);
+  if (FAILED(hr)) { return hr; }
+  response_data->set_guid(guid);
+
+  // Any response status but "ok" for the "app" element stops the "parsing".
+  CString str;
+  hr = ReadStringAttribute(node, Xml::Attribute::kStatus, &str);
+  if (FAILED(hr)) { return hr; }
+  if (str != Xml::Value::kStatusOk) {
+    response_data->set_status(str);
+    return S_OK;
+  }
+
+  // Now try and read the children nodes of the response.
+  CComPtr<IXMLDOMNodeList> child_nodes;
+  // Get all the children of the document.
+  hr = node->get_childNodes(&child_nodes);
+  if (FAILED(hr)) { return hr; }
+  if (!child_nodes) { return E_FAIL; }  // Protect against msxml S_FALSE return.
+
+  // Go over all the children and handle the children. We ignore all the
+  // children that we do not understand. Note that we expect the nodes that
+  // we want to be present. Although we are not enforcing this for now.
+  CComPtr<IXMLDOMNode> child_node;
+  while (child_nodes->nextNode(&child_node) != S_FALSE) {
+    XMLFQName node_name;
+    hr = GetXMLFQName(child_node, &node_name);
+    if (FAILED(hr)) { return hr; }
+
+    if (node_name.base == Xml::Element::kUpdateCheck) {
+      hr = ReadStringAttribute(child_node, Xml::Attribute::kStatus, &str);
+      if (FAILED(hr)) { return hr; }
+      response_data->set_status(str);
+      // TODO(omaha):  Check why we have kStatusOk at both levels of the XML
+      // (same for product parsing) and consolidate/remove as necessary.
+      if (str == Xml::Value::kStatusOk) {
+        int size = 0;
+        hr = ReadIntAttribute(child_node, Xml::Attribute::kSize, &size);
+        if (FAILED(hr)) { return hr; }
+        if (size < 0) {
+          return GOOPDATEXML_E_STRTOUINT;
+        }
+        response_data->set_size(size);
+
+        hr = ReadStringAttribute(child_node, Xml::Attribute::kHash, &str);
+        if (FAILED(hr)) { return hr; }
+        response_data->set_hash(str);
+
+        hr = ReadStringAttribute(child_node, Xml::Attribute::kCodebase, &str);
+        if (FAILED(hr)) { return hr; }
+        response_data->set_url(str);
+
+        hr = ReadStringAttribute(child_node, Xml::Attribute::kArguments, &str);
+        // arguments is optional
+        if (SUCCEEDED(hr)) {
+          response_data->set_arguments(str);
+        }
+      }
+    } else {
+      ASSERT1(false);
+    }
+
+    child_node = NULL;
+  }
+
+  return S_OK;
+}
+
+// This exists only to support handoffs from 1.0.x and 1.1.x metainstallers.
+HRESULT GoopdateXmlParser::ReadInstallElement(
+    IXMLDOMNode* node,
+    UpdateResponseData* response_data) {
+  ASSERT1(node);
+  ASSERT1(response_data);
+
+  HRESULT hr = ReadRequiredInstallAttributes(node, response_data);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return ReadOptionalInstallAttributes(node, response_data);
+}
+
+// This exists only to support handoffs from 1.0.x and 1.1.x metainstallers.
+HRESULT GoopdateXmlParser::ReadRequiredInstallAttributes(
+    IXMLDOMNode* node,
+    UpdateResponseData* response_data) {
+  ASSERT1(node);
+  ASSERT1(response_data);
+
+  // Read the guid and whether the application needs admin. Both the attributes
+  // are required.
+  GUID guid_value = {0};
+  HRESULT hr = ReadGuidAttribute(node, Xml::Attribute::kAppGuid,
+                                 &guid_value);
+  if (FAILED(hr)) { return hr; }
+
+  response_data->set_guid(guid_value);
+
+  CString needs_admin_str;
+  hr = ReadStringAttribute(node, Xml::Attribute::kNeedsAdmin,
+                           &needs_admin_str);
+  if (FAILED(hr)) { return hr; }
+
+  NeedsAdmin needs_admin;
+  hr = goopdate_utils::ConvertStringToNeedsAdmin(needs_admin_str, &needs_admin);
+  if (FAILED(hr)) { return hr; }
+
+  response_data->set_needs_admin(needs_admin);
+
+  // We only read the language and the application name from the seed manifest
+  // if the version of the seed manifest is greater than 2.0.
+  if (String_StringToDouble(seed_protocol_version) >
+      String_StringToDouble(Xml::Value::kVersion2)) {
+    ++metric_handoff_legacy_11;
+
+    CString app_name;
+    hr = ReadStringAttribute(node, Xml::Attribute::kApplicationName, &app_name);
+    if (FAILED(hr)) { return hr; }
+    response_data->set_app_name(app_name);
+
+    CString language;
+    hr = ReadStringAttribute(node, Xml::Attribute::kLang, &language);
+    if (FAILED(hr)) { return hr; }
+    response_data->set_language(language);
+  } else {
+    ++metric_handoff_legacy_10;
+  }
+
+  return S_OK;
+}
+
+// Since all of these attributes are optional, read failures do not cause this
+// method to fail.
+// This exists only to support handoffs from 1.0.x and 1.1.x metainstallers.
+HRESULT GoopdateXmlParser::ReadOptionalInstallAttributes(
+    IXMLDOMNode* node,
+    UpdateResponseData* response_data) {
+  ASSERT1(node);
+  ASSERT1(response_data);
+
+  CString iid;
+  HRESULT hr = ReadStringAttribute(node, Xml::Attribute::kInstallationId, &iid);
+  if (SUCCEEDED(hr)) {
+    response_data->set_installation_id(StringToGuid(iid));
+  }
+
+  CString ap;
+  hr = ReadStringAttribute(node, Xml::Attribute::kAdditionalParameter, &ap);
+  if (SUCCEEDED(hr)) {
+    response_data->set_ap(ap);
+  }
+
+  CString browser_type;
+  hr = ReadStringAttribute(node, Xml::Attribute::kBrowserType, &browser_type);
+  if (SUCCEEDED(hr)) {
+    BrowserType type = BROWSER_UNKNOWN;
+    hr = goopdate_utils::ConvertStringToBrowserType(browser_type, &type);
+    if (SUCCEEDED(hr)) {
+      response_data->set_browser_type(type);
+    }
+  }
+
+  return S_OK;
+}
+
+// Assumes all higher level validity checks have been done
+HRESULT GoopdateXmlParser::ReadUpdateResponses(
+    IXMLDOMNode* node,
+    UpdateResponses* responses) {
+  ASSERT1(node != NULL);
+  ASSERT1(responses != NULL);
+
+  CComPtr<IXMLDOMNodeList> child_nodes;
+  // Get all the children of the Node.
+  HRESULT hr = node->get_childNodes(&child_nodes);
+  if (FAILED(hr)) { return hr; }
+  if (!child_nodes) { return E_FAIL; }  // Protect against msxml S_FALSE return.
+
+  // Go Over all the children and read each of them. we will ignore ones that
+  // we dont understand.
+  hr = child_nodes->reset();
+  if (FAILED(hr)) { return hr; }
+
+  CComPtr<IXMLDOMNode> child_node;
+  while (child_nodes->nextNode(&child_node) != S_FALSE) {
+    XMLFQName child_node_name;
+    hr = GetXMLFQName(child_node, &child_node_name);
+    if (FAILED(hr)) { return hr; }
+
+    if (child_node_name.base == Xml::Element::kApp) {
+      // we got a response we should read that in.
+      UpdateResponse response;
+      hr = ReadUpdateResponse(child_node, &response);
+      if (FAILED(hr)) { return hr; }
+
+      const GUID& response_guid = response.update_response_data().guid();
+      ASSERT1(responses->find(response_guid) == responses->end());
+      (*responses)[response_guid] = response;
+    }
+    child_node = NULL;
+  }
+  return S_OK;
+}
+
+// This exists only to support handoffs from 1.0.x and 1.1.x metainstallers.
+HRESULT GoopdateXmlParser::ReadSeedInstalls(IXMLDOMNode* node,
+                                            UpdateResponses* responses) {
+  ASSERT1(node != NULL);
+  ASSERT1(responses != NULL);
+
+  CComPtr<IXMLDOMNodeList> child_nodes;
+  // Get all the children of the Node.
+  HRESULT hr = node->get_childNodes(&child_nodes);
+  if (FAILED(hr)) { return hr; }
+  if (!child_nodes) { return E_FAIL; }  // Protect against msxml S_FALSE return.
+
+  // Go Over all the children and read each of them. Since seed files are
+  // always of a version <= to this code, error if we run into a child we don't
+  // recognize.
+  hr = child_nodes->reset();
+  if (FAILED(hr)) { return hr; }
+
+  CComPtr<IXMLDOMNode> child_node;
+  while (child_nodes->nextNode(&child_node) != S_FALSE) {
+    XMLFQName child_node_name;
+    hr = GetXMLFQName(child_node, &child_node_name);
+    if (FAILED(hr)) { return hr; }
+
+    if (child_node_name.base == Xml::Element::kInstall) {
+      // We found an install node. We should read that in.
+      UpdateResponseData response_data;
+      hr = ReadInstallElement(child_node, &response_data);
+      if (FAILED(hr)) { return hr; }
+
+      UpdateResponse response(response_data);
+      const GUID& response_guid =  response.update_response_data().guid();
+      ASSERT1(responses->find(response_guid) == responses->end());
+      (*responses)[response_guid] = response;
+
+      child_node = NULL;
+    } else {
+      child_node = NULL;
+      return E_FAIL;
+    }
+  }
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::GetProtocolVersion(IXMLDOMElement* document_element,
+                                              CString* version) {
+  ASSERT1(document_element);
+  ASSERT1(version);
+
+  CString protocol_version;
+  return ReadStringAttribute(document_element,
+                             Xml::Attribute::kProtocol,
+                             version);
+}
+
+HRESULT GoopdateXmlParser::VerifyElementProtocolCompatibility(
+    IXMLDOMElement* document_element,
+    const CString& expected_version) {
+  ASSERT1(document_element);
+
+  CString protocol_version;
+  HRESULT hr = GetProtocolVersion(document_element, &protocol_version);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return VerifyProtocolCompatibility(protocol_version, expected_version);
+}
+
+// Returns GOOPDATEXML_E_XMLVERSION when the actual_ver is not between
+// the start_ver and the end_ver, both inclusive.
+HRESULT GoopdateXmlParser::VerifyProtocolRange(const CString& actual_ver,
+                                               const CString& start_ver,
+                                               const CString& end_ver) {
+  const double version = String_StringToDouble(actual_ver);
+  const double start = String_StringToDouble(start_ver);
+  const double end = String_StringToDouble(end_ver);
+  if (version < start || version > end) {
+    return GOOPDATEXML_E_XMLVERSION;
+  }
+
+  return S_OK;
+}
+
+// Verify that the protocol version is one we understand.  We accept
+// all version numbers where major version is the same as kExpectedVersion
+// which are greater than or equal to kExpectedVersion. In other words,
+// we handle future minor version number increases which should be
+// compatible.
+HRESULT GoopdateXmlParser::VerifyProtocolCompatibility(
+    const CString& actual_version,
+    const CString& expected_version) {
+  if (_tcscmp(actual_version, expected_version) != 0) {
+    const double version = String_StringToDouble(actual_version);
+    const double expected = String_StringToDouble(expected_version);
+    if (expected > version) {
+      return GOOPDATEXML_E_XMLVERSION;
+    }
+    const int version_major = static_cast<int>(version);
+    const int expected_major = static_cast<int>(expected);
+    if (version_major != expected_major) {
+      return GOOPDATEXML_E_XMLVERSION;
+    }
+  }
+
+  return S_OK;
+}
+
+// Currently, this method only validates the name and protocol version.
+HRESULT GoopdateXmlParser::ValidateResponseElement(
+    IXMLDOMElement* document_element) {
+  CComBSTR root_name;
+  HRESULT hr = document_element->get_baseName(&root_name);
+  if (FAILED(hr)) { return hr; }
+  XMLFQName doc_element_name(Xml::Namespace::kResponse, root_name);
+  if (doc_element_name.base != Xml::Element::kResponses) {
+    return GOOPDATEXML_E_RESPONSESNODE;
+  }
+
+  return VerifyElementProtocolCompatibility(document_element,
+                                            Xml::Value::kVersion2);
+}
+
+HRESULT GoopdateXmlParser::ParseManifestFile(const CString& file_name,
+                                             UpdateResponses* responses) {
+  if (responses == NULL) {
+    return E_INVALIDARG;
+  }
+
+  CComPtr<IXMLDOMElement> document_element;
+  HRESULT hr = GetDocumentElement(file_name, &document_element);
+  if (FAILED(hr)) { return hr; }
+
+  return ParseManifest(document_element, responses);
+}
+
+HRESULT GoopdateXmlParser::ParseManifestString(
+    const TCHAR* manifest,
+    UpdateResponses* responses) {
+  ASSERT1(manifest);
+  ASSERT1(responses);
+  CComPtr<IXMLDOMDocument> document;
+  HRESULT hr = LoadXMLFromMemory(manifest, false, &document);
+  if (FAILED(hr)) { return hr; }
+
+  CComPtr<IXMLDOMElement> document_element;
+  hr = document->get_documentElement(&document_element);
+  if (FAILED(hr)) { return hr; }
+  if (!document_element) {  // Protect against msxml S_FALSE return.
+    return E_FAIL;
+  }
+
+  return ParseManifest(document_element, responses);
+}
+
+HRESULT GoopdateXmlParser::ParseManifest(IXMLDOMElement* manifest,
+                                         UpdateResponses* responses) {
+  ASSERT1(manifest);
+  ASSERT1(responses);
+
+  CComBSTR uri;
+  HRESULT hr = manifest->get_namespaceURI(&uri);
+  if (FAILED(hr)) { return hr; }
+
+  if (uri == Xml::Namespace::kResponse) {
+    hr = ValidateResponseElement(manifest);
+    if (FAILED(hr)) { return hr; }
+
+    hr = ReadUpdateResponses(manifest, responses);
+    if (FAILED(hr)) { return hr; }
+  } else if (uri == Xml::Namespace::kSeed) {
+    // TODO(omaha): We should probably verify the name too.
+    hr = GetProtocolVersion(manifest, &seed_protocol_version);
+    if (FAILED(hr)) { return hr; }
+
+    hr = VerifyProtocolRange(seed_protocol_version,
+                             Xml::Value::kVersion2,
+                             Xml::Value::kVersion3);
+    if (FAILED(hr)) { return hr; }
+
+    hr = ReadSeedInstalls(manifest, responses);
+    if (FAILED(hr)) { return hr; }
+  } else {
+    return GOOPDATEXML_E_UNEXPECTED_URI;
+  }
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::CreateRequestElement(
+    const TCHAR* xml_element_name,
+    const CString& value,
+    IXMLDOMDocument* document,
+    IXMLDOMNode** request_element) {
+
+  ASSERT1(xml_element_name != NULL);
+  ASSERT1(document != NULL);
+  ASSERT1(request_element != NULL);
+
+  // request element names get o: prepended to avoid a size explosion where
+  // the namespace attribute gets automatically added to every element by
+  // msxml
+  CString name;
+  name.Format(_T("o:%s"), xml_element_name);
+
+  HRESULT hr = CreateXMLNode(document,
+                             NODE_ELEMENT,
+                             name,
+                             Xml::Namespace::kRequest,
+                             value,
+                             request_element);
+  return hr;
+}
+
+HRESULT GoopdateXmlParser::CreateAndAddRequestElement(
+    const TCHAR* xml_element_name,
+    const CString& value,
+    IXMLDOMDocument* document,
+    IXMLDOMNode* parent) {
+
+  ASSERT1(xml_element_name != NULL);
+  ASSERT1(document != NULL);
+  ASSERT1(parent != NULL);
+
+  CComPtr<IXMLDOMNode> element;
+  HRESULT hr = CreateRequestElement(xml_element_name,
+                                    value,
+                                    document,
+                                    &element);
+  if (FAILED(hr)) { return hr; }
+
+  hr = parent->appendChild(element, NULL);
+  if (FAILED(hr)) { return hr; }
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::AddAttributesToNode(
+    const CString& namespace_uri,
+    const std::vector<XMLNameValuePair>& attributes,
+    IXMLDOMNode* element) {
+  ASSERT1(element != NULL);
+  HRESULT hr;
+  for (size_t i = 0; i < attributes.size(); ++i) {
+    hr = AddXMLAttributeNode(element,
+                             namespace_uri,
+                             attributes[i].first,
+                             attributes[i].second);
+    if (FAILED(hr)) { return hr; }
+  }
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::CreateAppRequestElementHelper(
+    const AppRequest& app_request,
+    IXMLDOMDocument* document,
+    IXMLDOMNode** app_element) {
+  ASSERT1(app_element);
+  ASSERT1(document);
+
+  const AppData& app_data = app_request.request_data().app_data();
+
+  // Create the request node.
+  HRESULT hr = CreateRequestElement(Xml::Element::kApp,
+                                    _T(""),
+                                    document,
+                                    app_element);
+  if (FAILED(hr)) { return hr; }
+
+  // Add the appid to the app node.
+  // appid=""       // The application Id.
+  const int guid_len = kGuidLen;
+  TCHAR guid_str[guid_len + 1] = { _T('\0') };
+  if (StringFromGUID2(app_data.app_guid(), guid_str, guid_len + 1) <= 0) {
+    return E_FAIL;
+  }
+  if (FAILED(hr)) { return hr; }
+
+  // Saves about 600 bytes of code size by creating and destroying the
+  // array inside of the statement block.
+  {
+    // Create the list of attributes and the values that need to be added.
+    const XMLNameValuePair elements[] = {
+        std::make_pair(Xml::Attribute::kAppId, guid_str),
+        std::make_pair(Xml::Attribute::kVersion, app_data.version()),
+        std::make_pair(Xml::Attribute::kLang, app_data.language()),
+        std::make_pair(Xml::Attribute::kBrandCode, app_data.brand_code()),
+        std::make_pair(Xml::Attribute::kClientId, app_data.client_id())
+    };
+
+    for (size_t i = 0; i < arraysize(elements); ++i) {
+      hr = AddXMLAttributeNode(*app_element,
+                               Xml::Namespace::kRequest,
+                               elements[i].first,
+                               elements[i].second);
+      if (FAILED(hr)) { return hr; }
+    }
+  }
+
+  if (0 != app_data.install_time_diff_sec()) {
+    const int kSecondsPerDay = 24 * kSecondsPerHour;
+    int installed_full_days = app_data.install_time_diff_sec() / kSecondsPerDay;
+    hr = AddXMLAttributeNode(*app_element,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kInstalledAgeDays,
+                             itostr(installed_full_days));
+    if (FAILED(hr)) { return hr; }
+  }
+
+  if (GUID_NULL != app_data.iid()) {
+    hr = AddXMLAttributeNode(*app_element,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kInstallationId,
+                             GuidToString(app_data.iid()));
+    if (FAILED(hr)) { return hr; }
+  }
+
+  if (!app_data.install_source().IsEmpty()) {
+    hr = AddXMLAttributeNode(*app_element,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kInstallSource,
+                             app_data.install_source());
+    if (FAILED(hr)) { return hr; }
+  }
+
+  // Create and add component elements to the app element.
+  if (app_request.num_components() > 0) {
+    CComPtr<IXMLDOMNode> components_node;
+    hr = CreateRequestElement(Xml::Element::kComponents,
+                              _T(""),
+                              document,
+                              &components_node);
+    if (FAILED(hr)) { return hr; }
+
+    hr = (*app_element)->appendChild(components_node, NULL);
+    if (FAILED(hr)) { return hr; }
+
+    AppRequestDataVector::const_iterator it;
+    for (it = app_request.components_begin();
+         it != app_request.components_end();
+         ++it) {
+      const AppRequestData& component_request_data = *it;
+      const AppData& component_app_data = component_request_data.app_data();
+      CComPtr<IXMLDOMNode> component_node;
+      hr = CreateRequestElement(Xml::Element::kComponent,
+                                _T(""),
+                                document,
+                                &component_node);
+      if (FAILED(hr)) { return hr; }
+
+      hr = AddXMLAttributeNode(component_node,
+                               Xml::Namespace::kRequest,
+                               Xml::Attribute::kAppId,
+                               GuidToString(component_app_data.app_guid()));
+      if (FAILED(hr)) { return hr; }
+
+      hr = AddXMLAttributeNode(component_node,
+                               Xml::Namespace::kRequest,
+                               Xml::Attribute::kVersion,
+                               component_app_data.version());
+      if (FAILED(hr)) { return hr; }
+
+      hr = components_node->appendChild(component_node, NULL);
+      if (FAILED(hr)) { return hr; }
+
+      // TODO(omaha):  Create and add event elements to the component element
+      // by traversing the ping_events within component_request_data.
+      // Probably want to make the PingEvent traversal from below into a
+      // separate function.
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::CreateUpdateAppRequestElement(
+    const AppRequest& app_request,
+    IXMLDOMDocument* document,
+    IXMLDOMNode** app_element) {
+  HRESULT hr = CreateAppRequestElementHelper(app_request,
+                                             document,
+                                             app_element);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  const AppData& app_data = app_request.request_data().app_data();
+
+  // update check element
+  CComPtr<IXMLDOMNode> update_check;
+  hr = CreateRequestElement(Xml::Element::kUpdateCheck,
+                            _T(""),
+                            document,
+                            &update_check);
+  if (FAILED(hr)) { return hr; }
+
+  if (app_data.is_update_disabled()) {
+    hr = AddXMLAttributeNode(update_check,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kUpdateDisabled,
+                             Xml::Value::kTrue);
+    if (FAILED(hr)) { return hr; }
+  }
+
+  // tag is optional
+  if (!app_data.ap().IsEmpty()) {
+    hr = AddXMLAttributeNode(update_check,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kTag,
+                             app_data.ap());
+    if (FAILED(hr)) { return hr; }
+  }
+
+  // Add the Trusted Tester token under the "updatecheck" element.
+  if (!app_data.tt_token().IsEmpty()) {
+    hr = AddXMLAttributeNode(update_check,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kTTToken,
+                             app_data.tt_token());
+    if (FAILED(hr)) { return hr; }
+  }
+
+  hr = (*app_element)->appendChild(update_check, NULL);
+  if (FAILED(hr)) { return hr; }
+
+  if (!app_data.install_data_index().IsEmpty()) {
+    // data element.
+    CComPtr<IXMLDOMNode> install_data;
+    hr = CreateRequestElement(Xml::Element::kData,
+                              _T(""),
+                              document,
+                              &install_data);
+    if (FAILED(hr)) { return hr; }
+
+    hr = AddXMLAttributeNode(install_data,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kName,
+                             Xml::Value::kInstallData);
+    if (FAILED(hr)) { return hr; }
+
+    hr = AddXMLAttributeNode(install_data,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kIndex,
+                             app_data.install_data_index());
+    if (FAILED(hr)) { return hr; }
+
+    hr = (*app_element)->appendChild(install_data, NULL);
+    if (FAILED(hr)) { return hr; }
+  }
+
+  AppData::ActiveStates active = app_data.did_run();
+  if (active != AppData::ACTIVE_UNKNOWN) {
+    // didrun element. The server calls it "ping" for legacy reasons.
+    CComPtr<IXMLDOMNode> ping;
+    hr = CreateRequestElement(Xml::Element::kPing,
+                              _T(""),
+                              document,
+                              &ping);
+    if (FAILED(hr)) { return hr; }
+
+    const TCHAR* active_str(active == AppData::ACTIVE_RUN ?
+                            _T("1") :
+                            _T("0"));
+    hr = AddXMLAttributeNode(ping,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kActive,
+                             active_str);
+    if (FAILED(hr)) { return hr; }
+
+    hr = (*app_element)->appendChild(ping, NULL);
+    if (FAILED(hr)) { return hr; }
+  }
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::CreatePingAppRequestElement(
+    const AppRequest& app_request,
+    IXMLDOMDocument* document,
+    IXMLDOMNode** app_element) {
+  HRESULT hr = CreateAppRequestElementHelper(app_request,
+                                             document,
+                                             app_element);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // create and add Ping elements to the app element. Server calls ping elements
+  // "event" elements for legacy reasons.
+  std::vector<PingEvent>::const_iterator it;
+  for (it = app_request.request_data().ping_events_begin();
+       it != app_request.request_data().ping_events_end();
+       ++it) {
+    const PingEvent& app_event = *it;
+    CComPtr<IXMLDOMNode> ev;
+    hr = CreateRequestElement(Xml::Element::kEvent,
+                              _T(""),
+                              document,
+                              &ev);
+    if (FAILED(hr)) { return hr; }
+    CString str;
+    str.Format(_T("%d"), app_event.event_type());
+    hr = AddXMLAttributeNode(ev,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kEventType,
+                             str);
+    if (FAILED(hr)) { return hr; }
+    str.Format(_T("%d"), app_event.event_result());
+    hr = AddXMLAttributeNode(ev,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kEventResult,
+                             str);
+    if (FAILED(hr)) { return hr; }
+    str.Format(_T("%d"), app_event.error_code());
+    hr = AddXMLAttributeNode(ev,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kErrorCode,
+                             str);
+    if (FAILED(hr)) { return hr; }
+    str.Format(_T("%d"), app_event.extra_code1());
+    hr = AddXMLAttributeNode(ev,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kExtraCode1,
+                             str);
+    if (FAILED(hr)) { return hr; }
+    str = app_event.previous_version();
+    if (!str.IsEmpty()) {
+      hr = AddXMLAttributeNode(ev,
+                               Xml::Namespace::kRequest,
+                               Xml::Attribute::kPreviousVersion,
+                               str);
+      if (FAILED(hr)) { return hr; }
+    }
+
+    hr = (*app_element)->appendChild(ev, NULL);
+    if (FAILED(hr)) { return hr; }
+  }
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::GenerateRequest(const Request& req,
+                                           bool is_update_check,
+                                           CString* request_buffer) {
+  CORE_LOG(L3, (_T("[GenerateRequest]")));
+  ASSERT1(request_buffer);
+  if (!request_buffer) {
+    return E_INVALIDARG;
+  }
+
+  // Create the XML document.
+  CComPtr<IXMLDOMDocument> document;
+  HRESULT hr = CoCreateSafeDOMDocument(&document);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[CoCreateSafeDOMDocument failed][0x%x]"), hr));
+    return hr;
+  }
+
+  // Create the AppRequests Element.
+  CComPtr<IXMLDOMNode> update_requests;
+  hr = CreateRequestElement(Xml::Element::kRequests,
+                            _T(""),
+                            document,
+                            &update_requests);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[CreateRequestElement failed][0x%x]"), hr));
+    return hr;
+  }
+
+  // Add the update requests node to the document.
+  CComPtr<IXMLDOMElement> update_requests_node;
+  hr = update_requests->QueryInterface(&update_requests_node);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[update_requests->QueryInterface][0x%x]"), hr));
+    return hr;
+  }
+  hr = document->putref_documentElement(update_requests_node);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[putref_documentElement failed][0x%x]"), hr));
+    return hr;
+  }
+
+  // add attributes to the top element:
+  // * protocol - protocol version
+  // * version - omaha version
+  // * machineid - per machine guid
+  // * userid - per user guid
+  // * testsource - test source
+  // * requestid - Unique request id
+  hr = AddXMLAttributeNode(update_requests,
+                           Xml::Namespace::kRequest,
+                           Xml::Attribute::kProtocol,
+                           Xml::Value::kProtocol);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[AddXMLAttributeNode failed][0x%x]"), hr));
+    return hr;
+  }
+  hr = AddXMLAttributeNode(update_requests,
+                           Xml::Namespace::kRequest,
+                           Xml::Attribute::kVersion,
+                           req.version());
+  if (FAILED(hr)) { return hr; }
+  hr = AddXMLAttributeNode(update_requests,
+                           Xml::Namespace::kRequest,
+                           Xml::Attribute::kIsMachine,
+                           req.is_machine() ? _T("1") : _T("0"));
+  if (FAILED(hr)) { return hr; }
+  hr = AddXMLAttributeNode(update_requests,
+                           Xml::Namespace::kRequest,
+                           Xml::Attribute::kMachineId,
+                           req.machine_id());
+  if (FAILED(hr)) { return hr; }
+  hr = AddXMLAttributeNode(update_requests,
+                           Xml::Namespace::kRequest,
+                           Xml::Attribute::kUserId,
+                           req.user_id());
+  if (FAILED(hr)) { return hr; }
+  if (!req.test_source().IsEmpty()) {
+    hr = AddXMLAttributeNode(update_requests,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kTestSource,
+                             req.test_source());
+    if (FAILED(hr)) { return hr; }
+  }
+  if (!req.request_id().IsEmpty()) {
+    hr = AddXMLAttributeNode(update_requests,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kRequestId,
+                             req.request_id());
+    if (FAILED(hr)) { return hr; }
+  }
+
+  bool is_period_overridden = false;
+  const int check_period_sec =
+      ConfigManager::Instance()->GetLastCheckPeriodSec(&is_period_overridden);
+  if (is_period_overridden) {
+    hr = AddXMLAttributeNode(update_requests,
+                             Xml::Namespace::kRequest,
+                             Xml::Attribute::kPeriodOverrideSec,
+                             itostr(check_period_sec));
+    ASSERT1(SUCCEEDED(hr));
+  }
+
+  // Create os elements and add to the requests element.
+  CComPtr<IXMLDOMNode> os_element;
+  hr = CreateRequestElement(Xml::Element::kOs, _T(""), document, &os_element);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[CreateRequestElement failed][0x%x]"), hr));
+    return hr;
+  }
+  hr = AddXMLAttributeNode(os_element,
+                           Xml::Namespace::kRequest,
+                           Xml::Attribute::kPlatform,
+                           kPlatformWin);
+  hr = AddXMLAttributeNode(os_element,
+                           Xml::Namespace::kRequest,
+                           Xml::Attribute::kVersion,
+                           req.os_version());
+  hr = AddXMLAttributeNode(os_element,
+                           Xml::Namespace::kRequest,
+                           Xml::Attribute::kServicePack,
+                           req.os_service_pack());
+  if (FAILED(hr)) { return hr; }
+  hr = update_requests->appendChild(os_element, NULL);
+  if (FAILED(hr)) { return hr; }
+
+  // Create and add request's to the requests node.
+  AppRequestVector::const_iterator i;
+  for (i = req.app_requests_begin(); i != req.app_requests_end(); ++i) {
+    const AppRequest& app_request = *i;
+    // Create each of the request elements and add to the requests element.
+    CComPtr<IXMLDOMNode> request_element;
+    hr = is_update_check ?
+         CreateUpdateAppRequestElement(app_request,
+                                       document,
+                                       &request_element) :
+         CreatePingAppRequestElement(app_request,
+                                     document,
+                                     &request_element);
+    if (FAILED(hr)) { return hr; }
+
+    // Add the update request node to the AppRequests node.
+    hr = update_requests->appendChild(request_element, NULL);
+    if (FAILED(hr)) { return hr; }
+  }
+
+  // Extract the string out of the DOM, and add the initial processing
+  // instruction. We cannot use the xml processing instruction as the get_xml
+  // method returns utf-16 encoded string which causes the utf-8 marker to be
+  // removed. We will convert to utf-8 before the actual save.
+  CComBSTR xml_value(Xml::kHeaderText);
+  CComBSTR xml_body;
+  document->get_xml(&xml_body);
+  xml_value += xml_body;
+
+  *request_buffer = static_cast<TCHAR*>(xml_value);
+
+  return S_OK;
+}
+
+HRESULT GoopdateXmlParser::LoadXmlFileToMemory(const CString& file_name,
+                                               CString* buffer) {
+  ASSERT1(buffer);
+
+  CComPtr<IXMLDOMDocument> document;
+  HRESULT hr = LoadXMLFromFile(file_name, false, &document);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return SaveXMLToMemory(document, buffer);
+}
+
+}  // namespace omaha
diff --git a/goopdate/goopdate_xml_parser.h b/goopdate/goopdate_xml_parser.h
index 6a05c1b..1df93e5 100644
--- a/goopdate/goopdate_xml_parser.h
+++ b/goopdate/goopdate_xml_parser.h
@@ -1,198 +1,198 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Declares the Goopdate XML parser. This XML schema is used in the following:

-// 1. Creating update pings.

-// 2. Parsing update responses.

-// 3. Parsing the Install manifest.

-

-#ifndef OMAHA_GOOPDATE_GOOPDATE_XML_PARSER_H__

-#define OMAHA_GOOPDATE_GOOPDATE_XML_PARSER_H__

-

-#include <map>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/request.h"

-#include "omaha/goopdate/update_response.h"

-

-namespace omaha {

-

-const int kInvalidId = -1;

-

-// name and value of an element or attribute, used in internal loops.

-typedef std::pair<CString, CString> XMLNameValuePair;

-

-// Reader/writer for the Update request. The class is a simple wrapper on

-// top of XML DOM. The class performs validation of the response schema,

-// without calling into the xml schema validation of DOM.

-class GoopdateXmlParser {

- public:

-  // Parses the manifest file.

-  static HRESULT ParseManifestFile(const CString& file_name,

-                                   UpdateResponses* responses);

-

-  // Parses the manifest string.

-  static HRESULT ParseManifestString(const TCHAR* manifest,

-                                     UpdateResponses* responses);

-

-  // Generates the update request from the request node.

-  static HRESULT GenerateRequest(const Request& request,

-                                 bool is_update_check,

-                                 CString* request_string);

-

-  // Loads an XML file into memory.

-  static HRESULT LoadXmlFileToMemory(const CString& file_name,

-                                     CString* xml_string);

-

- private:

-  // Reads the protocol version of the xml file.

-  static HRESULT GetProtocolVersion(IXMLDOMElement* document_element,

-                                    CString* version);

-

-  // Reads the app elements into individual UpdateResponse elements

-  // and adds them to responses.

-  static HRESULT ReadUpdateResponses(IXMLDOMNode* gupdate,

-                                     UpdateResponses* responses);

-

-  // Reads the UpdateResponse element.

-  static HRESULT ReadUpdateResponse(IXMLDOMNode* app,

-                                    UpdateResponse* response);

-

-  // Reads the components section of a response.

-  static HRESULT ReadComponentsResponses(IXMLDOMNode* node,

-                                         UpdateResponse* response);

-

-  // Reads an individual component of a response.

-  static HRESULT ReadComponentResponseData(IXMLDOMNode* node,

-                                           UpdateResponseData* response_data);

-

-  // Reads the install elements into individual UpdateResponse elements

-  // and adds them to responses.

-  static HRESULT ReadSeedInstalls(IXMLDOMNode* gupdate,

-                                  UpdateResponses* responses);

-

-  // Reads the InstallsElement.

-  static HRESULT ReadInstallElement(IXMLDOMNode* node,

-                                    UpdateResponseData* response_data);

-

-  // Reads the attributes that must be in an install node.

-  static HRESULT ReadRequiredInstallAttributes(

-      IXMLDOMNode* node,

-      UpdateResponseData* response_data);

-

-  // Reads the attributes that are optional in an install node.

-  static HRESULT ReadOptionalInstallAttributes(

-      IXMLDOMNode* node,

-      UpdateResponseData* response_data);

-

-  // Reads the string value, either TEXT or CDATA, within the given node.

-  static HRESULT ReadStringValue(IXMLDOMNode* node, CString* value);

-

-  // Reads an attribute, given the node and the name of the attribute.

-  static HRESULT ReadAttribute(IXMLDOMNode* node, const TCHAR* attr_name,

-                               BSTR* value);

-

-  // Reads and parses an attribute that contains a boolean value.

-  static HRESULT ReadBooleanAttribute(IXMLDOMNode* node,

-                                      const TCHAR* attr_name,

-                                      bool* value);

-

-  // Reads an attribute that contains a guid.

-  static HRESULT ReadGuidAttribute(IXMLDOMNode* node,

-                                   const TCHAR* attr_name,

-                                   GUID* value);

-

-  // Reads a string attribute given the node and the attribute name.

-  static HRESULT ReadStringAttribute(IXMLDOMNode* node,

-                                     const TCHAR* attr_name,

-                                     CString* value);

-

-  // Reads an int attribute given the node and the attribute name.

-  static HRESULT ReadIntAttribute(IXMLDOMNode* node,

-                                  const TCHAR* attr_name,

-                                  int* value);

-

-  // creates an element in the request namespace

-  static HRESULT CreateRequestElement(const TCHAR* xml_element_name,

-                                      const CString& value,

-                                      IXMLDOMDocument* document,

-                                      IXMLDOMNode** request_element);

-

-  // Creates an element in the request namespace and adds it to parent

-  static HRESULT CreateAndAddRequestElement(const TCHAR* xml_element_name,

-                                            const CString& value,

-                                            IXMLDOMDocument* document,

-                                            IXMLDOMNode* parent);

-

-  // Converts a string to the SuccessfulInstallAction enum.

-  static SuccessfulInstallAction ConvertStringToSuccessAction(

-      const CString& text);

-

-  // Adds the attributes to the node.

-  static HRESULT AddAttributesToNode(

-      const CString& namespace_uri,

-      const std::vector<XMLNameValuePair>& attributes,

-      IXMLDOMNode* element);

-

-  // Verifies that document element's version is compatible.

-  static HRESULT VerifyElementProtocolCompatibility(

-      IXMLDOMElement* document_element,

-      const CString& expected_version);

-

-  // Verifies that the versions are compatible.

-  static HRESULT VerifyProtocolCompatibility(const CString& actual_version,

-                                             const CString& expected_version);

-

-  // Verifies that the response node name and version are valid.

-  static HRESULT ValidateResponseElement(IXMLDOMElement* document_element);

-

-  // Parses the manifest.

-  static HRESULT ParseManifest(IXMLDOMElement* manifest,

-                               UpdateResponses* responses);

-

-  // Verify that the protocol version is between the versions.

-  static HRESULT VerifyProtocolRange(const CString& actual_ver,

-                                     const CString& start_ver,

-                                     const CString& end_ver);

-

- private:

-  // Helper for CreateUpdateAppRequestElement and CreatePingAppRequestElement.

-  static HRESULT CreateAppRequestElementHelper(const AppRequest& app_request,

-                                               IXMLDOMDocument* document,

-                                               IXMLDOMNode** app_element);

-

-  // Creates the main app element, including the update element, and all its

-  // children.

-  static HRESULT CreateUpdateAppRequestElement(const AppRequest& app_request,

-                                               IXMLDOMDocument* document,

-                                               IXMLDOMNode** app_element);

-

-  // Creates the main app element, including the ping element, and all its

-  // children.

-  static HRESULT CreatePingAppRequestElement(const AppRequest& app_request,

-                                             IXMLDOMDocument* document,

-                                             IXMLDOMNode** app_element);

-

-  static CString seed_protocol_version;

-

-  friend class GoopdateXmlParserTest;

-

-  DISALLOW_IMPLICIT_CONSTRUCTORS(GoopdateXmlParser);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_GOOPDATE_XML_PARSER_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Declares the Goopdate XML parser. This XML schema is used in the following:
+// 1. Creating update pings.
+// 2. Parsing update responses.
+// 3. Parsing the Install manifest.
+
+#ifndef OMAHA_GOOPDATE_GOOPDATE_XML_PARSER_H__
+#define OMAHA_GOOPDATE_GOOPDATE_XML_PARSER_H__
+
+#include <map>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/request.h"
+#include "omaha/goopdate/update_response.h"
+
+namespace omaha {
+
+const int kInvalidId = -1;
+
+// name and value of an element or attribute, used in internal loops.
+typedef std::pair<CString, CString> XMLNameValuePair;
+
+// Reader/writer for the Update request. The class is a simple wrapper on
+// top of XML DOM. The class performs validation of the response schema,
+// without calling into the xml schema validation of DOM.
+class GoopdateXmlParser {
+ public:
+  // Parses the manifest file.
+  static HRESULT ParseManifestFile(const CString& file_name,
+                                   UpdateResponses* responses);
+
+  // Parses the manifest string.
+  static HRESULT ParseManifestString(const TCHAR* manifest,
+                                     UpdateResponses* responses);
+
+  // Generates the update request from the request node.
+  static HRESULT GenerateRequest(const Request& request,
+                                 bool is_update_check,
+                                 CString* request_string);
+
+  // Loads an XML file into memory.
+  static HRESULT LoadXmlFileToMemory(const CString& file_name,
+                                     CString* xml_string);
+
+ private:
+  // Reads the protocol version of the xml file.
+  static HRESULT GetProtocolVersion(IXMLDOMElement* document_element,
+                                    CString* version);
+
+  // Reads the app elements into individual UpdateResponse elements
+  // and adds them to responses.
+  static HRESULT ReadUpdateResponses(IXMLDOMNode* gupdate,
+                                     UpdateResponses* responses);
+
+  // Reads the UpdateResponse element.
+  static HRESULT ReadUpdateResponse(IXMLDOMNode* app,
+                                    UpdateResponse* response);
+
+  // Reads the components section of a response.
+  static HRESULT ReadComponentsResponses(IXMLDOMNode* node,
+                                         UpdateResponse* response);
+
+  // Reads an individual component of a response.
+  static HRESULT ReadComponentResponseData(IXMLDOMNode* node,
+                                           UpdateResponseData* response_data);
+
+  // Reads the install elements into individual UpdateResponse elements
+  // and adds them to responses.
+  static HRESULT ReadSeedInstalls(IXMLDOMNode* gupdate,
+                                  UpdateResponses* responses);
+
+  // Reads the InstallsElement.
+  static HRESULT ReadInstallElement(IXMLDOMNode* node,
+                                    UpdateResponseData* response_data);
+
+  // Reads the attributes that must be in an install node.
+  static HRESULT ReadRequiredInstallAttributes(
+      IXMLDOMNode* node,
+      UpdateResponseData* response_data);
+
+  // Reads the attributes that are optional in an install node.
+  static HRESULT ReadOptionalInstallAttributes(
+      IXMLDOMNode* node,
+      UpdateResponseData* response_data);
+
+  // Reads the string value, either TEXT or CDATA, within the given node.
+  static HRESULT ReadStringValue(IXMLDOMNode* node, CString* value);
+
+  // Reads an attribute, given the node and the name of the attribute.
+  static HRESULT ReadAttribute(IXMLDOMNode* node, const TCHAR* attr_name,
+                               BSTR* value);
+
+  // Reads and parses an attribute that contains a boolean value.
+  static HRESULT ReadBooleanAttribute(IXMLDOMNode* node,
+                                      const TCHAR* attr_name,
+                                      bool* value);
+
+  // Reads an attribute that contains a guid.
+  static HRESULT ReadGuidAttribute(IXMLDOMNode* node,
+                                   const TCHAR* attr_name,
+                                   GUID* value);
+
+  // Reads a string attribute given the node and the attribute name.
+  static HRESULT ReadStringAttribute(IXMLDOMNode* node,
+                                     const TCHAR* attr_name,
+                                     CString* value);
+
+  // Reads an int attribute given the node and the attribute name.
+  static HRESULT ReadIntAttribute(IXMLDOMNode* node,
+                                  const TCHAR* attr_name,
+                                  int* value);
+
+  // creates an element in the request namespace
+  static HRESULT CreateRequestElement(const TCHAR* xml_element_name,
+                                      const CString& value,
+                                      IXMLDOMDocument* document,
+                                      IXMLDOMNode** request_element);
+
+  // Creates an element in the request namespace and adds it to parent
+  static HRESULT CreateAndAddRequestElement(const TCHAR* xml_element_name,
+                                            const CString& value,
+                                            IXMLDOMDocument* document,
+                                            IXMLDOMNode* parent);
+
+  // Converts a string to the SuccessfulInstallAction enum.
+  static SuccessfulInstallAction ConvertStringToSuccessAction(
+      const CString& text);
+
+  // Adds the attributes to the node.
+  static HRESULT AddAttributesToNode(
+      const CString& namespace_uri,
+      const std::vector<XMLNameValuePair>& attributes,
+      IXMLDOMNode* element);
+
+  // Verifies that document element's version is compatible.
+  static HRESULT VerifyElementProtocolCompatibility(
+      IXMLDOMElement* document_element,
+      const CString& expected_version);
+
+  // Verifies that the versions are compatible.
+  static HRESULT VerifyProtocolCompatibility(const CString& actual_version,
+                                             const CString& expected_version);
+
+  // Verifies that the response node name and version are valid.
+  static HRESULT ValidateResponseElement(IXMLDOMElement* document_element);
+
+  // Parses the manifest.
+  static HRESULT ParseManifest(IXMLDOMElement* manifest,
+                               UpdateResponses* responses);
+
+  // Verify that the protocol version is between the versions.
+  static HRESULT VerifyProtocolRange(const CString& actual_ver,
+                                     const CString& start_ver,
+                                     const CString& end_ver);
+
+ private:
+  // Helper for CreateUpdateAppRequestElement and CreatePingAppRequestElement.
+  static HRESULT CreateAppRequestElementHelper(const AppRequest& app_request,
+                                               IXMLDOMDocument* document,
+                                               IXMLDOMNode** app_element);
+
+  // Creates the main app element, including the update element, and all its
+  // children.
+  static HRESULT CreateUpdateAppRequestElement(const AppRequest& app_request,
+                                               IXMLDOMDocument* document,
+                                               IXMLDOMNode** app_element);
+
+  // Creates the main app element, including the ping element, and all its
+  // children.
+  static HRESULT CreatePingAppRequestElement(const AppRequest& app_request,
+                                             IXMLDOMDocument* document,
+                                             IXMLDOMNode** app_element);
+
+  static CString seed_protocol_version;
+
+  friend class GoopdateXmlParserTest;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(GoopdateXmlParser);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_GOOPDATE_XML_PARSER_H__
diff --git a/goopdate/goopdate_xml_parser_unittest.cc b/goopdate/goopdate_xml_parser_unittest.cc
index 3fe8379..fc2e7e2 100644
--- a/goopdate/goopdate_xml_parser_unittest.cc
+++ b/goopdate/goopdate_xml_parser_unittest.cc
@@ -1,953 +1,953 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Goopdate Xml Parser unit tests.

-

-#include <windows.h>

-#include <utility>

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/xml_utils.h"

-#include "omaha/goopdate/goopdate_xml_parser.h"

-#include "omaha/goopdate/update_response.h"

-#include "omaha/goopdate/resources/goopdateres/goopdate.grh"

-#include "omaha/testing/resource.h"

-#include "omaha/testing/unit_test.h"

-

-namespace {

-

-const int kSeedManifestFileCount = 1;

-const int kSeedManifestResponseCount = 7;

-

-const TCHAR* const kPolicyKey =

-    _T("HKLM\\Software\\Policies\\Google\\Update\\");

-

-}  // namespace

-

-namespace omaha {

-

-const int kExpectedRequestLength = 2048;

-

-// Do NOT override the registry as this causes the XML Parser to fail on Vista.

-// Saves and restores registry values to prevent reading developer's update

-// check period override from impacting tests.

-class GoopdateXmlParserTest : public testing::Test {

- protected:

-  GoopdateXmlParserTest()

-      : is_updatedev_check_period_override_present_(false),

-        updatedev_check_period_override_(0),

-        is_policy_check_period_override_present_(false),

-        policy_check_period_override_(0) {

-  }

-

-  virtual void SetUp() {

-    is_updatedev_check_period_override_present_ =

-        SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                   kRegValueLastCheckPeriodSec,

-                                   &updatedev_check_period_override_));

-    RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV, kRegValueLastCheckPeriodSec);

-    is_policy_check_period_override_present_ =

-        SUCCEEDED(RegKey::GetValue(kPolicyKey,

-                                   _T("AutoUpdateCheckPeriodMinutes"),

-                                   &policy_check_period_override_));

-    RegKey::DeleteValue(kPolicyKey, _T("AutoUpdateCheckPeriodMinutes"));

-  }

-

-  virtual void TearDown() {

-    if (is_updatedev_check_period_override_present_) {

-      EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                        kRegValueLastCheckPeriodSec,

-                                        updatedev_check_period_override_));

-    } else {

-      RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV, kRegValueLastCheckPeriodSec);

-    }

-    if (is_policy_check_period_override_present_) {

-      EXPECT_SUCCEEDED(RegKey::SetValue(kPolicyKey,

-                                        _T("AutoUpdateCheckPeriodMinutes"),

-                                        policy_check_period_override_));

-    } else {

-      RegKey::DeleteValue(kPolicyKey, _T("AutoUpdateCheckPeriodMinutes"));

-    }

-  }

-

-  void CreateBaseAppData(bool is_machine, AppData* app_data) {

-    ASSERT_TRUE(app_data != NULL);

-

-    AppData data(

-        StringToGuid(_T("{83F0F399-FA78-4a94-A45E-253D4F42A4C5}")),

-        is_machine);

-    data.set_version(_T("1.0.101.0"));

-    data.set_language(_T("en_us"));

-    *app_data = data;

-  }

-

-  SuccessfulInstallAction ConvertStringToSuccessAction(const CString& text) {

-    return GoopdateXmlParser::ConvertStringToSuccessAction(text);

-  }

-

-  HRESULT VerifyProtocolCompatibility(const CString& actual_version,

-                                      const CString& expected_version) {

-    return GoopdateXmlParser::VerifyProtocolCompatibility(actual_version,

-                                                          expected_version);

-  }

-

-  static HRESULT ReadStringValue(IXMLDOMNode* node, CString* value) {

-    return GoopdateXmlParser::ReadStringValue(node, value);

-  }

-

-  bool is_updatedev_check_period_override_present_;

-  DWORD updatedev_check_period_override_;

-  bool is_policy_check_period_override_present_;

-  DWORD policy_check_period_override_;

-

-  static const int kServerManifestResponseCount = 5;

-  static const int kServerManifestComponentsResponseCount = 4;

-};

-

-TEST_F(GoopdateXmlParserTest, GenerateRequest_Test1) {

-  TCHAR expected_value[kExpectedRequestLength] = {0};

-  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST1, expected_value,

-                           kExpectedRequestLength) != 0);

-

-  Request req(false);

-  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));

-  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_os_version(_T("5.1"));

-  req.set_os_service_pack(_T(""));

-  req.set_version(_T("0.0.0.0"));

-  req.set_test_source(_T("dev"));

-

-  AppData app_data1;

-  CreateBaseAppData(req.is_machine(), &app_data1);

-  app_data1.set_did_run(AppData::ACTIVE_NOTRUN);

-  app_data1.set_ap(_T("dev"));

-  app_data1.set_iid(StringToGuid(_T("{A972BB39-CCA3-4f25-9737-3308F5FA19B5}")));

-  app_data1.set_client_id(_T("_one_client"));

-  app_data1.set_install_source(_T("oneclick"));

-  app_data1.set_brand_code(_T("GGLG"));

-  app_data1.set_install_time_diff_sec(3123456789);

-  app_data1.set_install_source(_T("oneclick"));

-

-  AppRequestData app_request_data1(app_data1);

-  AppRequest app_request1(app_request_data1);

-  req.AddAppRequest(app_request1);

-

-  AppData app_data2;

-  CreateBaseAppData(req.is_machine(), &app_data2);

-  app_data2.set_did_run(AppData::ACTIVE_NOTRUN);

-  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));

-  app_data2.set_client_id(_T("_another_client"));

-  app_data2.set_brand_code(_T("GooG"));

-  app_data2.set_install_time_diff_sec(30);

-  AppRequestData app_request_data2(app_data2);

-  AppRequest app_request2(app_request_data2);

-  req.AddAppRequest(app_request2);

-

-  CString request_string;

-  ASSERT_SUCCEEDED(

-      GoopdateXmlParser::GenerateRequest(req, true, &request_string));

-

-  ASSERT_STREQ(expected_value, request_string);

-}

-

-// Also tests the presence of periodoverridesec.

-TEST_F(GoopdateXmlParserTest, GenerateRequest_TestTTToken) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kPolicyKey,

-                                    _T("AutoUpdateCheckPeriodMinutes"),

-                                    static_cast<DWORD>(123456)));

-

-  TCHAR expected_value[kExpectedRequestLength] = {0};

-  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST_TTTOKEN,

-                           expected_value, kExpectedRequestLength) != 0);

-

-  Request req(false);

-  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));

-  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_os_version(_T("5.1"));

-  req.set_os_service_pack(_T(""));

-  req.set_version(_T("0.0.0.0"));

-  req.set_test_source(_T("dev"));

-

-  AppData app_data1;

-  CreateBaseAppData(req.is_machine(), &app_data1);

-  app_data1.set_did_run(AppData::ACTIVE_NOTRUN);

-  app_data1.set_ap(_T("dev"));

-  app_data1.set_tt_token(_T("foobar"));

-  app_data1.set_iid(StringToGuid(_T("{A972BB39-CCA3-4f25-9737-3308F5FA19B5}")));

-  app_data1.set_client_id(_T("_one_client"));

-  app_data1.set_install_source(_T("oneclick"));

-  app_data1.set_brand_code(_T("GGLG"));

-  app_data1.set_install_source(_T("oneclick"));

-

-  AppRequestData app_request_data1(app_data1);

-  AppRequest app_request1(app_request_data1);

-  req.AddAppRequest(app_request1);

-

-  AppData app_data2;

-  CreateBaseAppData(req.is_machine(), &app_data2);

-  app_data2.set_did_run(AppData::ACTIVE_NOTRUN);

-  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));

-  app_data2.set_client_id(_T("_another_client"));

-  app_data2.set_brand_code(_T("GooG"));

-  AppRequestData app_request_data2(app_data2);

-  AppRequest app_request2(app_request_data2);

-  req.AddAppRequest(app_request2);

-

-  CString request_string;

-  ASSERT_SUCCEEDED(

-      GoopdateXmlParser::GenerateRequest(req, true, &request_string));

-

-  ASSERT_STREQ(expected_value, request_string);

-}

-

-TEST_F(GoopdateXmlParserTest, GenerateRequest_TestUpdateDisabled) {

-  TCHAR expected_value[kExpectedRequestLength] = {0};

-  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST_UPDATE_DISABLED,

-                           expected_value, kExpectedRequestLength) != 0);

-

-  Request req(false);

-  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));

-  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_os_version(_T("5.1"));

-  req.set_os_service_pack(_T(""));

-  req.set_version(_T("0.0.0.0"));

-  req.set_test_source(_T("dev"));

-

-  AppData app_data1;

-  CreateBaseAppData(req.is_machine(), &app_data1);

-  app_data1.set_did_run(AppData::ACTIVE_NOTRUN);

-  app_data1.set_ap(_T("dev"));

-  app_data1.set_tt_token(_T("foobar"));

-  app_data1.set_iid(StringToGuid(_T("{A972BB39-CCA3-4f25-9737-3308F5FA19B5}")));

-  app_data1.set_client_id(_T("_one_client"));

-  app_data1.set_install_source(_T("oneclick"));

-  app_data1.set_brand_code(_T("GGLG"));

-  app_data1.set_install_source(_T("oneclick"));

-  app_data1.set_is_update_disabled(true);

-

-  AppRequestData app_request_data1(app_data1);

-  AppRequest app_request1(app_request_data1);

-  req.AddAppRequest(app_request1);

-

-  AppData app_data2;

-  CreateBaseAppData(req.is_machine(), &app_data2);

-  app_data2.set_did_run(AppData::ACTIVE_NOTRUN);

-  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));

-  app_data2.set_client_id(_T("_another_client"));

-  app_data2.set_brand_code(_T("GooG"));

-  AppRequestData app_request_data2(app_data2);

-  AppRequest app_request2(app_request_data2);

-  req.AddAppRequest(app_request2);

-

-  CString request_string;

-  ASSERT_SUCCEEDED(

-      GoopdateXmlParser::GenerateRequest(req, true, &request_string));

-

-  ASSERT_STREQ(expected_value, request_string);

-}

-

-TEST_F(GoopdateXmlParserTest, GenerateRequest_Test2) {

-  TCHAR expected_value[kExpectedRequestLength] = {0};

-  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST2, expected_value,

-                           kExpectedRequestLength) != 0);

-

-  Request req(true);

-  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));

-  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_os_version(_T("5.1"));

-  req.set_os_service_pack(_T("Service Pack 2"));

-  req.set_version(_T("8.9.10.11"));

-  req.set_test_source(_T("qa"));

-

-  AppData app_data1;

-  CreateBaseAppData(req.is_machine(), &app_data1);

-  AppRequestData app_request_data1(app_data1);

-  PingEvent ping_event(PingEvent::EVENT_INSTALL_COMPLETE,

-                       PingEvent::EVENT_RESULT_ERROR,

-                       1234,

-                       E_FAIL,

-                       _T("Install error"));

-  app_request_data1.AddPingEvent(ping_event);

-  EXPECT_EQ(0, app_data1.install_time_diff_sec());

-  AppRequest app_request1(app_request_data1);

-  req.AddAppRequest(app_request1);

-

-  AppData app_data2;

-  CreateBaseAppData(req.is_machine(), &app_data2);

-  app_data2.set_ap(_T("stable"));

-  app_data2.set_tt_token(_T("foobar"));

-  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));

-  app_data2.set_client_id(_T("_some_client"));

-  app_data2.set_brand_code(_T("GooG"));

-  app_data2.set_install_time_diff_sec(7 * 24 * 60 * 60 - 1);

-  AppRequestData app_request_data2(app_data2);

-  AppRequest app_request2(app_request_data2);

-  req.AddAppRequest(app_request2);

-

-  CString request_string;

-  ASSERT_SUCCEEDED(GoopdateXmlParser::GenerateRequest(req,

-                                                      false,

-                                                      &request_string));

-

-  ASSERT_STREQ(expected_value, request_string);

-}

-

-// Also tests the presence of periodoverridesec in non-update checks and integer

-// overflow of the registry value.

-TEST_F(GoopdateXmlParserTest, GenerateRequest_Test3_Components) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kPolicyKey,

-                                    _T("AutoUpdateCheckPeriodMinutes"),

-                                    static_cast<DWORD>(UINT_MAX / 60)));

-

-  TCHAR expected_value[kExpectedRequestLength] = {0};

-  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST3, expected_value,

-                           kExpectedRequestLength) != 0);

-

-  Request req(true);

-  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));

-  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_os_version(_T("5.1"));

-  req.set_os_service_pack(_T("Service Pack 2"));

-  req.set_version(_T("8.9.10.11"));

-  req.set_test_source(_T("qa"));

-

-  AppData app_data1;

-  CreateBaseAppData(req.is_machine(), &app_data1);

-

-  const TCHAR* kComponent1Guid = _T("{AC001D35-5F30-473A-9D7B-8FD3877AC28E}");

-  const TCHAR* kComponent1Version = _T("1.0.3.1");

-

-  const TCHAR* kComponent2Guid = _T("{F4E490BE-83BB-4D5A-8386-263DE047255E}");

-  const TCHAR* kComponent2Version = _T("1.1.4.2");

-

-  AppRequest app_request1;

-  AppRequestData app_request_data1(app_data1);

-

-  AppData component1;

-  component1.set_app_guid(StringToGuid(kComponent1Guid));

-  component1.set_is_machine_app(req.is_machine());

-  component1.set_version(kComponent1Version);

-  AppRequestData app_request_data_component1(component1);

-  app_request1.AddComponentRequest(app_request_data_component1);

-

-  AppData component2;

-  component2.set_app_guid(StringToGuid(kComponent2Guid));

-  component2.set_is_machine_app(req.is_machine());

-  component2.set_version(kComponent2Version);

-  AppRequestData app_request_data_component2(component2);

-  app_request1.AddComponentRequest(app_request_data_component2);

-

-  PingEvent ping_event(PingEvent::EVENT_INSTALL_COMPLETE,

-                       PingEvent::EVENT_RESULT_ERROR,

-                       1234,

-                       E_FAIL,

-                       _T("Install error"));

-  app_request_data1.AddPingEvent(ping_event);

-

-  app_request1.set_request_data(app_request_data1);

-  req.AddAppRequest(app_request1);

-

-  AppData app_data2;

-  CreateBaseAppData(req.is_machine(), &app_data2);

-  app_data2.set_ap(_T("stable"));

-  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));

-  app_data2.set_client_id(_T("_some_client"));

-  app_data2.set_brand_code(_T("GooG"));

-  AppRequestData app_request_data2(app_data2);

-  AppRequest app_request2(app_request_data2);

-  req.AddAppRequest(app_request2);

-

-  CString request_string;

-  bool encrypt = false;

-  ASSERT_SUCCEEDED(GoopdateXmlParser::GenerateRequest(req,

-                                                      false,

-                                                      &request_string));

-

-  ASSERT_FALSE(encrypt);

-  ASSERT_STREQ(expected_value, request_string);

-}

-

-TEST_F(GoopdateXmlParserTest, GenerateRequest_TestInstallDataIndex) {

-  TCHAR expected_value[kExpectedRequestLength] = {0};

-  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST4, expected_value,

-                           kExpectedRequestLength) != 0);

-

-  Request req(false);

-  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));

-  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));

-  req.set_os_version(_T("5.1"));

-  req.set_os_service_pack(_T(""));

-  req.set_version(_T("0.0.0.0"));

-  req.set_test_source(_T("dev"));

-

-  AppData app_data1;

-  CreateBaseAppData(req.is_machine(), &app_data1);

-  app_data1.set_did_run(AppData::ACTIVE_NOTRUN);

-  app_data1.set_ap(_T("dev"));

-  app_data1.set_iid(StringToGuid(_T("{A972BB39-CCA3-4f25-9737-3308F5FA19B5}")));

-  app_data1.set_brand_code(_T("GGLG"));

-  app_data1.set_client_id(_T("_one_client"));

-  app_data1.set_install_time_diff_sec(7 * 24 * 60 * 60);

-  app_data1.set_install_source(_T("oneclick"));

-  app_data1.set_install_data_index(_T("foobar"));

-

-  AppRequestData app_request_data1(app_data1);

-  AppRequest app_request1(app_request_data1);

-  req.AddAppRequest(app_request1);

-

-  AppData app_data2;

-  CreateBaseAppData(req.is_machine(), &app_data2);

-  app_data2.set_did_run(AppData::ACTIVE_NOTRUN);

-  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));

-  app_data2.set_client_id(_T("_another_client"));

-  app_data2.set_brand_code(_T("GooG"));

-  app_data2.set_install_time_diff_sec(7 * 24 * 60 * 60 + 1);

-  AppRequestData app_request_data2(app_data2);

-  AppRequest app_request2(app_request_data2);

-  req.AddAppRequest(app_request2);

-

-  CString request_string;

-  ASSERT_SUCCEEDED(

-      GoopdateXmlParser::GenerateRequest(req, true, &request_string));

-

-  ASSERT_STREQ(expected_value, request_string);

-}

-

-TEST_F(GoopdateXmlParserTest, ReadStringValue) {

-  const TCHAR* verbose_log = _T("\n  {\n    \"distribution\": {\n      ")

-                             _T("\"verbose_logging\": true\n    }\n  }\n  ");

-

-  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                    _T("server_manifest.xml")));

-  CComPtr<IXMLDOMDocument> document;

-  ASSERT_SUCCEEDED(LoadXMLFromFile(file_name, false, &document));

-

-  CComBSTR data_element_name(_T("data"));

-  CComPtr<IXMLDOMNodeList> data_elements;

-  ASSERT_SUCCEEDED(document->getElementsByTagName(data_element_name,

-                                                  &data_elements));

-

-  CComPtr<IXMLDOMNode> data_element;

-  ASSERT_SUCCEEDED(data_elements->nextNode(&data_element));

-  ASSERT_TRUE(data_element);

-

-  CString value;

-  ASSERT_SUCCEEDED(ReadStringValue(data_element, &value));

-  ASSERT_STREQ(verbose_log, value);

-}

-

-TEST_F(GoopdateXmlParserTest, ParseManifestFile_SeedManifest) {

-  CString filename_v2(ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                      _T("seed_manifest.xml")));

-  CString *filenames[1] = {&filename_v2};

-

-  for (int j = 0; j < kSeedManifestFileCount; j++) {

-    UpdateResponses responses;

-    ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(*filenames[j],

-                                                          &responses));

-    ASSERT_EQ(kSeedManifestResponseCount, responses.size());

-

-    GUID expected_guids[] = {

-        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9937}")),

-        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9938}")),

-        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9939}")),

-        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9940}")),

-        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9941}")),

-        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9942}")),

-        StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9943}")),

-    };

-

-    BrowserType expected_types[] = {

-        BROWSER_UNKNOWN,

-        BROWSER_UNKNOWN,

-        BROWSER_DEFAULT,

-        BROWSER_IE,

-        BROWSER_FIREFOX,

-        BROWSER_CHROME,

-        BROWSER_UNKNOWN

-    };

-

-    for (int i = 0; i < kSeedManifestResponseCount; i++) {

-      UpdateResponse response = responses[expected_guids[i]];

-      const UpdateResponseData& response_data = response.update_response_data();

-      EXPECT_TRUE(response_data.url().IsEmpty());

-      EXPECT_EQ(0, response_data.size());

-      EXPECT_TRUE(response_data.hash().IsEmpty());

-      EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());

-      EXPECT_TRUE(response_data.arguments().IsEmpty());

-      EXPECT_TRUE(expected_guids[i] == response_data.guid());

-      EXPECT_TRUE(response_data.status().IsEmpty());

-      EXPECT_TRUE(GUID_NULL == response_data.installation_id());

-      EXPECT_TRUE(response_data.ap().IsEmpty());

-      EXPECT_TRUE(response_data.success_url().IsEmpty());

-      EXPECT_TRUE(response_data.error_url().IsEmpty());

-      EXPECT_EQ(expected_types[i], response_data.browser_type());

-      EXPECT_STREQ(_T("en-US"), response_data.language());

-      EXPECT_STREQ(_T("Test App"), response_data.app_name());

-    }

-  }

-}

-

-TEST_F(GoopdateXmlParserTest, ParseManifestFile_ServerManifest) {

-  UpdateResponses responses;

-  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                    _T("server_manifest.xml")));

-  GUID guid  = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}"));

-  GUID guid2 = StringToGuid(_T("{104844D6-7DDA-460B-89F0-FBF8AFDD0A67}"));

-  GUID guid3 = StringToGuid(_T("{884a01d9-fb67-430a-b491-28f960dd7309}"));

-  GUID guid4 = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9936}"));

-  GUID guid5 = StringToGuid(_T("{8CF15C17-7BB5-433a-8E6C-C018D79D00B1}"));

-

-  const TCHAR* kVerboseLog = _T("\n  {\n    \"distribution\": {\n      ")

-                             _T("\"verbose_logging\": true\n    }\n  }\n  ");

-  const TCHAR* kSkipFirstRun = _T("{\n    \"distribution\": {\n      \"")

-                               _T("skip_first_run_ui\": true,\n    }\n  }\n  ");

-

-  ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(file_name, &responses));

-  ASSERT_EQ(kServerManifestResponseCount, responses.size());

-

-  UpdateResponseData response_data =

-      responses[guid].update_response_data();

-  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.101.0/test_foo_v1.0.101.0.msi"),

-               response_data.url());

-  EXPECT_STREQ(_T("6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="), response_data.hash());

-  EXPECT_EQ(80896, response_data.size());

-  EXPECT_EQ(NEEDS_ADMIN_YES, response_data.needs_admin());

-  EXPECT_TRUE(response_data.arguments().IsEmpty());

-  EXPECT_TRUE(guid == response_data.guid());

-  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());

-  EXPECT_TRUE(GUID_NULL == response_data.installation_id());

-  EXPECT_TRUE(response_data.ap().IsEmpty());

-  EXPECT_STREQ(_T("http://testsuccessurl.com"), response_data.success_url());

-  EXPECT_TRUE(response_data.error_url().IsEmpty());

-  EXPECT_TRUE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY, response_data.success_action());

-  EXPECT_EQ(0, responses[guid].num_components());

-  EXPECT_STREQ(kVerboseLog, response_data.GetInstallData(_T("verboselogging")));

-  EXPECT_STREQ(kSkipFirstRun, response_data.GetInstallData(_T("skipfirstrun")));

-  EXPECT_TRUE(response_data.GetInstallData(_T("foobar")).IsEmpty());

-

-  response_data = responses[guid4].update_response_data();

-  EXPECT_TRUE(response_data.url().IsEmpty());

-  EXPECT_EQ(0, response_data.size());

-  EXPECT_TRUE(response_data.hash().IsEmpty());

-  EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());

-  EXPECT_TRUE(response_data.arguments().IsEmpty());

-  EXPECT_TRUE(guid4 == response_data.guid());

-  EXPECT_STREQ(kResponseStatusNoUpdate, response_data.status());

-  EXPECT_TRUE(GUID_NULL == response_data.installation_id());

-  EXPECT_TRUE(response_data.ap().IsEmpty());

-  EXPECT_TRUE(response_data.success_url().IsEmpty());

-  EXPECT_TRUE(response_data.error_url().IsEmpty());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-  EXPECT_EQ(0, responses[guid4].num_components());

-

-  response_data = responses[guid2].update_response_data();

-  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.102.0/user_foo_v1.0.102.0.msi"),

-               response_data.url());

-  EXPECT_STREQ(_T("/XzRh1rpwqrDr6ashpmQnYZIzDI="), response_data.hash());

-  EXPECT_EQ(630152,               response_data.size());

-  EXPECT_EQ(NEEDS_ADMIN_NO,      response_data.needs_admin());

-  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());

-  EXPECT_STREQ(_T("/install"),    response_data.arguments());

-  EXPECT_TRUE(guid2 ==            response_data.guid());

-  EXPECT_TRUE(response_data.success_url().IsEmpty());

-  EXPECT_TRUE(response_data.error_url().IsEmpty());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-  EXPECT_EQ(0, responses[guid2].num_components());

-

-  response_data = responses[guid3].update_response_data();

-  EXPECT_TRUE(guid3 == response_data.guid());

-  EXPECT_STREQ(kResponseStatusRestrictedExportCountry, response_data.status());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-  EXPECT_EQ(0, responses[guid3].num_components());

-

-  response_data = responses[guid5].update_response_data();

-  EXPECT_TRUE(response_data.url().IsEmpty());

-  EXPECT_TRUE(response_data.hash().IsEmpty());

-  EXPECT_EQ(0, response_data.size());

-  EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());

-  EXPECT_TRUE(response_data.arguments().IsEmpty());

-  EXPECT_TRUE(guid5 == response_data.guid());

-  EXPECT_STREQ(kResponseStatusOsNotSupported, response_data.status());

-  EXPECT_TRUE(GUID_NULL == response_data.installation_id());

-  EXPECT_TRUE(response_data.ap().IsEmpty());

-  EXPECT_TRUE(response_data.success_url().IsEmpty());

-  EXPECT_STREQ(_T("http://foo.google.com/support/article.py?id=12345&")

-               _T("hl=es-419&os=5.1"),

-               response_data.error_url());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-  EXPECT_EQ(0, responses[guid5].num_components());

-}

-

-TEST_F(GoopdateXmlParserTest, ParseManifestFile_ServerManifest_Components) {

-  UpdateResponses responses;

-  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                    _T("server_manifest_components.xml")));

-

-  // App GUIDs.

-  GUID guid  = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}"));

-  GUID guid2 = StringToGuid(_T("{104844D6-7DDA-460B-89F0-FBF8AFDD0A67}"));

-  GUID guid3 = StringToGuid(_T("{884a01d9-fb67-430a-b491-28f960dd7309}"));

-  GUID guid4 = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9936}"));

-

-  ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(file_name, &responses));

-  ASSERT_EQ(kServerManifestComponentsResponseCount, responses.size());

-

-  UpdateResponse response(responses[guid]);

-  UpdateResponseData response_data(response.update_response_data());

-  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.101.0/test_foo_v1.0.101.0.msi"),

-               response_data.url());

-  EXPECT_STREQ(_T("6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="), response_data.hash());

-  EXPECT_EQ(80896, response_data.size());

-  EXPECT_EQ(NEEDS_ADMIN_YES, response_data.needs_admin());

-  EXPECT_TRUE(response_data.arguments().IsEmpty());

-  EXPECT_TRUE(guid == response_data.guid());

-  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());

-  EXPECT_TRUE(GUID_NULL == response_data.installation_id());

-  EXPECT_TRUE(response_data.ap().IsEmpty());

-  EXPECT_STREQ(_T("http://testsuccessurl.com"), response_data.success_url());

-  EXPECT_TRUE(response_data.error_url().IsEmpty());

-  EXPECT_TRUE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY, response_data.success_action());

-

-  UpdateResponseDatas expected_components;

-  UpdateResponseData temp;

-  temp.set_guid(StringToGuid(_T("{65C42695-84A0-41C4-B70F-D2786F674592}")));

-  temp.set_status(_T("ok"));

-  temp.set_url(_T("http://dl.google.com/foo/set_comp1.msi"));

-  temp.set_size(66324);

-  temp.set_hash(_T("6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="));

-  expected_components.insert(

-      std::pair<GUID, UpdateResponseData>(temp.guid(), temp));

-

-  UpdateResponseData temp2;

-  temp2.set_guid(StringToGuid(_T("{B318029C-3607-48EB-8DBB-33E8BA17BAF1}")));

-  temp2.set_status(_T("noupdate"));

-  expected_components.insert(

-      std::pair<GUID, UpdateResponseData>(temp2.guid(), temp2));

-

-  UpdateResponseData temp3;

-  temp3.set_guid(StringToGuid(_T("{D76AE6FC-1633-4131-B782-896804795DCB}")));

-  temp3.set_status(_T("ok"));

-  temp3.set_url(_T("http://tools.google.com/happy/some_comp_inst.msi"));

-  temp3.set_size(829984);

-  temp3.set_hash(_T("6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="));

-  expected_components.insert(

-      std::pair<GUID, UpdateResponseData>(temp3.guid(), temp3));

-

-  UpdateResponseData temp4;

-  temp4.set_guid(StringToGuid(_T("{67A52AEE-6E9F-4411-B425-F210B962CD6F}")));

-  temp4.set_status(_T("noupdate"));

-  expected_components.insert(

-      std::pair<GUID, UpdateResponseData>(temp4.guid(), temp4));

-

-  EXPECT_EQ(expected_components.size(), response.num_components());

-

-  UpdateResponseDatas::const_iterator it;

-  UpdateResponseDatas::const_iterator it_exp;

-  for (it = response.components_begin(), it_exp = expected_components.begin();

-       it_exp != expected_components.end();

-       ++it, ++it_exp) {

-    const UpdateResponseData& component = (*it).second;

-    const UpdateResponseData& component_expected = (*it_exp).second;

-

-    EXPECT_STREQ(component_expected.url(), component.url());

-    EXPECT_STREQ(component_expected.hash(), component.hash());

-    EXPECT_EQ(component_expected.size(), component.size());

-    EXPECT_EQ(component_expected.needs_admin(), component.needs_admin());

-    EXPECT_STREQ(component_expected.arguments(), component.arguments());

-    EXPECT_TRUE(::IsEqualGUID(component_expected.guid(), component.guid()));

-    EXPECT_STREQ(component_expected.status(), component.status());

-    EXPECT_TRUE(::IsEqualGUID(component_expected.installation_id(),

-                              component.installation_id()));

-    EXPECT_STREQ(component_expected.ap(), component.ap());

-    EXPECT_STREQ(component_expected.success_url(), component.success_url());

-    EXPECT_TRUE(response_data.error_url().IsEmpty());

-    EXPECT_EQ(component_expected.terminate_all_browsers(),

-              component.terminate_all_browsers());

-    EXPECT_EQ(component_expected.success_action(), component.success_action());

-  }

-

-  response = responses[guid4];

-  response_data = response.update_response_data();

-  EXPECT_TRUE(response_data.url().IsEmpty());

-  EXPECT_EQ(0, response_data.size());

-  EXPECT_TRUE(response_data.hash().IsEmpty());

-  EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());

-  EXPECT_TRUE(response_data.arguments().IsEmpty());

-  EXPECT_TRUE(guid4 == response_data.guid());

-  EXPECT_STREQ(kResponseStatusNoUpdate, response_data.status());

-  EXPECT_TRUE(GUID_NULL == response_data.installation_id());

-  EXPECT_TRUE(response_data.ap().IsEmpty());

-  EXPECT_TRUE(response_data.success_url().IsEmpty());

-  EXPECT_TRUE(response_data.error_url().IsEmpty());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-  EXPECT_EQ(1, response.num_components());

-

-  response = responses[guid2];

-  response_data = response.update_response_data();

-  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.102.0/user_foo_v1.0.102.0.msi"),

-               response_data.url());

-  EXPECT_STREQ(_T("/XzRh1rpwqrDr6ashpmQnYZIzDI="), response_data.hash());

-  EXPECT_EQ(630152,               response_data.size());

-  EXPECT_EQ(NEEDS_ADMIN_NO,      response_data.needs_admin());

-  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());

-  EXPECT_STREQ(_T("/install"),    response_data.arguments());

-  EXPECT_TRUE(guid2 ==            response_data.guid());

-  EXPECT_TRUE(response_data.success_url().IsEmpty());

-  EXPECT_TRUE(response_data.error_url().IsEmpty());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-  EXPECT_EQ(0, response.num_components());

-

-  response = responses[guid3];

-  response_data = response.update_response_data();

-  EXPECT_TRUE(guid3 == response_data.guid());

-  EXPECT_STREQ(kResponseStatusRestrictedExportCountry, response_data.status());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-  EXPECT_EQ(0, response.num_components());

-}

-

-TEST_F(GoopdateXmlParserTest, ParseManifestFile_EmptyFilename) {

-  CString empty_filename;

-  UpdateResponses responses;

-  EXPECT_EQ(E_INVALIDARG, GoopdateXmlParser::ParseManifestFile(empty_filename,

-                                                               &responses));

-}

-

-TEST_F(GoopdateXmlParserTest, ParseManifestFile_NoSuchFile) {

-  CString no_such_file(_T("no_such_file.xml"));

-  UpdateResponses responses;

-  EXPECT_EQ(0x800c0005, GoopdateXmlParser::ParseManifestFile(no_such_file,

-                                                             &responses));

-}

-

-// This is a duplicate of the ParseManifestFile test except that it uses

-// LoadXmlFileToMemory() and ParseManifestString().

-TEST_F(GoopdateXmlParserTest, ParseManifestString_ServerManifest) {

-  UpdateResponses responses;

-  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                    _T("server_manifest.xml")));

-  GUID guid  = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}"));

-  GUID guid2 = StringToGuid(_T("{104844D6-7DDA-460B-89F0-FBF8AFDD0A67}"));

-  GUID guid3 = StringToGuid(_T("{884a01d9-fb67-430a-b491-28f960dd7309}"));

-  GUID guid4 = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9936}"));

-  GUID guid5 = StringToGuid(_T("{8CF15C17-7BB5-433a-8E6C-C018D79D00B1}"));

-

-  CString manifest_contents;

-  EXPECT_SUCCEEDED(GoopdateXmlParser::LoadXmlFileToMemory(file_name,

-                                                          &manifest_contents));

-

-  ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestString(manifest_contents,

-                                                          &responses));

-  ASSERT_EQ(kServerManifestResponseCount, responses.size());

-

-  UpdateResponse response(responses[guid]);

-  UpdateResponseData response_data = response.update_response_data();

-  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.101.0/test_foo_v1.0.101.0.msi"),

-               response_data.url());

-  EXPECT_STREQ(_T("6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="), response_data.hash());

-  EXPECT_EQ(80896, response_data.size());

-  EXPECT_EQ(NEEDS_ADMIN_YES, response_data.needs_admin());

-  EXPECT_TRUE(response_data.arguments().IsEmpty());

-  EXPECT_TRUE(guid == response_data.guid());

-  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());

-  EXPECT_TRUE(GUID_NULL == response_data.installation_id());

-  EXPECT_TRUE(response_data.ap().IsEmpty());

-  EXPECT_STREQ(_T("http://testsuccessurl.com"), response_data.success_url());

-  EXPECT_TRUE(response_data.error_url().IsEmpty());

-  EXPECT_TRUE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY, response_data.success_action());

-

-  response = responses[guid4];

-  response_data = response.update_response_data();

-  EXPECT_TRUE(response_data.url().IsEmpty());

-  EXPECT_EQ(0, response_data.size());

-  EXPECT_TRUE(response_data.hash().IsEmpty());

-  EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());

-  EXPECT_TRUE(response_data.arguments().IsEmpty());

-  EXPECT_TRUE(guid4 == response_data.guid());

-  EXPECT_STREQ(kResponseStatusNoUpdate, response_data.status());

-  EXPECT_TRUE(GUID_NULL == response_data.installation_id());

-  EXPECT_TRUE(response_data.ap().IsEmpty());

-  EXPECT_TRUE(response_data.success_url().IsEmpty());

-  EXPECT_TRUE(response_data.error_url().IsEmpty());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-

-  response = responses[guid2];

-  response_data = response.update_response_data();

-  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.102.0/user_foo_v1.0.102.0.msi"),

-               response_data.url());

-  EXPECT_STREQ(_T("/XzRh1rpwqrDr6ashpmQnYZIzDI="), response_data.hash());

-  EXPECT_EQ(630152,               response_data.size());

-  EXPECT_EQ(NEEDS_ADMIN_NO,      response_data.needs_admin());

-  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());

-  EXPECT_STREQ(_T("/install"),    response_data.arguments());

-  EXPECT_TRUE(guid2 ==            response_data.guid());

-  EXPECT_TRUE(response_data.success_url().IsEmpty());

-  EXPECT_TRUE(response_data.error_url().IsEmpty());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-

-  response = responses[guid3];

-  response_data = response.update_response_data();

-  EXPECT_TRUE(guid3 == response_data.guid());

-  EXPECT_STREQ(kResponseStatusRestrictedExportCountry, response_data.status());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-

-  response = responses[guid5];

-  response_data = response.update_response_data();

-  EXPECT_TRUE(response_data.url().IsEmpty());

-  EXPECT_TRUE(response_data.hash().IsEmpty());

-  EXPECT_EQ(0, response_data.size());

-  EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());

-  EXPECT_TRUE(response_data.arguments().IsEmpty());

-  EXPECT_TRUE(guid5 == response_data.guid());

-  EXPECT_STREQ(kResponseStatusOsNotSupported, response_data.status());

-  EXPECT_TRUE(GUID_NULL == response_data.installation_id());

-  EXPECT_TRUE(response_data.ap().IsEmpty());

-  EXPECT_TRUE(response_data.success_url().IsEmpty());

-  EXPECT_STREQ(_T("http://foo.google.com/support/article.py?id=12345&")

-               _T("hl=es-419&os=5.1"),

-               response_data.error_url());

-  EXPECT_FALSE(response_data.terminate_all_browsers());

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());

-  EXPECT_EQ(0, response.num_components());

-}

-

-TEST_F(GoopdateXmlParserTest, ParseManifestString_EmptyString) {

-  CString empty_string;

-  UpdateResponses responses;

-  EXPECT_EQ(0xC00CE558, GoopdateXmlParser::ParseManifestString(empty_string,

-                                                               &responses));

-}

-

-TEST_F(GoopdateXmlParserTest, ParseManifestString_ManifestNotXml) {

-  CString not_xml(_T("<this> is not XML"));

-  UpdateResponses responses;

-  EXPECT_EQ(0xC00CE553, GoopdateXmlParser::ParseManifestString(not_xml,

-                                                               &responses));

-}

-

-TEST_F(GoopdateXmlParserTest, VerifyProtocolCompatibility) {

-  // Compatible versions (same major, actual minor >= expected)

-  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.0"), _T("2.0")));

-  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.00"), _T("2.0")));

-  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.001"), _T("2.0")));

-  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.1"), _T("2.0")));

-  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.9"), _T("2.0")));

-  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.9"), _T("2.4")));

-

-  // Incompatible versions (actual < expected)

-  EXPECT_EQ(GOOPDATEXML_E_XMLVERSION,

-            VerifyProtocolCompatibility(_T("2.0"), _T("2.1")));

-  EXPECT_EQ(GOOPDATEXML_E_XMLVERSION,

-            VerifyProtocolCompatibility(_T("2.1"), _T("3.0")));

-

-  // Incompatible versions (actual major < expected major)

-  EXPECT_EQ(GOOPDATEXML_E_XMLVERSION,

-            VerifyProtocolCompatibility(_T("3.0"), _T("2.0")));

-  EXPECT_EQ(GOOPDATEXML_E_XMLVERSION,

-            VerifyProtocolCompatibility(_T("3.0"), _T("2.1")));

-  EXPECT_EQ(GOOPDATEXML_E_XMLVERSION,

-            VerifyProtocolCompatibility(_T("3.0"), _T("2.9")));

-

-  // VerifyProtocolCompatibility isn't perfect.

-  // This test case succeeds but should return GOOPDATEXML_E_XMLVERSION.

-  // We shouldn't ever see this case in a real file.

-  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(

-                       _T("3.0"), _T("2.99999999999999999999999999999")));

-}

-

-TEST_F(GoopdateXmlParserTest, LoadXmlFileToMemory) {

-  CString base_seed_path(ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                         _T("seed_manifest_with_args.xml")));

-  const CString kExpectedManifestContents(

-      _T("<?xml version=\"1.0\"?>\r\n")

-      _T("<gupdate protocol=\"2.0\" signature=\"\" xmlns=\"http://www.google.com/update2/install\">\r\n")   // NOLINT

-      _T("\t<install appguid=\"{283EAF47-8817-4c2b-A801-AD1FADFB7BAA}\" needsadmin=\"true\" iid=\"{874E4D29-8671-40C8-859F-4DECA4819999}\" client=\"someclient\" ap=\"1.0-dev\"/>\r\n")   // NOLINT

-      _T("</gupdate>\r\n"));

-

-  CString manifest_contents;

-  EXPECT_SUCCEEDED(GoopdateXmlParser::LoadXmlFileToMemory(base_seed_path,

-                                                          &manifest_contents));

-

-  EXPECT_STREQ(kExpectedManifestContents, manifest_contents);

-}

-

-TEST_F(GoopdateXmlParserTest, LoadXmlFileToMemory_EmptyFilename) {

-  CString empty_filename;

-  CString manifest_contents;

-  EXPECT_EQ(E_INVALIDARG, GoopdateXmlParser::LoadXmlFileToMemory(

-                              empty_filename, &manifest_contents));

-}

-

-TEST_F(GoopdateXmlParserTest, LoadXmlFileToMemory_NoSuchFile) {

-  CString no_such_file(_T("no_such_file.xml"));

-  CString manifest_contents;

-  EXPECT_EQ(0x800c0005, GoopdateXmlParser::LoadXmlFileToMemory(

-                            no_such_file, &manifest_contents));

-}

-

-TEST_F(GoopdateXmlParserTest, ConvertStringToSuccessAction_EmptyString) {

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, ConvertStringToSuccessAction(_T("")));

-}

-

-TEST_F(GoopdateXmlParserTest, ConvertStringToSuccessAction_Default) {

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT,

-            ConvertStringToSuccessAction(_T("default")));

-}

-

-TEST_F(GoopdateXmlParserTest, ConvertStringToSuccessAction_ExitSilently) {

-  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY,

-            ConvertStringToSuccessAction(_T("exitsilently")));

-}

-

-TEST_F(GoopdateXmlParserTest,

-       ConvertStringToSuccessAction_ExitSilentlyOnLaunchCmd) {

-  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD,

-            ConvertStringToSuccessAction(_T("exitsilentlyonlaunchcmd")));

-}

-

-TEST_F(GoopdateXmlParserTest, ConvertStringToSuccessAction_UnknownAction) {

-  ExpectAsserts expect_asserts;

-  EXPECT_EQ(SUCCESS_ACTION_DEFAULT,

-            ConvertStringToSuccessAction(_T("foo bar")));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Goopdate Xml Parser unit tests.
+
+#include <windows.h>
+#include <utility>
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/xml_utils.h"
+#include "omaha/goopdate/goopdate_xml_parser.h"
+#include "omaha/goopdate/update_response.h"
+#include "omaha/goopdate/resources/goopdateres/goopdate.grh"
+#include "omaha/testing/resource.h"
+#include "omaha/testing/unit_test.h"
+
+namespace {
+
+const int kSeedManifestFileCount = 1;
+const int kSeedManifestResponseCount = 7;
+
+const TCHAR* const kPolicyKey =
+    _T("HKLM\\Software\\Policies\\Google\\Update\\");
+
+}  // namespace
+
+namespace omaha {
+
+const int kExpectedRequestLength = 2048;
+
+// Do NOT override the registry as this causes the XML Parser to fail on Vista.
+// Saves and restores registry values to prevent reading developer's update
+// check period override from impacting tests.
+class GoopdateXmlParserTest : public testing::Test {
+ protected:
+  GoopdateXmlParserTest()
+      : is_updatedev_check_period_override_present_(false),
+        updatedev_check_period_override_(0),
+        is_policy_check_period_override_present_(false),
+        policy_check_period_override_(0) {
+  }
+
+  virtual void SetUp() {
+    is_updatedev_check_period_override_present_ =
+        SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                   kRegValueLastCheckPeriodSec,
+                                   &updatedev_check_period_override_));
+    RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV, kRegValueLastCheckPeriodSec);
+    is_policy_check_period_override_present_ =
+        SUCCEEDED(RegKey::GetValue(kPolicyKey,
+                                   _T("AutoUpdateCheckPeriodMinutes"),
+                                   &policy_check_period_override_));
+    RegKey::DeleteValue(kPolicyKey, _T("AutoUpdateCheckPeriodMinutes"));
+  }
+
+  virtual void TearDown() {
+    if (is_updatedev_check_period_override_present_) {
+      EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                        kRegValueLastCheckPeriodSec,
+                                        updatedev_check_period_override_));
+    } else {
+      RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV, kRegValueLastCheckPeriodSec);
+    }
+    if (is_policy_check_period_override_present_) {
+      EXPECT_SUCCEEDED(RegKey::SetValue(kPolicyKey,
+                                        _T("AutoUpdateCheckPeriodMinutes"),
+                                        policy_check_period_override_));
+    } else {
+      RegKey::DeleteValue(kPolicyKey, _T("AutoUpdateCheckPeriodMinutes"));
+    }
+  }
+
+  void CreateBaseAppData(bool is_machine, AppData* app_data) {
+    ASSERT_TRUE(app_data != NULL);
+
+    AppData data(
+        StringToGuid(_T("{83F0F399-FA78-4a94-A45E-253D4F42A4C5}")),
+        is_machine);
+    data.set_version(_T("1.0.101.0"));
+    data.set_language(_T("en_us"));
+    *app_data = data;
+  }
+
+  SuccessfulInstallAction ConvertStringToSuccessAction(const CString& text) {
+    return GoopdateXmlParser::ConvertStringToSuccessAction(text);
+  }
+
+  HRESULT VerifyProtocolCompatibility(const CString& actual_version,
+                                      const CString& expected_version) {
+    return GoopdateXmlParser::VerifyProtocolCompatibility(actual_version,
+                                                          expected_version);
+  }
+
+  static HRESULT ReadStringValue(IXMLDOMNode* node, CString* value) {
+    return GoopdateXmlParser::ReadStringValue(node, value);
+  }
+
+  bool is_updatedev_check_period_override_present_;
+  DWORD updatedev_check_period_override_;
+  bool is_policy_check_period_override_present_;
+  DWORD policy_check_period_override_;
+
+  static const int kServerManifestResponseCount = 5;
+  static const int kServerManifestComponentsResponseCount = 4;
+};
+
+TEST_F(GoopdateXmlParserTest, GenerateRequest_Test1) {
+  TCHAR expected_value[kExpectedRequestLength] = {0};
+  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST1, expected_value,
+                           kExpectedRequestLength) != 0);
+
+  Request req(false);
+  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));
+  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_os_version(_T("5.1"));
+  req.set_os_service_pack(_T(""));
+  req.set_version(_T("0.0.0.0"));
+  req.set_test_source(_T("dev"));
+
+  AppData app_data1;
+  CreateBaseAppData(req.is_machine(), &app_data1);
+  app_data1.set_did_run(AppData::ACTIVE_NOTRUN);
+  app_data1.set_ap(_T("dev"));
+  app_data1.set_iid(StringToGuid(_T("{A972BB39-CCA3-4f25-9737-3308F5FA19B5}")));
+  app_data1.set_client_id(_T("_one_client"));
+  app_data1.set_install_source(_T("oneclick"));
+  app_data1.set_brand_code(_T("GGLG"));
+  app_data1.set_install_time_diff_sec(3123456789);
+  app_data1.set_install_source(_T("oneclick"));
+
+  AppRequestData app_request_data1(app_data1);
+  AppRequest app_request1(app_request_data1);
+  req.AddAppRequest(app_request1);
+
+  AppData app_data2;
+  CreateBaseAppData(req.is_machine(), &app_data2);
+  app_data2.set_did_run(AppData::ACTIVE_NOTRUN);
+  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));
+  app_data2.set_client_id(_T("_another_client"));
+  app_data2.set_brand_code(_T("GooG"));
+  app_data2.set_install_time_diff_sec(30);
+  AppRequestData app_request_data2(app_data2);
+  AppRequest app_request2(app_request_data2);
+  req.AddAppRequest(app_request2);
+
+  CString request_string;
+  ASSERT_SUCCEEDED(
+      GoopdateXmlParser::GenerateRequest(req, true, &request_string));
+
+  ASSERT_STREQ(expected_value, request_string);
+}
+
+// Also tests the presence of periodoverridesec.
+TEST_F(GoopdateXmlParserTest, GenerateRequest_TestTTToken) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kPolicyKey,
+                                    _T("AutoUpdateCheckPeriodMinutes"),
+                                    static_cast<DWORD>(123456)));
+
+  TCHAR expected_value[kExpectedRequestLength] = {0};
+  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST_TTTOKEN,
+                           expected_value, kExpectedRequestLength) != 0);
+
+  Request req(false);
+  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));
+  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_os_version(_T("5.1"));
+  req.set_os_service_pack(_T(""));
+  req.set_version(_T("0.0.0.0"));
+  req.set_test_source(_T("dev"));
+
+  AppData app_data1;
+  CreateBaseAppData(req.is_machine(), &app_data1);
+  app_data1.set_did_run(AppData::ACTIVE_NOTRUN);
+  app_data1.set_ap(_T("dev"));
+  app_data1.set_tt_token(_T("foobar"));
+  app_data1.set_iid(StringToGuid(_T("{A972BB39-CCA3-4f25-9737-3308F5FA19B5}")));
+  app_data1.set_client_id(_T("_one_client"));
+  app_data1.set_install_source(_T("oneclick"));
+  app_data1.set_brand_code(_T("GGLG"));
+  app_data1.set_install_source(_T("oneclick"));
+
+  AppRequestData app_request_data1(app_data1);
+  AppRequest app_request1(app_request_data1);
+  req.AddAppRequest(app_request1);
+
+  AppData app_data2;
+  CreateBaseAppData(req.is_machine(), &app_data2);
+  app_data2.set_did_run(AppData::ACTIVE_NOTRUN);
+  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));
+  app_data2.set_client_id(_T("_another_client"));
+  app_data2.set_brand_code(_T("GooG"));
+  AppRequestData app_request_data2(app_data2);
+  AppRequest app_request2(app_request_data2);
+  req.AddAppRequest(app_request2);
+
+  CString request_string;
+  ASSERT_SUCCEEDED(
+      GoopdateXmlParser::GenerateRequest(req, true, &request_string));
+
+  ASSERT_STREQ(expected_value, request_string);
+}
+
+TEST_F(GoopdateXmlParserTest, GenerateRequest_TestUpdateDisabled) {
+  TCHAR expected_value[kExpectedRequestLength] = {0};
+  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST_UPDATE_DISABLED,
+                           expected_value, kExpectedRequestLength) != 0);
+
+  Request req(false);
+  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));
+  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_os_version(_T("5.1"));
+  req.set_os_service_pack(_T(""));
+  req.set_version(_T("0.0.0.0"));
+  req.set_test_source(_T("dev"));
+
+  AppData app_data1;
+  CreateBaseAppData(req.is_machine(), &app_data1);
+  app_data1.set_did_run(AppData::ACTIVE_NOTRUN);
+  app_data1.set_ap(_T("dev"));
+  app_data1.set_tt_token(_T("foobar"));
+  app_data1.set_iid(StringToGuid(_T("{A972BB39-CCA3-4f25-9737-3308F5FA19B5}")));
+  app_data1.set_client_id(_T("_one_client"));
+  app_data1.set_install_source(_T("oneclick"));
+  app_data1.set_brand_code(_T("GGLG"));
+  app_data1.set_install_source(_T("oneclick"));
+  app_data1.set_is_update_disabled(true);
+
+  AppRequestData app_request_data1(app_data1);
+  AppRequest app_request1(app_request_data1);
+  req.AddAppRequest(app_request1);
+
+  AppData app_data2;
+  CreateBaseAppData(req.is_machine(), &app_data2);
+  app_data2.set_did_run(AppData::ACTIVE_NOTRUN);
+  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));
+  app_data2.set_client_id(_T("_another_client"));
+  app_data2.set_brand_code(_T("GooG"));
+  AppRequestData app_request_data2(app_data2);
+  AppRequest app_request2(app_request_data2);
+  req.AddAppRequest(app_request2);
+
+  CString request_string;
+  ASSERT_SUCCEEDED(
+      GoopdateXmlParser::GenerateRequest(req, true, &request_string));
+
+  ASSERT_STREQ(expected_value, request_string);
+}
+
+TEST_F(GoopdateXmlParserTest, GenerateRequest_Test2) {
+  TCHAR expected_value[kExpectedRequestLength] = {0};
+  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST2, expected_value,
+                           kExpectedRequestLength) != 0);
+
+  Request req(true);
+  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));
+  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_os_version(_T("5.1"));
+  req.set_os_service_pack(_T("Service Pack 2"));
+  req.set_version(_T("8.9.10.11"));
+  req.set_test_source(_T("qa"));
+
+  AppData app_data1;
+  CreateBaseAppData(req.is_machine(), &app_data1);
+  AppRequestData app_request_data1(app_data1);
+  PingEvent ping_event(PingEvent::EVENT_INSTALL_COMPLETE,
+                       PingEvent::EVENT_RESULT_ERROR,
+                       1234,
+                       E_FAIL,
+                       _T("Install error"));
+  app_request_data1.AddPingEvent(ping_event);
+  EXPECT_EQ(0, app_data1.install_time_diff_sec());
+  AppRequest app_request1(app_request_data1);
+  req.AddAppRequest(app_request1);
+
+  AppData app_data2;
+  CreateBaseAppData(req.is_machine(), &app_data2);
+  app_data2.set_ap(_T("stable"));
+  app_data2.set_tt_token(_T("foobar"));
+  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));
+  app_data2.set_client_id(_T("_some_client"));
+  app_data2.set_brand_code(_T("GooG"));
+  app_data2.set_install_time_diff_sec(7 * 24 * 60 * 60 - 1);
+  AppRequestData app_request_data2(app_data2);
+  AppRequest app_request2(app_request_data2);
+  req.AddAppRequest(app_request2);
+
+  CString request_string;
+  ASSERT_SUCCEEDED(GoopdateXmlParser::GenerateRequest(req,
+                                                      false,
+                                                      &request_string));
+
+  ASSERT_STREQ(expected_value, request_string);
+}
+
+// Also tests the presence of periodoverridesec in non-update checks and integer
+// overflow of the registry value.
+TEST_F(GoopdateXmlParserTest, GenerateRequest_Test3_Components) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kPolicyKey,
+                                    _T("AutoUpdateCheckPeriodMinutes"),
+                                    static_cast<DWORD>(UINT_MAX / 60)));
+
+  TCHAR expected_value[kExpectedRequestLength] = {0};
+  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST3, expected_value,
+                           kExpectedRequestLength) != 0);
+
+  Request req(true);
+  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));
+  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_os_version(_T("5.1"));
+  req.set_os_service_pack(_T("Service Pack 2"));
+  req.set_version(_T("8.9.10.11"));
+  req.set_test_source(_T("qa"));
+
+  AppData app_data1;
+  CreateBaseAppData(req.is_machine(), &app_data1);
+
+  const TCHAR* kComponent1Guid = _T("{AC001D35-5F30-473A-9D7B-8FD3877AC28E}");
+  const TCHAR* kComponent1Version = _T("1.0.3.1");
+
+  const TCHAR* kComponent2Guid = _T("{F4E490BE-83BB-4D5A-8386-263DE047255E}");
+  const TCHAR* kComponent2Version = _T("1.1.4.2");
+
+  AppRequest app_request1;
+  AppRequestData app_request_data1(app_data1);
+
+  AppData component1;
+  component1.set_app_guid(StringToGuid(kComponent1Guid));
+  component1.set_is_machine_app(req.is_machine());
+  component1.set_version(kComponent1Version);
+  AppRequestData app_request_data_component1(component1);
+  app_request1.AddComponentRequest(app_request_data_component1);
+
+  AppData component2;
+  component2.set_app_guid(StringToGuid(kComponent2Guid));
+  component2.set_is_machine_app(req.is_machine());
+  component2.set_version(kComponent2Version);
+  AppRequestData app_request_data_component2(component2);
+  app_request1.AddComponentRequest(app_request_data_component2);
+
+  PingEvent ping_event(PingEvent::EVENT_INSTALL_COMPLETE,
+                       PingEvent::EVENT_RESULT_ERROR,
+                       1234,
+                       E_FAIL,
+                       _T("Install error"));
+  app_request_data1.AddPingEvent(ping_event);
+
+  app_request1.set_request_data(app_request_data1);
+  req.AddAppRequest(app_request1);
+
+  AppData app_data2;
+  CreateBaseAppData(req.is_machine(), &app_data2);
+  app_data2.set_ap(_T("stable"));
+  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));
+  app_data2.set_client_id(_T("_some_client"));
+  app_data2.set_brand_code(_T("GooG"));
+  AppRequestData app_request_data2(app_data2);
+  AppRequest app_request2(app_request_data2);
+  req.AddAppRequest(app_request2);
+
+  CString request_string;
+  bool encrypt = false;
+  ASSERT_SUCCEEDED(GoopdateXmlParser::GenerateRequest(req,
+                                                      false,
+                                                      &request_string));
+
+  ASSERT_FALSE(encrypt);
+  ASSERT_STREQ(expected_value, request_string);
+}
+
+TEST_F(GoopdateXmlParserTest, GenerateRequest_TestInstallDataIndex) {
+  TCHAR expected_value[kExpectedRequestLength] = {0};
+  EXPECT_TRUE(::LoadString(NULL, IDS_EXPECTED_UPDATE_REQUEST4, expected_value,
+                           kExpectedRequestLength) != 0);
+
+  Request req(false);
+  req.set_machine_id(_T("{874E4D29-8671-40C8-859F-4DECA481CF42}"));
+  req.set_user_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_request_id(_T("{8CD4D4C7-D42E-49B7-9E1A-DDDC8F8F77A8}"));
+  req.set_os_version(_T("5.1"));
+  req.set_os_service_pack(_T(""));
+  req.set_version(_T("0.0.0.0"));
+  req.set_test_source(_T("dev"));
+
+  AppData app_data1;
+  CreateBaseAppData(req.is_machine(), &app_data1);
+  app_data1.set_did_run(AppData::ACTIVE_NOTRUN);
+  app_data1.set_ap(_T("dev"));
+  app_data1.set_iid(StringToGuid(_T("{A972BB39-CCA3-4f25-9737-3308F5FA19B5}")));
+  app_data1.set_brand_code(_T("GGLG"));
+  app_data1.set_client_id(_T("_one_client"));
+  app_data1.set_install_time_diff_sec(7 * 24 * 60 * 60);
+  app_data1.set_install_source(_T("oneclick"));
+  app_data1.set_install_data_index(_T("foobar"));
+
+  AppRequestData app_request_data1(app_data1);
+  AppRequest app_request1(app_request_data1);
+  req.AddAppRequest(app_request1);
+
+  AppData app_data2;
+  CreateBaseAppData(req.is_machine(), &app_data2);
+  app_data2.set_did_run(AppData::ACTIVE_NOTRUN);
+  app_data2.set_iid(StringToGuid(_T("{E9EF60A1-B254-4898-A1B3-6C9B60FAC94A}")));
+  app_data2.set_client_id(_T("_another_client"));
+  app_data2.set_brand_code(_T("GooG"));
+  app_data2.set_install_time_diff_sec(7 * 24 * 60 * 60 + 1);
+  AppRequestData app_request_data2(app_data2);
+  AppRequest app_request2(app_request_data2);
+  req.AddAppRequest(app_request2);
+
+  CString request_string;
+  ASSERT_SUCCEEDED(
+      GoopdateXmlParser::GenerateRequest(req, true, &request_string));
+
+  ASSERT_STREQ(expected_value, request_string);
+}
+
+TEST_F(GoopdateXmlParserTest, ReadStringValue) {
+  const TCHAR* verbose_log = _T("\n  {\n    \"distribution\": {\n      ")
+                             _T("\"verbose_logging\": true\n    }\n  }\n  ");
+
+  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                    _T("server_manifest.xml")));
+  CComPtr<IXMLDOMDocument> document;
+  ASSERT_SUCCEEDED(LoadXMLFromFile(file_name, false, &document));
+
+  CComBSTR data_element_name(_T("data"));
+  CComPtr<IXMLDOMNodeList> data_elements;
+  ASSERT_SUCCEEDED(document->getElementsByTagName(data_element_name,
+                                                  &data_elements));
+
+  CComPtr<IXMLDOMNode> data_element;
+  ASSERT_SUCCEEDED(data_elements->nextNode(&data_element));
+  ASSERT_TRUE(data_element);
+
+  CString value;
+  ASSERT_SUCCEEDED(ReadStringValue(data_element, &value));
+  ASSERT_STREQ(verbose_log, value);
+}
+
+TEST_F(GoopdateXmlParserTest, ParseManifestFile_SeedManifest) {
+  CString filename_v2(ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                      _T("seed_manifest.xml")));
+  CString *filenames[1] = {&filename_v2};
+
+  for (int j = 0; j < kSeedManifestFileCount; j++) {
+    UpdateResponses responses;
+    ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(*filenames[j],
+                                                          &responses));
+    ASSERT_EQ(kSeedManifestResponseCount, responses.size());
+
+    GUID expected_guids[] = {
+        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9937}")),
+        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9938}")),
+        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9939}")),
+        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9940}")),
+        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9941}")),
+        StringToGuid(_T("{D6B08267-B440-4c85-9F79-E195E80D9942}")),
+        StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9943}")),
+    };
+
+    BrowserType expected_types[] = {
+        BROWSER_UNKNOWN,
+        BROWSER_UNKNOWN,
+        BROWSER_DEFAULT,
+        BROWSER_IE,
+        BROWSER_FIREFOX,
+        BROWSER_CHROME,
+        BROWSER_UNKNOWN
+    };
+
+    for (int i = 0; i < kSeedManifestResponseCount; i++) {
+      UpdateResponse response = responses[expected_guids[i]];
+      const UpdateResponseData& response_data = response.update_response_data();
+      EXPECT_TRUE(response_data.url().IsEmpty());
+      EXPECT_EQ(0, response_data.size());
+      EXPECT_TRUE(response_data.hash().IsEmpty());
+      EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());
+      EXPECT_TRUE(response_data.arguments().IsEmpty());
+      EXPECT_TRUE(expected_guids[i] == response_data.guid());
+      EXPECT_TRUE(response_data.status().IsEmpty());
+      EXPECT_TRUE(GUID_NULL == response_data.installation_id());
+      EXPECT_TRUE(response_data.ap().IsEmpty());
+      EXPECT_TRUE(response_data.success_url().IsEmpty());
+      EXPECT_TRUE(response_data.error_url().IsEmpty());
+      EXPECT_EQ(expected_types[i], response_data.browser_type());
+      EXPECT_STREQ(_T("en-US"), response_data.language());
+      EXPECT_STREQ(_T("Test App"), response_data.app_name());
+    }
+  }
+}
+
+TEST_F(GoopdateXmlParserTest, ParseManifestFile_ServerManifest) {
+  UpdateResponses responses;
+  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                    _T("server_manifest.xml")));
+  GUID guid  = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}"));
+  GUID guid2 = StringToGuid(_T("{104844D6-7DDA-460B-89F0-FBF8AFDD0A67}"));
+  GUID guid3 = StringToGuid(_T("{884a01d9-fb67-430a-b491-28f960dd7309}"));
+  GUID guid4 = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9936}"));
+  GUID guid5 = StringToGuid(_T("{8CF15C17-7BB5-433a-8E6C-C018D79D00B1}"));
+
+  const TCHAR* kVerboseLog = _T("\n  {\n    \"distribution\": {\n      ")
+                             _T("\"verbose_logging\": true\n    }\n  }\n  ");
+  const TCHAR* kSkipFirstRun = _T("{\n    \"distribution\": {\n      \"")
+                               _T("skip_first_run_ui\": true,\n    }\n  }\n  ");
+
+  ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(file_name, &responses));
+  ASSERT_EQ(kServerManifestResponseCount, responses.size());
+
+  UpdateResponseData response_data =
+      responses[guid].update_response_data();
+  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.101.0/test_foo_v1.0.101.0.msi"),
+               response_data.url());
+  EXPECT_STREQ(_T("6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="), response_data.hash());
+  EXPECT_EQ(80896, response_data.size());
+  EXPECT_EQ(NEEDS_ADMIN_YES, response_data.needs_admin());
+  EXPECT_TRUE(response_data.arguments().IsEmpty());
+  EXPECT_TRUE(guid == response_data.guid());
+  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());
+  EXPECT_TRUE(GUID_NULL == response_data.installation_id());
+  EXPECT_TRUE(response_data.ap().IsEmpty());
+  EXPECT_STREQ(_T("http://testsuccessurl.com"), response_data.success_url());
+  EXPECT_TRUE(response_data.error_url().IsEmpty());
+  EXPECT_TRUE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY, response_data.success_action());
+  EXPECT_EQ(0, responses[guid].num_components());
+  EXPECT_STREQ(kVerboseLog, response_data.GetInstallData(_T("verboselogging")));
+  EXPECT_STREQ(kSkipFirstRun, response_data.GetInstallData(_T("skipfirstrun")));
+  EXPECT_TRUE(response_data.GetInstallData(_T("foobar")).IsEmpty());
+
+  response_data = responses[guid4].update_response_data();
+  EXPECT_TRUE(response_data.url().IsEmpty());
+  EXPECT_EQ(0, response_data.size());
+  EXPECT_TRUE(response_data.hash().IsEmpty());
+  EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());
+  EXPECT_TRUE(response_data.arguments().IsEmpty());
+  EXPECT_TRUE(guid4 == response_data.guid());
+  EXPECT_STREQ(kResponseStatusNoUpdate, response_data.status());
+  EXPECT_TRUE(GUID_NULL == response_data.installation_id());
+  EXPECT_TRUE(response_data.ap().IsEmpty());
+  EXPECT_TRUE(response_data.success_url().IsEmpty());
+  EXPECT_TRUE(response_data.error_url().IsEmpty());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+  EXPECT_EQ(0, responses[guid4].num_components());
+
+  response_data = responses[guid2].update_response_data();
+  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.102.0/user_foo_v1.0.102.0.msi"),
+               response_data.url());
+  EXPECT_STREQ(_T("/XzRh1rpwqrDr6ashpmQnYZIzDI="), response_data.hash());
+  EXPECT_EQ(630152,               response_data.size());
+  EXPECT_EQ(NEEDS_ADMIN_NO,      response_data.needs_admin());
+  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());
+  EXPECT_STREQ(_T("/install"),    response_data.arguments());
+  EXPECT_TRUE(guid2 ==            response_data.guid());
+  EXPECT_TRUE(response_data.success_url().IsEmpty());
+  EXPECT_TRUE(response_data.error_url().IsEmpty());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+  EXPECT_EQ(0, responses[guid2].num_components());
+
+  response_data = responses[guid3].update_response_data();
+  EXPECT_TRUE(guid3 == response_data.guid());
+  EXPECT_STREQ(kResponseStatusRestrictedExportCountry, response_data.status());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+  EXPECT_EQ(0, responses[guid3].num_components());
+
+  response_data = responses[guid5].update_response_data();
+  EXPECT_TRUE(response_data.url().IsEmpty());
+  EXPECT_TRUE(response_data.hash().IsEmpty());
+  EXPECT_EQ(0, response_data.size());
+  EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());
+  EXPECT_TRUE(response_data.arguments().IsEmpty());
+  EXPECT_TRUE(guid5 == response_data.guid());
+  EXPECT_STREQ(kResponseStatusOsNotSupported, response_data.status());
+  EXPECT_TRUE(GUID_NULL == response_data.installation_id());
+  EXPECT_TRUE(response_data.ap().IsEmpty());
+  EXPECT_TRUE(response_data.success_url().IsEmpty());
+  EXPECT_STREQ(_T("http://foo.google.com/support/article.py?id=12345&")
+               _T("hl=es-419&os=5.1"),
+               response_data.error_url());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+  EXPECT_EQ(0, responses[guid5].num_components());
+}
+
+TEST_F(GoopdateXmlParserTest, ParseManifestFile_ServerManifest_Components) {
+  UpdateResponses responses;
+  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                    _T("server_manifest_components.xml")));
+
+  // App GUIDs.
+  GUID guid  = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}"));
+  GUID guid2 = StringToGuid(_T("{104844D6-7DDA-460B-89F0-FBF8AFDD0A67}"));
+  GUID guid3 = StringToGuid(_T("{884a01d9-fb67-430a-b491-28f960dd7309}"));
+  GUID guid4 = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9936}"));
+
+  ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(file_name, &responses));
+  ASSERT_EQ(kServerManifestComponentsResponseCount, responses.size());
+
+  UpdateResponse response(responses[guid]);
+  UpdateResponseData response_data(response.update_response_data());
+  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.101.0/test_foo_v1.0.101.0.msi"),
+               response_data.url());
+  EXPECT_STREQ(_T("6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="), response_data.hash());
+  EXPECT_EQ(80896, response_data.size());
+  EXPECT_EQ(NEEDS_ADMIN_YES, response_data.needs_admin());
+  EXPECT_TRUE(response_data.arguments().IsEmpty());
+  EXPECT_TRUE(guid == response_data.guid());
+  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());
+  EXPECT_TRUE(GUID_NULL == response_data.installation_id());
+  EXPECT_TRUE(response_data.ap().IsEmpty());
+  EXPECT_STREQ(_T("http://testsuccessurl.com"), response_data.success_url());
+  EXPECT_TRUE(response_data.error_url().IsEmpty());
+  EXPECT_TRUE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY, response_data.success_action());
+
+  UpdateResponseDatas expected_components;
+  UpdateResponseData temp;
+  temp.set_guid(StringToGuid(_T("{65C42695-84A0-41C4-B70F-D2786F674592}")));
+  temp.set_status(_T("ok"));
+  temp.set_url(_T("http://dl.google.com/foo/set_comp1.msi"));
+  temp.set_size(66324);
+  temp.set_hash(_T("6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="));
+  expected_components.insert(
+      std::pair<GUID, UpdateResponseData>(temp.guid(), temp));
+
+  UpdateResponseData temp2;
+  temp2.set_guid(StringToGuid(_T("{B318029C-3607-48EB-8DBB-33E8BA17BAF1}")));
+  temp2.set_status(_T("noupdate"));
+  expected_components.insert(
+      std::pair<GUID, UpdateResponseData>(temp2.guid(), temp2));
+
+  UpdateResponseData temp3;
+  temp3.set_guid(StringToGuid(_T("{D76AE6FC-1633-4131-B782-896804795DCB}")));
+  temp3.set_status(_T("ok"));
+  temp3.set_url(_T("http://tools.google.com/happy/some_comp_inst.msi"));
+  temp3.set_size(829984);
+  temp3.set_hash(_T("6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="));
+  expected_components.insert(
+      std::pair<GUID, UpdateResponseData>(temp3.guid(), temp3));
+
+  UpdateResponseData temp4;
+  temp4.set_guid(StringToGuid(_T("{67A52AEE-6E9F-4411-B425-F210B962CD6F}")));
+  temp4.set_status(_T("noupdate"));
+  expected_components.insert(
+      std::pair<GUID, UpdateResponseData>(temp4.guid(), temp4));
+
+  EXPECT_EQ(expected_components.size(), response.num_components());
+
+  UpdateResponseDatas::const_iterator it;
+  UpdateResponseDatas::const_iterator it_exp;
+  for (it = response.components_begin(), it_exp = expected_components.begin();
+       it_exp != expected_components.end();
+       ++it, ++it_exp) {
+    const UpdateResponseData& component = (*it).second;
+    const UpdateResponseData& component_expected = (*it_exp).second;
+
+    EXPECT_STREQ(component_expected.url(), component.url());
+    EXPECT_STREQ(component_expected.hash(), component.hash());
+    EXPECT_EQ(component_expected.size(), component.size());
+    EXPECT_EQ(component_expected.needs_admin(), component.needs_admin());
+    EXPECT_STREQ(component_expected.arguments(), component.arguments());
+    EXPECT_TRUE(::IsEqualGUID(component_expected.guid(), component.guid()));
+    EXPECT_STREQ(component_expected.status(), component.status());
+    EXPECT_TRUE(::IsEqualGUID(component_expected.installation_id(),
+                              component.installation_id()));
+    EXPECT_STREQ(component_expected.ap(), component.ap());
+    EXPECT_STREQ(component_expected.success_url(), component.success_url());
+    EXPECT_TRUE(response_data.error_url().IsEmpty());
+    EXPECT_EQ(component_expected.terminate_all_browsers(),
+              component.terminate_all_browsers());
+    EXPECT_EQ(component_expected.success_action(), component.success_action());
+  }
+
+  response = responses[guid4];
+  response_data = response.update_response_data();
+  EXPECT_TRUE(response_data.url().IsEmpty());
+  EXPECT_EQ(0, response_data.size());
+  EXPECT_TRUE(response_data.hash().IsEmpty());
+  EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());
+  EXPECT_TRUE(response_data.arguments().IsEmpty());
+  EXPECT_TRUE(guid4 == response_data.guid());
+  EXPECT_STREQ(kResponseStatusNoUpdate, response_data.status());
+  EXPECT_TRUE(GUID_NULL == response_data.installation_id());
+  EXPECT_TRUE(response_data.ap().IsEmpty());
+  EXPECT_TRUE(response_data.success_url().IsEmpty());
+  EXPECT_TRUE(response_data.error_url().IsEmpty());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+  EXPECT_EQ(1, response.num_components());
+
+  response = responses[guid2];
+  response_data = response.update_response_data();
+  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.102.0/user_foo_v1.0.102.0.msi"),
+               response_data.url());
+  EXPECT_STREQ(_T("/XzRh1rpwqrDr6ashpmQnYZIzDI="), response_data.hash());
+  EXPECT_EQ(630152,               response_data.size());
+  EXPECT_EQ(NEEDS_ADMIN_NO,      response_data.needs_admin());
+  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());
+  EXPECT_STREQ(_T("/install"),    response_data.arguments());
+  EXPECT_TRUE(guid2 ==            response_data.guid());
+  EXPECT_TRUE(response_data.success_url().IsEmpty());
+  EXPECT_TRUE(response_data.error_url().IsEmpty());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+  EXPECT_EQ(0, response.num_components());
+
+  response = responses[guid3];
+  response_data = response.update_response_data();
+  EXPECT_TRUE(guid3 == response_data.guid());
+  EXPECT_STREQ(kResponseStatusRestrictedExportCountry, response_data.status());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+  EXPECT_EQ(0, response.num_components());
+}
+
+TEST_F(GoopdateXmlParserTest, ParseManifestFile_EmptyFilename) {
+  CString empty_filename;
+  UpdateResponses responses;
+  EXPECT_EQ(E_INVALIDARG, GoopdateXmlParser::ParseManifestFile(empty_filename,
+                                                               &responses));
+}
+
+TEST_F(GoopdateXmlParserTest, ParseManifestFile_NoSuchFile) {
+  CString no_such_file(_T("no_such_file.xml"));
+  UpdateResponses responses;
+  EXPECT_EQ(0x800c0005, GoopdateXmlParser::ParseManifestFile(no_such_file,
+                                                             &responses));
+}
+
+// This is a duplicate of the ParseManifestFile test except that it uses
+// LoadXmlFileToMemory() and ParseManifestString().
+TEST_F(GoopdateXmlParserTest, ParseManifestString_ServerManifest) {
+  UpdateResponses responses;
+  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                    _T("server_manifest.xml")));
+  GUID guid  = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}"));
+  GUID guid2 = StringToGuid(_T("{104844D6-7DDA-460B-89F0-FBF8AFDD0A67}"));
+  GUID guid3 = StringToGuid(_T("{884a01d9-fb67-430a-b491-28f960dd7309}"));
+  GUID guid4 = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9936}"));
+  GUID guid5 = StringToGuid(_T("{8CF15C17-7BB5-433a-8E6C-C018D79D00B1}"));
+
+  CString manifest_contents;
+  EXPECT_SUCCEEDED(GoopdateXmlParser::LoadXmlFileToMemory(file_name,
+                                                          &manifest_contents));
+
+  ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestString(manifest_contents,
+                                                          &responses));
+  ASSERT_EQ(kServerManifestResponseCount, responses.size());
+
+  UpdateResponse response(responses[guid]);
+  UpdateResponseData response_data = response.update_response_data();
+  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.101.0/test_foo_v1.0.101.0.msi"),
+               response_data.url());
+  EXPECT_STREQ(_T("6bPU7OnbKAGJ1LOw6fpIUuQl1FQ="), response_data.hash());
+  EXPECT_EQ(80896, response_data.size());
+  EXPECT_EQ(NEEDS_ADMIN_YES, response_data.needs_admin());
+  EXPECT_TRUE(response_data.arguments().IsEmpty());
+  EXPECT_TRUE(guid == response_data.guid());
+  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());
+  EXPECT_TRUE(GUID_NULL == response_data.installation_id());
+  EXPECT_TRUE(response_data.ap().IsEmpty());
+  EXPECT_STREQ(_T("http://testsuccessurl.com"), response_data.success_url());
+  EXPECT_TRUE(response_data.error_url().IsEmpty());
+  EXPECT_TRUE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY, response_data.success_action());
+
+  response = responses[guid4];
+  response_data = response.update_response_data();
+  EXPECT_TRUE(response_data.url().IsEmpty());
+  EXPECT_EQ(0, response_data.size());
+  EXPECT_TRUE(response_data.hash().IsEmpty());
+  EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());
+  EXPECT_TRUE(response_data.arguments().IsEmpty());
+  EXPECT_TRUE(guid4 == response_data.guid());
+  EXPECT_STREQ(kResponseStatusNoUpdate, response_data.status());
+  EXPECT_TRUE(GUID_NULL == response_data.installation_id());
+  EXPECT_TRUE(response_data.ap().IsEmpty());
+  EXPECT_TRUE(response_data.success_url().IsEmpty());
+  EXPECT_TRUE(response_data.error_url().IsEmpty());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+
+  response = responses[guid2];
+  response_data = response.update_response_data();
+  EXPECT_STREQ(_T("http://dl.google.com/foo/1.0.102.0/user_foo_v1.0.102.0.msi"),
+               response_data.url());
+  EXPECT_STREQ(_T("/XzRh1rpwqrDr6ashpmQnYZIzDI="), response_data.hash());
+  EXPECT_EQ(630152,               response_data.size());
+  EXPECT_EQ(NEEDS_ADMIN_NO,      response_data.needs_admin());
+  EXPECT_STREQ(kResponseStatusOkValue, response_data.status());
+  EXPECT_STREQ(_T("/install"),    response_data.arguments());
+  EXPECT_TRUE(guid2 ==            response_data.guid());
+  EXPECT_TRUE(response_data.success_url().IsEmpty());
+  EXPECT_TRUE(response_data.error_url().IsEmpty());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+
+  response = responses[guid3];
+  response_data = response.update_response_data();
+  EXPECT_TRUE(guid3 == response_data.guid());
+  EXPECT_STREQ(kResponseStatusRestrictedExportCountry, response_data.status());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+
+  response = responses[guid5];
+  response_data = response.update_response_data();
+  EXPECT_TRUE(response_data.url().IsEmpty());
+  EXPECT_TRUE(response_data.hash().IsEmpty());
+  EXPECT_EQ(0, response_data.size());
+  EXPECT_EQ(NEEDS_ADMIN_NO, response_data.needs_admin());
+  EXPECT_TRUE(response_data.arguments().IsEmpty());
+  EXPECT_TRUE(guid5 == response_data.guid());
+  EXPECT_STREQ(kResponseStatusOsNotSupported, response_data.status());
+  EXPECT_TRUE(GUID_NULL == response_data.installation_id());
+  EXPECT_TRUE(response_data.ap().IsEmpty());
+  EXPECT_TRUE(response_data.success_url().IsEmpty());
+  EXPECT_STREQ(_T("http://foo.google.com/support/article.py?id=12345&")
+               _T("hl=es-419&os=5.1"),
+               response_data.error_url());
+  EXPECT_FALSE(response_data.terminate_all_browsers());
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, response_data.success_action());
+  EXPECT_EQ(0, response.num_components());
+}
+
+TEST_F(GoopdateXmlParserTest, ParseManifestString_EmptyString) {
+  CString empty_string;
+  UpdateResponses responses;
+  EXPECT_EQ(0xC00CE558, GoopdateXmlParser::ParseManifestString(empty_string,
+                                                               &responses));
+}
+
+TEST_F(GoopdateXmlParserTest, ParseManifestString_ManifestNotXml) {
+  CString not_xml(_T("<this> is not XML"));
+  UpdateResponses responses;
+  EXPECT_EQ(0xC00CE553, GoopdateXmlParser::ParseManifestString(not_xml,
+                                                               &responses));
+}
+
+TEST_F(GoopdateXmlParserTest, VerifyProtocolCompatibility) {
+  // Compatible versions (same major, actual minor >= expected)
+  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.0"), _T("2.0")));
+  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.00"), _T("2.0")));
+  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.001"), _T("2.0")));
+  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.1"), _T("2.0")));
+  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.9"), _T("2.0")));
+  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(_T("2.9"), _T("2.4")));
+
+  // Incompatible versions (actual < expected)
+  EXPECT_EQ(GOOPDATEXML_E_XMLVERSION,
+            VerifyProtocolCompatibility(_T("2.0"), _T("2.1")));
+  EXPECT_EQ(GOOPDATEXML_E_XMLVERSION,
+            VerifyProtocolCompatibility(_T("2.1"), _T("3.0")));
+
+  // Incompatible versions (actual major < expected major)
+  EXPECT_EQ(GOOPDATEXML_E_XMLVERSION,
+            VerifyProtocolCompatibility(_T("3.0"), _T("2.0")));
+  EXPECT_EQ(GOOPDATEXML_E_XMLVERSION,
+            VerifyProtocolCompatibility(_T("3.0"), _T("2.1")));
+  EXPECT_EQ(GOOPDATEXML_E_XMLVERSION,
+            VerifyProtocolCompatibility(_T("3.0"), _T("2.9")));
+
+  // VerifyProtocolCompatibility isn't perfect.
+  // This test case succeeds but should return GOOPDATEXML_E_XMLVERSION.
+  // We shouldn't ever see this case in a real file.
+  EXPECT_SUCCEEDED(VerifyProtocolCompatibility(
+                       _T("3.0"), _T("2.99999999999999999999999999999")));
+}
+
+TEST_F(GoopdateXmlParserTest, LoadXmlFileToMemory) {
+  CString base_seed_path(ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                         _T("seed_manifest_with_args.xml")));
+  const CString kExpectedManifestContents(
+      _T("<?xml version=\"1.0\"?>\r\n")
+      _T("<gupdate protocol=\"2.0\" signature=\"\" xmlns=\"http://www.google.com/update2/install\">\r\n")   // NOLINT
+      _T("\t<install appguid=\"{283EAF47-8817-4c2b-A801-AD1FADFB7BAA}\" needsadmin=\"true\" iid=\"{874E4D29-8671-40C8-859F-4DECA4819999}\" client=\"someclient\" ap=\"1.0-dev\"/>\r\n")   // NOLINT
+      _T("</gupdate>\r\n"));
+
+  CString manifest_contents;
+  EXPECT_SUCCEEDED(GoopdateXmlParser::LoadXmlFileToMemory(base_seed_path,
+                                                          &manifest_contents));
+
+  EXPECT_STREQ(kExpectedManifestContents, manifest_contents);
+}
+
+TEST_F(GoopdateXmlParserTest, LoadXmlFileToMemory_EmptyFilename) {
+  CString empty_filename;
+  CString manifest_contents;
+  EXPECT_EQ(E_INVALIDARG, GoopdateXmlParser::LoadXmlFileToMemory(
+                              empty_filename, &manifest_contents));
+}
+
+TEST_F(GoopdateXmlParserTest, LoadXmlFileToMemory_NoSuchFile) {
+  CString no_such_file(_T("no_such_file.xml"));
+  CString manifest_contents;
+  EXPECT_EQ(0x800c0005, GoopdateXmlParser::LoadXmlFileToMemory(
+                            no_such_file, &manifest_contents));
+}
+
+TEST_F(GoopdateXmlParserTest, ConvertStringToSuccessAction_EmptyString) {
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT, ConvertStringToSuccessAction(_T("")));
+}
+
+TEST_F(GoopdateXmlParserTest, ConvertStringToSuccessAction_Default) {
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT,
+            ConvertStringToSuccessAction(_T("default")));
+}
+
+TEST_F(GoopdateXmlParserTest, ConvertStringToSuccessAction_ExitSilently) {
+  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY,
+            ConvertStringToSuccessAction(_T("exitsilently")));
+}
+
+TEST_F(GoopdateXmlParserTest,
+       ConvertStringToSuccessAction_ExitSilentlyOnLaunchCmd) {
+  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD,
+            ConvertStringToSuccessAction(_T("exitsilentlyonlaunchcmd")));
+}
+
+TEST_F(GoopdateXmlParserTest, ConvertStringToSuccessAction_UnknownAction) {
+  ExpectAsserts expect_asserts;
+  EXPECT_EQ(SUCCESS_ACTION_DEFAULT,
+            ConvertStringToSuccessAction(_T("foo bar")));
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/main.cc b/goopdate/main.cc
index 848ddfb..265695e 100644
--- a/goopdate/main.cc
+++ b/goopdate/main.cc
@@ -1,78 +1,78 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include "omaha/common/logging.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/google_update_idl_datax.h"

-#include "omaha/goopdate/goopdate.h"

-

-namespace {

-

-HINSTANCE dll_instance = NULL;

-

-}  // namespace

-

-// Captures the module instance. Never call ::DisableThreadLibraryCalls in a

-// module that statically links with LIBC and it is not using

-// _beginthreadex for the thread creation. This will leak the _tiddata.

-extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void* res) {

-  switch (reason) {

-    case DLL_PROCESS_ATTACH:

-      dll_instance = instance;

-      break;

-    case DLL_THREAD_ATTACH:

-    case DLL_THREAD_DETACH:

-    case DLL_PROCESS_DETACH:

-    default:

-      break;

-  }

-

-  return PrxDllMain(instance, reason, res);

-}

-

-// Since this entry point is called by a tiny shell we've built without

-// CRT support, the command line parameters contain the command line that

-// the OS created the process with. By convention, the first token in the

-// command line string is the filename of the program executable. The CRT takes

-// care of that for program that link with the standard libraries. Therefore,

-// there is a difference in the command line that the OS knows and the

-// command line that is passed to WinMain by the CRT. Our command line

-// parsing code takes care of this difference.

-extern "C" int APIENTRY DllEntry(TCHAR* cmd_line, int cmd_show) {

-  OPT_LOG(L1, (_T("[DllEntry][%s]"), cmd_line));

-

-  bool is_local_system =  false;

-  HRESULT hr = omaha::IsSystemProcess(&is_local_system);

-  if (SUCCEEDED(hr)) {

-    omaha::Goopdate goopdate(is_local_system);

-    hr = goopdate.Main(dll_instance, cmd_line, cmd_show);

-    if (FAILED(hr)) {

-      OPT_LOG(LEVEL_ERROR, (_T("[Main failed][%s][0x%08x]"), cmd_line, hr));

-    }

-  }

-

-  OPT_LOG(L1, (_T("[DllEntry exit][0x%08x]"), hr));

-  return static_cast<int>(hr);

-}

-

-extern "C" STDAPI DllCanUnloadNow() {

-  return PrxDllCanUnloadNow();

-}

-

-extern "C" STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID* ptr) {

-  return PrxDllGetClassObject(clsid, iid, ptr);

-}

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include "omaha/common/logging.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/google_update_idl_datax.h"
+#include "omaha/goopdate/goopdate.h"
+
+namespace {
+
+HINSTANCE dll_instance = NULL;
+
+}  // namespace
+
+// Captures the module instance. Never call ::DisableThreadLibraryCalls in a
+// module that statically links with LIBC and it is not using
+// _beginthreadex for the thread creation. This will leak the _tiddata.
+extern "C" BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void* res) {
+  switch (reason) {
+    case DLL_PROCESS_ATTACH:
+      dll_instance = instance;
+      break;
+    case DLL_THREAD_ATTACH:
+    case DLL_THREAD_DETACH:
+    case DLL_PROCESS_DETACH:
+    default:
+      break;
+  }
+
+  return PrxDllMain(instance, reason, res);
+}
+
+// Since this entry point is called by a tiny shell we've built without
+// CRT support, the command line parameters contain the command line that
+// the OS created the process with. By convention, the first token in the
+// command line string is the filename of the program executable. The CRT takes
+// care of that for program that link with the standard libraries. Therefore,
+// there is a difference in the command line that the OS knows and the
+// command line that is passed to WinMain by the CRT. Our command line
+// parsing code takes care of this difference.
+extern "C" int APIENTRY DllEntry(TCHAR* cmd_line, int cmd_show) {
+  OPT_LOG(L1, (_T("[DllEntry][%s]"), cmd_line));
+
+  bool is_local_system =  false;
+  HRESULT hr = omaha::IsSystemProcess(&is_local_system);
+  if (SUCCEEDED(hr)) {
+    omaha::Goopdate goopdate(is_local_system);
+    hr = goopdate.Main(dll_instance, cmd_line, cmd_show);
+    if (FAILED(hr)) {
+      OPT_LOG(LEVEL_ERROR, (_T("[Main failed][%s][0x%08x]"), cmd_line, hr));
+    }
+  }
+
+  OPT_LOG(L1, (_T("[DllEntry exit][0x%08x]"), hr));
+  return static_cast<int>(hr);
+}
+
+extern "C" STDAPI DllCanUnloadNow() {
+  return PrxDllCanUnloadNow();
+}
+
+extern "C" STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID* ptr) {
+  return PrxDllGetClassObject(clsid, iid, ptr);
+}
+
diff --git a/goopdate/main.h b/goopdate/main.h
index 982713d..73f020f 100644
--- a/goopdate/main.h
+++ b/goopdate/main.h
@@ -1,26 +1,26 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_GOOPDATE_MAIN_H__

-#define OMAHA_GOOPDATE_MAIN_H__

-

-#include <windows.h>

-#include <tchar.h>

-

-extern "C" typedef int (APIENTRY *DllEntry)(const TCHAR* cmd_line,

-                                            int cmd_show);

-

-#endif  // OMAHA_GOOPDATE_MAIN_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_GOOPDATE_MAIN_H__
+#define OMAHA_GOOPDATE_MAIN_H__
+
+#include <windows.h>
+#include <tchar.h>
+
+extern "C" typedef int (APIENTRY *DllEntry)(const TCHAR* cmd_line,
+                                            int cmd_show);
+
+#endif  // OMAHA_GOOPDATE_MAIN_H__
diff --git a/goopdate/main_unittest.cc b/goopdate/main_unittest.cc
index 6ee4ed6..2e4d54c 100644
--- a/goopdate/main_unittest.cc
+++ b/goopdate/main_unittest.cc
@@ -1,42 +1,42 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include <shlwapi.h>

-

-#include "omaha/goopdate/main.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(MainTest, EntryPoint) {

-  TCHAR path[MAX_PATH] = {0};

-  ASSERT_TRUE(::GetModuleFileName(NULL, path, MAX_PATH));

-  ::PathRemoveFileSpec(path);

-  ASSERT_TRUE(::PathAppend(path, omaha::kGoopdateDllName));

-

-  HMODULE module(::LoadLibraryEx(path, NULL, 0));

-  ASSERT_TRUE(module);

-

-  DllEntry dll_entry = reinterpret_cast<DllEntry>(

-      ::GetProcAddress(module, omaha::kGoopdateDllEntryAnsi));

-  ASSERT_TRUE(dll_entry);

-

-  ::FreeLibrary(module);

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include <shlwapi.h>
+
+#include "omaha/goopdate/main.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(MainTest, EntryPoint) {
+  TCHAR path[MAX_PATH] = {0};
+  ASSERT_TRUE(::GetModuleFileName(NULL, path, MAX_PATH));
+  ::PathRemoveFileSpec(path);
+  ASSERT_TRUE(::PathAppend(path, omaha::kGoopdateDllName));
+
+  HMODULE module(::LoadLibraryEx(path, NULL, 0));
+  ASSERT_TRUE(module);
+
+  DllEntry dll_entry = reinterpret_cast<DllEntry>(
+      ::GetProcAddress(module, omaha::kGoopdateDllEntryAnsi));
+  ASSERT_TRUE(dll_entry);
+
+  ::FreeLibrary(module);
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/program_instance.cc b/goopdate/program_instance.cc
index 855686f..ba16544 100644
--- a/goopdate/program_instance.cc
+++ b/goopdate/program_instance.cc
@@ -1,47 +1,47 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-

-#include "omaha/goopdate/program_instance.h"

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-// The manner in which we prevent multiple instances of

-// goopdate running in the user session is to

-// use a local name for the singleton mutex, and

-// grab the mutex till the end of our lifetime.

-bool ProgramInstance::EnsureSingleInstance() {

-  return CheckSingleInstance();

-}

-

-bool ProgramInstance::CheckSingleInstance() {

-  ASSERT1(!mutex_name_.IsEmpty());

-

-  reset(mutex_, ::CreateMutex(NULL, false, mutex_name_));

-  if (!mutex_) {

-    // We were not able to create the mutex instance for some reason.

-    return false;

-  }

-  DWORD error = ::GetLastError();

-  if (error == ERROR_ALREADY_EXISTS) {

-    // The program instance is already running since the mutex already exists.

-    return false;

-  }

-  return true;

-}

-

-}  // namespace omaha

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+
+#include "omaha/goopdate/program_instance.h"
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+// The manner in which we prevent multiple instances of
+// goopdate running in the user session is to
+// use a local name for the singleton mutex, and
+// grab the mutex till the end of our lifetime.
+bool ProgramInstance::EnsureSingleInstance() {
+  return CheckSingleInstance();
+}
+
+bool ProgramInstance::CheckSingleInstance() {
+  ASSERT1(!mutex_name_.IsEmpty());
+
+  reset(mutex_, ::CreateMutex(NULL, false, mutex_name_));
+  if (!mutex_) {
+    // We were not able to create the mutex instance for some reason.
+    return false;
+  }
+  DWORD error = ::GetLastError();
+  if (error == ERROR_ALREADY_EXISTS) {
+    // The program instance is already running since the mutex already exists.
+    return false;
+  }
+  return true;
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/program_instance.h b/goopdate/program_instance.h
index ae7cc82..98b0a4b 100644
--- a/goopdate/program_instance.h
+++ b/goopdate/program_instance.h
@@ -1,46 +1,46 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// TODO(omaha): move the code to common.

-

-#ifndef OMAHA_GOOPDATE_PROGRAM_INSTANCE_H__

-#define OMAHA_GOOPDATE_PROGRAM_INSTANCE_H__

-

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-#include "omaha/third_party/smartany/auto_any.h"

-

-namespace omaha {

-

-  // Helps limit the number of instances of a program. The class itself does not

-  // limit the number of instances. The calling code is expected to take action

-  // based on the return of EnsureSingleInstance function.

-  class ProgramInstance {

-   public:

-    explicit ProgramInstance(const TCHAR* mutex_name)

-        : mutex_name_(mutex_name) {}

-    virtual ~ProgramInstance() {}

-    bool EnsureSingleInstance();

-   private:

-    bool CheckSingleInstance();

-    CString mutex_name_;

-    auto_mutex mutex_;

-    DISALLOW_EVIL_CONSTRUCTORS(ProgramInstance);

-  };

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_PROGRAM_INSTANCE_H__

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// TODO(omaha): move the code to common.
+
+#ifndef OMAHA_GOOPDATE_PROGRAM_INSTANCE_H__
+#define OMAHA_GOOPDATE_PROGRAM_INSTANCE_H__
+
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+#include "omaha/third_party/smartany/auto_any.h"
+
+namespace omaha {
+
+  // Helps limit the number of instances of a program. The class itself does not
+  // limit the number of instances. The calling code is expected to take action
+  // based on the return of EnsureSingleInstance function.
+  class ProgramInstance {
+   public:
+    explicit ProgramInstance(const TCHAR* mutex_name)
+        : mutex_name_(mutex_name) {}
+    virtual ~ProgramInstance() {}
+    bool EnsureSingleInstance();
+   private:
+    bool CheckSingleInstance();
+    CString mutex_name_;
+    auto_mutex mutex_;
+    DISALLOW_EVIL_CONSTRUCTORS(ProgramInstance);
+  };
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_PROGRAM_INSTANCE_H__
diff --git a/goopdate/request.cc b/goopdate/request.cc
index 1f0707a..53c51b7 100644
--- a/goopdate/request.cc
+++ b/goopdate/request.cc
@@ -1,52 +1,52 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// goopdate server request

-

-#include "omaha/goopdate/request.h"

-#include <stdlib.h>

-#include <vector>

-#include "omaha/common/commontypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/goopdate_utils.h"

-

-namespace omaha {

-

-Request::Request(bool is_machine)

-    : is_machine_(is_machine),

-      machine_id_(goopdate_utils::GetPersistentMachineId()),

-      user_id_(goopdate_utils::GetPersistentUserId(is_machine ?

-                                                   MACHINE_KEY_NAME :

-                                                   USER_KEY_NAME)),

-      version_(GetVersionString()),

-      test_source_(ConfigManager::Instance()->GetTestSource()) {

-  GUID req_id = GUID_NULL;

-  VERIFY1(SUCCEEDED(::CoCreateGuid(&req_id)));

-  request_id_ = GuidToString(req_id);

-  VERIFY1(SUCCEEDED(goopdate_utils::GetOSInfo(&os_version_,

-                                              &os_service_pack_)));

-}

-

-Request::~Request() {

-}

-

-void Request::AddAppRequest(const AppRequest& app_request) {

-  app_requests_.push_back(app_request);

-}

-

-}  // namespace

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// goopdate server request
+
+#include "omaha/goopdate/request.h"
+#include <stdlib.h>
+#include <vector>
+#include "omaha/common/commontypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/goopdate_utils.h"
+
+namespace omaha {
+
+Request::Request(bool is_machine)
+    : is_machine_(is_machine),
+      machine_id_(goopdate_utils::GetPersistentMachineId()),
+      user_id_(goopdate_utils::GetPersistentUserId(is_machine ?
+                                                   MACHINE_KEY_NAME :
+                                                   USER_KEY_NAME)),
+      version_(GetVersionString()),
+      test_source_(ConfigManager::Instance()->GetTestSource()) {
+  GUID req_id = GUID_NULL;
+  VERIFY1(SUCCEEDED(::CoCreateGuid(&req_id)));
+  request_id_ = GuidToString(req_id);
+  VERIFY1(SUCCEEDED(goopdate_utils::GetOSInfo(&os_version_,
+                                              &os_service_pack_)));
+}
+
+Request::~Request() {
+}
+
+void Request::AddAppRequest(const AppRequest& app_request) {
+  app_requests_.push_back(app_request);
+}
+
+}  // namespace
diff --git a/goopdate/request.h b/goopdate/request.h
index f835c5c..00e4b13 100644
--- a/goopdate/request.h
+++ b/goopdate/request.h
@@ -1,97 +1,97 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// goopdate server request

-

-#ifndef OMAHA_GOOPDATE_REQUEST_H__

-#define OMAHA_GOOPDATE_REQUEST_H__

-

-#include <atlstr.h>

-#include <map>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/utils.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/app_request.h"

-#include "omaha/worker/ping_event.h"

-

-namespace omaha {

-

-class PingMock;

-

-class Request {

- public:

-  explicit Request(bool is_machine);

-  ~Request();

-

-  bool is_machine() const { return is_machine_; }

-  void set_is_machine(bool is_machine) { is_machine_ = is_machine; }

-  CString machine_id() const { return machine_id_; }

-  void set_machine_id(const CString& machine_id) { machine_id_ = machine_id; }

-  CString user_id() const { return user_id_; }

-  void set_user_id(const CString& user_id) { user_id_ = user_id; }

-  CString version() const { return version_; }

-  void set_version(const CString& version) { version_ = version; }

-  CString os_version() const { return os_version_; }

-  void set_os_version(const CString& os_version) { os_version_ = os_version; }

-  CString os_service_pack() const { return os_service_pack_; }

-  void set_os_service_pack(const CString& os_service_pack) {

-    os_service_pack_ = os_service_pack;

-  }

-  CString test_source() const { return test_source_; }

-  void set_test_source(const CString& test_source) {

-    test_source_ = test_source;

-  }

-  CString request_id() const { return request_id_; }

-  void set_request_id(const CString& request_id) {

-    request_id_ = request_id;

-  }

-

-  size_t get_request_count() const { return app_requests_.size(); }

-  AppRequestVector::const_iterator app_requests_begin() const {

-    return app_requests_.begin();

-  }

-  AppRequestVector::const_iterator app_requests_end() const {

-    return app_requests_.end();

-  }

-

-  // Request will hold onto and manage/release the app_request instance.

-  void AddAppRequest(const AppRequest& app_request);

-

- private:

-

-  bool is_machine_;

-  CString machine_id_;

-  CString user_id_;

-  CString version_;

-  CString os_version_;

-  CString os_service_pack_;

-

-  // Identifies the source of the request as a test/production prober system.

-  CString test_source_;

-

-  // Unique identifier for this request, used to associate the same request

-  // received multiple times on the server.

-  CString request_id_;

-  AppRequestVector app_requests_;

-

-  friend class PingMock;

-

-  DISALLOW_IMPLICIT_CONSTRUCTORS(Request);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_REQUEST_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// goopdate server request
+
+#ifndef OMAHA_GOOPDATE_REQUEST_H__
+#define OMAHA_GOOPDATE_REQUEST_H__
+
+#include <atlstr.h>
+#include <map>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/utils.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/app_request.h"
+#include "omaha/worker/ping_event.h"
+
+namespace omaha {
+
+class PingMock;
+
+class Request {
+ public:
+  explicit Request(bool is_machine);
+  ~Request();
+
+  bool is_machine() const { return is_machine_; }
+  void set_is_machine(bool is_machine) { is_machine_ = is_machine; }
+  CString machine_id() const { return machine_id_; }
+  void set_machine_id(const CString& machine_id) { machine_id_ = machine_id; }
+  CString user_id() const { return user_id_; }
+  void set_user_id(const CString& user_id) { user_id_ = user_id; }
+  CString version() const { return version_; }
+  void set_version(const CString& version) { version_ = version; }
+  CString os_version() const { return os_version_; }
+  void set_os_version(const CString& os_version) { os_version_ = os_version; }
+  CString os_service_pack() const { return os_service_pack_; }
+  void set_os_service_pack(const CString& os_service_pack) {
+    os_service_pack_ = os_service_pack;
+  }
+  CString test_source() const { return test_source_; }
+  void set_test_source(const CString& test_source) {
+    test_source_ = test_source;
+  }
+  CString request_id() const { return request_id_; }
+  void set_request_id(const CString& request_id) {
+    request_id_ = request_id;
+  }
+
+  size_t get_request_count() const { return app_requests_.size(); }
+  AppRequestVector::const_iterator app_requests_begin() const {
+    return app_requests_.begin();
+  }
+  AppRequestVector::const_iterator app_requests_end() const {
+    return app_requests_.end();
+  }
+
+  // Request will hold onto and manage/release the app_request instance.
+  void AddAppRequest(const AppRequest& app_request);
+
+ private:
+
+  bool is_machine_;
+  CString machine_id_;
+  CString user_id_;
+  CString version_;
+  CString os_version_;
+  CString os_service_pack_;
+
+  // Identifies the source of the request as a test/production prober system.
+  CString test_source_;
+
+  // Unique identifier for this request, used to associate the same request
+  // received multiple times on the server.
+  CString request_id_;
+  AppRequestVector app_requests_;
+
+  friend class PingMock;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Request);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_REQUEST_H__
diff --git a/goopdate/request.xsd b/goopdate/request.xsd
index 98d5d30..640d0a5 100644
--- a/goopdate/request.xsd
+++ b/goopdate/request.xsd
@@ -1,64 +1,64 @@
-<?xml version="1.0" encoding="utf-8"?>

-<xs:schema 

-  attributeFormDefault="unqualified" 

-  elementFormDefault="qualified" 

-  targetNamespace="http://www.google.com/omaha/request" 

-  xmlns:xs="http://www.w3.org/2001/XMLSchema"

-  xmlns:ts="http://www.google.com/omaha/request">

-  <xs:simpleType name="RequestType">

-    <xs:restriction base="xs:string">

-      <xs:enumeration value="UpdateRequest" />

-    </xs:restriction>

-  </xs:simpleType>

-  <xs:simpleType name="GuidType">

-    <xs:restriction base="xs:string">

-      <xs:pattern value="{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}}" />

-    </xs:restriction>

-  </xs:simpleType>

-  <xs:element name="requests">

-    <xs:complexType>

-      <xs:sequence>

-        <xs:element maxOccurs="1" minOccurs="1" name="omaha">

-          <xs:complexType>

-            <xs:sequence>

-              <xs:element name="version" type="xs:string" />

-              <xs:element name="lang" type="xs:string" />

-              <xs:element name="country" type="xs:string" />

-              <xs:element name="machineid" type="ts:GuidType" />

-            </xs:sequence>

-          </xs:complexType>

-        </xs:element>

-        <xs:element maxOccurs="unbounded" name="request">

-          <xs:complexType>

-            <xs:sequence>

-              <xs:element name="userid" type="ts:GuidType" />

-              <xs:element name="version" type="xs:string" />

-              <xs:element name="lang" type="xs:string" />

-              <xs:element name="country" type="xs:string" />

-              <xs:element name="brand" type="xs:string" />

-              <xs:element minOccurs="0" name="rlz">

-                <xs:complexType mixed="true">

-                  <xs:simpleContent>

-                    <xs:extension base="xs:string">

-                      <xs:attribute name="appid" type="xs:string" use="optional" />

-                    </xs:extension>

-                  </xs:simpleContent>

-                </xs:complexType>

-              </xs:element>

-              <xs:element minOccurs="0" maxOccurs="unbounded" name="attr">

-                <xs:complexType mixed="true">

-                  <xs:attribute name="name" type="xs:string" />

-                </xs:complexType>

-              </xs:element>

-              <xs:element name="arguments" type="xs:string" />

-            </xs:sequence>

-            <xs:attribute name="appid" type="ts:GuidType" use="required" />

-            <xs:attribute name="appname" type="xs:string" use="optional" />

-            <xs:attribute name="type" type="ts:RequestType" use="required" />

-          </xs:complexType>

-        </xs:element>

-      </xs:sequence>

-      <xs:attribute name="ver" type="xs:decimal" use="required" />

-    </xs:complexType>

-  </xs:element>

+<?xml version="1.0" encoding="utf-8"?>
+<xs:schema 
+  attributeFormDefault="unqualified" 
+  elementFormDefault="qualified" 
+  targetNamespace="http://www.google.com/omaha/request" 
+  xmlns:xs="http://www.w3.org/2001/XMLSchema"
+  xmlns:ts="http://www.google.com/omaha/request">
+  <xs:simpleType name="RequestType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="UpdateRequest" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="GuidType">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}}" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:element name="requests">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="1" minOccurs="1" name="omaha">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="version" type="xs:string" />
+              <xs:element name="lang" type="xs:string" />
+              <xs:element name="country" type="xs:string" />
+              <xs:element name="machineid" type="ts:GuidType" />
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+        <xs:element maxOccurs="unbounded" name="request">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="userid" type="ts:GuidType" />
+              <xs:element name="version" type="xs:string" />
+              <xs:element name="lang" type="xs:string" />
+              <xs:element name="country" type="xs:string" />
+              <xs:element name="brand" type="xs:string" />
+              <xs:element minOccurs="0" name="rlz">
+                <xs:complexType mixed="true">
+                  <xs:simpleContent>
+                    <xs:extension base="xs:string">
+                      <xs:attribute name="appid" type="xs:string" use="optional" />
+                    </xs:extension>
+                  </xs:simpleContent>
+                </xs:complexType>
+              </xs:element>
+              <xs:element minOccurs="0" maxOccurs="unbounded" name="attr">
+                <xs:complexType mixed="true">
+                  <xs:attribute name="name" type="xs:string" />
+                </xs:complexType>
+              </xs:element>
+              <xs:element name="arguments" type="xs:string" />
+            </xs:sequence>
+            <xs:attribute name="appid" type="ts:GuidType" use="required" />
+            <xs:attribute name="appname" type="xs:string" use="optional" />
+            <xs:attribute name="type" type="ts:RequestType" use="required" />
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+      <xs:attribute name="ver" type="xs:decimal" use="required" />
+    </xs:complexType>
+  </xs:element>
 </xs:schema>
\ No newline at end of file
diff --git a/goopdate/resource.h b/goopdate/resource.h
index 48702da..ee53aad 100644
--- a/goopdate/resource.h
+++ b/goopdate/resource.h
@@ -1,32 +1,32 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_RESOURCE_H__

-#define OMAHA_GOOPDATE_RESOURCE_H__

-

-// For the IDI_APP

-#include "omaha/google_update/resource.h"

-

-// For IDD_INSTALL_STOPPED used in ui.

-#include "omaha/goopdate/resources/goopdateres/goopdate.grh"

-

-#define IDR_GOOGLE_UPDATE_WORKER_CLASS          1000

-#define IDR_GOOGLE_UPDATE_WORKER_CLASS_MACHINE  1001

-#define IDR_GOOGLE_UPDATE_SERVICE_APPID         1002

-#define IDR_GOOGLE_UPDATE_CORE_CLASS            1003

-#define IDI_ELEVATION_MONIKER_ICON              1004

-

-#endif  // OMAHA_GOOPDATE_RESOURCE_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_RESOURCE_H__
+#define OMAHA_GOOPDATE_RESOURCE_H__
+
+// For the IDI_APP
+#include "omaha/google_update/resource.h"
+
+// For IDD_INSTALL_STOPPED used in ui.
+#include "omaha/goopdate/resources/goopdateres/goopdate.grh"
+
+#define IDR_GOOGLE_UPDATE_WORKER_CLASS          1000
+#define IDR_GOOGLE_UPDATE_WORKER_CLASS_MACHINE  1001
+#define IDR_GOOGLE_UPDATE_SERVICE_APPID         1002
+#define IDR_GOOGLE_UPDATE_CORE_CLASS            1003
+#define IDI_ELEVATION_MONIKER_ICON              1004
+
+#endif  // OMAHA_GOOPDATE_RESOURCE_H__
+
diff --git a/goopdate/resource_manager.cc b/goopdate/resource_manager.cc
index 228459a..56d0ff2 100644
--- a/goopdate/resource_manager.cc
+++ b/goopdate/resource_manager.cc
@@ -1,429 +1,429 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-#include "omaha/goopdate/resource_manager.h"

-

-#include <windows.h>

-#include <map>

-#include <vector>

-#include "omaha/common/constants.h"

-#include "omaha/common/commontypes.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/file_ver.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/path.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-

-namespace omaha {

-

-ResourceManager::ResourceManager(bool is_machine, const CString& resource_dir)

-    : resource_dll_(NULL),

-      is_machine_(is_machine),

-      resource_dir_(resource_dir) {

-}

-

-ResourceManager::~ResourceManager() {

-}

-

-HRESULT ResourceManager::LoadResourceDll(const CString& language) {

-  HRESULT hr = LoadResourceDllInternal(language);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Resource dll load failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  // All CString.LoadString and CreateDialog calls will use this module.

-  _AtlBaseModule.SetResourceInstance(resource_dll_);

-

-  FileVer file_ver;

-  VERIFY1(file_ver.Open(resource_dll_filepath_));

-  language_ = file_ver.QueryValue(kLanguageVersionName);

-  OPT_LOG(L1, (_T("[Loaded resource dll %s]"), resource_dll_filepath_));

-

-  ASSERT1(!language_.IsEmpty());

-  ASSERT1(!resource_dll_filepath_.IsEmpty());

-  ASSERT1(resource_dll_);

-

-  return S_OK;

-}

-

-HRESULT ResourceManager::LoadResourceDllInternal(const CString& language) {

-  // First try to load the resource dll for the language parameter.

-  if (!language.IsEmpty() &&

-      SUCCEEDED(LoadLibraryAsDataFile(GetResourceDllName(language)))) {

-    return S_OK;

-  }

-

-  // If for some reason we don't have a language, look up the user

-  // locale and convert it into our lang string names and load that.

-  HRESULT hr = LoadLibraryAsDataFile(

-      GetResourceDllName(GetDefaultUserLanguage()));

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Could not load any language dll.]")));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT ResourceManager::LoadLibraryAsDataFile(const CString& filename) {

-  ASSERT1(!filename.IsEmpty());

-  ASSERT1(!resource_dir_.IsEmpty());

-

-  resource_dll_filepath_ = ConcatenatePath(resource_dir_, filename);

-  if (resource_dll_filepath_.IsEmpty()) {

-    ASSERT1(false);

-    return GOOPDATE_E_RESOURCE_DLL_PATH_EMPTY;

-  }

-  resource_dll_ = ::LoadLibraryEx(resource_dll_filepath_,

-                                  NULL,

-                                  LOAD_LIBRARY_AS_DATAFILE);

-  if (!resource_dll_) {

-    HRESULT hr = HRESULTFromLastError();

-    OPT_LOG(L2, (_T("[Could not load resource dll %s.]"),

-                 resource_dll_filepath_));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-CString ResourceManager::GetResourceDllName(const CString& language) {

-  ASSERT1(!language.IsEmpty());

-

-  CString actual_language(language);

-  // Handle specific special cases

-  // * Chinese (Hong Kong) - separate language but uses the zh-TW resource DLL.

-  // * Hebrew synonyms - convert he to iw.

-  if (!language.CompareNoCase(_T("zh-HK"))) {

-    actual_language = _T("zh-TW");

-  } else if (!language.CompareNoCase(_T("he"))) {

-    actual_language = _T("iw");

-  }

-

-  CString filename;

-  filename.Format(kGoopdateResourceDllName, actual_language);

-  return filename;

-}

-

-CString ResourceManager::GetDefaultUserLanguage() {

-  return GetLanguageForLangID(::GetUserDefaultLangID());

-}

-

-// If an exact match is not found, returns "en".

-CString ResourceManager::GetLanguageForLangID(LANGID langid) {

-  const TCHAR* const kUltimateFallbackLang = _T("en");

-

-  // Check for the default case.

-  if (!langid) {

-    return kUltimateFallbackLang;

-  }

-

-  // First try to find the exact match.

-  for (int i = 0; kLanguageTranslationTable[i].langid; i++) {

-    if (kLanguageTranslationTable[i].langid == langid) {

-      return kLanguageTranslationTable[i].lang;

-    }

-  }

-

-  return kUltimateFallbackLang;

-}

-

-bool ResourceManager::IsLanguageStringSupported(const CString& language) {

-  std::map<CString, bool> languages;

-  GetDistinctLanguageMapFromTranslationTable(&languages);

-  return languages.find(language) != languages.end();

-}

-

-void ResourceManager::GetSupportedLanguages(

-    std::vector<CString>* codes) {

-  ASSERT1(codes);

-  std::map<CString, bool> languages;

-  GetDistinctLanguageMapFromTranslationTable(&languages);

-  for (std::map<CString, bool>::const_iterator it = languages.begin();

-       it != languages.end();

-       ++it) {

-    codes->push_back(it->first);

-  }

-}

-

-void ResourceManager::GetSupportedLanguageDllNames(

-    std::vector<CString>* filenames) {

-  std::vector<CString> codes;

-  GetSupportedLanguages(&codes);

-

-  for (size_t i = 0; i < codes.size(); ++i) {

-    if (!codes[i].CompareNoCase(_T("zh-HK"))) {

-      // There is not a separate DLL for this language because we use zh-TW DLL.

-      continue;

-    }

-    filenames->push_back(GetResourceDllName(codes[i]));

-  }

-}

-

-void ResourceManager::GetDistinctLanguageMapFromTranslationTable(

-    std::map<CString, bool>* languages) {

-  ASSERT1(languages);

-

-  for (int i = 0; kLanguageTranslationTable[i].langid; i++) {

-    CString lang = kLanguageTranslationTable[i].lang;

-    languages->insert(std::make_pair(lang, true));

-  }

-}

-

-

-const ResourceManager::LangIDAndPath

-    ResourceManager::kLanguageTranslationTable[] = {

-  // First we collect all main languages here which need special treatment.

-  // Special treatment might be necessary because of:

-  //  1.) Google has a special region code which is "Google specific". They

-  //      trump everything and should be at the beginning. (e.g. "iw")

-  //  2.) Usually a lot of languages are like "en-US", "en-GB",... and start

-  //      with the main language. However some languages like Norwegian do not

-  //      follow this scheme and we put them therefore at the top.

-  // The matching algorithm will look first for the full match, but at the same

-  // time it will look for a partial match. We want to add therefore the partial

-  // matches as high as possible to get them as a fallback.

-  { 0x0409, _T("en")         },  // _T("English (United States)")

-  { 0x040d, _T("iw")         },  // _T("Hebrew")

-  { 0x0464, _T("fil")        },  // _T("Tagalog")

-  { 0x0414, _T("no")         },  // _T("Norwegian (Bokmal, Norway)")

-

-  // and then we have all dialects here:

-  // { 0x041c, _T("sq-AL")      },  // _T("Albanian (Albania)")")

-  // { 0x0484, _T("gsw-FR")     },  // _T("Alsatian (France)")

-  // { 0x045e, _T("am-ET")      },  // _T("Amharic (Ethiopia)")

-  { 0x1401, _T("ar")  },  // _T("ar-DZ")      },  // _T("Arabic (Algeria)")

-  { 0x3c01, _T("ar")  },  // _T("ar-BH")      },  // _T("Arabic (Bahrain)")

-  { 0x0c01, _T("ar")  },  // _T("ar-EG")      },  // _T("Arabic (Egypt)")

-  { 0x0801, _T("ar")  },  // _T("ar-IQ")      },  // _T("Arabic (Iraq)")

-  { 0x2c01, _T("ar")  },  // _T("ar-JO")      },  // _T("Arabic (Jordan)")

-  { 0x3401, _T("ar")  },  // _T("ar-KW")      },  // _T("Arabic (Kuwait)")

-  { 0x3001, _T("ar")  },  // _T("ar-LB")      },  // _T("Arabic (Lebanon)")

-  { 0x1001, _T("ar")  },  // _T("ar-LY")      },  // _T("Arabic (Libya)")

-  { 0x1801, _T("ar")  },  // _T("ar-MA")      },  // _T("Arabic (Morocco)")

-  { 0x2001, _T("ar")  },  // _T("ar-OM")      },  // _T("Arabic (Oman)")

-  { 0x4001, _T("ar")  },  // _T("ar-QA")      },  // _T("Arabic (Qatar)")

-  { 0x0401, _T("ar")  },  // _T("ar-SA")      },  // _T("Arabic (Saudi Arabia)")

-  { 0x2801, _T("ar")  },  // _T("ar-SY")      },  // _T("Arabic (Syria)")

-  { 0x1c01, _T("ar")  },  // _T("ar-TN")      },  // _T("Arabic (Tunisia)")

-  { 0x3801, _T("ar")  },  // _T("ar-AE")      },  // _T("Arabic (U.A.E.)")

-  { 0x2401, _T("ar")  },  // _T("ar-YE")      },  // _T("Arabic (Yemen)")

-  { 0x042b, _T("ar")  },  // _T("hy-AM")      },  // _T("Armenian (Armenia)")

-  // { 0x044d, _T("as-IN")      },  // _T("Assamese (India)")

-  // { 0x082c, _T("az-Cyrl-AZ") },  // _T("Azeri (Azerbaijan, Cyrillic)")

-  // { 0x042c, _T("az-Latn-AZ") },  // _T("Azeri (Azerbaijan, Latin)")

-  // { 0x046d, _T("ba-RU")      },  // _T("Bashkir (Russia)")

-  // { 0x042d, _T("eu-ES")      },  // _T("Basque (Basque)")

-  // { 0x0423, _T("be-BY")      },  // _T("Belarusian (Belarus)")

-  { 0x0445, _T("bn")  },  // _T("bn-IN")      },  // _T("Bengali (India)")

-  // { 0x201a, _T("bs-Cyrl-BA") },  // _T("Bosnian (Bosnia and Herzegovina,

-  //                                       Cyrillic)")

-  // { 0x141a, _T("bs-Latn-BA") },  // _T("Bosnian (Bosnia and Herzegovina,

-  //                                       Latin)")

-  // { 0x047e, _T("br-FR")      },  // _T("Breton (France)")

-  { 0x0402, _T("bg")  },  // _T("bg-BG")   },  // _T("Bulgarian (Bulgaria)")

-  { 0x0403, _T("ca")  },  // _T("ca-ES")   },  // _T("Catalan (Catalan)")

-  { 0x0c04, _T("zh-HK") },  // _T("zh-HK")     // _T("Chinese

-                            //   (Hong Kong SAR, PRC)")

-  { 0x1404, _T("zh-CN") },  // _T("zh-MO")   },  // _T("Chinese (Macao SAR)")

-  { 0x0804, _T("zh-CN") },  // _T("zh-CN")   },  // _T("Chinese (PRC)")

-  { 0x1004, _T("zh-CN") },  // _T("zh-SG")   },  // _T("Chinese (Singapore)")

-  { 0x0404, _T("zh-TW") },  // _T("Chinese (Taiwan)")

-  { 0x101a, _T("hr")    },  // _T("hr-BA")   },  // _T("Croatian

-                            //   (Bosnia and Herzegovina, Latin)")

-  { 0x041a, _T("hr")    },  // _T("hr-HR")   },  // _T("Croatian (Croatia)")

-  { 0x0405, _T("cs")    },  // _T("cs-CZ")   },  // _T("Czech (Czech Republic)")

-  { 0x0406, _T("da")    },  // _T("da-DK")   },  // _T("Danish (Denmark)")

-  // { 0x048c, _T("gbz-AF")     },  // _T("Dari (Afghanistan)")

-  // { 0x0465, _T("dv-MV")      },  // _T("Divehi (Maldives)")

-  { 0x0813, _T("nl")  },  // _T("nl-BE")   },  // _T("Dutch (Belgium)")

-  { 0x0413, _T("nl")  },  // _T("nl-NL")   },  // _T("Dutch (Netherlands)")

-  { 0x0c09, _T("en")  },  // _T("en-AU")   },  // _T("English (Australia)")

-  { 0x2809, _T("en")  },  // _T("en-BZ")   },  // _T("English (Belize)")

-  { 0x1009, _T("en")  },  // _T("en-CA")   },  // _T("English (Canada)")

-  { 0x2409, _T("en")  },  // _T("en-029")  },  // _T("English (Caribbean)")

-  { 0x4009, _T("en")  },  // _T("en-IN")   },  // _T("English (India)")

-  { 0x1809, _T("en")  },  // _T("en-IE")   },  // _T("English (Ireland)")

-  { 0x2009, _T("en")  },  // _T("en-JM")   },  // _T("English (Jamaica)")

-  { 0x4409, _T("en")  },  // _T("en-MY")   },  // _T("English (Malaysia)")

-  { 0x1409, _T("en")  },  // _T("en-NZ")   },  // _T("English (New Zealand)")

-  { 0x3409, _T("en")  },  // _T("en-PH")   },  // _T("English (Philippines)")

-  { 0x4809, _T("en")  },  // _T("en-SG")   },  // _T("English (Singapore)")

-  { 0x1c09, _T("en")  },  // _T("en-ZA")   },  // _T("English (South Africa)")

-  { 0x2c09, _T("en")  },  // _T("en-TT")   },  // _T("English

-                          //   (Trinidad and Tobago)")

-  { 0x0809, _T("en-GB") },  // _T("English (United Kingdom)")

-  { 0x3009, _T("en")    },  // _T("en-ZW")      },  // _T("English (Zimbabwe)")

-  { 0x0425, _T("et")  },  // _T("et-EE")   },  // _T("Estonian (Estonia)")

-  // { 0x0438, _T("fo-FO")  },  // _T("Faroese (Faroe Islands)")

-  { 0x0464, _T("fil") },  // _T("fil-PH")    },  // _T("Filipino (Philippines)")

-  { 0x040b, _T("fi")  },  // _T("fi-FI")      },  // _T("Finnish (Finland)")

-  { 0x080c, _T("fr")  },  // _T("fr-BE")      },  // _T("French (Belgium)")

-  { 0x0c0c, _T("fr")  },  // _T("fr-CA")      },  // _T("French (Canada)")

-  { 0x040c, _T("fr")  },  // _T("fr-FR")      },  // _T("French (France)")

-  { 0x140c, _T("fr")  },  // _T("fr-LU")      },  // _T("French (Luxembourg)")

-  { 0x180c, _T("fr")  },  // _T("fr-MC")      },  // _T("French (Monaco)")

-  { 0x100c, _T("fr")  },  // _T("fr-CH")      },  // _T("French (Switzerland)")

-  // { 0x0462, _T("fy-NL")      },  // _T("Frisian (Netherlands)")

-  // { 0x0456, _T("gl-ES")      },  // _T("Galician (Spain)")

-  // { 0x0437, _T("ka-GE")      },  // _T("Georgian (Georgia)")

-  { 0x0c07, _T("de")  },  // _T("de-AT")   },  // _T("German (Austria)")

-  { 0x0407, _T("de")  },  // _T("de-DE")   },  // _T("German (Germany)")

-  { 0x1407, _T("de")  },  // _T("de-LI")   },  // _T("German (Liechtenstein)")

-  { 0x1007, _T("de")  },  // _T("de-LU")   },  // _T("German (Luxembourg)")

-  { 0x0807, _T("de")  },  // _T("de-CH")   },  // _T("German (Switzerland)")

-  { 0x0408, _T("el")  },  // _T("el-GR")   },  // _T("Greek (Greece)")

-  // { 0x046f, _T("kl-GL")      },  // _T("Greenlandic (Greenland)")

-  { 0x0447, _T("gu")  },  // _T("gu-IN")      },  // _T("Gujarati (India)")

-  // { 0x0468, _T("ha-Latn-NG") },  // _T("Hausa (Nigeria, Latin)")

-  // { 0x040d, _T("he-IL")      },  // _T("Hebrew (Israel)")

-  { 0x0439, _T("hi")  },  // _T("hi-IN")   },  // _T("Hindi (India)")

-  { 0x040e, _T("hu")  },  // _T("hu-HU")   },  // _T("Hungarian (Hungary)")

-  { 0x040f, _T("is")  },  // _T("is-IS")      },  // _T("Icelandic (Iceland)")

-  // { 0x0470, _T("ig-NG")      },  // _T("Igbo (Nigeria)")

-  { 0x0421, _T("id")  },  // _T("id-ID")    },  // _T("Indonesian (Indonesia)")

-  // { 0x085d, _T("iu-Latn-CA") },  // _T("Inuktitut (Canada, Latin)")

-  // { 0x045d, _T("iu-Cans-CA") },  // _T("Inuktitut (Canada, Syllabics)")

-  // { 0x083c, _T("ga-IE")      },  // _T("Irish (Ireland)")

-  { 0x0410, _T("it")  },  // _T("it-IT")      },  // _T("Italian (Italy)")

-  { 0x0810, _T("it")  },  // _T("it-CH")      },  // _T("Italian (Switzerland)")

-  { 0x0411, _T("ja")  },  // _T("ja-JP")      },  // _T("Japanese (Japan)")

-  { 0x044b, _T("kn")  },  // _T("kn-IN")      },  // _T("Kannada (India)")

-  // { 0x043f, _T("kk-KZ")      },  // _T("Kazakh (Kazakhstan)")

-  // { 0x0453, _T("kh-KH")      },  // _T("Khmer (Cambodia)")

-  // { 0x0486, _T("qut-GT")     },  // _T("K'iche (Guatemala)")

-  // { 0x0487, _T("rw-RW")      },  // _T("Kinyarwanda (Rwanda)")

-  // { 0x0457, _T("kok-IN")     },  // _T("Konkani (India)")

-  { 0x0812, _T("ko")         },  // _T("ko-Jo")      },  // _T("Korean (Johab)")

-  { 0x0412, _T("ko")         },  // _T("ko-KR")      },  // _T("Korean (Korea)")

-  // { 0x0440, _T("ky-KG")      },  // _T("Kyrgyz (Kyrgyzstan)")

-  // { 0x0454, _T("lo-LA")      },  // _T("Lao (Lao PDR)")

-  { 0x0426, _T("lv")  },  // _T("lv-LV")   },  // _T("Latvian (Latvia)")

-  { 0x0427, _T("lt")  },  // _T("lt-LT")   },  // _T("Lithuanian (Lithuania)")

-  // { 0x082e, _T("dsb-DE")     },  // _T("Lower Sorbian (Germany)")

-  // { 0x046e, _T("lb-LU")      },  // _T("Luxembourgish (Luxembourg)")

-  // { 0x042f, _T("mk-MK")      },  // _T("Macedonian (Macedonia, FYROM)")

-  { 0x083e, _T("ms")  },  // _T("ms-BN")  },  // _T("Malay (Brunei Darussalam)")

-  { 0x043e, _T("ms")  },  // _T("ms-MY")      },  // _T("Malay (Malaysia)")

-  { 0x044c, _T("ml")  },  // _T("ml-IN")      },  // _T("Malayalam (India)")

-  // { 0x043a, _T("mt-MT")      },  // _T("Maltese (Malta)")

-  // { 0x0481, _T("mi-NZ")      },  // _T("Maori (New Zealand)")

-  // { 0x047a, _T("arn-CL")     },  // _T("Mapudungun (Chile)")

-  { 0x044e, _T("mr")  },  // _T("mr-IN")      },  // _T("Marathi (India)")

-  // { 0x047c, _T("moh-CA")     },  // _T("Mohawk (Canada)")

-  // { 0x0450, _T("mn-Cyrl-MN") },  // _T("Mongolian (Mongolia)")

-  // { 0x0850, _T("mn-Mong-CN") },  // _T("Mongolian (PRC)")

-  // { 0x0461, _T("ne-NP")      },  // _T("Nepali (Nepal)")

-  // { 0x0414, _T("nb-NO")      },  // _T("Norwegian (Bokmal, Norway)")

-  // { 0x0814, _T("nn-NO")      },  // _T("Norwegian (Nynorsk, Norway)")

-  // { 0x0482, _T("oc-FR")      },  // _T("Occitan (France)")

-  { 0x0448, _T("or")  },  // _T("or-IN") },  // _T("Oriya (India)")

-  // { 0x0463, _T("ps-AF") },  // _T("Pashto (Afghanistan)")

-  { 0x0429, _T("fa")  },  // _T("fa-IR")      },  // _T("Persian (Iran)")

-  { 0x0415, _T("pl")  },  // _T("pl-PL")      },  // _T("Polish (Poland)")

-  { 0x0416, _T("pt-BR")      },  // _T("Portuguese (Brazil)")

-  { 0x0816, _T("pt-PT")      },  // _T("Portuguese (Portugal)")

-  // { 0x0446, _T("pa-IN")      },  // _T("Punjabi (India)")

-  // { 0x046b, _T("quz-BO")     },  // _T("Quechua (Bolivia)")

-  // { 0x086b, _T("quz-EC")     },  // _T("Quechua (Ecuador)")

-  // { 0x0c6b, _T("quz-PE")     },  // _T("Quechua (Peru)")

-  { 0x0418, _T("ro")  },  // _T("ro-RO")      },  // _T("Romanian (Romania)")

-  // { 0x0417, _T("rm-CH")      },  // _T("Romansh (Switzerland)")

-  { 0x0419, _T("ru")  },  // _T("ru-RU")      },  // _T("Russian (Russia)")

-  // { 0x243b, _T("smn-FI")     },  // _T("Sami (Inari, Finland)")

-  // { 0x103b, _T("smj-NO")     },  // _T("Sami (Lule, Norway)")

-  // { 0x143b, _T("smj-SE")     },  // _T("Sami (Lule, Sweden)")

-  // { 0x0c3b, _T("se-FI")      },  // _T("Sami (Northern, Finland)")

-  // { 0x043b, _T("se-NO")      },  // _T("Sami (Northern, Norway)")

-  // { 0x083b, _T("se-SE")      },  // _T("Sami (Northern, Sweden)")

-  // { 0x203b, _T("sms-FI")     },  // _T("Sami (Skolt, Finland)")

-  // { 0x183b, _T("sma-NO")     },  // _T("Sami (Southern, Norway)")

-  // { 0x1c3b, _T("sma-SE")     },  // _T("Sami (Southern, Sweden)")

-  // { 0x044f, _T("sa-IN")      },  // _T("Sanskrit (India)")

-  { 0x1c1a, _T("sr")  },  // _T("sr-Cyrl-BA") },  // _T("Serbian

-                          //   (Bosnia and Herzegovina, Cyrillic)")

-  { 0x181a, _T("sr")  },  // _T("sr-Latn-BA") },  // _T("Serbian

-                          //   (Bosnia and Herzegovina, Latin)")

-  { 0x0c1a, _T("sr")  },  // _T("sr-Cyrl-CS") },  // _T("Serbian

-                          //   (Serbia and Montenegro, Cyrillic)")

-  { 0x081a, _T("sr")  },  // _T("sr-Latn-CS") },  // _T("Serbian

-                          //   (Serbia and Montenegro, Latin)")

-  // { 0x046c, _T("ns-ZA")      },  // _T("Sesotho sa Leboa/Northern Sotho

-  //                                       (South Africa)")

-  // { 0x0432, _T("tn-ZA")      },  // _T("Setswana/Tswana (South Africa)")

-  // { 0x045b, _T("si-LK")      },  // _T("Sinhala (Sri Lanka)")

-  { 0x041b, _T("sk")  },  // _T("sk-SK")   },  // _T("Slovak (Slovakia)")

-  { 0x0424, _T("sl")  },  // _T("sl-SI")   },  // _T("Slovenian (Slovenia)")

-  { 0x2c0a, _T("es-419") },  // _T("es-AR")   },  // _T("Spanish (Argentina)")

-  { 0x400a, _T("es-419") },  // _T("es-BO")   },  // _T("Spanish (Bolivia)")

-  { 0x340a, _T("es-419") },  // _T("es-CL")   },  // _T("Spanish (Chile)")

-  { 0x240a, _T("es-419") },  // _T("es-CO")   },  // _T("Spanish (Colombia)")

-  { 0x140a, _T("es-419") },  // _T("es-CR")   },  // _T("Spanish (Costa Rica)")

-  { 0x1c0a, _T("es-419") },  // _T("es-DO")   },  // _T("Spanish

-                                                  //     (Dominican Republic)")

-  { 0x300a, _T("es-419") },  // _T("es-EC")   },  // _T("Spanish (Ecuador)")

-  { 0x440a, _T("es-419") },  // _T("es-SV")   },  // _T("Spanish (El Salvador)")

-  { 0x100a, _T("es-419") },  // _T("es-GT")   },  // _T("Spanish (Guatemala)")

-  { 0x480a, _T("es-419") },  // _T("es-HN")   },  // _T("Spanish (Honduras)")

-  { 0x080a, _T("es-419") },  // _T("es-MX")   },  // _T("Spanish (Mexico)")

-  { 0x4c0a, _T("es-419") },  // _T("es-NI")   },  // _T("Spanish (Nicaragua)")

-  { 0x180a, _T("es-419") },  // _T("es-PA")   },  // _T("Spanish (Panama)")

-  { 0x3c0a, _T("es-419") },  // _T("es-PY")   },  // _T("Spanish (Paraguay)")

-  { 0x280a, _T("es-419") },  // _T("es-PE")   },  // _T("Spanish (Peru)")

-  { 0x500a, _T("es-419") },  // _T("es-PR")   },  // _T("Spanish (Puerto Rico)")

-  { 0x0c0a, _T("es")     },  // _T("es-ES")   },  // _T("Spanish (Spain)")

-  { 0x040a, _T("es")     },  // _T("es-ES_tradnl")   },

-                             // _T("Spanish (Spain, Traditional Sort)")

-  { 0x540a, _T("es-419") },  // _T("es-US")   },  // _T("Spanish

-                                                  //     (United States)")

-  { 0x380a, _T("es-419") },  // _T("es-UY")   },  // _T("Spanish (Uruguay)")

-  { 0x200a, _T("es-419") },  // _T("es-VE")   },  // _T("Spanish (Venezuela)")

-  // { 0x0441, _T("sw-KE")      },  // _T("Swahili (Kenya)")

-  { 0x081d, _T("sv")  },  // _T("sv-FI")      },  // _T("Swedish (Finland)")

-  { 0x041d, _T("sv")  },  // _T("sv-SE")      },  // _T("Swedish (Sweden)")

-  // { 0x045a, _T("syr-SY")     },  // _T("Syriac (Syria)")

-  // { 0x0428, _T("tg-Cyrl-TJ") },  // _T("Tajik (Tajikistan)")

-  // { 0x085f, _T("tmz-Latn-DZ")},  // _T("Tamazight (Algeria, Latin)")

-  { 0x0449, _T("ta")  },  // _T("ta-IN")      },  // _T("Tamil (India)")

-  // { 0x0444, _T("tt-RU") },  // _T("Tatar (Russia)")

-  { 0x044a, _T("te")  },  // _T("te-IN") }, // _T("Telugu (India)")

-  { 0x041e, _T("th")  },  // _T("th-TH")      },  // _T("Thai (Thailand)")

-  // { 0x0851, _T("bo-BT")      },  // _T("Tibetan (Bhutan)")

-  // { 0x0451, _T("bo-CN")      },  // _T("Tibetan (PRC)")

-  { 0x041f, _T("tr")  },  // _T("tr-TR")      },  // _T("Turkish (Turkey)")

-  // { 0x0442, _T("tk-TM")      },  // _T("Turkmen (Turkmenistan)")

-  // { 0x0480, _T("ug-CN")      },  // _T("Uighur (PRC)")

-  { 0x0422, _T("uk")  },  // _T("uk-UA")      },  // _T("Ukrainian (Ukraine)")

-  // { 0x042e, _T("wen-DE")     },  // _T("Upper Sorbian (Germany)")

-  // { 0x0820,  _T("tr-IN")      },  // _T("Urdu(India)")

-  { 0x0420, _T("ur")  },  // _T("ur-PK") },  // _T("Urdu (Pakistan)")

-  // { 0x0843, _T("uz-Cyrl-UZ") }, // _T("Uzbek (Uzbekistan, Cyrillic)")

-  // { 0x0443, _T("uz-Latn-UZ") },  // _T("Uzbek (Uzbekistan, Latin)")

-  { 0x042a, _T("vi")  },  // _T("vi-VN")      },  // _T("Vietnamese (Vietnam)")

-  // { 0x0452, _T("cy-GB")      },  // _T("Welsh (United Kingdom)")

-  // { 0x0488, _T("wo-SN")      },  // _T("Wolof (Senegal)")

-  // { 0x0434, _T("xh-ZA")      },  // _T("Xhosa/isiXhosa (South Africa)")

-  // { 0x0485, _T("sah-RU")     },  // _T("Yakut (Russia)")

-  // { 0x0478, _T("ii-CN")      },  // _T("Yi (PRC)")

-  // { 0x046a, _T("yo-NG") }, // _T("Yoruba (Nigeria)")

-  // { 0x0435, _T("zu-ZA") }, // _T("Zulu/isiZulu (South Africa)")

-  { 0x0000, _T("")           }   // The list termination.

-};

-

-}  // namespace omaha.

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+#include "omaha/goopdate/resource_manager.h"
+
+#include <windows.h>
+#include <map>
+#include <vector>
+#include "omaha/common/constants.h"
+#include "omaha/common/commontypes.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/file_ver.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/path.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+
+namespace omaha {
+
+ResourceManager::ResourceManager(bool is_machine, const CString& resource_dir)
+    : resource_dll_(NULL),
+      is_machine_(is_machine),
+      resource_dir_(resource_dir) {
+}
+
+ResourceManager::~ResourceManager() {
+}
+
+HRESULT ResourceManager::LoadResourceDll(const CString& language) {
+  HRESULT hr = LoadResourceDllInternal(language);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Resource dll load failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  // All CString.LoadString and CreateDialog calls will use this module.
+  _AtlBaseModule.SetResourceInstance(resource_dll_);
+
+  FileVer file_ver;
+  VERIFY1(file_ver.Open(resource_dll_filepath_));
+  language_ = file_ver.QueryValue(kLanguageVersionName);
+  OPT_LOG(L1, (_T("[Loaded resource dll %s]"), resource_dll_filepath_));
+
+  ASSERT1(!language_.IsEmpty());
+  ASSERT1(!resource_dll_filepath_.IsEmpty());
+  ASSERT1(resource_dll_);
+
+  return S_OK;
+}
+
+HRESULT ResourceManager::LoadResourceDllInternal(const CString& language) {
+  // First try to load the resource dll for the language parameter.
+  if (!language.IsEmpty() &&
+      SUCCEEDED(LoadLibraryAsDataFile(GetResourceDllName(language)))) {
+    return S_OK;
+  }
+
+  // If for some reason we don't have a language, look up the user
+  // locale and convert it into our lang string names and load that.
+  HRESULT hr = LoadLibraryAsDataFile(
+      GetResourceDllName(GetDefaultUserLanguage()));
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Could not load any language dll.]")));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT ResourceManager::LoadLibraryAsDataFile(const CString& filename) {
+  ASSERT1(!filename.IsEmpty());
+  ASSERT1(!resource_dir_.IsEmpty());
+
+  resource_dll_filepath_ = ConcatenatePath(resource_dir_, filename);
+  if (resource_dll_filepath_.IsEmpty()) {
+    ASSERT1(false);
+    return GOOPDATE_E_RESOURCE_DLL_PATH_EMPTY;
+  }
+  resource_dll_ = ::LoadLibraryEx(resource_dll_filepath_,
+                                  NULL,
+                                  LOAD_LIBRARY_AS_DATAFILE);
+  if (!resource_dll_) {
+    HRESULT hr = HRESULTFromLastError();
+    OPT_LOG(L2, (_T("[Could not load resource dll %s.]"),
+                 resource_dll_filepath_));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+CString ResourceManager::GetResourceDllName(const CString& language) {
+  ASSERT1(!language.IsEmpty());
+
+  CString actual_language(language);
+  // Handle specific special cases
+  // * Chinese (Hong Kong) - separate language but uses the zh-TW resource DLL.
+  // * Hebrew synonyms - convert he to iw.
+  if (!language.CompareNoCase(_T("zh-HK"))) {
+    actual_language = _T("zh-TW");
+  } else if (!language.CompareNoCase(_T("he"))) {
+    actual_language = _T("iw");
+  }
+
+  CString filename;
+  filename.Format(kGoopdateResourceDllName, actual_language);
+  return filename;
+}
+
+CString ResourceManager::GetDefaultUserLanguage() {
+  return GetLanguageForLangID(::GetUserDefaultLangID());
+}
+
+// If an exact match is not found, returns "en".
+CString ResourceManager::GetLanguageForLangID(LANGID langid) {
+  const TCHAR* const kUltimateFallbackLang = _T("en");
+
+  // Check for the default case.
+  if (!langid) {
+    return kUltimateFallbackLang;
+  }
+
+  // First try to find the exact match.
+  for (int i = 0; kLanguageTranslationTable[i].langid; i++) {
+    if (kLanguageTranslationTable[i].langid == langid) {
+      return kLanguageTranslationTable[i].lang;
+    }
+  }
+
+  return kUltimateFallbackLang;
+}
+
+bool ResourceManager::IsLanguageStringSupported(const CString& language) {
+  std::map<CString, bool> languages;
+  GetDistinctLanguageMapFromTranslationTable(&languages);
+  return languages.find(language) != languages.end();
+}
+
+void ResourceManager::GetSupportedLanguages(
+    std::vector<CString>* codes) {
+  ASSERT1(codes);
+  std::map<CString, bool> languages;
+  GetDistinctLanguageMapFromTranslationTable(&languages);
+  for (std::map<CString, bool>::const_iterator it = languages.begin();
+       it != languages.end();
+       ++it) {
+    codes->push_back(it->first);
+  }
+}
+
+void ResourceManager::GetSupportedLanguageDllNames(
+    std::vector<CString>* filenames) {
+  std::vector<CString> codes;
+  GetSupportedLanguages(&codes);
+
+  for (size_t i = 0; i < codes.size(); ++i) {
+    if (!codes[i].CompareNoCase(_T("zh-HK"))) {
+      // There is not a separate DLL for this language because we use zh-TW DLL.
+      continue;
+    }
+    filenames->push_back(GetResourceDllName(codes[i]));
+  }
+}
+
+void ResourceManager::GetDistinctLanguageMapFromTranslationTable(
+    std::map<CString, bool>* languages) {
+  ASSERT1(languages);
+
+  for (int i = 0; kLanguageTranslationTable[i].langid; i++) {
+    CString lang = kLanguageTranslationTable[i].lang;
+    languages->insert(std::make_pair(lang, true));
+  }
+}
+
+
+const ResourceManager::LangIDAndPath
+    ResourceManager::kLanguageTranslationTable[] = {
+  // First we collect all main languages here which need special treatment.
+  // Special treatment might be necessary because of:
+  //  1.) Google has a special region code which is "Google specific". They
+  //      trump everything and should be at the beginning. (e.g. "iw")
+  //  2.) Usually a lot of languages are like "en-US", "en-GB",... and start
+  //      with the main language. However some languages like Norwegian do not
+  //      follow this scheme and we put them therefore at the top.
+  // The matching algorithm will look first for the full match, but at the same
+  // time it will look for a partial match. We want to add therefore the partial
+  // matches as high as possible to get them as a fallback.
+  { 0x0409, _T("en")         },  // _T("English (United States)")
+  { 0x040d, _T("iw")         },  // _T("Hebrew")
+  { 0x0464, _T("fil")        },  // _T("Tagalog")
+  { 0x0414, _T("no")         },  // _T("Norwegian (Bokmal, Norway)")
+
+  // and then we have all dialects here:
+  // { 0x041c, _T("sq-AL")      },  // _T("Albanian (Albania)")")
+  // { 0x0484, _T("gsw-FR")     },  // _T("Alsatian (France)")
+  // { 0x045e, _T("am-ET")      },  // _T("Amharic (Ethiopia)")
+  { 0x1401, _T("ar")  },  // _T("ar-DZ")      },  // _T("Arabic (Algeria)")
+  { 0x3c01, _T("ar")  },  // _T("ar-BH")      },  // _T("Arabic (Bahrain)")
+  { 0x0c01, _T("ar")  },  // _T("ar-EG")      },  // _T("Arabic (Egypt)")
+  { 0x0801, _T("ar")  },  // _T("ar-IQ")      },  // _T("Arabic (Iraq)")
+  { 0x2c01, _T("ar")  },  // _T("ar-JO")      },  // _T("Arabic (Jordan)")
+  { 0x3401, _T("ar")  },  // _T("ar-KW")      },  // _T("Arabic (Kuwait)")
+  { 0x3001, _T("ar")  },  // _T("ar-LB")      },  // _T("Arabic (Lebanon)")
+  { 0x1001, _T("ar")  },  // _T("ar-LY")      },  // _T("Arabic (Libya)")
+  { 0x1801, _T("ar")  },  // _T("ar-MA")      },  // _T("Arabic (Morocco)")
+  { 0x2001, _T("ar")  },  // _T("ar-OM")      },  // _T("Arabic (Oman)")
+  { 0x4001, _T("ar")  },  // _T("ar-QA")      },  // _T("Arabic (Qatar)")
+  { 0x0401, _T("ar")  },  // _T("ar-SA")      },  // _T("Arabic (Saudi Arabia)")
+  { 0x2801, _T("ar")  },  // _T("ar-SY")      },  // _T("Arabic (Syria)")
+  { 0x1c01, _T("ar")  },  // _T("ar-TN")      },  // _T("Arabic (Tunisia)")
+  { 0x3801, _T("ar")  },  // _T("ar-AE")      },  // _T("Arabic (U.A.E.)")
+  { 0x2401, _T("ar")  },  // _T("ar-YE")      },  // _T("Arabic (Yemen)")
+  { 0x042b, _T("ar")  },  // _T("hy-AM")      },  // _T("Armenian (Armenia)")
+  // { 0x044d, _T("as-IN")      },  // _T("Assamese (India)")
+  // { 0x082c, _T("az-Cyrl-AZ") },  // _T("Azeri (Azerbaijan, Cyrillic)")
+  // { 0x042c, _T("az-Latn-AZ") },  // _T("Azeri (Azerbaijan, Latin)")
+  // { 0x046d, _T("ba-RU")      },  // _T("Bashkir (Russia)")
+  // { 0x042d, _T("eu-ES")      },  // _T("Basque (Basque)")
+  // { 0x0423, _T("be-BY")      },  // _T("Belarusian (Belarus)")
+  { 0x0445, _T("bn")  },  // _T("bn-IN")      },  // _T("Bengali (India)")
+  // { 0x201a, _T("bs-Cyrl-BA") },  // _T("Bosnian (Bosnia and Herzegovina,
+  //                                       Cyrillic)")
+  // { 0x141a, _T("bs-Latn-BA") },  // _T("Bosnian (Bosnia and Herzegovina,
+  //                                       Latin)")
+  // { 0x047e, _T("br-FR")      },  // _T("Breton (France)")
+  { 0x0402, _T("bg")  },  // _T("bg-BG")   },  // _T("Bulgarian (Bulgaria)")
+  { 0x0403, _T("ca")  },  // _T("ca-ES")   },  // _T("Catalan (Catalan)")
+  { 0x0c04, _T("zh-HK") },  // _T("zh-HK")     // _T("Chinese
+                            //   (Hong Kong SAR, PRC)")
+  { 0x1404, _T("zh-CN") },  // _T("zh-MO")   },  // _T("Chinese (Macao SAR)")
+  { 0x0804, _T("zh-CN") },  // _T("zh-CN")   },  // _T("Chinese (PRC)")
+  { 0x1004, _T("zh-CN") },  // _T("zh-SG")   },  // _T("Chinese (Singapore)")
+  { 0x0404, _T("zh-TW") },  // _T("Chinese (Taiwan)")
+  { 0x101a, _T("hr")    },  // _T("hr-BA")   },  // _T("Croatian
+                            //   (Bosnia and Herzegovina, Latin)")
+  { 0x041a, _T("hr")    },  // _T("hr-HR")   },  // _T("Croatian (Croatia)")
+  { 0x0405, _T("cs")    },  // _T("cs-CZ")   },  // _T("Czech (Czech Republic)")
+  { 0x0406, _T("da")    },  // _T("da-DK")   },  // _T("Danish (Denmark)")
+  // { 0x048c, _T("gbz-AF")     },  // _T("Dari (Afghanistan)")
+  // { 0x0465, _T("dv-MV")      },  // _T("Divehi (Maldives)")
+  { 0x0813, _T("nl")  },  // _T("nl-BE")   },  // _T("Dutch (Belgium)")
+  { 0x0413, _T("nl")  },  // _T("nl-NL")   },  // _T("Dutch (Netherlands)")
+  { 0x0c09, _T("en")  },  // _T("en-AU")   },  // _T("English (Australia)")
+  { 0x2809, _T("en")  },  // _T("en-BZ")   },  // _T("English (Belize)")
+  { 0x1009, _T("en")  },  // _T("en-CA")   },  // _T("English (Canada)")
+  { 0x2409, _T("en")  },  // _T("en-029")  },  // _T("English (Caribbean)")
+  { 0x4009, _T("en")  },  // _T("en-IN")   },  // _T("English (India)")
+  { 0x1809, _T("en")  },  // _T("en-IE")   },  // _T("English (Ireland)")
+  { 0x2009, _T("en")  },  // _T("en-JM")   },  // _T("English (Jamaica)")
+  { 0x4409, _T("en")  },  // _T("en-MY")   },  // _T("English (Malaysia)")
+  { 0x1409, _T("en")  },  // _T("en-NZ")   },  // _T("English (New Zealand)")
+  { 0x3409, _T("en")  },  // _T("en-PH")   },  // _T("English (Philippines)")
+  { 0x4809, _T("en")  },  // _T("en-SG")   },  // _T("English (Singapore)")
+  { 0x1c09, _T("en")  },  // _T("en-ZA")   },  // _T("English (South Africa)")
+  { 0x2c09, _T("en")  },  // _T("en-TT")   },  // _T("English
+                          //   (Trinidad and Tobago)")
+  { 0x0809, _T("en-GB") },  // _T("English (United Kingdom)")
+  { 0x3009, _T("en")    },  // _T("en-ZW")      },  // _T("English (Zimbabwe)")
+  { 0x0425, _T("et")  },  // _T("et-EE")   },  // _T("Estonian (Estonia)")
+  // { 0x0438, _T("fo-FO")  },  // _T("Faroese (Faroe Islands)")
+  { 0x0464, _T("fil") },  // _T("fil-PH")    },  // _T("Filipino (Philippines)")
+  { 0x040b, _T("fi")  },  // _T("fi-FI")      },  // _T("Finnish (Finland)")
+  { 0x080c, _T("fr")  },  // _T("fr-BE")      },  // _T("French (Belgium)")
+  { 0x0c0c, _T("fr")  },  // _T("fr-CA")      },  // _T("French (Canada)")
+  { 0x040c, _T("fr")  },  // _T("fr-FR")      },  // _T("French (France)")
+  { 0x140c, _T("fr")  },  // _T("fr-LU")      },  // _T("French (Luxembourg)")
+  { 0x180c, _T("fr")  },  // _T("fr-MC")      },  // _T("French (Monaco)")
+  { 0x100c, _T("fr")  },  // _T("fr-CH")      },  // _T("French (Switzerland)")
+  // { 0x0462, _T("fy-NL")      },  // _T("Frisian (Netherlands)")
+  // { 0x0456, _T("gl-ES")      },  // _T("Galician (Spain)")
+  // { 0x0437, _T("ka-GE")      },  // _T("Georgian (Georgia)")
+  { 0x0c07, _T("de")  },  // _T("de-AT")   },  // _T("German (Austria)")
+  { 0x0407, _T("de")  },  // _T("de-DE")   },  // _T("German (Germany)")
+  { 0x1407, _T("de")  },  // _T("de-LI")   },  // _T("German (Liechtenstein)")
+  { 0x1007, _T("de")  },  // _T("de-LU")   },  // _T("German (Luxembourg)")
+  { 0x0807, _T("de")  },  // _T("de-CH")   },  // _T("German (Switzerland)")
+  { 0x0408, _T("el")  },  // _T("el-GR")   },  // _T("Greek (Greece)")
+  // { 0x046f, _T("kl-GL")      },  // _T("Greenlandic (Greenland)")
+  { 0x0447, _T("gu")  },  // _T("gu-IN")      },  // _T("Gujarati (India)")
+  // { 0x0468, _T("ha-Latn-NG") },  // _T("Hausa (Nigeria, Latin)")
+  // { 0x040d, _T("he-IL")      },  // _T("Hebrew (Israel)")
+  { 0x0439, _T("hi")  },  // _T("hi-IN")   },  // _T("Hindi (India)")
+  { 0x040e, _T("hu")  },  // _T("hu-HU")   },  // _T("Hungarian (Hungary)")
+  { 0x040f, _T("is")  },  // _T("is-IS")      },  // _T("Icelandic (Iceland)")
+  // { 0x0470, _T("ig-NG")      },  // _T("Igbo (Nigeria)")
+  { 0x0421, _T("id")  },  // _T("id-ID")    },  // _T("Indonesian (Indonesia)")
+  // { 0x085d, _T("iu-Latn-CA") },  // _T("Inuktitut (Canada, Latin)")
+  // { 0x045d, _T("iu-Cans-CA") },  // _T("Inuktitut (Canada, Syllabics)")
+  // { 0x083c, _T("ga-IE")      },  // _T("Irish (Ireland)")
+  { 0x0410, _T("it")  },  // _T("it-IT")      },  // _T("Italian (Italy)")
+  { 0x0810, _T("it")  },  // _T("it-CH")      },  // _T("Italian (Switzerland)")
+  { 0x0411, _T("ja")  },  // _T("ja-JP")      },  // _T("Japanese (Japan)")
+  { 0x044b, _T("kn")  },  // _T("kn-IN")      },  // _T("Kannada (India)")
+  // { 0x043f, _T("kk-KZ")      },  // _T("Kazakh (Kazakhstan)")
+  // { 0x0453, _T("kh-KH")      },  // _T("Khmer (Cambodia)")
+  // { 0x0486, _T("qut-GT")     },  // _T("K'iche (Guatemala)")
+  // { 0x0487, _T("rw-RW")      },  // _T("Kinyarwanda (Rwanda)")
+  // { 0x0457, _T("kok-IN")     },  // _T("Konkani (India)")
+  { 0x0812, _T("ko")         },  // _T("ko-Jo")      },  // _T("Korean (Johab)")
+  { 0x0412, _T("ko")         },  // _T("ko-KR")      },  // _T("Korean (Korea)")
+  // { 0x0440, _T("ky-KG")      },  // _T("Kyrgyz (Kyrgyzstan)")
+  // { 0x0454, _T("lo-LA")      },  // _T("Lao (Lao PDR)")
+  { 0x0426, _T("lv")  },  // _T("lv-LV")   },  // _T("Latvian (Latvia)")
+  { 0x0427, _T("lt")  },  // _T("lt-LT")   },  // _T("Lithuanian (Lithuania)")
+  // { 0x082e, _T("dsb-DE")     },  // _T("Lower Sorbian (Germany)")
+  // { 0x046e, _T("lb-LU")      },  // _T("Luxembourgish (Luxembourg)")
+  // { 0x042f, _T("mk-MK")      },  // _T("Macedonian (Macedonia, FYROM)")
+  { 0x083e, _T("ms")  },  // _T("ms-BN")  },  // _T("Malay (Brunei Darussalam)")
+  { 0x043e, _T("ms")  },  // _T("ms-MY")      },  // _T("Malay (Malaysia)")
+  { 0x044c, _T("ml")  },  // _T("ml-IN")      },  // _T("Malayalam (India)")
+  // { 0x043a, _T("mt-MT")      },  // _T("Maltese (Malta)")
+  // { 0x0481, _T("mi-NZ")      },  // _T("Maori (New Zealand)")
+  // { 0x047a, _T("arn-CL")     },  // _T("Mapudungun (Chile)")
+  { 0x044e, _T("mr")  },  // _T("mr-IN")      },  // _T("Marathi (India)")
+  // { 0x047c, _T("moh-CA")     },  // _T("Mohawk (Canada)")
+  // { 0x0450, _T("mn-Cyrl-MN") },  // _T("Mongolian (Mongolia)")
+  // { 0x0850, _T("mn-Mong-CN") },  // _T("Mongolian (PRC)")
+  // { 0x0461, _T("ne-NP")      },  // _T("Nepali (Nepal)")
+  // { 0x0414, _T("nb-NO")      },  // _T("Norwegian (Bokmal, Norway)")
+  // { 0x0814, _T("nn-NO")      },  // _T("Norwegian (Nynorsk, Norway)")
+  // { 0x0482, _T("oc-FR")      },  // _T("Occitan (France)")
+  { 0x0448, _T("or")  },  // _T("or-IN") },  // _T("Oriya (India)")
+  // { 0x0463, _T("ps-AF") },  // _T("Pashto (Afghanistan)")
+  { 0x0429, _T("fa")  },  // _T("fa-IR")      },  // _T("Persian (Iran)")
+  { 0x0415, _T("pl")  },  // _T("pl-PL")      },  // _T("Polish (Poland)")
+  { 0x0416, _T("pt-BR")      },  // _T("Portuguese (Brazil)")
+  { 0x0816, _T("pt-PT")      },  // _T("Portuguese (Portugal)")
+  // { 0x0446, _T("pa-IN")      },  // _T("Punjabi (India)")
+  // { 0x046b, _T("quz-BO")     },  // _T("Quechua (Bolivia)")
+  // { 0x086b, _T("quz-EC")     },  // _T("Quechua (Ecuador)")
+  // { 0x0c6b, _T("quz-PE")     },  // _T("Quechua (Peru)")
+  { 0x0418, _T("ro")  },  // _T("ro-RO")      },  // _T("Romanian (Romania)")
+  // { 0x0417, _T("rm-CH")      },  // _T("Romansh (Switzerland)")
+  { 0x0419, _T("ru")  },  // _T("ru-RU")      },  // _T("Russian (Russia)")
+  // { 0x243b, _T("smn-FI")     },  // _T("Sami (Inari, Finland)")
+  // { 0x103b, _T("smj-NO")     },  // _T("Sami (Lule, Norway)")
+  // { 0x143b, _T("smj-SE")     },  // _T("Sami (Lule, Sweden)")
+  // { 0x0c3b, _T("se-FI")      },  // _T("Sami (Northern, Finland)")
+  // { 0x043b, _T("se-NO")      },  // _T("Sami (Northern, Norway)")
+  // { 0x083b, _T("se-SE")      },  // _T("Sami (Northern, Sweden)")
+  // { 0x203b, _T("sms-FI")     },  // _T("Sami (Skolt, Finland)")
+  // { 0x183b, _T("sma-NO")     },  // _T("Sami (Southern, Norway)")
+  // { 0x1c3b, _T("sma-SE")     },  // _T("Sami (Southern, Sweden)")
+  // { 0x044f, _T("sa-IN")      },  // _T("Sanskrit (India)")
+  { 0x1c1a, _T("sr")  },  // _T("sr-Cyrl-BA") },  // _T("Serbian
+                          //   (Bosnia and Herzegovina, Cyrillic)")
+  { 0x181a, _T("sr")  },  // _T("sr-Latn-BA") },  // _T("Serbian
+                          //   (Bosnia and Herzegovina, Latin)")
+  { 0x0c1a, _T("sr")  },  // _T("sr-Cyrl-CS") },  // _T("Serbian
+                          //   (Serbia and Montenegro, Cyrillic)")
+  { 0x081a, _T("sr")  },  // _T("sr-Latn-CS") },  // _T("Serbian
+                          //   (Serbia and Montenegro, Latin)")
+  // { 0x046c, _T("ns-ZA")      },  // _T("Sesotho sa Leboa/Northern Sotho
+  //                                       (South Africa)")
+  // { 0x0432, _T("tn-ZA")      },  // _T("Setswana/Tswana (South Africa)")
+  // { 0x045b, _T("si-LK")      },  // _T("Sinhala (Sri Lanka)")
+  { 0x041b, _T("sk")  },  // _T("sk-SK")   },  // _T("Slovak (Slovakia)")
+  { 0x0424, _T("sl")  },  // _T("sl-SI")   },  // _T("Slovenian (Slovenia)")
+  { 0x2c0a, _T("es-419") },  // _T("es-AR")   },  // _T("Spanish (Argentina)")
+  { 0x400a, _T("es-419") },  // _T("es-BO")   },  // _T("Spanish (Bolivia)")
+  { 0x340a, _T("es-419") },  // _T("es-CL")   },  // _T("Spanish (Chile)")
+  { 0x240a, _T("es-419") },  // _T("es-CO")   },  // _T("Spanish (Colombia)")
+  { 0x140a, _T("es-419") },  // _T("es-CR")   },  // _T("Spanish (Costa Rica)")
+  { 0x1c0a, _T("es-419") },  // _T("es-DO")   },  // _T("Spanish
+                                                  //     (Dominican Republic)")
+  { 0x300a, _T("es-419") },  // _T("es-EC")   },  // _T("Spanish (Ecuador)")
+  { 0x440a, _T("es-419") },  // _T("es-SV")   },  // _T("Spanish (El Salvador)")
+  { 0x100a, _T("es-419") },  // _T("es-GT")   },  // _T("Spanish (Guatemala)")
+  { 0x480a, _T("es-419") },  // _T("es-HN")   },  // _T("Spanish (Honduras)")
+  { 0x080a, _T("es-419") },  // _T("es-MX")   },  // _T("Spanish (Mexico)")
+  { 0x4c0a, _T("es-419") },  // _T("es-NI")   },  // _T("Spanish (Nicaragua)")
+  { 0x180a, _T("es-419") },  // _T("es-PA")   },  // _T("Spanish (Panama)")
+  { 0x3c0a, _T("es-419") },  // _T("es-PY")   },  // _T("Spanish (Paraguay)")
+  { 0x280a, _T("es-419") },  // _T("es-PE")   },  // _T("Spanish (Peru)")
+  { 0x500a, _T("es-419") },  // _T("es-PR")   },  // _T("Spanish (Puerto Rico)")
+  { 0x0c0a, _T("es")     },  // _T("es-ES")   },  // _T("Spanish (Spain)")
+  { 0x040a, _T("es")     },  // _T("es-ES_tradnl")   },
+                             // _T("Spanish (Spain, Traditional Sort)")
+  { 0x540a, _T("es-419") },  // _T("es-US")   },  // _T("Spanish
+                                                  //     (United States)")
+  { 0x380a, _T("es-419") },  // _T("es-UY")   },  // _T("Spanish (Uruguay)")
+  { 0x200a, _T("es-419") },  // _T("es-VE")   },  // _T("Spanish (Venezuela)")
+  // { 0x0441, _T("sw-KE")      },  // _T("Swahili (Kenya)")
+  { 0x081d, _T("sv")  },  // _T("sv-FI")      },  // _T("Swedish (Finland)")
+  { 0x041d, _T("sv")  },  // _T("sv-SE")      },  // _T("Swedish (Sweden)")
+  // { 0x045a, _T("syr-SY")     },  // _T("Syriac (Syria)")
+  // { 0x0428, _T("tg-Cyrl-TJ") },  // _T("Tajik (Tajikistan)")
+  // { 0x085f, _T("tmz-Latn-DZ")},  // _T("Tamazight (Algeria, Latin)")
+  { 0x0449, _T("ta")  },  // _T("ta-IN")      },  // _T("Tamil (India)")
+  // { 0x0444, _T("tt-RU") },  // _T("Tatar (Russia)")
+  { 0x044a, _T("te")  },  // _T("te-IN") }, // _T("Telugu (India)")
+  { 0x041e, _T("th")  },  // _T("th-TH")      },  // _T("Thai (Thailand)")
+  // { 0x0851, _T("bo-BT")      },  // _T("Tibetan (Bhutan)")
+  // { 0x0451, _T("bo-CN")      },  // _T("Tibetan (PRC)")
+  { 0x041f, _T("tr")  },  // _T("tr-TR")      },  // _T("Turkish (Turkey)")
+  // { 0x0442, _T("tk-TM")      },  // _T("Turkmen (Turkmenistan)")
+  // { 0x0480, _T("ug-CN")      },  // _T("Uighur (PRC)")
+  { 0x0422, _T("uk")  },  // _T("uk-UA")      },  // _T("Ukrainian (Ukraine)")
+  // { 0x042e, _T("wen-DE")     },  // _T("Upper Sorbian (Germany)")
+  // { 0x0820,  _T("tr-IN")      },  // _T("Urdu(India)")
+  { 0x0420, _T("ur")  },  // _T("ur-PK") },  // _T("Urdu (Pakistan)")
+  // { 0x0843, _T("uz-Cyrl-UZ") }, // _T("Uzbek (Uzbekistan, Cyrillic)")
+  // { 0x0443, _T("uz-Latn-UZ") },  // _T("Uzbek (Uzbekistan, Latin)")
+  { 0x042a, _T("vi")  },  // _T("vi-VN")      },  // _T("Vietnamese (Vietnam)")
+  // { 0x0452, _T("cy-GB")      },  // _T("Welsh (United Kingdom)")
+  // { 0x0488, _T("wo-SN")      },  // _T("Wolof (Senegal)")
+  // { 0x0434, _T("xh-ZA")      },  // _T("Xhosa/isiXhosa (South Africa)")
+  // { 0x0485, _T("sah-RU")     },  // _T("Yakut (Russia)")
+  // { 0x0478, _T("ii-CN")      },  // _T("Yi (PRC)")
+  // { 0x046a, _T("yo-NG") }, // _T("Yoruba (Nigeria)")
+  // { 0x0435, _T("zu-ZA") }, // _T("Zulu/isiZulu (South Africa)")
+  { 0x0000, _T("")           }   // The list termination.
+};
+
+}  // namespace omaha.
diff --git a/goopdate/resource_manager.h b/goopdate/resource_manager.h
index 075b6e7..26a20be 100644
--- a/goopdate/resource_manager.h
+++ b/goopdate/resource_manager.h
@@ -1,81 +1,81 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Omaha resource manager.

-// Design Notes: Currently the resource manager only supports one language.

-

-#ifndef OMAHA_GOOPDATE_RESOURCE_MANAGER_H__

-#define OMAHA_GOOPDATE_RESOURCE_MANAGER_H__

-

-#include <atlstr.h>

-#include <map>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class ResourceManager {

- public:

-  ResourceManager(bool is_machine, const CString& resource_dir);

-  ~ResourceManager();

-

-  // Loads the resource dll and sets it as the default resource dll in ATL.

-  // The resource manager tries to load the resource dll corresponding to

-  // the language in the following order:

-  // 1. Language parameter.

-  // 2. Language in the registry.

-  // 3. First file returned by NTFS in the module directory.

-  HRESULT LoadResourceDll(const CString& language);

-  static CString GetDefaultUserLanguage();

-  static CString GetLanguageForLangID(LANGID langid);

-  static bool IsLanguageStringSupported(const CString& language);

-  static void GetSupportedLanguages(std::vector<CString>* codes);

-  static void GetSupportedLanguageDllNames(std::vector<CString>* filenames);

-  HMODULE resource_dll() const { return resource_dll_; }

-  CString language() const { return language_; }

-  CString resource_dll_filepath() const { return resource_dll_filepath_; }

-

- private:

-  static CString GetResourceDllName(const CString& language);

-  HRESULT LoadResourceDllInternal(const CString& language);

-  HRESULT LoadLibraryAsDataFile(const CString& filename);

-

-  // The bool is only here as a key for the map.  This could be a hash_set but

-  // the compiler doesn't like hash_set<CString>.

-  static void GetDistinctLanguageMapFromTranslationTable(

-      std::map<CString, bool>* map_lang);

-

-  HMODULE resource_dll_;

-  bool is_machine_;

-  CString resource_dir_;

-  CString language_;

-  CString resource_dll_filepath_;

-

-  // This is the structure of the table which contains the language identifier

-  // and the associated language string.

-  struct LangIDAndPath {

-    LANGID langid;

-    TCHAR lang[12];

-  };

-  static const LangIDAndPath kLanguageTranslationTable[];

-

-  friend class ResourceManagerTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(ResourceManager);

-};

-

-}  // namespace omaha.

-

-#endif  // OMAHA_GOOPDATE_RESOURCE_MANAGER_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Omaha resource manager.
+// Design Notes: Currently the resource manager only supports one language.
+
+#ifndef OMAHA_GOOPDATE_RESOURCE_MANAGER_H__
+#define OMAHA_GOOPDATE_RESOURCE_MANAGER_H__
+
+#include <atlstr.h>
+#include <map>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class ResourceManager {
+ public:
+  ResourceManager(bool is_machine, const CString& resource_dir);
+  ~ResourceManager();
+
+  // Loads the resource dll and sets it as the default resource dll in ATL.
+  // The resource manager tries to load the resource dll corresponding to
+  // the language in the following order:
+  // 1. Language parameter.
+  // 2. Language in the registry.
+  // 3. First file returned by NTFS in the module directory.
+  HRESULT LoadResourceDll(const CString& language);
+  static CString GetDefaultUserLanguage();
+  static CString GetLanguageForLangID(LANGID langid);
+  static bool IsLanguageStringSupported(const CString& language);
+  static void GetSupportedLanguages(std::vector<CString>* codes);
+  static void GetSupportedLanguageDllNames(std::vector<CString>* filenames);
+  HMODULE resource_dll() const { return resource_dll_; }
+  CString language() const { return language_; }
+  CString resource_dll_filepath() const { return resource_dll_filepath_; }
+
+ private:
+  static CString GetResourceDllName(const CString& language);
+  HRESULT LoadResourceDllInternal(const CString& language);
+  HRESULT LoadLibraryAsDataFile(const CString& filename);
+
+  // The bool is only here as a key for the map.  This could be a hash_set but
+  // the compiler doesn't like hash_set<CString>.
+  static void GetDistinctLanguageMapFromTranslationTable(
+      std::map<CString, bool>* map_lang);
+
+  HMODULE resource_dll_;
+  bool is_machine_;
+  CString resource_dir_;
+  CString language_;
+  CString resource_dll_filepath_;
+
+  // This is the structure of the table which contains the language identifier
+  // and the associated language string.
+  struct LangIDAndPath {
+    LANGID langid;
+    TCHAR lang[12];
+  };
+  static const LangIDAndPath kLanguageTranslationTable[];
+
+  friend class ResourceManagerTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ResourceManager);
+};
+
+}  // namespace omaha.
+
+#endif  // OMAHA_GOOPDATE_RESOURCE_MANAGER_H__
diff --git a/goopdate/resource_manager_unittest.cc b/goopdate/resource_manager_unittest.cc
index 3d9a655..d850050 100644
--- a/goopdate/resource_manager_unittest.cc
+++ b/goopdate/resource_manager_unittest.cc
@@ -1,414 +1,414 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// ResourceManager unit tests.

-

-#include <map>

-#include <vector>

-#include "omaha/common/app_util.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/string.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/resource_manager.h"

-#include "omaha/goopdate/resources/goopdateres/goopdate.grh"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class ResourceManagerTest : public testing::Test {

- protected:

-  virtual void SetUp() {

-    path_ = ConcatenatePath(app_util::GetModuleDirectory(NULL),

-                            _T("unittest_support\\Omaha_1.2.x_resources"));

-    manager_.reset(new ResourceManager(false, path_));

-  }

-

-  virtual void TearDown() {

-  }

-

-  void SetMachine(bool is_machine) {

-    manager_->is_machine_ = is_machine;

-  }

-

-  void SetResourceDir(const CString& resource_dir) {

-    manager_->resource_dir_ = resource_dir;

-  }

-

-  void GetDistinctLanguageMapFromTranslationTable(

-      std::map<CString, bool>* languages) {

-    manager_->GetDistinctLanguageMapFromTranslationTable(languages);

-  }

-

-  CString GetLang(LANGID langid) {

-    return manager_->GetLanguageForLangID(langid);

-  }

-

-  static CString GetResourceDllName(const CString& language) {

-    return ResourceManager::GetResourceDllName(language);

-  }

-

-  scoped_ptr<ResourceManager> manager_;

-  CString path_;

-};

-

-TEST_F(ResourceManagerTest, GetResourceDllName) {

-  const CString kLang(_T("en"));

-  CString ret = GetResourceDllName(kLang);

-

-  CString expected_filename;

-  expected_filename.Format(kGoopdateResourceDllName, kLang);

-  EXPECT_STREQ(expected_filename, ret);

-}

-

-TEST_F(ResourceManagerTest, GetResourceDllName_SpecialCases) {

-  // zh-HK -> zh-TW

-  EXPECT_STREQ(_T("goopdateres_zh-TW.dll"), GetResourceDllName(_T("zh-TW")));

-  EXPECT_STREQ(_T("goopdateres_zh-TW.dll"), GetResourceDllName(_T("zh-HK")));

-

-  // he -> iw

-  EXPECT_STREQ(_T("goopdateres_iw.dll"), GetResourceDllName(_T("iw")));

-  EXPECT_STREQ(_T("goopdateres_iw.dll"), GetResourceDllName(_T("he")));

-}

-

-TEST_F(ResourceManagerTest, LoadResourceFail) {

-  SetMachine(false);

-  SetResourceDir(_T("non_existing\\abcddir"));

-

-  CString lang(_T("en"));

-  EXPECT_HRESULT_FAILED(manager_->LoadResourceDll(lang));

-  EXPECT_FALSE(manager_->resource_dll());

-  EXPECT_STREQ(manager_->language(), _T(""));

-}

-

-TEST_F(ResourceManagerTest, LoadResourceDllCmdLine) {

-  SetMachine(false);

-

-  CString lang(_T("ca"));

-  EXPECT_HRESULT_SUCCEEDED(manager_->LoadResourceDll(lang));

-  EXPECT_TRUE(manager_->resource_dll());

-  EXPECT_STREQ(manager_->language(), lang);

-

-  CString expected_filename;

-  expected_filename.Format(kGoopdateResourceDllName, lang);

-  CString expected_path = ConcatenatePath(path_, expected_filename);

-  EXPECT_STREQ(expected_path, manager_->resource_dll_filepath());

-}

-

-TEST_F(ResourceManagerTest, LoadResourceDllCmdLineMachine) {

-  SetMachine(true);

-

-  CString lang(_T("ca"));

-  EXPECT_HRESULT_SUCCEEDED(manager_->LoadResourceDll(lang));

-  EXPECT_TRUE(manager_->resource_dll());

-  EXPECT_STREQ(manager_->language(), lang);

-

-  CString expected_filename;

-  expected_filename.Format(kGoopdateResourceDllName, lang);

-  CString expected_path = ConcatenatePath(path_, expected_filename);

-  EXPECT_STREQ(expected_path, manager_->resource_dll_filepath());

-}

-

-TEST_F(ResourceManagerTest, GetLanguageForLangID_NoLangID) {

-  EXPECT_STREQ(_T("en"), ResourceManager::GetLanguageForLangID(0));

-}

-

-TEST_F(ResourceManagerTest, GetLanguageForLangID_SupportedIds) {

-  EXPECT_STREQ(_T("ar"), GetLang(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("bg"), GetLang(MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("ca"), GetLang(MAKELANGID(LANG_CATALAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("cs"), GetLang(MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("da"), GetLang(MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("de"), GetLang(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("el"), GetLang(MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("en-GB"), GetLang(MAKELANGID(LANG_ENGLISH,

-                                               SUBLANG_ENGLISH_UK)));

-  EXPECT_STREQ(_T("es"), GetLang(MAKELANGID(LANG_SPANISH,

-                                            SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("es"), GetLang(MAKELANGID(LANG_SPANISH,

-                                            SUBLANG_SPANISH)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_MEXICAN)));

-  EXPECT_STREQ(_T("es"), GetLang(MAKELANGID(LANG_SPANISH,

-                                            SUBLANG_SPANISH_MODERN)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_GUATEMALA)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_COSTA_RICA)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_PANAMA)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(

-      LANG_SPANISH,

-      SUBLANG_SPANISH_DOMINICAN_REPUBLIC)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_VENEZUELA)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_COLOMBIA)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_PERU)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_ARGENTINA)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_ECUADOR)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_CHILE)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_URUGUAY)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_PARAGUAY)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_BOLIVIA)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_EL_SALVADOR)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_HONDURAS)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_NICARAGUA)));

-  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,

-                                                SUBLANG_SPANISH_PUERTO_RICO)));

-  EXPECT_STREQ(_T("et"), GetLang(MAKELANGID(LANG_ESTONIAN,

-                                            SUBLANG_ESTONIAN_ESTONIA)));

-  EXPECT_STREQ(_T("fi"), GetLang(MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("fil"), GetLang(MAKELANGID(LANG_FILIPINO, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("fr"), GetLang(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("hi"), GetLang(MAKELANGID(LANG_HINDI, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("hr"), GetLang(MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("hr"), GetLang(MAKELANGID(LANG_SERBIAN,

-                                            SUBLANG_SERBIAN_CROATIA)));

-  EXPECT_STREQ(_T("hu"), GetLang(MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("id"), GetLang(MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("it"), GetLang(MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("iw"), GetLang(MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("ja"), GetLang(MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("ko"), GetLang(MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("lt"), GetLang(MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("lv"), GetLang(MAKELANGID(LANG_LATVIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("nl"), GetLang(MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("no"), GetLang(MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("pl"), GetLang(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("pt-BR"), GetLang(MAKELANGID(LANG_PORTUGUESE,

-                                               SUBLANG_PORTUGUESE_BRAZILIAN)));

-  EXPECT_STREQ(_T("pt-PT"), GetLang(MAKELANGID(LANG_PORTUGUESE,

-                                               SUBLANG_PORTUGUESE)));

-  EXPECT_STREQ(_T("ro"), GetLang(MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("ru"), GetLang(MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("sk"), GetLang(MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("sl"), GetLang(MAKELANGID(LANG_SLOVENIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("sr"), GetLang(

-      MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_CYRILLIC)));

-  EXPECT_STREQ(_T("sr"), GetLang(

-      MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_LATIN)));

-  EXPECT_STREQ(_T("sr"), GetLang(MAKELANGID(LANG_SERBIAN,

-                                            SUBLANG_SERBIAN_CYRILLIC)));

-  EXPECT_STREQ(_T("sr"), GetLang(MAKELANGID(LANG_SERBIAN,

-                                            SUBLANG_SERBIAN_LATIN)));

-  EXPECT_STREQ(_T("sv"), GetLang(MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("th"), GetLang(MAKELANGID(LANG_THAI, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("tr"), GetLang(MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("uk"), GetLang(MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("vi"), GetLang(MAKELANGID(LANG_VIETNAMESE, SUBLANG_DEFAULT)));

-  EXPECT_STREQ(_T("zh-HK"), GetLang(MAKELANGID(LANG_CHINESE,

-                                               SUBLANG_CHINESE_HONGKONG)));

-  EXPECT_STREQ(_T("zh-CN"), GetLang(MAKELANGID(LANG_CHINESE,

-                                               SUBLANG_CHINESE_MACAU)));

-  EXPECT_STREQ(_T("zh-CN"), GetLang(MAKELANGID(LANG_CHINESE,

-                                               SUBLANG_CHINESE_SIMPLIFIED)));

-  EXPECT_STREQ(_T("zh-CN"), GetLang(MAKELANGID(LANG_CHINESE,

-                                               SUBLANG_CHINESE_SINGAPORE)));

-  EXPECT_STREQ(_T("zh-TW"), GetLang(MAKELANGID(LANG_CHINESE,

-                                               SUBLANG_CHINESE_TRADITIONAL)));

-}

-

-// Unsupported languages and sublanguages fall back to "en".

-TEST_F(ResourceManagerTest, GetLanguageForLangID_UnsupportedSubLang) {

-  // LANG_NEUTRAL is unsupported.

-  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)));

-  // LANG_AFRIKAANS is unsupported.

-  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_AFRIKAANS, SUBLANG_NEUTRAL)));

-  // SUBLANG_NEUTRAL is unsupported.

-  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_SPANISH, SUBLANG_NEUTRAL)));

-  // SUBLANG_SYS_DEFAULT is unsupported. It happens to be 2, which is not

-  // supported for Hungarian but is for English, Spanish, and others/

-  EXPECT_STREQ(_T("en"),

-               GetLang(MAKELANGID(LANG_HUNGARIAN, SUBLANG_SYS_DEFAULT)));

-  EXPECT_STREQ(_T("es-419"),

-               GetLang(MAKELANGID(LANG_SPANISH, SUBLANG_SYS_DEFAULT)));

-  // 0x3f is an invalid sublang. There is a "es" file.

-  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_SPANISH, 0x3f)));

-  // 0x3f is an invalid sublang. There is not a "zh" file.

-  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_CHINESE, 0x3f)));

-}

-

-TEST_F(ResourceManagerTest, TestCountLanguagesInTranslationTable) {

-  std::map<CString, bool> languages;

-  GetDistinctLanguageMapFromTranslationTable(&languages);

-  // Number of language DLLs + zh-HK special case.

-  EXPECT_EQ(54 + 1, languages.size());

-}

-

-TEST_F(ResourceManagerTest, TestAppropriateLanguagesInTranslationTable) {

-  std::map<CString, bool> languages;

-  GetDistinctLanguageMapFromTranslationTable(&languages);

-

-  EXPECT_TRUE(languages.find(_T("ar")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("bg")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("bn")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("ca")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("cs")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("da")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("de")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("el")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("en-GB")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("en")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("es-419")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("es")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("et")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("fa")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("fi")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("fil")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("fr")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("gu")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("hi")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("hr")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("hu")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("id")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("is")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("it")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("iw")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("ja")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("kn")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("ko")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("lt")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("lv")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("ml")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("mr")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("ms")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("nl")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("no")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("or")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("pl")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("pt-BR")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("pt-PT")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("ro")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("ru")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("sk")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("sl")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("sr")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("sv")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("ta")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("te")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("th")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("tr")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("uk")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("ur")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("vi")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("zh-CN")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("zh-HK")) != languages.end());

-  EXPECT_TRUE(languages.find(_T("zh-TW")) != languages.end());

-}

-

-TEST_F(ResourceManagerTest, TestCountLanguageDlls) {

-  std::vector<CString> filenames;

-  ResourceManager::GetSupportedLanguageDllNames(&filenames);

-  EXPECT_EQ(54, filenames.size());

-}

-

-TEST_F(ResourceManagerTest, TestAppropriateLanguageDlls) {

-  std::vector<CString> filenames;

-  ResourceManager::GetSupportedLanguageDllNames(&filenames);

-

-  std::vector<CString>::iterator iter = filenames.begin();

-

-  EXPECT_STREQ(_T("goopdateres_ar.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_bg.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_bn.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_ca.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_cs.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_da.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_de.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_el.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_en.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_en-GB.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_es.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_es-419.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_et.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_fa.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_fi.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_fil.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_fr.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_gu.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_hi.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_hr.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_hu.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_id.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_is.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_it.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_iw.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_ja.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_kn.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_ko.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_lt.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_lv.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_ml.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_mr.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_ms.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_nl.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_no.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_or.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_pl.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_pt-BR.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_pt-PT.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_ro.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_ru.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_sk.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_sl.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_sr.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_sv.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_ta.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_te.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_th.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_tr.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_uk.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_ur.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_vi.dll"), *iter++);

-  EXPECT_STREQ(_T("goopdateres_zh-CN.dll"), *iter++);

-  // goopdateres_zh-HK.dll not present

-  EXPECT_STREQ(_T("goopdateres_zh-TW.dll"), *iter++);

-}

-

-TEST_F(ResourceManagerTest, RussianResourcesValid) {

-  SetResourceDir(app_util::GetModuleDirectory(NULL));

-

-  CString lang(_T("ru"));

-  EXPECT_HRESULT_SUCCEEDED(manager_->LoadResourceDll(lang));

-  EXPECT_TRUE(manager_->resource_dll());

-  EXPECT_STREQ(lang, manager_->language());

-

-  CString install_success(FormatResourceMessage(

-      IDS_APPLICATION_INSTALLED_SUCCESSFULLY, _T("Gears")));

-  EXPECT_STREQ("Благодарим вас за установку Gears.",

-               WideToUtf8(install_success));

-

-  CString install_fail(FormatResourceMessage(IDS_INSTALLER_FAILED_WITH_MESSAGE,

-                            _T("12345"), _T("Action failed.")));

-  EXPECT_STREQ("Ошибка установщика 12345: Action failed.",

-               WideToUtf8(install_fail));

-}

-

-}  // namespace omaha.

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// ResourceManager unit tests.
+
+#include <map>
+#include <vector>
+#include "omaha/common/app_util.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/string.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/resource_manager.h"
+#include "omaha/goopdate/resources/goopdateres/goopdate.grh"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class ResourceManagerTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    path_ = ConcatenatePath(app_util::GetModuleDirectory(NULL),
+                            _T("unittest_support\\Omaha_1.2.x_resources"));
+    manager_.reset(new ResourceManager(false, path_));
+  }
+
+  virtual void TearDown() {
+  }
+
+  void SetMachine(bool is_machine) {
+    manager_->is_machine_ = is_machine;
+  }
+
+  void SetResourceDir(const CString& resource_dir) {
+    manager_->resource_dir_ = resource_dir;
+  }
+
+  void GetDistinctLanguageMapFromTranslationTable(
+      std::map<CString, bool>* languages) {
+    manager_->GetDistinctLanguageMapFromTranslationTable(languages);
+  }
+
+  CString GetLang(LANGID langid) {
+    return manager_->GetLanguageForLangID(langid);
+  }
+
+  static CString GetResourceDllName(const CString& language) {
+    return ResourceManager::GetResourceDllName(language);
+  }
+
+  scoped_ptr<ResourceManager> manager_;
+  CString path_;
+};
+
+TEST_F(ResourceManagerTest, GetResourceDllName) {
+  const CString kLang(_T("en"));
+  CString ret = GetResourceDllName(kLang);
+
+  CString expected_filename;
+  expected_filename.Format(kGoopdateResourceDllName, kLang);
+  EXPECT_STREQ(expected_filename, ret);
+}
+
+TEST_F(ResourceManagerTest, GetResourceDllName_SpecialCases) {
+  // zh-HK -> zh-TW
+  EXPECT_STREQ(_T("goopdateres_zh-TW.dll"), GetResourceDllName(_T("zh-TW")));
+  EXPECT_STREQ(_T("goopdateres_zh-TW.dll"), GetResourceDllName(_T("zh-HK")));
+
+  // he -> iw
+  EXPECT_STREQ(_T("goopdateres_iw.dll"), GetResourceDllName(_T("iw")));
+  EXPECT_STREQ(_T("goopdateres_iw.dll"), GetResourceDllName(_T("he")));
+}
+
+TEST_F(ResourceManagerTest, LoadResourceFail) {
+  SetMachine(false);
+  SetResourceDir(_T("non_existing\\abcddir"));
+
+  CString lang(_T("en"));
+  EXPECT_HRESULT_FAILED(manager_->LoadResourceDll(lang));
+  EXPECT_FALSE(manager_->resource_dll());
+  EXPECT_STREQ(manager_->language(), _T(""));
+}
+
+TEST_F(ResourceManagerTest, LoadResourceDllCmdLine) {
+  SetMachine(false);
+
+  CString lang(_T("ca"));
+  EXPECT_HRESULT_SUCCEEDED(manager_->LoadResourceDll(lang));
+  EXPECT_TRUE(manager_->resource_dll());
+  EXPECT_STREQ(manager_->language(), lang);
+
+  CString expected_filename;
+  expected_filename.Format(kGoopdateResourceDllName, lang);
+  CString expected_path = ConcatenatePath(path_, expected_filename);
+  EXPECT_STREQ(expected_path, manager_->resource_dll_filepath());
+}
+
+TEST_F(ResourceManagerTest, LoadResourceDllCmdLineMachine) {
+  SetMachine(true);
+
+  CString lang(_T("ca"));
+  EXPECT_HRESULT_SUCCEEDED(manager_->LoadResourceDll(lang));
+  EXPECT_TRUE(manager_->resource_dll());
+  EXPECT_STREQ(manager_->language(), lang);
+
+  CString expected_filename;
+  expected_filename.Format(kGoopdateResourceDllName, lang);
+  CString expected_path = ConcatenatePath(path_, expected_filename);
+  EXPECT_STREQ(expected_path, manager_->resource_dll_filepath());
+}
+
+TEST_F(ResourceManagerTest, GetLanguageForLangID_NoLangID) {
+  EXPECT_STREQ(_T("en"), ResourceManager::GetLanguageForLangID(0));
+}
+
+TEST_F(ResourceManagerTest, GetLanguageForLangID_SupportedIds) {
+  EXPECT_STREQ(_T("ar"), GetLang(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("bg"), GetLang(MAKELANGID(LANG_BULGARIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("ca"), GetLang(MAKELANGID(LANG_CATALAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("cs"), GetLang(MAKELANGID(LANG_CZECH, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("da"), GetLang(MAKELANGID(LANG_DANISH, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("de"), GetLang(MAKELANGID(LANG_GERMAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("el"), GetLang(MAKELANGID(LANG_GREEK, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("en-GB"), GetLang(MAKELANGID(LANG_ENGLISH,
+                                               SUBLANG_ENGLISH_UK)));
+  EXPECT_STREQ(_T("es"), GetLang(MAKELANGID(LANG_SPANISH,
+                                            SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("es"), GetLang(MAKELANGID(LANG_SPANISH,
+                                            SUBLANG_SPANISH)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_MEXICAN)));
+  EXPECT_STREQ(_T("es"), GetLang(MAKELANGID(LANG_SPANISH,
+                                            SUBLANG_SPANISH_MODERN)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_GUATEMALA)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_COSTA_RICA)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_PANAMA)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(
+      LANG_SPANISH,
+      SUBLANG_SPANISH_DOMINICAN_REPUBLIC)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_VENEZUELA)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_COLOMBIA)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_PERU)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_ARGENTINA)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_ECUADOR)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_CHILE)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_URUGUAY)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_PARAGUAY)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_BOLIVIA)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_EL_SALVADOR)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_HONDURAS)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_NICARAGUA)));
+  EXPECT_STREQ(_T("es-419"), GetLang(MAKELANGID(LANG_SPANISH,
+                                                SUBLANG_SPANISH_PUERTO_RICO)));
+  EXPECT_STREQ(_T("et"), GetLang(MAKELANGID(LANG_ESTONIAN,
+                                            SUBLANG_ESTONIAN_ESTONIA)));
+  EXPECT_STREQ(_T("fi"), GetLang(MAKELANGID(LANG_FINNISH, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("fil"), GetLang(MAKELANGID(LANG_FILIPINO, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("fr"), GetLang(MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("hi"), GetLang(MAKELANGID(LANG_HINDI, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("hr"), GetLang(MAKELANGID(LANG_CROATIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("hr"), GetLang(MAKELANGID(LANG_SERBIAN,
+                                            SUBLANG_SERBIAN_CROATIA)));
+  EXPECT_STREQ(_T("hu"), GetLang(MAKELANGID(LANG_HUNGARIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("id"), GetLang(MAKELANGID(LANG_INDONESIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("it"), GetLang(MAKELANGID(LANG_ITALIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("iw"), GetLang(MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("ja"), GetLang(MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("ko"), GetLang(MAKELANGID(LANG_KOREAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("lt"), GetLang(MAKELANGID(LANG_LITHUANIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("lv"), GetLang(MAKELANGID(LANG_LATVIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("nl"), GetLang(MAKELANGID(LANG_DUTCH, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("no"), GetLang(MAKELANGID(LANG_NORWEGIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("pl"), GetLang(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("pt-BR"), GetLang(MAKELANGID(LANG_PORTUGUESE,
+                                               SUBLANG_PORTUGUESE_BRAZILIAN)));
+  EXPECT_STREQ(_T("pt-PT"), GetLang(MAKELANGID(LANG_PORTUGUESE,
+                                               SUBLANG_PORTUGUESE)));
+  EXPECT_STREQ(_T("ro"), GetLang(MAKELANGID(LANG_ROMANIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("ru"), GetLang(MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("sk"), GetLang(MAKELANGID(LANG_SLOVAK, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("sl"), GetLang(MAKELANGID(LANG_SLOVENIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("sr"), GetLang(
+      MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_CYRILLIC)));
+  EXPECT_STREQ(_T("sr"), GetLang(
+      MAKELANGID(LANG_SERBIAN, SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_LATIN)));
+  EXPECT_STREQ(_T("sr"), GetLang(MAKELANGID(LANG_SERBIAN,
+                                            SUBLANG_SERBIAN_CYRILLIC)));
+  EXPECT_STREQ(_T("sr"), GetLang(MAKELANGID(LANG_SERBIAN,
+                                            SUBLANG_SERBIAN_LATIN)));
+  EXPECT_STREQ(_T("sv"), GetLang(MAKELANGID(LANG_SWEDISH, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("th"), GetLang(MAKELANGID(LANG_THAI, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("tr"), GetLang(MAKELANGID(LANG_TURKISH, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("uk"), GetLang(MAKELANGID(LANG_UKRAINIAN, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("vi"), GetLang(MAKELANGID(LANG_VIETNAMESE, SUBLANG_DEFAULT)));
+  EXPECT_STREQ(_T("zh-HK"), GetLang(MAKELANGID(LANG_CHINESE,
+                                               SUBLANG_CHINESE_HONGKONG)));
+  EXPECT_STREQ(_T("zh-CN"), GetLang(MAKELANGID(LANG_CHINESE,
+                                               SUBLANG_CHINESE_MACAU)));
+  EXPECT_STREQ(_T("zh-CN"), GetLang(MAKELANGID(LANG_CHINESE,
+                                               SUBLANG_CHINESE_SIMPLIFIED)));
+  EXPECT_STREQ(_T("zh-CN"), GetLang(MAKELANGID(LANG_CHINESE,
+                                               SUBLANG_CHINESE_SINGAPORE)));
+  EXPECT_STREQ(_T("zh-TW"), GetLang(MAKELANGID(LANG_CHINESE,
+                                               SUBLANG_CHINESE_TRADITIONAL)));
+}
+
+// Unsupported languages and sublanguages fall back to "en".
+TEST_F(ResourceManagerTest, GetLanguageForLangID_UnsupportedSubLang) {
+  // LANG_NEUTRAL is unsupported.
+  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)));
+  // LANG_AFRIKAANS is unsupported.
+  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_AFRIKAANS, SUBLANG_NEUTRAL)));
+  // SUBLANG_NEUTRAL is unsupported.
+  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_SPANISH, SUBLANG_NEUTRAL)));
+  // SUBLANG_SYS_DEFAULT is unsupported. It happens to be 2, which is not
+  // supported for Hungarian but is for English, Spanish, and others/
+  EXPECT_STREQ(_T("en"),
+               GetLang(MAKELANGID(LANG_HUNGARIAN, SUBLANG_SYS_DEFAULT)));
+  EXPECT_STREQ(_T("es-419"),
+               GetLang(MAKELANGID(LANG_SPANISH, SUBLANG_SYS_DEFAULT)));
+  // 0x3f is an invalid sublang. There is a "es" file.
+  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_SPANISH, 0x3f)));
+  // 0x3f is an invalid sublang. There is not a "zh" file.
+  EXPECT_STREQ(_T("en"), GetLang(MAKELANGID(LANG_CHINESE, 0x3f)));
+}
+
+TEST_F(ResourceManagerTest, TestCountLanguagesInTranslationTable) {
+  std::map<CString, bool> languages;
+  GetDistinctLanguageMapFromTranslationTable(&languages);
+  // Number of language DLLs + zh-HK special case.
+  EXPECT_EQ(54 + 1, languages.size());
+}
+
+TEST_F(ResourceManagerTest, TestAppropriateLanguagesInTranslationTable) {
+  std::map<CString, bool> languages;
+  GetDistinctLanguageMapFromTranslationTable(&languages);
+
+  EXPECT_TRUE(languages.find(_T("ar")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("bg")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("bn")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("ca")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("cs")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("da")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("de")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("el")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("en-GB")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("en")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("es-419")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("es")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("et")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("fa")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("fi")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("fil")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("fr")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("gu")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("hi")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("hr")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("hu")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("id")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("is")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("it")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("iw")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("ja")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("kn")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("ko")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("lt")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("lv")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("ml")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("mr")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("ms")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("nl")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("no")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("or")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("pl")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("pt-BR")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("pt-PT")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("ro")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("ru")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("sk")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("sl")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("sr")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("sv")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("ta")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("te")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("th")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("tr")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("uk")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("ur")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("vi")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("zh-CN")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("zh-HK")) != languages.end());
+  EXPECT_TRUE(languages.find(_T("zh-TW")) != languages.end());
+}
+
+TEST_F(ResourceManagerTest, TestCountLanguageDlls) {
+  std::vector<CString> filenames;
+  ResourceManager::GetSupportedLanguageDllNames(&filenames);
+  EXPECT_EQ(54, filenames.size());
+}
+
+TEST_F(ResourceManagerTest, TestAppropriateLanguageDlls) {
+  std::vector<CString> filenames;
+  ResourceManager::GetSupportedLanguageDllNames(&filenames);
+
+  std::vector<CString>::iterator iter = filenames.begin();
+
+  EXPECT_STREQ(_T("goopdateres_ar.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_bg.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_bn.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_ca.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_cs.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_da.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_de.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_el.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_en.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_en-GB.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_es.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_es-419.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_et.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_fa.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_fi.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_fil.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_fr.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_gu.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_hi.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_hr.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_hu.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_id.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_is.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_it.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_iw.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_ja.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_kn.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_ko.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_lt.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_lv.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_ml.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_mr.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_ms.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_nl.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_no.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_or.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_pl.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_pt-BR.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_pt-PT.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_ro.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_ru.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_sk.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_sl.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_sr.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_sv.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_ta.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_te.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_th.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_tr.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_uk.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_ur.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_vi.dll"), *iter++);
+  EXPECT_STREQ(_T("goopdateres_zh-CN.dll"), *iter++);
+  // goopdateres_zh-HK.dll not present
+  EXPECT_STREQ(_T("goopdateres_zh-TW.dll"), *iter++);
+}
+
+TEST_F(ResourceManagerTest, RussianResourcesValid) {
+  SetResourceDir(app_util::GetModuleDirectory(NULL));
+
+  CString lang(_T("ru"));
+  EXPECT_HRESULT_SUCCEEDED(manager_->LoadResourceDll(lang));
+  EXPECT_TRUE(manager_->resource_dll());
+  EXPECT_STREQ(lang, manager_->language());
+
+  CString install_success(FormatResourceMessage(
+      IDS_APPLICATION_INSTALLED_SUCCESSFULLY, _T("Gears")));
+  EXPECT_STREQ("Благодарим вас за установку Gears.",
+               WideToUtf8(install_success));
+
+  CString install_fail(FormatResourceMessage(IDS_INSTALLER_FAILED_WITH_MESSAGE,
+                            _T("12345"), _T("Action failed.")));
+  EXPECT_STREQ("Ошибка установщика 12345: Action failed.",
+               WideToUtf8(install_fail));
+}
+
+}  // namespace omaha.
+
diff --git a/goopdate/resources/build.scons b/goopdate/resources/build.scons
index 9a0f45b..50dc31b 100644
--- a/goopdate/resources/build.scons
+++ b/goopdate/resources/build.scons
@@ -1,101 +1,101 @@
-#!/usr/bin/python2.4

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-

-local_env = env.Clone(

-    PRECOMPILE_STOPFILE = '',

-    PRECOMPILE_BUILDER  = '',

-    COMPONENT_STATIC = False,

-)

-

-# We disable runtime stack check to avoid increasing the code size.

-# There is a compiler pragma to programmatically disable the stack checks

-# but for some reason it did not work.

-local_env.FilterOut(CPPFLAGS = ['/GS'])

-

-# Disable stack checks for VC80. Stack checks are on by default.

-if local_env['msc_ver'] >= 1400:

-  local_env['CCFLAGS'] += ['/GS-']

-

-

-_first = True

-for v in env['product_version']:

-

-  if _first:

-    _first = False

-    prefix = ''

-  else:

-    prefix = 'TEST_'

-

-  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-  for lang in env['languages']:

-    lang_env = local_env.Clone()

-    lang_env.Append(

-        RCFLAGS = [

-            '/DVERSION_MAJOR=%d' % v[0],

-            '/DVERSION_MINOR=%d' % v[1],

-            '/DVERSION_BUILD=%d' % v[2],

-            '/DVERSION_PATCH=%d' % v[3],

-            '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,

-            '/DLANGUAGE_STRING=\\"%s\\"' % lang

-            ],

-        CPPPATH = [

-            '$OBJ_ROOT/goopdate',  # Needed for the tlb

-            ],

-        LINKFLAGS = [

-            '/NODEFAULTLIB',

-            '/ENTRY:DllEntry',

-            '/MERGE:.rdata=.text',

-            '/BASE:0x19000000',

-            ],

-    )

-

-    # Avoid conflicts in obj targets

-    lang_env['OBJSUFFIX'] = '_' + lang + lang_env['OBJSUFFIX']

-    lang_env['OBJPREFIX'] = '%s/%s' % (lang, prefix) + lang_env['OBJPREFIX']

-

-    lang_base_name = 'generated_resources_' + lang

-    lang_res = lang_env.RES(

-        target='%s%s.res' % (prefix, lang_base_name),

-        source='goopdateres/%s.rc' % (lang_base_name),

-    )

-

-    # Force a rebuild when the version changes.

-    lang_env.Depends(lang_res, '$MAIN_DIR/VERSION')

-

-    lang_inputs = [

-        'resdll_main.cc',

-        lang_res,

-        # Needed to prevent rebuilding of the lib.

-        '$MAIN_DIR/installers/resource_only_dll.def'

-        ]

-

-    # Build the (unsigned) DLL

-    unsigned_dll = lang_env.ComponentLibrary(

-        lib_name='%s/%sgoopdateres_unsigned_%s.dll' % (lang, prefix, lang),

-        source=lang_inputs

-    )

-

-    signed_dll = lang_env.SignedBinary(

-        target='%s/%sgoopdateres_%s.dll' % (lang, prefix, lang),

-        source=unsigned_dll,

-    )

-

-    env.Replicate('$STAGING_DIR', signed_dll)

-

+#!/usr/bin/python2.4
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+
+local_env = env.Clone(
+    PRECOMPILE_STOPFILE = '',
+    PRECOMPILE_BUILDER  = '',
+    COMPONENT_STATIC = False,
+)
+
+# We disable runtime stack check to avoid increasing the code size.
+# There is a compiler pragma to programmatically disable the stack checks
+# but for some reason it did not work.
+local_env.FilterOut(CPPFLAGS = ['/GS'])
+
+# Disable stack checks for VC80. Stack checks are on by default.
+if local_env['msc_ver'] >= 1400:
+  local_env['CCFLAGS'] += ['/GS-']
+
+
+_first = True
+for v in env['product_version']:
+
+  if _first:
+    _first = False
+    prefix = ''
+  else:
+    prefix = 'TEST_'
+
+  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+  for lang in env['languages']:
+    lang_env = local_env.Clone()
+    lang_env.Append(
+        RCFLAGS = [
+            '/DVERSION_MAJOR=%d' % v[0],
+            '/DVERSION_MINOR=%d' % v[1],
+            '/DVERSION_BUILD=%d' % v[2],
+            '/DVERSION_PATCH=%d' % v[3],
+            '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,
+            '/DLANGUAGE_STRING=\\"%s\\"' % lang
+            ],
+        CPPPATH = [
+            '$OBJ_ROOT/goopdate',  # Needed for the tlb
+            ],
+        LINKFLAGS = [
+            '/NODEFAULTLIB',
+            '/ENTRY:DllEntry',
+            '/MERGE:.rdata=.text',
+            '/BASE:0x19000000',
+            ],
+    )
+
+    # Avoid conflicts in obj targets
+    lang_env['OBJSUFFIX'] = '_' + lang + lang_env['OBJSUFFIX']
+    lang_env['OBJPREFIX'] = '%s/%s' % (lang, prefix) + lang_env['OBJPREFIX']
+
+    lang_base_name = 'generated_resources_' + lang
+    lang_res = lang_env.RES(
+        target='%s%s.res' % (prefix, lang_base_name),
+        source='goopdateres/%s.rc' % (lang_base_name),
+    )
+
+    # Force a rebuild when the version changes.
+    lang_env.Depends(lang_res, '$MAIN_DIR/VERSION')
+
+    lang_inputs = [
+        'resdll_main.cc',
+        lang_res,
+        # Needed to prevent rebuilding of the lib.
+        '$MAIN_DIR/installers/resource_only_dll.def'
+        ]
+
+    # Build the (unsigned) DLL
+    unsigned_dll = lang_env.ComponentLibrary(
+        lib_name='%s/%sgoopdateres_unsigned_%s.dll' % (lang, prefix, lang),
+        source=lang_inputs
+    )
+
+    signed_dll = lang_env.SignedBinary(
+        target='%s/%sgoopdateres_%s.dll' % (lang, prefix, lang),
+        source=unsigned_dll,
+    )
+
+    env.Replicate('$STAGING_DIR', signed_dll)
+
diff --git a/goopdate/resources/goopdate_dll/goopdate_dll.grh b/goopdate/resources/goopdate_dll/goopdate_dll.grh
index 2ccd036..cf486f8 100644
--- a/goopdate/resources/goopdate_dll/goopdate_dll.grh
+++ b/goopdate/resources/goopdate_dll/goopdate_dll.grh
@@ -1,24 +1,24 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// This file is automatically generated by GRIT.  Do not edit.

-// Built on Mon Apr 06 16:08:49 2009

-

-#ifndef RESOURCE_459901594825__

-#define RESOURCE_459901594825__

-

-

-#define IDS_ELEVATION_MONIKER_DISPLAYNAME 3000

-

-#endif // RESOURCE_459901594825__

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// This file is automatically generated by GRIT.  Do not edit.
+// Built on Mon Apr 06 16:08:49 2009
+
+#ifndef RESOURCE_459901594825__
+#define RESOURCE_459901594825__
+
+
+#define IDS_ELEVATION_MONIKER_DISPLAYNAME 3000
+
+#endif // RESOURCE_459901594825__
diff --git a/goopdate/resources/goopdateres/goopdate.grh b/goopdate/resources/goopdateres/goopdate.grh
index 19f4080..984daf2 100644
--- a/goopdate/resources/goopdateres/goopdate.grh
+++ b/goopdate/resources/goopdateres/goopdate.grh
@@ -1,99 +1,99 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// This file is automatically generated by GRIT.  Do not edit.

-// Built on Mon Apr 06 16:27:45 2009

-

-#ifndef RESOURCE_350927934028__

-#define RESOURCE_350927934028__

-

-

-#define IDS_SERVICE_NAME 3000

-#define IDS_GENERIC_INSTALLER_DISPLAY_NAME 3001

-#define IDS_SERVICE_DISPLAY_NAME 3002

-#define IDS_DOWNLOADING 3003

-#define IDS_INSTALLING 3004

-#define IDS_WAITING_TO_CONNECT 3005

-#define IDS_WAITING_TO_DOWNLOAD 3006

-#define IDS_WAITING_TO_INSTALL 3007

-#define IDS_TEXT_RESTART_BROWSER 3008

-#define IDS_TEXT_RESTART_ALL_BROWSERS 3009

-#define IDS_CLOSE 3010

-#define IDS_RESTART_BROWSER_NOW 3011

-#define IDS_RESTART_BROWSER_LATER 3012

-#define IDS_RESTART_ALL_BROWSERS_NOW 3013

-#define IDS_RESTART_ALL_BROWSERS_LATER 3014

-#define IDS_WINDOW_TITLE 3015

-#define IDS_INSTALLATION_STOPPED_WINDOW_TITLE 3016

-#define IDS_INSTALL_STOPPED 3017

-#define IDS_UNKNOWN_APPLICATION 3018

-#define IDS_DOWNLOAD_HASH_MISMATCH 3019

-#define IDS_DOWNLOAD_ERROR 3020

-#define IDS_APPLICATION_INSTALLED_SUCCESSFULLY 3021

-#define IDS_INSTALL_FAILED 3022

-#define IDS_RESTRICTED_RESPONSE_FROM_SERVER 3023

-#define IDS_NON_OK_RESPONSE_FROM_SERVER 3024

-#define IDS_NEED_ADMIN_TO_INSTALL 3025

-#define IDS_NO_UPDATE_RESPONSE 3026

-#define IDS_APPLICATION_ALREADY_INSTALLING 3027

-#define IDS_INVALID_INSTALLER_FILENAME 3028

-#define IDS_INSTALLER_FAILED_TO_START 3029

-#define IDS_INSTALLER_TIMED_OUT 3030

-#define IDS_INSTALLER_FAILED_WITH_MESSAGE 3031

-#define IDS_INSTALLER_FAILED_NO_MESSAGE 3032

-#define IDS_MSI_INSTALL_ALREADY_RUNNING 3033

-#define IDS_RESUME_INSTALLATION 3034

-#define IDS_CANCEL_INSTALLATION 3035

-#define IDS_INITIALIZING 3036

-#define IDS_SETUP_FAILED 3037

-#define IDS_ELEVATION_FAILED 3038

-#define IDS_APPLICATION_INSTALLING_GOOGLE_UPDATE 3039

-#define IDS_INSTANCES_RUNNING_AFTER_SHUTDOWN 3040

-#define IDS_HELP_ME_FIX_THIS_TEXT 3041

-#define IDS_BUNDLE_INSTALL_FAILED 3042

-#define IDS_OS_NOT_SUPPORTED 3043

-#define IDS_WINDOWS_IS_NOT_UP_TO_DATE 3044

-#define IDS_HANDOFF_FAILED 3045

-#define IDS_TEXT_REBOOT 3046

-#define IDS_RESTART_NOW 3047

-#define IDS_RESTART_LATER 3048

-#define IDS_DOWNLOAD_PAUSED 3049

-#define IDS_PAUSE 3050

-#define IDS_RESUME 3051

-#define IDS_SERVICE_DESCRIPTION 3052

-#define IDS_SCHEDULED_TASK_DESCRIPTION 3053

-#define IDS_NO_NETWORK_PRESENT_ERROR 3054

-#define IDS_ERROR_HTTPSTATUS_UNAUTHORIZED 3055

-#define IDS_ERROR_HTTPSTATUS_FORBIDDEN 3056

-#define IDS_ERROR_HTTPSTATUS_PROXY_AUTH_REQUIRED 3057

-#define IDS_APP_INSTALL_DISABLED_BY_GROUP_POLICY 3058

-#define IDS_INSTALLER_OLD 3059

-#define IDS_PROXY_PROMPT_MESSAGE 3060

-#define IDI_SUCCEESS 1000

-#define IDD_PROGRESS 2000

-#define IDC_CLOSE 2001

-#define IDC_BUTTON1 2002

-#define IDC_BUTTON2 2003

-#define IDC_PROGRESS 2004

-#define IDC_INSTALLER_STATE_TEXT 2005

-#define IDC_INFO_TEXT 2006

-#define IDC_PAUSE_RESUME_TEXT 2007

-#define IDC_COMPLETE_TEXT 2008

-#define IDC_ERROR_TEXT 2009

-#define IDC_GET_HELP_TEXT 2010

-#define IDC_IMAGE 2011

-#define IDD_INSTALL_STOPPED 2012

-#define IDC_INSTALL_STOPPED_TEXT 2013

-

-#endif // RESOURCE_350927934028__

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// This file is automatically generated by GRIT.  Do not edit.
+// Built on Mon Apr 06 16:27:45 2009
+
+#ifndef RESOURCE_350927934028__
+#define RESOURCE_350927934028__
+
+
+#define IDS_SERVICE_NAME 3000
+#define IDS_GENERIC_INSTALLER_DISPLAY_NAME 3001
+#define IDS_SERVICE_DISPLAY_NAME 3002
+#define IDS_DOWNLOADING 3003
+#define IDS_INSTALLING 3004
+#define IDS_WAITING_TO_CONNECT 3005
+#define IDS_WAITING_TO_DOWNLOAD 3006
+#define IDS_WAITING_TO_INSTALL 3007
+#define IDS_TEXT_RESTART_BROWSER 3008
+#define IDS_TEXT_RESTART_ALL_BROWSERS 3009
+#define IDS_CLOSE 3010
+#define IDS_RESTART_BROWSER_NOW 3011
+#define IDS_RESTART_BROWSER_LATER 3012
+#define IDS_RESTART_ALL_BROWSERS_NOW 3013
+#define IDS_RESTART_ALL_BROWSERS_LATER 3014
+#define IDS_WINDOW_TITLE 3015
+#define IDS_INSTALLATION_STOPPED_WINDOW_TITLE 3016
+#define IDS_INSTALL_STOPPED 3017
+#define IDS_UNKNOWN_APPLICATION 3018
+#define IDS_DOWNLOAD_HASH_MISMATCH 3019
+#define IDS_DOWNLOAD_ERROR 3020
+#define IDS_APPLICATION_INSTALLED_SUCCESSFULLY 3021
+#define IDS_INSTALL_FAILED 3022
+#define IDS_RESTRICTED_RESPONSE_FROM_SERVER 3023
+#define IDS_NON_OK_RESPONSE_FROM_SERVER 3024
+#define IDS_NEED_ADMIN_TO_INSTALL 3025
+#define IDS_NO_UPDATE_RESPONSE 3026
+#define IDS_APPLICATION_ALREADY_INSTALLING 3027
+#define IDS_INVALID_INSTALLER_FILENAME 3028
+#define IDS_INSTALLER_FAILED_TO_START 3029
+#define IDS_INSTALLER_TIMED_OUT 3030
+#define IDS_INSTALLER_FAILED_WITH_MESSAGE 3031
+#define IDS_INSTALLER_FAILED_NO_MESSAGE 3032
+#define IDS_MSI_INSTALL_ALREADY_RUNNING 3033
+#define IDS_RESUME_INSTALLATION 3034
+#define IDS_CANCEL_INSTALLATION 3035
+#define IDS_INITIALIZING 3036
+#define IDS_SETUP_FAILED 3037
+#define IDS_ELEVATION_FAILED 3038
+#define IDS_APPLICATION_INSTALLING_GOOGLE_UPDATE 3039
+#define IDS_INSTANCES_RUNNING_AFTER_SHUTDOWN 3040
+#define IDS_HELP_ME_FIX_THIS_TEXT 3041
+#define IDS_BUNDLE_INSTALL_FAILED 3042
+#define IDS_OS_NOT_SUPPORTED 3043
+#define IDS_WINDOWS_IS_NOT_UP_TO_DATE 3044
+#define IDS_HANDOFF_FAILED 3045
+#define IDS_TEXT_REBOOT 3046
+#define IDS_RESTART_NOW 3047
+#define IDS_RESTART_LATER 3048
+#define IDS_DOWNLOAD_PAUSED 3049
+#define IDS_PAUSE 3050
+#define IDS_RESUME 3051
+#define IDS_SERVICE_DESCRIPTION 3052
+#define IDS_SCHEDULED_TASK_DESCRIPTION 3053
+#define IDS_NO_NETWORK_PRESENT_ERROR 3054
+#define IDS_ERROR_HTTPSTATUS_UNAUTHORIZED 3055
+#define IDS_ERROR_HTTPSTATUS_FORBIDDEN 3056
+#define IDS_ERROR_HTTPSTATUS_PROXY_AUTH_REQUIRED 3057
+#define IDS_APP_INSTALL_DISABLED_BY_GROUP_POLICY 3058
+#define IDS_INSTALLER_OLD 3059
+#define IDS_PROXY_PROMPT_MESSAGE 3060
+#define IDI_SUCCEESS 1000
+#define IDD_PROGRESS 2000
+#define IDC_CLOSE 2001
+#define IDC_BUTTON1 2002
+#define IDC_BUTTON2 2003
+#define IDC_PROGRESS 2004
+#define IDC_INSTALLER_STATE_TEXT 2005
+#define IDC_INFO_TEXT 2006
+#define IDC_PAUSE_RESUME_TEXT 2007
+#define IDC_COMPLETE_TEXT 2008
+#define IDC_ERROR_TEXT 2009
+#define IDC_GET_HELP_TEXT 2010
+#define IDC_IMAGE 2011
+#define IDD_INSTALL_STOPPED 2012
+#define IDC_INSTALL_STOPPED_TEXT 2013
+
+#endif // RESOURCE_350927934028__
diff --git a/goopdate/resources/resdll_main.cc b/goopdate/resources/resdll_main.cc
index 80d223d..a1acecb 100644
--- a/goopdate/resources/resdll_main.cc
+++ b/goopdate/resources/resdll_main.cc
@@ -1,26 +1,26 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-

-// Disable the runtime checks.

-#pragma runtime_checks("", off)

-

-BOOL WINAPI DllEntry(HINSTANCE module, DWORD reason_for_call, void*) {

-  if (reason_for_call == DLL_PROCESS_ATTACH) {

-    ::DisableThreadLibraryCalls(module);

-  }

-  return TRUE;

-}

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+
+// Disable the runtime checks.
+#pragma runtime_checks("", off)
+
+BOOL WINAPI DllEntry(HINSTANCE module, DWORD reason_for_call, void*) {
+  if (reason_for_call == DLL_PROCESS_ATTACH) {
+    ::DisableThreadLibraryCalls(module);
+  }
+  return TRUE;
+}
diff --git a/goopdate/resources/shared_resources.rc b/goopdate/resources/shared_resources.rc
index 607f065..c6a0b17 100644
--- a/goopdate/resources/shared_resources.rc
+++ b/goopdate/resources/shared_resources.rc
@@ -1,94 +1,94 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// This file contains the dialog templates for goopdate resources.

-// The file is used by GRIT to create the language specific resources, hence

-// we do not need to include any header files in here. GRIT automatically

-// generates the resource header.

-

-#include "afxres.h"

-#include "goopdateres/goopdate.grh"

-

-#ifndef APSTUDIO_INVOKED

-

-VS_VERSION_INFO VERSIONINFO

- FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- FILEFLAGSMASK 0x17L

-#ifdef _DEBUG

- FILEFLAGS 0x1L

-#else

- FILEFLAGS 0x0L

-#endif

- FILEOS 0x4L

- FILETYPE 0x0L

- FILESUBTYPE 0x0L

-BEGIN

-    BLOCK "StringFileInfo"

-    BEGIN

-        BLOCK "[GRITVERLANGCHARSETHEX]"

-        BEGIN

-            VALUE "CompanyName", "Google Inc."

-            VALUE "FileDescription", "Google Update Resource DLL"

-            VALUE "FileVersion", VERSION_NUMBER_STRING

-            VALUE "InternalName", "Google Update Resource DLL"

-            VALUE "LegalCopyright", "Copyright 2007-2009 Google Inc."

-            VALUE "OriginalFilename", "Goopdateres.dll"

-            VALUE "ProductName", "Google Update"

-            VALUE "ProductVersion", VERSION_NUMBER_STRING

-            VALUE "LanguageId", LANGUAGE_STRING

-#ifdef _DEBUG

-            VALUE "Debug", ""

-#endif

-#if !OFFICIAL_BUILD

-            VALUE "Privatebuild", ""

-#endif

-        END

-    END

-    BLOCK "VarFileInfo"

-    BEGIN

-        VALUE "Translation", [GRITVERLANGID], [GRITVERCHARSETID]

-    END

-END

-

-#endif  // APSTUDIO_INVOKED

-

-

-IDD_PROGRESS DIALOGEX 0, 0, 325, 80

-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_MINIMIZEBOX |

-    WS_POPUP | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU

-FONT 8, "MS Shell Dlg 2", 0, 0, 0x0

-BEGIN

-    PUSHBUTTON  "",IDC_CLOSE,248,57,70,16,NOT WS_VISIBLE

-    PUSHBUTTON  "",IDC_BUTTON1,7,57,152,16,NOT WS_VISIBLE

-    PUSHBUTTON  "",IDC_BUTTON2,166,57,152,16,NOT WS_VISIBLE

-    CONTROL     "",IDC_PROGRESS,"msctls_progress32",NOT WS_VISIBLE,7,36,311,10

-    LTEXT       "",IDC_INSTALLER_STATE_TEXT,7,7,197,16,NOT WS_VISIBLE

-    LTEXT       "",IDC_INFO_TEXT,7,54,311,8,NOT WS_VISIBLE

-    LTEXT       "",IDC_PAUSE_RESUME_TEXT,234,25,33,8,SS_NOTIFY | NOT WS_VISIBLE

-    LTEXT       "",IDC_COMPLETE_TEXT,39,7,279,43,SS_NOTIFY | NOT WS_VISIBLE

-    LTEXT       "",IDC_ERROR_TEXT,7,7,311,42,SS_NOTIFY | NOT WS_VISIBLE

-    LTEXT       "",IDC_GET_HELP_TEXT,7,60,220,16,SS_NOTIFY | NOT WS_VISIBLE

-    ICON           IDI_SUCCEESS,IDC_IMAGE,7,7,17,17

-END

-

-IDD_INSTALL_STOPPED DIALOGEX 0, 0, 260, 70

-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION

-FONT 8, "MS Shell Dlg 2", 400, 0, 0x1

-BEGIN

-    DEFPUSHBUTTON   "",IDOK,133,49,120,14

-    PUSHBUTTON      "",IDCANCEL,7,49,120,14

-    LTEXT           "",IDC_INSTALL_STOPPED_TEXT,7,7,246,34

-END

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// This file contains the dialog templates for goopdate resources.
+// The file is used by GRIT to create the language specific resources, hence
+// we do not need to include any header files in here. GRIT automatically
+// generates the resource header.
+
+#include "afxres.h"
+#include "goopdateres/goopdate.grh"
+
+#ifndef APSTUDIO_INVOKED
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "[GRITVERLANGCHARSETHEX]"
+        BEGIN
+            VALUE "CompanyName", "Google Inc."
+            VALUE "FileDescription", "Google Update Resource DLL"
+            VALUE "FileVersion", VERSION_NUMBER_STRING
+            VALUE "InternalName", "Google Update Resource DLL"
+            VALUE "LegalCopyright", "Copyright 2007-2009 Google Inc."
+            VALUE "OriginalFilename", "Goopdateres.dll"
+            VALUE "ProductName", "Google Update"
+            VALUE "ProductVersion", VERSION_NUMBER_STRING
+            VALUE "LanguageId", LANGUAGE_STRING
+#ifdef _DEBUG
+            VALUE "Debug", ""
+#endif
+#if !OFFICIAL_BUILD
+            VALUE "Privatebuild", ""
+#endif
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", [GRITVERLANGID], [GRITVERCHARSETID]
+    END
+END
+
+#endif  // APSTUDIO_INVOKED
+
+
+IDD_PROGRESS DIALOGEX 0, 0, 325, 80
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_MINIMIZEBOX |
+    WS_POPUP | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg 2", 0, 0, 0x0
+BEGIN
+    PUSHBUTTON  "",IDC_CLOSE,248,57,70,16,NOT WS_VISIBLE
+    PUSHBUTTON  "",IDC_BUTTON1,7,57,152,16,NOT WS_VISIBLE
+    PUSHBUTTON  "",IDC_BUTTON2,166,57,152,16,NOT WS_VISIBLE
+    CONTROL     "",IDC_PROGRESS,"msctls_progress32",NOT WS_VISIBLE,7,36,311,10
+    LTEXT       "",IDC_INSTALLER_STATE_TEXT,7,7,197,16,NOT WS_VISIBLE
+    LTEXT       "",IDC_INFO_TEXT,7,54,311,8,NOT WS_VISIBLE
+    LTEXT       "",IDC_PAUSE_RESUME_TEXT,234,25,33,8,SS_NOTIFY | NOT WS_VISIBLE
+    LTEXT       "",IDC_COMPLETE_TEXT,39,7,279,43,SS_NOTIFY | NOT WS_VISIBLE
+    LTEXT       "",IDC_ERROR_TEXT,7,7,311,42,SS_NOTIFY | NOT WS_VISIBLE
+    LTEXT       "",IDC_GET_HELP_TEXT,7,60,220,16,SS_NOTIFY | NOT WS_VISIBLE
+    ICON           IDI_SUCCEESS,IDC_IMAGE,7,7,17,17
+END
+
+IDD_INSTALL_STOPPED DIALOGEX 0, 0, 260, 70
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
+FONT 8, "MS Shell Dlg 2", 400, 0, 0x1
+BEGIN
+    DEFPUSHBUTTON   "",IDOK,133,49,120,14
+    PUSHBUTTON      "",IDCANCEL,7,49,120,14
+    LTEXT           "",IDC_INSTALL_STOPPED_TEXT,7,7,246,34
+END
diff --git a/goopdate/resources/shared_resources_bidi.rc b/goopdate/resources/shared_resources_bidi.rc
index 4f950c3..df1c488 100644
--- a/goopdate/resources/shared_resources_bidi.rc
+++ b/goopdate/resources/shared_resources_bidi.rc
@@ -1,95 +1,95 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// This file contains the dialog templates for BIDI languages.

-// The file is used by GRIT to create the language specific resources, hence

-// we do not need to include any header files in here. GRIT automatically

-// generates the resource header.

-

-#include "afxres.h"

-#include "goopdateres/goopdate.grh"

-

-#ifndef APSTUDIO_INVOKED

-

-VS_VERSION_INFO VERSIONINFO

- FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- FILEFLAGSMASK 0x17L

-#ifdef _DEBUG

- FILEFLAGS 0x1L

-#else

- FILEFLAGS 0x0L

-#endif

- FILEOS 0x4L

- FILETYPE 0x0L

- FILESUBTYPE 0x0L

-BEGIN

-    BLOCK "StringFileInfo"

-    BEGIN

-        BLOCK "[GRITVERLANGCHARSETHEX]"

-        BEGIN

-            VALUE "CompanyName", "Google Inc."

-            VALUE "FileDescription", "Google Update Resource DLL"

-            VALUE "FileVersion", VERSION_NUMBER_STRING

-            VALUE "InternalName", "Google Update Resource DLL"

-            VALUE "LegalCopyright", "Copyright 2007-2009 Google Inc."

-            VALUE "OriginalFilename", "Goopdateres.dll"

-            VALUE "ProductName", "Google Update"

-            VALUE "ProductVersion", VERSION_NUMBER_STRING

-            VALUE "LanguageId", LANGUAGE_STRING

-#ifdef _DEBUG

-            VALUE "Debug", ""

-#endif

-#if !OFFICIAL_BUILD

-            VALUE "Privatebuild", ""

-#endif

-        END

-    END

-    BLOCK "VarFileInfo"

-    BEGIN

-        VALUE "Translation", [GRITVERLANGID], [GRITVERCHARSETID]

-    END

-END

-

-#endif  // APSTUDIO_INVOKED

-

-IDD_PROGRESS DIALOGEX 0, 0, 325, 80

-STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_MINIMIZEBOX |

-    WS_POPUP | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU

-FONT 8, "MS Shell Dlg 2", 0, 0, 0x0

-EXSTYLE WS_EX_LAYOUTRTL

-BEGIN

-    PUSHBUTTON  "",IDC_CLOSE,248,57,70,16,NOT WS_VISIBLE

-    PUSHBUTTON  "",IDC_BUTTON1,7,57,152,16,NOT WS_VISIBLE

-    PUSHBUTTON  "",IDC_BUTTON2,166,57,152,16,NOT WS_VISIBLE

-    CONTROL     "",IDC_PROGRESS,"msctls_progress32",NOT WS_VISIBLE,7,36,311,10

-    LTEXT       "",IDC_INSTALLER_STATE_TEXT,7,7,197,16,NOT WS_VISIBLE

-    LTEXT       "",IDC_INFO_TEXT,7,54,311,8,NOT WS_VISIBLE

-    LTEXT       "",IDC_PAUSE_RESUME_TEXT,234,25,33,8,SS_NOTIFY | NOT WS_VISIBLE

-    LTEXT       "",IDC_COMPLETE_TEXT,39,7,279,43,SS_NOTIFY | NOT WS_VISIBLE

-    LTEXT       "",IDC_ERROR_TEXT,7,7,311,42,SS_NOTIFY | NOT WS_VISIBLE

-    LTEXT       "",IDC_GET_HELP_TEXT,7,60,220,16,SS_NOTIFY | NOT WS_VISIBLE

-    ICON           IDI_SUCCEESS,IDC_IMAGE,7,7,17,17

-END

-

-IDD_INSTALL_STOPPED DIALOGEX 0, 0, 260, 70

-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION

-FONT 8, "MS Shell Dlg 2", 400, 0, 0x1

-EXSTYLE WS_EX_LAYOUTRTL

-BEGIN

-    DEFPUSHBUTTON   "",IDOK,133,49,120,14

-    PUSHBUTTON      "",IDCANCEL,7,49,120,14

-    LTEXT           "",IDC_INSTALL_STOPPED_TEXT,7,7,246,34

-END

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// This file contains the dialog templates for BIDI languages.
+// The file is used by GRIT to create the language specific resources, hence
+// we do not need to include any header files in here. GRIT automatically
+// generates the resource header.
+
+#include "afxres.h"
+#include "goopdateres/goopdate.grh"
+
+#ifndef APSTUDIO_INVOKED
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "[GRITVERLANGCHARSETHEX]"
+        BEGIN
+            VALUE "CompanyName", "Google Inc."
+            VALUE "FileDescription", "Google Update Resource DLL"
+            VALUE "FileVersion", VERSION_NUMBER_STRING
+            VALUE "InternalName", "Google Update Resource DLL"
+            VALUE "LegalCopyright", "Copyright 2007-2009 Google Inc."
+            VALUE "OriginalFilename", "Goopdateres.dll"
+            VALUE "ProductName", "Google Update"
+            VALUE "ProductVersion", VERSION_NUMBER_STRING
+            VALUE "LanguageId", LANGUAGE_STRING
+#ifdef _DEBUG
+            VALUE "Debug", ""
+#endif
+#if !OFFICIAL_BUILD
+            VALUE "Privatebuild", ""
+#endif
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", [GRITVERLANGID], [GRITVERCHARSETID]
+    END
+END
+
+#endif  // APSTUDIO_INVOKED
+
+IDD_PROGRESS DIALOGEX 0, 0, 325, 80
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_MINIMIZEBOX |
+    WS_POPUP | WS_CLIPSIBLINGS | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg 2", 0, 0, 0x0
+EXSTYLE WS_EX_LAYOUTRTL
+BEGIN
+    PUSHBUTTON  "",IDC_CLOSE,248,57,70,16,NOT WS_VISIBLE
+    PUSHBUTTON  "",IDC_BUTTON1,7,57,152,16,NOT WS_VISIBLE
+    PUSHBUTTON  "",IDC_BUTTON2,166,57,152,16,NOT WS_VISIBLE
+    CONTROL     "",IDC_PROGRESS,"msctls_progress32",NOT WS_VISIBLE,7,36,311,10
+    LTEXT       "",IDC_INSTALLER_STATE_TEXT,7,7,197,16,NOT WS_VISIBLE
+    LTEXT       "",IDC_INFO_TEXT,7,54,311,8,NOT WS_VISIBLE
+    LTEXT       "",IDC_PAUSE_RESUME_TEXT,234,25,33,8,SS_NOTIFY | NOT WS_VISIBLE
+    LTEXT       "",IDC_COMPLETE_TEXT,39,7,279,43,SS_NOTIFY | NOT WS_VISIBLE
+    LTEXT       "",IDC_ERROR_TEXT,7,7,311,42,SS_NOTIFY | NOT WS_VISIBLE
+    LTEXT       "",IDC_GET_HELP_TEXT,7,60,220,16,SS_NOTIFY | NOT WS_VISIBLE
+    ICON           IDI_SUCCEESS,IDC_IMAGE,7,7,17,17
+END
+
+IDD_INSTALL_STOPPED DIALOGEX 0, 0, 260, 70
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
+FONT 8, "MS Shell Dlg 2", 400, 0, 0x1
+EXSTYLE WS_EX_LAYOUTRTL
+BEGIN
+    DEFPUSHBUTTON   "",IDOK,133,49,120,14
+    PUSHBUTTON      "",IDCANCEL,7,49,120,14
+    LTEXT           "",IDC_INSTALL_STOPPED_TEXT,7,7,246,34
+END
diff --git a/goopdate/response.xsd b/goopdate/response.xsd
index fdc5766..8b9b07a 100644
--- a/goopdate/response.xsd
+++ b/goopdate/response.xsd
@@ -1,51 +1,51 @@
-<?xml version="1.0" encoding="utf-8"?>

-<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" 

-           targetNamespace="http://www.google.com/omaha/response" 

-            xmlns:xs="http://www.w3.org/2001/XMLSchema"

-            xmlns:ts="http://www.google.com/omaha/response">

-  <xs:simpleType name="ResponseType">

-    <xs:restriction base="xs:string">

-      <xs:enumeration value="ok" />

-      <xs:enumeration value="noupdate" />

-      <xs:enumeration value="unknownapplication" />

-    </xs:restriction>

-  </xs:simpleType>

-  <xs:simpleType name="NeedsAdminType">

-    <xs:restriction base="xs:string">

-      <xs:enumeration value="true" />

-      <xs:enumeration value="false" />

-      <xs:enumeration value="prefers" />

-    </xs:restriction>

-  </xs:simpleType>

-  <xs:simpleType name="GuidType">

-    <xs:restriction base="xs:string">

-      <xs:pattern value="{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}}" />

-    </xs:restriction>

-  </xs:simpleType>

-  <xs:element name="responses">

-    <xs:complexType>

-      <xs:choice>

-        <xs:element minOccurs="0" maxOccurs="unbounded" name="response">

-          <xs:complexType>

-            <xs:sequence minOccurs="0">

-              <xs:element name="codebase" type="xs:string" />

-              <xs:element name="needsadmin" type="ts:NeedsAdminType" />

-              <xs:element name="hash" type="xs:string" />

-              <xs:element name="rlz" type="xs:string" />

-            </xs:sequence>

-            <xs:attribute name="status" type="ts:ResponseType" use="required" />

-            <xs:attribute name="appid" type="ts:GuidType" use="required" />

-          </xs:complexType>

-        </xs:element>

-        <xs:element minOccurs="0" maxOccurs="unbounded" name="install">

-          <xs:complexType>

-            <xs:attribute name="needsadmin" type="ts:NeedsAdminType" />

-            <xs:attribute name="appguid" type="ts:GuidType" />

-          </xs:complexType>

-        </xs:element>

-      </xs:choice>

-      <xs:attribute name="ver" type="xs:decimal" use="required" />

-      <xs:attribute name="signature" type="xs:string" use="required" />

-    </xs:complexType>

-  </xs:element>

+<?xml version="1.0" encoding="utf-8"?>
+<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" 
+           targetNamespace="http://www.google.com/omaha/response" 
+            xmlns:xs="http://www.w3.org/2001/XMLSchema"
+            xmlns:ts="http://www.google.com/omaha/response">
+  <xs:simpleType name="ResponseType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="ok" />
+      <xs:enumeration value="noupdate" />
+      <xs:enumeration value="unknownapplication" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="NeedsAdminType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="true" />
+      <xs:enumeration value="false" />
+      <xs:enumeration value="prefers" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="GuidType">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}}" />
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:element name="responses">
+    <xs:complexType>
+      <xs:choice>
+        <xs:element minOccurs="0" maxOccurs="unbounded" name="response">
+          <xs:complexType>
+            <xs:sequence minOccurs="0">
+              <xs:element name="codebase" type="xs:string" />
+              <xs:element name="needsadmin" type="ts:NeedsAdminType" />
+              <xs:element name="hash" type="xs:string" />
+              <xs:element name="rlz" type="xs:string" />
+            </xs:sequence>
+            <xs:attribute name="status" type="ts:ResponseType" use="required" />
+            <xs:attribute name="appid" type="ts:GuidType" use="required" />
+          </xs:complexType>
+        </xs:element>
+        <xs:element minOccurs="0" maxOccurs="unbounded" name="install">
+          <xs:complexType>
+            <xs:attribute name="needsadmin" type="ts:NeedsAdminType" />
+            <xs:attribute name="appguid" type="ts:GuidType" />
+          </xs:complexType>
+        </xs:element>
+      </xs:choice>
+      <xs:attribute name="ver" type="xs:decimal" use="required" />
+      <xs:attribute name="signature" type="xs:string" use="required" />
+    </xs:complexType>
+  </xs:element>
 </xs:schema>
\ No newline at end of file
diff --git a/goopdate/stats_uploader.cc b/goopdate/stats_uploader.cc
index 1e91ca0..b175fef 100644
--- a/goopdate/stats_uploader.cc
+++ b/goopdate/stats_uploader.cc
@@ -1,266 +1,266 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/goopdate/stats_uploader.h"

-#include <atlbase.h>

-#include <atlconv.h>

-#include <atlstr.h>

-#include <ctime>

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/net/browser_request.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/simple_request.h"

-#include "omaha/statsreport/aggregator-win32.h"

-#include "omaha/statsreport/const-win32.h"

-#include "omaha/statsreport/formatter.h"

-#include "omaha/statsreport/metrics.h"

-#include "omaha/statsreport/persistent_iterator-win32.h"

-

-using stats_report::g_global_metrics;

-

-using stats_report::kCountsKeyName;

-using stats_report::kTimingsKeyName;

-using stats_report::kIntegersKeyName;

-using stats_report::kBooleansKeyName;

-using stats_report::kStatsKeyFormatString;

-using stats_report::kLastTransmissionTimeValueName;

-

-using stats_report::Formatter;

-using stats_report::MetricsAggregatorWin32;

-using stats_report::PersistentMetricsIteratorWin32;

-

-namespace omaha {

-

-namespace {

-

-HRESULT ResetPersistentMetrics(RegKey* key) {

-  ASSERT1(key);

-  HRESULT result = S_OK;

-  DWORD now_sec = static_cast<DWORD>(time(NULL));

-  HRESULT hr = key->SetValue(kLastTransmissionTimeValueName, now_sec);

-  if (FAILED(hr)) {

-    result = hr;

-  }

-  hr = key->DeleteSubKey(kCountsKeyName);

-  if (FAILED(hr)) {

-    result = hr;

-  }

-  hr = key->DeleteSubKey(kTimingsKeyName);

-  if (FAILED(hr)) {

-    result = hr;

-  }

-  hr = key->DeleteSubKey(kIntegersKeyName);

-  if (FAILED(hr)) {

-    result = hr;

-  }

-  hr = key->DeleteSubKey(kBooleansKeyName);

-  if (FAILED(hr)) {

-    result = hr;

-  }

-  return result;

-}

-

-// Returns S_OK without uploading in OEM mode.

-HRESULT UploadMetrics(bool is_machine,

-                      const TCHAR* extra_url_data,

-                      const TCHAR* content) {

-  ASSERT1(content);

-

-  // Do not access the network during an OEM install.

-  if (!ConfigManager::Instance()->CanUseNetwork(is_machine)) {

-    CORE_LOG(L1, (_T("[Stats not uploaded because network use prohibited]")));

-    return GOOPDATE_E_CANNOT_USE_NETWORK;

-  }

-

-  const TCHAR* version = GetVersionString();

-  CString machine_id(goopdate_utils::GetPersistentMachineId());

-  CString user_id(goopdate_utils::GetPersistentUserId(is_machine ?

-                                                      MACHINE_KEY_NAME :

-                                                      USER_KEY_NAME));

-  CString test_source(ConfigManager::Instance()->GetTestSource());

-

-  CString url(kUrlUsageStatsReport);

-  url.AppendFormat(_T("?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s"),

-      kMetricsServerParamSourceId,  kMetricsProductName,

-      kMetricsServerParamVersion,   version,

-      kMetricsServerParamIsMachine, is_machine ? _T("1") : _T("0"),

-      kMetricsServerTestSource,     test_source,

-      kMetricsServerMachineId,      machine_id,

-      kMetricsServerUserId,         user_id,

-      extra_url_data);

-

-  CORE_LOG(L3, (_T("[upload usage stats][%s]"), content));

-

-  const NetworkConfig::Session& session(NetworkConfig::Instance().session());

-  NetworkRequest network_request(session);

-  network_request.set_num_retries(1);

-  network_request.AddHttpRequest(new SimpleRequest);

-  network_request.AddHttpRequest(new BrowserRequest);

-

-  // PostRequest falls back to https.

-  CString response;

-  return PostRequest(&network_request, true, url, content, &response);

-}

-

-HRESULT ReportMetrics(bool is_machine,

-                      const TCHAR* extra_url_data,

-                      DWORD interval) {

-  PersistentMetricsIteratorWin32 it(kMetricsProductName, is_machine), end;

-  Formatter formatter(CT2A(kMetricsProductName), interval);

-

-  for (; it != end; ++it) {

-    formatter.AddMetric(*it);

-  }

-

-  return UploadMetrics(is_machine, extra_url_data, CA2T(formatter.output()));

-}

-

-HRESULT DoResetMetrics(bool is_machine) {

-  CString key_name;

-  key_name.Format(kStatsKeyFormatString, kMetricsProductName);

-  HKEY parent_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

-  RegKey key;

-  HRESULT hr = key.Create(parent_key, key_name);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[Unable to create metrics key][0x%08x]"), hr));

-    return hr;

-  }

-  return ResetPersistentMetrics(&key);

-}

-

-HRESULT DoAggregateMetrics(bool is_machine) {

-  MetricsAggregatorWin32 aggregator(g_global_metrics,

-                                    kMetricsProductName,

-                                    is_machine);

-  if (!aggregator.AggregateMetrics()) {

-    CORE_LOG(LW, (_T("[Metrics aggregation failed for unknown reasons]")));

-    return GOOPDATE_E_METRICS_AGGREGATE_FAILED;

-  }

-  return S_OK;

-}

-

-HRESULT DoAggregateAndReportMetrics(bool is_machine, bool force_report) {

-  CString key_name;

-  key_name.Format(kStatsKeyFormatString, kMetricsProductName);

-  HKEY parent_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

-  RegKey key;

-  HRESULT hr = key.Create(parent_key, key_name);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[Unable to create metrics key][0x%08x]"), hr));

-    return hr;

-  }

-

-  DWORD now = static_cast<DWORD>(time(NULL));

-

-  DWORD last_transmission_time(0);

-  hr = key.GetValue(kLastTransmissionTimeValueName, &last_transmission_time);

-

-  // Reset and start over if last transmission time is missing or hinky.

-  if (FAILED(hr) || last_transmission_time > now) {

-    CORE_LOG(LW, (_T("[hinky or missing last transmission time]")));

-    ResetPersistentMetrics(&key);

-    return S_OK;

-  }

-

-  hr = DoAggregateMetrics(is_machine);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[DoAggregateMetrics failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  DWORD time_since_last_transmission = now - last_transmission_time;

-  if (force_report ||

-      time_since_last_transmission >= kMetricsUploadIntervalSec) {

-    // Report the metrics, reset the metrics, and update 'LastTransmission'.

-    HRESULT hr = ReportMetrics(is_machine, NULL, time_since_last_transmission);

-    if (SUCCEEDED(hr)) {

-      VERIFY1(SUCCEEDED(ResetPersistentMetrics(&key)));

-      DWORD now_sec = static_cast<DWORD>(time(NULL));

-      CORE_LOG(L3, (_T("[Stats upload successful]")));

-      return S_OK;

-    } else {

-      CORE_LOG(LE, (_T("[Stats upload failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-bool InitializeLock(GLock* lock, bool is_machine) {

-  ASSERT1(lock);

-  NamedObjectAttributes attributes;

-  GetNamedObjectAttributes(kMetricsSerializer, is_machine, &attributes);

-  return lock->InitializeWithSecAttr(attributes.name, &attributes.sa);

-}

-

-}  // namespace

-

-

-HRESULT ResetMetrics(bool is_machine) {

-  CORE_LOG(L2, (_T("[ResetMetrics]")));

-  GLock lock;

-  if (!InitializeLock(&lock, is_machine)) {

-    return GOOPDATE_E_METRICS_LOCK_INIT_FAILED;

-  }

-  __mutexScope(lock);

-  return DoResetMetrics(is_machine);

-}

-

-HRESULT AggregateMetrics(bool is_machine) {

-  CORE_LOG(L2, (_T("[AggregateMetrics]")));

-

-  if (!ConfigManager::Instance()->CanCollectStats(is_machine)) {

-    return S_OK;

-  }

-

-  GLock lock;

-  if (!InitializeLock(&lock, is_machine)) {

-    return GOOPDATE_E_METRICS_LOCK_INIT_FAILED;

-  }

-  __mutexScope(lock);

-  return DoAggregateMetrics(is_machine);

-}

-

-HRESULT AggregateAndReportMetrics(bool is_machine, bool force_report) {

-  CORE_LOG(L2, (_T("[AggregateAndReportMetrics]")));

-

-  if (!ConfigManager::Instance()->CanCollectStats(is_machine)) {

-    return S_OK;

-  }

-

-  GLock lock;

-  if (!InitializeLock(&lock, is_machine)) {

-    return GOOPDATE_E_METRICS_LOCK_INIT_FAILED;

-  }

-  __mutexScope(lock);

-  return DoAggregateAndReportMetrics(is_machine, force_report);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/goopdate/stats_uploader.h"
+#include <atlbase.h>
+#include <atlconv.h>
+#include <atlstr.h>
+#include <ctime>
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/net/browser_request.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/simple_request.h"
+#include "omaha/statsreport/aggregator-win32.h"
+#include "omaha/statsreport/const-win32.h"
+#include "omaha/statsreport/formatter.h"
+#include "omaha/statsreport/metrics.h"
+#include "omaha/statsreport/persistent_iterator-win32.h"
+
+using stats_report::g_global_metrics;
+
+using stats_report::kCountsKeyName;
+using stats_report::kTimingsKeyName;
+using stats_report::kIntegersKeyName;
+using stats_report::kBooleansKeyName;
+using stats_report::kStatsKeyFormatString;
+using stats_report::kLastTransmissionTimeValueName;
+
+using stats_report::Formatter;
+using stats_report::MetricsAggregatorWin32;
+using stats_report::PersistentMetricsIteratorWin32;
+
+namespace omaha {
+
+namespace {
+
+HRESULT ResetPersistentMetrics(RegKey* key) {
+  ASSERT1(key);
+  HRESULT result = S_OK;
+  DWORD now_sec = static_cast<DWORD>(time(NULL));
+  HRESULT hr = key->SetValue(kLastTransmissionTimeValueName, now_sec);
+  if (FAILED(hr)) {
+    result = hr;
+  }
+  hr = key->DeleteSubKey(kCountsKeyName);
+  if (FAILED(hr)) {
+    result = hr;
+  }
+  hr = key->DeleteSubKey(kTimingsKeyName);
+  if (FAILED(hr)) {
+    result = hr;
+  }
+  hr = key->DeleteSubKey(kIntegersKeyName);
+  if (FAILED(hr)) {
+    result = hr;
+  }
+  hr = key->DeleteSubKey(kBooleansKeyName);
+  if (FAILED(hr)) {
+    result = hr;
+  }
+  return result;
+}
+
+// Returns S_OK without uploading in OEM mode.
+HRESULT UploadMetrics(bool is_machine,
+                      const TCHAR* extra_url_data,
+                      const TCHAR* content) {
+  ASSERT1(content);
+
+  // Do not access the network during an OEM install.
+  if (!ConfigManager::Instance()->CanUseNetwork(is_machine)) {
+    CORE_LOG(L1, (_T("[Stats not uploaded because network use prohibited]")));
+    return GOOPDATE_E_CANNOT_USE_NETWORK;
+  }
+
+  const TCHAR* version = GetVersionString();
+  CString machine_id(goopdate_utils::GetPersistentMachineId());
+  CString user_id(goopdate_utils::GetPersistentUserId(is_machine ?
+                                                      MACHINE_KEY_NAME :
+                                                      USER_KEY_NAME));
+  CString test_source(ConfigManager::Instance()->GetTestSource());
+
+  CString url(kUrlUsageStatsReport);
+  url.AppendFormat(_T("?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s=%s&%s"),
+      kMetricsServerParamSourceId,  kMetricsProductName,
+      kMetricsServerParamVersion,   version,
+      kMetricsServerParamIsMachine, is_machine ? _T("1") : _T("0"),
+      kMetricsServerTestSource,     test_source,
+      kMetricsServerMachineId,      machine_id,
+      kMetricsServerUserId,         user_id,
+      extra_url_data);
+
+  CORE_LOG(L3, (_T("[upload usage stats][%s]"), content));
+
+  const NetworkConfig::Session& session(NetworkConfig::Instance().session());
+  NetworkRequest network_request(session);
+  network_request.set_num_retries(1);
+  network_request.AddHttpRequest(new SimpleRequest);
+  network_request.AddHttpRequest(new BrowserRequest);
+
+  // PostRequest falls back to https.
+  CString response;
+  return PostRequest(&network_request, true, url, content, &response);
+}
+
+HRESULT ReportMetrics(bool is_machine,
+                      const TCHAR* extra_url_data,
+                      DWORD interval) {
+  PersistentMetricsIteratorWin32 it(kMetricsProductName, is_machine), end;
+  Formatter formatter(CT2A(kMetricsProductName), interval);
+
+  for (; it != end; ++it) {
+    formatter.AddMetric(*it);
+  }
+
+  return UploadMetrics(is_machine, extra_url_data, CA2T(formatter.output()));
+}
+
+HRESULT DoResetMetrics(bool is_machine) {
+  CString key_name;
+  key_name.Format(kStatsKeyFormatString, kMetricsProductName);
+  HKEY parent_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+  RegKey key;
+  HRESULT hr = key.Create(parent_key, key_name);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[Unable to create metrics key][0x%08x]"), hr));
+    return hr;
+  }
+  return ResetPersistentMetrics(&key);
+}
+
+HRESULT DoAggregateMetrics(bool is_machine) {
+  MetricsAggregatorWin32 aggregator(g_global_metrics,
+                                    kMetricsProductName,
+                                    is_machine);
+  if (!aggregator.AggregateMetrics()) {
+    CORE_LOG(LW, (_T("[Metrics aggregation failed for unknown reasons]")));
+    return GOOPDATE_E_METRICS_AGGREGATE_FAILED;
+  }
+  return S_OK;
+}
+
+HRESULT DoAggregateAndReportMetrics(bool is_machine, bool force_report) {
+  CString key_name;
+  key_name.Format(kStatsKeyFormatString, kMetricsProductName);
+  HKEY parent_key = is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+  RegKey key;
+  HRESULT hr = key.Create(parent_key, key_name);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[Unable to create metrics key][0x%08x]"), hr));
+    return hr;
+  }
+
+  DWORD now = static_cast<DWORD>(time(NULL));
+
+  DWORD last_transmission_time(0);
+  hr = key.GetValue(kLastTransmissionTimeValueName, &last_transmission_time);
+
+  // Reset and start over if last transmission time is missing or hinky.
+  if (FAILED(hr) || last_transmission_time > now) {
+    CORE_LOG(LW, (_T("[hinky or missing last transmission time]")));
+    ResetPersistentMetrics(&key);
+    return S_OK;
+  }
+
+  hr = DoAggregateMetrics(is_machine);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[DoAggregateMetrics failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  DWORD time_since_last_transmission = now - last_transmission_time;
+  if (force_report ||
+      time_since_last_transmission >= kMetricsUploadIntervalSec) {
+    // Report the metrics, reset the metrics, and update 'LastTransmission'.
+    HRESULT hr = ReportMetrics(is_machine, NULL, time_since_last_transmission);
+    if (SUCCEEDED(hr)) {
+      VERIFY1(SUCCEEDED(ResetPersistentMetrics(&key)));
+      DWORD now_sec = static_cast<DWORD>(time(NULL));
+      CORE_LOG(L3, (_T("[Stats upload successful]")));
+      return S_OK;
+    } else {
+      CORE_LOG(LE, (_T("[Stats upload failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+bool InitializeLock(GLock* lock, bool is_machine) {
+  ASSERT1(lock);
+  NamedObjectAttributes attributes;
+  GetNamedObjectAttributes(kMetricsSerializer, is_machine, &attributes);
+  return lock->InitializeWithSecAttr(attributes.name, &attributes.sa);
+}
+
+}  // namespace
+
+
+HRESULT ResetMetrics(bool is_machine) {
+  CORE_LOG(L2, (_T("[ResetMetrics]")));
+  GLock lock;
+  if (!InitializeLock(&lock, is_machine)) {
+    return GOOPDATE_E_METRICS_LOCK_INIT_FAILED;
+  }
+  __mutexScope(lock);
+  return DoResetMetrics(is_machine);
+}
+
+HRESULT AggregateMetrics(bool is_machine) {
+  CORE_LOG(L2, (_T("[AggregateMetrics]")));
+
+  if (!ConfigManager::Instance()->CanCollectStats(is_machine)) {
+    return S_OK;
+  }
+
+  GLock lock;
+  if (!InitializeLock(&lock, is_machine)) {
+    return GOOPDATE_E_METRICS_LOCK_INIT_FAILED;
+  }
+  __mutexScope(lock);
+  return DoAggregateMetrics(is_machine);
+}
+
+HRESULT AggregateAndReportMetrics(bool is_machine, bool force_report) {
+  CORE_LOG(L2, (_T("[AggregateAndReportMetrics]")));
+
+  if (!ConfigManager::Instance()->CanCollectStats(is_machine)) {
+    return S_OK;
+  }
+
+  GLock lock;
+  if (!InitializeLock(&lock, is_machine)) {
+    return GOOPDATE_E_METRICS_LOCK_INIT_FAILED;
+  }
+  __mutexScope(lock);
+  return DoAggregateAndReportMetrics(is_machine, force_report);
+}
+
+}  // namespace omaha
+
diff --git a/goopdate/stats_uploader.h b/goopdate/stats_uploader.h
index 8945f42..eb88bea 100644
--- a/goopdate/stats_uploader.h
+++ b/goopdate/stats_uploader.h
@@ -1,53 +1,53 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// Constants for the statsreport library.

-

-#ifndef OMAHA_GOOPDATE_STATS_UPLOADER_H__

-#define OMAHA_GOOPDATE_STATS_UPLOADER_H__

-

-#include <windows.h>

-#include <tchar.h>

-

-namespace omaha {

-

-// The product name is chosen so that the stats are persisted under

-// the Google Update registry key for the machine or user, respectively.

-const TCHAR* const kMetricsProductName           = _T("Update");

-

-const TCHAR* const kMetricsServerParamSourceId   = _T("sourceid");

-const TCHAR* const kMetricsServerParamVersion    = _T("v");

-const TCHAR* const kMetricsServerParamIsMachine  = _T("ismachine");

-const TCHAR* const kMetricsServerTestSource      = _T("testsource");

-const TCHAR* const kMetricsServerMachineId       = _T("mi");

-const TCHAR* const kMetricsServerUserId          = _T("ui");

-

-// Metrics are uploaded every 25 hours.

-const int kMetricsUploadIntervalSec              = 25 * 60 * 60;

-

-// Deletes existing metrics and initializes 'LastTransmission' to current time.

-HRESULT ResetMetrics(bool is_machine);

-

-// Aggregates metrics by saving them in registry.

-HRESULT AggregateMetrics(bool is_machine);

-

-// Aggregates and reports the metrics if needed, as defined by the metrics

-// upload interval. The interval is ignored when 'force_report' is true.

-HRESULT AggregateAndReportMetrics(bool is_machine, bool force_report);

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_STATS_UPLOADER_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// Constants for the statsreport library.
+
+#ifndef OMAHA_GOOPDATE_STATS_UPLOADER_H__
+#define OMAHA_GOOPDATE_STATS_UPLOADER_H__
+
+#include <windows.h>
+#include <tchar.h>
+
+namespace omaha {
+
+// The product name is chosen so that the stats are persisted under
+// the Google Update registry key for the machine or user, respectively.
+const TCHAR* const kMetricsProductName           = _T("Update");
+
+const TCHAR* const kMetricsServerParamSourceId   = _T("sourceid");
+const TCHAR* const kMetricsServerParamVersion    = _T("v");
+const TCHAR* const kMetricsServerParamIsMachine  = _T("ismachine");
+const TCHAR* const kMetricsServerTestSource      = _T("testsource");
+const TCHAR* const kMetricsServerMachineId       = _T("mi");
+const TCHAR* const kMetricsServerUserId          = _T("ui");
+
+// Metrics are uploaded every 25 hours.
+const int kMetricsUploadIntervalSec              = 25 * 60 * 60;
+
+// Deletes existing metrics and initializes 'LastTransmission' to current time.
+HRESULT ResetMetrics(bool is_machine);
+
+// Aggregates metrics by saving them in registry.
+HRESULT AggregateMetrics(bool is_machine);
+
+// Aggregates and reports the metrics if needed, as defined by the metrics
+// upload interval. The interval is ignored when 'force_report' is true.
+HRESULT AggregateAndReportMetrics(bool is_machine, bool force_report);
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_STATS_UPLOADER_H__
+
diff --git a/goopdate/stats_uploader_unittest.cc b/goopdate/stats_uploader_unittest.cc
index d090e72..a974774 100644
--- a/goopdate/stats_uploader_unittest.cc
+++ b/goopdate/stats_uploader_unittest.cc
@@ -1,236 +1,236 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// All tests are user only.

-

-#include <windows.h>

-#include <limits.h>

-#include <ctime>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/error.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/goopdate/stats_uploader.h"

-#include "omaha/statsreport/metrics.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-DEFINE_METRIC_bool(test_bool);

-

-}  // namespace

-

-class StatsUploaderTest : public testing::Test {

- protected:

-  virtual void SetUp() {

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-

-    // Overriding HKLM prevents the Windows DNS resolver from working.

-    // Only override HKCU and run the tests as user.

-    OverrideSpecifiedRegistryHives(kRegistryHiveOverrideRoot, false, true);

-    stats_report::g_global_metrics.Initialize();

-

-    // These tests assume that metric collection is enabled.

-    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                      kRegValueForceUsageStats,

-                                      static_cast<DWORD>(1)));

-  }

-

-  virtual void TearDown() {

-    stats_report::g_global_metrics.Uninitialize();

-    RestoreRegistryHives();

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-  }

-

-  HRESULT GetMetricValue(const TCHAR* value_name, bool* value) {

-    CString key_name = key_name_ + CString(_T("Booleans"));

-

-    scoped_array<byte> buffer;

-    DWORD byte_count(0);

-    HRESULT hr = RegKey::GetValue(key_name,

-                                  value_name,

-                                  address(buffer),

-                                  &byte_count);

-    if (FAILED(hr)) {

-      return hr;

-    }

-    if (byte_count != sizeof(uint32)) {                         // NOLINT

-      return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);

-    }

-    *value = *reinterpret_cast<uint32*>(buffer.get()) != 0;

-    return S_OK;

-  }

-

-  HRESULT GetLastTrasmission(DWORD* last_transmission) {

-    const TCHAR value_name[] = _T("LastTransmission");

-    return RegKey::GetValue(key_name_, value_name, last_transmission);

-  }

-

-  HRESULT SetLastTransmission(DWORD last_transmission) {

-    const TCHAR value_name[] = _T("LastTransmission");

-    return RegKey::SetValue(key_name_, value_name, last_transmission);

-  }

-

-  bool AreMetricsEmpty() {

-    RegKey reg_key;

-    HRESULT hr = reg_key.Open(key_name_, KEY_READ);

-    if (FAILED(hr)) {

-      return true;

-    }

-    return reg_key.GetSubkeyCount() == 0;

-  }

-

-  static const TCHAR key_name_[];

-  static const TCHAR metric_name_[];

-};

-

-const TCHAR StatsUploaderTest::key_name_[] =

-    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily\\");

-const TCHAR StatsUploaderTest::metric_name_[] =  _T("test_bool");

-

-

-TEST_F(StatsUploaderTest, AggregateMetrics) {

-  bool value = false;

-  EXPECT_HRESULT_FAILED(GetMetricValue(metric_name_, &value));

-

-  metric_test_bool = true;

-  EXPECT_HRESULT_SUCCEEDED(AggregateMetrics(false));    // User.

-

-  EXPECT_HRESULT_SUCCEEDED(GetMetricValue(metric_name_, &value));

-  EXPECT_EQ(true, value);

-

-  metric_test_bool = false;

-  EXPECT_HRESULT_SUCCEEDED(AggregateMetrics(false));    // User.

-

-  EXPECT_HRESULT_SUCCEEDED(GetMetricValue(metric_name_, &value));

-  EXPECT_EQ(false, value);

-}

-

-TEST_F(StatsUploaderTest, AggregateAndReportMetrics) {

-  metric_test_bool = true;

-

-  // Metrics are not in the registry until they are aggregated.

-  bool value = false;

-  EXPECT_HRESULT_FAILED(GetMetricValue(metric_name_, &value));

-

-  // AggregateAndReportMetrics resets metrics and updates 'LastTransmission' to

-  // the current time since there was no 'LastTransmission'.

-  EXPECT_HRESULT_SUCCEEDED(AggregateAndReportMetrics(false, false));

-  EXPECT_TRUE(AreMetricsEmpty());

-  DWORD last_transmission(0);

-  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));

-  EXPECT_NE(0, last_transmission);

-

-  // AggregateAndReportMetrics aggregates but it does not report since

-  // 'LastTransmission is current.

-  EXPECT_HRESULT_SUCCEEDED(AggregateAndReportMetrics(false, false));

-  EXPECT_FALSE(AreMetricsEmpty());

-  EXPECT_HRESULT_SUCCEEDED(GetMetricValue(metric_name_, &value));

-  EXPECT_EQ(true, value);

-  DWORD previous_last_transmission = last_transmission;

-  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));

-  EXPECT_EQ(previous_last_transmission, last_transmission);

-

-  // Roll back 'Last Trasmission' by 26 hours. AggregateAndReportMetrics

-  // aggregates, reports metrics, and updates 'LastTransmission'.

-  metric_test_bool = true;

-  last_transmission -= 26 * 60 * 60;

-  EXPECT_HRESULT_SUCCEEDED(SetLastTransmission(last_transmission));

-  EXPECT_HRESULT_SUCCEEDED(AggregateAndReportMetrics(false, false));

-  EXPECT_TRUE(AreMetricsEmpty());

-  previous_last_transmission = last_transmission;

-  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));

-  EXPECT_NE(previous_last_transmission, last_transmission);

-

-  // Roll forward the 'LastTransmission' by 60 seconds.

-  // AggregateAndReportMetrics resets metrics and updates 'LastTransmission' to

-  // the current time since there 'LastTransmission' was in the future.

-  metric_test_bool = true;

-  last_transmission = static_cast<DWORD>(time(NULL)) + 60;

-  EXPECT_HRESULT_SUCCEEDED(SetLastTransmission(last_transmission));

-  EXPECT_HRESULT_SUCCEEDED(AggregateAndReportMetrics(false, false));

-  EXPECT_TRUE(AreMetricsEmpty());

-  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));

-  EXPECT_NE(0, last_transmission);

-

-  // Force reporting the metrics.

-  metric_test_bool = true;

-  EXPECT_HRESULT_SUCCEEDED(AggregateAndReportMetrics(false, true));

-  EXPECT_TRUE(AreMetricsEmpty());

-}

-

-TEST_F(StatsUploaderTest, ResetPersistentMetricsTest) {

-  const TCHAR* keys[] = {

-    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily\\Timings"),

-    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily\\Counts"),

-    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily\\Integers"),

-    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily\\Booleans"),

-  };

-  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKeys(keys, arraysize(keys)));

-  EXPECT_HRESULT_SUCCEEDED(ResetMetrics(false));    // User.

-

-  for (size_t i = 0; i != arraysize(keys); ++i) {

-    EXPECT_FALSE(RegKey::HasKey(keys[i]));

-  }

-  EXPECT_TRUE(AreMetricsEmpty());

-

-  DWORD last_transmission(ULONG_MAX);

-  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));

-  EXPECT_NE(0, last_transmission);

-}

-

-// AggregateAndReportMetrics aggregates, but is unable to report metrics and

-// does not update 'LastTransmission'.

-TEST_F(StatsUploaderTest,

-       AggregateAndReportMetrics_GoogleUpdateEulaNotAccepted_DoNotForce) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  metric_test_bool = true;

-  DWORD last_transmission = 12345678;

-  EXPECT_HRESULT_SUCCEEDED(SetLastTransmission(last_transmission));

-  EXPECT_EQ(GOOPDATE_E_CANNOT_USE_NETWORK,

-            AggregateAndReportMetrics(false, false));

-  EXPECT_FALSE(AreMetricsEmpty());

-  DWORD previous_last_transmission = last_transmission;

-  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));

-  EXPECT_EQ(12345678, last_transmission);

-}

-

-// AggregateAndReportMetrics aggregates, but is unable to report metrics and

-// does not update 'LastTransmission'.

-TEST_F(StatsUploaderTest,

-       AggregateAndReportMetrics_GoogleUpdateEulaNotAccepted_Force) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  metric_test_bool = true;

-  DWORD last_transmission = 12345678;

-  EXPECT_HRESULT_SUCCEEDED(SetLastTransmission(last_transmission));

-  EXPECT_EQ(GOOPDATE_E_CANNOT_USE_NETWORK,

-            AggregateAndReportMetrics(false, true));

-  EXPECT_FALSE(AreMetricsEmpty());

-  DWORD previous_last_transmission = last_transmission;

-  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));

-  EXPECT_EQ(12345678, last_transmission);

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// All tests are user only.
+
+#include <windows.h>
+#include <limits.h>
+#include <ctime>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/error.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/goopdate/stats_uploader.h"
+#include "omaha/statsreport/metrics.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+DEFINE_METRIC_bool(test_bool);
+
+}  // namespace
+
+class StatsUploaderTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+
+    // Overriding HKLM prevents the Windows DNS resolver from working.
+    // Only override HKCU and run the tests as user.
+    OverrideSpecifiedRegistryHives(kRegistryHiveOverrideRoot, false, true);
+    stats_report::g_global_metrics.Initialize();
+
+    // These tests assume that metric collection is enabled.
+    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                      kRegValueForceUsageStats,
+                                      static_cast<DWORD>(1)));
+  }
+
+  virtual void TearDown() {
+    stats_report::g_global_metrics.Uninitialize();
+    RestoreRegistryHives();
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+  }
+
+  HRESULT GetMetricValue(const TCHAR* value_name, bool* value) {
+    CString key_name = key_name_ + CString(_T("Booleans"));
+
+    scoped_array<byte> buffer;
+    DWORD byte_count(0);
+    HRESULT hr = RegKey::GetValue(key_name,
+                                  value_name,
+                                  address(buffer),
+                                  &byte_count);
+    if (FAILED(hr)) {
+      return hr;
+    }
+    if (byte_count != sizeof(uint32)) {                         // NOLINT
+      return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
+    }
+    *value = *reinterpret_cast<uint32*>(buffer.get()) != 0;
+    return S_OK;
+  }
+
+  HRESULT GetLastTrasmission(DWORD* last_transmission) {
+    const TCHAR value_name[] = _T("LastTransmission");
+    return RegKey::GetValue(key_name_, value_name, last_transmission);
+  }
+
+  HRESULT SetLastTransmission(DWORD last_transmission) {
+    const TCHAR value_name[] = _T("LastTransmission");
+    return RegKey::SetValue(key_name_, value_name, last_transmission);
+  }
+
+  bool AreMetricsEmpty() {
+    RegKey reg_key;
+    HRESULT hr = reg_key.Open(key_name_, KEY_READ);
+    if (FAILED(hr)) {
+      return true;
+    }
+    return reg_key.GetSubkeyCount() == 0;
+  }
+
+  static const TCHAR key_name_[];
+  static const TCHAR metric_name_[];
+};
+
+const TCHAR StatsUploaderTest::key_name_[] =
+    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily\\");
+const TCHAR StatsUploaderTest::metric_name_[] =  _T("test_bool");
+
+
+TEST_F(StatsUploaderTest, AggregateMetrics) {
+  bool value = false;
+  EXPECT_HRESULT_FAILED(GetMetricValue(metric_name_, &value));
+
+  metric_test_bool = true;
+  EXPECT_HRESULT_SUCCEEDED(AggregateMetrics(false));    // User.
+
+  EXPECT_HRESULT_SUCCEEDED(GetMetricValue(metric_name_, &value));
+  EXPECT_EQ(true, value);
+
+  metric_test_bool = false;
+  EXPECT_HRESULT_SUCCEEDED(AggregateMetrics(false));    // User.
+
+  EXPECT_HRESULT_SUCCEEDED(GetMetricValue(metric_name_, &value));
+  EXPECT_EQ(false, value);
+}
+
+TEST_F(StatsUploaderTest, AggregateAndReportMetrics) {
+  metric_test_bool = true;
+
+  // Metrics are not in the registry until they are aggregated.
+  bool value = false;
+  EXPECT_HRESULT_FAILED(GetMetricValue(metric_name_, &value));
+
+  // AggregateAndReportMetrics resets metrics and updates 'LastTransmission' to
+  // the current time since there was no 'LastTransmission'.
+  EXPECT_HRESULT_SUCCEEDED(AggregateAndReportMetrics(false, false));
+  EXPECT_TRUE(AreMetricsEmpty());
+  DWORD last_transmission(0);
+  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));
+  EXPECT_NE(0, last_transmission);
+
+  // AggregateAndReportMetrics aggregates but it does not report since
+  // 'LastTransmission is current.
+  EXPECT_HRESULT_SUCCEEDED(AggregateAndReportMetrics(false, false));
+  EXPECT_FALSE(AreMetricsEmpty());
+  EXPECT_HRESULT_SUCCEEDED(GetMetricValue(metric_name_, &value));
+  EXPECT_EQ(true, value);
+  DWORD previous_last_transmission = last_transmission;
+  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));
+  EXPECT_EQ(previous_last_transmission, last_transmission);
+
+  // Roll back 'Last Trasmission' by 26 hours. AggregateAndReportMetrics
+  // aggregates, reports metrics, and updates 'LastTransmission'.
+  metric_test_bool = true;
+  last_transmission -= 26 * 60 * 60;
+  EXPECT_HRESULT_SUCCEEDED(SetLastTransmission(last_transmission));
+  EXPECT_HRESULT_SUCCEEDED(AggregateAndReportMetrics(false, false));
+  EXPECT_TRUE(AreMetricsEmpty());
+  previous_last_transmission = last_transmission;
+  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));
+  EXPECT_NE(previous_last_transmission, last_transmission);
+
+  // Roll forward the 'LastTransmission' by 60 seconds.
+  // AggregateAndReportMetrics resets metrics and updates 'LastTransmission' to
+  // the current time since there 'LastTransmission' was in the future.
+  metric_test_bool = true;
+  last_transmission = static_cast<DWORD>(time(NULL)) + 60;
+  EXPECT_HRESULT_SUCCEEDED(SetLastTransmission(last_transmission));
+  EXPECT_HRESULT_SUCCEEDED(AggregateAndReportMetrics(false, false));
+  EXPECT_TRUE(AreMetricsEmpty());
+  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));
+  EXPECT_NE(0, last_transmission);
+
+  // Force reporting the metrics.
+  metric_test_bool = true;
+  EXPECT_HRESULT_SUCCEEDED(AggregateAndReportMetrics(false, true));
+  EXPECT_TRUE(AreMetricsEmpty());
+}
+
+TEST_F(StatsUploaderTest, ResetPersistentMetricsTest) {
+  const TCHAR* keys[] = {
+    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily\\Timings"),
+    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily\\Counts"),
+    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily\\Integers"),
+    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily\\Booleans"),
+  };
+  EXPECT_HRESULT_SUCCEEDED(RegKey::CreateKeys(keys, arraysize(keys)));
+  EXPECT_HRESULT_SUCCEEDED(ResetMetrics(false));    // User.
+
+  for (size_t i = 0; i != arraysize(keys); ++i) {
+    EXPECT_FALSE(RegKey::HasKey(keys[i]));
+  }
+  EXPECT_TRUE(AreMetricsEmpty());
+
+  DWORD last_transmission(ULONG_MAX);
+  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));
+  EXPECT_NE(0, last_transmission);
+}
+
+// AggregateAndReportMetrics aggregates, but is unable to report metrics and
+// does not update 'LastTransmission'.
+TEST_F(StatsUploaderTest,
+       AggregateAndReportMetrics_GoogleUpdateEulaNotAccepted_DoNotForce) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  metric_test_bool = true;
+  DWORD last_transmission = 12345678;
+  EXPECT_HRESULT_SUCCEEDED(SetLastTransmission(last_transmission));
+  EXPECT_EQ(GOOPDATE_E_CANNOT_USE_NETWORK,
+            AggregateAndReportMetrics(false, false));
+  EXPECT_FALSE(AreMetricsEmpty());
+  DWORD previous_last_transmission = last_transmission;
+  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));
+  EXPECT_EQ(12345678, last_transmission);
+}
+
+// AggregateAndReportMetrics aggregates, but is unable to report metrics and
+// does not update 'LastTransmission'.
+TEST_F(StatsUploaderTest,
+       AggregateAndReportMetrics_GoogleUpdateEulaNotAccepted_Force) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  metric_test_bool = true;
+  DWORD last_transmission = 12345678;
+  EXPECT_HRESULT_SUCCEEDED(SetLastTransmission(last_transmission));
+  EXPECT_EQ(GOOPDATE_E_CANNOT_USE_NETWORK,
+            AggregateAndReportMetrics(false, true));
+  EXPECT_FALSE(AreMetricsEmpty());
+  DWORD previous_last_transmission = last_transmission;
+  EXPECT_HRESULT_SUCCEEDED(GetLastTrasmission(&last_transmission));
+  EXPECT_EQ(12345678, last_transmission);
+}
+
+}  // namespace omaha
diff --git a/goopdate/ui_displayed_event.cc b/goopdate/ui_displayed_event.cc
index a493e24..b44b2c1 100644
--- a/goopdate/ui_displayed_event.cc
+++ b/goopdate/ui_displayed_event.cc
@@ -1,95 +1,95 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/ui_displayed_event.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/goopdate/goopdate_utils.h"

-

-namespace omaha {

-

-HRESULT UIDisplayedEventManager::CreateEvent(bool is_machine) {

-  ASSERT1(!IsEventHandleInitialized());

-  return goopdate_utils::CreateUniqueEventInEnvironment(

-        kUiDisplayedEventEnvironmentVariableName,

-        is_machine,

-        address(ui_displayed_event_));

-}

-

-// Caller does not own the event handle and must not close it.

-// There is a single event handle for each process. The handle is closed when

-// the process exits.

-HRESULT UIDisplayedEventManager::GetEvent(bool is_machine,

-                                          HANDLE* ui_displayed_event) {

-  ASSERT1(ui_displayed_event);

-  *ui_displayed_event = NULL;

-  if (IsEventHandleInitialized()) {

-    *ui_displayed_event = get(ui_displayed_event_);

-    return S_OK;

-  }

-

-  HRESULT hr = goopdate_utils::OpenUniqueEventFromEnvironment(

-      kUiDisplayedEventEnvironmentVariableName,

-      is_machine,

-      address(ui_displayed_event_));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  *ui_displayed_event = get(ui_displayed_event_);

-  return S_OK;

-}

-

-// Creates the event if it does not already exist in the environment.

-void UIDisplayedEventManager::SignalEvent(bool is_machine) {

-  CORE_LOG(L2, (_T("[SignalEvent]")));

-

-  if (!IsEventHandleInitialized()) {

-    HRESULT hr = GetEvent(is_machine, address(ui_displayed_event_));

-    if (HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND) == hr) {

-      // The event was not created by an earlier process. This can happen when

-      // developers run the /handoff process directly.

-      hr = CreateEvent(is_machine);

-    }

-    if (FAILED(hr)) {

-      reset(ui_displayed_event_);

-      // We may display two UIs.

-      return;

-    }

-  }

-

-  ASSERT1(IsEventHandleInitialized());

-  VERIFY1(::SetEvent(get(ui_displayed_event_)));

-}

-

-// Returns false if the event does not exist in the environment variable.

-bool UIDisplayedEventManager::HasUIBeenDisplayed(bool is_machine) {

-  HANDLE ui_displayed_event(NULL);

-  HRESULT hr = GetEvent(is_machine, &ui_displayed_event);

-  if (FAILED(hr)) {

-    return false;

-  }

-

-  int res = ::WaitForSingleObject(ui_displayed_event, 0);

-  ASSERT1(WAIT_OBJECT_0 == res || WAIT_TIMEOUT == res);

-  return WAIT_OBJECT_0 == res;

-}

-

-bool UIDisplayedEventManager::IsEventHandleInitialized() {

-  return valid(ui_displayed_event_);

-}

-

-scoped_handle UIDisplayedEventManager::ui_displayed_event_;

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/ui_displayed_event.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/goopdate/goopdate_utils.h"
+
+namespace omaha {
+
+HRESULT UIDisplayedEventManager::CreateEvent(bool is_machine) {
+  ASSERT1(!IsEventHandleInitialized());
+  return goopdate_utils::CreateUniqueEventInEnvironment(
+        kUiDisplayedEventEnvironmentVariableName,
+        is_machine,
+        address(ui_displayed_event_));
+}
+
+// Caller does not own the event handle and must not close it.
+// There is a single event handle for each process. The handle is closed when
+// the process exits.
+HRESULT UIDisplayedEventManager::GetEvent(bool is_machine,
+                                          HANDLE* ui_displayed_event) {
+  ASSERT1(ui_displayed_event);
+  *ui_displayed_event = NULL;
+  if (IsEventHandleInitialized()) {
+    *ui_displayed_event = get(ui_displayed_event_);
+    return S_OK;
+  }
+
+  HRESULT hr = goopdate_utils::OpenUniqueEventFromEnvironment(
+      kUiDisplayedEventEnvironmentVariableName,
+      is_machine,
+      address(ui_displayed_event_));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  *ui_displayed_event = get(ui_displayed_event_);
+  return S_OK;
+}
+
+// Creates the event if it does not already exist in the environment.
+void UIDisplayedEventManager::SignalEvent(bool is_machine) {
+  CORE_LOG(L2, (_T("[SignalEvent]")));
+
+  if (!IsEventHandleInitialized()) {
+    HRESULT hr = GetEvent(is_machine, address(ui_displayed_event_));
+    if (HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND) == hr) {
+      // The event was not created by an earlier process. This can happen when
+      // developers run the /handoff process directly.
+      hr = CreateEvent(is_machine);
+    }
+    if (FAILED(hr)) {
+      reset(ui_displayed_event_);
+      // We may display two UIs.
+      return;
+    }
+  }
+
+  ASSERT1(IsEventHandleInitialized());
+  VERIFY1(::SetEvent(get(ui_displayed_event_)));
+}
+
+// Returns false if the event does not exist in the environment variable.
+bool UIDisplayedEventManager::HasUIBeenDisplayed(bool is_machine) {
+  HANDLE ui_displayed_event(NULL);
+  HRESULT hr = GetEvent(is_machine, &ui_displayed_event);
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  int res = ::WaitForSingleObject(ui_displayed_event, 0);
+  ASSERT1(WAIT_OBJECT_0 == res || WAIT_TIMEOUT == res);
+  return WAIT_OBJECT_0 == res;
+}
+
+bool UIDisplayedEventManager::IsEventHandleInitialized() {
+  return valid(ui_displayed_event_);
+}
+
+scoped_handle UIDisplayedEventManager::ui_displayed_event_;
+
+}  // namespace omaha
diff --git a/goopdate/ui_displayed_event.h b/goopdate/ui_displayed_event.h
index 8660560..0c24186 100644
--- a/goopdate/ui_displayed_event.h
+++ b/goopdate/ui_displayed_event.h
@@ -1,53 +1,53 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_UI_DISPLAYED_EVENT_H_

-#define OMAHA_GOOPDATE_UI_DISPLAYED_EVENT_H_

-

-#include <windows.h>

-#include "omaha/common/scoped_any.h"

-

-namespace omaha {

-

-// Manages the UI Displayed Event, which is used to communicate whether a UI

-// has been displayed between processes.

-// This class is not thread safe.

-class UIDisplayedEventManager {

- public:

-  // Creates the event and sets its name in the environment variable.

-  static HRESULT CreateEvent(bool is_machine);

-

-  // Gets the event from the name in the environment variable.

-  static HRESULT GetEvent(bool is_machine, HANDLE* ui_displayed_event);

-

-  // Signals the event. Creates it if its name does not already exist in the

-  // environment variable.

-  static void SignalEvent(bool is_machine);

-

-  // Returns whether the event has been signaled.

-  static bool HasUIBeenDisplayed(bool is_machine);

-

- private:

-  // Returns whether this process's event handle has been initialized.

-  static bool IsEventHandleInitialized();

-

-  // A single instance of the UI Displayed Event handle to be used for the

-  // lifetime of this process.

-  static scoped_handle ui_displayed_event_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_UI_DISPLAYED_EVENT_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_UI_DISPLAYED_EVENT_H_
+#define OMAHA_GOOPDATE_UI_DISPLAYED_EVENT_H_
+
+#include <windows.h>
+#include "omaha/common/scoped_any.h"
+
+namespace omaha {
+
+// Manages the UI Displayed Event, which is used to communicate whether a UI
+// has been displayed between processes.
+// This class is not thread safe.
+class UIDisplayedEventManager {
+ public:
+  // Creates the event and sets its name in the environment variable.
+  static HRESULT CreateEvent(bool is_machine);
+
+  // Gets the event from the name in the environment variable.
+  static HRESULT GetEvent(bool is_machine, HANDLE* ui_displayed_event);
+
+  // Signals the event. Creates it if its name does not already exist in the
+  // environment variable.
+  static void SignalEvent(bool is_machine);
+
+  // Returns whether the event has been signaled.
+  static bool HasUIBeenDisplayed(bool is_machine);
+
+ private:
+  // Returns whether this process's event handle has been initialized.
+  static bool IsEventHandleInitialized();
+
+  // A single instance of the UI Displayed Event handle to be used for the
+  // lifetime of this process.
+  static scoped_handle ui_displayed_event_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_UI_DISPLAYED_EVENT_H_
diff --git a/goopdate/update_response.h b/goopdate/update_response.h
index b6c505e..00cd2b0 100644
--- a/goopdate/update_response.h
+++ b/goopdate/update_response.h
@@ -1,87 +1,87 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// update_response.h:  The hierarchical response for a product and its

-// components from a server request for install/update.

-

-#ifndef OMAHA_GOOPDATE_UPDATE_RESPONSE_H__

-#define OMAHA_GOOPDATE_UPDATE_RESPONSE_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <map>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/update_response_data.h"

-

-namespace omaha {

-

-class UpdateResponse {

- public:

-  UpdateResponse() {}

-  explicit UpdateResponse(const UpdateResponseData& response_data) {

-    response_data_ = response_data;

-  }

-  ~UpdateResponse() {}

-

-  void set_update_response_data(const UpdateResponseData& response_data) {

-    response_data_ = response_data;

-  }

-

-  const UpdateResponseData& update_response_data() const {

-    return response_data_;

-  }

-

-  // Adds the component. Returns false if the component already exists, and

-  // does not overwrite the value.

-  bool AddComponentResponseData(const UpdateResponseData& component_data) {

-    std::pair<GUID, UpdateResponseData> data(component_data.guid(),

-                                             component_data);

-    return components_.insert(data).second;

-  }

-

-  UpdateResponseDatas::const_iterator components_begin() const {

-    return components_.begin();

-  }

-

-  UpdateResponseDatas::const_iterator components_end() const {

-    return components_.end();

-  }

-

-  bool IsComponentPresent(const GUID& guid) const {

-    return components_.find(guid) != components_.end();

-  }

-

-  const UpdateResponseData& GetComponentData(const GUID& guid) const {

-    UpdateResponseDatas::const_iterator iter = components_.find(guid);

-    ASSERT1(iter != components_.end());

-    return (*iter).second;

-  }

-

-  size_t num_components() const { return components_.size(); }

-

- private:

-  UpdateResponseData response_data_;

-  UpdateResponseDatas components_;

-};

-

-// Map of UpdateResponses, key=Guid, value=UpdateResponse.

-typedef std::map<GUID, UpdateResponse, GuidComparer> UpdateResponses;

-

-}  // namespace omaha.

-

-#endif  // OMAHA_GOOPDATE_UPDATE_RESPONSE_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// update_response.h:  The hierarchical response for a product and its
+// components from a server request for install/update.
+
+#ifndef OMAHA_GOOPDATE_UPDATE_RESPONSE_H__
+#define OMAHA_GOOPDATE_UPDATE_RESPONSE_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <map>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/update_response_data.h"
+
+namespace omaha {
+
+class UpdateResponse {
+ public:
+  UpdateResponse() {}
+  explicit UpdateResponse(const UpdateResponseData& response_data) {
+    response_data_ = response_data;
+  }
+  ~UpdateResponse() {}
+
+  void set_update_response_data(const UpdateResponseData& response_data) {
+    response_data_ = response_data;
+  }
+
+  const UpdateResponseData& update_response_data() const {
+    return response_data_;
+  }
+
+  // Adds the component. Returns false if the component already exists, and
+  // does not overwrite the value.
+  bool AddComponentResponseData(const UpdateResponseData& component_data) {
+    std::pair<GUID, UpdateResponseData> data(component_data.guid(),
+                                             component_data);
+    return components_.insert(data).second;
+  }
+
+  UpdateResponseDatas::const_iterator components_begin() const {
+    return components_.begin();
+  }
+
+  UpdateResponseDatas::const_iterator components_end() const {
+    return components_.end();
+  }
+
+  bool IsComponentPresent(const GUID& guid) const {
+    return components_.find(guid) != components_.end();
+  }
+
+  const UpdateResponseData& GetComponentData(const GUID& guid) const {
+    UpdateResponseDatas::const_iterator iter = components_.find(guid);
+    ASSERT1(iter != components_.end());
+    return (*iter).second;
+  }
+
+  size_t num_components() const { return components_.size(); }
+
+ private:
+  UpdateResponseData response_data_;
+  UpdateResponseDatas components_;
+};
+
+// Map of UpdateResponses, key=Guid, value=UpdateResponse.
+typedef std::map<GUID, UpdateResponse, GuidComparer> UpdateResponses;
+
+}  // namespace omaha.
+
+#endif  // OMAHA_GOOPDATE_UPDATE_RESPONSE_H__
+
diff --git a/goopdate/update_response_data.h b/goopdate/update_response_data.h
index 8e0edb5..99ed801 100644
--- a/goopdate/update_response_data.h
+++ b/goopdate/update_response_data.h
@@ -1,181 +1,181 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// update_response_data.h: The app/component data for a response including what

-// to download, how big it is, hash, etc..

-

-#ifndef OMAHA_GOOPDATE_UPDATE_RESPONSE_DATA_H__

-#define OMAHA_GOOPDATE_UPDATE_RESPONSE_DATA_H__

-

-#include <functional>

-#include <map>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/browser_utils.h"

-

-namespace omaha {

-

-// key=IndexString, value=InstallDataString.

-typedef std::map<CString, CString> InstallDataMap;

-

-// Represents the values that are used by the application to indicate its

-// requirement for admin.

-enum NeedsAdmin {

-  NEEDS_ADMIN_YES = 0,  // The application will install machine-wide.

-  NEEDS_ADMIN_NO,       // The application will install per user.

-};

-

-// What Omaha should do on successful installation.

-enum SuccessfulInstallAction {

-  SUCCESS_ACTION_DEFAULT = 0,

-  SUCCESS_ACTION_EXIT_SILENTLY,

-  SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD,

-};

-

-// Represents the information that is parsed from the response returned by

-// the server. The class also represents the information that is parsed

-// from the manifest that is downloaded as part of the meta-installer.

-// The UpdateResponseData contains this information for one app or a component.

-// For an entire product, the UpdateResponse will contain a hierarchy of these,

-// one for the main app and for each component.

-class UpdateResponseData {

- public:

-  UpdateResponseData()

-      : size_(0),

-        needs_admin_(omaha::NEEDS_ADMIN_NO),

-        guid_(GUID_NULL),

-        installation_id_(GUID_NULL),

-        browser_type_(BROWSER_UNKNOWN),

-        terminate_all_browsers_(false),

-        success_action_(SUCCESS_ACTION_DEFAULT) {

-  }

-

-  // Getters and setters for the private members.

-  CString url() const { return url_; }

-  void set_url(const CString& url) { url_ = url; }

-  int size() const { return size_; }

-  void set_size(const int& size) { size_ = size; }

-  CString hash() const { return hash_; }

-  void set_hash(const CString& hash) { hash_ = hash; }

-  NeedsAdmin needs_admin() const { return needs_admin_; }

-  void set_needs_admin(const NeedsAdmin& needs_admin) {

-    needs_admin_ = needs_admin;

-  }

-  CString arguments() const { return arguments_; }

-  void set_arguments(const CString& arguments) { arguments_ = arguments; }

-  GUID guid() const { return guid_; }

-  void set_guid(const GUID& guid) { guid_ = guid; }

-  CString app_name() const { return app_name_; }

-  void set_app_name(const CString& app_name) { app_name_ = app_name; }

-  CString language() const { return language_; }

-  void set_language(const CString& language) { language_ = language; }

-  CString status() const { return status_; }

-  void set_status(const CString& status) { status_ = status; }

-  GUID installation_id() const { return installation_id_; }

-  void set_installation_id(const GUID& installation_id) {

-    installation_id_ = installation_id;

-  }

-  CString ap() const { return ap_; }

-  void set_ap(const CString& ap) { ap_ = ap; }

-

-  CString tt_token() const { return tt_token_; }

-  void set_tt_token(const CString& tt_token) { tt_token_ = tt_token; }

-

-  CString success_url() const { return success_url_; }

-  void set_success_url(const CString& success_url) {

-    success_url_ = success_url;

-  }

-

-  CString error_url() const { return error_url_; }

-  void set_error_url(const CString& error_url) {

-    error_url_ = error_url;

-  }

-

-  BrowserType browser_type() const { return browser_type_; }

-  void set_browser_type(BrowserType type) {

-    browser_type_ = type;

-  }

-

-  bool terminate_all_browsers() const { return terminate_all_browsers_; }

-  void set_terminate_all_browsers(bool terminate_all) {

-    terminate_all_browsers_ = terminate_all;

-  }

-

-  SuccessfulInstallAction success_action() const { return success_action_; }

-  void set_success_action(SuccessfulInstallAction success_action) {

-    success_action_ = success_action;

-  }

-

-  CString version() const { return version_; }

-  void set_version(const CString& version) { version_ = version; }

-

-  CString GetInstallData(const CString& index) const {

-    InstallDataMap::const_iterator iter = install_data_.find(index);

-    if (iter == install_data_.end()) {

-      return CString();

-    }

-    return iter->second;

-  }

-  void SetInstallData(const CString& index, const CString& value) {

-    ASSERT1(install_data_.find(index) == install_data_.end());

-    install_data_[index] = value;

-  }

-

- private:

-  CString url_;               // The url for the application installer.

-  int size_;                  // The size of the download.

-  CString hash_;              // The 160bit SHA1 hash of the downloaded file.

-  NeedsAdmin needs_admin_;    // If the application needs admin to install.

-  CString arguments_;         // Arguments for application installation.

-  GUID guid_;                 // Uniquely represents the application.

-  // Remove these 5 members when legacy support is removed.

-  CString app_name_;          // Application name for display.

-  CString language_;          // The language for this application.

-  GUID installation_id_;      // Uniquely represents this install.

-  CString ap_;                // ap value to be set in the registry.

-  BrowserType browser_type_;  // Browser to launch.

-

-  // The status of the response. There needs to be a protocol established

-  // between the server and client to determine what the action should be

-  // on downloading the application installer.

-  CString status_;

-

-  CString tt_token_;          // TT value to be set in the registry.

-  CString success_url_;       // URL to launch the browser on success.

-  CString error_url_;         // URL describing error.

-  bool terminate_all_browsers_;  // Whether to restart all browsers.

-  SuccessfulInstallAction success_action_;  // Action after install success.

-  CString version_;           // The version of the application itself.

-  InstallDataMap install_data_;  // Written to a file and passed as argument to

-                                 // app installer.

-};

-

-struct GuidComparer : public std::less<GUID> {

-  bool operator()(const GUID& lhs, const GUID& rhs) const {

-    CString lhs_guid_str = GuidToString(lhs);

-    CString rhs_guid_str = GuidToString(rhs);

-    return (_tcsicmp(lhs_guid_str, rhs_guid_str) < 0);

-  }

-};

-

-// Represent the list of requests and responses that are used to communicate

-// with the AU server.

-typedef std::map<GUID, UpdateResponseData, GuidComparer> UpdateResponseDatas;

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_UPDATE_RESPONSE_DATA_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// update_response_data.h: The app/component data for a response including what
+// to download, how big it is, hash, etc..
+
+#ifndef OMAHA_GOOPDATE_UPDATE_RESPONSE_DATA_H__
+#define OMAHA_GOOPDATE_UPDATE_RESPONSE_DATA_H__
+
+#include <functional>
+#include <map>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/browser_utils.h"
+
+namespace omaha {
+
+// key=IndexString, value=InstallDataString.
+typedef std::map<CString, CString> InstallDataMap;
+
+// Represents the values that are used by the application to indicate its
+// requirement for admin.
+enum NeedsAdmin {
+  NEEDS_ADMIN_YES = 0,  // The application will install machine-wide.
+  NEEDS_ADMIN_NO,       // The application will install per user.
+};
+
+// What Omaha should do on successful installation.
+enum SuccessfulInstallAction {
+  SUCCESS_ACTION_DEFAULT = 0,
+  SUCCESS_ACTION_EXIT_SILENTLY,
+  SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD,
+};
+
+// Represents the information that is parsed from the response returned by
+// the server. The class also represents the information that is parsed
+// from the manifest that is downloaded as part of the meta-installer.
+// The UpdateResponseData contains this information for one app or a component.
+// For an entire product, the UpdateResponse will contain a hierarchy of these,
+// one for the main app and for each component.
+class UpdateResponseData {
+ public:
+  UpdateResponseData()
+      : size_(0),
+        needs_admin_(omaha::NEEDS_ADMIN_NO),
+        guid_(GUID_NULL),
+        installation_id_(GUID_NULL),
+        browser_type_(BROWSER_UNKNOWN),
+        terminate_all_browsers_(false),
+        success_action_(SUCCESS_ACTION_DEFAULT) {
+  }
+
+  // Getters and setters for the private members.
+  CString url() const { return url_; }
+  void set_url(const CString& url) { url_ = url; }
+  int size() const { return size_; }
+  void set_size(const int& size) { size_ = size; }
+  CString hash() const { return hash_; }
+  void set_hash(const CString& hash) { hash_ = hash; }
+  NeedsAdmin needs_admin() const { return needs_admin_; }
+  void set_needs_admin(const NeedsAdmin& needs_admin) {
+    needs_admin_ = needs_admin;
+  }
+  CString arguments() const { return arguments_; }
+  void set_arguments(const CString& arguments) { arguments_ = arguments; }
+  GUID guid() const { return guid_; }
+  void set_guid(const GUID& guid) { guid_ = guid; }
+  CString app_name() const { return app_name_; }
+  void set_app_name(const CString& app_name) { app_name_ = app_name; }
+  CString language() const { return language_; }
+  void set_language(const CString& language) { language_ = language; }
+  CString status() const { return status_; }
+  void set_status(const CString& status) { status_ = status; }
+  GUID installation_id() const { return installation_id_; }
+  void set_installation_id(const GUID& installation_id) {
+    installation_id_ = installation_id;
+  }
+  CString ap() const { return ap_; }
+  void set_ap(const CString& ap) { ap_ = ap; }
+
+  CString tt_token() const { return tt_token_; }
+  void set_tt_token(const CString& tt_token) { tt_token_ = tt_token; }
+
+  CString success_url() const { return success_url_; }
+  void set_success_url(const CString& success_url) {
+    success_url_ = success_url;
+  }
+
+  CString error_url() const { return error_url_; }
+  void set_error_url(const CString& error_url) {
+    error_url_ = error_url;
+  }
+
+  BrowserType browser_type() const { return browser_type_; }
+  void set_browser_type(BrowserType type) {
+    browser_type_ = type;
+  }
+
+  bool terminate_all_browsers() const { return terminate_all_browsers_; }
+  void set_terminate_all_browsers(bool terminate_all) {
+    terminate_all_browsers_ = terminate_all;
+  }
+
+  SuccessfulInstallAction success_action() const { return success_action_; }
+  void set_success_action(SuccessfulInstallAction success_action) {
+    success_action_ = success_action;
+  }
+
+  CString version() const { return version_; }
+  void set_version(const CString& version) { version_ = version; }
+
+  CString GetInstallData(const CString& index) const {
+    InstallDataMap::const_iterator iter = install_data_.find(index);
+    if (iter == install_data_.end()) {
+      return CString();
+    }
+    return iter->second;
+  }
+  void SetInstallData(const CString& index, const CString& value) {
+    ASSERT1(install_data_.find(index) == install_data_.end());
+    install_data_[index] = value;
+  }
+
+ private:
+  CString url_;               // The url for the application installer.
+  int size_;                  // The size of the download.
+  CString hash_;              // The 160bit SHA1 hash of the downloaded file.
+  NeedsAdmin needs_admin_;    // If the application needs admin to install.
+  CString arguments_;         // Arguments for application installation.
+  GUID guid_;                 // Uniquely represents the application.
+  // Remove these 5 members when legacy support is removed.
+  CString app_name_;          // Application name for display.
+  CString language_;          // The language for this application.
+  GUID installation_id_;      // Uniquely represents this install.
+  CString ap_;                // ap value to be set in the registry.
+  BrowserType browser_type_;  // Browser to launch.
+
+  // The status of the response. There needs to be a protocol established
+  // between the server and client to determine what the action should be
+  // on downloading the application installer.
+  CString status_;
+
+  CString tt_token_;          // TT value to be set in the registry.
+  CString success_url_;       // URL to launch the browser on success.
+  CString error_url_;         // URL describing error.
+  bool terminate_all_browsers_;  // Whether to restart all browsers.
+  SuccessfulInstallAction success_action_;  // Action after install success.
+  CString version_;           // The version of the application itself.
+  InstallDataMap install_data_;  // Written to a file and passed as argument to
+                                 // app installer.
+};
+
+struct GuidComparer : public std::less<GUID> {
+  bool operator()(const GUID& lhs, const GUID& rhs) const {
+    CString lhs_guid_str = GuidToString(lhs);
+    CString rhs_guid_str = GuidToString(rhs);
+    return (_tcsicmp(lhs_guid_str, rhs_guid_str) < 0);
+  }
+};
+
+// Represent the list of requests and responses that are used to communicate
+// with the AU server.
+typedef std::map<GUID, UpdateResponseData, GuidComparer> UpdateResponseDatas;
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_UPDATE_RESPONSE_DATA_H__
+
diff --git a/goopdate/webplugin_utils.cc b/goopdate/webplugin_utils.cc
index 3d43ef6..551097e 100644
--- a/goopdate/webplugin_utils.cc
+++ b/goopdate/webplugin_utils.cc
@@ -1,227 +1,227 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/goopdate/webplugin_utils.h"

-

-#include "omaha/common/app_util.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system.h"

-#include "omaha/common/xml_utils.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource_manager.h"

-#include "omaha/net/browser_request.h"

-#include "omaha/net/cup_request.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/simple_request.h"

-

-namespace omaha {

-

-namespace webplugin_utils {

-

-HRESULT BuildOneClickRequestString(const CommandLineArgs& args,

-                                   CString* request_str) {

-  if (NULL == request_str) {

-    return E_INVALIDARG;

-  }

-

-  // If we're not /webplugin or the urldomain is empty, something's wrong.

-  if (args.mode != COMMANDLINE_MODE_WEBPLUGIN ||

-      args.webplugin_urldomain.IsEmpty()) {

-    return E_UNEXPECTED;

-  }

-

-  // TODO(omaha): Format() only handles up to 1024 characters.

-  const TCHAR* request_string_template = _T("?du=%s&args=%s");

-  CString request;

-

-  CString urldomain_escaped;

-  CString pluginargs_escaped;

-

-  StringEscape(args.webplugin_urldomain, false, &urldomain_escaped);

-  StringEscape(args.webplugin_args, false, &pluginargs_escaped);

-

-  request.Format(request_string_template,

-                 urldomain_escaped,

-                 pluginargs_escaped);

-

-  *request_str = request;

-  return S_OK;

-}

-

-// Need to verify we can load the resources required for the language the user

-// is requesting.  If for some reason the dll has been deleted on the machine,

-// then the /install instance of GoogleUpdate.exe will fail since it can't

-// load the resource dll.

-HRESULT VerifyResourceLanguage(const CString& webplugin_args) {

-  CString cmd_line;

-  cmd_line.Format(_T("gu.exe %s"), webplugin_args);

-  CommandLineArgs parsed_args;

-  HRESULT hr = ParseCommandLine(cmd_line, &parsed_args);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ParseCommandLine failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  bool is_machine = goopdate_utils::IsRunningFromOfficialGoopdateDir(true);

-  ResourceManager resource_manager(is_machine,

-                                   app_util::GetCurrentModuleDirectory());

-  hr = resource_manager.LoadResourceDll(parsed_args.extra.language);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[LoadResourceDll failed for lang][%s][0x%08x]"),

-                  parsed_args.extra.language, hr));

-    return GOOPDATE_E_ONECLICK_NO_LANGUAGE_RESOURCE;

-  }

-

-  return S_OK;

-}

-

-HRESULT BuildOneClickWorkerArgs(const CommandLineArgs& args,

-                                CString* oneclick_args) {

-  ASSERT1(oneclick_args);

-

-  // Since this is being called via WebPlugin only, we can rebuild the

-  // command line arguments from the valid params we can send on.

-  // For example, the web plugin will not send crash_cmd or debug_cmd

-  // or reg_server or unreg_server so we don't have to worry about those here.

-  CString cmd_line_args;

-  CommandLineArgs webplugin_cmdline_args;

-

-  // ParseCommandLine assumes the first argument is the program being run.

-  // Don't want to enforce that constraint on our callers, so we prepend with a

-  // fake exe name.

-  CString args_to_parse;

-  args_to_parse.Format(_T("%s %s"), kGoopdateFileName, args.webplugin_args);

-

-  // Parse the arguments we received as the second parameter to /webplugin.

-  HRESULT hr = ParseCommandLine(args_to_parse, &webplugin_cmdline_args);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Silent and other non-standard installs could be malicious. Prevent them.

-  if (webplugin_cmdline_args.mode != COMMANDLINE_MODE_INSTALL) {

-    return E_INVALIDARG;

-  }

-  if (webplugin_cmdline_args.is_silent_set ||

-      webplugin_cmdline_args.is_eula_required_set) {

-    return E_INVALIDARG;

-  }

-

-  CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL);

-  builder.set_extra_args(webplugin_cmdline_args.extra_args_str);

-

-  // We expect this value from the plugin.

-  ASSERT1(!args.install_source.IsEmpty());

-  if (args.install_source.IsEmpty()) {

-    return E_INVALIDARG;

-  }

-

-  builder.set_install_source(args.install_source);

-

-  *oneclick_args = builder.GetCommandLineArgs();

-

-  return S_OK;

-}

-

-HRESULT CopyGoopdateToTempDir(const CPath& current_goopdate_path,

-                              CPath* goopdate_temp_path) {

-  ASSERT1(goopdate_temp_path);

-

-  // Create a unique directory in the user's temp directory.

-  TCHAR pathbuf[MAX_PATH] = {0};

-  DWORD ret = ::GetTempPath(arraysize(pathbuf), pathbuf);

-  if (0 == ret) {

-    return HRESULTFromLastError();

-  }

-  if (ret >= arraysize(pathbuf)) {

-    return E_FAIL;

-  }

-

-  GUID guid = GUID_NULL;

-  HRESULT hr = ::CoCreateGuid(&guid);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString guid_str = GuidToString(guid);

-  CPath temp_path = pathbuf;

-  temp_path.Append(guid_str);

-  temp_path.Canonicalize();

-

-  hr = CreateDir(temp_path, NULL);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = File::CopyWildcards(current_goopdate_path, temp_path, _T("*.*"), true);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CORE_LOG(L2, (_T("[CopyGoopdateToTempDir][temp_path = %s]"), temp_path));

-  *goopdate_temp_path = temp_path;

-  return S_OK;

-}

-

-HRESULT DoOneClickInstall(const CommandLineArgs& args) {

-  CString cmd_line_args;

-  HRESULT hr = BuildOneClickWorkerArgs(args, &cmd_line_args);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[BuildOneClickWorkerArgs failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  CORE_LOG(L2, (_T("[DoOneClickInstall][cmd_line_args: %s]"), cmd_line_args));

-

-  // Check if we're running from the machine dir.

-  // If we're not, we must be running from user directory since OneClick only

-  // works against installed versions of Omaha.

-  CPath current_goopdate_path(app_util::GetCurrentModuleDirectory());

-  CPath goopdate_temp_path;

-  hr = CopyGoopdateToTempDir(current_goopdate_path, &goopdate_temp_path);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[CopyGoopdateToTempDir failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  CPath goopdate_temp_exe_path = goopdate_temp_path;

-  goopdate_temp_exe_path.Append(kGoopdateFileName);

-

-  // Launch goopdate again with the updated command line arguments.

-  hr = System::ShellExecuteProcess(goopdate_temp_exe_path,

-                                   cmd_line_args,

-                                   NULL,

-                                   NULL);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ShellExecuteProcess failed][%s][0x%08x]"),

-                  goopdate_temp_exe_path, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-}  // namespace webplugin_utils

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/goopdate/webplugin_utils.h"
+
+#include "omaha/common/app_util.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system.h"
+#include "omaha/common/xml_utils.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource_manager.h"
+#include "omaha/net/browser_request.h"
+#include "omaha/net/cup_request.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/simple_request.h"
+
+namespace omaha {
+
+namespace webplugin_utils {
+
+HRESULT BuildOneClickRequestString(const CommandLineArgs& args,
+                                   CString* request_str) {
+  if (NULL == request_str) {
+    return E_INVALIDARG;
+  }
+
+  // If we're not /webplugin or the urldomain is empty, something's wrong.
+  if (args.mode != COMMANDLINE_MODE_WEBPLUGIN ||
+      args.webplugin_urldomain.IsEmpty()) {
+    return E_UNEXPECTED;
+  }
+
+  // TODO(omaha): Format() only handles up to 1024 characters.
+  const TCHAR* request_string_template = _T("?du=%s&args=%s");
+  CString request;
+
+  CString urldomain_escaped;
+  CString pluginargs_escaped;
+
+  StringEscape(args.webplugin_urldomain, false, &urldomain_escaped);
+  StringEscape(args.webplugin_args, false, &pluginargs_escaped);
+
+  request.Format(request_string_template,
+                 urldomain_escaped,
+                 pluginargs_escaped);
+
+  *request_str = request;
+  return S_OK;
+}
+
+// Need to verify we can load the resources required for the language the user
+// is requesting.  If for some reason the dll has been deleted on the machine,
+// then the /install instance of GoogleUpdate.exe will fail since it can't
+// load the resource dll.
+HRESULT VerifyResourceLanguage(const CString& webplugin_args) {
+  CString cmd_line;
+  cmd_line.Format(_T("gu.exe %s"), webplugin_args);
+  CommandLineArgs parsed_args;
+  HRESULT hr = ParseCommandLine(cmd_line, &parsed_args);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ParseCommandLine failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  bool is_machine = goopdate_utils::IsRunningFromOfficialGoopdateDir(true);
+  ResourceManager resource_manager(is_machine,
+                                   app_util::GetCurrentModuleDirectory());
+  hr = resource_manager.LoadResourceDll(parsed_args.extra.language);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[LoadResourceDll failed for lang][%s][0x%08x]"),
+                  parsed_args.extra.language, hr));
+    return GOOPDATE_E_ONECLICK_NO_LANGUAGE_RESOURCE;
+  }
+
+  return S_OK;
+}
+
+HRESULT BuildOneClickWorkerArgs(const CommandLineArgs& args,
+                                CString* oneclick_args) {
+  ASSERT1(oneclick_args);
+
+  // Since this is being called via WebPlugin only, we can rebuild the
+  // command line arguments from the valid params we can send on.
+  // For example, the web plugin will not send crash_cmd or debug_cmd
+  // or reg_server or unreg_server so we don't have to worry about those here.
+  CString cmd_line_args;
+  CommandLineArgs webplugin_cmdline_args;
+
+  // ParseCommandLine assumes the first argument is the program being run.
+  // Don't want to enforce that constraint on our callers, so we prepend with a
+  // fake exe name.
+  CString args_to_parse;
+  args_to_parse.Format(_T("%s %s"), kGoopdateFileName, args.webplugin_args);
+
+  // Parse the arguments we received as the second parameter to /webplugin.
+  HRESULT hr = ParseCommandLine(args_to_parse, &webplugin_cmdline_args);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Silent and other non-standard installs could be malicious. Prevent them.
+  if (webplugin_cmdline_args.mode != COMMANDLINE_MODE_INSTALL) {
+    return E_INVALIDARG;
+  }
+  if (webplugin_cmdline_args.is_silent_set ||
+      webplugin_cmdline_args.is_eula_required_set) {
+    return E_INVALIDARG;
+  }
+
+  CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL);
+  builder.set_extra_args(webplugin_cmdline_args.extra_args_str);
+
+  // We expect this value from the plugin.
+  ASSERT1(!args.install_source.IsEmpty());
+  if (args.install_source.IsEmpty()) {
+    return E_INVALIDARG;
+  }
+
+  builder.set_install_source(args.install_source);
+
+  *oneclick_args = builder.GetCommandLineArgs();
+
+  return S_OK;
+}
+
+HRESULT CopyGoopdateToTempDir(const CPath& current_goopdate_path,
+                              CPath* goopdate_temp_path) {
+  ASSERT1(goopdate_temp_path);
+
+  // Create a unique directory in the user's temp directory.
+  TCHAR pathbuf[MAX_PATH] = {0};
+  DWORD ret = ::GetTempPath(arraysize(pathbuf), pathbuf);
+  if (0 == ret) {
+    return HRESULTFromLastError();
+  }
+  if (ret >= arraysize(pathbuf)) {
+    return E_FAIL;
+  }
+
+  GUID guid = GUID_NULL;
+  HRESULT hr = ::CoCreateGuid(&guid);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString guid_str = GuidToString(guid);
+  CPath temp_path = pathbuf;
+  temp_path.Append(guid_str);
+  temp_path.Canonicalize();
+
+  hr = CreateDir(temp_path, NULL);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = File::CopyWildcards(current_goopdate_path, temp_path, _T("*.*"), true);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CORE_LOG(L2, (_T("[CopyGoopdateToTempDir][temp_path = %s]"), temp_path));
+  *goopdate_temp_path = temp_path;
+  return S_OK;
+}
+
+HRESULT DoOneClickInstall(const CommandLineArgs& args) {
+  CString cmd_line_args;
+  HRESULT hr = BuildOneClickWorkerArgs(args, &cmd_line_args);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[BuildOneClickWorkerArgs failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  CORE_LOG(L2, (_T("[DoOneClickInstall][cmd_line_args: %s]"), cmd_line_args));
+
+  // Check if we're running from the machine dir.
+  // If we're not, we must be running from user directory since OneClick only
+  // works against installed versions of Omaha.
+  CPath current_goopdate_path(app_util::GetCurrentModuleDirectory());
+  CPath goopdate_temp_path;
+  hr = CopyGoopdateToTempDir(current_goopdate_path, &goopdate_temp_path);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[CopyGoopdateToTempDir failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  CPath goopdate_temp_exe_path = goopdate_temp_path;
+  goopdate_temp_exe_path.Append(kGoopdateFileName);
+
+  // Launch goopdate again with the updated command line arguments.
+  hr = System::ShellExecuteProcess(goopdate_temp_exe_path,
+                                   cmd_line_args,
+                                   NULL,
+                                   NULL);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ShellExecuteProcess failed][%s][0x%08x]"),
+                  goopdate_temp_exe_path, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+}  // namespace webplugin_utils
+
+}  // namespace omaha
+
diff --git a/goopdate/webplugin_utils.h b/goopdate/webplugin_utils.h
index 765217f..ea35146 100644
--- a/goopdate/webplugin_utils.h
+++ b/goopdate/webplugin_utils.h
@@ -1,53 +1,53 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_GOOPDATE_WEBPLUGIN_UTILS_H__

-#define OMAHA_GOOPDATE_WEBPLUGIN_UTILS_H__

-

-#include <windows.h>

-#include <atlpath.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/config_manager.h"

-

-namespace omaha {

-

-namespace webplugin_utils {

-

-// Verifies that the resource DLL we're going to load within googleupdate.exe is

-// available and loadable.

-HRESULT VerifyResourceLanguage(const CString& webplugin_args);

-

-// Copies required Goopdate files to a temp location before installing.

-HRESULT CopyGoopdateToTempDir(const CPath& current_goopdate_path,

-                              CPath* goopdate_temp_path);

-

-// Launches google_update.exe based on parameters sent with /webplugin.

-HRESULT DoOneClickInstall(const CommandLineArgs& args);

-

-// Creates request string for the webplugin URL check webservice call.

-HRESULT BuildOneClickRequestString(const CommandLineArgs& args,

-                                   CString* request_str);

-

-// Builds up the command line arguments to re-launch google_update.exe

-// when called with /pi.

-HRESULT BuildOneClickWorkerArgs(const CommandLineArgs& args, CString* args_out);

-

-}  // namespace webplugin_utils

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_WEBPLUGIN_UTILS_H__

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_GOOPDATE_WEBPLUGIN_UTILS_H__
+#define OMAHA_GOOPDATE_WEBPLUGIN_UTILS_H__
+
+#include <windows.h>
+#include <atlpath.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/config_manager.h"
+
+namespace omaha {
+
+namespace webplugin_utils {
+
+// Verifies that the resource DLL we're going to load within googleupdate.exe is
+// available and loadable.
+HRESULT VerifyResourceLanguage(const CString& webplugin_args);
+
+// Copies required Goopdate files to a temp location before installing.
+HRESULT CopyGoopdateToTempDir(const CPath& current_goopdate_path,
+                              CPath* goopdate_temp_path);
+
+// Launches google_update.exe based on parameters sent with /webplugin.
+HRESULT DoOneClickInstall(const CommandLineArgs& args);
+
+// Creates request string for the webplugin URL check webservice call.
+HRESULT BuildOneClickRequestString(const CommandLineArgs& args,
+                                   CString* request_str);
+
+// Builds up the command line arguments to re-launch google_update.exe
+// when called with /pi.
+HRESULT BuildOneClickWorkerArgs(const CommandLineArgs& args, CString* args_out);
+
+}  // namespace webplugin_utils
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_WEBPLUGIN_UTILS_H__
diff --git a/goopdate/webplugin_utils_unittest.cc b/goopdate/webplugin_utils_unittest.cc
index 59f482a..2b4d31a 100644
--- a/goopdate/webplugin_utils_unittest.cc
+++ b/goopdate/webplugin_utils_unittest.cc
@@ -1,164 +1,164 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/app_util.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/webplugin_utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace webplugin_utils {

-

-#define YOUTUBEUPLOADEREN_TAG \

-    _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&") \

-    _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")

-

-

-TEST(WebPluginUtilsTest, BuildOneClickRequestString_NullOutParam) {

-  CommandLineArgs args;

-  EXPECT_EQ(E_INVALIDARG, BuildOneClickRequestString(args, NULL));

-}

-

-TEST(WebPluginUtilsTest, BuildOneClickRequestString_WrongArgs) {

-  CommandLineArgs args;

-  CString request;

-  EXPECT_EQ(E_UNEXPECTED, BuildOneClickRequestString(args, &request));

-}

-

-TEST(WebPluginUtilsTest, BuildOneClickRequestString_NoUrlDomain) {

-  CommandLineArgs args;

-  CString request;

-

-  args.mode = COMMANDLINE_MODE_WEBPLUGIN;

-  EXPECT_EQ(E_UNEXPECTED, BuildOneClickRequestString(args, &request));

-}

-

-TEST(WebPluginUtilsTest, BuildOneClickRequestString_Valid) {

-  CommandLineArgs args;

-  CString request;

-

-  args.mode = COMMANDLINE_MODE_WEBPLUGIN;

-  args.webplugin_urldomain = _T("http://www.google.com/");

-  args.webplugin_args = _T("/install \"appguid=")

-      _T("{8A69D345-D564-463c-AFF1-A69D9E530F96}")

-      _T("&appname=Google Chrome&needsadmin=true&lang=en\"");

-  EXPECT_EQ(S_OK, BuildOneClickRequestString(args, &request));

-

-  EXPECT_STREQ(_T("?du=http://www.google.com/&args=/install%20")

-               _T("%22appguid=%7B8A69D345-D564-463c-AFF1-A69D9E530F96")

-               _T("%7D%26appname=Google%20Chrome%26needsadmin=true%26")

-               _T("lang=en%22"),

-               request);

-}

-

-TEST(WebPluginUtilsTest, BuildOneClickWorkerArgs_Valid) {

-  CommandLineArgs args;

-  CString oneclick_args;

-

-  args.install_source = _T("oneclick");

-  args.webplugin_args = _T("/install \"appguid=")

-      _T("{8A69D345-D564-463c-AFF1-A69D9E530F96}")

-      _T("&appname=Google Chrome&needsadmin=true&lang=en\"");

-  EXPECT_EQ(S_OK, BuildOneClickWorkerArgs(args, &oneclick_args));

-

-  EXPECT_STREQ(_T("/install ")

-               _T("\"appguid={8A69D345-D564-463c-AFF1-A69D9E530F96}")

-               _T("&appname=Google Chrome&needsadmin=true&lang=en\" ")

-               _T("/installsource oneclick"),

-               oneclick_args);

-}

-

-// This tests valid command line args that are not valid to be sent through

-// to google_update.exe (e.g. /install).

-TEST(WebPluginUtilsTest, BuildOneClickWorkerArgs_Invalid) {

-  CommandLineArgs args;

-  CString oneclick_args;

-

-  args.install_source = _T("oneclick");

-

-  args.webplugin_args = _T("/handoff ") YOUTUBEUPLOADEREN_TAG;

-  EXPECT_EQ(E_INVALIDARG, BuildOneClickWorkerArgs(args, &oneclick_args));

-

-  args.webplugin_args = _T("/regserver");

-  EXPECT_EQ(E_INVALIDARG, BuildOneClickWorkerArgs(args, &oneclick_args));

-

-  args.webplugin_args = _T("/unregserver");

-  EXPECT_EQ(E_INVALIDARG, BuildOneClickWorkerArgs(args, &oneclick_args));

-

-  args.webplugin_args = _T("/install ") YOUTUBEUPLOADEREN_TAG _T(" /silent");

-  EXPECT_EQ(E_INVALIDARG, BuildOneClickWorkerArgs(args, &oneclick_args));

-}

-

-TEST(WebPluginUtilsTest, CopyGoopdateToTempDir) {

-  CPath current_goopdate_path(app_util::GetCurrentModuleDirectory());

-  current_goopdate_path.Append(_T("unittest_support\\omaha_1.2.x\\"));

-  CPath goopdate_temp_path;

-  ASSERT_SUCCEEDED(CopyGoopdateToTempDir(current_goopdate_path,

-                                         &goopdate_temp_path));

-

-  std::vector<CString> files;

-  EXPECT_HRESULT_SUCCEEDED(FindFilesEx(goopdate_temp_path, _T("*.*"), &files));

-

-  EXPECT_EQ(3, files.size());

-

-  std::map<CString, int> files_map;

-  for (size_t file_index = 0; file_index < files.size(); ++file_index) {

-    files_map[files[file_index]] = 1;

-  }

-

-  EXPECT_TRUE(files_map.find(_T("GoogleUpdate.exe")) != files_map.end());

-  EXPECT_TRUE(files_map.find(_T("goopdate.dll")) != files_map.end());

-  EXPECT_TRUE(files_map.find(_T("goopdateres_en.dll")) != files_map.end());

-

-  EXPECT_HRESULT_SUCCEEDED(DeleteDirectory(goopdate_temp_path));

-}

-

-TEST(WebPluginUtilsTest, VerifyResourceLanguage_InvalidArgs) {

-  CString args = _T("/en");

-  EXPECT_FAILED(VerifyResourceLanguage(args));

-}

-

-TEST(WebPluginUtilsTest, VerifyResourceLanguage_LangOK) {

-  CString args = _T("/install \"appguid=")

-                 _T("{8A69D345-D564-463c-AFF1-A69D9E530F96}")

-                 _T("&appname=Google Chrome&needsadmin=true&lang=en\"");

-  EXPECT_SUCCEEDED(VerifyResourceLanguage(args));

-}

-

-TEST(WebPluginUtilsTest, VerifyResourceLanguage_LangNotFound) {

-  CString args = _T("/install \"appguid=")

-                 _T("{8A69D345-D564-463c-AFF1-A69D9E530F96}")

-                 _T("&appname=Google Chrome&needsadmin=true&lang=en\"");

-

-  CPath path_orig(app_util::GetCurrentModuleDirectory());

-  path_orig.Append(_T("goopdateres_en.dll"));

-  CPath path_moved(app_util::GetCurrentModuleDirectory());

-  path_moved.Append(_T("goopdateres_en_moved.dll"));

-

-  EXPECT_SUCCEEDED(File::Move(path_orig, path_moved, true));

-  EXPECT_EQ(GOOPDATE_E_ONECLICK_NO_LANGUAGE_RESOURCE,

-            VerifyResourceLanguage(args));

-  EXPECT_SUCCEEDED(File::Move(path_moved, path_orig, true));

-}

-

-}  // namespace webplugin_utils

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/app_util.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/webplugin_utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace webplugin_utils {
+
+#define YOUTUBEUPLOADEREN_TAG \
+    _T("\"appguid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}&") \
+    _T("appname=YouTubeUploader&needsadmin=False&lang=en\"")
+
+
+TEST(WebPluginUtilsTest, BuildOneClickRequestString_NullOutParam) {
+  CommandLineArgs args;
+  EXPECT_EQ(E_INVALIDARG, BuildOneClickRequestString(args, NULL));
+}
+
+TEST(WebPluginUtilsTest, BuildOneClickRequestString_WrongArgs) {
+  CommandLineArgs args;
+  CString request;
+  EXPECT_EQ(E_UNEXPECTED, BuildOneClickRequestString(args, &request));
+}
+
+TEST(WebPluginUtilsTest, BuildOneClickRequestString_NoUrlDomain) {
+  CommandLineArgs args;
+  CString request;
+
+  args.mode = COMMANDLINE_MODE_WEBPLUGIN;
+  EXPECT_EQ(E_UNEXPECTED, BuildOneClickRequestString(args, &request));
+}
+
+TEST(WebPluginUtilsTest, BuildOneClickRequestString_Valid) {
+  CommandLineArgs args;
+  CString request;
+
+  args.mode = COMMANDLINE_MODE_WEBPLUGIN;
+  args.webplugin_urldomain = _T("http://www.google.com/");
+  args.webplugin_args = _T("/install \"appguid=")
+      _T("{8A69D345-D564-463c-AFF1-A69D9E530F96}")
+      _T("&appname=Google Chrome&needsadmin=true&lang=en\"");
+  EXPECT_EQ(S_OK, BuildOneClickRequestString(args, &request));
+
+  EXPECT_STREQ(_T("?du=http://www.google.com/&args=/install%20")
+               _T("%22appguid=%7B8A69D345-D564-463c-AFF1-A69D9E530F96")
+               _T("%7D%26appname=Google%20Chrome%26needsadmin=true%26")
+               _T("lang=en%22"),
+               request);
+}
+
+TEST(WebPluginUtilsTest, BuildOneClickWorkerArgs_Valid) {
+  CommandLineArgs args;
+  CString oneclick_args;
+
+  args.install_source = _T("oneclick");
+  args.webplugin_args = _T("/install \"appguid=")
+      _T("{8A69D345-D564-463c-AFF1-A69D9E530F96}")
+      _T("&appname=Google Chrome&needsadmin=true&lang=en\"");
+  EXPECT_EQ(S_OK, BuildOneClickWorkerArgs(args, &oneclick_args));
+
+  EXPECT_STREQ(_T("/install ")
+               _T("\"appguid={8A69D345-D564-463c-AFF1-A69D9E530F96}")
+               _T("&appname=Google Chrome&needsadmin=true&lang=en\" ")
+               _T("/installsource oneclick"),
+               oneclick_args);
+}
+
+// This tests valid command line args that are not valid to be sent through
+// to google_update.exe (e.g. /install).
+TEST(WebPluginUtilsTest, BuildOneClickWorkerArgs_Invalid) {
+  CommandLineArgs args;
+  CString oneclick_args;
+
+  args.install_source = _T("oneclick");
+
+  args.webplugin_args = _T("/handoff ") YOUTUBEUPLOADEREN_TAG;
+  EXPECT_EQ(E_INVALIDARG, BuildOneClickWorkerArgs(args, &oneclick_args));
+
+  args.webplugin_args = _T("/regserver");
+  EXPECT_EQ(E_INVALIDARG, BuildOneClickWorkerArgs(args, &oneclick_args));
+
+  args.webplugin_args = _T("/unregserver");
+  EXPECT_EQ(E_INVALIDARG, BuildOneClickWorkerArgs(args, &oneclick_args));
+
+  args.webplugin_args = _T("/install ") YOUTUBEUPLOADEREN_TAG _T(" /silent");
+  EXPECT_EQ(E_INVALIDARG, BuildOneClickWorkerArgs(args, &oneclick_args));
+}
+
+TEST(WebPluginUtilsTest, CopyGoopdateToTempDir) {
+  CPath current_goopdate_path(app_util::GetCurrentModuleDirectory());
+  current_goopdate_path.Append(_T("unittest_support\\omaha_1.2.x\\"));
+  CPath goopdate_temp_path;
+  ASSERT_SUCCEEDED(CopyGoopdateToTempDir(current_goopdate_path,
+                                         &goopdate_temp_path));
+
+  std::vector<CString> files;
+  EXPECT_HRESULT_SUCCEEDED(FindFilesEx(goopdate_temp_path, _T("*.*"), &files));
+
+  EXPECT_EQ(3, files.size());
+
+  std::map<CString, int> files_map;
+  for (size_t file_index = 0; file_index < files.size(); ++file_index) {
+    files_map[files[file_index]] = 1;
+  }
+
+  EXPECT_TRUE(files_map.find(_T("GoogleUpdate.exe")) != files_map.end());
+  EXPECT_TRUE(files_map.find(_T("goopdate.dll")) != files_map.end());
+  EXPECT_TRUE(files_map.find(_T("goopdateres_en.dll")) != files_map.end());
+
+  EXPECT_HRESULT_SUCCEEDED(DeleteDirectory(goopdate_temp_path));
+}
+
+TEST(WebPluginUtilsTest, VerifyResourceLanguage_InvalidArgs) {
+  CString args = _T("/en");
+  EXPECT_FAILED(VerifyResourceLanguage(args));
+}
+
+TEST(WebPluginUtilsTest, VerifyResourceLanguage_LangOK) {
+  CString args = _T("/install \"appguid=")
+                 _T("{8A69D345-D564-463c-AFF1-A69D9E530F96}")
+                 _T("&appname=Google Chrome&needsadmin=true&lang=en\"");
+  EXPECT_SUCCEEDED(VerifyResourceLanguage(args));
+}
+
+TEST(WebPluginUtilsTest, VerifyResourceLanguage_LangNotFound) {
+  CString args = _T("/install \"appguid=")
+                 _T("{8A69D345-D564-463c-AFF1-A69D9E530F96}")
+                 _T("&appname=Google Chrome&needsadmin=true&lang=en\"");
+
+  CPath path_orig(app_util::GetCurrentModuleDirectory());
+  path_orig.Append(_T("goopdateres_en.dll"));
+  CPath path_moved(app_util::GetCurrentModuleDirectory());
+  path_moved.Append(_T("goopdateres_en_moved.dll"));
+
+  EXPECT_SUCCEEDED(File::Move(path_orig, path_moved, true));
+  EXPECT_EQ(GOOPDATE_E_ONECLICK_NO_LANGUAGE_RESOURCE,
+            VerifyResourceLanguage(args));
+  EXPECT_SUCCEEDED(File::Move(path_moved, path_orig, true));
+}
+
+}  // namespace webplugin_utils
+
+}  // namespace omaha
+
diff --git a/hammer.bat b/hammer.bat
index 39db402..2900563 100644
--- a/hammer.bat
+++ b/hammer.bat
@@ -1,2 +1,2 @@
-@call %SCT_DIR%\hammer.bat %*

-

+@call %SCT_DIR%\hammer.bat %*
+
diff --git a/installers/build.scons b/installers/build.scons
index 57c8fbd..2dca0c1 100644
--- a/installers/build.scons
+++ b/installers/build.scons
@@ -1,226 +1,226 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-import codecs

-import os

-import re

-import string

-

-from installers import build_metainstaller

-

-_RECOVERY_MARKUP_DLL = 'recovery_markup.dll'

-

-_CLICKONCE_DEPLOY_DIR = '$TARGET_ROOT/clickonce_deployment'

-

-# This will be of the form 'GoogleInstaller_en.application'.

-def _GetClickOnceDeploymentName(language):

-  return 'GoogleInstaller_%s.application' % (language)

-

-# Generate a ClickOnce deployment manifest personalized with the localized

-# display name of 'Google Installer'.

-def _GenerateDeploymentForOneLanguage(language):

-  clickonce_deployment_name = _GetClickOnceDeploymentName(language)

-

-  v = env['product_version'][0]

-  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-  clickonce_manifest_name = 'clickonce_bootstrap.exe.manifest'

-  clickonce_manifest = '%s/%s' % (_CLICKONCE_DEPLOY_DIR,

-                                  clickonce_manifest_name)

-

-  # Generate the deployment manifest with a dummy name of 'xxxXXXxxx'. The

-  # Python commands module does not work with Unicode strings, so we will

-  # substitute the name in the add_trusturlparams_and_name_command below.

-  generate_deploy_manifest_command = (

-      '@mage -New Deployment -Install false -ToFile $TARGET -Name xxxXXXxxx'

-      ' -Version %s -Processor x86 -AppManifest $SOURCE -AppCodeBase %s' %

-      (version_string, clickonce_manifest_name))

-

-  # Have to set up a clear chain of source->target1->target2->target3->etc so

-  # that declarative Hammer will know the order in which to run each command.

-  clickonce_target_1 = env.Command(

-      target=clickonce_deployment_name + '.base',

-      source=clickonce_manifest,

-      action=generate_deploy_manifest_command,

-  )

-

-  # Get the localized 'Google Installer' string.

-  mi_generated_res = (

-      '$MAIN_DIR/mi_exe_stub/mi_generated_resources_%s.rc' % language)

-  f_in = codecs.open(env.File(mi_generated_res).abspath, 'r', 'utf16')

-  mi_resource_contents = f_in.read()

-  f_in.close()

-

-  # index() will throw and abort the build if there is no match.

-  display_name_start = (

-      mi_resource_contents.index('IDS_GENERIC_INSTALLER_DISPLAY_NAME'))

-  display_name_start = mi_resource_contents.index('"', display_name_start)

-  display_name_end = mi_resource_contents.index('"', display_name_start + 1)

-  display_name = mi_resource_contents[display_name_start:display_name_end + 1]

-

-  # display_name is utf8 encoded to allow the commands and the default codec to

-  # pass it through.

-  display_name = display_name.encode('utf8')

-

-  # mage.exe does not provide a way to add the trustURLParameters attribute to

-  # an application manifest. This script fills that gap. It also adds in the

-  # localized display name, to get around issues with the Python commands

-  # module.

-  add_trusturlparams_and_name_command = (

-      '@python %s --manifest_file=$SOURCE --output_file=$TARGET --display_name='

-      '%s' % (env.File('$MAIN_DIR/clickonce/add_trusturlparams.py').abspath,

-      display_name))

-

-  # This is the next step in the target chain

-  clickonce_target_2 = env.Command(

-      target=clickonce_deployment_name + '.unsigned',

-      source=clickonce_target_1,

-      action=add_trusturlparams_and_name_command,

-  )

-

-  # Sign the deployment manifest.

-  sign_manifest_cmd =('@mage -Sign $SOURCE -ToFile $TARGET -TimestampUri '

-                      'http://timestamp.verisign.com/scripts/timstamp.dll ')

-

-  if env.Bit('build_server'):

-    sign_manifest_cmd += '-CertHash fe5008fe0da7a2033816752d6eafe95214f5a7e1'

-  else:

-    sign_manifest_cmd += '-CertFile %s -Password %s' % (

-        GetOption('authenticode_file'), GetOption('authenticode_password'))

-

-  # This will be of the form

-  # 'scons-out\dbg-win\clickonce_deployment\GoogleInstaller_en.application'.

-  sign_target = env.Command(

-      target='%s/%s' % (_CLICKONCE_DEPLOY_DIR, clickonce_deployment_name),

-      source=clickonce_target_2,

-      action=sign_manifest_cmd

-  )

-

-

-

-def _BuildSetup(is_repair = False):

-  # Build the meta-installer for each version.

-  PRODUCT_NAME = 'GoogleUpdate'

-  first = True

-  for v in env['product_version']:

-    if first:

-      first = False

-      prefix = ''

-    else:

-      prefix = 'TEST_'

-

-    source_binary = '$OBJ_ROOT/mi_exe_stub/%smi_exe_stub.exe' % (prefix)

-

-    if is_repair:

-      _BuildSetupRepairVersion(source_binary, PRODUCT_NAME, prefix)

-    else:

-      _BuildSetupVersion(source_binary, PRODUCT_NAME, prefix)

-

-

-

-def _BuildSetupRepairVersion(source_binary, product_name, prefix = ''):

-  # Build the target setup executable by merging the empty metafile

-  # with the resource dll built earlier

-  merged_output = env.Command(

-      target='%smi_exe_stub_repair.exe' % (prefix),

-      source=[source_binary, '$OBJ_ROOT/installers/' + _RECOVERY_MARKUP_DLL],

-      action='@$MAIN_DIR/tools/resmerge --copyappend $SOURCES $TARGET',

-  )

-

-  build_metainstaller.BuildMetaInstaller(

-      env=env,

-      target_name='%s%sSetup_repair.exe' % (prefix, product_name),

-      empty_metainstaller_path=merged_output,

-      google_update_files_path='$STAGING_DIR',

-      prefix = prefix,

-      suffix = '_repair',

-      additional_payload_contents = [

-          '$OBJ_ROOT/recovery/repair_exe/msp/GoogleUpdateHelperPatch.msp',

-          ],

-  )

-

-

-

-def _BuildSetupVersion(source_binary, product_name, prefix = ''):

-  target_name = '%s%sSetup.exe' % (prefix, product_name)

-

-  build_metainstaller.BuildMetaInstaller(

-      env=env,

-      target_name=target_name,

-      empty_metainstaller_path=source_binary,

-      google_update_files_path='$STAGING_DIR',

-      prefix=prefix

-  )

-

-  # Generate the i18n ClickOnce deployment manifest for languages that we

-  # support.

-  if env.Bit('all') or 'OMAHA_BUILD_CLICKONCE' in os.environ.keys():

-    for language in env['languages']:

-      _GenerateDeploymentForOneLanguage(language)

-      

-    # zh-HK needs a deployment file, but it is not in env['languages'] and there

-    # is no mi_generated_resources_zh-HK.rc file. The few translations are

-    # inherited from zh-TW, and there are no language code-specific values in

-    # the deployment file, so just copy the zh-TW file to zh-HK.

-    env.Command(

-        target='%s/%s' % (_CLICKONCE_DEPLOY_DIR,

-                          _GetClickOnceDeploymentName('zh-HK')),

-        source='%s/%s' % (_CLICKONCE_DEPLOY_DIR,

-                          _GetClickOnceDeploymentName('zh-TW')),

-        action='@copy /y $SOURCES $TARGET'

-    )

-

-if not env.Bit('official_installers'):

-  # The logic:

-  # - Set OMAHA_BUILD_TWO_VERSIONS environment variable to create the Test_

-  #   versions of the meta-installers, which can be used to test over-installs

-  #   and updates.

-  #

-  # Legacy Note:

-  # QA_* meta-installers are not longer being produced by the build.

-  # OMAHA_BUILD_ALLSETUPS is no longer being used.

-

-  # Build the normal tagged installers.

-  _BuildSetup()

-

-  env.Replicate(

-      target=[

-          '$TARGET_ROOT/clickonce_deployment/bin/',

-          '$STAGING_DIR',

-          ],

-      source='$OBJ_ROOT/installers/GoogleUpdateSetup.exe',

-  )

-

-  # Build the repair installer.

-  _BuildSetup(is_repair = True)

-

-  # Build a resource DLL containing the recovery markup resource.

-  dll_env = env.Clone(COMPONENT_STATIC=False)

-  dll_env['LINKFLAGS'] += ['/noentry']

-

-  dll_inputs = [

-      '../installers/resource_only_dll.def',

-      dll_env.RES('recovery_markup.res',

-                  '$MAIN_DIR/recovery/recovery_markup.rc')

-      ]

-

-  dll_env.ComponentLibrary(_RECOVERY_MARKUP_DLL, dll_inputs)

-

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+import codecs
+import os
+import re
+import string
+
+from installers import build_metainstaller
+
+_RECOVERY_MARKUP_DLL = 'recovery_markup.dll'
+
+_CLICKONCE_DEPLOY_DIR = '$TARGET_ROOT/clickonce_deployment'
+
+# This will be of the form 'GoogleInstaller_en.application'.
+def _GetClickOnceDeploymentName(language):
+  return 'GoogleInstaller_%s.application' % (language)
+
+# Generate a ClickOnce deployment manifest personalized with the localized
+# display name of 'Google Installer'.
+def _GenerateDeploymentForOneLanguage(language):
+  clickonce_deployment_name = _GetClickOnceDeploymentName(language)
+
+  v = env['product_version'][0]
+  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+  clickonce_manifest_name = 'clickonce_bootstrap.exe.manifest'
+  clickonce_manifest = '%s/%s' % (_CLICKONCE_DEPLOY_DIR,
+                                  clickonce_manifest_name)
+
+  # Generate the deployment manifest with a dummy name of 'xxxXXXxxx'. The
+  # Python commands module does not work with Unicode strings, so we will
+  # substitute the name in the add_trusturlparams_and_name_command below.
+  generate_deploy_manifest_command = (
+      '@mage -New Deployment -Install false -ToFile $TARGET -Name xxxXXXxxx'
+      ' -Version %s -Processor x86 -AppManifest $SOURCE -AppCodeBase %s' %
+      (version_string, clickonce_manifest_name))
+
+  # Have to set up a clear chain of source->target1->target2->target3->etc so
+  # that declarative Hammer will know the order in which to run each command.
+  clickonce_target_1 = env.Command(
+      target=clickonce_deployment_name + '.base',
+      source=clickonce_manifest,
+      action=generate_deploy_manifest_command,
+  )
+
+  # Get the localized 'Google Installer' string.
+  mi_generated_res = (
+      '$MAIN_DIR/mi_exe_stub/mi_generated_resources_%s.rc' % language)
+  f_in = codecs.open(env.File(mi_generated_res).abspath, 'r', 'utf16')
+  mi_resource_contents = f_in.read()
+  f_in.close()
+
+  # index() will throw and abort the build if there is no match.
+  display_name_start = (
+      mi_resource_contents.index('IDS_GENERIC_INSTALLER_DISPLAY_NAME'))
+  display_name_start = mi_resource_contents.index('"', display_name_start)
+  display_name_end = mi_resource_contents.index('"', display_name_start + 1)
+  display_name = mi_resource_contents[display_name_start:display_name_end + 1]
+
+  # display_name is utf8 encoded to allow the commands and the default codec to
+  # pass it through.
+  display_name = display_name.encode('utf8')
+
+  # mage.exe does not provide a way to add the trustURLParameters attribute to
+  # an application manifest. This script fills that gap. It also adds in the
+  # localized display name, to get around issues with the Python commands
+  # module.
+  add_trusturlparams_and_name_command = (
+      '@python %s --manifest_file=$SOURCE --output_file=$TARGET --display_name='
+      '%s' % (env.File('$MAIN_DIR/clickonce/add_trusturlparams.py').abspath,
+      display_name))
+
+  # This is the next step in the target chain
+  clickonce_target_2 = env.Command(
+      target=clickonce_deployment_name + '.unsigned',
+      source=clickonce_target_1,
+      action=add_trusturlparams_and_name_command,
+  )
+
+  # Sign the deployment manifest.
+  sign_manifest_cmd =('@mage -Sign $SOURCE -ToFile $TARGET -TimestampUri '
+                      'http://timestamp.verisign.com/scripts/timstamp.dll ')
+
+  if env.Bit('build_server'):
+    sign_manifest_cmd += '-CertHash fe5008fe0da7a2033816752d6eafe95214f5a7e1'
+  else:
+    sign_manifest_cmd += '-CertFile %s -Password %s' % (
+        GetOption('authenticode_file'), GetOption('authenticode_password'))
+
+  # This will be of the form
+  # 'scons-out\dbg-win\clickonce_deployment\GoogleInstaller_en.application'.
+  sign_target = env.Command(
+      target='%s/%s' % (_CLICKONCE_DEPLOY_DIR, clickonce_deployment_name),
+      source=clickonce_target_2,
+      action=sign_manifest_cmd
+  )
+
+
+
+def _BuildSetup(is_repair = False):
+  # Build the meta-installer for each version.
+  PRODUCT_NAME = 'GoogleUpdate'
+  first = True
+  for v in env['product_version']:
+    if first:
+      first = False
+      prefix = ''
+    else:
+      prefix = 'TEST_'
+
+    source_binary = '$OBJ_ROOT/mi_exe_stub/%smi_exe_stub.exe' % (prefix)
+
+    if is_repair:
+      _BuildSetupRepairVersion(source_binary, PRODUCT_NAME, prefix)
+    else:
+      _BuildSetupVersion(source_binary, PRODUCT_NAME, prefix)
+
+
+
+def _BuildSetupRepairVersion(source_binary, product_name, prefix = ''):
+  # Build the target setup executable by merging the empty metafile
+  # with the resource dll built earlier
+  merged_output = env.Command(
+      target='%smi_exe_stub_repair.exe' % (prefix),
+      source=[source_binary, '$OBJ_ROOT/installers/' + _RECOVERY_MARKUP_DLL],
+      action='@$MAIN_DIR/tools/resmerge --copyappend $SOURCES $TARGET',
+  )
+
+  build_metainstaller.BuildMetaInstaller(
+      env=env,
+      target_name='%s%sSetup_repair.exe' % (prefix, product_name),
+      empty_metainstaller_path=merged_output,
+      google_update_files_path='$STAGING_DIR',
+      prefix = prefix,
+      suffix = '_repair',
+      additional_payload_contents = [
+          '$OBJ_ROOT/recovery/repair_exe/msp/GoogleUpdateHelperPatch.msp',
+          ],
+  )
+
+
+
+def _BuildSetupVersion(source_binary, product_name, prefix = ''):
+  target_name = '%s%sSetup.exe' % (prefix, product_name)
+
+  build_metainstaller.BuildMetaInstaller(
+      env=env,
+      target_name=target_name,
+      empty_metainstaller_path=source_binary,
+      google_update_files_path='$STAGING_DIR',
+      prefix=prefix
+  )
+
+  # Generate the i18n ClickOnce deployment manifest for languages that we
+  # support.
+  if env.Bit('all') or 'OMAHA_BUILD_CLICKONCE' in os.environ.keys():
+    for language in env['languages']:
+      _GenerateDeploymentForOneLanguage(language)
+      
+    # zh-HK needs a deployment file, but it is not in env['languages'] and there
+    # is no mi_generated_resources_zh-HK.rc file. The few translations are
+    # inherited from zh-TW, and there are no language code-specific values in
+    # the deployment file, so just copy the zh-TW file to zh-HK.
+    env.Command(
+        target='%s/%s' % (_CLICKONCE_DEPLOY_DIR,
+                          _GetClickOnceDeploymentName('zh-HK')),
+        source='%s/%s' % (_CLICKONCE_DEPLOY_DIR,
+                          _GetClickOnceDeploymentName('zh-TW')),
+        action='@copy /y $SOURCES $TARGET'
+    )
+
+if not env.Bit('official_installers'):
+  # The logic:
+  # - Set OMAHA_BUILD_TWO_VERSIONS environment variable to create the Test_
+  #   versions of the meta-installers, which can be used to test over-installs
+  #   and updates.
+  #
+  # Legacy Note:
+  # QA_* meta-installers are not longer being produced by the build.
+  # OMAHA_BUILD_ALLSETUPS is no longer being used.
+
+  # Build the normal tagged installers.
+  _BuildSetup()
+
+  env.Replicate(
+      target=[
+          '$TARGET_ROOT/clickonce_deployment/bin/',
+          '$STAGING_DIR',
+          ],
+      source='$OBJ_ROOT/installers/GoogleUpdateSetup.exe',
+  )
+
+  # Build the repair installer.
+  _BuildSetup(is_repair = True)
+
+  # Build a resource DLL containing the recovery markup resource.
+  dll_env = env.Clone(COMPONENT_STATIC=False)
+  dll_env['LINKFLAGS'] += ['/noentry']
+
+  dll_inputs = [
+      '../installers/resource_only_dll.def',
+      dll_env.RES('recovery_markup.res',
+                  '$MAIN_DIR/recovery/recovery_markup.rc')
+      ]
+
+  dll_env.ComponentLibrary(_RECOVERY_MARKUP_DLL, dll_inputs)
+
+
diff --git a/installers/build_metainstaller.py b/installers/build_metainstaller.py
index b5ecf6e..001e999 100644
--- a/installers/build_metainstaller.py
+++ b/installers/build_metainstaller.py
@@ -1,164 +1,164 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-"""Build a meta-installer for Omaha's client installations.

-

-  The only function in this module creates an Omaha meta-installer, which is

-  an executable whose only job is to extract its payload (the actual installer

-  executable and a number of resource dlls), then launch the dropped installer

-  to finish the installation.

-

-  BuildMetaInstaller(): Build a meta-installer.

-"""

-

-from installers import get_payload_files

-

-

-def BuildMetaInstaller(env,

-                       target_name,

-                       empty_metainstaller_path,

-                       google_update_files_path,

-                       prefix = '',

-                       suffix = '',

-                       additional_payload_contents = None,

-                       additional_payload_contents_dependencies = None):

-  """Build a meta-installer.

-

-    Builds a full meta-installer, which is a meta-installer containing a full

-    list of required files (the payload), ie. language resourse dlls, installer

-    executables, etc.

-

-  Args:

-    env: environment to build with

-    target_name: name to use for the target executable

-    empty_metainstaller_path: path to the base (empty) meta-installer executable

-    google_update_files_path: path to the resource dlls to build into the

-        target executable

-    prefix: target file name prefix, used to distinguish different targets

-    suffix: target file name suffix, used to distinguish different targets

-    additional_payload_contents: any additional resources to build into the

-        executable, beyond the normal payload files

-    additional_payload_contents_dependencies: extra dependencies to be used to

-        ensure the executable is rebuilt when required

-

-  Returns:

-    Nothing.

-

-  Raises:

-    Nothing.

-  """

-

-  if additional_payload_contents is None:

-    additional_payload_contents = []

-

-  if additional_payload_contents_dependencies is None:

-    additional_payload_contents_dependencies = []

-

-  # Payload .tar.lzma

-  tarball_filename = '%spayload%s.tar' % (prefix, suffix)

-  payload_filename = tarball_filename + '.lzma'

-

-  # Collect a list of all the files to include in the payload

-  payload_file_names = get_payload_files.GetListOfPayloadFiles(

-      prefix,

-      env['ACTIVEX_FILENAME'],

-      env['BHO_FILENAME'],

-      env['languages'],

-      env['product_version'][0],

-  )

-

-  payload_contents = [google_update_files_path + '/' + file_name

-                      for file_name in payload_file_names]

-  payload_contents += additional_payload_contents

-

-  # Create the tarball

-  tarball_output = env.Command(

-      target=tarball_filename,    # Archive filename

-      source=payload_contents,    # List of files to include in tarball

-      action='python.exe %s -o $TARGET $SOURCES' % (

-          env.File('$MAIN_DIR/installers/generate_tarball.py').abspath),

-  )

-

-  # Add potentially hidden dependencies

-  if additional_payload_contents and additional_payload_contents_dependencies:

-    env.Depends(tarball_output, additional_payload_contents)

-    env.Depends(tarball_output, additional_payload_contents_dependencies)

-

-  # Compress the tarball

-  lzma_output = env.Command(

-      target=payload_filename,

-      source=tarball_output,

-      action='$MAIN_DIR/third_party/lzma/lzma.exe e $SOURCES $TARGET',

-  )

-

-  # Construct the resource generation script

-  manifest_path = '$MAIN_DIR/installers/installers.manifest'

-  res_command = 'python.exe %s -i %s -o $TARGET -p $SOURCES -m %s -r %s' % (

-      env.File('$MAIN_DIR/installers/generate_resource_script.py').abspath,

-      env.File('$MAIN_DIR/installers/resource.rc.in').abspath,

-      env.File(manifest_path).abspath,

-      env.File('$MAIN_DIR/installers/resource.h').abspath

-      )

-

-  # Generate the .rc file

-  rc_output = env.Command(

-      target='%sresource%s.rc' % (prefix, suffix),

-      source=lzma_output,

-      action=res_command,

-  )

-

-  # .res intermediate file

-  res_file = env.RES(rc_output)

-

-  # For some reason, RES() does not cause the .res file to depend on .rc input.

-  # It also does not detect the dependencies in the .rc file.

-  # This does not cause a rebuild for rarely changing files in res_command.

-  env.Depends(res_file, [rc_output, manifest_path, lzma_output])

-

-  # Resource DLL

-  dll_env = env.Clone(COMPONENT_STATIC=False)

-  dll_env['LINKFLAGS'] += ['/noentry']

-

-  dll_inputs = [

-      '$MAIN_DIR/installers/resource_only_dll.def',

-      res_file

-      ]

-

-  dll_output = dll_env.ComponentLibrary(

-      lib_name='%spayload%s.dll' % (prefix, suffix),

-      source=dll_inputs,

-  )

-

-  # Get only the dll itself from the output (ie. ignore .pdb, etc.)

-  dll_output_name = [f for f in dll_output if f.suffix == '.dll']

-

-  # Build the target setup executable by merging the empty metafile

-  # with the resource dll built above

-  merged_output = env.Command(

-      target='unsigned_' + target_name,

-      source=[empty_metainstaller_path, dll_output_name],

-      action='$MAIN_DIR/tools/resmerge --copyappend $SOURCES $TARGET'

-  )

-

-  signed_exe = env.SignedBinary(

-      target=target_name,

-      source=merged_output,

-  )

-

-  env.Replicate('$STAGING_DIR', signed_exe)

-

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+"""Build a meta-installer for Omaha's client installations.
+
+  The only function in this module creates an Omaha meta-installer, which is
+  an executable whose only job is to extract its payload (the actual installer
+  executable and a number of resource dlls), then launch the dropped installer
+  to finish the installation.
+
+  BuildMetaInstaller(): Build a meta-installer.
+"""
+
+from installers import get_payload_files
+
+
+def BuildMetaInstaller(env,
+                       target_name,
+                       empty_metainstaller_path,
+                       google_update_files_path,
+                       prefix = '',
+                       suffix = '',
+                       additional_payload_contents = None,
+                       additional_payload_contents_dependencies = None):
+  """Build a meta-installer.
+
+    Builds a full meta-installer, which is a meta-installer containing a full
+    list of required files (the payload), ie. language resourse dlls, installer
+    executables, etc.
+
+  Args:
+    env: environment to build with
+    target_name: name to use for the target executable
+    empty_metainstaller_path: path to the base (empty) meta-installer executable
+    google_update_files_path: path to the resource dlls to build into the
+        target executable
+    prefix: target file name prefix, used to distinguish different targets
+    suffix: target file name suffix, used to distinguish different targets
+    additional_payload_contents: any additional resources to build into the
+        executable, beyond the normal payload files
+    additional_payload_contents_dependencies: extra dependencies to be used to
+        ensure the executable is rebuilt when required
+
+  Returns:
+    Nothing.
+
+  Raises:
+    Nothing.
+  """
+
+  if additional_payload_contents is None:
+    additional_payload_contents = []
+
+  if additional_payload_contents_dependencies is None:
+    additional_payload_contents_dependencies = []
+
+  # Payload .tar.lzma
+  tarball_filename = '%spayload%s.tar' % (prefix, suffix)
+  payload_filename = tarball_filename + '.lzma'
+
+  # Collect a list of all the files to include in the payload
+  payload_file_names = get_payload_files.GetListOfPayloadFiles(
+      prefix,
+      env['ACTIVEX_FILENAME'],
+      env['BHO_FILENAME'],
+      env['languages'],
+      env['product_version'][0],
+  )
+
+  payload_contents = [google_update_files_path + '/' + file_name
+                      for file_name in payload_file_names]
+  payload_contents += additional_payload_contents
+
+  # Create the tarball
+  tarball_output = env.Command(
+      target=tarball_filename,    # Archive filename
+      source=payload_contents,    # List of files to include in tarball
+      action='python.exe %s -o $TARGET $SOURCES' % (
+          env.File('$MAIN_DIR/installers/generate_tarball.py').abspath),
+  )
+
+  # Add potentially hidden dependencies
+  if additional_payload_contents and additional_payload_contents_dependencies:
+    env.Depends(tarball_output, additional_payload_contents)
+    env.Depends(tarball_output, additional_payload_contents_dependencies)
+
+  # Compress the tarball
+  lzma_output = env.Command(
+      target=payload_filename,
+      source=tarball_output,
+      action='$MAIN_DIR/third_party/lzma/lzma.exe e $SOURCES $TARGET',
+  )
+
+  # Construct the resource generation script
+  manifest_path = '$MAIN_DIR/installers/installers.manifest'
+  res_command = 'python.exe %s -i %s -o $TARGET -p $SOURCES -m %s -r %s' % (
+      env.File('$MAIN_DIR/installers/generate_resource_script.py').abspath,
+      env.File('$MAIN_DIR/installers/resource.rc.in').abspath,
+      env.File(manifest_path).abspath,
+      env.File('$MAIN_DIR/installers/resource.h').abspath
+      )
+
+  # Generate the .rc file
+  rc_output = env.Command(
+      target='%sresource%s.rc' % (prefix, suffix),
+      source=lzma_output,
+      action=res_command,
+  )
+
+  # .res intermediate file
+  res_file = env.RES(rc_output)
+
+  # For some reason, RES() does not cause the .res file to depend on .rc input.
+  # It also does not detect the dependencies in the .rc file.
+  # This does not cause a rebuild for rarely changing files in res_command.
+  env.Depends(res_file, [rc_output, manifest_path, lzma_output])
+
+  # Resource DLL
+  dll_env = env.Clone(COMPONENT_STATIC=False)
+  dll_env['LINKFLAGS'] += ['/noentry']
+
+  dll_inputs = [
+      '$MAIN_DIR/installers/resource_only_dll.def',
+      res_file
+      ]
+
+  dll_output = dll_env.ComponentLibrary(
+      lib_name='%spayload%s.dll' % (prefix, suffix),
+      source=dll_inputs,
+  )
+
+  # Get only the dll itself from the output (ie. ignore .pdb, etc.)
+  dll_output_name = [f for f in dll_output if f.suffix == '.dll']
+
+  # Build the target setup executable by merging the empty metafile
+  # with the resource dll built above
+  merged_output = env.Command(
+      target='unsigned_' + target_name,
+      source=[empty_metainstaller_path, dll_output_name],
+      action='$MAIN_DIR/tools/resmerge --copyappend $SOURCES $TARGET'
+  )
+
+  signed_exe = env.SignedBinary(
+      target=target_name,
+      source=merged_output,
+  )
+
+  env.Replicate('$STAGING_DIR', signed_exe)
+
+
diff --git a/installers/generate_resource_script.py b/installers/generate_resource_script.py
index c08d1ee..d755fc1 100644
--- a/installers/generate_resource_script.py
+++ b/installers/generate_resource_script.py
@@ -1,62 +1,62 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-import getopt

-import os.path

-import re

-import sys

-

-def GenerateResourceScript(input_filename, output_filename, payload_filename,

-                           manifest_filename, resource_filename):

-  """

-  Given a template name, output filename, payload filename, manifest filename,

-  and resource_filename, and creates a resource script.

-  """

-  f_int = open(input_filename, 'r')

-  f_out = open(output_filename, 'w')

-

-  for line in f_int.readlines():

-    f_out.write(re.sub(r'__RESOURCE_FILENAME__', resource_filename,

-                re.sub(r'__MANIFEST_FILENAME__', manifest_filename,

-                re.sub(r'__PAYLOAD_FILENAME__', payload_filename, line))))

-

-(opts, args) = getopt.getopt(sys.argv[1:], 'i:o:p:m:r:')

-

-input_filename = ''

-output_filename = ''

-payload_filename = ''

-manifest_filename = ''

-resource_filename = ''

-

-for (o, v) in opts:

-  if o == '-i':

-    input_filename = v

-  if o == '-o':

-    output_filename = v

-  if o == '-p':

-    payload_filename = v

-  if o == '-m':

-    manifest_filename = v

-  if o == '-r':

-    resource_filename = v

-

-# The forward slashes prevent the RC compiler from trying to interpret

-# backslashes in the quoted path.

-GenerateResourceScript(input_filename, output_filename,

-  re.sub(r'\\', r'/', payload_filename),

-  re.sub(r'\\', r'/', manifest_filename),

-  re.sub(r'\\', r'/', resource_filename))

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+import getopt
+import os.path
+import re
+import sys
+
+def GenerateResourceScript(input_filename, output_filename, payload_filename,
+                           manifest_filename, resource_filename):
+  """
+  Given a template name, output filename, payload filename, manifest filename,
+  and resource_filename, and creates a resource script.
+  """
+  f_int = open(input_filename, 'r')
+  f_out = open(output_filename, 'w')
+
+  for line in f_int.readlines():
+    f_out.write(re.sub(r'__RESOURCE_FILENAME__', resource_filename,
+                re.sub(r'__MANIFEST_FILENAME__', manifest_filename,
+                re.sub(r'__PAYLOAD_FILENAME__', payload_filename, line))))
+
+(opts, args) = getopt.getopt(sys.argv[1:], 'i:o:p:m:r:')
+
+input_filename = ''
+output_filename = ''
+payload_filename = ''
+manifest_filename = ''
+resource_filename = ''
+
+for (o, v) in opts:
+  if o == '-i':
+    input_filename = v
+  if o == '-o':
+    output_filename = v
+  if o == '-p':
+    payload_filename = v
+  if o == '-m':
+    manifest_filename = v
+  if o == '-r':
+    resource_filename = v
+
+# The forward slashes prevent the RC compiler from trying to interpret
+# backslashes in the quoted path.
+GenerateResourceScript(input_filename, output_filename,
+  re.sub(r'\\', r'/', payload_filename),
+  re.sub(r'\\', r'/', manifest_filename),
+  re.sub(r'\\', r'/', resource_filename))
diff --git a/installers/generate_tarball.py b/installers/generate_tarball.py
index 1c6db0b..f12af59 100644
--- a/installers/generate_tarball.py
+++ b/installers/generate_tarball.py
@@ -1,49 +1,49 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-import getopt

-import os.path

-import sys

-import tarfile

-import urllib

-

-TEST_PREFIX = 'TEST_'

-

-def GenerateTarball(output_filename, members):

-  """

-  Given a tarball name and a sequence of filenames, creates a tarball

-  containing the named files.

-  """

-  tarball = tarfile.open(output_filename, 'w')

-  for filename in members:

-    # A hacky convention to get around the spaces in filenames is to

-    # urlencode them. So at this point we unescape those characters.

-    scrubbed_filename = urllib.unquote(os.path.basename(filename))

-    if scrubbed_filename.startswith(TEST_PREFIX):

-      scrubbed_filename = scrubbed_filename[len(TEST_PREFIX):]

-    tarball.add(filename, scrubbed_filename)

-  tarball.close()

-

-(opts, args) = getopt.getopt(sys.argv[1:], 'i:o:p:')

-

-output_filename = ''

-

-for (o, v) in opts:

-  if o == '-o':

-    output_filename = v

-

-GenerateTarball(output_filename, args)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+import getopt
+import os.path
+import sys
+import tarfile
+import urllib
+
+TEST_PREFIX = 'TEST_'
+
+def GenerateTarball(output_filename, members):
+  """
+  Given a tarball name and a sequence of filenames, creates a tarball
+  containing the named files.
+  """
+  tarball = tarfile.open(output_filename, 'w')
+  for filename in members:
+    # A hacky convention to get around the spaces in filenames is to
+    # urlencode them. So at this point we unescape those characters.
+    scrubbed_filename = urllib.unquote(os.path.basename(filename))
+    if scrubbed_filename.startswith(TEST_PREFIX):
+      scrubbed_filename = scrubbed_filename[len(TEST_PREFIX):]
+    tarball.add(filename, scrubbed_filename)
+  tarball.close()
+
+(opts, args) = getopt.getopt(sys.argv[1:], 'i:o:p:')
+
+output_filename = ''
+
+for (o, v) in opts:
+  if o == '-o':
+    output_filename = v
+
+GenerateTarball(output_filename, args)
diff --git a/installers/get_payload_files.py b/installers/get_payload_files.py
index 20bb9c9..02645d1 100644
--- a/installers/get_payload_files.py
+++ b/installers/get_payload_files.py
@@ -1,47 +1,47 @@
-#!/usr/bin/python2.4

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-def GetListOfPayloadFiles(prefix,

-                          activex_filename,

-                          bho_filename,

-                          languages,

-                          product_version):

-  payload_files = [

-      'GoogleUpdate.exe',

-      '%sgoopdate.dll' % (prefix),

-      # One-Click DLL

-      '%s%s' % (prefix, activex_filename),

-      # BHO proxy DLL

-      '%s%s' % (prefix, bho_filename),

-      'GoogleUpdateHelper.msi',

-      ]

-

-  # TODO(omaha): Eliminate this and add GoogleCrashHandler.exe above once we no

-  # longer need to support versions less than 1.2.147.x.

-  # Note: check will be incorrect for versions such as 0.3.0.0, but it is

-  # assumed that such versions will not be used.

-  if (product_version[0] > 1 or

-      product_version[1] > 2 or

-      product_version[2] > 146):

-    payload_files += ['GoogleCrashHandler.exe']

-

-  for language in languages:

-    payload_files += ['%sgoopdateres_%s.dll' % (prefix, language)]

-

-  return payload_files

-

-

+#!/usr/bin/python2.4
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+def GetListOfPayloadFiles(prefix,
+                          activex_filename,
+                          bho_filename,
+                          languages,
+                          product_version):
+  payload_files = [
+      'GoogleUpdate.exe',
+      '%sgoopdate.dll' % (prefix),
+      # One-Click DLL
+      '%s%s' % (prefix, activex_filename),
+      # BHO proxy DLL
+      '%s%s' % (prefix, bho_filename),
+      'GoogleUpdateHelper.msi',
+      ]
+
+  # TODO(omaha): Eliminate this and add GoogleCrashHandler.exe above once we no
+  # longer need to support versions less than 1.2.147.x.
+  # Note: check will be incorrect for versions such as 0.3.0.0, but it is
+  # assumed that such versions will not be used.
+  if (product_version[0] > 1 or
+      product_version[1] > 2 or
+      product_version[2] > 146):
+    payload_files += ['GoogleCrashHandler.exe']
+
+  for language in languages:
+    payload_files += ['%sgoopdateres_%s.dll' % (prefix, language)]
+
+  return payload_files
+
+
diff --git a/installers/installers.manifest b/installers/installers.manifest
index a485609..c3263b5 100644
--- a/installers/installers.manifest
+++ b/installers/installers.manifest
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="utf-8"?>

-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

-  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">

-    <security>

-      <requestedPrivileges>

-        <requestedExecutionLevel level="asInvoker" />

-      </requestedPrivileges>

-    </security>

-  </trustInfo>

-</assembly>

+<?xml version="1.0" encoding="utf-8"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+</assembly>
diff --git a/installers/resource.h b/installers/resource.h
index 24fd28d..e76ebbb 100644
--- a/installers/resource.h
+++ b/installers/resource.h
@@ -1,33 +1,33 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// Used by mi.rc

-

-#ifndef OMAHA_INSTALLERS_RESOURCE_H__

-#define OMAHA_INSTALLERS_RESOURCE_H__

-

-#define IDI_APP                         101

-#define IDR_PAYLOAD                     102

-

-// Next default values for new objects

-#ifdef APSTUDIO_INVOKED

-#ifndef APSTUDIO_READONLY_SYMBOLS

-#define _APS_NEXT_RESOURCE_VALUE        103

-#define _APS_NEXT_COMMAND_VALUE         40001

-#define _APS_NEXT_CONTROL_VALUE         1001

-#define _APS_NEXT_SYMED_VALUE           101

-#endif

-#endif

-

-#endif  // OMAHA_INSTALLERS_RESOURCE_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// Used by mi.rc
+
+#ifndef OMAHA_INSTALLERS_RESOURCE_H__
+#define OMAHA_INSTALLERS_RESOURCE_H__
+
+#define IDI_APP                         101
+#define IDR_PAYLOAD                     102
+
+// Next default values for new objects
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        103
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
+
+#endif  // OMAHA_INSTALLERS_RESOURCE_H__
diff --git a/installers/resource.rc.in b/installers/resource.rc.in
index 9e6ed25..3e38f4d 100644
--- a/installers/resource.rc.in
+++ b/installers/resource.rc.in
@@ -1,23 +1,23 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The __ symbols are replaced by a script that creates the rc file.

-#include "__RESOURCE_FILENAME__"

-

-#include "afxres.h"

-

-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

-IDR_PAYLOAD B "__PAYLOAD_FILENAME__"

-1 RT_MANIFEST "__MANIFEST_FILENAME__"

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The __ symbols are replaced by a script that creates the rc file.
+#include "__RESOURCE_FILENAME__"
+
+#include "afxres.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+IDR_PAYLOAD B "__PAYLOAD_FILENAME__"
+1 RT_MANIFEST "__MANIFEST_FILENAME__"
diff --git a/installers/resource_only_dll.def b/installers/resource_only_dll.def
index 21ac577..078c46b 100644
--- a/installers/resource_only_dll.def
+++ b/installers/resource_only_dll.def
@@ -1,16 +1,16 @@
-; Copyright 2007-2009 Google Inc.

-;

-; Licensed under the Apache License, Version 2.0 (the "License");

-; you may not use this file except in compliance with the License.

-; You may obtain a copy of the License at

-;

-;      http://www.apache.org/licenses/LICENSE-2.0

-;

-; Unless required by applicable law or agreed to in writing, software

-; distributed under the License is distributed on an "AS IS" BASIS,

-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-; See the License for the specific language governing permissions and

-; limitations under the License.

-; ========================================================================

-;

-; dummy def file to create implib

+; Copyright 2007-2009 Google Inc.
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+; ========================================================================
+;
+; dummy def file to create implib
diff --git a/installers/tag_meta_installers.py b/installers/tag_meta_installers.py
index a591d5c..d85d5b0 100644
--- a/installers/tag_meta_installers.py
+++ b/installers/tag_meta_installers.py
@@ -1,285 +1,285 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2005-2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-"""Creates application specific meta-installers.

-

-Run this script with the directory that contains the build files,

-GoogleupdateSetup_<lang>.exe and pass it the file that contains the application

-information to be stamped inside the binary.

-

-"""

-

-import codecs

-import os

-import sys

-import re

-import urllib

-

-class Bundle:

-  """Represents the information for a bundle"""

-  def __init__(self, exe_name, admin, language,

-               browser_type, stats, installers_txt_filename, applications):

-    self.applications = applications

-    self.name = exe_name

-    self.needs_admin = admin

-    self.lang = language

-    self.browser = browser_type

-    self.usage_stats = stats

-    self.installers_txt_filename = installers_txt_filename

-    self.output_file_name = ""

-

-def UrlEncodeString(name):

-  """Converts the name into utf8 encoded and then urlencodes it.

-

-  Args:

-    name: The string to utf8 convert.

-

-  Returns:

-    The utf8 converted urlencoded string.

-  """

-  utf8_str = name.encode('utf8')

-  return urllib.quote(utf8_str)

-

-def ReadBundleInstallerFile(installers_txt_filename):

-  """Read the installation file and return a list of the values.

-     Only reads information from bundle installer files. The filename

-     should contain the "bundle" word.

-  Args:

-    installers_txt_filename: The file which contains application specific

-                             values, of guid, name, exe_name, needs_admin and

-                             language.

-

-  Returns:

-    A dictionary of Bundles key=language, value=[Bundle]

-  """

-  bundles = {}

-  installers_txt_file = codecs.open(installers_txt_filename, 'r', 'utf16')

-  for line in installers_txt_file.readlines():

-    line = line.strip()

-    if len(line) and not line.startswith('#'):

-      (exe_name, needs_admin, language, browser, usage, bundle_apps) =\

-        eval(line)

-      bundle = Bundle(exe_name, needs_admin, language,

-                      browser, usage,

-                      installers_txt_filename, bundle_apps)

-      if (not bundles.has_key(language)):

-        bundles[language] = [bundle]

-      else:

-        bundles[language] .append(bundle)

-  return bundles

-

-def BuildOutputDirectory(output_dir, lang, app):

-  """Returns the output directory for the app.

-

-  Args:

-    app: The application for which to generate the path.

-    lang: The language of the applicaiton.

-    output_dir: The output directory.

-

-  Returns:

-    The path of the output file.

-  """

-  installers_txt_filename = app.installers_txt_filename

-

-  end_idx = installers_txt_filename.find('_installers.txt')

-  app_dirname = installers_txt_filename[:end_idx]

-

-  app_path = os.path.join(output_dir, app_dirname)

-  lang_path = os.path.join(app_path, lang)

-  return lang_path

-

-

-def SetOutputFileNames(file_name, apps, output_dir):

-  """Sets the output file names inside the Application.

-

-  Args:

-    file_name: The input file name that needs to be stamped. This

-               is used for deciding whether to use TEST in the name,

-               and the directory. The names of this file is expected

-               to be either TEST_GoogleUpdateSetup.exe or

-               GoogleUpdateSetup.exe

-    apps: Dictionary of applications keyed by language.

-    output_dir: The output directory.

-

-  Returns:

-    All the applications for a particular language.

-  """

-

-  # Determine the language.

-  file = os.path.basename(file_name)

-  if file.startswith('TEST_'):

-    test = True

-  else:

-    test = False

-

-  for (lang, apps_lang) in apps.iteritems():

-    # Get the output filename and set it on the application.

-    for app in apps_lang:

-      output_path = BuildOutputDirectory(output_dir, lang, app)

-      path = os.path.join(output_path, GetOutputFileName(test, app.name, lang))

-      app.output_file_name = path

-

-def GetOutputFileName(test, name, lang):

-  """Creates the output file name based on the language and the name of the app.

-  Args:

-    test: Whether the input file name starts with TEST.

-    name: The name of the application. I.e. Chrome, GoogleGears.

-    lang: The language of the installer.

-  Returns:

-    The output filename

-  """

-  if test:

-    file_name = 'Tagged_TEST_%sSetup_%s.exe' % (name, lang)

-  else:

-    file_name = 'Tagged_%sSetup_%s.exe' % (name, lang)

-  return file_name

-

-def BuildTagStringForBundle(bundle):

-  """Builds the string to be tagged into the binary for a bundle.

-  Args:

-    bundle: Contains all information about a bundle.

-  Returns:

-    The string to be tagged into the installer.

-  """

-  args = '\"'

-  first_app = True

-  for app in bundle.applications:

-    if not first_app:

-      args += '&'

-    first_app = False

-    (guid, name, ap) = app

-    display_name = UrlEncodeString(name)

-    args += 'appguid=%s&appname=%s&needsadmin=%s' % \

-            (guid, display_name, bundle.needs_admin)

-    if ap:

-      args += '&ap=%s' % ap

-

-  if bundle.usage_stats:

-    args += '&usagestats=%s' % bundle.usage_stats

-  if bundle.browser:

-    args += '&browser=%s' % bundle.browser

-  if bundle.lang:

-    args += '&lang=%s' % bundle.lang

-  args += '\"'

-  return args

-

-def TagOneFile(file, app, applytag_exe_name):

-  """Tags one file with the information contained inside the application.

-  Args:

-    file: The input file to be stamped.

-    app: Contains all the application data.

-    applytag_exe_name: The full path of applytag.exe.

-  """

-  tag_string = BuildTagStringForBundle(app)

-

-  output_path = app.output_file_name

-  if not os.path.exists(file):

-    print 'Could not find file %s required for creating %s' % \

-          (file, output_path)

-    return False

-

-  arguments = [applytag_exe_name,

-               file,

-               output_path,

-               tag_string

-              ]

-  print 'Building %s with tag %s' % (output_path, tag_string)

-  os.spawnv(os.P_WAIT, applytag_exe_name, arguments)

-  return True

-

-def GetAllSetupExeInDirectory(dir):

-  """Creates a number of application specific binaries for the

-     passed in binary.

-  Args:

-    dir: The input directory.

-  Returns:

-    A list of files that are match the regex:

-    TEST_GoogleUpdateSetup_.*.exe$|^GoogleUpdateSetup_.*.exe$

-  """

-  ret_files = []

-  files = os.listdir(dir)

-  for file in files:

-    regex = re.compile('^TEST_GoogleUpdateSetup_.*.exe$|'

-                       '^GoogleUpdateSetup_.*.exe$')

-    if not regex.match(file):

-      continue

-    ret_files.append(file)

-  return ret_files

-

-def TagBinary(apps, file, applytag_exe_name):

-  """Creates a number of application specific binaries for the

-     passed in binary.

-  Args:

-    apps: Dictionary of key=lang, value=[Application].

-    file: The input file to be stamped.

-    applytag_exe_name: The full path to applytag_exe_name.

-  """

-  if not apps:

-    return

-  for apps_lang in apps:

-    for app in apps[apps_lang]:

-      TagOneFile(file, app, applytag_exe_name)

-

-def PrintUsage():

-  print ''

-  print 'Tool to stamp the Guid, Application name, needs admin into the'

-  print 'meta-installer.'

-  print 'Reads <installer file> which contains the application name,'

-  print 'guid, needs_admin and stamps the meta-installer <file> with'

-  print 'these values.'

-  print 'For an example of the <installer file> take a look at'

-  print '#/installers/googlegears_installer.txt'

-  print ''

-  print 'tag_meta_installers.py <applytag> <input file> <installer file>\

-  <output file>'

-

-def main():

-  if len(sys.argv) != 5:

-    PrintUsage()

-    return

-

-  apply_tag_exe = sys.argv[1]

-  input_file = sys.argv[2]

-  file_name = sys.argv[3]

-  output_dir = sys.argv[4]

-

-  if not os.path.exists(apply_tag_exe):

-    print "Could not find applytag.exe"

-    PrintUsage()

-    return

-

-  if not os.path.exists(file_name):

-    print "Invalid filename %s" % file_name

-    PrintUsage()

-    return

-

-  if not os.path.exists(input_file):

-    print "Invalid directory %s" % input_file

-    PrintUsage()

-    return

-

-  if not os.path.exists(output_dir):

-    os.mkdir(output_dir)

-

-  # Read in the installers.txt file.

-  apps = ReadBundleInstallerFile(file_name)

-

-  SetOutputFileNames(input_file, apps, output_dir)

-  TagBinary(apps, input_file, apply_tag_exe)

-

-if __name__ == '__main__':

-  main()

+#!/usr/bin/python2.4
+#
+# Copyright 2005-2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+"""Creates application specific meta-installers.
+
+Run this script with the directory that contains the build files,
+GoogleupdateSetup_<lang>.exe and pass it the file that contains the application
+information to be stamped inside the binary.
+
+"""
+
+import codecs
+import os
+import sys
+import re
+import urllib
+
+class Bundle:
+  """Represents the information for a bundle"""
+  def __init__(self, exe_name, admin, language,
+               browser_type, stats, installers_txt_filename, applications):
+    self.applications = applications
+    self.name = exe_name
+    self.needs_admin = admin
+    self.lang = language
+    self.browser = browser_type
+    self.usage_stats = stats
+    self.installers_txt_filename = installers_txt_filename
+    self.output_file_name = ""
+
+def UrlEncodeString(name):
+  """Converts the name into utf8 encoded and then urlencodes it.
+
+  Args:
+    name: The string to utf8 convert.
+
+  Returns:
+    The utf8 converted urlencoded string.
+  """
+  utf8_str = name.encode('utf8')
+  return urllib.quote(utf8_str)
+
+def ReadBundleInstallerFile(installers_txt_filename):
+  """Read the installation file and return a list of the values.
+     Only reads information from bundle installer files. The filename
+     should contain the "bundle" word.
+  Args:
+    installers_txt_filename: The file which contains application specific
+                             values, of guid, name, exe_name, needs_admin and
+                             language.
+
+  Returns:
+    A dictionary of Bundles key=language, value=[Bundle]
+  """
+  bundles = {}
+  installers_txt_file = codecs.open(installers_txt_filename, 'r', 'utf16')
+  for line in installers_txt_file.readlines():
+    line = line.strip()
+    if len(line) and not line.startswith('#'):
+      (exe_name, needs_admin, language, browser, usage, bundle_apps) =\
+        eval(line)
+      bundle = Bundle(exe_name, needs_admin, language,
+                      browser, usage,
+                      installers_txt_filename, bundle_apps)
+      if (not bundles.has_key(language)):
+        bundles[language] = [bundle]
+      else:
+        bundles[language] .append(bundle)
+  return bundles
+
+def BuildOutputDirectory(output_dir, lang, app):
+  """Returns the output directory for the app.
+
+  Args:
+    app: The application for which to generate the path.
+    lang: The language of the applicaiton.
+    output_dir: The output directory.
+
+  Returns:
+    The path of the output file.
+  """
+  installers_txt_filename = app.installers_txt_filename
+
+  end_idx = installers_txt_filename.find('_installers.txt')
+  app_dirname = installers_txt_filename[:end_idx]
+
+  app_path = os.path.join(output_dir, app_dirname)
+  lang_path = os.path.join(app_path, lang)
+  return lang_path
+
+
+def SetOutputFileNames(file_name, apps, output_dir):
+  """Sets the output file names inside the Application.
+
+  Args:
+    file_name: The input file name that needs to be stamped. This
+               is used for deciding whether to use TEST in the name,
+               and the directory. The names of this file is expected
+               to be either TEST_GoogleUpdateSetup.exe or
+               GoogleUpdateSetup.exe
+    apps: Dictionary of applications keyed by language.
+    output_dir: The output directory.
+
+  Returns:
+    All the applications for a particular language.
+  """
+
+  # Determine the language.
+  file = os.path.basename(file_name)
+  if file.startswith('TEST_'):
+    test = True
+  else:
+    test = False
+
+  for (lang, apps_lang) in apps.iteritems():
+    # Get the output filename and set it on the application.
+    for app in apps_lang:
+      output_path = BuildOutputDirectory(output_dir, lang, app)
+      path = os.path.join(output_path, GetOutputFileName(test, app.name, lang))
+      app.output_file_name = path
+
+def GetOutputFileName(test, name, lang):
+  """Creates the output file name based on the language and the name of the app.
+  Args:
+    test: Whether the input file name starts with TEST.
+    name: The name of the application. I.e. Chrome, GoogleGears.
+    lang: The language of the installer.
+  Returns:
+    The output filename
+  """
+  if test:
+    file_name = 'Tagged_TEST_%sSetup_%s.exe' % (name, lang)
+  else:
+    file_name = 'Tagged_%sSetup_%s.exe' % (name, lang)
+  return file_name
+
+def BuildTagStringForBundle(bundle):
+  """Builds the string to be tagged into the binary for a bundle.
+  Args:
+    bundle: Contains all information about a bundle.
+  Returns:
+    The string to be tagged into the installer.
+  """
+  args = '\"'
+  first_app = True
+  for app in bundle.applications:
+    if not first_app:
+      args += '&'
+    first_app = False
+    (guid, name, ap) = app
+    display_name = UrlEncodeString(name)
+    args += 'appguid=%s&appname=%s&needsadmin=%s' % \
+            (guid, display_name, bundle.needs_admin)
+    if ap:
+      args += '&ap=%s' % ap
+
+  if bundle.usage_stats:
+    args += '&usagestats=%s' % bundle.usage_stats
+  if bundle.browser:
+    args += '&browser=%s' % bundle.browser
+  if bundle.lang:
+    args += '&lang=%s' % bundle.lang
+  args += '\"'
+  return args
+
+def TagOneFile(file, app, applytag_exe_name):
+  """Tags one file with the information contained inside the application.
+  Args:
+    file: The input file to be stamped.
+    app: Contains all the application data.
+    applytag_exe_name: The full path of applytag.exe.
+  """
+  tag_string = BuildTagStringForBundle(app)
+
+  output_path = app.output_file_name
+  if not os.path.exists(file):
+    print 'Could not find file %s required for creating %s' % \
+          (file, output_path)
+    return False
+
+  arguments = [applytag_exe_name,
+               file,
+               output_path,
+               tag_string
+              ]
+  print 'Building %s with tag %s' % (output_path, tag_string)
+  os.spawnv(os.P_WAIT, applytag_exe_name, arguments)
+  return True
+
+def GetAllSetupExeInDirectory(dir):
+  """Creates a number of application specific binaries for the
+     passed in binary.
+  Args:
+    dir: The input directory.
+  Returns:
+    A list of files that are match the regex:
+    TEST_GoogleUpdateSetup_.*.exe$|^GoogleUpdateSetup_.*.exe$
+  """
+  ret_files = []
+  files = os.listdir(dir)
+  for file in files:
+    regex = re.compile('^TEST_GoogleUpdateSetup_.*.exe$|'
+                       '^GoogleUpdateSetup_.*.exe$')
+    if not regex.match(file):
+      continue
+    ret_files.append(file)
+  return ret_files
+
+def TagBinary(apps, file, applytag_exe_name):
+  """Creates a number of application specific binaries for the
+     passed in binary.
+  Args:
+    apps: Dictionary of key=lang, value=[Application].
+    file: The input file to be stamped.
+    applytag_exe_name: The full path to applytag_exe_name.
+  """
+  if not apps:
+    return
+  for apps_lang in apps:
+    for app in apps[apps_lang]:
+      TagOneFile(file, app, applytag_exe_name)
+
+def PrintUsage():
+  print ''
+  print 'Tool to stamp the Guid, Application name, needs admin into the'
+  print 'meta-installer.'
+  print 'Reads <installer file> which contains the application name,'
+  print 'guid, needs_admin and stamps the meta-installer <file> with'
+  print 'these values.'
+  print 'For an example of the <installer file> take a look at'
+  print '#/installers/googlegears_installer.txt'
+  print ''
+  print 'tag_meta_installers.py <applytag> <input file> <installer file>\
+  <output file>'
+
+def main():
+  if len(sys.argv) != 5:
+    PrintUsage()
+    return
+
+  apply_tag_exe = sys.argv[1]
+  input_file = sys.argv[2]
+  file_name = sys.argv[3]
+  output_dir = sys.argv[4]
+
+  if not os.path.exists(apply_tag_exe):
+    print "Could not find applytag.exe"
+    PrintUsage()
+    return
+
+  if not os.path.exists(file_name):
+    print "Invalid filename %s" % file_name
+    PrintUsage()
+    return
+
+  if not os.path.exists(input_file):
+    print "Invalid directory %s" % input_file
+    PrintUsage()
+    return
+
+  if not os.path.exists(output_dir):
+    os.mkdir(output_dir)
+
+  # Read in the installers.txt file.
+  apps = ReadBundleInstallerFile(file_name)
+
+  SetOutputFileNames(input_file, apps, output_dir)
+  TagBinary(apps, input_file, apply_tag_exe)
+
+if __name__ == '__main__':
+  main()
diff --git a/installers/tagged_installer.py b/installers/tagged_installer.py
index 04fbc3b..41732b0 100644
--- a/installers/tagged_installer.py
+++ b/installers/tagged_installer.py
@@ -1,90 +1,90 @@
-#!/usr/bin/python2.4

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-import os

-import re

-

-from installers import tag_meta_installers

-

-

-def TagOneBundle(env, bundle, untagged_binary, output_dir):

-  tag_str = tag_meta_installers.BuildTagStringForBundle(bundle)

-

-  # Need to find relative path to output file under source dir, to allow

-  # it to be redirected under the output directory.

-  indx = bundle.output_file_name.find('installers')

-  relative_filepath = bundle.output_file_name[indx+len('installers')+1:]

-

-  tag_output = env.Command(

-      target='%s/%s' % (output_dir, relative_filepath),

-      source='$STAGING_DIR/%s' % (untagged_binary),

-      action='%s $SOURCES $TARGET %s' % (

-          env.File('$STAGING_DIR/ApplyTag.exe').abspath, tag_str)

-  )

-

-  # Add extra (hidden) dependency.

-  env.Depends(tag_output, bundle.installers_txt_filename)

-

-

-def _ReadAllBundleInstallerFiles(installers_txt_files_path):

-  """Enumerates all the .*_installers.txt files in the installers_txt_files_path

-     directory, and creates bundles corresponding to the info in each line in

-     the *_installers.txt file.

-  Returns:

-    Returns a dictionary of Bundles with key=lang.

-  """

-  bundles = {}

-  files = os.listdir(installers_txt_files_path)

-  for file in files:

-    regex = re.compile('^(.*)_installers.txt$')

-    if not regex.match(file):

-      continue

-

-    installer_file = os.path.join(installers_txt_files_path, file)

-

-    # Read in the installer file.

-    read_bundles = tag_meta_installers.ReadBundleInstallerFile(installer_file)

-

-    for (key, bundle_list) in read_bundles.items():

-      if not bundle_list or not key:

-        continue

-      if not bundles.has_key(key):

-        bundles[key] = bundle_list

-      else:

-        new_bundles_list = bundles[key] + bundle_list

-        bundles[key] = new_bundles_list

-  return bundles

-

-

-def CreateTaggedInstallers(env, installers_txt_files_path, product_name,

-                           prefix = ''):

-  """For each application with an installers.txt file in installer_files_path,

-     create tagged metainstaller(s).

-  """

-  bundles = _ReadAllBundleInstallerFiles(installers_txt_files_path)

-

-  untagged_binary = '%s%sSetup.exe' % (prefix, product_name)

-

-  tag_meta_installers.SetOutputFileNames(untagged_binary, bundles, '')

-  for bundles_lang in bundles.itervalues():

-    for bundle in bundles_lang:

-      TagOneBundle(

-          env=env,

-          bundle=bundle,

-          untagged_binary=untagged_binary,

-          output_dir='$TARGET_ROOT/Tagged_Installers',

-      )

-

+#!/usr/bin/python2.4
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+import os
+import re
+
+from installers import tag_meta_installers
+
+
+def TagOneBundle(env, bundle, untagged_binary, output_dir):
+  tag_str = tag_meta_installers.BuildTagStringForBundle(bundle)
+
+  # Need to find relative path to output file under source dir, to allow
+  # it to be redirected under the output directory.
+  indx = bundle.output_file_name.find('installers')
+  relative_filepath = bundle.output_file_name[indx+len('installers')+1:]
+
+  tag_output = env.Command(
+      target='%s/%s' % (output_dir, relative_filepath),
+      source='$STAGING_DIR/%s' % (untagged_binary),
+      action='%s $SOURCES $TARGET %s' % (
+          env.File('$STAGING_DIR/ApplyTag.exe').abspath, tag_str)
+  )
+
+  # Add extra (hidden) dependency.
+  env.Depends(tag_output, bundle.installers_txt_filename)
+
+
+def _ReadAllBundleInstallerFiles(installers_txt_files_path):
+  """Enumerates all the .*_installers.txt files in the installers_txt_files_path
+     directory, and creates bundles corresponding to the info in each line in
+     the *_installers.txt file.
+  Returns:
+    Returns a dictionary of Bundles with key=lang.
+  """
+  bundles = {}
+  files = os.listdir(installers_txt_files_path)
+  for file in files:
+    regex = re.compile('^(.*)_installers.txt$')
+    if not regex.match(file):
+      continue
+
+    installer_file = os.path.join(installers_txt_files_path, file)
+
+    # Read in the installer file.
+    read_bundles = tag_meta_installers.ReadBundleInstallerFile(installer_file)
+
+    for (key, bundle_list) in read_bundles.items():
+      if not bundle_list or not key:
+        continue
+      if not bundles.has_key(key):
+        bundles[key] = bundle_list
+      else:
+        new_bundles_list = bundles[key] + bundle_list
+        bundles[key] = new_bundles_list
+  return bundles
+
+
+def CreateTaggedInstallers(env, installers_txt_files_path, product_name,
+                           prefix = ''):
+  """For each application with an installers.txt file in installer_files_path,
+     create tagged metainstaller(s).
+  """
+  bundles = _ReadAllBundleInstallerFiles(installers_txt_files_path)
+
+  untagged_binary = '%s%sSetup.exe' % (prefix, product_name)
+
+  tag_meta_installers.SetOutputFileNames(untagged_binary, bundles, '')
+  for bundles_lang in bundles.itervalues():
+    for bundle in bundles_lang:
+      TagOneBundle(
+          env=env,
+          bundle=bundle,
+          untagged_binary=untagged_binary,
+          output_dir='$TARGET_ROOT/Tagged_Installers',
+      )
+
diff --git a/installers/update_version.py b/installers/update_version.py
index 5d4f437..fe129d6 100644
--- a/installers/update_version.py
+++ b/installers/update_version.py
@@ -1,52 +1,52 @@
-#!/usr/bin/python2.4

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-#

-# Update these values to match the checked in version.

-#

-_LANGUAGES_NOT_IN_BUILD = []

-

-

-# Sets the version and plug-in filenames to the values for the checked in build.

-# Removes languages that are in the current mk_common but not in the checked in

-# build.

-# Returns list of removed languages.

-def UpdateSettingsForCheckedInVersion(env,

-                                      version_major,

-                                      version_minor,

-                                      version_build,

-                                      version_patch,

-                                      oneclick_plugin_version):

-  print

-  print '******* CHANGING VERSION! *******'

-  env.SetProductVersion(

-      version_major, version_minor, version_build, version_patch)

-

-  print

-  print '*********************************'

-  print 'Plug-in version: ' + oneclick_plugin_version

-  print '*********************************'

-  env.SetActiveXFilenames(oneclick_plugin_version)

-

-  for language in _LANGUAGES_NOT_IN_BUILD:

-    if language in env['languages']:

-      env['languages'].remove(language)

-      print '*** Removing language: ' + language

-

-  return _LANGUAGES_NOT_IN_BUILD

-

-

+#!/usr/bin/python2.4
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+#
+# Update these values to match the checked in version.
+#
+_LANGUAGES_NOT_IN_BUILD = []
+
+
+# Sets the version and plug-in filenames to the values for the checked in build.
+# Removes languages that are in the current mk_common but not in the checked in
+# build.
+# Returns list of removed languages.
+def UpdateSettingsForCheckedInVersion(env,
+                                      version_major,
+                                      version_minor,
+                                      version_build,
+                                      version_patch,
+                                      oneclick_plugin_version):
+  print
+  print '******* CHANGING VERSION! *******'
+  env.SetProductVersion(
+      version_major, version_minor, version_build, version_patch)
+
+  print
+  print '*********************************'
+  print 'Plug-in version: ' + oneclick_plugin_version
+  print '*********************************'
+  env.SetActiveXFilenames(oneclick_plugin_version)
+
+  for language in _LANGUAGES_NOT_IN_BUILD:
+    if language in env['languages']:
+      env['languages'].remove(language)
+      print '*** Removing language: ' + language
+
+  return _LANGUAGES_NOT_IN_BUILD
+
+
diff --git a/main.scons b/main.scons
index 314b4c6..4bab038 100644
--- a/main.scons
+++ b/main.scons
@@ -1,743 +1,743 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-# This main.scons file is the root description of the build specified in this

-# directory and those under it. Individual components and the source files

-# used to build them are described in subsidiary files called 'build.scons'.

-#

-# To build this project change the current directory to googleclient/Omaha.

-# Then run hammer.bat

-#

-# A number of command line options can be specified. For a full list, use the

-# -h and -H command options.

-#

-# Some useful options include:

-#   -h   :   Prints a list of which modules and build variants are available

-#            in this project.

-#   -H   :   Print SCons specific help. SCons is a build tool which this

-#            project uses in tandem with the Software Construction Toolkit

-#            to build.

-#   -c   :   Clean the project. I.e. delete all build output.

-#   -j3  :   Run up to 3 build steps at once.

-#

-# Some useful build targets include:

-#    all_programs    :   Build all programs generated by this project.

-#    all_libraries   :   Build all libraries generated by this project.

-#    all_tests       :   Build all tests generated by this project.

-#    run_all_tests   :   Build and run all tests generated by this project.

-#

-# Some examples:

-#   Build all programs and libraries in debug mode:

-#     hammer

-#   Build and run all tests in debug mode on windows:

-#     hammer MODE=dbg-win run_all_tests

-#   Build arbitrary library in the default mode:

-#     hammer <library name>

-

-import os

-

-# To switch the build, simply change the value of the msc_ver variable below.

-# VC2003/VC71 is 1310 but not supported by the current build.

-# VC2005/VC80 is 1400.

-# VC2008/VC90 is 1500.

-_msc_ver = 1400

-

-# TODO(Omaha) - Change this to match the official product name

-_PUBLISHER_NAME = 'Google'

-_PRODUCT_NAME = 'Update'

-_ACTIVEX_NAME = 'npGoogleOneClick'

-_BHO_NAME = 'GoopdateBho'

-

-# COM proxy setting.

-# The proxy clsid needs to be changed anytime the interfaces in

-# google_update_idl.idl change, or when a new interface is added. Use

-# guidgen.exe to generate new clsids in the format 'static const struct GUID'.

-# PROXY_CLSID_IS = {29A96789-9595-4947-BEDB-0FCC776F7DB8}

-_PROXY_CLSID_IS = ('{0x29a96789, 0x9595, 0x4947, '

-    '{0xbe, 0xdb, 0xf, 0xcc, 0x77, 0x6f, 0x7d, 0xb8}}')

-

-#

-# Set up version info

-#

-execfile('VERSION')

-

-

-# Windows is the only environment we bulid for, so create a specialized base

-# environment for Windows.

-win_env = Environment()

-

-# Make sure we use the Vista SDK.

-# NOTE: This must be set before the 'component_setup' tool is used.

-win_env['PLATFORM_SDK_DIR'] = '$PLATFORM_SDK_VISTA_6_0_DIR'

-

-win_env.Tool('component_setup')

-win_env.Tool('target_platform_windows')

-

-# Need to use 'masm' to override the 'as' tool currently used

-# by default in 'target_platform_windows'

-win_env.Tool('masm')

-

-win_env.Tool('atlmfc_vc80')

-

-# Visual Studio 2008 does not ship the sign tool. Use the sign tool from

-# the Platform SDK.

-win_env.Tool('code_signing')

-_signtool_path = os.path.join(os.environ['OMAHA_VISTASDK_DIR'],

-                             'bin\\signtool.exe')

-win_env['SIGNTOOL'] = '"' + _signtool_path + '"'

-

-# Remove this value because it conflicts with a #define

-# in shlwapi.h in the Vista SDK

-win_env.FilterOut(CPPDEFINES = ['OS_WINDOWS=OS_WINDOWS'])

-

-win_env.Tool('component_targets_msvs')

-

-# We pre-generate our own manifests, so make sure hammer does not generate

-# default ones for us

-del win_env['MANIFEST_FILE']

-

-# Hack to work around bug in Hammer (http://b/1585388).

-# TODO(Omaha): Remove when bug is fixed.

-if win_env['ENV'].has_key('SYSTEMROOT'):

-  if win_env['ENV'].has_key('SystemRoot'):

-    del win_env['ENV']['SYSTEMROOT']

-    del os.environ['SYSTEMROOT']

-

-

-# Declare command line options relating to code signing

-AddOption(

-    '--authenticode_file',

-    action='store',

-    nargs=1,

-    type='string',

-    default='$MAIN_DIR/data/OmahaTestCert.pfx'

-)

-

-default_cert_password = 'test'

-AddOption(

-    '--authenticode_password',

-    action='store',

-    nargs=1,

-    type='string',

-    default=default_cert_password

-)

-

-# Declare option for specifying path to new official build files

-AddOption(

-    '--official_build_path',

-    action='store',

-    nargs=1,

-    type='string',

-    default=None

-)

-

-# Declare various boolean states.

-DeclareBit('use_precompiled_headers', 'Use precompiled headers in build')

-DeclareBit('official_installers', 'Building using checked-in binaries')

-DeclareBit('build_server', 'Running on the build server')

-DeclareBit('test_certificate', 'Files will be signed with the test certificate')

-DeclareBit('bin', 'Building from pre-built binaries')

-DeclareBit('min', 'Building minimal set of projects')

-DeclareBit('all', 'Building all Projects')

-DeclareBit('msvs', 'Building Visual Studio solution files')

-

-# Build official installers if --official_installers is on the command line.

-win_env.SetBitFromOption('official_installers', False)

-

-# Build as a build server if --build_server is on the command line.

-win_env.SetBitFromOption('build_server', False)

-

-# Build from pre-built binaries if --bin is on the command line.

-win_env.SetBitFromOption('bin', False)

-

-# Build minimal set of libs if --min is on the command line.

-win_env.SetBitFromOption('min', False)

-

-# Build all libs if --all is on the command line.

-win_env.SetBitFromOption('all', False)

-

-# Build Visual Studio solution files if --msvs is on the command line.

-win_env.SetBitFromOption('msvs', False)

-

-# Also build all directories if this is the build server.

-if win_env.Bit('build_server'):

-  win_env.SetBits('all')

-

-# Make sure 'all' overrides 'min'.

-if win_env.Bit('all'):

-  win_env.ClearBits('min')

-

-# Allow use of command-line-specified certificates to sign with, but

-# only if we're not on the build server.

-if not win_env.Bit('build_server'):

-  win_env.Replace(

-    CERTIFICATE_PATH=GetOption('authenticode_file'),

-    CERTIFICATE_PASSWORD=GetOption('authenticode_password'),

-  )

-

-  # Store whether we're using the default test cert separately, because

-  # we won't always know what the default password was.

-  if GetOption('authenticode_password') is default_cert_password:

-    win_env.SetBits('test_certificate')

-

-

-# The precompiled headers are to be used as an optional build speed up

-# build facility. Individual compilation units in the project must build with

-# or without precompiled headers. Building without precompiled headers is sort

-# of meaningless, since all the time we should build with it. However,

-# eliminating the dependency is desirable from a few reasons:

-# 1. making sure the files in the project include all the definitions they need

-# 2. creating different precompile headers if needed.

-# 3. making sure the precompile headers do not add to the size bloat.

-# There are two current limitations with the current setup.

-# First, due to pushing the warning level to W4 and WAll, we rely on the

-# common precompile.h to properly turn off the warnings inside system and

-# library code.

-# Second, to override the ATLASSERT, a file must be included before any of

-# the atl headers. To do this on a case by case basis is impractical and

-# error prone.

-# Therefore, when building with precompile headers off, the code is

-# building on W3 and it is not taking over the ATL asserts.

-win_env.SetBitFromOption('use_precompiled_headers', True)

-

-if win_env.Bit('use_precompiled_headers'):

-  print 'Using precompiled headers.'

-

-def _EnablePrecompile(self_env, target_name):

-  if self_env.Bit('use_precompiled_headers'):

-

-    # We enable all warnings on all levels. The goal is to fix the code that

-    # we have written and to programmatically disable the warnings for the

-    # code we do not control. This list of warnings should shrink as the code

-    # gets fixed.

-    self_env.FilterOut(CCFLAGS=['/W3'])

-    self_env.Append(

-        CCFLAGS = [

-            '/W4',

-            '/Wall',

-            ],

-        INCLUDES = [

-            '$MAIN_DIR/precompile/precompile.h'

-            ],

-    )

-

-    self_env['PCHSTOP'] = '$MAIN_DIR/precompile/precompile.h'

-

-    pch_env = self_env.Clone()

-    # Must manually force-include the header, as the precompilation step does

-    # not evaluate $INCLUDES

-    pch_env.Append(CCFLAGS = ['/FI$MAIN_DIR/precompile/precompile.h'])

-    pch_output = pch_env.PCH(

-        target=target_name.replace('.', '_') + '.pch',

-        source='$MAIN_DIR/precompile/precompile.cc',

-    )

-

-    self_env['PCH'] = pch_output[0]

-

-    # Return the pch .obj file that is created, so it can be

-    # included with the inputs of a module

-    return [pch_output[1]]

-

-win_env.AddMethod(_EnablePrecompile, 'EnablePrecompile')

-

-

-def _SetProductVersion(self_env,

-                       version_major,

-                       version_minor,

-                       version_build,

-                       version_patch):

-  build_two_versions = False

-

-  if (self_env.Bit('build_server') or

-      'OMAHA_BUILD_TWO_VERSIONS' in os.environ.keys()):

-    build_two_versions = True

-

-  if build_two_versions:

-    self_env['product_version_series'] = [0, 1]

-  else:

-    self_env['product_version_series'] = [0]

-

-  if version_patch > 0:

-    original_value = version_patch

-    value_name = 'patch'

-  else:

-    original_value = version_build

-    value_name = 'build'

-  if 2 * (original_value / 2) == original_value:

-    raise Exception('ERROR: By convention, the %s number in VERSION '

-      '(currently %d) should be odd.' % (value_name, original_value))

-

-  ver_descriptions = []

-  versions = []

-  for delta in self_env['product_version_series']:

-    # If we're doing a patch, increment that; else, increment build

-    vp = version_patch

-    vb = version_build

-    if vp > 0:

-      vp = vp + delta

-    else:

-      vb = vb + delta

-    v = (version_major, version_minor, vb, vp)

-    versions.append(v)

-    ver_descriptions.append('%d.%d.%d.%d' %

-        (version_major, version_minor, vb, vp))

-

-  self_env['product_version'] = versions

-

-  # print the version string so we know what build are we building on the

-  # build server

-  print 'Working on versions: %s' % ', '.join(ver_descriptions)

-

-win_env.AddMethod(_SetProductVersion, 'SetProductVersion')

-win_env.SetProductVersion(version_major, version_minor, version_build, version_patch)

-

-

-win_env['msc_ver'] = _msc_ver;

-

-

-# Plug-in versioning. Firefox Plug-in needs a different filename for each

-# version of the plug-in. If the filename is the same, even though the path

-# is different, Firefox decides not to load the new DLL if it has the old DLL

-# loaded in memory.

-def _SetActiveXFilenames(self_env, activex_version):

-  activex_name = _ACTIVEX_NAME + activex_version

-  self_env['ACTIVEX_FILENAME'] = activex_name + '.dll'

-  self_env['ACTIVEX_UNSIGNED_FILENAME'] = activex_name + '_unsigned.dll'

-

-win_env.AddMethod(_SetActiveXFilenames, 'SetActiveXFilenames')

-win_env.SetActiveXFilenames(oneclick_plugin_version)

-

-

-# BHO settings.

-win_env['BHO_FILENAME'] = '%s.dll' % (_BHO_NAME)

-win_env['BHO_UNSIGNED_FILENAME'] = '%s_unsigned.dll' % (_BHO_NAME)

-

-

-win_env.Append(

-    # Add windows specific compiler flags.

-    CCFLAGS = [

-        '/nologo',

-        '/c',

-        '/Zc:forScope',

-        '/D_HAS_EXCEPTIONS=0',

-        '/DCOMPILER_MSVC',

-        '/J',

-        '/DSTL_MSVC',

-        '/GR-',

-        '/D_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=1',

-        '/D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1',

-        '/D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1',

-        '/WX',      # warnings as errors

-

-        #

-        # Disable the following level 4 warnings below.

-        #

-        '/wd4127',  # conditional expression is constant

-        '/wd4189',  # local variable is initialized but not referenced

-        '/wd4505',  # unreferenced local function has been removed

-

-        #

-        # Disable the pedantic warnings below.

-        #

-        '/wd4191',  # unsafe conversion from 'type of expression' to

-                    #     'type required'

-        '/wd4217',  # member template functions cannot be used for

-                    #     copy-assignment...

-        '/wd4365',  # conversion from 'type_1' to 'type_2',

-                    #     signed/unsigned mismatch

-        '/wd4512',  # assignment operator could not be generated

-        '/wd4514',  # unreferenced inline function has been removed

-        '/wd4555',  # expression has no effect

-        '/wd4619',  # #pragma warning : there is no warning number 'number'

-        '/wd4623',  # default constructor could not be generated...

-        '/wd4625',  # copy constructor could not be generated...

-        '/wd4626',  # assignment operator could not be generated...

-        '/wd4668',  # not defined as a preprocessor macro, replacing with '0'.

-        '/wd4710',  # function not inlined

-        '/wd4711',  # function 'function' selected for inline expansion

-        '/wd4738',  # storing 32-bit float result in memory...

-        '/wd4820',  # bytes padding added after construct 'member_name'

-        ],

-

-    # Where to look for include files.

-    CPPPATH = [

-        '$MAIN_DIR',

-        '$MAIN_DIR/..',

-        '$MAIN_DIR/third_party/chrome',

-        ],

-

-    # Defines for windows environment.

-    CPPDEFINES = [

-        'WIN32', '_WINDOWS',

-        'UNICODE', '_UNICODE',

-        'WIN32_LEAN_AND_MEAN',

-        'STRICT',

-        'SECURITY_WIN32',

-        '_ATL_ALL_WARNINGS',

-        '_ATL_CSTRING_EXPLICIT_CONSTRUCTORS',

-        '_ATL_CSTRING_NO_CRT',

-        '_ATL_NO_ACLAPI',

-        '_ATL_NO_DEFAULT_LIBS',

-        '_ATL_NO_EXCEPTIONS',

-        '_ATL_NO_GLOBAL_SOCKET_STARTUP',

-        '_ATL_NO_PERF_SUPPORT',

-        '_ATL_NO_TRACK_HEAP',

-        '_ATL_NO_UUIDOF',

-        '_CRT_RAND_S',      # rand_s support available in Windows XP only.

-        '_WTL_NO_CSTRING',  # WTL uses ATL CString instead.

-

-        # '_ATL_NO_CONNECTION_POINTS',

-        # '_ATL_NO_DOCHOSTUIHANDLER',

-        # '_ATL_NO_HOSTING',

-

-        # Set these C_DEFINES when APPVER=5.0

-        # (see win32.mak in Platform SDK)

-        # Target Windows XP and IE 6.0 and above.

-        'WINVER=0x0501',

-        '_WIN32_WINNT=0x0501',

-        '_WIN32_IE=0x0600',

-        '_RICHEDIT_VER=0x0010',

-

-        # don't define min and max in windef.h

-        'NOMINMAX',

-

-        # Logging is enabled in all modes for

-        # diagnostics purposes.

-        'LOGGING',

-        'PUBLISHER_NAME_ANSI=\\"%s\\"' % _PUBLISHER_NAME,

-        'PRODUCT_NAME_ANSI=\\"%s\\"' % _PRODUCT_NAME,

-        'ACTIVEX_NAME=_T(\\"%s\\")' % _ACTIVEX_NAME,

-        'PROXY_CLSID_IS=%s' % _PROXY_CLSID_IS,

-        'OFFICIAL_BUILD=%d' % win_env.Bit('build_server'),

-        'TEST_CERTIFICATE=%d' % win_env.Bit('test_certificate'),

-        'ACTIVEX_FILENAME=_T(\\"%s\\")' % win_env['ACTIVEX_FILENAME'],

-        'ACTIVEX_VERSION_ANSI=\\"%s\\"' % oneclick_plugin_version,

-        'BHO_NAME=_T(\\"%s\\")' % _BHO_NAME,

-        'BHO_FILENAME=_T(\\"%s\\")' % win_env['BHO_FILENAME'],

-        ],

-

-    # Link in some windows libraries.

-    LIBS = [

-        'advapi32',

-        'comdlg32',

-        'gdi32',

-        'kernel32',

-        'odbc32',

-        'odbccp32',

-        'ole32',

-        'oleaut32',

-        'shell32',

-        'user32',

-        'uuid',

-        'winspool',

-        ],

-

-    # Common linker flags.

-    LINKFLAGS = [

-        '/nologo',

-        '/SUBSYSTEM:WINDOWS',

-        '/MACHINE:X86',

-        '/RELEASE',

-        '/MAP',

-        '/NODEFAULTLIB',

-        ],

-

-    # Shared library specific linker flags.

-    SHLINKFLAGS = [

-        '/nologo',

-        '/SUBSYSTEM:WINDOWS',

-        '/MACHINE:x86',

-        ],

-

-    # Resource compiler flags.

-    RCFLAGS = [

-        '/l 1033',  # /l == default language ID

-        '/DOFFICIAL_BUILD=%d' % win_env.Bit('build_server'),

-        '/DPUBLISHER_NAME_ANSI=\\"%s\\"' % _PUBLISHER_NAME,

-        '/DPRODUCT_NAME_ANSI=\\"%s\\"' % _PRODUCT_NAME,

-        '/DACTIVEX_NAME=_T(\\"%s\\")' % _ACTIVEX_NAME,

-        '/DACTIVEX_FILENAME=_T(\\"%s\\")' % win_env['ACTIVEX_FILENAME'],

-        '/DACTIVEX_VERSION_ANSI=\\"%s\\"' % oneclick_plugin_version,

-        '/DBHO_NAME=_T(\\"%s\\")' % _BHO_NAME,

-        '/DBHO_FILENAME=_T(\\"%s\\")' % win_env['BHO_FILENAME'],

-        ],

-)

-

-# Allow verification of these settings in the build log.

-if win_env.Bit('build_server'):

-  print 'OFFICIAL_BUILD=1'

-  print 'TEST_CERTIFICATE=%d' % win_env.Bit('test_certificate')

-

-

-# List of languages that we compile in.

-win_env['languages'] = [

-    'ar',

-    'bg',

-    'bn',

-    'ca',

-    'cs',

-    'da',

-    'de',

-    'el',

-    'en',

-    'en-GB',

-    'es',

-    'es-419',

-    'et',

-    'fa',

-    'fi',

-    'fil',

-    'fr',

-    'gu',

-    'hi',

-    'hr',

-    'hu',

-    'id',

-    'is',

-    'it',

-    'iw',

-    'ja',

-    'kn',

-    'ko',

-    'lt',

-    'lv',

-    'ml',

-    'mr',

-    'ms',

-    'nl',

-    'no',

-    'or',

-    'pl',

-    'pt-BR',

-    'pt-PT',

-    'ro',

-    'ru',

-    'sk',

-    'sl',

-    'sr',

-    'sv',

-    'ta',

-    'te',

-    'th',

-    'tr',

-    'uk',

-    'ur',

-    'vi',

-    'zh-CN',

-    'zh-TW',

-    ]

-

-# Make sure python.exe can be located.

-win_env.AppendENVPath('PATH', os.environ['OMAHA_PYTHON_DIR'])

-

-# Make sure Vista SDK in all the important paths earlier in path than VC80.

-_sdk_path = os.environ['OMAHA_VISTASDK_DIR']

-for mid_dir in ['', 'vc']:

-  for env_var, sub_dir in [('PATH', 'bin'),

-                           ('INCLUDE', 'include'),

-                           ('LIB', 'lib')]:

-    var_path = os.path.join(_sdk_path, mid_dir, sub_dir)

-    if os.path.exists(var_path):

-      win_env.PrependENVPath(env_var, var_path)

-

-if not win_env.Bit('official_installers'):

-  win_env.Append(CPPPATH = os.environ['OMAHA_WTL_DIR'])

-

-  # Make sure csc.exe can be located.

-  win_env.AppendENVPath('PATH', os.environ['OMAHA_NET_DIR'])

-

-  # WiX path has to be added before the WiX tool can be called.

-  win_env.AppendENVPath('PATH', os.environ['OMAHA_WIX_DIR'])

-  win_env.Tool('wix')

-

-

-_base_dirs = [

-    '.',      # ./build.scons is used to copy some files to staging.

-    'common',

-    'core',

-    'goopdate',

-    'google_update',

-    'mi_exe_stub',

-    'net',

-    'recovery',

-    'service',

-    'setup',

-    'statsreport',

-    'testing',

-    'third_party',

-    'tools',

-    'worker',

-    ]

-

-_normal_dirs = [

-    'bho',

-    'clickonce',

-    'installers',

-    'standalone',

-    'plugins',

-    ]

-

-_official_installers_dirs = [

-    'enterprise',

-    'installers',

-    ]

-

-_extra_dirs = [

-    'enterprise',

-    'test',

-    ]

-

-#

-# Need to decide which subdirs need to be built.

-#

-_dirs_to_build = set()

-

-if win_env.Bit('official_installers'):

-  # Only want to build very specific subdirs.

-  _dirs_to_build.update(_official_installers_dirs)

-elif not win_env.Bit('bin'):

-  # All other configs get the base dirs.

-  _dirs_to_build.update(_base_dirs)

-

-  if win_env.Bit('min'):

-    print '*** Building Minimal Set of Projects ***'

-  else:

-    _dirs_to_build.update(_normal_dirs)

-

-  if win_env.Bit('all'):

-    _dirs_to_build.update(_extra_dirs)

-

-# Build Google application-specific metainstallers.

-if os.path.exists(win_env.Dir('$MAIN_DIR/internal').abspath):

-  _dirs_to_build.update(['internal'])

-

-# Instruct Hammer which dirs to build.

-win_env['BUILD_SCONSCRIPTS'] = list(_dirs_to_build)

-

-# Create the leaf debug Windows environment.

-windows_debug_env = win_env.Clone(

-    # Give this build a name and a description.

-    BUILD_TYPE = 'dbg-win',

-    BUILD_TYPE_DESCRIPTION = 'Windows debug build',

-)

-

-# Use common debug settings.

-windows_debug_env.Tool('target_debug')

-

-windows_debug_env.Append(

-    CCFLAGS = [

-        '/RTC1',

-        '/Od',

-        '/MTd',

-        ],

-    CPPDEFINES = [

-        '_DEBUG',

-        'DEBUG',

-        ],

-)

-

-

-# Create the leaf optimized Windows environment.

-windows_optimized_env = win_env.Clone(

-    # Give this build a name and a description.

-    BUILD_TYPE = 'opt-win',

-    BUILD_TYPE_DESCRIPTION = 'Windows optimized build',

-)

-

-# Use common optimized settings.

-windows_optimized_env.Tool('target_optimized')

-

-windows_optimized_env.Append(

-    CCFLAGS = [

-        '/O1',        # Optimize for small size.

-        '/GS',

-        '/FD',

-        '/GL',        # Global optimization goes with link flag '/LTCG'

-        '/MT',

-        ],

-    CPPDEFINES = [

-        'NDEBUG',

-        'SHIPPING'    # code in 'common' needs this

-        ],

-    ARFLAGS = [

-        '/LTCG',      # Set LTCG for creation of .lib files too.

-        ],

-    LINKFLAGS = [

-        '/incremental:no',

-        '/opt:ref',

-        '/opt:icf=32',

-        '/opt:nowin98',

-        '/LTCG',      # Link-time code generation goes with cl flag '/GL'

-        ],

-)

-

-

-# Create an environment for coverage test builds, based on the dbg build.

-windows_coverage_env = windows_debug_env.Clone(

-    BUILD_TYPE = 'coverage-win',

-    BUILD_TYPE_DESCRIPTION = 'Windows coverage build',

-)

-# The Coverage build require additional tools that not everyone has. Therefore,

-# it should build as part of the all group.

-windows_coverage_env.FilterOut(BUILD_GROUPS=['all'])

-

-windows_coverage_env.Tool('code_coverage')

-

-# Coverage will run omaha_unittest.exe, which requires some extra environment.

-for env_var in os.environ:

-  if not env_var in windows_coverage_env['ENV']:

-    windows_coverage_env['ENV'][env_var] = os.environ[env_var]

-

-# Create a target that covers everything in the staging dir, as many of those

-# files will be required for the unittests to run successfully.

-windows_coverage_env.Alias(

-    'run_omaha_unittest',

-    '$STAGING_DIR',

-    '$STAGING_DIR/omaha_unittest.exe'

-)

-windows_coverage_env.Append(

-    COVERAGE_TARGETS=['run_omaha_unittest'],

-    COVERAGE_INSTRUMENTATION_PATHS=['$STAGING_DIR'],

-    CPPDEFINES=['COVERAGE_ENABLED'],

-)

-

-# Make debug the default build after any copies of it have been made.

-windows_debug_env.Append(BUILD_GROUPS = ['default'])

-

-# ----------------------------------------------------------

-

-# Build the variants listed above.

-# This step will call each of the SConscripts (build.scons) listed,

-# once for each variant currently being built.

-BuildEnvironments(

-    [ windows_debug_env,

-      windows_optimized_env,

-      windows_coverage_env,

-    ]

-)

-

-if win_env.Bit('msvs'):

-  source_project = win_env.ComponentVSDirProject('all_source', ['$MAIN_DIR'])

-

-  # 'all_*' values do not appear to be populated until after BuildEnvironments

-  # is called. Thus, the solution will be specific to either debug or optimized.

-  # ComponentVSSourceProject() might be more desirable, but it does not appear

-  # to work.

-  windows_debug_env.ComponentVSSolution('omaha_dbg',

-                                        ['all_programs', 'all_libraries'],

-                                        projects=[source_project])

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+# This main.scons file is the root description of the build specified in this
+# directory and those under it. Individual components and the source files
+# used to build them are described in subsidiary files called 'build.scons'.
+#
+# To build this project change the current directory to googleclient/Omaha.
+# Then run hammer.bat
+#
+# A number of command line options can be specified. For a full list, use the
+# -h and -H command options.
+#
+# Some useful options include:
+#   -h   :   Prints a list of which modules and build variants are available
+#            in this project.
+#   -H   :   Print SCons specific help. SCons is a build tool which this
+#            project uses in tandem with the Software Construction Toolkit
+#            to build.
+#   -c   :   Clean the project. I.e. delete all build output.
+#   -j3  :   Run up to 3 build steps at once.
+#
+# Some useful build targets include:
+#    all_programs    :   Build all programs generated by this project.
+#    all_libraries   :   Build all libraries generated by this project.
+#    all_tests       :   Build all tests generated by this project.
+#    run_all_tests   :   Build and run all tests generated by this project.
+#
+# Some examples:
+#   Build all programs and libraries in debug mode:
+#     hammer
+#   Build and run all tests in debug mode on windows:
+#     hammer MODE=dbg-win run_all_tests
+#   Build arbitrary library in the default mode:
+#     hammer <library name>
+
+import os
+
+# To switch the build, simply change the value of the msc_ver variable below.
+# VC2003/VC71 is 1310 but not supported by the current build.
+# VC2005/VC80 is 1400.
+# VC2008/VC90 is 1500.
+_msc_ver = 1400
+
+# TODO(Omaha) - Change this to match the official product name
+_PUBLISHER_NAME = 'Google'
+_PRODUCT_NAME = 'Update'
+_ACTIVEX_NAME = 'npGoogleOneClick'
+_BHO_NAME = 'GoopdateBho'
+
+# COM proxy setting.
+# The proxy clsid needs to be changed anytime the interfaces in
+# google_update_idl.idl change, or when a new interface is added. Use
+# guidgen.exe to generate new clsids in the format 'static const struct GUID'.
+# PROXY_CLSID_IS = {29A96789-9595-4947-BEDB-0FCC776F7DB8}
+_PROXY_CLSID_IS = ('{0x29a96789, 0x9595, 0x4947, '
+    '{0xbe, 0xdb, 0xf, 0xcc, 0x77, 0x6f, 0x7d, 0xb8}}')
+
+#
+# Set up version info
+#
+execfile('VERSION')
+
+
+# Windows is the only environment we bulid for, so create a specialized base
+# environment for Windows.
+win_env = Environment()
+
+# Make sure we use the Vista SDK.
+# NOTE: This must be set before the 'component_setup' tool is used.
+win_env['PLATFORM_SDK_DIR'] = '$PLATFORM_SDK_VISTA_6_0_DIR'
+
+win_env.Tool('component_setup')
+win_env.Tool('target_platform_windows')
+
+# Need to use 'masm' to override the 'as' tool currently used
+# by default in 'target_platform_windows'
+win_env.Tool('masm')
+
+win_env.Tool('atlmfc_vc80')
+
+# Visual Studio 2008 does not ship the sign tool. Use the sign tool from
+# the Platform SDK.
+win_env.Tool('code_signing')
+_signtool_path = os.path.join(os.environ['OMAHA_VISTASDK_DIR'],
+                             'bin\\signtool.exe')
+win_env['SIGNTOOL'] = '"' + _signtool_path + '"'
+
+# Remove this value because it conflicts with a #define
+# in shlwapi.h in the Vista SDK
+win_env.FilterOut(CPPDEFINES = ['OS_WINDOWS=OS_WINDOWS'])
+
+win_env.Tool('component_targets_msvs')
+
+# We pre-generate our own manifests, so make sure hammer does not generate
+# default ones for us
+del win_env['MANIFEST_FILE']
+
+# Hack to work around bug in Hammer (http://b/1585388).
+# TODO(Omaha): Remove when bug is fixed.
+if win_env['ENV'].has_key('SYSTEMROOT'):
+  if win_env['ENV'].has_key('SystemRoot'):
+    del win_env['ENV']['SYSTEMROOT']
+    del os.environ['SYSTEMROOT']
+
+
+# Declare command line options relating to code signing
+AddOption(
+    '--authenticode_file',
+    action='store',
+    nargs=1,
+    type='string',
+    default='$MAIN_DIR/data/OmahaTestCert.pfx'
+)
+
+default_cert_password = 'test'
+AddOption(
+    '--authenticode_password',
+    action='store',
+    nargs=1,
+    type='string',
+    default=default_cert_password
+)
+
+# Declare option for specifying path to new official build files
+AddOption(
+    '--official_build_path',
+    action='store',
+    nargs=1,
+    type='string',
+    default=None
+)
+
+# Declare various boolean states.
+DeclareBit('use_precompiled_headers', 'Use precompiled headers in build')
+DeclareBit('official_installers', 'Building using checked-in binaries')
+DeclareBit('build_server', 'Running on the build server')
+DeclareBit('test_certificate', 'Files will be signed with the test certificate')
+DeclareBit('bin', 'Building from pre-built binaries')
+DeclareBit('min', 'Building minimal set of projects')
+DeclareBit('all', 'Building all Projects')
+DeclareBit('msvs', 'Building Visual Studio solution files')
+
+# Build official installers if --official_installers is on the command line.
+win_env.SetBitFromOption('official_installers', False)
+
+# Build as a build server if --build_server is on the command line.
+win_env.SetBitFromOption('build_server', False)
+
+# Build from pre-built binaries if --bin is on the command line.
+win_env.SetBitFromOption('bin', False)
+
+# Build minimal set of libs if --min is on the command line.
+win_env.SetBitFromOption('min', False)
+
+# Build all libs if --all is on the command line.
+win_env.SetBitFromOption('all', False)
+
+# Build Visual Studio solution files if --msvs is on the command line.
+win_env.SetBitFromOption('msvs', False)
+
+# Also build all directories if this is the build server.
+if win_env.Bit('build_server'):
+  win_env.SetBits('all')
+
+# Make sure 'all' overrides 'min'.
+if win_env.Bit('all'):
+  win_env.ClearBits('min')
+
+# Allow use of command-line-specified certificates to sign with, but
+# only if we're not on the build server.
+if not win_env.Bit('build_server'):
+  win_env.Replace(
+    CERTIFICATE_PATH=GetOption('authenticode_file'),
+    CERTIFICATE_PASSWORD=GetOption('authenticode_password'),
+  )
+
+  # Store whether we're using the default test cert separately, because
+  # we won't always know what the default password was.
+  if GetOption('authenticode_password') is default_cert_password:
+    win_env.SetBits('test_certificate')
+
+
+# The precompiled headers are to be used as an optional build speed up
+# build facility. Individual compilation units in the project must build with
+# or without precompiled headers. Building without precompiled headers is sort
+# of meaningless, since all the time we should build with it. However,
+# eliminating the dependency is desirable from a few reasons:
+# 1. making sure the files in the project include all the definitions they need
+# 2. creating different precompile headers if needed.
+# 3. making sure the precompile headers do not add to the size bloat.
+# There are two current limitations with the current setup.
+# First, due to pushing the warning level to W4 and WAll, we rely on the
+# common precompile.h to properly turn off the warnings inside system and
+# library code.
+# Second, to override the ATLASSERT, a file must be included before any of
+# the atl headers. To do this on a case by case basis is impractical and
+# error prone.
+# Therefore, when building with precompile headers off, the code is
+# building on W3 and it is not taking over the ATL asserts.
+win_env.SetBitFromOption('use_precompiled_headers', True)
+
+if win_env.Bit('use_precompiled_headers'):
+  print 'Using precompiled headers.'
+
+def _EnablePrecompile(self_env, target_name):
+  if self_env.Bit('use_precompiled_headers'):
+
+    # We enable all warnings on all levels. The goal is to fix the code that
+    # we have written and to programmatically disable the warnings for the
+    # code we do not control. This list of warnings should shrink as the code
+    # gets fixed.
+    self_env.FilterOut(CCFLAGS=['/W3'])
+    self_env.Append(
+        CCFLAGS = [
+            '/W4',
+            '/Wall',
+            ],
+        INCLUDES = [
+            '$MAIN_DIR/precompile/precompile.h'
+            ],
+    )
+
+    self_env['PCHSTOP'] = '$MAIN_DIR/precompile/precompile.h'
+
+    pch_env = self_env.Clone()
+    # Must manually force-include the header, as the precompilation step does
+    # not evaluate $INCLUDES
+    pch_env.Append(CCFLAGS = ['/FI$MAIN_DIR/precompile/precompile.h'])
+    pch_output = pch_env.PCH(
+        target=target_name.replace('.', '_') + '.pch',
+        source='$MAIN_DIR/precompile/precompile.cc',
+    )
+
+    self_env['PCH'] = pch_output[0]
+
+    # Return the pch .obj file that is created, so it can be
+    # included with the inputs of a module
+    return [pch_output[1]]
+
+win_env.AddMethod(_EnablePrecompile, 'EnablePrecompile')
+
+
+def _SetProductVersion(self_env,
+                       version_major,
+                       version_minor,
+                       version_build,
+                       version_patch):
+  build_two_versions = False
+
+  if (self_env.Bit('build_server') or
+      'OMAHA_BUILD_TWO_VERSIONS' in os.environ.keys()):
+    build_two_versions = True
+
+  if build_two_versions:
+    self_env['product_version_series'] = [0, 1]
+  else:
+    self_env['product_version_series'] = [0]
+
+  if version_patch > 0:
+    original_value = version_patch
+    value_name = 'patch'
+  else:
+    original_value = version_build
+    value_name = 'build'
+  if 2 * (original_value / 2) == original_value:
+    raise Exception('ERROR: By convention, the %s number in VERSION '
+      '(currently %d) should be odd.' % (value_name, original_value))
+
+  ver_descriptions = []
+  versions = []
+  for delta in self_env['product_version_series']:
+    # If we're doing a patch, increment that; else, increment build
+    vp = version_patch
+    vb = version_build
+    if vp > 0:
+      vp = vp + delta
+    else:
+      vb = vb + delta
+    v = (version_major, version_minor, vb, vp)
+    versions.append(v)
+    ver_descriptions.append('%d.%d.%d.%d' %
+        (version_major, version_minor, vb, vp))
+
+  self_env['product_version'] = versions
+
+  # print the version string so we know what build are we building on the
+  # build server
+  print 'Working on versions: %s' % ', '.join(ver_descriptions)
+
+win_env.AddMethod(_SetProductVersion, 'SetProductVersion')
+win_env.SetProductVersion(version_major, version_minor, version_build, version_patch)
+
+
+win_env['msc_ver'] = _msc_ver;
+
+
+# Plug-in versioning. Firefox Plug-in needs a different filename for each
+# version of the plug-in. If the filename is the same, even though the path
+# is different, Firefox decides not to load the new DLL if it has the old DLL
+# loaded in memory.
+def _SetActiveXFilenames(self_env, activex_version):
+  activex_name = _ACTIVEX_NAME + activex_version
+  self_env['ACTIVEX_FILENAME'] = activex_name + '.dll'
+  self_env['ACTIVEX_UNSIGNED_FILENAME'] = activex_name + '_unsigned.dll'
+
+win_env.AddMethod(_SetActiveXFilenames, 'SetActiveXFilenames')
+win_env.SetActiveXFilenames(oneclick_plugin_version)
+
+
+# BHO settings.
+win_env['BHO_FILENAME'] = '%s.dll' % (_BHO_NAME)
+win_env['BHO_UNSIGNED_FILENAME'] = '%s_unsigned.dll' % (_BHO_NAME)
+
+
+win_env.Append(
+    # Add windows specific compiler flags.
+    CCFLAGS = [
+        '/nologo',
+        '/c',
+        '/Zc:forScope',
+        '/D_HAS_EXCEPTIONS=0',
+        '/DCOMPILER_MSVC',
+        '/J',
+        '/DSTL_MSVC',
+        '/GR-',
+        '/D_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=1',
+        '/D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1',
+        '/D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1',
+        '/WX',      # warnings as errors
+
+        #
+        # Disable the following level 4 warnings below.
+        #
+        '/wd4127',  # conditional expression is constant
+        '/wd4189',  # local variable is initialized but not referenced
+        '/wd4505',  # unreferenced local function has been removed
+
+        #
+        # Disable the pedantic warnings below.
+        #
+        '/wd4191',  # unsafe conversion from 'type of expression' to
+                    #     'type required'
+        '/wd4217',  # member template functions cannot be used for
+                    #     copy-assignment...
+        '/wd4365',  # conversion from 'type_1' to 'type_2',
+                    #     signed/unsigned mismatch
+        '/wd4512',  # assignment operator could not be generated
+        '/wd4514',  # unreferenced inline function has been removed
+        '/wd4555',  # expression has no effect
+        '/wd4619',  # #pragma warning : there is no warning number 'number'
+        '/wd4623',  # default constructor could not be generated...
+        '/wd4625',  # copy constructor could not be generated...
+        '/wd4626',  # assignment operator could not be generated...
+        '/wd4668',  # not defined as a preprocessor macro, replacing with '0'.
+        '/wd4710',  # function not inlined
+        '/wd4711',  # function 'function' selected for inline expansion
+        '/wd4738',  # storing 32-bit float result in memory...
+        '/wd4820',  # bytes padding added after construct 'member_name'
+        ],
+
+    # Where to look for include files.
+    CPPPATH = [
+        '$MAIN_DIR',
+        '$MAIN_DIR/..',
+        '$MAIN_DIR/third_party/chrome',
+        ],
+
+    # Defines for windows environment.
+    CPPDEFINES = [
+        'WIN32', '_WINDOWS',
+        'UNICODE', '_UNICODE',
+        'WIN32_LEAN_AND_MEAN',
+        'STRICT',
+        'SECURITY_WIN32',
+        '_ATL_ALL_WARNINGS',
+        '_ATL_CSTRING_EXPLICIT_CONSTRUCTORS',
+        '_ATL_CSTRING_NO_CRT',
+        '_ATL_NO_ACLAPI',
+        '_ATL_NO_DEFAULT_LIBS',
+        '_ATL_NO_EXCEPTIONS',
+        '_ATL_NO_GLOBAL_SOCKET_STARTUP',
+        '_ATL_NO_PERF_SUPPORT',
+        '_ATL_NO_TRACK_HEAP',
+        '_ATL_NO_UUIDOF',
+        '_CRT_RAND_S',      # rand_s support available in Windows XP only.
+        '_WTL_NO_CSTRING',  # WTL uses ATL CString instead.
+
+        # '_ATL_NO_CONNECTION_POINTS',
+        # '_ATL_NO_DOCHOSTUIHANDLER',
+        # '_ATL_NO_HOSTING',
+
+        # Set these C_DEFINES when APPVER=5.0
+        # (see win32.mak in Platform SDK)
+        # Target Windows XP and IE 6.0 and above.
+        'WINVER=0x0501',
+        '_WIN32_WINNT=0x0501',
+        '_WIN32_IE=0x0600',
+        '_RICHEDIT_VER=0x0010',
+
+        # don't define min and max in windef.h
+        'NOMINMAX',
+
+        # Logging is enabled in all modes for
+        # diagnostics purposes.
+        'LOGGING',
+        'PUBLISHER_NAME_ANSI=\\"%s\\"' % _PUBLISHER_NAME,
+        'PRODUCT_NAME_ANSI=\\"%s\\"' % _PRODUCT_NAME,
+        'ACTIVEX_NAME=_T(\\"%s\\")' % _ACTIVEX_NAME,
+        'PROXY_CLSID_IS=%s' % _PROXY_CLSID_IS,
+        'OFFICIAL_BUILD=%d' % win_env.Bit('build_server'),
+        'TEST_CERTIFICATE=%d' % win_env.Bit('test_certificate'),
+        'ACTIVEX_FILENAME=_T(\\"%s\\")' % win_env['ACTIVEX_FILENAME'],
+        'ACTIVEX_VERSION_ANSI=\\"%s\\"' % oneclick_plugin_version,
+        'BHO_NAME=_T(\\"%s\\")' % _BHO_NAME,
+        'BHO_FILENAME=_T(\\"%s\\")' % win_env['BHO_FILENAME'],
+        ],
+
+    # Link in some windows libraries.
+    LIBS = [
+        'advapi32',
+        'comdlg32',
+        'gdi32',
+        'kernel32',
+        'odbc32',
+        'odbccp32',
+        'ole32',
+        'oleaut32',
+        'shell32',
+        'user32',
+        'uuid',
+        'winspool',
+        ],
+
+    # Common linker flags.
+    LINKFLAGS = [
+        '/nologo',
+        '/SUBSYSTEM:WINDOWS',
+        '/MACHINE:X86',
+        '/RELEASE',
+        '/MAP',
+        '/NODEFAULTLIB',
+        ],
+
+    # Shared library specific linker flags.
+    SHLINKFLAGS = [
+        '/nologo',
+        '/SUBSYSTEM:WINDOWS',
+        '/MACHINE:x86',
+        ],
+
+    # Resource compiler flags.
+    RCFLAGS = [
+        '/l 1033',  # /l == default language ID
+        '/DOFFICIAL_BUILD=%d' % win_env.Bit('build_server'),
+        '/DPUBLISHER_NAME_ANSI=\\"%s\\"' % _PUBLISHER_NAME,
+        '/DPRODUCT_NAME_ANSI=\\"%s\\"' % _PRODUCT_NAME,
+        '/DACTIVEX_NAME=_T(\\"%s\\")' % _ACTIVEX_NAME,
+        '/DACTIVEX_FILENAME=_T(\\"%s\\")' % win_env['ACTIVEX_FILENAME'],
+        '/DACTIVEX_VERSION_ANSI=\\"%s\\"' % oneclick_plugin_version,
+        '/DBHO_NAME=_T(\\"%s\\")' % _BHO_NAME,
+        '/DBHO_FILENAME=_T(\\"%s\\")' % win_env['BHO_FILENAME'],
+        ],
+)
+
+# Allow verification of these settings in the build log.
+if win_env.Bit('build_server'):
+  print 'OFFICIAL_BUILD=1'
+  print 'TEST_CERTIFICATE=%d' % win_env.Bit('test_certificate')
+
+
+# List of languages that we compile in.
+win_env['languages'] = [
+    'ar',
+    'bg',
+    'bn',
+    'ca',
+    'cs',
+    'da',
+    'de',
+    'el',
+    'en',
+    'en-GB',
+    'es',
+    'es-419',
+    'et',
+    'fa',
+    'fi',
+    'fil',
+    'fr',
+    'gu',
+    'hi',
+    'hr',
+    'hu',
+    'id',
+    'is',
+    'it',
+    'iw',
+    'ja',
+    'kn',
+    'ko',
+    'lt',
+    'lv',
+    'ml',
+    'mr',
+    'ms',
+    'nl',
+    'no',
+    'or',
+    'pl',
+    'pt-BR',
+    'pt-PT',
+    'ro',
+    'ru',
+    'sk',
+    'sl',
+    'sr',
+    'sv',
+    'ta',
+    'te',
+    'th',
+    'tr',
+    'uk',
+    'ur',
+    'vi',
+    'zh-CN',
+    'zh-TW',
+    ]
+
+# Make sure python.exe can be located.
+win_env.AppendENVPath('PATH', os.environ['OMAHA_PYTHON_DIR'])
+
+# Make sure Vista SDK in all the important paths earlier in path than VC80.
+_sdk_path = os.environ['OMAHA_VISTASDK_DIR']
+for mid_dir in ['', 'vc']:
+  for env_var, sub_dir in [('PATH', 'bin'),
+                           ('INCLUDE', 'include'),
+                           ('LIB', 'lib')]:
+    var_path = os.path.join(_sdk_path, mid_dir, sub_dir)
+    if os.path.exists(var_path):
+      win_env.PrependENVPath(env_var, var_path)
+
+if not win_env.Bit('official_installers'):
+  win_env.Append(CPPPATH = os.environ['OMAHA_WTL_DIR'])
+
+  # Make sure csc.exe can be located.
+  win_env.AppendENVPath('PATH', os.environ['OMAHA_NET_DIR'])
+
+  # WiX path has to be added before the WiX tool can be called.
+  win_env.AppendENVPath('PATH', os.environ['OMAHA_WIX_DIR'])
+  win_env.Tool('wix')
+
+
+_base_dirs = [
+    '.',      # ./build.scons is used to copy some files to staging.
+    'common',
+    'core',
+    'goopdate',
+    'google_update',
+    'mi_exe_stub',
+    'net',
+    'recovery',
+    'service',
+    'setup',
+    'statsreport',
+    'testing',
+    'third_party',
+    'tools',
+    'worker',
+    ]
+
+_normal_dirs = [
+    'bho',
+    'clickonce',
+    'installers',
+    'standalone',
+    'plugins',
+    ]
+
+_official_installers_dirs = [
+    'enterprise',
+    'installers',
+    ]
+
+_extra_dirs = [
+    'enterprise',
+    'test',
+    ]
+
+#
+# Need to decide which subdirs need to be built.
+#
+_dirs_to_build = set()
+
+if win_env.Bit('official_installers'):
+  # Only want to build very specific subdirs.
+  _dirs_to_build.update(_official_installers_dirs)
+elif not win_env.Bit('bin'):
+  # All other configs get the base dirs.
+  _dirs_to_build.update(_base_dirs)
+
+  if win_env.Bit('min'):
+    print '*** Building Minimal Set of Projects ***'
+  else:
+    _dirs_to_build.update(_normal_dirs)
+
+  if win_env.Bit('all'):
+    _dirs_to_build.update(_extra_dirs)
+
+# Build Google application-specific metainstallers.
+if os.path.exists(win_env.Dir('$MAIN_DIR/internal').abspath):
+  _dirs_to_build.update(['internal'])
+
+# Instruct Hammer which dirs to build.
+win_env['BUILD_SCONSCRIPTS'] = list(_dirs_to_build)
+
+# Create the leaf debug Windows environment.
+windows_debug_env = win_env.Clone(
+    # Give this build a name and a description.
+    BUILD_TYPE = 'dbg-win',
+    BUILD_TYPE_DESCRIPTION = 'Windows debug build',
+)
+
+# Use common debug settings.
+windows_debug_env.Tool('target_debug')
+
+windows_debug_env.Append(
+    CCFLAGS = [
+        '/RTC1',
+        '/Od',
+        '/MTd',
+        ],
+    CPPDEFINES = [
+        '_DEBUG',
+        'DEBUG',
+        ],
+)
+
+
+# Create the leaf optimized Windows environment.
+windows_optimized_env = win_env.Clone(
+    # Give this build a name and a description.
+    BUILD_TYPE = 'opt-win',
+    BUILD_TYPE_DESCRIPTION = 'Windows optimized build',
+)
+
+# Use common optimized settings.
+windows_optimized_env.Tool('target_optimized')
+
+windows_optimized_env.Append(
+    CCFLAGS = [
+        '/O1',        # Optimize for small size.
+        '/GS',
+        '/FD',
+        '/GL',        # Global optimization goes with link flag '/LTCG'
+        '/MT',
+        ],
+    CPPDEFINES = [
+        'NDEBUG',
+        'SHIPPING'    # code in 'common' needs this
+        ],
+    ARFLAGS = [
+        '/LTCG',      # Set LTCG for creation of .lib files too.
+        ],
+    LINKFLAGS = [
+        '/incremental:no',
+        '/opt:ref',
+        '/opt:icf=32',
+        '/opt:nowin98',
+        '/LTCG',      # Link-time code generation goes with cl flag '/GL'
+        ],
+)
+
+
+# Create an environment for coverage test builds, based on the dbg build.
+windows_coverage_env = windows_debug_env.Clone(
+    BUILD_TYPE = 'coverage-win',
+    BUILD_TYPE_DESCRIPTION = 'Windows coverage build',
+)
+# The Coverage build require additional tools that not everyone has. Therefore,
+# it should build as part of the all group.
+windows_coverage_env.FilterOut(BUILD_GROUPS=['all'])
+
+windows_coverage_env.Tool('code_coverage')
+
+# Coverage will run omaha_unittest.exe, which requires some extra environment.
+for env_var in os.environ:
+  if not env_var in windows_coverage_env['ENV']:
+    windows_coverage_env['ENV'][env_var] = os.environ[env_var]
+
+# Create a target that covers everything in the staging dir, as many of those
+# files will be required for the unittests to run successfully.
+windows_coverage_env.Alias(
+    'run_omaha_unittest',
+    '$STAGING_DIR',
+    '$STAGING_DIR/omaha_unittest.exe'
+)
+windows_coverage_env.Append(
+    COVERAGE_TARGETS=['run_omaha_unittest'],
+    COVERAGE_INSTRUMENTATION_PATHS=['$STAGING_DIR'],
+    CPPDEFINES=['COVERAGE_ENABLED'],
+)
+
+# Make debug the default build after any copies of it have been made.
+windows_debug_env.Append(BUILD_GROUPS = ['default'])
+
+# ----------------------------------------------------------
+
+# Build the variants listed above.
+# This step will call each of the SConscripts (build.scons) listed,
+# once for each variant currently being built.
+BuildEnvironments(
+    [ windows_debug_env,
+      windows_optimized_env,
+      windows_coverage_env,
+    ]
+)
+
+if win_env.Bit('msvs'):
+  source_project = win_env.ComponentVSDirProject('all_source', ['$MAIN_DIR'])
+
+  # 'all_*' values do not appear to be populated until after BuildEnvironments
+  # is called. Thus, the solution will be specific to either debug or optimized.
+  # ComponentVSSourceProject() might be more desirable, but it does not appear
+  # to work.
+  windows_debug_env.ComponentVSSolution('omaha_dbg',
+                                        ['all_programs', 'all_libraries'],
+                                        projects=[source_project])
diff --git a/mi_exe_stub/README.txt b/mi_exe_stub/README.txt
index 3e1c211..534f0c6 100644
--- a/mi_exe_stub/README.txt
+++ b/mi_exe_stub/README.txt
@@ -1,3 +1,3 @@
-This directory contains the source needed to build the Omaha meta-installer EXE, which is the installer that installs Omaha. We call it a meta-installer to distinguish it from the Omaha update client, which itself is an installer.

-

+This directory contains the source needed to build the Omaha meta-installer EXE, which is the installer that installs Omaha. We call it a meta-installer to distinguish it from the Omaha update client, which itself is an installer.
+
 This project differs from the mi_msi project solely in that it's an EXE rather than an MSI. Some customers need one, and some need the other.
\ No newline at end of file
diff --git a/mi_exe_stub/build.scons b/mi_exe_stub/build.scons
index 53d9ec5..f2303a5 100644
--- a/mi_exe_stub/build.scons
+++ b/mi_exe_stub/build.scons
@@ -1,111 +1,111 @@
-# Copyright 2008-2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-def AddCommonOptions(env):

-  # Make the target compile mbcs by removing the UNICODE define and defining

-  # MBCS instead.

-  env.FilterOut(CPPDEFINES=['UNICODE', '_UNICODE'])

-  env.Append(

-      CPPDEFINES = [

-          '_MBCS',

-          '_ATL_MIN_CRT',

-          '_ATL_SECURE_NO_DEPRECATE',

-          '_CRT_SECURE_NO_WARNINGS',

-          ],

-      CCFLAGS = [

-          '/D_SECURE_SCL=0',

-          '/D_SECURE_ATL=0',

-          ],

-  )

-

-

-first = 1

-for v in env['product_version']:

-  temp_env = env.Clone()

-  AddCommonOptions(temp_env)

-

-  if first:

-    first = 0

-    prefix = ''

-  else:

-    prefix = 'TEST_'

-    temp_env['OBJPREFIX'] = temp_env['OBJPREFIX'] + 'test/'

-

-  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-  # MI stub links with the minicrt.lib in the non-debug builds.

-  # This gets its size down to about 27K and it saves about 40K in library code

-  temp_env.Append(

-      LIBS = [

-          'lzma.lib',

-          'mi_exe_stub.lib',

-          ('atls.lib',  'atlsd.lib')[temp_env.Bit('debug')],

-          ('minicrt.lib', 'libcmtd.lib')[temp_env.Bit('debug')],

-          ('',          'libcpmtd.lib')[temp_env.Bit('debug')],

-          'shlwapi.lib',

-          'version.lib',

-          ],

-      RCFLAGS = [

-          '/DVERSION_MAJOR=%d' % v[0],

-          '/DVERSION_MINOR=%d' % v[1],

-          '/DVERSION_BUILD=%d' % v[2],

-          '/DVERSION_PATCH=%d' % v[3],

-          '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,

-          '/DLANGUAGE_STRING=\\"%s\\"' % 'en'

-          ],

-

-      # This avoids missing __load_config_used

-      LINKFLAGS = [

-          '/SAFESEH:NO'

-          ],

-  )

-

-

-  exe_inputs = temp_env.RES(

-      target=prefix + 'mi.res',

-      source='mi.rc'

-  )

-

-  # Force a rebuild when the version changes.

-  temp_env.Depends(exe_inputs, '$MAIN_DIR/VERSION')

-

-  for language in env['languages']:

-    base_name = 'mi_generated_resources_' + language

-    exe_inputs += temp_env.RES(

-        target=prefix + base_name + '.res',

-        source=base_name + '.rc',

-    )

-

-  temp_env.ComponentProgram(prefix + 'mi_exe_stub.exe', exe_inputs)

-

-

-local_env = env.Clone()

-AddCommonOptions(local_env)

-

-# Avoid target conflicts over extractor.obj

-local_env['OBJSUFFIX'] = '_mi' + local_env['OBJSUFFIX']

-

-local_inputs = [

-    # "../test/step_test.cc",  # This is commented until dependencies of libs

-                                # are sorted out, such as printf.

-    'mi.cc',

-    'process.cc',

-    'tar.cc',

-    '../common/extractor.cc'

-    ]

-

-local_env.ComponentLibrary('mi_exe_stub', local_inputs)

+# Copyright 2008-2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+def AddCommonOptions(env):
+  # Make the target compile mbcs by removing the UNICODE define and defining
+  # MBCS instead.
+  env.FilterOut(CPPDEFINES=['UNICODE', '_UNICODE'])
+  env.Append(
+      CPPDEFINES = [
+          '_MBCS',
+          '_ATL_MIN_CRT',
+          '_ATL_SECURE_NO_DEPRECATE',
+          '_CRT_SECURE_NO_WARNINGS',
+          ],
+      CCFLAGS = [
+          '/D_SECURE_SCL=0',
+          '/D_SECURE_ATL=0',
+          ],
+  )
+
+
+first = 1
+for v in env['product_version']:
+  temp_env = env.Clone()
+  AddCommonOptions(temp_env)
+
+  if first:
+    first = 0
+    prefix = ''
+  else:
+    prefix = 'TEST_'
+    temp_env['OBJPREFIX'] = temp_env['OBJPREFIX'] + 'test/'
+
+  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+  # MI stub links with the minicrt.lib in the non-debug builds.
+  # This gets its size down to about 27K and it saves about 40K in library code
+  temp_env.Append(
+      LIBS = [
+          'lzma.lib',
+          'mi_exe_stub.lib',
+          ('atls.lib',  'atlsd.lib')[temp_env.Bit('debug')],
+          ('minicrt.lib', 'libcmtd.lib')[temp_env.Bit('debug')],
+          ('',          'libcpmtd.lib')[temp_env.Bit('debug')],
+          'shlwapi.lib',
+          'version.lib',
+          ],
+      RCFLAGS = [
+          '/DVERSION_MAJOR=%d' % v[0],
+          '/DVERSION_MINOR=%d' % v[1],
+          '/DVERSION_BUILD=%d' % v[2],
+          '/DVERSION_PATCH=%d' % v[3],
+          '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,
+          '/DLANGUAGE_STRING=\\"%s\\"' % 'en'
+          ],
+
+      # This avoids missing __load_config_used
+      LINKFLAGS = [
+          '/SAFESEH:NO'
+          ],
+  )
+
+
+  exe_inputs = temp_env.RES(
+      target=prefix + 'mi.res',
+      source='mi.rc'
+  )
+
+  # Force a rebuild when the version changes.
+  temp_env.Depends(exe_inputs, '$MAIN_DIR/VERSION')
+
+  for language in env['languages']:
+    base_name = 'mi_generated_resources_' + language
+    exe_inputs += temp_env.RES(
+        target=prefix + base_name + '.res',
+        source=base_name + '.rc',
+    )
+
+  temp_env.ComponentProgram(prefix + 'mi_exe_stub.exe', exe_inputs)
+
+
+local_env = env.Clone()
+AddCommonOptions(local_env)
+
+# Avoid target conflicts over extractor.obj
+local_env['OBJSUFFIX'] = '_mi' + local_env['OBJSUFFIX']
+
+local_inputs = [
+    # "../test/step_test.cc",  # This is commented until dependencies of libs
+                                # are sorted out, such as printf.
+    'mi.cc',
+    'process.cc',
+    'tar.cc',
+    '../common/extractor.cc'
+    ]
+
+local_env.ComponentLibrary('mi_exe_stub', local_inputs)
diff --git a/mi_exe_stub/mi.cc b/mi_exe_stub/mi.cc
index 6b64670..0f1eab5 100644
--- a/mi_exe_stub/mi.cc
+++ b/mi_exe_stub/mi.cc
@@ -1,482 +1,482 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Implementation of the metainstaller logic.

-// Untars a tarball and executes the extracted executable.

-// If no command line is specified, "/install" is passed to the executable

-// along with a .gup file if one is extracted.

-// If found, the contents of the signature tag are also passed to the

-// executable unmodified.

-

-#pragma warning(push)

-// C4548: expression before comma has no effect

-#pragma warning(disable : 4548)

-#include <windows.h>

-#include <atlstr.h>

-#include <atlsimpcoll.h>

-#pragma warning(pop)

-#include <msxml2.h>

-#include <shellapi.h>

-#include <algorithm>

-

-#include "base/scoped_ptr.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/error.h"

-#include "omaha/common/extractor.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/system_info.h"

-#include "omaha/mi_exe_stub/process.h"

-#include "omaha/mi_exe_stub/mi.grh"

-#include "omaha/mi_exe_stub/tar.h"

-extern "C" {

-#include "third_party/lzma/LzmaStateDecode.h"

-}

-

-namespace omaha  {

-

-// Resource ID of the goopdate payload inside the meta-installer.

-#define IDR_PAYLOAD 102

-

-namespace {

-

-HRESULT HandleError(HRESULT hr);

-

-// The function assumes that the extractor has already been opened.

-// The buffer must be deleted by the caller.

-char* ReadTag(TagExtractor* extractor) {

-  const int kMaxTagLength = 0x10000;  // 64KB

-

-  int tag_buffer_size = 0;

-  if (!extractor->ExtractTag(NULL, &tag_buffer_size)) {

-    return NULL;

-  }

-  if (!tag_buffer_size || (tag_buffer_size >= kMaxTagLength)) {

-    return NULL;

-  }

-

-  scoped_array<char> tag_buffer(new char[tag_buffer_size]);

-  if (!tag_buffer.get()) {

-    return NULL;

-  }

-

-  if (!extractor->ExtractTag(tag_buffer.get(), &tag_buffer_size)) {

-    _ASSERTE(false);

-    return NULL;

-  }

-

-  // Do a sanity check of the tag string. The double quote '"'

-  // is a special character that should not be included in the tag string.

-  for (const char* tag_char = tag_buffer.get(); *tag_char; ++tag_char) {

-    if (*tag_char == '"') {

-      _ASSERTE(false);

-      return NULL;

-    }

-  }

-

-  return tag_buffer.release();

-}

-

-// Extract the tag containing the extra information written by the server.

-// The memory returned by the function will have to be freed using delete[]

-// operator.

-char* ExtractTag(const TCHAR* module_file_name) {

-  if (!module_file_name) {

-    return NULL;

-  }

-

-  TagExtractor extractor;

-  if (!extractor.OpenFile(module_file_name)) {

-    return NULL;

-  }

-  char* ret = ReadTag(&extractor);

-  extractor.CloseFile();

-

-  return ret;

-}

-

-class MetaInstaller {

- public:

-  MetaInstaller(HINSTANCE instance, LPCSTR cmd_line)

-      : instance_(instance),

-        cmd_line_(cmd_line),

-        exit_code_(0) {

-  }

-

-  ~MetaInstaller() {

-    // When a crash happens while running GoogleUpdate and breakpad gets it

-    // GooogleUpdate.exe is started with the /report to report the crash.

-    // In a crash, the temp directory and the contained files can't be deleted.

-    if (exit_code_ != GOOPDATE_E_CRASH) {

-      CleanUpTempDirectory();

-    }

-  }

-

-  CString ConvertByteArrayToWideCharArray(const char* input, size_t len) {

-    _ASSERTE(input != NULL);

-    CString out_str;

-    TCHAR* out = out_str.GetBufferSetLength(len);

-    for (size_t i = 0; i < len; ++i) {

-      out[i] = static_cast<TCHAR>(input[i]);

-    }

-    return out_str;

-  }

-

-  int ExtractAndRun() {

-    if (CreateUniqueTempDirectory() != 0) {

-      return -1;

-    }

-    CString tarball_filename(ExtractTarballToTempLocation());

-    if (tarball_filename.IsEmpty()) {

-      return -1;

-    }

-    scoped_hfile tarball_file(::CreateFile(tarball_filename,

-                                           GENERIC_READ,

-                                           FILE_SHARE_READ,

-                                           NULL,

-                                           OPEN_EXISTING,

-                                           0,

-                                           NULL));

-    if (!tarball_file) return -1;

-

-    // Extract files from the archive and run the first EXE we find in it.

-    Tar tar(temp_dir_, get(tarball_file), true);

-    tar.SetCallback(TarFileCallback, this);

-    if (!tar.ExtractToDir()) {

-      return -1;

-    }

-

-    exit_code_ = ULONG_MAX;

-    if (!exe_path_.IsEmpty()) {

-      // Build the command line. There are three scenarios we consider:

-      // 1. Run by the user, in which case the MI does not receive any

-      //    argument on its command line. In this case the command line

-      //    to run is: "exe_path" /install [["]manifest["]]

-      // 2. Run with command line arguments. The tag, if present, will be

-      //    appended to the command line.

-      //    The command line is: "exe_path" args <tag>

-      //    For example, pass "/silent /install" to the metainstaller to

-      //    initiate a silent install using the extra args in the tag.

-      //    If a command line does not take a tag or a custom tag is needed,

-      //    use an untagged file.

-      CString command_line(exe_path_);

-      ::PathQuoteSpaces(CStrBuf(command_line, MAX_PATH));

-

-      scoped_array<char> tag(GetTag());

-      CString wide_tag;

-      if (tag.get()) {

-        wide_tag = ConvertByteArrayToWideCharArray(tag.get(),

-                                                           strlen(tag.get()));

-      }

-

-      if (cmd_line_.IsEmpty()) {

-        // Run-by-user case.

-        if (wide_tag.IsEmpty()) {

-          _ASSERTE(!"Must provide arguments with an untagged metainstaller.");

-          HRESULT hr = GOOPDATE_E_UNTAGGED_METAINSTALLER;

-          HandleError(hr);

-          return hr;

-        }

-        command_line.AppendFormat(" /%s", kCmdLineInstall);

-      } else {

-        command_line.AppendFormat(" %s", cmd_line_);

-

-        CheckAndHandleRecoveryCase(&command_line);

-      }

-

-      if (!wide_tag.IsEmpty()) {

-        command_line.AppendFormat(" \"%s\"", wide_tag);

-      }

-

-      RunAndWait(command_line, &exit_code_);

-    }

-    // Propagate up the exit code of the program we have run.

-    return exit_code_;

-  }

-

- private:

-  void CleanUpTempDirectory() {

-    // Delete our temp directory and its contents.

-    for (int i = 0; i != files_to_delete_.GetSize(); ++i) {

-      DeleteFile(files_to_delete_[i]);

-    }

-    files_to_delete_.RemoveAll();

-

-    ::RemoveDirectory(temp_dir_);

-    temp_dir_.Empty();

-  }

-

-  // Determines whether this is a silent install.

-  bool IsSilentInstall() {

-    CString silent_argument;

-    silent_argument.Format("/%s", kCmdLineSilent);

-

-    return silent_argument == cmd_line_;

-  }

-

-  // Determines whether the MI is being invoked for recovery purposes, and,

-  // if so, appends the MI's full path to the command line.

-  // cmd_line_ must begin with "/recover" in order for the recovery case to be

-  // detected.

-  void CheckAndHandleRecoveryCase(CString* command_line) {

-    _ASSERTE(command_line);

-

-    CString recover_argument;

-    recover_argument.Format("/%s", kCmdLineRecover);

-

-    if (cmd_line_.Left(recover_argument.GetLength()) == recover_argument) {

-      TCHAR current_path[MAX_PATH] = {0};

-      if (::GetModuleFileName(NULL, current_path, MAX_PATH - 1)) {

-        command_line->AppendFormat(" \"%s\"", current_path);

-      }

-    }

-  }

-

-  // Create a temp directory to hold the embedded setup files.

-  // This is a bit of a hack: we ask the system to create a temporary

-  // filename for us, and instead we use that name for a subdirectory name.

-  int CreateUniqueTempDirectory() {

-    ::GetTempPath(MAX_PATH, CStrBuf(temp_root_dir_, MAX_PATH));

-    if (::CreateDirectory(temp_root_dir_, NULL) != 0 ||

-        ::GetLastError() == ERROR_ALREADY_EXISTS) {

-      if (!::GetTempFileName(temp_root_dir_,

-                             _T("GUM"),

-                             0,  // form a unique filename

-                             CStrBuf(temp_dir_, MAX_PATH))) {

-        return -1;

-      }

-      // GetTempFileName() actually creates the temp file, so delete it.

-      ::DeleteFile(temp_dir_);

-      ::CreateDirectory(temp_dir_, NULL);

-    } else {

-      return -1;

-    }

-    return 0;

-  }

-

-  CString ExtractTarballToTempLocation() {

-    CString tarball_filename;

-    if (::GetTempFileName(temp_root_dir_,

-                          _T("GUT"),

-                          0,  // form a unique filename

-                          CStrBuf(tarball_filename, MAX_PATH))) {

-      files_to_delete_.Add(tarball_filename);

-      HRSRC res_info = ::FindResource(NULL,

-                                      MAKEINTRESOURCE(IDR_PAYLOAD),

-                                      _T("B"));

-      if (NULL != res_info) {

-        HGLOBAL resource = ::LoadResource(NULL, res_info);

-        if (NULL != resource) {

-          LPVOID resource_pointer = ::LockResource(resource);

-          if (NULL != resource_pointer) {

-            scoped_hfile tarball_file(::CreateFile(tarball_filename,

-                                                   GENERIC_READ | GENERIC_WRITE,

-                                                   0,

-                                                   NULL,

-                                                   OPEN_ALWAYS,

-                                                   0,

-                                                   NULL));

-            if (valid(tarball_file)) {

-              int error = DecompressBufferToFile(

-                              resource_pointer,

-                              ::SizeofResource(NULL, res_info),

-                              get(tarball_file));

-              if (error == 0) {

-                return tarball_filename;

-              }

-            }

-          }

-        }

-      }

-    }

-    return CString();

-  }

-

-  char* GetTag() const {

-    // Get this module file name.

-    TCHAR module_file_name[MAX_PATH] = {0};

-    if (!::GetModuleFileName(instance_, module_file_name, MAX_PATH)) {

-      _ASSERTE(false);

-      return NULL;

-    }

-

-    return ExtractTag(module_file_name);

-  }

-

-  static CString GetFilespec(const CString &path) {

-    int pos = path.ReverseFind('\\');

-    if (pos != -1) {

-      return path.Mid(pos + 1);

-    }

-    return path;

-  }

-

-  void HandleTarFile(const char *filename) {

-    CString new_filename(filename);

-    files_to_delete_.Add(new_filename);

-    CString filespec(GetFilespec(new_filename));

-    filespec.MakeLower();

-

-    if (filespec.GetLength() > 4) {

-      CString extension(filespec.Mid(filespec.GetLength() - 4));

-

-      if (extension == ".exe") {

-        // We're interested in remembering only the first exe in the tarball.

-        if (exe_path_.IsEmpty()) {

-          exe_path_ = new_filename;

-        }

-      }

-    }

-  }

-

-  static void TarFileCallback(void *context, const char *filename) {

-    MetaInstaller *mi = reinterpret_cast<MetaInstaller *>(context);

-    mi->HandleTarFile(filename);

-  }

-

-  // Decompress the content of the memory buffer into the file

-  // This code stolen from jeanluc in //googleclient/bar

-  static int DecompressBufferToFile(const void *buf,

-                                    size_t buf_len,

-                                    HANDLE file) {

-    // need header and len minimally

-    if (buf_len < LZMA_PROPERTIES_SIZE + 8) {

-      return -1;

-    }

-

-    CLzmaDecoderState decoder = {};

-    const unsigned char *pos = reinterpret_cast<const unsigned char*>(buf);

-

-    // get properties

-    int res_info = LzmaDecodeProperties(&decoder.Properties, pos,

-      LZMA_PROPERTIES_SIZE);

-    if (LZMA_RESULT_OK != res_info) {

-      return -1;

-    }

-

-    // advance buffer past header

-    pos += LZMA_PROPERTIES_SIZE;

-    buf_len -= LZMA_PROPERTIES_SIZE;

-

-    // get the length

-    ULONGLONG size;

-    memcpy(&size, pos, sizeof(size));

-

-    pos += sizeof(size);

-    buf_len -= sizeof(size);

-

-    // allocate the dictionary buffer

-    CAutoVectorPtr<CProb> probs;

-    if (!probs.Allocate(LzmaGetNumProbs(&decoder.Properties))) {

-      return -1;

-    }

-

-    CAutoVectorPtr<unsigned char> dict;

-    if (!dict.Allocate(decoder.Properties.DictionarySize)) {

-      return -1;

-    }

-

-    // and initialize the decoder

-    decoder.Dictionary = dict.m_p;

-    decoder.Probs = probs.m_p;

-

-    LzmaDecoderInit(&decoder);

-

-    while (0 != size || 0 != buf_len) {

-      SizeT in_consumed = 0;

-      SizeT out_produced = 0;

-      unsigned char chunk[8192];

-

-      // extract a chunk - note that the decompresser barfs on us if we

-      // extract too much data from it, so make sure to bound out_len

-      // to the amount of data left.

-      SizeT out_size = std::min(static_cast<SizeT>(size), sizeof(chunk));

-      res_info = LzmaDecode(&decoder, pos, buf_len, &in_consumed, chunk,

-        out_size, &out_produced, buf_len == 0);

-      if (LZMA_RESULT_OK != res_info) {

-        return -1;

-      }

-

-      pos += in_consumed;

-      buf_len -= in_consumed;

-      size -= out_produced;

-

-      DWORD written;

-      if (!::WriteFile(file, chunk, out_produced, &written, NULL)) {

-        return -1;

-      }

-

-      if (written != out_produced) {

-        return -1;

-      }

-    }

-    return 0;

-  }

-

-  HINSTANCE instance_;

-  CString cmd_line_;

-  CString exe_path_;

-  DWORD exit_code_;

-  CSimpleArray<CString> files_to_delete_;

-  CString temp_dir_;

-  CString temp_root_dir_;

-};

-

-HRESULT CheckOSRequirements() {

-  return SystemInfo::OSWin2KSP4OrLater() ? S_OK :

-                                           GOOPDATE_E_RUNNING_INFERIOR_WINDOWS;

-}

-

-HRESULT HandleError(HRESULT hr) {

-  CString msg_box_title;

-  CString msg_box_text;

-

-  msg_box_title.LoadString(IDS_GENERIC_INSTALLER_DISPLAY_NAME);

-  switch (hr) {

-    case GOOPDATE_E_RUNNING_INFERIOR_WINDOWS:

-      msg_box_text.LoadString(IDS_RUNNING_INFERIOR_WINDOWS);

-      break;

-

-    case GOOPDATE_E_UNTAGGED_METAINSTALLER:

-    default:

-      msg_box_text.LoadString(IDS_GENERIC_ERROR);

-      break;

-  }

-

-  ::MessageBox(NULL, msg_box_text, msg_box_title, MB_OK);

-  return hr;

-}

-

-}  // namespace

-

-}  // namespace omaha

-

-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int) {

-  scoped_co_init init_com_apt;

-  HRESULT hr(init_com_apt.hresult());

-  if (FAILED(hr)) {

-    return omaha::HandleError(hr);

-  }

-

-  hr = omaha::CheckOSRequirements();

-  if (FAILED(hr)) {

-    return omaha::HandleError(hr);

-  }

-

-  omaha::MetaInstaller mi(hInstance, lpCmdLine);

-  int result = mi.ExtractAndRun();

-  return result;

-}

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Implementation of the metainstaller logic.
+// Untars a tarball and executes the extracted executable.
+// If no command line is specified, "/install" is passed to the executable
+// along with a .gup file if one is extracted.
+// If found, the contents of the signature tag are also passed to the
+// executable unmodified.
+
+#pragma warning(push)
+// C4548: expression before comma has no effect
+#pragma warning(disable : 4548)
+#include <windows.h>
+#include <atlstr.h>
+#include <atlsimpcoll.h>
+#pragma warning(pop)
+#include <msxml2.h>
+#include <shellapi.h>
+#include <algorithm>
+
+#include "base/scoped_ptr.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/error.h"
+#include "omaha/common/extractor.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/system_info.h"
+#include "omaha/mi_exe_stub/process.h"
+#include "omaha/mi_exe_stub/mi.grh"
+#include "omaha/mi_exe_stub/tar.h"
+extern "C" {
+#include "third_party/lzma/LzmaStateDecode.h"
+}
+
+namespace omaha  {
+
+// Resource ID of the goopdate payload inside the meta-installer.
+#define IDR_PAYLOAD 102
+
+namespace {
+
+HRESULT HandleError(HRESULT hr);
+
+// The function assumes that the extractor has already been opened.
+// The buffer must be deleted by the caller.
+char* ReadTag(TagExtractor* extractor) {
+  const int kMaxTagLength = 0x10000;  // 64KB
+
+  int tag_buffer_size = 0;
+  if (!extractor->ExtractTag(NULL, &tag_buffer_size)) {
+    return NULL;
+  }
+  if (!tag_buffer_size || (tag_buffer_size >= kMaxTagLength)) {
+    return NULL;
+  }
+
+  scoped_array<char> tag_buffer(new char[tag_buffer_size]);
+  if (!tag_buffer.get()) {
+    return NULL;
+  }
+
+  if (!extractor->ExtractTag(tag_buffer.get(), &tag_buffer_size)) {
+    _ASSERTE(false);
+    return NULL;
+  }
+
+  // Do a sanity check of the tag string. The double quote '"'
+  // is a special character that should not be included in the tag string.
+  for (const char* tag_char = tag_buffer.get(); *tag_char; ++tag_char) {
+    if (*tag_char == '"') {
+      _ASSERTE(false);
+      return NULL;
+    }
+  }
+
+  return tag_buffer.release();
+}
+
+// Extract the tag containing the extra information written by the server.
+// The memory returned by the function will have to be freed using delete[]
+// operator.
+char* ExtractTag(const TCHAR* module_file_name) {
+  if (!module_file_name) {
+    return NULL;
+  }
+
+  TagExtractor extractor;
+  if (!extractor.OpenFile(module_file_name)) {
+    return NULL;
+  }
+  char* ret = ReadTag(&extractor);
+  extractor.CloseFile();
+
+  return ret;
+}
+
+class MetaInstaller {
+ public:
+  MetaInstaller(HINSTANCE instance, LPCSTR cmd_line)
+      : instance_(instance),
+        cmd_line_(cmd_line),
+        exit_code_(0) {
+  }
+
+  ~MetaInstaller() {
+    // When a crash happens while running GoogleUpdate and breakpad gets it
+    // GooogleUpdate.exe is started with the /report to report the crash.
+    // In a crash, the temp directory and the contained files can't be deleted.
+    if (exit_code_ != GOOPDATE_E_CRASH) {
+      CleanUpTempDirectory();
+    }
+  }
+
+  CString ConvertByteArrayToWideCharArray(const char* input, size_t len) {
+    _ASSERTE(input != NULL);
+    CString out_str;
+    TCHAR* out = out_str.GetBufferSetLength(len);
+    for (size_t i = 0; i < len; ++i) {
+      out[i] = static_cast<TCHAR>(input[i]);
+    }
+    return out_str;
+  }
+
+  int ExtractAndRun() {
+    if (CreateUniqueTempDirectory() != 0) {
+      return -1;
+    }
+    CString tarball_filename(ExtractTarballToTempLocation());
+    if (tarball_filename.IsEmpty()) {
+      return -1;
+    }
+    scoped_hfile tarball_file(::CreateFile(tarball_filename,
+                                           GENERIC_READ,
+                                           FILE_SHARE_READ,
+                                           NULL,
+                                           OPEN_EXISTING,
+                                           0,
+                                           NULL));
+    if (!tarball_file) return -1;
+
+    // Extract files from the archive and run the first EXE we find in it.
+    Tar tar(temp_dir_, get(tarball_file), true);
+    tar.SetCallback(TarFileCallback, this);
+    if (!tar.ExtractToDir()) {
+      return -1;
+    }
+
+    exit_code_ = ULONG_MAX;
+    if (!exe_path_.IsEmpty()) {
+      // Build the command line. There are three scenarios we consider:
+      // 1. Run by the user, in which case the MI does not receive any
+      //    argument on its command line. In this case the command line
+      //    to run is: "exe_path" /install [["]manifest["]]
+      // 2. Run with command line arguments. The tag, if present, will be
+      //    appended to the command line.
+      //    The command line is: "exe_path" args <tag>
+      //    For example, pass "/silent /install" to the metainstaller to
+      //    initiate a silent install using the extra args in the tag.
+      //    If a command line does not take a tag or a custom tag is needed,
+      //    use an untagged file.
+      CString command_line(exe_path_);
+      ::PathQuoteSpaces(CStrBuf(command_line, MAX_PATH));
+
+      scoped_array<char> tag(GetTag());
+      CString wide_tag;
+      if (tag.get()) {
+        wide_tag = ConvertByteArrayToWideCharArray(tag.get(),
+                                                           strlen(tag.get()));
+      }
+
+      if (cmd_line_.IsEmpty()) {
+        // Run-by-user case.
+        if (wide_tag.IsEmpty()) {
+          _ASSERTE(!"Must provide arguments with an untagged metainstaller.");
+          HRESULT hr = GOOPDATE_E_UNTAGGED_METAINSTALLER;
+          HandleError(hr);
+          return hr;
+        }
+        command_line.AppendFormat(" /%s", kCmdLineInstall);
+      } else {
+        command_line.AppendFormat(" %s", cmd_line_);
+
+        CheckAndHandleRecoveryCase(&command_line);
+      }
+
+      if (!wide_tag.IsEmpty()) {
+        command_line.AppendFormat(" \"%s\"", wide_tag);
+      }
+
+      RunAndWait(command_line, &exit_code_);
+    }
+    // Propagate up the exit code of the program we have run.
+    return exit_code_;
+  }
+
+ private:
+  void CleanUpTempDirectory() {
+    // Delete our temp directory and its contents.
+    for (int i = 0; i != files_to_delete_.GetSize(); ++i) {
+      DeleteFile(files_to_delete_[i]);
+    }
+    files_to_delete_.RemoveAll();
+
+    ::RemoveDirectory(temp_dir_);
+    temp_dir_.Empty();
+  }
+
+  // Determines whether this is a silent install.
+  bool IsSilentInstall() {
+    CString silent_argument;
+    silent_argument.Format("/%s", kCmdLineSilent);
+
+    return silent_argument == cmd_line_;
+  }
+
+  // Determines whether the MI is being invoked for recovery purposes, and,
+  // if so, appends the MI's full path to the command line.
+  // cmd_line_ must begin with "/recover" in order for the recovery case to be
+  // detected.
+  void CheckAndHandleRecoveryCase(CString* command_line) {
+    _ASSERTE(command_line);
+
+    CString recover_argument;
+    recover_argument.Format("/%s", kCmdLineRecover);
+
+    if (cmd_line_.Left(recover_argument.GetLength()) == recover_argument) {
+      TCHAR current_path[MAX_PATH] = {0};
+      if (::GetModuleFileName(NULL, current_path, MAX_PATH - 1)) {
+        command_line->AppendFormat(" \"%s\"", current_path);
+      }
+    }
+  }
+
+  // Create a temp directory to hold the embedded setup files.
+  // This is a bit of a hack: we ask the system to create a temporary
+  // filename for us, and instead we use that name for a subdirectory name.
+  int CreateUniqueTempDirectory() {
+    ::GetTempPath(MAX_PATH, CStrBuf(temp_root_dir_, MAX_PATH));
+    if (::CreateDirectory(temp_root_dir_, NULL) != 0 ||
+        ::GetLastError() == ERROR_ALREADY_EXISTS) {
+      if (!::GetTempFileName(temp_root_dir_,
+                             _T("GUM"),
+                             0,  // form a unique filename
+                             CStrBuf(temp_dir_, MAX_PATH))) {
+        return -1;
+      }
+      // GetTempFileName() actually creates the temp file, so delete it.
+      ::DeleteFile(temp_dir_);
+      ::CreateDirectory(temp_dir_, NULL);
+    } else {
+      return -1;
+    }
+    return 0;
+  }
+
+  CString ExtractTarballToTempLocation() {
+    CString tarball_filename;
+    if (::GetTempFileName(temp_root_dir_,
+                          _T("GUT"),
+                          0,  // form a unique filename
+                          CStrBuf(tarball_filename, MAX_PATH))) {
+      files_to_delete_.Add(tarball_filename);
+      HRSRC res_info = ::FindResource(NULL,
+                                      MAKEINTRESOURCE(IDR_PAYLOAD),
+                                      _T("B"));
+      if (NULL != res_info) {
+        HGLOBAL resource = ::LoadResource(NULL, res_info);
+        if (NULL != resource) {
+          LPVOID resource_pointer = ::LockResource(resource);
+          if (NULL != resource_pointer) {
+            scoped_hfile tarball_file(::CreateFile(tarball_filename,
+                                                   GENERIC_READ | GENERIC_WRITE,
+                                                   0,
+                                                   NULL,
+                                                   OPEN_ALWAYS,
+                                                   0,
+                                                   NULL));
+            if (valid(tarball_file)) {
+              int error = DecompressBufferToFile(
+                              resource_pointer,
+                              ::SizeofResource(NULL, res_info),
+                              get(tarball_file));
+              if (error == 0) {
+                return tarball_filename;
+              }
+            }
+          }
+        }
+      }
+    }
+    return CString();
+  }
+
+  char* GetTag() const {
+    // Get this module file name.
+    TCHAR module_file_name[MAX_PATH] = {0};
+    if (!::GetModuleFileName(instance_, module_file_name, MAX_PATH)) {
+      _ASSERTE(false);
+      return NULL;
+    }
+
+    return ExtractTag(module_file_name);
+  }
+
+  static CString GetFilespec(const CString &path) {
+    int pos = path.ReverseFind('\\');
+    if (pos != -1) {
+      return path.Mid(pos + 1);
+    }
+    return path;
+  }
+
+  void HandleTarFile(const char *filename) {
+    CString new_filename(filename);
+    files_to_delete_.Add(new_filename);
+    CString filespec(GetFilespec(new_filename));
+    filespec.MakeLower();
+
+    if (filespec.GetLength() > 4) {
+      CString extension(filespec.Mid(filespec.GetLength() - 4));
+
+      if (extension == ".exe") {
+        // We're interested in remembering only the first exe in the tarball.
+        if (exe_path_.IsEmpty()) {
+          exe_path_ = new_filename;
+        }
+      }
+    }
+  }
+
+  static void TarFileCallback(void *context, const char *filename) {
+    MetaInstaller *mi = reinterpret_cast<MetaInstaller *>(context);
+    mi->HandleTarFile(filename);
+  }
+
+  // Decompress the content of the memory buffer into the file
+  // This code stolen from jeanluc in //googleclient/bar
+  static int DecompressBufferToFile(const void *buf,
+                                    size_t buf_len,
+                                    HANDLE file) {
+    // need header and len minimally
+    if (buf_len < LZMA_PROPERTIES_SIZE + 8) {
+      return -1;
+    }
+
+    CLzmaDecoderState decoder = {};
+    const unsigned char *pos = reinterpret_cast<const unsigned char*>(buf);
+
+    // get properties
+    int res_info = LzmaDecodeProperties(&decoder.Properties, pos,
+      LZMA_PROPERTIES_SIZE);
+    if (LZMA_RESULT_OK != res_info) {
+      return -1;
+    }
+
+    // advance buffer past header
+    pos += LZMA_PROPERTIES_SIZE;
+    buf_len -= LZMA_PROPERTIES_SIZE;
+
+    // get the length
+    ULONGLONG size;
+    memcpy(&size, pos, sizeof(size));
+
+    pos += sizeof(size);
+    buf_len -= sizeof(size);
+
+    // allocate the dictionary buffer
+    CAutoVectorPtr<CProb> probs;
+    if (!probs.Allocate(LzmaGetNumProbs(&decoder.Properties))) {
+      return -1;
+    }
+
+    CAutoVectorPtr<unsigned char> dict;
+    if (!dict.Allocate(decoder.Properties.DictionarySize)) {
+      return -1;
+    }
+
+    // and initialize the decoder
+    decoder.Dictionary = dict.m_p;
+    decoder.Probs = probs.m_p;
+
+    LzmaDecoderInit(&decoder);
+
+    while (0 != size || 0 != buf_len) {
+      SizeT in_consumed = 0;
+      SizeT out_produced = 0;
+      unsigned char chunk[8192];
+
+      // extract a chunk - note that the decompresser barfs on us if we
+      // extract too much data from it, so make sure to bound out_len
+      // to the amount of data left.
+      SizeT out_size = std::min(static_cast<SizeT>(size), sizeof(chunk));
+      res_info = LzmaDecode(&decoder, pos, buf_len, &in_consumed, chunk,
+        out_size, &out_produced, buf_len == 0);
+      if (LZMA_RESULT_OK != res_info) {
+        return -1;
+      }
+
+      pos += in_consumed;
+      buf_len -= in_consumed;
+      size -= out_produced;
+
+      DWORD written;
+      if (!::WriteFile(file, chunk, out_produced, &written, NULL)) {
+        return -1;
+      }
+
+      if (written != out_produced) {
+        return -1;
+      }
+    }
+    return 0;
+  }
+
+  HINSTANCE instance_;
+  CString cmd_line_;
+  CString exe_path_;
+  DWORD exit_code_;
+  CSimpleArray<CString> files_to_delete_;
+  CString temp_dir_;
+  CString temp_root_dir_;
+};
+
+HRESULT CheckOSRequirements() {
+  return SystemInfo::OSWin2KSP4OrLater() ? S_OK :
+                                           GOOPDATE_E_RUNNING_INFERIOR_WINDOWS;
+}
+
+HRESULT HandleError(HRESULT hr) {
+  CString msg_box_title;
+  CString msg_box_text;
+
+  msg_box_title.LoadString(IDS_GENERIC_INSTALLER_DISPLAY_NAME);
+  switch (hr) {
+    case GOOPDATE_E_RUNNING_INFERIOR_WINDOWS:
+      msg_box_text.LoadString(IDS_RUNNING_INFERIOR_WINDOWS);
+      break;
+
+    case GOOPDATE_E_UNTAGGED_METAINSTALLER:
+    default:
+      msg_box_text.LoadString(IDS_GENERIC_ERROR);
+      break;
+  }
+
+  ::MessageBox(NULL, msg_box_text, msg_box_title, MB_OK);
+  return hr;
+}
+
+}  // namespace
+
+}  // namespace omaha
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int) {
+  scoped_co_init init_com_apt;
+  HRESULT hr(init_com_apt.hresult());
+  if (FAILED(hr)) {
+    return omaha::HandleError(hr);
+  }
+
+  hr = omaha::CheckOSRequirements();
+  if (FAILED(hr)) {
+    return omaha::HandleError(hr);
+  }
+
+  omaha::MetaInstaller mi(hInstance, lpCmdLine);
+  int result = mi.ExtractAndRun();
+  return result;
+}
+
diff --git a/mi_exe_stub/mi.grh b/mi_exe_stub/mi.grh
index 75f7357..b9fbdfc 100644
--- a/mi_exe_stub/mi.grh
+++ b/mi_exe_stub/mi.grh
@@ -1,26 +1,26 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// This file is automatically generated by GRIT.  Do not edit.

-// Built on Mon Apr 06 11:07:10 2009

-

-#ifndef RESOURCE_894478371968__

-#define RESOURCE_894478371968__

-

-

-#define IDS_GENERIC_INSTALLER_DISPLAY_NAME 21837

-#define IDS_GENERIC_ERROR 21838

-#define IDS_RUNNING_INFERIOR_WINDOWS 21839

-

-#endif // RESOURCE_894478371968__

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// This file is automatically generated by GRIT.  Do not edit.
+// Built on Mon Apr 06 11:07:10 2009
+
+#ifndef RESOURCE_894478371968__
+#define RESOURCE_894478371968__
+
+
+#define IDS_GENERIC_INSTALLER_DISPLAY_NAME 21837
+#define IDS_GENERIC_ERROR 21838
+#define IDS_RUNNING_INFERIOR_WINDOWS 21839
+
+#endif // RESOURCE_894478371968__
diff --git a/mi_exe_stub/mi.rc b/mi_exe_stub/mi.rc
index 9d796ed..1234d2f 100644
--- a/mi_exe_stub/mi.rc
+++ b/mi_exe_stub/mi.rc
@@ -1,69 +1,69 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <winres.h>

-#include <winresrc.h>

-#include "afxres.h"

-#include "resource.h"

-

-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

-

-IDI_APP            ICON               "mi.ico"

-

-VS_VERSION_INFO VERSIONINFO

- FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- FILEFLAGSMASK 0x17L

-#ifdef _DEBUG

- FILEFLAGS 0x1L

-#else

- FILEFLAGS 0x0L

-#endif

- FILEOS 0x4L

- FILETYPE 0x0L

- FILESUBTYPE 0x0L

-BEGIN

-    BLOCK "StringFileInfo"

-    BEGIN

-        BLOCK "040904b0"

-        BEGIN

-            VALUE "CompanyName", "Google Inc."

-            VALUE "FileDescription", "Setup"

-            VALUE "FileVersion", VERSION_NUMBER_STRING

-            VALUE "InternalName", "Setup"

-            VALUE "LegalCopyright", "Copyright 2007-2009 Google Inc."

-            VALUE "OriginalFilename", "Setup"

-            VALUE "ProductName", "Setup"

-            VALUE "ProductVersion", VERSION_NUMBER_STRING

-            VALUE "LanguageId", LANGUAGE_STRING

-#ifdef _DEBUG

-            VALUE "Debug", ""

-#endif

-#if !OFFICIAL_BUILD

-            VALUE "Privatebuild", ""

-#endif

-

-        END

-    END

-    BLOCK "VarFileInfo"

-    BEGIN

-        VALUE "Translation", 0x0409, 1200

-    END

-END

-

-// Allow the TB component installer to elevate the Omaha metainstaller.

-LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

-#define IDR_GOOGLEUPDATE 1

-IDR_GOOGLEUPDATE GOOGLEUPDATE { 1L }

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <winres.h>
+#include <winresrc.h>
+#include "afxres.h"
+#include "resource.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+IDI_APP            ICON               "mi.ico"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Google Inc."
+            VALUE "FileDescription", "Setup"
+            VALUE "FileVersion", VERSION_NUMBER_STRING
+            VALUE "InternalName", "Setup"
+            VALUE "LegalCopyright", "Copyright 2007-2009 Google Inc."
+            VALUE "OriginalFilename", "Setup"
+            VALUE "ProductName", "Setup"
+            VALUE "ProductVersion", VERSION_NUMBER_STRING
+            VALUE "LanguageId", LANGUAGE_STRING
+#ifdef _DEBUG
+            VALUE "Debug", ""
+#endif
+#if !OFFICIAL_BUILD
+            VALUE "Privatebuild", ""
+#endif
+
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x0409, 1200
+    END
+END
+
+// Allow the TB component installer to elevate the Omaha metainstaller.
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#define IDR_GOOGLEUPDATE 1
+IDR_GOOGLEUPDATE GOOGLEUPDATE { 1L }
diff --git a/mi_exe_stub/process.cc b/mi_exe_stub/process.cc
index 252e7fe..b7ce951 100644
--- a/mi_exe_stub/process.cc
+++ b/mi_exe_stub/process.cc
@@ -1,72 +1,72 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/mi_exe_stub/process.h"

-#include <strsafe.h>

-

-static bool run_and_wait(const CString &command_line,

-                         DWORD* exit_code,

-                         bool wait,

-                         int cmd_show) {

-  CString cmd_line(command_line);

-  STARTUPINFO si = {0};

-  PROCESS_INFORMATION pi = {0};

-

-  GetStartupInfo(&si);

-  si.dwFlags |= STARTF_FORCEOFFFEEDBACK;

-  si.dwFlags |= STARTF_USESHOWWINDOW;

-  si.wShowWindow = static_cast<WORD>(cmd_show);

-

-  BOOL create_process_result = CreateProcess(NULL,

-                                             cmd_line.GetBuffer(),

-                                             NULL,

-                                             NULL,

-                                             FALSE,

-                                             CREATE_UNICODE_ENVIRONMENT,

-                                             NULL,

-                                             NULL,

-                                             &si,

-                                             &pi);

-  if (!create_process_result) {

-    *exit_code = GetLastError();

-    return false;

-  }

-

-  if (wait) {

-    WaitForSingleObject(pi.hProcess, INFINITE);

-  }

-

-  bool result = true;

-  if (exit_code) {

-    result = !!GetExitCodeProcess(pi.hProcess, exit_code);

-  }

-

-  CloseHandle(pi.hProcess);

-  CloseHandle(pi.hThread);

-

-  return result;

-}

-

-bool RunAndWaitHidden(const CString &command_line, DWORD *exit_code) {

-  return run_and_wait(command_line, exit_code, true, SW_HIDE);

-}

-

-bool RunAndWait(const CString &command_line, DWORD *exit_code) {

-  return run_and_wait(command_line, exit_code, true, SW_SHOWNORMAL);

-}

-

-bool Run(const CString &command_line) {

-  return run_and_wait(command_line, NULL, false, SW_SHOWNORMAL);

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/mi_exe_stub/process.h"
+#include <strsafe.h>
+
+static bool run_and_wait(const CString &command_line,
+                         DWORD* exit_code,
+                         bool wait,
+                         int cmd_show) {
+  CString cmd_line(command_line);
+  STARTUPINFO si = {0};
+  PROCESS_INFORMATION pi = {0};
+
+  GetStartupInfo(&si);
+  si.dwFlags |= STARTF_FORCEOFFFEEDBACK;
+  si.dwFlags |= STARTF_USESHOWWINDOW;
+  si.wShowWindow = static_cast<WORD>(cmd_show);
+
+  BOOL create_process_result = CreateProcess(NULL,
+                                             cmd_line.GetBuffer(),
+                                             NULL,
+                                             NULL,
+                                             FALSE,
+                                             CREATE_UNICODE_ENVIRONMENT,
+                                             NULL,
+                                             NULL,
+                                             &si,
+                                             &pi);
+  if (!create_process_result) {
+    *exit_code = GetLastError();
+    return false;
+  }
+
+  if (wait) {
+    WaitForSingleObject(pi.hProcess, INFINITE);
+  }
+
+  bool result = true;
+  if (exit_code) {
+    result = !!GetExitCodeProcess(pi.hProcess, exit_code);
+  }
+
+  CloseHandle(pi.hProcess);
+  CloseHandle(pi.hThread);
+
+  return result;
+}
+
+bool RunAndWaitHidden(const CString &command_line, DWORD *exit_code) {
+  return run_and_wait(command_line, exit_code, true, SW_HIDE);
+}
+
+bool RunAndWait(const CString &command_line, DWORD *exit_code) {
+  return run_and_wait(command_line, exit_code, true, SW_SHOWNORMAL);
+}
+
+bool Run(const CString &command_line) {
+  return run_and_wait(command_line, NULL, false, SW_SHOWNORMAL);
+}
diff --git a/mi_exe_stub/process.h b/mi_exe_stub/process.h
index 2aeb6e6..5ed66bb 100644
--- a/mi_exe_stub/process.h
+++ b/mi_exe_stub/process.h
@@ -1,39 +1,39 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_MI_EXE_STUB_PROCESS_H_

-#define OMAHA_MI_EXE_STUB_PROCESS_H_

-

-#pragma warning(push)

-#pragma warning(disable : 4548)

-// C4548: expression before comma has no effect

-#include <atlbase.h>

-#include <atlstr.h>

-#pragma warning(pop)

-

-// Convenience function to launch a process. Returns true if we successfully

-// launched it.

-bool Run(const CString &command_line);

-

-// Convenience function to launch a process, wait for it to finish,

-// and return the result.

-bool RunAndWait(const CString &command_line, DWORD *exit_code);

-

-// Convenience function to launch a process with the initial window hidden,

-// wait for it to finish and return the result.

-bool RunAndWaitHidden(const CString &command_line, DWORD *exit_code);

-

-#endif  // OMAHA_MI_EXE_STUB_PROCESS_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_MI_EXE_STUB_PROCESS_H_
+#define OMAHA_MI_EXE_STUB_PROCESS_H_
+
+#pragma warning(push)
+#pragma warning(disable : 4548)
+// C4548: expression before comma has no effect
+#include <atlbase.h>
+#include <atlstr.h>
+#pragma warning(pop)
+
+// Convenience function to launch a process. Returns true if we successfully
+// launched it.
+bool Run(const CString &command_line);
+
+// Convenience function to launch a process, wait for it to finish,
+// and return the result.
+bool RunAndWait(const CString &command_line, DWORD *exit_code);
+
+// Convenience function to launch a process with the initial window hidden,
+// wait for it to finish and return the result.
+bool RunAndWaitHidden(const CString &command_line, DWORD *exit_code);
+
+#endif  // OMAHA_MI_EXE_STUB_PROCESS_H_
diff --git a/mi_exe_stub/resource.h b/mi_exe_stub/resource.h
index cebefc4..fc12206 100644
--- a/mi_exe_stub/resource.h
+++ b/mi_exe_stub/resource.h
@@ -1,23 +1,23 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_MI_EXE_STUB_RESOURCE_H__

-#define OMAHA_MI_EXE_STUB_RESOURCE_H__

-

-#define IDI_APP 101

-

-#endif  // OMAHA_MI_EXE_STUB_RESOURCE_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_MI_EXE_STUB_RESOURCE_H__
+#define OMAHA_MI_EXE_STUB_RESOURCE_H__
+
+#define IDI_APP 101
+
+#endif  // OMAHA_MI_EXE_STUB_RESOURCE_H__
+
diff --git a/mi_exe_stub/tar.cc b/mi_exe_stub/tar.cc
index 11f2e7e..654eecc 100644
--- a/mi_exe_stub/tar.cc
+++ b/mi_exe_stub/tar.cc
@@ -1,123 +1,123 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/mi_exe_stub/tar.h"

-#include <strsafe.h>

-

-#define USTAR_MAGIC "ustar"

-#define USTAR_OFFSET 257

-#define USTAR_DONE "\0\0\0\0\0"

-

-template <typename T, size_t N>

-char (&ArraySizeHelper(T (&array)[N]))[N];    // NOLINT

-#define arraysize(array) (sizeof(ArraySizeHelper(array)))

-

-

-Tar::Tar(const char *target_dir, HANDLE file_handle, bool delete_when_done)

-    : target_directory_name_(target_dir),

-      file_handle_(file_handle),

-      delete_when_done_(delete_when_done),

-      callback_(NULL),

-      callback_context_(NULL) {}

-

-Tar::~Tar() {

-  for (int i = 0; i != files_to_delete_.GetSize(); ++i) {

-    DeleteFile(files_to_delete_[i]);

-  }

-}

-

-bool Tar::ExtractToDir() {

-  bool done = false;

-  do {

-    if (!ExtractOneFile(&done)) {

-      return false;

-    }

-  } while (!done);

-  return true;

-}

-

-bool Tar::ExtractOneFile(bool *done) {

-  USTARHeader header;

-  DWORD bytes_handled;

-  bool result = true;

-  BOOL file_result;

-

-  file_result = ReadFile(file_handle_, &header, sizeof(USTARHeader),

-    &bytes_handled, NULL);

-  if (!file_result || bytes_handled != sizeof(USTARHeader)) {

-    return false;

-  }

-  if (0 == memcmp(header.magic, USTAR_DONE, arraysize(USTAR_DONE) - 1)) {

-    // We're probably done, since we read the final block of all zeroes.

-    *done = true;

-    return true;

-  }

-  if (0 != memcmp(header.magic, USTAR_MAGIC, arraysize(USTAR_MAGIC) - 1)) {

-    return false;

-  }

-  CString new_filename(target_directory_name_);

-  new_filename += "\\";

-  new_filename += header.name;

-  HANDLE new_file = CreateFile(new_filename, GENERIC_WRITE, 0, NULL,

-    CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);

-  if (new_file == INVALID_HANDLE_VALUE) {

-    return false;

-  }

-  // We don't check for conversion errors because the input data is fixed at

-  // build time, so it'll either always work or never work, and we won't ship

-  // one that never works.

-  DWORD tar_file_size = strtol(header.size, NULL, 8);

-  DWORD next_offset = SetFilePointer(file_handle_, 0, NULL, FILE_CURRENT) +

-      tar_file_size + (512 - tar_file_size & 0x1ff);

-  while (tar_file_size > 0) {

-    const int COPY_BUFFER_SIZE = 256 * 1024;

-    char copy_buffer[COPY_BUFFER_SIZE];

-    DWORD bytes_to_handle = COPY_BUFFER_SIZE;

-    if (bytes_to_handle > tar_file_size) {

-      bytes_to_handle = tar_file_size;

-    }

-    file_result = ReadFile(file_handle_, copy_buffer, bytes_to_handle,

-      &bytes_handled, NULL);

-    if (!file_result) {

-      result = false;

-      break;

-    } else {

-      file_result = WriteFile(new_file, copy_buffer, bytes_to_handle,

-        &bytes_handled, NULL);

-      if (!file_result) {

-        result = false;

-        break;

-      } else {

-        tar_file_size -= bytes_to_handle;

-      }

-    }

-  }

-  CloseHandle(new_file);

-  if (result) {

-    if (delete_when_done_) {

-      files_to_delete_.Add(new_filename);

-    }

-    if (callback_ != NULL) {

-      callback_(callback_context_, new_filename);

-    }

-  }

-

-  if (INVALID_SET_FILE_POINTER != next_offset) {

-    SetFilePointer(file_handle_, next_offset, NULL, FILE_BEGIN);

-  }

-

-  return result;

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/mi_exe_stub/tar.h"
+#include <strsafe.h>
+
+#define USTAR_MAGIC "ustar"
+#define USTAR_OFFSET 257
+#define USTAR_DONE "\0\0\0\0\0"
+
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];    // NOLINT
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+
+Tar::Tar(const char *target_dir, HANDLE file_handle, bool delete_when_done)
+    : target_directory_name_(target_dir),
+      file_handle_(file_handle),
+      delete_when_done_(delete_when_done),
+      callback_(NULL),
+      callback_context_(NULL) {}
+
+Tar::~Tar() {
+  for (int i = 0; i != files_to_delete_.GetSize(); ++i) {
+    DeleteFile(files_to_delete_[i]);
+  }
+}
+
+bool Tar::ExtractToDir() {
+  bool done = false;
+  do {
+    if (!ExtractOneFile(&done)) {
+      return false;
+    }
+  } while (!done);
+  return true;
+}
+
+bool Tar::ExtractOneFile(bool *done) {
+  USTARHeader header;
+  DWORD bytes_handled;
+  bool result = true;
+  BOOL file_result;
+
+  file_result = ReadFile(file_handle_, &header, sizeof(USTARHeader),
+    &bytes_handled, NULL);
+  if (!file_result || bytes_handled != sizeof(USTARHeader)) {
+    return false;
+  }
+  if (0 == memcmp(header.magic, USTAR_DONE, arraysize(USTAR_DONE) - 1)) {
+    // We're probably done, since we read the final block of all zeroes.
+    *done = true;
+    return true;
+  }
+  if (0 != memcmp(header.magic, USTAR_MAGIC, arraysize(USTAR_MAGIC) - 1)) {
+    return false;
+  }
+  CString new_filename(target_directory_name_);
+  new_filename += "\\";
+  new_filename += header.name;
+  HANDLE new_file = CreateFile(new_filename, GENERIC_WRITE, 0, NULL,
+    CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
+  if (new_file == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+  // We don't check for conversion errors because the input data is fixed at
+  // build time, so it'll either always work or never work, and we won't ship
+  // one that never works.
+  DWORD tar_file_size = strtol(header.size, NULL, 8);
+  DWORD next_offset = SetFilePointer(file_handle_, 0, NULL, FILE_CURRENT) +
+      tar_file_size + (512 - tar_file_size & 0x1ff);
+  while (tar_file_size > 0) {
+    const int COPY_BUFFER_SIZE = 256 * 1024;
+    char copy_buffer[COPY_BUFFER_SIZE];
+    DWORD bytes_to_handle = COPY_BUFFER_SIZE;
+    if (bytes_to_handle > tar_file_size) {
+      bytes_to_handle = tar_file_size;
+    }
+    file_result = ReadFile(file_handle_, copy_buffer, bytes_to_handle,
+      &bytes_handled, NULL);
+    if (!file_result) {
+      result = false;
+      break;
+    } else {
+      file_result = WriteFile(new_file, copy_buffer, bytes_to_handle,
+        &bytes_handled, NULL);
+      if (!file_result) {
+        result = false;
+        break;
+      } else {
+        tar_file_size -= bytes_to_handle;
+      }
+    }
+  }
+  CloseHandle(new_file);
+  if (result) {
+    if (delete_when_done_) {
+      files_to_delete_.Add(new_filename);
+    }
+    if (callback_ != NULL) {
+      callback_(callback_context_, new_filename);
+    }
+  }
+
+  if (INVALID_SET_FILE_POINTER != next_offset) {
+    SetFilePointer(file_handle_, next_offset, NULL, FILE_BEGIN);
+  }
+
+  return result;
+}
diff --git a/mi_exe_stub/tar.h b/mi_exe_stub/tar.h
index 95049dc..29125b8 100644
--- a/mi_exe_stub/tar.h
+++ b/mi_exe_stub/tar.h
@@ -1,79 +1,79 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_MI_EXE_STUB_TAR_H_

-#define OMAHA_MI_EXE_STUB_TAR_H_

-

-#pragma warning(push)

-// C4548: expression before comma has no effect

-#pragma warning(disable : 4548)

-#include <atlbase.h>

-#include <atlstr.h>

-#include <atlsimpcoll.h>

-#pragma warning(pop)

-

-static const int NAME_SIZE = 100;

-

-typedef struct {

-  char name[NAME_SIZE];

-  char mode[8];

-  char uid[8];

-  char gid[8];

-  char size[12];

-  char mtime[12];

-  char chksum[8];

-  char typeflag;

-  char linkname[NAME_SIZE];

-  char magic[6];

-  char version[2];

-  char uname[32];

-  char gname[32];

-  char devmajor[8];

-  char devminor[8];

-  char prefix[155];

-  char dummy[12];  // make it exactly 512 bytes

-} USTARHeader;

-

-// Supports untarring of files from a tar-format archive. Pretty minimal;

-// doesn't work with everything in the USTAR format.

-class Tar {

- public:

-  Tar(const char *target_dir, HANDLE file_handle, bool delete_when_done);

-  ~Tar();

-

-  typedef void (*TarFileCallback)(void *context, const char *filename);

-

-  void SetCallback(TarFileCallback callback, void *callback_context) {

-    callback_ = callback;

-    callback_context_ = callback_context;

-  }

-

-  // Extracts all files in archive to directory specified in constructor.

-  // Directory must exist. Returns true if successful.

-  bool ExtractToDir();

-

- private:

-  HANDLE file_handle_;

-  CString target_directory_name_;

-  bool delete_when_done_;

-  CSimpleArray<CString> files_to_delete_;

-  TarFileCallback callback_;

-  void *callback_context_;

-

-  bool ExtractOneFile(bool *done);

-};

-

-#endif  // OMAHA_MI_EXE_STUB_TAR_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_MI_EXE_STUB_TAR_H_
+#define OMAHA_MI_EXE_STUB_TAR_H_
+
+#pragma warning(push)
+// C4548: expression before comma has no effect
+#pragma warning(disable : 4548)
+#include <atlbase.h>
+#include <atlstr.h>
+#include <atlsimpcoll.h>
+#pragma warning(pop)
+
+static const int NAME_SIZE = 100;
+
+typedef struct {
+  char name[NAME_SIZE];
+  char mode[8];
+  char uid[8];
+  char gid[8];
+  char size[12];
+  char mtime[12];
+  char chksum[8];
+  char typeflag;
+  char linkname[NAME_SIZE];
+  char magic[6];
+  char version[2];
+  char uname[32];
+  char gname[32];
+  char devmajor[8];
+  char devminor[8];
+  char prefix[155];
+  char dummy[12];  // make it exactly 512 bytes
+} USTARHeader;
+
+// Supports untarring of files from a tar-format archive. Pretty minimal;
+// doesn't work with everything in the USTAR format.
+class Tar {
+ public:
+  Tar(const char *target_dir, HANDLE file_handle, bool delete_when_done);
+  ~Tar();
+
+  typedef void (*TarFileCallback)(void *context, const char *filename);
+
+  void SetCallback(TarFileCallback callback, void *callback_context) {
+    callback_ = callback;
+    callback_context_ = callback_context;
+  }
+
+  // Extracts all files in archive to directory specified in constructor.
+  // Directory must exist. Returns true if successful.
+  bool ExtractToDir();
+
+ private:
+  HANDLE file_handle_;
+  CString target_directory_name_;
+  bool delete_when_done_;
+  CSimpleArray<CString> files_to_delete_;
+  TarFileCallback callback_;
+  void *callback_context_;
+
+  bool ExtractOneFile(bool *done);
+};
+
+#endif  // OMAHA_MI_EXE_STUB_TAR_H_
diff --git a/net/bind_status_callback.cc b/net/bind_status_callback.cc
index 927bb9a..acc715c 100644
--- a/net/bind_status_callback.cc
+++ b/net/bind_status_callback.cc
@@ -1,319 +1,319 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// IBindStatusCallback interface.

-

-#include "omaha/net/bind_status_callback.h"

-#include <wininet.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-HRESULT QueryHttpInfo(IWinInetHttpInfo* http_info, DWORD query, CString* info) {

-  CORE_LOG(L3, (_T("[QueryHttpInfo][%d]"), query));

-  ASSERT1(http_info);

-  ASSERT1(query);

-  ASSERT1(info);

-

-  info->Empty();

-  DWORD size = 0;

-  DWORD flags = 0;

-  HRESULT hr = http_info->QueryInfo(query, 0, &size, &flags, 0);

-  CORE_LOG(L3, (_T("[http_info->QueryInfo][0x%x][%d]"), hr, size));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CStringA buf;

-  hr = http_info->QueryInfo(query, CStrBufA(buf, size), &size, &flags, 0);

-  CORE_LOG(L3, (_T("[http_info->QueryInfo][0x%x][%d]"), hr, size));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CORE_LOG(L3, (_T("[QueryHttpInfo success][%d][%s]"), query, CA2T(buf)));

-  *info = buf;

-  return S_OK;

-}

-

-BindStatusCallback::BindStatusCallback()

-    : http_verb_(BINDVERB_GET),

-      post_data_byte_count_(0),

-      response_headers_(NULL),

-      response_code_(0) {

-}

-

-HRESULT BindStatusCallback::CreateAndSend(BSTR url,

-                                          BSTR data,

-                                          BSTR request_headers,

-                                          VARIANT response_headers_needed,

-                                          VARIANT* response_headers,

-                                          DWORD* response_code,

-                                          BSTR* cache_filename) {

-  if (!url || !*url) {

-    return E_INVALIDARG;

-  }

-  if (!cache_filename) {

-    return E_INVALIDARG;

-  }

-  *cache_filename = NULL;

-

-  // Using CComObjectNoLock. For the BHO, the DLL is always locked into memory,

-  // and for the exe case, goopdate.dll is always loaded, so using the NoLock

-  // version works well.

-  CComObjectNoLock<BindStatusCallback>* bsc_obj =

-      new CComObjectNoLock<BindStatusCallback>;

-  if (!bsc_obj) {

-    CORE_LOG(LE, (_T("[BindStatusCallback creation failed]")));

-    return E_OUTOFMEMORY;

-  }

-

-  // Implicit AddRef() to bring the refcount to 1.

-  CComPtr<IBindStatusCallback> bsc(bsc_obj);

-  HRESULT hr = bsc_obj->Init(data,

-                             request_headers,

-                             response_headers_needed,

-                             response_headers,

-                             response_code);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString filename;

-  hr = ::URLDownloadToCacheFile(NULL,

-                                url,

-                                CStrBuf(filename, MAX_PATH),

-                                MAX_PATH,

-                                0,

-                                bsc);

-  CORE_LOG(L2, (_T("URLDownloadToCacheFile 0x%x %s"), hr, url));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ASSERT1(!filename.IsEmpty());

-  CORE_LOG(L2, (_T("[BrowserHttpRequest::Send][cache file][%s]"), filename));

-  *cache_filename = filename.AllocSysString();

-  return hr;

-}

-

-HRESULT BindStatusCallback::Init(BSTR post_data,

-                                 BSTR request_headers,

-                                 VARIANT response_headers_needed,

-                                 VARIANT* response_headers,

-                                 DWORD* response_code) {

-  ASSERT1(response_code);

-  if (!response_code) {

-    return E_INVALIDARG;

-  }

-  *response_code = 0;

-

-  if (V_VT(&response_headers_needed) != VT_EMPTY) {

-    if ((V_VT(&response_headers_needed) != (VT_ARRAY | VT_UI4)) ||

-        !response_headers) {

-      return E_INVALIDARG;

-    }

-    response_headers->vt = VT_EMPTY;

-    response_headers_needed_ = response_headers_needed.parray;

-    if (!response_headers_needed_.GetCount()) {

-      return E_INVALIDARG;

-    }

-  }

-

-  request_headers_ = request_headers;

-  response_code_ = response_code;

-  response_headers_ = response_headers;

-  if (!post_data) {

-    http_verb_ = BINDVERB_GET;

-    return S_OK;

-  }

-

-  http_verb_ = BINDVERB_POST;

-  post_data_byte_count_ = ::SysStringByteLen(post_data);

-  reset(post_data_, ::GlobalAlloc(GPTR, post_data_byte_count_));

-  if (!post_data_) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LE, (_T("[BindStatusCallback Init failed 0x%x]"), hr));

-    return hr;

-  }

-

-  memcpy(get(post_data_), post_data, post_data_byte_count_);

-  return S_OK;

-}

-

-// IBindStatusCallback methods.

-

-STDMETHODIMP BindStatusCallback::OnStartBinding(DWORD, IBinding* binding) {

-  binding_ = binding;

-  return S_OK;

-}

-

-STDMETHODIMP BindStatusCallback::GetPriority(LONG*) {

-  return E_NOTIMPL;

-}

-

-STDMETHODIMP BindStatusCallback::OnLowResource(DWORD) {

-  return E_NOTIMPL;

-}

-

-STDMETHODIMP BindStatusCallback::OnProgress(ULONG, ULONG, ULONG, LPCWSTR) {

-  return E_NOTIMPL;

-}

-

-STDMETHODIMP BindStatusCallback::OnStopBinding(HRESULT, LPCWSTR) {

-  CComQIPtr<IWinInetHttpInfo> http_info(binding_);

-  if (!http_info) {

-    return S_OK;

-  }

-

-  CString response_code_buf;

-  if (SUCCEEDED(QueryHttpInfo(http_info,

-                              HTTP_QUERY_STATUS_CODE,

-                              &response_code_buf)) &&

-      !response_code_buf.IsEmpty()) {

-    *response_code_ = _ttoi(response_code_buf);

-  }

-

-  if (!response_headers_needed_) {

-    return S_OK;

-  }

-  ASSERT1(response_headers_);

-  int count = response_headers_needed_.GetCount();

-  ASSERT1(count > 0);

-  int lower_bound = response_headers_needed_.GetLowerBound();

-  int upper_bound = response_headers_needed_.GetUpperBound();

-

-  CComSafeArray<BSTR> response_array(count, lower_bound);

-  for (int i = lower_bound; i <= upper_bound; ++i) {

-    CString response_header_buf;

-    QueryHttpInfo(http_info, response_headers_needed_[i], &response_header_buf);

-    response_array[i] = response_header_buf.AllocSysString();

-  }

-

-  response_headers_->vt = VT_ARRAY | VT_BSTR;

-  response_headers_->parray = response_array.Detach();

-  return S_OK;

-}

-

-STDMETHODIMP BindStatusCallback::GetBindInfo(DWORD* flags, BINDINFO* info) {

-  ASSERT1(flags);

-  ASSERT1(info);

-  *flags = 0;

-

-  // Set up the BINDINFO data structure.

-  info->cbSize = sizeof(*info);

-  info->dwBindVerb = http_verb_;

-  info->szExtraInfo = NULL;

-

-  // Initialize the STGMEDIUM.

-  SetZero(info->stgmedData);

-  info->grfBindInfoF = 0;

-  info->szCustomVerb = NULL;

-

-  switch (http_verb_) {

-    case BINDVERB_POST:

-      if (post_data_) {

-        // Fill the STGMEDIUM with the data to post. Certain versions of Urlmon

-        // require TYMED_GLOBAL with GMEM_FIXED.

-        info->stgmedData.tymed = TYMED_HGLOBAL;

-        info->stgmedData.hGlobal = get(post_data_);

-

-        // The documentation for GetBindInfo() indicates that the method could

-        // be called multiple times for the same request. We do not want to

-        // allocate global memory for each of those times. So we maintain

-        // ownership of the global memory, and pass a reference to it each time.

-        // The HGLOBAL is released on BindStatusCallback destruction. Hence we

-        // set pUnkForRelease to our IUnknown ptr.

-        info->stgmedData.pUnkForRelease =

-            static_cast<IBindStatusCallback*>(this);

-        AddRef();

-

-        info->cbstgmedData = post_data_byte_count_;

-      }

-      return S_OK;

-

-    case BINDVERB_GET:

-      return S_OK;

-

-    case BINDVERB_PUT:

-    case BINDVERB_CUSTOM:

-    default:

-      ASSERT1(false);

-      return E_FAIL;

-  }

-}

-

-STDMETHODIMP BindStatusCallback::OnDataAvailable(DWORD,

-                                                 DWORD,

-                                                 FORMATETC*,

-                                                 STGMEDIUM*) {

-  // The documentation does not explicitly say that E_NOTIMPL can be returned

-  // for this method. So we return S_OK.

-  return S_OK;

-}

-

-STDMETHODIMP BindStatusCallback::OnObjectAvailable(REFIID, IUnknown*) {

-  // The documentation does not explicitly say that E_NOTIMPL can be returned

-  // for this method. So we return S_OK.

-  return S_OK;

-}

-

-STDMETHODIMP BindStatusCallback::BeginningTransaction(LPCWSTR,

-                                                      LPCWSTR,

-                                                      DWORD,

-                                                      LPWSTR* request_headers) {

-  if (!request_headers) {

-    return E_INVALIDARG;

-  }

-  *request_headers = NULL;

-

-  if (request_headers_.IsEmpty()) {

-    return S_OK;

-  }

-

-  int request_headers_size = request_headers_.GetLength() + 1;

-  TCHAR* additional_headers = static_cast<TCHAR*>(

-      ::CoTaskMemAlloc(request_headers_size * sizeof(TCHAR)));

-  if (!additional_headers) {

-    return E_OUTOFMEMORY;

-  }

-

-  _tcscpy_s(additional_headers, request_headers_size, request_headers_);

-  *request_headers = additional_headers;

-

-  return S_OK;

-}

-

-STDMETHODIMP BindStatusCallback::OnResponse(DWORD response_code,

-                                            LPCWSTR response_headers,

-                                            LPCWSTR request_headers,

-                                            LPWSTR* additional_headers) {

-  CORE_LOG(L1, (_T("[OnResponse [%d][%s]"), response_code, response_headers));

-  UNREFERENCED_PARAMETER(response_code);

-  UNREFERENCED_PARAMETER(response_headers);

-  UNREFERENCED_PARAMETER(request_headers);

-  if (!additional_headers) {

-    return E_INVALIDARG;

-  }

-

-  *additional_headers = NULL;

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// IBindStatusCallback interface.
+
+#include "omaha/net/bind_status_callback.h"
+#include <wininet.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+HRESULT QueryHttpInfo(IWinInetHttpInfo* http_info, DWORD query, CString* info) {
+  CORE_LOG(L3, (_T("[QueryHttpInfo][%d]"), query));
+  ASSERT1(http_info);
+  ASSERT1(query);
+  ASSERT1(info);
+
+  info->Empty();
+  DWORD size = 0;
+  DWORD flags = 0;
+  HRESULT hr = http_info->QueryInfo(query, 0, &size, &flags, 0);
+  CORE_LOG(L3, (_T("[http_info->QueryInfo][0x%x][%d]"), hr, size));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CStringA buf;
+  hr = http_info->QueryInfo(query, CStrBufA(buf, size), &size, &flags, 0);
+  CORE_LOG(L3, (_T("[http_info->QueryInfo][0x%x][%d]"), hr, size));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CORE_LOG(L3, (_T("[QueryHttpInfo success][%d][%s]"), query, CA2T(buf)));
+  *info = buf;
+  return S_OK;
+}
+
+BindStatusCallback::BindStatusCallback()
+    : http_verb_(BINDVERB_GET),
+      post_data_byte_count_(0),
+      response_headers_(NULL),
+      response_code_(0) {
+}
+
+HRESULT BindStatusCallback::CreateAndSend(BSTR url,
+                                          BSTR data,
+                                          BSTR request_headers,
+                                          VARIANT response_headers_needed,
+                                          VARIANT* response_headers,
+                                          DWORD* response_code,
+                                          BSTR* cache_filename) {
+  if (!url || !*url) {
+    return E_INVALIDARG;
+  }
+  if (!cache_filename) {
+    return E_INVALIDARG;
+  }
+  *cache_filename = NULL;
+
+  // Using CComObjectNoLock. For the BHO, the DLL is always locked into memory,
+  // and for the exe case, goopdate.dll is always loaded, so using the NoLock
+  // version works well.
+  CComObjectNoLock<BindStatusCallback>* bsc_obj =
+      new CComObjectNoLock<BindStatusCallback>;
+  if (!bsc_obj) {
+    CORE_LOG(LE, (_T("[BindStatusCallback creation failed]")));
+    return E_OUTOFMEMORY;
+  }
+
+  // Implicit AddRef() to bring the refcount to 1.
+  CComPtr<IBindStatusCallback> bsc(bsc_obj);
+  HRESULT hr = bsc_obj->Init(data,
+                             request_headers,
+                             response_headers_needed,
+                             response_headers,
+                             response_code);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString filename;
+  hr = ::URLDownloadToCacheFile(NULL,
+                                url,
+                                CStrBuf(filename, MAX_PATH),
+                                MAX_PATH,
+                                0,
+                                bsc);
+  CORE_LOG(L2, (_T("URLDownloadToCacheFile 0x%x %s"), hr, url));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ASSERT1(!filename.IsEmpty());
+  CORE_LOG(L2, (_T("[BrowserHttpRequest::Send][cache file][%s]"), filename));
+  *cache_filename = filename.AllocSysString();
+  return hr;
+}
+
+HRESULT BindStatusCallback::Init(BSTR post_data,
+                                 BSTR request_headers,
+                                 VARIANT response_headers_needed,
+                                 VARIANT* response_headers,
+                                 DWORD* response_code) {
+  ASSERT1(response_code);
+  if (!response_code) {
+    return E_INVALIDARG;
+  }
+  *response_code = 0;
+
+  if (V_VT(&response_headers_needed) != VT_EMPTY) {
+    if ((V_VT(&response_headers_needed) != (VT_ARRAY | VT_UI4)) ||
+        !response_headers) {
+      return E_INVALIDARG;
+    }
+    response_headers->vt = VT_EMPTY;
+    response_headers_needed_ = response_headers_needed.parray;
+    if (!response_headers_needed_.GetCount()) {
+      return E_INVALIDARG;
+    }
+  }
+
+  request_headers_ = request_headers;
+  response_code_ = response_code;
+  response_headers_ = response_headers;
+  if (!post_data) {
+    http_verb_ = BINDVERB_GET;
+    return S_OK;
+  }
+
+  http_verb_ = BINDVERB_POST;
+  post_data_byte_count_ = ::SysStringByteLen(post_data);
+  reset(post_data_, ::GlobalAlloc(GPTR, post_data_byte_count_));
+  if (!post_data_) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LE, (_T("[BindStatusCallback Init failed 0x%x]"), hr));
+    return hr;
+  }
+
+  memcpy(get(post_data_), post_data, post_data_byte_count_);
+  return S_OK;
+}
+
+// IBindStatusCallback methods.
+
+STDMETHODIMP BindStatusCallback::OnStartBinding(DWORD, IBinding* binding) {
+  binding_ = binding;
+  return S_OK;
+}
+
+STDMETHODIMP BindStatusCallback::GetPriority(LONG*) {
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP BindStatusCallback::OnLowResource(DWORD) {
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP BindStatusCallback::OnProgress(ULONG, ULONG, ULONG, LPCWSTR) {
+  return E_NOTIMPL;
+}
+
+STDMETHODIMP BindStatusCallback::OnStopBinding(HRESULT, LPCWSTR) {
+  CComQIPtr<IWinInetHttpInfo> http_info(binding_);
+  if (!http_info) {
+    return S_OK;
+  }
+
+  CString response_code_buf;
+  if (SUCCEEDED(QueryHttpInfo(http_info,
+                              HTTP_QUERY_STATUS_CODE,
+                              &response_code_buf)) &&
+      !response_code_buf.IsEmpty()) {
+    *response_code_ = _ttoi(response_code_buf);
+  }
+
+  if (!response_headers_needed_) {
+    return S_OK;
+  }
+  ASSERT1(response_headers_);
+  int count = response_headers_needed_.GetCount();
+  ASSERT1(count > 0);
+  int lower_bound = response_headers_needed_.GetLowerBound();
+  int upper_bound = response_headers_needed_.GetUpperBound();
+
+  CComSafeArray<BSTR> response_array(count, lower_bound);
+  for (int i = lower_bound; i <= upper_bound; ++i) {
+    CString response_header_buf;
+    QueryHttpInfo(http_info, response_headers_needed_[i], &response_header_buf);
+    response_array[i] = response_header_buf.AllocSysString();
+  }
+
+  response_headers_->vt = VT_ARRAY | VT_BSTR;
+  response_headers_->parray = response_array.Detach();
+  return S_OK;
+}
+
+STDMETHODIMP BindStatusCallback::GetBindInfo(DWORD* flags, BINDINFO* info) {
+  ASSERT1(flags);
+  ASSERT1(info);
+  *flags = 0;
+
+  // Set up the BINDINFO data structure.
+  info->cbSize = sizeof(*info);
+  info->dwBindVerb = http_verb_;
+  info->szExtraInfo = NULL;
+
+  // Initialize the STGMEDIUM.
+  SetZero(info->stgmedData);
+  info->grfBindInfoF = 0;
+  info->szCustomVerb = NULL;
+
+  switch (http_verb_) {
+    case BINDVERB_POST:
+      if (post_data_) {
+        // Fill the STGMEDIUM with the data to post. Certain versions of Urlmon
+        // require TYMED_GLOBAL with GMEM_FIXED.
+        info->stgmedData.tymed = TYMED_HGLOBAL;
+        info->stgmedData.hGlobal = get(post_data_);
+
+        // The documentation for GetBindInfo() indicates that the method could
+        // be called multiple times for the same request. We do not want to
+        // allocate global memory for each of those times. So we maintain
+        // ownership of the global memory, and pass a reference to it each time.
+        // The HGLOBAL is released on BindStatusCallback destruction. Hence we
+        // set pUnkForRelease to our IUnknown ptr.
+        info->stgmedData.pUnkForRelease =
+            static_cast<IBindStatusCallback*>(this);
+        AddRef();
+
+        info->cbstgmedData = post_data_byte_count_;
+      }
+      return S_OK;
+
+    case BINDVERB_GET:
+      return S_OK;
+
+    case BINDVERB_PUT:
+    case BINDVERB_CUSTOM:
+    default:
+      ASSERT1(false);
+      return E_FAIL;
+  }
+}
+
+STDMETHODIMP BindStatusCallback::OnDataAvailable(DWORD,
+                                                 DWORD,
+                                                 FORMATETC*,
+                                                 STGMEDIUM*) {
+  // The documentation does not explicitly say that E_NOTIMPL can be returned
+  // for this method. So we return S_OK.
+  return S_OK;
+}
+
+STDMETHODIMP BindStatusCallback::OnObjectAvailable(REFIID, IUnknown*) {
+  // The documentation does not explicitly say that E_NOTIMPL can be returned
+  // for this method. So we return S_OK.
+  return S_OK;
+}
+
+STDMETHODIMP BindStatusCallback::BeginningTransaction(LPCWSTR,
+                                                      LPCWSTR,
+                                                      DWORD,
+                                                      LPWSTR* request_headers) {
+  if (!request_headers) {
+    return E_INVALIDARG;
+  }
+  *request_headers = NULL;
+
+  if (request_headers_.IsEmpty()) {
+    return S_OK;
+  }
+
+  int request_headers_size = request_headers_.GetLength() + 1;
+  TCHAR* additional_headers = static_cast<TCHAR*>(
+      ::CoTaskMemAlloc(request_headers_size * sizeof(TCHAR)));
+  if (!additional_headers) {
+    return E_OUTOFMEMORY;
+  }
+
+  _tcscpy_s(additional_headers, request_headers_size, request_headers_);
+  *request_headers = additional_headers;
+
+  return S_OK;
+}
+
+STDMETHODIMP BindStatusCallback::OnResponse(DWORD response_code,
+                                            LPCWSTR response_headers,
+                                            LPCWSTR request_headers,
+                                            LPWSTR* additional_headers) {
+  CORE_LOG(L1, (_T("[OnResponse [%d][%s]"), response_code, response_headers));
+  UNREFERENCED_PARAMETER(response_code);
+  UNREFERENCED_PARAMETER(response_headers);
+  UNREFERENCED_PARAMETER(request_headers);
+  if (!additional_headers) {
+    return E_INVALIDARG;
+  }
+
+  *additional_headers = NULL;
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/net/bind_status_callback.h b/net/bind_status_callback.h
index 98fee1b..c505081 100644
--- a/net/bind_status_callback.h
+++ b/net/bind_status_callback.h
@@ -1,96 +1,96 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// IBindStatusCallback interface. Support for HTTP POST.

-

-#ifndef OMAHA_NET_BIND_STATUS_CALLBACK_H__

-#define OMAHA_NET_BIND_STATUS_CALLBACK_H__

-

-#include <windows.h>

-#include <urlmon.h>

-#include <atlbase.h>

-#include <atlcom.h>

-#include <atlsafe.h>

-#include <atlstr.h>

-#include "omaha/common/scoped_any.h"

-

-namespace omaha {

-

-class ATL_NO_VTABLE BindStatusCallback

-    : public CComObjectRootEx<CComObjectThreadModel>,

-      public IBindStatusCallback,

-      public IHttpNegotiate {

- public:

-  static HRESULT CreateAndSend(BSTR url,

-                               BSTR post_data,

-                               BSTR request_headers,

-                               VARIANT response_headers_needed,

-                               VARIANT* response_headers,

-                               DWORD* response_code,

-                               BSTR* cache_filename);

-

-  // C4505: unreferenced IUnknown local functions have been removed

-  #pragma warning(disable : 4505)

-  BEGIN_COM_MAP(BindStatusCallback)

-    COM_INTERFACE_ENTRY(IBindStatusCallback)

-    COM_INTERFACE_ENTRY(IHttpNegotiate)

-  END_COM_MAP()

-

-  // IBindStatusCallback methods.

-  STDMETHODIMP OnStartBinding(DWORD reserved, IBinding* binding);

-  STDMETHODIMP GetPriority(LONG* priority);

-  STDMETHODIMP OnLowResource(DWORD reserved);

-  STDMETHODIMP OnProgress(ULONG, ULONG, ULONG, LPCWSTR);

-  STDMETHODIMP OnStopBinding(HRESULT, LPCWSTR);

-  STDMETHODIMP GetBindInfo(DWORD* bindf_flags, BINDINFO* bind_info);

-  STDMETHODIMP OnDataAvailable(DWORD, DWORD, FORMATETC*, STGMEDIUM*);

-  STDMETHODIMP OnObjectAvailable(REFIID, IUnknown*);

-

-  // IHttpNegotiate methods

-  STDMETHODIMP BeginningTransaction(LPCWSTR url,

-                                    LPCWSTR request_headers,

-                                    DWORD reserved,

-                                    LPWSTR* additional_headers);

-  STDMETHODIMP OnResponse(DWORD response_code,

-                          LPCWSTR response_headers,

-                          LPCWSTR request_headers,

-                          LPWSTR* additional_request_headers);

-

- protected:

-  BindStatusCallback();

-  virtual ~BindStatusCallback() {}

-

- private:

-  HRESULT Init(BSTR post_data,

-               BSTR request_headers,

-               VARIANT response_headers_needed,

-               VARIANT* response_headers,

-               DWORD* response_code);

-

- private:

-  BINDVERB              http_verb_;

-  scoped_hglobal        post_data_;

-  DWORD                 post_data_byte_count_;

-  CString               request_headers_;

-  CComSafeArray<DWORD>  response_headers_needed_;

-  VARIANT*              response_headers_;

-  DWORD*                response_code_;

-  CComPtr<IBinding>     binding_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_NET_BIND_STATUS_CALLBACK_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// IBindStatusCallback interface. Support for HTTP POST.
+
+#ifndef OMAHA_NET_BIND_STATUS_CALLBACK_H__
+#define OMAHA_NET_BIND_STATUS_CALLBACK_H__
+
+#include <windows.h>
+#include <urlmon.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlsafe.h>
+#include <atlstr.h>
+#include "omaha/common/scoped_any.h"
+
+namespace omaha {
+
+class ATL_NO_VTABLE BindStatusCallback
+    : public CComObjectRootEx<CComObjectThreadModel>,
+      public IBindStatusCallback,
+      public IHttpNegotiate {
+ public:
+  static HRESULT CreateAndSend(BSTR url,
+                               BSTR post_data,
+                               BSTR request_headers,
+                               VARIANT response_headers_needed,
+                               VARIANT* response_headers,
+                               DWORD* response_code,
+                               BSTR* cache_filename);
+
+  // C4505: unreferenced IUnknown local functions have been removed
+  #pragma warning(disable : 4505)
+  BEGIN_COM_MAP(BindStatusCallback)
+    COM_INTERFACE_ENTRY(IBindStatusCallback)
+    COM_INTERFACE_ENTRY(IHttpNegotiate)
+  END_COM_MAP()
+
+  // IBindStatusCallback methods.
+  STDMETHODIMP OnStartBinding(DWORD reserved, IBinding* binding);
+  STDMETHODIMP GetPriority(LONG* priority);
+  STDMETHODIMP OnLowResource(DWORD reserved);
+  STDMETHODIMP OnProgress(ULONG, ULONG, ULONG, LPCWSTR);
+  STDMETHODIMP OnStopBinding(HRESULT, LPCWSTR);
+  STDMETHODIMP GetBindInfo(DWORD* bindf_flags, BINDINFO* bind_info);
+  STDMETHODIMP OnDataAvailable(DWORD, DWORD, FORMATETC*, STGMEDIUM*);
+  STDMETHODIMP OnObjectAvailable(REFIID, IUnknown*);
+
+  // IHttpNegotiate methods
+  STDMETHODIMP BeginningTransaction(LPCWSTR url,
+                                    LPCWSTR request_headers,
+                                    DWORD reserved,
+                                    LPWSTR* additional_headers);
+  STDMETHODIMP OnResponse(DWORD response_code,
+                          LPCWSTR response_headers,
+                          LPCWSTR request_headers,
+                          LPWSTR* additional_request_headers);
+
+ protected:
+  BindStatusCallback();
+  virtual ~BindStatusCallback() {}
+
+ private:
+  HRESULT Init(BSTR post_data,
+               BSTR request_headers,
+               VARIANT response_headers_needed,
+               VARIANT* response_headers,
+               DWORD* response_code);
+
+ private:
+  BINDVERB              http_verb_;
+  scoped_hglobal        post_data_;
+  DWORD                 post_data_byte_count_;
+  CString               request_headers_;
+  CComSafeArray<DWORD>  response_headers_needed_;
+  VARIANT*              response_headers_;
+  DWORD*                response_code_;
+  CComPtr<IBinding>     binding_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_NET_BIND_STATUS_CALLBACK_H__
+
diff --git a/net/bits_request.cc b/net/bits_request.cc
index cdedddc..7bcb772 100644
--- a/net/bits_request.cc
+++ b/net/bits_request.cc
@@ -1,600 +1,600 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// There is an implicit assumption that one bits job contains only one file.

-//

-// TODO(omaha): assert somewhere on all the job invariants.

-//

-// TODO(omaha): no caching at all is implemented, as far as sharing downloads

-// between different bits users downloading the same file.

-// TODO(omaha): same user downloading same file in different logon session is

-// not handled.

-// TODO(omaha): generally speaking, impersonation scenarios are not

-// yet handled by the code. This is important when creating or opening an

-// existing job.

-

-#include "omaha/net/bits_request.h"

-

-#include <winhttp.h>

-#include <atlbase.h>

-#include <atlstr.h>

-#include <functional>

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/utils.h"

-#include "omaha/net/bits_utils.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/proxy_auth.h"

-

-namespace omaha {

-

-namespace {

-

-const TCHAR* const kJobDescription = _T("Google Update");

-

-// TODO(omaha): expose polling interval, as it is likely that polling for

-// downloading files must be different than polling for retrieving smaller

-// files.

-const int kPollingIntervalMs = 1000;

-

-// Returns the job priority or -1 in case of errors.

-int GetJobPriority(IBackgroundCopyJob* job) {

-  ASSERT1(job);

-  BG_JOB_PRIORITY priority = BG_JOB_PRIORITY_FOREGROUND;

-  return SUCCEEDED(job->GetPriority(&priority)) ? priority : -1;

-}

-

-}   // namespace

-

-

-BitsRequest::BitsRequest()

-    : request_buffer_(NULL),

-      request_buffer_length_(0),

-      low_priority_(false),

-      is_canceled_(false),

-      callback_(NULL),

-      minimum_retry_delay_(-1),

-      no_progress_timeout_(-1),

-      current_auth_scheme_(0),

-      creds_set_scheme_unknown_(false) {

-  VERIFY1(SUCCEEDED(GetBitsManager(&bits_manager_)));

-}

-

-// Once this instance connects to a BITS job, it either completes the job

-// or it cleans it up to avoid leaving junk in the BITS queue.

-BitsRequest::~BitsRequest() {

-  Close();

-  callback_ = NULL;

-

-  // TODO(omaha): for unknown reasons, qmgrprxy.dll gets unloaded at some point

-  // during program execution and subsequent calls to BITS crash. This

-  // indicates a ref count problem somewhere. The work around is to not

-  // call the IUnknown::Release if the module is not in memory.

-  if (::GetModuleHandle(_T("qmgrprxy.dll")) == NULL) {

-    bits_manager_.Detach();

-  }

-}

-

-HRESULT BitsRequest::Close() {

-  NET_LOG(L3, (_T("[BitsRequest::Close]")));

-  __mutexBlock(lock_) {

-    if (request_state_.get()) {

-      VERIFY1(SUCCEEDED(CancelBitsJob(request_state_->bits_job)));

-    }

-    request_state_.reset();

-  }

-  return S_OK;

-}

-

-HRESULT BitsRequest::Cancel() {

-  NET_LOG(L3, (_T("[BitsRequest::Cancel]")));

-  __mutexBlock(lock_) {

-    is_canceled_ = true;

-    if (request_state_.get()) {

-      VERIFY1(SUCCEEDED(CancelBitsJob(request_state_->bits_job)));

-    }

-  }

-  return S_OK;

-}

-

-HRESULT BitsRequest::Send() {

-  NET_LOG(L3, (_T("[BitsRequest::Send][%s]"), url_));

-

-  ASSERT1(!url_.IsEmpty());

-

-  __mutexBlock(lock_) {

-    if (request_state_.get()) {

-      VERIFY1(SUCCEEDED(CancelBitsJob(request_state_->bits_job)));

-    }

-    request_state_.reset(new TransientRequestState);

-  }

-

-  bool is_created = false;

-  HRESULT hr = BitsRequest::CreateOrOpenJob(filename_,

-                                            &request_state_->bits_job,

-                                            &is_created);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // The job id is used for logging purposes only.

-  request_state_->bits_job->GetId(&request_state_->bits_job_id);

-

-  NET_LOG(L3, (_T("[BITS job %s]"), GuidToString(request_state_->bits_job_id)));

-

-  if (is_created) {

-    hr = SetInvariantJobProperties();

-    if (FAILED(hr)) {

-      HRESULT hr_cancel_bits_job(CancelBitsJob(request_state_->bits_job));

-      if (FAILED(hr_cancel_bits_job)) {

-        NET_LOG(LW, (_T("[CancelBitsJob failed][0x%08x]"), hr_cancel_bits_job));

-      }

-      request_state_->bits_job = NULL;

-      return hr;

-    }

-  }

-

-  return DoSend();

-}

-

-HRESULT BitsRequest::QueryHeadersString(uint32, const TCHAR*, CString*) const {

-  return E_NOTIMPL;

-}

-

-CString BitsRequest::GetResponseHeaders() const {

-  return CString();

-}

-

-

-HRESULT BitsRequest::CreateOrOpenJob(const TCHAR* display_name,

-                                     IBackgroundCopyJob** bits_job,

-                                     bool* is_created) {

-  ASSERT1(display_name);

-  ASSERT1(bits_job);

-  ASSERT1(*bits_job == NULL);

-  ASSERT1(is_created);

-

-  CComPtr<IBackgroundCopyManager> bits_manager;

-  HRESULT hr = GetBitsManager(&bits_manager);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Try to find if we already have the job in the BITS queue.

-  // By convention, the display name of the job is the same as the file name.

-  CComPtr<IBackgroundCopyJob> job;

-  hr = FindBitsJobIf(std::bind2nd(JobDisplayNameEqual(), display_name),

-                     bits_manager,

-                     &job);

-  if (SUCCEEDED(hr)) {

-    NET_LOG(L3, (_T("[found BITS job][%s]"), display_name));

-    *bits_job = job.Detach();

-    *is_created = false;

-    return S_OK;

-  }

-

-  GUID guid = {0};

-  hr = bits_manager->CreateJob(display_name, BG_JOB_TYPE_DOWNLOAD, &guid, &job);

-  if (SUCCEEDED(hr)) {

-    *bits_job = job.Detach();

-    *is_created = true;

-    return S_OK;

-  }

-

-  *bits_job = NULL;

-  return hr;

-}

-

-HRESULT BitsRequest::SetInvariantJobProperties() {

-  ASSERT1(request_state_.get());

-  ASSERT1(request_state_->bits_job);

-  HRESULT hr = request_state_->bits_job->AddFile(url_, filename_);

-  if (FAILED(hr)) {

-    NET_LOG(LE, (_T("[IBackgroundCopyJob::AddFile failed][0x%08x]"), hr));

-    return hr;

-  }

-  hr = request_state_->bits_job->SetDescription(kJobDescription);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  return S_OK;

-}

-

-HRESULT BitsRequest::SetJobProperties() {

-  ASSERT1(request_state_.get());

-  ASSERT1(request_state_->bits_job);

-  BG_JOB_PRIORITY priority = low_priority_ ? BG_JOB_PRIORITY_NORMAL :

-                                             BG_JOB_PRIORITY_FOREGROUND;

-  HRESULT hr = request_state_->bits_job->SetPriority(priority);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (minimum_retry_delay_ != -1) {

-    ASSERT1(minimum_retry_delay_ >= 0);

-    hr = request_state_->bits_job->SetMinimumRetryDelay(minimum_retry_delay_);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-  if (no_progress_timeout_ != -1) {

-    ASSERT1(no_progress_timeout_ >= 0);

-    hr = request_state_->bits_job->SetNoProgressTimeout(no_progress_timeout_);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-  return S_OK;

-}

-

-HRESULT BitsRequest::DetectManualProxy() {

-  if (NetworkConfig::GetAccessType(network_config_) !=

-      WINHTTP_ACCESS_TYPE_AUTO_DETECT) {

-    return S_OK;

-  }

-

-  HttpClient::ProxyInfo proxy_info = {0};

-  HRESULT hr = NetworkConfig::Instance().GetProxyForUrl(

-      url_,

-      network_config_.auto_config_url,

-      &proxy_info);

-  if (SUCCEEDED(hr) &&

-      proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {

-    network_config_.auto_detect = false;

-    network_config_.auto_config_url.Empty();

-    network_config_.proxy = proxy_info.proxy;

-    network_config_.proxy_bypass = proxy_info.proxy_bypass;

-  }

-

-  ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy));

-  ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy_bypass));

-

-  NET_LOG(L3, (_T("[GetProxyForUrl returned][0x%08x]"), hr));

-  return hr;

-}

-

-HRESULT BitsRequest::SetJobProxyUsage() {

-  ASSERT1(request_state_.get());

-  ASSERT1(request_state_->bits_job);

-  BG_JOB_PROXY_USAGE proxy_usage = BG_JOB_PROXY_USAGE_NO_PROXY;

-  const TCHAR* proxy = NULL;

-  const TCHAR* proxy_bypass = NULL;

-

-  DetectManualProxy();

-

-  int access_type = NetworkConfig::GetAccessType(network_config_);

-  if (access_type == WINHTTP_ACCESS_TYPE_AUTO_DETECT) {

-    proxy_usage = BG_JOB_PROXY_USAGE_AUTODETECT;

-  } else if (access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {

-    proxy_usage = BG_JOB_PROXY_USAGE_OVERRIDE;

-    proxy = network_config_.proxy;

-    proxy_bypass = network_config_.proxy_bypass;

-  }

-  HRESULT hr = request_state_->bits_job->SetProxySettings(proxy_usage,

-                                                          proxy,

-                                                          proxy_bypass);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (proxy_usage == BG_JOB_PROXY_USAGE_AUTODETECT ||

-      proxy_usage == BG_JOB_PROXY_USAGE_OVERRIDE) {

-    // Set implicit credentials if we are going through a proxy, just in case

-    // the proxy is requiring authentication. Continue on errors, maybe

-    // the credentials won't be needed anyway. There will be one more chance

-    // to set credentials when the proxy challenges and the job errors out.

-    creds_set_scheme_unknown_ = false;

-    hr = SetProxyAuthImplicitCredentials(request_state_->bits_job,

-                                         BG_AUTH_SCHEME_NEGOTIATE);

-    if (SUCCEEDED(hr)) {

-      current_auth_scheme_ = BG_AUTH_SCHEME_NEGOTIATE;

-    } else {

-      OPT_LOG(LW, (_T("[failed to set BITS proxy credentials][0x%08x]"), hr));

-    }

-  }

-  return S_OK;

-}

-

-HRESULT BitsRequest::DoSend() {

-  ASSERT1(request_state_.get());

-  ASSERT1(request_state_->bits_job);

-

-  NET_LOG(L3, (_T("[BitsRequest::DoSend]")));

-

-  if (is_canceled_) {

-    return OMAHA_NET_E_REQUEST_CANCELLED;

-  }

-

-  HRESULT hr = SetJobProperties();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  hr = SetJobProxyUsage();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  hr = request_state_->bits_job->Resume();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  NET_LOG(L3, (_T("[job priority %d]"),

-               GetJobPriority(request_state_->bits_job)));

-

-  // Poll for state changes. The code executing on the state changes must be

-  // idempotent, as the same state can be seen multiple times when looping.

-  // There is only one important case, which is retrying the job when the

-  // job is in the ERROR state. We attempt to handle the error, for

-  // example retrying one more time or changing proxy credentials, and then

-  // we resume the job. There is an assumption, so far true, that calling

-  // Resume on a job, the state changes right away from SUSPENDED to QUEUED.

-

-  for (;;) {

-    if (is_canceled_) {

-      return OMAHA_NET_E_REQUEST_CANCELLED;

-    }

-

-    BG_JOB_STATE job_state = BG_JOB_STATE_ERROR;

-    hr = request_state_->bits_job->GetState(&job_state);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    NET_LOG(L3, (_T("[job %s][state %s]"),

-                 GuidToString(request_state_->bits_job_id),

-                 JobStateToString(job_state)));

-

-    switch (job_state) {

-      case BG_JOB_STATE_QUEUED:

-        break;

-

-      case BG_JOB_STATE_CONNECTING:

-        if (callback_) {

-          callback_->OnProgress(0,

-                                0,

-                                WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER,

-                                NULL);

-        }

-        break;

-

-      case BG_JOB_STATE_TRANSFERRING:

-        OnStateTransferring();

-        break;

-

-      case BG_JOB_STATE_TRANSIENT_ERROR:

-        break;

-

-      case BG_JOB_STATE_ERROR:

-        hr = OnStateError();

-        if (SUCCEEDED(hr)) {

-          // The error handler dealt with the error. Countinue the loop.

-          break;

-        }

-

-        // Give up.

-        return request_state_->http_status_code ? S_OK : hr;

-

-      case BG_JOB_STATE_TRANSFERRED:

-        hr = request_state_->bits_job->Complete();

-        if (SUCCEEDED(hr) || BG_S_UNABLE_TO_DELETE_FILES == hr) {

-          // Assume the status code is 200 if the transfer completed. BITS does

-          // ot provide access to the status code.

-          request_state_->http_status_code = HTTP_STATUS_OK;

-

-          if (creds_set_scheme_unknown_) {

-            // Bits job completed successfully. If we have a valid username, we

-            // record the auth scheme with the NetworkConfig, so it can be used

-            // in the future within this process.

-            ASSERT1(BitsToWinhttpProxyAuthScheme(current_auth_scheme_) !=

-                    UNKNOWN_AUTH_SCHEME);

-            bool is_https = String_StartsWith(url_, kHttpsProtoScheme, true);

-            VERIFY1(SUCCEEDED(NetworkConfig::Instance().SetProxyAuthScheme(

-                network_config_.proxy, is_https,

-                BitsToWinhttpProxyAuthScheme(current_auth_scheme_))));

-          }

-

-          return S_OK;

-        } else {

-          return hr;

-        }

-

-      case BG_JOB_STATE_SUSPENDED:

-        // Pausing downloads is not supported yet.

-        ASSERT1(false);

-        return E_FAIL;

-

-      case BG_JOB_STATE_ACKNOWLEDGED:

-        ASSERT1(false);

-        return S_OK;

-

-      case BG_JOB_STATE_CANCELLED:

-        return OMAHA_NET_E_REQUEST_CANCELLED;

-    };

-

-    ::Sleep(kPollingIntervalMs);

-  }

-}

-

-HRESULT BitsRequest::OnStateTransferring() {

-  if (!callback_) {

-    return S_OK;

-  }

-  BG_JOB_PROGRESS progress = {0};

-  HRESULT hr = request_state_->bits_job->GetProgress(&progress);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ASSERT1(progress.FilesTotal == 1);

-  ASSERT1(progress.BytesTransferred <= INT_MAX);

-  ASSERT1(progress.BytesTotal <= INT_MAX);

-  callback_->OnProgress(static_cast<int>(progress.BytesTransferred),

-                        static_cast<int>(progress.BytesTotal),

-                        WINHTTP_CALLBACK_STATUS_READ_COMPLETE,

-                        NULL);

-  return S_OK;

-}

-

-HRESULT BitsRequest::OnStateError() {

-  CComPtr<IBackgroundCopyError> error;

-  HRESULT hr = request_state_->bits_job->GetError(&error);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  BG_ERROR_CONTEXT error_context = BG_ERROR_CONTEXT_NONE;

-  HRESULT error_code = E_FAIL;

-  hr = error->GetError(&error_context, &error_code);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(FAILED(error_code));

-

-  NET_LOG(L3, (_T("[handle bits error][0x%08x]"), error_code));

-

-  request_state_->http_status_code = GetHttpStatusFromBitsError(error_code);

-

-  if (error_code == BG_E_HTTP_ERROR_407) {

-    hr = !creds_set_scheme_unknown_ ? HandleProxyAuthenticationError() :

-                                      HandleProxyAuthenticationErrorCredsSet();

-    if (SUCCEEDED(hr)) {

-      return S_OK;

-    }

-  }

-

-  // We could not handle this error. The control will return to the caller.

-  return error_code;

-}

-

-HRESULT BitsRequest::GetProxyCredentials() {

-  CString username;

-  CString password;

-  uint32 auth_scheme = UNKNOWN_AUTH_SCHEME;

-  bool is_https = String_StartsWith(url_, kHttpsProtoScheme, true);

-

-  if (!NetworkConfig::Instance().GetProxyCredentials(true, false,

-          network_config_.proxy, is_https, &username, &password,

-          &auth_scheme)) {

-    OPT_LOG(LE, (_T("[BitsRequest::GetProxyCredentials failed]")));

-    return E_ACCESSDENIED;

-  }

-

-  if (auth_scheme != UNKNOWN_AUTH_SCHEME) {

-    current_auth_scheme_ = WinHttpToBitsProxyAuthScheme(auth_scheme);

-    OPT_LOG(L3, (_T("[BitsRequest::GetProxyCredentials][%s]"),

-                 BitsAuthSchemeToString(current_auth_scheme_)));

-    return SetProxyAuthCredentials(request_state_->bits_job,

-               CStrBuf(username), CStrBuf(password),

-               static_cast<BG_AUTH_SCHEME>(current_auth_scheme_));

-  }

-

-  OPT_LOG(L3, (_T("[BitsRequest::GetProxyCredentials][Auth scheme unknown]")));

-  // We do not know the scheme beforehand. So we set credentials on all the

-  // schemes except BASIC and try them out in seqence. We could have used BASIC

-  // as well, however, we do not want to leak passwords by mistake.

-  for (int scheme = BG_AUTH_SCHEME_DIGEST; scheme <= BG_AUTH_SCHEME_NEGOTIATE;

-       ++scheme) {

-    HRESULT hr = SetProxyAuthCredentials(request_state_->bits_job,

-                                         CStrBuf(username), CStrBuf(password),

-                                         static_cast<BG_AUTH_SCHEME>(scheme));

-    if (FAILED(hr)) {

-      OPT_LOG(LE, (_T("[BitsRequest::GetProxyCredentials][0x%08x][%s]"),

-                   hr, BitsAuthSchemeToString(scheme)));

-      return hr;

-    }

-  }

-

-  current_auth_scheme_ = BG_AUTH_SCHEME_NEGOTIATE;

-  creds_set_scheme_unknown_ = true;

-  return S_OK;

-}

-

-HRESULT BitsRequest::HandleProxyAuthenticationError() {

-  ASSERT1(!creds_set_scheme_unknown_);

-  HRESULT hr = E_ACCESSDENIED;

-

-  if (current_auth_scheme_ == 0) {

-    current_auth_scheme_ = BG_AUTH_SCHEME_NEGOTIATE;

-    hr = SetProxyAuthImplicitCredentials(request_state_->bits_job,

-                                         BG_AUTH_SCHEME_NEGOTIATE);

-  } else if (current_auth_scheme_ == BG_AUTH_SCHEME_NEGOTIATE) {

-    current_auth_scheme_ = BG_AUTH_SCHEME_NTLM;

-    hr = SetProxyAuthImplicitCredentials(request_state_->bits_job,

-                                         BG_AUTH_SCHEME_NTLM);

-  } else {

-    hr = GetProxyCredentials();

-  }

-

-  OPT_LOG(L3, (_T("[BitsRequest::HandleProxyAuthenticationError][0x%08x][%s]"),

-               hr, BitsAuthSchemeToString(current_auth_scheme_)));

-  return SUCCEEDED(hr) ? request_state_->bits_job->Resume() : hr;

-}

-

-HRESULT BitsRequest::HandleProxyAuthenticationErrorCredsSet() {

-  ASSERT1(creds_set_scheme_unknown_);

-

-  if (current_auth_scheme_ == BG_AUTH_SCHEME_NEGOTIATE) {

-    current_auth_scheme_ = BG_AUTH_SCHEME_NTLM;

-  } else if (current_auth_scheme_ == BG_AUTH_SCHEME_NTLM) {

-    current_auth_scheme_ = BG_AUTH_SCHEME_DIGEST;

-  } else {

-    OPT_LOG(LE, (_T("[HandleProxyAuthenticationErrorCredsSet][Failure]")));

-    return E_ACCESSDENIED;

-  }

-

-  OPT_LOG(L3, (_T("[BitsRequest::HandleProxyAuthenticationErrorCredsSet][%s]"),

-               BitsAuthSchemeToString(current_auth_scheme_)));

-  return request_state_->bits_job->Resume();

-}

-

-int BitsRequest::WinHttpToBitsProxyAuthScheme(uint32 winhttp_scheme) {

-  if (winhttp_scheme == WINHTTP_AUTH_SCHEME_NEGOTIATE) {

-    return BG_AUTH_SCHEME_NEGOTIATE;

-  }

-  if (winhttp_scheme == WINHTTP_AUTH_SCHEME_NTLM) {

-    return BG_AUTH_SCHEME_NTLM;

-  }

-  if (winhttp_scheme == WINHTTP_AUTH_SCHEME_DIGEST) {

-    return BG_AUTH_SCHEME_DIGEST;

-  }

-  if (winhttp_scheme == WINHTTP_AUTH_SCHEME_BASIC) {

-    return BG_AUTH_SCHEME_BASIC;

-  }

-

-  ASSERT1(false);

-  return UNKNOWN_AUTH_SCHEME;

-}

-

-uint32 BitsRequest::BitsToWinhttpProxyAuthScheme(int bits_scheme) {

-  if (bits_scheme == BG_AUTH_SCHEME_NEGOTIATE) {

-    return WINHTTP_AUTH_SCHEME_NEGOTIATE;

-  }

-  if (bits_scheme == BG_AUTH_SCHEME_NTLM) {

-    return WINHTTP_AUTH_SCHEME_NTLM;

-  }

-  if (bits_scheme == BG_AUTH_SCHEME_DIGEST) {

-    return WINHTTP_AUTH_SCHEME_DIGEST;

-  }

-  if (bits_scheme == BG_AUTH_SCHEME_BASIC) {

-    return WINHTTP_AUTH_SCHEME_BASIC;

-  }

-

-  ASSERT1(false);

-  return UNKNOWN_AUTH_SCHEME;

-}

-

-}   // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// There is an implicit assumption that one bits job contains only one file.
+//
+// TODO(omaha): assert somewhere on all the job invariants.
+//
+// TODO(omaha): no caching at all is implemented, as far as sharing downloads
+// between different bits users downloading the same file.
+// TODO(omaha): same user downloading same file in different logon session is
+// not handled.
+// TODO(omaha): generally speaking, impersonation scenarios are not
+// yet handled by the code. This is important when creating or opening an
+// existing job.
+
+#include "omaha/net/bits_request.h"
+
+#include <winhttp.h>
+#include <atlbase.h>
+#include <atlstr.h>
+#include <functional>
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/utils.h"
+#include "omaha/net/bits_utils.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/proxy_auth.h"
+
+namespace omaha {
+
+namespace {
+
+const TCHAR* const kJobDescription = _T("Google Update");
+
+// TODO(omaha): expose polling interval, as it is likely that polling for
+// downloading files must be different than polling for retrieving smaller
+// files.
+const int kPollingIntervalMs = 1000;
+
+// Returns the job priority or -1 in case of errors.
+int GetJobPriority(IBackgroundCopyJob* job) {
+  ASSERT1(job);
+  BG_JOB_PRIORITY priority = BG_JOB_PRIORITY_FOREGROUND;
+  return SUCCEEDED(job->GetPriority(&priority)) ? priority : -1;
+}
+
+}   // namespace
+
+
+BitsRequest::BitsRequest()
+    : request_buffer_(NULL),
+      request_buffer_length_(0),
+      low_priority_(false),
+      is_canceled_(false),
+      callback_(NULL),
+      minimum_retry_delay_(-1),
+      no_progress_timeout_(-1),
+      current_auth_scheme_(0),
+      creds_set_scheme_unknown_(false) {
+  VERIFY1(SUCCEEDED(GetBitsManager(&bits_manager_)));
+}
+
+// Once this instance connects to a BITS job, it either completes the job
+// or it cleans it up to avoid leaving junk in the BITS queue.
+BitsRequest::~BitsRequest() {
+  Close();
+  callback_ = NULL;
+
+  // TODO(omaha): for unknown reasons, qmgrprxy.dll gets unloaded at some point
+  // during program execution and subsequent calls to BITS crash. This
+  // indicates a ref count problem somewhere. The work around is to not
+  // call the IUnknown::Release if the module is not in memory.
+  if (::GetModuleHandle(_T("qmgrprxy.dll")) == NULL) {
+    bits_manager_.Detach();
+  }
+}
+
+HRESULT BitsRequest::Close() {
+  NET_LOG(L3, (_T("[BitsRequest::Close]")));
+  __mutexBlock(lock_) {
+    if (request_state_.get()) {
+      VERIFY1(SUCCEEDED(CancelBitsJob(request_state_->bits_job)));
+    }
+    request_state_.reset();
+  }
+  return S_OK;
+}
+
+HRESULT BitsRequest::Cancel() {
+  NET_LOG(L3, (_T("[BitsRequest::Cancel]")));
+  __mutexBlock(lock_) {
+    is_canceled_ = true;
+    if (request_state_.get()) {
+      VERIFY1(SUCCEEDED(CancelBitsJob(request_state_->bits_job)));
+    }
+  }
+  return S_OK;
+}
+
+HRESULT BitsRequest::Send() {
+  NET_LOG(L3, (_T("[BitsRequest::Send][%s]"), url_));
+
+  ASSERT1(!url_.IsEmpty());
+
+  __mutexBlock(lock_) {
+    if (request_state_.get()) {
+      VERIFY1(SUCCEEDED(CancelBitsJob(request_state_->bits_job)));
+    }
+    request_state_.reset(new TransientRequestState);
+  }
+
+  bool is_created = false;
+  HRESULT hr = BitsRequest::CreateOrOpenJob(filename_,
+                                            &request_state_->bits_job,
+                                            &is_created);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // The job id is used for logging purposes only.
+  request_state_->bits_job->GetId(&request_state_->bits_job_id);
+
+  NET_LOG(L3, (_T("[BITS job %s]"), GuidToString(request_state_->bits_job_id)));
+
+  if (is_created) {
+    hr = SetInvariantJobProperties();
+    if (FAILED(hr)) {
+      HRESULT hr_cancel_bits_job(CancelBitsJob(request_state_->bits_job));
+      if (FAILED(hr_cancel_bits_job)) {
+        NET_LOG(LW, (_T("[CancelBitsJob failed][0x%08x]"), hr_cancel_bits_job));
+      }
+      request_state_->bits_job = NULL;
+      return hr;
+    }
+  }
+
+  return DoSend();
+}
+
+HRESULT BitsRequest::QueryHeadersString(uint32, const TCHAR*, CString*) const {
+  return E_NOTIMPL;
+}
+
+CString BitsRequest::GetResponseHeaders() const {
+  return CString();
+}
+
+
+HRESULT BitsRequest::CreateOrOpenJob(const TCHAR* display_name,
+                                     IBackgroundCopyJob** bits_job,
+                                     bool* is_created) {
+  ASSERT1(display_name);
+  ASSERT1(bits_job);
+  ASSERT1(*bits_job == NULL);
+  ASSERT1(is_created);
+
+  CComPtr<IBackgroundCopyManager> bits_manager;
+  HRESULT hr = GetBitsManager(&bits_manager);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Try to find if we already have the job in the BITS queue.
+  // By convention, the display name of the job is the same as the file name.
+  CComPtr<IBackgroundCopyJob> job;
+  hr = FindBitsJobIf(std::bind2nd(JobDisplayNameEqual(), display_name),
+                     bits_manager,
+                     &job);
+  if (SUCCEEDED(hr)) {
+    NET_LOG(L3, (_T("[found BITS job][%s]"), display_name));
+    *bits_job = job.Detach();
+    *is_created = false;
+    return S_OK;
+  }
+
+  GUID guid = {0};
+  hr = bits_manager->CreateJob(display_name, BG_JOB_TYPE_DOWNLOAD, &guid, &job);
+  if (SUCCEEDED(hr)) {
+    *bits_job = job.Detach();
+    *is_created = true;
+    return S_OK;
+  }
+
+  *bits_job = NULL;
+  return hr;
+}
+
+HRESULT BitsRequest::SetInvariantJobProperties() {
+  ASSERT1(request_state_.get());
+  ASSERT1(request_state_->bits_job);
+  HRESULT hr = request_state_->bits_job->AddFile(url_, filename_);
+  if (FAILED(hr)) {
+    NET_LOG(LE, (_T("[IBackgroundCopyJob::AddFile failed][0x%08x]"), hr));
+    return hr;
+  }
+  hr = request_state_->bits_job->SetDescription(kJobDescription);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  return S_OK;
+}
+
+HRESULT BitsRequest::SetJobProperties() {
+  ASSERT1(request_state_.get());
+  ASSERT1(request_state_->bits_job);
+  BG_JOB_PRIORITY priority = low_priority_ ? BG_JOB_PRIORITY_NORMAL :
+                                             BG_JOB_PRIORITY_FOREGROUND;
+  HRESULT hr = request_state_->bits_job->SetPriority(priority);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (minimum_retry_delay_ != -1) {
+    ASSERT1(minimum_retry_delay_ >= 0);
+    hr = request_state_->bits_job->SetMinimumRetryDelay(minimum_retry_delay_);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+  if (no_progress_timeout_ != -1) {
+    ASSERT1(no_progress_timeout_ >= 0);
+    hr = request_state_->bits_job->SetNoProgressTimeout(no_progress_timeout_);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+  return S_OK;
+}
+
+HRESULT BitsRequest::DetectManualProxy() {
+  if (NetworkConfig::GetAccessType(network_config_) !=
+      WINHTTP_ACCESS_TYPE_AUTO_DETECT) {
+    return S_OK;
+  }
+
+  HttpClient::ProxyInfo proxy_info = {0};
+  HRESULT hr = NetworkConfig::Instance().GetProxyForUrl(
+      url_,
+      network_config_.auto_config_url,
+      &proxy_info);
+  if (SUCCEEDED(hr) &&
+      proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
+    network_config_.auto_detect = false;
+    network_config_.auto_config_url.Empty();
+    network_config_.proxy = proxy_info.proxy;
+    network_config_.proxy_bypass = proxy_info.proxy_bypass;
+  }
+
+  ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy));
+  ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy_bypass));
+
+  NET_LOG(L3, (_T("[GetProxyForUrl returned][0x%08x]"), hr));
+  return hr;
+}
+
+HRESULT BitsRequest::SetJobProxyUsage() {
+  ASSERT1(request_state_.get());
+  ASSERT1(request_state_->bits_job);
+  BG_JOB_PROXY_USAGE proxy_usage = BG_JOB_PROXY_USAGE_NO_PROXY;
+  const TCHAR* proxy = NULL;
+  const TCHAR* proxy_bypass = NULL;
+
+  DetectManualProxy();
+
+  int access_type = NetworkConfig::GetAccessType(network_config_);
+  if (access_type == WINHTTP_ACCESS_TYPE_AUTO_DETECT) {
+    proxy_usage = BG_JOB_PROXY_USAGE_AUTODETECT;
+  } else if (access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
+    proxy_usage = BG_JOB_PROXY_USAGE_OVERRIDE;
+    proxy = network_config_.proxy;
+    proxy_bypass = network_config_.proxy_bypass;
+  }
+  HRESULT hr = request_state_->bits_job->SetProxySettings(proxy_usage,
+                                                          proxy,
+                                                          proxy_bypass);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (proxy_usage == BG_JOB_PROXY_USAGE_AUTODETECT ||
+      proxy_usage == BG_JOB_PROXY_USAGE_OVERRIDE) {
+    // Set implicit credentials if we are going through a proxy, just in case
+    // the proxy is requiring authentication. Continue on errors, maybe
+    // the credentials won't be needed anyway. There will be one more chance
+    // to set credentials when the proxy challenges and the job errors out.
+    creds_set_scheme_unknown_ = false;
+    hr = SetProxyAuthImplicitCredentials(request_state_->bits_job,
+                                         BG_AUTH_SCHEME_NEGOTIATE);
+    if (SUCCEEDED(hr)) {
+      current_auth_scheme_ = BG_AUTH_SCHEME_NEGOTIATE;
+    } else {
+      OPT_LOG(LW, (_T("[failed to set BITS proxy credentials][0x%08x]"), hr));
+    }
+  }
+  return S_OK;
+}
+
+HRESULT BitsRequest::DoSend() {
+  ASSERT1(request_state_.get());
+  ASSERT1(request_state_->bits_job);
+
+  NET_LOG(L3, (_T("[BitsRequest::DoSend]")));
+
+  if (is_canceled_) {
+    return OMAHA_NET_E_REQUEST_CANCELLED;
+  }
+
+  HRESULT hr = SetJobProperties();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  hr = SetJobProxyUsage();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  hr = request_state_->bits_job->Resume();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  NET_LOG(L3, (_T("[job priority %d]"),
+               GetJobPriority(request_state_->bits_job)));
+
+  // Poll for state changes. The code executing on the state changes must be
+  // idempotent, as the same state can be seen multiple times when looping.
+  // There is only one important case, which is retrying the job when the
+  // job is in the ERROR state. We attempt to handle the error, for
+  // example retrying one more time or changing proxy credentials, and then
+  // we resume the job. There is an assumption, so far true, that calling
+  // Resume on a job, the state changes right away from SUSPENDED to QUEUED.
+
+  for (;;) {
+    if (is_canceled_) {
+      return OMAHA_NET_E_REQUEST_CANCELLED;
+    }
+
+    BG_JOB_STATE job_state = BG_JOB_STATE_ERROR;
+    hr = request_state_->bits_job->GetState(&job_state);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    NET_LOG(L3, (_T("[job %s][state %s]"),
+                 GuidToString(request_state_->bits_job_id),
+                 JobStateToString(job_state)));
+
+    switch (job_state) {
+      case BG_JOB_STATE_QUEUED:
+        break;
+
+      case BG_JOB_STATE_CONNECTING:
+        if (callback_) {
+          callback_->OnProgress(0,
+                                0,
+                                WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER,
+                                NULL);
+        }
+        break;
+
+      case BG_JOB_STATE_TRANSFERRING:
+        OnStateTransferring();
+        break;
+
+      case BG_JOB_STATE_TRANSIENT_ERROR:
+        break;
+
+      case BG_JOB_STATE_ERROR:
+        hr = OnStateError();
+        if (SUCCEEDED(hr)) {
+          // The error handler dealt with the error. Countinue the loop.
+          break;
+        }
+
+        // Give up.
+        return request_state_->http_status_code ? S_OK : hr;
+
+      case BG_JOB_STATE_TRANSFERRED:
+        hr = request_state_->bits_job->Complete();
+        if (SUCCEEDED(hr) || BG_S_UNABLE_TO_DELETE_FILES == hr) {
+          // Assume the status code is 200 if the transfer completed. BITS does
+          // ot provide access to the status code.
+          request_state_->http_status_code = HTTP_STATUS_OK;
+
+          if (creds_set_scheme_unknown_) {
+            // Bits job completed successfully. If we have a valid username, we
+            // record the auth scheme with the NetworkConfig, so it can be used
+            // in the future within this process.
+            ASSERT1(BitsToWinhttpProxyAuthScheme(current_auth_scheme_) !=
+                    UNKNOWN_AUTH_SCHEME);
+            bool is_https = String_StartsWith(url_, kHttpsProtoScheme, true);
+            VERIFY1(SUCCEEDED(NetworkConfig::Instance().SetProxyAuthScheme(
+                network_config_.proxy, is_https,
+                BitsToWinhttpProxyAuthScheme(current_auth_scheme_))));
+          }
+
+          return S_OK;
+        } else {
+          return hr;
+        }
+
+      case BG_JOB_STATE_SUSPENDED:
+        // Pausing downloads is not supported yet.
+        ASSERT1(false);
+        return E_FAIL;
+
+      case BG_JOB_STATE_ACKNOWLEDGED:
+        ASSERT1(false);
+        return S_OK;
+
+      case BG_JOB_STATE_CANCELLED:
+        return OMAHA_NET_E_REQUEST_CANCELLED;
+    };
+
+    ::Sleep(kPollingIntervalMs);
+  }
+}
+
+HRESULT BitsRequest::OnStateTransferring() {
+  if (!callback_) {
+    return S_OK;
+  }
+  BG_JOB_PROGRESS progress = {0};
+  HRESULT hr = request_state_->bits_job->GetProgress(&progress);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ASSERT1(progress.FilesTotal == 1);
+  ASSERT1(progress.BytesTransferred <= INT_MAX);
+  ASSERT1(progress.BytesTotal <= INT_MAX);
+  callback_->OnProgress(static_cast<int>(progress.BytesTransferred),
+                        static_cast<int>(progress.BytesTotal),
+                        WINHTTP_CALLBACK_STATUS_READ_COMPLETE,
+                        NULL);
+  return S_OK;
+}
+
+HRESULT BitsRequest::OnStateError() {
+  CComPtr<IBackgroundCopyError> error;
+  HRESULT hr = request_state_->bits_job->GetError(&error);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  BG_ERROR_CONTEXT error_context = BG_ERROR_CONTEXT_NONE;
+  HRESULT error_code = E_FAIL;
+  hr = error->GetError(&error_context, &error_code);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(FAILED(error_code));
+
+  NET_LOG(L3, (_T("[handle bits error][0x%08x]"), error_code));
+
+  request_state_->http_status_code = GetHttpStatusFromBitsError(error_code);
+
+  if (error_code == BG_E_HTTP_ERROR_407) {
+    hr = !creds_set_scheme_unknown_ ? HandleProxyAuthenticationError() :
+                                      HandleProxyAuthenticationErrorCredsSet();
+    if (SUCCEEDED(hr)) {
+      return S_OK;
+    }
+  }
+
+  // We could not handle this error. The control will return to the caller.
+  return error_code;
+}
+
+HRESULT BitsRequest::GetProxyCredentials() {
+  CString username;
+  CString password;
+  uint32 auth_scheme = UNKNOWN_AUTH_SCHEME;
+  bool is_https = String_StartsWith(url_, kHttpsProtoScheme, true);
+
+  if (!NetworkConfig::Instance().GetProxyCredentials(true, false,
+          network_config_.proxy, is_https, &username, &password,
+          &auth_scheme)) {
+    OPT_LOG(LE, (_T("[BitsRequest::GetProxyCredentials failed]")));
+    return E_ACCESSDENIED;
+  }
+
+  if (auth_scheme != UNKNOWN_AUTH_SCHEME) {
+    current_auth_scheme_ = WinHttpToBitsProxyAuthScheme(auth_scheme);
+    OPT_LOG(L3, (_T("[BitsRequest::GetProxyCredentials][%s]"),
+                 BitsAuthSchemeToString(current_auth_scheme_)));
+    return SetProxyAuthCredentials(request_state_->bits_job,
+               CStrBuf(username), CStrBuf(password),
+               static_cast<BG_AUTH_SCHEME>(current_auth_scheme_));
+  }
+
+  OPT_LOG(L3, (_T("[BitsRequest::GetProxyCredentials][Auth scheme unknown]")));
+  // We do not know the scheme beforehand. So we set credentials on all the
+  // schemes except BASIC and try them out in seqence. We could have used BASIC
+  // as well, however, we do not want to leak passwords by mistake.
+  for (int scheme = BG_AUTH_SCHEME_DIGEST; scheme <= BG_AUTH_SCHEME_NEGOTIATE;
+       ++scheme) {
+    HRESULT hr = SetProxyAuthCredentials(request_state_->bits_job,
+                                         CStrBuf(username), CStrBuf(password),
+                                         static_cast<BG_AUTH_SCHEME>(scheme));
+    if (FAILED(hr)) {
+      OPT_LOG(LE, (_T("[BitsRequest::GetProxyCredentials][0x%08x][%s]"),
+                   hr, BitsAuthSchemeToString(scheme)));
+      return hr;
+    }
+  }
+
+  current_auth_scheme_ = BG_AUTH_SCHEME_NEGOTIATE;
+  creds_set_scheme_unknown_ = true;
+  return S_OK;
+}
+
+HRESULT BitsRequest::HandleProxyAuthenticationError() {
+  ASSERT1(!creds_set_scheme_unknown_);
+  HRESULT hr = E_ACCESSDENIED;
+
+  if (current_auth_scheme_ == 0) {
+    current_auth_scheme_ = BG_AUTH_SCHEME_NEGOTIATE;
+    hr = SetProxyAuthImplicitCredentials(request_state_->bits_job,
+                                         BG_AUTH_SCHEME_NEGOTIATE);
+  } else if (current_auth_scheme_ == BG_AUTH_SCHEME_NEGOTIATE) {
+    current_auth_scheme_ = BG_AUTH_SCHEME_NTLM;
+    hr = SetProxyAuthImplicitCredentials(request_state_->bits_job,
+                                         BG_AUTH_SCHEME_NTLM);
+  } else {
+    hr = GetProxyCredentials();
+  }
+
+  OPT_LOG(L3, (_T("[BitsRequest::HandleProxyAuthenticationError][0x%08x][%s]"),
+               hr, BitsAuthSchemeToString(current_auth_scheme_)));
+  return SUCCEEDED(hr) ? request_state_->bits_job->Resume() : hr;
+}
+
+HRESULT BitsRequest::HandleProxyAuthenticationErrorCredsSet() {
+  ASSERT1(creds_set_scheme_unknown_);
+
+  if (current_auth_scheme_ == BG_AUTH_SCHEME_NEGOTIATE) {
+    current_auth_scheme_ = BG_AUTH_SCHEME_NTLM;
+  } else if (current_auth_scheme_ == BG_AUTH_SCHEME_NTLM) {
+    current_auth_scheme_ = BG_AUTH_SCHEME_DIGEST;
+  } else {
+    OPT_LOG(LE, (_T("[HandleProxyAuthenticationErrorCredsSet][Failure]")));
+    return E_ACCESSDENIED;
+  }
+
+  OPT_LOG(L3, (_T("[BitsRequest::HandleProxyAuthenticationErrorCredsSet][%s]"),
+               BitsAuthSchemeToString(current_auth_scheme_)));
+  return request_state_->bits_job->Resume();
+}
+
+int BitsRequest::WinHttpToBitsProxyAuthScheme(uint32 winhttp_scheme) {
+  if (winhttp_scheme == WINHTTP_AUTH_SCHEME_NEGOTIATE) {
+    return BG_AUTH_SCHEME_NEGOTIATE;
+  }
+  if (winhttp_scheme == WINHTTP_AUTH_SCHEME_NTLM) {
+    return BG_AUTH_SCHEME_NTLM;
+  }
+  if (winhttp_scheme == WINHTTP_AUTH_SCHEME_DIGEST) {
+    return BG_AUTH_SCHEME_DIGEST;
+  }
+  if (winhttp_scheme == WINHTTP_AUTH_SCHEME_BASIC) {
+    return BG_AUTH_SCHEME_BASIC;
+  }
+
+  ASSERT1(false);
+  return UNKNOWN_AUTH_SCHEME;
+}
+
+uint32 BitsRequest::BitsToWinhttpProxyAuthScheme(int bits_scheme) {
+  if (bits_scheme == BG_AUTH_SCHEME_NEGOTIATE) {
+    return WINHTTP_AUTH_SCHEME_NEGOTIATE;
+  }
+  if (bits_scheme == BG_AUTH_SCHEME_NTLM) {
+    return WINHTTP_AUTH_SCHEME_NTLM;
+  }
+  if (bits_scheme == BG_AUTH_SCHEME_DIGEST) {
+    return WINHTTP_AUTH_SCHEME_DIGEST;
+  }
+  if (bits_scheme == BG_AUTH_SCHEME_BASIC) {
+    return WINHTTP_AUTH_SCHEME_BASIC;
+  }
+
+  ASSERT1(false);
+  return UNKNOWN_AUTH_SCHEME;
+}
+
+}   // namespace omaha
+
diff --git a/net/bits_request.h b/net/bits_request.h
index 92fc93a..6c5ec5b 100644
--- a/net/bits_request.h
+++ b/net/bits_request.h
@@ -1,216 +1,216 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// BitsRequest provides http transactions using BITS, with an optional

-// number of retries using a specified network configuration.

-//

-// BITS is sending the following string as user agent:

-//    User-Agent: Microsoft BITS/6.6

-// where the version seems to be the version of %windir%\System32\QMgr.dll.

-// The user agent of BITS can't be controlled programmatically.

-//

-// TODO(omaha): the class interface is not stable yet, as a few more

-// getters and setters are still needed.

-

-#ifndef OMAHA_NET_BITS_REQUEST_H__

-#define OMAHA_NET_BITS_REQUEST_H__

-

-#include <windows.h>

-#include <bits.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/utils.h"

-#include "omaha/net/http_request.h"

-

-namespace omaha {

-

-class BitsRequest : public HttpRequestInterface {

- public:

-  BitsRequest();

-  virtual ~BitsRequest();

-

-  virtual HRESULT Close();

-

-  virtual HRESULT Send();

-

-  virtual HRESULT Cancel();

-

-  virtual std::vector<uint8> GetResponse() const {

-    return std::vector<uint8>();

-  }

-

-  // TODO(omaha): BITS provides access to headers on Windows Vista.

-  virtual HRESULT QueryHeadersString(uint32 info_level,

-                                     const TCHAR* name,

-                                     CString* value) const;

-  virtual CString GetResponseHeaders() const;

-

-  // Returns the http status code in case of errors or 200 when the file is

-  // successfully transferred. BITS does not provide access to the status code

-  // directly; in some conditions the status code can be deduced from the error.

-  virtual int GetHttpStatusCode() const {

-    return request_state_.get() ? request_state_->http_status_code : 0;

-  }

-

-  virtual CString ToString() const { return _T("BITS"); }

-

-  virtual void set_session_handle(HINTERNET session_handle) {

-    session_handle_ = session_handle;

-  }

-

-  virtual void set_url(const CString& url) { url_ = url; }

-

-  virtual void set_request_buffer(const void* buffer, size_t buffer_length) {

-    request_buffer_ = buffer;

-    request_buffer_length_ = buffer_length;

-  }

-

-  virtual void set_network_configuration(const Config& network_config) {

-    network_config_ = network_config;

-  }

-

-  // Sets the filename to receive the response instead of the memory buffer.

-  virtual void set_filename(const CString& filename) { filename_ = filename; }

-

-  virtual void set_low_priority(bool low_priority) {

-    low_priority_ = low_priority;

-  }

-

-  virtual void set_callback(NetworkRequestCallback* callback) {

-    callback_ = callback;

-  }

-

-  virtual void set_additional_headers(const CString& additional_headers) {

-    additional_headers_ = additional_headers;

-  }

-

-  virtual CString user_agent() const { return user_agent_; }

-

-  virtual void set_user_agent(const CString& user_agent) {

-    user_agent_ = user_agent;

-  }

-

-  // Sets the minimum length of time that BITS waits after encountering a

-  // transient error condition before trying to transfer the file.

-  // The default value is 600 seconds.

-  void set_minimum_retry_delay(int minimum_retry_delay) {

-    minimum_retry_delay_ = minimum_retry_delay;

-  }

-

-  // Sets the length of time that BITS tries to transfer the file after a

-  // transient error condition occurs. If BITS does not make progress during

-  // the retry period, it moves the state of the job from transient error

-  // to the error state. The default value is 14 days.

-  void set_no_progress_timeout(int no_progress_timeout) {

-    no_progress_timeout_ = no_progress_timeout;

-  }

-

- private:

-  // Sets invariant job properties, such as the filename and the description.

-  // These parameters can't change over the job life time.

-  HRESULT SetInvariantJobProperties();

-

-  // Sets non-invariant job properties.

-  HRESULT SetJobProperties();

-

-  // Uses the SimpleRequest HttpClient to detect the proxy for the current

-  // request.

-  HRESULT DetectManualProxy();

-

-  // Specifies how a job connects to the Internet.

-  HRESULT SetJobProxyUsage();

-

-  // Runs a polling loop waiting for the job to transition in one of its

-  // final states.

-  HRESULT DoSend();

-

-  // Handles the BG_JOB_STATE_ERROR. It returns S_OK when the error has

-  // been handled, otherwise, it returns the job error code and it makes the

-  // control return to the caller of Send.

-  HRESULT OnStateError();

-

-  // Handles the BG_JOB_STATE_TRANSFERRING.

-  HRESULT OnStateTransferring();

-

-  // Gets username and password through NetworkConfig. If successful, sets the

-  // credentials on the BITS job.

-  HRESULT GetProxyCredentials();

-

-  // Handles 407 errors. Tries autologon schemes.

-  HRESULT HandleProxyAuthenticationError();

-

-  // Handles 407 errors by cycling through the auth schemes, when credentials

-  // are already set on the BITS job.

-  HRESULT HandleProxyAuthenticationErrorCredsSet();

-

-  int WinHttpToBitsProxyAuthScheme(uint32 winhttp_scheme);

-  uint32 BitsToWinhttpProxyAuthScheme(int bits_scheme);

-

-  // Creates or opens an existing job.

-  // 'is_created' is true if the job has been created or false if the job

-  // has been opened.

-  static HRESULT CreateOrOpenJob(const TCHAR* display_name,

-                                 IBackgroundCopyJob** bits_job,

-                                 bool* is_created);

-

-  // Returns major.minor.0.0 BITS version.

-  static ULONGLONG GetBitsVersion();

-

-  // Holds the transient state corresponding to a BITS request.

-  struct TransientRequestState {

-    TransientRequestState() : http_status_code(0) {

-      SetZero(bits_job_id);

-    }

-

-    int http_status_code;

-    CComPtr<IBackgroundCopyJob> bits_job;

-    GUID bits_job_id;

-  };

-

-  LLock lock_;

-  CString url_;

-  CString filename_;

-  const void* request_buffer_;          // Contains the request body for POST.

-  size_t      request_buffer_length_;   // Length of the request body.

-  CString additional_headers_;

-  CString user_agent_;

-  Config network_config_;

-  bool low_priority_;

-  bool is_canceled_;

-  HINTERNET session_handle_;  // Not owned by this class.

-  NetworkRequestCallback* callback_;

-  int minimum_retry_delay_;

-  int no_progress_timeout_;

-  int current_auth_scheme_;

-

-  // For manual proxy authentication, if we do not know the auth scheme that the

-  // proxy is using, we set the username/password on all the schemes and try

-  // them out in sequence.

-  bool creds_set_scheme_unknown_;

-

-  scoped_ptr<TransientRequestState> request_state_;

-

-  // See http://b/1189928

-  CComPtr<IBackgroundCopyManager> bits_manager_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(BitsRequest);

-};

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_BITS_REQUEST_H__

-

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// BitsRequest provides http transactions using BITS, with an optional
+// number of retries using a specified network configuration.
+//
+// BITS is sending the following string as user agent:
+//    User-Agent: Microsoft BITS/6.6
+// where the version seems to be the version of %windir%\System32\QMgr.dll.
+// The user agent of BITS can't be controlled programmatically.
+//
+// TODO(omaha): the class interface is not stable yet, as a few more
+// getters and setters are still needed.
+
+#ifndef OMAHA_NET_BITS_REQUEST_H__
+#define OMAHA_NET_BITS_REQUEST_H__
+
+#include <windows.h>
+#include <bits.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/utils.h"
+#include "omaha/net/http_request.h"
+
+namespace omaha {
+
+class BitsRequest : public HttpRequestInterface {
+ public:
+  BitsRequest();
+  virtual ~BitsRequest();
+
+  virtual HRESULT Close();
+
+  virtual HRESULT Send();
+
+  virtual HRESULT Cancel();
+
+  virtual std::vector<uint8> GetResponse() const {
+    return std::vector<uint8>();
+  }
+
+  // TODO(omaha): BITS provides access to headers on Windows Vista.
+  virtual HRESULT QueryHeadersString(uint32 info_level,
+                                     const TCHAR* name,
+                                     CString* value) const;
+  virtual CString GetResponseHeaders() const;
+
+  // Returns the http status code in case of errors or 200 when the file is
+  // successfully transferred. BITS does not provide access to the status code
+  // directly; in some conditions the status code can be deduced from the error.
+  virtual int GetHttpStatusCode() const {
+    return request_state_.get() ? request_state_->http_status_code : 0;
+  }
+
+  virtual CString ToString() const { return _T("BITS"); }
+
+  virtual void set_session_handle(HINTERNET session_handle) {
+    session_handle_ = session_handle;
+  }
+
+  virtual void set_url(const CString& url) { url_ = url; }
+
+  virtual void set_request_buffer(const void* buffer, size_t buffer_length) {
+    request_buffer_ = buffer;
+    request_buffer_length_ = buffer_length;
+  }
+
+  virtual void set_network_configuration(const Config& network_config) {
+    network_config_ = network_config;
+  }
+
+  // Sets the filename to receive the response instead of the memory buffer.
+  virtual void set_filename(const CString& filename) { filename_ = filename; }
+
+  virtual void set_low_priority(bool low_priority) {
+    low_priority_ = low_priority;
+  }
+
+  virtual void set_callback(NetworkRequestCallback* callback) {
+    callback_ = callback;
+  }
+
+  virtual void set_additional_headers(const CString& additional_headers) {
+    additional_headers_ = additional_headers;
+  }
+
+  virtual CString user_agent() const { return user_agent_; }
+
+  virtual void set_user_agent(const CString& user_agent) {
+    user_agent_ = user_agent;
+  }
+
+  // Sets the minimum length of time that BITS waits after encountering a
+  // transient error condition before trying to transfer the file.
+  // The default value is 600 seconds.
+  void set_minimum_retry_delay(int minimum_retry_delay) {
+    minimum_retry_delay_ = minimum_retry_delay;
+  }
+
+  // Sets the length of time that BITS tries to transfer the file after a
+  // transient error condition occurs. If BITS does not make progress during
+  // the retry period, it moves the state of the job from transient error
+  // to the error state. The default value is 14 days.
+  void set_no_progress_timeout(int no_progress_timeout) {
+    no_progress_timeout_ = no_progress_timeout;
+  }
+
+ private:
+  // Sets invariant job properties, such as the filename and the description.
+  // These parameters can't change over the job life time.
+  HRESULT SetInvariantJobProperties();
+
+  // Sets non-invariant job properties.
+  HRESULT SetJobProperties();
+
+  // Uses the SimpleRequest HttpClient to detect the proxy for the current
+  // request.
+  HRESULT DetectManualProxy();
+
+  // Specifies how a job connects to the Internet.
+  HRESULT SetJobProxyUsage();
+
+  // Runs a polling loop waiting for the job to transition in one of its
+  // final states.
+  HRESULT DoSend();
+
+  // Handles the BG_JOB_STATE_ERROR. It returns S_OK when the error has
+  // been handled, otherwise, it returns the job error code and it makes the
+  // control return to the caller of Send.
+  HRESULT OnStateError();
+
+  // Handles the BG_JOB_STATE_TRANSFERRING.
+  HRESULT OnStateTransferring();
+
+  // Gets username and password through NetworkConfig. If successful, sets the
+  // credentials on the BITS job.
+  HRESULT GetProxyCredentials();
+
+  // Handles 407 errors. Tries autologon schemes.
+  HRESULT HandleProxyAuthenticationError();
+
+  // Handles 407 errors by cycling through the auth schemes, when credentials
+  // are already set on the BITS job.
+  HRESULT HandleProxyAuthenticationErrorCredsSet();
+
+  int WinHttpToBitsProxyAuthScheme(uint32 winhttp_scheme);
+  uint32 BitsToWinhttpProxyAuthScheme(int bits_scheme);
+
+  // Creates or opens an existing job.
+  // 'is_created' is true if the job has been created or false if the job
+  // has been opened.
+  static HRESULT CreateOrOpenJob(const TCHAR* display_name,
+                                 IBackgroundCopyJob** bits_job,
+                                 bool* is_created);
+
+  // Returns major.minor.0.0 BITS version.
+  static ULONGLONG GetBitsVersion();
+
+  // Holds the transient state corresponding to a BITS request.
+  struct TransientRequestState {
+    TransientRequestState() : http_status_code(0) {
+      SetZero(bits_job_id);
+    }
+
+    int http_status_code;
+    CComPtr<IBackgroundCopyJob> bits_job;
+    GUID bits_job_id;
+  };
+
+  LLock lock_;
+  CString url_;
+  CString filename_;
+  const void* request_buffer_;          // Contains the request body for POST.
+  size_t      request_buffer_length_;   // Length of the request body.
+  CString additional_headers_;
+  CString user_agent_;
+  Config network_config_;
+  bool low_priority_;
+  bool is_canceled_;
+  HINTERNET session_handle_;  // Not owned by this class.
+  NetworkRequestCallback* callback_;
+  int minimum_retry_delay_;
+  int no_progress_timeout_;
+  int current_auth_scheme_;
+
+  // For manual proxy authentication, if we do not know the auth scheme that the
+  // proxy is using, we set the username/password on all the schemes and try
+  // them out in sequence.
+  bool creds_set_scheme_unknown_;
+
+  scoped_ptr<TransientRequestState> request_state_;
+
+  // See http://b/1189928
+  CComPtr<IBackgroundCopyManager> bits_manager_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(BitsRequest);
+};
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_BITS_REQUEST_H__
+
+
diff --git a/net/bits_request_unittest.cc b/net/bits_request_unittest.cc
index 6229c62..cb8f426 100644
--- a/net/bits_request_unittest.cc
+++ b/net/bits_request_unittest.cc
@@ -1,43 +1,43 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <winhttp.h>

-#include "omaha/common/app_util.h"

-#include "omaha/net/bits_request.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Moves the job to error state if no progress at all is made for 10 seconds.

-TEST(BitsRequestTest, Send) {

-  BitsRequest bits_request;

-  bits_request.set_no_progress_timeout(10);   // 10 seconds.

-  CString temp_dir = app_util::GetTempDir();

-  CString temp_file;

-  EXPECT_TRUE(::GetTempFileName(temp_dir, _T("tmp"), 0,

-                                CStrBuf(temp_file, MAX_PATH)));

-  bits_request.set_filename(temp_file);

-  bits_request.set_url(_T("http://dl.google.com/update2/UpdateData.bin"));

-  EXPECT_HRESULT_SUCCEEDED(bits_request.Send());

-  EXPECT_EQ(HTTP_STATUS_OK, bits_request.GetHttpStatusCode());

-

-  bits_request.set_low_priority(true);

-  EXPECT_HRESULT_SUCCEEDED(bits_request.Send());

-  EXPECT_EQ(HTTP_STATUS_OK, bits_request.GetHttpStatusCode());

-}

-

-}   // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <winhttp.h>
+#include "omaha/common/app_util.h"
+#include "omaha/net/bits_request.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Moves the job to error state if no progress at all is made for 10 seconds.
+TEST(BitsRequestTest, Send) {
+  BitsRequest bits_request;
+  bits_request.set_no_progress_timeout(10);   // 10 seconds.
+  CString temp_dir = app_util::GetTempDir();
+  CString temp_file;
+  EXPECT_TRUE(::GetTempFileName(temp_dir, _T("tmp"), 0,
+                                CStrBuf(temp_file, MAX_PATH)));
+  bits_request.set_filename(temp_file);
+  bits_request.set_url(_T("http://dl.google.com/update2/UpdateData.bin"));
+  EXPECT_HRESULT_SUCCEEDED(bits_request.Send());
+  EXPECT_EQ(HTTP_STATUS_OK, bits_request.GetHttpStatusCode());
+
+  bits_request.set_low_priority(true);
+  EXPECT_HRESULT_SUCCEEDED(bits_request.Send());
+  EXPECT_EQ(HTTP_STATUS_OK, bits_request.GetHttpStatusCode());
+}
+
+}   // namespace omaha
+
diff --git a/net/bits_utils.cc b/net/bits_utils.cc
index a77ff34..f8beb5c 100644
--- a/net/bits_utils.cc
+++ b/net/bits_utils.cc
@@ -1,164 +1,164 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/net/bits_utils.h"

-

-#include <windows.h>

-#include <winhttp.h>

-#include <cstring>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/scoped_ptr_cotask.h"

-

-namespace omaha {

-

-// Gets the instance of BITS manager.

-HRESULT GetBitsManager(IBackgroundCopyManager** bits_manager) {

-  ASSERT1(bits_manager);

-  if (*bits_manager) {

-    (*bits_manager)->Release();

-  }

-  *bits_manager = NULL;

-

-  CComPtr<IBackgroundCopyManager> object;

-  HRESULT hr = object.CoCreateInstance(__uuidof(BackgroundCopyManager));

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[failed to get BITS interface][0x%08x]"), hr));

-    const HRESULT kServiceDisabled(HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED));

-    return (hr == kServiceDisabled) ? CI_E_BITS_DISABLED : hr;

-  }

-  *bits_manager = object.Detach();

-  return S_OK;

-}

-

-bool JobLocalNameEqual::operator()(IBackgroundCopyJob* job,

-                                   const TCHAR* name) const {

-  ASSERT1(job);

-  ASSERT1(name);

-  CComPtr<IEnumBackgroundCopyFiles> files;

-  if (FAILED(job->EnumFiles(&files))) {

-    return false;

-  }

-  ULONG file_count = 0;

-  if (FAILED(files->GetCount(&file_count))) {

-    return false;

-  }

-  for (size_t i = 0; i != file_count; ++i) {

-    CComPtr<IBackgroundCopyFile> file;

-    if (files->Next(1, &file, NULL) == S_OK) {

-      scoped_ptr_cotask<TCHAR> local_name;

-      if (SUCCEEDED(file->GetLocalName(address(local_name)))) {

-        if (_tcscmp(local_name.get(), name) == 0) {

-          return true;

-        }

-      }

-    }

-  }

-  return false;

-}

-

-bool JobDisplayNameEqual::operator()(IBackgroundCopyJob* job,

-                                     const TCHAR* name) const {

-  ASSERT1(job);

-  ASSERT1(name);

-  scoped_ptr_cotask<TCHAR> display_name;

-  HRESULT hr = job->GetDisplayName(address(display_name));

-  if (SUCCEEDED(hr)) {

-    return _tcscmp(display_name.get(), name) == 0;

-  }

-  return false;

-}

-

-HRESULT SetProxyAuthImplicitCredentials(IBackgroundCopyJob* job,

-                                        BG_AUTH_SCHEME auth_scheme) {

-  return SetProxyAuthCredentials(job, NULL, NULL, auth_scheme);

-}

-

-HRESULT SetProxyAuthCredentials(IBackgroundCopyJob* job,

-                                TCHAR* username,

-                                TCHAR* password,

-                                BG_AUTH_SCHEME auth_scheme) {

-  ASSERT1(job);

-  CComQIPtr<IBackgroundCopyJob2> job2(job);

-  if (!job2) {

-    return E_NOINTERFACE;

-  }

-  BG_AUTH_CREDENTIALS auth_cred;

-  SetZero(auth_cred);

-  auth_cred.Target = BG_AUTH_TARGET_PROXY;

-  auth_cred.Scheme = auth_scheme;

-  auth_cred.Credentials.Basic.UserName = username;

-  auth_cred.Credentials.Basic.Password = password;

-  return job2->SetCredentials(&auth_cred);

-}

-

-int GetHttpStatusFromBitsError(HRESULT error) {

-  // Bits errors are defined in bitsmsg.h. Although not documented, it is

-  // clear that all errors corresponding to http status code have the high

-  // word equal to 0x8019.

-  bool is_valid = HIWORD(error) == 0x8019 &&

-                  LOWORD(error) >= HTTP_STATUS_FIRST &&

-                  LOWORD(error) <= HTTP_STATUS_LAST;

-  return is_valid ? LOWORD(error) : 0;

-}

-

-HRESULT CancelBitsJob(IBackgroundCopyJob* job) {

-  if (job) {

-    BG_JOB_STATE job_state = BG_JOB_STATE_ERROR;

-    HRESULT hr = job->GetState(&job_state);

-    if (SUCCEEDED(hr) &&

-        job_state != BG_JOB_STATE_CANCELLED &&

-        job_state != BG_JOB_STATE_ACKNOWLEDGED) {

-      HRESULT hr = job->Cancel();

-      if (FAILED(hr)) {

-        NET_LOG(LW, (_T("[CancelBitsJob failed][0x%08x]"), hr));

-      }

-      return hr;

-    }

-  }

-  return S_OK;

-}

-

-#define RETURN_TSTR(x) case (x): return _T(#x)

-CString JobStateToString(BG_JOB_STATE job_state) {

-  switch (job_state) {

-    RETURN_TSTR(BG_JOB_STATE_QUEUED);

-    RETURN_TSTR(BG_JOB_STATE_CONNECTING);

-    RETURN_TSTR(BG_JOB_STATE_TRANSFERRING);

-    RETURN_TSTR(BG_JOB_STATE_TRANSIENT_ERROR);

-    RETURN_TSTR(BG_JOB_STATE_ERROR);

-    RETURN_TSTR(BG_JOB_STATE_TRANSFERRED);

-    RETURN_TSTR(BG_JOB_STATE_SUSPENDED);

-    RETURN_TSTR(BG_JOB_STATE_ACKNOWLEDGED);

-    RETURN_TSTR(BG_JOB_STATE_CANCELLED);

-  }

-  return _T("");

-}

-

-CString BitsAuthSchemeToString(int auth_scheme) {

-  switch (auth_scheme) {

-    RETURN_TSTR(BG_AUTH_SCHEME_NEGOTIATE);

-    RETURN_TSTR(BG_AUTH_SCHEME_NTLM);

-    RETURN_TSTR(BG_AUTH_SCHEME_DIGEST);

-    RETURN_TSTR(BG_AUTH_SCHEME_BASIC);

-    RETURN_TSTR(0);

-  }

-  return _T("");

-}

-

-}   // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/net/bits_utils.h"
+
+#include <windows.h>
+#include <winhttp.h>
+#include <cstring>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/scoped_ptr_cotask.h"
+
+namespace omaha {
+
+// Gets the instance of BITS manager.
+HRESULT GetBitsManager(IBackgroundCopyManager** bits_manager) {
+  ASSERT1(bits_manager);
+  if (*bits_manager) {
+    (*bits_manager)->Release();
+  }
+  *bits_manager = NULL;
+
+  CComPtr<IBackgroundCopyManager> object;
+  HRESULT hr = object.CoCreateInstance(__uuidof(BackgroundCopyManager));
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[failed to get BITS interface][0x%08x]"), hr));
+    const HRESULT kServiceDisabled(HRESULT_FROM_WIN32(ERROR_SERVICE_DISABLED));
+    return (hr == kServiceDisabled) ? CI_E_BITS_DISABLED : hr;
+  }
+  *bits_manager = object.Detach();
+  return S_OK;
+}
+
+bool JobLocalNameEqual::operator()(IBackgroundCopyJob* job,
+                                   const TCHAR* name) const {
+  ASSERT1(job);
+  ASSERT1(name);
+  CComPtr<IEnumBackgroundCopyFiles> files;
+  if (FAILED(job->EnumFiles(&files))) {
+    return false;
+  }
+  ULONG file_count = 0;
+  if (FAILED(files->GetCount(&file_count))) {
+    return false;
+  }
+  for (size_t i = 0; i != file_count; ++i) {
+    CComPtr<IBackgroundCopyFile> file;
+    if (files->Next(1, &file, NULL) == S_OK) {
+      scoped_ptr_cotask<TCHAR> local_name;
+      if (SUCCEEDED(file->GetLocalName(address(local_name)))) {
+        if (_tcscmp(local_name.get(), name) == 0) {
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+bool JobDisplayNameEqual::operator()(IBackgroundCopyJob* job,
+                                     const TCHAR* name) const {
+  ASSERT1(job);
+  ASSERT1(name);
+  scoped_ptr_cotask<TCHAR> display_name;
+  HRESULT hr = job->GetDisplayName(address(display_name));
+  if (SUCCEEDED(hr)) {
+    return _tcscmp(display_name.get(), name) == 0;
+  }
+  return false;
+}
+
+HRESULT SetProxyAuthImplicitCredentials(IBackgroundCopyJob* job,
+                                        BG_AUTH_SCHEME auth_scheme) {
+  return SetProxyAuthCredentials(job, NULL, NULL, auth_scheme);
+}
+
+HRESULT SetProxyAuthCredentials(IBackgroundCopyJob* job,
+                                TCHAR* username,
+                                TCHAR* password,
+                                BG_AUTH_SCHEME auth_scheme) {
+  ASSERT1(job);
+  CComQIPtr<IBackgroundCopyJob2> job2(job);
+  if (!job2) {
+    return E_NOINTERFACE;
+  }
+  BG_AUTH_CREDENTIALS auth_cred;
+  SetZero(auth_cred);
+  auth_cred.Target = BG_AUTH_TARGET_PROXY;
+  auth_cred.Scheme = auth_scheme;
+  auth_cred.Credentials.Basic.UserName = username;
+  auth_cred.Credentials.Basic.Password = password;
+  return job2->SetCredentials(&auth_cred);
+}
+
+int GetHttpStatusFromBitsError(HRESULT error) {
+  // Bits errors are defined in bitsmsg.h. Although not documented, it is
+  // clear that all errors corresponding to http status code have the high
+  // word equal to 0x8019.
+  bool is_valid = HIWORD(error) == 0x8019 &&
+                  LOWORD(error) >= HTTP_STATUS_FIRST &&
+                  LOWORD(error) <= HTTP_STATUS_LAST;
+  return is_valid ? LOWORD(error) : 0;
+}
+
+HRESULT CancelBitsJob(IBackgroundCopyJob* job) {
+  if (job) {
+    BG_JOB_STATE job_state = BG_JOB_STATE_ERROR;
+    HRESULT hr = job->GetState(&job_state);
+    if (SUCCEEDED(hr) &&
+        job_state != BG_JOB_STATE_CANCELLED &&
+        job_state != BG_JOB_STATE_ACKNOWLEDGED) {
+      HRESULT hr = job->Cancel();
+      if (FAILED(hr)) {
+        NET_LOG(LW, (_T("[CancelBitsJob failed][0x%08x]"), hr));
+      }
+      return hr;
+    }
+  }
+  return S_OK;
+}
+
+#define RETURN_TSTR(x) case (x): return _T(#x)
+CString JobStateToString(BG_JOB_STATE job_state) {
+  switch (job_state) {
+    RETURN_TSTR(BG_JOB_STATE_QUEUED);
+    RETURN_TSTR(BG_JOB_STATE_CONNECTING);
+    RETURN_TSTR(BG_JOB_STATE_TRANSFERRING);
+    RETURN_TSTR(BG_JOB_STATE_TRANSIENT_ERROR);
+    RETURN_TSTR(BG_JOB_STATE_ERROR);
+    RETURN_TSTR(BG_JOB_STATE_TRANSFERRED);
+    RETURN_TSTR(BG_JOB_STATE_SUSPENDED);
+    RETURN_TSTR(BG_JOB_STATE_ACKNOWLEDGED);
+    RETURN_TSTR(BG_JOB_STATE_CANCELLED);
+  }
+  return _T("");
+}
+
+CString BitsAuthSchemeToString(int auth_scheme) {
+  switch (auth_scheme) {
+    RETURN_TSTR(BG_AUTH_SCHEME_NEGOTIATE);
+    RETURN_TSTR(BG_AUTH_SCHEME_NTLM);
+    RETURN_TSTR(BG_AUTH_SCHEME_DIGEST);
+    RETURN_TSTR(BG_AUTH_SCHEME_BASIC);
+    RETURN_TSTR(0);
+  }
+  return _T("");
+}
+
+}   // namespace omaha
+
diff --git a/net/bits_utils.h b/net/bits_utils.h
index 7d40547..bc79e25 100644
--- a/net/bits_utils.h
+++ b/net/bits_utils.h
@@ -1,105 +1,105 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_NET_BITS_UTILS_H__

-#define OMAHA_NET_BITS_UTILS_H__

-

-#include <windows.h>

-#include <bits.h>

-#include <atlbase.h>

-#include <atlstr.h>

-#include <functional>

-

-namespace omaha {

-

-// Gets the instance of BITS manager.

-HRESULT GetBitsManager(IBackgroundCopyManager** bits_manager);

-

-// Compares the local name of a job.

-struct JobLocalNameEqual

-    : public std::binary_function<IBackgroundCopyJob*, const TCHAR*, bool> {

-

-  bool operator()(IBackgroundCopyJob* job, const TCHAR* local_name) const;

-};

-

-// Compares the display name of a job.

-struct JobDisplayNameEqual

-    : public std::binary_function<IBackgroundCopyJob*, const TCHAR*, bool> {

-

-  bool operator()(IBackgroundCopyJob* job, const TCHAR* local_name) const;

-};

-

-// Finds a job that matches the given predicate.

-// TODO(omaha): do we need to search across all users?

-template<class Predicate>

-HRESULT FindBitsJobIf(Predicate pred,

-                      IBackgroundCopyManager* bits_manager,

-                      IBackgroundCopyJob** job) {

-  if (!bits_manager || !job || *job) {

-    return E_INVALIDARG;

-  }

-

-  // Enumerate the jobs that belong to the calling user.

-  CComPtr<IEnumBackgroundCopyJobs> jobs;

-  HRESULT hr = bits_manager->EnumJobs(0, &jobs);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ULONG job_count = 0;

-  hr = jobs->GetCount(&job_count);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  for (size_t i = 0; i != job_count; ++i) {

-    CComPtr<IBackgroundCopyJob> current_job;

-    if (jobs->Next(1, &current_job, NULL) != S_OK) {

-      break;

-    }

-    if (pred(current_job)) {

-      *job = current_job.Detach();

-      return S_OK;

-    }

-  }

-  return E_FAIL;

-}

-

-// Sets using the implicit credentials to authenticate to proxy servers.

-HRESULT SetProxyAuthImplicitCredentials(IBackgroundCopyJob* job,

-                                        BG_AUTH_SCHEME auth_scheme);

-

-// Sets credentials to authenticate to proxy servers. username and password can

-// be NULL, in which case BITS will try connecting with implicit/autologon

-// credentials.

-HRESULT SetProxyAuthCredentials(IBackgroundCopyJob* job,

-                                TCHAR* username,

-                                TCHAR* password,

-                                BG_AUTH_SCHEME auth_scheme);

-

-// Returns an HTTP status code from the BITS error code.

-int GetHttpStatusFromBitsError(HRESULT error);

-

-// Cancels a job.

-HRESULT CancelBitsJob(IBackgroundCopyJob* job);

-

-// Converts a job state to a string.

-CString JobStateToString(BG_JOB_STATE job_state);

-

-// Converts a BITS auth scheme to a string.

-CString BitsAuthSchemeToString(int auth_scheme);

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_BITS_UTILS_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_NET_BITS_UTILS_H__
+#define OMAHA_NET_BITS_UTILS_H__
+
+#include <windows.h>
+#include <bits.h>
+#include <atlbase.h>
+#include <atlstr.h>
+#include <functional>
+
+namespace omaha {
+
+// Gets the instance of BITS manager.
+HRESULT GetBitsManager(IBackgroundCopyManager** bits_manager);
+
+// Compares the local name of a job.
+struct JobLocalNameEqual
+    : public std::binary_function<IBackgroundCopyJob*, const TCHAR*, bool> {
+
+  bool operator()(IBackgroundCopyJob* job, const TCHAR* local_name) const;
+};
+
+// Compares the display name of a job.
+struct JobDisplayNameEqual
+    : public std::binary_function<IBackgroundCopyJob*, const TCHAR*, bool> {
+
+  bool operator()(IBackgroundCopyJob* job, const TCHAR* local_name) const;
+};
+
+// Finds a job that matches the given predicate.
+// TODO(omaha): do we need to search across all users?
+template<class Predicate>
+HRESULT FindBitsJobIf(Predicate pred,
+                      IBackgroundCopyManager* bits_manager,
+                      IBackgroundCopyJob** job) {
+  if (!bits_manager || !job || *job) {
+    return E_INVALIDARG;
+  }
+
+  // Enumerate the jobs that belong to the calling user.
+  CComPtr<IEnumBackgroundCopyJobs> jobs;
+  HRESULT hr = bits_manager->EnumJobs(0, &jobs);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ULONG job_count = 0;
+  hr = jobs->GetCount(&job_count);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  for (size_t i = 0; i != job_count; ++i) {
+    CComPtr<IBackgroundCopyJob> current_job;
+    if (jobs->Next(1, &current_job, NULL) != S_OK) {
+      break;
+    }
+    if (pred(current_job)) {
+      *job = current_job.Detach();
+      return S_OK;
+    }
+  }
+  return E_FAIL;
+}
+
+// Sets using the implicit credentials to authenticate to proxy servers.
+HRESULT SetProxyAuthImplicitCredentials(IBackgroundCopyJob* job,
+                                        BG_AUTH_SCHEME auth_scheme);
+
+// Sets credentials to authenticate to proxy servers. username and password can
+// be NULL, in which case BITS will try connecting with implicit/autologon
+// credentials.
+HRESULT SetProxyAuthCredentials(IBackgroundCopyJob* job,
+                                TCHAR* username,
+                                TCHAR* password,
+                                BG_AUTH_SCHEME auth_scheme);
+
+// Returns an HTTP status code from the BITS error code.
+int GetHttpStatusFromBitsError(HRESULT error);
+
+// Cancels a job.
+HRESULT CancelBitsJob(IBackgroundCopyJob* job);
+
+// Converts a job state to a string.
+CString JobStateToString(BG_JOB_STATE job_state);
+
+// Converts a BITS auth scheme to a string.
+CString BitsAuthSchemeToString(int auth_scheme);
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_BITS_UTILS_H__
+
diff --git a/net/bits_utils_unittest.cc b/net/bits_utils_unittest.cc
index 4f2c294..0cdc044 100644
--- a/net/bits_utils_unittest.cc
+++ b/net/bits_utils_unittest.cc
@@ -1,46 +1,46 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <winhttp.h>

-#include <atlbase.h>

-#include "omaha/net/bits_utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(BitsUtilsTest, GetBitsManager) {

-  CComPtr<IBackgroundCopyManager> bits_manager;

-  ASSERT_HRESULT_SUCCEEDED(GetBitsManager(&bits_manager));

-}

-

-TEST(BitsUtilsTest, GetHttpStatusFromBitsError) {

-  EXPECT_EQ(GetHttpStatusFromBitsError(BG_E_HTTP_ERROR_400),

-            HTTP_STATUS_BAD_REQUEST);

-  EXPECT_EQ(GetHttpStatusFromBitsError(BG_E_HTTP_ERROR_407),

-            HTTP_STATUS_PROXY_AUTH_REQ);

-  EXPECT_EQ(GetHttpStatusFromBitsError(BG_E_HTTP_ERROR_100),

-            HTTP_STATUS_CONTINUE);

-  EXPECT_EQ(GetHttpStatusFromBitsError(BG_E_HTTP_ERROR_505),

-            HTTP_STATUS_VERSION_NOT_SUP);

-

-  EXPECT_EQ(GetHttpStatusFromBitsError(-1), 0);

-  EXPECT_EQ(GetHttpStatusFromBitsError(0), 0);

-  EXPECT_EQ(GetHttpStatusFromBitsError(99), 0);

-  EXPECT_EQ(GetHttpStatusFromBitsError(506), 0);

-}

-

-}   // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <winhttp.h>
+#include <atlbase.h>
+#include "omaha/net/bits_utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(BitsUtilsTest, GetBitsManager) {
+  CComPtr<IBackgroundCopyManager> bits_manager;
+  ASSERT_HRESULT_SUCCEEDED(GetBitsManager(&bits_manager));
+}
+
+TEST(BitsUtilsTest, GetHttpStatusFromBitsError) {
+  EXPECT_EQ(GetHttpStatusFromBitsError(BG_E_HTTP_ERROR_400),
+            HTTP_STATUS_BAD_REQUEST);
+  EXPECT_EQ(GetHttpStatusFromBitsError(BG_E_HTTP_ERROR_407),
+            HTTP_STATUS_PROXY_AUTH_REQ);
+  EXPECT_EQ(GetHttpStatusFromBitsError(BG_E_HTTP_ERROR_100),
+            HTTP_STATUS_CONTINUE);
+  EXPECT_EQ(GetHttpStatusFromBitsError(BG_E_HTTP_ERROR_505),
+            HTTP_STATUS_VERSION_NOT_SUP);
+
+  EXPECT_EQ(GetHttpStatusFromBitsError(-1), 0);
+  EXPECT_EQ(GetHttpStatusFromBitsError(0), 0);
+  EXPECT_EQ(GetHttpStatusFromBitsError(99), 0);
+  EXPECT_EQ(GetHttpStatusFromBitsError(506), 0);
+}
+
+}   // namespace omaha
+
diff --git a/net/browser_request.cc b/net/browser_request.cc
index 8e8ddec..51aad09 100644
--- a/net/browser_request.cc
+++ b/net/browser_request.cc
@@ -1,150 +1,150 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Not used at the moment. The idea is to use an external process, such as

-// the web browser in cases where GoogleUpdate.exe is not able to connect

-// directly for some reason.

-//

-// TODO(Omaha) - Better algorithm for finding IBrowserHttpRequest2 objects:

-// We currently use shared memory. We have the high integrity process

-// read from shared memory that the low integrity process writes to. We assume

-// a common executable, IEXPLORE.exe, which is limiting, because in the future

-// we could be embedded in multiple processes.

-

-// Another choice for detection will be more efficient overall. But it will

-// entail some work: each IBrowserRequest will register itself with the ROT.

-// It does this through a medium-integrity GoogleUpdate.exe. The high integrity

-// process will then impersonate the explorer token, and then CoCreate

-// GoogleUpdate.exe at medium integrity. Then the medium integrity GoogleUpdate

-// can return an appropriate IBrowserRequest interface from the local ROT.

-//

-// This scheme is flexible enough that it can work regardless of which

-// process the IBrowserRequest object(s) reside in. We could have a Firefox

-// plugin, a Chrome-resident object, an object residing inside Google Talk, etc.

-

-#include "omaha/net/browser_request.h"

-#include <atlbase.h>

-#include <atlcom.h>

-#include "omaha/common/logging.h"

-#include "omaha/common/system.h"

-#include "omaha/common/vista_utils.h"

-#include "omaha/goopdate/google_update_proxy.h"

-

-namespace omaha {

-

-BrowserRequest::BrowserRequest() {

-  NET_LOG(L3, (_T("[BrowserRequest::BrowserRequest]")));

-  user_agent_.Format(_T("%s;iexplore"), NetworkConfig::GetUserAgent());

-

-#if 0

-  if (!GetAvailableBrowserObjects()) {

-    NET_LOG(LW, (_T("[BrowserRequest: No Browser Objects Found.]")));

-  }

-#endif

-}

-

-bool BrowserRequest::GetAvailableBrowserObjects() {

-  std::vector<uint32> pids;

-  HRESULT hr = vista::GetProcessPidsForActiveUserOrSession(kIExplore, &pids);

-  if (FAILED(hr)) {

-    NET_LOG(LE, (_T("[GetProcessPidsForActiveUserOrSession fail][0x%x]"), hr));

-    return false;

-  }

-

-  bool is_system = false;

-  hr = IsSystemProcess(&is_system);

-  if (FAILED(hr)) {

-    NET_LOG(LE, (_T("[IsSystemProcess failed][0x%x]"), hr));

-    return false;

-  }

-

-  CString shared_memory_prefix;

-  DWORD active_session = System::GetActiveSessionId();

-  if (is_system && active_session != System::GetCurrentSessionId()) {

-    // The Session\\ syntax references a local object in a different session.

-    shared_memory_prefix.Format(_T("Session\\%d\\"), active_session);

-  }

-  shared_memory_prefix += kBrowserHttpRequestShareName;

-

-  std::vector<uint32>::const_iterator iter = pids.begin();

-  for (; iter != pids.end(); ++iter) {

-    uint32 pid = *iter;

-    CString shared_memory_name;

-    shared_memory_name = shared_memory_prefix;

-    shared_memory_name.AppendFormat(_T("%d"), pid);

-    SharedMemoryAttributes default_attributes(shared_memory_name,

-                                              CSecurityDesc());

-    SharedMemoryProxy<IBrowserHttpRequest2, FakeGLock> proxy_read(

-                                                           true,

-                                                           &default_attributes);

-    CComPtr<IBrowserHttpRequest2> browser_http_request;

-    HRESULT hr = proxy_read.GetObject(&browser_http_request);

-    if (FAILED(hr) || !browser_http_request) {

-      NET_LOG(LW, (_T("[GetObject failed][%d][%d][0x%x]"),

-                   pid, browser_http_request, hr));

-      // Keep looking for more IBrowserHttpRequest2 objects.

-      continue;

-    }

-

-    objects_.push_back(browser_http_request);

-  }

-

-  return !objects_.empty();

-}

-

-HRESULT BrowserRequest::SendRequest(BSTR url,

-                                    BSTR post_data,

-                                    BSTR request_headers,

-                                    VARIANT response_headers_needed,

-                                    CComVariant* response_headers,

-                                    DWORD* response_code,

-                                    BSTR* cache_filename_bstr) {

-  NET_LOG(L3, (_T("[BrowserRequest::SendRequest]")));

-  if (objects_.empty()) {

-    NET_LOG(LE, (_T("[SendRequest: No Browser Objects available.]")));

-    return E_FAIL;

-  }

-

-  BrowserObjects::const_iterator i = objects_.begin();

-  HRESULT hr = E_UNEXPECTED;

-  CComBSTR cache_filename;

-  for (; i != objects_.end(); ++i) {

-    CComPtr<IBrowserHttpRequest2> browser_object(*i);

-    response_headers->Clear();

-    *response_code = 0;

-    cache_filename.Empty();

-    hr = browser_object->Send(url,

-                              post_data,

-                              request_headers,

-                              response_headers_needed,

-                              response_headers,

-                              response_code,

-                              &cache_filename);

-    NET_LOG(L3, (_T("[BrowserRequest::SendRequest][0x%x][%d][%s]"),

-                 hr, *response_code, cache_filename));

-

-    if (!*response_code) {

-      continue;

-    }

-

-    *cache_filename_bstr = cache_filename.Detach();

-    return S_OK;

-  }

-

-  return FAILED(hr) ? hr : E_UNEXPECTED;

-}

-

-}   // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Not used at the moment. The idea is to use an external process, such as
+// the web browser in cases where GoogleUpdate.exe is not able to connect
+// directly for some reason.
+//
+// TODO(Omaha) - Better algorithm for finding IBrowserHttpRequest2 objects:
+// We currently use shared memory. We have the high integrity process
+// read from shared memory that the low integrity process writes to. We assume
+// a common executable, IEXPLORE.exe, which is limiting, because in the future
+// we could be embedded in multiple processes.
+
+// Another choice for detection will be more efficient overall. But it will
+// entail some work: each IBrowserRequest will register itself with the ROT.
+// It does this through a medium-integrity GoogleUpdate.exe. The high integrity
+// process will then impersonate the explorer token, and then CoCreate
+// GoogleUpdate.exe at medium integrity. Then the medium integrity GoogleUpdate
+// can return an appropriate IBrowserRequest interface from the local ROT.
+//
+// This scheme is flexible enough that it can work regardless of which
+// process the IBrowserRequest object(s) reside in. We could have a Firefox
+// plugin, a Chrome-resident object, an object residing inside Google Talk, etc.
+
+#include "omaha/net/browser_request.h"
+#include <atlbase.h>
+#include <atlcom.h>
+#include "omaha/common/logging.h"
+#include "omaha/common/system.h"
+#include "omaha/common/vista_utils.h"
+#include "omaha/goopdate/google_update_proxy.h"
+
+namespace omaha {
+
+BrowserRequest::BrowserRequest() {
+  NET_LOG(L3, (_T("[BrowserRequest::BrowserRequest]")));
+  user_agent_.Format(_T("%s;iexplore"), NetworkConfig::GetUserAgent());
+
+#if 0
+  if (!GetAvailableBrowserObjects()) {
+    NET_LOG(LW, (_T("[BrowserRequest: No Browser Objects Found.]")));
+  }
+#endif
+}
+
+bool BrowserRequest::GetAvailableBrowserObjects() {
+  std::vector<uint32> pids;
+  HRESULT hr = vista::GetProcessPidsForActiveUserOrSession(kIExplore, &pids);
+  if (FAILED(hr)) {
+    NET_LOG(LE, (_T("[GetProcessPidsForActiveUserOrSession fail][0x%x]"), hr));
+    return false;
+  }
+
+  bool is_system = false;
+  hr = IsSystemProcess(&is_system);
+  if (FAILED(hr)) {
+    NET_LOG(LE, (_T("[IsSystemProcess failed][0x%x]"), hr));
+    return false;
+  }
+
+  CString shared_memory_prefix;
+  DWORD active_session = System::GetActiveSessionId();
+  if (is_system && active_session != System::GetCurrentSessionId()) {
+    // The Session\\ syntax references a local object in a different session.
+    shared_memory_prefix.Format(_T("Session\\%d\\"), active_session);
+  }
+  shared_memory_prefix += kBrowserHttpRequestShareName;
+
+  std::vector<uint32>::const_iterator iter = pids.begin();
+  for (; iter != pids.end(); ++iter) {
+    uint32 pid = *iter;
+    CString shared_memory_name;
+    shared_memory_name = shared_memory_prefix;
+    shared_memory_name.AppendFormat(_T("%d"), pid);
+    SharedMemoryAttributes default_attributes(shared_memory_name,
+                                              CSecurityDesc());
+    SharedMemoryProxy<IBrowserHttpRequest2, FakeGLock> proxy_read(
+                                                           true,
+                                                           &default_attributes);
+    CComPtr<IBrowserHttpRequest2> browser_http_request;
+    HRESULT hr = proxy_read.GetObject(&browser_http_request);
+    if (FAILED(hr) || !browser_http_request) {
+      NET_LOG(LW, (_T("[GetObject failed][%d][%d][0x%x]"),
+                   pid, browser_http_request, hr));
+      // Keep looking for more IBrowserHttpRequest2 objects.
+      continue;
+    }
+
+    objects_.push_back(browser_http_request);
+  }
+
+  return !objects_.empty();
+}
+
+HRESULT BrowserRequest::SendRequest(BSTR url,
+                                    BSTR post_data,
+                                    BSTR request_headers,
+                                    VARIANT response_headers_needed,
+                                    CComVariant* response_headers,
+                                    DWORD* response_code,
+                                    BSTR* cache_filename_bstr) {
+  NET_LOG(L3, (_T("[BrowserRequest::SendRequest]")));
+  if (objects_.empty()) {
+    NET_LOG(LE, (_T("[SendRequest: No Browser Objects available.]")));
+    return E_FAIL;
+  }
+
+  BrowserObjects::const_iterator i = objects_.begin();
+  HRESULT hr = E_UNEXPECTED;
+  CComBSTR cache_filename;
+  for (; i != objects_.end(); ++i) {
+    CComPtr<IBrowserHttpRequest2> browser_object(*i);
+    response_headers->Clear();
+    *response_code = 0;
+    cache_filename.Empty();
+    hr = browser_object->Send(url,
+                              post_data,
+                              request_headers,
+                              response_headers_needed,
+                              response_headers,
+                              response_code,
+                              &cache_filename);
+    NET_LOG(L3, (_T("[BrowserRequest::SendRequest][0x%x][%d][%s]"),
+                 hr, *response_code, cache_filename));
+
+    if (!*response_code) {
+      continue;
+    }
+
+    *cache_filename_bstr = cache_filename.Detach();
+    return S_OK;
+  }
+
+  return FAILED(hr) ? hr : E_UNEXPECTED;
+}
+
+}   // namespace omaha
+
diff --git a/net/browser_request.h b/net/browser_request.h
index d8942e8..f7ffd2e 100644
--- a/net/browser_request.h
+++ b/net/browser_request.h
@@ -1,57 +1,57 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// BrowserRequest provides http transactions proxied through a user's browser.

-

-#ifndef OMAHA_NET_BROWSER_REQUEST_H__

-#define OMAHA_NET_BROWSER_REQUEST_H__

-

-#include <list>

-#include "omaha/net/urlmon_request.h"

-

-namespace omaha {

-

-typedef std::list<CAdapt<CComPtr<IBrowserHttpRequest2> > > BrowserObjects;

-

-class BrowserRequest : public UrlmonRequest {

- public:

-  BrowserRequest();

-  virtual ~BrowserRequest() {}

-

-  virtual CString ToString() const { return _T("iexplore"); }

-

-  virtual HRESULT SendRequest(BSTR url,

-                              BSTR post_data,

-                              BSTR request_headers,

-                              VARIANT response_headers_needed,

-                              CComVariant* response_headers,

-                              DWORD* response_code,

-                              BSTR* cache_filename);

-

- private:

-  bool GetAvailableBrowserObjects();

-  BrowserObjects objects_;

-

-  friend class BrowserRequestTest;

-  friend class CupRequestTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(BrowserRequest);

-};

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_BROWSER_REQUEST_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// BrowserRequest provides http transactions proxied through a user's browser.
+
+#ifndef OMAHA_NET_BROWSER_REQUEST_H__
+#define OMAHA_NET_BROWSER_REQUEST_H__
+
+#include <list>
+#include "omaha/net/urlmon_request.h"
+
+namespace omaha {
+
+typedef std::list<CAdapt<CComPtr<IBrowserHttpRequest2> > > BrowserObjects;
+
+class BrowserRequest : public UrlmonRequest {
+ public:
+  BrowserRequest();
+  virtual ~BrowserRequest() {}
+
+  virtual CString ToString() const { return _T("iexplore"); }
+
+  virtual HRESULT SendRequest(BSTR url,
+                              BSTR post_data,
+                              BSTR request_headers,
+                              VARIANT response_headers_needed,
+                              CComVariant* response_headers,
+                              DWORD* response_code,
+                              BSTR* cache_filename);
+
+ private:
+  bool GetAvailableBrowserObjects();
+  BrowserObjects objects_;
+
+  friend class BrowserRequestTest;
+  friend class CupRequestTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(BrowserRequest);
+};
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_BROWSER_REQUEST_H__
+
diff --git a/net/browser_request_unittest.cc b/net/browser_request_unittest.cc
index a3dc56d..ad02a0e 100644
--- a/net/browser_request_unittest.cc
+++ b/net/browser_request_unittest.cc
@@ -1,122 +1,122 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include <windows.h>

-#include <winhttp.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/string.h"

-#include "omaha/net/browser_request.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class BrowserRequestTest : public testing::Test {

- protected:

-  BrowserRequestTest() : are_browser_objects_available(false) {

-    BrowserRequest request;

-    are_browser_objects_available = !request.objects_.empty();

-  }

-

-  void BrowserGet(const CString& url);

-  void BrowserGet204(const CString& url);

-  void BrowserDownload(const CString& url);

-

-  bool are_browser_objects_available;

-};

-

-void BrowserRequestTest::BrowserGet(const CString& url) {

-  if (!are_browser_objects_available) {

-    return;

-  }

-

-  BrowserRequest browser_request;

-  browser_request.set_url(url);

-  EXPECT_HRESULT_SUCCEEDED(browser_request.Send());

-  EXPECT_EQ(HTTP_STATUS_OK, browser_request.GetHttpStatusCode());

-

-  CString response(Utf8BufferToWideChar(browser_request.GetResponse()));

-  EXPECT_NE(-1, response.Find(_T("User-agent: *")));

-  CString content_type;

-  browser_request.QueryHeadersString(WINHTTP_QUERY_CONTENT_TYPE,

-                                     NULL, &content_type);

-  EXPECT_STREQ(_T("text/plain"), content_type);

-  EXPECT_FALSE(browser_request.GetResponseHeaders().IsEmpty());

-}

-

-void BrowserRequestTest::BrowserGet204(const CString& url) {

-  if (!are_browser_objects_available) {

-    return;

-  }

-

-  BrowserRequest browser_request;

-  browser_request.set_url(url);

-  EXPECT_HRESULT_SUCCEEDED(browser_request.Send());

-  EXPECT_EQ(HTTP_STATUS_NO_CONTENT, browser_request.GetHttpStatusCode());

-  CString response(Utf8BufferToWideChar(browser_request.GetResponse()));

-  EXPECT_EQ(-1, response.Find(_T("User-agent: *")));

-  CString content_type;

-  browser_request.QueryHeadersString(WINHTTP_QUERY_CONTENT_TYPE,

-                                     NULL, &content_type);

-  EXPECT_STREQ(_T("text/html"), content_type);

-  EXPECT_FALSE(browser_request.GetResponseHeaders().IsEmpty());

-}

-

-void BrowserRequestTest::BrowserDownload(const CString& url) {

-  if (!are_browser_objects_available) {

-    return;

-  }

-

-  BrowserRequest browser_request;

-  CString temp_dir = app_util::GetTempDir();

-  CString temp_file;

-  EXPECT_TRUE(::GetTempFileName(temp_dir, _T("tmp"), 0,

-                                CStrBuf(temp_file, MAX_PATH)));

-  browser_request.set_filename(temp_file);

-  browser_request.set_url(url);

-

-  // First request.

-  ASSERT_HRESULT_SUCCEEDED(browser_request.Send());

-  EXPECT_EQ(HTTP_STATUS_OK, browser_request.GetHttpStatusCode());

-  browser_request.Close();

-

-  // Second request.

-  ASSERT_HRESULT_SUCCEEDED(browser_request.Send());

-  EXPECT_EQ(HTTP_STATUS_OK, browser_request.GetHttpStatusCode());

-

-  EXPECT_TRUE(::DeleteFile(temp_file));

-}

-

-// http get.

-TEST_F(BrowserRequestTest, HttpGet) {

-  BrowserGet(_T("http://www.google.com/robots.txt"));

-}

-

-// https get.

-TEST_F(BrowserRequestTest, HttpsGet) {

-  BrowserGet(_T("https://www.google.com/robots.txt"));

-}

-

-TEST_F(BrowserRequestTest, Download) {

-  BrowserDownload(_T("http://dl.google.com/update2/UpdateData.bin"));

-}

-

-// http get 204.

-TEST_F(BrowserRequestTest, HttpGet204) {

-  BrowserGet204(_T("http://tools.google.com/service/check2"));

-}

-

-}   // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include <windows.h>
+#include <winhttp.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/string.h"
+#include "omaha/net/browser_request.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class BrowserRequestTest : public testing::Test {
+ protected:
+  BrowserRequestTest() : are_browser_objects_available(false) {
+    BrowserRequest request;
+    are_browser_objects_available = !request.objects_.empty();
+  }
+
+  void BrowserGet(const CString& url);
+  void BrowserGet204(const CString& url);
+  void BrowserDownload(const CString& url);
+
+  bool are_browser_objects_available;
+};
+
+void BrowserRequestTest::BrowserGet(const CString& url) {
+  if (!are_browser_objects_available) {
+    return;
+  }
+
+  BrowserRequest browser_request;
+  browser_request.set_url(url);
+  EXPECT_HRESULT_SUCCEEDED(browser_request.Send());
+  EXPECT_EQ(HTTP_STATUS_OK, browser_request.GetHttpStatusCode());
+
+  CString response(Utf8BufferToWideChar(browser_request.GetResponse()));
+  EXPECT_NE(-1, response.Find(_T("User-agent: *")));
+  CString content_type;
+  browser_request.QueryHeadersString(WINHTTP_QUERY_CONTENT_TYPE,
+                                     NULL, &content_type);
+  EXPECT_STREQ(_T("text/plain"), content_type);
+  EXPECT_FALSE(browser_request.GetResponseHeaders().IsEmpty());
+}
+
+void BrowserRequestTest::BrowserGet204(const CString& url) {
+  if (!are_browser_objects_available) {
+    return;
+  }
+
+  BrowserRequest browser_request;
+  browser_request.set_url(url);
+  EXPECT_HRESULT_SUCCEEDED(browser_request.Send());
+  EXPECT_EQ(HTTP_STATUS_NO_CONTENT, browser_request.GetHttpStatusCode());
+  CString response(Utf8BufferToWideChar(browser_request.GetResponse()));
+  EXPECT_EQ(-1, response.Find(_T("User-agent: *")));
+  CString content_type;
+  browser_request.QueryHeadersString(WINHTTP_QUERY_CONTENT_TYPE,
+                                     NULL, &content_type);
+  EXPECT_STREQ(_T("text/html"), content_type);
+  EXPECT_FALSE(browser_request.GetResponseHeaders().IsEmpty());
+}
+
+void BrowserRequestTest::BrowserDownload(const CString& url) {
+  if (!are_browser_objects_available) {
+    return;
+  }
+
+  BrowserRequest browser_request;
+  CString temp_dir = app_util::GetTempDir();
+  CString temp_file;
+  EXPECT_TRUE(::GetTempFileName(temp_dir, _T("tmp"), 0,
+                                CStrBuf(temp_file, MAX_PATH)));
+  browser_request.set_filename(temp_file);
+  browser_request.set_url(url);
+
+  // First request.
+  ASSERT_HRESULT_SUCCEEDED(browser_request.Send());
+  EXPECT_EQ(HTTP_STATUS_OK, browser_request.GetHttpStatusCode());
+  browser_request.Close();
+
+  // Second request.
+  ASSERT_HRESULT_SUCCEEDED(browser_request.Send());
+  EXPECT_EQ(HTTP_STATUS_OK, browser_request.GetHttpStatusCode());
+
+  EXPECT_TRUE(::DeleteFile(temp_file));
+}
+
+// http get.
+TEST_F(BrowserRequestTest, HttpGet) {
+  BrowserGet(_T("http://www.google.com/robots.txt"));
+}
+
+// https get.
+TEST_F(BrowserRequestTest, HttpsGet) {
+  BrowserGet(_T("https://www.google.com/robots.txt"));
+}
+
+TEST_F(BrowserRequestTest, Download) {
+  BrowserDownload(_T("http://dl.google.com/update2/UpdateData.bin"));
+}
+
+// http get 204.
+TEST_F(BrowserRequestTest, HttpGet204) {
+  BrowserGet204(_T("http://tools.google.com/service/check2"));
+}
+
+}   // namespace omaha
+
diff --git a/net/build.scons b/net/build.scons
index 8691565..907550c 100644
--- a/net/build.scons
+++ b/net/build.scons
@@ -1,60 +1,60 @@
-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-# Create a local clone, so the parent environment is

-# unaffected by changes made here.

-local_env = env.Clone()

-

-local_env.Append(

-    CCFLAGS = [

-        '/wd4510',  # default constructor could not be generated

-        '/wd4610',  # object 'class' can never be instantiated

-        ],

-    CPPPATH = [

-        '$MAIN_DIR/third_party/c99/include',   # C99 inttypes.h for security

-

-        # Need to look in output dir to find .h files generated by midl compiler.

-        # This also allows Hammer to understand dependencies between this subdir

-        # and the .idl files in the goopdate folder.

-        '$OBJ_ROOT',

-        ],

-)

-

-inputs = [

-    'bind_status_callback.cc',

-    'bits_request.cc',

-    'bits_utils.cc',

-    'browser_request.cc',

-    'cup_request.cc',

-    'cup_utils.cc',

-    'detector.cc',

-    'http_client.cc',

-    'simple_request.cc',

-    'urlmon_request.cc',

-    'net_diags.cc',

-    'net_utils.cc',

-    'network_config.cc',

-    'network_request.cc',

-    'network_request_impl.cc',

-    'proxy_auth.cc',

-    #'wininet.cc',      # we don't have support for wininet yet

-    'winhttp.cc',

-    'winhttp_vtable.cc',

-]

-

-# Build these into a library.

-local_env.ComponentLibrary('net', inputs)

+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+# Create a local clone, so the parent environment is
+# unaffected by changes made here.
+local_env = env.Clone()
+
+local_env.Append(
+    CCFLAGS = [
+        '/wd4510',  # default constructor could not be generated
+        '/wd4610',  # object 'class' can never be instantiated
+        ],
+    CPPPATH = [
+        '$MAIN_DIR/third_party/c99/include',   # C99 inttypes.h for security
+
+        # Need to look in output dir to find .h files generated by midl compiler.
+        # This also allows Hammer to understand dependencies between this subdir
+        # and the .idl files in the goopdate folder.
+        '$OBJ_ROOT',
+        ],
+)
+
+inputs = [
+    'bind_status_callback.cc',
+    'bits_request.cc',
+    'bits_utils.cc',
+    'browser_request.cc',
+    'cup_request.cc',
+    'cup_utils.cc',
+    'detector.cc',
+    'http_client.cc',
+    'simple_request.cc',
+    'urlmon_request.cc',
+    'net_diags.cc',
+    'net_utils.cc',
+    'network_config.cc',
+    'network_request.cc',
+    'network_request_impl.cc',
+    'proxy_auth.cc',
+    #'wininet.cc',      # we don't have support for wininet yet
+    'winhttp.cc',
+    'winhttp_vtable.cc',
+]
+
+# Build these into a library.
+local_env.ComponentLibrary('net', inputs)
diff --git a/net/cup_pubkey.1.h b/net/cup_pubkey.1.h
index 93ac220..86434c8 100644
--- a/net/cup_pubkey.1.h
+++ b/net/cup_pubkey.1.h
@@ -1,15 +1,15 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-{1,32,0xb7e418f5,0x24168e4a,0x573b9e59,0xc8467437,0x86855da2,0x219222a2,0x1d0d377f,0x4a8c6193,0x49d12e87,0xa3babd81,0x4a2bb798,0xb73612a5,0x2c3da8a9,0xcc81079e,0xb8421488,0x2c8b88a2,0x70bf4b04,0x4560d954,0xdddcab57,0x7ba7ea81,0xc376b2e3,0xedc0b845,0xf6fb118a,0x48e62940,0x1dfdc5e,0x2ef66eb3,0x812fcf0b,0x2d8e5a9,0x58cffdc9,0x934ec9f,0x86f866a9,0xb7abbedc,0xc6aa01c0,0xd7802d7c,0x20d5045b,0xf54eaac3,0xb0464829,0x91a6fa43,0x24ccf604,0xf7230e2b,0xbbc91fee,0x45dd54c3,0x4ee47f6d,0x46f30e32,0xf9229e70,0xc89e98ed,0x614c1bce,0x86427571,0xa141ecf2,0x9caf8721,0xf8d32d46,0x1d7d3021,0xfa7f4f82,0x887d82c3,0xd802562b,0xc1e4f75d,0x48896303,0xbffb080,0x42d60913,0xdf7b2b64,0x673a8774,0x7e3a4082,0xbc5f74c6,0x8fb64535,0xd9a3cda}

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+{1,32,0xb7e418f5,0x24168e4a,0x573b9e59,0xc8467437,0x86855da2,0x219222a2,0x1d0d377f,0x4a8c6193,0x49d12e87,0xa3babd81,0x4a2bb798,0xb73612a5,0x2c3da8a9,0xcc81079e,0xb8421488,0x2c8b88a2,0x70bf4b04,0x4560d954,0xdddcab57,0x7ba7ea81,0xc376b2e3,0xedc0b845,0xf6fb118a,0x48e62940,0x1dfdc5e,0x2ef66eb3,0x812fcf0b,0x2d8e5a9,0x58cffdc9,0x934ec9f,0x86f866a9,0xb7abbedc,0xc6aa01c0,0xd7802d7c,0x20d5045b,0xf54eaac3,0xb0464829,0x91a6fa43,0x24ccf604,0xf7230e2b,0xbbc91fee,0x45dd54c3,0x4ee47f6d,0x46f30e32,0xf9229e70,0xc89e98ed,0x614c1bce,0x86427571,0xa141ecf2,0x9caf8721,0xf8d32d46,0x1d7d3021,0xfa7f4f82,0x887d82c3,0xd802562b,0xc1e4f75d,0x48896303,0xbffb080,0x42d60913,0xdf7b2b64,0x673a8774,0x7e3a4082,0xbc5f74c6,0x8fb64535,0xd9a3cda}
diff --git a/net/cup_pubkey.2.h b/net/cup_pubkey.2.h
index c2dda87..745307d 100644
--- a/net/cup_pubkey.2.h
+++ b/net/cup_pubkey.2.h
@@ -1,15 +1,15 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
 {2,32,0xfcd21d33,0x755a2de3,0xb7eac22,0x66b2aab6,0x6e6a1202,0x25a4dda,0x688b1eeb,0x6c75b003,0xbf3f9c25,0x89d0ffb9,0x23a83c49,0x31c441e5,0xa2b0e2fc,0x3c42ba60,0xcc79562c,0x29596164,0xfd5fffed,0x5ca40b27,0x89ed0af9,0x7e1ca88c,0xd016c69d,0x2f4e0d47,0x60c7bc5b,0x6a6db0c8,0xd7f6d5ff,0x1cb8dd55,0xa8fa737,0x3214960,0x3c300808,0xbbc7d2d9,0xf16b147e,0x9051df10,0xfc2292d9,0xa49712f2,0x53d70c7a,0x1287e191,0x8861d9a4,0x4bdc0671,0xf80caeaf,0xd5a83088,0x54e61a01,0x33e9b7af,0x5bc1383a,0x5f588f2e,0x24b3c6b,0xcc46fd12,0xcccc71e6,0x81f29a2e,0xdf12115d,0x260df134,0x723c0a2e,0x38a59429,0xf013fc9e,0x447a495,0xc92ab3f8,0x73128650,0x873e4994,0x17bded64,0x4d38c74a,0x9e8061d2,0xcff7210d,0xd9d7ed35,0x9182aa4,0x1f579b9c,0x966a57da}
\ No newline at end of file
diff --git a/net/cup_pubkey.3.h b/net/cup_pubkey.3.h
index 0ed59fd..b4af8cd 100644
--- a/net/cup_pubkey.3.h
+++ b/net/cup_pubkey.3.h
@@ -1,15 +1,15 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
 {3,32,0xb65e606b,0x905b9ba8,0x265d1815,0x923d5656,0x90640cd2,0x6365205,0x95b5f1dd,0x400c19b6,0xb4d77fae,0xdbd62a10,0xc4ba5466,0x2ed2a86e,0xe3345196,0xcfae25e,0x77e82f37,0xa3c1fa89,0x9fd3b9bd,0x68f95095,0xe6f5041,0x29a39dd5,0xcd60a78b,0x57e2017e,0x1921ebe8,0xca64543a,0x3d809822,0x7b24bddb,0xf4f7258,0xe812abee,0x51cbb2c5,0x6fee0df4,0x2bf64151,0x2a556212,0xfad45ee0,0x3f9fb0dc,0xf2945a,0xae5a629a,0x51f513d6,0xf0e04255,0x55ffd41,0x161af605,0x80811b22,0x52614662,0xc2e1bafe,0xa9e4617c,0xc7c7e9a2,0xa7643c24,0x9caecd4a,0xc04c3fa7,0x58bdb1bc,0xb06ed81b,0xfa8d9a2c,0xda1649ab,0x65c66680,0x9e58710c,0x15c06bc2,0xfef323f0,0x733ecc43,0x5d827fd0,0xfba47d79,0xb0cebc02,0xff590f6a,0x44a808b2,0x84b8a4ba,0x22762070,0x9ffc9d9f}
\ No newline at end of file
diff --git a/net/cup_reference_pubkey.1.h b/net/cup_reference_pubkey.1.h
index 8b47174..12d4d94 100644
--- a/net/cup_reference_pubkey.1.h
+++ b/net/cup_reference_pubkey.1.h
@@ -1,15 +1,15 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
 {1,32,0x53237ebd,0x7e012da6,0x2be8e5c5,0x631f548f,0x254a6cb1,0x4ed1812a,0x1fbd0d6b,0xc2690f5c,0xdb26f107,0x910072f2,0xe8d2451a,0x4ab13f07,0x6502be4e,0xfae1059f,0x2596195d,0x6998cc6c,0x122d5aa2,0x93fa179a,0x9fec32a5,0xa01a0535,0xb9c4a41f,0xead27de3,0x1c52c595,0x6b2d934f,0x3ffa6eaa,0x810e39bd,0x867db50e,0xcf2af656,0xac8e3aab,0x73698f94,0x378f8426,0x4622f3fb,0x18b64f90,0x3ee404fc,0xf335a03,0xd30cc6b,0x8217e5e0,0xff6d53d8,0x2870f8c4,0xd595e7a4,0x2952f894,0x6649f64a,0x24d90d64,0xa1d5a97b,0xebbdb966,0x7027bb9a,0x7dc9c5cd,0x1179c475,0xff570e96,0x9f65a38,0xbd340fa1,0x74634eb6,0x5ff46343,0x55045098,0x26974be4,0x475bedc4,0x9bce9883,0xf6e9ff20,0x5bde2bf2,0x3d56a643,0x82d2c723,0xd4da78dd,0x660e8ccd,0x32b6e38e,0x87461df9}
\ No newline at end of file
diff --git a/net/cup_request.cc b/net/cup_request.cc
index 56855de..66bc957 100644
--- a/net/cup_request.cc
+++ b/net/cup_request.cc
@@ -1,696 +1,696 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// TODO(omaha): to minimize conversions from UNICODE to UTF-8 consider an

-// API that takes the request body as UTF-8 and it stores it as UTF-8.

-

-#include "omaha/net/cup_request.h"

-

-#include <atlconv.h>

-#include <atlstr.h>

-#include <vector>

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/encrypt.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/security/b64.h"

-#include "omaha/common/security/hmac.h"

-#include "omaha/common/security/rsa.h"

-#include "omaha/common/security/sha.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-#include "omaha/net/cup_utils.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/net_utils.h"

-#include "omaha/net/network_config.h"

-

-using omaha::encrypt::EncryptData;

-using omaha::encrypt::DecryptData;

-

-namespace omaha {

-

-namespace detail {

-

-class CupRequestImpl {

- public:

-  explicit CupRequestImpl(HttpRequestInterface* http_request);

-  ~CupRequestImpl();

-

-  HRESULT Close();

-  HRESULT Send();

-  HRESULT Cancel();

-  std::vector<uint8> GetResponse() const;

-  HRESULT QueryHeadersString(uint32 info_level,

-                                    const TCHAR* name,

-                                    CString* value) const;

-  CString GetResponseHeaders() const;

-  int GetHttpStatusCode() const;

-  CString ToString() const;

-  void SetEntropy(const void* data, size_t data_length);

-

-  void set_session_handle(HINTERNET session_handle);

-  void set_url(const CString& url);

-  void set_request_buffer(const void* buffer, size_t buffer_length);

-  void set_network_configuration(const Config& network_config);

-  void set_filename(const CString& filename);

-  void set_low_priority(bool low_priority);

-  void set_callback(NetworkRequestCallback* callback);

-  void set_additional_headers(const CString& additional_headers);

-  CString user_agent() const;

-  void set_user_agent(const CString& user_agent);

-

- private:

-  HRESULT DoSend();

-  HRESULT BuildRequest();

-  HRESULT BuildChallengeHash();

-  HRESULT BuildClientProof();

-  HRESULT InitializeEntropy();

-  HRESULT AuthenticateResponse();

-

-  // Loads the {sk, c} credentials from persistent storage.

-  HRESULT LoadCredentials(std::vector<uint8>* sk, CStringA* c);

-

-  // Saves the {sk, c} credentials. The key is encrypted before saving it.

-  HRESULT SaveCredentials(const std::vector<uint8>& sk, const CStringA& c);

-

-  // Replaces the https protocol scheme with http.

-  CString BuildInnerRequestUrl(const CString& url);

-

-  // The transient state of the request, so that we can start always with a

-  // clean slate even though the same instance is being reuse across requests.

-  struct TransientCupState {

-    std::vector<uint8> entropy;

-    std::vector<uint8> r;         // Random bytes (r).

-    std::vector<uint8> sk;        // Cached shared key (sk)

-    std::vector<uint8> new_sk;    // Current shared_key (sk').

-    std::vector<uint8> hw;        // Challenge hash (hw).

-    std::vector<uint8> hm;        // Response hash (hm).

-

-    CStringA cp;                  // Client proof (cp).

-    CStringA sp;                  // Server proof (sp).

-    CStringA vw;                  // Versioned challenge (v|w).

-    std::vector<uint8> response;  // The received response.

-    CStringA c;                   // Cached client cookie (c)

-    CStringA new_cookie;          // The cookie returned by the server (c').

-

-    // The url of the request. It includes the original url plus the versioned

-    // challenge (v|w).

-    CStringA request_url;

-  };

-  scoped_ptr<TransientCupState> cup_;

-

-  CStringA url_;                        // The original url.

-  const void* request_buffer_;          // Contains the request body for POST.

-  size_t      request_buffer_length_;   // Length of the request body.

-  std::vector<uint8> entropy_;          // Optional entropy pass by the caller,

-                                        // mostly for testing purpose.

-

-  // {sk, c} credentials. They are persisted in the registry when the object is

-  // destroyed. The vast majority of network code runs impersonated. Writing

-  // through the credentials is likely to fail. However, due to how the

-  // CUP object is being used by the upper layers of the network code, a

-  // write back policy is possible.

-  std::vector<uint8> persisted_sk_;

-  CStringA           persisted_c_;

-

-  scoped_ptr<RSA> rsa_;

-  RSA::PublicKey public_key_;                      // Server public key (pk[v]).

-  scoped_ptr<HttpRequestInterface> http_request_;  // Inner http request.

-

-  static const RSA::PublicKeyInstance kCupProductionPublicKey;

-  static const RSA::PublicKeyInstance kCupTestPublicKey;

-

-  DISALLOW_EVIL_CONSTRUCTORS(CupRequestImpl);

-};

-

-const RSA::PublicKeyInstance CupRequestImpl::kCupProductionPublicKey =

-#include "omaha/net/cup_pubkey.3.h"

-;   // NOLINT

-

-const RSA::PublicKeyInstance CupRequestImpl::kCupTestPublicKey =

-#include "omaha/net/cup_pubkey.2.h"

-;   // NOLINT

-

-CupRequestImpl::CupRequestImpl(HttpRequestInterface* http_request)

-    : request_buffer_(NULL),

-      request_buffer_length_(0),

-      public_key_(NULL) {

-  ASSERT1(http_request);

-  bool is_using_cup_test_keys = NetworkConfig::IsUsingCupTestKeys();

-  public_key_ = is_using_cup_test_keys ? kCupTestPublicKey :

-                                         kCupProductionPublicKey;

-

-  // Try to retrieve the credentials if we have any. If we have succeeded, then

-  // we must have a {sk, c} pair. If we have failed, then we will generate

-  // a fresh set of credentials later on.

-  HRESULT hr = LoadCredentials(&persisted_sk_, &persisted_c_);

-  if (FAILED(hr)) {

-    ASSERT1(persisted_sk_.empty());

-    ASSERT1(persisted_c_.IsEmpty());

-  }

-

-  rsa_.reset(new RSA(public_key_));

-  http_request_.reset(http_request);

-

-  // Decorate the user agent by appending the "CUP" suffix. This overrides

-  // the user agent of the inner http request.

-  CString user_agent(http_request_->user_agent());

-  user_agent += _T(";cup");

-  http_request_->set_user_agent(user_agent);

-}

-

-CupRequestImpl::~CupRequestImpl() {

-  Close();

-}

-

-HRESULT CupRequestImpl::Close() {

-  cup_.reset();

-

-  // TODO(omaha): optimize so that if the credentials did not change then

-  // there would be not need to write back.

-  if (!persisted_sk_.empty() && !persisted_c_.IsEmpty()) {

-    VERIFY1(SUCCEEDED(SaveCredentials(persisted_sk_, persisted_c_)));

-  }

-  return http_request_->Close();

-}

-

-HRESULT CupRequestImpl::Send() {

-  // Start with a fresh CUP state. This is important as the client may

-  // reuse the same CUP request for subsequent requests.

-  cup_.reset(new TransientCupState);

-

-  // First, build a request, send it, and then authenticate the response.

-  HRESULT hr = BuildRequest();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  hr = DoSend();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  hr = AuthenticateResponse();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  return S_OK;

-}

-

-HRESULT CupRequestImpl::BuildRequest() {

-  HRESULT hr(InitializeEntropy());

-  if (FAILED(hr)) {

-    return hr;

-  }

-  // Start with some random bytes.

-  cup_->r = cup_utils::RsaPad(rsa_->size(),

-                              &cup_->entropy.front(), cup_->entropy.size());

-

-  // Derive a new shared key (sk') as the hash of the random bytes.

-  // TODO(omaha): consider protecting the key using ::CryptProtectmemory when

-  // not being used.

-  cup_->new_sk = cup_utils::Hash(cup_->r);

-

-  // Compute the challenge (w) by encrypting in place (r) with the server

-  // public key pk[v].

-  size_t encrypted_size = rsa_->raw(&cup_->r.front(), cup_->r.size());

-  ASSERT1(encrypted_size == cup_->r.size());

-

-  // Compute the versioned challenge (v|w) as

-  // decimal-v:base64-encoded-rsa-wrapper.

-  cup_->vw.Format("%d:%s",

-                  rsa_->version(),

-                  cup_utils::B64Encode(&cup_->r.front(), cup_->r.size()));

-

-  // Compute the url of the CUP request.

-  // Append a query string or append to the existing query string if any.

-  const char* format_string = url_.Find('?') != -1 ? "%1&w=%2" : "%1?w=%2";

-  cup_->request_url.FormatMessage(format_string, url_, cup_->vw);

-

-  // Compute the challenge hash (hw) as HASH(HASH(v|w)|HASH(req))

-  hr = BuildChallengeHash();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Compute the client proof as SYMsign[sk](0|hw|HASH(c)) if we have a

-  // {sk, c} pair or as SYMsign[sk'](3|hw) if we do not.

-  hr = BuildClientProof();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  NET_LOG(L4, (_T("[hw: %s]"), BytesToHex(cup_->hw)));

-

-  // This is what the client sends up along with the request: a versioned

-  // challenge, a client proof, and a client cookie if it has one.

-

-  NET_LOG(L4, (_T("[request:     %s]"), CA2T(cup_->request_url)));

-  NET_LOG(L4, (_T("[ifmatch:     %s]"), CA2T(cup_->cp)));

-  NET_LOG(L4, (_T("[cookie:      %s]"), CA2T(cup_->c)));

-

-  return S_OK;

-}

-

-HRESULT CupRequestImpl::BuildChallengeHash() {

-  // The hash of the request if carried through all the cryptographic proofs.

-  // The challenge hash hw is computed as:

-  // HASH(HASH(v|w)|HASH(request_url)|HASH(body)).

-  // For simplicity, the protocol scheme and the port are dropped before

-  // hashing. The hash is computed over the CUP request url, which includes

-  // the versioned hash.

-  scoped_ptr<HttpClient> http_client(CreateHttpClient());

-  if (!http_client.get()) {

-    return OMAHA_NET_E_CUP_NO_HTTP_CLIENT;

-  }

-  HRESULT hr = http_client->Initialize();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(!cup_->request_url.IsEmpty());

-  CString url(cup_->request_url);

-  CString scheme, server, url_path, query_string;

-  hr = http_client->CrackUrl(url,

-                             0,

-                             &scheme,

-                             &server,

-                             NULL,

-                             &url_path,

-                             &query_string);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ASSERT1(!scheme.IsEmpty());

-  ASSERT1(!server.IsEmpty());

-  ASSERT1(!url_path.IsEmpty());

-  url.FormatMessage(_T("//%1%2%3"), server, url_path, query_string);

-

-  CStringA req(url);

-

-  // Compute hw as HASH(HASH(v|w)|HASH(request_url)|HASH(body)).

-  ASSERT1(!cup_->vw.IsEmpty());

-  ASSERT1(!url.IsEmpty());

-  cup_->hw = cup_utils::HashBuffers(cup_->vw.GetString(), cup_->vw.GetLength(),

-                                    req.GetString(), req.GetLength(),

-                                    request_buffer_, request_buffer_length_);

-  return S_OK;

-}

-

-HRESULT CupRequestImpl::BuildClientProof() {

-  // Use persisted {sk, c} or start with empty credentials otherwise.

-  ASSERT1(cup_->sk.empty());

-  ASSERT1(cup_->c.IsEmpty());

-  if (!persisted_sk_.empty() && !persisted_c_.IsEmpty()) {

-    cup_->sk = persisted_sk_;

-    cup_->c  = persisted_c_;

-  }

-

-  std::vector<uint8> hcp;   // hmac of the client proof.

-  if (!cup_->sk.empty() && !cup_->c.IsEmpty()) {

-    // Use the cached shared key (sk) and the cookie (c) if we have them.

-    ASSERT1(cup_->sk.size() == SHA_DIGEST_SIZE);

-    NET_LOG(L4, (_T("[using sk: %s]"), BytesToHex(cup_->sk)));

-

-    // Compute 'cp' as SYMsign[sk](0|HASH(w)|HASH(c))

-    std::vector<uint8> hc = cup_utils::Hash(cup_->c);

-    hcp = cup_utils::SymSign(cup_->sk, 0, &cup_->hw, &hc, NULL);

-  } else {

-    // There is no saved shared key. Use current shared key (new_sk).

-    ASSERT1(cup_->new_sk.size() == SHA_DIGEST_SIZE);

-    NET_LOG(L4, (_T("[using sk': %s]"), BytesToHex(cup_->new_sk)));

-

-    // Compute 'cp' as SYMsign[sk'](3|HASH(w))

-    hcp = cup_utils::SymSign(cup_->new_sk, 3, &cup_->hw, NULL, NULL);

-  }

-

-  NET_LOG(L4, (_T("[client proof hmac: %s]"), BytesToHex(hcp)));

-  cup_->cp = cup_utils::B64Encode(hcp);

-  return S_OK;

-}

-

-HRESULT CupRequestImpl::AuthenticateResponse() {

-  // This is what the server has sent down along with the response:

-  // a server proof, and optionally a new cookie for the client.

-  NET_LOG(L4, (_T("[etag:        %s]"), CA2T(cup_->sp)));

-  NET_LOG(L4, (_T("[svr cookie:  %s]"), CA2T(cup_->new_cookie)));

-

-  if (cup_->sp.IsEmpty()) {

-    // We can't authenticate anything without the server proof.

-    return OMAHA_NET_E_CUP_NO_SERVER_PROOF;

-  }

-

-  // Compute the hash of the response (hm).

-  cup_->hm = cup_utils::Hash(cup_->response);

-  NET_LOG(L4, (_T("[hm: %s]"), BytesToHex(cup_->hm)));

-

-  // Verify the response and the challenge w are authenticated by the

-  // client shared key. The validation has at least one subtle aspect: the

-  // client must try two signatures. First, it tries to authenticate using

-  // the new sk and the new cookie. If the response does not authenticate but

-  // the client has an old key, it should try authenticating with the old key.

-  // This second step is important in the case of an attacker or server

-  // misconfiguration where the server is signing with the old key but still

-  // sending a cookie.

-  std::vector<uint8> hmac;

-  if (!cup_->new_cookie.IsEmpty() && !cup_->new_sk.empty()) {

-    // The server has sent down a new cookie because the client proof or the

-    // client cookie were not good or missing. Try to authenticate using the

-    // new shared key and the new cookie {sk', c'}.

-    std::vector<uint8> hnew_c = cup_utils::Hash(cup_->new_cookie);  // HASH(c')

-

-    // Compute the server proof (sp) as SYMsign[sk'](1|hw|hm|hc').

-    hmac = cup_utils::SymSign(cup_->new_sk, 1, &cup_->hw, &cup_->hm, &hnew_c);

-    CStringA expected_sp = cup_utils::B64Encode(hmac);

-

-    if (expected_sp == cup_->sp) {

-      // Copy the credentials to write them back when this object is destroyed.

-      persisted_sk_ = cup_->new_sk;

-      persisted_c_  = cup_->new_cookie;

-      return S_OK;

-    }

-  }

-

-  if (!cup_->sk.empty()) {

-    // The server has accepted our client proof (cp) and consequently the sk.

-

-    // Compute the server proof as SYMsign[sk](2|hw|hm).

-    hmac = cup_utils::SymSign(cup_->sk, 2, &cup_->hw, &cup_->hm, NULL);

-    CStringA expected_sp = cup_utils::B64Encode(hmac);

-

-    if (expected_sp == cup_->sp) {

-      return S_OK;

-    }

-  }

-

-  NET_LOG(L4, (_T("[expected server proof: %s]"), BytesToHex(hmac)));

-

-  // The server proof does not authenticate. We reject this response.

-  return OMAHA_NET_E_CUP_NOT_TRUSTED;

-}

-

-HRESULT CupRequestImpl::LoadCredentials(std::vector<uint8>* sk, CStringA* c) {

-  ASSERT1(sk);

-  ASSERT1(c);

-  NetworkConfig& network_config = NetworkConfig::Instance();

-  CupCredentials cup_credentials;

-  HRESULT hr = network_config.GetCupCredentials(&cup_credentials);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  std::vector<uint8> decrypted_sk;

-  hr = DecryptData(NULL,

-                   0,

-                   &cup_credentials.sk.front(),

-                   cup_credentials.sk.size(),

-                   &decrypted_sk);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  sk->swap(decrypted_sk);

-  c->SetString(cup_credentials.c);

-  return S_OK;

-}

-

-HRESULT CupRequestImpl::SaveCredentials(const std::vector<uint8>& sk,

-                                        const CStringA& c) {

-  // Update the client persistent state if the response has been validated.

-  // The client key is encrypted while on the disk.

-  NetworkConfig& network_config = NetworkConfig::Instance();

-  CupCredentials cup_credentials;

-  cup_credentials.c.SetString(c);

-  HRESULT hr = EncryptData(NULL,

-                           0,

-                           &sk.front(),

-                           sk.size(),

-                           &cup_credentials.sk);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  // Try to persist the new client credentials.

-  hr = network_config.SetCupCredentials(&cup_credentials);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  return S_OK;

-}

-

-HRESULT CupRequestImpl::DoSend() {

-  // The url of the inner request includes the versioned challenge.

-  // It replaces the protocol from https to http since CUP over https is

-  // not supported.

-  http_request_->set_url(BuildInnerRequestUrl(CString(cup_->request_url)));

-

-  // Prepare additional headers to send.

-  CString additional_headers;

-

-  // The client proof (cp) is sent as the "If-Match" header.

-  ASSERT1(!cup_->cp.IsEmpty());

-  CStringA if_match_header;

-  if_match_header.Format("\"%s\"", cup_->cp);

-  additional_headers += HttpClient::BuildRequestHeader(_T("If-Match"),

-                                                       CA2T(if_match_header));

-

-  // Send the client cookie (c) if we have one.

-  if (!cup_->c.IsEmpty()) {

-    additional_headers += HttpClient::BuildRequestHeader(_T("Cookie"),

-                                                         CA2T(cup_->c));

-  }

-  http_request_->set_additional_headers(additional_headers);

-

-  NET_LOG(L5, (_T("[CUP request][%s]"),

-               BufferToPrintableString(request_buffer_,

-                                       request_buffer_length_)));

-  HRESULT hr = http_request_->Send();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  http_request_->GetResponse().swap(cup_->response);

-  int status_code(http_request_->GetHttpStatusCode());

-  if (status_code != HTTP_STATUS_OK) {

-    return HRESULTFromHttpStatusCode(status_code);

-  }

-  NET_LOG(L5, (_T("[CUP response][%s]"),

-               VectorToPrintableString(cup_->response)));

-

-  // Get the server proof (sp).

-  CString etag_header;

-  http_request_->QueryHeadersString(WINHTTP_QUERY_ETAG, NULL, &etag_header);

-  UnenclosePath(&etag_header);   // Remove the quotes.

-  cup_->sp = CT2A(etag_header);

-

-  // Get the client cookie c'. The cookie may or may not be there. If the

-  // server has accepted both client proof (sp) then no

-  // new cookie is sent down. This is an indication for the client to

-  // use its {sk, c} pair.

-  CString set_cookie_header;

-  http_request_->QueryHeadersString(WINHTTP_QUERY_SET_COOKIE,

-                                    NULL, &set_cookie_header);

-

-  // Parse the cookie header to extract c=xxx cookie.

-  cup_->new_cookie = CT2A(cup_utils::ParseCupCookie(set_cookie_header));

-  return S_OK;

-}

-

-HRESULT CupRequestImpl::Cancel() {

-  return http_request_->Cancel();

-}

-

-std::vector<uint8> CupRequestImpl::GetResponse() const {

-  return http_request_->GetResponse();

-}

-

-HRESULT CupRequestImpl::QueryHeadersString(uint32 info_level,

-                                           const TCHAR* name,

-                                           CString* value) const {

-  return http_request_->QueryHeadersString(info_level, name, value);

-}

-

-CString CupRequestImpl::GetResponseHeaders() const {

-  return http_request_->GetResponseHeaders();

-}

-

-int CupRequestImpl::GetHttpStatusCode() const {

-  return http_request_->GetHttpStatusCode();

-}

-

-CString CupRequestImpl::ToString() const {

-  return CString("CUP:") + http_request_->ToString();

-}

-

-void CupRequestImpl::set_session_handle(HINTERNET session_handle) {

-  http_request_->set_session_handle(session_handle);

-}

-

-void CupRequestImpl::set_url(const CString& url) {

-  url_ = CT2A(url, CP_UTF8);

-}

-

-void CupRequestImpl::set_request_buffer(const void* buffer,

-                                        size_t buffer_length) {

-  request_buffer_ = buffer;

-  request_buffer_length_ = buffer_length;

-  http_request_->set_request_buffer(request_buffer_, request_buffer_length_);

-}

-

-void CupRequestImpl::set_network_configuration(const Config& network_config) {

-  http_request_->set_network_configuration(network_config);

-}

-

-void CupRequestImpl::set_filename(const CString& filename) {

-  http_request_->set_filename(filename);

-}

-

-void CupRequestImpl::set_low_priority(bool low_priority) {

-  http_request_->set_low_priority(low_priority);

-}

-

-void CupRequestImpl::set_callback(NetworkRequestCallback* callback) {

-  http_request_->set_callback(callback);

-}

-

-void CupRequestImpl::set_additional_headers(const CString& additional_headers) {

-  http_request_->set_additional_headers(additional_headers);

-}

-

-CString CupRequestImpl::user_agent() const {

-  return http_request_->user_agent();

-}

-

-void CupRequestImpl::set_user_agent(const CString& user_agent) {

-  http_request_->set_user_agent(user_agent);

-}

-

-void CupRequestImpl::SetEntropy(const void* data, size_t data_length) {

-  ASSERT(false, (_T("Do not call from production code")));

-  ASSERT1(data);

-  const uint8* first(static_cast<const uint8*>(data));

-  const uint8* last(first + data_length);

-  std::vector<uint8> new_entropy(first, last);

-  entropy_.swap(new_entropy);

-}

-

-HRESULT CupRequestImpl::InitializeEntropy() {

-  if (entropy_.empty()) {

-    cup_->entropy.resize(rsa_->size() - SHA_DIGEST_SIZE);

-    if (!GenRandom(&cup_->entropy.front(), cup_->entropy.size())) {

-      return OMAHA_NET_E_CUP_NO_ENTROPY;

-    }

-  } else {

-    cup_->entropy = entropy_;

-  }

-  return S_OK;

-}

-

-CString CupRequestImpl::BuildInnerRequestUrl(const CString& url) {

-  CString result(url);

-  if (String_StartsWith(result, kHttpsProtoScheme, true)) {

-    result = url.Mid(_tcslen(kHttpsProtoScheme));

-    result.Insert(0, kHttpProtoScheme);

-  }

-  return result;

-}

-

-}   // namespace detail

-

-

-CupRequest::CupRequest(HttpRequestInterface* http_request) {

-  ASSERT1(http_request);

-  impl_.reset(new detail::CupRequestImpl(http_request));

-}

-

-CupRequest::~CupRequest() {

-}

-

-HRESULT CupRequest::Close() {

-  return impl_->Close();

-}

-

-HRESULT CupRequest::Send() {

-  return impl_->Send();

-}

-

-HRESULT CupRequest::Cancel() {

-  return impl_->Cancel();

-}

-

-std::vector<uint8> CupRequest::GetResponse() const {

-  return impl_->GetResponse();

-}

-

-int CupRequest::GetHttpStatusCode() const {

-  return impl_->GetHttpStatusCode();

-}

-

-HRESULT CupRequest::QueryHeadersString(uint32 info_level,

-                                       const TCHAR* name,

-                                       CString* value) const {

-  return impl_->QueryHeadersString(info_level, name, value);

-}

-

-CString CupRequest::GetResponseHeaders() const {

-  return impl_->GetResponseHeaders();

-}

-

-CString CupRequest::ToString() const {

-  return impl_->ToString();

-}

-

-void CupRequest::set_session_handle(HINTERNET session_handle) {

-  return impl_->set_session_handle(session_handle);

-}

-

-void CupRequest::set_url(const CString& url) {

-  impl_->set_url(url);

-}

-

-void CupRequest::set_request_buffer(const void* buffer, size_t buffer_length) {

-  impl_->set_request_buffer(buffer, buffer_length);

-}

-

-void CupRequest::set_network_configuration(const Config& network_config) {

-  impl_->set_network_configuration(network_config);

-}

-

-void CupRequest::set_filename(const CString& filename) {

-  impl_->set_filename(filename);

-}

-

-void CupRequest::set_low_priority(bool low_priority) {

-  impl_->set_low_priority(low_priority);

-}

-

-void CupRequest::set_callback(NetworkRequestCallback* callback) {

-  impl_->set_callback(callback);

-}

-

-void CupRequest::set_additional_headers(const CString& additional_headers) {

-  impl_->set_additional_headers(additional_headers);

-}

-

-CString CupRequest::user_agent() const {

-  return impl_->user_agent();

-}

-

-void CupRequest::set_user_agent(const CString& user_agent) {

-  impl_->set_user_agent(user_agent);

-}

-

-void CupRequest::SetEntropy(const void* data, size_t data_length) {

-  return impl_->SetEntropy(data, data_length);

-}

-

-}   // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// TODO(omaha): to minimize conversions from UNICODE to UTF-8 consider an
+// API that takes the request body as UTF-8 and it stores it as UTF-8.
+
+#include "omaha/net/cup_request.h"
+
+#include <atlconv.h>
+#include <atlstr.h>
+#include <vector>
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/encrypt.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/security/b64.h"
+#include "omaha/common/security/hmac.h"
+#include "omaha/common/security/rsa.h"
+#include "omaha/common/security/sha.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+#include "omaha/net/cup_utils.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/net_utils.h"
+#include "omaha/net/network_config.h"
+
+using omaha::encrypt::EncryptData;
+using omaha::encrypt::DecryptData;
+
+namespace omaha {
+
+namespace detail {
+
+class CupRequestImpl {
+ public:
+  explicit CupRequestImpl(HttpRequestInterface* http_request);
+  ~CupRequestImpl();
+
+  HRESULT Close();
+  HRESULT Send();
+  HRESULT Cancel();
+  std::vector<uint8> GetResponse() const;
+  HRESULT QueryHeadersString(uint32 info_level,
+                                    const TCHAR* name,
+                                    CString* value) const;
+  CString GetResponseHeaders() const;
+  int GetHttpStatusCode() const;
+  CString ToString() const;
+  void SetEntropy(const void* data, size_t data_length);
+
+  void set_session_handle(HINTERNET session_handle);
+  void set_url(const CString& url);
+  void set_request_buffer(const void* buffer, size_t buffer_length);
+  void set_network_configuration(const Config& network_config);
+  void set_filename(const CString& filename);
+  void set_low_priority(bool low_priority);
+  void set_callback(NetworkRequestCallback* callback);
+  void set_additional_headers(const CString& additional_headers);
+  CString user_agent() const;
+  void set_user_agent(const CString& user_agent);
+
+ private:
+  HRESULT DoSend();
+  HRESULT BuildRequest();
+  HRESULT BuildChallengeHash();
+  HRESULT BuildClientProof();
+  HRESULT InitializeEntropy();
+  HRESULT AuthenticateResponse();
+
+  // Loads the {sk, c} credentials from persistent storage.
+  HRESULT LoadCredentials(std::vector<uint8>* sk, CStringA* c);
+
+  // Saves the {sk, c} credentials. The key is encrypted before saving it.
+  HRESULT SaveCredentials(const std::vector<uint8>& sk, const CStringA& c);
+
+  // Replaces the https protocol scheme with http.
+  CString BuildInnerRequestUrl(const CString& url);
+
+  // The transient state of the request, so that we can start always with a
+  // clean slate even though the same instance is being reuse across requests.
+  struct TransientCupState {
+    std::vector<uint8> entropy;
+    std::vector<uint8> r;         // Random bytes (r).
+    std::vector<uint8> sk;        // Cached shared key (sk)
+    std::vector<uint8> new_sk;    // Current shared_key (sk').
+    std::vector<uint8> hw;        // Challenge hash (hw).
+    std::vector<uint8> hm;        // Response hash (hm).
+
+    CStringA cp;                  // Client proof (cp).
+    CStringA sp;                  // Server proof (sp).
+    CStringA vw;                  // Versioned challenge (v|w).
+    std::vector<uint8> response;  // The received response.
+    CStringA c;                   // Cached client cookie (c)
+    CStringA new_cookie;          // The cookie returned by the server (c').
+
+    // The url of the request. It includes the original url plus the versioned
+    // challenge (v|w).
+    CStringA request_url;
+  };
+  scoped_ptr<TransientCupState> cup_;
+
+  CStringA url_;                        // The original url.
+  const void* request_buffer_;          // Contains the request body for POST.
+  size_t      request_buffer_length_;   // Length of the request body.
+  std::vector<uint8> entropy_;          // Optional entropy pass by the caller,
+                                        // mostly for testing purpose.
+
+  // {sk, c} credentials. They are persisted in the registry when the object is
+  // destroyed. The vast majority of network code runs impersonated. Writing
+  // through the credentials is likely to fail. However, due to how the
+  // CUP object is being used by the upper layers of the network code, a
+  // write back policy is possible.
+  std::vector<uint8> persisted_sk_;
+  CStringA           persisted_c_;
+
+  scoped_ptr<RSA> rsa_;
+  RSA::PublicKey public_key_;                      // Server public key (pk[v]).
+  scoped_ptr<HttpRequestInterface> http_request_;  // Inner http request.
+
+  static const RSA::PublicKeyInstance kCupProductionPublicKey;
+  static const RSA::PublicKeyInstance kCupTestPublicKey;
+
+  DISALLOW_EVIL_CONSTRUCTORS(CupRequestImpl);
+};
+
+const RSA::PublicKeyInstance CupRequestImpl::kCupProductionPublicKey =
+#include "omaha/net/cup_pubkey.3.h"
+;   // NOLINT
+
+const RSA::PublicKeyInstance CupRequestImpl::kCupTestPublicKey =
+#include "omaha/net/cup_pubkey.2.h"
+;   // NOLINT
+
+CupRequestImpl::CupRequestImpl(HttpRequestInterface* http_request)
+    : request_buffer_(NULL),
+      request_buffer_length_(0),
+      public_key_(NULL) {
+  ASSERT1(http_request);
+  bool is_using_cup_test_keys = NetworkConfig::IsUsingCupTestKeys();
+  public_key_ = is_using_cup_test_keys ? kCupTestPublicKey :
+                                         kCupProductionPublicKey;
+
+  // Try to retrieve the credentials if we have any. If we have succeeded, then
+  // we must have a {sk, c} pair. If we have failed, then we will generate
+  // a fresh set of credentials later on.
+  HRESULT hr = LoadCredentials(&persisted_sk_, &persisted_c_);
+  if (FAILED(hr)) {
+    ASSERT1(persisted_sk_.empty());
+    ASSERT1(persisted_c_.IsEmpty());
+  }
+
+  rsa_.reset(new RSA(public_key_));
+  http_request_.reset(http_request);
+
+  // Decorate the user agent by appending the "CUP" suffix. This overrides
+  // the user agent of the inner http request.
+  CString user_agent(http_request_->user_agent());
+  user_agent += _T(";cup");
+  http_request_->set_user_agent(user_agent);
+}
+
+CupRequestImpl::~CupRequestImpl() {
+  Close();
+}
+
+HRESULT CupRequestImpl::Close() {
+  cup_.reset();
+
+  // TODO(omaha): optimize so that if the credentials did not change then
+  // there would be not need to write back.
+  if (!persisted_sk_.empty() && !persisted_c_.IsEmpty()) {
+    VERIFY1(SUCCEEDED(SaveCredentials(persisted_sk_, persisted_c_)));
+  }
+  return http_request_->Close();
+}
+
+HRESULT CupRequestImpl::Send() {
+  // Start with a fresh CUP state. This is important as the client may
+  // reuse the same CUP request for subsequent requests.
+  cup_.reset(new TransientCupState);
+
+  // First, build a request, send it, and then authenticate the response.
+  HRESULT hr = BuildRequest();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  hr = DoSend();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  hr = AuthenticateResponse();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  return S_OK;
+}
+
+HRESULT CupRequestImpl::BuildRequest() {
+  HRESULT hr(InitializeEntropy());
+  if (FAILED(hr)) {
+    return hr;
+  }
+  // Start with some random bytes.
+  cup_->r = cup_utils::RsaPad(rsa_->size(),
+                              &cup_->entropy.front(), cup_->entropy.size());
+
+  // Derive a new shared key (sk') as the hash of the random bytes.
+  // TODO(omaha): consider protecting the key using ::CryptProtectmemory when
+  // not being used.
+  cup_->new_sk = cup_utils::Hash(cup_->r);
+
+  // Compute the challenge (w) by encrypting in place (r) with the server
+  // public key pk[v].
+  size_t encrypted_size = rsa_->raw(&cup_->r.front(), cup_->r.size());
+  ASSERT1(encrypted_size == cup_->r.size());
+
+  // Compute the versioned challenge (v|w) as
+  // decimal-v:base64-encoded-rsa-wrapper.
+  cup_->vw.Format("%d:%s",
+                  rsa_->version(),
+                  cup_utils::B64Encode(&cup_->r.front(), cup_->r.size()));
+
+  // Compute the url of the CUP request.
+  // Append a query string or append to the existing query string if any.
+  const char* format_string = url_.Find('?') != -1 ? "%1&w=%2" : "%1?w=%2";
+  cup_->request_url.FormatMessage(format_string, url_, cup_->vw);
+
+  // Compute the challenge hash (hw) as HASH(HASH(v|w)|HASH(req))
+  hr = BuildChallengeHash();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Compute the client proof as SYMsign[sk](0|hw|HASH(c)) if we have a
+  // {sk, c} pair or as SYMsign[sk'](3|hw) if we do not.
+  hr = BuildClientProof();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  NET_LOG(L4, (_T("[hw: %s]"), BytesToHex(cup_->hw)));
+
+  // This is what the client sends up along with the request: a versioned
+  // challenge, a client proof, and a client cookie if it has one.
+
+  NET_LOG(L4, (_T("[request:     %s]"), CA2T(cup_->request_url)));
+  NET_LOG(L4, (_T("[ifmatch:     %s]"), CA2T(cup_->cp)));
+  NET_LOG(L4, (_T("[cookie:      %s]"), CA2T(cup_->c)));
+
+  return S_OK;
+}
+
+HRESULT CupRequestImpl::BuildChallengeHash() {
+  // The hash of the request if carried through all the cryptographic proofs.
+  // The challenge hash hw is computed as:
+  // HASH(HASH(v|w)|HASH(request_url)|HASH(body)).
+  // For simplicity, the protocol scheme and the port are dropped before
+  // hashing. The hash is computed over the CUP request url, which includes
+  // the versioned hash.
+  scoped_ptr<HttpClient> http_client(CreateHttpClient());
+  if (!http_client.get()) {
+    return OMAHA_NET_E_CUP_NO_HTTP_CLIENT;
+  }
+  HRESULT hr = http_client->Initialize();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(!cup_->request_url.IsEmpty());
+  CString url(cup_->request_url);
+  CString scheme, server, url_path, query_string;
+  hr = http_client->CrackUrl(url,
+                             0,
+                             &scheme,
+                             &server,
+                             NULL,
+                             &url_path,
+                             &query_string);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ASSERT1(!scheme.IsEmpty());
+  ASSERT1(!server.IsEmpty());
+  ASSERT1(!url_path.IsEmpty());
+  url.FormatMessage(_T("//%1%2%3"), server, url_path, query_string);
+
+  CStringA req(url);
+
+  // Compute hw as HASH(HASH(v|w)|HASH(request_url)|HASH(body)).
+  ASSERT1(!cup_->vw.IsEmpty());
+  ASSERT1(!url.IsEmpty());
+  cup_->hw = cup_utils::HashBuffers(cup_->vw.GetString(), cup_->vw.GetLength(),
+                                    req.GetString(), req.GetLength(),
+                                    request_buffer_, request_buffer_length_);
+  return S_OK;
+}
+
+HRESULT CupRequestImpl::BuildClientProof() {
+  // Use persisted {sk, c} or start with empty credentials otherwise.
+  ASSERT1(cup_->sk.empty());
+  ASSERT1(cup_->c.IsEmpty());
+  if (!persisted_sk_.empty() && !persisted_c_.IsEmpty()) {
+    cup_->sk = persisted_sk_;
+    cup_->c  = persisted_c_;
+  }
+
+  std::vector<uint8> hcp;   // hmac of the client proof.
+  if (!cup_->sk.empty() && !cup_->c.IsEmpty()) {
+    // Use the cached shared key (sk) and the cookie (c) if we have them.
+    ASSERT1(cup_->sk.size() == SHA_DIGEST_SIZE);
+    NET_LOG(L4, (_T("[using sk: %s]"), BytesToHex(cup_->sk)));
+
+    // Compute 'cp' as SYMsign[sk](0|HASH(w)|HASH(c))
+    std::vector<uint8> hc = cup_utils::Hash(cup_->c);
+    hcp = cup_utils::SymSign(cup_->sk, 0, &cup_->hw, &hc, NULL);
+  } else {
+    // There is no saved shared key. Use current shared key (new_sk).
+    ASSERT1(cup_->new_sk.size() == SHA_DIGEST_SIZE);
+    NET_LOG(L4, (_T("[using sk': %s]"), BytesToHex(cup_->new_sk)));
+
+    // Compute 'cp' as SYMsign[sk'](3|HASH(w))
+    hcp = cup_utils::SymSign(cup_->new_sk, 3, &cup_->hw, NULL, NULL);
+  }
+
+  NET_LOG(L4, (_T("[client proof hmac: %s]"), BytesToHex(hcp)));
+  cup_->cp = cup_utils::B64Encode(hcp);
+  return S_OK;
+}
+
+HRESULT CupRequestImpl::AuthenticateResponse() {
+  // This is what the server has sent down along with the response:
+  // a server proof, and optionally a new cookie for the client.
+  NET_LOG(L4, (_T("[etag:        %s]"), CA2T(cup_->sp)));
+  NET_LOG(L4, (_T("[svr cookie:  %s]"), CA2T(cup_->new_cookie)));
+
+  if (cup_->sp.IsEmpty()) {
+    // We can't authenticate anything without the server proof.
+    return OMAHA_NET_E_CUP_NO_SERVER_PROOF;
+  }
+
+  // Compute the hash of the response (hm).
+  cup_->hm = cup_utils::Hash(cup_->response);
+  NET_LOG(L4, (_T("[hm: %s]"), BytesToHex(cup_->hm)));
+
+  // Verify the response and the challenge w are authenticated by the
+  // client shared key. The validation has at least one subtle aspect: the
+  // client must try two signatures. First, it tries to authenticate using
+  // the new sk and the new cookie. If the response does not authenticate but
+  // the client has an old key, it should try authenticating with the old key.
+  // This second step is important in the case of an attacker or server
+  // misconfiguration where the server is signing with the old key but still
+  // sending a cookie.
+  std::vector<uint8> hmac;
+  if (!cup_->new_cookie.IsEmpty() && !cup_->new_sk.empty()) {
+    // The server has sent down a new cookie because the client proof or the
+    // client cookie were not good or missing. Try to authenticate using the
+    // new shared key and the new cookie {sk', c'}.
+    std::vector<uint8> hnew_c = cup_utils::Hash(cup_->new_cookie);  // HASH(c')
+
+    // Compute the server proof (sp) as SYMsign[sk'](1|hw|hm|hc').
+    hmac = cup_utils::SymSign(cup_->new_sk, 1, &cup_->hw, &cup_->hm, &hnew_c);
+    CStringA expected_sp = cup_utils::B64Encode(hmac);
+
+    if (expected_sp == cup_->sp) {
+      // Copy the credentials to write them back when this object is destroyed.
+      persisted_sk_ = cup_->new_sk;
+      persisted_c_  = cup_->new_cookie;
+      return S_OK;
+    }
+  }
+
+  if (!cup_->sk.empty()) {
+    // The server has accepted our client proof (cp) and consequently the sk.
+
+    // Compute the server proof as SYMsign[sk](2|hw|hm).
+    hmac = cup_utils::SymSign(cup_->sk, 2, &cup_->hw, &cup_->hm, NULL);
+    CStringA expected_sp = cup_utils::B64Encode(hmac);
+
+    if (expected_sp == cup_->sp) {
+      return S_OK;
+    }
+  }
+
+  NET_LOG(L4, (_T("[expected server proof: %s]"), BytesToHex(hmac)));
+
+  // The server proof does not authenticate. We reject this response.
+  return OMAHA_NET_E_CUP_NOT_TRUSTED;
+}
+
+HRESULT CupRequestImpl::LoadCredentials(std::vector<uint8>* sk, CStringA* c) {
+  ASSERT1(sk);
+  ASSERT1(c);
+  NetworkConfig& network_config = NetworkConfig::Instance();
+  CupCredentials cup_credentials;
+  HRESULT hr = network_config.GetCupCredentials(&cup_credentials);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  std::vector<uint8> decrypted_sk;
+  hr = DecryptData(NULL,
+                   0,
+                   &cup_credentials.sk.front(),
+                   cup_credentials.sk.size(),
+                   &decrypted_sk);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  sk->swap(decrypted_sk);
+  c->SetString(cup_credentials.c);
+  return S_OK;
+}
+
+HRESULT CupRequestImpl::SaveCredentials(const std::vector<uint8>& sk,
+                                        const CStringA& c) {
+  // Update the client persistent state if the response has been validated.
+  // The client key is encrypted while on the disk.
+  NetworkConfig& network_config = NetworkConfig::Instance();
+  CupCredentials cup_credentials;
+  cup_credentials.c.SetString(c);
+  HRESULT hr = EncryptData(NULL,
+                           0,
+                           &sk.front(),
+                           sk.size(),
+                           &cup_credentials.sk);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  // Try to persist the new client credentials.
+  hr = network_config.SetCupCredentials(&cup_credentials);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  return S_OK;
+}
+
+HRESULT CupRequestImpl::DoSend() {
+  // The url of the inner request includes the versioned challenge.
+  // It replaces the protocol from https to http since CUP over https is
+  // not supported.
+  http_request_->set_url(BuildInnerRequestUrl(CString(cup_->request_url)));
+
+  // Prepare additional headers to send.
+  CString additional_headers;
+
+  // The client proof (cp) is sent as the "If-Match" header.
+  ASSERT1(!cup_->cp.IsEmpty());
+  CStringA if_match_header;
+  if_match_header.Format("\"%s\"", cup_->cp);
+  additional_headers += HttpClient::BuildRequestHeader(_T("If-Match"),
+                                                       CA2T(if_match_header));
+
+  // Send the client cookie (c) if we have one.
+  if (!cup_->c.IsEmpty()) {
+    additional_headers += HttpClient::BuildRequestHeader(_T("Cookie"),
+                                                         CA2T(cup_->c));
+  }
+  http_request_->set_additional_headers(additional_headers);
+
+  NET_LOG(L5, (_T("[CUP request][%s]"),
+               BufferToPrintableString(request_buffer_,
+                                       request_buffer_length_)));
+  HRESULT hr = http_request_->Send();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  http_request_->GetResponse().swap(cup_->response);
+  int status_code(http_request_->GetHttpStatusCode());
+  if (status_code != HTTP_STATUS_OK) {
+    return HRESULTFromHttpStatusCode(status_code);
+  }
+  NET_LOG(L5, (_T("[CUP response][%s]"),
+               VectorToPrintableString(cup_->response)));
+
+  // Get the server proof (sp).
+  CString etag_header;
+  http_request_->QueryHeadersString(WINHTTP_QUERY_ETAG, NULL, &etag_header);
+  UnenclosePath(&etag_header);   // Remove the quotes.
+  cup_->sp = CT2A(etag_header);
+
+  // Get the client cookie c'. The cookie may or may not be there. If the
+  // server has accepted both client proof (sp) then no
+  // new cookie is sent down. This is an indication for the client to
+  // use its {sk, c} pair.
+  CString set_cookie_header;
+  http_request_->QueryHeadersString(WINHTTP_QUERY_SET_COOKIE,
+                                    NULL, &set_cookie_header);
+
+  // Parse the cookie header to extract c=xxx cookie.
+  cup_->new_cookie = CT2A(cup_utils::ParseCupCookie(set_cookie_header));
+  return S_OK;
+}
+
+HRESULT CupRequestImpl::Cancel() {
+  return http_request_->Cancel();
+}
+
+std::vector<uint8> CupRequestImpl::GetResponse() const {
+  return http_request_->GetResponse();
+}
+
+HRESULT CupRequestImpl::QueryHeadersString(uint32 info_level,
+                                           const TCHAR* name,
+                                           CString* value) const {
+  return http_request_->QueryHeadersString(info_level, name, value);
+}
+
+CString CupRequestImpl::GetResponseHeaders() const {
+  return http_request_->GetResponseHeaders();
+}
+
+int CupRequestImpl::GetHttpStatusCode() const {
+  return http_request_->GetHttpStatusCode();
+}
+
+CString CupRequestImpl::ToString() const {
+  return CString("CUP:") + http_request_->ToString();
+}
+
+void CupRequestImpl::set_session_handle(HINTERNET session_handle) {
+  http_request_->set_session_handle(session_handle);
+}
+
+void CupRequestImpl::set_url(const CString& url) {
+  url_ = CT2A(url, CP_UTF8);
+}
+
+void CupRequestImpl::set_request_buffer(const void* buffer,
+                                        size_t buffer_length) {
+  request_buffer_ = buffer;
+  request_buffer_length_ = buffer_length;
+  http_request_->set_request_buffer(request_buffer_, request_buffer_length_);
+}
+
+void CupRequestImpl::set_network_configuration(const Config& network_config) {
+  http_request_->set_network_configuration(network_config);
+}
+
+void CupRequestImpl::set_filename(const CString& filename) {
+  http_request_->set_filename(filename);
+}
+
+void CupRequestImpl::set_low_priority(bool low_priority) {
+  http_request_->set_low_priority(low_priority);
+}
+
+void CupRequestImpl::set_callback(NetworkRequestCallback* callback) {
+  http_request_->set_callback(callback);
+}
+
+void CupRequestImpl::set_additional_headers(const CString& additional_headers) {
+  http_request_->set_additional_headers(additional_headers);
+}
+
+CString CupRequestImpl::user_agent() const {
+  return http_request_->user_agent();
+}
+
+void CupRequestImpl::set_user_agent(const CString& user_agent) {
+  http_request_->set_user_agent(user_agent);
+}
+
+void CupRequestImpl::SetEntropy(const void* data, size_t data_length) {
+  ASSERT(false, (_T("Do not call from production code")));
+  ASSERT1(data);
+  const uint8* first(static_cast<const uint8*>(data));
+  const uint8* last(first + data_length);
+  std::vector<uint8> new_entropy(first, last);
+  entropy_.swap(new_entropy);
+}
+
+HRESULT CupRequestImpl::InitializeEntropy() {
+  if (entropy_.empty()) {
+    cup_->entropy.resize(rsa_->size() - SHA_DIGEST_SIZE);
+    if (!GenRandom(&cup_->entropy.front(), cup_->entropy.size())) {
+      return OMAHA_NET_E_CUP_NO_ENTROPY;
+    }
+  } else {
+    cup_->entropy = entropy_;
+  }
+  return S_OK;
+}
+
+CString CupRequestImpl::BuildInnerRequestUrl(const CString& url) {
+  CString result(url);
+  if (String_StartsWith(result, kHttpsProtoScheme, true)) {
+    result = url.Mid(_tcslen(kHttpsProtoScheme));
+    result.Insert(0, kHttpProtoScheme);
+  }
+  return result;
+}
+
+}   // namespace detail
+
+
+CupRequest::CupRequest(HttpRequestInterface* http_request) {
+  ASSERT1(http_request);
+  impl_.reset(new detail::CupRequestImpl(http_request));
+}
+
+CupRequest::~CupRequest() {
+}
+
+HRESULT CupRequest::Close() {
+  return impl_->Close();
+}
+
+HRESULT CupRequest::Send() {
+  return impl_->Send();
+}
+
+HRESULT CupRequest::Cancel() {
+  return impl_->Cancel();
+}
+
+std::vector<uint8> CupRequest::GetResponse() const {
+  return impl_->GetResponse();
+}
+
+int CupRequest::GetHttpStatusCode() const {
+  return impl_->GetHttpStatusCode();
+}
+
+HRESULT CupRequest::QueryHeadersString(uint32 info_level,
+                                       const TCHAR* name,
+                                       CString* value) const {
+  return impl_->QueryHeadersString(info_level, name, value);
+}
+
+CString CupRequest::GetResponseHeaders() const {
+  return impl_->GetResponseHeaders();
+}
+
+CString CupRequest::ToString() const {
+  return impl_->ToString();
+}
+
+void CupRequest::set_session_handle(HINTERNET session_handle) {
+  return impl_->set_session_handle(session_handle);
+}
+
+void CupRequest::set_url(const CString& url) {
+  impl_->set_url(url);
+}
+
+void CupRequest::set_request_buffer(const void* buffer, size_t buffer_length) {
+  impl_->set_request_buffer(buffer, buffer_length);
+}
+
+void CupRequest::set_network_configuration(const Config& network_config) {
+  impl_->set_network_configuration(network_config);
+}
+
+void CupRequest::set_filename(const CString& filename) {
+  impl_->set_filename(filename);
+}
+
+void CupRequest::set_low_priority(bool low_priority) {
+  impl_->set_low_priority(low_priority);
+}
+
+void CupRequest::set_callback(NetworkRequestCallback* callback) {
+  impl_->set_callback(callback);
+}
+
+void CupRequest::set_additional_headers(const CString& additional_headers) {
+  impl_->set_additional_headers(additional_headers);
+}
+
+CString CupRequest::user_agent() const {
+  return impl_->user_agent();
+}
+
+void CupRequest::set_user_agent(const CString& user_agent) {
+  impl_->set_user_agent(user_agent);
+}
+
+void CupRequest::SetEntropy(const void* data, size_t data_length) {
+  return impl_->SetEntropy(data, data_length);
+}
+
+}   // namespace omaha
+
diff --git a/net/cup_request.h b/net/cup_request.h
index cbea994..12686f3 100644
--- a/net/cup_request.h
+++ b/net/cup_request.h
@@ -1,117 +1,117 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// CupRequest provides CUP capabilities for a generic HttpRequestInterface.

-

-#ifndef OMAHA_NET_CUP_REQUEST_H__

-#define OMAHA_NET_CUP_REQUEST_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/net/http_request.h"

-#include "base/scoped_ptr.h"

-

-namespace omaha {

-

-// The cup credentials are persisted across sessions. The sk is encrypted

-// while on the disk so only a user with the same login credentials as

-// the encryptor can decrypt it. The credentials are protected

-// using the system default security, so users can't modify each other's

-// credentials. In case of elevated administrators, the credentials are

-// protected from the non-elevated administrators, so the latter can't

-// read the keys and attack the elevated administrator.

-//

-// Cup credentials can be negotiated using either production keys or

-// test keys. There is a registry value override to specify that test keys

-// be used. For the change to be effective, the old credentials must be cleared.

-struct CupCredentials {

-  std::vector<uint8> sk;             // shared key (sk)

-  CStringA c;                        // client cookie (c)

-};

-

-namespace detail {

-

-// The implementation uses the pimpl idiom or bridge design pattern to

-// encapsulate the cup protocol implementation details from the calling code.

-class CupRequestImpl;

-

-}   // namespace detail

-

-class CupRequest : public HttpRequestInterface {

- public:

-  // Decorates an HttpRequestInterface to provide CUP functionality.

-  // It takes ownership of the object provided as parameter.

-  explicit CupRequest(HttpRequestInterface* http_request);

-

-  virtual ~CupRequest();

-

-  virtual HRESULT Close();

-

-  virtual HRESULT Send();

-

-  virtual HRESULT Cancel();

-

-  virtual std::vector<uint8> GetResponse() const;

-

-  virtual HRESULT QueryHeadersString(uint32 info_level,

-                                     const TCHAR* name,

-                                     CString* value) const;

-  virtual CString GetResponseHeaders() const;

-

-  virtual int GetHttpStatusCode() const;

-

-  virtual CString ToString() const;

-

-  virtual void set_session_handle(HINTERNET session_handle);

-

-  virtual void set_url(const CString& url);

-

-  virtual void set_request_buffer(const void* buffer, size_t buffer_length);

-

-  virtual void set_network_configuration(const Config& network_config);

-

-  // Sets the filename to receive the response instead of the memory buffer.

-  virtual void set_filename(const CString& filename);

-

-  virtual void set_low_priority(bool low_priority);

-

-  virtual void set_callback(NetworkRequestCallback* callback);

-

-  virtual void set_additional_headers(const CString& additional_headers);

-

-  virtual CString user_agent() const;

-

-  virtual void set_user_agent(const CString& user_agent);

-

-  // Sets random bytes provided by the caller. This is useful for testing

-  // purposes and it is not be called by production code.

-  // Otherwise, when entropy is not provided, the implementation

-  // fills in the internal entropy buffer with cryptographically random bytes.

-  // Calling this method can result in compromising the security of the

-  // protocol, depending on the quality of entropy provided.

-  void SetEntropy(const void* data, size_t data_length);

-

- private:

-

-  scoped_ptr<detail::CupRequestImpl> impl_;

-  DISALLOW_EVIL_CONSTRUCTORS(CupRequest);

-};

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_CUP_REQUEST_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// CupRequest provides CUP capabilities for a generic HttpRequestInterface.
+
+#ifndef OMAHA_NET_CUP_REQUEST_H__
+#define OMAHA_NET_CUP_REQUEST_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/net/http_request.h"
+#include "base/scoped_ptr.h"
+
+namespace omaha {
+
+// The cup credentials are persisted across sessions. The sk is encrypted
+// while on the disk so only a user with the same login credentials as
+// the encryptor can decrypt it. The credentials are protected
+// using the system default security, so users can't modify each other's
+// credentials. In case of elevated administrators, the credentials are
+// protected from the non-elevated administrators, so the latter can't
+// read the keys and attack the elevated administrator.
+//
+// Cup credentials can be negotiated using either production keys or
+// test keys. There is a registry value override to specify that test keys
+// be used. For the change to be effective, the old credentials must be cleared.
+struct CupCredentials {
+  std::vector<uint8> sk;             // shared key (sk)
+  CStringA c;                        // client cookie (c)
+};
+
+namespace detail {
+
+// The implementation uses the pimpl idiom or bridge design pattern to
+// encapsulate the cup protocol implementation details from the calling code.
+class CupRequestImpl;
+
+}   // namespace detail
+
+class CupRequest : public HttpRequestInterface {
+ public:
+  // Decorates an HttpRequestInterface to provide CUP functionality.
+  // It takes ownership of the object provided as parameter.
+  explicit CupRequest(HttpRequestInterface* http_request);
+
+  virtual ~CupRequest();
+
+  virtual HRESULT Close();
+
+  virtual HRESULT Send();
+
+  virtual HRESULT Cancel();
+
+  virtual std::vector<uint8> GetResponse() const;
+
+  virtual HRESULT QueryHeadersString(uint32 info_level,
+                                     const TCHAR* name,
+                                     CString* value) const;
+  virtual CString GetResponseHeaders() const;
+
+  virtual int GetHttpStatusCode() const;
+
+  virtual CString ToString() const;
+
+  virtual void set_session_handle(HINTERNET session_handle);
+
+  virtual void set_url(const CString& url);
+
+  virtual void set_request_buffer(const void* buffer, size_t buffer_length);
+
+  virtual void set_network_configuration(const Config& network_config);
+
+  // Sets the filename to receive the response instead of the memory buffer.
+  virtual void set_filename(const CString& filename);
+
+  virtual void set_low_priority(bool low_priority);
+
+  virtual void set_callback(NetworkRequestCallback* callback);
+
+  virtual void set_additional_headers(const CString& additional_headers);
+
+  virtual CString user_agent() const;
+
+  virtual void set_user_agent(const CString& user_agent);
+
+  // Sets random bytes provided by the caller. This is useful for testing
+  // purposes and it is not be called by production code.
+  // Otherwise, when entropy is not provided, the implementation
+  // fills in the internal entropy buffer with cryptographically random bytes.
+  // Calling this method can result in compromising the security of the
+  // protocol, depending on the quality of entropy provided.
+  void SetEntropy(const void* data, size_t data_length);
+
+ private:
+
+  scoped_ptr<detail::CupRequestImpl> impl_;
+  DISALLOW_EVIL_CONSTRUCTORS(CupRequest);
+};
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_CUP_REQUEST_H__
+
diff --git a/net/cup_request_unittest.cc b/net/cup_request_unittest.cc
index 24d50a8..2079f6e 100644
--- a/net/cup_request_unittest.cc
+++ b/net/cup_request_unittest.cc
@@ -1,161 +1,161 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// This unit test is hardcoded to run against production servers only.

-

-#include <iostream>

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/net/browser_request.h"

-#include "omaha/net/cup_request.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/simple_request.h"

-#include "omaha/net/urlmon_request.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-const TCHAR* const kGetUrl =

-    _T("http://tools.google.com/service/update2/id");

-const TCHAR* const kGetUrlNoResponseBody =

-    _T("http://tools.google.com/service/update2/nil");

-const TCHAR* const kPostUrl =

-    _T("http://tools.google.com/service/update2");

-const uint8 kRequestBuffer[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><o:gupdate xmlns:o=\"http://www.google.com/update2/request\" protocol=\"2.0\" version=\"1.2.1.0\" ismachine=\"1\" machineid=\"{00A3CC40-4DA1-405E-BCAD-CE46F7A49A6E}\" userid=\"{C161C6CD-FC1B-43FF-8B33-CAB5EE144664}\" testsource=\"dev\"><o:os platform=\"win\" version=\"5.1\" sp=\"Service Pack 2\"/><o:app appid=\"{52820187-5605-4C18-AA51-8BD0A1209C8C}\" version=\"1.1.1.3\" lang=\"abc\" client=\"{0AF52D61-9958-4fea-9B29-CDD9DCDBB145}\" iid=\"{F723495F-8ACF-4746-8240-643741C797B5}\"><o:event eventtype=\"1\" eventresult=\"1\" errorcode=\"0\" previousversion=\"1.0.0.0\"/></o:app></o:gupdate>";  // NOLINT

-

-class CupRequestTest : public testing::Test {

- protected:

-  CupRequestTest() : are_browser_objects_available(false) {

-    BrowserRequest request;

-    are_browser_objects_available = !request.objects_.empty();

-  }

-

-  static void SetUpTestCase() {

-    NetworkConfig& network_config(NetworkConfig::Instance());

-    network_config.SetCupCredentials(NULL);

-

-    // For debugging purposes, try FF configuration first.

-    network_config.Clear();

-    network_config.Add(new FirefoxProxyDetector());

-    EXPECT_HRESULT_SUCCEEDED(network_config.Detect());

-  }

-

-  static void TearDownTestCase() {

-    NetworkConfig& network_config(NetworkConfig::Instance());

-    network_config.SetCupCredentials(NULL);

-    network_config.Clear();

-  }

-

-  void DoRequest(HttpRequestInterface* contained_request,

-                 const CString& url,

-                 const uint8* request_buffer,

-                 size_t request_buffer_lenght) {

-    scoped_ptr<CupRequest> http_request(new CupRequest(contained_request));

-

-    // This will use Firefox or direct connection if FF is not installed.

-    NetworkConfig& network_config(NetworkConfig::Instance());

-    std::vector<Config> network_configurations(

-        network_config.GetConfigurations());

-    network_configurations.push_back(Config());

-

-    // Clear CUP credentials.

-    network_config.SetCupCredentials(NULL);

-

-    HINTERNET handle = NetworkConfig::Instance().session().session_handle;

-    http_request->set_session_handle(handle);

-    http_request->set_network_configuration(network_configurations[0]);

-    http_request->set_url(url);

-    if (request_buffer) {

-      http_request->set_request_buffer(request_buffer, request_buffer_lenght);

-    }

-

-    // First request goes with a fresh set of client credentials.

-    EXPECT_HRESULT_SUCCEEDED(http_request->Send());

-    EXPECT_EQ(http_request->GetHttpStatusCode(), HTTP_STATUS_OK);

-    std::vector<uint8> response(http_request->GetResponse());

-

-    // Second request goes with cached client credentials.

-    EXPECT_HRESULT_SUCCEEDED(http_request->Send());

-    EXPECT_EQ(http_request->GetHttpStatusCode(), HTTP_STATUS_OK);

-    response = http_request->GetResponse();

-

-    // Check the request has a user agent.

-    CString user_agent;

-    http_request->QueryHeadersString(

-      WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_USER_AGENT,

-      WINHTTP_HEADER_NAME_BY_INDEX,

-      &user_agent);

-    EXPECT_STREQ(http_request->user_agent(), user_agent);

-

-    // After each test run we should have some {sk, c} persisted in the

-    // registry. The CUP credentials are written back when the CUP request

-    // that has created them is destroyed.

-    http_request.reset();

-    CupCredentials cup_creds;

-    EXPECT_HRESULT_SUCCEEDED(network_config.GetCupCredentials(&cup_creds));

-    EXPECT_FALSE(cup_creds.sk.empty());

-    EXPECT_FALSE(cup_creds.c.IsEmpty());

-

-    network_config.SetCupCredentials(NULL);

-    EXPECT_HRESULT_FAILED(network_config.GetCupCredentials(&cup_creds));

-  }

-

-  bool are_browser_objects_available;

-};

-

-TEST_F(CupRequestTest, GetSimpleRequest) {

-  DoRequest(new SimpleRequest, kGetUrl, NULL, 0);

-  DoRequest(new SimpleRequest, kGetUrlNoResponseBody, NULL, 0);

-}

-

-TEST_F(CupRequestTest, GetUrlmonRequest) {

-  DoRequest(new UrlmonRequest, kGetUrl, NULL, 0);

-  DoRequest(new SimpleRequest, kGetUrlNoResponseBody, NULL, 0);

-}

-

-TEST_F(CupRequestTest, GetBrowserRequest) {

-  if (are_browser_objects_available) {

-    DoRequest(new BrowserRequest, kGetUrl, NULL, 0);

-    DoRequest(new SimpleRequest, kGetUrlNoResponseBody, NULL, 0);

-  } else {

-    std::wcout << "\tTest did not run because no browser object was available"

-               << std::endl;

-  }

-}

-

-TEST_F(CupRequestTest, PostSimpleRequest) {

-  DoRequest(new SimpleRequest, kPostUrl,

-            kRequestBuffer, arraysize(kRequestBuffer) - 1);

-}

-

-TEST_F(CupRequestTest, PostUrlmonRequest) {

-  DoRequest(new UrlmonRequest, kPostUrl,

-            kRequestBuffer, arraysize(kRequestBuffer) - 1);

-}

-

-TEST_F(CupRequestTest, PostBrowserRequest) {

-  if (are_browser_objects_available) {

-    DoRequest(new BrowserRequest, kPostUrl,

-              kRequestBuffer, arraysize(kRequestBuffer) - 1);

-  } else {

-    std::wcout << "\tTest did not run because no browser object was available"

-               << std::endl;

-  }

-}

-

-}   // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// This unit test is hardcoded to run against production servers only.
+
+#include <iostream>
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/net/browser_request.h"
+#include "omaha/net/cup_request.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/simple_request.h"
+#include "omaha/net/urlmon_request.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+const TCHAR* const kGetUrl =
+    _T("http://tools.google.com/service/update2/id");
+const TCHAR* const kGetUrlNoResponseBody =
+    _T("http://tools.google.com/service/update2/nil");
+const TCHAR* const kPostUrl =
+    _T("http://tools.google.com/service/update2");
+const uint8 kRequestBuffer[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><o:gupdate xmlns:o=\"http://www.google.com/update2/request\" protocol=\"2.0\" version=\"1.2.1.0\" ismachine=\"1\" machineid=\"{00A3CC40-4DA1-405E-BCAD-CE46F7A49A6E}\" userid=\"{C161C6CD-FC1B-43FF-8B33-CAB5EE144664}\" testsource=\"dev\"><o:os platform=\"win\" version=\"5.1\" sp=\"Service Pack 2\"/><o:app appid=\"{52820187-5605-4C18-AA51-8BD0A1209C8C}\" version=\"1.1.1.3\" lang=\"abc\" client=\"{0AF52D61-9958-4fea-9B29-CDD9DCDBB145}\" iid=\"{F723495F-8ACF-4746-8240-643741C797B5}\"><o:event eventtype=\"1\" eventresult=\"1\" errorcode=\"0\" previousversion=\"1.0.0.0\"/></o:app></o:gupdate>";  // NOLINT
+
+class CupRequestTest : public testing::Test {
+ protected:
+  CupRequestTest() : are_browser_objects_available(false) {
+    BrowserRequest request;
+    are_browser_objects_available = !request.objects_.empty();
+  }
+
+  static void SetUpTestCase() {
+    NetworkConfig& network_config(NetworkConfig::Instance());
+    network_config.SetCupCredentials(NULL);
+
+    // For debugging purposes, try FF configuration first.
+    network_config.Clear();
+    network_config.Add(new FirefoxProxyDetector());
+    EXPECT_HRESULT_SUCCEEDED(network_config.Detect());
+  }
+
+  static void TearDownTestCase() {
+    NetworkConfig& network_config(NetworkConfig::Instance());
+    network_config.SetCupCredentials(NULL);
+    network_config.Clear();
+  }
+
+  void DoRequest(HttpRequestInterface* contained_request,
+                 const CString& url,
+                 const uint8* request_buffer,
+                 size_t request_buffer_lenght) {
+    scoped_ptr<CupRequest> http_request(new CupRequest(contained_request));
+
+    // This will use Firefox or direct connection if FF is not installed.
+    NetworkConfig& network_config(NetworkConfig::Instance());
+    std::vector<Config> network_configurations(
+        network_config.GetConfigurations());
+    network_configurations.push_back(Config());
+
+    // Clear CUP credentials.
+    network_config.SetCupCredentials(NULL);
+
+    HINTERNET handle = NetworkConfig::Instance().session().session_handle;
+    http_request->set_session_handle(handle);
+    http_request->set_network_configuration(network_configurations[0]);
+    http_request->set_url(url);
+    if (request_buffer) {
+      http_request->set_request_buffer(request_buffer, request_buffer_lenght);
+    }
+
+    // First request goes with a fresh set of client credentials.
+    EXPECT_HRESULT_SUCCEEDED(http_request->Send());
+    EXPECT_EQ(http_request->GetHttpStatusCode(), HTTP_STATUS_OK);
+    std::vector<uint8> response(http_request->GetResponse());
+
+    // Second request goes with cached client credentials.
+    EXPECT_HRESULT_SUCCEEDED(http_request->Send());
+    EXPECT_EQ(http_request->GetHttpStatusCode(), HTTP_STATUS_OK);
+    response = http_request->GetResponse();
+
+    // Check the request has a user agent.
+    CString user_agent;
+    http_request->QueryHeadersString(
+      WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_USER_AGENT,
+      WINHTTP_HEADER_NAME_BY_INDEX,
+      &user_agent);
+    EXPECT_STREQ(http_request->user_agent(), user_agent);
+
+    // After each test run we should have some {sk, c} persisted in the
+    // registry. The CUP credentials are written back when the CUP request
+    // that has created them is destroyed.
+    http_request.reset();
+    CupCredentials cup_creds;
+    EXPECT_HRESULT_SUCCEEDED(network_config.GetCupCredentials(&cup_creds));
+    EXPECT_FALSE(cup_creds.sk.empty());
+    EXPECT_FALSE(cup_creds.c.IsEmpty());
+
+    network_config.SetCupCredentials(NULL);
+    EXPECT_HRESULT_FAILED(network_config.GetCupCredentials(&cup_creds));
+  }
+
+  bool are_browser_objects_available;
+};
+
+TEST_F(CupRequestTest, GetSimpleRequest) {
+  DoRequest(new SimpleRequest, kGetUrl, NULL, 0);
+  DoRequest(new SimpleRequest, kGetUrlNoResponseBody, NULL, 0);
+}
+
+TEST_F(CupRequestTest, GetUrlmonRequest) {
+  DoRequest(new UrlmonRequest, kGetUrl, NULL, 0);
+  DoRequest(new SimpleRequest, kGetUrlNoResponseBody, NULL, 0);
+}
+
+TEST_F(CupRequestTest, GetBrowserRequest) {
+  if (are_browser_objects_available) {
+    DoRequest(new BrowserRequest, kGetUrl, NULL, 0);
+    DoRequest(new SimpleRequest, kGetUrlNoResponseBody, NULL, 0);
+  } else {
+    std::wcout << "\tTest did not run because no browser object was available"
+               << std::endl;
+  }
+}
+
+TEST_F(CupRequestTest, PostSimpleRequest) {
+  DoRequest(new SimpleRequest, kPostUrl,
+            kRequestBuffer, arraysize(kRequestBuffer) - 1);
+}
+
+TEST_F(CupRequestTest, PostUrlmonRequest) {
+  DoRequest(new UrlmonRequest, kPostUrl,
+            kRequestBuffer, arraysize(kRequestBuffer) - 1);
+}
+
+TEST_F(CupRequestTest, PostBrowserRequest) {
+  if (are_browser_objects_available) {
+    DoRequest(new BrowserRequest, kPostUrl,
+              kRequestBuffer, arraysize(kRequestBuffer) - 1);
+  } else {
+    std::wcout << "\tTest did not run because no browser object was available"
+               << std::endl;
+  }
+}
+
+}   // namespace omaha
+
diff --git a/net/cup_utils.cc b/net/cup_utils.cc
index 8a58751..283d1d6 100644
--- a/net/cup_utils.cc
+++ b/net/cup_utils.cc
@@ -1,145 +1,145 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/net/cup_utils.h"

-

-#include <algorithm>

-#include <vector>

-#include "omaha/common/debug.h"

-#include "omaha/common/security/b64.h"

-#include "omaha/common/security/hmac.h"

-#include "omaha/common/security/sha.h"

-

-namespace omaha {

-

-namespace cup_utils {

-

-std::vector<uint8> RsaPad(size_t rsa_key_size,

-                          const void* data, size_t data_length) {

-  ASSERT1(rsa_key_size >= SHA_DIGEST_SIZE);

-  ASSERT1(data);

-

-  // The result gets padded with zeros if the result size is greater than

-  // the size of the buffer provided by the caller.

-  const uint8* start = static_cast<const uint8*>(data);

-  std::vector<uint8> result(start, start + data_length);

-  result.resize(rsa_key_size - SHA_DIGEST_SIZE);

-

-  // The input needs to be smaller than the RSA modulus, which has always the

-  // msb set.

-  result[0] &= 127;  // Reset msb

-  result[0] |= 64;   // Set second highest bit.

-

-  uint8 digest[SHA_DIGEST_SIZE] = {0};

-  SHA(&result.front(), result.size(), digest);

-

-  result.insert(result.end(), digest, digest + SHA_DIGEST_SIZE);

-  ASSERT1(result.size() == rsa_key_size);

-  return result;

-}

-

-CStringA B64Encode(const void* data, size_t data_length) {

-  ASSERT1(data);

-

-  // After encoding the size grows a little bit, about 133%. We assume 150%

-  // bigger size for simplicity. Also, the output length is a multiple of

-  // 4 bytes, so the minimum buffer should be at least 5 chars to include

-  // space for the string terminator.

-  CStringA result;

-  const size_t kMinBuffer = 5;

-  int result_max_size = std::max(data_length * 3 / 2, kMinBuffer);

-  int result_size = B64_encode(static_cast<const uint8*>(data),

-                               data_length,

-                               CStrBufA(result, result_max_size),

-                               result_max_size);

-  ASSERT1(result_size == result.GetLength());

-  return result;

-}

-

-CStringA B64Encode(const std::vector<uint8>& data) {

-  return B64Encode(&data.front(), data.size());

-}

-

-std::vector<uint8> Hash(const std::vector<uint8>& data) {

-  std::vector<uint8>result(SHA_DIGEST_SIZE);

-  SHA(data.empty() ? NULL : &data.front(), data.size(), &result.front());

-  return result;

-}

-

-std::vector<uint8> Hash(const CStringA& data) {

-  std::vector<uint8>result(SHA_DIGEST_SIZE);

-  SHA(data.GetString(), data.GetLength(), &result.front());

-  return result;

-}

-

-std::vector<uint8> HashBuffers(const void* buf1, size_t len1,

-                               const void* buf2, size_t len2,

-                               const void* buf3, size_t len3) {

-  SHA_CTX sha_ctx = {0};

-  SHA_init(&sha_ctx);

-  const void* buffers[] = {buf1, buf2, buf3};

-  const size_t lengths[] = {len1, len2, len3};

-  for (size_t i = 0; i != arraysize(buffers); ++i) {

-    uint8 hash[SHA_DIGEST_SIZE] = {0};

-    SHA(buffers[i], lengths[i], hash);

-    SHA_update(&sha_ctx, hash, sizeof(hash));

-  }

-  std::vector<uint8> result(SHA_DIGEST_SIZE);

-  memcpy(&result.front(), SHA_final(&sha_ctx), result.size());

-  return result;

-}

-

-std::vector<uint8> SymSign(const std::vector<uint8>& key,

-                           uint8 id,

-                           const std::vector<uint8>* h1,

-                           const std::vector<uint8>* h2,

-                           const std::vector<uint8>* h3) {

-  HMAC_CTX hmac_ctx = {0};

-  HMAC_SHA_init(&hmac_ctx, &key.front(), key.size());

-  HMAC_update(&hmac_ctx, &id, sizeof(id));

-  const std::vector<uint8>* args[] = {h1, h2, h3};

-  for (size_t i = 0; i != arraysize(args); ++i) {

-    if (args[i]) {

-      ASSERT1(args[i]->size() == SHA_DIGEST_SIZE);

-      HMAC_update(&hmac_ctx, &args[i]->front(), args[i]->size());

-    }

-  }

-  std::vector<uint8> result(SHA_DIGEST_SIZE);

-  memcpy(&result.front(), HMAC_final(&hmac_ctx), result.size());

-  return result;

-}

-

-// Looks for "c=", extracts a substring up to ';', which is the attribute

-// delimiter, and trims the white spaces at the end. If found, it returns

-// the string corresponding to "c=xxx", otherwise it returns an empty string.

-CString ParseCupCookie(const CString& cookie_header) {

-  CString cookie;

-  int start = cookie_header.Find(_T("c="));

-  if (start != -1) {

-    int end = cookie_header.Find(_T(';'), start);

-    if (end != -1) {

-      cookie = cookie_header.Mid(start, end - start);

-    } else {

-      cookie = cookie_header.Mid(start);

-    }

-    cookie.TrimRight(_T(' '));

-  }

-  return cookie;

-}

-

-}  // namespace cup_utils

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/net/cup_utils.h"
+
+#include <algorithm>
+#include <vector>
+#include "omaha/common/debug.h"
+#include "omaha/common/security/b64.h"
+#include "omaha/common/security/hmac.h"
+#include "omaha/common/security/sha.h"
+
+namespace omaha {
+
+namespace cup_utils {
+
+std::vector<uint8> RsaPad(size_t rsa_key_size,
+                          const void* data, size_t data_length) {
+  ASSERT1(rsa_key_size >= SHA_DIGEST_SIZE);
+  ASSERT1(data);
+
+  // The result gets padded with zeros if the result size is greater than
+  // the size of the buffer provided by the caller.
+  const uint8* start = static_cast<const uint8*>(data);
+  std::vector<uint8> result(start, start + data_length);
+  result.resize(rsa_key_size - SHA_DIGEST_SIZE);
+
+  // The input needs to be smaller than the RSA modulus, which has always the
+  // msb set.
+  result[0] &= 127;  // Reset msb
+  result[0] |= 64;   // Set second highest bit.
+
+  uint8 digest[SHA_DIGEST_SIZE] = {0};
+  SHA(&result.front(), result.size(), digest);
+
+  result.insert(result.end(), digest, digest + SHA_DIGEST_SIZE);
+  ASSERT1(result.size() == rsa_key_size);
+  return result;
+}
+
+CStringA B64Encode(const void* data, size_t data_length) {
+  ASSERT1(data);
+
+  // After encoding the size grows a little bit, about 133%. We assume 150%
+  // bigger size for simplicity. Also, the output length is a multiple of
+  // 4 bytes, so the minimum buffer should be at least 5 chars to include
+  // space for the string terminator.
+  CStringA result;
+  const size_t kMinBuffer = 5;
+  int result_max_size = std::max(data_length * 3 / 2, kMinBuffer);
+  int result_size = B64_encode(static_cast<const uint8*>(data),
+                               data_length,
+                               CStrBufA(result, result_max_size),
+                               result_max_size);
+  ASSERT1(result_size == result.GetLength());
+  return result;
+}
+
+CStringA B64Encode(const std::vector<uint8>& data) {
+  return B64Encode(&data.front(), data.size());
+}
+
+std::vector<uint8> Hash(const std::vector<uint8>& data) {
+  std::vector<uint8>result(SHA_DIGEST_SIZE);
+  SHA(data.empty() ? NULL : &data.front(), data.size(), &result.front());
+  return result;
+}
+
+std::vector<uint8> Hash(const CStringA& data) {
+  std::vector<uint8>result(SHA_DIGEST_SIZE);
+  SHA(data.GetString(), data.GetLength(), &result.front());
+  return result;
+}
+
+std::vector<uint8> HashBuffers(const void* buf1, size_t len1,
+                               const void* buf2, size_t len2,
+                               const void* buf3, size_t len3) {
+  SHA_CTX sha_ctx = {0};
+  SHA_init(&sha_ctx);
+  const void* buffers[] = {buf1, buf2, buf3};
+  const size_t lengths[] = {len1, len2, len3};
+  for (size_t i = 0; i != arraysize(buffers); ++i) {
+    uint8 hash[SHA_DIGEST_SIZE] = {0};
+    SHA(buffers[i], lengths[i], hash);
+    SHA_update(&sha_ctx, hash, sizeof(hash));
+  }
+  std::vector<uint8> result(SHA_DIGEST_SIZE);
+  memcpy(&result.front(), SHA_final(&sha_ctx), result.size());
+  return result;
+}
+
+std::vector<uint8> SymSign(const std::vector<uint8>& key,
+                           uint8 id,
+                           const std::vector<uint8>* h1,
+                           const std::vector<uint8>* h2,
+                           const std::vector<uint8>* h3) {
+  HMAC_CTX hmac_ctx = {0};
+  HMAC_SHA_init(&hmac_ctx, &key.front(), key.size());
+  HMAC_update(&hmac_ctx, &id, sizeof(id));
+  const std::vector<uint8>* args[] = {h1, h2, h3};
+  for (size_t i = 0; i != arraysize(args); ++i) {
+    if (args[i]) {
+      ASSERT1(args[i]->size() == SHA_DIGEST_SIZE);
+      HMAC_update(&hmac_ctx, &args[i]->front(), args[i]->size());
+    }
+  }
+  std::vector<uint8> result(SHA_DIGEST_SIZE);
+  memcpy(&result.front(), HMAC_final(&hmac_ctx), result.size());
+  return result;
+}
+
+// Looks for "c=", extracts a substring up to ';', which is the attribute
+// delimiter, and trims the white spaces at the end. If found, it returns
+// the string corresponding to "c=xxx", otherwise it returns an empty string.
+CString ParseCupCookie(const CString& cookie_header) {
+  CString cookie;
+  int start = cookie_header.Find(_T("c="));
+  if (start != -1) {
+    int end = cookie_header.Find(_T(';'), start);
+    if (end != -1) {
+      cookie = cookie_header.Mid(start, end - start);
+    } else {
+      cookie = cookie_header.Mid(start);
+    }
+    cookie.TrimRight(_T(' '));
+  }
+  return cookie;
+}
+
+}  // namespace cup_utils
+
+}  // namespace omaha
+
diff --git a/net/cup_utils.h b/net/cup_utils.h
index 4daf3f6..8ea9e2f 100644
--- a/net/cup_utils.h
+++ b/net/cup_utils.h
@@ -1,69 +1,69 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_NET_CUP_UTILS_H__

-#define OMAHA_NET_CUP_UTILS_H__

-

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-namespace cup_utils {

-

-// Takes up to (rsa_key_size - SHA_DIGEST_SIZE) from the caller provided

-// input, and creates a padded result (data | SHA1(data)), where the msb

-// is keybits-160 and the lsb is 160 SHA1 bits. If less input is provided

-// the function pads the input with zeros.

-std::vector<uint8> RsaPad(size_t rsa_key_size,

-                          const void* data, size_t data_length);

-

-// Encodes a buffer of bytes as B64. This encoder has a few differences from

-// the standard: it uses a different char set that is http friendly and it does

-// not pad the output with '='.

-CStringA B64Encode(const void* data, size_t data_length);

-

-// Encodes a vector of bytes as web safe B64.

-CStringA B64Encode(const std::vector<uint8>& data);

-

-// Computes the SHA hash of a vector of bytes: HASH(data).

-std::vector<uint8> Hash(const std::vector<uint8>& data);

-

-// Computes the SHA hash of a CStringA: HASH(data).

-std::vector<uint8> Hash(const CStringA& data);

-

-// Computes the SHA hash of buffers: HASH(HASH(buf1)|HASH(buf2)|HASH(buf3)).

-std::vector<uint8> HashBuffers(const void* buf1, size_t len1,

-                               const void* buf2, size_t len2,

-                               const void* buf3, size_t len3);

-

-// Computes the HMAC of hashes: SYMSign[key](id|h1|h2|h3)

-// NULL arguments are not included in the signature computation.

-std::vector<uint8> SymSign(const std::vector<uint8>& key,

-                           uint8 id,

-                           const std::vector<uint8>* h1,

-                           const std::vector<uint8>* h2,

-                           const std::vector<uint8>* h3);

-

-// Parses out the c=xxx; from the cookie header.

-CString ParseCupCookie(const CString& cookie_header);

-

-}  // namespace cup_utils

-

-}  // namespace omaha

-

-#endif  // OMAHA_NET_CUP_UTILS_H__

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_NET_CUP_UTILS_H__
+#define OMAHA_NET_CUP_UTILS_H__
+
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+namespace cup_utils {
+
+// Takes up to (rsa_key_size - SHA_DIGEST_SIZE) from the caller provided
+// input, and creates a padded result (data | SHA1(data)), where the msb
+// is keybits-160 and the lsb is 160 SHA1 bits. If less input is provided
+// the function pads the input with zeros.
+std::vector<uint8> RsaPad(size_t rsa_key_size,
+                          const void* data, size_t data_length);
+
+// Encodes a buffer of bytes as B64. This encoder has a few differences from
+// the standard: it uses a different char set that is http friendly and it does
+// not pad the output with '='.
+CStringA B64Encode(const void* data, size_t data_length);
+
+// Encodes a vector of bytes as web safe B64.
+CStringA B64Encode(const std::vector<uint8>& data);
+
+// Computes the SHA hash of a vector of bytes: HASH(data).
+std::vector<uint8> Hash(const std::vector<uint8>& data);
+
+// Computes the SHA hash of a CStringA: HASH(data).
+std::vector<uint8> Hash(const CStringA& data);
+
+// Computes the SHA hash of buffers: HASH(HASH(buf1)|HASH(buf2)|HASH(buf3)).
+std::vector<uint8> HashBuffers(const void* buf1, size_t len1,
+                               const void* buf2, size_t len2,
+                               const void* buf3, size_t len3);
+
+// Computes the HMAC of hashes: SYMSign[key](id|h1|h2|h3)
+// NULL arguments are not included in the signature computation.
+std::vector<uint8> SymSign(const std::vector<uint8>& key,
+                           uint8 id,
+                           const std::vector<uint8>* h1,
+                           const std::vector<uint8>* h2,
+                           const std::vector<uint8>* h3);
+
+// Parses out the c=xxx; from the cookie header.
+CString ParseCupCookie(const CString& cookie_header);
+
+}  // namespace cup_utils
+
+}  // namespace omaha
+
+#endif  // OMAHA_NET_CUP_UTILS_H__
diff --git a/net/cup_utils_unittest.cc b/net/cup_utils_unittest.cc
index 9ba56e9..cead7ff 100644
--- a/net/cup_utils_unittest.cc
+++ b/net/cup_utils_unittest.cc
@@ -1,161 +1,161 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <cstring>

-#include <vector>

-#include "omaha/common/security/sha.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-#include "omaha/net/cup_utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace cup_utils {

-

-namespace {

-

-const char kPlainText[] = "The quick brown fox jumps over the lazy dog";

-const int kRsaKeySize = 128;         // 128 bytes.

-

-// Test padding for a random message of num_bytes length.

-void TestPadding(size_t num_bytes) {

-  std::vector<uint8> data(num_bytes);

-  EXPECT_TRUE(GenRandom(&data.front(), data.size()));

-  std::vector<uint8> m = RsaPad(kRsaKeySize, &data.front(), data.size());

-  EXPECT_EQ(m.size(), kRsaKeySize);

-

-  uint8 hash[SHA_DIGEST_SIZE] = {0};

-  SHA(&m.front(), m.size() - SHA_DIGEST_SIZE, hash);

-  EXPECT_EQ(memcmp(hash, &m[kRsaKeySize - SHA_DIGEST_SIZE], sizeof(hash)), 0);

-

-  EXPECT_FALSE(m[0] & 0x80);    // msb is always reset.

-  EXPECT_TRUE(m[0] & 0x60);     // bit next to msb is always set.

-}

-

-}  // namespace

-

-

-TEST(CupUtilsTest, RsaPad) {

-  EXPECT_GE(kRsaKeySize, SHA_DIGEST_SIZE);

-

-  TestPadding(1);                 // 1 byte.

-  TestPadding(SHA_DIGEST_SIZE);   // 20 bytes.

-  TestPadding(kRsaKeySize);       // 128 bytes.

-  TestPadding(1000);              // 1000 bytes.

-}

-

-// The underlying B64_encode function in common/security does not pad

-// with '='.

-TEST(CupUtilsTest, B64Encode) {

-  const char* bytes = "1";

-  EXPECT_STREQ(B64Encode(bytes, strlen(bytes)), "MQ");

-  bytes = "12";

-  EXPECT_STREQ(B64Encode(bytes, strlen(bytes)), "MTI");

-  bytes = "123";

-  EXPECT_STREQ(B64Encode(bytes, strlen(bytes)), "MTIz");

-  bytes = "Google Inc";

-  EXPECT_STREQ(B64Encode(bytes, strlen(bytes)), "R29vZ2xlIEluYw");

-

-  const uint8* first = reinterpret_cast<const uint8*>(bytes);

-  const uint8* last = first + strlen(bytes);

-  EXPECT_STREQ(B64Encode(std::vector<uint8>(first, last)), "R29vZ2xlIEluYw");

-}

-

-TEST(CupUtilsTest, Hash) {

-  // Empty vector.

-  std::vector<uint8> data;

-  std::vector<uint8> hash = Hash(data);

-  EXPECT_STREQ(BytesToHex(hash),

-               _T("da39a3ee5e6b4b0d3255bfef95601890afd80709"));

-

-  // Non-empty vector.

-  const uint8* first = reinterpret_cast<const uint8*>(kPlainText);

-  const uint8* last  = first + strlen(kPlainText);

-  data.clear();

-  data.insert(data.begin(), first, last);

-  hash = Hash(data);

-  EXPECT_STREQ(BytesToHex(hash),

-               _T("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"));

-

-  // Empty CString.

-  hash = Hash(CStringA());

-  EXPECT_STREQ(BytesToHex(hash),

-               _T("da39a3ee5e6b4b0d3255bfef95601890afd80709"));

-

-  // Non-empty CString.

-  hash = Hash(CStringA(kPlainText));

-  EXPECT_STREQ(BytesToHex(hash),

-               _T("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"));

-

-  // Hash of strings

-  CStringA arg(kPlainText);

-  hash = HashBuffers(arg.GetString(), arg.GetLength(), NULL, 0, NULL, 0);

-  EXPECT_STREQ(BytesToHex(hash),

-               _T("64eb91d899d68d2af394fbfe8f7c3b2884055ddb"));

-

-  hash = HashBuffers(NULL, 0, arg.GetString(), arg.GetLength(), NULL, 0);

-  EXPECT_STREQ(BytesToHex(hash),

-               _T("6c9f398d556ffe64fe441ca5491e25fd67d2ab65"));

-

-  hash = HashBuffers(NULL, 0, NULL, 0, arg.GetString(), arg.GetLength());

-  EXPECT_STREQ(BytesToHex(hash),

-               _T("9a7e591318dc169fc023414d8d25321bcb11121e"));

-

-  hash = HashBuffers(NULL, 0, NULL, 0, NULL, 0);

-  EXPECT_STREQ(BytesToHex(hash),

-               _T("d0dc1cf9bf61884f8e7982e0b1b87954bd9ee9c7"));

-}

-

-TEST(CupUtilsTest, SymSign) {

-  // Sign of vectors: ignore NULL vectors.

-  std::vector<uint8> key;  // This is the signing key.

-  key.push_back(7);

-

-  CStringA arg(kPlainText);

-  std::vector<uint8> hash = Hash(arg);

-  std::vector<uint8> sym_sign = SymSign(key, 1, &hash, NULL, NULL);

-  EXPECT_STREQ(BytesToHex(sym_sign),

-               _T("1c6fa359c0a7b11421ae4d31a92f9de8a4ef8d2d"));

-

-  sym_sign = SymSign(key, 1, NULL, &hash, NULL);

-  EXPECT_STREQ(BytesToHex(sym_sign),

-               _T("1c6fa359c0a7b11421ae4d31a92f9de8a4ef8d2d"));

-

-  sym_sign = SymSign(key, 1, NULL, NULL, &hash);

-  EXPECT_STREQ(BytesToHex(sym_sign),

-               _T("1c6fa359c0a7b11421ae4d31a92f9de8a4ef8d2d"));

-

-  sym_sign = SymSign(key, 1, &hash, &hash, &hash);

-    EXPECT_STREQ(BytesToHex(sym_sign),

-                 _T("fef3e343795946cd47ff4e07eca5f3f09b051d86"));

-}

-

-TEST(CupUtilsTest, ParseCupCookie) {

-  EXPECT_STREQ(_T(""), ParseCupCookie(_T("")));

-  EXPECT_STREQ(_T(""), ParseCupCookie(_T("foo; bar;")));

-  EXPECT_STREQ(_T("c="), ParseCupCookie(_T("c=")));

-  EXPECT_STREQ(_T("c="), ParseCupCookie(_T("c= ;")));

-  EXPECT_STREQ(_T("c=foo"), ParseCupCookie(_T("c=foo")));

-  EXPECT_STREQ(_T("c=foo"), ParseCupCookie(_T(";c=foo")));

-  EXPECT_STREQ(_T("c=foo"), ParseCupCookie(_T("c=foo ; bar;")));

-  EXPECT_STREQ(_T("c=foo"), ParseCupCookie(_T("b=bar; c=foo;")));

-  EXPECT_STREQ(_T("c=foo"), ParseCupCookie(_T("b=bar; c=foo ; foobar")));

-}

-

-}  // namespace cup_utils

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <cstring>
+#include <vector>
+#include "omaha/common/security/sha.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+#include "omaha/net/cup_utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace cup_utils {
+
+namespace {
+
+const char kPlainText[] = "The quick brown fox jumps over the lazy dog";
+const int kRsaKeySize = 128;         // 128 bytes.
+
+// Test padding for a random message of num_bytes length.
+void TestPadding(size_t num_bytes) {
+  std::vector<uint8> data(num_bytes);
+  EXPECT_TRUE(GenRandom(&data.front(), data.size()));
+  std::vector<uint8> m = RsaPad(kRsaKeySize, &data.front(), data.size());
+  EXPECT_EQ(m.size(), kRsaKeySize);
+
+  uint8 hash[SHA_DIGEST_SIZE] = {0};
+  SHA(&m.front(), m.size() - SHA_DIGEST_SIZE, hash);
+  EXPECT_EQ(memcmp(hash, &m[kRsaKeySize - SHA_DIGEST_SIZE], sizeof(hash)), 0);
+
+  EXPECT_FALSE(m[0] & 0x80);    // msb is always reset.
+  EXPECT_TRUE(m[0] & 0x60);     // bit next to msb is always set.
+}
+
+}  // namespace
+
+
+TEST(CupUtilsTest, RsaPad) {
+  EXPECT_GE(kRsaKeySize, SHA_DIGEST_SIZE);
+
+  TestPadding(1);                 // 1 byte.
+  TestPadding(SHA_DIGEST_SIZE);   // 20 bytes.
+  TestPadding(kRsaKeySize);       // 128 bytes.
+  TestPadding(1000);              // 1000 bytes.
+}
+
+// The underlying B64_encode function in common/security does not pad
+// with '='.
+TEST(CupUtilsTest, B64Encode) {
+  const char* bytes = "1";
+  EXPECT_STREQ(B64Encode(bytes, strlen(bytes)), "MQ");
+  bytes = "12";
+  EXPECT_STREQ(B64Encode(bytes, strlen(bytes)), "MTI");
+  bytes = "123";
+  EXPECT_STREQ(B64Encode(bytes, strlen(bytes)), "MTIz");
+  bytes = "Google Inc";
+  EXPECT_STREQ(B64Encode(bytes, strlen(bytes)), "R29vZ2xlIEluYw");
+
+  const uint8* first = reinterpret_cast<const uint8*>(bytes);
+  const uint8* last = first + strlen(bytes);
+  EXPECT_STREQ(B64Encode(std::vector<uint8>(first, last)), "R29vZ2xlIEluYw");
+}
+
+TEST(CupUtilsTest, Hash) {
+  // Empty vector.
+  std::vector<uint8> data;
+  std::vector<uint8> hash = Hash(data);
+  EXPECT_STREQ(BytesToHex(hash),
+               _T("da39a3ee5e6b4b0d3255bfef95601890afd80709"));
+
+  // Non-empty vector.
+  const uint8* first = reinterpret_cast<const uint8*>(kPlainText);
+  const uint8* last  = first + strlen(kPlainText);
+  data.clear();
+  data.insert(data.begin(), first, last);
+  hash = Hash(data);
+  EXPECT_STREQ(BytesToHex(hash),
+               _T("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"));
+
+  // Empty CString.
+  hash = Hash(CStringA());
+  EXPECT_STREQ(BytesToHex(hash),
+               _T("da39a3ee5e6b4b0d3255bfef95601890afd80709"));
+
+  // Non-empty CString.
+  hash = Hash(CStringA(kPlainText));
+  EXPECT_STREQ(BytesToHex(hash),
+               _T("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"));
+
+  // Hash of strings
+  CStringA arg(kPlainText);
+  hash = HashBuffers(arg.GetString(), arg.GetLength(), NULL, 0, NULL, 0);
+  EXPECT_STREQ(BytesToHex(hash),
+               _T("64eb91d899d68d2af394fbfe8f7c3b2884055ddb"));
+
+  hash = HashBuffers(NULL, 0, arg.GetString(), arg.GetLength(), NULL, 0);
+  EXPECT_STREQ(BytesToHex(hash),
+               _T("6c9f398d556ffe64fe441ca5491e25fd67d2ab65"));
+
+  hash = HashBuffers(NULL, 0, NULL, 0, arg.GetString(), arg.GetLength());
+  EXPECT_STREQ(BytesToHex(hash),
+               _T("9a7e591318dc169fc023414d8d25321bcb11121e"));
+
+  hash = HashBuffers(NULL, 0, NULL, 0, NULL, 0);
+  EXPECT_STREQ(BytesToHex(hash),
+               _T("d0dc1cf9bf61884f8e7982e0b1b87954bd9ee9c7"));
+}
+
+TEST(CupUtilsTest, SymSign) {
+  // Sign of vectors: ignore NULL vectors.
+  std::vector<uint8> key;  // This is the signing key.
+  key.push_back(7);
+
+  CStringA arg(kPlainText);
+  std::vector<uint8> hash = Hash(arg);
+  std::vector<uint8> sym_sign = SymSign(key, 1, &hash, NULL, NULL);
+  EXPECT_STREQ(BytesToHex(sym_sign),
+               _T("1c6fa359c0a7b11421ae4d31a92f9de8a4ef8d2d"));
+
+  sym_sign = SymSign(key, 1, NULL, &hash, NULL);
+  EXPECT_STREQ(BytesToHex(sym_sign),
+               _T("1c6fa359c0a7b11421ae4d31a92f9de8a4ef8d2d"));
+
+  sym_sign = SymSign(key, 1, NULL, NULL, &hash);
+  EXPECT_STREQ(BytesToHex(sym_sign),
+               _T("1c6fa359c0a7b11421ae4d31a92f9de8a4ef8d2d"));
+
+  sym_sign = SymSign(key, 1, &hash, &hash, &hash);
+    EXPECT_STREQ(BytesToHex(sym_sign),
+                 _T("fef3e343795946cd47ff4e07eca5f3f09b051d86"));
+}
+
+TEST(CupUtilsTest, ParseCupCookie) {
+  EXPECT_STREQ(_T(""), ParseCupCookie(_T("")));
+  EXPECT_STREQ(_T(""), ParseCupCookie(_T("foo; bar;")));
+  EXPECT_STREQ(_T("c="), ParseCupCookie(_T("c=")));
+  EXPECT_STREQ(_T("c="), ParseCupCookie(_T("c= ;")));
+  EXPECT_STREQ(_T("c=foo"), ParseCupCookie(_T("c=foo")));
+  EXPECT_STREQ(_T("c=foo"), ParseCupCookie(_T(";c=foo")));
+  EXPECT_STREQ(_T("c=foo"), ParseCupCookie(_T("c=foo ; bar;")));
+  EXPECT_STREQ(_T("c=foo"), ParseCupCookie(_T("b=bar; c=foo;")));
+  EXPECT_STREQ(_T("c=foo"), ParseCupCookie(_T("b=bar; c=foo ; foobar")));
+}
+
+}  // namespace cup_utils
+
+}  // namespace omaha
diff --git a/net/detector.cc b/net/detector.cc
index 6a6c5ce..a02e1f9 100644
--- a/net/detector.cc
+++ b/net/detector.cc
@@ -1,408 +1,408 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// TODO(omaha): move EnclosePath and UnenclosePath functions from path.h to

-//               string.h

-// TODO(omaha): Firefox detector does not handle proxy bypass.

-

-#include "omaha/net/detector.h"

-

-#include "base/scoped_ptr.h"

-#include "omaha/common/atl_regexp.h"

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/file_reader.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/string.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/time.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/network_config.h"

-

-namespace omaha {

-

-namespace  {

-

-// Returns true if the caller's impersonation or process access token user

-// is LOCAL_SYSTEM.

-bool IsRunningAsSystem() {

-  CString sid;

-  HRESULT hr = user_info::GetCurrentThreadUser(&sid);

-  if (SUCCEEDED(hr)) {

-    return IsLocalSystemSid(sid);

-  }

-  sid.Empty();

-  hr = user_info::GetCurrentUser(NULL, NULL, &sid);

-  if (SUCCEEDED(hr)) {

-    return IsLocalSystemSid(sid);

-  }

-  return false;

-}

-

-}  // namespace

-

-HRESULT GoogleProxyDetector::Detect(Config* config) {

-  ASSERT1(config);

-  RegKey reg_key;

-  HRESULT hr = reg_key.Open(reg_path_, KEY_READ);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  CString proxy_host;

-  hr = reg_key.GetValue(kRegValueProxyHost, &proxy_host);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  DWORD proxy_port(0);

-  hr = reg_key.GetValue(kRegValueProxyPort, &proxy_port);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  *config = Config();

-  config->proxy.Format(_T("%s:%d"), proxy_host, proxy_port);

-  config->source = _T("Google");

-  return S_OK;

-}

-

-FirefoxProxyDetector::FirefoxProxyDetector()

-    : cached_prefs_last_modified_(0),

-      cached_config_(new Config) {}

-

-FirefoxProxyDetector::~FirefoxProxyDetector() {}

-

-HRESULT FirefoxProxyDetector::Detect(Config* config) {

-  ASSERT1(config);

-

-  // The Firefox profile is not available when running as a local system.

-  if (IsRunningAsSystem()) {

-    return E_FAIL;

-  }

-

-  const TCHAR* const kFirefoxPrefsJsFile = _T("\\prefs.js");

-

-  CString name, path;

-  HRESULT hr = GetFirefoxDefaultProfile(&name, &path);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  path.Append(kFirefoxPrefsJsFile);

-

-  // Has the current profile been modified? Check the name, path, and

-  // last modified time of the profile are the same as their cached values.

-  FILETIME filetime_last_modified = {0};

-  int64 last_modified = 0;

-  if (SUCCEEDED(File::GetFileTime(path,

-                                  NULL,

-                                  NULL,

-                                  &filetime_last_modified))) {

-    last_modified = FileTimeToInt64(filetime_last_modified);

-  }

-  if (name.CompareNoCase(cached_prefs_name_)      == 0 &&

-      path.CompareNoCase(cached_prefs_file_path_) == 0 &&

-      last_modified == cached_prefs_last_modified_     &&

-      last_modified) {

-    NET_LOG(L4, (_T("[using FF cached profile][%s]"), path));

-    *config = *cached_config_;

-    return S_OK;

-  }

-

-  hr = ParsePrefsFile(name, path, config);

-  if (SUCCEEDED(hr) && last_modified) {

-    NET_LOG(L4, (_T("[cache FF profile][%s]"), path));

-    cached_prefs_name_          = name;

-    cached_prefs_file_path_     = path;

-    cached_prefs_last_modified_ = last_modified;

-    *cached_config_             = *config;

-  }

-  return hr;

-}

-

-// This is what the proxy configuration in Firefox looks like:

-// user_pref("network.proxy.autoconfig_url", "http://wpad/wpad.dat");

-// user_pref("network.proxy.ftp", "127.0.0.1");

-// user_pref("network.proxy.ftp_port", 8888);

-// user_pref("network.proxy.gopher", "127.0.0.1");

-// user_pref("network.proxy.gopher_port", 8888);

-// user_pref("network.proxy.http", "127.0.0.1");

-// user_pref("network.proxy.http_port", 8888);

-// user_pref("network.proxy.share_proxy_settings", true);

-// user_pref("network.proxy.socks", "127.0.0.1");

-// user_pref("network.proxy.socks_port", 8888);

-// user_pref("network.proxy.ssl", "127.0.0.1");

-// user_pref("network.proxy.ssl_port", 8888);

-// user_pref("network.proxy.type", 4);

-HRESULT FirefoxProxyDetector::ParsePrefsFile(const TCHAR* name,

-                                             const TCHAR* file_path,

-                                             Config* config) {

-  ASSERT1(name);

-  ASSERT1(file_path);

-  ASSERT1(config);

-

-  *config = Config();

-  config->source = _T("FireFox");

-

-  // TODO(omaha): implement optimization not to parse the file again if it

-  // did not change.

-  UNREFERENCED_PARAMETER(name);

-

-  // There were issues in production where the code fails to allocate

-  // the 1MB memory buffer as it had been initially requested by a previous

-  // version of the code.

-  //

-  // The assert below is somehow flaky but useful to detect the unlikely cases

-  // when the prefs file can't be opened.

-  FileReader prefs_file;

-  const size_t kBufferSize = 0x10000;      // 64KB buffer.

-  HRESULT hr = prefs_file.Init(file_path, kBufferSize);

-  ASSERT1(SUCCEEDED(hr));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString proxy_type;

-  CString proxy_config_url;

-  CString proxy_http_host;

-  CString proxy_http_port;

-  CString proxy_ssl_host;

-  CString proxy_ssl_port;

-

-  // For each line in the prefs.js, try to parse the proxy information out.

-  char line[1024] = {0};

-  while (SUCCEEDED(prefs_file.ReadLineAnsi(arraysize(line), line))) {

-    ParsePrefsLine(line,

-                   &proxy_type,

-                   &proxy_config_url,

-                   &proxy_http_host,

-                   &proxy_http_port,

-                   &proxy_ssl_host,

-                   &proxy_ssl_port);

-  }

-

-  // The default in FireFox is direct connection so it may be that the

-  // network.proxy.type is missing.

-  int type = PROXY_TYPE_NO_PROXY;

-  if (!proxy_type.IsEmpty() &&

-      !String_StringToDecimalIntChecked(proxy_type, &type)) {

-    return E_UNEXPECTED;

-  }

-

-  // Direct connection.

-  if (type == PROXY_TYPE_NO_PROXY) {

-    return S_OK;

-  }

-

-  // We look for both proxy auto-detect and proxy config url, to emulate

-  // the IE behavior, where when the auto-detect fails it defaults to the

-  // auto config url. Firefox remembers the auto config url even if not used,

-  // so it might not hurt to try it out.

-  if (type & PROXY_TYPE_AUTO_DETECT) {

-    config->auto_detect = true;

-  }

-  if ((type & PROXY_TYPE_AUTO_CONFIG_URL) && !proxy_config_url.IsEmpty()) {

-    UnenclosePath(&proxy_config_url);

-    config->auto_config_url = proxy_config_url;

-  }

-

-  // Named proxy.

-  if (!(type & PROXY_TYPE_NAMED_PROXY)) {

-    return S_OK;

-  }

-

-  CString proxy;

-  hr = BuildProxyString(proxy_http_host,

-                        proxy_http_port,

-                        proxy_ssl_host,

-                        proxy_ssl_port,

-                        &proxy);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  config->proxy = proxy;

-  return S_OK;

-}

-

-HRESULT FirefoxProxyDetector::BuildProxyString(const CString& proxy_http_host,

-                                               const CString& http_port,

-                                               const CString& proxy_ssl_host,

-                                               const CString& ssl_port,

-                                               CString* proxy) {

-  ASSERT1(proxy);

-

-  CString http_host = proxy_http_host;

-  CString ssl_host  = proxy_ssl_host;

-

-  // The host names in the prefs file are strings literals.

-  UnenclosePath(&http_host);

-  UnenclosePath(&ssl_host);

-

-  // Validate the port values.

-  if (!http_port.IsEmpty()) {

-    int http_port_num = 0;

-    if (!String_StringToDecimalIntChecked(http_port, &http_port_num) ||

-        http_port_num <= 0 &&

-        http_port_num > INTERNET_MAX_PORT_NUMBER_VALUE) {

-      return E_INVALIDARG;

-    }

-  }

-  if (!ssl_port.IsEmpty()) {

-    int ssl_port_num = 0;

-    if (!String_StringToDecimalIntChecked(ssl_port, &ssl_port_num) ||

-        ssl_port_num <= 0 ||

-        ssl_port_num > INTERNET_MAX_PORT_NUMBER_VALUE) {

-      return E_INVALIDARG;

-    }

-  }

-

-  // Format the proxy string.

-  CString str;

-  if (!http_host.IsEmpty()) {

-    str.AppendFormat(_T("http=%s"), http_host);

-    if (!http_port.IsEmpty()) {

-      str.AppendFormat(_T(":%s"), http_port);

-    }

-  }

-  if (!ssl_host.IsEmpty()) {

-    // Append a separator if needed.

-    if (!str.IsEmpty()) {

-      str += _T(';');

-    }

-    str.AppendFormat(_T("https=%s"), ssl_host);

-    if (!ssl_port.IsEmpty()) {

-      str.AppendFormat(_T(":%s"), ssl_port);

-    }

-  }

-

-  *proxy = str;

-  return S_OK;

-}

-

-// Parses a line from the prefs.js. An example of line to parse is:

-// user_pref("network.proxy.http", "foo");

-void FirefoxProxyDetector::ParsePrefsLine(const char* ansi_line,

-                                          CString* proxy_type,

-                                          CString* proxy_config_url,

-                                          CString* proxy_http_host,

-                                          CString* proxy_http_port,

-                                          CString* proxy_ssl_host,

-                                          CString* proxy_ssl_port) {

-  // Skip the lines that do not contain "network.proxy" to speed up the

-  // parsing. This is important for large prefs files.

-  if (strstr(ansi_line, "network.proxy.") == NULL) {

-    return;

-  }

-

-  AtlRE proxy_type_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.type\\\"\\b*,\\b*{\\d+}\\)"), false);                    // NOLINT

-  AtlRE proxy_config_url_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.autoconfig_url\\\"\\b*,\\b*{\\q}\\)"), false);     // NOLINT

-  AtlRE proxy_http_host_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.http\\\"\\b*,\\b*{\\q}\\)"), false);                // NOLINT

-  AtlRE proxy_http_port_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.http_port\\\"\\b*,\\b*{\\d+}\\)"), false);          // NOLINT

-  AtlRE proxy_ssl_host_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.ssl\\\"\\b*,\\b*{\\q}\\)"), false);                  // NOLINT

-  AtlRE proxy_ssl_port_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.ssl_port\\\"\\b*,\\b*{\\d+}\\)"), false);            // NOLINT

-

-  CString line(ansi_line);

-  if (AtlRE::PartialMatch(line, proxy_type_regex, proxy_type)) {

-    return;

-  }

-  if (AtlRE::PartialMatch(line, proxy_config_url_regex, proxy_config_url)) {

-    return;

-  }

-  if (AtlRE::PartialMatch(line, proxy_http_host_regex, proxy_http_host)) {

-    return;

-  }

-  if (AtlRE::PartialMatch(line, proxy_http_port_regex, proxy_http_port)) {

-    return;

-  }

-  if (AtlRE::PartialMatch(line, proxy_ssl_host_regex, proxy_ssl_host)) {

-    return;

-  }

-  if (AtlRE::PartialMatch(line, proxy_ssl_port_regex, proxy_ssl_port)) {

-    return;

-  }

-}

-

-HRESULT DefaultProxyDetector::Detect(Config* config) {

-  ASSERT1(config);

-

-  scoped_ptr<HttpClient> http_client(CreateHttpClient());

-

-  // We expect to be able to instantiate either of the http clients.

-  ASSERT1(http_client.get());

-  if (!http_client.get()) {

-    return E_UNEXPECTED;

-  }

-  HRESULT hr = http_client->Initialize();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  HttpClient::ProxyInfo proxy_info = {0};

-  hr = http_client->GetDefaultProxyConfiguration(&proxy_info);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {

-    Config proxy_config;

-    proxy_config.source = _T("winhttp");

-    proxy_config.proxy = proxy_info.proxy;

-    proxy_config.proxy_bypass = proxy_info.proxy_bypass;

-    *config = proxy_config;

-    return S_OK;

-  } else {

-    return E_FAIL;

-  }

-}

-

-HRESULT IEProxyDetector::Detect(Config* config) {

-  ASSERT1(config);

-

-  // Internet Explorer proxy configuration is not available when running as

-  // local system.

-  if (IsRunningAsSystem()) {

-    return E_FAIL;

-  }

-

-  scoped_ptr<HttpClient> http_client(CreateHttpClient());

-

-  // We expect to be able to instantiate either of the http clients.

-  ASSERT1(http_client.get());

-  if (!http_client.get()) {

-    return E_UNEXPECTED;

-  }

-  HRESULT hr = http_client->Initialize();

-  if (FAILED(hr)) {

-    return hr;

-  }

-  HttpClient::CurrentUserIEProxyConfig ie_proxy_config = {0};

-  hr = http_client->GetIEProxyConfiguration(&ie_proxy_config);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  config->source = _T("IE");

-  config->auto_detect = ie_proxy_config.auto_detect;

-  config->auto_config_url = ie_proxy_config.auto_config_url;

-  config->proxy = ie_proxy_config.proxy;

-  config->proxy_bypass = ie_proxy_config.proxy_bypass;

-

-  ::GlobalFree(const_cast<TCHAR*>(ie_proxy_config.auto_config_url));

-  ::GlobalFree(const_cast<TCHAR*>(ie_proxy_config.proxy));

-  ::GlobalFree(const_cast<TCHAR*>(ie_proxy_config.proxy_bypass));

-

-  return S_OK;

-};

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// TODO(omaha): move EnclosePath and UnenclosePath functions from path.h to
+//               string.h
+// TODO(omaha): Firefox detector does not handle proxy bypass.
+
+#include "omaha/net/detector.h"
+
+#include "base/scoped_ptr.h"
+#include "omaha/common/atl_regexp.h"
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/file_reader.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/string.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/time.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/network_config.h"
+
+namespace omaha {
+
+namespace  {
+
+// Returns true if the caller's impersonation or process access token user
+// is LOCAL_SYSTEM.
+bool IsRunningAsSystem() {
+  CString sid;
+  HRESULT hr = user_info::GetCurrentThreadUser(&sid);
+  if (SUCCEEDED(hr)) {
+    return IsLocalSystemSid(sid);
+  }
+  sid.Empty();
+  hr = user_info::GetCurrentUser(NULL, NULL, &sid);
+  if (SUCCEEDED(hr)) {
+    return IsLocalSystemSid(sid);
+  }
+  return false;
+}
+
+}  // namespace
+
+HRESULT GoogleProxyDetector::Detect(Config* config) {
+  ASSERT1(config);
+  RegKey reg_key;
+  HRESULT hr = reg_key.Open(reg_path_, KEY_READ);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  CString proxy_host;
+  hr = reg_key.GetValue(kRegValueProxyHost, &proxy_host);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  DWORD proxy_port(0);
+  hr = reg_key.GetValue(kRegValueProxyPort, &proxy_port);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  *config = Config();
+  config->proxy.Format(_T("%s:%d"), proxy_host, proxy_port);
+  config->source = _T("Google");
+  return S_OK;
+}
+
+FirefoxProxyDetector::FirefoxProxyDetector()
+    : cached_prefs_last_modified_(0),
+      cached_config_(new Config) {}
+
+FirefoxProxyDetector::~FirefoxProxyDetector() {}
+
+HRESULT FirefoxProxyDetector::Detect(Config* config) {
+  ASSERT1(config);
+
+  // The Firefox profile is not available when running as a local system.
+  if (IsRunningAsSystem()) {
+    return E_FAIL;
+  }
+
+  const TCHAR* const kFirefoxPrefsJsFile = _T("\\prefs.js");
+
+  CString name, path;
+  HRESULT hr = GetFirefoxDefaultProfile(&name, &path);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  path.Append(kFirefoxPrefsJsFile);
+
+  // Has the current profile been modified? Check the name, path, and
+  // last modified time of the profile are the same as their cached values.
+  FILETIME filetime_last_modified = {0};
+  int64 last_modified = 0;
+  if (SUCCEEDED(File::GetFileTime(path,
+                                  NULL,
+                                  NULL,
+                                  &filetime_last_modified))) {
+    last_modified = FileTimeToInt64(filetime_last_modified);
+  }
+  if (name.CompareNoCase(cached_prefs_name_)      == 0 &&
+      path.CompareNoCase(cached_prefs_file_path_) == 0 &&
+      last_modified == cached_prefs_last_modified_     &&
+      last_modified) {
+    NET_LOG(L4, (_T("[using FF cached profile][%s]"), path));
+    *config = *cached_config_;
+    return S_OK;
+  }
+
+  hr = ParsePrefsFile(name, path, config);
+  if (SUCCEEDED(hr) && last_modified) {
+    NET_LOG(L4, (_T("[cache FF profile][%s]"), path));
+    cached_prefs_name_          = name;
+    cached_prefs_file_path_     = path;
+    cached_prefs_last_modified_ = last_modified;
+    *cached_config_             = *config;
+  }
+  return hr;
+}
+
+// This is what the proxy configuration in Firefox looks like:
+// user_pref("network.proxy.autoconfig_url", "http://wpad/wpad.dat");
+// user_pref("network.proxy.ftp", "127.0.0.1");
+// user_pref("network.proxy.ftp_port", 8888);
+// user_pref("network.proxy.gopher", "127.0.0.1");
+// user_pref("network.proxy.gopher_port", 8888);
+// user_pref("network.proxy.http", "127.0.0.1");
+// user_pref("network.proxy.http_port", 8888);
+// user_pref("network.proxy.share_proxy_settings", true);
+// user_pref("network.proxy.socks", "127.0.0.1");
+// user_pref("network.proxy.socks_port", 8888);
+// user_pref("network.proxy.ssl", "127.0.0.1");
+// user_pref("network.proxy.ssl_port", 8888);
+// user_pref("network.proxy.type", 4);
+HRESULT FirefoxProxyDetector::ParsePrefsFile(const TCHAR* name,
+                                             const TCHAR* file_path,
+                                             Config* config) {
+  ASSERT1(name);
+  ASSERT1(file_path);
+  ASSERT1(config);
+
+  *config = Config();
+  config->source = _T("FireFox");
+
+  // TODO(omaha): implement optimization not to parse the file again if it
+  // did not change.
+  UNREFERENCED_PARAMETER(name);
+
+  // There were issues in production where the code fails to allocate
+  // the 1MB memory buffer as it had been initially requested by a previous
+  // version of the code.
+  //
+  // The assert below is somehow flaky but useful to detect the unlikely cases
+  // when the prefs file can't be opened.
+  FileReader prefs_file;
+  const size_t kBufferSize = 0x10000;      // 64KB buffer.
+  HRESULT hr = prefs_file.Init(file_path, kBufferSize);
+  ASSERT1(SUCCEEDED(hr));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString proxy_type;
+  CString proxy_config_url;
+  CString proxy_http_host;
+  CString proxy_http_port;
+  CString proxy_ssl_host;
+  CString proxy_ssl_port;
+
+  // For each line in the prefs.js, try to parse the proxy information out.
+  char line[1024] = {0};
+  while (SUCCEEDED(prefs_file.ReadLineAnsi(arraysize(line), line))) {
+    ParsePrefsLine(line,
+                   &proxy_type,
+                   &proxy_config_url,
+                   &proxy_http_host,
+                   &proxy_http_port,
+                   &proxy_ssl_host,
+                   &proxy_ssl_port);
+  }
+
+  // The default in FireFox is direct connection so it may be that the
+  // network.proxy.type is missing.
+  int type = PROXY_TYPE_NO_PROXY;
+  if (!proxy_type.IsEmpty() &&
+      !String_StringToDecimalIntChecked(proxy_type, &type)) {
+    return E_UNEXPECTED;
+  }
+
+  // Direct connection.
+  if (type == PROXY_TYPE_NO_PROXY) {
+    return S_OK;
+  }
+
+  // We look for both proxy auto-detect and proxy config url, to emulate
+  // the IE behavior, where when the auto-detect fails it defaults to the
+  // auto config url. Firefox remembers the auto config url even if not used,
+  // so it might not hurt to try it out.
+  if (type & PROXY_TYPE_AUTO_DETECT) {
+    config->auto_detect = true;
+  }
+  if ((type & PROXY_TYPE_AUTO_CONFIG_URL) && !proxy_config_url.IsEmpty()) {
+    UnenclosePath(&proxy_config_url);
+    config->auto_config_url = proxy_config_url;
+  }
+
+  // Named proxy.
+  if (!(type & PROXY_TYPE_NAMED_PROXY)) {
+    return S_OK;
+  }
+
+  CString proxy;
+  hr = BuildProxyString(proxy_http_host,
+                        proxy_http_port,
+                        proxy_ssl_host,
+                        proxy_ssl_port,
+                        &proxy);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  config->proxy = proxy;
+  return S_OK;
+}
+
+HRESULT FirefoxProxyDetector::BuildProxyString(const CString& proxy_http_host,
+                                               const CString& http_port,
+                                               const CString& proxy_ssl_host,
+                                               const CString& ssl_port,
+                                               CString* proxy) {
+  ASSERT1(proxy);
+
+  CString http_host = proxy_http_host;
+  CString ssl_host  = proxy_ssl_host;
+
+  // The host names in the prefs file are strings literals.
+  UnenclosePath(&http_host);
+  UnenclosePath(&ssl_host);
+
+  // Validate the port values.
+  if (!http_port.IsEmpty()) {
+    int http_port_num = 0;
+    if (!String_StringToDecimalIntChecked(http_port, &http_port_num) ||
+        http_port_num <= 0 &&
+        http_port_num > INTERNET_MAX_PORT_NUMBER_VALUE) {
+      return E_INVALIDARG;
+    }
+  }
+  if (!ssl_port.IsEmpty()) {
+    int ssl_port_num = 0;
+    if (!String_StringToDecimalIntChecked(ssl_port, &ssl_port_num) ||
+        ssl_port_num <= 0 ||
+        ssl_port_num > INTERNET_MAX_PORT_NUMBER_VALUE) {
+      return E_INVALIDARG;
+    }
+  }
+
+  // Format the proxy string.
+  CString str;
+  if (!http_host.IsEmpty()) {
+    str.AppendFormat(_T("http=%s"), http_host);
+    if (!http_port.IsEmpty()) {
+      str.AppendFormat(_T(":%s"), http_port);
+    }
+  }
+  if (!ssl_host.IsEmpty()) {
+    // Append a separator if needed.
+    if (!str.IsEmpty()) {
+      str += _T(';');
+    }
+    str.AppendFormat(_T("https=%s"), ssl_host);
+    if (!ssl_port.IsEmpty()) {
+      str.AppendFormat(_T(":%s"), ssl_port);
+    }
+  }
+
+  *proxy = str;
+  return S_OK;
+}
+
+// Parses a line from the prefs.js. An example of line to parse is:
+// user_pref("network.proxy.http", "foo");
+void FirefoxProxyDetector::ParsePrefsLine(const char* ansi_line,
+                                          CString* proxy_type,
+                                          CString* proxy_config_url,
+                                          CString* proxy_http_host,
+                                          CString* proxy_http_port,
+                                          CString* proxy_ssl_host,
+                                          CString* proxy_ssl_port) {
+  // Skip the lines that do not contain "network.proxy" to speed up the
+  // parsing. This is important for large prefs files.
+  if (strstr(ansi_line, "network.proxy.") == NULL) {
+    return;
+  }
+
+  AtlRE proxy_type_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.type\\\"\\b*,\\b*{\\d+}\\)"), false);                    // NOLINT
+  AtlRE proxy_config_url_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.autoconfig_url\\\"\\b*,\\b*{\\q}\\)"), false);     // NOLINT
+  AtlRE proxy_http_host_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.http\\\"\\b*,\\b*{\\q}\\)"), false);                // NOLINT
+  AtlRE proxy_http_port_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.http_port\\\"\\b*,\\b*{\\d+}\\)"), false);          // NOLINT
+  AtlRE proxy_ssl_host_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.ssl\\\"\\b*,\\b*{\\q}\\)"), false);                  // NOLINT
+  AtlRE proxy_ssl_port_regex(_T("^\\b*user_pref\\b*\\(\\b*\\\"network\\.proxy\\.ssl_port\\\"\\b*,\\b*{\\d+}\\)"), false);            // NOLINT
+
+  CString line(ansi_line);
+  if (AtlRE::PartialMatch(line, proxy_type_regex, proxy_type)) {
+    return;
+  }
+  if (AtlRE::PartialMatch(line, proxy_config_url_regex, proxy_config_url)) {
+    return;
+  }
+  if (AtlRE::PartialMatch(line, proxy_http_host_regex, proxy_http_host)) {
+    return;
+  }
+  if (AtlRE::PartialMatch(line, proxy_http_port_regex, proxy_http_port)) {
+    return;
+  }
+  if (AtlRE::PartialMatch(line, proxy_ssl_host_regex, proxy_ssl_host)) {
+    return;
+  }
+  if (AtlRE::PartialMatch(line, proxy_ssl_port_regex, proxy_ssl_port)) {
+    return;
+  }
+}
+
+HRESULT DefaultProxyDetector::Detect(Config* config) {
+  ASSERT1(config);
+
+  scoped_ptr<HttpClient> http_client(CreateHttpClient());
+
+  // We expect to be able to instantiate either of the http clients.
+  ASSERT1(http_client.get());
+  if (!http_client.get()) {
+    return E_UNEXPECTED;
+  }
+  HRESULT hr = http_client->Initialize();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  HttpClient::ProxyInfo proxy_info = {0};
+  hr = http_client->GetDefaultProxyConfiguration(&proxy_info);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
+    Config proxy_config;
+    proxy_config.source = _T("winhttp");
+    proxy_config.proxy = proxy_info.proxy;
+    proxy_config.proxy_bypass = proxy_info.proxy_bypass;
+    *config = proxy_config;
+    return S_OK;
+  } else {
+    return E_FAIL;
+  }
+}
+
+HRESULT IEProxyDetector::Detect(Config* config) {
+  ASSERT1(config);
+
+  // Internet Explorer proxy configuration is not available when running as
+  // local system.
+  if (IsRunningAsSystem()) {
+    return E_FAIL;
+  }
+
+  scoped_ptr<HttpClient> http_client(CreateHttpClient());
+
+  // We expect to be able to instantiate either of the http clients.
+  ASSERT1(http_client.get());
+  if (!http_client.get()) {
+    return E_UNEXPECTED;
+  }
+  HRESULT hr = http_client->Initialize();
+  if (FAILED(hr)) {
+    return hr;
+  }
+  HttpClient::CurrentUserIEProxyConfig ie_proxy_config = {0};
+  hr = http_client->GetIEProxyConfiguration(&ie_proxy_config);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  config->source = _T("IE");
+  config->auto_detect = ie_proxy_config.auto_detect;
+  config->auto_config_url = ie_proxy_config.auto_config_url;
+  config->proxy = ie_proxy_config.proxy;
+  config->proxy_bypass = ie_proxy_config.proxy_bypass;
+
+  ::GlobalFree(const_cast<TCHAR*>(ie_proxy_config.auto_config_url));
+  ::GlobalFree(const_cast<TCHAR*>(ie_proxy_config.proxy));
+  ::GlobalFree(const_cast<TCHAR*>(ie_proxy_config.proxy_bypass));
+
+  return S_OK;
+};
+
+}  // namespace omaha
+
diff --git a/net/detector.h b/net/detector.h
index 07d5e2e..d87e683 100644
--- a/net/detector.h
+++ b/net/detector.h
@@ -1,126 +1,126 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_NET_DETECTOR_H__

-#define OMAHA_NET_DETECTOR_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-

-namespace omaha {

-

-struct Config;

-

-class ProxyDetectorInterface {

- public:

-  // Detects proxy information.

-  virtual HRESULT Detect(Config* config) = 0;

-  virtual ~ProxyDetectorInterface() {}

-};

-

-// Detects proxy information for the corp machines. This information is

-// periodically distributed by SMS and it is part of the gWindows image.

-// The proxy information is stored under: HKLM\SOFTWARE\Google\UpdateDev

-class GoogleProxyDetector : public ProxyDetectorInterface {

- public:

-  explicit GoogleProxyDetector(const CString& reg_path)

-      : reg_path_(reg_path) {}

-

-  virtual HRESULT Detect(Config* config);

- private:

-  CString reg_path_;

-  DISALLOW_EVIL_CONSTRUCTORS(GoogleProxyDetector);

-};

-

-// Detects winhttp proxy information. This is what the winhttp proxy

-// configuration utility (proxycfg.exe) has set.

-// The winhttp proxy settings are under:

-// HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Connections

-class DefaultProxyDetector : public ProxyDetectorInterface {

- public:

-  DefaultProxyDetector() {}

-  virtual HRESULT Detect(Config* config);

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(DefaultProxyDetector);

-};

-

-// Detects proxy information for Firefox.

-// http://www.mozilla.org/quality/networking/docs/netprefs.html

-// It works only when the calling code runs as or it impersonates a user.

-class FirefoxProxyDetector : public ProxyDetectorInterface {

- public:

-  enum ProxyType {

-    PROXY_TYPE_NO_PROXY         = 0,

-    PROXY_TYPE_NAMED_PROXY      = 1,

-    PROXY_TYPE_AUTO_CONFIG_URL  = 2,

-    PROXY_TYPE_AUTO_DETECT      = 4

-  };

-

-  FirefoxProxyDetector();

-  virtual ~FirefoxProxyDetector();

-

-  virtual HRESULT Detect(Config* config);

-

- private:

-  // Parses the prefs.js file.

-  HRESULT ParsePrefsFile(const TCHAR* name,

-                         const TCHAR* file_path,

-                         Config* config);

-

-  // Parse one line of the prefs file.

-  void ParsePrefsLine(const char* ansi_line,

-                      CString* proxy_type,

-                      CString* proxy_config_url,

-                      CString* proxy_http_host,

-                      CString* proxy_http_port,

-                      CString* proxy_ssl_host,

-                      CString* proxy_ssl_port);

-

-  // Builds a proxy string out of individual components.

-  HRESULT BuildProxyString(const CString& http_host,

-                           const CString& http_port,

-                           const CString& ssl_host,

-                           const CString& ssl_port,

-                           CString* proxy);

-

-  // Cached configuration values for the current FF profile.

-  CString            cached_prefs_name_;

-  CString            cached_prefs_file_path_;

-  int64              cached_prefs_last_modified_;

-  scoped_ptr<Config> cached_config_;

-

-  friend class FirefoxProxyDetectorTest;

-  DISALLOW_EVIL_CONSTRUCTORS(FirefoxProxyDetector);

-};

-

-// Detects wininet proxy information for the current user. The caller must

-// run as user to retrieve the correct information.

-// It works only when the calling code runs as or it impersonates a user.

-class IEProxyDetector : public ProxyDetectorInterface {

- public:

-  IEProxyDetector() {}

-  virtual HRESULT Detect(Config* config);

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(IEProxyDetector);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_NET_DETECTOR_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_NET_DETECTOR_H__
+#define OMAHA_NET_DETECTOR_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+
+namespace omaha {
+
+struct Config;
+
+class ProxyDetectorInterface {
+ public:
+  // Detects proxy information.
+  virtual HRESULT Detect(Config* config) = 0;
+  virtual ~ProxyDetectorInterface() {}
+};
+
+// Detects proxy information for the corp machines. This information is
+// periodically distributed by SMS and it is part of the gWindows image.
+// The proxy information is stored under: HKLM\SOFTWARE\Google\UpdateDev
+class GoogleProxyDetector : public ProxyDetectorInterface {
+ public:
+  explicit GoogleProxyDetector(const CString& reg_path)
+      : reg_path_(reg_path) {}
+
+  virtual HRESULT Detect(Config* config);
+ private:
+  CString reg_path_;
+  DISALLOW_EVIL_CONSTRUCTORS(GoogleProxyDetector);
+};
+
+// Detects winhttp proxy information. This is what the winhttp proxy
+// configuration utility (proxycfg.exe) has set.
+// The winhttp proxy settings are under:
+// HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Connections
+class DefaultProxyDetector : public ProxyDetectorInterface {
+ public:
+  DefaultProxyDetector() {}
+  virtual HRESULT Detect(Config* config);
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(DefaultProxyDetector);
+};
+
+// Detects proxy information for Firefox.
+// http://www.mozilla.org/quality/networking/docs/netprefs.html
+// It works only when the calling code runs as or it impersonates a user.
+class FirefoxProxyDetector : public ProxyDetectorInterface {
+ public:
+  enum ProxyType {
+    PROXY_TYPE_NO_PROXY         = 0,
+    PROXY_TYPE_NAMED_PROXY      = 1,
+    PROXY_TYPE_AUTO_CONFIG_URL  = 2,
+    PROXY_TYPE_AUTO_DETECT      = 4
+  };
+
+  FirefoxProxyDetector();
+  virtual ~FirefoxProxyDetector();
+
+  virtual HRESULT Detect(Config* config);
+
+ private:
+  // Parses the prefs.js file.
+  HRESULT ParsePrefsFile(const TCHAR* name,
+                         const TCHAR* file_path,
+                         Config* config);
+
+  // Parse one line of the prefs file.
+  void ParsePrefsLine(const char* ansi_line,
+                      CString* proxy_type,
+                      CString* proxy_config_url,
+                      CString* proxy_http_host,
+                      CString* proxy_http_port,
+                      CString* proxy_ssl_host,
+                      CString* proxy_ssl_port);
+
+  // Builds a proxy string out of individual components.
+  HRESULT BuildProxyString(const CString& http_host,
+                           const CString& http_port,
+                           const CString& ssl_host,
+                           const CString& ssl_port,
+                           CString* proxy);
+
+  // Cached configuration values for the current FF profile.
+  CString            cached_prefs_name_;
+  CString            cached_prefs_file_path_;
+  int64              cached_prefs_last_modified_;
+  scoped_ptr<Config> cached_config_;
+
+  friend class FirefoxProxyDetectorTest;
+  DISALLOW_EVIL_CONSTRUCTORS(FirefoxProxyDetector);
+};
+
+// Detects wininet proxy information for the current user. The caller must
+// run as user to retrieve the correct information.
+// It works only when the calling code runs as or it impersonates a user.
+class IEProxyDetector : public ProxyDetectorInterface {
+ public:
+  IEProxyDetector() {}
+  virtual HRESULT Detect(Config* config);
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(IEProxyDetector);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_NET_DETECTOR_H__
+
diff --git a/net/detector_unittest.cc b/net/detector_unittest.cc
index 131fe52..82b85bc 100644
--- a/net/detector_unittest.cc
+++ b/net/detector_unittest.cc
@@ -1,326 +1,326 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <cstdio>

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/browser_utils.h"

-#include "omaha/net/detector.h"

-#include "omaha/net/network_config.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class FirefoxProxyDetectorTest : public testing::Test {

- public:

-  FirefoxProxyDetectorTest() {}

-

-  virtual void SetUp() {

-    detector_.reset(new FirefoxProxyDetector);

-  }

-

-  virtual void TearDown() {

-  }

-

-  HRESULT BuildProxyString(const CString& http_host,

-                           const CString& http_port,

-                           const CString& ssl_host,

-                           const CString& ssl_port,

-                           CString* proxy) {

-    return detector_->BuildProxyString(http_host,

-                                       http_port,

-                                       ssl_host,

-                                       ssl_port,

-                                       proxy);

-  }

-

-  void ParsePrefsLine(const char* ansi_line,

-                      CString* proxy_type,

-                      CString* proxy_config_url,

-                      CString* proxy_http_host,

-                      CString* proxy_http_port,

-                      CString* proxy_ssl_host,

-                      CString* proxy_ssl_port) {

-    detector_->ParsePrefsLine(ansi_line,

-                              proxy_type,

-                              proxy_config_url,

-                              proxy_http_host,

-                              proxy_http_port,

-                              proxy_ssl_host,

-                              proxy_ssl_port);

-  }

-

-

-  HRESULT ParsePrefsFile(const TCHAR* name,

-                         const TCHAR* file_path,

-                         Config* config) {

-    return detector_->ParsePrefsFile(name, file_path, config);

-  }

-

-  // Builds a mock prefs file to test the parsing code.

-  bool BuildPrefsFile(const CString& type,

-                      const CString& config_url,

-                      const CString& http_host,

-                      const CString& http_port,

-                      const CString& ssl_host,

-                      const CString& ssl_port,

-                      CString* file_path);

-

-  scoped_ptr<FirefoxProxyDetector> detector_;

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(FirefoxProxyDetectorTest);

-};

-

-bool FirefoxProxyDetectorTest::BuildPrefsFile(const CString& type,

-                                              const CString& config_url,

-                                              const CString& http_host,

-                                              const CString& http_port,

-                                              const CString& ssl_host,

-                                              const CString& ssl_port,

-                                              CString* file_path) {

-  CString temp_dir(app_util::GetTempDir());

-  file_path->Format(_T("%somaha_test_%x.js"), temp_dir, ::GetTickCount());

-

-  FILE* prefs_file = NULL;

-  fopen_s(&prefs_file, CStringA(*file_path), "w");

-  if (!prefs_file) {

-    return false;

-  }

-

-  fprintf(prefs_file,

-          "user_pref(\"network.proxy.type\", %s);\n",

-          CStringA(type));

-  fprintf(prefs_file,

-          "user_pref(\"network.proxy.autoconfig_url\", \"%s\");\n",

-          CStringA(config_url));

-  fprintf(prefs_file,

-          "user_pref(\"network.proxy.http\", \"%s\");\n",

-          CStringA(http_host));

-  fprintf(prefs_file,

-          "user_pref(\"network.proxy.http_port\", %s);\n",

-          CStringA(http_port));

-  fprintf(prefs_file,

-          "user_pref(\"network.proxy.ssl\", \"%s\");\n",

-          CStringA(ssl_host));

-  fprintf(prefs_file,

-          "user_pref(\"network.proxy.ssl_port\", %s);\n",

-          CStringA(ssl_port));

-

-  fclose(prefs_file);

-

-  return true;

-}

-

-TEST_F(FirefoxProxyDetectorTest, BuildProxyString) {

-  CString http_host = _T("foo");

-  CString http_port = _T("80");

-  CString ssl_host;

-  CString ssl_port;

-  CString proxy;

-

-  EXPECT_SUCCEEDED(BuildProxyString(http_host,

-                                    http_port,

-                                    ssl_host,

-                                    ssl_port,

-                                    &proxy));

-  EXPECT_STREQ(proxy, _T("http=foo:80"));

-

-  http_host = _T("foo");

-  http_port = _T("80");

-  ssl_host  = _T("bar");

-  ssl_port  = _T("8080");

-

-  EXPECT_SUCCEEDED(BuildProxyString(http_host,

-                                    http_port,

-                                    ssl_host,

-                                    ssl_port,

-                                    &proxy));

-  EXPECT_STREQ(proxy, _T("http=foo:80;https=bar:8080"));

-

-  http_host.Empty();

-  http_port.Empty();

-  ssl_host  = _T("bar");

-  ssl_port  = _T("8080");

-

-  EXPECT_SUCCEEDED(BuildProxyString(http_host,

-                                    http_port,

-                                    ssl_host,

-                                    ssl_port,

-                                    &proxy));

-  EXPECT_STREQ(proxy, _T("https=bar:8080"));

-}

-

-TEST_F(FirefoxProxyDetectorTest, ParsePrefsLine) {

-  CString type;

-  CString config_url;

-  CString http_host;

-  CString http_port;

-  CString ssl_host;

-  CString ssl_port;

-

-  // Parse "type".

-  const char* ansi_line = "user_pref(\"network.proxy.type\", 4);";

-  ParsePrefsLine(ansi_line,

-                 &type,

-                 &config_url,

-                 &http_host,

-                 &http_port,

-                 &ssl_host,

-                 &ssl_port);

-  EXPECT_STREQ(type, _T("4"));

-

-  // Parse "config_url".

-  ansi_line =

-      "user_pref(\"network.proxy.autoconfig_url\", \"http://wpad/wpad.dat\");";

-  ParsePrefsLine(ansi_line,

-                 &type,

-                 &config_url,

-                 &http_host,

-                 &http_port,

-                 &ssl_host,

-                 &ssl_port);

-  EXPECT_STREQ(config_url, _T("\"http://wpad/wpad.dat\""));

-

-  // Parse "http_host".

-  ansi_line = "user_pref(\"network.proxy.http\", \"127.0.0.1\");";

-  ParsePrefsLine(ansi_line,

-                 &type,

-                 &config_url,

-                 &http_host,

-                 &http_port,

-                 &ssl_host,

-                 &ssl_port);

-  EXPECT_STREQ(http_host, _T("\"127.0.0.1\""));

-

-  // Parse "http_port".

-  ansi_line = "user_pref(\"network.proxy.http_port\", 8888);";

-  ParsePrefsLine(ansi_line,

-                 &type,

-                 &config_url,

-                 &http_host,

-                 &http_port,

-                 &ssl_host,

-                 &ssl_port);

-  EXPECT_STREQ(http_port, _T("8888"));

-

-  // Parse "ssl_host".

-  ansi_line = "user_pref(\"network.proxy.ssl\", \"10.0.0.1\");";

-  ParsePrefsLine(ansi_line,

-                 &type,

-                 &config_url,

-                 &http_host,

-                 &http_port,

-                 &ssl_host,

-                 &ssl_port);

-  EXPECT_STREQ(ssl_host, _T("\"10.0.0.1\""));

-

-  // Parse "ssl_port".

-  ansi_line = "user_pref(\"network.proxy.ssl_port\", 8080);";

-  ParsePrefsLine(ansi_line,

-                 &type,

-                 &config_url,

-                 &http_host,

-                 &http_port,

-                 &ssl_host,

-                 &ssl_port);

-  EXPECT_STREQ(ssl_port, _T("8080"));

-}

-

-TEST_F(FirefoxProxyDetectorTest, ParsePrefsFile) {

-  // Direct connection

-  CString prefs_file;

-  bool res = BuildPrefsFile(_T("0"),

-                            _T("http://foobar"),

-                            _T("foo"),

-                            _T("80"),

-                            _T("bar"),

-                            _T("8080"),

-                            &prefs_file);

-  ASSERT_TRUE(res);

-  Config config;

-  EXPECT_SUCCEEDED(ParsePrefsFile(_T(""), prefs_file, &config));

-  EXPECT_FALSE(config.auto_detect);

-  EXPECT_TRUE(config.auto_config_url.IsEmpty());

-  EXPECT_TRUE(config.proxy.IsEmpty());

-  EXPECT_TRUE(config.proxy_bypass.IsEmpty());

-  EXPECT_TRUE(::DeleteFile(prefs_file));

-

-  // Named proxy.

-  res = BuildPrefsFile(_T("1"),

-                       _T("http://foobar"),

-                       _T("foo"),

-                       _T("80"),

-                       _T("bar"),

-                       _T("8080"),

-                       &prefs_file);

-  ASSERT_TRUE(res);

-  config = Config();

-  EXPECT_SUCCEEDED(ParsePrefsFile(_T(""), prefs_file, &config));

-  EXPECT_FALSE(config.auto_detect);

-  EXPECT_TRUE(config.auto_config_url.IsEmpty());

-  EXPECT_STREQ(config.proxy, _T("http=foo:80;https=bar:8080"));

-  EXPECT_TRUE(config.proxy_bypass.IsEmpty());

-  EXPECT_TRUE(::DeleteFile(prefs_file));

-

-  // Auto config url.

-  res = BuildPrefsFile(_T("2"),

-                       _T("http://foobar"),

-                       _T("foo"),

-                       _T("80"),

-                       _T("bar"),

-                       _T("8080"),

-                       &prefs_file);

-  ASSERT_TRUE(res);

-  config = Config();

-  EXPECT_SUCCEEDED(ParsePrefsFile(_T(""), prefs_file, &config));

-  EXPECT_FALSE(config.auto_detect);

-  EXPECT_STREQ(config.auto_config_url, _T("http://foobar"));

-  EXPECT_TRUE(config.proxy.IsEmpty());

-  EXPECT_TRUE(config.proxy_bypass.IsEmpty());

-  EXPECT_TRUE(::DeleteFile(prefs_file));

-

-  // Auto detect.

-  res = BuildPrefsFile(_T("4"),

-                       _T("http://foobar"),

-                       _T("foo"),

-                       _T("80"),

-                       _T("bar"),

-                       _T("8080"),

-                       &prefs_file);

-  ASSERT_TRUE(res);

-  config = Config();

-  EXPECT_SUCCEEDED(ParsePrefsFile(_T(""), prefs_file, &config));

-  EXPECT_TRUE(config.auto_detect);

-  EXPECT_TRUE(config.auto_config_url.IsEmpty());

-  EXPECT_TRUE(config.proxy.IsEmpty());

-  EXPECT_TRUE(config.proxy_bypass.IsEmpty());

-  EXPECT_TRUE(::DeleteFile(prefs_file));

-}

-

-// Tries to detect the configuration if a profile is available.

-TEST_F(FirefoxProxyDetectorTest, Detect) {

-  CString name, path;

-  if (FAILED(GetFirefoxDefaultProfile(&name, &path))) {

-    return;

-  }

-  Config config;

-  EXPECT_SUCCEEDED(detector_->Detect(&config));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <cstdio>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/browser_utils.h"
+#include "omaha/net/detector.h"
+#include "omaha/net/network_config.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class FirefoxProxyDetectorTest : public testing::Test {
+ public:
+  FirefoxProxyDetectorTest() {}
+
+  virtual void SetUp() {
+    detector_.reset(new FirefoxProxyDetector);
+  }
+
+  virtual void TearDown() {
+  }
+
+  HRESULT BuildProxyString(const CString& http_host,
+                           const CString& http_port,
+                           const CString& ssl_host,
+                           const CString& ssl_port,
+                           CString* proxy) {
+    return detector_->BuildProxyString(http_host,
+                                       http_port,
+                                       ssl_host,
+                                       ssl_port,
+                                       proxy);
+  }
+
+  void ParsePrefsLine(const char* ansi_line,
+                      CString* proxy_type,
+                      CString* proxy_config_url,
+                      CString* proxy_http_host,
+                      CString* proxy_http_port,
+                      CString* proxy_ssl_host,
+                      CString* proxy_ssl_port) {
+    detector_->ParsePrefsLine(ansi_line,
+                              proxy_type,
+                              proxy_config_url,
+                              proxy_http_host,
+                              proxy_http_port,
+                              proxy_ssl_host,
+                              proxy_ssl_port);
+  }
+
+
+  HRESULT ParsePrefsFile(const TCHAR* name,
+                         const TCHAR* file_path,
+                         Config* config) {
+    return detector_->ParsePrefsFile(name, file_path, config);
+  }
+
+  // Builds a mock prefs file to test the parsing code.
+  bool BuildPrefsFile(const CString& type,
+                      const CString& config_url,
+                      const CString& http_host,
+                      const CString& http_port,
+                      const CString& ssl_host,
+                      const CString& ssl_port,
+                      CString* file_path);
+
+  scoped_ptr<FirefoxProxyDetector> detector_;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(FirefoxProxyDetectorTest);
+};
+
+bool FirefoxProxyDetectorTest::BuildPrefsFile(const CString& type,
+                                              const CString& config_url,
+                                              const CString& http_host,
+                                              const CString& http_port,
+                                              const CString& ssl_host,
+                                              const CString& ssl_port,
+                                              CString* file_path) {
+  CString temp_dir(app_util::GetTempDir());
+  file_path->Format(_T("%somaha_test_%x.js"), temp_dir, ::GetTickCount());
+
+  FILE* prefs_file = NULL;
+  fopen_s(&prefs_file, CStringA(*file_path), "w");
+  if (!prefs_file) {
+    return false;
+  }
+
+  fprintf(prefs_file,
+          "user_pref(\"network.proxy.type\", %s);\n",
+          CStringA(type));
+  fprintf(prefs_file,
+          "user_pref(\"network.proxy.autoconfig_url\", \"%s\");\n",
+          CStringA(config_url));
+  fprintf(prefs_file,
+          "user_pref(\"network.proxy.http\", \"%s\");\n",
+          CStringA(http_host));
+  fprintf(prefs_file,
+          "user_pref(\"network.proxy.http_port\", %s);\n",
+          CStringA(http_port));
+  fprintf(prefs_file,
+          "user_pref(\"network.proxy.ssl\", \"%s\");\n",
+          CStringA(ssl_host));
+  fprintf(prefs_file,
+          "user_pref(\"network.proxy.ssl_port\", %s);\n",
+          CStringA(ssl_port));
+
+  fclose(prefs_file);
+
+  return true;
+}
+
+TEST_F(FirefoxProxyDetectorTest, BuildProxyString) {
+  CString http_host = _T("foo");
+  CString http_port = _T("80");
+  CString ssl_host;
+  CString ssl_port;
+  CString proxy;
+
+  EXPECT_SUCCEEDED(BuildProxyString(http_host,
+                                    http_port,
+                                    ssl_host,
+                                    ssl_port,
+                                    &proxy));
+  EXPECT_STREQ(proxy, _T("http=foo:80"));
+
+  http_host = _T("foo");
+  http_port = _T("80");
+  ssl_host  = _T("bar");
+  ssl_port  = _T("8080");
+
+  EXPECT_SUCCEEDED(BuildProxyString(http_host,
+                                    http_port,
+                                    ssl_host,
+                                    ssl_port,
+                                    &proxy));
+  EXPECT_STREQ(proxy, _T("http=foo:80;https=bar:8080"));
+
+  http_host.Empty();
+  http_port.Empty();
+  ssl_host  = _T("bar");
+  ssl_port  = _T("8080");
+
+  EXPECT_SUCCEEDED(BuildProxyString(http_host,
+                                    http_port,
+                                    ssl_host,
+                                    ssl_port,
+                                    &proxy));
+  EXPECT_STREQ(proxy, _T("https=bar:8080"));
+}
+
+TEST_F(FirefoxProxyDetectorTest, ParsePrefsLine) {
+  CString type;
+  CString config_url;
+  CString http_host;
+  CString http_port;
+  CString ssl_host;
+  CString ssl_port;
+
+  // Parse "type".
+  const char* ansi_line = "user_pref(\"network.proxy.type\", 4);";
+  ParsePrefsLine(ansi_line,
+                 &type,
+                 &config_url,
+                 &http_host,
+                 &http_port,
+                 &ssl_host,
+                 &ssl_port);
+  EXPECT_STREQ(type, _T("4"));
+
+  // Parse "config_url".
+  ansi_line =
+      "user_pref(\"network.proxy.autoconfig_url\", \"http://wpad/wpad.dat\");";
+  ParsePrefsLine(ansi_line,
+                 &type,
+                 &config_url,
+                 &http_host,
+                 &http_port,
+                 &ssl_host,
+                 &ssl_port);
+  EXPECT_STREQ(config_url, _T("\"http://wpad/wpad.dat\""));
+
+  // Parse "http_host".
+  ansi_line = "user_pref(\"network.proxy.http\", \"127.0.0.1\");";
+  ParsePrefsLine(ansi_line,
+                 &type,
+                 &config_url,
+                 &http_host,
+                 &http_port,
+                 &ssl_host,
+                 &ssl_port);
+  EXPECT_STREQ(http_host, _T("\"127.0.0.1\""));
+
+  // Parse "http_port".
+  ansi_line = "user_pref(\"network.proxy.http_port\", 8888);";
+  ParsePrefsLine(ansi_line,
+                 &type,
+                 &config_url,
+                 &http_host,
+                 &http_port,
+                 &ssl_host,
+                 &ssl_port);
+  EXPECT_STREQ(http_port, _T("8888"));
+
+  // Parse "ssl_host".
+  ansi_line = "user_pref(\"network.proxy.ssl\", \"10.0.0.1\");";
+  ParsePrefsLine(ansi_line,
+                 &type,
+                 &config_url,
+                 &http_host,
+                 &http_port,
+                 &ssl_host,
+                 &ssl_port);
+  EXPECT_STREQ(ssl_host, _T("\"10.0.0.1\""));
+
+  // Parse "ssl_port".
+  ansi_line = "user_pref(\"network.proxy.ssl_port\", 8080);";
+  ParsePrefsLine(ansi_line,
+                 &type,
+                 &config_url,
+                 &http_host,
+                 &http_port,
+                 &ssl_host,
+                 &ssl_port);
+  EXPECT_STREQ(ssl_port, _T("8080"));
+}
+
+TEST_F(FirefoxProxyDetectorTest, ParsePrefsFile) {
+  // Direct connection
+  CString prefs_file;
+  bool res = BuildPrefsFile(_T("0"),
+                            _T("http://foobar"),
+                            _T("foo"),
+                            _T("80"),
+                            _T("bar"),
+                            _T("8080"),
+                            &prefs_file);
+  ASSERT_TRUE(res);
+  Config config;
+  EXPECT_SUCCEEDED(ParsePrefsFile(_T(""), prefs_file, &config));
+  EXPECT_FALSE(config.auto_detect);
+  EXPECT_TRUE(config.auto_config_url.IsEmpty());
+  EXPECT_TRUE(config.proxy.IsEmpty());
+  EXPECT_TRUE(config.proxy_bypass.IsEmpty());
+  EXPECT_TRUE(::DeleteFile(prefs_file));
+
+  // Named proxy.
+  res = BuildPrefsFile(_T("1"),
+                       _T("http://foobar"),
+                       _T("foo"),
+                       _T("80"),
+                       _T("bar"),
+                       _T("8080"),
+                       &prefs_file);
+  ASSERT_TRUE(res);
+  config = Config();
+  EXPECT_SUCCEEDED(ParsePrefsFile(_T(""), prefs_file, &config));
+  EXPECT_FALSE(config.auto_detect);
+  EXPECT_TRUE(config.auto_config_url.IsEmpty());
+  EXPECT_STREQ(config.proxy, _T("http=foo:80;https=bar:8080"));
+  EXPECT_TRUE(config.proxy_bypass.IsEmpty());
+  EXPECT_TRUE(::DeleteFile(prefs_file));
+
+  // Auto config url.
+  res = BuildPrefsFile(_T("2"),
+                       _T("http://foobar"),
+                       _T("foo"),
+                       _T("80"),
+                       _T("bar"),
+                       _T("8080"),
+                       &prefs_file);
+  ASSERT_TRUE(res);
+  config = Config();
+  EXPECT_SUCCEEDED(ParsePrefsFile(_T(""), prefs_file, &config));
+  EXPECT_FALSE(config.auto_detect);
+  EXPECT_STREQ(config.auto_config_url, _T("http://foobar"));
+  EXPECT_TRUE(config.proxy.IsEmpty());
+  EXPECT_TRUE(config.proxy_bypass.IsEmpty());
+  EXPECT_TRUE(::DeleteFile(prefs_file));
+
+  // Auto detect.
+  res = BuildPrefsFile(_T("4"),
+                       _T("http://foobar"),
+                       _T("foo"),
+                       _T("80"),
+                       _T("bar"),
+                       _T("8080"),
+                       &prefs_file);
+  ASSERT_TRUE(res);
+  config = Config();
+  EXPECT_SUCCEEDED(ParsePrefsFile(_T(""), prefs_file, &config));
+  EXPECT_TRUE(config.auto_detect);
+  EXPECT_TRUE(config.auto_config_url.IsEmpty());
+  EXPECT_TRUE(config.proxy.IsEmpty());
+  EXPECT_TRUE(config.proxy_bypass.IsEmpty());
+  EXPECT_TRUE(::DeleteFile(prefs_file));
+}
+
+// Tries to detect the configuration if a profile is available.
+TEST_F(FirefoxProxyDetectorTest, Detect) {
+  CString name, path;
+  if (FAILED(GetFirefoxDefaultProfile(&name, &path))) {
+    return;
+  }
+  Config config;
+  EXPECT_SUCCEEDED(detector_->Detect(&config));
+}
+
+}  // namespace omaha
+
diff --git a/net/http_client.cc b/net/http_client.cc
index 60671e3..d632494 100644
--- a/net/http_client.cc
+++ b/net/http_client.cc
@@ -1,168 +1,168 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// The code below is not thread safe.

-

-#include "omaha/net/http_client.h"

-

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-HttpClient::Factory* HttpClient::factory_ = NULL;

-

-HttpClient::Factory& HttpClient::GetFactory() {

-  if (!factory_) {

-    factory_ = new Factory();

-  }

-  return *factory_;

-}

-

-void HttpClient::DeleteFactory() {

-  delete factory_;

-  factory_ = NULL;

-}

-

-HttpClient* CreateHttpClient() {

-  HttpClient* http_client =

-    HttpClient::GetFactory().CreateObject(HttpClient::WINHTTP);

-  if (!http_client) {

-    http_client = HttpClient::GetFactory().CreateObject(HttpClient::WININET);

-  }

-  return http_client;

-}

-

-CString HttpClient::BuildRequestHeader(const TCHAR* name, const TCHAR* value) {

-  ASSERT1(name && *name);

-  ASSERT1(value && *value);

-  CString header;

-  header.Format(_T("%s: %s\r\n"), name, value);

-  return header;

-}

-

-HttpClient::StatusCodeClass HttpClient::GetStatusCodeClass(int status_code) {

-  ASSERT1(!status_code ||

-      (HTTP_STATUS_FIRST <= status_code && status_code <= HTTP_STATUS_LAST));

-  return static_cast<StatusCodeClass>(status_code / 100 * 100);

-}

-

-HRESULT HttpClient::QueryHeadersString(HINTERNET request_handle,

-                                       uint32 info_level,

-                                       const TCHAR* name,

-                                       CString* value,

-                                       DWORD* index) {

-  ASSERT1(value);

-

-  DWORD num_bytes = 0;

-  HRESULT hr = QueryHeaders(request_handle,

-                            info_level,

-                            name,

-                            NULL,

-                            &num_bytes,

-                            index);

-  if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {

-    return hr;

-  }

-  CString val;

-  hr = QueryHeaders(request_handle,

-                    info_level,

-                    name,

-                    val.GetBuffer(num_bytes/sizeof(TCHAR)),

-                    &num_bytes,

-                    index);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(num_bytes);

-  val.ReleaseBufferSetLength(num_bytes/sizeof(TCHAR));

-  *value = val;

-  return S_OK;

-}

-

-HRESULT HttpClient::QueryHeadersInt(HINTERNET request_handle,

-                                    uint32 info_level,

-                                    const TCHAR* name,

-                                    int* value,

-                                    DWORD* index) {

-  ASSERT1(value);

-  info_level |= WINHTTP_QUERY_FLAG_NUMBER;

-  DWORD value_size = sizeof(*value);

-  HRESULT hr = QueryHeaders(request_handle,

-                            info_level,

-                            name,

-                            value,

-                            &value_size,

-                            index);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(value_size == sizeof(*value));

-  return S_OK;

-}

-

-HRESULT HttpClient::QueryOptionString(HINTERNET handle,

-                                      uint32 option,

-                                      CString* value) {

-  ASSERT1(value);

-  DWORD num_bytes = 0;

-  HRESULT hr = QueryOption(handle, option, NULL, &num_bytes);

-  DWORD last_error = ::GetLastError();

-  if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {

-    return hr;

-  }

-  ASSERT1(num_bytes);

-  CString val;

-  hr = QueryOption(handle, option, val.GetBuffer(num_bytes), &num_bytes);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(num_bytes);

-  val.ReleaseBufferSetLength(num_bytes/sizeof(TCHAR));

-  *value = val;

-  return S_OK;

-}

-

-HRESULT HttpClient::QueryOptionInt(HINTERNET handle,

-                                   uint32 option,

-                                   int* value) {

-  ASSERT1(value);

-  DWORD val = 0;

-  DWORD num_bytes = sizeof(val);

-  HRESULT hr = QueryOption(handle, option, &val, &num_bytes);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(num_bytes == sizeof(val));

-  *value = val;

-  return S_OK;

-}

-

-HRESULT HttpClient::SetOptionString(HINTERNET handle,

-                                    uint32 option,

-                                    const TCHAR* value) {

-  ASSERT1(value);

-  const void* buffer = value;

-  DWORD buffer_length = _tcslen(value) * sizeof(TCHAR);

-  return SetOption(handle, option, buffer, buffer_length);

-}

-

-HRESULT HttpClient::SetOptionInt(HINTERNET handle, uint32 option, int value) {

-  DWORD val = value;

-  return SetOption(handle, option, &val, sizeof(val));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// The code below is not thread safe.
+
+#include "omaha/net/http_client.h"
+
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+HttpClient::Factory* HttpClient::factory_ = NULL;
+
+HttpClient::Factory& HttpClient::GetFactory() {
+  if (!factory_) {
+    factory_ = new Factory();
+  }
+  return *factory_;
+}
+
+void HttpClient::DeleteFactory() {
+  delete factory_;
+  factory_ = NULL;
+}
+
+HttpClient* CreateHttpClient() {
+  HttpClient* http_client =
+    HttpClient::GetFactory().CreateObject(HttpClient::WINHTTP);
+  if (!http_client) {
+    http_client = HttpClient::GetFactory().CreateObject(HttpClient::WININET);
+  }
+  return http_client;
+}
+
+CString HttpClient::BuildRequestHeader(const TCHAR* name, const TCHAR* value) {
+  ASSERT1(name && *name);
+  ASSERT1(value && *value);
+  CString header;
+  header.Format(_T("%s: %s\r\n"), name, value);
+  return header;
+}
+
+HttpClient::StatusCodeClass HttpClient::GetStatusCodeClass(int status_code) {
+  ASSERT1(!status_code ||
+      (HTTP_STATUS_FIRST <= status_code && status_code <= HTTP_STATUS_LAST));
+  return static_cast<StatusCodeClass>(status_code / 100 * 100);
+}
+
+HRESULT HttpClient::QueryHeadersString(HINTERNET request_handle,
+                                       uint32 info_level,
+                                       const TCHAR* name,
+                                       CString* value,
+                                       DWORD* index) {
+  ASSERT1(value);
+
+  DWORD num_bytes = 0;
+  HRESULT hr = QueryHeaders(request_handle,
+                            info_level,
+                            name,
+                            NULL,
+                            &num_bytes,
+                            index);
+  if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
+    return hr;
+  }
+  CString val;
+  hr = QueryHeaders(request_handle,
+                    info_level,
+                    name,
+                    val.GetBuffer(num_bytes/sizeof(TCHAR)),
+                    &num_bytes,
+                    index);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(num_bytes);
+  val.ReleaseBufferSetLength(num_bytes/sizeof(TCHAR));
+  *value = val;
+  return S_OK;
+}
+
+HRESULT HttpClient::QueryHeadersInt(HINTERNET request_handle,
+                                    uint32 info_level,
+                                    const TCHAR* name,
+                                    int* value,
+                                    DWORD* index) {
+  ASSERT1(value);
+  info_level |= WINHTTP_QUERY_FLAG_NUMBER;
+  DWORD value_size = sizeof(*value);
+  HRESULT hr = QueryHeaders(request_handle,
+                            info_level,
+                            name,
+                            value,
+                            &value_size,
+                            index);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(value_size == sizeof(*value));
+  return S_OK;
+}
+
+HRESULT HttpClient::QueryOptionString(HINTERNET handle,
+                                      uint32 option,
+                                      CString* value) {
+  ASSERT1(value);
+  DWORD num_bytes = 0;
+  HRESULT hr = QueryOption(handle, option, NULL, &num_bytes);
+  DWORD last_error = ::GetLastError();
+  if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
+    return hr;
+  }
+  ASSERT1(num_bytes);
+  CString val;
+  hr = QueryOption(handle, option, val.GetBuffer(num_bytes), &num_bytes);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(num_bytes);
+  val.ReleaseBufferSetLength(num_bytes/sizeof(TCHAR));
+  *value = val;
+  return S_OK;
+}
+
+HRESULT HttpClient::QueryOptionInt(HINTERNET handle,
+                                   uint32 option,
+                                   int* value) {
+  ASSERT1(value);
+  DWORD val = 0;
+  DWORD num_bytes = sizeof(val);
+  HRESULT hr = QueryOption(handle, option, &val, &num_bytes);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(num_bytes == sizeof(val));
+  *value = val;
+  return S_OK;
+}
+
+HRESULT HttpClient::SetOptionString(HINTERNET handle,
+                                    uint32 option,
+                                    const TCHAR* value) {
+  ASSERT1(value);
+  const void* buffer = value;
+  DWORD buffer_length = _tcslen(value) * sizeof(TCHAR);
+  return SetOption(handle, option, buffer, buffer_length);
+}
+
+HRESULT HttpClient::SetOptionInt(HINTERNET handle, uint32 option, int value) {
+  DWORD val = value;
+  return SetOption(handle, option, &val, sizeof(val));
+}
+
+}  // namespace omaha
+
diff --git a/net/http_client.h b/net/http_client.h
index 663dfae..da7208a 100644
--- a/net/http_client.h
+++ b/net/http_client.h
@@ -1,343 +1,343 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// HttpClient provides a wrapper for WinHTTP and some helpers to make it

-// easy to call it from c++.

-

-// Runtime requirements: WinHTTP 5.1 is now an operating-system component of

-// the following systems:

-// - Windows Vista

-// - Windows Server 2003 family

-// - Windows XP SP1

-// - Windows 2000 SP3 (except Datacenter Server)

-//

-// TODO(omaha): fix prototype of several methods to take size_t instead of int

-// TODO(omaha): there are many overloads that do not have to be virtual.

-// TODO(omaha): in the end HttpClient is just a c++ wrapper for WinHttp. Some

-//              refactoring may be needed, for example to provide access to

-//              the internal session and connection handles. It may make sense

-//              to reuse these handles, most likely the session handle.

-// TODO(omaha): the idea of implementing the winhttp interface on top of

-//              wininet seems impractical now, as they may be subtle

-//              differences in behavior. The fallback on wininet when winhttp

-//              is not available could be better done by using the higher

-//              level urlmon functions, which perhaps we should do anyway,

-//              just in case winhttp is not working for some reason or bug.

-//              Since now we are not doing downloads in any of our long lived

-//              processes, the handle and memory leaks do not affect us much.

-

-#ifndef OMAHA_NET_HTTP_CLIENT_H__

-#define OMAHA_NET_HTTP_CLIENT_H__

-

-#include <windows.h>

-#include <atlstr.h>

-

-#if !defined(_WININET_)

-#include <winhttp.h>    // NOLINT

-

-  // The following definitions are missing in winhttp.h

-#define INTERNET_MAX_HOST_NAME_LENGTH   256

-#define INTERNET_MAX_USER_NAME_LENGTH   128

-#define INTERNET_MAX_PASSWORD_LENGTH    128

-#define INTERNET_MAX_PORT_NUMBER_LENGTH 5

-#define INTERNET_MAX_PORT_NUMBER_VALUE  65535

-#define INTERNET_MAX_PATH_LENGTH        2048

-#define INTERNET_MAX_SCHEME_LENGTH      32

-#define INTERNET_MAX_URL_LENGTH         (INTERNET_MAX_SCHEME_LENGTH \

-                                        + sizeof("://") \

-                                        + INTERNET_MAX_PATH_LENGTH)

-#endif

-

-// This is a definition we made up for convenience, just to be consistent with

-// the other types of network access.

-#define WINHTTP_ACCESS_TYPE_AUTO_DETECT 2

-

-#include "base/basictypes.h"

-#include "omaha/common/object_factory.h"

-

-namespace omaha {

-

-const TCHAR* const kHttpGetMethod = _T("GET");

-const TCHAR* const kHttpPostMethod = _T("POST");

-const TCHAR* const kHttpContentLengthHeader = _T("Content-Length");

-const TCHAR* const kHttpContentTypeHeader = _T("Content-Type");

-const TCHAR* const kHttpLastModifiedHeader = _T("Last-Modified");

-const TCHAR* const kHttpIfModifiedSinceHeader = _T("If-Modified-Since");

-const TCHAR* const kHttpPostTextContentType =

-                _T("application/x-www-form-urlencoded");

-const TCHAR* const kHttpPostRawContentType = _T("application/octet-stream");

-const TCHAR* const kHttpBinaryContentType =_T("binary");

-const TCHAR* const kHttpXmlContentType =_T("application/xml");

-

-class HttpClient {

- public:

-  enum HttpStack {WINHTTP, WININET};

-

-  // Use registry for network configuration info.

-  static const int kAccessTypeDefaultProxy  = 0;

-  // Unconditional direct connection.

-  static const int kAccessTypeNoProxy       = 1;

-  // Use the specified proxy server.

-  static const int kAccessTypeNamedProxy    = 3;

-

-  // GetFactory and DeleteFactory methods below are not thread safe.

-  // The caller must initialize and cleanup the factory before going

-  // multithreaded.

-  //

-  // Gets the singleton instance of the object factory.

-  typedef Factory<HttpClient, HttpStack> Factory;

-  static Factory& GetFactory();

-

-  // Cleans up the object factory.

-  static void DeleteFactory();

-

-  struct ProxyInfo {

-    uint32 access_type;

-    const TCHAR* proxy;

-    const TCHAR* proxy_bypass;

-  };

-

-  struct CurrentUserIEProxyConfig {

-    bool auto_detect;

-    const TCHAR* auto_config_url;

-    const TCHAR* proxy;

-    const TCHAR* proxy_bypass;

-  };

-

-  struct AutoProxyOptions {

-    uint32 flags;

-    uint32 auto_detect_flags;

-    const TCHAR* auto_config_url;

-    bool auto_logon_if_challenged;

-  };

-

-  virtual ~HttpClient() {}

-

-  // Initializes the use of http functions by loading the corresponding http

-  // stack.

-  virtual HRESULT Initialize() = 0;

-

-  // Adds one or more http request headers to the http request.

-  virtual HRESULT AddRequestHeaders(HINTERNET request,

-                                    const TCHAR* headers,

-                                    int length,

-                                    uint32 modifiers) = 0;

-

-  // Determines whether WinHTTP is available.

-  virtual HRESULT CheckPlatform() = 0;

-

-  // Closes an http handle.

-  virtual HRESULT Close(HINTERNET handle) = 0;

-

-  // Specifies the initial server and port of an http request.

-  virtual HRESULT Connect(HINTERNET session_handle,

-                          const TCHAR* server,

-                          int port,

-                          HINTERNET* connection_handle) = 0;

-

-  // Breaks urls into component parts.

-  virtual HRESULT CrackUrl(const TCHAR* url,

-                           uint32 flags,

-                           CString* scheme,

-                           CString* server,

-                           int* port,

-                           CString* url_path,

-                           CString* extra_info) = 0;

-

-  // Builds a url from component parts.

-  virtual HRESULT CreateUrl(const TCHAR* scheme,

-                            const TCHAR* server,

-                            int port,

-                            const TCHAR* url_path,

-                            const TCHAR* extra_info,

-                            uint32 flags,

-                            CString* url) = 0;

-

-

-  // Finds the url for the proxy auto-configuration (PAC) file.

-  // It reports the url of the PAC file but it does not download the file.

-  virtual HRESULT DetectAutoProxyConfigUrl(uint32 flags,

-                                           CString* auto_config_url) = 0;

-

-  // Gets the proxy configuration from the registry.

-  virtual HRESULT GetDefaultProxyConfiguration(ProxyInfo* proxy_info) = 0;

-

-  // Gets the Internet Explorer configuration for the current user.

-  virtual HRESULT GetIEProxyConfiguration(

-                      CurrentUserIEProxyConfig* proxy_info) = 0;

-

-  // Gets the proxy information for an url. This function implements the

-  // web proxy auto-discovery (WPAD) protocol for automatically configuring

-  // the proxy settings for an http request. The WPAD protocol downloads a

-  // proxy auto-configuration (PAC) file, which is a script that identifies

-  // the proxy server to use for a given target url.

-  virtual HRESULT GetProxyForUrl(HINTERNET session_handle,

-                                 const TCHAR* url,

-                                 const AutoProxyOptions* auto_proxy_options,

-                                 ProxyInfo* proxy_info) = 0;

-

-  // Opens a new http session. The http session contains user specific state

-  // such as cookies, proxy, and authentication credentials.

-  virtual HRESULT Open(const TCHAR* user_agent,

-                       uint32 access_type,

-                       const TCHAR* proxy_name,

-                       const TCHAR* proxy_bypass,

-                       HINTERNET* session_handle) = 0;

-

-  // Specifies the http request.

-  virtual HRESULT OpenRequest(HINTERNET connection_handle,

-                              const TCHAR* verb,

-                              const TCHAR* uri,

-                              const TCHAR* version,

-                              const TCHAR* referrer,

-                              const TCHAR** accept_types,

-                              uint32 flags,

-                              HINTERNET* request_handle) = 0;

-

-  // Returns the authorization schemes that are supported by the server or

-  // the proxy server.

-  virtual HRESULT QueryAuthSchemes(HINTERNET request_handle,

-                                   uint32* supported_schemes,

-                                   uint32* first_scheme,

-                                   uint32* auth_target) = 0;

-

-  // Returns the amount of data, in bytes, available to be read.

-  virtual HRESULT QueryDataAvailable(HINTERNET request_handle,

-                                     DWORD* num_bytes) = 0;

-

-  // Retrieves header information associated with the request.

-  virtual HRESULT QueryHeaders(HINTERNET request_handle,

-                               uint32 info_level,

-                               const TCHAR* name,

-                               void* buffer,

-                               DWORD* buffer_length,

-                               DWORD* index) = 0;

-

-  // Queries an internet option.

-  virtual HRESULT QueryOption(HINTERNET handle,

-                              uint32 option,

-                              void* buffer,

-                              DWORD* buffer_length) = 0;

-

-  // Reads response data.

-  virtual HRESULT ReadData(HINTERNET request_handle,

-                           void* buffer,

-                           DWORD buffer_length,

-                           DWORD* bytes_read) = 0;

-

-  // Waits to receive the response to an HTTP request. When ReceiveResponse

-  // completes successfully, the status code and response headers have been

-  // received.

-  virtual HRESULT ReceiveResponse(HINTERNET request_handle) = 0;

-

-  // Sends the request to the server. It also allows to send optional data

-  // for POST requests.

-  virtual HRESULT SendRequest(HINTERNET request_handle,

-                              const TCHAR* headers,

-                              DWORD headers_length,

-                              const void* optional_data,

-                              DWORD optional_data_length,

-                              DWORD content_length) = 0;

-

-  // Sets the authentication credentials.

-  virtual HRESULT SetCredentials(HINTERNET request_handle,

-                                 uint32 auth_targets,

-                                 uint32 auth_scheme,

-                                 const TCHAR* user_name,

-                                 const TCHAR* password) = 0;

-

-  // Sets the proxy configuration in registry.

-  virtual HRESULT SetDefaultProxyConfiguration(const ProxyInfo& proxy_info) = 0;

-

-  // Sets an internet option, either for the session or the request handle.

-  virtual HRESULT SetOption(HINTERNET handle,

-                            uint32 option,

-                            const void* buffer,

-                            DWORD buffer_length) = 0;

-

-  typedef void (__stdcall *StatusCallback)(HINTERNET handle,

-                                           uint32 context,

-                                           uint32 status,

-                                           void* status_information,

-                                           size_t status_info_length);

-  virtual StatusCallback SetStatusCallback(HINTERNET handle,

-                                           StatusCallback callback,

-                                           uint32 flags) = 0;

-

-  // Sets timeout values for this http request.

-  virtual HRESULT SetTimeouts(HINTERNET handle,

-                              int resolve_timeout_ms,

-                              int connect_timeout_ms,

-                              int send_timeout_ms,

-                              int receive_timeout_ms) = 0;

-

-  // Writes data to the server.

-  virtual HRESULT WriteData(HINTERNET request_handle,

-                            const void* buffer,

-                            DWORD bytes_to_write,

-                            DWORD* bytes_written) = 0;

-

-  //

-  // Http helpers.

-  //

-  // Builds one http header entry, with the following format:

-  //    name: value\r\n

-  static CString BuildRequestHeader(const TCHAR* name, const TCHAR* value);

-

-  enum StatusCodeClass {

-    STATUS_CODE_NOCODE        = 0,

-    STATUS_CODE_INFORMATIONAL = 100,

-    STATUS_CODE_SUCCESSFUL    = 200,

-    STATUS_CODE_REDIRECTION   = 300,

-    STATUS_CODE_CLIENT_ERROR  = 400,

-    STATUS_CODE_SERVER_ERROR  = 500

-  };

-  // Returns the class of a status code, such as 100, 200...

-  static StatusCodeClass GetStatusCodeClass(int status_code);

-

-  HRESULT QueryHeadersString(HINTERNET request_handle,

-                             uint32 info_level,

-                             const TCHAR* name,

-                             CString* value,

-                             DWORD* index);

-  HRESULT QueryHeadersInt(HINTERNET request_handle,

-                          uint32 info_level,

-                          const TCHAR* name,

-                          int* value,

-                          DWORD* index);

-

-  HRESULT QueryOptionString(HINTERNET handle, uint32 option, CString* value);

-  HRESULT QueryOptionInt(HINTERNET handle, uint32 option, int* value);

-

-  HRESULT SetOptionString(HINTERNET handle, uint32 option, const TCHAR* value);

-  HRESULT SetOptionInt(HINTERNET handle, uint32 option, int value);

-

- protected:

-  HttpClient() {}

-

- private:

-  static Factory* factory_;

-  DISALLOW_EVIL_CONSTRUCTORS(HttpClient);

-};

-

-// Creates an http client, depending on what is available on the platform.

-// WinHttp is preferred over WinInet.

-HttpClient* CreateHttpClient();

-

-}  // namespace omaha

-

-#endif  // OMAHA_NET_HTTP_CLIENT_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// HttpClient provides a wrapper for WinHTTP and some helpers to make it
+// easy to call it from c++.
+
+// Runtime requirements: WinHTTP 5.1 is now an operating-system component of
+// the following systems:
+// - Windows Vista
+// - Windows Server 2003 family
+// - Windows XP SP1
+// - Windows 2000 SP3 (except Datacenter Server)
+//
+// TODO(omaha): fix prototype of several methods to take size_t instead of int
+// TODO(omaha): there are many overloads that do not have to be virtual.
+// TODO(omaha): in the end HttpClient is just a c++ wrapper for WinHttp. Some
+//              refactoring may be needed, for example to provide access to
+//              the internal session and connection handles. It may make sense
+//              to reuse these handles, most likely the session handle.
+// TODO(omaha): the idea of implementing the winhttp interface on top of
+//              wininet seems impractical now, as they may be subtle
+//              differences in behavior. The fallback on wininet when winhttp
+//              is not available could be better done by using the higher
+//              level urlmon functions, which perhaps we should do anyway,
+//              just in case winhttp is not working for some reason or bug.
+//              Since now we are not doing downloads in any of our long lived
+//              processes, the handle and memory leaks do not affect us much.
+
+#ifndef OMAHA_NET_HTTP_CLIENT_H__
+#define OMAHA_NET_HTTP_CLIENT_H__
+
+#include <windows.h>
+#include <atlstr.h>
+
+#if !defined(_WININET_)
+#include <winhttp.h>    // NOLINT
+
+  // The following definitions are missing in winhttp.h
+#define INTERNET_MAX_HOST_NAME_LENGTH   256
+#define INTERNET_MAX_USER_NAME_LENGTH   128
+#define INTERNET_MAX_PASSWORD_LENGTH    128
+#define INTERNET_MAX_PORT_NUMBER_LENGTH 5
+#define INTERNET_MAX_PORT_NUMBER_VALUE  65535
+#define INTERNET_MAX_PATH_LENGTH        2048
+#define INTERNET_MAX_SCHEME_LENGTH      32
+#define INTERNET_MAX_URL_LENGTH         (INTERNET_MAX_SCHEME_LENGTH \
+                                        + sizeof("://") \
+                                        + INTERNET_MAX_PATH_LENGTH)
+#endif
+
+// This is a definition we made up for convenience, just to be consistent with
+// the other types of network access.
+#define WINHTTP_ACCESS_TYPE_AUTO_DETECT 2
+
+#include "base/basictypes.h"
+#include "omaha/common/object_factory.h"
+
+namespace omaha {
+
+const TCHAR* const kHttpGetMethod = _T("GET");
+const TCHAR* const kHttpPostMethod = _T("POST");
+const TCHAR* const kHttpContentLengthHeader = _T("Content-Length");
+const TCHAR* const kHttpContentTypeHeader = _T("Content-Type");
+const TCHAR* const kHttpLastModifiedHeader = _T("Last-Modified");
+const TCHAR* const kHttpIfModifiedSinceHeader = _T("If-Modified-Since");
+const TCHAR* const kHttpPostTextContentType =
+                _T("application/x-www-form-urlencoded");
+const TCHAR* const kHttpPostRawContentType = _T("application/octet-stream");
+const TCHAR* const kHttpBinaryContentType =_T("binary");
+const TCHAR* const kHttpXmlContentType =_T("application/xml");
+
+class HttpClient {
+ public:
+  enum HttpStack {WINHTTP, WININET};
+
+  // Use registry for network configuration info.
+  static const int kAccessTypeDefaultProxy  = 0;
+  // Unconditional direct connection.
+  static const int kAccessTypeNoProxy       = 1;
+  // Use the specified proxy server.
+  static const int kAccessTypeNamedProxy    = 3;
+
+  // GetFactory and DeleteFactory methods below are not thread safe.
+  // The caller must initialize and cleanup the factory before going
+  // multithreaded.
+  //
+  // Gets the singleton instance of the object factory.
+  typedef Factory<HttpClient, HttpStack> Factory;
+  static Factory& GetFactory();
+
+  // Cleans up the object factory.
+  static void DeleteFactory();
+
+  struct ProxyInfo {
+    uint32 access_type;
+    const TCHAR* proxy;
+    const TCHAR* proxy_bypass;
+  };
+
+  struct CurrentUserIEProxyConfig {
+    bool auto_detect;
+    const TCHAR* auto_config_url;
+    const TCHAR* proxy;
+    const TCHAR* proxy_bypass;
+  };
+
+  struct AutoProxyOptions {
+    uint32 flags;
+    uint32 auto_detect_flags;
+    const TCHAR* auto_config_url;
+    bool auto_logon_if_challenged;
+  };
+
+  virtual ~HttpClient() {}
+
+  // Initializes the use of http functions by loading the corresponding http
+  // stack.
+  virtual HRESULT Initialize() = 0;
+
+  // Adds one or more http request headers to the http request.
+  virtual HRESULT AddRequestHeaders(HINTERNET request,
+                                    const TCHAR* headers,
+                                    int length,
+                                    uint32 modifiers) = 0;
+
+  // Determines whether WinHTTP is available.
+  virtual HRESULT CheckPlatform() = 0;
+
+  // Closes an http handle.
+  virtual HRESULT Close(HINTERNET handle) = 0;
+
+  // Specifies the initial server and port of an http request.
+  virtual HRESULT Connect(HINTERNET session_handle,
+                          const TCHAR* server,
+                          int port,
+                          HINTERNET* connection_handle) = 0;
+
+  // Breaks urls into component parts.
+  virtual HRESULT CrackUrl(const TCHAR* url,
+                           uint32 flags,
+                           CString* scheme,
+                           CString* server,
+                           int* port,
+                           CString* url_path,
+                           CString* extra_info) = 0;
+
+  // Builds a url from component parts.
+  virtual HRESULT CreateUrl(const TCHAR* scheme,
+                            const TCHAR* server,
+                            int port,
+                            const TCHAR* url_path,
+                            const TCHAR* extra_info,
+                            uint32 flags,
+                            CString* url) = 0;
+
+
+  // Finds the url for the proxy auto-configuration (PAC) file.
+  // It reports the url of the PAC file but it does not download the file.
+  virtual HRESULT DetectAutoProxyConfigUrl(uint32 flags,
+                                           CString* auto_config_url) = 0;
+
+  // Gets the proxy configuration from the registry.
+  virtual HRESULT GetDefaultProxyConfiguration(ProxyInfo* proxy_info) = 0;
+
+  // Gets the Internet Explorer configuration for the current user.
+  virtual HRESULT GetIEProxyConfiguration(
+                      CurrentUserIEProxyConfig* proxy_info) = 0;
+
+  // Gets the proxy information for an url. This function implements the
+  // web proxy auto-discovery (WPAD) protocol for automatically configuring
+  // the proxy settings for an http request. The WPAD protocol downloads a
+  // proxy auto-configuration (PAC) file, which is a script that identifies
+  // the proxy server to use for a given target url.
+  virtual HRESULT GetProxyForUrl(HINTERNET session_handle,
+                                 const TCHAR* url,
+                                 const AutoProxyOptions* auto_proxy_options,
+                                 ProxyInfo* proxy_info) = 0;
+
+  // Opens a new http session. The http session contains user specific state
+  // such as cookies, proxy, and authentication credentials.
+  virtual HRESULT Open(const TCHAR* user_agent,
+                       uint32 access_type,
+                       const TCHAR* proxy_name,
+                       const TCHAR* proxy_bypass,
+                       HINTERNET* session_handle) = 0;
+
+  // Specifies the http request.
+  virtual HRESULT OpenRequest(HINTERNET connection_handle,
+                              const TCHAR* verb,
+                              const TCHAR* uri,
+                              const TCHAR* version,
+                              const TCHAR* referrer,
+                              const TCHAR** accept_types,
+                              uint32 flags,
+                              HINTERNET* request_handle) = 0;
+
+  // Returns the authorization schemes that are supported by the server or
+  // the proxy server.
+  virtual HRESULT QueryAuthSchemes(HINTERNET request_handle,
+                                   uint32* supported_schemes,
+                                   uint32* first_scheme,
+                                   uint32* auth_target) = 0;
+
+  // Returns the amount of data, in bytes, available to be read.
+  virtual HRESULT QueryDataAvailable(HINTERNET request_handle,
+                                     DWORD* num_bytes) = 0;
+
+  // Retrieves header information associated with the request.
+  virtual HRESULT QueryHeaders(HINTERNET request_handle,
+                               uint32 info_level,
+                               const TCHAR* name,
+                               void* buffer,
+                               DWORD* buffer_length,
+                               DWORD* index) = 0;
+
+  // Queries an internet option.
+  virtual HRESULT QueryOption(HINTERNET handle,
+                              uint32 option,
+                              void* buffer,
+                              DWORD* buffer_length) = 0;
+
+  // Reads response data.
+  virtual HRESULT ReadData(HINTERNET request_handle,
+                           void* buffer,
+                           DWORD buffer_length,
+                           DWORD* bytes_read) = 0;
+
+  // Waits to receive the response to an HTTP request. When ReceiveResponse
+  // completes successfully, the status code and response headers have been
+  // received.
+  virtual HRESULT ReceiveResponse(HINTERNET request_handle) = 0;
+
+  // Sends the request to the server. It also allows to send optional data
+  // for POST requests.
+  virtual HRESULT SendRequest(HINTERNET request_handle,
+                              const TCHAR* headers,
+                              DWORD headers_length,
+                              const void* optional_data,
+                              DWORD optional_data_length,
+                              DWORD content_length) = 0;
+
+  // Sets the authentication credentials.
+  virtual HRESULT SetCredentials(HINTERNET request_handle,
+                                 uint32 auth_targets,
+                                 uint32 auth_scheme,
+                                 const TCHAR* user_name,
+                                 const TCHAR* password) = 0;
+
+  // Sets the proxy configuration in registry.
+  virtual HRESULT SetDefaultProxyConfiguration(const ProxyInfo& proxy_info) = 0;
+
+  // Sets an internet option, either for the session or the request handle.
+  virtual HRESULT SetOption(HINTERNET handle,
+                            uint32 option,
+                            const void* buffer,
+                            DWORD buffer_length) = 0;
+
+  typedef void (__stdcall *StatusCallback)(HINTERNET handle,
+                                           uint32 context,
+                                           uint32 status,
+                                           void* status_information,
+                                           size_t status_info_length);
+  virtual StatusCallback SetStatusCallback(HINTERNET handle,
+                                           StatusCallback callback,
+                                           uint32 flags) = 0;
+
+  // Sets timeout values for this http request.
+  virtual HRESULT SetTimeouts(HINTERNET handle,
+                              int resolve_timeout_ms,
+                              int connect_timeout_ms,
+                              int send_timeout_ms,
+                              int receive_timeout_ms) = 0;
+
+  // Writes data to the server.
+  virtual HRESULT WriteData(HINTERNET request_handle,
+                            const void* buffer,
+                            DWORD bytes_to_write,
+                            DWORD* bytes_written) = 0;
+
+  //
+  // Http helpers.
+  //
+  // Builds one http header entry, with the following format:
+  //    name: value\r\n
+  static CString BuildRequestHeader(const TCHAR* name, const TCHAR* value);
+
+  enum StatusCodeClass {
+    STATUS_CODE_NOCODE        = 0,
+    STATUS_CODE_INFORMATIONAL = 100,
+    STATUS_CODE_SUCCESSFUL    = 200,
+    STATUS_CODE_REDIRECTION   = 300,
+    STATUS_CODE_CLIENT_ERROR  = 400,
+    STATUS_CODE_SERVER_ERROR  = 500
+  };
+  // Returns the class of a status code, such as 100, 200...
+  static StatusCodeClass GetStatusCodeClass(int status_code);
+
+  HRESULT QueryHeadersString(HINTERNET request_handle,
+                             uint32 info_level,
+                             const TCHAR* name,
+                             CString* value,
+                             DWORD* index);
+  HRESULT QueryHeadersInt(HINTERNET request_handle,
+                          uint32 info_level,
+                          const TCHAR* name,
+                          int* value,
+                          DWORD* index);
+
+  HRESULT QueryOptionString(HINTERNET handle, uint32 option, CString* value);
+  HRESULT QueryOptionInt(HINTERNET handle, uint32 option, int* value);
+
+  HRESULT SetOptionString(HINTERNET handle, uint32 option, const TCHAR* value);
+  HRESULT SetOptionInt(HINTERNET handle, uint32 option, int value);
+
+ protected:
+  HttpClient() {}
+
+ private:
+  static Factory* factory_;
+  DISALLOW_EVIL_CONSTRUCTORS(HttpClient);
+};
+
+// Creates an http client, depending on what is available on the platform.
+// WinHttp is preferred over WinInet.
+HttpClient* CreateHttpClient();
+
+}  // namespace omaha
+
+#endif  // OMAHA_NET_HTTP_CLIENT_H__
+
diff --git a/net/http_client_unittest.cc b/net/http_client_unittest.cc
index 1d520f0..897c984 100644
--- a/net/http_client_unittest.cc
+++ b/net/http_client_unittest.cc
@@ -1,236 +1,236 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// Since the net code is linked in as a lib, force the registration code to

-// be a dependency, otherwise the linker is optimizing in out.

-#pragma comment(linker, "/INCLUDE:_kRegisterWinHttp")

-

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/net/http_client.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Test fixture, perhaps we need it later.

-class HttpClientTest : public testing::Test {

- protected:

-  HttpClientTest() {}

-

-  static void SetUpTestCase() {}

-

-  virtual void SetUp() {

-    http_client_.reset(

-        HttpClient::GetFactory().CreateObject(HttpClient::WINHTTP));

-    ASSERT_TRUE(http_client_.get());

-    ASSERT_SUCCEEDED(http_client_->Initialize());

-  }

-

-  virtual void TearDown() {

-    http_client_.reset();

-  }

-

-  void GetUrl(const TCHAR* url, bool use_proxy);

-

-  scoped_ptr<HttpClient> http_client_;

-};

-

-CString BuildUserAgent() {

-  CString user_agent;

-  user_agent.Format(_T("HttpClientTest version %s"), omaha::GetVersionString());

-  return user_agent;

-}

-

-const TCHAR kTestUrlGet[]       = _T("http://www.google.com/robots.txt");

-const TCHAR kTestSecureUrlGet[] = _T("https://www.google.com/robots.txt");

-

-// If using a proxy is specified, the function does WPAD detection to get the

-// name of the proxy to be used. The request goes direct if the WPAD fails.

-void HttpClientTest::GetUrl(const TCHAR* url, bool use_proxy) {

-  ASSERT_TRUE(url);

-

-  CString server, path;

-  int port = 0;

-  ASSERT_SUCCEEDED(http_client_->CrackUrl(url,

-                                          ICU_DECODE,

-                                          NULL,

-                                          &server,

-                                          &port,

-                                          &path,

-                                          NULL));

-  ASSERT_STREQ(server, _T("www.google.com"));

-  ASSERT_STREQ(path, _T("/robots.txt"));

-

-  HINTERNET session_handle = NULL;

-  ASSERT_SUCCEEDED(http_client_->Open(BuildUserAgent(),

-                                      HttpClient::kAccessTypeNoProxy,

-                                      NULL,

-                                      NULL,

-                                      &session_handle));

-  if (use_proxy) {

-    HttpClient::AutoProxyOptions autoproxy_options = {0};

-    autoproxy_options.flags = WINHTTP_AUTOPROXY_AUTO_DETECT;

-    autoproxy_options.auto_detect_flags = WINHTTP_AUTO_DETECT_TYPE_DHCP |

-                                          WINHTTP_AUTO_DETECT_TYPE_DNS_A;

-    autoproxy_options.auto_logon_if_challenged = true;

-    HttpClient::ProxyInfo proxy_info = {0};

-    http_client_->GetProxyForUrl(session_handle,

-                                 url,

-                                 &autoproxy_options,

-                                 &proxy_info);

-    if (proxy_info.proxy && wcslen(proxy_info.proxy)) {

-      proxy_info.access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;

-      EXPECT_SUCCEEDED(http_client_->SetOption(session_handle,

-                                               WINHTTP_OPTION_PROXY,

-                                               &proxy_info,

-                                               sizeof(proxy_info)));

-    }

-    ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy));

-    ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy_bypass));

-  }

-

-  HINTERNET connection_handle = NULL;

-  ASSERT_SUCCEEDED(http_client_->Connect(session_handle,

-                                         server,

-                                         port,

-                                         &connection_handle));

-  uint32 flags = port == 443 ? WINHTTP_FLAG_SECURE : 0;

-  HINTERNET request_handle = NULL;

-  ASSERT_SUCCEEDED(http_client_->OpenRequest(connection_handle,

-                                             _T("GET"),

-                                             path,

-                                             NULL,     // HTTP 1.1

-                                             NULL,     // Referrer.

-                                             NULL,     // Default accept types.

-                                             flags,

-                                             &request_handle));

-  ASSERT_SUCCEEDED(http_client_->SendRequest(request_handle,

-                                             NULL, 0, NULL, 0, 0));

-  ASSERT_SUCCEEDED(http_client_->ReceiveResponse(request_handle));

-  CString content_type;

-  EXPECT_SUCCEEDED(http_client_->QueryHeadersString(request_handle,

-                                                    WINHTTP_QUERY_CONTENT_TYPE,

-                                                    NULL,

-                                                    &content_type,

-                                                    NULL));

-  EXPECT_STREQ(content_type, _T("text/plain"));

-  CString server_header;

-  EXPECT_SUCCEEDED(http_client_->QueryHeadersString(request_handle,

-                                                    WINHTTP_QUERY_SERVER,

-                                                    NULL,

-                                                    &server_header,

-                                                    NULL));

-  CString response;

-  DWORD size = 0;

-  do {

-    // Use ReadData to determine when a response has been completely read.

-    // Always allocate a buffer for ReadData even though QueryDataAvailable

-    // might return 0 bytes available.

-    ASSERT_SUCCEEDED(http_client_->QueryDataAvailable(request_handle, &size));

-    std::vector<uint8> buf(size + 1);

-    ASSERT_SUCCEEDED(http_client_->ReadData(request_handle,

-                                            &buf.front(),

-                                            buf.size(),

-                                            &size));

-    buf.resize(size);

-    if (size) {

-      response += CString(reinterpret_cast<char*>(&buf.front()), buf.size());

-    }

-  } while (size > 0);

-

-  // Compare a little bit of the body.

-  response.Truncate(10);

-  ASSERT_STREQ(response, _T("User-agent"));

-

-  ASSERT_SUCCEEDED(http_client_->Close(request_handle));

-  ASSERT_SUCCEEDED(http_client_->Close(connection_handle));

-  ASSERT_SUCCEEDED(http_client_->Close(session_handle));

-}

-

-TEST_F(HttpClientTest, Get) {

-  GetUrl(kTestUrlGet, false);

-}

-

-TEST_F(HttpClientTest, SecureGet) {

-  GetUrl(kTestSecureUrlGet, false);

-}

-

-TEST_F(HttpClientTest, ProxyGet) {

-  GetUrl(kTestUrlGet, true);

-}

-

-TEST_F(HttpClientTest, ProxySecureGet) {

-  GetUrl(kTestSecureUrlGet, true);

-}

-

-TEST_F(HttpClientTest, BuildRequestHeader) {

-  ASSERT_STREQ(HttpClient::BuildRequestHeader(_T("foo"), _T("bar")),

-               _T("foo: bar\r\n"));

-}

-

-TEST_F(HttpClientTest, GetStatusCodeClass) {

-  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_CONTINUE),

-            HttpClient::STATUS_CODE_INFORMATIONAL);

-

-  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_OK),

-            HttpClient::STATUS_CODE_SUCCESSFUL);

-

-  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_PARTIAL_CONTENT),

-            HttpClient::STATUS_CODE_SUCCESSFUL);

-

-  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_AMBIGUOUS),

-            HttpClient::STATUS_CODE_REDIRECTION);

-

-  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_REDIRECT),

-            HttpClient::STATUS_CODE_REDIRECTION);

-

-  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_BAD_REQUEST),

-            HttpClient::STATUS_CODE_CLIENT_ERROR);

-

-  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_SERVICE_UNAVAIL),

-            HttpClient::STATUS_CODE_SERVER_ERROR);

-}

-

-TEST_F(HttpClientTest, CrackUrl) {

-  CString scheme, server, path, query;

-  int port = 0;

-  ASSERT_SUCCEEDED(http_client_->CrackUrl(_T("http://host/path?query"),

-                                          0,

-                                          &scheme,

-                                          &server,

-                                          &port,

-                                          &path,

-                                          &query));

-  ASSERT_STREQ(scheme, _T("http"));

-  ASSERT_STREQ(server, _T("host"));

-  ASSERT_EQ(port, INTERNET_DEFAULT_HTTP_PORT);

-  ASSERT_STREQ(path, _T("/path"));

-  ASSERT_STREQ(query, _T("?query"));

-

-  ASSERT_SUCCEEDED(http_client_->CrackUrl(_T("http://host"),

-                                          0,

-                                          NULL,

-                                          NULL,

-                                          NULL,

-                                          &path,

-                                          &query));

-  ASSERT_STREQ(path, _T(""));

-  ASSERT_STREQ(query, _T(""));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// Since the net code is linked in as a lib, force the registration code to
+// be a dependency, otherwise the linker is optimizing in out.
+#pragma comment(linker, "/INCLUDE:_kRegisterWinHttp")
+
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/net/http_client.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Test fixture, perhaps we need it later.
+class HttpClientTest : public testing::Test {
+ protected:
+  HttpClientTest() {}
+
+  static void SetUpTestCase() {}
+
+  virtual void SetUp() {
+    http_client_.reset(
+        HttpClient::GetFactory().CreateObject(HttpClient::WINHTTP));
+    ASSERT_TRUE(http_client_.get());
+    ASSERT_SUCCEEDED(http_client_->Initialize());
+  }
+
+  virtual void TearDown() {
+    http_client_.reset();
+  }
+
+  void GetUrl(const TCHAR* url, bool use_proxy);
+
+  scoped_ptr<HttpClient> http_client_;
+};
+
+CString BuildUserAgent() {
+  CString user_agent;
+  user_agent.Format(_T("HttpClientTest version %s"), omaha::GetVersionString());
+  return user_agent;
+}
+
+const TCHAR kTestUrlGet[]       = _T("http://www.google.com/robots.txt");
+const TCHAR kTestSecureUrlGet[] = _T("https://www.google.com/robots.txt");
+
+// If using a proxy is specified, the function does WPAD detection to get the
+// name of the proxy to be used. The request goes direct if the WPAD fails.
+void HttpClientTest::GetUrl(const TCHAR* url, bool use_proxy) {
+  ASSERT_TRUE(url);
+
+  CString server, path;
+  int port = 0;
+  ASSERT_SUCCEEDED(http_client_->CrackUrl(url,
+                                          ICU_DECODE,
+                                          NULL,
+                                          &server,
+                                          &port,
+                                          &path,
+                                          NULL));
+  ASSERT_STREQ(server, _T("www.google.com"));
+  ASSERT_STREQ(path, _T("/robots.txt"));
+
+  HINTERNET session_handle = NULL;
+  ASSERT_SUCCEEDED(http_client_->Open(BuildUserAgent(),
+                                      HttpClient::kAccessTypeNoProxy,
+                                      NULL,
+                                      NULL,
+                                      &session_handle));
+  if (use_proxy) {
+    HttpClient::AutoProxyOptions autoproxy_options = {0};
+    autoproxy_options.flags = WINHTTP_AUTOPROXY_AUTO_DETECT;
+    autoproxy_options.auto_detect_flags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
+                                          WINHTTP_AUTO_DETECT_TYPE_DNS_A;
+    autoproxy_options.auto_logon_if_challenged = true;
+    HttpClient::ProxyInfo proxy_info = {0};
+    http_client_->GetProxyForUrl(session_handle,
+                                 url,
+                                 &autoproxy_options,
+                                 &proxy_info);
+    if (proxy_info.proxy && wcslen(proxy_info.proxy)) {
+      proxy_info.access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+      EXPECT_SUCCEEDED(http_client_->SetOption(session_handle,
+                                               WINHTTP_OPTION_PROXY,
+                                               &proxy_info,
+                                               sizeof(proxy_info)));
+    }
+    ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy));
+    ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy_bypass));
+  }
+
+  HINTERNET connection_handle = NULL;
+  ASSERT_SUCCEEDED(http_client_->Connect(session_handle,
+                                         server,
+                                         port,
+                                         &connection_handle));
+  uint32 flags = port == 443 ? WINHTTP_FLAG_SECURE : 0;
+  HINTERNET request_handle = NULL;
+  ASSERT_SUCCEEDED(http_client_->OpenRequest(connection_handle,
+                                             _T("GET"),
+                                             path,
+                                             NULL,     // HTTP 1.1
+                                             NULL,     // Referrer.
+                                             NULL,     // Default accept types.
+                                             flags,
+                                             &request_handle));
+  ASSERT_SUCCEEDED(http_client_->SendRequest(request_handle,
+                                             NULL, 0, NULL, 0, 0));
+  ASSERT_SUCCEEDED(http_client_->ReceiveResponse(request_handle));
+  CString content_type;
+  EXPECT_SUCCEEDED(http_client_->QueryHeadersString(request_handle,
+                                                    WINHTTP_QUERY_CONTENT_TYPE,
+                                                    NULL,
+                                                    &content_type,
+                                                    NULL));
+  EXPECT_STREQ(content_type, _T("text/plain"));
+  CString server_header;
+  EXPECT_SUCCEEDED(http_client_->QueryHeadersString(request_handle,
+                                                    WINHTTP_QUERY_SERVER,
+                                                    NULL,
+                                                    &server_header,
+                                                    NULL));
+  CString response;
+  DWORD size = 0;
+  do {
+    // Use ReadData to determine when a response has been completely read.
+    // Always allocate a buffer for ReadData even though QueryDataAvailable
+    // might return 0 bytes available.
+    ASSERT_SUCCEEDED(http_client_->QueryDataAvailable(request_handle, &size));
+    std::vector<uint8> buf(size + 1);
+    ASSERT_SUCCEEDED(http_client_->ReadData(request_handle,
+                                            &buf.front(),
+                                            buf.size(),
+                                            &size));
+    buf.resize(size);
+    if (size) {
+      response += CString(reinterpret_cast<char*>(&buf.front()), buf.size());
+    }
+  } while (size > 0);
+
+  // Compare a little bit of the body.
+  response.Truncate(10);
+  ASSERT_STREQ(response, _T("User-agent"));
+
+  ASSERT_SUCCEEDED(http_client_->Close(request_handle));
+  ASSERT_SUCCEEDED(http_client_->Close(connection_handle));
+  ASSERT_SUCCEEDED(http_client_->Close(session_handle));
+}
+
+TEST_F(HttpClientTest, Get) {
+  GetUrl(kTestUrlGet, false);
+}
+
+TEST_F(HttpClientTest, SecureGet) {
+  GetUrl(kTestSecureUrlGet, false);
+}
+
+TEST_F(HttpClientTest, ProxyGet) {
+  GetUrl(kTestUrlGet, true);
+}
+
+TEST_F(HttpClientTest, ProxySecureGet) {
+  GetUrl(kTestSecureUrlGet, true);
+}
+
+TEST_F(HttpClientTest, BuildRequestHeader) {
+  ASSERT_STREQ(HttpClient::BuildRequestHeader(_T("foo"), _T("bar")),
+               _T("foo: bar\r\n"));
+}
+
+TEST_F(HttpClientTest, GetStatusCodeClass) {
+  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_CONTINUE),
+            HttpClient::STATUS_CODE_INFORMATIONAL);
+
+  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_OK),
+            HttpClient::STATUS_CODE_SUCCESSFUL);
+
+  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_PARTIAL_CONTENT),
+            HttpClient::STATUS_CODE_SUCCESSFUL);
+
+  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_AMBIGUOUS),
+            HttpClient::STATUS_CODE_REDIRECTION);
+
+  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_REDIRECT),
+            HttpClient::STATUS_CODE_REDIRECTION);
+
+  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_BAD_REQUEST),
+            HttpClient::STATUS_CODE_CLIENT_ERROR);
+
+  EXPECT_EQ(HttpClient::GetStatusCodeClass(HTTP_STATUS_SERVICE_UNAVAIL),
+            HttpClient::STATUS_CODE_SERVER_ERROR);
+}
+
+TEST_F(HttpClientTest, CrackUrl) {
+  CString scheme, server, path, query;
+  int port = 0;
+  ASSERT_SUCCEEDED(http_client_->CrackUrl(_T("http://host/path?query"),
+                                          0,
+                                          &scheme,
+                                          &server,
+                                          &port,
+                                          &path,
+                                          &query));
+  ASSERT_STREQ(scheme, _T("http"));
+  ASSERT_STREQ(server, _T("host"));
+  ASSERT_EQ(port, INTERNET_DEFAULT_HTTP_PORT);
+  ASSERT_STREQ(path, _T("/path"));
+  ASSERT_STREQ(query, _T("?query"));
+
+  ASSERT_SUCCEEDED(http_client_->CrackUrl(_T("http://host"),
+                                          0,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          &path,
+                                          &query));
+  ASSERT_STREQ(path, _T(""));
+  ASSERT_STREQ(query, _T(""));
+}
+
+}  // namespace omaha
+
diff --git a/net/http_request.h b/net/http_request.h
index 48ececa..c9a396e 100644
--- a/net/http_request.h
+++ b/net/http_request.h
@@ -1,90 +1,90 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// HttpRequestInterface defines an interface for http transactions, with an

-// optional number of retries, going over a specified network configuration.

-//

-// TODO(omaha): the class interface is not stable yet, as a few more

-// getters and setters are still needed.

-

-#ifndef OMAHA_NET_HTTP_REQUEST_H__

-#define OMAHA_NET_HTTP_REQUEST_H__

-

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/net/network_config.h"

-

-namespace omaha {

-

-class NetworkRequestCallback;

-

-class HttpRequestInterface {

- public:

-  virtual ~HttpRequestInterface() {}

-

-  virtual HRESULT Close() = 0;

-

-  // Sends a fault-tolerant http request. Returns S_OK if the http transaction

-  // went through and the correct response is available.

-  virtual HRESULT Send() = 0;

-

-  virtual HRESULT Cancel() = 0;

-

-  virtual std::vector<uint8> GetResponse() const = 0;

-

-  virtual int GetHttpStatusCode() const = 0;

-

-  virtual HRESULT QueryHeadersString(uint32 info_level,

-                                     const TCHAR* name,

-                                     CString* value) const = 0;

-

-  virtual CString GetResponseHeaders() const = 0;

-

-  virtual CString ToString() const = 0;

-

-  virtual void set_session_handle(HINTERNET session_handle) = 0;

-

-  virtual void set_url(const CString& url) = 0;

-

-  virtual void set_request_buffer(const void* buffer,

-                                  size_t buffer_length) = 0;

-

-  virtual void set_network_configuration(const Config& network_config) = 0;

-

-  // Sets the filename to receive the response instead of the memory buffer.

-  virtual void set_filename(const CString& filename) = 0;

-

-  virtual void set_low_priority(bool low_priority) = 0;

-

-  virtual void set_callback(NetworkRequestCallback* callback) = 0;

-

-  virtual void set_additional_headers(const CString& additional_headers) = 0;

-

-  // Gets the user agent for this http request. The default user agent has

-  // the following format: Google Update/a.b.c.d;req1;req2 where a.b.c.d is

-  // the version of the client code and req1, req2,... are appended by

-  // different http requests. For example:

-  //    User-Agent: Google Update/1.2.15.0;winhttp;cup

-  // indicates a WinHTTP+CUP request.

-  virtual CString user_agent() const = 0;

-

-  virtual void set_user_agent(const CString& user_agent) = 0;

-};

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_HTTP_REQUEST_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// HttpRequestInterface defines an interface for http transactions, with an
+// optional number of retries, going over a specified network configuration.
+//
+// TODO(omaha): the class interface is not stable yet, as a few more
+// getters and setters are still needed.
+
+#ifndef OMAHA_NET_HTTP_REQUEST_H__
+#define OMAHA_NET_HTTP_REQUEST_H__
+
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/net/network_config.h"
+
+namespace omaha {
+
+class NetworkRequestCallback;
+
+class HttpRequestInterface {
+ public:
+  virtual ~HttpRequestInterface() {}
+
+  virtual HRESULT Close() = 0;
+
+  // Sends a fault-tolerant http request. Returns S_OK if the http transaction
+  // went through and the correct response is available.
+  virtual HRESULT Send() = 0;
+
+  virtual HRESULT Cancel() = 0;
+
+  virtual std::vector<uint8> GetResponse() const = 0;
+
+  virtual int GetHttpStatusCode() const = 0;
+
+  virtual HRESULT QueryHeadersString(uint32 info_level,
+                                     const TCHAR* name,
+                                     CString* value) const = 0;
+
+  virtual CString GetResponseHeaders() const = 0;
+
+  virtual CString ToString() const = 0;
+
+  virtual void set_session_handle(HINTERNET session_handle) = 0;
+
+  virtual void set_url(const CString& url) = 0;
+
+  virtual void set_request_buffer(const void* buffer,
+                                  size_t buffer_length) = 0;
+
+  virtual void set_network_configuration(const Config& network_config) = 0;
+
+  // Sets the filename to receive the response instead of the memory buffer.
+  virtual void set_filename(const CString& filename) = 0;
+
+  virtual void set_low_priority(bool low_priority) = 0;
+
+  virtual void set_callback(NetworkRequestCallback* callback) = 0;
+
+  virtual void set_additional_headers(const CString& additional_headers) = 0;
+
+  // Gets the user agent for this http request. The default user agent has
+  // the following format: Google Update/a.b.c.d;req1;req2 where a.b.c.d is
+  // the version of the client code and req1, req2,... are appended by
+  // different http requests. For example:
+  //    User-Agent: Google Update/1.2.15.0;winhttp;cup
+  // indicates a WinHTTP+CUP request.
+  virtual CString user_agent() const = 0;
+
+  virtual void set_user_agent(const CString& user_agent) = 0;
+};
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_HTTP_REQUEST_H__
+
diff --git a/net/net_diags.cc b/net/net_diags.cc
index ef17de9..2fc99d6 100644
--- a/net/net_diags.cc
+++ b/net/net_diags.cc
@@ -1,173 +1,173 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Some simple network diags.

-

-#include "omaha/net/net_diags.h"

-#include <windows.h>

-#include <stdarg.h>

-#include <vector>

-#include "omaha/common/app_util.h"

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/network_request.h"

-

-namespace omaha {

-

-NetDiags::NetDiags() {

-  Initialize();

-}

-

-NetDiags::~NetDiags() {

-  ::CoUninitialize();

-}

-

-bool PrintToConsole(const TCHAR* format, ...) {

-  ASSERT1(format);

-  va_list arg_list;

-  va_start(arg_list, format);

-  CString msg;

-  msg.FormatV(format, arg_list);

-  ASSERT1(msg.GetLength() > 0);

-  va_end(arg_list);

-

-  DWORD count = 0;

-  bool result = !!::WriteConsole(::GetStdHandle(STD_OUTPUT_HANDLE),

-                                 msg,

-                                 msg.GetLength(),

-                                 &count,

-                                 NULL);

-  ASSERT1(result);

-  ASSERT1(msg.GetLength() == static_cast<int>(count));

-  return result;

-}

-

-void NetDiags::Initialize() {

-  if (!SystemInfo::IsRunningOnXPOrLater()) {

-    ::MessageBox(NULL,

-        _T("GoogleUpdate.exe"),

-        _T("\"GoogleUpdate.exe /NetDiags\" only runs on Windows XP or later."),

-        MB_OK);

-    ::ExitProcess(1);

-  }

-

-  if (!AttachConsoleWrap(ATTACH_PARENT_PROCESS)) {

-    ::MessageBox(NULL,

-        _T("GoogleUpdate.exe"),

-        _T("Please run \"GoogleUpdate.exe /NetDiags\" from a cmd.exe window."),

-        MB_OK);

-    ::ExitProcess(1);

-  }

-

-  PrintToConsole(_T("\n"));

-  HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

-  if (FAILED(hr)) {

-    PrintToConsole(_T("Failed to ::CoInitialize() [0x%x]\n"), hr);

-    ::ExitProcess(1);

-  }

-

-  // Initialize the detection chain: GoogleProxy, FireFox if it is the

-  // default browser, and IE.

-  NetworkConfig& network_config(NetworkConfig::Instance());

-  network_config.Clear();

-  BrowserType browser_type(BROWSER_UNKNOWN);

-  GetDefaultBrowserType(&browser_type);

-  if (browser_type == BROWSER_FIREFOX) {

-    PrintToConsole(_T("Default browser is Firefox\n"));

-    network_config.Add(new FirefoxProxyDetector());

-  }

-  network_config.Add(new IEProxyDetector());

-

-  std::vector<Config> configs = network_config.GetConfigurations();

-  if (configs.empty()) {

-    PrintToConsole(_T("No Network Configurations to display\n"));

-  } else {

-    PrintToConsole(_T("[Detected Network Configurations][\n%s]\n"),

-                   NetworkConfig::ToString(configs));

-  }

-}

-

-void NetDiags::OnProgress(int bytes, int bytes_total, int, const TCHAR*) {

-  PrintToConsole(_T("\n[Downloading %d of %d]\n"), bytes, bytes_total);

-}

-

-// http get.

-void NetDiags::DoGet(const CString& url) {

-  PrintToConsole(_T("\nGET request for [%s]\n"), url);

-  NetworkRequest network_request(NetworkConfig::Instance().session());

-  network_request.set_callback(this);

-  network_request.set_num_retries(2);

-  CString response;

-  HRESULT hr = GetRequest(&network_request, url, &response);

-  int status = network_request.http_status_code();

-  if (FAILED(hr)) {

-    PrintToConsole(_T("GET request failed. HRESULT=[0x%x], HTTP Status=[%d]\n"),

-                   hr, status);

-    return;

-  }

-

-  PrintToConsole(_T("HTTP Status=[%d]\n"), status);

-  PrintToConsole(_T("HTTP Response=\n[%s]\n"), response);

-}

-

-// http download.

-void NetDiags::DoDownload(const CString& url) {

-  PrintToConsole(_T("\nDownload request for [%s]\n"), url);

-  NetworkRequest network_request(NetworkConfig::Instance().session());

-  network_request.set_callback(this);

-  network_request.set_num_retries(2);

-

-  CString temp_dir = app_util::GetTempDir();

-  CString temp_file;

-  if (!::GetTempFileName(temp_dir,

-                         _T("tmp"),

-                         0,

-                         CStrBuf(temp_file, MAX_PATH))) {

-    PrintToConsole(_T("::GetTempFileName Failed [%d]\n"), ::GetLastError());

-    return;

-  }

-

-  HRESULT hr = network_request.DownloadFile(url, temp_file);

-  int status = network_request.http_status_code();

-  if (FAILED(hr)) {

-    PrintToConsole(_T("Download failed. HRESULT=[0x%x], HTTP Status=[%d]\n"),

-                   hr, status);

-    return;

-  }

-

-  PrintToConsole(_T("HTTP Status=[%d]\n"), status);

-  PrintToConsole(_T("Downloaded File=[%s]\n"), temp_file);

-  if (!::DeleteFile(temp_file)) {

-    PrintToConsole(_T("::DeleteFile Failed [%s][%d]\n"),

-                   temp_file, ::GetLastError());

-    return;

-  } else {

-    PrintToConsole(_T("Deleted file [%s]\n"), temp_file);

-  }

-}

-

-// Run the tests.

-int NetDiags::Main() {

-  DoGet(_T("http://www.google.com/robots.txt"));

-  DoGet(_T("https://www.google.com/robots.txt"));

-  DoDownload(_T("http://www.google.com/intl/en_ALL/images/logo.gif"));

-  return 0;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Some simple network diags.
+
+#include "omaha/net/net_diags.h"
+#include <windows.h>
+#include <stdarg.h>
+#include <vector>
+#include "omaha/common/app_util.h"
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/network_request.h"
+
+namespace omaha {
+
+NetDiags::NetDiags() {
+  Initialize();
+}
+
+NetDiags::~NetDiags() {
+  ::CoUninitialize();
+}
+
+bool PrintToConsole(const TCHAR* format, ...) {
+  ASSERT1(format);
+  va_list arg_list;
+  va_start(arg_list, format);
+  CString msg;
+  msg.FormatV(format, arg_list);
+  ASSERT1(msg.GetLength() > 0);
+  va_end(arg_list);
+
+  DWORD count = 0;
+  bool result = !!::WriteConsole(::GetStdHandle(STD_OUTPUT_HANDLE),
+                                 msg,
+                                 msg.GetLength(),
+                                 &count,
+                                 NULL);
+  ASSERT1(result);
+  ASSERT1(msg.GetLength() == static_cast<int>(count));
+  return result;
+}
+
+void NetDiags::Initialize() {
+  if (!SystemInfo::IsRunningOnXPOrLater()) {
+    ::MessageBox(NULL,
+        _T("GoogleUpdate.exe"),
+        _T("\"GoogleUpdate.exe /NetDiags\" only runs on Windows XP or later."),
+        MB_OK);
+    ::ExitProcess(1);
+  }
+
+  if (!AttachConsoleWrap(ATTACH_PARENT_PROCESS)) {
+    ::MessageBox(NULL,
+        _T("GoogleUpdate.exe"),
+        _T("Please run \"GoogleUpdate.exe /NetDiags\" from a cmd.exe window."),
+        MB_OK);
+    ::ExitProcess(1);
+  }
+
+  PrintToConsole(_T("\n"));
+  HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+  if (FAILED(hr)) {
+    PrintToConsole(_T("Failed to ::CoInitialize() [0x%x]\n"), hr);
+    ::ExitProcess(1);
+  }
+
+  // Initialize the detection chain: GoogleProxy, FireFox if it is the
+  // default browser, and IE.
+  NetworkConfig& network_config(NetworkConfig::Instance());
+  network_config.Clear();
+  BrowserType browser_type(BROWSER_UNKNOWN);
+  GetDefaultBrowserType(&browser_type);
+  if (browser_type == BROWSER_FIREFOX) {
+    PrintToConsole(_T("Default browser is Firefox\n"));
+    network_config.Add(new FirefoxProxyDetector());
+  }
+  network_config.Add(new IEProxyDetector());
+
+  std::vector<Config> configs = network_config.GetConfigurations();
+  if (configs.empty()) {
+    PrintToConsole(_T("No Network Configurations to display\n"));
+  } else {
+    PrintToConsole(_T("[Detected Network Configurations][\n%s]\n"),
+                   NetworkConfig::ToString(configs));
+  }
+}
+
+void NetDiags::OnProgress(int bytes, int bytes_total, int, const TCHAR*) {
+  PrintToConsole(_T("\n[Downloading %d of %d]\n"), bytes, bytes_total);
+}
+
+// http get.
+void NetDiags::DoGet(const CString& url) {
+  PrintToConsole(_T("\nGET request for [%s]\n"), url);
+  NetworkRequest network_request(NetworkConfig::Instance().session());
+  network_request.set_callback(this);
+  network_request.set_num_retries(2);
+  CString response;
+  HRESULT hr = GetRequest(&network_request, url, &response);
+  int status = network_request.http_status_code();
+  if (FAILED(hr)) {
+    PrintToConsole(_T("GET request failed. HRESULT=[0x%x], HTTP Status=[%d]\n"),
+                   hr, status);
+    return;
+  }
+
+  PrintToConsole(_T("HTTP Status=[%d]\n"), status);
+  PrintToConsole(_T("HTTP Response=\n[%s]\n"), response);
+}
+
+// http download.
+void NetDiags::DoDownload(const CString& url) {
+  PrintToConsole(_T("\nDownload request for [%s]\n"), url);
+  NetworkRequest network_request(NetworkConfig::Instance().session());
+  network_request.set_callback(this);
+  network_request.set_num_retries(2);
+
+  CString temp_dir = app_util::GetTempDir();
+  CString temp_file;
+  if (!::GetTempFileName(temp_dir,
+                         _T("tmp"),
+                         0,
+                         CStrBuf(temp_file, MAX_PATH))) {
+    PrintToConsole(_T("::GetTempFileName Failed [%d]\n"), ::GetLastError());
+    return;
+  }
+
+  HRESULT hr = network_request.DownloadFile(url, temp_file);
+  int status = network_request.http_status_code();
+  if (FAILED(hr)) {
+    PrintToConsole(_T("Download failed. HRESULT=[0x%x], HTTP Status=[%d]\n"),
+                   hr, status);
+    return;
+  }
+
+  PrintToConsole(_T("HTTP Status=[%d]\n"), status);
+  PrintToConsole(_T("Downloaded File=[%s]\n"), temp_file);
+  if (!::DeleteFile(temp_file)) {
+    PrintToConsole(_T("::DeleteFile Failed [%s][%d]\n"),
+                   temp_file, ::GetLastError());
+    return;
+  } else {
+    PrintToConsole(_T("Deleted file [%s]\n"), temp_file);
+  }
+}
+
+// Run the tests.
+int NetDiags::Main() {
+  DoGet(_T("http://www.google.com/robots.txt"));
+  DoGet(_T("https://www.google.com/robots.txt"));
+  DoDownload(_T("http://www.google.com/intl/en_ALL/images/logo.gif"));
+  return 0;
+}
+
+}  // namespace omaha
+
diff --git a/net/net_diags.h b/net/net_diags.h
index 30e53bf..bd92e60 100644
--- a/net/net_diags.h
+++ b/net/net_diags.h
@@ -1,47 +1,47 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_NET_NET_DIAGS_H__

-#define OMAHA_NET_NET_DIAGS_H__

-

-#include <tchar.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "omaha/net/network_request.h"

-

-namespace omaha {

-

-class NetDiags : public NetworkRequestCallback {

- public:

-  NetDiags();

-  ~NetDiags();

-

-  // Run the tests.

-  int Main();

-

- private:

-  void Initialize();

-  virtual void OnProgress(int bytes, int bytes_total, int, const TCHAR*);

-

-  // http get.

-  void DoGet(const CString& url);

-  void DoDownload(const CString& url);

-};

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_NET_DIAGS_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_NET_NET_DIAGS_H__
+#define OMAHA_NET_NET_DIAGS_H__
+
+#include <tchar.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "omaha/net/network_request.h"
+
+namespace omaha {
+
+class NetDiags : public NetworkRequestCallback {
+ public:
+  NetDiags();
+  ~NetDiags();
+
+  // Run the tests.
+  int Main();
+
+ private:
+  void Initialize();
+  virtual void OnProgress(int bytes, int bytes_total, int, const TCHAR*);
+
+  // http get.
+  void DoGet(const CString& url);
+  void DoDownload(const CString& url);
+};
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_NET_DIAGS_H__
+
diff --git a/net/net_utils.cc b/net/net_utils.cc
index 563011a..e186a3c 100644
--- a/net/net_utils.cc
+++ b/net/net_utils.cc
@@ -1,78 +1,78 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/net/net_utils.h"

-#include <iphlpapi.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-bool IsMachineConnectedToNetwork() {

-  // Get the table of information on all interfaces.

-  DWORD table_size = 0;

-  DWORD result = ::GetIfTable(NULL, &table_size, false);

-  if (result != ERROR_INSUFFICIENT_BUFFER) {

-    NET_LOG(LW, (_T("[GetIfTable failed to get the table size][%d]"), result));

-    return true;

-  }

-

-  scoped_array<char> buffer(new char[table_size]);

-  MIB_IFTABLE* mib_table = reinterpret_cast<MIB_IFTABLE*>(buffer.get());

-  result = ::GetIfTable(mib_table, &table_size, false);

-  if (result != NO_ERROR) {

-    NET_LOG(LW, (_T("[GetIfTable failed][%d]"), result));

-    return true;

-  }

-

-  // Scan the table looking for active connections.

-  bool active_LAN = false;

-  bool active_WAN = false;

-  for (size_t i = 0; i < mib_table->dwNumEntries; ++i) {

-    if (mib_table->table[i].dwType != MIB_IF_TYPE_LOOPBACK) {

-      active_WAN = active_WAN ||

-          mib_table->table[i].dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED;

-      active_LAN = active_LAN ||

-          mib_table->table[i].dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL;

-    }

-  }

-

-  return active_LAN || active_WAN;

-}

-

-CString BufferToPrintableString(const void* buffer, size_t length) {

-  CString result;

-  result.Preallocate(length);

-  if (buffer) {

-    for (size_t i = 0; i != length; ++i) {

-      char ch = (static_cast<const char*>(buffer))[i];

-      result.AppendChar((isprint(ch) || ch =='\r' || ch == '\n') ? ch : '.');

-    }

-  }

-  return result;

-}

-

-CString VectorToPrintableString(const std::vector<uint8>& response) {

-  CString str;

-  if (!response.empty()) {

-    str = BufferToPrintableString(&response.front(), response.size());

-  }

-  return str;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/net/net_utils.h"
+#include <iphlpapi.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+bool IsMachineConnectedToNetwork() {
+  // Get the table of information on all interfaces.
+  DWORD table_size = 0;
+  DWORD result = ::GetIfTable(NULL, &table_size, false);
+  if (result != ERROR_INSUFFICIENT_BUFFER) {
+    NET_LOG(LW, (_T("[GetIfTable failed to get the table size][%d]"), result));
+    return true;
+  }
+
+  scoped_array<char> buffer(new char[table_size]);
+  MIB_IFTABLE* mib_table = reinterpret_cast<MIB_IFTABLE*>(buffer.get());
+  result = ::GetIfTable(mib_table, &table_size, false);
+  if (result != NO_ERROR) {
+    NET_LOG(LW, (_T("[GetIfTable failed][%d]"), result));
+    return true;
+  }
+
+  // Scan the table looking for active connections.
+  bool active_LAN = false;
+  bool active_WAN = false;
+  for (size_t i = 0; i < mib_table->dwNumEntries; ++i) {
+    if (mib_table->table[i].dwType != MIB_IF_TYPE_LOOPBACK) {
+      active_WAN = active_WAN ||
+          mib_table->table[i].dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED;
+      active_LAN = active_LAN ||
+          mib_table->table[i].dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL;
+    }
+  }
+
+  return active_LAN || active_WAN;
+}
+
+CString BufferToPrintableString(const void* buffer, size_t length) {
+  CString result;
+  result.Preallocate(length);
+  if (buffer) {
+    for (size_t i = 0; i != length; ++i) {
+      char ch = (static_cast<const char*>(buffer))[i];
+      result.AppendChar((isprint(ch) || ch =='\r' || ch == '\n') ? ch : '.');
+    }
+  }
+  return result;
+}
+
+CString VectorToPrintableString(const std::vector<uint8>& response) {
+  CString str;
+  if (!response.empty()) {
+    str = BufferToPrintableString(&response.front(), response.size());
+  }
+  return str;
+}
+
+}  // namespace omaha
+
diff --git a/net/net_utils.h b/net/net_utils.h
index 5140d06..ef8d394 100644
--- a/net/net_utils.h
+++ b/net/net_utils.h
@@ -1,39 +1,39 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_NET_NET_UTILS_H__

-#define OMAHA_NET_NET_UTILS_H__

-

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-// Returns true if the machine is connected to the LAN/WAN network. This

-// does not mean the machine is able to access the Internet. When the function

-// can't determine the connection state, it assumes the machine is connected

-// and it returns true as well.

-bool IsMachineConnectedToNetwork();

-

-// Converts a buffer or a vector to a string for logging purposes.

-// Non-printable characters are converted to '.'.

-CString BufferToPrintableString(const void* buffer, size_t length);

-CString VectorToPrintableString(const std::vector<uint8>& response);

-

-}  // namespace omaha

-

-#endif  // OMAHA_NET_NET_UTILS_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_NET_NET_UTILS_H__
+#define OMAHA_NET_NET_UTILS_H__
+
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+// Returns true if the machine is connected to the LAN/WAN network. This
+// does not mean the machine is able to access the Internet. When the function
+// can't determine the connection state, it assumes the machine is connected
+// and it returns true as well.
+bool IsMachineConnectedToNetwork();
+
+// Converts a buffer or a vector to a string for logging purposes.
+// Non-printable characters are converted to '.'.
+CString BufferToPrintableString(const void* buffer, size_t length);
+CString VectorToPrintableString(const std::vector<uint8>& response);
+
+}  // namespace omaha
+
+#endif  // OMAHA_NET_NET_UTILS_H__
+
diff --git a/net/net_utils_unittest.cc b/net/net_utils_unittest.cc
index 7818eea..e2bdbd9 100644
--- a/net/net_utils_unittest.cc
+++ b/net/net_utils_unittest.cc
@@ -1,44 +1,44 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/net/net_utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// It only tests for the happy scenario.

-TEST(NetUtilsTest, IsMachineConnectedToNetwork) {

-  EXPECT_TRUE(IsMachineConnectedToNetwork());

-}

-

-TEST(NetUtilsTest, BufferToPrintableString) {

-  EXPECT_STREQ(_T(""), BufferToPrintableString(NULL, 0));

-

-  const char* buffer = "a\n\r\xff";

-  EXPECT_STREQ(_T("a\n\r."),

-               BufferToPrintableString(buffer, strlen(buffer)));

-}

-

-TEST(NetUtilsTest, VectorToPrintableString) {

-  EXPECT_STREQ(_T(""), VectorToPrintableString(std::vector<uint8>()));

-

-  const char* buffer = "a\n\r\xff";

-  std::vector<uint8> vec(buffer, buffer + strlen(buffer));

-  EXPECT_STREQ(_T("a\n\r."), VectorToPrintableString(vec));

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/net/net_utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// It only tests for the happy scenario.
+TEST(NetUtilsTest, IsMachineConnectedToNetwork) {
+  EXPECT_TRUE(IsMachineConnectedToNetwork());
+}
+
+TEST(NetUtilsTest, BufferToPrintableString) {
+  EXPECT_STREQ(_T(""), BufferToPrintableString(NULL, 0));
+
+  const char* buffer = "a\n\r\xff";
+  EXPECT_STREQ(_T("a\n\r."),
+               BufferToPrintableString(buffer, strlen(buffer)));
+}
+
+TEST(NetUtilsTest, VectorToPrintableString) {
+  EXPECT_STREQ(_T(""), VectorToPrintableString(std::vector<uint8>()));
+
+  const char* buffer = "a\n\r\xff";
+  std::vector<uint8> vec(buffer, buffer + strlen(buffer));
+  EXPECT_STREQ(_T("a\n\r."), VectorToPrintableString(vec));
+}
+
+}  // namespace omaha
+
diff --git a/net/network_config.cc b/net/network_config.cc
index d050023..f3aefbe 100644
--- a/net/network_config.cc
+++ b/net/network_config.cc
@@ -1,514 +1,514 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/net/network_config.h"

-

-#include <winhttp.h>

-#include <atlconv.h>

-#include <atlsecurity.h>

-#include <hash_set>

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/string.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/net/cup_request.h"

-#include "omaha/net/http_client.h"

-#include "omaha/goopdate/resource.h"

-

-using omaha::user_info::GetCurrentUser;

-

-namespace omaha {

-

-// Computes the hash value of a Config object. Names in the stdext namespace are

-// not currently part of the ISO C++ standard.

-uint32 hash_value(const Config& config) {

-  uint32 hash = stdext::hash_value(config.auto_detect)                 ^

-                stdext::hash_value(config.auto_config_url.GetString()) ^

-                stdext::hash_value(config.proxy.GetString())           ^

-                stdext::hash_value(config.proxy_bypass.GetString());

-  return hash;

-}

-

-NetworkConfig* const NetworkConfig::kInvalidInstance  =

-    reinterpret_cast<NetworkConfig* const>(-1);

-NetworkConfig* NetworkConfig::instance_               = NULL;

-

-const TCHAR* const NetworkConfig::kNetworkSubkey      = _T("network");

-const TCHAR* const NetworkConfig::kNetworkCupSubkey   = _T("secure");

-const TCHAR* const NetworkConfig::kCupClientSecretKey = _T("sk");

-const TCHAR* const NetworkConfig::kCupClientCookie    = _T("c");

-

-const TCHAR* const NetworkConfig::kUserAgent = _T("Google Update/%s");

-

-NetworkConfig::NetworkConfig()

-    : is_machine_(false),

-      is_initialized_(false) {}

-

-NetworkConfig::~NetworkConfig() {

-  if (session_.session_handle && http_client_.get()) {

-    http_client_->Close(session_.session_handle);

-    session_.session_handle = NULL;

-  }

-  if (session_.impersonation_token) {

-    ::CloseHandle(session_.impersonation_token);

-    session_.impersonation_token = NULL;

-  }

-  Clear();

-}

-

-NetworkConfig& NetworkConfig::Instance() {

-  // Getting the instance after the instance has been deleted is a bug in

-  // the logic of the program.

-  ASSERT1(instance_ != kInvalidInstance);

-  if (!instance_) {

-    instance_ = new NetworkConfig();

-  }

-  return *instance_;

-}

-

-// Initialize creates or opens a global lock to synchronize access to

-// registry where CUP credentials are stored. Each user including non-elevated

-// admins stores network configuration data, such as the CUP password in

-// its HKCU. The admin users, including the LOCAL_SYSTEM, store data in HKLM.

-// Therefore, the naming of the global lock is different: users have their

-// lock postfixed with their sid, so the serialization only occurs within the

-// same user's programs. Admin users use the same named lock since they store

-// data in a shared HKLM. The data of the admin users is disambiguated by

-// postfixing their registry sub key with sids.

-// In conclusion, users have sid-postfixed locks and their data goes in

-// their respective HKCU. Admin users have the same lock and their data goes

-// under HKLM in sid-postfixed stores.

-//

-// The named lock is created in the global namespace to account for users

-// logging in from different TS sessions.

-//

-// The CUP credentials must be protected with ACLs so non-elevated admins can't

-// read elevated-admins' keys and attack the protocol.

-//

-// Also, an Internet session is created and associated with the impersonation

-// token.

-HRESULT NetworkConfig::Initialize(bool is_machine,

-                                  HANDLE impersonation_token) {

-  ASSERT1(!is_initialized_);

-  is_machine_ = is_machine;

-  HRESULT hr = GetCurrentUser(NULL, NULL, &sid_);

-  if (FAILED(hr)) {

-    NET_LOG(LE, (_T("[GetCurrentUser failed][0x%x]"), hr));

-    return hr;

-  }

-  hr = InitializeLock();

-  if (FAILED(hr)) {

-    NET_LOG(LE, (_T("[InitializeLock failed][0x%x]"), hr));

-    return hr;

-  }

-  hr = InitializeRegistryKey();

-  if (FAILED(hr)) {

-    NET_LOG(LE, (_T("[InitializeRegistryKey failed][0x%x]"), hr));

-    return hr;

-  }

-

-  http_client_.reset(CreateHttpClient());

-  ASSERT1(http_client_.get());

-  if (!http_client_.get()) {

-    NET_LOG(LE, (_T("[CreateHttpClient failed]")));

-    return E_UNEXPECTED;

-  }

-  hr = http_client_->Initialize();

-  if (FAILED(hr)) {

-    // TODO(omaha): This makes an assumption that only WinHttp is

-    // supported by the network code.

-    NET_LOG(LE, (_T("[http_client_->Initialize() failed][0x%x]"), hr));

-    return OMAHA_NET_E_WINHTTP_NOT_AVAILABLE;

-  }

-

-  hr = http_client_->Open(NULL,

-                          WINHTTP_ACCESS_TYPE_NO_PROXY,

-                          WINHTTP_NO_PROXY_NAME,

-                          WINHTTP_NO_PROXY_BYPASS,

-                          &session_.session_handle);

-  if (FAILED(hr)) {

-    NET_LOG(LE, (_T("[http_client_->Open() failed][0x%x]"), hr));

-    return hr;

-  }

-

-  session_.impersonation_token = impersonation_token;

-  is_initialized_ = true;

-  return S_OK;

-}

-

-HRESULT NetworkConfig::InitializeLock() {

-  NamedObjectAttributes lock_attr;

-  GetNamedObjectAttributes(kNetworkConfigLock, is_machine_, &lock_attr);

-  return global_lock_.InitializeWithSecAttr(lock_attr.name, &lock_attr.sa) ?

-         S_OK : E_FAIL;

-}

-

-HRESULT NetworkConfig::InitializeRegistryKey() {

-  // The registry path under which to store persistent network configuration.

-  // The "network" subkey is created with default security. Below "network",

-  // the "secure" key is created so that only system and administrators have

-  // access to it.

-  registry_update_network_path_ = is_machine_ ? MACHINE_REG_UPDATE :

-                                                USER_REG_UPDATE;

-  registry_update_network_path_ =

-      AppendRegKeyPath(registry_update_network_path_, kNetworkSubkey);

-  RegKey reg_key_network;

-  DWORD disposition = 0;

-  HRESULT hr = reg_key_network.Create(registry_update_network_path_,

-                                      NULL,                 // Class.

-                                      0,                    // Options.

-                                      KEY_CREATE_SUB_KEY,   // SAM desired.

-                                      NULL,                 // Security attrs.

-                                      &disposition);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // When initializing for machine, grant access to administrators and system.

-  scoped_ptr<CSecurityAttributes> sa;

-  if (is_machine_) {

-    sa.reset(new CSecurityAttributes);

-    GetAdminDaclSecurityAttributes(sa.get(), GENERIC_ALL);

-  }

-

-  disposition = 0;

-  RegKey reg_key_network_secure;

-  CString subkey_name = is_machine_ ?

-                        JoinStrings(kNetworkCupSubkey, sid_, _T("-")) :

-                        kNetworkCupSubkey;

-  hr = reg_key_network_secure.Create(reg_key_network.Key(),  // Parent.

-                                     subkey_name,            // Subkey name.

-                                     NULL,                   // Class.

-                                     0,                      // Options.

-                                     KEY_READ,               // SAM desired.

-                                     sa.get(),               // Security attrs.

-                                     &disposition);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  return S_OK;

-}

-

-void NetworkConfig::Add(ProxyDetectorInterface* detector) {

-  ASSERT1(detector);

-  __mutexBlock(lock_) {

-    detectors_.push_back(detector);

-  }

-}

-

-void NetworkConfig::Clear() {

-  __mutexBlock(lock_) {

-    for (size_t i = 0; i != detectors_.size(); ++i) {

-      delete detectors_[i];

-    }

-    detectors_.clear();

-    configurations_.clear();

-  }

-}

-

-HRESULT NetworkConfig::Detect() {

-  __mutexBlock(lock_) {

-    std::vector<Config> configurations;

-    for (size_t i = 0; i != detectors_.size(); ++i) {

-      Config config;

-      if (SUCCEEDED(detectors_[i]->Detect(&config))) {

-        configurations.push_back(config);

-      }

-    }

-    configurations_.swap(configurations);

-  }

-  return S_OK;

-}

-

-std::vector<Config> NetworkConfig::GetConfigurations() const {

-  std::vector<Config> configurations;

-  __mutexBlock(lock_) {

-    configurations = configurations_;

-  }

-  return configurations;

-}

-

-HRESULT NetworkConfig::GetConfigurationOverride(Config* config) {

-  ASSERT1(config);

-  __mutexBlock(lock_) {

-    if (configuration_override_.get()) {

-      *config = *configuration_override_;

-      return S_OK;

-    }

-  }

-  return E_FAIL;

-}

-

-void NetworkConfig::SetConfigurationOverride(

-    const Config* configuration_override) {

-  __mutexBlock(lock_) {

-    if (configuration_override) {

-      configuration_override_.reset(new Config);

-      *configuration_override_ = *configuration_override;

-    } else {

-      configuration_override_.reset();

-    }

-  }

-}

-

-// Serializes configurations for debugging purposes.

-

-CString NetworkConfig::ToString(const Config& config) {

-  CString result;

-  result.AppendFormat(_T("source=%s, "), config.source);

-  switch (GetAccessType(config)) {

-    case WINHTTP_ACCESS_TYPE_NO_PROXY:

-      result.AppendFormat(_T("direct connection"));

-      break;

-    case WINHTTP_ACCESS_TYPE_NAMED_PROXY:

-      result.AppendFormat(_T("named proxy=%s, bypass=%s"),

-                          config.proxy, config.proxy_bypass);

-      break;

-    case WINHTTP_ACCESS_TYPE_AUTO_DETECT:

-      result.AppendFormat(_T("wpad=%d, script=%s"),

-                          config.auto_detect, config.auto_config_url);

-      break;

-    default:

-      ASSERT1(false);

-      break;

-  }

-  return result;

-}

-

-CString NetworkConfig::ToString(const std::vector<Config>& configurations) {

-  CString result;

-  for (size_t i = 0; i != configurations.size(); ++i) {

-    result.Append(NetworkConfig::ToString(configurations[i]));

-    result.Append(_T("\r\n"));

-  }

-  return result;

-}

-

-int NetworkConfig::GetAccessType(const Config& config) {

-  if (config.auto_detect || !config.auto_config_url.IsEmpty()) {

-    return WINHTTP_ACCESS_TYPE_AUTO_DETECT;

-  } else if (!config.proxy.IsEmpty()) {

-    return WINHTTP_ACCESS_TYPE_NAMED_PROXY;

-  } else {

-    return WINHTTP_ACCESS_TYPE_NO_PROXY;

-  }

-}

-

-HRESULT NetworkConfig::GetCupCredentials(CupCredentials* cup_credentials) {

-  ASSERT1(cup_credentials);

-  ASSERT1(is_initialized_);

-  __mutexBlock(global_lock_) {

-    CString subkey_name = is_machine_ ?

-                          JoinStrings(kNetworkCupSubkey, sid_, _T("-")) :

-                          kNetworkCupSubkey;

-    CString key_name = AppendRegKeyPath(registry_update_network_path_,

-                                        subkey_name);

-    RegKey reg_key;

-    HRESULT hr = reg_key.Open(key_name, KEY_READ);

-    if (FAILED(hr)) {

-      return hr;

-    }

-    scoped_array<byte> buf;

-    DWORD buf_length = 0;

-    hr = reg_key.GetValue(kCupClientSecretKey, address(buf), &buf_length);

-    if (FAILED(hr)) {

-      return hr;

-    }

-    CString cookie;

-    hr = reg_key.GetValue(kCupClientCookie, &cookie);

-    if (FAILED(hr)) {

-      return hr;

-    }

-    cup_credentials->sk.resize(buf_length);

-    memcpy(&cup_credentials->sk.front(), buf.get(), buf_length);

-    cup_credentials->c = CT2A(cookie);

-  }

-  return S_OK;

-}

-

-HRESULT NetworkConfig::SetCupCredentials(

-            const CupCredentials* cup_credentials) {

-  ASSERT1(is_initialized_);

-  __mutexBlock(global_lock_) {

-    CString subkey_name = is_machine_ ?

-                          JoinStrings(kNetworkCupSubkey, sid_, _T("-")) :

-                          kNetworkCupSubkey;

-    CString key_name = AppendRegKeyPath(registry_update_network_path_,

-                                        subkey_name);

-    RegKey reg_key;

-    HRESULT hr = reg_key.Open(key_name, KEY_WRITE);

-    if (FAILED(hr)) {

-      NET_LOG(L2, (_T("[Registry key open failed][%s][0x%08x]"), key_name, hr));

-      return hr;

-    }

-    if (!cup_credentials) {

-      HRESULT hr1 = reg_key.DeleteValue(kCupClientSecretKey);

-      HRESULT hr2 = reg_key.DeleteValue(kCupClientCookie);

-      return (SUCCEEDED(hr1) && SUCCEEDED(hr2)) ? S_OK : HRESULTFromLastError();

-    }

-    hr = reg_key.SetValue(kCupClientSecretKey,

-             static_cast<const byte*>(&cup_credentials->sk.front()),

-             cup_credentials->sk.size());

-    if (FAILED(hr)) {

-      return hr;

-    }

-    hr = reg_key.SetValue(kCupClientCookie, CA2T(cup_credentials->c));

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-  return S_OK;

-}

-

-bool NetworkConfig::IsUsingCupTestKeys() {

-  DWORD value = 0;

-  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                 kRegValueCupKeys,

-                                 &value))) {

-    return value != 0;

-  } else {

-    return false;

-  }

-}

-

-void NetworkConfig::ConfigureProxyAuth(const CString& caption,

-                                       const CString& message,

-                                       HWND parent,

-                                       uint32 cancel_prompt_threshold) {

-  return proxy_auth_.ConfigureProxyAuth(caption, message, parent,

-                                        cancel_prompt_threshold);

-}

-

-bool NetworkConfig::GetProxyCredentials(bool allow_ui,

-                                        bool force_ui,

-                                        const CString& proxy_settings,

-                                        bool is_https,

-                                        CString* username,

-                                        CString* password,

-                                        uint32* auth_scheme) {

-  ASSERT1(username);

-  ASSERT1(password);

-  ASSERT1(auth_scheme);

-  const CString& proxy = ProxyAuth::ExtractProxy(proxy_settings, is_https);

-  return proxy_auth_.GetProxyCredentials(allow_ui, force_ui, proxy,

-                                         username, password, auth_scheme);

-}

-

-HRESULT NetworkConfig::SetProxyAuthScheme(const CString& proxy_settings,

-                                          bool is_https,

-                                          uint32 auth_scheme) {

-  ASSERT1(auth_scheme != UNKNOWN_AUTH_SCHEME);

-  const CString& proxy = ProxyAuth::ExtractProxy(proxy_settings, is_https);

-  return proxy_auth_.SetProxyAuthScheme(proxy, auth_scheme);

-}

-

-// TODO(omaha): the code does WPAD auto detect in all cases. It is possible for

-// a configuration to specify no auto detection but provide the proxy script

-// url. The current code does not account for this yet.

-HRESULT NetworkConfig::GetProxyForUrl(const CString& url,

-                                      const CString& auto_config_url,

-                                      HttpClient::ProxyInfo* proxy_info) {

-  ASSERT1(proxy_info);

-  HttpClient::AutoProxyOptions auto_proxy_options = {0};

-  auto_proxy_options.flags = WINHTTP_AUTOPROXY_AUTO_DETECT;

-  auto_proxy_options.auto_detect_flags = WINHTTP_AUTO_DETECT_TYPE_DHCP |

-                                         WINHTTP_AUTO_DETECT_TYPE_DNS_A;

-  if (!auto_config_url.IsEmpty()) {

-    auto_proxy_options.auto_config_url = auto_config_url;

-    auto_proxy_options.flags |= WINHTTP_AUTOPROXY_CONFIG_URL;

-  }

-  auto_proxy_options.auto_logon_if_challenged = true;

-

-  return http_client_->GetProxyForUrl(session_.session_handle,

-                                      url,

-                                      &auto_proxy_options,

-                                      proxy_info);

-}

-

-CString NetworkConfig::GetUserAgent() {

-  CString user_agent;

-  user_agent.Format(kUserAgent, GetVersionString());

-  return user_agent;

-}

-

-CString NetworkConfig::JoinStrings(const TCHAR* s1,

-                                   const TCHAR* s2,

-                                   const TCHAR* delim) {

-  CString result;

-  const TCHAR* components[] = {s1, s2};

-  JoinStringsInArray(components, arraysize(components), delim, &result);

-  return result;

-}

-

-// Using std::hash_set adds about 2K uncompressed code size. Using a CAtlMap

-// adds about 1.5K. Usually, there are only five detected configurations so

-// an O(n^2) algorithm would work well. The advantage of the current

-// implementation is simplicity. It also does not handle conflicts. Conflicts

-// are not expected, due to how the Config structure is being used.

-// TODO(omaha): consider not using the hash_set and save about 1K of code.

-void NetworkConfig::RemoveDuplicates(std::vector<Config>* config) {

-  ASSERT1(config);

-

-  // Iterate over the input configurations, remember the hash of each

-  // distinct configuration, and remove the duplicates by skipping the

-  // configurations seen before.

-  std::vector<Config> input(*config);

-  config->clear();

-

-  typedef stdext::hash_set<uint32> Keys;

-  Keys keys;

-  for (size_t i = 0; i != input.size(); ++i) {

-    std::pair<Keys::iterator, bool> result(keys.insert(hash_value(input[i])));

-    if (result.second) {

-      config->push_back(input[i]);

-    }

-  }

-}

-

-Config NetworkConfig::ParseNetConfig(const CString& net_config) {

-  Config config;

-  int pos(0);

-  CString token = net_config.Tokenize(_T(";"), pos);

-  while (pos != -1) {

-    CString name, value;

-    if (ParseNameValuePair(token, _T('='), &name, &value)) {

-      bool auto_detect(false);

-      if (name == _T("wpad") &&

-          SUCCEEDED(String_StringToBool(value, &auto_detect))) {

-        config.auto_detect = auto_detect;

-      } else if (name == _T("script")) {

-        config.auto_config_url = value;

-      } else if (name == _T("proxy")) {

-        config.proxy = value;

-      }

-    }

-    token = net_config.Tokenize(_T(";"), pos);

-  }

-  return config;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/net/network_config.h"
+
+#include <winhttp.h>
+#include <atlconv.h>
+#include <atlsecurity.h>
+#include <hash_set>
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/string.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/net/cup_request.h"
+#include "omaha/net/http_client.h"
+#include "omaha/goopdate/resource.h"
+
+using omaha::user_info::GetCurrentUser;
+
+namespace omaha {
+
+// Computes the hash value of a Config object. Names in the stdext namespace are
+// not currently part of the ISO C++ standard.
+uint32 hash_value(const Config& config) {
+  uint32 hash = stdext::hash_value(config.auto_detect)                 ^
+                stdext::hash_value(config.auto_config_url.GetString()) ^
+                stdext::hash_value(config.proxy.GetString())           ^
+                stdext::hash_value(config.proxy_bypass.GetString());
+  return hash;
+}
+
+NetworkConfig* const NetworkConfig::kInvalidInstance  =
+    reinterpret_cast<NetworkConfig* const>(-1);
+NetworkConfig* NetworkConfig::instance_               = NULL;
+
+const TCHAR* const NetworkConfig::kNetworkSubkey      = _T("network");
+const TCHAR* const NetworkConfig::kNetworkCupSubkey   = _T("secure");
+const TCHAR* const NetworkConfig::kCupClientSecretKey = _T("sk");
+const TCHAR* const NetworkConfig::kCupClientCookie    = _T("c");
+
+const TCHAR* const NetworkConfig::kUserAgent = _T("Google Update/%s");
+
+NetworkConfig::NetworkConfig()
+    : is_machine_(false),
+      is_initialized_(false) {}
+
+NetworkConfig::~NetworkConfig() {
+  if (session_.session_handle && http_client_.get()) {
+    http_client_->Close(session_.session_handle);
+    session_.session_handle = NULL;
+  }
+  if (session_.impersonation_token) {
+    ::CloseHandle(session_.impersonation_token);
+    session_.impersonation_token = NULL;
+  }
+  Clear();
+}
+
+NetworkConfig& NetworkConfig::Instance() {
+  // Getting the instance after the instance has been deleted is a bug in
+  // the logic of the program.
+  ASSERT1(instance_ != kInvalidInstance);
+  if (!instance_) {
+    instance_ = new NetworkConfig();
+  }
+  return *instance_;
+}
+
+// Initialize creates or opens a global lock to synchronize access to
+// registry where CUP credentials are stored. Each user including non-elevated
+// admins stores network configuration data, such as the CUP password in
+// its HKCU. The admin users, including the LOCAL_SYSTEM, store data in HKLM.
+// Therefore, the naming of the global lock is different: users have their
+// lock postfixed with their sid, so the serialization only occurs within the
+// same user's programs. Admin users use the same named lock since they store
+// data in a shared HKLM. The data of the admin users is disambiguated by
+// postfixing their registry sub key with sids.
+// In conclusion, users have sid-postfixed locks and their data goes in
+// their respective HKCU. Admin users have the same lock and their data goes
+// under HKLM in sid-postfixed stores.
+//
+// The named lock is created in the global namespace to account for users
+// logging in from different TS sessions.
+//
+// The CUP credentials must be protected with ACLs so non-elevated admins can't
+// read elevated-admins' keys and attack the protocol.
+//
+// Also, an Internet session is created and associated with the impersonation
+// token.
+HRESULT NetworkConfig::Initialize(bool is_machine,
+                                  HANDLE impersonation_token) {
+  ASSERT1(!is_initialized_);
+  is_machine_ = is_machine;
+  HRESULT hr = GetCurrentUser(NULL, NULL, &sid_);
+  if (FAILED(hr)) {
+    NET_LOG(LE, (_T("[GetCurrentUser failed][0x%x]"), hr));
+    return hr;
+  }
+  hr = InitializeLock();
+  if (FAILED(hr)) {
+    NET_LOG(LE, (_T("[InitializeLock failed][0x%x]"), hr));
+    return hr;
+  }
+  hr = InitializeRegistryKey();
+  if (FAILED(hr)) {
+    NET_LOG(LE, (_T("[InitializeRegistryKey failed][0x%x]"), hr));
+    return hr;
+  }
+
+  http_client_.reset(CreateHttpClient());
+  ASSERT1(http_client_.get());
+  if (!http_client_.get()) {
+    NET_LOG(LE, (_T("[CreateHttpClient failed]")));
+    return E_UNEXPECTED;
+  }
+  hr = http_client_->Initialize();
+  if (FAILED(hr)) {
+    // TODO(omaha): This makes an assumption that only WinHttp is
+    // supported by the network code.
+    NET_LOG(LE, (_T("[http_client_->Initialize() failed][0x%x]"), hr));
+    return OMAHA_NET_E_WINHTTP_NOT_AVAILABLE;
+  }
+
+  hr = http_client_->Open(NULL,
+                          WINHTTP_ACCESS_TYPE_NO_PROXY,
+                          WINHTTP_NO_PROXY_NAME,
+                          WINHTTP_NO_PROXY_BYPASS,
+                          &session_.session_handle);
+  if (FAILED(hr)) {
+    NET_LOG(LE, (_T("[http_client_->Open() failed][0x%x]"), hr));
+    return hr;
+  }
+
+  session_.impersonation_token = impersonation_token;
+  is_initialized_ = true;
+  return S_OK;
+}
+
+HRESULT NetworkConfig::InitializeLock() {
+  NamedObjectAttributes lock_attr;
+  GetNamedObjectAttributes(kNetworkConfigLock, is_machine_, &lock_attr);
+  return global_lock_.InitializeWithSecAttr(lock_attr.name, &lock_attr.sa) ?
+         S_OK : E_FAIL;
+}
+
+HRESULT NetworkConfig::InitializeRegistryKey() {
+  // The registry path under which to store persistent network configuration.
+  // The "network" subkey is created with default security. Below "network",
+  // the "secure" key is created so that only system and administrators have
+  // access to it.
+  registry_update_network_path_ = is_machine_ ? MACHINE_REG_UPDATE :
+                                                USER_REG_UPDATE;
+  registry_update_network_path_ =
+      AppendRegKeyPath(registry_update_network_path_, kNetworkSubkey);
+  RegKey reg_key_network;
+  DWORD disposition = 0;
+  HRESULT hr = reg_key_network.Create(registry_update_network_path_,
+                                      NULL,                 // Class.
+                                      0,                    // Options.
+                                      KEY_CREATE_SUB_KEY,   // SAM desired.
+                                      NULL,                 // Security attrs.
+                                      &disposition);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // When initializing for machine, grant access to administrators and system.
+  scoped_ptr<CSecurityAttributes> sa;
+  if (is_machine_) {
+    sa.reset(new CSecurityAttributes);
+    GetAdminDaclSecurityAttributes(sa.get(), GENERIC_ALL);
+  }
+
+  disposition = 0;
+  RegKey reg_key_network_secure;
+  CString subkey_name = is_machine_ ?
+                        JoinStrings(kNetworkCupSubkey, sid_, _T("-")) :
+                        kNetworkCupSubkey;
+  hr = reg_key_network_secure.Create(reg_key_network.Key(),  // Parent.
+                                     subkey_name,            // Subkey name.
+                                     NULL,                   // Class.
+                                     0,                      // Options.
+                                     KEY_READ,               // SAM desired.
+                                     sa.get(),               // Security attrs.
+                                     &disposition);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  return S_OK;
+}
+
+void NetworkConfig::Add(ProxyDetectorInterface* detector) {
+  ASSERT1(detector);
+  __mutexBlock(lock_) {
+    detectors_.push_back(detector);
+  }
+}
+
+void NetworkConfig::Clear() {
+  __mutexBlock(lock_) {
+    for (size_t i = 0; i != detectors_.size(); ++i) {
+      delete detectors_[i];
+    }
+    detectors_.clear();
+    configurations_.clear();
+  }
+}
+
+HRESULT NetworkConfig::Detect() {
+  __mutexBlock(lock_) {
+    std::vector<Config> configurations;
+    for (size_t i = 0; i != detectors_.size(); ++i) {
+      Config config;
+      if (SUCCEEDED(detectors_[i]->Detect(&config))) {
+        configurations.push_back(config);
+      }
+    }
+    configurations_.swap(configurations);
+  }
+  return S_OK;
+}
+
+std::vector<Config> NetworkConfig::GetConfigurations() const {
+  std::vector<Config> configurations;
+  __mutexBlock(lock_) {
+    configurations = configurations_;
+  }
+  return configurations;
+}
+
+HRESULT NetworkConfig::GetConfigurationOverride(Config* config) {
+  ASSERT1(config);
+  __mutexBlock(lock_) {
+    if (configuration_override_.get()) {
+      *config = *configuration_override_;
+      return S_OK;
+    }
+  }
+  return E_FAIL;
+}
+
+void NetworkConfig::SetConfigurationOverride(
+    const Config* configuration_override) {
+  __mutexBlock(lock_) {
+    if (configuration_override) {
+      configuration_override_.reset(new Config);
+      *configuration_override_ = *configuration_override;
+    } else {
+      configuration_override_.reset();
+    }
+  }
+}
+
+// Serializes configurations for debugging purposes.
+
+CString NetworkConfig::ToString(const Config& config) {
+  CString result;
+  result.AppendFormat(_T("source=%s, "), config.source);
+  switch (GetAccessType(config)) {
+    case WINHTTP_ACCESS_TYPE_NO_PROXY:
+      result.AppendFormat(_T("direct connection"));
+      break;
+    case WINHTTP_ACCESS_TYPE_NAMED_PROXY:
+      result.AppendFormat(_T("named proxy=%s, bypass=%s"),
+                          config.proxy, config.proxy_bypass);
+      break;
+    case WINHTTP_ACCESS_TYPE_AUTO_DETECT:
+      result.AppendFormat(_T("wpad=%d, script=%s"),
+                          config.auto_detect, config.auto_config_url);
+      break;
+    default:
+      ASSERT1(false);
+      break;
+  }
+  return result;
+}
+
+CString NetworkConfig::ToString(const std::vector<Config>& configurations) {
+  CString result;
+  for (size_t i = 0; i != configurations.size(); ++i) {
+    result.Append(NetworkConfig::ToString(configurations[i]));
+    result.Append(_T("\r\n"));
+  }
+  return result;
+}
+
+int NetworkConfig::GetAccessType(const Config& config) {
+  if (config.auto_detect || !config.auto_config_url.IsEmpty()) {
+    return WINHTTP_ACCESS_TYPE_AUTO_DETECT;
+  } else if (!config.proxy.IsEmpty()) {
+    return WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+  } else {
+    return WINHTTP_ACCESS_TYPE_NO_PROXY;
+  }
+}
+
+HRESULT NetworkConfig::GetCupCredentials(CupCredentials* cup_credentials) {
+  ASSERT1(cup_credentials);
+  ASSERT1(is_initialized_);
+  __mutexBlock(global_lock_) {
+    CString subkey_name = is_machine_ ?
+                          JoinStrings(kNetworkCupSubkey, sid_, _T("-")) :
+                          kNetworkCupSubkey;
+    CString key_name = AppendRegKeyPath(registry_update_network_path_,
+                                        subkey_name);
+    RegKey reg_key;
+    HRESULT hr = reg_key.Open(key_name, KEY_READ);
+    if (FAILED(hr)) {
+      return hr;
+    }
+    scoped_array<byte> buf;
+    DWORD buf_length = 0;
+    hr = reg_key.GetValue(kCupClientSecretKey, address(buf), &buf_length);
+    if (FAILED(hr)) {
+      return hr;
+    }
+    CString cookie;
+    hr = reg_key.GetValue(kCupClientCookie, &cookie);
+    if (FAILED(hr)) {
+      return hr;
+    }
+    cup_credentials->sk.resize(buf_length);
+    memcpy(&cup_credentials->sk.front(), buf.get(), buf_length);
+    cup_credentials->c = CT2A(cookie);
+  }
+  return S_OK;
+}
+
+HRESULT NetworkConfig::SetCupCredentials(
+            const CupCredentials* cup_credentials) {
+  ASSERT1(is_initialized_);
+  __mutexBlock(global_lock_) {
+    CString subkey_name = is_machine_ ?
+                          JoinStrings(kNetworkCupSubkey, sid_, _T("-")) :
+                          kNetworkCupSubkey;
+    CString key_name = AppendRegKeyPath(registry_update_network_path_,
+                                        subkey_name);
+    RegKey reg_key;
+    HRESULT hr = reg_key.Open(key_name, KEY_WRITE);
+    if (FAILED(hr)) {
+      NET_LOG(L2, (_T("[Registry key open failed][%s][0x%08x]"), key_name, hr));
+      return hr;
+    }
+    if (!cup_credentials) {
+      HRESULT hr1 = reg_key.DeleteValue(kCupClientSecretKey);
+      HRESULT hr2 = reg_key.DeleteValue(kCupClientCookie);
+      return (SUCCEEDED(hr1) && SUCCEEDED(hr2)) ? S_OK : HRESULTFromLastError();
+    }
+    hr = reg_key.SetValue(kCupClientSecretKey,
+             static_cast<const byte*>(&cup_credentials->sk.front()),
+             cup_credentials->sk.size());
+    if (FAILED(hr)) {
+      return hr;
+    }
+    hr = reg_key.SetValue(kCupClientCookie, CA2T(cup_credentials->c));
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+  return S_OK;
+}
+
+bool NetworkConfig::IsUsingCupTestKeys() {
+  DWORD value = 0;
+  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                 kRegValueCupKeys,
+                                 &value))) {
+    return value != 0;
+  } else {
+    return false;
+  }
+}
+
+void NetworkConfig::ConfigureProxyAuth(const CString& caption,
+                                       const CString& message,
+                                       HWND parent,
+                                       uint32 cancel_prompt_threshold) {
+  return proxy_auth_.ConfigureProxyAuth(caption, message, parent,
+                                        cancel_prompt_threshold);
+}
+
+bool NetworkConfig::GetProxyCredentials(bool allow_ui,
+                                        bool force_ui,
+                                        const CString& proxy_settings,
+                                        bool is_https,
+                                        CString* username,
+                                        CString* password,
+                                        uint32* auth_scheme) {
+  ASSERT1(username);
+  ASSERT1(password);
+  ASSERT1(auth_scheme);
+  const CString& proxy = ProxyAuth::ExtractProxy(proxy_settings, is_https);
+  return proxy_auth_.GetProxyCredentials(allow_ui, force_ui, proxy,
+                                         username, password, auth_scheme);
+}
+
+HRESULT NetworkConfig::SetProxyAuthScheme(const CString& proxy_settings,
+                                          bool is_https,
+                                          uint32 auth_scheme) {
+  ASSERT1(auth_scheme != UNKNOWN_AUTH_SCHEME);
+  const CString& proxy = ProxyAuth::ExtractProxy(proxy_settings, is_https);
+  return proxy_auth_.SetProxyAuthScheme(proxy, auth_scheme);
+}
+
+// TODO(omaha): the code does WPAD auto detect in all cases. It is possible for
+// a configuration to specify no auto detection but provide the proxy script
+// url. The current code does not account for this yet.
+HRESULT NetworkConfig::GetProxyForUrl(const CString& url,
+                                      const CString& auto_config_url,
+                                      HttpClient::ProxyInfo* proxy_info) {
+  ASSERT1(proxy_info);
+  HttpClient::AutoProxyOptions auto_proxy_options = {0};
+  auto_proxy_options.flags = WINHTTP_AUTOPROXY_AUTO_DETECT;
+  auto_proxy_options.auto_detect_flags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
+                                         WINHTTP_AUTO_DETECT_TYPE_DNS_A;
+  if (!auto_config_url.IsEmpty()) {
+    auto_proxy_options.auto_config_url = auto_config_url;
+    auto_proxy_options.flags |= WINHTTP_AUTOPROXY_CONFIG_URL;
+  }
+  auto_proxy_options.auto_logon_if_challenged = true;
+
+  return http_client_->GetProxyForUrl(session_.session_handle,
+                                      url,
+                                      &auto_proxy_options,
+                                      proxy_info);
+}
+
+CString NetworkConfig::GetUserAgent() {
+  CString user_agent;
+  user_agent.Format(kUserAgent, GetVersionString());
+  return user_agent;
+}
+
+CString NetworkConfig::JoinStrings(const TCHAR* s1,
+                                   const TCHAR* s2,
+                                   const TCHAR* delim) {
+  CString result;
+  const TCHAR* components[] = {s1, s2};
+  JoinStringsInArray(components, arraysize(components), delim, &result);
+  return result;
+}
+
+// Using std::hash_set adds about 2K uncompressed code size. Using a CAtlMap
+// adds about 1.5K. Usually, there are only five detected configurations so
+// an O(n^2) algorithm would work well. The advantage of the current
+// implementation is simplicity. It also does not handle conflicts. Conflicts
+// are not expected, due to how the Config structure is being used.
+// TODO(omaha): consider not using the hash_set and save about 1K of code.
+void NetworkConfig::RemoveDuplicates(std::vector<Config>* config) {
+  ASSERT1(config);
+
+  // Iterate over the input configurations, remember the hash of each
+  // distinct configuration, and remove the duplicates by skipping the
+  // configurations seen before.
+  std::vector<Config> input(*config);
+  config->clear();
+
+  typedef stdext::hash_set<uint32> Keys;
+  Keys keys;
+  for (size_t i = 0; i != input.size(); ++i) {
+    std::pair<Keys::iterator, bool> result(keys.insert(hash_value(input[i])));
+    if (result.second) {
+      config->push_back(input[i]);
+    }
+  }
+}
+
+Config NetworkConfig::ParseNetConfig(const CString& net_config) {
+  Config config;
+  int pos(0);
+  CString token = net_config.Tokenize(_T(";"), pos);
+  while (pos != -1) {
+    CString name, value;
+    if (ParseNameValuePair(token, _T('='), &name, &value)) {
+      bool auto_detect(false);
+      if (name == _T("wpad") &&
+          SUCCEEDED(String_StringToBool(value, &auto_detect))) {
+        config.auto_detect = auto_detect;
+      } else if (name == _T("script")) {
+        config.auto_config_url = value;
+      } else if (name == _T("proxy")) {
+        config.proxy = value;
+      }
+    }
+    token = net_config.Tokenize(_T(";"), pos);
+  }
+  return config;
+}
+
+}  // namespace omaha
+
diff --git a/net/network_config.h b/net/network_config.h
index 27d40c2..ce16cb7 100644
--- a/net/network_config.h
+++ b/net/network_config.h
@@ -1,287 +1,287 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// TODO(omaha): provide a way to remember the last good network configuration.

-

-// TODO(omaha): maybe reconsider the singleton and allow multiple instances

-// of it to exist, to allow for testability. The app will most likely use it as

-// a singleton but the class itself should allow for multiple instances.

-

-// TODO(omaha): might need to remove dependency on winhttp.h when implementing

-// support for wininet; see http://b/1119232

-

-#ifndef OMAHA_NET_NETWORK_CONFIG_H__

-#define OMAHA_NET_NETWORK_CONFIG_H__

-

-#include <windows.h>

-#include <winhttp.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/net/detector.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/proxy_auth.h"

-

-namespace ATL {

-

-class CSecurityDesc;

-

-}  // namespace ATL

-

-namespace omaha {

-

-// There are three ways by which an application could connect to the Internet:

-// 1. Direct connection.

-//    The config for the direction connection must not specify WPAD information

-//    nor named proxy information.

-// 2. Named proxy.

-//    The config for named proxy only includes proxy and proxy_bypass.

-// 3. Proxy auto detection.

-//    The config for proxy auto detection should include either the auto-detect

-//    flag or the auto configuration url. Named proxy information is discarded

-//    if present.

-struct Config {

-  Config() : auto_detect(false) {}

-

-  // Mostly used for debugging purposes to identify who created the instance.

-  CString source;

-

-  // Specifies the configuration is WPAD.

-  bool auto_detect;

-

-  // The url of the proxy configuration script, if known.

-  CString auto_config_url;

-

-  // Named proxy information.

-  // The proxy string is usually something as "http=foo:80;https=bar:8080".

-  // According to the documentation for WINHTTP_PROXY_INFO, multiple proxies

-  // are separated by semicolons or whitespace. The documentation for

-  // IBackgroundCopyJob::SetProxySettings says that the list is

-  // space-delimited.

-  // TODO(omaha): our proxy information is semicolon-separated. This may

-  // result in compatibility problems with BITS. Fix this.

-  CString proxy;

-  CString proxy_bypass;

-};

-

-struct CupCredentials;

-

-// Manages the network configurations.

-class NetworkConfig {

-  public:

-

-  // Abstracts the Internet session, as provided by winhttp or wininet.

-  // A winhttp session should map to one and only one identity. in other words,

-  // a winhttp session is used to manage the network traffic of a single

-  // authenticated user, or a group of anonymous users.

-  struct Session {

-    Session()

-        : session_handle(NULL),

-          impersonation_token(NULL) {}

-

-    HINTERNET session_handle;

-    HANDLE    impersonation_token;

-  };

-

-  // Instance, Initialize, and DeleteInstance methods below are not thread safe.

-  // The caller must initialize and cleanup the instance before going

-  // multithreaded.

-  //

-  // Gets the singleton instance of the class.

-  // TODO(omaha): rename to GetInstance for consistency

-  static NetworkConfig& Instance();

-

-  // Initializes the instance. It takes ownership of the impersonation token

-  // provided.

-  HRESULT Initialize(bool is_machine, HANDLE impersonation_token);

-

-  bool is_initialized() const { return is_initialized_; }

-

-  // Cleans up the class instance.

-  static void DeleteInstance();

-

-  // Hooks up a proxy detector. The class takes ownership of the detector.

-  void Add(ProxyDetectorInterface* detector);

-

-  // Clears all detectors and configurations. It does not clear the session.

-  // TODO(omaha): rename to avoid the confusion that Clear clears the sessions

-  // as well.

-  void Clear();

-

-  // Detects the network configuration for each of the registered detectors.

-  HRESULT Detect();

-

-  // Returns the detected configurations.

-  std::vector<Config> GetConfigurations() const;

-

-  // Gets the persisted CUP credentials.

-  HRESULT GetCupCredentials(CupCredentials* cup_credentials);

-

-  // Saves the CUP credentials in persistent storage. If the parameter is null,

-  // it clears the credentials.

-  HRESULT SetCupCredentials(const CupCredentials* cup_credentials);

-

-  // The caption is an unformatted string. The message is a formatted string

-  // that accepts one FormatMessage parameter, the proxy server. The

-  // cancel_prompt_threshold is the max number of times the user will see

-  // prompts for this process.

-  void ConfigureProxyAuth(const CString& caption, const CString& message,

-                          HWND parent, uint32 cancel_prompt_threshold);

-

-  // Prompts for credentials, or gets cached credentials if they exist.

-  bool GetProxyCredentials(bool allow_ui,

-                           bool force_ui,

-                           const CString& proxy_settings,

-                           bool is_https,

-                           CString* username,

-                           CString* password,

-                           uint32* auth_scheme);

-

-  // Once a auth scheme has been verified against a proxy, this allows a client

-  // to record the auth scheme that was used and was successful, so it can be

-  // cached for future use within this process.

-  HRESULT SetProxyAuthScheme(const CString& proxy_settings,

-                             bool is_https,

-                             uint32 auth_scheme);

-

-  // Runs the WPAD protocol to compute the proxy information to be used

-  // for the given url. The ProxyInfo pointer members must be freed using

-  // GlobalFree.

-  HRESULT GetProxyForUrl(const CString& url,

-                         const CString& auto_config_url,

-                         HttpClient::ProxyInfo* proxy_info);

-

-  Session session() const { return session_; }

-

-  // Returns the global configuration override if available.

-  HRESULT GetConfigurationOverride(Config* configuration_override);

-

-  // Sets the global configuration override. The function clears the existing

-  // configuration if the parameter is NULL.

-  void SetConfigurationOverride(const Config* configuration_override);

-

-  // True if the CUP test keys are being used to negotiate the CUP

-  // credentials.

-  bool static IsUsingCupTestKeys();

-

-  // Returns the prefix of the user agent string.

-  static CString GetUserAgent();

-

-  // Eliminates the redundant configurations, for example, if multiple

-  // direct connection or proxy auto-detect occur.

-  static void RemoveDuplicates(std::vector<Config>*);

-

-  // Parses a network configuration string. The format of the string is:

-  // wpad=[false|true];script=script_url;proxy=host:port

-  // Ignores the names and the values it does not understand.

-  static Config ParseNetConfig(const CString& net_config);

-

-  // Serializes configurations for debugging purposes.

-  static CString ToString(const std::vector<Config>& configurations);

-  static CString ToString(const Config& configuration);

-

-  static int GetAccessType(const Config& config);

-

-  // Returns s1 + delim + s2. Consider making it an utility function if

-  // more usage patterns are found.

-  static CString JoinStrings(const TCHAR* s1,

-                             const TCHAR* s2,

-                             const TCHAR* delim);

-

- private:

-  NetworkConfig();

-  ~NetworkConfig();

-

-  HRESULT InitializeLock();

-  HRESULT InitializeRegistryKey();

-

-  static NetworkConfig* const kInvalidInstance;

-  static NetworkConfig* instance_;

-

-  // Registry sub key where network configuration is persisted.

-  static const TCHAR* const kNetworkSubkey;

-

-  // Registry sub key where CUP configuration is persisted.

-  static const TCHAR* const kNetworkCupSubkey;

-

-  // The secret key must be encrypted by the caller. This class does not do any

-  // encryption.

-  static const TCHAR* const kCupClientSecretKey;      // CUP sk.

-  static const TCHAR* const kCupClientCookie;         // CUP c.

-

-  static const TCHAR* const kUserAgent;

-

-  bool is_machine_;     // True if the instance is initialized for machine.

-

-  std::vector<Config> configurations_;

-  std::vector<ProxyDetectorInterface*> detectors_;

-

-  CString sid_;   // The user sid.

-

-  // The registry path under which to store persistent network configuration.

-  CString registry_update_network_path_;

-

-  // Synchronizes access to per-process instance data, which includes

-  // the detectors and configurations.

-  LLock lock_;

-

-  // Synchronizes access to per-session instance data, such as the

-  // CUP credentials.

-  GLock global_lock_;

-

-  bool is_initialized_;

-

-  scoped_ptr<Config> configuration_override_;

-

-  Session session_;

-  scoped_ptr<HttpClient> http_client_;

-

-  // Manages the proxy auth credentials. Typically a http client tries to

-  // use autologon via Negotiate/NTLM with a proxy server. If that fails, the

-  // Http client then calls GetProxyCredentials() on NetworkConfig.

-  // GetProxyCredentials() gets credentials by either prompting the user, or

-  // cached credentials. Then the http client tries again. Options are set via

-  // ConfigureProxyAuth().

-  ProxyAuth proxy_auth_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(NetworkConfig);

-};

-

-// For unittests, where creation and termination of NetworkConfig instances

-// is required, the implementation disables the dead reference detection. This

-// forces an inline of the code below for unit tests, so different behavior

-// can be achieved, even though the rest of the implementation compiles in

-// a library. It is somehow brittle but good enough for now.

-

-#ifdef UNITTEST

-__forceinline

-#else

-  inline

-#endif

-void NetworkConfig::DeleteInstance() {

-  delete instance_;

-#ifdef UNITTEST

-  instance_ = NULL;

-#else

-  instance_ = kInvalidInstance;

-#endif

-}

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_NETWORK_CONFIG_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// TODO(omaha): provide a way to remember the last good network configuration.
+
+// TODO(omaha): maybe reconsider the singleton and allow multiple instances
+// of it to exist, to allow for testability. The app will most likely use it as
+// a singleton but the class itself should allow for multiple instances.
+
+// TODO(omaha): might need to remove dependency on winhttp.h when implementing
+// support for wininet; see http://b/1119232
+
+#ifndef OMAHA_NET_NETWORK_CONFIG_H__
+#define OMAHA_NET_NETWORK_CONFIG_H__
+
+#include <windows.h>
+#include <winhttp.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/net/detector.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/proxy_auth.h"
+
+namespace ATL {
+
+class CSecurityDesc;
+
+}  // namespace ATL
+
+namespace omaha {
+
+// There are three ways by which an application could connect to the Internet:
+// 1. Direct connection.
+//    The config for the direction connection must not specify WPAD information
+//    nor named proxy information.
+// 2. Named proxy.
+//    The config for named proxy only includes proxy and proxy_bypass.
+// 3. Proxy auto detection.
+//    The config for proxy auto detection should include either the auto-detect
+//    flag or the auto configuration url. Named proxy information is discarded
+//    if present.
+struct Config {
+  Config() : auto_detect(false) {}
+
+  // Mostly used for debugging purposes to identify who created the instance.
+  CString source;
+
+  // Specifies the configuration is WPAD.
+  bool auto_detect;
+
+  // The url of the proxy configuration script, if known.
+  CString auto_config_url;
+
+  // Named proxy information.
+  // The proxy string is usually something as "http=foo:80;https=bar:8080".
+  // According to the documentation for WINHTTP_PROXY_INFO, multiple proxies
+  // are separated by semicolons or whitespace. The documentation for
+  // IBackgroundCopyJob::SetProxySettings says that the list is
+  // space-delimited.
+  // TODO(omaha): our proxy information is semicolon-separated. This may
+  // result in compatibility problems with BITS. Fix this.
+  CString proxy;
+  CString proxy_bypass;
+};
+
+struct CupCredentials;
+
+// Manages the network configurations.
+class NetworkConfig {
+  public:
+
+  // Abstracts the Internet session, as provided by winhttp or wininet.
+  // A winhttp session should map to one and only one identity. in other words,
+  // a winhttp session is used to manage the network traffic of a single
+  // authenticated user, or a group of anonymous users.
+  struct Session {
+    Session()
+        : session_handle(NULL),
+          impersonation_token(NULL) {}
+
+    HINTERNET session_handle;
+    HANDLE    impersonation_token;
+  };
+
+  // Instance, Initialize, and DeleteInstance methods below are not thread safe.
+  // The caller must initialize and cleanup the instance before going
+  // multithreaded.
+  //
+  // Gets the singleton instance of the class.
+  // TODO(omaha): rename to GetInstance for consistency
+  static NetworkConfig& Instance();
+
+  // Initializes the instance. It takes ownership of the impersonation token
+  // provided.
+  HRESULT Initialize(bool is_machine, HANDLE impersonation_token);
+
+  bool is_initialized() const { return is_initialized_; }
+
+  // Cleans up the class instance.
+  static void DeleteInstance();
+
+  // Hooks up a proxy detector. The class takes ownership of the detector.
+  void Add(ProxyDetectorInterface* detector);
+
+  // Clears all detectors and configurations. It does not clear the session.
+  // TODO(omaha): rename to avoid the confusion that Clear clears the sessions
+  // as well.
+  void Clear();
+
+  // Detects the network configuration for each of the registered detectors.
+  HRESULT Detect();
+
+  // Returns the detected configurations.
+  std::vector<Config> GetConfigurations() const;
+
+  // Gets the persisted CUP credentials.
+  HRESULT GetCupCredentials(CupCredentials* cup_credentials);
+
+  // Saves the CUP credentials in persistent storage. If the parameter is null,
+  // it clears the credentials.
+  HRESULT SetCupCredentials(const CupCredentials* cup_credentials);
+
+  // The caption is an unformatted string. The message is a formatted string
+  // that accepts one FormatMessage parameter, the proxy server. The
+  // cancel_prompt_threshold is the max number of times the user will see
+  // prompts for this process.
+  void ConfigureProxyAuth(const CString& caption, const CString& message,
+                          HWND parent, uint32 cancel_prompt_threshold);
+
+  // Prompts for credentials, or gets cached credentials if they exist.
+  bool GetProxyCredentials(bool allow_ui,
+                           bool force_ui,
+                           const CString& proxy_settings,
+                           bool is_https,
+                           CString* username,
+                           CString* password,
+                           uint32* auth_scheme);
+
+  // Once a auth scheme has been verified against a proxy, this allows a client
+  // to record the auth scheme that was used and was successful, so it can be
+  // cached for future use within this process.
+  HRESULT SetProxyAuthScheme(const CString& proxy_settings,
+                             bool is_https,
+                             uint32 auth_scheme);
+
+  // Runs the WPAD protocol to compute the proxy information to be used
+  // for the given url. The ProxyInfo pointer members must be freed using
+  // GlobalFree.
+  HRESULT GetProxyForUrl(const CString& url,
+                         const CString& auto_config_url,
+                         HttpClient::ProxyInfo* proxy_info);
+
+  Session session() const { return session_; }
+
+  // Returns the global configuration override if available.
+  HRESULT GetConfigurationOverride(Config* configuration_override);
+
+  // Sets the global configuration override. The function clears the existing
+  // configuration if the parameter is NULL.
+  void SetConfigurationOverride(const Config* configuration_override);
+
+  // True if the CUP test keys are being used to negotiate the CUP
+  // credentials.
+  bool static IsUsingCupTestKeys();
+
+  // Returns the prefix of the user agent string.
+  static CString GetUserAgent();
+
+  // Eliminates the redundant configurations, for example, if multiple
+  // direct connection or proxy auto-detect occur.
+  static void RemoveDuplicates(std::vector<Config>*);
+
+  // Parses a network configuration string. The format of the string is:
+  // wpad=[false|true];script=script_url;proxy=host:port
+  // Ignores the names and the values it does not understand.
+  static Config ParseNetConfig(const CString& net_config);
+
+  // Serializes configurations for debugging purposes.
+  static CString ToString(const std::vector<Config>& configurations);
+  static CString ToString(const Config& configuration);
+
+  static int GetAccessType(const Config& config);
+
+  // Returns s1 + delim + s2. Consider making it an utility function if
+  // more usage patterns are found.
+  static CString JoinStrings(const TCHAR* s1,
+                             const TCHAR* s2,
+                             const TCHAR* delim);
+
+ private:
+  NetworkConfig();
+  ~NetworkConfig();
+
+  HRESULT InitializeLock();
+  HRESULT InitializeRegistryKey();
+
+  static NetworkConfig* const kInvalidInstance;
+  static NetworkConfig* instance_;
+
+  // Registry sub key where network configuration is persisted.
+  static const TCHAR* const kNetworkSubkey;
+
+  // Registry sub key where CUP configuration is persisted.
+  static const TCHAR* const kNetworkCupSubkey;
+
+  // The secret key must be encrypted by the caller. This class does not do any
+  // encryption.
+  static const TCHAR* const kCupClientSecretKey;      // CUP sk.
+  static const TCHAR* const kCupClientCookie;         // CUP c.
+
+  static const TCHAR* const kUserAgent;
+
+  bool is_machine_;     // True if the instance is initialized for machine.
+
+  std::vector<Config> configurations_;
+  std::vector<ProxyDetectorInterface*> detectors_;
+
+  CString sid_;   // The user sid.
+
+  // The registry path under which to store persistent network configuration.
+  CString registry_update_network_path_;
+
+  // Synchronizes access to per-process instance data, which includes
+  // the detectors and configurations.
+  LLock lock_;
+
+  // Synchronizes access to per-session instance data, such as the
+  // CUP credentials.
+  GLock global_lock_;
+
+  bool is_initialized_;
+
+  scoped_ptr<Config> configuration_override_;
+
+  Session session_;
+  scoped_ptr<HttpClient> http_client_;
+
+  // Manages the proxy auth credentials. Typically a http client tries to
+  // use autologon via Negotiate/NTLM with a proxy server. If that fails, the
+  // Http client then calls GetProxyCredentials() on NetworkConfig.
+  // GetProxyCredentials() gets credentials by either prompting the user, or
+  // cached credentials. Then the http client tries again. Options are set via
+  // ConfigureProxyAuth().
+  ProxyAuth proxy_auth_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(NetworkConfig);
+};
+
+// For unittests, where creation and termination of NetworkConfig instances
+// is required, the implementation disables the dead reference detection. This
+// forces an inline of the code below for unit tests, so different behavior
+// can be achieved, even though the rest of the implementation compiles in
+// a library. It is somehow brittle but good enough for now.
+
+#ifdef UNITTEST
+__forceinline
+#else
+  inline
+#endif
+void NetworkConfig::DeleteInstance() {
+  delete instance_;
+#ifdef UNITTEST
+  instance_ = NULL;
+#else
+  instance_ = kInvalidInstance;
+#endif
+}
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_NETWORK_CONFIG_H__
+
diff --git a/net/network_config_unittest.cc b/net/network_config_unittest.cc
index 5d1e101..d751252 100644
--- a/net/network_config_unittest.cc
+++ b/net/network_config_unittest.cc
@@ -1,223 +1,223 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <atlconv.h>

-#include <cstring>

-#include "base/basictypes.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/net/cup_request.h"

-#include "omaha/net/cup_utils.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/network_config.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class NetworkConfigTest : public testing::Test {

- protected:

-  NetworkConfigTest() {}

-

-  static void SetUpTestCase() {}

-

-  static void TearDownTestCase() {}

-

-  virtual void SetUp() {}

-

-  virtual void TearDown() {}

-};

-

-TEST_F(NetworkConfigTest, GetAccessType) {

-  EXPECT_EQ(NetworkConfig::GetAccessType(Config()),

-            WINHTTP_ACCESS_TYPE_NO_PROXY);

-

-  Config config;

-  config.auto_detect = true;

-  EXPECT_EQ(NetworkConfig::GetAccessType(config),

-            WINHTTP_ACCESS_TYPE_AUTO_DETECT);

-

-  config = Config();

-  config.auto_config_url = _T("http://foo");

-  EXPECT_EQ(NetworkConfig::GetAccessType(config),

-            WINHTTP_ACCESS_TYPE_AUTO_DETECT);

-

-  config = Config();

-  config.auto_detect = true;

-  config.proxy = _T("foo");

-  EXPECT_EQ(NetworkConfig::GetAccessType(config),

-            WINHTTP_ACCESS_TYPE_AUTO_DETECT);

-

-  config = Config();

-  config.proxy = _T("foo");

-  EXPECT_EQ(NetworkConfig::GetAccessType(config),

-            WINHTTP_ACCESS_TYPE_NAMED_PROXY);

-}

-

-TEST_F(NetworkConfigTest, CupCredentials) {

-  NetworkConfig& network_config = NetworkConfig::Instance();

-  EXPECT_HRESULT_SUCCEEDED(network_config.SetCupCredentials(NULL));

-

-  CupCredentials cup_credentials1;

-  EXPECT_HRESULT_FAILED(network_config.GetCupCredentials(&cup_credentials1));

-

-  // Start with some random bytes. Persist them as sk and as B64-encoded c.

-  // Read back and verify they match.

-  uint8 data[20] = {0};

-  EXPECT_TRUE(GenRandom(data, arraysize(data)));

-

-  const uint8* first = data;

-  const uint8* last  = data + arraysize(data);

-  cup_credentials1.sk.insert(cup_credentials1.sk.begin(), first, last);

-  cup_credentials1.c = cup_utils::B64Encode(data, arraysize(data));

-

-  EXPECT_HRESULT_SUCCEEDED(network_config.SetCupCredentials(&cup_credentials1));

-

-  CupCredentials cup_credentials2;

-  EXPECT_HRESULT_SUCCEEDED(network_config.GetCupCredentials(&cup_credentials2));

-  EXPECT_EQ(cup_credentials1.sk.size(), cup_credentials2.sk.size());

-  EXPECT_TRUE(memcmp(&cup_credentials1.sk.front(),

-                     &cup_credentials2.sk.front(),

-                     cup_credentials1.sk.size()) == 0);

-  EXPECT_STREQ(cup_credentials1.c, cup_credentials2.c);

-

-  EXPECT_HRESULT_SUCCEEDED(network_config.SetCupCredentials(NULL));

-  EXPECT_HRESULT_FAILED(network_config.GetCupCredentials(&cup_credentials1));

-}

-

-TEST_F(NetworkConfigTest, JoinStrings) {

-  EXPECT_STREQ(NetworkConfig::JoinStrings(NULL, NULL, NULL), _T(""));

-

-  CString result;

-  EXPECT_STREQ(NetworkConfig::JoinStrings(NULL, NULL, _T("-")), _T("-"));

-  EXPECT_STREQ(NetworkConfig::JoinStrings(_T("foo"), _T("bar"), _T("-")),

-                                          _T("foo-bar"));

-}

-

-TEST_F(NetworkConfigTest, GetUserAgentTest) {

-  CString version(GetVersionString());

-  EXPECT_FALSE(version.IsEmpty());

-  CString actual_user_agent(NetworkConfig::GetUserAgent());

-  CString expected_user_agent;

-  expected_user_agent.Format(_T("Google Update/%s"), version);

-  EXPECT_STREQ(actual_user_agent, expected_user_agent);

-}

-

-// Hosts names used in the test are only used as string literals.

-TEST_F(NetworkConfigTest, RemoveDuplicates) {

-  // 'source' is not considered in the hash computation.

-  std::vector<Config> configurations;

-  Config cfg1;

-  cfg1.source = "foo";

-  Config cfg2;

-  cfg2.source = "bar";

-  configurations.push_back(cfg1);

-  configurations.push_back(cfg2);

-  NetworkConfig::RemoveDuplicates(&configurations);

-  EXPECT_EQ(1, configurations.size());

-  configurations.clear();

-

-  // Remove redundant direct connection configurations.

-  Config direct_config;

-  configurations.push_back(direct_config);

-  configurations.push_back(direct_config);

-  NetworkConfig::RemoveDuplicates(&configurations);

-  EXPECT_EQ(1, configurations.size());

-  configurations.clear();

-

-  // Remove redundant WPAD configurations.

-  Config wpad_config;

-  wpad_config.auto_detect = true;

-  configurations.push_back(wpad_config);

-  configurations.push_back(wpad_config);

-  NetworkConfig::RemoveDuplicates(&configurations);

-  EXPECT_EQ(1, configurations.size());

-  configurations.clear();

-

-  // Remove redundant WPAD with auto config url configurations.

-  Config wpad_url_config;

-  wpad_url_config.auto_detect = true;

-  wpad_url_config.auto_config_url = _T("http://www.google.com/wpad.dat");

-  configurations.push_back(wpad_url_config);

-  configurations.push_back(wpad_url_config);

-  NetworkConfig::RemoveDuplicates(&configurations);

-  EXPECT_EQ(1, configurations.size());

-  configurations.clear();

-

-  // Remove redundant named proxy configurations.

-  Config named_proxy_config;

-  named_proxy_config.proxy = _T("www1.google.com:3128");

-  configurations.push_back(named_proxy_config);

-  configurations.push_back(named_proxy_config);

-  NetworkConfig::RemoveDuplicates(&configurations);

-  EXPECT_EQ(1, configurations.size());

-  configurations.clear();

-

-  // Does not remove distinct configurations.

-  Config named_proxy_config_alt;

-  named_proxy_config_alt.proxy = _T("www2.google.com:3128");

-  configurations.push_back(named_proxy_config);

-  configurations.push_back(named_proxy_config_alt);

-  configurations.push_back(direct_config);

-  configurations.push_back(wpad_config);

-  configurations.push_back(wpad_url_config);

-  NetworkConfig::RemoveDuplicates(&configurations);

-  EXPECT_EQ(5, configurations.size());

-}

-

-TEST_F(NetworkConfigTest, ParseNetConfig) {

-  Config config = NetworkConfig::ParseNetConfig(_T(""));

-  EXPECT_EQ(false, config.auto_detect);

-  EXPECT_EQ(true,  config.auto_config_url.IsEmpty());

-  EXPECT_EQ(true,  config.proxy.IsEmpty());

-

-  config = NetworkConfig::ParseNetConfig(_T("wpad=false"));

-  EXPECT_EQ(false, config.auto_detect);

-  EXPECT_EQ(true,  config.auto_config_url.IsEmpty());

-  EXPECT_EQ(true,  config.proxy.IsEmpty());

-

-  config = NetworkConfig::ParseNetConfig(_T("wpad=true"));

-  EXPECT_EQ(true,  config.auto_detect);

-  EXPECT_EQ(true,  config.auto_config_url.IsEmpty());

-  EXPECT_EQ(true,  config.proxy.IsEmpty());

-

-  config = NetworkConfig::ParseNetConfig(_T("script=foo;proxy=bar"));

-  EXPECT_EQ(false, config.auto_detect);

-  EXPECT_STREQ(_T("foo"), config.auto_config_url);

-  EXPECT_EQ(_T("bar"), config.proxy);

-

-  config = NetworkConfig::ParseNetConfig(_T("proxy=foobar"));

-  EXPECT_EQ(false, config.auto_detect);

-  EXPECT_EQ(true, config.auto_config_url.IsEmpty());

-  EXPECT_EQ(_T("foobar"), config.proxy);

-}

-

-TEST_F(NetworkConfigTest, ConfigurationOverride) {

-  NetworkConfig& network_config = NetworkConfig::Instance();

-

-  Config actual, expected;

-  expected.auto_detect = true;

-  network_config.SetConfigurationOverride(&expected);

-  EXPECT_HRESULT_SUCCEEDED(network_config.GetConfigurationOverride(&actual));

-  EXPECT_EQ(expected.auto_detect, actual.auto_detect);

-

-  network_config.SetConfigurationOverride(NULL);

-  EXPECT_EQ(E_FAIL, network_config.GetConfigurationOverride(&actual));

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <atlconv.h>
+#include <cstring>
+#include "base/basictypes.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/net/cup_request.h"
+#include "omaha/net/cup_utils.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/network_config.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class NetworkConfigTest : public testing::Test {
+ protected:
+  NetworkConfigTest() {}
+
+  static void SetUpTestCase() {}
+
+  static void TearDownTestCase() {}
+
+  virtual void SetUp() {}
+
+  virtual void TearDown() {}
+};
+
+TEST_F(NetworkConfigTest, GetAccessType) {
+  EXPECT_EQ(NetworkConfig::GetAccessType(Config()),
+            WINHTTP_ACCESS_TYPE_NO_PROXY);
+
+  Config config;
+  config.auto_detect = true;
+  EXPECT_EQ(NetworkConfig::GetAccessType(config),
+            WINHTTP_ACCESS_TYPE_AUTO_DETECT);
+
+  config = Config();
+  config.auto_config_url = _T("http://foo");
+  EXPECT_EQ(NetworkConfig::GetAccessType(config),
+            WINHTTP_ACCESS_TYPE_AUTO_DETECT);
+
+  config = Config();
+  config.auto_detect = true;
+  config.proxy = _T("foo");
+  EXPECT_EQ(NetworkConfig::GetAccessType(config),
+            WINHTTP_ACCESS_TYPE_AUTO_DETECT);
+
+  config = Config();
+  config.proxy = _T("foo");
+  EXPECT_EQ(NetworkConfig::GetAccessType(config),
+            WINHTTP_ACCESS_TYPE_NAMED_PROXY);
+}
+
+TEST_F(NetworkConfigTest, CupCredentials) {
+  NetworkConfig& network_config = NetworkConfig::Instance();
+  EXPECT_HRESULT_SUCCEEDED(network_config.SetCupCredentials(NULL));
+
+  CupCredentials cup_credentials1;
+  EXPECT_HRESULT_FAILED(network_config.GetCupCredentials(&cup_credentials1));
+
+  // Start with some random bytes. Persist them as sk and as B64-encoded c.
+  // Read back and verify they match.
+  uint8 data[20] = {0};
+  EXPECT_TRUE(GenRandom(data, arraysize(data)));
+
+  const uint8* first = data;
+  const uint8* last  = data + arraysize(data);
+  cup_credentials1.sk.insert(cup_credentials1.sk.begin(), first, last);
+  cup_credentials1.c = cup_utils::B64Encode(data, arraysize(data));
+
+  EXPECT_HRESULT_SUCCEEDED(network_config.SetCupCredentials(&cup_credentials1));
+
+  CupCredentials cup_credentials2;
+  EXPECT_HRESULT_SUCCEEDED(network_config.GetCupCredentials(&cup_credentials2));
+  EXPECT_EQ(cup_credentials1.sk.size(), cup_credentials2.sk.size());
+  EXPECT_TRUE(memcmp(&cup_credentials1.sk.front(),
+                     &cup_credentials2.sk.front(),
+                     cup_credentials1.sk.size()) == 0);
+  EXPECT_STREQ(cup_credentials1.c, cup_credentials2.c);
+
+  EXPECT_HRESULT_SUCCEEDED(network_config.SetCupCredentials(NULL));
+  EXPECT_HRESULT_FAILED(network_config.GetCupCredentials(&cup_credentials1));
+}
+
+TEST_F(NetworkConfigTest, JoinStrings) {
+  EXPECT_STREQ(NetworkConfig::JoinStrings(NULL, NULL, NULL), _T(""));
+
+  CString result;
+  EXPECT_STREQ(NetworkConfig::JoinStrings(NULL, NULL, _T("-")), _T("-"));
+  EXPECT_STREQ(NetworkConfig::JoinStrings(_T("foo"), _T("bar"), _T("-")),
+                                          _T("foo-bar"));
+}
+
+TEST_F(NetworkConfigTest, GetUserAgentTest) {
+  CString version(GetVersionString());
+  EXPECT_FALSE(version.IsEmpty());
+  CString actual_user_agent(NetworkConfig::GetUserAgent());
+  CString expected_user_agent;
+  expected_user_agent.Format(_T("Google Update/%s"), version);
+  EXPECT_STREQ(actual_user_agent, expected_user_agent);
+}
+
+// Hosts names used in the test are only used as string literals.
+TEST_F(NetworkConfigTest, RemoveDuplicates) {
+  // 'source' is not considered in the hash computation.
+  std::vector<Config> configurations;
+  Config cfg1;
+  cfg1.source = "foo";
+  Config cfg2;
+  cfg2.source = "bar";
+  configurations.push_back(cfg1);
+  configurations.push_back(cfg2);
+  NetworkConfig::RemoveDuplicates(&configurations);
+  EXPECT_EQ(1, configurations.size());
+  configurations.clear();
+
+  // Remove redundant direct connection configurations.
+  Config direct_config;
+  configurations.push_back(direct_config);
+  configurations.push_back(direct_config);
+  NetworkConfig::RemoveDuplicates(&configurations);
+  EXPECT_EQ(1, configurations.size());
+  configurations.clear();
+
+  // Remove redundant WPAD configurations.
+  Config wpad_config;
+  wpad_config.auto_detect = true;
+  configurations.push_back(wpad_config);
+  configurations.push_back(wpad_config);
+  NetworkConfig::RemoveDuplicates(&configurations);
+  EXPECT_EQ(1, configurations.size());
+  configurations.clear();
+
+  // Remove redundant WPAD with auto config url configurations.
+  Config wpad_url_config;
+  wpad_url_config.auto_detect = true;
+  wpad_url_config.auto_config_url = _T("http://www.google.com/wpad.dat");
+  configurations.push_back(wpad_url_config);
+  configurations.push_back(wpad_url_config);
+  NetworkConfig::RemoveDuplicates(&configurations);
+  EXPECT_EQ(1, configurations.size());
+  configurations.clear();
+
+  // Remove redundant named proxy configurations.
+  Config named_proxy_config;
+  named_proxy_config.proxy = _T("www1.google.com:3128");
+  configurations.push_back(named_proxy_config);
+  configurations.push_back(named_proxy_config);
+  NetworkConfig::RemoveDuplicates(&configurations);
+  EXPECT_EQ(1, configurations.size());
+  configurations.clear();
+
+  // Does not remove distinct configurations.
+  Config named_proxy_config_alt;
+  named_proxy_config_alt.proxy = _T("www2.google.com:3128");
+  configurations.push_back(named_proxy_config);
+  configurations.push_back(named_proxy_config_alt);
+  configurations.push_back(direct_config);
+  configurations.push_back(wpad_config);
+  configurations.push_back(wpad_url_config);
+  NetworkConfig::RemoveDuplicates(&configurations);
+  EXPECT_EQ(5, configurations.size());
+}
+
+TEST_F(NetworkConfigTest, ParseNetConfig) {
+  Config config = NetworkConfig::ParseNetConfig(_T(""));
+  EXPECT_EQ(false, config.auto_detect);
+  EXPECT_EQ(true,  config.auto_config_url.IsEmpty());
+  EXPECT_EQ(true,  config.proxy.IsEmpty());
+
+  config = NetworkConfig::ParseNetConfig(_T("wpad=false"));
+  EXPECT_EQ(false, config.auto_detect);
+  EXPECT_EQ(true,  config.auto_config_url.IsEmpty());
+  EXPECT_EQ(true,  config.proxy.IsEmpty());
+
+  config = NetworkConfig::ParseNetConfig(_T("wpad=true"));
+  EXPECT_EQ(true,  config.auto_detect);
+  EXPECT_EQ(true,  config.auto_config_url.IsEmpty());
+  EXPECT_EQ(true,  config.proxy.IsEmpty());
+
+  config = NetworkConfig::ParseNetConfig(_T("script=foo;proxy=bar"));
+  EXPECT_EQ(false, config.auto_detect);
+  EXPECT_STREQ(_T("foo"), config.auto_config_url);
+  EXPECT_EQ(_T("bar"), config.proxy);
+
+  config = NetworkConfig::ParseNetConfig(_T("proxy=foobar"));
+  EXPECT_EQ(false, config.auto_detect);
+  EXPECT_EQ(true, config.auto_config_url.IsEmpty());
+  EXPECT_EQ(_T("foobar"), config.proxy);
+}
+
+TEST_F(NetworkConfigTest, ConfigurationOverride) {
+  NetworkConfig& network_config = NetworkConfig::Instance();
+
+  Config actual, expected;
+  expected.auto_detect = true;
+  network_config.SetConfigurationOverride(&expected);
+  EXPECT_HRESULT_SUCCEEDED(network_config.GetConfigurationOverride(&actual));
+  EXPECT_EQ(expected.auto_detect, actual.auto_detect);
+
+  network_config.SetConfigurationOverride(NULL);
+  EXPECT_EQ(E_FAIL, network_config.GetConfigurationOverride(&actual));
+}
+
+}  // namespace omaha
+
diff --git a/net/network_request.cc b/net/network_request.cc
index cf21ae9..b3283fe 100644
--- a/net/network_request.cc
+++ b/net/network_request.cc
@@ -1,122 +1,122 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/net/network_request.h"

-#include "omaha/net/network_request_impl.h"

-

-namespace omaha {

-

-NetworkRequest::NetworkRequest(const NetworkConfig::Session& network_session) {

-  impl_.reset(new detail::NetworkRequestImpl(network_session));

-}

-

-NetworkRequest::~NetworkRequest() {

-}

-

-HRESULT NetworkRequest::Close() {

-  return impl_->Close();

-}

-

-void NetworkRequest::AddHttpRequest(HttpRequestInterface* http_request) {

-  return impl_->AddHttpRequest(http_request);

-}

-

-HRESULT NetworkRequest::Post(const CString& url,

-                             const void* buffer,

-                             size_t length,

-                             std::vector<uint8>* response) {

-  return impl_->Post(url, buffer, length, response);

-}

-

-HRESULT NetworkRequest::Get(const CString& url, std::vector<uint8>* response) {

-  return impl_->Get(url, response);

-}

-

-HRESULT NetworkRequest::DownloadFile(const CString& url,

-                                     const CString& filename) {

-  return impl_->DownloadFile(url, filename);

-}

-

-HRESULT NetworkRequest::Pause() {

-  return impl_->Pause();

-}

-

-HRESULT NetworkRequest::Cancel() {

-  return impl_->Cancel();

-}

-

-void NetworkRequest::AddHeader(const TCHAR* name, const TCHAR* value) {

-  return impl_->AddHeader(name, value);

-}

-

-int NetworkRequest::http_status_code() const {

-  return impl_->http_status_code();

-}

-

-void NetworkRequest::set_num_retries(int num_retries) {

-  return impl_->set_num_retries(num_retries);

-}

-

-void NetworkRequest::set_time_between_retries(int time_between_retries_ms) {

-  return impl_->set_time_between_retries(time_between_retries_ms);

-}

-

-void NetworkRequest::set_callback(NetworkRequestCallback* callback) {

-  return impl_->set_callback(callback);

-}

-

-CString NetworkRequest::response_headers() const {

-  return impl_->response_headers();

-}

-

-CString NetworkRequest::trace() const {

-  return impl_->trace();

-}

-

-HRESULT NetworkRequest::QueryHeadersString(uint32 info_level,

-                                           const TCHAR* name,

-                                           CString* value) {

-  return impl_->QueryHeadersString(info_level, name, value);

-}

-

-void NetworkRequest::set_low_priority(bool low_priority) {

-  return impl_->set_low_priority(low_priority);

-}

-

-void NetworkRequest::set_network_configuration(

-    const Config* network_configuration) {

-  return impl_->set_network_configuration(network_configuration);

-}

-

-HRESULT PostRequest(NetworkRequest* network_request,

-                    bool fallback_to_https,

-                    const CString& url,

-                    const CString& request_string,

-                    CString* response) {

-  return detail::PostRequest(network_request,

-                             fallback_to_https,

-                             url,

-                             request_string,

-                             response);

-}

-

-HRESULT GetRequest(NetworkRequest* network_request,

-                   const CString& url,

-                   CString* response) {

-  return detail::GetRequest(network_request, url, response);

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/net/network_request.h"
+#include "omaha/net/network_request_impl.h"
+
+namespace omaha {
+
+NetworkRequest::NetworkRequest(const NetworkConfig::Session& network_session) {
+  impl_.reset(new detail::NetworkRequestImpl(network_session));
+}
+
+NetworkRequest::~NetworkRequest() {
+}
+
+HRESULT NetworkRequest::Close() {
+  return impl_->Close();
+}
+
+void NetworkRequest::AddHttpRequest(HttpRequestInterface* http_request) {
+  return impl_->AddHttpRequest(http_request);
+}
+
+HRESULT NetworkRequest::Post(const CString& url,
+                             const void* buffer,
+                             size_t length,
+                             std::vector<uint8>* response) {
+  return impl_->Post(url, buffer, length, response);
+}
+
+HRESULT NetworkRequest::Get(const CString& url, std::vector<uint8>* response) {
+  return impl_->Get(url, response);
+}
+
+HRESULT NetworkRequest::DownloadFile(const CString& url,
+                                     const CString& filename) {
+  return impl_->DownloadFile(url, filename);
+}
+
+HRESULT NetworkRequest::Pause() {
+  return impl_->Pause();
+}
+
+HRESULT NetworkRequest::Cancel() {
+  return impl_->Cancel();
+}
+
+void NetworkRequest::AddHeader(const TCHAR* name, const TCHAR* value) {
+  return impl_->AddHeader(name, value);
+}
+
+int NetworkRequest::http_status_code() const {
+  return impl_->http_status_code();
+}
+
+void NetworkRequest::set_num_retries(int num_retries) {
+  return impl_->set_num_retries(num_retries);
+}
+
+void NetworkRequest::set_time_between_retries(int time_between_retries_ms) {
+  return impl_->set_time_between_retries(time_between_retries_ms);
+}
+
+void NetworkRequest::set_callback(NetworkRequestCallback* callback) {
+  return impl_->set_callback(callback);
+}
+
+CString NetworkRequest::response_headers() const {
+  return impl_->response_headers();
+}
+
+CString NetworkRequest::trace() const {
+  return impl_->trace();
+}
+
+HRESULT NetworkRequest::QueryHeadersString(uint32 info_level,
+                                           const TCHAR* name,
+                                           CString* value) {
+  return impl_->QueryHeadersString(info_level, name, value);
+}
+
+void NetworkRequest::set_low_priority(bool low_priority) {
+  return impl_->set_low_priority(low_priority);
+}
+
+void NetworkRequest::set_network_configuration(
+    const Config* network_configuration) {
+  return impl_->set_network_configuration(network_configuration);
+}
+
+HRESULT PostRequest(NetworkRequest* network_request,
+                    bool fallback_to_https,
+                    const CString& url,
+                    const CString& request_string,
+                    CString* response) {
+  return detail::PostRequest(network_request,
+                             fallback_to_https,
+                             url,
+                             request_string,
+                             response);
+}
+
+HRESULT GetRequest(NetworkRequest* network_request,
+                   const CString& url,
+                   CString* response) {
+  return detail::GetRequest(network_request, url, response);
+}
+
+}  // namespace omaha
+
diff --git a/net/network_request.h b/net/network_request.h
index fbd24a0..c424e9c 100644
--- a/net/network_request.h
+++ b/net/network_request.h
@@ -1,192 +1,192 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// TODO(omaha): implement a way to get the last network error.

-//

-// TODO(omaha): might have to do some working regarding the cookie handling.

-// WinHttp keeps a per session cookie cache. We are currently tearing down

-// the session after each request, so cookies are lost. Normally we don't

-// need cookies at Omaha except for CUP.

-

-#ifndef OMAHA_NET_NETWORK_REQUEST_H__

-#define OMAHA_NET_NETWORK_REQUEST_H__

-

-#include <windows.h>

-#include <winhttp.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/string.h"

-#include "omaha/net/network_config.h"

-

-namespace omaha {

-

-namespace detail {

-

-class NetworkRequestImpl;

-

-}   // namespace detail

-

-class NetworkRequestCallback {

- public:

-  virtual ~NetworkRequestCallback() {}

-

-  // Indicates the progress of the NetworkRequest.

-  //

-  // bytes - Current number of bytes transferred, relative to the expected

-  //         maximum indicated by the bytes_total.

-  // bytes_max - The expected number of total bytes to transfer This is usually

-  //             the content length value or 0 if the content length is not

-  //             available.

-  // status - WinHttp status codes regarding the progress of the request.

-  // status_text - Additional information, when available.

-  virtual void OnProgress(int bytes, int bytes_total,

-                          int status, const TCHAR* status_text) = 0;

-};

-

-class  HttpRequestInterface;

-

-// NetworkRequest is the main interface to the net module. The semantics of

-// the interface is defined as transferring bytes from a url, with an optional

-// request body, to a destination specified as a memory buffer or a file.

-// NetworkRequest encapsulates the retry logic for a request, the fall back to

-// different network configurations, and ultimately the fallback to different

-// network mechanisms. The calls are blocking calls. One instance of the class

-// is responsible for one request only.

-// The client of NetworkRequest is responsible for configuring the network

-// fallbacks. This gives the caller a lot of flexibility over the fallbacks but

-// it requires more work to properly set the fallback chain.

-class NetworkRequest {

- public:

-  explicit NetworkRequest(const NetworkConfig::Session& network_session);

-  ~NetworkRequest();

-

-  // Cancels the request. Cancel can be called from a different thread.

-  // Calling Cancel makes the control return to the caller of Post or Get

-  // methods. The object can't be reused once it is canceled.

-  HRESULT Cancel();

-

-  // Closes the request and releases the request resources, such as handles or

-  // interface pointers. Unlike Cancel, the request object can be reused

-  // after closing.

-  HRESULT Close();

-

-  // Adds an instance of HttpRequestInterface at the end of the fallback

-  // chain of http requests. This class takes ownership of the http_request

-  // object.

-  void AddHttpRequest(HttpRequestInterface* http_request);

-

-  // Post, Get, and DownloadFile return S_OK if the request completed

-  // successfully and the response is available to the caller. For errors,

-  // the status code can be checked.

-  //

-  // Posts a buffer to a url.

-  HRESULT Post(const CString& url,

-               const void* buffer,

-               size_t length,

-               std::vector<uint8>* response);

-

-  // Posts an UTF-8 string to a url.

-  HRESULT PostUtf8String(const CString& url,

-               const CStringA& request,

-               std::vector<uint8>* response) {

-    const uint8* buffer = reinterpret_cast<const uint8*>(request.GetString());

-    size_t length = request.GetLength();

-    return Post(url, buffer, length, response);

-  }

-

-  // Posts a Unicode string to a url.

-  HRESULT PostString(const CString& url,

-                     const CString& request,

-                     std::vector<uint8>* response) {

-    return PostUtf8String(url, WideToUtf8(request), response);

-  }

-

-  // Gets a url.

-  HRESULT Get(const CString& url, std::vector<uint8>* response);

-

-  // Downloads a url to a file.

-  HRESULT DownloadFile(const CString& url, const CString& filename);

-

-  // Temporarily stops the network request.

-  HRESULT Pause();

-

-  // Adds a request header. The header with the same name is only added once.

-  // The method is only good enough for what Omaha needs and it is not good

-  // for general purpose header manipulation, which is quite sophisticated.

-  void AddHeader(const TCHAR* name, const TCHAR* value);

-

-  // Queries a response header. This is the companion for the AddHeader

-  // method above.

-  HRESULT QueryHeadersString(uint32 info_level,

-                             const TCHAR* name,

-                             CString* value);

-

-  // Returns the http status code if available.

-  int http_status_code() const;

-

-  // Returns the response headers, separated by \r\n.

-  CString response_headers() const;

-

-  // Returns a trace of the request for logging purposes.

-  CString trace() const;

-

-  // Sets the number of retries for the request. The retry mechanism uses

-  // exponential backoff to decrease the rate of the retries.

-  void set_num_retries(int num_retries);

-

-  void set_time_between_retries(int time_between_retries_ms);

-

-  // Sets an external observer for the request. The ownership of the callback

-  // remains with the caller. The current implementation provides callback

-  // notification for DownloadFile only.

-  void set_callback(NetworkRequestCallback* callback);

-

-  // Sets the priority of the request. Currently, only BITS requests support

-  // prioritization of requests.

-  void set_low_priority(bool low_priority);

-

-  // Overrides detecting the network configuration and uses the configuration

-  // specified. If parameter is NULL, it defaults to detecting the configuration

-  // automatically.

-  void set_network_configuration(const Config* network_configuration);

-

- private:

-  // Uses pimpl idiom to minimize dependencies on implementation details.

-  scoped_ptr<detail::NetworkRequestImpl> impl_;

-  DISALLOW_EVIL_CONSTRUCTORS(NetworkRequest);

-};

-

-

-// Posts a request, falling back from http to https if the http request failed.

-// Returns S_OK if the request is successfully sent. Returns the error

-// corresponding to the http request in case of errors.

-HRESULT PostRequest(NetworkRequest* network_request,

-                    bool fallback_to_https,

-                    const CString& url,

-                    const CString& request_string,

-                    CString* response);

-

-// Gets a request.

-HRESULT GetRequest(NetworkRequest* network_request,

-                   const CString& url,

-                   CString* response);

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_NETWORK_REQUEST_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// TODO(omaha): implement a way to get the last network error.
+//
+// TODO(omaha): might have to do some working regarding the cookie handling.
+// WinHttp keeps a per session cookie cache. We are currently tearing down
+// the session after each request, so cookies are lost. Normally we don't
+// need cookies at Omaha except for CUP.
+
+#ifndef OMAHA_NET_NETWORK_REQUEST_H__
+#define OMAHA_NET_NETWORK_REQUEST_H__
+
+#include <windows.h>
+#include <winhttp.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/string.h"
+#include "omaha/net/network_config.h"
+
+namespace omaha {
+
+namespace detail {
+
+class NetworkRequestImpl;
+
+}   // namespace detail
+
+class NetworkRequestCallback {
+ public:
+  virtual ~NetworkRequestCallback() {}
+
+  // Indicates the progress of the NetworkRequest.
+  //
+  // bytes - Current number of bytes transferred, relative to the expected
+  //         maximum indicated by the bytes_total.
+  // bytes_max - The expected number of total bytes to transfer This is usually
+  //             the content length value or 0 if the content length is not
+  //             available.
+  // status - WinHttp status codes regarding the progress of the request.
+  // status_text - Additional information, when available.
+  virtual void OnProgress(int bytes, int bytes_total,
+                          int status, const TCHAR* status_text) = 0;
+};
+
+class  HttpRequestInterface;
+
+// NetworkRequest is the main interface to the net module. The semantics of
+// the interface is defined as transferring bytes from a url, with an optional
+// request body, to a destination specified as a memory buffer or a file.
+// NetworkRequest encapsulates the retry logic for a request, the fall back to
+// different network configurations, and ultimately the fallback to different
+// network mechanisms. The calls are blocking calls. One instance of the class
+// is responsible for one request only.
+// The client of NetworkRequest is responsible for configuring the network
+// fallbacks. This gives the caller a lot of flexibility over the fallbacks but
+// it requires more work to properly set the fallback chain.
+class NetworkRequest {
+ public:
+  explicit NetworkRequest(const NetworkConfig::Session& network_session);
+  ~NetworkRequest();
+
+  // Cancels the request. Cancel can be called from a different thread.
+  // Calling Cancel makes the control return to the caller of Post or Get
+  // methods. The object can't be reused once it is canceled.
+  HRESULT Cancel();
+
+  // Closes the request and releases the request resources, such as handles or
+  // interface pointers. Unlike Cancel, the request object can be reused
+  // after closing.
+  HRESULT Close();
+
+  // Adds an instance of HttpRequestInterface at the end of the fallback
+  // chain of http requests. This class takes ownership of the http_request
+  // object.
+  void AddHttpRequest(HttpRequestInterface* http_request);
+
+  // Post, Get, and DownloadFile return S_OK if the request completed
+  // successfully and the response is available to the caller. For errors,
+  // the status code can be checked.
+  //
+  // Posts a buffer to a url.
+  HRESULT Post(const CString& url,
+               const void* buffer,
+               size_t length,
+               std::vector<uint8>* response);
+
+  // Posts an UTF-8 string to a url.
+  HRESULT PostUtf8String(const CString& url,
+               const CStringA& request,
+               std::vector<uint8>* response) {
+    const uint8* buffer = reinterpret_cast<const uint8*>(request.GetString());
+    size_t length = request.GetLength();
+    return Post(url, buffer, length, response);
+  }
+
+  // Posts a Unicode string to a url.
+  HRESULT PostString(const CString& url,
+                     const CString& request,
+                     std::vector<uint8>* response) {
+    return PostUtf8String(url, WideToUtf8(request), response);
+  }
+
+  // Gets a url.
+  HRESULT Get(const CString& url, std::vector<uint8>* response);
+
+  // Downloads a url to a file.
+  HRESULT DownloadFile(const CString& url, const CString& filename);
+
+  // Temporarily stops the network request.
+  HRESULT Pause();
+
+  // Adds a request header. The header with the same name is only added once.
+  // The method is only good enough for what Omaha needs and it is not good
+  // for general purpose header manipulation, which is quite sophisticated.
+  void AddHeader(const TCHAR* name, const TCHAR* value);
+
+  // Queries a response header. This is the companion for the AddHeader
+  // method above.
+  HRESULT QueryHeadersString(uint32 info_level,
+                             const TCHAR* name,
+                             CString* value);
+
+  // Returns the http status code if available.
+  int http_status_code() const;
+
+  // Returns the response headers, separated by \r\n.
+  CString response_headers() const;
+
+  // Returns a trace of the request for logging purposes.
+  CString trace() const;
+
+  // Sets the number of retries for the request. The retry mechanism uses
+  // exponential backoff to decrease the rate of the retries.
+  void set_num_retries(int num_retries);
+
+  void set_time_between_retries(int time_between_retries_ms);
+
+  // Sets an external observer for the request. The ownership of the callback
+  // remains with the caller. The current implementation provides callback
+  // notification for DownloadFile only.
+  void set_callback(NetworkRequestCallback* callback);
+
+  // Sets the priority of the request. Currently, only BITS requests support
+  // prioritization of requests.
+  void set_low_priority(bool low_priority);
+
+  // Overrides detecting the network configuration and uses the configuration
+  // specified. If parameter is NULL, it defaults to detecting the configuration
+  // automatically.
+  void set_network_configuration(const Config* network_configuration);
+
+ private:
+  // Uses pimpl idiom to minimize dependencies on implementation details.
+  scoped_ptr<detail::NetworkRequestImpl> impl_;
+  DISALLOW_EVIL_CONSTRUCTORS(NetworkRequest);
+};
+
+
+// Posts a request, falling back from http to https if the http request failed.
+// Returns S_OK if the request is successfully sent. Returns the error
+// corresponding to the http request in case of errors.
+HRESULT PostRequest(NetworkRequest* network_request,
+                    bool fallback_to_https,
+                    const CString& url,
+                    const CString& request_string,
+                    CString* response);
+
+// Gets a request.
+HRESULT GetRequest(NetworkRequest* network_request,
+                   const CString& url,
+                   CString* response);
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_NETWORK_REQUEST_H__
+
diff --git a/net/network_request_impl.cc b/net/network_request_impl.cc
index 6812a35..46d6fd9 100644
--- a/net/network_request_impl.cc
+++ b/net/network_request_impl.cc
@@ -1,581 +1,581 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/net/network_request_impl.h"

-#include <limits.h>

-#include <atlsecurity.h>

-#include <algorithm>

-#include <cctype>

-#include <functional>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/scoped_impersonation.h"

-#include "omaha/common/string.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/net_utils.h"

-#include "omaha/net/network_config.h"

-

-namespace omaha {

-

-namespace detail {

-

-// Returns the user sid corresponding to the token. This function is only used

-// for logging purposes.

-CString GetTokenUser(HANDLE token) {

-  CAccessToken access_token;

-  access_token.Attach(token);

-  CSid sid;

-  access_token.GetUser(&sid);

-  access_token.Detach();

-  return sid.Sid();

-}

-

-// Logs bytes from the beginning of the file. Non-printable bytes are

-// replaced with '.'.

-void LogFileBytes(const CString& filename, size_t num_bytes) {

-  scoped_hfile file(::CreateFile(filename,

-                                 GENERIC_READ,

-                                 FILE_SHARE_READ,

-                                 NULL,

-                                 OPEN_EXISTING,

-                                 FILE_ATTRIBUTE_NORMAL,

-                                 NULL));

-  std::vector<char> bytes(num_bytes);

-  DWORD bytes_read(0);

-  if (file) {

-    ::ReadFile(get(file), &bytes.front(), bytes.size(), &bytes_read, NULL);

-  }

-  bytes.resize(bytes_read);

-  replace_if(bytes.begin(), bytes.end(), std::not1(std::ptr_fun(isprint)), '.');

-  bytes.push_back('\0');

-  NET_LOG(L3, (_T("[file bytes: %hs]"), &bytes.front()));

-}

-

-NetworkRequestImpl::NetworkRequestImpl(

-    const NetworkConfig::Session& network_session)

-      : cur_http_request_(NULL),

-        cur_network_config_(NULL),

-        last_network_error_(S_OK),

-        http_status_code_(0),

-        num_retries_(0),

-        low_priority_(false),

-        time_between_retries_ms_(kDefaultTimeBetweenRetriesMs),

-        callback_(NULL),

-        request_buffer_(NULL),

-        request_buffer_length_(0),

-        response_(NULL),

-        network_session_(network_session),

-        is_canceled_(false) {

-  // NetworkConfig::Initialize must be called before using NetworkRequest.

-  // If Winhttp cannot be loaded, this handle will be NULL.

-  if (!network_session.session_handle) {

-    NET_LOG(LW, (_T("[NetworkRequestImpl: session_handle is NULL.]")));

-  }

-

-  // Create a manual reset event to wait on during retry periods.

-  // The event is signaled by NetworkRequestImpl::Cancel, to break out of

-  // the retry loop and return control to the caller.

-  reset(event_cancel_, ::CreateEvent(NULL, true, false, NULL));

-  ASSERT1(event_cancel_);

-}

-

-NetworkRequestImpl::~NetworkRequestImpl() {

-  for (size_t i = 0; i != http_request_chain_.size(); ++i) {

-    delete http_request_chain_[i];

-  }

-}

-

-void NetworkRequestImpl::Reset() {

-  if (response_) {

-    response_->clear();

-  }

-  response_headers_.Empty();

-  http_status_code_   = 0;

-  last_network_error_ = S_OK;

-  cur_http_request_   = NULL;

-  cur_network_config_ = NULL;

-}

-

-HRESULT NetworkRequestImpl::Close() {

-  HRESULT hr = S_OK;

-  for (size_t i = 0; i != http_request_chain_.size(); ++i) {

-    hr = http_request_chain_[i]->Close();

-  }

-  return hr;

-}

-

-HRESULT NetworkRequestImpl::Cancel() {

-  NET_LOG(L3, (_T("[NetworkRequestImpl::Cancel]")));

-  HRESULT hr = S_OK;

-  ::InterlockedExchange(&is_canceled_, true);

-  if (event_cancel_) {

-    hr = ::SetEvent(get(event_cancel_)) ? S_OK : HRESULTFromLastError();

-  }

-  for (size_t i = 0; i != http_request_chain_.size(); ++i) {

-    hr = http_request_chain_[i]->Cancel();

-  }

-  return hr;

-}

-

-void NetworkRequestImpl::AddHttpRequest(HttpRequestInterface* http_request) {

-  ASSERT1(http_request);

-  http_request_chain_.push_back(http_request);

-}

-

-HRESULT NetworkRequestImpl::Post(const CString& url,

-                                 const void* buffer,

-                                 size_t length,

-                                 std::vector<uint8>* response) {

-  ASSERT1(response);

-  url_ = url;

-  request_buffer_ = buffer;

-  request_buffer_length_ = length;

-  response_ = response;

-  return DoSendWithRetries();

-}

-

-HRESULT NetworkRequestImpl::Get(const CString& url,

-                                std::vector<uint8>* response) {

-  ASSERT1(response);

-  url_ = url;

-  request_buffer_ = NULL;

-  request_buffer_length_ = 0;

-  response_ = response;

-  return DoSendWithRetries();

-}

-

-HRESULT NetworkRequestImpl::DownloadFile(const CString& url,

-                                         const CString& filename) {

-  url_ = url;

-  filename_ = filename;

-  request_buffer_ = NULL;

-  request_buffer_length_ = 0;

-  response_ = NULL;

-  return DoSendWithRetries();

-}

-

-HRESULT NetworkRequestImpl::Pause() {

-  return E_NOTIMPL;

-}

-

-HRESULT NetworkRequestImpl::DoSendWithRetries() {

-  ASSERT1(num_retries_ >= 0);

-  ASSERT1(response_ || !filename_.IsEmpty());

-

-  // Impersonate the user if a valid impersonation token is presented.

-  // Continue unimpersonated if the impersonation fails.

-  HANDLE impersonation_token = network_session_.impersonation_token;

-  scoped_impersonation impersonate_user(impersonation_token);

-  if (impersonation_token) {

-    DWORD result = impersonate_user.result();

-    ASSERT(result == ERROR_SUCCESS, (_T("impersonation failed %d"), result));

-    NET_LOG(L3, (_T("[impersonating %s]"), GetTokenUser(impersonation_token)));

-  }

-

-  Reset();

-

-  int http_status_code(0);

-  CString response_headers;

-  std::vector<uint8> response;

-

-  trace_.AppendFormat(_T("Url=%s\r\n"), url_);

-

-  HRESULT hr = S_OK;

-  int wait_interval_ms = time_between_retries_ms_;

-  for (int i = 0; i < 1 + num_retries_; ++i) {

-    if (IsHandleSignaled(get(event_cancel_))) {

-      ASSERT1(is_canceled_);

-

-      // There is no state to be set when the request is canceled.

-      return OMAHA_NET_E_REQUEST_CANCELLED;

-    }

-

-    // Wait before retrying if there are retries to be done.

-    if (i > 0) {

-      NET_LOG(L3, (_T("[wait %d ms]"), wait_interval_ms));

-      VERIFY1(::WaitForSingleObject(get(event_cancel_),

-                                    wait_interval_ms) != WAIT_FAILED);

-

-      // Compute the next wait interval and check for multiplication overflow.

-      if (wait_interval_ms > INT_MAX / kTimeBetweenRetriesMultiplier) {

-        ASSERT1(false);

-        hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);

-        break;

-      }

-      wait_interval_ms *= kTimeBetweenRetriesMultiplier;

-    }

-

-    DetectNetworkConfiguration(&network_configurations_);

-    ASSERT1(!network_configurations_.empty());

-    OPT_LOG(L2, (_T("[detected configurations][\r\n%s]"),

-                 NetworkConfig::ToString(network_configurations_)));

-

-    hr = DoSend(&http_status_code, &response_headers, &response);

-    HttpClient::StatusCodeClass status_code_class =

-        HttpClient::GetStatusCodeClass(http_status_code);

-    if (SUCCEEDED(hr) ||

-        hr == OMAHA_NET_E_REQUEST_CANCELLED ||

-        status_code_class == HttpClient::STATUS_CODE_CLIENT_ERROR) {

-      break;

-    }

-  }

-

-  // Update the object state with the local values.

-  http_status_code_ = http_status_code;

-  response_headers_ = response_headers;

-  if (response_) {

-    response_->swap(response);

-  }

-

-  // Avoid returning generic errors from the network stack.

-  ASSERT1(hr != E_FAIL);

-  return hr;

-}

-

-HRESULT NetworkRequestImpl::DoSend(int* http_status_code,

-                                   CString* response_headers,

-                                   std::vector<uint8>* response) const {

-  ASSERT1(http_status_code);

-  ASSERT1(response_headers);

-  ASSERT1(response);

-

-  OPT_LOG(L3, (_T("[Send][url=%s][request=%s][filename=%s]"),

-          url_,

-          BufferToPrintableString(request_buffer_, request_buffer_length_),

-          filename_));

-

-  // Cache the values corresponding to the error encountered by the first

-  // configuration, which is the preferred configuration.

-  HRESULT error_hr = S_OK;

-  int     error_http_status_code = 0;

-  CString error_response_headers;

-  std::vector<uint8> error_response;

-

-  // Tries out all the available configurations until one of them succeeds.

-  // TODO(omaha): remember the last good configuration and prefer that for

-  // future requests.

-  HRESULT hr = S_OK;

-  ASSERT1(!network_configurations_.empty());

-  for (size_t i = 0; i != network_configurations_.size(); ++i) {

-    cur_network_config_ = &network_configurations_[i];

-    hr = DoSendWithConfig(http_status_code, response_headers, response);

-    if (i == 0 && FAILED(hr)) {

-      error_hr = hr;

-      error_http_status_code = *http_status_code;

-      error_response_headers = *response_headers;

-      error_response.swap(*response);

-    }

-

-    if (SUCCEEDED(hr) ||

-        hr == OMAHA_NET_E_REQUEST_CANCELLED ||

-        *http_status_code == HTTP_STATUS_NOT_FOUND) {

-      break;

-    }

-  }

-

-  // There are only three possible outcomes: success, cancel, and an error

-  // other than cancel.

-  HRESULT result = S_OK;

-  if (SUCCEEDED(hr) || hr == OMAHA_NET_E_REQUEST_CANCELLED) {

-    result = hr;

-  } else {

-    // In case of errors, log the error and the response returned by the first

-    // network configuration.

-    result = error_hr;

-    *http_status_code = error_http_status_code;

-    *response_headers = error_response_headers;

-    response->swap(error_response);

-  }

-

-  OPT_LOG(L3, (_T("[Send response received][%s][0x%08x]"),

-               VectorToPrintableString(*response)));

-

-#ifdef DEBUG

-  if (!filename_.IsEmpty()) {

-    const size_t kNumBytes = 8196;    // 8 kb.

-    LogFileBytes(filename_, kNumBytes);

-  }

-#endif

-

-  return result;

-}

-

-HRESULT NetworkRequestImpl::DoSendWithConfig(

-    int* http_status_code,

-    CString* response_headers,

-    std::vector<uint8>* response) const {

-  ASSERT1(response_headers);

-  ASSERT1(response);

-  ASSERT1(http_status_code);

-

-  HRESULT error_hr = S_OK;

-  int     error_http_status_code = 0;

-  CString error_response_headers;

-  std::vector<uint8> error_response;

-

-  ASSERT1(cur_network_config_);

-

-  CString msg;

-  msg.Format(_T("Trying config: %s"),

-             NetworkConfig::ToString(*cur_network_config_));

-  NET_LOG(L3, (_T("[msg %s]"), msg));

-  trace_.AppendFormat(_T("%s.\r\n"), msg);

-

-  HRESULT hr = S_OK;

-  ASSERT1(!http_request_chain_.empty());

-  for (size_t i = 0; i != http_request_chain_.size(); ++i) {

-    cur_http_request_ = http_request_chain_[i];

-

-    CString msg;

-    msg.Format(_T("trying %s"), cur_http_request_->ToString());

-    NET_LOG(L3, (_T("[%s]"), msg));

-    trace_.AppendFormat(_T("%s.\r\n"), msg);

-

-    hr = DoSendHttpRequest(http_status_code, response_headers, response);

-

-    msg.Format(_T("Send request returned 0x%08x. Http status code %d"),

-               hr, *http_status_code);

-    NET_LOG(L3, (_T("[%s]"), msg));

-    trace_.AppendFormat(_T("%s.\r\n"), msg);

-

-    if (i == 0 && FAILED(hr)) {

-      error_hr = hr;

-      error_http_status_code = cur_http_request_->GetHttpStatusCode();

-      error_response_headers = cur_http_request_->GetResponseHeaders();

-      cur_http_request_->GetResponse().swap(error_response);

-    }

-

-    // The chain traversal stops when the request is successful or

-    // it is canceled, or the status code is 404.

-    // In the case of 404 response, all HttpRequests are likely to return

-    // the same 404 response.

-    if (SUCCEEDED(hr) ||

-        hr == OMAHA_NET_E_REQUEST_CANCELLED ||

-        *http_status_code == HTTP_STATUS_NOT_FOUND) {

-      break;

-    }

-  }

-

-  // There are only three possible outcomes: success, cancel, and an error

-  // other than cancel.

-  HRESULT result = S_OK;

-  if (SUCCEEDED(hr) || hr == OMAHA_NET_E_REQUEST_CANCELLED) {

-    result = hr;

-  } else {

-    // In case of errors, log the error and the response returned by the first

-    // http request object.

-    result = error_hr;

-    *http_status_code = error_http_status_code;

-    *response_headers = error_response_headers;

-    response->swap(error_response);

-  }

-

-  return result;

-}

-

-HRESULT NetworkRequestImpl::DoSendHttpRequest(

-    int* http_status_code,

-    CString* response_headers,

-    std::vector<uint8>* response) const {

-  ASSERT1(response_headers);

-  ASSERT1(response);

-  ASSERT1(http_status_code);

-

-  ASSERT1(cur_http_request_);

-

-  // Set common HttpRequestInterface properties.

-  cur_http_request_->set_session_handle(network_session_.session_handle);

-  cur_http_request_->set_request_buffer(request_buffer_,

-                                        request_buffer_length_);

-  cur_http_request_->set_url(url_);

-  cur_http_request_->set_filename(filename_);

-  cur_http_request_->set_low_priority(low_priority_);

-  cur_http_request_->set_callback(callback_);

-  cur_http_request_->set_additional_headers(additional_headers_);

-  cur_http_request_->set_network_configuration(*cur_network_config_);

-

-  if (IsHandleSignaled(get(event_cancel_))) {

-    return OMAHA_NET_E_REQUEST_CANCELLED;

-  }

-

-  // The algorithm is very rough meaning it does not look at the error

-  // returned by the Send and it blindly retries the call. For some errors

-  // it may not make sense to retry at all, for example, let's say the

-  // error is ERROR_DISK_FULL.

-  NET_LOG(L3, (_T("[%s]"), url_));

-  HRESULT hr = cur_http_request_->Send();

-  NET_LOG(L3, (_T("[HttpRequestInterface::Send returned 0x%08x]"), hr));

-

-  if (hr == OMAHA_NET_E_REQUEST_CANCELLED) {

-    return hr;

-  }

-

-  *http_status_code = cur_http_request_->GetHttpStatusCode();

-  *response_headers = cur_http_request_->GetResponseHeaders();

-  cur_http_request_->GetResponse().swap(*response);

-

-  // Check if the computer is connected to the network.

-  if (FAILED(hr)) {

-    hr = IsMachineConnectedToNetwork() ? hr : GOOPDATE_E_NO_NETWORK;

-    return hr;

-  }

-

-  // Status code must be available if the http request is successful. This

-  // is the contract that http requests objects in the fallback chain must

-  // implement.

-  ASSERT1(SUCCEEDED(hr) && *http_status_code);

-  ASSERT1(HTTP_STATUS_FIRST <= *http_status_code &&

-          *http_status_code <= HTTP_STATUS_LAST);

-

-  switch (*http_status_code) {

-    case HTTP_STATUS_OK:                // 200

-    case HTTP_STATUS_NO_CONTENT:        // 204

-    case HTTP_STATUS_PARTIAL_CONTENT:   // 206

-    case HTTP_STATUS_NOT_MODIFIED:      // 304

-      hr = S_OK;

-      break;

-

-    default:

-      hr = HRESULTFromHttpStatusCode(*http_status_code);

-      break;

-  }

-  return hr;

-}

-

-void NetworkRequestImpl::AddHeader(const TCHAR* name, const TCHAR* value) {

-  ASSERT1(name && *name);

-  ASSERT1(value && *value);

-  if (_tcsicmp(additional_headers_, name) == 0) {

-    return;

-  }

-  // Documentation specifies each header must be terminated by \r\n.

-  additional_headers_.AppendFormat(_T("%s: %s\r\n"), name, value);

-}

-

-HRESULT NetworkRequestImpl::QueryHeadersString(uint32 info_level,

-                                               const TCHAR* name,

-                                               CString* value) {

-  // Name can be null when the info_level specifies the header to query.

-  ASSERT1(value);

-  if (!cur_http_request_) {

-    return E_UNEXPECTED;

-  }

-  return cur_http_request_->QueryHeadersString(info_level, name, value);

-}

-

-void NetworkRequestImpl::DetectNetworkConfiguration(

-    std::vector<Config>* network_configurations) const {

-  ASSERT1(network_configurations);

-

-  network_configurations->clear();

-

-  // Use this object's configuration override if one is set.

-  if (network_configuration_.get()) {

-    network_configurations->push_back(*network_configuration_);

-    return;

-  }

-

-  // Use the global configuration override if the network config has one.

-  NetworkConfig& network_config(NetworkConfig::Instance());

-  Config config;

-  if (SUCCEEDED(network_config.GetConfigurationOverride(&config))) {

-    network_configurations->push_back(config);

-    return;

-  }

-

-  // Detect the configurations if no configuration override is specified.

-  HRESULT hr = network_config.Detect();

-  if (SUCCEEDED(hr)) {

-    network_config.GetConfigurations().swap(*network_configurations);

-  } else {

-    NET_LOG(LW, (_T("[failed to detect net config][0x%08x]"), hr));

-  }

-

-  config = Config();

-  config.source = _T("auto");

-

-  // Always try WPAD. Might be important to try this first in the case of

-  // corporate network, where direct connection might not be available at all.

-  config.auto_detect = true;

-  network_configurations->push_back(config);

-

-  // Default to direct connection as a last resort.

-  network_configurations->push_back(config);

-

-  // Some of the configurations might occur multiple times. To avoid retrying

-  // the same configuration over, try to remove duplicates while preserving

-  // the order of existing configurations.

-  NetworkConfig::RemoveDuplicates(network_configurations);

-  ASSERT1(!network_configurations->empty());

-}

-

-HRESULT PostRequest(NetworkRequest* network_request,

-                    bool fallback_to_https,

-                    const CString& url,

-                    const CString& request_string,

-                    CString* response) {

-  ASSERT1(network_request);

-  ASSERT1(response);

-

-  const CStringA utf8_request_string(WideToUtf8(request_string));

-  std::vector<uint8> response_buffer;

-  HRESULT hr = network_request->PostUtf8String(url,

-                                               utf8_request_string,

-                                               &response_buffer);

-  bool is_canceled(hr == OMAHA_NET_E_REQUEST_CANCELLED);

-  if (FAILED(hr) && !is_canceled && fallback_to_https) {

-    // Replace http with https and resend the request.

-    if (String_StartsWith(url, kHttpProtoScheme, true)) {

-      CString https_url = url.Mid(_tcslen(kHttpProtoScheme));

-      https_url.Insert(0, kHttpsProtoScheme);

-

-      NET_LOG(L3, (_T("[network request fallback to %s]"), https_url));

-      response_buffer.clear();

-      if (SUCCEEDED(network_request->PostUtf8String(https_url,

-                                                    utf8_request_string,

-                                                    &response_buffer))) {

-        hr = S_OK;

-      }

-    }

-  }

-  if (!response_buffer.empty()) {

-    *response = Utf8BufferToWideChar(response_buffer);

-  }

-  return hr;

-}

-

-HRESULT GetRequest(NetworkRequest* network_request,

-                   const CString& url,

-                   CString* response) {

-  ASSERT1(network_request);

-  ASSERT1(response);

-

-  std::vector<uint8> response_buffer;

-  HRESULT hr = network_request->Get(url, &response_buffer);

-  if (!response_buffer.empty()) {

-    *response = Utf8BufferToWideChar(response_buffer);

-  }

-  return hr;

-}

-

-}   // namespace detail

-

-}   // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/net/network_request_impl.h"
+#include <limits.h>
+#include <atlsecurity.h>
+#include <algorithm>
+#include <cctype>
+#include <functional>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/scoped_impersonation.h"
+#include "omaha/common/string.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/net_utils.h"
+#include "omaha/net/network_config.h"
+
+namespace omaha {
+
+namespace detail {
+
+// Returns the user sid corresponding to the token. This function is only used
+// for logging purposes.
+CString GetTokenUser(HANDLE token) {
+  CAccessToken access_token;
+  access_token.Attach(token);
+  CSid sid;
+  access_token.GetUser(&sid);
+  access_token.Detach();
+  return sid.Sid();
+}
+
+// Logs bytes from the beginning of the file. Non-printable bytes are
+// replaced with '.'.
+void LogFileBytes(const CString& filename, size_t num_bytes) {
+  scoped_hfile file(::CreateFile(filename,
+                                 GENERIC_READ,
+                                 FILE_SHARE_READ,
+                                 NULL,
+                                 OPEN_EXISTING,
+                                 FILE_ATTRIBUTE_NORMAL,
+                                 NULL));
+  std::vector<char> bytes(num_bytes);
+  DWORD bytes_read(0);
+  if (file) {
+    ::ReadFile(get(file), &bytes.front(), bytes.size(), &bytes_read, NULL);
+  }
+  bytes.resize(bytes_read);
+  replace_if(bytes.begin(), bytes.end(), std::not1(std::ptr_fun(isprint)), '.');
+  bytes.push_back('\0');
+  NET_LOG(L3, (_T("[file bytes: %hs]"), &bytes.front()));
+}
+
+NetworkRequestImpl::NetworkRequestImpl(
+    const NetworkConfig::Session& network_session)
+      : cur_http_request_(NULL),
+        cur_network_config_(NULL),
+        last_network_error_(S_OK),
+        http_status_code_(0),
+        num_retries_(0),
+        low_priority_(false),
+        time_between_retries_ms_(kDefaultTimeBetweenRetriesMs),
+        callback_(NULL),
+        request_buffer_(NULL),
+        request_buffer_length_(0),
+        response_(NULL),
+        network_session_(network_session),
+        is_canceled_(false) {
+  // NetworkConfig::Initialize must be called before using NetworkRequest.
+  // If Winhttp cannot be loaded, this handle will be NULL.
+  if (!network_session.session_handle) {
+    NET_LOG(LW, (_T("[NetworkRequestImpl: session_handle is NULL.]")));
+  }
+
+  // Create a manual reset event to wait on during retry periods.
+  // The event is signaled by NetworkRequestImpl::Cancel, to break out of
+  // the retry loop and return control to the caller.
+  reset(event_cancel_, ::CreateEvent(NULL, true, false, NULL));
+  ASSERT1(event_cancel_);
+}
+
+NetworkRequestImpl::~NetworkRequestImpl() {
+  for (size_t i = 0; i != http_request_chain_.size(); ++i) {
+    delete http_request_chain_[i];
+  }
+}
+
+void NetworkRequestImpl::Reset() {
+  if (response_) {
+    response_->clear();
+  }
+  response_headers_.Empty();
+  http_status_code_   = 0;
+  last_network_error_ = S_OK;
+  cur_http_request_   = NULL;
+  cur_network_config_ = NULL;
+}
+
+HRESULT NetworkRequestImpl::Close() {
+  HRESULT hr = S_OK;
+  for (size_t i = 0; i != http_request_chain_.size(); ++i) {
+    hr = http_request_chain_[i]->Close();
+  }
+  return hr;
+}
+
+HRESULT NetworkRequestImpl::Cancel() {
+  NET_LOG(L3, (_T("[NetworkRequestImpl::Cancel]")));
+  HRESULT hr = S_OK;
+  ::InterlockedExchange(&is_canceled_, true);
+  if (event_cancel_) {
+    hr = ::SetEvent(get(event_cancel_)) ? S_OK : HRESULTFromLastError();
+  }
+  for (size_t i = 0; i != http_request_chain_.size(); ++i) {
+    hr = http_request_chain_[i]->Cancel();
+  }
+  return hr;
+}
+
+void NetworkRequestImpl::AddHttpRequest(HttpRequestInterface* http_request) {
+  ASSERT1(http_request);
+  http_request_chain_.push_back(http_request);
+}
+
+HRESULT NetworkRequestImpl::Post(const CString& url,
+                                 const void* buffer,
+                                 size_t length,
+                                 std::vector<uint8>* response) {
+  ASSERT1(response);
+  url_ = url;
+  request_buffer_ = buffer;
+  request_buffer_length_ = length;
+  response_ = response;
+  return DoSendWithRetries();
+}
+
+HRESULT NetworkRequestImpl::Get(const CString& url,
+                                std::vector<uint8>* response) {
+  ASSERT1(response);
+  url_ = url;
+  request_buffer_ = NULL;
+  request_buffer_length_ = 0;
+  response_ = response;
+  return DoSendWithRetries();
+}
+
+HRESULT NetworkRequestImpl::DownloadFile(const CString& url,
+                                         const CString& filename) {
+  url_ = url;
+  filename_ = filename;
+  request_buffer_ = NULL;
+  request_buffer_length_ = 0;
+  response_ = NULL;
+  return DoSendWithRetries();
+}
+
+HRESULT NetworkRequestImpl::Pause() {
+  return E_NOTIMPL;
+}
+
+HRESULT NetworkRequestImpl::DoSendWithRetries() {
+  ASSERT1(num_retries_ >= 0);
+  ASSERT1(response_ || !filename_.IsEmpty());
+
+  // Impersonate the user if a valid impersonation token is presented.
+  // Continue unimpersonated if the impersonation fails.
+  HANDLE impersonation_token = network_session_.impersonation_token;
+  scoped_impersonation impersonate_user(impersonation_token);
+  if (impersonation_token) {
+    DWORD result = impersonate_user.result();
+    ASSERT(result == ERROR_SUCCESS, (_T("impersonation failed %d"), result));
+    NET_LOG(L3, (_T("[impersonating %s]"), GetTokenUser(impersonation_token)));
+  }
+
+  Reset();
+
+  int http_status_code(0);
+  CString response_headers;
+  std::vector<uint8> response;
+
+  trace_.AppendFormat(_T("Url=%s\r\n"), url_);
+
+  HRESULT hr = S_OK;
+  int wait_interval_ms = time_between_retries_ms_;
+  for (int i = 0; i < 1 + num_retries_; ++i) {
+    if (IsHandleSignaled(get(event_cancel_))) {
+      ASSERT1(is_canceled_);
+
+      // There is no state to be set when the request is canceled.
+      return OMAHA_NET_E_REQUEST_CANCELLED;
+    }
+
+    // Wait before retrying if there are retries to be done.
+    if (i > 0) {
+      NET_LOG(L3, (_T("[wait %d ms]"), wait_interval_ms));
+      VERIFY1(::WaitForSingleObject(get(event_cancel_),
+                                    wait_interval_ms) != WAIT_FAILED);
+
+      // Compute the next wait interval and check for multiplication overflow.
+      if (wait_interval_ms > INT_MAX / kTimeBetweenRetriesMultiplier) {
+        ASSERT1(false);
+        hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
+        break;
+      }
+      wait_interval_ms *= kTimeBetweenRetriesMultiplier;
+    }
+
+    DetectNetworkConfiguration(&network_configurations_);
+    ASSERT1(!network_configurations_.empty());
+    OPT_LOG(L2, (_T("[detected configurations][\r\n%s]"),
+                 NetworkConfig::ToString(network_configurations_)));
+
+    hr = DoSend(&http_status_code, &response_headers, &response);
+    HttpClient::StatusCodeClass status_code_class =
+        HttpClient::GetStatusCodeClass(http_status_code);
+    if (SUCCEEDED(hr) ||
+        hr == OMAHA_NET_E_REQUEST_CANCELLED ||
+        status_code_class == HttpClient::STATUS_CODE_CLIENT_ERROR) {
+      break;
+    }
+  }
+
+  // Update the object state with the local values.
+  http_status_code_ = http_status_code;
+  response_headers_ = response_headers;
+  if (response_) {
+    response_->swap(response);
+  }
+
+  // Avoid returning generic errors from the network stack.
+  ASSERT1(hr != E_FAIL);
+  return hr;
+}
+
+HRESULT NetworkRequestImpl::DoSend(int* http_status_code,
+                                   CString* response_headers,
+                                   std::vector<uint8>* response) const {
+  ASSERT1(http_status_code);
+  ASSERT1(response_headers);
+  ASSERT1(response);
+
+  OPT_LOG(L3, (_T("[Send][url=%s][request=%s][filename=%s]"),
+          url_,
+          BufferToPrintableString(request_buffer_, request_buffer_length_),
+          filename_));
+
+  // Cache the values corresponding to the error encountered by the first
+  // configuration, which is the preferred configuration.
+  HRESULT error_hr = S_OK;
+  int     error_http_status_code = 0;
+  CString error_response_headers;
+  std::vector<uint8> error_response;
+
+  // Tries out all the available configurations until one of them succeeds.
+  // TODO(omaha): remember the last good configuration and prefer that for
+  // future requests.
+  HRESULT hr = S_OK;
+  ASSERT1(!network_configurations_.empty());
+  for (size_t i = 0; i != network_configurations_.size(); ++i) {
+    cur_network_config_ = &network_configurations_[i];
+    hr = DoSendWithConfig(http_status_code, response_headers, response);
+    if (i == 0 && FAILED(hr)) {
+      error_hr = hr;
+      error_http_status_code = *http_status_code;
+      error_response_headers = *response_headers;
+      error_response.swap(*response);
+    }
+
+    if (SUCCEEDED(hr) ||
+        hr == OMAHA_NET_E_REQUEST_CANCELLED ||
+        *http_status_code == HTTP_STATUS_NOT_FOUND) {
+      break;
+    }
+  }
+
+  // There are only three possible outcomes: success, cancel, and an error
+  // other than cancel.
+  HRESULT result = S_OK;
+  if (SUCCEEDED(hr) || hr == OMAHA_NET_E_REQUEST_CANCELLED) {
+    result = hr;
+  } else {
+    // In case of errors, log the error and the response returned by the first
+    // network configuration.
+    result = error_hr;
+    *http_status_code = error_http_status_code;
+    *response_headers = error_response_headers;
+    response->swap(error_response);
+  }
+
+  OPT_LOG(L3, (_T("[Send response received][%s][0x%08x]"),
+               VectorToPrintableString(*response)));
+
+#ifdef DEBUG
+  if (!filename_.IsEmpty()) {
+    const size_t kNumBytes = 8196;    // 8 kb.
+    LogFileBytes(filename_, kNumBytes);
+  }
+#endif
+
+  return result;
+}
+
+HRESULT NetworkRequestImpl::DoSendWithConfig(
+    int* http_status_code,
+    CString* response_headers,
+    std::vector<uint8>* response) const {
+  ASSERT1(response_headers);
+  ASSERT1(response);
+  ASSERT1(http_status_code);
+
+  HRESULT error_hr = S_OK;
+  int     error_http_status_code = 0;
+  CString error_response_headers;
+  std::vector<uint8> error_response;
+
+  ASSERT1(cur_network_config_);
+
+  CString msg;
+  msg.Format(_T("Trying config: %s"),
+             NetworkConfig::ToString(*cur_network_config_));
+  NET_LOG(L3, (_T("[msg %s]"), msg));
+  trace_.AppendFormat(_T("%s.\r\n"), msg);
+
+  HRESULT hr = S_OK;
+  ASSERT1(!http_request_chain_.empty());
+  for (size_t i = 0; i != http_request_chain_.size(); ++i) {
+    cur_http_request_ = http_request_chain_[i];
+
+    CString msg;
+    msg.Format(_T("trying %s"), cur_http_request_->ToString());
+    NET_LOG(L3, (_T("[%s]"), msg));
+    trace_.AppendFormat(_T("%s.\r\n"), msg);
+
+    hr = DoSendHttpRequest(http_status_code, response_headers, response);
+
+    msg.Format(_T("Send request returned 0x%08x. Http status code %d"),
+               hr, *http_status_code);
+    NET_LOG(L3, (_T("[%s]"), msg));
+    trace_.AppendFormat(_T("%s.\r\n"), msg);
+
+    if (i == 0 && FAILED(hr)) {
+      error_hr = hr;
+      error_http_status_code = cur_http_request_->GetHttpStatusCode();
+      error_response_headers = cur_http_request_->GetResponseHeaders();
+      cur_http_request_->GetResponse().swap(error_response);
+    }
+
+    // The chain traversal stops when the request is successful or
+    // it is canceled, or the status code is 404.
+    // In the case of 404 response, all HttpRequests are likely to return
+    // the same 404 response.
+    if (SUCCEEDED(hr) ||
+        hr == OMAHA_NET_E_REQUEST_CANCELLED ||
+        *http_status_code == HTTP_STATUS_NOT_FOUND) {
+      break;
+    }
+  }
+
+  // There are only three possible outcomes: success, cancel, and an error
+  // other than cancel.
+  HRESULT result = S_OK;
+  if (SUCCEEDED(hr) || hr == OMAHA_NET_E_REQUEST_CANCELLED) {
+    result = hr;
+  } else {
+    // In case of errors, log the error and the response returned by the first
+    // http request object.
+    result = error_hr;
+    *http_status_code = error_http_status_code;
+    *response_headers = error_response_headers;
+    response->swap(error_response);
+  }
+
+  return result;
+}
+
+HRESULT NetworkRequestImpl::DoSendHttpRequest(
+    int* http_status_code,
+    CString* response_headers,
+    std::vector<uint8>* response) const {
+  ASSERT1(response_headers);
+  ASSERT1(response);
+  ASSERT1(http_status_code);
+
+  ASSERT1(cur_http_request_);
+
+  // Set common HttpRequestInterface properties.
+  cur_http_request_->set_session_handle(network_session_.session_handle);
+  cur_http_request_->set_request_buffer(request_buffer_,
+                                        request_buffer_length_);
+  cur_http_request_->set_url(url_);
+  cur_http_request_->set_filename(filename_);
+  cur_http_request_->set_low_priority(low_priority_);
+  cur_http_request_->set_callback(callback_);
+  cur_http_request_->set_additional_headers(additional_headers_);
+  cur_http_request_->set_network_configuration(*cur_network_config_);
+
+  if (IsHandleSignaled(get(event_cancel_))) {
+    return OMAHA_NET_E_REQUEST_CANCELLED;
+  }
+
+  // The algorithm is very rough meaning it does not look at the error
+  // returned by the Send and it blindly retries the call. For some errors
+  // it may not make sense to retry at all, for example, let's say the
+  // error is ERROR_DISK_FULL.
+  NET_LOG(L3, (_T("[%s]"), url_));
+  HRESULT hr = cur_http_request_->Send();
+  NET_LOG(L3, (_T("[HttpRequestInterface::Send returned 0x%08x]"), hr));
+
+  if (hr == OMAHA_NET_E_REQUEST_CANCELLED) {
+    return hr;
+  }
+
+  *http_status_code = cur_http_request_->GetHttpStatusCode();
+  *response_headers = cur_http_request_->GetResponseHeaders();
+  cur_http_request_->GetResponse().swap(*response);
+
+  // Check if the computer is connected to the network.
+  if (FAILED(hr)) {
+    hr = IsMachineConnectedToNetwork() ? hr : GOOPDATE_E_NO_NETWORK;
+    return hr;
+  }
+
+  // Status code must be available if the http request is successful. This
+  // is the contract that http requests objects in the fallback chain must
+  // implement.
+  ASSERT1(SUCCEEDED(hr) && *http_status_code);
+  ASSERT1(HTTP_STATUS_FIRST <= *http_status_code &&
+          *http_status_code <= HTTP_STATUS_LAST);
+
+  switch (*http_status_code) {
+    case HTTP_STATUS_OK:                // 200
+    case HTTP_STATUS_NO_CONTENT:        // 204
+    case HTTP_STATUS_PARTIAL_CONTENT:   // 206
+    case HTTP_STATUS_NOT_MODIFIED:      // 304
+      hr = S_OK;
+      break;
+
+    default:
+      hr = HRESULTFromHttpStatusCode(*http_status_code);
+      break;
+  }
+  return hr;
+}
+
+void NetworkRequestImpl::AddHeader(const TCHAR* name, const TCHAR* value) {
+  ASSERT1(name && *name);
+  ASSERT1(value && *value);
+  if (_tcsicmp(additional_headers_, name) == 0) {
+    return;
+  }
+  // Documentation specifies each header must be terminated by \r\n.
+  additional_headers_.AppendFormat(_T("%s: %s\r\n"), name, value);
+}
+
+HRESULT NetworkRequestImpl::QueryHeadersString(uint32 info_level,
+                                               const TCHAR* name,
+                                               CString* value) {
+  // Name can be null when the info_level specifies the header to query.
+  ASSERT1(value);
+  if (!cur_http_request_) {
+    return E_UNEXPECTED;
+  }
+  return cur_http_request_->QueryHeadersString(info_level, name, value);
+}
+
+void NetworkRequestImpl::DetectNetworkConfiguration(
+    std::vector<Config>* network_configurations) const {
+  ASSERT1(network_configurations);
+
+  network_configurations->clear();
+
+  // Use this object's configuration override if one is set.
+  if (network_configuration_.get()) {
+    network_configurations->push_back(*network_configuration_);
+    return;
+  }
+
+  // Use the global configuration override if the network config has one.
+  NetworkConfig& network_config(NetworkConfig::Instance());
+  Config config;
+  if (SUCCEEDED(network_config.GetConfigurationOverride(&config))) {
+    network_configurations->push_back(config);
+    return;
+  }
+
+  // Detect the configurations if no configuration override is specified.
+  HRESULT hr = network_config.Detect();
+  if (SUCCEEDED(hr)) {
+    network_config.GetConfigurations().swap(*network_configurations);
+  } else {
+    NET_LOG(LW, (_T("[failed to detect net config][0x%08x]"), hr));
+  }
+
+  config = Config();
+  config.source = _T("auto");
+
+  // Always try WPAD. Might be important to try this first in the case of
+  // corporate network, where direct connection might not be available at all.
+  config.auto_detect = true;
+  network_configurations->push_back(config);
+
+  // Default to direct connection as a last resort.
+  network_configurations->push_back(config);
+
+  // Some of the configurations might occur multiple times. To avoid retrying
+  // the same configuration over, try to remove duplicates while preserving
+  // the order of existing configurations.
+  NetworkConfig::RemoveDuplicates(network_configurations);
+  ASSERT1(!network_configurations->empty());
+}
+
+HRESULT PostRequest(NetworkRequest* network_request,
+                    bool fallback_to_https,
+                    const CString& url,
+                    const CString& request_string,
+                    CString* response) {
+  ASSERT1(network_request);
+  ASSERT1(response);
+
+  const CStringA utf8_request_string(WideToUtf8(request_string));
+  std::vector<uint8> response_buffer;
+  HRESULT hr = network_request->PostUtf8String(url,
+                                               utf8_request_string,
+                                               &response_buffer);
+  bool is_canceled(hr == OMAHA_NET_E_REQUEST_CANCELLED);
+  if (FAILED(hr) && !is_canceled && fallback_to_https) {
+    // Replace http with https and resend the request.
+    if (String_StartsWith(url, kHttpProtoScheme, true)) {
+      CString https_url = url.Mid(_tcslen(kHttpProtoScheme));
+      https_url.Insert(0, kHttpsProtoScheme);
+
+      NET_LOG(L3, (_T("[network request fallback to %s]"), https_url));
+      response_buffer.clear();
+      if (SUCCEEDED(network_request->PostUtf8String(https_url,
+                                                    utf8_request_string,
+                                                    &response_buffer))) {
+        hr = S_OK;
+      }
+    }
+  }
+  if (!response_buffer.empty()) {
+    *response = Utf8BufferToWideChar(response_buffer);
+  }
+  return hr;
+}
+
+HRESULT GetRequest(NetworkRequest* network_request,
+                   const CString& url,
+                   CString* response) {
+  ASSERT1(network_request);
+  ASSERT1(response);
+
+  std::vector<uint8> response_buffer;
+  HRESULT hr = network_request->Get(url, &response_buffer);
+  if (!response_buffer.empty()) {
+    *response = Utf8BufferToWideChar(response_buffer);
+  }
+  return hr;
+}
+
+}   // namespace detail
+
+}   // namespace omaha
+
diff --git a/net/network_request_impl.h b/net/network_request_impl.h
index 0f4d30e..a24c20e 100644
--- a/net/network_request_impl.h
+++ b/net/network_request_impl.h
@@ -1,192 +1,192 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The class structure is as following:

-//    - NetworkRequest and the underlying NetworkRequestImpl provide fault

-//      tolerant client server http transactions.

-//    - HttpRequestInterface defines an interface for different mechanisms that

-//      can move bytes between the client and the server. These mechanisms are

-//      chained up so that the control passes from one mechanism to the next

-//      until one of them is able to fulfill the request or an error is

-//      generated. Currently, SimpleRequest and BitsRequest are provided.

-//    - HttpClient is the c++ wrapper over winhttp-wininet.

-

-#ifndef OMAHA_NET_NETWORK_REQUEST_IMPL_H__

-#define OMAHA_NET_NETWORK_REQUEST_IMPL_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/http_request.h"

-

-namespace omaha {

-

-namespace detail {

-

-class NetworkRequestImpl {

- public:

-  explicit NetworkRequestImpl(const NetworkConfig::Session& network_session);

-  ~NetworkRequestImpl();

-

-  HRESULT Close();

-

-  void AddHttpRequest(HttpRequestInterface* http_request);

-

-  HRESULT Post(const CString& url,

-               const void* buffer,

-               size_t length,

-               std::vector<uint8>* response);

-  HRESULT Get(const CString& url, std::vector<uint8>* response);

-  HRESULT DownloadFile(const CString& url, const CString& filename);

-

-  HRESULT Pause();

-  HRESULT Cancel();

-

-  void AddHeader(const TCHAR* name, const TCHAR* value);

-

-  HRESULT QueryHeadersString(uint32 info_level,

-                             const TCHAR* name,

-                             CString* value);

-

-  int http_status_code() const { return http_status_code_; }

-

-  CString response_headers() const { return response_headers_; }

-

-  void set_num_retries(int num_retries) { num_retries_ = num_retries; }

-

-  void set_time_between_retries(int time_between_retries_ms) {

-    time_between_retries_ms_ = time_between_retries_ms;

-  }

-

-  void set_callback(NetworkRequestCallback* callback) {

-    callback_ = callback;

-  }

-

-  void set_low_priority(bool low_priority) { low_priority_ = low_priority; }

-

-  void set_network_configuration(const Config* network_configuration) {

-    if (network_configuration) {

-      network_configuration_.reset(new Config);

-      *network_configuration_ = *network_configuration;

-    } else {

-      network_configuration_.reset();

-    }

-  }

-

-  CString trace() const { return trace_; }

-

-  // Detects the available network configurations and returns the chain of

-  // configurations to be used.

-  void DetectNetworkConfiguration(

-      std::vector<Config>* network_configurations) const;

-

- private:

-  // Resets the state of the output data members.

-  void Reset();

-

-  // Sends the request with a retry policy. This is the only function that

-  // modifies the state of the output data members: the status code, the

-  // response headers, and the response. When errors are encountered, the

-  // output data members contain the values corresponding to first network

-  // configuration and first HttpRequest instance in the fallback chain.

-  HRESULT DoSendWithRetries();

-

-  // Sends a single request and receives the response.

-  HRESULT DoSend(int* http_status_code,

-                 CString* response_headers,

-                 std::vector<uint8>* response) const;

-

-  // Sends the request using the current configuration. The request is tried for

-  // each HttpRequestInterface in the fallback chain until one of them succeeds

-  // or the end of the chain is reached.

-  HRESULT DoSendWithConfig(int* http_status_code,

-                           CString* response_headers,

-                           std::vector<uint8>* response) const;

-

-  // Sends an http request using the current HttpRequest interface over the

-  // current network configuration.

-  HRESULT DoSendHttpRequest(int* http_status_code,

-                            CString* response_headers,

-                            std::vector<uint8>* response) const;

-

-  // Specifies the chain of HttpRequestInterface to handle the request.

-  std::vector<HttpRequestInterface*> http_request_chain_;

-

-  // Specifies the detected network configurations.

-  std::vector<Config> network_configurations_;

-

-  // Specifies the network configuration override. When set, the network

-  // configurations are not auto detected.

-  scoped_ptr<Config> network_configuration_;

-

-  // Input data members.

-  // The request and response buffers are owner by the caller.

-  CString  url_;

-  const void* request_buffer_;     // Contains the request body for POST.

-  size_t   request_buffer_length_;  // Length of the request body.

-  CString  filename_;              // Contains the response for downloads.

-  CString  additional_headers_;    // Each header is separated by \r\n.

-  int      num_retries_;

-  bool     low_priority_;

-  int time_between_retries_ms_;

-

-  // Output data members.

-  int      http_status_code_;

-  CString  response_headers_;      // Each header is separated by \r\n.

-  std::vector<uint8>* response_;   // Contains the response for Post and Get.

-  HRESULT  last_network_error_;    // TODO(omaha): not implemented.

-

-  const NetworkConfig::Session  network_session_;

-  NetworkRequestCallback*       callback_;

-

-  // The http request and the network configuration currently in use.

-  mutable HttpRequestInterface* cur_http_request_;

-  mutable const Config*         cur_network_config_;

-

-  volatile LONG is_canceled_;

-  scoped_event event_cancel_;

-

-  LLock lock_;

-

-  // Contains the trace of the request as handled by the fallback chain.

-  mutable CString trace_;

-

-  static const int kDefaultTimeBetweenRetriesMs   = 5000;     // 5 seconds.

-  static const int kTimeBetweenRetriesMultiplier  = 2;

-

-  DISALLOW_EVIL_CONSTRUCTORS(NetworkRequestImpl);

-};

-

-HRESULT PostRequest(NetworkRequest* network_request,

-                    bool fallback_to_https,

-                    const CString& url,

-                    const CString& request_string,

-                    CString* response);

-

-HRESULT GetRequest(NetworkRequest* network_request,

-                   const CString& url,

-                   CString* response);

-

-}   // namespace detail

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_NETWORK_REQUEST_IMPL_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The class structure is as following:
+//    - NetworkRequest and the underlying NetworkRequestImpl provide fault
+//      tolerant client server http transactions.
+//    - HttpRequestInterface defines an interface for different mechanisms that
+//      can move bytes between the client and the server. These mechanisms are
+//      chained up so that the control passes from one mechanism to the next
+//      until one of them is able to fulfill the request or an error is
+//      generated. Currently, SimpleRequest and BitsRequest are provided.
+//    - HttpClient is the c++ wrapper over winhttp-wininet.
+
+#ifndef OMAHA_NET_NETWORK_REQUEST_IMPL_H__
+#define OMAHA_NET_NETWORK_REQUEST_IMPL_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/http_request.h"
+
+namespace omaha {
+
+namespace detail {
+
+class NetworkRequestImpl {
+ public:
+  explicit NetworkRequestImpl(const NetworkConfig::Session& network_session);
+  ~NetworkRequestImpl();
+
+  HRESULT Close();
+
+  void AddHttpRequest(HttpRequestInterface* http_request);
+
+  HRESULT Post(const CString& url,
+               const void* buffer,
+               size_t length,
+               std::vector<uint8>* response);
+  HRESULT Get(const CString& url, std::vector<uint8>* response);
+  HRESULT DownloadFile(const CString& url, const CString& filename);
+
+  HRESULT Pause();
+  HRESULT Cancel();
+
+  void AddHeader(const TCHAR* name, const TCHAR* value);
+
+  HRESULT QueryHeadersString(uint32 info_level,
+                             const TCHAR* name,
+                             CString* value);
+
+  int http_status_code() const { return http_status_code_; }
+
+  CString response_headers() const { return response_headers_; }
+
+  void set_num_retries(int num_retries) { num_retries_ = num_retries; }
+
+  void set_time_between_retries(int time_between_retries_ms) {
+    time_between_retries_ms_ = time_between_retries_ms;
+  }
+
+  void set_callback(NetworkRequestCallback* callback) {
+    callback_ = callback;
+  }
+
+  void set_low_priority(bool low_priority) { low_priority_ = low_priority; }
+
+  void set_network_configuration(const Config* network_configuration) {
+    if (network_configuration) {
+      network_configuration_.reset(new Config);
+      *network_configuration_ = *network_configuration;
+    } else {
+      network_configuration_.reset();
+    }
+  }
+
+  CString trace() const { return trace_; }
+
+  // Detects the available network configurations and returns the chain of
+  // configurations to be used.
+  void DetectNetworkConfiguration(
+      std::vector<Config>* network_configurations) const;
+
+ private:
+  // Resets the state of the output data members.
+  void Reset();
+
+  // Sends the request with a retry policy. This is the only function that
+  // modifies the state of the output data members: the status code, the
+  // response headers, and the response. When errors are encountered, the
+  // output data members contain the values corresponding to first network
+  // configuration and first HttpRequest instance in the fallback chain.
+  HRESULT DoSendWithRetries();
+
+  // Sends a single request and receives the response.
+  HRESULT DoSend(int* http_status_code,
+                 CString* response_headers,
+                 std::vector<uint8>* response) const;
+
+  // Sends the request using the current configuration. The request is tried for
+  // each HttpRequestInterface in the fallback chain until one of them succeeds
+  // or the end of the chain is reached.
+  HRESULT DoSendWithConfig(int* http_status_code,
+                           CString* response_headers,
+                           std::vector<uint8>* response) const;
+
+  // Sends an http request using the current HttpRequest interface over the
+  // current network configuration.
+  HRESULT DoSendHttpRequest(int* http_status_code,
+                            CString* response_headers,
+                            std::vector<uint8>* response) const;
+
+  // Specifies the chain of HttpRequestInterface to handle the request.
+  std::vector<HttpRequestInterface*> http_request_chain_;
+
+  // Specifies the detected network configurations.
+  std::vector<Config> network_configurations_;
+
+  // Specifies the network configuration override. When set, the network
+  // configurations are not auto detected.
+  scoped_ptr<Config> network_configuration_;
+
+  // Input data members.
+  // The request and response buffers are owner by the caller.
+  CString  url_;
+  const void* request_buffer_;     // Contains the request body for POST.
+  size_t   request_buffer_length_;  // Length of the request body.
+  CString  filename_;              // Contains the response for downloads.
+  CString  additional_headers_;    // Each header is separated by \r\n.
+  int      num_retries_;
+  bool     low_priority_;
+  int time_between_retries_ms_;
+
+  // Output data members.
+  int      http_status_code_;
+  CString  response_headers_;      // Each header is separated by \r\n.
+  std::vector<uint8>* response_;   // Contains the response for Post and Get.
+  HRESULT  last_network_error_;    // TODO(omaha): not implemented.
+
+  const NetworkConfig::Session  network_session_;
+  NetworkRequestCallback*       callback_;
+
+  // The http request and the network configuration currently in use.
+  mutable HttpRequestInterface* cur_http_request_;
+  mutable const Config*         cur_network_config_;
+
+  volatile LONG is_canceled_;
+  scoped_event event_cancel_;
+
+  LLock lock_;
+
+  // Contains the trace of the request as handled by the fallback chain.
+  mutable CString trace_;
+
+  static const int kDefaultTimeBetweenRetriesMs   = 5000;     // 5 seconds.
+  static const int kTimeBetweenRetriesMultiplier  = 2;
+
+  DISALLOW_EVIL_CONSTRUCTORS(NetworkRequestImpl);
+};
+
+HRESULT PostRequest(NetworkRequest* network_request,
+                    bool fallback_to_https,
+                    const CString& url,
+                    const CString& request_string,
+                    CString* response);
+
+HRESULT GetRequest(NetworkRequest* network_request,
+                   const CString& url,
+                   CString* response);
+
+}   // namespace detail
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_NETWORK_REQUEST_IMPL_H__
+
diff --git a/net/network_request_unittest.cc b/net/network_request_unittest.cc
index bea7180..5090063 100644
--- a/net/network_request_unittest.cc
+++ b/net/network_request_unittest.cc
@@ -1,414 +1,414 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <winhttp.h>

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "base/basictypes.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/queue_timer.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vista_utils.h"

-#include "omaha/net/bits_request.h"

-#include "omaha/net/browser_request.h"

-#include "omaha/net/cup_request.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/simple_request.h"

-#include "omaha/net/urlmon_request.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class NetworkRequestTest

-    : public testing::Test,

-      public NetworkRequestCallback {

- protected:

-  NetworkRequestTest() {}

-

-  static void SetUpTestCase() {

-    // Initialize the detection chain: GoogleProxy, FireFox if it is the

-    // default browser, and IE.

-    NetworkConfig& network_config(NetworkConfig::Instance());

-    network_config.Clear();

-    network_config.Add(new GoogleProxyDetector(MACHINE_REG_UPDATE_DEV));

-    BrowserType browser_type(BROWSER_UNKNOWN);

-    GetDefaultBrowserType(&browser_type);

-    if (browser_type == BROWSER_FIREFOX) {

-      network_config.Add(new FirefoxProxyDetector());

-    }

-    network_config.Add(new IEProxyDetector());

-    network_config.Add(new DefaultProxyDetector);

-

-    vista::GetLoggedOnUserToken(&token_);

-  }

-

-  static void TearDownTestCase() {

-    if (token_) {

-      ::CloseHandle(token_);

-    }

-    NetworkConfig::Instance().Clear();

-  }

-

-  virtual void SetUp() {

-    const NetworkConfig::Session& session(NetworkConfig::Instance().session());

-    network_request_.reset(new NetworkRequest(session));

-  }

-

-  virtual void TearDown() {}

-

-  virtual void OnProgress(int bytes, int bytes_total, int, const TCHAR*) {

-    UNREFERENCED_PARAMETER(bytes);

-    UNREFERENCED_PARAMETER(bytes_total);

-    NET_LOG(L3, (_T("[downloading %d of %d]"), bytes, bytes_total));

-  }

-

-  static void CancelCallback(QueueTimer* queue_timer) {

-    ASSERT_TRUE(queue_timer);

-    ASSERT_TRUE(queue_timer->ctx());

-    void* ctx = queue_timer->ctx();

-    NetworkRequestTest* test = static_cast<NetworkRequestTest*>(ctx);

-

-    const TCHAR* msg = _T("CancelCallback");

-    ASSERT_HRESULT_SUCCEEDED(test->network_request_->Cancel());

-  }

-

-  // http get.

-  void HttpGetHelper() {

-    std::vector<uint8> response;

-    CString url = _T("http://www.google.com/robots.txt");

-    network_request_->set_num_retries(2);

-    EXPECT_HRESULT_SUCCEEDED(network_request_->Get(url, &response));

-    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);

-  }

-

-  // https get.

-  void HttpsGetHelper() {

-    std::vector<uint8> response;

-    CString url = _T("https://www.google.com/robots.txt");

-    network_request_->set_num_retries(2);

-    EXPECT_HRESULT_SUCCEEDED(network_request_->Get(url, &response));

-    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);

-  }

-

-  // http post.

-  void HttpPostHelper() {

-    std::vector<uint8> response;

-

-    CString url = _T("http://tools.google.com/service/update2");

-    // Post a buffer.

-    const uint8 request[] = "<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" testsource=\"dev\"/>";  // NOLINT

-    network_request_->set_num_retries(2);

-    EXPECT_HRESULT_SUCCEEDED(network_request_->Post(url,

-                                                    request,

-                                                    arraysize(request) - 1,

-                                                    &response));

-    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);

-

-    // Post an UTF8 string.

-    CStringA utf8_request(reinterpret_cast<const char*>(request));

-    EXPECT_HRESULT_SUCCEEDED(network_request_->PostUtf8String(url,

-                                                              utf8_request,

-                                                              &response));

-    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);

-

-    // Post a Unicode string.

-    CString unicode_request(reinterpret_cast<const char*>(request));

-    EXPECT_HRESULT_SUCCEEDED(network_request_->PostString(url,

-                                                          unicode_request,

-                                                          &response));

-    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);

-  }

-

-  // Download http file.

-  void DownloadHelper() {

-    CString url = _T("http://dl.google.com/update2/UpdateData.bin");

-

-    CString temp_dir = app_util::GetTempDir();

-    CString temp_file;

-    EXPECT_TRUE(::GetTempFileName(temp_dir, _T("tmp"), 0,

-                                  CStrBuf(temp_file, MAX_PATH)));

-    network_request_->set_num_retries(2);

-    network_request_->set_low_priority(true);

-    network_request_->set_callback(this);

-    EXPECT_HRESULT_SUCCEEDED(network_request_->DownloadFile(url, temp_file));

-    EXPECT_TRUE(::DeleteFile(temp_file));

-    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);

-  }

-

-  void MultipleRequestsHelper() {

-    std::vector<uint8> response;

-

-    CString url = _T("http://tools.google.com/service/update2");

-    const uint8 request[] = "<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" testsource=\"dev\"/>";  // NOLINT

-    for (size_t i = 0; i != 3; ++i) {

-      EXPECT_HRESULT_SUCCEEDED(network_request_->Post(url,

-                                                      request,

-                                                      arraysize(request) - 1,

-                                                      &response));

-      EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);

-    }

-  }

-

-  void PostRequestHelper() {

-    CString response;

-    CString url = _T("http://tools.google.com/service/update2");

-    CString request = _T("<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" testsource=\"dev\"/>");  // NOLINT

-    EXPECT_HRESULT_SUCCEEDED(PostRequest(network_request_.get(),

-                                         true,

-                                         url,

-                                         request,

-                                         &response));

-  }

-

-  void PostRequestNegativeTestHelper() {

-    CString response;

-    CString url = _T("http://no_such_host.google.com/service/update2");

-    CString request = _T("<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" testsource=\"dev\"/>");  // NOLINT

-    EXPECT_HRESULT_FAILED(PostRequest(network_request_.get(),

-                                      true,

-                                      url,

-                                      request,

-                                      &response));

-  }

-

-  void RetriesNegativeTestHelper() {

-    // Try a direct connection to a non-existent host and keep retrying until

-    // the retries are used up. Urlmon request is using IE's settings.

-    // Therefore, it is possible a proxy is used. In this case, the http

-    // response is '503 Service Unavailable'.

-    Config config;

-    network_request_->set_network_configuration(&config);

-    network_request_->set_num_retries(2);

-    network_request_->set_time_between_retries(10);   // 10 miliseconds.

-    std::vector<uint8> response;

-

-    CString url = _T("http://nohost/nofile");

-

-    // One request plus 2 retries after 10 and 20 miliseconds respectively.

-    HRESULT hr = network_request_->Get(url, &response);

-    EXPECT_TRUE(hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_NAME_NOT_RESOLVED) ||

-                hr == INET_E_RESOURCE_NOT_FOUND ||

-                hr == HRESULTFromHttpStatusCode(503));

-  }

-

-  void CancelTest_GetHelper() {

-    HANDLE timer_queue = ::CreateTimerQueue();

-    ASSERT_TRUE(timer_queue);

-    ON_SCOPE_EXIT(::DeleteTimerQueueEx, timer_queue, INVALID_HANDLE_VALUE);

-

-    QueueTimer queue_timer(timer_queue,

-                           &NetworkRequestTest::CancelCallback,

-                           this);

-    ASSERT_HRESULT_SUCCEEDED(queue_timer.Start(200, 0, WT_EXECUTEONLYONCE));

-

-    // Try a direct connection to a non-existent host and keep retrying until

-    // canceled by the timer.

-    Config config;

-    network_request_->set_network_configuration(&config);

-    network_request_->set_num_retries(10);

-    network_request_->set_time_between_retries(10);  // 10 miliseconds.

-    std::vector<uint8> response;

-

-    CString url = _T("http://nohost/nofile");

-

-    EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED,

-              network_request_->Get(url, &response));

-

-    EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED,

-              network_request_->Get(url, &response));

-  }

-

-  scoped_ptr<NetworkRequest> network_request_;

-  static HANDLE token_;

-};

-

-HANDLE NetworkRequestTest::token_ = NULL;

-

-// http get.

-TEST_F(NetworkRequestTest, HttpGet) {

-  network_request_->AddHttpRequest(new SimpleRequest);

-  network_request_->AddHttpRequest(new BrowserRequest);

-  HttpGetHelper();

-}

-

-// http get.

-TEST_F(NetworkRequestTest, HttpGetUrlmon) {

-  network_request_->AddHttpRequest(new UrlmonRequest);

-  network_request_->AddHttpRequest(new BrowserRequest);

-  HttpGetHelper();

-}

-

-// https get.

-TEST_F(NetworkRequestTest, HttpsGet) {

-  network_request_->AddHttpRequest(new SimpleRequest);

-  network_request_->AddHttpRequest(new BrowserRequest);

-  HttpsGetHelper();

-}

-

-// https get.

-TEST_F(NetworkRequestTest, HttpsGetUrlmon) {

-  network_request_->AddHttpRequest(new UrlmonRequest);

-  network_request_->AddHttpRequest(new BrowserRequest);

-  HttpsGetHelper();

-}

-

-// http post.

-TEST_F(NetworkRequestTest, HttpPost) {

-  network_request_->AddHttpRequest(new CupRequest(new SimpleRequest));

-  network_request_->AddHttpRequest(new SimpleRequest);

-  network_request_->AddHttpRequest(new CupRequest(new BrowserRequest));

-  HttpPostHelper();

-}

-

-// http post.

-TEST_F(NetworkRequestTest, HttpPostUrlmon) {

-  network_request_->AddHttpRequest(new CupRequest(new UrlmonRequest));

-  network_request_->AddHttpRequest(new UrlmonRequest);

-  network_request_->AddHttpRequest(new CupRequest(new BrowserRequest));

-  HttpPostHelper();

-}

-

-// Download http file.

-TEST_F(NetworkRequestTest, Download) {

-  BitsRequest* bits_request(new BitsRequest);

-  // Bits specific settings.

-  //

-  // Hardcode for now the min value, just to see how it works.

-  // TODO(omaha): expose properties to NetworkRequest.

-  bits_request->set_minimum_retry_delay(60);

-  bits_request->set_no_progress_timeout(5);

-

-  network_request_->AddHttpRequest(bits_request);

-  network_request_->AddHttpRequest(new SimpleRequest);

-  network_request_->AddHttpRequest(new BrowserRequest);

-  DownloadHelper();

-}

-

-// Download http file.

-TEST_F(NetworkRequestTest, DownloadUrlmon) {

-  BitsRequest* bits_request(new BitsRequest);

-  // Bits specific settings.

-  bits_request->set_minimum_retry_delay(60);

-  bits_request->set_no_progress_timeout(5);

-

-  network_request_->AddHttpRequest(bits_request);

-  network_request_->AddHttpRequest(new UrlmonRequest);

-  network_request_->AddHttpRequest(new BrowserRequest);

-  DownloadHelper();

-}

-

-TEST_F(NetworkRequestTest, MultipleRequests) {

-  network_request_->AddHttpRequest(new CupRequest(new SimpleRequest));

-  MultipleRequestsHelper();

-}

-

-TEST_F(NetworkRequestTest, MultipleRequestsUrlmon) {

-  network_request_->AddHttpRequest(new CupRequest(new UrlmonRequest));

-  MultipleRequestsHelper();

-}

-

-TEST_F(NetworkRequestTest, PostRequest) {

-  network_request_->AddHttpRequest(new SimpleRequest);

-  PostRequestHelper();

-}

-

-TEST_F(NetworkRequestTest, PostRequestUrlmon) {

-  network_request_->AddHttpRequest(new UrlmonRequest);

-  PostRequestHelper();

-}

-

-TEST_F(NetworkRequestTest, PostRequestNegativeTest) {

-  network_request_->AddHttpRequest(new SimpleRequest);

-  PostRequestNegativeTestHelper();

-}

-

-TEST_F(NetworkRequestTest, PostRequestNegativeTestUrlmon) {

-  network_request_->AddHttpRequest(new UrlmonRequest);

-  PostRequestNegativeTestHelper();

-}

-

-TEST_F(NetworkRequestTest, RetriesNegativeTest) {

-  network_request_->AddHttpRequest(new SimpleRequest);

-  RetriesNegativeTestHelper();

-}

-

-TEST_F(NetworkRequestTest, RetriesNegativeTestUrlmon) {

-  network_request_->AddHttpRequest(new UrlmonRequest);

-  RetriesNegativeTestHelper();

-}

-

-// Network request can't be reused once canceled.

-TEST_F(NetworkRequestTest, CancelTest_CannotReuse) {

-  network_request_->Cancel();

-  std::vector<uint8> response;

-

-  CString url = _T("https://www.google.com/robots.txt");

-  EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED,

-            network_request_->Get(url, &response));

-}

-

-TEST_F(NetworkRequestTest, CancelTest_DownloadFile) {

-  HANDLE timer_queue = ::CreateTimerQueue();

-  ASSERT_TRUE(timer_queue);

-  ON_SCOPE_EXIT(::DeleteTimerQueueEx, timer_queue, INVALID_HANDLE_VALUE);

-

-  QueueTimer queue_timer(timer_queue,

-                         &NetworkRequestTest::CancelCallback,

-                         this);

-  ASSERT_HRESULT_SUCCEEDED(queue_timer.Start(200, 0, WT_EXECUTEONLYONCE));

-

-  // Try a direct connection to a non-existent host and keep retrying until

-  // canceled by the timer.

-  Config config;

-  network_request_->set_network_configuration(&config);

-

-  BitsRequest* bits_request(new BitsRequest);

-  bits_request->set_minimum_retry_delay(60);

-  bits_request->set_no_progress_timeout(5);

-  network_request_->AddHttpRequest(bits_request);

-  network_request_->set_num_retries(10);

-  network_request_->set_time_between_retries(10);  // 10 miliseconds.

-  std::vector<uint8> response;

-

-  CString url = _T("http://nohost/nofile");

-

-  EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED,

-            network_request_->DownloadFile(url, _T("c:\\foo")));

-

-  EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED,

-            network_request_->DownloadFile(url, _T("c:\\foo")));

-}

-

-TEST_F(NetworkRequestTest, CancelTest_Get) {

-  network_request_->AddHttpRequest(new SimpleRequest);

-  CancelTest_GetHelper();

-}

-

-TEST_F(NetworkRequestTest, CancelTest_GetUrlmon) {

-  network_request_->AddHttpRequest(new UrlmonRequest);

-  CancelTest_GetHelper();

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <winhttp.h>
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "base/basictypes.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/queue_timer.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vista_utils.h"
+#include "omaha/net/bits_request.h"
+#include "omaha/net/browser_request.h"
+#include "omaha/net/cup_request.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/simple_request.h"
+#include "omaha/net/urlmon_request.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class NetworkRequestTest
+    : public testing::Test,
+      public NetworkRequestCallback {
+ protected:
+  NetworkRequestTest() {}
+
+  static void SetUpTestCase() {
+    // Initialize the detection chain: GoogleProxy, FireFox if it is the
+    // default browser, and IE.
+    NetworkConfig& network_config(NetworkConfig::Instance());
+    network_config.Clear();
+    network_config.Add(new GoogleProxyDetector(MACHINE_REG_UPDATE_DEV));
+    BrowserType browser_type(BROWSER_UNKNOWN);
+    GetDefaultBrowserType(&browser_type);
+    if (browser_type == BROWSER_FIREFOX) {
+      network_config.Add(new FirefoxProxyDetector());
+    }
+    network_config.Add(new IEProxyDetector());
+    network_config.Add(new DefaultProxyDetector);
+
+    vista::GetLoggedOnUserToken(&token_);
+  }
+
+  static void TearDownTestCase() {
+    if (token_) {
+      ::CloseHandle(token_);
+    }
+    NetworkConfig::Instance().Clear();
+  }
+
+  virtual void SetUp() {
+    const NetworkConfig::Session& session(NetworkConfig::Instance().session());
+    network_request_.reset(new NetworkRequest(session));
+  }
+
+  virtual void TearDown() {}
+
+  virtual void OnProgress(int bytes, int bytes_total, int, const TCHAR*) {
+    UNREFERENCED_PARAMETER(bytes);
+    UNREFERENCED_PARAMETER(bytes_total);
+    NET_LOG(L3, (_T("[downloading %d of %d]"), bytes, bytes_total));
+  }
+
+  static void CancelCallback(QueueTimer* queue_timer) {
+    ASSERT_TRUE(queue_timer);
+    ASSERT_TRUE(queue_timer->ctx());
+    void* ctx = queue_timer->ctx();
+    NetworkRequestTest* test = static_cast<NetworkRequestTest*>(ctx);
+
+    const TCHAR* msg = _T("CancelCallback");
+    ASSERT_HRESULT_SUCCEEDED(test->network_request_->Cancel());
+  }
+
+  // http get.
+  void HttpGetHelper() {
+    std::vector<uint8> response;
+    CString url = _T("http://www.google.com/robots.txt");
+    network_request_->set_num_retries(2);
+    EXPECT_HRESULT_SUCCEEDED(network_request_->Get(url, &response));
+    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);
+  }
+
+  // https get.
+  void HttpsGetHelper() {
+    std::vector<uint8> response;
+    CString url = _T("https://www.google.com/robots.txt");
+    network_request_->set_num_retries(2);
+    EXPECT_HRESULT_SUCCEEDED(network_request_->Get(url, &response));
+    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);
+  }
+
+  // http post.
+  void HttpPostHelper() {
+    std::vector<uint8> response;
+
+    CString url = _T("http://tools.google.com/service/update2");
+    // Post a buffer.
+    const uint8 request[] = "<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" testsource=\"dev\"/>";  // NOLINT
+    network_request_->set_num_retries(2);
+    EXPECT_HRESULT_SUCCEEDED(network_request_->Post(url,
+                                                    request,
+                                                    arraysize(request) - 1,
+                                                    &response));
+    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);
+
+    // Post an UTF8 string.
+    CStringA utf8_request(reinterpret_cast<const char*>(request));
+    EXPECT_HRESULT_SUCCEEDED(network_request_->PostUtf8String(url,
+                                                              utf8_request,
+                                                              &response));
+    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);
+
+    // Post a Unicode string.
+    CString unicode_request(reinterpret_cast<const char*>(request));
+    EXPECT_HRESULT_SUCCEEDED(network_request_->PostString(url,
+                                                          unicode_request,
+                                                          &response));
+    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);
+  }
+
+  // Download http file.
+  void DownloadHelper() {
+    CString url = _T("http://dl.google.com/update2/UpdateData.bin");
+
+    CString temp_dir = app_util::GetTempDir();
+    CString temp_file;
+    EXPECT_TRUE(::GetTempFileName(temp_dir, _T("tmp"), 0,
+                                  CStrBuf(temp_file, MAX_PATH)));
+    network_request_->set_num_retries(2);
+    network_request_->set_low_priority(true);
+    network_request_->set_callback(this);
+    EXPECT_HRESULT_SUCCEEDED(network_request_->DownloadFile(url, temp_file));
+    EXPECT_TRUE(::DeleteFile(temp_file));
+    EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);
+  }
+
+  void MultipleRequestsHelper() {
+    std::vector<uint8> response;
+
+    CString url = _T("http://tools.google.com/service/update2");
+    const uint8 request[] = "<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" testsource=\"dev\"/>";  // NOLINT
+    for (size_t i = 0; i != 3; ++i) {
+      EXPECT_HRESULT_SUCCEEDED(network_request_->Post(url,
+                                                      request,
+                                                      arraysize(request) - 1,
+                                                      &response));
+      EXPECT_EQ(network_request_->http_status_code(), HTTP_STATUS_OK);
+    }
+  }
+
+  void PostRequestHelper() {
+    CString response;
+    CString url = _T("http://tools.google.com/service/update2");
+    CString request = _T("<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" testsource=\"dev\"/>");  // NOLINT
+    EXPECT_HRESULT_SUCCEEDED(PostRequest(network_request_.get(),
+                                         true,
+                                         url,
+                                         request,
+                                         &response));
+  }
+
+  void PostRequestNegativeTestHelper() {
+    CString response;
+    CString url = _T("http://no_such_host.google.com/service/update2");
+    CString request = _T("<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" testsource=\"dev\"/>");  // NOLINT
+    EXPECT_HRESULT_FAILED(PostRequest(network_request_.get(),
+                                      true,
+                                      url,
+                                      request,
+                                      &response));
+  }
+
+  void RetriesNegativeTestHelper() {
+    // Try a direct connection to a non-existent host and keep retrying until
+    // the retries are used up. Urlmon request is using IE's settings.
+    // Therefore, it is possible a proxy is used. In this case, the http
+    // response is '503 Service Unavailable'.
+    Config config;
+    network_request_->set_network_configuration(&config);
+    network_request_->set_num_retries(2);
+    network_request_->set_time_between_retries(10);   // 10 miliseconds.
+    std::vector<uint8> response;
+
+    CString url = _T("http://nohost/nofile");
+
+    // One request plus 2 retries after 10 and 20 miliseconds respectively.
+    HRESULT hr = network_request_->Get(url, &response);
+    EXPECT_TRUE(hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_NAME_NOT_RESOLVED) ||
+                hr == INET_E_RESOURCE_NOT_FOUND ||
+                hr == HRESULTFromHttpStatusCode(503));
+  }
+
+  void CancelTest_GetHelper() {
+    HANDLE timer_queue = ::CreateTimerQueue();
+    ASSERT_TRUE(timer_queue);
+    ON_SCOPE_EXIT(::DeleteTimerQueueEx, timer_queue, INVALID_HANDLE_VALUE);
+
+    QueueTimer queue_timer(timer_queue,
+                           &NetworkRequestTest::CancelCallback,
+                           this);
+    ASSERT_HRESULT_SUCCEEDED(queue_timer.Start(200, 0, WT_EXECUTEONLYONCE));
+
+    // Try a direct connection to a non-existent host and keep retrying until
+    // canceled by the timer.
+    Config config;
+    network_request_->set_network_configuration(&config);
+    network_request_->set_num_retries(10);
+    network_request_->set_time_between_retries(10);  // 10 miliseconds.
+    std::vector<uint8> response;
+
+    CString url = _T("http://nohost/nofile");
+
+    EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED,
+              network_request_->Get(url, &response));
+
+    EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED,
+              network_request_->Get(url, &response));
+  }
+
+  scoped_ptr<NetworkRequest> network_request_;
+  static HANDLE token_;
+};
+
+HANDLE NetworkRequestTest::token_ = NULL;
+
+// http get.
+TEST_F(NetworkRequestTest, HttpGet) {
+  network_request_->AddHttpRequest(new SimpleRequest);
+  network_request_->AddHttpRequest(new BrowserRequest);
+  HttpGetHelper();
+}
+
+// http get.
+TEST_F(NetworkRequestTest, HttpGetUrlmon) {
+  network_request_->AddHttpRequest(new UrlmonRequest);
+  network_request_->AddHttpRequest(new BrowserRequest);
+  HttpGetHelper();
+}
+
+// https get.
+TEST_F(NetworkRequestTest, HttpsGet) {
+  network_request_->AddHttpRequest(new SimpleRequest);
+  network_request_->AddHttpRequest(new BrowserRequest);
+  HttpsGetHelper();
+}
+
+// https get.
+TEST_F(NetworkRequestTest, HttpsGetUrlmon) {
+  network_request_->AddHttpRequest(new UrlmonRequest);
+  network_request_->AddHttpRequest(new BrowserRequest);
+  HttpsGetHelper();
+}
+
+// http post.
+TEST_F(NetworkRequestTest, HttpPost) {
+  network_request_->AddHttpRequest(new CupRequest(new SimpleRequest));
+  network_request_->AddHttpRequest(new SimpleRequest);
+  network_request_->AddHttpRequest(new CupRequest(new BrowserRequest));
+  HttpPostHelper();
+}
+
+// http post.
+TEST_F(NetworkRequestTest, HttpPostUrlmon) {
+  network_request_->AddHttpRequest(new CupRequest(new UrlmonRequest));
+  network_request_->AddHttpRequest(new UrlmonRequest);
+  network_request_->AddHttpRequest(new CupRequest(new BrowserRequest));
+  HttpPostHelper();
+}
+
+// Download http file.
+TEST_F(NetworkRequestTest, Download) {
+  BitsRequest* bits_request(new BitsRequest);
+  // Bits specific settings.
+  //
+  // Hardcode for now the min value, just to see how it works.
+  // TODO(omaha): expose properties to NetworkRequest.
+  bits_request->set_minimum_retry_delay(60);
+  bits_request->set_no_progress_timeout(5);
+
+  network_request_->AddHttpRequest(bits_request);
+  network_request_->AddHttpRequest(new SimpleRequest);
+  network_request_->AddHttpRequest(new BrowserRequest);
+  DownloadHelper();
+}
+
+// Download http file.
+TEST_F(NetworkRequestTest, DownloadUrlmon) {
+  BitsRequest* bits_request(new BitsRequest);
+  // Bits specific settings.
+  bits_request->set_minimum_retry_delay(60);
+  bits_request->set_no_progress_timeout(5);
+
+  network_request_->AddHttpRequest(bits_request);
+  network_request_->AddHttpRequest(new UrlmonRequest);
+  network_request_->AddHttpRequest(new BrowserRequest);
+  DownloadHelper();
+}
+
+TEST_F(NetworkRequestTest, MultipleRequests) {
+  network_request_->AddHttpRequest(new CupRequest(new SimpleRequest));
+  MultipleRequestsHelper();
+}
+
+TEST_F(NetworkRequestTest, MultipleRequestsUrlmon) {
+  network_request_->AddHttpRequest(new CupRequest(new UrlmonRequest));
+  MultipleRequestsHelper();
+}
+
+TEST_F(NetworkRequestTest, PostRequest) {
+  network_request_->AddHttpRequest(new SimpleRequest);
+  PostRequestHelper();
+}
+
+TEST_F(NetworkRequestTest, PostRequestUrlmon) {
+  network_request_->AddHttpRequest(new UrlmonRequest);
+  PostRequestHelper();
+}
+
+TEST_F(NetworkRequestTest, PostRequestNegativeTest) {
+  network_request_->AddHttpRequest(new SimpleRequest);
+  PostRequestNegativeTestHelper();
+}
+
+TEST_F(NetworkRequestTest, PostRequestNegativeTestUrlmon) {
+  network_request_->AddHttpRequest(new UrlmonRequest);
+  PostRequestNegativeTestHelper();
+}
+
+TEST_F(NetworkRequestTest, RetriesNegativeTest) {
+  network_request_->AddHttpRequest(new SimpleRequest);
+  RetriesNegativeTestHelper();
+}
+
+TEST_F(NetworkRequestTest, RetriesNegativeTestUrlmon) {
+  network_request_->AddHttpRequest(new UrlmonRequest);
+  RetriesNegativeTestHelper();
+}
+
+// Network request can't be reused once canceled.
+TEST_F(NetworkRequestTest, CancelTest_CannotReuse) {
+  network_request_->Cancel();
+  std::vector<uint8> response;
+
+  CString url = _T("https://www.google.com/robots.txt");
+  EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED,
+            network_request_->Get(url, &response));
+}
+
+TEST_F(NetworkRequestTest, CancelTest_DownloadFile) {
+  HANDLE timer_queue = ::CreateTimerQueue();
+  ASSERT_TRUE(timer_queue);
+  ON_SCOPE_EXIT(::DeleteTimerQueueEx, timer_queue, INVALID_HANDLE_VALUE);
+
+  QueueTimer queue_timer(timer_queue,
+                         &NetworkRequestTest::CancelCallback,
+                         this);
+  ASSERT_HRESULT_SUCCEEDED(queue_timer.Start(200, 0, WT_EXECUTEONLYONCE));
+
+  // Try a direct connection to a non-existent host and keep retrying until
+  // canceled by the timer.
+  Config config;
+  network_request_->set_network_configuration(&config);
+
+  BitsRequest* bits_request(new BitsRequest);
+  bits_request->set_minimum_retry_delay(60);
+  bits_request->set_no_progress_timeout(5);
+  network_request_->AddHttpRequest(bits_request);
+  network_request_->set_num_retries(10);
+  network_request_->set_time_between_retries(10);  // 10 miliseconds.
+  std::vector<uint8> response;
+
+  CString url = _T("http://nohost/nofile");
+
+  EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED,
+            network_request_->DownloadFile(url, _T("c:\\foo")));
+
+  EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED,
+            network_request_->DownloadFile(url, _T("c:\\foo")));
+}
+
+TEST_F(NetworkRequestTest, CancelTest_Get) {
+  network_request_->AddHttpRequest(new SimpleRequest);
+  CancelTest_GetHelper();
+}
+
+TEST_F(NetworkRequestTest, CancelTest_GetUrlmon) {
+  network_request_->AddHttpRequest(new UrlmonRequest);
+  CancelTest_GetHelper();
+}
+
+}  // namespace omaha
+
diff --git a/net/proxy_auth.cc b/net/proxy_auth.cc
index d07f0d2..3a9372a 100644
--- a/net/proxy_auth.cc
+++ b/net/proxy_auth.cc
@@ -1,459 +1,459 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-#include "omaha/net/proxy_auth.h"

-#include <atlcom.h>

-#include <pstore.h>

-#include <wincred.h>

-#include <wincrypt.h>

-#include "omaha/common/encrypt.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/smart_handle.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system_info.h"

-#include "omaha/third_party/smartany/scoped_any.h"

-

-using omaha::encrypt::EncryptData;

-using omaha::encrypt::DecryptData;

-

-namespace omaha {

-

-static const GUID kPreIE7CredTypeGuid = { 0x5e7e8100, 0x9138, 0x11d1,

-  { 0x94, 0x5a, 0x00, 0xc0, 0x4f, 0xc3, 0x08, 0xff } };

-static const GUID kPreIE7CredSubtypeGuid = { 0 };

-

-#define kIE7CredKey "abe2869f-9b47-4cd9-a358-c22904dba7f7"

-

-bool ProxyAuth::IsPromptAllowed() {

-  __mutexScope(lock_);

-  return prompt_cancelled_ < cancel_prompt_threshold_;

-}

-

-void ProxyAuth::PromptCancelled() {

-  __mutexScope(lock_);

-  prompt_cancelled_++;

-}

-

-CString ProxyAuth::ExtractProxy(const CString& proxy_settings,

-                                bool isHttps) {

-  if (proxy_settings.IsEmpty()) {

-    NET_LOG(L3, (_T("[ProxyAuth::ExtractProxy][Empty settings")));

-    return proxy_settings;

-  }

-

-  int equals_index = String_FindChar(proxy_settings, L'=');

-  if (equals_index >= 0) {

-    const wchar_t* prefix = L"http=";

-    if (isHttps)

-      prefix = L"https=";

-

-    int prefix_index = String_FindString(proxy_settings, prefix);

-    if (prefix_index == -1) {

-      // fallback to whatever we've got after an equals sign

-      prefix = L"=";

-      prefix_index = equals_index;

-    }

-

-    int first = prefix_index + lstrlen(prefix);

-    int length = String_FindChar(proxy_settings, L' ');

-    if (length == -1) {

-      return proxy_settings.Mid(first);

-    } else {

-      return proxy_settings.Mid(first, length);

-    }

-  }

-

-  return proxy_settings;

-}

-

-void ProxyAuth::ConfigureProxyAuth(const CString& caption,

-                                   const CString& message,

-                                   HWND parent,

-                                   uint32 cancel_prompt_threshold) {

-  ASSERT1(!caption.IsEmpty());

-  ASSERT1(!message.IsEmpty());

-  ASSERT1(parent);

-  ASSERT1(cancel_prompt_threshold);

-

-  proxy_prompt_caption_ = caption;

-  proxy_prompt_message_ = message;

-  parent_hwnd_ = parent;

-  cancel_prompt_threshold_ = cancel_prompt_threshold;

-}

-

-bool ProxyAuth::PromptUser(const CString& server) {

-  scoped_library credui_lib(::LoadLibrary(L"credui.dll"));

-  ASSERT1(credui_lib);

-  if (!credui_lib)

-    return false;

-

-  typedef BOOL (__stdcall *CredUIPromptForCredentialsW_type)(

-      PCREDUI_INFO pUiInfo,

-      PCTSTR pszTargetName,

-      PCtxtHandle Reserved,

-      DWORD dwAuthError,

-      PCTSTR pszUserName,

-      ULONG ulUserNameMaxChars,

-      PCTSTR pszPassword,

-      ULONG ulPasswordMaxChars,

-      PBOOL pfSave,

-      DWORD dwFlags);

-  CredUIPromptForCredentialsW_type CredUIPromptForCredentialsW_fn =

-      reinterpret_cast<CredUIPromptForCredentialsW_type>(

-          GetProcAddress(get(credui_lib), "CredUIPromptForCredentialsW"));

-  ASSERT1(CredUIPromptForCredentialsW_fn || SystemInfo::IsRunningOnW2K());

-  if (!CredUIPromptForCredentialsW_fn)

-    return false;

-

-  wchar_t username[CREDUI_MAX_USERNAME_LENGTH + 1];

-  wchar_t password[CREDUI_MAX_PASSWORD_LENGTH + 1];

-  BOOL check;

-  CREDUI_INFO info = {0};

-  info.cbSize = sizeof(info);

-

-  ASSERT1(parent_hwnd_);

-  info.hwndParent = parent_hwnd_;

-

-  ASSERT1(!proxy_prompt_message_.IsEmpty());

-  ASSERT1(!proxy_prompt_caption_.IsEmpty());

-  CString message;

-  message.FormatMessage(proxy_prompt_message_, server);

-  info.pszMessageText = message.GetString();

-  info.pszCaptionText = proxy_prompt_caption_;

-

-  DWORD result;

-  do {

-    username[0] = L'\0';

-    password[0] = L'\0';

-    result = CredUIPromptForCredentialsW_fn(

-        &info,

-        server,

-        NULL,

-        0,

-        username,

-        CREDUI_MAX_USERNAME_LENGTH,

-        password,

-        CREDUI_MAX_PASSWORD_LENGTH,

-        &check,

-        CREDUI_FLAGS_ALWAYS_SHOW_UI | CREDUI_FLAGS_GENERIC_CREDENTIALS |

-        CREDUI_FLAGS_DO_NOT_PERSIST);

-    NET_LOG(L3, (_T("[CredUIPromptForCredentialsW returned %d]"), result));

-  } while (result == NO_ERROR && (!username[0] || !password[0]));

-

-  if (result == NO_ERROR) {

-    AddCred(server, username, password);

-  } else if (result == ERROR_CANCELLED) {

-    PromptCancelled();

-  }

-

-  return result == NO_ERROR;

-}

-

-bool ProxyAuth::GetProxyCredentials(bool allow_ui, bool force_ui,

-                                    const CString& proxy_server,

-                                    CString* username, CString* password,

-                                    uint32* auth_scheme) {

-  CString server(proxy_server);

-  if (server.IsEmpty()) {

-    server = kDefaultProxyServer;

-  }

-

-  __mutexScope(lock_);

-  int i = -1;

-  if (!force_ui)

-    i = servers_.Find(server);

-

-  if (i == -1) {

-    if (ReadFromIE7(server) || ReadFromPreIE7(server) ||

-        (allow_ui && parent_hwnd_ && IsPromptAllowed() && PromptUser(server))) {

-      i = servers_.GetSize() - 1;

-    }

-  }

-

-  if (i >= 0) {

-    ASSERT1(!usernames_[i].IsEmpty() && !passwords_[i].empty());

-    std::vector<uint8> decrypted_password;

-    HRESULT hr = DecryptData(NULL,

-                             0,

-                             &passwords_[i].front(),

-                             passwords_[i].size(),

-                             &decrypted_password);

-    if (FAILED(hr)) {

-      NET_LOG(LE, (_T("[DecryptData failed][0x%x]"), hr));

-      return false;

-    }

-

-    *username = usernames_[i];

-    *password = reinterpret_cast<TCHAR*>(&decrypted_password.front());

-    *auth_scheme = auth_schemes_[i];

-  }

-

-  NET_LOG(L3, (_T("[ProxyAuth::GetProxyCredentials][%d][%s][%s][%d]"),

-               i, proxy_server, *username, *auth_scheme));

-  return i >= 0;

-}

-

-static bool ParseCredsFromRawBuffer(const BYTE* buffer, const DWORD bytes,

-                                    CString* username, CString* password) {

-  ASSERT1(bytes > 0);

-  if (bytes <= 0)

-    return false;

-

-  const char* ascii_buffer = reinterpret_cast<const char*>(buffer);

-  const unsigned ascii_length =

-    static_cast<const unsigned>(strlen(ascii_buffer));

-

-  // The buffer could be ascii or wide characters, so we detect which one it

-  // is and copy the ascii characters to a wide string if necessary

-  const wchar_t* user_pass = NULL;

-  CString temp;

-  if (ascii_length == bytes - 1) {

-    temp = AnsiToWideString(ascii_buffer, ascii_length);

-    user_pass = temp.GetString();

-  } else {

-    user_pass = reinterpret_cast<const wchar_t*>(buffer);

-  }

-

-  int colon_pos = String_FindChar(user_pass, L':');

-  if (colon_pos >= 0) {

-    username->SetString(user_pass, colon_pos);

-    password->SetString(user_pass + colon_pos + 1);

-  }

-

-  return colon_pos >= 0;

-}

-

-void ProxyAuth::AddCred(const CString& server, const CString& username,

-                        const CString& password) {

-  std::vector<uint8> encrypted_password;

-  HRESULT hr = EncryptData(NULL,

-                           0,

-                           password,

-                           (password.GetLength() + 1) * sizeof(TCHAR),

-                           &encrypted_password);

-  if (FAILED(hr)) {

-    NET_LOG(LE, (_T("[EncryptData failed][0x%x]"), hr));

-    return;

-  }

-

-  __mutexScope(lock_);

-  int i = servers_.Find(server);

-  if (i == -1) {

-    servers_.Add(server);

-    usernames_.Add(username);

-    passwords_.Add(encrypted_password);

-    auth_schemes_.Add(UNKNOWN_AUTH_SCHEME);

-  } else {

-    usernames_[i] = username;

-    passwords_[i] = encrypted_password;

-    auth_schemes_[i] = UNKNOWN_AUTH_SCHEME;

-  }

-

-  NET_LOG(L3, (_T("[ProxyAuth::AddCred][%s][%s]"), server, username));

-}

-

-HRESULT ProxyAuth::SetProxyAuthScheme(const CString& proxy_server,

-                                      uint32 scheme) {

-  CString server(proxy_server);

-  if (server.IsEmpty()) {

-    server = kDefaultProxyServer;

-  }

-

-  __mutexScope(lock_);

-  int i = servers_.Find(server);

-  if (i == -1) {

-    NET_LOG(LE, (_T("[ProxyAuth::SetProxyAuthScheme][%s not found]"), server));

-    return E_INVALIDARG;

-  }

-

-  auth_schemes_[i] = scheme;

-  NET_LOG(L3, (_T("[ProxyAuth::SetProxyAuthScheme][%s][%s][%d]"),

-               server, usernames_[i], scheme));

-  return S_OK;

-}

-

-// This approach (the key in particular) comes from a securityfocus posting:

-// http://www.securityfocus.com/archive/1/458115/30/0/threaded

-bool ProxyAuth::ReadFromIE7(const CString& server) {

-  scoped_library crypt_lib(::LoadLibrary(L"crypt32.dll"));

-  ASSERT1(crypt_lib);

-  if (!crypt_lib)

-    return false;

-

-  typedef BOOL (__stdcall *CryptUnprotectData_type)(DATA_BLOB*, LPWSTR*,

-    DATA_BLOB*, PVOID, CRYPTPROTECT_PROMPTSTRUCT*, DWORD, DATA_BLOB*);

-  CryptUnprotectData_type CryptUnprotectData_fn =

-      reinterpret_cast<CryptUnprotectData_type>(

-          GetProcAddress(get(crypt_lib), "CryptUnprotectData"));

-  ASSERT1(CryptUnprotectData_fn);

-  if (!CryptUnprotectData_fn)

-    return false;

-

-  // Load CredEnumerate and CredFree dynamically because they don't exist on

-  // Win2K and so loading the GoogleDesktopCommon.dll otherwise.

-  scoped_library advapi_lib(::LoadLibrary(L"advapi32.dll"));

-  ASSERT1(advapi_lib);

-  if (!advapi_lib)

-    return false;

-

-  typedef BOOL (__stdcall *CredEnumerateW_type)(LPCWSTR, DWORD, DWORD*,

-                                                PCREDENTIAL**);

-  CredEnumerateW_type CredEnumerateW_fn =

-      reinterpret_cast<CredEnumerateW_type>(

-          GetProcAddress(get(advapi_lib), "CredEnumerateW"));

-  ASSERT1(CredEnumerateW_fn || SystemInfo::IsRunningOnW2K());

-  if (!CredEnumerateW_fn)

-    return false;

-

-  typedef VOID (__stdcall *CredFree_type)(PVOID);

-  CredFree_type CredFree_fn = reinterpret_cast<CredFree_type>(

-      GetProcAddress(get(advapi_lib), "CredFree"));

-  ASSERT1(CredFree_fn || SystemInfo::IsRunningOnW2K());

-  if (!CredFree_fn)

-    return false;

-

-  // Done with dynamically loading methods.  CredEnumerate (and CredFree if

-  // we didn't return) will have failed to load on Win2K

-

-  DATA_BLOB optional_entropy;

-

-  char key[ARRAYSIZE(kIE7CredKey)] = kIE7CredKey;

-  int16 temp[ARRAYSIZE(key)];

-  for (int i = 0; i < ARRAYSIZE(key); ++i)

-    temp[i] = static_cast<int16>(key[i] * 4);

-

-  optional_entropy.pbData = reinterpret_cast<BYTE*>(&temp);

-  optional_entropy.cbData = sizeof(temp);

-

-  CString target(NOTRANSL(L"Microsoft_WinInet_"));

-  target += server;

-  target += L"*";

-

-  DWORD count = 0;

-  CREDENTIAL** credentials = NULL;

-  CString username;

-  CString password;

-

-  bool found = false;

-  if (CredEnumerateW_fn(target, 0, &count, &credentials)) {

-    for (unsigned i = 0; i < count; ++i) {

-      if (credentials[i]->Type == CRED_TYPE_GENERIC) {

-        DATA_BLOB data_in;

-        DATA_BLOB data_out = { 0 };

-        data_in.pbData = static_cast<BYTE*>(credentials[i]->CredentialBlob);

-        data_in.cbData = credentials[i]->CredentialBlobSize;

-

-        if (CryptUnprotectData_fn(&data_in, NULL, &optional_entropy, NULL, NULL,

-                                  0, &data_out)) {

-          found = ParseCredsFromRawBuffer(data_out.pbData, data_out.cbData,

-                                          &username, &password);

-          LocalFree(data_out.pbData);

-          if (found) {

-            AddCred(server, username, password);

-            break;

-          }

-        }

-      }

-    }

-    CredFree_fn(credentials);

-  }

-

-  return found;

-}

-

-bool ProxyAuth::ReadFromPreIE7(const CString& server) {

-  scoped_library pstore_lib(::LoadLibrary(L"pstorec.dll"));

-  ASSERT1(pstore_lib);

-  if (!pstore_lib)

-    return false;

-

-  typedef HRESULT (__stdcall *PStoreCreateInstance_type)(IPStore**,

-    PST_PROVIDERID*, void*, DWORD);

-  PStoreCreateInstance_type PStoreCreateInstance_fn =

-      reinterpret_cast<PStoreCreateInstance_type>(

-          GetProcAddress(get(pstore_lib), "PStoreCreateInstance"));

-  ASSERT1(PStoreCreateInstance_fn);

-  if (!PStoreCreateInstance_fn)

-    return false;

-

-  CString username;

-  CString password;

-  bool found = false;

-

-  scoped_co_init initializer(COINIT_APARTMENTTHREADED);

-  HRESULT hr = E_FAIL;

-

-  // The best reference I found about these iterators, especially how to free

-  // the item_name returned by this iterator was a microsoft patent application:

-  // http://www.patentstorm.us/patents/6272631-description.html

-  CComPtr<IPStore> pstore;

-  VERIFY1(SUCCEEDED(hr = PStoreCreateInstance_fn(&pstore, NULL, NULL, 0)));

-  if (SUCCEEDED(hr)) {

-    CComPtr<IEnumPStoreTypes> enum_types;

-    VERIFY1(SUCCEEDED(hr = pstore->EnumTypes(PST_KEY_CURRENT_USER, 0,

-                                             &enum_types)));

-    if (SUCCEEDED(hr)) {

-      GUID type_guid = { 0 };

-      // Get the types one at a time

-      while (enum_types->Next(1, &type_guid, NULL) == S_OK) {

-        if (type_guid != kPreIE7CredTypeGuid)

-          continue;

-

-        CComPtr<IEnumPStoreTypes> enum_subtypes;

-        VERIFY1(SUCCEEDED(hr = pstore->EnumSubtypes(PST_KEY_CURRENT_USER,

-          &type_guid, 0, &enum_subtypes)));

-        if (SUCCEEDED(hr)) {

-          GUID subtype_guid = { 0 };

-          // Get the subtypes one at a time

-          while (enum_subtypes->Next(1, &subtype_guid, NULL) == S_OK) {

-            if (subtype_guid != kPreIE7CredSubtypeGuid)

-              continue;

-

-            CComPtr<IEnumPStoreItems> enum_items;

-            VERIFY1(SUCCEEDED(hr = pstore->EnumItems(PST_KEY_CURRENT_USER,

-              &type_guid, &subtype_guid, 0, &enum_items)));

-            if (SUCCEEDED(hr)) {

-              wchar_t* item_name = NULL;

-              // Get the items one at a time

-              while (enum_items->Next(1, &item_name, NULL) == S_OK) {

-                DWORD data_length = 0;

-                byte* data = NULL;

-

-                VERIFY1(SUCCEEDED(hr = pstore->ReadItem(PST_KEY_CURRENT_USER,

-                  &type_guid, &subtype_guid, item_name, &data_length, &data,

-                  NULL, 0)));

-                if (SUCCEEDED(hr)) {

-                  found = ParseCredsFromRawBuffer(data, data_length,

-                                                  &username, &password);

-                  CoTaskMemFree(data);

-                }

-

-                CoTaskMemFree(item_name);

-                if (found) {

-                  AddCred(server, username, password);

-                  break;

-                }

-              }  // end enum_items loop

-            }

-          }  // end enum_subtypes loop

-        }

-      }  // end enum_types loop

-    }

-  }

-

-  return found;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+#include "omaha/net/proxy_auth.h"
+#include <atlcom.h>
+#include <pstore.h>
+#include <wincred.h>
+#include <wincrypt.h>
+#include "omaha/common/encrypt.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/smart_handle.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system_info.h"
+#include "omaha/third_party/smartany/scoped_any.h"
+
+using omaha::encrypt::EncryptData;
+using omaha::encrypt::DecryptData;
+
+namespace omaha {
+
+static const GUID kPreIE7CredTypeGuid = { 0x5e7e8100, 0x9138, 0x11d1,
+  { 0x94, 0x5a, 0x00, 0xc0, 0x4f, 0xc3, 0x08, 0xff } };
+static const GUID kPreIE7CredSubtypeGuid = { 0 };
+
+#define kIE7CredKey "abe2869f-9b47-4cd9-a358-c22904dba7f7"
+
+bool ProxyAuth::IsPromptAllowed() {
+  __mutexScope(lock_);
+  return prompt_cancelled_ < cancel_prompt_threshold_;
+}
+
+void ProxyAuth::PromptCancelled() {
+  __mutexScope(lock_);
+  prompt_cancelled_++;
+}
+
+CString ProxyAuth::ExtractProxy(const CString& proxy_settings,
+                                bool isHttps) {
+  if (proxy_settings.IsEmpty()) {
+    NET_LOG(L3, (_T("[ProxyAuth::ExtractProxy][Empty settings")));
+    return proxy_settings;
+  }
+
+  int equals_index = String_FindChar(proxy_settings, L'=');
+  if (equals_index >= 0) {
+    const wchar_t* prefix = L"http=";
+    if (isHttps)
+      prefix = L"https=";
+
+    int prefix_index = String_FindString(proxy_settings, prefix);
+    if (prefix_index == -1) {
+      // fallback to whatever we've got after an equals sign
+      prefix = L"=";
+      prefix_index = equals_index;
+    }
+
+    int first = prefix_index + lstrlen(prefix);
+    int length = String_FindChar(proxy_settings, L' ');
+    if (length == -1) {
+      return proxy_settings.Mid(first);
+    } else {
+      return proxy_settings.Mid(first, length);
+    }
+  }
+
+  return proxy_settings;
+}
+
+void ProxyAuth::ConfigureProxyAuth(const CString& caption,
+                                   const CString& message,
+                                   HWND parent,
+                                   uint32 cancel_prompt_threshold) {
+  ASSERT1(!caption.IsEmpty());
+  ASSERT1(!message.IsEmpty());
+  ASSERT1(parent);
+  ASSERT1(cancel_prompt_threshold);
+
+  proxy_prompt_caption_ = caption;
+  proxy_prompt_message_ = message;
+  parent_hwnd_ = parent;
+  cancel_prompt_threshold_ = cancel_prompt_threshold;
+}
+
+bool ProxyAuth::PromptUser(const CString& server) {
+  scoped_library credui_lib(::LoadLibrary(L"credui.dll"));
+  ASSERT1(credui_lib);
+  if (!credui_lib)
+    return false;
+
+  typedef BOOL (__stdcall *CredUIPromptForCredentialsW_type)(
+      PCREDUI_INFO pUiInfo,
+      PCTSTR pszTargetName,
+      PCtxtHandle Reserved,
+      DWORD dwAuthError,
+      PCTSTR pszUserName,
+      ULONG ulUserNameMaxChars,
+      PCTSTR pszPassword,
+      ULONG ulPasswordMaxChars,
+      PBOOL pfSave,
+      DWORD dwFlags);
+  CredUIPromptForCredentialsW_type CredUIPromptForCredentialsW_fn =
+      reinterpret_cast<CredUIPromptForCredentialsW_type>(
+          GetProcAddress(get(credui_lib), "CredUIPromptForCredentialsW"));
+  ASSERT1(CredUIPromptForCredentialsW_fn || SystemInfo::IsRunningOnW2K());
+  if (!CredUIPromptForCredentialsW_fn)
+    return false;
+
+  wchar_t username[CREDUI_MAX_USERNAME_LENGTH + 1];
+  wchar_t password[CREDUI_MAX_PASSWORD_LENGTH + 1];
+  BOOL check;
+  CREDUI_INFO info = {0};
+  info.cbSize = sizeof(info);
+
+  ASSERT1(parent_hwnd_);
+  info.hwndParent = parent_hwnd_;
+
+  ASSERT1(!proxy_prompt_message_.IsEmpty());
+  ASSERT1(!proxy_prompt_caption_.IsEmpty());
+  CString message;
+  message.FormatMessage(proxy_prompt_message_, server);
+  info.pszMessageText = message.GetString();
+  info.pszCaptionText = proxy_prompt_caption_;
+
+  DWORD result;
+  do {
+    username[0] = L'\0';
+    password[0] = L'\0';
+    result = CredUIPromptForCredentialsW_fn(
+        &info,
+        server,
+        NULL,
+        0,
+        username,
+        CREDUI_MAX_USERNAME_LENGTH,
+        password,
+        CREDUI_MAX_PASSWORD_LENGTH,
+        &check,
+        CREDUI_FLAGS_ALWAYS_SHOW_UI | CREDUI_FLAGS_GENERIC_CREDENTIALS |
+        CREDUI_FLAGS_DO_NOT_PERSIST);
+    NET_LOG(L3, (_T("[CredUIPromptForCredentialsW returned %d]"), result));
+  } while (result == NO_ERROR && (!username[0] || !password[0]));
+
+  if (result == NO_ERROR) {
+    AddCred(server, username, password);
+  } else if (result == ERROR_CANCELLED) {
+    PromptCancelled();
+  }
+
+  return result == NO_ERROR;
+}
+
+bool ProxyAuth::GetProxyCredentials(bool allow_ui, bool force_ui,
+                                    const CString& proxy_server,
+                                    CString* username, CString* password,
+                                    uint32* auth_scheme) {
+  CString server(proxy_server);
+  if (server.IsEmpty()) {
+    server = kDefaultProxyServer;
+  }
+
+  __mutexScope(lock_);
+  int i = -1;
+  if (!force_ui)
+    i = servers_.Find(server);
+
+  if (i == -1) {
+    if (ReadFromIE7(server) || ReadFromPreIE7(server) ||
+        (allow_ui && parent_hwnd_ && IsPromptAllowed() && PromptUser(server))) {
+      i = servers_.GetSize() - 1;
+    }
+  }
+
+  if (i >= 0) {
+    ASSERT1(!usernames_[i].IsEmpty() && !passwords_[i].empty());
+    std::vector<uint8> decrypted_password;
+    HRESULT hr = DecryptData(NULL,
+                             0,
+                             &passwords_[i].front(),
+                             passwords_[i].size(),
+                             &decrypted_password);
+    if (FAILED(hr)) {
+      NET_LOG(LE, (_T("[DecryptData failed][0x%x]"), hr));
+      return false;
+    }
+
+    *username = usernames_[i];
+    *password = reinterpret_cast<TCHAR*>(&decrypted_password.front());
+    *auth_scheme = auth_schemes_[i];
+  }
+
+  NET_LOG(L3, (_T("[ProxyAuth::GetProxyCredentials][%d][%s][%s][%d]"),
+               i, proxy_server, *username, *auth_scheme));
+  return i >= 0;
+}
+
+static bool ParseCredsFromRawBuffer(const BYTE* buffer, const DWORD bytes,
+                                    CString* username, CString* password) {
+  ASSERT1(bytes > 0);
+  if (bytes <= 0)
+    return false;
+
+  const char* ascii_buffer = reinterpret_cast<const char*>(buffer);
+  const unsigned ascii_length =
+    static_cast<const unsigned>(strlen(ascii_buffer));
+
+  // The buffer could be ascii or wide characters, so we detect which one it
+  // is and copy the ascii characters to a wide string if necessary
+  const wchar_t* user_pass = NULL;
+  CString temp;
+  if (ascii_length == bytes - 1) {
+    temp = AnsiToWideString(ascii_buffer, ascii_length);
+    user_pass = temp.GetString();
+  } else {
+    user_pass = reinterpret_cast<const wchar_t*>(buffer);
+  }
+
+  int colon_pos = String_FindChar(user_pass, L':');
+  if (colon_pos >= 0) {
+    username->SetString(user_pass, colon_pos);
+    password->SetString(user_pass + colon_pos + 1);
+  }
+
+  return colon_pos >= 0;
+}
+
+void ProxyAuth::AddCred(const CString& server, const CString& username,
+                        const CString& password) {
+  std::vector<uint8> encrypted_password;
+  HRESULT hr = EncryptData(NULL,
+                           0,
+                           password,
+                           (password.GetLength() + 1) * sizeof(TCHAR),
+                           &encrypted_password);
+  if (FAILED(hr)) {
+    NET_LOG(LE, (_T("[EncryptData failed][0x%x]"), hr));
+    return;
+  }
+
+  __mutexScope(lock_);
+  int i = servers_.Find(server);
+  if (i == -1) {
+    servers_.Add(server);
+    usernames_.Add(username);
+    passwords_.Add(encrypted_password);
+    auth_schemes_.Add(UNKNOWN_AUTH_SCHEME);
+  } else {
+    usernames_[i] = username;
+    passwords_[i] = encrypted_password;
+    auth_schemes_[i] = UNKNOWN_AUTH_SCHEME;
+  }
+
+  NET_LOG(L3, (_T("[ProxyAuth::AddCred][%s][%s]"), server, username));
+}
+
+HRESULT ProxyAuth::SetProxyAuthScheme(const CString& proxy_server,
+                                      uint32 scheme) {
+  CString server(proxy_server);
+  if (server.IsEmpty()) {
+    server = kDefaultProxyServer;
+  }
+
+  __mutexScope(lock_);
+  int i = servers_.Find(server);
+  if (i == -1) {
+    NET_LOG(LE, (_T("[ProxyAuth::SetProxyAuthScheme][%s not found]"), server));
+    return E_INVALIDARG;
+  }
+
+  auth_schemes_[i] = scheme;
+  NET_LOG(L3, (_T("[ProxyAuth::SetProxyAuthScheme][%s][%s][%d]"),
+               server, usernames_[i], scheme));
+  return S_OK;
+}
+
+// This approach (the key in particular) comes from a securityfocus posting:
+// http://www.securityfocus.com/archive/1/458115/30/0/threaded
+bool ProxyAuth::ReadFromIE7(const CString& server) {
+  scoped_library crypt_lib(::LoadLibrary(L"crypt32.dll"));
+  ASSERT1(crypt_lib);
+  if (!crypt_lib)
+    return false;
+
+  typedef BOOL (__stdcall *CryptUnprotectData_type)(DATA_BLOB*, LPWSTR*,
+    DATA_BLOB*, PVOID, CRYPTPROTECT_PROMPTSTRUCT*, DWORD, DATA_BLOB*);
+  CryptUnprotectData_type CryptUnprotectData_fn =
+      reinterpret_cast<CryptUnprotectData_type>(
+          GetProcAddress(get(crypt_lib), "CryptUnprotectData"));
+  ASSERT1(CryptUnprotectData_fn);
+  if (!CryptUnprotectData_fn)
+    return false;
+
+  // Load CredEnumerate and CredFree dynamically because they don't exist on
+  // Win2K and so loading the GoogleDesktopCommon.dll otherwise.
+  scoped_library advapi_lib(::LoadLibrary(L"advapi32.dll"));
+  ASSERT1(advapi_lib);
+  if (!advapi_lib)
+    return false;
+
+  typedef BOOL (__stdcall *CredEnumerateW_type)(LPCWSTR, DWORD, DWORD*,
+                                                PCREDENTIAL**);
+  CredEnumerateW_type CredEnumerateW_fn =
+      reinterpret_cast<CredEnumerateW_type>(
+          GetProcAddress(get(advapi_lib), "CredEnumerateW"));
+  ASSERT1(CredEnumerateW_fn || SystemInfo::IsRunningOnW2K());
+  if (!CredEnumerateW_fn)
+    return false;
+
+  typedef VOID (__stdcall *CredFree_type)(PVOID);
+  CredFree_type CredFree_fn = reinterpret_cast<CredFree_type>(
+      GetProcAddress(get(advapi_lib), "CredFree"));
+  ASSERT1(CredFree_fn || SystemInfo::IsRunningOnW2K());
+  if (!CredFree_fn)
+    return false;
+
+  // Done with dynamically loading methods.  CredEnumerate (and CredFree if
+  // we didn't return) will have failed to load on Win2K
+
+  DATA_BLOB optional_entropy;
+
+  char key[ARRAYSIZE(kIE7CredKey)] = kIE7CredKey;
+  int16 temp[ARRAYSIZE(key)];
+  for (int i = 0; i < ARRAYSIZE(key); ++i)
+    temp[i] = static_cast<int16>(key[i] * 4);
+
+  optional_entropy.pbData = reinterpret_cast<BYTE*>(&temp);
+  optional_entropy.cbData = sizeof(temp);
+
+  CString target(NOTRANSL(L"Microsoft_WinInet_"));
+  target += server;
+  target += L"*";
+
+  DWORD count = 0;
+  CREDENTIAL** credentials = NULL;
+  CString username;
+  CString password;
+
+  bool found = false;
+  if (CredEnumerateW_fn(target, 0, &count, &credentials)) {
+    for (unsigned i = 0; i < count; ++i) {
+      if (credentials[i]->Type == CRED_TYPE_GENERIC) {
+        DATA_BLOB data_in;
+        DATA_BLOB data_out = { 0 };
+        data_in.pbData = static_cast<BYTE*>(credentials[i]->CredentialBlob);
+        data_in.cbData = credentials[i]->CredentialBlobSize;
+
+        if (CryptUnprotectData_fn(&data_in, NULL, &optional_entropy, NULL, NULL,
+                                  0, &data_out)) {
+          found = ParseCredsFromRawBuffer(data_out.pbData, data_out.cbData,
+                                          &username, &password);
+          LocalFree(data_out.pbData);
+          if (found) {
+            AddCred(server, username, password);
+            break;
+          }
+        }
+      }
+    }
+    CredFree_fn(credentials);
+  }
+
+  return found;
+}
+
+bool ProxyAuth::ReadFromPreIE7(const CString& server) {
+  scoped_library pstore_lib(::LoadLibrary(L"pstorec.dll"));
+  ASSERT1(pstore_lib);
+  if (!pstore_lib)
+    return false;
+
+  typedef HRESULT (__stdcall *PStoreCreateInstance_type)(IPStore**,
+    PST_PROVIDERID*, void*, DWORD);
+  PStoreCreateInstance_type PStoreCreateInstance_fn =
+      reinterpret_cast<PStoreCreateInstance_type>(
+          GetProcAddress(get(pstore_lib), "PStoreCreateInstance"));
+  ASSERT1(PStoreCreateInstance_fn);
+  if (!PStoreCreateInstance_fn)
+    return false;
+
+  CString username;
+  CString password;
+  bool found = false;
+
+  scoped_co_init initializer(COINIT_APARTMENTTHREADED);
+  HRESULT hr = E_FAIL;
+
+  // The best reference I found about these iterators, especially how to free
+  // the item_name returned by this iterator was a microsoft patent application:
+  // http://www.patentstorm.us/patents/6272631-description.html
+  CComPtr<IPStore> pstore;
+  VERIFY1(SUCCEEDED(hr = PStoreCreateInstance_fn(&pstore, NULL, NULL, 0)));
+  if (SUCCEEDED(hr)) {
+    CComPtr<IEnumPStoreTypes> enum_types;
+    VERIFY1(SUCCEEDED(hr = pstore->EnumTypes(PST_KEY_CURRENT_USER, 0,
+                                             &enum_types)));
+    if (SUCCEEDED(hr)) {
+      GUID type_guid = { 0 };
+      // Get the types one at a time
+      while (enum_types->Next(1, &type_guid, NULL) == S_OK) {
+        if (type_guid != kPreIE7CredTypeGuid)
+          continue;
+
+        CComPtr<IEnumPStoreTypes> enum_subtypes;
+        VERIFY1(SUCCEEDED(hr = pstore->EnumSubtypes(PST_KEY_CURRENT_USER,
+          &type_guid, 0, &enum_subtypes)));
+        if (SUCCEEDED(hr)) {
+          GUID subtype_guid = { 0 };
+          // Get the subtypes one at a time
+          while (enum_subtypes->Next(1, &subtype_guid, NULL) == S_OK) {
+            if (subtype_guid != kPreIE7CredSubtypeGuid)
+              continue;
+
+            CComPtr<IEnumPStoreItems> enum_items;
+            VERIFY1(SUCCEEDED(hr = pstore->EnumItems(PST_KEY_CURRENT_USER,
+              &type_guid, &subtype_guid, 0, &enum_items)));
+            if (SUCCEEDED(hr)) {
+              wchar_t* item_name = NULL;
+              // Get the items one at a time
+              while (enum_items->Next(1, &item_name, NULL) == S_OK) {
+                DWORD data_length = 0;
+                byte* data = NULL;
+
+                VERIFY1(SUCCEEDED(hr = pstore->ReadItem(PST_KEY_CURRENT_USER,
+                  &type_guid, &subtype_guid, item_name, &data_length, &data,
+                  NULL, 0)));
+                if (SUCCEEDED(hr)) {
+                  found = ParseCredsFromRawBuffer(data, data_length,
+                                                  &username, &password);
+                  CoTaskMemFree(data);
+                }
+
+                CoTaskMemFree(item_name);
+                if (found) {
+                  AddCred(server, username, password);
+                  break;
+                }
+              }  // end enum_items loop
+            }
+          }  // end enum_subtypes loop
+        }
+      }  // end enum_types loop
+    }
+  }
+
+  return found;
+}
+
+}  // namespace omaha
+
diff --git a/net/proxy_auth.h b/net/proxy_auth.h
index 3eebb17..43cdf40 100644
--- a/net/proxy_auth.h
+++ b/net/proxy_auth.h
@@ -1,102 +1,102 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_NET_PROXY_AUTH_H__

-#define OMAHA_NET_PROXY_AUTH_H__

-

-#include <windows.h>

-#include <tchar.h>

-#include <atlsimpcoll.h>

-#include <atlstr.h>

-#include <vector>

-#include "omaha/common/synchronized.h"

-

-#define UNKNOWN_AUTH_SCHEME  0x0000FFFF

-const TCHAR* const kDefaultProxyServer = _T("<Default Proxy>");

-const uint32 kDefaultCancelPromptThreshold = 1;

-

-namespace omaha {

-

-// A class that reads and stores the Internet Explorer saved proxy

-// authentication info.  Works with versions of IE up to and including 7.

-class ProxyAuth {

- public:

-  ProxyAuth() : prompt_cancelled_(0),

-                cancel_prompt_threshold_(kDefaultCancelPromptThreshold),

-                parent_hwnd_(NULL) {}

-  ~ProxyAuth() {}

-

-  void ConfigureProxyAuth(const CString& caption, const CString& message,

-                          HWND parent, uint32 cancel_prompt_threshold);

-

-  // Retrieves the saved proxy credentials for Internet Explorer currently.

-  // In the future, there may be other sources of credentials.

-  //

-  // @param allow_ui Whether to allow a ui prompt

-  // @param server The proxy server in domain:port format (e.g., foo.com:8080)

-  // @param username The stored username for this proxy server

-  // @param password The stored password for this proxy server

-  // @returns true if credentials were found, otherwise false

-  bool GetProxyCredentials(bool allow_ui, bool force_ui, const CString& server,

-                           CString* username, CString* password,

-                           uint32* auth_scheme);

-

-  static CString ExtractProxy(const CString& proxy_settings, bool isHttps);

-

-  // This function adds a credential entry, or updates an existing server's

-  // credential entry if it already exists

-  void AddCred(const CString& server, const CString& username,

-               const CString& password);

-  HRESULT SetProxyAuthScheme(const CString& server, uint32 scheme);

-

-  bool IsPromptAllowed();

-  void PromptCancelled();

-

- private:

-  // The servers_, usernames_, and passwords_ lists form a map from server to

-  // (username, password) tuple.  They're implemented here using SimplyArrays

-  // because the otherhead of a map is thought to be too much, since most

-  // users will have one proxy server at most, not dozens.  Accesses are

-  // protected with the lock_.

-  omaha::LLock lock_;

-  CSimpleArray<CString> servers_;

-  CSimpleArray<CString> usernames_;

-  CSimpleArray<std::vector<uint8> > passwords_;

-  CSimpleArray<uint32> auth_schemes_;

-

-  // counts how many times the user has cancelled the authentication prompt.

-  uint32 prompt_cancelled_;

-

-  // after this many authentication prompt cancellations, stop prompting.

-  uint32 cancel_prompt_threshold_;

-

-  CString proxy_prompt_caption_;

-  CString proxy_prompt_message_;

-

-  // Parent window for the credentials prompt.

-  HWND parent_hwnd_;

-

-  bool ReadFromIE7(const CString& server);

-  bool ReadFromPreIE7(const CString& server);

-  bool PromptUser(const CString& server);

-

-  DISALLOW_EVIL_CONSTRUCTORS(ProxyAuth);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_NET_PROXY_AUTH_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_NET_PROXY_AUTH_H__
+#define OMAHA_NET_PROXY_AUTH_H__
+
+#include <windows.h>
+#include <tchar.h>
+#include <atlsimpcoll.h>
+#include <atlstr.h>
+#include <vector>
+#include "omaha/common/synchronized.h"
+
+#define UNKNOWN_AUTH_SCHEME  0x0000FFFF
+const TCHAR* const kDefaultProxyServer = _T("<Default Proxy>");
+const uint32 kDefaultCancelPromptThreshold = 1;
+
+namespace omaha {
+
+// A class that reads and stores the Internet Explorer saved proxy
+// authentication info.  Works with versions of IE up to and including 7.
+class ProxyAuth {
+ public:
+  ProxyAuth() : prompt_cancelled_(0),
+                cancel_prompt_threshold_(kDefaultCancelPromptThreshold),
+                parent_hwnd_(NULL) {}
+  ~ProxyAuth() {}
+
+  void ConfigureProxyAuth(const CString& caption, const CString& message,
+                          HWND parent, uint32 cancel_prompt_threshold);
+
+  // Retrieves the saved proxy credentials for Internet Explorer currently.
+  // In the future, there may be other sources of credentials.
+  //
+  // @param allow_ui Whether to allow a ui prompt
+  // @param server The proxy server in domain:port format (e.g., foo.com:8080)
+  // @param username The stored username for this proxy server
+  // @param password The stored password for this proxy server
+  // @returns true if credentials were found, otherwise false
+  bool GetProxyCredentials(bool allow_ui, bool force_ui, const CString& server,
+                           CString* username, CString* password,
+                           uint32* auth_scheme);
+
+  static CString ExtractProxy(const CString& proxy_settings, bool isHttps);
+
+  // This function adds a credential entry, or updates an existing server's
+  // credential entry if it already exists
+  void AddCred(const CString& server, const CString& username,
+               const CString& password);
+  HRESULT SetProxyAuthScheme(const CString& server, uint32 scheme);
+
+  bool IsPromptAllowed();
+  void PromptCancelled();
+
+ private:
+  // The servers_, usernames_, and passwords_ lists form a map from server to
+  // (username, password) tuple.  They're implemented here using SimplyArrays
+  // because the otherhead of a map is thought to be too much, since most
+  // users will have one proxy server at most, not dozens.  Accesses are
+  // protected with the lock_.
+  omaha::LLock lock_;
+  CSimpleArray<CString> servers_;
+  CSimpleArray<CString> usernames_;
+  CSimpleArray<std::vector<uint8> > passwords_;
+  CSimpleArray<uint32> auth_schemes_;
+
+  // counts how many times the user has cancelled the authentication prompt.
+  uint32 prompt_cancelled_;
+
+  // after this many authentication prompt cancellations, stop prompting.
+  uint32 cancel_prompt_threshold_;
+
+  CString proxy_prompt_caption_;
+  CString proxy_prompt_message_;
+
+  // Parent window for the credentials prompt.
+  HWND parent_hwnd_;
+
+  bool ReadFromIE7(const CString& server);
+  bool ReadFromPreIE7(const CString& server);
+  bool PromptUser(const CString& server);
+
+  DISALLOW_EVIL_CONSTRUCTORS(ProxyAuth);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_NET_PROXY_AUTH_H__
+
diff --git a/net/simple_request.cc b/net/simple_request.cc
index 5cba8b4..46a97d5 100644
--- a/net/simple_request.cc
+++ b/net/simple_request.cc
@@ -1,624 +1,624 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// The implementation does not allow concurrent calls on the same object but

-// it allows calling SimpleRequest::Cancel in order to stop an ongoing request.

-// The transient state of the request is maintained by request_state_.

-// The state is created by SimpleRequest::Send and it is destroyed by

-// SimpleRequest::Close. The only concurrent access to the object state can

-// happened during calling SimpleRequest::Cancel. Cancel closes the

-// connection and the request handles. This makes any of the WinHttp calls

-// on these handles fail and SimpleRequest::Send return to the caller.

-

-#include "omaha/net/simple_request.h"

-

-#include <atlconv.h>

-#include <climits>

-#include <vector>

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/string.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/proxy_auth.h"

-

-namespace omaha {

-

-SimpleRequest::SimpleRequest()

-    : request_buffer_(NULL),

-      request_buffer_length_(0),

-      is_canceled_(false),

-      session_handle_(NULL),

-      low_priority_(false),

-      callback_(NULL) {

-  user_agent_.Format(_T("%s;winhttp"), NetworkConfig::GetUserAgent());

-  http_client_.reset(CreateHttpClient());

-}

-

-SimpleRequest::~SimpleRequest() {

-  Close();

-  callback_ = NULL;

-}

-

-HRESULT SimpleRequest::Close() {

-  NET_LOG(L3, (_T("[SimpleRequest::Close]")));

-  __mutexBlock(lock_) {

-    CloseHandles(request_state_.get());

-    request_state_.reset();

-  }

-  return S_OK;

-}

-

-HRESULT SimpleRequest::Cancel() {

-  NET_LOG(L3, (_T("[SimpleRequest::Cancel]")));

-  __mutexBlock(lock_) {

-    is_canceled_ = true;

-    CloseHandles(request_state_.get());

-  }

-  return S_OK;

-}

-

-HRESULT SimpleRequest::Send() {

-  NET_LOG(L3, (_T("[SimpleRequest::Send][%s]"), url_));

-

-  ASSERT1(!url_.IsEmpty());

-  if (!session_handle_) {

-    // Winhttp could not be loaded.

-    NET_LOG(LW, (_T("[SimpleRequest: session_handle_ is NULL.]")));

-    // TODO(omaha): This makes an assumption that only WinHttp is

-    // supported by the network code.

-    return OMAHA_NET_E_WINHTTP_NOT_AVAILABLE;

-  }

-

-  __mutexBlock(lock_) {

-    CloseHandles(request_state_.get());

-    request_state_.reset(new TransientRequestState);

-  }

-

-  HRESULT hr = DoSend();

-  int status_code(GetHttpStatusCode());

-  if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_OPERATION_CANCELLED) ||

-      is_canceled_) {

-    hr = OMAHA_NET_E_REQUEST_CANCELLED;

-  }

-  NET_LOG(L3, (_T("[SimpleRequest::Send][0x%08x][%d]"), hr, status_code));

-  return hr;

-}

-

-HRESULT SimpleRequest::DoSend() {

-  // First chance to see if it is canceled.

-  if (is_canceled_) {

-    return OMAHA_NET_E_REQUEST_CANCELLED;

-  }

-

-  HRESULT hr = http_client_->Initialize();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = http_client_->CrackUrl(url_,

-                              ICU_DECODE,

-                              &request_state_->scheme,

-                              &request_state_->server,

-                              &request_state_->port,

-                              &request_state_->url_path,

-                              NULL);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(!request_state_->scheme.CompareNoCase(kHttpProtoScheme) ||

-          !request_state_->scheme.CompareNoCase(kHttpsProtoScheme));

-

-  hr = http_client_->Connect(session_handle_,

-                             request_state_->server,

-                             request_state_->port,

-                             &request_state_->connection_handle);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // TODO(omaha): figure out the accept types.

-  //              figure out more flags.

-  DWORD flags = WINHTTP_FLAG_REFRESH;

-  bool is_https = false;

-  if (request_state_->scheme == kHttpsProtoScheme) {

-    is_https = true;

-    flags |= WINHTTP_FLAG_SECURE;

-  }

-  const TCHAR* verb = IsPostRequest() ? _T("POST") : _T("GET");

-  hr = http_client_->OpenRequest(request_state_->connection_handle,

-                                 verb, request_state_->url_path,

-                                 NULL, WINHTTP_NO_REFERER,

-                                 WINHTTP_DEFAULT_ACCEPT_TYPES, flags,

-                                 &request_state_->request_handle);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Disable redirects for POST requests.

-  if (IsPostRequest()) {

-    VERIFY1(SUCCEEDED(http_client_->SetOptionInt(request_state_->request_handle,

-                                                 WINHTTP_OPTION_DISABLE_FEATURE,

-                                                 WINHTTP_DISABLE_REDIRECTS)));

-  }

-

-  additional_headers_.AppendFormat(_T("User-Agent: %s\r\n"), user_agent_);

-  uint32 header_flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE;

-  hr = http_client_->AddRequestHeaders(request_state_->request_handle,

-                                       additional_headers_,

-                                       -1,

-                                       header_flags);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // If the WPAD detection fails, allow the request to go direct connection.

-  SetProxyInformation();

-

-  // The purpose of the status callback is informational only.

-  HttpClient::StatusCallback old_callback =

-      http_client_->SetStatusCallback(request_state_->request_handle,

-                                      &SimpleRequest::StatusCallback,

-                                      WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS);

-  // No previous callback should be there for this handle or the callback

-  // could not be installed, for example, when the request handle has been

-  // canceled already.

-  const HttpClient::StatusCallback kInvalidStatusCallback =

-      reinterpret_cast<HttpClient::StatusCallback>(

-          WINHTTP_INVALID_STATUS_CALLBACK);

-  ASSERT1(old_callback == NULL ||

-          old_callback == kInvalidStatusCallback);

-

-  // Up to this point nothing has been sent over the wire.

-  // Second chance to see if it is canceled.

-  if (is_canceled_) {

-    return OMAHA_NET_E_REQUEST_CANCELLED;

-  }

-

-  int proxy_retry_count = 0;

-  int max_proxy_retries = 1;

-  CString username;

-  CString password;

-

-  bool done = false;

-  while (!done) {

-    uint32& request_scheme = request_state_->proxy_authentication_scheme;

-    if (request_scheme) {

-      NET_LOG(L3, (_T("[SR::DoSend][auth_scheme][%d]"), request_scheme));

-      http_client_->SetCredentials(request_state_->request_handle,

-                                   WINHTTP_AUTH_TARGET_PROXY,

-                                   request_scheme,

-                                   username, password);

-    }

-

-    size_t bytes_to_send = request_buffer_length_;

-    hr = http_client_->SendRequest(request_state_->request_handle,

-                                   NULL,

-                                   0,

-                                   request_buffer_,

-                                   bytes_to_send,

-                                   bytes_to_send);

-    if (FAILED(hr)) {

-      return hr;

-    }

-    NET_LOG(L3, (_T("[SimpleRequest::DoSend][request sent]")));

-

-    hr = http_client_->ReceiveResponse(request_state_->request_handle);

-#if DEBUG

-    LogResponseHeaders();

-#endif

-    if (hr == ERROR_WINHTTP_RESEND_REQUEST) {

-      // Resend the request if needed, likely because the authentication

-      // scheme requires many transactions on the same handle.

-      continue;

-    } else if (FAILED(hr)) {

-      return hr;

-    }

-

-    hr = http_client_->QueryHeadersInt(request_state_->request_handle,

-                                       WINHTTP_QUERY_STATUS_CODE,

-                                       NULL,

-                                       &request_state_->http_status_code,

-                                       NULL);

-    if (FAILED(hr)) {

-      return hr;

-    }

-    if (request_state_->http_status_code < HTTP_STATUS_FIRST ||

-        request_state_->http_status_code > HTTP_STATUS_LAST) {

-      return E_FAIL;

-    }

-

-    switch (request_state_->http_status_code) {

-      case HTTP_STATUS_DENIED:

-        // 401 responses are not supported. Omaha does not have to authenticate

-        // to our backend.

-        done = true;

-        break;

-

-      case HTTP_STATUS_PROXY_AUTH_REQ: {

-        NET_LOG(L2, (_T("[http proxy requires authentication]")));

-        ++proxy_retry_count;

-        if (proxy_retry_count > max_proxy_retries) {

-          // If we get multiple 407s in a row then we are done. It does not make

-          // sense to retry further.

-          done = true;

-          break;

-        }

-        if (!request_scheme) {

-          uint32 supported_schemes(0), first_scheme(0), auth_target(0);

-          hr = http_client_->QueryAuthSchemes(request_state_->request_handle,

-                                              &supported_schemes,

-                                              &first_scheme,

-                                              &auth_target);

-          if (FAILED(hr)) {

-            return hr;

-          }

-          ASSERT1(auth_target == WINHTTP_AUTH_TARGET_PROXY);

-          request_scheme = ChooseProxyAuthScheme(supported_schemes);

-          ASSERT1(request_scheme);

-          NET_LOG(L3, (_T("[SR::DoSend][Auth scheme][%d]"), request_scheme));

-          if (request_scheme == WINHTTP_AUTH_SCHEME_NEGOTIATE ||

-              request_scheme == WINHTTP_AUTH_SCHEME_NTLM) {

-            // Increases the retry count. Tries to do an autologon at first, and

-            // if that fails, will call GetProxyCredentials below.

-            ++max_proxy_retries;

-            break;

-          }

-        }

-

-        uint32 auth_scheme = UNKNOWN_AUTH_SCHEME;

-        // May prompt the user for credentials, or get cached credentials.

-        NetworkConfig& network_config = NetworkConfig::Instance();

-        if (!network_config.GetProxyCredentials(true,

-                                                false,

-                                                request_state_->proxy,

-                                                is_https,

-                                                &username,

-                                                &password,

-                                                &auth_scheme)) {

-          NET_LOG(LE, (_T("[SimpleRequest::DoSend][GetProxyCreds failed]")));

-          done = true;

-          break;

-        }

-        if (auth_scheme != UNKNOWN_AUTH_SCHEME) {

-          // Uses the known scheme that was successful previously.

-          request_scheme = auth_scheme;

-        }

-        break;

-      }

-

-      default:

-        // We got some kind of response. If we have a valid username, we

-        // record the auth scheme with the NetworkConfig, so it can be cached

-        // for future use within this process.

-        if (!username.IsEmpty()) {

-          VERIFY1(SUCCEEDED(NetworkConfig::Instance().SetProxyAuthScheme(

-              request_state_->proxy, is_https, request_scheme)));

-        }

-        done = true;

-        break;

-    }

-  }

-

-  // In the case of a "204 No Content" response, WinHttp blocks when

-  // querying or reading the available data. According to the RFC,

-  // the 204 response must not include a message-body, and thus is always

-  // terminated by the first empty line after the header fields.

-  // It appears WinHttp does not internally handles the 204 response.If this,

-  // condition is not handled here explicitly, WinHttp will timeout when

-  // waiting for the data instead of returning right away.

-  if (request_state_->http_status_code == HTTP_STATUS_NO_CONTENT) {

-    return S_OK;

-  }

-

-  http_client_->QueryHeadersInt(request_state_->request_handle,

-                                WINHTTP_QUERY_CONTENT_LENGTH,

-                                WINHTTP_HEADER_NAME_BY_INDEX,

-                                &request_state_->content_length,

-                                WINHTTP_NO_HEADER_INDEX);

-

-  // Read the remaining bytes of the body. If we have a file to save the

-  // response into, create the file.

-  // TODO(omaha): we should attempt to cleanup the file only if we

-  // created it in the first place.

-  ScopeGuard delete_file_guard = MakeGuard(::DeleteFile, filename_);

-  scoped_hfile file_handle;

-  if (!filename_.IsEmpty()) {

-    reset(file_handle, ::CreateFile(filename_, GENERIC_WRITE, 0, NULL,

-                                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,

-                                    NULL));

-    if (!file_handle) {

-      return HRESULTFromLastError();

-    }

-  }

-

-  const bool is_http_success =

-      request_state_->http_status_code == HTTP_STATUS_OK ||

-      request_state_->http_status_code == HTTP_STATUS_PARTIAL_CONTENT;

-

-  std::vector<uint8> buffer;

-  do  {

-    DWORD bytes_available(0);

-    http_client_->QueryDataAvailable(request_state_->request_handle,

-                                     &bytes_available);

-    buffer.resize(1 + bytes_available);

-    hr = http_client_->ReadData(request_state_->request_handle,

-                                &buffer.front(),

-                                buffer.size(),

-                                &bytes_available);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    request_state_->current_bytes += bytes_available;

-    if (request_state_->content_length) {

-      ASSERT1(request_state_->current_bytes <= request_state_->content_length);

-    }

-

-    // The callback is called only for 200 or 206 http codes.

-    if (callback_ && request_state_->content_length && is_http_success) {

-      callback_->OnProgress(request_state_->current_bytes,

-                            request_state_->content_length,

-                            WINHTTP_CALLBACK_STATUS_READ_COMPLETE,

-                            NULL);

-    }

-

-    buffer.resize(bytes_available);

-    if (!buffer.empty()) {

-      if (!filename_.IsEmpty()) {

-        DWORD num_bytes(0);

-        if (!::WriteFile(get(file_handle),

-                         reinterpret_cast<const char*>(&buffer.front()),

-                         buffer.size(), &num_bytes, NULL)) {

-          return HRESULTFromLastError();

-        }

-        ASSERT1(num_bytes == buffer.size());

-      } else {

-        request_state_->response.insert(request_state_->response.end(),

-                                        buffer.begin(),

-                                        buffer.end());

-      }

-    }

-  } while (!buffer.empty());

-

-  NET_LOG(L3, (_T("[bytes downloaded %d]"), request_state_->current_bytes));

-  if (file_handle) {

-    // All bytes must be written to the file in the file download case.

-    ASSERT1(::SetFilePointer(get(file_handle), 0, NULL, FILE_CURRENT) ==

-            static_cast<DWORD>(request_state_->current_bytes));

-  }

-

-  delete_file_guard.Dismiss();

-  return S_OK;

-}

-

-std::vector<uint8> SimpleRequest::GetResponse() const {

-  return request_state_.get() ? request_state_->response :

-                                std::vector<uint8>();

-}

-

-HRESULT SimpleRequest::QueryHeadersString(uint32 info_level,

-                                          const TCHAR* name,

-                                          CString* value) const {

-  // Name can be null when the info_level specifies the header to query.

-  ASSERT1(value);

-  if (!http_client_.get() ||

-      !request_state_.get() ||

-      !request_state_->request_handle) {

-    return E_UNEXPECTED;

-  }

-

-  return http_client_->QueryHeadersString(request_state_->request_handle,

-                                          info_level,

-                                          name,

-                                          value,

-                                          WINHTTP_NO_HEADER_INDEX);

-}

-

-CString SimpleRequest::GetResponseHeaders() const {

-  CString response_headers;

-  if (http_client_.get() &&

-      request_state_.get() &&

-      request_state_->request_handle) {

-    CString response_headers;

-    if (SUCCEEDED(http_client_->QueryHeadersString(

-        request_state_->request_handle,

-        WINHTTP_QUERY_RAW_HEADERS_CRLF,

-        WINHTTP_HEADER_NAME_BY_INDEX,

-        &response_headers,

-        WINHTTP_NO_HEADER_INDEX))) {

-      return response_headers;

-    }

-  }

-  return CString();

-}

-

-

-uint32 SimpleRequest::ChooseProxyAuthScheme(uint32 supported_schemes) {

-  // It is the server's responsibility only to accept

-  // authentication schemes that provide a sufficient level

-  // of security to protect the server's resources.

-  //

-  // The client is also obligated only to use an authentication

-  // scheme that adequately protects its username and password.

-  //

-  // TODO(omaha): remove Basic authentication because Basic authentication

-  // exposes the client's username and password to anyone monitoring

-  // the connection. This option is here for Fiddler testing purposes.

-

-  uint32 auth_schemes[] = {

-    WINHTTP_AUTH_SCHEME_NEGOTIATE,

-    WINHTTP_AUTH_SCHEME_NTLM,

-    WINHTTP_AUTH_SCHEME_DIGEST,

-    WINHTTP_AUTH_SCHEME_BASIC,

-  };

-  for (int i = 0; i < arraysize(auth_schemes); ++i) {

-    if (supported_schemes & auth_schemes[i]) {

-      return auth_schemes[i];

-    }

-  }

-

-  return 0;

-}

-

-void SimpleRequest::SetProxyInformation() {

-  bool uses_proxy = false;

-  CString proxy, proxy_bypass;

-  int access_type = NetworkConfig::GetAccessType(network_config_);

-  if (access_type == WINHTTP_ACCESS_TYPE_AUTO_DETECT) {

-    HttpClient::ProxyInfo proxy_info = {0};

-    HRESULT hr = NetworkConfig::Instance().GetProxyForUrl(

-        url_,

-        network_config_.auto_config_url,

-        &proxy_info);

-    if (SUCCEEDED(hr)) {

-      // The result of proxy auto-detection could be that either a proxy is

-      // found, or direct connection is allowed for the specified url.

-      ASSERT(proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY ||

-             proxy_info.access_type == WINHTTP_ACCESS_TYPE_NO_PROXY,

-             (_T("[Unexpected access_type][%d]"), proxy_info.access_type));

-

-      uses_proxy = proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY;

-

-      proxy = proxy_info.proxy;

-      proxy_bypass = proxy_info.proxy_bypass;

-

-      ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy));

-      ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy_bypass));

-    } else {

-      ASSERT1(!uses_proxy);

-      NET_LOG(LW, (_T("[GetProxyForUrl failed][0x%08x]"), hr));

-    }

-  } else if (access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {

-    uses_proxy = true;

-    proxy = network_config_.proxy;

-    proxy_bypass = network_config_.proxy_bypass;

-  }

-

-  // If a proxy is going to be used, modify the state of the object and

-  // set the proxy information on the request handle.

-  if (uses_proxy) {

-    ASSERT1(!proxy.IsEmpty());

-

-    request_state_->proxy        = proxy;

-    request_state_->proxy_bypass = proxy_bypass;

-

-    HttpClient::ProxyInfo proxy_info = {0};

-    proxy_info.access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;

-    proxy_info.proxy = request_state_->proxy;

-    proxy_info.proxy_bypass = request_state_->proxy_bypass;

-

-    NET_LOG(L3, (_T("[using proxy %s]"), proxy_info.proxy));

-    VERIFY1(SUCCEEDED(http_client_->SetOption(request_state_->request_handle,

-                                              WINHTTP_OPTION_PROXY,

-                                              &proxy_info,

-                                              sizeof(proxy_info))));

-  }

-}

-

-void SimpleRequest::LogResponseHeaders() {

-  CString response_headers;

-  http_client_->QueryHeadersString(request_state_->request_handle,

-                                   WINHTTP_QUERY_RAW_HEADERS_CRLF,

-                                   WINHTTP_HEADER_NAME_BY_INDEX,

-                                   &response_headers,

-                                   WINHTTP_NO_HEADER_INDEX);

-  NET_LOG(L3, (_T("[response headers...]\r\n%s"), response_headers));

-}

-

-void __stdcall SimpleRequest::StatusCallback(HINTERNET handle,

-                                             uint32 context,

-                                             uint32 status,

-                                             void* info,

-                                             size_t info_len) {

-  UNREFERENCED_PARAMETER(context);

-

-  CString status_string;

-  CString info_string;

-  switch (status) {

-    case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME:

-      status_string = _T("resolving");

-      info_string.SetString(static_cast<TCHAR*>(info), info_len);  // host name

-      break;

-    case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED:

-      status_string = _T("resolved");

-      info_string.SetString(static_cast<TCHAR*>(info), info_len);  // host ip

-      break;

-    case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER:

-      status_string = _T("connecting");

-      info_string.SetString(static_cast<TCHAR*>(info), info_len);  // host ip

-      break;

-    case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER:

-      status_string = _T("connected");

-      info_string.SetString(static_cast<TCHAR*>(info), info_len);  // host ip

-      break;

-    case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:

-      status_string = _T("sending");

-      break;

-    case WINHTTP_CALLBACK_STATUS_REQUEST_SENT:

-      status_string = _T("sent");

-      break;

-    case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE:

-      status_string = _T("receiving");

-      break;

-    case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED:

-      status_string = _T("received");

-      break;

-    case WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION:

-      status_string = _T("closing");

-      break;

-    case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED:

-      status_string = _T("closed");

-      break;

-    case WINHTTP_CALLBACK_STATUS_REDIRECT:

-      status_string = _T("redirect");

-      info_string.SetString(static_cast<TCHAR*>(info), info_len);  // url

-      break;

-    default:

-      break;

-  }

-  CString log_line;

-  log_line.AppendFormat(_T("[HttpClient::StatusCallback][0x%08x]"), handle);

-  if (!status_string.IsEmpty()) {

-    log_line.AppendFormat(_T("[%s]"), status_string);

-  } else {

-    log_line.AppendFormat(_T("[0x%08x]"), status);

-  }

-  if (!info_string.IsEmpty()) {

-    log_line.AppendFormat(_T("[%s]"), info_string);

-  }

-  NET_LOG(L3, (_T("%s"), log_line));

-}

-

-void SimpleRequest::CloseHandles(TransientRequestState* request_state) {

-  if (request_state) {

-    if (request_state->request_handle) {

-      http_client_->Close(request_state->request_handle);

-      request_state->request_handle = NULL;

-    }

-    if (request_state->connection_handle) {

-      http_client_->Close(request_state->connection_handle);

-      request_state->connection_handle = NULL;

-    }

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// The implementation does not allow concurrent calls on the same object but
+// it allows calling SimpleRequest::Cancel in order to stop an ongoing request.
+// The transient state of the request is maintained by request_state_.
+// The state is created by SimpleRequest::Send and it is destroyed by
+// SimpleRequest::Close. The only concurrent access to the object state can
+// happened during calling SimpleRequest::Cancel. Cancel closes the
+// connection and the request handles. This makes any of the WinHttp calls
+// on these handles fail and SimpleRequest::Send return to the caller.
+
+#include "omaha/net/simple_request.h"
+
+#include <atlconv.h>
+#include <climits>
+#include <vector>
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/string.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/proxy_auth.h"
+
+namespace omaha {
+
+SimpleRequest::SimpleRequest()
+    : request_buffer_(NULL),
+      request_buffer_length_(0),
+      is_canceled_(false),
+      session_handle_(NULL),
+      low_priority_(false),
+      callback_(NULL) {
+  user_agent_.Format(_T("%s;winhttp"), NetworkConfig::GetUserAgent());
+  http_client_.reset(CreateHttpClient());
+}
+
+SimpleRequest::~SimpleRequest() {
+  Close();
+  callback_ = NULL;
+}
+
+HRESULT SimpleRequest::Close() {
+  NET_LOG(L3, (_T("[SimpleRequest::Close]")));
+  __mutexBlock(lock_) {
+    CloseHandles(request_state_.get());
+    request_state_.reset();
+  }
+  return S_OK;
+}
+
+HRESULT SimpleRequest::Cancel() {
+  NET_LOG(L3, (_T("[SimpleRequest::Cancel]")));
+  __mutexBlock(lock_) {
+    is_canceled_ = true;
+    CloseHandles(request_state_.get());
+  }
+  return S_OK;
+}
+
+HRESULT SimpleRequest::Send() {
+  NET_LOG(L3, (_T("[SimpleRequest::Send][%s]"), url_));
+
+  ASSERT1(!url_.IsEmpty());
+  if (!session_handle_) {
+    // Winhttp could not be loaded.
+    NET_LOG(LW, (_T("[SimpleRequest: session_handle_ is NULL.]")));
+    // TODO(omaha): This makes an assumption that only WinHttp is
+    // supported by the network code.
+    return OMAHA_NET_E_WINHTTP_NOT_AVAILABLE;
+  }
+
+  __mutexBlock(lock_) {
+    CloseHandles(request_state_.get());
+    request_state_.reset(new TransientRequestState);
+  }
+
+  HRESULT hr = DoSend();
+  int status_code(GetHttpStatusCode());
+  if (hr == HRESULT_FROM_WIN32(ERROR_WINHTTP_OPERATION_CANCELLED) ||
+      is_canceled_) {
+    hr = OMAHA_NET_E_REQUEST_CANCELLED;
+  }
+  NET_LOG(L3, (_T("[SimpleRequest::Send][0x%08x][%d]"), hr, status_code));
+  return hr;
+}
+
+HRESULT SimpleRequest::DoSend() {
+  // First chance to see if it is canceled.
+  if (is_canceled_) {
+    return OMAHA_NET_E_REQUEST_CANCELLED;
+  }
+
+  HRESULT hr = http_client_->Initialize();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = http_client_->CrackUrl(url_,
+                              ICU_DECODE,
+                              &request_state_->scheme,
+                              &request_state_->server,
+                              &request_state_->port,
+                              &request_state_->url_path,
+                              NULL);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(!request_state_->scheme.CompareNoCase(kHttpProtoScheme) ||
+          !request_state_->scheme.CompareNoCase(kHttpsProtoScheme));
+
+  hr = http_client_->Connect(session_handle_,
+                             request_state_->server,
+                             request_state_->port,
+                             &request_state_->connection_handle);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // TODO(omaha): figure out the accept types.
+  //              figure out more flags.
+  DWORD flags = WINHTTP_FLAG_REFRESH;
+  bool is_https = false;
+  if (request_state_->scheme == kHttpsProtoScheme) {
+    is_https = true;
+    flags |= WINHTTP_FLAG_SECURE;
+  }
+  const TCHAR* verb = IsPostRequest() ? _T("POST") : _T("GET");
+  hr = http_client_->OpenRequest(request_state_->connection_handle,
+                                 verb, request_state_->url_path,
+                                 NULL, WINHTTP_NO_REFERER,
+                                 WINHTTP_DEFAULT_ACCEPT_TYPES, flags,
+                                 &request_state_->request_handle);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Disable redirects for POST requests.
+  if (IsPostRequest()) {
+    VERIFY1(SUCCEEDED(http_client_->SetOptionInt(request_state_->request_handle,
+                                                 WINHTTP_OPTION_DISABLE_FEATURE,
+                                                 WINHTTP_DISABLE_REDIRECTS)));
+  }
+
+  additional_headers_.AppendFormat(_T("User-Agent: %s\r\n"), user_agent_);
+  uint32 header_flags = WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE;
+  hr = http_client_->AddRequestHeaders(request_state_->request_handle,
+                                       additional_headers_,
+                                       -1,
+                                       header_flags);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // If the WPAD detection fails, allow the request to go direct connection.
+  SetProxyInformation();
+
+  // The purpose of the status callback is informational only.
+  HttpClient::StatusCallback old_callback =
+      http_client_->SetStatusCallback(request_state_->request_handle,
+                                      &SimpleRequest::StatusCallback,
+                                      WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS);
+  // No previous callback should be there for this handle or the callback
+  // could not be installed, for example, when the request handle has been
+  // canceled already.
+  const HttpClient::StatusCallback kInvalidStatusCallback =
+      reinterpret_cast<HttpClient::StatusCallback>(
+          WINHTTP_INVALID_STATUS_CALLBACK);
+  ASSERT1(old_callback == NULL ||
+          old_callback == kInvalidStatusCallback);
+
+  // Up to this point nothing has been sent over the wire.
+  // Second chance to see if it is canceled.
+  if (is_canceled_) {
+    return OMAHA_NET_E_REQUEST_CANCELLED;
+  }
+
+  int proxy_retry_count = 0;
+  int max_proxy_retries = 1;
+  CString username;
+  CString password;
+
+  bool done = false;
+  while (!done) {
+    uint32& request_scheme = request_state_->proxy_authentication_scheme;
+    if (request_scheme) {
+      NET_LOG(L3, (_T("[SR::DoSend][auth_scheme][%d]"), request_scheme));
+      http_client_->SetCredentials(request_state_->request_handle,
+                                   WINHTTP_AUTH_TARGET_PROXY,
+                                   request_scheme,
+                                   username, password);
+    }
+
+    size_t bytes_to_send = request_buffer_length_;
+    hr = http_client_->SendRequest(request_state_->request_handle,
+                                   NULL,
+                                   0,
+                                   request_buffer_,
+                                   bytes_to_send,
+                                   bytes_to_send);
+    if (FAILED(hr)) {
+      return hr;
+    }
+    NET_LOG(L3, (_T("[SimpleRequest::DoSend][request sent]")));
+
+    hr = http_client_->ReceiveResponse(request_state_->request_handle);
+#if DEBUG
+    LogResponseHeaders();
+#endif
+    if (hr == ERROR_WINHTTP_RESEND_REQUEST) {
+      // Resend the request if needed, likely because the authentication
+      // scheme requires many transactions on the same handle.
+      continue;
+    } else if (FAILED(hr)) {
+      return hr;
+    }
+
+    hr = http_client_->QueryHeadersInt(request_state_->request_handle,
+                                       WINHTTP_QUERY_STATUS_CODE,
+                                       NULL,
+                                       &request_state_->http_status_code,
+                                       NULL);
+    if (FAILED(hr)) {
+      return hr;
+    }
+    if (request_state_->http_status_code < HTTP_STATUS_FIRST ||
+        request_state_->http_status_code > HTTP_STATUS_LAST) {
+      return E_FAIL;
+    }
+
+    switch (request_state_->http_status_code) {
+      case HTTP_STATUS_DENIED:
+        // 401 responses are not supported. Omaha does not have to authenticate
+        // to our backend.
+        done = true;
+        break;
+
+      case HTTP_STATUS_PROXY_AUTH_REQ: {
+        NET_LOG(L2, (_T("[http proxy requires authentication]")));
+        ++proxy_retry_count;
+        if (proxy_retry_count > max_proxy_retries) {
+          // If we get multiple 407s in a row then we are done. It does not make
+          // sense to retry further.
+          done = true;
+          break;
+        }
+        if (!request_scheme) {
+          uint32 supported_schemes(0), first_scheme(0), auth_target(0);
+          hr = http_client_->QueryAuthSchemes(request_state_->request_handle,
+                                              &supported_schemes,
+                                              &first_scheme,
+                                              &auth_target);
+          if (FAILED(hr)) {
+            return hr;
+          }
+          ASSERT1(auth_target == WINHTTP_AUTH_TARGET_PROXY);
+          request_scheme = ChooseProxyAuthScheme(supported_schemes);
+          ASSERT1(request_scheme);
+          NET_LOG(L3, (_T("[SR::DoSend][Auth scheme][%d]"), request_scheme));
+          if (request_scheme == WINHTTP_AUTH_SCHEME_NEGOTIATE ||
+              request_scheme == WINHTTP_AUTH_SCHEME_NTLM) {
+            // Increases the retry count. Tries to do an autologon at first, and
+            // if that fails, will call GetProxyCredentials below.
+            ++max_proxy_retries;
+            break;
+          }
+        }
+
+        uint32 auth_scheme = UNKNOWN_AUTH_SCHEME;
+        // May prompt the user for credentials, or get cached credentials.
+        NetworkConfig& network_config = NetworkConfig::Instance();
+        if (!network_config.GetProxyCredentials(true,
+                                                false,
+                                                request_state_->proxy,
+                                                is_https,
+                                                &username,
+                                                &password,
+                                                &auth_scheme)) {
+          NET_LOG(LE, (_T("[SimpleRequest::DoSend][GetProxyCreds failed]")));
+          done = true;
+          break;
+        }
+        if (auth_scheme != UNKNOWN_AUTH_SCHEME) {
+          // Uses the known scheme that was successful previously.
+          request_scheme = auth_scheme;
+        }
+        break;
+      }
+
+      default:
+        // We got some kind of response. If we have a valid username, we
+        // record the auth scheme with the NetworkConfig, so it can be cached
+        // for future use within this process.
+        if (!username.IsEmpty()) {
+          VERIFY1(SUCCEEDED(NetworkConfig::Instance().SetProxyAuthScheme(
+              request_state_->proxy, is_https, request_scheme)));
+        }
+        done = true;
+        break;
+    }
+  }
+
+  // In the case of a "204 No Content" response, WinHttp blocks when
+  // querying or reading the available data. According to the RFC,
+  // the 204 response must not include a message-body, and thus is always
+  // terminated by the first empty line after the header fields.
+  // It appears WinHttp does not internally handles the 204 response.If this,
+  // condition is not handled here explicitly, WinHttp will timeout when
+  // waiting for the data instead of returning right away.
+  if (request_state_->http_status_code == HTTP_STATUS_NO_CONTENT) {
+    return S_OK;
+  }
+
+  http_client_->QueryHeadersInt(request_state_->request_handle,
+                                WINHTTP_QUERY_CONTENT_LENGTH,
+                                WINHTTP_HEADER_NAME_BY_INDEX,
+                                &request_state_->content_length,
+                                WINHTTP_NO_HEADER_INDEX);
+
+  // Read the remaining bytes of the body. If we have a file to save the
+  // response into, create the file.
+  // TODO(omaha): we should attempt to cleanup the file only if we
+  // created it in the first place.
+  ScopeGuard delete_file_guard = MakeGuard(::DeleteFile, filename_);
+  scoped_hfile file_handle;
+  if (!filename_.IsEmpty()) {
+    reset(file_handle, ::CreateFile(filename_, GENERIC_WRITE, 0, NULL,
+                                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+                                    NULL));
+    if (!file_handle) {
+      return HRESULTFromLastError();
+    }
+  }
+
+  const bool is_http_success =
+      request_state_->http_status_code == HTTP_STATUS_OK ||
+      request_state_->http_status_code == HTTP_STATUS_PARTIAL_CONTENT;
+
+  std::vector<uint8> buffer;
+  do  {
+    DWORD bytes_available(0);
+    http_client_->QueryDataAvailable(request_state_->request_handle,
+                                     &bytes_available);
+    buffer.resize(1 + bytes_available);
+    hr = http_client_->ReadData(request_state_->request_handle,
+                                &buffer.front(),
+                                buffer.size(),
+                                &bytes_available);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    request_state_->current_bytes += bytes_available;
+    if (request_state_->content_length) {
+      ASSERT1(request_state_->current_bytes <= request_state_->content_length);
+    }
+
+    // The callback is called only for 200 or 206 http codes.
+    if (callback_ && request_state_->content_length && is_http_success) {
+      callback_->OnProgress(request_state_->current_bytes,
+                            request_state_->content_length,
+                            WINHTTP_CALLBACK_STATUS_READ_COMPLETE,
+                            NULL);
+    }
+
+    buffer.resize(bytes_available);
+    if (!buffer.empty()) {
+      if (!filename_.IsEmpty()) {
+        DWORD num_bytes(0);
+        if (!::WriteFile(get(file_handle),
+                         reinterpret_cast<const char*>(&buffer.front()),
+                         buffer.size(), &num_bytes, NULL)) {
+          return HRESULTFromLastError();
+        }
+        ASSERT1(num_bytes == buffer.size());
+      } else {
+        request_state_->response.insert(request_state_->response.end(),
+                                        buffer.begin(),
+                                        buffer.end());
+      }
+    }
+  } while (!buffer.empty());
+
+  NET_LOG(L3, (_T("[bytes downloaded %d]"), request_state_->current_bytes));
+  if (file_handle) {
+    // All bytes must be written to the file in the file download case.
+    ASSERT1(::SetFilePointer(get(file_handle), 0, NULL, FILE_CURRENT) ==
+            static_cast<DWORD>(request_state_->current_bytes));
+  }
+
+  delete_file_guard.Dismiss();
+  return S_OK;
+}
+
+std::vector<uint8> SimpleRequest::GetResponse() const {
+  return request_state_.get() ? request_state_->response :
+                                std::vector<uint8>();
+}
+
+HRESULT SimpleRequest::QueryHeadersString(uint32 info_level,
+                                          const TCHAR* name,
+                                          CString* value) const {
+  // Name can be null when the info_level specifies the header to query.
+  ASSERT1(value);
+  if (!http_client_.get() ||
+      !request_state_.get() ||
+      !request_state_->request_handle) {
+    return E_UNEXPECTED;
+  }
+
+  return http_client_->QueryHeadersString(request_state_->request_handle,
+                                          info_level,
+                                          name,
+                                          value,
+                                          WINHTTP_NO_HEADER_INDEX);
+}
+
+CString SimpleRequest::GetResponseHeaders() const {
+  CString response_headers;
+  if (http_client_.get() &&
+      request_state_.get() &&
+      request_state_->request_handle) {
+    CString response_headers;
+    if (SUCCEEDED(http_client_->QueryHeadersString(
+        request_state_->request_handle,
+        WINHTTP_QUERY_RAW_HEADERS_CRLF,
+        WINHTTP_HEADER_NAME_BY_INDEX,
+        &response_headers,
+        WINHTTP_NO_HEADER_INDEX))) {
+      return response_headers;
+    }
+  }
+  return CString();
+}
+
+
+uint32 SimpleRequest::ChooseProxyAuthScheme(uint32 supported_schemes) {
+  // It is the server's responsibility only to accept
+  // authentication schemes that provide a sufficient level
+  // of security to protect the server's resources.
+  //
+  // The client is also obligated only to use an authentication
+  // scheme that adequately protects its username and password.
+  //
+  // TODO(omaha): remove Basic authentication because Basic authentication
+  // exposes the client's username and password to anyone monitoring
+  // the connection. This option is here for Fiddler testing purposes.
+
+  uint32 auth_schemes[] = {
+    WINHTTP_AUTH_SCHEME_NEGOTIATE,
+    WINHTTP_AUTH_SCHEME_NTLM,
+    WINHTTP_AUTH_SCHEME_DIGEST,
+    WINHTTP_AUTH_SCHEME_BASIC,
+  };
+  for (int i = 0; i < arraysize(auth_schemes); ++i) {
+    if (supported_schemes & auth_schemes[i]) {
+      return auth_schemes[i];
+    }
+  }
+
+  return 0;
+}
+
+void SimpleRequest::SetProxyInformation() {
+  bool uses_proxy = false;
+  CString proxy, proxy_bypass;
+  int access_type = NetworkConfig::GetAccessType(network_config_);
+  if (access_type == WINHTTP_ACCESS_TYPE_AUTO_DETECT) {
+    HttpClient::ProxyInfo proxy_info = {0};
+    HRESULT hr = NetworkConfig::Instance().GetProxyForUrl(
+        url_,
+        network_config_.auto_config_url,
+        &proxy_info);
+    if (SUCCEEDED(hr)) {
+      // The result of proxy auto-detection could be that either a proxy is
+      // found, or direct connection is allowed for the specified url.
+      ASSERT(proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY ||
+             proxy_info.access_type == WINHTTP_ACCESS_TYPE_NO_PROXY,
+             (_T("[Unexpected access_type][%d]"), proxy_info.access_type));
+
+      uses_proxy = proxy_info.access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+
+      proxy = proxy_info.proxy;
+      proxy_bypass = proxy_info.proxy_bypass;
+
+      ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy));
+      ::GlobalFree(const_cast<wchar_t*>(proxy_info.proxy_bypass));
+    } else {
+      ASSERT1(!uses_proxy);
+      NET_LOG(LW, (_T("[GetProxyForUrl failed][0x%08x]"), hr));
+    }
+  } else if (access_type == WINHTTP_ACCESS_TYPE_NAMED_PROXY) {
+    uses_proxy = true;
+    proxy = network_config_.proxy;
+    proxy_bypass = network_config_.proxy_bypass;
+  }
+
+  // If a proxy is going to be used, modify the state of the object and
+  // set the proxy information on the request handle.
+  if (uses_proxy) {
+    ASSERT1(!proxy.IsEmpty());
+
+    request_state_->proxy        = proxy;
+    request_state_->proxy_bypass = proxy_bypass;
+
+    HttpClient::ProxyInfo proxy_info = {0};
+    proxy_info.access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+    proxy_info.proxy = request_state_->proxy;
+    proxy_info.proxy_bypass = request_state_->proxy_bypass;
+
+    NET_LOG(L3, (_T("[using proxy %s]"), proxy_info.proxy));
+    VERIFY1(SUCCEEDED(http_client_->SetOption(request_state_->request_handle,
+                                              WINHTTP_OPTION_PROXY,
+                                              &proxy_info,
+                                              sizeof(proxy_info))));
+  }
+}
+
+void SimpleRequest::LogResponseHeaders() {
+  CString response_headers;
+  http_client_->QueryHeadersString(request_state_->request_handle,
+                                   WINHTTP_QUERY_RAW_HEADERS_CRLF,
+                                   WINHTTP_HEADER_NAME_BY_INDEX,
+                                   &response_headers,
+                                   WINHTTP_NO_HEADER_INDEX);
+  NET_LOG(L3, (_T("[response headers...]\r\n%s"), response_headers));
+}
+
+void __stdcall SimpleRequest::StatusCallback(HINTERNET handle,
+                                             uint32 context,
+                                             uint32 status,
+                                             void* info,
+                                             size_t info_len) {
+  UNREFERENCED_PARAMETER(context);
+
+  CString status_string;
+  CString info_string;
+  switch (status) {
+    case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME:
+      status_string = _T("resolving");
+      info_string.SetString(static_cast<TCHAR*>(info), info_len);  // host name
+      break;
+    case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED:
+      status_string = _T("resolved");
+      info_string.SetString(static_cast<TCHAR*>(info), info_len);  // host ip
+      break;
+    case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER:
+      status_string = _T("connecting");
+      info_string.SetString(static_cast<TCHAR*>(info), info_len);  // host ip
+      break;
+    case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER:
+      status_string = _T("connected");
+      info_string.SetString(static_cast<TCHAR*>(info), info_len);  // host ip
+      break;
+    case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
+      status_string = _T("sending");
+      break;
+    case WINHTTP_CALLBACK_STATUS_REQUEST_SENT:
+      status_string = _T("sent");
+      break;
+    case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE:
+      status_string = _T("receiving");
+      break;
+    case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED:
+      status_string = _T("received");
+      break;
+    case WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION:
+      status_string = _T("closing");
+      break;
+    case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED:
+      status_string = _T("closed");
+      break;
+    case WINHTTP_CALLBACK_STATUS_REDIRECT:
+      status_string = _T("redirect");
+      info_string.SetString(static_cast<TCHAR*>(info), info_len);  // url
+      break;
+    default:
+      break;
+  }
+  CString log_line;
+  log_line.AppendFormat(_T("[HttpClient::StatusCallback][0x%08x]"), handle);
+  if (!status_string.IsEmpty()) {
+    log_line.AppendFormat(_T("[%s]"), status_string);
+  } else {
+    log_line.AppendFormat(_T("[0x%08x]"), status);
+  }
+  if (!info_string.IsEmpty()) {
+    log_line.AppendFormat(_T("[%s]"), info_string);
+  }
+  NET_LOG(L3, (_T("%s"), log_line));
+}
+
+void SimpleRequest::CloseHandles(TransientRequestState* request_state) {
+  if (request_state) {
+    if (request_state->request_handle) {
+      http_client_->Close(request_state->request_handle);
+      request_state->request_handle = NULL;
+    }
+    if (request_state->connection_handle) {
+      http_client_->Close(request_state->connection_handle);
+      request_state->connection_handle = NULL;
+    }
+  }
+}
+
+}  // namespace omaha
+
diff --git a/net/simple_request.h b/net/simple_request.h
index 0d3be83..374b0b9 100644
--- a/net/simple_request.h
+++ b/net/simple_request.h
@@ -1,176 +1,176 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// SimpleRequest provides for http transactions using WinHttp/WinInet.

-//

-// TODO(omaha): the class interface is not stable yet, as a few more

-// getters and setters are still needed.

-//

-// TODO(omaha): receiving a response into a file is not implemented yet.

-

-#ifndef OMAHA_NET_SIMPLE_REQUEST_H__

-#define OMAHA_NET_SIMPLE_REQUEST_H__

-

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/http_request.h"

-#include "omaha/net/network_config.h"

-

-namespace omaha {

-

-class SimpleRequest : public HttpRequestInterface {

- public:

-  SimpleRequest();

-  virtual ~SimpleRequest();

-

-  virtual HRESULT Close();

-

-  virtual HRESULT Send();

-

-  virtual HRESULT Cancel();

-

-  virtual std::vector<uint8> GetResponse() const;

-

-  virtual int GetHttpStatusCode() const {

-    return request_state_.get() ? request_state_->http_status_code : 0;

-  }

-

-  virtual HRESULT QueryHeadersString(uint32 info_level,

-                                     const TCHAR* name,

-                                     CString* value) const;

-

-  virtual CString GetResponseHeaders() const;

-

-  virtual CString ToString() const { return _T("WinHTTP"); }

-

-  virtual void set_session_handle(HINTERNET session_handle) {

-    session_handle_ = session_handle;

-  }

-

-  virtual void set_url(const CString& url) { url_ = url; }

-

-  virtual void set_request_buffer(const void* buffer, size_t buffer_length) {

-    request_buffer_ = buffer;

-    request_buffer_length_ = buffer_length;

-  }

-

-  virtual void set_network_configuration(const Config& network_config) {

-    network_config_ = network_config;

-  }

-

-  // Sets the filename to receive the response instead of the memory buffer.

-  virtual void set_filename(const CString& filename) { filename_ = filename; }

-

-  virtual void set_low_priority(bool low_priority) {

-    low_priority_ = low_priority;

-  }

-

-  virtual void set_callback(NetworkRequestCallback* callback) {

-    callback_ = callback;

-  }

-

-  virtual void set_additional_headers(const CString& additional_headers) {

-    additional_headers_ = additional_headers;

-  }

-

-  virtual CString user_agent() const { return user_agent_; }

-

-  virtual void set_user_agent(const CString& user_agent) {

-    user_agent_ = user_agent;

-  }

-

- private:

-  HRESULT DoSend();

-

-  void LogResponseHeaders();

-

-  // Sets proxy information for the request.

-  void SetProxyInformation();

-

-  struct TransientRequestState;

-  void CloseHandles(TransientRequestState* transient_request_state);

-

-  static uint32 ChooseProxyAuthScheme(uint32 supported_schemes);

-

-  static void __stdcall StatusCallback(HINTERNET handle,

-                                       uint32 context,

-                                       uint32 status,

-                                       void* info,

-                                       uint32 info_len);

-

-  // Returns true if the request is a POST request, in other words, if there

-  // is a request buffer to be sent to the server.

-  bool IsPostRequest() const { return request_buffer_ != NULL; }

-

-  // Holds the transient state corresponding to a single http request. We

-  // prefer to isolate the state of a request to avoid dirty state.

-  struct TransientRequestState {

-    TransientRequestState()

-        : port(0),

-          http_status_code(0),

-          proxy_authentication_scheme(0),

-          content_length(0),

-          current_bytes(0),

-          connection_handle(NULL),

-          request_handle(NULL) {}

-    ~TransientRequestState() {

-      ASSERT1(connection_handle == NULL);

-      ASSERT1(request_handle == NULL);

-    }

-

-    CString scheme;

-    CString server;

-    int     port;

-    CString url_path;

-

-    std::vector<uint8> response;

-    int http_status_code;

-    uint32 proxy_authentication_scheme;

-    CString proxy;

-    CString proxy_bypass;

-    int content_length;

-    int current_bytes;

-

-    HINTERNET connection_handle;

-    HINTERNET request_handle;

-  };

-

-  LLock lock_;

-  volatile bool is_canceled_;

-  HINTERNET session_handle_;  // Not owned by this class.

-  CString url_;

-  CString filename_;

-  const void* request_buffer_;          // Contains the request body for POST.

-  size_t      request_buffer_length_;   // Length of the request body.

-  CString additional_headers_;

-  CString user_agent_;

-  Config network_config_;

-  bool low_priority_;

-  NetworkRequestCallback* callback_;

-  scoped_ptr<HttpClient> http_client_;

-  scoped_ptr<TransientRequestState> request_state_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(SimpleRequest);

-};

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_SIMPLE_REQUEST_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// SimpleRequest provides for http transactions using WinHttp/WinInet.
+//
+// TODO(omaha): the class interface is not stable yet, as a few more
+// getters and setters are still needed.
+//
+// TODO(omaha): receiving a response into a file is not implemented yet.
+
+#ifndef OMAHA_NET_SIMPLE_REQUEST_H__
+#define OMAHA_NET_SIMPLE_REQUEST_H__
+
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/http_request.h"
+#include "omaha/net/network_config.h"
+
+namespace omaha {
+
+class SimpleRequest : public HttpRequestInterface {
+ public:
+  SimpleRequest();
+  virtual ~SimpleRequest();
+
+  virtual HRESULT Close();
+
+  virtual HRESULT Send();
+
+  virtual HRESULT Cancel();
+
+  virtual std::vector<uint8> GetResponse() const;
+
+  virtual int GetHttpStatusCode() const {
+    return request_state_.get() ? request_state_->http_status_code : 0;
+  }
+
+  virtual HRESULT QueryHeadersString(uint32 info_level,
+                                     const TCHAR* name,
+                                     CString* value) const;
+
+  virtual CString GetResponseHeaders() const;
+
+  virtual CString ToString() const { return _T("WinHTTP"); }
+
+  virtual void set_session_handle(HINTERNET session_handle) {
+    session_handle_ = session_handle;
+  }
+
+  virtual void set_url(const CString& url) { url_ = url; }
+
+  virtual void set_request_buffer(const void* buffer, size_t buffer_length) {
+    request_buffer_ = buffer;
+    request_buffer_length_ = buffer_length;
+  }
+
+  virtual void set_network_configuration(const Config& network_config) {
+    network_config_ = network_config;
+  }
+
+  // Sets the filename to receive the response instead of the memory buffer.
+  virtual void set_filename(const CString& filename) { filename_ = filename; }
+
+  virtual void set_low_priority(bool low_priority) {
+    low_priority_ = low_priority;
+  }
+
+  virtual void set_callback(NetworkRequestCallback* callback) {
+    callback_ = callback;
+  }
+
+  virtual void set_additional_headers(const CString& additional_headers) {
+    additional_headers_ = additional_headers;
+  }
+
+  virtual CString user_agent() const { return user_agent_; }
+
+  virtual void set_user_agent(const CString& user_agent) {
+    user_agent_ = user_agent;
+  }
+
+ private:
+  HRESULT DoSend();
+
+  void LogResponseHeaders();
+
+  // Sets proxy information for the request.
+  void SetProxyInformation();
+
+  struct TransientRequestState;
+  void CloseHandles(TransientRequestState* transient_request_state);
+
+  static uint32 ChooseProxyAuthScheme(uint32 supported_schemes);
+
+  static void __stdcall StatusCallback(HINTERNET handle,
+                                       uint32 context,
+                                       uint32 status,
+                                       void* info,
+                                       uint32 info_len);
+
+  // Returns true if the request is a POST request, in other words, if there
+  // is a request buffer to be sent to the server.
+  bool IsPostRequest() const { return request_buffer_ != NULL; }
+
+  // Holds the transient state corresponding to a single http request. We
+  // prefer to isolate the state of a request to avoid dirty state.
+  struct TransientRequestState {
+    TransientRequestState()
+        : port(0),
+          http_status_code(0),
+          proxy_authentication_scheme(0),
+          content_length(0),
+          current_bytes(0),
+          connection_handle(NULL),
+          request_handle(NULL) {}
+    ~TransientRequestState() {
+      ASSERT1(connection_handle == NULL);
+      ASSERT1(request_handle == NULL);
+    }
+
+    CString scheme;
+    CString server;
+    int     port;
+    CString url_path;
+
+    std::vector<uint8> response;
+    int http_status_code;
+    uint32 proxy_authentication_scheme;
+    CString proxy;
+    CString proxy_bypass;
+    int content_length;
+    int current_bytes;
+
+    HINTERNET connection_handle;
+    HINTERNET request_handle;
+  };
+
+  LLock lock_;
+  volatile bool is_canceled_;
+  HINTERNET session_handle_;  // Not owned by this class.
+  CString url_;
+  CString filename_;
+  const void* request_buffer_;          // Contains the request body for POST.
+  size_t      request_buffer_length_;   // Length of the request body.
+  CString additional_headers_;
+  CString user_agent_;
+  Config network_config_;
+  bool low_priority_;
+  NetworkRequestCallback* callback_;
+  scoped_ptr<HttpClient> http_client_;
+  scoped_ptr<TransientRequestState> request_state_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(SimpleRequest);
+};
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_SIMPLE_REQUEST_H__
+
diff --git a/net/simple_request_unittest.cc b/net/simple_request_unittest.cc
index c189f7d..ea3052e 100644
--- a/net/simple_request_unittest.cc
+++ b/net/simple_request_unittest.cc
@@ -1,230 +1,230 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Tests Get over http and https, using direct connection and wpad proxy.

-//

-// TODO(omaha): missing Post unit tests

-

-#include <windows.h>

-#include <winhttp.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/error.h"

-#include "omaha/common/string.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/simple_request.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class SimpleRequestTest : public testing::Test {

- protected:

-  SimpleRequestTest() {}

-

-  void SimpleGet(const CString& url, const Config& config);

-

-  void SimpleGetHostNotFound(const CString& url, const Config& config);

-

-  void SimpleGetFileNotFound(const CString& url, const Config& config);

-

-  void SimpleGetRedirect(const CString& url, const Config& config);

-

-  void PrepareRequest(const CString& url,

-                      const Config& config,

-                      SimpleRequest* simple_request);

-};

-

-void SimpleRequestTest::PrepareRequest(const CString& url,

-                                       const Config& config,

-                                       SimpleRequest* simple_request) {

-  ASSERT_TRUE(simple_request);

-  HINTERNET handle = NetworkConfig::Instance().session().session_handle;

-  simple_request->set_session_handle(handle);

-  simple_request->set_url(url);

-  simple_request->set_network_configuration(config);

-}

-

-void SimpleRequestTest::SimpleGet(const CString& url, const Config& config) {

-  SimpleRequest simple_request;

-  PrepareRequest(url, config, &simple_request);

-  EXPECT_HRESULT_SUCCEEDED(simple_request.Send());

-  EXPECT_EQ(HTTP_STATUS_OK, simple_request.GetHttpStatusCode());

-  CString response = Utf8BufferToWideChar(simple_request.GetResponse());

-

-  // robots.txt response contains "User-agent: *". This is not the "User-Agent"

-  // http header.

-  EXPECT_NE(-1, response.Find(_T("User-agent: *")));

-  CString content_type;

-  simple_request.QueryHeadersString(WINHTTP_QUERY_CONTENT_TYPE,

-                                    NULL, &content_type);

-  EXPECT_STREQ(_T("text/plain"), content_type);

-  CString server;

-  simple_request.QueryHeadersString(WINHTTP_QUERY_CUSTOM,

-                                    _T("Server"), &server);

-  EXPECT_STREQ(_T("gws"), server);

-  EXPECT_FALSE(simple_request.GetResponseHeaders().IsEmpty());

-

-  // Check the user agent went out with the request.

-  CString user_agent;

-  simple_request.QueryHeadersString(

-      WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_USER_AGENT,

-      WINHTTP_HEADER_NAME_BY_INDEX,

-      &user_agent);

-  EXPECT_STREQ(simple_request.user_agent(), user_agent);

-}

-

-void SimpleRequestTest::SimpleGetHostNotFound(const CString& url,

-                                              const Config& config) {

-  SimpleRequest simple_request;

-  PrepareRequest(url, config, &simple_request);

-

-  HRESULT hr = simple_request.Send();

-  int status_code = simple_request.GetHttpStatusCode();

-

-  if (config.auto_detect) {

-    // When the http host is not found, the proxy server usually returns 503.

-    // When the https host is not found, the proxy server returns 404. This may

-    // result in a flaky unit test but it's the best it can be done for now.

-    EXPECT_HRESULT_SUCCEEDED(hr);

-    if (String_StartsWith(url, kHttpsProtoScheme, true)) {

-      EXPECT_EQ(HTTP_STATUS_NOT_FOUND, status_code);

-    } else {

-      EXPECT_EQ(HTTP_STATUS_SERVICE_UNAVAIL, status_code);

-    }

-  } else {

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_WINHTTP_NAME_NOT_RESOLVED), hr);

-    EXPECT_EQ(0, status_code);

-  }

-}

-

-void SimpleRequestTest::SimpleGetFileNotFound(const CString& url,

-                                              const Config& config) {

-  SimpleRequest simple_request;

-  PrepareRequest(url, config, &simple_request);

-  EXPECT_HRESULT_SUCCEEDED(simple_request.Send());

-  EXPECT_EQ(HTTP_STATUS_NOT_FOUND, simple_request.GetHttpStatusCode());

-}

-

-void SimpleRequestTest::SimpleGetRedirect(const CString& url,

-                                          const Config& config) {

-  SimpleRequest simple_request;

-  PrepareRequest(url, config, &simple_request);

-  EXPECT_HRESULT_SUCCEEDED(simple_request.Send());

-  EXPECT_EQ(HTTP_STATUS_OK, simple_request.GetHttpStatusCode());

-}

-

-//

-// http tests.

-//

-// http get, direct connection.

-TEST_F(SimpleRequestTest, HttpGetDirect) {

-  SimpleGet(_T("http://www.google.com/robots.txt"), Config());

-}

-

-// http get, direct connection, negative test.

-TEST_F(SimpleRequestTest, HttpGetDirectHostNotFound) {

-  SimpleGetHostNotFound(_T("http://no_such_host.google.com/"), Config());

-}

-

-// http get, direct connection, negative test.

-TEST_F(SimpleRequestTest, HttpGetDirectFileNotFound) {

-  SimpleGetFileNotFound(_T("http://tools.google.com/no_such_file"), Config());

-}

-

-// http get, proxy wpad.

-TEST_F(SimpleRequestTest, HttpGetProxy) {

-  Config config;

-  config.auto_detect = true;

-  SimpleGet(_T("http://www.google.com/robots.txt"), config);

-}

-

-// http get, proxy wpad, negative test.

-TEST_F(SimpleRequestTest, HttpGetProxyHostNotFound) {

-  Config config;

-  config.auto_detect = true;

-  SimpleGetHostNotFound(_T("http://no_such_host.google.com/"), config);

-}

-

-// http get, proxy wpad.

-TEST_F(SimpleRequestTest, HttpGetProxyFileNotFound) {

-  Config config;

-  config.auto_detect = true;

-  SimpleGetFileNotFound(_T("http://tools.google.com/no_such_file"), config);

-}

-

-

-//

-// https tests.

-//

-// https get, direct.

-TEST_F(SimpleRequestTest, HttpsGetDirect) {

-  SimpleGet(_T("https://www.google.com/robots.txt"), Config());

-}

-

-// https get, direct, negative test.

-TEST_F(SimpleRequestTest, HttpsGetDirectHostNotFound) {

-  SimpleGetHostNotFound(_T("https://no_such_host.google.com/"), Config());

-}

-

-// https get, direct connection, negative test.

-TEST_F(SimpleRequestTest, HttpsGetDirectFileNotFound) {

-  SimpleGetFileNotFound(_T("https://tools.google.com/no_such_file"), Config());

-}

-

-// https get, proxy wpad.

-TEST_F(SimpleRequestTest, HttpsGetProxy) {

-  Config config;

-  config.auto_detect = true;

-  SimpleGet(_T("https://www.google.com/robots.txt"), config);

-}

-

-// https get, proxy wpad, negative test.

-TEST_F(SimpleRequestTest, HttpsGetProxyHostNotFound) {

-  Config config;

-  config.auto_detect = true;

-  SimpleGetHostNotFound(_T("https://no_such_host.google.com/"), config);

-}

-

-// https get, proxy wpad, negative test.

-TEST_F(SimpleRequestTest, HttpsGetProxyFileNotFound) {

-  Config config;

-  config.auto_detect = true;

-  SimpleGetFileNotFound(_T("https://tools.google.com/no_such_file"), config);

-}

-

-// Should not be able to reuse the object once canceled, even if closed.

-TEST_F(SimpleRequestTest, Cancel_CannotReuse) {

-  SimpleRequest simple_request;

-  PrepareRequest(_T("http:\\foo\\"), Config(), &simple_request);

-  EXPECT_HRESULT_SUCCEEDED(simple_request.Cancel());

-  EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED, simple_request.Send());

-  EXPECT_HRESULT_SUCCEEDED(simple_request.Close());

-  EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED, simple_request.Send());

-}

-

-// Http get request should follow redirects. The url below redirects to

-// https://tools.google.com/service/update2/oneclick and then it returns

-// 200 OK and some xml body.

-// TODO(omaha): Pick a new URL since this service is now obsolete and could

-// be removed at some point.

-TEST_F(SimpleRequestTest, HttpGet_Redirect) {

-  SimpleGetRedirect(_T("http://tools.google.com/service/update2/oneclick"),

-                    Config());

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Tests Get over http and https, using direct connection and wpad proxy.
+//
+// TODO(omaha): missing Post unit tests
+
+#include <windows.h>
+#include <winhttp.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/error.h"
+#include "omaha/common/string.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/simple_request.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class SimpleRequestTest : public testing::Test {
+ protected:
+  SimpleRequestTest() {}
+
+  void SimpleGet(const CString& url, const Config& config);
+
+  void SimpleGetHostNotFound(const CString& url, const Config& config);
+
+  void SimpleGetFileNotFound(const CString& url, const Config& config);
+
+  void SimpleGetRedirect(const CString& url, const Config& config);
+
+  void PrepareRequest(const CString& url,
+                      const Config& config,
+                      SimpleRequest* simple_request);
+};
+
+void SimpleRequestTest::PrepareRequest(const CString& url,
+                                       const Config& config,
+                                       SimpleRequest* simple_request) {
+  ASSERT_TRUE(simple_request);
+  HINTERNET handle = NetworkConfig::Instance().session().session_handle;
+  simple_request->set_session_handle(handle);
+  simple_request->set_url(url);
+  simple_request->set_network_configuration(config);
+}
+
+void SimpleRequestTest::SimpleGet(const CString& url, const Config& config) {
+  SimpleRequest simple_request;
+  PrepareRequest(url, config, &simple_request);
+  EXPECT_HRESULT_SUCCEEDED(simple_request.Send());
+  EXPECT_EQ(HTTP_STATUS_OK, simple_request.GetHttpStatusCode());
+  CString response = Utf8BufferToWideChar(simple_request.GetResponse());
+
+  // robots.txt response contains "User-agent: *". This is not the "User-Agent"
+  // http header.
+  EXPECT_NE(-1, response.Find(_T("User-agent: *")));
+  CString content_type;
+  simple_request.QueryHeadersString(WINHTTP_QUERY_CONTENT_TYPE,
+                                    NULL, &content_type);
+  EXPECT_STREQ(_T("text/plain"), content_type);
+  CString server;
+  simple_request.QueryHeadersString(WINHTTP_QUERY_CUSTOM,
+                                    _T("Server"), &server);
+  EXPECT_STREQ(_T("gws"), server);
+  EXPECT_FALSE(simple_request.GetResponseHeaders().IsEmpty());
+
+  // Check the user agent went out with the request.
+  CString user_agent;
+  simple_request.QueryHeadersString(
+      WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_USER_AGENT,
+      WINHTTP_HEADER_NAME_BY_INDEX,
+      &user_agent);
+  EXPECT_STREQ(simple_request.user_agent(), user_agent);
+}
+
+void SimpleRequestTest::SimpleGetHostNotFound(const CString& url,
+                                              const Config& config) {
+  SimpleRequest simple_request;
+  PrepareRequest(url, config, &simple_request);
+
+  HRESULT hr = simple_request.Send();
+  int status_code = simple_request.GetHttpStatusCode();
+
+  if (config.auto_detect) {
+    // When the http host is not found, the proxy server usually returns 503.
+    // When the https host is not found, the proxy server returns 404. This may
+    // result in a flaky unit test but it's the best it can be done for now.
+    EXPECT_HRESULT_SUCCEEDED(hr);
+    if (String_StartsWith(url, kHttpsProtoScheme, true)) {
+      EXPECT_EQ(HTTP_STATUS_NOT_FOUND, status_code);
+    } else {
+      EXPECT_EQ(HTTP_STATUS_SERVICE_UNAVAIL, status_code);
+    }
+  } else {
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_WINHTTP_NAME_NOT_RESOLVED), hr);
+    EXPECT_EQ(0, status_code);
+  }
+}
+
+void SimpleRequestTest::SimpleGetFileNotFound(const CString& url,
+                                              const Config& config) {
+  SimpleRequest simple_request;
+  PrepareRequest(url, config, &simple_request);
+  EXPECT_HRESULT_SUCCEEDED(simple_request.Send());
+  EXPECT_EQ(HTTP_STATUS_NOT_FOUND, simple_request.GetHttpStatusCode());
+}
+
+void SimpleRequestTest::SimpleGetRedirect(const CString& url,
+                                          const Config& config) {
+  SimpleRequest simple_request;
+  PrepareRequest(url, config, &simple_request);
+  EXPECT_HRESULT_SUCCEEDED(simple_request.Send());
+  EXPECT_EQ(HTTP_STATUS_OK, simple_request.GetHttpStatusCode());
+}
+
+//
+// http tests.
+//
+// http get, direct connection.
+TEST_F(SimpleRequestTest, HttpGetDirect) {
+  SimpleGet(_T("http://www.google.com/robots.txt"), Config());
+}
+
+// http get, direct connection, negative test.
+TEST_F(SimpleRequestTest, HttpGetDirectHostNotFound) {
+  SimpleGetHostNotFound(_T("http://no_such_host.google.com/"), Config());
+}
+
+// http get, direct connection, negative test.
+TEST_F(SimpleRequestTest, HttpGetDirectFileNotFound) {
+  SimpleGetFileNotFound(_T("http://tools.google.com/no_such_file"), Config());
+}
+
+// http get, proxy wpad.
+TEST_F(SimpleRequestTest, HttpGetProxy) {
+  Config config;
+  config.auto_detect = true;
+  SimpleGet(_T("http://www.google.com/robots.txt"), config);
+}
+
+// http get, proxy wpad, negative test.
+TEST_F(SimpleRequestTest, HttpGetProxyHostNotFound) {
+  Config config;
+  config.auto_detect = true;
+  SimpleGetHostNotFound(_T("http://no_such_host.google.com/"), config);
+}
+
+// http get, proxy wpad.
+TEST_F(SimpleRequestTest, HttpGetProxyFileNotFound) {
+  Config config;
+  config.auto_detect = true;
+  SimpleGetFileNotFound(_T("http://tools.google.com/no_such_file"), config);
+}
+
+
+//
+// https tests.
+//
+// https get, direct.
+TEST_F(SimpleRequestTest, HttpsGetDirect) {
+  SimpleGet(_T("https://www.google.com/robots.txt"), Config());
+}
+
+// https get, direct, negative test.
+TEST_F(SimpleRequestTest, HttpsGetDirectHostNotFound) {
+  SimpleGetHostNotFound(_T("https://no_such_host.google.com/"), Config());
+}
+
+// https get, direct connection, negative test.
+TEST_F(SimpleRequestTest, HttpsGetDirectFileNotFound) {
+  SimpleGetFileNotFound(_T("https://tools.google.com/no_such_file"), Config());
+}
+
+// https get, proxy wpad.
+TEST_F(SimpleRequestTest, HttpsGetProxy) {
+  Config config;
+  config.auto_detect = true;
+  SimpleGet(_T("https://www.google.com/robots.txt"), config);
+}
+
+// https get, proxy wpad, negative test.
+TEST_F(SimpleRequestTest, HttpsGetProxyHostNotFound) {
+  Config config;
+  config.auto_detect = true;
+  SimpleGetHostNotFound(_T("https://no_such_host.google.com/"), config);
+}
+
+// https get, proxy wpad, negative test.
+TEST_F(SimpleRequestTest, HttpsGetProxyFileNotFound) {
+  Config config;
+  config.auto_detect = true;
+  SimpleGetFileNotFound(_T("https://tools.google.com/no_such_file"), config);
+}
+
+// Should not be able to reuse the object once canceled, even if closed.
+TEST_F(SimpleRequestTest, Cancel_CannotReuse) {
+  SimpleRequest simple_request;
+  PrepareRequest(_T("http:\\foo\\"), Config(), &simple_request);
+  EXPECT_HRESULT_SUCCEEDED(simple_request.Cancel());
+  EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED, simple_request.Send());
+  EXPECT_HRESULT_SUCCEEDED(simple_request.Close());
+  EXPECT_EQ(OMAHA_NET_E_REQUEST_CANCELLED, simple_request.Send());
+}
+
+// Http get request should follow redirects. The url below redirects to
+// https://tools.google.com/service/update2/oneclick and then it returns
+// 200 OK and some xml body.
+// TODO(omaha): Pick a new URL since this service is now obsolete and could
+// be removed at some point.
+TEST_F(SimpleRequestTest, HttpGet_Redirect) {
+  SimpleGetRedirect(_T("http://tools.google.com/service/update2/oneclick"),
+                    Config());
+}
+
+}  // namespace omaha
+
diff --git a/net/urlmon_request.cc b/net/urlmon_request.cc
index cf83479..54c2fc3 100644
--- a/net/urlmon_request.cc
+++ b/net/urlmon_request.cc
@@ -1,197 +1,197 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/net/urlmon_request.h"

-#include <winhttp.h>

-#include <atlbase.h>

-#include <atlcom.h>

-#include <atlcomcli.h>

-#include <vector>

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-#include "omaha/net/bind_status_callback.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/network_config.h"

-

-namespace omaha {

-

-const DWORD response_headers_needed[] = {

-  WINHTTP_QUERY_CONTENT_TYPE,

-  WINHTTP_QUERY_ETAG,

-  WINHTTP_QUERY_SET_COOKIE,

-  WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_USER_AGENT,

-  WINHTTP_QUERY_RAW_HEADERS_CRLF,

-};

-

-UrlmonRequest::UrlmonRequest()

-    : request_buffer_(NULL),

-      request_buffer_length_(0),

-      http_status_code_(0),

-      is_cancelled_(false) {

-  NET_LOG(L3, (_T("[UrlmonRequest::UrlmonRequest]")));

-  user_agent_.Format(_T("%s;urlmon"), NetworkConfig::GetUserAgent());

-}

-

-UrlmonRequest::~UrlmonRequest() {

-  Close();

-}

-

-HRESULT UrlmonRequest::Close() {

-  http_status_code_ = 0;

-  response_body_.clear();

-  raw_response_headers_.Empty();

-  response_headers_map_.clear();

-  return S_OK;

-}

-

-CComBSTR BuildRequestHeaders(const CString& user_agent,

-                             const CString& additional_headers) {

-  CString headers_to_send;

-  if (!user_agent.IsEmpty()) {

-    headers_to_send += _T("User-Agent: ");

-    headers_to_send += user_agent;

-    headers_to_send = String_MakeEndWith(headers_to_send, _T("\r\n"), false);

-  }

-

-  if (!additional_headers.IsEmpty()) {

-    headers_to_send += additional_headers;

-    headers_to_send = String_MakeEndWith(headers_to_send, _T("\r\n"), false);

-  }

-

-  return CComBSTR(headers_to_send);

-}

-

-HRESULT UrlmonRequest::ProcessResponseHeaders(

-                            const CComVariant& headers,

-                            const CComSafeArray<DWORD>& headers_needed) {

-  if (headers.vt != (VT_ARRAY | VT_BSTR)) {

-    return E_FAIL;

-  }

-

-  CComSafeArray<BSTR> response_headers(headers.parray);

-  DWORD count = response_headers.GetCount();

-  if (count != headers_needed.GetCount()) {

-    return E_FAIL;

-  }

-

-  response_headers_map_.clear();

-  LONG lower_bound = response_headers.GetLowerBound();

-  LONG upper_bound = response_headers.GetUpperBound();

-  for (int i = lower_bound; i <= upper_bound; ++i) {

-    response_headers_map_.insert(std::make_pair(headers_needed[i],

-                                                response_headers[i]));

-    NET_LOG(L3, (_T("[ProcessResponseHeaders][%d][%s]"),

-                 i, response_headers[i]));

-  }

-  raw_response_headers_ = response_headers_map_[WINHTTP_QUERY_RAW_HEADERS_CRLF];

-  return S_OK;

-}

-

-HRESULT UrlmonRequest::ProcessResponseFile(const CComBSTR& cache_filename) {

-  if (!cache_filename.Length()) {

-    // Response with no body.

-    return S_OK;

-  }

-

-  if (!filename_.IsEmpty()) {

-    // The caller expects the response to be stored in the target file.

-    return File::Copy(cache_filename, filename_, true);

-  }

-

-  response_body_.clear();

-  HRESULT hr = ReadEntireFileShareMode(cache_filename,

-                                       0,

-                                       FILE_SHARE_READ,

-                                       &response_body_);

-  if (FAILED(hr) || response_body_.empty()) {

-    return hr;

-  }

-  return S_OK;

-}

-

-HRESULT UrlmonRequest::SendRequest(BSTR url,

-                                   BSTR post_data,

-                                   BSTR request_headers,

-                                   VARIANT response_headers_needed,

-                                   CComVariant* response_headers,

-                                   DWORD* response_code,

-                                   BSTR* cache_filename) {

-  HRESULT hr = BindStatusCallback::CreateAndSend(url,

-                                                 post_data,

-                                                 request_headers,

-                                                 response_headers_needed,

-                                                 response_headers,

-                                                 response_code,

-                                                 cache_filename);

-  NET_LOG(L3, (_T("[UrlmonRequest::SendRequest][0x%x][%d][%s]"),

-               hr, *response_code, *cache_filename));

-  if (!*response_code) {

-    return FAILED(hr) ? hr : E_UNEXPECTED;

-  }

-

-  return S_OK;

-}

-

-HRESULT UrlmonRequest::Send() {

-  NET_LOG(L3, (_T("[UrlmonRequest::Send]")));

-  if (is_cancelled_) {

-    return OMAHA_NET_E_REQUEST_CANCELLED;

-  }

-

-  ASSERT1(url_.Length() > 0);

-  CComBSTR headers_to_send(BuildRequestHeaders(user_agent(),

-                                               additional_headers_));

-  CComBSTR post_data;

-  if (request_buffer_) {

-    post_data.AppendBytes(static_cast<const char*>(request_buffer_),

-                          request_buffer_length_);

-  }

-  CComSafeArray<DWORD> headers_needed(arraysize(response_headers_needed));

-  for (size_t i = 0; i < arraysize(response_headers_needed); ++i) {

-    headers_needed.SetAt(i, response_headers_needed[i]);

-  }

-  CComVariant response_headers;

-  CComBSTR cache_filename;

-

-  HRESULT hr = SendRequest(url_,

-                           post_data,

-                           headers_to_send,

-                           CComVariant(headers_needed),

-                           &response_headers,

-                           &http_status_code_,

-                           &cache_filename);

-  if (FAILED(hr)) {

-    NET_LOG(LW, (_T("[UrlmonRequest::Send][0x%08x]"), hr));

-    return hr;

-  }

-

-  VERIFY1(SUCCEEDED(ProcessResponseHeaders(response_headers, headers_needed)));

-  VERIFY1(SUCCEEDED(ProcessResponseFile(cache_filename)));

-  return S_OK;

-}

-

-// TODO(omaha): cancel the underlying IBindStatusCallback object.

-HRESULT UrlmonRequest::Cancel() {

-  NET_LOG(L2, (_T("[UrlmonRequest::Cancel]")));

-  ::InterlockedExchange(&is_cancelled_, true);

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/net/urlmon_request.h"
+#include <winhttp.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlcomcli.h>
+#include <vector>
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+#include "omaha/net/bind_status_callback.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/network_config.h"
+
+namespace omaha {
+
+const DWORD response_headers_needed[] = {
+  WINHTTP_QUERY_CONTENT_TYPE,
+  WINHTTP_QUERY_ETAG,
+  WINHTTP_QUERY_SET_COOKIE,
+  WINHTTP_QUERY_FLAG_REQUEST_HEADERS | WINHTTP_QUERY_USER_AGENT,
+  WINHTTP_QUERY_RAW_HEADERS_CRLF,
+};
+
+UrlmonRequest::UrlmonRequest()
+    : request_buffer_(NULL),
+      request_buffer_length_(0),
+      http_status_code_(0),
+      is_cancelled_(false) {
+  NET_LOG(L3, (_T("[UrlmonRequest::UrlmonRequest]")));
+  user_agent_.Format(_T("%s;urlmon"), NetworkConfig::GetUserAgent());
+}
+
+UrlmonRequest::~UrlmonRequest() {
+  Close();
+}
+
+HRESULT UrlmonRequest::Close() {
+  http_status_code_ = 0;
+  response_body_.clear();
+  raw_response_headers_.Empty();
+  response_headers_map_.clear();
+  return S_OK;
+}
+
+CComBSTR BuildRequestHeaders(const CString& user_agent,
+                             const CString& additional_headers) {
+  CString headers_to_send;
+  if (!user_agent.IsEmpty()) {
+    headers_to_send += _T("User-Agent: ");
+    headers_to_send += user_agent;
+    headers_to_send = String_MakeEndWith(headers_to_send, _T("\r\n"), false);
+  }
+
+  if (!additional_headers.IsEmpty()) {
+    headers_to_send += additional_headers;
+    headers_to_send = String_MakeEndWith(headers_to_send, _T("\r\n"), false);
+  }
+
+  return CComBSTR(headers_to_send);
+}
+
+HRESULT UrlmonRequest::ProcessResponseHeaders(
+                            const CComVariant& headers,
+                            const CComSafeArray<DWORD>& headers_needed) {
+  if (headers.vt != (VT_ARRAY | VT_BSTR)) {
+    return E_FAIL;
+  }
+
+  CComSafeArray<BSTR> response_headers(headers.parray);
+  DWORD count = response_headers.GetCount();
+  if (count != headers_needed.GetCount()) {
+    return E_FAIL;
+  }
+
+  response_headers_map_.clear();
+  LONG lower_bound = response_headers.GetLowerBound();
+  LONG upper_bound = response_headers.GetUpperBound();
+  for (int i = lower_bound; i <= upper_bound; ++i) {
+    response_headers_map_.insert(std::make_pair(headers_needed[i],
+                                                response_headers[i]));
+    NET_LOG(L3, (_T("[ProcessResponseHeaders][%d][%s]"),
+                 i, response_headers[i]));
+  }
+  raw_response_headers_ = response_headers_map_[WINHTTP_QUERY_RAW_HEADERS_CRLF];
+  return S_OK;
+}
+
+HRESULT UrlmonRequest::ProcessResponseFile(const CComBSTR& cache_filename) {
+  if (!cache_filename.Length()) {
+    // Response with no body.
+    return S_OK;
+  }
+
+  if (!filename_.IsEmpty()) {
+    // The caller expects the response to be stored in the target file.
+    return File::Copy(cache_filename, filename_, true);
+  }
+
+  response_body_.clear();
+  HRESULT hr = ReadEntireFileShareMode(cache_filename,
+                                       0,
+                                       FILE_SHARE_READ,
+                                       &response_body_);
+  if (FAILED(hr) || response_body_.empty()) {
+    return hr;
+  }
+  return S_OK;
+}
+
+HRESULT UrlmonRequest::SendRequest(BSTR url,
+                                   BSTR post_data,
+                                   BSTR request_headers,
+                                   VARIANT response_headers_needed,
+                                   CComVariant* response_headers,
+                                   DWORD* response_code,
+                                   BSTR* cache_filename) {
+  HRESULT hr = BindStatusCallback::CreateAndSend(url,
+                                                 post_data,
+                                                 request_headers,
+                                                 response_headers_needed,
+                                                 response_headers,
+                                                 response_code,
+                                                 cache_filename);
+  NET_LOG(L3, (_T("[UrlmonRequest::SendRequest][0x%x][%d][%s]"),
+               hr, *response_code, *cache_filename));
+  if (!*response_code) {
+    return FAILED(hr) ? hr : E_UNEXPECTED;
+  }
+
+  return S_OK;
+}
+
+HRESULT UrlmonRequest::Send() {
+  NET_LOG(L3, (_T("[UrlmonRequest::Send]")));
+  if (is_cancelled_) {
+    return OMAHA_NET_E_REQUEST_CANCELLED;
+  }
+
+  ASSERT1(url_.Length() > 0);
+  CComBSTR headers_to_send(BuildRequestHeaders(user_agent(),
+                                               additional_headers_));
+  CComBSTR post_data;
+  if (request_buffer_) {
+    post_data.AppendBytes(static_cast<const char*>(request_buffer_),
+                          request_buffer_length_);
+  }
+  CComSafeArray<DWORD> headers_needed(arraysize(response_headers_needed));
+  for (size_t i = 0; i < arraysize(response_headers_needed); ++i) {
+    headers_needed.SetAt(i, response_headers_needed[i]);
+  }
+  CComVariant response_headers;
+  CComBSTR cache_filename;
+
+  HRESULT hr = SendRequest(url_,
+                           post_data,
+                           headers_to_send,
+                           CComVariant(headers_needed),
+                           &response_headers,
+                           &http_status_code_,
+                           &cache_filename);
+  if (FAILED(hr)) {
+    NET_LOG(LW, (_T("[UrlmonRequest::Send][0x%08x]"), hr));
+    return hr;
+  }
+
+  VERIFY1(SUCCEEDED(ProcessResponseHeaders(response_headers, headers_needed)));
+  VERIFY1(SUCCEEDED(ProcessResponseFile(cache_filename)));
+  return S_OK;
+}
+
+// TODO(omaha): cancel the underlying IBindStatusCallback object.
+HRESULT UrlmonRequest::Cancel() {
+  NET_LOG(L2, (_T("[UrlmonRequest::Cancel]")));
+  ::InterlockedExchange(&is_cancelled_, true);
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/net/urlmon_request.h b/net/urlmon_request.h
index d15ae5f..7756229 100644
--- a/net/urlmon_request.h
+++ b/net/urlmon_request.h
@@ -1,146 +1,146 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// UrlmonRequest sends http transactions through urlmon.dll

-

-#ifndef OMAHA_NET_URLMON_REQUEST_H__

-#define OMAHA_NET_URLMON_REQUEST_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <atlsafe.h>

-#include <map>

-#include <vector>

-#include "base/basictypes.h"

-#include "goopdate/google_update_idl.h"

-#include "omaha/common/debug.h"

-#include "omaha/net/http_request.h"

-

-namespace omaha {

-

-class UrlmonRequest : public HttpRequestInterface {

- public:

-  UrlmonRequest();

-  virtual ~UrlmonRequest();

-

-  // HttpRequestInterface methods.

-  virtual HRESULT Close();

-

-  virtual HRESULT Send();

-

-  virtual HRESULT Cancel();

-

-  virtual std::vector<uint8> GetResponse() const {

-    return response_body_;

-  }

-

-  virtual int GetHttpStatusCode() const {

-    return http_status_code_;

-  }

-

-  virtual HRESULT QueryHeadersString(uint32 info_level,

-                                     const TCHAR* name,

-                                     CString* value) const {

-    // TODO(Omaha) - support for a custom name string.

-    name;

-

-    ASSERT1(value);

-    value->Empty();

-    std::map<DWORD, CString>::const_iterator cur =

-        response_headers_map_.find(info_level);

-    if (cur != response_headers_map_.end()) {

-      *value = cur->second;

-    }

-    return !value->IsEmpty() ? S_OK : E_FAIL;

-  }

-

-  virtual CString GetResponseHeaders() const {

-    return raw_response_headers_;

-  }

-

-  virtual CString ToString() const { return _T("urlmon"); }

-

-  // No effect for this class.

-  virtual void set_session_handle(HINTERNET) {}

-

-  virtual void set_url(const CString& url) { url_ = url; }

-

-  virtual void set_request_buffer(const void* buffer, size_t buffer_length) {

-    request_buffer_ = buffer;

-    request_buffer_length_ = buffer_length;

-  }

-

-  virtual void set_network_configuration(const Config& network_config) {

-    network_config;

-  }

-

-  // Sets the filename to receive the response instead of the memory buffer.

-  virtual void set_filename(const CString& filename) { filename_ = filename; }

-

-  virtual void set_low_priority(bool low_priority) {

-    low_priority;

-  }

-

-  virtual void set_callback(NetworkRequestCallback* callback) {

-    // TODO(Omaha) - Provide events.

-    callback;

-  }

-

-  virtual void set_additional_headers(const CString& additional_headers) {

-    additional_headers_ = additional_headers;

-  }

-

-  virtual CString user_agent() const { return user_agent_; }

-

-  virtual void set_user_agent(const CString& user_agent) {

-    user_agent_ = user_agent;

-  }

-

-  virtual HRESULT SendRequest(BSTR url,

-                              BSTR post_data,

-                              BSTR request_headers,

-                              VARIANT response_headers_needed,

-                              CComVariant* response_headers,

-                              DWORD* response_code,

-                              BSTR* cache_filename);

-

- protected:

-  CString user_agent_;

-

- private:

-  HRESULT ProcessResponseHeaders(const CComVariant& headers,

-                                 const CComSafeArray<DWORD>& headers_needed);

-  HRESULT ProcessResponseFile(const CComBSTR& cache_filename);

-  bool CreateBrowserHttpRequest();

-

-  CComBSTR url_;

-  CString filename_;

-  const void* request_buffer_;          // Contains the request body for POST.

-  size_t      request_buffer_length_;   // Length of the request body.

-  CString additional_headers_;

-

-  volatile LONG is_cancelled_;

-  DWORD http_status_code_;

-  std::vector<uint8> response_body_;

-  std::map<DWORD, CString> response_headers_map_;

-  CString raw_response_headers_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(UrlmonRequest);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_NET_URLMON_REQUEST_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// UrlmonRequest sends http transactions through urlmon.dll
+
+#ifndef OMAHA_NET_URLMON_REQUEST_H__
+#define OMAHA_NET_URLMON_REQUEST_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <atlsafe.h>
+#include <map>
+#include <vector>
+#include "base/basictypes.h"
+#include "goopdate/google_update_idl.h"
+#include "omaha/common/debug.h"
+#include "omaha/net/http_request.h"
+
+namespace omaha {
+
+class UrlmonRequest : public HttpRequestInterface {
+ public:
+  UrlmonRequest();
+  virtual ~UrlmonRequest();
+
+  // HttpRequestInterface methods.
+  virtual HRESULT Close();
+
+  virtual HRESULT Send();
+
+  virtual HRESULT Cancel();
+
+  virtual std::vector<uint8> GetResponse() const {
+    return response_body_;
+  }
+
+  virtual int GetHttpStatusCode() const {
+    return http_status_code_;
+  }
+
+  virtual HRESULT QueryHeadersString(uint32 info_level,
+                                     const TCHAR* name,
+                                     CString* value) const {
+    // TODO(Omaha) - support for a custom name string.
+    name;
+
+    ASSERT1(value);
+    value->Empty();
+    std::map<DWORD, CString>::const_iterator cur =
+        response_headers_map_.find(info_level);
+    if (cur != response_headers_map_.end()) {
+      *value = cur->second;
+    }
+    return !value->IsEmpty() ? S_OK : E_FAIL;
+  }
+
+  virtual CString GetResponseHeaders() const {
+    return raw_response_headers_;
+  }
+
+  virtual CString ToString() const { return _T("urlmon"); }
+
+  // No effect for this class.
+  virtual void set_session_handle(HINTERNET) {}
+
+  virtual void set_url(const CString& url) { url_ = url; }
+
+  virtual void set_request_buffer(const void* buffer, size_t buffer_length) {
+    request_buffer_ = buffer;
+    request_buffer_length_ = buffer_length;
+  }
+
+  virtual void set_network_configuration(const Config& network_config) {
+    network_config;
+  }
+
+  // Sets the filename to receive the response instead of the memory buffer.
+  virtual void set_filename(const CString& filename) { filename_ = filename; }
+
+  virtual void set_low_priority(bool low_priority) {
+    low_priority;
+  }
+
+  virtual void set_callback(NetworkRequestCallback* callback) {
+    // TODO(Omaha) - Provide events.
+    callback;
+  }
+
+  virtual void set_additional_headers(const CString& additional_headers) {
+    additional_headers_ = additional_headers;
+  }
+
+  virtual CString user_agent() const { return user_agent_; }
+
+  virtual void set_user_agent(const CString& user_agent) {
+    user_agent_ = user_agent;
+  }
+
+  virtual HRESULT SendRequest(BSTR url,
+                              BSTR post_data,
+                              BSTR request_headers,
+                              VARIANT response_headers_needed,
+                              CComVariant* response_headers,
+                              DWORD* response_code,
+                              BSTR* cache_filename);
+
+ protected:
+  CString user_agent_;
+
+ private:
+  HRESULT ProcessResponseHeaders(const CComVariant& headers,
+                                 const CComSafeArray<DWORD>& headers_needed);
+  HRESULT ProcessResponseFile(const CComBSTR& cache_filename);
+  bool CreateBrowserHttpRequest();
+
+  CComBSTR url_;
+  CString filename_;
+  const void* request_buffer_;          // Contains the request body for POST.
+  size_t      request_buffer_length_;   // Length of the request body.
+  CString additional_headers_;
+
+  volatile LONG is_cancelled_;
+  DWORD http_status_code_;
+  std::vector<uint8> response_body_;
+  std::map<DWORD, CString> response_headers_map_;
+  CString raw_response_headers_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(UrlmonRequest);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_NET_URLMON_REQUEST_H__
+
diff --git a/net/winhttp.cc b/net/winhttp.cc
index 1f511c4..e2de416 100644
--- a/net/winhttp.cc
+++ b/net/winhttp.cc
@@ -1,593 +1,593 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Internet-access utility functions via winhttp

-

-#include "omaha/net/http_client.h"

-

-#include <vector>                   // NOLINT

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/utils.h"

-#include "omaha/net/winhttp_vtable.h"

-

-namespace omaha {

-

-class WinHttp : public HttpClient {

- public:

-  static HttpClient* Create() { return new WinHttp; }

-

-  virtual HRESULT Initialize();

-  virtual HRESULT AddRequestHeaders(HINTERNET request,

-                                    const TCHAR* headers,

-                                    int length,

-                                    uint32 modifiers);

-  virtual HRESULT CheckPlatform();

-  virtual HRESULT Close(HINTERNET handle);

-  virtual HRESULT Connect(HINTERNET session_handle,

-                          const TCHAR* server,

-                          int port,

-                          HINTERNET* connection_handle);

-  virtual HRESULT CrackUrl(const TCHAR* url,

-                           uint32 flags,

-                           CString* scheme,

-                           CString* server,

-                           int* port,

-                           CString* url_path,

-                           CString* extra_info);

-  virtual HRESULT CreateUrl(const TCHAR* scheme,

-                            const TCHAR* server,

-                            int port,

-                            const TCHAR* url_path,

-                            const TCHAR* extra_info,

-                            uint32 flags,

-                            CString* url);

-  virtual HRESULT DetectAutoProxyConfigUrl(uint32 flags,

-                                           CString* auto_config_url);

-  virtual HRESULT GetDefaultProxyConfiguration(ProxyInfo* proxy_info);

-  virtual HRESULT GetIEProxyConfiguration(

-                      CurrentUserIEProxyConfig* proxy_info);

-  virtual HRESULT GetProxyForUrl(HINTERNET session_handle,

-                                 const TCHAR* url,

-                                 const AutoProxyOptions* auto_proxy_options,

-                                 ProxyInfo* proxy_info);

-  virtual HRESULT Open(const TCHAR* user_agent,

-                       uint32 access_type,

-                       const TCHAR* proxy_name,

-                       const TCHAR* proxy_bypass,

-                       HINTERNET* session_handle);

-  virtual HRESULT OpenRequest(HINTERNET connection_handle,

-                              const TCHAR* verb,

-                              const TCHAR* uri,

-                              const TCHAR* version,

-                              const TCHAR* referrer,

-                              const TCHAR** accept_types,

-                              uint32 flags,

-                              HINTERNET* request_handle);

-  virtual HRESULT QueryAuthSchemes(HINTERNET request_handle,

-                                   uint32* supported_schemes,

-                                   uint32* first_scheme,

-                                   uint32* auth_target);

-  virtual HRESULT QueryDataAvailable(HINTERNET request_handle,

-                                     DWORD* num_bytes);

-  virtual HRESULT QueryHeaders(HINTERNET request_handle,

-                               uint32 info_level,

-                               const TCHAR* name,

-                               void* buffer,

-                               DWORD* buffer_length,

-                               DWORD* index);

-  virtual HRESULT QueryOption(HINTERNET handle,

-                              uint32 option,

-                              void* buffer,

-                              DWORD* buffer_length);

-  virtual HRESULT ReadData(HINTERNET request_handle,

-                           void* buffer,

-                           DWORD buffer_length,

-                           DWORD* bytes_read);

-  virtual HRESULT ReceiveResponse(HINTERNET request_handle);

-  virtual HRESULT SendRequest(HINTERNET request_handle,

-                              const TCHAR* headers,

-                              DWORD headers_length,

-                              const void* optional_data,

-                              DWORD optional_data_length,

-                              DWORD content_length);

-  virtual HRESULT SetCredentials(HINTERNET request_handle,

-                                 uint32 auth_targets,

-                                 uint32 auth_scheme,

-                                 const TCHAR* user_name,

-                                 const TCHAR* password);

-  virtual HRESULT SetDefaultProxyConfiguration(const ProxyInfo& proxy_info);

-  virtual HRESULT SetOption(HINTERNET handle,

-                            uint32 option,

-                            const void* buffer,

-                            DWORD buffer_length);

-  virtual StatusCallback SetStatusCallback(HINTERNET handle,

-                                           StatusCallback callback,

-                                           uint32 flags);

-  virtual HRESULT SetTimeouts(HINTERNET handle,

-                              int resolve_timeout_ms,

-                              int connect_timeout_ms,

-                              int send_timeout_ms,

-                              int receive_timeout_ms);

-  virtual HRESULT WriteData(HINTERNET request_handle,

-                            const void* buffer,

-                            DWORD bytes_to_write,

-                            DWORD* bytes_written);

-

- private:

-  WinHttp();

-

-  bool is_initialized_;

-

-  static WinHttpVTable winhttp_;

-  static LLock lock_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(WinHttp);

-};

-

-WinHttpVTable WinHttp::winhttp_;

-LLock         WinHttp::lock_;

-

-// TODO(omaha): remove after the implementation is complete.

-// 4100: unreferenced formal parameter

-#pragma warning(disable : 4100)

-

-WinHttp::WinHttp() : is_initialized_(false) {

-}

-

-HRESULT WinHttp::Initialize() {

-  if (is_initialized_) {

-    return S_OK;

-  }

-  __mutexBlock(WinHttp::lock_) {

-    if (!winhttp_.Load()) {

-      HRESULT hr = HRESULTFromLastError();

-      NET_LOG(LEVEL_ERROR, (_T("[failed to load winhttp][0x%08x]"), hr));

-      return hr;

-    }

-  }

-  is_initialized_ = true;

-  return S_OK;

-}

-

-HRESULT WinHttp::Open(const TCHAR* user_agent,

-                      uint32 access_type,

-                      const TCHAR* proxy_name,

-                      const TCHAR* proxy_bypass,

-                      HINTERNET* session_handle) {

-  *session_handle = winhttp_.WinHttpOpen(user_agent,

-                                         access_type,

-                                         proxy_name,

-                                         proxy_bypass,

-                                         0);   // Synchronous mode always.

-  return *session_handle ? S_OK : HRESULTFromLastError();

-}

-

-// Quoting from the MSDN documentation:

-//    "Operations on a WinHTTP request handle should be synchronized.

-//    For example, an application should avoid closing a request handle on one

-//    thread while another thread is sending or receiving a request.

-//    To terminate an asynchronous request, close the request handle during

-//    a callback notification. To terminate a synchronous request, close the

-//    handle when the previous WinHTTP call returns."

-// Synchronizing on the request handle adds quite a bit of complexity to the

-// code. Blocking WinHTTP calls can block for quite a while: by default the

-// connect time out is 60 seconds, the send or receive timeout is 30 seconds,

-// and the receive response timeout is 90 seconds. Waiting as much to

-// cancel a request in progress is not acceptable. We noticed that closing

-// the request handle from a different thread makes the blocking WinHTTP

-// thread return right away. We are not fixing this for now, as the benefit

-// seems to be minimal while increasing the complexity of the code.

-HRESULT WinHttp::Close(HINTERNET handle) {

-  ASSERT1(handle);

-  return winhttp_.WinHttpCloseHandle(handle) ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::Connect(HINTERNET session_handle,

-                         const TCHAR* server,

-                         int port,

-                         HINTERNET* connection_handle) {

-  ASSERT1(server);

-  ASSERT1(port <= INTERNET_MAX_PORT_NUMBER_VALUE);

-

-  *connection_handle = winhttp_.WinHttpConnect(session_handle,

-                                              server,

-                                              static_cast<INTERNET_PORT>(port),

-                                              0);

-  return *connection_handle ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::OpenRequest(HINTERNET connection_handle,

-                             const TCHAR* verb,

-                             const TCHAR* uri,

-                             const TCHAR* version,

-                             const TCHAR* referrer,

-                             const TCHAR** accept_types,

-                             uint32 flags,

-                             HINTERNET* request_handle) {

-  *request_handle = winhttp_.WinHttpOpenRequest(connection_handle,

-                                                verb,

-                                                uri,

-                                                version,

-                                                referrer,

-                                                accept_types,

-                                                flags);

-  return *request_handle ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::SendRequest(HINTERNET request_handle,

-                             const TCHAR* headers,

-                             DWORD headers_length,

-                             const void* optional_data,

-                             DWORD optional_data_length,

-                             DWORD content_length) {

-  bool res = !!winhttp_.WinHttpSendRequest(

-                            request_handle,

-                            headers,

-                            headers_length,

-                            const_cast<void*>(optional_data),

-                            optional_data_length,

-                            content_length,

-                            reinterpret_cast<DWORD_PTR>(this));

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::ReceiveResponse(HINTERNET request_handle) {

-  bool res = !!winhttp_.WinHttpReceiveResponse(request_handle, NULL);

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::QueryDataAvailable(HINTERNET request_handle,

-                                    DWORD* num_bytes) {

-  ASSERT1(num_bytes);

-

-  DWORD bytes_available = 0;

-  bool res = !!winhttp_.WinHttpQueryDataAvailable(request_handle,

-                                                  &bytes_available);

-  *num_bytes = bytes_available;

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::SetTimeouts(HINTERNET handle,

-                             int resolve_timeout_ms,

-                             int connect_timeout_ms,

-                             int send_timeout_ms,

-                             int receive_timeout_ms) {

-  bool res = !!winhttp_.WinHttpSetTimeouts(handle,

-                                           resolve_timeout_ms,

-                                           connect_timeout_ms,

-                                           send_timeout_ms,

-                                           receive_timeout_ms);

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::ReadData(HINTERNET request_handle,

-                         void* buffer,

-                         DWORD buffer_length,

-                         DWORD* bytes_read) {

-  ASSERT1(buffer);

-  ASSERT1(bytes_read);

-

-  DWORD bytes_read_local = 0;

-  bool res = !!winhttp_.WinHttpReadData(request_handle,

-                                        buffer,

-                                        buffer_length,

-                                        &bytes_read_local);

-  if (!res) {

-    return HRESULTFromLastError();

-  }

-  *bytes_read = bytes_read_local;

-  return S_OK;

-}

-

-HRESULT WinHttp::WriteData(HINTERNET request_handle,

-                           const void* buffer,

-                           DWORD bytes_to_write,

-                           DWORD* bytes_written) {

-  ASSERT1(buffer);

-  ASSERT1(bytes_written);

-

-  DWORD bytes_written_local = 0;

-  bool res = !!winhttp_.WinHttpWriteData(request_handle,

-                                         buffer,

-                                         bytes_to_write,

-                                         &bytes_written_local);

-  *bytes_written = bytes_written_local;

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::SetCredentials(HINTERNET request_handle,

-                                uint32 auth_targets,

-                                uint32 auth_scheme,

-                                const TCHAR* user_name,

-                                const TCHAR* password) {

-  bool res = !!winhttp_.WinHttpSetCredentials(request_handle,

-                                              auth_targets,

-                                              auth_scheme,

-                                              user_name,

-                                              password,

-                                              NULL);

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::DetectAutoProxyConfigUrl(uint32 flags,

-                                          CString* auto_config_url) {

-  ASSERT1(auto_config_url);

-  TCHAR* url = NULL;

-  bool res = !!winhttp_.WinHttpDetectAutoProxyConfigUrl(flags, &url);

-  *auto_config_url = url;

-  HRESULT hr = res ? S_OK : HRESULTFromLastError();

-  if (url) {

-    VERIFY1(!::GlobalFree(url));

-  }

-  return hr;

-}

-

-HRESULT WinHttp::GetDefaultProxyConfiguration(ProxyInfo* proxy_info) {

-  ASSERT1(proxy_info);

-

-  WINHTTP_PROXY_INFO pi = {0};

-  bool res = !!winhttp_.WinHttpGetDefaultProxyConfiguration(&pi);

-

-  proxy_info->access_type  = pi.dwAccessType;

-  proxy_info->proxy        = pi.lpszProxy;

-  proxy_info->proxy_bypass = pi.lpszProxyBypass;

-

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::SetDefaultProxyConfiguration(const ProxyInfo& proxy_info) {

-  WINHTTP_PROXY_INFO pi = {0};

-  pi.dwAccessType    = proxy_info.access_type;

-  pi.lpszProxy       = const_cast<TCHAR*>(proxy_info.proxy);

-  pi.lpszProxyBypass = const_cast<TCHAR*>(proxy_info.proxy_bypass);

-

-  bool res = !!winhttp_.WinHttpSetDefaultProxyConfiguration(&pi);

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::GetIEProxyConfiguration(CurrentUserIEProxyConfig* proxy_info) {

-  ASSERT1(proxy_info);

-

-  WINHTTP_CURRENT_USER_IE_PROXY_CONFIG pi = {0};

-  bool res = !!winhttp_.WinHttpGetIEProxyConfigForCurrentUser(&pi);

-

-  proxy_info->auto_detect     = !!pi.fAutoDetect;

-  proxy_info->auto_config_url = pi.lpszAutoConfigUrl;

-  proxy_info->proxy           = pi.lpszProxy;

-  proxy_info->proxy_bypass    = pi.lpszProxyBypass;

-

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::GetProxyForUrl(HINTERNET session_handle,

-                                const TCHAR* url,

-                                const AutoProxyOptions* auto_proxy_options,

-                                ProxyInfo* proxy_info) {

-  ASSERT1(auto_proxy_options);

-  ASSERT1(proxy_info);

-

-  WINHTTP_AUTOPROXY_OPTIONS apo = {0};

-  apo.dwFlags                = auto_proxy_options->flags;

-  apo.dwAutoDetectFlags      = auto_proxy_options->auto_detect_flags;

-  apo.lpszAutoConfigUrl      = auto_proxy_options->auto_config_url;

-  apo.lpvReserved            = NULL;

-  apo.dwReserved             = 0;

-  apo.fAutoLogonIfChallenged = auto_proxy_options->auto_logon_if_challenged;

-

-  WINHTTP_PROXY_INFO pi = {0};

-

-  ASSERT1(session_handle);

-  bool res = !!winhttp_.WinHttpGetProxyForUrl(session_handle, url, &apo, &pi);

-

-  proxy_info->access_type  = pi.dwAccessType;

-  proxy_info->proxy        = pi.lpszProxy;

-  proxy_info->proxy_bypass = pi.lpszProxyBypass;

-

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::QueryAuthSchemes(HINTERNET request_handle,

-                                  uint32* supported_schemes,

-                                  uint32* first_scheme,

-                                  uint32* auth_target) {

-  ASSERT1(supported_schemes);

-  ASSERT1(first_scheme);

-  ASSERT1(auth_target);

-

-  DWORD ss = 0;

-  DWORD fs = 0;

-  DWORD at = 0;

-

-  ASSERT1(request_handle);

-  bool res = !!winhttp_.WinHttpQueryAuthSchemes(request_handle, &ss, &fs, &at);

-

-  *supported_schemes = ss;

-  *first_scheme      = fs;

-  *auth_target       = at;

-

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::AddRequestHeaders(HINTERNET request_handle,

-                                   const TCHAR* headers,

-                                   int length,

-                                   uint32 modifiers) {

-  ASSERT1(headers);

-  bool res = !!winhttp_.WinHttpAddRequestHeaders(request_handle,

-                                                 headers,

-                                                 length,

-                                                 modifiers);

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::CrackUrl(const TCHAR* url,

-                          uint32 flags,

-                          CString* scheme,

-                          CString* server,

-                          int* port,

-                          CString* url_path,

-                          CString* extra_info) {

-  ASSERT1(url);

-  size_t url_length = _tcslen(url);

-  URL_COMPONENTS url_comp = {0};

-  url_comp.dwStructSize   = sizeof(url_comp);

-  if (scheme) {

-    url_comp.lpszScheme     = scheme->GetBuffer(INTERNET_MAX_SCHEME_LENGTH);

-    url_comp.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;

-  }

-  if (server) {

-    url_comp.lpszHostName    = server->GetBuffer(INTERNET_MAX_HOST_NAME_LENGTH);

-    url_comp.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;

-  }

-  if (url_path) {

-    url_comp.lpszUrlPath     = url_path->GetBuffer(INTERNET_MAX_PATH_LENGTH);

-    url_comp.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;

-  }

-  if (extra_info) {

-    // There is no constant for the extra info max length.

-    url_comp.lpszExtraInfo    = extra_info->GetBuffer(INTERNET_MAX_PATH_LENGTH);

-    url_comp.dwExtraInfoLength = INTERNET_MAX_PATH_LENGTH;

-  }

-  bool res = !!winhttp_.WinHttpCrackUrl(url, url_length, flags, &url_comp);

-  if (scheme) {

-    scheme->ReleaseBuffer(url_comp.dwSchemeLength);

-  }

-  if (server) {

-    server->ReleaseBuffer(url_comp.dwHostNameLength);

-  }

-  if (port) {

-    *port = url_comp.nPort;

-  }

-  if (url_path) {

-    url_path->ReleaseBuffer(url_comp.dwUrlPathLength);

-  }

-  if (extra_info) {

-    extra_info->ReleaseBuffer(url_comp.dwExtraInfoLength);

-  }

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::CreateUrl(const TCHAR* scheme,

-                           const TCHAR* server,

-                           int port,

-                           const TCHAR* url_path,

-                           const TCHAR* extra_info,

-                           uint32 flags,

-                           CString* url) {

-  ASSERT1(url);

-  ASSERT1(port <= INTERNET_MAX_PORT_NUMBER_VALUE);

-

-  URL_COMPONENTS url_comp = {0};

-  url_comp.dwStructSize   = sizeof(url_comp);

-  if (scheme) {

-    url_comp.lpszScheme        = const_cast<TCHAR*>(scheme);

-    url_comp.dwSchemeLength    = _tcslen(scheme);

-  }

-  if (server) {

-    url_comp.lpszHostName      = const_cast<TCHAR*>(server);

-    url_comp.dwHostNameLength  = _tcslen(server);

-  }

-  if (port) {

-    url_comp.nPort             = static_cast<INTERNET_PORT>(port);

-  }

-  if (url_path) {

-    url_comp.lpszUrlPath       = const_cast<TCHAR*>(url_path);

-    url_comp.dwUrlPathLength   = _tcslen(url_path);

-  }

-  if (extra_info) {

-    url_comp.lpszExtraInfo     = const_cast<TCHAR*>(extra_info);

-    url_comp.dwExtraInfoLength = _tcslen(extra_info);

-  }

-

-  DWORD url_length = 0;

-  bool res = !!winhttp_.WinHttpCreateUrl(

-                            &url_comp,

-                            flags,

-                            url->GetBuffer(INTERNET_MAX_URL_LENGTH),

-                            &url_length);

-  if (!res) {

-    return HRESULTFromLastError();

-  }

-  ASSERT1(url_length);

-  url->ReleaseBuffer(url_length);

-  return S_OK;

-}

-

-HttpClient::StatusCallback WinHttp::SetStatusCallback(HINTERNET handle,

-                                                      StatusCallback callback,

-                                                      uint32 flags) {

-  WINHTTP_STATUS_CALLBACK winhttp_status_callback =

-      winhttp_.WinHttpSetStatusCallback(

-          handle,

-          reinterpret_cast<WINHTTP_STATUS_CALLBACK>(callback),

-          flags,

-          NULL);

-  return reinterpret_cast<HttpClient::StatusCallback>(winhttp_status_callback);

-}

-

-HRESULT WinHttp::CheckPlatform() {

-  return !!winhttp_.WinHttpCheckPlatform() ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::QueryHeaders(HINTERNET request_handle,

-                              uint32 info_level,

-                              const TCHAR* name,

-                              void* buffer,

-                              DWORD* buffer_length,

-                              DWORD* index) {

-  ASSERT1(buffer_length);

-  bool res = !!winhttp_.WinHttpQueryHeaders(request_handle,

-                                            info_level,

-                                            name,

-                                            buffer,

-                                            buffer_length,

-                                            index);

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::QueryOption(HINTERNET handle,

-                             uint32 option,

-                             void* buffer,

-                             DWORD* buffer_length) {

-  ASSERT1(buffer_length);

-  bool res = !!winhttp_.WinHttpQueryOption(handle, option,

-                                           buffer, buffer_length);

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT WinHttp::SetOption(HINTERNET handle,

-                           uint32 option,

-                           const void* buffer,

-                           DWORD buffer_length) {

-  ASSERT1(buffer);

-  ASSERT1(buffer_length);

-  bool res = !!winhttp_.WinHttpSetOption(handle,

-                                         option,

-                                         const_cast<void*>(buffer),

-                                         buffer_length);

-  return res ? S_OK : HRESULTFromLastError();

-}

-

-extern "C" const bool kRegisterWinHttp =

-    HttpClient::GetFactory().Register(HttpClient::WINHTTP, &WinHttp::Create);

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Internet-access utility functions via winhttp
+
+#include "omaha/net/http_client.h"
+
+#include <vector>                   // NOLINT
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/utils.h"
+#include "omaha/net/winhttp_vtable.h"
+
+namespace omaha {
+
+class WinHttp : public HttpClient {
+ public:
+  static HttpClient* Create() { return new WinHttp; }
+
+  virtual HRESULT Initialize();
+  virtual HRESULT AddRequestHeaders(HINTERNET request,
+                                    const TCHAR* headers,
+                                    int length,
+                                    uint32 modifiers);
+  virtual HRESULT CheckPlatform();
+  virtual HRESULT Close(HINTERNET handle);
+  virtual HRESULT Connect(HINTERNET session_handle,
+                          const TCHAR* server,
+                          int port,
+                          HINTERNET* connection_handle);
+  virtual HRESULT CrackUrl(const TCHAR* url,
+                           uint32 flags,
+                           CString* scheme,
+                           CString* server,
+                           int* port,
+                           CString* url_path,
+                           CString* extra_info);
+  virtual HRESULT CreateUrl(const TCHAR* scheme,
+                            const TCHAR* server,
+                            int port,
+                            const TCHAR* url_path,
+                            const TCHAR* extra_info,
+                            uint32 flags,
+                            CString* url);
+  virtual HRESULT DetectAutoProxyConfigUrl(uint32 flags,
+                                           CString* auto_config_url);
+  virtual HRESULT GetDefaultProxyConfiguration(ProxyInfo* proxy_info);
+  virtual HRESULT GetIEProxyConfiguration(
+                      CurrentUserIEProxyConfig* proxy_info);
+  virtual HRESULT GetProxyForUrl(HINTERNET session_handle,
+                                 const TCHAR* url,
+                                 const AutoProxyOptions* auto_proxy_options,
+                                 ProxyInfo* proxy_info);
+  virtual HRESULT Open(const TCHAR* user_agent,
+                       uint32 access_type,
+                       const TCHAR* proxy_name,
+                       const TCHAR* proxy_bypass,
+                       HINTERNET* session_handle);
+  virtual HRESULT OpenRequest(HINTERNET connection_handle,
+                              const TCHAR* verb,
+                              const TCHAR* uri,
+                              const TCHAR* version,
+                              const TCHAR* referrer,
+                              const TCHAR** accept_types,
+                              uint32 flags,
+                              HINTERNET* request_handle);
+  virtual HRESULT QueryAuthSchemes(HINTERNET request_handle,
+                                   uint32* supported_schemes,
+                                   uint32* first_scheme,
+                                   uint32* auth_target);
+  virtual HRESULT QueryDataAvailable(HINTERNET request_handle,
+                                     DWORD* num_bytes);
+  virtual HRESULT QueryHeaders(HINTERNET request_handle,
+                               uint32 info_level,
+                               const TCHAR* name,
+                               void* buffer,
+                               DWORD* buffer_length,
+                               DWORD* index);
+  virtual HRESULT QueryOption(HINTERNET handle,
+                              uint32 option,
+                              void* buffer,
+                              DWORD* buffer_length);
+  virtual HRESULT ReadData(HINTERNET request_handle,
+                           void* buffer,
+                           DWORD buffer_length,
+                           DWORD* bytes_read);
+  virtual HRESULT ReceiveResponse(HINTERNET request_handle);
+  virtual HRESULT SendRequest(HINTERNET request_handle,
+                              const TCHAR* headers,
+                              DWORD headers_length,
+                              const void* optional_data,
+                              DWORD optional_data_length,
+                              DWORD content_length);
+  virtual HRESULT SetCredentials(HINTERNET request_handle,
+                                 uint32 auth_targets,
+                                 uint32 auth_scheme,
+                                 const TCHAR* user_name,
+                                 const TCHAR* password);
+  virtual HRESULT SetDefaultProxyConfiguration(const ProxyInfo& proxy_info);
+  virtual HRESULT SetOption(HINTERNET handle,
+                            uint32 option,
+                            const void* buffer,
+                            DWORD buffer_length);
+  virtual StatusCallback SetStatusCallback(HINTERNET handle,
+                                           StatusCallback callback,
+                                           uint32 flags);
+  virtual HRESULT SetTimeouts(HINTERNET handle,
+                              int resolve_timeout_ms,
+                              int connect_timeout_ms,
+                              int send_timeout_ms,
+                              int receive_timeout_ms);
+  virtual HRESULT WriteData(HINTERNET request_handle,
+                            const void* buffer,
+                            DWORD bytes_to_write,
+                            DWORD* bytes_written);
+
+ private:
+  WinHttp();
+
+  bool is_initialized_;
+
+  static WinHttpVTable winhttp_;
+  static LLock lock_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(WinHttp);
+};
+
+WinHttpVTable WinHttp::winhttp_;
+LLock         WinHttp::lock_;
+
+// TODO(omaha): remove after the implementation is complete.
+// 4100: unreferenced formal parameter
+#pragma warning(disable : 4100)
+
+WinHttp::WinHttp() : is_initialized_(false) {
+}
+
+HRESULT WinHttp::Initialize() {
+  if (is_initialized_) {
+    return S_OK;
+  }
+  __mutexBlock(WinHttp::lock_) {
+    if (!winhttp_.Load()) {
+      HRESULT hr = HRESULTFromLastError();
+      NET_LOG(LEVEL_ERROR, (_T("[failed to load winhttp][0x%08x]"), hr));
+      return hr;
+    }
+  }
+  is_initialized_ = true;
+  return S_OK;
+}
+
+HRESULT WinHttp::Open(const TCHAR* user_agent,
+                      uint32 access_type,
+                      const TCHAR* proxy_name,
+                      const TCHAR* proxy_bypass,
+                      HINTERNET* session_handle) {
+  *session_handle = winhttp_.WinHttpOpen(user_agent,
+                                         access_type,
+                                         proxy_name,
+                                         proxy_bypass,
+                                         0);   // Synchronous mode always.
+  return *session_handle ? S_OK : HRESULTFromLastError();
+}
+
+// Quoting from the MSDN documentation:
+//    "Operations on a WinHTTP request handle should be synchronized.
+//    For example, an application should avoid closing a request handle on one
+//    thread while another thread is sending or receiving a request.
+//    To terminate an asynchronous request, close the request handle during
+//    a callback notification. To terminate a synchronous request, close the
+//    handle when the previous WinHTTP call returns."
+// Synchronizing on the request handle adds quite a bit of complexity to the
+// code. Blocking WinHTTP calls can block for quite a while: by default the
+// connect time out is 60 seconds, the send or receive timeout is 30 seconds,
+// and the receive response timeout is 90 seconds. Waiting as much to
+// cancel a request in progress is not acceptable. We noticed that closing
+// the request handle from a different thread makes the blocking WinHTTP
+// thread return right away. We are not fixing this for now, as the benefit
+// seems to be minimal while increasing the complexity of the code.
+HRESULT WinHttp::Close(HINTERNET handle) {
+  ASSERT1(handle);
+  return winhttp_.WinHttpCloseHandle(handle) ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::Connect(HINTERNET session_handle,
+                         const TCHAR* server,
+                         int port,
+                         HINTERNET* connection_handle) {
+  ASSERT1(server);
+  ASSERT1(port <= INTERNET_MAX_PORT_NUMBER_VALUE);
+
+  *connection_handle = winhttp_.WinHttpConnect(session_handle,
+                                              server,
+                                              static_cast<INTERNET_PORT>(port),
+                                              0);
+  return *connection_handle ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::OpenRequest(HINTERNET connection_handle,
+                             const TCHAR* verb,
+                             const TCHAR* uri,
+                             const TCHAR* version,
+                             const TCHAR* referrer,
+                             const TCHAR** accept_types,
+                             uint32 flags,
+                             HINTERNET* request_handle) {
+  *request_handle = winhttp_.WinHttpOpenRequest(connection_handle,
+                                                verb,
+                                                uri,
+                                                version,
+                                                referrer,
+                                                accept_types,
+                                                flags);
+  return *request_handle ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::SendRequest(HINTERNET request_handle,
+                             const TCHAR* headers,
+                             DWORD headers_length,
+                             const void* optional_data,
+                             DWORD optional_data_length,
+                             DWORD content_length) {
+  bool res = !!winhttp_.WinHttpSendRequest(
+                            request_handle,
+                            headers,
+                            headers_length,
+                            const_cast<void*>(optional_data),
+                            optional_data_length,
+                            content_length,
+                            reinterpret_cast<DWORD_PTR>(this));
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::ReceiveResponse(HINTERNET request_handle) {
+  bool res = !!winhttp_.WinHttpReceiveResponse(request_handle, NULL);
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::QueryDataAvailable(HINTERNET request_handle,
+                                    DWORD* num_bytes) {
+  ASSERT1(num_bytes);
+
+  DWORD bytes_available = 0;
+  bool res = !!winhttp_.WinHttpQueryDataAvailable(request_handle,
+                                                  &bytes_available);
+  *num_bytes = bytes_available;
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::SetTimeouts(HINTERNET handle,
+                             int resolve_timeout_ms,
+                             int connect_timeout_ms,
+                             int send_timeout_ms,
+                             int receive_timeout_ms) {
+  bool res = !!winhttp_.WinHttpSetTimeouts(handle,
+                                           resolve_timeout_ms,
+                                           connect_timeout_ms,
+                                           send_timeout_ms,
+                                           receive_timeout_ms);
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::ReadData(HINTERNET request_handle,
+                         void* buffer,
+                         DWORD buffer_length,
+                         DWORD* bytes_read) {
+  ASSERT1(buffer);
+  ASSERT1(bytes_read);
+
+  DWORD bytes_read_local = 0;
+  bool res = !!winhttp_.WinHttpReadData(request_handle,
+                                        buffer,
+                                        buffer_length,
+                                        &bytes_read_local);
+  if (!res) {
+    return HRESULTFromLastError();
+  }
+  *bytes_read = bytes_read_local;
+  return S_OK;
+}
+
+HRESULT WinHttp::WriteData(HINTERNET request_handle,
+                           const void* buffer,
+                           DWORD bytes_to_write,
+                           DWORD* bytes_written) {
+  ASSERT1(buffer);
+  ASSERT1(bytes_written);
+
+  DWORD bytes_written_local = 0;
+  bool res = !!winhttp_.WinHttpWriteData(request_handle,
+                                         buffer,
+                                         bytes_to_write,
+                                         &bytes_written_local);
+  *bytes_written = bytes_written_local;
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::SetCredentials(HINTERNET request_handle,
+                                uint32 auth_targets,
+                                uint32 auth_scheme,
+                                const TCHAR* user_name,
+                                const TCHAR* password) {
+  bool res = !!winhttp_.WinHttpSetCredentials(request_handle,
+                                              auth_targets,
+                                              auth_scheme,
+                                              user_name,
+                                              password,
+                                              NULL);
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::DetectAutoProxyConfigUrl(uint32 flags,
+                                          CString* auto_config_url) {
+  ASSERT1(auto_config_url);
+  TCHAR* url = NULL;
+  bool res = !!winhttp_.WinHttpDetectAutoProxyConfigUrl(flags, &url);
+  *auto_config_url = url;
+  HRESULT hr = res ? S_OK : HRESULTFromLastError();
+  if (url) {
+    VERIFY1(!::GlobalFree(url));
+  }
+  return hr;
+}
+
+HRESULT WinHttp::GetDefaultProxyConfiguration(ProxyInfo* proxy_info) {
+  ASSERT1(proxy_info);
+
+  WINHTTP_PROXY_INFO pi = {0};
+  bool res = !!winhttp_.WinHttpGetDefaultProxyConfiguration(&pi);
+
+  proxy_info->access_type  = pi.dwAccessType;
+  proxy_info->proxy        = pi.lpszProxy;
+  proxy_info->proxy_bypass = pi.lpszProxyBypass;
+
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::SetDefaultProxyConfiguration(const ProxyInfo& proxy_info) {
+  WINHTTP_PROXY_INFO pi = {0};
+  pi.dwAccessType    = proxy_info.access_type;
+  pi.lpszProxy       = const_cast<TCHAR*>(proxy_info.proxy);
+  pi.lpszProxyBypass = const_cast<TCHAR*>(proxy_info.proxy_bypass);
+
+  bool res = !!winhttp_.WinHttpSetDefaultProxyConfiguration(&pi);
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::GetIEProxyConfiguration(CurrentUserIEProxyConfig* proxy_info) {
+  ASSERT1(proxy_info);
+
+  WINHTTP_CURRENT_USER_IE_PROXY_CONFIG pi = {0};
+  bool res = !!winhttp_.WinHttpGetIEProxyConfigForCurrentUser(&pi);
+
+  proxy_info->auto_detect     = !!pi.fAutoDetect;
+  proxy_info->auto_config_url = pi.lpszAutoConfigUrl;
+  proxy_info->proxy           = pi.lpszProxy;
+  proxy_info->proxy_bypass    = pi.lpszProxyBypass;
+
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::GetProxyForUrl(HINTERNET session_handle,
+                                const TCHAR* url,
+                                const AutoProxyOptions* auto_proxy_options,
+                                ProxyInfo* proxy_info) {
+  ASSERT1(auto_proxy_options);
+  ASSERT1(proxy_info);
+
+  WINHTTP_AUTOPROXY_OPTIONS apo = {0};
+  apo.dwFlags                = auto_proxy_options->flags;
+  apo.dwAutoDetectFlags      = auto_proxy_options->auto_detect_flags;
+  apo.lpszAutoConfigUrl      = auto_proxy_options->auto_config_url;
+  apo.lpvReserved            = NULL;
+  apo.dwReserved             = 0;
+  apo.fAutoLogonIfChallenged = auto_proxy_options->auto_logon_if_challenged;
+
+  WINHTTP_PROXY_INFO pi = {0};
+
+  ASSERT1(session_handle);
+  bool res = !!winhttp_.WinHttpGetProxyForUrl(session_handle, url, &apo, &pi);
+
+  proxy_info->access_type  = pi.dwAccessType;
+  proxy_info->proxy        = pi.lpszProxy;
+  proxy_info->proxy_bypass = pi.lpszProxyBypass;
+
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::QueryAuthSchemes(HINTERNET request_handle,
+                                  uint32* supported_schemes,
+                                  uint32* first_scheme,
+                                  uint32* auth_target) {
+  ASSERT1(supported_schemes);
+  ASSERT1(first_scheme);
+  ASSERT1(auth_target);
+
+  DWORD ss = 0;
+  DWORD fs = 0;
+  DWORD at = 0;
+
+  ASSERT1(request_handle);
+  bool res = !!winhttp_.WinHttpQueryAuthSchemes(request_handle, &ss, &fs, &at);
+
+  *supported_schemes = ss;
+  *first_scheme      = fs;
+  *auth_target       = at;
+
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::AddRequestHeaders(HINTERNET request_handle,
+                                   const TCHAR* headers,
+                                   int length,
+                                   uint32 modifiers) {
+  ASSERT1(headers);
+  bool res = !!winhttp_.WinHttpAddRequestHeaders(request_handle,
+                                                 headers,
+                                                 length,
+                                                 modifiers);
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::CrackUrl(const TCHAR* url,
+                          uint32 flags,
+                          CString* scheme,
+                          CString* server,
+                          int* port,
+                          CString* url_path,
+                          CString* extra_info) {
+  ASSERT1(url);
+  size_t url_length = _tcslen(url);
+  URL_COMPONENTS url_comp = {0};
+  url_comp.dwStructSize   = sizeof(url_comp);
+  if (scheme) {
+    url_comp.lpszScheme     = scheme->GetBuffer(INTERNET_MAX_SCHEME_LENGTH);
+    url_comp.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;
+  }
+  if (server) {
+    url_comp.lpszHostName    = server->GetBuffer(INTERNET_MAX_HOST_NAME_LENGTH);
+    url_comp.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
+  }
+  if (url_path) {
+    url_comp.lpszUrlPath     = url_path->GetBuffer(INTERNET_MAX_PATH_LENGTH);
+    url_comp.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
+  }
+  if (extra_info) {
+    // There is no constant for the extra info max length.
+    url_comp.lpszExtraInfo    = extra_info->GetBuffer(INTERNET_MAX_PATH_LENGTH);
+    url_comp.dwExtraInfoLength = INTERNET_MAX_PATH_LENGTH;
+  }
+  bool res = !!winhttp_.WinHttpCrackUrl(url, url_length, flags, &url_comp);
+  if (scheme) {
+    scheme->ReleaseBuffer(url_comp.dwSchemeLength);
+  }
+  if (server) {
+    server->ReleaseBuffer(url_comp.dwHostNameLength);
+  }
+  if (port) {
+    *port = url_comp.nPort;
+  }
+  if (url_path) {
+    url_path->ReleaseBuffer(url_comp.dwUrlPathLength);
+  }
+  if (extra_info) {
+    extra_info->ReleaseBuffer(url_comp.dwExtraInfoLength);
+  }
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::CreateUrl(const TCHAR* scheme,
+                           const TCHAR* server,
+                           int port,
+                           const TCHAR* url_path,
+                           const TCHAR* extra_info,
+                           uint32 flags,
+                           CString* url) {
+  ASSERT1(url);
+  ASSERT1(port <= INTERNET_MAX_PORT_NUMBER_VALUE);
+
+  URL_COMPONENTS url_comp = {0};
+  url_comp.dwStructSize   = sizeof(url_comp);
+  if (scheme) {
+    url_comp.lpszScheme        = const_cast<TCHAR*>(scheme);
+    url_comp.dwSchemeLength    = _tcslen(scheme);
+  }
+  if (server) {
+    url_comp.lpszHostName      = const_cast<TCHAR*>(server);
+    url_comp.dwHostNameLength  = _tcslen(server);
+  }
+  if (port) {
+    url_comp.nPort             = static_cast<INTERNET_PORT>(port);
+  }
+  if (url_path) {
+    url_comp.lpszUrlPath       = const_cast<TCHAR*>(url_path);
+    url_comp.dwUrlPathLength   = _tcslen(url_path);
+  }
+  if (extra_info) {
+    url_comp.lpszExtraInfo     = const_cast<TCHAR*>(extra_info);
+    url_comp.dwExtraInfoLength = _tcslen(extra_info);
+  }
+
+  DWORD url_length = 0;
+  bool res = !!winhttp_.WinHttpCreateUrl(
+                            &url_comp,
+                            flags,
+                            url->GetBuffer(INTERNET_MAX_URL_LENGTH),
+                            &url_length);
+  if (!res) {
+    return HRESULTFromLastError();
+  }
+  ASSERT1(url_length);
+  url->ReleaseBuffer(url_length);
+  return S_OK;
+}
+
+HttpClient::StatusCallback WinHttp::SetStatusCallback(HINTERNET handle,
+                                                      StatusCallback callback,
+                                                      uint32 flags) {
+  WINHTTP_STATUS_CALLBACK winhttp_status_callback =
+      winhttp_.WinHttpSetStatusCallback(
+          handle,
+          reinterpret_cast<WINHTTP_STATUS_CALLBACK>(callback),
+          flags,
+          NULL);
+  return reinterpret_cast<HttpClient::StatusCallback>(winhttp_status_callback);
+}
+
+HRESULT WinHttp::CheckPlatform() {
+  return !!winhttp_.WinHttpCheckPlatform() ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::QueryHeaders(HINTERNET request_handle,
+                              uint32 info_level,
+                              const TCHAR* name,
+                              void* buffer,
+                              DWORD* buffer_length,
+                              DWORD* index) {
+  ASSERT1(buffer_length);
+  bool res = !!winhttp_.WinHttpQueryHeaders(request_handle,
+                                            info_level,
+                                            name,
+                                            buffer,
+                                            buffer_length,
+                                            index);
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::QueryOption(HINTERNET handle,
+                             uint32 option,
+                             void* buffer,
+                             DWORD* buffer_length) {
+  ASSERT1(buffer_length);
+  bool res = !!winhttp_.WinHttpQueryOption(handle, option,
+                                           buffer, buffer_length);
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT WinHttp::SetOption(HINTERNET handle,
+                           uint32 option,
+                           const void* buffer,
+                           DWORD buffer_length) {
+  ASSERT1(buffer);
+  ASSERT1(buffer_length);
+  bool res = !!winhttp_.WinHttpSetOption(handle,
+                                         option,
+                                         const_cast<void*>(buffer),
+                                         buffer_length);
+  return res ? S_OK : HRESULTFromLastError();
+}
+
+extern "C" const bool kRegisterWinHttp =
+    HttpClient::GetFactory().Register(HttpClient::WINHTTP, &WinHttp::Create);
+
+}  // namespace omaha
+
diff --git a/net/winhttp_vtable.cc b/net/winhttp_vtable.cc
index a3eeeab..4b1b835 100644
--- a/net/winhttp_vtable.cc
+++ b/net/winhttp_vtable.cc
@@ -1,74 +1,74 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/net/winhttp_vtable.h"

-

-namespace omaha {

-

-bool WinHttpVTable::Load() {

-  if (IsLoaded()) {

-    return true;

-  }

-  Clear();

-  library_ = ::LoadLibrary(_T("winhttp"));

-  if (!library_) {

-    library_ = ::LoadLibrary(_T("winhttp5"));

-    if (!library_) {

-      return false;

-    }

-  }

-  bool is_valid =

-     GPA("WinHttpAddRequestHeaders",       &WinHttpAddRequestHeaders_pointer) &&

-     GPA("WinHttpCheckPlatform",           &WinHttpCheckPlatform_pointer) &&

-     GPA("WinHttpCloseHandle",             &WinHttpCloseHandle_pointer) &&

-     GPA("WinHttpConnect",                 &WinHttpConnect_pointer) &&

-     GPA("WinHttpCrackUrl",                &WinHttpCrackUrl_pointer) &&

-     GPA("WinHttpCreateUrl",               &WinHttpCreateUrl_pointer) &&

-     GPA("WinHttpDetectAutoProxyConfigUrl", &WinHttpDetectAutoProxyConfigUrl_pointer) &&    // NOLINT

-     GPA("WinHttpGetIEProxyConfigForCurrentUser", &WinHttpGetIEProxyConfigForCurrentUser_pointer) &&    // NOLINT

-     GPA("WinHttpGetDefaultProxyConfiguration", &WinHttpGetDefaultProxyConfiguration_pointer) &&    // NOLINT

-     GPA("WinHttpGetProxyForUrl",          &WinHttpGetProxyForUrl_pointer) &&

-     GPA("WinHttpOpen",                    &WinHttpOpen_pointer) &&

-     GPA("WinHttpOpenRequest",             &WinHttpOpenRequest_pointer) &&

-     GPA("WinHttpQueryAuthSchemes",        &WinHttpQueryAuthSchemes_pointer) &&

-     GPA("WinHttpQueryDataAvailable",      &WinHttpQueryDataAvailable_pointer) &&   // NOLINT

-     GPA("WinHttpQueryHeaders",            &WinHttpQueryHeaders_pointer) &&

-     GPA("WinHttpQueryOption",             &WinHttpQueryOption_pointer) &&

-     GPA("WinHttpReadData",                &WinHttpReadData_pointer) &&

-     GPA("WinHttpReceiveResponse",         &WinHttpReceiveResponse_pointer) &&

-     GPA("WinHttpSendRequest",             &WinHttpSendRequest_pointer) &&

-     GPA("WinHttpSetDefaultProxyConfiguration", &WinHttpSetDefaultProxyConfiguration_pointer) &&    // NOLINT

-     GPA("WinHttpSetCredentials",          &WinHttpSetCredentials_pointer) &&

-     GPA("WinHttpSetOption",               &WinHttpSetOption_pointer) &&

-     GPA("WinHttpSetStatusCallback",       &WinHttpSetStatusCallback_pointer) &&

-     GPA("WinHttpSetTimeouts",             &WinHttpSetTimeouts_pointer) &&

-     GPA("WinHttpWriteData",               &WinHttpWriteData_pointer);

-

-  if (!is_valid) {

-    Unload();

-  }

-  return is_valid;

-}

-

-void WinHttpVTable::Unload() {

-  if (library_) {

-    ::FreeLibrary(library_);

-    library_ = NULL;

-  }

-  Clear();

-}

-

-}   // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/net/winhttp_vtable.h"
+
+namespace omaha {
+
+bool WinHttpVTable::Load() {
+  if (IsLoaded()) {
+    return true;
+  }
+  Clear();
+  library_ = ::LoadLibrary(_T("winhttp"));
+  if (!library_) {
+    library_ = ::LoadLibrary(_T("winhttp5"));
+    if (!library_) {
+      return false;
+    }
+  }
+  bool is_valid =
+     GPA("WinHttpAddRequestHeaders",       &WinHttpAddRequestHeaders_pointer) &&
+     GPA("WinHttpCheckPlatform",           &WinHttpCheckPlatform_pointer) &&
+     GPA("WinHttpCloseHandle",             &WinHttpCloseHandle_pointer) &&
+     GPA("WinHttpConnect",                 &WinHttpConnect_pointer) &&
+     GPA("WinHttpCrackUrl",                &WinHttpCrackUrl_pointer) &&
+     GPA("WinHttpCreateUrl",               &WinHttpCreateUrl_pointer) &&
+     GPA("WinHttpDetectAutoProxyConfigUrl", &WinHttpDetectAutoProxyConfigUrl_pointer) &&    // NOLINT
+     GPA("WinHttpGetIEProxyConfigForCurrentUser", &WinHttpGetIEProxyConfigForCurrentUser_pointer) &&    // NOLINT
+     GPA("WinHttpGetDefaultProxyConfiguration", &WinHttpGetDefaultProxyConfiguration_pointer) &&    // NOLINT
+     GPA("WinHttpGetProxyForUrl",          &WinHttpGetProxyForUrl_pointer) &&
+     GPA("WinHttpOpen",                    &WinHttpOpen_pointer) &&
+     GPA("WinHttpOpenRequest",             &WinHttpOpenRequest_pointer) &&
+     GPA("WinHttpQueryAuthSchemes",        &WinHttpQueryAuthSchemes_pointer) &&
+     GPA("WinHttpQueryDataAvailable",      &WinHttpQueryDataAvailable_pointer) &&   // NOLINT
+     GPA("WinHttpQueryHeaders",            &WinHttpQueryHeaders_pointer) &&
+     GPA("WinHttpQueryOption",             &WinHttpQueryOption_pointer) &&
+     GPA("WinHttpReadData",                &WinHttpReadData_pointer) &&
+     GPA("WinHttpReceiveResponse",         &WinHttpReceiveResponse_pointer) &&
+     GPA("WinHttpSendRequest",             &WinHttpSendRequest_pointer) &&
+     GPA("WinHttpSetDefaultProxyConfiguration", &WinHttpSetDefaultProxyConfiguration_pointer) &&    // NOLINT
+     GPA("WinHttpSetCredentials",          &WinHttpSetCredentials_pointer) &&
+     GPA("WinHttpSetOption",               &WinHttpSetOption_pointer) &&
+     GPA("WinHttpSetStatusCallback",       &WinHttpSetStatusCallback_pointer) &&
+     GPA("WinHttpSetTimeouts",             &WinHttpSetTimeouts_pointer) &&
+     GPA("WinHttpWriteData",               &WinHttpWriteData_pointer);
+
+  if (!is_valid) {
+    Unload();
+  }
+  return is_valid;
+}
+
+void WinHttpVTable::Unload() {
+  if (library_) {
+    ::FreeLibrary(library_);
+    library_ = NULL;
+  }
+  Clear();
+}
+
+}   // namespace omaha
+
diff --git a/net/winhttp_vtable.h b/net/winhttp_vtable.h
index 6e4491a..7799f75 100644
--- a/net/winhttp_vtable.h
+++ b/net/winhttp_vtable.h
@@ -1,181 +1,181 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// WinHttpVTable provides dynamic loading of winhttp.dll.

-

-// Runtime requirements: WinHTTP 5.1 is now an operating-system component of

-// the following systems:

-// - Windows Vista

-// - Windows Server 2003 family

-// - Windows XP SP1

-// - Windows 2000 SP3 (except Datacenter Server)

-

-#ifndef OMAHA_NET_WINHTTP_VTABLE_H__

-#define OMAHA_NET_WINHTTP_VTABLE_H__

-

-#include <windows.h>

-#include <winhttp.h>

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-class WinHttpVTable {

- public:

-  BOOL WinHttpAddRequestHeaders(HINTERNET, const TCHAR*, DWORD, DWORD);

-  BOOL WinHttpCheckPlatform();

-  BOOL WinHttpCloseHandle(HINTERNET);

-  HINTERNET WinHttpConnect(HINTERNET, const TCHAR*, INTERNET_PORT, DWORD);

-  BOOL WinHttpCrackUrl(const TCHAR*, DWORD, DWORD, URL_COMPONENTS*);

-  BOOL WinHttpCreateUrl(URL_COMPONENTS*, DWORD, TCHAR*, DWORD*);

-  BOOL WinHttpGetDefaultProxyConfiguration(WINHTTP_PROXY_INFO*);

-  BOOL WinHttpGetIEProxyConfigForCurrentUser(

-           WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*);

-  HINTERNET WinHttpOpen(const TCHAR*, DWORD, const TCHAR*, const TCHAR*, DWORD);

-  HINTERNET WinHttpOpenRequest(HINTERNET,

-                               const TCHAR*,

-                               const TCHAR*,

-                               const TCHAR*,

-                               const TCHAR*,

-                               const TCHAR**,

-                               DWORD);

-  BOOL WinHttpQueryAuthSchemes(HINTERNET, DWORD*, DWORD*, DWORD*);

-  BOOL WinHttpQueryDataAvailable(HINTERNET, DWORD*);

-  BOOL WinHttpQueryHeaders(HINTERNET,

-                           DWORD,

-                           const TCHAR*,

-                           void*,

-                           DWORD*,

-                           DWORD*);

-  BOOL WinHttpQueryOption(HINTERNET, DWORD, void*, DWORD*);

-  BOOL WinHttpReadData(HINTERNET, void*, DWORD, DWORD*);

-  BOOL WinHttpWriteData(HINTERNET, const void*, DWORD, DWORD*);

-  BOOL WinHttpReceiveResponse(HINTERNET, void*);

-  BOOL WinHttpSendRequest(HINTERNET,

-                          const TCHAR*,

-                          DWORD,

-                          void*,

-                          DWORD,

-                          DWORD,

-                          DWORD_PTR);

-  BOOL WinHttpSetCredentials(HINTERNET,

-                             DWORD,

-                             DWORD,

-                             const TCHAR*,

-                             const TCHAR*,

-                             void*);

-  BOOL WinHttpSetOption(HINTERNET, DWORD, void*, DWORD);

-  WINHTTP_STATUS_CALLBACK WinHttpSetStatusCallback(HINTERNET,

-                                                   WINHTTP_STATUS_CALLBACK,

-                                                   DWORD,

-                                                   DWORD_PTR);

-  BOOL WinHttpSetTimeouts(HINTERNET, int, int, int, int);

-  BOOL WinHttpGetProxyForUrl(HINTERNET,

-                             const TCHAR*,

-                             WINHTTP_AUTOPROXY_OPTIONS*,

-                             WINHTTP_PROXY_INFO*);

-  BOOL WinHttpDetectAutoProxyConfigUrl(DWORD, TCHAR**);

-  BOOL WinHttpSetDefaultProxyConfiguration(WINHTTP_PROXY_INFO*);

-

-  WinHttpVTable() { Clear(); }

-  ~WinHttpVTable() { Unload(); }

-

-  // Loads library, snap links.

-  bool Load();

-

-  // Unloads library, clear links.

-  void Unload();

-

-  bool IsLoaded() { return NULL != library_; }

-

- private:

-  void Clear() { memset(this, 0, sizeof(*this)); }

-

-  template <typename T>

-  bool GPA(const char* function_name, T* function_pointer) {

-    ASSERT1(function_name);

-    *function_pointer = reinterpret_cast<T>(::GetProcAddress(library_,

-                                                             function_name));

-    return NULL != *function_pointer;

-  }

-

-  // No good way to keep lines below 80 chars.

-  BOOL      (CALLBACK *WinHttpAddRequestHeaders_pointer)(HINTERNET, const TCHAR*, DWORD, DWORD);    // NOLINT

-  BOOL      (CALLBACK *WinHttpCheckPlatform_pointer)();

-  BOOL      (CALLBACK *WinHttpCloseHandle_pointer)(HINTERNET);    // NOLINT

-  HINTERNET (CALLBACK *WinHttpConnect_pointer)(HINTERNET, const TCHAR*, INTERNET_PORT, DWORD);    // NOLINT

-  BOOL      (CALLBACK *WinHttpCrackUrl_pointer)(const TCHAR*, DWORD, DWORD, URL_COMPONENTS*);    // NOLINT

-  BOOL      (CALLBACK *WinHttpCreateUrl_pointer)(URL_COMPONENTS*, DWORD, TCHAR*, DWORD*);        // NOLINT

-  BOOL      (CALLBACK *WinHttpDetectAutoProxyConfigUrl_pointer)(DWORD, TCHAR**);    // NOLINT

-  BOOL      (CALLBACK *WinHttpGetDefaultProxyConfiguration_pointer)(WINHTTP_PROXY_INFO*);    // NOLINT

-  BOOL      (CALLBACK *WinHttpGetIEProxyConfigForCurrentUser_pointer)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* pProxyConfig);    // NOLINT

-  BOOL      (CALLBACK *WinHttpGetProxyForUrl_pointer)(HINTERNET, const TCHAR*, WINHTTP_AUTOPROXY_OPTIONS*, WINHTTP_PROXY_INFO*);    // NOLINT

-  HINTERNET (CALLBACK *WinHttpOpen_pointer)(const TCHAR*, DWORD, const TCHAR*, const TCHAR*, DWORD);    // NOLINT

-  HINTERNET (CALLBACK *WinHttpOpenRequest_pointer)(HINTERNET, const TCHAR*, const TCHAR*, const TCHAR*, const TCHAR*, const TCHAR**, DWORD);    // NOLINT

-  BOOL      (CALLBACK *WinHttpQueryAuthSchemes_pointer)(HINTERNET, DWORD*, DWORD*, DWORD*);    // NOLINT

-  BOOL      (CALLBACK *WinHttpQueryDataAvailable_pointer)(HINTERNET, DWORD*);    // NOLINT

-  BOOL      (CALLBACK *WinHttpQueryHeaders_pointer)(HINTERNET, DWORD, const TCHAR*, void*, DWORD*, DWORD*);    // NOLINT

-  BOOL      (CALLBACK *WinHttpQueryOption_pointer)(HINTERNET, DWORD, void*, DWORD*);    // NOLINT

-  BOOL      (CALLBACK *WinHttpReadData_pointer)(HINTERNET, void*, DWORD, DWORD*);    // NOLINT

-  BOOL      (CALLBACK *WinHttpReceiveResponse_pointer)(HINTERNET, void*);    // NOLINT

-  BOOL      (CALLBACK *WinHttpSendRequest_pointer)(HINTERNET, const TCHAR*, DWORD, void*, DWORD, DWORD, DWORD_PTR);    // NOLINT

-  BOOL      (CALLBACK *WinHttpSetCredentials_pointer)(HINTERNET, DWORD, DWORD, const TCHAR*, const TCHAR*, void*);    // NOLINT

-  BOOL      (CALLBACK *WinHttpSetDefaultProxyConfiguration_pointer)(WINHTTP_PROXY_INFO*);   // NOLINT

-  BOOL      (CALLBACK *WinHttpSetOption_pointer)(HINTERNET, DWORD, void*, DWORD);    // NOLINT

-  BOOL      (CALLBACK *WinHttpSetTimeouts_pointer)(HINTERNET, int, int, int, int);    // NOLINT

-  BOOL      (CALLBACK *WinHttpWriteData_pointer)(HINTERNET, LPCVOID, DWORD, DWORD*);   // NOLINT

-  WINHTTP_STATUS_CALLBACK (CALLBACK *WinHttpSetStatusCallback_pointer)(HINTERNET, WINHTTP_STATUS_CALLBACK, DWORD, DWORD_PTR);    // NOLINT

-

-  HINSTANCE library_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(WinHttpVTable);

-};

-

-#define PROTECT_WRAP(function, proto, call, result_type, result_error_value)  \

-inline result_type WinHttpVTable::function proto {         \

-  return function##_pointer call;                          \

-}

-

-// No good way to keep lines below 80 chars.

-PROTECT_WRAP(WinHttpAddRequestHeaders, (HINTERNET a, const TCHAR* b, DWORD c, DWORD d), (a, b, c, d), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpCheckPlatform, (), (), BOOL, FALSE);

-PROTECT_WRAP(WinHttpCloseHandle, (HINTERNET a), (a), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpConnect, (HINTERNET a, const TCHAR* b, INTERNET_PORT c, DWORD d), (a, b, c, d), HINTERNET, NULL);    // NOLINT

-PROTECT_WRAP(WinHttpCrackUrl, (const TCHAR* a, DWORD b, DWORD c, LPURL_COMPONENTS d), (a, b, c, d), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpCreateUrl, (URL_COMPONENTS* a, DWORD b, TCHAR* c, DWORD* d), (a, b, c, d), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpDetectAutoProxyConfigUrl, (DWORD a, TCHAR** b), (a, b), BOOL, FALSE);   // NOLINT

-PROTECT_WRAP(WinHttpGetDefaultProxyConfiguration, (WINHTTP_PROXY_INFO* a), (a), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpGetIEProxyConfigForCurrentUser, (WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* a), (a),  BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpGetProxyForUrl, (HINTERNET a, const TCHAR* b, WINHTTP_AUTOPROXY_OPTIONS* c, WINHTTP_PROXY_INFO* d), (a, b, c, d), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpOpen, (const TCHAR* a, DWORD b, const TCHAR* c, const TCHAR* d, DWORD e), (a, b, c, d, e), HINTERNET, NULL);    // NOLINT

-PROTECT_WRAP(WinHttpOpenRequest, (HINTERNET a, const TCHAR* b, const TCHAR* c, const TCHAR* d, const TCHAR* e, const TCHAR** f, DWORD g), (a, b, c, d, e, f, g), HINTERNET, NULL);    // NOLINT

-PROTECT_WRAP(WinHttpQueryAuthSchemes, (HINTERNET a, DWORD* b, DWORD* c, DWORD* d), (a, b, c, d), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpQueryDataAvailable, (HINTERNET a, DWORD* b), (a, b), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpQueryHeaders, (HINTERNET a, DWORD b, const TCHAR* c, void* d, DWORD* e, DWORD* f), (a, b, c, d, e, f), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpQueryOption, (HINTERNET a, DWORD b, void* c, DWORD* d), (a, b, c, d), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpReadData, (HINTERNET a, void* b, DWORD c, DWORD* d), (a, b, c, d), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpReceiveResponse, (HINTERNET a, void* b), (a, b), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpSendRequest, (HINTERNET a, const TCHAR* b, DWORD c, void* d, DWORD e, DWORD f, DWORD_PTR g), (a, b, c, d, e, f, g), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpSetCredentials, (HINTERNET a, DWORD b, DWORD c, const TCHAR* d, const TCHAR* e, void* f), (a, b, c, d, e, f), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpSetDefaultProxyConfiguration, (WINHTTP_PROXY_INFO* a), (a), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpSetOption, (HINTERNET a, DWORD b, void* c, DWORD d), (a, b, c, d), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpSetStatusCallback, (HINTERNET a, WINHTTP_STATUS_CALLBACK b, DWORD c, DWORD_PTR d), (a, b, c, d), WINHTTP_STATUS_CALLBACK, WINHTTP_INVALID_STATUS_CALLBACK);    // NOLINT

-PROTECT_WRAP(WinHttpSetTimeouts, (HINTERNET a, int b, int c, int d, int e), (a, b, c, d, e), BOOL, FALSE);    // NOLINT

-PROTECT_WRAP(WinHttpWriteData, (HINTERNET a, LPCVOID b, DWORD c, DWORD* d), (a, b, c, d), BOOL, FALSE);    // NOLINT

-

-}   // namespace omaha

-

-#endif  // OMAHA_NET_WINHTTP_VTABLE_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// WinHttpVTable provides dynamic loading of winhttp.dll.
+
+// Runtime requirements: WinHTTP 5.1 is now an operating-system component of
+// the following systems:
+// - Windows Vista
+// - Windows Server 2003 family
+// - Windows XP SP1
+// - Windows 2000 SP3 (except Datacenter Server)
+
+#ifndef OMAHA_NET_WINHTTP_VTABLE_H__
+#define OMAHA_NET_WINHTTP_VTABLE_H__
+
+#include <windows.h>
+#include <winhttp.h>
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+class WinHttpVTable {
+ public:
+  BOOL WinHttpAddRequestHeaders(HINTERNET, const TCHAR*, DWORD, DWORD);
+  BOOL WinHttpCheckPlatform();
+  BOOL WinHttpCloseHandle(HINTERNET);
+  HINTERNET WinHttpConnect(HINTERNET, const TCHAR*, INTERNET_PORT, DWORD);
+  BOOL WinHttpCrackUrl(const TCHAR*, DWORD, DWORD, URL_COMPONENTS*);
+  BOOL WinHttpCreateUrl(URL_COMPONENTS*, DWORD, TCHAR*, DWORD*);
+  BOOL WinHttpGetDefaultProxyConfiguration(WINHTTP_PROXY_INFO*);
+  BOOL WinHttpGetIEProxyConfigForCurrentUser(
+           WINHTTP_CURRENT_USER_IE_PROXY_CONFIG*);
+  HINTERNET WinHttpOpen(const TCHAR*, DWORD, const TCHAR*, const TCHAR*, DWORD);
+  HINTERNET WinHttpOpenRequest(HINTERNET,
+                               const TCHAR*,
+                               const TCHAR*,
+                               const TCHAR*,
+                               const TCHAR*,
+                               const TCHAR**,
+                               DWORD);
+  BOOL WinHttpQueryAuthSchemes(HINTERNET, DWORD*, DWORD*, DWORD*);
+  BOOL WinHttpQueryDataAvailable(HINTERNET, DWORD*);
+  BOOL WinHttpQueryHeaders(HINTERNET,
+                           DWORD,
+                           const TCHAR*,
+                           void*,
+                           DWORD*,
+                           DWORD*);
+  BOOL WinHttpQueryOption(HINTERNET, DWORD, void*, DWORD*);
+  BOOL WinHttpReadData(HINTERNET, void*, DWORD, DWORD*);
+  BOOL WinHttpWriteData(HINTERNET, const void*, DWORD, DWORD*);
+  BOOL WinHttpReceiveResponse(HINTERNET, void*);
+  BOOL WinHttpSendRequest(HINTERNET,
+                          const TCHAR*,
+                          DWORD,
+                          void*,
+                          DWORD,
+                          DWORD,
+                          DWORD_PTR);
+  BOOL WinHttpSetCredentials(HINTERNET,
+                             DWORD,
+                             DWORD,
+                             const TCHAR*,
+                             const TCHAR*,
+                             void*);
+  BOOL WinHttpSetOption(HINTERNET, DWORD, void*, DWORD);
+  WINHTTP_STATUS_CALLBACK WinHttpSetStatusCallback(HINTERNET,
+                                                   WINHTTP_STATUS_CALLBACK,
+                                                   DWORD,
+                                                   DWORD_PTR);
+  BOOL WinHttpSetTimeouts(HINTERNET, int, int, int, int);
+  BOOL WinHttpGetProxyForUrl(HINTERNET,
+                             const TCHAR*,
+                             WINHTTP_AUTOPROXY_OPTIONS*,
+                             WINHTTP_PROXY_INFO*);
+  BOOL WinHttpDetectAutoProxyConfigUrl(DWORD, TCHAR**);
+  BOOL WinHttpSetDefaultProxyConfiguration(WINHTTP_PROXY_INFO*);
+
+  WinHttpVTable() { Clear(); }
+  ~WinHttpVTable() { Unload(); }
+
+  // Loads library, snap links.
+  bool Load();
+
+  // Unloads library, clear links.
+  void Unload();
+
+  bool IsLoaded() { return NULL != library_; }
+
+ private:
+  void Clear() { memset(this, 0, sizeof(*this)); }
+
+  template <typename T>
+  bool GPA(const char* function_name, T* function_pointer) {
+    ASSERT1(function_name);
+    *function_pointer = reinterpret_cast<T>(::GetProcAddress(library_,
+                                                             function_name));
+    return NULL != *function_pointer;
+  }
+
+  // No good way to keep lines below 80 chars.
+  BOOL      (CALLBACK *WinHttpAddRequestHeaders_pointer)(HINTERNET, const TCHAR*, DWORD, DWORD);    // NOLINT
+  BOOL      (CALLBACK *WinHttpCheckPlatform_pointer)();
+  BOOL      (CALLBACK *WinHttpCloseHandle_pointer)(HINTERNET);    // NOLINT
+  HINTERNET (CALLBACK *WinHttpConnect_pointer)(HINTERNET, const TCHAR*, INTERNET_PORT, DWORD);    // NOLINT
+  BOOL      (CALLBACK *WinHttpCrackUrl_pointer)(const TCHAR*, DWORD, DWORD, URL_COMPONENTS*);    // NOLINT
+  BOOL      (CALLBACK *WinHttpCreateUrl_pointer)(URL_COMPONENTS*, DWORD, TCHAR*, DWORD*);        // NOLINT
+  BOOL      (CALLBACK *WinHttpDetectAutoProxyConfigUrl_pointer)(DWORD, TCHAR**);    // NOLINT
+  BOOL      (CALLBACK *WinHttpGetDefaultProxyConfiguration_pointer)(WINHTTP_PROXY_INFO*);    // NOLINT
+  BOOL      (CALLBACK *WinHttpGetIEProxyConfigForCurrentUser_pointer)(WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* pProxyConfig);    // NOLINT
+  BOOL      (CALLBACK *WinHttpGetProxyForUrl_pointer)(HINTERNET, const TCHAR*, WINHTTP_AUTOPROXY_OPTIONS*, WINHTTP_PROXY_INFO*);    // NOLINT
+  HINTERNET (CALLBACK *WinHttpOpen_pointer)(const TCHAR*, DWORD, const TCHAR*, const TCHAR*, DWORD);    // NOLINT
+  HINTERNET (CALLBACK *WinHttpOpenRequest_pointer)(HINTERNET, const TCHAR*, const TCHAR*, const TCHAR*, const TCHAR*, const TCHAR**, DWORD);    // NOLINT
+  BOOL      (CALLBACK *WinHttpQueryAuthSchemes_pointer)(HINTERNET, DWORD*, DWORD*, DWORD*);    // NOLINT
+  BOOL      (CALLBACK *WinHttpQueryDataAvailable_pointer)(HINTERNET, DWORD*);    // NOLINT
+  BOOL      (CALLBACK *WinHttpQueryHeaders_pointer)(HINTERNET, DWORD, const TCHAR*, void*, DWORD*, DWORD*);    // NOLINT
+  BOOL      (CALLBACK *WinHttpQueryOption_pointer)(HINTERNET, DWORD, void*, DWORD*);    // NOLINT
+  BOOL      (CALLBACK *WinHttpReadData_pointer)(HINTERNET, void*, DWORD, DWORD*);    // NOLINT
+  BOOL      (CALLBACK *WinHttpReceiveResponse_pointer)(HINTERNET, void*);    // NOLINT
+  BOOL      (CALLBACK *WinHttpSendRequest_pointer)(HINTERNET, const TCHAR*, DWORD, void*, DWORD, DWORD, DWORD_PTR);    // NOLINT
+  BOOL      (CALLBACK *WinHttpSetCredentials_pointer)(HINTERNET, DWORD, DWORD, const TCHAR*, const TCHAR*, void*);    // NOLINT
+  BOOL      (CALLBACK *WinHttpSetDefaultProxyConfiguration_pointer)(WINHTTP_PROXY_INFO*);   // NOLINT
+  BOOL      (CALLBACK *WinHttpSetOption_pointer)(HINTERNET, DWORD, void*, DWORD);    // NOLINT
+  BOOL      (CALLBACK *WinHttpSetTimeouts_pointer)(HINTERNET, int, int, int, int);    // NOLINT
+  BOOL      (CALLBACK *WinHttpWriteData_pointer)(HINTERNET, LPCVOID, DWORD, DWORD*);   // NOLINT
+  WINHTTP_STATUS_CALLBACK (CALLBACK *WinHttpSetStatusCallback_pointer)(HINTERNET, WINHTTP_STATUS_CALLBACK, DWORD, DWORD_PTR);    // NOLINT
+
+  HINSTANCE library_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(WinHttpVTable);
+};
+
+#define PROTECT_WRAP(function, proto, call, result_type, result_error_value)  \
+inline result_type WinHttpVTable::function proto {         \
+  return function##_pointer call;                          \
+}
+
+// No good way to keep lines below 80 chars.
+PROTECT_WRAP(WinHttpAddRequestHeaders, (HINTERNET a, const TCHAR* b, DWORD c, DWORD d), (a, b, c, d), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpCheckPlatform, (), (), BOOL, FALSE);
+PROTECT_WRAP(WinHttpCloseHandle, (HINTERNET a), (a), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpConnect, (HINTERNET a, const TCHAR* b, INTERNET_PORT c, DWORD d), (a, b, c, d), HINTERNET, NULL);    // NOLINT
+PROTECT_WRAP(WinHttpCrackUrl, (const TCHAR* a, DWORD b, DWORD c, LPURL_COMPONENTS d), (a, b, c, d), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpCreateUrl, (URL_COMPONENTS* a, DWORD b, TCHAR* c, DWORD* d), (a, b, c, d), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpDetectAutoProxyConfigUrl, (DWORD a, TCHAR** b), (a, b), BOOL, FALSE);   // NOLINT
+PROTECT_WRAP(WinHttpGetDefaultProxyConfiguration, (WINHTTP_PROXY_INFO* a), (a), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpGetIEProxyConfigForCurrentUser, (WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* a), (a),  BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpGetProxyForUrl, (HINTERNET a, const TCHAR* b, WINHTTP_AUTOPROXY_OPTIONS* c, WINHTTP_PROXY_INFO* d), (a, b, c, d), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpOpen, (const TCHAR* a, DWORD b, const TCHAR* c, const TCHAR* d, DWORD e), (a, b, c, d, e), HINTERNET, NULL);    // NOLINT
+PROTECT_WRAP(WinHttpOpenRequest, (HINTERNET a, const TCHAR* b, const TCHAR* c, const TCHAR* d, const TCHAR* e, const TCHAR** f, DWORD g), (a, b, c, d, e, f, g), HINTERNET, NULL);    // NOLINT
+PROTECT_WRAP(WinHttpQueryAuthSchemes, (HINTERNET a, DWORD* b, DWORD* c, DWORD* d), (a, b, c, d), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpQueryDataAvailable, (HINTERNET a, DWORD* b), (a, b), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpQueryHeaders, (HINTERNET a, DWORD b, const TCHAR* c, void* d, DWORD* e, DWORD* f), (a, b, c, d, e, f), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpQueryOption, (HINTERNET a, DWORD b, void* c, DWORD* d), (a, b, c, d), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpReadData, (HINTERNET a, void* b, DWORD c, DWORD* d), (a, b, c, d), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpReceiveResponse, (HINTERNET a, void* b), (a, b), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpSendRequest, (HINTERNET a, const TCHAR* b, DWORD c, void* d, DWORD e, DWORD f, DWORD_PTR g), (a, b, c, d, e, f, g), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpSetCredentials, (HINTERNET a, DWORD b, DWORD c, const TCHAR* d, const TCHAR* e, void* f), (a, b, c, d, e, f), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpSetDefaultProxyConfiguration, (WINHTTP_PROXY_INFO* a), (a), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpSetOption, (HINTERNET a, DWORD b, void* c, DWORD d), (a, b, c, d), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpSetStatusCallback, (HINTERNET a, WINHTTP_STATUS_CALLBACK b, DWORD c, DWORD_PTR d), (a, b, c, d), WINHTTP_STATUS_CALLBACK, WINHTTP_INVALID_STATUS_CALLBACK);    // NOLINT
+PROTECT_WRAP(WinHttpSetTimeouts, (HINTERNET a, int b, int c, int d, int e), (a, b, c, d, e), BOOL, FALSE);    // NOLINT
+PROTECT_WRAP(WinHttpWriteData, (HINTERNET a, LPCVOID b, DWORD c, DWORD* d), (a, b, c, d), BOOL, FALSE);    // NOLINT
+
+}   // namespace omaha
+
+#endif  // OMAHA_NET_WINHTTP_VTABLE_H__
+
diff --git a/net/winhttp_vtable_unittest.cc b/net/winhttp_vtable_unittest.cc
index 8fa583e..c1311c8 100644
--- a/net/winhttp_vtable_unittest.cc
+++ b/net/winhttp_vtable_unittest.cc
@@ -1,44 +1,44 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/net/winhttp_vtable.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(WinHttpVTableTest, WinHttpVTable) {

-  WinHttpVTable winhttp;

-  if (winhttp.Load()) {

-    // Check to see if the winhttp module has already been loaded.

-    bool was_loaded = ::GetModuleHandle(_T("winhttp")) ||

-                      ::GetModuleHandle(_T("winhttp5"));

-    EXPECT_TRUE(winhttp.IsLoaded());

-    EXPECT_TRUE(winhttp.Load());

-    EXPECT_TRUE(::GetModuleHandle(_T("winhttp")) ||

-                ::GetModuleHandle(_T("winhttp5")));

-    EXPECT_TRUE(winhttp.WinHttpCheckPlatform());

-    winhttp.Unload();

-    EXPECT_FALSE(winhttp.IsLoaded());

-    if (!was_loaded) {

-      // If the module was not loaded at the beginning of the test then it

-      // should not be loaded now either.

-      EXPECT_FALSE(::GetModuleHandle(_T("winhttp")) ||

-                   ::GetModuleHandle(_T("winhttp5")));

-    }

-  }

-}

-

-}   // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/net/winhttp_vtable.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(WinHttpVTableTest, WinHttpVTable) {
+  WinHttpVTable winhttp;
+  if (winhttp.Load()) {
+    // Check to see if the winhttp module has already been loaded.
+    bool was_loaded = ::GetModuleHandle(_T("winhttp")) ||
+                      ::GetModuleHandle(_T("winhttp5"));
+    EXPECT_TRUE(winhttp.IsLoaded());
+    EXPECT_TRUE(winhttp.Load());
+    EXPECT_TRUE(::GetModuleHandle(_T("winhttp")) ||
+                ::GetModuleHandle(_T("winhttp5")));
+    EXPECT_TRUE(winhttp.WinHttpCheckPlatform());
+    winhttp.Unload();
+    EXPECT_FALSE(winhttp.IsLoaded());
+    if (!was_loaded) {
+      // If the module was not loaded at the beginning of the test then it
+      // should not be loaded now either.
+      EXPECT_FALSE(::GetModuleHandle(_T("winhttp")) ||
+                   ::GetModuleHandle(_T("winhttp5")));
+    }
+  }
+}
+
+}   // namespace omaha
+
diff --git a/net/wininet.cc b/net/wininet.cc
index 4ab2dda..58479f8 100644
--- a/net/wininet.cc
+++ b/net/wininet.cc
@@ -1,1541 +1,1541 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <wininet.h>

-#include <atlstr.h>

-#include <vector>                     // NOLINT

-

-#include "omaha/net/http_client.h"

-

-#include "base/scoped_ptr.h"

-#include "omaha/common/atl_regexp.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/string.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-class WinInet : public HttpClient {

- public:

-  static HttpClient* Create() { return new WinInet; }

-

-  virtual HRESULT Initialize();

-

-  virtual HRESULT Open(const TCHAR* user_agent,

-                         uint32 access_type,

-                         const TCHAR* proxy_name,

-                         const TCHAR* proxy_bypass);

-

-  virtual HRESULT Close();

-

-  virtual HRESULT Connect(const TCHAR* server, int port);

-

-  virtual HRESULT OpenRequest(const TCHAR* verb,

-                              const TCHAR* uri,

-                              const TCHAR* version,

-                              const TCHAR* referrer,

-                              const TCHAR** accept_types,

-                              uint32 flags);

-

-  virtual HRESULT SendRequest(const TCHAR* headers,

-                              int headers_length,

-                              const void* optional_data,

-                              size_t optional_data_length,

-                              size_t content_length);

-

-  virtual HRESULT SetTimeouts(int resolve_timeout_ms,

-                              int connect_timeout_ms,

-                              int send_timeout_ms,

-                              int receive_timeout_ms);

-

-  virtual HRESULT ReceiveResponse();

-

-  virtual HRESULT QueryDataAvailable(int* num_bytes);

-

-  virtual HRESULT ReadData(std::vector<uint8>* data);

-

-  virtual HRESULT WriteData(const std::vector<uint8>& data, int* bytes_written);

-

-  virtual HRESULT SetCredentials(uint32 auth_targets,

-                                 uint32 auth_scheme,

-                                 const TCHAR* user_name,

-                                 const TCHAR* password);

-

-  virtual HRESULT DetectAutoProxyConfigUrl(uint32 flags,

-                                           CString* auto_config_url);

-

-  virtual HRESULT GetDefaultProxyConfiguration(ProxyInfo* proxy_info);

-

-  virtual HRESULT SetDefaultProxyConfiguration(const ProxyInfo& proxy_info);

-

-  virtual HRESULT GetIEProxyConfiguration(CurrentUserIEProxyConfig* proxy_info);

-

-  virtual HRESULT GetProxyForUrl(const TCHAR* url,

-                                 const AutoProxyOptions* auto_proxy_options,

-                                 ProxyInfo* pProxyInfo);

-

-  virtual HRESULT QueryAuthSchemes(uint32* supported_schemes,

-                                          uint32* first_scheme,

-                                          uint32* auth_target);

-

-  virtual HRESULT AddRequestHeaders(const TCHAR* headers,

-                                    int length,

-                                    uint32 modifiers);

-

-  virtual HRESULT QueryHeaders(uint32 info_level,

-                               const TCHAR* name,

-                               CString* value,

-                               int* index);

-  virtual HRESULT QueryHeaders(uint32 info_level,

-                               const TCHAR* name,

-                               int* value,

-                               int* index);

-

-  virtual HRESULT QueryOption(bool is_session_option,

-                              uint32 option,

-                              std::vector<uint8>* val);

-

-  virtual HRESULT QueryOptionString(bool is_session_option,

-                                    uint32 option,

-                                    CString* value);

-

-  virtual HRESULT QueryOptionInt(bool is_session_option,

-                                 uint32 option,

-                                 int* value);

-

-  virtual HRESULT SetOption(bool is_session_option,

-                            uint32 option,

-                            const void* buffer,

-                            size_t buffer_length);

-

-  virtual HRESULT SetOption(bool is_session_option,

-                            uint32 option,

-                            const std::vector<uint8>* val);

-

-  virtual HRESULT SetOptionString(bool is_session_option,

-                                  uint32 option,

-                                  const TCHAR* value);

-

-  virtual HRESULT SetOptionInt(bool is_session_option,

-                               uint32 option,

-                               int value);

-

-  virtual HRESULT CrackUrl(const TCHAR* url,

-                           uint32 flags,

-                           CString* scheme,

-                           CString* server,

-                           int* port,

-                           CString* url_path,

-                           CString* extra_info);

-

-  virtual HRESULT CreateUrl(const TCHAR* scheme,

-                            const TCHAR* server,

-                            int port,

-                            const TCHAR* url_path,

-                            const TCHAR* extra_info,

-                            uint32 flags,

-                            CString* url);

-

-

-  typedef void (*StatusCallback)(uint32 context,

-                                 int status,

-                                 void* status_information,

-                                 size_t status_info_length);

-  virtual StatusCallback SetStatusCallback(StatusCallback callback,

-                                           uint32 flags);

- private:

-  WinInet();

-  DISALLOW_EVIL_CONSTRUCTORS(WinInet);

-};

-

-

-// TODO(omaha): remove after the implementation is complete.

-// 4100: unreferenced formal parameter

-#pragma warning(disable : 4100)

-

-WinInet::WinInet() {

-}

-

-HRESULT WinInet::Initialize() {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::Open(const TCHAR* user_agent,

-                      uint32 access_type,

-                      const TCHAR* proxy_name,

-                      const TCHAR* proxy_bypass) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::Close() {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::Connect(const TCHAR* server, int port) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::OpenRequest(const TCHAR* verb,

-                             const TCHAR* uri,

-                             const TCHAR* version,

-                             const TCHAR* referrer,

-                             const TCHAR** accept_types,

-                             uint32 flags) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::SendRequest(const TCHAR* headers,

-                             int headers_length,

-                             const void* optional_data,

-                             size_t optional_data_length,

-                             size_t content_length) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::SetTimeouts(int resolve_timeout_ms,

-                             int connect_timeout_ms,

-                             int send_timeout_ms,

-                             int receive_timeout_ms) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::ReceiveResponse() {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::QueryDataAvailable(int* num_bytes) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::ReadData(std::vector<uint8>* data) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::WriteData(const std::vector<uint8>& data, int* bytes_written) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::SetCredentials(uint32 auth_targets,

-                                uint32 auth_scheme,

-                                const TCHAR* user_name,

-                                const TCHAR* password) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::DetectAutoProxyConfigUrl(uint32 flags,

-                                          CString* auto_config_url) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::GetDefaultProxyConfiguration(ProxyInfo* proxy_info) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::SetDefaultProxyConfiguration(const ProxyInfo& proxy_info) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::GetIEProxyConfiguration(CurrentUserIEProxyConfig* proxy_info) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::GetProxyForUrl(const TCHAR* url,

-                                const AutoProxyOptions* auto_proxy_options,

-                                ProxyInfo* pProxyInfo) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::QueryAuthSchemes(uint32* supported_schemes,

-                                  uint32* first_scheme,

-                                  uint32* auth_target) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::AddRequestHeaders(const TCHAR* headers,

-                                   int length,

-                                   uint32 modifiers) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::QueryHeaders(uint32 info_level,

-                              const TCHAR* name,

-                              CString* value,

-                              int* index) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::QueryHeaders(uint32 info_level,

-                              const TCHAR* name,

-                              int* value,

-                              int* index) {

-  return E_NOTIMPL;

-}

-

-

-HRESULT WinInet::QueryOption(bool is_session_option,

-                             uint32 option,

-                             std::vector<uint8>* val) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::QueryOptionString(bool is_session_option,

-                                   uint32 option,

-                                   CString* value) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::QueryOptionInt(bool is_session_option,

-                                uint32 option,

-                                int* value) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::SetOption(bool is_session_option,

-                           uint32 option,

-                           const void* buffer,

-                           size_t buffer_length) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::SetOption(bool is_session_option,

-                           uint32 option,

-                           const std::vector<uint8>* val) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::SetOptionString(bool is_session_option,

-                                 uint32 option,

-                                 const TCHAR* value) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::SetOptionInt(bool is_session_option,

-                              uint32 option,

-                              int value) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::CrackUrl(const TCHAR* url,

-                          uint32 flags,

-                          CString* scheme,

-                          CString* server,

-                          int* port,

-                          CString* url_path,

-                          CString* extra_info) {

-  return E_NOTIMPL;

-}

-

-HRESULT WinInet::CreateUrl(const TCHAR* scheme,

-                           const TCHAR* server,

-                           int port,

-                           const TCHAR* url_path,

-                           const TCHAR* extra_info,

-                           uint32 flags,

-                           CString* url) {

-  return E_NOTIMPL;

-}

-

-HttpClient::StatusCallback WinInet::SetStatusCallback(

-                               HttpClient::StatusCallback callback,

-                               uint32 flags) {

-  return NULL;

-}

-

-extern "C" const bool kRegisterWinInet =

-    HttpClient::GetFactory().Register(HttpClient::WININET, &WinInet::Create);

-

-

-}  // namespace omaha

-

-#if 0

-// Constants

-const uint32 kInternetRequestCachingDefaultFlags = INTERNET_FLAG_NO_UI |

-                                                   INTERNET_FLAG_NO_COOKIES;

-const uint32 kInternetRequestNoCacheDefaultFlags =

-                 INTERNET_FLAG_NO_UI |

-                 INTERNET_FLAG_NO_COOKIES |

-                 INTERNET_FLAG_NO_CACHE_WRITE |

-                 INTERNET_FLAG_PRAGMA_NOCACHE |

-                 INTERNET_FLAG_RELOAD;

-const TCHAR kProxyAuthenticateHeader[] = _T("Proxy-Authenticate:");

-const TCHAR kNegotiateAuthScheme[] = _T("Negotiate");

-const TCHAR kNTLMAuthScheme[] = _T("NTLM");

-const TCHAR kDigestAuthScheme[] = _T("Digest");

-const TCHAR kBasicAuthScheme[] = _T("Basic");

-

-// Provides dynamic loading of WinInet.dll

-//

-// Delay loading wininet.dll would be nice but would (tediously) involve

-// modifying the mk_file for all DLLs/EXEs that use any of the functions that

-// use InetGet.  Which is all of them (since it is used in debug.cpp).  So

-// instead, we do it the old-fashioned way.

-//

-// N.B.: When WinInetVTable has been Load()ed, the wininet.dll is loaded -

-// which adds significantly to the working set of your process.  So beware of

-// loading the WinInetVTable and leaving it loaded, esp. if you have a static

-// instance of WinInetVTable.  And on the other hand, the load/unload operation

-// is expensive (slow) so you want to reuse your Load()ed WinInetVTable if

-// you're going to be needing it frequently.  Note that that cost is in the

-// loading/unloading of the DLL, thus 'nested' uses (which only need to 'snap'

-// the links) are cheap.

-class WinInetVTable {

- public:

-  // Functions are simply reflected through data members holding function

-  // pointers, taking advantage of C-syntax (you can call indirectly through a

-  // function pointer without a '*').  No error checking is done: call through

-  // only when Loaded() == true.

-  BOOL      HttpAddRequestHeaders(HINTERNET, const TCHAR*, DWORD, DWORD);

-  BOOL      HttpEndRequest(HINTERNET, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);

-  HINTERNET HttpOpenRequest(HINTERNET,

-                            const TCHAR*,

-                            const TCHAR*,

-                            const TCHAR*,

-                            const TCHAR*,

-                            const TCHAR**,

-                            DWORD,

-                            DWORD_PTR);

-  BOOL      HttpQueryInfo(HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD);

-  BOOL      HttpSendRequestEx(HINTERNET,

-                              LPINTERNET_BUFFERS,

-                              LPINTERNET_BUFFERS,

-                              DWORD,

-                              DWORD_PTR);

-  BOOL      HttpSendRequest(HINTERNET, const TCHAR*, DWORD, LPVOID, DWORD);

-  BOOL      InternetCloseHandle(HINTERNET);

-  HINTERNET InternetConnect(HINTERNET,

-                            const TCHAR*,

-                            INTERNET_PORT,

-                            const TCHAR*,

-                            const TCHAR*,

-                            DWORD,

-                            DWORD,

-                            DWORD);

-  BOOL      InternetGetConnectedStateEx(LPDWORD, char*, DWORD, DWORD);

-  HINTERNET InternetOpen(const TCHAR*,

-                         DWORD,

-                         const TCHAR*,

-                         const TCHAR*,

-                         DWORD);

-  HINTERNET InternetOpenUrl(HINTERNET,

-                            const TCHAR*,

-                            const TCHAR*,

-                            DWORD,

-                            DWORD,

-                            DWORD_PTR);

-  BOOL      InternetQueryDataAvailable(HINTERNET, LPDWORD, DWORD, DWORD);

-  BOOL      InternetReadFile(HINTERNET, LPVOID, DWORD, LPDWORD);

-  HINTERNET InternetReadFileEx(HINTERNET, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);

-  BOOL      InternetGetCookie(const TCHAR*, const TCHAR*, TCHAR*, LPDWORD);

-  BOOL      InternetSetCookie(const TCHAR*, const TCHAR*, const TCHAR*);

-  BOOL      InternetAutodial(DWORD, HWND);

-  BOOL      InternetAutodialHangup(DWORD);

-  BOOL      InternetQueryOption(HINTERNET hInternet,

-                                DWORD dwOption,

-                                LPVOID lpBuffer,

-                                LPDWORD lpdwBufferLength);

-  BOOL      InternetSetOption(HINTERNET hInternet,

-                              DWORD dwOption,

-                              LPVOID lpBuffer,

-                              DWORD dwBufferLength);

-  BOOL      InternetCheckConnection(const TCHAR*,

-                                    DWORD, DWORD);

-  BOOL      InternetCrackUrl(const TCHAR*,

-                             DWORD,

-                             DWORD,

-                             LPURL_COMPONENTS);

-  INTERNET_STATUS_CALLBACK InternetSetStatusCallback(HINTERNET, INTERNET_STATUS_CALLBACK);

-

-  WinInetVTable();

-  ~WinInetVTable();

-

-  bool Load();    // Load library, snap links

-  void Unload();  // Unload library, clear links

-

-  bool Loaded() { return NULL != library_; }

-

- protected:

-  BOOL      (CALLBACK *HttpAddRequestHeaders_pointer)(HINTERNET, const TCHAR*, DWORD, DWORD);

-  BOOL      (CALLBACK *HttpEndRequest_pointer)(HINTERNET, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);

-  HINTERNET (CALLBACK *HttpOpenRequest_pointer)(HINTERNET, const TCHAR*, const TCHAR*, const TCHAR*, const TCHAR*, const TCHAR**, DWORD, DWORD_PTR);

-  BOOL      (CALLBACK *HttpQueryInfo_pointer)(HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD);

-  BOOL      (CALLBACK *HttpSendRequestEx_pointer)(HINTERNET, LPINTERNET_BUFFERS, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);

-  BOOL      (CALLBACK *HttpSendRequest_pointer)(HINTERNET, const TCHAR*, DWORD, LPVOID, DWORD);

-  BOOL      (CALLBACK *InternetCloseHandle_pointer)(HINTERNET);

-  HINTERNET (CALLBACK *InternetConnect_pointer)(HINTERNET, const TCHAR*, INTERNET_PORT, const TCHAR*, const TCHAR*, DWORD, DWORD, DWORD);

-  BOOL      (CALLBACK *InternetGetConnectedStateEx_pointer)(LPDWORD, char*, DWORD, DWORD);

-  HINTERNET (CALLBACK *InternetOpen_pointer)(const TCHAR*, DWORD, const TCHAR*, const TCHAR*, DWORD);

-  HINTERNET (CALLBACK *InternetOpenUrl_pointer)(HINTERNET, const TCHAR*, const TCHAR*, DWORD, DWORD, DWORD_PTR);

-  BOOL      (CALLBACK *InternetQueryDataAvailable_pointer)(HINTERNET, LPDWORD, DWORD, DWORD);

-  BOOL      (CALLBACK *InternetReadFile_pointer)(HINTERNET, LPVOID, DWORD, LPDWORD);

-  HINTERNET (CALLBACK *InternetReadFileEx_pointer)(HINTERNET, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);

-  BOOL      (CALLBACK *InternetGetCookie_pointer)(const TCHAR*, const TCHAR*, TCHAR*, LPDWORD);

-  BOOL      (CALLBACK *InternetSetCookie_pointer)(const TCHAR*, const TCHAR*, const TCHAR*);

-  BOOL      (CALLBACK *InternetAutodial_pointer)(DWORD, HWND);

-  BOOL      (CALLBACK *InternetAutodialHangup_pointer)(DWORD);

-  BOOL      (CALLBACK *InternetQueryOption_pointer)(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength);

-  BOOL      (CALLBACK *InternetSetOption_pointer)(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength);

-  BOOL      (CALLBACK *InternetCheckConnection_pointer)(const TCHAR*, DWORD, DWORD);

-  BOOL      (CALLBACK *InternetCrackUrl_pointer)(const TCHAR*, DWORD, DWORD, LPURL_COMPONENTS);

-  INTERNET_STATUS_CALLBACK (CALLBACK *InternetSetStatusCallback_pointer)(HINTERNET, INTERNET_STATUS_CALLBACK);

-

-  HINSTANCE library_;

-

-  void Clear();

-

-  // Simple wrapper around GetProcAddress()

-  template <typename T>

-  bool GPA(const char* function_name, T& function_pointer);   // NO LINT

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(WinInetVTable);

-};

-

-

-class InetHttpClient : public HttpClient {

- public:

-  static InetHttpClient* Create();

-  virtual ~InetHttpClient();

-  virtual HRESULT Abort();

-  virtual uint32 GetStatus();

-  virtual HRESULT GetResponseHeader(const TCHAR* name, CString* value);

-  virtual HRESULT GetAllResponseHeaders(CString* response_headers);

-  virtual HRESULT GetResponseText(CString* response_text, uint32 max_size);

-  virtual HRESULT GetRawResponseBody(std::vector<byte>* response_body,

-                                     uint32 max_size);

-  virtual HRESULT SaveRawResponseBody(const TCHAR* response_filename,

-                                      uint32 max_size);

-  virtual HRESULT QueryProxyAuthScheme(AuthScheme* auth_scheme);

-  virtual HRESULT GetAutoProxyForUrl(const TCHAR* url, CString* proxy);

-  virtual HRESULT GetDefaultProxyConfiguration(AccessType* access_type,

-                                               CString* proxy,

-                                               CString* proxy_bypass);

- protected:

-  virtual HRESULT InternalCrackUrl(const CString& url,

-                                   bool to_escape,

-                                   URL_COMPONENTS* url_components);

-  virtual HRESULT SendRequest(const TCHAR* server,

-                              uint32 port,

-                              const TCHAR* path);

-  virtual bool CheckConnection();

- private:

-  InetHttpClient();

-  HRESULT Init();

-  void Close();

-  HRESULT SetTimeouts();

-  HRESULT SetHttpProxyCredentials(const TCHAR* username, const TCHAR* password);

-  HRESULT SkipSSLCertErrorIfNeeded();

-  HRESULT InternalSend(const TCHAR* server,

-                       uint32 port,

-                       const TCHAR* path,

-                       bool use_proxy);

-  HRESULT InternalGetRawResponseBody(std::vector<byte>* response_body,

-                                     const TCHAR* response_filename,

-                                     uint32 max_size);

-  static void CALLBACK StatusCallback(HINTERNET handle,

-                                      DWORD_PTR context,

-                                      DWORD status,

-                                      void* info,

-                                      DWORD info_len);

-

-  WinInetVTable wininet_;

-  HINTERNET session_handle_;

-  HINTERNET connection_handle_;

-  HINTERNET request_handle_;

-  uint32 status_;

-  bool is_initialized_;

-  bool is_aborted_;

-  LLock lock_;

-

-  // Parses the header "Proxy-Authenticate:"

-  static AtlRE proxy_auth_header_regex_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(InetHttpClient);

-};

-

-AtlRE InetHttpClient::proxy_auth_header_regex_(

-    _T("\\n*Proxy\\-Authenticate\\:\\b*{\\w}\\n*"), false);

-

-HttpClient* CreateInetHttpClient() {

-  return InetHttpClient::Create();

-}

-

-InetHttpClient* InetHttpClient::Create() {

-  scoped_ptr<InetHttpClient> http_client(new InetHttpClient());

-  if (http_client.get()) {

-    if (SUCCEEDED(http_client->Init())) {

-      return http_client.release();

-    }

-  }

-  return NULL;

-}

-

-InetHttpClient::InetHttpClient()

-    : session_handle_(NULL),

-      connection_handle_(NULL),

-      request_handle_(NULL),

-      status_(0),

-      is_initialized_(false),

-      is_aborted_(false) {

-}

-

-InetHttpClient::~InetHttpClient() {

-  Close();

-  wininet_.Unload();

-}

-

-HRESULT InetHttpClient::Abort() {

-  UTIL_LOG(L6, (_T("[InetHttpClient::Abort]")));

-

-  is_aborted_ = true;

-  Close();

-  return S_OK;

-}

-

-void InetHttpClient::Close() {

-  // Closing the handles will unblock all WinInet calls unless a call is

-  // waiting for DNS lookup, or in other words, when the state is where

-  // between INTERNET_STATUS_RESOLVING_NAME and INTERNET_STATUS_NAME_RESOLVED.

-  // In that case, closing the handles does not have any effect.

-  // This is also the case even we use async WinInet calls.

-

-  __mutexScope(lock_);

-

-  if (request_handle_) {

-    wininet_.InternetCloseHandle(request_handle_);

-    request_handle_ = NULL;

-  }

-

-  if (connection_handle_) {

-    wininet_.InternetCloseHandle(connection_handle_);

-    connection_handle_ = NULL;

-  }

-

-  if (session_handle_) {

-    wininet_.InternetCloseHandle(session_handle_);

-    session_handle_ = NULL;

-  }

-}

-

-HRESULT InetHttpClient::Init() {

-  if (is_initialized_) {

-    return E_UNEXPECTED;

-  }

-

-  is_initialized_ = true;

-

-  if (!wininet_.Load()) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[Failed to load wininet][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT InetHttpClient::SetTimeouts() {

-  ASSERT1(session_handle_);

-

-  uint32 connect_timeout_ms = connect_timeout_ms_;

-  uint32 send_timeout_ms = send_timeout_ms_;

-  uint32 receive_timeout_ms = receive_timeout_ms_;

-#if DEBUG

-  ConfigProfile::GetValue(kServerSettings,

-                          kConfigConnectTimeoutMs,

-                          &connect_timeout_ms);

-  ConfigProfile::GetValue(kServerSettings,

-                          kConfigSendTimeoutMs,

-                          &send_timeout_ms);

-  ConfigProfile::GetValue(kServerSettings,

-                          kConfigReceiveTimeoutMs,

-                          &receive_timeout_ms);

-#endif

-  if (connect_timeout_ms || send_timeout_ms || receive_timeout_ms) {

-    if (!wininet_.InternetSetOption(session_handle_,

-                                    INTERNET_OPTION_CONNECT_TIMEOUT,

-                                    &connect_timeout_ms,

-                                    sizeof(connect_timeout_ms))) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set connection timeout]")

-                             _T("[0x%08x]"), HRESULTFromLastError()));

-    }

-    if (!wininet_.InternetSetOption(session_handle_,

-                                    INTERNET_OPTION_SEND_TIMEOUT,

-                                    &send_timeout_ms,

-                                    sizeof(send_timeout_ms))) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set send timeout]")

-                             _T("[0x%08x]"), HRESULTFromLastError()));

-    }

-    if (!wininet_.InternetSetOption(session_handle_,

-                                    INTERNET_OPTION_RECEIVE_TIMEOUT,

-                                    &receive_timeout_ms,

-                                    sizeof(receive_timeout_ms))) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set receive timeout]")

-                             _T("[0x%08x]"), HRESULTFromLastError()));

-    }

-  }

-  return S_OK;

-}

-

-HRESULT InetHttpClient::SetHttpProxyCredentials(const TCHAR* username,

-                                                const TCHAR* password) {

-  ASSERT1(connection_handle_);

-

-  if (username && *username && password && *password) {

-    if (!wininet_.InternetSetOption(connection_handle_,

-                                    INTERNET_OPTION_PROXY_USERNAME,

-                                    const_cast<TCHAR*>(username),

-                                    _tcslen(username))) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set proxy authentication username]")

-                             _T("[0x%08x]"), HRESULTFromLastError()));

-    }

-    if (!wininet_.InternetSetOption(connection_handle_,

-                                    INTERNET_OPTION_PROXY_PASSWORD,

-                                    const_cast<TCHAR*>(password),

-                                    _tcslen(password))) {

-      UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set proxy authentication password]")

-                             _T("[0x%08x]"), HRESULTFromLastError()));

-    }

-  }

-  return S_OK;

-}

-

-HRESULT InetHttpClient::SkipSSLCertErrorIfNeeded() {

-#if DEBUG

-  ASSERT1(request_handle_);

-

-  bool ignore_certificate_errors = false;

-  ConfigProfile::GetValue(kServerSettings,

-                          kConfigSecurityIgnoreCertificateErrors,

-                          &ignore_certificate_errors);

-  if (ignore_certificate_errors) {

-    UTIL_LOG(L6, (_T("[InetHttpClient::SkipSSLCertErrorIfNeeded]")

-                  _T("[ignore certificate error]")));

-    DWORD flags = 0;

-    DWORD flags_len = sizeof(flags);

-    if (wininet_.InternetQueryOption(request_handle_,

-                                     INTERNET_OPTION_SECURITY_FLAGS,

-                                     &flags,

-                                     &flags_len)) {

-      flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA |

-               SECURITY_FLAG_IGNORE_CERT_CN_INVALID;

-      if (!wininet_.InternetSetOption(request_handle_,

-                                      INTERNET_OPTION_SECURITY_FLAGS,

-                                      &flags,

-                                      sizeof(flags))) {

-        UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set ignore SSL cert error]")

-                               _T("[0x%08x]"), HRESULTFromLastError()));

-      }

-    } else {

-      UTIL_LOG(LEVEL_ERROR, (_T("[InternetQueryOption failed]")

-                             _T("[0x%08x]"), HRESULTFromLastError()));

-    }

-  }

-#endif

-

-  return S_OK;

-}

-

-HRESULT InetHttpClient::SendRequest(const TCHAR* server,

-                                    uint32 port,

-                                    const TCHAR* path) {

-  ASSERT1(server && *server);

-  ASSERT1(path && *path);

-

-  UTIL_LOG(L6, (_T("[InetHttpClient::SendRequest]")

-                _T("[%s:%u%s]"), server, port, path));

-

-  // When we are using WinInet http client, we will encouter auto-dial if the

-  // user sets "Always dial my default connection" in Internet Explorer.

-  // To fix this problem, we will check whether there is an active Internet

-  // connection first.

-  if (!IsMachineConnected()) {

-    return HRESULT_FROM_WIN32(ERROR_INTERNET_CANNOT_CONNECT);

-  }

-

-  HRESULT hr = S_OK;

-

-  for (uint32 i = 0; i < 1 + retries_; ++i) {

-    if (i > 0) {

-      ::Sleep(retry_delay_ms_);

-      UTIL_LOG(L6, (_T("[InetHttpClient::SendRequest - retry %u]"), i));

-    }

-

-    hr = InternalSend(server, port, path, true);

-    if (retry_without_proxy_ && !proxy_server_.IsEmpty() &&

-        (FAILED(hr) || (status_ != HTTP_STATUS_OK &&

-                        status_ != HTTP_STATUS_NOT_MODIFIED))) {

-      UTIL_LOG(L6, (_T("[failed with proxy]")

-                    _T("[%s][%u][0x%08x]"), proxy_server_, hr));

-      hr = InternalSend(server, port, path, false);

-      if (SUCCEEDED(hr)) {

-        UTIL_LOG(L6, (_T("[switch to direct connection]")));

-        GetProxyConfig()->SwitchAutoProxyToDirectConnection();

-      }

-    }

-    if (SUCCEEDED(hr)) {

-      break;

-    }

-  }

-

-  if (FAILED(hr)) {

-    // Convert hresults to be of the CI_E format.

-    // If you need to be aware of another error code, then

-    // add another CI_E_ error to this type of switch statment

-    // in every HttpClient::Send method.

-    //

-    // __HRESULT_FROM_WIN32 will always be a macro where as

-    // HRESULT_FROM_WIN32 can be an inline function. Using HRESULT_FROM_WIN32

-    // can break the switch statement.

-    //

-    // TODO(omaha):  refactor weird switch.

-    switch (hr) {

-      case __HRESULT_FROM_WIN32(ERROR_INTERNET_SEC_CERT_DATE_INVALID):

-        hr = CI_E_HTTPS_CERT_FAILURE;

-        break;

-    }

-  }

-

-  return hr;

-}

-

-HRESULT InetHttpClient::InternalSend(const TCHAR* server,

-                                     uint32 port,

-                                     const TCHAR* path,

-                                     bool use_proxy) {

-  ASSERT1(server && *server);

-  ASSERT1(path && *path);

-

-  UTIL_LOG(L6, (_T("[InetHttpClient::InternalSend]")

-                _T("[%s:%u%s][%u]"), server, port, path, use_proxy));

-

-  HRESULT hr = S_OK;

-

-  // Close all handles from previous request.

-  Close();

-

-  // Open the Internet session.

-  if (!use_proxy ||  proxy_server_.IsEmpty()) {

-    session_handle_ = wininet_.InternetOpen(NULL,

-                                            INTERNET_OPEN_TYPE_DIRECT,

-                                            NULL,

-                                            NULL,

-                                            0);

-  } else {

-    session_handle_ = wininet_.InternetOpen(NULL,

-                                            INTERNET_OPEN_TYPE_PROXY,

-                                            proxy_server_,

-                                            NULL,

-                                            0);

-  }

-  if (!session_handle_) {

-    hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[InternetOpen failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (is_aborted_) {

-    return E_ABORT;

-  }

-

-  // Set timeouts.

-  SetTimeouts();

-

-  if (is_aborted_) {

-    return E_ABORT;

-  }

-

-  // Connect to the server

-  connection_handle_ = wininet_.InternetConnect(

-                                    session_handle_,

-                                    server,

-                                    static_cast<INTERNET_PORT>(port),

-                                    NULL,

-                                    NULL,

-                                    INTERNET_SERVICE_HTTP,

-                                    0,

-                                    NULL);

-  if (!connection_handle_) {

-    hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[InternetConnect failed]")

-                           _T("[%s:%u%s][0x%08x]"), server, port, path, hr));

-    return hr;

-  }

-

-  if (is_aborted_) {

-    return E_ABORT;

-  }

-

-  // Set proxy credentials.

-  if (use_proxy) {

-    SetHttpProxyCredentials(proxy_auth_username_, proxy_auth_password_);

-  }

-

-  if (is_aborted_) {

-    return E_ABORT;

-  }

-

-  // Prepare the flags.

-  DWORD flags = no_cache_ ? kInternetRequestNoCacheDefaultFlags :

-                            kInternetRequestCachingDefaultFlags;

-  if (port == kDefaultSslProxyPort) {

-    flags |= INTERNET_FLAG_SECURE;

-  }

-

-  // Send the request. A context is required otherwise the callback won't happen

-  // even if the WinInet is used in synchronous mode.

-  DWORD_PTR context = reinterpret_cast<DWORD_PTR>(this);

-  if (post_data_.empty()) {

-    // For GET.

-    request_handle_ = wininet_.HttpOpenRequest(connection_handle_,

-                                               kHttpGetMethod,

-                                               path,

-                                               NULL,

-                                               NULL,

-                                               NULL,

-                                               flags,

-                                               context);

-    if (!request_handle_) {

-      hr = HRESULTFromLastError();

-      UTIL_LOG(LEVEL_ERROR, (_T("[HttpOpenRequest failed to open GET request]")

-                             _T("[%s:%u%s][0x%08x]"), server, port, path, hr));

-      return hr;

-    }

-

-    INTERNET_STATUS_CALLBACK old_callback =

-        wininet_.InternetSetStatusCallback(request_handle_, &StatusCallback);

-    ASSERT1(old_callback == NULL);

-    if (old_callback != INTERNET_INVALID_STATUS_CALLBACK) {

-      UTIL_LOG(L6, (_T("[InternetSetStatusCallback succeeded]")

-                    _T("[0x%08x]"), request_handle_));

-    } else {

-      hr = HRESULTFromLastError();

-      UTIL_LOG(LEVEL_WARNING, (_T("[InternetSetStatusCallback failed]")

-                               _T("[%s:%u%s][0x%08x]"),

-                               server, port, path, hr));

-    }

-

-    if (is_aborted_) {

-      return E_ABORT;

-    }

-

-    if (port == kDefaultSslProxyPort) {

-      SkipSSLCertErrorIfNeeded();

-    }

-

-    if (is_aborted_) {

-      return E_ABORT;

-    }

-

-    if (!wininet_.HttpSendRequest(request_handle_,

-                                  additional_headers_.GetString(),

-                                  additional_headers_.GetLength(),

-                                  NULL,

-                                  0)) {

-      hr = HRESULTFromLastError();

-      UTIL_LOG(LEVEL_ERROR, (_T("[HttpSendRequest failed to send GET request]")

-                             _T("[%s:%u%s][0x%08x]"), server, port, path, hr));

-

-      // Occasionally setting the option to skip SSL certificate error before

-      // sending the request does not work. We have to set it again after

-      // failed to send the request.

-      if (port == kDefaultSslProxyPort) {

-        SkipSSLCertErrorIfNeeded();

-        if (!wininet_.HttpSendRequest(request_handle_,

-                                      additional_headers_.GetString(),

-                                      additional_headers_.GetLength(),

-                                      NULL,

-                                      0)) {

-          hr = HRESULTFromLastError();

-          UTIL_LOG(LEVEL_ERROR, (_T("[HttpSendRequest failed to resend GET]")

-                                 _T("[%s:%u%s][0x%08x]"),

-                                 server, port, path, hr));

-        } else {

-          hr = S_OK;

-        }

-      }

-

-      if (FAILED(hr)) {

-        return hr;

-      }

-    }

-  } else {

-    // For post

-    request_handle_ = wininet_.HttpOpenRequest(connection_handle_,

-                                               kHttpPostMethod,

-                                               path,

-                                               NULL,

-                                               NULL,

-                                               NULL,

-                                               flags,

-                                               context);

-    if (!request_handle_) {

-      hr = HRESULTFromLastError();

-      UTIL_LOG(LEVEL_ERROR, (_T("[HttpOpenRequest failed to open POST request]")

-                             _T("[%s:%u%s][0x%08x]"), server, port, path, hr));

-      return hr;

-    }

-

-    INTERNET_STATUS_CALLBACK old_callback =

-        wininet_.InternetSetStatusCallback(request_handle_, StatusCallback);

-    ASSERT1(old_callback == NULL);

-    if (old_callback != INTERNET_INVALID_STATUS_CALLBACK) {

-      UTIL_LOG(L6, (_T("[InternetSetStatusCallback succeeded]")

-                    _T("[0x%08x]"), request_handle_));

-    } else {

-      hr = HRESULTFromLastError();

-      UTIL_LOG(LEVEL_WARNING, (_T("[InternetSetStatusCallback failed]")

-                               _T("[%s:%u%s][0x%08x]"),

-                               server, port, path, hr));

-    }

-

-    if (is_aborted_) {

-      return E_ABORT;

-    }

-

-    SkipSSLCertErrorIfNeeded();

-

-    if (is_aborted_) {

-      return E_ABORT;

-    }

-

-    if (!wininet_.HttpSendRequest(request_handle_,

-                                  additional_headers_.GetString(),

-                                  additional_headers_.GetLength(),

-                                  &post_data_.front(),

-                                  post_data_.size())) {

-      hr = HRESULTFromLastError();

-      UTIL_LOG(LEVEL_ERROR, (_T("[HttpSendRequest failed to send POST request]")

-                             _T("[%s:%u%s][0x%08x]"), server, port, path, hr));

-      return hr;

-    }

-  }

-

-  if (is_aborted_) {

-    return E_ABORT;

-  }

-

-  // Get the response status.

-  DWORD value = 0;

-  DWORD value_size = sizeof(value);

-  if (!wininet_.HttpQueryInfo(request_handle_,

-                              HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,

-                              &value,

-                              &value_size,

-                              0)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed to get status]")

-                           _T("[%s:%u%s][0x%08x]"), server, port, path, hr));

-    return hr;

-  }

-

-  status_ = static_cast<uint32>(value);

-  return S_OK;

-}

-

-uint32 InetHttpClient::GetStatus() {

-  return status_;

-}

-

-HRESULT InetHttpClient::GetResponseHeader(const TCHAR* name, CString* value) {

-  ASSERT1(name && *name);

-  ASSERT1(value);

-

-  if (!status_) {

-    return E_FAIL;

-  }

-

-  HRESULT hr = S_OK;

-

-  value->SetString(name);

-  TCHAR* buf = value->GetBuffer();

-  DWORD size = value->GetLength() * sizeof(TCHAR);

-  if (wininet_.HttpQueryInfo(request_handle_,

-                             HTTP_QUERY_CUSTOM,

-                             buf,

-                             &size,

-                             0)) {

-    value->ReleaseBuffer(size / sizeof(TCHAR));

-  } else {

-    DWORD error = ::GetLastError();

-    if (error == ERROR_INSUFFICIENT_BUFFER) {

-      buf = value->GetBufferSetLength(size / sizeof(TCHAR));

-      if (!wininet_.HttpQueryInfo(request_handle_,

-                                  HTTP_QUERY_CUSTOM,

-                                  buf,

-                                  &size,

-                                  0)) {

-        hr = HRESULTFromLastError();

-        UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));

-      }

-      value->ReleaseBuffer(size / sizeof(TCHAR));

-    } else {

-      hr = HRESULT_FROM_WIN32(error);

-      UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));

-    }

-  }

-

-  return hr;

-}

-

-HRESULT InetHttpClient::GetAllResponseHeaders(CString* response_headers) {

-  ASSERT1(response_headers);

-  ASSERT1(request_handle_);

-

-  if (!status_) {

-    return E_FAIL;

-  }

-

-  HRESULT hr = S_OK;

-

-  DWORD size = 0;

-  if (!wininet_.HttpQueryInfo(request_handle_,

-                              HTTP_QUERY_RAW_HEADERS_CRLF,

-                              NULL,

-                              &size,

-                              0)) {

-    DWORD error = ::GetLastError();

-    if (error == ERROR_INSUFFICIENT_BUFFER) {

-      TCHAR* buf = response_headers->GetBufferSetLength(size / sizeof(TCHAR));

-      if (!wininet_.HttpQueryInfo(request_handle_,

-                                  HTTP_QUERY_RAW_HEADERS_CRLF,

-                                  buf,

-                                  &size,

-                                  0)) {

-        hr = HRESULTFromLastError();

-        UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));

-      }

-      response_headers->ReleaseBuffer(size / sizeof(TCHAR));

-    } else {

-      hr = HRESULT_FROM_WIN32(error);

-      UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));

-    }

-  }

-

-  return hr;

-}

-

-HRESULT InetHttpClient::GetResponseText(CString* response_text,

-                                        uint32 max_size) {

-  ASSERT1(response_text);

-  ASSERT1(request_handle_);

-

-  if (!status_) {

-    return E_FAIL;

-  }

-

-  const int kBufferSize = 1024;

-  char buffer[kBufferSize] = {0};

-

-  CStringA ansi_response_text;

-  uint32 size = 0;

-  while (true) {

-    if (is_aborted_) {

-      return E_ABORT;

-    }

-

-    DWORD bytes_read = 0;

-    if (wininet_.InternetReadFile(request_handle_,

-                                  buffer,

-                                  kBufferSize,

-                                  &bytes_read) && bytes_read) {

-      size += bytes_read;

-      if (max_size && size > max_size) {

-        return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);

-      }

-      ansi_response_text.Append(buffer, bytes_read);

-    } else {

-      break;

-    }

-  }

-

-  response_text->SetString(Utf8ToWideChar(ansi_response_text.GetString(),

-                                          ansi_response_text.GetLength()));

-

-  return S_OK;

-}

-

-HRESULT InetHttpClient::GetRawResponseBody(std::vector<byte>* response_body,

-                                           uint32 max_size) {

-  return InternalGetRawResponseBody(response_body, NULL, max_size);

-}

-

-HRESULT InetHttpClient::SaveRawResponseBody(const TCHAR* response_filename,

-                                            uint32 max_size) {

-  return InternalGetRawResponseBody(NULL, response_filename, max_size);

-}

-

-HRESULT InetHttpClient::InternalGetRawResponseBody(

-                            std::vector<byte>* response_body,

-                            const TCHAR* response_filename,

-                            uint32 max_size) {

-  ASSERT((response_body != NULL) ^ (response_filename != NULL), (_T("")));

-  ASSERT1(request_handle_);

-

-  if (!status_) {

-    return E_FAIL;

-  }

-

-  HRESULT hr = S_OK;

-  scoped_hfile file;

-

-  if (response_body) {

-    response_body->clear();

-  } else {

-    reset(file, ::CreateFile(response_filename,

-                             FILE_WRITE_DATA,

-                             0,

-                             NULL,

-                             CREATE_ALWAYS,

-                             0,

-                             NULL));

-    if (!file) {

-      return HRESULTFromLastError();

-    }

-  }

-

-  const int kBufferSize = 1024;

-  char buffer[kBufferSize];

-  uint32 size = 0;

-  while (true) {

-    if (is_aborted_) {

-      return E_ABORT;

-    }

-

-    DWORD bytes_read = 0;

-    if (wininet_.InternetReadFile(request_handle_,

-                                  buffer,

-                                  kBufferSize,

-                                  &bytes_read) && bytes_read) {

-      size += bytes_read;

-      if (max_size && size > max_size) {

-        return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);

-      }

-      if (response_body) {

-        response_body->insert(response_body->end(),

-                              buffer,

-                              buffer + bytes_read);

-      } else {

-        DWORD bytes_written = 0;

-        if (!::WriteFile(get(file), buffer, bytes_read, &bytes_written, NULL)) {

-          hr = HRESULTFromLastError();

-          break;

-        }

-      }

-    } else {

-      break;

-    }

-  }

-

-  return hr;

-}

-

-HRESULT InetHttpClient::QueryProxyAuthScheme(AuthScheme* auth_scheme) {

-  ASSERT1(auth_scheme);

-

-  *auth_scheme = NO_AUTH_SCHEME;

-

-  // Find out authentication scheme by communicating with google server via

-  // proxy server and checking the response header to find out the

-  // authentication scheme the proxy server requires.

-

-  // Send the request to query google server only if we have not got 407 error.

-  HRESULT hr = S_OK;

-  if (status_ != HTTP_STATUS_PROXY_AUTH_REQ) {

-    hr = SendRequest(kGoogleHttpServer, kDefaultHttpProxyPort, _T("/"));

-  }

-  if (SUCCEEDED(hr) && status_ == HTTP_STATUS_PROXY_AUTH_REQ) {

-    CString response_headers;

-    hr = GetAllResponseHeaders(&response_headers);

-    if (SUCCEEDED(hr)) {

-      const TCHAR* response_headers_str = response_headers.GetString();

-      CString auth_scheme_str;

-      AuthScheme curr_auth_scheme = NO_AUTH_SCHEME;

-      while (AtlRE::FindAndConsume(&response_headers_str,

-                                   proxy_auth_header_regex_,

-                                   &auth_scheme_str)) {

-        AuthScheme other_auth_scheme = NO_AUTH_SCHEME;

-        if (auth_scheme_str.CompareNoCase(kNegotiateAuthScheme) == 0) {

-          other_auth_scheme = AUTH_SCHEME_NEGOTIATE;

-        } else if (auth_scheme_str.CompareNoCase(kNTLMAuthScheme) == 0) {

-          other_auth_scheme = AUTH_SCHEME_NTLM;

-        } else if (auth_scheme_str.CompareNoCase(kDigestAuthScheme) == 0) {

-          other_auth_scheme = AUTH_SCHEME_DIGEST;

-        } else if (auth_scheme_str.CompareNoCase(kBasicAuthScheme) == 0) {

-          other_auth_scheme = AUTH_SCHEME_BASIC;

-        } else {

-          other_auth_scheme = UNKNOWN_AUTH_SCHEME;

-        }

-        if (static_cast<int>(other_auth_scheme) >

-            static_cast<int>(curr_auth_scheme)) {

-          curr_auth_scheme = other_auth_scheme;

-        }

-      }

-      *auth_scheme = curr_auth_scheme;

-      return S_OK;

-    }

-  }

-

-  return E_FAIL;

-}

-

-// We do not support Auto-proxy for WinInet because jsproxy.dll seems to be

-// very instable and cause crashes from time to time.

-HRESULT InetHttpClient::GetAutoProxyForUrl(const TCHAR*, CString*) {

-  return E_NOTIMPL;

-}

-

-HRESULT InetHttpClient::GetDefaultProxyConfiguration(AccessType* access_type,

-                                                     CString* proxy,

-                                                     CString* proxy_bypass) {

-  DWORD size_needed = 0;

-  if (wininet_.InternetQueryOption(NULL,

-                                   INTERNET_OPTION_PROXY,

-                                   NULL,

-                                   &size_needed) ||

-      ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {

-    UTIL_LOG(LEVEL_ERROR, (_T("[InternetQueryOption failed]")));

-    return E_FAIL;

-  }

-

-  scoped_array<byte> proxy_info_buffer(new byte[size_needed]);

-  if (!wininet_.InternetQueryOption(NULL,

-                                    INTERNET_OPTION_PROXY,

-                                    proxy_info_buffer.get(),

-                                    &size_needed)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[InternetQueryOption failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  INTERNET_PROXY_INFO* proxy_info = reinterpret_cast<INTERNET_PROXY_INFO*>(

-                                        proxy_info_buffer.get());

-

-  if (access_type) {

-    if (proxy_info->dwAccessType == INTERNET_OPEN_TYPE_DIRECT) {

-      *access_type = NO_PROXY;

-    } else if (proxy_info->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {

-      *access_type = NAMED_PROXY;

-    } else {

-      *access_type = AUTO_PROXY_AUTO_DETECT;

-    }

-  }

-

-  if (proxy) {

-    // proxy_info->lpszProxy points to an ASCII string.

-    *proxy = reinterpret_cast<const char*>(proxy_info->lpszProxy);

-  }

-

-  if (proxy_bypass) {

-    // proxy_info->lpszProxyBypass points to an ASCII string.

-    *proxy_bypass = reinterpret_cast<const char*>(proxy_info->lpszProxyBypass);

-  }

-

-  return S_OK;

-}

-

-// TODO(omaha): check connection by requesting a well known url instead of

-// using WinInet. The WinInet code does an ICMP ping apparently, which is

-// usually blocked by firewalls.

-bool InetHttpClient::CheckConnection() {

-  return wininet_.InternetCheckConnection(

-      kHttpProtoScheme kProtoSuffix kGoogleHttpServer _T("/"),

-      FLAG_ICC_FORCE_CONNECTION, 0) == TRUE;

-}

-

-HRESULT InetHttpClient::InternalCrackUrl(const CString& url, bool to_escape,

-                                         URL_COMPONENTS* url_components) {

-  ASSERT(!url.IsEmpty(), (_T("")));

-  ASSERT1(url_components);

-

-  if (!wininet_.InternetCrackUrl(url.GetString(),

-                                 url.GetLength(),

-                                 to_escape ? ICU_ESCAPE : 0,

-                                 url_components)) {

-    HRESULT hr = HRESULTFromLastError();

-    UTIL_LOG(LEVEL_ERROR, (_T("[InternetCrackUrl failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-void CALLBACK InetHttpClient::StatusCallback(HINTERNET handle,

-                                             DWORD_PTR context,

-                                             DWORD status,

-                                             void* info,

-                                             DWORD info_len) {

-  // Unlike WinHttp, the ip addresses are not unicode strings.

-  CString info_string;

-  switch (status) {

-    case INTERNET_STATUS_RESOLVING_NAME:

-      status = CALLBACK_STATUS_RESOLVING_NAME;

-      break;

-    case INTERNET_STATUS_NAME_RESOLVED:

-      info_string = static_cast<char*>(info);

-      info = info_string.GetBuffer();

-      status = CALLBACK_STATUS_NAME_RESOLVED;

-      break;

-    case INTERNET_STATUS_CONNECTING_TO_SERVER:

-      info_string = static_cast<char*>(info);

-      info = info_string.GetBuffer();

-      status = CALLBACK_STATUS_CONNECTING_TO_SERVER;

-      break;

-    case INTERNET_STATUS_CONNECTED_TO_SERVER:

-      info_string = static_cast<char*>(info);

-      info = info_string.GetBuffer();

-      status = CALLBACK_STATUS_CONNECTED_TO_SERVER;

-      break;

-    case INTERNET_STATUS_SENDING_REQUEST:

-      status = CALLBACK_STATUS_SENDING_REQUEST;

-      break;

-    case INTERNET_STATUS_REQUEST_SENT:

-      status = CALLBACK_STATUS_REQUEST_SENT;

-      break;

-    case INTERNET_STATUS_RECEIVING_RESPONSE:

-      status = CALLBACK_STATUS_RECEIVING_RESPONSE;

-      break;

-    case INTERNET_STATUS_RESPONSE_RECEIVED:

-      status = CALLBACK_STATUS_RESPONSE_RECEIVED;

-      break;

-    case INTERNET_STATUS_CLOSING_CONNECTION:

-      status = CALLBACK_STATUS_CLOSING_CONNECTION;

-      break;

-    case INTERNET_STATUS_CONNECTION_CLOSED:

-      status = CALLBACK_STATUS_CONNECTION_CLOSED;

-      break;

-    case INTERNET_STATUS_REDIRECT:

-      status = CALLBACK_STATUS_REDIRECT;

-      break;

-    default:

-      return;

-  };

-  HttpClient::StatusCallback(handle, context, status, info, info_len);

-}

-

-// WinInetVTable: delay-loading of WININET.DLL.

-// Handling of and protection of Wininet APIs.

-//   Dynamically load to wininet.dll.

-//   Wrap all calls in an Structured Exception handler - wininet is buggy and

-//   throws access violations

-WinInetVTable::WinInetVTable() { Clear(); }

-WinInetVTable::~WinInetVTable() { Unload(); }

-

-template <typename T>

-bool WinInetVTable::GPA(const char* function_name,

-                        T& function_pointer) {      // NO LINT

-  ASSERT(function_name, (L""));

-  function_pointer = reinterpret_cast<T>(::GetProcAddress(library_,

-                                                          function_name));

-  return NULL != function_pointer;

-}

-

-bool WinInetVTable::Load() {

-  if (Loaded()) {

-    return true;

-  }

-

-  Clear();

-

-  {

-    library_ = ::LoadLibrary(_T("wininet"));

-  }

-  if (!library_) {

-    return false;

-  }

-

-  bool all_valid = (

-         GPA("HttpAddRequestHeadersW",       HttpAddRequestHeaders_pointer))

-      & (GPA("HttpEndRequestW",              HttpEndRequest_pointer))

-      & (GPA("HttpOpenRequestW",             HttpOpenRequest_pointer))

-      & (GPA("HttpQueryInfoW",               HttpQueryInfo_pointer))

-      & (GPA("HttpSendRequestExW",           HttpSendRequestEx_pointer))

-      & (GPA("HttpSendRequestW",             HttpSendRequest_pointer))

-      & (GPA("InternetCloseHandle",          InternetCloseHandle_pointer))

-      & (GPA("InternetConnectW",             InternetConnect_pointer))

-      & (GPA("InternetGetConnectedStateExW", InternetGetConnectedStateEx_pointer))

-      & (GPA("InternetOpenW",                InternetOpen_pointer))

-      & (GPA("InternetOpenUrlW",             InternetOpenUrl_pointer))

-      & (GPA("InternetQueryDataAvailable",   InternetQueryDataAvailable_pointer))

-      & (GPA("InternetReadFile",             InternetReadFile_pointer))

-      & (GPA("InternetReadFileExW",          InternetReadFileEx_pointer))

-      & (GPA("InternetSetStatusCallbackW",   InternetSetStatusCallback_pointer))

-      & (GPA("InternetGetCookieW",           InternetGetCookie_pointer))

-      & (GPA("InternetSetCookieW",           InternetSetCookie_pointer))

-      & (GPA("InternetAutodial",             InternetAutodial_pointer))

-      & (GPA("InternetAutodialHangup",       InternetAutodialHangup_pointer))

-      & (GPA("InternetQueryOptionW",         InternetQueryOption_pointer))

-      & (GPA("InternetSetOptionW",           InternetSetOption_pointer))

-      & (GPA("InternetCheckConnectionW",     InternetCheckConnection_pointer))

-      & (GPA("InternetCrackUrlW",            InternetCrackUrl_pointer));

-

-  if (!all_valid) {

-    Unload();

-  }

-

-  return all_valid;

-}

-

-void WinInetVTable::Unload() {

-  if (library_) {

-    ::FreeLibrary(library_);

-    library_ = NULL;

-  }

-  Clear();

-}

-

-void WinInetVTable::Clear() {

-  ::memset(this, 0, sizeof(*this));

-}

-

-#define PROTECT_WRAP(function, proto, call, result_type, result_error_value)  \

-result_type WinInetVTable::function proto {                  \

-    result_type result;                                      \

-    __try {                                                  \

-      result = function##_pointer call;                      \

-    }                                                        \

-    __except(EXCEPTION_EXECUTE_HANDLER) {                    \

-      result = result_error_value;                           \

-    }                                                        \

-    return result;                                           \

-}

-

-PROTECT_WRAP(HttpAddRequestHeaders, (HINTERNET a, const TCHAR* b, DWORD c, DWORD d), (a, b, c, d), BOOL, FALSE);

-PROTECT_WRAP(HttpEndRequest, (HINTERNET a, LPINTERNET_BUFFERS b, DWORD c, DWORD_PTR d), (a, b, c, d), BOOL, FALSE);

-PROTECT_WRAP(HttpOpenRequest, (HINTERNET a, const TCHAR* b, const TCHAR* c, const TCHAR* d, const TCHAR* e, const TCHAR** f, DWORD g, DWORD_PTR h), (a, b, c, d, e, f, g, h), HINTERNET, NULL);

-PROTECT_WRAP(HttpQueryInfo, (HINTERNET a, DWORD b, LPVOID c, LPDWORD d, LPDWORD e), (a, b, c, d, e), BOOL, FALSE);

-PROTECT_WRAP(HttpSendRequestEx, (HINTERNET a, LPINTERNET_BUFFERS b, LPINTERNET_BUFFERS c, DWORD d, DWORD_PTR e), (a, b, c, d, e), BOOL, FALSE);

-PROTECT_WRAP(HttpSendRequest, (HINTERNET a, const TCHAR* b, DWORD c, LPVOID d, DWORD e), (a, b, c, d, e), BOOL, FALSE);

-PROTECT_WRAP(InternetCloseHandle, (HINTERNET a), (a), BOOL, FALSE);

-PROTECT_WRAP(InternetConnect, (HINTERNET a, const TCHAR* b, INTERNET_PORT c, const TCHAR* d, const TCHAR* e, DWORD f, DWORD g, DWORD h), (a, b, c, d, e, f, g, h), HINTERNET, NULL);

-PROTECT_WRAP(InternetGetConnectedStateEx, (LPDWORD a, char* b, DWORD c, DWORD d), (a, b, c, d), BOOL, FALSE);

-PROTECT_WRAP(InternetOpen, (const TCHAR* a, DWORD b, const TCHAR* c, const TCHAR* d, DWORD e), (a, b, c, d, e), HINTERNET, NULL);

-PROTECT_WRAP(InternetOpenUrl, (HINTERNET a, const TCHAR* b, const TCHAR* c, DWORD d, DWORD e, DWORD_PTR f), (a, b, c, d, e, f), HINTERNET, NULL);

-PROTECT_WRAP(InternetQueryDataAvailable, (HINTERNET a, LPDWORD b, DWORD c, DWORD d), (a, b, c, d), BOOL, FALSE);

-PROTECT_WRAP(InternetReadFile, (HINTERNET a, LPVOID b, DWORD c, LPDWORD d), (a, b, c, d), BOOL, FALSE);

-PROTECT_WRAP(InternetReadFileEx, (HINTERNET a, LPINTERNET_BUFFERS b, DWORD c, DWORD_PTR d), (a, b, c, d), HINTERNET, NULL);

-PROTECT_WRAP(InternetSetStatusCallback, (HINTERNET a, INTERNET_STATUS_CALLBACK b), (a, b), INTERNET_STATUS_CALLBACK, INTERNET_INVALID_STATUS_CALLBACK);

-PROTECT_WRAP(InternetGetCookie, (const TCHAR* a, const TCHAR* b, TCHAR* c, LPDWORD d), (a, b, c, d), BOOL, FALSE);

-PROTECT_WRAP(InternetSetCookie, (const TCHAR* a, const TCHAR* b, const TCHAR* c), (a, b, c), BOOL, FALSE);

-PROTECT_WRAP(InternetAutodial, (DWORD a, HWND b), (a, b), BOOL, FALSE);

-PROTECT_WRAP(InternetAutodialHangup, (DWORD a), (a), BOOL, FALSE);

-PROTECT_WRAP(InternetQueryOption, (HINTERNET a, DWORD b, LPVOID c, LPDWORD d), (a, b, c, d), BOOL, FALSE);

-PROTECT_WRAP(InternetSetOption, (HINTERNET a, DWORD b, LPVOID c, DWORD d), (a, b, c, d), BOOL, FALSE);

-PROTECT_WRAP(InternetCheckConnection, (const TCHAR* a, DWORD b, DWORD c), (a, b, c), BOOL, FALSE);

-PROTECT_WRAP(InternetCrackUrl, (const TCHAR* a, DWORD b, DWORD c, LPURL_COMPONENTS d), (a, b, c, d), BOOL, FALSE);

-#endif

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <wininet.h>
+#include <atlstr.h>
+#include <vector>                     // NOLINT
+
+#include "omaha/net/http_client.h"
+
+#include "base/scoped_ptr.h"
+#include "omaha/common/atl_regexp.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/string.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+class WinInet : public HttpClient {
+ public:
+  static HttpClient* Create() { return new WinInet; }
+
+  virtual HRESULT Initialize();
+
+  virtual HRESULT Open(const TCHAR* user_agent,
+                         uint32 access_type,
+                         const TCHAR* proxy_name,
+                         const TCHAR* proxy_bypass);
+
+  virtual HRESULT Close();
+
+  virtual HRESULT Connect(const TCHAR* server, int port);
+
+  virtual HRESULT OpenRequest(const TCHAR* verb,
+                              const TCHAR* uri,
+                              const TCHAR* version,
+                              const TCHAR* referrer,
+                              const TCHAR** accept_types,
+                              uint32 flags);
+
+  virtual HRESULT SendRequest(const TCHAR* headers,
+                              int headers_length,
+                              const void* optional_data,
+                              size_t optional_data_length,
+                              size_t content_length);
+
+  virtual HRESULT SetTimeouts(int resolve_timeout_ms,
+                              int connect_timeout_ms,
+                              int send_timeout_ms,
+                              int receive_timeout_ms);
+
+  virtual HRESULT ReceiveResponse();
+
+  virtual HRESULT QueryDataAvailable(int* num_bytes);
+
+  virtual HRESULT ReadData(std::vector<uint8>* data);
+
+  virtual HRESULT WriteData(const std::vector<uint8>& data, int* bytes_written);
+
+  virtual HRESULT SetCredentials(uint32 auth_targets,
+                                 uint32 auth_scheme,
+                                 const TCHAR* user_name,
+                                 const TCHAR* password);
+
+  virtual HRESULT DetectAutoProxyConfigUrl(uint32 flags,
+                                           CString* auto_config_url);
+
+  virtual HRESULT GetDefaultProxyConfiguration(ProxyInfo* proxy_info);
+
+  virtual HRESULT SetDefaultProxyConfiguration(const ProxyInfo& proxy_info);
+
+  virtual HRESULT GetIEProxyConfiguration(CurrentUserIEProxyConfig* proxy_info);
+
+  virtual HRESULT GetProxyForUrl(const TCHAR* url,
+                                 const AutoProxyOptions* auto_proxy_options,
+                                 ProxyInfo* pProxyInfo);
+
+  virtual HRESULT QueryAuthSchemes(uint32* supported_schemes,
+                                          uint32* first_scheme,
+                                          uint32* auth_target);
+
+  virtual HRESULT AddRequestHeaders(const TCHAR* headers,
+                                    int length,
+                                    uint32 modifiers);
+
+  virtual HRESULT QueryHeaders(uint32 info_level,
+                               const TCHAR* name,
+                               CString* value,
+                               int* index);
+  virtual HRESULT QueryHeaders(uint32 info_level,
+                               const TCHAR* name,
+                               int* value,
+                               int* index);
+
+  virtual HRESULT QueryOption(bool is_session_option,
+                              uint32 option,
+                              std::vector<uint8>* val);
+
+  virtual HRESULT QueryOptionString(bool is_session_option,
+                                    uint32 option,
+                                    CString* value);
+
+  virtual HRESULT QueryOptionInt(bool is_session_option,
+                                 uint32 option,
+                                 int* value);
+
+  virtual HRESULT SetOption(bool is_session_option,
+                            uint32 option,
+                            const void* buffer,
+                            size_t buffer_length);
+
+  virtual HRESULT SetOption(bool is_session_option,
+                            uint32 option,
+                            const std::vector<uint8>* val);
+
+  virtual HRESULT SetOptionString(bool is_session_option,
+                                  uint32 option,
+                                  const TCHAR* value);
+
+  virtual HRESULT SetOptionInt(bool is_session_option,
+                               uint32 option,
+                               int value);
+
+  virtual HRESULT CrackUrl(const TCHAR* url,
+                           uint32 flags,
+                           CString* scheme,
+                           CString* server,
+                           int* port,
+                           CString* url_path,
+                           CString* extra_info);
+
+  virtual HRESULT CreateUrl(const TCHAR* scheme,
+                            const TCHAR* server,
+                            int port,
+                            const TCHAR* url_path,
+                            const TCHAR* extra_info,
+                            uint32 flags,
+                            CString* url);
+
+
+  typedef void (*StatusCallback)(uint32 context,
+                                 int status,
+                                 void* status_information,
+                                 size_t status_info_length);
+  virtual StatusCallback SetStatusCallback(StatusCallback callback,
+                                           uint32 flags);
+ private:
+  WinInet();
+  DISALLOW_EVIL_CONSTRUCTORS(WinInet);
+};
+
+
+// TODO(omaha): remove after the implementation is complete.
+// 4100: unreferenced formal parameter
+#pragma warning(disable : 4100)
+
+WinInet::WinInet() {
+}
+
+HRESULT WinInet::Initialize() {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::Open(const TCHAR* user_agent,
+                      uint32 access_type,
+                      const TCHAR* proxy_name,
+                      const TCHAR* proxy_bypass) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::Close() {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::Connect(const TCHAR* server, int port) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::OpenRequest(const TCHAR* verb,
+                             const TCHAR* uri,
+                             const TCHAR* version,
+                             const TCHAR* referrer,
+                             const TCHAR** accept_types,
+                             uint32 flags) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::SendRequest(const TCHAR* headers,
+                             int headers_length,
+                             const void* optional_data,
+                             size_t optional_data_length,
+                             size_t content_length) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::SetTimeouts(int resolve_timeout_ms,
+                             int connect_timeout_ms,
+                             int send_timeout_ms,
+                             int receive_timeout_ms) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::ReceiveResponse() {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::QueryDataAvailable(int* num_bytes) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::ReadData(std::vector<uint8>* data) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::WriteData(const std::vector<uint8>& data, int* bytes_written) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::SetCredentials(uint32 auth_targets,
+                                uint32 auth_scheme,
+                                const TCHAR* user_name,
+                                const TCHAR* password) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::DetectAutoProxyConfigUrl(uint32 flags,
+                                          CString* auto_config_url) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::GetDefaultProxyConfiguration(ProxyInfo* proxy_info) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::SetDefaultProxyConfiguration(const ProxyInfo& proxy_info) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::GetIEProxyConfiguration(CurrentUserIEProxyConfig* proxy_info) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::GetProxyForUrl(const TCHAR* url,
+                                const AutoProxyOptions* auto_proxy_options,
+                                ProxyInfo* pProxyInfo) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::QueryAuthSchemes(uint32* supported_schemes,
+                                  uint32* first_scheme,
+                                  uint32* auth_target) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::AddRequestHeaders(const TCHAR* headers,
+                                   int length,
+                                   uint32 modifiers) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::QueryHeaders(uint32 info_level,
+                              const TCHAR* name,
+                              CString* value,
+                              int* index) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::QueryHeaders(uint32 info_level,
+                              const TCHAR* name,
+                              int* value,
+                              int* index) {
+  return E_NOTIMPL;
+}
+
+
+HRESULT WinInet::QueryOption(bool is_session_option,
+                             uint32 option,
+                             std::vector<uint8>* val) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::QueryOptionString(bool is_session_option,
+                                   uint32 option,
+                                   CString* value) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::QueryOptionInt(bool is_session_option,
+                                uint32 option,
+                                int* value) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::SetOption(bool is_session_option,
+                           uint32 option,
+                           const void* buffer,
+                           size_t buffer_length) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::SetOption(bool is_session_option,
+                           uint32 option,
+                           const std::vector<uint8>* val) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::SetOptionString(bool is_session_option,
+                                 uint32 option,
+                                 const TCHAR* value) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::SetOptionInt(bool is_session_option,
+                              uint32 option,
+                              int value) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::CrackUrl(const TCHAR* url,
+                          uint32 flags,
+                          CString* scheme,
+                          CString* server,
+                          int* port,
+                          CString* url_path,
+                          CString* extra_info) {
+  return E_NOTIMPL;
+}
+
+HRESULT WinInet::CreateUrl(const TCHAR* scheme,
+                           const TCHAR* server,
+                           int port,
+                           const TCHAR* url_path,
+                           const TCHAR* extra_info,
+                           uint32 flags,
+                           CString* url) {
+  return E_NOTIMPL;
+}
+
+HttpClient::StatusCallback WinInet::SetStatusCallback(
+                               HttpClient::StatusCallback callback,
+                               uint32 flags) {
+  return NULL;
+}
+
+extern "C" const bool kRegisterWinInet =
+    HttpClient::GetFactory().Register(HttpClient::WININET, &WinInet::Create);
+
+
+}  // namespace omaha
+
+#if 0
+// Constants
+const uint32 kInternetRequestCachingDefaultFlags = INTERNET_FLAG_NO_UI |
+                                                   INTERNET_FLAG_NO_COOKIES;
+const uint32 kInternetRequestNoCacheDefaultFlags =
+                 INTERNET_FLAG_NO_UI |
+                 INTERNET_FLAG_NO_COOKIES |
+                 INTERNET_FLAG_NO_CACHE_WRITE |
+                 INTERNET_FLAG_PRAGMA_NOCACHE |
+                 INTERNET_FLAG_RELOAD;
+const TCHAR kProxyAuthenticateHeader[] = _T("Proxy-Authenticate:");
+const TCHAR kNegotiateAuthScheme[] = _T("Negotiate");
+const TCHAR kNTLMAuthScheme[] = _T("NTLM");
+const TCHAR kDigestAuthScheme[] = _T("Digest");
+const TCHAR kBasicAuthScheme[] = _T("Basic");
+
+// Provides dynamic loading of WinInet.dll
+//
+// Delay loading wininet.dll would be nice but would (tediously) involve
+// modifying the mk_file for all DLLs/EXEs that use any of the functions that
+// use InetGet.  Which is all of them (since it is used in debug.cpp).  So
+// instead, we do it the old-fashioned way.
+//
+// N.B.: When WinInetVTable has been Load()ed, the wininet.dll is loaded -
+// which adds significantly to the working set of your process.  So beware of
+// loading the WinInetVTable and leaving it loaded, esp. if you have a static
+// instance of WinInetVTable.  And on the other hand, the load/unload operation
+// is expensive (slow) so you want to reuse your Load()ed WinInetVTable if
+// you're going to be needing it frequently.  Note that that cost is in the
+// loading/unloading of the DLL, thus 'nested' uses (which only need to 'snap'
+// the links) are cheap.
+class WinInetVTable {
+ public:
+  // Functions are simply reflected through data members holding function
+  // pointers, taking advantage of C-syntax (you can call indirectly through a
+  // function pointer without a '*').  No error checking is done: call through
+  // only when Loaded() == true.
+  BOOL      HttpAddRequestHeaders(HINTERNET, const TCHAR*, DWORD, DWORD);
+  BOOL      HttpEndRequest(HINTERNET, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);
+  HINTERNET HttpOpenRequest(HINTERNET,
+                            const TCHAR*,
+                            const TCHAR*,
+                            const TCHAR*,
+                            const TCHAR*,
+                            const TCHAR**,
+                            DWORD,
+                            DWORD_PTR);
+  BOOL      HttpQueryInfo(HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD);
+  BOOL      HttpSendRequestEx(HINTERNET,
+                              LPINTERNET_BUFFERS,
+                              LPINTERNET_BUFFERS,
+                              DWORD,
+                              DWORD_PTR);
+  BOOL      HttpSendRequest(HINTERNET, const TCHAR*, DWORD, LPVOID, DWORD);
+  BOOL      InternetCloseHandle(HINTERNET);
+  HINTERNET InternetConnect(HINTERNET,
+                            const TCHAR*,
+                            INTERNET_PORT,
+                            const TCHAR*,
+                            const TCHAR*,
+                            DWORD,
+                            DWORD,
+                            DWORD);
+  BOOL      InternetGetConnectedStateEx(LPDWORD, char*, DWORD, DWORD);
+  HINTERNET InternetOpen(const TCHAR*,
+                         DWORD,
+                         const TCHAR*,
+                         const TCHAR*,
+                         DWORD);
+  HINTERNET InternetOpenUrl(HINTERNET,
+                            const TCHAR*,
+                            const TCHAR*,
+                            DWORD,
+                            DWORD,
+                            DWORD_PTR);
+  BOOL      InternetQueryDataAvailable(HINTERNET, LPDWORD, DWORD, DWORD);
+  BOOL      InternetReadFile(HINTERNET, LPVOID, DWORD, LPDWORD);
+  HINTERNET InternetReadFileEx(HINTERNET, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);
+  BOOL      InternetGetCookie(const TCHAR*, const TCHAR*, TCHAR*, LPDWORD);
+  BOOL      InternetSetCookie(const TCHAR*, const TCHAR*, const TCHAR*);
+  BOOL      InternetAutodial(DWORD, HWND);
+  BOOL      InternetAutodialHangup(DWORD);
+  BOOL      InternetQueryOption(HINTERNET hInternet,
+                                DWORD dwOption,
+                                LPVOID lpBuffer,
+                                LPDWORD lpdwBufferLength);
+  BOOL      InternetSetOption(HINTERNET hInternet,
+                              DWORD dwOption,
+                              LPVOID lpBuffer,
+                              DWORD dwBufferLength);
+  BOOL      InternetCheckConnection(const TCHAR*,
+                                    DWORD, DWORD);
+  BOOL      InternetCrackUrl(const TCHAR*,
+                             DWORD,
+                             DWORD,
+                             LPURL_COMPONENTS);
+  INTERNET_STATUS_CALLBACK InternetSetStatusCallback(HINTERNET, INTERNET_STATUS_CALLBACK);
+
+  WinInetVTable();
+  ~WinInetVTable();
+
+  bool Load();    // Load library, snap links
+  void Unload();  // Unload library, clear links
+
+  bool Loaded() { return NULL != library_; }
+
+ protected:
+  BOOL      (CALLBACK *HttpAddRequestHeaders_pointer)(HINTERNET, const TCHAR*, DWORD, DWORD);
+  BOOL      (CALLBACK *HttpEndRequest_pointer)(HINTERNET, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);
+  HINTERNET (CALLBACK *HttpOpenRequest_pointer)(HINTERNET, const TCHAR*, const TCHAR*, const TCHAR*, const TCHAR*, const TCHAR**, DWORD, DWORD_PTR);
+  BOOL      (CALLBACK *HttpQueryInfo_pointer)(HINTERNET, DWORD, LPVOID, LPDWORD, LPDWORD);
+  BOOL      (CALLBACK *HttpSendRequestEx_pointer)(HINTERNET, LPINTERNET_BUFFERS, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);
+  BOOL      (CALLBACK *HttpSendRequest_pointer)(HINTERNET, const TCHAR*, DWORD, LPVOID, DWORD);
+  BOOL      (CALLBACK *InternetCloseHandle_pointer)(HINTERNET);
+  HINTERNET (CALLBACK *InternetConnect_pointer)(HINTERNET, const TCHAR*, INTERNET_PORT, const TCHAR*, const TCHAR*, DWORD, DWORD, DWORD);
+  BOOL      (CALLBACK *InternetGetConnectedStateEx_pointer)(LPDWORD, char*, DWORD, DWORD);
+  HINTERNET (CALLBACK *InternetOpen_pointer)(const TCHAR*, DWORD, const TCHAR*, const TCHAR*, DWORD);
+  HINTERNET (CALLBACK *InternetOpenUrl_pointer)(HINTERNET, const TCHAR*, const TCHAR*, DWORD, DWORD, DWORD_PTR);
+  BOOL      (CALLBACK *InternetQueryDataAvailable_pointer)(HINTERNET, LPDWORD, DWORD, DWORD);
+  BOOL      (CALLBACK *InternetReadFile_pointer)(HINTERNET, LPVOID, DWORD, LPDWORD);
+  HINTERNET (CALLBACK *InternetReadFileEx_pointer)(HINTERNET, LPINTERNET_BUFFERS, DWORD, DWORD_PTR);
+  BOOL      (CALLBACK *InternetGetCookie_pointer)(const TCHAR*, const TCHAR*, TCHAR*, LPDWORD);
+  BOOL      (CALLBACK *InternetSetCookie_pointer)(const TCHAR*, const TCHAR*, const TCHAR*);
+  BOOL      (CALLBACK *InternetAutodial_pointer)(DWORD, HWND);
+  BOOL      (CALLBACK *InternetAutodialHangup_pointer)(DWORD);
+  BOOL      (CALLBACK *InternetQueryOption_pointer)(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, LPDWORD lpdwBufferLength);
+  BOOL      (CALLBACK *InternetSetOption_pointer)(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength);
+  BOOL      (CALLBACK *InternetCheckConnection_pointer)(const TCHAR*, DWORD, DWORD);
+  BOOL      (CALLBACK *InternetCrackUrl_pointer)(const TCHAR*, DWORD, DWORD, LPURL_COMPONENTS);
+  INTERNET_STATUS_CALLBACK (CALLBACK *InternetSetStatusCallback_pointer)(HINTERNET, INTERNET_STATUS_CALLBACK);
+
+  HINSTANCE library_;
+
+  void Clear();
+
+  // Simple wrapper around GetProcAddress()
+  template <typename T>
+  bool GPA(const char* function_name, T& function_pointer);   // NO LINT
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(WinInetVTable);
+};
+
+
+class InetHttpClient : public HttpClient {
+ public:
+  static InetHttpClient* Create();
+  virtual ~InetHttpClient();
+  virtual HRESULT Abort();
+  virtual uint32 GetStatus();
+  virtual HRESULT GetResponseHeader(const TCHAR* name, CString* value);
+  virtual HRESULT GetAllResponseHeaders(CString* response_headers);
+  virtual HRESULT GetResponseText(CString* response_text, uint32 max_size);
+  virtual HRESULT GetRawResponseBody(std::vector<byte>* response_body,
+                                     uint32 max_size);
+  virtual HRESULT SaveRawResponseBody(const TCHAR* response_filename,
+                                      uint32 max_size);
+  virtual HRESULT QueryProxyAuthScheme(AuthScheme* auth_scheme);
+  virtual HRESULT GetAutoProxyForUrl(const TCHAR* url, CString* proxy);
+  virtual HRESULT GetDefaultProxyConfiguration(AccessType* access_type,
+                                               CString* proxy,
+                                               CString* proxy_bypass);
+ protected:
+  virtual HRESULT InternalCrackUrl(const CString& url,
+                                   bool to_escape,
+                                   URL_COMPONENTS* url_components);
+  virtual HRESULT SendRequest(const TCHAR* server,
+                              uint32 port,
+                              const TCHAR* path);
+  virtual bool CheckConnection();
+ private:
+  InetHttpClient();
+  HRESULT Init();
+  void Close();
+  HRESULT SetTimeouts();
+  HRESULT SetHttpProxyCredentials(const TCHAR* username, const TCHAR* password);
+  HRESULT SkipSSLCertErrorIfNeeded();
+  HRESULT InternalSend(const TCHAR* server,
+                       uint32 port,
+                       const TCHAR* path,
+                       bool use_proxy);
+  HRESULT InternalGetRawResponseBody(std::vector<byte>* response_body,
+                                     const TCHAR* response_filename,
+                                     uint32 max_size);
+  static void CALLBACK StatusCallback(HINTERNET handle,
+                                      DWORD_PTR context,
+                                      DWORD status,
+                                      void* info,
+                                      DWORD info_len);
+
+  WinInetVTable wininet_;
+  HINTERNET session_handle_;
+  HINTERNET connection_handle_;
+  HINTERNET request_handle_;
+  uint32 status_;
+  bool is_initialized_;
+  bool is_aborted_;
+  LLock lock_;
+
+  // Parses the header "Proxy-Authenticate:"
+  static AtlRE proxy_auth_header_regex_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(InetHttpClient);
+};
+
+AtlRE InetHttpClient::proxy_auth_header_regex_(
+    _T("\\n*Proxy\\-Authenticate\\:\\b*{\\w}\\n*"), false);
+
+HttpClient* CreateInetHttpClient() {
+  return InetHttpClient::Create();
+}
+
+InetHttpClient* InetHttpClient::Create() {
+  scoped_ptr<InetHttpClient> http_client(new InetHttpClient());
+  if (http_client.get()) {
+    if (SUCCEEDED(http_client->Init())) {
+      return http_client.release();
+    }
+  }
+  return NULL;
+}
+
+InetHttpClient::InetHttpClient()
+    : session_handle_(NULL),
+      connection_handle_(NULL),
+      request_handle_(NULL),
+      status_(0),
+      is_initialized_(false),
+      is_aborted_(false) {
+}
+
+InetHttpClient::~InetHttpClient() {
+  Close();
+  wininet_.Unload();
+}
+
+HRESULT InetHttpClient::Abort() {
+  UTIL_LOG(L6, (_T("[InetHttpClient::Abort]")));
+
+  is_aborted_ = true;
+  Close();
+  return S_OK;
+}
+
+void InetHttpClient::Close() {
+  // Closing the handles will unblock all WinInet calls unless a call is
+  // waiting for DNS lookup, or in other words, when the state is where
+  // between INTERNET_STATUS_RESOLVING_NAME and INTERNET_STATUS_NAME_RESOLVED.
+  // In that case, closing the handles does not have any effect.
+  // This is also the case even we use async WinInet calls.
+
+  __mutexScope(lock_);
+
+  if (request_handle_) {
+    wininet_.InternetCloseHandle(request_handle_);
+    request_handle_ = NULL;
+  }
+
+  if (connection_handle_) {
+    wininet_.InternetCloseHandle(connection_handle_);
+    connection_handle_ = NULL;
+  }
+
+  if (session_handle_) {
+    wininet_.InternetCloseHandle(session_handle_);
+    session_handle_ = NULL;
+  }
+}
+
+HRESULT InetHttpClient::Init() {
+  if (is_initialized_) {
+    return E_UNEXPECTED;
+  }
+
+  is_initialized_ = true;
+
+  if (!wininet_.Load()) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[Failed to load wininet][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT InetHttpClient::SetTimeouts() {
+  ASSERT1(session_handle_);
+
+  uint32 connect_timeout_ms = connect_timeout_ms_;
+  uint32 send_timeout_ms = send_timeout_ms_;
+  uint32 receive_timeout_ms = receive_timeout_ms_;
+#if DEBUG
+  ConfigProfile::GetValue(kServerSettings,
+                          kConfigConnectTimeoutMs,
+                          &connect_timeout_ms);
+  ConfigProfile::GetValue(kServerSettings,
+                          kConfigSendTimeoutMs,
+                          &send_timeout_ms);
+  ConfigProfile::GetValue(kServerSettings,
+                          kConfigReceiveTimeoutMs,
+                          &receive_timeout_ms);
+#endif
+  if (connect_timeout_ms || send_timeout_ms || receive_timeout_ms) {
+    if (!wininet_.InternetSetOption(session_handle_,
+                                    INTERNET_OPTION_CONNECT_TIMEOUT,
+                                    &connect_timeout_ms,
+                                    sizeof(connect_timeout_ms))) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set connection timeout]")
+                             _T("[0x%08x]"), HRESULTFromLastError()));
+    }
+    if (!wininet_.InternetSetOption(session_handle_,
+                                    INTERNET_OPTION_SEND_TIMEOUT,
+                                    &send_timeout_ms,
+                                    sizeof(send_timeout_ms))) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set send timeout]")
+                             _T("[0x%08x]"), HRESULTFromLastError()));
+    }
+    if (!wininet_.InternetSetOption(session_handle_,
+                                    INTERNET_OPTION_RECEIVE_TIMEOUT,
+                                    &receive_timeout_ms,
+                                    sizeof(receive_timeout_ms))) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set receive timeout]")
+                             _T("[0x%08x]"), HRESULTFromLastError()));
+    }
+  }
+  return S_OK;
+}
+
+HRESULT InetHttpClient::SetHttpProxyCredentials(const TCHAR* username,
+                                                const TCHAR* password) {
+  ASSERT1(connection_handle_);
+
+  if (username && *username && password && *password) {
+    if (!wininet_.InternetSetOption(connection_handle_,
+                                    INTERNET_OPTION_PROXY_USERNAME,
+                                    const_cast<TCHAR*>(username),
+                                    _tcslen(username))) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set proxy authentication username]")
+                             _T("[0x%08x]"), HRESULTFromLastError()));
+    }
+    if (!wininet_.InternetSetOption(connection_handle_,
+                                    INTERNET_OPTION_PROXY_PASSWORD,
+                                    const_cast<TCHAR*>(password),
+                                    _tcslen(password))) {
+      UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set proxy authentication password]")
+                             _T("[0x%08x]"), HRESULTFromLastError()));
+    }
+  }
+  return S_OK;
+}
+
+HRESULT InetHttpClient::SkipSSLCertErrorIfNeeded() {
+#if DEBUG
+  ASSERT1(request_handle_);
+
+  bool ignore_certificate_errors = false;
+  ConfigProfile::GetValue(kServerSettings,
+                          kConfigSecurityIgnoreCertificateErrors,
+                          &ignore_certificate_errors);
+  if (ignore_certificate_errors) {
+    UTIL_LOG(L6, (_T("[InetHttpClient::SkipSSLCertErrorIfNeeded]")
+                  _T("[ignore certificate error]")));
+    DWORD flags = 0;
+    DWORD flags_len = sizeof(flags);
+    if (wininet_.InternetQueryOption(request_handle_,
+                                     INTERNET_OPTION_SECURITY_FLAGS,
+                                     &flags,
+                                     &flags_len)) {
+      flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA |
+               SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
+      if (!wininet_.InternetSetOption(request_handle_,
+                                      INTERNET_OPTION_SECURITY_FLAGS,
+                                      &flags,
+                                      sizeof(flags))) {
+        UTIL_LOG(LEVEL_ERROR, (_T("[Failed to set ignore SSL cert error]")
+                               _T("[0x%08x]"), HRESULTFromLastError()));
+      }
+    } else {
+      UTIL_LOG(LEVEL_ERROR, (_T("[InternetQueryOption failed]")
+                             _T("[0x%08x]"), HRESULTFromLastError()));
+    }
+  }
+#endif
+
+  return S_OK;
+}
+
+HRESULT InetHttpClient::SendRequest(const TCHAR* server,
+                                    uint32 port,
+                                    const TCHAR* path) {
+  ASSERT1(server && *server);
+  ASSERT1(path && *path);
+
+  UTIL_LOG(L6, (_T("[InetHttpClient::SendRequest]")
+                _T("[%s:%u%s]"), server, port, path));
+
+  // When we are using WinInet http client, we will encouter auto-dial if the
+  // user sets "Always dial my default connection" in Internet Explorer.
+  // To fix this problem, we will check whether there is an active Internet
+  // connection first.
+  if (!IsMachineConnected()) {
+    return HRESULT_FROM_WIN32(ERROR_INTERNET_CANNOT_CONNECT);
+  }
+
+  HRESULT hr = S_OK;
+
+  for (uint32 i = 0; i < 1 + retries_; ++i) {
+    if (i > 0) {
+      ::Sleep(retry_delay_ms_);
+      UTIL_LOG(L6, (_T("[InetHttpClient::SendRequest - retry %u]"), i));
+    }
+
+    hr = InternalSend(server, port, path, true);
+    if (retry_without_proxy_ && !proxy_server_.IsEmpty() &&
+        (FAILED(hr) || (status_ != HTTP_STATUS_OK &&
+                        status_ != HTTP_STATUS_NOT_MODIFIED))) {
+      UTIL_LOG(L6, (_T("[failed with proxy]")
+                    _T("[%s][%u][0x%08x]"), proxy_server_, hr));
+      hr = InternalSend(server, port, path, false);
+      if (SUCCEEDED(hr)) {
+        UTIL_LOG(L6, (_T("[switch to direct connection]")));
+        GetProxyConfig()->SwitchAutoProxyToDirectConnection();
+      }
+    }
+    if (SUCCEEDED(hr)) {
+      break;
+    }
+  }
+
+  if (FAILED(hr)) {
+    // Convert hresults to be of the CI_E format.
+    // If you need to be aware of another error code, then
+    // add another CI_E_ error to this type of switch statment
+    // in every HttpClient::Send method.
+    //
+    // __HRESULT_FROM_WIN32 will always be a macro where as
+    // HRESULT_FROM_WIN32 can be an inline function. Using HRESULT_FROM_WIN32
+    // can break the switch statement.
+    //
+    // TODO(omaha):  refactor weird switch.
+    switch (hr) {
+      case __HRESULT_FROM_WIN32(ERROR_INTERNET_SEC_CERT_DATE_INVALID):
+        hr = CI_E_HTTPS_CERT_FAILURE;
+        break;
+    }
+  }
+
+  return hr;
+}
+
+HRESULT InetHttpClient::InternalSend(const TCHAR* server,
+                                     uint32 port,
+                                     const TCHAR* path,
+                                     bool use_proxy) {
+  ASSERT1(server && *server);
+  ASSERT1(path && *path);
+
+  UTIL_LOG(L6, (_T("[InetHttpClient::InternalSend]")
+                _T("[%s:%u%s][%u]"), server, port, path, use_proxy));
+
+  HRESULT hr = S_OK;
+
+  // Close all handles from previous request.
+  Close();
+
+  // Open the Internet session.
+  if (!use_proxy ||  proxy_server_.IsEmpty()) {
+    session_handle_ = wininet_.InternetOpen(NULL,
+                                            INTERNET_OPEN_TYPE_DIRECT,
+                                            NULL,
+                                            NULL,
+                                            0);
+  } else {
+    session_handle_ = wininet_.InternetOpen(NULL,
+                                            INTERNET_OPEN_TYPE_PROXY,
+                                            proxy_server_,
+                                            NULL,
+                                            0);
+  }
+  if (!session_handle_) {
+    hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[InternetOpen failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (is_aborted_) {
+    return E_ABORT;
+  }
+
+  // Set timeouts.
+  SetTimeouts();
+
+  if (is_aborted_) {
+    return E_ABORT;
+  }
+
+  // Connect to the server
+  connection_handle_ = wininet_.InternetConnect(
+                                    session_handle_,
+                                    server,
+                                    static_cast<INTERNET_PORT>(port),
+                                    NULL,
+                                    NULL,
+                                    INTERNET_SERVICE_HTTP,
+                                    0,
+                                    NULL);
+  if (!connection_handle_) {
+    hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[InternetConnect failed]")
+                           _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
+    return hr;
+  }
+
+  if (is_aborted_) {
+    return E_ABORT;
+  }
+
+  // Set proxy credentials.
+  if (use_proxy) {
+    SetHttpProxyCredentials(proxy_auth_username_, proxy_auth_password_);
+  }
+
+  if (is_aborted_) {
+    return E_ABORT;
+  }
+
+  // Prepare the flags.
+  DWORD flags = no_cache_ ? kInternetRequestNoCacheDefaultFlags :
+                            kInternetRequestCachingDefaultFlags;
+  if (port == kDefaultSslProxyPort) {
+    flags |= INTERNET_FLAG_SECURE;
+  }
+
+  // Send the request. A context is required otherwise the callback won't happen
+  // even if the WinInet is used in synchronous mode.
+  DWORD_PTR context = reinterpret_cast<DWORD_PTR>(this);
+  if (post_data_.empty()) {
+    // For GET.
+    request_handle_ = wininet_.HttpOpenRequest(connection_handle_,
+                                               kHttpGetMethod,
+                                               path,
+                                               NULL,
+                                               NULL,
+                                               NULL,
+                                               flags,
+                                               context);
+    if (!request_handle_) {
+      hr = HRESULTFromLastError();
+      UTIL_LOG(LEVEL_ERROR, (_T("[HttpOpenRequest failed to open GET request]")
+                             _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
+      return hr;
+    }
+
+    INTERNET_STATUS_CALLBACK old_callback =
+        wininet_.InternetSetStatusCallback(request_handle_, &StatusCallback);
+    ASSERT1(old_callback == NULL);
+    if (old_callback != INTERNET_INVALID_STATUS_CALLBACK) {
+      UTIL_LOG(L6, (_T("[InternetSetStatusCallback succeeded]")
+                    _T("[0x%08x]"), request_handle_));
+    } else {
+      hr = HRESULTFromLastError();
+      UTIL_LOG(LEVEL_WARNING, (_T("[InternetSetStatusCallback failed]")
+                               _T("[%s:%u%s][0x%08x]"),
+                               server, port, path, hr));
+    }
+
+    if (is_aborted_) {
+      return E_ABORT;
+    }
+
+    if (port == kDefaultSslProxyPort) {
+      SkipSSLCertErrorIfNeeded();
+    }
+
+    if (is_aborted_) {
+      return E_ABORT;
+    }
+
+    if (!wininet_.HttpSendRequest(request_handle_,
+                                  additional_headers_.GetString(),
+                                  additional_headers_.GetLength(),
+                                  NULL,
+                                  0)) {
+      hr = HRESULTFromLastError();
+      UTIL_LOG(LEVEL_ERROR, (_T("[HttpSendRequest failed to send GET request]")
+                             _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
+
+      // Occasionally setting the option to skip SSL certificate error before
+      // sending the request does not work. We have to set it again after
+      // failed to send the request.
+      if (port == kDefaultSslProxyPort) {
+        SkipSSLCertErrorIfNeeded();
+        if (!wininet_.HttpSendRequest(request_handle_,
+                                      additional_headers_.GetString(),
+                                      additional_headers_.GetLength(),
+                                      NULL,
+                                      0)) {
+          hr = HRESULTFromLastError();
+          UTIL_LOG(LEVEL_ERROR, (_T("[HttpSendRequest failed to resend GET]")
+                                 _T("[%s:%u%s][0x%08x]"),
+                                 server, port, path, hr));
+        } else {
+          hr = S_OK;
+        }
+      }
+
+      if (FAILED(hr)) {
+        return hr;
+      }
+    }
+  } else {
+    // For post
+    request_handle_ = wininet_.HttpOpenRequest(connection_handle_,
+                                               kHttpPostMethod,
+                                               path,
+                                               NULL,
+                                               NULL,
+                                               NULL,
+                                               flags,
+                                               context);
+    if (!request_handle_) {
+      hr = HRESULTFromLastError();
+      UTIL_LOG(LEVEL_ERROR, (_T("[HttpOpenRequest failed to open POST request]")
+                             _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
+      return hr;
+    }
+
+    INTERNET_STATUS_CALLBACK old_callback =
+        wininet_.InternetSetStatusCallback(request_handle_, StatusCallback);
+    ASSERT1(old_callback == NULL);
+    if (old_callback != INTERNET_INVALID_STATUS_CALLBACK) {
+      UTIL_LOG(L6, (_T("[InternetSetStatusCallback succeeded]")
+                    _T("[0x%08x]"), request_handle_));
+    } else {
+      hr = HRESULTFromLastError();
+      UTIL_LOG(LEVEL_WARNING, (_T("[InternetSetStatusCallback failed]")
+                               _T("[%s:%u%s][0x%08x]"),
+                               server, port, path, hr));
+    }
+
+    if (is_aborted_) {
+      return E_ABORT;
+    }
+
+    SkipSSLCertErrorIfNeeded();
+
+    if (is_aborted_) {
+      return E_ABORT;
+    }
+
+    if (!wininet_.HttpSendRequest(request_handle_,
+                                  additional_headers_.GetString(),
+                                  additional_headers_.GetLength(),
+                                  &post_data_.front(),
+                                  post_data_.size())) {
+      hr = HRESULTFromLastError();
+      UTIL_LOG(LEVEL_ERROR, (_T("[HttpSendRequest failed to send POST request]")
+                             _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
+      return hr;
+    }
+  }
+
+  if (is_aborted_) {
+    return E_ABORT;
+  }
+
+  // Get the response status.
+  DWORD value = 0;
+  DWORD value_size = sizeof(value);
+  if (!wininet_.HttpQueryInfo(request_handle_,
+                              HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
+                              &value,
+                              &value_size,
+                              0)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed to get status]")
+                           _T("[%s:%u%s][0x%08x]"), server, port, path, hr));
+    return hr;
+  }
+
+  status_ = static_cast<uint32>(value);
+  return S_OK;
+}
+
+uint32 InetHttpClient::GetStatus() {
+  return status_;
+}
+
+HRESULT InetHttpClient::GetResponseHeader(const TCHAR* name, CString* value) {
+  ASSERT1(name && *name);
+  ASSERT1(value);
+
+  if (!status_) {
+    return E_FAIL;
+  }
+
+  HRESULT hr = S_OK;
+
+  value->SetString(name);
+  TCHAR* buf = value->GetBuffer();
+  DWORD size = value->GetLength() * sizeof(TCHAR);
+  if (wininet_.HttpQueryInfo(request_handle_,
+                             HTTP_QUERY_CUSTOM,
+                             buf,
+                             &size,
+                             0)) {
+    value->ReleaseBuffer(size / sizeof(TCHAR));
+  } else {
+    DWORD error = ::GetLastError();
+    if (error == ERROR_INSUFFICIENT_BUFFER) {
+      buf = value->GetBufferSetLength(size / sizeof(TCHAR));
+      if (!wininet_.HttpQueryInfo(request_handle_,
+                                  HTTP_QUERY_CUSTOM,
+                                  buf,
+                                  &size,
+                                  0)) {
+        hr = HRESULTFromLastError();
+        UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));
+      }
+      value->ReleaseBuffer(size / sizeof(TCHAR));
+    } else {
+      hr = HRESULT_FROM_WIN32(error);
+      UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));
+    }
+  }
+
+  return hr;
+}
+
+HRESULT InetHttpClient::GetAllResponseHeaders(CString* response_headers) {
+  ASSERT1(response_headers);
+  ASSERT1(request_handle_);
+
+  if (!status_) {
+    return E_FAIL;
+  }
+
+  HRESULT hr = S_OK;
+
+  DWORD size = 0;
+  if (!wininet_.HttpQueryInfo(request_handle_,
+                              HTTP_QUERY_RAW_HEADERS_CRLF,
+                              NULL,
+                              &size,
+                              0)) {
+    DWORD error = ::GetLastError();
+    if (error == ERROR_INSUFFICIENT_BUFFER) {
+      TCHAR* buf = response_headers->GetBufferSetLength(size / sizeof(TCHAR));
+      if (!wininet_.HttpQueryInfo(request_handle_,
+                                  HTTP_QUERY_RAW_HEADERS_CRLF,
+                                  buf,
+                                  &size,
+                                  0)) {
+        hr = HRESULTFromLastError();
+        UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));
+      }
+      response_headers->ReleaseBuffer(size / sizeof(TCHAR));
+    } else {
+      hr = HRESULT_FROM_WIN32(error);
+      UTIL_LOG(LEVEL_ERROR, (_T("[HttpQueryInfo failed][0x%08x]"), hr));
+    }
+  }
+
+  return hr;
+}
+
+HRESULT InetHttpClient::GetResponseText(CString* response_text,
+                                        uint32 max_size) {
+  ASSERT1(response_text);
+  ASSERT1(request_handle_);
+
+  if (!status_) {
+    return E_FAIL;
+  }
+
+  const int kBufferSize = 1024;
+  char buffer[kBufferSize] = {0};
+
+  CStringA ansi_response_text;
+  uint32 size = 0;
+  while (true) {
+    if (is_aborted_) {
+      return E_ABORT;
+    }
+
+    DWORD bytes_read = 0;
+    if (wininet_.InternetReadFile(request_handle_,
+                                  buffer,
+                                  kBufferSize,
+                                  &bytes_read) && bytes_read) {
+      size += bytes_read;
+      if (max_size && size > max_size) {
+        return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+      }
+      ansi_response_text.Append(buffer, bytes_read);
+    } else {
+      break;
+    }
+  }
+
+  response_text->SetString(Utf8ToWideChar(ansi_response_text.GetString(),
+                                          ansi_response_text.GetLength()));
+
+  return S_OK;
+}
+
+HRESULT InetHttpClient::GetRawResponseBody(std::vector<byte>* response_body,
+                                           uint32 max_size) {
+  return InternalGetRawResponseBody(response_body, NULL, max_size);
+}
+
+HRESULT InetHttpClient::SaveRawResponseBody(const TCHAR* response_filename,
+                                            uint32 max_size) {
+  return InternalGetRawResponseBody(NULL, response_filename, max_size);
+}
+
+HRESULT InetHttpClient::InternalGetRawResponseBody(
+                            std::vector<byte>* response_body,
+                            const TCHAR* response_filename,
+                            uint32 max_size) {
+  ASSERT((response_body != NULL) ^ (response_filename != NULL), (_T("")));
+  ASSERT1(request_handle_);
+
+  if (!status_) {
+    return E_FAIL;
+  }
+
+  HRESULT hr = S_OK;
+  scoped_hfile file;
+
+  if (response_body) {
+    response_body->clear();
+  } else {
+    reset(file, ::CreateFile(response_filename,
+                             FILE_WRITE_DATA,
+                             0,
+                             NULL,
+                             CREATE_ALWAYS,
+                             0,
+                             NULL));
+    if (!file) {
+      return HRESULTFromLastError();
+    }
+  }
+
+  const int kBufferSize = 1024;
+  char buffer[kBufferSize];
+  uint32 size = 0;
+  while (true) {
+    if (is_aborted_) {
+      return E_ABORT;
+    }
+
+    DWORD bytes_read = 0;
+    if (wininet_.InternetReadFile(request_handle_,
+                                  buffer,
+                                  kBufferSize,
+                                  &bytes_read) && bytes_read) {
+      size += bytes_read;
+      if (max_size && size > max_size) {
+        return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+      }
+      if (response_body) {
+        response_body->insert(response_body->end(),
+                              buffer,
+                              buffer + bytes_read);
+      } else {
+        DWORD bytes_written = 0;
+        if (!::WriteFile(get(file), buffer, bytes_read, &bytes_written, NULL)) {
+          hr = HRESULTFromLastError();
+          break;
+        }
+      }
+    } else {
+      break;
+    }
+  }
+
+  return hr;
+}
+
+HRESULT InetHttpClient::QueryProxyAuthScheme(AuthScheme* auth_scheme) {
+  ASSERT1(auth_scheme);
+
+  *auth_scheme = NO_AUTH_SCHEME;
+
+  // Find out authentication scheme by communicating with google server via
+  // proxy server and checking the response header to find out the
+  // authentication scheme the proxy server requires.
+
+  // Send the request to query google server only if we have not got 407 error.
+  HRESULT hr = S_OK;
+  if (status_ != HTTP_STATUS_PROXY_AUTH_REQ) {
+    hr = SendRequest(kGoogleHttpServer, kDefaultHttpProxyPort, _T("/"));
+  }
+  if (SUCCEEDED(hr) && status_ == HTTP_STATUS_PROXY_AUTH_REQ) {
+    CString response_headers;
+    hr = GetAllResponseHeaders(&response_headers);
+    if (SUCCEEDED(hr)) {
+      const TCHAR* response_headers_str = response_headers.GetString();
+      CString auth_scheme_str;
+      AuthScheme curr_auth_scheme = NO_AUTH_SCHEME;
+      while (AtlRE::FindAndConsume(&response_headers_str,
+                                   proxy_auth_header_regex_,
+                                   &auth_scheme_str)) {
+        AuthScheme other_auth_scheme = NO_AUTH_SCHEME;
+        if (auth_scheme_str.CompareNoCase(kNegotiateAuthScheme) == 0) {
+          other_auth_scheme = AUTH_SCHEME_NEGOTIATE;
+        } else if (auth_scheme_str.CompareNoCase(kNTLMAuthScheme) == 0) {
+          other_auth_scheme = AUTH_SCHEME_NTLM;
+        } else if (auth_scheme_str.CompareNoCase(kDigestAuthScheme) == 0) {
+          other_auth_scheme = AUTH_SCHEME_DIGEST;
+        } else if (auth_scheme_str.CompareNoCase(kBasicAuthScheme) == 0) {
+          other_auth_scheme = AUTH_SCHEME_BASIC;
+        } else {
+          other_auth_scheme = UNKNOWN_AUTH_SCHEME;
+        }
+        if (static_cast<int>(other_auth_scheme) >
+            static_cast<int>(curr_auth_scheme)) {
+          curr_auth_scheme = other_auth_scheme;
+        }
+      }
+      *auth_scheme = curr_auth_scheme;
+      return S_OK;
+    }
+  }
+
+  return E_FAIL;
+}
+
+// We do not support Auto-proxy for WinInet because jsproxy.dll seems to be
+// very instable and cause crashes from time to time.
+HRESULT InetHttpClient::GetAutoProxyForUrl(const TCHAR*, CString*) {
+  return E_NOTIMPL;
+}
+
+HRESULT InetHttpClient::GetDefaultProxyConfiguration(AccessType* access_type,
+                                                     CString* proxy,
+                                                     CString* proxy_bypass) {
+  DWORD size_needed = 0;
+  if (wininet_.InternetQueryOption(NULL,
+                                   INTERNET_OPTION_PROXY,
+                                   NULL,
+                                   &size_needed) ||
+      ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+    UTIL_LOG(LEVEL_ERROR, (_T("[InternetQueryOption failed]")));
+    return E_FAIL;
+  }
+
+  scoped_array<byte> proxy_info_buffer(new byte[size_needed]);
+  if (!wininet_.InternetQueryOption(NULL,
+                                    INTERNET_OPTION_PROXY,
+                                    proxy_info_buffer.get(),
+                                    &size_needed)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[InternetQueryOption failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  INTERNET_PROXY_INFO* proxy_info = reinterpret_cast<INTERNET_PROXY_INFO*>(
+                                        proxy_info_buffer.get());
+
+  if (access_type) {
+    if (proxy_info->dwAccessType == INTERNET_OPEN_TYPE_DIRECT) {
+      *access_type = NO_PROXY;
+    } else if (proxy_info->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
+      *access_type = NAMED_PROXY;
+    } else {
+      *access_type = AUTO_PROXY_AUTO_DETECT;
+    }
+  }
+
+  if (proxy) {
+    // proxy_info->lpszProxy points to an ASCII string.
+    *proxy = reinterpret_cast<const char*>(proxy_info->lpszProxy);
+  }
+
+  if (proxy_bypass) {
+    // proxy_info->lpszProxyBypass points to an ASCII string.
+    *proxy_bypass = reinterpret_cast<const char*>(proxy_info->lpszProxyBypass);
+  }
+
+  return S_OK;
+}
+
+// TODO(omaha): check connection by requesting a well known url instead of
+// using WinInet. The WinInet code does an ICMP ping apparently, which is
+// usually blocked by firewalls.
+bool InetHttpClient::CheckConnection() {
+  return wininet_.InternetCheckConnection(
+      kHttpProtoScheme kProtoSuffix kGoogleHttpServer _T("/"),
+      FLAG_ICC_FORCE_CONNECTION, 0) == TRUE;
+}
+
+HRESULT InetHttpClient::InternalCrackUrl(const CString& url, bool to_escape,
+                                         URL_COMPONENTS* url_components) {
+  ASSERT(!url.IsEmpty(), (_T("")));
+  ASSERT1(url_components);
+
+  if (!wininet_.InternetCrackUrl(url.GetString(),
+                                 url.GetLength(),
+                                 to_escape ? ICU_ESCAPE : 0,
+                                 url_components)) {
+    HRESULT hr = HRESULTFromLastError();
+    UTIL_LOG(LEVEL_ERROR, (_T("[InternetCrackUrl failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+void CALLBACK InetHttpClient::StatusCallback(HINTERNET handle,
+                                             DWORD_PTR context,
+                                             DWORD status,
+                                             void* info,
+                                             DWORD info_len) {
+  // Unlike WinHttp, the ip addresses are not unicode strings.
+  CString info_string;
+  switch (status) {
+    case INTERNET_STATUS_RESOLVING_NAME:
+      status = CALLBACK_STATUS_RESOLVING_NAME;
+      break;
+    case INTERNET_STATUS_NAME_RESOLVED:
+      info_string = static_cast<char*>(info);
+      info = info_string.GetBuffer();
+      status = CALLBACK_STATUS_NAME_RESOLVED;
+      break;
+    case INTERNET_STATUS_CONNECTING_TO_SERVER:
+      info_string = static_cast<char*>(info);
+      info = info_string.GetBuffer();
+      status = CALLBACK_STATUS_CONNECTING_TO_SERVER;
+      break;
+    case INTERNET_STATUS_CONNECTED_TO_SERVER:
+      info_string = static_cast<char*>(info);
+      info = info_string.GetBuffer();
+      status = CALLBACK_STATUS_CONNECTED_TO_SERVER;
+      break;
+    case INTERNET_STATUS_SENDING_REQUEST:
+      status = CALLBACK_STATUS_SENDING_REQUEST;
+      break;
+    case INTERNET_STATUS_REQUEST_SENT:
+      status = CALLBACK_STATUS_REQUEST_SENT;
+      break;
+    case INTERNET_STATUS_RECEIVING_RESPONSE:
+      status = CALLBACK_STATUS_RECEIVING_RESPONSE;
+      break;
+    case INTERNET_STATUS_RESPONSE_RECEIVED:
+      status = CALLBACK_STATUS_RESPONSE_RECEIVED;
+      break;
+    case INTERNET_STATUS_CLOSING_CONNECTION:
+      status = CALLBACK_STATUS_CLOSING_CONNECTION;
+      break;
+    case INTERNET_STATUS_CONNECTION_CLOSED:
+      status = CALLBACK_STATUS_CONNECTION_CLOSED;
+      break;
+    case INTERNET_STATUS_REDIRECT:
+      status = CALLBACK_STATUS_REDIRECT;
+      break;
+    default:
+      return;
+  };
+  HttpClient::StatusCallback(handle, context, status, info, info_len);
+}
+
+// WinInetVTable: delay-loading of WININET.DLL.
+// Handling of and protection of Wininet APIs.
+//   Dynamically load to wininet.dll.
+//   Wrap all calls in an Structured Exception handler - wininet is buggy and
+//   throws access violations
+WinInetVTable::WinInetVTable() { Clear(); }
+WinInetVTable::~WinInetVTable() { Unload(); }
+
+template <typename T>
+bool WinInetVTable::GPA(const char* function_name,
+                        T& function_pointer) {      // NO LINT
+  ASSERT(function_name, (L""));
+  function_pointer = reinterpret_cast<T>(::GetProcAddress(library_,
+                                                          function_name));
+  return NULL != function_pointer;
+}
+
+bool WinInetVTable::Load() {
+  if (Loaded()) {
+    return true;
+  }
+
+  Clear();
+
+  {
+    library_ = ::LoadLibrary(_T("wininet"));
+  }
+  if (!library_) {
+    return false;
+  }
+
+  bool all_valid = (
+         GPA("HttpAddRequestHeadersW",       HttpAddRequestHeaders_pointer))
+      & (GPA("HttpEndRequestW",              HttpEndRequest_pointer))
+      & (GPA("HttpOpenRequestW",             HttpOpenRequest_pointer))
+      & (GPA("HttpQueryInfoW",               HttpQueryInfo_pointer))
+      & (GPA("HttpSendRequestExW",           HttpSendRequestEx_pointer))
+      & (GPA("HttpSendRequestW",             HttpSendRequest_pointer))
+      & (GPA("InternetCloseHandle",          InternetCloseHandle_pointer))
+      & (GPA("InternetConnectW",             InternetConnect_pointer))
+      & (GPA("InternetGetConnectedStateExW", InternetGetConnectedStateEx_pointer))
+      & (GPA("InternetOpenW",                InternetOpen_pointer))
+      & (GPA("InternetOpenUrlW",             InternetOpenUrl_pointer))
+      & (GPA("InternetQueryDataAvailable",   InternetQueryDataAvailable_pointer))
+      & (GPA("InternetReadFile",             InternetReadFile_pointer))
+      & (GPA("InternetReadFileExW",          InternetReadFileEx_pointer))
+      & (GPA("InternetSetStatusCallbackW",   InternetSetStatusCallback_pointer))
+      & (GPA("InternetGetCookieW",           InternetGetCookie_pointer))
+      & (GPA("InternetSetCookieW",           InternetSetCookie_pointer))
+      & (GPA("InternetAutodial",             InternetAutodial_pointer))
+      & (GPA("InternetAutodialHangup",       InternetAutodialHangup_pointer))
+      & (GPA("InternetQueryOptionW",         InternetQueryOption_pointer))
+      & (GPA("InternetSetOptionW",           InternetSetOption_pointer))
+      & (GPA("InternetCheckConnectionW",     InternetCheckConnection_pointer))
+      & (GPA("InternetCrackUrlW",            InternetCrackUrl_pointer));
+
+  if (!all_valid) {
+    Unload();
+  }
+
+  return all_valid;
+}
+
+void WinInetVTable::Unload() {
+  if (library_) {
+    ::FreeLibrary(library_);
+    library_ = NULL;
+  }
+  Clear();
+}
+
+void WinInetVTable::Clear() {
+  ::memset(this, 0, sizeof(*this));
+}
+
+#define PROTECT_WRAP(function, proto, call, result_type, result_error_value)  \
+result_type WinInetVTable::function proto {                  \
+    result_type result;                                      \
+    __try {                                                  \
+      result = function##_pointer call;                      \
+    }                                                        \
+    __except(EXCEPTION_EXECUTE_HANDLER) {                    \
+      result = result_error_value;                           \
+    }                                                        \
+    return result;                                           \
+}
+
+PROTECT_WRAP(HttpAddRequestHeaders, (HINTERNET a, const TCHAR* b, DWORD c, DWORD d), (a, b, c, d), BOOL, FALSE);
+PROTECT_WRAP(HttpEndRequest, (HINTERNET a, LPINTERNET_BUFFERS b, DWORD c, DWORD_PTR d), (a, b, c, d), BOOL, FALSE);
+PROTECT_WRAP(HttpOpenRequest, (HINTERNET a, const TCHAR* b, const TCHAR* c, const TCHAR* d, const TCHAR* e, const TCHAR** f, DWORD g, DWORD_PTR h), (a, b, c, d, e, f, g, h), HINTERNET, NULL);
+PROTECT_WRAP(HttpQueryInfo, (HINTERNET a, DWORD b, LPVOID c, LPDWORD d, LPDWORD e), (a, b, c, d, e), BOOL, FALSE);
+PROTECT_WRAP(HttpSendRequestEx, (HINTERNET a, LPINTERNET_BUFFERS b, LPINTERNET_BUFFERS c, DWORD d, DWORD_PTR e), (a, b, c, d, e), BOOL, FALSE);
+PROTECT_WRAP(HttpSendRequest, (HINTERNET a, const TCHAR* b, DWORD c, LPVOID d, DWORD e), (a, b, c, d, e), BOOL, FALSE);
+PROTECT_WRAP(InternetCloseHandle, (HINTERNET a), (a), BOOL, FALSE);
+PROTECT_WRAP(InternetConnect, (HINTERNET a, const TCHAR* b, INTERNET_PORT c, const TCHAR* d, const TCHAR* e, DWORD f, DWORD g, DWORD h), (a, b, c, d, e, f, g, h), HINTERNET, NULL);
+PROTECT_WRAP(InternetGetConnectedStateEx, (LPDWORD a, char* b, DWORD c, DWORD d), (a, b, c, d), BOOL, FALSE);
+PROTECT_WRAP(InternetOpen, (const TCHAR* a, DWORD b, const TCHAR* c, const TCHAR* d, DWORD e), (a, b, c, d, e), HINTERNET, NULL);
+PROTECT_WRAP(InternetOpenUrl, (HINTERNET a, const TCHAR* b, const TCHAR* c, DWORD d, DWORD e, DWORD_PTR f), (a, b, c, d, e, f), HINTERNET, NULL);
+PROTECT_WRAP(InternetQueryDataAvailable, (HINTERNET a, LPDWORD b, DWORD c, DWORD d), (a, b, c, d), BOOL, FALSE);
+PROTECT_WRAP(InternetReadFile, (HINTERNET a, LPVOID b, DWORD c, LPDWORD d), (a, b, c, d), BOOL, FALSE);
+PROTECT_WRAP(InternetReadFileEx, (HINTERNET a, LPINTERNET_BUFFERS b, DWORD c, DWORD_PTR d), (a, b, c, d), HINTERNET, NULL);
+PROTECT_WRAP(InternetSetStatusCallback, (HINTERNET a, INTERNET_STATUS_CALLBACK b), (a, b), INTERNET_STATUS_CALLBACK, INTERNET_INVALID_STATUS_CALLBACK);
+PROTECT_WRAP(InternetGetCookie, (const TCHAR* a, const TCHAR* b, TCHAR* c, LPDWORD d), (a, b, c, d), BOOL, FALSE);
+PROTECT_WRAP(InternetSetCookie, (const TCHAR* a, const TCHAR* b, const TCHAR* c), (a, b, c), BOOL, FALSE);
+PROTECT_WRAP(InternetAutodial, (DWORD a, HWND b), (a, b), BOOL, FALSE);
+PROTECT_WRAP(InternetAutodialHangup, (DWORD a), (a), BOOL, FALSE);
+PROTECT_WRAP(InternetQueryOption, (HINTERNET a, DWORD b, LPVOID c, LPDWORD d), (a, b, c, d), BOOL, FALSE);
+PROTECT_WRAP(InternetSetOption, (HINTERNET a, DWORD b, LPVOID c, DWORD d), (a, b, c, d), BOOL, FALSE);
+PROTECT_WRAP(InternetCheckConnection, (const TCHAR* a, DWORD b, DWORD c), (a, b, c), BOOL, FALSE);
+PROTECT_WRAP(InternetCrackUrl, (const TCHAR* a, DWORD b, DWORD c, LPURL_COMPONENTS d), (a, b, c, d), BOOL, FALSE);
+#endif
+
diff --git a/plugins/baseplugin.cc b/plugins/baseplugin.cc
index e0b2659..dd3ac71 100644
--- a/plugins/baseplugin.cc
+++ b/plugins/baseplugin.cc
@@ -1,255 +1,255 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Base implementation and build blocks for NPAPI Plugins

-// using the new NPRuntime supported by Firefox and others

-//

-// Mozilla doesn't currently have a framework in place for

-// building plug-ins using the new NPRuntime model, so

-// I had to roll my own.

-

-#include "plugins/baseplugin.h"

-#include "omaha/third_party/gecko/include/npupp.h"

-

-BasePlugin::BasePlugin(NPP npp)

-    : npp_(npp) {

-  NPN_GetValue(npp_, NPNVWindowNPObject, &window_object_);

-  NPN_RetainObject(window_object_);

-}

-

-BasePlugin::~BasePlugin() {

-  if (window_object_) {

-    NPN_ReleaseObject(window_object_);

-  }

-}

-

-void BasePlugin::InitializePluginMap() {

-  // Go through the list of IDs

-  PLUGIN_MAP* pDispMap = GetPluginMap();

-  PLUGIN_MAP_ENTRY* pEntry;

-

-  if (pDispMap != NULL) {

-    // populate all entries

-    pEntry = pDispMap->entries;

-    while (pEntry->name != NULL) {

-      pEntry->np_id = NPN_GetStringIdentifier(pEntry->name);

-      ++pEntry;

-    }

-  }

-}

-

-PLUGIN_MAP_ENTRY* BasePlugin::GetPluginEntry(NPIdentifier np_id)  {

-  PLUGIN_MAP* pDispMap = GetPluginMap();

-  PLUGIN_MAP_ENTRY* pEntry;

-

-  if (pDispMap != NULL) {

-    // search for entry

-    pEntry = pDispMap->entries;

-    while (pEntry->np_id != NULL) {

-      if (pEntry->np_id == np_id) {

-        return pEntry;

-      }

-      ++pEntry;

-    }

-  }

-

-  return NULL;  // name not found

-}

-

-bool BasePlugin::HasMethod(NPIdentifier name)  {

-  PLUGIN_MAP_ENTRY* pEntry = GetPluginEntry(name);

-  return pEntry && !pEntry->function_get;

-}

-

-bool BasePlugin::InvokeDefault(const NPVariant *args,

-                               uint32_t argument_count,

-                               NPVariant *result) {

-  UNREFERENCED_PARAMETER(args);

-  UNREFERENCED_PARAMETER(argument_count);

-  UNREFERENCED_PARAMETER(result);

-  return false;

-}

-

-

-bool BasePlugin::Invoke(NPIdentifier name,

-                        const NPVariant *args,

-                        uint32_t argument_count,

-                        NPVariant *result)  {

-  // get entry for the member ID

-  PLUGIN_MAP_ENTRY* pEntry = GetPluginEntry(name);

-  if (pEntry == NULL || pEntry->function_get) {

-    return false;

-  }

-

-  // do standard method call

-  return (this->*(pEntry->function))(args, argument_count, result);

-}

-

-bool BasePlugin::HasProperty(NPIdentifier name)  {

-  PLUGIN_MAP_ENTRY* pEntry = GetPluginEntry(name);

-  return pEntry && pEntry->function_get;

-}

-

-bool BasePlugin::GetProperty(NPIdentifier name, NPVariant *result) {

-  PLUGIN_MAP_ENTRY* pEntry = GetPluginEntry(name);

-  if (pEntry == NULL || !pEntry->function_get) {

-    return false;

-  }

-

-  // do standard method call

-  return (this->*(pEntry->function_get))(result);

-}

-

-bool BasePlugin::SetProperty(NPIdentifier name,

-                             const NPVariant *value) {

-  // get entry for the member ID

-  PLUGIN_MAP_ENTRY* pEntry = GetPluginEntry(name);

-  if (pEntry == NULL || !pEntry->function_get) {

-    return false;

-  }

-

-  // do standard method call

-  return (this->*(pEntry->function_set))(value);

-}

-

-

-void BasePlugin::Invalidate() {

-}

-

-bool BasePlugin::RemoveProperty(NPIdentifier name)  {

-  UNREFERENCED_PARAMETER(name);

-  return false;

-}

-

-void BasePlugin::Shutdown() {

-}

-

-// static

-void BasePlugin::_Deallocate(NPObject *npobj) {

-  // Call the virtual destructor.

-  delete static_cast<BasePlugin *>(npobj);

-}

-

-// static

-void BasePlugin::_Invalidate(NPObject *npobj) {

-  (static_cast<BasePlugin *>(npobj))->Invalidate();

-}

-

-// static

-bool BasePlugin::_HasMethod(NPObject *npobj, NPIdentifier name)  {

-  return (static_cast<BasePlugin *>(npobj))->HasMethod(name);

-}

-

-// static

-bool BasePlugin::_Invoke(NPObject *npobj,

-                         NPIdentifier name,

-                         const NPVariant *args,

-                         uint32_t argument_count,

-                         NPVariant *result)  {

-  return (static_cast<BasePlugin *>(npobj))->Invoke(

-      name,

-      args,

-      argument_count,

-      result);

-}

-

-// static

-bool BasePlugin::_InvokeDefault(NPObject *npobj,

-                                const NPVariant *args,

-                                uint32_t argument_count,

-                                NPVariant *result) {

-  return (static_cast<BasePlugin *>(npobj))->InvokeDefault(

-      args,

-      argument_count,

-      result);

-}

-

-// static

-bool BasePlugin::_HasProperty(NPObject * npobj, NPIdentifier name)  {

-  return (static_cast<BasePlugin *>(npobj))->HasProperty(name);

-}

-

-// static

-bool BasePlugin::_GetProperty(NPObject *npobj,

-                              NPIdentifier name,

-                              NPVariant *result) {

-  return (static_cast<BasePlugin *>(npobj))->GetProperty(name, result);

-}

-

-// static

-bool BasePlugin::_SetProperty(NPObject *npobj,

-                              NPIdentifier name,

-                              const NPVariant *value)  {

-  return (static_cast<BasePlugin *>(npobj))->SetProperty(name, value);

-}

-

-// static

-bool BasePlugin::_RemoveProperty(NPObject *npobj, NPIdentifier name)  {

-  return (static_cast<BasePlugin *>(npobj))->RemoveProperty(name);

-}

-

-CPlugin::CPlugin(NPP pNPInstance)

-    : np_instance_(pNPInstance),

-      bInitialized_(FALSE),

-      scriptable_object_(NULL)  {

-}

-

-CPlugin::~CPlugin() {

-  if (scriptable_object_) {

-    NPN_ReleaseObject(scriptable_object_);

-  }

-}

-

-NPBool CPlugin::init(NPWindow* np_window) {

-  bInitialized_ = TRUE;

-  NPBool returnvalue = TRUE;

-  if (the_npclass_staticinit) {

-      returnvalue = (*the_npclass_staticinit)

-          (np_instance_, np_window)? TRUE : FALSE;

-  }

-

-  return returnvalue;

-}

-

-void CPlugin::shut()  {

-  if (scriptable_object_) {

-    (static_cast<BasePlugin*>(scriptable_object_))->Shutdown();

-  }

-  bInitialized_ = FALSE;

-}

-

-NPBool CPlugin::isInitialized() {

-  return bInitialized_;

-}

-

-int16 CPlugin::handleEvent(void* event) {

-  UNREFERENCED_PARAMETER(event);

-  return 0;

-}

-

-NPObject* CPlugin::GetScriptableObject()  {

-  if (!scriptable_object_) {

-    scriptable_object_ = NPN_CreateObject(

-        np_instance_,

-        &CPlugin::the_npclass);

-  }

-

-  if (scriptable_object_) {

-    NPN_RetainObject(scriptable_object_);

-  }

-

-  return scriptable_object_;

-}

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Base implementation and build blocks for NPAPI Plugins
+// using the new NPRuntime supported by Firefox and others
+//
+// Mozilla doesn't currently have a framework in place for
+// building plug-ins using the new NPRuntime model, so
+// I had to roll my own.
+
+#include "plugins/baseplugin.h"
+#include "omaha/third_party/gecko/include/npupp.h"
+
+BasePlugin::BasePlugin(NPP npp)
+    : npp_(npp) {
+  NPN_GetValue(npp_, NPNVWindowNPObject, &window_object_);
+  NPN_RetainObject(window_object_);
+}
+
+BasePlugin::~BasePlugin() {
+  if (window_object_) {
+    NPN_ReleaseObject(window_object_);
+  }
+}
+
+void BasePlugin::InitializePluginMap() {
+  // Go through the list of IDs
+  PLUGIN_MAP* pDispMap = GetPluginMap();
+  PLUGIN_MAP_ENTRY* pEntry;
+
+  if (pDispMap != NULL) {
+    // populate all entries
+    pEntry = pDispMap->entries;
+    while (pEntry->name != NULL) {
+      pEntry->np_id = NPN_GetStringIdentifier(pEntry->name);
+      ++pEntry;
+    }
+  }
+}
+
+PLUGIN_MAP_ENTRY* BasePlugin::GetPluginEntry(NPIdentifier np_id)  {
+  PLUGIN_MAP* pDispMap = GetPluginMap();
+  PLUGIN_MAP_ENTRY* pEntry;
+
+  if (pDispMap != NULL) {
+    // search for entry
+    pEntry = pDispMap->entries;
+    while (pEntry->np_id != NULL) {
+      if (pEntry->np_id == np_id) {
+        return pEntry;
+      }
+      ++pEntry;
+    }
+  }
+
+  return NULL;  // name not found
+}
+
+bool BasePlugin::HasMethod(NPIdentifier name)  {
+  PLUGIN_MAP_ENTRY* pEntry = GetPluginEntry(name);
+  return pEntry && !pEntry->function_get;
+}
+
+bool BasePlugin::InvokeDefault(const NPVariant *args,
+                               uint32_t argument_count,
+                               NPVariant *result) {
+  UNREFERENCED_PARAMETER(args);
+  UNREFERENCED_PARAMETER(argument_count);
+  UNREFERENCED_PARAMETER(result);
+  return false;
+}
+
+
+bool BasePlugin::Invoke(NPIdentifier name,
+                        const NPVariant *args,
+                        uint32_t argument_count,
+                        NPVariant *result)  {
+  // get entry for the member ID
+  PLUGIN_MAP_ENTRY* pEntry = GetPluginEntry(name);
+  if (pEntry == NULL || pEntry->function_get) {
+    return false;
+  }
+
+  // do standard method call
+  return (this->*(pEntry->function))(args, argument_count, result);
+}
+
+bool BasePlugin::HasProperty(NPIdentifier name)  {
+  PLUGIN_MAP_ENTRY* pEntry = GetPluginEntry(name);
+  return pEntry && pEntry->function_get;
+}
+
+bool BasePlugin::GetProperty(NPIdentifier name, NPVariant *result) {
+  PLUGIN_MAP_ENTRY* pEntry = GetPluginEntry(name);
+  if (pEntry == NULL || !pEntry->function_get) {
+    return false;
+  }
+
+  // do standard method call
+  return (this->*(pEntry->function_get))(result);
+}
+
+bool BasePlugin::SetProperty(NPIdentifier name,
+                             const NPVariant *value) {
+  // get entry for the member ID
+  PLUGIN_MAP_ENTRY* pEntry = GetPluginEntry(name);
+  if (pEntry == NULL || !pEntry->function_get) {
+    return false;
+  }
+
+  // do standard method call
+  return (this->*(pEntry->function_set))(value);
+}
+
+
+void BasePlugin::Invalidate() {
+}
+
+bool BasePlugin::RemoveProperty(NPIdentifier name)  {
+  UNREFERENCED_PARAMETER(name);
+  return false;
+}
+
+void BasePlugin::Shutdown() {
+}
+
+// static
+void BasePlugin::_Deallocate(NPObject *npobj) {
+  // Call the virtual destructor.
+  delete static_cast<BasePlugin *>(npobj);
+}
+
+// static
+void BasePlugin::_Invalidate(NPObject *npobj) {
+  (static_cast<BasePlugin *>(npobj))->Invalidate();
+}
+
+// static
+bool BasePlugin::_HasMethod(NPObject *npobj, NPIdentifier name)  {
+  return (static_cast<BasePlugin *>(npobj))->HasMethod(name);
+}
+
+// static
+bool BasePlugin::_Invoke(NPObject *npobj,
+                         NPIdentifier name,
+                         const NPVariant *args,
+                         uint32_t argument_count,
+                         NPVariant *result)  {
+  return (static_cast<BasePlugin *>(npobj))->Invoke(
+      name,
+      args,
+      argument_count,
+      result);
+}
+
+// static
+bool BasePlugin::_InvokeDefault(NPObject *npobj,
+                                const NPVariant *args,
+                                uint32_t argument_count,
+                                NPVariant *result) {
+  return (static_cast<BasePlugin *>(npobj))->InvokeDefault(
+      args,
+      argument_count,
+      result);
+}
+
+// static
+bool BasePlugin::_HasProperty(NPObject * npobj, NPIdentifier name)  {
+  return (static_cast<BasePlugin *>(npobj))->HasProperty(name);
+}
+
+// static
+bool BasePlugin::_GetProperty(NPObject *npobj,
+                              NPIdentifier name,
+                              NPVariant *result) {
+  return (static_cast<BasePlugin *>(npobj))->GetProperty(name, result);
+}
+
+// static
+bool BasePlugin::_SetProperty(NPObject *npobj,
+                              NPIdentifier name,
+                              const NPVariant *value)  {
+  return (static_cast<BasePlugin *>(npobj))->SetProperty(name, value);
+}
+
+// static
+bool BasePlugin::_RemoveProperty(NPObject *npobj, NPIdentifier name)  {
+  return (static_cast<BasePlugin *>(npobj))->RemoveProperty(name);
+}
+
+CPlugin::CPlugin(NPP pNPInstance)
+    : np_instance_(pNPInstance),
+      bInitialized_(FALSE),
+      scriptable_object_(NULL)  {
+}
+
+CPlugin::~CPlugin() {
+  if (scriptable_object_) {
+    NPN_ReleaseObject(scriptable_object_);
+  }
+}
+
+NPBool CPlugin::init(NPWindow* np_window) {
+  bInitialized_ = TRUE;
+  NPBool returnvalue = TRUE;
+  if (the_npclass_staticinit) {
+      returnvalue = (*the_npclass_staticinit)
+          (np_instance_, np_window)? TRUE : FALSE;
+  }
+
+  return returnvalue;
+}
+
+void CPlugin::shut()  {
+  if (scriptable_object_) {
+    (static_cast<BasePlugin*>(scriptable_object_))->Shutdown();
+  }
+  bInitialized_ = FALSE;
+}
+
+NPBool CPlugin::isInitialized() {
+  return bInitialized_;
+}
+
+int16 CPlugin::handleEvent(void* event) {
+  UNREFERENCED_PARAMETER(event);
+  return 0;
+}
+
+NPObject* CPlugin::GetScriptableObject()  {
+  if (!scriptable_object_) {
+    scriptable_object_ = NPN_CreateObject(
+        np_instance_,
+        &CPlugin::the_npclass);
+  }
+
+  if (scriptable_object_) {
+    NPN_RetainObject(scriptable_object_);
+  }
+
+  return scriptable_object_;
+}
+
diff --git a/plugins/baseplugin.h b/plugins/baseplugin.h
index 9775809..2f3d41d 100644
--- a/plugins/baseplugin.h
+++ b/plugins/baseplugin.h
@@ -1,229 +1,229 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Base implementation and build blocks for NPAPI Plugins

-// using the new NPRuntime supported by Firefox and others

-//

-// Mozilla doesn't currently have a framework in place for

-// building plug-ins using the new NPRuntime model, so

-// I had to roll my own.

-//

-// TODO(omaha) - better document this code so other Google

-// projects can use this framework.

-

-#ifndef OMAHA_PLUGINS_BASEPLUGIN_H__

-#define OMAHA_PLUGINS_BASEPLUGIN_H__

-

-#include <windows.h>

-#include <windowsx.h>

-#include "omaha/third_party/gecko/include/npapi.h"

-#include "omaha/third_party/gecko/include/npruntime.h"

-

-class BasePlugin;

-typedef bool (BasePlugin::*PLUGIN_FUNC)(

-  const NPVariant *args, uint32_t argument_count, NPVariant *result);

-typedef bool (BasePlugin::*PLUGIN_PROPGET)(NPVariant *result);

-typedef bool (BasePlugin::*PLUGIN_PROPSET)(const NPVariant *value);

-typedef NPBool (*PLUGIN_STATIC_INIT)(NPP np_instance, NPWindow* np_window);

-

-struct PLUGIN_MAP_ENTRY {

-  LPCSTR name;                  // member/property name

-  NPIdentifier np_id;           // NPIdentifier

-  PLUGIN_FUNC function;         // member Function

-  PLUGIN_PROPGET function_get;  // member for Get<property>

-  PLUGIN_PROPSET function_set;  // member for Set<property>

-  uint32_t argument_count;      // argument_count for Invoke()

-};

-

-struct PLUGIN_MAP {

-  PLUGIN_MAP_ENTRY* entries;

-};

-

-class CPlugin {

- private:

-  NPP np_instance_;

-  NPBool bInitialized_;

-  NPObject *scriptable_object_;

-

- public:

-  explicit CPlugin(NPP pNPInstance);

-  ~CPlugin();

-

-  NPBool init(NPWindow* np_window);

-  void shut();

-  NPBool isInitialized();

-

-  int16 handleEvent(void* event);

-

-  NPObject *GetScriptableObject();

-  static NPClass the_npclass;

-  static PLUGIN_STATIC_INIT the_npclass_staticinit;

-};

-

-

-

-// Helper class that can be used to map calls to the NPObject hooks

-// into virtual methods on instances of classes that derive from this

-// class.

-class BasePlugin : public NPObject  {

- public:

-  explicit BasePlugin(NPP npp);

-  virtual ~BasePlugin();

-

-  // Virtual functions that a derived class can override

-  virtual void Invalidate();

-  virtual bool HasMethod(NPIdentifier name);

-  virtual bool Invoke(NPIdentifier name, const NPVariant *args,

-                      uint32_t argument_count, NPVariant *result);

-  virtual bool InvokeDefault(const NPVariant *args, uint32_t argument_count,

-                             NPVariant *result);

-  virtual bool HasProperty(NPIdentifier name);

-  virtual bool GetProperty(NPIdentifier name, NPVariant *result);

-  virtual bool SetProperty(NPIdentifier name, const NPVariant *value);

-  virtual bool RemoveProperty(NPIdentifier name);

-  virtual void Shutdown();

-

-  virtual PLUGIN_MAP_ENTRY* GetPluginEntry(NPIdentifier np_id);

-

- protected:

-  // Virtual functions that a derived class can override

-  virtual PLUGIN_MAP* GetPluginMap() {return NULL;}

-

-  // Helpers:

-  void InitializePluginMap();

-  NPObject* window_object() {return window_object_;}

-

- public:

-  // Statics

-  static void _Deallocate(NPObject *npobj);

-  static void _Invalidate(NPObject *npobj);

-  static bool _HasMethod(NPObject *npobj, NPIdentifier name);

-  static bool _Invoke(NPObject *npobj, NPIdentifier name,

-                      const NPVariant *args, uint32_t argument_count,

-                      NPVariant *result);

-  static bool _InvokeDefault(NPObject *npobj, const NPVariant *args,

-                             uint32_t argument_count, NPVariant *result);

-  static bool _HasProperty(NPObject * npobj, NPIdentifier name);

-  static bool _GetProperty(NPObject *npobj, NPIdentifier name,

-                           NPVariant *result);

-  static bool _SetProperty(NPObject *npobj, NPIdentifier name,

-                           const NPVariant *value);

-  static bool _RemoveProperty(NPObject *npobj, NPIdentifier name);

-

- protected:

-  NPP npp_;

-  NPObject *window_object_;

-};

-

-// Only one of these can be declared:

-#define DECLARE_CPLUGIN_NPCLASS() \

-  static NPBool init(NPP np_instance, NPWindow* np_window);

-

-#define DEFINE_CPLUGIN_NPCLASS(the_class) \

-  NPClass CPlugin::the_npclass = the_class::get_NPClass(); \

-  PLUGIN_STATIC_INIT CPlugin::the_npclass_staticinit = the_class::init; \

-  NPBool the_class::init(NPP np_instance, NPWindow* np_window)  {            \

-    UNREFERENCED_PARAMETER(np_instance);                                     \

-    UNREFERENCED_PARAMETER(np_window);                                       \

-

-#define END_DEFINE_CPLUGIN_NPCLASS() \

-  }

-

-#define DECLARE_PLUGIN_CLASS(the_class)                                      \

-class the_class : public BasePlugin {                                        \

-private:                                                                     \

-  static PLUGIN_MAP_ENTRY plugin_entries_[];                                 \

-  static NPClass the_class##_NPClass;                                        \

-protected:                                                                   \

-  virtual PLUGIN_MAP* GetPluginMap();                                        \

-  static PLUGIN_MAP plugin_map;                                              \

-  static NPObject* AllocateScriptablePluginObject(NPP npp,                   \

-                       NPClass *theclass) {                                  \

-    UNREFERENCED_PARAMETER(theclass);                                        \

-    return new the_class(npp);                                               \

-  }                                                                          \

-public:                                                                      \

-  static NPClass& get_NPClass() {return the_class##_NPClass;}                \

-  explicit the_class(NPP npp);                                               \

-  virtual ~the_class();                                                      \

-

-#define DECLARE_PLUGIN_FUNCTION(member_function)                             \

-  bool member_function(const NPVariant *args,                                \

-           uint32_t argument_count, NPVariant *result);

-

-#define DECLARE_PLUGIN_PROPERTY(member_function)     \

-  bool Get##member_function(NPVariant *result);      \

-  bool Set##member_function(const NPVariant *value);

-

-#define END_DECLARE_PLUGIN_CLASS(the_class)    \

-  };

-

-// Macros to define plugin methods

-#define BEGIN_PLUGIN_CLASS(the_class)                         \

-  NPClass the_class::the_class##_NPClass = {                  \

-  NP_CLASS_STRUCT_VERSION,                                    \

-  AllocateScriptablePluginObject,                             \

-  BasePlugin::_Deallocate,                                    \

-  BasePlugin::_Invalidate,                                    \

-  BasePlugin::_HasMethod,                                     \

-  BasePlugin::_Invoke,                                        \

-  BasePlugin::_InvokeDefault,                                 \

-  BasePlugin::_HasProperty,                                   \

-  BasePlugin::_GetProperty,                                   \

-  BasePlugin::_SetProperty,                                   \

-  BasePlugin::_RemoveProperty                                 \

-};                                                            \

-PLUGIN_MAP* the_class::GetPluginMap() {                       \

-  static bool initialized = false;                            \

-  if (!initialized) {                                         \

-    initialized = true;                                       \

-    InitializePluginMap();                                    \

-  }                                                           \

-  return &the_class::plugin_map;                              \

-  }                                                           \

-PLUGIN_MAP the_class::plugin_map =                            \

-  { &the_class::plugin_entries_[0] };                         \

-PLUGIN_MAP_ENTRY the_class::plugin_entries_[] =  {            \

-                                                                    // NO_LINT

-#define PLUGIN_FUNCTION(the_class, member_function, argument_count)       \

-  { #member_function, NULL,                                               \

-    (PLUGIN_FUNC)&member_function, NULL, NULL, argument_count             \

-    },

-

-#define PLUGIN_PROPERTY(the_class, member_function)                       \

-  { #member_function, NULL,                                               \

-  NULL, (PLUGIN_PROPGET)&Get##member_function,                            \

-  (PLUGIN_PROPSET)&Set##member_function,                                  \

-    0},

-

-#define END_BEGIN_PLUGIN_CLASS \

-  { NULL, NULL,                \

-    NULL, NULL, NULL, 0,       \

-    }, };

-

-#define BEGIN_PLUGIN_CLASS_CTOR(the_class)                                   \

-  the_class::the_class(NPP npp) : BasePlugin(npp) {                          \

-                                                                    // NO_LINT

-#define END_PLUGIN_CLASS_CTOR                                                \

-  }

-

-#define BEGIN_PLUGIN_CLASS_DTOR(the_class)                                   \

-  the_class::~the_class() {                                                  \

-                                                                    // NO_LINT

-#define END_PLUGIN_CLASS_DTOR                                                \

-  }

-

-#endif  // OMAHA_PLUGINS_BASEPLUGIN_H__

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Base implementation and build blocks for NPAPI Plugins
+// using the new NPRuntime supported by Firefox and others
+//
+// Mozilla doesn't currently have a framework in place for
+// building plug-ins using the new NPRuntime model, so
+// I had to roll my own.
+//
+// TODO(omaha) - better document this code so other Google
+// projects can use this framework.
+
+#ifndef OMAHA_PLUGINS_BASEPLUGIN_H__
+#define OMAHA_PLUGINS_BASEPLUGIN_H__
+
+#include <windows.h>
+#include <windowsx.h>
+#include "omaha/third_party/gecko/include/npapi.h"
+#include "omaha/third_party/gecko/include/npruntime.h"
+
+class BasePlugin;
+typedef bool (BasePlugin::*PLUGIN_FUNC)(
+  const NPVariant *args, uint32_t argument_count, NPVariant *result);
+typedef bool (BasePlugin::*PLUGIN_PROPGET)(NPVariant *result);
+typedef bool (BasePlugin::*PLUGIN_PROPSET)(const NPVariant *value);
+typedef NPBool (*PLUGIN_STATIC_INIT)(NPP np_instance, NPWindow* np_window);
+
+struct PLUGIN_MAP_ENTRY {
+  LPCSTR name;                  // member/property name
+  NPIdentifier np_id;           // NPIdentifier
+  PLUGIN_FUNC function;         // member Function
+  PLUGIN_PROPGET function_get;  // member for Get<property>
+  PLUGIN_PROPSET function_set;  // member for Set<property>
+  uint32_t argument_count;      // argument_count for Invoke()
+};
+
+struct PLUGIN_MAP {
+  PLUGIN_MAP_ENTRY* entries;
+};
+
+class CPlugin {
+ private:
+  NPP np_instance_;
+  NPBool bInitialized_;
+  NPObject *scriptable_object_;
+
+ public:
+  explicit CPlugin(NPP pNPInstance);
+  ~CPlugin();
+
+  NPBool init(NPWindow* np_window);
+  void shut();
+  NPBool isInitialized();
+
+  int16 handleEvent(void* event);
+
+  NPObject *GetScriptableObject();
+  static NPClass the_npclass;
+  static PLUGIN_STATIC_INIT the_npclass_staticinit;
+};
+
+
+
+// Helper class that can be used to map calls to the NPObject hooks
+// into virtual methods on instances of classes that derive from this
+// class.
+class BasePlugin : public NPObject  {
+ public:
+  explicit BasePlugin(NPP npp);
+  virtual ~BasePlugin();
+
+  // Virtual functions that a derived class can override
+  virtual void Invalidate();
+  virtual bool HasMethod(NPIdentifier name);
+  virtual bool Invoke(NPIdentifier name, const NPVariant *args,
+                      uint32_t argument_count, NPVariant *result);
+  virtual bool InvokeDefault(const NPVariant *args, uint32_t argument_count,
+                             NPVariant *result);
+  virtual bool HasProperty(NPIdentifier name);
+  virtual bool GetProperty(NPIdentifier name, NPVariant *result);
+  virtual bool SetProperty(NPIdentifier name, const NPVariant *value);
+  virtual bool RemoveProperty(NPIdentifier name);
+  virtual void Shutdown();
+
+  virtual PLUGIN_MAP_ENTRY* GetPluginEntry(NPIdentifier np_id);
+
+ protected:
+  // Virtual functions that a derived class can override
+  virtual PLUGIN_MAP* GetPluginMap() {return NULL;}
+
+  // Helpers:
+  void InitializePluginMap();
+  NPObject* window_object() {return window_object_;}
+
+ public:
+  // Statics
+  static void _Deallocate(NPObject *npobj);
+  static void _Invalidate(NPObject *npobj);
+  static bool _HasMethod(NPObject *npobj, NPIdentifier name);
+  static bool _Invoke(NPObject *npobj, NPIdentifier name,
+                      const NPVariant *args, uint32_t argument_count,
+                      NPVariant *result);
+  static bool _InvokeDefault(NPObject *npobj, const NPVariant *args,
+                             uint32_t argument_count, NPVariant *result);
+  static bool _HasProperty(NPObject * npobj, NPIdentifier name);
+  static bool _GetProperty(NPObject *npobj, NPIdentifier name,
+                           NPVariant *result);
+  static bool _SetProperty(NPObject *npobj, NPIdentifier name,
+                           const NPVariant *value);
+  static bool _RemoveProperty(NPObject *npobj, NPIdentifier name);
+
+ protected:
+  NPP npp_;
+  NPObject *window_object_;
+};
+
+// Only one of these can be declared:
+#define DECLARE_CPLUGIN_NPCLASS() \
+  static NPBool init(NPP np_instance, NPWindow* np_window);
+
+#define DEFINE_CPLUGIN_NPCLASS(the_class) \
+  NPClass CPlugin::the_npclass = the_class::get_NPClass(); \
+  PLUGIN_STATIC_INIT CPlugin::the_npclass_staticinit = the_class::init; \
+  NPBool the_class::init(NPP np_instance, NPWindow* np_window)  {            \
+    UNREFERENCED_PARAMETER(np_instance);                                     \
+    UNREFERENCED_PARAMETER(np_window);                                       \
+
+#define END_DEFINE_CPLUGIN_NPCLASS() \
+  }
+
+#define DECLARE_PLUGIN_CLASS(the_class)                                      \
+class the_class : public BasePlugin {                                        \
+private:                                                                     \
+  static PLUGIN_MAP_ENTRY plugin_entries_[];                                 \
+  static NPClass the_class##_NPClass;                                        \
+protected:                                                                   \
+  virtual PLUGIN_MAP* GetPluginMap();                                        \
+  static PLUGIN_MAP plugin_map;                                              \
+  static NPObject* AllocateScriptablePluginObject(NPP npp,                   \
+                       NPClass *theclass) {                                  \
+    UNREFERENCED_PARAMETER(theclass);                                        \
+    return new the_class(npp);                                               \
+  }                                                                          \
+public:                                                                      \
+  static NPClass& get_NPClass() {return the_class##_NPClass;}                \
+  explicit the_class(NPP npp);                                               \
+  virtual ~the_class();                                                      \
+
+#define DECLARE_PLUGIN_FUNCTION(member_function)                             \
+  bool member_function(const NPVariant *args,                                \
+           uint32_t argument_count, NPVariant *result);
+
+#define DECLARE_PLUGIN_PROPERTY(member_function)     \
+  bool Get##member_function(NPVariant *result);      \
+  bool Set##member_function(const NPVariant *value);
+
+#define END_DECLARE_PLUGIN_CLASS(the_class)    \
+  };
+
+// Macros to define plugin methods
+#define BEGIN_PLUGIN_CLASS(the_class)                         \
+  NPClass the_class::the_class##_NPClass = {                  \
+  NP_CLASS_STRUCT_VERSION,                                    \
+  AllocateScriptablePluginObject,                             \
+  BasePlugin::_Deallocate,                                    \
+  BasePlugin::_Invalidate,                                    \
+  BasePlugin::_HasMethod,                                     \
+  BasePlugin::_Invoke,                                        \
+  BasePlugin::_InvokeDefault,                                 \
+  BasePlugin::_HasProperty,                                   \
+  BasePlugin::_GetProperty,                                   \
+  BasePlugin::_SetProperty,                                   \
+  BasePlugin::_RemoveProperty                                 \
+};                                                            \
+PLUGIN_MAP* the_class::GetPluginMap() {                       \
+  static bool initialized = false;                            \
+  if (!initialized) {                                         \
+    initialized = true;                                       \
+    InitializePluginMap();                                    \
+  }                                                           \
+  return &the_class::plugin_map;                              \
+  }                                                           \
+PLUGIN_MAP the_class::plugin_map =                            \
+  { &the_class::plugin_entries_[0] };                         \
+PLUGIN_MAP_ENTRY the_class::plugin_entries_[] =  {            \
+                                                                    // NO_LINT
+#define PLUGIN_FUNCTION(the_class, member_function, argument_count)       \
+  { #member_function, NULL,                                               \
+    (PLUGIN_FUNC)&member_function, NULL, NULL, argument_count             \
+    },
+
+#define PLUGIN_PROPERTY(the_class, member_function)                       \
+  { #member_function, NULL,                                               \
+  NULL, (PLUGIN_PROPGET)&Get##member_function,                            \
+  (PLUGIN_PROPSET)&Set##member_function,                                  \
+    0},
+
+#define END_BEGIN_PLUGIN_CLASS \
+  { NULL, NULL,                \
+    NULL, NULL, NULL, 0,       \
+    }, };
+
+#define BEGIN_PLUGIN_CLASS_CTOR(the_class)                                   \
+  the_class::the_class(NPP npp) : BasePlugin(npp) {                          \
+                                                                    // NO_LINT
+#define END_PLUGIN_CLASS_CTOR                                                \
+  }
+
+#define BEGIN_PLUGIN_CLASS_DTOR(the_class)                                   \
+  the_class::~the_class() {                                                  \
+                                                                    // NO_LINT
+#define END_PLUGIN_CLASS_DTOR                                                \
+  }
+
+#endif  // OMAHA_PLUGINS_BASEPLUGIN_H__
+
diff --git a/plugins/build.scons b/plugins/build.scons
index f3c54b0..a9703b6 100644
--- a/plugins/build.scons
+++ b/plugins/build.scons
@@ -1,228 +1,228 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-_first = True

-for v in env['product_version']:

-  temp_env = env.Clone(COMPONENT_STATIC = False)

-

-  if _first:

-    _first = False

-    prefix = ''

-  else:

-    prefix = 'TEST_'

-    temp_env['OBJPREFIX'] = temp_env['OBJPREFIX'] + 'test/'

-

-  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-  temp_env.Append(

-      RCFLAGS = [

-          '/DVERSION_MAJOR=%d' % v[0],

-          '/DVERSION_MINOR=%d' % v[1],

-          '/DVERSION_BUILD=%d' % v[2],

-          '/DVERSION_PATCH=%d' % v[3],

-          '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,

-          ],

-

-      CPPDEFINES = [

-          '_ATL_APARTMENT_THREADED',

-          'VERSION_NUMBER_STRING=\\"%s\\"' % version_string,

-          ],

-

-      CPPPATH = [

-          '$OBJ_ROOT',

-          ],

-

-      LIBS = [

-          '$LIB_DIR/breakpad.lib',

-          '$LIB_DIR/common.lib',

-          '$LIB_DIR/goopdate_dll.lib',

-          '$LIB_DIR/logging.lib',

-          '$LIB_DIR/npOneClick_dll.lib',

-          '$LIB_DIR/npOneClick_dll_no_pch.lib',

-          '$LIB_DIR/npOneClickPlugin.lib',

-          '$LIB_DIR/net.lib',

-          '$LIB_DIR/security.lib',

-          '$LIB_DIR/statsreport.lib',

-          '$LIB_DIR/worker.lib',

-

-          ('atls.lib', 'atlsd.lib')[temp_env.Bit('debug')],

-          ('libcmt.lib', 'libcmtd.lib')[temp_env.Bit('debug')],

-          ('libcpmt.lib', 'libcpmtd.lib')[temp_env.Bit('debug')],

-          'comctl32.lib',

-          'crypt32.lib',

-          'Iphlpapi.lib',

-          'Mstask.lib',

-          'Netapi32.lib',

-          'psapi.lib',

-          'rasapi32.lib',

-          'shlwapi.lib',

-          'Version.lib',

-          'urlmon.lib',

-          'userenv.lib',

-          'wininet.lib',

-          'Wintrust.lib',

-          'WtsApi32.lib',

-          ],

-  )

-

-  resource_res = temp_env.RES(

-      target=prefix + 'resource.res',

-      source='resource.rc',

-  )

-

-  # Force a rebuild when the version changes.

-  temp_env.Depends(resource_res,

-                   ['$MAIN_DIR/VERSION', '$OBJ_ROOT/plugins/oneclick_idl.tlb'])

-

-  # TODO(Omaha): Remove plugin dependencies on goopdate and all its

-  # dependencies.

-

-  target_name = prefix + temp_env['ACTIVEX_UNSIGNED_FILENAME']

-

-  temp_inputs = [

-      'dllmain.cc',

-      'oneclick.def',

-      resource_res,

-      ]

-

-  if env.Bit('use_precompiled_headers'):

-    pch_obj = temp_env.EnablePrecompile(target_name)

-

-    # Force a rebuild of the precompiled headers when the version changes.

-    # This is necessary in this project because VERSION_NUMBER_STRING is added

-    # to the CL flags whereas for other projects it is only in the RC flags.

-    temp_env.Depends(pch_obj, '$MAIN_DIR/VERSION')

-

-    temp_inputs += [pch_obj]

-

-

-  unsigned_dll = temp_env.ComponentLibrary(

-      lib_name=target_name,

-      source=temp_inputs

-  )

-

-  signed_dll = temp_env.SignedBinary(

-      target=prefix + temp_env['ACTIVEX_FILENAME'],

-      source=unsigned_dll,

-  )

-

-  env.Replicate('$STAGING_DIR', signed_dll)

-  env.Replicate('$STAGING_DIR', [f for f in unsigned_dll if f.suffix == '.pdb'])

-

-

-#

-# Generate oneclick_idl.idl. The output is an IDL file with a variant CLSID

-# for coclass GoopdateOneClickControl.

-#

-generated_idl = env.Command(

-    target='oneclick_idl.idl',

-    source='$MAIN_DIR/plugins/oneclick_idl.idl',

-    action=('python %s/plugins/generate_oneclick_idl.py --idl_template_file '

-        '$SOURCE --idl_output_file $TARGET' % env['MAIN_DIR'])

-)

-

-

-#

-# Build the type library

-#

-midl_env = env.Clone()

-midl_env.Tool('midl')

-

-midl_env['MIDLFLAGS'] += [

-    '/Oicf',  # generate optimized stubless proxy/stub code

-    ]

-

-# Create the type library, taking the generated idl file as input

-midl_env.TypeLibrary(generated_idl)

-

-

-#

-# Generate the GUIDs with no precompile option set, otherwise we get an error.

-#

-no_precomp_env = env.Clone()

-no_precomp_env.Append(

-    CCFLAGS = [

-        '/wd4255',  # no function prototype given: converting '()' to '(void)'

-        ],

-    CPPPATH = [

-        '$OBJ_ROOT',  # Needed for generated files

-        ],

-)

-

-no_precomp_env.ComponentLibrary(

-    lib_name='npOneClick_dll_no_pch.lib',

-    source='$OBJ_ROOT/plugins/oneclick_idl_i.c',

-)

-

-

-#

-# Build npOneClick_dll.lib

-#

-one_click_env = env.Clone()

-one_click_env.Append(

-    CCFLAGS = [

-        '/wd4946',  # reinterpret_cast used between related classes

-        ],

-    CPPDEFINES = [

-        '_ATL_APARTMENT_THREADED',

-        ],

-    CPPPATH = [

-        '$OBJ_ROOT',  # Needed for generated files

-        ],

-)

-

-target_name = 'npOneClick_dll.lib'

-

-one_click_inputs = [

-    'oneclick.cc',

-    'oneclick_browser_callback_activex.cc',

-    'oneclick_worker.cc',

-    'oneclick_atl_module.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  one_click_inputs += one_click_env.EnablePrecompile(target_name)

-

-one_click_env.ComponentLibrary(

-    lib_name=target_name,

-    source=one_click_inputs,

-)

-

-

-#

-# Build npOneClickPlugin.lib

-#

-ocp_env = env.Clone()

-ocp_env['CCFLAGS'] += [

-    '/D_X86_',  # needed for NPAPI code to build NT headers properly

-    ]

-

-ocp_env.ComponentLibrary(

-    lib_name='npOneClickPlugin.lib',

-    source=[

-        'np_entry.cc',

-        'baseplugin.cc',

-        'npOneClick.cc',

-        'npn_gate.cc',

-        'npp_gate.cc',

-        'oneclick_browser_callback_npapi.cc',

-        ]

-)

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+_first = True
+for v in env['product_version']:
+  temp_env = env.Clone(COMPONENT_STATIC = False)
+
+  if _first:
+    _first = False
+    prefix = ''
+  else:
+    prefix = 'TEST_'
+    temp_env['OBJPREFIX'] = temp_env['OBJPREFIX'] + 'test/'
+
+  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+  temp_env.Append(
+      RCFLAGS = [
+          '/DVERSION_MAJOR=%d' % v[0],
+          '/DVERSION_MINOR=%d' % v[1],
+          '/DVERSION_BUILD=%d' % v[2],
+          '/DVERSION_PATCH=%d' % v[3],
+          '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,
+          ],
+
+      CPPDEFINES = [
+          '_ATL_APARTMENT_THREADED',
+          'VERSION_NUMBER_STRING=\\"%s\\"' % version_string,
+          ],
+
+      CPPPATH = [
+          '$OBJ_ROOT',
+          ],
+
+      LIBS = [
+          '$LIB_DIR/breakpad.lib',
+          '$LIB_DIR/common.lib',
+          '$LIB_DIR/goopdate_dll.lib',
+          '$LIB_DIR/logging.lib',
+          '$LIB_DIR/npOneClick_dll.lib',
+          '$LIB_DIR/npOneClick_dll_no_pch.lib',
+          '$LIB_DIR/npOneClickPlugin.lib',
+          '$LIB_DIR/net.lib',
+          '$LIB_DIR/security.lib',
+          '$LIB_DIR/statsreport.lib',
+          '$LIB_DIR/worker.lib',
+
+          ('atls.lib', 'atlsd.lib')[temp_env.Bit('debug')],
+          ('libcmt.lib', 'libcmtd.lib')[temp_env.Bit('debug')],
+          ('libcpmt.lib', 'libcpmtd.lib')[temp_env.Bit('debug')],
+          'comctl32.lib',
+          'crypt32.lib',
+          'Iphlpapi.lib',
+          'Mstask.lib',
+          'Netapi32.lib',
+          'psapi.lib',
+          'rasapi32.lib',
+          'shlwapi.lib',
+          'Version.lib',
+          'urlmon.lib',
+          'userenv.lib',
+          'wininet.lib',
+          'Wintrust.lib',
+          'WtsApi32.lib',
+          ],
+  )
+
+  resource_res = temp_env.RES(
+      target=prefix + 'resource.res',
+      source='resource.rc',
+  )
+
+  # Force a rebuild when the version changes.
+  temp_env.Depends(resource_res,
+                   ['$MAIN_DIR/VERSION', '$OBJ_ROOT/plugins/oneclick_idl.tlb'])
+
+  # TODO(Omaha): Remove plugin dependencies on goopdate and all its
+  # dependencies.
+
+  target_name = prefix + temp_env['ACTIVEX_UNSIGNED_FILENAME']
+
+  temp_inputs = [
+      'dllmain.cc',
+      'oneclick.def',
+      resource_res,
+      ]
+
+  if env.Bit('use_precompiled_headers'):
+    pch_obj = temp_env.EnablePrecompile(target_name)
+
+    # Force a rebuild of the precompiled headers when the version changes.
+    # This is necessary in this project because VERSION_NUMBER_STRING is added
+    # to the CL flags whereas for other projects it is only in the RC flags.
+    temp_env.Depends(pch_obj, '$MAIN_DIR/VERSION')
+
+    temp_inputs += [pch_obj]
+
+
+  unsigned_dll = temp_env.ComponentLibrary(
+      lib_name=target_name,
+      source=temp_inputs
+  )
+
+  signed_dll = temp_env.SignedBinary(
+      target=prefix + temp_env['ACTIVEX_FILENAME'],
+      source=unsigned_dll,
+  )
+
+  env.Replicate('$STAGING_DIR', signed_dll)
+  env.Replicate('$STAGING_DIR', [f for f in unsigned_dll if f.suffix == '.pdb'])
+
+
+#
+# Generate oneclick_idl.idl. The output is an IDL file with a variant CLSID
+# for coclass GoopdateOneClickControl.
+#
+generated_idl = env.Command(
+    target='oneclick_idl.idl',
+    source='$MAIN_DIR/plugins/oneclick_idl.idl',
+    action=('python %s/plugins/generate_oneclick_idl.py --idl_template_file '
+        '$SOURCE --idl_output_file $TARGET' % env['MAIN_DIR'])
+)
+
+
+#
+# Build the type library
+#
+midl_env = env.Clone()
+midl_env.Tool('midl')
+
+midl_env['MIDLFLAGS'] += [
+    '/Oicf',  # generate optimized stubless proxy/stub code
+    ]
+
+# Create the type library, taking the generated idl file as input
+midl_env.TypeLibrary(generated_idl)
+
+
+#
+# Generate the GUIDs with no precompile option set, otherwise we get an error.
+#
+no_precomp_env = env.Clone()
+no_precomp_env.Append(
+    CCFLAGS = [
+        '/wd4255',  # no function prototype given: converting '()' to '(void)'
+        ],
+    CPPPATH = [
+        '$OBJ_ROOT',  # Needed for generated files
+        ],
+)
+
+no_precomp_env.ComponentLibrary(
+    lib_name='npOneClick_dll_no_pch.lib',
+    source='$OBJ_ROOT/plugins/oneclick_idl_i.c',
+)
+
+
+#
+# Build npOneClick_dll.lib
+#
+one_click_env = env.Clone()
+one_click_env.Append(
+    CCFLAGS = [
+        '/wd4946',  # reinterpret_cast used between related classes
+        ],
+    CPPDEFINES = [
+        '_ATL_APARTMENT_THREADED',
+        ],
+    CPPPATH = [
+        '$OBJ_ROOT',  # Needed for generated files
+        ],
+)
+
+target_name = 'npOneClick_dll.lib'
+
+one_click_inputs = [
+    'oneclick.cc',
+    'oneclick_browser_callback_activex.cc',
+    'oneclick_worker.cc',
+    'oneclick_atl_module.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  one_click_inputs += one_click_env.EnablePrecompile(target_name)
+
+one_click_env.ComponentLibrary(
+    lib_name=target_name,
+    source=one_click_inputs,
+)
+
+
+#
+# Build npOneClickPlugin.lib
+#
+ocp_env = env.Clone()
+ocp_env['CCFLAGS'] += [
+    '/D_X86_',  # needed for NPAPI code to build NT headers properly
+    ]
+
+ocp_env.ComponentLibrary(
+    lib_name='npOneClickPlugin.lib',
+    source=[
+        'np_entry.cc',
+        'baseplugin.cc',
+        'npOneClick.cc',
+        'npn_gate.cc',
+        'npp_gate.cc',
+        'oneclick_browser_callback_npapi.cc',
+        ]
+)
+
diff --git a/plugins/dllmain.cc b/plugins/dllmain.cc
index c2765a1..8b662ba 100644
--- a/plugins/dllmain.cc
+++ b/plugins/dllmain.cc
@@ -1,61 +1,61 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// DLLMain boilerplate

-//

-

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-

-// Force the linker to include the ATLModule instance

-// (see plugins/oneclick_atl_module.cpp)

-#pragma comment(linker, "/INCLUDE:__AtlModule")

-

-// Force the linker to include the object map definition. Each class that

-// requires COM registration must be added here, otherwise its object entry

-// will be missing from the object map.

-#pragma comment(linker, "/INCLUDE:___pobjMap_GoopdateCtrl")

-

-void OneClickOutOfMemoryHandler() {

-  ::RaiseException(EXCEPTION_ACCESS_VIOLATION,

-                   EXCEPTION_NONCONTINUABLE,

-                   0,

-                   NULL);

-}

-

-extern "C" {

-DLLEXPORT

-BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) {

-  switch (reason) {

-    case DLL_PROCESS_ATTACH:

-      VERIFY1(set_new_handler(&OneClickOutOfMemoryHandler) == 0);

-      break;

-

-    case DLL_THREAD_ATTACH:

-      break;

-

-    case DLL_THREAD_DETACH:

-      break;

-

-    case DLL_PROCESS_DETACH:

-      break;

-

-    default:

-      break;

-  }

-  return TRUE;

-}

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// DLLMain boilerplate
+//
+
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+
+// Force the linker to include the ATLModule instance
+// (see plugins/oneclick_atl_module.cpp)
+#pragma comment(linker, "/INCLUDE:__AtlModule")
+
+// Force the linker to include the object map definition. Each class that
+// requires COM registration must be added here, otherwise its object entry
+// will be missing from the object map.
+#pragma comment(linker, "/INCLUDE:___pobjMap_GoopdateCtrl")
+
+void OneClickOutOfMemoryHandler() {
+  ::RaiseException(EXCEPTION_ACCESS_VIOLATION,
+                   EXCEPTION_NONCONTINUABLE,
+                   0,
+                   NULL);
+}
+
+extern "C" {
+DLLEXPORT
+BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) {
+  switch (reason) {
+    case DLL_PROCESS_ATTACH:
+      VERIFY1(set_new_handler(&OneClickOutOfMemoryHandler) == 0);
+      break;
+
+    case DLL_THREAD_ATTACH:
+      break;
+
+    case DLL_THREAD_DETACH:
+      break;
+
+    case DLL_PROCESS_DETACH:
+      break;
+
+    default:
+      break;
+  }
+  return TRUE;
+}
+}
diff --git a/plugins/generate_oneclick_idl.py b/plugins/generate_oneclick_idl.py
index f94c7c6..069a7aa 100644
--- a/plugins/generate_oneclick_idl.py
+++ b/plugins/generate_oneclick_idl.py
@@ -1,116 +1,116 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2007-2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-"""

-Generates IDL file for the OneClick ActiveX control from the passed-in IDL

-template. The input template is a complete IDL file in all but one respect;

-It has one replaceable entry for the CLSID for GoopdateOneClickControl.

-We generate a GUID using UUIDGEN.EXE, and write out an IDL with a new CLSID.

-

-"""

-

-import sys

-import os

-import getopt

-import commands

-

-

-def _GetStatusOutput(cmd):

-  """Return (status, output) of executing cmd in a shell."""

-  if os.name == "nt":

-    pipe = os.popen(cmd + " 2>&1", 'r')

-    text = pipe.read()

-    sts = pipe.close()

-    if sts is None: sts = 0

-    if text[-1:] == '\n': text = text[:-1]

-    return sts, text

-  else:

-    return commands.getstatusoutput(cmd)

-

-

-def _GenerateIDLText(idl_template):

-  (status, guid) = _GetStatusOutput("uuidgen.exe")

-  if status != 0:

-    raise SystemExit("Failed to get GUID: %s" % guid)

-

-  return idl_template % guid

-

-

-def _GenerateIDLFile(idl_template_filename, idl_output_filename):

-  f_in = open(idl_template_filename, 'r')

-  idl_template = f_in.read()

-  f_in.close()

-

-  idl_output = _GenerateIDLText(idl_template)

-

-  f_out = open(idl_output_filename, 'w')

-  f_out.write("""

-                 // ** AUTOGENERATED FILE. DO NOT HAND-EDIT **

-              """)

-  f_out.write(idl_output)

-  f_out.close()

-

-

-def _Usage():

-  """Prints out script usage information."""

-  print """

-generate_oneclick_idl.py: Write out the given IDL file.

-

-Usage:

-  generate_oneclick_idl.py [--help

-                            | --idl_template_file filename

-                              --idl_output_file filename]

-

-Options:

-  --help                    Show this information.

-  --idl_output_file filename     Path/name of output IDL filename.

-  --idl_template_file filename      Path/name of input IDL template.

-"""

-

-

-def _Main():

-  """Generates IDL file."""

-  # use getopt to parse the option and argument list; this may raise, but

-  # don't catch it

-  _ARGUMENT_LIST = ["help", "idl_template_file=", "idl_output_file="]

-  (opts, args) = getopt.getopt(sys.argv[1:], "", _ARGUMENT_LIST)

-  if not opts or ("--help", "") in opts:

-    _Usage()

-    sys.exit()

-

-  idl_template_filename = ""

-  idl_output_filename = ""

-

-  for (o, v) in opts:

-    if o == "--idl_template_file":

-      idl_template_filename = v

-    if o == "--idl_output_file":

-      idl_output_filename = v

-

-  # make sure we have work to do

-  if not idl_template_filename:

-    raise SystemExit("no idl_template_filename specified")

-  if not idl_output_filename:

-    raise SystemExit("no idl_output_filename specified")

-

-  _GenerateIDLFile(idl_template_filename, idl_output_filename)

-  sys.exit()

-

-

-if __name__ == "__main__":

-  _Main()

-

+#!/usr/bin/python2.4
+#
+# Copyright 2007-2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+"""
+Generates IDL file for the OneClick ActiveX control from the passed-in IDL
+template. The input template is a complete IDL file in all but one respect;
+It has one replaceable entry for the CLSID for GoopdateOneClickControl.
+We generate a GUID using UUIDGEN.EXE, and write out an IDL with a new CLSID.
+
+"""
+
+import sys
+import os
+import getopt
+import commands
+
+
+def _GetStatusOutput(cmd):
+  """Return (status, output) of executing cmd in a shell."""
+  if os.name == "nt":
+    pipe = os.popen(cmd + " 2>&1", 'r')
+    text = pipe.read()
+    sts = pipe.close()
+    if sts is None: sts = 0
+    if text[-1:] == '\n': text = text[:-1]
+    return sts, text
+  else:
+    return commands.getstatusoutput(cmd)
+
+
+def _GenerateIDLText(idl_template):
+  (status, guid) = _GetStatusOutput("uuidgen.exe")
+  if status != 0:
+    raise SystemExit("Failed to get GUID: %s" % guid)
+
+  return idl_template % guid
+
+
+def _GenerateIDLFile(idl_template_filename, idl_output_filename):
+  f_in = open(idl_template_filename, 'r')
+  idl_template = f_in.read()
+  f_in.close()
+
+  idl_output = _GenerateIDLText(idl_template)
+
+  f_out = open(idl_output_filename, 'w')
+  f_out.write("""
+                 // ** AUTOGENERATED FILE. DO NOT HAND-EDIT **
+              """)
+  f_out.write(idl_output)
+  f_out.close()
+
+
+def _Usage():
+  """Prints out script usage information."""
+  print """
+generate_oneclick_idl.py: Write out the given IDL file.
+
+Usage:
+  generate_oneclick_idl.py [--help
+                            | --idl_template_file filename
+                              --idl_output_file filename]
+
+Options:
+  --help                    Show this information.
+  --idl_output_file filename     Path/name of output IDL filename.
+  --idl_template_file filename      Path/name of input IDL template.
+"""
+
+
+def _Main():
+  """Generates IDL file."""
+  # use getopt to parse the option and argument list; this may raise, but
+  # don't catch it
+  _ARGUMENT_LIST = ["help", "idl_template_file=", "idl_output_file="]
+  (opts, args) = getopt.getopt(sys.argv[1:], "", _ARGUMENT_LIST)
+  if not opts or ("--help", "") in opts:
+    _Usage()
+    sys.exit()
+
+  idl_template_filename = ""
+  idl_output_filename = ""
+
+  for (o, v) in opts:
+    if o == "--idl_template_file":
+      idl_template_filename = v
+    if o == "--idl_output_file":
+      idl_output_filename = v
+
+  # make sure we have work to do
+  if not idl_template_filename:
+    raise SystemExit("no idl_template_filename specified")
+  if not idl_output_filename:
+    raise SystemExit("no idl_output_filename specified")
+
+  _GenerateIDLFile(idl_template_filename, idl_output_filename)
+  sys.exit()
+
+
+if __name__ == "__main__":
+  _Main()
+
diff --git a/plugins/npOneClick.cc b/plugins/npOneClick.cc
index c584bad..926903b 100644
--- a/plugins/npOneClick.cc
+++ b/plugins/npOneClick.cc
@@ -1,263 +1,263 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// The OneClick NPAPI Plugin implementation

-// using the new NPRuntime supported by Firefox and others

-//

-//

-

-#pragma warning(push)

-#pragma warning(disable : 4201 4265)

-// 4201: nonstandard extension used : nameless struct/union

-// 4265: class has virtual functions, but destructor is not virtual

-

-#include "base/scoped_ptr.h"

-#include "omaha/plugins/npOneClick.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/string.h"

-#include "omaha/plugins/oneclick_browser_callback_npapi.h"

-#include "omaha/plugins/oneclick_worker.h"

-

-#pragma warning(pop)

-

-using omaha::ScopeGuard;

-using omaha::MakeGuard;

-

-// Convert NPString to a const wide string.

-CString ConvertNPStringToString(const NPString utf8_str) {

-  CString utf16_str;

-  if (!utf8_str.utf8characters || !utf8_str.utf8length) {

-    return utf16_str;

-  }

-

-  int len = ::MultiByteToWideChar(CP_UTF8,

-                                  0,

-                                  utf8_str.utf8characters,

-                                  utf8_str.utf8length,

-                                  NULL,

-                                  0);

-  ATLASSERT(len);

-  if (!len) {

-    return utf16_str;

-  }

-  ATLVERIFY(::MultiByteToWideChar(CP_UTF8,

-                                  0,

-                                  utf8_str.utf8characters,

-                                  utf8_str.utf8length,

-                                  CStrBuf(utf16_str, len, CStrBuf::SET_LENGTH),

-                                  len));

-

-  PLUGIN_LOG(L2, (_T("[ConvertNPStringToString][%s]"), utf16_str));

-  return utf16_str;

-}

-

-// The primary plug-in class, NPOneClickClass.

-BEGIN_PLUGIN_CLASS(NPOneClickClass)

-  PLUGIN_FUNCTION(NPOneClickClass, Install, 3)

-  PLUGIN_FUNCTION(NPOneClickClass, Install2, 1)

-  PLUGIN_FUNCTION(NPOneClickClass, GetInstalledVersion, 2)

-  PLUGIN_FUNCTION(NPOneClickClass, GetOneClickVersion, 0)

-END_BEGIN_PLUGIN_CLASS

-

-DEFINE_CPLUGIN_NPCLASS(NPOneClickClass)

-  PLUGIN_LOG(L2, (_T("[NPOneClickClass::Static constructor]")));

-  return TRUE;

-END_DEFINE_CPLUGIN_NPCLASS()

-

-BEGIN_PLUGIN_CLASS_CTOR(NPOneClickClass)

-  PLUGIN_LOG(L2, (_T("[NPOneClickClass::constructor]")));

-

-  is_worker_url_set_ = false;

-  oneclick_worker_.reset(new omaha::OneClickWorker());

-  RETTRACE_IF_FAILED(oneclick_worker_->Initialize());

-END_PLUGIN_CLASS_CTOR

-

-BEGIN_PLUGIN_CLASS_DTOR(NPOneClickClass)

-  PLUGIN_LOG(L2, (_T("[NPOneClickClass::destructor]")));

-END_PLUGIN_CLASS_DTOR

-

-void NPOneClickClass::Shutdown() {

-  VERIFY1(SUCCEEDED(oneclick_worker_->Shutdown()));

-}

-

-HRESULT NPOneClickClass::EnsureWorkerUrlSet() {

-  if (is_worker_url_set_) {

-    return S_OK;

-  }

-

-  CString browser_url_str;

-  HRESULT hr = GetUrl(&browser_url_str);

-  if (FAILED(hr)) {

-    PLUGIN_LOG(LE, (_T("[GetUrl failed][0x%x]"), hr));

-    return hr;

-  }

-

-  oneclick_worker_->set_browser_url(browser_url_str);

-  is_worker_url_set_ = true;

-  return S_OK;

-}

-

-// STDMETHOD(Install)(BSTR cmd_line_args,

-//                    VARIANT* success_callback,

-//                    VARIANT* failure_callback);

-bool NPOneClickClass::Install(const NPVariant* args,

-                              uint32_t argCount,

-                              NPVariant* result) {

-  UNREFERENCED_PARAMETER(result);

-

-  PLUGIN_LOG(L2, (_T("[NPOneClickClass::Install]")));

-  RETTRACE_EXCEPTION_IF_FAILED(EnsureWorkerUrlSet());

-

-  RETTRACE_EXCEPTION_IF_FALSE(argCount == 3 &&

-                              args &&

-                              NPVARIANT_IS_STRING(args[0]));

-

-  omaha::OneClickBrowserCallbackNpapi browser_callback;

-  RETTRACE_EXCEPTION_IF_FAILED(browser_callback.Initialize(npp_,

-                                                           args[1],

-                                                           args[2]));

-

-  RETTRACE_EXCEPTION_IF_FAILED(oneclick_worker_->DoOneClickInstall(

-      ConvertNPStringToString(NPVARIANT_TO_STRING(args[0])),

-      &browser_callback));

-

-  return true;

-}

-

-// STDMETHOD(Install2)(BSTR extra_args);

-bool NPOneClickClass::Install2(const NPVariant* args,

-                               uint32_t argCount,

-                               NPVariant* result) {

-  UNREFERENCED_PARAMETER(result);

-

-  PLUGIN_LOG(L2, (_T("[NPOneClickClass::Install2]")));

-  RETTRACE_EXCEPTION_IF_FAILED(EnsureWorkerUrlSet());

-

-  RETTRACE_EXCEPTION_IF_FALSE(argCount == 1 &&

-                              args &&

-                              NPVARIANT_IS_STRING(args[0]));

-

-  RETTRACE_EXCEPTION_IF_FAILED(oneclick_worker_->DoOneClickInstall2(

-      ConvertNPStringToString(NPVARIANT_TO_STRING(args[0]))));

-

-  return true;

-}

-

-// STDMETHOD(GetInstalledVersion)(BSTR guid_string,

-//                                VARIANT_BOOL is_machine,

-//                                BSTR* version_string);

-bool NPOneClickClass::GetInstalledVersion(const NPVariant* args,

-                                          uint32_t argCount,

-                                          NPVariant* result) {

-  PLUGIN_LOG(L2, (_T("[NPOneClickClass::GetInstalledVersion]")));

-  RETTRACE_EXCEPTION_IF_FAILED(EnsureWorkerUrlSet());

-

-  NULL_TO_NPVARIANT(*result);

-  RETTRACE_EXCEPTION_IF_FALSE(argCount == 2 &&

-                              args &&

-                              NPVARIANT_IS_STRING(args[0]) &&

-                              NPVARIANT_IS_BOOLEAN(args[1]));

-

-  CString version;

-  RETTRACE_EXCEPTION_IF_FAILED(oneclick_worker_->GetInstalledVersion(

-      ConvertNPStringToString(NPVARIANT_TO_STRING(args[0])),

-      NPVARIANT_TO_BOOLEAN(args[1]),

-      &version));

-

-  size_t version_length = version.GetLength() + 1;

-  RETTRACE_EXCEPTION_IF_FALSE(version_length);

-  char* version_out = reinterpret_cast<char *>(NPN_MemAlloc(version_length));

-  RETTRACE_EXCEPTION_IF_FALSE(version_out);

-  RETTRACE_EXCEPTION_IF_FALSE(

-      ::lstrcpynA(version_out, CStringA(version), version_length));

-

-  PLUGIN_LOG(L2, (_T("[GetInstalledVersion][%S]"), version_out));

-  STRINGZ_TO_NPVARIANT(version_out, *result);

-  return true;

-}

-

-// STDMETHOD(GetOneClickVersion)(long* version);

-bool NPOneClickClass::GetOneClickVersion(const NPVariant* args,

-                                         uint32_t argCount,

-                                         NPVariant* result) {

-  UNREFERENCED_PARAMETER(args);

-  PLUGIN_LOG(L2, (_T("[NPOneClickClass::GetOneClickVersion]")));

-  RETTRACE_EXCEPTION_IF_FAILED(EnsureWorkerUrlSet());

-

-  NULL_TO_NPVARIANT(*result);

-  RETTRACE_EXCEPTION_IF_FALSE(argCount == 0);

-

-  int32 version = 0;

-  RETTRACE_EXCEPTION_IF_FAILED(oneclick_worker_->GetOneClickVersion(&version));

-

-  INT32_TO_NPVARIANT(version, *result);

-  return true;

-}

-

-// get the URL that we are currently hosted in

-// Essentially, we return window.location.href

-HRESULT NPOneClickClass::GetUrl(CString* url_str) {

-  PLUGIN_LOG(L2, (_T("[NPOneClickClass::GetUrl]")));

-  // If npp_ is NULL, Init() has not been called

-  ATLASSERT(npp_);

-  ATLASSERT(url_str != NULL);

-  if (npp_ == NULL || url_str == NULL) {

-    return E_POINTER;

-  }

-

-  NPObject* window_object = NULL;

-

-  // Reference count not bumped up, do not release window_object

-  NPN_GetValue(npp_, NPNVWindowNPObject, &window_object);

-  if (!window_object)  {

-    return E_UNEXPECTED;

-  }

-

-  NPIdentifier location_id = NPN_GetStringIdentifier("location");

-  NPIdentifier href_id = NPN_GetStringIdentifier("href");

-

-  NPVariant locationv;

-  // Initialize the variant to NULL

-  NULL_TO_NPVARIANT(locationv);

-  NPN_GetProperty(npp_, window_object, location_id, &locationv);

-  ON_SCOPE_EXIT(NPN_ReleaseVariantValue, &locationv);

-

-  NPObject* location = NULL;

-  if (NPVARIANT_IS_OBJECT(locationv)) {

-    location = NPVARIANT_TO_OBJECT(locationv);

-  }

-

-  if (!location) {

-    return E_UNEXPECTED;

-  }

-

-  NPVariant hrefv;

-  // Initialize the variant to NULL

-  NULL_TO_NPVARIANT(hrefv);

-  NPN_GetProperty(npp_, location, href_id, &hrefv);

-  ON_SCOPE_EXIT(NPN_ReleaseVariantValue, &hrefv);

-

-  if (NPVARIANT_IS_STRING(hrefv)) {

-    CString url(ConvertNPStringToString(NPVARIANT_TO_STRING(hrefv)));

-    ATLASSERT(!url.IsEmpty());

-    if (!url.IsEmpty()) {

-      *url_str = url;

-    }

-  }

-

-  return S_OK;

-}

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// The OneClick NPAPI Plugin implementation
+// using the new NPRuntime supported by Firefox and others
+//
+//
+
+#pragma warning(push)
+#pragma warning(disable : 4201 4265)
+// 4201: nonstandard extension used : nameless struct/union
+// 4265: class has virtual functions, but destructor is not virtual
+
+#include "base/scoped_ptr.h"
+#include "omaha/plugins/npOneClick.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/string.h"
+#include "omaha/plugins/oneclick_browser_callback_npapi.h"
+#include "omaha/plugins/oneclick_worker.h"
+
+#pragma warning(pop)
+
+using omaha::ScopeGuard;
+using omaha::MakeGuard;
+
+// Convert NPString to a const wide string.
+CString ConvertNPStringToString(const NPString utf8_str) {
+  CString utf16_str;
+  if (!utf8_str.utf8characters || !utf8_str.utf8length) {
+    return utf16_str;
+  }
+
+  int len = ::MultiByteToWideChar(CP_UTF8,
+                                  0,
+                                  utf8_str.utf8characters,
+                                  utf8_str.utf8length,
+                                  NULL,
+                                  0);
+  ATLASSERT(len);
+  if (!len) {
+    return utf16_str;
+  }
+  ATLVERIFY(::MultiByteToWideChar(CP_UTF8,
+                                  0,
+                                  utf8_str.utf8characters,
+                                  utf8_str.utf8length,
+                                  CStrBuf(utf16_str, len, CStrBuf::SET_LENGTH),
+                                  len));
+
+  PLUGIN_LOG(L2, (_T("[ConvertNPStringToString][%s]"), utf16_str));
+  return utf16_str;
+}
+
+// The primary plug-in class, NPOneClickClass.
+BEGIN_PLUGIN_CLASS(NPOneClickClass)
+  PLUGIN_FUNCTION(NPOneClickClass, Install, 3)
+  PLUGIN_FUNCTION(NPOneClickClass, Install2, 1)
+  PLUGIN_FUNCTION(NPOneClickClass, GetInstalledVersion, 2)
+  PLUGIN_FUNCTION(NPOneClickClass, GetOneClickVersion, 0)
+END_BEGIN_PLUGIN_CLASS
+
+DEFINE_CPLUGIN_NPCLASS(NPOneClickClass)
+  PLUGIN_LOG(L2, (_T("[NPOneClickClass::Static constructor]")));
+  return TRUE;
+END_DEFINE_CPLUGIN_NPCLASS()
+
+BEGIN_PLUGIN_CLASS_CTOR(NPOneClickClass)
+  PLUGIN_LOG(L2, (_T("[NPOneClickClass::constructor]")));
+
+  is_worker_url_set_ = false;
+  oneclick_worker_.reset(new omaha::OneClickWorker());
+  RETTRACE_IF_FAILED(oneclick_worker_->Initialize());
+END_PLUGIN_CLASS_CTOR
+
+BEGIN_PLUGIN_CLASS_DTOR(NPOneClickClass)
+  PLUGIN_LOG(L2, (_T("[NPOneClickClass::destructor]")));
+END_PLUGIN_CLASS_DTOR
+
+void NPOneClickClass::Shutdown() {
+  VERIFY1(SUCCEEDED(oneclick_worker_->Shutdown()));
+}
+
+HRESULT NPOneClickClass::EnsureWorkerUrlSet() {
+  if (is_worker_url_set_) {
+    return S_OK;
+  }
+
+  CString browser_url_str;
+  HRESULT hr = GetUrl(&browser_url_str);
+  if (FAILED(hr)) {
+    PLUGIN_LOG(LE, (_T("[GetUrl failed][0x%x]"), hr));
+    return hr;
+  }
+
+  oneclick_worker_->set_browser_url(browser_url_str);
+  is_worker_url_set_ = true;
+  return S_OK;
+}
+
+// STDMETHOD(Install)(BSTR cmd_line_args,
+//                    VARIANT* success_callback,
+//                    VARIANT* failure_callback);
+bool NPOneClickClass::Install(const NPVariant* args,
+                              uint32_t argCount,
+                              NPVariant* result) {
+  UNREFERENCED_PARAMETER(result);
+
+  PLUGIN_LOG(L2, (_T("[NPOneClickClass::Install]")));
+  RETTRACE_EXCEPTION_IF_FAILED(EnsureWorkerUrlSet());
+
+  RETTRACE_EXCEPTION_IF_FALSE(argCount == 3 &&
+                              args &&
+                              NPVARIANT_IS_STRING(args[0]));
+
+  omaha::OneClickBrowserCallbackNpapi browser_callback;
+  RETTRACE_EXCEPTION_IF_FAILED(browser_callback.Initialize(npp_,
+                                                           args[1],
+                                                           args[2]));
+
+  RETTRACE_EXCEPTION_IF_FAILED(oneclick_worker_->DoOneClickInstall(
+      ConvertNPStringToString(NPVARIANT_TO_STRING(args[0])),
+      &browser_callback));
+
+  return true;
+}
+
+// STDMETHOD(Install2)(BSTR extra_args);
+bool NPOneClickClass::Install2(const NPVariant* args,
+                               uint32_t argCount,
+                               NPVariant* result) {
+  UNREFERENCED_PARAMETER(result);
+
+  PLUGIN_LOG(L2, (_T("[NPOneClickClass::Install2]")));
+  RETTRACE_EXCEPTION_IF_FAILED(EnsureWorkerUrlSet());
+
+  RETTRACE_EXCEPTION_IF_FALSE(argCount == 1 &&
+                              args &&
+                              NPVARIANT_IS_STRING(args[0]));
+
+  RETTRACE_EXCEPTION_IF_FAILED(oneclick_worker_->DoOneClickInstall2(
+      ConvertNPStringToString(NPVARIANT_TO_STRING(args[0]))));
+
+  return true;
+}
+
+// STDMETHOD(GetInstalledVersion)(BSTR guid_string,
+//                                VARIANT_BOOL is_machine,
+//                                BSTR* version_string);
+bool NPOneClickClass::GetInstalledVersion(const NPVariant* args,
+                                          uint32_t argCount,
+                                          NPVariant* result) {
+  PLUGIN_LOG(L2, (_T("[NPOneClickClass::GetInstalledVersion]")));
+  RETTRACE_EXCEPTION_IF_FAILED(EnsureWorkerUrlSet());
+
+  NULL_TO_NPVARIANT(*result);
+  RETTRACE_EXCEPTION_IF_FALSE(argCount == 2 &&
+                              args &&
+                              NPVARIANT_IS_STRING(args[0]) &&
+                              NPVARIANT_IS_BOOLEAN(args[1]));
+
+  CString version;
+  RETTRACE_EXCEPTION_IF_FAILED(oneclick_worker_->GetInstalledVersion(
+      ConvertNPStringToString(NPVARIANT_TO_STRING(args[0])),
+      NPVARIANT_TO_BOOLEAN(args[1]),
+      &version));
+
+  size_t version_length = version.GetLength() + 1;
+  RETTRACE_EXCEPTION_IF_FALSE(version_length);
+  char* version_out = reinterpret_cast<char *>(NPN_MemAlloc(version_length));
+  RETTRACE_EXCEPTION_IF_FALSE(version_out);
+  RETTRACE_EXCEPTION_IF_FALSE(
+      ::lstrcpynA(version_out, CStringA(version), version_length));
+
+  PLUGIN_LOG(L2, (_T("[GetInstalledVersion][%S]"), version_out));
+  STRINGZ_TO_NPVARIANT(version_out, *result);
+  return true;
+}
+
+// STDMETHOD(GetOneClickVersion)(long* version);
+bool NPOneClickClass::GetOneClickVersion(const NPVariant* args,
+                                         uint32_t argCount,
+                                         NPVariant* result) {
+  UNREFERENCED_PARAMETER(args);
+  PLUGIN_LOG(L2, (_T("[NPOneClickClass::GetOneClickVersion]")));
+  RETTRACE_EXCEPTION_IF_FAILED(EnsureWorkerUrlSet());
+
+  NULL_TO_NPVARIANT(*result);
+  RETTRACE_EXCEPTION_IF_FALSE(argCount == 0);
+
+  int32 version = 0;
+  RETTRACE_EXCEPTION_IF_FAILED(oneclick_worker_->GetOneClickVersion(&version));
+
+  INT32_TO_NPVARIANT(version, *result);
+  return true;
+}
+
+// get the URL that we are currently hosted in
+// Essentially, we return window.location.href
+HRESULT NPOneClickClass::GetUrl(CString* url_str) {
+  PLUGIN_LOG(L2, (_T("[NPOneClickClass::GetUrl]")));
+  // If npp_ is NULL, Init() has not been called
+  ATLASSERT(npp_);
+  ATLASSERT(url_str != NULL);
+  if (npp_ == NULL || url_str == NULL) {
+    return E_POINTER;
+  }
+
+  NPObject* window_object = NULL;
+
+  // Reference count not bumped up, do not release window_object
+  NPN_GetValue(npp_, NPNVWindowNPObject, &window_object);
+  if (!window_object)  {
+    return E_UNEXPECTED;
+  }
+
+  NPIdentifier location_id = NPN_GetStringIdentifier("location");
+  NPIdentifier href_id = NPN_GetStringIdentifier("href");
+
+  NPVariant locationv;
+  // Initialize the variant to NULL
+  NULL_TO_NPVARIANT(locationv);
+  NPN_GetProperty(npp_, window_object, location_id, &locationv);
+  ON_SCOPE_EXIT(NPN_ReleaseVariantValue, &locationv);
+
+  NPObject* location = NULL;
+  if (NPVARIANT_IS_OBJECT(locationv)) {
+    location = NPVARIANT_TO_OBJECT(locationv);
+  }
+
+  if (!location) {
+    return E_UNEXPECTED;
+  }
+
+  NPVariant hrefv;
+  // Initialize the variant to NULL
+  NULL_TO_NPVARIANT(hrefv);
+  NPN_GetProperty(npp_, location, href_id, &hrefv);
+  ON_SCOPE_EXIT(NPN_ReleaseVariantValue, &hrefv);
+
+  if (NPVARIANT_IS_STRING(hrefv)) {
+    CString url(ConvertNPStringToString(NPVARIANT_TO_STRING(hrefv)));
+    ATLASSERT(!url.IsEmpty());
+    if (!url.IsEmpty()) {
+      *url_str = url;
+    }
+  }
+
+  return S_OK;
+}
+
diff --git a/plugins/npOneClick.h b/plugins/npOneClick.h
index e014e6b..9549617 100644
--- a/plugins/npOneClick.h
+++ b/plugins/npOneClick.h
@@ -1,184 +1,184 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// The OneClick NPAPI Plugin implementation

-// using the new NPRuntime supported by Firefox and other

-

-#ifndef OMAHA_PLUGINS_NPONECLICK_H__

-#define OMAHA_PLUGINS_NPONECLICK_H__

-

-#include "omaha/third_party/gecko/include/npupp.h"

-

-#include <atlsafe.h>              // NOLINT

-

-#include "omaha/plugins/baseplugin.h"

-

-// These files need to be included _after_ the headers above because

-// npupp.h includes windows.h in a special way and defines uint32 and so

-// forth on its own.  If we include these "standard" headers first, then

-// the type system gets all confused.  However, including these afterwards

-// makes lint angry since you're not normally supposed to do this.  But that's

-// why there is the NOLINT comment after each of the header lines below.

-#include <ATLBase.h>              // NOLINT

-#include <ATLSafe.h>              // NOLINT

-#include <ATLCom.h>               // NOLINT

-#include <ATLStr.h>               // NOLINT

-#include <ATLConv.h>              // NOLINT

-#include <ObjSafe.h>              // NOLINT

-

-// Need to do the following, rather than #include common/basictypes.h

-// because some defines/types in basictypes.h conflict with the NPAPI

-// headers

-

-// Force basictypes.h to not be included

-#define BASE_BASICTYPES_H_

-

-// #undef ATLASSERT, we will use the one from atlassert.h #included below

-#undef ATLASSERT

-

-// Copied from basictypes.h

-// Typedefing some values that are needed within logging.h

-typedef uint64 time64;

-

-// Copied from basictypes.h

-// A macro to disallow the evil copy constructor and operator= functions

-// This should be used in the private: declarations for a class

-#define DISALLOW_EVIL_CONSTRUCTORS(TypeName)    \

-  TypeName(const TypeName&);                    \

-  TypeName &operator=(const TypeName&)

-

-#include "common/atlconvfix.h"

-// logging.h contains definitions for PLUGIN_LOG

-#include "common/logging.h"

-#include "common/atlassert.h"

-// debug.h contains definitions for ASSERT

-#include "common/debug.h"

-

-#ifndef ARRAYSIZE

-#define ARRAYSIZE(x) (sizeof(x) / sizeof(*(x)))

-#endif

-

-// Helper macros

-// TRACE, ASSERT and return if the first argument evaluates to false

-#define RETTRACE_IF_FALSE(x)                                \

-  do {                                                      \

-    BOOL success(!!(x));                                    \

-    if (!success) {                                         \

-      PLUGIN_LOG(L2, (_T("[") _T(#x) _T("] is FALSE")));    \

-      ASSERT(FALSE, (_T("[") _T(#x) _T("] is FALSE")));     \

-      return;                                               \

-    }                                                       \

-  } while (false)                                           \

-

-// TRACE, ASSERT and return if the HRESULT argument is a COM error

-#define RETTRACE_IF_FAILED(x)  RETTRACE_IF_FALSE(SUCCEEDED(x))

-

-// TRACE, throw exception and return if the first argument evaluates to false

-#define RETTRACE_EXCEPTION_IF_FALSE(x)                      \

-  do {                                                      \

-    BOOL success(!!(x));                                    \

-    if (!success) {                                         \

-      PLUGIN_LOG(L2, (_T("[") _T(#x) _T("] is FALSE")));    \

-      ASSERT(FALSE, (_T("[") _T(#x) _T("] is FALSE")));     \

-      NPN_SetException(this, "false");                      \

-      return true;                                          \

-    }                                                       \

-  } while (false)                                           \

-

-// TRACE, throw exception and return if the HRESULT argument is a COM error

-#define RETTRACE_EXCEPTION_IF_FAILED(x)                     \

-  do {                                                      \

-    HRESULT hr = (x);                                       \

-    if (FAILED(hr)) {                                       \

-      PLUGIN_LOG(L2, (_T("[") _T(#x) _T("] is FAILED")));   \

-      ASSERT(FALSE, (_T("[") _T(#x) _T("] is FAILED")));    \

-      char buf[32];                                         \

-      ::wnsprintfA(buf, ARRAYSIZE(buf), "0x%08x", hr);      \

-      NPN_SetException(this, buf);                          \

-      return true;                                          \

-    }                                                       \

-  } while (false)                                           \

-

-// Simple helper macro for the class to define bool based properties

-#define DEFINE_BOOL_PROPERTY(the_class, x, instance, method)                  \

-bool the_class::Get##x(NPVariant *result) {                                   \

-  PLUGIN_LOG(L2, (_T("[") _T(#the_class) _T("::Get") _T(#x) _T("]")));        \

-  RETTRACE_EXCEPTION_IF_FALSE(instance != NULL);                              \

-  VARIANT_BOOL yes = VARIANT_FALSE;                                           \

-  RETTRACE_EXCEPTION_IF_FAILED(instance->method(&yes));                       \

-  BOOLEAN_TO_NPVARIANT(yes == VARIANT_TRUE, *result);                         \

-  return true;                                                                \

-}                                                                             \

-                                                                              \

-bool the_class::Set##x(const NPVariant *value) {                              \

-  PLUGIN_LOG(L2, (_T("[") _T(#the_class) _T("::Set") _T(#x)                   \

-                  _T("] - Not Implemented")));                                \

-  /* Script should not be calling this! */                                    \

-  ATLASSERT(FALSE);                                                           \

-  return false;                                                               \

-}

-

-// Simple helper macro for the class to define string based properties

-#define DEFINE_STRING_PROPERTY(the_class, x, instance, method)                \

-bool the_class::Get##x(NPVariant *result) {                                   \

-  PLUGIN_LOG(L2, (_T("[") _T(#the_class) _T("::Get") _T(#x) _T("]")));        \

-  RETTRACE_EXCEPTION_IF_FALSE(instance);                                      \

-  CComBSTR bstr;                                                              \

-  instance->method(&bstr);                                                    \

-  size_t cch = bstr.Length() + 1;                                             \

-  RETTRACE_EXCEPTION_IF_FALSE(cch);                                           \

-  /* Use NPN_MemAlloc() to allocate [out] parameter memory */                 \

-  char* result_##x = reinterpret_cast<char *>(NPN_MemAlloc(cch));             \

-  RETTRACE_EXCEPTION_IF_FALSE(::lstrcpynA(result_##x, CW2A(bstr), cch));      \

-  PLUGIN_LOG(L2, (_T("[") _T(#the_class) _T("::Get") _T(#x)                   \

-                  _T("][retval=%S]"), result_##x));                           \

-  STRINGZ_TO_NPVARIANT(result_##x, *result);                                  \

-  return true;                                                                \

-}                                                                             \

-                                                                              \

-bool the_class::Set##x(const NPVariant *value) {                              \

-  PLUGIN_LOG(L2, (_T("[") _T(#the_class) _T("::Set") _T(#x)                   \

-                  _T("] - Not Implemented")));                                \

-  /* Script should not be calling this! */                                    \

-  ATLASSERT(FALSE);                                                           \

-  return false;                                                               \

-}                                                                             \

-

-namespace omaha {

-

-class OneClickWorker;

-

-}  // namespace omaha

-

-

-// The primary plug-in class, NPOneClickClass.

-DECLARE_PLUGIN_CLASS(NPOneClickClass)

-  virtual void Shutdown();

-  DECLARE_PLUGIN_FUNCTION(Install)

-  DECLARE_PLUGIN_FUNCTION(Install2)

-  DECLARE_PLUGIN_FUNCTION(GetInstalledVersion)

-  DECLARE_PLUGIN_FUNCTION(GetOneClickVersion)

-  DECLARE_CPLUGIN_NPCLASS()

- private:

-  HRESULT EnsureWorkerUrlSet();

-  HRESULT GetUrl(CString* url_str);

-

-  scoped_ptr<omaha::OneClickWorker> oneclick_worker_;

-  bool is_worker_url_set_;

-END_DECLARE_PLUGIN_CLASS(NPOneClickClass)

-

-#endif  // OMAHA_PLUGINS_NPONECLICK_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// The OneClick NPAPI Plugin implementation
+// using the new NPRuntime supported by Firefox and other
+
+#ifndef OMAHA_PLUGINS_NPONECLICK_H__
+#define OMAHA_PLUGINS_NPONECLICK_H__
+
+#include "omaha/third_party/gecko/include/npupp.h"
+
+#include <atlsafe.h>              // NOLINT
+
+#include "omaha/plugins/baseplugin.h"
+
+// These files need to be included _after_ the headers above because
+// npupp.h includes windows.h in a special way and defines uint32 and so
+// forth on its own.  If we include these "standard" headers first, then
+// the type system gets all confused.  However, including these afterwards
+// makes lint angry since you're not normally supposed to do this.  But that's
+// why there is the NOLINT comment after each of the header lines below.
+#include <ATLBase.h>              // NOLINT
+#include <ATLSafe.h>              // NOLINT
+#include <ATLCom.h>               // NOLINT
+#include <ATLStr.h>               // NOLINT
+#include <ATLConv.h>              // NOLINT
+#include <ObjSafe.h>              // NOLINT
+
+// Need to do the following, rather than #include common/basictypes.h
+// because some defines/types in basictypes.h conflict with the NPAPI
+// headers
+
+// Force basictypes.h to not be included
+#define BASE_BASICTYPES_H_
+
+// #undef ATLASSERT, we will use the one from atlassert.h #included below
+#undef ATLASSERT
+
+// Copied from basictypes.h
+// Typedefing some values that are needed within logging.h
+typedef uint64 time64;
+
+// Copied from basictypes.h
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_EVIL_CONSTRUCTORS(TypeName)    \
+  TypeName(const TypeName&);                    \
+  TypeName &operator=(const TypeName&)
+
+#include "common/atlconvfix.h"
+// logging.h contains definitions for PLUGIN_LOG
+#include "common/logging.h"
+#include "common/atlassert.h"
+// debug.h contains definitions for ASSERT
+#include "common/debug.h"
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(x) (sizeof(x) / sizeof(*(x)))
+#endif
+
+// Helper macros
+// TRACE, ASSERT and return if the first argument evaluates to false
+#define RETTRACE_IF_FALSE(x)                                \
+  do {                                                      \
+    BOOL success(!!(x));                                    \
+    if (!success) {                                         \
+      PLUGIN_LOG(L2, (_T("[") _T(#x) _T("] is FALSE")));    \
+      ASSERT(FALSE, (_T("[") _T(#x) _T("] is FALSE")));     \
+      return;                                               \
+    }                                                       \
+  } while (false)                                           \
+
+// TRACE, ASSERT and return if the HRESULT argument is a COM error
+#define RETTRACE_IF_FAILED(x)  RETTRACE_IF_FALSE(SUCCEEDED(x))
+
+// TRACE, throw exception and return if the first argument evaluates to false
+#define RETTRACE_EXCEPTION_IF_FALSE(x)                      \
+  do {                                                      \
+    BOOL success(!!(x));                                    \
+    if (!success) {                                         \
+      PLUGIN_LOG(L2, (_T("[") _T(#x) _T("] is FALSE")));    \
+      ASSERT(FALSE, (_T("[") _T(#x) _T("] is FALSE")));     \
+      NPN_SetException(this, "false");                      \
+      return true;                                          \
+    }                                                       \
+  } while (false)                                           \
+
+// TRACE, throw exception and return if the HRESULT argument is a COM error
+#define RETTRACE_EXCEPTION_IF_FAILED(x)                     \
+  do {                                                      \
+    HRESULT hr = (x);                                       \
+    if (FAILED(hr)) {                                       \
+      PLUGIN_LOG(L2, (_T("[") _T(#x) _T("] is FAILED")));   \
+      ASSERT(FALSE, (_T("[") _T(#x) _T("] is FAILED")));    \
+      char buf[32];                                         \
+      ::wnsprintfA(buf, ARRAYSIZE(buf), "0x%08x", hr);      \
+      NPN_SetException(this, buf);                          \
+      return true;                                          \
+    }                                                       \
+  } while (false)                                           \
+
+// Simple helper macro for the class to define bool based properties
+#define DEFINE_BOOL_PROPERTY(the_class, x, instance, method)                  \
+bool the_class::Get##x(NPVariant *result) {                                   \
+  PLUGIN_LOG(L2, (_T("[") _T(#the_class) _T("::Get") _T(#x) _T("]")));        \
+  RETTRACE_EXCEPTION_IF_FALSE(instance != NULL);                              \
+  VARIANT_BOOL yes = VARIANT_FALSE;                                           \
+  RETTRACE_EXCEPTION_IF_FAILED(instance->method(&yes));                       \
+  BOOLEAN_TO_NPVARIANT(yes == VARIANT_TRUE, *result);                         \
+  return true;                                                                \
+}                                                                             \
+                                                                              \
+bool the_class::Set##x(const NPVariant *value) {                              \
+  PLUGIN_LOG(L2, (_T("[") _T(#the_class) _T("::Set") _T(#x)                   \
+                  _T("] - Not Implemented")));                                \
+  /* Script should not be calling this! */                                    \
+  ATLASSERT(FALSE);                                                           \
+  return false;                                                               \
+}
+
+// Simple helper macro for the class to define string based properties
+#define DEFINE_STRING_PROPERTY(the_class, x, instance, method)                \
+bool the_class::Get##x(NPVariant *result) {                                   \
+  PLUGIN_LOG(L2, (_T("[") _T(#the_class) _T("::Get") _T(#x) _T("]")));        \
+  RETTRACE_EXCEPTION_IF_FALSE(instance);                                      \
+  CComBSTR bstr;                                                              \
+  instance->method(&bstr);                                                    \
+  size_t cch = bstr.Length() + 1;                                             \
+  RETTRACE_EXCEPTION_IF_FALSE(cch);                                           \
+  /* Use NPN_MemAlloc() to allocate [out] parameter memory */                 \
+  char* result_##x = reinterpret_cast<char *>(NPN_MemAlloc(cch));             \
+  RETTRACE_EXCEPTION_IF_FALSE(::lstrcpynA(result_##x, CW2A(bstr), cch));      \
+  PLUGIN_LOG(L2, (_T("[") _T(#the_class) _T("::Get") _T(#x)                   \
+                  _T("][retval=%S]"), result_##x));                           \
+  STRINGZ_TO_NPVARIANT(result_##x, *result);                                  \
+  return true;                                                                \
+}                                                                             \
+                                                                              \
+bool the_class::Set##x(const NPVariant *value) {                              \
+  PLUGIN_LOG(L2, (_T("[") _T(#the_class) _T("::Set") _T(#x)                   \
+                  _T("] - Not Implemented")));                                \
+  /* Script should not be calling this! */                                    \
+  ATLASSERT(FALSE);                                                           \
+  return false;                                                               \
+}                                                                             \
+
+namespace omaha {
+
+class OneClickWorker;
+
+}  // namespace omaha
+
+
+// The primary plug-in class, NPOneClickClass.
+DECLARE_PLUGIN_CLASS(NPOneClickClass)
+  virtual void Shutdown();
+  DECLARE_PLUGIN_FUNCTION(Install)
+  DECLARE_PLUGIN_FUNCTION(Install2)
+  DECLARE_PLUGIN_FUNCTION(GetInstalledVersion)
+  DECLARE_PLUGIN_FUNCTION(GetOneClickVersion)
+  DECLARE_CPLUGIN_NPCLASS()
+ private:
+  HRESULT EnsureWorkerUrlSet();
+  HRESULT GetUrl(CString* url_str);
+
+  scoped_ptr<omaha::OneClickWorker> oneclick_worker_;
+  bool is_worker_url_set_;
+END_DECLARE_PLUGIN_CLASS(NPOneClickClass)
+
+#endif  // OMAHA_PLUGINS_NPONECLICK_H__
+
diff --git a/plugins/np_entry.cc b/plugins/np_entry.cc
index 96f3312..6c99449 100644
--- a/plugins/np_entry.cc
+++ b/plugins/np_entry.cc
@@ -1,193 +1,193 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

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

-//

-// Main plugin entry point implementation

-//

-

-#pragma warning(push)

-#pragma warning(disable: 4201)  // c4201: nonstandard extension used

-                                //        nameless struct/union

-

-#include "omaha/third_party/gecko/include/npapi.h"

-#include "omaha/third_party/gecko/include/npupp.h"

-

-#pragma warning(pop)

-

-#ifndef HIBYTE

-#define HIBYTE(x) (((static_cast<uint32>(x)) & 0xff00) >> 8)

-#endif

-

-NPNetscapeFuncs NPNFuncs;

-

-#ifdef XP_WIN

-

-NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs) {

-  if (pFuncs == NULL) {

-    return NPERR_INVALID_FUNCTABLE_ERROR;

-  }

-

-  if (pFuncs->size < sizeof(NPPluginFuncs)) {

-    return NPERR_INVALID_FUNCTABLE_ERROR;

-  }

-

-  pFuncs->version       = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;

-  pFuncs->newp          = NPP_New;

-  pFuncs->destroy       = NPP_Destroy;

-  pFuncs->setwindow     = NPP_SetWindow;

-  pFuncs->newstream     = NPP_NewStream;

-  pFuncs->destroystream = NPP_DestroyStream;

-  pFuncs->asfile        = NPP_StreamAsFile;

-  pFuncs->writeready    = NPP_WriteReady;

-  pFuncs->write         = NPP_Write;

-  pFuncs->print         = NPP_Print;

-  pFuncs->event         = NPP_HandleEvent;

-  pFuncs->urlnotify     = NPP_URLNotify;

-  pFuncs->getvalue      = NPP_GetValue;

-  pFuncs->setvalue      = NPP_SetValue;

-  pFuncs->javaClass     = NULL;

-

-  return NPERR_NO_ERROR;

-}

-

-#endif /* XP_WIN */

-

-char* NPP_GetMIMEDescription();

-

-char* NP_GetMIMEDescription() {

-  return NPP_GetMIMEDescription();

-}

-

-NPError NP_GetValue(void* future, NPPVariable variable, void *value) {

-  return NPP_GetValue(reinterpret_cast<NPP_t *>(future), variable, value);

-}

-

-NPError OSCALL NP_Initialize(NPNetscapeFuncs* pFuncs

-#ifdef XP_UNIX

-                             , NPPluginFuncs* pluginFuncs

-#endif

-                             ) {

-  if (pFuncs == NULL) {

-    return NPERR_INVALID_FUNCTABLE_ERROR;

-  }

-

-  if (HIBYTE(pFuncs->version) > NP_VERSION_MAJOR) {

-    return NPERR_INCOMPATIBLE_VERSION_ERROR;

-  }

-

-  // TODO(omaha): This is not matching, find out why

-  // if(pFuncs->size < sizeof(NPNetscapeFuncs))

-  //  return NPERR_INVALID_FUNCTABLE_ERROR;

-

-  NPNFuncs.size                    = pFuncs->size;

-  NPNFuncs.version                 = pFuncs->version;

-  NPNFuncs.geturlnotify            = pFuncs->geturlnotify;

-  NPNFuncs.geturl                  = pFuncs->geturl;

-  NPNFuncs.posturlnotify           = pFuncs->posturlnotify;

-  NPNFuncs.posturl                 = pFuncs->posturl;

-  NPNFuncs.requestread             = pFuncs->requestread;

-  NPNFuncs.newstream               = pFuncs->newstream;

-  NPNFuncs.write                   = pFuncs->write;

-  NPNFuncs.destroystream           = pFuncs->destroystream;

-  NPNFuncs.status                  = pFuncs->status;

-  NPNFuncs.uagent                  = pFuncs->uagent;

-  NPNFuncs.memalloc                = pFuncs->memalloc;

-  NPNFuncs.memfree                 = pFuncs->memfree;

-  NPNFuncs.memflush                = pFuncs->memflush;

-  NPNFuncs.reloadplugins           = pFuncs->reloadplugins;

-  NPNFuncs.getJavaEnv              = pFuncs->getJavaEnv;

-  NPNFuncs.getJavaPeer             = pFuncs->getJavaPeer;

-  NPNFuncs.getvalue                = pFuncs->getvalue;

-  NPNFuncs.setvalue                = pFuncs->setvalue;

-  NPNFuncs.invalidaterect          = pFuncs->invalidaterect;

-  NPNFuncs.invalidateregion        = pFuncs->invalidateregion;

-  NPNFuncs.forceredraw             = pFuncs->forceredraw;

-  NPNFuncs.getstringidentifier     = pFuncs->getstringidentifier;

-  NPNFuncs.getstringidentifiers    = pFuncs->getstringidentifiers;

-  NPNFuncs.getintidentifier        = pFuncs->getintidentifier;

-  NPNFuncs.identifierisstring      = pFuncs->identifierisstring;

-  NPNFuncs.utf8fromidentifier      = pFuncs->utf8fromidentifier;

-  NPNFuncs.intfromidentifier       = pFuncs->intfromidentifier;

-  NPNFuncs.createobject            = pFuncs->createobject;

-  NPNFuncs.retainobject            = pFuncs->retainobject;

-  NPNFuncs.releaseobject           = pFuncs->releaseobject;

-  NPNFuncs.invoke                  = pFuncs->invoke;

-  NPNFuncs.invokeDefault           = pFuncs->invokeDefault;

-  NPNFuncs.evaluate                = pFuncs->evaluate;

-  NPNFuncs.getproperty             = pFuncs->getproperty;

-  NPNFuncs.setproperty             = pFuncs->setproperty;

-  NPNFuncs.removeproperty          = pFuncs->removeproperty;

-  NPNFuncs.hasproperty             = pFuncs->hasproperty;

-  NPNFuncs.hasmethod               = pFuncs->hasmethod;

-  NPNFuncs.releasevariantvalue     = pFuncs->releasevariantvalue;

-  NPNFuncs.setexception            = pFuncs->setexception;

-

-#ifdef XP_UNIX

-  /*

-   * Set up the plugin function table that Netscape will use to

-   * call us.  Netscape needs to know about our version and size

-   * and have a UniversalProcPointer for every function we

-   * implement.

-   */

-  pluginFuncs->version    = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;

-  pluginFuncs->size       = sizeof(NPPluginFuncs);

-  pluginFuncs->newp       = NewNPP_NewProc(NPP_New);

-  pluginFuncs->destroy    = NewNPP_DestroyProc(NPP_Destroy);

-  pluginFuncs->setwindow  = NewNPP_SetWindowProc(NPP_SetWindow);

-  pluginFuncs->newstream  = NewNPP_NewStreamProc(NPP_NewStream);

-  pluginFuncs->destroystream = NewNPP_DestroyStreamProc(NPP_DestroyStream);

-  pluginFuncs->asfile     = NewNPP_StreamAsFileProc(NPP_StreamAsFile);

-  pluginFuncs->writeready = NewNPP_WriteReadyProc(NPP_WriteReady);

-  pluginFuncs->write      = NewNPP_WriteProc(NPP_Write);

-  pluginFuncs->print      = NewNPP_PrintProc(NPP_Print);

-  pluginFuncs->urlnotify  = NewNPP_URLNotifyProc(NPP_URLNotify);

-  pluginFuncs->event      = NULL;

-  pluginFuncs->getvalue   = NewNPP_GetValueProc(NPP_GetValue);

-#ifdef OJI

-  pluginFuncs->javaClass  = NPP_GetJavaClass();

-#endif

-

-  NPP_Initialize();

-#endif

-

-  return NPERR_NO_ERROR;

-}

-

-NPError OSCALL NP_Shutdown() {

-  return NPERR_NO_ERROR;

-}

+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+//////////////////////////////////////////////////////////////
+//
+// Main plugin entry point implementation
+//
+
+#pragma warning(push)
+#pragma warning(disable: 4201)  // c4201: nonstandard extension used
+                                //        nameless struct/union
+
+#include "omaha/third_party/gecko/include/npapi.h"
+#include "omaha/third_party/gecko/include/npupp.h"
+
+#pragma warning(pop)
+
+#ifndef HIBYTE
+#define HIBYTE(x) (((static_cast<uint32>(x)) & 0xff00) >> 8)
+#endif
+
+NPNetscapeFuncs NPNFuncs;
+
+#ifdef XP_WIN
+
+NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs) {
+  if (pFuncs == NULL) {
+    return NPERR_INVALID_FUNCTABLE_ERROR;
+  }
+
+  if (pFuncs->size < sizeof(NPPluginFuncs)) {
+    return NPERR_INVALID_FUNCTABLE_ERROR;
+  }
+
+  pFuncs->version       = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
+  pFuncs->newp          = NPP_New;
+  pFuncs->destroy       = NPP_Destroy;
+  pFuncs->setwindow     = NPP_SetWindow;
+  pFuncs->newstream     = NPP_NewStream;
+  pFuncs->destroystream = NPP_DestroyStream;
+  pFuncs->asfile        = NPP_StreamAsFile;
+  pFuncs->writeready    = NPP_WriteReady;
+  pFuncs->write         = NPP_Write;
+  pFuncs->print         = NPP_Print;
+  pFuncs->event         = NPP_HandleEvent;
+  pFuncs->urlnotify     = NPP_URLNotify;
+  pFuncs->getvalue      = NPP_GetValue;
+  pFuncs->setvalue      = NPP_SetValue;
+  pFuncs->javaClass     = NULL;
+
+  return NPERR_NO_ERROR;
+}
+
+#endif /* XP_WIN */
+
+char* NPP_GetMIMEDescription();
+
+char* NP_GetMIMEDescription() {
+  return NPP_GetMIMEDescription();
+}
+
+NPError NP_GetValue(void* future, NPPVariable variable, void *value) {
+  return NPP_GetValue(reinterpret_cast<NPP_t *>(future), variable, value);
+}
+
+NPError OSCALL NP_Initialize(NPNetscapeFuncs* pFuncs
+#ifdef XP_UNIX
+                             , NPPluginFuncs* pluginFuncs
+#endif
+                             ) {
+  if (pFuncs == NULL) {
+    return NPERR_INVALID_FUNCTABLE_ERROR;
+  }
+
+  if (HIBYTE(pFuncs->version) > NP_VERSION_MAJOR) {
+    return NPERR_INCOMPATIBLE_VERSION_ERROR;
+  }
+
+  // TODO(omaha): This is not matching, find out why
+  // if(pFuncs->size < sizeof(NPNetscapeFuncs))
+  //  return NPERR_INVALID_FUNCTABLE_ERROR;
+
+  NPNFuncs.size                    = pFuncs->size;
+  NPNFuncs.version                 = pFuncs->version;
+  NPNFuncs.geturlnotify            = pFuncs->geturlnotify;
+  NPNFuncs.geturl                  = pFuncs->geturl;
+  NPNFuncs.posturlnotify           = pFuncs->posturlnotify;
+  NPNFuncs.posturl                 = pFuncs->posturl;
+  NPNFuncs.requestread             = pFuncs->requestread;
+  NPNFuncs.newstream               = pFuncs->newstream;
+  NPNFuncs.write                   = pFuncs->write;
+  NPNFuncs.destroystream           = pFuncs->destroystream;
+  NPNFuncs.status                  = pFuncs->status;
+  NPNFuncs.uagent                  = pFuncs->uagent;
+  NPNFuncs.memalloc                = pFuncs->memalloc;
+  NPNFuncs.memfree                 = pFuncs->memfree;
+  NPNFuncs.memflush                = pFuncs->memflush;
+  NPNFuncs.reloadplugins           = pFuncs->reloadplugins;
+  NPNFuncs.getJavaEnv              = pFuncs->getJavaEnv;
+  NPNFuncs.getJavaPeer             = pFuncs->getJavaPeer;
+  NPNFuncs.getvalue                = pFuncs->getvalue;
+  NPNFuncs.setvalue                = pFuncs->setvalue;
+  NPNFuncs.invalidaterect          = pFuncs->invalidaterect;
+  NPNFuncs.invalidateregion        = pFuncs->invalidateregion;
+  NPNFuncs.forceredraw             = pFuncs->forceredraw;
+  NPNFuncs.getstringidentifier     = pFuncs->getstringidentifier;
+  NPNFuncs.getstringidentifiers    = pFuncs->getstringidentifiers;
+  NPNFuncs.getintidentifier        = pFuncs->getintidentifier;
+  NPNFuncs.identifierisstring      = pFuncs->identifierisstring;
+  NPNFuncs.utf8fromidentifier      = pFuncs->utf8fromidentifier;
+  NPNFuncs.intfromidentifier       = pFuncs->intfromidentifier;
+  NPNFuncs.createobject            = pFuncs->createobject;
+  NPNFuncs.retainobject            = pFuncs->retainobject;
+  NPNFuncs.releaseobject           = pFuncs->releaseobject;
+  NPNFuncs.invoke                  = pFuncs->invoke;
+  NPNFuncs.invokeDefault           = pFuncs->invokeDefault;
+  NPNFuncs.evaluate                = pFuncs->evaluate;
+  NPNFuncs.getproperty             = pFuncs->getproperty;
+  NPNFuncs.setproperty             = pFuncs->setproperty;
+  NPNFuncs.removeproperty          = pFuncs->removeproperty;
+  NPNFuncs.hasproperty             = pFuncs->hasproperty;
+  NPNFuncs.hasmethod               = pFuncs->hasmethod;
+  NPNFuncs.releasevariantvalue     = pFuncs->releasevariantvalue;
+  NPNFuncs.setexception            = pFuncs->setexception;
+
+#ifdef XP_UNIX
+  /*
+   * Set up the plugin function table that Netscape will use to
+   * call us.  Netscape needs to know about our version and size
+   * and have a UniversalProcPointer for every function we
+   * implement.
+   */
+  pluginFuncs->version    = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
+  pluginFuncs->size       = sizeof(NPPluginFuncs);
+  pluginFuncs->newp       = NewNPP_NewProc(NPP_New);
+  pluginFuncs->destroy    = NewNPP_DestroyProc(NPP_Destroy);
+  pluginFuncs->setwindow  = NewNPP_SetWindowProc(NPP_SetWindow);
+  pluginFuncs->newstream  = NewNPP_NewStreamProc(NPP_NewStream);
+  pluginFuncs->destroystream = NewNPP_DestroyStreamProc(NPP_DestroyStream);
+  pluginFuncs->asfile     = NewNPP_StreamAsFileProc(NPP_StreamAsFile);
+  pluginFuncs->writeready = NewNPP_WriteReadyProc(NPP_WriteReady);
+  pluginFuncs->write      = NewNPP_WriteProc(NPP_Write);
+  pluginFuncs->print      = NewNPP_PrintProc(NPP_Print);
+  pluginFuncs->urlnotify  = NewNPP_URLNotifyProc(NPP_URLNotify);
+  pluginFuncs->event      = NULL;
+  pluginFuncs->getvalue   = NewNPP_GetValueProc(NPP_GetValue);
+#ifdef OJI
+  pluginFuncs->javaClass  = NPP_GetJavaClass();
+#endif
+
+  NPP_Initialize();
+#endif
+
+  return NPERR_NO_ERROR;
+}
+
+NPError OSCALL NP_Shutdown() {
+  return NPERR_NO_ERROR;
+}
diff --git a/plugins/npn_gate.cc b/plugins/npn_gate.cc
index efeb79b..1281004 100644
--- a/plugins/npn_gate.cc
+++ b/plugins/npn_gate.cc
@@ -1,340 +1,340 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

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

-//

-// Implementation of Netscape entry points (NPN_*)

-//

-

-#pragma warning(push)

-#pragma warning(disable: 4201)  // c4201: nonstandard extension used

-                                //        nameless struct/union

-

-#include "omaha/third_party/gecko/include/npapi.h"

-#include "omaha/third_party/gecko/include/npupp.h"

-

-#pragma warning(pop)

-

-#ifndef HIBYTE

-#define HIBYTE(x) (((static_cast<uint32>(x)) & 0xff00) >> 8)

-#endif

-

-#ifndef LOBYTE

-#define LOBYTE(W) ((W) & 0xFF)

-#endif

-

-extern NPNetscapeFuncs NPNFuncs;

-

-void NPN_Version(int* plugin_major,

-                 int* plugin_minor,

-                 int* netscape_major,

-                 int* netscape_minor) {

-  *plugin_major   = NP_VERSION_MAJOR;

-  *plugin_minor   = NP_VERSION_MINOR;

-  *netscape_major = HIBYTE(NPNFuncs.version);

-  *netscape_minor = LOBYTE(NPNFuncs.version);

-}

-

-NPError NPN_GetURLNotify(NPP instance,

-                         const char *url,

-                         const char *target,

-                         void* notifyData) {

-  int navMinorVers = NPNFuncs.version & 0xFF;

-  NPError rv = NPERR_NO_ERROR;

-

-  if (navMinorVers >= NPVERS_HAS_NOTIFICATION) {

-    rv = NPNFuncs.geturlnotify(instance, url, target, notifyData);

-  } else {

-    rv = NPERR_INCOMPATIBLE_VERSION_ERROR;

-  }

-

-  return rv;

-}

-

-NPError NPN_GetURL(NPP instance, const char *url, const char *target) {

-  NPError rv = NPNFuncs.geturl(instance, url, target);

-  return rv;

-}

-

-NPError NPN_PostURLNotify(NPP instance,

-                          const char* url,

-                          const char* window,

-                          uint32 len,

-                          const char* buf,

-                          NPBool file,

-                          void* notifyData) {

-  int navMinorVers = NPNFuncs.version & 0xFF;

-  NPError rv = NPERR_NO_ERROR;

-

-  if (navMinorVers >= NPVERS_HAS_NOTIFICATION) {

-    rv = NPNFuncs.posturlnotify(instance,

-                                url,

-                                window,

-                                len,

-                                buf,

-                                file,

-                                notifyData);

-  } else {

-    rv = NPERR_INCOMPATIBLE_VERSION_ERROR;

-  }

-

-  return rv;

-}

-

-NPError NPN_PostURL(NPP instance,

-                    const char* url,

-                    const char* window,

-                    uint32 len,

-                    const char* buf,

-                    NPBool file) {

-  NPError rv = NPNFuncs.posturl(instance, url, window, len, buf, file);

-  return rv;

-}

-

-NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList) {

-  NPError rv = NPNFuncs.requestread(stream, rangeList);

-  return rv;

-}

-

-NPError NPN_NewStream(NPP instance,

-                      NPMIMEType type,

-                      const char* target,

-                      NPStream** stream) {

-  int navMinorVersion = NPNFuncs.version & 0xFF;

-

-  NPError rv = NPERR_NO_ERROR;

-

-  if (navMinorVersion >= NPVERS_HAS_STREAMOUTPUT) {

-    rv = NPNFuncs.newstream(instance, type, target, stream);

-  } else {

-    rv = NPERR_INCOMPATIBLE_VERSION_ERROR;

-  }

-

-  return rv;

-}

-

-int32 NPN_Write(NPP instance, NPStream *stream, int32 len, void *buffer) {

-  int navMinorVersion = NPNFuncs.version & 0xFF;

-  int32 rv = 0;

-

-  if (navMinorVersion >= NPVERS_HAS_STREAMOUTPUT) {

-    rv = NPNFuncs.write(instance, stream, len, buffer);

-  } else {

-    rv = -1;

-  }

-

-  return rv;

-}

-

-NPError NPN_DestroyStream(NPP instance, NPStream* stream, NPError reason) {

-  int navMinorVersion = NPNFuncs.version & 0xFF;

-  NPError rv = NPERR_NO_ERROR;

-

-  if (navMinorVersion >= NPVERS_HAS_STREAMOUTPUT) {

-    rv = NPNFuncs.destroystream(instance, stream, reason);

-  } else {

-    rv = NPERR_INCOMPATIBLE_VERSION_ERROR;

-  }

-

-  return rv;

-}

-

-void NPN_Status(NPP instance, const char *message) {

-  NPNFuncs.status(instance, message);

-}

-

-const char* NPN_UserAgent(NPP instance) {

-  const char * rv = NULL;

-  rv = NPNFuncs.uagent(instance);

-  return rv;

-}

-

-void* NPN_MemAlloc(uint32 size) {

-  void * rv = NULL;

-  rv = NPNFuncs.memalloc(size);

-  return rv;

-}

-

-void NPN_MemFree(void* ptr) {

-  NPNFuncs.memfree(ptr);

-}

-

-uint32 NPN_MemFlush(uint32 size) {

-  uint32 rv = NPNFuncs.memflush(size);

-  return rv;

-}

-

-void NPN_ReloadPlugins(NPBool reloadPages) {

-  NPNFuncs.reloadplugins(reloadPages);

-}

-

-JRIEnv* NPN_GetJavaEnv(void) {

-  JRIEnv * rv = NULL;

-  rv = NPNFuncs.getJavaEnv();

-  return rv;

-}

-

-jref NPN_GetJavaPeer(NPP instance) {

-  jref rv;

-  rv = NPNFuncs.getJavaPeer(instance);

-  return rv;

-}

-

-NPError NPN_GetValue(NPP instance, NPNVariable variable, void *value) {

-  NPError rv = NPNFuncs.getvalue(instance, variable, value);

-  return rv;

-}

-

-NPError NPN_SetValue(NPP instance, NPPVariable variable, void *value) {

-  NPError rv = NPNFuncs.setvalue(instance, variable, value);

-  return rv;

-}

-

-void NPN_InvalidateRect(NPP instance, NPRect *invalidRect) {

-  NPNFuncs.invalidaterect(instance, invalidRect);

-}

-

-void NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion) {

-  NPNFuncs.invalidateregion(instance, invalidRegion);

-}

-

-void NPN_ForceRedraw(NPP instance) {

-  NPNFuncs.forceredraw(instance);

-}

-

-NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name) {

-  return NPNFuncs.getstringidentifier(name);

-}

-

-void NPN_GetStringIdentifiers(const NPUTF8 **names,

-                              uint32_t nameCount,

-                              NPIdentifier *identifiers) {

-  return NPNFuncs.getstringidentifiers(names, nameCount, identifiers);

-}

-

-NPIdentifier NPN_GetStringIdentifier(int32_t intid) {

-  return NPNFuncs.getintidentifier(intid);

-}

-

-bool NPN_IdentifierIsString(NPIdentifier identifier) {

-  return NPNFuncs.identifierisstring(identifier);

-}

-

-NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier) {

-  return NPNFuncs.utf8fromidentifier(identifier);

-}

-

-int32_t NPN_IntFromIdentifier(NPIdentifier identifier) {

-  return NPNFuncs.intfromidentifier(identifier);

-}

-

-NPObject *NPN_CreateObject(NPP npp, NPClass *aClass) {

-  return NPNFuncs.createobject(npp, aClass);

-}

-

-NPObject *NPN_RetainObject(NPObject *obj) {

-  return NPNFuncs.retainobject(obj);

-}

-

-void NPN_ReleaseObject(NPObject *obj) {

-  return NPNFuncs.releaseobject(obj);

-}

-

-bool NPN_Invoke(NPP npp,

-                NPObject* obj,

-                NPIdentifier methodName,

-                const NPVariant *args,

-                uint32_t argCount,

-                NPVariant *result) {

-  return NPNFuncs.invoke(npp, obj, methodName, args, argCount, result);

-}

-

-bool NPN_InvokeDefault(NPP npp,

-                       NPObject* obj,

-                       const NPVariant *args,

-                       uint32_t argCount,

-                       NPVariant *result) {

-  return NPNFuncs.invokeDefault(npp, obj, args, argCount, result);

-}

-

-bool NPN_Evaluate(NPP npp,

-                  NPObject* obj,

-                  NPString *script,

-                  NPVariant *result) {

-  return NPNFuncs.evaluate(npp, obj, script, result);

-}

-

-bool NPN_GetProperty(NPP npp,

-                     NPObject* obj,

-                     NPIdentifier propertyName,

-                     NPVariant *result) {

-  return NPNFuncs.getproperty(npp, obj, propertyName, result);

-}

-

-bool NPN_SetProperty(NPP npp,

-                     NPObject* obj,

-                     NPIdentifier propertyName,

-                     const NPVariant *value) {

-  return NPNFuncs.setproperty(npp, obj, propertyName, value);

-}

-

-bool NPN_RemoveProperty(NPP npp,

-                        NPObject* obj,

-                        NPIdentifier propertyName) {

-  return NPNFuncs.removeproperty(npp, obj, propertyName);

-}

-

-bool NPN_HasProperty(NPP npp,

-                     NPObject* obj,

-                     NPIdentifier propertyName) {

-  return NPNFuncs.hasproperty(npp, obj, propertyName);

-}

-

-bool NPN_HasMethod(NPP npp,

-                   NPObject* obj,

-                   NPIdentifier methodName) {

-  return NPNFuncs.hasmethod(npp, obj, methodName);

-}

-

-void NPN_ReleaseVariantValue(NPVariant *variant) {

-  NPNFuncs.releasevariantvalue(variant);

-}

-

-void NPN_SetException(NPObject* obj, const NPUTF8 *message) {

-  NPNFuncs.setexception(obj, message);

-}

-

+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+////////////////////////////////////////////////////////////
+//
+// Implementation of Netscape entry points (NPN_*)
+//
+
+#pragma warning(push)
+#pragma warning(disable: 4201)  // c4201: nonstandard extension used
+                                //        nameless struct/union
+
+#include "omaha/third_party/gecko/include/npapi.h"
+#include "omaha/third_party/gecko/include/npupp.h"
+
+#pragma warning(pop)
+
+#ifndef HIBYTE
+#define HIBYTE(x) (((static_cast<uint32>(x)) & 0xff00) >> 8)
+#endif
+
+#ifndef LOBYTE
+#define LOBYTE(W) ((W) & 0xFF)
+#endif
+
+extern NPNetscapeFuncs NPNFuncs;
+
+void NPN_Version(int* plugin_major,
+                 int* plugin_minor,
+                 int* netscape_major,
+                 int* netscape_minor) {
+  *plugin_major   = NP_VERSION_MAJOR;
+  *plugin_minor   = NP_VERSION_MINOR;
+  *netscape_major = HIBYTE(NPNFuncs.version);
+  *netscape_minor = LOBYTE(NPNFuncs.version);
+}
+
+NPError NPN_GetURLNotify(NPP instance,
+                         const char *url,
+                         const char *target,
+                         void* notifyData) {
+  int navMinorVers = NPNFuncs.version & 0xFF;
+  NPError rv = NPERR_NO_ERROR;
+
+  if (navMinorVers >= NPVERS_HAS_NOTIFICATION) {
+    rv = NPNFuncs.geturlnotify(instance, url, target, notifyData);
+  } else {
+    rv = NPERR_INCOMPATIBLE_VERSION_ERROR;
+  }
+
+  return rv;
+}
+
+NPError NPN_GetURL(NPP instance, const char *url, const char *target) {
+  NPError rv = NPNFuncs.geturl(instance, url, target);
+  return rv;
+}
+
+NPError NPN_PostURLNotify(NPP instance,
+                          const char* url,
+                          const char* window,
+                          uint32 len,
+                          const char* buf,
+                          NPBool file,
+                          void* notifyData) {
+  int navMinorVers = NPNFuncs.version & 0xFF;
+  NPError rv = NPERR_NO_ERROR;
+
+  if (navMinorVers >= NPVERS_HAS_NOTIFICATION) {
+    rv = NPNFuncs.posturlnotify(instance,
+                                url,
+                                window,
+                                len,
+                                buf,
+                                file,
+                                notifyData);
+  } else {
+    rv = NPERR_INCOMPATIBLE_VERSION_ERROR;
+  }
+
+  return rv;
+}
+
+NPError NPN_PostURL(NPP instance,
+                    const char* url,
+                    const char* window,
+                    uint32 len,
+                    const char* buf,
+                    NPBool file) {
+  NPError rv = NPNFuncs.posturl(instance, url, window, len, buf, file);
+  return rv;
+}
+
+NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList) {
+  NPError rv = NPNFuncs.requestread(stream, rangeList);
+  return rv;
+}
+
+NPError NPN_NewStream(NPP instance,
+                      NPMIMEType type,
+                      const char* target,
+                      NPStream** stream) {
+  int navMinorVersion = NPNFuncs.version & 0xFF;
+
+  NPError rv = NPERR_NO_ERROR;
+
+  if (navMinorVersion >= NPVERS_HAS_STREAMOUTPUT) {
+    rv = NPNFuncs.newstream(instance, type, target, stream);
+  } else {
+    rv = NPERR_INCOMPATIBLE_VERSION_ERROR;
+  }
+
+  return rv;
+}
+
+int32 NPN_Write(NPP instance, NPStream *stream, int32 len, void *buffer) {
+  int navMinorVersion = NPNFuncs.version & 0xFF;
+  int32 rv = 0;
+
+  if (navMinorVersion >= NPVERS_HAS_STREAMOUTPUT) {
+    rv = NPNFuncs.write(instance, stream, len, buffer);
+  } else {
+    rv = -1;
+  }
+
+  return rv;
+}
+
+NPError NPN_DestroyStream(NPP instance, NPStream* stream, NPError reason) {
+  int navMinorVersion = NPNFuncs.version & 0xFF;
+  NPError rv = NPERR_NO_ERROR;
+
+  if (navMinorVersion >= NPVERS_HAS_STREAMOUTPUT) {
+    rv = NPNFuncs.destroystream(instance, stream, reason);
+  } else {
+    rv = NPERR_INCOMPATIBLE_VERSION_ERROR;
+  }
+
+  return rv;
+}
+
+void NPN_Status(NPP instance, const char *message) {
+  NPNFuncs.status(instance, message);
+}
+
+const char* NPN_UserAgent(NPP instance) {
+  const char * rv = NULL;
+  rv = NPNFuncs.uagent(instance);
+  return rv;
+}
+
+void* NPN_MemAlloc(uint32 size) {
+  void * rv = NULL;
+  rv = NPNFuncs.memalloc(size);
+  return rv;
+}
+
+void NPN_MemFree(void* ptr) {
+  NPNFuncs.memfree(ptr);
+}
+
+uint32 NPN_MemFlush(uint32 size) {
+  uint32 rv = NPNFuncs.memflush(size);
+  return rv;
+}
+
+void NPN_ReloadPlugins(NPBool reloadPages) {
+  NPNFuncs.reloadplugins(reloadPages);
+}
+
+JRIEnv* NPN_GetJavaEnv(void) {
+  JRIEnv * rv = NULL;
+  rv = NPNFuncs.getJavaEnv();
+  return rv;
+}
+
+jref NPN_GetJavaPeer(NPP instance) {
+  jref rv;
+  rv = NPNFuncs.getJavaPeer(instance);
+  return rv;
+}
+
+NPError NPN_GetValue(NPP instance, NPNVariable variable, void *value) {
+  NPError rv = NPNFuncs.getvalue(instance, variable, value);
+  return rv;
+}
+
+NPError NPN_SetValue(NPP instance, NPPVariable variable, void *value) {
+  NPError rv = NPNFuncs.setvalue(instance, variable, value);
+  return rv;
+}
+
+void NPN_InvalidateRect(NPP instance, NPRect *invalidRect) {
+  NPNFuncs.invalidaterect(instance, invalidRect);
+}
+
+void NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion) {
+  NPNFuncs.invalidateregion(instance, invalidRegion);
+}
+
+void NPN_ForceRedraw(NPP instance) {
+  NPNFuncs.forceredraw(instance);
+}
+
+NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name) {
+  return NPNFuncs.getstringidentifier(name);
+}
+
+void NPN_GetStringIdentifiers(const NPUTF8 **names,
+                              uint32_t nameCount,
+                              NPIdentifier *identifiers) {
+  return NPNFuncs.getstringidentifiers(names, nameCount, identifiers);
+}
+
+NPIdentifier NPN_GetStringIdentifier(int32_t intid) {
+  return NPNFuncs.getintidentifier(intid);
+}
+
+bool NPN_IdentifierIsString(NPIdentifier identifier) {
+  return NPNFuncs.identifierisstring(identifier);
+}
+
+NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier) {
+  return NPNFuncs.utf8fromidentifier(identifier);
+}
+
+int32_t NPN_IntFromIdentifier(NPIdentifier identifier) {
+  return NPNFuncs.intfromidentifier(identifier);
+}
+
+NPObject *NPN_CreateObject(NPP npp, NPClass *aClass) {
+  return NPNFuncs.createobject(npp, aClass);
+}
+
+NPObject *NPN_RetainObject(NPObject *obj) {
+  return NPNFuncs.retainobject(obj);
+}
+
+void NPN_ReleaseObject(NPObject *obj) {
+  return NPNFuncs.releaseobject(obj);
+}
+
+bool NPN_Invoke(NPP npp,
+                NPObject* obj,
+                NPIdentifier methodName,
+                const NPVariant *args,
+                uint32_t argCount,
+                NPVariant *result) {
+  return NPNFuncs.invoke(npp, obj, methodName, args, argCount, result);
+}
+
+bool NPN_InvokeDefault(NPP npp,
+                       NPObject* obj,
+                       const NPVariant *args,
+                       uint32_t argCount,
+                       NPVariant *result) {
+  return NPNFuncs.invokeDefault(npp, obj, args, argCount, result);
+}
+
+bool NPN_Evaluate(NPP npp,
+                  NPObject* obj,
+                  NPString *script,
+                  NPVariant *result) {
+  return NPNFuncs.evaluate(npp, obj, script, result);
+}
+
+bool NPN_GetProperty(NPP npp,
+                     NPObject* obj,
+                     NPIdentifier propertyName,
+                     NPVariant *result) {
+  return NPNFuncs.getproperty(npp, obj, propertyName, result);
+}
+
+bool NPN_SetProperty(NPP npp,
+                     NPObject* obj,
+                     NPIdentifier propertyName,
+                     const NPVariant *value) {
+  return NPNFuncs.setproperty(npp, obj, propertyName, value);
+}
+
+bool NPN_RemoveProperty(NPP npp,
+                        NPObject* obj,
+                        NPIdentifier propertyName) {
+  return NPNFuncs.removeproperty(npp, obj, propertyName);
+}
+
+bool NPN_HasProperty(NPP npp,
+                     NPObject* obj,
+                     NPIdentifier propertyName) {
+  return NPNFuncs.hasproperty(npp, obj, propertyName);
+}
+
+bool NPN_HasMethod(NPP npp,
+                   NPObject* obj,
+                   NPIdentifier methodName) {
+  return NPNFuncs.hasmethod(npp, obj, methodName);
+}
+
+void NPN_ReleaseVariantValue(NPVariant *variant) {
+  NPNFuncs.releasevariantvalue(variant);
+}
+
+void NPN_SetException(NPObject* obj, const NPUTF8 *message) {
+  NPNFuncs.setexception(obj, message);
+}
+
diff --git a/plugins/npp_gate.cc b/plugins/npp_gate.cc
index 8ab5f23..2c377f1 100644
--- a/plugins/npp_gate.cc
+++ b/plugins/npp_gate.cc
@@ -1,300 +1,300 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

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

-//

-// Implementation of plugin entry points (NPP_*)

-// most are just empty stubs for this particular plugin

-//

-#include "plugins/baseplugin.h"

-#include "common/const_config.h"

-

-#pragma warning(push)

-#pragma warning(disable: 4100 4061)

-// 4100: unreferenced formal parameter

-// 4061: enumerator 'x' in switch of enum 'y'

-//       is not explicitly handled by a case label

-

-

-char* NPP_GetMIMEDescription() {

-  return kOneClickPluginMimeDescriptionAnsi;

-}

-

-NPError NPP_Initialize() {

-  return NPERR_NO_ERROR;

-}

-

-void NPP_Shutdown() {

-}

-

-// here the plugin creates an instance of our CPlugin object which

-// will be associated with this newly created plugin instance and

-// will do all the neccessary job

-NPError NPP_New(NPMIMEType plugin_type,

-                NPP instance,

-                uint16 mode,

-                int16 argc,

-                char* argn[],

-                char* argv[],

-                NPSavedData* saved) {

-  if (instance == NULL) {

-    return NPERR_INVALID_INSTANCE_ERROR;

-  }

-

-  NPError rv = NPERR_NO_ERROR;

-

-  CPlugin* plugin = new CPlugin(instance);

-  if (plugin == NULL) {

-    return NPERR_OUT_OF_MEMORY_ERROR;

-  }

-

-  instance->pdata = reinterpret_cast<void*>(plugin);

-  return rv;

-}

-

-// here is the place to clean up and destroy the CPlugin object

-NPError NPP_Destroy(NPP instance, NPSavedData** save) {

-  if (instance == NULL) {

-    return NPERR_INVALID_INSTANCE_ERROR;

-  }

-

-  NPError rv = NPERR_NO_ERROR;

-

-  CPlugin* plugin = reinterpret_cast<CPlugin*>(instance->pdata);

-  if (plugin != NULL) {

-    plugin->shut();

-    delete plugin;

-  }

-  return rv;

-}

-

-// during this call we know when the plugin window is ready or

-// is about to be destroyed so we can do some gui specific

-// initialization and shutdown

-NPError NPP_SetWindow(NPP instance, NPWindow* np_window) {

-  if (instance == NULL) {

-    return NPERR_INVALID_INSTANCE_ERROR;

-  }

-

-  NPError rv = NPERR_NO_ERROR;

-

-  if (np_window == NULL) {

-    return NPERR_GENERIC_ERROR;

-  }

-

-  CPlugin* plugin = reinterpret_cast<CPlugin*>(instance->pdata);

-

-  if (plugin == NULL) {

-    return NPERR_GENERIC_ERROR;

-  }

-

-  // window just created

-  if (!plugin->isInitialized() && (np_window->window != NULL)) {

-    if (!plugin->init(np_window)) {

-      delete plugin;

-      plugin = NULL;

-      instance->pdata = NULL;

-      return NPERR_MODULE_LOAD_FAILED_ERROR;

-    }

-  }

-

-  // window goes away

-  if ((np_window->window == NULL) && plugin->isInitialized()) {

-    return NPERR_NO_ERROR;

-  }

-

-  // window resized

-  if (plugin->isInitialized() && (np_window->window != NULL)) {

-    return NPERR_NO_ERROR;

-  }

-

-  // this should not happen, nothing to do

-  if ((np_window->window == NULL) && !plugin->isInitialized()) {

-    return NPERR_NO_ERROR;

-  }

-

-  return rv;

-}

-

-// ==============================

-// ! Scriptability related code !

-// ==============================

-//

-// here the plugin is asked by Mozilla to tell if it is scriptable

-// we should return a valid interface id and a pointer to

-// nsScriptablePeer interface which we should have implemented

-// and which should be defined in the corressponding *.xpt file

-// in the bin/components folder

-NPError NPP_GetValue(NPP instance, NPPVariable variable, void* value) {

-  if (instance == NULL) {

-    return NPERR_INVALID_INSTANCE_ERROR;

-  }

-

-  NPError rv = NPERR_NO_ERROR;

-

-  if (instance == NULL) {

-    return NPERR_GENERIC_ERROR;

-  }

-

-  CPlugin* plugin = reinterpret_cast<CPlugin*>(instance->pdata);

-  if (plugin == NULL) {

-    return NPERR_GENERIC_ERROR;

-  }

-

-  switch (variable) {

-  case NPPVpluginNameString:

-    *(reinterpret_cast<char**>(value)) = "NPRuntimeTest";

-    break;

-  case NPPVpluginDescriptionString:

-    *(reinterpret_cast<char**>(value)) =

-        "NPRuntime scriptability API test plugin";

-    break;

-  case NPPVpluginScriptableNPObject:

-    *(reinterpret_cast<NPObject**>(value)) = plugin->GetScriptableObject();

-    break;

-  default:

-    rv = NPERR_GENERIC_ERROR;

-    break;

-  }

-

-  return rv;

-}

-

-NPError NPP_NewStream(NPP instance,

-                      NPMIMEType type,

-                      NPStream* stream,

-                      NPBool seekable,

-                      uint16* stype) {

-  if (instance == NULL) {

-    return NPERR_INVALID_INSTANCE_ERROR;

-  }

-

-  NPError rv = NPERR_NO_ERROR;

-  return rv;

-}

-

-int32 NPP_WriteReady(NPP instance, NPStream* stream) {

-  if (instance == NULL) {

-    return NPERR_INVALID_INSTANCE_ERROR;

-  }

-

-  int32 rv = 0x0fffffff;

-  return rv;

-}

-

-int32 NPP_Write(NPP instance,

-                NPStream* stream,

-                int32 offset,

-                int32 len,

-                void* buffer) {

-  if (instance == NULL) {

-    return NPERR_INVALID_INSTANCE_ERROR;

-  }

-

-  int32 rv = len;

-  return rv;

-}

-

-NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPError reason) {

-  if (instance == NULL) {

-    return NPERR_INVALID_INSTANCE_ERROR;

-  }

-

-  NPError rv = NPERR_NO_ERROR;

-  return rv;

-}

-

-void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) {

-  if (instance == NULL) {

-    return;

-  }

-}

-

-void NPP_Print(NPP instance, NPPrint* print_info) {

-  if (instance == NULL) {

-    return;

-  }

-}

-

-void NPP_URLNotify(NPP instance,

-                   const char* url,

-                   NPReason reason,

-                   void* notify_data) {

-  if (instance == NULL) {

-    return;

-  }

-}

-

-NPError NPP_SetValue(NPP instance, NPNVariable variable, void* value) {

-  if (instance == NULL) {

-    return NPERR_INVALID_INSTANCE_ERROR;

-  }

-

-  NPError rv = NPERR_NO_ERROR;

-  return rv;

-}

-

-int16 NPP_HandleEvent(NPP instance, void* event) {

-  if (instance == NULL) {

-    return 0;

-  }

-

-  int16 rv = 0;

-  CPlugin* plugin = reinterpret_cast<CPlugin*>(instance->pdata);

-  if (plugin) {

-    rv = plugin->handleEvent(event);

-  }

-

-  return rv;

-}

-

-NPObject* NPP_GetScriptableInstance(NPP instance) {

-  if (!instance) {

-    return 0;

-  }

-

-  NPObject *npobj = 0;

-  CPlugin* plugin = reinterpret_cast<CPlugin*>(instance->pdata);

-  if (!plugin) {

-    npobj = plugin->GetScriptableObject();

-  }

-

-  return npobj;

-}

-

-#pragma warning(pop)

-

+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+////////////////////////////////////////////////////////////
+//
+// Implementation of plugin entry points (NPP_*)
+// most are just empty stubs for this particular plugin
+//
+#include "plugins/baseplugin.h"
+#include "common/const_config.h"
+
+#pragma warning(push)
+#pragma warning(disable: 4100 4061)
+// 4100: unreferenced formal parameter
+// 4061: enumerator 'x' in switch of enum 'y'
+//       is not explicitly handled by a case label
+
+
+char* NPP_GetMIMEDescription() {
+  return kOneClickPluginMimeDescriptionAnsi;
+}
+
+NPError NPP_Initialize() {
+  return NPERR_NO_ERROR;
+}
+
+void NPP_Shutdown() {
+}
+
+// here the plugin creates an instance of our CPlugin object which
+// will be associated with this newly created plugin instance and
+// will do all the neccessary job
+NPError NPP_New(NPMIMEType plugin_type,
+                NPP instance,
+                uint16 mode,
+                int16 argc,
+                char* argn[],
+                char* argv[],
+                NPSavedData* saved) {
+  if (instance == NULL) {
+    return NPERR_INVALID_INSTANCE_ERROR;
+  }
+
+  NPError rv = NPERR_NO_ERROR;
+
+  CPlugin* plugin = new CPlugin(instance);
+  if (plugin == NULL) {
+    return NPERR_OUT_OF_MEMORY_ERROR;
+  }
+
+  instance->pdata = reinterpret_cast<void*>(plugin);
+  return rv;
+}
+
+// here is the place to clean up and destroy the CPlugin object
+NPError NPP_Destroy(NPP instance, NPSavedData** save) {
+  if (instance == NULL) {
+    return NPERR_INVALID_INSTANCE_ERROR;
+  }
+
+  NPError rv = NPERR_NO_ERROR;
+
+  CPlugin* plugin = reinterpret_cast<CPlugin*>(instance->pdata);
+  if (plugin != NULL) {
+    plugin->shut();
+    delete plugin;
+  }
+  return rv;
+}
+
+// during this call we know when the plugin window is ready or
+// is about to be destroyed so we can do some gui specific
+// initialization and shutdown
+NPError NPP_SetWindow(NPP instance, NPWindow* np_window) {
+  if (instance == NULL) {
+    return NPERR_INVALID_INSTANCE_ERROR;
+  }
+
+  NPError rv = NPERR_NO_ERROR;
+
+  if (np_window == NULL) {
+    return NPERR_GENERIC_ERROR;
+  }
+
+  CPlugin* plugin = reinterpret_cast<CPlugin*>(instance->pdata);
+
+  if (plugin == NULL) {
+    return NPERR_GENERIC_ERROR;
+  }
+
+  // window just created
+  if (!plugin->isInitialized() && (np_window->window != NULL)) {
+    if (!plugin->init(np_window)) {
+      delete plugin;
+      plugin = NULL;
+      instance->pdata = NULL;
+      return NPERR_MODULE_LOAD_FAILED_ERROR;
+    }
+  }
+
+  // window goes away
+  if ((np_window->window == NULL) && plugin->isInitialized()) {
+    return NPERR_NO_ERROR;
+  }
+
+  // window resized
+  if (plugin->isInitialized() && (np_window->window != NULL)) {
+    return NPERR_NO_ERROR;
+  }
+
+  // this should not happen, nothing to do
+  if ((np_window->window == NULL) && !plugin->isInitialized()) {
+    return NPERR_NO_ERROR;
+  }
+
+  return rv;
+}
+
+// ==============================
+// ! Scriptability related code !
+// ==============================
+//
+// here the plugin is asked by Mozilla to tell if it is scriptable
+// we should return a valid interface id and a pointer to
+// nsScriptablePeer interface which we should have implemented
+// and which should be defined in the corressponding *.xpt file
+// in the bin/components folder
+NPError NPP_GetValue(NPP instance, NPPVariable variable, void* value) {
+  if (instance == NULL) {
+    return NPERR_INVALID_INSTANCE_ERROR;
+  }
+
+  NPError rv = NPERR_NO_ERROR;
+
+  if (instance == NULL) {
+    return NPERR_GENERIC_ERROR;
+  }
+
+  CPlugin* plugin = reinterpret_cast<CPlugin*>(instance->pdata);
+  if (plugin == NULL) {
+    return NPERR_GENERIC_ERROR;
+  }
+
+  switch (variable) {
+  case NPPVpluginNameString:
+    *(reinterpret_cast<char**>(value)) = "NPRuntimeTest";
+    break;
+  case NPPVpluginDescriptionString:
+    *(reinterpret_cast<char**>(value)) =
+        "NPRuntime scriptability API test plugin";
+    break;
+  case NPPVpluginScriptableNPObject:
+    *(reinterpret_cast<NPObject**>(value)) = plugin->GetScriptableObject();
+    break;
+  default:
+    rv = NPERR_GENERIC_ERROR;
+    break;
+  }
+
+  return rv;
+}
+
+NPError NPP_NewStream(NPP instance,
+                      NPMIMEType type,
+                      NPStream* stream,
+                      NPBool seekable,
+                      uint16* stype) {
+  if (instance == NULL) {
+    return NPERR_INVALID_INSTANCE_ERROR;
+  }
+
+  NPError rv = NPERR_NO_ERROR;
+  return rv;
+}
+
+int32 NPP_WriteReady(NPP instance, NPStream* stream) {
+  if (instance == NULL) {
+    return NPERR_INVALID_INSTANCE_ERROR;
+  }
+
+  int32 rv = 0x0fffffff;
+  return rv;
+}
+
+int32 NPP_Write(NPP instance,
+                NPStream* stream,
+                int32 offset,
+                int32 len,
+                void* buffer) {
+  if (instance == NULL) {
+    return NPERR_INVALID_INSTANCE_ERROR;
+  }
+
+  int32 rv = len;
+  return rv;
+}
+
+NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPError reason) {
+  if (instance == NULL) {
+    return NPERR_INVALID_INSTANCE_ERROR;
+  }
+
+  NPError rv = NPERR_NO_ERROR;
+  return rv;
+}
+
+void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) {
+  if (instance == NULL) {
+    return;
+  }
+}
+
+void NPP_Print(NPP instance, NPPrint* print_info) {
+  if (instance == NULL) {
+    return;
+  }
+}
+
+void NPP_URLNotify(NPP instance,
+                   const char* url,
+                   NPReason reason,
+                   void* notify_data) {
+  if (instance == NULL) {
+    return;
+  }
+}
+
+NPError NPP_SetValue(NPP instance, NPNVariable variable, void* value) {
+  if (instance == NULL) {
+    return NPERR_INVALID_INSTANCE_ERROR;
+  }
+
+  NPError rv = NPERR_NO_ERROR;
+  return rv;
+}
+
+int16 NPP_HandleEvent(NPP instance, void* event) {
+  if (instance == NULL) {
+    return 0;
+  }
+
+  int16 rv = 0;
+  CPlugin* plugin = reinterpret_cast<CPlugin*>(instance->pdata);
+  if (plugin) {
+    rv = plugin->handleEvent(event);
+  }
+
+  return rv;
+}
+
+NPObject* NPP_GetScriptableInstance(NPP instance) {
+  if (!instance) {
+    return 0;
+  }
+
+  NPObject *npobj = 0;
+  CPlugin* plugin = reinterpret_cast<CPlugin*>(instance->pdata);
+  if (!plugin) {
+    npobj = plugin->GetScriptableObject();
+  }
+
+  return npobj;
+}
+
+#pragma warning(pop)
+
diff --git a/plugins/oneclick.cc b/plugins/oneclick.cc
index f2f98f5..9649521 100644
--- a/plugins/oneclick.cc
+++ b/plugins/oneclick.cc
@@ -1,148 +1,148 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Implementation of the OneClick Plugin.

-

-#include "omaha/plugins/oneclick.h"

-

-#include <atlsafe.h>

-

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/string.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/plugins/oneclick_browser_callback_activex.h"

-

-namespace omaha {

-

-GoopdateCtrl::GoopdateCtrl() : is_worker_url_set_(false) {

-  CORE_LOG(L2, (_T("[GoopdateCtrl::GoopdateCtrl]")));

-}

-

-GoopdateCtrl::~GoopdateCtrl() {

-  CORE_LOG(L2, (_T("[GoopdateCtrl::~GoopdateCtrl]")));

-}

-

-void GoopdateCtrl::EnsureWorkerUrlSet() {

-  if (is_worker_url_set_) {

-    return;

-  }

-

-  CComBSTR browser_url_bstr;

-  if (!GetOurUrl(&browser_url_bstr)) {

-    ASSERT(false, (_T("[SetSite] failed GetOurUrl() call")));

-    return;

-  }

-

-  CORE_LOG(L2, (_T("[EnsureWorkerUrlSet][url=%s]"), browser_url_bstr));

-  oneclick_worker_->set_browser_url(browser_url_bstr);

-  is_worker_url_set_ = true;

-}

-

-STDMETHODIMP GoopdateCtrl::Install(BSTR cmd_line_args,

-                                   VARIANT* success_callback,

-                                   VARIANT* failure_callback) {

-  EnsureWorkerUrlSet();

-  ASSERT1(cmd_line_args && cmd_line_args[0]);

-

-  if (!cmd_line_args || !cmd_line_args[0]) {

-    return E_INVALIDARG;

-  }

-

-  CORE_LOG(L2, (_T("[GoopdateCtrl::Install][cmd_line \"%s\"]"),

-                CW2CT(cmd_line_args)));

-

-  OneClickBrowserCallbackActiveX browser_callback;

-  HRESULT hr = browser_callback.Initialize(success_callback, failure_callback);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString cmd_line_args_str(cmd_line_args);

-  hr = oneclick_worker_->DoOneClickInstall(cmd_line_args_str,

-                                           &browser_callback);

-

-  return hr;

-}

-

-STDMETHODIMP GoopdateCtrl::Install2(BSTR extra_args) {

-  EnsureWorkerUrlSet();

-  ASSERT1(extra_args && extra_args[0]);

-

-  if (!extra_args || !extra_args[0]) {

-    return E_INVALIDARG;

-  }

-

-  CORE_LOG(L2, (_T("[GoopdateCtrl::Install2][extra_args \"%s\"]"),

-                CW2CT(extra_args)));

-

-  CString extra_args_str(extra_args);

-  return oneclick_worker_->DoOneClickInstall2(extra_args_str);

-}

-

-STDMETHODIMP GoopdateCtrl::GetInstalledVersion(BSTR guid_string,

-                                               VARIANT_BOOL is_machine,

-                                               BSTR* version_string) {

-  CORE_LOG(L2, (_T("[GoopdateCtrl::GetInstalledVersion][%s][%d]"),

-                guid_string, is_machine));

-  EnsureWorkerUrlSet();

-

-  if (!version_string) {

-    return E_POINTER;

-  }

-  *version_string = NULL;

-

-  CString version;

-  HRESULT hr = oneclick_worker_->GetInstalledVersion(guid_string,

-                                                     is_machine == VARIANT_TRUE,

-                                                     &version);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  *version_string = version.AllocSysString();

-  return S_OK;

-}

-

-STDMETHODIMP GoopdateCtrl::GetOneClickVersion(long* version) {

-  CORE_LOG(L2, (_T("[GoopdateCtrl::GetOneClickVersion]")));

-  EnsureWorkerUrlSet();

-

-  return oneclick_worker_->GetOneClickVersion(version);

-}

-

-HRESULT GoopdateCtrl::FinalConstruct() {

-  CORE_LOG(L2, (_T("[GoopdateCtrl::FinalConstruct]")));

-  oneclick_worker_.reset(new OneClickWorker());

-  return oneclick_worker_->Initialize();

-}

-

-void GoopdateCtrl::FinalRelease() {

-  CORE_LOG(L2, (_T("[GoopdateCtrl::FinalRelease]")));

-}

-

-CString GoopdateCtrl::GetGoopdateShellPathForRegMap() {

-  return goopdate_utils::BuildGoogleUpdateExeDir(

-      goopdate_utils::IsRunningFromOfficialGoopdateDir(true));

-}

-

-OBJECT_ENTRY_AUTO(__uuidof(GoopdateOneClickControl), GoopdateCtrl)

-

-}  // namespace omaha

-

-// 4505: unreferenced local function has been removed

-#pragma warning(disable : 4505)

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Implementation of the OneClick Plugin.
+
+#include "omaha/plugins/oneclick.h"
+
+#include <atlsafe.h>
+
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/string.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/plugins/oneclick_browser_callback_activex.h"
+
+namespace omaha {
+
+GoopdateCtrl::GoopdateCtrl() : is_worker_url_set_(false) {
+  CORE_LOG(L2, (_T("[GoopdateCtrl::GoopdateCtrl]")));
+}
+
+GoopdateCtrl::~GoopdateCtrl() {
+  CORE_LOG(L2, (_T("[GoopdateCtrl::~GoopdateCtrl]")));
+}
+
+void GoopdateCtrl::EnsureWorkerUrlSet() {
+  if (is_worker_url_set_) {
+    return;
+  }
+
+  CComBSTR browser_url_bstr;
+  if (!GetOurUrl(&browser_url_bstr)) {
+    ASSERT(false, (_T("[SetSite] failed GetOurUrl() call")));
+    return;
+  }
+
+  CORE_LOG(L2, (_T("[EnsureWorkerUrlSet][url=%s]"), browser_url_bstr));
+  oneclick_worker_->set_browser_url(browser_url_bstr);
+  is_worker_url_set_ = true;
+}
+
+STDMETHODIMP GoopdateCtrl::Install(BSTR cmd_line_args,
+                                   VARIANT* success_callback,
+                                   VARIANT* failure_callback) {
+  EnsureWorkerUrlSet();
+  ASSERT1(cmd_line_args && cmd_line_args[0]);
+
+  if (!cmd_line_args || !cmd_line_args[0]) {
+    return E_INVALIDARG;
+  }
+
+  CORE_LOG(L2, (_T("[GoopdateCtrl::Install][cmd_line \"%s\"]"),
+                CW2CT(cmd_line_args)));
+
+  OneClickBrowserCallbackActiveX browser_callback;
+  HRESULT hr = browser_callback.Initialize(success_callback, failure_callback);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString cmd_line_args_str(cmd_line_args);
+  hr = oneclick_worker_->DoOneClickInstall(cmd_line_args_str,
+                                           &browser_callback);
+
+  return hr;
+}
+
+STDMETHODIMP GoopdateCtrl::Install2(BSTR extra_args) {
+  EnsureWorkerUrlSet();
+  ASSERT1(extra_args && extra_args[0]);
+
+  if (!extra_args || !extra_args[0]) {
+    return E_INVALIDARG;
+  }
+
+  CORE_LOG(L2, (_T("[GoopdateCtrl::Install2][extra_args \"%s\"]"),
+                CW2CT(extra_args)));
+
+  CString extra_args_str(extra_args);
+  return oneclick_worker_->DoOneClickInstall2(extra_args_str);
+}
+
+STDMETHODIMP GoopdateCtrl::GetInstalledVersion(BSTR guid_string,
+                                               VARIANT_BOOL is_machine,
+                                               BSTR* version_string) {
+  CORE_LOG(L2, (_T("[GoopdateCtrl::GetInstalledVersion][%s][%d]"),
+                guid_string, is_machine));
+  EnsureWorkerUrlSet();
+
+  if (!version_string) {
+    return E_POINTER;
+  }
+  *version_string = NULL;
+
+  CString version;
+  HRESULT hr = oneclick_worker_->GetInstalledVersion(guid_string,
+                                                     is_machine == VARIANT_TRUE,
+                                                     &version);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  *version_string = version.AllocSysString();
+  return S_OK;
+}
+
+STDMETHODIMP GoopdateCtrl::GetOneClickVersion(long* version) {
+  CORE_LOG(L2, (_T("[GoopdateCtrl::GetOneClickVersion]")));
+  EnsureWorkerUrlSet();
+
+  return oneclick_worker_->GetOneClickVersion(version);
+}
+
+HRESULT GoopdateCtrl::FinalConstruct() {
+  CORE_LOG(L2, (_T("[GoopdateCtrl::FinalConstruct]")));
+  oneclick_worker_.reset(new OneClickWorker());
+  return oneclick_worker_->Initialize();
+}
+
+void GoopdateCtrl::FinalRelease() {
+  CORE_LOG(L2, (_T("[GoopdateCtrl::FinalRelease]")));
+}
+
+CString GoopdateCtrl::GetGoopdateShellPathForRegMap() {
+  return goopdate_utils::BuildGoogleUpdateExeDir(
+      goopdate_utils::IsRunningFromOfficialGoopdateDir(true));
+}
+
+OBJECT_ENTRY_AUTO(__uuidof(GoopdateOneClickControl), GoopdateCtrl)
+
+}  // namespace omaha
+
+// 4505: unreferenced local function has been removed
+#pragma warning(disable : 4505)
+
diff --git a/plugins/oneclick.def b/plugins/oneclick.def
index 707c502..6ba661a 100644
--- a/plugins/oneclick.def
+++ b/plugins/oneclick.def
@@ -1,26 +1,26 @@
-; Copyright 2007-2009 Google Inc.

-;

-; Licensed under the Apache License, Version 2.0 (the "License");

-; you may not use this file except in compliance with the License.

-; You may obtain a copy of the License at

-;

-;      http://www.apache.org/licenses/LICENSE-2.0

-;

-; Unless required by applicable law or agreed to in writing, software

-; distributed under the License is distributed on an "AS IS" BASIS,

-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-; See the License for the specific language governing permissions and

-; limitations under the License.

-; ========================================================================

-;

-; OneClick.def : COM entry points.

-

-EXPORTS

-  NP_GetEntryPoints     @1

-  NP_Initialize         @2

-  NP_Shutdown           @3

-  DllCanUnloadNow       PRIVATE

-  DllGetClassObject     PRIVATE

-  DllRegisterServer     PRIVATE

-  DllUnregisterServer   PRIVATE

-

+; Copyright 2007-2009 Google Inc.
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+; ========================================================================
+;
+; OneClick.def : COM entry points.
+
+EXPORTS
+  NP_GetEntryPoints     @1
+  NP_Initialize         @2
+  NP_Shutdown           @3
+  DllCanUnloadNow       PRIVATE
+  DllGetClassObject     PRIVATE
+  DllRegisterServer     PRIVATE
+  DllUnregisterServer   PRIVATE
+
diff --git a/plugins/oneclick.h b/plugins/oneclick.h
index 3701b79..7931438 100644
--- a/plugins/oneclick.h
+++ b/plugins/oneclick.h
@@ -1,141 +1,141 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// One-click support for Omaha returning users.

-

-#ifndef OMAHA_PLUGINS_ONECLICK_H__

-#define OMAHA_PLUGINS_ONECLICK_H__

-

-// TODO(omaha): We may want to move sitelock.h to be the "standard" sitelock.h

-// file from Microsoft (and move that file to omaha/external) and then have our

-// modifications to sitelock be in a derived class within the plugins

-// directory.

-

-#include <objsafe.h>

-#include <shellapi.h>

-#include <winhttp.h>

-#include <atlbase.h>

-#include <atlcom.h>

-#include <atlctl.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/ATLRegMapEx.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/const_config.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/debug.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/plugins/resource.h"

-#include "omaha/plugins/oneclick_worker.h"

-#include "plugins/sitelock.h"

-#include "plugins/oneclick_idl.h"

-

-// This doesn't get generated into the oneclick_idl.h as an extern and our

-// build environment doesn't let us include oneclick_idl_i.c

-// since we do it differently so extern define this here.

-extern "C" const IID DIID__GoogleUpdateOneClickEvents;

-

-namespace omaha {

-

-class GoopdateCtrl;

-

-typedef IObjectSafetyImpl<GoopdateCtrl, INTERFACESAFE_FOR_UNTRUSTED_CALLER>

-            ObjectSafety;

-

-typedef CSiteLock<GoopdateCtrl> SiteLock;

-

-// Using 0xffff for the major/minor versions in the IDispatchImpl template will

-// make ATL load the typelib directly from the DLL instead of looking up typelib

-// registration in registry. The big benefit is that we do not need to register

-// the typelib. Also, this is needed for Vista SP1 with UAC off, in which

-// oleaut32 does not read typelib information from HKCU, because of a bug.

-class ATL_NO_VTABLE GoopdateCtrl

-    : public CComObjectRootEx<CComObjectThreadModel>,

-      public CComCoClass<GoopdateCtrl, &__uuidof(GoopdateOneClickControl)>,

-      public IDispatchImpl<IGoogleUpdateOneClick,

-                           &__uuidof(IGoogleUpdateOneClick),

-                           &LIBID_OneClickLib, 0xffff, 0xffff>,

-      public ObjectSafety,

-      public SiteLock,

-      public IObjectWithSiteImpl<GoopdateCtrl> {

- public:

-  GoopdateCtrl();

-  virtual ~GoopdateCtrl();

-

-  DECLARE_REGISTRY_RESOURCEID_EX(IDR_ONECLICK)

-

-  #pragma warning(push)

-  // C4640: construction of local static object is not thread-safe

-  #pragma warning(disable : 4640)

-  BEGIN_REGISTRY_MAP()

-    REGMAP_ENTRY(_T("HKROOT"),            goopdate_utils::GetHKRoot())

-    REGMAP_ENTRY(_T("PROGID"),            kOneClickProgId)

-    REGMAP_ENTRY(_T("CLSID"),             __uuidof(GoopdateOneClickControl))

-    REGMAP_ENTRY(_T("PLUGINDOMAIN"),      kGoopdateServer)

-    REGMAP_ENTRY(_T("PLUGINVERSION"),     ACTIVEX_VERSION_ANSI)

-    REGMAP_ENTRY(_T("PLUGINDESCRIPTION"), kCiProgram)

-    REGMAP_ENTRY(_T("PLUGINPRODUCT"),     kCiProgram)

-    REGMAP_ENTRY(_T("PLUGINVENDOR"),      PUBLISHER_NAME_ANSI)

-    REGMAP_ENTRY(_T("PLUGINMIMETYPE"),    kOneClickPluginMimeTypeAnsi)

-    REGMAP_ENTRY(_T("SHELLNAME"),         kGoopdateFileName)

-    // Not fatal if "SHELLPATH" is empty because the side-effect would be that

-    // on Vista, the user will get prompted on invoking one-click.

-    REGMAP_ENTRY(_T("SHELLPATH"),         GetGoopdateShellPathForRegMap())

-    REGMAP_MODULE2(_T("NPONECLICK.DLL"),  ACTIVEX_FILENAME)

-  END_REGISTRY_MAP()

-  #pragma warning(pop)

-

-  BEGIN_COM_MAP(GoopdateCtrl)

-    COM_INTERFACE_ENTRY(IDispatch)

-    COM_INTERFACE_ENTRY(IObjectWithSite)

-    COM_INTERFACE_ENTRY(IObjectSafety)

-  END_COM_MAP()

-

-  DECLARE_NOT_AGGREGATABLE(GoopdateCtrl)

-  DECLARE_PROTECT_FINAL_CONSTRUCT();

-

-  // Installs the application that the passed-in manifest corresponds to.

-  STDMETHOD(Install)(BSTR cmd_line_args,

-                     VARIANT* success_callback,

-                     VARIANT* failure_callback);

-  STDMETHOD(Install2)(BSTR extra_args);

-

-  // Gets the version of the passed in application guid. If the application is

-  // not installed, returns an empty string.

-  STDMETHOD(GetInstalledVersion)(BSTR guid_string,

-                                 VARIANT_BOOL is_machine,

-                                 BSTR* version_string);

-

-  // Gets the version of the plugin.  This value will be ACTIVEX_VERSION_ANSI.

-  STDMETHOD(GetOneClickVersion)(long* version);

-

-  HRESULT FinalConstruct();

-  void FinalRelease();

-

- private:

-  void EnsureWorkerUrlSet();

-

-  scoped_ptr<OneClickWorker> oneclick_worker_;

-  bool is_worker_url_set_;

-

-  // If Admin, returns the path for Machine Goopdate. Else returns path for User

-  // Goopdate.

-  static CString GetGoopdateShellPathForRegMap();

-};

-

-}  // namespace omaha.

-

-#endif  // OMAHA_PLUGINS_ONECLICK_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// One-click support for Omaha returning users.
+
+#ifndef OMAHA_PLUGINS_ONECLICK_H__
+#define OMAHA_PLUGINS_ONECLICK_H__
+
+// TODO(omaha): We may want to move sitelock.h to be the "standard" sitelock.h
+// file from Microsoft (and move that file to omaha/external) and then have our
+// modifications to sitelock be in a derived class within the plugins
+// directory.
+
+#include <objsafe.h>
+#include <shellapi.h>
+#include <winhttp.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlctl.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/ATLRegMapEx.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/const_config.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/debug.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/plugins/resource.h"
+#include "omaha/plugins/oneclick_worker.h"
+#include "plugins/sitelock.h"
+#include "plugins/oneclick_idl.h"
+
+// This doesn't get generated into the oneclick_idl.h as an extern and our
+// build environment doesn't let us include oneclick_idl_i.c
+// since we do it differently so extern define this here.
+extern "C" const IID DIID__GoogleUpdateOneClickEvents;
+
+namespace omaha {
+
+class GoopdateCtrl;
+
+typedef IObjectSafetyImpl<GoopdateCtrl, INTERFACESAFE_FOR_UNTRUSTED_CALLER>
+            ObjectSafety;
+
+typedef CSiteLock<GoopdateCtrl> SiteLock;
+
+// Using 0xffff for the major/minor versions in the IDispatchImpl template will
+// make ATL load the typelib directly from the DLL instead of looking up typelib
+// registration in registry. The big benefit is that we do not need to register
+// the typelib. Also, this is needed for Vista SP1 with UAC off, in which
+// oleaut32 does not read typelib information from HKCU, because of a bug.
+class ATL_NO_VTABLE GoopdateCtrl
+    : public CComObjectRootEx<CComObjectThreadModel>,
+      public CComCoClass<GoopdateCtrl, &__uuidof(GoopdateOneClickControl)>,
+      public IDispatchImpl<IGoogleUpdateOneClick,
+                           &__uuidof(IGoogleUpdateOneClick),
+                           &LIBID_OneClickLib, 0xffff, 0xffff>,
+      public ObjectSafety,
+      public SiteLock,
+      public IObjectWithSiteImpl<GoopdateCtrl> {
+ public:
+  GoopdateCtrl();
+  virtual ~GoopdateCtrl();
+
+  DECLARE_REGISTRY_RESOURCEID_EX(IDR_ONECLICK)
+
+  #pragma warning(push)
+  // C4640: construction of local static object is not thread-safe
+  #pragma warning(disable : 4640)
+  BEGIN_REGISTRY_MAP()
+    REGMAP_ENTRY(_T("HKROOT"),            goopdate_utils::GetHKRoot())
+    REGMAP_ENTRY(_T("PROGID"),            kOneClickProgId)
+    REGMAP_ENTRY(_T("CLSID"),             __uuidof(GoopdateOneClickControl))
+    REGMAP_ENTRY(_T("PLUGINDOMAIN"),      kGoopdateServer)
+    REGMAP_ENTRY(_T("PLUGINVERSION"),     ACTIVEX_VERSION_ANSI)
+    REGMAP_ENTRY(_T("PLUGINDESCRIPTION"), kCiProgram)
+    REGMAP_ENTRY(_T("PLUGINPRODUCT"),     kCiProgram)
+    REGMAP_ENTRY(_T("PLUGINVENDOR"),      PUBLISHER_NAME_ANSI)
+    REGMAP_ENTRY(_T("PLUGINMIMETYPE"),    kOneClickPluginMimeTypeAnsi)
+    REGMAP_ENTRY(_T("SHELLNAME"),         kGoopdateFileName)
+    // Not fatal if "SHELLPATH" is empty because the side-effect would be that
+    // on Vista, the user will get prompted on invoking one-click.
+    REGMAP_ENTRY(_T("SHELLPATH"),         GetGoopdateShellPathForRegMap())
+    REGMAP_MODULE2(_T("NPONECLICK.DLL"),  ACTIVEX_FILENAME)
+  END_REGISTRY_MAP()
+  #pragma warning(pop)
+
+  BEGIN_COM_MAP(GoopdateCtrl)
+    COM_INTERFACE_ENTRY(IDispatch)
+    COM_INTERFACE_ENTRY(IObjectWithSite)
+    COM_INTERFACE_ENTRY(IObjectSafety)
+  END_COM_MAP()
+
+  DECLARE_NOT_AGGREGATABLE(GoopdateCtrl)
+  DECLARE_PROTECT_FINAL_CONSTRUCT();
+
+  // Installs the application that the passed-in manifest corresponds to.
+  STDMETHOD(Install)(BSTR cmd_line_args,
+                     VARIANT* success_callback,
+                     VARIANT* failure_callback);
+  STDMETHOD(Install2)(BSTR extra_args);
+
+  // Gets the version of the passed in application guid. If the application is
+  // not installed, returns an empty string.
+  STDMETHOD(GetInstalledVersion)(BSTR guid_string,
+                                 VARIANT_BOOL is_machine,
+                                 BSTR* version_string);
+
+  // Gets the version of the plugin.  This value will be ACTIVEX_VERSION_ANSI.
+  STDMETHOD(GetOneClickVersion)(long* version);
+
+  HRESULT FinalConstruct();
+  void FinalRelease();
+
+ private:
+  void EnsureWorkerUrlSet();
+
+  scoped_ptr<OneClickWorker> oneclick_worker_;
+  bool is_worker_url_set_;
+
+  // If Admin, returns the path for Machine Goopdate. Else returns path for User
+  // Goopdate.
+  static CString GetGoopdateShellPathForRegMap();
+};
+
+}  // namespace omaha.
+
+#endif  // OMAHA_PLUGINS_ONECLICK_H__
+
diff --git a/plugins/oneclick.rgs b/plugins/oneclick.rgs
index 05cb691..857ee85 100644
--- a/plugins/oneclick.rgs
+++ b/plugins/oneclick.rgs
@@ -1,97 +1,97 @@
-%HKROOT%

-{

-  NoRemove SOFTWARE

-  {

-    NoRemove MozillaPlugins

-    {

-      ForceRemove '@%PLUGINDOMAIN%/%PLUGINPRODUCT%;version=%PLUGINVERSION%'

-      {

-        val Path = s '%NPONECLICK.DLL%'

-        val Description = s '%PLUGINDESCRIPTION%'

-        val ProductName = s '%PLUGINPRODUCT%'

-        val Vendor = s '%PLUGINVENDOR%'

-        val Version = s '%PLUGINVERSION%'

-        MimeTypes

-        {

-          '%PLUGINMIMETYPE%'

-        }

-      }

-    }

-    NoRemove Microsoft

-    {

-      NoRemove Windows

-      {

-        NoRemove CurrentVersion

-        {

-          NoRemove Ext

-          {

-            NoRemove PreApproved

-            {

-              ForceRemove '%CLSID%'

-            }

-            NoRemove Stats

-            {

-              ForceRemove '%CLSID%'

-              {

-                iexplore

-                {

-                  AllowedDomains

-                  {

-                    '*'

-                  }

-                }

-              }

-            }

-          }

-        }

-      }

-      NoRemove 'Internet Explorer'

-      {

-        NoRemove 'Low Rights'

-        {

-          NoRemove 'ElevationPolicy'

-          {

-            ForceRemove '%CLSID%'

-            {

-              val AppName = s '%SHELLNAME%'

-              val AppPath = s '%SHELLPATH%'

-              val Policy = d '3'

-            }

-          }

-        }

-      }

-    }

-    NoRemove Classes

-    {

-      ForceRemove '%PROGID%' = s '%PLUGINPRODUCT% Plugin'

-      {

-        CLSID = s '%CLSID%'

-      }

-      NoRemove CLSID

-      {

-        ForceRemove '%CLSID%' = s '%PLUGINPRODUCT% Plugin'

-        {

-          ProgID = s '%PROGID%'

-          InprocServer32 = s '%MODULE%'

-          {

-            val ThreadingModel = s 'Apartment'

-          }

-        }

-      }

-      NoRemove MIME

-      {

-        NoRemove Database

-        {

-          NoRemove 'Content Type'

-          {

-            ForceRemove '%PLUGINMIMETYPE%'

-            {

-              val CLSID = s '%CLSID%'

-            }

-          }

-        }

-      }

-    }

-  }

-}

-

+%HKROOT%
+{
+  NoRemove SOFTWARE
+  {
+    NoRemove MozillaPlugins
+    {
+      ForceRemove '@%PLUGINDOMAIN%/%PLUGINPRODUCT%;version=%PLUGINVERSION%'
+      {
+        val Path = s '%NPONECLICK.DLL%'
+        val Description = s '%PLUGINDESCRIPTION%'
+        val ProductName = s '%PLUGINPRODUCT%'
+        val Vendor = s '%PLUGINVENDOR%'
+        val Version = s '%PLUGINVERSION%'
+        MimeTypes
+        {
+          '%PLUGINMIMETYPE%'
+        }
+      }
+    }
+    NoRemove Microsoft
+    {
+      NoRemove Windows
+      {
+        NoRemove CurrentVersion
+        {
+          NoRemove Ext
+          {
+            NoRemove PreApproved
+            {
+              ForceRemove '%CLSID%'
+            }
+            NoRemove Stats
+            {
+              ForceRemove '%CLSID%'
+              {
+                iexplore
+                {
+                  AllowedDomains
+                  {
+                    '*'
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      NoRemove 'Internet Explorer'
+      {
+        NoRemove 'Low Rights'
+        {
+          NoRemove 'ElevationPolicy'
+          {
+            ForceRemove '%CLSID%'
+            {
+              val AppName = s '%SHELLNAME%'
+              val AppPath = s '%SHELLPATH%'
+              val Policy = d '3'
+            }
+          }
+        }
+      }
+    }
+    NoRemove Classes
+    {
+      ForceRemove '%PROGID%' = s '%PLUGINPRODUCT% Plugin'
+      {
+        CLSID = s '%CLSID%'
+      }
+      NoRemove CLSID
+      {
+        ForceRemove '%CLSID%' = s '%PLUGINPRODUCT% Plugin'
+        {
+          ProgID = s '%PROGID%'
+          InprocServer32 = s '%MODULE%'
+          {
+            val ThreadingModel = s 'Apartment'
+          }
+        }
+      }
+      NoRemove MIME
+      {
+        NoRemove Database
+        {
+          NoRemove 'Content Type'
+          {
+            ForceRemove '%PLUGINMIMETYPE%'
+            {
+              val CLSID = s '%CLSID%'
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
diff --git a/plugins/oneclick_atl_module.cc b/plugins/oneclick_atl_module.cc
index 0945a52..221c222 100644
--- a/plugins/oneclick_atl_module.cc
+++ b/plugins/oneclick_atl_module.cc
@@ -1,66 +1,66 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The ATL module definition and module instance.

-

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "plugins/oneclick_idl.h"

-

-namespace omaha {

-

-class OneClickModule : public CAtlDllModuleT<OneClickModule> {

- public :

-  OneClickModule() {}

-  DECLARE_LIBID(LIBID_OneClickLib)

-};

-

-extern "C" {

-  OneClickModule _AtlModule;

-}

-

-}  // namespace omaha.

-

-HRESULT RegisterOrUnregisterDll(bool is_register) {

-  HRESULT hr = is_register ? omaha::_AtlModule.DllRegisterServer(false) :

-                             omaha::_AtlModule.DllUnregisterServer(false);

-  ASSERT(SUCCEEDED(hr), (_T("[RegisterOrUnregisterDll failed][%d][0x%08x]"),

-                         is_register, hr));

-  return hr;

-}

-

-// The standard COM entry points below are exported using a .def file.

-STDAPI DllCanUnloadNow() {

-  return omaha::_AtlModule.DllCanUnloadNow();

-}

-

-STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv) {

-  return omaha::_AtlModule.DllGetClassObject(rclsid, riid, ppv);

-}

-

-STDAPI DllRegisterServer() {

-  return omaha::goopdate_utils::RegisterOrUnregisterModule(

-      true,

-      &RegisterOrUnregisterDll);

-}

-

-STDAPI DllUnregisterServer() {

-  return omaha::goopdate_utils::RegisterOrUnregisterModule(

-      false,

-      &RegisterOrUnregisterDll);

-}

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The ATL module definition and module instance.
+
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "plugins/oneclick_idl.h"
+
+namespace omaha {
+
+class OneClickModule : public CAtlDllModuleT<OneClickModule> {
+ public :
+  OneClickModule() {}
+  DECLARE_LIBID(LIBID_OneClickLib)
+};
+
+extern "C" {
+  OneClickModule _AtlModule;
+}
+
+}  // namespace omaha.
+
+HRESULT RegisterOrUnregisterDll(bool is_register) {
+  HRESULT hr = is_register ? omaha::_AtlModule.DllRegisterServer(false) :
+                             omaha::_AtlModule.DllUnregisterServer(false);
+  ASSERT(SUCCEEDED(hr), (_T("[RegisterOrUnregisterDll failed][%d][0x%08x]"),
+                         is_register, hr));
+  return hr;
+}
+
+// The standard COM entry points below are exported using a .def file.
+STDAPI DllCanUnloadNow() {
+  return omaha::_AtlModule.DllCanUnloadNow();
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv) {
+  return omaha::_AtlModule.DllGetClassObject(rclsid, riid, ppv);
+}
+
+STDAPI DllRegisterServer() {
+  return omaha::goopdate_utils::RegisterOrUnregisterModule(
+      true,
+      &RegisterOrUnregisterDll);
+}
+
+STDAPI DllUnregisterServer() {
+  return omaha::goopdate_utils::RegisterOrUnregisterModule(
+      false,
+      &RegisterOrUnregisterDll);
+}
+
diff --git a/plugins/oneclick_browser_callback.h b/plugins/oneclick_browser_callback.h
index b3f05dc..25e0701 100644
--- a/plugins/oneclick_browser_callback.h
+++ b/plugins/oneclick_browser_callback.h
@@ -1,43 +1,43 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// OneClick browser-specific callback classes.  This is the abstract base class

-// for a browser-callback class to derive from.

-

-#ifndef OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_H__

-#define OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_H__

-

-#include <windows.h>

-

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class OneClickBrowserCallback {

- public:

-  OneClickBrowserCallback() {}

-  virtual ~OneClickBrowserCallback() {}

-

-  virtual void DoSuccessCallback() = 0;

-  virtual void DoFailureCallback(HRESULT hr_error) = 0;

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(OneClickBrowserCallback);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// OneClick browser-specific callback classes.  This is the abstract base class
+// for a browser-callback class to derive from.
+
+#ifndef OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_H__
+#define OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_H__
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class OneClickBrowserCallback {
+ public:
+  OneClickBrowserCallback() {}
+  virtual ~OneClickBrowserCallback() {}
+
+  virtual void DoSuccessCallback() = 0;
+  virtual void DoFailureCallback(HRESULT hr_error) = 0;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(OneClickBrowserCallback);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_H__
+
diff --git a/plugins/oneclick_browser_callback_activex.cc b/plugins/oneclick_browser_callback_activex.cc
index 625eab0..a45d04a 100644
--- a/plugins/oneclick_browser_callback_activex.cc
+++ b/plugins/oneclick_browser_callback_activex.cc
@@ -1,173 +1,173 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// OneClick callback helper for ActiveX browsers.

-

-#include "omaha/plugins/oneclick_browser_callback_activex.h"

-

-#include <dispex.h>

-#include <winhttp.h>

-#include <atlbase.h>

-#include <atlcom.h>

-

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/string.h"

-#include "omaha/goopdate/goopdate_utils.h"

-

-// Note:  IE gives a dispinterface JScriptTypeInfo as our onxxxxx property

-// values. classid: C59C6B12-F6C1-11CF-8835-00A0C911E8B2

-// We invoke "dispatch id 0" to call the associated function.

-// See http://www.ddj.com/windows/184404200

-

-// We prefer to call things thru IDispatchEx in order to use DISPID_THIS.

-// Note: strangely, the parameters passed thru IDispatch are in reverse order as

-// compared to the method signature being invoked.

-

-namespace omaha {

-

-OneClickBrowserCallbackActiveX::OneClickBrowserCallbackActiveX() {

-}

-

-OneClickBrowserCallbackActiveX::~OneClickBrowserCallbackActiveX() {

-}

-

-HRESULT OneClickBrowserCallbackActiveX::Initialize(VARIANT* success_callback,

-                                                   VARIANT* failure_callback) {

-  // These two parameters are optional, but if they're valid VARIANTs then they

-  // need to be of type VT_DISPATCH or we fail.

-

-  if (!VariantIsNullOrUndefined(success_callback)) {

-    if (success_callback->vt == VT_DISPATCH) {

-      success_callback_dispatch_ = success_callback->pdispVal;

-    } else {

-      return E_INVALIDARG;

-    }

-  }

-

-  if (!VariantIsNullOrUndefined(failure_callback)) {

-    if (failure_callback->vt == VT_DISPATCH) {

-      failure_callback_dispatch_ = failure_callback->pdispVal;

-    } else {

-      return E_INVALIDARG;

-    }

-  }

-

-  return S_OK;

-}

-

-bool OneClickBrowserCallbackActiveX::VariantIsNullOrUndefined(

-    const VARIANT* var) {

-  return var->vt == VT_NULL || var->vt == VT_EMPTY;

-}

-

-void OneClickBrowserCallbackActiveX::DoSuccessCallback() {

-  CORE_LOG(L2, (_T("[DoSuccessCallback entered]")));

-

-  if (!success_callback_dispatch_) {

-    return;

-  }

-

-  const DISPID kDispId0 = 0;

-

-  HRESULT hr = 0;

-  DISPPARAMS dispparams = {0};

-  CComQIPtr<IDispatchEx> dispatchex =

-      static_cast<IDispatch*>(success_callback_dispatch_);

-

-  if (dispatchex) {

-    DISPID disp_this = DISPID_THIS;

-    VARIANT var[1];

-    var[0].vt = VT_DISPATCH;

-    var[0].pdispVal = dispatchex;

-

-    dispparams.rgvarg = var;

-    dispparams.rgdispidNamedArgs = &disp_this;

-    dispparams.cNamedArgs = 1;

-    dispparams.cArgs = 1;

-

-    hr = dispatchex->InvokeEx(kDispId0, LOCALE_USER_DEFAULT,

-                              DISPATCH_METHOD, &dispparams,

-                              NULL, NULL, NULL);

-  } else if (success_callback_dispatch_) {

-    // Fallback on IDispatch if needed.

-    UINT arg_err = 0;

-    dispparams.cArgs = 0;

-

-    hr = success_callback_dispatch_->Invoke(kDispId0,

-                                            IID_NULL,

-                                            LOCALE_SYSTEM_DEFAULT,

-                                            DISPATCH_METHOD,

-                                            &dispparams,

-                                            NULL,

-                                            NULL,

-                                            &arg_err);

-  }

-}

-

-void OneClickBrowserCallbackActiveX::DoFailureCallback(HRESULT hr_error) {

-  CORE_LOG(L2, (_T("[DoFailureCallback entered][hr_error=0x%x]"), hr_error));

-

-  if (!failure_callback_dispatch_) {

-    return;

-  }

-

-  const DISPID kDispId0 = 0;

-

-  HRESULT hr = 0;

-  DISPPARAMS dispparams = {0};

-  CComQIPtr<IDispatchEx> dispatchex =

-      static_cast<IDispatch*>(failure_callback_dispatch_);

-

-  if (dispatchex) {

-    DISPID disp_this = DISPID_THIS;

-    VARIANT var[2];

-    var[0].vt = VT_DISPATCH;

-    var[0].pdispVal = dispatchex;

-    var[1].vt = VT_I4;

-    var[1].intVal = hr_error;

-

-    dispparams.rgvarg = var;

-    dispparams.rgdispidNamedArgs = &disp_this;

-    dispparams.cNamedArgs = 1;

-    dispparams.cArgs = 2;

-

-    hr = dispatchex->InvokeEx(kDispId0, LOCALE_USER_DEFAULT,

-                              DISPATCH_METHOD, &dispparams,

-                              NULL, NULL, NULL);

-  } else if (failure_callback_dispatch_) {

-    // Fallback on IDispatch if needed.

-    UINT arg_err = 0;

-    VARIANT var[1];

-    var[0].vt = VT_I4;

-    var[0].intVal = hr_error;

-

-    dispparams.rgvarg = var;

-    dispparams.cArgs = 1;

-

-    hr = failure_callback_dispatch_->Invoke(kDispId0,

-                                            IID_NULL,

-                                            LOCALE_SYSTEM_DEFAULT,

-                                            DISPATCH_METHOD,

-                                            &dispparams,

-                                            NULL,

-                                            NULL,

-                                            &arg_err);

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// OneClick callback helper for ActiveX browsers.
+
+#include "omaha/plugins/oneclick_browser_callback_activex.h"
+
+#include <dispex.h>
+#include <winhttp.h>
+#include <atlbase.h>
+#include <atlcom.h>
+
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/string.h"
+#include "omaha/goopdate/goopdate_utils.h"
+
+// Note:  IE gives a dispinterface JScriptTypeInfo as our onxxxxx property
+// values. classid: C59C6B12-F6C1-11CF-8835-00A0C911E8B2
+// We invoke "dispatch id 0" to call the associated function.
+// See http://www.ddj.com/windows/184404200
+
+// We prefer to call things thru IDispatchEx in order to use DISPID_THIS.
+// Note: strangely, the parameters passed thru IDispatch are in reverse order as
+// compared to the method signature being invoked.
+
+namespace omaha {
+
+OneClickBrowserCallbackActiveX::OneClickBrowserCallbackActiveX() {
+}
+
+OneClickBrowserCallbackActiveX::~OneClickBrowserCallbackActiveX() {
+}
+
+HRESULT OneClickBrowserCallbackActiveX::Initialize(VARIANT* success_callback,
+                                                   VARIANT* failure_callback) {
+  // These two parameters are optional, but if they're valid VARIANTs then they
+  // need to be of type VT_DISPATCH or we fail.
+
+  if (!VariantIsNullOrUndefined(success_callback)) {
+    if (success_callback->vt == VT_DISPATCH) {
+      success_callback_dispatch_ = success_callback->pdispVal;
+    } else {
+      return E_INVALIDARG;
+    }
+  }
+
+  if (!VariantIsNullOrUndefined(failure_callback)) {
+    if (failure_callback->vt == VT_DISPATCH) {
+      failure_callback_dispatch_ = failure_callback->pdispVal;
+    } else {
+      return E_INVALIDARG;
+    }
+  }
+
+  return S_OK;
+}
+
+bool OneClickBrowserCallbackActiveX::VariantIsNullOrUndefined(
+    const VARIANT* var) {
+  return var->vt == VT_NULL || var->vt == VT_EMPTY;
+}
+
+void OneClickBrowserCallbackActiveX::DoSuccessCallback() {
+  CORE_LOG(L2, (_T("[DoSuccessCallback entered]")));
+
+  if (!success_callback_dispatch_) {
+    return;
+  }
+
+  const DISPID kDispId0 = 0;
+
+  HRESULT hr = 0;
+  DISPPARAMS dispparams = {0};
+  CComQIPtr<IDispatchEx> dispatchex =
+      static_cast<IDispatch*>(success_callback_dispatch_);
+
+  if (dispatchex) {
+    DISPID disp_this = DISPID_THIS;
+    VARIANT var[1];
+    var[0].vt = VT_DISPATCH;
+    var[0].pdispVal = dispatchex;
+
+    dispparams.rgvarg = var;
+    dispparams.rgdispidNamedArgs = &disp_this;
+    dispparams.cNamedArgs = 1;
+    dispparams.cArgs = 1;
+
+    hr = dispatchex->InvokeEx(kDispId0, LOCALE_USER_DEFAULT,
+                              DISPATCH_METHOD, &dispparams,
+                              NULL, NULL, NULL);
+  } else if (success_callback_dispatch_) {
+    // Fallback on IDispatch if needed.
+    UINT arg_err = 0;
+    dispparams.cArgs = 0;
+
+    hr = success_callback_dispatch_->Invoke(kDispId0,
+                                            IID_NULL,
+                                            LOCALE_SYSTEM_DEFAULT,
+                                            DISPATCH_METHOD,
+                                            &dispparams,
+                                            NULL,
+                                            NULL,
+                                            &arg_err);
+  }
+}
+
+void OneClickBrowserCallbackActiveX::DoFailureCallback(HRESULT hr_error) {
+  CORE_LOG(L2, (_T("[DoFailureCallback entered][hr_error=0x%x]"), hr_error));
+
+  if (!failure_callback_dispatch_) {
+    return;
+  }
+
+  const DISPID kDispId0 = 0;
+
+  HRESULT hr = 0;
+  DISPPARAMS dispparams = {0};
+  CComQIPtr<IDispatchEx> dispatchex =
+      static_cast<IDispatch*>(failure_callback_dispatch_);
+
+  if (dispatchex) {
+    DISPID disp_this = DISPID_THIS;
+    VARIANT var[2];
+    var[0].vt = VT_DISPATCH;
+    var[0].pdispVal = dispatchex;
+    var[1].vt = VT_I4;
+    var[1].intVal = hr_error;
+
+    dispparams.rgvarg = var;
+    dispparams.rgdispidNamedArgs = &disp_this;
+    dispparams.cNamedArgs = 1;
+    dispparams.cArgs = 2;
+
+    hr = dispatchex->InvokeEx(kDispId0, LOCALE_USER_DEFAULT,
+                              DISPATCH_METHOD, &dispparams,
+                              NULL, NULL, NULL);
+  } else if (failure_callback_dispatch_) {
+    // Fallback on IDispatch if needed.
+    UINT arg_err = 0;
+    VARIANT var[1];
+    var[0].vt = VT_I4;
+    var[0].intVal = hr_error;
+
+    dispparams.rgvarg = var;
+    dispparams.cArgs = 1;
+
+    hr = failure_callback_dispatch_->Invoke(kDispId0,
+                                            IID_NULL,
+                                            LOCALE_SYSTEM_DEFAULT,
+                                            DISPATCH_METHOD,
+                                            &dispparams,
+                                            NULL,
+                                            NULL,
+                                            &arg_err);
+  }
+}
+
+}  // namespace omaha
+
diff --git a/plugins/oneclick_browser_callback_activex.h b/plugins/oneclick_browser_callback_activex.h
index 52c9b8a..8424665 100644
--- a/plugins/oneclick_browser_callback_activex.h
+++ b/plugins/oneclick_browser_callback_activex.h
@@ -1,58 +1,58 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-// OneClick browser-specific callback class for IE/ActiveX.

-

-#ifndef OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_ACTIVEX_H__

-#define OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_ACTIVEX_H__

-

-#include <atlbase.h>

-#include <atlcom.h>

-

-#include "omaha/plugins/oneclick_browser_callback.h"

-

-namespace omaha {

-

-class OneClickBrowserCallbackActiveX : public OneClickBrowserCallback {

- public:

-  OneClickBrowserCallbackActiveX();

-  virtual ~OneClickBrowserCallbackActiveX();

-

-  // Initialize the callback with two VARIANT values which are Javascript

-  // functions to be called.  IE passes Javascript classes as an IDispatch

-  // wrapped inside a VARIANT.

-  // The VARIANT parameters are optional which means we won't call a function in

-  // those cases.

-  HRESULT Initialize(VARIANT* success_callback, VARIANT* failure_callback);

-

-  // Overrides from abstract base class.

-  virtual void DoSuccessCallback();

-  virtual void DoFailureCallback(HRESULT hr_error);

-

- private:

-  CComPtr<IDispatch> success_callback_dispatch_;

-  CComPtr<IDispatch> failure_callback_dispatch_;

-

-  // Returns true if var is VT_NULL or VT_EMPTY.

-  bool VariantIsNullOrUndefined(const VARIANT* var);

-

-  DISALLOW_EVIL_CONSTRUCTORS(OneClickBrowserCallbackActiveX);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_ACTIVEX_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+// OneClick browser-specific callback class for IE/ActiveX.
+
+#ifndef OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_ACTIVEX_H__
+#define OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_ACTIVEX_H__
+
+#include <atlbase.h>
+#include <atlcom.h>
+
+#include "omaha/plugins/oneclick_browser_callback.h"
+
+namespace omaha {
+
+class OneClickBrowserCallbackActiveX : public OneClickBrowserCallback {
+ public:
+  OneClickBrowserCallbackActiveX();
+  virtual ~OneClickBrowserCallbackActiveX();
+
+  // Initialize the callback with two VARIANT values which are Javascript
+  // functions to be called.  IE passes Javascript classes as an IDispatch
+  // wrapped inside a VARIANT.
+  // The VARIANT parameters are optional which means we won't call a function in
+  // those cases.
+  HRESULT Initialize(VARIANT* success_callback, VARIANT* failure_callback);
+
+  // Overrides from abstract base class.
+  virtual void DoSuccessCallback();
+  virtual void DoFailureCallback(HRESULT hr_error);
+
+ private:
+  CComPtr<IDispatch> success_callback_dispatch_;
+  CComPtr<IDispatch> failure_callback_dispatch_;
+
+  // Returns true if var is VT_NULL or VT_EMPTY.
+  bool VariantIsNullOrUndefined(const VARIANT* var);
+
+  DISALLOW_EVIL_CONSTRUCTORS(OneClickBrowserCallbackActiveX);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_ACTIVEX_H__
+
diff --git a/plugins/oneclick_browser_callback_npapi.cc b/plugins/oneclick_browser_callback_npapi.cc
index 4e11029..e2de655 100644
--- a/plugins/oneclick_browser_callback_npapi.cc
+++ b/plugins/oneclick_browser_callback_npapi.cc
@@ -1,111 +1,111 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// OneClick helper functions.

-

-// Note:  oneclick_browser_callback_npapi.h cannot be included before system

-// headers due to conflicts between base/windows code and NPAPI

-// definitions.

-

-#pragma warning(push)

-#pragma warning(disable : 4201 4265)

-// 4201: nonstandard extension used : nameless struct/union

-// 4265: class has virtual functions, but destructor is not virtual

-

-#include "base/scoped_ptr.h"

-#include "omaha/plugins/npOneClick.h"

-#include "omaha/plugins/oneclick_browser_callback_npapi.h"

-

-#pragma warning(pop)

-

-namespace omaha {

-

-OneClickBrowserCallbackNpapi::OneClickBrowserCallbackNpapi()

-    : npp_(NULL), success_callback_(NULL), failure_callback_(NULL) {

-}

-

-OneClickBrowserCallbackNpapi::~OneClickBrowserCallbackNpapi() {

-  if (success_callback_) {

-    NPN_ReleaseObject(success_callback_);

-    success_callback_ = NULL;

-  }

-  if (failure_callback_) {

-    NPN_ReleaseObject(failure_callback_);

-    failure_callback_ = NULL;

-  }

-}

-

-HRESULT OneClickBrowserCallbackNpapi::Initialize(NPP npp,

-                                                 NPVariant success_callback,

-                                                 NPVariant failure_callback) {

-  npp_ = npp;

-

-  if (NPVARIANT_IS_OBJECT(success_callback)) {

-    success_callback_ = NPVARIANT_TO_OBJECT(success_callback);

-    NPN_RetainObject(success_callback_);

-  }

-

-  if (NPVARIANT_IS_OBJECT(failure_callback)) {

-    failure_callback_ = NPVARIANT_TO_OBJECT(failure_callback);

-    NPN_RetainObject(failure_callback_);

-  }

-

-  return S_OK;

-}

-

-void OneClickBrowserCallbackNpapi::DoSuccessCallback() {

-  CORE_LOG(L2, (_T("[DoSuccessCallback entered]")));

-

-  if (!success_callback_) {

-    CORE_LOG(L2, (_T("[DoSuccessCallback entered][NO success_callback_]")));

-    return;

-  }

-

-  CORE_LOG(L2, (_T("[DoSuccessCallback entered][valid success_callback_]")));

-  NPVariant rval;

-  NULL_TO_NPVARIANT(rval);

-

-  NPN_InvokeDefault(npp_,

-                    success_callback_,

-                    NULL,

-                    0,

-                    &rval);

-}

-

-void OneClickBrowserCallbackNpapi::DoFailureCallback(HRESULT hr_error) {

-  CORE_LOG(L2, (_T("[DoFailureCallback entered][hr_error=0x%x]"), hr_error));

-

-  if (!failure_callback_) {

-    CORE_LOG(L2, (_T("[DoFailureCallback entered][NO failure_callback_]")));

-    return;

-  }

-

-  CORE_LOG(L2, (_T("[DoFailureCallback entered][valid failure_callback_]")));

-  NPVariant rval;

-  NULL_TO_NPVARIANT(rval);

-

-  NPVariant arg;

-  NULL_TO_NPVARIANT(arg);

-  INT32_TO_NPVARIANT(hr_error, arg);

-

-  NPN_InvokeDefault(npp_,

-                    failure_callback_,

-                    &arg,

-                    1,

-                    &rval);

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// OneClick helper functions.
+
+// Note:  oneclick_browser_callback_npapi.h cannot be included before system
+// headers due to conflicts between base/windows code and NPAPI
+// definitions.
+
+#pragma warning(push)
+#pragma warning(disable : 4201 4265)
+// 4201: nonstandard extension used : nameless struct/union
+// 4265: class has virtual functions, but destructor is not virtual
+
+#include "base/scoped_ptr.h"
+#include "omaha/plugins/npOneClick.h"
+#include "omaha/plugins/oneclick_browser_callback_npapi.h"
+
+#pragma warning(pop)
+
+namespace omaha {
+
+OneClickBrowserCallbackNpapi::OneClickBrowserCallbackNpapi()
+    : npp_(NULL), success_callback_(NULL), failure_callback_(NULL) {
+}
+
+OneClickBrowserCallbackNpapi::~OneClickBrowserCallbackNpapi() {
+  if (success_callback_) {
+    NPN_ReleaseObject(success_callback_);
+    success_callback_ = NULL;
+  }
+  if (failure_callback_) {
+    NPN_ReleaseObject(failure_callback_);
+    failure_callback_ = NULL;
+  }
+}
+
+HRESULT OneClickBrowserCallbackNpapi::Initialize(NPP npp,
+                                                 NPVariant success_callback,
+                                                 NPVariant failure_callback) {
+  npp_ = npp;
+
+  if (NPVARIANT_IS_OBJECT(success_callback)) {
+    success_callback_ = NPVARIANT_TO_OBJECT(success_callback);
+    NPN_RetainObject(success_callback_);
+  }
+
+  if (NPVARIANT_IS_OBJECT(failure_callback)) {
+    failure_callback_ = NPVARIANT_TO_OBJECT(failure_callback);
+    NPN_RetainObject(failure_callback_);
+  }
+
+  return S_OK;
+}
+
+void OneClickBrowserCallbackNpapi::DoSuccessCallback() {
+  CORE_LOG(L2, (_T("[DoSuccessCallback entered]")));
+
+  if (!success_callback_) {
+    CORE_LOG(L2, (_T("[DoSuccessCallback entered][NO success_callback_]")));
+    return;
+  }
+
+  CORE_LOG(L2, (_T("[DoSuccessCallback entered][valid success_callback_]")));
+  NPVariant rval;
+  NULL_TO_NPVARIANT(rval);
+
+  NPN_InvokeDefault(npp_,
+                    success_callback_,
+                    NULL,
+                    0,
+                    &rval);
+}
+
+void OneClickBrowserCallbackNpapi::DoFailureCallback(HRESULT hr_error) {
+  CORE_LOG(L2, (_T("[DoFailureCallback entered][hr_error=0x%x]"), hr_error));
+
+  if (!failure_callback_) {
+    CORE_LOG(L2, (_T("[DoFailureCallback entered][NO failure_callback_]")));
+    return;
+  }
+
+  CORE_LOG(L2, (_T("[DoFailureCallback entered][valid failure_callback_]")));
+  NPVariant rval;
+  NULL_TO_NPVARIANT(rval);
+
+  NPVariant arg;
+  NULL_TO_NPVARIANT(arg);
+  INT32_TO_NPVARIANT(hr_error, arg);
+
+  NPN_InvokeDefault(npp_,
+                    failure_callback_,
+                    &arg,
+                    1,
+                    &rval);
+}
+
+}  // namespace omaha
+
diff --git a/plugins/oneclick_browser_callback_npapi.h b/plugins/oneclick_browser_callback_npapi.h
index b6a3e34..a93316d 100644
--- a/plugins/oneclick_browser_callback_npapi.h
+++ b/plugins/oneclick_browser_callback_npapi.h
@@ -1,55 +1,55 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-// OneClick browser-specific callback class for NPAPI based browsers.

-

-#ifndef OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_NPAPI_H__

-#define OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_NPAPI_H__

-

-#include "omaha/plugins/oneclick_browser_callback.h"

-

-namespace omaha {

-

-class OneClickBrowserCallbackNpapi : public OneClickBrowserCallback {

- public:

-  OneClickBrowserCallbackNpapi();

-  virtual ~OneClickBrowserCallbackNpapi();

-

-  // Initializes the callback class with the NPP and two NPVariant values which

-  // represent the Javascript functions to be called.  NPAPI passes Javascript

-  // functions as an NPObject wrapped within an NPVariant.

-  // The NPVariant parameters are optional (can be internally NULL) which means

-  // we won't call a function in those cases.

-  HRESULT Initialize(NPP npp,

-                     NPVariant success_callback,

-                     NPVariant failure_callback);

-

-  // Overrides from abstract base class.

-  virtual void DoSuccessCallback();

-  virtual void DoFailureCallback(HRESULT hr_error);

-

- private:

-  NPP npp_;

-  NPObject* success_callback_;

-  NPObject* failure_callback_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(OneClickBrowserCallbackNpapi);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_NPAPI_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+// OneClick browser-specific callback class for NPAPI based browsers.
+
+#ifndef OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_NPAPI_H__
+#define OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_NPAPI_H__
+
+#include "omaha/plugins/oneclick_browser_callback.h"
+
+namespace omaha {
+
+class OneClickBrowserCallbackNpapi : public OneClickBrowserCallback {
+ public:
+  OneClickBrowserCallbackNpapi();
+  virtual ~OneClickBrowserCallbackNpapi();
+
+  // Initializes the callback class with the NPP and two NPVariant values which
+  // represent the Javascript functions to be called.  NPAPI passes Javascript
+  // functions as an NPObject wrapped within an NPVariant.
+  // The NPVariant parameters are optional (can be internally NULL) which means
+  // we won't call a function in those cases.
+  HRESULT Initialize(NPP npp,
+                     NPVariant success_callback,
+                     NPVariant failure_callback);
+
+  // Overrides from abstract base class.
+  virtual void DoSuccessCallback();
+  virtual void DoFailureCallback(HRESULT hr_error);
+
+ private:
+  NPP npp_;
+  NPObject* success_callback_;
+  NPObject* failure_callback_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(OneClickBrowserCallbackNpapi);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_PLUGINS_ONECLICK_BROWSER_CALLBACK_NPAPI_H__
+
diff --git a/plugins/oneclick_idl.idl b/plugins/oneclick_idl.idl
index 3e01bd6..b21e3ed 100644
--- a/plugins/oneclick_idl.idl
+++ b/plugins/oneclick_idl.idl
@@ -1,81 +1,81 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Template IDL file for the OneClick ActiveX control. This template is a

-// complete IDL file in all but one respect; It has one replaceable entry

-// for the CLSID for GoopdateOneClickControl. This template is processed by

-// generate_oneclick_idl.py, which generates a GUID using UUIDGEN.EXE, and

-// writes out a (now complete) IDL file with the new CLSID.

-//

-// Background Information:

-// We generate new CLSIDs for each fresh build of Omaha. But we keep the MIME

-// Type constant, as long as we do not change the interface for the control.

-// The control is created with an OBJECT tag of the form:

-//   <OBJECT ID="OneClickCtrl" TYPE="application/x-vnd.Google.OneClickCtrl.1">

-//   </OBJECT>

-// And we register under HKCR\MIME\Database\ContentType, where we keep the MIME

-// type constant, but change the CLSID with each build. This allows us to "hot

-// swap" the control, and we don't face the issue of IE always using the older

-// version of the control unless it is restarted.

-

-import "oaidl.idl";

-import "ocidl.idl";

-

-[

-  object,

-  uuid(65CAE76D-A7FC-4629-A7C3-9AF61876894B),

-  dual,

-  helpstring("Google Update One Click Control Automation Interface"),

-  pointer_default(unique)

-]

-interface IGoogleUpdateOneClick : IDispatch

-{

-  // Deprecated. Will be removed in the next release of OneClick.

-  [id(1), helpstring("Install")] HRESULT Install(

-      [in] BSTR cmd_line_args,

-      [in] VARIANT* success_callback,

-      [in] VARIANT* failure_callback);

-

-  // New, easier way of calling Install. Use this for newer web pages.

-  [id(2), helpstring("Install2")] HRESULT Install2([in] BSTR extra_args);

-

-  [id(3), helpstring("GetInstalledVersion")] HRESULT GetInstalledVersion(

-      [in] BSTR guid_string,

-      [in] VARIANT_BOOL is_machine,

-      [out, retval] BSTR* version_string);

-

-  [id(4), helpstring("GetOneClickVersion")] HRESULT GetOneClickVersion(

-      [out, retval] long* version);

-};

-

-[

-  uuid(BBEFAF3A-5D73-4cc5-A2A1-34E5C55169B0),

-  version(1.0),

-  helpstring("Google Update One Click 1.0 Type Library")

-]

-library OneClickLib

-{

-  importlib("stdole2.tlb");

-  importlib("stdole32.tlb");

-

-  [

-    uuid(%s),

-    helpstring("Google Update One Click Control Class")

-  ]

-  coclass GoopdateOneClickControl

-  {

-    [default] interface IGoogleUpdateOneClick;

-  };

-};

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Template IDL file for the OneClick ActiveX control. This template is a
+// complete IDL file in all but one respect; It has one replaceable entry
+// for the CLSID for GoopdateOneClickControl. This template is processed by
+// generate_oneclick_idl.py, which generates a GUID using UUIDGEN.EXE, and
+// writes out a (now complete) IDL file with the new CLSID.
+//
+// Background Information:
+// We generate new CLSIDs for each fresh build of Omaha. But we keep the MIME
+// Type constant, as long as we do not change the interface for the control.
+// The control is created with an OBJECT tag of the form:
+//   <OBJECT ID="OneClickCtrl" TYPE="application/x-vnd.Google.OneClickCtrl.1">
+//   </OBJECT>
+// And we register under HKCR\MIME\Database\ContentType, where we keep the MIME
+// type constant, but change the CLSID with each build. This allows us to "hot
+// swap" the control, and we don't face the issue of IE always using the older
+// version of the control unless it is restarted.
+
+import "oaidl.idl";
+import "ocidl.idl";
+
+[
+  object,
+  uuid(65CAE76D-A7FC-4629-A7C3-9AF61876894B),
+  dual,
+  helpstring("Google Update One Click Control Automation Interface"),
+  pointer_default(unique)
+]
+interface IGoogleUpdateOneClick : IDispatch
+{
+  // Deprecated. Will be removed in the next release of OneClick.
+  [id(1), helpstring("Install")] HRESULT Install(
+      [in] BSTR cmd_line_args,
+      [in] VARIANT* success_callback,
+      [in] VARIANT* failure_callback);
+
+  // New, easier way of calling Install. Use this for newer web pages.
+  [id(2), helpstring("Install2")] HRESULT Install2([in] BSTR extra_args);
+
+  [id(3), helpstring("GetInstalledVersion")] HRESULT GetInstalledVersion(
+      [in] BSTR guid_string,
+      [in] VARIANT_BOOL is_machine,
+      [out, retval] BSTR* version_string);
+
+  [id(4), helpstring("GetOneClickVersion")] HRESULT GetOneClickVersion(
+      [out, retval] long* version);
+};
+
+[
+  uuid(BBEFAF3A-5D73-4cc5-A2A1-34E5C55169B0),
+  version(1.0),
+  helpstring("Google Update One Click 1.0 Type Library")
+]
+library OneClickLib
+{
+  importlib("stdole2.tlb");
+  importlib("stdole32.tlb");
+
+  [
+    uuid(%s),
+    helpstring("Google Update One Click Control Class")
+  ]
+  coclass GoopdateOneClickControl
+  {
+    [default] interface IGoogleUpdateOneClick;
+  };
+};
diff --git a/plugins/oneclick_worker.cc b/plugins/oneclick_worker.cc
index 92d2cb4..893d460 100644
--- a/plugins/oneclick_worker.cc
+++ b/plugins/oneclick_worker.cc
@@ -1,287 +1,287 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// OneClick worker to handle threads and manage callbacks to the browser.

-

-#include "omaha/plugins/oneclick_worker.h"

-

-#include <dispex.h>

-#include <wininet.h>

-#include <atlbase.h>

-#include <atlcom.h>

-

-#include "omaha/common/app_util.h"

-#include "omaha/common/atl_regexp.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/string.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/webplugin_utils.h"

-#include "omaha/worker/application_manager.h"

-

-#define INITGUID

-#include <guiddef.h>  // NOLINT

-

-namespace omaha {

-

-const TCHAR* site_lock_pattern_strings[] = {

-  _T("^https?://(gears)|(mail)|(tools)|(www)|(desktop)\\.google\\.com/"),

-  _T("^https?://www\\.google\\.(ad)|(bg)|(ca)|(cn)|(cz)|(de)|(es)|(fi)|(fr)|(gr)|(hr)|(hu)|(it)|(ki)|(kr)|(lt)|(lv)|(nl)|(no)|(pl)|(pt)|(ro)|(ru)|(sk)|(sg)|(sl)|(sr)|(vn)/"),  // NOLINT

-  _T("^https?://www\\.google\\.co\\.(hu)|(id)|(il)|(it)|(jp)|(kr)|(th)|(uk)/"),

-  _T("^https?://www\\.google\\.com\\.(ar)|(au)|(br)|(cn)|(et)|(gr)|(hr)|(ki)|(lv)|(om)|(pl)|(pt)|(ru)|(sg)|(sv)|(tr)|(vn)/"),  // NOLINT

-};

-

-typedef std::vector<AtlRegExp*> HostRegexp;

-

-class SiteLockPatterns {

- public:

-  SiteLockPatterns() {}

-  ~SiteLockPatterns();

-  bool AddPattern(const CString& host_pattern);

-  bool Match(const CString& url);

-

- private:

-  HostRegexp hosts_;

-};

-

-bool SiteLockPatterns::AddPattern(const CString& host_pattern) {

-  scoped_ptr<AtlRegExp> regex(new AtlRegExp);

-  REParseError error = regex->Parse(host_pattern);

-  if (error != REPARSE_ERROR_OK) {

-    return false;

-  }

-

-  hosts_.push_back(regex.release());

-  return true;

-}

-

-bool SiteLockPatterns::Match(const CString& url) {

-  if (url.IsEmpty()) {

-    return false;

-  }

-

-  ASSERT1(!hosts_.empty());

-  for (size_t i = 0; i < hosts_.size(); ++i) {

-    AtlMatchContext url_match;

-    if (hosts_[i]->Match(url, &url_match)) {

-      return true;

-    }

-  }

-

-  return false;

-}

-

-SiteLockPatterns::~SiteLockPatterns() {

-  for (size_t i = 0; i < hosts_.size(); ++i) {

-    delete hosts_[i];

-  }

-}

-

-OneClickWorker::OneClickWorker() {

-  CORE_LOG(L2, (_T("OneClickWorker::OneClickWorker()")));

-

-  site_lock_patterns_.reset(new SiteLockPatterns());

-  // TODO(Omaha): Download new patterns on the fly.

-  for (int i = 0; i < arraysize(site_lock_pattern_strings); ++i) {

-    VERIFY1(site_lock_patterns_->AddPattern(site_lock_pattern_strings[i]));

-  }

-

-  CString update_dev_host_pattern;

-  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                 kRegValueOneClickHostPattern,

-                                 &update_dev_host_pattern)) &&

-      !update_dev_host_pattern.IsEmpty()) {

-    VERIFY1(site_lock_patterns_->AddPattern(update_dev_host_pattern));

-  }

-}

-

-OneClickWorker::~OneClickWorker() {

-  CORE_LOG(L2, (_T("OneClickWorker::~OneClickWorker()")));

-}

-

-HRESULT OneClickWorker::Initialize() {

-  CORE_LOG(L2, (_T("[OneClickWorker::Initialize]")));

-

-  return S_OK;

-}

-

-HRESULT OneClickWorker::Shutdown() {

-  CORE_LOG(L2, (_T("[OneClickWorker::Shutdown]")));

-

-  return S_OK;

-}

-

-bool OneClickWorker::InApprovedDomain() {

-  ASSERT1(!browser_url_.IsEmpty());

-  return site_lock_patterns_->Match(browser_url_);

-}

-

-HRESULT OneClickWorker::DoOneClickInstall(

-    const TCHAR* cmd_line_args,

-    OneClickBrowserCallback* browser_callback) {

-  CORE_LOG(L2, (_T("[OneClickWorker::DoOneClickInstall]")

-                _T("[cmd_line_args=%s][browser_url=%s]"),

-                cmd_line_args, browser_url_));

-  ASSERT1(browser_callback);

-

-  HRESULT hr = DoOneClickInstallInternal(cmd_line_args);

-  if (SUCCEEDED(hr)) {

-    browser_callback->DoSuccessCallback();

-  } else {

-    CORE_LOG(LE, (_T("[DoOneClickInstallInternal failed][0x%x]"), hr));

-    browser_callback->DoFailureCallback(hr);

-  }

-

-  // Return success in all cases. The failure callback has already been called

-  // above, and we don't want to cause a failure path to be called again when

-  // the JavaScript catches the exception.

-  return S_OK;

-}

-

-HRESULT OneClickWorker::DoOneClickInstall2(const TCHAR* extra_args) {

-  CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL);

-  builder.set_extra_args(extra_args);

-  return DoOneClickInstallInternal(builder.GetCommandLineArgs());

-}

-

-HRESULT OneClickWorker::DoOneClickInstallInternal(const TCHAR* cmd_line_args) {

-  if (!InApprovedDomain()) {

-    return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED;

-  }

-

-#ifdef _DEBUG

-  // If the args are exactly __DIRECTNOTIFY__ then just fire the event

-  // out of this thread.  This allows for easy testing of the

-  // browser interface without requiring launch of

-  // google_update.exe.

-  if (0 == _wcsicmp(L"__DIRECTNOTIFY__", cmd_line_args)) {

-    return S_OK;

-  }

-#endif

-

-  HRESULT hr = webplugin_utils::VerifyResourceLanguage(cmd_line_args);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[VerifyResourceLanguage failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  CString url_domain;

-  hr = GetUrlDomain(browser_url_, &url_domain);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString url_domain_encoded;

-  CString cmd_line_args_encoded;

-  hr = StringEscape(url_domain, false, &url_domain_encoded);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = StringEscape(cmd_line_args, false, &cmd_line_args_encoded);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CommandLineBuilder builder(COMMANDLINE_MODE_WEBPLUGIN);

-  builder.set_webplugin_url_domain(url_domain_encoded);

-  builder.set_webplugin_args(cmd_line_args_encoded);

-  builder.set_install_source(kCmdLineInstallSource_OneClick);

-  CString final_cmd_line_args = builder.GetCommandLineArgs();

-

-  CORE_LOG(L2, (_T("[OneClickWorker::DoOneClickInstallInternal]")

-                _T("[Final command line params: %s]"),

-                final_cmd_line_args));

-

-  scoped_process process_goopdate;

-

-  hr = goopdate_utils::StartGoogleUpdateWithArgs(

-          goopdate_utils::IsRunningFromOfficialGoopdateDir(true),

-          final_cmd_line_args,

-          address(process_goopdate));

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[OneClickWorker::DoOneClickInstallInternal]")

-                  _T("[Failed StartGoogleUpdateWithArgs: 0x%x"),

-                  hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT OneClickWorker::GetInstalledVersion(const TCHAR* guid_string,

-                                            bool is_machine,

-                                            CString* version_string) {

-  CORE_LOG(L2, (_T("[GoopdateCtrl::GetInstalledVersion][%s][%d]"),

-                guid_string, is_machine));

-  if (!InApprovedDomain()) {

-    return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED;

-  }

-

-  ASSERT1(version_string);

-  version_string->Empty();

-

-  AppManager app_manager(is_machine);

-  ProductData product_data;

-  HRESULT hr = app_manager.ReadProductDataFromStore(StringToGuid(guid_string),

-                                                    &product_data);

-  if (SUCCEEDED(hr) && !product_data.app_data().is_uninstalled()) {

-    *version_string = product_data.app_data().version();

-  }

-  return S_OK;

-}

-

-HRESULT OneClickWorker::GetOneClickVersion(long* version) {   // NOLINT

-  CORE_LOG(L2, (_T("[OneClickWorker::GetOneClickVersion]")));

-  if (!InApprovedDomain()) {

-    return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED;

-  }

-

-  if (!version) {

-    return E_POINTER;

-  }

-

-  *version = atoi(ACTIVEX_VERSION_ANSI);  // NOLINT

-  return S_OK;

-}

-

-HRESULT OneClickWorker::GetUrlDomain(const CString& url, CString* url_domain) {

-  ASSERT1(url_domain);

-  url_domain->Empty();

-

-  URL_COMPONENTS urlComponents = {0};

-  urlComponents.dwStructSize = sizeof(urlComponents);

-  urlComponents.dwSchemeLength = 1;

-  urlComponents.dwHostNameLength = 1;

-  if (!::InternetCrackUrl(url, 0, 0, &urlComponents)) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(L2, (_T("[OneClickWorker failed InternetCrackUrl hr=0x%x]"), hr));

-    return hr;

-  }

-

-  CString scheme(urlComponents.lpszScheme, urlComponents.dwSchemeLength);

-  CString host_name(urlComponents.lpszHostName, urlComponents.dwHostNameLength);

-  ASSERT1(!scheme.IsEmpty());

-  ASSERT1(!host_name.IsEmpty());

-

-  url_domain->Format(_T("%s://%s/"), scheme, host_name);

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// OneClick worker to handle threads and manage callbacks to the browser.
+
+#include "omaha/plugins/oneclick_worker.h"
+
+#include <dispex.h>
+#include <wininet.h>
+#include <atlbase.h>
+#include <atlcom.h>
+
+#include "omaha/common/app_util.h"
+#include "omaha/common/atl_regexp.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/string.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/webplugin_utils.h"
+#include "omaha/worker/application_manager.h"
+
+#define INITGUID
+#include <guiddef.h>  // NOLINT
+
+namespace omaha {
+
+const TCHAR* site_lock_pattern_strings[] = {
+  _T("^https?://(gears)|(mail)|(tools)|(www)|(desktop)\\.google\\.com/"),
+  _T("^https?://www\\.google\\.(ad)|(bg)|(ca)|(cn)|(cz)|(de)|(es)|(fi)|(fr)|(gr)|(hr)|(hu)|(it)|(ki)|(kr)|(lt)|(lv)|(nl)|(no)|(pl)|(pt)|(ro)|(ru)|(sk)|(sg)|(sl)|(sr)|(vn)/"),  // NOLINT
+  _T("^https?://www\\.google\\.co\\.(hu)|(id)|(il)|(it)|(jp)|(kr)|(th)|(uk)/"),
+  _T("^https?://www\\.google\\.com\\.(ar)|(au)|(br)|(cn)|(et)|(gr)|(hr)|(ki)|(lv)|(om)|(pl)|(pt)|(ru)|(sg)|(sv)|(tr)|(vn)/"),  // NOLINT
+};
+
+typedef std::vector<AtlRegExp*> HostRegexp;
+
+class SiteLockPatterns {
+ public:
+  SiteLockPatterns() {}
+  ~SiteLockPatterns();
+  bool AddPattern(const CString& host_pattern);
+  bool Match(const CString& url);
+
+ private:
+  HostRegexp hosts_;
+};
+
+bool SiteLockPatterns::AddPattern(const CString& host_pattern) {
+  scoped_ptr<AtlRegExp> regex(new AtlRegExp);
+  REParseError error = regex->Parse(host_pattern);
+  if (error != REPARSE_ERROR_OK) {
+    return false;
+  }
+
+  hosts_.push_back(regex.release());
+  return true;
+}
+
+bool SiteLockPatterns::Match(const CString& url) {
+  if (url.IsEmpty()) {
+    return false;
+  }
+
+  ASSERT1(!hosts_.empty());
+  for (size_t i = 0; i < hosts_.size(); ++i) {
+    AtlMatchContext url_match;
+    if (hosts_[i]->Match(url, &url_match)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+SiteLockPatterns::~SiteLockPatterns() {
+  for (size_t i = 0; i < hosts_.size(); ++i) {
+    delete hosts_[i];
+  }
+}
+
+OneClickWorker::OneClickWorker() {
+  CORE_LOG(L2, (_T("OneClickWorker::OneClickWorker()")));
+
+  site_lock_patterns_.reset(new SiteLockPatterns());
+  // TODO(Omaha): Download new patterns on the fly.
+  for (int i = 0; i < arraysize(site_lock_pattern_strings); ++i) {
+    VERIFY1(site_lock_patterns_->AddPattern(site_lock_pattern_strings[i]));
+  }
+
+  CString update_dev_host_pattern;
+  if (SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                 kRegValueOneClickHostPattern,
+                                 &update_dev_host_pattern)) &&
+      !update_dev_host_pattern.IsEmpty()) {
+    VERIFY1(site_lock_patterns_->AddPattern(update_dev_host_pattern));
+  }
+}
+
+OneClickWorker::~OneClickWorker() {
+  CORE_LOG(L2, (_T("OneClickWorker::~OneClickWorker()")));
+}
+
+HRESULT OneClickWorker::Initialize() {
+  CORE_LOG(L2, (_T("[OneClickWorker::Initialize]")));
+
+  return S_OK;
+}
+
+HRESULT OneClickWorker::Shutdown() {
+  CORE_LOG(L2, (_T("[OneClickWorker::Shutdown]")));
+
+  return S_OK;
+}
+
+bool OneClickWorker::InApprovedDomain() {
+  ASSERT1(!browser_url_.IsEmpty());
+  return site_lock_patterns_->Match(browser_url_);
+}
+
+HRESULT OneClickWorker::DoOneClickInstall(
+    const TCHAR* cmd_line_args,
+    OneClickBrowserCallback* browser_callback) {
+  CORE_LOG(L2, (_T("[OneClickWorker::DoOneClickInstall]")
+                _T("[cmd_line_args=%s][browser_url=%s]"),
+                cmd_line_args, browser_url_));
+  ASSERT1(browser_callback);
+
+  HRESULT hr = DoOneClickInstallInternal(cmd_line_args);
+  if (SUCCEEDED(hr)) {
+    browser_callback->DoSuccessCallback();
+  } else {
+    CORE_LOG(LE, (_T("[DoOneClickInstallInternal failed][0x%x]"), hr));
+    browser_callback->DoFailureCallback(hr);
+  }
+
+  // Return success in all cases. The failure callback has already been called
+  // above, and we don't want to cause a failure path to be called again when
+  // the JavaScript catches the exception.
+  return S_OK;
+}
+
+HRESULT OneClickWorker::DoOneClickInstall2(const TCHAR* extra_args) {
+  CommandLineBuilder builder(COMMANDLINE_MODE_INSTALL);
+  builder.set_extra_args(extra_args);
+  return DoOneClickInstallInternal(builder.GetCommandLineArgs());
+}
+
+HRESULT OneClickWorker::DoOneClickInstallInternal(const TCHAR* cmd_line_args) {
+  if (!InApprovedDomain()) {
+    return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED;
+  }
+
+#ifdef _DEBUG
+  // If the args are exactly __DIRECTNOTIFY__ then just fire the event
+  // out of this thread.  This allows for easy testing of the
+  // browser interface without requiring launch of
+  // google_update.exe.
+  if (0 == _wcsicmp(L"__DIRECTNOTIFY__", cmd_line_args)) {
+    return S_OK;
+  }
+#endif
+
+  HRESULT hr = webplugin_utils::VerifyResourceLanguage(cmd_line_args);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[VerifyResourceLanguage failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  CString url_domain;
+  hr = GetUrlDomain(browser_url_, &url_domain);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString url_domain_encoded;
+  CString cmd_line_args_encoded;
+  hr = StringEscape(url_domain, false, &url_domain_encoded);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = StringEscape(cmd_line_args, false, &cmd_line_args_encoded);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CommandLineBuilder builder(COMMANDLINE_MODE_WEBPLUGIN);
+  builder.set_webplugin_url_domain(url_domain_encoded);
+  builder.set_webplugin_args(cmd_line_args_encoded);
+  builder.set_install_source(kCmdLineInstallSource_OneClick);
+  CString final_cmd_line_args = builder.GetCommandLineArgs();
+
+  CORE_LOG(L2, (_T("[OneClickWorker::DoOneClickInstallInternal]")
+                _T("[Final command line params: %s]"),
+                final_cmd_line_args));
+
+  scoped_process process_goopdate;
+
+  hr = goopdate_utils::StartGoogleUpdateWithArgs(
+          goopdate_utils::IsRunningFromOfficialGoopdateDir(true),
+          final_cmd_line_args,
+          address(process_goopdate));
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[OneClickWorker::DoOneClickInstallInternal]")
+                  _T("[Failed StartGoogleUpdateWithArgs: 0x%x"),
+                  hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT OneClickWorker::GetInstalledVersion(const TCHAR* guid_string,
+                                            bool is_machine,
+                                            CString* version_string) {
+  CORE_LOG(L2, (_T("[GoopdateCtrl::GetInstalledVersion][%s][%d]"),
+                guid_string, is_machine));
+  if (!InApprovedDomain()) {
+    return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED;
+  }
+
+  ASSERT1(version_string);
+  version_string->Empty();
+
+  AppManager app_manager(is_machine);
+  ProductData product_data;
+  HRESULT hr = app_manager.ReadProductDataFromStore(StringToGuid(guid_string),
+                                                    &product_data);
+  if (SUCCEEDED(hr) && !product_data.app_data().is_uninstalled()) {
+    *version_string = product_data.app_data().version();
+  }
+  return S_OK;
+}
+
+HRESULT OneClickWorker::GetOneClickVersion(long* version) {   // NOLINT
+  CORE_LOG(L2, (_T("[OneClickWorker::GetOneClickVersion]")));
+  if (!InApprovedDomain()) {
+    return GOOPDATE_E_ONECLICK_HOSTCHECK_FAILED;
+  }
+
+  if (!version) {
+    return E_POINTER;
+  }
+
+  *version = atoi(ACTIVEX_VERSION_ANSI);  // NOLINT
+  return S_OK;
+}
+
+HRESULT OneClickWorker::GetUrlDomain(const CString& url, CString* url_domain) {
+  ASSERT1(url_domain);
+  url_domain->Empty();
+
+  URL_COMPONENTS urlComponents = {0};
+  urlComponents.dwStructSize = sizeof(urlComponents);
+  urlComponents.dwSchemeLength = 1;
+  urlComponents.dwHostNameLength = 1;
+  if (!::InternetCrackUrl(url, 0, 0, &urlComponents)) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(L2, (_T("[OneClickWorker failed InternetCrackUrl hr=0x%x]"), hr));
+    return hr;
+  }
+
+  CString scheme(urlComponents.lpszScheme, urlComponents.dwSchemeLength);
+  CString host_name(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
+  ASSERT1(!scheme.IsEmpty());
+  ASSERT1(!host_name.IsEmpty());
+
+  url_domain->Format(_T("%s://%s/"), scheme, host_name);
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/plugins/oneclick_worker.h b/plugins/oneclick_worker.h
index aefcaaa..f9c2f7e 100644
--- a/plugins/oneclick_worker.h
+++ b/plugins/oneclick_worker.h
@@ -1,76 +1,76 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// OneClick worker class shared by the different plugin architectures.

-// This class does most of the OneClick heavy lifting.

-

-#ifndef OMAHA_PLUGINS_ONECLICK_WORKER_H__

-#define OMAHA_PLUGINS_ONECLICK_WORKER_H__

-

-#include <windows.h>

-

-#include "base/scoped_ptr.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/plugins/oneclick_browser_callback.h"

-

-namespace omaha {

-

-class SiteLockPatterns;

-

-class OneClickWorker {

- public:

-  OneClickWorker();

-  ~OneClickWorker();

-

-  HRESULT Initialize();

-  HRESULT Shutdown();

-

-  // Performs a OneClick install.

-  // cmd_line_args - arguments to eventually be passed to googleupdate.exe.

-  // browser_callback - Callback class to fire success/failure events to.

-  // NOTE:  OneClickWorker assumes memory ownership of browser_callback.

-  HRESULT DoOneClickInstall(const TCHAR* cmd_line_args,

-                            OneClickBrowserCallback* browser_callback);

-  // The incoming extra_args are used to construct an "/install" command line.

-  HRESULT DoOneClickInstall2(const TCHAR* extra_args);

-

-  HRESULT GetInstalledVersion(const TCHAR* guid_string,

-                              bool is_machine,

-                              CString* version_string);

-

-  HRESULT GetOneClickVersion(long* version);

-

-  bool InApprovedDomain();

-

-  void set_browser_url(const TCHAR* browser_url) {

-    browser_url_ = browser_url;

-    browser_url_.MakeLower();

-  }

-

- private:

-  HRESULT DoOneClickInstallInternal(const TCHAR* cmd_line_args);

-  HRESULT GetUrlDomain(const CString& url, CString* url_domain);

-

-  CString browser_url_;

-  scoped_ptr<SiteLockPatterns> site_lock_patterns_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(OneClickWorker);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_PLUGINS_ONECLICK_WORKER_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// OneClick worker class shared by the different plugin architectures.
+// This class does most of the OneClick heavy lifting.
+
+#ifndef OMAHA_PLUGINS_ONECLICK_WORKER_H__
+#define OMAHA_PLUGINS_ONECLICK_WORKER_H__
+
+#include <windows.h>
+
+#include "base/scoped_ptr.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/plugins/oneclick_browser_callback.h"
+
+namespace omaha {
+
+class SiteLockPatterns;
+
+class OneClickWorker {
+ public:
+  OneClickWorker();
+  ~OneClickWorker();
+
+  HRESULT Initialize();
+  HRESULT Shutdown();
+
+  // Performs a OneClick install.
+  // cmd_line_args - arguments to eventually be passed to googleupdate.exe.
+  // browser_callback - Callback class to fire success/failure events to.
+  // NOTE:  OneClickWorker assumes memory ownership of browser_callback.
+  HRESULT DoOneClickInstall(const TCHAR* cmd_line_args,
+                            OneClickBrowserCallback* browser_callback);
+  // The incoming extra_args are used to construct an "/install" command line.
+  HRESULT DoOneClickInstall2(const TCHAR* extra_args);
+
+  HRESULT GetInstalledVersion(const TCHAR* guid_string,
+                              bool is_machine,
+                              CString* version_string);
+
+  HRESULT GetOneClickVersion(long* version);
+
+  bool InApprovedDomain();
+
+  void set_browser_url(const TCHAR* browser_url) {
+    browser_url_ = browser_url;
+    browser_url_.MakeLower();
+  }
+
+ private:
+  HRESULT DoOneClickInstallInternal(const TCHAR* cmd_line_args);
+  HRESULT GetUrlDomain(const CString& url, CString* url_domain);
+
+  CString browser_url_;
+  scoped_ptr<SiteLockPatterns> site_lock_patterns_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(OneClickWorker);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_PLUGINS_ONECLICK_WORKER_H__
+
diff --git a/plugins/resource.h b/plugins/resource.h
index 6ea8689..ac22f29 100644
--- a/plugins/resource.h
+++ b/plugins/resource.h
@@ -1,25 +1,25 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Symbol definitions for the OneClick DLL resources.

-

-#ifndef OMAHA_PLUGINS_RESOURCE_H__

-#define OMAHA_PLUGINS_RESOURCE_H__

-

-// The id of the ATL COM registration script

-#define IDR_ONECLICK              100

-

-#endif  // OMAHA_PLUGINS_RESOURCE_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Symbol definitions for the OneClick DLL resources.
+
+#ifndef OMAHA_PLUGINS_RESOURCE_H__
+#define OMAHA_PLUGINS_RESOURCE_H__
+
+// The id of the ATL COM registration script
+#define IDR_ONECLICK              100
+
+#endif  // OMAHA_PLUGINS_RESOURCE_H__
+
diff --git a/plugins/resource.rc b/plugins/resource.rc
index 0e6d766..54fe76c 100644
--- a/plugins/resource.rc
+++ b/plugins/resource.rc
@@ -1,37 +1,37 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// One-Click resource file.

-

-

-

-#include "common/const_config.h"

-

-#define MIME_TYPE kOneClickPluginMimeTypeAnsi

-

-#include "goopdate/goopdate_version.rc"

-

-

-// COM type library.

-// This MIDL-generated file goes under /build/MODE/obj, which is in our RC path

-1             TYPELIB   "plugins\\oneclick_idl.tlb"

-

-#include "omaha/goopdate/resource.h"

-

-// ATL COM registration file.

-100              REGISTRY        "oneclick.rgs"

-

-

-

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// One-Click resource file.
+
+
+
+#include "common/const_config.h"
+
+#define MIME_TYPE kOneClickPluginMimeTypeAnsi
+
+#include "goopdate/goopdate_version.rc"
+
+
+// COM type library.
+// This MIDL-generated file goes under /build/MODE/obj, which is in our RC path
+1             TYPELIB   "plugins\\oneclick_idl.tlb"
+
+#include "omaha/goopdate/resource.h"
+
+// ATL COM registration file.
+100              REGISTRY        "oneclick.rgs"
+
+
+
diff --git a/plugins/sitelock.h b/plugins/sitelock.h
index 3ac34f1..7449fcf 100644
--- a/plugins/sitelock.h
+++ b/plugins/sitelock.h
@@ -1,1049 +1,1049 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// note:  this file is originally from Microsoft for SiteLock, but has been

-// modified to support getting the browser URL via NPAPI so we can use this

-// for validating within Firefox and other browsers as well

-

-#ifndef OMAHA_PLUGINS_SITELOCK_H__

-#define OMAHA_PLUGINS_SITELOCK_H__

-

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

-// SiteLock 1.14

-// ATL sample code for restricting activation of ActiveX controls.

-// Copyright Microsoft Corporation. All rights reserved.

-// Last updated: July 19 2007

-

-

-// Includes

-#include <atlctl.h>

-#include <comdef.h>

-#include <shlguid.h>

-#include <dispex.h>   // IObjectIdentity

-

-// Pragmas

-#pragma once

-

-#include "common/logging.h"

-// Version information

-#define SITELOCK_VERSION 0x00010014   // 1.14

-

-#ifdef SITELOCK_SUPPORT_DOWNLOAD

-#pragma message("sitelock.h : This version of SiteLock " \

-                "does not support downloading.")

-#endif

-

-// Overview:

-// To enable scripting, developers must declare their ActiveX controls as

-// "safe for scripting".

-// This is done by implementing interface IObjectSafety, which comes with very

-// important safety assumptions. Once marked as "safe for scripting", ActiveX

-// controls may be activated by untrusted web sites. Therefore "safe for

-// scripting" controls must guarantee all their methods are safe regardless of

-// the activation context. Practically however, it may not be possible for an

-// ActiveX control to guarantee safety in all activation contexts. The site lock

-// framework allows developers to specify which zones and domains can

-// instantiate ActiveX controls. For example, this may allow a developer

-// to implement methods that can only be called if the activation context is the

-// intranet zone.

-

-// Usage:

-// 1/ Include current header file sitelock.h (after including ATL header files).

-//

-// 2/ Derive from "public IObjectSafetySiteLockImpl

-//                   <CYourClass, INTERFACESAFE_FOR...>,".

-//    This replaces the default IObjectSafetyImpl interface implementation.

-//

-// 3/ Add the following to your control's COM map:

-//    COM_INTERFACE_ENTRY(IObjectSafety)

-//    COM_INTERFACE_ENTRY(IObjectSafetySiteLock)

-//

-// 4/ Add one of the following to specify allowed activation contexts:

-//    a) A public (or friend) member variable, for example:

-//    const CYourClass::SiteList CYourClass::rgslTrustedSites[6] =

-//       {{ SiteList::Deny,  L"http",  L"users.microsoft.com" },

-//        { SiteList::Allow, L"http",  L"microsoft com"       },

-//        { SiteList::Allow, L"http",  SITELOCK_INTRANET_ZONE },

-//        { SiteList::Deny,  L"https", L"users.microsoft.com" },

-//        { SiteList::Allow, L"https", L"microsoft.com"       },

-//        { SiteList::Allow, L"https", SITELOCK_INTRANET_ZONE }};

-//

-//    b) A set of site lock macros, for example:

-//    #define SITELOCK_USE_MAP (prior to including sitelock.h)

-//    BEGIN_SITELOCK_MAP()

-//        SITELOCK_DENYHTTP    ( L"users.microsoft.com" )

-//        SITELOCK_ALLOWHTTP  ( L"microsoft com"       )

-//        SITELOCK_ALLOWHTTP  ( SITELOCK_INTRANET_ZONE )

-//        SITELOCK_DENYHTTPS  ( L"users.microsoft.com" )

-//        SITELOCK_ALLOWHTTPS  ( L"microsoft.com"       )

-//        SITELOCK_ALLOWHTTPS  ( SITELOCK_INTRANET_ZONE )

-//    END_SITELOCK_MAP()

-//

-//    The examples above block "*.users.microsoft.com" sites (http and https).

-//    The examples above allow "*.microsoft.com" sites (http and https).

-//    The examples above allow intranet sites (http and https).

-//

-// 5/ Choose an expiry lifespan:

-//    You can specify the lifespan of your control one of two ways.

-//    By declaring an enumeration (slightly more efficient):

-//       enum { dwControlLifespan = (lifespan in days) };

-//    By declaring a member variable:

-//       static const DWORD dwControlLifespan = (lifespan in days);

-//    When in doubt, choose a shorter duration rather than a longer one.

-//    Expiration can be disabled by adding #define SITELOCK_NO_EXPIRY before

-//    including sitelock.h.

-//

-// 6/ Implement IObjectWithSite or IOleObject:

-//    IObjectWithSite is a lightweight interface able to indicate the

-//      activation URL to site lock.

-//    IOleObject is a heavier interface providing additional OLE capabilities.

-//    If you need IOleObject, add #define SITELOCK_USE_IOLEOBJECT before

-//      including sitelock.h.

-//    Otherwise, simply implement IObjectWithSite:

-//      - Derive from "IObjectWithSiteImpl<CYourClass>".

-//      - Add COM_INTERFACE_ENTRY(IObjectWithSite) to your control's COM map.

-//    You should never implement both IObjectWithSite and IOleObject.

-//

-// 7/ Link with urlmon.lib.

-

-// Detailed usage:

-//   --- Entries ---:

-//   Site lock entries are defined by the following elements:

-//   iAllowType is:

-//    SiteList::Allow:    allowed location

-//      SiteList::Deny:      blocked location

-//   szScheme is:

-//    L"http":        non-SSL location

-//    L"https":        SSL-enabled location

-//    Other:          in rare cases, the scheme may be outlook:, ms-help:, etc.

-//   szDomain is:

-//    Doman:          a string defining a domain

-//    Zone:          a constant specifying a zone

-//

-//    --- Ordering ---:

-//    Entries are matched in the order they appear in.

-//    The first entry that matches will be accepted.

-//    Deny entries should therefore be placed before allow entries.

-//

-//    --- Protocols ---:

-//    To support multiple protocols (http and https), define separate entries.

-//

-//    --- Domain names ---:

-//    This sample code performs a case-sensitive comparison after domain

-//    normalization. Whether domain normalization converts strings to lower

-//    case depends on the scheme provider.

-//

-//    If a domain does not contain any special indicator, only domains with the

-//    right suffix will match. For example:

-//    An entry of "microsoft.com" will match "microsoft.com".

-//      An entry of "microsoft.com" will match "office.microsoft.com"

-//      An entry of "microsoft.com" will not match "mymicrosoft.com"

-//    An entry of "microsoft.com" will not match "www.microsoft.com.hacker.com"

-//

-//    If a domain begins with "*.", only child domains will match.

-//    For example:

-//    An entry of "*.microsoft.com" will match "foo.microsoft.com".

-//    An entry of "*.microsoft.com" will not match "microsoft.com".

-//

-//    If a domain begins with "=", only the specified domain will match.

-//    For example:

-//    An entry of "=microsoft.com" will match "microsoft.com".

-//    An entry of "=microsoft.com" will not match "foo.microsoft.com".

-//

-//    If a domain is set to "*", all domains will match.

-//    This is useful to only restrict to specific schemes (ex: http vs. https).

-//

-//    If a domain name is NULL, then the scheme provider should return an error

-//    when asking for the domain. This is appropriate for protocols

-//    (outlook: or ms-help:) that do not use server names.

-//

-//    If a domain name is SITELOCK_INTRANET_ZONE, then any server in the

-//    Intranet zone will match. Due to a zone limitation, sites in the user's

-//    Trusted Sites list will also match. However, since Trusted Sites

-//    typically permit downloading and running of unsigned, unsafe controls,

-//    security is limited for those sites anyway.

-//

-//    If a domain name is SITELOCK_MYCOMPUTER_ZONE, then any page residing on

-//    the user's local machine will match.

-//

-//    If a domain name is SITELOCK_TRUSTED_ZONE, then any page residing in the

-//    user's Trusted Sites list will match.

-

-

-// Language checks

-#ifndef __cplusplus

-#error ATL Requires C++

-#endif

-

-// Windows constants

-#if (WINVER < 0x0600)

-#define IDN_USE_STD3_ASCII_RULES  0x02  // Enforce STD3 ASCII restrictions

-#endif

-

-// Function prototypes

-typedef int (WINAPI * PFN_IdnToAscii)(DWORD, LPCWSTR, int, LPWSTR, int);

-

-// Macros

-#ifndef cElements

-template<typename T> static char cElementsVerify(void const *, T) throw() {

-  return 0;

-}

-

-template<typename T> static void cElementsVerify(T *const, T *const *) throw() {

-};

-

-#define cElements(arr) (sizeof(cElementsVerify(arr, &(arr))) * \

-                        (sizeof(arr)/sizeof(*(arr))))

-#endif

-

-// Restrictions

-#define SITELOCK_INTRANET_ZONE    ((const OLECHAR *)-1)

-#define SITELOCK_MYCOMPUTER_ZONE  ((const OLECHAR *)-2)

-#define SITELOCK_TRUSTED_ZONE    ((const OLECHAR *)-3)

-

-#ifndef SITELOCK_NO_EXPIRY

-// Helper functions for expiry

-#if defined(_WIN64) && defined(_M_IA64)

-#pragma section(".base", long, read, write)           // NO_LINT

-extern "C" __declspec(allocate(".base")) extern IMAGE_DOS_HEADER __ImageBase;

-#else

-extern "C" IMAGE_DOS_HEADER __ImageBase;

-#endif

-#define ImageNtHeaders(pBase) ((PIMAGE_NT_HEADERS)((PCHAR)(pBase) + \

-                                    ((PIMAGE_DOS_HEADER)(pBase))->e_lfanew))

-

-#define LODWORD(_qw)    ((DWORD)(_qw))

-#define HIDWORD(_qw)    ((DWORD)(((_qw) >> 32) & 0xffffffff))

-inline void _UNIXTimeToFILETIME(time_t t, LPFILETIME ft) {

-  // The time_t is a 32-bit value for the number of seconds since

-  // January 1, 1970.

-  // A FILETIME is a 64-bit for the number of 100-nanosecond periods since

-  // January 1, 1601.

-  // Convert by multiplying the time_t value by 1e+7 to get to the same base

-  // granularity, then add the numeric equivalent of January 1, 1970 as

-  // FILETIME.

-

-  ULONGLONG qw = ((ULONGLONG)t * 10000000ui64) + 116444736000000000ui64;

-  ft->dwHighDateTime = HIDWORD(qw);

-  ft->dwLowDateTime = LODWORD(qw);

-}

-inline time_t _FILETIMEToUNIXTime(LPFILETIME ft) {

-  ULONGLONG qw = (((ULONGLONG)ft->dwHighDateTime)<<32) + ft->dwLowDateTime;

-  return (time_t)((qw - 116444736000000000ui64) / 10000000ui64);

-}

-#endif  // SITELOCK_NO_EXPIRY

-

-// Interface declaring "safe for scripting" methods with additional site lock

-// capabilities

-class __declspec(uuid("7FEB54AE-E3F9-40FC-AB5A-28A545C0F193"))

-    ATL_NO_VTABLE IObjectSafetySiteLock : public IObjectSafety {

- public:

-  // Site lock entry definition

-  struct SiteList {

-    enum SiteListCategory {

-      Allow,                // permit

-      Deny,                // disallow

-      Download              // OBSOLETE, do not use

-    } iAllowType;

-    const OLECHAR*    szScheme;    // scheme (http or https)

-    const OLECHAR*    szDomain;    // domain

-  };

-

-  // Capability definition

-  enum Capability {

-    CanDownload    = 0x00000001,  // OBSOLETE. Here for backwards compat only.

-    UsesIOleObject = 0x00000002,  // Use IOleObject instead of IObjectWithSite.

-    HasExpiry     = 0x00000004,  // Control will expire when lifespan elapsed.

-  };

-

-  // Returns capabilities (this can be used by testing tools to query for

-  // custom capabilities or version information)

-  STDMETHOD(GetCapabilities)(DWORD* pdwCapability) = 0;

-

-  // Returns site lock entries controlling activation

-  STDMETHOD(GetApprovedSites)(const SiteList** pSiteList, DWORD* cSites)  = 0;

-

-  // Returns lifespan as number of days and date (version 1.05 or higher)

-  STDMETHOD(GetExpiryDate)(DWORD* pdwLifespan, FILETIME* pExpiryDate)    = 0;

-};

-

-

-inline LPCTSTR const UrlZoneToString(DWORD dwZone) {

-  switch (dwZone) {

-    case URLZONE_LOCAL_MACHINE: return _T("URLZONE_LOCAL_MACHINE");

-    case URLZONE_INTRANET:      return _T("URLZONE_INTRANET");

-    case URLZONE_TRUSTED:       return _T("URLZONE_TRUSTED");

-    case URLZONE_INTERNET:      return _T("URLZONE_INTERNET");

-    case URLZONE_UNTRUSTED:     return _T("URLZONE_UNTRUSTED");

-    default:                    return _T("URLZONE_UNKNOWN");

-  }

-}

-

-bool AreObjectsEqual(IDispatch* disp1, IDispatch* disp2) {

-  // if the arguments are equal then the objects are equal

-  if (disp1 == disp2) return true;

-

-  // if the arguments are not equal, then compare the IUnknowns

-  if (disp1 && disp2) {

-    CComPtr<IUnknown> unk1;

-    CComPtr<IUnknown> unk2;

-    // This must always succeed.

-    VERIFY1(SUCCEEDED(disp1->QueryInterface(&unk1)));

-    VERIFY1(SUCCEEDED(disp2->QueryInterface(&unk2)));

-    ASSERT1(unk1 && unk2);

-

-    if (unk1 == unk2) return true;

-

-    // Not all the hope is lost. If the IUnknown pointers are different, try

-    // to query for object identity and use that to compare.

-    if (unk1 && unk2) {

-      CComPtr<IObjectIdentity> object_identity;

-      if (SUCCEEDED(unk1.QueryInterface(&object_identity))) {

-        if (object_identity) {

-          HRESULT hr = object_identity->IsEqualObject(unk2);

-          ASSERT(SUCCEEDED(hr), (_T("")));

-          return hr == S_OK;

-        }

-      }

-    }

-  }

-

-  return false;

-}

-

-

-#ifdef SITELOCK_USE_MAP

-// Site lock actual map entry macro

-#define SITELOCK_ALLOWHTTPS(domain) \

-    {IObjectSafetySiteLock::SiteList::Allow,  L"https",  domain},

-#define SITELOCK_DENYHTTPS(domain)  \

-    {IObjectSafetySiteLock::SiteList::Deny,    L"https",  domain},

-#define SITELOCK_ALLOWHTTP(domain)  \

-    {IObjectSafetySiteLock::SiteList::Allow,  L"http",  domain},

-#define SITELOCK_DENYHTTP(domain)   \

-    {IObjectSafetySiteLock::SiteList::Deny,    L"http",  domain},

-

-// Site lock begin map entry macro

-#define BEGIN_SITELOCK_MAP() \

-  static const IObjectSafetySiteLock::SiteList *                             \

-      GetSiteLockMapAndCount(DWORD* dwCount)                                 \

-{                                                                            \

-  static IObjectSafetySiteLock::SiteList rgslTrustedSites[] = {              \

-                                                                    // NO_LINT

-// Site lock end map entry macro

-#define END_SITELOCK_MAP()                                                   \

-{(IObjectSafetySiteLock::SiteList::SiteListCategory)0, 0, 0}};               \

-  *dwCount = cElements(rgslTrustedSites) - 1;                                \

-  return rgslTrustedSites;                                                   \

-}                                                                            \

-  static const IObjectSafetySiteLock::SiteList * GetSiteLockMap()            \

-{                                                                            \

-  DWORD dwCount = 0;                                                         \

-  return GetSiteLockMapAndCount(&dwCount);                                   \

-}                                                                            \

-  static DWORD GetSiteLockMapCount()                                         \

-{                                                                            \

-  DWORD dwCount = 0;                                                         \

-  GetSiteLockMapAndCount(&dwCount);                                          \

-  return dwCount;                                                            \

-}                                                                            \

-

-#endif  // SITELOCK_USE_MAP

-

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

-// CSiteLock - Site lock templated class

-template <typename T>

-class ATL_NO_VTABLE CSiteLock {

- public:

-#ifdef SITELOCK_NO_EXPIRY

-  bool ControlExpired(DWORD = 0)    { return false; }

-#else

-  bool ControlExpired(DWORD dwExpiresDays = T::dwControlLifespan) {

-    SYSTEMTIME st = {0};

-    FILETIME ft = {0};

-

-    GetSystemTime(&st);

-    if (!SystemTimeToFileTime(&st, &ft))

-      return true;

-

-    time_t ttTime = _FILETIMEToUNIXTime(&ft);

-    time_t ttExpire = ImageNtHeaders(&__ImageBase)->FileHeader.TimeDateStamp;

-    ttExpire += dwExpiresDays*86400;

-

-    return (ttTime > ttExpire);

-  }

-#endif

-

-#ifdef SITELOCK_USE_MAP

-  // Checks if the activation URL is in an allowed domain / zone

-  bool InApprovedDomain(

-      const IObjectSafetySiteLock::SiteList* rgslTrustedSites =

-          T::GetSiteLockMap(),

-      int cTrustedSites = T::GetSiteLockMapCount()) {

-#else

-  // Checks if the activation URL is in an allowed domain / zone

-  bool InApprovedDomain(

-      const IObjectSafetySiteLock::SiteList* rgslTrustedSites =

-          T::rgslTrustedSites,

-      int cTrustedSites = cElements(T::rgslTrustedSites)) {

-#endif

-    // Retrieve the activation URL

-    CComBSTR  bstrUrl;

-

-    if (!GetOurUrl(bstrUrl)) {

-      CORE_LOG(LEVEL_ERROR,

-               (_T("[CSiteLock::InApprovedDomain]")

-                _T("[unsafe: failed to get the url]")));

-      return false;

-    }

-

-    return InApprovedDomain(bstrUrl, rgslTrustedSites, cTrustedSites);

-  }

-

- protected:

-

-  // Retrieves the activation URL

-  bool GetOurUrl(BSTR* bstr_url) {

-    if (NULL == bstr_url) {

-      return false;

-    }

-    CComPtr<IServiceProvider> spSrvProv;

-    if (!GetServiceProvider(&spSrvProv)) {

-      return false;

-    }

-    ASSERT1(spSrvProv);

-

-    // See if we're hosted within IE

-    // Query the site for a web browser object

-    CComPtr<IWebBrowser2> spWebBrowser;

-    CComPtr<IHTMLDocument2> spHTMLDocument2;

-    HRESULT hr = spSrvProv->QueryService(

-        SID_SWebBrowserApp,

-        IID_IWebBrowser2,

-        reinterpret_cast<void**>(&spWebBrowser));

-

-    if (FAILED(hr)) {

-#ifdef SITELOCK_USE_IOLEOBJECT

-      return false;

-#else

-      // Local declarations

-      CComPtr<IOleContainer> spContainer;

-      CComPtr<IOleClientSite> spClientSite;

-

-      // Get the client site, container, document, and url.

-      T* pT = static_cast<T*>(this);

-      hr = pT->GetSite(IID_IOleClientSite,

-                       reinterpret_cast<void**>(&spClientSite));

-      if (FAILED(hr)) {

-        return false;

-      }

-      hr = spClientSite->GetContainer(&spContainer);

-      if (FAILED(hr)) {

-        return false;

-      }

-      hr = spContainer.QueryInterface(&spHTMLDocument2);

-      if (FAILED(hr)) {

-        return false;

-      }

-      if (FAILED(spHTMLDocument2->get_URL(bstr_url))) {

-        return false;

-      }

-#endif

-    } else {

-      ASSERT1(spWebBrowser);

-

-      CComPtr<IDispatch> spDocument;

-      hr = spWebBrowser->get_Document(&spDocument);

-      if (FAILED(hr) || !spDocument) {

-        return false;

-      }

-

-      hr = spDocument.QueryInterface(&spHTMLDocument2);

-      if (FAILED(hr) || !spHTMLDocument2) {

-        return false;

-      }

-

-      // Retrieves the URL of the document hosting the control.

-      hr = spHTMLDocument2->get_URL(bstr_url);

-      if (FAILED(hr) || !*bstr_url) {

-        return false;

-      }

-    }

-

-#ifdef DEBUG

-    // A little bit of debug code to dump the urls that we care about.

-    // Find out if this is a top level window or a frame.

-    CComPtr<IHTMLWindow2> spWindow;

-    hr = spHTMLDocument2->get_parentWindow(&spWindow);

-    if (FAILED(hr) || !spWindow) {

-      return false;

-    }

-

-    // Get our window. This is the window.self

-    CComPtr<IHTMLWindow2> spWindowCur;

-    hr = spWindow->get_self(&spWindowCur);

-    if (FAILED(hr) || !spWindowCur) {

-      return false;

-    }

-

-    // Get the top level window.

-    CComPtr<IHTMLWindow2> spWindowTop;

-    hr = spWindow->get_top(&spWindowTop);

-    if (FAILED(hr) || !spWindowTop) {

-      return false;

-    }

-

-    // in a frameless situation, the windows are the same.

-    bool isTopLevel = AreObjectsEqual(spWindowCur, spWindowTop);

-    if (!isTopLevel) {

-      CORE_LOG(L3,

-               (_T("[CSiteLock::GetOurUrl][We are hosted in a frame][url=%s]"),

-               (*bstr_url)));

-    }

-

-    // Retrieves the URL of the resource that Microsoft Internet Explorer

-    // is currently displaying.

-    CComBSTR browserUrl;

-    VERIFY1(SUCCEEDED(spWebBrowser->get_LocationURL(&browserUrl)));

-

-    // Retrieves the URL of the current window and document hosting the control.

-    CComPtr<IHTMLLocation> spLocation;

-    VERIFY1(SUCCEEDED(spWindowCur->get_location(&spLocation)));

-

-    CComBSTR curUrl;

-    VERIFY1(SUCCEEDED(spLocation->get_href(&curUrl)));

-

-    // Retrieves the URL of the top window.

-    spLocation = 0;

-    VERIFY1(SUCCEEDED(spWindowTop->get_location(&spLocation)));

-

-    // In a cross-scripting situation we won't be able to get the href property

-    CComBSTR topUrl;

-    if (FAILED(spLocation->get_href(&topUrl))) {

-      topUrl = _T("null");

-    }

-

-    ASSERT1(*bstr_url && curUrl && topUrl && browserUrl);

-    CORE_LOG(L3,

-             (_T("[CSiteLock::GetOurUrl][doc=%s][self=%s][top=%s][browser=%s]"),

-             *bstr_url,

-             curUrl,

-             topUrl,

-             browserUrl));

-

-#endif

-

-    ASSERT(*bstr_url, (_T("post-condition")));

-    return true;

-  }

-

- private:

-

-  bool InApprovedDomain(CComBSTR bstrUrl,

-    const IObjectSafetySiteLock::SiteList *rgslTrustedSites,

-    int cTrustedSites) {

-

-    if (!bstrUrl) {

-      return false;

-    }

-

-    DWORD dwZone = URLZONE_UNTRUSTED;

-    if (!GetUrlZone(bstrUrl, &dwZone)) {

-      CORE_LOG(LEVEL_ERROR, (_T("[CSiteLock::InApprovedDomain]")

-                             _T("[unsafe: failed to get url zone][url=%s]"),

-                             bstrUrl));

-      return false;

-    }

-

-    // Check if the activation URL is in an allowed domain / zone

-    if (!FApprovedDomain(bstrUrl, dwZone, rgslTrustedSites, cTrustedSites)) {

-      ASSERT(FALSE, (_T("[CSiteLock::InApprovedDomain][unsafe: not in approved")

-                     _T(" domain][url=%s][zone=%s]")

-                     _T("- Check your ciconfig.ini to make sure you have the ")

-                     _T("right server in there!"),

-        bstrUrl, UrlZoneToString(dwZone)));

-      CORE_LOG(LEVEL_ERROR, (_T("[CSiteLock::InApprovedDomain][unsafe: not in")

-                             _T(" approved domain][url=%s][zone=%s]"),

-        bstrUrl, UrlZoneToString(dwZone)));

-      return false;

-    }

-

-    CORE_LOG(LEVEL_INF3,

-             (_T("[CSiteLock::InApprovedDomain][safe][%s][%s]"),

-             bstrUrl,

-             UrlZoneToString(dwZone)));

-    return true;

-  }

-

-  bool GetUrlZone(CComBSTR bstrURL, DWORD* zone_out) {

-    if (!bstrURL || !zone_out) {

-      return false;

-    }

-    CComPtr<IServiceProvider> spSrvProv;

-    CComPtr<IInternetSecurityManager> spInetSecMgr;

-    if (!GetServiceProvider(&spSrvProv) ||

-        FAILED(spSrvProv->QueryService(

-            SID_SInternetSecurityManager,

-            __uuidof(IInternetSecurityManager),

-            reinterpret_cast<void **>(&spInetSecMgr)))) {

-      RET_FALSE_IF_FAILED(::CoInternetCreateSecurityManager(NULL,

-                                                            &spInetSecMgr,

-                                                            NULL));

-    }

-    ASSERT1(spInetSecMgr);

-    RET_FALSE_IF_FAILED(spInetSecMgr->MapUrlToZone(bstrURL, zone_out, 0));

-    return true;

-  }

-

-  bool GetServiceProvider(IServiceProvider** ppSrvProv) {

-    if (NULL == ppSrvProv) {

-      return false;

-    }

-    // Get the current pointer as an instance of the template class

-    T* pT = static_cast<T*>(this);

-

-#ifdef SITELOCK_USE_IOLEOBJECT

-    CComPtr<IOleClientSite> spClientSite;

-    RET_FALSE_IF_FAILED(pT->GetClientSite(

-        reinterpret_cast<IOleClientSite**>(ppSrvProv)));

-    RET_IF_FALSE(spClientSite, false);

-    RET_FALSE_IF_FAILED(spClientSite->QueryInterface(

-        IID_IServiceProvider,

-        reinterpret_cast<void **>(ppSrvProv)));

-#else  // USE_IOBJECTWITHSITE

-    if FAILED(pT->GetSite(IID_IServiceProvider,

-                          reinterpret_cast<void**>(ppSrvProv))) {

-      return false;

-    }

-#endif

-

-    ASSERT(ppSrvProv, (_T("post-condition")));  // Post-condition.

-    return true;

-  }

-

-  // Checks if an activation URL is in an allowed domain / zone

-  bool FApprovedDomain(const OLECHAR* wzUrl,

-                       DWORD dwZone,

-                       const IObjectSafetySiteLock::SiteList* rgslTrustedSites,

-                       int cTrustedSites) {

-    // Declarations

-    HRESULT hr = S_OK;

-    OLECHAR wzDomain[INTERNET_MAX_HOST_NAME_LENGTH + 1] = {0};

-    OLECHAR wzScheme[INTERNET_MAX_SCHEME_LENGTH + 1] = {0};

-

-    // Retrieve the normalized domain and scheme

-    hr = GetDomainAndScheme(wzUrl,

-                            wzScheme,

-                            cElements(wzScheme),

-                            wzDomain,

-                            cElements(wzDomain));

-    if (FAILED(hr)) {

-      return false;

-    }

-

-    // Try to match the activation URL with each entry in order

-    DWORD cbScheme = (::lstrlenW(wzScheme) + 1) * sizeof(OLECHAR);

-    for (int i = 0; i < cTrustedSites; i++) {

-      // Try to match by scheme

-      DWORD cbSiteScheme = (::lstrlenW(rgslTrustedSites[i].szScheme) + 1) *

-                           sizeof(OLECHAR);

-      if (cbScheme != cbSiteScheme) {

-        continue;

-      }

-      if (0 != ::memcmp(wzScheme, rgslTrustedSites[i].szScheme, cbScheme)) {

-        continue;

-      }

-

-      // Try to match by zone

-      if (rgslTrustedSites[i].szDomain == SITELOCK_INTRANET_ZONE) {

-        if ((dwZone == URLZONE_INTRANET) || (dwZone == URLZONE_TRUSTED)) {

-          return (rgslTrustedSites[i].iAllowType ==

-                  IObjectSafetySiteLock::SiteList::Allow);

-        }

-      } else if (rgslTrustedSites[i].szDomain == SITELOCK_MYCOMPUTER_ZONE) {

-        if (dwZone == URLZONE_LOCAL_MACHINE) {

-          return (rgslTrustedSites[i].iAllowType ==

-                  IObjectSafetySiteLock::SiteList::Allow);

-        }

-      } else if (rgslTrustedSites[i].szDomain == SITELOCK_TRUSTED_ZONE) {

-        if (dwZone == URLZONE_TRUSTED) {

-          return (rgslTrustedSites[i].iAllowType ==

-                  IObjectSafetySiteLock::SiteList::Allow);

-        }

-        // Try to match by domain name

-      } else if (MatchDomains(rgslTrustedSites[i].szDomain, wzDomain)) {

-        return (rgslTrustedSites[i].iAllowType ==

-                IObjectSafetySiteLock::SiteList::Allow);

-      }

-    }

-    return false;

-  };

-

-  // Normalizes an international domain name

-  HRESULT NormalizeDomain(OLECHAR * wzDomain, int cchDomain) {

-    // Data validation

-    if (!wzDomain) {

-      return E_POINTER;

-    }

-

-    // If the domain is only 7-bit ASCII, normalization is not required

-    bool fFoundUnicode = false;

-    for (const OLECHAR * wz = wzDomain; *wz != 0; wz++) {

-      if (0x80 <= *wz) {

-        fFoundUnicode = true;

-        break;

-      }

-    }

-    if (!fFoundUnicode) {

-      return S_OK;

-    }

-

-    // Construct a fully qualified path to the Windows system directory

-    static const WCHAR wzNormaliz[] = L"normaliz.dll";

-    static const int cchNormaliz = cElements(wzNormaliz);

-    WCHAR wzDllPath[MAX_PATH + 1] = {0};

-    if (!::GetSystemDirectoryW(wzDllPath,

-                               cElements(wzDllPath) - cchNormaliz - 1)) {

-      return E_FAIL;

-    }

-    int cchDllPath = ::lstrlenW(wzDllPath);

-    if (!cchDllPath) {

-      return E_FAIL;

-    }

-    if (wzDllPath[cchDllPath-1] != L'\\') {

-      wzDllPath[cchDllPath++] = L'\\';

-    }

-    ::CopyMemory(wzDllPath + cchDllPath,

-                 wzNormaliz,

-                 cchNormaliz * sizeof(WCHAR));

-

-    // Load the DLL used for domain normalization

-    HMODULE hNormaliz = ::LoadLibraryExW(wzDllPath,

-                                         NULL,

-                                         LOAD_WITH_ALTERED_SEARCH_PATH);

-    if (!hNormaliz) {

-      return E_FAIL;

-    }

-

-    HRESULT hr = E_FAIL;

-

-    // Locate the entry point used for domain normalization

-    PFN_IdnToAscii pfnIdnToAscii =

-        (PFN_IdnToAscii)::GetProcAddress(hNormaliz, "IdnToAscii");

-    if (!pfnIdnToAscii) {

-      goto cleanup;

-    }

-

-    // Normalize the domain name

-    WCHAR wzEncoded[INTERNET_MAX_HOST_NAME_LENGTH + 1];

-    int cchEncode = pfnIdnToAscii(IDN_USE_STD3_ASCII_RULES,

-                                  wzDomain,

-                                  ::lstrlenW(wzDomain),

-                                  wzEncoded,

-                                  cElements(wzEncoded));

-    if (0 == cchEncode) {

-      hr = HRESULT_FROM_WIN32(::GetLastError());

-      goto cleanup;

-    }

-

-    // Copy results to the input buffer

-    if (cchEncode >= cchDomain) {

-      hr = E_OUTOFMEMORY;

-      goto cleanup;

-    }

-

-    ::CopyMemory(wzDomain, wzEncoded, cchEncode * sizeof(WCHAR));

-    hr = S_OK;

-

- cleanup:

-    if (hNormaliz) {

-      ::CloseHandle(hNormaliz);

-    }

-

-    return hr;

-  }

-

-  // Extracts a normalized domain and scheme from an activation URL

-  HRESULT GetDomainAndScheme(const OLECHAR* wzUrl,

-                             OLECHAR* wzScheme,

-                             DWORD cchScheme,

-                             OLECHAR* wzDomain,

-                             DWORD cchDomain) {

-    // Data validation

-    if (!wzDomain || !wzScheme) {

-      return E_POINTER;

-    }

-

-    // Extract the scheme

-    HRESULT hr = ::UrlGetPartW(wzUrl, wzScheme, &cchScheme, URL_PART_SCHEME, 0);

-    if (FAILED(hr)) {

-      return E_FAIL;

-    }

-

-    // Extract the host name

-    DWORD cchDomain2 = cchDomain;

-    hr = ::UrlGetPartW(wzUrl, wzDomain, &cchDomain2, URL_PART_HOSTNAME, 0);

-    if (FAILED(hr)) {

-      *wzDomain = 0;

-    }

-

-    // Exclude any URL specifying a user name or password

-    if ((0 == ::_wcsicmp(wzScheme, L"http")) ||

-        (0 == ::_wcsicmp(wzScheme, L"https"))) {

-      DWORD cch = 1;

-      WCHAR wzTemp[1] = {0};

-      ::UrlGetPartW(wzUrl, wzTemp, &cch, URL_PART_USERNAME, 0);

-      if (1 < cch) {

-        return E_FAIL;

-      }

-      ::UrlGetPartW(wzUrl, wzTemp, &cch, URL_PART_PASSWORD, 0);

-      if (1 < cch) {

-        return E_FAIL;

-      }

-    }

-

-    // Normalize the domain name

-    return NormalizeDomain(wzDomain, cchDomain);

-  }

-

-  // Attempts to match an activation URL with a domain name

-  bool MatchDomains(const OLECHAR* wzTrustedDomain,

-                    const OLECHAR* wzOurDomain) {

-    // Data validation

-    if (!wzTrustedDomain) {

-      return (0 == *wzOurDomain);  // match only if empty

-    }

-

-    // Declarations

-    int cchTrusted = ::lstrlenW(wzTrustedDomain);

-    int cchOur = ::lstrlenW(wzOurDomain);

-    bool fForcePrefix = false;

-    bool fDenyPrefix = false;

-

-    // Check if all activation URLs should be matched

-    if (0 == ::wcscmp(wzTrustedDomain, L"*")) {

-      return true;

-    }

-

-    // Check if the entry is like *. and setup the comparison range

-    if ((2 < cchTrusted) &&

-        (L'*' == wzTrustedDomain[0]) &&

-        (L'.' == wzTrustedDomain[1])) {

-      fForcePrefix = true;

-      wzTrustedDomain += 2;

-      cchTrusted -= 2;

-

-      // Check if the entry is like = and setup the comparison range

-    } else if ((1 < cchTrusted) && (L'=' == wzTrustedDomain[0])) {

-      fDenyPrefix = true;

-      wzTrustedDomain++;

-      cchTrusted--;

-    };

-

-    // Check if there is a count mismatch

-    if (cchTrusted > cchOur) {

-      return false;

-    }

-

-    // Compare URLs on the desired character range

-    if (0 != ::memcmp(wzOurDomain + cchOur - cchTrusted,

-                      wzTrustedDomain,

-                      cchTrusted * sizeof(OLECHAR))) {

-      return false;

-    }

-

-    // Compare URLs without allowing child domains

-    if (!fForcePrefix && (cchTrusted == cchOur)) {

-      return true;

-    }

-

-    // Compare URLs requiring child domains

-    if (!fDenyPrefix && (wzOurDomain[cchOur - cchTrusted - 1] == L'.')) {

-      return true;

-    }

-

-    return false;

-  }

-};

-

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

-// IObjectSafetySiteLockImpl - "Safe for scripting" template

-template <typename T, DWORD dwSupportedSafety>

-class ATL_NO_VTABLE IObjectSafetySiteLockImpl

-    : public IObjectSafetySiteLock,

-      public CSiteLock<T> {

- public:

-  // Constructor

-  IObjectSafetySiteLockImpl(): m_dwCurrentSafety(0) {}

-

-  // Returns safety options

-  STDMETHOD(GetInterfaceSafetyOptions)(REFIID riid,

-                                       DWORD * pdwSupportedOptions,

-                                       DWORD * pdwEnabledOptions) {

-    // Data validation

-    if (!pdwSupportedOptions || !pdwEnabledOptions) {

-      return E_POINTER;

-    }

-

-    // Declarations

-    HRESULT hr = S_OK;

-    IUnknown* pUnk = NULL;

-

-    // Get the current pointer as an instance of the template class

-    T * pT = static_cast<T*>(this);

-

-    // Check if the requested COM interface is supported

-    hr = pT->GetUnknown()->QueryInterface(riid,

-                                          reinterpret_cast<void**>(&pUnk));

-    if (FAILED(hr)) {

-      *pdwSupportedOptions = 0;

-      *pdwEnabledOptions   = 0;

-      return hr;

-    }

-

-    // Release the interface

-    pUnk->Release();

-

-    // Check expiry and if the activation URL is allowed

-    if (!ControlExpired() && InApprovedDomain()) {

-      *pdwSupportedOptions = dwSupportedSafety;

-      *pdwEnabledOptions   = m_dwCurrentSafety;

-    } else {

-      *pdwSupportedOptions = dwSupportedSafety;

-      *pdwEnabledOptions   = 0;

-    }

-    return S_OK;

-  }

-

-  // Sets safety options

-  STDMETHOD(SetInterfaceSafetyOptions)(REFIID riid,

-                                       DWORD dwOptionSetMask,

-                                       DWORD dwEnabledOptions) {

-    // Declarations

-    HRESULT hr = S_OK;

-    IUnknown* pUnk = NULL;

-

-    // Get the current pointer as an instance of the template class

-    T * pT = static_cast<T*>(this);

-

-    // Check if we support the interface and return E_NOINTERFACE if we don't

-    // Check if the requested COM interface is supported

-    hr = pT->GetUnknown()->QueryInterface(riid,

-                                          reinterpret_cast<void**>(&pUnk));

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    // Release the interface

-    pUnk->Release();

-

-    // Reject unsupported requests

-    if (dwOptionSetMask & ~dwSupportedSafety) {

-      return E_FAIL;

-    }

-

-    // Calculate safety options

-    DWORD dwNewSafety = (m_dwCurrentSafety & ~dwOptionSetMask) |

-                        (dwOptionSetMask & dwEnabledOptions);

-    if (m_dwCurrentSafety != dwNewSafety) {

-      // Check expiry and if the activation URL is allowed

-      if (ControlExpired() || !InApprovedDomain()) {

-        return E_FAIL;

-      }

-

-      // Set safety options

-      m_dwCurrentSafety = dwNewSafety;

-    }

-    return S_OK;

-  }

-

-  // Returns capabilities (this can be used by testing tools to query for

-  // custom capabilities or version information)

-  STDMETHOD(GetCapabilities)(DWORD * pdwCapability) {

-    // Data validation

-    if (!pdwCapability) {

-      return E_POINTER;

-    }

-

-    // Return the version if 0 is passed in

-    if (0 == *pdwCapability) {

-      *pdwCapability = SITELOCK_VERSION;

-      return S_OK;

-    }

-

-    // Return the options if 1 is passed in

-    if (1 == *pdwCapability) {

-      *pdwCapability =

-#ifdef SITELOCK_USE_IOLEOBJECT

-        Capability::UsesIOleObject |

-#endif

-#ifndef SITELOCK_NO_EXPIRY

-        Capability::HasExpiry |

-#endif

-        0;

-      return S_OK;

-    }

-

-    // Return not implemented otherwise

-    *pdwCapability = 0;

-    return E_NOTIMPL;

-  }

-

-  // Returns site lock entries controlling activation

-  STDMETHOD(GetApprovedSites)(const SiteList ** pSiteList, DWORD * pcEntries) {

-    // Data validation

-    if (!pSiteList || !pcEntries) {

-      return E_POINTER;

-    }

-

-    // Return specified site lock entries

-#ifdef SITELOCK_USE_MAP

-    // Use the site lock map

-    *pSiteList = T::GetSiteLockMapAndCount(*pcEntries);

-#else

-    // Use the static member

-    *pSiteList = T::rgslTrustedSites;

-    *pcEntries = cElements(T::rgslTrustedSites);

-#endif

-    return S_OK;

-  }

-

-  STDMETHOD(GetExpiryDate)(DWORD * pdwLifespan, FILETIME * pExpiryDate) {

-    if (!pdwLifespan || !pExpiryDate) {

-      return E_POINTER;

-    }

-

-#ifdef SITELOCK_NO_EXPIRY

-    *pdwLifespan = 0;

-    ::ZeroMemory(reinterpret_cast<void*>(pExpiryDate), sizeof(FILETIME));

-    return E_NOTIMPL;

-#else

-    *pdwLifespan = T::dwControlLifespan;

-

-    // Calculate expiry date from life span

-    time_t ttExpire = ImageNtHeaders(&__ImageBase)->FileHeader.TimeDateStamp;

-    ttExpire += T::dwControlLifespan*86400;  // seconds per day

-    _UNIXTimeToFILETIME(ttExpire, pExpiryDate);

-

-    return S_OK;

-#endif

-  }

-

- private:

-  // Current safety

-  DWORD m_dwCurrentSafety;

-};

-

-#endif  // OMAHA_PLUGINS_SITELOCK_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// note:  this file is originally from Microsoft for SiteLock, but has been
+// modified to support getting the browser URL via NPAPI so we can use this
+// for validating within Firefox and other browsers as well
+
+#ifndef OMAHA_PLUGINS_SITELOCK_H__
+#define OMAHA_PLUGINS_SITELOCK_H__
+
+///////////////////////////////////////////////////////////////////////////////
+// SiteLock 1.14
+// ATL sample code for restricting activation of ActiveX controls.
+// Copyright Microsoft Corporation. All rights reserved.
+// Last updated: July 19 2007
+
+
+// Includes
+#include <atlctl.h>
+#include <comdef.h>
+#include <shlguid.h>
+#include <dispex.h>   // IObjectIdentity
+
+// Pragmas
+#pragma once
+
+#include "common/logging.h"
+// Version information
+#define SITELOCK_VERSION 0x00010014   // 1.14
+
+#ifdef SITELOCK_SUPPORT_DOWNLOAD
+#pragma message("sitelock.h : This version of SiteLock " \
+                "does not support downloading.")
+#endif
+
+// Overview:
+// To enable scripting, developers must declare their ActiveX controls as
+// "safe for scripting".
+// This is done by implementing interface IObjectSafety, which comes with very
+// important safety assumptions. Once marked as "safe for scripting", ActiveX
+// controls may be activated by untrusted web sites. Therefore "safe for
+// scripting" controls must guarantee all their methods are safe regardless of
+// the activation context. Practically however, it may not be possible for an
+// ActiveX control to guarantee safety in all activation contexts. The site lock
+// framework allows developers to specify which zones and domains can
+// instantiate ActiveX controls. For example, this may allow a developer
+// to implement methods that can only be called if the activation context is the
+// intranet zone.
+
+// Usage:
+// 1/ Include current header file sitelock.h (after including ATL header files).
+//
+// 2/ Derive from "public IObjectSafetySiteLockImpl
+//                   <CYourClass, INTERFACESAFE_FOR...>,".
+//    This replaces the default IObjectSafetyImpl interface implementation.
+//
+// 3/ Add the following to your control's COM map:
+//    COM_INTERFACE_ENTRY(IObjectSafety)
+//    COM_INTERFACE_ENTRY(IObjectSafetySiteLock)
+//
+// 4/ Add one of the following to specify allowed activation contexts:
+//    a) A public (or friend) member variable, for example:
+//    const CYourClass::SiteList CYourClass::rgslTrustedSites[6] =
+//       {{ SiteList::Deny,  L"http",  L"users.microsoft.com" },
+//        { SiteList::Allow, L"http",  L"microsoft com"       },
+//        { SiteList::Allow, L"http",  SITELOCK_INTRANET_ZONE },
+//        { SiteList::Deny,  L"https", L"users.microsoft.com" },
+//        { SiteList::Allow, L"https", L"microsoft.com"       },
+//        { SiteList::Allow, L"https", SITELOCK_INTRANET_ZONE }};
+//
+//    b) A set of site lock macros, for example:
+//    #define SITELOCK_USE_MAP (prior to including sitelock.h)
+//    BEGIN_SITELOCK_MAP()
+//        SITELOCK_DENYHTTP    ( L"users.microsoft.com" )
+//        SITELOCK_ALLOWHTTP  ( L"microsoft com"       )
+//        SITELOCK_ALLOWHTTP  ( SITELOCK_INTRANET_ZONE )
+//        SITELOCK_DENYHTTPS  ( L"users.microsoft.com" )
+//        SITELOCK_ALLOWHTTPS  ( L"microsoft.com"       )
+//        SITELOCK_ALLOWHTTPS  ( SITELOCK_INTRANET_ZONE )
+//    END_SITELOCK_MAP()
+//
+//    The examples above block "*.users.microsoft.com" sites (http and https).
+//    The examples above allow "*.microsoft.com" sites (http and https).
+//    The examples above allow intranet sites (http and https).
+//
+// 5/ Choose an expiry lifespan:
+//    You can specify the lifespan of your control one of two ways.
+//    By declaring an enumeration (slightly more efficient):
+//       enum { dwControlLifespan = (lifespan in days) };
+//    By declaring a member variable:
+//       static const DWORD dwControlLifespan = (lifespan in days);
+//    When in doubt, choose a shorter duration rather than a longer one.
+//    Expiration can be disabled by adding #define SITELOCK_NO_EXPIRY before
+//    including sitelock.h.
+//
+// 6/ Implement IObjectWithSite or IOleObject:
+//    IObjectWithSite is a lightweight interface able to indicate the
+//      activation URL to site lock.
+//    IOleObject is a heavier interface providing additional OLE capabilities.
+//    If you need IOleObject, add #define SITELOCK_USE_IOLEOBJECT before
+//      including sitelock.h.
+//    Otherwise, simply implement IObjectWithSite:
+//      - Derive from "IObjectWithSiteImpl<CYourClass>".
+//      - Add COM_INTERFACE_ENTRY(IObjectWithSite) to your control's COM map.
+//    You should never implement both IObjectWithSite and IOleObject.
+//
+// 7/ Link with urlmon.lib.
+
+// Detailed usage:
+//   --- Entries ---:
+//   Site lock entries are defined by the following elements:
+//   iAllowType is:
+//    SiteList::Allow:    allowed location
+//      SiteList::Deny:      blocked location
+//   szScheme is:
+//    L"http":        non-SSL location
+//    L"https":        SSL-enabled location
+//    Other:          in rare cases, the scheme may be outlook:, ms-help:, etc.
+//   szDomain is:
+//    Doman:          a string defining a domain
+//    Zone:          a constant specifying a zone
+//
+//    --- Ordering ---:
+//    Entries are matched in the order they appear in.
+//    The first entry that matches will be accepted.
+//    Deny entries should therefore be placed before allow entries.
+//
+//    --- Protocols ---:
+//    To support multiple protocols (http and https), define separate entries.
+//
+//    --- Domain names ---:
+//    This sample code performs a case-sensitive comparison after domain
+//    normalization. Whether domain normalization converts strings to lower
+//    case depends on the scheme provider.
+//
+//    If a domain does not contain any special indicator, only domains with the
+//    right suffix will match. For example:
+//    An entry of "microsoft.com" will match "microsoft.com".
+//      An entry of "microsoft.com" will match "office.microsoft.com"
+//      An entry of "microsoft.com" will not match "mymicrosoft.com"
+//    An entry of "microsoft.com" will not match "www.microsoft.com.hacker.com"
+//
+//    If a domain begins with "*.", only child domains will match.
+//    For example:
+//    An entry of "*.microsoft.com" will match "foo.microsoft.com".
+//    An entry of "*.microsoft.com" will not match "microsoft.com".
+//
+//    If a domain begins with "=", only the specified domain will match.
+//    For example:
+//    An entry of "=microsoft.com" will match "microsoft.com".
+//    An entry of "=microsoft.com" will not match "foo.microsoft.com".
+//
+//    If a domain is set to "*", all domains will match.
+//    This is useful to only restrict to specific schemes (ex: http vs. https).
+//
+//    If a domain name is NULL, then the scheme provider should return an error
+//    when asking for the domain. This is appropriate for protocols
+//    (outlook: or ms-help:) that do not use server names.
+//
+//    If a domain name is SITELOCK_INTRANET_ZONE, then any server in the
+//    Intranet zone will match. Due to a zone limitation, sites in the user's
+//    Trusted Sites list will also match. However, since Trusted Sites
+//    typically permit downloading and running of unsigned, unsafe controls,
+//    security is limited for those sites anyway.
+//
+//    If a domain name is SITELOCK_MYCOMPUTER_ZONE, then any page residing on
+//    the user's local machine will match.
+//
+//    If a domain name is SITELOCK_TRUSTED_ZONE, then any page residing in the
+//    user's Trusted Sites list will match.
+
+
+// Language checks
+#ifndef __cplusplus
+#error ATL Requires C++
+#endif
+
+// Windows constants
+#if (WINVER < 0x0600)
+#define IDN_USE_STD3_ASCII_RULES  0x02  // Enforce STD3 ASCII restrictions
+#endif
+
+// Function prototypes
+typedef int (WINAPI * PFN_IdnToAscii)(DWORD, LPCWSTR, int, LPWSTR, int);
+
+// Macros
+#ifndef cElements
+template<typename T> static char cElementsVerify(void const *, T) throw() {
+  return 0;
+}
+
+template<typename T> static void cElementsVerify(T *const, T *const *) throw() {
+};
+
+#define cElements(arr) (sizeof(cElementsVerify(arr, &(arr))) * \
+                        (sizeof(arr)/sizeof(*(arr))))
+#endif
+
+// Restrictions
+#define SITELOCK_INTRANET_ZONE    ((const OLECHAR *)-1)
+#define SITELOCK_MYCOMPUTER_ZONE  ((const OLECHAR *)-2)
+#define SITELOCK_TRUSTED_ZONE    ((const OLECHAR *)-3)
+
+#ifndef SITELOCK_NO_EXPIRY
+// Helper functions for expiry
+#if defined(_WIN64) && defined(_M_IA64)
+#pragma section(".base", long, read, write)           // NO_LINT
+extern "C" __declspec(allocate(".base")) extern IMAGE_DOS_HEADER __ImageBase;
+#else
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+#endif
+#define ImageNtHeaders(pBase) ((PIMAGE_NT_HEADERS)((PCHAR)(pBase) + \
+                                    ((PIMAGE_DOS_HEADER)(pBase))->e_lfanew))
+
+#define LODWORD(_qw)    ((DWORD)(_qw))
+#define HIDWORD(_qw)    ((DWORD)(((_qw) >> 32) & 0xffffffff))
+inline void _UNIXTimeToFILETIME(time_t t, LPFILETIME ft) {
+  // The time_t is a 32-bit value for the number of seconds since
+  // January 1, 1970.
+  // A FILETIME is a 64-bit for the number of 100-nanosecond periods since
+  // January 1, 1601.
+  // Convert by multiplying the time_t value by 1e+7 to get to the same base
+  // granularity, then add the numeric equivalent of January 1, 1970 as
+  // FILETIME.
+
+  ULONGLONG qw = ((ULONGLONG)t * 10000000ui64) + 116444736000000000ui64;
+  ft->dwHighDateTime = HIDWORD(qw);
+  ft->dwLowDateTime = LODWORD(qw);
+}
+inline time_t _FILETIMEToUNIXTime(LPFILETIME ft) {
+  ULONGLONG qw = (((ULONGLONG)ft->dwHighDateTime)<<32) + ft->dwLowDateTime;
+  return (time_t)((qw - 116444736000000000ui64) / 10000000ui64);
+}
+#endif  // SITELOCK_NO_EXPIRY
+
+// Interface declaring "safe for scripting" methods with additional site lock
+// capabilities
+class __declspec(uuid("7FEB54AE-E3F9-40FC-AB5A-28A545C0F193"))
+    ATL_NO_VTABLE IObjectSafetySiteLock : public IObjectSafety {
+ public:
+  // Site lock entry definition
+  struct SiteList {
+    enum SiteListCategory {
+      Allow,                // permit
+      Deny,                // disallow
+      Download              // OBSOLETE, do not use
+    } iAllowType;
+    const OLECHAR*    szScheme;    // scheme (http or https)
+    const OLECHAR*    szDomain;    // domain
+  };
+
+  // Capability definition
+  enum Capability {
+    CanDownload    = 0x00000001,  // OBSOLETE. Here for backwards compat only.
+    UsesIOleObject = 0x00000002,  // Use IOleObject instead of IObjectWithSite.
+    HasExpiry     = 0x00000004,  // Control will expire when lifespan elapsed.
+  };
+
+  // Returns capabilities (this can be used by testing tools to query for
+  // custom capabilities or version information)
+  STDMETHOD(GetCapabilities)(DWORD* pdwCapability) = 0;
+
+  // Returns site lock entries controlling activation
+  STDMETHOD(GetApprovedSites)(const SiteList** pSiteList, DWORD* cSites)  = 0;
+
+  // Returns lifespan as number of days and date (version 1.05 or higher)
+  STDMETHOD(GetExpiryDate)(DWORD* pdwLifespan, FILETIME* pExpiryDate)    = 0;
+};
+
+
+inline LPCTSTR const UrlZoneToString(DWORD dwZone) {
+  switch (dwZone) {
+    case URLZONE_LOCAL_MACHINE: return _T("URLZONE_LOCAL_MACHINE");
+    case URLZONE_INTRANET:      return _T("URLZONE_INTRANET");
+    case URLZONE_TRUSTED:       return _T("URLZONE_TRUSTED");
+    case URLZONE_INTERNET:      return _T("URLZONE_INTERNET");
+    case URLZONE_UNTRUSTED:     return _T("URLZONE_UNTRUSTED");
+    default:                    return _T("URLZONE_UNKNOWN");
+  }
+}
+
+bool AreObjectsEqual(IDispatch* disp1, IDispatch* disp2) {
+  // if the arguments are equal then the objects are equal
+  if (disp1 == disp2) return true;
+
+  // if the arguments are not equal, then compare the IUnknowns
+  if (disp1 && disp2) {
+    CComPtr<IUnknown> unk1;
+    CComPtr<IUnknown> unk2;
+    // This must always succeed.
+    VERIFY1(SUCCEEDED(disp1->QueryInterface(&unk1)));
+    VERIFY1(SUCCEEDED(disp2->QueryInterface(&unk2)));
+    ASSERT1(unk1 && unk2);
+
+    if (unk1 == unk2) return true;
+
+    // Not all the hope is lost. If the IUnknown pointers are different, try
+    // to query for object identity and use that to compare.
+    if (unk1 && unk2) {
+      CComPtr<IObjectIdentity> object_identity;
+      if (SUCCEEDED(unk1.QueryInterface(&object_identity))) {
+        if (object_identity) {
+          HRESULT hr = object_identity->IsEqualObject(unk2);
+          ASSERT(SUCCEEDED(hr), (_T("")));
+          return hr == S_OK;
+        }
+      }
+    }
+  }
+
+  return false;
+}
+
+
+#ifdef SITELOCK_USE_MAP
+// Site lock actual map entry macro
+#define SITELOCK_ALLOWHTTPS(domain) \
+    {IObjectSafetySiteLock::SiteList::Allow,  L"https",  domain},
+#define SITELOCK_DENYHTTPS(domain)  \
+    {IObjectSafetySiteLock::SiteList::Deny,    L"https",  domain},
+#define SITELOCK_ALLOWHTTP(domain)  \
+    {IObjectSafetySiteLock::SiteList::Allow,  L"http",  domain},
+#define SITELOCK_DENYHTTP(domain)   \
+    {IObjectSafetySiteLock::SiteList::Deny,    L"http",  domain},
+
+// Site lock begin map entry macro
+#define BEGIN_SITELOCK_MAP() \
+  static const IObjectSafetySiteLock::SiteList *                             \
+      GetSiteLockMapAndCount(DWORD* dwCount)                                 \
+{                                                                            \
+  static IObjectSafetySiteLock::SiteList rgslTrustedSites[] = {              \
+                                                                    // NO_LINT
+// Site lock end map entry macro
+#define END_SITELOCK_MAP()                                                   \
+{(IObjectSafetySiteLock::SiteList::SiteListCategory)0, 0, 0}};               \
+  *dwCount = cElements(rgslTrustedSites) - 1;                                \
+  return rgslTrustedSites;                                                   \
+}                                                                            \
+  static const IObjectSafetySiteLock::SiteList * GetSiteLockMap()            \
+{                                                                            \
+  DWORD dwCount = 0;                                                         \
+  return GetSiteLockMapAndCount(&dwCount);                                   \
+}                                                                            \
+  static DWORD GetSiteLockMapCount()                                         \
+{                                                                            \
+  DWORD dwCount = 0;                                                         \
+  GetSiteLockMapAndCount(&dwCount);                                          \
+  return dwCount;                                                            \
+}                                                                            \
+
+#endif  // SITELOCK_USE_MAP
+
+///////////////////////////////////////////////////////////////////////////////
+// CSiteLock - Site lock templated class
+template <typename T>
+class ATL_NO_VTABLE CSiteLock {
+ public:
+#ifdef SITELOCK_NO_EXPIRY
+  bool ControlExpired(DWORD = 0)    { return false; }
+#else
+  bool ControlExpired(DWORD dwExpiresDays = T::dwControlLifespan) {
+    SYSTEMTIME st = {0};
+    FILETIME ft = {0};
+
+    GetSystemTime(&st);
+    if (!SystemTimeToFileTime(&st, &ft))
+      return true;
+
+    time_t ttTime = _FILETIMEToUNIXTime(&ft);
+    time_t ttExpire = ImageNtHeaders(&__ImageBase)->FileHeader.TimeDateStamp;
+    ttExpire += dwExpiresDays*86400;
+
+    return (ttTime > ttExpire);
+  }
+#endif
+
+#ifdef SITELOCK_USE_MAP
+  // Checks if the activation URL is in an allowed domain / zone
+  bool InApprovedDomain(
+      const IObjectSafetySiteLock::SiteList* rgslTrustedSites =
+          T::GetSiteLockMap(),
+      int cTrustedSites = T::GetSiteLockMapCount()) {
+#else
+  // Checks if the activation URL is in an allowed domain / zone
+  bool InApprovedDomain(
+      const IObjectSafetySiteLock::SiteList* rgslTrustedSites =
+          T::rgslTrustedSites,
+      int cTrustedSites = cElements(T::rgslTrustedSites)) {
+#endif
+    // Retrieve the activation URL
+    CComBSTR  bstrUrl;
+
+    if (!GetOurUrl(bstrUrl)) {
+      CORE_LOG(LEVEL_ERROR,
+               (_T("[CSiteLock::InApprovedDomain]")
+                _T("[unsafe: failed to get the url]")));
+      return false;
+    }
+
+    return InApprovedDomain(bstrUrl, rgslTrustedSites, cTrustedSites);
+  }
+
+ protected:
+
+  // Retrieves the activation URL
+  bool GetOurUrl(BSTR* bstr_url) {
+    if (NULL == bstr_url) {
+      return false;
+    }
+    CComPtr<IServiceProvider> spSrvProv;
+    if (!GetServiceProvider(&spSrvProv)) {
+      return false;
+    }
+    ASSERT1(spSrvProv);
+
+    // See if we're hosted within IE
+    // Query the site for a web browser object
+    CComPtr<IWebBrowser2> spWebBrowser;
+    CComPtr<IHTMLDocument2> spHTMLDocument2;
+    HRESULT hr = spSrvProv->QueryService(
+        SID_SWebBrowserApp,
+        IID_IWebBrowser2,
+        reinterpret_cast<void**>(&spWebBrowser));
+
+    if (FAILED(hr)) {
+#ifdef SITELOCK_USE_IOLEOBJECT
+      return false;
+#else
+      // Local declarations
+      CComPtr<IOleContainer> spContainer;
+      CComPtr<IOleClientSite> spClientSite;
+
+      // Get the client site, container, document, and url.
+      T* pT = static_cast<T*>(this);
+      hr = pT->GetSite(IID_IOleClientSite,
+                       reinterpret_cast<void**>(&spClientSite));
+      if (FAILED(hr)) {
+        return false;
+      }
+      hr = spClientSite->GetContainer(&spContainer);
+      if (FAILED(hr)) {
+        return false;
+      }
+      hr = spContainer.QueryInterface(&spHTMLDocument2);
+      if (FAILED(hr)) {
+        return false;
+      }
+      if (FAILED(spHTMLDocument2->get_URL(bstr_url))) {
+        return false;
+      }
+#endif
+    } else {
+      ASSERT1(spWebBrowser);
+
+      CComPtr<IDispatch> spDocument;
+      hr = spWebBrowser->get_Document(&spDocument);
+      if (FAILED(hr) || !spDocument) {
+        return false;
+      }
+
+      hr = spDocument.QueryInterface(&spHTMLDocument2);
+      if (FAILED(hr) || !spHTMLDocument2) {
+        return false;
+      }
+
+      // Retrieves the URL of the document hosting the control.
+      hr = spHTMLDocument2->get_URL(bstr_url);
+      if (FAILED(hr) || !*bstr_url) {
+        return false;
+      }
+    }
+
+#ifdef DEBUG
+    // A little bit of debug code to dump the urls that we care about.
+    // Find out if this is a top level window or a frame.
+    CComPtr<IHTMLWindow2> spWindow;
+    hr = spHTMLDocument2->get_parentWindow(&spWindow);
+    if (FAILED(hr) || !spWindow) {
+      return false;
+    }
+
+    // Get our window. This is the window.self
+    CComPtr<IHTMLWindow2> spWindowCur;
+    hr = spWindow->get_self(&spWindowCur);
+    if (FAILED(hr) || !spWindowCur) {
+      return false;
+    }
+
+    // Get the top level window.
+    CComPtr<IHTMLWindow2> spWindowTop;
+    hr = spWindow->get_top(&spWindowTop);
+    if (FAILED(hr) || !spWindowTop) {
+      return false;
+    }
+
+    // in a frameless situation, the windows are the same.
+    bool isTopLevel = AreObjectsEqual(spWindowCur, spWindowTop);
+    if (!isTopLevel) {
+      CORE_LOG(L3,
+               (_T("[CSiteLock::GetOurUrl][We are hosted in a frame][url=%s]"),
+               (*bstr_url)));
+    }
+
+    // Retrieves the URL of the resource that Microsoft Internet Explorer
+    // is currently displaying.
+    CComBSTR browserUrl;
+    VERIFY1(SUCCEEDED(spWebBrowser->get_LocationURL(&browserUrl)));
+
+    // Retrieves the URL of the current window and document hosting the control.
+    CComPtr<IHTMLLocation> spLocation;
+    VERIFY1(SUCCEEDED(spWindowCur->get_location(&spLocation)));
+
+    CComBSTR curUrl;
+    VERIFY1(SUCCEEDED(spLocation->get_href(&curUrl)));
+
+    // Retrieves the URL of the top window.
+    spLocation = 0;
+    VERIFY1(SUCCEEDED(spWindowTop->get_location(&spLocation)));
+
+    // In a cross-scripting situation we won't be able to get the href property
+    CComBSTR topUrl;
+    if (FAILED(spLocation->get_href(&topUrl))) {
+      topUrl = _T("null");
+    }
+
+    ASSERT1(*bstr_url && curUrl && topUrl && browserUrl);
+    CORE_LOG(L3,
+             (_T("[CSiteLock::GetOurUrl][doc=%s][self=%s][top=%s][browser=%s]"),
+             *bstr_url,
+             curUrl,
+             topUrl,
+             browserUrl));
+
+#endif
+
+    ASSERT(*bstr_url, (_T("post-condition")));
+    return true;
+  }
+
+ private:
+
+  bool InApprovedDomain(CComBSTR bstrUrl,
+    const IObjectSafetySiteLock::SiteList *rgslTrustedSites,
+    int cTrustedSites) {
+
+    if (!bstrUrl) {
+      return false;
+    }
+
+    DWORD dwZone = URLZONE_UNTRUSTED;
+    if (!GetUrlZone(bstrUrl, &dwZone)) {
+      CORE_LOG(LEVEL_ERROR, (_T("[CSiteLock::InApprovedDomain]")
+                             _T("[unsafe: failed to get url zone][url=%s]"),
+                             bstrUrl));
+      return false;
+    }
+
+    // Check if the activation URL is in an allowed domain / zone
+    if (!FApprovedDomain(bstrUrl, dwZone, rgslTrustedSites, cTrustedSites)) {
+      ASSERT(FALSE, (_T("[CSiteLock::InApprovedDomain][unsafe: not in approved")
+                     _T(" domain][url=%s][zone=%s]")
+                     _T("- Check your ciconfig.ini to make sure you have the ")
+                     _T("right server in there!"),
+        bstrUrl, UrlZoneToString(dwZone)));
+      CORE_LOG(LEVEL_ERROR, (_T("[CSiteLock::InApprovedDomain][unsafe: not in")
+                             _T(" approved domain][url=%s][zone=%s]"),
+        bstrUrl, UrlZoneToString(dwZone)));
+      return false;
+    }
+
+    CORE_LOG(LEVEL_INF3,
+             (_T("[CSiteLock::InApprovedDomain][safe][%s][%s]"),
+             bstrUrl,
+             UrlZoneToString(dwZone)));
+    return true;
+  }
+
+  bool GetUrlZone(CComBSTR bstrURL, DWORD* zone_out) {
+    if (!bstrURL || !zone_out) {
+      return false;
+    }
+    CComPtr<IServiceProvider> spSrvProv;
+    CComPtr<IInternetSecurityManager> spInetSecMgr;
+    if (!GetServiceProvider(&spSrvProv) ||
+        FAILED(spSrvProv->QueryService(
+            SID_SInternetSecurityManager,
+            __uuidof(IInternetSecurityManager),
+            reinterpret_cast<void **>(&spInetSecMgr)))) {
+      RET_FALSE_IF_FAILED(::CoInternetCreateSecurityManager(NULL,
+                                                            &spInetSecMgr,
+                                                            NULL));
+    }
+    ASSERT1(spInetSecMgr);
+    RET_FALSE_IF_FAILED(spInetSecMgr->MapUrlToZone(bstrURL, zone_out, 0));
+    return true;
+  }
+
+  bool GetServiceProvider(IServiceProvider** ppSrvProv) {
+    if (NULL == ppSrvProv) {
+      return false;
+    }
+    // Get the current pointer as an instance of the template class
+    T* pT = static_cast<T*>(this);
+
+#ifdef SITELOCK_USE_IOLEOBJECT
+    CComPtr<IOleClientSite> spClientSite;
+    RET_FALSE_IF_FAILED(pT->GetClientSite(
+        reinterpret_cast<IOleClientSite**>(ppSrvProv)));
+    RET_IF_FALSE(spClientSite, false);
+    RET_FALSE_IF_FAILED(spClientSite->QueryInterface(
+        IID_IServiceProvider,
+        reinterpret_cast<void **>(ppSrvProv)));
+#else  // USE_IOBJECTWITHSITE
+    if FAILED(pT->GetSite(IID_IServiceProvider,
+                          reinterpret_cast<void**>(ppSrvProv))) {
+      return false;
+    }
+#endif
+
+    ASSERT(ppSrvProv, (_T("post-condition")));  // Post-condition.
+    return true;
+  }
+
+  // Checks if an activation URL is in an allowed domain / zone
+  bool FApprovedDomain(const OLECHAR* wzUrl,
+                       DWORD dwZone,
+                       const IObjectSafetySiteLock::SiteList* rgslTrustedSites,
+                       int cTrustedSites) {
+    // Declarations
+    HRESULT hr = S_OK;
+    OLECHAR wzDomain[INTERNET_MAX_HOST_NAME_LENGTH + 1] = {0};
+    OLECHAR wzScheme[INTERNET_MAX_SCHEME_LENGTH + 1] = {0};
+
+    // Retrieve the normalized domain and scheme
+    hr = GetDomainAndScheme(wzUrl,
+                            wzScheme,
+                            cElements(wzScheme),
+                            wzDomain,
+                            cElements(wzDomain));
+    if (FAILED(hr)) {
+      return false;
+    }
+
+    // Try to match the activation URL with each entry in order
+    DWORD cbScheme = (::lstrlenW(wzScheme) + 1) * sizeof(OLECHAR);
+    for (int i = 0; i < cTrustedSites; i++) {
+      // Try to match by scheme
+      DWORD cbSiteScheme = (::lstrlenW(rgslTrustedSites[i].szScheme) + 1) *
+                           sizeof(OLECHAR);
+      if (cbScheme != cbSiteScheme) {
+        continue;
+      }
+      if (0 != ::memcmp(wzScheme, rgslTrustedSites[i].szScheme, cbScheme)) {
+        continue;
+      }
+
+      // Try to match by zone
+      if (rgslTrustedSites[i].szDomain == SITELOCK_INTRANET_ZONE) {
+        if ((dwZone == URLZONE_INTRANET) || (dwZone == URLZONE_TRUSTED)) {
+          return (rgslTrustedSites[i].iAllowType ==
+                  IObjectSafetySiteLock::SiteList::Allow);
+        }
+      } else if (rgslTrustedSites[i].szDomain == SITELOCK_MYCOMPUTER_ZONE) {
+        if (dwZone == URLZONE_LOCAL_MACHINE) {
+          return (rgslTrustedSites[i].iAllowType ==
+                  IObjectSafetySiteLock::SiteList::Allow);
+        }
+      } else if (rgslTrustedSites[i].szDomain == SITELOCK_TRUSTED_ZONE) {
+        if (dwZone == URLZONE_TRUSTED) {
+          return (rgslTrustedSites[i].iAllowType ==
+                  IObjectSafetySiteLock::SiteList::Allow);
+        }
+        // Try to match by domain name
+      } else if (MatchDomains(rgslTrustedSites[i].szDomain, wzDomain)) {
+        return (rgslTrustedSites[i].iAllowType ==
+                IObjectSafetySiteLock::SiteList::Allow);
+      }
+    }
+    return false;
+  };
+
+  // Normalizes an international domain name
+  HRESULT NormalizeDomain(OLECHAR * wzDomain, int cchDomain) {
+    // Data validation
+    if (!wzDomain) {
+      return E_POINTER;
+    }
+
+    // If the domain is only 7-bit ASCII, normalization is not required
+    bool fFoundUnicode = false;
+    for (const OLECHAR * wz = wzDomain; *wz != 0; wz++) {
+      if (0x80 <= *wz) {
+        fFoundUnicode = true;
+        break;
+      }
+    }
+    if (!fFoundUnicode) {
+      return S_OK;
+    }
+
+    // Construct a fully qualified path to the Windows system directory
+    static const WCHAR wzNormaliz[] = L"normaliz.dll";
+    static const int cchNormaliz = cElements(wzNormaliz);
+    WCHAR wzDllPath[MAX_PATH + 1] = {0};
+    if (!::GetSystemDirectoryW(wzDllPath,
+                               cElements(wzDllPath) - cchNormaliz - 1)) {
+      return E_FAIL;
+    }
+    int cchDllPath = ::lstrlenW(wzDllPath);
+    if (!cchDllPath) {
+      return E_FAIL;
+    }
+    if (wzDllPath[cchDllPath-1] != L'\\') {
+      wzDllPath[cchDllPath++] = L'\\';
+    }
+    ::CopyMemory(wzDllPath + cchDllPath,
+                 wzNormaliz,
+                 cchNormaliz * sizeof(WCHAR));
+
+    // Load the DLL used for domain normalization
+    HMODULE hNormaliz = ::LoadLibraryExW(wzDllPath,
+                                         NULL,
+                                         LOAD_WITH_ALTERED_SEARCH_PATH);
+    if (!hNormaliz) {
+      return E_FAIL;
+    }
+
+    HRESULT hr = E_FAIL;
+
+    // Locate the entry point used for domain normalization
+    PFN_IdnToAscii pfnIdnToAscii =
+        (PFN_IdnToAscii)::GetProcAddress(hNormaliz, "IdnToAscii");
+    if (!pfnIdnToAscii) {
+      goto cleanup;
+    }
+
+    // Normalize the domain name
+    WCHAR wzEncoded[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+    int cchEncode = pfnIdnToAscii(IDN_USE_STD3_ASCII_RULES,
+                                  wzDomain,
+                                  ::lstrlenW(wzDomain),
+                                  wzEncoded,
+                                  cElements(wzEncoded));
+    if (0 == cchEncode) {
+      hr = HRESULT_FROM_WIN32(::GetLastError());
+      goto cleanup;
+    }
+
+    // Copy results to the input buffer
+    if (cchEncode >= cchDomain) {
+      hr = E_OUTOFMEMORY;
+      goto cleanup;
+    }
+
+    ::CopyMemory(wzDomain, wzEncoded, cchEncode * sizeof(WCHAR));
+    hr = S_OK;
+
+ cleanup:
+    if (hNormaliz) {
+      ::CloseHandle(hNormaliz);
+    }
+
+    return hr;
+  }
+
+  // Extracts a normalized domain and scheme from an activation URL
+  HRESULT GetDomainAndScheme(const OLECHAR* wzUrl,
+                             OLECHAR* wzScheme,
+                             DWORD cchScheme,
+                             OLECHAR* wzDomain,
+                             DWORD cchDomain) {
+    // Data validation
+    if (!wzDomain || !wzScheme) {
+      return E_POINTER;
+    }
+
+    // Extract the scheme
+    HRESULT hr = ::UrlGetPartW(wzUrl, wzScheme, &cchScheme, URL_PART_SCHEME, 0);
+    if (FAILED(hr)) {
+      return E_FAIL;
+    }
+
+    // Extract the host name
+    DWORD cchDomain2 = cchDomain;
+    hr = ::UrlGetPartW(wzUrl, wzDomain, &cchDomain2, URL_PART_HOSTNAME, 0);
+    if (FAILED(hr)) {
+      *wzDomain = 0;
+    }
+
+    // Exclude any URL specifying a user name or password
+    if ((0 == ::_wcsicmp(wzScheme, L"http")) ||
+        (0 == ::_wcsicmp(wzScheme, L"https"))) {
+      DWORD cch = 1;
+      WCHAR wzTemp[1] = {0};
+      ::UrlGetPartW(wzUrl, wzTemp, &cch, URL_PART_USERNAME, 0);
+      if (1 < cch) {
+        return E_FAIL;
+      }
+      ::UrlGetPartW(wzUrl, wzTemp, &cch, URL_PART_PASSWORD, 0);
+      if (1 < cch) {
+        return E_FAIL;
+      }
+    }
+
+    // Normalize the domain name
+    return NormalizeDomain(wzDomain, cchDomain);
+  }
+
+  // Attempts to match an activation URL with a domain name
+  bool MatchDomains(const OLECHAR* wzTrustedDomain,
+                    const OLECHAR* wzOurDomain) {
+    // Data validation
+    if (!wzTrustedDomain) {
+      return (0 == *wzOurDomain);  // match only if empty
+    }
+
+    // Declarations
+    int cchTrusted = ::lstrlenW(wzTrustedDomain);
+    int cchOur = ::lstrlenW(wzOurDomain);
+    bool fForcePrefix = false;
+    bool fDenyPrefix = false;
+
+    // Check if all activation URLs should be matched
+    if (0 == ::wcscmp(wzTrustedDomain, L"*")) {
+      return true;
+    }
+
+    // Check if the entry is like *. and setup the comparison range
+    if ((2 < cchTrusted) &&
+        (L'*' == wzTrustedDomain[0]) &&
+        (L'.' == wzTrustedDomain[1])) {
+      fForcePrefix = true;
+      wzTrustedDomain += 2;
+      cchTrusted -= 2;
+
+      // Check if the entry is like = and setup the comparison range
+    } else if ((1 < cchTrusted) && (L'=' == wzTrustedDomain[0])) {
+      fDenyPrefix = true;
+      wzTrustedDomain++;
+      cchTrusted--;
+    };
+
+    // Check if there is a count mismatch
+    if (cchTrusted > cchOur) {
+      return false;
+    }
+
+    // Compare URLs on the desired character range
+    if (0 != ::memcmp(wzOurDomain + cchOur - cchTrusted,
+                      wzTrustedDomain,
+                      cchTrusted * sizeof(OLECHAR))) {
+      return false;
+    }
+
+    // Compare URLs without allowing child domains
+    if (!fForcePrefix && (cchTrusted == cchOur)) {
+      return true;
+    }
+
+    // Compare URLs requiring child domains
+    if (!fDenyPrefix && (wzOurDomain[cchOur - cchTrusted - 1] == L'.')) {
+      return true;
+    }
+
+    return false;
+  }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// IObjectSafetySiteLockImpl - "Safe for scripting" template
+template <typename T, DWORD dwSupportedSafety>
+class ATL_NO_VTABLE IObjectSafetySiteLockImpl
+    : public IObjectSafetySiteLock,
+      public CSiteLock<T> {
+ public:
+  // Constructor
+  IObjectSafetySiteLockImpl(): m_dwCurrentSafety(0) {}
+
+  // Returns safety options
+  STDMETHOD(GetInterfaceSafetyOptions)(REFIID riid,
+                                       DWORD * pdwSupportedOptions,
+                                       DWORD * pdwEnabledOptions) {
+    // Data validation
+    if (!pdwSupportedOptions || !pdwEnabledOptions) {
+      return E_POINTER;
+    }
+
+    // Declarations
+    HRESULT hr = S_OK;
+    IUnknown* pUnk = NULL;
+
+    // Get the current pointer as an instance of the template class
+    T * pT = static_cast<T*>(this);
+
+    // Check if the requested COM interface is supported
+    hr = pT->GetUnknown()->QueryInterface(riid,
+                                          reinterpret_cast<void**>(&pUnk));
+    if (FAILED(hr)) {
+      *pdwSupportedOptions = 0;
+      *pdwEnabledOptions   = 0;
+      return hr;
+    }
+
+    // Release the interface
+    pUnk->Release();
+
+    // Check expiry and if the activation URL is allowed
+    if (!ControlExpired() && InApprovedDomain()) {
+      *pdwSupportedOptions = dwSupportedSafety;
+      *pdwEnabledOptions   = m_dwCurrentSafety;
+    } else {
+      *pdwSupportedOptions = dwSupportedSafety;
+      *pdwEnabledOptions   = 0;
+    }
+    return S_OK;
+  }
+
+  // Sets safety options
+  STDMETHOD(SetInterfaceSafetyOptions)(REFIID riid,
+                                       DWORD dwOptionSetMask,
+                                       DWORD dwEnabledOptions) {
+    // Declarations
+    HRESULT hr = S_OK;
+    IUnknown* pUnk = NULL;
+
+    // Get the current pointer as an instance of the template class
+    T * pT = static_cast<T*>(this);
+
+    // Check if we support the interface and return E_NOINTERFACE if we don't
+    // Check if the requested COM interface is supported
+    hr = pT->GetUnknown()->QueryInterface(riid,
+                                          reinterpret_cast<void**>(&pUnk));
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    // Release the interface
+    pUnk->Release();
+
+    // Reject unsupported requests
+    if (dwOptionSetMask & ~dwSupportedSafety) {
+      return E_FAIL;
+    }
+
+    // Calculate safety options
+    DWORD dwNewSafety = (m_dwCurrentSafety & ~dwOptionSetMask) |
+                        (dwOptionSetMask & dwEnabledOptions);
+    if (m_dwCurrentSafety != dwNewSafety) {
+      // Check expiry and if the activation URL is allowed
+      if (ControlExpired() || !InApprovedDomain()) {
+        return E_FAIL;
+      }
+
+      // Set safety options
+      m_dwCurrentSafety = dwNewSafety;
+    }
+    return S_OK;
+  }
+
+  // Returns capabilities (this can be used by testing tools to query for
+  // custom capabilities or version information)
+  STDMETHOD(GetCapabilities)(DWORD * pdwCapability) {
+    // Data validation
+    if (!pdwCapability) {
+      return E_POINTER;
+    }
+
+    // Return the version if 0 is passed in
+    if (0 == *pdwCapability) {
+      *pdwCapability = SITELOCK_VERSION;
+      return S_OK;
+    }
+
+    // Return the options if 1 is passed in
+    if (1 == *pdwCapability) {
+      *pdwCapability =
+#ifdef SITELOCK_USE_IOLEOBJECT
+        Capability::UsesIOleObject |
+#endif
+#ifndef SITELOCK_NO_EXPIRY
+        Capability::HasExpiry |
+#endif
+        0;
+      return S_OK;
+    }
+
+    // Return not implemented otherwise
+    *pdwCapability = 0;
+    return E_NOTIMPL;
+  }
+
+  // Returns site lock entries controlling activation
+  STDMETHOD(GetApprovedSites)(const SiteList ** pSiteList, DWORD * pcEntries) {
+    // Data validation
+    if (!pSiteList || !pcEntries) {
+      return E_POINTER;
+    }
+
+    // Return specified site lock entries
+#ifdef SITELOCK_USE_MAP
+    // Use the site lock map
+    *pSiteList = T::GetSiteLockMapAndCount(*pcEntries);
+#else
+    // Use the static member
+    *pSiteList = T::rgslTrustedSites;
+    *pcEntries = cElements(T::rgslTrustedSites);
+#endif
+    return S_OK;
+  }
+
+  STDMETHOD(GetExpiryDate)(DWORD * pdwLifespan, FILETIME * pExpiryDate) {
+    if (!pdwLifespan || !pExpiryDate) {
+      return E_POINTER;
+    }
+
+#ifdef SITELOCK_NO_EXPIRY
+    *pdwLifespan = 0;
+    ::ZeroMemory(reinterpret_cast<void*>(pExpiryDate), sizeof(FILETIME));
+    return E_NOTIMPL;
+#else
+    *pdwLifespan = T::dwControlLifespan;
+
+    // Calculate expiry date from life span
+    time_t ttExpire = ImageNtHeaders(&__ImageBase)->FileHeader.TimeDateStamp;
+    ttExpire += T::dwControlLifespan*86400;  // seconds per day
+    _UNIXTimeToFILETIME(ttExpire, pExpiryDate);
+
+    return S_OK;
+#endif
+  }
+
+ private:
+  // Current safety
+  DWORD m_dwCurrentSafety;
+};
+
+#endif  // OMAHA_PLUGINS_SITELOCK_H__
diff --git a/precompile/precompile.cc b/precompile/precompile.cc
index fd0f0f8..a108af7 100644
--- a/precompile/precompile.cc
+++ b/precompile/precompile.cc
@@ -1,18 +1,18 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// 4505: unreferenced local function has been removed

-#pragma warning(disable : 4505)

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// 4505: unreferenced local function has been removed
+#pragma warning(disable : 4505)
+
diff --git a/precompile/precompile.h b/precompile/precompile.h
index 4494841..9aa7bac 100644
--- a/precompile/precompile.h
+++ b/precompile/precompile.h
@@ -1,73 +1,73 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_PRECOMPILE_PRECOMPILE_H__

-#define OMAHA_PRECOMPILE_PRECOMPILE_H__

-

-// 'function': name was marked as #pragma deprecated

-#pragma warning(disable : 4995)

-

-#pragma warning(push)

-// C4201: nonstandard extension used : nameless struct/union

-#pragma warning(disable : 4201)

-#include <windows.h>

-#include <winioctl.h>

-#include <wtypes.h>

-#include <tchar.h>

-#include <strsafe.h>

-

-#include "omaha/common/atlassert.h"   // Redefines ATLASSERT.

-

-// C4061: enumerate is not explicitly handled by a case label

-// C4265: class has virtual functions, but destructor is not virtual

-// C4510: default constructor could not be generated

-// C4548: expression before comma has no effect

-// C4610: struct can never be instantiated - user defined constructor required

-// C4826: conversion from 'type1 ' to 'type_2' is sign-extended

-#pragma warning(disable : 4061 4265 4510 4610 4548 4826)

-#include <atlbase.h>

-#include <atlstr.h>

-#include <atlcoll.h>

-#include <atlcom.h>

-#include <atlhost.h>

-#include <atlrx.h>

-#include <atlsecurity.h>

-#include <atltypes.h>

-#include <atlwin.h>

-#include <algorithm>

-#include <cstdlib>

-#include <list>

-#include <map>

-#include <queue>

-#include <string>

-#include <vector>

-#pragma warning(pop)

-

-#if (_MSC_VER < 1400)

-// TODO(omaha): fix the atlconv for VC8.

-#include "omaha/common/atlconvfix.h"

-#endif

-

-#pragma warning(push)

-// C4310: cast truncates constant value

-#pragma warning(disable : 4310)

-#include "base/basictypes.h"

-#pragma warning(pop)

-

-#ifdef UNITTEST

-#include "third_party/gtest/include/gtest/gtest.h"

-#endif  // UNITTEST

-

-#endif  // OMAHA_PRECOMPILE_PRECOMPILE_H__

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_PRECOMPILE_PRECOMPILE_H__
+#define OMAHA_PRECOMPILE_PRECOMPILE_H__
+
+// 'function': name was marked as #pragma deprecated
+#pragma warning(disable : 4995)
+
+#pragma warning(push)
+// C4201: nonstandard extension used : nameless struct/union
+#pragma warning(disable : 4201)
+#include <windows.h>
+#include <winioctl.h>
+#include <wtypes.h>
+#include <tchar.h>
+#include <strsafe.h>
+
+#include "omaha/common/atlassert.h"   // Redefines ATLASSERT.
+
+// C4061: enumerate is not explicitly handled by a case label
+// C4265: class has virtual functions, but destructor is not virtual
+// C4510: default constructor could not be generated
+// C4548: expression before comma has no effect
+// C4610: struct can never be instantiated - user defined constructor required
+// C4826: conversion from 'type1 ' to 'type_2' is sign-extended
+#pragma warning(disable : 4061 4265 4510 4610 4548 4826)
+#include <atlbase.h>
+#include <atlstr.h>
+#include <atlcoll.h>
+#include <atlcom.h>
+#include <atlhost.h>
+#include <atlrx.h>
+#include <atlsecurity.h>
+#include <atltypes.h>
+#include <atlwin.h>
+#include <algorithm>
+#include <cstdlib>
+#include <list>
+#include <map>
+#include <queue>
+#include <string>
+#include <vector>
+#pragma warning(pop)
+
+#if (_MSC_VER < 1400)
+// TODO(omaha): fix the atlconv for VC8.
+#include "omaha/common/atlconvfix.h"
+#endif
+
+#pragma warning(push)
+// C4310: cast truncates constant value
+#pragma warning(disable : 4310)
+#include "base/basictypes.h"
+#pragma warning(pop)
+
+#ifdef UNITTEST
+#include "third_party/gtest/include/gtest/gtest.h"
+#endif  // UNITTEST
+
+#endif  // OMAHA_PRECOMPILE_PRECOMPILE_H__
diff --git a/recovery/build.scons b/recovery/build.scons
index f2ab64a..f0fe973 100644
--- a/recovery/build.scons
+++ b/recovery/build.scons
@@ -1,87 +1,87 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-#

-# Build google_update_recovery library for Google app consumption.

-#

-rec_env = env.Clone()

-recovery_inputs = [

-    '../common/google_update_recovery.cc',

-    '../common/signaturevalidator.cc',

-    ]

-

-# Need to add custom suffix to avoid target conflict with

-# common/signaturevalidator.obj

-rec_env['OBJSUFFIX'] = '_rec' + rec_env['OBJSUFFIX']

-

-rec_env.ComponentLibrary('google_update_recovery.lib', recovery_inputs)

-

-# Save the lib to the main build directory, so we have it saved with each

-# official build.

-env.Replicate('$STAGING_DIR', ['$LIB_DIR/google_update_recovery.lib',

-                               '$MAIN_DIR/common/google_update_recovery.h'])

-

-

-#

-# Build the test

-#

-test_env = env.Clone()

-test_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-test_env.Append(

-    LINKFLAGS = [

-        '/SUBSYSTEM:CONSOLE'

-        ],

-    LIBS = [

-        '$LIB_DIR/common.lib',

-        '$LIB_DIR/net.lib',

-        '$LIB_DIR/google_update_recovery.lib',

-        '$LIB_DIR/security.lib',

-        ('atls.lib', 'atlsd.lib')[test_env.Bit('debug')],

-        ('libcmt.lib', 'libcmtd.lib')[test_env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[test_env.Bit('debug')],

-        'crypt32.lib',

-        'wintrust.lib',

-

-        # These are required by common_lib

-        'netapi32.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'shlwapi.lib',

-        'userenv.lib',

-        'version.lib',

-        'wtsapi32.lib',

-

-        # net

-        'iphlpapi.lib',

-        ],

-)

-

-target_name = 'RecoveryTest.exe'

-

-test_inputs = [

-    'recovery_test.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  test_inputs += test_env.EnablePrecompile(target_name)

-

-test_env.ComponentProgram(target_name, test_inputs)

-

-

-env.BuildSConscript('repair_exe')

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+#
+# Build google_update_recovery library for Google app consumption.
+#
+rec_env = env.Clone()
+recovery_inputs = [
+    '../common/google_update_recovery.cc',
+    '../common/signaturevalidator.cc',
+    ]
+
+# Need to add custom suffix to avoid target conflict with
+# common/signaturevalidator.obj
+rec_env['OBJSUFFIX'] = '_rec' + rec_env['OBJSUFFIX']
+
+rec_env.ComponentLibrary('google_update_recovery.lib', recovery_inputs)
+
+# Save the lib to the main build directory, so we have it saved with each
+# official build.
+env.Replicate('$STAGING_DIR', ['$LIB_DIR/google_update_recovery.lib',
+                               '$MAIN_DIR/common/google_update_recovery.h'])
+
+
+#
+# Build the test
+#
+test_env = env.Clone()
+test_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+test_env.Append(
+    LINKFLAGS = [
+        '/SUBSYSTEM:CONSOLE'
+        ],
+    LIBS = [
+        '$LIB_DIR/common.lib',
+        '$LIB_DIR/net.lib',
+        '$LIB_DIR/google_update_recovery.lib',
+        '$LIB_DIR/security.lib',
+        ('atls.lib', 'atlsd.lib')[test_env.Bit('debug')],
+        ('libcmt.lib', 'libcmtd.lib')[test_env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[test_env.Bit('debug')],
+        'crypt32.lib',
+        'wintrust.lib',
+
+        # These are required by common_lib
+        'netapi32.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'shlwapi.lib',
+        'userenv.lib',
+        'version.lib',
+        'wtsapi32.lib',
+
+        # net
+        'iphlpapi.lib',
+        ],
+)
+
+target_name = 'RecoveryTest.exe'
+
+test_inputs = [
+    'recovery_test.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  test_inputs += test_env.EnablePrecompile(target_name)
+
+test_env.ComponentProgram(target_name, test_inputs)
+
+
+env.BuildSConscript('repair_exe')
diff --git a/recovery/lib/google_update_recovery.h b/recovery/lib/google_update_recovery.h
index ccf4b48..a62627a 100644
--- a/recovery/lib/google_update_recovery.h
+++ b/recovery/lib/google_update_recovery.h
@@ -1,47 +1,47 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Defines the interface to the Google Update recovery mechanism to be included

-// in Google apps.

-

-#ifndef OMAHA_RECOVERY_LIB_GOOGLE_UPDATE_RECOVERY_H__

-#define OMAHA_RECOVERY_LIB_GOOGLE_UPDATE_RECOVERY_H__

-

-#include <tchar.h>

-#include <windows.h>

-

-#ifndef UNICODE

-#error The distributed library only supports UNICODE.

-#endif

-

-extern "C" {

-typedef HRESULT (*DownloadCallback)(const TCHAR* url,

-                                    const TCHAR* file_path,

-                                    void* context);

-

-// Determines whether there is a Code Red event for the current installation

-// and repairs it if necessary.

-// app_language should follow the external Internet standard

-// Best Common Practice (BCP) 47: http://www.rfc-editor.org/rfc/bcp/bcp47.txt

-// context can be NULL if download_callback does not use it.

-HRESULT FixGoogleUpdate(const TCHAR* app_guid,

-                        const TCHAR* app_version,

-                        const TCHAR* app_language,

-                        bool is_machine_app,

-                        DownloadCallback download_callback,

-                        void* context);

-}  // extern "C"

-

-#endif  // OMAHA_RECOVERY_LIB_GOOGLE_UPDATE_RECOVERY_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Defines the interface to the Google Update recovery mechanism to be included
+// in Google apps.
+
+#ifndef OMAHA_RECOVERY_LIB_GOOGLE_UPDATE_RECOVERY_H__
+#define OMAHA_RECOVERY_LIB_GOOGLE_UPDATE_RECOVERY_H__
+
+#include <tchar.h>
+#include <windows.h>
+
+#ifndef UNICODE
+#error The distributed library only supports UNICODE.
+#endif
+
+extern "C" {
+typedef HRESULT (*DownloadCallback)(const TCHAR* url,
+                                    const TCHAR* file_path,
+                                    void* context);
+
+// Determines whether there is a Code Red event for the current installation
+// and repairs it if necessary.
+// app_language should follow the external Internet standard
+// Best Common Practice (BCP) 47: http://www.rfc-editor.org/rfc/bcp/bcp47.txt
+// context can be NULL if download_callback does not use it.
+HRESULT FixGoogleUpdate(const TCHAR* app_guid,
+                        const TCHAR* app_version,
+                        const TCHAR* app_language,
+                        bool is_machine_app,
+                        DownloadCallback download_callback,
+                        void* context);
+}  // extern "C"
+
+#endif  // OMAHA_RECOVERY_LIB_GOOGLE_UPDATE_RECOVERY_H__
diff --git a/recovery/lib/readme.txt b/recovery/lib/readme.txt
index 93f2dd2..9d4f645 100644
--- a/recovery/lib/readme.txt
+++ b/recovery/lib/readme.txt
@@ -1 +1 @@
-These files are for Omaha Code Red (Google Update Recovery). Use these files to integrate Code Red into your Omaha-compatible app.

+These files are for Omaha Code Red (Google Update Recovery). Use these files to integrate Code Red into your Omaha-compatible app.
diff --git a/recovery/recovery_markup.rc b/recovery/recovery_markup.rc
index 409e1bb..e707c72 100644
--- a/recovery/recovery_markup.rc
+++ b/recovery/recovery_markup.rc
@@ -1,28 +1,28 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <afxres.h>

-

-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

-#ifdef _WIN32

-LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL

-#pragma code_page(1252)

-#endif //_WIN32

-

-#define IDR_REPAIR_FILE_MARKUP 1

-

-IDR_REPAIR_FILE_MARKUP GOOGLEUPDATEREPAIR { 1L }

-

-#endif    // English (U.S.) resources

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <afxres.h>
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1252)
+#endif //_WIN32
+
+#define IDR_REPAIR_FILE_MARKUP 1
+
+IDR_REPAIR_FILE_MARKUP GOOGLEUPDATEREPAIR { 1L }
+
+#endif    // English (U.S.) resources
diff --git a/recovery/recovery_test.cc b/recovery/recovery_test.cc
index 8d51ac2..5bf1d90 100644
--- a/recovery/recovery_test.cc
+++ b/recovery/recovery_test.cc
@@ -1,88 +1,88 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Test app for the Google Update recovery mechanism.

-#include <windows.h>

-#include <atlstr.h>

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/google_update_recovery.h"

-#include "omaha/common/logging.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/network_request.h"

-

-using omaha::GoogleProxyDetector;

-using omaha::FirefoxProxyDetector;

-using omaha::IEProxyDetector;

-using omaha::NetworkRequest;

-using omaha::NetworkConfig;

-

-namespace {

-

-// Implements the DownloadFileMethod signature.

-HRESULT DownloadFile(const TCHAR* url, const TCHAR* file_path, void*) {

-  UTIL_LOG(L2, (_T("[DownloadFile][%s][%s]"), url, file_path));

-

-  ASSERT1(url);

-  ASSERT1(file_path);

-

-  CString test_url(url);

-  CString test_file_path(file_path);

-

-// Include this code to override the address portion of the URL.

-#if 1

-  // Change the URL below to point to a test repair exe of your own.

-  const TCHAR* const kTestAddress =

-      _T("http://dl.google.com/insert_your_file_here?");

-

-  VERIFY1(1 == test_url.Replace(omaha::kUrlCodeRedCheck, kTestAddress));

-#endif

-

-  // Initialize the network for user with no impersonation required.

-  NetworkConfig& network_config = NetworkConfig::Instance();

-  network_config.Initialize(false, NULL);

-  network_config.Add(new GoogleProxyDetector(MACHINE_REG_UPDATE_DEV));

-  network_config.Add(new FirefoxProxyDetector());

-  network_config.Add(new IEProxyDetector());

-

-  NetworkRequest network_request(network_config.session());

-  HRESULT hr = network_request.DownloadFile(test_url, CString(file_path));

-

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[DownloadFile failed][%s][0x%08x]"), test_url, hr));

-    return hr;

-  }

-

-  int status_code = network_request.http_status_code();

-  UTIL_LOG(L2, (_T("[HTTP status][%u]"), status_code));

-

-  return (HTTP_STATUS_OK == status_code) ? S_OK : E_FAIL;

-}

-

-}  // namespace

-

-int main() {

-  const TCHAR* const kDummyGuid = _T("{20F8FA32-8E16-4046-834B-88661E021AFC}");

-

-  HRESULT hr = FixGoogleUpdate(kDummyGuid,

-                               _T("1.0.555.0"),

-                               _T("en-us"),

-                               true,

-                               DownloadFile,

-                               NULL);

-

-  return hr;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Test app for the Google Update recovery mechanism.
+#include <windows.h>
+#include <atlstr.h>
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/google_update_recovery.h"
+#include "omaha/common/logging.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/network_request.h"
+
+using omaha::GoogleProxyDetector;
+using omaha::FirefoxProxyDetector;
+using omaha::IEProxyDetector;
+using omaha::NetworkRequest;
+using omaha::NetworkConfig;
+
+namespace {
+
+// Implements the DownloadFileMethod signature.
+HRESULT DownloadFile(const TCHAR* url, const TCHAR* file_path, void*) {
+  UTIL_LOG(L2, (_T("[DownloadFile][%s][%s]"), url, file_path));
+
+  ASSERT1(url);
+  ASSERT1(file_path);
+
+  CString test_url(url);
+  CString test_file_path(file_path);
+
+// Include this code to override the address portion of the URL.
+#if 1
+  // Change the URL below to point to a test repair exe of your own.
+  const TCHAR* const kTestAddress =
+      _T("http://dl.google.com/insert_your_file_here?");
+
+  VERIFY1(1 == test_url.Replace(omaha::kUrlCodeRedCheck, kTestAddress));
+#endif
+
+  // Initialize the network for user with no impersonation required.
+  NetworkConfig& network_config = NetworkConfig::Instance();
+  network_config.Initialize(false, NULL);
+  network_config.Add(new GoogleProxyDetector(MACHINE_REG_UPDATE_DEV));
+  network_config.Add(new FirefoxProxyDetector());
+  network_config.Add(new IEProxyDetector());
+
+  NetworkRequest network_request(network_config.session());
+  HRESULT hr = network_request.DownloadFile(test_url, CString(file_path));
+
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[DownloadFile failed][%s][0x%08x]"), test_url, hr));
+    return hr;
+  }
+
+  int status_code = network_request.http_status_code();
+  UTIL_LOG(L2, (_T("[HTTP status][%u]"), status_code));
+
+  return (HTTP_STATUS_OK == status_code) ? S_OK : E_FAIL;
+}
+
+}  // namespace
+
+int main() {
+  const TCHAR* const kDummyGuid = _T("{20F8FA32-8E16-4046-834B-88661E021AFC}");
+
+  HRESULT hr = FixGoogleUpdate(kDummyGuid,
+                               _T("1.0.555.0"),
+                               _T("en-us"),
+                               true,
+                               DownloadFile,
+                               NULL);
+
+  return hr;
+}
diff --git a/recovery/repair_exe/build.scons b/recovery/repair_exe/build.scons
index 0b2e72b..bce4c3e 100644
--- a/recovery/repair_exe/build.scons
+++ b/recovery/repair_exe/build.scons
@@ -1,46 +1,46 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-local_env = env.Clone()

-

-target_name = 'repair_goopdate.lib'

-

-inputs = [

-    'mspexecutableelevator.cc',

-    'repair_goopdate.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  inputs += local_env.EnablePrecompile(target_name)

-

-local_env.ComponentLibrary(target_name, inputs)

-

-

-subdirs = [

-    'custom_action',

-    ]

-

-if not env.Bit('min'):

-  subdirs += [

-      'msp',

-      ]

-

-for subdir in subdirs:

-  env.BuildSConscript(subdir)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+local_env = env.Clone()
+
+target_name = 'repair_goopdate.lib'
+
+inputs = [
+    'mspexecutableelevator.cc',
+    'repair_goopdate.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  inputs += local_env.EnablePrecompile(target_name)
+
+local_env.ComponentLibrary(target_name, inputs)
+
+
+subdirs = [
+    'custom_action',
+    ]
+
+if not env.Bit('min'):
+  subdirs += [
+      'msp',
+      ]
+
+for subdir in subdirs:
+  env.BuildSConscript(subdir)
diff --git a/recovery/repair_exe/custom_action/build.scons b/recovery/repair_exe/custom_action/build.scons
index 0be4dc6..1fb3350 100644
--- a/recovery/repair_exe/custom_action/build.scons
+++ b/recovery/repair_exe/custom_action/build.scons
@@ -1,112 +1,112 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-#

-# Build executecustomaction.dll

-#

-dll_env = env.Clone(

-    # Build a dll, not a lib.

-    COMPONENT_STATIC = False,

-)

-

-dll_env.Append(

-    LIBS = [

-        ('atls.lib', 'atlsd.lib')[dll_env.Bit('debug')],

-        ('libcmt.lib', 'libcmtd.lib')[dll_env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[dll_env.Bit('debug')],

-        '$LIB_DIR/common.lib',

-        '$LIB_DIR/google_update_recovery.lib',

-        '$LIB_DIR/repair_goopdate.lib',

-        'crypt32.lib',

-        'msi.lib',

-        'wintrust.lib',

-

-        # These are required by common_lib

-        'netapi32.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'shlwapi.lib',

-        'userenv.lib',

-        'version.lib',

-        'wtsapi32.lib',

-        ],

-

-    CPPDEFINES = [

-        '_USRDLL',

-        ],

-)

-

-target_name = 'executecustomaction.dll'

-

-dll_inputs = [

-    'execute_repair_file.cc',

-    'executecustomaction.cc',

-    'executecustomaction.def',

-    ]

-if env.Bit('use_precompiled_headers'):

-  dll_inputs += dll_env.EnablePrecompile(target_name)

-

-dll_env.ComponentLibrary(

-    lib_name=target_name,

-    source=dll_inputs,

-)

-

-

-#

-# Build testelevateusingmsp.exe

-#

-exe_env = env.Clone()

-

-exe_env['LIBS'] += [

-    ('atls.lib', 'atlsd.lib')[exe_env.Bit('debug')],

-    ('libcmt.lib', 'libcmtd.lib')[exe_env.Bit('debug')],

-    ('libcpmt.lib', 'libcpmtd.lib')[exe_env.Bit('debug')],

-    '$LIB_DIR/common.lib',

-    '$LIB_DIR/repair_goopdate.lib',

-    'crypt32.lib',

-    'msi.lib',

-    'wintrust.lib',

-    # These are required by common_lib

-    'netapi32.lib',

-    'psapi.lib',

-    'rasapi32.lib',

-    'shlwapi.lib',

-    'userenv.lib',

-    'version.lib',

-    'wtsapi32.lib',

-    ]

-

-# This is a console application.

-exe_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-exe_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-target_name = 'testelevateusingmsp.exe'

-

-exe_inputs = [

-    'testelevateusingmsp.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  exe_inputs += exe_env.EnablePrecompile(target_name)

-

-exe_env.ComponentProgram(

-    prog_name=target_name,

-    source=exe_inputs,

-)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+#
+# Build executecustomaction.dll
+#
+dll_env = env.Clone(
+    # Build a dll, not a lib.
+    COMPONENT_STATIC = False,
+)
+
+dll_env.Append(
+    LIBS = [
+        ('atls.lib', 'atlsd.lib')[dll_env.Bit('debug')],
+        ('libcmt.lib', 'libcmtd.lib')[dll_env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[dll_env.Bit('debug')],
+        '$LIB_DIR/common.lib',
+        '$LIB_DIR/google_update_recovery.lib',
+        '$LIB_DIR/repair_goopdate.lib',
+        'crypt32.lib',
+        'msi.lib',
+        'wintrust.lib',
+
+        # These are required by common_lib
+        'netapi32.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'shlwapi.lib',
+        'userenv.lib',
+        'version.lib',
+        'wtsapi32.lib',
+        ],
+
+    CPPDEFINES = [
+        '_USRDLL',
+        ],
+)
+
+target_name = 'executecustomaction.dll'
+
+dll_inputs = [
+    'execute_repair_file.cc',
+    'executecustomaction.cc',
+    'executecustomaction.def',
+    ]
+if env.Bit('use_precompiled_headers'):
+  dll_inputs += dll_env.EnablePrecompile(target_name)
+
+dll_env.ComponentLibrary(
+    lib_name=target_name,
+    source=dll_inputs,
+)
+
+
+#
+# Build testelevateusingmsp.exe
+#
+exe_env = env.Clone()
+
+exe_env['LIBS'] += [
+    ('atls.lib', 'atlsd.lib')[exe_env.Bit('debug')],
+    ('libcmt.lib', 'libcmtd.lib')[exe_env.Bit('debug')],
+    ('libcpmt.lib', 'libcpmtd.lib')[exe_env.Bit('debug')],
+    '$LIB_DIR/common.lib',
+    '$LIB_DIR/repair_goopdate.lib',
+    'crypt32.lib',
+    'msi.lib',
+    'wintrust.lib',
+    # These are required by common_lib
+    'netapi32.lib',
+    'psapi.lib',
+    'rasapi32.lib',
+    'shlwapi.lib',
+    'userenv.lib',
+    'version.lib',
+    'wtsapi32.lib',
+    ]
+
+# This is a console application.
+exe_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+exe_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+target_name = 'testelevateusingmsp.exe'
+
+exe_inputs = [
+    'testelevateusingmsp.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  exe_inputs += exe_env.EnablePrecompile(target_name)
+
+exe_env.ComponentProgram(
+    prog_name=target_name,
+    source=exe_inputs,
+)
diff --git a/recovery/repair_exe/custom_action/execute_repair_file.cc b/recovery/repair_exe/custom_action/execute_repair_file.cc
index 690ada2..b830024 100644
--- a/recovery/repair_exe/custom_action/execute_repair_file.cc
+++ b/recovery/repair_exe/custom_action/execute_repair_file.cc
@@ -1,135 +1,135 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Verifies and executes the repair file for the MSP custom action.

-

-#include "omaha/recovery/repair_exe/custom_action/execute_repair_file.h"

-#include <shlobj.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/string.h"

-#include "omaha/common/system.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-namespace {

-

-// TODO(omaha): Add a parameter to specify the process working directory

-HRESULT ExecuteFile(const CString& filename, const CString& args) {

-  HRESULT hr = System::ShellExecuteProcess(filename, args, NULL, NULL);

-

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[ExecuteFile - failed to exec][%s][%s][0x%08x]"),

-                  filename, args, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT GetDir(int csidl, const CString& path_tail, CString* dir) {

-  ASSERT1(dir);

-

-  CString path;

-  HRESULT hr = GetFolderPath(csidl, &path);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (!::PathAppend(CStrBuf(path, MAX_PATH), path_tail)) {

-    return E_FAIL;

-  }

-  dir->SetString(path);

-

-  // Try to create the directory. Continue if the directory can't be created.

-  hr = CreateDir(path, NULL);

-  if (FAILED(hr)) {

-    UTIL_LOG(LW, (_T("[GetDir failed to create dir][%s][0x%08x]"), path, hr));

-  }

-  return S_OK;

-}

-

-// Creates machine wide goopdate install dir: "Program Files/Google/Update".

-CString GetMachineGoopdateInstallDir() {

-  CString path;

-  VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES,

-                           CString(OMAHA_REL_GOOPDATE_INSTALL_DIR),

-                           &path)));

-  return path;

-}

-

-// Copies the file to "%ProgramFiles%\Google\Update\".

-// Assumes %ProgramFiles% is secure, which it should be unless permissions have

-// been changed.

-// Note: Cannot use the temp dir because MSI uses the logon user's environment

-// and the user's temp dir is unlikely to be secure.

-HRESULT CopyToSecureLocation(const CString& source, CString* new_location) {

-  if (source.IsEmpty() || !new_location) {

-    return E_INVALIDARG;

-  }

-

-  CString filename = GetFileFromPath(source);

-  *new_location = GetMachineGoopdateInstallDir();

-  if (!::PathAppend(CStrBuf(*new_location, MAX_PATH), filename)) {

-    return HRESULTFromLastError();

-  }

-

-  return File::Copy(source, *new_location, true);

-}

-

-}  // namespace

-

-HRESULT VerifyIsValidRepairFile(const CString& filename);

-

-// Assumes it is called elevated or with admin permissions.

-// Copies the file to a secure location, before verifying and executing it.

-// When the file is an Omaha metainstaller, it is important that the temp

-// directory when elevated is also secure in order to maintain the security

-// of all files being executed while elevated.

-HRESULT VerifyFileAndExecute(const CString& filename, const CString& args) {

-  UTIL_LOG(L1, (_T("[VerifyFileAndExecute][%s][%s]"), filename, args));

-

-  CString secure_filename;

-  HRESULT hr = CopyToSecureLocation(filename, &secure_filename);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[CopyToSecureLocation failed][error 0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = omaha::VerifyIsValidRepairFile(secure_filename);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[VerifyIsValidRepairFile failed][error 0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = ExecuteFile(secure_filename, args);

-  if (FAILED(hr)) {

-    UTIL_LOG(LE, (_T("[ExecuteFile failed][error 0x%08x]"), hr));

-    return hr;

-  }

-

-  // Use the API directly rather than File::DeleteAfterReboot() because

-  // File::DeleteAfterReboot() moves the file immediately, causing the

-  // GetFileVersionInfoSize call in the metainstaller to fail.

-  // Because this is always run as SYSTEM, the delayed delete will succeed.

-  VERIFY1(::MoveFileEx(secure_filename, NULL, MOVEFILE_DELAY_UNTIL_REBOOT));

-

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Verifies and executes the repair file for the MSP custom action.
+
+#include "omaha/recovery/repair_exe/custom_action/execute_repair_file.h"
+#include <shlobj.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/string.h"
+#include "omaha/common/system.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+namespace {
+
+// TODO(omaha): Add a parameter to specify the process working directory
+HRESULT ExecuteFile(const CString& filename, const CString& args) {
+  HRESULT hr = System::ShellExecuteProcess(filename, args, NULL, NULL);
+
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[ExecuteFile - failed to exec][%s][%s][0x%08x]"),
+                  filename, args, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT GetDir(int csidl, const CString& path_tail, CString* dir) {
+  ASSERT1(dir);
+
+  CString path;
+  HRESULT hr = GetFolderPath(csidl, &path);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (!::PathAppend(CStrBuf(path, MAX_PATH), path_tail)) {
+    return E_FAIL;
+  }
+  dir->SetString(path);
+
+  // Try to create the directory. Continue if the directory can't be created.
+  hr = CreateDir(path, NULL);
+  if (FAILED(hr)) {
+    UTIL_LOG(LW, (_T("[GetDir failed to create dir][%s][0x%08x]"), path, hr));
+  }
+  return S_OK;
+}
+
+// Creates machine wide goopdate install dir: "Program Files/Google/Update".
+CString GetMachineGoopdateInstallDir() {
+  CString path;
+  VERIFY1(SUCCEEDED(GetDir(CSIDL_PROGRAM_FILES,
+                           CString(OMAHA_REL_GOOPDATE_INSTALL_DIR),
+                           &path)));
+  return path;
+}
+
+// Copies the file to "%ProgramFiles%\Google\Update\".
+// Assumes %ProgramFiles% is secure, which it should be unless permissions have
+// been changed.
+// Note: Cannot use the temp dir because MSI uses the logon user's environment
+// and the user's temp dir is unlikely to be secure.
+HRESULT CopyToSecureLocation(const CString& source, CString* new_location) {
+  if (source.IsEmpty() || !new_location) {
+    return E_INVALIDARG;
+  }
+
+  CString filename = GetFileFromPath(source);
+  *new_location = GetMachineGoopdateInstallDir();
+  if (!::PathAppend(CStrBuf(*new_location, MAX_PATH), filename)) {
+    return HRESULTFromLastError();
+  }
+
+  return File::Copy(source, *new_location, true);
+}
+
+}  // namespace
+
+HRESULT VerifyIsValidRepairFile(const CString& filename);
+
+// Assumes it is called elevated or with admin permissions.
+// Copies the file to a secure location, before verifying and executing it.
+// When the file is an Omaha metainstaller, it is important that the temp
+// directory when elevated is also secure in order to maintain the security
+// of all files being executed while elevated.
+HRESULT VerifyFileAndExecute(const CString& filename, const CString& args) {
+  UTIL_LOG(L1, (_T("[VerifyFileAndExecute][%s][%s]"), filename, args));
+
+  CString secure_filename;
+  HRESULT hr = CopyToSecureLocation(filename, &secure_filename);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[CopyToSecureLocation failed][error 0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = omaha::VerifyIsValidRepairFile(secure_filename);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[VerifyIsValidRepairFile failed][error 0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = ExecuteFile(secure_filename, args);
+  if (FAILED(hr)) {
+    UTIL_LOG(LE, (_T("[ExecuteFile failed][error 0x%08x]"), hr));
+    return hr;
+  }
+
+  // Use the API directly rather than File::DeleteAfterReboot() because
+  // File::DeleteAfterReboot() moves the file immediately, causing the
+  // GetFileVersionInfoSize call in the metainstaller to fail.
+  // Because this is always run as SYSTEM, the delayed delete will succeed.
+  VERIFY1(::MoveFileEx(secure_filename, NULL, MOVEFILE_DELAY_UNTIL_REBOOT));
+
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/recovery/repair_exe/custom_action/execute_repair_file.h b/recovery/repair_exe/custom_action/execute_repair_file.h
index 80696da..123b05d 100644
--- a/recovery/repair_exe/custom_action/execute_repair_file.h
+++ b/recovery/repair_exe/custom_action/execute_repair_file.h
@@ -1,31 +1,31 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Verifies and executes the repair file for the MSP custom action.

-

-#ifndef OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTE_REPAIR_FILE_H__

-#define OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTE_REPAIR_FILE_H__

-

-#include <windows.h>

-#include <atlstr.h>

-

-namespace omaha {

-

-// Verifies the repair file and executes it.

-HRESULT VerifyFileAndExecute(const CString& filename, const CString& args);

-

-}  // namespace omaha

-

-#endif  // OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTE_REPAIR_FILE_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Verifies and executes the repair file for the MSP custom action.
+
+#ifndef OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTE_REPAIR_FILE_H__
+#define OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTE_REPAIR_FILE_H__
+
+#include <windows.h>
+#include <atlstr.h>
+
+namespace omaha {
+
+// Verifies the repair file and executes it.
+HRESULT VerifyFileAndExecute(const CString& filename, const CString& args);
+
+}  // namespace omaha
+
+#endif  // OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTE_REPAIR_FILE_H__
diff --git a/recovery/repair_exe/custom_action/execute_repair_file_unittest.cc b/recovery/repair_exe/custom_action/execute_repair_file_unittest.cc
index 8116c1c..f534e89 100644
--- a/recovery/repair_exe/custom_action/execute_repair_file_unittest.cc
+++ b/recovery/repair_exe/custom_action/execute_repair_file_unittest.cc
@@ -1,145 +1,145 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Unit tests for the file execution module of the MSP custom action.

-

-#include "omaha/common/app_util.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/recovery/repair_exe/custom_action/execute_repair_file.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-// The valid repair file saves the arguments passed to it to a file.

-void RunAndVerifySavedArgs(const CString& args) {

-  CString expected_copy_path =

-      _T("%PROGRAMFILES%\\Google\\Update\\SaveArguments.exe");

-  EXPECT_SUCCEEDED(ExpandStringWithSpecialFolders(&expected_copy_path));

-  CString saved_arguments_file_path =

-      _T("%PROGRAMFILES%\\Google\\Update\\saved_arguments.txt");

-  EXPECT_SUCCEEDED(ExpandStringWithSpecialFolders(&saved_arguments_file_path));

-

-  CString repair_file(app_util::GetCurrentModuleDirectory());

-  EXPECT_TRUE(::PathAppend(CStrBuf(repair_file, MAX_PATH),

-              _T("unittest_support\\SaveArguments.exe")));

-

-  ::DeleteFile(saved_arguments_file_path);

-

-  if (vista_util::IsUserAdmin()) {

-    EXPECT_FALSE(File::Exists(saved_arguments_file_path));

-

-    EXPECT_SUCCEEDED(omaha::VerifyFileAndExecute(repair_file, args));

-

-    bool is_found = false;

-    for (int tries = 0; tries < 100 && !is_found; ++tries) {

-      ::Sleep(50);

-      is_found = File::Exists(saved_arguments_file_path);

-    }

-    ASSERT_TRUE(is_found);

-

-    scoped_hfile file;

-    for (int tries = 0; tries < 100 && !valid(file); ++tries) {

-      ::Sleep(50);

-      reset(file, ::CreateFile(saved_arguments_file_path,

-                               GENERIC_READ,

-                               0,                        // do not share

-                               NULL,                     // default security

-                               OPEN_EXISTING,            // existing file only

-                               FILE_ATTRIBUTE_NORMAL,

-                               NULL));                   // no template

-    }

-    ASSERT_TRUE(valid(file));

-

-    const int kBufferLen = 50;

-    TCHAR buffer[kBufferLen + 1] = {0};

-    DWORD bytes_read = 0;

-

-    // Do not assume the buffer read by ReadFile remains zero-terminated.

-    EXPECT_TRUE(::ReadFile(get(file),

-                           buffer,

-                           kBufferLen * sizeof(TCHAR),

-                           &bytes_read,

-                           NULL));

-    EXPECT_EQ(0, bytes_read % sizeof(TCHAR));

-    buffer[bytes_read / sizeof(TCHAR)] = _T('\0');

-    EXPECT_STREQ(args, buffer);

-

-    reset(file);

-

-    ::DeleteFile(expected_copy_path);

-    EXPECT_TRUE(::DeleteFile(saved_arguments_file_path));

-  } else {

-    const bool expected_file_exists = File::Exists(saved_arguments_file_path);

-    EXPECT_EQ(E_ACCESSDENIED, omaha::VerifyFileAndExecute(repair_file, args));

-

-    // We can't force the file to be deleted, so make sure it wasn't created

-    // or deleted by the above method.

-    EXPECT_EQ(expected_file_exists, File::Exists(saved_arguments_file_path));

-  }

-}

-

-}  // namespace

-

-TEST(ExecuteRepairFileTest, VerifyFileAndExecute_EmptyFilename) {

-  EXPECT_EQ(E_INVALIDARG, VerifyFileAndExecute(_T(""), _T("")));

-}

-

-TEST(ExecuteRepairFileTest, VerifyFileAndExecute_FileDoesNotExist) {

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            VerifyFileAndExecute(_T("no_such_file.exe"), _T("")));

-}

-

-TEST(ExecuteRepairFileTest, VerifyFileAndExecute_FilenameIsDirectory) {

-  EXPECT_EQ(E_ACCESSDENIED,

-            VerifyFileAndExecute(_T("C:\\Windows"), _T("")));

-}

-

-TEST(ExecuteRepairFileTest, VerifyFileAndExecute_UnsignedFile) {

-  CString expected_copy_path =

-      _T("%PROGRAMFILES%\\Google\\Update\\GoogleUpdate_unsigned.exe");

-  EXPECT_SUCCEEDED(ExpandStringWithSpecialFolders(&expected_copy_path));

-  CString repair_file(app_util::GetCurrentModuleDirectory());

-  EXPECT_TRUE(::PathAppend(CStrBuf(repair_file, MAX_PATH),

-              _T("GoogleUpdate_unsigned.exe")));

-

-  if (vista_util::IsUserAdmin()) {

-    EXPECT_EQ(TRUST_E_NOSIGNATURE, VerifyFileAndExecute(repair_file, _T("")));

-

-    EXPECT_TRUE(File::Exists(expected_copy_path));

-    EXPECT_TRUE(::DeleteFile(expected_copy_path));

-  } else {

-    const bool expected_file_exists = File::Exists(expected_copy_path);

-    EXPECT_EQ(E_ACCESSDENIED, VerifyFileAndExecute(repair_file, _T("")));

-

-    // We can't force the file to be deleted, so make sure it wasn't created

-    // or deleted by the above method.

-    EXPECT_EQ(expected_file_exists, File::Exists(expected_copy_path));

-  }

-}

-

-TEST(ExecuteRepairFileTest, VerifyFileAndExecute_ValidRepairFileWithArgs) {

-  RunAndVerifySavedArgs(_T("These /are the args."));

-}

-

-TEST(ExecuteRepairFileTest, VerifyFileAndExecute_ValidRepairFileWithoutArgs) {

-  RunAndVerifySavedArgs(_T(""));

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Unit tests for the file execution module of the MSP custom action.
+
+#include "omaha/common/app_util.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/recovery/repair_exe/custom_action/execute_repair_file.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+// The valid repair file saves the arguments passed to it to a file.
+void RunAndVerifySavedArgs(const CString& args) {
+  CString expected_copy_path =
+      _T("%PROGRAMFILES%\\Google\\Update\\SaveArguments.exe");
+  EXPECT_SUCCEEDED(ExpandStringWithSpecialFolders(&expected_copy_path));
+  CString saved_arguments_file_path =
+      _T("%PROGRAMFILES%\\Google\\Update\\saved_arguments.txt");
+  EXPECT_SUCCEEDED(ExpandStringWithSpecialFolders(&saved_arguments_file_path));
+
+  CString repair_file(app_util::GetCurrentModuleDirectory());
+  EXPECT_TRUE(::PathAppend(CStrBuf(repair_file, MAX_PATH),
+              _T("unittest_support\\SaveArguments.exe")));
+
+  ::DeleteFile(saved_arguments_file_path);
+
+  if (vista_util::IsUserAdmin()) {
+    EXPECT_FALSE(File::Exists(saved_arguments_file_path));
+
+    EXPECT_SUCCEEDED(omaha::VerifyFileAndExecute(repair_file, args));
+
+    bool is_found = false;
+    for (int tries = 0; tries < 100 && !is_found; ++tries) {
+      ::Sleep(50);
+      is_found = File::Exists(saved_arguments_file_path);
+    }
+    ASSERT_TRUE(is_found);
+
+    scoped_hfile file;
+    for (int tries = 0; tries < 100 && !valid(file); ++tries) {
+      ::Sleep(50);
+      reset(file, ::CreateFile(saved_arguments_file_path,
+                               GENERIC_READ,
+                               0,                        // do not share
+                               NULL,                     // default security
+                               OPEN_EXISTING,            // existing file only
+                               FILE_ATTRIBUTE_NORMAL,
+                               NULL));                   // no template
+    }
+    ASSERT_TRUE(valid(file));
+
+    const int kBufferLen = 50;
+    TCHAR buffer[kBufferLen + 1] = {0};
+    DWORD bytes_read = 0;
+
+    // Do not assume the buffer read by ReadFile remains zero-terminated.
+    EXPECT_TRUE(::ReadFile(get(file),
+                           buffer,
+                           kBufferLen * sizeof(TCHAR),
+                           &bytes_read,
+                           NULL));
+    EXPECT_EQ(0, bytes_read % sizeof(TCHAR));
+    buffer[bytes_read / sizeof(TCHAR)] = _T('\0');
+    EXPECT_STREQ(args, buffer);
+
+    reset(file);
+
+    ::DeleteFile(expected_copy_path);
+    EXPECT_TRUE(::DeleteFile(saved_arguments_file_path));
+  } else {
+    const bool expected_file_exists = File::Exists(saved_arguments_file_path);
+    EXPECT_EQ(E_ACCESSDENIED, omaha::VerifyFileAndExecute(repair_file, args));
+
+    // We can't force the file to be deleted, so make sure it wasn't created
+    // or deleted by the above method.
+    EXPECT_EQ(expected_file_exists, File::Exists(saved_arguments_file_path));
+  }
+}
+
+}  // namespace
+
+TEST(ExecuteRepairFileTest, VerifyFileAndExecute_EmptyFilename) {
+  EXPECT_EQ(E_INVALIDARG, VerifyFileAndExecute(_T(""), _T("")));
+}
+
+TEST(ExecuteRepairFileTest, VerifyFileAndExecute_FileDoesNotExist) {
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            VerifyFileAndExecute(_T("no_such_file.exe"), _T("")));
+}
+
+TEST(ExecuteRepairFileTest, VerifyFileAndExecute_FilenameIsDirectory) {
+  EXPECT_EQ(E_ACCESSDENIED,
+            VerifyFileAndExecute(_T("C:\\Windows"), _T("")));
+}
+
+TEST(ExecuteRepairFileTest, VerifyFileAndExecute_UnsignedFile) {
+  CString expected_copy_path =
+      _T("%PROGRAMFILES%\\Google\\Update\\GoogleUpdate_unsigned.exe");
+  EXPECT_SUCCEEDED(ExpandStringWithSpecialFolders(&expected_copy_path));
+  CString repair_file(app_util::GetCurrentModuleDirectory());
+  EXPECT_TRUE(::PathAppend(CStrBuf(repair_file, MAX_PATH),
+              _T("GoogleUpdate_unsigned.exe")));
+
+  if (vista_util::IsUserAdmin()) {
+    EXPECT_EQ(TRUST_E_NOSIGNATURE, VerifyFileAndExecute(repair_file, _T("")));
+
+    EXPECT_TRUE(File::Exists(expected_copy_path));
+    EXPECT_TRUE(::DeleteFile(expected_copy_path));
+  } else {
+    const bool expected_file_exists = File::Exists(expected_copy_path);
+    EXPECT_EQ(E_ACCESSDENIED, VerifyFileAndExecute(repair_file, _T("")));
+
+    // We can't force the file to be deleted, so make sure it wasn't created
+    // or deleted by the above method.
+    EXPECT_EQ(expected_file_exists, File::Exists(expected_copy_path));
+  }
+}
+
+TEST(ExecuteRepairFileTest, VerifyFileAndExecute_ValidRepairFileWithArgs) {
+  RunAndVerifySavedArgs(_T("These /are the args."));
+}
+
+TEST(ExecuteRepairFileTest, VerifyFileAndExecute_ValidRepairFileWithoutArgs) {
+  RunAndVerifySavedArgs(_T(""));
+}
+
+}  // namespace omaha
diff --git a/recovery/repair_exe/custom_action/executecustomaction.cc b/recovery/repair_exe/custom_action/executecustomaction.cc
index 7b78d52..4261b4f 100644
--- a/recovery/repair_exe/custom_action/executecustomaction.cc
+++ b/recovery/repair_exe/custom_action/executecustomaction.cc
@@ -1,70 +1,70 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Custom action helper DLL:

-// The custom actions created in this project are for Google Update MSI patch,

-// which is installed temporarily and uses this DLL to verify a downloaded

-// executable and run it with elevated privileges.

-

-

-#include "omaha/recovery/repair_exe/custom_action/executecustomaction.h"

-#include <Msiquery.h>

-#include "omaha/common/debug.h"

-#include "omaha/recovery/repair_exe/mspexecutableelevator.h"

-#include "omaha/recovery/repair_exe/custom_action/execute_repair_file.h"

-

-namespace {

-

-omaha::CustomActionModule _AtlModule;

-

-}  // namespace

-

-// DLL Entry Point

-extern "C" BOOL WINAPI DllMain(HINSTANCE,

-                               DWORD dwReason,

-                               LPVOID lpReserved) {

-  return _AtlModule.DllMain(dwReason, lpReserved);

-}

-

-// Verify an executable and run it

-UINT __stdcall VerifyFileAndExecute(MSIHANDLE install_handle) {

-  TCHAR custom_action_data[2048] = {0};

-  DWORD size = ARRAYSIZE(custom_action_data) - 1;

-  *custom_action_data = _T('\0');

-  if (ERROR_SUCCESS == ::MsiGetProperty(install_handle,

-                                        _T("CustomActionData"),

-                                        custom_action_data,

-                                        &size) &&

-      _T('\0') != *custom_action_data) {

-    custom_action_data[ARRAYSIZE(custom_action_data) - 1] = _T('\0');

-

-    TCHAR* executable = NULL;

-    TCHAR* arguments = NULL;

-    DWORD calling_process_id = 0;

-    if (omaha::msp_executable_elevator::ParseMSPCommandLine(

-            custom_action_data,

-            &executable,

-            &arguments,

-            &calling_process_id) &&

-        executable && arguments) {

-      HRESULT hr = omaha::VerifyFileAndExecute(executable, arguments);

-      VERIFY1(omaha::msp_executable_elevator::SetResultOfExecute(NULL, hr));

-    }

-  }

-  return 0;

-}

-

-// 4505: unreferenced local function has been removed

-#pragma warning(disable : 4505)

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Custom action helper DLL:
+// The custom actions created in this project are for Google Update MSI patch,
+// which is installed temporarily and uses this DLL to verify a downloaded
+// executable and run it with elevated privileges.
+
+
+#include "omaha/recovery/repair_exe/custom_action/executecustomaction.h"
+#include <Msiquery.h>
+#include "omaha/common/debug.h"
+#include "omaha/recovery/repair_exe/mspexecutableelevator.h"
+#include "omaha/recovery/repair_exe/custom_action/execute_repair_file.h"
+
+namespace {
+
+omaha::CustomActionModule _AtlModule;
+
+}  // namespace
+
+// DLL Entry Point
+extern "C" BOOL WINAPI DllMain(HINSTANCE,
+                               DWORD dwReason,
+                               LPVOID lpReserved) {
+  return _AtlModule.DllMain(dwReason, lpReserved);
+}
+
+// Verify an executable and run it
+UINT __stdcall VerifyFileAndExecute(MSIHANDLE install_handle) {
+  TCHAR custom_action_data[2048] = {0};
+  DWORD size = ARRAYSIZE(custom_action_data) - 1;
+  *custom_action_data = _T('\0');
+  if (ERROR_SUCCESS == ::MsiGetProperty(install_handle,
+                                        _T("CustomActionData"),
+                                        custom_action_data,
+                                        &size) &&
+      _T('\0') != *custom_action_data) {
+    custom_action_data[ARRAYSIZE(custom_action_data) - 1] = _T('\0');
+
+    TCHAR* executable = NULL;
+    TCHAR* arguments = NULL;
+    DWORD calling_process_id = 0;
+    if (omaha::msp_executable_elevator::ParseMSPCommandLine(
+            custom_action_data,
+            &executable,
+            &arguments,
+            &calling_process_id) &&
+        executable && arguments) {
+      HRESULT hr = omaha::VerifyFileAndExecute(executable, arguments);
+      VERIFY1(omaha::msp_executable_elevator::SetResultOfExecute(NULL, hr));
+    }
+  }
+  return 0;
+}
+
+// 4505: unreferenced local function has been removed
+#pragma warning(disable : 4505)
diff --git a/recovery/repair_exe/custom_action/executecustomaction.def b/recovery/repair_exe/custom_action/executecustomaction.def
index 352b92c..827e1fd 100644
--- a/recovery/repair_exe/custom_action/executecustomaction.def
+++ b/recovery/repair_exe/custom_action/executecustomaction.def
@@ -1,19 +1,19 @@
-; Copyright 2007-2009 Google Inc.

-;

-; Licensed under the Apache License, Version 2.0 (the "License");

-; you may not use this file except in compliance with the License.

-; You may obtain a copy of the License at

-;

-;      http://www.apache.org/licenses/LICENSE-2.0

-;

-; Unless required by applicable law or agreed to in writing, software

-; distributed under the License is distributed on an "AS IS" BASIS,

-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-; See the License for the specific language governing permissions and

-; limitations under the License.

-; ========================================================================

-

-LIBRARY      "executecustomaction.dll"

-

-EXPORTS

-  VerifyFileAndExecute

+; Copyright 2007-2009 Google Inc.
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+; ========================================================================
+
+LIBRARY      "executecustomaction.dll"
+
+EXPORTS
+  VerifyFileAndExecute
diff --git a/recovery/repair_exe/custom_action/executecustomaction.h b/recovery/repair_exe/custom_action/executecustomaction.h
index e074369..033f6f7 100644
--- a/recovery/repair_exe/custom_action/executecustomaction.h
+++ b/recovery/repair_exe/custom_action/executecustomaction.h
@@ -1,38 +1,38 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Header files to precompile for the installer.

-

-#ifndef  OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTECUSTOMACTION_H__

-#define  OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTECUSTOMACTION_H__

-

-#include <windows.h>

-#include <msi.h>

-#include <atlbase.h>

-

-namespace omaha {

-

-class CustomActionModule : public CAtlDllModuleT<CustomActionModule> {

- public:

-  CustomActionModule() {}

-  ~CustomActionModule() {}

-};

-

-}  // namespace omaha

-

-extern "C"

-UINT __stdcall VerifyFileAndExecute(MSIHANDLE);

-

-#endif  // OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTECUSTOMACTION_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Header files to precompile for the installer.
+
+#ifndef  OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTECUSTOMACTION_H__
+#define  OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTECUSTOMACTION_H__
+
+#include <windows.h>
+#include <msi.h>
+#include <atlbase.h>
+
+namespace omaha {
+
+class CustomActionModule : public CAtlDllModuleT<CustomActionModule> {
+ public:
+  CustomActionModule() {}
+  ~CustomActionModule() {}
+};
+
+}  // namespace omaha
+
+extern "C"
+UINT __stdcall VerifyFileAndExecute(MSIHANDLE);
+
+#endif  // OMAHA_RECOVERY_REPAIR_EXE_CUSTOM_ACTION_EXECUTECUSTOMACTION_H__
diff --git a/recovery/repair_exe/custom_action/testelevateusingmsp.cc b/recovery/repair_exe/custom_action/testelevateusingmsp.cc
index a58b2c8..d1be88e 100644
--- a/recovery/repair_exe/custom_action/testelevateusingmsp.cc
+++ b/recovery/repair_exe/custom_action/testelevateusingmsp.cc
@@ -1,59 +1,59 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Command line utility that elevates an executable using an MSI Patch.

-// The MSI patch is assumed to be in the same directory as this executable.

-

-#include <windows.h>

-#include <atlstr.h>

-#include "omaha/common/constants.h"

-#include "omaha/recovery/repair_exe/mspexecutableelevator.h"

-

-int main(int argc, char** argv) {

-  DWORD process_id = 0;

-  if (2 <= argc) {

-    CString arguments;

-    if (3 <= argc) {

-      arguments = argv[2];

-    }

-    HANDLE process = NULL;

-    HRESULT hr = omaha::msp_executable_elevator::ExecuteGoogleSignedExe(

-        CString(argv[1]),

-        arguments,

-        omaha::kHelperInstallerProductGuid,

-        omaha::kHelperPatchGuid,

-        omaha::kHelperPatchName,

-        &process);

-    if (process) {

-      process_id = ::GetProcessId(process);

-      ::CloseHandle(process);

-    }

-    wprintf(_T("%s (process handle:%x process id: %u hresult:%x)"),

-           (SUCCEEDED(hr) ? _T("Success") : _T("Failure")),

-           process,

-           process_id,

-           static_cast<int>(hr));

-  } else {

-    static TCHAR explain_test[] =

-      _T("testelevateusingmsp\n\n")

-      _T("To use this test, pass the full path to an executable containing ")

-      _T("the Google Update Repair resource and is signed with a Google ")

-      _T("code-signing certificate that has a certain subject and ")

-      _T("organization unit name.")

-      _T("\n\nAn optional parameter to that executable may be passed as well.");

-    wprintf(explain_test);

-  }

-  return process_id;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Command line utility that elevates an executable using an MSI Patch.
+// The MSI patch is assumed to be in the same directory as this executable.
+
+#include <windows.h>
+#include <atlstr.h>
+#include "omaha/common/constants.h"
+#include "omaha/recovery/repair_exe/mspexecutableelevator.h"
+
+int main(int argc, char** argv) {
+  DWORD process_id = 0;
+  if (2 <= argc) {
+    CString arguments;
+    if (3 <= argc) {
+      arguments = argv[2];
+    }
+    HANDLE process = NULL;
+    HRESULT hr = omaha::msp_executable_elevator::ExecuteGoogleSignedExe(
+        CString(argv[1]),
+        arguments,
+        omaha::kHelperInstallerProductGuid,
+        omaha::kHelperPatchGuid,
+        omaha::kHelperPatchName,
+        &process);
+    if (process) {
+      process_id = ::GetProcessId(process);
+      ::CloseHandle(process);
+    }
+    wprintf(_T("%s (process handle:%x process id: %u hresult:%x)"),
+           (SUCCEEDED(hr) ? _T("Success") : _T("Failure")),
+           process,
+           process_id,
+           static_cast<int>(hr));
+  } else {
+    static TCHAR explain_test[] =
+      _T("testelevateusingmsp\n\n")
+      _T("To use this test, pass the full path to an executable containing ")
+      _T("the Google Update Repair resource and is signed with a Google ")
+      _T("code-signing certificate that has a certain subject and ")
+      _T("organization unit name.")
+      _T("\n\nAn optional parameter to that executable may be passed as well.");
+    wprintf(explain_test);
+  }
+  return process_id;
+}
diff --git a/recovery/repair_exe/msp/build.scons b/recovery/repair_exe/msp/build.scons
index a1b77bf..dbcb25a 100644
--- a/recovery/repair_exe/msp/build.scons
+++ b/recovery/repair_exe/msp/build.scons
@@ -1,156 +1,156 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-#

-# Hammer file to create the stub .msi and .msp files

-#

-

-import os

-import stat

-

-Import('env')

-

-

-_custom_actions_path = (

-    '$OBJ_ROOT/recovery/repair_exe/custom_action/executecustomaction.dll')

-_cert_file = env.File(GetOption('authenticode_file')).abspath[:-3] + 'cer'

-_required_file = '$MAIN_DIR/recovery/repair_exe/msp/requiredfile.txt'

-

-google_update_version = env['product_version'][0]

-google_update_version_string = '%d.%d.%d.%d' % (google_update_version[0],

-                                                google_update_version[1],

-                                                google_update_version[2],

-                                                google_update_version[3])

-

-old_unsigned_env = env.Clone()

-old_unsigned_env.Append(

-    WIXCANDLEFLAGS = [

-        '-dFinalMsi=0',

-        '-dCertificateFile=' + _cert_file,

-        '-dRequiredFile=' + env.File(_required_file).abspath,

-        '-dGoogleUpdateVersion=' + google_update_version_string,

-        ],

-    WIXLIGHTFLAGS = [

-        '-dRequiredFile=' + env.File(_required_file).abspath,

-        ],

-)

-

-old_unsigned_output = old_unsigned_env.WiX('GoogleUpdateHelper_unsigned.msi',

-    'patchableinstaller.wxs')

-

-env.Depends(old_unsigned_output, [_custom_actions_path, _required_file])

-

-

-new_unsigned_env = env.Clone()

-new_unsigned_env.Append(

-    WIXCANDLEFLAGS = [

-        '-dFinalMsi=1',

-        '-dExecuteCustomActionDLL=' + env.File(_custom_actions_path).abspath,

-        '-dCertificateFile=' + _cert_file,

-        '-dRequiredFile=' + env.File(_required_file).abspath,

-        '-dGoogleUpdateVersion=' + google_update_version_string,

-        ],

-    WIXLIGHTFLAGS = [

-        '-dRequiredFile=' + env.File(_required_file).abspath,

-        ],

-)

-

-# Output to a subdirectory to avoid having

-# 2 intermediate wixobj files with the same name and path.

-new_unsigned_env['WIXOBJPREFIX'] = new_unsigned_env['WIXOBJPREFIX'] + 'new/'

-new_unsigned_env['WIXMSIPREFIX'] = new_unsigned_env['WIXMSIPREFIX'] + 'new/'

-

-new_unsigned_output = new_unsigned_env.WiX(

-    target='GoogleUpdateHelper_unsigned.msi',

-    source='patchableinstaller.wxs'

-)

-

-env.Depends(new_unsigned_output, [_custom_actions_path, _required_file])

-

-

-#

-# Create the MSP file

-#

-msp_env = env.Clone()

-

-patch_output = msp_env.Command(

-    target='patch.wixobj',

-    source='patch.wxs',

-    action=('@candle.exe -nologo -out $TARGET $SOURCE -dAfterImage=%s'

-            ' -dBeforeImage=%s' % (env.File(new_unsigned_output[0]).abspath,

-                                   env.File(old_unsigned_output[0]).abspath))

-)

-

-# Required because the before and after images are not in the source.

-Depends(patch_output, [new_unsigned_output, old_unsigned_output])

-

-pcp_output = msp_env.Command(

-    target='patch.pcp',

-    source=patch_output,

-    action='@light.exe -nologo -out $TARGET $SOURCE'

-)

-

-# The PCP, and thus the MSP, fail to rebuild when the MSI files change without

-# this explicit dependency, probably because the .wixobj hash does not change.

-Depends(pcp_output, [patch_output, old_unsigned_output, new_unsigned_output])

-

-# Delete temp dir that vista sdk version of msimsp.exe cannot remove for itself.

-_temp_dir = os.path.join(env['ENV']['TMP'], '~pcw_tmp.tmp')

-if os.path.exists(_temp_dir):

-  # Recursively delete subdirectories

-  def rm_rf(dir):

-    for file in os.listdir(dir):

-      path = os.path.join(dir, file)

-      if os.path.isdir(path):

-        rm_rf(path)

-      else:

-        os.chmod(path, stat.S_IWRITE)  # Make sure file is writeable.

-        os.remove(path)

-    os.rmdir(dir)

-

-  # Remove the temp dir.

-  rm_rf(_temp_dir)

-

-unsigned_msp_name = 'GoogleUpdateHelperPatch_unsigned.msp'

-unsigned_msp_path = '$OBJ_ROOT/recovery/repair_exe/msp/' + unsigned_msp_name

-

-msp_output = msp_env.Command(

-    target=unsigned_msp_name,

-    source=pcp_output,

-    action='@msimsp.exe -s $SOURCE -p $TARGET -l %s' % (

-        env.File(unsigned_msp_path + '.log').abspath),

-)

-

-# For unknown reasons, the PCP fails to rebuild and cause the MSP to rebuild

-# when the MSI files change without this explicit dependency.

-Depends(msp_output, pcp_output)

-

-

-#

-# Sign the old MSI and MSP

-#

-signed_msi = env.SignedBinary(

-    target='GoogleUpdateHelper.msi',

-    source=old_unsigned_output,

-)

-

-signed_msp = env.SignedBinary(

-    target='GoogleUpdateHelperPatch.msp',

-    source=msp_output,

-)

-

-env.Replicate('$STAGING_DIR', [signed_msi, signed_msp])

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+#
+# Hammer file to create the stub .msi and .msp files
+#
+
+import os
+import stat
+
+Import('env')
+
+
+_custom_actions_path = (
+    '$OBJ_ROOT/recovery/repair_exe/custom_action/executecustomaction.dll')
+_cert_file = env.File(GetOption('authenticode_file')).abspath[:-3] + 'cer'
+_required_file = '$MAIN_DIR/recovery/repair_exe/msp/requiredfile.txt'
+
+google_update_version = env['product_version'][0]
+google_update_version_string = '%d.%d.%d.%d' % (google_update_version[0],
+                                                google_update_version[1],
+                                                google_update_version[2],
+                                                google_update_version[3])
+
+old_unsigned_env = env.Clone()
+old_unsigned_env.Append(
+    WIXCANDLEFLAGS = [
+        '-dFinalMsi=0',
+        '-dCertificateFile=' + _cert_file,
+        '-dRequiredFile=' + env.File(_required_file).abspath,
+        '-dGoogleUpdateVersion=' + google_update_version_string,
+        ],
+    WIXLIGHTFLAGS = [
+        '-dRequiredFile=' + env.File(_required_file).abspath,
+        ],
+)
+
+old_unsigned_output = old_unsigned_env.WiX('GoogleUpdateHelper_unsigned.msi',
+    'patchableinstaller.wxs')
+
+env.Depends(old_unsigned_output, [_custom_actions_path, _required_file])
+
+
+new_unsigned_env = env.Clone()
+new_unsigned_env.Append(
+    WIXCANDLEFLAGS = [
+        '-dFinalMsi=1',
+        '-dExecuteCustomActionDLL=' + env.File(_custom_actions_path).abspath,
+        '-dCertificateFile=' + _cert_file,
+        '-dRequiredFile=' + env.File(_required_file).abspath,
+        '-dGoogleUpdateVersion=' + google_update_version_string,
+        ],
+    WIXLIGHTFLAGS = [
+        '-dRequiredFile=' + env.File(_required_file).abspath,
+        ],
+)
+
+# Output to a subdirectory to avoid having
+# 2 intermediate wixobj files with the same name and path.
+new_unsigned_env['WIXOBJPREFIX'] = new_unsigned_env['WIXOBJPREFIX'] + 'new/'
+new_unsigned_env['WIXMSIPREFIX'] = new_unsigned_env['WIXMSIPREFIX'] + 'new/'
+
+new_unsigned_output = new_unsigned_env.WiX(
+    target='GoogleUpdateHelper_unsigned.msi',
+    source='patchableinstaller.wxs'
+)
+
+env.Depends(new_unsigned_output, [_custom_actions_path, _required_file])
+
+
+#
+# Create the MSP file
+#
+msp_env = env.Clone()
+
+patch_output = msp_env.Command(
+    target='patch.wixobj',
+    source='patch.wxs',
+    action=('@candle.exe -nologo -out $TARGET $SOURCE -dAfterImage=%s'
+            ' -dBeforeImage=%s' % (env.File(new_unsigned_output[0]).abspath,
+                                   env.File(old_unsigned_output[0]).abspath))
+)
+
+# Required because the before and after images are not in the source.
+Depends(patch_output, [new_unsigned_output, old_unsigned_output])
+
+pcp_output = msp_env.Command(
+    target='patch.pcp',
+    source=patch_output,
+    action='@light.exe -nologo -out $TARGET $SOURCE'
+)
+
+# The PCP, and thus the MSP, fail to rebuild when the MSI files change without
+# this explicit dependency, probably because the .wixobj hash does not change.
+Depends(pcp_output, [patch_output, old_unsigned_output, new_unsigned_output])
+
+# Delete temp dir that vista sdk version of msimsp.exe cannot remove for itself.
+_temp_dir = os.path.join(env['ENV']['TMP'], '~pcw_tmp.tmp')
+if os.path.exists(_temp_dir):
+  # Recursively delete subdirectories
+  def rm_rf(dir):
+    for file in os.listdir(dir):
+      path = os.path.join(dir, file)
+      if os.path.isdir(path):
+        rm_rf(path)
+      else:
+        os.chmod(path, stat.S_IWRITE)  # Make sure file is writeable.
+        os.remove(path)
+    os.rmdir(dir)
+
+  # Remove the temp dir.
+  rm_rf(_temp_dir)
+
+unsigned_msp_name = 'GoogleUpdateHelperPatch_unsigned.msp'
+unsigned_msp_path = '$OBJ_ROOT/recovery/repair_exe/msp/' + unsigned_msp_name
+
+msp_output = msp_env.Command(
+    target=unsigned_msp_name,
+    source=pcp_output,
+    action='@msimsp.exe -s $SOURCE -p $TARGET -l %s' % (
+        env.File(unsigned_msp_path + '.log').abspath),
+)
+
+# For unknown reasons, the PCP fails to rebuild and cause the MSP to rebuild
+# when the MSI files change without this explicit dependency.
+Depends(msp_output, pcp_output)
+
+
+#
+# Sign the old MSI and MSP
+#
+signed_msi = env.SignedBinary(
+    target='GoogleUpdateHelper.msi',
+    source=old_unsigned_output,
+)
+
+signed_msp = env.SignedBinary(
+    target='GoogleUpdateHelperPatch.msp',
+    source=msp_output,
+)
+
+env.Replicate('$STAGING_DIR', [signed_msi, signed_msp])
diff --git a/recovery/repair_exe/msp/patch.wxs b/recovery/repair_exe/msp/patch.wxs
index 6210458..b859f05 100644
--- a/recovery/repair_exe/msp/patch.wxs
+++ b/recovery/repair_exe/msp/patch.wxs
@@ -1,38 +1,38 @@
-<?xml version="1.0" encoding="Windows-1252"?>

-<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">

-  <PatchCreation Id="E0D0D2C9-5836-4023-AB1D-54EC3B90AD03"

-    AllowMajorVersionMismatches="no"

-    AllowProductCodeMismatches="no"

-    CleanWorkingFolder="yes"

-    WholeFilesOnly="yes">

-

-    <PatchInformation

-      Description="Patches Google Update"

-      Comments="Copyright 2007-2009 Google Inc."

-      Keywords="Installer"

-      Manufacturer="Google Inc."

-      ShortNames="no"

-      Languages="1033"

-      Compressed="no"

-      SummaryCodepage="1252" />

-

-    <PatchMetadata

-      Description="Patches Google Update"

-      DisplayName="Google Update patch"

-      TargetProductName="Google Update"

-      ManufacturerName="Google Inc."

-      MoreInfoURL="http://www.google.com/support/installer/?patch"

-      Classification="Service Pack"

-      AllowRemoval="yes" />

-

-    <Family DiskId="2" MediaSrcProp="GoogleUpdatePatchSrcPropName"

-            Name="GoogleUp" SequenceStart="1000">

-      <UpgradeImage Id="AfterImage" SourceFile="$(var.AfterImage)">

-        <TargetImage Id="BeforeImage" SourceFile="$(var.BeforeImage)"

-                     Order="2" IgnoreMissingFiles="no" />

-      </UpgradeImage>

-    </Family>

-

-    <TargetProductCode Id="A92DAB39-4E2C-4304-9AB6-BC44E68B55E2" />

-  </PatchCreation>

-</Wix>

+<?xml version="1.0" encoding="Windows-1252"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+  <PatchCreation Id="E0D0D2C9-5836-4023-AB1D-54EC3B90AD03"
+    AllowMajorVersionMismatches="no"
+    AllowProductCodeMismatches="no"
+    CleanWorkingFolder="yes"
+    WholeFilesOnly="yes">
+
+    <PatchInformation
+      Description="Patches Google Update"
+      Comments="Copyright 2007-2009 Google Inc."
+      Keywords="Installer"
+      Manufacturer="Google Inc."
+      ShortNames="no"
+      Languages="1033"
+      Compressed="no"
+      SummaryCodepage="1252" />
+
+    <PatchMetadata
+      Description="Patches Google Update"
+      DisplayName="Google Update patch"
+      TargetProductName="Google Update"
+      ManufacturerName="Google Inc."
+      MoreInfoURL="http://www.google.com/support/installer/?patch"
+      Classification="Service Pack"
+      AllowRemoval="yes" />
+
+    <Family DiskId="2" MediaSrcProp="GoogleUpdatePatchSrcPropName"
+            Name="GoogleUp" SequenceStart="1000">
+      <UpgradeImage Id="AfterImage" SourceFile="$(var.AfterImage)">
+        <TargetImage Id="BeforeImage" SourceFile="$(var.BeforeImage)"
+                     Order="2" IgnoreMissingFiles="no" />
+      </UpgradeImage>
+    </Family>
+
+    <TargetProductCode Id="A92DAB39-4E2C-4304-9AB6-BC44E68B55E2" />
+  </PatchCreation>
+</Wix>
diff --git a/recovery/repair_exe/msp/patchableinstaller.wxs b/recovery/repair_exe/msp/patchableinstaller.wxs
index da05ba9..cf99f8b 100644
--- a/recovery/repair_exe/msp/patchableinstaller.wxs
+++ b/recovery/repair_exe/msp/patchableinstaller.wxs
@@ -1,83 +1,83 @@
-<?xml version="1.0" encoding="Windows-1252"?>

-<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">

-  <Product Id="A92DAB39-4E2C-4304-9AB6-BC44E68B55E2"

-    Name="Google Update Helper"

-    Language="1033"

-    Codepage="1252"

-    UpgradeCode="9515FFBD-40AB-4690-B983-4FA8E14EE7F5"

-    Version="$(var.GoogleUpdateVersion)"

-    Manufacturer="Google Inc.">

-

-    <Package Id="*"

-      Description="Google Update Helper"

-      Comments="Copyright 2007-2009 Google Inc."

-      Manufacturer="Google Inc."

-      Languages="1033"

-      SummaryCodepage="1252"

-      InstallerVersion="300"

-      InstallPrivileges="elevated"

-      Compressed="no" />

-

-    <!-- Cannot patch an msi without a file -->

-    <Media Id="1" Cabinet="required.cab" EmbedCab="yes"/>

-

-    <Directory Id="TARGETDIR" Name="SourceDir">

-      <Directory Id="ProgramFilesFolder">

-        <Directory Id="GoogleProgramDir" Name="Google">

-          <Directory Id="UpdateDir" Name="Update">

-

-            <Component Id="MainComponent" Guid="717B7059-A988-492f-AF1B-DCF70BE809AB">

-              <!-- Cannot have an msi patch without a file -->

-<?if $(var.FinalMsi) = 1 ?>

-              <File Id="RequiredFile" Name="RequiredFile.txt" DiskId="1" Source="$(var.RequiredFile)" Vital="yes"/>

-<?endif?>

-              <!-- Cannot have an empty component -->

-              <RegistryValue Id="NonEmptyComponent" Action="write" Root="HKLM" Key="SOFTWARE\Google\Update" Name="MsiStubRun" Type="integer" Value="0" />

-            </Component>

-

-          </Directory>

-        </Directory>

-      </Directory>

-    </Directory>

-

-    <PatchCertificates>

-      <DigitalCertificate Id="CertificateForPatching" SourceFile="$(var.CertificateFile)" />

-    </PatchCertificates>

-

-    <Feature Id="Complete" Level="1">

-      <ComponentRef Id="MainComponent" />

-    </Feature>

-

-<?if $(var.FinalMsi) = 1 ?>

-    <Binary Id="ExecuteLibrary" SourceFile="$(var.ExecuteCustomActionDLL)" />

-

-    <!-- Need to mark these custom properties as secure so that in Vista they are passed to the high-integrity msi server -->

-    <Property Id="EXECUTABLECOMMANDLINE" Secure="yes"/>

-

-    <CustomAction Id="LaunchFile.PropertyAssign" Property="LaunchFile" Value="[EXECUTABLECOMMANDLINE]" />

-

-    <CustomAction Id="LaunchFile" Return="ignore" Execute="deferred" Impersonate="no"

-      BinaryKey="ExecuteLibrary" DllEntry="VerifyFileAndExecute"/>

-

-    <InstallExecuteSequence>

-      <Custom Action="LaunchFile.PropertyAssign" Before="LaunchFile">NOT EXECUTABLECOMMANDLINE=""</Custom>

-      <Custom Action="LaunchFile" Before="InstallFinalize">NOT EXECUTABLECOMMANDLINE=""</Custom>

-    </InstallExecuteSequence>

-<?endif?>

-

-    <!-- Make sure the product shows up for all users -->

-    <Property Id="ALLUSERS" Value="1" />

-

-    <!-- Hide ARP entry -->

-    <Property Id="ARPSYSTEMCOMPONENT" Value="1" />

-

-    <!-- Disable rollback to make the msi and patch a little faster.

-         If an install, patch, or unpatch fails, it is ok to leave behind a partial install/patch/unpatch.

-         A failed install prevents patching anyway.

-         A failed patch should not stop us from patching again (at least for a few more times).

-         Rolling back a failed unpatch does not enable us to patch again.

-         And in all cases, the uninstaller should clean up whatever may be left behind. -->

-    <Property Id="DISABLEROLLBACK" Value="1" />

-

-  </Product>

-</Wix>

+<?xml version="1.0" encoding="Windows-1252"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+  <Product Id="A92DAB39-4E2C-4304-9AB6-BC44E68B55E2"
+    Name="Google Update Helper"
+    Language="1033"
+    Codepage="1252"
+    UpgradeCode="9515FFBD-40AB-4690-B983-4FA8E14EE7F5"
+    Version="$(var.GoogleUpdateVersion)"
+    Manufacturer="Google Inc.">
+
+    <Package Id="*"
+      Description="Google Update Helper"
+      Comments="Copyright 2007-2009 Google Inc."
+      Manufacturer="Google Inc."
+      Languages="1033"
+      SummaryCodepage="1252"
+      InstallerVersion="300"
+      InstallPrivileges="elevated"
+      Compressed="no" />
+
+    <!-- Cannot patch an msi without a file -->
+    <Media Id="1" Cabinet="required.cab" EmbedCab="yes"/>
+
+    <Directory Id="TARGETDIR" Name="SourceDir">
+      <Directory Id="ProgramFilesFolder">
+        <Directory Id="GoogleProgramDir" Name="Google">
+          <Directory Id="UpdateDir" Name="Update">
+
+            <Component Id="MainComponent" Guid="717B7059-A988-492f-AF1B-DCF70BE809AB">
+              <!-- Cannot have an msi patch without a file -->
+<?if $(var.FinalMsi) = 1 ?>
+              <File Id="RequiredFile" Name="RequiredFile.txt" DiskId="1" Source="$(var.RequiredFile)" Vital="yes"/>
+<?endif?>
+              <!-- Cannot have an empty component -->
+              <RegistryValue Id="NonEmptyComponent" Action="write" Root="HKLM" Key="SOFTWARE\Google\Update" Name="MsiStubRun" Type="integer" Value="0" />
+            </Component>
+
+          </Directory>
+        </Directory>
+      </Directory>
+    </Directory>
+
+    <PatchCertificates>
+      <DigitalCertificate Id="CertificateForPatching" SourceFile="$(var.CertificateFile)" />
+    </PatchCertificates>
+
+    <Feature Id="Complete" Level="1">
+      <ComponentRef Id="MainComponent" />
+    </Feature>
+
+<?if $(var.FinalMsi) = 1 ?>
+    <Binary Id="ExecuteLibrary" SourceFile="$(var.ExecuteCustomActionDLL)" />
+
+    <!-- Need to mark these custom properties as secure so that in Vista they are passed to the high-integrity msi server -->
+    <Property Id="EXECUTABLECOMMANDLINE" Secure="yes"/>
+
+    <CustomAction Id="LaunchFile.PropertyAssign" Property="LaunchFile" Value="[EXECUTABLECOMMANDLINE]" />
+
+    <CustomAction Id="LaunchFile" Return="ignore" Execute="deferred" Impersonate="no"
+      BinaryKey="ExecuteLibrary" DllEntry="VerifyFileAndExecute"/>
+
+    <InstallExecuteSequence>
+      <Custom Action="LaunchFile.PropertyAssign" Before="LaunchFile">NOT EXECUTABLECOMMANDLINE=""</Custom>
+      <Custom Action="LaunchFile" Before="InstallFinalize">NOT EXECUTABLECOMMANDLINE=""</Custom>
+    </InstallExecuteSequence>
+<?endif?>
+
+    <!-- Make sure the product shows up for all users -->
+    <Property Id="ALLUSERS" Value="1" />
+
+    <!-- Hide ARP entry -->
+    <Property Id="ARPSYSTEMCOMPONENT" Value="1" />
+
+    <!-- Disable rollback to make the msi and patch a little faster.
+         If an install, patch, or unpatch fails, it is ok to leave behind a partial install/patch/unpatch.
+         A failed install prevents patching anyway.
+         A failed patch should not stop us from patching again (at least for a few more times).
+         Rolling back a failed unpatch does not enable us to patch again.
+         And in all cases, the uninstaller should clean up whatever may be left behind. -->
+    <Property Id="DISABLEROLLBACK" Value="1" />
+
+  </Product>
+</Wix>
diff --git a/recovery/repair_exe/msp/setup_env.bat b/recovery/repair_exe/msp/setup_env.bat
index 7841dfe..3ddcc76 100644
--- a/recovery/repair_exe/msp/setup_env.bat
+++ b/recovery/repair_exe/msp/setup_env.bat
@@ -1,5 +1,5 @@
-:: This script must not rely on any external tools or PATH values.

-@echo OFF

-

-:: Creating the MSP requires the msimsp.exe from the 2003 R2 SDK

-set PATH=%PATH%;%~dp0..\..\..\..\third_party\platformsdk_win_server_2003_r2_partial\Samples\SysMgmt\Msi\Patching

+:: This script must not rely on any external tools or PATH values.
+@echo OFF
+
+:: Creating the MSP requires the msimsp.exe from the 2003 R2 SDK
+set PATH=%PATH%;%~dp0..\..\..\..\third_party\platformsdk_win_server_2003_r2_partial\Samples\SysMgmt\Msi\Patching
diff --git a/recovery/repair_exe/msp/testApplying300Patches.bat b/recovery/repair_exe/msp/testApplying300Patches.bat
index 33947e6..6936dd2 100644
--- a/recovery/repair_exe/msp/testApplying300Patches.bat
+++ b/recovery/repair_exe/msp/testApplying300Patches.bat
@@ -1,23 +1,23 @@
-@echo off

-

-rem normally, only 127 patches can be applied to an msi

-

-set /A ii=0

-

-rem msiexec /i GoogleUpdateHelper.msi /qn

-rem echo original product installed

-

-:repeat

-

-msiexec /update GoogleUpdateHelperPatch.msp REINSTALL=ALL /qn /L*v patchapply%ii%.log

-echo patch %ii% applied

-if %ii% GEQ 127	pause

-msiexec /uninstall {E0D0D2C9-5836-4023-AB1D-54EC3B90AD03} /package {A92DAB39-4E2C-4304-9AB6-BC44E68B55E2} /qn /L*v patchremove%ii%.log

-echo patch %ii% removed

-

-set /A ii=%ii%+1

-

-if %ii% NEQ 300	goto repeat

-rem if %ii% NEQ 127	goto repeat

-

-set ii=

+@echo off
+
+rem normally, only 127 patches can be applied to an msi
+
+set /A ii=0
+
+rem msiexec /i GoogleUpdateHelper.msi /qn
+rem echo original product installed
+
+:repeat
+
+msiexec /update GoogleUpdateHelperPatch.msp REINSTALL=ALL /qn /L*v patchapply%ii%.log
+echo patch %ii% applied
+if %ii% GEQ 127	pause
+msiexec /uninstall {E0D0D2C9-5836-4023-AB1D-54EC3B90AD03} /package {A92DAB39-4E2C-4304-9AB6-BC44E68B55E2} /qn /L*v patchremove%ii%.log
+echo patch %ii% removed
+
+set /A ii=%ii%+1
+
+if %ii% NEQ 300	goto repeat
+rem if %ii% NEQ 127	goto repeat
+
+set ii=
diff --git a/recovery/repair_exe/mspexecutableelevator.cc b/recovery/repair_exe/mspexecutableelevator.cc
index c87d458..c52a4b3 100644
--- a/recovery/repair_exe/mspexecutableelevator.cc
+++ b/recovery/repair_exe/mspexecutableelevator.cc
@@ -1,213 +1,213 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// This is the implementation of the API for verifying and executing

-// an executable under high integrity using an Msi Patch.

-//

-// This class assumes the following:

-//  1) its needed Msi has already been installed,

-//  2) its needed Msp is in the same directory as this module,

-//  3) the name of the Msp file,

-//  4) the name of the property passed as CustomActionData to the custom action,

-//  5) the guid of the patch, and

-//  6) the guid of the Msi install which will be patched.

-

-#define _WIN32_MSI 300

-

-#include "omaha/recovery/repair_exe/mspexecutableelevator.h"

-#include <atlpath.h>

-#include <msi.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/string.h"

-

-namespace omaha {

-

-namespace msp_executable_elevator {

-

-// Used to return information back to the process that called

-// ExecuteGoogleSignedExe.

-struct SharedMemoryInfo {

-  HANDLE process;

-  HRESULT launch_result;

-};

-

-// Used to store the name of the shared memory.  The name is retrieved from

-// the MSP command line when parsing the command line.  The code assumes that

-// only one thread per process will call ParseMSPCommandLine followed by

-// SetResultOfExecute (which is a safe assumption if this functionality is only

-// used for the purpose for which it was originally written).

-// Assumes that the MSP is in the same directory as the current process.

-static TCHAR parsed_shared_memory_name[200];

-

-HRESULT ExecuteGoogleSignedExe(const TCHAR* exe,

-                               const TCHAR* args,

-                               const TCHAR* kProductGuid,

-                               const TCHAR* kPatchGuid,

-                               const TCHAR* kPatchName,

-                               HANDLE* process) {

-  ASSERT1(exe);

-  ASSERT1(args);

-  ASSERT1(process);

-  ASSERT1(kProductGuid);

-  ASSERT1(kPatchGuid);

-  ASSERT1(kPatchName);

-

-  // Create shared memory in which to receive result of attempt to launch

-  // process and a handle to the launched process.

-  HRESULT hr = E_FAIL;

-  GUID random_guid = {0};

-  TCHAR shared_memory_name[200] = {0};

-  if (SUCCEEDED(::CoCreateGuid(&random_guid)) &&

-      0 < ::StringFromGUID2(random_guid,

-                            shared_memory_name,

-                            ARRAYSIZE(shared_memory_name))) {

-    HANDLE file_mapping = ::CreateFileMapping(INVALID_HANDLE_VALUE,

-                                              NULL,

-                                              PAGE_READWRITE,

-                                              0,

-                                              sizeof(file_mapping),

-                                              shared_memory_name);

-    if (file_mapping) {

-      SharedMemoryInfo* shared_info = reinterpret_cast<SharedMemoryInfo*>

-          (::MapViewOfFileEx(file_mapping,

-                             FILE_MAP_ALL_ACCESS,

-                             0,

-                             0,

-                             sizeof(*shared_info),

-                             0));

-      if (shared_info) {

-        shared_info->launch_result = E_FAIL;

-        shared_info->process = NULL;

-        // Create command line to pass to patch.  Parameters are the name of the

-        // shared memory just created, the current process id, the executable

-        // to launch, and the executable's arguments.

-        CString command_line;

-        command_line.Format(_T("EXECUTABLECOMMANDLINE=\"%s %u \"\"%s\"\" %s\" ")

-                            _T("REINSTALL=ALL"),

-                            shared_memory_name,

-                            GetCurrentProcessId(),

-                            exe,

-                            args);

-        // Generate path to patch using path to current module.

-        TCHAR module_name[MAX_PATH] = {0};

-        DWORD len = ::GetModuleFileName(_AtlBaseModule.GetModuleInstance(),

-                                        module_name,

-                                        ARRAYSIZE(module_name));

-        module_name[ARRAYSIZE(module_name) - 1] = '\0';

-        if (0 < len && len < ARRAYSIZE(module_name) &&

-            0 < command_line.GetLength()) {

-          CPath path = module_name;

-          if (path.RemoveFileSpec() && path.Append(kPatchName)) {

-            path.Canonicalize();

-            // Set install level to none so that user does not see

-            // an Msi window and so that a restore point is not created.

-            ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);

-            UINT res = ::MsiApplyPatch(path,

-                                       NULL,

-                                       INSTALLTYPE_DEFAULT,

-                                       command_line);

-            // MsiApplyPatch will not return until the passed executable has

-            // been launched (or not) and the shared memory has been updated.

-            *process = shared_info->process;

-            hr = HRESULT_FROM_WIN32(res);

-            if (SUCCEEDED(hr))

-              hr = shared_info->launch_result;

-          }

-        }

-        ::MsiRemovePatches(kPatchGuid,

-                           kProductGuid,

-                           INSTALLTYPE_SINGLE_INSTANCE,

-                           NULL);

-        VERIFY1(::UnmapViewOfFile(shared_info));

-      }

-      VERIFY1(::CloseHandle(file_mapping));

-    }

-  }

-  return hr;

-}

-

-bool ParseMSPCommandLine(TCHAR* command_line,

-                         TCHAR** executable_result,

-                         TCHAR** arguments_result,

-                         DWORD* calling_process_id) {

-  ASSERT1(command_line);

-  ASSERT1(executable_result);

-  ASSERT1(arguments_result);

-  ASSERT1(calling_process_id);

-  // Parse command line.  First extract name of shared memory into which

-  // the process handle of launched executable will be written.  Then extract

-  // the process id of calling process.  This process id will be used to create

-  // for the calling process a handle to the launched executable. Finally,

-  // extract the path to executable so that we can verify the executable.

-  TCHAR* shared_memory_name = NULL;

-  TCHAR* process_id_param = NULL;

-  TCHAR* arguments = NULL;

-  if (SplitCommandLineInPlace(command_line, &shared_memory_name, &arguments) &&

-      shared_memory_name && arguments &&

-      SplitCommandLineInPlace(arguments, &process_id_param, &arguments) &&

-      process_id_param && arguments &&

-      SplitCommandLineInPlace(arguments, executable_result, &arguments) &&

-      *executable_result && arguments) {

-    *calling_process_id = static_cast<DWORD>(_wtoi(process_id_param));

-    *arguments_result = arguments;

-    _tcsncpy(parsed_shared_memory_name,

-             shared_memory_name,

-             ARRAYSIZE(parsed_shared_memory_name));

-    parsed_shared_memory_name[ARRAYSIZE(parsed_shared_memory_name) - 1] =

-        _T('\0');

-    return true;

-  }

-  return false;

-}

-

-// Copy process handle and result to shared memory.

-// Process can be NULL.

-bool SetResultOfExecute(HANDLE process, HRESULT result) {

-  bool success = false;

-  if (_T('\0') != *parsed_shared_memory_name) {

-    HANDLE file_mapping = ::OpenFileMapping(FILE_MAP_WRITE,

-                                            FALSE,

-                                            parsed_shared_memory_name);

-    if (file_mapping) {

-      SharedMemoryInfo* shared_info = reinterpret_cast<SharedMemoryInfo*>

-          (::MapViewOfFileEx(file_mapping,

-                             FILE_MAP_WRITE,

-                             0,

-                             0,

-                             sizeof(SharedMemoryInfo),

-                             0));

-      if (shared_info) {

-        shared_info->process = process;

-        shared_info->launch_result = result;

-        VERIFY1(::UnmapViewOfFile(shared_info));

-        success = true;

-      } else {

-        ASSERT(false, (_T("::MapViewOfFileEx failed.")));

-      }

-

-      VERIFY1(::CloseHandle(file_mapping));

-    } else {

-      ASSERT(false, (_T("::OpenFileMapping failed.")));

-    }

-  } else {

-    ASSERT(false, (_T("parsed_shared_memory_name is empty.")));

-  }

-  return success;

-}

-

-}  // namespace msp_executable_elevator

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// This is the implementation of the API for verifying and executing
+// an executable under high integrity using an Msi Patch.
+//
+// This class assumes the following:
+//  1) its needed Msi has already been installed,
+//  2) its needed Msp is in the same directory as this module,
+//  3) the name of the Msp file,
+//  4) the name of the property passed as CustomActionData to the custom action,
+//  5) the guid of the patch, and
+//  6) the guid of the Msi install which will be patched.
+
+#define _WIN32_MSI 300
+
+#include "omaha/recovery/repair_exe/mspexecutableelevator.h"
+#include <atlpath.h>
+#include <msi.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/string.h"
+
+namespace omaha {
+
+namespace msp_executable_elevator {
+
+// Used to return information back to the process that called
+// ExecuteGoogleSignedExe.
+struct SharedMemoryInfo {
+  HANDLE process;
+  HRESULT launch_result;
+};
+
+// Used to store the name of the shared memory.  The name is retrieved from
+// the MSP command line when parsing the command line.  The code assumes that
+// only one thread per process will call ParseMSPCommandLine followed by
+// SetResultOfExecute (which is a safe assumption if this functionality is only
+// used for the purpose for which it was originally written).
+// Assumes that the MSP is in the same directory as the current process.
+static TCHAR parsed_shared_memory_name[200];
+
+HRESULT ExecuteGoogleSignedExe(const TCHAR* exe,
+                               const TCHAR* args,
+                               const TCHAR* kProductGuid,
+                               const TCHAR* kPatchGuid,
+                               const TCHAR* kPatchName,
+                               HANDLE* process) {
+  ASSERT1(exe);
+  ASSERT1(args);
+  ASSERT1(process);
+  ASSERT1(kProductGuid);
+  ASSERT1(kPatchGuid);
+  ASSERT1(kPatchName);
+
+  // Create shared memory in which to receive result of attempt to launch
+  // process and a handle to the launched process.
+  HRESULT hr = E_FAIL;
+  GUID random_guid = {0};
+  TCHAR shared_memory_name[200] = {0};
+  if (SUCCEEDED(::CoCreateGuid(&random_guid)) &&
+      0 < ::StringFromGUID2(random_guid,
+                            shared_memory_name,
+                            ARRAYSIZE(shared_memory_name))) {
+    HANDLE file_mapping = ::CreateFileMapping(INVALID_HANDLE_VALUE,
+                                              NULL,
+                                              PAGE_READWRITE,
+                                              0,
+                                              sizeof(file_mapping),
+                                              shared_memory_name);
+    if (file_mapping) {
+      SharedMemoryInfo* shared_info = reinterpret_cast<SharedMemoryInfo*>
+          (::MapViewOfFileEx(file_mapping,
+                             FILE_MAP_ALL_ACCESS,
+                             0,
+                             0,
+                             sizeof(*shared_info),
+                             0));
+      if (shared_info) {
+        shared_info->launch_result = E_FAIL;
+        shared_info->process = NULL;
+        // Create command line to pass to patch.  Parameters are the name of the
+        // shared memory just created, the current process id, the executable
+        // to launch, and the executable's arguments.
+        CString command_line;
+        command_line.Format(_T("EXECUTABLECOMMANDLINE=\"%s %u \"\"%s\"\" %s\" ")
+                            _T("REINSTALL=ALL"),
+                            shared_memory_name,
+                            GetCurrentProcessId(),
+                            exe,
+                            args);
+        // Generate path to patch using path to current module.
+        TCHAR module_name[MAX_PATH] = {0};
+        DWORD len = ::GetModuleFileName(_AtlBaseModule.GetModuleInstance(),
+                                        module_name,
+                                        ARRAYSIZE(module_name));
+        module_name[ARRAYSIZE(module_name) - 1] = '\0';
+        if (0 < len && len < ARRAYSIZE(module_name) &&
+            0 < command_line.GetLength()) {
+          CPath path = module_name;
+          if (path.RemoveFileSpec() && path.Append(kPatchName)) {
+            path.Canonicalize();
+            // Set install level to none so that user does not see
+            // an Msi window and so that a restore point is not created.
+            ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+            UINT res = ::MsiApplyPatch(path,
+                                       NULL,
+                                       INSTALLTYPE_DEFAULT,
+                                       command_line);
+            // MsiApplyPatch will not return until the passed executable has
+            // been launched (or not) and the shared memory has been updated.
+            *process = shared_info->process;
+            hr = HRESULT_FROM_WIN32(res);
+            if (SUCCEEDED(hr))
+              hr = shared_info->launch_result;
+          }
+        }
+        ::MsiRemovePatches(kPatchGuid,
+                           kProductGuid,
+                           INSTALLTYPE_SINGLE_INSTANCE,
+                           NULL);
+        VERIFY1(::UnmapViewOfFile(shared_info));
+      }
+      VERIFY1(::CloseHandle(file_mapping));
+    }
+  }
+  return hr;
+}
+
+bool ParseMSPCommandLine(TCHAR* command_line,
+                         TCHAR** executable_result,
+                         TCHAR** arguments_result,
+                         DWORD* calling_process_id) {
+  ASSERT1(command_line);
+  ASSERT1(executable_result);
+  ASSERT1(arguments_result);
+  ASSERT1(calling_process_id);
+  // Parse command line.  First extract name of shared memory into which
+  // the process handle of launched executable will be written.  Then extract
+  // the process id of calling process.  This process id will be used to create
+  // for the calling process a handle to the launched executable. Finally,
+  // extract the path to executable so that we can verify the executable.
+  TCHAR* shared_memory_name = NULL;
+  TCHAR* process_id_param = NULL;
+  TCHAR* arguments = NULL;
+  if (SplitCommandLineInPlace(command_line, &shared_memory_name, &arguments) &&
+      shared_memory_name && arguments &&
+      SplitCommandLineInPlace(arguments, &process_id_param, &arguments) &&
+      process_id_param && arguments &&
+      SplitCommandLineInPlace(arguments, executable_result, &arguments) &&
+      *executable_result && arguments) {
+    *calling_process_id = static_cast<DWORD>(_wtoi(process_id_param));
+    *arguments_result = arguments;
+    _tcsncpy(parsed_shared_memory_name,
+             shared_memory_name,
+             ARRAYSIZE(parsed_shared_memory_name));
+    parsed_shared_memory_name[ARRAYSIZE(parsed_shared_memory_name) - 1] =
+        _T('\0');
+    return true;
+  }
+  return false;
+}
+
+// Copy process handle and result to shared memory.
+// Process can be NULL.
+bool SetResultOfExecute(HANDLE process, HRESULT result) {
+  bool success = false;
+  if (_T('\0') != *parsed_shared_memory_name) {
+    HANDLE file_mapping = ::OpenFileMapping(FILE_MAP_WRITE,
+                                            FALSE,
+                                            parsed_shared_memory_name);
+    if (file_mapping) {
+      SharedMemoryInfo* shared_info = reinterpret_cast<SharedMemoryInfo*>
+          (::MapViewOfFileEx(file_mapping,
+                             FILE_MAP_WRITE,
+                             0,
+                             0,
+                             sizeof(SharedMemoryInfo),
+                             0));
+      if (shared_info) {
+        shared_info->process = process;
+        shared_info->launch_result = result;
+        VERIFY1(::UnmapViewOfFile(shared_info));
+        success = true;
+      } else {
+        ASSERT(false, (_T("::MapViewOfFileEx failed.")));
+      }
+
+      VERIFY1(::CloseHandle(file_mapping));
+    } else {
+      ASSERT(false, (_T("::OpenFileMapping failed.")));
+    }
+  } else {
+    ASSERT(false, (_T("parsed_shared_memory_name is empty.")));
+  }
+  return success;
+}
+
+}  // namespace msp_executable_elevator
+
+}  // namespace omaha
+
diff --git a/recovery/repair_exe/mspexecutableelevator.h b/recovery/repair_exe/mspexecutableelevator.h
index fd33999..0cc35d5 100644
--- a/recovery/repair_exe/mspexecutableelevator.h
+++ b/recovery/repair_exe/mspexecutableelevator.h
@@ -1,65 +1,65 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// This is the API for verifying and executing an executable under high

-// integrity using an Msi Patch.  This API assumes its needed Msi has already

-// been installed and its needed Msp is in the same directory as this module.

-//

-// This class encapsulates the code for passing information between a process

-// requesting that an executable be elevated and the custom action DLL

-// in the patch which actually elevates the executable.

-

-#ifndef OMAHA_RECOVERY_REPAIR_EXE_MSPEXECUTABLEELEVATOR_H__

-#define OMAHA_RECOVERY_REPAIR_EXE_MSPEXECUTABLEELEVATOR_H__

-

-#include <windows.h>

-#include <tchar.h>

-

-namespace omaha {

-

-namespace msp_executable_elevator {

-

-// The following function should be called by the code requesting that

-// an executable be elevated:

-

-// Use an MSI patch to verify and execute an executable.  Returns a handle

-// to the process executed.

-HRESULT ExecuteGoogleSignedExe(const TCHAR* executable,

-                               const TCHAR* arguments,

-                               const TCHAR* kProductGuid,

-                               const TCHAR* kPatchGuid,

-                               const TCHAR* kPatchName,

-                               HANDLE* process);

-

-// The following functions should be called by the code (i.e., the custom action

-// DLL) that actually elevates the executable:

-

-// From the command line passed to the MSP, retrieve the parameters that will be

-// passed to VerifyFileAndExecute.

-// This function is destructive to the passed command line buffer.  The pointers

-// "executable" and "arguments" will point into the command line buffer.

-bool ParseMSPCommandLine(TCHAR* command_line,

-                         TCHAR** executable,

-                         TCHAR** arguments,

-                         DWORD* calling_process_id);

-

-// Records the result of the call to VerifyFileAndExecute.

-bool SetResultOfExecute(HANDLE process, HRESULT result);

-

-}  // namespace msp_executable_elevator

-

-}  // namespace omaha

-

-#endif  // OMAHA_RECOVERY_REPAIR_EXE_MSPEXECUTABLEELEVATOR_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// This is the API for verifying and executing an executable under high
+// integrity using an Msi Patch.  This API assumes its needed Msi has already
+// been installed and its needed Msp is in the same directory as this module.
+//
+// This class encapsulates the code for passing information between a process
+// requesting that an executable be elevated and the custom action DLL
+// in the patch which actually elevates the executable.
+
+#ifndef OMAHA_RECOVERY_REPAIR_EXE_MSPEXECUTABLEELEVATOR_H__
+#define OMAHA_RECOVERY_REPAIR_EXE_MSPEXECUTABLEELEVATOR_H__
+
+#include <windows.h>
+#include <tchar.h>
+
+namespace omaha {
+
+namespace msp_executable_elevator {
+
+// The following function should be called by the code requesting that
+// an executable be elevated:
+
+// Use an MSI patch to verify and execute an executable.  Returns a handle
+// to the process executed.
+HRESULT ExecuteGoogleSignedExe(const TCHAR* executable,
+                               const TCHAR* arguments,
+                               const TCHAR* kProductGuid,
+                               const TCHAR* kPatchGuid,
+                               const TCHAR* kPatchName,
+                               HANDLE* process);
+
+// The following functions should be called by the code (i.e., the custom action
+// DLL) that actually elevates the executable:
+
+// From the command line passed to the MSP, retrieve the parameters that will be
+// passed to VerifyFileAndExecute.
+// This function is destructive to the passed command line buffer.  The pointers
+// "executable" and "arguments" will point into the command line buffer.
+bool ParseMSPCommandLine(TCHAR* command_line,
+                         TCHAR** executable,
+                         TCHAR** arguments,
+                         DWORD* calling_process_id);
+
+// Records the result of the call to VerifyFileAndExecute.
+bool SetResultOfExecute(HANDLE process, HRESULT result);
+
+}  // namespace msp_executable_elevator
+
+}  // namespace omaha
+
+#endif  // OMAHA_RECOVERY_REPAIR_EXE_MSPEXECUTABLEELEVATOR_H__
diff --git a/recovery/repair_exe/mspexecutableelevator_unittest.cc b/recovery/repair_exe/mspexecutableelevator_unittest.cc
index ef8ab6c..d3bf36a 100644
--- a/recovery/repair_exe/mspexecutableelevator_unittest.cc
+++ b/recovery/repair_exe/mspexecutableelevator_unittest.cc
@@ -1,264 +1,264 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Unit tests for msp_executable_elevator.

-//

-// Note for Windows Vista and later: These tests will fail because the Msi*

-// methods return an error because they do not elevate due to the UI level NONE.

-// Enabling the UI would cause UAC prompts and the creation of restore points.

-// The workaround is to run from an administrator command prompt.

-

-#include <windows.h>

-#include <msi.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/recovery/repair_exe/mspexecutableelevator.h"

-#include "omaha/setup/msi_test_utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-// Note: For some reason, the product ID GUIDs are swizzled in the registry.

-extern const TCHAR kMsiProductPatchesKey[] =

-    _T("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\")

-    _T("Installer\\UserData\\S-1-5-18\\Products\\")

-    _T("93BAD29AC2E44034A96BCB446EB8552E\\Patches");

-

-void InstallMsi() {

-  CString msi_path(app_util::GetCurrentModuleDirectory());

-  EXPECT_TRUE(::PathAppend(CStrBuf(msi_path, MAX_PATH),

-                           kHelperInstallerName));

-  ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);

-

-  UINT res = ::MsiInstallProduct(msi_path, _T(""));

-

-  if (vista_util::IsUserAdmin()) {

-    if (ERROR_SUCCESS != res) {

-      EXPECT_EQ(ERROR_PRODUCT_VERSION, res);

-      // The product may already be installed. Force a reinstall of everything.

-      res = ::MsiInstallProduct(msi_path,

-                                _T("REINSTALL=ALL REINSTALLMODE=vamus"));

-    }

-    EXPECT_EQ(ERROR_SUCCESS, res);

-  } else {

-    if (IsMsiHelperInstalled()) {

-      EXPECT_EQ(ERROR_INSTALL_PACKAGE_REJECTED, res);

-    } else {

-      EXPECT_EQ(ERROR_INSTALL_FAILURE, res);

-    }

-  }

-}

-

-void RemoveMsi() {

-  ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);

-  UINT res = ::MsiConfigureProduct(kHelperInstallerProductGuid,

-                                   INSTALLLEVEL_DEFAULT,

-                                   INSTALLSTATE_ABSENT);

-  if (vista_util::IsUserAdmin()) {

-    EXPECT_TRUE((ERROR_SUCCESS == res) ||

-                ((ERROR_UNKNOWN_PRODUCT == res) && !IsMsiHelperInstalled()));

-  } else {

-    if (IsMsiHelperInstalled()) {

-      EXPECT_EQ(ERROR_INSTALL_FAILURE, res);

-    } else {

-      EXPECT_EQ(ERROR_UNKNOWN_PRODUCT, res);

-    }

-  }

-}

-

-HRESULT ExecuteGoogleSignedExeWithCorrectPatchInfo(const TCHAR* executable,

-                                                   const TCHAR* arguments,

-                                                   HANDLE* process) {

-  return msp_executable_elevator::ExecuteGoogleSignedExe(

-                                      executable,

-                                      arguments,

-                                      kHelperInstallerProductGuid,

-                                      kHelperPatchGuid,

-                                      kHelperPatchName,

-                                      process);

-}

-

-// Base class for tests that expect the MSI to be installed.

-// The elevation mechanism will not be installed when these test complete.

-class RepairGoopdateWithMsiInstalledTest : public testing::Test {

- protected:

-  static void SetUpTestCase() {

-    InstallMsi();

-  }

-

-  static void TearDownTestCase() {

-    RemoveMsi();

-  }

-};

-

-// Base class for tests that expect the MSI not to be installed.

-// The elevation mechanism will not be installed when these test complete.

-class RepairGoopdateWithoutMsiInstalledTest : public testing::Test {

- protected:

-  static void SetUpTestCase() {

-    RemoveMsi();

-  }

-};

-

-TEST_F(RepairGoopdateWithMsiInstalledTest,

-       ExecuteGoogleSignedExe_RepairFileDoesNotExist) {

-  CString repair_file(_T("no_such_file.exe"));

-  HANDLE process = NULL;

-  HRESULT hr = ExecuteGoogleSignedExeWithCorrectPatchInfo(repair_file,

-                                                          _T(""),

-                                                          &process);

-  if (vista_util::IsUserAdmin() || IsMsiHelperInstalled()) {

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);

-  } else {

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND), hr);

-  }

-

-  EXPECT_TRUE(NULL == process);

-}

-

-TEST_F(RepairGoopdateWithMsiInstalledTest,

-       ExecuteGoogleSignedExe_UnsignedFile) {

-  CString repair_file(app_util::GetCurrentModuleDirectory());

-  EXPECT_TRUE(::PathAppend(CStrBuf(repair_file, MAX_PATH),

-              _T("GoogleUpdate_unsigned.exe")));

-  HANDLE process = NULL;

-  HRESULT hr = ExecuteGoogleSignedExeWithCorrectPatchInfo(repair_file,

-                                                          _T(""),

-                                                          &process);

-  if (vista_util::IsUserAdmin() || IsMsiHelperInstalled()) {

-    EXPECT_EQ(TRUST_E_NOSIGNATURE, hr);

-  } else {

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND), hr);

-  }

-  EXPECT_TRUE(NULL == process);

-}

-

-// This valid repair file saves the arguments passed to it to a file.

-TEST_F(RepairGoopdateWithMsiInstalledTest,

-       ExecuteGoogleSignedExe_ValidRepairFile) {

-  const TCHAR kArgs[] = _T("These /are the args.");

-  CString repair_file(app_util::GetCurrentModuleDirectory());

-  EXPECT_TRUE(::PathAppend(CStrBuf(repair_file, MAX_PATH),

-              _T("unittest_support\\SaveArguments.exe")));

-  CString program_files_path;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files_path));

-  CString saved_arguments_file_path =

-      program_files_path + _T("\\Google\\Update\\saved_arguments.txt");

-

-  ::DeleteFile(saved_arguments_file_path);

-

-  bool is_msi_installed = IsMsiHelperInstalled();

-

-  if (vista_util::IsUserAdmin() || is_msi_installed) {

-    if (vista_util::IsUserAdmin()) {

-      EXPECT_FALSE(File::Exists(saved_arguments_file_path));

-    }

-

-    // Verify that no patch is installed.

-    EXPECT_TRUE(RegKey::HasNativeKey(kMsiProductPatchesKey));

-    RegKey product_patches_key;

-    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,

-                                              KEY_READ | KEY_WOW64_64KEY));

-    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());

-

-    HANDLE process = NULL;

-    EXPECT_SUCCEEDED(ExecuteGoogleSignedExeWithCorrectPatchInfo(repair_file,

-                                                                kArgs,

-                                                                &process));

-    EXPECT_TRUE(NULL == process);

-

-    // Verify that patch was uninstalled.

-    // GetSubkeyCount fails if we don't re-open the key.

-    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,

-                                              KEY_READ | KEY_WOW64_64KEY));

-    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());

-

-    bool is_found = false;

-    for (int tries = 0; tries < 100 && !is_found; ++tries) {

-      ::Sleep(50);

-      is_found = File::Exists(saved_arguments_file_path);

-    }

-    ASSERT_TRUE(is_found);

-

-    scoped_hfile file;

-    for (int tries = 0; tries < 100 && !valid(file); ++tries) {

-      ::Sleep(50);

-      reset(file, ::CreateFile(saved_arguments_file_path,

-                               GENERIC_READ,

-                               0,                        // do not share

-                               NULL,                     // default security

-                               OPEN_EXISTING,            // existing file only

-                               FILE_ATTRIBUTE_NORMAL,

-                               NULL));                   // no template

-    }

-    ASSERT_TRUE(valid(file));

-

-    const int kBufferLen = 50;

-    TCHAR buffer[kBufferLen + 1] = {0};

-    DWORD bytes_read = 0;

-

-    EXPECT_TRUE(::ReadFile(get(file),

-                           buffer,

-                           kBufferLen * sizeof(TCHAR),

-                           &bytes_read,

-                           NULL));

-    EXPECT_EQ(0, bytes_read % sizeof(TCHAR));

-    buffer[bytes_read / sizeof(TCHAR)] = _T('\0');

-    EXPECT_STREQ(kArgs, buffer);

-

-    reset(file);

-

-    bool succeeded = !!::DeleteFile(saved_arguments_file_path);

-    if (vista_util::IsUserAdmin()) {

-      EXPECT_TRUE(succeeded);

-    }

-  } else {

-    bool expected_file_exists = File::Exists(saved_arguments_file_path);

-    HANDLE process = NULL;

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND),

-              ExecuteGoogleSignedExeWithCorrectPatchInfo(repair_file,

-                                                         kArgs,

-                                                         &process));

-    EXPECT_TRUE(NULL == process);

-

-    // We can't force the file to be deleted, so make sure it wasn't created

-    // or deleted by the above method.

-    EXPECT_EQ(expected_file_exists, File::Exists(saved_arguments_file_path));

-  }

-}

-

-TEST_F(RepairGoopdateWithoutMsiInstalledTest,

-       ExecuteGoogleSignedExe_MsiNotInstalled) {

-  if (!vista_util::IsUserAdmin() && IsMsiHelperInstalled()) {

-    std::wcout << _T("\tThis test did not run because the user is not an ")

-                  _T("admin and the MSI is already installed.") << std::endl;

-    return;

-  }

-

-  CString repair_file(_T("notepad.exe"));

-  HANDLE process = NULL;

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND),

-            ExecuteGoogleSignedExeWithCorrectPatchInfo(repair_file,

-                                                       _T(""),

-                                                       &process));

-  EXPECT_TRUE(NULL == process);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Unit tests for msp_executable_elevator.
+//
+// Note for Windows Vista and later: These tests will fail because the Msi*
+// methods return an error because they do not elevate due to the UI level NONE.
+// Enabling the UI would cause UAC prompts and the creation of restore points.
+// The workaround is to run from an administrator command prompt.
+
+#include <windows.h>
+#include <msi.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/recovery/repair_exe/mspexecutableelevator.h"
+#include "omaha/setup/msi_test_utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+// Note: For some reason, the product ID GUIDs are swizzled in the registry.
+extern const TCHAR kMsiProductPatchesKey[] =
+    _T("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\")
+    _T("Installer\\UserData\\S-1-5-18\\Products\\")
+    _T("93BAD29AC2E44034A96BCB446EB8552E\\Patches");
+
+void InstallMsi() {
+  CString msi_path(app_util::GetCurrentModuleDirectory());
+  EXPECT_TRUE(::PathAppend(CStrBuf(msi_path, MAX_PATH),
+                           kHelperInstallerName));
+  ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+  UINT res = ::MsiInstallProduct(msi_path, _T(""));
+
+  if (vista_util::IsUserAdmin()) {
+    if (ERROR_SUCCESS != res) {
+      EXPECT_EQ(ERROR_PRODUCT_VERSION, res);
+      // The product may already be installed. Force a reinstall of everything.
+      res = ::MsiInstallProduct(msi_path,
+                                _T("REINSTALL=ALL REINSTALLMODE=vamus"));
+    }
+    EXPECT_EQ(ERROR_SUCCESS, res);
+  } else {
+    if (IsMsiHelperInstalled()) {
+      EXPECT_EQ(ERROR_INSTALL_PACKAGE_REJECTED, res);
+    } else {
+      EXPECT_EQ(ERROR_INSTALL_FAILURE, res);
+    }
+  }
+}
+
+void RemoveMsi() {
+  ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+  UINT res = ::MsiConfigureProduct(kHelperInstallerProductGuid,
+                                   INSTALLLEVEL_DEFAULT,
+                                   INSTALLSTATE_ABSENT);
+  if (vista_util::IsUserAdmin()) {
+    EXPECT_TRUE((ERROR_SUCCESS == res) ||
+                ((ERROR_UNKNOWN_PRODUCT == res) && !IsMsiHelperInstalled()));
+  } else {
+    if (IsMsiHelperInstalled()) {
+      EXPECT_EQ(ERROR_INSTALL_FAILURE, res);
+    } else {
+      EXPECT_EQ(ERROR_UNKNOWN_PRODUCT, res);
+    }
+  }
+}
+
+HRESULT ExecuteGoogleSignedExeWithCorrectPatchInfo(const TCHAR* executable,
+                                                   const TCHAR* arguments,
+                                                   HANDLE* process) {
+  return msp_executable_elevator::ExecuteGoogleSignedExe(
+                                      executable,
+                                      arguments,
+                                      kHelperInstallerProductGuid,
+                                      kHelperPatchGuid,
+                                      kHelperPatchName,
+                                      process);
+}
+
+// Base class for tests that expect the MSI to be installed.
+// The elevation mechanism will not be installed when these test complete.
+class RepairGoopdateWithMsiInstalledTest : public testing::Test {
+ protected:
+  static void SetUpTestCase() {
+    InstallMsi();
+  }
+
+  static void TearDownTestCase() {
+    RemoveMsi();
+  }
+};
+
+// Base class for tests that expect the MSI not to be installed.
+// The elevation mechanism will not be installed when these test complete.
+class RepairGoopdateWithoutMsiInstalledTest : public testing::Test {
+ protected:
+  static void SetUpTestCase() {
+    RemoveMsi();
+  }
+};
+
+TEST_F(RepairGoopdateWithMsiInstalledTest,
+       ExecuteGoogleSignedExe_RepairFileDoesNotExist) {
+  CString repair_file(_T("no_such_file.exe"));
+  HANDLE process = NULL;
+  HRESULT hr = ExecuteGoogleSignedExeWithCorrectPatchInfo(repair_file,
+                                                          _T(""),
+                                                          &process);
+  if (vista_util::IsUserAdmin() || IsMsiHelperInstalled()) {
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);
+  } else {
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND), hr);
+  }
+
+  EXPECT_TRUE(NULL == process);
+}
+
+TEST_F(RepairGoopdateWithMsiInstalledTest,
+       ExecuteGoogleSignedExe_UnsignedFile) {
+  CString repair_file(app_util::GetCurrentModuleDirectory());
+  EXPECT_TRUE(::PathAppend(CStrBuf(repair_file, MAX_PATH),
+              _T("GoogleUpdate_unsigned.exe")));
+  HANDLE process = NULL;
+  HRESULT hr = ExecuteGoogleSignedExeWithCorrectPatchInfo(repair_file,
+                                                          _T(""),
+                                                          &process);
+  if (vista_util::IsUserAdmin() || IsMsiHelperInstalled()) {
+    EXPECT_EQ(TRUST_E_NOSIGNATURE, hr);
+  } else {
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND), hr);
+  }
+  EXPECT_TRUE(NULL == process);
+}
+
+// This valid repair file saves the arguments passed to it to a file.
+TEST_F(RepairGoopdateWithMsiInstalledTest,
+       ExecuteGoogleSignedExe_ValidRepairFile) {
+  const TCHAR kArgs[] = _T("These /are the args.");
+  CString repair_file(app_util::GetCurrentModuleDirectory());
+  EXPECT_TRUE(::PathAppend(CStrBuf(repair_file, MAX_PATH),
+              _T("unittest_support\\SaveArguments.exe")));
+  CString program_files_path;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files_path));
+  CString saved_arguments_file_path =
+      program_files_path + _T("\\Google\\Update\\saved_arguments.txt");
+
+  ::DeleteFile(saved_arguments_file_path);
+
+  bool is_msi_installed = IsMsiHelperInstalled();
+
+  if (vista_util::IsUserAdmin() || is_msi_installed) {
+    if (vista_util::IsUserAdmin()) {
+      EXPECT_FALSE(File::Exists(saved_arguments_file_path));
+    }
+
+    // Verify that no patch is installed.
+    EXPECT_TRUE(RegKey::HasNativeKey(kMsiProductPatchesKey));
+    RegKey product_patches_key;
+    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,
+                                              KEY_READ | KEY_WOW64_64KEY));
+    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());
+
+    HANDLE process = NULL;
+    EXPECT_SUCCEEDED(ExecuteGoogleSignedExeWithCorrectPatchInfo(repair_file,
+                                                                kArgs,
+                                                                &process));
+    EXPECT_TRUE(NULL == process);
+
+    // Verify that patch was uninstalled.
+    // GetSubkeyCount fails if we don't re-open the key.
+    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,
+                                              KEY_READ | KEY_WOW64_64KEY));
+    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());
+
+    bool is_found = false;
+    for (int tries = 0; tries < 100 && !is_found; ++tries) {
+      ::Sleep(50);
+      is_found = File::Exists(saved_arguments_file_path);
+    }
+    ASSERT_TRUE(is_found);
+
+    scoped_hfile file;
+    for (int tries = 0; tries < 100 && !valid(file); ++tries) {
+      ::Sleep(50);
+      reset(file, ::CreateFile(saved_arguments_file_path,
+                               GENERIC_READ,
+                               0,                        // do not share
+                               NULL,                     // default security
+                               OPEN_EXISTING,            // existing file only
+                               FILE_ATTRIBUTE_NORMAL,
+                               NULL));                   // no template
+    }
+    ASSERT_TRUE(valid(file));
+
+    const int kBufferLen = 50;
+    TCHAR buffer[kBufferLen + 1] = {0};
+    DWORD bytes_read = 0;
+
+    EXPECT_TRUE(::ReadFile(get(file),
+                           buffer,
+                           kBufferLen * sizeof(TCHAR),
+                           &bytes_read,
+                           NULL));
+    EXPECT_EQ(0, bytes_read % sizeof(TCHAR));
+    buffer[bytes_read / sizeof(TCHAR)] = _T('\0');
+    EXPECT_STREQ(kArgs, buffer);
+
+    reset(file);
+
+    bool succeeded = !!::DeleteFile(saved_arguments_file_path);
+    if (vista_util::IsUserAdmin()) {
+      EXPECT_TRUE(succeeded);
+    }
+  } else {
+    bool expected_file_exists = File::Exists(saved_arguments_file_path);
+    HANDLE process = NULL;
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND),
+              ExecuteGoogleSignedExeWithCorrectPatchInfo(repair_file,
+                                                         kArgs,
+                                                         &process));
+    EXPECT_TRUE(NULL == process);
+
+    // We can't force the file to be deleted, so make sure it wasn't created
+    // or deleted by the above method.
+    EXPECT_EQ(expected_file_exists, File::Exists(saved_arguments_file_path));
+  }
+}
+
+TEST_F(RepairGoopdateWithoutMsiInstalledTest,
+       ExecuteGoogleSignedExe_MsiNotInstalled) {
+  if (!vista_util::IsUserAdmin() && IsMsiHelperInstalled()) {
+    std::wcout << _T("\tThis test did not run because the user is not an ")
+                  _T("admin and the MSI is already installed.") << std::endl;
+    return;
+  }
+
+  CString repair_file(_T("notepad.exe"));
+  HANDLE process = NULL;
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND),
+            ExecuteGoogleSignedExeWithCorrectPatchInfo(repair_file,
+                                                       _T(""),
+                                                       &process));
+  EXPECT_TRUE(NULL == process);
+}
+
+}  // namespace omaha
diff --git a/recovery/repair_exe/repair_goopdate.cc b/recovery/repair_exe/repair_goopdate.cc
index 6b977f8..16cb32f 100644
--- a/recovery/repair_exe/repair_goopdate.cc
+++ b/recovery/repair_exe/repair_goopdate.cc
@@ -1,78 +1,78 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Helper for the Google Update repair file. It launches the same repair file

-// elevated using the MSP.

-

-#include "omaha/recovery/repair_exe/repair_goopdate.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/recovery/repair_exe/mspexecutableelevator.h"

-

-namespace omaha {

-

-// Returns without launching the repair file if is_machine is false, running

-// on a pre-Windows Vista OS, or the current user is Local System.

-// This method does not always launch the repair file because we expect this

-// to be called from the repair file, and there is no reason to launch another

-// process.

-bool LaunchRepairFileElevated(bool is_machine,

-                              const TCHAR* repair_file,

-                              const TCHAR* args,

-                              HRESULT* elevation_hr) {

-  ASSERT1(elevation_hr);

-

-  *elevation_hr = S_OK;

-

-  if (!is_machine) {

-    UTIL_LOG(L2,  (_T("[user instance - not elevating]")));

-    return false;

-  }

-  if (!vista_util::IsVistaOrLater()) {

-    UTIL_LOG(L2,  (_T("[Pre-Windows Vista OS - not elevating]")));

-    return false;

-  }

-

-  bool is_user_local_system = false;

-  HRESULT hr = IsSystemProcess(&is_user_local_system);

-  if (SUCCEEDED(hr) && is_user_local_system) {

-    UTIL_LOG(L2,  (_T("[User is already SYSTEM - not elevating]")));

-    return false;

-  }

-

-  HANDLE process = NULL;

-  *elevation_hr = msp_executable_elevator::ExecuteGoogleSignedExe(

-                                               repair_file,

-                                               args,

-                                               kHelperInstallerProductGuid,

-                                               kHelperPatchGuid,

-                                               kHelperPatchName,

-                                               &process);

-  // Our implementation of msp_executable_elevator does not set the process

-  // handle parameter, but we did not remove it from the borrowed code.

-  ASSERT1(!process);

-

-  if (FAILED(*elevation_hr)) {

-    UTIL_LOG(LE, (_T("[ExecuteGoogleSignedExe failed][error 0x%08x]"),

-                  *elevation_hr));

-    return false;

-  }

-

-  return true;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Helper for the Google Update repair file. It launches the same repair file
+// elevated using the MSP.
+
+#include "omaha/recovery/repair_exe/repair_goopdate.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/recovery/repair_exe/mspexecutableelevator.h"
+
+namespace omaha {
+
+// Returns without launching the repair file if is_machine is false, running
+// on a pre-Windows Vista OS, or the current user is Local System.
+// This method does not always launch the repair file because we expect this
+// to be called from the repair file, and there is no reason to launch another
+// process.
+bool LaunchRepairFileElevated(bool is_machine,
+                              const TCHAR* repair_file,
+                              const TCHAR* args,
+                              HRESULT* elevation_hr) {
+  ASSERT1(elevation_hr);
+
+  *elevation_hr = S_OK;
+
+  if (!is_machine) {
+    UTIL_LOG(L2,  (_T("[user instance - not elevating]")));
+    return false;
+  }
+  if (!vista_util::IsVistaOrLater()) {
+    UTIL_LOG(L2,  (_T("[Pre-Windows Vista OS - not elevating]")));
+    return false;
+  }
+
+  bool is_user_local_system = false;
+  HRESULT hr = IsSystemProcess(&is_user_local_system);
+  if (SUCCEEDED(hr) && is_user_local_system) {
+    UTIL_LOG(L2,  (_T("[User is already SYSTEM - not elevating]")));
+    return false;
+  }
+
+  HANDLE process = NULL;
+  *elevation_hr = msp_executable_elevator::ExecuteGoogleSignedExe(
+                                               repair_file,
+                                               args,
+                                               kHelperInstallerProductGuid,
+                                               kHelperPatchGuid,
+                                               kHelperPatchName,
+                                               &process);
+  // Our implementation of msp_executable_elevator does not set the process
+  // handle parameter, but we did not remove it from the borrowed code.
+  ASSERT1(!process);
+
+  if (FAILED(*elevation_hr)) {
+    UTIL_LOG(LE, (_T("[ExecuteGoogleSignedExe failed][error 0x%08x]"),
+                  *elevation_hr));
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace omaha
diff --git a/recovery/repair_exe/repair_goopdate.h b/recovery/repair_exe/repair_goopdate.h
index f5068c7..bfb2a3c 100644
--- a/recovery/repair_exe/repair_goopdate.h
+++ b/recovery/repair_exe/repair_goopdate.h
@@ -1,42 +1,42 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Helper for the Google Update repair file. It launches the same repair file

-// elevated using the MSP.

-

-#ifndef OMAHA_RECOVERY_REPAIR_EXE_REPAIR_GOOPDATE_H__

-#define OMAHA_RECOVERY_REPAIR_EXE_REPAIR_GOOPDATE_H__

-

-#include <windows.h>

-#include <tchar.h>

-

-namespace omaha {

-

-// Launches the repair file elevated if necessary.

-// Returns whether the repair file was successfully launched elevated.

-// When the method returns false, the caller should execute the repair

-// operations unelevated. Otherwise, the caller is done.

-// Example:

-//   if (!LaunchRepairFileElevated(...)) {

-//     DoRepairUnelevated();

-//   }

-bool LaunchRepairFileElevated(bool is_machine,

-                              const TCHAR* repair_file,

-                              const TCHAR* args,

-                              HRESULT* elevation_hr);

-

-}  // namespace omaha

-

-#endif  // OMAHA_RECOVERY_REPAIR_EXE_REPAIR_GOOPDATE_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Helper for the Google Update repair file. It launches the same repair file
+// elevated using the MSP.
+
+#ifndef OMAHA_RECOVERY_REPAIR_EXE_REPAIR_GOOPDATE_H__
+#define OMAHA_RECOVERY_REPAIR_EXE_REPAIR_GOOPDATE_H__
+
+#include <windows.h>
+#include <tchar.h>
+
+namespace omaha {
+
+// Launches the repair file elevated if necessary.
+// Returns whether the repair file was successfully launched elevated.
+// When the method returns false, the caller should execute the repair
+// operations unelevated. Otherwise, the caller is done.
+// Example:
+//   if (!LaunchRepairFileElevated(...)) {
+//     DoRepairUnelevated();
+//   }
+bool LaunchRepairFileElevated(bool is_machine,
+                              const TCHAR* repair_file,
+                              const TCHAR* args,
+                              HRESULT* elevation_hr);
+
+}  // namespace omaha
+
+#endif  // OMAHA_RECOVERY_REPAIR_EXE_REPAIR_GOOPDATE_H__
diff --git a/recovery/repair_exe/repair_goopdate_unittest.cc b/recovery/repair_exe/repair_goopdate_unittest.cc
index 61a5f17..d3422c1 100644
--- a/recovery/repair_exe/repair_goopdate_unittest.cc
+++ b/recovery/repair_exe/repair_goopdate_unittest.cc
@@ -1,228 +1,228 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Unit tests for the Omaha repair mechanism.

-

-#include "omaha/common/app_util.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/recovery/repair_exe/repair_goopdate.h"

-#include "omaha/setup/msi_test_utils.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-const TCHAR kArgumentSavingExecutableRelativePath[] =

-    _T("unittest_support\\SaveArguments.exe");

-

-extern const TCHAR kMsiProductPatchesKey[];

-void InstallMsi();

-void RemoveMsi();

-

-class RepairGoopdateTest : public testing::Test {

- protected:

-  static void SetUpTestCase() {

-    valid_path = app_util::GetCurrentModuleDirectory();

-    VERIFY1(::PathAppend(CStrBuf(valid_path, MAX_PATH),

-                         kArgumentSavingExecutableRelativePath));

-  }

-

-  static CString valid_path;

-};

-

-CString RepairGoopdateTest::valid_path;

-

-TEST_F(RepairGoopdateTest, LaunchRepairFileElevated_UserInstance) {

-  HRESULT hr = E_FAIL;

-  EXPECT_FALSE(LaunchRepairFileElevated(false, valid_path, _T("/update"), &hr));

-  EXPECT_SUCCEEDED(hr);

-}

-

-// This test only runs on pre-Windows Vista OSes.

-TEST_F(RepairGoopdateTest, LaunchRepairFileElevated_MachineInstancePreVista) {

-  if (!vista_util::IsVistaOrLater()) {

-    HRESULT hr = E_FAIL;

-    EXPECT_FALSE(LaunchRepairFileElevated(true, valid_path, _T(""), &hr));

-    EXPECT_SUCCEEDED(hr);

-  }

-}

-

-// This test only runs on Windows Vista and later OSes.

-TEST_F(RepairGoopdateTest,

-       LaunchRepairFileElevated_MachineInstanceVistaWithMsiInstalledValidFile) {

-  if (!vista_util::IsVistaOrLater()) {

-    std::wcout << _T("\tThis test did not run because it requires Windows ")

-                  _T("Vista or later.") << std::endl;

-    return;

-  }

-

-  const TCHAR kArgs[] = _T("/update");

-  CString saved_arguments_file_path =

-      _T("%PROGRAMFILES%\\Google\\Update\\saved_arguments.txt");

-  EXPECT_SUCCEEDED(ExpandStringWithSpecialFolders(&saved_arguments_file_path));

-

-  ::DeleteFile(saved_arguments_file_path);

-

-  bool is_msi_installed = IsMsiHelperInstalled();

-

-  if (vista_util::IsUserAdmin() || is_msi_installed) {

-    if (vista_util::IsUserAdmin()) {

-      EXPECT_FALSE(File::Exists(saved_arguments_file_path));

-    }

-

-    InstallMsi();

-

-    // Verify that no patch is installed.

-    EXPECT_TRUE(RegKey::HasNativeKey(kMsiProductPatchesKey));

-    RegKey product_patches_key;

-    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,

-                                              KEY_READ | KEY_WOW64_64KEY));

-    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());

-

-    HRESULT hr = E_FAIL;

-    EXPECT_TRUE(LaunchRepairFileElevated(true, valid_path, kArgs, &hr));

-    EXPECT_SUCCEEDED(hr);

-

-    // Verify that patch was uninstalled.

-    // GetSubkeyCount fails if we don't re-open the key.

-    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,

-                                              KEY_READ | KEY_WOW64_64KEY));

-    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());

-

-    bool is_found = false;

-    for (int tries = 0; tries < 100 && !is_found; ++tries) {

-      ::Sleep(50);

-      is_found = File::Exists(saved_arguments_file_path);

-    }

-    ASSERT_TRUE(is_found);

-

-    scoped_hfile file;

-    for (int tries = 0; tries < 100 && !valid(file); ++tries) {

-      ::Sleep(50);

-      reset(file, ::CreateFile(saved_arguments_file_path,

-                               GENERIC_READ,

-                               0,                        // do not share

-                               NULL,                     // default security

-                               OPEN_EXISTING,            // existing file only

-                               FILE_ATTRIBUTE_NORMAL,

-                               NULL));                   // no template

-    }

-    ASSERT_TRUE(valid(file));

-

-    const int kBufferLen = 50;

-    TCHAR buffer[kBufferLen + 1] = {0};

-    DWORD bytes_read = 0;

-

-    EXPECT_TRUE(::ReadFile(get(file),

-                           buffer,

-                           kBufferLen * sizeof(TCHAR),

-                           &bytes_read,

-                           NULL));

-

-    EXPECT_EQ(0, bytes_read % sizeof(TCHAR));

-    buffer[bytes_read / sizeof(TCHAR)] = _T('\0');

-    EXPECT_STREQ(kArgs, buffer);

-

-    reset(file);

-

-    BOOL succeeded = ::DeleteFile(saved_arguments_file_path);

-    if (vista_util::IsUserAdmin()) {

-      EXPECT_TRUE(succeeded);

-    }

-

-    RemoveMsi();

-  } else {

-    const bool expected_file_exists = File::Exists(saved_arguments_file_path);

-    HRESULT hr = E_FAIL;

-    EXPECT_FALSE(LaunchRepairFileElevated(true, valid_path, kArgs, &hr));

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND), hr);

-

-    // We can't force the file to be deleted, so make sure it wasn't created

-    // or deleted by the above method.

-    EXPECT_EQ(expected_file_exists, File::Exists(saved_arguments_file_path));

-  }

-}

-

-// This test only runs on Windows Vista and later OSes.

-// The MSP to runs, but fails because the specified file (the unit tests)

-// is not a valid repair file.

-TEST_F(RepairGoopdateTest,

-       LaunchRepairFileElevated_MachineInstanceVistaWithMsiInstalledBadFile) {

-  if (!vista_util::IsVistaOrLater()) {

-    std::wcout << _T("\tThis test did not run because it requires Windows ")

-                  _T("Vista or later.") << std::endl;

-    return;

-  }

-

-  if (vista_util::IsUserAdmin() || IsMsiHelperInstalled()) {

-    InstallMsi();

-

-    // Verify that no patch is installed.

-    EXPECT_TRUE(RegKey::HasNativeKey(kMsiProductPatchesKey));

-    RegKey product_patches_key;

-    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,

-                                              KEY_READ | KEY_WOW64_64KEY));

-    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());

-

-    HRESULT hr = E_FAIL;

-    EXPECT_FALSE(LaunchRepairFileElevated(true,

-                                          app_util::GetCurrentModulePath(),

-                                          _T("/update"),

-                                          &hr));

-    EXPECT_EQ(TRUST_E_NOSIGNATURE, hr);

-

-    // Verify that patch was uninstalled.

-    // GetSubkeyCount fails if we don't re-open the key.

-    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,

-                                              KEY_READ | KEY_WOW64_64KEY));

-    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());

-

-    RemoveMsi();

-  } else {

-    HRESULT hr = E_FAIL;

-    EXPECT_FALSE(LaunchRepairFileElevated(true,

-                                          app_util::GetCurrentModulePath(),

-                                          _T("/update"),

-                                          &hr));

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND), hr);

-  }

-}

-

-// This test only runs on Windows Vista and later OSes.

-TEST_F(RepairGoopdateTest,

-       LaunchRepairFileElevated_MachineInstanceVistaWithoutMsiInstalled) {

-  if (!vista_util::IsVistaOrLater()) {

-    std::wcout << _T("\tThis test did not run because it requires Windows ")

-                  _T("Vista or later.") << std::endl;

-    return;

-  }

-

-  if (vista_util::IsUserAdmin()) {

-    RemoveMsi();

-  } else if (IsMsiHelperInstalled()) {

-    std::wcout << _T("\tThis test did not run because the user is not an ")

-                  _T("admin and the MSI is already installed.") << std::endl;

-    return;

-  }

-  // else the user is not an admin but the MSI is not installed, so continue.

-

-  HRESULT hr = E_FAIL;

-  EXPECT_FALSE(LaunchRepairFileElevated(true, valid_path, _T("/update"), &hr));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND), hr);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Unit tests for the Omaha repair mechanism.
+
+#include "omaha/common/app_util.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/recovery/repair_exe/repair_goopdate.h"
+#include "omaha/setup/msi_test_utils.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+const TCHAR kArgumentSavingExecutableRelativePath[] =
+    _T("unittest_support\\SaveArguments.exe");
+
+extern const TCHAR kMsiProductPatchesKey[];
+void InstallMsi();
+void RemoveMsi();
+
+class RepairGoopdateTest : public testing::Test {
+ protected:
+  static void SetUpTestCase() {
+    valid_path = app_util::GetCurrentModuleDirectory();
+    VERIFY1(::PathAppend(CStrBuf(valid_path, MAX_PATH),
+                         kArgumentSavingExecutableRelativePath));
+  }
+
+  static CString valid_path;
+};
+
+CString RepairGoopdateTest::valid_path;
+
+TEST_F(RepairGoopdateTest, LaunchRepairFileElevated_UserInstance) {
+  HRESULT hr = E_FAIL;
+  EXPECT_FALSE(LaunchRepairFileElevated(false, valid_path, _T("/update"), &hr));
+  EXPECT_SUCCEEDED(hr);
+}
+
+// This test only runs on pre-Windows Vista OSes.
+TEST_F(RepairGoopdateTest, LaunchRepairFileElevated_MachineInstancePreVista) {
+  if (!vista_util::IsVistaOrLater()) {
+    HRESULT hr = E_FAIL;
+    EXPECT_FALSE(LaunchRepairFileElevated(true, valid_path, _T(""), &hr));
+    EXPECT_SUCCEEDED(hr);
+  }
+}
+
+// This test only runs on Windows Vista and later OSes.
+TEST_F(RepairGoopdateTest,
+       LaunchRepairFileElevated_MachineInstanceVistaWithMsiInstalledValidFile) {
+  if (!vista_util::IsVistaOrLater()) {
+    std::wcout << _T("\tThis test did not run because it requires Windows ")
+                  _T("Vista or later.") << std::endl;
+    return;
+  }
+
+  const TCHAR kArgs[] = _T("/update");
+  CString saved_arguments_file_path =
+      _T("%PROGRAMFILES%\\Google\\Update\\saved_arguments.txt");
+  EXPECT_SUCCEEDED(ExpandStringWithSpecialFolders(&saved_arguments_file_path));
+
+  ::DeleteFile(saved_arguments_file_path);
+
+  bool is_msi_installed = IsMsiHelperInstalled();
+
+  if (vista_util::IsUserAdmin() || is_msi_installed) {
+    if (vista_util::IsUserAdmin()) {
+      EXPECT_FALSE(File::Exists(saved_arguments_file_path));
+    }
+
+    InstallMsi();
+
+    // Verify that no patch is installed.
+    EXPECT_TRUE(RegKey::HasNativeKey(kMsiProductPatchesKey));
+    RegKey product_patches_key;
+    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,
+                                              KEY_READ | KEY_WOW64_64KEY));
+    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());
+
+    HRESULT hr = E_FAIL;
+    EXPECT_TRUE(LaunchRepairFileElevated(true, valid_path, kArgs, &hr));
+    EXPECT_SUCCEEDED(hr);
+
+    // Verify that patch was uninstalled.
+    // GetSubkeyCount fails if we don't re-open the key.
+    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,
+                                              KEY_READ | KEY_WOW64_64KEY));
+    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());
+
+    bool is_found = false;
+    for (int tries = 0; tries < 100 && !is_found; ++tries) {
+      ::Sleep(50);
+      is_found = File::Exists(saved_arguments_file_path);
+    }
+    ASSERT_TRUE(is_found);
+
+    scoped_hfile file;
+    for (int tries = 0; tries < 100 && !valid(file); ++tries) {
+      ::Sleep(50);
+      reset(file, ::CreateFile(saved_arguments_file_path,
+                               GENERIC_READ,
+                               0,                        // do not share
+                               NULL,                     // default security
+                               OPEN_EXISTING,            // existing file only
+                               FILE_ATTRIBUTE_NORMAL,
+                               NULL));                   // no template
+    }
+    ASSERT_TRUE(valid(file));
+
+    const int kBufferLen = 50;
+    TCHAR buffer[kBufferLen + 1] = {0};
+    DWORD bytes_read = 0;
+
+    EXPECT_TRUE(::ReadFile(get(file),
+                           buffer,
+                           kBufferLen * sizeof(TCHAR),
+                           &bytes_read,
+                           NULL));
+
+    EXPECT_EQ(0, bytes_read % sizeof(TCHAR));
+    buffer[bytes_read / sizeof(TCHAR)] = _T('\0');
+    EXPECT_STREQ(kArgs, buffer);
+
+    reset(file);
+
+    BOOL succeeded = ::DeleteFile(saved_arguments_file_path);
+    if (vista_util::IsUserAdmin()) {
+      EXPECT_TRUE(succeeded);
+    }
+
+    RemoveMsi();
+  } else {
+    const bool expected_file_exists = File::Exists(saved_arguments_file_path);
+    HRESULT hr = E_FAIL;
+    EXPECT_FALSE(LaunchRepairFileElevated(true, valid_path, kArgs, &hr));
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND), hr);
+
+    // We can't force the file to be deleted, so make sure it wasn't created
+    // or deleted by the above method.
+    EXPECT_EQ(expected_file_exists, File::Exists(saved_arguments_file_path));
+  }
+}
+
+// This test only runs on Windows Vista and later OSes.
+// The MSP to runs, but fails because the specified file (the unit tests)
+// is not a valid repair file.
+TEST_F(RepairGoopdateTest,
+       LaunchRepairFileElevated_MachineInstanceVistaWithMsiInstalledBadFile) {
+  if (!vista_util::IsVistaOrLater()) {
+    std::wcout << _T("\tThis test did not run because it requires Windows ")
+                  _T("Vista or later.") << std::endl;
+    return;
+  }
+
+  if (vista_util::IsUserAdmin() || IsMsiHelperInstalled()) {
+    InstallMsi();
+
+    // Verify that no patch is installed.
+    EXPECT_TRUE(RegKey::HasNativeKey(kMsiProductPatchesKey));
+    RegKey product_patches_key;
+    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,
+                                              KEY_READ | KEY_WOW64_64KEY));
+    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());
+
+    HRESULT hr = E_FAIL;
+    EXPECT_FALSE(LaunchRepairFileElevated(true,
+                                          app_util::GetCurrentModulePath(),
+                                          _T("/update"),
+                                          &hr));
+    EXPECT_EQ(TRUST_E_NOSIGNATURE, hr);
+
+    // Verify that patch was uninstalled.
+    // GetSubkeyCount fails if we don't re-open the key.
+    EXPECT_SUCCEEDED(product_patches_key.Open(kMsiProductPatchesKey,
+                                              KEY_READ | KEY_WOW64_64KEY));
+    EXPECT_EQ(0, product_patches_key.GetSubkeyCount());
+
+    RemoveMsi();
+  } else {
+    HRESULT hr = E_FAIL;
+    EXPECT_FALSE(LaunchRepairFileElevated(true,
+                                          app_util::GetCurrentModulePath(),
+                                          _T("/update"),
+                                          &hr));
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND), hr);
+  }
+}
+
+// This test only runs on Windows Vista and later OSes.
+TEST_F(RepairGoopdateTest,
+       LaunchRepairFileElevated_MachineInstanceVistaWithoutMsiInstalled) {
+  if (!vista_util::IsVistaOrLater()) {
+    std::wcout << _T("\tThis test did not run because it requires Windows ")
+                  _T("Vista or later.") << std::endl;
+    return;
+  }
+
+  if (vista_util::IsUserAdmin()) {
+    RemoveMsi();
+  } else if (IsMsiHelperInstalled()) {
+    std::wcout << _T("\tThis test did not run because the user is not an ")
+                  _T("admin and the MSI is already installed.") << std::endl;
+    return;
+  }
+  // else the user is not an admin but the MSI is not installed, so continue.
+
+  HRESULT hr = E_FAIL;
+  EXPECT_FALSE(LaunchRepairFileElevated(true, valid_path, _T("/update"), &hr));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_PATCH_TARGET_NOT_FOUND), hr);
+}
+
+}  // namespace omaha
diff --git a/service/build.scons b/service/build.scons
index fdb1c56..7ba41a6 100644
--- a/service/build.scons
+++ b/service/build.scons
@@ -1,33 +1,33 @@
-# Copyright 2008-2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-# Create a local clone, so the parent environment is

-# unaffected by changes made here.

-local_env = env.Clone()

-

-local_env.Append(

-    CPPPATH = [

-        '$OBJ_ROOT',    # Needed for generated files.

-        ],

-)

-

-inputs = [

-    'service_main.cc',

-    ]

-

-# Build these into a library.

-local_env.ComponentLibrary('service', inputs)

+# Copyright 2008-2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+# Create a local clone, so the parent environment is
+# unaffected by changes made here.
+local_env = env.Clone()
+
+local_env.Append(
+    CPPPATH = [
+        '$OBJ_ROOT',    # Needed for generated files.
+        ],
+)
+
+inputs = [
+    'service_main.cc',
+    ]
+
+# Build these into a library.
+local_env.ComponentLibrary('service', inputs)
diff --git a/service/service_main.cc b/service/service_main.cc
index 0705af3..1a1d0fe 100644
--- a/service/service_main.cc
+++ b/service/service_main.cc
@@ -1,454 +1,454 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The service can be started in one of two modes:

-//   * As a regular service, typically at system startup.

-//   * As a COM service, typically by an Omaha client using IGoogleUpdateCore.

-// The COM case is distinguished from the regular service case by registering a

-// ServiceParameters command line in the AppID registration.

-//

-// In all cases, the service initializes COM, and allows for IGoogleUpdateCore

-// clients to connect to the service. In the regular service case, the service

-// shuts down after a small idle check timeout, provided that there are no COM

-// clients connected. In the COM server case, and in the case where there are

-// COM clients connected in the regular service case, the service will shut down

-// when the last client disconnects.

-//

-// To be exact, the service will initiate shutdown in all cases when the ATL

-// module count drops to zero.

-//

-// ATL does not allow for directly reusing the delayed COM shutdown mechanism

-// available for Local servers. The assumption likely being that services run

-// forever. Since we do not want our service to run forever, we override some

-// of the functions to get the same effect.

-

-

-#include "omaha/service/service_main.h"

-

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/queue_timer.h"

-#include "omaha/core/google_update_core.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/goopdate_utils.h"

-

-namespace omaha {

-

-_ATL_OBJMAP_ENTRY ServiceModule::object_map_[] = {

-  OBJECT_ENTRY(__uuidof(GoogleUpdateCoreClass), GoogleUpdateCore)

-END_OBJECT_MAP()

-

-ServiceModule::ServiceModule()

-    : timer_queue_(NULL),

-      service_thread_(NULL),

-      is_service_com_server_(false) {

-  SERVICE_LOG(L1, (_T("[ServiceModule::ServiceModule]")));

-  _tcscpy(m_szServiceName, ConfigManager::GetCurrentServiceName());

-}

-

-ServiceModule::~ServiceModule() {

-  SERVICE_LOG(L1, (_T("[ServiceModule::~ServiceModule]")));

-  ASSERT1(!service_thread_);

-  ASSERT1(!timer_queue_);

-  ASSERT1(!idle_check_timer_.get());

-

-  // ServiceModule is typically created on the stack. We therefore reset the

-  // global ATL Module to NULL when ServiceModule is destroyed.

-  _pAtlModule = NULL;

-}

-

-// Security descriptor for the Service's CoInitializeSecurity

-void GetCOMSecDesc(CSecurityDesc* security_descriptor) {

-  security_descriptor->SetOwner(Sids::Admins());

-  security_descriptor->SetGroup(Sids::Admins());

-  CDacl dacl;

-  dacl.AddAllowedAce(Sids::System(), COM_RIGHTS_EXECUTE);

-  dacl.AddAllowedAce(Sids::Admins(), COM_RIGHTS_EXECUTE);

-  dacl.AddAllowedAce(Sids::Interactive(), COM_RIGHTS_EXECUTE);

-  security_descriptor->SetDacl(dacl);

-  security_descriptor->MakeAbsolute();

-}

-

-HRESULT ServiceModule::InitializeSecurity() throw() {

-  SERVICE_LOG(L3, (_T("[ServiceModule::InitializeSecurity]")));

-

-  CSecurityDesc security_descriptor;

-  GetCOMSecDesc(&security_descriptor);

-  HRESULT hr = ::CoInitializeSecurity(

-      const_cast<SECURITY_DESCRIPTOR*>(

-          security_descriptor.GetPSECURITY_DESCRIPTOR()),

-      -1,

-      NULL,

-      NULL,

-      RPC_C_AUTHN_LEVEL_PKT_PRIVACY,

-      RPC_C_IMP_LEVEL_IDENTIFY,

-      NULL,

-      EOAC_DYNAMIC_CLOAKING | EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL,

-      NULL);

-  ASSERT(SUCCEEDED(hr), (_T("[ServiceModule::InitializeSecurity][0x%x]"), hr));

-  return hr;

-}

-

-void ServiceModule::ServiceMain(DWORD argc, LPTSTR* argv) throw() {

-  ASSERT1(argc <= 2);

-  is_service_com_server_ =

-      argc == 2 && !CString(argv[1]).CompareNoCase(kCmdLineServiceComServer);

-  SERVICE_LOG(L3, (_T("[ServiceMain][is_service_com_server_][%d]"),

-                   is_service_com_server_));

-  Base::ServiceMain(argc, argv);

-}

-

-HRESULT ServiceModule::RegisterClassObjects(DWORD class_context,

-                                            DWORD flags) throw() {

-  SERVICE_LOG(L3, (_T("[ServiceModule::RegisterClassObjects]")));

-  for (_ATL_OBJMAP_ENTRY* objmap_entry = object_map_;

-       objmap_entry->pclsid != NULL;

-       objmap_entry++) {

-    HRESULT hr = objmap_entry->RegisterClassObject(class_context, flags);

-    if (FAILED(hr)) {

-      SERVICE_LOG(LE, (_T("[RegisterClassObject failed][%s][0x%x]"),

-                       GuidToString(*objmap_entry->pclsid), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT ServiceModule::RevokeClassObjects() throw() {

-  SERVICE_LOG(L3, (_T("[ServiceModule::RevokeClassObjects]")));

-  for (_ATL_OBJMAP_ENTRY* objmap_entry = object_map_;

-       objmap_entry->pclsid != NULL;

-       objmap_entry++) {

-    HRESULT hr = objmap_entry->RevokeClassObject();

-    if (FAILED(hr)) {

-      SERVICE_LOG(LE, (_T("[RevokeClassObject failed][%s][0x%x]"),

-                       GuidToString(*objmap_entry->pclsid), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT ServiceModule::RegisterServer(BOOL, const CLSID*) throw() {

-  SERVICE_LOG(L3, (_T("[ServiceModule::RegisterServer]")));

-  for (_ATL_OBJMAP_ENTRY* objmap_entry = object_map_;

-       objmap_entry->pclsid != NULL;

-       objmap_entry++) {

-    HRESULT hr = objmap_entry->pfnUpdateRegistry(TRUE);

-    if (FAILED(hr)) {

-      SERVICE_LOG(LE, (_T("[pfnUpdateRegistry failed][%s][0x%x]"),

-                       GuidToString(*objmap_entry->pclsid), hr));

-      return hr;

-    }

-

-    hr = AtlRegisterClassCategoriesHelper(*objmap_entry->pclsid,

-                                          objmap_entry->pfnGetCategoryMap(),

-                                          TRUE);

-    if (FAILED(hr)) {

-      SERVICE_LOG(LE, (_T("[AtlRegisterClassCategoriesHelper fail][%s][0x%x]"),

-                       GuidToString(*objmap_entry->pclsid), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT ServiceModule::UnregisterServer(BOOL, const CLSID*) throw() {

-  SERVICE_LOG(L3, (_T("[ServiceModule::UnregisterServer]")));

-  for (_ATL_OBJMAP_ENTRY* objmap_entry = object_map_;

-       objmap_entry->pclsid != NULL;

-       objmap_entry++) {

-    HRESULT hr = AtlRegisterClassCategoriesHelper(*objmap_entry->pclsid,

-                     objmap_entry->pfnGetCategoryMap(),

-                     FALSE);

-    if (FAILED(hr)) {

-      SERVICE_LOG(LE, (_T("[AtlRegisterClassCategoriesHelper fail][%s][0x%x]"),

-                       GuidToString(*objmap_entry->pclsid), hr));

-      return hr;

-    }

-

-    hr = objmap_entry->pfnUpdateRegistry(FALSE);

-    if (FAILED(hr)) {

-      SERVICE_LOG(LE, (_T("[pfnUpdateRegistry failed][%s][0x%x]"),

-                       GuidToString(*objmap_entry->pclsid), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT ServiceModule::RegisterCOMService() {

-  SERVICE_LOG(L3, (_T("[ServiceModule::RegisterCOMService]")));

-  HRESULT hr = UpdateRegistryAppId(TRUE);

-  if (FAILED(hr)) {

-    SERVICE_LOG(LE, (_T("[UpdateRegistryAppId failed][0x%x]"), hr));

-    return hr;

-  }

-

-  RegKey key_app_id;

-  hr = key_app_id.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE);

-  if (FAILED(hr)) {

-    SERVICE_LOG(LE, (_T("[Could not open HKLM\\AppID][0x%x]"), hr));

-    return hr;

-  }

-

-  RegKey key;

-  hr = key.Create(key_app_id.Key(), GetAppIdT());

-  if (FAILED(hr)) {

-    SERVICE_LOG(LE, (_T("[Fail open HKLM\\AppID\\%s][0x%x]"), GetAppId(), hr));

-    return hr;

-  }

-

-  // m_szServiceName is set in the constructor.

-  hr = key.SetValue(_T("LocalService"), m_szServiceName);

-  if (FAILED(hr)) {

-    SERVICE_LOG(LE, (_T("[Could not set LocalService value][0x%x]"), hr));

-    return hr;

-  }

-

-  // The SCM will pass this switch to ServiceMain() during COM activation.

-  hr = key.SetValue(_T("ServiceParameters"), kCmdLineServiceComServer);

-  if (FAILED(hr)) {

-    SERVICE_LOG(LE, (_T("[Could not set ServiceParameters value][0x%x]"), hr));

-    return hr;

-  }

-

-  return RegisterServer(FALSE);

-}

-

-HRESULT ServiceModule::UnregisterCOMService() {

-  SERVICE_LOG(L3, (_T("[ServiceModule::UnregisterCOMService]")));

-  HRESULT hr = UnregisterServer(FALSE);

-  if (FAILED(hr)) {

-    SERVICE_LOG(LE, (_T("[UnregisterServer failed][0x%x]"), hr));

-    return hr;

-  }

-

-  return UpdateRegistryAppId(FALSE);

-}

-

-HRESULT ServiceModule::PreMessageLoop(int show_cmd) {

-  SERVICE_LOG(L1, (_T("[ServiceModule::PreMessageLoop]")));

-

-  m_dwThreadID = ::GetCurrentThreadId();

-  // Use the delayed monitor thread COM shutdown mechanism.

-  m_bDelayShutdown = true;

-  service_thread_ = ::OpenThread(SYNCHRONIZE, false, m_dwThreadID);

-

-  // Initialize COM, COM security, register COM class objects.

-  HRESULT hr = Base::PreMessageLoop(show_cmd);

-  ASSERT(SUCCEEDED(hr), (_T("[Base::PreMessageLoop failed][0x%x]"), hr));

-  if (is_service_com_server_) {

-    SERVICE_LOG(L3, (_T("[Service in COM server mode.]")));

-    return hr;

-  }

-

-  // This is the regular service case. Increment the ATL module count. Run an

-  // idle timer, at the end of which the module count is decremented. The

-  // service will exit if the module count drops to zero.

-  Lock();

-  VERIFY1(SUCCEEDED(StartIdleCheckTimer()));

-

-  SERVICE_LOG(L1, (_T("[Starting Google Update core...]")));

-  CommandLineBuilder builder(COMMANDLINE_MODE_CORE);

-  CString args = builder.GetCommandLineArgs();

-  hr = goopdate_utils::StartGoogleUpdateWithArgs(true, args, NULL);

-  if (FAILED(hr)) {

-    SERVICE_LOG(LE, (_T("[Starting Google Update failed][0x%08x]"), hr));

-  }

-

-  return S_OK;

-}

-

-HRESULT ServiceModule::PostMessageLoop() {

-  SERVICE_LOG(L1, (_T("[ServiceModule::PostMessageLoop]")));

-  if (!is_service_com_server_) {

-    VERIFY1(SUCCEEDED(StopIdleCheckTimer()));

-  }

-

-  return Base::PostMessageLoop();

-}

-

-int ServiceModule::Main(int show_cmd) {

-  if (CAtlBaseModule::m_bInitFailed) {

-    SERVICE_LOG(LE, (_T("[CAtlBaseModule init failed]")));

-    return -1;

-  }

-  HRESULT hr = Start(show_cmd);

-  return static_cast<int>(hr);

-}

-

-// When ServiceModule::Start executes, it blocks on StartServiceCtrlDispatcher.

-// Internally, the SCM creates a service thread which starts executing the code

-// specified by the SERVICE_TABLE_ENTRY. The ATL code then calls PreMessageLoop

-// and PostMessageLoop on this thread. When the service stops, the execution

-// flow returns from StartServiceCtrlDispatcher and the main thread blocks

-// waiting on the service thread to exit.

-// Before synchronizing the main thread and the service thread, a race condition

-// resulted in http://b/1134747.

-HRESULT ServiceModule::Start(int show_cmd) {

-  SERVICE_LOG(L1, (_T("[ServiceModule::Start]")));

-  UNREFERENCED_PARAMETER(show_cmd);

-

-  SERVICE_TABLE_ENTRY st[] = {

-    { m_szServiceName, Base::_ServiceMain },

-    { NULL, NULL }

-  };

-

-  m_status.dwWin32ExitCode = 0;

-  if (!::StartServiceCtrlDispatcher(st)) {

-    m_status.dwWin32ExitCode = ::GetLastError();

-  }

-

-  if (service_thread_) {

-    DWORD result = ::WaitForSingleObject(service_thread_, kShutdownIntervalMs);

-    ASSERT1(result == WAIT_OBJECT_0);

-    ::CloseHandle(service_thread_);

-    service_thread_ = NULL;

-  }

-

-  return m_status.dwWin32ExitCode;

-}

-

-HRESULT ServiceModule::StartIdleCheckTimer() {

-  SERVICE_LOG(L1, (_T("[ServiceModule::StartIdleCheckTimer]")));

-

-  timer_queue_ = ::CreateTimerQueue();

-  if (!timer_queue_) {

-    HRESULT hr = HRESULTFromLastError();

-    SERVICE_LOG(LE, (_T("[CreateTimerQueue failed][0x%08x]"), hr));

-    return hr;

-  }

-  idle_check_timer_.reset(new QueueTimer(timer_queue_,

-                                         &ServiceModule::IdleCheckTimerCallback,

-                                         this));

-  HRESULT hr = idle_check_timer_->Start(kIdleCheckIntervalMs,

-                                        0,

-                                        WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE);

-  if (FAILED(hr)) {

-    SERVICE_LOG(LE, (_T("[idle check time failed to start][0x%08x]"), hr));

-    return hr;

-  }

-  return S_OK;

-}

-

-HRESULT ServiceModule::StopIdleCheckTimer() {

-  SERVICE_LOG(L1, (_T("[ServiceModule::StopIdleCheckTimer]")));

-  idle_check_timer_.reset();

-  if (timer_queue_) {

-    VERIFY1(::DeleteTimerQueueEx(timer_queue_, INVALID_HANDLE_VALUE));

-  }

-  timer_queue_ = NULL;

-  return S_OK;

-}

-

-

-void ServiceModule::IdleCheckTimerCallback(QueueTimer* timer) {

-  SERVICE_LOG(L1, (_T("[ServiceModule::IdleCheckTimerCallback]")));

-

-  ASSERT1(timer);

-  ASSERT1(timer->ctx());

-

-  ServiceModule* service_module = static_cast<ServiceModule*>(timer->ctx());

-  service_module->Unlock();

-}

-

-// If the module count drops to zero, Unlock() signals an event. There is a

-// monitor thread listening to this event, which initiates shutdown of the

-// service.

-// This is cloned from CAtlExeModuleT.Unlock(). The only difference is the call

-// to "OnStop()" instead of the "::PostThreadMessage(m_dwMainThreadID...".

-// OnStop() correctly sets the service status to SERVICE_STOP_PENDING, and posts

-// a WM_QUIT to the service thread.

-LONG ServiceModule::Unlock() throw() {

-  LONG retval = CComGlobalsThreadModel::Decrement(&m_nLockCnt);

-  SERVICE_LOG(L3, (_T("[ServiceModule::Unlock][%d]"), retval));

-

-  if (retval == 0) {

-    if (m_bDelayShutdown) {

-      m_bActivity = true;

-      ::SetEvent(m_hEventShutdown);

-    } else {

-      OnStop();

-    }

-  }

-

-  return retval;

-}

-

-// This is cloned from CAtlExeModuleT.MonitorShutdown(). The only difference is

-// the call to "OnStop()" instead of the "::PostThreadMessage(m_dwMainThreadID".

-void ServiceModule::MonitorShutdown() throw() {

-  SERVICE_LOG(L3, (_T("[ServiceModule::MonitorShutdown]")));

-

-  while (true) {

-    ::WaitForSingleObject(m_hEventShutdown, INFINITE);

-    SERVICE_LOG(L4, (_T("[Infinite Wait][%d][%d]"), m_bActivity, m_nLockCnt));

-

-    DWORD wait = 0;

-    do {

-      m_bActivity = false;

-      wait = ::WaitForSingleObject(m_hEventShutdown, m_dwTimeOut);

-    } while (wait == WAIT_OBJECT_0);

-

-    SERVICE_LOG(L4, (_T("[MonitorShutdown][%d][%d]"), m_bActivity, m_nLockCnt));

-    if (!m_bActivity && m_nLockCnt == 0) {

-      ::CoSuspendClassObjects();

-      if (m_nLockCnt == 0) {

-        break;

-      }

-    }

-  }

-

-  ::CloseHandle(m_hEventShutdown);

-  OnStop();

-}

-

-// This is cloned from CAtlExeModuleT.StartMonitor().

-HANDLE ServiceModule::StartMonitor() throw() {

-  SERVICE_LOG(L3, (_T("[ServiceModule::StartMonitor]")));

-  m_hEventShutdown = ::CreateEvent(NULL, false, false, NULL);

-  if (m_hEventShutdown == NULL) {

-    return NULL;

-  }

-

-  DWORD thread_id(0);

-  HANDLE monitor = ::CreateThread(NULL, 0, MonitorProc, this, 0, &thread_id);

-  if (monitor == NULL) {

-    ::CloseHandle(m_hEventShutdown);

-  }

-

-  return monitor;

-}

-

-// This is cloned from CAtlExeModuleT.MonitorProc().

-DWORD WINAPI ServiceModule::MonitorProc(void* pv) throw() {

-  SERVICE_LOG(L3, (_T("[ServiceModule::MonitorProc]")));

-  ServiceModule* service_module = static_cast<ServiceModule*>(pv);

-  ASSERT1(service_module);

-

-  service_module->MonitorShutdown();

-  return 0;

-}

-

-}  // namespace omaha

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The service can be started in one of two modes:
+//   * As a regular service, typically at system startup.
+//   * As a COM service, typically by an Omaha client using IGoogleUpdateCore.
+// The COM case is distinguished from the regular service case by registering a
+// ServiceParameters command line in the AppID registration.
+//
+// In all cases, the service initializes COM, and allows for IGoogleUpdateCore
+// clients to connect to the service. In the regular service case, the service
+// shuts down after a small idle check timeout, provided that there are no COM
+// clients connected. In the COM server case, and in the case where there are
+// COM clients connected in the regular service case, the service will shut down
+// when the last client disconnects.
+//
+// To be exact, the service will initiate shutdown in all cases when the ATL
+// module count drops to zero.
+//
+// ATL does not allow for directly reusing the delayed COM shutdown mechanism
+// available for Local servers. The assumption likely being that services run
+// forever. Since we do not want our service to run forever, we override some
+// of the functions to get the same effect.
+
+
+#include "omaha/service/service_main.h"
+
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/queue_timer.h"
+#include "omaha/core/google_update_core.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/goopdate_utils.h"
+
+namespace omaha {
+
+_ATL_OBJMAP_ENTRY ServiceModule::object_map_[] = {
+  OBJECT_ENTRY(__uuidof(GoogleUpdateCoreClass), GoogleUpdateCore)
+END_OBJECT_MAP()
+
+ServiceModule::ServiceModule()
+    : timer_queue_(NULL),
+      service_thread_(NULL),
+      is_service_com_server_(false) {
+  SERVICE_LOG(L1, (_T("[ServiceModule::ServiceModule]")));
+  _tcscpy(m_szServiceName, ConfigManager::GetCurrentServiceName());
+}
+
+ServiceModule::~ServiceModule() {
+  SERVICE_LOG(L1, (_T("[ServiceModule::~ServiceModule]")));
+  ASSERT1(!service_thread_);
+  ASSERT1(!timer_queue_);
+  ASSERT1(!idle_check_timer_.get());
+
+  // ServiceModule is typically created on the stack. We therefore reset the
+  // global ATL Module to NULL when ServiceModule is destroyed.
+  _pAtlModule = NULL;
+}
+
+// Security descriptor for the Service's CoInitializeSecurity
+void GetCOMSecDesc(CSecurityDesc* security_descriptor) {
+  security_descriptor->SetOwner(Sids::Admins());
+  security_descriptor->SetGroup(Sids::Admins());
+  CDacl dacl;
+  dacl.AddAllowedAce(Sids::System(), COM_RIGHTS_EXECUTE);
+  dacl.AddAllowedAce(Sids::Admins(), COM_RIGHTS_EXECUTE);
+  dacl.AddAllowedAce(Sids::Interactive(), COM_RIGHTS_EXECUTE);
+  security_descriptor->SetDacl(dacl);
+  security_descriptor->MakeAbsolute();
+}
+
+HRESULT ServiceModule::InitializeSecurity() throw() {
+  SERVICE_LOG(L3, (_T("[ServiceModule::InitializeSecurity]")));
+
+  CSecurityDesc security_descriptor;
+  GetCOMSecDesc(&security_descriptor);
+  HRESULT hr = ::CoInitializeSecurity(
+      const_cast<SECURITY_DESCRIPTOR*>(
+          security_descriptor.GetPSECURITY_DESCRIPTOR()),
+      -1,
+      NULL,
+      NULL,
+      RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+      RPC_C_IMP_LEVEL_IDENTIFY,
+      NULL,
+      EOAC_DYNAMIC_CLOAKING | EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL,
+      NULL);
+  ASSERT(SUCCEEDED(hr), (_T("[ServiceModule::InitializeSecurity][0x%x]"), hr));
+  return hr;
+}
+
+void ServiceModule::ServiceMain(DWORD argc, LPTSTR* argv) throw() {
+  ASSERT1(argc <= 2);
+  is_service_com_server_ =
+      argc == 2 && !CString(argv[1]).CompareNoCase(kCmdLineServiceComServer);
+  SERVICE_LOG(L3, (_T("[ServiceMain][is_service_com_server_][%d]"),
+                   is_service_com_server_));
+  Base::ServiceMain(argc, argv);
+}
+
+HRESULT ServiceModule::RegisterClassObjects(DWORD class_context,
+                                            DWORD flags) throw() {
+  SERVICE_LOG(L3, (_T("[ServiceModule::RegisterClassObjects]")));
+  for (_ATL_OBJMAP_ENTRY* objmap_entry = object_map_;
+       objmap_entry->pclsid != NULL;
+       objmap_entry++) {
+    HRESULT hr = objmap_entry->RegisterClassObject(class_context, flags);
+    if (FAILED(hr)) {
+      SERVICE_LOG(LE, (_T("[RegisterClassObject failed][%s][0x%x]"),
+                       GuidToString(*objmap_entry->pclsid), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT ServiceModule::RevokeClassObjects() throw() {
+  SERVICE_LOG(L3, (_T("[ServiceModule::RevokeClassObjects]")));
+  for (_ATL_OBJMAP_ENTRY* objmap_entry = object_map_;
+       objmap_entry->pclsid != NULL;
+       objmap_entry++) {
+    HRESULT hr = objmap_entry->RevokeClassObject();
+    if (FAILED(hr)) {
+      SERVICE_LOG(LE, (_T("[RevokeClassObject failed][%s][0x%x]"),
+                       GuidToString(*objmap_entry->pclsid), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT ServiceModule::RegisterServer(BOOL, const CLSID*) throw() {
+  SERVICE_LOG(L3, (_T("[ServiceModule::RegisterServer]")));
+  for (_ATL_OBJMAP_ENTRY* objmap_entry = object_map_;
+       objmap_entry->pclsid != NULL;
+       objmap_entry++) {
+    HRESULT hr = objmap_entry->pfnUpdateRegistry(TRUE);
+    if (FAILED(hr)) {
+      SERVICE_LOG(LE, (_T("[pfnUpdateRegistry failed][%s][0x%x]"),
+                       GuidToString(*objmap_entry->pclsid), hr));
+      return hr;
+    }
+
+    hr = AtlRegisterClassCategoriesHelper(*objmap_entry->pclsid,
+                                          objmap_entry->pfnGetCategoryMap(),
+                                          TRUE);
+    if (FAILED(hr)) {
+      SERVICE_LOG(LE, (_T("[AtlRegisterClassCategoriesHelper fail][%s][0x%x]"),
+                       GuidToString(*objmap_entry->pclsid), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT ServiceModule::UnregisterServer(BOOL, const CLSID*) throw() {
+  SERVICE_LOG(L3, (_T("[ServiceModule::UnregisterServer]")));
+  for (_ATL_OBJMAP_ENTRY* objmap_entry = object_map_;
+       objmap_entry->pclsid != NULL;
+       objmap_entry++) {
+    HRESULT hr = AtlRegisterClassCategoriesHelper(*objmap_entry->pclsid,
+                     objmap_entry->pfnGetCategoryMap(),
+                     FALSE);
+    if (FAILED(hr)) {
+      SERVICE_LOG(LE, (_T("[AtlRegisterClassCategoriesHelper fail][%s][0x%x]"),
+                       GuidToString(*objmap_entry->pclsid), hr));
+      return hr;
+    }
+
+    hr = objmap_entry->pfnUpdateRegistry(FALSE);
+    if (FAILED(hr)) {
+      SERVICE_LOG(LE, (_T("[pfnUpdateRegistry failed][%s][0x%x]"),
+                       GuidToString(*objmap_entry->pclsid), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT ServiceModule::RegisterCOMService() {
+  SERVICE_LOG(L3, (_T("[ServiceModule::RegisterCOMService]")));
+  HRESULT hr = UpdateRegistryAppId(TRUE);
+  if (FAILED(hr)) {
+    SERVICE_LOG(LE, (_T("[UpdateRegistryAppId failed][0x%x]"), hr));
+    return hr;
+  }
+
+  RegKey key_app_id;
+  hr = key_app_id.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE);
+  if (FAILED(hr)) {
+    SERVICE_LOG(LE, (_T("[Could not open HKLM\\AppID][0x%x]"), hr));
+    return hr;
+  }
+
+  RegKey key;
+  hr = key.Create(key_app_id.Key(), GetAppIdT());
+  if (FAILED(hr)) {
+    SERVICE_LOG(LE, (_T("[Fail open HKLM\\AppID\\%s][0x%x]"), GetAppId(), hr));
+    return hr;
+  }
+
+  // m_szServiceName is set in the constructor.
+  hr = key.SetValue(_T("LocalService"), m_szServiceName);
+  if (FAILED(hr)) {
+    SERVICE_LOG(LE, (_T("[Could not set LocalService value][0x%x]"), hr));
+    return hr;
+  }
+
+  // The SCM will pass this switch to ServiceMain() during COM activation.
+  hr = key.SetValue(_T("ServiceParameters"), kCmdLineServiceComServer);
+  if (FAILED(hr)) {
+    SERVICE_LOG(LE, (_T("[Could not set ServiceParameters value][0x%x]"), hr));
+    return hr;
+  }
+
+  return RegisterServer(FALSE);
+}
+
+HRESULT ServiceModule::UnregisterCOMService() {
+  SERVICE_LOG(L3, (_T("[ServiceModule::UnregisterCOMService]")));
+  HRESULT hr = UnregisterServer(FALSE);
+  if (FAILED(hr)) {
+    SERVICE_LOG(LE, (_T("[UnregisterServer failed][0x%x]"), hr));
+    return hr;
+  }
+
+  return UpdateRegistryAppId(FALSE);
+}
+
+HRESULT ServiceModule::PreMessageLoop(int show_cmd) {
+  SERVICE_LOG(L1, (_T("[ServiceModule::PreMessageLoop]")));
+
+  m_dwThreadID = ::GetCurrentThreadId();
+  // Use the delayed monitor thread COM shutdown mechanism.
+  m_bDelayShutdown = true;
+  service_thread_ = ::OpenThread(SYNCHRONIZE, false, m_dwThreadID);
+
+  // Initialize COM, COM security, register COM class objects.
+  HRESULT hr = Base::PreMessageLoop(show_cmd);
+  ASSERT(SUCCEEDED(hr), (_T("[Base::PreMessageLoop failed][0x%x]"), hr));
+  if (is_service_com_server_) {
+    SERVICE_LOG(L3, (_T("[Service in COM server mode.]")));
+    return hr;
+  }
+
+  // This is the regular service case. Increment the ATL module count. Run an
+  // idle timer, at the end of which the module count is decremented. The
+  // service will exit if the module count drops to zero.
+  Lock();
+  VERIFY1(SUCCEEDED(StartIdleCheckTimer()));
+
+  SERVICE_LOG(L1, (_T("[Starting Google Update core...]")));
+  CommandLineBuilder builder(COMMANDLINE_MODE_CORE);
+  CString args = builder.GetCommandLineArgs();
+  hr = goopdate_utils::StartGoogleUpdateWithArgs(true, args, NULL);
+  if (FAILED(hr)) {
+    SERVICE_LOG(LE, (_T("[Starting Google Update failed][0x%08x]"), hr));
+  }
+
+  return S_OK;
+}
+
+HRESULT ServiceModule::PostMessageLoop() {
+  SERVICE_LOG(L1, (_T("[ServiceModule::PostMessageLoop]")));
+  if (!is_service_com_server_) {
+    VERIFY1(SUCCEEDED(StopIdleCheckTimer()));
+  }
+
+  return Base::PostMessageLoop();
+}
+
+int ServiceModule::Main(int show_cmd) {
+  if (CAtlBaseModule::m_bInitFailed) {
+    SERVICE_LOG(LE, (_T("[CAtlBaseModule init failed]")));
+    return -1;
+  }
+  HRESULT hr = Start(show_cmd);
+  return static_cast<int>(hr);
+}
+
+// When ServiceModule::Start executes, it blocks on StartServiceCtrlDispatcher.
+// Internally, the SCM creates a service thread which starts executing the code
+// specified by the SERVICE_TABLE_ENTRY. The ATL code then calls PreMessageLoop
+// and PostMessageLoop on this thread. When the service stops, the execution
+// flow returns from StartServiceCtrlDispatcher and the main thread blocks
+// waiting on the service thread to exit.
+// Before synchronizing the main thread and the service thread, a race condition
+// resulted in http://b/1134747.
+HRESULT ServiceModule::Start(int show_cmd) {
+  SERVICE_LOG(L1, (_T("[ServiceModule::Start]")));
+  UNREFERENCED_PARAMETER(show_cmd);
+
+  SERVICE_TABLE_ENTRY st[] = {
+    { m_szServiceName, Base::_ServiceMain },
+    { NULL, NULL }
+  };
+
+  m_status.dwWin32ExitCode = 0;
+  if (!::StartServiceCtrlDispatcher(st)) {
+    m_status.dwWin32ExitCode = ::GetLastError();
+  }
+
+  if (service_thread_) {
+    DWORD result = ::WaitForSingleObject(service_thread_, kShutdownIntervalMs);
+    ASSERT1(result == WAIT_OBJECT_0);
+    ::CloseHandle(service_thread_);
+    service_thread_ = NULL;
+  }
+
+  return m_status.dwWin32ExitCode;
+}
+
+HRESULT ServiceModule::StartIdleCheckTimer() {
+  SERVICE_LOG(L1, (_T("[ServiceModule::StartIdleCheckTimer]")));
+
+  timer_queue_ = ::CreateTimerQueue();
+  if (!timer_queue_) {
+    HRESULT hr = HRESULTFromLastError();
+    SERVICE_LOG(LE, (_T("[CreateTimerQueue failed][0x%08x]"), hr));
+    return hr;
+  }
+  idle_check_timer_.reset(new QueueTimer(timer_queue_,
+                                         &ServiceModule::IdleCheckTimerCallback,
+                                         this));
+  HRESULT hr = idle_check_timer_->Start(kIdleCheckIntervalMs,
+                                        0,
+                                        WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE);
+  if (FAILED(hr)) {
+    SERVICE_LOG(LE, (_T("[idle check time failed to start][0x%08x]"), hr));
+    return hr;
+  }
+  return S_OK;
+}
+
+HRESULT ServiceModule::StopIdleCheckTimer() {
+  SERVICE_LOG(L1, (_T("[ServiceModule::StopIdleCheckTimer]")));
+  idle_check_timer_.reset();
+  if (timer_queue_) {
+    VERIFY1(::DeleteTimerQueueEx(timer_queue_, INVALID_HANDLE_VALUE));
+  }
+  timer_queue_ = NULL;
+  return S_OK;
+}
+
+
+void ServiceModule::IdleCheckTimerCallback(QueueTimer* timer) {
+  SERVICE_LOG(L1, (_T("[ServiceModule::IdleCheckTimerCallback]")));
+
+  ASSERT1(timer);
+  ASSERT1(timer->ctx());
+
+  ServiceModule* service_module = static_cast<ServiceModule*>(timer->ctx());
+  service_module->Unlock();
+}
+
+// If the module count drops to zero, Unlock() signals an event. There is a
+// monitor thread listening to this event, which initiates shutdown of the
+// service.
+// This is cloned from CAtlExeModuleT.Unlock(). The only difference is the call
+// to "OnStop()" instead of the "::PostThreadMessage(m_dwMainThreadID...".
+// OnStop() correctly sets the service status to SERVICE_STOP_PENDING, and posts
+// a WM_QUIT to the service thread.
+LONG ServiceModule::Unlock() throw() {
+  LONG retval = CComGlobalsThreadModel::Decrement(&m_nLockCnt);
+  SERVICE_LOG(L3, (_T("[ServiceModule::Unlock][%d]"), retval));
+
+  if (retval == 0) {
+    if (m_bDelayShutdown) {
+      m_bActivity = true;
+      ::SetEvent(m_hEventShutdown);
+    } else {
+      OnStop();
+    }
+  }
+
+  return retval;
+}
+
+// This is cloned from CAtlExeModuleT.MonitorShutdown(). The only difference is
+// the call to "OnStop()" instead of the "::PostThreadMessage(m_dwMainThreadID".
+void ServiceModule::MonitorShutdown() throw() {
+  SERVICE_LOG(L3, (_T("[ServiceModule::MonitorShutdown]")));
+
+  while (true) {
+    ::WaitForSingleObject(m_hEventShutdown, INFINITE);
+    SERVICE_LOG(L4, (_T("[Infinite Wait][%d][%d]"), m_bActivity, m_nLockCnt));
+
+    DWORD wait = 0;
+    do {
+      m_bActivity = false;
+      wait = ::WaitForSingleObject(m_hEventShutdown, m_dwTimeOut);
+    } while (wait == WAIT_OBJECT_0);
+
+    SERVICE_LOG(L4, (_T("[MonitorShutdown][%d][%d]"), m_bActivity, m_nLockCnt));
+    if (!m_bActivity && m_nLockCnt == 0) {
+      ::CoSuspendClassObjects();
+      if (m_nLockCnt == 0) {
+        break;
+      }
+    }
+  }
+
+  ::CloseHandle(m_hEventShutdown);
+  OnStop();
+}
+
+// This is cloned from CAtlExeModuleT.StartMonitor().
+HANDLE ServiceModule::StartMonitor() throw() {
+  SERVICE_LOG(L3, (_T("[ServiceModule::StartMonitor]")));
+  m_hEventShutdown = ::CreateEvent(NULL, false, false, NULL);
+  if (m_hEventShutdown == NULL) {
+    return NULL;
+  }
+
+  DWORD thread_id(0);
+  HANDLE monitor = ::CreateThread(NULL, 0, MonitorProc, this, 0, &thread_id);
+  if (monitor == NULL) {
+    ::CloseHandle(m_hEventShutdown);
+  }
+
+  return monitor;
+}
+
+// This is cloned from CAtlExeModuleT.MonitorProc().
+DWORD WINAPI ServiceModule::MonitorProc(void* pv) throw() {
+  SERVICE_LOG(L3, (_T("[ServiceModule::MonitorProc]")));
+  ServiceModule* service_module = static_cast<ServiceModule*>(pv);
+  ASSERT1(service_module);
+
+  service_module->MonitorShutdown();
+  return 0;
+}
+
+}  // namespace omaha
+
diff --git a/service/service_main.h b/service/service_main.h
index 7621107..3d3cf05 100644
--- a/service/service_main.h
+++ b/service/service_main.h
@@ -1,123 +1,123 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// The service is a bootstrap for a local system process to start

-// when the computer starts. The service shuts itself down in 30 seconds.

-

-#ifndef OMAHA_SERVICE_SERVICE_MAIN_H__

-#define OMAHA_SERVICE_SERVICE_MAIN_H__

-

-#include <atlbase.h>

-#include <atlcom.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "goopdate/google_update_idl.h"

-#include "omaha/common/atlregmapex.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/resource.h"

-

-namespace omaha {

-

-class QueueTimer;

-

-class ServiceModule

-    : public CAtlServiceModuleT<ServiceModule, IDS_SERVICE_NAME> {

- public:

-  typedef CAtlServiceModuleT<ServiceModule, IDS_SERVICE_NAME> Base;

-

-  #pragma warning(push)

-  // C4640: construction of local static object is not thread-safe

-  #pragma warning(disable : 4640)

-

-  DECLARE_REGISTRY_APPID_RESOURCEID_EX(IDR_GOOGLE_UPDATE_SERVICE_APPID,

-      GuidToString(__uuidof(GoogleUpdateCoreClass)))

-

-  BEGIN_REGISTRY_MAP()

-    REGMAP_RESOURCE(_T("DESCRIPTION"), IDS_SERVICE_DESCRIPTION)

-    REGMAP_ENTRY(_T("FILENAME"),       kServiceFileName)

-  END_REGISTRY_MAP()

-

-  #pragma warning(pop)

-

-  ServiceModule();

-  ~ServiceModule();

-

-  // Runs the entry point for the service.

-  int Main(int show_cmd);

-

-  // These methods are called by ATL and they must be public.

-  void ServiceMain(DWORD argc, LPTSTR* argv) throw();

-  HRESULT PreMessageLoop(int show_cmd);

-  HRESULT PostMessageLoop();

-  HRESULT InitializeSecurity() throw();

-  HRESULT RegisterClassObjects(DWORD class_context, DWORD flags) throw();

-  HRESULT RevokeClassObjects() throw();

-  HRESULT RegisterServer(BOOL reg_typelib = FALSE,

-                         const CLSID* clsid = NULL) throw();

-  HRESULT UnregisterServer(BOOL reg_typelib, const CLSID* clsid = NULL) throw();

-  LONG Unlock() throw();

-  void MonitorShutdown() throw();

-  HANDLE StartMonitor() throw();

-  static DWORD WINAPI MonitorProc(void* pv) throw();

-

-  // These methods are helpers called by setup for service registration.

-  HRESULT RegisterCOMService();

-  HRESULT UnregisterCOMService();

-

- private:

-  // Calls the service dispatcher to start the service.

-  HRESULT Start(int show_cmd);

-

-  // Creates and starts the idle check timer.

-  HRESULT StartIdleCheckTimer();

-

-  // Stops and destroys the idle check timer.

-  HRESULT StopIdleCheckTimer();

-

-  static void IdleCheckTimerCallback(QueueTimer* timer);

-

-  HANDLE timer_queue_;

-  HANDLE service_thread_;   // The service thread provided by the SCM.

-  scoped_ptr<QueueTimer> idle_check_timer_;

-  bool is_service_com_server_;  // True if the service is being invoked by COM.

-

-  // Service shut down wait timeout. The main thread waits for the service

-  // thread to exit, after the service stops.

-  static const DWORD kShutdownIntervalMs = 1000L * 30;         // 30 seconds.

-

-  // Service idle check timeout. The service shuts down itself after startup.

-  static const DWORD kIdleCheckIntervalMs = 1000L * 30;        // 30 seconds.

-

-  // Service failover constants.

-  //

-  // Time after which the SCM resets the failure count to zero if there are

-  // no failures.

-  static const DWORD kResetPeriodSec      = 60 * 60 * 24;     // 1 day.

-

-  // Time to wait before performing the specified action.

-  static const DWORD kActionDelayMs       = 1000L * 60 * 15;  // 15 minutes.

-

-  // A private object map with custom registration works best, even though this

-  // stuff is deprecated. This is because GoogleUpdate.exe has other objects

-  // defined elsewhere and we do not want to expose those from the service.

-  static _ATL_OBJMAP_ENTRY object_map_[2];

-

-  DISALLOW_EVIL_CONSTRUCTORS(ServiceModule);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_SERVICE_SERVICE_MAIN_H__

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// The service is a bootstrap for a local system process to start
+// when the computer starts. The service shuts itself down in 30 seconds.
+
+#ifndef OMAHA_SERVICE_SERVICE_MAIN_H__
+#define OMAHA_SERVICE_SERVICE_MAIN_H__
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "goopdate/google_update_idl.h"
+#include "omaha/common/atlregmapex.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/resource.h"
+
+namespace omaha {
+
+class QueueTimer;
+
+class ServiceModule
+    : public CAtlServiceModuleT<ServiceModule, IDS_SERVICE_NAME> {
+ public:
+  typedef CAtlServiceModuleT<ServiceModule, IDS_SERVICE_NAME> Base;
+
+  #pragma warning(push)
+  // C4640: construction of local static object is not thread-safe
+  #pragma warning(disable : 4640)
+
+  DECLARE_REGISTRY_APPID_RESOURCEID_EX(IDR_GOOGLE_UPDATE_SERVICE_APPID,
+      GuidToString(__uuidof(GoogleUpdateCoreClass)))
+
+  BEGIN_REGISTRY_MAP()
+    REGMAP_RESOURCE(_T("DESCRIPTION"), IDS_SERVICE_DESCRIPTION)
+    REGMAP_ENTRY(_T("FILENAME"),       kServiceFileName)
+  END_REGISTRY_MAP()
+
+  #pragma warning(pop)
+
+  ServiceModule();
+  ~ServiceModule();
+
+  // Runs the entry point for the service.
+  int Main(int show_cmd);
+
+  // These methods are called by ATL and they must be public.
+  void ServiceMain(DWORD argc, LPTSTR* argv) throw();
+  HRESULT PreMessageLoop(int show_cmd);
+  HRESULT PostMessageLoop();
+  HRESULT InitializeSecurity() throw();
+  HRESULT RegisterClassObjects(DWORD class_context, DWORD flags) throw();
+  HRESULT RevokeClassObjects() throw();
+  HRESULT RegisterServer(BOOL reg_typelib = FALSE,
+                         const CLSID* clsid = NULL) throw();
+  HRESULT UnregisterServer(BOOL reg_typelib, const CLSID* clsid = NULL) throw();
+  LONG Unlock() throw();
+  void MonitorShutdown() throw();
+  HANDLE StartMonitor() throw();
+  static DWORD WINAPI MonitorProc(void* pv) throw();
+
+  // These methods are helpers called by setup for service registration.
+  HRESULT RegisterCOMService();
+  HRESULT UnregisterCOMService();
+
+ private:
+  // Calls the service dispatcher to start the service.
+  HRESULT Start(int show_cmd);
+
+  // Creates and starts the idle check timer.
+  HRESULT StartIdleCheckTimer();
+
+  // Stops and destroys the idle check timer.
+  HRESULT StopIdleCheckTimer();
+
+  static void IdleCheckTimerCallback(QueueTimer* timer);
+
+  HANDLE timer_queue_;
+  HANDLE service_thread_;   // The service thread provided by the SCM.
+  scoped_ptr<QueueTimer> idle_check_timer_;
+  bool is_service_com_server_;  // True if the service is being invoked by COM.
+
+  // Service shut down wait timeout. The main thread waits for the service
+  // thread to exit, after the service stops.
+  static const DWORD kShutdownIntervalMs = 1000L * 30;         // 30 seconds.
+
+  // Service idle check timeout. The service shuts down itself after startup.
+  static const DWORD kIdleCheckIntervalMs = 1000L * 30;        // 30 seconds.
+
+  // Service failover constants.
+  //
+  // Time after which the SCM resets the failure count to zero if there are
+  // no failures.
+  static const DWORD kResetPeriodSec      = 60 * 60 * 24;     // 1 day.
+
+  // Time to wait before performing the specified action.
+  static const DWORD kActionDelayMs       = 1000L * 60 * 15;  // 15 minutes.
+
+  // A private object map with custom registration works best, even though this
+  // stuff is deprecated. This is because GoogleUpdate.exe has other objects
+  // defined elsewhere and we do not want to expose those from the service.
+  static _ATL_OBJMAP_ENTRY object_map_[2];
+
+  DISALLOW_EVIL_CONSTRUCTORS(ServiceModule);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_SERVICE_SERVICE_MAIN_H__
+
diff --git a/setup/build.scons b/setup/build.scons
index a26d7e9..b6f12da 100644
--- a/setup/build.scons
+++ b/setup/build.scons
@@ -1,35 +1,35 @@
-# Copyright 2008-2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-inputs = [

-    'setup.cc',

-    'setup_files.cc',

-    'setup_google_update.cc',

-    'setup_metrics.cc',

-    'setup_service.cc',

-    ]

-

-local_env = env.Clone()

-

-# Need to look in output dir to find .h files generated by midl compiler.

-# This also allows Hammer to understand dependencies between this subdir

-# and the .idl files in the goopdate folder.

-local_env['CPPPATH'] += ['$OBJ_ROOT']

-

-

-# Build these into a static library.

-local_env.ComponentLibrary('setup', inputs)

+# Copyright 2008-2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+inputs = [
+    'setup.cc',
+    'setup_files.cc',
+    'setup_google_update.cc',
+    'setup_metrics.cc',
+    'setup_service.cc',
+    ]
+
+local_env = env.Clone()
+
+# Need to look in output dir to find .h files generated by midl compiler.
+# This also allows Hammer to understand dependencies between this subdir
+# and the .idl files in the goopdate folder.
+local_env['CPPPATH'] += ['$OBJ_ROOT']
+
+
+# Build these into a static library.
+local_env.ComponentLibrary('setup', inputs)
diff --git a/setup/msi_test_utils.cc b/setup/msi_test_utils.cc
index 3ec3586..dd2c159 100644
--- a/setup/msi_test_utils.cc
+++ b/setup/msi_test_utils.cc
@@ -1,50 +1,50 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// IsMsiHelperInstalled requires MSI version 3.0 for MsiEnumProductsEx.

-// Omaha does not require MSI 3.0.

-#ifdef _WIN32_MSI

-#if (_WIN32_MSI < 300)

-#undef _WIN32_MSI

-#define _WIN32_MSI 300

-#endif

-#else

-#define _WIN32_MSI 300

-#endif

-

-#include <windows.h>

-#include <msi.h>

-#include "omaha/common/constants.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-bool IsMsiHelperInstalled() {

-  int res = ::MsiEnumProductsEx(kHelperInstallerProductGuid,

-                                NULL,

-                                MSIINSTALLCONTEXT_MACHINE,

-                                0,

-                                NULL,

-                                NULL,

-                                NULL,

-                                NULL);

-

-  bool is_msi_installed = (ERROR_SUCCESS == res);

-  EXPECT_TRUE(is_msi_installed || ERROR_NO_MORE_ITEMS == res);

-

-  return is_msi_installed;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// IsMsiHelperInstalled requires MSI version 3.0 for MsiEnumProductsEx.
+// Omaha does not require MSI 3.0.
+#ifdef _WIN32_MSI
+#if (_WIN32_MSI < 300)
+#undef _WIN32_MSI
+#define _WIN32_MSI 300
+#endif
+#else
+#define _WIN32_MSI 300
+#endif
+
+#include <windows.h>
+#include <msi.h>
+#include "omaha/common/constants.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+bool IsMsiHelperInstalled() {
+  int res = ::MsiEnumProductsEx(kHelperInstallerProductGuid,
+                                NULL,
+                                MSIINSTALLCONTEXT_MACHINE,
+                                0,
+                                NULL,
+                                NULL,
+                                NULL,
+                                NULL);
+
+  bool is_msi_installed = (ERROR_SUCCESS == res);
+  EXPECT_TRUE(is_msi_installed || ERROR_NO_MORE_ITEMS == res);
+
+  return is_msi_installed;
+}
+
+}  // namespace omaha
diff --git a/setup/msi_test_utils.h b/setup/msi_test_utils.h
index 4cb2318..bcdf8cf 100644
--- a/setup/msi_test_utils.h
+++ b/setup/msi_test_utils.h
@@ -1,26 +1,26 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_SETUP_MSI_TEST_UTILS_H_

-#define OMAHA_SETUP_MSI_TEST_UTILS_H_

-

-namespace omaha {

-

-// Returns true if the Helper MSI is installed.

-bool IsMsiHelperInstalled();

-

-}  // namespace omaha

-

-#endif  // OMAHA_SETUP_MSI_TEST_UTILS_H_

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_SETUP_MSI_TEST_UTILS_H_
+#define OMAHA_SETUP_MSI_TEST_UTILS_H_
+
+namespace omaha {
+
+// Returns true if the Helper MSI is installed.
+bool IsMsiHelperInstalled();
+
+}  // namespace omaha
+
+#endif  // OMAHA_SETUP_MSI_TEST_UTILS_H_
diff --git a/setup/setup.cc b/setup/setup.cc
index a3ba2e6..6b4ad28 100644
--- a/setup/setup.cc
+++ b/setup/setup.cc
@@ -1,2236 +1,2236 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// This class handles the installation of Google Update when it is run with the

-// install or update switch. It is invoked when Google Update is launched from

-// the meta-installer and as part of self-update.

-//

-//

-// *** Documentation for OEM Installs ***

-//

-// A /oem install requires:

-//  * Per-machine install

-//  * Running as admin

-//  * Running in Windows audit mode (ConfigManager::IsWindowsInstalling())

-//  * Standalone installer (determined in LaunchInstalledWorker())

-//

-// If the first three conditions are met, this class writes the OemInstallTime

-// registry value, which is used by ConfigManager::IsOemInstalling() along with

-// other logic to determine whether Google Update is running in an OEM install

-// environment.

-// Other objects use IsOemInstalling() - not IsWindowsInstalling() - to

-// determine whether to run in a disabled mode for OEM factory installations.

-// For example, the core exits immediately without checking for updates or Code

-// Red events, no instances ping, and persistent IDs are not saved.

-// OemInstallTime is never cleared. The logic in IsOemInstalling() determines

-// when the system is no longer in an OEM install mode.

-

-#include "omaha/setup/setup.h"

-#include <regstr.h>

-#include <algorithm>

-#include <functional>

-#include <vector>

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/highres_timer-win32.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/path.h"

-#include "omaha/common/process.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/system.h"

-#include "omaha/common/time.h"

-#include "omaha/common/timer.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/common/xml_utils.h"

-#include "omaha/net/http_client.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/event_logger.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/stats_uploader.h"

-#include "omaha/goopdate/ui_displayed_event.h"

-#include "omaha/setup/setup_files.h"

-#include "omaha/setup/setup_google_update.h"

-#include "omaha/setup/setup_metrics.h"

-#include "omaha/setup/setup_service.h"

-

-namespace omaha {

-

-namespace {

-

-const int kVersion10 = 10;

-const int kVersion11 = 11;

-const int kVersion11MachineLock = 111;

-const int kVersion12 = 12;

-

-void GetShutdownEventAttributes(bool is_machine, NamedObjectAttributes* attr) {

-  ASSERT1(attr);

-  GetNamedObjectAttributes(kShutdownEvent, is_machine, attr);

-}

-

-// Returns the process's mode based on its command line.

-HRESULT GetProcessModeFromPid(uint32 pid, CommandLineMode* mode) {

-  ASSERT1(mode);

-

-  CString cmd_line;

-  HRESULT hr = Process::GetCommandLine(pid, &cmd_line);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[GetCommandLine failed][%u][0x%08x]"), pid, hr));

-    return hr;

-  }

-

-  CommandLineArgs args;

-  hr = ParseCommandLine(cmd_line, &args);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[ParseCommandLine failed][%u][%s][0x%08x]"),

-                   pid, cmd_line, hr));

-    return hr;

-  }

-

-  OPT_LOG(L2, (_T("[Process %u][cmd line %s][mode %u]"),

-               pid, cmd_line, args.mode));

-  *mode = args.mode;

-  return S_OK;

-}

-

-void IncrementProcessWaitFailCount(CommandLineMode mode) {

-  switch (mode) {

-    case COMMANDLINE_MODE_UNKNOWN:

-      ++metric_setup_process_wait_failed_unknown;

-      break;

-    case COMMANDLINE_MODE_NOARGS:  // Legacy install

-    case COMMANDLINE_MODE_LEGACYUI:

-    case COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF:

-      ++metric_setup_process_wait_failed_legacy;

-      break;

-    case COMMANDLINE_MODE_CORE:

-      ++metric_setup_process_wait_failed_core;

-      break;

-    case COMMANDLINE_MODE_REPORTCRASH:

-      ++metric_setup_process_wait_failed_report;

-      break;

-    case COMMANDLINE_MODE_UPDATE:

-      ++metric_setup_process_wait_failed_update;

-      break;

-    case COMMANDLINE_MODE_IG:

-      ++metric_setup_process_wait_failed_ig;

-      break;

-    case COMMANDLINE_MODE_HANDOFF_INSTALL:

-      ++metric_setup_process_wait_failed_handoff;

-      break;

-    case COMMANDLINE_MODE_UG:

-      ++metric_setup_process_wait_failed_ug;

-      break;

-    case COMMANDLINE_MODE_UA:

-      ++metric_setup_process_wait_failed_ua;

-      break;

-    case COMMANDLINE_MODE_CODE_RED_CHECK:

-      ++metric_setup_process_wait_failed_cr;

-      break;

-    case COMMANDLINE_MODE_CRASH_HANDLER:

-    case COMMANDLINE_MODE_SERVICE:

-    case COMMANDLINE_MODE_SERVICE_REGISTER:

-    case COMMANDLINE_MODE_SERVICE_UNREGISTER:

-    case COMMANDLINE_MODE_REGSERVER:

-    case COMMANDLINE_MODE_UNREGSERVER:

-    case COMMANDLINE_MODE_NETDIAGS:

-    case COMMANDLINE_MODE_CRASH:

-    case COMMANDLINE_MODE_INSTALL:

-    case COMMANDLINE_MODE_RECOVER:

-    case COMMANDLINE_MODE_WEBPLUGIN:

-    case COMMANDLINE_MODE_COMSERVER:

-    case COMMANDLINE_MODE_REGISTER_PRODUCT:

-    case COMMANDLINE_MODE_UNREGISTER_PRODUCT:

-    default:

-      ++metric_setup_process_wait_failed_other;

-      break;

-  }

-}

-

-// Returns the pids of all other GoogleUpdate.exe processes with the specified

-// argument string. Checks processes for all users that it has privileges to

-// access.

-HRESULT GetPidsWithArgsForAllUsers(const CString& args,

-                                   std::vector<uint32>* pids) {

-  ASSERT1(pids);

-

-  std::vector<CString> command_line;

-  command_line.push_back(args);

-

-  DWORD flags = EXCLUDE_CURRENT_PROCESS |

-                INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;

-  HRESULT hr = Process::FindProcesses(flags,

-                                      kGoopdateFileName,

-                                      true,

-                                      CString(),

-                                      command_line,

-                                      pids);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-const TCHAR* const kUninstallEventDesc = _T("Google Update uninstall");

-

-void WriteGoogleUpdateUninstallEvent(bool is_machine) {

-  GoogleUpdateLogEvent uninstall_event(EVENTLOG_INFORMATION_TYPE,

-                                       kUninstallEventId,

-                                       is_machine);

-  uninstall_event.set_event_desc(kUninstallEventDesc);

-  uninstall_event.WriteEvent();

-}

-

-// Returns true if the mode can be determined and pid represents a "/c" process.

-bool IsCoreProcess(uint32 pid) {

-  CommandLineMode mode(COMMANDLINE_MODE_UNKNOWN);

-  return SUCCEEDED(GetProcessModeFromPid(pid, &mode)) &&

-         COMMANDLINE_MODE_CORE == mode;

-}

-

-}  // namespace

-

-bool Setup::did_uninstall_ = false;

-

-Setup::Setup(bool is_machine, const CommandLineArgs* args)

-    : is_machine_(is_machine),

-      mode_(MODE_UNKNOWN),

-      args_(args),

-      extra_code1_(S_OK),

-      launched_offline_worker_(false) {

-  SETUP_LOG(L2, (_T("[Setup::Setup]")));

-}

-

-Setup::~Setup() {

-  SETUP_LOG(L2, (_T("[Setup::~Setup]")));

-}

-

-// Handles the elevation case, then calls DoInstall to do the real work if

-// elevation is not required.

-// If elevation is required, the method returns when the elevated instance

-// exits because there is nothing more to do in this Omaha instance.

-HRESULT Setup::Install(const CString& cmd_line) {

-  SETUP_LOG(L2, (_T("[Setup::Install][%s]"), cmd_line));

-  ASSERT1(!cmd_line.IsEmpty());

-

-  mode_ = MODE_INSTALL;

-

-  if (args_->is_oem_set) {

-    HRESULT hr = SetOemInstallState();

-    if (FAILED(hr)) {

-      return hr;

-    }

-  } else if (ConfigManager::Instance()->IsWindowsInstalling()) {

-    ASSERT(false, (_T("[In OEM Audit Mode but not doing OEM install]")));

-    return GOOPDATE_E_NON_OEM_INSTALL_IN_AUDIT_MODE;

-  }

-

-  ++metric_setup_install_total;

-  if (args_->is_install_elevated) {

-    ++metric_setup_uac_succeeded;

-  }

-

-  // If we ever support NEEDS_ADMIN_PREFERS variants, handle them here.

-  // We will also need to tell the installer how to install.

-

-  if (IsElevationRequired()) {

-    HRESULT hr = ElevateAndWait(cmd_line);

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[Setup::ElevateAndWait failed][%s][0x%08x]"),

-                    cmd_line, hr));

-    }

-    return hr;

-  }

-

-  if (vista_util::IsVistaOrLater() &&

-      !is_machine_ &&

-      vista_util::IsUserAdmin()) {

-    ++metric_setup_user_app_admin;

-  }

-

-  HRESULT hr = DoInstall();

-

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  ++metric_setup_install_succeeded;

-  return S_OK;

-}

-

-HRESULT Setup::InstallSelfSilently() {

-  SETUP_LOG(L2, (_T("[Setup::InstallSelfSilently]")));

-  ASSERT1(!IsElevationRequired());

-  ASSERT1(!args_->extra_args_str.IsEmpty());

-

-  // TODO(omaha): add metrics.

-  mode_ = MODE_SELF_INSTALL;

-

-  HRESULT hr = DoInstall();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // TODO(omaha): add metrics.

-  return S_OK;

-}

-

-HRESULT Setup::UpdateSelfSilently() {

-  SETUP_LOG(L2, (_T("[Setup::UpdateSelfSilently]")));

-  ASSERT1(!IsElevationRequired());

-  ASSERT1(args_->extra_args_str.IsEmpty());

-

-  ++metric_setup_update_self_total;

-  mode_ = MODE_SELF_UPDATE;

-

-  HRESULT hr = DoInstall();

-  if (FAILED(hr)) {

-    PersistUpdateErrorInfo(is_machine_, hr, extra_code1_, GetVersionString());

-    return hr;

-  }

-

-  ++metric_setup_update_self_succeeded;

-  return S_OK;

-}

-

-HRESULT Setup::RepairSilently() {

-  SETUP_LOG(L2, (_T("[Setup::RepairSilently]")));

-  ASSERT1(!IsElevationRequired());

-  ASSERT1(args_->extra_args_str.IsEmpty());

-

-  mode_ = MODE_REPAIR;

-

-  HRESULT hr = DoInstall();

-  if (FAILED(hr)) {

-    // Use the update failed ping for repairs too.

-    PersistUpdateErrorInfo(is_machine_, hr, extra_code1_, GetVersionString());

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// Protects all setup-related operations with:

-// * Setup Lock - Prevents other instances from installing Google Update for

-// this machine/user at the same time.

-// * Shutdown Event - Tells existing other instances and any instances that may

-// start during Setup to exit.

-// Setup-related operations do not include installation of the app.

-// Also tries to acquire the locks for Omaha 1.0 and 1.1, which are lock10 and

-// lock11, respectively.

-// Until we secure the current setup lock (bug 1076207), we return an error if

-// we are unable to acquire the legacy locks.

-// Gets the legacy locks first because we wait a lot longer for them during

-// updates and would not want to hold the setup lock all that time.

-// Legacy Setup Locks are not released until the app is installed.

-//

-// Sets the EULA as accepted when installing and /eularequired is not specified.

-// This can be done outside the locks. Setting EULA not accepted is done inside

-// the lock and process protection in DoProtectedGoogleUpdateInstall.

-HRESULT Setup::DoInstall() {

-  ASSERT1(MODE_UNKNOWN != mode_);

-  ASSERT1(!IsElevationRequired());

-

-  if (!args_->is_eula_required_set &&

-      (MODE_INSTALL == mode_ || MODE_SELF_INSTALL == mode_)) {

-    HRESULT hr = SetEulaAccepted(is_machine_);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  // Validate that key OS components are installed.

-  if (!HasXmlParser()) {

-    return GOOPDATE_E_RUNNING_INFERIOR_MSXML;

-  }

-

-  // Start the setup timer.

-  metrics_timer_.reset(new HighresTimer);

-

-  GLock lock10, lock11_user, lock11_machine, setup_lock;

-

-  // Initialize all locks.

-  if (!InitLegacySetupLocks(&lock10, &lock11_user, &lock11_machine)) {

-    SETUP_LOG(L2, (_T("[Setup::InitLegacySetupLocks failed]")));

-    return GOOPDATE_E_SETUP_LOCK_INIT_FAILED;

-  }

-  if (!InitSetupLock(is_machine_, &setup_lock)) {

-    SETUP_LOG(L2, (_T("[Setup::InitSetupLock failed]")));

-    extra_code1_ = kVersion12;

-    return GOOPDATE_E_SETUP_LOCK_INIT_FAILED;

-  }

-

-  scoped_process handoff_process;

-

-  // Attempt to acquire all locks. Acquire them in a new scope so they are

-  // automatically released by ScopeGuards when we no longer need protection.

-  {

-    HighresTimer lock_metrics_timer;

-

-    // Try to acquire the 1.0/1.1 locks to prevent these installers from

-    // running, but do not fail if not acquired because this prevents

-    // simultaneous user and machine installs because both used the same name.

-    // See bug 1145609. For simplicity, hold these locks until the function

-    // exits.

-    if (!lock10.Lock(kSetupLockWaitMs)) {

-      OPT_LOG(LW, (_T("[Failed to acquire 1.0 setup lock]")));

-    }

-

-    if (!lock11_user.Lock(kSetupLockWaitMs)) {

-      OPT_LOG(LW, (_T("[Failed to acquire 1.1 user setup lock]")));

-    }

-

-    if (is_machine_) {

-      if (!lock11_machine.Lock(kSetupLockWaitMs)) {

-        OPT_LOG(LE, (_T("[Failed to acquire 1.1 machine setup lock]")));

-        return HandleLockFailed(kVersion11MachineLock);

-      }

-    }

-    ScopeGuard lock11_machine_guard = MakeObjGuard(lock11_machine,

-                                                   &GLock::Unlock);

-    if (!is_machine_) {

-      lock11_machine_guard.Dismiss();

-    }

-

-    if (!setup_lock.Lock(kSetupLockWaitMs)) {

-      OPT_LOG(LE, (_T("[Failed to acquire setup lock]")));

-      return HandleLockFailed(kVersion12);

-    }

-    ON_SCOPE_EXIT_OBJ(setup_lock, &GLock::Unlock);

-

-    metric_setup_lock_acquire_ms.AddSample(lock_metrics_timer.GetElapsedMs());

-    SETUP_LOG(L1, (_T("[Setup Locks acquired]")));

-

-    // Do the installation.

-    HRESULT hr = DoProtectedInstall(address(handoff_process));

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[Setup::DoProtectedInstall failed][0x%08x]"), hr));

-      SETUP_LOG(L1, (_T("[Releasing Setup Lock]")));

-      return hr;

-    }

-

-    SETUP_LOG(L1, (_T("[Releasing Setup Lock]")));

-  }  // End lock protection.

-

-  if (handoff_process) {

-    ASSERT1(MODE_INSTALL == mode_);

-

-    // TODO(omaha): Why do we exit once the UI event is signaled? It is not

-    // related to the locks like waiting for /ig and it complicates the code.

-    HRESULT hr = WaitForHandoffWorker(get(handoff_process));

-

-    if (FAILED(hr)) {

-      if (!ShouldWaitForWorkerProcess()) {

-        // Did not wait for the second process to exit. The error may not be the

-        // exit code of the worker process. Report that the handoff failed.

-        OPT_LOG(LE, (_T("[Wait for Google Update hand off failed][0x%08x]"),

-                     hr));

-        extra_code1_ = hr;

-        return GOOPDATE_E_HANDOFF_FAILED;

-      } else {

-        return hr;

-      }

-    }

-

-    ++metric_setup_handoff_only_succeeded;

-  }

-

-  return S_OK;

-}

-

-// Sets appropriate metrics and extra_code1_ value. It then tries to determine

-// the scenario that caused this failure and returns an appropriate error.

-// The detected processes may not actually be in conflict with this one, but are

-// more than likely the cause of the lock failure.

-HRESULT Setup::HandleLockFailed(int lock_version) {

-  ++metric_setup_locks_failed;

-

-  switch (lock_version) {

-    case kVersion10:

-      ASSERT1(false);

-      extra_code1_ = kVersion10;

-      break;

-    case kVersion11:

-      extra_code1_ = kVersion11;

-      ++metric_setup_lock11_failed;

-      break;

-    case kVersion11MachineLock:

-      extra_code1_ = kVersion11MachineLock;

-      ++metric_setup_lock11_failed;

-      break;

-    case kVersion12:

-      extra_code1_ = kVersion12;

-      ++metric_setup_lock12_failed;

-      break;

-    default:

-      ASSERT1(false);

-      extra_code1_ = -1;

-      break;

-  }

-

-  Pids matching_pids;

-  CString switch_to_include;

-

-  switch_to_include.Format(_T("/%s"), kCmdLineUpdate);

-  HRESULT hr = GetPidsWithArgsForAllUsers(switch_to_include, &matching_pids);

-  if (FAILED(hr)) {

-    ASSERT1(false);

-    return GOOPDATE_E_FAILED_TO_GET_LOCK;

-  }

-  if (!matching_pids.empty()) {

-    return GOOPDATE_E_FAILED_TO_GET_LOCK_UPDATE_PROCESS_RUNNING;

-  }

-

-  switch_to_include.Format(_T("/%s"), kCmdLineInstall);

-  hr = GetPidsWithArgsForAllUsers(switch_to_include, &matching_pids);

-  if (FAILED(hr)) {

-    ASSERT1(false);

-    return GOOPDATE_E_FAILED_TO_GET_LOCK;

-  }

-  if (matching_pids.empty()) {

-    return GOOPDATE_E_FAILED_TO_GET_LOCK;

-  }

-

-  // Another /install process was found. Determine if it has the same cmd line.

-  const TCHAR* this_cmd_line = ::GetCommandLine();

-  if (!this_cmd_line) {

-    ASSERT1(false);

-    return GOOPDATE_E_FAILED_TO_GET_LOCK;

-  }

-  const CString current_cmd_line(this_cmd_line);

-  if (current_cmd_line.IsEmpty()) {

-    ASSERT1(false);

-    return GOOPDATE_E_FAILED_TO_GET_LOCK;

-  }

-

-  // Strip the directory path, which may vary, and executable name.

-  int exe_index = current_cmd_line.Find(kGoopdateFileName);

-  if (-1 == exe_index) {

-    ASSERT(false, (_T("Unable to find %s in %s"),

-                   kGoopdateFileName, current_cmd_line));

-    return GOOPDATE_E_FAILED_TO_GET_LOCK;

-  }

-  int args_start = exe_index + _tcslen(kGoopdateFileName);

-  // Support enclosed paths; increment past closing double quote.

-  if (_T('"') == current_cmd_line.GetAt(args_start)) {

-    ++args_start;

-  }

-  const int args_length = current_cmd_line.GetLength() - args_start;

-  CString current_args = current_cmd_line.Right(args_length);

-  current_args.Trim();

-

-  for (size_t i = 0; i < matching_pids.size(); ++i) {

-    CString matching_pid_cmd_line;

-    if (FAILED(Process::GetCommandLine(matching_pids[i],

-                                       &matching_pid_cmd_line))) {

-      continue;

-    }

-

-    if (-1 != matching_pid_cmd_line.Find(current_args)) {

-      // Assume that this is a match and not a subset.

-      return GOOPDATE_E_FAILED_TO_GET_LOCK_MATCHING_INSTALL_PROCESS_RUNNING;

-    }

-  }

-

-  return GOOPDATE_E_FAILED_TO_GET_LOCK_NONMATCHING_INSTALL_PROCESS_RUNNING;

-}

-

-// Assumes the necessary locks have been acquired.

-HRESULT Setup::DoProtectedInstall(HANDLE* handoff_process) {

-  SETUP_LOG(L2, (_T("[Setup::DoProtectedInstall]")));

-  ASSERT1(handoff_process);

-  ASSERT1(MODE_UNKNOWN != mode_);

-

-  SetupFiles setup_files(is_machine_);

-

-  HRESULT hr = setup_files.Init();

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[SetupFiles::Init failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (ShouldInstall(&setup_files)) {

-    ++metric_setup_do_self_install_total;

-    HRESULT hr = DoProtectedGoogleUpdateInstall(&setup_files);

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[DoProtectedGoogleUpdateInstall fail][0x%08x]"), hr));

-      // Do not return until rolling back, releasing the events and restarting

-      // the core.

-    }

-

-    if (FAILED(hr)) {

-      RollBack(&setup_files);

-    }

-

-    // We need to hold the shutdown events until phase 2 is complete.

-    // Phase 2 will release the current version's event. Here we release all

-    // shutdown events, including the one that should have already been released

-    // to be safe (i.e. in case phase 2 crashes).

-    // This will happen before the Setup Lock is released, preventing any races.

-    ReleaseShutdownEvents();

-

-    if (FAILED(hr)) {

-      // We may have shutdown an existing core. Start it again if possible.

-      // First kill running cores to prevent the stated instance from exiting

-      // because it cannot acquire the single program instance.

-      OPT_LOG(L2, (_T("[Attempting to restart existing core]")));

-

-      VERIFY1(SUCCEEDED(TerminateCoreProcesses()));

-

-      HRESULT start_hr = StartCore();

-      if (FAILED(start_hr)) {

-        SETUP_LOG(LW, (_T("[StartCore failed][0x%08x]"), start_hr));

-      }

-

-      return hr;

-    }

-

-    ++metric_setup_do_self_install_succeeded;

-    return S_OK;

-  } else if (MODE_INSTALL == mode_) {

-    // No setup was required. Launch the worker to install the app.

-    // Since we are not doing any setup in the worker, return without waiting

-    // so that we can release the Setup Lock.

-    ++metric_setup_handoff_only_total;

-

-    hr = LaunchInstalledWorker(false,   // Do not run setup phase 2.

-                               handoff_process);

-    if (SUCCEEDED(hr)) {

-      metric_setup_handoff_ms.AddSample(metrics_timer_->GetElapsedMs());

-    } else {

-      OPT_LOG(LE, (_T("[Failed to launch installed instance][0x%08x]"), hr));

-      // TODO(omaha): Consider checking for GoogleUpdate.exe in version

-      // directory in file not found case and copying it to shell location then

-      // relaunching.

-    }

-

-    // Start the core in case one is not already running. If one is already

-    // running, this one will exit quickly.

-    HRESULT start_hr = StartCore();

-    if (FAILED(start_hr)) {

-      SETUP_LOG(LW, (_T("[StartCore failed][0x%08x]"), start_hr));

-    }

-

-    return hr;

-  } else {

-    // Do not launch the worker because there is no app to install.

-    OPT_LOG(L1, (_T("[Not installing Google Update or an app]")));

-

-    // Start the core in case one is not already running. If one is already

-    // running, this one will exit quickly.

-    return StartCore();

-  }

-}

-

-// Assumes that the shell is the correct version for the existing Omaha version.

-bool Setup::ShouldInstall(SetupFiles* setup_files) {

-  SETUP_LOG(L2, (_T("[Setup::ShouldInstall]")));

-  ASSERT1(setup_files);

-

-  ++metric_setup_should_install_total;

-

-  ULONGLONG my_version = GetVersion();

-

-  const ConfigManager* cm = ConfigManager::Instance();

-  CString existing_version;

-  HRESULT hr = RegKey::GetValue(cm->registry_clients_goopdate(is_machine_),

-                                kRegValueProductVersion,

-                                &existing_version);

-  if (FAILED(hr)) {

-    OPT_LOG(L2, (_T("[fresh install]")));

-    ++metric_setup_should_install_true_fresh_install;

-    return true;

-  }

-

-  OPT_LOG(L2, (_T("[Existing version: %s][Running version: %s]"),

-               existing_version, GetVersionString()));

-  UpdateCoreNotRunningMetric(existing_version);

-

-  // If running from the official install directory for this type of install

-  // (user/machine), it is most likely a OneClick install. Do not install self.

-  if (goopdate_utils::IsRunningFromOfficialGoopdateDir(is_machine_)) {

-    ++metric_setup_should_install_false_oc;

-    return false;

-  }

-

-  if (MODE_INSTALL == mode_) {

-    ++metric_setup_subsequent_install_total;

-  }

-

-  bool should_install(false);

-

-  ULONGLONG cv = VersionFromString(existing_version);

-  if (cv > my_version) {

-    SETUP_LOG(L2, (_T("[not installing, newer version exists]")));

-    ++metric_setup_should_install_false_older;

-    should_install = false;

-  } else if (cv < my_version) {

-    SETUP_LOG(L2, (_T("[installing with local build]")));

-    ++metric_setup_should_install_true_newer;

-    should_install = true;

-  } else {

-    // Same version.

-    should_install = ShouldOverinstallSameVersion(setup_files);

-    if (should_install) {

-      ++metric_setup_should_install_true_same;

-    } else {

-      ++metric_setup_should_install_false_same;

-    }

-  }

-

-  if (MODE_INSTALL == mode_ && should_install) {

-    ++metric_setup_subsequent_install_should_install_true;

-  }

-

-  OPT_LOG(L1, (_T("[machine = %d][existing version = %s][should_install = %d]"),

-               is_machine_, existing_version, should_install));

-

-  return should_install;

-}

-

-// Checks the following:

-//  * OverInstall override.

-//  * The "installed" version in the registry equals this version.

-//    If not, this version was not fully installed even though "pv" says it is.

-//  * Files are properly installed.

-bool Setup::ShouldOverinstallSameVersion(SetupFiles* setup_files) {

-  SETUP_LOG(L2, (_T("[Setup::ShouldOverinstallSameVersion]")));

-  ASSERT1(setup_files);

-

-  const ConfigManager* cm = ConfigManager::Instance();

-

-  bool should_over_install = cm->CanOverInstall();

-  SETUP_LOG(L1, (_T("[should over install = %d]"), should_over_install));

-  if (should_over_install) {

-    SETUP_LOG(L2, (_T("[overinstalling with local build]")));

-    return true;

-  }

-

-  CString installed_version;

-  HRESULT hr = RegKey::GetValue(cm->registry_update(is_machine_),

-                                kRegValueInstalledVersion,

-                                &installed_version);

-  if (FAILED(hr) || GetVersionString() != installed_version) {

-    SETUP_LOG(L1, (_T("[installed version missing or did not match][%s]"),

-                   installed_version));

-    ++metric_setup_should_install_true_same_completion_missing;

-    return true;

-  }

-

-  if (setup_files->ShouldOverinstallSameVersion()) {

-    SETUP_LOG(L1, (_T("[files need over-install]")));

-    return true;

-  }

-

-  // TODO(omaha): Verify the current installation is complete and correct.

-  // For example, in Omaha 1, we would always set the run key to the version

-  // being installed. Now that code is in SetupGoogleUpdate, and it does not get

-  // called.

-

-  return false;

-}

-

-

-void Setup::UpdateCoreNotRunningMetric(const CString& existing_version) {

-  if (!goopdate_utils::IsGoogleUpdate2OrLater(existing_version)) {

-    return;

-  }

-

-  Pids found_core_pids;

-  HRESULT hr = FindCoreProcesses(&found_core_pids);

-  if (FAILED(hr)) {

-    ASSERT(false, (_T("[FindCoreProcesses failed][0x%08x]"), hr));

-    return;

-  }

-

-  if (found_core_pids.empty()) {

-    ++metric_setup_installed_core_not_running;

-  }

-}

-

-// When installing and /eularequired is specified, calls SetEulaNotAccepted

-// after guaranteeing that no other processes are running.

-HRESULT Setup::DoProtectedGoogleUpdateInstall(SetupFiles* setup_files) {

-  ASSERT1(setup_files);

-  SETUP_LOG(L2, (_T("[Setup::DoProtectedGoogleUpdateInstall]")));

-

-  HRESULT hr = StopGoogleUpdateAndWait();

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[StopGoogleUpdateAndWait failed][0x%08x]"), hr));

-    if (E_ACCESSDENIED == hr) {

-      return GOOPDATE_E_ACCESSDENIED_STOP_PROCESSES;

-    }

-    return hr;

-  }

-

-  VERIFY1(SUCCEEDED(ResetMetrics(is_machine_)));

-

-  if (args_->is_eula_required_set) {

-    if (MODE_INSTALL == mode_ || MODE_SELF_INSTALL == mode_) {

-      hr = SetEulaNotAccepted(is_machine_);

-      if (FAILED(hr)) {

-        return hr;

-      }

-    } else {

-      ASSERT1(false);

-    }

-  }

-

-  hr = setup_files->Install();

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[SetupFiles::Install failed][0x%08x]"), hr));

-    extra_code1_ = setup_files->extra_code1();

-    return hr;

-  }

-  ASSERT1(!setup_files->extra_code1());

-

-  scoped_event setup_complete_event;

-  VERIFY1(SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(

-      kSetupCompleteEventEnvironmentVariableName,

-      is_machine_,

-      address(setup_complete_event))));

-  // Continue on failure. We just will not be able to release the lock early.

-

-  hr = goopdate_utils::GetVerFromRegistry(is_machine_,

-                                          kGoogleUpdateAppId,

-                                          &saved_version_);

-  if (FAILED(hr)) {

-    SETUP_LOG(L3, (_T("[GetVerFromRegistry failed][0x%08x]"), hr));

-    // Continue as this is expected for first installs.

-  }

-

-  // Set the version so the constant shell will know which version to use.

-  hr = RegKey::SetValue(

-      ConfigManager::Instance()->registry_clients_goopdate(is_machine_),

-      kRegValueProductVersion,

-      GetVersionString());

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Failed to set version in registry][0x%08x]"), hr));

-    if (E_ACCESSDENIED == hr) {

-      return GOOPDATE_E_ACCESSDENIED_SETUP_REG_ACCESS;

-    }

-    return hr;

-  }

-

-  // Start the worker to run setup phase 2 and install the app.

-  scoped_process worker_process;

-  hr = LaunchInstalledWorker(true,  // Run setup phase 2.

-                             address(worker_process));

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Failed to launch installed instance][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Wait for setup to complete to ensure the Setup Lock is held though the

-  // end of setup.

-  OPT_LOG(L1, (_T("[Waiting for setup to complete]")));

-  uint32 exit_code(0);

-  hr = WaitForProcessExitOrEvent(get(worker_process),

-                                 get(setup_complete_event),

-                                 &exit_code);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Failed waiting for setup to complete][0x%08x]"), hr));

-    return hr;

-  }

-  if (exit_code) {

-    OPT_LOG(LE, (_T("[Setup exited with error][0x%08x]"), exit_code));

-    ASSERT1(FAILED(exit_code));

-

-    return exit_code;

-  }

-

-  metric_setup_install_google_update_total_ms.AddSample(

-      metrics_timer_->GetElapsedMs());

-  return S_OK;

-}

-

-void Setup::RollBack(SetupFiles* setup_files) {

-  OPT_LOG(L1, (_T("[Roll back]")));

-  ASSERT1(setup_files);

-

-  // Restore the saved version.

-  if (!saved_version_.IsEmpty()) {

-    SETUP_LOG(L1, (_T("[Rolling back version to %s]"), saved_version_));

-    ++metric_setup_rollback_version;

-

-    VERIFY1(SUCCEEDED(RegKey::SetValue(

-        ConfigManager::Instance()->registry_clients_goopdate(is_machine_),

-        kRegValueProductVersion,

-        saved_version_)));

-  }

-

-  VERIFY1(SUCCEEDED(setup_files->RollBack()));

-}

-

-// Assumes the caller is ensuring this is the only running instance of setup.

-// The original process holds the lock while it waits for this one to complete.

-HRESULT Setup::SetupGoogleUpdate() {

-  SETUP_LOG(L2, (_T("[Setup::SetupGoogleUpdate]")));

-  ASSERT1(!IsElevationRequired());

-  mode_ = MODE_PHASE2;

-

-  HighresTimer phase2_metrics_timer;

-

-  omaha::SetupGoogleUpdate setup_google_update(is_machine_, args_);

-

-  HRESULT hr = setup_google_update.FinishInstall();

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[FinishInstall failed][0x%08x]"), hr));

-

-    // We shutdown the existing core. Start a core - which one depends on where

-    // we failed - again if possible.

-    // There is a chance we have messed up the launch mechanisms and the core

-    // will not even start on reboot.

-    VERIFY1(SUCCEEDED(StartCore()));

-

-    return hr;

-  }

-

-  // Release the shutdown event, so we can start the core and do not interfere

-  // with other app installs that may be waiting on the Setup Lock.

-  NamedObjectAttributes event_attr;

-  GetShutdownEventAttributes(is_machine_, &event_attr);

-  scoped_event shutdown_event(::OpenEvent(EVENT_MODIFY_STATE,

-                                          false,

-                                          event_attr.name));

-  if (shutdown_event) {

-    VERIFY1(::ResetEvent(get(shutdown_event)));

-  } else {

-    SETUP_LOG(LW, (_T("[::OpenEvent failed][%s][%u]"),

-                  event_attr.name, ::GetLastError()));

-  }

-

-  if (is_machine_) {

-    hr = StartMachineCoreProcess();

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[StartMachineCoreProcess failed][0x%08x]"), hr));

-      return hr;

-    }

-  } else {

-    CString core_cmd_line(setup_google_update.BuildCoreProcessCommandLine());

-    hr = StartUserCoreProcess(core_cmd_line);

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[StartUserCoreProcess failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  // Setup is now complete.

-  SetSetupCompleteEvent();

-

-  metric_setup_phase2_ms.AddSample(phase2_metrics_timer.GetElapsedMs());

-  return S_OK;

-}

-

-// Stops all user/machine instances including the service, unregisters using

-// SetupGoogleUpdate, then deletes  the files using SetupFiles.

-// Does not wait for the processes to exit, except the service.

-// Protects all operations with the setup lock. If MSI is found busy, Omaha

-// won't uninstall.

-HRESULT Setup::Uninstall() {

-  OPT_LOG(L1, (_T("[Setup::Uninstall]")));

-  ASSERT1(!IsElevationRequired());

-  mode_ = MODE_UNINSTALL;

-

-  // Try to get the global setup lock; if the lock is taken, do not block

-  // waiting to uninstall; just return.

-  GLock setup_lock;

-  VERIFY1(InitSetupLock(is_machine_, &setup_lock));

-  if (!setup_lock.Lock(0)) {

-    OPT_LOG(LE, (_T("[Failed to acquire setup lock]")));

-    return E_FAIL;

-  }

-

-  return DoProtectedUninstall();

-}

-

-// Aggregates metrics regardless of whether uninstall is allowed.

-// Foces reporting of the metrics if uninstall is allowed.

-// Assumes that the current process holds the Setup Lock.

-HRESULT Setup::DoProtectedUninstall() {

-  const bool can_uninstall = CanUninstallGoogleUpdate();

-  OPT_LOG(L1, (_T("[CanUninstallGoogleUpdate returned %d]"), can_uninstall));

-  ASSERT1(!IsElevationRequired());

-

-  if (can_uninstall) {

-    HRESULT hr = AggregateAndReportMetrics(is_machine_, true);

-    VERIFY1(SUCCEEDED(hr) || GOOPDATE_E_CANNOT_USE_NETWORK == hr);

-  } else {

-    VERIFY1(SUCCEEDED(AggregateMetrics(is_machine_)));

-  }

-

-  if (!can_uninstall) {

-    return GOOPDATE_E_CANT_UNINSTALL;

-  }

-

-  if (is_machine_) {

-    HRESULT hr = SetupService::StopService();

-    if (FAILED(hr)) {

-      SETUP_LOG(LW, (_T("[SetupService::StopService failed][0x%08x]"), hr));

-      ASSERT1(HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) == hr);

-    }

-  }

-  VERIFY1(SUCCEEDED(SignalShutdownEvent()));

-

-  // TODO(omaha): Consider waiting for the Omaha processes to exit. This would

-  // need to exclude any processes, such as /ua /uninstall, that can uninstall.

-

-  // Write the event in the event log before uninstalling the program since

-  // the event contains version and language information, which are removed

-  // during the uninstall.

-  WriteGoogleUpdateUninstallEvent(is_machine_);

-

-  omaha::SetupGoogleUpdate setup_google_update(is_machine_, args_);

-  setup_google_update.Uninstall();

-

-  SetupFiles setup_files(is_machine_);

-  setup_files.Uninstall();

-

-  OPT_LOG(L1, (_T("[Uninstall complete]")));

-  did_uninstall_ = true;

-  return S_OK;

-}

-

-// Should only be called after the point where Uninstall would have been called.

-// Works correctly in the case where the Setup Lock is not held but an app is

-// being installed because it does not check the number of registered apps.

-// Either Omaha is installed or has been cleaned up.

-// Installed means Clients, ClientState, etc. sub keys exist.

-// Cleaned up may mean the Update key does not exist or some values, such as

-// mid and uid exist, but there are no subkeys.

-// The Update key should never exist without any values.

-// Does not take the Setup Lock because it is just a dbg check. It is possible

-// for the value of did_uninstall_ to be changed in another thread or for

-// another process to install or uninstall Google Update while this is running.

-void Setup::CheckInstallStateConsistency(bool is_machine) {

-  UNREFERENCED_PARAMETER(is_machine);

-#if DEBUG

-  CString key_name = ConfigManager::Instance()->registry_update(is_machine);

-  if (!RegKey::HasKey(key_name)) {

-    // Either this instance called uninstall or it is the non-elevated machine

-    // instance on Vista and later. Both cannot be true in the same instance.

-    ASSERT1(did_uninstall_ != (is_machine && !vista_util::IsUserAdmin()));

-    return;

-  }

-

-  RegKey update_key;

-  ASSERT1(SUCCEEDED(update_key.Open(key_name, KEY_READ)));

-

-  ASSERT1(0 != update_key.GetValueCount());

-

-  if (did_uninstall_) {

-    ASSERT1(0 == update_key.GetSubkeyCount());

-    ASSERT1(!update_key.HasValue(kRegValueInstalledVersion));

-    ASSERT1(!update_key.HasValue(kRegValueInstalledPath));

-  } else {

-    ASSERT1(update_key.HasSubkey(_T("Clients")));

-    ASSERT1(update_key.HasSubkey(_T("ClientState")));

-    ASSERT1(update_key.HasSubkey(_T("network")));

-    ASSERT1(update_key.HasValue(kRegValueInstalledVersion));

-    ASSERT1(update_key.HasValue(kRegValueInstalledPath));

-

-    CString installed_version;

-    ASSERT1(SUCCEEDED(update_key.GetValue(kRegValueInstalledVersion,

-                                          &installed_version)));

-    const CString state_key_name =

-      ConfigManager::Instance()->registry_client_state_goopdate(is_machine);

-    CString pv;

-    ASSERT1(SUCCEEDED(RegKey::GetValue(state_key_name,

-                                       kRegValueProductVersion,

-                                       &pv)));

-    ASSERT1(installed_version == pv);

-  }

-#endif

-}

-

-// Stops both legacy and current instances.

-// Holds the shutdown events so that other instances do not start running.

-// The caller is responsible for releasing the events.

-// Because this waiting occurs before a UI is generated, we do not want to wait

-// too long.

-HRESULT Setup::StopGoogleUpdate() {

-  OPT_LOG(L1, (_T("[Stopping other instances]")));

-

-  // In the machine install case, we should first stop the service.

-  // This means that we should not get the service as a process to wait

-  // on when the machine goopdate tries to enumerate the processes.

-  if (is_machine_) {

-    OPT_LOG(L1, (_T("[Stopping service]")));

-    HRESULT hr = SetupService::StopService();

-    if (FAILED(hr)) {

-      OPT_LOG(LE, (_T("[StopService failed][0x%08x]"), hr));

-    }

-  }

-

-  HRESULT hr = SignalLegacyShutdownEvents();

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[SignalLegacyShutdownEvents failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = SignalShutdownEvent();

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[SignalShutdownEvent failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT Setup::StopGoogleUpdateAndWait() {

-  HRESULT hr = StopGoogleUpdate();

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[StopGoogleUpdate failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  Pids pids;

-  hr = GetPidsToWaitFor(&pids);

-  if (FAILED(hr)) {

-    SETUP_LOG(LEVEL_ERROR, (_T("[GetPidsToWaitFor failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = WaitForOtherInstancesToExit(pids);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[WaitForOtherInstancesToExit failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// Signals >= 1.2.x processes to exit.

-HRESULT Setup::SignalShutdownEvent() {

-  SETUP_LOG(L1, (_T("[Setup::SignalShutdownEvent]")));

-  NamedObjectAttributes event_attr;

-  GetShutdownEventAttributes(is_machine_, &event_attr);

-

-  if (!shutdown_event_) {

-    HRESULT hr = goopdate_utils::CreateEvent(&event_attr,

-                                             address(shutdown_event_));

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[CreateEvent current failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  VERIFY1(::SetEvent(get(shutdown_event_)));

-

-  return S_OK;

-}

-

-// Signals the quiet mode events for 1.0.x (pre-i18n) and 1.1.x (i18n)

-// processes, causing them to exit.

-HRESULT Setup::SignalLegacyShutdownEvents() {

-  SETUP_LOG(L1, (_T("[Setup::SignalLegacyShutdownEvents]")));

-

-  // Signal 1.0.x (pre-i18n) processes.

-  CString sid;

-  HRESULT hr = GetAppropriateSid(&sid);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString legacy_1_0_shutdown_event_name;

-  legacy_1_0_shutdown_event_name.Format(kEventLegacyQuietModeName, sid);

-

-  hr = CreateLegacyEvent(legacy_1_0_shutdown_event_name,

-                         address(legacy_1_0_shutdown_event_));

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[CreateLegacyEvent legacy quiet mode failed][0x%08x]"),

-                  hr));

-    return hr;

-  }

-

-

-  // Signal 1.1.x (i18n) processes.

-  // 1.1 used the same event GUID in a different way.

-  CString legacy_1_1_shutdown_event_name(is_machine_ ? kOmaha11GlobalPrefix :

-                                                       kOmaha11LocalPrefix);

-  legacy_1_1_shutdown_event_name.Append(kShutdownEvent);

-

-  hr = CreateLegacyEvent(legacy_1_1_shutdown_event_name,

-                         address(legacy_1_1_shutdown_event_));

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[CreateLegacyEvent quiet mode failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  VERIFY1(::SetEvent(get(legacy_1_0_shutdown_event_)));

-  VERIFY1(::SetEvent(get(legacy_1_1_shutdown_event_)));

-

-  return S_OK;

-}

-

-// The caller is responsible for reseting the event and closing the handle.

-HRESULT Setup::CreateLegacyEvent(const CString& event_name,

-                                 HANDLE* event_handle) const {

-  ASSERT1(event_handle);

-  ASSERT1(!event_name.IsEmpty());

-  CSecurityAttributes sa;

-  if (is_machine_) {

-    // Grant access to administrators and system. This allows an admin

-    // instance to open and modify the event even if the system created it.

-    GetAdminDaclSecurityAttributes(&sa, GENERIC_ALL);

-  }

-  *event_handle = ::CreateEvent(&sa,

-                                true,   // manual reset

-                                false,  // not signaled

-                                event_name);

-

-  if (!*event_handle) {

-    DWORD error = ::GetLastError();

-    SETUP_LOG(LEVEL_ERROR, (_T("[::CreateEvent failed][%u]"), error));

-    return HRESULT_FROM_WIN32(error);

-  }

-

-  return S_OK;

-}

-

-void Setup::ReleaseShutdownEvents() {

-  VERIFY1(::ResetEvent(get(shutdown_event_)));

-  reset(shutdown_event_);

-  VERIFY1(::ResetEvent(get(legacy_1_0_shutdown_event_)));

-  reset(legacy_1_0_shutdown_event_);

-  VERIFY1(::ResetEvent(get(legacy_1_1_shutdown_event_)));

-  reset(legacy_1_1_shutdown_event_);

-}

-

-void Setup::SetSetupCompleteEvent() const {

-  scoped_event complete_event;

-  HRESULT hr = goopdate_utils::OpenUniqueEventFromEnvironment(

-      kSetupCompleteEventEnvironmentVariableName,

-      is_machine_,

-      address(complete_event));

-

-  if (FAILED(hr)) {

-    // We just will not be able to release the lock early.

-    return;

-  }

-

-  ASSERT1(complete_event);

-  VERIFY1(::SetEvent(get(complete_event)));

-}

-

-// Because this waiting can occur before a UI is generated, we do not want to

-// wait too long.

-// If a process fails to stop, its mode is stored in extra_code1_.

-// Does not return until all opened handles have been closed.

-// TODO(omaha): Add a parameter to specify the amount of time to wait to this

-// method and StopGoogleUpdateAndWait after we unify Setup and always have a UI.

-HRESULT Setup::WaitForOtherInstancesToExit(const Pids& pids) {

-  OPT_LOG(L1, (_T("[Waiting for other instances to exit]")));

-

-  // Wait for all the processes to exit.

-  std::vector<HANDLE> handles;

-  for (size_t i = 0; i < pids.size(); ++i) {

-    SETUP_LOG(L2, (_T("[Waiting for process][%u]"), pids[i]));

-

-    DWORD desired_access =

-        PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE;

-    scoped_handle handle(::OpenProcess(desired_access,

-                                       FALSE,

-                                       pids[i]));

-    if (!handle) {

-      HRESULT hr = HRESULTFromLastError();

-      SETUP_LOG(LE, (_T("[::OpenProcess failed][%u][0x%08x]"), pids[i], hr));

-      continue;

-    }

-

-    handles.push_back(release(handle));

-  }

-

-  HRESULT hr = S_OK;

-  if (!handles.empty()) {

-    SETUP_LOG(L2, (_T("[Calling ::WaitForMultipleObjects]")));

-

-    // In the /install case, there is no UI so we cannot wait too long.

-    // In other cases, we are silent or some other app is displaying a UI.

-    const int shutdown_wait_ms = IsInteractiveInstall() ?

-                                 kSetupShutdownWaitMsInteractiveNoUi :

-                                 kSetupShutdownWaitMsSilent;

-    HighresTimer metrics_timer;

-    DWORD res = ::WaitForMultipleObjects(handles.size(),

-                                         &handles.front(),

-                                         true,  // wait for all

-                                         shutdown_wait_ms);

-    metric_setup_process_wait_ms.AddSample(metrics_timer.GetElapsedMs());

-

-    SETUP_LOG(L2, (_T("[::WaitForMultipleObjects returned]")));

-    ASSERT1(WAIT_OBJECT_0 == res || WAIT_TIMEOUT == res);

-    if (WAIT_FAILED == res) {

-      DWORD error = ::GetLastError();

-      SETUP_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));

-      hr = HRESULT_FROM_WIN32(error);

-    } else if (WAIT_OBJECT_0 != res) {

-      OPT_LOG(LEVEL_ERROR, (_T("[Other GoogleUpdate.exe instances failed to ")

-                            _T("shutdown in time][%u]"), res));

-

-      extra_code1_ = COMMANDLINE_MODE_UNKNOWN;

-

-      SETUP_LOG(L2, (_T("[Listing processes that did not exit. This may be ")

-                    _T("incomplete if processes exited after ")

-                    _T("WaitForMultipleObjects returned.]")));

-      for (size_t i = 0; i < handles.size(); ++i) {

-        if (WAIT_TIMEOUT == ::WaitForSingleObject(handles[i], 0)) {

-          uint32 pid = Process::GetProcessIdFromHandle(handles[i]);

-          if (!pid) {

-            SETUP_LOG(LW, (_T(" [Process::GetProcessIdFromHandle failed][%u]"),

-                          ::GetLastError()));

-            SETUP_LOG(L2, (_T(" [Process did not exit][unknown]")));

-            continue;

-          }

-          SETUP_LOG(L2, (_T(" [Process did not exit][%u]"), pid));

-

-          CommandLineMode mode(COMMANDLINE_MODE_UNKNOWN);

-          if (SUCCEEDED(GetProcessModeFromPid(pid, &mode))) {

-            extra_code1_ = mode;

-          }

-          IncrementProcessWaitFailCount(mode);

-        }

-      }

-

-      ++metric_setup_process_wait_failed;

-      hr = GOOPDATE_E_INSTANCES_RUNNING;

-    }

-  }

-  if (SUCCEEDED(hr)) {

-    SETUP_LOG(L3, (_T("[Wait for all processes to exit succeeded]")));

-  }

-

-  // Close the handles.

-  for (size_t i = 0; i < handles.size(); ++i) {

-    if (!::CloseHandle(handles[i])) {

-      HRESULT hr = HRESULTFromLastError();

-      SETUP_LOG(LEVEL_WARNING, (_T("[CloseHandle failed][0x%08x]"), hr));

-    }

-  }

-

-  return hr;

-}

-

-// Wait for all instances of Omaha running as the current user - or SYSTEM for

-// machine installs - except "/install" instances, which should be blocked by

-// the Setup Lock, which we are holding.

-// For machine installs, also wait for instances running with ("/handoff" OR

-// "/ig") AND "needsadmin=True" running as any user. These instances are

-// installing a machine app as a non-SYSTEM user and may also cause conflicts.

-HRESULT Setup::GetPidsToWaitFor(Pids* pids) const {

-  ASSERT1(pids);

-

-  HRESULT hr = GetPidsToWaitForUsingCommandLine(pids);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  SETUP_LOG(L3, (_T("[found %d processes using cmd line]"), pids->size()));

-

-  // Remove any copies of the current PID from the list. This can happen when

-  // doing self-updates.

-  const uint32 current_pid = ::GetCurrentProcessId();

-  Pids::iterator it = std::remove(pids->begin(), pids->end(), current_pid);

-  if (pids->end() != it) {

-    SETUP_LOG(L2, (_T("[removing current PID from list of PIDs]")));

-  }

-  pids->erase(it, pids->end());

-

-  SETUP_LOG(L3, (_T("[found %d total processes to wait for]"), pids->size()));

-

-  return S_OK;

-}

-

-// Finds legacy processes to wait for based on the command line.

-HRESULT Setup::GetPidsToWaitForUsingCommandLine(Pids* pids) const {

-  ASSERT1(pids);

-

-  CString user_sid;

-  HRESULT hr = GetAppropriateSid(&user_sid);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Get all processes running as the current user/SYSTEM except those with

-  // * "/install" - must be excluded because may be waiting for the Setup Lock.

-  // * "/registerproduct" - same as for /install.

-  // * "/installelevated" OR "/ui" - legacy switches used only for machine

-  //   installs but ran as user and could cause false positives. For machine

-  //   installs, we look for these running as any user in a separate search.

-  std::vector<CString> command_lines;

-  CString switch_to_exclude;

-  switch_to_exclude.Format(_T("/%s"), kCmdLineInstall);

-  command_lines.push_back(switch_to_exclude);

-  switch_to_exclude.Format(_T("/%s"), kCmdLineRegisterProduct);

-  command_lines.push_back(switch_to_exclude);

-  switch_to_exclude.Format(_T("/%s"), kCmdLineLegacyVistaInstall);

-  command_lines.push_back(switch_to_exclude);

-  switch_to_exclude.Format(_T("/%s"), kCmdLineLegacyUi);

-  command_lines.push_back(switch_to_exclude);

-

-  DWORD flags = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |

-                EXCLUDE_CURRENT_PROCESS |

-                EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;

-  Pids found_pids;

-  hr = Process::FindProcesses(flags,

-                              kGoopdateFileName,

-                              true,

-                              user_sid,

-                              command_lines,

-                              &found_pids);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));

-    return hr;

-  }

-  for (size_t i = 0; i < found_pids.size(); ++i) {

-    pids->push_back(found_pids[i]);

-  }

-

-  // Get all processes running as any user with:

-  // * "/handoff" or "/ig" and"needsadmin=True"

-  // * "-Embedding" and running from machine install location.

-  std::vector<uint32> machine_install_worker_pids;

-  hr = goopdate_utils::GetInstallWorkerProcesses(true,

-                                                 &machine_install_worker_pids);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[GetInstallWorkerProcesses failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (is_machine_) {

-    // Add all machine install worker pids to the list of pids to wait for.

-    for (size_t i = 0; i < machine_install_worker_pids.size(); ++i) {

-      pids->push_back(machine_install_worker_pids[i]);

-    }

-  } else {

-    // Remove machine install worker pids from the list of pids to wait for.

-    for (size_t i = 0; i < machine_install_worker_pids.size(); ++i) {

-      std::vector<uint32>::iterator iter = find(pids->begin(),

-                                                pids->end(),

-                                                machine_install_worker_pids[i]);

-      if (pids->end() != iter) {

-        pids->erase(iter);

-      }

-    }

-  }

-

-  if (is_machine_) {

-    // Find legacy machine install processes that run as user. Check all users.

-    std::vector<CString> legacy_machine_command_lines;

-    CString switch_to_include;

-    switch_to_include.Format(_T("/%s"), kCmdLineLegacyVistaInstall);

-    command_lines.push_back(switch_to_include);

-    switch_to_include.Format(_T("/%s"), kCmdLineLegacyUi);

-    command_lines.push_back(switch_to_include);

-

-    DWORD flags = EXCLUDE_CURRENT_PROCESS |

-                  INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;

-    Pids found_legacy_machine_pids;

-    hr = Process::FindProcesses(flags,

-                                kGoopdateFileName,

-                                true,

-                                user_sid,

-                                legacy_machine_command_lines,

-                                &found_legacy_machine_pids);

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));

-      return hr;

-    }

-    for (size_t i = 0; i < found_legacy_machine_pids.size(); ++i) {

-      // Because we excluded these processes in the first search, we should not

-      // get any duplicates.

-      ASSERT1(found_pids.end() ==

-              std::find(found_pids.begin(),

-                        found_pids.end(),

-                        found_legacy_machine_pids[i]));

-      pids->push_back(found_legacy_machine_pids[i]);

-    }

-  }

-

-  return S_OK;

-}

-

-// On Windows Vista, an admin must be elevated in order to install a machine app

-// without elevating. On Vista, IsUserAdmin returns false unless the user is

-// elevated.

-bool Setup::IsElevationRequired() const {

-  return is_machine_ && !vista_util::IsUserAdmin();

-}

-

-// The behavior depends on the OS:

-//  1. OS >= Vista : Try to elevate - causes a UAC dialog.

-//  2. OS < Vista  : Fail with a message box.

-// We should be here only in case of initial machine installs when the user is

-// not an elevated admin.

-HRESULT Setup::ElevateAndWait(const CString& cmd_line) {

-  OPT_LOG(L1, (_T("[Elevating][%s]"), cmd_line));

-  ASSERT1(is_machine_);

-  ASSERT1(!vista_util::IsUserAdmin());

-  ASSERT1(MODE_INSTALL == mode_);

-

-  if (!IsInteractiveInstall()) {

-    return GOOPDATE_E_SILENT_INSTALL_NEEDS_ELEVATION;

-  }

-

-  if (args_->is_install_elevated) {

-    // This can happen if UAC is disabled. See http://b/1187784.

-    SETUP_LOG(LE, (_T("[Install elevated process requires elevation]")));

-    return GOOPDATE_E_INSTALL_ELEVATED_PROCESS_NEEDS_ELEVATION;

-  }

-

-  if (!vista_util::IsVistaOrLater()) {

-    // TODO(omaha): We could consider to ask for credentials here.

-    // This TODO existed in Omaha 1. How would we even do this?

-    SETUP_LOG(LE, (_T("[Non Admin trying to install admin app]")));

-    ++metric_setup_machine_app_non_admin;

-    return GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP;

-  }

-

-  CString cmd_line_elevated(GetCmdLineTail(cmd_line));

-  cmd_line_elevated.AppendFormat(_T(" /%s"), kCmdLineInstallElevated);

-

-  HRESULT hr = goopdate_utils::StartElevatedSelfWithArgsAndWait(

-      cmd_line_elevated);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Starting elevated GoogleUpdate.exe failed][%s][0x%08x]"),

-                 cmd_line, hr));

-

-    extra_code1_ = hr;

-    if (vista_util::IsUserNonElevatedAdmin()) {

-      return GOOPDATE_E_ELEVATION_FAILED_ADMIN;

-    } else {

-      return GOOPDATE_E_ELEVATION_FAILED_NON_ADMIN;

-    }

-  }

-

-  // TODO(omaha): we might have to look at the exit_code from above.

-  // Do not know what we should do in case of an error.

-

-  return S_OK;

-}

-

-HRESULT Setup::CopyOfflineFilesForGuid(const CString& app_guid,

-                                       const CString& offline_dir) {

-  SETUP_LOG(L3, (_T("[Setup::CopyOfflineFilesForGuid][%s][%s]"),

-                 app_guid, offline_dir));

-

-  CPath setup_temp_dir(app_util::GetCurrentModuleDirectory());

-

-  // Copy offline manifest into "Google\Update\Offline\{guid}.gup".

-  CString manifest_filename = app_guid + _T(".gup");

-  CString source_manifest_path = ConcatenatePath(setup_temp_dir,

-                                                 manifest_filename);

-  if (!File::Exists(source_manifest_path)) {

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-  if (!File::IsDirectory(offline_dir)) {

-    VERIFY1(SUCCEEDED(CreateDir(offline_dir, NULL)));

-  }

-  CString dest_manifest_path = ConcatenatePath(offline_dir,

-                                               manifest_filename);

-  HRESULT hr = File::Copy(source_manifest_path, dest_manifest_path, true);

-  if (FAILED(hr)) {

-    SETUP_LOG(L4, (_T("[File copy failed][%s][%s][0x%x]"),

-                   source_manifest_path, dest_manifest_path, hr));

-    return hr;

-  }

-

-  CString pattern;

-  // Find the installer file. "Installer.exe.{guid}". Only one file per guid is

-  // supported. Store "Installer.exe" in the directory

-  // "Google\Update\Offline\{guid}".

-  pattern.Format(_T("*.%s"), app_guid);

-  std::vector<CString> files;

-  hr = FindFiles(setup_temp_dir, pattern, &files);

-  if (FAILED(hr)) {

-    SETUP_LOG(L4, (_T("[FindFiles failed][0x%x]"), hr));

-    return hr;

-  }

-  if (files.empty()) {

-    SETUP_LOG(L4, (_T("[FindFiles found no files]")));

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-

-  ASSERT1(files.size() == 1);

-  ASSERT1(files[0].GetLength() > app_guid.GetLength());

-

-  CString file_path = ConcatenatePath(setup_temp_dir, files[0]);

-  CString renamed_file_name = files[0].Left(files[0].GetLength() -

-                                            app_guid.GetLength() - 1);

-  CString offline_app_dir = ConcatenatePath(offline_dir, app_guid);

-  CString new_file_path = ConcatenatePath(offline_app_dir, renamed_file_name);

-  SETUP_LOG(L4, (_T("[new_file_path][%s]"), new_file_path));

-

-  if (File::IsDirectory(offline_app_dir)) {

-    VERIFY1(SUCCEEDED(DeleteDirectoryFiles(offline_app_dir)));

-  } else {

-    hr = CreateDir(offline_app_dir, NULL);

-    if (FAILED(hr)) {

-      SETUP_LOG(L3, (_T("[CreateDir failed][%s]"), offline_app_dir));

-      return hr;

-    }

-  }

-

-  return File::Copy(file_path, new_file_path, false);

-}

-

-bool Setup::CopyOfflineFiles(const CString& offline_dir) {

-  SETUP_LOG(L3, (_T("[Setup::CopyOfflineFiles][%s]"), offline_dir));

-

-  ASSERT1(!args_->extra.apps.empty());

-  if (args_->extra.apps.empty()) {

-    return false;

-  }

-

-  for (size_t i = 0; i < args_->extra.apps.size(); ++i) {

-    const GUID& app_guid = args_->extra.apps[i].app_guid;

-    HRESULT hr = CopyOfflineFilesForGuid(GuidToString(app_guid), offline_dir);

-    if (FAILED(hr)) {

-      SETUP_LOG(L3, (_T("[CopyOfflineFilesForGuid failed][0x%x]"), hr));

-      return false;

-    }

-  }

-

-  return true;

-}

-

-// The installed worker is in the final location and can access the network to

-// provide stats and error information.

-// worker_pi can be NULL.

-// TODO(omaha): Extract the command line building and unit test it.

-// Starts the file that was just installed or the registered version of Google

-// Update depending on whether Google Update is being installed

-// (do_setup_phase_2).

-// If do_setup_phase_2 is true, assumes the new version has been set in the

-// registry.

-// SelfInstall uses UG with the /machine override because UG silently completes

-// setup without installing an app and SelfInstall may not be running as

-// LocalSystem.

-// Detects whether this is an offline install and stages the files

-// appropriately.

-// Reports errors when when offline files are not present for scenarios that

-// require offline installs.

-HRESULT Setup::LaunchInstalledWorker(bool do_setup_phase_2, HANDLE* process) {

-  SETUP_LOG(L2, (_T("[Setup::LaunchInstalledWorker]")));

-

-  bool is_offline = false;

-  CommandLineMode cmd_line_mode = COMMANDLINE_MODE_UNKNOWN;

-  if (MODE_INSTALL == mode_) {

-    // If offline binaries are found the program enters the offline mode.

-    is_offline = CopyOfflineFiles(is_machine_ ?

-        ConfigManager::Instance()->GetMachineSecureOfflineStorageDir() :

-        ConfigManager::Instance()->GetUserOfflineStorageDir());

-    cmd_line_mode = do_setup_phase_2 ? COMMANDLINE_MODE_IG :

-                                       COMMANDLINE_MODE_HANDOFF_INSTALL;

-  } else {

-    ASSERT1(!args_->is_oem_set);

-    cmd_line_mode = COMMANDLINE_MODE_UG;

-  }

-

-  CommandLineBuilder builder(cmd_line_mode);

-  if (is_offline) {

-    builder.set_is_offline_set(is_offline);

-    // If installsource is present on the command line, it will override this.

-    builder.set_install_source(kCmdLineInstallSource_Offline);

-  } else if (args_->is_oem_set) {

-    return GOOPDATE_E_OEM_WITH_ONLINE_INSTALLER;

-  } else if (args_->is_eula_required_set) {

-    return GOOPDATE_E_EULA_REQURED_WITH_ONLINE_INSTALLER;

-  }

-

-  switch (mode_) {

-    case MODE_INSTALL:

-      builder.set_is_silent_set(args_->is_silent_set);

-      builder.set_is_eula_required_set(args_->is_eula_required_set);

-      ASSERT1(!args_->extra_args_str.IsEmpty());

-      builder.set_extra_args(args_->extra_args_str);

-      builder.set_app_args(args_->app_args_str);

-      if (!args_->install_source.IsEmpty()) {

-        builder.set_install_source(args_->install_source);

-      }

-      break;

-    case MODE_SELF_UPDATE:

-      ASSERT1(do_setup_phase_2);

-      ASSERT1(args_->extra_args_str.IsEmpty());

-      break;

-    case MODE_SELF_INSTALL:

-      ASSERT1(do_setup_phase_2);

-      ASSERT1(!args_->extra_args_str.IsEmpty());

-      builder.set_is_machine_set(is_machine_);

-      break;

-    case MODE_REPAIR:

-      ASSERT1(do_setup_phase_2);

-      ASSERT1(args_->extra_args_str.IsEmpty());

-      builder.set_is_machine_set(is_machine_);

-      break;

-    case MODE_UNKNOWN:

-    case MODE_PHASE2:

-    case MODE_UNINSTALL:

-    default:

-      ASSERT1(false);

-      break;

-  }

-

-  CString cmd_line = builder.GetCommandLineArgs();

-

-  HRESULT hr = goopdate_utils::StartGoogleUpdateWithArgs(is_machine_,

-                                                         cmd_line,

-                                                         process);

-  if (FAILED(hr)) {

-    if (do_setup_phase_2) {

-      OPT_LOG(LE, (_T("[Starting Google Update failed][%s][0x%08x]"),

-                   cmd_line, hr));

-      ASSERT1(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr);

-      return hr;

-    } else {

-      OPT_LOG(LE, (_T("[Google Update hand off failed][%s][0x%08x]"),

-                   cmd_line, hr));

-      extra_code1_ = hr;

-      return GOOPDATE_E_HANDOFF_FAILED;

-    }

-  }

-

-  launched_offline_worker_ = is_offline;

-

-  return S_OK;

-}

-

-// Start the machine core process using one of the launch mechanisms.

-// We know that at least one of the service and scheduled task were installed

-// because otherwise we would have exited fatally.

-// If the service was not installed, starting it will just fail silently and we

-// will start the scheduled task.

-// do not call this method until the shutdown event has been released or the

-// process may immediately exit.

-// TODO(omaha): Provide service_hr and task_hr failures in a ping.

-HRESULT Setup::StartMachineCoreProcess() const {

-  SETUP_LOG(L3, (_T("[Setup::StartMachineCoreProcess]")));

-

-  HighresTimer metrics_timer;

-

-  // Start the service.

-  ++metric_setup_start_service_total;

-  HRESULT service_hr = SetupService::StartService();

-  if (SUCCEEDED(service_hr)) {

-    metric_setup_start_service_ms.AddSample(metrics_timer.GetElapsedMs());

-    OPT_LOG(L1, (_T("[Service started]")));

-    ++metric_setup_start_service_succeeded;

-    return S_OK;

-  }

-  metric_setup_start_service_failed_ms.AddSample(metrics_timer.GetElapsedMs());

-  OPT_LOG(LEVEL_ERROR, (_T("[Start service failed][0x%08x]"), service_hr));

-  metric_setup_start_service_error = service_hr;

-

-  // TODO(omaha): We should only skip this block when /install /silent fails

-  // and there are no other apps installed. Guarantee this somehow.

-  ++metric_setup_start_task_total;

-  const ULONGLONG start_task_start_ms = metrics_timer.GetElapsedMs();

-  HRESULT task_hr = goopdate_utils::StartGoopdateTaskCore(true);

-  if (SUCCEEDED(task_hr)) {

-    const ULONGLONG start_task_end_ms = metrics_timer.GetElapsedMs();

-    ASSERT1(start_task_end_ms >= start_task_start_ms);

-    metric_setup_start_task_ms.AddSample(

-        start_task_end_ms - start_task_start_ms);

-    OPT_LOG(L1, (_T("[run scheduled task succeeded]")));

-    ++metric_setup_start_task_succeeded;

-    return S_OK;

-  }

-  OPT_LOG(LE, (_T("[Start scheduled task failed][0x%08x]"), task_hr));

-  metric_setup_start_task_error = task_hr;

-

-  return service_hr;

-}

-

-// Start the user core process directly.

-// do not call this method until the shutdown event has been released or the

-// process may immediately exit.

-HRESULT Setup::StartUserCoreProcess(const CString& core_cmd_line) const {

-  HRESULT hr = System::ShellExecuteCommandLine(core_cmd_line, NULL, NULL);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[Could not start Google Update Core][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT Setup::FindCoreProcesses(Pids* found_core_pids) const {

-  SETUP_LOG(L3, (_T("[Setup::FindCoreProcesses]")));

-  ASSERT1(found_core_pids);

-

-  CString user_sid;

-  HRESULT hr = GetAppropriateSid(&user_sid);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  std::vector<CString> command_lines;

-  CString switch_to_include;

-  switch_to_include.Format(_T("/%s"), kCmdLineCore);

-  command_lines.push_back(switch_to_include);

-

-  DWORD flags = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |

-                EXCLUDE_CURRENT_PROCESS |

-                INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;

-  hr = Process::FindProcesses(flags,

-                              kGoopdateFileName,

-                              true,

-                              user_sid,

-                              command_lines,

-                              found_core_pids);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Remove PIDs where the command line is not actually the "/c" switch and is

-  // some other command line, such as "/cr".

-  const Pids::iterator new_end = std::remove_if(

-      found_core_pids->begin(),

-      found_core_pids->end(),

-      std::not1(std::ptr_fun(IsCoreProcess)));

-  if (new_end != found_core_pids->end()) {

-    found_core_pids->erase(new_end, found_core_pids->end());

-  }

-

-  SETUP_LOG(L2, (_T("[Core processes found][%u]"), found_core_pids->size()));

-  return S_OK;

-}

-

-// Does not try to terminate legacy processes.

-// Waits up to 500 ms for the terminated core processes to exit.

-HRESULT Setup::TerminateCoreProcesses() const {

-  SETUP_LOG(L2, (_T("[Setup::TerminateCoreProcesses]")));

-  Pids found_core_pids;

-  HRESULT hr = FindCoreProcesses(&found_core_pids);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[FindCoreProcesses failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  std::vector<HANDLE> terminated_processes;

-  for (size_t i = 0; i < found_core_pids.size(); ++i) {

-    uint32 pid = found_core_pids[i];

-

-    SETUP_LOG(L2, (_T("[Terminating core process][%u]"), pid));

-

-    HANDLE process(::OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, pid));

-    if (!process) {

-      SETUP_LOG(LW, (_T("[::OpenProcess failed][%u][%u]"),

-                     pid, ::GetLastError()));

-      continue;

-    }

-    terminated_processes.push_back(process);

-

-    if (!::TerminateProcess(process, static_cast<uint32>(-2))) {

-      SETUP_LOG(LW, (_T("[::TerminateProcess failed][%u][%u]"),

-                     pid, ::GetLastError()));

-    }

-  }

-

-  if (terminated_processes.empty()) {

-    return S_OK;

-  }

-  // Do not return until the handles have been closed.

-

-  const int kCoreTerminateWaitMs = 500;

-  DWORD res = ::WaitForMultipleObjects(terminated_processes.size(),

-                                       &terminated_processes.front(),

-                                       true,  // wait for all

-                                       kCoreTerminateWaitMs);

-  SETUP_LOG(L2, (_T("[::WaitForMultipleObjects returned]")));

-  ASSERT1(WAIT_OBJECT_0 == res || WAIT_TIMEOUT == res);

-  if (WAIT_FAILED == res) {

-    DWORD error = ::GetLastError();

-    SETUP_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));

-    hr = HRESULT_FROM_WIN32(error);

-  } else {

-    hr = HRESULT_FROM_WIN32(res);

-  }

-

-  for (size_t i = 0; i < terminated_processes.size(); ++i) {

-    VERIFY1(::CloseHandle(terminated_processes[i]));

-  }

-

-  return hr;

-}

-

-// Tries to start the core using existing launch methods if present.

-// Uses the the service registry value, scheduled task, and Run key value names

-// for this version; if the ones in the installed version are are different,

-// this method will not be able to start the core.

-HRESULT Setup::StartCore() const {

-  SETUP_LOG(L2, (_T("[Attempting to start existing core]")));

-

-  if (is_machine_) {

-    HRESULT hr = StartMachineCoreProcess();

-    if (FAILED(hr)) {

-      SETUP_LOG(LW, (_T("[StartMachineCoreProcess failed][0x%08x]"), hr));

-      return hr;

-    }

-  } else {

-    // Read the Run key entry to determine how to run the version that we

-    // believe is installed, which may not be this instance's version or even

-    // the the version in the registry if it has been over-written by us.

-    CString run_key_path = AppendRegKeyPath(USER_KEY_NAME, REGSTR_PATH_RUN);

-    RegKey key;

-    HRESULT hr = key.Open(run_key_path);

-    if (FAILED(hr)) {

-      SETUP_LOG(LW, (_T("[Failed to open Run key][%s][0x%08x]"),

-                     run_key_path, hr));

-      return hr;

-    }

-

-    CString installed_run_cmd_line;

-    hr = key.GetValue(kRunValueName, &installed_run_cmd_line);

-    if (FAILED(hr)) {

-      SETUP_LOG(LW, (_T("[Failed to get Run value][%s][0x%08x]"),

-                     kRunValueName, hr));

-      return hr;

-    }

-

-    hr = StartUserCoreProcess(installed_run_cmd_line);

-    if (FAILED(hr)) {

-      SETUP_LOG(LW, (_T("[StartUserCoreProcess failed][%s][0x%08x]"),

-                     installed_run_cmd_line, hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-// If the process exits without signaling the event, its exit code is returned.

-// Waits for the process to exit (and ignore the event) unless this is an

-// interactive install.

-// If event is NULL, waits for the process to exit.

-HRESULT Setup::WaitForProcessExitOrEvent(HANDLE process,

-                                         HANDLE event,

-                                         uint32* exit_code) const {

-  SETUP_LOG(L3, (_T("[Setup::WaitForProcessExitOrEvent]")));

-  ASSERT1(process);

-  ASSERT1(exit_code);

-  *exit_code = 0;

-

-  const bool include_event_in_wait = event && !ShouldWaitForWorkerProcess();

-  HANDLE handles[] = {process, event};

-

-  const int num_handles = arraysize(handles) - (include_event_in_wait ? 0 : 1);

-  const int kProcessSignaled = WAIT_OBJECT_0;

-  const int kEventSignaled = WAIT_OBJECT_0 + 1;

-

-  int res = ::WaitForMultipleObjects(num_handles,

-                                     handles,

-                                     false,  // wait for any one

-                                     INFINITE);

-  ASSERT1(kProcessSignaled == res ||

-          (kEventSignaled == res) && include_event_in_wait);

-  if (WAIT_FAILED == res) {

-    DWORD error = ::GetLastError();

-    SETUP_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));

-    return HRESULT_FROM_WIN32(error);

-  }

-

-  // If the process exited, get the exit code.

-  if (kProcessSignaled == res) {

-    DWORD local_exit_code = 0;

-    if (::GetExitCodeProcess(process, &local_exit_code)) {

-      SETUP_LOG(L2, (_T("[process exited][PID %u][exit code 0x%08x]"),

-                    Process::GetProcessIdFromHandle(process), local_exit_code));

-      *exit_code = local_exit_code;

-    } else {

-      DWORD error = ::GetLastError();

-      SETUP_LOG(LE, (_T("[::GetExitCodeProcess failed][%u]"), error));

-      return HRESULT_FROM_WIN32(error);

-    }

-  } else {

-    ASSERT1(kEventSignaled == res);

-    ASSERT1(2 == num_handles);

-    SETUP_LOG(L2, (_T("[event received before process exited]")));

-  }

-

-  return S_OK;

-}

-

-// Requires that the UI displayed event and

-// kUiDisplayedEventEnvironmentVariableName environment variable exist.

-HRESULT Setup::WaitForHandoffWorker(HANDLE process) const {

-  HANDLE ui_displayed_event(INVALID_HANDLE_VALUE);

-  HRESULT hr = UIDisplayedEventManager::GetEvent(is_machine_,

-                                                 &ui_displayed_event);

-  if (FAILED(hr)) {

-    // The event was created in this process, so this should always succeed.

-    ASSERT(false, (_T("OpenUniqueEventFromEnvironment failed][0x%08x]"), hr));

-    // Only wait for the process to exit.

-  }

-

-  uint32 exit_code(0);

-  hr = WaitForProcessExitOrEvent(process, ui_displayed_event, &exit_code);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[WaitForProcessExitOrEvent failed][0x%08x]"), hr));

-    return hr;

-  }

-  if (exit_code) {

-    OPT_LOG(LE, (_T("[Handoff exited with error][0x%08x]"), exit_code));

-    ASSERT1(FAILED(exit_code));

-    return exit_code;

-  }

-

-  if (ui_displayed_event &&

-      WAIT_OBJECT_0 == ::WaitForSingleObject(ui_displayed_event, 0)) {

-    metric_setup_handoff_ui_ms.AddSample(metrics_timer_->GetElapsedMs());

-  }

-

-  return S_OK;

-}

-

-// Returns Local System's SID for machine installs and the user's SID otherwise.

-HRESULT Setup::GetAppropriateSid(CString* sid) const {

-  ASSERT1(sid);

-  if (is_machine_) {

-    *sid = kLocalSystemSid;

-  } else {

-    HRESULT hr = user_info::GetCurrentUser(NULL, NULL, sid);

-    if (FAILED(hr)) {

-      SETUP_LOG(LEVEL_ERROR, (_T("[GetCurrentUser failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-bool Setup::InitSetupLock(bool is_machine, GLock* setup_lock) {

-  ASSERT1(setup_lock);

-  NamedObjectAttributes setup_lock_attr;

-  GetNamedObjectAttributes(kSetupMutex, is_machine, &setup_lock_attr);

-  return setup_lock->InitializeWithSecAttr(setup_lock_attr.name,

-                                           &setup_lock_attr.sa);

-}

-

-bool Setup::InitLegacySetupLocks(GLock* lock10,

-                                 GLock* lock11_user,

-                                 GLock* lock11_machine) {

-  ASSERT1(lock10);

-  ASSERT1(lock11_user);

-  ASSERT1(lock11_machine);

-

-  // Omaha 1.0 ensures "there is only one instance of goopdate that is trying to

-  // install at a time." Thus, the lock is the same for machine and user.

-  CString mutex10_name(kOmaha10GlobalPrefix);

-  mutex10_name.Append(kSetupMutex);

-  bool is_initialized = lock10->Initialize(mutex10_name);

-  if (!is_initialized) {

-    extra_code1_ = kVersion10;

-    return false;

-  }

-

-  // Omaha 1.1. ensures "there is only one instance of goopdate per machine or

-  // per user that is trying to install at a time." It allowed installs by

-  // different users to be concurrent by using the Global and Local namespaces.

-  // The machine name was only used when running as Local System, so machine

-  // instances need to look for both the user and machine lock to prevent

-  // conflicts with initial installs running as the user.

-  CString lock11_user_name(kOmaha11LocalPrefix);

-  lock11_user_name.Append(kSetupMutex);

-  is_initialized = lock11_user->Initialize(lock11_user_name);

-  if (!is_initialized) {

-    extra_code1_ = kVersion11;

-    return false;

-  }

-

-  if (is_machine_) {

-    CString lock11_machine_name(kOmaha11GlobalPrefix);

-    lock11_machine_name.Append(kSetupMutex);

-    extra_code1_ = kVersion11MachineLock;

-    return lock11_machine->Initialize(lock11_machine_name);

-  } else {

-    return true;

-  }

-}

-

-void Setup::PersistUpdateErrorInfo(bool is_machine,

-                                   HRESULT error,

-                                   int extra_code1,

-                                   const CString& version) {

-  const TCHAR* update_key_name =

-      ConfigManager::Instance()->registry_update(is_machine);

-  VERIFY1(SUCCEEDED(RegKey::SetValue(update_key_name,

-                                     kRegValueSelfUpdateErrorCode,

-                                     static_cast<DWORD>(error))));

-  VERIFY1(SUCCEEDED(RegKey::SetValue(update_key_name,

-                                     kRegValueSelfUpdateExtraCode1,

-                                     static_cast<DWORD>(extra_code1))));

-  VERIFY1(SUCCEEDED(RegKey::SetValue(update_key_name,

-                                     kRegValueSelfUpdateVersion,

-                                     version)));

-}

-

-// Returns false if the values cannot be deleted to avoid skewing the log data

-// with a single user pinging repeatedly with the same data.

-bool Setup::ReadAndClearUpdateErrorInfo(bool is_machine,

-                                        DWORD* error_code,

-                                        DWORD* extra_code1,

-                                        CString* version) {

-  ASSERT1(error_code);

-  ASSERT1(extra_code1);

-  ASSERT1(version);

-

-  const TCHAR* update_key_name =

-      ConfigManager::Instance()->registry_update(is_machine);

-  RegKey update_key;

-  HRESULT hr = update_key.Open(update_key_name);

-  if (FAILED(hr)) {

-    ASSERT1(false);

-    return false;

-  }

-

-  if (!update_key.HasValue(kRegValueSelfUpdateErrorCode)) {

-    ASSERT1(!update_key.HasValue(kRegValueSelfUpdateExtraCode1));

-    return false;

-  }

-

-  VERIFY1(SUCCEEDED(update_key.GetValue(kRegValueSelfUpdateErrorCode,

-                                        error_code)));

-  ASSERT1(FAILED(*error_code));

-

-  VERIFY1(SUCCEEDED(update_key.GetValue(kRegValueSelfUpdateExtraCode1,

-                                        extra_code1)));

-

-  VERIFY1(SUCCEEDED(update_key.GetValue(kRegValueSelfUpdateVersion, version)));

-

-  if (FAILED(update_key.DeleteValue(kRegValueSelfUpdateErrorCode)) ||

-      FAILED(update_key.DeleteValue(kRegValueSelfUpdateExtraCode1)) ||

-      FAILED(update_key.DeleteValue(kRegValueSelfUpdateVersion))) {

-    ASSERT1(false);

-    return false;

-  }

-

-  return true;

-}

-

-bool Setup::HasXmlParser() {

-  CComPtr<IXMLDOMDocument> my_xmldoc;

-  HRESULT hr = CoCreateSafeDOMDocument(&my_xmldoc);

-  const bool ret = SUCCEEDED(hr);

-  CORE_LOG(L3, (_T("[Setup::HasXmlParser returned %d][0x%08x]"), ret, hr));

-  return ret;

-}

-

-// Assumes that the Setup Lock is held.

-// This method is based on the assumption that if another install, which could

-// be modifying the number of clients, is in progress, that it either:

-//  (a) Has the Setup Lock, which is not possible because this process has it.

-//  (b) Has started an install worker.

-bool Setup::CanUninstallGoogleUpdate() const {

-  CORE_LOG(L2, (_T("[Setup::CanUninstallGoogleUpdate]")));

-  if (goopdate_utils::IsAppInstallWorkerRunning(is_machine_)) {

-    CORE_LOG(L2, (_T("[Found install workers. Not uninstalling]")));

-    return false;

-  }

-  size_t num_clients(0);

-  if (SUCCEEDED(goopdate_utils::GetNumClients(is_machine_, &num_clients)) &&

-      num_clients >= 2) {

-    CORE_LOG(L3, (_T("[Found products. Not uninstalling]")));

-    return false;

-  }

-  return true;

-}

-

-bool Setup::IsInteractiveInstall() const {

-  return (MODE_INSTALL == mode_) && !args_->is_silent_set;

-}

-

-// The result of this method is only valid after the worker has been launched.

-// The /install instance should wait for worker process (/ig or /handoff) if:

-//  * Running silently: The exit code is only indication of install result.

-//  * Offline install: The main reason we exit early normally is to release the

-//    Setup Locks and allow downloads for multiple app installs to occur

-//    simultaneously. Since offline installers do not download, this is less of

-//    a concern. Also, Pack launches the offline installer interactively if the

-//    user chooses to retry after a failure. See http://b/1543716.

-// Long term, we will refactor the locking and always wait for the worker.

-bool Setup::ShouldWaitForWorkerProcess() const {

-  return !IsInteractiveInstall() || launched_offline_worker_;

-}

-

-HRESULT Setup::SetOemInstallState() {

-  ASSERT1(MODE_INSTALL == mode_);

-  ASSERT1(args_->is_oem_set);

-

-  if (!is_machine_ ||

-      IsElevationRequired() ||

-      !ConfigManager::Instance()->IsWindowsInstalling()) {

-    return GOOPDATE_E_OEM_NOT_MACHINE_AND_PRIVILEGED_AND_AUDIT_MODE;

-  }

-

-  const DWORD now = Time64ToInt32(GetCurrent100NSTime());

-  OPT_LOG(L1, (_T("[Beginning OEM install][%u]"), now));

-  HRESULT hr = RegKey::SetValue(

-      ConfigManager::Instance()->machine_registry_update(),

-      kRegValueOemInstallTimeSec,

-      now);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  ASSERT1(ConfigManager::Instance()->IsOemInstalling(is_machine_));

-

-  return S_OK;

-}

-

-HRESULT Setup::SetEulaAccepted(bool is_machine) {

-  SETUP_LOG(L4, (_T("[SetEulaAccepted][%d]"), is_machine));

-  const TCHAR* update_key_name =

-      ConfigManager::Instance()->registry_update(is_machine);

-  return RegKey::HasKey(update_key_name) ?

-      RegKey::DeleteValue(update_key_name, kRegValueOmahaEulaAccepted) :

-      S_OK;

-}

-

-// Does not write the registry if Google Update is already installed as

-// determined by the presence of 2 or more registered apps. In those cases, we

-// assume the existing EULA state is correct and do not want to disable updates

-// for an existing installation.

-// Assumes it is called with appropriate synchronization protection such that it

-// can reliably check the number of registered clients.

-HRESULT Setup::SetEulaNotAccepted(bool is_machine) {

-  SETUP_LOG(L4, (_T("[SetEulaNotAccepted][%d]"), is_machine));

-

-  size_t num_clients(0);

-  if (SUCCEEDED(goopdate_utils::GetNumClients(is_machine, &num_clients)) &&

-      num_clients >= 2) {

-    SETUP_LOG(L4, (_T(" [Apps registered. Not setting eulaaccepted=0.]")));

-    return S_OK;

-  }

-

-  const ConfigManager* cm = ConfigManager::Instance();

-  return RegKey::SetValue(cm->registry_update(is_machine),

-                          kRegValueOmahaEulaAccepted,

-                          static_cast<DWORD>(0));

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// This class handles the installation of Google Update when it is run with the
+// install or update switch. It is invoked when Google Update is launched from
+// the meta-installer and as part of self-update.
+//
+//
+// *** Documentation for OEM Installs ***
+//
+// A /oem install requires:
+//  * Per-machine install
+//  * Running as admin
+//  * Running in Windows audit mode (ConfigManager::IsWindowsInstalling())
+//  * Standalone installer (determined in LaunchInstalledWorker())
+//
+// If the first three conditions are met, this class writes the OemInstallTime
+// registry value, which is used by ConfigManager::IsOemInstalling() along with
+// other logic to determine whether Google Update is running in an OEM install
+// environment.
+// Other objects use IsOemInstalling() - not IsWindowsInstalling() - to
+// determine whether to run in a disabled mode for OEM factory installations.
+// For example, the core exits immediately without checking for updates or Code
+// Red events, no instances ping, and persistent IDs are not saved.
+// OemInstallTime is never cleared. The logic in IsOemInstalling() determines
+// when the system is no longer in an OEM install mode.
+
+#include "omaha/setup/setup.h"
+#include <regstr.h>
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/highres_timer-win32.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/path.h"
+#include "omaha/common/process.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/system.h"
+#include "omaha/common/time.h"
+#include "omaha/common/timer.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/common/xml_utils.h"
+#include "omaha/net/http_client.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/event_logger.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/stats_uploader.h"
+#include "omaha/goopdate/ui_displayed_event.h"
+#include "omaha/setup/setup_files.h"
+#include "omaha/setup/setup_google_update.h"
+#include "omaha/setup/setup_metrics.h"
+#include "omaha/setup/setup_service.h"
+
+namespace omaha {
+
+namespace {
+
+const int kVersion10 = 10;
+const int kVersion11 = 11;
+const int kVersion11MachineLock = 111;
+const int kVersion12 = 12;
+
+void GetShutdownEventAttributes(bool is_machine, NamedObjectAttributes* attr) {
+  ASSERT1(attr);
+  GetNamedObjectAttributes(kShutdownEvent, is_machine, attr);
+}
+
+// Returns the process's mode based on its command line.
+HRESULT GetProcessModeFromPid(uint32 pid, CommandLineMode* mode) {
+  ASSERT1(mode);
+
+  CString cmd_line;
+  HRESULT hr = Process::GetCommandLine(pid, &cmd_line);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[GetCommandLine failed][%u][0x%08x]"), pid, hr));
+    return hr;
+  }
+
+  CommandLineArgs args;
+  hr = ParseCommandLine(cmd_line, &args);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[ParseCommandLine failed][%u][%s][0x%08x]"),
+                   pid, cmd_line, hr));
+    return hr;
+  }
+
+  OPT_LOG(L2, (_T("[Process %u][cmd line %s][mode %u]"),
+               pid, cmd_line, args.mode));
+  *mode = args.mode;
+  return S_OK;
+}
+
+void IncrementProcessWaitFailCount(CommandLineMode mode) {
+  switch (mode) {
+    case COMMANDLINE_MODE_UNKNOWN:
+      ++metric_setup_process_wait_failed_unknown;
+      break;
+    case COMMANDLINE_MODE_NOARGS:  // Legacy install
+    case COMMANDLINE_MODE_LEGACYUI:
+    case COMMANDLINE_MODE_LEGACY_MANIFEST_HANDOFF:
+      ++metric_setup_process_wait_failed_legacy;
+      break;
+    case COMMANDLINE_MODE_CORE:
+      ++metric_setup_process_wait_failed_core;
+      break;
+    case COMMANDLINE_MODE_REPORTCRASH:
+      ++metric_setup_process_wait_failed_report;
+      break;
+    case COMMANDLINE_MODE_UPDATE:
+      ++metric_setup_process_wait_failed_update;
+      break;
+    case COMMANDLINE_MODE_IG:
+      ++metric_setup_process_wait_failed_ig;
+      break;
+    case COMMANDLINE_MODE_HANDOFF_INSTALL:
+      ++metric_setup_process_wait_failed_handoff;
+      break;
+    case COMMANDLINE_MODE_UG:
+      ++metric_setup_process_wait_failed_ug;
+      break;
+    case COMMANDLINE_MODE_UA:
+      ++metric_setup_process_wait_failed_ua;
+      break;
+    case COMMANDLINE_MODE_CODE_RED_CHECK:
+      ++metric_setup_process_wait_failed_cr;
+      break;
+    case COMMANDLINE_MODE_CRASH_HANDLER:
+    case COMMANDLINE_MODE_SERVICE:
+    case COMMANDLINE_MODE_SERVICE_REGISTER:
+    case COMMANDLINE_MODE_SERVICE_UNREGISTER:
+    case COMMANDLINE_MODE_REGSERVER:
+    case COMMANDLINE_MODE_UNREGSERVER:
+    case COMMANDLINE_MODE_NETDIAGS:
+    case COMMANDLINE_MODE_CRASH:
+    case COMMANDLINE_MODE_INSTALL:
+    case COMMANDLINE_MODE_RECOVER:
+    case COMMANDLINE_MODE_WEBPLUGIN:
+    case COMMANDLINE_MODE_COMSERVER:
+    case COMMANDLINE_MODE_REGISTER_PRODUCT:
+    case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
+    default:
+      ++metric_setup_process_wait_failed_other;
+      break;
+  }
+}
+
+// Returns the pids of all other GoogleUpdate.exe processes with the specified
+// argument string. Checks processes for all users that it has privileges to
+// access.
+HRESULT GetPidsWithArgsForAllUsers(const CString& args,
+                                   std::vector<uint32>* pids) {
+  ASSERT1(pids);
+
+  std::vector<CString> command_line;
+  command_line.push_back(args);
+
+  DWORD flags = EXCLUDE_CURRENT_PROCESS |
+                INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
+  HRESULT hr = Process::FindProcesses(flags,
+                                      kGoopdateFileName,
+                                      true,
+                                      CString(),
+                                      command_line,
+                                      pids);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+const TCHAR* const kUninstallEventDesc = _T("Google Update uninstall");
+
+void WriteGoogleUpdateUninstallEvent(bool is_machine) {
+  GoogleUpdateLogEvent uninstall_event(EVENTLOG_INFORMATION_TYPE,
+                                       kUninstallEventId,
+                                       is_machine);
+  uninstall_event.set_event_desc(kUninstallEventDesc);
+  uninstall_event.WriteEvent();
+}
+
+// Returns true if the mode can be determined and pid represents a "/c" process.
+bool IsCoreProcess(uint32 pid) {
+  CommandLineMode mode(COMMANDLINE_MODE_UNKNOWN);
+  return SUCCEEDED(GetProcessModeFromPid(pid, &mode)) &&
+         COMMANDLINE_MODE_CORE == mode;
+}
+
+}  // namespace
+
+bool Setup::did_uninstall_ = false;
+
+Setup::Setup(bool is_machine, const CommandLineArgs* args)
+    : is_machine_(is_machine),
+      mode_(MODE_UNKNOWN),
+      args_(args),
+      extra_code1_(S_OK),
+      launched_offline_worker_(false) {
+  SETUP_LOG(L2, (_T("[Setup::Setup]")));
+}
+
+Setup::~Setup() {
+  SETUP_LOG(L2, (_T("[Setup::~Setup]")));
+}
+
+// Handles the elevation case, then calls DoInstall to do the real work if
+// elevation is not required.
+// If elevation is required, the method returns when the elevated instance
+// exits because there is nothing more to do in this Omaha instance.
+HRESULT Setup::Install(const CString& cmd_line) {
+  SETUP_LOG(L2, (_T("[Setup::Install][%s]"), cmd_line));
+  ASSERT1(!cmd_line.IsEmpty());
+
+  mode_ = MODE_INSTALL;
+
+  if (args_->is_oem_set) {
+    HRESULT hr = SetOemInstallState();
+    if (FAILED(hr)) {
+      return hr;
+    }
+  } else if (ConfigManager::Instance()->IsWindowsInstalling()) {
+    ASSERT(false, (_T("[In OEM Audit Mode but not doing OEM install]")));
+    return GOOPDATE_E_NON_OEM_INSTALL_IN_AUDIT_MODE;
+  }
+
+  ++metric_setup_install_total;
+  if (args_->is_install_elevated) {
+    ++metric_setup_uac_succeeded;
+  }
+
+  // If we ever support NEEDS_ADMIN_PREFERS variants, handle them here.
+  // We will also need to tell the installer how to install.
+
+  if (IsElevationRequired()) {
+    HRESULT hr = ElevateAndWait(cmd_line);
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[Setup::ElevateAndWait failed][%s][0x%08x]"),
+                    cmd_line, hr));
+    }
+    return hr;
+  }
+
+  if (vista_util::IsVistaOrLater() &&
+      !is_machine_ &&
+      vista_util::IsUserAdmin()) {
+    ++metric_setup_user_app_admin;
+  }
+
+  HRESULT hr = DoInstall();
+
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  ++metric_setup_install_succeeded;
+  return S_OK;
+}
+
+HRESULT Setup::InstallSelfSilently() {
+  SETUP_LOG(L2, (_T("[Setup::InstallSelfSilently]")));
+  ASSERT1(!IsElevationRequired());
+  ASSERT1(!args_->extra_args_str.IsEmpty());
+
+  // TODO(omaha): add metrics.
+  mode_ = MODE_SELF_INSTALL;
+
+  HRESULT hr = DoInstall();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // TODO(omaha): add metrics.
+  return S_OK;
+}
+
+HRESULT Setup::UpdateSelfSilently() {
+  SETUP_LOG(L2, (_T("[Setup::UpdateSelfSilently]")));
+  ASSERT1(!IsElevationRequired());
+  ASSERT1(args_->extra_args_str.IsEmpty());
+
+  ++metric_setup_update_self_total;
+  mode_ = MODE_SELF_UPDATE;
+
+  HRESULT hr = DoInstall();
+  if (FAILED(hr)) {
+    PersistUpdateErrorInfo(is_machine_, hr, extra_code1_, GetVersionString());
+    return hr;
+  }
+
+  ++metric_setup_update_self_succeeded;
+  return S_OK;
+}
+
+HRESULT Setup::RepairSilently() {
+  SETUP_LOG(L2, (_T("[Setup::RepairSilently]")));
+  ASSERT1(!IsElevationRequired());
+  ASSERT1(args_->extra_args_str.IsEmpty());
+
+  mode_ = MODE_REPAIR;
+
+  HRESULT hr = DoInstall();
+  if (FAILED(hr)) {
+    // Use the update failed ping for repairs too.
+    PersistUpdateErrorInfo(is_machine_, hr, extra_code1_, GetVersionString());
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// Protects all setup-related operations with:
+// * Setup Lock - Prevents other instances from installing Google Update for
+// this machine/user at the same time.
+// * Shutdown Event - Tells existing other instances and any instances that may
+// start during Setup to exit.
+// Setup-related operations do not include installation of the app.
+// Also tries to acquire the locks for Omaha 1.0 and 1.1, which are lock10 and
+// lock11, respectively.
+// Until we secure the current setup lock (bug 1076207), we return an error if
+// we are unable to acquire the legacy locks.
+// Gets the legacy locks first because we wait a lot longer for them during
+// updates and would not want to hold the setup lock all that time.
+// Legacy Setup Locks are not released until the app is installed.
+//
+// Sets the EULA as accepted when installing and /eularequired is not specified.
+// This can be done outside the locks. Setting EULA not accepted is done inside
+// the lock and process protection in DoProtectedGoogleUpdateInstall.
+HRESULT Setup::DoInstall() {
+  ASSERT1(MODE_UNKNOWN != mode_);
+  ASSERT1(!IsElevationRequired());
+
+  if (!args_->is_eula_required_set &&
+      (MODE_INSTALL == mode_ || MODE_SELF_INSTALL == mode_)) {
+    HRESULT hr = SetEulaAccepted(is_machine_);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  // Validate that key OS components are installed.
+  if (!HasXmlParser()) {
+    return GOOPDATE_E_RUNNING_INFERIOR_MSXML;
+  }
+
+  // Start the setup timer.
+  metrics_timer_.reset(new HighresTimer);
+
+  GLock lock10, lock11_user, lock11_machine, setup_lock;
+
+  // Initialize all locks.
+  if (!InitLegacySetupLocks(&lock10, &lock11_user, &lock11_machine)) {
+    SETUP_LOG(L2, (_T("[Setup::InitLegacySetupLocks failed]")));
+    return GOOPDATE_E_SETUP_LOCK_INIT_FAILED;
+  }
+  if (!InitSetupLock(is_machine_, &setup_lock)) {
+    SETUP_LOG(L2, (_T("[Setup::InitSetupLock failed]")));
+    extra_code1_ = kVersion12;
+    return GOOPDATE_E_SETUP_LOCK_INIT_FAILED;
+  }
+
+  scoped_process handoff_process;
+
+  // Attempt to acquire all locks. Acquire them in a new scope so they are
+  // automatically released by ScopeGuards when we no longer need protection.
+  {
+    HighresTimer lock_metrics_timer;
+
+    // Try to acquire the 1.0/1.1 locks to prevent these installers from
+    // running, but do not fail if not acquired because this prevents
+    // simultaneous user and machine installs because both used the same name.
+    // See bug 1145609. For simplicity, hold these locks until the function
+    // exits.
+    if (!lock10.Lock(kSetupLockWaitMs)) {
+      OPT_LOG(LW, (_T("[Failed to acquire 1.0 setup lock]")));
+    }
+
+    if (!lock11_user.Lock(kSetupLockWaitMs)) {
+      OPT_LOG(LW, (_T("[Failed to acquire 1.1 user setup lock]")));
+    }
+
+    if (is_machine_) {
+      if (!lock11_machine.Lock(kSetupLockWaitMs)) {
+        OPT_LOG(LE, (_T("[Failed to acquire 1.1 machine setup lock]")));
+        return HandleLockFailed(kVersion11MachineLock);
+      }
+    }
+    ScopeGuard lock11_machine_guard = MakeObjGuard(lock11_machine,
+                                                   &GLock::Unlock);
+    if (!is_machine_) {
+      lock11_machine_guard.Dismiss();
+    }
+
+    if (!setup_lock.Lock(kSetupLockWaitMs)) {
+      OPT_LOG(LE, (_T("[Failed to acquire setup lock]")));
+      return HandleLockFailed(kVersion12);
+    }
+    ON_SCOPE_EXIT_OBJ(setup_lock, &GLock::Unlock);
+
+    metric_setup_lock_acquire_ms.AddSample(lock_metrics_timer.GetElapsedMs());
+    SETUP_LOG(L1, (_T("[Setup Locks acquired]")));
+
+    // Do the installation.
+    HRESULT hr = DoProtectedInstall(address(handoff_process));
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[Setup::DoProtectedInstall failed][0x%08x]"), hr));
+      SETUP_LOG(L1, (_T("[Releasing Setup Lock]")));
+      return hr;
+    }
+
+    SETUP_LOG(L1, (_T("[Releasing Setup Lock]")));
+  }  // End lock protection.
+
+  if (handoff_process) {
+    ASSERT1(MODE_INSTALL == mode_);
+
+    // TODO(omaha): Why do we exit once the UI event is signaled? It is not
+    // related to the locks like waiting for /ig and it complicates the code.
+    HRESULT hr = WaitForHandoffWorker(get(handoff_process));
+
+    if (FAILED(hr)) {
+      if (!ShouldWaitForWorkerProcess()) {
+        // Did not wait for the second process to exit. The error may not be the
+        // exit code of the worker process. Report that the handoff failed.
+        OPT_LOG(LE, (_T("[Wait for Google Update hand off failed][0x%08x]"),
+                     hr));
+        extra_code1_ = hr;
+        return GOOPDATE_E_HANDOFF_FAILED;
+      } else {
+        return hr;
+      }
+    }
+
+    ++metric_setup_handoff_only_succeeded;
+  }
+
+  return S_OK;
+}
+
+// Sets appropriate metrics and extra_code1_ value. It then tries to determine
+// the scenario that caused this failure and returns an appropriate error.
+// The detected processes may not actually be in conflict with this one, but are
+// more than likely the cause of the lock failure.
+HRESULT Setup::HandleLockFailed(int lock_version) {
+  ++metric_setup_locks_failed;
+
+  switch (lock_version) {
+    case kVersion10:
+      ASSERT1(false);
+      extra_code1_ = kVersion10;
+      break;
+    case kVersion11:
+      extra_code1_ = kVersion11;
+      ++metric_setup_lock11_failed;
+      break;
+    case kVersion11MachineLock:
+      extra_code1_ = kVersion11MachineLock;
+      ++metric_setup_lock11_failed;
+      break;
+    case kVersion12:
+      extra_code1_ = kVersion12;
+      ++metric_setup_lock12_failed;
+      break;
+    default:
+      ASSERT1(false);
+      extra_code1_ = -1;
+      break;
+  }
+
+  Pids matching_pids;
+  CString switch_to_include;
+
+  switch_to_include.Format(_T("/%s"), kCmdLineUpdate);
+  HRESULT hr = GetPidsWithArgsForAllUsers(switch_to_include, &matching_pids);
+  if (FAILED(hr)) {
+    ASSERT1(false);
+    return GOOPDATE_E_FAILED_TO_GET_LOCK;
+  }
+  if (!matching_pids.empty()) {
+    return GOOPDATE_E_FAILED_TO_GET_LOCK_UPDATE_PROCESS_RUNNING;
+  }
+
+  switch_to_include.Format(_T("/%s"), kCmdLineInstall);
+  hr = GetPidsWithArgsForAllUsers(switch_to_include, &matching_pids);
+  if (FAILED(hr)) {
+    ASSERT1(false);
+    return GOOPDATE_E_FAILED_TO_GET_LOCK;
+  }
+  if (matching_pids.empty()) {
+    return GOOPDATE_E_FAILED_TO_GET_LOCK;
+  }
+
+  // Another /install process was found. Determine if it has the same cmd line.
+  const TCHAR* this_cmd_line = ::GetCommandLine();
+  if (!this_cmd_line) {
+    ASSERT1(false);
+    return GOOPDATE_E_FAILED_TO_GET_LOCK;
+  }
+  const CString current_cmd_line(this_cmd_line);
+  if (current_cmd_line.IsEmpty()) {
+    ASSERT1(false);
+    return GOOPDATE_E_FAILED_TO_GET_LOCK;
+  }
+
+  // Strip the directory path, which may vary, and executable name.
+  int exe_index = current_cmd_line.Find(kGoopdateFileName);
+  if (-1 == exe_index) {
+    ASSERT(false, (_T("Unable to find %s in %s"),
+                   kGoopdateFileName, current_cmd_line));
+    return GOOPDATE_E_FAILED_TO_GET_LOCK;
+  }
+  int args_start = exe_index + _tcslen(kGoopdateFileName);
+  // Support enclosed paths; increment past closing double quote.
+  if (_T('"') == current_cmd_line.GetAt(args_start)) {
+    ++args_start;
+  }
+  const int args_length = current_cmd_line.GetLength() - args_start;
+  CString current_args = current_cmd_line.Right(args_length);
+  current_args.Trim();
+
+  for (size_t i = 0; i < matching_pids.size(); ++i) {
+    CString matching_pid_cmd_line;
+    if (FAILED(Process::GetCommandLine(matching_pids[i],
+                                       &matching_pid_cmd_line))) {
+      continue;
+    }
+
+    if (-1 != matching_pid_cmd_line.Find(current_args)) {
+      // Assume that this is a match and not a subset.
+      return GOOPDATE_E_FAILED_TO_GET_LOCK_MATCHING_INSTALL_PROCESS_RUNNING;
+    }
+  }
+
+  return GOOPDATE_E_FAILED_TO_GET_LOCK_NONMATCHING_INSTALL_PROCESS_RUNNING;
+}
+
+// Assumes the necessary locks have been acquired.
+HRESULT Setup::DoProtectedInstall(HANDLE* handoff_process) {
+  SETUP_LOG(L2, (_T("[Setup::DoProtectedInstall]")));
+  ASSERT1(handoff_process);
+  ASSERT1(MODE_UNKNOWN != mode_);
+
+  SetupFiles setup_files(is_machine_);
+
+  HRESULT hr = setup_files.Init();
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[SetupFiles::Init failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (ShouldInstall(&setup_files)) {
+    ++metric_setup_do_self_install_total;
+    HRESULT hr = DoProtectedGoogleUpdateInstall(&setup_files);
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[DoProtectedGoogleUpdateInstall fail][0x%08x]"), hr));
+      // Do not return until rolling back, releasing the events and restarting
+      // the core.
+    }
+
+    if (FAILED(hr)) {
+      RollBack(&setup_files);
+    }
+
+    // We need to hold the shutdown events until phase 2 is complete.
+    // Phase 2 will release the current version's event. Here we release all
+    // shutdown events, including the one that should have already been released
+    // to be safe (i.e. in case phase 2 crashes).
+    // This will happen before the Setup Lock is released, preventing any races.
+    ReleaseShutdownEvents();
+
+    if (FAILED(hr)) {
+      // We may have shutdown an existing core. Start it again if possible.
+      // First kill running cores to prevent the stated instance from exiting
+      // because it cannot acquire the single program instance.
+      OPT_LOG(L2, (_T("[Attempting to restart existing core]")));
+
+      VERIFY1(SUCCEEDED(TerminateCoreProcesses()));
+
+      HRESULT start_hr = StartCore();
+      if (FAILED(start_hr)) {
+        SETUP_LOG(LW, (_T("[StartCore failed][0x%08x]"), start_hr));
+      }
+
+      return hr;
+    }
+
+    ++metric_setup_do_self_install_succeeded;
+    return S_OK;
+  } else if (MODE_INSTALL == mode_) {
+    // No setup was required. Launch the worker to install the app.
+    // Since we are not doing any setup in the worker, return without waiting
+    // so that we can release the Setup Lock.
+    ++metric_setup_handoff_only_total;
+
+    hr = LaunchInstalledWorker(false,   // Do not run setup phase 2.
+                               handoff_process);
+    if (SUCCEEDED(hr)) {
+      metric_setup_handoff_ms.AddSample(metrics_timer_->GetElapsedMs());
+    } else {
+      OPT_LOG(LE, (_T("[Failed to launch installed instance][0x%08x]"), hr));
+      // TODO(omaha): Consider checking for GoogleUpdate.exe in version
+      // directory in file not found case and copying it to shell location then
+      // relaunching.
+    }
+
+    // Start the core in case one is not already running. If one is already
+    // running, this one will exit quickly.
+    HRESULT start_hr = StartCore();
+    if (FAILED(start_hr)) {
+      SETUP_LOG(LW, (_T("[StartCore failed][0x%08x]"), start_hr));
+    }
+
+    return hr;
+  } else {
+    // Do not launch the worker because there is no app to install.
+    OPT_LOG(L1, (_T("[Not installing Google Update or an app]")));
+
+    // Start the core in case one is not already running. If one is already
+    // running, this one will exit quickly.
+    return StartCore();
+  }
+}
+
+// Assumes that the shell is the correct version for the existing Omaha version.
+bool Setup::ShouldInstall(SetupFiles* setup_files) {
+  SETUP_LOG(L2, (_T("[Setup::ShouldInstall]")));
+  ASSERT1(setup_files);
+
+  ++metric_setup_should_install_total;
+
+  ULONGLONG my_version = GetVersion();
+
+  const ConfigManager* cm = ConfigManager::Instance();
+  CString existing_version;
+  HRESULT hr = RegKey::GetValue(cm->registry_clients_goopdate(is_machine_),
+                                kRegValueProductVersion,
+                                &existing_version);
+  if (FAILED(hr)) {
+    OPT_LOG(L2, (_T("[fresh install]")));
+    ++metric_setup_should_install_true_fresh_install;
+    return true;
+  }
+
+  OPT_LOG(L2, (_T("[Existing version: %s][Running version: %s]"),
+               existing_version, GetVersionString()));
+  UpdateCoreNotRunningMetric(existing_version);
+
+  // If running from the official install directory for this type of install
+  // (user/machine), it is most likely a OneClick install. Do not install self.
+  if (goopdate_utils::IsRunningFromOfficialGoopdateDir(is_machine_)) {
+    ++metric_setup_should_install_false_oc;
+    return false;
+  }
+
+  if (MODE_INSTALL == mode_) {
+    ++metric_setup_subsequent_install_total;
+  }
+
+  bool should_install(false);
+
+  ULONGLONG cv = VersionFromString(existing_version);
+  if (cv > my_version) {
+    SETUP_LOG(L2, (_T("[not installing, newer version exists]")));
+    ++metric_setup_should_install_false_older;
+    should_install = false;
+  } else if (cv < my_version) {
+    SETUP_LOG(L2, (_T("[installing with local build]")));
+    ++metric_setup_should_install_true_newer;
+    should_install = true;
+  } else {
+    // Same version.
+    should_install = ShouldOverinstallSameVersion(setup_files);
+    if (should_install) {
+      ++metric_setup_should_install_true_same;
+    } else {
+      ++metric_setup_should_install_false_same;
+    }
+  }
+
+  if (MODE_INSTALL == mode_ && should_install) {
+    ++metric_setup_subsequent_install_should_install_true;
+  }
+
+  OPT_LOG(L1, (_T("[machine = %d][existing version = %s][should_install = %d]"),
+               is_machine_, existing_version, should_install));
+
+  return should_install;
+}
+
+// Checks the following:
+//  * OverInstall override.
+//  * The "installed" version in the registry equals this version.
+//    If not, this version was not fully installed even though "pv" says it is.
+//  * Files are properly installed.
+bool Setup::ShouldOverinstallSameVersion(SetupFiles* setup_files) {
+  SETUP_LOG(L2, (_T("[Setup::ShouldOverinstallSameVersion]")));
+  ASSERT1(setup_files);
+
+  const ConfigManager* cm = ConfigManager::Instance();
+
+  bool should_over_install = cm->CanOverInstall();
+  SETUP_LOG(L1, (_T("[should over install = %d]"), should_over_install));
+  if (should_over_install) {
+    SETUP_LOG(L2, (_T("[overinstalling with local build]")));
+    return true;
+  }
+
+  CString installed_version;
+  HRESULT hr = RegKey::GetValue(cm->registry_update(is_machine_),
+                                kRegValueInstalledVersion,
+                                &installed_version);
+  if (FAILED(hr) || GetVersionString() != installed_version) {
+    SETUP_LOG(L1, (_T("[installed version missing or did not match][%s]"),
+                   installed_version));
+    ++metric_setup_should_install_true_same_completion_missing;
+    return true;
+  }
+
+  if (setup_files->ShouldOverinstallSameVersion()) {
+    SETUP_LOG(L1, (_T("[files need over-install]")));
+    return true;
+  }
+
+  // TODO(omaha): Verify the current installation is complete and correct.
+  // For example, in Omaha 1, we would always set the run key to the version
+  // being installed. Now that code is in SetupGoogleUpdate, and it does not get
+  // called.
+
+  return false;
+}
+
+
+void Setup::UpdateCoreNotRunningMetric(const CString& existing_version) {
+  if (!goopdate_utils::IsGoogleUpdate2OrLater(existing_version)) {
+    return;
+  }
+
+  Pids found_core_pids;
+  HRESULT hr = FindCoreProcesses(&found_core_pids);
+  if (FAILED(hr)) {
+    ASSERT(false, (_T("[FindCoreProcesses failed][0x%08x]"), hr));
+    return;
+  }
+
+  if (found_core_pids.empty()) {
+    ++metric_setup_installed_core_not_running;
+  }
+}
+
+// When installing and /eularequired is specified, calls SetEulaNotAccepted
+// after guaranteeing that no other processes are running.
+HRESULT Setup::DoProtectedGoogleUpdateInstall(SetupFiles* setup_files) {
+  ASSERT1(setup_files);
+  SETUP_LOG(L2, (_T("[Setup::DoProtectedGoogleUpdateInstall]")));
+
+  HRESULT hr = StopGoogleUpdateAndWait();
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[StopGoogleUpdateAndWait failed][0x%08x]"), hr));
+    if (E_ACCESSDENIED == hr) {
+      return GOOPDATE_E_ACCESSDENIED_STOP_PROCESSES;
+    }
+    return hr;
+  }
+
+  VERIFY1(SUCCEEDED(ResetMetrics(is_machine_)));
+
+  if (args_->is_eula_required_set) {
+    if (MODE_INSTALL == mode_ || MODE_SELF_INSTALL == mode_) {
+      hr = SetEulaNotAccepted(is_machine_);
+      if (FAILED(hr)) {
+        return hr;
+      }
+    } else {
+      ASSERT1(false);
+    }
+  }
+
+  hr = setup_files->Install();
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[SetupFiles::Install failed][0x%08x]"), hr));
+    extra_code1_ = setup_files->extra_code1();
+    return hr;
+  }
+  ASSERT1(!setup_files->extra_code1());
+
+  scoped_event setup_complete_event;
+  VERIFY1(SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(
+      kSetupCompleteEventEnvironmentVariableName,
+      is_machine_,
+      address(setup_complete_event))));
+  // Continue on failure. We just will not be able to release the lock early.
+
+  hr = goopdate_utils::GetVerFromRegistry(is_machine_,
+                                          kGoogleUpdateAppId,
+                                          &saved_version_);
+  if (FAILED(hr)) {
+    SETUP_LOG(L3, (_T("[GetVerFromRegistry failed][0x%08x]"), hr));
+    // Continue as this is expected for first installs.
+  }
+
+  // Set the version so the constant shell will know which version to use.
+  hr = RegKey::SetValue(
+      ConfigManager::Instance()->registry_clients_goopdate(is_machine_),
+      kRegValueProductVersion,
+      GetVersionString());
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Failed to set version in registry][0x%08x]"), hr));
+    if (E_ACCESSDENIED == hr) {
+      return GOOPDATE_E_ACCESSDENIED_SETUP_REG_ACCESS;
+    }
+    return hr;
+  }
+
+  // Start the worker to run setup phase 2 and install the app.
+  scoped_process worker_process;
+  hr = LaunchInstalledWorker(true,  // Run setup phase 2.
+                             address(worker_process));
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Failed to launch installed instance][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Wait for setup to complete to ensure the Setup Lock is held though the
+  // end of setup.
+  OPT_LOG(L1, (_T("[Waiting for setup to complete]")));
+  uint32 exit_code(0);
+  hr = WaitForProcessExitOrEvent(get(worker_process),
+                                 get(setup_complete_event),
+                                 &exit_code);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Failed waiting for setup to complete][0x%08x]"), hr));
+    return hr;
+  }
+  if (exit_code) {
+    OPT_LOG(LE, (_T("[Setup exited with error][0x%08x]"), exit_code));
+    ASSERT1(FAILED(exit_code));
+
+    return exit_code;
+  }
+
+  metric_setup_install_google_update_total_ms.AddSample(
+      metrics_timer_->GetElapsedMs());
+  return S_OK;
+}
+
+void Setup::RollBack(SetupFiles* setup_files) {
+  OPT_LOG(L1, (_T("[Roll back]")));
+  ASSERT1(setup_files);
+
+  // Restore the saved version.
+  if (!saved_version_.IsEmpty()) {
+    SETUP_LOG(L1, (_T("[Rolling back version to %s]"), saved_version_));
+    ++metric_setup_rollback_version;
+
+    VERIFY1(SUCCEEDED(RegKey::SetValue(
+        ConfigManager::Instance()->registry_clients_goopdate(is_machine_),
+        kRegValueProductVersion,
+        saved_version_)));
+  }
+
+  VERIFY1(SUCCEEDED(setup_files->RollBack()));
+}
+
+// Assumes the caller is ensuring this is the only running instance of setup.
+// The original process holds the lock while it waits for this one to complete.
+HRESULT Setup::SetupGoogleUpdate() {
+  SETUP_LOG(L2, (_T("[Setup::SetupGoogleUpdate]")));
+  ASSERT1(!IsElevationRequired());
+  mode_ = MODE_PHASE2;
+
+  HighresTimer phase2_metrics_timer;
+
+  omaha::SetupGoogleUpdate setup_google_update(is_machine_, args_);
+
+  HRESULT hr = setup_google_update.FinishInstall();
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[FinishInstall failed][0x%08x]"), hr));
+
+    // We shutdown the existing core. Start a core - which one depends on where
+    // we failed - again if possible.
+    // There is a chance we have messed up the launch mechanisms and the core
+    // will not even start on reboot.
+    VERIFY1(SUCCEEDED(StartCore()));
+
+    return hr;
+  }
+
+  // Release the shutdown event, so we can start the core and do not interfere
+  // with other app installs that may be waiting on the Setup Lock.
+  NamedObjectAttributes event_attr;
+  GetShutdownEventAttributes(is_machine_, &event_attr);
+  scoped_event shutdown_event(::OpenEvent(EVENT_MODIFY_STATE,
+                                          false,
+                                          event_attr.name));
+  if (shutdown_event) {
+    VERIFY1(::ResetEvent(get(shutdown_event)));
+  } else {
+    SETUP_LOG(LW, (_T("[::OpenEvent failed][%s][%u]"),
+                  event_attr.name, ::GetLastError()));
+  }
+
+  if (is_machine_) {
+    hr = StartMachineCoreProcess();
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[StartMachineCoreProcess failed][0x%08x]"), hr));
+      return hr;
+    }
+  } else {
+    CString core_cmd_line(setup_google_update.BuildCoreProcessCommandLine());
+    hr = StartUserCoreProcess(core_cmd_line);
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[StartUserCoreProcess failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  // Setup is now complete.
+  SetSetupCompleteEvent();
+
+  metric_setup_phase2_ms.AddSample(phase2_metrics_timer.GetElapsedMs());
+  return S_OK;
+}
+
+// Stops all user/machine instances including the service, unregisters using
+// SetupGoogleUpdate, then deletes  the files using SetupFiles.
+// Does not wait for the processes to exit, except the service.
+// Protects all operations with the setup lock. If MSI is found busy, Omaha
+// won't uninstall.
+HRESULT Setup::Uninstall() {
+  OPT_LOG(L1, (_T("[Setup::Uninstall]")));
+  ASSERT1(!IsElevationRequired());
+  mode_ = MODE_UNINSTALL;
+
+  // Try to get the global setup lock; if the lock is taken, do not block
+  // waiting to uninstall; just return.
+  GLock setup_lock;
+  VERIFY1(InitSetupLock(is_machine_, &setup_lock));
+  if (!setup_lock.Lock(0)) {
+    OPT_LOG(LE, (_T("[Failed to acquire setup lock]")));
+    return E_FAIL;
+  }
+
+  return DoProtectedUninstall();
+}
+
+// Aggregates metrics regardless of whether uninstall is allowed.
+// Foces reporting of the metrics if uninstall is allowed.
+// Assumes that the current process holds the Setup Lock.
+HRESULT Setup::DoProtectedUninstall() {
+  const bool can_uninstall = CanUninstallGoogleUpdate();
+  OPT_LOG(L1, (_T("[CanUninstallGoogleUpdate returned %d]"), can_uninstall));
+  ASSERT1(!IsElevationRequired());
+
+  if (can_uninstall) {
+    HRESULT hr = AggregateAndReportMetrics(is_machine_, true);
+    VERIFY1(SUCCEEDED(hr) || GOOPDATE_E_CANNOT_USE_NETWORK == hr);
+  } else {
+    VERIFY1(SUCCEEDED(AggregateMetrics(is_machine_)));
+  }
+
+  if (!can_uninstall) {
+    return GOOPDATE_E_CANT_UNINSTALL;
+  }
+
+  if (is_machine_) {
+    HRESULT hr = SetupService::StopService();
+    if (FAILED(hr)) {
+      SETUP_LOG(LW, (_T("[SetupService::StopService failed][0x%08x]"), hr));
+      ASSERT1(HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) == hr);
+    }
+  }
+  VERIFY1(SUCCEEDED(SignalShutdownEvent()));
+
+  // TODO(omaha): Consider waiting for the Omaha processes to exit. This would
+  // need to exclude any processes, such as /ua /uninstall, that can uninstall.
+
+  // Write the event in the event log before uninstalling the program since
+  // the event contains version and language information, which are removed
+  // during the uninstall.
+  WriteGoogleUpdateUninstallEvent(is_machine_);
+
+  omaha::SetupGoogleUpdate setup_google_update(is_machine_, args_);
+  setup_google_update.Uninstall();
+
+  SetupFiles setup_files(is_machine_);
+  setup_files.Uninstall();
+
+  OPT_LOG(L1, (_T("[Uninstall complete]")));
+  did_uninstall_ = true;
+  return S_OK;
+}
+
+// Should only be called after the point where Uninstall would have been called.
+// Works correctly in the case where the Setup Lock is not held but an app is
+// being installed because it does not check the number of registered apps.
+// Either Omaha is installed or has been cleaned up.
+// Installed means Clients, ClientState, etc. sub keys exist.
+// Cleaned up may mean the Update key does not exist or some values, such as
+// mid and uid exist, but there are no subkeys.
+// The Update key should never exist without any values.
+// Does not take the Setup Lock because it is just a dbg check. It is possible
+// for the value of did_uninstall_ to be changed in another thread or for
+// another process to install or uninstall Google Update while this is running.
+void Setup::CheckInstallStateConsistency(bool is_machine) {
+  UNREFERENCED_PARAMETER(is_machine);
+#if DEBUG
+  CString key_name = ConfigManager::Instance()->registry_update(is_machine);
+  if (!RegKey::HasKey(key_name)) {
+    // Either this instance called uninstall or it is the non-elevated machine
+    // instance on Vista and later. Both cannot be true in the same instance.
+    ASSERT1(did_uninstall_ != (is_machine && !vista_util::IsUserAdmin()));
+    return;
+  }
+
+  RegKey update_key;
+  ASSERT1(SUCCEEDED(update_key.Open(key_name, KEY_READ)));
+
+  ASSERT1(0 != update_key.GetValueCount());
+
+  if (did_uninstall_) {
+    ASSERT1(0 == update_key.GetSubkeyCount());
+    ASSERT1(!update_key.HasValue(kRegValueInstalledVersion));
+    ASSERT1(!update_key.HasValue(kRegValueInstalledPath));
+  } else {
+    ASSERT1(update_key.HasSubkey(_T("Clients")));
+    ASSERT1(update_key.HasSubkey(_T("ClientState")));
+    ASSERT1(update_key.HasSubkey(_T("network")));
+    ASSERT1(update_key.HasValue(kRegValueInstalledVersion));
+    ASSERT1(update_key.HasValue(kRegValueInstalledPath));
+
+    CString installed_version;
+    ASSERT1(SUCCEEDED(update_key.GetValue(kRegValueInstalledVersion,
+                                          &installed_version)));
+    const CString state_key_name =
+      ConfigManager::Instance()->registry_client_state_goopdate(is_machine);
+    CString pv;
+    ASSERT1(SUCCEEDED(RegKey::GetValue(state_key_name,
+                                       kRegValueProductVersion,
+                                       &pv)));
+    ASSERT1(installed_version == pv);
+  }
+#endif
+}
+
+// Stops both legacy and current instances.
+// Holds the shutdown events so that other instances do not start running.
+// The caller is responsible for releasing the events.
+// Because this waiting occurs before a UI is generated, we do not want to wait
+// too long.
+HRESULT Setup::StopGoogleUpdate() {
+  OPT_LOG(L1, (_T("[Stopping other instances]")));
+
+  // In the machine install case, we should first stop the service.
+  // This means that we should not get the service as a process to wait
+  // on when the machine goopdate tries to enumerate the processes.
+  if (is_machine_) {
+    OPT_LOG(L1, (_T("[Stopping service]")));
+    HRESULT hr = SetupService::StopService();
+    if (FAILED(hr)) {
+      OPT_LOG(LE, (_T("[StopService failed][0x%08x]"), hr));
+    }
+  }
+
+  HRESULT hr = SignalLegacyShutdownEvents();
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[SignalLegacyShutdownEvents failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = SignalShutdownEvent();
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[SignalShutdownEvent failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT Setup::StopGoogleUpdateAndWait() {
+  HRESULT hr = StopGoogleUpdate();
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[StopGoogleUpdate failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  Pids pids;
+  hr = GetPidsToWaitFor(&pids);
+  if (FAILED(hr)) {
+    SETUP_LOG(LEVEL_ERROR, (_T("[GetPidsToWaitFor failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = WaitForOtherInstancesToExit(pids);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[WaitForOtherInstancesToExit failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// Signals >= 1.2.x processes to exit.
+HRESULT Setup::SignalShutdownEvent() {
+  SETUP_LOG(L1, (_T("[Setup::SignalShutdownEvent]")));
+  NamedObjectAttributes event_attr;
+  GetShutdownEventAttributes(is_machine_, &event_attr);
+
+  if (!shutdown_event_) {
+    HRESULT hr = goopdate_utils::CreateEvent(&event_attr,
+                                             address(shutdown_event_));
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[CreateEvent current failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  VERIFY1(::SetEvent(get(shutdown_event_)));
+
+  return S_OK;
+}
+
+// Signals the quiet mode events for 1.0.x (pre-i18n) and 1.1.x (i18n)
+// processes, causing them to exit.
+HRESULT Setup::SignalLegacyShutdownEvents() {
+  SETUP_LOG(L1, (_T("[Setup::SignalLegacyShutdownEvents]")));
+
+  // Signal 1.0.x (pre-i18n) processes.
+  CString sid;
+  HRESULT hr = GetAppropriateSid(&sid);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString legacy_1_0_shutdown_event_name;
+  legacy_1_0_shutdown_event_name.Format(kEventLegacyQuietModeName, sid);
+
+  hr = CreateLegacyEvent(legacy_1_0_shutdown_event_name,
+                         address(legacy_1_0_shutdown_event_));
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[CreateLegacyEvent legacy quiet mode failed][0x%08x]"),
+                  hr));
+    return hr;
+  }
+
+
+  // Signal 1.1.x (i18n) processes.
+  // 1.1 used the same event GUID in a different way.
+  CString legacy_1_1_shutdown_event_name(is_machine_ ? kOmaha11GlobalPrefix :
+                                                       kOmaha11LocalPrefix);
+  legacy_1_1_shutdown_event_name.Append(kShutdownEvent);
+
+  hr = CreateLegacyEvent(legacy_1_1_shutdown_event_name,
+                         address(legacy_1_1_shutdown_event_));
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[CreateLegacyEvent quiet mode failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  VERIFY1(::SetEvent(get(legacy_1_0_shutdown_event_)));
+  VERIFY1(::SetEvent(get(legacy_1_1_shutdown_event_)));
+
+  return S_OK;
+}
+
+// The caller is responsible for reseting the event and closing the handle.
+HRESULT Setup::CreateLegacyEvent(const CString& event_name,
+                                 HANDLE* event_handle) const {
+  ASSERT1(event_handle);
+  ASSERT1(!event_name.IsEmpty());
+  CSecurityAttributes sa;
+  if (is_machine_) {
+    // Grant access to administrators and system. This allows an admin
+    // instance to open and modify the event even if the system created it.
+    GetAdminDaclSecurityAttributes(&sa, GENERIC_ALL);
+  }
+  *event_handle = ::CreateEvent(&sa,
+                                true,   // manual reset
+                                false,  // not signaled
+                                event_name);
+
+  if (!*event_handle) {
+    DWORD error = ::GetLastError();
+    SETUP_LOG(LEVEL_ERROR, (_T("[::CreateEvent failed][%u]"), error));
+    return HRESULT_FROM_WIN32(error);
+  }
+
+  return S_OK;
+}
+
+void Setup::ReleaseShutdownEvents() {
+  VERIFY1(::ResetEvent(get(shutdown_event_)));
+  reset(shutdown_event_);
+  VERIFY1(::ResetEvent(get(legacy_1_0_shutdown_event_)));
+  reset(legacy_1_0_shutdown_event_);
+  VERIFY1(::ResetEvent(get(legacy_1_1_shutdown_event_)));
+  reset(legacy_1_1_shutdown_event_);
+}
+
+void Setup::SetSetupCompleteEvent() const {
+  scoped_event complete_event;
+  HRESULT hr = goopdate_utils::OpenUniqueEventFromEnvironment(
+      kSetupCompleteEventEnvironmentVariableName,
+      is_machine_,
+      address(complete_event));
+
+  if (FAILED(hr)) {
+    // We just will not be able to release the lock early.
+    return;
+  }
+
+  ASSERT1(complete_event);
+  VERIFY1(::SetEvent(get(complete_event)));
+}
+
+// Because this waiting can occur before a UI is generated, we do not want to
+// wait too long.
+// If a process fails to stop, its mode is stored in extra_code1_.
+// Does not return until all opened handles have been closed.
+// TODO(omaha): Add a parameter to specify the amount of time to wait to this
+// method and StopGoogleUpdateAndWait after we unify Setup and always have a UI.
+HRESULT Setup::WaitForOtherInstancesToExit(const Pids& pids) {
+  OPT_LOG(L1, (_T("[Waiting for other instances to exit]")));
+
+  // Wait for all the processes to exit.
+  std::vector<HANDLE> handles;
+  for (size_t i = 0; i < pids.size(); ++i) {
+    SETUP_LOG(L2, (_T("[Waiting for process][%u]"), pids[i]));
+
+    DWORD desired_access =
+        PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE;
+    scoped_handle handle(::OpenProcess(desired_access,
+                                       FALSE,
+                                       pids[i]));
+    if (!handle) {
+      HRESULT hr = HRESULTFromLastError();
+      SETUP_LOG(LE, (_T("[::OpenProcess failed][%u][0x%08x]"), pids[i], hr));
+      continue;
+    }
+
+    handles.push_back(release(handle));
+  }
+
+  HRESULT hr = S_OK;
+  if (!handles.empty()) {
+    SETUP_LOG(L2, (_T("[Calling ::WaitForMultipleObjects]")));
+
+    // In the /install case, there is no UI so we cannot wait too long.
+    // In other cases, we are silent or some other app is displaying a UI.
+    const int shutdown_wait_ms = IsInteractiveInstall() ?
+                                 kSetupShutdownWaitMsInteractiveNoUi :
+                                 kSetupShutdownWaitMsSilent;
+    HighresTimer metrics_timer;
+    DWORD res = ::WaitForMultipleObjects(handles.size(),
+                                         &handles.front(),
+                                         true,  // wait for all
+                                         shutdown_wait_ms);
+    metric_setup_process_wait_ms.AddSample(metrics_timer.GetElapsedMs());
+
+    SETUP_LOG(L2, (_T("[::WaitForMultipleObjects returned]")));
+    ASSERT1(WAIT_OBJECT_0 == res || WAIT_TIMEOUT == res);
+    if (WAIT_FAILED == res) {
+      DWORD error = ::GetLastError();
+      SETUP_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));
+      hr = HRESULT_FROM_WIN32(error);
+    } else if (WAIT_OBJECT_0 != res) {
+      OPT_LOG(LEVEL_ERROR, (_T("[Other GoogleUpdate.exe instances failed to ")
+                            _T("shutdown in time][%u]"), res));
+
+      extra_code1_ = COMMANDLINE_MODE_UNKNOWN;
+
+      SETUP_LOG(L2, (_T("[Listing processes that did not exit. This may be ")
+                    _T("incomplete if processes exited after ")
+                    _T("WaitForMultipleObjects returned.]")));
+      for (size_t i = 0; i < handles.size(); ++i) {
+        if (WAIT_TIMEOUT == ::WaitForSingleObject(handles[i], 0)) {
+          uint32 pid = Process::GetProcessIdFromHandle(handles[i]);
+          if (!pid) {
+            SETUP_LOG(LW, (_T(" [Process::GetProcessIdFromHandle failed][%u]"),
+                          ::GetLastError()));
+            SETUP_LOG(L2, (_T(" [Process did not exit][unknown]")));
+            continue;
+          }
+          SETUP_LOG(L2, (_T(" [Process did not exit][%u]"), pid));
+
+          CommandLineMode mode(COMMANDLINE_MODE_UNKNOWN);
+          if (SUCCEEDED(GetProcessModeFromPid(pid, &mode))) {
+            extra_code1_ = mode;
+          }
+          IncrementProcessWaitFailCount(mode);
+        }
+      }
+
+      ++metric_setup_process_wait_failed;
+      hr = GOOPDATE_E_INSTANCES_RUNNING;
+    }
+  }
+  if (SUCCEEDED(hr)) {
+    SETUP_LOG(L3, (_T("[Wait for all processes to exit succeeded]")));
+  }
+
+  // Close the handles.
+  for (size_t i = 0; i < handles.size(); ++i) {
+    if (!::CloseHandle(handles[i])) {
+      HRESULT hr = HRESULTFromLastError();
+      SETUP_LOG(LEVEL_WARNING, (_T("[CloseHandle failed][0x%08x]"), hr));
+    }
+  }
+
+  return hr;
+}
+
+// Wait for all instances of Omaha running as the current user - or SYSTEM for
+// machine installs - except "/install" instances, which should be blocked by
+// the Setup Lock, which we are holding.
+// For machine installs, also wait for instances running with ("/handoff" OR
+// "/ig") AND "needsadmin=True" running as any user. These instances are
+// installing a machine app as a non-SYSTEM user and may also cause conflicts.
+HRESULT Setup::GetPidsToWaitFor(Pids* pids) const {
+  ASSERT1(pids);
+
+  HRESULT hr = GetPidsToWaitForUsingCommandLine(pids);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  SETUP_LOG(L3, (_T("[found %d processes using cmd line]"), pids->size()));
+
+  // Remove any copies of the current PID from the list. This can happen when
+  // doing self-updates.
+  const uint32 current_pid = ::GetCurrentProcessId();
+  Pids::iterator it = std::remove(pids->begin(), pids->end(), current_pid);
+  if (pids->end() != it) {
+    SETUP_LOG(L2, (_T("[removing current PID from list of PIDs]")));
+  }
+  pids->erase(it, pids->end());
+
+  SETUP_LOG(L3, (_T("[found %d total processes to wait for]"), pids->size()));
+
+  return S_OK;
+}
+
+// Finds legacy processes to wait for based on the command line.
+HRESULT Setup::GetPidsToWaitForUsingCommandLine(Pids* pids) const {
+  ASSERT1(pids);
+
+  CString user_sid;
+  HRESULT hr = GetAppropriateSid(&user_sid);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Get all processes running as the current user/SYSTEM except those with
+  // * "/install" - must be excluded because may be waiting for the Setup Lock.
+  // * "/registerproduct" - same as for /install.
+  // * "/installelevated" OR "/ui" - legacy switches used only for machine
+  //   installs but ran as user and could cause false positives. For machine
+  //   installs, we look for these running as any user in a separate search.
+  std::vector<CString> command_lines;
+  CString switch_to_exclude;
+  switch_to_exclude.Format(_T("/%s"), kCmdLineInstall);
+  command_lines.push_back(switch_to_exclude);
+  switch_to_exclude.Format(_T("/%s"), kCmdLineRegisterProduct);
+  command_lines.push_back(switch_to_exclude);
+  switch_to_exclude.Format(_T("/%s"), kCmdLineLegacyVistaInstall);
+  command_lines.push_back(switch_to_exclude);
+  switch_to_exclude.Format(_T("/%s"), kCmdLineLegacyUi);
+  command_lines.push_back(switch_to_exclude);
+
+  DWORD flags = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |
+                EXCLUDE_CURRENT_PROCESS |
+                EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
+  Pids found_pids;
+  hr = Process::FindProcesses(flags,
+                              kGoopdateFileName,
+                              true,
+                              user_sid,
+                              command_lines,
+                              &found_pids);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));
+    return hr;
+  }
+  for (size_t i = 0; i < found_pids.size(); ++i) {
+    pids->push_back(found_pids[i]);
+  }
+
+  // Get all processes running as any user with:
+  // * "/handoff" or "/ig" and"needsadmin=True"
+  // * "-Embedding" and running from machine install location.
+  std::vector<uint32> machine_install_worker_pids;
+  hr = goopdate_utils::GetInstallWorkerProcesses(true,
+                                                 &machine_install_worker_pids);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[GetInstallWorkerProcesses failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (is_machine_) {
+    // Add all machine install worker pids to the list of pids to wait for.
+    for (size_t i = 0; i < machine_install_worker_pids.size(); ++i) {
+      pids->push_back(machine_install_worker_pids[i]);
+    }
+  } else {
+    // Remove machine install worker pids from the list of pids to wait for.
+    for (size_t i = 0; i < machine_install_worker_pids.size(); ++i) {
+      std::vector<uint32>::iterator iter = find(pids->begin(),
+                                                pids->end(),
+                                                machine_install_worker_pids[i]);
+      if (pids->end() != iter) {
+        pids->erase(iter);
+      }
+    }
+  }
+
+  if (is_machine_) {
+    // Find legacy machine install processes that run as user. Check all users.
+    std::vector<CString> legacy_machine_command_lines;
+    CString switch_to_include;
+    switch_to_include.Format(_T("/%s"), kCmdLineLegacyVistaInstall);
+    command_lines.push_back(switch_to_include);
+    switch_to_include.Format(_T("/%s"), kCmdLineLegacyUi);
+    command_lines.push_back(switch_to_include);
+
+    DWORD flags = EXCLUDE_CURRENT_PROCESS |
+                  INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
+    Pids found_legacy_machine_pids;
+    hr = Process::FindProcesses(flags,
+                                kGoopdateFileName,
+                                true,
+                                user_sid,
+                                legacy_machine_command_lines,
+                                &found_legacy_machine_pids);
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));
+      return hr;
+    }
+    for (size_t i = 0; i < found_legacy_machine_pids.size(); ++i) {
+      // Because we excluded these processes in the first search, we should not
+      // get any duplicates.
+      ASSERT1(found_pids.end() ==
+              std::find(found_pids.begin(),
+                        found_pids.end(),
+                        found_legacy_machine_pids[i]));
+      pids->push_back(found_legacy_machine_pids[i]);
+    }
+  }
+
+  return S_OK;
+}
+
+// On Windows Vista, an admin must be elevated in order to install a machine app
+// without elevating. On Vista, IsUserAdmin returns false unless the user is
+// elevated.
+bool Setup::IsElevationRequired() const {
+  return is_machine_ && !vista_util::IsUserAdmin();
+}
+
+// The behavior depends on the OS:
+//  1. OS >= Vista : Try to elevate - causes a UAC dialog.
+//  2. OS < Vista  : Fail with a message box.
+// We should be here only in case of initial machine installs when the user is
+// not an elevated admin.
+HRESULT Setup::ElevateAndWait(const CString& cmd_line) {
+  OPT_LOG(L1, (_T("[Elevating][%s]"), cmd_line));
+  ASSERT1(is_machine_);
+  ASSERT1(!vista_util::IsUserAdmin());
+  ASSERT1(MODE_INSTALL == mode_);
+
+  if (!IsInteractiveInstall()) {
+    return GOOPDATE_E_SILENT_INSTALL_NEEDS_ELEVATION;
+  }
+
+  if (args_->is_install_elevated) {
+    // This can happen if UAC is disabled. See http://b/1187784.
+    SETUP_LOG(LE, (_T("[Install elevated process requires elevation]")));
+    return GOOPDATE_E_INSTALL_ELEVATED_PROCESS_NEEDS_ELEVATION;
+  }
+
+  if (!vista_util::IsVistaOrLater()) {
+    // TODO(omaha): We could consider to ask for credentials here.
+    // This TODO existed in Omaha 1. How would we even do this?
+    SETUP_LOG(LE, (_T("[Non Admin trying to install admin app]")));
+    ++metric_setup_machine_app_non_admin;
+    return GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP;
+  }
+
+  CString cmd_line_elevated(GetCmdLineTail(cmd_line));
+  cmd_line_elevated.AppendFormat(_T(" /%s"), kCmdLineInstallElevated);
+
+  HRESULT hr = goopdate_utils::StartElevatedSelfWithArgsAndWait(
+      cmd_line_elevated);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Starting elevated GoogleUpdate.exe failed][%s][0x%08x]"),
+                 cmd_line, hr));
+
+    extra_code1_ = hr;
+    if (vista_util::IsUserNonElevatedAdmin()) {
+      return GOOPDATE_E_ELEVATION_FAILED_ADMIN;
+    } else {
+      return GOOPDATE_E_ELEVATION_FAILED_NON_ADMIN;
+    }
+  }
+
+  // TODO(omaha): we might have to look at the exit_code from above.
+  // Do not know what we should do in case of an error.
+
+  return S_OK;
+}
+
+HRESULT Setup::CopyOfflineFilesForGuid(const CString& app_guid,
+                                       const CString& offline_dir) {
+  SETUP_LOG(L3, (_T("[Setup::CopyOfflineFilesForGuid][%s][%s]"),
+                 app_guid, offline_dir));
+
+  CPath setup_temp_dir(app_util::GetCurrentModuleDirectory());
+
+  // Copy offline manifest into "Google\Update\Offline\{guid}.gup".
+  CString manifest_filename = app_guid + _T(".gup");
+  CString source_manifest_path = ConcatenatePath(setup_temp_dir,
+                                                 manifest_filename);
+  if (!File::Exists(source_manifest_path)) {
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+  if (!File::IsDirectory(offline_dir)) {
+    VERIFY1(SUCCEEDED(CreateDir(offline_dir, NULL)));
+  }
+  CString dest_manifest_path = ConcatenatePath(offline_dir,
+                                               manifest_filename);
+  HRESULT hr = File::Copy(source_manifest_path, dest_manifest_path, true);
+  if (FAILED(hr)) {
+    SETUP_LOG(L4, (_T("[File copy failed][%s][%s][0x%x]"),
+                   source_manifest_path, dest_manifest_path, hr));
+    return hr;
+  }
+
+  CString pattern;
+  // Find the installer file. "Installer.exe.{guid}". Only one file per guid is
+  // supported. Store "Installer.exe" in the directory
+  // "Google\Update\Offline\{guid}".
+  pattern.Format(_T("*.%s"), app_guid);
+  std::vector<CString> files;
+  hr = FindFiles(setup_temp_dir, pattern, &files);
+  if (FAILED(hr)) {
+    SETUP_LOG(L4, (_T("[FindFiles failed][0x%x]"), hr));
+    return hr;
+  }
+  if (files.empty()) {
+    SETUP_LOG(L4, (_T("[FindFiles found no files]")));
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+
+  ASSERT1(files.size() == 1);
+  ASSERT1(files[0].GetLength() > app_guid.GetLength());
+
+  CString file_path = ConcatenatePath(setup_temp_dir, files[0]);
+  CString renamed_file_name = files[0].Left(files[0].GetLength() -
+                                            app_guid.GetLength() - 1);
+  CString offline_app_dir = ConcatenatePath(offline_dir, app_guid);
+  CString new_file_path = ConcatenatePath(offline_app_dir, renamed_file_name);
+  SETUP_LOG(L4, (_T("[new_file_path][%s]"), new_file_path));
+
+  if (File::IsDirectory(offline_app_dir)) {
+    VERIFY1(SUCCEEDED(DeleteDirectoryFiles(offline_app_dir)));
+  } else {
+    hr = CreateDir(offline_app_dir, NULL);
+    if (FAILED(hr)) {
+      SETUP_LOG(L3, (_T("[CreateDir failed][%s]"), offline_app_dir));
+      return hr;
+    }
+  }
+
+  return File::Copy(file_path, new_file_path, false);
+}
+
+bool Setup::CopyOfflineFiles(const CString& offline_dir) {
+  SETUP_LOG(L3, (_T("[Setup::CopyOfflineFiles][%s]"), offline_dir));
+
+  ASSERT1(!args_->extra.apps.empty());
+  if (args_->extra.apps.empty()) {
+    return false;
+  }
+
+  for (size_t i = 0; i < args_->extra.apps.size(); ++i) {
+    const GUID& app_guid = args_->extra.apps[i].app_guid;
+    HRESULT hr = CopyOfflineFilesForGuid(GuidToString(app_guid), offline_dir);
+    if (FAILED(hr)) {
+      SETUP_LOG(L3, (_T("[CopyOfflineFilesForGuid failed][0x%x]"), hr));
+      return false;
+    }
+  }
+
+  return true;
+}
+
+// The installed worker is in the final location and can access the network to
+// provide stats and error information.
+// worker_pi can be NULL.
+// TODO(omaha): Extract the command line building and unit test it.
+// Starts the file that was just installed or the registered version of Google
+// Update depending on whether Google Update is being installed
+// (do_setup_phase_2).
+// If do_setup_phase_2 is true, assumes the new version has been set in the
+// registry.
+// SelfInstall uses UG with the /machine override because UG silently completes
+// setup without installing an app and SelfInstall may not be running as
+// LocalSystem.
+// Detects whether this is an offline install and stages the files
+// appropriately.
+// Reports errors when when offline files are not present for scenarios that
+// require offline installs.
+HRESULT Setup::LaunchInstalledWorker(bool do_setup_phase_2, HANDLE* process) {
+  SETUP_LOG(L2, (_T("[Setup::LaunchInstalledWorker]")));
+
+  bool is_offline = false;
+  CommandLineMode cmd_line_mode = COMMANDLINE_MODE_UNKNOWN;
+  if (MODE_INSTALL == mode_) {
+    // If offline binaries are found the program enters the offline mode.
+    is_offline = CopyOfflineFiles(is_machine_ ?
+        ConfigManager::Instance()->GetMachineSecureOfflineStorageDir() :
+        ConfigManager::Instance()->GetUserOfflineStorageDir());
+    cmd_line_mode = do_setup_phase_2 ? COMMANDLINE_MODE_IG :
+                                       COMMANDLINE_MODE_HANDOFF_INSTALL;
+  } else {
+    ASSERT1(!args_->is_oem_set);
+    cmd_line_mode = COMMANDLINE_MODE_UG;
+  }
+
+  CommandLineBuilder builder(cmd_line_mode);
+  if (is_offline) {
+    builder.set_is_offline_set(is_offline);
+    // If installsource is present on the command line, it will override this.
+    builder.set_install_source(kCmdLineInstallSource_Offline);
+  } else if (args_->is_oem_set) {
+    return GOOPDATE_E_OEM_WITH_ONLINE_INSTALLER;
+  } else if (args_->is_eula_required_set) {
+    return GOOPDATE_E_EULA_REQURED_WITH_ONLINE_INSTALLER;
+  }
+
+  switch (mode_) {
+    case MODE_INSTALL:
+      builder.set_is_silent_set(args_->is_silent_set);
+      builder.set_is_eula_required_set(args_->is_eula_required_set);
+      ASSERT1(!args_->extra_args_str.IsEmpty());
+      builder.set_extra_args(args_->extra_args_str);
+      builder.set_app_args(args_->app_args_str);
+      if (!args_->install_source.IsEmpty()) {
+        builder.set_install_source(args_->install_source);
+      }
+      break;
+    case MODE_SELF_UPDATE:
+      ASSERT1(do_setup_phase_2);
+      ASSERT1(args_->extra_args_str.IsEmpty());
+      break;
+    case MODE_SELF_INSTALL:
+      ASSERT1(do_setup_phase_2);
+      ASSERT1(!args_->extra_args_str.IsEmpty());
+      builder.set_is_machine_set(is_machine_);
+      break;
+    case MODE_REPAIR:
+      ASSERT1(do_setup_phase_2);
+      ASSERT1(args_->extra_args_str.IsEmpty());
+      builder.set_is_machine_set(is_machine_);
+      break;
+    case MODE_UNKNOWN:
+    case MODE_PHASE2:
+    case MODE_UNINSTALL:
+    default:
+      ASSERT1(false);
+      break;
+  }
+
+  CString cmd_line = builder.GetCommandLineArgs();
+
+  HRESULT hr = goopdate_utils::StartGoogleUpdateWithArgs(is_machine_,
+                                                         cmd_line,
+                                                         process);
+  if (FAILED(hr)) {
+    if (do_setup_phase_2) {
+      OPT_LOG(LE, (_T("[Starting Google Update failed][%s][0x%08x]"),
+                   cmd_line, hr));
+      ASSERT1(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr);
+      return hr;
+    } else {
+      OPT_LOG(LE, (_T("[Google Update hand off failed][%s][0x%08x]"),
+                   cmd_line, hr));
+      extra_code1_ = hr;
+      return GOOPDATE_E_HANDOFF_FAILED;
+    }
+  }
+
+  launched_offline_worker_ = is_offline;
+
+  return S_OK;
+}
+
+// Start the machine core process using one of the launch mechanisms.
+// We know that at least one of the service and scheduled task were installed
+// because otherwise we would have exited fatally.
+// If the service was not installed, starting it will just fail silently and we
+// will start the scheduled task.
+// do not call this method until the shutdown event has been released or the
+// process may immediately exit.
+// TODO(omaha): Provide service_hr and task_hr failures in a ping.
+HRESULT Setup::StartMachineCoreProcess() const {
+  SETUP_LOG(L3, (_T("[Setup::StartMachineCoreProcess]")));
+
+  HighresTimer metrics_timer;
+
+  // Start the service.
+  ++metric_setup_start_service_total;
+  HRESULT service_hr = SetupService::StartService();
+  if (SUCCEEDED(service_hr)) {
+    metric_setup_start_service_ms.AddSample(metrics_timer.GetElapsedMs());
+    OPT_LOG(L1, (_T("[Service started]")));
+    ++metric_setup_start_service_succeeded;
+    return S_OK;
+  }
+  metric_setup_start_service_failed_ms.AddSample(metrics_timer.GetElapsedMs());
+  OPT_LOG(LEVEL_ERROR, (_T("[Start service failed][0x%08x]"), service_hr));
+  metric_setup_start_service_error = service_hr;
+
+  // TODO(omaha): We should only skip this block when /install /silent fails
+  // and there are no other apps installed. Guarantee this somehow.
+  ++metric_setup_start_task_total;
+  const ULONGLONG start_task_start_ms = metrics_timer.GetElapsedMs();
+  HRESULT task_hr = goopdate_utils::StartGoopdateTaskCore(true);
+  if (SUCCEEDED(task_hr)) {
+    const ULONGLONG start_task_end_ms = metrics_timer.GetElapsedMs();
+    ASSERT1(start_task_end_ms >= start_task_start_ms);
+    metric_setup_start_task_ms.AddSample(
+        start_task_end_ms - start_task_start_ms);
+    OPT_LOG(L1, (_T("[run scheduled task succeeded]")));
+    ++metric_setup_start_task_succeeded;
+    return S_OK;
+  }
+  OPT_LOG(LE, (_T("[Start scheduled task failed][0x%08x]"), task_hr));
+  metric_setup_start_task_error = task_hr;
+
+  return service_hr;
+}
+
+// Start the user core process directly.
+// do not call this method until the shutdown event has been released or the
+// process may immediately exit.
+HRESULT Setup::StartUserCoreProcess(const CString& core_cmd_line) const {
+  HRESULT hr = System::ShellExecuteCommandLine(core_cmd_line, NULL, NULL);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[Could not start Google Update Core][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT Setup::FindCoreProcesses(Pids* found_core_pids) const {
+  SETUP_LOG(L3, (_T("[Setup::FindCoreProcesses]")));
+  ASSERT1(found_core_pids);
+
+  CString user_sid;
+  HRESULT hr = GetAppropriateSid(&user_sid);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  std::vector<CString> command_lines;
+  CString switch_to_include;
+  switch_to_include.Format(_T("/%s"), kCmdLineCore);
+  command_lines.push_back(switch_to_include);
+
+  DWORD flags = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |
+                EXCLUDE_CURRENT_PROCESS |
+                INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
+  hr = Process::FindProcesses(flags,
+                              kGoopdateFileName,
+                              true,
+                              user_sid,
+                              command_lines,
+                              found_core_pids);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Remove PIDs where the command line is not actually the "/c" switch and is
+  // some other command line, such as "/cr".
+  const Pids::iterator new_end = std::remove_if(
+      found_core_pids->begin(),
+      found_core_pids->end(),
+      std::not1(std::ptr_fun(IsCoreProcess)));
+  if (new_end != found_core_pids->end()) {
+    found_core_pids->erase(new_end, found_core_pids->end());
+  }
+
+  SETUP_LOG(L2, (_T("[Core processes found][%u]"), found_core_pids->size()));
+  return S_OK;
+}
+
+// Does not try to terminate legacy processes.
+// Waits up to 500 ms for the terminated core processes to exit.
+HRESULT Setup::TerminateCoreProcesses() const {
+  SETUP_LOG(L2, (_T("[Setup::TerminateCoreProcesses]")));
+  Pids found_core_pids;
+  HRESULT hr = FindCoreProcesses(&found_core_pids);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[FindCoreProcesses failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  std::vector<HANDLE> terminated_processes;
+  for (size_t i = 0; i < found_core_pids.size(); ++i) {
+    uint32 pid = found_core_pids[i];
+
+    SETUP_LOG(L2, (_T("[Terminating core process][%u]"), pid));
+
+    HANDLE process(::OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, pid));
+    if (!process) {
+      SETUP_LOG(LW, (_T("[::OpenProcess failed][%u][%u]"),
+                     pid, ::GetLastError()));
+      continue;
+    }
+    terminated_processes.push_back(process);
+
+    if (!::TerminateProcess(process, static_cast<uint32>(-2))) {
+      SETUP_LOG(LW, (_T("[::TerminateProcess failed][%u][%u]"),
+                     pid, ::GetLastError()));
+    }
+  }
+
+  if (terminated_processes.empty()) {
+    return S_OK;
+  }
+  // Do not return until the handles have been closed.
+
+  const int kCoreTerminateWaitMs = 500;
+  DWORD res = ::WaitForMultipleObjects(terminated_processes.size(),
+                                       &terminated_processes.front(),
+                                       true,  // wait for all
+                                       kCoreTerminateWaitMs);
+  SETUP_LOG(L2, (_T("[::WaitForMultipleObjects returned]")));
+  ASSERT1(WAIT_OBJECT_0 == res || WAIT_TIMEOUT == res);
+  if (WAIT_FAILED == res) {
+    DWORD error = ::GetLastError();
+    SETUP_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));
+    hr = HRESULT_FROM_WIN32(error);
+  } else {
+    hr = HRESULT_FROM_WIN32(res);
+  }
+
+  for (size_t i = 0; i < terminated_processes.size(); ++i) {
+    VERIFY1(::CloseHandle(terminated_processes[i]));
+  }
+
+  return hr;
+}
+
+// Tries to start the core using existing launch methods if present.
+// Uses the the service registry value, scheduled task, and Run key value names
+// for this version; if the ones in the installed version are are different,
+// this method will not be able to start the core.
+HRESULT Setup::StartCore() const {
+  SETUP_LOG(L2, (_T("[Attempting to start existing core]")));
+
+  if (is_machine_) {
+    HRESULT hr = StartMachineCoreProcess();
+    if (FAILED(hr)) {
+      SETUP_LOG(LW, (_T("[StartMachineCoreProcess failed][0x%08x]"), hr));
+      return hr;
+    }
+  } else {
+    // Read the Run key entry to determine how to run the version that we
+    // believe is installed, which may not be this instance's version or even
+    // the the version in the registry if it has been over-written by us.
+    CString run_key_path = AppendRegKeyPath(USER_KEY_NAME, REGSTR_PATH_RUN);
+    RegKey key;
+    HRESULT hr = key.Open(run_key_path);
+    if (FAILED(hr)) {
+      SETUP_LOG(LW, (_T("[Failed to open Run key][%s][0x%08x]"),
+                     run_key_path, hr));
+      return hr;
+    }
+
+    CString installed_run_cmd_line;
+    hr = key.GetValue(kRunValueName, &installed_run_cmd_line);
+    if (FAILED(hr)) {
+      SETUP_LOG(LW, (_T("[Failed to get Run value][%s][0x%08x]"),
+                     kRunValueName, hr));
+      return hr;
+    }
+
+    hr = StartUserCoreProcess(installed_run_cmd_line);
+    if (FAILED(hr)) {
+      SETUP_LOG(LW, (_T("[StartUserCoreProcess failed][%s][0x%08x]"),
+                     installed_run_cmd_line, hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+// If the process exits without signaling the event, its exit code is returned.
+// Waits for the process to exit (and ignore the event) unless this is an
+// interactive install.
+// If event is NULL, waits for the process to exit.
+HRESULT Setup::WaitForProcessExitOrEvent(HANDLE process,
+                                         HANDLE event,
+                                         uint32* exit_code) const {
+  SETUP_LOG(L3, (_T("[Setup::WaitForProcessExitOrEvent]")));
+  ASSERT1(process);
+  ASSERT1(exit_code);
+  *exit_code = 0;
+
+  const bool include_event_in_wait = event && !ShouldWaitForWorkerProcess();
+  HANDLE handles[] = {process, event};
+
+  const int num_handles = arraysize(handles) - (include_event_in_wait ? 0 : 1);
+  const int kProcessSignaled = WAIT_OBJECT_0;
+  const int kEventSignaled = WAIT_OBJECT_0 + 1;
+
+  int res = ::WaitForMultipleObjects(num_handles,
+                                     handles,
+                                     false,  // wait for any one
+                                     INFINITE);
+  ASSERT1(kProcessSignaled == res ||
+          (kEventSignaled == res) && include_event_in_wait);
+  if (WAIT_FAILED == res) {
+    DWORD error = ::GetLastError();
+    SETUP_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));
+    return HRESULT_FROM_WIN32(error);
+  }
+
+  // If the process exited, get the exit code.
+  if (kProcessSignaled == res) {
+    DWORD local_exit_code = 0;
+    if (::GetExitCodeProcess(process, &local_exit_code)) {
+      SETUP_LOG(L2, (_T("[process exited][PID %u][exit code 0x%08x]"),
+                    Process::GetProcessIdFromHandle(process), local_exit_code));
+      *exit_code = local_exit_code;
+    } else {
+      DWORD error = ::GetLastError();
+      SETUP_LOG(LE, (_T("[::GetExitCodeProcess failed][%u]"), error));
+      return HRESULT_FROM_WIN32(error);
+    }
+  } else {
+    ASSERT1(kEventSignaled == res);
+    ASSERT1(2 == num_handles);
+    SETUP_LOG(L2, (_T("[event received before process exited]")));
+  }
+
+  return S_OK;
+}
+
+// Requires that the UI displayed event and
+// kUiDisplayedEventEnvironmentVariableName environment variable exist.
+HRESULT Setup::WaitForHandoffWorker(HANDLE process) const {
+  HANDLE ui_displayed_event(INVALID_HANDLE_VALUE);
+  HRESULT hr = UIDisplayedEventManager::GetEvent(is_machine_,
+                                                 &ui_displayed_event);
+  if (FAILED(hr)) {
+    // The event was created in this process, so this should always succeed.
+    ASSERT(false, (_T("OpenUniqueEventFromEnvironment failed][0x%08x]"), hr));
+    // Only wait for the process to exit.
+  }
+
+  uint32 exit_code(0);
+  hr = WaitForProcessExitOrEvent(process, ui_displayed_event, &exit_code);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[WaitForProcessExitOrEvent failed][0x%08x]"), hr));
+    return hr;
+  }
+  if (exit_code) {
+    OPT_LOG(LE, (_T("[Handoff exited with error][0x%08x]"), exit_code));
+    ASSERT1(FAILED(exit_code));
+    return exit_code;
+  }
+
+  if (ui_displayed_event &&
+      WAIT_OBJECT_0 == ::WaitForSingleObject(ui_displayed_event, 0)) {
+    metric_setup_handoff_ui_ms.AddSample(metrics_timer_->GetElapsedMs());
+  }
+
+  return S_OK;
+}
+
+// Returns Local System's SID for machine installs and the user's SID otherwise.
+HRESULT Setup::GetAppropriateSid(CString* sid) const {
+  ASSERT1(sid);
+  if (is_machine_) {
+    *sid = kLocalSystemSid;
+  } else {
+    HRESULT hr = user_info::GetCurrentUser(NULL, NULL, sid);
+    if (FAILED(hr)) {
+      SETUP_LOG(LEVEL_ERROR, (_T("[GetCurrentUser failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+bool Setup::InitSetupLock(bool is_machine, GLock* setup_lock) {
+  ASSERT1(setup_lock);
+  NamedObjectAttributes setup_lock_attr;
+  GetNamedObjectAttributes(kSetupMutex, is_machine, &setup_lock_attr);
+  return setup_lock->InitializeWithSecAttr(setup_lock_attr.name,
+                                           &setup_lock_attr.sa);
+}
+
+bool Setup::InitLegacySetupLocks(GLock* lock10,
+                                 GLock* lock11_user,
+                                 GLock* lock11_machine) {
+  ASSERT1(lock10);
+  ASSERT1(lock11_user);
+  ASSERT1(lock11_machine);
+
+  // Omaha 1.0 ensures "there is only one instance of goopdate that is trying to
+  // install at a time." Thus, the lock is the same for machine and user.
+  CString mutex10_name(kOmaha10GlobalPrefix);
+  mutex10_name.Append(kSetupMutex);
+  bool is_initialized = lock10->Initialize(mutex10_name);
+  if (!is_initialized) {
+    extra_code1_ = kVersion10;
+    return false;
+  }
+
+  // Omaha 1.1. ensures "there is only one instance of goopdate per machine or
+  // per user that is trying to install at a time." It allowed installs by
+  // different users to be concurrent by using the Global and Local namespaces.
+  // The machine name was only used when running as Local System, so machine
+  // instances need to look for both the user and machine lock to prevent
+  // conflicts with initial installs running as the user.
+  CString lock11_user_name(kOmaha11LocalPrefix);
+  lock11_user_name.Append(kSetupMutex);
+  is_initialized = lock11_user->Initialize(lock11_user_name);
+  if (!is_initialized) {
+    extra_code1_ = kVersion11;
+    return false;
+  }
+
+  if (is_machine_) {
+    CString lock11_machine_name(kOmaha11GlobalPrefix);
+    lock11_machine_name.Append(kSetupMutex);
+    extra_code1_ = kVersion11MachineLock;
+    return lock11_machine->Initialize(lock11_machine_name);
+  } else {
+    return true;
+  }
+}
+
+void Setup::PersistUpdateErrorInfo(bool is_machine,
+                                   HRESULT error,
+                                   int extra_code1,
+                                   const CString& version) {
+  const TCHAR* update_key_name =
+      ConfigManager::Instance()->registry_update(is_machine);
+  VERIFY1(SUCCEEDED(RegKey::SetValue(update_key_name,
+                                     kRegValueSelfUpdateErrorCode,
+                                     static_cast<DWORD>(error))));
+  VERIFY1(SUCCEEDED(RegKey::SetValue(update_key_name,
+                                     kRegValueSelfUpdateExtraCode1,
+                                     static_cast<DWORD>(extra_code1))));
+  VERIFY1(SUCCEEDED(RegKey::SetValue(update_key_name,
+                                     kRegValueSelfUpdateVersion,
+                                     version)));
+}
+
+// Returns false if the values cannot be deleted to avoid skewing the log data
+// with a single user pinging repeatedly with the same data.
+bool Setup::ReadAndClearUpdateErrorInfo(bool is_machine,
+                                        DWORD* error_code,
+                                        DWORD* extra_code1,
+                                        CString* version) {
+  ASSERT1(error_code);
+  ASSERT1(extra_code1);
+  ASSERT1(version);
+
+  const TCHAR* update_key_name =
+      ConfigManager::Instance()->registry_update(is_machine);
+  RegKey update_key;
+  HRESULT hr = update_key.Open(update_key_name);
+  if (FAILED(hr)) {
+    ASSERT1(false);
+    return false;
+  }
+
+  if (!update_key.HasValue(kRegValueSelfUpdateErrorCode)) {
+    ASSERT1(!update_key.HasValue(kRegValueSelfUpdateExtraCode1));
+    return false;
+  }
+
+  VERIFY1(SUCCEEDED(update_key.GetValue(kRegValueSelfUpdateErrorCode,
+                                        error_code)));
+  ASSERT1(FAILED(*error_code));
+
+  VERIFY1(SUCCEEDED(update_key.GetValue(kRegValueSelfUpdateExtraCode1,
+                                        extra_code1)));
+
+  VERIFY1(SUCCEEDED(update_key.GetValue(kRegValueSelfUpdateVersion, version)));
+
+  if (FAILED(update_key.DeleteValue(kRegValueSelfUpdateErrorCode)) ||
+      FAILED(update_key.DeleteValue(kRegValueSelfUpdateExtraCode1)) ||
+      FAILED(update_key.DeleteValue(kRegValueSelfUpdateVersion))) {
+    ASSERT1(false);
+    return false;
+  }
+
+  return true;
+}
+
+bool Setup::HasXmlParser() {
+  CComPtr<IXMLDOMDocument> my_xmldoc;
+  HRESULT hr = CoCreateSafeDOMDocument(&my_xmldoc);
+  const bool ret = SUCCEEDED(hr);
+  CORE_LOG(L3, (_T("[Setup::HasXmlParser returned %d][0x%08x]"), ret, hr));
+  return ret;
+}
+
+// Assumes that the Setup Lock is held.
+// This method is based on the assumption that if another install, which could
+// be modifying the number of clients, is in progress, that it either:
+//  (a) Has the Setup Lock, which is not possible because this process has it.
+//  (b) Has started an install worker.
+bool Setup::CanUninstallGoogleUpdate() const {
+  CORE_LOG(L2, (_T("[Setup::CanUninstallGoogleUpdate]")));
+  if (goopdate_utils::IsAppInstallWorkerRunning(is_machine_)) {
+    CORE_LOG(L2, (_T("[Found install workers. Not uninstalling]")));
+    return false;
+  }
+  size_t num_clients(0);
+  if (SUCCEEDED(goopdate_utils::GetNumClients(is_machine_, &num_clients)) &&
+      num_clients >= 2) {
+    CORE_LOG(L3, (_T("[Found products. Not uninstalling]")));
+    return false;
+  }
+  return true;
+}
+
+bool Setup::IsInteractiveInstall() const {
+  return (MODE_INSTALL == mode_) && !args_->is_silent_set;
+}
+
+// The result of this method is only valid after the worker has been launched.
+// The /install instance should wait for worker process (/ig or /handoff) if:
+//  * Running silently: The exit code is only indication of install result.
+//  * Offline install: The main reason we exit early normally is to release the
+//    Setup Locks and allow downloads for multiple app installs to occur
+//    simultaneously. Since offline installers do not download, this is less of
+//    a concern. Also, Pack launches the offline installer interactively if the
+//    user chooses to retry after a failure. See http://b/1543716.
+// Long term, we will refactor the locking and always wait for the worker.
+bool Setup::ShouldWaitForWorkerProcess() const {
+  return !IsInteractiveInstall() || launched_offline_worker_;
+}
+
+HRESULT Setup::SetOemInstallState() {
+  ASSERT1(MODE_INSTALL == mode_);
+  ASSERT1(args_->is_oem_set);
+
+  if (!is_machine_ ||
+      IsElevationRequired() ||
+      !ConfigManager::Instance()->IsWindowsInstalling()) {
+    return GOOPDATE_E_OEM_NOT_MACHINE_AND_PRIVILEGED_AND_AUDIT_MODE;
+  }
+
+  const DWORD now = Time64ToInt32(GetCurrent100NSTime());
+  OPT_LOG(L1, (_T("[Beginning OEM install][%u]"), now));
+  HRESULT hr = RegKey::SetValue(
+      ConfigManager::Instance()->machine_registry_update(),
+      kRegValueOemInstallTimeSec,
+      now);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  ASSERT1(ConfigManager::Instance()->IsOemInstalling(is_machine_));
+
+  return S_OK;
+}
+
+HRESULT Setup::SetEulaAccepted(bool is_machine) {
+  SETUP_LOG(L4, (_T("[SetEulaAccepted][%d]"), is_machine));
+  const TCHAR* update_key_name =
+      ConfigManager::Instance()->registry_update(is_machine);
+  return RegKey::HasKey(update_key_name) ?
+      RegKey::DeleteValue(update_key_name, kRegValueOmahaEulaAccepted) :
+      S_OK;
+}
+
+// Does not write the registry if Google Update is already installed as
+// determined by the presence of 2 or more registered apps. In those cases, we
+// assume the existing EULA state is correct and do not want to disable updates
+// for an existing installation.
+// Assumes it is called with appropriate synchronization protection such that it
+// can reliably check the number of registered clients.
+HRESULT Setup::SetEulaNotAccepted(bool is_machine) {
+  SETUP_LOG(L4, (_T("[SetEulaNotAccepted][%d]"), is_machine));
+
+  size_t num_clients(0);
+  if (SUCCEEDED(goopdate_utils::GetNumClients(is_machine, &num_clients)) &&
+      num_clients >= 2) {
+    SETUP_LOG(L4, (_T(" [Apps registered. Not setting eulaaccepted=0.]")));
+    return S_OK;
+  }
+
+  const ConfigManager* cm = ConfigManager::Instance();
+  return RegKey::SetValue(cm->registry_update(is_machine),
+                          kRegValueOmahaEulaAccepted,
+                          static_cast<DWORD>(0));
+}
+
+}  // namespace omaha
diff --git a/setup/setup.h b/setup/setup.h
index 2799708..ba66b77 100644
--- a/setup/setup.h
+++ b/setup/setup.h
@@ -1,290 +1,290 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// There are two phases of setup:

-//  1) Copy the Google Update files to the install location.

-//   * Executed by InstallGoogleUpdateAndApp().

-//   * This is done in an instance running from a temp location.

-//  2) Do everything else to install Google Update.

-//   * Executed by SetupGoogleUpdate().

-//   * This is done in an instance running from the installed location.

-//

-//  Uninstall() undoes both phases of setup.

-//  All methods assume the instance is running with the correct permissions.

-

-#ifndef OMAHA_SETUP_SETUP_H__

-#define OMAHA_SETUP_SETUP_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/scoped_any.h"

-

-namespace omaha {

-

-class GLock;

-class HighresTimer;

-struct NamedObjectAttributes;

-

-struct CommandLineArgs;

-class SetupFiles;

-

-class Setup {

- public:

-  Setup(bool is_machine, const CommandLineArgs* args);

-  ~Setup();

-

-  // Installs Google Update, if necessary, and launches a worker to install app.

-  // Handles elevation.

-  HRESULT Install(const CString& cmd_line);

-

-  // Installs Google Update silently without installing an app.

-  HRESULT InstallSelfSilently();

-

-  // Updates Google Update.

-  HRESULT UpdateSelfSilently();

-

-  // Repairs Google Update for Code Red recovery.

-  HRESULT RepairSilently();

-

-  // Completes installation from the installed location.

-  HRESULT SetupGoogleUpdate();

-

-  // Obtains the Setup Lock and uninstalls all Google Update versions if

-  // Google Update can be uninstalled.

-  HRESULT Uninstall();

-

-  // Verifies that Google Update is either properly installed or uninstalled

-  // completely. Returns whether Google Update is installed.

-  // TODO(omaha): Consider making this and did_uninstall_ non-static after

-  // refactoring Setup phases. May require a Setup member in Goopdate.

-  static void CheckInstallStateConsistency(bool is_machine);

-

-  // Writes error info for silent updates to the registry so the installed Omaha

-  // can send an update failed ping.

-  static void PersistUpdateErrorInfo(bool is_machine,

-                                     HRESULT error,

-                                     int extra_code1,

-                                     const CString& version);

-

-  // Reads the error info for silent updates from the registry if present and

-  // deletes it. Returns true if the data is valid.

-  static bool ReadAndClearUpdateErrorInfo(bool is_machine,

-                                          DWORD* error_code,

-                                          DWORD* extra_code1,

-                                          CString* version);

-

-  // Marks Google Update EULA as accepted by deleting the registry value.

-  // Does not touch apps' EULA state.

-  static HRESULT SetEulaAccepted(bool is_machine);

-

-  int extra_code1() const { return extra_code1_; }

-

- private:

-  // Defines the mode of the instance.

-  enum Mode {

-    MODE_UNKNOWN,

-    MODE_INSTALL,

-    MODE_SELF_INSTALL,

-    MODE_SELF_UPDATE,

-    MODE_REPAIR,

-    MODE_PHASE2,

-    MODE_UNINSTALL,

-  };

-

-  typedef std::vector<uint32> Pids;

-

-  // Does all non-elevation work for Install().

-  HRESULT DoInstall();

-

-  // Handles Setup lock acquisition failures and returns the error to report.

-  HRESULT HandleLockFailed(int lock_version);

-

-  // Does the install work within all necessary locks, which have already been

-  // obtained.

-  // If handoff_process is not NULL on a successful return, the caller should

-  // wait for this process after releasing the locks.

-  HRESULT DoProtectedInstall(HANDLE* handoff_process);

-

-  // Uninstalls all Google Update versions after checking if Google Update can

-  // be uninstalled.

-  HRESULT DoProtectedUninstall();

-

-  // Returns whether Google Update should be installed.

-  bool ShouldInstall(SetupFiles* setup_files);

-

-  // Returns whether the same version of Google Update should be over-installed.

-  bool ShouldOverinstallSameVersion(SetupFiles* setup_files);

-

-  // Increments the usage stat if a core process is not running and the existing

-  // version is >= 1.2.0.0.

-  void UpdateCoreNotRunningMetric(const CString& existing_version);

-

-  HRESULT DoProtectedGoogleUpdateInstall(SetupFiles* setup_files);

-

-  // Rolls back the changes made during DoProtectedGoogleUpdateInstall().

-  // Call when that method fails.

-  void RollBack(SetupFiles* setup_files);

-

-  // Installs the Google Update files.

-  HRESULT InstallPhase1();

-

-  // Tells other instances to stop.

-  HRESULT StopGoogleUpdate();

-

-  // Tells other instances to stop then waits for them to exit.

-  HRESULT StopGoogleUpdateAndWait();

-

-  // Sets the non-legacy shutdown event to signal other instances for this user

-  // or machine to exit.

-  HRESULT SignalShutdownEvent();

-

-  // Signals the legacy quiet mode events to cause all legacy Google Update

-  // processes for this user or machine to exit.

-  HRESULT SignalLegacyShutdownEvents();

-

-  // Creates and sets the specified legacy event.

-  HRESULT CreateLegacyEvent(const CString& event_name,

-                            HANDLE* event_handle) const;

-

-  // Releases all the shutdown events.

-  void ReleaseShutdownEvents();

-

-  // Sets the setup complete event, signalling the other setup instance to

-  // release the Setup Lock.

-  void SetSetupCompleteEvent() const;

-

-  // Waits for other instances of GoogleUpdate.exe to exit.

-  HRESULT WaitForOtherInstancesToExit(const Pids& pids);

-

-  // Gets the list of all the GoogleUpdate.exe processes to wait for.

-  HRESULT GetPidsToWaitFor(Pids* pids) const;

-

-  // Gets the list of GoogleUpdate processes to wait for based on processes'

-  // command line.

-  HRESULT GetPidsToWaitForUsingCommandLine(Pids* pids) const;

-

-  // Returns whether elevation is required to perform this install.

-  bool IsElevationRequired() const;

-

-  // Starts Omaha elevated if possible and waits for it to exit.

-  // The same arguments are passed to the elevated instance.

-  HRESULT ElevateAndWait(const CString& cmd_line);

-

-  // Given a guid, finds and copies the offline manifest and binaries from the

-  // current module directory to the offline_dir passed in. offline_dir is

-  // typically the Google\Update\Offline\ directory. The offline manifest is

-  // copied to offline_dir\{GUID}.gup. The binaries are in the format

-  // "Installer.msi.{GUID}", and they are copied to the offline_dir under the

-  // subdirectory {GUID}, as Installer.msi.

-  static HRESULT CopyOfflineFilesForGuid(const CString& app_guid,

-                                         const CString& offline_dir);

-

-  // For all the applications that have been requested, copy the offline

-  // binaries. Calls CopyOfflineFilesForGuid() for each app_guid.

-  bool CopyOfflineFiles(const CString& offline_dir);

-

-  // Launches a worker process from the installed location to run setup phase 2,

-  // if specified, and install the app.

-  HRESULT LaunchInstalledWorker(bool do_setup_phase_2, HANDLE* process);

-

-  // Starts the core.

-  HRESULT StartMachineCoreProcess() const;

-  HRESULT StartUserCoreProcess(const CString& core_cmd_line) const;

-

-  // Returns the pids of running Omaha 2 Core processes for this user/system.

-  HRESULT FindCoreProcesses(Pids* found_core_pids) const;

-

-  // Forcefully kills appropriate core processes using ::TerminateProcess().

-  HRESULT TerminateCoreProcesses() const;

-

-  // Verifies that the appropriate core is running.

-  bool IsCoreProcessRunning() const;

-

-  // Starts the installed long-lived process.

-  HRESULT StartCore() const;

-

-  // Waits for the process or an event.

-  // If the process exits before the event is signaled, the exit code is

-  // returned in exit_code.

-  // The event should not be signaled until at least the point where the process

-  // is handling and reporting its own errors.

-  HRESULT WaitForProcessExitOrEvent(HANDLE process,

-                                    HANDLE event,

-                                    uint32* exit_code) const;

-

-  // Waits for the UI in the handoff worker to be initialized such that it can

-  // handle its own errors.

-  HRESULT WaitForHandoffWorker(HANDLE process) const;

-

-  // Returns the SID to use for process searches, mutexes, etc. during this

-  // installation.

-  HRESULT GetAppropriateSid(CString* sid) const;

-

-  // Initializes the Setup Lock with correct name and security attributes.

-  static bool InitSetupLock(bool is_machine, GLock* setup_lock);

-

-  // Initializes legacy Setup Locks with correct name and security attributes.

-  bool InitLegacySetupLocks(GLock* lock10,

-                            GLock* lock11_user,

-                            GLock* lock11_machine);

-

-  // Returns true if it can instantiate MSXML parser.

-  static bool HasXmlParser();

-

-  // Returns true if GoogleUpdate can be uninstalled now.

-  bool CanUninstallGoogleUpdate() const;

-

-  bool IsInteractiveInstall() const;

-

-  bool ShouldWaitForWorkerProcess() const;

-

-  // Sets values for OEM installs in the registry.

-  HRESULT SetOemInstallState();

-

-  // Marks Google Update EULA as not accepted if it is not already installed.

-  // Does not touch apps' EULA state.

-  static HRESULT SetEulaNotAccepted(bool is_machine);

-

-  const bool is_machine_;

-  Mode mode_;

-  const CommandLineArgs* const args_;

-  CString saved_version_;  // Previous version saved for roll back.

-  scoped_event legacy_1_0_shutdown_event_;

-  scoped_event legacy_1_1_shutdown_event_;

-  scoped_event shutdown_event_;

-  int extra_code1_;

-

-  // Whether an offline worker has been launched. Not valid until worker has

-  // been launched. If true, this Setup instance is for offline metainstaller.

-  bool launched_offline_worker_;

-

-  scoped_ptr<HighresTimer> metrics_timer_;

-

-  // Whether this process uninstalled Google Update for any reason.

-  // Access must be protected by the Setup Lock.

-  static bool did_uninstall_;

-

-  friend class SetupTest;

-  friend class SetupOfflineInstallerTest;

-  DISALLOW_EVIL_CONSTRUCTORS(Setup);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_SETUP_SETUP_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// There are two phases of setup:
+//  1) Copy the Google Update files to the install location.
+//   * Executed by InstallGoogleUpdateAndApp().
+//   * This is done in an instance running from a temp location.
+//  2) Do everything else to install Google Update.
+//   * Executed by SetupGoogleUpdate().
+//   * This is done in an instance running from the installed location.
+//
+//  Uninstall() undoes both phases of setup.
+//  All methods assume the instance is running with the correct permissions.
+
+#ifndef OMAHA_SETUP_SETUP_H__
+#define OMAHA_SETUP_SETUP_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/scoped_any.h"
+
+namespace omaha {
+
+class GLock;
+class HighresTimer;
+struct NamedObjectAttributes;
+
+struct CommandLineArgs;
+class SetupFiles;
+
+class Setup {
+ public:
+  Setup(bool is_machine, const CommandLineArgs* args);
+  ~Setup();
+
+  // Installs Google Update, if necessary, and launches a worker to install app.
+  // Handles elevation.
+  HRESULT Install(const CString& cmd_line);
+
+  // Installs Google Update silently without installing an app.
+  HRESULT InstallSelfSilently();
+
+  // Updates Google Update.
+  HRESULT UpdateSelfSilently();
+
+  // Repairs Google Update for Code Red recovery.
+  HRESULT RepairSilently();
+
+  // Completes installation from the installed location.
+  HRESULT SetupGoogleUpdate();
+
+  // Obtains the Setup Lock and uninstalls all Google Update versions if
+  // Google Update can be uninstalled.
+  HRESULT Uninstall();
+
+  // Verifies that Google Update is either properly installed or uninstalled
+  // completely. Returns whether Google Update is installed.
+  // TODO(omaha): Consider making this and did_uninstall_ non-static after
+  // refactoring Setup phases. May require a Setup member in Goopdate.
+  static void CheckInstallStateConsistency(bool is_machine);
+
+  // Writes error info for silent updates to the registry so the installed Omaha
+  // can send an update failed ping.
+  static void PersistUpdateErrorInfo(bool is_machine,
+                                     HRESULT error,
+                                     int extra_code1,
+                                     const CString& version);
+
+  // Reads the error info for silent updates from the registry if present and
+  // deletes it. Returns true if the data is valid.
+  static bool ReadAndClearUpdateErrorInfo(bool is_machine,
+                                          DWORD* error_code,
+                                          DWORD* extra_code1,
+                                          CString* version);
+
+  // Marks Google Update EULA as accepted by deleting the registry value.
+  // Does not touch apps' EULA state.
+  static HRESULT SetEulaAccepted(bool is_machine);
+
+  int extra_code1() const { return extra_code1_; }
+
+ private:
+  // Defines the mode of the instance.
+  enum Mode {
+    MODE_UNKNOWN,
+    MODE_INSTALL,
+    MODE_SELF_INSTALL,
+    MODE_SELF_UPDATE,
+    MODE_REPAIR,
+    MODE_PHASE2,
+    MODE_UNINSTALL,
+  };
+
+  typedef std::vector<uint32> Pids;
+
+  // Does all non-elevation work for Install().
+  HRESULT DoInstall();
+
+  // Handles Setup lock acquisition failures and returns the error to report.
+  HRESULT HandleLockFailed(int lock_version);
+
+  // Does the install work within all necessary locks, which have already been
+  // obtained.
+  // If handoff_process is not NULL on a successful return, the caller should
+  // wait for this process after releasing the locks.
+  HRESULT DoProtectedInstall(HANDLE* handoff_process);
+
+  // Uninstalls all Google Update versions after checking if Google Update can
+  // be uninstalled.
+  HRESULT DoProtectedUninstall();
+
+  // Returns whether Google Update should be installed.
+  bool ShouldInstall(SetupFiles* setup_files);
+
+  // Returns whether the same version of Google Update should be over-installed.
+  bool ShouldOverinstallSameVersion(SetupFiles* setup_files);
+
+  // Increments the usage stat if a core process is not running and the existing
+  // version is >= 1.2.0.0.
+  void UpdateCoreNotRunningMetric(const CString& existing_version);
+
+  HRESULT DoProtectedGoogleUpdateInstall(SetupFiles* setup_files);
+
+  // Rolls back the changes made during DoProtectedGoogleUpdateInstall().
+  // Call when that method fails.
+  void RollBack(SetupFiles* setup_files);
+
+  // Installs the Google Update files.
+  HRESULT InstallPhase1();
+
+  // Tells other instances to stop.
+  HRESULT StopGoogleUpdate();
+
+  // Tells other instances to stop then waits for them to exit.
+  HRESULT StopGoogleUpdateAndWait();
+
+  // Sets the non-legacy shutdown event to signal other instances for this user
+  // or machine to exit.
+  HRESULT SignalShutdownEvent();
+
+  // Signals the legacy quiet mode events to cause all legacy Google Update
+  // processes for this user or machine to exit.
+  HRESULT SignalLegacyShutdownEvents();
+
+  // Creates and sets the specified legacy event.
+  HRESULT CreateLegacyEvent(const CString& event_name,
+                            HANDLE* event_handle) const;
+
+  // Releases all the shutdown events.
+  void ReleaseShutdownEvents();
+
+  // Sets the setup complete event, signalling the other setup instance to
+  // release the Setup Lock.
+  void SetSetupCompleteEvent() const;
+
+  // Waits for other instances of GoogleUpdate.exe to exit.
+  HRESULT WaitForOtherInstancesToExit(const Pids& pids);
+
+  // Gets the list of all the GoogleUpdate.exe processes to wait for.
+  HRESULT GetPidsToWaitFor(Pids* pids) const;
+
+  // Gets the list of GoogleUpdate processes to wait for based on processes'
+  // command line.
+  HRESULT GetPidsToWaitForUsingCommandLine(Pids* pids) const;
+
+  // Returns whether elevation is required to perform this install.
+  bool IsElevationRequired() const;
+
+  // Starts Omaha elevated if possible and waits for it to exit.
+  // The same arguments are passed to the elevated instance.
+  HRESULT ElevateAndWait(const CString& cmd_line);
+
+  // Given a guid, finds and copies the offline manifest and binaries from the
+  // current module directory to the offline_dir passed in. offline_dir is
+  // typically the Google\Update\Offline\ directory. The offline manifest is
+  // copied to offline_dir\{GUID}.gup. The binaries are in the format
+  // "Installer.msi.{GUID}", and they are copied to the offline_dir under the
+  // subdirectory {GUID}, as Installer.msi.
+  static HRESULT CopyOfflineFilesForGuid(const CString& app_guid,
+                                         const CString& offline_dir);
+
+  // For all the applications that have been requested, copy the offline
+  // binaries. Calls CopyOfflineFilesForGuid() for each app_guid.
+  bool CopyOfflineFiles(const CString& offline_dir);
+
+  // Launches a worker process from the installed location to run setup phase 2,
+  // if specified, and install the app.
+  HRESULT LaunchInstalledWorker(bool do_setup_phase_2, HANDLE* process);
+
+  // Starts the core.
+  HRESULT StartMachineCoreProcess() const;
+  HRESULT StartUserCoreProcess(const CString& core_cmd_line) const;
+
+  // Returns the pids of running Omaha 2 Core processes for this user/system.
+  HRESULT FindCoreProcesses(Pids* found_core_pids) const;
+
+  // Forcefully kills appropriate core processes using ::TerminateProcess().
+  HRESULT TerminateCoreProcesses() const;
+
+  // Verifies that the appropriate core is running.
+  bool IsCoreProcessRunning() const;
+
+  // Starts the installed long-lived process.
+  HRESULT StartCore() const;
+
+  // Waits for the process or an event.
+  // If the process exits before the event is signaled, the exit code is
+  // returned in exit_code.
+  // The event should not be signaled until at least the point where the process
+  // is handling and reporting its own errors.
+  HRESULT WaitForProcessExitOrEvent(HANDLE process,
+                                    HANDLE event,
+                                    uint32* exit_code) const;
+
+  // Waits for the UI in the handoff worker to be initialized such that it can
+  // handle its own errors.
+  HRESULT WaitForHandoffWorker(HANDLE process) const;
+
+  // Returns the SID to use for process searches, mutexes, etc. during this
+  // installation.
+  HRESULT GetAppropriateSid(CString* sid) const;
+
+  // Initializes the Setup Lock with correct name and security attributes.
+  static bool InitSetupLock(bool is_machine, GLock* setup_lock);
+
+  // Initializes legacy Setup Locks with correct name and security attributes.
+  bool InitLegacySetupLocks(GLock* lock10,
+                            GLock* lock11_user,
+                            GLock* lock11_machine);
+
+  // Returns true if it can instantiate MSXML parser.
+  static bool HasXmlParser();
+
+  // Returns true if GoogleUpdate can be uninstalled now.
+  bool CanUninstallGoogleUpdate() const;
+
+  bool IsInteractiveInstall() const;
+
+  bool ShouldWaitForWorkerProcess() const;
+
+  // Sets values for OEM installs in the registry.
+  HRESULT SetOemInstallState();
+
+  // Marks Google Update EULA as not accepted if it is not already installed.
+  // Does not touch apps' EULA state.
+  static HRESULT SetEulaNotAccepted(bool is_machine);
+
+  const bool is_machine_;
+  Mode mode_;
+  const CommandLineArgs* const args_;
+  CString saved_version_;  // Previous version saved for roll back.
+  scoped_event legacy_1_0_shutdown_event_;
+  scoped_event legacy_1_1_shutdown_event_;
+  scoped_event shutdown_event_;
+  int extra_code1_;
+
+  // Whether an offline worker has been launched. Not valid until worker has
+  // been launched. If true, this Setup instance is for offline metainstaller.
+  bool launched_offline_worker_;
+
+  scoped_ptr<HighresTimer> metrics_timer_;
+
+  // Whether this process uninstalled Google Update for any reason.
+  // Access must be protected by the Setup Lock.
+  static bool did_uninstall_;
+
+  friend class SetupTest;
+  friend class SetupOfflineInstallerTest;
+  DISALLOW_EVIL_CONSTRUCTORS(Setup);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_SETUP_SETUP_H__
+
diff --git a/setup/setup_files.cc b/setup/setup_files.cc
index 5f6b94e..5630df9 100644
--- a/setup/setup_files.cc
+++ b/setup/setup_files.cc
@@ -1,516 +1,516 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/setup/setup_files.h"

-

-#include <atlpath.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/scoped_current_directory.h"

-#include "omaha/common/signaturevalidator.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource_manager.h"

-#include "omaha/setup/setup_metrics.h"

-

-namespace omaha {

-

-const int kNumberOfCreateServiceRetries = 5;

-const int kSleepBetweenCreateServiceRetryMs = 200;

-

-SetupFiles::SetupFiles(bool is_machine)

-: is_machine_(is_machine) {

-  SETUP_LOG(L2, (_T("[SetupFiles::SetupFiles]")));

-}

-

-SetupFiles::~SetupFiles() {

-  SETUP_LOG(L2, (_T("[SetupFiles::~SetupFiles]")));

-

-  if (!saved_shell_path_.IsEmpty()) {

-    // Delete the saved copy of the previous shell.

-    VERIFY1(SUCCEEDED(File::Remove(saved_shell_path_)));

-  }

-}

-

-HRESULT SetupFiles::Init() {

-  SETUP_LOG(L2, (_T("[SetupFiles::Init]")));

-

-  HRESULT hr = BuildFileLists();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// We only do these checks for the same exact version. This is especially true

-// when doing file comparisons, because the filenames as well as the number of

-// files can change from version to version. An earlier version should not

-// overinstall a newer version by mistake because it is checking for files that

-// no longer exist in the new version.

-bool SetupFiles::ShouldOverinstallSameVersion() {

-  SETUP_LOG(L2, (_T("[SetupFiles::ShouldOverinstallSameVersion]")));

-

-  CPath install_dir = goopdate_utils::BuildInstallDirectory(is_machine_,

-                                                            GetVersionString());

-  for (size_t i = 0 ; i < core_program_files_.size(); ++i) {

-    CString full_path = ConcatenatePath(install_dir, core_program_files_[i]);

-    if (full_path.IsEmpty()) {

-      ASSERT1(false);

-      return true;

-    }

-    if (!File::Exists(full_path)) {

-      SETUP_LOG(L2, (_T("[core file missing - overinstall][%s]]"), full_path));

-      return true;

-    }

-  }

-

-  for (size_t i = 0 ; i < optional_files_.size(); ++i) {

-    CString full_path = ConcatenatePath(install_dir, optional_files_[i]);

-    if (full_path.IsEmpty()) {

-      ASSERT1(false);

-      return true;

-    }

-    if (!File::Exists(full_path)) {

-      SETUP_LOG(L2, (_T("[optional file missing - overinstall][%s]]"),

-                     full_path));

-      return true;

-    }

-  }

-

-  CString shell_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_);

-  if (!File::Exists(shell_path)) {

-    SETUP_LOG(L2, (_T("[shell missing - overinstall][%s]]"), shell_path));

-    return true;

-  }

-

-  return false;

-}

-

-// Install the required and optional files.

-// Assumes that the user already has the appropriate permissions

-// (e.g. is elevated for a machine install).

-// Assumes ShouldInstall has been called and returned true.

-// Assumes no other instances of GoogleUpdate.exe are running.

-HRESULT SetupFiles::Install() {

-  OPT_LOG(L1, (_T("[Install files]")));

-  ASSERT1(vista_util::IsUserAdmin() || !is_machine_);

-

-  ++metric_setup_files_total;

-  HighresTimer metrics_timer;

-

-

-  SETUP_LOG(L3,

-      (_T("[IsAdmin=%d, IsNonElevatedAdmin=%d, SvcInstalled=%d, MachineApp=%d"),

-       vista_util::IsUserAdmin(),

-       vista_util::IsUserNonElevatedAdmin(),

-       goopdate_utils::IsServiceInstalled(),

-       is_machine_));

-

-  const bool should_over_install = ConfigManager::Instance()->CanOverInstall();

-

-  // Copy the core program files.

-  CPath install_dir = goopdate_utils::BuildInstallDirectory(is_machine_,

-                                                            GetVersionString());

-  HRESULT hr = CopyInstallFiles(core_program_files_,

-                                install_dir,

-                                should_over_install);

-  if (FAILED(hr)) {

-    OPT_LOG(LEVEL_ERROR, (_T("[Failed to copy the files][0x%08x]"), hr));

-    if (E_ACCESSDENIED == hr) {

-      return GOOPDATE_E_ACCESSDENIED_COPYING_CORE_FILES;

-    }

-    return hr;

-  }

-

-  hr = CopyShell();

-  if (FAILED(hr)) {

-    OPT_LOG(LEVEL_ERROR, (_T("[Failed to copy shell][0x%08x]"), hr));

-    if (E_ACCESSDENIED == hr) {

-      return GOOPDATE_E_ACCESSDENIED_COPYING_SHELL;

-    }

-    return hr;

-  }

-

-  // Copy the optional files.

-  VERIFY1(SUCCEEDED(CopyInstallFiles(optional_files_,

-                                     install_dir,

-                                     should_over_install)));

-

-  metric_setup_files_ms.AddSample(metrics_timer.GetElapsedMs());

-  ++metric_setup_files_verification_succeeded;

-  return S_OK;

-}

-

-// Currently only rolls back the shell file.

-HRESULT SetupFiles::RollBack() {

-  OPT_LOG(L1, (_T("[Roll back files]")));

-  ++metric_setup_rollback_files;

-

-  if (!saved_shell_path_.IsEmpty()) {

-    SETUP_LOG(L1, (_T("[Rolling back shell from %s]"), saved_shell_path_));

-    ++metric_setup_files_rollback_shell;

-

-    std::vector<CString> saved_paths;

-    saved_paths.push_back(saved_shell_path_);

-    std::vector<CString> install_paths;

-    install_paths.push_back(

-        goopdate_utils::BuildGoogleUpdateExePath(is_machine_));

-

-    HRESULT hr = CopyAndValidateFiles(saved_paths, install_paths, true);

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[CopyAndValidateFiles failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-void SetupFiles::Uninstall() {

-  SETUP_LOG(L2, (_T("[SetupFiles::Uninstall]")));

-

-  // In case we are deleting the current directory as well, let's reset the

-  // current directory to a temporary directory. On exit, we'll try to restore

-  // the directory (if it still exists).

-  scoped_current_directory root_dir(app_util::GetTempDir());

-

-  // Delete the install and crash reports directories.

-  CString install_dir(

-      is_machine_ ? ConfigManager::Instance()->GetMachineGoopdateInstallDir() :

-                    ConfigManager::Instance()->GetUserGoopdateInstallDir());

-  HRESULT hr = DeleteDirectory(install_dir);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[DeleteDirectory failed][%s][0x%08x]"),

-                   install_dir, hr));

-  }

-

-  // TODO(omaha): Remove this and GetMachineDownloadStorageDir() when legacy

-  // support is removed.

-  // This directory may have been used by previous Omaha versions. Delete it in

-  // case this install was upgraded from one of those.

-  if (is_machine_) {

-    CString dir(ConfigManager::Instance()->GetMachineDownloadStorageDir());

-    hr = DeleteDirectory(dir);

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[DeleteDirectory failed][%s][0x%08x]"), dir, hr));

-    }

-  }

-}

-

-HRESULT SetupFiles::CopyShell() {

-  bool should_copy = false;

-  bool already_exists = false;

-  CString shell_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_);

-

-  HRESULT hr = ShouldCopyShell(shell_path,

-                               &should_copy,

-                               &already_exists);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[ShouldCopyShell failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (should_copy) {

-    if (already_exists) {

-      ++metric_setup_files_replace_shell;

-      VERIFY1(SUCCEEDED(SaveShellForRollback(shell_path)));

-    }

-

-    std::vector<CString> shell_files;

-    shell_files.push_back(kGoopdateFileName);

-    CPath shell_dir(shell_path);

-    VERIFY1(shell_dir.RemoveFileSpec());

-    hr = CopyInstallFiles(shell_files, shell_dir, already_exists);

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[CopyInstallFiles of shell failed][0x%08x]"), hr));

-      // TODO(omaha): If a shell already exists, we could try using the

-      // existing one, but that may lead to unexpected behavior.

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT SetupFiles::ShouldCopyShell(const CString& shell_install_path,

-                                    bool* should_copy,

-                                    bool* already_exists) const {

-  ASSERT1(should_copy);

-  ASSERT1(already_exists);

-  *should_copy = false;

-  *already_exists = false;

-

-  CPath source_shell_path(app_util::GetCurrentModuleDirectory());

-  if (!source_shell_path.Append(kGoopdateFileName)) {

-    return GOOPDATE_E_PATH_APPEND_FAILED;

-  }

-

-  if (!File::Exists(shell_install_path)) {

-    SETUP_LOG(L3, (_T("[shell does not exist - copying]")));

-    *should_copy = true;

-    return S_OK;

-  }

-  *already_exists = true;

-

-  ULONGLONG existing_version = app_util::GetVersionFromFile(shell_install_path);

-  if (!existing_version) {

-    ASSERT(false, (_T("[failed to get existing shell version - replacing]")));

-    *should_copy = true;

-    return S_OK;

-  }

-

-  ULONGLONG source_version = app_util::GetVersionFromFile(source_shell_path);

-  if (!source_version) {

-    ASSERT(false, (_T("[failed to get this shell version - not replacing]")));

-    *should_copy = false;

-    return E_FAIL;

-  }

-

-  if (existing_version > source_version) {

-    SETUP_LOG(L2, (_T("[newer shell version exists - not copying]")));

-    *should_copy = false;

-  } else if (existing_version < source_version) {

-    SETUP_LOG(L2, (_T("[older shell version exists - copying]")));

-    *should_copy = true;

-  } else {

-    // Same version.

-    *should_copy = ConfigManager::Instance()->CanOverInstall();

-    SETUP_LOG(L2, (_T("[same version exists - %s copying]"),

-                  *should_copy ? _T("") : _T("not")));

-  }

-

-  return S_OK;

-}

-

-HRESULT SetupFiles::SaveShellForRollback(const CString& shell_install_path) {

-  // Copy existing file to a temporary file in case we need to roll back.

-  CString temp_file;

-  if (!::GetTempFileName(app_util::GetTempDir(),

-                         _T("gsh"),

-                         0,

-                         CStrBuf(temp_file, MAX_PATH))) {

-    DWORD error = ::GetLastError();

-    SETUP_LOG(LEVEL_WARNING, (_T("[::GetTempFileName failed][%d]"), error));

-    return HRESULT_FROM_WIN32(error);

-  }

-

-  HRESULT hr = File::Copy(shell_install_path, temp_file, true);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  saved_shell_path_ = temp_file;

-  return S_OK;

-}

-

-HRESULT SetupFiles::BuildFileLists() {

-  ASSERT1(core_program_files_.empty());

-  ASSERT1(optional_files_.empty());

-

-  core_program_files_.clear();

-  core_program_files_.push_back(kGoopdateFileName);

-  core_program_files_.push_back(kGoopdateDllName);

-  core_program_files_.push_back(kGoopdateCrashHandlerFileName);

-

-  ResourceManager::GetSupportedLanguageDllNames(&core_program_files_);

-

-  core_program_files_.push_back(kHelperInstallerName);

-

-  optional_files_.clear();

-  optional_files_.push_back(ACTIVEX_FILENAME);

-  optional_files_.push_back(BHO_FILENAME);

-

-  return S_OK;

-}

-

-// Assumes that an install is needed.

-HRESULT SetupFiles::CopyInstallFiles(const std::vector<CString>& file_names,

-                                     const CString& destination_dir,

-                                     bool overwrite) {

-  SETUP_LOG(L1, (_T("[SetupFiles::CopyInstallFiles]")

-                _T("[destination dir=%s][overwrite=%d]"),

-                destination_dir, overwrite));

-  ASSERT1(!file_names.empty());

-

-  CPath source_dir(app_util::GetCurrentModuleDirectory());

-  SETUP_LOG(L2, (_T("[source_dir=%s]"),

-                static_cast<const TCHAR*>(source_dir)));

-

-  if (!File::Exists(destination_dir)) {

-    // This creates the dir recursively.

-    HRESULT hr = CreateDir(destination_dir, NULL);

-    if (FAILED(hr)) {

-      return hr;

-    }

-  }

-

-  // Clean up any leftover pending removals that a previous uninstall

-  // may have left behind.

-  // Only do a prefix match if the directory is not the main Update directory.

-  // Otherwise, we may remove entries for previous version directories.

-  CPath install_path(destination_dir);

-  install_path.Canonicalize();

-  CPath goopdate_install_path(

-      is_machine_ ?

-      ConfigManager::Instance()->GetMachineGoopdateInstallDir() :

-      ConfigManager::Instance()->GetUserGoopdateInstallDir());

-  goopdate_install_path.Canonicalize();

-  bool prefix_match = install_path.m_strPath != goopdate_install_path.m_strPath;

-  HRESULT hr = File::RemoveFromMovesPendingReboot(destination_dir,

-                                                  prefix_match);

-  VERIFY1(SUCCEEDED(hr) || !vista_util::IsUserAdmin());

-

-  std::vector<CString> source_file_paths;

-  std::vector<CString> destination_file_paths;

-  for (size_t i = 0; i < file_names.size(); ++i) {

-    CPath file_from(source_dir);

-    if (!file_from.Append(file_names[i])) {

-      return GOOPDATE_E_PATH_APPEND_FAILED;

-    }

-    source_file_paths.push_back(file_from);

-

-    CPath file(destination_dir);

-    if (!file.Append(file_names[i])) {

-      return GOOPDATE_E_PATH_APPEND_FAILED;

-    }

-    destination_file_paths.push_back(file);

-

-    SETUP_LOG(L2, (_T("[from=%s][to=%s]"),

-                  source_file_paths[i],

-                  destination_file_paths[i]));

-  }

-

-  hr = CopyAndValidateFiles(source_file_paths,

-                            destination_file_paths,

-                            overwrite);

-

-  SETUP_LOG(L2, (_T("[SetupFiles::CopyInstallFiles - done")));

-  return hr;

-}

-

-HRESULT SetupFiles::CopyAndValidateFiles(

-    const std::vector<CString>& source_file_paths,

-    const std::vector<CString>& destination_file_paths,

-    bool overwrite) {

-  ASSERT1(!source_file_paths.empty());

-  ASSERT1(!destination_file_paths.empty());

-  ASSERT1(source_file_paths.size() == destination_file_paths.size());

-

-  if (overwrite) {

-    // Best effort attempt to delete the current set of files:

-    //  * try to remove an .old file that might be there.

-    //  * move the current file to a .old and delete it after reboot.

-    // Because this is a best effort, we do not propogate errors.

-

-    for (size_t i = 0; i != destination_file_paths.size(); ++i) {

-      const CString cur_file = destination_file_paths[i];

-      const CString dot_old(cur_file + _T(".old"));

-      VERIFY1(SUCCEEDED(File::Remove(dot_old)));

-      HRESULT hr = File::Move(cur_file, dot_old, true);

-      if (SUCCEEDED(hr)) {

-        // Delete after reboot only works for admins. .old files will be left

-        // for user installs not being run by elevated admins.

-        hr = File::DeleteAfterReboot(dot_old);

-        if (FAILED(hr)) {

-          SETUP_LOG(LW, (_T("DeleteAfterReboot of %s failed with 0x%08x."),

-                        dot_old, hr));

-        }

-      } else {

-        SETUP_LOG(L2, (_T("[failed to move][%s][0x%08x]"), cur_file, hr));

-        ASSERT1(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);

-      }

-    }

-  }

-

-  for (size_t i = 0; i != source_file_paths.size(); ++i) {

-    extra_code1_ = i + 1;  // 1-based; reserves 0 for success or not set.

-

-    HRESULT hr = VerifyFileSignature(source_file_paths[i]);

-    if (FAILED(hr)) {

-      OPT_LOG(LE, (_T("[pre-copy signature validation failed][from=%s][0x%x]"),

-                   source_file_paths[i], hr));

-      ++metric_setup_files_verification_failed_pre;

-      return hr;

-    }

-

-    hr = File::Copy(source_file_paths[i], destination_file_paths[i], true);

-    if (FAILED(hr)) {

-      OPT_LOG(LE, (_T("[copy failed][from=%s][to=%s][0x%08x]"),

-                   source_file_paths[i], destination_file_paths[i], hr));

-      return hr;

-    }

-

-    hr = VerifyFileSignature(destination_file_paths[i]);

-    if (FAILED(hr)) {

-      OPT_LOG(LE, (_T("[postcopy signature failed][from=%s][to=%s][0x%x]"),

-                   source_file_paths[i], destination_file_paths[i], hr));

-      ++metric_setup_files_verification_failed_post;

-      VERIFY1(SUCCEEDED(File::Remove(destination_file_paths[i])));

-      return hr;

-    }

-  }

-

-  extra_code1_ = 0;

-  return S_OK;

-}

-

-// The only secure location we copy to is Program Files, which only happens for

-// machine installs.

-HRESULT SetupFiles::VerifyFileSignature(const CString& filepath) {

-  if (!is_machine_) {

-    return S_OK;

-  }

-

-  // Verify the Authenticode signature but use use only the local cache for

-  // revocation checks.

-  HRESULT hr = VerifySignature(filepath, false);

-#if TEST_CERTIFICATE

-  // The chain of trust will not validate on builds signed with the test

-  // certificate.

-  if (CERT_E_UNTRUSTEDROOT == hr) {

-    hr = S_OK;

-  }

-#endif

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Verify that there is a Google certificate and that it has not expired.

-  if (!VerifySigneeIsGoogle(filepath)) {

-    if (VerifySigneeIsGoogleNoTimestampCheck(filepath)) {

-      // Google was verified as the signee when not doing a timestamp check, so

-      // it must be the timestamp check that failed.

-      return GOOPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED_TIMESTAMP_CHECK;

-    }

-    return GOOPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED;

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/setup/setup_files.h"
+
+#include <atlpath.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/scoped_current_directory.h"
+#include "omaha/common/signaturevalidator.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource_manager.h"
+#include "omaha/setup/setup_metrics.h"
+
+namespace omaha {
+
+const int kNumberOfCreateServiceRetries = 5;
+const int kSleepBetweenCreateServiceRetryMs = 200;
+
+SetupFiles::SetupFiles(bool is_machine)
+: is_machine_(is_machine) {
+  SETUP_LOG(L2, (_T("[SetupFiles::SetupFiles]")));
+}
+
+SetupFiles::~SetupFiles() {
+  SETUP_LOG(L2, (_T("[SetupFiles::~SetupFiles]")));
+
+  if (!saved_shell_path_.IsEmpty()) {
+    // Delete the saved copy of the previous shell.
+    VERIFY1(SUCCEEDED(File::Remove(saved_shell_path_)));
+  }
+}
+
+HRESULT SetupFiles::Init() {
+  SETUP_LOG(L2, (_T("[SetupFiles::Init]")));
+
+  HRESULT hr = BuildFileLists();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// We only do these checks for the same exact version. This is especially true
+// when doing file comparisons, because the filenames as well as the number of
+// files can change from version to version. An earlier version should not
+// overinstall a newer version by mistake because it is checking for files that
+// no longer exist in the new version.
+bool SetupFiles::ShouldOverinstallSameVersion() {
+  SETUP_LOG(L2, (_T("[SetupFiles::ShouldOverinstallSameVersion]")));
+
+  CPath install_dir = goopdate_utils::BuildInstallDirectory(is_machine_,
+                                                            GetVersionString());
+  for (size_t i = 0 ; i < core_program_files_.size(); ++i) {
+    CString full_path = ConcatenatePath(install_dir, core_program_files_[i]);
+    if (full_path.IsEmpty()) {
+      ASSERT1(false);
+      return true;
+    }
+    if (!File::Exists(full_path)) {
+      SETUP_LOG(L2, (_T("[core file missing - overinstall][%s]]"), full_path));
+      return true;
+    }
+  }
+
+  for (size_t i = 0 ; i < optional_files_.size(); ++i) {
+    CString full_path = ConcatenatePath(install_dir, optional_files_[i]);
+    if (full_path.IsEmpty()) {
+      ASSERT1(false);
+      return true;
+    }
+    if (!File::Exists(full_path)) {
+      SETUP_LOG(L2, (_T("[optional file missing - overinstall][%s]]"),
+                     full_path));
+      return true;
+    }
+  }
+
+  CString shell_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_);
+  if (!File::Exists(shell_path)) {
+    SETUP_LOG(L2, (_T("[shell missing - overinstall][%s]]"), shell_path));
+    return true;
+  }
+
+  return false;
+}
+
+// Install the required and optional files.
+// Assumes that the user already has the appropriate permissions
+// (e.g. is elevated for a machine install).
+// Assumes ShouldInstall has been called and returned true.
+// Assumes no other instances of GoogleUpdate.exe are running.
+HRESULT SetupFiles::Install() {
+  OPT_LOG(L1, (_T("[Install files]")));
+  ASSERT1(vista_util::IsUserAdmin() || !is_machine_);
+
+  ++metric_setup_files_total;
+  HighresTimer metrics_timer;
+
+
+  SETUP_LOG(L3,
+      (_T("[IsAdmin=%d, IsNonElevatedAdmin=%d, SvcInstalled=%d, MachineApp=%d"),
+       vista_util::IsUserAdmin(),
+       vista_util::IsUserNonElevatedAdmin(),
+       goopdate_utils::IsServiceInstalled(),
+       is_machine_));
+
+  const bool should_over_install = ConfigManager::Instance()->CanOverInstall();
+
+  // Copy the core program files.
+  CPath install_dir = goopdate_utils::BuildInstallDirectory(is_machine_,
+                                                            GetVersionString());
+  HRESULT hr = CopyInstallFiles(core_program_files_,
+                                install_dir,
+                                should_over_install);
+  if (FAILED(hr)) {
+    OPT_LOG(LEVEL_ERROR, (_T("[Failed to copy the files][0x%08x]"), hr));
+    if (E_ACCESSDENIED == hr) {
+      return GOOPDATE_E_ACCESSDENIED_COPYING_CORE_FILES;
+    }
+    return hr;
+  }
+
+  hr = CopyShell();
+  if (FAILED(hr)) {
+    OPT_LOG(LEVEL_ERROR, (_T("[Failed to copy shell][0x%08x]"), hr));
+    if (E_ACCESSDENIED == hr) {
+      return GOOPDATE_E_ACCESSDENIED_COPYING_SHELL;
+    }
+    return hr;
+  }
+
+  // Copy the optional files.
+  VERIFY1(SUCCEEDED(CopyInstallFiles(optional_files_,
+                                     install_dir,
+                                     should_over_install)));
+
+  metric_setup_files_ms.AddSample(metrics_timer.GetElapsedMs());
+  ++metric_setup_files_verification_succeeded;
+  return S_OK;
+}
+
+// Currently only rolls back the shell file.
+HRESULT SetupFiles::RollBack() {
+  OPT_LOG(L1, (_T("[Roll back files]")));
+  ++metric_setup_rollback_files;
+
+  if (!saved_shell_path_.IsEmpty()) {
+    SETUP_LOG(L1, (_T("[Rolling back shell from %s]"), saved_shell_path_));
+    ++metric_setup_files_rollback_shell;
+
+    std::vector<CString> saved_paths;
+    saved_paths.push_back(saved_shell_path_);
+    std::vector<CString> install_paths;
+    install_paths.push_back(
+        goopdate_utils::BuildGoogleUpdateExePath(is_machine_));
+
+    HRESULT hr = CopyAndValidateFiles(saved_paths, install_paths, true);
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[CopyAndValidateFiles failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+void SetupFiles::Uninstall() {
+  SETUP_LOG(L2, (_T("[SetupFiles::Uninstall]")));
+
+  // In case we are deleting the current directory as well, let's reset the
+  // current directory to a temporary directory. On exit, we'll try to restore
+  // the directory (if it still exists).
+  scoped_current_directory root_dir(app_util::GetTempDir());
+
+  // Delete the install and crash reports directories.
+  CString install_dir(
+      is_machine_ ? ConfigManager::Instance()->GetMachineGoopdateInstallDir() :
+                    ConfigManager::Instance()->GetUserGoopdateInstallDir());
+  HRESULT hr = DeleteDirectory(install_dir);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[DeleteDirectory failed][%s][0x%08x]"),
+                   install_dir, hr));
+  }
+
+  // TODO(omaha): Remove this and GetMachineDownloadStorageDir() when legacy
+  // support is removed.
+  // This directory may have been used by previous Omaha versions. Delete it in
+  // case this install was upgraded from one of those.
+  if (is_machine_) {
+    CString dir(ConfigManager::Instance()->GetMachineDownloadStorageDir());
+    hr = DeleteDirectory(dir);
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[DeleteDirectory failed][%s][0x%08x]"), dir, hr));
+    }
+  }
+}
+
+HRESULT SetupFiles::CopyShell() {
+  bool should_copy = false;
+  bool already_exists = false;
+  CString shell_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_);
+
+  HRESULT hr = ShouldCopyShell(shell_path,
+                               &should_copy,
+                               &already_exists);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[ShouldCopyShell failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (should_copy) {
+    if (already_exists) {
+      ++metric_setup_files_replace_shell;
+      VERIFY1(SUCCEEDED(SaveShellForRollback(shell_path)));
+    }
+
+    std::vector<CString> shell_files;
+    shell_files.push_back(kGoopdateFileName);
+    CPath shell_dir(shell_path);
+    VERIFY1(shell_dir.RemoveFileSpec());
+    hr = CopyInstallFiles(shell_files, shell_dir, already_exists);
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[CopyInstallFiles of shell failed][0x%08x]"), hr));
+      // TODO(omaha): If a shell already exists, we could try using the
+      // existing one, but that may lead to unexpected behavior.
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT SetupFiles::ShouldCopyShell(const CString& shell_install_path,
+                                    bool* should_copy,
+                                    bool* already_exists) const {
+  ASSERT1(should_copy);
+  ASSERT1(already_exists);
+  *should_copy = false;
+  *already_exists = false;
+
+  CPath source_shell_path(app_util::GetCurrentModuleDirectory());
+  if (!source_shell_path.Append(kGoopdateFileName)) {
+    return GOOPDATE_E_PATH_APPEND_FAILED;
+  }
+
+  if (!File::Exists(shell_install_path)) {
+    SETUP_LOG(L3, (_T("[shell does not exist - copying]")));
+    *should_copy = true;
+    return S_OK;
+  }
+  *already_exists = true;
+
+  ULONGLONG existing_version = app_util::GetVersionFromFile(shell_install_path);
+  if (!existing_version) {
+    ASSERT(false, (_T("[failed to get existing shell version - replacing]")));
+    *should_copy = true;
+    return S_OK;
+  }
+
+  ULONGLONG source_version = app_util::GetVersionFromFile(source_shell_path);
+  if (!source_version) {
+    ASSERT(false, (_T("[failed to get this shell version - not replacing]")));
+    *should_copy = false;
+    return E_FAIL;
+  }
+
+  if (existing_version > source_version) {
+    SETUP_LOG(L2, (_T("[newer shell version exists - not copying]")));
+    *should_copy = false;
+  } else if (existing_version < source_version) {
+    SETUP_LOG(L2, (_T("[older shell version exists - copying]")));
+    *should_copy = true;
+  } else {
+    // Same version.
+    *should_copy = ConfigManager::Instance()->CanOverInstall();
+    SETUP_LOG(L2, (_T("[same version exists - %s copying]"),
+                  *should_copy ? _T("") : _T("not")));
+  }
+
+  return S_OK;
+}
+
+HRESULT SetupFiles::SaveShellForRollback(const CString& shell_install_path) {
+  // Copy existing file to a temporary file in case we need to roll back.
+  CString temp_file;
+  if (!::GetTempFileName(app_util::GetTempDir(),
+                         _T("gsh"),
+                         0,
+                         CStrBuf(temp_file, MAX_PATH))) {
+    DWORD error = ::GetLastError();
+    SETUP_LOG(LEVEL_WARNING, (_T("[::GetTempFileName failed][%d]"), error));
+    return HRESULT_FROM_WIN32(error);
+  }
+
+  HRESULT hr = File::Copy(shell_install_path, temp_file, true);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  saved_shell_path_ = temp_file;
+  return S_OK;
+}
+
+HRESULT SetupFiles::BuildFileLists() {
+  ASSERT1(core_program_files_.empty());
+  ASSERT1(optional_files_.empty());
+
+  core_program_files_.clear();
+  core_program_files_.push_back(kGoopdateFileName);
+  core_program_files_.push_back(kGoopdateDllName);
+  core_program_files_.push_back(kGoopdateCrashHandlerFileName);
+
+  ResourceManager::GetSupportedLanguageDllNames(&core_program_files_);
+
+  core_program_files_.push_back(kHelperInstallerName);
+
+  optional_files_.clear();
+  optional_files_.push_back(ACTIVEX_FILENAME);
+  optional_files_.push_back(BHO_FILENAME);
+
+  return S_OK;
+}
+
+// Assumes that an install is needed.
+HRESULT SetupFiles::CopyInstallFiles(const std::vector<CString>& file_names,
+                                     const CString& destination_dir,
+                                     bool overwrite) {
+  SETUP_LOG(L1, (_T("[SetupFiles::CopyInstallFiles]")
+                _T("[destination dir=%s][overwrite=%d]"),
+                destination_dir, overwrite));
+  ASSERT1(!file_names.empty());
+
+  CPath source_dir(app_util::GetCurrentModuleDirectory());
+  SETUP_LOG(L2, (_T("[source_dir=%s]"),
+                static_cast<const TCHAR*>(source_dir)));
+
+  if (!File::Exists(destination_dir)) {
+    // This creates the dir recursively.
+    HRESULT hr = CreateDir(destination_dir, NULL);
+    if (FAILED(hr)) {
+      return hr;
+    }
+  }
+
+  // Clean up any leftover pending removals that a previous uninstall
+  // may have left behind.
+  // Only do a prefix match if the directory is not the main Update directory.
+  // Otherwise, we may remove entries for previous version directories.
+  CPath install_path(destination_dir);
+  install_path.Canonicalize();
+  CPath goopdate_install_path(
+      is_machine_ ?
+      ConfigManager::Instance()->GetMachineGoopdateInstallDir() :
+      ConfigManager::Instance()->GetUserGoopdateInstallDir());
+  goopdate_install_path.Canonicalize();
+  bool prefix_match = install_path.m_strPath != goopdate_install_path.m_strPath;
+  HRESULT hr = File::RemoveFromMovesPendingReboot(destination_dir,
+                                                  prefix_match);
+  VERIFY1(SUCCEEDED(hr) || !vista_util::IsUserAdmin());
+
+  std::vector<CString> source_file_paths;
+  std::vector<CString> destination_file_paths;
+  for (size_t i = 0; i < file_names.size(); ++i) {
+    CPath file_from(source_dir);
+    if (!file_from.Append(file_names[i])) {
+      return GOOPDATE_E_PATH_APPEND_FAILED;
+    }
+    source_file_paths.push_back(file_from);
+
+    CPath file(destination_dir);
+    if (!file.Append(file_names[i])) {
+      return GOOPDATE_E_PATH_APPEND_FAILED;
+    }
+    destination_file_paths.push_back(file);
+
+    SETUP_LOG(L2, (_T("[from=%s][to=%s]"),
+                  source_file_paths[i],
+                  destination_file_paths[i]));
+  }
+
+  hr = CopyAndValidateFiles(source_file_paths,
+                            destination_file_paths,
+                            overwrite);
+
+  SETUP_LOG(L2, (_T("[SetupFiles::CopyInstallFiles - done")));
+  return hr;
+}
+
+HRESULT SetupFiles::CopyAndValidateFiles(
+    const std::vector<CString>& source_file_paths,
+    const std::vector<CString>& destination_file_paths,
+    bool overwrite) {
+  ASSERT1(!source_file_paths.empty());
+  ASSERT1(!destination_file_paths.empty());
+  ASSERT1(source_file_paths.size() == destination_file_paths.size());
+
+  if (overwrite) {
+    // Best effort attempt to delete the current set of files:
+    //  * try to remove an .old file that might be there.
+    //  * move the current file to a .old and delete it after reboot.
+    // Because this is a best effort, we do not propogate errors.
+
+    for (size_t i = 0; i != destination_file_paths.size(); ++i) {
+      const CString cur_file = destination_file_paths[i];
+      const CString dot_old(cur_file + _T(".old"));
+      VERIFY1(SUCCEEDED(File::Remove(dot_old)));
+      HRESULT hr = File::Move(cur_file, dot_old, true);
+      if (SUCCEEDED(hr)) {
+        // Delete after reboot only works for admins. .old files will be left
+        // for user installs not being run by elevated admins.
+        hr = File::DeleteAfterReboot(dot_old);
+        if (FAILED(hr)) {
+          SETUP_LOG(LW, (_T("DeleteAfterReboot of %s failed with 0x%08x."),
+                        dot_old, hr));
+        }
+      } else {
+        SETUP_LOG(L2, (_T("[failed to move][%s][0x%08x]"), cur_file, hr));
+        ASSERT1(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);
+      }
+    }
+  }
+
+  for (size_t i = 0; i != source_file_paths.size(); ++i) {
+    extra_code1_ = i + 1;  // 1-based; reserves 0 for success or not set.
+
+    HRESULT hr = VerifyFileSignature(source_file_paths[i]);
+    if (FAILED(hr)) {
+      OPT_LOG(LE, (_T("[pre-copy signature validation failed][from=%s][0x%x]"),
+                   source_file_paths[i], hr));
+      ++metric_setup_files_verification_failed_pre;
+      return hr;
+    }
+
+    hr = File::Copy(source_file_paths[i], destination_file_paths[i], true);
+    if (FAILED(hr)) {
+      OPT_LOG(LE, (_T("[copy failed][from=%s][to=%s][0x%08x]"),
+                   source_file_paths[i], destination_file_paths[i], hr));
+      return hr;
+    }
+
+    hr = VerifyFileSignature(destination_file_paths[i]);
+    if (FAILED(hr)) {
+      OPT_LOG(LE, (_T("[postcopy signature failed][from=%s][to=%s][0x%x]"),
+                   source_file_paths[i], destination_file_paths[i], hr));
+      ++metric_setup_files_verification_failed_post;
+      VERIFY1(SUCCEEDED(File::Remove(destination_file_paths[i])));
+      return hr;
+    }
+  }
+
+  extra_code1_ = 0;
+  return S_OK;
+}
+
+// The only secure location we copy to is Program Files, which only happens for
+// machine installs.
+HRESULT SetupFiles::VerifyFileSignature(const CString& filepath) {
+  if (!is_machine_) {
+    return S_OK;
+  }
+
+  // Verify the Authenticode signature but use use only the local cache for
+  // revocation checks.
+  HRESULT hr = VerifySignature(filepath, false);
+#if TEST_CERTIFICATE
+  // The chain of trust will not validate on builds signed with the test
+  // certificate.
+  if (CERT_E_UNTRUSTEDROOT == hr) {
+    hr = S_OK;
+  }
+#endif
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Verify that there is a Google certificate and that it has not expired.
+  if (!VerifySigneeIsGoogle(filepath)) {
+    if (VerifySigneeIsGoogleNoTimestampCheck(filepath)) {
+      // Google was verified as the signee when not doing a timestamp check, so
+      // it must be the timestamp check that failed.
+      return GOOPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED_TIMESTAMP_CHECK;
+    }
+    return GOOPDATE_E_VERIFY_SIGNEE_IS_GOOGLE_FAILED;
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/setup/setup_files.h b/setup/setup_files.h
index 79f21bb..2956177 100644
--- a/setup/setup_files.h
+++ b/setup/setup_files.h
@@ -1,106 +1,106 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_SETUP_SETUP_FILES_H__

-#define OMAHA_SETUP_SETUP_FILES_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-struct Files {

-  const TCHAR* file_name;

-};

-

-class SetupFiles {

- public:

-  explicit SetupFiles(bool is_machine);

-  virtual ~SetupFiles();

-

-  HRESULT Init();

-

-  // Returns whether the same version of Google Update should be over-installed.

-  bool ShouldOverinstallSameVersion();

-

-  // Installs Google Update files but does not register or install any other

-  // applications. Returns whether Google Update was installed.

-  // TODO(omaha3): Remove the virtual methods from this class. They are only

-  // needed for unit tests and can be eliminated in the upcoming redesign.

-  virtual HRESULT Install();

-

-  // Rolls back the changes made during Install(). Call when Setup fails.

-  // Returns S_OK if there is nothing to do.

-  HRESULT RollBack();

-

-  // Uninstalls Google Update files installed by Install().

-  void Uninstall();

-

-  int extra_code1() const { return extra_code1_; }

-

- private:

-  // Copies the shell to the version-independent location if needed.

-  HRESULT CopyShell();

-

-  // Determines whether to copy the shell to the version-independent location.

-  HRESULT ShouldCopyShell(const CString& shell_dir,

-                          bool* should_copy,

-                          bool* already_exists) const;

-

-  // Saves the previous version of the shell in case we need to roll it back.

-  HRESULT SaveShellForRollback(const CString& shell_install_path);

-

-  // Creates the lists of files that belong to Google Update.

-  HRESULT BuildFileLists();

-

-  // Copies file_names from the current directory to the destination directory.

-  HRESULT CopyInstallFiles(const std::vector<CString>& file_names,

-                           const CString& destination_dir,

-                           bool overwrite);

-

-  // Copies each file from the source path to its corresponding destination

-  // path. Verifies the signature of the file on each side of the copy.

-  // If overwrite is true, files are moved to .old and scheduled for delete

-  // after reboot, which only works for elevated admins.

-  HRESULT CopyAndValidateFiles(

-      const std::vector<CString>& source_file_paths,

-      const std::vector<CString>& destination_file_paths,

-      bool overwrite);

-

-  // Verifies the file is signed with the Google Certificate.

-  // Returns true if filepath is properly signed.

-  // Only verifies files if they are being installed to a secure location.

-  // If not an official build, allows the Google Test Certificate.

-  // Only checks certain extensions since not all extensions can be signed.

-  HRESULT VerifyFileSignature(const CString& filepath);

-

-  const bool is_machine_;

-  CString saved_shell_path_;  // Path of the previous shell saved for roll back.

-  std::vector<CString> core_program_files_;

-  std::vector<CString> optional_files_;

-

-  int extra_code1_;

-

-  friend class SetupFilesTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(SetupFiles);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_SETUP_SETUP_FILES_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_SETUP_SETUP_FILES_H__
+#define OMAHA_SETUP_SETUP_FILES_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+struct Files {
+  const TCHAR* file_name;
+};
+
+class SetupFiles {
+ public:
+  explicit SetupFiles(bool is_machine);
+  virtual ~SetupFiles();
+
+  HRESULT Init();
+
+  // Returns whether the same version of Google Update should be over-installed.
+  bool ShouldOverinstallSameVersion();
+
+  // Installs Google Update files but does not register or install any other
+  // applications. Returns whether Google Update was installed.
+  // TODO(omaha3): Remove the virtual methods from this class. They are only
+  // needed for unit tests and can be eliminated in the upcoming redesign.
+  virtual HRESULT Install();
+
+  // Rolls back the changes made during Install(). Call when Setup fails.
+  // Returns S_OK if there is nothing to do.
+  HRESULT RollBack();
+
+  // Uninstalls Google Update files installed by Install().
+  void Uninstall();
+
+  int extra_code1() const { return extra_code1_; }
+
+ private:
+  // Copies the shell to the version-independent location if needed.
+  HRESULT CopyShell();
+
+  // Determines whether to copy the shell to the version-independent location.
+  HRESULT ShouldCopyShell(const CString& shell_dir,
+                          bool* should_copy,
+                          bool* already_exists) const;
+
+  // Saves the previous version of the shell in case we need to roll it back.
+  HRESULT SaveShellForRollback(const CString& shell_install_path);
+
+  // Creates the lists of files that belong to Google Update.
+  HRESULT BuildFileLists();
+
+  // Copies file_names from the current directory to the destination directory.
+  HRESULT CopyInstallFiles(const std::vector<CString>& file_names,
+                           const CString& destination_dir,
+                           bool overwrite);
+
+  // Copies each file from the source path to its corresponding destination
+  // path. Verifies the signature of the file on each side of the copy.
+  // If overwrite is true, files are moved to .old and scheduled for delete
+  // after reboot, which only works for elevated admins.
+  HRESULT CopyAndValidateFiles(
+      const std::vector<CString>& source_file_paths,
+      const std::vector<CString>& destination_file_paths,
+      bool overwrite);
+
+  // Verifies the file is signed with the Google Certificate.
+  // Returns true if filepath is properly signed.
+  // Only verifies files if they are being installed to a secure location.
+  // If not an official build, allows the Google Test Certificate.
+  // Only checks certain extensions since not all extensions can be signed.
+  HRESULT VerifyFileSignature(const CString& filepath);
+
+  const bool is_machine_;
+  CString saved_shell_path_;  // Path of the previous shell saved for roll back.
+  std::vector<CString> core_program_files_;
+  std::vector<CString> optional_files_;
+
+  int extra_code1_;
+
+  friend class SetupFilesTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(SetupFiles);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_SETUP_SETUP_FILES_H__
+
diff --git a/setup/setup_files_unittest.cc b/setup/setup_files_unittest.cc
index 0a7418a..a73d9f9 100644
--- a/setup/setup_files_unittest.cc
+++ b/setup/setup_files_unittest.cc
@@ -1,491 +1,491 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/path.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/setup/setup_files.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-const int kNumberOfLanguageDlls = 54;

-const int kNumberOfRequiredFiles = 4;

-const int kNumberOfOptionalFiles = 2;

-const int kNumberOfInstalledRequiredFiles =

-    kNumberOfLanguageDlls + kNumberOfRequiredFiles;

-// FindFiles returns "." and ".." in addition to the actual files.

-const int kExtraFilesReturnedByFindFiles = 2;

-const int kExpectedFilesReturnedByFindFiles =

-    kNumberOfInstalledRequiredFiles + kNumberOfOptionalFiles +

-    kExtraFilesReturnedByFindFiles;

-

-const TCHAR kFutureVersionString[] = _T("9.8.7.6");

-const ULONGLONG kFutureVersion = 0x0009000800070006;

-

-}  // namespace

-

-void CopyGoopdateFiles(const CString& omaha_path, const CString& version) {

-  const CString version_path = ConcatenatePath(omaha_path, version);

-

-  ASSERT_SUCCEEDED(File::Copy(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("GoogleUpdate.exe")),

-      ConcatenatePath(omaha_path, _T("GoogleUpdate.exe")),

-      false));

-

-  ASSERT_SUCCEEDED(CreateDir(version_path, NULL));

-

-  const TCHAR* files[] = {_T("GoogleUpdate.exe"),

-                          _T("GoogleUpdateHelper.msi"),

-                          _T("GoogleCrashHandler.exe"),

-                          _T("goopdate.dll"),

-                          _T("GoopdateBho.dll"),

-                          ACTIVEX_FILENAME};

-  for (size_t i = 0; i < arraysize(files); ++i) {

-    ASSERT_SUCCEEDED(File::Copy(

-        ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                        files[i]),

-        ConcatenatePath(version_path, files[i]),

-        false));

-  }

-

-  ASSERT_SUCCEEDED(File::CopyWildcards(app_util::GetCurrentModuleDirectory(),

-                                       version_path,

-                                       _T("goopdateres_\?\?.dll"),

-                                       false));

-  ASSERT_SUCCEEDED(File::CopyWildcards(app_util::GetCurrentModuleDirectory(),

-                                       version_path,

-                                       _T("goopdateres_\?\?\?.dll"),

-                                       false));

-  ASSERT_SUCCEEDED(File::CopyWildcards(app_util::GetCurrentModuleDirectory(),

-                                       version_path,

-                                       _T("goopdateres_\?\?-\?\?.dll"),

-                                       false));

-  ASSERT_SUCCEEDED(File::CopyWildcards(app_util::GetCurrentModuleDirectory(),

-                                       version_path,

-                                       _T("goopdateres_\?\?-\?\?\?.dll"),

-                                       false));

-}

-

-class SetupFilesTest : public testing::Test {

- protected:

-  explicit SetupFilesTest(bool is_machine)

-      : is_machine_(is_machine),

-        omaha_path_(is_machine ?

-            GetGoogleUpdateMachinePath() : GetGoogleUpdateUserPath()),

-        hive_override_key_name_(kRegistryHiveOverrideRoot) {

-  }

-

-  static void SetUpTestCase() {

-    exe_parent_dir_ = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                      _T("unittest_support\\"));

-

-    this_version_ = GetVersionString();

-

-    expected_is_overinstall_ = !OFFICIAL_BUILD;

-#ifdef DEBUG

-    if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueNameOverInstall)) {

-      DWORD value = 0;

-      EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                        kRegValueNameOverInstall,

-                                        &value));

-      expected_is_overinstall_ = value != 0;

-    }

-#endif

-  }

-

-  void SetUp() {

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    // Do not override HKLM because it contains the CSIDL_* definitions.

-    OverrideSpecifiedRegistryHives(hive_override_key_name_, false, true);

-

-    setup_files_.reset(new SetupFiles(is_machine_));

-

-    ASSERT_HRESULT_SUCCEEDED(setup_files_->Init());

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-  }

-

-  // Assumes the executable version has been changed to the future version.

-  void InstallHelper(const CString& omaha_path) {

-    const CString version_path = ConcatenatePath(omaha_path,

-                                                 kFutureVersionString);

-

-    ASSERT_EQ(kNumberOfInstalledRequiredFiles,

-              setup_files_->core_program_files_.size());

-    ASSERT_EQ(kNumberOfOptionalFiles, setup_files_->optional_files_.size());

-

-    DeleteDirectory(version_path);

-    ASSERT_FALSE(File::IsDirectory(version_path));

-

-    EXPECT_SUCCEEDED(setup_files_->Install());

-

-    EXPECT_TRUE(File::Exists(ConcatenatePath(omaha_path,

-                             _T("GoogleUpdate.exe"))));

-

-    EXPECT_TRUE(File::IsDirectory(version_path));

-

-    std::vector<CString> files;

-    EXPECT_SUCCEEDED(FindFiles(version_path, _T("*.*"), &files));

-    ASSERT_EQ(kExpectedFilesReturnedByFindFiles, files.size());

-    int file_index = kExtraFilesReturnedByFindFiles;

-    EXPECT_STREQ(_T("GoogleCrashHandler.exe"), files[file_index++]);

-    EXPECT_STREQ(_T("GoogleUpdate.exe"), files[file_index++]);

-    EXPECT_STREQ(_T("GoogleUpdateHelper.msi"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdate.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("GoopdateBho.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_ar.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_bg.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_bn.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_ca.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_cs.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_da.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_de.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_el.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_en-GB.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_en.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_es-419.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_es.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_et.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_fa.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_fi.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_fil.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_fr.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_gu.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_hi.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_hr.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_hu.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_id.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_is.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_it.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_iw.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_ja.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_kn.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_ko.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_lt.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_lv.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_ml.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_mr.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_ms.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_nl.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_no.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_or.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_pl.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_pt-BR.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_pt-PT.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_ro.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_ru.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_sk.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_sl.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_sr.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_sv.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_ta.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_te.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_th.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_tr.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_uk.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_ur.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_vi.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_zh-CN.dll"), files[file_index++]);

-    EXPECT_STREQ(_T("goopdateres_zh-TW.dll"), files[file_index++]);

-    EXPECT_STREQ(ACTIVEX_FILENAME, files[file_index++]);

-

-    EXPECT_SUCCEEDED(DeleteDirectory(version_path));

-  }

-

-  HRESULT ShouldCopyShell(const CString& shell_install_path,

-                          bool* should_copy,

-                          bool* already_exists) const {

-    return setup_files_->ShouldCopyShell(shell_install_path,

-                                         should_copy,

-                                         already_exists);

-  }

-

-  const bool is_machine_;

-  const CString omaha_path_;

-  const CString hive_override_key_name_;

-  scoped_ptr<SetupFiles> setup_files_;

-

-  static CString exe_parent_dir_;

-  static CString this_version_;

-  static bool expected_is_overinstall_;

-};

-

-CString SetupFilesTest::exe_parent_dir_;

-CString SetupFilesTest::this_version_;

-bool SetupFilesTest::expected_is_overinstall_;

-

-class SetupFilesMachineTest : public SetupFilesTest {

- protected:

-  SetupFilesMachineTest()

-    : SetupFilesTest(true) {

-  }

-};

-

-class SetupFilesUserTest : public SetupFilesTest {

- protected:

-  SetupFilesUserTest()

-    : SetupFilesTest(false) {

-  }

-};

-

-TEST_F(SetupFilesUserTest,

-       ShouldOverinstallSameVersion_SameVersionFilesMissing) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-  ASSERT_SUCCEEDED(

-      DeleteDirectory(ConcatenatePath(omaha_path_, this_version_)));

-  CString file_path = ConcatenatePath(

-                          ConcatenatePath(omaha_path_, this_version_),

-                          _T("goopdate.dll"));

-  ASSERT_FALSE(File::Exists(file_path));

-

-  EXPECT_TRUE(setup_files_->ShouldOverinstallSameVersion());

-}

-

-TEST_F(SetupFilesUserTest,

-       ShouldOverinstallSameVersion_SameVersionFilesPresent) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-

-  EXPECT_FALSE(setup_files_->ShouldOverinstallSameVersion());

-}

-

-TEST_F(SetupFilesUserTest,

-       ShouldOverinstallSameVersion_SameVersionRequiredFileMissing) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-  CString path = ConcatenatePath(ConcatenatePath(omaha_path_, this_version_),

-                                 _T("goopdate.dll"));

-  ASSERT_SUCCEEDED(File::Remove(path));

-  ASSERT_FALSE(File::Exists(path));

-

-  EXPECT_TRUE(setup_files_->ShouldOverinstallSameVersion());

-}

-

-TEST_F(SetupFilesUserTest,

-       ShouldOverinstallSameVersion_SameVersionOptionalFileMissing) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-  CString path = ConcatenatePath(ConcatenatePath(omaha_path_, this_version_),

-                                 _T("GoopdateBho.dll"));

-  ASSERT_SUCCEEDED(File::Remove(path));

-  ASSERT_FALSE(File::Exists(path));

-

-  EXPECT_TRUE(setup_files_->ShouldOverinstallSameVersion());

-}

-

-TEST_F(SetupFilesUserTest,

-       ShouldOverinstallSameVersion_SameVersionShellMissing) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-  CString shell_path = ConcatenatePath(omaha_path_, _T("GoogleUpdate.exe"));

-  ASSERT_TRUE(SUCCEEDED(File::DeleteAfterReboot(shell_path)) ||

-              !vista_util::IsUserAdmin());

-  ASSERT_FALSE(File::Exists(shell_path));

-

-  EXPECT_TRUE(setup_files_->ShouldOverinstallSameVersion());

-}

-

-TEST_F(SetupFilesUserTest,

-       ShouldOverinstallSameVersion_NewerVersionShellMissing) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    kFutureVersionString));

-

-  CopyGoopdateFiles(omaha_path_, kFutureVersionString);

-  CString shell_path = ConcatenatePath(omaha_path_, _T("GoogleUpdate.exe"));

-  ASSERT_TRUE(SUCCEEDED(File::DeleteAfterReboot(shell_path)) ||

-              !vista_util::IsUserAdmin());

-  ASSERT_FALSE(File::Exists(shell_path));

-

-  // Does not check the version.

-  EXPECT_TRUE(setup_files_->ShouldOverinstallSameVersion());

-

-  EXPECT_SUCCEEDED(

-      DeleteDirectory(ConcatenatePath(omaha_path_, kFutureVersionString)));

-}

-

-TEST_F(SetupFilesMachineTest, Install_NotOverInstall) {

-  if (vista_util::IsUserAdmin()) {

-    // Fake the version

-    const ULONGLONG module_version = GetVersion();

-    InitializeVersion(kFutureVersion);

-

-// TODO(omaha): Remove the ifdef when signing occurs after instrumentation.

-#ifdef COVERAGE_ENABLED

-  std::wcout << _T("\tTest does not run in coverage builds.") << std::endl;

-#else

-    InstallHelper(omaha_path_);

-#endif

-

-    InitializeVersion(module_version);

-  } else {

-    // This method expects to be called elevated for machine installs.

-    ExpectAsserts expect_asserts;

-    EXPECT_EQ(GOOPDATE_E_ACCESSDENIED_COPYING_CORE_FILES,

-              setup_files_->Install());

-  }

-}

-

-TEST_F(SetupFilesUserTest, Install_NotOverInstall) {

-  // Fake the version

-  const ULONGLONG module_version = GetVersion();

-  InitializeVersion(kFutureVersion);

-

-  InstallHelper(omaha_path_);

-

-  InitializeVersion(module_version);

-}

-

-TEST_F(SetupFilesUserTest, ShouldCopyShell_ExistingIsNewer) {

-  CString target_path = ConcatenatePath(

-      ConcatenatePath(exe_parent_dir_, _T("omaha_1.2.x_newer")),

-      _T("GoogleUpdate.exe"));

-  ASSERT_TRUE(File::Exists(target_path));

-  bool should_copy = false;

-  bool already_exists = false;

-  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));

-  EXPECT_FALSE(should_copy);

-  EXPECT_TRUE(already_exists);

-}

-

-TEST_F(SetupFilesUserTest, ShouldCopyShell_ExistingIsSame) {

-  CString target_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                        _T("GoogleUpdate.exe"));

-  ASSERT_TRUE(File::Exists(target_path));

-  bool should_copy = false;

-  bool already_exists = false;

-

-  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));

-  EXPECT_EQ(expected_is_overinstall_, should_copy);

-  EXPECT_TRUE(already_exists);

-

-  if (ShouldRunLargeTest()) {

-    // Override OverInstall to test official behavior on non-official builds.

-

-    DWORD existing_overinstall(0);

-    bool had_existing_overinstall = SUCCEEDED(RegKey::GetValue(

-                                                  MACHINE_REG_UPDATE_DEV,

-                                                  kRegValueNameOverInstall,

-                                                  &existing_overinstall));

-

-    EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                      kRegValueNameOverInstall,

-                                      static_cast<DWORD>(0)));

-

-    EXPECT_SUCCEEDED(

-        ShouldCopyShell(target_path, &should_copy, &already_exists));

-#ifdef DEBUG

-    EXPECT_FALSE(should_copy);

-#else

-    EXPECT_EQ(expected_is_overinstall_, should_copy);

-#endif

-    EXPECT_TRUE(already_exists);

-

-    // Restore "overinstall"

-    if (had_existing_overinstall) {

-      EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                        kRegValueNameOverInstall,

-                                        existing_overinstall));

-    } else {

-      EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,

-                                           kRegValueNameOverInstall));

-    }

-  }

-}

-

-TEST_F(SetupFilesUserTest, ShouldCopyShell_ExistingIsOlderMinor) {

-  CString target_path = ConcatenatePath(

-      ConcatenatePath(exe_parent_dir_, _T("omaha_1.1.x")),

-      _T("GoogleUpdate.exe"));

-  ASSERT_TRUE(File::Exists(target_path));

-  bool should_copy = false;

-  bool already_exists = false;

-  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));

-  EXPECT_TRUE(should_copy);

-  EXPECT_TRUE(already_exists);

-}

-

-// The 1.2.x directory will not always have an older GoogleUpdate.exe than the

-// saved version that we use for official builds.

-#if !OFFICIAL_BUILD

-TEST_F(SetupFilesUserTest, ShouldCopyShell_ExistingIsOlderSameMinor) {

-  CString target_path = ConcatenatePath(

-      ConcatenatePath(exe_parent_dir_, _T("omaha_1.2.x")),

-      _T("GoogleUpdate.exe"));

-  ASSERT_TRUE(File::Exists(target_path));

-  bool should_copy = false;

-  bool already_exists = false;

-  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));

-  EXPECT_TRUE(should_copy);

-  EXPECT_TRUE(already_exists);

-}

-#endif

-

-// Assumes LongRunningSilent.exe does not have a version resource.

-TEST_F(SetupFilesUserTest, ShouldCopyShell_ExistingHasNoVersion) {

-  CString target_path = ConcatenatePath(

-      ConcatenatePath(exe_parent_dir_, _T("does_not_shutdown")),

-      _T("GoogleUpdate.exe"));

-  ASSERT_TRUE(File::Exists(target_path));

-  bool should_copy = false;

-  bool already_exists = false;

-  ExpectAsserts expect_asserts;

-  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));

-  EXPECT_TRUE(should_copy);

-  EXPECT_TRUE(already_exists);

-}

-

-TEST_F(SetupFilesUserTest, ShouldCopyShell_NoExistingFile) {

-  CString target_path = ConcatenatePath(

-      ConcatenatePath(exe_parent_dir_, _T("no_such_dir")),

-      _T("GoogleUpdate.exe"));

-  ASSERT_FALSE(File::Exists(target_path));

-  bool should_copy = false;

-  bool already_exists = false;

-  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));

-  EXPECT_TRUE(should_copy);

-  EXPECT_FALSE(already_exists);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/path.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/setup/setup_files.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+const int kNumberOfLanguageDlls = 54;
+const int kNumberOfRequiredFiles = 4;
+const int kNumberOfOptionalFiles = 2;
+const int kNumberOfInstalledRequiredFiles =
+    kNumberOfLanguageDlls + kNumberOfRequiredFiles;
+// FindFiles returns "." and ".." in addition to the actual files.
+const int kExtraFilesReturnedByFindFiles = 2;
+const int kExpectedFilesReturnedByFindFiles =
+    kNumberOfInstalledRequiredFiles + kNumberOfOptionalFiles +
+    kExtraFilesReturnedByFindFiles;
+
+const TCHAR kFutureVersionString[] = _T("9.8.7.6");
+const ULONGLONG kFutureVersion = 0x0009000800070006;
+
+}  // namespace
+
+void CopyGoopdateFiles(const CString& omaha_path, const CString& version) {
+  const CString version_path = ConcatenatePath(omaha_path, version);
+
+  ASSERT_SUCCEEDED(File::Copy(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("GoogleUpdate.exe")),
+      ConcatenatePath(omaha_path, _T("GoogleUpdate.exe")),
+      false));
+
+  ASSERT_SUCCEEDED(CreateDir(version_path, NULL));
+
+  const TCHAR* files[] = {_T("GoogleUpdate.exe"),
+                          _T("GoogleUpdateHelper.msi"),
+                          _T("GoogleCrashHandler.exe"),
+                          _T("goopdate.dll"),
+                          _T("GoopdateBho.dll"),
+                          ACTIVEX_FILENAME};
+  for (size_t i = 0; i < arraysize(files); ++i) {
+    ASSERT_SUCCEEDED(File::Copy(
+        ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                        files[i]),
+        ConcatenatePath(version_path, files[i]),
+        false));
+  }
+
+  ASSERT_SUCCEEDED(File::CopyWildcards(app_util::GetCurrentModuleDirectory(),
+                                       version_path,
+                                       _T("goopdateres_\?\?.dll"),
+                                       false));
+  ASSERT_SUCCEEDED(File::CopyWildcards(app_util::GetCurrentModuleDirectory(),
+                                       version_path,
+                                       _T("goopdateres_\?\?\?.dll"),
+                                       false));
+  ASSERT_SUCCEEDED(File::CopyWildcards(app_util::GetCurrentModuleDirectory(),
+                                       version_path,
+                                       _T("goopdateres_\?\?-\?\?.dll"),
+                                       false));
+  ASSERT_SUCCEEDED(File::CopyWildcards(app_util::GetCurrentModuleDirectory(),
+                                       version_path,
+                                       _T("goopdateres_\?\?-\?\?\?.dll"),
+                                       false));
+}
+
+class SetupFilesTest : public testing::Test {
+ protected:
+  explicit SetupFilesTest(bool is_machine)
+      : is_machine_(is_machine),
+        omaha_path_(is_machine ?
+            GetGoogleUpdateMachinePath() : GetGoogleUpdateUserPath()),
+        hive_override_key_name_(kRegistryHiveOverrideRoot) {
+  }
+
+  static void SetUpTestCase() {
+    exe_parent_dir_ = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                      _T("unittest_support\\"));
+
+    this_version_ = GetVersionString();
+
+    expected_is_overinstall_ = !OFFICIAL_BUILD;
+#ifdef DEBUG
+    if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueNameOverInstall)) {
+      DWORD value = 0;
+      EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                        kRegValueNameOverInstall,
+                                        &value));
+      expected_is_overinstall_ = value != 0;
+    }
+#endif
+  }
+
+  void SetUp() {
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    // Do not override HKLM because it contains the CSIDL_* definitions.
+    OverrideSpecifiedRegistryHives(hive_override_key_name_, false, true);
+
+    setup_files_.reset(new SetupFiles(is_machine_));
+
+    ASSERT_HRESULT_SUCCEEDED(setup_files_->Init());
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+  }
+
+  // Assumes the executable version has been changed to the future version.
+  void InstallHelper(const CString& omaha_path) {
+    const CString version_path = ConcatenatePath(omaha_path,
+                                                 kFutureVersionString);
+
+    ASSERT_EQ(kNumberOfInstalledRequiredFiles,
+              setup_files_->core_program_files_.size());
+    ASSERT_EQ(kNumberOfOptionalFiles, setup_files_->optional_files_.size());
+
+    DeleteDirectory(version_path);
+    ASSERT_FALSE(File::IsDirectory(version_path));
+
+    EXPECT_SUCCEEDED(setup_files_->Install());
+
+    EXPECT_TRUE(File::Exists(ConcatenatePath(omaha_path,
+                             _T("GoogleUpdate.exe"))));
+
+    EXPECT_TRUE(File::IsDirectory(version_path));
+
+    std::vector<CString> files;
+    EXPECT_SUCCEEDED(FindFiles(version_path, _T("*.*"), &files));
+    ASSERT_EQ(kExpectedFilesReturnedByFindFiles, files.size());
+    int file_index = kExtraFilesReturnedByFindFiles;
+    EXPECT_STREQ(_T("GoogleCrashHandler.exe"), files[file_index++]);
+    EXPECT_STREQ(_T("GoogleUpdate.exe"), files[file_index++]);
+    EXPECT_STREQ(_T("GoogleUpdateHelper.msi"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdate.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("GoopdateBho.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_ar.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_bg.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_bn.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_ca.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_cs.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_da.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_de.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_el.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_en-GB.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_en.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_es-419.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_es.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_et.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_fa.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_fi.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_fil.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_fr.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_gu.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_hi.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_hr.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_hu.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_id.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_is.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_it.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_iw.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_ja.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_kn.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_ko.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_lt.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_lv.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_ml.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_mr.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_ms.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_nl.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_no.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_or.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_pl.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_pt-BR.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_pt-PT.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_ro.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_ru.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_sk.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_sl.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_sr.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_sv.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_ta.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_te.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_th.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_tr.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_uk.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_ur.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_vi.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_zh-CN.dll"), files[file_index++]);
+    EXPECT_STREQ(_T("goopdateres_zh-TW.dll"), files[file_index++]);
+    EXPECT_STREQ(ACTIVEX_FILENAME, files[file_index++]);
+
+    EXPECT_SUCCEEDED(DeleteDirectory(version_path));
+  }
+
+  HRESULT ShouldCopyShell(const CString& shell_install_path,
+                          bool* should_copy,
+                          bool* already_exists) const {
+    return setup_files_->ShouldCopyShell(shell_install_path,
+                                         should_copy,
+                                         already_exists);
+  }
+
+  const bool is_machine_;
+  const CString omaha_path_;
+  const CString hive_override_key_name_;
+  scoped_ptr<SetupFiles> setup_files_;
+
+  static CString exe_parent_dir_;
+  static CString this_version_;
+  static bool expected_is_overinstall_;
+};
+
+CString SetupFilesTest::exe_parent_dir_;
+CString SetupFilesTest::this_version_;
+bool SetupFilesTest::expected_is_overinstall_;
+
+class SetupFilesMachineTest : public SetupFilesTest {
+ protected:
+  SetupFilesMachineTest()
+    : SetupFilesTest(true) {
+  }
+};
+
+class SetupFilesUserTest : public SetupFilesTest {
+ protected:
+  SetupFilesUserTest()
+    : SetupFilesTest(false) {
+  }
+};
+
+TEST_F(SetupFilesUserTest,
+       ShouldOverinstallSameVersion_SameVersionFilesMissing) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+  ASSERT_SUCCEEDED(
+      DeleteDirectory(ConcatenatePath(omaha_path_, this_version_)));
+  CString file_path = ConcatenatePath(
+                          ConcatenatePath(omaha_path_, this_version_),
+                          _T("goopdate.dll"));
+  ASSERT_FALSE(File::Exists(file_path));
+
+  EXPECT_TRUE(setup_files_->ShouldOverinstallSameVersion());
+}
+
+TEST_F(SetupFilesUserTest,
+       ShouldOverinstallSameVersion_SameVersionFilesPresent) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+
+  EXPECT_FALSE(setup_files_->ShouldOverinstallSameVersion());
+}
+
+TEST_F(SetupFilesUserTest,
+       ShouldOverinstallSameVersion_SameVersionRequiredFileMissing) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+  CString path = ConcatenatePath(ConcatenatePath(omaha_path_, this_version_),
+                                 _T("goopdate.dll"));
+  ASSERT_SUCCEEDED(File::Remove(path));
+  ASSERT_FALSE(File::Exists(path));
+
+  EXPECT_TRUE(setup_files_->ShouldOverinstallSameVersion());
+}
+
+TEST_F(SetupFilesUserTest,
+       ShouldOverinstallSameVersion_SameVersionOptionalFileMissing) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+  CString path = ConcatenatePath(ConcatenatePath(omaha_path_, this_version_),
+                                 _T("GoopdateBho.dll"));
+  ASSERT_SUCCEEDED(File::Remove(path));
+  ASSERT_FALSE(File::Exists(path));
+
+  EXPECT_TRUE(setup_files_->ShouldOverinstallSameVersion());
+}
+
+TEST_F(SetupFilesUserTest,
+       ShouldOverinstallSameVersion_SameVersionShellMissing) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+  CString shell_path = ConcatenatePath(omaha_path_, _T("GoogleUpdate.exe"));
+  ASSERT_TRUE(SUCCEEDED(File::DeleteAfterReboot(shell_path)) ||
+              !vista_util::IsUserAdmin());
+  ASSERT_FALSE(File::Exists(shell_path));
+
+  EXPECT_TRUE(setup_files_->ShouldOverinstallSameVersion());
+}
+
+TEST_F(SetupFilesUserTest,
+       ShouldOverinstallSameVersion_NewerVersionShellMissing) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    kFutureVersionString));
+
+  CopyGoopdateFiles(omaha_path_, kFutureVersionString);
+  CString shell_path = ConcatenatePath(omaha_path_, _T("GoogleUpdate.exe"));
+  ASSERT_TRUE(SUCCEEDED(File::DeleteAfterReboot(shell_path)) ||
+              !vista_util::IsUserAdmin());
+  ASSERT_FALSE(File::Exists(shell_path));
+
+  // Does not check the version.
+  EXPECT_TRUE(setup_files_->ShouldOverinstallSameVersion());
+
+  EXPECT_SUCCEEDED(
+      DeleteDirectory(ConcatenatePath(omaha_path_, kFutureVersionString)));
+}
+
+TEST_F(SetupFilesMachineTest, Install_NotOverInstall) {
+  if (vista_util::IsUserAdmin()) {
+    // Fake the version
+    const ULONGLONG module_version = GetVersion();
+    InitializeVersion(kFutureVersion);
+
+// TODO(omaha): Remove the ifdef when signing occurs after instrumentation.
+#ifdef COVERAGE_ENABLED
+  std::wcout << _T("\tTest does not run in coverage builds.") << std::endl;
+#else
+    InstallHelper(omaha_path_);
+#endif
+
+    InitializeVersion(module_version);
+  } else {
+    // This method expects to be called elevated for machine installs.
+    ExpectAsserts expect_asserts;
+    EXPECT_EQ(GOOPDATE_E_ACCESSDENIED_COPYING_CORE_FILES,
+              setup_files_->Install());
+  }
+}
+
+TEST_F(SetupFilesUserTest, Install_NotOverInstall) {
+  // Fake the version
+  const ULONGLONG module_version = GetVersion();
+  InitializeVersion(kFutureVersion);
+
+  InstallHelper(omaha_path_);
+
+  InitializeVersion(module_version);
+}
+
+TEST_F(SetupFilesUserTest, ShouldCopyShell_ExistingIsNewer) {
+  CString target_path = ConcatenatePath(
+      ConcatenatePath(exe_parent_dir_, _T("omaha_1.2.x_newer")),
+      _T("GoogleUpdate.exe"));
+  ASSERT_TRUE(File::Exists(target_path));
+  bool should_copy = false;
+  bool already_exists = false;
+  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));
+  EXPECT_FALSE(should_copy);
+  EXPECT_TRUE(already_exists);
+}
+
+TEST_F(SetupFilesUserTest, ShouldCopyShell_ExistingIsSame) {
+  CString target_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                        _T("GoogleUpdate.exe"));
+  ASSERT_TRUE(File::Exists(target_path));
+  bool should_copy = false;
+  bool already_exists = false;
+
+  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));
+  EXPECT_EQ(expected_is_overinstall_, should_copy);
+  EXPECT_TRUE(already_exists);
+
+  if (ShouldRunLargeTest()) {
+    // Override OverInstall to test official behavior on non-official builds.
+
+    DWORD existing_overinstall(0);
+    bool had_existing_overinstall = SUCCEEDED(RegKey::GetValue(
+                                                  MACHINE_REG_UPDATE_DEV,
+                                                  kRegValueNameOverInstall,
+                                                  &existing_overinstall));
+
+    EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                      kRegValueNameOverInstall,
+                                      static_cast<DWORD>(0)));
+
+    EXPECT_SUCCEEDED(
+        ShouldCopyShell(target_path, &should_copy, &already_exists));
+#ifdef DEBUG
+    EXPECT_FALSE(should_copy);
+#else
+    EXPECT_EQ(expected_is_overinstall_, should_copy);
+#endif
+    EXPECT_TRUE(already_exists);
+
+    // Restore "overinstall"
+    if (had_existing_overinstall) {
+      EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                        kRegValueNameOverInstall,
+                                        existing_overinstall));
+    } else {
+      EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,
+                                           kRegValueNameOverInstall));
+    }
+  }
+}
+
+TEST_F(SetupFilesUserTest, ShouldCopyShell_ExistingIsOlderMinor) {
+  CString target_path = ConcatenatePath(
+      ConcatenatePath(exe_parent_dir_, _T("omaha_1.1.x")),
+      _T("GoogleUpdate.exe"));
+  ASSERT_TRUE(File::Exists(target_path));
+  bool should_copy = false;
+  bool already_exists = false;
+  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));
+  EXPECT_TRUE(should_copy);
+  EXPECT_TRUE(already_exists);
+}
+
+// The 1.2.x directory will not always have an older GoogleUpdate.exe than the
+// saved version that we use for official builds.
+#if !OFFICIAL_BUILD
+TEST_F(SetupFilesUserTest, ShouldCopyShell_ExistingIsOlderSameMinor) {
+  CString target_path = ConcatenatePath(
+      ConcatenatePath(exe_parent_dir_, _T("omaha_1.2.x")),
+      _T("GoogleUpdate.exe"));
+  ASSERT_TRUE(File::Exists(target_path));
+  bool should_copy = false;
+  bool already_exists = false;
+  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));
+  EXPECT_TRUE(should_copy);
+  EXPECT_TRUE(already_exists);
+}
+#endif
+
+// Assumes LongRunningSilent.exe does not have a version resource.
+TEST_F(SetupFilesUserTest, ShouldCopyShell_ExistingHasNoVersion) {
+  CString target_path = ConcatenatePath(
+      ConcatenatePath(exe_parent_dir_, _T("does_not_shutdown")),
+      _T("GoogleUpdate.exe"));
+  ASSERT_TRUE(File::Exists(target_path));
+  bool should_copy = false;
+  bool already_exists = false;
+  ExpectAsserts expect_asserts;
+  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));
+  EXPECT_TRUE(should_copy);
+  EXPECT_TRUE(already_exists);
+}
+
+TEST_F(SetupFilesUserTest, ShouldCopyShell_NoExistingFile) {
+  CString target_path = ConcatenatePath(
+      ConcatenatePath(exe_parent_dir_, _T("no_such_dir")),
+      _T("GoogleUpdate.exe"));
+  ASSERT_FALSE(File::Exists(target_path));
+  bool should_copy = false;
+  bool already_exists = false;
+  EXPECT_SUCCEEDED(ShouldCopyShell(target_path, &should_copy, &already_exists));
+  EXPECT_TRUE(should_copy);
+  EXPECT_FALSE(already_exists);
+}
+
+}  // namespace omaha
diff --git a/setup/setup_google_update.cc b/setup/setup_google_update.cc
index a0c8b21..12e0601 100644
--- a/setup/setup_google_update.cc
+++ b/setup/setup_google_update.cc
@@ -1,798 +1,798 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/setup/setup_google_update.h"

-

-#include <msi.h>

-#include <atlpath.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "goopdate\google_update_idl.h"  // NOLINT

-#include "omaha/common/app_util.h"

-#include "omaha/common/atlregmapex.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/service_utils.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/user_info.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource.h"

-#include "omaha/setup/setup_metrics.h"

-#include "omaha/setup/setup_service.h"

-#include "omaha/worker/ping.h"

-#include "omaha/worker/ping_event.h"

-#include "omaha/worker/ping_utils.h"

-

-namespace omaha {

-

-namespace {

-

-#ifdef _DEBUG

-HRESULT VerifyCOMLocalServerRegistration(bool is_machine) {

-  // Validate the following:

-  // * LocalServer32 under CLSID_OnDemandMachineAppsClass or

-  //   CLSID_OnDemandUserAppsClass should be ...Google\Update\GoogleUpdate.exe.

-  // * InProcServer32 under CLSID of IID_IGoogleUpdate should be

-  //   ...Google\Update\{version}\goopdate.dll.

-  // * ProxyStubClsid32 under IGoogleUpdate interface should be the CLSID of the

-  //   proxy, which is IID_IGoogleUpdate.

-

-  CString base_clsid_key(goopdate_utils::GetHKRoot());

-  base_clsid_key += _T("\\Software\\Classes\\CLSID\\");

-  CString ondemand_clsid_key(base_clsid_key);

-  ondemand_clsid_key += GuidToString(is_machine ?

-                                     __uuidof(OnDemandMachineAppsClass) :

-                                     __uuidof(OnDemandUserAppsClass));

-  CString local_server_key(ondemand_clsid_key + _T("\\LocalServer32"));

-  CString installed_server;

-  ASSERT1(SUCCEEDED(RegKey::GetValue(local_server_key,

-                                     NULL,

-                                     &installed_server)));

-  ASSERT1(!installed_server.IsEmpty());

-

-  CString expected_server(app_util::GetModulePath(NULL));

-  EnclosePath(&expected_server);

-  ASSERT1(!expected_server.IsEmpty());

-  SETUP_LOG(L3, (_T("[installed_server=%s][expected_server=%s]"),

-                 installed_server, expected_server));

-  ASSERT1(installed_server == expected_server);

-

-  const GUID proxy_clsid = PROXY_CLSID_IS;

-  CString ondemand_proxy_clsid_key(base_clsid_key);

-  ondemand_proxy_clsid_key += GuidToString(proxy_clsid);

-  CString inproc_server_key(ondemand_proxy_clsid_key + _T("\\InProcServer32"));

-  ASSERT1(SUCCEEDED(RegKey::GetValue(inproc_server_key,

-                                     NULL,

-                                     &installed_server)));

-  ASSERT1(!installed_server.IsEmpty());

-  expected_server = app_util::GetCurrentModulePath();

-  ASSERT1(!expected_server.IsEmpty());

-  SETUP_LOG(L3, (_T("[installed proxy=%s][expected proxy=%s]"),

-                 installed_server, expected_server));

-  ASSERT1(installed_server == expected_server);

-

-  CString igoogleupdate_interface_key(goopdate_utils::GetHKRoot());

-  igoogleupdate_interface_key += _T("\\Software\\Classes\\Interface\\");

-  igoogleupdate_interface_key += GuidToString(__uuidof(IGoogleUpdate));

-  igoogleupdate_interface_key += _T("\\ProxyStubClsid32");

-  CString proxy_interface_value;

-  ASSERT1(SUCCEEDED(RegKey::GetValue(igoogleupdate_interface_key,

-                                     NULL,

-                                     &proxy_interface_value)));

-  ASSERT1(!proxy_interface_value.IsEmpty());

-  ASSERT1(proxy_interface_value == GuidToString(proxy_clsid));

-

-  return S_OK;

-}

-#endif

-

-}  // namespace

-

-SetupGoogleUpdate::SetupGoogleUpdate(bool is_machine,

-                                     const CommandLineArgs* args)

-    : is_machine_(is_machine),

-#ifdef _DEBUG

-      have_called_uninstall_previous_versions_(false),

-#endif

-      args_(args) {

-  this_version_ = GetVersionString();

-}

-

-SetupGoogleUpdate::~SetupGoogleUpdate() {

-  SETUP_LOG(L2, (_T("[SetupGoogleUpdate::~SetupGoogleUpdate]")));

-}

-

-// TODO(omaha): Add a VerifyInstall() method that can be called by /handoff

-// instances to verify the installation and call FinishInstall() if it fails.

-

-// Assumes the caller is ensuring this is the only running instance of setup.

-// The original process holds the lock while it waits for this one to complete.

-HRESULT SetupGoogleUpdate::FinishInstall() {

-  SETUP_LOG(L2, (_T("[SetupGoogleUpdate::FinishInstall]")));

-

-  HRESULT hr = InstallRegistryValues();

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[InstallRegistryValues failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = InstallLaunchMechanisms();

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[InstallLaunchMechanisms failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = InstallMsiHelper();

-  if (FAILED(hr)) {

-    SETUP_LOG(L1, (_T("[InstallMsiHelper failed][0x%08x]"), hr));

-    // TODO(omaha): Retry on ERROR_INSTALL_ALREADY_RUNNING like InstallManager

-    // if we move helper MSI installation after app installation.

-    ASSERT1(HRESULT_FROM_WIN32(ERROR_INSTALL_SERVICE_FAILURE) == hr ||

-            HRESULT_FROM_WIN32(ERROR_INSTALL_ALREADY_RUNNING) == hr);

-  }

-

-  HRESULT hr_register_com_server(RegisterOrUnregisterCOMLocalServer(true));

-  ASSERT1(SUCCEEDED(hr_register_com_server));

-  if (FAILED(hr_register_com_server)) {

-    OPT_LOG(L3, (_T("[RegisterOrUnregisterCOMLocalServer failed][0x%x]"),

-                 hr_register_com_server));

-    Ping ping;

-    VERIFY1(SUCCEEDED(ping_utils::SendGoopdatePing(

-                                      is_machine_,

-                                      args_->extra,

-                                      PingEvent::EVENT_SETUP_COM_SERVER_FAILURE,

-                                      hr_register_com_server,

-                                      0,

-                                      NULL,

-                                      &ping)));

-  }

-

-  ASSERT1(SUCCEEDED(VerifyCOMLocalServerRegistration(is_machine_)));

-

-  // We would prefer to uninstall previous versions last, but the web plugin

-  // requires that the old plugin is uninstalled before installing the new one.

-  VERIFY1(SUCCEEDED(UninstallPreviousVersions()));

-  VERIFY1(SUCCEEDED(InstallOptionalComponents()));

-

-  // Writing this value indicates that this Omaha version was successfully

-  // installed.

-  CString reg_update = ConfigManager::Instance()->registry_update(is_machine_);

-  hr = RegKey::SetValue(reg_update, kRegValueInstalledVersion, this_version_);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Delete the "LastChecked" registry value after a successful install or

-  // update so that Omaha checks for updates soon after the install. This

-  // helps detecting a heart beat from the new version sooner as well as

-  // avoiding deferring application updates for too long in the case where both

-  // Omaha and application updates are available.

-  RegKey::DeleteValue(reg_update, kRegValueLastChecked);

-

-  return S_OK;

-}

-

-

-HRESULT SetupGoogleUpdate::InstallRegistryValues() {

-  OPT_LOG(L3, (_T("[SetupGoogleUpdate::InstallRegistryValues]")));

-

-  const ConfigManager* cm = ConfigManager::Instance();

-  const TCHAR* keys[] = { cm->registry_google(is_machine_),

-                          cm->registry_update(is_machine_),

-                          cm->registry_client_state(is_machine_),

-                          cm->registry_clients(is_machine_),

-                          cm->registry_clients_goopdate(is_machine_),

-                          cm->registry_client_state_goopdate(is_machine_),

-                        };

-

-  HRESULT hr = RegKey::CreateKeys(keys, arraysize(keys));

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Failed to create reg keys][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (is_machine_) {

-    hr = CreateClientStateMedium();

-    if (FAILED(hr)) {

-      SETUP_LOG(L3, (_T("[CreateClientStateMedium failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  CString shell_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_);

-  if (shell_path.IsEmpty() || !File::Exists(shell_path)) {

-    SETUP_LOG(LE, (_T("[Failed to get valid shell path]")));

-    return E_FAIL;

-  }

-  hr = RegKey::SetValue(cm->registry_update(is_machine_),

-                        kRegValueInstalledPath,

-                        shell_path);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[Failed to write shell path][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Set all the information for this instance correctly in the registry.

-  const CString goopdate_state_key_name =

-      cm->registry_client_state_goopdate(is_machine_);

-

-  // IID and branding are optional, so ignore errors.

-  VERIFY1(SUCCEEDED(SetInstallationId()));

-  VERIFY1(SUCCEEDED(goopdate_utils::SetGoogleUpdateBranding(

-      goopdate_state_key_name,

-      args_->extra.brand_code,

-      args_->extra.client_id)));

-

-  // Set pv in ClientState for consistency. Optional, so ignore errors.

-  ASSERT1(!this_version_.IsEmpty());

-  VERIFY1(SUCCEEDED(RegKey::SetValue(goopdate_state_key_name,

-                                     kRegValueProductVersion,

-                                     this_version_)));

-

-  return S_OK;

-}

-

-// Creates the ClientStateMedium key and adds ACLs that allows authenticated

-// users to read and write values in its subkeys.

-// Since this key is not as secure as other keys, the supported values must be

-// limited and the use of them must be carefully designed.

-HRESULT SetupGoogleUpdate::CreateClientStateMedium() {

-  ASSERT1(is_machine_);

-

-  // Authenticated non-admins may read, write, and create values.

-  const ACCESS_MASK kNonAdminAccessMask = KEY_READ | KEY_SET_VALUE;

-  // The override privileges apply to all subkeys and values but not to the

-  // ClientStateMedium key itself.

-  const uint8 kAceFlags =

-      CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;

-

-  const CString key_full_name =

-      ConfigManager::Instance()->machine_registry_client_state_medium();

-  HRESULT hr = RegKey::CreateKey(key_full_name);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[Create ClientStateMedium failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  // GetNamedSecurityInfo requires the key name start with "MACHINE".

-  // TODO(omaha): Replace AddAllowedAce or add an override that takes a handle

-  // instead of a name to eliminate this issue.

-  CString compatible_key_name = key_full_name;

-  VERIFY1(1 == compatible_key_name.Replace(MACHINE_KEY_NAME, _T("MACHINE")));

-

-  hr = AddAllowedAce(compatible_key_name,

-                     SE_REGISTRY_KEY,

-                     Sids::Interactive(),

-                     kNonAdminAccessMask,

-                     kAceFlags);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[AddAllowedAce failed][%s][0x%08x]"),

-                   key_full_name, hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// Overwrites any existing IID for Omaha if a new one is specified.

-HRESULT SetupGoogleUpdate::SetInstallationId() {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::SetInstallationId]")));

-

-  if (GUID_NULL != args_->extra.installation_id) {

-    CString goopdate_state_key_name =

-        ConfigManager::Instance()->registry_client_state_goopdate(is_machine_);

-    return RegKey::SetValue(goopdate_state_key_name,

-                            kRegValueInstallationId,

-                            GuidToString(args_->extra.installation_id));

-  }

-

-  return S_OK;

-}

-

-HRESULT SetupGoogleUpdate::InstallLaunchMechanisms() {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallLaunchMechanisms]")));

-  if (is_machine_) {

-    HRESULT hr = InstallMachineLaunchMechanisms();

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[InstallMachineLaunchMechanisms fail][0x%08x]"), hr));

-      return hr;

-    }

-  } else {

-    HRESULT hr = InstallUserLaunchMechanisms();

-    if (FAILED(hr)) {

-      SETUP_LOG(LE, (_T("[InstallUserLaunchMechanisms failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-void SetupGoogleUpdate::UninstallLaunchMechanisms() {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallLaunchMechanisms]")));

-  if (is_machine_) {

-    VERIFY1(SUCCEEDED(SetupService::UninstallService()));

-  } else {

-    // We only need to do this in case of the user goopdate, as

-    // there is no machine Run at startup installation.

-    VERIFY1(SUCCEEDED(ConfigureUserRunAtStartup(false)));  // delete entry

-  }

-

-  VERIFY1(SUCCEEDED(goopdate_utils::UninstallGoopdateTasks(is_machine_)));

-}

-

-HRESULT SetupGoogleUpdate::InstallScheduledTask() {

-  CString exe_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_);

-

-  HighresTimer metrics_timer;

-  const ULONGLONG install_task_start_ms = metrics_timer.GetElapsedMs();

-

-  HRESULT hr = goopdate_utils::InstallGoopdateTasks(exe_path, is_machine_);

-

-  if (SUCCEEDED(hr)) {

-    const ULONGLONG install_task_end_ms = metrics_timer.GetElapsedMs();

-    ASSERT1(install_task_end_ms >= install_task_start_ms);

-    metric_setup_install_task_ms.AddSample(

-        install_task_end_ms - install_task_start_ms);

-    ++metric_setup_install_task_succeeded;

-  } else {

-    OPT_LOG(LEVEL_ERROR, (_T("[Install task failed][0x%08x]"), hr));

-    metric_setup_install_task_error = hr;

-  }

-

-  return hr;

-}

-

-// Assumes the any existing service instance has been stopped

-// TODO(omaha): Provide service_hr and task_hr failures in a ping.

-// They are no longer being provided in the URL.

-HRESULT SetupGoogleUpdate::InstallMachineLaunchMechanisms() {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallMachineLaunchMechanisms]")));

-  ++metric_setup_install_service_task_total;

-

-  // Install the service and scheduled task. Failing to install both will

-  // fail setup.

-  OPT_LOG(L1, (_T("[Installing service]")));

-  HighresTimer metrics_timer;

-

-  HRESULT service_hr = SetupService::InstallService(

-      goopdate_utils::BuildGoogleUpdateExePath(is_machine_));

-

-  if (SUCCEEDED(service_hr)) {

-    metric_setup_install_service_ms.AddSample(

-        metrics_timer.GetElapsedMs());

-    ++metric_setup_install_service_succeeded;

-  } else {

-    metric_setup_install_service_failed_ms.AddSample(

-        metrics_timer.GetElapsedMs());

-    OPT_LOG(LEVEL_ERROR, (_T("[Install service failed][0x%08x]"), service_hr));

-    metric_setup_install_service_error = service_hr;

-  }

-

-  HRESULT task_hr = InstallScheduledTask();

-

-  if (FAILED(service_hr) && FAILED(task_hr)) {

-    ++metric_setup_install_service_and_task_failed;

-    return service_hr;

-  }

-  if (args_->is_oem_set) {

-    // OEM installs are on clean systems in a controlled environment. We expect

-    // both mechanisms to install.

-    if (FAILED(service_hr)) {

-      return service_hr;

-    }

-    if (FAILED(task_hr)) {

-      return task_hr;

-    }

-  }

-

-  if (SUCCEEDED(service_hr) && SUCCEEDED(task_hr)) {

-    ++metric_setup_install_service_and_task_succeeded;

-  }

-

-  return S_OK;

-}

-

-HRESULT SetupGoogleUpdate::InstallUserLaunchMechanisms() {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallUserLaunchMechanisms]")));

-

-  HRESULT run_hr = ConfigureUserRunAtStartup(true);  // install

-  ASSERT(SUCCEEDED(run_hr), (_T("ConfigureRunAtStartup 0x%x"), run_hr));

-

-  HRESULT task_hr = InstallScheduledTask();

-  ASSERT(SUCCEEDED(task_hr), (_T("InstallScheduledTask 0x%x"), task_hr));

-

-  if (FAILED(run_hr) && FAILED(task_hr)) {

-    // We need atleast one launch mechanism.

-    return run_hr;

-  }

-

-  return S_OK;

-}

-

-// Sets a value in the Run key in the user registry to start the core.

-HRESULT SetupGoogleUpdate::ConfigureUserRunAtStartup(bool install) {

-  SETUP_LOG(L3, (_T("SetupGoogleUpdate::ConfigureUserRunAtStartup")));

-  // Always send false argument as this method is only called for user

-  // goopdate installs.

-  CString core_cmd = BuildCoreProcessCommandLine();

-  return ConfigureRunAtStartup(USER_KEY_NAME, kRunValueName, core_cmd, install);

-}

-

-HRESULT SetupGoogleUpdate::RegisterOrUnregisterCOMLocalServer(bool reg) {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::RegisterOrUnregisterCOMLocalServer]")

-                 _T("[%d]"), reg));

-  CString google_update_path = goopdate_utils::BuildGoogleUpdateExePath(

-                                   is_machine_);

-  CString register_cmd;

-  register_cmd.Format(_T("/%s"), reg ? _T("RegServer") : _T("UnregServer"));

-  HRESULT hr = RegisterOrUnregisterExe(google_update_path, register_cmd);

-  if (FAILED(hr)) {

-    SETUP_LOG(LE, (_T("[RegisterOrUnregisterExe failed][0x%08x]"), hr));

-    return hr;

-  }

-  return S_OK;

-}

-

-// Assumes that the MSI is in the current directory.

-// To debug MSI failures, use the following statement:

-// ::MsiEnableLog(INSTALLLOGMODE_VERBOSE, _T("C:\\msi.log"), NULL);

-HRESULT SetupGoogleUpdate::InstallMsiHelper() {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallMsiHelper]")));

-  if (!is_machine_) {

-    return S_OK;

-  }

-

-  ++metric_setup_helper_msi_install_total;

-  HighresTimer metrics_timer;

-

-  CString msi_path(app_util::GetCurrentModuleDirectory());

-  if (!::PathAppend(CStrBuf(msi_path, MAX_PATH), kHelperInstallerName)) {

-    ASSERT1(false);

-    return GOOPDATE_E_PATH_APPEND_FAILED;

-  }

-

-  // Setting INSTALLUILEVEL_NONE causes installation to be silent and not

-  // create a restore point.

-  ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);

-

-  // Try a normal install.

-  UINT res = ::MsiInstallProduct(msi_path, _T(""));

-  if (ERROR_PRODUCT_VERSION == res) {

-    // The product may already be installed. Force a reinstall of everything.

-    SETUP_LOG(L3, (_T("[ERROR_PRODUCT_VERSION returned - forcing reinstall]")));

-    res = ::MsiInstallProduct(msi_path,

-                              _T("REINSTALL=ALL REINSTALLMODE=vamus"));

-  }

-

-  HRESULT hr = HRESULT_FROM_WIN32(res);

-  if (FAILED(hr)) {

-    SETUP_LOG(L1, (_T("[MsiInstallProduct failed][0x%08x][%u]"), hr, res));

-    return hr;

-  }

-

-  metric_setup_helper_msi_install_ms.AddSample(metrics_timer.GetElapsedMs());

-  ++metric_setup_helper_msi_install_succeeded;

-  return S_OK;

-}

-

-// The MSI is uninstalled.

-// TODO(omaha): Make sure this works after deleting the MSI.

-HRESULT SetupGoogleUpdate::UninstallMsiHelper() {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallMsiHelper]")));

-  if (!is_machine_) {

-    return S_OK;

-  }

-

-  // Setting INSTALLUILEVEL_NONE causes installation to be silent and not

-  // create a restore point.

-  ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);

-  UINT res = ::MsiConfigureProduct(kHelperInstallerProductGuid,

-                                   INSTALLLEVEL_DEFAULT,

-                                   INSTALLSTATE_ABSENT);

-

-  // Ignore the product not currently installed result.

-  if ((ERROR_SUCCESS != res) && (ERROR_UNKNOWN_PRODUCT != res)) {

-    HRESULT hr = HRESULT_FROM_WIN32(res);

-    if (FAILED(hr)) {

-      SETUP_LOG(L1, (_T("[MsiInstallProduct failed][0x%08x][%u]"), hr, res));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT SetupGoogleUpdate::InstallOptionalComponents() {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallOptionalComponents]")));

-  ASSERT1(have_called_uninstall_previous_versions_);

-  // Failure of registration of optional components is acceptable in release

-  // builds.

-  HRESULT hr = S_OK;

-

-  CString goopdate_oneclick_path =

-      BuildSupportFileInstallPath(ACTIVEX_FILENAME);

-  hr = RegisterDll(goopdate_oneclick_path);

-  if (FAILED(hr)) {

-    SETUP_LOG(L1, (_T("[Register OneClick DLL failed][0x%08x]"), hr));

-  }

-

-#if 0

-  // Only install the BHO for machine installs. There is no corresponding HKCU

-  // registration for BHOs.

-  if (is_machine_) {

-    CString goopdate_bho_proxy_path = BuildSupportFileInstallPath(BHO_FILENAME);

-    hr = RegisterDll(goopdate_bho_proxy_path);

-    if (FAILED(hr)) {

-      SETUP_LOG(L1, (_T("[Register bho_proxy DLL failed][0x%08x]"), hr));

-    }

-  }

-#endif

-

-  return hr;

-}

-

-HRESULT SetupGoogleUpdate::UninstallOptionalComponents() {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallOptionalComponents]")));

-  // Unregistration. Failure is acceptable in release builds.

-  HRESULT hr = S_OK;

-

-  CString goopdate_oneclick_path =

-      BuildSupportFileInstallPath(ACTIVEX_FILENAME);

-  hr = UnregisterDll(goopdate_oneclick_path);

-  if (FAILED(hr)) {

-    SETUP_LOG(L1, (_T("[Unregister OneClick DLL failed][0x%08x]"), hr));

-  }

-

-#if 0

-  if (is_machine_) {

-    CString goopdate_bho_proxy_path = BuildSupportFileInstallPath(BHO_FILENAME);

-    hr = UnregisterDll(goopdate_bho_proxy_path);

-    if (FAILED(hr)) {

-      SETUP_LOG(L1, (_T("[Unregister bho_proxy DLL failed][0x%08x]"), hr));

-    }

-  }

-#endif

-

-  return hr;

-}

-

-CString SetupGoogleUpdate::BuildSupportFileInstallPath(

-    const CString& filename) const {

-  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::BuildSupportFileInstallPath][%s]"),

-                 filename));

-  CPath install_file_path = goopdate_utils::BuildInstallDirectory(

-                                is_machine_,

-                                this_version_);

-  VERIFY1(install_file_path.Append(filename));

-

-  return install_file_path;

-}

-

-CString SetupGoogleUpdate::BuildCoreProcessCommandLine() const {

-  CommandLineBuilder builder(COMMANDLINE_MODE_CORE);

-  CString google_update_path = goopdate_utils::BuildGoogleUpdateExePath(

-                                   is_machine_);

-  return builder.GetCommandLine(google_update_path);

-}

-

-HRESULT SetupGoogleUpdate::UninstallPreviousVersions() {

-#ifdef _DEBUG

-  have_called_uninstall_previous_versions_ = true;

-#endif

-

-  VERIFY1(SUCCEEDED(goopdate_utils::UninstallLegacyGoopdateTasks(is_machine_)));

-

-  CString install_path(

-      is_machine_ ? ConfigManager::Instance()->GetMachineGoopdateInstallDir() :

-                    ConfigManager::Instance()->GetUserGoopdateInstallDir());

-  SETUP_LOG(L1, (_T("[SetupGoogleUpdate::UninstallPreviousVersions][%s][%s]"),

-                 install_path, this_version_));

-  // An empty install_path can be disastrous as it will start deleting from the

-  // current directory.

-  ASSERT1(!install_path.IsEmpty());

-  if (install_path.IsEmpty()) {

-    return E_UNEXPECTED;

-  }

-

-  // In the Google\\Update directory, run over all files and directories.

-  WIN32_FIND_DATA file_data = {0};

-  CPath find_files(install_path);

-  VERIFY1(find_files.Append(_T("*.*")));

-

-  scoped_hfind find_handle(::FindFirstFile(find_files, &file_data));

-  ASSERT1(find_handle);

-  if (!find_handle) {

-    // We should have found ".", "..", and our versioned directory.

-    DWORD err = ::GetLastError();

-    SETUP_LOG(LE, (L"[Subdirs not found under dir][%s][%d]", find_files, err));

-    return HRESULT_FROM_WIN32(err);

-  }

-

-  BOOL found_next = TRUE;

-  for (; found_next; found_next = ::FindNextFile(get(find_handle),

-                                                 &file_data)) {

-    CPath file_or_directory(install_path);

-    VERIFY1(file_or_directory.Append(file_data.cFileName));

-    if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {

-      // Do not delete the shell as it is used by all versions.

-      if (_tcsicmp(file_data.cFileName, kGoopdateFileName)) {

-        DeleteBeforeOrAfterReboot(file_or_directory);

-      }

-    } else if (_tcscmp(file_data.cFileName, _T("..")) &&

-               _tcscmp(file_data.cFileName, _T(".")) &&

-               _tcsicmp(file_data.cFileName, this_version_) &&

-               (!args_->is_offline_set ||

-                _tcscmp(file_data.cFileName, OFFLINE_DIR_NAME))) {

-      // Unregister the previous version OneClick if it exists. Ignore

-      // failures. The file is named npGoogleOneClick*.dll.

-      CPath old_oneclick(file_or_directory);

-      VERIFY1(old_oneclick.Append(ACTIVEX_NAME _T("*.dll")));

-      WIN32_FIND_DATA old_oneclick_file_data = {0};

-      scoped_hfind found_oneclick(::FindFirstFile(old_oneclick,

-                                                  &old_oneclick_file_data));

-      if (found_oneclick) {

-        CPath old_oneclick_file(file_or_directory);

-        VERIFY1(old_oneclick_file.Append(old_oneclick_file_data.cFileName));

-        VERIFY1(SUCCEEDED(UnregisterDll(old_oneclick_file)));

-      }

-

-      if (is_machine_) {

-        // BHO is only installed for the machine case.

-        // Unregister the previous version BHO if it exists. Ignore failures.

-        CPath old_bho_dll(file_or_directory);

-        VERIFY1(old_bho_dll.Append(BHO_FILENAME));

-        if (File::Exists(old_bho_dll)) {

-          if (FAILED(UnregisterDll(old_bho_dll))) {

-            SETUP_LOG(LW, (L"[UnregisterDll() failed][%s]", old_bho_dll));

-          }

-        }

-      }

-      // Delete entire sub-directory.

-      DeleteBeforeOrAfterReboot(file_or_directory);

-    }

-  }

-

-  // Need to clean up old lang key for Goopdate.  Don't care about failure.

-  CString goopdate_client_key =

-      ConfigManager::Instance()->registry_clients_goopdate(is_machine_);

-  RegKey::DeleteValue(goopdate_client_key, kRegValueLanguage);

-

-  if (!found_next) {

-    DWORD err = ::GetLastError();

-    if (ERROR_NO_MORE_FILES != err) {

-      SETUP_LOG(LE, (L"[::FindNextFile() failed][%d]", err));

-      return HRESULT_FROM_WIN32(err);

-    }

-  }

-

-  return S_OK;

-}

-

-void SetupGoogleUpdate::Uninstall() {

-  OPT_LOG(L1, (_T("[SetupGoogleUpdate::Uninstall]")));

-

-  HRESULT hr = UninstallOptionalComponents();

-  if (FAILED(hr)) {

-    SETUP_LOG(LW, (_T("[UninstallOptionalComponents failed][0x%08x]"), hr));

-    ASSERT1(HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND) == hr);

-  }

-

-  // TODO(omaha): Some of the checks assume that The uninstall is being

-  // executed from the installed path. This is not the case when /install is

-  // uninstalling and will also not be the case when Setup is merged into one

-  // process.

-  if (goopdate_utils::IsRunningFromOfficialGoopdateDir(is_machine_)) {

-    ASSERT1(SUCCEEDED(VerifyCOMLocalServerRegistration(is_machine_)));

-  }

-  hr = RegisterOrUnregisterCOMLocalServer(false);

-  if (FAILED(hr)) {

-    SETUP_LOG(LW,

-              (_T("[RegisterOrUnregisterCOMLocalServer failed][0x%08x]"), hr));

-    ASSERT1(GOOGLEUPDATE_E_DLL_NOT_FOUND == hr ||

-            HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);

-  }

-

-  hr = UninstallMsiHelper();

-  if (FAILED(hr)) {

-    SETUP_LOG(L1, (_T("[UninstallMsiHelper failed][0x%08x]"), hr));

-    ASSERT1(HRESULT_FROM_WIN32(ERROR_INSTALL_SERVICE_FAILURE) == hr);

-  }

-

-  UninstallLaunchMechanisms();

-

-  // Remove everything under top level Google Update registry key.

-  hr = DeleteRegistryKeys();

-  ASSERT1(SUCCEEDED(hr) || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);

-}

-

-// Also deletes the main Google Update key if there is nothing in it.

-HRESULT SetupGoogleUpdate::DeleteRegistryKeys() {

-  OPT_LOG(L3, (_T("[SetupGoogleUpdate::DeleteRegistryKeys]")));

-

-  CString root_key = ConfigManager::Instance()->registry_update(is_machine_);

-  ASSERT1(!root_key.IsEmpty());

-

-  RegKey root;

-  HRESULT hr = root.Open(root_key);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  std::vector<CString> sub_keys;

-  size_t num_keys = root.GetSubkeyCount();

-  for (size_t i = 0; i < num_keys; ++i) {

-    CString sub_key_name;

-    hr = root.GetSubkeyNameAt(i, &sub_key_name);

-    ASSERT1(hr == S_OK);

-    if (SUCCEEDED(hr)) {

-      sub_keys.push_back(sub_key_name);

-    }

-  }

-

-  ASSERT1(num_keys == sub_keys.size());

-  // Delete all the sub keys of the root key.

-  for (size_t i = 0; i < num_keys; ++i) {

-    VERIFY1(SUCCEEDED(root.RecurseDeleteSubKey(sub_keys[i])));

-  }

-

-  // Now delete all the values of the root key.

-  // The mi and ui values are not deleted.

-  // The Last* values are not deleted.

-  // TODO(Omaha): The above a temporary fix for bug 1539293. Need a better

-  // long-term solution.

-  size_t num_values = root.GetValueCount();

-  std::vector<CString> value_names;

-  for (size_t i = 0; i < num_values; ++i) {

-    CString value_name;

-    DWORD type = 0;

-    hr = root.GetValueNameAt(i, &value_name, &type);

-    ASSERT1(hr == S_OK);

-    // TODO(omaha): Remove kRegValueLast* once we have an install API.

-    if (SUCCEEDED(hr)) {

-      if (value_name != kRegValueMachineId &&

-          value_name != kRegValueUserId &&

-          value_name != kRegValueLastInstallerResult &&

-          value_name != kRegValueLastInstallerError &&

-          value_name != kRegValueLastInstallerResultUIString &&

-          value_name != kRegValueLastInstallerSuccessLaunchCmdLine) {

-        value_names.push_back(value_name);

-      }

-    }

-  }

-

-  for (size_t i = 0; i < value_names.size(); ++i) {

-    VERIFY1(SUCCEEDED(root.DeleteValue(value_names[i])));

-  }

-

-  if (0 == root.GetValueCount() && 0 == root.GetSubkeyCount()) {

-    VERIFY1(SUCCEEDED(RegKey::DeleteKey(root_key, false)));

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/setup/setup_google_update.h"
+
+#include <msi.h>
+#include <atlpath.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "goopdate\google_update_idl.h"  // NOLINT
+#include "omaha/common/app_util.h"
+#include "omaha/common/atlregmapex.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/service_utils.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/user_info.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource.h"
+#include "omaha/setup/setup_metrics.h"
+#include "omaha/setup/setup_service.h"
+#include "omaha/worker/ping.h"
+#include "omaha/worker/ping_event.h"
+#include "omaha/worker/ping_utils.h"
+
+namespace omaha {
+
+namespace {
+
+#ifdef _DEBUG
+HRESULT VerifyCOMLocalServerRegistration(bool is_machine) {
+  // Validate the following:
+  // * LocalServer32 under CLSID_OnDemandMachineAppsClass or
+  //   CLSID_OnDemandUserAppsClass should be ...Google\Update\GoogleUpdate.exe.
+  // * InProcServer32 under CLSID of IID_IGoogleUpdate should be
+  //   ...Google\Update\{version}\goopdate.dll.
+  // * ProxyStubClsid32 under IGoogleUpdate interface should be the CLSID of the
+  //   proxy, which is IID_IGoogleUpdate.
+
+  CString base_clsid_key(goopdate_utils::GetHKRoot());
+  base_clsid_key += _T("\\Software\\Classes\\CLSID\\");
+  CString ondemand_clsid_key(base_clsid_key);
+  ondemand_clsid_key += GuidToString(is_machine ?
+                                     __uuidof(OnDemandMachineAppsClass) :
+                                     __uuidof(OnDemandUserAppsClass));
+  CString local_server_key(ondemand_clsid_key + _T("\\LocalServer32"));
+  CString installed_server;
+  ASSERT1(SUCCEEDED(RegKey::GetValue(local_server_key,
+                                     NULL,
+                                     &installed_server)));
+  ASSERT1(!installed_server.IsEmpty());
+
+  CString expected_server(app_util::GetModulePath(NULL));
+  EnclosePath(&expected_server);
+  ASSERT1(!expected_server.IsEmpty());
+  SETUP_LOG(L3, (_T("[installed_server=%s][expected_server=%s]"),
+                 installed_server, expected_server));
+  ASSERT1(installed_server == expected_server);
+
+  const GUID proxy_clsid = PROXY_CLSID_IS;
+  CString ondemand_proxy_clsid_key(base_clsid_key);
+  ondemand_proxy_clsid_key += GuidToString(proxy_clsid);
+  CString inproc_server_key(ondemand_proxy_clsid_key + _T("\\InProcServer32"));
+  ASSERT1(SUCCEEDED(RegKey::GetValue(inproc_server_key,
+                                     NULL,
+                                     &installed_server)));
+  ASSERT1(!installed_server.IsEmpty());
+  expected_server = app_util::GetCurrentModulePath();
+  ASSERT1(!expected_server.IsEmpty());
+  SETUP_LOG(L3, (_T("[installed proxy=%s][expected proxy=%s]"),
+                 installed_server, expected_server));
+  ASSERT1(installed_server == expected_server);
+
+  CString igoogleupdate_interface_key(goopdate_utils::GetHKRoot());
+  igoogleupdate_interface_key += _T("\\Software\\Classes\\Interface\\");
+  igoogleupdate_interface_key += GuidToString(__uuidof(IGoogleUpdate));
+  igoogleupdate_interface_key += _T("\\ProxyStubClsid32");
+  CString proxy_interface_value;
+  ASSERT1(SUCCEEDED(RegKey::GetValue(igoogleupdate_interface_key,
+                                     NULL,
+                                     &proxy_interface_value)));
+  ASSERT1(!proxy_interface_value.IsEmpty());
+  ASSERT1(proxy_interface_value == GuidToString(proxy_clsid));
+
+  return S_OK;
+}
+#endif
+
+}  // namespace
+
+SetupGoogleUpdate::SetupGoogleUpdate(bool is_machine,
+                                     const CommandLineArgs* args)
+    : is_machine_(is_machine),
+#ifdef _DEBUG
+      have_called_uninstall_previous_versions_(false),
+#endif
+      args_(args) {
+  this_version_ = GetVersionString();
+}
+
+SetupGoogleUpdate::~SetupGoogleUpdate() {
+  SETUP_LOG(L2, (_T("[SetupGoogleUpdate::~SetupGoogleUpdate]")));
+}
+
+// TODO(omaha): Add a VerifyInstall() method that can be called by /handoff
+// instances to verify the installation and call FinishInstall() if it fails.
+
+// Assumes the caller is ensuring this is the only running instance of setup.
+// The original process holds the lock while it waits for this one to complete.
+HRESULT SetupGoogleUpdate::FinishInstall() {
+  SETUP_LOG(L2, (_T("[SetupGoogleUpdate::FinishInstall]")));
+
+  HRESULT hr = InstallRegistryValues();
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[InstallRegistryValues failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = InstallLaunchMechanisms();
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[InstallLaunchMechanisms failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = InstallMsiHelper();
+  if (FAILED(hr)) {
+    SETUP_LOG(L1, (_T("[InstallMsiHelper failed][0x%08x]"), hr));
+    // TODO(omaha): Retry on ERROR_INSTALL_ALREADY_RUNNING like InstallManager
+    // if we move helper MSI installation after app installation.
+    ASSERT1(HRESULT_FROM_WIN32(ERROR_INSTALL_SERVICE_FAILURE) == hr ||
+            HRESULT_FROM_WIN32(ERROR_INSTALL_ALREADY_RUNNING) == hr);
+  }
+
+  HRESULT hr_register_com_server(RegisterOrUnregisterCOMLocalServer(true));
+  ASSERT1(SUCCEEDED(hr_register_com_server));
+  if (FAILED(hr_register_com_server)) {
+    OPT_LOG(L3, (_T("[RegisterOrUnregisterCOMLocalServer failed][0x%x]"),
+                 hr_register_com_server));
+    Ping ping;
+    VERIFY1(SUCCEEDED(ping_utils::SendGoopdatePing(
+                                      is_machine_,
+                                      args_->extra,
+                                      PingEvent::EVENT_SETUP_COM_SERVER_FAILURE,
+                                      hr_register_com_server,
+                                      0,
+                                      NULL,
+                                      &ping)));
+  }
+
+  ASSERT1(SUCCEEDED(VerifyCOMLocalServerRegistration(is_machine_)));
+
+  // We would prefer to uninstall previous versions last, but the web plugin
+  // requires that the old plugin is uninstalled before installing the new one.
+  VERIFY1(SUCCEEDED(UninstallPreviousVersions()));
+  VERIFY1(SUCCEEDED(InstallOptionalComponents()));
+
+  // Writing this value indicates that this Omaha version was successfully
+  // installed.
+  CString reg_update = ConfigManager::Instance()->registry_update(is_machine_);
+  hr = RegKey::SetValue(reg_update, kRegValueInstalledVersion, this_version_);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Delete the "LastChecked" registry value after a successful install or
+  // update so that Omaha checks for updates soon after the install. This
+  // helps detecting a heart beat from the new version sooner as well as
+  // avoiding deferring application updates for too long in the case where both
+  // Omaha and application updates are available.
+  RegKey::DeleteValue(reg_update, kRegValueLastChecked);
+
+  return S_OK;
+}
+
+
+HRESULT SetupGoogleUpdate::InstallRegistryValues() {
+  OPT_LOG(L3, (_T("[SetupGoogleUpdate::InstallRegistryValues]")));
+
+  const ConfigManager* cm = ConfigManager::Instance();
+  const TCHAR* keys[] = { cm->registry_google(is_machine_),
+                          cm->registry_update(is_machine_),
+                          cm->registry_client_state(is_machine_),
+                          cm->registry_clients(is_machine_),
+                          cm->registry_clients_goopdate(is_machine_),
+                          cm->registry_client_state_goopdate(is_machine_),
+                        };
+
+  HRESULT hr = RegKey::CreateKeys(keys, arraysize(keys));
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Failed to create reg keys][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (is_machine_) {
+    hr = CreateClientStateMedium();
+    if (FAILED(hr)) {
+      SETUP_LOG(L3, (_T("[CreateClientStateMedium failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  CString shell_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_);
+  if (shell_path.IsEmpty() || !File::Exists(shell_path)) {
+    SETUP_LOG(LE, (_T("[Failed to get valid shell path]")));
+    return E_FAIL;
+  }
+  hr = RegKey::SetValue(cm->registry_update(is_machine_),
+                        kRegValueInstalledPath,
+                        shell_path);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[Failed to write shell path][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Set all the information for this instance correctly in the registry.
+  const CString goopdate_state_key_name =
+      cm->registry_client_state_goopdate(is_machine_);
+
+  // IID and branding are optional, so ignore errors.
+  VERIFY1(SUCCEEDED(SetInstallationId()));
+  VERIFY1(SUCCEEDED(goopdate_utils::SetGoogleUpdateBranding(
+      goopdate_state_key_name,
+      args_->extra.brand_code,
+      args_->extra.client_id)));
+
+  // Set pv in ClientState for consistency. Optional, so ignore errors.
+  ASSERT1(!this_version_.IsEmpty());
+  VERIFY1(SUCCEEDED(RegKey::SetValue(goopdate_state_key_name,
+                                     kRegValueProductVersion,
+                                     this_version_)));
+
+  return S_OK;
+}
+
+// Creates the ClientStateMedium key and adds ACLs that allows authenticated
+// users to read and write values in its subkeys.
+// Since this key is not as secure as other keys, the supported values must be
+// limited and the use of them must be carefully designed.
+HRESULT SetupGoogleUpdate::CreateClientStateMedium() {
+  ASSERT1(is_machine_);
+
+  // Authenticated non-admins may read, write, and create values.
+  const ACCESS_MASK kNonAdminAccessMask = KEY_READ | KEY_SET_VALUE;
+  // The override privileges apply to all subkeys and values but not to the
+  // ClientStateMedium key itself.
+  const uint8 kAceFlags =
+      CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
+
+  const CString key_full_name =
+      ConfigManager::Instance()->machine_registry_client_state_medium();
+  HRESULT hr = RegKey::CreateKey(key_full_name);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[Create ClientStateMedium failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  // GetNamedSecurityInfo requires the key name start with "MACHINE".
+  // TODO(omaha): Replace AddAllowedAce or add an override that takes a handle
+  // instead of a name to eliminate this issue.
+  CString compatible_key_name = key_full_name;
+  VERIFY1(1 == compatible_key_name.Replace(MACHINE_KEY_NAME, _T("MACHINE")));
+
+  hr = AddAllowedAce(compatible_key_name,
+                     SE_REGISTRY_KEY,
+                     Sids::Interactive(),
+                     kNonAdminAccessMask,
+                     kAceFlags);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[AddAllowedAce failed][%s][0x%08x]"),
+                   key_full_name, hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// Overwrites any existing IID for Omaha if a new one is specified.
+HRESULT SetupGoogleUpdate::SetInstallationId() {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::SetInstallationId]")));
+
+  if (GUID_NULL != args_->extra.installation_id) {
+    CString goopdate_state_key_name =
+        ConfigManager::Instance()->registry_client_state_goopdate(is_machine_);
+    return RegKey::SetValue(goopdate_state_key_name,
+                            kRegValueInstallationId,
+                            GuidToString(args_->extra.installation_id));
+  }
+
+  return S_OK;
+}
+
+HRESULT SetupGoogleUpdate::InstallLaunchMechanisms() {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallLaunchMechanisms]")));
+  if (is_machine_) {
+    HRESULT hr = InstallMachineLaunchMechanisms();
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[InstallMachineLaunchMechanisms fail][0x%08x]"), hr));
+      return hr;
+    }
+  } else {
+    HRESULT hr = InstallUserLaunchMechanisms();
+    if (FAILED(hr)) {
+      SETUP_LOG(LE, (_T("[InstallUserLaunchMechanisms failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+void SetupGoogleUpdate::UninstallLaunchMechanisms() {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallLaunchMechanisms]")));
+  if (is_machine_) {
+    VERIFY1(SUCCEEDED(SetupService::UninstallService()));
+  } else {
+    // We only need to do this in case of the user goopdate, as
+    // there is no machine Run at startup installation.
+    VERIFY1(SUCCEEDED(ConfigureUserRunAtStartup(false)));  // delete entry
+  }
+
+  VERIFY1(SUCCEEDED(goopdate_utils::UninstallGoopdateTasks(is_machine_)));
+}
+
+HRESULT SetupGoogleUpdate::InstallScheduledTask() {
+  CString exe_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_);
+
+  HighresTimer metrics_timer;
+  const ULONGLONG install_task_start_ms = metrics_timer.GetElapsedMs();
+
+  HRESULT hr = goopdate_utils::InstallGoopdateTasks(exe_path, is_machine_);
+
+  if (SUCCEEDED(hr)) {
+    const ULONGLONG install_task_end_ms = metrics_timer.GetElapsedMs();
+    ASSERT1(install_task_end_ms >= install_task_start_ms);
+    metric_setup_install_task_ms.AddSample(
+        install_task_end_ms - install_task_start_ms);
+    ++metric_setup_install_task_succeeded;
+  } else {
+    OPT_LOG(LEVEL_ERROR, (_T("[Install task failed][0x%08x]"), hr));
+    metric_setup_install_task_error = hr;
+  }
+
+  return hr;
+}
+
+// Assumes the any existing service instance has been stopped
+// TODO(omaha): Provide service_hr and task_hr failures in a ping.
+// They are no longer being provided in the URL.
+HRESULT SetupGoogleUpdate::InstallMachineLaunchMechanisms() {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallMachineLaunchMechanisms]")));
+  ++metric_setup_install_service_task_total;
+
+  // Install the service and scheduled task. Failing to install both will
+  // fail setup.
+  OPT_LOG(L1, (_T("[Installing service]")));
+  HighresTimer metrics_timer;
+
+  HRESULT service_hr = SetupService::InstallService(
+      goopdate_utils::BuildGoogleUpdateExePath(is_machine_));
+
+  if (SUCCEEDED(service_hr)) {
+    metric_setup_install_service_ms.AddSample(
+        metrics_timer.GetElapsedMs());
+    ++metric_setup_install_service_succeeded;
+  } else {
+    metric_setup_install_service_failed_ms.AddSample(
+        metrics_timer.GetElapsedMs());
+    OPT_LOG(LEVEL_ERROR, (_T("[Install service failed][0x%08x]"), service_hr));
+    metric_setup_install_service_error = service_hr;
+  }
+
+  HRESULT task_hr = InstallScheduledTask();
+
+  if (FAILED(service_hr) && FAILED(task_hr)) {
+    ++metric_setup_install_service_and_task_failed;
+    return service_hr;
+  }
+  if (args_->is_oem_set) {
+    // OEM installs are on clean systems in a controlled environment. We expect
+    // both mechanisms to install.
+    if (FAILED(service_hr)) {
+      return service_hr;
+    }
+    if (FAILED(task_hr)) {
+      return task_hr;
+    }
+  }
+
+  if (SUCCEEDED(service_hr) && SUCCEEDED(task_hr)) {
+    ++metric_setup_install_service_and_task_succeeded;
+  }
+
+  return S_OK;
+}
+
+HRESULT SetupGoogleUpdate::InstallUserLaunchMechanisms() {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallUserLaunchMechanisms]")));
+
+  HRESULT run_hr = ConfigureUserRunAtStartup(true);  // install
+  ASSERT(SUCCEEDED(run_hr), (_T("ConfigureRunAtStartup 0x%x"), run_hr));
+
+  HRESULT task_hr = InstallScheduledTask();
+  ASSERT(SUCCEEDED(task_hr), (_T("InstallScheduledTask 0x%x"), task_hr));
+
+  if (FAILED(run_hr) && FAILED(task_hr)) {
+    // We need atleast one launch mechanism.
+    return run_hr;
+  }
+
+  return S_OK;
+}
+
+// Sets a value in the Run key in the user registry to start the core.
+HRESULT SetupGoogleUpdate::ConfigureUserRunAtStartup(bool install) {
+  SETUP_LOG(L3, (_T("SetupGoogleUpdate::ConfigureUserRunAtStartup")));
+  // Always send false argument as this method is only called for user
+  // goopdate installs.
+  CString core_cmd = BuildCoreProcessCommandLine();
+  return ConfigureRunAtStartup(USER_KEY_NAME, kRunValueName, core_cmd, install);
+}
+
+HRESULT SetupGoogleUpdate::RegisterOrUnregisterCOMLocalServer(bool reg) {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::RegisterOrUnregisterCOMLocalServer]")
+                 _T("[%d]"), reg));
+  CString google_update_path = goopdate_utils::BuildGoogleUpdateExePath(
+                                   is_machine_);
+  CString register_cmd;
+  register_cmd.Format(_T("/%s"), reg ? _T("RegServer") : _T("UnregServer"));
+  HRESULT hr = RegisterOrUnregisterExe(google_update_path, register_cmd);
+  if (FAILED(hr)) {
+    SETUP_LOG(LE, (_T("[RegisterOrUnregisterExe failed][0x%08x]"), hr));
+    return hr;
+  }
+  return S_OK;
+}
+
+// Assumes that the MSI is in the current directory.
+// To debug MSI failures, use the following statement:
+// ::MsiEnableLog(INSTALLLOGMODE_VERBOSE, _T("C:\\msi.log"), NULL);
+HRESULT SetupGoogleUpdate::InstallMsiHelper() {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallMsiHelper]")));
+  if (!is_machine_) {
+    return S_OK;
+  }
+
+  ++metric_setup_helper_msi_install_total;
+  HighresTimer metrics_timer;
+
+  CString msi_path(app_util::GetCurrentModuleDirectory());
+  if (!::PathAppend(CStrBuf(msi_path, MAX_PATH), kHelperInstallerName)) {
+    ASSERT1(false);
+    return GOOPDATE_E_PATH_APPEND_FAILED;
+  }
+
+  // Setting INSTALLUILEVEL_NONE causes installation to be silent and not
+  // create a restore point.
+  ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+
+  // Try a normal install.
+  UINT res = ::MsiInstallProduct(msi_path, _T(""));
+  if (ERROR_PRODUCT_VERSION == res) {
+    // The product may already be installed. Force a reinstall of everything.
+    SETUP_LOG(L3, (_T("[ERROR_PRODUCT_VERSION returned - forcing reinstall]")));
+    res = ::MsiInstallProduct(msi_path,
+                              _T("REINSTALL=ALL REINSTALLMODE=vamus"));
+  }
+
+  HRESULT hr = HRESULT_FROM_WIN32(res);
+  if (FAILED(hr)) {
+    SETUP_LOG(L1, (_T("[MsiInstallProduct failed][0x%08x][%u]"), hr, res));
+    return hr;
+  }
+
+  metric_setup_helper_msi_install_ms.AddSample(metrics_timer.GetElapsedMs());
+  ++metric_setup_helper_msi_install_succeeded;
+  return S_OK;
+}
+
+// The MSI is uninstalled.
+// TODO(omaha): Make sure this works after deleting the MSI.
+HRESULT SetupGoogleUpdate::UninstallMsiHelper() {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallMsiHelper]")));
+  if (!is_machine_) {
+    return S_OK;
+  }
+
+  // Setting INSTALLUILEVEL_NONE causes installation to be silent and not
+  // create a restore point.
+  ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+  UINT res = ::MsiConfigureProduct(kHelperInstallerProductGuid,
+                                   INSTALLLEVEL_DEFAULT,
+                                   INSTALLSTATE_ABSENT);
+
+  // Ignore the product not currently installed result.
+  if ((ERROR_SUCCESS != res) && (ERROR_UNKNOWN_PRODUCT != res)) {
+    HRESULT hr = HRESULT_FROM_WIN32(res);
+    if (FAILED(hr)) {
+      SETUP_LOG(L1, (_T("[MsiInstallProduct failed][0x%08x][%u]"), hr, res));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT SetupGoogleUpdate::InstallOptionalComponents() {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallOptionalComponents]")));
+  ASSERT1(have_called_uninstall_previous_versions_);
+  // Failure of registration of optional components is acceptable in release
+  // builds.
+  HRESULT hr = S_OK;
+
+  CString goopdate_oneclick_path =
+      BuildSupportFileInstallPath(ACTIVEX_FILENAME);
+  hr = RegisterDll(goopdate_oneclick_path);
+  if (FAILED(hr)) {
+    SETUP_LOG(L1, (_T("[Register OneClick DLL failed][0x%08x]"), hr));
+  }
+
+#if 0
+  // Only install the BHO for machine installs. There is no corresponding HKCU
+  // registration for BHOs.
+  if (is_machine_) {
+    CString goopdate_bho_proxy_path = BuildSupportFileInstallPath(BHO_FILENAME);
+    hr = RegisterDll(goopdate_bho_proxy_path);
+    if (FAILED(hr)) {
+      SETUP_LOG(L1, (_T("[Register bho_proxy DLL failed][0x%08x]"), hr));
+    }
+  }
+#endif
+
+  return hr;
+}
+
+HRESULT SetupGoogleUpdate::UninstallOptionalComponents() {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallOptionalComponents]")));
+  // Unregistration. Failure is acceptable in release builds.
+  HRESULT hr = S_OK;
+
+  CString goopdate_oneclick_path =
+      BuildSupportFileInstallPath(ACTIVEX_FILENAME);
+  hr = UnregisterDll(goopdate_oneclick_path);
+  if (FAILED(hr)) {
+    SETUP_LOG(L1, (_T("[Unregister OneClick DLL failed][0x%08x]"), hr));
+  }
+
+#if 0
+  if (is_machine_) {
+    CString goopdate_bho_proxy_path = BuildSupportFileInstallPath(BHO_FILENAME);
+    hr = UnregisterDll(goopdate_bho_proxy_path);
+    if (FAILED(hr)) {
+      SETUP_LOG(L1, (_T("[Unregister bho_proxy DLL failed][0x%08x]"), hr));
+    }
+  }
+#endif
+
+  return hr;
+}
+
+CString SetupGoogleUpdate::BuildSupportFileInstallPath(
+    const CString& filename) const {
+  SETUP_LOG(L3, (_T("[SetupGoogleUpdate::BuildSupportFileInstallPath][%s]"),
+                 filename));
+  CPath install_file_path = goopdate_utils::BuildInstallDirectory(
+                                is_machine_,
+                                this_version_);
+  VERIFY1(install_file_path.Append(filename));
+
+  return install_file_path;
+}
+
+CString SetupGoogleUpdate::BuildCoreProcessCommandLine() const {
+  CommandLineBuilder builder(COMMANDLINE_MODE_CORE);
+  CString google_update_path = goopdate_utils::BuildGoogleUpdateExePath(
+                                   is_machine_);
+  return builder.GetCommandLine(google_update_path);
+}
+
+HRESULT SetupGoogleUpdate::UninstallPreviousVersions() {
+#ifdef _DEBUG
+  have_called_uninstall_previous_versions_ = true;
+#endif
+
+  VERIFY1(SUCCEEDED(goopdate_utils::UninstallLegacyGoopdateTasks(is_machine_)));
+
+  CString install_path(
+      is_machine_ ? ConfigManager::Instance()->GetMachineGoopdateInstallDir() :
+                    ConfigManager::Instance()->GetUserGoopdateInstallDir());
+  SETUP_LOG(L1, (_T("[SetupGoogleUpdate::UninstallPreviousVersions][%s][%s]"),
+                 install_path, this_version_));
+  // An empty install_path can be disastrous as it will start deleting from the
+  // current directory.
+  ASSERT1(!install_path.IsEmpty());
+  if (install_path.IsEmpty()) {
+    return E_UNEXPECTED;
+  }
+
+  // In the Google\\Update directory, run over all files and directories.
+  WIN32_FIND_DATA file_data = {0};
+  CPath find_files(install_path);
+  VERIFY1(find_files.Append(_T("*.*")));
+
+  scoped_hfind find_handle(::FindFirstFile(find_files, &file_data));
+  ASSERT1(find_handle);
+  if (!find_handle) {
+    // We should have found ".", "..", and our versioned directory.
+    DWORD err = ::GetLastError();
+    SETUP_LOG(LE, (L"[Subdirs not found under dir][%s][%d]", find_files, err));
+    return HRESULT_FROM_WIN32(err);
+  }
+
+  BOOL found_next = TRUE;
+  for (; found_next; found_next = ::FindNextFile(get(find_handle),
+                                                 &file_data)) {
+    CPath file_or_directory(install_path);
+    VERIFY1(file_or_directory.Append(file_data.cFileName));
+    if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+      // Do not delete the shell as it is used by all versions.
+      if (_tcsicmp(file_data.cFileName, kGoopdateFileName)) {
+        DeleteBeforeOrAfterReboot(file_or_directory);
+      }
+    } else if (_tcscmp(file_data.cFileName, _T("..")) &&
+               _tcscmp(file_data.cFileName, _T(".")) &&
+               _tcsicmp(file_data.cFileName, this_version_) &&
+               (!args_->is_offline_set ||
+                _tcscmp(file_data.cFileName, OFFLINE_DIR_NAME))) {
+      // Unregister the previous version OneClick if it exists. Ignore
+      // failures. The file is named npGoogleOneClick*.dll.
+      CPath old_oneclick(file_or_directory);
+      VERIFY1(old_oneclick.Append(ACTIVEX_NAME _T("*.dll")));
+      WIN32_FIND_DATA old_oneclick_file_data = {0};
+      scoped_hfind found_oneclick(::FindFirstFile(old_oneclick,
+                                                  &old_oneclick_file_data));
+      if (found_oneclick) {
+        CPath old_oneclick_file(file_or_directory);
+        VERIFY1(old_oneclick_file.Append(old_oneclick_file_data.cFileName));
+        VERIFY1(SUCCEEDED(UnregisterDll(old_oneclick_file)));
+      }
+
+      if (is_machine_) {
+        // BHO is only installed for the machine case.
+        // Unregister the previous version BHO if it exists. Ignore failures.
+        CPath old_bho_dll(file_or_directory);
+        VERIFY1(old_bho_dll.Append(BHO_FILENAME));
+        if (File::Exists(old_bho_dll)) {
+          if (FAILED(UnregisterDll(old_bho_dll))) {
+            SETUP_LOG(LW, (L"[UnregisterDll() failed][%s]", old_bho_dll));
+          }
+        }
+      }
+      // Delete entire sub-directory.
+      DeleteBeforeOrAfterReboot(file_or_directory);
+    }
+  }
+
+  // Need to clean up old lang key for Goopdate.  Don't care about failure.
+  CString goopdate_client_key =
+      ConfigManager::Instance()->registry_clients_goopdate(is_machine_);
+  RegKey::DeleteValue(goopdate_client_key, kRegValueLanguage);
+
+  if (!found_next) {
+    DWORD err = ::GetLastError();
+    if (ERROR_NO_MORE_FILES != err) {
+      SETUP_LOG(LE, (L"[::FindNextFile() failed][%d]", err));
+      return HRESULT_FROM_WIN32(err);
+    }
+  }
+
+  return S_OK;
+}
+
+void SetupGoogleUpdate::Uninstall() {
+  OPT_LOG(L1, (_T("[SetupGoogleUpdate::Uninstall]")));
+
+  HRESULT hr = UninstallOptionalComponents();
+  if (FAILED(hr)) {
+    SETUP_LOG(LW, (_T("[UninstallOptionalComponents failed][0x%08x]"), hr));
+    ASSERT1(HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND) == hr);
+  }
+
+  // TODO(omaha): Some of the checks assume that The uninstall is being
+  // executed from the installed path. This is not the case when /install is
+  // uninstalling and will also not be the case when Setup is merged into one
+  // process.
+  if (goopdate_utils::IsRunningFromOfficialGoopdateDir(is_machine_)) {
+    ASSERT1(SUCCEEDED(VerifyCOMLocalServerRegistration(is_machine_)));
+  }
+  hr = RegisterOrUnregisterCOMLocalServer(false);
+  if (FAILED(hr)) {
+    SETUP_LOG(LW,
+              (_T("[RegisterOrUnregisterCOMLocalServer failed][0x%08x]"), hr));
+    ASSERT1(GOOGLEUPDATE_E_DLL_NOT_FOUND == hr ||
+            HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);
+  }
+
+  hr = UninstallMsiHelper();
+  if (FAILED(hr)) {
+    SETUP_LOG(L1, (_T("[UninstallMsiHelper failed][0x%08x]"), hr));
+    ASSERT1(HRESULT_FROM_WIN32(ERROR_INSTALL_SERVICE_FAILURE) == hr);
+  }
+
+  UninstallLaunchMechanisms();
+
+  // Remove everything under top level Google Update registry key.
+  hr = DeleteRegistryKeys();
+  ASSERT1(SUCCEEDED(hr) || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);
+}
+
+// Also deletes the main Google Update key if there is nothing in it.
+HRESULT SetupGoogleUpdate::DeleteRegistryKeys() {
+  OPT_LOG(L3, (_T("[SetupGoogleUpdate::DeleteRegistryKeys]")));
+
+  CString root_key = ConfigManager::Instance()->registry_update(is_machine_);
+  ASSERT1(!root_key.IsEmpty());
+
+  RegKey root;
+  HRESULT hr = root.Open(root_key);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  std::vector<CString> sub_keys;
+  size_t num_keys = root.GetSubkeyCount();
+  for (size_t i = 0; i < num_keys; ++i) {
+    CString sub_key_name;
+    hr = root.GetSubkeyNameAt(i, &sub_key_name);
+    ASSERT1(hr == S_OK);
+    if (SUCCEEDED(hr)) {
+      sub_keys.push_back(sub_key_name);
+    }
+  }
+
+  ASSERT1(num_keys == sub_keys.size());
+  // Delete all the sub keys of the root key.
+  for (size_t i = 0; i < num_keys; ++i) {
+    VERIFY1(SUCCEEDED(root.RecurseDeleteSubKey(sub_keys[i])));
+  }
+
+  // Now delete all the values of the root key.
+  // The mi and ui values are not deleted.
+  // The Last* values are not deleted.
+  // TODO(Omaha): The above a temporary fix for bug 1539293. Need a better
+  // long-term solution.
+  size_t num_values = root.GetValueCount();
+  std::vector<CString> value_names;
+  for (size_t i = 0; i < num_values; ++i) {
+    CString value_name;
+    DWORD type = 0;
+    hr = root.GetValueNameAt(i, &value_name, &type);
+    ASSERT1(hr == S_OK);
+    // TODO(omaha): Remove kRegValueLast* once we have an install API.
+    if (SUCCEEDED(hr)) {
+      if (value_name != kRegValueMachineId &&
+          value_name != kRegValueUserId &&
+          value_name != kRegValueLastInstallerResult &&
+          value_name != kRegValueLastInstallerError &&
+          value_name != kRegValueLastInstallerResultUIString &&
+          value_name != kRegValueLastInstallerSuccessLaunchCmdLine) {
+        value_names.push_back(value_name);
+      }
+    }
+  }
+
+  for (size_t i = 0; i < value_names.size(); ++i) {
+    VERIFY1(SUCCEEDED(root.DeleteValue(value_names[i])));
+  }
+
+  if (0 == root.GetValueCount() && 0 == root.GetSubkeyCount()) {
+    VERIFY1(SUCCEEDED(RegKey::DeleteKey(root_key, false)));
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/setup/setup_google_update.h b/setup/setup_google_update.h
index c6b6337..e15cdc7 100644
--- a/setup/setup_google_update.h
+++ b/setup/setup_google_update.h
@@ -1,119 +1,119 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_SETUP_SETUP_GOOGLE_UPDATE_H__

-#define OMAHA_SETUP_SETUP_GOOGLE_UPDATE_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-

-namespace omaha {

-

-struct CommandLineArgs;

-

-class SetupGoogleUpdate {

- public:

-  SetupGoogleUpdate(bool is_machine, const CommandLineArgs* args);

-  ~SetupGoogleUpdate();

-

-  HRESULT FinishInstall();

-

-  // Uninstalls Google Update registrations created by FinishInstall().

-  void Uninstall();

-

-  // Build the command line to execute the installed core.

-  CString BuildCoreProcessCommandLine() const;

-

- private:

-  HRESULT FinishMachineInstall();

-

-  // Installs appropriate launch mechanism(s) starts one of them if appropriate.

-  HRESULT InstallLaunchMechanisms();

-

-  // Uninstalls appropriate launch mechanism(s).

-  void UninstallLaunchMechanisms();

-

-  // Installs the scheduled task which runs the GoogleUpdate core.

-  HRESULT InstallScheduledTask();

-

-  // Installs the service and scheduled task.

-  HRESULT InstallMachineLaunchMechanisms();

-

-  // Add Google Update to the user's Run key.

-  HRESULT InstallUserLaunchMechanisms();

-

-  // Configures goopdate to run at startup.

-  //

-  // @param install: true if we should configure to run at startup, false if we

-  //   should clean up the configuration (meaning that we should not run at

-  //   startup)

-  HRESULT ConfigureUserRunAtStartup(bool install);

-

-  HRESULT InstallRegistryValues();

-

-  // Create's the ClientStateMedium key with relaxed ACLs.

-  // Only call for machine installs.

-  HRESULT CreateClientStateMedium();

-

-  // Writes the Installation ID to the registry.

-  HRESULT SetInstallationId();

-

-  // Register COM classes and interfaces.

-  HRESULT RegisterOrUnregisterCOMLocalServer(bool register);

-

-  // Installs the helper (MSI).

-  HRESULT InstallMsiHelper();

-

-  // Uninstalls the helper (MSI).

-  HRESULT UninstallMsiHelper();

-

-  HRESULT InstallOptionalComponents();

-

-  HRESULT UninstallOptionalComponents();

-

-  // Build the install file path for support files. For example,

-  CString BuildSupportFileInstallPath(const CString& filename) const;

-

-  // Deletes the Omaha registry keys except the machine id and the user id

-  // values under the main update key.

-  HRESULT DeleteRegistryKeys();

-

-  // Uninstall previous versions after an overinstall of the new version. We do

-  // the following:

-  //   * Delete all sub-directories under Google\\Update, except the running

-  //     version's directory.

-  //   * Uninstall the BHO, so IE does not load it in the future.

-  HRESULT UninstallPreviousVersions();

-

-  const bool is_machine_;

-  const CommandLineArgs* const args_;

-  CString this_version_;

-

-#ifdef _DEBUG

-  bool have_called_uninstall_previous_versions_;

-#endif

-

-  friend class SetupGoogleUpdateTest;

-  friend class AppManagerTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(SetupGoogleUpdate);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_SETUP_SETUP_GOOGLE_UPDATE_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_SETUP_SETUP_GOOGLE_UPDATE_H__
+#define OMAHA_SETUP_SETUP_GOOGLE_UPDATE_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+
+namespace omaha {
+
+struct CommandLineArgs;
+
+class SetupGoogleUpdate {
+ public:
+  SetupGoogleUpdate(bool is_machine, const CommandLineArgs* args);
+  ~SetupGoogleUpdate();
+
+  HRESULT FinishInstall();
+
+  // Uninstalls Google Update registrations created by FinishInstall().
+  void Uninstall();
+
+  // Build the command line to execute the installed core.
+  CString BuildCoreProcessCommandLine() const;
+
+ private:
+  HRESULT FinishMachineInstall();
+
+  // Installs appropriate launch mechanism(s) starts one of them if appropriate.
+  HRESULT InstallLaunchMechanisms();
+
+  // Uninstalls appropriate launch mechanism(s).
+  void UninstallLaunchMechanisms();
+
+  // Installs the scheduled task which runs the GoogleUpdate core.
+  HRESULT InstallScheduledTask();
+
+  // Installs the service and scheduled task.
+  HRESULT InstallMachineLaunchMechanisms();
+
+  // Add Google Update to the user's Run key.
+  HRESULT InstallUserLaunchMechanisms();
+
+  // Configures goopdate to run at startup.
+  //
+  // @param install: true if we should configure to run at startup, false if we
+  //   should clean up the configuration (meaning that we should not run at
+  //   startup)
+  HRESULT ConfigureUserRunAtStartup(bool install);
+
+  HRESULT InstallRegistryValues();
+
+  // Create's the ClientStateMedium key with relaxed ACLs.
+  // Only call for machine installs.
+  HRESULT CreateClientStateMedium();
+
+  // Writes the Installation ID to the registry.
+  HRESULT SetInstallationId();
+
+  // Register COM classes and interfaces.
+  HRESULT RegisterOrUnregisterCOMLocalServer(bool register);
+
+  // Installs the helper (MSI).
+  HRESULT InstallMsiHelper();
+
+  // Uninstalls the helper (MSI).
+  HRESULT UninstallMsiHelper();
+
+  HRESULT InstallOptionalComponents();
+
+  HRESULT UninstallOptionalComponents();
+
+  // Build the install file path for support files. For example,
+  CString BuildSupportFileInstallPath(const CString& filename) const;
+
+  // Deletes the Omaha registry keys except the machine id and the user id
+  // values under the main update key.
+  HRESULT DeleteRegistryKeys();
+
+  // Uninstall previous versions after an overinstall of the new version. We do
+  // the following:
+  //   * Delete all sub-directories under Google\\Update, except the running
+  //     version's directory.
+  //   * Uninstall the BHO, so IE does not load it in the future.
+  HRESULT UninstallPreviousVersions();
+
+  const bool is_machine_;
+  const CommandLineArgs* const args_;
+  CString this_version_;
+
+#ifdef _DEBUG
+  bool have_called_uninstall_previous_versions_;
+#endif
+
+  friend class SetupGoogleUpdateTest;
+  friend class AppManagerTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(SetupGoogleUpdate);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_SETUP_SETUP_GOOGLE_UPDATE_H__
+
diff --git a/setup/setup_google_update_unittest.cc b/setup/setup_google_update_unittest.cc
index 96bd277..bf58cc2 100644
--- a/setup/setup_google_update_unittest.cc
+++ b/setup/setup_google_update_unittest.cc
@@ -1,858 +1,858 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <msi.h>

-#include "base/scoped_ptr.h"

-#include "goopdate/google_update_idl.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/atlregmapex.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/setup/msi_test_utils.h"

-#include "omaha/setup/setup_google_update.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-const TCHAR kMsiInstallRegValue[] = _T("MsiStubRun");

-const TCHAR kMsiUninstallKey[] =

-    _T("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\")

-    _T("Uninstall\\{A92DAB39-4E2C-4304-9AB6-BC44E68B55E2}");

-const TCHAR kRunKey[] =

-    _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");

-

-const TCHAR* const kExpectedIid = _T("{A972BB39-CCA3-4F25-9737-3308F5FA19B5}");

-const TCHAR* const kExpectedBrand = _T("GOOG");

-const TCHAR* const kExpectedClientId = _T("some_partner");

-

-const TCHAR* const kAppId1 = _T("{B7E61EF9-AAE5-4cdf-A2D3-E4C8DF975145}");

-const TCHAR* const kAppId2 = _T("{35F1A986-417D-4039-8718-781DD418232A}");

-

-const TCHAR kRegistryHiveOverrideRootInHklm[] =

-    _T("HKLM\\Software\\Google\\Update\\UnitTest\\");

-

-// Copies the shell and DLLs that FinishInstall needs.

-// Does not replace files if they already exist.

-void CopyFilesRequiredByFinishInstall(bool is_machine, const CString& version) {

-  ASSERT_FALSE(is_machine) << _T("machine installs not currently supported");

-  const CString omaha_path = is_machine ?

-      GetGoogleUpdateMachinePath() : GetGoogleUpdateUserPath();

-  const CString expected_shell_path =

-      ConcatenatePath(omaha_path, _T("GoogleUpdate.exe"));

-  const CString version_path = ConcatenatePath(omaha_path, version);

-

-  ASSERT_SUCCEEDED(CreateDir(omaha_path, NULL));

-  ASSERT_SUCCEEDED(File::Copy(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("GoogleUpdate.exe")),

-      expected_shell_path,

-      false));

-

-  ASSERT_SUCCEEDED(CreateDir(version_path, NULL));

-

-  const TCHAR* files[] = {_T("goopdate.dll"),

-                          _T("GoopdateBho.dll"),

-                          ACTIVEX_FILENAME};

-  for (size_t i = 0; i < arraysize(files); ++i) {

-    ASSERT_SUCCEEDED(File::Copy(

-        ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                        files[i]),

-        ConcatenatePath(version_path, files[i]),

-        false));

-  }

-}

-

-// RegisterOrUnregisterCOMLocalServer() called from FinishInstall() runs in a

-// separate process. When using registry redirection in the test, the new

-// process writes to the real registry, so the unit test fails. This function

-// creates dummy entries that VerifyCOMLocalServerRegistration() verifies, and

-// is happy about.

-void SetupCOMLocalServerRegistration(bool is_machine) {

-  // Setup the following for the unit test:

-  // * LocalServer32 under CLSID_OnDemandMachineAppsClass or

-  //   CLSID_OnDemandUserAppsClass should be the current exe's module path.

-  // * InProcServer32 under CLSID of IID_IGoogleUpdate should be the path of the

-  //   current module.

-  // * ProxyStubClsid32 under IGoogleUpdate interface should be the CLSID of the

-  //   proxy, which is PROXY_CLSID_IS.

-

-  CString base_clsid_key(is_machine ? _T("HKLM") : _T("HKCU"));

-  base_clsid_key += _T("\\Software\\Classes\\CLSID\\");

-  CString ondemand_clsid_key(base_clsid_key);

-  ondemand_clsid_key += GuidToString(is_machine ?

-                                     __uuidof(OnDemandMachineAppsClass) :

-                                     __uuidof(OnDemandUserAppsClass));

-  CString local_server_key(ondemand_clsid_key + _T("\\LocalServer32"));

-  CString expected_server(app_util::GetModulePath(NULL));

-  EnclosePath(&expected_server);

-  ASSERT_FALSE(expected_server.IsEmpty());

-  ASSERT_SUCCEEDED(RegKey::SetValue(local_server_key,

-                                    NULL,

-                                    expected_server));

-

-  const GUID proxy_clsid = PROXY_CLSID_IS;

-  CString ondemand_proxy_clsid_key(base_clsid_key);

-  ondemand_proxy_clsid_key += GuidToString(proxy_clsid);

-  CString inproc_server_key(ondemand_proxy_clsid_key + _T("\\InProcServer32"));

-  expected_server = app_util::GetCurrentModulePath();

-  ASSERT_FALSE(expected_server.IsEmpty());

-  ASSERT_SUCCEEDED(RegKey::SetValue(inproc_server_key,

-                                    NULL,

-                                    expected_server));

-

-  CString igoogleupdate_interface_key(is_machine ? _T("HKLM") : _T("HKCU"));

-  igoogleupdate_interface_key += _T("\\Software\\Classes\\Interface\\");

-  igoogleupdate_interface_key += GuidToString(__uuidof(IGoogleUpdate));

-  igoogleupdate_interface_key += _T("\\ProxyStubClsid32");

-  CString proxy_interface_value(GuidToString(proxy_clsid));

-  ASSERT_FALSE(proxy_interface_value.IsEmpty());

-  ASSERT_SUCCEEDED(RegKey::SetValue(igoogleupdate_interface_key,

-                                    NULL,

-                                    proxy_interface_value));

-}

-

-void VerifyAccessRightsForTrustee(const CString& key_name,

-                                  ACCESS_MASK expected_access_rights,

-                                  CDacl* dacl,

-                                  TRUSTEE* trustee) {

-  CString fail_message;

-  fail_message.Format(_T("Key: %s; Trustee: "), key_name);

-  if (TRUSTEE_IS_NAME == trustee->TrusteeForm) {

-    fail_message.Append(trustee->ptstrName);

-  } else {

-    EXPECT_TRUE(TRUSTEE_IS_SID == trustee->TrusteeForm);

-    fail_message.Append(_T("is a SID"));

-  }

-

-  // Cast away the const so the pointer can be passed to the API. This should

-  // be safe for these purposes and because this is a unit test.

-  PACL pacl = const_cast<PACL>(dacl->GetPACL());

-  ACCESS_MASK access_rights = 0;

-  EXPECT_EQ(ERROR_SUCCESS, ::GetEffectiveRightsFromAcl(pacl,

-                                                       trustee,

-                                                       &access_rights)) <<

-      fail_message.GetString();

-  EXPECT_EQ(expected_access_rights, access_rights) << fail_message.GetString();

-}

-

-// TODO(omaha): It would be nice to test the access for a non-admin process.

-// The test requires admin privileges to run, so this would likely require

-// running a de-elevated process.

-void VerifyHklmKeyHasIntegrity(

-    const CString& key_name,

-    ACCESS_MASK expected_non_admin_interactive_access) {

-

-  // These checks take a long time, so avoid some of them in the common case.

-  if (!ShouldRunLargeTest()) {

-    return;

-  }

-

-  const ACCESS_MASK kExpectedPowerUsersAccess = vista_util::IsVistaOrLater() ?

-      0 : DELETE | READ_CONTROL | KEY_READ | KEY_WRITE;

-

-  CDacl dacl;

-  RegKey key;

-  EXPECT_SUCCEEDED(key.Open(key_name));

-  EXPECT_TRUE(::AtlGetDacl(key.Key(), SE_REGISTRY_KEY, &dacl));

-

-  CString current_user_sid_string;

-  EXPECT_SUCCEEDED(

-      user_info::GetCurrentUser(NULL, NULL, &current_user_sid_string));

-  PSID current_user_sid = NULL;

-  EXPECT_TRUE(ConvertStringSidToSid(current_user_sid_string,

-                                    &current_user_sid));

-  TRUSTEE current_user = {0};

-  current_user.TrusteeForm = TRUSTEE_IS_SID;

-  current_user.TrusteeType = TRUSTEE_IS_USER;

-  current_user.ptstrName = static_cast<LPTSTR>(current_user_sid);

-  VerifyAccessRightsForTrustee(key_name, KEY_ALL_ACCESS, &dacl, &current_user);

-  EXPECT_FALSE(::LocalFree(current_user_sid));

-

-  PSID local_system_sid = NULL;

-  EXPECT_TRUE(ConvertStringSidToSid(kLocalSystemSid, &local_system_sid));

-  TRUSTEE local_system = {0};

-  local_system.TrusteeForm = TRUSTEE_IS_SID;

-  local_system.TrusteeType = TRUSTEE_IS_USER;

-  local_system.ptstrName = static_cast<LPTSTR>(local_system_sid);

-  VerifyAccessRightsForTrustee(key_name, KEY_ALL_ACCESS, &dacl, &local_system);

-  EXPECT_FALSE(::LocalFree(local_system_sid));

-

-  TRUSTEE administrators = {0};

-  administrators.TrusteeForm = TRUSTEE_IS_NAME;

-  administrators.TrusteeType = TRUSTEE_IS_GROUP;

-  administrators.ptstrName = _T("Administrators");

-  VerifyAccessRightsForTrustee(key_name,

-                               KEY_ALL_ACCESS,

-                               &dacl,

-                               &administrators);

-

-  TRUSTEE users = {0};

-  users.TrusteeForm = TRUSTEE_IS_NAME;

-  users.TrusteeType = TRUSTEE_IS_GROUP;

-  users.ptstrName = _T("Users");

-  VerifyAccessRightsForTrustee(key_name, KEY_READ, &dacl, &users);

-

-  TRUSTEE power_users = {0};

-  power_users.TrusteeForm = TRUSTEE_IS_NAME;

-  power_users.TrusteeType = TRUSTEE_IS_GROUP;

-  power_users.ptstrName = _T("Power Users");

-  VerifyAccessRightsForTrustee(key_name,

-                               kExpectedPowerUsersAccess,

-                               &dacl,

-                               &power_users);

-

-  TRUSTEE interactive = {0};

-  interactive.TrusteeForm = TRUSTEE_IS_NAME;

-  interactive.TrusteeType = TRUSTEE_IS_GROUP;

-  interactive.ptstrName = _T("INTERACTIVE");

-  VerifyAccessRightsForTrustee(key_name,

-                               expected_non_admin_interactive_access,

-                               &dacl,

-                               &interactive);

-

-  TRUSTEE everyone = {0};

-  everyone.TrusteeForm = TRUSTEE_IS_NAME;

-  everyone.TrusteeType = TRUSTEE_IS_GROUP;

-  everyone.ptstrName = _T("Everyone");

-  VerifyAccessRightsForTrustee(key_name, 0, &dacl, &everyone);

-

-  TRUSTEE guest = {0};

-  guest.TrusteeForm = TRUSTEE_IS_NAME;

-  guest.TrusteeType = TRUSTEE_IS_USER;

-  guest.ptstrName = _T("Guest");

-  VerifyAccessRightsForTrustee(key_name, 0, &dacl, &guest);

-}

-

-}  // namespace

-

-// INTERACTIVE group inherits privileges from Users in the default case.

-void VerifyHklmKeyHasDefaultIntegrity(const CString& key_full_name) {

-  VerifyHklmKeyHasIntegrity(key_full_name, KEY_READ);

-}

-

-void VerifyHklmKeyHasMediumIntegrity(const CString& key_full_name) {

-  VerifyHklmKeyHasIntegrity(key_full_name, KEY_READ | KEY_SET_VALUE);

-}

-

-class SetupGoogleUpdateTest : public testing::Test {

- protected:

-  explicit SetupGoogleUpdateTest(bool is_machine)

-      : is_machine_(is_machine) {

-  }

-

-  void SetUp() {

-    GUID iid  = StringToGuid(kExpectedIid);

-    CommandLineAppArgs extra;

-    args_.extra.language = _T("en");

-    args_.extra.installation_id = iid;

-    args_.extra.brand_code = kExpectedBrand;

-    args_.extra.client_id = kExpectedClientId;

-    args_.extra.referral_id = _T("should not be used by setup");

-    args_.extra.apps.push_back(extra);

-    setup_google_update_.reset(new SetupGoogleUpdate(is_machine_, &args_));

-  }

-

-  HRESULT InstallRegistryValues() {

-    return setup_google_update_->InstallRegistryValues();

-  }

-

-  HRESULT InstallLaunchMechanisms() {

-    return setup_google_update_->InstallLaunchMechanisms();

-  }

-

-  void UninstallLaunchMechanisms() {

-    setup_google_update_->UninstallLaunchMechanisms();

-  }

-

-  HRESULT CreateClientStateMedium() {

-    return setup_google_update_->CreateClientStateMedium();

-  }

-

-  HRESULT InstallMsiHelper() {

-    return setup_google_update_->InstallMsiHelper();

-  }

-

-  HRESULT UninstallMsiHelper() {

-    return setup_google_update_->UninstallMsiHelper();

-  }

-

-  bool is_machine_;

-  scoped_ptr<SetupGoogleUpdate> setup_google_update_;

-  CommandLineArgs args_;

-};

-

-class SetupGoogleUpdateUserTest : public SetupGoogleUpdateTest {

- protected:

-  SetupGoogleUpdateUserTest()

-      : SetupGoogleUpdateTest(false) {

-  }

-};

-

-class SetupGoogleUpdateMachineTest : public SetupGoogleUpdateTest {

- protected:

-  SetupGoogleUpdateMachineTest()

-      : SetupGoogleUpdateTest(true) {

-  }

-};

-

-class SetupGoogleUpdateUserRegistryProtectedTest

-    : public SetupGoogleUpdateUserTest {

- protected:

-  SetupGoogleUpdateUserRegistryProtectedTest()

-      : SetupGoogleUpdateUserTest(),

-        hive_override_key_name_(kRegistryHiveOverrideRoot) {

-    const CString expected_shell_path =

-        ConcatenatePath(GetGoogleUpdateUserPath(), _T("GoogleUpdate.exe"));

-    expected_run_key_value_.Format(_T("\"%s\" /c"), expected_shell_path);

-  }

-

-  void SetUp() {

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    // Do not override HKLM because it contains the CSIDL_* definitions.

-    OverrideSpecifiedRegistryHives(hive_override_key_name_, false, true);

-

-    SetupGoogleUpdateUserTest::SetUp();

-  }

-

-  virtual void TearDown() {

-    SetupGoogleUpdateUserTest::TearDown();

-

-    RestoreRegistryHives();

-    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-  }

-

-  CString hive_override_key_name_;

-  CString expected_run_key_value_;

-};

-

-class SetupGoogleUpdateMachineRegistryProtectedTest

-    : public SetupGoogleUpdateMachineTest {

- protected:

-  SetupGoogleUpdateMachineRegistryProtectedTest()

-      : SetupGoogleUpdateMachineTest(),

-        hive_override_key_name_(kRegistryHiveOverrideRoot) {

-  }

-

-  void SetUp() {

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    OverrideRegistryHives(hive_override_key_name_);

-

-    // Add CSIDL values needed by the tests.

-    ASSERT_SUCCEEDED(RegKey::SetValue(kCsidlSystemIdsRegKey,

-                                      kCsidlProgramFilesRegValue,

-                                      _T("C:\\Program Files")));

-

-    SetupGoogleUpdateMachineTest::SetUp();

-  }

-

-  virtual void TearDown() {

-    SetupGoogleUpdateMachineTest::TearDown();

-

-    RestoreRegistryHives();

-    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-  }

-

-  CString hive_override_key_name_;

-};

-

-// There are a few tests where keys need to inherit the HKLM privileges, so put

-// the override root in HKLM. All tests using this framework must run as admin.

-class SetupGoogleUpdateMachineRegistryProtectedInHklmTest

-    : public SetupGoogleUpdateMachineRegistryProtectedTest {

- protected:

-  SetupGoogleUpdateMachineRegistryProtectedInHklmTest()

-      : SetupGoogleUpdateMachineRegistryProtectedTest() {

-    hive_override_key_name_ = kRegistryHiveOverrideRootInHklm;

-  }

-};

-

-// This test uninstalls all other versions of Omaha.

-TEST_F(SetupGoogleUpdateUserRegistryProtectedTest,

-       FinishInstall_RunKeyDoesNotExist) {

-  if (!ShouldRunLargeTest()) {

-    return;

-  }

-

-  // The version in the real registry must be set because it is used by

-  // GoogleUpdate.exe during registrations.

-  RestoreRegistryHives();

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    GetVersionString()));

-  OverrideSpecifiedRegistryHives(hive_override_key_name_, false, true);

-

-  CopyFilesRequiredByFinishInstall(is_machine_, GetVersionString());

-  SetupCOMLocalServerRegistration(is_machine_);

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(_T("HKCU\\Software\\Classes")));

-

-  ASSERT_FALSE(RegKey::HasKey(kRunKey));

-

-  EXPECT_SUCCEEDED(setup_google_update_->FinishInstall());

-

-  // Check the system state.

-

-  CPath expected_shell_path(GetGoogleUpdateUserPath());

-  expected_shell_path.Append(_T("GoogleUpdate.exe"));

-  CString shell_path;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE, _T("path"), &shell_path));

-  EXPECT_STREQ(expected_shell_path, shell_path);

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kRunKey, _T("Google Update"), &value));

-  EXPECT_STREQ(expected_run_key_value_, value);

-  EXPECT_TRUE(goopdate_utils::IsInstalledGoopdateTaskUA(false));

-  EXPECT_FALSE(goopdate_utils::IsDisabledGoopdateTaskUA(false));

-

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, kRegValueInstalledVersion, &value));

-  EXPECT_EQ(GetVersionString(), value);

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, kRegValueLastChecked));

-

-  // TODO(omaha): Check for other state.

-

-  // Clean up the launch mechanisms, at least one of which is not in the

-  // overriding registry.

-  UninstallLaunchMechanisms();

-  EXPECT_FALSE(RegKey::HasValue(kRunKey, _T("Google Update")));

-  EXPECT_FALSE(goopdate_utils::IsInstalledGoopdateTaskUA(false));

-}

-

-// TODO(omaha): Assumes GoogleUpdate.exe exists in the installed location, which

-// is not always true when run independently.

-TEST_F(SetupGoogleUpdateUserRegistryProtectedTest, InstallRegistryValues) {

-  // For this test only, we must also override HKLM in order to check that

-  // MACHINE_REG_CLIENT_STATE_MEDIUM was not created.

-  // Get the correct value of and set the CSIDL value needed by the test.

-  CString profile_path;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROFILE, &profile_path));

-  OverrideSpecifiedRegistryHives(hive_override_key_name_, true, true);

-  CString user_sid;

-  EXPECT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid));

-  const TCHAR* const kProfileListKey =

-      _T("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\")

-      _T("ProfileList\\");

-  const CString profile_path_key = kProfileListKey + user_sid;

-  EXPECT_SUCCEEDED(

-    RegKey::SetValue(profile_path_key, _T("ProfileImagePath"), profile_path));

-

-  EXPECT_SUCCEEDED(InstallRegistryValues());

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  EXPECT_TRUE(RegKey::HasKey(USER_REG_GOOGLE));

-  EXPECT_TRUE(RegKey::HasKey(USER_REG_UPDATE));

-  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS));

-  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENT_STATE));

-  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));

-  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENT_STATE_GOOPDATE));

-  EXPECT_FALSE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_MEDIUM));

-

-  // Ensure no unexpected keys were created.

-  RegKey google_key;

-  EXPECT_SUCCEEDED(google_key.Open(USER_REG_GOOGLE));

-  EXPECT_EQ(1, google_key.GetSubkeyCount());

-

-  RegKey update_key;

-  EXPECT_SUCCEEDED(update_key.Open(USER_REG_UPDATE));

-  EXPECT_EQ(2, update_key.GetSubkeyCount());

-

-  RegKey clients_key;

-  EXPECT_SUCCEEDED(clients_key.Open(USER_REG_CLIENTS));

-  EXPECT_EQ(1, clients_key.GetSubkeyCount());

-

-  RegKey client_state_key;

-  EXPECT_SUCCEEDED(client_state_key.Open(USER_REG_CLIENT_STATE));

-  EXPECT_EQ(1, client_state_key.GetSubkeyCount());

-

-  CPath expected_shell_path(GetGoogleUpdateUserPath());

-  expected_shell_path.Append(_T("GoogleUpdate.exe"));

-  CString shell_path;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE, _T("path"), &shell_path));

-  EXPECT_STREQ(expected_shell_path, shell_path);

-

-  CString iid;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE, _T("iid"), &iid));

-  EXPECT_STREQ(kExpectedIid, iid);

-

-  CString brand;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE, _T("brand"), &brand));

-  EXPECT_STREQ(kExpectedBrand, brand);

-

-  CString client_id;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("client"),

-                                    &client_id));

-  EXPECT_STREQ(kExpectedClientId, client_id);

-

-  EXPECT_FALSE(

-      RegKey::HasValue(USER_REG_CLIENT_STATE_GOOPDATE, _T("referral")));

-

-  DWORD install_time(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("InstallTime"),

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-

-  CString product_version;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("pv"),

-                                    &product_version));

-  EXPECT_STREQ(GetVersionString(), product_version);

-}

-

-// TODO(omaha): Assumes GoogleUpdate.exe exists in the installed location, which

-// is not always true when run independently.

-// TODO(omaha): Fails when run by itself on Windows Vista.

-TEST_F(SetupGoogleUpdateMachineRegistryProtectedInHklmTest,

-       InstallRegistryValues) {

-// TODO(omaha): Remove the ifdef when signing occurs after instrumentation or

-// the TODO above is addressed.

-#ifdef COVERAGE_ENABLED

-  std::wcout << _T("\tTest does not run in coverage builds.") << std::endl;

-#else

-  EXPECT_SUCCEEDED(InstallRegistryValues());

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_GOOGLE));

-  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_UPDATE));

-  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS));

-  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE));

-  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS_GOOPDATE));

-  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));

-  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_MEDIUM));

-

-  // Ensure no unexpected keys were created.

-  RegKey google_key;

-  EXPECT_SUCCEEDED(google_key.Open(MACHINE_REG_GOOGLE));

-  EXPECT_EQ(1, google_key.GetSubkeyCount());

-

-  RegKey update_key;

-  EXPECT_SUCCEEDED(update_key.Open(MACHINE_REG_UPDATE));

-  EXPECT_EQ(3, update_key.GetSubkeyCount());

-

-  RegKey clients_key;

-  EXPECT_SUCCEEDED(clients_key.Open(MACHINE_REG_CLIENTS));

-  EXPECT_EQ(1, clients_key.GetSubkeyCount());

-

-  RegKey client_state_key;

-  EXPECT_SUCCEEDED(client_state_key.Open(MACHINE_REG_CLIENT_STATE));

-  EXPECT_EQ(1, client_state_key.GetSubkeyCount());

-

-  RegKey client_state_medium_key;

-  EXPECT_SUCCEEDED(

-      client_state_medium_key.Open(MACHINE_REG_CLIENT_STATE_MEDIUM));

-  EXPECT_EQ(0, client_state_medium_key.GetSubkeyCount());

-  VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE_MEDIUM);

-

-  CString expected_shell_path;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &expected_shell_path));

-  expected_shell_path.Append(_T("\\Google\\Update\\GoogleUpdate.exe"));

-  CString shell_path;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("path"), &shell_path));

-  EXPECT_STREQ(expected_shell_path, shell_path);

-

-  CString iid;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE, _T("iid"), &iid));

-  EXPECT_STREQ(kExpectedIid, iid);

-

-  CString brand;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE, _T("brand"), &brand));

-  EXPECT_STREQ(kExpectedBrand, brand);

-

-  CString client_id;

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("client"),

-                                    &client_id));

-  EXPECT_STREQ(kExpectedClientId, client_id);

-

-  EXPECT_FALSE(

-      RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE, _T("referral")));

-

-  DWORD install_time(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("InstallTime"),

-                                    &install_time));

-  EXPECT_GE(now, install_time);

-  EXPECT_GE(static_cast<uint32>(200), now - install_time);

-

-  CString product_version;

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("pv"),

-                                    &product_version));

-  EXPECT_STREQ(GetVersionString(), product_version);

-

-  // Test permission of Update and ClientState. ClientStateMedium checked above.

-  VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_UPDATE);

-  VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE);

-

-  // Test the permission inheritance for ClientStateMedium.

-  const CString app_client_state_medium_key_name = AppendRegKeyPath(

-      MACHINE_REG_CLIENT_STATE_MEDIUM,

-      kAppId1);

-  EXPECT_SUCCEEDED(RegKey::CreateKey(app_client_state_medium_key_name));

-

-  VerifyHklmKeyHasMediumIntegrity(app_client_state_medium_key_name);

-#endif

-}

-

-TEST_F(SetupGoogleUpdateMachineRegistryProtectedInHklmTest,

-       CreateClientStateMedium_KeyAlreadyExistsWithSamePermissions) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));

-  EXPECT_SUCCEEDED(CreateClientStateMedium());

-  VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE_MEDIUM);

-

-  EXPECT_SUCCEEDED(CreateClientStateMedium());

-  VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE_MEDIUM);

-}

-

-// CreateClientStateMedium does not replace permissions on existing keys.

-TEST_F(SetupGoogleUpdateMachineRegistryProtectedInHklmTest,

-       CreateClientStateMedium_KeysAlreadyExistWithDifferentPermissions) {

-  if (!ShouldRunLargeTest()) {

-    return;

-  }

-

-  const CString app1_client_state_medium_key_name = AppendRegKeyPath(

-      MACHINE_REG_CLIENT_STATE_MEDIUM,

-      kAppId1);

-  const CString app2_client_state_medium_key_name = AppendRegKeyPath(

-      MACHINE_REG_CLIENT_STATE_MEDIUM,

-      kAppId2);

-

-  TRUSTEE users = {0};

-  users.TrusteeForm = TRUSTEE_IS_NAME;

-  users.TrusteeType = TRUSTEE_IS_GROUP;

-  users.ptstrName = _T("Users");

-

-  TRUSTEE interactive = {0};

-  interactive.TrusteeForm = TRUSTEE_IS_NAME;

-  interactive.TrusteeType = TRUSTEE_IS_GROUP;

-  interactive.ptstrName = _T("INTERACTIVE");

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));

-

-  CDacl dacl;

-  dacl.AddAllowedAce(Sids::Admins(), GENERIC_ALL);

-  // Interactive is not explicitly set.

-  dacl.AddAllowedAce(Sids::Users(), KEY_WRITE);

-

-  CSecurityDesc security_descriptor;

-  security_descriptor.SetDacl(dacl);

-  security_descriptor.MakeAbsolute();

-

-  CSecurityAttributes sa;

-  sa.Set(security_descriptor);

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENT_STATE_MEDIUM,

-                                     REG_NONE,

-                                     REG_OPTION_NON_VOLATILE,

-                                     &sa));

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(app1_client_state_medium_key_name));

-

-

-  EXPECT_SUCCEEDED(CreateClientStateMedium());

-

-  // Verify the ACLs for the existing keys were not changed.

-  // INTERACTIVE appears to inherit the privileges of Users.

-  VerifyAccessRightsForTrustee(

-      MACHINE_REG_CLIENT_STATE_MEDIUM, KEY_WRITE, &dacl, &users);

-  VerifyAccessRightsForTrustee(

-      MACHINE_REG_CLIENT_STATE_MEDIUM, KEY_WRITE, &dacl, &interactive);

-  VerifyAccessRightsForTrustee(

-      app1_client_state_medium_key_name, KEY_WRITE, &dacl, &users);

-  VerifyAccessRightsForTrustee(

-      app1_client_state_medium_key_name, KEY_WRITE, &dacl, &interactive);

-

-  // Verify the ACLs of newly created subkeys.

-  EXPECT_SUCCEEDED(RegKey::CreateKey(app2_client_state_medium_key_name));

-  VerifyAccessRightsForTrustee(

-      app2_client_state_medium_key_name, KEY_WRITE, &dacl, &users);

-  VerifyAccessRightsForTrustee(

-      app2_client_state_medium_key_name, KEY_WRITE, &dacl, &interactive);

-}

-

-TEST_F(SetupGoogleUpdateUserRegistryProtectedTest,

-       InstallLaunchMechanisms_RunKeyValueExists) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kRunKey, _T("Google Update"), _T("fo /b")));

-

-  EXPECT_SUCCEEDED(InstallLaunchMechanisms());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kRunKey, _T("Google Update"), &value));

-  EXPECT_STREQ(expected_run_key_value_, value);

-  EXPECT_TRUE(goopdate_utils::IsInstalledGoopdateTaskUA(false));

-  EXPECT_FALSE(goopdate_utils::IsDisabledGoopdateTaskUA(false));

-

-  UninstallLaunchMechanisms();

-  EXPECT_FALSE(RegKey::HasValue(kRunKey, _T("Google Update")));

-  EXPECT_FALSE(goopdate_utils::IsInstalledGoopdateTaskUA(false));

-}

-

-TEST_F(SetupGoogleUpdateUserRegistryProtectedTest,

-       InstallLaunchMechanisms_RunKeyDoesNotExist) {

-  ASSERT_FALSE(RegKey::HasKey(kRunKey));

-

-  EXPECT_SUCCEEDED(InstallLaunchMechanisms());

-

-  CString value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kRunKey, _T("Google Update"), &value));

-  EXPECT_STREQ(expected_run_key_value_, value);

-  EXPECT_TRUE(goopdate_utils::IsInstalledGoopdateTaskUA(false));

-  EXPECT_FALSE(goopdate_utils::IsDisabledGoopdateTaskUA(false));

-

-  UninstallLaunchMechanisms();

-  EXPECT_FALSE(RegKey::HasValue(kRunKey, _T("Google Update")));

-  EXPECT_FALSE(goopdate_utils::IsInstalledGoopdateTaskUA(false));

-}

-

-// The helper can be installed when the test begins.

-// It will not be installed when the test successfully completes.

-TEST_F(SetupGoogleUpdateMachineTest, InstallAndUninstallMsiHelper) {

-  if (!ShouldRunLargeTest()) {

-    return;

-  }

-  const TCHAR* MsiInstallRegValueKey =

-      ConfigManager::Instance()->machine_registry_update();

-

-  if (vista_util::IsUserAdmin()) {

-    // Prepare for the test - make sure the helper isn't installed.

-    EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());

-    EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));

-    EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey));

-

-    // Verify installation.

-    DWORD reg_value = 0xffffffff;

-    EXPECT_HRESULT_SUCCEEDED(InstallMsiHelper());

-    EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));

-    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(MsiInstallRegValueKey,

-                                              kMsiInstallRegValue,

-                                              &reg_value));

-    EXPECT_EQ(0, reg_value);

-    EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey));

-

-    // Verify over-install.

-    EXPECT_HRESULT_SUCCEEDED(InstallMsiHelper());

-    EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));

-    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(MsiInstallRegValueKey,

-                                              kMsiInstallRegValue,

-                                              &reg_value));

-    EXPECT_EQ(0, reg_value);

-    EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey));

-

-    // Verify uninstall.

-    EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());

-    EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));

-    EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey));

-

-    // Verify uninstall when not currently installed.

-    EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());

-  } else {

-    {

-      // This method expects to be called elevated and makes an assumption

-      // about a return value.

-      ExpectAsserts expect_asserts;

-      EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INSTALL_PACKAGE_REJECTED),

-                InstallMsiHelper());

-    }

-    if (IsMsiHelperInstalled()) {

-      // If the MSI is installed UninstallMsiHelper returns

-      // ERROR_INSTALL_FAILURE.

-      EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE),

-                UninstallMsiHelper());

-    } else {

-      // If the MSI is not installed UninstallMsiHelper returns S_OK.

-      EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());

-    }

-  }

-}

-

-// This test installs a different build of the helper installer then calls

-// InstallMsiHelper to install the one that has been built.

-// If run without the REINSTALL property, ERROR_PRODUCT_VERSION would occur.

-// This test verifies that such overinstalls are correctly handled and that the

-// registry value is correctly changed.

-// Note: The name of the installer cannot be different. MSI tries to find the

-// original filename in the new directory.

-// The helper can be installed when the test begins.

-// It will not be installed when the test successfully completes.

-TEST_F(SetupGoogleUpdateMachineTest,

-       InstallMsiHelper_OverinstallDifferentMsiBuild) {

-  if (!ShouldRunLargeTest()) {

-    return;

-  }

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tThis test did not run because it must be run as admin.")

-               << std::endl;

-    return;

-  }

-

-  const TCHAR kDifferentMsi[] =

-      _T("unittest_support\\GoogleUpdateHelper.msi");

-  const TCHAR* MsiInstallRegValueKey =

-      ConfigManager::Instance()->machine_registry_update();

-

-  CString different_msi_path(app_util::GetCurrentModuleDirectory());

-  ASSERT_TRUE(::PathAppend(CStrBuf(different_msi_path, MAX_PATH),

-                           kDifferentMsi));

-

-  // Prepare for the test - make sure the helper is not installed.

-  EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());

-  EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));

-  EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey));

-

-  // Install an older version of the MSI.

-  DWORD reg_value = 0xffffffff;

-  ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);

-  EXPECT_EQ(ERROR_SUCCESS, ::MsiInstallProduct(different_msi_path, _T("")));

-  EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::GetValue(MsiInstallRegValueKey, kMsiInstallRegValue, &reg_value));

-  EXPECT_EQ(9, reg_value);

-  EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey));

-

-  // Over-install.

-  EXPECT_HRESULT_SUCCEEDED(InstallMsiHelper());

-  EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::GetValue(MsiInstallRegValueKey, kMsiInstallRegValue, &reg_value));

-  EXPECT_EQ(0, reg_value);

-  EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey));

-

-  // Clean up.

-  EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());

-  EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));

-  EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey));

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <msi.h>
+#include "base/scoped_ptr.h"
+#include "goopdate/google_update_idl.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/atlregmapex.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/setup/msi_test_utils.h"
+#include "omaha/setup/setup_google_update.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+const TCHAR kMsiInstallRegValue[] = _T("MsiStubRun");
+const TCHAR kMsiUninstallKey[] =
+    _T("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\")
+    _T("Uninstall\\{A92DAB39-4E2C-4304-9AB6-BC44E68B55E2}");
+const TCHAR kRunKey[] =
+    _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");
+
+const TCHAR* const kExpectedIid = _T("{A972BB39-CCA3-4F25-9737-3308F5FA19B5}");
+const TCHAR* const kExpectedBrand = _T("GOOG");
+const TCHAR* const kExpectedClientId = _T("some_partner");
+
+const TCHAR* const kAppId1 = _T("{B7E61EF9-AAE5-4cdf-A2D3-E4C8DF975145}");
+const TCHAR* const kAppId2 = _T("{35F1A986-417D-4039-8718-781DD418232A}");
+
+const TCHAR kRegistryHiveOverrideRootInHklm[] =
+    _T("HKLM\\Software\\Google\\Update\\UnitTest\\");
+
+// Copies the shell and DLLs that FinishInstall needs.
+// Does not replace files if they already exist.
+void CopyFilesRequiredByFinishInstall(bool is_machine, const CString& version) {
+  ASSERT_FALSE(is_machine) << _T("machine installs not currently supported");
+  const CString omaha_path = is_machine ?
+      GetGoogleUpdateMachinePath() : GetGoogleUpdateUserPath();
+  const CString expected_shell_path =
+      ConcatenatePath(omaha_path, _T("GoogleUpdate.exe"));
+  const CString version_path = ConcatenatePath(omaha_path, version);
+
+  ASSERT_SUCCEEDED(CreateDir(omaha_path, NULL));
+  ASSERT_SUCCEEDED(File::Copy(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("GoogleUpdate.exe")),
+      expected_shell_path,
+      false));
+
+  ASSERT_SUCCEEDED(CreateDir(version_path, NULL));
+
+  const TCHAR* files[] = {_T("goopdate.dll"),
+                          _T("GoopdateBho.dll"),
+                          ACTIVEX_FILENAME};
+  for (size_t i = 0; i < arraysize(files); ++i) {
+    ASSERT_SUCCEEDED(File::Copy(
+        ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                        files[i]),
+        ConcatenatePath(version_path, files[i]),
+        false));
+  }
+}
+
+// RegisterOrUnregisterCOMLocalServer() called from FinishInstall() runs in a
+// separate process. When using registry redirection in the test, the new
+// process writes to the real registry, so the unit test fails. This function
+// creates dummy entries that VerifyCOMLocalServerRegistration() verifies, and
+// is happy about.
+void SetupCOMLocalServerRegistration(bool is_machine) {
+  // Setup the following for the unit test:
+  // * LocalServer32 under CLSID_OnDemandMachineAppsClass or
+  //   CLSID_OnDemandUserAppsClass should be the current exe's module path.
+  // * InProcServer32 under CLSID of IID_IGoogleUpdate should be the path of the
+  //   current module.
+  // * ProxyStubClsid32 under IGoogleUpdate interface should be the CLSID of the
+  //   proxy, which is PROXY_CLSID_IS.
+
+  CString base_clsid_key(is_machine ? _T("HKLM") : _T("HKCU"));
+  base_clsid_key += _T("\\Software\\Classes\\CLSID\\");
+  CString ondemand_clsid_key(base_clsid_key);
+  ondemand_clsid_key += GuidToString(is_machine ?
+                                     __uuidof(OnDemandMachineAppsClass) :
+                                     __uuidof(OnDemandUserAppsClass));
+  CString local_server_key(ondemand_clsid_key + _T("\\LocalServer32"));
+  CString expected_server(app_util::GetModulePath(NULL));
+  EnclosePath(&expected_server);
+  ASSERT_FALSE(expected_server.IsEmpty());
+  ASSERT_SUCCEEDED(RegKey::SetValue(local_server_key,
+                                    NULL,
+                                    expected_server));
+
+  const GUID proxy_clsid = PROXY_CLSID_IS;
+  CString ondemand_proxy_clsid_key(base_clsid_key);
+  ondemand_proxy_clsid_key += GuidToString(proxy_clsid);
+  CString inproc_server_key(ondemand_proxy_clsid_key + _T("\\InProcServer32"));
+  expected_server = app_util::GetCurrentModulePath();
+  ASSERT_FALSE(expected_server.IsEmpty());
+  ASSERT_SUCCEEDED(RegKey::SetValue(inproc_server_key,
+                                    NULL,
+                                    expected_server));
+
+  CString igoogleupdate_interface_key(is_machine ? _T("HKLM") : _T("HKCU"));
+  igoogleupdate_interface_key += _T("\\Software\\Classes\\Interface\\");
+  igoogleupdate_interface_key += GuidToString(__uuidof(IGoogleUpdate));
+  igoogleupdate_interface_key += _T("\\ProxyStubClsid32");
+  CString proxy_interface_value(GuidToString(proxy_clsid));
+  ASSERT_FALSE(proxy_interface_value.IsEmpty());
+  ASSERT_SUCCEEDED(RegKey::SetValue(igoogleupdate_interface_key,
+                                    NULL,
+                                    proxy_interface_value));
+}
+
+void VerifyAccessRightsForTrustee(const CString& key_name,
+                                  ACCESS_MASK expected_access_rights,
+                                  CDacl* dacl,
+                                  TRUSTEE* trustee) {
+  CString fail_message;
+  fail_message.Format(_T("Key: %s; Trustee: "), key_name);
+  if (TRUSTEE_IS_NAME == trustee->TrusteeForm) {
+    fail_message.Append(trustee->ptstrName);
+  } else {
+    EXPECT_TRUE(TRUSTEE_IS_SID == trustee->TrusteeForm);
+    fail_message.Append(_T("is a SID"));
+  }
+
+  // Cast away the const so the pointer can be passed to the API. This should
+  // be safe for these purposes and because this is a unit test.
+  PACL pacl = const_cast<PACL>(dacl->GetPACL());
+  ACCESS_MASK access_rights = 0;
+  EXPECT_EQ(ERROR_SUCCESS, ::GetEffectiveRightsFromAcl(pacl,
+                                                       trustee,
+                                                       &access_rights)) <<
+      fail_message.GetString();
+  EXPECT_EQ(expected_access_rights, access_rights) << fail_message.GetString();
+}
+
+// TODO(omaha): It would be nice to test the access for a non-admin process.
+// The test requires admin privileges to run, so this would likely require
+// running a de-elevated process.
+void VerifyHklmKeyHasIntegrity(
+    const CString& key_name,
+    ACCESS_MASK expected_non_admin_interactive_access) {
+
+  // These checks take a long time, so avoid some of them in the common case.
+  if (!ShouldRunLargeTest()) {
+    return;
+  }
+
+  const ACCESS_MASK kExpectedPowerUsersAccess = vista_util::IsVistaOrLater() ?
+      0 : DELETE | READ_CONTROL | KEY_READ | KEY_WRITE;
+
+  CDacl dacl;
+  RegKey key;
+  EXPECT_SUCCEEDED(key.Open(key_name));
+  EXPECT_TRUE(::AtlGetDacl(key.Key(), SE_REGISTRY_KEY, &dacl));
+
+  CString current_user_sid_string;
+  EXPECT_SUCCEEDED(
+      user_info::GetCurrentUser(NULL, NULL, &current_user_sid_string));
+  PSID current_user_sid = NULL;
+  EXPECT_TRUE(ConvertStringSidToSid(current_user_sid_string,
+                                    &current_user_sid));
+  TRUSTEE current_user = {0};
+  current_user.TrusteeForm = TRUSTEE_IS_SID;
+  current_user.TrusteeType = TRUSTEE_IS_USER;
+  current_user.ptstrName = static_cast<LPTSTR>(current_user_sid);
+  VerifyAccessRightsForTrustee(key_name, KEY_ALL_ACCESS, &dacl, &current_user);
+  EXPECT_FALSE(::LocalFree(current_user_sid));
+
+  PSID local_system_sid = NULL;
+  EXPECT_TRUE(ConvertStringSidToSid(kLocalSystemSid, &local_system_sid));
+  TRUSTEE local_system = {0};
+  local_system.TrusteeForm = TRUSTEE_IS_SID;
+  local_system.TrusteeType = TRUSTEE_IS_USER;
+  local_system.ptstrName = static_cast<LPTSTR>(local_system_sid);
+  VerifyAccessRightsForTrustee(key_name, KEY_ALL_ACCESS, &dacl, &local_system);
+  EXPECT_FALSE(::LocalFree(local_system_sid));
+
+  TRUSTEE administrators = {0};
+  administrators.TrusteeForm = TRUSTEE_IS_NAME;
+  administrators.TrusteeType = TRUSTEE_IS_GROUP;
+  administrators.ptstrName = _T("Administrators");
+  VerifyAccessRightsForTrustee(key_name,
+                               KEY_ALL_ACCESS,
+                               &dacl,
+                               &administrators);
+
+  TRUSTEE users = {0};
+  users.TrusteeForm = TRUSTEE_IS_NAME;
+  users.TrusteeType = TRUSTEE_IS_GROUP;
+  users.ptstrName = _T("Users");
+  VerifyAccessRightsForTrustee(key_name, KEY_READ, &dacl, &users);
+
+  TRUSTEE power_users = {0};
+  power_users.TrusteeForm = TRUSTEE_IS_NAME;
+  power_users.TrusteeType = TRUSTEE_IS_GROUP;
+  power_users.ptstrName = _T("Power Users");
+  VerifyAccessRightsForTrustee(key_name,
+                               kExpectedPowerUsersAccess,
+                               &dacl,
+                               &power_users);
+
+  TRUSTEE interactive = {0};
+  interactive.TrusteeForm = TRUSTEE_IS_NAME;
+  interactive.TrusteeType = TRUSTEE_IS_GROUP;
+  interactive.ptstrName = _T("INTERACTIVE");
+  VerifyAccessRightsForTrustee(key_name,
+                               expected_non_admin_interactive_access,
+                               &dacl,
+                               &interactive);
+
+  TRUSTEE everyone = {0};
+  everyone.TrusteeForm = TRUSTEE_IS_NAME;
+  everyone.TrusteeType = TRUSTEE_IS_GROUP;
+  everyone.ptstrName = _T("Everyone");
+  VerifyAccessRightsForTrustee(key_name, 0, &dacl, &everyone);
+
+  TRUSTEE guest = {0};
+  guest.TrusteeForm = TRUSTEE_IS_NAME;
+  guest.TrusteeType = TRUSTEE_IS_USER;
+  guest.ptstrName = _T("Guest");
+  VerifyAccessRightsForTrustee(key_name, 0, &dacl, &guest);
+}
+
+}  // namespace
+
+// INTERACTIVE group inherits privileges from Users in the default case.
+void VerifyHklmKeyHasDefaultIntegrity(const CString& key_full_name) {
+  VerifyHklmKeyHasIntegrity(key_full_name, KEY_READ);
+}
+
+void VerifyHklmKeyHasMediumIntegrity(const CString& key_full_name) {
+  VerifyHklmKeyHasIntegrity(key_full_name, KEY_READ | KEY_SET_VALUE);
+}
+
+class SetupGoogleUpdateTest : public testing::Test {
+ protected:
+  explicit SetupGoogleUpdateTest(bool is_machine)
+      : is_machine_(is_machine) {
+  }
+
+  void SetUp() {
+    GUID iid  = StringToGuid(kExpectedIid);
+    CommandLineAppArgs extra;
+    args_.extra.language = _T("en");
+    args_.extra.installation_id = iid;
+    args_.extra.brand_code = kExpectedBrand;
+    args_.extra.client_id = kExpectedClientId;
+    args_.extra.referral_id = _T("should not be used by setup");
+    args_.extra.apps.push_back(extra);
+    setup_google_update_.reset(new SetupGoogleUpdate(is_machine_, &args_));
+  }
+
+  HRESULT InstallRegistryValues() {
+    return setup_google_update_->InstallRegistryValues();
+  }
+
+  HRESULT InstallLaunchMechanisms() {
+    return setup_google_update_->InstallLaunchMechanisms();
+  }
+
+  void UninstallLaunchMechanisms() {
+    setup_google_update_->UninstallLaunchMechanisms();
+  }
+
+  HRESULT CreateClientStateMedium() {
+    return setup_google_update_->CreateClientStateMedium();
+  }
+
+  HRESULT InstallMsiHelper() {
+    return setup_google_update_->InstallMsiHelper();
+  }
+
+  HRESULT UninstallMsiHelper() {
+    return setup_google_update_->UninstallMsiHelper();
+  }
+
+  bool is_machine_;
+  scoped_ptr<SetupGoogleUpdate> setup_google_update_;
+  CommandLineArgs args_;
+};
+
+class SetupGoogleUpdateUserTest : public SetupGoogleUpdateTest {
+ protected:
+  SetupGoogleUpdateUserTest()
+      : SetupGoogleUpdateTest(false) {
+  }
+};
+
+class SetupGoogleUpdateMachineTest : public SetupGoogleUpdateTest {
+ protected:
+  SetupGoogleUpdateMachineTest()
+      : SetupGoogleUpdateTest(true) {
+  }
+};
+
+class SetupGoogleUpdateUserRegistryProtectedTest
+    : public SetupGoogleUpdateUserTest {
+ protected:
+  SetupGoogleUpdateUserRegistryProtectedTest()
+      : SetupGoogleUpdateUserTest(),
+        hive_override_key_name_(kRegistryHiveOverrideRoot) {
+    const CString expected_shell_path =
+        ConcatenatePath(GetGoogleUpdateUserPath(), _T("GoogleUpdate.exe"));
+    expected_run_key_value_.Format(_T("\"%s\" /c"), expected_shell_path);
+  }
+
+  void SetUp() {
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    // Do not override HKLM because it contains the CSIDL_* definitions.
+    OverrideSpecifiedRegistryHives(hive_override_key_name_, false, true);
+
+    SetupGoogleUpdateUserTest::SetUp();
+  }
+
+  virtual void TearDown() {
+    SetupGoogleUpdateUserTest::TearDown();
+
+    RestoreRegistryHives();
+    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+  }
+
+  CString hive_override_key_name_;
+  CString expected_run_key_value_;
+};
+
+class SetupGoogleUpdateMachineRegistryProtectedTest
+    : public SetupGoogleUpdateMachineTest {
+ protected:
+  SetupGoogleUpdateMachineRegistryProtectedTest()
+      : SetupGoogleUpdateMachineTest(),
+        hive_override_key_name_(kRegistryHiveOverrideRoot) {
+  }
+
+  void SetUp() {
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    OverrideRegistryHives(hive_override_key_name_);
+
+    // Add CSIDL values needed by the tests.
+    ASSERT_SUCCEEDED(RegKey::SetValue(kCsidlSystemIdsRegKey,
+                                      kCsidlProgramFilesRegValue,
+                                      _T("C:\\Program Files")));
+
+    SetupGoogleUpdateMachineTest::SetUp();
+  }
+
+  virtual void TearDown() {
+    SetupGoogleUpdateMachineTest::TearDown();
+
+    RestoreRegistryHives();
+    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+  }
+
+  CString hive_override_key_name_;
+};
+
+// There are a few tests where keys need to inherit the HKLM privileges, so put
+// the override root in HKLM. All tests using this framework must run as admin.
+class SetupGoogleUpdateMachineRegistryProtectedInHklmTest
+    : public SetupGoogleUpdateMachineRegistryProtectedTest {
+ protected:
+  SetupGoogleUpdateMachineRegistryProtectedInHklmTest()
+      : SetupGoogleUpdateMachineRegistryProtectedTest() {
+    hive_override_key_name_ = kRegistryHiveOverrideRootInHklm;
+  }
+};
+
+// This test uninstalls all other versions of Omaha.
+TEST_F(SetupGoogleUpdateUserRegistryProtectedTest,
+       FinishInstall_RunKeyDoesNotExist) {
+  if (!ShouldRunLargeTest()) {
+    return;
+  }
+
+  // The version in the real registry must be set because it is used by
+  // GoogleUpdate.exe during registrations.
+  RestoreRegistryHives();
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    GetVersionString()));
+  OverrideSpecifiedRegistryHives(hive_override_key_name_, false, true);
+
+  CopyFilesRequiredByFinishInstall(is_machine_, GetVersionString());
+  SetupCOMLocalServerRegistration(is_machine_);
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(_T("HKCU\\Software\\Classes")));
+
+  ASSERT_FALSE(RegKey::HasKey(kRunKey));
+
+  EXPECT_SUCCEEDED(setup_google_update_->FinishInstall());
+
+  // Check the system state.
+
+  CPath expected_shell_path(GetGoogleUpdateUserPath());
+  expected_shell_path.Append(_T("GoogleUpdate.exe"));
+  CString shell_path;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE, _T("path"), &shell_path));
+  EXPECT_STREQ(expected_shell_path, shell_path);
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kRunKey, _T("Google Update"), &value));
+  EXPECT_STREQ(expected_run_key_value_, value);
+  EXPECT_TRUE(goopdate_utils::IsInstalledGoopdateTaskUA(false));
+  EXPECT_FALSE(goopdate_utils::IsDisabledGoopdateTaskUA(false));
+
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, kRegValueInstalledVersion, &value));
+  EXPECT_EQ(GetVersionString(), value);
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, kRegValueLastChecked));
+
+  // TODO(omaha): Check for other state.
+
+  // Clean up the launch mechanisms, at least one of which is not in the
+  // overriding registry.
+  UninstallLaunchMechanisms();
+  EXPECT_FALSE(RegKey::HasValue(kRunKey, _T("Google Update")));
+  EXPECT_FALSE(goopdate_utils::IsInstalledGoopdateTaskUA(false));
+}
+
+// TODO(omaha): Assumes GoogleUpdate.exe exists in the installed location, which
+// is not always true when run independently.
+TEST_F(SetupGoogleUpdateUserRegistryProtectedTest, InstallRegistryValues) {
+  // For this test only, we must also override HKLM in order to check that
+  // MACHINE_REG_CLIENT_STATE_MEDIUM was not created.
+  // Get the correct value of and set the CSIDL value needed by the test.
+  CString profile_path;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROFILE, &profile_path));
+  OverrideSpecifiedRegistryHives(hive_override_key_name_, true, true);
+  CString user_sid;
+  EXPECT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid));
+  const TCHAR* const kProfileListKey =
+      _T("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\")
+      _T("ProfileList\\");
+  const CString profile_path_key = kProfileListKey + user_sid;
+  EXPECT_SUCCEEDED(
+    RegKey::SetValue(profile_path_key, _T("ProfileImagePath"), profile_path));
+
+  EXPECT_SUCCEEDED(InstallRegistryValues());
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  EXPECT_TRUE(RegKey::HasKey(USER_REG_GOOGLE));
+  EXPECT_TRUE(RegKey::HasKey(USER_REG_UPDATE));
+  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS));
+  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENT_STATE));
+  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));
+  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENT_STATE_GOOPDATE));
+  EXPECT_FALSE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_MEDIUM));
+
+  // Ensure no unexpected keys were created.
+  RegKey google_key;
+  EXPECT_SUCCEEDED(google_key.Open(USER_REG_GOOGLE));
+  EXPECT_EQ(1, google_key.GetSubkeyCount());
+
+  RegKey update_key;
+  EXPECT_SUCCEEDED(update_key.Open(USER_REG_UPDATE));
+  EXPECT_EQ(2, update_key.GetSubkeyCount());
+
+  RegKey clients_key;
+  EXPECT_SUCCEEDED(clients_key.Open(USER_REG_CLIENTS));
+  EXPECT_EQ(1, clients_key.GetSubkeyCount());
+
+  RegKey client_state_key;
+  EXPECT_SUCCEEDED(client_state_key.Open(USER_REG_CLIENT_STATE));
+  EXPECT_EQ(1, client_state_key.GetSubkeyCount());
+
+  CPath expected_shell_path(GetGoogleUpdateUserPath());
+  expected_shell_path.Append(_T("GoogleUpdate.exe"));
+  CString shell_path;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE, _T("path"), &shell_path));
+  EXPECT_STREQ(expected_shell_path, shell_path);
+
+  CString iid;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE, _T("iid"), &iid));
+  EXPECT_STREQ(kExpectedIid, iid);
+
+  CString brand;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE, _T("brand"), &brand));
+  EXPECT_STREQ(kExpectedBrand, brand);
+
+  CString client_id;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("client"),
+                                    &client_id));
+  EXPECT_STREQ(kExpectedClientId, client_id);
+
+  EXPECT_FALSE(
+      RegKey::HasValue(USER_REG_CLIENT_STATE_GOOPDATE, _T("referral")));
+
+  DWORD install_time(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("InstallTime"),
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+
+  CString product_version;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("pv"),
+                                    &product_version));
+  EXPECT_STREQ(GetVersionString(), product_version);
+}
+
+// TODO(omaha): Assumes GoogleUpdate.exe exists in the installed location, which
+// is not always true when run independently.
+// TODO(omaha): Fails when run by itself on Windows Vista.
+TEST_F(SetupGoogleUpdateMachineRegistryProtectedInHklmTest,
+       InstallRegistryValues) {
+// TODO(omaha): Remove the ifdef when signing occurs after instrumentation or
+// the TODO above is addressed.
+#ifdef COVERAGE_ENABLED
+  std::wcout << _T("\tTest does not run in coverage builds.") << std::endl;
+#else
+  EXPECT_SUCCEEDED(InstallRegistryValues());
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_GOOGLE));
+  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_UPDATE));
+  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS));
+  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE));
+  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS_GOOPDATE));
+  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));
+  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_MEDIUM));
+
+  // Ensure no unexpected keys were created.
+  RegKey google_key;
+  EXPECT_SUCCEEDED(google_key.Open(MACHINE_REG_GOOGLE));
+  EXPECT_EQ(1, google_key.GetSubkeyCount());
+
+  RegKey update_key;
+  EXPECT_SUCCEEDED(update_key.Open(MACHINE_REG_UPDATE));
+  EXPECT_EQ(3, update_key.GetSubkeyCount());
+
+  RegKey clients_key;
+  EXPECT_SUCCEEDED(clients_key.Open(MACHINE_REG_CLIENTS));
+  EXPECT_EQ(1, clients_key.GetSubkeyCount());
+
+  RegKey client_state_key;
+  EXPECT_SUCCEEDED(client_state_key.Open(MACHINE_REG_CLIENT_STATE));
+  EXPECT_EQ(1, client_state_key.GetSubkeyCount());
+
+  RegKey client_state_medium_key;
+  EXPECT_SUCCEEDED(
+      client_state_medium_key.Open(MACHINE_REG_CLIENT_STATE_MEDIUM));
+  EXPECT_EQ(0, client_state_medium_key.GetSubkeyCount());
+  VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE_MEDIUM);
+
+  CString expected_shell_path;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &expected_shell_path));
+  expected_shell_path.Append(_T("\\Google\\Update\\GoogleUpdate.exe"));
+  CString shell_path;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("path"), &shell_path));
+  EXPECT_STREQ(expected_shell_path, shell_path);
+
+  CString iid;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE, _T("iid"), &iid));
+  EXPECT_STREQ(kExpectedIid, iid);
+
+  CString brand;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE, _T("brand"), &brand));
+  EXPECT_STREQ(kExpectedBrand, brand);
+
+  CString client_id;
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("client"),
+                                    &client_id));
+  EXPECT_STREQ(kExpectedClientId, client_id);
+
+  EXPECT_FALSE(
+      RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE, _T("referral")));
+
+  DWORD install_time(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("InstallTime"),
+                                    &install_time));
+  EXPECT_GE(now, install_time);
+  EXPECT_GE(static_cast<uint32>(200), now - install_time);
+
+  CString product_version;
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("pv"),
+                                    &product_version));
+  EXPECT_STREQ(GetVersionString(), product_version);
+
+  // Test permission of Update and ClientState. ClientStateMedium checked above.
+  VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_UPDATE);
+  VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE);
+
+  // Test the permission inheritance for ClientStateMedium.
+  const CString app_client_state_medium_key_name = AppendRegKeyPath(
+      MACHINE_REG_CLIENT_STATE_MEDIUM,
+      kAppId1);
+  EXPECT_SUCCEEDED(RegKey::CreateKey(app_client_state_medium_key_name));
+
+  VerifyHklmKeyHasMediumIntegrity(app_client_state_medium_key_name);
+#endif
+}
+
+TEST_F(SetupGoogleUpdateMachineRegistryProtectedInHklmTest,
+       CreateClientStateMedium_KeyAlreadyExistsWithSamePermissions) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));
+  EXPECT_SUCCEEDED(CreateClientStateMedium());
+  VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE_MEDIUM);
+
+  EXPECT_SUCCEEDED(CreateClientStateMedium());
+  VerifyHklmKeyHasDefaultIntegrity(MACHINE_REG_CLIENT_STATE_MEDIUM);
+}
+
+// CreateClientStateMedium does not replace permissions on existing keys.
+TEST_F(SetupGoogleUpdateMachineRegistryProtectedInHklmTest,
+       CreateClientStateMedium_KeysAlreadyExistWithDifferentPermissions) {
+  if (!ShouldRunLargeTest()) {
+    return;
+  }
+
+  const CString app1_client_state_medium_key_name = AppendRegKeyPath(
+      MACHINE_REG_CLIENT_STATE_MEDIUM,
+      kAppId1);
+  const CString app2_client_state_medium_key_name = AppendRegKeyPath(
+      MACHINE_REG_CLIENT_STATE_MEDIUM,
+      kAppId2);
+
+  TRUSTEE users = {0};
+  users.TrusteeForm = TRUSTEE_IS_NAME;
+  users.TrusteeType = TRUSTEE_IS_GROUP;
+  users.ptstrName = _T("Users");
+
+  TRUSTEE interactive = {0};
+  interactive.TrusteeForm = TRUSTEE_IS_NAME;
+  interactive.TrusteeType = TRUSTEE_IS_GROUP;
+  interactive.ptstrName = _T("INTERACTIVE");
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));
+
+  CDacl dacl;
+  dacl.AddAllowedAce(Sids::Admins(), GENERIC_ALL);
+  // Interactive is not explicitly set.
+  dacl.AddAllowedAce(Sids::Users(), KEY_WRITE);
+
+  CSecurityDesc security_descriptor;
+  security_descriptor.SetDacl(dacl);
+  security_descriptor.MakeAbsolute();
+
+  CSecurityAttributes sa;
+  sa.Set(security_descriptor);
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENT_STATE_MEDIUM,
+                                     REG_NONE,
+                                     REG_OPTION_NON_VOLATILE,
+                                     &sa));
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(app1_client_state_medium_key_name));
+
+
+  EXPECT_SUCCEEDED(CreateClientStateMedium());
+
+  // Verify the ACLs for the existing keys were not changed.
+  // INTERACTIVE appears to inherit the privileges of Users.
+  VerifyAccessRightsForTrustee(
+      MACHINE_REG_CLIENT_STATE_MEDIUM, KEY_WRITE, &dacl, &users);
+  VerifyAccessRightsForTrustee(
+      MACHINE_REG_CLIENT_STATE_MEDIUM, KEY_WRITE, &dacl, &interactive);
+  VerifyAccessRightsForTrustee(
+      app1_client_state_medium_key_name, KEY_WRITE, &dacl, &users);
+  VerifyAccessRightsForTrustee(
+      app1_client_state_medium_key_name, KEY_WRITE, &dacl, &interactive);
+
+  // Verify the ACLs of newly created subkeys.
+  EXPECT_SUCCEEDED(RegKey::CreateKey(app2_client_state_medium_key_name));
+  VerifyAccessRightsForTrustee(
+      app2_client_state_medium_key_name, KEY_WRITE, &dacl, &users);
+  VerifyAccessRightsForTrustee(
+      app2_client_state_medium_key_name, KEY_WRITE, &dacl, &interactive);
+}
+
+TEST_F(SetupGoogleUpdateUserRegistryProtectedTest,
+       InstallLaunchMechanisms_RunKeyValueExists) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kRunKey, _T("Google Update"), _T("fo /b")));
+
+  EXPECT_SUCCEEDED(InstallLaunchMechanisms());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kRunKey, _T("Google Update"), &value));
+  EXPECT_STREQ(expected_run_key_value_, value);
+  EXPECT_TRUE(goopdate_utils::IsInstalledGoopdateTaskUA(false));
+  EXPECT_FALSE(goopdate_utils::IsDisabledGoopdateTaskUA(false));
+
+  UninstallLaunchMechanisms();
+  EXPECT_FALSE(RegKey::HasValue(kRunKey, _T("Google Update")));
+  EXPECT_FALSE(goopdate_utils::IsInstalledGoopdateTaskUA(false));
+}
+
+TEST_F(SetupGoogleUpdateUserRegistryProtectedTest,
+       InstallLaunchMechanisms_RunKeyDoesNotExist) {
+  ASSERT_FALSE(RegKey::HasKey(kRunKey));
+
+  EXPECT_SUCCEEDED(InstallLaunchMechanisms());
+
+  CString value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kRunKey, _T("Google Update"), &value));
+  EXPECT_STREQ(expected_run_key_value_, value);
+  EXPECT_TRUE(goopdate_utils::IsInstalledGoopdateTaskUA(false));
+  EXPECT_FALSE(goopdate_utils::IsDisabledGoopdateTaskUA(false));
+
+  UninstallLaunchMechanisms();
+  EXPECT_FALSE(RegKey::HasValue(kRunKey, _T("Google Update")));
+  EXPECT_FALSE(goopdate_utils::IsInstalledGoopdateTaskUA(false));
+}
+
+// The helper can be installed when the test begins.
+// It will not be installed when the test successfully completes.
+TEST_F(SetupGoogleUpdateMachineTest, InstallAndUninstallMsiHelper) {
+  if (!ShouldRunLargeTest()) {
+    return;
+  }
+  const TCHAR* MsiInstallRegValueKey =
+      ConfigManager::Instance()->machine_registry_update();
+
+  if (vista_util::IsUserAdmin()) {
+    // Prepare for the test - make sure the helper isn't installed.
+    EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());
+    EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));
+    EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey));
+
+    // Verify installation.
+    DWORD reg_value = 0xffffffff;
+    EXPECT_HRESULT_SUCCEEDED(InstallMsiHelper());
+    EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));
+    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(MsiInstallRegValueKey,
+                                              kMsiInstallRegValue,
+                                              &reg_value));
+    EXPECT_EQ(0, reg_value);
+    EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey));
+
+    // Verify over-install.
+    EXPECT_HRESULT_SUCCEEDED(InstallMsiHelper());
+    EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));
+    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(MsiInstallRegValueKey,
+                                              kMsiInstallRegValue,
+                                              &reg_value));
+    EXPECT_EQ(0, reg_value);
+    EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey));
+
+    // Verify uninstall.
+    EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());
+    EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));
+    EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey));
+
+    // Verify uninstall when not currently installed.
+    EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());
+  } else {
+    {
+      // This method expects to be called elevated and makes an assumption
+      // about a return value.
+      ExpectAsserts expect_asserts;
+      EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INSTALL_PACKAGE_REJECTED),
+                InstallMsiHelper());
+    }
+    if (IsMsiHelperInstalled()) {
+      // If the MSI is installed UninstallMsiHelper returns
+      // ERROR_INSTALL_FAILURE.
+      EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_INSTALL_FAILURE),
+                UninstallMsiHelper());
+    } else {
+      // If the MSI is not installed UninstallMsiHelper returns S_OK.
+      EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());
+    }
+  }
+}
+
+// This test installs a different build of the helper installer then calls
+// InstallMsiHelper to install the one that has been built.
+// If run without the REINSTALL property, ERROR_PRODUCT_VERSION would occur.
+// This test verifies that such overinstalls are correctly handled and that the
+// registry value is correctly changed.
+// Note: The name of the installer cannot be different. MSI tries to find the
+// original filename in the new directory.
+// The helper can be installed when the test begins.
+// It will not be installed when the test successfully completes.
+TEST_F(SetupGoogleUpdateMachineTest,
+       InstallMsiHelper_OverinstallDifferentMsiBuild) {
+  if (!ShouldRunLargeTest()) {
+    return;
+  }
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tThis test did not run because it must be run as admin.")
+               << std::endl;
+    return;
+  }
+
+  const TCHAR kDifferentMsi[] =
+      _T("unittest_support\\GoogleUpdateHelper.msi");
+  const TCHAR* MsiInstallRegValueKey =
+      ConfigManager::Instance()->machine_registry_update();
+
+  CString different_msi_path(app_util::GetCurrentModuleDirectory());
+  ASSERT_TRUE(::PathAppend(CStrBuf(different_msi_path, MAX_PATH),
+                           kDifferentMsi));
+
+  // Prepare for the test - make sure the helper is not installed.
+  EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());
+  EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));
+  EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey));
+
+  // Install an older version of the MSI.
+  DWORD reg_value = 0xffffffff;
+  ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
+  EXPECT_EQ(ERROR_SUCCESS, ::MsiInstallProduct(different_msi_path, _T("")));
+  EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::GetValue(MsiInstallRegValueKey, kMsiInstallRegValue, &reg_value));
+  EXPECT_EQ(9, reg_value);
+  EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey));
+
+  // Over-install.
+  EXPECT_HRESULT_SUCCEEDED(InstallMsiHelper());
+  EXPECT_TRUE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::GetValue(MsiInstallRegValueKey, kMsiInstallRegValue, &reg_value));
+  EXPECT_EQ(0, reg_value);
+  EXPECT_TRUE(RegKey::HasKey(kMsiUninstallKey));
+
+  // Clean up.
+  EXPECT_HRESULT_SUCCEEDED(UninstallMsiHelper());
+  EXPECT_FALSE(RegKey::HasValue(MsiInstallRegValueKey, kMsiInstallRegValue));
+  EXPECT_FALSE(RegKey::HasKey(kMsiUninstallKey));
+}
+
+}  // namespace omaha
diff --git a/setup/setup_metrics.cc b/setup/setup_metrics.cc
index 8685b77..253f377 100644
--- a/setup/setup_metrics.cc
+++ b/setup/setup_metrics.cc
@@ -1,123 +1,123 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/setup/setup_metrics.h"

-

-namespace omaha {

-

-DEFINE_METRIC_count(setup_install_total);

-DEFINE_METRIC_count(setup_install_succeeded);

-

-DEFINE_METRIC_count(setup_update_self_total);

-DEFINE_METRIC_count(setup_update_self_succeeded);

-

-DEFINE_METRIC_count(setup_do_self_install_total);

-DEFINE_METRIC_count(setup_do_self_install_succeeded);

-

-DEFINE_METRIC_count(setup_handoff_only_total);

-DEFINE_METRIC_count(setup_handoff_only_succeeded);

-

-DEFINE_METRIC_timing(setup_install_google_update_total_ms);

-

-DEFINE_METRIC_timing(setup_handoff_ms);

-DEFINE_METRIC_timing(setup_handoff_ui_ms);

-

-DEFINE_METRIC_count(setup_installed_core_not_running);

-

-DEFINE_METRIC_count(setup_should_install_total);

-DEFINE_METRIC_count(setup_should_install_false_oc);

-DEFINE_METRIC_count(setup_should_install_true_fresh_install);

-DEFINE_METRIC_count(setup_should_install_false_older);

-DEFINE_METRIC_count(setup_should_install_true_newer);

-DEFINE_METRIC_count(setup_should_install_false_same);

-DEFINE_METRIC_count(setup_should_install_true_same);

-DEFINE_METRIC_count(setup_should_install_true_same_completion_missing);

-DEFINE_METRIC_count(setup_subsequent_install_total);

-DEFINE_METRIC_count(setup_subsequent_install_should_install_true);

-

-DEFINE_METRIC_count(setup_files_total);

-DEFINE_METRIC_count(setup_files_verification_succeeded);

-DEFINE_METRIC_count(setup_files_verification_failed_pre);

-DEFINE_METRIC_count(setup_files_verification_failed_post);

-

-DEFINE_METRIC_timing(setup_files_ms);

-

-DEFINE_METRIC_count(setup_files_replace_shell);

-

-DEFINE_METRIC_timing(setup_phase2_ms);

-

-DEFINE_METRIC_count(setup_install_service_task_total);

-DEFINE_METRIC_count(setup_install_service_succeeded);

-DEFINE_METRIC_count(setup_install_task_succeeded);

-DEFINE_METRIC_count(setup_install_service_and_task_succeeded);

-DEFINE_METRIC_count(setup_install_service_and_task_failed);

-DEFINE_METRIC_integer(setup_install_service_error);

-DEFINE_METRIC_integer(setup_install_task_error);

-

-DEFINE_METRIC_timing(setup_install_service_ms);

-DEFINE_METRIC_timing(setup_install_service_failed_ms);

-DEFINE_METRIC_timing(setup_install_task_ms);

-

-DEFINE_METRIC_count(setup_start_service_total);

-DEFINE_METRIC_count(setup_start_service_succeeded);

-DEFINE_METRIC_integer(setup_start_service_error);

-

-DEFINE_METRIC_timing(setup_start_service_ms);

-DEFINE_METRIC_timing(setup_start_service_failed_ms);

-

-DEFINE_METRIC_count(setup_start_task_total);

-DEFINE_METRIC_count(setup_start_task_succeeded);

-DEFINE_METRIC_integer(setup_start_task_error);

-

-DEFINE_METRIC_timing(setup_start_task_ms);

-

-DEFINE_METRIC_count(setup_helper_msi_install_total);

-DEFINE_METRIC_count(setup_helper_msi_install_succeeded);

-

-DEFINE_METRIC_timing(setup_helper_msi_install_ms);

-

-DEFINE_METRIC_count(setup_locks_failed);

-DEFINE_METRIC_count(setup_lock11_failed);

-DEFINE_METRIC_count(setup_lock12_failed);

-

-DEFINE_METRIC_timing(setup_lock_acquire_ms);

-

-DEFINE_METRIC_count(setup_process_wait_failed);

-DEFINE_METRIC_count(setup_process_wait_failed_unknown);

-DEFINE_METRIC_count(setup_process_wait_failed_core);

-DEFINE_METRIC_count(setup_process_wait_failed_report);

-DEFINE_METRIC_count(setup_process_wait_failed_update);

-DEFINE_METRIC_count(setup_process_wait_failed_ig);

-DEFINE_METRIC_count(setup_process_wait_failed_handoff);

-DEFINE_METRIC_count(setup_process_wait_failed_ug);

-DEFINE_METRIC_count(setup_process_wait_failed_ua);

-DEFINE_METRIC_count(setup_process_wait_failed_cr);

-DEFINE_METRIC_count(setup_process_wait_failed_legacy);

-DEFINE_METRIC_count(setup_process_wait_failed_other);

-

-DEFINE_METRIC_timing(setup_process_wait_ms);

-

-DEFINE_METRIC_count(setup_rollback_version);

-DEFINE_METRIC_count(setup_rollback_files);

-DEFINE_METRIC_count(setup_files_rollback_shell);

-

-DEFINE_METRIC_count(setup_uac_succeeded);

-

-DEFINE_METRIC_count(setup_user_app_admin);

-DEFINE_METRIC_count(setup_machine_app_non_admin);

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/setup/setup_metrics.h"
+
+namespace omaha {
+
+DEFINE_METRIC_count(setup_install_total);
+DEFINE_METRIC_count(setup_install_succeeded);
+
+DEFINE_METRIC_count(setup_update_self_total);
+DEFINE_METRIC_count(setup_update_self_succeeded);
+
+DEFINE_METRIC_count(setup_do_self_install_total);
+DEFINE_METRIC_count(setup_do_self_install_succeeded);
+
+DEFINE_METRIC_count(setup_handoff_only_total);
+DEFINE_METRIC_count(setup_handoff_only_succeeded);
+
+DEFINE_METRIC_timing(setup_install_google_update_total_ms);
+
+DEFINE_METRIC_timing(setup_handoff_ms);
+DEFINE_METRIC_timing(setup_handoff_ui_ms);
+
+DEFINE_METRIC_count(setup_installed_core_not_running);
+
+DEFINE_METRIC_count(setup_should_install_total);
+DEFINE_METRIC_count(setup_should_install_false_oc);
+DEFINE_METRIC_count(setup_should_install_true_fresh_install);
+DEFINE_METRIC_count(setup_should_install_false_older);
+DEFINE_METRIC_count(setup_should_install_true_newer);
+DEFINE_METRIC_count(setup_should_install_false_same);
+DEFINE_METRIC_count(setup_should_install_true_same);
+DEFINE_METRIC_count(setup_should_install_true_same_completion_missing);
+DEFINE_METRIC_count(setup_subsequent_install_total);
+DEFINE_METRIC_count(setup_subsequent_install_should_install_true);
+
+DEFINE_METRIC_count(setup_files_total);
+DEFINE_METRIC_count(setup_files_verification_succeeded);
+DEFINE_METRIC_count(setup_files_verification_failed_pre);
+DEFINE_METRIC_count(setup_files_verification_failed_post);
+
+DEFINE_METRIC_timing(setup_files_ms);
+
+DEFINE_METRIC_count(setup_files_replace_shell);
+
+DEFINE_METRIC_timing(setup_phase2_ms);
+
+DEFINE_METRIC_count(setup_install_service_task_total);
+DEFINE_METRIC_count(setup_install_service_succeeded);
+DEFINE_METRIC_count(setup_install_task_succeeded);
+DEFINE_METRIC_count(setup_install_service_and_task_succeeded);
+DEFINE_METRIC_count(setup_install_service_and_task_failed);
+DEFINE_METRIC_integer(setup_install_service_error);
+DEFINE_METRIC_integer(setup_install_task_error);
+
+DEFINE_METRIC_timing(setup_install_service_ms);
+DEFINE_METRIC_timing(setup_install_service_failed_ms);
+DEFINE_METRIC_timing(setup_install_task_ms);
+
+DEFINE_METRIC_count(setup_start_service_total);
+DEFINE_METRIC_count(setup_start_service_succeeded);
+DEFINE_METRIC_integer(setup_start_service_error);
+
+DEFINE_METRIC_timing(setup_start_service_ms);
+DEFINE_METRIC_timing(setup_start_service_failed_ms);
+
+DEFINE_METRIC_count(setup_start_task_total);
+DEFINE_METRIC_count(setup_start_task_succeeded);
+DEFINE_METRIC_integer(setup_start_task_error);
+
+DEFINE_METRIC_timing(setup_start_task_ms);
+
+DEFINE_METRIC_count(setup_helper_msi_install_total);
+DEFINE_METRIC_count(setup_helper_msi_install_succeeded);
+
+DEFINE_METRIC_timing(setup_helper_msi_install_ms);
+
+DEFINE_METRIC_count(setup_locks_failed);
+DEFINE_METRIC_count(setup_lock11_failed);
+DEFINE_METRIC_count(setup_lock12_failed);
+
+DEFINE_METRIC_timing(setup_lock_acquire_ms);
+
+DEFINE_METRIC_count(setup_process_wait_failed);
+DEFINE_METRIC_count(setup_process_wait_failed_unknown);
+DEFINE_METRIC_count(setup_process_wait_failed_core);
+DEFINE_METRIC_count(setup_process_wait_failed_report);
+DEFINE_METRIC_count(setup_process_wait_failed_update);
+DEFINE_METRIC_count(setup_process_wait_failed_ig);
+DEFINE_METRIC_count(setup_process_wait_failed_handoff);
+DEFINE_METRIC_count(setup_process_wait_failed_ug);
+DEFINE_METRIC_count(setup_process_wait_failed_ua);
+DEFINE_METRIC_count(setup_process_wait_failed_cr);
+DEFINE_METRIC_count(setup_process_wait_failed_legacy);
+DEFINE_METRIC_count(setup_process_wait_failed_other);
+
+DEFINE_METRIC_timing(setup_process_wait_ms);
+
+DEFINE_METRIC_count(setup_rollback_version);
+DEFINE_METRIC_count(setup_rollback_files);
+DEFINE_METRIC_count(setup_files_rollback_shell);
+
+DEFINE_METRIC_count(setup_uac_succeeded);
+
+DEFINE_METRIC_count(setup_user_app_admin);
+DEFINE_METRIC_count(setup_machine_app_non_admin);
+
+}  // namespace omaha
+
diff --git a/setup/setup_metrics.h b/setup/setup_metrics.h
index 50a8800..9b56de0 100644
--- a/setup/setup_metrics.h
+++ b/setup/setup_metrics.h
@@ -1,228 +1,228 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// Declares the usage metrics used by the setup module.

-

-#ifndef OMAHA_SETUP_SETUP_METRICS_H__

-#define OMAHA_SETUP_SETUP_METRICS_H__

-

-#include "omaha/statsreport/metrics.h"

-

-namespace omaha {

-

-// How many times the Install() was called.

-DECLARE_METRIC_count(setup_install_total);

-// How many times the Install() method succeeded.

-DECLARE_METRIC_count(setup_install_succeeded);

-

-// How many times the UpdateSelfSilently() was called.

-DECLARE_METRIC_count(setup_update_self_total);

-// How many times the UpdateSelfSilently() method succeeded.

-DECLARE_METRIC_count(setup_update_self_succeeded);

-

-// How many times the Install() resulted in a Google Update install attempt.

-DECLARE_METRIC_count(setup_do_self_install_total);

-// How many times the Install() succeeded in installing Google Update.

-DECLARE_METRIC_count(setup_do_self_install_succeeded);

-

-// How many times the Install() resulted in a handoff attempt.

-// Does not include legacy handoffs, which do not go through Setup.

-DECLARE_METRIC_count(setup_handoff_only_total);

-// How many times the Install() successfully handed off.

-// Does not include legacy handoffs, which do not go through Setup.

-DECLARE_METRIC_count(setup_handoff_only_succeeded);

-

-// Total time (ms) spent installing Google Update as measured by time between

-// when DoInstall() is called and Setup phase 2 completes. Excludes handoffs.

-DECLARE_METRIC_timing(setup_install_google_update_total_ms);

-

-// Time (ms) from Setup starts until hands off to existing Omaha installation.

-DECLARE_METRIC_timing(setup_handoff_ms);

-// Time (ms) from Setup starts until the hand off process displays its UI.

-DECLARE_METRIC_timing(setup_handoff_ui_ms);

-

-// How many times Setup was run when Omaha was already installed but the core

-// was not running. Only incremented if existing Omaha version >= 1.2.0.0.

-DECLARE_METRIC_count(setup_installed_core_not_running);

-

-//

-// ShouldInstall metrics

-//

-

-// Times ShouldInstall() was called.

-DECLARE_METRIC_count(setup_should_install_total);

-

-// Times ShouldInstall() returned false because of OneClick case.

-DECLARE_METRIC_count(setup_should_install_false_oc);

-

-// Times ShouldInstall() returned true because not already installed.

-DECLARE_METRIC_count(setup_should_install_true_fresh_install);

-

-// Times ShouldInstall() returned false because older version than installed.

-DECLARE_METRIC_count(setup_should_install_false_older);

-

-// Times ShouldInstall() returned true because newer version than installed.

-DECLARE_METRIC_count(setup_should_install_true_newer);

-

-// Times ShouldInstall() returned false because same version fully installed.

-DECLARE_METRIC_count(setup_should_install_false_same);

-// Times ShouldInstall() returned true because same version not fully installed.

-DECLARE_METRIC_count(setup_should_install_true_same);

-// Times ShouldOverinstallSameVersion() returned true because the successful

-// install completion indicator was not present.

-DECLARE_METRIC_count(setup_should_install_true_same_completion_missing);

-

-// Times ShouldInstall() was called during a metainstaller installation when

-// some Omaha version was already installed.

-DECLARE_METRIC_count(setup_subsequent_install_total);

-// Times ShouldInstall() returned true during a metainstaller installation when

-// some Omaha version was already installed.

-DECLARE_METRIC_count(setup_subsequent_install_should_install_true);

-

-//

-// Setup Files

-//

-

-// How many times Setup attempted to install the files.

-DECLARE_METRIC_count(setup_files_total);

-// How many times Setup successfully installed the files.

-DECLARE_METRIC_count(setup_files_verification_succeeded);

-// How many times file install failed due to file verification before copy.

-DECLARE_METRIC_count(setup_files_verification_failed_pre);

-// How many times file install failed due to file verification after copy.

-DECLARE_METRIC_count(setup_files_verification_failed_post);

-

-// Total time (ms) spent installing files.

-DECLARE_METRIC_timing(setup_files_ms);

-

-// How many times the shell was replaced.

-DECLARE_METRIC_count(setup_files_replace_shell);

-

-//

-// Setup Phase 2

-//

-

-// Total time (ms) spent in Setup phase 2.

-DECLARE_METRIC_timing(setup_phase2_ms);

-

-// How many times Setup attempted to install the service and scheduled task.

-DECLARE_METRIC_count(setup_install_service_task_total);

-// How many times Setup successfully installed the service.

-DECLARE_METRIC_count(setup_install_service_succeeded);

-// How many times Setup successfully installed the scheduled task.

-DECLARE_METRIC_count(setup_install_task_succeeded);

-// How many times Setup successfully installed both service and scheduled task.

-DECLARE_METRIC_count(setup_install_service_and_task_succeeded);

-// How many times Setup failed to install both the service and scheduled task.

-DECLARE_METRIC_count(setup_install_service_and_task_failed);

-// The error returned by InstallService().

-DECLARE_METRIC_integer(setup_install_service_error);

-// The error returned by InstallScheduledTask().

-DECLARE_METRIC_integer(setup_install_task_error);

-

-// Time (ms) it took to install the service.

-DECLARE_METRIC_timing(setup_install_service_ms);

-// Time (ms) waited for the service to install when it failed to install.

-DECLARE_METRIC_timing(setup_install_service_failed_ms);

-// Time (ms) it took to install the scheduled task.

-DECLARE_METRIC_timing(setup_install_task_ms);

-

-

-// How many times Setup attempted to start the service.

-DECLARE_METRIC_count(setup_start_service_total);

-// How many times Setup successfully started the service.

-DECLARE_METRIC_count(setup_start_service_succeeded);

-// The error returned by StartService().

-DECLARE_METRIC_integer(setup_start_service_error);

-

-// Time (ms) it took to start the service.

-DECLARE_METRIC_timing(setup_start_service_ms);

-// Time (ms) waited for the service to start when it failed to start.

-DECLARE_METRIC_timing(setup_start_service_failed_ms);

-

-// How many times Setup attempted to start the scheduled task.

-DECLARE_METRIC_count(setup_start_task_total);

-// How many times Setup successfully started the scheduled task.

-DECLARE_METRIC_count(setup_start_task_succeeded);

-// The error returned by StartScheduledTask().

-DECLARE_METRIC_integer(setup_start_task_error);

-

-// Time (ms) it took to start scheduled task.

-DECLARE_METRIC_timing(setup_start_task_ms);

-

-// How many times Setup attempted to install the helper MSI.

-DECLARE_METRIC_count(setup_helper_msi_install_total);

-// How many times Setup successfully installed the helper MSI.

-DECLARE_METRIC_count(setup_helper_msi_install_succeeded);

-

-// Time (ms) it took to install the helper MSI.

-DECLARE_METRIC_timing(setup_helper_msi_install_ms);

-

-//

-// Specific Setup Failures

-//

-

-// How many times Setup failed to get any of the Setup locks.

-DECLARE_METRIC_count(setup_locks_failed);

-// How many times Setup failed to get the 1.1 Setup Lock.

-DECLARE_METRIC_count(setup_lock11_failed);

-// How many times Setup failed to get the 1.2 Setup Lock.

-DECLARE_METRIC_count(setup_lock12_failed);

-

-// Time (ms) it took to acquire all Setup locks.

-DECLARE_METRIC_timing(setup_lock_acquire_ms);

-

-

-// How many times Setup failed waiting for processes to stop - all modes.

-DECLARE_METRIC_count(setup_process_wait_failed);

-// How many times Setup failed waiting for processes to stop - specific modes.

-// The sum of these should equal setup_process_wait_failed.

-DECLARE_METRIC_count(setup_process_wait_failed_unknown);

-DECLARE_METRIC_count(setup_process_wait_failed_core);

-DECLARE_METRIC_count(setup_process_wait_failed_report);

-DECLARE_METRIC_count(setup_process_wait_failed_update);

-DECLARE_METRIC_count(setup_process_wait_failed_ig);

-DECLARE_METRIC_count(setup_process_wait_failed_handoff);

-DECLARE_METRIC_count(setup_process_wait_failed_ug);

-DECLARE_METRIC_count(setup_process_wait_failed_ua);

-DECLARE_METRIC_count(setup_process_wait_failed_cr);

-DECLARE_METRIC_count(setup_process_wait_failed_legacy);  // Any legacy mode.

-DECLARE_METRIC_count(setup_process_wait_failed_other);   // All other modes.

-

-// Time (ms) spent waiting for processes to exit - both successes and failures.

-DECLARE_METRIC_timing(setup_process_wait_ms);

-

-//

-// Other Setup Statistics

-//

-

-// How many times Setup rolled back the version.

-DECLARE_METRIC_count(setup_rollback_version);

-// How many times Setup rolled back file installation.

-DECLARE_METRIC_count(setup_rollback_files);

-// How many times Setup rolled back the shell.

-DECLARE_METRIC_count(setup_files_rollback_shell);

-

-// How many times Setup ran after elevating.

-DECLARE_METRIC_count(setup_uac_succeeded);

-

-// How many times Setup installed a user app as an elevated admin on >= Vista.

-DECLARE_METRIC_count(setup_user_app_admin);

-// How many times Setup attempted to install machine app as non-admin on <Vista.

-DECLARE_METRIC_count(setup_machine_app_non_admin);

-

-}  // namespace omaha

-

-#endif  // OMAHA_SETUP_SETUP_METRICS_H__

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// Declares the usage metrics used by the setup module.
+
+#ifndef OMAHA_SETUP_SETUP_METRICS_H__
+#define OMAHA_SETUP_SETUP_METRICS_H__
+
+#include "omaha/statsreport/metrics.h"
+
+namespace omaha {
+
+// How many times the Install() was called.
+DECLARE_METRIC_count(setup_install_total);
+// How many times the Install() method succeeded.
+DECLARE_METRIC_count(setup_install_succeeded);
+
+// How many times the UpdateSelfSilently() was called.
+DECLARE_METRIC_count(setup_update_self_total);
+// How many times the UpdateSelfSilently() method succeeded.
+DECLARE_METRIC_count(setup_update_self_succeeded);
+
+// How many times the Install() resulted in a Google Update install attempt.
+DECLARE_METRIC_count(setup_do_self_install_total);
+// How many times the Install() succeeded in installing Google Update.
+DECLARE_METRIC_count(setup_do_self_install_succeeded);
+
+// How many times the Install() resulted in a handoff attempt.
+// Does not include legacy handoffs, which do not go through Setup.
+DECLARE_METRIC_count(setup_handoff_only_total);
+// How many times the Install() successfully handed off.
+// Does not include legacy handoffs, which do not go through Setup.
+DECLARE_METRIC_count(setup_handoff_only_succeeded);
+
+// Total time (ms) spent installing Google Update as measured by time between
+// when DoInstall() is called and Setup phase 2 completes. Excludes handoffs.
+DECLARE_METRIC_timing(setup_install_google_update_total_ms);
+
+// Time (ms) from Setup starts until hands off to existing Omaha installation.
+DECLARE_METRIC_timing(setup_handoff_ms);
+// Time (ms) from Setup starts until the hand off process displays its UI.
+DECLARE_METRIC_timing(setup_handoff_ui_ms);
+
+// How many times Setup was run when Omaha was already installed but the core
+// was not running. Only incremented if existing Omaha version >= 1.2.0.0.
+DECLARE_METRIC_count(setup_installed_core_not_running);
+
+//
+// ShouldInstall metrics
+//
+
+// Times ShouldInstall() was called.
+DECLARE_METRIC_count(setup_should_install_total);
+
+// Times ShouldInstall() returned false because of OneClick case.
+DECLARE_METRIC_count(setup_should_install_false_oc);
+
+// Times ShouldInstall() returned true because not already installed.
+DECLARE_METRIC_count(setup_should_install_true_fresh_install);
+
+// Times ShouldInstall() returned false because older version than installed.
+DECLARE_METRIC_count(setup_should_install_false_older);
+
+// Times ShouldInstall() returned true because newer version than installed.
+DECLARE_METRIC_count(setup_should_install_true_newer);
+
+// Times ShouldInstall() returned false because same version fully installed.
+DECLARE_METRIC_count(setup_should_install_false_same);
+// Times ShouldInstall() returned true because same version not fully installed.
+DECLARE_METRIC_count(setup_should_install_true_same);
+// Times ShouldOverinstallSameVersion() returned true because the successful
+// install completion indicator was not present.
+DECLARE_METRIC_count(setup_should_install_true_same_completion_missing);
+
+// Times ShouldInstall() was called during a metainstaller installation when
+// some Omaha version was already installed.
+DECLARE_METRIC_count(setup_subsequent_install_total);
+// Times ShouldInstall() returned true during a metainstaller installation when
+// some Omaha version was already installed.
+DECLARE_METRIC_count(setup_subsequent_install_should_install_true);
+
+//
+// Setup Files
+//
+
+// How many times Setup attempted to install the files.
+DECLARE_METRIC_count(setup_files_total);
+// How many times Setup successfully installed the files.
+DECLARE_METRIC_count(setup_files_verification_succeeded);
+// How many times file install failed due to file verification before copy.
+DECLARE_METRIC_count(setup_files_verification_failed_pre);
+// How many times file install failed due to file verification after copy.
+DECLARE_METRIC_count(setup_files_verification_failed_post);
+
+// Total time (ms) spent installing files.
+DECLARE_METRIC_timing(setup_files_ms);
+
+// How many times the shell was replaced.
+DECLARE_METRIC_count(setup_files_replace_shell);
+
+//
+// Setup Phase 2
+//
+
+// Total time (ms) spent in Setup phase 2.
+DECLARE_METRIC_timing(setup_phase2_ms);
+
+// How many times Setup attempted to install the service and scheduled task.
+DECLARE_METRIC_count(setup_install_service_task_total);
+// How many times Setup successfully installed the service.
+DECLARE_METRIC_count(setup_install_service_succeeded);
+// How many times Setup successfully installed the scheduled task.
+DECLARE_METRIC_count(setup_install_task_succeeded);
+// How many times Setup successfully installed both service and scheduled task.
+DECLARE_METRIC_count(setup_install_service_and_task_succeeded);
+// How many times Setup failed to install both the service and scheduled task.
+DECLARE_METRIC_count(setup_install_service_and_task_failed);
+// The error returned by InstallService().
+DECLARE_METRIC_integer(setup_install_service_error);
+// The error returned by InstallScheduledTask().
+DECLARE_METRIC_integer(setup_install_task_error);
+
+// Time (ms) it took to install the service.
+DECLARE_METRIC_timing(setup_install_service_ms);
+// Time (ms) waited for the service to install when it failed to install.
+DECLARE_METRIC_timing(setup_install_service_failed_ms);
+// Time (ms) it took to install the scheduled task.
+DECLARE_METRIC_timing(setup_install_task_ms);
+
+
+// How many times Setup attempted to start the service.
+DECLARE_METRIC_count(setup_start_service_total);
+// How many times Setup successfully started the service.
+DECLARE_METRIC_count(setup_start_service_succeeded);
+// The error returned by StartService().
+DECLARE_METRIC_integer(setup_start_service_error);
+
+// Time (ms) it took to start the service.
+DECLARE_METRIC_timing(setup_start_service_ms);
+// Time (ms) waited for the service to start when it failed to start.
+DECLARE_METRIC_timing(setup_start_service_failed_ms);
+
+// How many times Setup attempted to start the scheduled task.
+DECLARE_METRIC_count(setup_start_task_total);
+// How many times Setup successfully started the scheduled task.
+DECLARE_METRIC_count(setup_start_task_succeeded);
+// The error returned by StartScheduledTask().
+DECLARE_METRIC_integer(setup_start_task_error);
+
+// Time (ms) it took to start scheduled task.
+DECLARE_METRIC_timing(setup_start_task_ms);
+
+// How many times Setup attempted to install the helper MSI.
+DECLARE_METRIC_count(setup_helper_msi_install_total);
+// How many times Setup successfully installed the helper MSI.
+DECLARE_METRIC_count(setup_helper_msi_install_succeeded);
+
+// Time (ms) it took to install the helper MSI.
+DECLARE_METRIC_timing(setup_helper_msi_install_ms);
+
+//
+// Specific Setup Failures
+//
+
+// How many times Setup failed to get any of the Setup locks.
+DECLARE_METRIC_count(setup_locks_failed);
+// How many times Setup failed to get the 1.1 Setup Lock.
+DECLARE_METRIC_count(setup_lock11_failed);
+// How many times Setup failed to get the 1.2 Setup Lock.
+DECLARE_METRIC_count(setup_lock12_failed);
+
+// Time (ms) it took to acquire all Setup locks.
+DECLARE_METRIC_timing(setup_lock_acquire_ms);
+
+
+// How many times Setup failed waiting for processes to stop - all modes.
+DECLARE_METRIC_count(setup_process_wait_failed);
+// How many times Setup failed waiting for processes to stop - specific modes.
+// The sum of these should equal setup_process_wait_failed.
+DECLARE_METRIC_count(setup_process_wait_failed_unknown);
+DECLARE_METRIC_count(setup_process_wait_failed_core);
+DECLARE_METRIC_count(setup_process_wait_failed_report);
+DECLARE_METRIC_count(setup_process_wait_failed_update);
+DECLARE_METRIC_count(setup_process_wait_failed_ig);
+DECLARE_METRIC_count(setup_process_wait_failed_handoff);
+DECLARE_METRIC_count(setup_process_wait_failed_ug);
+DECLARE_METRIC_count(setup_process_wait_failed_ua);
+DECLARE_METRIC_count(setup_process_wait_failed_cr);
+DECLARE_METRIC_count(setup_process_wait_failed_legacy);  // Any legacy mode.
+DECLARE_METRIC_count(setup_process_wait_failed_other);   // All other modes.
+
+// Time (ms) spent waiting for processes to exit - both successes and failures.
+DECLARE_METRIC_timing(setup_process_wait_ms);
+
+//
+// Other Setup Statistics
+//
+
+// How many times Setup rolled back the version.
+DECLARE_METRIC_count(setup_rollback_version);
+// How many times Setup rolled back file installation.
+DECLARE_METRIC_count(setup_rollback_files);
+// How many times Setup rolled back the shell.
+DECLARE_METRIC_count(setup_files_rollback_shell);
+
+// How many times Setup ran after elevating.
+DECLARE_METRIC_count(setup_uac_succeeded);
+
+// How many times Setup installed a user app as an elevated admin on >= Vista.
+DECLARE_METRIC_count(setup_user_app_admin);
+// How many times Setup attempted to install machine app as non-admin on <Vista.
+DECLARE_METRIC_count(setup_machine_app_non_admin);
+
+}  // namespace omaha
+
+#endif  // OMAHA_SETUP_SETUP_METRICS_H__
diff --git a/setup/setup_service.cc b/setup/setup_service.cc
index 76c62d6..02e9fd1 100644
--- a/setup/setup_service.cc
+++ b/setup/setup_service.cc
@@ -1,294 +1,294 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/setup/setup_service.h"

-

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/service_utils.h"

-#include "omaha/goopdate/command_line_builder.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/service/service_main.h"

-

-namespace omaha {

-

-HRESULT SetupService::StartService() {

-  OPT_LOG(L1, (_T("[SetupService::StartService]")));

-

-  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));

-  if (!scm) {

-    return HRESULTFromLastError();

-  }

-  CString service_name(ConfigManager::GetCurrentServiceName());

-  if (service_name.IsEmpty()) {

-    return GOOPDATE_E_SERVICE_NAME_EMPTY;

-  }

-  scoped_service service(::OpenService(get(scm),

-                                       service_name,

-                                       SERVICE_QUERY_STATUS | SERVICE_START));

-  if (!service) {

-    return HRESULTFromLastError();

-  }

-

-  SERVICE_STATUS status = {0};

-  if (::QueryServiceStatus(get(service), &status)) {

-    if (status.dwCurrentState == SERVICE_RUNNING ||

-        status.dwCurrentState == SERVICE_START_PENDING) {

-      SETUP_LOG(L1, (_T("[SetupService::StartService already running]")));

-      return S_OK;

-    }

-  }

-

-  // Start the service.

-  if (!::StartService(get(service), 0, NULL)) {

-    return HRESULTFromLastError();

-  }

-

-  SETUP_LOG(L1, (_T("[SetupService::StartService started]")));

-  return S_OK;

-}

-

-HRESULT SetupService::StopService() {

-  SETUP_LOG(L1, (_T("[SetupService::StopService]")));

-  CString service_name(ConfigManager::GetCurrentServiceName());

-  if (service_name.IsEmpty()) {

-    return GOOPDATE_E_SERVICE_NAME_EMPTY;

-  }

-

-  return ServiceInstall::StopService(service_name);

-}

-

-HRESULT SetupService::InstallService(const TCHAR* file_path) {

-  ASSERT1(file_path);

-

-  // Quote the FilePath before creating/updating the service. Append the

-  // arguments to be passed to the service entry point.

-  CString file_path_service(file_path);

-  EnclosePath(&file_path_service);

-  CString service_cmd_line(file_path_service);

-  CommandLineBuilder builder(COMMANDLINE_MODE_SERVICE);

-  service_cmd_line.AppendFormat(_T(" %s"), builder.GetCommandLineArgs());

-  SETUP_LOG(L2, (_T("[service command line ][%s]"), service_cmd_line));

-

-  CString service_description;

-  VERIFY1(service_description.LoadString(IDS_SERVICE_DESCRIPTION));

-

-  HRESULT hr = DoInstallService(service_cmd_line, service_description);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return InstallCOMService();

-}

-

-HRESULT SetupService::InstallCOMService() {

-  SETUP_LOG(L1, (_T("[SetupService::InstallCOMService]")));

-

-  return ServiceModule().RegisterCOMService();

-}

-

-HRESULT SetupService::DoInstallService(const TCHAR* service_cmd_line,

-                                       const TCHAR* description) {

-  SETUP_LOG(L1, (_T("[SetupService::DoInstallService][%s]"), service_cmd_line));

-

-  ASSERT1(service_cmd_line);

-  ASSERT1(description);

-

-  if (goopdate_utils::IsServiceInstalled()) {

-    // Lightweight upgrade of existing service.

-    HRESULT hr = UpgradeService(service_cmd_line);

-    ASSERT1(SUCCEEDED(hr));

-    if (SUCCEEDED(hr)) {

-      VERIFY1(SUCCEEDED(SetDescription(ConfigManager::GetCurrentServiceName(),

-                                       description)));

-      return hr;

-    }

-

-    // Delete any previous versions of the service. Then create a new service

-    // name, and fall through to install that.

-    VERIFY1(SUCCEEDED(DeleteServices()));

-    VERIFY1(SUCCEEDED(

-        ConfigManager::CreateAndSetVersionedServiceNameInRegistry()));

-    ASSERT1(!goopdate_utils::IsServiceInstalled());

-  }

-

-  return DoInstallNewService(ConfigManager::GetCurrentServiceName(),

-                             ConfigManager::GetCurrentServiceDisplayName(),

-                             service_cmd_line,

-                             description);

-}

-

-HRESULT SetupService::DoInstallNewService(const TCHAR* service_name,

-                                          const TCHAR* service_display_name,

-                                          const TCHAR* service_cmd_line,

-                                          const TCHAR* description) {

-  ASSERT1(service_name);

-  ASSERT1(service_display_name);

-  ASSERT1(service_cmd_line);

-  ASSERT1(description);

-  if (!*service_name) {

-    return GOOPDATE_E_SERVICE_NAME_EMPTY;

-  }

-

-  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));

-  if (!scm) {

-    ASSERT1(false);

-    HRESULT hr = HRESULTFromLastError();

-    SETUP_LOG(LEVEL_ERROR, (_T("Failed to open SC Manager 0x%08x"), hr));

-    return hr;

-  }

-

-  scoped_service service(::CreateService(

-                               get(scm),

-                               service_name,

-                               service_display_name,

-                               SERVICE_ALL_ACCESS,

-                               SERVICE_WIN32_OWN_PROCESS,

-                               SERVICE_AUTO_START,

-                               SERVICE_ERROR_NORMAL,

-                               service_cmd_line,

-                               NULL,

-                               NULL,

-                               _T("RPCSS\0"),

-                               NULL,

-                               NULL));

-  if (!service) {

-    HRESULT hr = HRESULTFromLastError();

-    SETUP_LOG(LEVEL_ERROR, (_T("[CreateService failed][0x%08x]"), hr));

-    return hr;

-  }

-  VERIFY1(SUCCEEDED(SetDescription(service_name, description)));

-  SETUP_LOG(L1, (_T("[SetupService::InstallService - service installed]")));

-  return S_OK;

-}

-

-// Uninstalls the service by:

-// 1. unregistering it

-// 2. deleting it from SCM if needed.

-HRESULT SetupService::UninstallService() {

-  SETUP_LOG(L3, (_T("[SetupService::UninstallService]")));

-

-  HRESULT hr = StopService();

-  if (FAILED(hr)) {

-    SETUP_LOG(LW, (_T("[SetupService::StopService failed][0x%08x]"), hr));

-    ASSERT1(HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) == hr);

-  }

-

-  VERIFY1(SUCCEEDED(ServiceModule().UnregisterCOMService()));

-

-  hr = DeleteServices();

-  if (FAILED(hr)) {

-    OPT_LOG(LEVEL_ERROR, (_T("[Can't delete the service][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT SetupService::UpgradeService(const TCHAR* service_cmd_line) {

-  ASSERT1(service_cmd_line);

-  ASSERT1(goopdate_utils::IsServiceInstalled());

-  if (!goopdate_utils::IsServiceInstalled()) {

-    return E_UNEXPECTED;

-  }

-

-  // Modify the configuration of the existing service.

-  HRESULT hr(StopService());

-  if (FAILED(hr)) {

-    ASSERT1(false);

-    SETUP_LOG(LEVEL_ERROR, (_T("[Can't stop the service][0x%08x]"), hr));

-    return hr;

-  }

-

-  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));

-  if (!scm) {

-    ASSERT1(false);

-    SETUP_LOG(LEVEL_ERROR, (_T("Failed to open SC Manager 0x%08x"),

-                           HRESULTFromLastError()));

-    return HRESULTFromLastError();

-  }

-

-  CString service_name(ConfigManager::GetCurrentServiceName());

-  if (service_name.IsEmpty()) {

-    return GOOPDATE_E_SERVICE_NAME_EMPTY;

-  }

-  scoped_service service(::OpenService(get(scm),

-                                       service_name,

-                                       SERVICE_CHANGE_CONFIG));

-  if (!service) {

-    ASSERT1(false);

-    SETUP_LOG(LEVEL_ERROR, (_T("Failed to open service for update 0x%08x"),

-                           HRESULTFromLastError()));

-    return HRESULTFromLastError();

-  }

-

-  if (!::ChangeServiceConfig(get(service),

-                             SERVICE_WIN32_OWN_PROCESS,

-                             SERVICE_AUTO_START,

-                             SERVICE_ERROR_NORMAL,

-                             service_cmd_line,

-                             NULL,

-                             NULL,

-                             NULL,

-                             NULL,

-                             NULL,

-                             NULL)) {

-    ASSERT1(false);

-    SETUP_LOG(LEVEL_ERROR, (_T("Failed to change service config 0x%08x"),

-                           HRESULTFromLastError()));

-    return HRESULTFromLastError();

-  }

-

-  SETUP_LOG(L3, (_T("[ChangeServiceConfig succeeded]")));

-  return S_OK;

-}

-

-HRESULT SetupService::DeleteServices() {

-  return ServiceInstall::UninstallServices(kServicePrefix, NULL);

-}

-

-HRESULT SetupService::SetDescription(const TCHAR* name,

-                                     const TCHAR* description) {

-  ASSERT1(name);

-  ASSERT1(description);

-  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));

-  if (!scm) {

-    return HRESULTFromLastError();

-  }

-

-  // Opening the service with less rights fails the ChangeServiceConfig2 call

-  // with E_ACCESSDENIED.

-  scoped_service service(::OpenService(get(scm), name, SERVICE_ALL_ACCESS));

-  if (!service) {

-    return HRESULTFromLastError();

-  }

-  SERVICE_DESCRIPTION info = { const_cast<TCHAR*>(description) };

-  if (!::ChangeServiceConfig2(get(service),

-                              SERVICE_CONFIG_DESCRIPTION,

-                              &info)) {

-    return HRESULTFromLastError();

-  }

-  SETUP_LOG(L3, (_T("[service description changed successfully]")));

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/setup/setup_service.h"
+
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/service_utils.h"
+#include "omaha/goopdate/command_line_builder.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/service/service_main.h"
+
+namespace omaha {
+
+HRESULT SetupService::StartService() {
+  OPT_LOG(L1, (_T("[SetupService::StartService]")));
+
+  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
+  if (!scm) {
+    return HRESULTFromLastError();
+  }
+  CString service_name(ConfigManager::GetCurrentServiceName());
+  if (service_name.IsEmpty()) {
+    return GOOPDATE_E_SERVICE_NAME_EMPTY;
+  }
+  scoped_service service(::OpenService(get(scm),
+                                       service_name,
+                                       SERVICE_QUERY_STATUS | SERVICE_START));
+  if (!service) {
+    return HRESULTFromLastError();
+  }
+
+  SERVICE_STATUS status = {0};
+  if (::QueryServiceStatus(get(service), &status)) {
+    if (status.dwCurrentState == SERVICE_RUNNING ||
+        status.dwCurrentState == SERVICE_START_PENDING) {
+      SETUP_LOG(L1, (_T("[SetupService::StartService already running]")));
+      return S_OK;
+    }
+  }
+
+  // Start the service.
+  if (!::StartService(get(service), 0, NULL)) {
+    return HRESULTFromLastError();
+  }
+
+  SETUP_LOG(L1, (_T("[SetupService::StartService started]")));
+  return S_OK;
+}
+
+HRESULT SetupService::StopService() {
+  SETUP_LOG(L1, (_T("[SetupService::StopService]")));
+  CString service_name(ConfigManager::GetCurrentServiceName());
+  if (service_name.IsEmpty()) {
+    return GOOPDATE_E_SERVICE_NAME_EMPTY;
+  }
+
+  return ServiceInstall::StopService(service_name);
+}
+
+HRESULT SetupService::InstallService(const TCHAR* file_path) {
+  ASSERT1(file_path);
+
+  // Quote the FilePath before creating/updating the service. Append the
+  // arguments to be passed to the service entry point.
+  CString file_path_service(file_path);
+  EnclosePath(&file_path_service);
+  CString service_cmd_line(file_path_service);
+  CommandLineBuilder builder(COMMANDLINE_MODE_SERVICE);
+  service_cmd_line.AppendFormat(_T(" %s"), builder.GetCommandLineArgs());
+  SETUP_LOG(L2, (_T("[service command line ][%s]"), service_cmd_line));
+
+  CString service_description;
+  VERIFY1(service_description.LoadString(IDS_SERVICE_DESCRIPTION));
+
+  HRESULT hr = DoInstallService(service_cmd_line, service_description);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return InstallCOMService();
+}
+
+HRESULT SetupService::InstallCOMService() {
+  SETUP_LOG(L1, (_T("[SetupService::InstallCOMService]")));
+
+  return ServiceModule().RegisterCOMService();
+}
+
+HRESULT SetupService::DoInstallService(const TCHAR* service_cmd_line,
+                                       const TCHAR* description) {
+  SETUP_LOG(L1, (_T("[SetupService::DoInstallService][%s]"), service_cmd_line));
+
+  ASSERT1(service_cmd_line);
+  ASSERT1(description);
+
+  if (goopdate_utils::IsServiceInstalled()) {
+    // Lightweight upgrade of existing service.
+    HRESULT hr = UpgradeService(service_cmd_line);
+    ASSERT1(SUCCEEDED(hr));
+    if (SUCCEEDED(hr)) {
+      VERIFY1(SUCCEEDED(SetDescription(ConfigManager::GetCurrentServiceName(),
+                                       description)));
+      return hr;
+    }
+
+    // Delete any previous versions of the service. Then create a new service
+    // name, and fall through to install that.
+    VERIFY1(SUCCEEDED(DeleteServices()));
+    VERIFY1(SUCCEEDED(
+        ConfigManager::CreateAndSetVersionedServiceNameInRegistry()));
+    ASSERT1(!goopdate_utils::IsServiceInstalled());
+  }
+
+  return DoInstallNewService(ConfigManager::GetCurrentServiceName(),
+                             ConfigManager::GetCurrentServiceDisplayName(),
+                             service_cmd_line,
+                             description);
+}
+
+HRESULT SetupService::DoInstallNewService(const TCHAR* service_name,
+                                          const TCHAR* service_display_name,
+                                          const TCHAR* service_cmd_line,
+                                          const TCHAR* description) {
+  ASSERT1(service_name);
+  ASSERT1(service_display_name);
+  ASSERT1(service_cmd_line);
+  ASSERT1(description);
+  if (!*service_name) {
+    return GOOPDATE_E_SERVICE_NAME_EMPTY;
+  }
+
+  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
+  if (!scm) {
+    ASSERT1(false);
+    HRESULT hr = HRESULTFromLastError();
+    SETUP_LOG(LEVEL_ERROR, (_T("Failed to open SC Manager 0x%08x"), hr));
+    return hr;
+  }
+
+  scoped_service service(::CreateService(
+                               get(scm),
+                               service_name,
+                               service_display_name,
+                               SERVICE_ALL_ACCESS,
+                               SERVICE_WIN32_OWN_PROCESS,
+                               SERVICE_AUTO_START,
+                               SERVICE_ERROR_NORMAL,
+                               service_cmd_line,
+                               NULL,
+                               NULL,
+                               _T("RPCSS\0"),
+                               NULL,
+                               NULL));
+  if (!service) {
+    HRESULT hr = HRESULTFromLastError();
+    SETUP_LOG(LEVEL_ERROR, (_T("[CreateService failed][0x%08x]"), hr));
+    return hr;
+  }
+  VERIFY1(SUCCEEDED(SetDescription(service_name, description)));
+  SETUP_LOG(L1, (_T("[SetupService::InstallService - service installed]")));
+  return S_OK;
+}
+
+// Uninstalls the service by:
+// 1. unregistering it
+// 2. deleting it from SCM if needed.
+HRESULT SetupService::UninstallService() {
+  SETUP_LOG(L3, (_T("[SetupService::UninstallService]")));
+
+  HRESULT hr = StopService();
+  if (FAILED(hr)) {
+    SETUP_LOG(LW, (_T("[SetupService::StopService failed][0x%08x]"), hr));
+    ASSERT1(HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) == hr);
+  }
+
+  VERIFY1(SUCCEEDED(ServiceModule().UnregisterCOMService()));
+
+  hr = DeleteServices();
+  if (FAILED(hr)) {
+    OPT_LOG(LEVEL_ERROR, (_T("[Can't delete the service][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT SetupService::UpgradeService(const TCHAR* service_cmd_line) {
+  ASSERT1(service_cmd_line);
+  ASSERT1(goopdate_utils::IsServiceInstalled());
+  if (!goopdate_utils::IsServiceInstalled()) {
+    return E_UNEXPECTED;
+  }
+
+  // Modify the configuration of the existing service.
+  HRESULT hr(StopService());
+  if (FAILED(hr)) {
+    ASSERT1(false);
+    SETUP_LOG(LEVEL_ERROR, (_T("[Can't stop the service][0x%08x]"), hr));
+    return hr;
+  }
+
+  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
+  if (!scm) {
+    ASSERT1(false);
+    SETUP_LOG(LEVEL_ERROR, (_T("Failed to open SC Manager 0x%08x"),
+                           HRESULTFromLastError()));
+    return HRESULTFromLastError();
+  }
+
+  CString service_name(ConfigManager::GetCurrentServiceName());
+  if (service_name.IsEmpty()) {
+    return GOOPDATE_E_SERVICE_NAME_EMPTY;
+  }
+  scoped_service service(::OpenService(get(scm),
+                                       service_name,
+                                       SERVICE_CHANGE_CONFIG));
+  if (!service) {
+    ASSERT1(false);
+    SETUP_LOG(LEVEL_ERROR, (_T("Failed to open service for update 0x%08x"),
+                           HRESULTFromLastError()));
+    return HRESULTFromLastError();
+  }
+
+  if (!::ChangeServiceConfig(get(service),
+                             SERVICE_WIN32_OWN_PROCESS,
+                             SERVICE_AUTO_START,
+                             SERVICE_ERROR_NORMAL,
+                             service_cmd_line,
+                             NULL,
+                             NULL,
+                             NULL,
+                             NULL,
+                             NULL,
+                             NULL)) {
+    ASSERT1(false);
+    SETUP_LOG(LEVEL_ERROR, (_T("Failed to change service config 0x%08x"),
+                           HRESULTFromLastError()));
+    return HRESULTFromLastError();
+  }
+
+  SETUP_LOG(L3, (_T("[ChangeServiceConfig succeeded]")));
+  return S_OK;
+}
+
+HRESULT SetupService::DeleteServices() {
+  return ServiceInstall::UninstallServices(kServicePrefix, NULL);
+}
+
+HRESULT SetupService::SetDescription(const TCHAR* name,
+                                     const TCHAR* description) {
+  ASSERT1(name);
+  ASSERT1(description);
+  scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
+  if (!scm) {
+    return HRESULTFromLastError();
+  }
+
+  // Opening the service with less rights fails the ChangeServiceConfig2 call
+  // with E_ACCESSDENIED.
+  scoped_service service(::OpenService(get(scm), name, SERVICE_ALL_ACCESS));
+  if (!service) {
+    return HRESULTFromLastError();
+  }
+  SERVICE_DESCRIPTION info = { const_cast<TCHAR*>(description) };
+  if (!::ChangeServiceConfig2(get(service),
+                              SERVICE_CONFIG_DESCRIPTION,
+                              &info)) {
+    return HRESULTFromLastError();
+  }
+  SETUP_LOG(L3, (_T("[service description changed successfully]")));
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/setup/setup_service.h b/setup/setup_service.h
index a2e7a84..b2c0b68 100644
--- a/setup/setup_service.h
+++ b/setup/setup_service.h
@@ -1,69 +1,69 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Sets up and controls the Google Update service.

-

-#ifndef OMAHA_SETUP_SETUP_SERVICE_H__

-#define OMAHA_SETUP_SETUP_SERVICE_H__

-

-#include <windows.h>

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-

-namespace omaha {

-

-class SetupService {

- public:

-  // Controls the service.

-  static HRESULT StartService();

-  static HRESULT StopService();

-

-  // Installs and uninstalls the service.

-  static HRESULT InstallService(const TCHAR* file_path);

-  static HRESULT UninstallService();

-

- private:

-  // COM registration for the GoogleUpdateCoreClass.

-  static HRESULT InstallCOMService();

-

-  static HRESULT DoInstallService(const TCHAR* service_cmd_line,

-                                  const TCHAR* desc);

-

-  static HRESULT DoInstallNewService(const TCHAR* service_name,

-                                     const TCHAR* service_display_name,

-                                     const TCHAR* service_cmd_line,

-                                     const TCHAR* description);

-

-  // Upgrades the service.

-  static HRESULT UpgradeService(const TCHAR* service_cmd_line);

-

-  // Deletes all services prefixed with "gupdate" from the SCM.

-  static HRESULT DeleteServices();

-

-  // Sets the service description. If the description is an empty string, the

-  // current description is deleted.

-  static HRESULT SetDescription(const TCHAR* name,

-                                const TCHAR* description);

-

-  friend class SetupServiceTest;

-  friend class CoreUtilsTest;

-

-  DISALLOW_IMPLICIT_CONSTRUCTORS(SetupService);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_SETUP_SETUP_SERVICE_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Sets up and controls the Google Update service.
+
+#ifndef OMAHA_SETUP_SETUP_SERVICE_H__
+#define OMAHA_SETUP_SETUP_SERVICE_H__
+
+#include <windows.h>
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+
+namespace omaha {
+
+class SetupService {
+ public:
+  // Controls the service.
+  static HRESULT StartService();
+  static HRESULT StopService();
+
+  // Installs and uninstalls the service.
+  static HRESULT InstallService(const TCHAR* file_path);
+  static HRESULT UninstallService();
+
+ private:
+  // COM registration for the GoogleUpdateCoreClass.
+  static HRESULT InstallCOMService();
+
+  static HRESULT DoInstallService(const TCHAR* service_cmd_line,
+                                  const TCHAR* desc);
+
+  static HRESULT DoInstallNewService(const TCHAR* service_name,
+                                     const TCHAR* service_display_name,
+                                     const TCHAR* service_cmd_line,
+                                     const TCHAR* description);
+
+  // Upgrades the service.
+  static HRESULT UpgradeService(const TCHAR* service_cmd_line);
+
+  // Deletes all services prefixed with "gupdate" from the SCM.
+  static HRESULT DeleteServices();
+
+  // Sets the service description. If the description is an empty string, the
+  // current description is deleted.
+  static HRESULT SetDescription(const TCHAR* name,
+                                const TCHAR* description);
+
+  friend class SetupServiceTest;
+  friend class CoreUtilsTest;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SetupService);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_SETUP_SETUP_SERVICE_H__
+
diff --git a/setup/setup_service_unittest.cc b/setup/setup_service_unittest.cc
index d01f96d..5ac3572 100644
--- a/setup/setup_service_unittest.cc
+++ b/setup/setup_service_unittest.cc
@@ -1,25 +1,25 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/testing/unit_test.h"

-#include "omaha/setup/setup_service.h"

-

-namespace omaha {

-

-// TODO(omaha): Test SetupServiceTest

-TEST(SetupServiceTest, SetupServiceTest) {

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/testing/unit_test.h"
+#include "omaha/setup/setup_service.h"
+
+namespace omaha {
+
+// TODO(omaha): Test SetupServiceTest
+TEST(SetupServiceTest, SetupServiceTest) {
+}
+
+}  // namespace omaha
diff --git a/setup/setup_unittest.cc b/setup/setup_unittest.cc
index 56aec45..19fe449 100644
--- a/setup/setup_unittest.cc
+++ b/setup/setup_unittest.cc
@@ -1,2792 +1,2792 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/process.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/system.h"

-#include "omaha/common/thread.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/setup/setup.h"

-#include "omaha/setup/setup_files.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-namespace {

-

-const int kProcessesCleanupWait = 30000;

-

-const TCHAR* const kFutureVersionString = _T("9.8.7.6");

-

-const TCHAR* const kAppMachineClientsPath =

-    _T("HKLM\\Software\\Google\\Update\\Clients\\")

-    _T("{50DA5C89-FF97-4536-BF3F-DF54C2F02EA8}\\");

-const TCHAR* const kAppMachineClientStatePath =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{50DA5C89-FF97-4536-BF3F-DF54C2F02EA8}\\");

-const TCHAR* const kApp2MachineClientsPath =

-    _T("HKLM\\Software\\Google\\Update\\Clients\\")

-    _T("{CB8E8A3C-7295-4529-B083-D5F76DCD4CC2}\\");

-

-const TCHAR* const kAppUserClientsPath =

-    _T("HKCU\\Software\\Google\\Update\\Clients\\")

-    _T("{50DA5C89-FF97-4536-BF3F-DF54C2F02EA8}\\");

-const TCHAR* const kAppUserClientStatePath =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\")

-    _T("{50DA5C89-FF97-4536-BF3F-DF54C2F02EA8}\\");

-const TCHAR* const kApp2UserClientsPath =

-    _T("HKCU\\Software\\Google\\Update\\Clients\\")

-    _T("{CB8E8A3C-7295-4529-B083-D5F76DCD4CC2}\\");

-

-

-class HoldLock : public Runnable {

- public:

-  explicit HoldLock(bool is_machine)

-      : is_machine_(is_machine) {

-    reset(lock_acquired_event_, ::CreateEvent(NULL, false, false, NULL));

-    reset(stop_event_, ::CreateEvent(NULL, false, false, NULL));

-  }

-

-  virtual void Run() {

-    GLock setup_lock;

-    NamedObjectAttributes setup_lock_attr;

-    GetNamedObjectAttributes(omaha::kSetupMutex, is_machine_, &setup_lock_attr);

-    EXPECT_TRUE(setup_lock.InitializeWithSecAttr(setup_lock_attr.name,

-                                                 &setup_lock_attr.sa));

-    __mutexScope(setup_lock);

-

-    EXPECT_TRUE(::SetEvent(get(lock_acquired_event_)));

-

-    EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(stop_event_), INFINITE));

-  }

-

-  void Stop() {

-    EXPECT_TRUE(::SetEvent(get(stop_event_)));

-  }

-

-  void WaitForLockToBeAcquired() {

-    EXPECT_EQ(WAIT_OBJECT_0,

-              ::WaitForSingleObject(get(lock_acquired_event_), 2000));

-  }

-

- private:

-  const bool is_machine_;

-  scoped_event lock_acquired_event_;

-  scoped_event stop_event_;

-

-  DISALLOW_IMPLICIT_CONSTRUCTORS(HoldLock);

-};

-

-class SetupFilesMockFailInstall : public SetupFiles {

- public:

-  explicit SetupFilesMockFailInstall(bool is_machine)

-      : SetupFiles(is_machine) {

-  }

-

-  virtual HRESULT Install() {

-    return kExpetedError;

-  }

-

-  static const HRESULT kExpetedError = 0x86427531;

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(SetupFilesMockFailInstall);

-};

-

-}  // namespace

-

-void CopyGoopdateFiles(const CString& omaha_path, const CString& version);

-

-class SetupTest : public testing::Test {

- protected:

-

-  typedef std::vector<uint32> Pids;

-

-  static void SetUpTestCase() {

-    CString exe_parent_dir = ConcatenatePath(

-                                 app_util::GetCurrentModuleDirectory(),

-                                 _T("unittest_support\\"));

-    omaha_exe_path_ = ConcatenatePath(exe_parent_dir,

-                                      _T("omaha_1.2.x\\GoogleUpdate.exe"));

-    omaha_10_exe_path_ = ConcatenatePath(exe_parent_dir,

-                                         _T("omaha_1.0.x\\GoogleUpdate.exe"));

-    omaha_11_exe_path_ = ConcatenatePath(exe_parent_dir,

-                                         _T("omaha_1.1.x\\GoogleUpdate.exe"));

-    not_listening_exe_path_ = ConcatenatePath(

-                                  exe_parent_dir,

-                                  _T("does_not_shutdown\\GoogleUpdate.exe"));

-  }

-

-  explicit SetupTest(bool is_machine)

-      : is_machine_(is_machine),

-        omaha_path_(GetGoogleUpdateUserPath()) {

-  }

-

-  void SetUp() {

-    ASSERT_SUCCEEDED(CreateDir(omaha_path_, NULL));

-    setup_.reset(new omaha::Setup(is_machine_, &args_));

-  }

-

-  bool ShouldInstall() {

-    SetupFiles setup_files(is_machine_);

-    setup_files.Init();

-    return setup_->ShouldInstall(&setup_files);

-  }

-

-  HRESULT StopGoogleUpdateAndWait() {

-    return setup_->StopGoogleUpdateAndWait();

-  }

-

-  HRESULT LaunchInstalledWorker(bool do_setup_phase_2, HANDLE* process) {

-    return setup_->LaunchInstalledWorker(do_setup_phase_2, process);

-  }

-

-  HRESULT TerminateCoreProcesses() const {

-    return setup_->TerminateCoreProcesses();

-  }

-

-  bool InitLegacySetupLocks(GLock* lock10,

-                            GLock* lock11_user,

-                            GLock* lock11_machine) {

-    return setup_->InitLegacySetupLocks(lock10, lock11_user, lock11_machine);

-  }

-

-  void PersistUpdateErrorInfo(bool is_machine,

-                              HRESULT error,

-                              int extra_code1,

-                              const CString& version) {

-    setup_->PersistUpdateErrorInfo(is_machine, error, extra_code1, version);

-  }

-

-  static bool HasXmlParser() { return Setup::HasXmlParser(); }

-

-  bool launched_offline_worker() { return setup_->launched_offline_worker_; }

-

-  void SetModeInstall() { setup_->mode_ = Setup::MODE_INSTALL; }

-  void SetModeSelfInstall() { setup_->mode_ = Setup::MODE_SELF_INSTALL; }

-  void SetModeSelfUpdate() { setup_->mode_ = Setup::MODE_SELF_UPDATE; }

-

-  // Uses DoInstall() instead of Install() as necessary to avoid the elevation

-  // check in Install().

-  HRESULT TestInstall() {

-    if (!is_machine_ || vista_util::IsUserAdmin()) {

-      return setup_->Install(_T("foo"));

-    } else {

-      setup_->mode_ = Setup::MODE_INSTALL;

-      return setup_->DoInstall();

-    }

-  }

-

-  // Acquires the Setup Lock in another thread then calls TestInstall().

-  void TestInstallWhileHoldingLock() {

-    HoldLock hold_lock(is_machine_);

-

-    Thread thread;

-    thread.Start(&hold_lock);

-    hold_lock.WaitForLockToBeAcquired();

-

-    EXPECT_EQ(GOOPDATE_E_FAILED_TO_GET_LOCK, TestInstall());

-

-    hold_lock.Stop();

-    thread.WaitTillExit(1000);

-  }

-

-  // Acquires the Setup Lock in another thread then calls DoInstall().

-  // Useful for testing modes other than MODE_INSTALL.

-  void TestDoInstallWhileHoldingLock() {

-    HoldLock hold_lock(is_machine_);

-

-    Thread thread;

-    thread.Start(&hold_lock);

-    hold_lock.WaitForLockToBeAcquired();

-

-    EXPECT_EQ(GOOPDATE_E_FAILED_TO_GET_LOCK, setup_->DoInstall());

-

-    hold_lock.Stop();

-    thread.WaitTillExit(1000);

-  }

-

-  void TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles() {

-    SetupFilesMockFailInstall setup_files_mock(is_machine_);

-

-    EXPECT_EQ(SetupFilesMockFailInstall::kExpetedError,

-              setup_->DoProtectedGoogleUpdateInstall(&setup_files_mock));

-  }

-

-  void StopGoogleUpdateAndWaitSucceedsTestHelper(bool use_job_objects_only) {

-    if (is_machine_ && !vista_util::IsUserAdmin()) {

-      std::wcout << _T("\tTest did not run because the user is not an admin.")

-                 << std::endl;

-      return;

-    }

-

-    // This test has been the most problematic, so do not run on build systems.

-    if (!ShouldRunLargeTest() || IsBuildSystem()) {

-      return;

-    }

-

-    scoped_process core_process;

-    scoped_process omaha_1_0_process;

-    scoped_process omaha_1_1_process;

-    scoped_process install_process;

-    scoped_process opposite_process;

-    scoped_process user_handoff_process;

-    scoped_process user_install_goopdate_process;

-    scoped_process user_install_needsadmin_process;

-    scoped_process setup_phase1_job_process;

-    scoped_process setup_phase1_job_opposite_process;

-    scoped_process install_job_opposite_process;

-    scoped_process silent_job_opposite_process;

-    scoped_process silent_do_not_kill_job_opposite_process;

-    scoped_job setup_phase1_job;

-    scoped_job setup_phase1_job_opposite;

-    scoped_job install_job_opposite;

-    scoped_job silent_job_opposite;

-    scoped_job silent_do_not_kill_job_opposite;

-

-    StartCoreProcessesToShutdown(address(core_process),

-                                 address(omaha_1_0_process),

-                                 address(omaha_1_1_process));

-    EXPECT_TRUE(core_process);

-    EXPECT_TRUE(omaha_1_0_process);

-    EXPECT_TRUE(omaha_1_1_process);

-

-    if (use_job_objects_only && is_machine_) {

-      // When starting the core process with psexec, there is a race condition

-      // between that process initializing (and joining a Job Object) and

-      // StopGoogleUpdateAndWait() looking for processes. If the latter wins,

-      // the core process is not found and StopGoogleUpdateAndWait() does not

-      // wait for the core process. As a result,

-      // ::WaitForSingleObject(get(core_process), 0)) would fail intermittently.

-      // Sleep here to allow the process to start and join the job.

-      // Note that this race condition is similar to ones we might encounter

-      // in the field when using Job Objects.

-      ::Sleep(500);

-    }

-

-    // /install is always ignored.

-    LaunchProcess(not_listening_exe_path_,

-                  _T("/install"),

-                  is_machine_,

-                  address(install_process));

-    EXPECT_TRUE(install_process);

-    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(install_process), 0));

-

-    if (vista_util::IsUserAdmin()) {

-      // Other users are usually ignored - use always ignored command line.

-      LaunchProcess(not_listening_exe_path_,

-                    _T(""),

-                    !is_machine_,

-                    address(opposite_process));

-      EXPECT_TRUE(opposite_process);

-      EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(opposite_process), 0));

-    } else {

-      EXPECT_FALSE(is_machine_)

-          << _T("Unexpected call for for machine when non-admin.");

-      // We can't launch a system process when non-admin.

-      std::wcout << _T("\tPart of this test did not run because the user is ")

-                    _T("not an admin.") << std::endl;

-    }

-

-    CString same_needsadmin = is_machine_ ? _T("\"needsadmin=True\"") :

-                                            _T("\"needsadmin=False\"");

-    CString opposite_needsadmin = is_machine_ ? _T("\"needsadmin=False\"") :

-                                                _T("\"needsadmin=True\"");

-    // Machine setup looks for users running /handoff and /ig with

-    // needsadmin=True and user setup ignores /handoff and /ig with

-    // needsadmin=True.

-    // Launching with needsadmin=<opposite> tests that machine ignores

-    // needsadmin=False and user ignores needsadmin=True.

-    LaunchProcess(not_listening_exe_path_,

-                  _T("/handoff ") + opposite_needsadmin,

-                  false,  // As the user.

-                  address(user_handoff_process));

-    EXPECT_TRUE(user_handoff_process);

-    EXPECT_EQ(WAIT_TIMEOUT,

-              ::WaitForSingleObject(get(user_handoff_process), 0));

-

-    LaunchProcess(not_listening_exe_path_,

-                  _T("/ig ") + opposite_needsadmin,

-                  false,  // As the user.

-                  address(user_install_goopdate_process));

-    EXPECT_TRUE(user_install_goopdate_process);

-    EXPECT_EQ(WAIT_TIMEOUT,

-              ::WaitForSingleObject(get(user_install_goopdate_process), 0));

-

-    // This process should be ignored even though it has needsadmin=<same>.

-    LaunchProcess(not_listening_exe_path_,

-                  _T("/install ") + same_needsadmin,

-                  false,  // As the user.

-                  address(user_install_needsadmin_process));

-    EXPECT_TRUE(user_install_goopdate_process);

-    EXPECT_EQ(WAIT_TIMEOUT,

-              ::WaitForSingleObject(get(user_install_goopdate_process), 0));

-

-    if (use_job_objects_only) {

-      // This Job Object is ignored.

-      // Only start this process when only using Job Objects because the

-      // argument-less process would be caught by the command line search.

-      LaunchJobProcess(is_machine_,

-                       is_machine_,

-                       kSetupPhase1NonSelfUpdateJobObject,

-                       address(setup_phase1_job_process),

-                       address(setup_phase1_job));

-      EXPECT_TRUE(setup_phase1_job_process);

-      EXPECT_EQ(WAIT_TIMEOUT,

-                ::WaitForSingleObject(get(setup_phase1_job_process), 0));

-    }

-

-    if (is_machine_ || vista_util::IsUserAdmin()) {

-      // These processes should be ignored because they are for the opposite

-      // set of processes.

-

-      LaunchJobProcess(!is_machine_,

-                       !is_machine_,

-                       kSetupPhase1NonSelfUpdateJobObject,

-                       address(setup_phase1_job_opposite_process),

-                       address(setup_phase1_job_opposite));

-      EXPECT_TRUE(setup_phase1_job_opposite_process);

-      EXPECT_EQ(WAIT_TIMEOUT,

-                ::WaitForSingleObject(get(setup_phase1_job_opposite_process),

-                                      0));

-

-      LaunchJobProcess(!is_machine_,

-                       !is_machine_,

-                       kAppInstallJobObject,

-                       address(install_job_opposite_process),

-                       address(install_job_opposite));

-      EXPECT_TRUE(install_job_opposite_process);

-      EXPECT_EQ(WAIT_TIMEOUT,

-                ::WaitForSingleObject(get(install_job_opposite_process), 0));

-

-      LaunchJobProcess(!is_machine_,

-                       !is_machine_,

-                       kSilentJobObject,

-                       address(silent_job_opposite_process),

-                       address(silent_job_opposite));

-      EXPECT_TRUE(install_job_opposite_process);

-      EXPECT_EQ(WAIT_TIMEOUT,

-                ::WaitForSingleObject(get(install_job_opposite_process), 0));

-

-      LaunchJobProcess(!is_machine_,

-                       !is_machine_,

-                       kSilentDoNotKillJobObject,

-                       address(silent_do_not_kill_job_opposite_process),

-                       address(silent_do_not_kill_job_opposite));

-      EXPECT_TRUE(install_job_opposite_process);

-      EXPECT_EQ(WAIT_TIMEOUT,

-                ::WaitForSingleObject(get(install_job_opposite_process), 0));

-    }

-

-    EXPECT_SUCCEEDED(StopGoogleUpdateAndWait());

-    EXPECT_EQ(0, setup_->extra_code1());

-

-    // Verify all real processes exited and terminate all the ones that aren't

-    // listening to shutdown.

-    HANDLE processes[] = {get(core_process),

-                          get(omaha_1_0_process),

-                          get(omaha_1_1_process)};

-    if (use_job_objects_only) {

-      // Since we only wait for processes in the Job Objects, legacy processes

-      // may not have stopped by the time StopGoogleUpdateAndWait() returns.

-      EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(core_process), 0));

-

-      // Now wait for the legacy processes to exit to avoid interfering with

-      // other tests.

-      EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(arraysize(processes),

-                                                        processes,

-                                                        true,  // wait for all

-                                                        8000));

-    } else {

-      EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(arraysize(processes),

-                                                        processes,

-                                                        true,  // wait for all

-                                                        0));

-    }

-

-    // Terminate all the processes and wait for them to exit to avoid

-    // interfering with other tests.

-    std::vector<HANDLE> started_processes;

-    started_processes.push_back(get(install_process));

-    if (vista_util::IsUserAdmin()) {

-      started_processes.push_back(get(opposite_process));

-    }

-    started_processes.push_back(get(user_handoff_process));

-    started_processes.push_back(get(user_install_goopdate_process));

-    started_processes.push_back(get(user_install_needsadmin_process));

-    if (use_job_objects_only) {

-      started_processes.push_back(get(setup_phase1_job_process));

-    }

-    if (is_machine_ || vista_util::IsUserAdmin()) {

-      started_processes.push_back(get(setup_phase1_job_opposite_process));

-      started_processes.push_back(get(install_job_opposite_process));

-      started_processes.push_back(get(silent_job_opposite_process));

-      started_processes.push_back(get(silent_do_not_kill_job_opposite_process));

-    }

-

-    for (size_t i = 0; i < started_processes.size(); ++i) {

-      EXPECT_TRUE(::TerminateProcess(started_processes[i], 1));

-    }

-    EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(started_processes.size(),

-                                                      &started_processes[0],

-                                                      true,  // wait for all

-                                                      kProcessesCleanupWait));

-  }

-

-  void StopGoogleUpdateAndWaitSucceedsTest() {

-    StopGoogleUpdateAndWaitSucceedsTestHelper(false);

-  }

-

-  HRESULT GetRunningCoreProcesses(Pids* core_processes) {

-    ASSERT1(core_processes);

-

-    CString user_sid_to_use;

-    if (is_machine_) {

-      user_sid_to_use = kLocalSystemSid;

-    } else {

-      EXPECT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid_to_use));

-    }

-

-    DWORD flags = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |

-                  EXCLUDE_CURRENT_PROCESS |

-                  INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;

-

-    std::vector<CString> command_lines;

-    command_lines.push_back(_T("/c"));

-

-    return Process::FindProcesses(flags,

-                                  _T("GoogleUpdate.exe"),

-                                  true,

-                                  user_sid_to_use,

-                                  command_lines,

-                                  core_processes);

-  }

-

-  void KillRunningCoreProcesses() {

-    Pids core_processes;

-    EXPECT_SUCCEEDED(GetRunningCoreProcesses(&core_processes));

-

-    for (size_t i = 0; i < core_processes.size(); ++i) {

-      scoped_process process(::OpenProcess(PROCESS_TERMINATE,

-                                           FALSE,

-                                           core_processes[i]));

-      EXPECT_TRUE(process);

-      EXPECT_TRUE(::TerminateProcess(get(process), static_cast<uint32>(-2)));

-    }

-  }

-

-  // Uses psexec to start processes as SYSTEM if necessary.

-  // Assumes that psexec blocks until the process exits.

-  // TODO(omaha): Start the opposite instances and wait for them in

-  // StopGoogleUpdateAndWaitSucceedsTest. They should not close.

-  void StartCoreProcessesToShutdown(HANDLE* core_process,

-                                    HANDLE* omaha_1_0_process,

-                                    HANDLE* omaha_1_1_process) {

-    ASSERT_TRUE(core_process);

-    ASSERT_TRUE(omaha_1_0_process);

-    ASSERT_TRUE(omaha_1_1_process);

-

-    // Find the core process or start one if necessary.

-    Pids core_processes;

-    EXPECT_SUCCEEDED(GetRunningCoreProcesses(&core_processes));

-    ASSERT_LE(core_processes.size(), static_cast<size_t>(1))

-        << _T("Only one core should be running.");

-

-    if (core_processes.empty()) {

-      LaunchProcess(omaha_exe_path_,

-                    _T("/c"),

-                    is_machine_,

-                    core_process);

-    } else {

-      *core_process = ::OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE,

-                                    FALSE,

-                                    core_processes[0]);

-    }

-    ASSERT_TRUE(*core_process);

-

-    // Start the legacy versions.

-    LaunchProcess(omaha_10_exe_path_, _T(""), is_machine_, omaha_1_0_process);

-    LaunchProcess(omaha_11_exe_path_, _T(""), is_machine_, omaha_1_1_process);

-

-    HANDLE processes[] = {*core_process,

-                          *omaha_1_0_process,

-                          *omaha_1_1_process};

-    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForMultipleObjects(arraysize(processes),

-                                                     processes,

-                                                     true,  // wait for all

-                                                     0));

-  }

-

-  // Launches an instance of GoogleUpdate.exe that doesn't exit.

-  void StopGoogleUpdateAndWaitProcessesDoNotStopTest() {

-    LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(is_machine_,

-                                                   _T(""),

-                                                   COMMANDLINE_MODE_NOARGS);

-  }

-

-  void LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(

-      bool is_machine_process,

-      const CString& args,

-      CommandLineMode expected_running_process_mode) {

-    ASSERT_TRUE(args);

-

-    if (is_machine_ && !vista_util::IsUserAdmin()) {

-      std::wcout << _T("\tTest did not run because the user is not an admin.")

-                 << std::endl;

-      return;

-    }

-

-    if (!ShouldRunLargeTest()) {

-      return;

-    }

-    scoped_process process;

-    LaunchProcess(not_listening_exe_path_,

-                  args,

-                  is_machine_process,

-                  address(process));

-    EXPECT_TRUE(process);

-    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(process), 0));

-

-    // Tests that use this method intermittently fail when run on build systems.

-    // This code attempts to ensure that the process is further along in the

-    // initialization process by waiting until Process::GetCommandLine succeeds.

-    HRESULT hr = E_FAIL;

-    CString process_cmd;

-    for (int tries = 0; tries < 100 && FAILED(hr); ++tries) {

-      hr = Process::GetCommandLine(::GetProcessId(get(process)), &process_cmd);

-      if (FAILED(hr)) {

-        ::Sleep(50);

-      }

-    }

-    EXPECT_SUCCEEDED(hr);

-

-    EXPECT_EQ(GOOPDATE_E_INSTANCES_RUNNING, StopGoogleUpdateAndWait());

-    EXPECT_EQ(expected_running_process_mode, setup_->extra_code1());

-    // Make sure the process is still running to help debug failures.

-    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(process), 0));

-

-

-    EXPECT_TRUE(::TerminateProcess(get(process), 1));

-    EXPECT_EQ(WAIT_OBJECT_0,

-              ::WaitForSingleObject(get(process), kProcessesCleanupWait));

-  }

-

-  // If start using Job Objects again, make sure the test only uses Job Objects.

-  void LaunchProcessInJobAndExpectStopGoogleUpdateAndWaitTimesOut(

-      const CString& job_base_name,

-      bool machine_as_system) {

-    ASSERT_TRUE(is_machine_ || !machine_as_system);

-

-    if (!ShouldRunLargeTest()) {

-      return;

-    }

-

-

-    scoped_process process;

-    scoped_job job;

-

-    LaunchJobProcess(is_machine_,

-                     machine_as_system,

-                     job_base_name,

-                     address(process),

-                     address(job));

-    EXPECT_TRUE(process);

-    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(process), 0));

-

-    EXPECT_EQ(GOOPDATE_E_INSTANCES_RUNNING, StopGoogleUpdateAndWait());

-    EXPECT_EQ(COMMANDLINE_MODE_NOARGS, setup_->extra_code1());

-

-    EXPECT_TRUE(::TerminateProcess(get(process), 1));

-    EXPECT_EQ(WAIT_OBJECT_0,

-              ::WaitForSingleObject(get(process), kProcessesCleanupWait));

-  }

-

-  // Starts a core process for this user, a core for the opposite type of user,

-  // and a /cr process (similar command line to /c), and a process without args.

-  void TestTerminateCoreProcessesWithBothTypesRunningAndOtherProcesses() {

-    scoped_process core_process;

-    scoped_process opposite_core_process;

-    scoped_process codered_process;

-    scoped_process noargs_process;

-    LaunchProcess(not_listening_exe_path_,

-                  _T("/c"),

-                  is_machine_,

-                  address(core_process));

-    EXPECT_TRUE(core_process);

-    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(core_process), 0));

-    LaunchProcess(not_listening_exe_path_,

-                  _T("/c"),

-                  !is_machine_,

-                  address(opposite_core_process));

-    EXPECT_TRUE(opposite_core_process);

-    EXPECT_EQ(WAIT_TIMEOUT,

-              ::WaitForSingleObject(get(opposite_core_process), 0));

-    LaunchProcess(not_listening_exe_path_,

-                  _T("/cr"),

-                  is_machine_,

-                  address(codered_process));

-    EXPECT_TRUE(codered_process);

-    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(codered_process), 0));

-    LaunchProcess(not_listening_exe_path_,

-                  _T(""),

-                  is_machine_,

-                  address(noargs_process));

-    EXPECT_TRUE(noargs_process);

-    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(noargs_process), 0));

-

-    EXPECT_SUCCEEDED(TerminateCoreProcesses());

-

-    EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(core_process), 8000));

-    HANDLE ignored_processes[] = {get(opposite_core_process),

-                                  get(codered_process),

-                                  get(noargs_process)};

-    EXPECT_EQ(WAIT_TIMEOUT,

-              ::WaitForMultipleObjects(arraysize(ignored_processes),

-                                                 ignored_processes,

-                                                 false,  // wait for any

-                                                 1000));

-

-    HANDLE started_processes[] = {get(core_process),

-                                  get(opposite_core_process),

-                                  get(codered_process),

-                                  get(noargs_process)};

-    EXPECT_TRUE(::TerminateProcess(get(opposite_core_process), 1));

-    EXPECT_TRUE(::TerminateProcess(get(codered_process), 1));

-    EXPECT_TRUE(::TerminateProcess(get(noargs_process), 1));

-    EXPECT_EQ(WAIT_OBJECT_0,

-              ::WaitForMultipleObjects(arraysize(started_processes),

-                                                 started_processes,

-                                                 true,  // wait for all

-                                                 kProcessesCleanupWait));

-  }

-

-  // Sets the legacy setup locks then attempts to run setup with the legacy

-  // versions. When the lock is not held and a newer version is installed,

-  // the legacy executables do a handoff install and exit. Since we have

-  // acquired the locks, the legacy executables should wait and not exit.

-  // Check both after a second.

-  // If Omaha 1.2.x is not found, a fake version is installed to prevent the

-  // legacy installers from installing.

-  // When is_machine_ is true, the legacy installers will start the Service.

-  void AcquireLegacySetupLocksTest() {

-    if (is_machine_ && !vista_util::IsUserAdmin()) {

-      std::wcout << _T("\tTest did not run because the user is not an admin.")

-                 << std::endl;

-      return;

-    }

-

-    if (!ShouldRunLargeTest()) {

-      return;

-    }

-

-    CString omaha_clients_key_name = is_machine_ ?

-                                     MACHINE_REG_CLIENTS_GOOPDATE :

-                                     USER_REG_CLIENTS_GOOPDATE;

-    CString version;

-    if (FAILED(RegKey::GetValue(omaha_clients_key_name,

-                                _T("pv"),

-                                &version)) ||

-        (_T("1.2.") != version.Left(4))) {

-      // Fool the legacy instances into thinking a newer version is installed

-      // so that they don't try to install when we release the locks.

-      // Do not worry about restoring it because there is only a potential

-      // problem when running a legacy metainstaller after this test.

-      version = _T("1.2.0.654");

-      EXPECT_SUCCEEDED(RegKey::SetValue(omaha_clients_key_name,

-                                        _T("pv"),

-                                        version));

-    }

-

-    // Legacy installers check for the files and over-install if they are not

-    // found, so we copy files to the version directory.

-    CString install_dir = ConcatenatePath(

-        is_machine_ ?

-        ConfigManager::Instance()->GetMachineGoopdateInstallDir() :

-        ConfigManager::Instance()->GetUserGoopdateInstallDir(),

-        version);

-    EXPECT_SUCCEEDED(File::CopyTree(

-        ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                        _T("unittest_support\\omaha_1.2.x\\")),

-        install_dir,

-        false));

-

-    // This block of code reproduces what we do in Setup::DoInstall().

-    GLock lock10, lock11_user, lock11_machine;

-    EXPECT_TRUE(InitLegacySetupLocks(&lock10, &lock11_user, &lock11_machine));

-    EXPECT_TRUE(lock10.Lock(500));

-    EXPECT_TRUE(lock11_user.Lock(500));

-    if (is_machine_) {

-      EXPECT_TRUE(lock11_machine.Lock(500));

-    }

-

-    // Start the legacy processes, and verify that they are blocked.

-    scoped_process omaha_1_0_process;

-    scoped_process omaha_1_1_process;

-    scoped_process omaha_1_0_process_as_system;

-    scoped_process omaha_1_1_process_as_system;

-    LaunchProcess(omaha_10_exe_path_,

-                  _T("/install"),

-                  false,  // As the user.

-                  address(omaha_1_0_process));

-    LaunchProcess(omaha_11_exe_path_,

-                  _T("/update"),

-                  false,  // As the user.

-                  address(omaha_1_1_process));

-    if (is_machine_) {

-      // For the machine case, tests the legacy process running both as Local

-      // System and as the user.

-      LaunchProcess(omaha_10_exe_path_,

-                    _T("/install"),

-                    true,  // As Local System.

-                    address(omaha_1_0_process_as_system));

-      LaunchProcess(omaha_11_exe_path_,

-                    _T("/update"),

-                    true,  // As Local System.

-                    address(omaha_1_1_process_as_system));

-    }

-

-

-    HANDLE processes[] = {get(omaha_1_0_process),

-                          get(omaha_1_1_process),

-                          get(omaha_1_0_process_as_system),

-                          get(omaha_1_1_process_as_system)};

-    int num_processes = arraysize(processes) - (is_machine_ ? 0 : 2);

-    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForMultipleObjects(num_processes,

-                                                     processes,

-                                                     false,  // wait for any

-                                                     1000));

-

-    // Release the locks and the legacy processes should exit

-    ASSERT_TRUE(lock10.Unlock());

-    ASSERT_TRUE(lock11_user.Unlock());

-    if (is_machine_) {

-      ASSERT_TRUE(lock11_machine.Unlock());

-    }

-

-    EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(num_processes,

-                                                      processes,

-                                                      true,  // wait for all

-                                                      kProcessesCleanupWait));

-  }

-

-  // Starts dummy process that doesn't exit and assigns it to the specified job.

-  // The handle returned by ShellExecute does not have PROCESS_SET_QUOTA access

-  // rights, so we get a new handle with the correct access rights to return to

-  // the caller.

-  void LaunchJobProcess(bool is_machine,

-                        bool as_system,

-                        const CString& job_base_name,

-                        HANDLE* process,

-                        HANDLE* job) {

-    ASSERT_TRUE(process);

-    ASSERT_TRUE(job);

-    ASSERT_TRUE(is_machine || !as_system);

-

-    scoped_process launched_process;

-    LaunchProcess(not_listening_exe_path_,

-                  _T(""),

-                  as_system,

-                  address(launched_process));

-    ASSERT_TRUE(launched_process);

-

-    *process = ::OpenProcess(PROCESS_ALL_ACCESS,

-                             false,

-                             ::GetProcessId(get(launched_process)));

-    ASSERT_TRUE(*process);

-

-    NamedObjectAttributes job_attr;

-    GetNamedObjectAttributes(job_base_name, is_machine, &job_attr);

-    *job = ::CreateJobObject(&job_attr.sa, job_attr.name);

-    ASSERT_TRUE(*job);

-

-    if (ERROR_ALREADY_EXISTS != ::GetLastError()) {

-      // Configure the newly created Job Object so it is compatible with any

-      // real processes that may be created.

-      JOBOBJECT_EXTENDED_LIMIT_INFORMATION extended_info = {0};

-

-      ASSERT_TRUE(::QueryInformationJobObject(

-                      *job,

-                      ::JobObjectExtendedLimitInformation,

-                      &extended_info,

-                      sizeof(extended_info),

-                      NULL)) <<

-          _T("Last Error: ") << ::GetLastError() << std::endl;

-

-      extended_info.BasicLimitInformation.LimitFlags =

-          JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;

-      ASSERT_TRUE(::SetInformationJobObject(*job,

-                                            ::JobObjectExtendedLimitInformation,

-                                            &extended_info,

-                                            sizeof(extended_info))) <<

-          _T("Last Error: ") << ::GetLastError() << std::endl;

-    }

-

-    ASSERT_TRUE(::AssignProcessToJobObject(*job, *process)) <<

-        _T("Last Error: ") << ::GetLastError() << std::endl;

-  }

-

-  const bool is_machine_;

-  const CString omaha_path_;

-  scoped_ptr<omaha::Setup> setup_;

-  CommandLineArgs args_;

-

-  static CString omaha_exe_path_;

-  static CString omaha_10_exe_path_;

-  static CString omaha_11_exe_path_;

-  static CString not_listening_exe_path_;

-};

-

-CString SetupTest::omaha_exe_path_;

-CString SetupTest::omaha_10_exe_path_;

-CString SetupTest::omaha_11_exe_path_;

-CString SetupTest::not_listening_exe_path_;

-

-class SetupMachineTest : public SetupTest {

- protected:

-  SetupMachineTest() : SetupTest(true) {

-  }

-

-  static void SetUpTestCase() {

-    // SeDebugPrivilege is required for elevated admins to open process open

-    // Local System processes with PROCESS_QUERY_INFORMATION access rights.

-    System::AdjustPrivilege(SE_DEBUG_NAME, true);

-

-    SetupTest::SetUpTestCase();

-  }

-};

-

-class SetupUserTest : public SetupTest {

- protected:

-  SetupUserTest() : SetupTest(false) {

-  }

-};

-

-class SetupFutureVersionInstalledUserTest : public SetupUserTest {

- protected:

-  SetupFutureVersionInstalledUserTest()

-      : SetupUserTest(),

-        future_version_path_(ConcatenatePath(omaha_path_,

-                                             kFutureVersionString)) {

-  }

-

-  virtual void SetUp() {

-    args_.extra_args_str = _T("\"appname=foo&lang=en\"");

-    CommandLineAppArgs app_args;

-    app_args.app_guid = StringToGuid(kAppGuid_);

-    args_.extra.apps.push_back(app_args);

-    SetupUserTest::SetUp();

-

-    // Save the existing version if present.

-    RegKey::GetValue(USER_REG_CLIENTS_GOOPDATE,

-                     kRegValueProductVersion,

-                     &existing_version_);

-    InstallFutureVersion();

-  }

-

-  virtual void TearDown() {

-    EXPECT_SUCCEEDED(DeleteDirectory(future_version_path_));

-    if (existing_version_.IsEmpty()) {

-      EXPECT_SUCCEEDED(RegKey::DeleteValue(USER_REG_CLIENTS_GOOPDATE,

-                                           kRegValueProductVersion));

-    } else {

-      EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                        kRegValueProductVersion,

-                                        existing_version_));

-    }

-

-    SetupUserTest::TearDown();

-  }

-

-  void InstallFutureVersion() {

-    DeleteDirectory(future_version_path_);

-    ASSERT_FALSE(File::IsDirectory(future_version_path_));

-

-    ASSERT_SUCCEEDED(CreateDir(future_version_path_, NULL));

-

-    ASSERT_SUCCEEDED(File::Copy(

-        ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                        _T("GoogleUpdate.exe")),

-        omaha_path_ + _T("GoogleUpdate.exe"),

-        false));

-

-    ASSERT_SUCCEEDED(File::Copy(

-        ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                        _T("goopdate.dll")),

-        ConcatenatePath(future_version_path_, _T("goopdate.dll")),

-        false));

-    ASSERT_SUCCEEDED(File::Copy(

-        ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                        _T("goopdateres_en.dll")),

-        ConcatenatePath(future_version_path_, _T("goopdateres_en.dll")),

-        false));

-

-    ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                      kRegValueProductVersion,

-                                      kFutureVersionString));

-  }

-

-  CString existing_version_;  // Saves the existing version from the registry.

-  const CString future_version_path_;

-  static const TCHAR* const kAppGuid_;

-};

-

-const TCHAR* const SetupFutureVersionInstalledUserTest::kAppGuid_ =

-    _T("{01D33078-BA95-4da6-A3FC-F31593FD4AA2}");

-

-class SetupRegistryProtectedUserTest : public SetupUserTest {

- protected:

-  SetupRegistryProtectedUserTest()

-      : SetupUserTest(),

-        hive_override_key_name_(kRegistryHiveOverrideRoot) {

-  }

-

-  static void SetUpTestCase() {

-    this_version_ = GetVersionString();

-    expected_is_overinstall_ = !OFFICIAL_BUILD;

-#ifdef DEBUG

-    if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueNameOverInstall)) {

-      DWORD value = 0;

-      EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,

-                                        kRegValueNameOverInstall,

-                                        &value));

-      expected_is_overinstall_ = value != 0;

-    }

-#endif

-  }

-

-  virtual void SetUp() {

-    SetupUserTest::SetUp();

-

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    // Do not override HKLM because it contains the CSIDL_* definitions.

-    OverrideSpecifiedRegistryHives(hive_override_key_name_, false, true);

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-

-    SetupUserTest::TearDown();

-  }

-

-  const CString hive_override_key_name_;

-

-  static CString this_version_;

-  static bool expected_is_overinstall_;

-};

-

-CString SetupRegistryProtectedUserTest::this_version_;

-bool SetupRegistryProtectedUserTest::expected_is_overinstall_;

-

-class SetupRegistryProtectedMachineTest : public SetupMachineTest {

- protected:

-  SetupRegistryProtectedMachineTest()

-      : SetupMachineTest(),

-        hive_override_key_name_(kRegistryHiveOverrideRoot) {

-  }

-

-  virtual void SetUp() {

-    SetupMachineTest::SetUp();

-

-    // Prime the cache of CSIDL_PROGRAM_FILES so it is available even after

-    // we override HKLM.

-    CString program_files_path;

-    EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files_path));

-

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    OverrideRegistryHives(hive_override_key_name_);

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-

-    SetupMachineTest::TearDown();

-  }

-

-  const CString hive_override_key_name_;

-};

-

-class SetupOfflineInstallerTest : public testing::Test {

- protected:

-  static bool CallCopyOfflineFiles(const CommandLineArgs& args,

-                                   const CString& target_location) {

-    omaha::Setup setup(false, &args);

-    return setup.CopyOfflineFiles(target_location);

-  }

-

-  static HRESULT CallCopyOfflineFilesForGuid(const CString& app_guid,

-                                             const CString& target_location) {

-    return omaha::Setup::CopyOfflineFilesForGuid(app_guid, target_location);

-  }

-};

-

-

-TEST_F(SetupFutureVersionInstalledUserTest, Install_HandoffWithShellMissing) {

-  CString shell_path = ConcatenatePath(omaha_path_, _T("GoogleUpdate.exe"));

-  ASSERT_TRUE(SUCCEEDED(File::DeleteAfterReboot(shell_path)) ||

-              !vista_util::IsUserAdmin());

-  ASSERT_FALSE(File::Exists(shell_path));

-

-  scoped_event ui_displayed_event;

-  ASSERT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(

-      kUiDisplayedEventEnvironmentVariableName,

-      is_machine_,

-      address(ui_displayed_event)));

-

-  EXPECT_EQ(GOOPDATE_E_HANDOFF_FAILED, setup_->Install(_T("/foo")));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), setup_->extra_code1());

-}

-

-TEST_F(SetupFutureVersionInstalledUserTest,

-       Install_HandoffWithGoopdateDllMissing) {

-  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));

-  ASSERT_SUCCEEDED(File::Remove(dll_path));

-  ASSERT_FALSE(File::Exists(dll_path));

-

-  scoped_event ui_displayed_event;

-  ASSERT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(

-      kUiDisplayedEventEnvironmentVariableName,

-      is_machine_,

-      address(ui_displayed_event)));

-

-  EXPECT_EQ(GOOPDATE_E_HANDOFF_FAILED, setup_->Install(_T("/foo")));

-  EXPECT_EQ(GOOGLEUPDATE_E_DLL_NOT_FOUND, setup_->extra_code1());

-}

-

-// The setup would cause a failure but we shouldn't see it because the event is

-// already signaled.

-// There is a race condition, especially on build machines, where the process

-// may have exited by the time we check for it and the event. Thus, there are

-// two expected cases.

-TEST_F(SetupFutureVersionInstalledUserTest,

-       Install_HandoffWithEventSignaledBeforeExit) {

-  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));

-  ASSERT_SUCCEEDED(File::Remove(dll_path));

-  ASSERT_FALSE(File::Exists(dll_path));

-

-  scoped_event ui_displayed_event;

-  ASSERT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(

-      kUiDisplayedEventEnvironmentVariableName,

-      is_machine_,

-      address(ui_displayed_event)));

-  ASSERT_TRUE(::SetEvent(get(ui_displayed_event)));

-

-  HRESULT hr = setup_->Install(_T("/foo"));

-  EXPECT_TRUE(SUCCEEDED(hr) || GOOPDATE_E_HANDOFF_FAILED == hr);

-  if (SUCCEEDED(hr)) {

-    EXPECT_EQ(0, setup_->extra_code1());

-

-    // There is a timing issue where GoogleUpdate.exe may not look at pv in the

-    // registry until after the existing_version_ has been restored to the

-    // registry. This causes GoogleUpdate.exe to find goopdate.dll in the

-    // existing_version_ and run with a UI. Wait so that this does not happen.

-#if OFFICIAL_BUILD

-    ::Sleep(8000);

-#else

-    ::Sleep(1000);

-#endif

-  } else {

-    EXPECT_EQ(GOOGLEUPDATE_E_DLL_NOT_FOUND, setup_->extra_code1());

-  }

-}

-

-// Silent installs ignore the event, so we should always get the exit code.

-// Also, exit code is reported directly instead of GOOPDATE_E_HANDOFF_FAILED.

-TEST_F(SetupFutureVersionInstalledUserTest,

-       Install_SilentHandoffWithEventSignaledBeforeExit) {

-  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));

-  ASSERT_SUCCEEDED(File::Remove(dll_path));

-  ASSERT_FALSE(File::Exists(dll_path));

-

-  scoped_event ui_displayed_event;

-  ASSERT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(

-      kUiDisplayedEventEnvironmentVariableName,

-      is_machine_,

-      address(ui_displayed_event)));

-  ASSERT_TRUE(::SetEvent(get(ui_displayed_event)));

-

-  args_.is_silent_set = true;

-  EXPECT_EQ(GOOGLEUPDATE_E_DLL_NOT_FOUND, setup_->Install(_T("/foo")));

-  EXPECT_EQ(0, setup_->extra_code1());

-}

-

-// Offline installs ignore the event regardless of whether they are silent, so

-// we should always get the exit code.

-// Also, exit code is reported directly instead of GOOPDATE_E_HANDOFF_FAILED.

-TEST_F(SetupFutureVersionInstalledUserTest,

-       Install_InteractiveOfflineHandoffWithEventSignaledBeforeExit) {

-  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));

-  ASSERT_SUCCEEDED(File::Remove(dll_path));

-  ASSERT_FALSE(File::Exists(dll_path));

-

-  scoped_event ui_displayed_event;

-  ASSERT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(

-      kUiDisplayedEventEnvironmentVariableName,

-      is_machine_,

-      address(ui_displayed_event)));

-  ASSERT_TRUE(::SetEvent(get(ui_displayed_event)));

-

-  // Make Setup think this is an offline install.

-  CString manifest_path;

-  manifest_path.Format(_T("%s\\%s.gup"),

-                           app_util::GetCurrentModuleDirectory(),

-                           kAppGuid_);

-  File manifest_file;

-  ASSERT_SUCCEEDED(manifest_file.Open(manifest_path, true, false));

-  ASSERT_SUCCEEDED(manifest_file.Touch());

-  ASSERT_SUCCEEDED(manifest_file.Close());

-

-  CString installer_path;

-  installer_path.Format(_T("%s\\unittest_installer.exe.%s"),

-                            app_util::GetCurrentModuleDirectory(),

-                            kAppGuid_);

-  File installer_file;

-  EXPECT_SUCCEEDED(installer_file.Open(installer_path, true, false));

-  EXPECT_SUCCEEDED(installer_file.Touch());

-  EXPECT_SUCCEEDED(installer_file.Close());

-

-  EXPECT_EQ(GOOGLEUPDATE_E_DLL_NOT_FOUND, setup_->Install(_T("/foo")));

-  EXPECT_EQ(0, setup_->extra_code1());

-

-  EXPECT_FALSE(args_.is_silent_set);  // Ensure not silent as voids this test.

-  EXPECT_TRUE(launched_offline_worker());

-

-  EXPECT_TRUE(::DeleteFile(manifest_path));

-  EXPECT_TRUE(::DeleteFile(installer_path));

-}

-

-TEST_F(SetupFutureVersionInstalledUserTest,

-       InstallSelfSilently_NoRunKey) {

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideSpecifiedRegistryHives(kRegistryHiveOverrideRoot, false, true);

-

-  // Write the future version to the override registry.

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    kFutureVersionString));

-

-  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));

-  ASSERT_SUCCEEDED(File::Remove(dll_path));

-  ASSERT_FALSE(File::Exists(dll_path));

-

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            setup_->InstallSelfSilently());

-  EXPECT_EQ(0, setup_->extra_code1());

-

-  RestoreRegistryHives();

-  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-TEST_F(SetupFutureVersionInstalledUserTest,

-       InstallSelfSilently_ValidRunKey) {

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideSpecifiedRegistryHives(kRegistryHiveOverrideRoot, false, true);

-

-  // Write the future version to the override registry.

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    kFutureVersionString));

-

-  const TCHAR kRunKey[] =

-      _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");

-  const CString shell_path = ConcatenatePath(GetGoogleUpdateUserPath(),

-                                             _T("GoogleUpdate.exe"));

-  CString run_value;

-  run_value.Format(_T("\"%s\" /just_exit"), shell_path);

-  ASSERT_SUCCEEDED(RegKey::SetValue(kRunKey, _T("Google Update"), run_value));

-

-  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));

-  ASSERT_SUCCEEDED(File::Remove(dll_path));

-  ASSERT_FALSE(File::Exists(dll_path));

-

-  EXPECT_SUCCEEDED(setup_->InstallSelfSilently());

-  EXPECT_EQ(0, setup_->extra_code1());

-

-  RestoreRegistryHives();

-  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-TEST_F(SetupUserTest, HasXmlParser) {

-  EXPECT_TRUE(HasXmlParser());

-}

-

-TEST_F(SetupUserTest, Install_LockTimedOut) {

-  TestInstallWhileHoldingLock();

-}

-

-TEST_F(SetupMachineTest, Install_LockTimedOut) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  TestInstallWhileHoldingLock();

-}

-

-TEST_F(SetupRegistryProtectedUserTest, Install_OEM) {

-  // The test fixture only disables HKCU by default. Disable HKLM too.

-  OverrideSpecifiedRegistryHives(hive_override_key_name_, true, true);

-

-  if (vista_util::IsVistaOrLater()) {

-    ASSERT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    ASSERT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  ASSERT_TRUE(ConfigManager::Instance()->IsWindowsInstalling());

-

-  args_.is_oem_set = true;

-  EXPECT_EQ(GOOPDATE_E_OEM_NOT_MACHINE_AND_PRIVILEGED_AND_AUDIT_MODE,

-            setup_->Install(_T("foo")));

-

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, kRegValueOemInstallTimeSec));

-  EXPECT_FALSE(

-      RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueOemInstallTimeSec));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest, Install_OemElevationRequired) {

-  if (vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user IS an admin.")

-               << std::endl;

-    return;

-  }

-

-  if (vista_util::IsVistaOrLater()) {

-    ASSERT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    ASSERT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  ASSERT_TRUE(ConfigManager::Instance()->IsWindowsInstalling());

-

-  args_.is_oem_set = true;

-  EXPECT_EQ(GOOPDATE_E_OEM_NOT_MACHINE_AND_PRIVILEGED_AND_AUDIT_MODE,

-            setup_->Install(_T("foo")));

-

-  EXPECT_FALSE(

-      RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueOemInstallTimeSec));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest, Install_OemNotAuditMode) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  args_.is_oem_set = true;

-  EXPECT_EQ(GOOPDATE_E_OEM_NOT_MACHINE_AND_PRIVILEGED_AND_AUDIT_MODE,

-            setup_->Install(_T("foo")));

-  EXPECT_FALSE(

-      RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueOemInstallTimeSec));

-}

-

-// Prevents the install from continuing by holding the Setup Lock.

-TEST_F(SetupRegistryProtectedMachineTest, Install_OemFails) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  if (vista_util::IsVistaOrLater()) {

-    ASSERT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-

-    // TODO(omaha): Overriding HKLM causes HasXmlParser() to fail on Vista,

-    // preventing this test from running correctly.

-    return;

-  } else {

-    ASSERT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-  ASSERT_TRUE(ConfigManager::Instance()->IsWindowsInstalling());

-

-  HoldLock hold_lock(is_machine_);

-  Thread thread;

-  thread.Start(&hold_lock);

-  hold_lock.WaitForLockToBeAcquired();

-

-  args_.is_oem_set = true;

-  EXPECT_EQ(GOOPDATE_E_FAILED_TO_GET_LOCK, setup_->Install(_T("foo")));

-

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueMachineId));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueUserId));

-  EXPECT_TRUE(

-      RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueOemInstallTimeSec));

-

-  hold_lock.Stop();

-  thread.WaitTillExit(1000);

-}

-

-TEST_F(SetupMachineTest, LaunchInstalledWorker_OemInstallNotOffline) {

-  SetModeInstall();

-  CommandLineAppArgs app1;

-  args_.extra.apps.push_back(app1);

-  args_.is_oem_set = true;

-  EXPECT_EQ(GOOPDATE_E_OEM_WITH_ONLINE_INSTALLER,

-            LaunchInstalledWorker(true, NULL));

-}

-

-TEST_F(SetupMachineTest, LaunchInstalledWorker_OemUpdateNotOffline) {

-  SetModeSelfUpdate();

-  args_.is_oem_set = true;

-  ExpectAsserts expect_asserts;

-  EXPECT_EQ(GOOPDATE_E_OEM_WITH_ONLINE_INSTALLER,

-            LaunchInstalledWorker(true, NULL));

-}

-

-TEST_F(SetupMachineTest, LaunchInstalledWorker_EulaRequiredNotOffline) {

-  SetModeInstall();

-  CommandLineAppArgs app1;

-  args_.extra.apps.push_back(app1);

-  args_.is_eula_required_set = true;

-  EXPECT_EQ(GOOPDATE_E_EULA_REQURED_WITH_ONLINE_INSTALLER,

-            LaunchInstalledWorker(true, NULL));

-}

-

-TEST_F(SetupUserTest, LaunchInstalledWorker_EulaRequiredNotOffline) {

-  SetModeInstall();

-  CommandLineAppArgs app1;

-  args_.extra.apps.push_back(app1);

-  args_.is_eula_required_set = true;

-  EXPECT_EQ(GOOPDATE_E_EULA_REQURED_WITH_ONLINE_INSTALLER,

-            LaunchInstalledWorker(true, NULL));

-}

-

-//

-// ShouldInstall tests.

-//

-

-TEST_F(SetupRegistryProtectedUserTest, ShouldInstall_NewerVersion) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    _T("1.0.3.4")));

-  EXPECT_TRUE(ShouldInstall());

-}

-

-TEST_F(SetupRegistryProtectedUserTest, ShouldInstall_OlderVersion) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    _T("9.8.7.6")));

-  EXPECT_FALSE(ShouldInstall());

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ShouldInstall_SameVersionFilesMissingSameLanguage) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueInstalledVersion,

-                                    this_version_));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-  ASSERT_SUCCEEDED(

-      DeleteDirectory(ConcatenatePath(omaha_path_, this_version_)));

-  CString file_path = ConcatenatePath(

-                          ConcatenatePath(omaha_path_, this_version_),

-                          _T("goopdate.dll"));

-  ASSERT_FALSE(File::Exists(file_path));

-

-  EXPECT_TRUE(ShouldInstall());

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ShouldInstall_SameVersionFilesPresentSameLanguage) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueInstalledVersion,

-                                    this_version_));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-

-  EXPECT_EQ(expected_is_overinstall_, ShouldInstall());

-

-  if (ShouldRunLargeTest()) {

-    // Override OverInstall to test official behavior on non-official builds.

-

-    DWORD existing_overinstall(0);

-    bool had_existing_overinstall = SUCCEEDED(RegKey::GetValue(

-                                                  MACHINE_REG_UPDATE_DEV,

-                                                  kRegValueNameOverInstall,

-                                                  &existing_overinstall));

-

-    EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                      kRegValueNameOverInstall,

-                                      static_cast<DWORD>(0)));

-#ifdef DEBUG

-    EXPECT_FALSE(ShouldInstall());

-#else

-    EXPECT_EQ(expected_is_overinstall_, ShouldInstall());

-#endif

-

-    // Restore "overinstall"

-    if (had_existing_overinstall) {

-      EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                        kRegValueNameOverInstall,

-                                        existing_overinstall));

-    } else {

-      EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,

-                                           kRegValueNameOverInstall));

-    }

-  }

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ShouldInstall_SameVersionFilesPresentSameLanguageMissingInstalledVer) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-

-  EXPECT_TRUE(ShouldInstall());

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ShouldInstall_SameVersionFilesPresentSameLanguageNewerInstalledVer) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueInstalledVersion,

-                                    kRegValueInstalledVersion));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-

-  EXPECT_TRUE(ShouldInstall());

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ShouldInstall_SameVersionFilesPresentDifferentLanguage) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueInstalledVersion,

-                                    this_version_));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-

-  EXPECT_EQ(expected_is_overinstall_, ShouldInstall());

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ShouldInstall_SameVersionFilesPresentNoLanguage) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueInstalledVersion,

-                                    this_version_));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-

-  EXPECT_EQ(expected_is_overinstall_, ShouldInstall());

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ShouldInstall_SameVersionRequiredFileMissing) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueInstalledVersion,

-                                    this_version_));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-  CString path = ConcatenatePath(ConcatenatePath(omaha_path_, this_version_),

-                                 _T("goopdate.dll"));

-  ASSERT_SUCCEEDED(File::Remove(path));

-  ASSERT_FALSE(File::Exists(path));

-

-  EXPECT_TRUE(ShouldInstall());

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ShouldInstall_SameVersionOptionalFileMissing) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueInstalledVersion,

-                                    this_version_));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-  CString path = ConcatenatePath(ConcatenatePath(omaha_path_, this_version_),

-                                 _T("GoopdateBho.dll"));

-  ASSERT_SUCCEEDED(File::Remove(path));

-  ASSERT_FALSE(File::Exists(path));

-

-  EXPECT_TRUE(ShouldInstall());

-}

-

-TEST_F(SetupRegistryProtectedUserTest, ShouldInstall_SameVersionShellMissing) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueInstalledVersion,

-                                    this_version_));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    this_version_));

-

-  CopyGoopdateFiles(omaha_path_, this_version_);

-  CString shell_path = ConcatenatePath(omaha_path_, _T("GoogleUpdate.exe"));

-  ASSERT_TRUE(SUCCEEDED(File::DeleteAfterReboot(shell_path)) ||

-              !vista_util::IsUserAdmin());

-  ASSERT_FALSE(File::Exists(shell_path));

-

-  EXPECT_TRUE(ShouldInstall());

-}

-

-TEST_F(SetupRegistryProtectedUserTest, ShouldInstall_NewerVersionShellMissing) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueInstalledVersion,

-                                    this_version_));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    kFutureVersionString));

-

-  CopyGoopdateFiles(omaha_path_, kFutureVersionString);

-  CString shell_path = ConcatenatePath(omaha_path_, _T("GoogleUpdate.exe"));

-  ASSERT_TRUE(SUCCEEDED(File::DeleteAfterReboot(shell_path)) ||

-              !vista_util::IsUserAdmin());

-  ASSERT_FALSE(File::Exists(shell_path));

-

-  EXPECT_FALSE(ShouldInstall());

-

-  EXPECT_SUCCEEDED(

-      DeleteDirectory(ConcatenatePath(omaha_path_, kFutureVersionString)));

-}

-

-//

-// StopGoogleUpdateAndWait tests.

-//

-// These are "large" tests.

-// They kill currently running GoogleUpdate processes, including the core, owned

-// by the current user or SYSTEM.

-// A core may already be running, so if a core process is found, it is used for

-// the tests. Otherwise, they launch a core from a previous build.

-// Using a previous build ensures that the shutdown event hasn't changed.

-// There is no test directly that this version can shutdown itself, but that is

-// much less likely to break.

-// The tests also start 1.0.x and 1.1.x legacy instances.

-// The Succeeds tests will fail if any processes that don't listen to the

-// shutdown event are running.

-//

-

-TEST_F(SetupUserTest, StopGoogleUpdateAndWait_Succeeds) {

-  StopGoogleUpdateAndWaitSucceedsTest();

-}

-

-TEST_F(SetupMachineTest, StopGoogleUpdateAndWait_Succeeds) {

-  StopGoogleUpdateAndWaitSucceedsTest();

-}

-

-// TODO(omaha): If start using Job Objects again, enable these tests.

-/*

-TEST_F(SetupUserTest, StopGoogleUpdateAndWait_SucceedsUsingOnlyJobObjects) {

-  StopGoogleUpdateAndWaitWithProcessSearchDisabledSucceedsTest();

-}

-

-TEST_F(SetupMachineTest, StopGoogleUpdateAndWait_SucceedsUsingOnlyJobObjects) {

-  StopGoogleUpdateAndWaitWithProcessSearchDisabledSucceedsTest();

-}

-*/

-

-TEST_F(SetupUserTest, StopGoogleUpdateAndWait_ProcessesDoNotStop) {

-  StopGoogleUpdateAndWaitProcessesDoNotStopTest();

-}

-

-TEST_F(SetupMachineTest, StopGoogleUpdateAndWait_ProcessesDoNotStop) {

-  StopGoogleUpdateAndWaitProcessesDoNotStopTest();

-}

-

-TEST_F(SetupMachineTest,

-       StopGoogleUpdateAndWait_MachineHandoffWorkerRunningAsUser) {

-  LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(

-      false,

-      _T("/handoff \"needsadmin=True\""),

-      COMMANDLINE_MODE_HANDOFF_INSTALL);

-}

-

-TEST_F(SetupMachineTest,

-       StopGoogleUpdateAndWait_MachineInstallGoogleUpdateWorkerRunningAsUser) {

-  LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(

-      false,

-      _T("/ig \"needsadmin=True\""),

-      COMMANDLINE_MODE_IG);

-}

-

-TEST_F(SetupMachineTest,

-       StopGoogleUpdateAndWait_UserHandoffWorkerRunningAsSystem) {

-  LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(

-      true,

-      _T("/handoff \"needsadmin=False\""),

-      COMMANDLINE_MODE_HANDOFF_INSTALL);

-}

-

-TEST_F(SetupMachineTest,

-       StopGoogleUpdateAndWait_UserInstallGoogleUpdateWorkerRunningAsSystem) {

-  LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(

-      true,

-      _T("/ig \"needsadmin=False\""),

-      COMMANDLINE_MODE_IG);

-}

-

-TEST_F(SetupUserTest, TerminateCoreProcesses_NoneRunning) {

-  KillRunningCoreProcesses();

-

-  EXPECT_SUCCEEDED(TerminateCoreProcesses());

-}

-

-TEST_F(SetupUserTest,

-       TerminateCoreProcesses_BothTypesRunningAndSimilarArgsProcess) {

-  TestTerminateCoreProcessesWithBothTypesRunningAndOtherProcesses();

-}

-

-TEST_F(SetupMachineTest, TerminateCoreProcesses_NoneRunning) {

-  KillRunningCoreProcesses();

-

-  EXPECT_SUCCEEDED(TerminateCoreProcesses());

-}

-

-TEST_F(SetupMachineTest,

-       TerminateCoreProcesses_BothTypesRunningAndSimilarArgsProcess) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-}

-  TestTerminateCoreProcessesWithBothTypesRunningAndOtherProcesses();

-}

-

-TEST_F(SetupUserTest, AcquireLegacySetupLocks_LegacyExesWait) {

-  AcquireLegacySetupLocksTest();

-}

-

-TEST_F(SetupMachineTest, AcquireLegacySetupLocks_LegacyExesWait) {

-  AcquireLegacySetupLocksTest();

-}

-

-TEST_F(SetupRegistryProtectedUserTest, PersistUpdateErrorInfo) {

-  PersistUpdateErrorInfo(is_machine_, 0x98765432, 77, _T("1.2.3.4"));

-

-  DWORD value(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE,

-                                    kRegValueSelfUpdateErrorCode,

-                                    &value));

-  EXPECT_EQ(0x98765432, value);

-

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE,

-                                    kRegValueSelfUpdateExtraCode1,

-                                    &value));

-  EXPECT_EQ(77, value);

-

-  CString version;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE,

-                                    kRegValueSelfUpdateVersion,

-                                    &version));

-  EXPECT_FALSE(version.IsEmpty());

-  EXPECT_STREQ(_T("1.2.3.4"), version);

-}

-

-TEST_F(SetupRegistryProtectedMachineTest, PersistUpdateErrorInfo) {

-  PersistUpdateErrorInfo(is_machine_, 0x98765430, 0x12345678, _T("2.3.4.5"));

-

-  DWORD value(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateErrorCode,

-                                    &value));

-  EXPECT_EQ(0x98765430, value);

-

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateExtraCode1,

-                                    &value));

-  EXPECT_EQ(0x12345678, value);

-

-  CString version;

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateVersion,

-                                    &version));

-  EXPECT_FALSE(version.IsEmpty());

-  EXPECT_STREQ(_T("2.3.4.5"), version);

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ReadAndClearUpdateErrorInfo_KeyDoesNotExist) {

-  DWORD self_update_error_code(0);

-  DWORD self_update_extra_code1(0);

-  CString self_update_version;

-  ExpectAsserts expect_asserts;

-  EXPECT_FALSE(Setup::ReadAndClearUpdateErrorInfo(false,

-                                                  &self_update_error_code,

-                                                  &self_update_extra_code1,

-                                                  &self_update_version));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       ReadAndClearUpdateErrorInfo_KeyDoesNotExist) {

-  DWORD self_update_error_code(0);

-  DWORD self_update_extra_code1(0);

-  CString self_update_version;

-  ExpectAsserts expect_asserts;

-  EXPECT_FALSE(Setup::ReadAndClearUpdateErrorInfo(true,

-                                                  &self_update_error_code,

-                                                  &self_update_extra_code1,

-                                                  &self_update_version));

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ReadAndClearUpdateErrorInfo_UpdateErrorCodeDoesNotExist) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));

-  DWORD self_update_error_code(0);

-  DWORD self_update_extra_code1(0);

-  CString self_update_version;

-  EXPECT_FALSE(Setup::ReadAndClearUpdateErrorInfo(false,

-                                                  &self_update_error_code,

-                                                  &self_update_extra_code1,

-                                                  &self_update_version));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       ReadAndClearUpdateErrorInfo_UpdateErrorCodeDoesNotExist) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));

-  DWORD self_update_error_code(0);

-  DWORD self_update_extra_code1(0);

-  CString self_update_version;

-  EXPECT_FALSE(Setup::ReadAndClearUpdateErrorInfo(true,

-                                                  &self_update_error_code,

-                                                  &self_update_extra_code1,

-                                                  &self_update_version));

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ReadAndClearUpdateErrorInfo_AllValuesPresent) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueSelfUpdateErrorCode,

-                                    static_cast<DWORD>(0x87654321)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueSelfUpdateExtraCode1,

-                                    static_cast<DWORD>(55)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueSelfUpdateVersion,

-                                    _T("0.2.4.8")));

-

-  DWORD self_update_error_code(0);

-  DWORD self_update_extra_code1(0);

-  CString self_update_version;

-  EXPECT_TRUE(Setup::ReadAndClearUpdateErrorInfo(false,

-                                                 &self_update_error_code,

-                                                 &self_update_extra_code1,

-                                                 &self_update_version));

-

-  EXPECT_EQ(0x87654321, self_update_error_code);

-  EXPECT_EQ(55, self_update_extra_code1);

-  EXPECT_STREQ(_T("0.2.4.8"), self_update_version);

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       ReadAndClearUpdateErrorInfo_AllValuesPresent) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateErrorCode,

-                                    static_cast<DWORD>(0x87654321)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateExtraCode1,

-                                    static_cast<DWORD>(55)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateVersion,

-                                    _T("0.2.4.8")));

-

-  DWORD self_update_error_code(0);

-  DWORD self_update_extra_code1(0);

-  CString self_update_version;

-  EXPECT_TRUE(Setup::ReadAndClearUpdateErrorInfo(true,

-                                                 &self_update_error_code,

-                                                 &self_update_extra_code1,

-                                                 &self_update_version));

-

-  EXPECT_EQ(0x87654321, self_update_error_code);

-  EXPECT_EQ(55, self_update_extra_code1);

-  EXPECT_STREQ(_T("0.2.4.8"), self_update_version);

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       ReadAndClearUpdateErrorInfo_ValuesPresentInMachineOnly) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateErrorCode,

-                                    static_cast<DWORD>(0x87654321)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateExtraCode1,

-                                    static_cast<DWORD>(55)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateVersion,

-                                    _T("0.2.4.8")));

-

-  DWORD self_update_error_code(0);

-  DWORD self_update_extra_code1(0);

-  CString self_update_version;

-  ExpectAsserts expect_asserts;

-  EXPECT_FALSE(Setup::ReadAndClearUpdateErrorInfo(false,

-                                                  &self_update_error_code,

-                                                  &self_update_extra_code1,

-                                                  &self_update_version));

-  // Clean up HKLM, which isn't overridden.

-  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,

-                                       kRegValueSelfUpdateErrorCode));

-  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,

-                                       kRegValueSelfUpdateExtraCode1));

-  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,

-                                       kRegValueSelfUpdateVersion));

-}

-

-TEST_F(SetupOfflineInstallerTest, ValidOfflineInstaller) {

-  CString guid_string = _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");

-

-  CString offline_manifest_path(guid_string);

-  offline_manifest_path += _T(".gup");

-  offline_manifest_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                          offline_manifest_path);

-  ASSERT_SUCCEEDED(File::Copy(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("server_manifest_one_app.xml")),

-      offline_manifest_path,

-      false));

-

-  CString installer_exe = _T("foo_installer.exe");

-  CString tarred_installer_path;

-  tarred_installer_path.Format(_T("%s.%s"), installer_exe, guid_string);

-  tarred_installer_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                          tarred_installer_path);

-

-  ASSERT_SUCCEEDED(File::Copy(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("GoogleUpdate.exe")),

-      tarred_installer_path,

-      false));

-

-  CommandLineArgs args;

-  CommandLineAppArgs app1;

-  app1.app_guid = StringToGuid(guid_string);

-  args.extra.apps.push_back(app1);

-  CString target_location = ConcatenatePath(

-                                app_util::GetCurrentModuleDirectory(),

-                                _T("offline_test"));

-

-  ASSERT_TRUE(CallCopyOfflineFiles(args, target_location));

-

-  CString target_manifest = ConcatenatePath(target_location,

-                                            guid_string + _T(".gup"));

-  EXPECT_TRUE(File::Exists(target_manifest));

-  CString target_file = ConcatenatePath(

-      ConcatenatePath(target_location, guid_string), installer_exe);

-  EXPECT_TRUE(File::Exists(target_file));

-

-  EXPECT_SUCCEEDED(DeleteDirectory(target_location));

-  EXPECT_SUCCEEDED(File::Remove(tarred_installer_path));

-  EXPECT_SUCCEEDED(File::Remove(offline_manifest_path));

-}

-

-TEST_F(SetupOfflineInstallerTest, NoOfflineInstaller) {

-  CString guid_string = _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");

-  CommandLineArgs args;

-  CommandLineAppArgs app1;

-  app1.app_guid = StringToGuid(guid_string);

-  args.extra.apps.push_back(app1);

-  CString target_location = ConcatenatePath(

-                                app_util::GetCurrentModuleDirectory(),

-                                _T("offline_test"));

-

-  EXPECT_FALSE(CallCopyOfflineFiles(args, target_location));

-}

-

-TEST_F(SetupOfflineInstallerTest, ValidCopyOfflineFilesForGuid) {

-  CString guid_string = _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");

-

-  CString offline_manifest_path(guid_string);

-  offline_manifest_path += _T(".gup");

-  offline_manifest_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                          offline_manifest_path);

-  ASSERT_SUCCEEDED(File::Copy(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("server_manifest_one_app.xml")),

-      offline_manifest_path,

-      false));

-

-  CString installer_exe = _T("foo_installer.exe");

-  CString tarred_installer_path;

-  tarred_installer_path.Format(_T("%s.%s"), installer_exe, guid_string);

-  tarred_installer_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                          tarred_installer_path);

-

-  ASSERT_SUCCEEDED(File::Copy(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("GoogleUpdate.exe")),

-      tarred_installer_path,

-      false));

-

-  CString target_location = ConcatenatePath(

-                                app_util::GetCurrentModuleDirectory(),

-                                _T("offline_test"));

-

-  ASSERT_SUCCEEDED(CallCopyOfflineFilesForGuid(guid_string, target_location));

-

-  CString target_manifest = ConcatenatePath(target_location,

-                                            guid_string + _T(".gup"));

-  EXPECT_TRUE(File::Exists(target_manifest));

-  CString target_file = ConcatenatePath(

-      ConcatenatePath(target_location, guid_string), installer_exe);

-  EXPECT_TRUE(File::Exists(target_file));

-

-  EXPECT_SUCCEEDED(DeleteDirectory(target_location));

-  EXPECT_SUCCEEDED(File::Remove(tarred_installer_path));

-  EXPECT_SUCCEEDED(File::Remove(offline_manifest_path));

-}

-

-TEST_F(SetupOfflineInstallerTest, NoCopyOfflineFilesForGuid) {

-  CString guid_string = _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");

-  CString target_location = ConcatenatePath(

-                                app_util::GetCurrentModuleDirectory(),

-                                _T("offline_test"));

-

-  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            CallCopyOfflineFilesForGuid(guid_string, target_location));

-}

-

-// A few tests for the public method. The bulk of the EULA cases are covered by

-// Install() and DoProtectedGoogleUpdateInstall() tests.

-TEST_F(SetupRegistryProtectedMachineTest, SetEulaAccepted_KeyDoesNotExist) {

-  EXPECT_EQ(S_OK, Setup::SetEulaAccepted(true));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest, SetEulaAccepted_ValueDoesNotExist) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));

-  EXPECT_EQ(S_FALSE, Setup::SetEulaAccepted(true));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest, SetEulaAccepted_ExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_SUCCEEDED(Setup::SetEulaAccepted(true));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-

-  // ClientState for Google Update (never used) and other apps is not affected.

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(SetupRegistryProtectedUserTest, SetEulaAccepted_KeyDoesNotExist) {

-  EXPECT_EQ(S_OK, Setup::SetEulaAccepted(false));

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedUserTest, SetEulaAccepted_ValueDoesNotExist) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));

-  EXPECT_EQ(S_FALSE, Setup::SetEulaAccepted(false));

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedUserTest, SetEulaAccepted_ExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_SUCCEEDED(Setup::SetEulaAccepted(false));

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-

-  // ClientState for Google Update (never used) and other apps is not affected.

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStatePath,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       Install_EulaNotRequired_UpdateKeyDoesNotExist) {

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       Install_EulaNotRequired_EulaValueDoesNotExist) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       Install_EulaNotRequired_EulaValueExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-

-  // ClientState for Google Update (never used) and other apps is not affected.

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       Install_EulaNotRequired_EulaValueExistsOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       Install_EulaNotRequired_EulaValueExistsOther) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(8000)));

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       Install_EulaNotRequired_EulaValueExistsString) {

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), _T("0")));

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       Install_EulaNotRequired_EulaValueDoesNotExistAlreadyInstalled) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       Install_EulaNotRequired_EulaValueExistsZeroAlreadyInstalled) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoInstall_SelfInstall_EulaNotRequired_EulaValueExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  SetModeSelfInstall();

-  args_.is_eula_required_set = false;

-  TestDoInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-// Self-update does not clear eulaaccepted. This case should never happen.

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoInstall_SelfUpdate_EulaNotRequired_EulaValueExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  SetModeSelfUpdate();

-  args_.is_eula_required_set = false;

-  TestDoInstallWhileHoldingLock();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// EULA required is not handled by DoInstall(). It is handled later by

-// DoProtectedGoogleUpdateInstall().

-TEST_F(SetupRegistryProtectedMachineTest,

-       Install_EulaRequired_EulaValueDoesNotExist) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));

-  args_.is_eula_required_set = true;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_UpdateKeyDoesNotExist) {

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-

-  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-

-  // ClientState for Google Update (never used) and other apps is not affected.

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-}

-

-// The existing value is ignored if there are not two registered apps. This is

-// an artifact of the implementation and not a requirement.

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOther) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(8000)));

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsString) {

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), _T("0")));

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// One app is not sufficient for detecting that Google Update is already

-// installed.

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistOneAppRegistered) {  // NOLINT

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// Even Google Update registered is not sufficient for detecting that Google

-// Update is already installed.

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistGoogleUpdateRegistered) {  // NOLINT

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// Important: The existing state is not changed because two apps are registered.

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistTwoAppsRegistered) {  // NOLINT

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2MachineClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-// The existing state is not changed because Google Update is already

-// installed, but there is no way to differentiate this from writing 0.

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsZeroTwoAppsRegistered) {  // NOLINT

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2MachineClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// The existing state is not changed because Google Update is already installed.

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOneTwoAppsRegistered) {  // NOLINT

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2MachineClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-}

-

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_SelfInstall_EulaRequired_UpdateKeyDoesNotExist) {  // NOLINT

-  SetModeSelfInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// Self-update does not set eulaaccepted. This case should never happen.

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_SelfUpdate_EulaRequired_UpdateKeyDoesNotExist) {  // NOLINT

-  SetModeSelfUpdate();

-  args_.is_eula_required_set = true;

-  ExpectAsserts expect_asserts;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));

-}

-

-// EULA not required is not handled by DoProtectedGoogleUpdateInstall(). It

-// would have already been handled by DoInstall().

-TEST_F(SetupRegistryProtectedMachineTest,

-       DoProtectedGoogleUpdateInstall_EulaNotRequired_EulaValueExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  SetModeInstall();

-  args_.is_eula_required_set = false;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       Install_EulaNotRequired_UpdateKeyDoesNotExist) {

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       Install_EulaNotRequired_EulaValueDoesNotExist) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       Install_EulaNotRequired_EulaValueExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-

-  // ClientState for Google Update (never used) and other apps is not affected.

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStatePath,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       Install_EulaNotRequired_EulaValueExistsOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       Install_EulaNotRequired_EulaValueExistsOther) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(8000)));

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       Install_EulaNotRequired_EulaValueExistsString) {

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(USER_REG_UPDATE, _T("eulaaccepted"), _T("0")));

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       Install_EulaNotRequired_EulaValueDoesNotExistAlreadyInstalled) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       Install_EulaNotRequired_EulaValueExistsZeroAlreadyInstalled) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  args_.is_eula_required_set = false;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       DoInstall_SelfInstall_EulaNotRequired_EulaValueExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  SetModeSelfInstall();

-  args_.is_eula_required_set = false;

-  TestDoInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-// Self-update does not clear eulaaccepted. This case should never happen.

-TEST_F(SetupRegistryProtectedUserTest,

-       DoInstall_SelfUpdate_EulaNotRequired_EulaValueExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  SetModeSelfUpdate();

-  args_.is_eula_required_set = false;

-  TestDoInstallWhileHoldingLock();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// EULA required is not handled by DoInstall(). It is handled later by

-// DoProtectedGoogleUpdateInstall().

-TEST_F(SetupRegistryProtectedUserTest,

-       Install_EulaRequired_EulaValueDoesNotExist) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));

-  args_.is_eula_required_set = true;

-  TestInstallWhileHoldingLock();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_UpdateKeyDoesNotExist) {

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-

-  // ClientState for Google Update (never used) and other apps is not affected.

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-  value = UINT_MAX;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStatePath,

-                   _T("eulaaccepted"),

-                   &value));

-  EXPECT_EQ(0, value);

-}

-

-// The existing value is ignored if there are not two registered apps. This is

-// an artifact of the implementation and not a requirement.

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOne) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOther) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(8000)));

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsString) {

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(USER_REG_UPDATE, _T("eulaaccepted"), _T("0")));

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// One app is not sufficient for detecting that Google Update is already

-// installed.

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistOneAppRegistered) {  // NOLINT

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// Even Google Update registered is not sufficient for detecting that Google

-// Update is already installed.

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistGoogleUpdateRegistered) {  // NOLINT

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// Important: The existing state is not changed because two apps are registered.

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistTwoAppsRegistered) {  // NOLINT

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2UserClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-// The existing state is not changed because Google Update is already

-// installed, but there is no way to differentiate this from writing 0.

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsZeroTwoAppsRegistered) {  // NOLINT

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2UserClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// The existing state is not changed because Google Update is already installed.

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOneTwoAppsRegistered) {  // NOLINT

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2UserClientsPath,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  SetModeInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(1, value);

-}

-

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_SelfInstall_EulaRequired_UpdateKeyDoesNotExist) {  // NOLINT

-  SetModeSelfInstall();

-  args_.is_eula_required_set = true;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-// Self-update does not set eulaaccepted. This case should never happen.

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_SelfUpdate_EulaRequired_UpdateKeyDoesNotExist) {  // NOLINT

-  SetModeSelfUpdate();

-  args_.is_eula_required_set = true;

-  ExpectAsserts expect_asserts;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));

-}

-

-// EULA not required is not handled by DoProtectedGoogleUpdateInstall(). It

-// would have already been handled by DoInstall().

-TEST_F(SetupRegistryProtectedUserTest,

-       DoProtectedGoogleUpdateInstall_EulaNotRequired_EulaValueExistsZero) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  SetModeInstall();

-  args_.is_eula_required_set = false;

-  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();

-  DWORD value = UINT_MAX;

-  EXPECT_SUCCEEDED(

-      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));

-  EXPECT_EQ(0, value);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/process.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/system.h"
+#include "omaha/common/thread.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/setup/setup.h"
+#include "omaha/setup/setup_files.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+namespace {
+
+const int kProcessesCleanupWait = 30000;
+
+const TCHAR* const kFutureVersionString = _T("9.8.7.6");
+
+const TCHAR* const kAppMachineClientsPath =
+    _T("HKLM\\Software\\Google\\Update\\Clients\\")
+    _T("{50DA5C89-FF97-4536-BF3F-DF54C2F02EA8}\\");
+const TCHAR* const kAppMachineClientStatePath =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{50DA5C89-FF97-4536-BF3F-DF54C2F02EA8}\\");
+const TCHAR* const kApp2MachineClientsPath =
+    _T("HKLM\\Software\\Google\\Update\\Clients\\")
+    _T("{CB8E8A3C-7295-4529-B083-D5F76DCD4CC2}\\");
+
+const TCHAR* const kAppUserClientsPath =
+    _T("HKCU\\Software\\Google\\Update\\Clients\\")
+    _T("{50DA5C89-FF97-4536-BF3F-DF54C2F02EA8}\\");
+const TCHAR* const kAppUserClientStatePath =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\")
+    _T("{50DA5C89-FF97-4536-BF3F-DF54C2F02EA8}\\");
+const TCHAR* const kApp2UserClientsPath =
+    _T("HKCU\\Software\\Google\\Update\\Clients\\")
+    _T("{CB8E8A3C-7295-4529-B083-D5F76DCD4CC2}\\");
+
+
+class HoldLock : public Runnable {
+ public:
+  explicit HoldLock(bool is_machine)
+      : is_machine_(is_machine) {
+    reset(lock_acquired_event_, ::CreateEvent(NULL, false, false, NULL));
+    reset(stop_event_, ::CreateEvent(NULL, false, false, NULL));
+  }
+
+  virtual void Run() {
+    GLock setup_lock;
+    NamedObjectAttributes setup_lock_attr;
+    GetNamedObjectAttributes(omaha::kSetupMutex, is_machine_, &setup_lock_attr);
+    EXPECT_TRUE(setup_lock.InitializeWithSecAttr(setup_lock_attr.name,
+                                                 &setup_lock_attr.sa));
+    __mutexScope(setup_lock);
+
+    EXPECT_TRUE(::SetEvent(get(lock_acquired_event_)));
+
+    EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(stop_event_), INFINITE));
+  }
+
+  void Stop() {
+    EXPECT_TRUE(::SetEvent(get(stop_event_)));
+  }
+
+  void WaitForLockToBeAcquired() {
+    EXPECT_EQ(WAIT_OBJECT_0,
+              ::WaitForSingleObject(get(lock_acquired_event_), 2000));
+  }
+
+ private:
+  const bool is_machine_;
+  scoped_event lock_acquired_event_;
+  scoped_event stop_event_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(HoldLock);
+};
+
+class SetupFilesMockFailInstall : public SetupFiles {
+ public:
+  explicit SetupFilesMockFailInstall(bool is_machine)
+      : SetupFiles(is_machine) {
+  }
+
+  virtual HRESULT Install() {
+    return kExpetedError;
+  }
+
+  static const HRESULT kExpetedError = 0x86427531;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(SetupFilesMockFailInstall);
+};
+
+}  // namespace
+
+void CopyGoopdateFiles(const CString& omaha_path, const CString& version);
+
+class SetupTest : public testing::Test {
+ protected:
+
+  typedef std::vector<uint32> Pids;
+
+  static void SetUpTestCase() {
+    CString exe_parent_dir = ConcatenatePath(
+                                 app_util::GetCurrentModuleDirectory(),
+                                 _T("unittest_support\\"));
+    omaha_exe_path_ = ConcatenatePath(exe_parent_dir,
+                                      _T("omaha_1.2.x\\GoogleUpdate.exe"));
+    omaha_10_exe_path_ = ConcatenatePath(exe_parent_dir,
+                                         _T("omaha_1.0.x\\GoogleUpdate.exe"));
+    omaha_11_exe_path_ = ConcatenatePath(exe_parent_dir,
+                                         _T("omaha_1.1.x\\GoogleUpdate.exe"));
+    not_listening_exe_path_ = ConcatenatePath(
+                                  exe_parent_dir,
+                                  _T("does_not_shutdown\\GoogleUpdate.exe"));
+  }
+
+  explicit SetupTest(bool is_machine)
+      : is_machine_(is_machine),
+        omaha_path_(GetGoogleUpdateUserPath()) {
+  }
+
+  void SetUp() {
+    ASSERT_SUCCEEDED(CreateDir(omaha_path_, NULL));
+    setup_.reset(new omaha::Setup(is_machine_, &args_));
+  }
+
+  bool ShouldInstall() {
+    SetupFiles setup_files(is_machine_);
+    setup_files.Init();
+    return setup_->ShouldInstall(&setup_files);
+  }
+
+  HRESULT StopGoogleUpdateAndWait() {
+    return setup_->StopGoogleUpdateAndWait();
+  }
+
+  HRESULT LaunchInstalledWorker(bool do_setup_phase_2, HANDLE* process) {
+    return setup_->LaunchInstalledWorker(do_setup_phase_2, process);
+  }
+
+  HRESULT TerminateCoreProcesses() const {
+    return setup_->TerminateCoreProcesses();
+  }
+
+  bool InitLegacySetupLocks(GLock* lock10,
+                            GLock* lock11_user,
+                            GLock* lock11_machine) {
+    return setup_->InitLegacySetupLocks(lock10, lock11_user, lock11_machine);
+  }
+
+  void PersistUpdateErrorInfo(bool is_machine,
+                              HRESULT error,
+                              int extra_code1,
+                              const CString& version) {
+    setup_->PersistUpdateErrorInfo(is_machine, error, extra_code1, version);
+  }
+
+  static bool HasXmlParser() { return Setup::HasXmlParser(); }
+
+  bool launched_offline_worker() { return setup_->launched_offline_worker_; }
+
+  void SetModeInstall() { setup_->mode_ = Setup::MODE_INSTALL; }
+  void SetModeSelfInstall() { setup_->mode_ = Setup::MODE_SELF_INSTALL; }
+  void SetModeSelfUpdate() { setup_->mode_ = Setup::MODE_SELF_UPDATE; }
+
+  // Uses DoInstall() instead of Install() as necessary to avoid the elevation
+  // check in Install().
+  HRESULT TestInstall() {
+    if (!is_machine_ || vista_util::IsUserAdmin()) {
+      return setup_->Install(_T("foo"));
+    } else {
+      setup_->mode_ = Setup::MODE_INSTALL;
+      return setup_->DoInstall();
+    }
+  }
+
+  // Acquires the Setup Lock in another thread then calls TestInstall().
+  void TestInstallWhileHoldingLock() {
+    HoldLock hold_lock(is_machine_);
+
+    Thread thread;
+    thread.Start(&hold_lock);
+    hold_lock.WaitForLockToBeAcquired();
+
+    EXPECT_EQ(GOOPDATE_E_FAILED_TO_GET_LOCK, TestInstall());
+
+    hold_lock.Stop();
+    thread.WaitTillExit(1000);
+  }
+
+  // Acquires the Setup Lock in another thread then calls DoInstall().
+  // Useful for testing modes other than MODE_INSTALL.
+  void TestDoInstallWhileHoldingLock() {
+    HoldLock hold_lock(is_machine_);
+
+    Thread thread;
+    thread.Start(&hold_lock);
+    hold_lock.WaitForLockToBeAcquired();
+
+    EXPECT_EQ(GOOPDATE_E_FAILED_TO_GET_LOCK, setup_->DoInstall());
+
+    hold_lock.Stop();
+    thread.WaitTillExit(1000);
+  }
+
+  void TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles() {
+    SetupFilesMockFailInstall setup_files_mock(is_machine_);
+
+    EXPECT_EQ(SetupFilesMockFailInstall::kExpetedError,
+              setup_->DoProtectedGoogleUpdateInstall(&setup_files_mock));
+  }
+
+  void StopGoogleUpdateAndWaitSucceedsTestHelper(bool use_job_objects_only) {
+    if (is_machine_ && !vista_util::IsUserAdmin()) {
+      std::wcout << _T("\tTest did not run because the user is not an admin.")
+                 << std::endl;
+      return;
+    }
+
+    // This test has been the most problematic, so do not run on build systems.
+    if (!ShouldRunLargeTest() || IsBuildSystem()) {
+      return;
+    }
+
+    scoped_process core_process;
+    scoped_process omaha_1_0_process;
+    scoped_process omaha_1_1_process;
+    scoped_process install_process;
+    scoped_process opposite_process;
+    scoped_process user_handoff_process;
+    scoped_process user_install_goopdate_process;
+    scoped_process user_install_needsadmin_process;
+    scoped_process setup_phase1_job_process;
+    scoped_process setup_phase1_job_opposite_process;
+    scoped_process install_job_opposite_process;
+    scoped_process silent_job_opposite_process;
+    scoped_process silent_do_not_kill_job_opposite_process;
+    scoped_job setup_phase1_job;
+    scoped_job setup_phase1_job_opposite;
+    scoped_job install_job_opposite;
+    scoped_job silent_job_opposite;
+    scoped_job silent_do_not_kill_job_opposite;
+
+    StartCoreProcessesToShutdown(address(core_process),
+                                 address(omaha_1_0_process),
+                                 address(omaha_1_1_process));
+    EXPECT_TRUE(core_process);
+    EXPECT_TRUE(omaha_1_0_process);
+    EXPECT_TRUE(omaha_1_1_process);
+
+    if (use_job_objects_only && is_machine_) {
+      // When starting the core process with psexec, there is a race condition
+      // between that process initializing (and joining a Job Object) and
+      // StopGoogleUpdateAndWait() looking for processes. If the latter wins,
+      // the core process is not found and StopGoogleUpdateAndWait() does not
+      // wait for the core process. As a result,
+      // ::WaitForSingleObject(get(core_process), 0)) would fail intermittently.
+      // Sleep here to allow the process to start and join the job.
+      // Note that this race condition is similar to ones we might encounter
+      // in the field when using Job Objects.
+      ::Sleep(500);
+    }
+
+    // /install is always ignored.
+    LaunchProcess(not_listening_exe_path_,
+                  _T("/install"),
+                  is_machine_,
+                  address(install_process));
+    EXPECT_TRUE(install_process);
+    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(install_process), 0));
+
+    if (vista_util::IsUserAdmin()) {
+      // Other users are usually ignored - use always ignored command line.
+      LaunchProcess(not_listening_exe_path_,
+                    _T(""),
+                    !is_machine_,
+                    address(opposite_process));
+      EXPECT_TRUE(opposite_process);
+      EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(opposite_process), 0));
+    } else {
+      EXPECT_FALSE(is_machine_)
+          << _T("Unexpected call for for machine when non-admin.");
+      // We can't launch a system process when non-admin.
+      std::wcout << _T("\tPart of this test did not run because the user is ")
+                    _T("not an admin.") << std::endl;
+    }
+
+    CString same_needsadmin = is_machine_ ? _T("\"needsadmin=True\"") :
+                                            _T("\"needsadmin=False\"");
+    CString opposite_needsadmin = is_machine_ ? _T("\"needsadmin=False\"") :
+                                                _T("\"needsadmin=True\"");
+    // Machine setup looks for users running /handoff and /ig with
+    // needsadmin=True and user setup ignores /handoff and /ig with
+    // needsadmin=True.
+    // Launching with needsadmin=<opposite> tests that machine ignores
+    // needsadmin=False and user ignores needsadmin=True.
+    LaunchProcess(not_listening_exe_path_,
+                  _T("/handoff ") + opposite_needsadmin,
+                  false,  // As the user.
+                  address(user_handoff_process));
+    EXPECT_TRUE(user_handoff_process);
+    EXPECT_EQ(WAIT_TIMEOUT,
+              ::WaitForSingleObject(get(user_handoff_process), 0));
+
+    LaunchProcess(not_listening_exe_path_,
+                  _T("/ig ") + opposite_needsadmin,
+                  false,  // As the user.
+                  address(user_install_goopdate_process));
+    EXPECT_TRUE(user_install_goopdate_process);
+    EXPECT_EQ(WAIT_TIMEOUT,
+              ::WaitForSingleObject(get(user_install_goopdate_process), 0));
+
+    // This process should be ignored even though it has needsadmin=<same>.
+    LaunchProcess(not_listening_exe_path_,
+                  _T("/install ") + same_needsadmin,
+                  false,  // As the user.
+                  address(user_install_needsadmin_process));
+    EXPECT_TRUE(user_install_goopdate_process);
+    EXPECT_EQ(WAIT_TIMEOUT,
+              ::WaitForSingleObject(get(user_install_goopdate_process), 0));
+
+    if (use_job_objects_only) {
+      // This Job Object is ignored.
+      // Only start this process when only using Job Objects because the
+      // argument-less process would be caught by the command line search.
+      LaunchJobProcess(is_machine_,
+                       is_machine_,
+                       kSetupPhase1NonSelfUpdateJobObject,
+                       address(setup_phase1_job_process),
+                       address(setup_phase1_job));
+      EXPECT_TRUE(setup_phase1_job_process);
+      EXPECT_EQ(WAIT_TIMEOUT,
+                ::WaitForSingleObject(get(setup_phase1_job_process), 0));
+    }
+
+    if (is_machine_ || vista_util::IsUserAdmin()) {
+      // These processes should be ignored because they are for the opposite
+      // set of processes.
+
+      LaunchJobProcess(!is_machine_,
+                       !is_machine_,
+                       kSetupPhase1NonSelfUpdateJobObject,
+                       address(setup_phase1_job_opposite_process),
+                       address(setup_phase1_job_opposite));
+      EXPECT_TRUE(setup_phase1_job_opposite_process);
+      EXPECT_EQ(WAIT_TIMEOUT,
+                ::WaitForSingleObject(get(setup_phase1_job_opposite_process),
+                                      0));
+
+      LaunchJobProcess(!is_machine_,
+                       !is_machine_,
+                       kAppInstallJobObject,
+                       address(install_job_opposite_process),
+                       address(install_job_opposite));
+      EXPECT_TRUE(install_job_opposite_process);
+      EXPECT_EQ(WAIT_TIMEOUT,
+                ::WaitForSingleObject(get(install_job_opposite_process), 0));
+
+      LaunchJobProcess(!is_machine_,
+                       !is_machine_,
+                       kSilentJobObject,
+                       address(silent_job_opposite_process),
+                       address(silent_job_opposite));
+      EXPECT_TRUE(install_job_opposite_process);
+      EXPECT_EQ(WAIT_TIMEOUT,
+                ::WaitForSingleObject(get(install_job_opposite_process), 0));
+
+      LaunchJobProcess(!is_machine_,
+                       !is_machine_,
+                       kSilentDoNotKillJobObject,
+                       address(silent_do_not_kill_job_opposite_process),
+                       address(silent_do_not_kill_job_opposite));
+      EXPECT_TRUE(install_job_opposite_process);
+      EXPECT_EQ(WAIT_TIMEOUT,
+                ::WaitForSingleObject(get(install_job_opposite_process), 0));
+    }
+
+    EXPECT_SUCCEEDED(StopGoogleUpdateAndWait());
+    EXPECT_EQ(0, setup_->extra_code1());
+
+    // Verify all real processes exited and terminate all the ones that aren't
+    // listening to shutdown.
+    HANDLE processes[] = {get(core_process),
+                          get(omaha_1_0_process),
+                          get(omaha_1_1_process)};
+    if (use_job_objects_only) {
+      // Since we only wait for processes in the Job Objects, legacy processes
+      // may not have stopped by the time StopGoogleUpdateAndWait() returns.
+      EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(core_process), 0));
+
+      // Now wait for the legacy processes to exit to avoid interfering with
+      // other tests.
+      EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(arraysize(processes),
+                                                        processes,
+                                                        true,  // wait for all
+                                                        8000));
+    } else {
+      EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(arraysize(processes),
+                                                        processes,
+                                                        true,  // wait for all
+                                                        0));
+    }
+
+    // Terminate all the processes and wait for them to exit to avoid
+    // interfering with other tests.
+    std::vector<HANDLE> started_processes;
+    started_processes.push_back(get(install_process));
+    if (vista_util::IsUserAdmin()) {
+      started_processes.push_back(get(opposite_process));
+    }
+    started_processes.push_back(get(user_handoff_process));
+    started_processes.push_back(get(user_install_goopdate_process));
+    started_processes.push_back(get(user_install_needsadmin_process));
+    if (use_job_objects_only) {
+      started_processes.push_back(get(setup_phase1_job_process));
+    }
+    if (is_machine_ || vista_util::IsUserAdmin()) {
+      started_processes.push_back(get(setup_phase1_job_opposite_process));
+      started_processes.push_back(get(install_job_opposite_process));
+      started_processes.push_back(get(silent_job_opposite_process));
+      started_processes.push_back(get(silent_do_not_kill_job_opposite_process));
+    }
+
+    for (size_t i = 0; i < started_processes.size(); ++i) {
+      EXPECT_TRUE(::TerminateProcess(started_processes[i], 1));
+    }
+    EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(started_processes.size(),
+                                                      &started_processes[0],
+                                                      true,  // wait for all
+                                                      kProcessesCleanupWait));
+  }
+
+  void StopGoogleUpdateAndWaitSucceedsTest() {
+    StopGoogleUpdateAndWaitSucceedsTestHelper(false);
+  }
+
+  HRESULT GetRunningCoreProcesses(Pids* core_processes) {
+    ASSERT1(core_processes);
+
+    CString user_sid_to_use;
+    if (is_machine_) {
+      user_sid_to_use = kLocalSystemSid;
+    } else {
+      EXPECT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &user_sid_to_use));
+    }
+
+    DWORD flags = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |
+                  EXCLUDE_CURRENT_PROCESS |
+                  INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
+
+    std::vector<CString> command_lines;
+    command_lines.push_back(_T("/c"));
+
+    return Process::FindProcesses(flags,
+                                  _T("GoogleUpdate.exe"),
+                                  true,
+                                  user_sid_to_use,
+                                  command_lines,
+                                  core_processes);
+  }
+
+  void KillRunningCoreProcesses() {
+    Pids core_processes;
+    EXPECT_SUCCEEDED(GetRunningCoreProcesses(&core_processes));
+
+    for (size_t i = 0; i < core_processes.size(); ++i) {
+      scoped_process process(::OpenProcess(PROCESS_TERMINATE,
+                                           FALSE,
+                                           core_processes[i]));
+      EXPECT_TRUE(process);
+      EXPECT_TRUE(::TerminateProcess(get(process), static_cast<uint32>(-2)));
+    }
+  }
+
+  // Uses psexec to start processes as SYSTEM if necessary.
+  // Assumes that psexec blocks until the process exits.
+  // TODO(omaha): Start the opposite instances and wait for them in
+  // StopGoogleUpdateAndWaitSucceedsTest. They should not close.
+  void StartCoreProcessesToShutdown(HANDLE* core_process,
+                                    HANDLE* omaha_1_0_process,
+                                    HANDLE* omaha_1_1_process) {
+    ASSERT_TRUE(core_process);
+    ASSERT_TRUE(omaha_1_0_process);
+    ASSERT_TRUE(omaha_1_1_process);
+
+    // Find the core process or start one if necessary.
+    Pids core_processes;
+    EXPECT_SUCCEEDED(GetRunningCoreProcesses(&core_processes));
+    ASSERT_LE(core_processes.size(), static_cast<size_t>(1))
+        << _T("Only one core should be running.");
+
+    if (core_processes.empty()) {
+      LaunchProcess(omaha_exe_path_,
+                    _T("/c"),
+                    is_machine_,
+                    core_process);
+    } else {
+      *core_process = ::OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE,
+                                    FALSE,
+                                    core_processes[0]);
+    }
+    ASSERT_TRUE(*core_process);
+
+    // Start the legacy versions.
+    LaunchProcess(omaha_10_exe_path_, _T(""), is_machine_, omaha_1_0_process);
+    LaunchProcess(omaha_11_exe_path_, _T(""), is_machine_, omaha_1_1_process);
+
+    HANDLE processes[] = {*core_process,
+                          *omaha_1_0_process,
+                          *omaha_1_1_process};
+    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForMultipleObjects(arraysize(processes),
+                                                     processes,
+                                                     true,  // wait for all
+                                                     0));
+  }
+
+  // Launches an instance of GoogleUpdate.exe that doesn't exit.
+  void StopGoogleUpdateAndWaitProcessesDoNotStopTest() {
+    LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(is_machine_,
+                                                   _T(""),
+                                                   COMMANDLINE_MODE_NOARGS);
+  }
+
+  void LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(
+      bool is_machine_process,
+      const CString& args,
+      CommandLineMode expected_running_process_mode) {
+    ASSERT_TRUE(args);
+
+    if (is_machine_ && !vista_util::IsUserAdmin()) {
+      std::wcout << _T("\tTest did not run because the user is not an admin.")
+                 << std::endl;
+      return;
+    }
+
+    if (!ShouldRunLargeTest()) {
+      return;
+    }
+    scoped_process process;
+    LaunchProcess(not_listening_exe_path_,
+                  args,
+                  is_machine_process,
+                  address(process));
+    EXPECT_TRUE(process);
+    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(process), 0));
+
+    // Tests that use this method intermittently fail when run on build systems.
+    // This code attempts to ensure that the process is further along in the
+    // initialization process by waiting until Process::GetCommandLine succeeds.
+    HRESULT hr = E_FAIL;
+    CString process_cmd;
+    for (int tries = 0; tries < 100 && FAILED(hr); ++tries) {
+      hr = Process::GetCommandLine(::GetProcessId(get(process)), &process_cmd);
+      if (FAILED(hr)) {
+        ::Sleep(50);
+      }
+    }
+    EXPECT_SUCCEEDED(hr);
+
+    EXPECT_EQ(GOOPDATE_E_INSTANCES_RUNNING, StopGoogleUpdateAndWait());
+    EXPECT_EQ(expected_running_process_mode, setup_->extra_code1());
+    // Make sure the process is still running to help debug failures.
+    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(process), 0));
+
+
+    EXPECT_TRUE(::TerminateProcess(get(process), 1));
+    EXPECT_EQ(WAIT_OBJECT_0,
+              ::WaitForSingleObject(get(process), kProcessesCleanupWait));
+  }
+
+  // If start using Job Objects again, make sure the test only uses Job Objects.
+  void LaunchProcessInJobAndExpectStopGoogleUpdateAndWaitTimesOut(
+      const CString& job_base_name,
+      bool machine_as_system) {
+    ASSERT_TRUE(is_machine_ || !machine_as_system);
+
+    if (!ShouldRunLargeTest()) {
+      return;
+    }
+
+
+    scoped_process process;
+    scoped_job job;
+
+    LaunchJobProcess(is_machine_,
+                     machine_as_system,
+                     job_base_name,
+                     address(process),
+                     address(job));
+    EXPECT_TRUE(process);
+    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(process), 0));
+
+    EXPECT_EQ(GOOPDATE_E_INSTANCES_RUNNING, StopGoogleUpdateAndWait());
+    EXPECT_EQ(COMMANDLINE_MODE_NOARGS, setup_->extra_code1());
+
+    EXPECT_TRUE(::TerminateProcess(get(process), 1));
+    EXPECT_EQ(WAIT_OBJECT_0,
+              ::WaitForSingleObject(get(process), kProcessesCleanupWait));
+  }
+
+  // Starts a core process for this user, a core for the opposite type of user,
+  // and a /cr process (similar command line to /c), and a process without args.
+  void TestTerminateCoreProcessesWithBothTypesRunningAndOtherProcesses() {
+    scoped_process core_process;
+    scoped_process opposite_core_process;
+    scoped_process codered_process;
+    scoped_process noargs_process;
+    LaunchProcess(not_listening_exe_path_,
+                  _T("/c"),
+                  is_machine_,
+                  address(core_process));
+    EXPECT_TRUE(core_process);
+    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(core_process), 0));
+    LaunchProcess(not_listening_exe_path_,
+                  _T("/c"),
+                  !is_machine_,
+                  address(opposite_core_process));
+    EXPECT_TRUE(opposite_core_process);
+    EXPECT_EQ(WAIT_TIMEOUT,
+              ::WaitForSingleObject(get(opposite_core_process), 0));
+    LaunchProcess(not_listening_exe_path_,
+                  _T("/cr"),
+                  is_machine_,
+                  address(codered_process));
+    EXPECT_TRUE(codered_process);
+    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(codered_process), 0));
+    LaunchProcess(not_listening_exe_path_,
+                  _T(""),
+                  is_machine_,
+                  address(noargs_process));
+    EXPECT_TRUE(noargs_process);
+    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(get(noargs_process), 0));
+
+    EXPECT_SUCCEEDED(TerminateCoreProcesses());
+
+    EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(core_process), 8000));
+    HANDLE ignored_processes[] = {get(opposite_core_process),
+                                  get(codered_process),
+                                  get(noargs_process)};
+    EXPECT_EQ(WAIT_TIMEOUT,
+              ::WaitForMultipleObjects(arraysize(ignored_processes),
+                                                 ignored_processes,
+                                                 false,  // wait for any
+                                                 1000));
+
+    HANDLE started_processes[] = {get(core_process),
+                                  get(opposite_core_process),
+                                  get(codered_process),
+                                  get(noargs_process)};
+    EXPECT_TRUE(::TerminateProcess(get(opposite_core_process), 1));
+    EXPECT_TRUE(::TerminateProcess(get(codered_process), 1));
+    EXPECT_TRUE(::TerminateProcess(get(noargs_process), 1));
+    EXPECT_EQ(WAIT_OBJECT_0,
+              ::WaitForMultipleObjects(arraysize(started_processes),
+                                                 started_processes,
+                                                 true,  // wait for all
+                                                 kProcessesCleanupWait));
+  }
+
+  // Sets the legacy setup locks then attempts to run setup with the legacy
+  // versions. When the lock is not held and a newer version is installed,
+  // the legacy executables do a handoff install and exit. Since we have
+  // acquired the locks, the legacy executables should wait and not exit.
+  // Check both after a second.
+  // If Omaha 1.2.x is not found, a fake version is installed to prevent the
+  // legacy installers from installing.
+  // When is_machine_ is true, the legacy installers will start the Service.
+  void AcquireLegacySetupLocksTest() {
+    if (is_machine_ && !vista_util::IsUserAdmin()) {
+      std::wcout << _T("\tTest did not run because the user is not an admin.")
+                 << std::endl;
+      return;
+    }
+
+    if (!ShouldRunLargeTest()) {
+      return;
+    }
+
+    CString omaha_clients_key_name = is_machine_ ?
+                                     MACHINE_REG_CLIENTS_GOOPDATE :
+                                     USER_REG_CLIENTS_GOOPDATE;
+    CString version;
+    if (FAILED(RegKey::GetValue(omaha_clients_key_name,
+                                _T("pv"),
+                                &version)) ||
+        (_T("1.2.") != version.Left(4))) {
+      // Fool the legacy instances into thinking a newer version is installed
+      // so that they don't try to install when we release the locks.
+      // Do not worry about restoring it because there is only a potential
+      // problem when running a legacy metainstaller after this test.
+      version = _T("1.2.0.654");
+      EXPECT_SUCCEEDED(RegKey::SetValue(omaha_clients_key_name,
+                                        _T("pv"),
+                                        version));
+    }
+
+    // Legacy installers check for the files and over-install if they are not
+    // found, so we copy files to the version directory.
+    CString install_dir = ConcatenatePath(
+        is_machine_ ?
+        ConfigManager::Instance()->GetMachineGoopdateInstallDir() :
+        ConfigManager::Instance()->GetUserGoopdateInstallDir(),
+        version);
+    EXPECT_SUCCEEDED(File::CopyTree(
+        ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                        _T("unittest_support\\omaha_1.2.x\\")),
+        install_dir,
+        false));
+
+    // This block of code reproduces what we do in Setup::DoInstall().
+    GLock lock10, lock11_user, lock11_machine;
+    EXPECT_TRUE(InitLegacySetupLocks(&lock10, &lock11_user, &lock11_machine));
+    EXPECT_TRUE(lock10.Lock(500));
+    EXPECT_TRUE(lock11_user.Lock(500));
+    if (is_machine_) {
+      EXPECT_TRUE(lock11_machine.Lock(500));
+    }
+
+    // Start the legacy processes, and verify that they are blocked.
+    scoped_process omaha_1_0_process;
+    scoped_process omaha_1_1_process;
+    scoped_process omaha_1_0_process_as_system;
+    scoped_process omaha_1_1_process_as_system;
+    LaunchProcess(omaha_10_exe_path_,
+                  _T("/install"),
+                  false,  // As the user.
+                  address(omaha_1_0_process));
+    LaunchProcess(omaha_11_exe_path_,
+                  _T("/update"),
+                  false,  // As the user.
+                  address(omaha_1_1_process));
+    if (is_machine_) {
+      // For the machine case, tests the legacy process running both as Local
+      // System and as the user.
+      LaunchProcess(omaha_10_exe_path_,
+                    _T("/install"),
+                    true,  // As Local System.
+                    address(omaha_1_0_process_as_system));
+      LaunchProcess(omaha_11_exe_path_,
+                    _T("/update"),
+                    true,  // As Local System.
+                    address(omaha_1_1_process_as_system));
+    }
+
+
+    HANDLE processes[] = {get(omaha_1_0_process),
+                          get(omaha_1_1_process),
+                          get(omaha_1_0_process_as_system),
+                          get(omaha_1_1_process_as_system)};
+    int num_processes = arraysize(processes) - (is_machine_ ? 0 : 2);
+    EXPECT_EQ(WAIT_TIMEOUT, ::WaitForMultipleObjects(num_processes,
+                                                     processes,
+                                                     false,  // wait for any
+                                                     1000));
+
+    // Release the locks and the legacy processes should exit
+    ASSERT_TRUE(lock10.Unlock());
+    ASSERT_TRUE(lock11_user.Unlock());
+    if (is_machine_) {
+      ASSERT_TRUE(lock11_machine.Unlock());
+    }
+
+    EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(num_processes,
+                                                      processes,
+                                                      true,  // wait for all
+                                                      kProcessesCleanupWait));
+  }
+
+  // Starts dummy process that doesn't exit and assigns it to the specified job.
+  // The handle returned by ShellExecute does not have PROCESS_SET_QUOTA access
+  // rights, so we get a new handle with the correct access rights to return to
+  // the caller.
+  void LaunchJobProcess(bool is_machine,
+                        bool as_system,
+                        const CString& job_base_name,
+                        HANDLE* process,
+                        HANDLE* job) {
+    ASSERT_TRUE(process);
+    ASSERT_TRUE(job);
+    ASSERT_TRUE(is_machine || !as_system);
+
+    scoped_process launched_process;
+    LaunchProcess(not_listening_exe_path_,
+                  _T(""),
+                  as_system,
+                  address(launched_process));
+    ASSERT_TRUE(launched_process);
+
+    *process = ::OpenProcess(PROCESS_ALL_ACCESS,
+                             false,
+                             ::GetProcessId(get(launched_process)));
+    ASSERT_TRUE(*process);
+
+    NamedObjectAttributes job_attr;
+    GetNamedObjectAttributes(job_base_name, is_machine, &job_attr);
+    *job = ::CreateJobObject(&job_attr.sa, job_attr.name);
+    ASSERT_TRUE(*job);
+
+    if (ERROR_ALREADY_EXISTS != ::GetLastError()) {
+      // Configure the newly created Job Object so it is compatible with any
+      // real processes that may be created.
+      JOBOBJECT_EXTENDED_LIMIT_INFORMATION extended_info = {0};
+
+      ASSERT_TRUE(::QueryInformationJobObject(
+                      *job,
+                      ::JobObjectExtendedLimitInformation,
+                      &extended_info,
+                      sizeof(extended_info),
+                      NULL)) <<
+          _T("Last Error: ") << ::GetLastError() << std::endl;
+
+      extended_info.BasicLimitInformation.LimitFlags =
+          JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
+      ASSERT_TRUE(::SetInformationJobObject(*job,
+                                            ::JobObjectExtendedLimitInformation,
+                                            &extended_info,
+                                            sizeof(extended_info))) <<
+          _T("Last Error: ") << ::GetLastError() << std::endl;
+    }
+
+    ASSERT_TRUE(::AssignProcessToJobObject(*job, *process)) <<
+        _T("Last Error: ") << ::GetLastError() << std::endl;
+  }
+
+  const bool is_machine_;
+  const CString omaha_path_;
+  scoped_ptr<omaha::Setup> setup_;
+  CommandLineArgs args_;
+
+  static CString omaha_exe_path_;
+  static CString omaha_10_exe_path_;
+  static CString omaha_11_exe_path_;
+  static CString not_listening_exe_path_;
+};
+
+CString SetupTest::omaha_exe_path_;
+CString SetupTest::omaha_10_exe_path_;
+CString SetupTest::omaha_11_exe_path_;
+CString SetupTest::not_listening_exe_path_;
+
+class SetupMachineTest : public SetupTest {
+ protected:
+  SetupMachineTest() : SetupTest(true) {
+  }
+
+  static void SetUpTestCase() {
+    // SeDebugPrivilege is required for elevated admins to open process open
+    // Local System processes with PROCESS_QUERY_INFORMATION access rights.
+    System::AdjustPrivilege(SE_DEBUG_NAME, true);
+
+    SetupTest::SetUpTestCase();
+  }
+};
+
+class SetupUserTest : public SetupTest {
+ protected:
+  SetupUserTest() : SetupTest(false) {
+  }
+};
+
+class SetupFutureVersionInstalledUserTest : public SetupUserTest {
+ protected:
+  SetupFutureVersionInstalledUserTest()
+      : SetupUserTest(),
+        future_version_path_(ConcatenatePath(omaha_path_,
+                                             kFutureVersionString)) {
+  }
+
+  virtual void SetUp() {
+    args_.extra_args_str = _T("\"appname=foo&lang=en\"");
+    CommandLineAppArgs app_args;
+    app_args.app_guid = StringToGuid(kAppGuid_);
+    args_.extra.apps.push_back(app_args);
+    SetupUserTest::SetUp();
+
+    // Save the existing version if present.
+    RegKey::GetValue(USER_REG_CLIENTS_GOOPDATE,
+                     kRegValueProductVersion,
+                     &existing_version_);
+    InstallFutureVersion();
+  }
+
+  virtual void TearDown() {
+    EXPECT_SUCCEEDED(DeleteDirectory(future_version_path_));
+    if (existing_version_.IsEmpty()) {
+      EXPECT_SUCCEEDED(RegKey::DeleteValue(USER_REG_CLIENTS_GOOPDATE,
+                                           kRegValueProductVersion));
+    } else {
+      EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                        kRegValueProductVersion,
+                                        existing_version_));
+    }
+
+    SetupUserTest::TearDown();
+  }
+
+  void InstallFutureVersion() {
+    DeleteDirectory(future_version_path_);
+    ASSERT_FALSE(File::IsDirectory(future_version_path_));
+
+    ASSERT_SUCCEEDED(CreateDir(future_version_path_, NULL));
+
+    ASSERT_SUCCEEDED(File::Copy(
+        ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                        _T("GoogleUpdate.exe")),
+        omaha_path_ + _T("GoogleUpdate.exe"),
+        false));
+
+    ASSERT_SUCCEEDED(File::Copy(
+        ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                        _T("goopdate.dll")),
+        ConcatenatePath(future_version_path_, _T("goopdate.dll")),
+        false));
+    ASSERT_SUCCEEDED(File::Copy(
+        ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                        _T("goopdateres_en.dll")),
+        ConcatenatePath(future_version_path_, _T("goopdateres_en.dll")),
+        false));
+
+    ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                      kRegValueProductVersion,
+                                      kFutureVersionString));
+  }
+
+  CString existing_version_;  // Saves the existing version from the registry.
+  const CString future_version_path_;
+  static const TCHAR* const kAppGuid_;
+};
+
+const TCHAR* const SetupFutureVersionInstalledUserTest::kAppGuid_ =
+    _T("{01D33078-BA95-4da6-A3FC-F31593FD4AA2}");
+
+class SetupRegistryProtectedUserTest : public SetupUserTest {
+ protected:
+  SetupRegistryProtectedUserTest()
+      : SetupUserTest(),
+        hive_override_key_name_(kRegistryHiveOverrideRoot) {
+  }
+
+  static void SetUpTestCase() {
+    this_version_ = GetVersionString();
+    expected_is_overinstall_ = !OFFICIAL_BUILD;
+#ifdef DEBUG
+    if (RegKey::HasValue(MACHINE_REG_UPDATE_DEV, kRegValueNameOverInstall)) {
+      DWORD value = 0;
+      EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE_DEV,
+                                        kRegValueNameOverInstall,
+                                        &value));
+      expected_is_overinstall_ = value != 0;
+    }
+#endif
+  }
+
+  virtual void SetUp() {
+    SetupUserTest::SetUp();
+
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    // Do not override HKLM because it contains the CSIDL_* definitions.
+    OverrideSpecifiedRegistryHives(hive_override_key_name_, false, true);
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+
+    SetupUserTest::TearDown();
+  }
+
+  const CString hive_override_key_name_;
+
+  static CString this_version_;
+  static bool expected_is_overinstall_;
+};
+
+CString SetupRegistryProtectedUserTest::this_version_;
+bool SetupRegistryProtectedUserTest::expected_is_overinstall_;
+
+class SetupRegistryProtectedMachineTest : public SetupMachineTest {
+ protected:
+  SetupRegistryProtectedMachineTest()
+      : SetupMachineTest(),
+        hive_override_key_name_(kRegistryHiveOverrideRoot) {
+  }
+
+  virtual void SetUp() {
+    SetupMachineTest::SetUp();
+
+    // Prime the cache of CSIDL_PROGRAM_FILES so it is available even after
+    // we override HKLM.
+    CString program_files_path;
+    EXPECT_SUCCEEDED(GetFolderPath(CSIDL_PROGRAM_FILES, &program_files_path));
+
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    OverrideRegistryHives(hive_override_key_name_);
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+
+    SetupMachineTest::TearDown();
+  }
+
+  const CString hive_override_key_name_;
+};
+
+class SetupOfflineInstallerTest : public testing::Test {
+ protected:
+  static bool CallCopyOfflineFiles(const CommandLineArgs& args,
+                                   const CString& target_location) {
+    omaha::Setup setup(false, &args);
+    return setup.CopyOfflineFiles(target_location);
+  }
+
+  static HRESULT CallCopyOfflineFilesForGuid(const CString& app_guid,
+                                             const CString& target_location) {
+    return omaha::Setup::CopyOfflineFilesForGuid(app_guid, target_location);
+  }
+};
+
+
+TEST_F(SetupFutureVersionInstalledUserTest, Install_HandoffWithShellMissing) {
+  CString shell_path = ConcatenatePath(omaha_path_, _T("GoogleUpdate.exe"));
+  ASSERT_TRUE(SUCCEEDED(File::DeleteAfterReboot(shell_path)) ||
+              !vista_util::IsUserAdmin());
+  ASSERT_FALSE(File::Exists(shell_path));
+
+  scoped_event ui_displayed_event;
+  ASSERT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(
+      kUiDisplayedEventEnvironmentVariableName,
+      is_machine_,
+      address(ui_displayed_event)));
+
+  EXPECT_EQ(GOOPDATE_E_HANDOFF_FAILED, setup_->Install(_T("/foo")));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), setup_->extra_code1());
+}
+
+TEST_F(SetupFutureVersionInstalledUserTest,
+       Install_HandoffWithGoopdateDllMissing) {
+  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));
+  ASSERT_SUCCEEDED(File::Remove(dll_path));
+  ASSERT_FALSE(File::Exists(dll_path));
+
+  scoped_event ui_displayed_event;
+  ASSERT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(
+      kUiDisplayedEventEnvironmentVariableName,
+      is_machine_,
+      address(ui_displayed_event)));
+
+  EXPECT_EQ(GOOPDATE_E_HANDOFF_FAILED, setup_->Install(_T("/foo")));
+  EXPECT_EQ(GOOGLEUPDATE_E_DLL_NOT_FOUND, setup_->extra_code1());
+}
+
+// The setup would cause a failure but we shouldn't see it because the event is
+// already signaled.
+// There is a race condition, especially on build machines, where the process
+// may have exited by the time we check for it and the event. Thus, there are
+// two expected cases.
+TEST_F(SetupFutureVersionInstalledUserTest,
+       Install_HandoffWithEventSignaledBeforeExit) {
+  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));
+  ASSERT_SUCCEEDED(File::Remove(dll_path));
+  ASSERT_FALSE(File::Exists(dll_path));
+
+  scoped_event ui_displayed_event;
+  ASSERT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(
+      kUiDisplayedEventEnvironmentVariableName,
+      is_machine_,
+      address(ui_displayed_event)));
+  ASSERT_TRUE(::SetEvent(get(ui_displayed_event)));
+
+  HRESULT hr = setup_->Install(_T("/foo"));
+  EXPECT_TRUE(SUCCEEDED(hr) || GOOPDATE_E_HANDOFF_FAILED == hr);
+  if (SUCCEEDED(hr)) {
+    EXPECT_EQ(0, setup_->extra_code1());
+
+    // There is a timing issue where GoogleUpdate.exe may not look at pv in the
+    // registry until after the existing_version_ has been restored to the
+    // registry. This causes GoogleUpdate.exe to find goopdate.dll in the
+    // existing_version_ and run with a UI. Wait so that this does not happen.
+#if OFFICIAL_BUILD
+    ::Sleep(8000);
+#else
+    ::Sleep(1000);
+#endif
+  } else {
+    EXPECT_EQ(GOOGLEUPDATE_E_DLL_NOT_FOUND, setup_->extra_code1());
+  }
+}
+
+// Silent installs ignore the event, so we should always get the exit code.
+// Also, exit code is reported directly instead of GOOPDATE_E_HANDOFF_FAILED.
+TEST_F(SetupFutureVersionInstalledUserTest,
+       Install_SilentHandoffWithEventSignaledBeforeExit) {
+  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));
+  ASSERT_SUCCEEDED(File::Remove(dll_path));
+  ASSERT_FALSE(File::Exists(dll_path));
+
+  scoped_event ui_displayed_event;
+  ASSERT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(
+      kUiDisplayedEventEnvironmentVariableName,
+      is_machine_,
+      address(ui_displayed_event)));
+  ASSERT_TRUE(::SetEvent(get(ui_displayed_event)));
+
+  args_.is_silent_set = true;
+  EXPECT_EQ(GOOGLEUPDATE_E_DLL_NOT_FOUND, setup_->Install(_T("/foo")));
+  EXPECT_EQ(0, setup_->extra_code1());
+}
+
+// Offline installs ignore the event regardless of whether they are silent, so
+// we should always get the exit code.
+// Also, exit code is reported directly instead of GOOPDATE_E_HANDOFF_FAILED.
+TEST_F(SetupFutureVersionInstalledUserTest,
+       Install_InteractiveOfflineHandoffWithEventSignaledBeforeExit) {
+  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));
+  ASSERT_SUCCEEDED(File::Remove(dll_path));
+  ASSERT_FALSE(File::Exists(dll_path));
+
+  scoped_event ui_displayed_event;
+  ASSERT_SUCCEEDED(goopdate_utils::CreateUniqueEventInEnvironment(
+      kUiDisplayedEventEnvironmentVariableName,
+      is_machine_,
+      address(ui_displayed_event)));
+  ASSERT_TRUE(::SetEvent(get(ui_displayed_event)));
+
+  // Make Setup think this is an offline install.
+  CString manifest_path;
+  manifest_path.Format(_T("%s\\%s.gup"),
+                           app_util::GetCurrentModuleDirectory(),
+                           kAppGuid_);
+  File manifest_file;
+  ASSERT_SUCCEEDED(manifest_file.Open(manifest_path, true, false));
+  ASSERT_SUCCEEDED(manifest_file.Touch());
+  ASSERT_SUCCEEDED(manifest_file.Close());
+
+  CString installer_path;
+  installer_path.Format(_T("%s\\unittest_installer.exe.%s"),
+                            app_util::GetCurrentModuleDirectory(),
+                            kAppGuid_);
+  File installer_file;
+  EXPECT_SUCCEEDED(installer_file.Open(installer_path, true, false));
+  EXPECT_SUCCEEDED(installer_file.Touch());
+  EXPECT_SUCCEEDED(installer_file.Close());
+
+  EXPECT_EQ(GOOGLEUPDATE_E_DLL_NOT_FOUND, setup_->Install(_T("/foo")));
+  EXPECT_EQ(0, setup_->extra_code1());
+
+  EXPECT_FALSE(args_.is_silent_set);  // Ensure not silent as voids this test.
+  EXPECT_TRUE(launched_offline_worker());
+
+  EXPECT_TRUE(::DeleteFile(manifest_path));
+  EXPECT_TRUE(::DeleteFile(installer_path));
+}
+
+TEST_F(SetupFutureVersionInstalledUserTest,
+       InstallSelfSilently_NoRunKey) {
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideSpecifiedRegistryHives(kRegistryHiveOverrideRoot, false, true);
+
+  // Write the future version to the override registry.
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    kFutureVersionString));
+
+  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));
+  ASSERT_SUCCEEDED(File::Remove(dll_path));
+  ASSERT_FALSE(File::Exists(dll_path));
+
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            setup_->InstallSelfSilently());
+  EXPECT_EQ(0, setup_->extra_code1());
+
+  RestoreRegistryHives();
+  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+TEST_F(SetupFutureVersionInstalledUserTest,
+       InstallSelfSilently_ValidRunKey) {
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideSpecifiedRegistryHives(kRegistryHiveOverrideRoot, false, true);
+
+  // Write the future version to the override registry.
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    kFutureVersionString));
+
+  const TCHAR kRunKey[] =
+      _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");
+  const CString shell_path = ConcatenatePath(GetGoogleUpdateUserPath(),
+                                             _T("GoogleUpdate.exe"));
+  CString run_value;
+  run_value.Format(_T("\"%s\" /just_exit"), shell_path);
+  ASSERT_SUCCEEDED(RegKey::SetValue(kRunKey, _T("Google Update"), run_value));
+
+  CString dll_path = ConcatenatePath(future_version_path_, _T("goopdate.dll"));
+  ASSERT_SUCCEEDED(File::Remove(dll_path));
+  ASSERT_FALSE(File::Exists(dll_path));
+
+  EXPECT_SUCCEEDED(setup_->InstallSelfSilently());
+  EXPECT_EQ(0, setup_->extra_code1());
+
+  RestoreRegistryHives();
+  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+TEST_F(SetupUserTest, HasXmlParser) {
+  EXPECT_TRUE(HasXmlParser());
+}
+
+TEST_F(SetupUserTest, Install_LockTimedOut) {
+  TestInstallWhileHoldingLock();
+}
+
+TEST_F(SetupMachineTest, Install_LockTimedOut) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  TestInstallWhileHoldingLock();
+}
+
+TEST_F(SetupRegistryProtectedUserTest, Install_OEM) {
+  // The test fixture only disables HKCU by default. Disable HKLM too.
+  OverrideSpecifiedRegistryHives(hive_override_key_name_, true, true);
+
+  if (vista_util::IsVistaOrLater()) {
+    ASSERT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    ASSERT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  ASSERT_TRUE(ConfigManager::Instance()->IsWindowsInstalling());
+
+  args_.is_oem_set = true;
+  EXPECT_EQ(GOOPDATE_E_OEM_NOT_MACHINE_AND_PRIVILEGED_AND_AUDIT_MODE,
+            setup_->Install(_T("foo")));
+
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, kRegValueOemInstallTimeSec));
+  EXPECT_FALSE(
+      RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueOemInstallTimeSec));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest, Install_OemElevationRequired) {
+  if (vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user IS an admin.")
+               << std::endl;
+    return;
+  }
+
+  if (vista_util::IsVistaOrLater()) {
+    ASSERT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    ASSERT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  ASSERT_TRUE(ConfigManager::Instance()->IsWindowsInstalling());
+
+  args_.is_oem_set = true;
+  EXPECT_EQ(GOOPDATE_E_OEM_NOT_MACHINE_AND_PRIVILEGED_AND_AUDIT_MODE,
+            setup_->Install(_T("foo")));
+
+  EXPECT_FALSE(
+      RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueOemInstallTimeSec));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest, Install_OemNotAuditMode) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  args_.is_oem_set = true;
+  EXPECT_EQ(GOOPDATE_E_OEM_NOT_MACHINE_AND_PRIVILEGED_AND_AUDIT_MODE,
+            setup_->Install(_T("foo")));
+  EXPECT_FALSE(
+      RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueOemInstallTimeSec));
+}
+
+// Prevents the install from continuing by holding the Setup Lock.
+TEST_F(SetupRegistryProtectedMachineTest, Install_OemFails) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  if (vista_util::IsVistaOrLater()) {
+    ASSERT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+
+    // TODO(omaha): Overriding HKLM causes HasXmlParser() to fail on Vista,
+    // preventing this test from running correctly.
+    return;
+  } else {
+    ASSERT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+  ASSERT_TRUE(ConfigManager::Instance()->IsWindowsInstalling());
+
+  HoldLock hold_lock(is_machine_);
+  Thread thread;
+  thread.Start(&hold_lock);
+  hold_lock.WaitForLockToBeAcquired();
+
+  args_.is_oem_set = true;
+  EXPECT_EQ(GOOPDATE_E_FAILED_TO_GET_LOCK, setup_->Install(_T("foo")));
+
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueMachineId));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueUserId));
+  EXPECT_TRUE(
+      RegKey::HasValue(MACHINE_REG_UPDATE, kRegValueOemInstallTimeSec));
+
+  hold_lock.Stop();
+  thread.WaitTillExit(1000);
+}
+
+TEST_F(SetupMachineTest, LaunchInstalledWorker_OemInstallNotOffline) {
+  SetModeInstall();
+  CommandLineAppArgs app1;
+  args_.extra.apps.push_back(app1);
+  args_.is_oem_set = true;
+  EXPECT_EQ(GOOPDATE_E_OEM_WITH_ONLINE_INSTALLER,
+            LaunchInstalledWorker(true, NULL));
+}
+
+TEST_F(SetupMachineTest, LaunchInstalledWorker_OemUpdateNotOffline) {
+  SetModeSelfUpdate();
+  args_.is_oem_set = true;
+  ExpectAsserts expect_asserts;
+  EXPECT_EQ(GOOPDATE_E_OEM_WITH_ONLINE_INSTALLER,
+            LaunchInstalledWorker(true, NULL));
+}
+
+TEST_F(SetupMachineTest, LaunchInstalledWorker_EulaRequiredNotOffline) {
+  SetModeInstall();
+  CommandLineAppArgs app1;
+  args_.extra.apps.push_back(app1);
+  args_.is_eula_required_set = true;
+  EXPECT_EQ(GOOPDATE_E_EULA_REQURED_WITH_ONLINE_INSTALLER,
+            LaunchInstalledWorker(true, NULL));
+}
+
+TEST_F(SetupUserTest, LaunchInstalledWorker_EulaRequiredNotOffline) {
+  SetModeInstall();
+  CommandLineAppArgs app1;
+  args_.extra.apps.push_back(app1);
+  args_.is_eula_required_set = true;
+  EXPECT_EQ(GOOPDATE_E_EULA_REQURED_WITH_ONLINE_INSTALLER,
+            LaunchInstalledWorker(true, NULL));
+}
+
+//
+// ShouldInstall tests.
+//
+
+TEST_F(SetupRegistryProtectedUserTest, ShouldInstall_NewerVersion) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    _T("1.0.3.4")));
+  EXPECT_TRUE(ShouldInstall());
+}
+
+TEST_F(SetupRegistryProtectedUserTest, ShouldInstall_OlderVersion) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    _T("9.8.7.6")));
+  EXPECT_FALSE(ShouldInstall());
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ShouldInstall_SameVersionFilesMissingSameLanguage) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueInstalledVersion,
+                                    this_version_));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+  ASSERT_SUCCEEDED(
+      DeleteDirectory(ConcatenatePath(omaha_path_, this_version_)));
+  CString file_path = ConcatenatePath(
+                          ConcatenatePath(omaha_path_, this_version_),
+                          _T("goopdate.dll"));
+  ASSERT_FALSE(File::Exists(file_path));
+
+  EXPECT_TRUE(ShouldInstall());
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ShouldInstall_SameVersionFilesPresentSameLanguage) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueInstalledVersion,
+                                    this_version_));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+
+  EXPECT_EQ(expected_is_overinstall_, ShouldInstall());
+
+  if (ShouldRunLargeTest()) {
+    // Override OverInstall to test official behavior on non-official builds.
+
+    DWORD existing_overinstall(0);
+    bool had_existing_overinstall = SUCCEEDED(RegKey::GetValue(
+                                                  MACHINE_REG_UPDATE_DEV,
+                                                  kRegValueNameOverInstall,
+                                                  &existing_overinstall));
+
+    EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                      kRegValueNameOverInstall,
+                                      static_cast<DWORD>(0)));
+#ifdef DEBUG
+    EXPECT_FALSE(ShouldInstall());
+#else
+    EXPECT_EQ(expected_is_overinstall_, ShouldInstall());
+#endif
+
+    // Restore "overinstall"
+    if (had_existing_overinstall) {
+      EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                        kRegValueNameOverInstall,
+                                        existing_overinstall));
+    } else {
+      EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,
+                                           kRegValueNameOverInstall));
+    }
+  }
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ShouldInstall_SameVersionFilesPresentSameLanguageMissingInstalledVer) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+
+  EXPECT_TRUE(ShouldInstall());
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ShouldInstall_SameVersionFilesPresentSameLanguageNewerInstalledVer) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueInstalledVersion,
+                                    kRegValueInstalledVersion));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+
+  EXPECT_TRUE(ShouldInstall());
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ShouldInstall_SameVersionFilesPresentDifferentLanguage) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueInstalledVersion,
+                                    this_version_));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+
+  EXPECT_EQ(expected_is_overinstall_, ShouldInstall());
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ShouldInstall_SameVersionFilesPresentNoLanguage) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueInstalledVersion,
+                                    this_version_));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+
+  EXPECT_EQ(expected_is_overinstall_, ShouldInstall());
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ShouldInstall_SameVersionRequiredFileMissing) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueInstalledVersion,
+                                    this_version_));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+  CString path = ConcatenatePath(ConcatenatePath(omaha_path_, this_version_),
+                                 _T("goopdate.dll"));
+  ASSERT_SUCCEEDED(File::Remove(path));
+  ASSERT_FALSE(File::Exists(path));
+
+  EXPECT_TRUE(ShouldInstall());
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ShouldInstall_SameVersionOptionalFileMissing) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueInstalledVersion,
+                                    this_version_));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+  CString path = ConcatenatePath(ConcatenatePath(omaha_path_, this_version_),
+                                 _T("GoopdateBho.dll"));
+  ASSERT_SUCCEEDED(File::Remove(path));
+  ASSERT_FALSE(File::Exists(path));
+
+  EXPECT_TRUE(ShouldInstall());
+}
+
+TEST_F(SetupRegistryProtectedUserTest, ShouldInstall_SameVersionShellMissing) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueInstalledVersion,
+                                    this_version_));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    this_version_));
+
+  CopyGoopdateFiles(omaha_path_, this_version_);
+  CString shell_path = ConcatenatePath(omaha_path_, _T("GoogleUpdate.exe"));
+  ASSERT_TRUE(SUCCEEDED(File::DeleteAfterReboot(shell_path)) ||
+              !vista_util::IsUserAdmin());
+  ASSERT_FALSE(File::Exists(shell_path));
+
+  EXPECT_TRUE(ShouldInstall());
+}
+
+TEST_F(SetupRegistryProtectedUserTest, ShouldInstall_NewerVersionShellMissing) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueInstalledVersion,
+                                    this_version_));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    kFutureVersionString));
+
+  CopyGoopdateFiles(omaha_path_, kFutureVersionString);
+  CString shell_path = ConcatenatePath(omaha_path_, _T("GoogleUpdate.exe"));
+  ASSERT_TRUE(SUCCEEDED(File::DeleteAfterReboot(shell_path)) ||
+              !vista_util::IsUserAdmin());
+  ASSERT_FALSE(File::Exists(shell_path));
+
+  EXPECT_FALSE(ShouldInstall());
+
+  EXPECT_SUCCEEDED(
+      DeleteDirectory(ConcatenatePath(omaha_path_, kFutureVersionString)));
+}
+
+//
+// StopGoogleUpdateAndWait tests.
+//
+// These are "large" tests.
+// They kill currently running GoogleUpdate processes, including the core, owned
+// by the current user or SYSTEM.
+// A core may already be running, so if a core process is found, it is used for
+// the tests. Otherwise, they launch a core from a previous build.
+// Using a previous build ensures that the shutdown event hasn't changed.
+// There is no test directly that this version can shutdown itself, but that is
+// much less likely to break.
+// The tests also start 1.0.x and 1.1.x legacy instances.
+// The Succeeds tests will fail if any processes that don't listen to the
+// shutdown event are running.
+//
+
+TEST_F(SetupUserTest, StopGoogleUpdateAndWait_Succeeds) {
+  StopGoogleUpdateAndWaitSucceedsTest();
+}
+
+TEST_F(SetupMachineTest, StopGoogleUpdateAndWait_Succeeds) {
+  StopGoogleUpdateAndWaitSucceedsTest();
+}
+
+// TODO(omaha): If start using Job Objects again, enable these tests.
+/*
+TEST_F(SetupUserTest, StopGoogleUpdateAndWait_SucceedsUsingOnlyJobObjects) {
+  StopGoogleUpdateAndWaitWithProcessSearchDisabledSucceedsTest();
+}
+
+TEST_F(SetupMachineTest, StopGoogleUpdateAndWait_SucceedsUsingOnlyJobObjects) {
+  StopGoogleUpdateAndWaitWithProcessSearchDisabledSucceedsTest();
+}
+*/
+
+TEST_F(SetupUserTest, StopGoogleUpdateAndWait_ProcessesDoNotStop) {
+  StopGoogleUpdateAndWaitProcessesDoNotStopTest();
+}
+
+TEST_F(SetupMachineTest, StopGoogleUpdateAndWait_ProcessesDoNotStop) {
+  StopGoogleUpdateAndWaitProcessesDoNotStopTest();
+}
+
+TEST_F(SetupMachineTest,
+       StopGoogleUpdateAndWait_MachineHandoffWorkerRunningAsUser) {
+  LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(
+      false,
+      _T("/handoff \"needsadmin=True\""),
+      COMMANDLINE_MODE_HANDOFF_INSTALL);
+}
+
+TEST_F(SetupMachineTest,
+       StopGoogleUpdateAndWait_MachineInstallGoogleUpdateWorkerRunningAsUser) {
+  LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(
+      false,
+      _T("/ig \"needsadmin=True\""),
+      COMMANDLINE_MODE_IG);
+}
+
+TEST_F(SetupMachineTest,
+       StopGoogleUpdateAndWait_UserHandoffWorkerRunningAsSystem) {
+  LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(
+      true,
+      _T("/handoff \"needsadmin=False\""),
+      COMMANDLINE_MODE_HANDOFF_INSTALL);
+}
+
+TEST_F(SetupMachineTest,
+       StopGoogleUpdateAndWait_UserInstallGoogleUpdateWorkerRunningAsSystem) {
+  LaunchProcessAndExpectStopGoogleUpdateAndWaitTimesOut(
+      true,
+      _T("/ig \"needsadmin=False\""),
+      COMMANDLINE_MODE_IG);
+}
+
+TEST_F(SetupUserTest, TerminateCoreProcesses_NoneRunning) {
+  KillRunningCoreProcesses();
+
+  EXPECT_SUCCEEDED(TerminateCoreProcesses());
+}
+
+TEST_F(SetupUserTest,
+       TerminateCoreProcesses_BothTypesRunningAndSimilarArgsProcess) {
+  TestTerminateCoreProcessesWithBothTypesRunningAndOtherProcesses();
+}
+
+TEST_F(SetupMachineTest, TerminateCoreProcesses_NoneRunning) {
+  KillRunningCoreProcesses();
+
+  EXPECT_SUCCEEDED(TerminateCoreProcesses());
+}
+
+TEST_F(SetupMachineTest,
+       TerminateCoreProcesses_BothTypesRunningAndSimilarArgsProcess) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+}
+  TestTerminateCoreProcessesWithBothTypesRunningAndOtherProcesses();
+}
+
+TEST_F(SetupUserTest, AcquireLegacySetupLocks_LegacyExesWait) {
+  AcquireLegacySetupLocksTest();
+}
+
+TEST_F(SetupMachineTest, AcquireLegacySetupLocks_LegacyExesWait) {
+  AcquireLegacySetupLocksTest();
+}
+
+TEST_F(SetupRegistryProtectedUserTest, PersistUpdateErrorInfo) {
+  PersistUpdateErrorInfo(is_machine_, 0x98765432, 77, _T("1.2.3.4"));
+
+  DWORD value(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE,
+                                    kRegValueSelfUpdateErrorCode,
+                                    &value));
+  EXPECT_EQ(0x98765432, value);
+
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE,
+                                    kRegValueSelfUpdateExtraCode1,
+                                    &value));
+  EXPECT_EQ(77, value);
+
+  CString version;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_UPDATE,
+                                    kRegValueSelfUpdateVersion,
+                                    &version));
+  EXPECT_FALSE(version.IsEmpty());
+  EXPECT_STREQ(_T("1.2.3.4"), version);
+}
+
+TEST_F(SetupRegistryProtectedMachineTest, PersistUpdateErrorInfo) {
+  PersistUpdateErrorInfo(is_machine_, 0x98765430, 0x12345678, _T("2.3.4.5"));
+
+  DWORD value(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateErrorCode,
+                                    &value));
+  EXPECT_EQ(0x98765430, value);
+
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateExtraCode1,
+                                    &value));
+  EXPECT_EQ(0x12345678, value);
+
+  CString version;
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateVersion,
+                                    &version));
+  EXPECT_FALSE(version.IsEmpty());
+  EXPECT_STREQ(_T("2.3.4.5"), version);
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ReadAndClearUpdateErrorInfo_KeyDoesNotExist) {
+  DWORD self_update_error_code(0);
+  DWORD self_update_extra_code1(0);
+  CString self_update_version;
+  ExpectAsserts expect_asserts;
+  EXPECT_FALSE(Setup::ReadAndClearUpdateErrorInfo(false,
+                                                  &self_update_error_code,
+                                                  &self_update_extra_code1,
+                                                  &self_update_version));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       ReadAndClearUpdateErrorInfo_KeyDoesNotExist) {
+  DWORD self_update_error_code(0);
+  DWORD self_update_extra_code1(0);
+  CString self_update_version;
+  ExpectAsserts expect_asserts;
+  EXPECT_FALSE(Setup::ReadAndClearUpdateErrorInfo(true,
+                                                  &self_update_error_code,
+                                                  &self_update_extra_code1,
+                                                  &self_update_version));
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ReadAndClearUpdateErrorInfo_UpdateErrorCodeDoesNotExist) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));
+  DWORD self_update_error_code(0);
+  DWORD self_update_extra_code1(0);
+  CString self_update_version;
+  EXPECT_FALSE(Setup::ReadAndClearUpdateErrorInfo(false,
+                                                  &self_update_error_code,
+                                                  &self_update_extra_code1,
+                                                  &self_update_version));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       ReadAndClearUpdateErrorInfo_UpdateErrorCodeDoesNotExist) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));
+  DWORD self_update_error_code(0);
+  DWORD self_update_extra_code1(0);
+  CString self_update_version;
+  EXPECT_FALSE(Setup::ReadAndClearUpdateErrorInfo(true,
+                                                  &self_update_error_code,
+                                                  &self_update_extra_code1,
+                                                  &self_update_version));
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ReadAndClearUpdateErrorInfo_AllValuesPresent) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueSelfUpdateErrorCode,
+                                    static_cast<DWORD>(0x87654321)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueSelfUpdateExtraCode1,
+                                    static_cast<DWORD>(55)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueSelfUpdateVersion,
+                                    _T("0.2.4.8")));
+
+  DWORD self_update_error_code(0);
+  DWORD self_update_extra_code1(0);
+  CString self_update_version;
+  EXPECT_TRUE(Setup::ReadAndClearUpdateErrorInfo(false,
+                                                 &self_update_error_code,
+                                                 &self_update_extra_code1,
+                                                 &self_update_version));
+
+  EXPECT_EQ(0x87654321, self_update_error_code);
+  EXPECT_EQ(55, self_update_extra_code1);
+  EXPECT_STREQ(_T("0.2.4.8"), self_update_version);
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       ReadAndClearUpdateErrorInfo_AllValuesPresent) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateErrorCode,
+                                    static_cast<DWORD>(0x87654321)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateExtraCode1,
+                                    static_cast<DWORD>(55)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateVersion,
+                                    _T("0.2.4.8")));
+
+  DWORD self_update_error_code(0);
+  DWORD self_update_extra_code1(0);
+  CString self_update_version;
+  EXPECT_TRUE(Setup::ReadAndClearUpdateErrorInfo(true,
+                                                 &self_update_error_code,
+                                                 &self_update_extra_code1,
+                                                 &self_update_version));
+
+  EXPECT_EQ(0x87654321, self_update_error_code);
+  EXPECT_EQ(55, self_update_extra_code1);
+  EXPECT_STREQ(_T("0.2.4.8"), self_update_version);
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       ReadAndClearUpdateErrorInfo_ValuesPresentInMachineOnly) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateErrorCode,
+                                    static_cast<DWORD>(0x87654321)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateExtraCode1,
+                                    static_cast<DWORD>(55)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateVersion,
+                                    _T("0.2.4.8")));
+
+  DWORD self_update_error_code(0);
+  DWORD self_update_extra_code1(0);
+  CString self_update_version;
+  ExpectAsserts expect_asserts;
+  EXPECT_FALSE(Setup::ReadAndClearUpdateErrorInfo(false,
+                                                  &self_update_error_code,
+                                                  &self_update_extra_code1,
+                                                  &self_update_version));
+  // Clean up HKLM, which isn't overridden.
+  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,
+                                       kRegValueSelfUpdateErrorCode));
+  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,
+                                       kRegValueSelfUpdateExtraCode1));
+  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,
+                                       kRegValueSelfUpdateVersion));
+}
+
+TEST_F(SetupOfflineInstallerTest, ValidOfflineInstaller) {
+  CString guid_string = _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");
+
+  CString offline_manifest_path(guid_string);
+  offline_manifest_path += _T(".gup");
+  offline_manifest_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                          offline_manifest_path);
+  ASSERT_SUCCEEDED(File::Copy(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("server_manifest_one_app.xml")),
+      offline_manifest_path,
+      false));
+
+  CString installer_exe = _T("foo_installer.exe");
+  CString tarred_installer_path;
+  tarred_installer_path.Format(_T("%s.%s"), installer_exe, guid_string);
+  tarred_installer_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                          tarred_installer_path);
+
+  ASSERT_SUCCEEDED(File::Copy(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("GoogleUpdate.exe")),
+      tarred_installer_path,
+      false));
+
+  CommandLineArgs args;
+  CommandLineAppArgs app1;
+  app1.app_guid = StringToGuid(guid_string);
+  args.extra.apps.push_back(app1);
+  CString target_location = ConcatenatePath(
+                                app_util::GetCurrentModuleDirectory(),
+                                _T("offline_test"));
+
+  ASSERT_TRUE(CallCopyOfflineFiles(args, target_location));
+
+  CString target_manifest = ConcatenatePath(target_location,
+                                            guid_string + _T(".gup"));
+  EXPECT_TRUE(File::Exists(target_manifest));
+  CString target_file = ConcatenatePath(
+      ConcatenatePath(target_location, guid_string), installer_exe);
+  EXPECT_TRUE(File::Exists(target_file));
+
+  EXPECT_SUCCEEDED(DeleteDirectory(target_location));
+  EXPECT_SUCCEEDED(File::Remove(tarred_installer_path));
+  EXPECT_SUCCEEDED(File::Remove(offline_manifest_path));
+}
+
+TEST_F(SetupOfflineInstallerTest, NoOfflineInstaller) {
+  CString guid_string = _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");
+  CommandLineArgs args;
+  CommandLineAppArgs app1;
+  app1.app_guid = StringToGuid(guid_string);
+  args.extra.apps.push_back(app1);
+  CString target_location = ConcatenatePath(
+                                app_util::GetCurrentModuleDirectory(),
+                                _T("offline_test"));
+
+  EXPECT_FALSE(CallCopyOfflineFiles(args, target_location));
+}
+
+TEST_F(SetupOfflineInstallerTest, ValidCopyOfflineFilesForGuid) {
+  CString guid_string = _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");
+
+  CString offline_manifest_path(guid_string);
+  offline_manifest_path += _T(".gup");
+  offline_manifest_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                          offline_manifest_path);
+  ASSERT_SUCCEEDED(File::Copy(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("server_manifest_one_app.xml")),
+      offline_manifest_path,
+      false));
+
+  CString installer_exe = _T("foo_installer.exe");
+  CString tarred_installer_path;
+  tarred_installer_path.Format(_T("%s.%s"), installer_exe, guid_string);
+  tarred_installer_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                          tarred_installer_path);
+
+  ASSERT_SUCCEEDED(File::Copy(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("GoogleUpdate.exe")),
+      tarred_installer_path,
+      false));
+
+  CString target_location = ConcatenatePath(
+                                app_util::GetCurrentModuleDirectory(),
+                                _T("offline_test"));
+
+  ASSERT_SUCCEEDED(CallCopyOfflineFilesForGuid(guid_string, target_location));
+
+  CString target_manifest = ConcatenatePath(target_location,
+                                            guid_string + _T(".gup"));
+  EXPECT_TRUE(File::Exists(target_manifest));
+  CString target_file = ConcatenatePath(
+      ConcatenatePath(target_location, guid_string), installer_exe);
+  EXPECT_TRUE(File::Exists(target_file));
+
+  EXPECT_SUCCEEDED(DeleteDirectory(target_location));
+  EXPECT_SUCCEEDED(File::Remove(tarred_installer_path));
+  EXPECT_SUCCEEDED(File::Remove(offline_manifest_path));
+}
+
+TEST_F(SetupOfflineInstallerTest, NoCopyOfflineFilesForGuid) {
+  CString guid_string = _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");
+  CString target_location = ConcatenatePath(
+                                app_util::GetCurrentModuleDirectory(),
+                                _T("offline_test"));
+
+  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            CallCopyOfflineFilesForGuid(guid_string, target_location));
+}
+
+// A few tests for the public method. The bulk of the EULA cases are covered by
+// Install() and DoProtectedGoogleUpdateInstall() tests.
+TEST_F(SetupRegistryProtectedMachineTest, SetEulaAccepted_KeyDoesNotExist) {
+  EXPECT_EQ(S_OK, Setup::SetEulaAccepted(true));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest, SetEulaAccepted_ValueDoesNotExist) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));
+  EXPECT_EQ(S_FALSE, Setup::SetEulaAccepted(true));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest, SetEulaAccepted_ExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_SUCCEEDED(Setup::SetEulaAccepted(true));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+
+  // ClientState for Google Update (never used) and other apps is not affected.
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(SetupRegistryProtectedUserTest, SetEulaAccepted_KeyDoesNotExist) {
+  EXPECT_EQ(S_OK, Setup::SetEulaAccepted(false));
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedUserTest, SetEulaAccepted_ValueDoesNotExist) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));
+  EXPECT_EQ(S_FALSE, Setup::SetEulaAccepted(false));
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedUserTest, SetEulaAccepted_ExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_SUCCEEDED(Setup::SetEulaAccepted(false));
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+
+  // ClientState for Google Update (never used) and other apps is not affected.
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStatePath,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       Install_EulaNotRequired_UpdateKeyDoesNotExist) {
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       Install_EulaNotRequired_EulaValueDoesNotExist) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       Install_EulaNotRequired_EulaValueExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+
+  // ClientState for Google Update (never used) and other apps is not affected.
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       Install_EulaNotRequired_EulaValueExistsOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       Install_EulaNotRequired_EulaValueExistsOther) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(8000)));
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       Install_EulaNotRequired_EulaValueExistsString) {
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), _T("0")));
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       Install_EulaNotRequired_EulaValueDoesNotExistAlreadyInstalled) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       Install_EulaNotRequired_EulaValueExistsZeroAlreadyInstalled) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoInstall_SelfInstall_EulaNotRequired_EulaValueExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  SetModeSelfInstall();
+  args_.is_eula_required_set = false;
+  TestDoInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+// Self-update does not clear eulaaccepted. This case should never happen.
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoInstall_SelfUpdate_EulaNotRequired_EulaValueExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  SetModeSelfUpdate();
+  args_.is_eula_required_set = false;
+  TestDoInstallWhileHoldingLock();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// EULA required is not handled by DoInstall(). It is handled later by
+// DoProtectedGoogleUpdateInstall().
+TEST_F(SetupRegistryProtectedMachineTest,
+       Install_EulaRequired_EulaValueDoesNotExist) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));
+  args_.is_eula_required_set = true;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_UpdateKeyDoesNotExist) {
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+
+  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+
+  // ClientState for Google Update (never used) and other apps is not affected.
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppMachineClientStatePath,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+}
+
+// The existing value is ignored if there are not two registered apps. This is
+// an artifact of the implementation and not a requirement.
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOther) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(8000)));
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsString) {
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), _T("0")));
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// One app is not sufficient for detecting that Google Update is already
+// installed.
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistOneAppRegistered) {  // NOLINT
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// Even Google Update registered is not sufficient for detecting that Google
+// Update is already installed.
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistGoogleUpdateRegistered) {  // NOLINT
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// Important: The existing state is not changed because two apps are registered.
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistTwoAppsRegistered) {  // NOLINT
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2MachineClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+// The existing state is not changed because Google Update is already
+// installed, but there is no way to differentiate this from writing 0.
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsZeroTwoAppsRegistered) {  // NOLINT
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2MachineClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// The existing state is not changed because Google Update is already installed.
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOneTwoAppsRegistered) {  // NOLINT
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppMachineClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2MachineClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+}
+
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_SelfInstall_EulaRequired_UpdateKeyDoesNotExist) {  // NOLINT
+  SetModeSelfInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// Self-update does not set eulaaccepted. This case should never happen.
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_SelfUpdate_EulaRequired_UpdateKeyDoesNotExist) {  // NOLINT
+  SetModeSelfUpdate();
+  args_.is_eula_required_set = true;
+  ExpectAsserts expect_asserts;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_UPDATE, _T("eulaaccepted")));
+}
+
+// EULA not required is not handled by DoProtectedGoogleUpdateInstall(). It
+// would have already been handled by DoInstall().
+TEST_F(SetupRegistryProtectedMachineTest,
+       DoProtectedGoogleUpdateInstall_EulaNotRequired_EulaValueExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  SetModeInstall();
+  args_.is_eula_required_set = false;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(MACHINE_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       Install_EulaNotRequired_UpdateKeyDoesNotExist) {
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       Install_EulaNotRequired_EulaValueDoesNotExist) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       Install_EulaNotRequired_EulaValueExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+
+  // ClientState for Google Update (never used) and other apps is not affected.
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStatePath,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       Install_EulaNotRequired_EulaValueExistsOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       Install_EulaNotRequired_EulaValueExistsOther) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(8000)));
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       Install_EulaNotRequired_EulaValueExistsString) {
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(USER_REG_UPDATE, _T("eulaaccepted"), _T("0")));
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       Install_EulaNotRequired_EulaValueDoesNotExistAlreadyInstalled) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       Install_EulaNotRequired_EulaValueExistsZeroAlreadyInstalled) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  args_.is_eula_required_set = false;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       DoInstall_SelfInstall_EulaNotRequired_EulaValueExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  SetModeSelfInstall();
+  args_.is_eula_required_set = false;
+  TestDoInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+// Self-update does not clear eulaaccepted. This case should never happen.
+TEST_F(SetupRegistryProtectedUserTest,
+       DoInstall_SelfUpdate_EulaNotRequired_EulaValueExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  SetModeSelfUpdate();
+  args_.is_eula_required_set = false;
+  TestDoInstallWhileHoldingLock();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// EULA required is not handled by DoInstall(). It is handled later by
+// DoProtectedGoogleUpdateInstall().
+TEST_F(SetupRegistryProtectedUserTest,
+       Install_EulaRequired_EulaValueDoesNotExist) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));
+  args_.is_eula_required_set = true;
+  TestInstallWhileHoldingLock();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_UpdateKeyDoesNotExist) {
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientStatePath,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+
+  // ClientState for Google Update (never used) and other apps is not affected.
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+  value = UINT_MAX;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kAppUserClientStatePath,
+                   _T("eulaaccepted"),
+                   &value));
+  EXPECT_EQ(0, value);
+}
+
+// The existing value is ignored if there are not two registered apps. This is
+// an artifact of the implementation and not a requirement.
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOne) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOther) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(8000)));
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsString) {
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(USER_REG_UPDATE, _T("eulaaccepted"), _T("0")));
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// One app is not sufficient for detecting that Google Update is already
+// installed.
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistOneAppRegistered) {  // NOLINT
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// Even Google Update registered is not sufficient for detecting that Google
+// Update is already installed.
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistGoogleUpdateRegistered) {  // NOLINT
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// Important: The existing state is not changed because two apps are registered.
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueDoesNotExistTwoAppsRegistered) {  // NOLINT
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2UserClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+// The existing state is not changed because Google Update is already
+// installed, but there is no way to differentiate this from writing 0.
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsZeroTwoAppsRegistered) {  // NOLINT
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2UserClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// The existing state is not changed because Google Update is already installed.
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaRequired_EulaValueExistsOneTwoAppsRegistered) {  // NOLINT
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kAppUserClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2UserClientsPath,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  SetModeInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(1, value);
+}
+
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_SelfInstall_EulaRequired_UpdateKeyDoesNotExist) {  // NOLINT
+  SetModeSelfInstall();
+  args_.is_eula_required_set = true;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+// Self-update does not set eulaaccepted. This case should never happen.
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_SelfUpdate_EulaRequired_UpdateKeyDoesNotExist) {  // NOLINT
+  SetModeSelfUpdate();
+  args_.is_eula_required_set = true;
+  ExpectAsserts expect_asserts;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_FALSE(RegKey::HasValue(USER_REG_UPDATE, _T("eulaaccepted")));
+}
+
+// EULA not required is not handled by DoProtectedGoogleUpdateInstall(). It
+// would have already been handled by DoInstall().
+TEST_F(SetupRegistryProtectedUserTest,
+       DoProtectedGoogleUpdateInstall_EulaNotRequired_EulaValueExistsZero) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  SetModeInstall();
+  args_.is_eula_required_set = false;
+  TestDoProtectedGoogleUpdateInstallWithFailingSetupFiles();
+  DWORD value = UINT_MAX;
+  EXPECT_SUCCEEDED(
+      RegKey::GetValue(USER_REG_UPDATE, _T("eulaaccepted"), &value));
+  EXPECT_EQ(0, value);
+}
+
+}  // namespace omaha
diff --git a/site_scons/site_init.py b/site_scons/site_init.py
index 2b5a0a5..c6631a6 100644
--- a/site_scons/site_init.py
+++ b/site_scons/site_init.py
@@ -1,20 +1,20 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-# Nothing to see here.  This file just needs to exist so that SCons can load

-# the tools in the site_scons subdirectory.  Customization of environments and

-# their methods should be done via those tools.

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+# Nothing to see here.  This file just needs to exist so that SCons can load
+# the tools in the site_scons subdirectory.  Customization of environments and
+# their methods should be done via those tools.
diff --git a/site_scons/site_tools/wix.py b/site_scons/site_tools/wix.py
index 5914fe8..dc7aa1a 100644
--- a/site_scons/site_tools/wix.py
+++ b/site_scons/site_tools/wix.py
@@ -1,112 +1,112 @@
-"""SCons.Tool.wix

-

-Tool-specific initialization for wix, the Windows Installer XML Tool.

-

-There normally shouldn't be any need to import this module directly.

-It will usually be imported through the generic SCons.Tool.Tool()

-selection method.

-"""

-

-#

-# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation

-#

-# Permission is hereby granted, free of charge, to any person obtaining

-# a copy of this software and associated documentation files (the

-# "Software"), to deal in the Software without restriction, including

-# without limitation the rights to use, copy, modify, merge, publish,

-# distribute, sublicense, and/or sell copies of the Software, and to

-# permit persons to whom the Software is furnished to do so, subject to

-# the following conditions:

-#

-# The above copyright notice and this permission notice shall be included

-# in all copies or substantial portions of the Software.

-#

-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY

-# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE

-# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND

-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE

-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION

-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

-#

-

-__revision__ = "src/engine/SCons/Tool/wix.py 3603 2008/10/10 05:46:45 scons"

-

-import SCons.Builder

-import SCons.Action

-import os

-import string

-

-

-def generate(env):

-    """Add Builders and construction variables for WiX to an Environment."""

-    if not exists(env):

-      return

-

-    env['WIXCANDLEFLAGS'] = ['-nologo']

-    env['WIXCANDLEINCLUDE'] = []

-    env['WIXCANDLECOM'] = '$WIXCANDLE $WIXCANDLEFLAGS -I $WIXCANDLEINCLUDE -o ${TARGET} ${SOURCE}'

-

-    env['WIXLIGHTFLAGS'].append( '-nologo' )

-    env['WIXLIGHTCOM'] = "$WIXLIGHT $WIXLIGHTFLAGS -out ${TARGET} ${SOURCES}"

-    env['WIXSRCSUFFIX'] = '.wxs'

-    env['WIXOBJPREFIX'] = ''

-    env['WIXOBJSUFFIX'] = '.wxiobj'

-    env['WIXMSIPREFIX'] = ''

-    env['WIXMSISUFFIX'] = '.msi'

-

-    object_builder = SCons.Builder.Builder(

-        action      = '$WIXCANDLECOM',

-        prefix      = '$WIXOBJPREFIX',

-        suffix      = '$WIXOBJSUFFIX',

-        src_suffix  = '$WIXSRCSUFFIX')

-

-    linker_builder = SCons.Builder.Builder(

-        action      = '$WIXLIGHTCOM',

-        prefix      = '$WIXMSIPREFIX',

-        suffix      = '$WIXMSISUFFIX',

-        src_suffix  = '$WIXOBJSUFFIX',

-        src_builder = object_builder)

-

-    env['BUILDERS']['WiX'] = linker_builder

-

-def exists(env):

-    env['WIXCANDLE'] = 'candle.exe'

-    env['WIXLIGHT']  = 'light.exe'

-    env['WIXLIGHTFLAGS'] = []

-

-    # try to find the candle.exe and light.exe tools and

-    # add the install directory to light libpath.

-    # for path in os.environ['PATH'].split(os.pathsep).

-    # also look in env['ENV']['PATH'] first.

-    wix_paths = string.split(env['ENV'].get('PATH', ''), os.pathsep)

-    wix_paths += string.split(os.environ['PATH'], os.pathsep)

-    for path in wix_paths:

-        if not path:

-            continue

-

-        # workaround for some weird python win32 bug.

-        if path[0] == '"' and path[-1:]=='"':

-            path = path[1:-1]

-

-        # normalize the path

-        path = os.path.normpath(path)

-

-        # search for the tools in the PATH environment variable

-        try:

-            if env['WIXCANDLE'] in os.listdir(path) and\

-               env['WIXLIGHT']  in os.listdir(path):

-                   env.PrependENVPath('PATH', path)

-                   extra_files = [os.path.join(i) for i in [

-                       'wixui.wixlib',

-                       'WixUI_en-us.wxl']]

-                   if (os.path.exists(extra_files[0]) and

-                       os.path.exists(extra_files[1])):

-                       env.Append(WIXLIGHTFLAGS=[

-                           extra_files[0],

-                           '-loc', extra_files[1]])

-                   return 1

-        except OSError:

-            pass # ignore this, could be a stale PATH entry.

-

-    return None

+"""SCons.Tool.wix
+
+Tool-specific initialization for wix, the Windows Installer XML Tool.
+
+There normally shouldn't be any need to import this module directly.
+It will usually be imported through the generic SCons.Tool.Tool()
+selection method.
+"""
+
+#
+# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "src/engine/SCons/Tool/wix.py 3603 2008/10/10 05:46:45 scons"
+
+import SCons.Builder
+import SCons.Action
+import os
+import string
+
+
+def generate(env):
+    """Add Builders and construction variables for WiX to an Environment."""
+    if not exists(env):
+      return
+
+    env['WIXCANDLEFLAGS'] = ['-nologo']
+    env['WIXCANDLEINCLUDE'] = []
+    env['WIXCANDLECOM'] = '$WIXCANDLE $WIXCANDLEFLAGS -I $WIXCANDLEINCLUDE -o ${TARGET} ${SOURCE}'
+
+    env['WIXLIGHTFLAGS'].append( '-nologo' )
+    env['WIXLIGHTCOM'] = "$WIXLIGHT $WIXLIGHTFLAGS -out ${TARGET} ${SOURCES}"
+    env['WIXSRCSUFFIX'] = '.wxs'
+    env['WIXOBJPREFIX'] = ''
+    env['WIXOBJSUFFIX'] = '.wxiobj'
+    env['WIXMSIPREFIX'] = ''
+    env['WIXMSISUFFIX'] = '.msi'
+
+    object_builder = SCons.Builder.Builder(
+        action      = '$WIXCANDLECOM',
+        prefix      = '$WIXOBJPREFIX',
+        suffix      = '$WIXOBJSUFFIX',
+        src_suffix  = '$WIXSRCSUFFIX')
+
+    linker_builder = SCons.Builder.Builder(
+        action      = '$WIXLIGHTCOM',
+        prefix      = '$WIXMSIPREFIX',
+        suffix      = '$WIXMSISUFFIX',
+        src_suffix  = '$WIXOBJSUFFIX',
+        src_builder = object_builder)
+
+    env['BUILDERS']['WiX'] = linker_builder
+
+def exists(env):
+    env['WIXCANDLE'] = 'candle.exe'
+    env['WIXLIGHT']  = 'light.exe'
+    env['WIXLIGHTFLAGS'] = []
+
+    # try to find the candle.exe and light.exe tools and
+    # add the install directory to light libpath.
+    # for path in os.environ['PATH'].split(os.pathsep).
+    # also look in env['ENV']['PATH'] first.
+    wix_paths = string.split(env['ENV'].get('PATH', ''), os.pathsep)
+    wix_paths += string.split(os.environ['PATH'], os.pathsep)
+    for path in wix_paths:
+        if not path:
+            continue
+
+        # workaround for some weird python win32 bug.
+        if path[0] == '"' and path[-1:]=='"':
+            path = path[1:-1]
+
+        # normalize the path
+        path = os.path.normpath(path)
+
+        # search for the tools in the PATH environment variable
+        try:
+            if env['WIXCANDLE'] in os.listdir(path) and\
+               env['WIXLIGHT']  in os.listdir(path):
+                   env.PrependENVPath('PATH', path)
+                   extra_files = [os.path.join(i) for i in [
+                       'wixui.wixlib',
+                       'WixUI_en-us.wxl']]
+                   if (os.path.exists(extra_files[0]) and
+                       os.path.exists(extra_files[1])):
+                       env.Append(WIXLIGHTFLAGS=[
+                           extra_files[0],
+                           '-loc', extra_files[1]])
+                   return 1
+        except OSError:
+            pass # ignore this, could be a stale PATH entry.
+
+    return None
diff --git a/standalone/build.scons b/standalone/build.scons
index 7b7348e..0c77922 100644
--- a/standalone/build.scons
+++ b/standalone/build.scons
@@ -1,40 +1,40 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-

-from standalone import standalone_installer

-

-# Build the meta-installer for each version.

-first = True

-for v in env['product_version']:

-  if first:

-    first = False

-    prefix = ''

-  else:

-    prefix = 'TEST_'

-

-  source_binary = '$OBJ_ROOT/mi_exe_stub/%smi_exe_stub.exe' % (prefix)

-

-  standalone_installer.BuildOfflineInstallersVersion(

-      env,

-      '$STAGING_DIR',

-      source_binary,

-      '$MAIN_DIR/standalone/standalone_installers.txt',

-      '$MAIN_DIR/standalone/manifests',

-      prefix)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+
+from standalone import standalone_installer
+
+# Build the meta-installer for each version.
+first = True
+for v in env['product_version']:
+  if first:
+    first = False
+    prefix = ''
+  else:
+    prefix = 'TEST_'
+
+  source_binary = '$OBJ_ROOT/mi_exe_stub/%smi_exe_stub.exe' % (prefix)
+
+  standalone_installer.BuildOfflineInstallersVersion(
+      env,
+      '$STAGING_DIR',
+      source_binary,
+      '$MAIN_DIR/standalone/standalone_installers.txt',
+      '$MAIN_DIR/standalone/manifests',
+      prefix)
diff --git "a/standalone/manifests/\173D6B08267-B440-4C85-9F79-E195E80D9937\175.gup" "b/standalone/manifests/\173D6B08267-B440-4C85-9F79-E195E80D9937\175.gup"
index 1cb0201..310de51 100644
--- "a/standalone/manifests/\173D6B08267-B440-4C85-9F79-E195E80D9937\175.gup"
+++ "b/standalone/manifests/\173D6B08267-B440-4C85-9F79-E195E80D9937\175.gup"
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">

-  <app appid="{D6B08267-B440-4C85-9F79-E195E80D9937}" status="ok">

-    <updatecheck arguments="REGISTER_LAUNCH_COMMAND=1"

-                 codebase="http://dl.google.com/foo/test_foo_v1.0.101.0.msi"

-                 hash="Bul1OVnBVhX1R6KwS7gaTtZm9m8="

-                 needsadmin="true"

-                 size="50688"

-                 status="ok"/>

-</app>

-</gupdate>

+<?xml version="1.0" encoding="UTF-8"?>
+<gupdate xmlns="http://www.google.com/update2/response" protocol="2.0">
+  <app appid="{D6B08267-B440-4C85-9F79-E195E80D9937}" status="ok">
+    <updatecheck arguments="REGISTER_LAUNCH_COMMAND=1"
+                 codebase="http://dl.google.com/foo/test_foo_v1.0.101.0.msi"
+                 hash="Bul1OVnBVhX1R6KwS7gaTtZm9m8="
+                 needsadmin="true"
+                 size="50688"
+                 status="ok"/>
+</app>
+</gupdate>
diff --git a/standalone/standalone_installer.py b/standalone/standalone_installer.py
index 74b935e..6ba1e17 100644
--- a/standalone/standalone_installer.py
+++ b/standalone/standalone_installer.py
@@ -1,189 +1,189 @@
-#!/usr/bin/python2.4

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-# This is very close to the logic within installers\build.scons. The difference

-# is that we have an additional file standalone_installers.txt. This file

-# contains a list of standalone installers that we create within this mk_file.

-# The corresponding binaries for the standalone installers are checked into the

-# standalone\binaries sub-directory, and referenced from

-# standalone_installers.txt. For each entry in standalone_installers.txt, we

-# create a corresponding "standalone" installer, which is the meta-installer,

-# plus the offline setup binaries, tarred together.

-

-import codecs

-import os

-

-from installers import tagged_installer

-from installers import build_metainstaller

-from installers import tag_meta_installers

-

-

-class OffLineInstaller:

-  """Represents the information for a bundle"""

-  def __init__(self, installers_txt_filename, exe_name, binaries):

-    self.installers_txt_filename = installers_txt_filename

-    self.name = exe_name

-    self.binaries = binaries

-

-

-def ReadOffLineInstallersFile(env, offline_installers_file_name):

-  """Enumerates the entries in the offline installers file.

-  Returns:

-    Returns a list of structures used for creating the prestamped binaries.

-  """

-  offline_installers = []

-  offline_abs_path = env.File(offline_installers_file_name).abspath

-  installer_file = codecs.open(offline_abs_path, 'r')

-  for line in installer_file.readlines():

-    line = line.strip()

-    if len(line) and not line.startswith('#'):

-      (installers_txt_filename, exe_name, binaries) = eval(line)

-      installer = OffLineInstaller(installers_txt_filename, exe_name, binaries)

-      offline_installers.append(installer)

-  return offline_installers

-

-

-def BuildOfflineInstallersVersion(env,

-                                  google_update_files_path,

-                                  source_binary,

-                                  offline_installers_file_name,

-                                  manifest_files_path,

-                                  prefix = '',

-                                  is_official = False):

-  offline_installers = ReadOffLineInstallersFile(env,

-      offline_installers_file_name)

-

-  for offline_installer in offline_installers:

-    BuildOfflineInstaller(

-        env,

-        offline_installer,

-        google_update_files_path,

-        source_binary,

-        offline_installers_file_name,

-        manifest_files_path,

-        prefix,

-        is_official

-    )

-

-

-def BuildOfflineInstaller(env,

-                          offline_installer,

-                          google_update_files_path,

-                          source_binary,

-                          offline_installers_file_name,

-                          manifest_files_path,

-                          prefix = '',

-                          is_official = False):

-  product_name = offline_installer.name

-  if not is_official:

-    product_name = 'UNOFFICIAL_' + product_name

-

-  target_base = prefix + product_name

-  target_name = target_base + '.exe'

-  log_name = target_base + '_Contents.txt'

-

-  # Write Omaha's VERSION file.

-  if prefix:

-    version_index = 1

-  else:

-    version_index = 0

-

-  v = env['product_version'][version_index]

-  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-  log_text = '*** Omaha Version ***\n\n'

-  log_text += version_string + '\n'

-

-  # Rename the checked in binaries by adding the application guid as the

-  # extension. This is needed as the meta-installer expects the

-  # extension.

-  # Also, log information about each app.

-  additional_payload_contents = []

-  for binary in offline_installer.binaries:

-    (binary_name, guid) = binary

-    output_file = os.path.basename(binary_name) + '.' + guid

-

-    # Have to use Command('copy') here instead of replicate, as the

-    # file is being renamed in the process.

-    env.Command(

-        target=output_file,

-        source=binary_name,

-        action='@copy /y $SOURCES $TARGET'

-    )

-

-    manifest_file_path = manifest_files_path + '/' + guid + '.gup'

-    additional_payload_contents += [output_file, manifest_file_path]

-

-    # Log info about the app.

-    log_text += '\n\n*** App: ' + guid + ' ***\n'

-    log_text += '\nINSTALLER:\n' + binary_name + '\n'

-

-    manifest_file = open(env.File(manifest_file_path).abspath, 'r', -1)

-    manifest_file_contents = manifest_file.read()

-    manifest_file.close()

-    log_text += '\nMANIFEST:\n'

-    log_text += manifest_file_contents

-

-  def WriteLog(target, source, env):

-    f = open(env.File(target[0]).abspath, 'w')

-    f.write(env['write_data'])

-    f.close()

-    return 0

-

-  env.Command(

-      target='$STAGING_DIR/' + log_name,

-      source=[],

-      action=WriteLog,

-      write_data=log_text

-  )

-

-  build_metainstaller.BuildMetaInstaller(

-      env=env,

-      target_name=target_name,

-      empty_metainstaller_path=source_binary,

-      google_update_files_path=google_update_files_path,

-      prefix=prefix,

-      suffix='_' + product_name,

-      additional_payload_contents=additional_payload_contents,

-      additional_payload_contents_dependencies=offline_installers_file_name

-  )

-

-  # Tag the meta-installer if an installers.txt file was specified.

-  if offline_installer.installers_txt_filename:

-    installers_txt_path = (env.File('$MAIN_DIR/' +

-        offline_installer.installers_txt_filename).abspath)

-    app_bundles = tag_meta_installers.ReadBundleInstallerFile(

-        installers_txt_path)

-

-    bundles = {}

-    for (key, bundle_list) in app_bundles.items():

-      if not bundle_list or not key:

-        continue

-      if not bundles.has_key(key):

-        bundles[key] = bundle_list

-      else:

-        new_bundles_list = bundles[key] + bundle_list

-        bundles[key] = new_bundles_list

-

-    tag_meta_installers.SetOutputFileNames(target_name, bundles, '')

-    for bundles_lang in bundles.itervalues():

-      for bundle in bundles_lang:

-        tagged_installer.TagOneBundle(

-            env=env,

-            bundle=bundle,

-            untagged_binary=target_name,

-            output_dir='$TARGET_ROOT/Tagged_Offline_Installers',

-        )

+#!/usr/bin/python2.4
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+# This is very close to the logic within installers\build.scons. The difference
+# is that we have an additional file standalone_installers.txt. This file
+# contains a list of standalone installers that we create within this mk_file.
+# The corresponding binaries for the standalone installers are checked into the
+# standalone\binaries sub-directory, and referenced from
+# standalone_installers.txt. For each entry in standalone_installers.txt, we
+# create a corresponding "standalone" installer, which is the meta-installer,
+# plus the offline setup binaries, tarred together.
+
+import codecs
+import os
+
+from installers import tagged_installer
+from installers import build_metainstaller
+from installers import tag_meta_installers
+
+
+class OffLineInstaller:
+  """Represents the information for a bundle"""
+  def __init__(self, installers_txt_filename, exe_name, binaries):
+    self.installers_txt_filename = installers_txt_filename
+    self.name = exe_name
+    self.binaries = binaries
+
+
+def ReadOffLineInstallersFile(env, offline_installers_file_name):
+  """Enumerates the entries in the offline installers file.
+  Returns:
+    Returns a list of structures used for creating the prestamped binaries.
+  """
+  offline_installers = []
+  offline_abs_path = env.File(offline_installers_file_name).abspath
+  installer_file = codecs.open(offline_abs_path, 'r')
+  for line in installer_file.readlines():
+    line = line.strip()
+    if len(line) and not line.startswith('#'):
+      (installers_txt_filename, exe_name, binaries) = eval(line)
+      installer = OffLineInstaller(installers_txt_filename, exe_name, binaries)
+      offline_installers.append(installer)
+  return offline_installers
+
+
+def BuildOfflineInstallersVersion(env,
+                                  google_update_files_path,
+                                  source_binary,
+                                  offline_installers_file_name,
+                                  manifest_files_path,
+                                  prefix = '',
+                                  is_official = False):
+  offline_installers = ReadOffLineInstallersFile(env,
+      offline_installers_file_name)
+
+  for offline_installer in offline_installers:
+    BuildOfflineInstaller(
+        env,
+        offline_installer,
+        google_update_files_path,
+        source_binary,
+        offline_installers_file_name,
+        manifest_files_path,
+        prefix,
+        is_official
+    )
+
+
+def BuildOfflineInstaller(env,
+                          offline_installer,
+                          google_update_files_path,
+                          source_binary,
+                          offline_installers_file_name,
+                          manifest_files_path,
+                          prefix = '',
+                          is_official = False):
+  product_name = offline_installer.name
+  if not is_official:
+    product_name = 'UNOFFICIAL_' + product_name
+
+  target_base = prefix + product_name
+  target_name = target_base + '.exe'
+  log_name = target_base + '_Contents.txt'
+
+  # Write Omaha's VERSION file.
+  if prefix:
+    version_index = 1
+  else:
+    version_index = 0
+
+  v = env['product_version'][version_index]
+  version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+  log_text = '*** Omaha Version ***\n\n'
+  log_text += version_string + '\n'
+
+  # Rename the checked in binaries by adding the application guid as the
+  # extension. This is needed as the meta-installer expects the
+  # extension.
+  # Also, log information about each app.
+  additional_payload_contents = []
+  for binary in offline_installer.binaries:
+    (binary_name, guid) = binary
+    output_file = os.path.basename(binary_name) + '.' + guid
+
+    # Have to use Command('copy') here instead of replicate, as the
+    # file is being renamed in the process.
+    env.Command(
+        target=output_file,
+        source=binary_name,
+        action='@copy /y $SOURCES $TARGET'
+    )
+
+    manifest_file_path = manifest_files_path + '/' + guid + '.gup'
+    additional_payload_contents += [output_file, manifest_file_path]
+
+    # Log info about the app.
+    log_text += '\n\n*** App: ' + guid + ' ***\n'
+    log_text += '\nINSTALLER:\n' + binary_name + '\n'
+
+    manifest_file = open(env.File(manifest_file_path).abspath, 'r', -1)
+    manifest_file_contents = manifest_file.read()
+    manifest_file.close()
+    log_text += '\nMANIFEST:\n'
+    log_text += manifest_file_contents
+
+  def WriteLog(target, source, env):
+    f = open(env.File(target[0]).abspath, 'w')
+    f.write(env['write_data'])
+    f.close()
+    return 0
+
+  env.Command(
+      target='$STAGING_DIR/' + log_name,
+      source=[],
+      action=WriteLog,
+      write_data=log_text
+  )
+
+  build_metainstaller.BuildMetaInstaller(
+      env=env,
+      target_name=target_name,
+      empty_metainstaller_path=source_binary,
+      google_update_files_path=google_update_files_path,
+      prefix=prefix,
+      suffix='_' + product_name,
+      additional_payload_contents=additional_payload_contents,
+      additional_payload_contents_dependencies=offline_installers_file_name
+  )
+
+  # Tag the meta-installer if an installers.txt file was specified.
+  if offline_installer.installers_txt_filename:
+    installers_txt_path = (env.File('$MAIN_DIR/' +
+        offline_installer.installers_txt_filename).abspath)
+    app_bundles = tag_meta_installers.ReadBundleInstallerFile(
+        installers_txt_path)
+
+    bundles = {}
+    for (key, bundle_list) in app_bundles.items():
+      if not bundle_list or not key:
+        continue
+      if not bundles.has_key(key):
+        bundles[key] = bundle_list
+      else:
+        new_bundles_list = bundles[key] + bundle_list
+        bundles[key] = new_bundles_list
+
+    tag_meta_installers.SetOutputFileNames(target_name, bundles, '')
+    for bundles_lang in bundles.itervalues():
+      for bundle in bundles_lang:
+        tagged_installer.TagOneBundle(
+            env=env,
+            bundle=bundle,
+            untagged_binary=target_name,
+            output_dir='$TARGET_ROOT/Tagged_Offline_Installers',
+        )
diff --git a/standalone/standalone_installers.txt b/standalone/standalone_installers.txt
index 1556892..9b7ea65 100644
--- a/standalone/standalone_installers.txt
+++ b/standalone/standalone_installers.txt
@@ -1 +1 @@
-('/installers/SampleApp_installers.txt', 'TestFoo', [('$STAGING_DIR/unittest_support/test_foo_v1.0.101.0.msi', '{D6B08267-B440-4C85-9F79-E195E80D9937}')])

+('/installers/SampleApp_installers.txt', 'TestFoo', [('$STAGING_DIR/unittest_support/test_foo_v1.0.101.0.msi', '{D6B08267-B440-4C85-9F79-E195E80D9937}')])
diff --git a/statsreport/aggregator-win32.cc b/statsreport/aggregator-win32.cc
index 8450407..c1c8df7 100644
--- a/statsreport/aggregator-win32.cc
+++ b/statsreport/aggregator-win32.cc
@@ -1,147 +1,147 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Implementation of Win32 metrics aggregator.

-#include "aggregator-win32.h"

-#include "const-win32.h"

-#include "util-win32.h"

-

-namespace stats_report {

-

-MetricsAggregatorWin32::MetricsAggregatorWin32(MetricCollection &coll,

-                                               const wchar_t *key_name)

-    : MetricsAggregator(coll),

-      is_machine_(false) {

-  DCHECK(NULL != key_name);

-

-  key_name_.Format(kStatsKeyFormatString, key_name);

-}

-

-MetricsAggregatorWin32::MetricsAggregatorWin32(MetricCollection &coll,

-                                               const wchar_t *key_name,

-                                               bool is_machine)

-    : MetricsAggregator(coll),

-      is_machine_(is_machine) {

-  DCHECK(NULL != key_name);

-

-  key_name_.Format(kStatsKeyFormatString, key_name);

-}

-

-MetricsAggregatorWin32::~MetricsAggregatorWin32() {

-}

-

-bool MetricsAggregatorWin32::StartAggregation() {

-  DCHECK(NULL == key_.m_hKey);

-

-  HKEY parent_key = is_machine_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

-  LONG err = key_.Create(parent_key, key_name_);

-  if (err != ERROR_SUCCESS)

-    return false;

-

-  return true;

-}

-

-void MetricsAggregatorWin32::EndAggregation() {

-  count_key_.Close();

-  timing_key_.Close();

-  integer_key_.Close();

-  bool_key_.Close();

-

-  key_.Close();

-}

-

-bool MetricsAggregatorWin32::EnsureKey(const wchar_t *name, CRegKey *key) {

-  if (NULL != key->m_hKey)

-    return true;

-

-  LONG err = key->Create(key_, name);

-  if (ERROR_SUCCESS != err) {

-    DCHECK(NULL == key->m_hKey);

-    // TODO(omaha): log?

-    return false;

-  }

-

-  return true;

-}

-

-void MetricsAggregatorWin32::Aggregate(CountMetric &metric) {

-  // do as little as possible if no value

-  uint64 value = metric.Reset();

-  if (0 == value)

-    return;

-

-  if (!EnsureKey(kCountsKeyName, &count_key_))

-    return;

-

-  CString name(metric.name());

-  uint64 reg_value = 0;

-  if (!GetData(count_key_, name, &reg_value)) {

-    // TODO(omaha): clean up??

-  }

-  reg_value += value;

-

-  DWORD err = count_key_.SetBinaryValue(name, &reg_value, sizeof(reg_value));

-}

-

-void MetricsAggregatorWin32::Aggregate(TimingMetric &metric) {

-  // do as little as possible if no value

-  TimingMetric::TimingData value = metric.Reset();

-  if (0 == value.count)

-    return;

-

-  if (!EnsureKey(kTimingsKeyName, &timing_key_))

-    return;

-

-  CString name(metric.name());

-  TimingMetric::TimingData reg_value;

-  if (!GetData(timing_key_, name, &reg_value)) {

-    memcpy(&reg_value, &value, sizeof(value));

-  } else {

-    reg_value.count += value.count;

-    reg_value.sum += value.sum;

-    reg_value.minimum = std::min(reg_value.minimum, value.minimum);

-    reg_value.maximum = std::max(reg_value.maximum, value.maximum);

-  }

-

-  DWORD err = timing_key_.SetBinaryValue(name, &reg_value, sizeof(reg_value));

-}

-

-void MetricsAggregatorWin32::Aggregate(IntegerMetric &metric) {

-  // do as little as possible if no value

-  uint64 value = metric.value();

-  if (0 == value)

-    return;

-

-  if (!EnsureKey(kIntegersKeyName, &integer_key_))

-    return;

-

-  DWORD err = integer_key_.SetBinaryValue(CString(metric.name()),

-                                          &value, sizeof(value));

-}

-

-void MetricsAggregatorWin32::Aggregate(BoolMetric &metric) {

-  // do as little as possible if no value

-  int32 value = metric.Reset();

-  if (BoolMetric::kBoolUnset == value)

-    return;

-

-  if (!EnsureKey(kBooleansKeyName, &bool_key_))

-    return;

-

-  DWORD err = bool_key_.SetBinaryValue(CString(metric.name()),

-                                       &value, sizeof(value));

-}

-

-} // namespace stats_report

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Implementation of Win32 metrics aggregator.
+#include "aggregator-win32.h"
+#include "const-win32.h"
+#include "util-win32.h"
+
+namespace stats_report {
+
+MetricsAggregatorWin32::MetricsAggregatorWin32(MetricCollection &coll,
+                                               const wchar_t *key_name)
+    : MetricsAggregator(coll),
+      is_machine_(false) {
+  DCHECK(NULL != key_name);
+
+  key_name_.Format(kStatsKeyFormatString, key_name);
+}
+
+MetricsAggregatorWin32::MetricsAggregatorWin32(MetricCollection &coll,
+                                               const wchar_t *key_name,
+                                               bool is_machine)
+    : MetricsAggregator(coll),
+      is_machine_(is_machine) {
+  DCHECK(NULL != key_name);
+
+  key_name_.Format(kStatsKeyFormatString, key_name);
+}
+
+MetricsAggregatorWin32::~MetricsAggregatorWin32() {
+}
+
+bool MetricsAggregatorWin32::StartAggregation() {
+  DCHECK(NULL == key_.m_hKey);
+
+  HKEY parent_key = is_machine_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+  LONG err = key_.Create(parent_key, key_name_);
+  if (err != ERROR_SUCCESS)
+    return false;
+
+  return true;
+}
+
+void MetricsAggregatorWin32::EndAggregation() {
+  count_key_.Close();
+  timing_key_.Close();
+  integer_key_.Close();
+  bool_key_.Close();
+
+  key_.Close();
+}
+
+bool MetricsAggregatorWin32::EnsureKey(const wchar_t *name, CRegKey *key) {
+  if (NULL != key->m_hKey)
+    return true;
+
+  LONG err = key->Create(key_, name);
+  if (ERROR_SUCCESS != err) {
+    DCHECK(NULL == key->m_hKey);
+    // TODO(omaha): log?
+    return false;
+  }
+
+  return true;
+}
+
+void MetricsAggregatorWin32::Aggregate(CountMetric &metric) {
+  // do as little as possible if no value
+  uint64 value = metric.Reset();
+  if (0 == value)
+    return;
+
+  if (!EnsureKey(kCountsKeyName, &count_key_))
+    return;
+
+  CString name(metric.name());
+  uint64 reg_value = 0;
+  if (!GetData(count_key_, name, &reg_value)) {
+    // TODO(omaha): clean up??
+  }
+  reg_value += value;
+
+  DWORD err = count_key_.SetBinaryValue(name, &reg_value, sizeof(reg_value));
+}
+
+void MetricsAggregatorWin32::Aggregate(TimingMetric &metric) {
+  // do as little as possible if no value
+  TimingMetric::TimingData value = metric.Reset();
+  if (0 == value.count)
+    return;
+
+  if (!EnsureKey(kTimingsKeyName, &timing_key_))
+    return;
+
+  CString name(metric.name());
+  TimingMetric::TimingData reg_value;
+  if (!GetData(timing_key_, name, &reg_value)) {
+    memcpy(&reg_value, &value, sizeof(value));
+  } else {
+    reg_value.count += value.count;
+    reg_value.sum += value.sum;
+    reg_value.minimum = std::min(reg_value.minimum, value.minimum);
+    reg_value.maximum = std::max(reg_value.maximum, value.maximum);
+  }
+
+  DWORD err = timing_key_.SetBinaryValue(name, &reg_value, sizeof(reg_value));
+}
+
+void MetricsAggregatorWin32::Aggregate(IntegerMetric &metric) {
+  // do as little as possible if no value
+  uint64 value = metric.value();
+  if (0 == value)
+    return;
+
+  if (!EnsureKey(kIntegersKeyName, &integer_key_))
+    return;
+
+  DWORD err = integer_key_.SetBinaryValue(CString(metric.name()),
+                                          &value, sizeof(value));
+}
+
+void MetricsAggregatorWin32::Aggregate(BoolMetric &metric) {
+  // do as little as possible if no value
+  int32 value = metric.Reset();
+  if (BoolMetric::kBoolUnset == value)
+    return;
+
+  if (!EnsureKey(kBooleansKeyName, &bool_key_))
+    return;
+
+  DWORD err = bool_key_.SetBinaryValue(CString(metric.name()),
+                                       &value, sizeof(value));
+}
+
+} // namespace stats_report
diff --git a/statsreport/aggregator-win32.h b/statsreport/aggregator-win32.h
index 118373c..f9ad30b 100644
--- a/statsreport/aggregator-win32.h
+++ b/statsreport/aggregator-win32.h
@@ -1,86 +1,86 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Win32 aggregator, which aggregates counters to registry under a named

-// Mutex lock.

-#ifndef OMAHA_STATSREPORT_AGGREGATOR_WIN32_H__

-#define OMAHA_STATSREPORT_AGGREGATOR_WIN32_H__

-

-#include "aggregator.h"

-#include <atlbase.h>

-#include <atlstr.h>

-

-namespace stats_report {

-

-class MetricsAggregatorWin32: public MetricsAggregator {

-public:

-  /// @param coll the metrics collection to aggregate, most usually this

-  ///           is g_global_metrics.

-  /// @param app_name name of the subkey under HKCU\Software\Google we

-  ///           aggregate to.

-  MetricsAggregatorWin32(MetricCollection &coll,

-                         const wchar_t *app_name);

-

-  /// @param is_machine specifies the registry hive where the stats are

-  ///           aggregated to.

-  MetricsAggregatorWin32(MetricCollection &coll,

-                         const wchar_t *app_name,

-                         bool is_machine);

-  virtual ~MetricsAggregatorWin32();

-

-protected:

-  virtual bool StartAggregation();

-  virtual void EndAggregation();

-

-  virtual void Aggregate(CountMetric &metric);

-  virtual void Aggregate(TimingMetric &metric);

-  virtual void Aggregate(IntegerMetric &metric);

-  virtual void Aggregate(BoolMetric &metric);

-private:

-  enum {

-    /// Max length of time we wait for the mutex on StartAggregation.

-    kMaxMutexWaitMs = 1000, // 1 second for now

-  };

-

-  /// Ensures that *key is open, opening it if it's NULL

-  /// @return true on success, false on failure to open key

-  bool EnsureKey(const wchar_t *name, CRegKey *key);

-

-  /// Mutex name for locking access to key

-  CString mutex_name_;

-

-  /// Subkey name, as per constructor docs

-  CString key_name_;

-

-  /// Handle to our subkey under HKCU\Software\Google

-  CRegKey key_;

-

-  /// Subkeys under the above

-  /// @{

-  CRegKey count_key_;

-  CRegKey timing_key_;

-  CRegKey integer_key_;

-  CRegKey bool_key_;

-  /// @}

-

-  /// Specifies HKLM or HKCU, respectively.

-  bool is_machine_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(MetricsAggregatorWin32);

-};

-

-} // namespace stats_report

-

-#endif  // OMAHA_STATSREPORT_AGGREGATOR_WIN32_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Win32 aggregator, which aggregates counters to registry under a named
+// Mutex lock.
+#ifndef OMAHA_STATSREPORT_AGGREGATOR_WIN32_H__
+#define OMAHA_STATSREPORT_AGGREGATOR_WIN32_H__
+
+#include "aggregator.h"
+#include <atlbase.h>
+#include <atlstr.h>
+
+namespace stats_report {
+
+class MetricsAggregatorWin32: public MetricsAggregator {
+public:
+  /// @param coll the metrics collection to aggregate, most usually this
+  ///           is g_global_metrics.
+  /// @param app_name name of the subkey under HKCU\Software\Google we
+  ///           aggregate to.
+  MetricsAggregatorWin32(MetricCollection &coll,
+                         const wchar_t *app_name);
+
+  /// @param is_machine specifies the registry hive where the stats are
+  ///           aggregated to.
+  MetricsAggregatorWin32(MetricCollection &coll,
+                         const wchar_t *app_name,
+                         bool is_machine);
+  virtual ~MetricsAggregatorWin32();
+
+protected:
+  virtual bool StartAggregation();
+  virtual void EndAggregation();
+
+  virtual void Aggregate(CountMetric &metric);
+  virtual void Aggregate(TimingMetric &metric);
+  virtual void Aggregate(IntegerMetric &metric);
+  virtual void Aggregate(BoolMetric &metric);
+private:
+  enum {
+    /// Max length of time we wait for the mutex on StartAggregation.
+    kMaxMutexWaitMs = 1000, // 1 second for now
+  };
+
+  /// Ensures that *key is open, opening it if it's NULL
+  /// @return true on success, false on failure to open key
+  bool EnsureKey(const wchar_t *name, CRegKey *key);
+
+  /// Mutex name for locking access to key
+  CString mutex_name_;
+
+  /// Subkey name, as per constructor docs
+  CString key_name_;
+
+  /// Handle to our subkey under HKCU\Software\Google
+  CRegKey key_;
+
+  /// Subkeys under the above
+  /// @{
+  CRegKey count_key_;
+  CRegKey timing_key_;
+  CRegKey integer_key_;
+  CRegKey bool_key_;
+  /// @}
+
+  /// Specifies HKLM or HKCU, respectively.
+  bool is_machine_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(MetricsAggregatorWin32);
+};
+
+} // namespace stats_report
+
+#endif  // OMAHA_STATSREPORT_AGGREGATOR_WIN32_H__
diff --git a/statsreport/aggregator-win32_unittest.cc b/statsreport/aggregator-win32_unittest.cc
index a34329c..3a23360 100644
--- a/statsreport/aggregator-win32_unittest.cc
+++ b/statsreport/aggregator-win32_unittest.cc
@@ -1,98 +1,98 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Implementation of Win32 metrics aggregator.

-#include "aggregator-win32.h"

-#include "aggregator-win32_unittest.h"

-#include "aggregator_unittest.h"

-#include "omaha/third_party/gtest/include/gtest/gtest.h"

-

-using namespace stats_report;

-

-#define APP_NAME_STRING L"aggregator-win32_unittest"

-#define PREFIX_KEY_STRING L"Software\\Google\\" 

-#define SUFFIX_KEY_STRING L"\\UsageStats\\Daily"

-#define ROOT_KEY_STRING PREFIX_KEY_STRING APP_NAME_STRING 

-#define KEY_STRING ROOT_KEY_STRING SUFFIX_KEY_STRING

-

-const wchar_t MetricsAggregatorWin32Test::kAppName[] = APP_NAME_STRING;

-const wchar_t MetricsAggregatorWin32Test::kRootKeyName[] = ROOT_KEY_STRING;

-const wchar_t MetricsAggregatorWin32Test::kCountsKeyName[] = 

-                                                      KEY_STRING L"\\Counts";

-const wchar_t MetricsAggregatorWin32Test::kTimingsKeyName[] = 

-                                                      KEY_STRING L"\\Timings";

-const wchar_t MetricsAggregatorWin32Test::kIntegersKeyName[] = 

-                                                      KEY_STRING L"\\Integers";

-const wchar_t MetricsAggregatorWin32Test::kBoolsKeyName[] = 

-                                                      KEY_STRING L"\\Booleans";

-

-

-#define EXPECT_REGVAL_EQ(value, key_name, value_name) do { \

-  char buf[sizeof(value)]; \

-  ULONG len = sizeof(buf); \

-  CRegKey key; \

-  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, key_name)); \

-  EXPECT_EQ(ERROR_SUCCESS, key.QueryBinaryValue(value_name, buf, &len)); \

-  EXPECT_EQ(sizeof(buf), len); \

-  EXPECT_EQ(0, memcmp(&value, buf, sizeof(buf))); \

-} while(0)

-

-TEST_F(MetricsAggregatorWin32Test, AggregateWin32) {

-  MetricsAggregatorWin32 agg(coll_, kAppName);

-

-  EXPECT_TRUE(agg.AggregateMetrics());

-  AddStats();  

-  EXPECT_TRUE(agg.AggregateMetrics());  

-

-  {

-    int64 one = 1, two = 2;

-    EXPECT_REGVAL_EQ(one, kCountsKeyName, L"c1");

-    EXPECT_REGVAL_EQ(two, kCountsKeyName, L"c2");

-

-    TimingMetric::TimingData data1 = { 2, 0, 1500, 500, 1000 };  

-    TimingMetric::TimingData data2 = { 2, 0, 2030, 30, 2000 };  

-    EXPECT_REGVAL_EQ(data1, kTimingsKeyName, L"t1");

-    EXPECT_REGVAL_EQ(data2, kTimingsKeyName, L"t2");

-

-    EXPECT_REGVAL_EQ(one, kIntegersKeyName, L"i1");

-    EXPECT_REGVAL_EQ(two, kIntegersKeyName, L"i2");

-

-    int32 bool_true = 1, bool_false = 0;

-    EXPECT_REGVAL_EQ(bool_true, kBoolsKeyName, L"b1");

-    EXPECT_REGVAL_EQ(bool_false, kBoolsKeyName, L"b2");

-  }

-  

-  AddStats();  

-  EXPECT_TRUE(agg.AggregateMetrics());  

-

-  {

-    int64 two = 2, four = 4;

-    EXPECT_REGVAL_EQ(two, kCountsKeyName, L"c1");

-    EXPECT_REGVAL_EQ(four, kCountsKeyName, L"c2");

-

-    TimingMetric::TimingData data1 = { 4, 0, 3000, 500, 1000 };  

-    TimingMetric::TimingData data2 = { 4, 0, 4060, 30, 2000 };  

-    EXPECT_REGVAL_EQ(data1, kTimingsKeyName, L"t1");

-    EXPECT_REGVAL_EQ(data2, kTimingsKeyName, L"t2");

-

-    int64 one = 1;

-    EXPECT_REGVAL_EQ(one, kIntegersKeyName, L"i1");

-    EXPECT_REGVAL_EQ(two, kIntegersKeyName, L"i2");

-

-    int32 bool_true = 1, bool_false = 0;

-    EXPECT_REGVAL_EQ(bool_true, kBoolsKeyName, L"b1");

-    EXPECT_REGVAL_EQ(bool_false, kBoolsKeyName, L"b2");

-  }

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Implementation of Win32 metrics aggregator.
+#include "aggregator-win32.h"
+#include "aggregator-win32_unittest.h"
+#include "aggregator_unittest.h"
+#include "omaha/third_party/gtest/include/gtest/gtest.h"
+
+using namespace stats_report;
+
+#define APP_NAME_STRING L"aggregator-win32_unittest"
+#define PREFIX_KEY_STRING L"Software\\Google\\" 
+#define SUFFIX_KEY_STRING L"\\UsageStats\\Daily"
+#define ROOT_KEY_STRING PREFIX_KEY_STRING APP_NAME_STRING 
+#define KEY_STRING ROOT_KEY_STRING SUFFIX_KEY_STRING
+
+const wchar_t MetricsAggregatorWin32Test::kAppName[] = APP_NAME_STRING;
+const wchar_t MetricsAggregatorWin32Test::kRootKeyName[] = ROOT_KEY_STRING;
+const wchar_t MetricsAggregatorWin32Test::kCountsKeyName[] = 
+                                                      KEY_STRING L"\\Counts";
+const wchar_t MetricsAggregatorWin32Test::kTimingsKeyName[] = 
+                                                      KEY_STRING L"\\Timings";
+const wchar_t MetricsAggregatorWin32Test::kIntegersKeyName[] = 
+                                                      KEY_STRING L"\\Integers";
+const wchar_t MetricsAggregatorWin32Test::kBoolsKeyName[] = 
+                                                      KEY_STRING L"\\Booleans";
+
+
+#define EXPECT_REGVAL_EQ(value, key_name, value_name) do { \
+  char buf[sizeof(value)]; \
+  ULONG len = sizeof(buf); \
+  CRegKey key; \
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, key_name)); \
+  EXPECT_EQ(ERROR_SUCCESS, key.QueryBinaryValue(value_name, buf, &len)); \
+  EXPECT_EQ(sizeof(buf), len); \
+  EXPECT_EQ(0, memcmp(&value, buf, sizeof(buf))); \
+} while(0)
+
+TEST_F(MetricsAggregatorWin32Test, AggregateWin32) {
+  MetricsAggregatorWin32 agg(coll_, kAppName);
+
+  EXPECT_TRUE(agg.AggregateMetrics());
+  AddStats();  
+  EXPECT_TRUE(agg.AggregateMetrics());  
+
+  {
+    int64 one = 1, two = 2;
+    EXPECT_REGVAL_EQ(one, kCountsKeyName, L"c1");
+    EXPECT_REGVAL_EQ(two, kCountsKeyName, L"c2");
+
+    TimingMetric::TimingData data1 = { 2, 0, 1500, 500, 1000 };  
+    TimingMetric::TimingData data2 = { 2, 0, 2030, 30, 2000 };  
+    EXPECT_REGVAL_EQ(data1, kTimingsKeyName, L"t1");
+    EXPECT_REGVAL_EQ(data2, kTimingsKeyName, L"t2");
+
+    EXPECT_REGVAL_EQ(one, kIntegersKeyName, L"i1");
+    EXPECT_REGVAL_EQ(two, kIntegersKeyName, L"i2");
+
+    int32 bool_true = 1, bool_false = 0;
+    EXPECT_REGVAL_EQ(bool_true, kBoolsKeyName, L"b1");
+    EXPECT_REGVAL_EQ(bool_false, kBoolsKeyName, L"b2");
+  }
+  
+  AddStats();  
+  EXPECT_TRUE(agg.AggregateMetrics());  
+
+  {
+    int64 two = 2, four = 4;
+    EXPECT_REGVAL_EQ(two, kCountsKeyName, L"c1");
+    EXPECT_REGVAL_EQ(four, kCountsKeyName, L"c2");
+
+    TimingMetric::TimingData data1 = { 4, 0, 3000, 500, 1000 };  
+    TimingMetric::TimingData data2 = { 4, 0, 4060, 30, 2000 };  
+    EXPECT_REGVAL_EQ(data1, kTimingsKeyName, L"t1");
+    EXPECT_REGVAL_EQ(data2, kTimingsKeyName, L"t2");
+
+    int64 one = 1;
+    EXPECT_REGVAL_EQ(one, kIntegersKeyName, L"i1");
+    EXPECT_REGVAL_EQ(two, kIntegersKeyName, L"i2");
+
+    int32 bool_true = 1, bool_false = 0;
+    EXPECT_REGVAL_EQ(bool_true, kBoolsKeyName, L"b1");
+    EXPECT_REGVAL_EQ(bool_false, kBoolsKeyName, L"b2");
+  }
+}
diff --git a/statsreport/aggregator-win32_unittest.h b/statsreport/aggregator-win32_unittest.h
index d15f23d..72eefbf 100644
--- a/statsreport/aggregator-win32_unittest.h
+++ b/statsreport/aggregator-win32_unittest.h
@@ -1,61 +1,61 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-#ifndef OMAHA_STATSREPORT_AGGREGATOR_WIN32_UNITTEST_H__

-#define OMAHA_STATSREPORT_AGGREGATOR_WIN32_UNITTEST_H__

-

-#include "aggregator_unittest.h"

-#include "aggregator-win32.h"

-

-/// Shared test fixture for win32 unit tests

-class MetricsAggregatorWin32Test: public MetricsAggregatorTest {

-public:

-  virtual void SetUp() {

-    // clean the registry

-    SHDeleteKey(HKEY_CURRENT_USER, kRootKeyName);

-    MetricsAggregatorTest::SetUp();

-  }

-  virtual void TearDown() {

-    MetricsAggregatorTest::TearDown();

-    SHDeleteKey(HKEY_CURRENT_USER, kRootKeyName);

-  }

-

-  void AddStats() {

-    ++c1_;

-    ++c2_;

-    ++c2_;

-

-    t1_.AddSample(1000);

-    t1_.AddSample(500);

-

-    t2_.AddSample(2000);

-    t2_.AddSample(30);

-

-    i1_ = 1;

-    i2_ = 2;

-

-    b1_ = true;

-    b2_ = false;

-  }

-

-  static const wchar_t kAppName[];

-  static const wchar_t kRootKeyName[];

-  static const wchar_t kCountsKeyName[];

-  static const wchar_t kTimingsKeyName[];

-  static const wchar_t kIntegersKeyName[];

-  static const wchar_t kBoolsKeyName[];

-};

-

-#endif  // OMAHA_STATSREPORT_AGGREGATOR_WIN32_UNITTEST_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+#ifndef OMAHA_STATSREPORT_AGGREGATOR_WIN32_UNITTEST_H__
+#define OMAHA_STATSREPORT_AGGREGATOR_WIN32_UNITTEST_H__
+
+#include "aggregator_unittest.h"
+#include "aggregator-win32.h"
+
+/// Shared test fixture for win32 unit tests
+class MetricsAggregatorWin32Test: public MetricsAggregatorTest {
+public:
+  virtual void SetUp() {
+    // clean the registry
+    SHDeleteKey(HKEY_CURRENT_USER, kRootKeyName);
+    MetricsAggregatorTest::SetUp();
+  }
+  virtual void TearDown() {
+    MetricsAggregatorTest::TearDown();
+    SHDeleteKey(HKEY_CURRENT_USER, kRootKeyName);
+  }
+
+  void AddStats() {
+    ++c1_;
+    ++c2_;
+    ++c2_;
+
+    t1_.AddSample(1000);
+    t1_.AddSample(500);
+
+    t2_.AddSample(2000);
+    t2_.AddSample(30);
+
+    i1_ = 1;
+    i2_ = 2;
+
+    b1_ = true;
+    b2_ = false;
+  }
+
+  static const wchar_t kAppName[];
+  static const wchar_t kRootKeyName[];
+  static const wchar_t kCountsKeyName[];
+  static const wchar_t kTimingsKeyName[];
+  static const wchar_t kIntegersKeyName[];
+  static const wchar_t kBoolsKeyName[];
+};
+
+#endif  // OMAHA_STATSREPORT_AGGREGATOR_WIN32_UNITTEST_H__
diff --git a/statsreport/aggregator.cc b/statsreport/aggregator.cc
index 7987194..754b496 100644
--- a/statsreport/aggregator.cc
+++ b/statsreport/aggregator.cc
@@ -1,77 +1,77 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Implementation of helper classes to aggregate the collected in-memory 

-// stats to persistent storage.

-#include "aggregator.h"

-

-namespace stats_report {

-

-bool MetricsAggregator::AggregateMetrics() {

-  if (!StartAggregation())

-    return false;

-  

-  MetricIterator it(coll_), end;

-  for (; it != end; ++it) {

-    MetricBase *metric = *it;

-    DCHECK(NULL != metric);

-    

-    switch (metric->type()) {

-     case kCountType:

-      Aggregate(metric->AsCount());

-      break;

-     case kTimingType:

-      Aggregate(metric->AsTiming());

-      break;

-     case kIntegerType:

-      Aggregate(metric->AsInteger());

-      break;

-     case kBoolType:

-      Aggregate(metric->AsBool());

-      break;

-     default:

-      DCHECK(false && "Impossible metric type");

-      break;

-    }

-  }

-  

-  // done, close up

-  EndAggregation();

-  

-  return true;

-}

-

-MetricsAggregator::MetricsAggregator() : coll_(g_global_metrics) {

-  DCHECK(coll_.initialized());

-}

-

-MetricsAggregator::MetricsAggregator(const MetricCollection &coll) 

-    : coll_(coll) {

-  DCHECK(coll_.initialized());

-}

-

-MetricsAggregator::~MetricsAggregator() {

-}

-

-bool MetricsAggregator::StartAggregation() {

-  // nothing

-  return true;

-}

-

-void MetricsAggregator::EndAggregation() {

-  // nothing

-}

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Implementation of helper classes to aggregate the collected in-memory 
+// stats to persistent storage.
+#include "aggregator.h"
+
+namespace stats_report {
+
+bool MetricsAggregator::AggregateMetrics() {
+  if (!StartAggregation())
+    return false;
+  
+  MetricIterator it(coll_), end;
+  for (; it != end; ++it) {
+    MetricBase *metric = *it;
+    DCHECK(NULL != metric);
+    
+    switch (metric->type()) {
+     case kCountType:
+      Aggregate(metric->AsCount());
+      break;
+     case kTimingType:
+      Aggregate(metric->AsTiming());
+      break;
+     case kIntegerType:
+      Aggregate(metric->AsInteger());
+      break;
+     case kBoolType:
+      Aggregate(metric->AsBool());
+      break;
+     default:
+      DCHECK(false && "Impossible metric type");
+      break;
+    }
+  }
+  
+  // done, close up
+  EndAggregation();
+  
+  return true;
+}
+
+MetricsAggregator::MetricsAggregator() : coll_(g_global_metrics) {
+  DCHECK(coll_.initialized());
+}
+
+MetricsAggregator::MetricsAggregator(const MetricCollection &coll) 
+    : coll_(coll) {
+  DCHECK(coll_.initialized());
+}
+
+MetricsAggregator::~MetricsAggregator() {
+}
+
+bool MetricsAggregator::StartAggregation() {
+  // nothing
+  return true;
+}
+
+void MetricsAggregator::EndAggregation() {
+  // nothing
+}
+
 } // namespace stats_report
\ No newline at end of file
diff --git a/statsreport/aggregator.h b/statsreport/aggregator.h
index 13047d5..02cec72 100644
--- a/statsreport/aggregator.h
+++ b/statsreport/aggregator.h
@@ -1,60 +1,60 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Helper class to aggregate the collected in-memory stats to persistent

-// storage.

-#ifndef OMAHA_STATSREPORT_AGGREGATOR_H__

-#define OMAHA_STATSREPORT_AGGREGATOR_H__

-

-#include "metrics.h"

-

-namespace stats_report {

-// TODO(omaha): Refactor to avoid cross platform code duplication.

-

-/// Wrapper class and interface for metrics aggregation. This is a platform

-/// independent class and needs to be subclassed for various platforms and/or

-/// metrics persistence methods

-class MetricsAggregator {

-public:

-  /// Aggregate all metrics in the associated collection

-  /// @returns true iff aggregation started successfully, false otherwise.

-  bool AggregateMetrics();

-

-protected:

-  MetricsAggregator();

-  MetricsAggregator(const MetricCollection &coll);

-  virtual ~MetricsAggregator();

-

-  /// Start aggregation. Override this to grab locks, open files, whatever

-  /// needs to happen or can expedite the individual aggregate steps.

-  /// @return true on success, false on failure.

-  /// @note aggregation will not progress if this function returns false

-  virtual bool StartAggregation();

-  virtual void EndAggregation();

-

-  virtual void Aggregate(CountMetric &metric) = 0;

-  virtual void Aggregate(TimingMetric &metric) = 0;

-  virtual void Aggregate(IntegerMetric &metric) = 0;

-  virtual void Aggregate(BoolMetric &metric) = 0;

-

-private:

-  DISALLOW_EVIL_CONSTRUCTORS(MetricsAggregator);

-

-  const MetricCollection &coll_;

-};

-

-} // namespace stats_report

-

-#endif  // OMAHA_STATSREPORT_AGGREGATOR_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Helper class to aggregate the collected in-memory stats to persistent
+// storage.
+#ifndef OMAHA_STATSREPORT_AGGREGATOR_H__
+#define OMAHA_STATSREPORT_AGGREGATOR_H__
+
+#include "metrics.h"
+
+namespace stats_report {
+// TODO(omaha): Refactor to avoid cross platform code duplication.
+
+/// Wrapper class and interface for metrics aggregation. This is a platform
+/// independent class and needs to be subclassed for various platforms and/or
+/// metrics persistence methods
+class MetricsAggregator {
+public:
+  /// Aggregate all metrics in the associated collection
+  /// @returns true iff aggregation started successfully, false otherwise.
+  bool AggregateMetrics();
+
+protected:
+  MetricsAggregator();
+  MetricsAggregator(const MetricCollection &coll);
+  virtual ~MetricsAggregator();
+
+  /// Start aggregation. Override this to grab locks, open files, whatever
+  /// needs to happen or can expedite the individual aggregate steps.
+  /// @return true on success, false on failure.
+  /// @note aggregation will not progress if this function returns false
+  virtual bool StartAggregation();
+  virtual void EndAggregation();
+
+  virtual void Aggregate(CountMetric &metric) = 0;
+  virtual void Aggregate(TimingMetric &metric) = 0;
+  virtual void Aggregate(IntegerMetric &metric) = 0;
+  virtual void Aggregate(BoolMetric &metric) = 0;
+
+private:
+  DISALLOW_EVIL_CONSTRUCTORS(MetricsAggregator);
+
+  const MetricCollection &coll_;
+};
+
+} // namespace stats_report
+
+#endif  // OMAHA_STATSREPORT_AGGREGATOR_H__
diff --git a/statsreport/aggregator_unittest.cc b/statsreport/aggregator_unittest.cc
index 73d607f..fd03319 100644
--- a/statsreport/aggregator_unittest.cc
+++ b/statsreport/aggregator_unittest.cc
@@ -1,119 +1,119 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Implementation of helper classes to aggregate the collected in-memory

-// stats to persistent storage.

-#include "aggregator.h"

-#include "aggregator_unittest.h"

-

-using namespace stats_report;

-

-class TestMetricsAggregator: public MetricsAggregator {

-public:

-  TestMetricsAggregator(MetricCollection &coll) : MetricsAggregator(coll)

-      , aggregating_(false), counts_(0), timings_(0), integers_(0), bools_(0) {

-  }

-

-  ~TestMetricsAggregator() {

-  }

-

-  bool aggregating() const { return aggregating_; }

-  int counts() const { return counts_; }

-  int timings() const { return timings_; }

-  int integers() const { return integers_; }

-  int bools() const { return bools_; }

-

-protected:

-  virtual bool StartAggregation() {

-    aggregating_ = true;

-    counts_ = 0;

-    timings_ = 0;

-    integers_ = 0;

-    bools_ = 0;

-

-    return true;

-  }

-

-  virtual void EndAggregation() {

-    aggregating_ = false;

-  }

-

-  virtual void Aggregate(CountMetric &metric) {

-    EXPECT_TRUE(aggregating());

-    metric.Reset();

-    ++counts_;

-  }

-

-  virtual void Aggregate(TimingMetric &metric) {

-    UNREFERENCED_PARAMETER(metric);

-    EXPECT_TRUE(aggregating());

-    metric.Reset();

-    ++timings_;

-  }

-  virtual void Aggregate(IntegerMetric &metric) {

-    UNREFERENCED_PARAMETER(metric);

-    EXPECT_TRUE(aggregating());

-    // Integer metrics don't get reset on aggregation

-    ++integers_;

-  }

-  virtual void Aggregate(BoolMetric &metric) {

-    EXPECT_TRUE(aggregating());

-    metric.Reset();

-    ++bools_;

-  }

-

-private:

-  bool aggregating_;

-  int counts_;

-  int timings_;

-  int integers_;

-  int bools_;

-};

-

-TEST_F(MetricsAggregatorTest, Aggregate) {

-  TestMetricsAggregator agg(coll_);

-

-  EXPECT_FALSE(agg.aggregating());

-  EXPECT_EQ(0, agg.counts());

-  EXPECT_EQ(0, agg.timings());

-  EXPECT_EQ(0, agg.integers());

-  EXPECT_EQ(0, agg.bools());

-  EXPECT_TRUE(agg.AggregateMetrics());

-  EXPECT_FALSE(agg.aggregating());

-

-  // check that we saw all counters.

-  EXPECT_TRUE(kNumCounts == agg.counts());

-  EXPECT_TRUE(kNumTimings == agg.timings());

-  EXPECT_TRUE(kNumIntegers == agg.integers());

-  EXPECT_TRUE(kNumBools == agg.bools());

-}

-

-class FailureTestMetricsAggregator: public TestMetricsAggregator {

-public:

-  FailureTestMetricsAggregator(MetricCollection &coll) :

-      TestMetricsAggregator(coll) {

-  }

-

-protected:

-  virtual bool StartAggregation() {

-    return false;

-  }

-};

-

-TEST_F(MetricsAggregatorTest, AggregateFailure) {

-  FailureTestMetricsAggregator agg(coll_);

-

-  EXPECT_FALSE(agg.AggregateMetrics());

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Implementation of helper classes to aggregate the collected in-memory
+// stats to persistent storage.
+#include "aggregator.h"
+#include "aggregator_unittest.h"
+
+using namespace stats_report;
+
+class TestMetricsAggregator: public MetricsAggregator {
+public:
+  TestMetricsAggregator(MetricCollection &coll) : MetricsAggregator(coll)
+      , aggregating_(false), counts_(0), timings_(0), integers_(0), bools_(0) {
+  }
+
+  ~TestMetricsAggregator() {
+  }
+
+  bool aggregating() const { return aggregating_; }
+  int counts() const { return counts_; }
+  int timings() const { return timings_; }
+  int integers() const { return integers_; }
+  int bools() const { return bools_; }
+
+protected:
+  virtual bool StartAggregation() {
+    aggregating_ = true;
+    counts_ = 0;
+    timings_ = 0;
+    integers_ = 0;
+    bools_ = 0;
+
+    return true;
+  }
+
+  virtual void EndAggregation() {
+    aggregating_ = false;
+  }
+
+  virtual void Aggregate(CountMetric &metric) {
+    EXPECT_TRUE(aggregating());
+    metric.Reset();
+    ++counts_;
+  }
+
+  virtual void Aggregate(TimingMetric &metric) {
+    UNREFERENCED_PARAMETER(metric);
+    EXPECT_TRUE(aggregating());
+    metric.Reset();
+    ++timings_;
+  }
+  virtual void Aggregate(IntegerMetric &metric) {
+    UNREFERENCED_PARAMETER(metric);
+    EXPECT_TRUE(aggregating());
+    // Integer metrics don't get reset on aggregation
+    ++integers_;
+  }
+  virtual void Aggregate(BoolMetric &metric) {
+    EXPECT_TRUE(aggregating());
+    metric.Reset();
+    ++bools_;
+  }
+
+private:
+  bool aggregating_;
+  int counts_;
+  int timings_;
+  int integers_;
+  int bools_;
+};
+
+TEST_F(MetricsAggregatorTest, Aggregate) {
+  TestMetricsAggregator agg(coll_);
+
+  EXPECT_FALSE(agg.aggregating());
+  EXPECT_EQ(0, agg.counts());
+  EXPECT_EQ(0, agg.timings());
+  EXPECT_EQ(0, agg.integers());
+  EXPECT_EQ(0, agg.bools());
+  EXPECT_TRUE(agg.AggregateMetrics());
+  EXPECT_FALSE(agg.aggregating());
+
+  // check that we saw all counters.
+  EXPECT_TRUE(kNumCounts == agg.counts());
+  EXPECT_TRUE(kNumTimings == agg.timings());
+  EXPECT_TRUE(kNumIntegers == agg.integers());
+  EXPECT_TRUE(kNumBools == agg.bools());
+}
+
+class FailureTestMetricsAggregator: public TestMetricsAggregator {
+public:
+  FailureTestMetricsAggregator(MetricCollection &coll) :
+      TestMetricsAggregator(coll) {
+  }
+
+protected:
+  virtual bool StartAggregation() {
+    return false;
+  }
+};
+
+TEST_F(MetricsAggregatorTest, AggregateFailure) {
+  FailureTestMetricsAggregator agg(coll_);
+
+  EXPECT_FALSE(agg.AggregateMetrics());
+}
diff --git a/statsreport/aggregator_unittest.h b/statsreport/aggregator_unittest.h
index 0e59ff1..32d15ae 100644
--- a/statsreport/aggregator_unittest.h
+++ b/statsreport/aggregator_unittest.h
@@ -1,68 +1,68 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-#ifndef OMAHA_STATSREPORT_AGGREGATOR_UNITTEST_H__

-#define OMAHA_STATSREPORT_AGGREGATOR_UNITTEST_H__

-

-#include "metrics.h"

-#include "omaha/third_party/gtest/include/gtest/gtest.h"

-

-/// Test fixture shared among aggregator unit tests

-class MetricsAggregatorTest: public testing::Test {

-public:

-#define INIT_METRIC(type, name) name##_(#name, &coll_)

-#define DECL_METRIC(type, name) stats_report::type##Metric name##_

-

-  MetricsAggregatorTest() :

-    INIT_METRIC(Count, c1),

-    INIT_METRIC(Count, c2),

-    INIT_METRIC(Timing, t1),

-    INIT_METRIC(Timing, t2),

-    INIT_METRIC(Integer, i1),

-    INIT_METRIC(Integer, i2),

-    INIT_METRIC(Bool, b1),

-    INIT_METRIC(Bool, b2) {

-  }

-

-  enum {

-    kNumCounts = 2,

-    kNumTimings = 2,

-    kNumIntegers = 2,

-    kNumBools = 2

-  };

-

-  stats_report::MetricCollection coll_;

-  DECL_METRIC(Count, c1);

-  DECL_METRIC(Count, c2);

-  DECL_METRIC(Timing, t1);

-  DECL_METRIC(Timing, t2);

-  DECL_METRIC(Integer, i1);

-  DECL_METRIC(Integer, i2);

-  DECL_METRIC(Bool, b1);

-  DECL_METRIC(Bool, b2);

-

-#undef INIT_METRIC

-#undef DECL_METRIC

-

-  virtual void SetUp() {

-    coll_.Initialize();

-  }

-

-  virtual void TearDown() {

-    coll_.Uninitialize();

-  }

-};

-

-#endif  // OMAHA_STATSREPORT_AGGREGATOR_UNITTEST_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+#ifndef OMAHA_STATSREPORT_AGGREGATOR_UNITTEST_H__
+#define OMAHA_STATSREPORT_AGGREGATOR_UNITTEST_H__
+
+#include "metrics.h"
+#include "omaha/third_party/gtest/include/gtest/gtest.h"
+
+/// Test fixture shared among aggregator unit tests
+class MetricsAggregatorTest: public testing::Test {
+public:
+#define INIT_METRIC(type, name) name##_(#name, &coll_)
+#define DECL_METRIC(type, name) stats_report::type##Metric name##_
+
+  MetricsAggregatorTest() :
+    INIT_METRIC(Count, c1),
+    INIT_METRIC(Count, c2),
+    INIT_METRIC(Timing, t1),
+    INIT_METRIC(Timing, t2),
+    INIT_METRIC(Integer, i1),
+    INIT_METRIC(Integer, i2),
+    INIT_METRIC(Bool, b1),
+    INIT_METRIC(Bool, b2) {
+  }
+
+  enum {
+    kNumCounts = 2,
+    kNumTimings = 2,
+    kNumIntegers = 2,
+    kNumBools = 2
+  };
+
+  stats_report::MetricCollection coll_;
+  DECL_METRIC(Count, c1);
+  DECL_METRIC(Count, c2);
+  DECL_METRIC(Timing, t1);
+  DECL_METRIC(Timing, t2);
+  DECL_METRIC(Integer, i1);
+  DECL_METRIC(Integer, i2);
+  DECL_METRIC(Bool, b1);
+  DECL_METRIC(Bool, b2);
+
+#undef INIT_METRIC
+#undef DECL_METRIC
+
+  virtual void SetUp() {
+    coll_.Initialize();
+  }
+
+  virtual void TearDown() {
+    coll_.Uninitialize();
+  }
+};
+
+#endif  // OMAHA_STATSREPORT_AGGREGATOR_UNITTEST_H__
diff --git a/statsreport/build.scons b/statsreport/build.scons
index a3212b7..f8a39b9 100644
--- a/statsreport/build.scons
+++ b/statsreport/build.scons
@@ -1,41 +1,41 @@
-# Copyright 2008-2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-# Create a local clone, so the parent environment is

-# unaffected by changes made here.

-local_env = env.Clone()

-

-local_env.Append(

-    CCFLAGS = [

-        '/wd4018',  # signed/unsigned mismatch

-

-        # enumerator in switch is not explicitly handled by a case label

-        '/wd4061',

-        ],

-)

-

-inputs = [

-    'aggregator.cc',

-    'aggregator-win32.cc',

-    'const-win32.cc',

-    'formatter.cc',

-    'metrics.cc',

-    'persistent_iterator-win32.cc',

-    ]

-

-# Build these into a library.

-local_env.ComponentLibrary('statsreport', inputs)

+# Copyright 2008-2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+# Create a local clone, so the parent environment is
+# unaffected by changes made here.
+local_env = env.Clone()
+
+local_env.Append(
+    CCFLAGS = [
+        '/wd4018',  # signed/unsigned mismatch
+
+        # enumerator in switch is not explicitly handled by a case label
+        '/wd4061',
+        ],
+)
+
+inputs = [
+    'aggregator.cc',
+    'aggregator-win32.cc',
+    'const-win32.cc',
+    'formatter.cc',
+    'metrics.cc',
+    'persistent_iterator-win32.cc',
+    ]
+
+# Build these into a library.
+local_env.ComponentLibrary('statsreport', inputs)
diff --git a/statsreport/const-win32.cc b/statsreport/const-win32.cc
index 9dadc5a..265fd25 100644
--- a/statsreport/const-win32.cc
+++ b/statsreport/const-win32.cc
@@ -1,29 +1,29 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Constants for Win32 stats aggregation and uploading

-#include "const-win32.h"

-

-namespace stats_report {

-

-const wchar_t kTimingsKeyName[] = L"Timings";

-const wchar_t kCountsKeyName[] = L"Counts";

-const wchar_t kIntegersKeyName[] = L"Integers";

-const wchar_t kBooleansKeyName[] = L"Booleans";

-const wchar_t kStatsKeyFormatString[] = L"Software\\Google\\"

-                                        L"%ws\\UsageStats\\Daily";

-const wchar_t kLastTransmissionTimeValueName[] = L"LastTransmission";

-

-} // namespace stats_report 

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Constants for Win32 stats aggregation and uploading
+#include "const-win32.h"
+
+namespace stats_report {
+
+const wchar_t kTimingsKeyName[] = L"Timings";
+const wchar_t kCountsKeyName[] = L"Counts";
+const wchar_t kIntegersKeyName[] = L"Integers";
+const wchar_t kBooleansKeyName[] = L"Booleans";
+const wchar_t kStatsKeyFormatString[] = L"Software\\Google\\"
+                                        L"%ws\\UsageStats\\Daily";
+const wchar_t kLastTransmissionTimeValueName[] = L"LastTransmission";
+
+} // namespace stats_report 
diff --git a/statsreport/const-win32.h b/statsreport/const-win32.h
index ca1c578..058eda7 100644
--- a/statsreport/const-win32.h
+++ b/statsreport/const-win32.h
@@ -1,31 +1,31 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Constants for Win32 stats aggregation and uploading

-#ifndef OMAHA_STATSREPORT_CONST_WIN32_H__

-#define OMAHA_STATSREPORT_CONST_WIN32_H__

-

-namespace stats_report {

-

-extern const wchar_t kCountsKeyName[];

-extern const wchar_t kTimingsKeyName[];

-extern const wchar_t kIntegersKeyName[];

-extern const wchar_t kBooleansKeyName[];

-extern const wchar_t kStatsKeyFormatString[];

-extern const wchar_t kLastTransmissionTimeValueName[];

-

-} // namespace stats_report

-

-#endif  // OMAHA_STATSREPORT_CONST_WIN32_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Constants for Win32 stats aggregation and uploading
+#ifndef OMAHA_STATSREPORT_CONST_WIN32_H__
+#define OMAHA_STATSREPORT_CONST_WIN32_H__
+
+namespace stats_report {
+
+extern const wchar_t kCountsKeyName[];
+extern const wchar_t kTimingsKeyName[];
+extern const wchar_t kIntegersKeyName[];
+extern const wchar_t kBooleansKeyName[];
+extern const wchar_t kStatsKeyFormatString[];
+extern const wchar_t kLastTransmissionTimeValueName[];
+
+} // namespace stats_report
+
+#endif  // OMAHA_STATSREPORT_CONST_WIN32_H__
diff --git a/statsreport/formatter.cc b/statsreport/formatter.cc
index 12f9710..3ddd761 100644
--- a/statsreport/formatter.cc
+++ b/statsreport/formatter.cc
@@ -1,81 +1,81 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-//

-#include "formatter.h"

-

-namespace stats_report {

-

-Formatter::Formatter(const char *name, uint32 measurement_secs) {

-  output_ << name << "&" << measurement_secs;

-}

-

-Formatter::~Formatter() {

-}

-

-void Formatter::AddCount(const char *name, uint64 value) {

-  output_ << "&" << name << ":c=" << value;

-}

-

-void Formatter::AddTiming(const char *name, uint64 num, uint64 avg,

-                          uint64 min, uint64 max) {

-  output_ << "&" << name << ":t=" << num << ";"

-                                  << avg << ";" << min << ";" << max;

-}

-

-void Formatter::AddInteger(const char *name, uint64 value) {

-  output_ << "&" << name << ":i=" << value;

-}

-

-void Formatter::AddBoolean(const char *name, bool value) {

-  output_ << "&" << name << ":b=" << (value ? "t" : "f");

-}

-

-void Formatter::AddMetric(MetricBase *metric) {

-  switch (metric->type()) {

-    case kCountType: {

-      CountMetric &count = metric->AsCount();

-      AddCount(count.name(), count.value());

-    }

-    break;

-

-    case kTimingType: {

-      TimingMetric &timing = metric->AsTiming();

-      AddTiming(timing.name(), timing.count(), timing.average(),

-                timing.minimum(), timing.maximum());

-    }

-    break;

-

-    case kIntegerType: {

-      IntegerMetric &integer = metric->AsInteger();

-      AddInteger(integer.name(), integer.value());

-    }

-    break;

-

-    case kBoolType: {

-      BoolMetric &boolean = metric->AsBool();

-      // TODO(omaha): boolean.value() returns a TristateBoolValue. The

-      // formatter is going to serialize kBoolUnset to true.

-      DCHECK_NE(boolean.value(), BoolMetric::kBoolUnset);

-      AddBoolean(boolean.name(), boolean.value() != BoolMetric::kBoolFalse);

-    }

-    break;

-

-    default:

-      DCHECK(false && "Impossible metric type");

-  }

-}

-

-} // namespace stats_report

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+//
+#include "formatter.h"
+
+namespace stats_report {
+
+Formatter::Formatter(const char *name, uint32 measurement_secs) {
+  output_ << name << "&" << measurement_secs;
+}
+
+Formatter::~Formatter() {
+}
+
+void Formatter::AddCount(const char *name, uint64 value) {
+  output_ << "&" << name << ":c=" << value;
+}
+
+void Formatter::AddTiming(const char *name, uint64 num, uint64 avg,
+                          uint64 min, uint64 max) {
+  output_ << "&" << name << ":t=" << num << ";"
+                                  << avg << ";" << min << ";" << max;
+}
+
+void Formatter::AddInteger(const char *name, uint64 value) {
+  output_ << "&" << name << ":i=" << value;
+}
+
+void Formatter::AddBoolean(const char *name, bool value) {
+  output_ << "&" << name << ":b=" << (value ? "t" : "f");
+}
+
+void Formatter::AddMetric(MetricBase *metric) {
+  switch (metric->type()) {
+    case kCountType: {
+      CountMetric &count = metric->AsCount();
+      AddCount(count.name(), count.value());
+    }
+    break;
+
+    case kTimingType: {
+      TimingMetric &timing = metric->AsTiming();
+      AddTiming(timing.name(), timing.count(), timing.average(),
+                timing.minimum(), timing.maximum());
+    }
+    break;
+
+    case kIntegerType: {
+      IntegerMetric &integer = metric->AsInteger();
+      AddInteger(integer.name(), integer.value());
+    }
+    break;
+
+    case kBoolType: {
+      BoolMetric &boolean = metric->AsBool();
+      // TODO(omaha): boolean.value() returns a TristateBoolValue. The
+      // formatter is going to serialize kBoolUnset to true.
+      DCHECK_NE(boolean.value(), BoolMetric::kBoolUnset);
+      AddBoolean(boolean.name(), boolean.value() != BoolMetric::kBoolFalse);
+    }
+    break;
+
+    default:
+      DCHECK(false && "Impossible metric type");
+  }
+}
+
+} // namespace stats_report
diff --git a/statsreport/formatter.h b/statsreport/formatter.h
index 6a8d09e..1c1db6c 100644
--- a/statsreport/formatter.h
+++ b/statsreport/formatter.h
@@ -1,60 +1,60 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Utility class to format metrics to a string suitable for posting to

-// TB stats server.

-#ifndef OMAHA_STATSREPORT_FORMATTER_H__

-#define OMAHA_STATSREPORT_FORMATTER_H__

-

-#include "base/basictypes.h"

-#include "metrics.h"

-#include <strstream>

-

-namespace stats_report {

-

-/// A utility class that knows how to turn metrics into a string for

-/// reporting to the Toolbar stats server.

-/// This code is mostly appropriated from the toolbars stats formatter

-class Formatter {

-public:

-  /// @param name the name of the application to report stats against

-  Formatter(const char *name, uint32 measurement_secs);

-  ~Formatter();

-

-  /// Add metric to the output string

-  void AddMetric(MetricBase *metric);

-

-  /// Add typed metrics to the output string

-  /// @{

-  void AddCount(const char *name, uint64 value);

-  void AddTiming(const char *name, uint64 num, uint64 avg, uint64 min,

-                 uint64 max);

-  void AddInteger(const char *name, uint64 value);

-  void AddBoolean(const char *name, bool value);

-  /// @}

-

-  /// Terminates the output string and returns it.

-  /// It is an error to add metrics after output() is called.

-  const char *output() { output_ << std::ends; return output_.str(); }

-

-private:

-  DISALLOW_EVIL_CONSTRUCTORS(Formatter);

-

-  mutable std::strstream output_;

-};

-

-} // namespace stats_report

-

-#endif  // OMAHA_STATSREPORT_FORMATTER_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Utility class to format metrics to a string suitable for posting to
+// TB stats server.
+#ifndef OMAHA_STATSREPORT_FORMATTER_H__
+#define OMAHA_STATSREPORT_FORMATTER_H__
+
+#include "base/basictypes.h"
+#include "metrics.h"
+#include <strstream>
+
+namespace stats_report {
+
+/// A utility class that knows how to turn metrics into a string for
+/// reporting to the Toolbar stats server.
+/// This code is mostly appropriated from the toolbars stats formatter
+class Formatter {
+public:
+  /// @param name the name of the application to report stats against
+  Formatter(const char *name, uint32 measurement_secs);
+  ~Formatter();
+
+  /// Add metric to the output string
+  void AddMetric(MetricBase *metric);
+
+  /// Add typed metrics to the output string
+  /// @{
+  void AddCount(const char *name, uint64 value);
+  void AddTiming(const char *name, uint64 num, uint64 avg, uint64 min,
+                 uint64 max);
+  void AddInteger(const char *name, uint64 value);
+  void AddBoolean(const char *name, bool value);
+  /// @}
+
+  /// Terminates the output string and returns it.
+  /// It is an error to add metrics after output() is called.
+  const char *output() { output_ << std::ends; return output_.str(); }
+
+private:
+  DISALLOW_EVIL_CONSTRUCTORS(Formatter);
+
+  mutable std::strstream output_;
+};
+
+} // namespace stats_report
+
+#endif  // OMAHA_STATSREPORT_FORMATTER_H__
diff --git a/statsreport/formatter_unittest.cc b/statsreport/formatter_unittest.cc
index 8fe50e0..e23ee77 100644
--- a/statsreport/formatter_unittest.cc
+++ b/statsreport/formatter_unittest.cc
@@ -1,36 +1,36 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-#include "omaha/third_party/gtest/include/gtest/gtest.h"

-#include "formatter.h"

-

-using stats_report::Formatter;

-

-TEST(Formatter, Format) {

-  Formatter formatter("test_application", 86400);

-  

-  formatter.AddCount("count1", 10);

-  formatter.AddTiming("timing1", 2, 150, 50, 200);

-  formatter.AddInteger("integer1", 3000);

-  formatter.AddBoolean("boolean1", true);

-  formatter.AddBoolean("boolean2", false);

-  

-  EXPECT_STREQ("test_application&86400"

-               "&count1:c=10"

-               "&timing1:t=2;150;50;200"

-               "&integer1:i=3000"

-               "&boolean1:b=t"

-               "&boolean2:b=f",

-               formatter.output());

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+#include "omaha/third_party/gtest/include/gtest/gtest.h"
+#include "formatter.h"
+
+using stats_report::Formatter;
+
+TEST(Formatter, Format) {
+  Formatter formatter("test_application", 86400);
+  
+  formatter.AddCount("count1", 10);
+  formatter.AddTiming("timing1", 2, 150, 50, 200);
+  formatter.AddInteger("integer1", 3000);
+  formatter.AddBoolean("boolean1", true);
+  formatter.AddBoolean("boolean2", false);
+  
+  EXPECT_STREQ("test_application&86400"
+               "&count1:c=10"
+               "&timing1:t=2;150;50;200"
+               "&integer1:i=3000"
+               "&boolean1:b=t"
+               "&boolean2:b=f",
+               formatter.output());
 }
\ No newline at end of file
diff --git a/statsreport/metrics.cc b/statsreport/metrics.cc
index 8309901..1c80bf9 100644
--- a/statsreport/metrics.cc
+++ b/statsreport/metrics.cc
@@ -1,241 +1,241 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Implements metrics and metrics collections

-#include "omaha/statsreport/metrics.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/synchronized.h"

-

-namespace stats_report {

-// Make sure global stats collection is placed in zeroed storage so as to avoid

-// initialization order snafus.

-MetricCollectionBase g_global_metric_storage = { 0, 0 };

-MetricCollection &g_global_metrics =

-                  *static_cast<MetricCollection*>(&g_global_metric_storage);

-

-#pragma warning(push)

-// C4640: construction of local static object is not thread-safe.

-// C4073: initializers put in library initialization area.

-#pragma warning(disable : 4640 4073)

-

-// Serialize all metric manipulation and access under this lock.

-//

-// Initializes g_lock before other global objects of user defined types.

-// It assumes the program is single threaded while executing CRT startup and

-// exit code.

-#pragma init_seg(lib)

-omaha::LLock g_lock;

-#pragma warning(pop)

-

-class MetricBase::ObjectLock {

-public:

-  ObjectLock(const MetricBase *metric) : metric_(metric) {

-    metric_->Lock();

-  }

-

-  ~ObjectLock() {

-    metric_->Unlock();

-  }

-

-private:

-  MetricBase const *const metric_;

-  DISALLOW_EVIL_CONSTRUCTORS(MetricBase::ObjectLock);

-};

-

-void MetricBase::Lock() const {

-  g_lock.Lock();

-}

-

-void MetricBase::Unlock() const {

-  g_lock.Unlock();

-}

-

-MetricBase::MetricBase(const char *name,

-                       MetricType type,

-                       MetricCollectionBase *coll)

-    : name_(name), type_(type), next_(coll->first_), coll_(coll) {

-  DCHECK_NE(static_cast<MetricCollectionBase*>(NULL), coll_);

-  DCHECK_EQ(false, coll_->initialized_);

-  coll->first_ = this;

-}

-

-MetricBase::MetricBase(const char *name, MetricType type)

-    : name_(name), type_(type), next_(NULL), coll_(NULL) {

-}

-

-MetricBase::~MetricBase() {

-  if (coll_) {

-    DCHECK_EQ(this, coll_->first_);

-    DCHECK(!coll_->initialized_)

-      << "Metric destructor called without call to Uninitialize().";

-

-    coll_->first_ = next_;

-  } else {

-    DCHECK(NULL == next_);

-  }

-}

-

-void IntegerMetricBase::Set(uint64 value) {

-  ObjectLock lock(this);

-  ASSERT1(value != kint64max);

-  value_ = value;

-}

-

-uint64 IntegerMetricBase::value() const {

-  ObjectLock lock(this);

-  uint64 ret = value_;

-  ASSERT1(ret != kint64max);

-  return ret;

-}

-

-void IntegerMetricBase::Increment() {

-  ObjectLock lock(this);

-  ++value_;

-}

-

-void IntegerMetricBase::Decrement() {

-  ObjectLock lock(this);

-  --value_;

-}

-

-void IntegerMetricBase::Add(uint64 value){

-  ObjectLock lock(this);

-  value_ += value;

-}

-

-void IntegerMetricBase::Subtract(uint64 value) {

-  ObjectLock lock(this);

-  if (value_ < value)

-    value_ = 0;

-  else

-    value_ -= value;

-}

-

-uint64 CountMetric::Reset() {

-  ObjectLock lock(this);

-  uint64 ret = value_;

-  value_ = 0;

-  return ret;

-}

-

-TimingMetric::TimingData TimingMetric::Reset() {

-  ObjectLock lock(this);

-  TimingData ret = data_;

-  Clear();

-  return ret;

-}

-

-uint32 TimingMetric::count() const {

-  ObjectLock lock(this);

-  uint32 ret = data_.count;

-  return ret;

-}

-

-uint64 TimingMetric::sum() const {

-  ObjectLock lock(this);

-  uint64 ret = data_.sum;

-  return ret;

-}

-

-uint64 TimingMetric::minimum() const {

-  ObjectLock lock(this);

-  uint64 ret = data_.minimum;

-  return ret;

-}

-

-uint64 TimingMetric::maximum() const {

-  ObjectLock lock(this);

-  uint64 ret = data_.maximum;

-  return ret;

-}

-

-uint64 TimingMetric::average() const {

-  ObjectLock lock(this);

-

-  uint64 ret = 0;

-  if (0 == data_.count) {

-    DCHECK_EQ(0, data_.sum);

-  } else {

-    ret = data_.sum / data_.count;

-  }

-  return ret;

-}

-

-void TimingMetric::AddSample(uint64 time_ms) {

-  ObjectLock lock(this);

-  if (0 == data_.count) {

-    data_.minimum = time_ms;

-    data_.maximum = time_ms;

-  } else {

-    if (data_.minimum > time_ms)

-      data_.minimum = time_ms;

-    if (data_.maximum < time_ms)

-      data_.maximum = time_ms;

-  }

-  data_.count++;

-  data_.sum += time_ms;

-}

-

-void TimingMetric::AddSamples(uint64 count, uint64 total_time_ms) {

-  if (0 == count)

-    return;

-

-  uint64 time_ms = total_time_ms / count;

-

-  ObjectLock lock(this);

-  if (0 == data_.count) {

-    data_.minimum = time_ms;

-    data_.maximum = time_ms;

-  } else {

-    if (data_.minimum > time_ms)

-      data_.minimum = time_ms;

-    if (data_.maximum < time_ms)

-      data_.maximum = time_ms;

-  }

-

-  // TODO(omaha): truncation from 64 to 32 may occur here.

-  DCHECK_LE(count, kuint32max);

-  data_.count += static_cast<uint32>(count);

-  data_.sum += total_time_ms;

-}

-

-void TimingMetric::Clear() {

-  memset(&data_, 0, sizeof(data_));

-}

-

-void BoolMetric::Set(bool value) {

-  ObjectLock lock(this);

-  value_ = value ? kBoolTrue : kBoolFalse;

-}

-

-BoolMetric::TristateBoolValue BoolMetric::Reset() {

-  ObjectLock lock(this);

-  TristateBoolValue ret = value_;

-  value_ = kBoolUnset;

-  return ret;

-}

-

-void MetricCollection::Initialize() {

-  DCHECK(!initialized());

-  initialized_ = true;

-}

-

-void MetricCollection::Uninitialize() {

-  DCHECK(initialized());

-  initialized_ = false;

-}

-

-

-}  // namespace stats_report

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Implements metrics and metrics collections
+#include "omaha/statsreport/metrics.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/synchronized.h"
+
+namespace stats_report {
+// Make sure global stats collection is placed in zeroed storage so as to avoid
+// initialization order snafus.
+MetricCollectionBase g_global_metric_storage = { 0, 0 };
+MetricCollection &g_global_metrics =
+                  *static_cast<MetricCollection*>(&g_global_metric_storage);
+
+#pragma warning(push)
+// C4640: construction of local static object is not thread-safe.
+// C4073: initializers put in library initialization area.
+#pragma warning(disable : 4640 4073)
+
+// Serialize all metric manipulation and access under this lock.
+//
+// Initializes g_lock before other global objects of user defined types.
+// It assumes the program is single threaded while executing CRT startup and
+// exit code.
+#pragma init_seg(lib)
+omaha::LLock g_lock;
+#pragma warning(pop)
+
+class MetricBase::ObjectLock {
+public:
+  ObjectLock(const MetricBase *metric) : metric_(metric) {
+    metric_->Lock();
+  }
+
+  ~ObjectLock() {
+    metric_->Unlock();
+  }
+
+private:
+  MetricBase const *const metric_;
+  DISALLOW_EVIL_CONSTRUCTORS(MetricBase::ObjectLock);
+};
+
+void MetricBase::Lock() const {
+  g_lock.Lock();
+}
+
+void MetricBase::Unlock() const {
+  g_lock.Unlock();
+}
+
+MetricBase::MetricBase(const char *name,
+                       MetricType type,
+                       MetricCollectionBase *coll)
+    : name_(name), type_(type), next_(coll->first_), coll_(coll) {
+  DCHECK_NE(static_cast<MetricCollectionBase*>(NULL), coll_);
+  DCHECK_EQ(false, coll_->initialized_);
+  coll->first_ = this;
+}
+
+MetricBase::MetricBase(const char *name, MetricType type)
+    : name_(name), type_(type), next_(NULL), coll_(NULL) {
+}
+
+MetricBase::~MetricBase() {
+  if (coll_) {
+    DCHECK_EQ(this, coll_->first_);
+    DCHECK(!coll_->initialized_)
+      << "Metric destructor called without call to Uninitialize().";
+
+    coll_->first_ = next_;
+  } else {
+    DCHECK(NULL == next_);
+  }
+}
+
+void IntegerMetricBase::Set(uint64 value) {
+  ObjectLock lock(this);
+  ASSERT1(value != kint64max);
+  value_ = value;
+}
+
+uint64 IntegerMetricBase::value() const {
+  ObjectLock lock(this);
+  uint64 ret = value_;
+  ASSERT1(ret != kint64max);
+  return ret;
+}
+
+void IntegerMetricBase::Increment() {
+  ObjectLock lock(this);
+  ++value_;
+}
+
+void IntegerMetricBase::Decrement() {
+  ObjectLock lock(this);
+  --value_;
+}
+
+void IntegerMetricBase::Add(uint64 value){
+  ObjectLock lock(this);
+  value_ += value;
+}
+
+void IntegerMetricBase::Subtract(uint64 value) {
+  ObjectLock lock(this);
+  if (value_ < value)
+    value_ = 0;
+  else
+    value_ -= value;
+}
+
+uint64 CountMetric::Reset() {
+  ObjectLock lock(this);
+  uint64 ret = value_;
+  value_ = 0;
+  return ret;
+}
+
+TimingMetric::TimingData TimingMetric::Reset() {
+  ObjectLock lock(this);
+  TimingData ret = data_;
+  Clear();
+  return ret;
+}
+
+uint32 TimingMetric::count() const {
+  ObjectLock lock(this);
+  uint32 ret = data_.count;
+  return ret;
+}
+
+uint64 TimingMetric::sum() const {
+  ObjectLock lock(this);
+  uint64 ret = data_.sum;
+  return ret;
+}
+
+uint64 TimingMetric::minimum() const {
+  ObjectLock lock(this);
+  uint64 ret = data_.minimum;
+  return ret;
+}
+
+uint64 TimingMetric::maximum() const {
+  ObjectLock lock(this);
+  uint64 ret = data_.maximum;
+  return ret;
+}
+
+uint64 TimingMetric::average() const {
+  ObjectLock lock(this);
+
+  uint64 ret = 0;
+  if (0 == data_.count) {
+    DCHECK_EQ(0, data_.sum);
+  } else {
+    ret = data_.sum / data_.count;
+  }
+  return ret;
+}
+
+void TimingMetric::AddSample(uint64 time_ms) {
+  ObjectLock lock(this);
+  if (0 == data_.count) {
+    data_.minimum = time_ms;
+    data_.maximum = time_ms;
+  } else {
+    if (data_.minimum > time_ms)
+      data_.minimum = time_ms;
+    if (data_.maximum < time_ms)
+      data_.maximum = time_ms;
+  }
+  data_.count++;
+  data_.sum += time_ms;
+}
+
+void TimingMetric::AddSamples(uint64 count, uint64 total_time_ms) {
+  if (0 == count)
+    return;
+
+  uint64 time_ms = total_time_ms / count;
+
+  ObjectLock lock(this);
+  if (0 == data_.count) {
+    data_.minimum = time_ms;
+    data_.maximum = time_ms;
+  } else {
+    if (data_.minimum > time_ms)
+      data_.minimum = time_ms;
+    if (data_.maximum < time_ms)
+      data_.maximum = time_ms;
+  }
+
+  // TODO(omaha): truncation from 64 to 32 may occur here.
+  DCHECK_LE(count, kuint32max);
+  data_.count += static_cast<uint32>(count);
+  data_.sum += total_time_ms;
+}
+
+void TimingMetric::Clear() {
+  memset(&data_, 0, sizeof(data_));
+}
+
+void BoolMetric::Set(bool value) {
+  ObjectLock lock(this);
+  value_ = value ? kBoolTrue : kBoolFalse;
+}
+
+BoolMetric::TristateBoolValue BoolMetric::Reset() {
+  ObjectLock lock(this);
+  TristateBoolValue ret = value_;
+  value_ = kBoolUnset;
+  return ret;
+}
+
+void MetricCollection::Initialize() {
+  DCHECK(!initialized());
+  initialized_ = true;
+}
+
+void MetricCollection::Uninitialize() {
+  DCHECK(initialized());
+  initialized_ = false;
+}
+
+
+}  // namespace stats_report
diff --git a/statsreport/metrics.h b/statsreport/metrics.h
index 994ca58..87a2369 100644
--- a/statsreport/metrics.h
+++ b/statsreport/metrics.h
@@ -1,539 +1,539 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Declares the interface to in-memory metrics capture

-#ifndef OMAHA_STATSREPORT_METRICS_H__

-#define OMAHA_STATSREPORT_METRICS_H__

-

-#include <iterator>

-#include "base/basictypes.h"

-#include "omaha/common/highres_timer-win32.h"

-#include "omaha/common/logging/logging.h"

-

-/// Macros to declare & define named & typed metrics.

-/// Put declarations in headers or in cpp files, where you need access

-/// to the metrics. For each declared metric, there must be precisely

-/// one definition in a compilation unit someplace.

-

-/// A count metric should be used to report anything that monotonically

-/// increases.

-/// Examples:

-///    # event count

-///      how often does this condition hit, this function get called

-///    # aggregate sums

-///      how many bytes are written

-#define DECLARE_METRIC_count(name)   DECLARE_METRIC(CountMetric, name)

-#define DEFINE_METRIC_count(name)   DEFINE_METRIC(CountMetric, name)

-

-/// Use timing metrics to report on the performance of important things.

-/// A timing metric will report the count of occurrences, as well as the

-/// average, min and max times.

-/// Samples are measured in milliseconds if you use the TIME_SCOPE macro

-/// or the HighResTimer class to collect samples.

-#define DECLARE_METRIC_timing(name)  DECLARE_METRIC(TimingMetric, name)

-#define DEFINE_METRIC_timing(name)  DEFINE_METRIC(TimingMetric, name)

-

-/// Collects a sample from here to the end of the current scope, and

-/// adds the sample to the timing metric supplied

-#define TIME_SCOPE(timing) \

-  stats_report::TimingSample __xxsample__(timing)

-

-/// Use integer metrics to report runtime values that fluctuate.

-/// Examples:

-///    # object count

-///      How many objects of some type exist

-///    # disk space or memory

-///      How much disk space or memory is in use

-#define DECLARE_METRIC_integer(name) DECLARE_METRIC(IntegerMetric, name)

-#define DEFINE_METRIC_integer(name) DEFINE_METRIC(IntegerMetric, name)

-

-

-/// Use boolean metrics to report the occurrence of important but rare events

-/// or conditions. Note that a boolean metric is tri-state, so you typically

-/// want to set it only in one direction, and typically to true.

-/// Setting a boolean metric one way or another on a trigger event will report

-/// the setting of the boolean immediately prior to reporting, which is

-/// typically not what you want.

-#define DECLARE_METRIC_bool(name)    DECLARE_METRIC(BoolMetric, name)

-#define DEFINE_METRIC_bool(name)    DEFINE_METRIC(BoolMetric, name)

-

-

-/// Implementation macros

-#define DECLARE_METRIC(type, name) \

-  namespace omaha_client_statsreport { \

-  extern stats_report::type metric_##name; \

-  } \

-  using omaha_client_statsreport::metric_##name

-

-#define DEFINE_METRIC(type, name) \

-  namespace omaha_client_statsreport { \

-  stats_report::type metric_##name(#name, \

-  &stats_report::g_global_metric_storage); \

-  } \

-  using omaha_client_statsreport::metric_##name

-

-

-namespace stats_report {

-

-enum MetricType {

-  // use zero for invalid, because global storage defaults to zero

-  kInvalidType = 0,

-  kCountType,

-  kTimingType,

-  kIntegerType,

-  kBoolType

-};

-

-// fwd.

-struct MetricCollectionBase;

-class MetricCollection;

-class MetricBase;

-class IntegerMetricBase;

-class CountMetric;

-class TimingMetric;

-class IntegerMetric;

-class BoolMetric;

-

-/// Base class for all stats instances.

-/// Stats instances are chained together against a MetricCollection to

-/// allow enumerating stats.

-///

-/// MetricCollection is factored into a class to make it easier to unittest

-/// the implementation.

-class MetricBase {

-public:

-  /// @name Downcasts

-  /// @{

-  CountMetric &AsCount();

-  TimingMetric &AsTiming();

-  IntegerMetric &AsInteger();

-  BoolMetric &AsBool();

-

-  const CountMetric &AsCount() const;

-  const TimingMetric &AsTiming() const;

-  const IntegerMetric &AsInteger() const;

-  const BoolMetric &AsBool() const;

-  /// @}

-

-  /// @name Accessors

-  /// @{

-  MetricType type() const { return type_; }

-  MetricBase *next() const { return next_; }

-  const char *name() const { return name_; }

-  /// @}

-

-  // TODO(omaha): does this need to be virtual?

-  virtual ~MetricBase() = 0;

-

-protected:

-  class ObjectLock;

-  void Lock() const;

-  void Unlock() const;

-

-  /// Constructs a MetricBase and adds to the provided MetricCollection.

-  /// @note Metrics can only be constructed up to the point where the

-  ///     MetricCollection is initialized, and there's no locking performed.

-  ///     The assumption is that outside unit tests, Metrics will we declared

-  ///     as static/global variables, and initialized at static initialization

-  ///     time - and static initialization is single-threaded.

-  MetricBase(const char *name, MetricType type, MetricCollectionBase *coll);

-

-  /// Constructs a named typed MetricBase

-  MetricBase(const char *name, MetricType type);

-

-  /// Our name

-  char const *const name_;

-

-  /// type of this metric

-  MetricType const type_;

-

-  /// chains to next stat instance

-  MetricBase *const next_;

-

-  /// The collection we're created against

-  MetricCollectionBase *const coll_;

-

-private:

-  DISALLOW_EVIL_CONSTRUCTORS(MetricBase);

-};

-

-/// Must be a POD

-struct MetricCollectionBase {

-  bool initialized_;

-  MetricBase *first_;

-};

-

-/// Inherit from base, which is a POD and can be initialized at link time.

-///

-/// The global MetricCollection is aliased to a link-time initialized

-/// instance of MetricCollectionBase, and must not extend the size of its

-/// base class.

-class MetricCollection: public MetricCollectionBase {

-public:

-  MetricCollection() {

-    initialized_ = false;

-    first_ = NULL;

-  }

-  ~MetricCollection() {

-    DCHECK(NULL == first_);

-  }

-

-  /// Initialize must be called after all metrics have been added to the

-  /// collection, but before enumerating it for e.g. aggregation or reporting.

-  /// The intent is that outside unit tests, there will only be the global

-  /// metrics collection, which will accrue all metrics defined with the

-  /// DEFINE_METRIC_* macros.

-  /// Typically you'd call Initialize very early in your main function, and

-  /// Uninitialize towards the end of main.

-  /// It is an error to Initialize() when the collection is initialized().

-  void Initialize();

-

-  /// Uninitialize must be called before removing (deleting or deconstructing)

-  /// metrics from the collection.

-  /// It is an error to Uninitialize() when the collection is !initialized().

-  void Uninitialize();

-

-  MetricBase *first() const { return first_; }

-  bool initialized() const { return initialized_; }

-

-private:

-  using MetricCollectionBase::initialized_;

-  using MetricCollectionBase::first_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(MetricCollection);

-

-  /// MetricBase is intimate with us

-  friend class MetricBase;

-};

-

-/// Implements a forward_iterator for MetricCollection.

-class MetricIterator: public std::iterator<std::forward_iterator_tag,

-                                           MetricBase *> {

-public:

-  MetricIterator() : curr_(NULL) {

-  }

-  MetricIterator(const MetricIterator &other) : curr_(other.curr_) {

-  }

-  MetricIterator(const MetricCollection &coll) : curr_(coll.first()) {

-    DCHECK(coll.initialized());

-  }

-

-  MetricBase *operator*() const {

-    return curr_;

-  }

-  MetricBase *operator->() const {

-    return curr_;

-  }

-  MetricIterator operator++() { // preincrement

-    if (curr_)

-      curr_ = curr_->next();

-

-    return (*this);

-  }

-  MetricIterator operator++(int) {// postincrement

-    MetricIterator ret = *this;

-    ++*this;

-    return (ret);

-  }

-

-private:

-  MetricBase *curr_;

-};

-

-inline bool operator == (const MetricIterator &a, const MetricIterator &b) {

-  return *a == *b;

-}

-inline bool operator != (const MetricIterator &a, const MetricIterator &b) {

-  return !operator == (a, b);

-}

-

-/// Globally defined counters are registered here

-extern MetricCollectionBase g_global_metric_storage;

-

-/// And more conveniently accessed through here

-extern MetricCollection &g_global_metrics;

-

-/// Base class for integer metrics

-class IntegerMetricBase: public MetricBase {

-public:

-  /// Sets the current value

-  void Set(uint64 value);

-

-  /// Retrieves the current value

-  uint64 value() const;

-

-  void operator ++ ()     { Increment(); }

-  void operator ++ (int)  { Increment(); }

-  void operator += (uint64 addend) { Add(addend); }

-

-protected:

-  IntegerMetricBase(const char *name,

-                    MetricType type,

-                    MetricCollectionBase *coll)

-      : MetricBase(name, type, coll), value_(0) {

-  }

-  IntegerMetricBase(const char *name, MetricType type, uint64 value)

-      : MetricBase(name, type), value_(value) {

-  }

-

-  void Increment();

-  void Decrement();

-  void Add(uint64 value);

-  void Subtract(uint64 value);

-

-  uint64 value_;

-

-private:

-  DISALLOW_EVIL_CONSTRUCTORS(IntegerMetricBase);

-};

-

-/// A count metric is a cumulative counter of events.

-class CountMetric: public IntegerMetricBase {

-public:

-  CountMetric(const char *name, MetricCollectionBase *coll)

-      : IntegerMetricBase(name, kCountType, coll) {

-  }

-

-  CountMetric(const char *name, uint64 value)

-      : IntegerMetricBase(name, kCountType, value) {

-  }

-

-  /// Nulls the metric and returns the current values.

-  uint64 Reset();

-

-private:

-  DISALLOW_EVIL_CONSTRUCTORS(CountMetric);

-};

-

-class TimingMetric: public MetricBase {

-public:

-  struct TimingData {

-    uint32 count;

-    uint32 align; // allow access to the alignment gap between count and sum,

-                  // makes it esier to unittest.

-    uint64 sum; // ms

-    uint64 minimum; // ms

-    uint64 maximum; // ms

-  };

-

-  TimingMetric(const char *name, MetricCollectionBase *coll)

-      : MetricBase(name, kTimingType, coll) {

-    Clear();

-  }

-

-  TimingMetric(const char *name, const TimingData &value)

-      : MetricBase(name, kTimingType), data_(value) {

-  }

-

-  uint32 count() const;

-  uint64 sum() const;

-  uint64 minimum() const;

-  uint64 maximum() const;

-  uint64 average() const;

-

-  /// Adds a single sample to the metric

-  /// @param time_ms time (in milliseconds) for this sample

-  void AddSample(uint64 time_ms);

-

-  /// Adds count samples to the metric

-  /// @note use this when capturing time over a variable number of items to

-  ///     normalize e.g. download time per byte or KB. This records one sample

-  ///     over count items, which is numerically more stable for the average

-  ///     than dividing the captured time by the item count. As a side benefit

-  ///     the timer will also record the item count.

-  /// @note if count == 0, no sample will be recorded

-  /// @param count number of samples to add

-  /// @param total_time_ms the total time consumed by all the "count" samples

-  void AddSamples(uint64 count, uint64 total_time_ms);

-

-  /// Nulls the metric and returns the current values.

-  TimingData Reset();

-

-private:

-  DISALLOW_EVIL_CONSTRUCTORS(TimingMetric);

-

-  void Clear();

-

-  TimingData data_;

-};

-

-/// A convenience class to sample the time from construction to destruction

-/// against a given timing metric.

-class TimingSample {

-public:

-  /// @param timing the metric the sample is to be tallied against

-  explicit TimingSample(TimingMetric &timing) : timing_(timing), count_(1) {

-  }

-

-  /// @param timing the metric the sample is to be tallied against

-  /// @param item_count count of items processed, used to divide the sampled

-  ///     time so as to capture time per item, which is often a better measure

-  ///     than the total time over a varying number of items.

-  TimingSample(TimingMetric &timing, uint32 item_count) : timing_(timing),

-      count_(item_count) {

-  }

-

-  ~TimingSample() {

-    // We discard samples with a zero count

-    if(count_ == 1)

-      timing_.AddSample(timer_.GetElapsedMs());

-    else

-      timing_.AddSamples(count_, timer_.GetElapsedMs());

-  }

-

-  /// @name Accessors

-  /// @{

-  uint32 count() const { return count_; }

-  void set_count(uint32 count) { count_ = count; }

-  /// @}

-

-private:

-  /// Collects the sample for us.

-  omaha::HighresTimer timer_;

-

-  /// The metric we tally against.

-  TimingMetric &timing_;

-

-  /// The item count we divide the captured time by

-  uint32 count_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(TimingSample);

-};

-

-/// An integer metric is used to sample values that vary over time.

-/// On aggregation the instantaneous value of the integer metric is captured.

-class IntegerMetric: public IntegerMetricBase {

-public:

-  IntegerMetric(const char *name, MetricCollectionBase *coll)

-      : IntegerMetricBase(name, kIntegerType, coll) {

-  }

-

-  IntegerMetric(const char *name, uint64 value)

-      : IntegerMetricBase(name, kIntegerType, value) {

-  }

-

-  void operator = (uint64 value)   { Set(value); }

-

-  void operator -- ()     { Decrement(); }

-  void operator -- (int)  { Decrement(); }

-  void operator -= (uint64 sub)    { Subtract(sub); }

-

-private:

-  DISALLOW_EVIL_CONSTRUCTORS(IntegerMetric);

-};

-

-/// A bool metric is tri-state, and can be:

-///    - unset,

-///    - true or

-///    - false

-/// to match other metrics, which are implicitly unset if they've not changed

-/// from their initial value.

-class BoolMetric: public MetricBase {

-public:

-  /// Values we can take

-  enum TristateBoolValue {

-    kBoolUnset = -1,

-    kBoolFalse,

-    kBoolTrue,

-  };

-

-  BoolMetric(const char *name, MetricCollectionBase *coll)

-        : MetricBase(name, kBoolType, coll), value_(kBoolUnset) {

-  }

-

-  BoolMetric(const char *name, uint32 value)

-        : MetricBase(name, kBoolType) {

-    switch (value) {

-     case kBoolFalse:

-     case kBoolTrue:

-      value_ = static_cast<TristateBoolValue>(value);

-      break;

-

-     default:

-      DCHECK(false && "Unexpected tristate bool value on construction");

-      value_ = kBoolUnset;

-    }

-  }

-

-  /// Sets the flag to the provided value.

-  void Set(bool value);

-

-  void operator = (bool value) {

-    Set(value);

-  }

-

-  /// Nulls the metric and returns the current values.

-  TristateBoolValue Reset();

-

-  /// Returns the current value - not threadsafe

-  TristateBoolValue value() const { return value_; };

-

-private:

-  DISALLOW_EVIL_CONSTRUCTORS(BoolMetric);

-

-  TristateBoolValue value_;

-};

-

-inline CountMetric &MetricBase::AsCount() {

-  DCHECK_EQ(kCountType, type());

-

-  return static_cast<CountMetric&>(*this);

-}

-

-inline TimingMetric &MetricBase::AsTiming() {

-  DCHECK_EQ(kTimingType, type());

-

-  return static_cast<TimingMetric&>(*this);

-}

-

-inline IntegerMetric &MetricBase::AsInteger() {

-  DCHECK_EQ(kIntegerType, type());

-

-  return static_cast<IntegerMetric&>(*this);

-}

-

-inline BoolMetric &MetricBase::AsBool() {

-  DCHECK_EQ(kBoolType, type());

-

-  return static_cast<BoolMetric&>(*this);

-}

-

-inline const CountMetric &MetricBase::AsCount() const {

-  DCHECK_EQ(kCountType, type());

-

-  return static_cast<const CountMetric&>(*this);

-}

-

-inline const TimingMetric &MetricBase::AsTiming() const {

-  DCHECK_EQ(kTimingType, type());

-

-  return static_cast<const TimingMetric&>(*this);

-}

-

-inline const IntegerMetric &MetricBase::AsInteger() const {

-  DCHECK_EQ(kIntegerType, type());

-

-  return static_cast<const IntegerMetric&>(*this);

-}

-

-inline const BoolMetric &MetricBase::AsBool() const {

-  DCHECK_EQ(kBoolType, type());

-

-  return static_cast<const BoolMetric&>(*this);

-}

-

-} // namespace stats_report

-

-#endif  // OMAHA_STATSREPORT_METRICS_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Declares the interface to in-memory metrics capture
+#ifndef OMAHA_STATSREPORT_METRICS_H__
+#define OMAHA_STATSREPORT_METRICS_H__
+
+#include <iterator>
+#include "base/basictypes.h"
+#include "omaha/common/highres_timer-win32.h"
+#include "omaha/common/logging/logging.h"
+
+/// Macros to declare & define named & typed metrics.
+/// Put declarations in headers or in cpp files, where you need access
+/// to the metrics. For each declared metric, there must be precisely
+/// one definition in a compilation unit someplace.
+
+/// A count metric should be used to report anything that monotonically
+/// increases.
+/// Examples:
+///    # event count
+///      how often does this condition hit, this function get called
+///    # aggregate sums
+///      how many bytes are written
+#define DECLARE_METRIC_count(name)   DECLARE_METRIC(CountMetric, name)
+#define DEFINE_METRIC_count(name)   DEFINE_METRIC(CountMetric, name)
+
+/// Use timing metrics to report on the performance of important things.
+/// A timing metric will report the count of occurrences, as well as the
+/// average, min and max times.
+/// Samples are measured in milliseconds if you use the TIME_SCOPE macro
+/// or the HighResTimer class to collect samples.
+#define DECLARE_METRIC_timing(name)  DECLARE_METRIC(TimingMetric, name)
+#define DEFINE_METRIC_timing(name)  DEFINE_METRIC(TimingMetric, name)
+
+/// Collects a sample from here to the end of the current scope, and
+/// adds the sample to the timing metric supplied
+#define TIME_SCOPE(timing) \
+  stats_report::TimingSample __xxsample__(timing)
+
+/// Use integer metrics to report runtime values that fluctuate.
+/// Examples:
+///    # object count
+///      How many objects of some type exist
+///    # disk space or memory
+///      How much disk space or memory is in use
+#define DECLARE_METRIC_integer(name) DECLARE_METRIC(IntegerMetric, name)
+#define DEFINE_METRIC_integer(name) DEFINE_METRIC(IntegerMetric, name)
+
+
+/// Use boolean metrics to report the occurrence of important but rare events
+/// or conditions. Note that a boolean metric is tri-state, so you typically
+/// want to set it only in one direction, and typically to true.
+/// Setting a boolean metric one way or another on a trigger event will report
+/// the setting of the boolean immediately prior to reporting, which is
+/// typically not what you want.
+#define DECLARE_METRIC_bool(name)    DECLARE_METRIC(BoolMetric, name)
+#define DEFINE_METRIC_bool(name)    DEFINE_METRIC(BoolMetric, name)
+
+
+/// Implementation macros
+#define DECLARE_METRIC(type, name) \
+  namespace omaha_client_statsreport { \
+  extern stats_report::type metric_##name; \
+  } \
+  using omaha_client_statsreport::metric_##name
+
+#define DEFINE_METRIC(type, name) \
+  namespace omaha_client_statsreport { \
+  stats_report::type metric_##name(#name, \
+  &stats_report::g_global_metric_storage); \
+  } \
+  using omaha_client_statsreport::metric_##name
+
+
+namespace stats_report {
+
+enum MetricType {
+  // use zero for invalid, because global storage defaults to zero
+  kInvalidType = 0,
+  kCountType,
+  kTimingType,
+  kIntegerType,
+  kBoolType
+};
+
+// fwd.
+struct MetricCollectionBase;
+class MetricCollection;
+class MetricBase;
+class IntegerMetricBase;
+class CountMetric;
+class TimingMetric;
+class IntegerMetric;
+class BoolMetric;
+
+/// Base class for all stats instances.
+/// Stats instances are chained together against a MetricCollection to
+/// allow enumerating stats.
+///
+/// MetricCollection is factored into a class to make it easier to unittest
+/// the implementation.
+class MetricBase {
+public:
+  /// @name Downcasts
+  /// @{
+  CountMetric &AsCount();
+  TimingMetric &AsTiming();
+  IntegerMetric &AsInteger();
+  BoolMetric &AsBool();
+
+  const CountMetric &AsCount() const;
+  const TimingMetric &AsTiming() const;
+  const IntegerMetric &AsInteger() const;
+  const BoolMetric &AsBool() const;
+  /// @}
+
+  /// @name Accessors
+  /// @{
+  MetricType type() const { return type_; }
+  MetricBase *next() const { return next_; }
+  const char *name() const { return name_; }
+  /// @}
+
+  // TODO(omaha): does this need to be virtual?
+  virtual ~MetricBase() = 0;
+
+protected:
+  class ObjectLock;
+  void Lock() const;
+  void Unlock() const;
+
+  /// Constructs a MetricBase and adds to the provided MetricCollection.
+  /// @note Metrics can only be constructed up to the point where the
+  ///     MetricCollection is initialized, and there's no locking performed.
+  ///     The assumption is that outside unit tests, Metrics will we declared
+  ///     as static/global variables, and initialized at static initialization
+  ///     time - and static initialization is single-threaded.
+  MetricBase(const char *name, MetricType type, MetricCollectionBase *coll);
+
+  /// Constructs a named typed MetricBase
+  MetricBase(const char *name, MetricType type);
+
+  /// Our name
+  char const *const name_;
+
+  /// type of this metric
+  MetricType const type_;
+
+  /// chains to next stat instance
+  MetricBase *const next_;
+
+  /// The collection we're created against
+  MetricCollectionBase *const coll_;
+
+private:
+  DISALLOW_EVIL_CONSTRUCTORS(MetricBase);
+};
+
+/// Must be a POD
+struct MetricCollectionBase {
+  bool initialized_;
+  MetricBase *first_;
+};
+
+/// Inherit from base, which is a POD and can be initialized at link time.
+///
+/// The global MetricCollection is aliased to a link-time initialized
+/// instance of MetricCollectionBase, and must not extend the size of its
+/// base class.
+class MetricCollection: public MetricCollectionBase {
+public:
+  MetricCollection() {
+    initialized_ = false;
+    first_ = NULL;
+  }
+  ~MetricCollection() {
+    DCHECK(NULL == first_);
+  }
+
+  /// Initialize must be called after all metrics have been added to the
+  /// collection, but before enumerating it for e.g. aggregation or reporting.
+  /// The intent is that outside unit tests, there will only be the global
+  /// metrics collection, which will accrue all metrics defined with the
+  /// DEFINE_METRIC_* macros.
+  /// Typically you'd call Initialize very early in your main function, and
+  /// Uninitialize towards the end of main.
+  /// It is an error to Initialize() when the collection is initialized().
+  void Initialize();
+
+  /// Uninitialize must be called before removing (deleting or deconstructing)
+  /// metrics from the collection.
+  /// It is an error to Uninitialize() when the collection is !initialized().
+  void Uninitialize();
+
+  MetricBase *first() const { return first_; }
+  bool initialized() const { return initialized_; }
+
+private:
+  using MetricCollectionBase::initialized_;
+  using MetricCollectionBase::first_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(MetricCollection);
+
+  /// MetricBase is intimate with us
+  friend class MetricBase;
+};
+
+/// Implements a forward_iterator for MetricCollection.
+class MetricIterator: public std::iterator<std::forward_iterator_tag,
+                                           MetricBase *> {
+public:
+  MetricIterator() : curr_(NULL) {
+  }
+  MetricIterator(const MetricIterator &other) : curr_(other.curr_) {
+  }
+  MetricIterator(const MetricCollection &coll) : curr_(coll.first()) {
+    DCHECK(coll.initialized());
+  }
+
+  MetricBase *operator*() const {
+    return curr_;
+  }
+  MetricBase *operator->() const {
+    return curr_;
+  }
+  MetricIterator operator++() { // preincrement
+    if (curr_)
+      curr_ = curr_->next();
+
+    return (*this);
+  }
+  MetricIterator operator++(int) {// postincrement
+    MetricIterator ret = *this;
+    ++*this;
+    return (ret);
+  }
+
+private:
+  MetricBase *curr_;
+};
+
+inline bool operator == (const MetricIterator &a, const MetricIterator &b) {
+  return *a == *b;
+}
+inline bool operator != (const MetricIterator &a, const MetricIterator &b) {
+  return !operator == (a, b);
+}
+
+/// Globally defined counters are registered here
+extern MetricCollectionBase g_global_metric_storage;
+
+/// And more conveniently accessed through here
+extern MetricCollection &g_global_metrics;
+
+/// Base class for integer metrics
+class IntegerMetricBase: public MetricBase {
+public:
+  /// Sets the current value
+  void Set(uint64 value);
+
+  /// Retrieves the current value
+  uint64 value() const;
+
+  void operator ++ ()     { Increment(); }
+  void operator ++ (int)  { Increment(); }
+  void operator += (uint64 addend) { Add(addend); }
+
+protected:
+  IntegerMetricBase(const char *name,
+                    MetricType type,
+                    MetricCollectionBase *coll)
+      : MetricBase(name, type, coll), value_(0) {
+  }
+  IntegerMetricBase(const char *name, MetricType type, uint64 value)
+      : MetricBase(name, type), value_(value) {
+  }
+
+  void Increment();
+  void Decrement();
+  void Add(uint64 value);
+  void Subtract(uint64 value);
+
+  uint64 value_;
+
+private:
+  DISALLOW_EVIL_CONSTRUCTORS(IntegerMetricBase);
+};
+
+/// A count metric is a cumulative counter of events.
+class CountMetric: public IntegerMetricBase {
+public:
+  CountMetric(const char *name, MetricCollectionBase *coll)
+      : IntegerMetricBase(name, kCountType, coll) {
+  }
+
+  CountMetric(const char *name, uint64 value)
+      : IntegerMetricBase(name, kCountType, value) {
+  }
+
+  /// Nulls the metric and returns the current values.
+  uint64 Reset();
+
+private:
+  DISALLOW_EVIL_CONSTRUCTORS(CountMetric);
+};
+
+class TimingMetric: public MetricBase {
+public:
+  struct TimingData {
+    uint32 count;
+    uint32 align; // allow access to the alignment gap between count and sum,
+                  // makes it esier to unittest.
+    uint64 sum; // ms
+    uint64 minimum; // ms
+    uint64 maximum; // ms
+  };
+
+  TimingMetric(const char *name, MetricCollectionBase *coll)
+      : MetricBase(name, kTimingType, coll) {
+    Clear();
+  }
+
+  TimingMetric(const char *name, const TimingData &value)
+      : MetricBase(name, kTimingType), data_(value) {
+  }
+
+  uint32 count() const;
+  uint64 sum() const;
+  uint64 minimum() const;
+  uint64 maximum() const;
+  uint64 average() const;
+
+  /// Adds a single sample to the metric
+  /// @param time_ms time (in milliseconds) for this sample
+  void AddSample(uint64 time_ms);
+
+  /// Adds count samples to the metric
+  /// @note use this when capturing time over a variable number of items to
+  ///     normalize e.g. download time per byte or KB. This records one sample
+  ///     over count items, which is numerically more stable for the average
+  ///     than dividing the captured time by the item count. As a side benefit
+  ///     the timer will also record the item count.
+  /// @note if count == 0, no sample will be recorded
+  /// @param count number of samples to add
+  /// @param total_time_ms the total time consumed by all the "count" samples
+  void AddSamples(uint64 count, uint64 total_time_ms);
+
+  /// Nulls the metric and returns the current values.
+  TimingData Reset();
+
+private:
+  DISALLOW_EVIL_CONSTRUCTORS(TimingMetric);
+
+  void Clear();
+
+  TimingData data_;
+};
+
+/// A convenience class to sample the time from construction to destruction
+/// against a given timing metric.
+class TimingSample {
+public:
+  /// @param timing the metric the sample is to be tallied against
+  explicit TimingSample(TimingMetric &timing) : timing_(timing), count_(1) {
+  }
+
+  /// @param timing the metric the sample is to be tallied against
+  /// @param item_count count of items processed, used to divide the sampled
+  ///     time so as to capture time per item, which is often a better measure
+  ///     than the total time over a varying number of items.
+  TimingSample(TimingMetric &timing, uint32 item_count) : timing_(timing),
+      count_(item_count) {
+  }
+
+  ~TimingSample() {
+    // We discard samples with a zero count
+    if(count_ == 1)
+      timing_.AddSample(timer_.GetElapsedMs());
+    else
+      timing_.AddSamples(count_, timer_.GetElapsedMs());
+  }
+
+  /// @name Accessors
+  /// @{
+  uint32 count() const { return count_; }
+  void set_count(uint32 count) { count_ = count; }
+  /// @}
+
+private:
+  /// Collects the sample for us.
+  omaha::HighresTimer timer_;
+
+  /// The metric we tally against.
+  TimingMetric &timing_;
+
+  /// The item count we divide the captured time by
+  uint32 count_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(TimingSample);
+};
+
+/// An integer metric is used to sample values that vary over time.
+/// On aggregation the instantaneous value of the integer metric is captured.
+class IntegerMetric: public IntegerMetricBase {
+public:
+  IntegerMetric(const char *name, MetricCollectionBase *coll)
+      : IntegerMetricBase(name, kIntegerType, coll) {
+  }
+
+  IntegerMetric(const char *name, uint64 value)
+      : IntegerMetricBase(name, kIntegerType, value) {
+  }
+
+  void operator = (uint64 value)   { Set(value); }
+
+  void operator -- ()     { Decrement(); }
+  void operator -- (int)  { Decrement(); }
+  void operator -= (uint64 sub)    { Subtract(sub); }
+
+private:
+  DISALLOW_EVIL_CONSTRUCTORS(IntegerMetric);
+};
+
+/// A bool metric is tri-state, and can be:
+///    - unset,
+///    - true or
+///    - false
+/// to match other metrics, which are implicitly unset if they've not changed
+/// from their initial value.
+class BoolMetric: public MetricBase {
+public:
+  /// Values we can take
+  enum TristateBoolValue {
+    kBoolUnset = -1,
+    kBoolFalse,
+    kBoolTrue,
+  };
+
+  BoolMetric(const char *name, MetricCollectionBase *coll)
+        : MetricBase(name, kBoolType, coll), value_(kBoolUnset) {
+  }
+
+  BoolMetric(const char *name, uint32 value)
+        : MetricBase(name, kBoolType) {
+    switch (value) {
+     case kBoolFalse:
+     case kBoolTrue:
+      value_ = static_cast<TristateBoolValue>(value);
+      break;
+
+     default:
+      DCHECK(false && "Unexpected tristate bool value on construction");
+      value_ = kBoolUnset;
+    }
+  }
+
+  /// Sets the flag to the provided value.
+  void Set(bool value);
+
+  void operator = (bool value) {
+    Set(value);
+  }
+
+  /// Nulls the metric and returns the current values.
+  TristateBoolValue Reset();
+
+  /// Returns the current value - not threadsafe
+  TristateBoolValue value() const { return value_; };
+
+private:
+  DISALLOW_EVIL_CONSTRUCTORS(BoolMetric);
+
+  TristateBoolValue value_;
+};
+
+inline CountMetric &MetricBase::AsCount() {
+  DCHECK_EQ(kCountType, type());
+
+  return static_cast<CountMetric&>(*this);
+}
+
+inline TimingMetric &MetricBase::AsTiming() {
+  DCHECK_EQ(kTimingType, type());
+
+  return static_cast<TimingMetric&>(*this);
+}
+
+inline IntegerMetric &MetricBase::AsInteger() {
+  DCHECK_EQ(kIntegerType, type());
+
+  return static_cast<IntegerMetric&>(*this);
+}
+
+inline BoolMetric &MetricBase::AsBool() {
+  DCHECK_EQ(kBoolType, type());
+
+  return static_cast<BoolMetric&>(*this);
+}
+
+inline const CountMetric &MetricBase::AsCount() const {
+  DCHECK_EQ(kCountType, type());
+
+  return static_cast<const CountMetric&>(*this);
+}
+
+inline const TimingMetric &MetricBase::AsTiming() const {
+  DCHECK_EQ(kTimingType, type());
+
+  return static_cast<const TimingMetric&>(*this);
+}
+
+inline const IntegerMetric &MetricBase::AsInteger() const {
+  DCHECK_EQ(kIntegerType, type());
+
+  return static_cast<const IntegerMetric&>(*this);
+}
+
+inline const BoolMetric &MetricBase::AsBool() const {
+  DCHECK_EQ(kBoolType, type());
+
+  return static_cast<const BoolMetric&>(*this);
+}
+
+} // namespace stats_report
+
+#endif  // OMAHA_STATSREPORT_METRICS_H__
diff --git a/statsreport/metrics_unittest.cc b/statsreport/metrics_unittest.cc
index 7ddcebc..155d049 100644
--- a/statsreport/metrics_unittest.cc
+++ b/statsreport/metrics_unittest.cc
@@ -1,361 +1,361 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// metrics report unit testing

-#include "omaha/third_party/gtest/include/gtest/gtest.h"

-#include "metrics.h"

-#include <algorithm>

-#include <new>

-

-DECLARE_METRIC_count(count);

-DEFINE_METRIC_count(count);

-

-DECLARE_METRIC_timing(timing);

-DEFINE_METRIC_timing(timing);

-

-DECLARE_METRIC_integer(integer);

-DEFINE_METRIC_integer(integer);

-

-DECLARE_METRIC_bool(bool);

-DEFINE_METRIC_bool(bool);

-

-using namespace stats_report;

-

-namespace {

-

-class MetricsTest: public testing::Test {

-protected:

-  MetricCollection coll_;

-};

-

-class MetricsEnumTest: public MetricsTest {

-public:

-  virtual void SetUp() {

-    coll_.Initialize();

-  }

-

-  virtual void TearDown() {

-    coll_.Uninitialize();

-  }

-

-protected:

-  MetricsEnumTest(): count_("count", &coll_), timing_("timing", &coll_),

-       integer_("integer", &coll_), bool_("bool", &coll_){

-  }

-

-  CountMetric count_;

-  TimingMetric timing_;

-  IntegerMetric integer_;

-  BoolMetric bool_;

-};

-

-} // namespace

-

-// Validates that the above-declared metrics are available

-// in the expected namespace

-TEST_F(MetricsTest, Globals) {

-  EXPECT_EQ(0, ::metric_count.Reset());

-  TimingMetric::TimingData data = ::metric_timing.Reset();

-  EXPECT_EQ(0, data.count);

-  EXPECT_EQ(0, data.maximum);

-  EXPECT_EQ(0, data.minimum);

-  EXPECT_EQ(0, data.sum);

-

-  EXPECT_EQ(0, ::metric_integer.value());

-  EXPECT_EQ(BoolMetric::kBoolUnset, ::metric_bool.Reset());

-

-  // Check for correct initialization

-  EXPECT_STREQ("count", metric_count.name());

-  EXPECT_STREQ("timing", metric_timing.name());

-  EXPECT_STREQ("integer", metric_integer.name());

-  EXPECT_STREQ("bool", metric_bool.name());

-}

-

-

-// make GTest happy

-inline std::ostream &operator << (std::ostream &str, const MetricIterator &it) {

-  str << std::hex << (void*)*it;

-  return str;

-}

-

-TEST_F(MetricsTest, CollectionInitialization) {

-  // The global MetricCollection is aliased to zero memory so as to ensure

-  // no initialization order snafus. If an initialized MetricCollection

-  // sets any of its storage to non-zero, there's a good chance that e.g. a

-  // vtbl has snuck in there, which must not happen

-  char buf1[sizeof(MetricCollection)] = { 0 };

-  char buf2[sizeof(MetricCollection)] = { 0 };

-

-  // Placement new a MetricCollection to one of the buffers

-  new (buf1) MetricCollection();

-

-  // and check they're still equivalent

-  EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(MetricCollection)));

-

-  // MetricCollection must not extend MetricCollectionBase in size

-  EXPECT_EQ(sizeof(MetricCollection), sizeof(MetricCollectionBase));

-}

-

-TEST_F(MetricsTest, Count) {

-  CountMetric foo("foo", &coll_);

-

-  EXPECT_EQ(0, foo.Reset());

-  EXPECT_EQ(kCountType, foo.type());

-  CountMetric &foo_ref = foo.AsCount();

-

-  ++foo;

-  EXPECT_EQ(1, foo.value());

-  foo++;

-  EXPECT_EQ(2, foo.value());

-

-  foo += 100;

-  EXPECT_EQ(102, foo.value());

-}

-

-TEST_F(MetricsTest, Timing) {

-  TimingMetric foo("foo", &coll_);

-

-  EXPECT_EQ(kTimingType, foo.type());

-  TimingMetric &foo_ref = foo.AsTiming();

-

-  foo.AddSample(100);

-  foo.AddSample(50);

-

-  EXPECT_EQ(2, foo.count());

-  EXPECT_EQ(150, foo.sum());

-  EXPECT_EQ(100, foo.maximum());

-  EXPECT_EQ(50, foo.minimum());

-  EXPECT_EQ(75, foo.average());

-

-  TimingMetric::TimingData data = foo.Reset();

-  EXPECT_EQ(2, data.count);

-  EXPECT_EQ(150, data.sum);

-  EXPECT_EQ(100, data.maximum);

-  EXPECT_EQ(50, data.minimum);

-

-  EXPECT_EQ(0, foo.count());

-  EXPECT_EQ(0, foo.sum());

-  EXPECT_EQ(0, foo.maximum());

-  EXPECT_EQ(0, foo.minimum());

-  EXPECT_EQ(0, foo.average());

-

-  // Test counted samples

-  foo.AddSamples(10, 1000);

-  foo.AddSamples(10, 500);

-  EXPECT_EQ(20, foo.count());

-  EXPECT_EQ(1500, foo.sum());

-  EXPECT_EQ(100, foo.maximum());

-  EXPECT_EQ(50, foo.minimum());

-  EXPECT_EQ(75, foo.average());

-}

-

-TEST_F(MetricsTest, TimingSample) {

-  TimingMetric foo("foo", &coll_);

-

-  // add a sample to foo

-  {

-    TimingSample sample(foo);

-

-    ::Sleep(30);

-  }

-

-  TimingMetric::TimingData data = foo.Reset();

-

-  // Should be precisely one sample in there

-  EXPECT_EQ(1, data.count);

-

-  // Let's hope the scheduler doesn't leave us hanging more than 10 ms.

-  // Increased time from 40 to 100 because test failed intermittently on Pulse.

-  EXPECT_GE(30 + 70, data.sum);

-  // The sleep above seems to often terminate early on the build server,

-  // I've observed captured times down to 18 ms, which is strange.

-  // TODO(omaha): figure out whether the timer is broken or whether

-  //    sleep is breaking its promise, or whether e.g. we're getting different

-  //    walltimes on different CPUs due to BIOS bugs on the build server

-  EXPECT_LE(14, data.sum);

-

-  // again, this time with a non-unity count

-  {

-    TimingSample sample(foo, 2);

-

-    EXPECT_EQ(2, sample.count());

-    ::Sleep(30);

-  }

-

-  data = foo.Reset();

-

-  // Should be precisely two samples in there

-  EXPECT_EQ(2, data.count);

-

-  // Let's hope the scheduler doesn't leave us hanging more than 10 ms.

-  // Increased time from 40 to 100 because test failed intermittently on Pulse.

-  EXPECT_GE(30 + 70, data.sum);

-  EXPECT_LE(14, data.sum);

-

-  // now with zero count

-  {

-    TimingSample sample(foo, 0);

-  }

-

-  data = foo.Reset();

-

-  // Should be no samples in there

-  EXPECT_EQ(0, data.count);

-}

-

-TEST_F(MetricsTest, Integer) {

-  IntegerMetric foo("foo", &coll_);

-

-  EXPECT_EQ(kIntegerType, foo.type());

-  IntegerMetric &foo_ref = foo.AsInteger();

-

-  EXPECT_EQ(0, foo.value());

-  foo.Set(1005);

-  EXPECT_EQ(1005, foo.value());

-  foo = 1009UL;

-  EXPECT_EQ(1009, foo.value());

-

-  foo.Set(0);

-

-  ++foo;

-  EXPECT_EQ(1, foo.value());

-  foo++;

-  EXPECT_EQ(2, foo.value());

-

-  foo += 100;

-  EXPECT_EQ(102, foo.value());

-

-  foo -= 100;

-  EXPECT_EQ(2, foo.value());

-  foo--;

-  EXPECT_EQ(1, foo.value());

-  --foo;

-  EXPECT_EQ(0, foo.value());

-}

-

-TEST_F(MetricsTest, Bool) {

-  BoolMetric foo("foo", &coll_);

-

-  EXPECT_EQ(kBoolType, foo.type());

-  BoolMetric &foo_ref = foo.AsBool();

-

-  EXPECT_EQ(BoolMetric::kBoolUnset, foo.Reset());

-  foo.Set(true);

-  EXPECT_EQ(BoolMetric::kBoolTrue, foo.Reset());

-  foo.Set(false);

-  EXPECT_EQ(BoolMetric::kBoolFalse, foo.Reset());

-  EXPECT_EQ(BoolMetric::kBoolUnset, foo.Reset());

-}

-

-TEST_F(MetricsEnumTest, Enumeration) {

-  MetricBase *metrics[] = {

-        &count_,

-        &timing_,

-        &integer_,

-        &bool_,

-  };

-

-  for (int i = 0; i < sizeof(metrics) / sizeof(metrics[0]); ++i) {

-    MetricBase *stat = metrics[i];

-    MetricBase *curr = coll_.first();

-

-    for (; NULL != curr; curr = curr->next()) {

-      if (stat == curr)

-        break;

-    }

-

-    // if NULL, we didn't find our counter

-    EXPECT_TRUE(NULL != curr);

-  }

-}

-

-TEST_F(MetricsEnumTest, Iterator) {

-  typedef MetricBase *MetricBasePtr;

-  MetricBasePtr metrics[] = { &count_, &timing_, &integer_, &bool_, };

-  int num_stats = sizeof(metrics) / sizeof(metrics[0]);

-

-  MetricIterator it(coll_), end;

-  EXPECT_NE(it, end);

-

-  // copy construction

-  EXPECT_EQ(it, MetricIterator(it));

-  EXPECT_EQ(end, MetricIterator(end));

-

-  // # of iterations

-  int i = 0;

-  while (it++ != end)

-    ++i;

-  DCHECK_EQ(i, num_stats);

-  DCHECK_EQ(it, end);

-

-  // increment past end is idempotent

-  ++it;

-  DCHECK_EQ(it, end);

-

-  // Check that we return no garbage or nonsense

-  for (it = MetricIterator(coll_); it != end; ++it) {

-    MetricBasePtr *stats_end = &metrics[num_stats];

-    EXPECT_NE(stats_end, std::find(metrics, stats_end, *it));

-  }

-

-  // and that all metrics can be found

-  for (int i = 0; i < sizeof(metrics) / sizeof(metrics[0]); ++i) {

-    MetricBase *stat = metrics[i];

-

-    EXPECT_EQ(stat, *std::find(MetricIterator(coll_), end, stat));

-  }

-}

-

-TEST_F(MetricsTest, SimpleConstruction) {

-  const CountMetric c("c", 100);

-

-  EXPECT_EQ(100, c.value());

-  EXPECT_EQ(kCountType, c.type());

-  EXPECT_STREQ("c", c.name());

-  EXPECT_TRUE(NULL == c.next());

-

-  TimingMetric::TimingData data = { 10, 0, 1000, 10, 500 };

-  const TimingMetric t("t", data);

-

-  EXPECT_EQ(10, t.count());

-  EXPECT_EQ(1000, t.sum());

-  EXPECT_EQ(10, t.minimum());

-  EXPECT_EQ(500, t.maximum());

-  EXPECT_EQ(kTimingType, t.type());

-  EXPECT_STREQ("t", t.name());

-  EXPECT_TRUE(NULL == t.next());

-

-  const IntegerMetric i("i", 200);

-

-  EXPECT_EQ(200, i.value());

-  EXPECT_EQ(kIntegerType, i.type());

-  EXPECT_STREQ("i", i.name());

-  EXPECT_TRUE(NULL == i.next());

-

-  const BoolMetric bool_true("bool_true", BoolMetric::kBoolTrue);

-

-  EXPECT_EQ(BoolMetric::kBoolTrue, bool_true.value());

-  EXPECT_EQ(kBoolType, bool_true.type());

-  EXPECT_STREQ("bool_true", bool_true.name());

-  EXPECT_TRUE(NULL == bool_true.next());

-

-  const BoolMetric bool_false("bool_false", BoolMetric::kBoolFalse);

-

-  EXPECT_EQ(BoolMetric::kBoolFalse, bool_false.value());

-  EXPECT_EQ(kBoolType, bool_false.type());

-  EXPECT_STREQ("bool_false", bool_false.name());

-  EXPECT_TRUE(NULL == bool_false.next());

-}

-

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// metrics report unit testing
+#include "omaha/third_party/gtest/include/gtest/gtest.h"
+#include "metrics.h"
+#include <algorithm>
+#include <new>
+
+DECLARE_METRIC_count(count);
+DEFINE_METRIC_count(count);
+
+DECLARE_METRIC_timing(timing);
+DEFINE_METRIC_timing(timing);
+
+DECLARE_METRIC_integer(integer);
+DEFINE_METRIC_integer(integer);
+
+DECLARE_METRIC_bool(bool);
+DEFINE_METRIC_bool(bool);
+
+using namespace stats_report;
+
+namespace {
+
+class MetricsTest: public testing::Test {
+protected:
+  MetricCollection coll_;
+};
+
+class MetricsEnumTest: public MetricsTest {
+public:
+  virtual void SetUp() {
+    coll_.Initialize();
+  }
+
+  virtual void TearDown() {
+    coll_.Uninitialize();
+  }
+
+protected:
+  MetricsEnumTest(): count_("count", &coll_), timing_("timing", &coll_),
+       integer_("integer", &coll_), bool_("bool", &coll_){
+  }
+
+  CountMetric count_;
+  TimingMetric timing_;
+  IntegerMetric integer_;
+  BoolMetric bool_;
+};
+
+} // namespace
+
+// Validates that the above-declared metrics are available
+// in the expected namespace
+TEST_F(MetricsTest, Globals) {
+  EXPECT_EQ(0, ::metric_count.Reset());
+  TimingMetric::TimingData data = ::metric_timing.Reset();
+  EXPECT_EQ(0, data.count);
+  EXPECT_EQ(0, data.maximum);
+  EXPECT_EQ(0, data.minimum);
+  EXPECT_EQ(0, data.sum);
+
+  EXPECT_EQ(0, ::metric_integer.value());
+  EXPECT_EQ(BoolMetric::kBoolUnset, ::metric_bool.Reset());
+
+  // Check for correct initialization
+  EXPECT_STREQ("count", metric_count.name());
+  EXPECT_STREQ("timing", metric_timing.name());
+  EXPECT_STREQ("integer", metric_integer.name());
+  EXPECT_STREQ("bool", metric_bool.name());
+}
+
+
+// make GTest happy
+inline std::ostream &operator << (std::ostream &str, const MetricIterator &it) {
+  str << std::hex << (void*)*it;
+  return str;
+}
+
+TEST_F(MetricsTest, CollectionInitialization) {
+  // The global MetricCollection is aliased to zero memory so as to ensure
+  // no initialization order snafus. If an initialized MetricCollection
+  // sets any of its storage to non-zero, there's a good chance that e.g. a
+  // vtbl has snuck in there, which must not happen
+  char buf1[sizeof(MetricCollection)] = { 0 };
+  char buf2[sizeof(MetricCollection)] = { 0 };
+
+  // Placement new a MetricCollection to one of the buffers
+  new (buf1) MetricCollection();
+
+  // and check they're still equivalent
+  EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(MetricCollection)));
+
+  // MetricCollection must not extend MetricCollectionBase in size
+  EXPECT_EQ(sizeof(MetricCollection), sizeof(MetricCollectionBase));
+}
+
+TEST_F(MetricsTest, Count) {
+  CountMetric foo("foo", &coll_);
+
+  EXPECT_EQ(0, foo.Reset());
+  EXPECT_EQ(kCountType, foo.type());
+  CountMetric &foo_ref = foo.AsCount();
+
+  ++foo;
+  EXPECT_EQ(1, foo.value());
+  foo++;
+  EXPECT_EQ(2, foo.value());
+
+  foo += 100;
+  EXPECT_EQ(102, foo.value());
+}
+
+TEST_F(MetricsTest, Timing) {
+  TimingMetric foo("foo", &coll_);
+
+  EXPECT_EQ(kTimingType, foo.type());
+  TimingMetric &foo_ref = foo.AsTiming();
+
+  foo.AddSample(100);
+  foo.AddSample(50);
+
+  EXPECT_EQ(2, foo.count());
+  EXPECT_EQ(150, foo.sum());
+  EXPECT_EQ(100, foo.maximum());
+  EXPECT_EQ(50, foo.minimum());
+  EXPECT_EQ(75, foo.average());
+
+  TimingMetric::TimingData data = foo.Reset();
+  EXPECT_EQ(2, data.count);
+  EXPECT_EQ(150, data.sum);
+  EXPECT_EQ(100, data.maximum);
+  EXPECT_EQ(50, data.minimum);
+
+  EXPECT_EQ(0, foo.count());
+  EXPECT_EQ(0, foo.sum());
+  EXPECT_EQ(0, foo.maximum());
+  EXPECT_EQ(0, foo.minimum());
+  EXPECT_EQ(0, foo.average());
+
+  // Test counted samples
+  foo.AddSamples(10, 1000);
+  foo.AddSamples(10, 500);
+  EXPECT_EQ(20, foo.count());
+  EXPECT_EQ(1500, foo.sum());
+  EXPECT_EQ(100, foo.maximum());
+  EXPECT_EQ(50, foo.minimum());
+  EXPECT_EQ(75, foo.average());
+}
+
+TEST_F(MetricsTest, TimingSample) {
+  TimingMetric foo("foo", &coll_);
+
+  // add a sample to foo
+  {
+    TimingSample sample(foo);
+
+    ::Sleep(30);
+  }
+
+  TimingMetric::TimingData data = foo.Reset();
+
+  // Should be precisely one sample in there
+  EXPECT_EQ(1, data.count);
+
+  // Let's hope the scheduler doesn't leave us hanging more than 10 ms.
+  // Increased time from 40 to 100 because test failed intermittently on Pulse.
+  EXPECT_GE(30 + 70, data.sum);
+  // The sleep above seems to often terminate early on the build server,
+  // I've observed captured times down to 18 ms, which is strange.
+  // TODO(omaha): figure out whether the timer is broken or whether
+  //    sleep is breaking its promise, or whether e.g. we're getting different
+  //    walltimes on different CPUs due to BIOS bugs on the build server
+  EXPECT_LE(14, data.sum);
+
+  // again, this time with a non-unity count
+  {
+    TimingSample sample(foo, 2);
+
+    EXPECT_EQ(2, sample.count());
+    ::Sleep(30);
+  }
+
+  data = foo.Reset();
+
+  // Should be precisely two samples in there
+  EXPECT_EQ(2, data.count);
+
+  // Let's hope the scheduler doesn't leave us hanging more than 10 ms.
+  // Increased time from 40 to 100 because test failed intermittently on Pulse.
+  EXPECT_GE(30 + 70, data.sum);
+  EXPECT_LE(14, data.sum);
+
+  // now with zero count
+  {
+    TimingSample sample(foo, 0);
+  }
+
+  data = foo.Reset();
+
+  // Should be no samples in there
+  EXPECT_EQ(0, data.count);
+}
+
+TEST_F(MetricsTest, Integer) {
+  IntegerMetric foo("foo", &coll_);
+
+  EXPECT_EQ(kIntegerType, foo.type());
+  IntegerMetric &foo_ref = foo.AsInteger();
+
+  EXPECT_EQ(0, foo.value());
+  foo.Set(1005);
+  EXPECT_EQ(1005, foo.value());
+  foo = 1009UL;
+  EXPECT_EQ(1009, foo.value());
+
+  foo.Set(0);
+
+  ++foo;
+  EXPECT_EQ(1, foo.value());
+  foo++;
+  EXPECT_EQ(2, foo.value());
+
+  foo += 100;
+  EXPECT_EQ(102, foo.value());
+
+  foo -= 100;
+  EXPECT_EQ(2, foo.value());
+  foo--;
+  EXPECT_EQ(1, foo.value());
+  --foo;
+  EXPECT_EQ(0, foo.value());
+}
+
+TEST_F(MetricsTest, Bool) {
+  BoolMetric foo("foo", &coll_);
+
+  EXPECT_EQ(kBoolType, foo.type());
+  BoolMetric &foo_ref = foo.AsBool();
+
+  EXPECT_EQ(BoolMetric::kBoolUnset, foo.Reset());
+  foo.Set(true);
+  EXPECT_EQ(BoolMetric::kBoolTrue, foo.Reset());
+  foo.Set(false);
+  EXPECT_EQ(BoolMetric::kBoolFalse, foo.Reset());
+  EXPECT_EQ(BoolMetric::kBoolUnset, foo.Reset());
+}
+
+TEST_F(MetricsEnumTest, Enumeration) {
+  MetricBase *metrics[] = {
+        &count_,
+        &timing_,
+        &integer_,
+        &bool_,
+  };
+
+  for (int i = 0; i < sizeof(metrics) / sizeof(metrics[0]); ++i) {
+    MetricBase *stat = metrics[i];
+    MetricBase *curr = coll_.first();
+
+    for (; NULL != curr; curr = curr->next()) {
+      if (stat == curr)
+        break;
+    }
+
+    // if NULL, we didn't find our counter
+    EXPECT_TRUE(NULL != curr);
+  }
+}
+
+TEST_F(MetricsEnumTest, Iterator) {
+  typedef MetricBase *MetricBasePtr;
+  MetricBasePtr metrics[] = { &count_, &timing_, &integer_, &bool_, };
+  int num_stats = sizeof(metrics) / sizeof(metrics[0]);
+
+  MetricIterator it(coll_), end;
+  EXPECT_NE(it, end);
+
+  // copy construction
+  EXPECT_EQ(it, MetricIterator(it));
+  EXPECT_EQ(end, MetricIterator(end));
+
+  // # of iterations
+  int i = 0;
+  while (it++ != end)
+    ++i;
+  DCHECK_EQ(i, num_stats);
+  DCHECK_EQ(it, end);
+
+  // increment past end is idempotent
+  ++it;
+  DCHECK_EQ(it, end);
+
+  // Check that we return no garbage or nonsense
+  for (it = MetricIterator(coll_); it != end; ++it) {
+    MetricBasePtr *stats_end = &metrics[num_stats];
+    EXPECT_NE(stats_end, std::find(metrics, stats_end, *it));
+  }
+
+  // and that all metrics can be found
+  for (int i = 0; i < sizeof(metrics) / sizeof(metrics[0]); ++i) {
+    MetricBase *stat = metrics[i];
+
+    EXPECT_EQ(stat, *std::find(MetricIterator(coll_), end, stat));
+  }
+}
+
+TEST_F(MetricsTest, SimpleConstruction) {
+  const CountMetric c("c", 100);
+
+  EXPECT_EQ(100, c.value());
+  EXPECT_EQ(kCountType, c.type());
+  EXPECT_STREQ("c", c.name());
+  EXPECT_TRUE(NULL == c.next());
+
+  TimingMetric::TimingData data = { 10, 0, 1000, 10, 500 };
+  const TimingMetric t("t", data);
+
+  EXPECT_EQ(10, t.count());
+  EXPECT_EQ(1000, t.sum());
+  EXPECT_EQ(10, t.minimum());
+  EXPECT_EQ(500, t.maximum());
+  EXPECT_EQ(kTimingType, t.type());
+  EXPECT_STREQ("t", t.name());
+  EXPECT_TRUE(NULL == t.next());
+
+  const IntegerMetric i("i", 200);
+
+  EXPECT_EQ(200, i.value());
+  EXPECT_EQ(kIntegerType, i.type());
+  EXPECT_STREQ("i", i.name());
+  EXPECT_TRUE(NULL == i.next());
+
+  const BoolMetric bool_true("bool_true", BoolMetric::kBoolTrue);
+
+  EXPECT_EQ(BoolMetric::kBoolTrue, bool_true.value());
+  EXPECT_EQ(kBoolType, bool_true.type());
+  EXPECT_STREQ("bool_true", bool_true.name());
+  EXPECT_TRUE(NULL == bool_true.next());
+
+  const BoolMetric bool_false("bool_false", BoolMetric::kBoolFalse);
+
+  EXPECT_EQ(BoolMetric::kBoolFalse, bool_false.value());
+  EXPECT_EQ(kBoolType, bool_false.type());
+  EXPECT_STREQ("bool_false", bool_false.name());
+  EXPECT_TRUE(NULL == bool_false.next());
+}
+
diff --git a/statsreport/persistent_iterator-win32.cc b/statsreport/persistent_iterator-win32.cc
index 0cd26ba..b9eca5c 100644
--- a/statsreport/persistent_iterator-win32.cc
+++ b/statsreport/persistent_iterator-win32.cc
@@ -1,138 +1,138 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Iterator over persisted metrics

-#include "persistent_iterator-win32.h"

-

-namespace stats_report {

-

-void PersistentMetricsIteratorWin32::Next() {

-  current_value_.reset();

-

-  // Try to open the top-level key if we didn't already.

-  if (NULL == key_.m_hKey) {

-    HKEY parent_key = is_machine_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;

-    LONG err = key_.Open(parent_key, key_name_, KEY_READ);

-    if (err != ERROR_SUCCESS)

-      return;

-  }

-

-  // Loop until we find a value

-  while (state_ != kFinished) {

-    if (NULL == sub_key_.m_hKey) {

-      const wchar_t *subkey_name = NULL;

-      switch (state_) {

-       case kUninitialized:

-        state_ = kCounts;

-        subkey_name = kCountsKeyName;

-        break;

-       case kCounts:

-        state_ = kTimings;

-        subkey_name = kTimingsKeyName;

-        break;

-       case kTimings:

-        state_ = kIntegers;

-        subkey_name = kIntegersKeyName;

-        break;

-       case kIntegers:

-        state_ = kBooleans;

-        subkey_name = kBooleansKeyName;

-        break;

-       case kBooleans:

-        state_ = kFinished;

-        break;

-       case kFinished:

-        break;

-      }

-

-      if (NULL != subkey_name) {

-        LONG err = sub_key_.Open(key_, subkey_name, KEY_READ);

-        // go around the loop on error to try the next key type

-        if (ERROR_SUCCESS != err)

-          continue;

-      }

-

-      // reset value enumeration

-      value_index_ = 0;

-    }

-

-    if (state_ != kFinished) {

-      DCHECK(NULL != sub_key_.m_hKey);

-      CString wide_value_name;

-      DWORD value_name_len = 255;

-      DWORD value_type = 0;

-      BYTE buf[sizeof(TimingMetric::TimingData)];

-      DWORD value_len = sizeof(buf);

-

-      // Get the next key and value

-      LONG err = ::RegEnumValue(sub_key_, value_index_,

-                    CStrBuf(wide_value_name, value_name_len), &value_name_len,

-                    0, &value_type,

-                    buf, &value_len);

-

-      ++value_index_;

-

-      if (ERROR_NO_MORE_ITEMS == err) {

-        // done with this subkey, go around again

-        sub_key_.Close();

-        continue;

-      } else if (ERROR_SUCCESS != err) {

-        // some other error, broken into a separate case for ease of debugging

-        DCHECK(false && "Unexpected error during reg value enumeration");

-      } else {

-        DCHECK(ERROR_SUCCESS == err);

-

-        // convert value to ASCII

-        current_value_name_ = wide_value_name;

-

-        switch (state_) {

-         case kCounts:

-          if (value_len != sizeof(uint64))

-            continue;

-          current_value_.reset(new CountMetric(current_value_name_ .GetString(),

-                                          *reinterpret_cast<uint64*>(&buf[0])));

-          break;

-         case kTimings:

-          if (value_len != sizeof(TimingMetric::TimingData))

-            continue;

-          current_value_.reset(new TimingMetric(current_value_name_.GetString(),

-                        *reinterpret_cast<TimingMetric::TimingData*>(&buf[0])));

-          break;

-         case kIntegers:

-          if (value_len != sizeof(uint64))

-            continue;

-          current_value_.reset(new IntegerMetric(

-                                      current_value_name_.GetString(),

-                                      *reinterpret_cast<uint64*>(&buf[0])));

-          break;

-         case kBooleans:

-          if (value_len != sizeof(uint32))

-            continue;

-          current_value_.reset(new BoolMetric(current_value_name_.GetString(),

-                                          *reinterpret_cast<uint32*>(&buf[0])));

-          break;

-         default:

-          DCHECK(false && "Impossible state during reg value enumeration");

-          break;

-        }

-

-        if (current_value_.get())

-          return;

-      }

-    }

-  }

-}

-

-} // namespace stats_report

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Iterator over persisted metrics
+#include "persistent_iterator-win32.h"
+
+namespace stats_report {
+
+void PersistentMetricsIteratorWin32::Next() {
+  current_value_.reset();
+
+  // Try to open the top-level key if we didn't already.
+  if (NULL == key_.m_hKey) {
+    HKEY parent_key = is_machine_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+    LONG err = key_.Open(parent_key, key_name_, KEY_READ);
+    if (err != ERROR_SUCCESS)
+      return;
+  }
+
+  // Loop until we find a value
+  while (state_ != kFinished) {
+    if (NULL == sub_key_.m_hKey) {
+      const wchar_t *subkey_name = NULL;
+      switch (state_) {
+       case kUninitialized:
+        state_ = kCounts;
+        subkey_name = kCountsKeyName;
+        break;
+       case kCounts:
+        state_ = kTimings;
+        subkey_name = kTimingsKeyName;
+        break;
+       case kTimings:
+        state_ = kIntegers;
+        subkey_name = kIntegersKeyName;
+        break;
+       case kIntegers:
+        state_ = kBooleans;
+        subkey_name = kBooleansKeyName;
+        break;
+       case kBooleans:
+        state_ = kFinished;
+        break;
+       case kFinished:
+        break;
+      }
+
+      if (NULL != subkey_name) {
+        LONG err = sub_key_.Open(key_, subkey_name, KEY_READ);
+        // go around the loop on error to try the next key type
+        if (ERROR_SUCCESS != err)
+          continue;
+      }
+
+      // reset value enumeration
+      value_index_ = 0;
+    }
+
+    if (state_ != kFinished) {
+      DCHECK(NULL != sub_key_.m_hKey);
+      CString wide_value_name;
+      DWORD value_name_len = 255;
+      DWORD value_type = 0;
+      BYTE buf[sizeof(TimingMetric::TimingData)];
+      DWORD value_len = sizeof(buf);
+
+      // Get the next key and value
+      LONG err = ::RegEnumValue(sub_key_, value_index_,
+                    CStrBuf(wide_value_name, value_name_len), &value_name_len,
+                    0, &value_type,
+                    buf, &value_len);
+
+      ++value_index_;
+
+      if (ERROR_NO_MORE_ITEMS == err) {
+        // done with this subkey, go around again
+        sub_key_.Close();
+        continue;
+      } else if (ERROR_SUCCESS != err) {
+        // some other error, broken into a separate case for ease of debugging
+        DCHECK(false && "Unexpected error during reg value enumeration");
+      } else {
+        DCHECK(ERROR_SUCCESS == err);
+
+        // convert value to ASCII
+        current_value_name_ = wide_value_name;
+
+        switch (state_) {
+         case kCounts:
+          if (value_len != sizeof(uint64))
+            continue;
+          current_value_.reset(new CountMetric(current_value_name_ .GetString(),
+                                          *reinterpret_cast<uint64*>(&buf[0])));
+          break;
+         case kTimings:
+          if (value_len != sizeof(TimingMetric::TimingData))
+            continue;
+          current_value_.reset(new TimingMetric(current_value_name_.GetString(),
+                        *reinterpret_cast<TimingMetric::TimingData*>(&buf[0])));
+          break;
+         case kIntegers:
+          if (value_len != sizeof(uint64))
+            continue;
+          current_value_.reset(new IntegerMetric(
+                                      current_value_name_.GetString(),
+                                      *reinterpret_cast<uint64*>(&buf[0])));
+          break;
+         case kBooleans:
+          if (value_len != sizeof(uint32))
+            continue;
+          current_value_.reset(new BoolMetric(current_value_name_.GetString(),
+                                          *reinterpret_cast<uint32*>(&buf[0])));
+          break;
+         default:
+          DCHECK(false && "Impossible state during reg value enumeration");
+          break;
+        }
+
+        if (current_value_.get())
+          return;
+      }
+    }
+  }
+}
+
+} // namespace stats_report
diff --git a/statsreport/persistent_iterator-win32.h b/statsreport/persistent_iterator-win32.h
index f0b45b9..d35f91e 100644
--- a/statsreport/persistent_iterator-win32.h
+++ b/statsreport/persistent_iterator-win32.h
@@ -1,136 +1,136 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Iterator over persisted metrics

-#ifndef OMAHA_STATSREPORT_PERSISTENT_ITERATOR_WIN32_H__

-#define OMAHA_STATSREPORT_PERSISTENT_ITERATOR_WIN32_H__

-

-#include "base/scoped_ptr.h"

-#include "metrics.h"

-#include "const-win32.h"

-

-#include <atlbase.h>

-#include <atlstr.h>

-#include <iterator>

-

-namespace stats_report {

-

-/// Forward iterator for persisted metrics

-class PersistentMetricsIteratorWin32

-    : public std::iterator<std::forward_iterator_tag, const MetricBase *> {

-public:

-  /// @param app_name see MetricsAggregatorWin32

-  explicit PersistentMetricsIteratorWin32(const wchar_t *app_name)

-      : state_(kUninitialized),

-       is_machine_(false) {

-    key_name_.Format(kStatsKeyFormatString, app_name);

-    Next();

-  }

-

-  /// @param app_name see MetricsAggregatorWin32

-  /// @param is_machine specifies the registry hive

-  PersistentMetricsIteratorWin32(const wchar_t *app_name, bool is_machine)

-      : state_(kUninitialized),

-        is_machine_(is_machine) {

-    key_name_.Format(kStatsKeyFormatString, app_name);

-    Next();

-  }

-

-  /// Constructs the at-end iterator

-  PersistentMetricsIteratorWin32() : state_(kUninitialized) {

-  }

-

-  MetricBase *operator* () {

-    return Current();

-  }

-  MetricBase *operator-> () {

-    return Current();

-  }

-

-  /// Preincrement, we don't implement postincrement because we don't

-  /// want to deal with making iterators copyable, comparable etc.

-  PersistentMetricsIteratorWin32 &operator++() {

-    Next();

-

-    return (*this);

-  }

-

-  /// Compare for equality with o.

-  bool equals(const PersistentMetricsIteratorWin32 &o) const {

-    // compare equal to self, and end iterators compare equal

-    if ((this == &o) || (NULL == current_value_.get() &&

-                         NULL == o.current_value_.get()))

-      return true;

-

-    return false;

-  }

-

-private:

-  MetricBase *Current() {

-    DCHECK(current_value_.get());

-    return current_value_.get();

-  }

-

-  enum IterationState {

-    kUninitialized,

-    kCounts,

-    kTimings,

-    kIntegers,

-    kBooleans,

-    kFinished,

-  };

-

-  /// Walk to the next key/value under iteration

-  void Next();

-

-  /// Keeps track of which subkey we're iterating over

-  IterationState state_;

-

-  /// The full path from HKCU to the key we iterate over

-  CString key_name_;

-

-  /// The top-level key we're iterating over, valid only

-  /// after first call to Next().

-  CRegKey key_;

-

-  /// The subkey we're currently enumerating over

-  CRegKey sub_key_;

-

-  /// Current value we're indexing over

-  DWORD value_index_;

-

-  /// Name of the value under the iterator

-  CStringA current_value_name_;

-

-  /// The metric under the iterator

-  scoped_ptr<MetricBase> current_value_;

-

-  /// Specifies HKLM or HKCU, respectively.

-  bool is_machine_;

-};

-

-inline bool operator == (const PersistentMetricsIteratorWin32 &a,

-                         const PersistentMetricsIteratorWin32 &b) {

-  return a.equals(b);

-}

-

-inline bool operator != (const PersistentMetricsIteratorWin32 &a,

-                         const PersistentMetricsIteratorWin32 &b) {

-  return !a.equals(b);

-}

-

-} // namespace stats_report

-

-#endif  // OMAHA_STATSREPORT_PERSISTENT_ITERATOR_WIN32_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Iterator over persisted metrics
+#ifndef OMAHA_STATSREPORT_PERSISTENT_ITERATOR_WIN32_H__
+#define OMAHA_STATSREPORT_PERSISTENT_ITERATOR_WIN32_H__
+
+#include "base/scoped_ptr.h"
+#include "metrics.h"
+#include "const-win32.h"
+
+#include <atlbase.h>
+#include <atlstr.h>
+#include <iterator>
+
+namespace stats_report {
+
+/// Forward iterator for persisted metrics
+class PersistentMetricsIteratorWin32
+    : public std::iterator<std::forward_iterator_tag, const MetricBase *> {
+public:
+  /// @param app_name see MetricsAggregatorWin32
+  explicit PersistentMetricsIteratorWin32(const wchar_t *app_name)
+      : state_(kUninitialized),
+       is_machine_(false) {
+    key_name_.Format(kStatsKeyFormatString, app_name);
+    Next();
+  }
+
+  /// @param app_name see MetricsAggregatorWin32
+  /// @param is_machine specifies the registry hive
+  PersistentMetricsIteratorWin32(const wchar_t *app_name, bool is_machine)
+      : state_(kUninitialized),
+        is_machine_(is_machine) {
+    key_name_.Format(kStatsKeyFormatString, app_name);
+    Next();
+  }
+
+  /// Constructs the at-end iterator
+  PersistentMetricsIteratorWin32() : state_(kUninitialized) {
+  }
+
+  MetricBase *operator* () {
+    return Current();
+  }
+  MetricBase *operator-> () {
+    return Current();
+  }
+
+  /// Preincrement, we don't implement postincrement because we don't
+  /// want to deal with making iterators copyable, comparable etc.
+  PersistentMetricsIteratorWin32 &operator++() {
+    Next();
+
+    return (*this);
+  }
+
+  /// Compare for equality with o.
+  bool equals(const PersistentMetricsIteratorWin32 &o) const {
+    // compare equal to self, and end iterators compare equal
+    if ((this == &o) || (NULL == current_value_.get() &&
+                         NULL == o.current_value_.get()))
+      return true;
+
+    return false;
+  }
+
+private:
+  MetricBase *Current() {
+    DCHECK(current_value_.get());
+    return current_value_.get();
+  }
+
+  enum IterationState {
+    kUninitialized,
+    kCounts,
+    kTimings,
+    kIntegers,
+    kBooleans,
+    kFinished,
+  };
+
+  /// Walk to the next key/value under iteration
+  void Next();
+
+  /// Keeps track of which subkey we're iterating over
+  IterationState state_;
+
+  /// The full path from HKCU to the key we iterate over
+  CString key_name_;
+
+  /// The top-level key we're iterating over, valid only
+  /// after first call to Next().
+  CRegKey key_;
+
+  /// The subkey we're currently enumerating over
+  CRegKey sub_key_;
+
+  /// Current value we're indexing over
+  DWORD value_index_;
+
+  /// Name of the value under the iterator
+  CStringA current_value_name_;
+
+  /// The metric under the iterator
+  scoped_ptr<MetricBase> current_value_;
+
+  /// Specifies HKLM or HKCU, respectively.
+  bool is_machine_;
+};
+
+inline bool operator == (const PersistentMetricsIteratorWin32 &a,
+                         const PersistentMetricsIteratorWin32 &b) {
+  return a.equals(b);
+}
+
+inline bool operator != (const PersistentMetricsIteratorWin32 &a,
+                         const PersistentMetricsIteratorWin32 &b) {
+  return !a.equals(b);
+}
+
+} // namespace stats_report
+
+#endif  // OMAHA_STATSREPORT_PERSISTENT_ITERATOR_WIN32_H__
diff --git a/statsreport/persistent_iterator-win32_unittest.cc b/statsreport/persistent_iterator-win32_unittest.cc
index 84db6f9..6893b69 100644
--- a/statsreport/persistent_iterator-win32_unittest.cc
+++ b/statsreport/persistent_iterator-win32_unittest.cc
@@ -1,130 +1,130 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-#include "omaha/third_party/gtest/include/gtest/gtest.h"

-#include "const-win32.h"

-#include "aggregator-win32_unittest.h"

-#include "persistent_iterator-win32.h"

-#include <atlbase.h>

-#include <atlcom.h>

-#include <iterator>

-#include <map>

-

-using namespace stats_report;

-

-namespace {

-

-class PersistentMetricsIteratorWin32Test: public MetricsAggregatorWin32Test {

-public:

-  bool WriteStats() {

-    // put some persistent metrics into the registry

-    MetricsAggregatorWin32 agg(coll_, kAppName);

-    AddStats();

-    bool ret = agg.AggregateMetrics();

-

-    // Reset the stats, we should now have the same stats

-    // in our collection as in registry.

-    AddStats();

-

-    return ret;

-  }

-

-  typedef std::map<std::string, MetricBase*> MetricsMap;

-  void IndexMetrics(MetricsMap *metrics) {

-    // build a map over the metrics in our collection

-    MetricIterator it(coll_), end;

-

-    for (; it != end; ++it) {

-      metrics->insert(std::make_pair(std::string(it->name()), *it));

-    }

-  }

-};

-

-// compare two metrics instances for equality

-bool equals(MetricBase *a, MetricBase *b) {

-  if (!a || !b)

-    return false;

-

-  if (a->type() != b->type() || 0 != strcmp(a->name(), b->name()))

-    return false;

-

-  switch (a->type()) {

-   case kCountType:

-    return a->AsCount().value() == b->AsCount().value();

-    break;

-   case kTimingType: {

-      TimingMetric &at = a->AsTiming();

-      TimingMetric &bt = b->AsTiming();

-

-      return at.count() == bt.count() &&

-             at.sum() == bt.sum() &&

-             at.minimum() == bt.minimum() &&

-             at.maximum() == bt.maximum();

-    }

-    break;

-   case kIntegerType:

-    return a->AsInteger().value() == b->AsInteger().value();

-    break;

-   case kBoolType:

-    return a->AsBool().value() == b->AsBool().value();

-    break;

-

-   case kInvalidType:

-   default:

-    LOG(FATAL) << "Impossible metric type";

-  }

-

-  return false;

-}

-

-} // namespace

-

-TEST_F(PersistentMetricsIteratorWin32Test, Basic) {

-  EXPECT_TRUE(WriteStats());

-  PersistentMetricsIteratorWin32 a, b, c(kAppName);

-

-  EXPECT_TRUE(a == b);

-  EXPECT_TRUE(b == a);

-

-  EXPECT_FALSE(a == c);

-  EXPECT_FALSE(b == c);

-  EXPECT_FALSE(c == a);

-  EXPECT_FALSE(c == b);

-

-  ++a;

-  EXPECT_TRUE(a == b);

-  EXPECT_TRUE(b == a);

-}

-

-// Test to see whether we can reliably roundtrip metrics through

-// the registry without molestation

-TEST_F(PersistentMetricsIteratorWin32Test, UnmolestedValues) {

-  EXPECT_TRUE(WriteStats());

-

-  MetricsMap metrics;

-  IndexMetrics(&metrics);

-

-  PersistentMetricsIteratorWin32 it(kAppName), end;

-  int count = 0;

-  for (; it != end; ++it) {

-    MetricsMap::iterator found = metrics.find(it->name());

-

-    // make sure we found it, and that it's unmolested in value

-    EXPECT_TRUE(found != metrics.end() && equals(found->second, *it));

-    count++;

-  }

-

-  // Did we visit all metrics?

-  EXPECT_EQ(count, metrics.size());

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+#include "omaha/third_party/gtest/include/gtest/gtest.h"
+#include "const-win32.h"
+#include "aggregator-win32_unittest.h"
+#include "persistent_iterator-win32.h"
+#include <atlbase.h>
+#include <atlcom.h>
+#include <iterator>
+#include <map>
+
+using namespace stats_report;
+
+namespace {
+
+class PersistentMetricsIteratorWin32Test: public MetricsAggregatorWin32Test {
+public:
+  bool WriteStats() {
+    // put some persistent metrics into the registry
+    MetricsAggregatorWin32 agg(coll_, kAppName);
+    AddStats();
+    bool ret = agg.AggregateMetrics();
+
+    // Reset the stats, we should now have the same stats
+    // in our collection as in registry.
+    AddStats();
+
+    return ret;
+  }
+
+  typedef std::map<std::string, MetricBase*> MetricsMap;
+  void IndexMetrics(MetricsMap *metrics) {
+    // build a map over the metrics in our collection
+    MetricIterator it(coll_), end;
+
+    for (; it != end; ++it) {
+      metrics->insert(std::make_pair(std::string(it->name()), *it));
+    }
+  }
+};
+
+// compare two metrics instances for equality
+bool equals(MetricBase *a, MetricBase *b) {
+  if (!a || !b)
+    return false;
+
+  if (a->type() != b->type() || 0 != strcmp(a->name(), b->name()))
+    return false;
+
+  switch (a->type()) {
+   case kCountType:
+    return a->AsCount().value() == b->AsCount().value();
+    break;
+   case kTimingType: {
+      TimingMetric &at = a->AsTiming();
+      TimingMetric &bt = b->AsTiming();
+
+      return at.count() == bt.count() &&
+             at.sum() == bt.sum() &&
+             at.minimum() == bt.minimum() &&
+             at.maximum() == bt.maximum();
+    }
+    break;
+   case kIntegerType:
+    return a->AsInteger().value() == b->AsInteger().value();
+    break;
+   case kBoolType:
+    return a->AsBool().value() == b->AsBool().value();
+    break;
+
+   case kInvalidType:
+   default:
+    LOG(FATAL) << "Impossible metric type";
+  }
+
+  return false;
+}
+
+} // namespace
+
+TEST_F(PersistentMetricsIteratorWin32Test, Basic) {
+  EXPECT_TRUE(WriteStats());
+  PersistentMetricsIteratorWin32 a, b, c(kAppName);
+
+  EXPECT_TRUE(a == b);
+  EXPECT_TRUE(b == a);
+
+  EXPECT_FALSE(a == c);
+  EXPECT_FALSE(b == c);
+  EXPECT_FALSE(c == a);
+  EXPECT_FALSE(c == b);
+
+  ++a;
+  EXPECT_TRUE(a == b);
+  EXPECT_TRUE(b == a);
+}
+
+// Test to see whether we can reliably roundtrip metrics through
+// the registry without molestation
+TEST_F(PersistentMetricsIteratorWin32Test, UnmolestedValues) {
+  EXPECT_TRUE(WriteStats());
+
+  MetricsMap metrics;
+  IndexMetrics(&metrics);
+
+  PersistentMetricsIteratorWin32 it(kAppName), end;
+  int count = 0;
+  for (; it != end; ++it) {
+    MetricsMap::iterator found = metrics.find(it->name());
+
+    // make sure we found it, and that it's unmolested in value
+    EXPECT_TRUE(found != metrics.end() && equals(found->second, *it));
+    count++;
+  }
+
+  // Did we visit all metrics?
+  EXPECT_EQ(count, metrics.size());
+}
diff --git a/statsreport/util-win32.h b/statsreport/util-win32.h
index 295f75b..22f7068 100644
--- a/statsreport/util-win32.h
+++ b/statsreport/util-win32.h
@@ -1,36 +1,36 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Utility functions for Win32 stats aggregation and uploading

-#ifndef OMAHA_STATSREPORT_UTIL_WIN32_H__

-#define OMAHA_STATSREPORT_UTIL_WIN32_H__

-

-namespace stats_report {

-

-template <class ValueType>

-bool GetData(CRegKey &parent, const wchar_t *value_name, ValueType *value) {

-  ULONG len = sizeof(ValueType);

-  LONG err = parent.QueryBinaryValue(value_name, value, &len);

-  if (ERROR_SUCCESS != err || len != sizeof(ValueType)) {

-    memset(value, 0, sizeof(ValueType));

-    return false;

-  }

-

-  return true;

-}

-

-} // namespace stats_report

-

-#endif  // OMAHA_STATSREPORT_UTIL_WIN32_H__

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Utility functions for Win32 stats aggregation and uploading
+#ifndef OMAHA_STATSREPORT_UTIL_WIN32_H__
+#define OMAHA_STATSREPORT_UTIL_WIN32_H__
+
+namespace stats_report {
+
+template <class ValueType>
+bool GetData(CRegKey &parent, const wchar_t *value_name, ValueType *value) {
+  ULONG len = sizeof(ValueType);
+  LONG err = parent.QueryBinaryValue(value_name, value, &len);
+  if (ERROR_SUCCESS != err || len != sizeof(ValueType)) {
+    memset(value, 0, sizeof(ValueType));
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace stats_report
+
+#endif  // OMAHA_STATSREPORT_UTIL_WIN32_H__
diff --git a/test/build.scons b/test/build.scons
index dd37eba..e79b54e 100644
--- a/test/build.scons
+++ b/test/build.scons
@@ -1,239 +1,239 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-import binascii

-import md5

-from enterprise.installer import build_enterprise_installer

-

-

-def BuildMSI(version, namespace, exe_name, wxs_template, msi_base_name,

-             is_enterprise=False, prefix=''):

-  if is_enterprise:

-    msi_base_name = 'enterprise_' + msi_base_name

-  msi_base_name = prefix + msi_base_name

-

-  # Have to use 'copy' here because we are renaming the file, and it is being

-  # renamed to match the final msi name to avoid collisions in the wixobj files.

-  copy_target = env.Command(

-      target=msi_base_name + '.wxs',

-      source=wxs_template,

-      action='@copy /y $SOURCE $TARGET',

-  )

-

-  PRODUCT_GUID = build_enterprise_installer.GenerateNameBasedGUID(

-      namespace,

-      'Product ' + version

-  )

-  COMPONENT_GUID = build_enterprise_installer.GenerateNameBasedGUID(

-      namespace,

-      'Component ' + version

-  )

-  COMPONENT_GUID_REGISTRY = build_enterprise_installer.GenerateNameBasedGUID(

-      namespace,

-      'Component Registry ' + version

-  )

-  COMPONENT_GUID_NOTIFY_SUCCESS = (

-      build_enterprise_installer.GenerateNameBasedGUID(

-          namespace,

-          'Component Notify Success ' + version

-      ))

-  COMPONENT_GUID_REGISTER_LAUNCH = (

-      build_enterprise_installer.GenerateNameBasedGUID(

-          namespace,

-          'Component Register Launch Command ' + version

-      ))

-  COMPONENT_GUID_NOTIFY_FAILED = (

-      build_enterprise_installer.GenerateNameBasedGUID(

-          namespace,

-          'Component Notify Failed ' + version

-      ))

-  COMPONENT_GUID_PROPERTY_BAR = (

-      build_enterprise_installer.GenerateNameBasedGUID(

-          namespace,

-          'Component Property Bar ' + version

-      ))

-

-  wix_env = env.Clone()

-  wix_env.Append(

-      WIXLIGHTFLAGS = [

-          # Add a supress for:

-          # warning LGHT1076 : ICE91: The file will be installed to the per user

-          # directory that doesn't vary based on ALLUSERS value. This file won't

-          # be copied to each user's profile even if a per machine installation

-          # is desired.

-          # This warning is generated by light when we produce a user only

-          # installer, and can be ignored as this is a user only installer.

-          '-sw1076'

-          ],

-      WIXCANDLEFLAGS = [

-          '-dFooExePath=' + wix_env.File(exe_name).abspath,

-          '-dFooVersion=' + version,

-          '-dFooProductGuid=' + PRODUCT_GUID,

-          '-dFooComponentGuid=' + COMPONENT_GUID,

-          '-dFooComponentGuidRegistry=' + COMPONENT_GUID_REGISTRY,

-          '-dFooComponentGuidNotifySuccess=' + COMPONENT_GUID_NOTIFY_SUCCESS,

-          '-dFooComponentRegisterLaunchCommand=' +

-              COMPONENT_GUID_REGISTER_LAUNCH,

-          '-dFooComponentGuidNotifyFailed=' + COMPONENT_GUID_NOTIFY_FAILED,

-          '-dFooComponentGuidPropertyBar=' + COMPONENT_GUID_PROPERTY_BAR,

-          ],

-  )

-

-  wix_inputs = copy_target

-  # Force a rebuild when the exe file changes.

-  additional_dependencies = [exe_name]

-

-  if is_enterprise:

-    wix_env['WIXCANDLEFLAGS'] += ['-dIsEnterprise=1']

-

-    # The metainstaller change does not get passed through even though the

-    # .wixobj file is rebuilt because the hash of the .wixobj does not change.

-    metainstaller_path = '$STAGING_DIR/%sGoogleUpdateSetup.exe' % (prefix)

-    google_update_wixobj = build_enterprise_installer.BuildGoogleUpdateFragment(

-            env,

-            metainstaller_path,

-            'Test Foo',

-            version,

-            '{D6B08267-B440-4c85-9F79-E195E80D9937}',

-            '&ap=enterprise',

-            msi_base_name,

-            ('$MAIN_DIR/enterprise/installer/'

-                'google_update_installer_fragment.wxs.xml'),

-            is_using_google_update_1_2_171_or_later=True

-    )

-

-    wix_inputs += [google_update_wixobj]

-    additional_dependencies += [metainstaller_path]

-  else:

-    wix_env['WIXCANDLEFLAGS'] += ['-dIsEnterprise=0']

-

-  unsigned_msi = wix_env.WiX('unsigned_%s.msi' % msi_base_name, wix_inputs)

-

-  wix_env.Depends(unsigned_msi, additional_dependencies)

-

-  signed_output = env.SignedBinary(

-      target=msi_base_name + '.msi',

-      source=unsigned_msi,

-  )

-

-  env.Replicate('$STAGING_DIR', signed_output)

-

-_GUID_NAMESPACE = binascii.a2b_hex('BE19B3E4502845af8B3E67A99FCDCFB1')

-_USER_GUID_NAMESPACE = binascii.a2b_hex('2B599C061F7C4eed9D686616EEBDDFDB')

-

-# test_foo.wxs.xml is so named because SCons tries to apply WiX building

-# rules to any input file with the .wxs suffix even in a custom command.

-_WXS_TEMPLATE_NAME = 'test_foo.wxs.xml'

-_USER_WXS_TEMPLATE_NAME = 'user_app.wxs.xml'

-

-for (major, minor, build, patch) in [(1,0,101,0), (1,0,102,0)]:

-  version = '%d.%d.%d.%d' % (major, minor, build, patch)

-  msi_base_name = 'test_foo_v' + version

-

-  ver_env = env.Clone()

-  ver_env.Append(

-      LIBS = [

-          ('libcmt.lib', 'libcmtd.lib')[env.Bit('debug')],

-          ('libcpmt.lib', 'libcpmtd.lib')[env.Bit('debug')],

-          'version.lib',

-          ],

-      RCFLAGS = [

-          '-DVERSION_STRING=%s' % version,

-          '-DMAJOR=%s' % major,

-          '-DMINOR=%s' % minor,

-          '-DBUILD=%s' % build,

-          '-DPATCH=%s' % patch

-          ],

-  )

-

-  ver_env['OBJPREFIX'] = '%s%s/' % (ver_env['OBJPREFIX'], version)

-

-  unsigned_exe = ver_env.ComponentProgram(

-      prog_name='unsigned_test_foo_v%s.exe' % version,

-      source=[

-          'test_foo.cc',

-          ver_env.RES('test_foo_v%s.res' % version, 'test_foo.rc'),

-          ]

-  )

-

-  signed_output = ver_env.SignedBinary(

-      target='test_foo_v%s.exe' % version,

-      source=unsigned_exe,

-  )

-

-  ver_env.Replicate('$STAGING_DIR', signed_output)

-

-  signed_exe = signed_output[0]

-

-  BuildMSI(version, _GUID_NAMESPACE, signed_exe, _WXS_TEMPLATE_NAME,

-           msi_base_name)

-

-  # Build the enterprise installer for each version of Omaha.

-  first = True

-  for _ in env['product_version']:

-    if first:

-      first = False

-      prefix = ''

-    else:

-      prefix = 'TEST_'

-

-    BuildMSI(version, _GUID_NAMESPACE, signed_exe, _WXS_TEMPLATE_NAME,

-             msi_base_name, is_enterprise=True, prefix=prefix)

-

-  BuildMSI(version, _USER_GUID_NAMESPACE, signed_exe, _USER_WXS_TEMPLATE_NAME,

-           'user_app_v' + version)

-

-bar_env = env.Clone()

-bar_env.Append(

-    LIBS = [

-        ('libcmt.lib', 'libcmtd.lib')[env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[env.Bit('debug')],

-        ],

-)

-bar_env.ComponentProgram('test_bar.cc')

-

-

-""" This is commented out because it step_test is currently unused,

-    and may be removed. Remove this if/when step_test is removed.

-

-omaha_system_env = env.Clone()

-omaha_system_env.Append(

-    CPPDEFINES = [

-        'UNICODE',

-        '_UNICODE'

-        ],

-    LIBS = [

-        '$LIB_PATH/common.lib',

-        ('atls.lib', 'atlsd.lib')[env.Bit('debug')],

-        ('libcmt.lib', 'libcmtd.lib')[env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[env.Bit('debug')],

-        ],

-)

-

-

-omaha_system_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-omaha_system_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-omaha_system_env.ComponentProgram([

-    'omaha_system_test.cc',

-    'step_test.cc',

-    ],

-)

-"""

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+import binascii
+import md5
+from enterprise.installer import build_enterprise_installer
+
+
+def BuildMSI(version, namespace, exe_name, wxs_template, msi_base_name,
+             is_enterprise=False, prefix=''):
+  if is_enterprise:
+    msi_base_name = 'enterprise_' + msi_base_name
+  msi_base_name = prefix + msi_base_name
+
+  # Have to use 'copy' here because we are renaming the file, and it is being
+  # renamed to match the final msi name to avoid collisions in the wixobj files.
+  copy_target = env.Command(
+      target=msi_base_name + '.wxs',
+      source=wxs_template,
+      action='@copy /y $SOURCE $TARGET',
+  )
+
+  PRODUCT_GUID = build_enterprise_installer.GenerateNameBasedGUID(
+      namespace,
+      'Product ' + version
+  )
+  COMPONENT_GUID = build_enterprise_installer.GenerateNameBasedGUID(
+      namespace,
+      'Component ' + version
+  )
+  COMPONENT_GUID_REGISTRY = build_enterprise_installer.GenerateNameBasedGUID(
+      namespace,
+      'Component Registry ' + version
+  )
+  COMPONENT_GUID_NOTIFY_SUCCESS = (
+      build_enterprise_installer.GenerateNameBasedGUID(
+          namespace,
+          'Component Notify Success ' + version
+      ))
+  COMPONENT_GUID_REGISTER_LAUNCH = (
+      build_enterprise_installer.GenerateNameBasedGUID(
+          namespace,
+          'Component Register Launch Command ' + version
+      ))
+  COMPONENT_GUID_NOTIFY_FAILED = (
+      build_enterprise_installer.GenerateNameBasedGUID(
+          namespace,
+          'Component Notify Failed ' + version
+      ))
+  COMPONENT_GUID_PROPERTY_BAR = (
+      build_enterprise_installer.GenerateNameBasedGUID(
+          namespace,
+          'Component Property Bar ' + version
+      ))
+
+  wix_env = env.Clone()
+  wix_env.Append(
+      WIXLIGHTFLAGS = [
+          # Add a supress for:
+          # warning LGHT1076 : ICE91: The file will be installed to the per user
+          # directory that doesn't vary based on ALLUSERS value. This file won't
+          # be copied to each user's profile even if a per machine installation
+          # is desired.
+          # This warning is generated by light when we produce a user only
+          # installer, and can be ignored as this is a user only installer.
+          '-sw1076'
+          ],
+      WIXCANDLEFLAGS = [
+          '-dFooExePath=' + wix_env.File(exe_name).abspath,
+          '-dFooVersion=' + version,
+          '-dFooProductGuid=' + PRODUCT_GUID,
+          '-dFooComponentGuid=' + COMPONENT_GUID,
+          '-dFooComponentGuidRegistry=' + COMPONENT_GUID_REGISTRY,
+          '-dFooComponentGuidNotifySuccess=' + COMPONENT_GUID_NOTIFY_SUCCESS,
+          '-dFooComponentRegisterLaunchCommand=' +
+              COMPONENT_GUID_REGISTER_LAUNCH,
+          '-dFooComponentGuidNotifyFailed=' + COMPONENT_GUID_NOTIFY_FAILED,
+          '-dFooComponentGuidPropertyBar=' + COMPONENT_GUID_PROPERTY_BAR,
+          ],
+  )
+
+  wix_inputs = copy_target
+  # Force a rebuild when the exe file changes.
+  additional_dependencies = [exe_name]
+
+  if is_enterprise:
+    wix_env['WIXCANDLEFLAGS'] += ['-dIsEnterprise=1']
+
+    # The metainstaller change does not get passed through even though the
+    # .wixobj file is rebuilt because the hash of the .wixobj does not change.
+    metainstaller_path = '$STAGING_DIR/%sGoogleUpdateSetup.exe' % (prefix)
+    google_update_wixobj = build_enterprise_installer.BuildGoogleUpdateFragment(
+            env,
+            metainstaller_path,
+            'Test Foo',
+            version,
+            '{D6B08267-B440-4c85-9F79-E195E80D9937}',
+            '&ap=enterprise',
+            msi_base_name,
+            ('$MAIN_DIR/enterprise/installer/'
+                'google_update_installer_fragment.wxs.xml'),
+            is_using_google_update_1_2_171_or_later=True
+    )
+
+    wix_inputs += [google_update_wixobj]
+    additional_dependencies += [metainstaller_path]
+  else:
+    wix_env['WIXCANDLEFLAGS'] += ['-dIsEnterprise=0']
+
+  unsigned_msi = wix_env.WiX('unsigned_%s.msi' % msi_base_name, wix_inputs)
+
+  wix_env.Depends(unsigned_msi, additional_dependencies)
+
+  signed_output = env.SignedBinary(
+      target=msi_base_name + '.msi',
+      source=unsigned_msi,
+  )
+
+  env.Replicate('$STAGING_DIR', signed_output)
+
+_GUID_NAMESPACE = binascii.a2b_hex('BE19B3E4502845af8B3E67A99FCDCFB1')
+_USER_GUID_NAMESPACE = binascii.a2b_hex('2B599C061F7C4eed9D686616EEBDDFDB')
+
+# test_foo.wxs.xml is so named because SCons tries to apply WiX building
+# rules to any input file with the .wxs suffix even in a custom command.
+_WXS_TEMPLATE_NAME = 'test_foo.wxs.xml'
+_USER_WXS_TEMPLATE_NAME = 'user_app.wxs.xml'
+
+for (major, minor, build, patch) in [(1,0,101,0), (1,0,102,0)]:
+  version = '%d.%d.%d.%d' % (major, minor, build, patch)
+  msi_base_name = 'test_foo_v' + version
+
+  ver_env = env.Clone()
+  ver_env.Append(
+      LIBS = [
+          ('libcmt.lib', 'libcmtd.lib')[env.Bit('debug')],
+          ('libcpmt.lib', 'libcpmtd.lib')[env.Bit('debug')],
+          'version.lib',
+          ],
+      RCFLAGS = [
+          '-DVERSION_STRING=%s' % version,
+          '-DMAJOR=%s' % major,
+          '-DMINOR=%s' % minor,
+          '-DBUILD=%s' % build,
+          '-DPATCH=%s' % patch
+          ],
+  )
+
+  ver_env['OBJPREFIX'] = '%s%s/' % (ver_env['OBJPREFIX'], version)
+
+  unsigned_exe = ver_env.ComponentProgram(
+      prog_name='unsigned_test_foo_v%s.exe' % version,
+      source=[
+          'test_foo.cc',
+          ver_env.RES('test_foo_v%s.res' % version, 'test_foo.rc'),
+          ]
+  )
+
+  signed_output = ver_env.SignedBinary(
+      target='test_foo_v%s.exe' % version,
+      source=unsigned_exe,
+  )
+
+  ver_env.Replicate('$STAGING_DIR', signed_output)
+
+  signed_exe = signed_output[0]
+
+  BuildMSI(version, _GUID_NAMESPACE, signed_exe, _WXS_TEMPLATE_NAME,
+           msi_base_name)
+
+  # Build the enterprise installer for each version of Omaha.
+  first = True
+  for _ in env['product_version']:
+    if first:
+      first = False
+      prefix = ''
+    else:
+      prefix = 'TEST_'
+
+    BuildMSI(version, _GUID_NAMESPACE, signed_exe, _WXS_TEMPLATE_NAME,
+             msi_base_name, is_enterprise=True, prefix=prefix)
+
+  BuildMSI(version, _USER_GUID_NAMESPACE, signed_exe, _USER_WXS_TEMPLATE_NAME,
+           'user_app_v' + version)
+
+bar_env = env.Clone()
+bar_env.Append(
+    LIBS = [
+        ('libcmt.lib', 'libcmtd.lib')[env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[env.Bit('debug')],
+        ],
+)
+bar_env.ComponentProgram('test_bar.cc')
+
+
+""" This is commented out because it step_test is currently unused,
+    and may be removed. Remove this if/when step_test is removed.
+
+omaha_system_env = env.Clone()
+omaha_system_env.Append(
+    CPPDEFINES = [
+        'UNICODE',
+        '_UNICODE'
+        ],
+    LIBS = [
+        '$LIB_PATH/common.lib',
+        ('atls.lib', 'atlsd.lib')[env.Bit('debug')],
+        ('libcmt.lib', 'libcmtd.lib')[env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[env.Bit('debug')],
+        ],
+)
+
+
+omaha_system_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+omaha_system_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+omaha_system_env.ComponentProgram([
+    'omaha_system_test.cc',
+    'step_test.cc',
+    ],
+)
+"""
+
diff --git a/test/omaha_system_test.cc b/test/omaha_system_test.cc
index d8df368..c578d4f 100644
--- a/test/omaha_system_test.cc
+++ b/test/omaha_system_test.cc
@@ -1,123 +1,123 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#pragma warning(push)

-// C4548: expression before comma has no effect

-#pragma warning(disable : 4548)

-#include <atlstr.h>

-#pragma warning(pop)

-#include <regstr.h>

-#include "omaha/mi_exe_stub/mi_step_test.h"

-#include "omaha/test/step_test.h"

-

-class MIWatcher : public StepTestWatcher {

-public:

-  MIWatcher() : StepTestWatcher(MI_STEP_TEST_NAME),

-    system_should_be_clean_(true) {

-  }

-

-  ~MIWatcher() {

-  }

-

-protected:

-  bool VerifyStep(DWORD step, bool *testing_complete) {

-    bool result = true;

-    switch (step) {

-      case MI_STEP_VERIFY_PRECONDITIONS:

-        if (system_should_be_clean_) {

-          result = VerifyCleanSystem();

-        } else {

-          result = false;

-          _tprintf(_T("Unexpected state.\r\n"));

-        }

-        break;

-      case MI_STEP_PROGRAM_START:

-        if (system_should_be_clean_) {

-          result = VerifyCleanSystem();

-          system_should_be_clean_ = false;

-        } else {

-          result = false;

-          _tprintf(_T("Unexpected state.\r\n"));

-        }

-          break;

-      case MI_STEP_PROGRAM_END:

-        result  = VerifyTestFooInstalled();

-        result &= VerifyOmahaInstalled();

-        break;

-    }

-    *testing_complete = (step >= MI_STEP_PROGRAM_END);

-    return result;

-  }

-

-  void PrintIntroduction() {

-    _tprintf(

-      _T("Ready to test mi.exe.\r\n")

-      _T("System should not have any version of Omaha installed on it.\r\n")

-      _T("System should not have any version of \"!!! Test Foo\" installed on it.\r\n")

-      _T("Please run SampleSetup.exe now.\r\n")

-    );

-  }

-

-  void PrintConclusion() {

-    _tprintf(

-      _T("Test of mi.exe is complete.\r\n")

-    );

-  }

-

-private:

-  bool system_should_be_clean_;

-

-#define TEST_FOO_REG_UNINST_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{8EE7241A-9AFD-324A-884C-B62DC5DAE506}"

-#define TEST_FOO_V2_REG_UNINST_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{EE93BF87-0CDD-3F0B-A4D6-3B3A1C54E3FA}"

-

-  bool VerifyCleanSystem() {

-    if (RegistryKeyExists(HKEY_LOCAL_MACHINE, _T(TEST_FOO_REG_UNINST_KEY))) {

-      _tprintf(_T("Product !!! Test Foo (old version) appears to be installed on this system.\r\n"));

-      return false;

-    }

-    if (RegistryKeyExists(HKEY_LOCAL_MACHINE, _T(TEST_FOO_V2_REG_UNINST_KEY))) {

-      _tprintf(_T("Product !!! Test Foo appears to be installed on this system.\r\n"));

-      return false;

-    }

-    if (RegistryValueExists(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, _T("Google Update"))) {

-      _tprintf(_T("Omaha Run key is present on this system.\r\n"));

-      return false;

-    }

-    return true;

-  }

-

-  bool VerifyTestFooInstalled() {

-    if (!RegistryKeyExists(HKEY_LOCAL_MACHINE, _T(TEST_FOO_V2_REG_UNINST_KEY))) {

-      _tprintf(_T("Product !!! Test Foo is not installed on this system.\r\n"));

-      return false;

-    }

-    return true;

-  }

-

-  bool VerifyOmahaInstalled() {

-    if (!RegistryValueExists(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, _T("Google Update"))) {

-      _tprintf(_T("Omaha Run key is missing on this system.\r\n"));

-      return false;

-    }

-    return true;

-  }

-};

-

-int main() {

-

-  MIWatcher watcher;

-  watcher.Go();

-  return 0;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#pragma warning(push)
+// C4548: expression before comma has no effect
+#pragma warning(disable : 4548)
+#include <atlstr.h>
+#pragma warning(pop)
+#include <regstr.h>
+#include "omaha/mi_exe_stub/mi_step_test.h"
+#include "omaha/test/step_test.h"
+
+class MIWatcher : public StepTestWatcher {
+public:
+  MIWatcher() : StepTestWatcher(MI_STEP_TEST_NAME),
+    system_should_be_clean_(true) {
+  }
+
+  ~MIWatcher() {
+  }
+
+protected:
+  bool VerifyStep(DWORD step, bool *testing_complete) {
+    bool result = true;
+    switch (step) {
+      case MI_STEP_VERIFY_PRECONDITIONS:
+        if (system_should_be_clean_) {
+          result = VerifyCleanSystem();
+        } else {
+          result = false;
+          _tprintf(_T("Unexpected state.\r\n"));
+        }
+        break;
+      case MI_STEP_PROGRAM_START:
+        if (system_should_be_clean_) {
+          result = VerifyCleanSystem();
+          system_should_be_clean_ = false;
+        } else {
+          result = false;
+          _tprintf(_T("Unexpected state.\r\n"));
+        }
+          break;
+      case MI_STEP_PROGRAM_END:
+        result  = VerifyTestFooInstalled();
+        result &= VerifyOmahaInstalled();
+        break;
+    }
+    *testing_complete = (step >= MI_STEP_PROGRAM_END);
+    return result;
+  }
+
+  void PrintIntroduction() {
+    _tprintf(
+      _T("Ready to test mi.exe.\r\n")
+      _T("System should not have any version of Omaha installed on it.\r\n")
+      _T("System should not have any version of \"!!! Test Foo\" installed on it.\r\n")
+      _T("Please run SampleSetup.exe now.\r\n")
+    );
+  }
+
+  void PrintConclusion() {
+    _tprintf(
+      _T("Test of mi.exe is complete.\r\n")
+    );
+  }
+
+private:
+  bool system_should_be_clean_;
+
+#define TEST_FOO_REG_UNINST_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{8EE7241A-9AFD-324A-884C-B62DC5DAE506}"
+#define TEST_FOO_V2_REG_UNINST_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{EE93BF87-0CDD-3F0B-A4D6-3B3A1C54E3FA}"
+
+  bool VerifyCleanSystem() {
+    if (RegistryKeyExists(HKEY_LOCAL_MACHINE, _T(TEST_FOO_REG_UNINST_KEY))) {
+      _tprintf(_T("Product !!! Test Foo (old version) appears to be installed on this system.\r\n"));
+      return false;
+    }
+    if (RegistryKeyExists(HKEY_LOCAL_MACHINE, _T(TEST_FOO_V2_REG_UNINST_KEY))) {
+      _tprintf(_T("Product !!! Test Foo appears to be installed on this system.\r\n"));
+      return false;
+    }
+    if (RegistryValueExists(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, _T("Google Update"))) {
+      _tprintf(_T("Omaha Run key is present on this system.\r\n"));
+      return false;
+    }
+    return true;
+  }
+
+  bool VerifyTestFooInstalled() {
+    if (!RegistryKeyExists(HKEY_LOCAL_MACHINE, _T(TEST_FOO_V2_REG_UNINST_KEY))) {
+      _tprintf(_T("Product !!! Test Foo is not installed on this system.\r\n"));
+      return false;
+    }
+    return true;
+  }
+
+  bool VerifyOmahaInstalled() {
+    if (!RegistryValueExists(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, _T("Google Update"))) {
+      _tprintf(_T("Omaha Run key is missing on this system.\r\n"));
+      return false;
+    }
+    return true;
+  }
+};
+
+int main() {
+
+  MIWatcher watcher;
+  watcher.Go();
+  return 0;
+}
diff --git a/test/step_test.cc b/test/step_test.cc
index f36aea3..ed0625d 100644
--- a/test/step_test.cc
+++ b/test/step_test.cc
@@ -1,157 +1,157 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/test/step_test.h"

-

-const TCHAR *StepTestBase::RESUME_EVENT_TEMPLATE = _T("R %s");

-const TCHAR *StepTestBase::STEP_REACHED_EVENT_TEMPLATE = _T("SR %s");

-const TCHAR *StepTestBase::STATE_REG_KEY_TEMPLATE = _T("SOFTWARE\\GAT %s");

-const TCHAR *StepTestBase::STATE_REG_VALUE_NAME = _T("state");

-

-StepTestBase::StepTestBase(const TCHAR*) : step_reached_event_(NULL),

-resume_event_(NULL), state_key_(NULL) {

-}

-

-void StepTestBase::Terminate() {

-  CloseHandle(step_reached_event_);

-  CloseHandle(resume_event_);

-  RegCloseKey(state_key_);

-}

-

-StepTestBase::~StepTestBase() {

-  Terminate();

-}

-

-StepTestStepper::StepTestStepper(const TCHAR* name) :

-  StepTestBase(name),

-  is_someone_listening_(false) {

-  CString namebuf;

-

-  // A "broadcaster" is a program that notifies the "listener" program that

-  // the broadcaster has reached an interesting point in its execution, and

-  // the listener should check state.

-  //

-  // Results will be unpredictable if two broadcasters are running at the

-  // same time. However, since a broadcaster will only open the resume event

-  // and not create it, we shouldn't see any problems where two broadcasters

-  // deadlock each other.

-  namebuf.Format(RESUME_EVENT_TEMPLATE, name);

-  resume_event_ = OpenEvent(EVENT_ALL_ACCESS, FALSE, namebuf);

-  if (resume_event_ != NULL) {

-    is_someone_listening_ = true;

-

-    namebuf.Format(STEP_REACHED_EVENT_TEMPLATE, name);

-    step_reached_event_ = OpenEvent(EVENT_ALL_ACCESS, FALSE, namebuf);

-

-    namebuf.Format(STATE_REG_KEY_TEMPLATE, name);

-    RegCreateKeyEx(HKEY_CURRENT_USER, namebuf, 0, NULL, REG_OPTION_VOLATILE,

-      KEY_READ | KEY_WRITE, NULL, &state_key_, NULL);

-  } else {

-    Terminate();

-  }

-}

-

-StepTestStepper::~StepTestStepper() {

-  Terminate();

-}

-

-void StepTestStepper::Step(DWORD step) {

-  if (!is_someone_listening_) {

-    return;

-  }

-  RegSetValueEx(state_key_, STATE_REG_VALUE_NAME, 0, REG_DWORD,

-    reinterpret_cast<BYTE*>(&step), sizeof(step));

-  SetEvent(step_reached_event_);

-  WaitForSingleObject(resume_event_, INFINITE);

-}

-

-StepTestWatcher::StepTestWatcher(const TCHAR* name) : StepTestBase(name),

-  name_(name) {

-}

-

-StepTestWatcher::~StepTestWatcher() {

-  Terminate();

-}

-

-void StepTestWatcher::Go() {

-  DWORD step = 0;

-  bool done = false;

-

-  PrintIntroduction();

-

-  printf("Verifying preconditions...\r\n");

-  bool passed = VerifyStep(0, &done);

-  if (passed) {

-    _tprintf(_T("Preconditions OK.\r\n"));

-  } else {

-    _tprintf(_T("*** Preconditions FAILED. ***\r\n"));

-  }

-

-  CString namebuf;

-

-  namebuf.Format(RESUME_EVENT_TEMPLATE, name_);

-  resume_event_ = CreateEvent(NULL, FALSE, FALSE, namebuf);

-  namebuf.Format(STEP_REACHED_EVENT_TEMPLATE, name_);

-  step_reached_event_ = CreateEvent(NULL, FALSE, FALSE, namebuf);

-

-  namebuf.Format(STATE_REG_KEY_TEMPLATE, name_);

-  RegCreateKeyEx(HKEY_CURRENT_USER, namebuf, 0, NULL, REG_OPTION_VOLATILE,

-    KEY_READ, NULL, &state_key_, NULL);

-

-  printf("Begin test now.\r\n");

-

-  done = false;

-  while (!done) {

-    WaitForSingleObject(step_reached_event_, INFINITE);

-    DWORD step_size = sizeof(step);

-    RegQueryValueEx(state_key_, STATE_REG_VALUE_NAME, NULL, NULL,

-      reinterpret_cast<BYTE*>(&step), &step_size);

-    printf("Testing step %d.\r\n", step);

-    passed = VerifyStep(step, &done);

-    if (!passed) {

-      _tprintf(_T("\r\n\r\n*** TEST FAILURE: Step %d. ***\r\nr\n"), step);

-    }

-    SetEvent(resume_event_);

-  }

-

-  PrintConclusion();

-}

-

-bool StepTestWatcher::RegistryKeyExists(HKEY root, const TCHAR* name) {

-  HKEY key;

-  LONG result = RegOpenKeyEx(root, name, 0, KEY_READ, &key);

-  if (ERROR_SUCCESS == result) {

-    RegCloseKey(key);

-    return true;

-  }

-  return false;

-}

-

-bool StepTestWatcher::RegistryValueExists(HKEY root, const TCHAR* key_name,

-                                          const TCHAR* value_name) {

-  bool result = false;

-  HKEY key;

-  LONG reg_result = RegOpenKeyEx(root, key_name, 0, KEY_READ, &key);

-  if (ERROR_SUCCESS == reg_result) {

-    DWORD dummy_size = 0;

-    reg_result = RegQueryValueEx(key, value_name, NULL, NULL, NULL,

-      &dummy_size);

-    if (reg_result == ERROR_SUCCESS && dummy_size > 0) {

-      result = true;

-    }

-    RegCloseKey(key);

-  }

-  return result;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/test/step_test.h"
+
+const TCHAR *StepTestBase::RESUME_EVENT_TEMPLATE = _T("R %s");
+const TCHAR *StepTestBase::STEP_REACHED_EVENT_TEMPLATE = _T("SR %s");
+const TCHAR *StepTestBase::STATE_REG_KEY_TEMPLATE = _T("SOFTWARE\\GAT %s");
+const TCHAR *StepTestBase::STATE_REG_VALUE_NAME = _T("state");
+
+StepTestBase::StepTestBase(const TCHAR*) : step_reached_event_(NULL),
+resume_event_(NULL), state_key_(NULL) {
+}
+
+void StepTestBase::Terminate() {
+  CloseHandle(step_reached_event_);
+  CloseHandle(resume_event_);
+  RegCloseKey(state_key_);
+}
+
+StepTestBase::~StepTestBase() {
+  Terminate();
+}
+
+StepTestStepper::StepTestStepper(const TCHAR* name) :
+  StepTestBase(name),
+  is_someone_listening_(false) {
+  CString namebuf;
+
+  // A "broadcaster" is a program that notifies the "listener" program that
+  // the broadcaster has reached an interesting point in its execution, and
+  // the listener should check state.
+  //
+  // Results will be unpredictable if two broadcasters are running at the
+  // same time. However, since a broadcaster will only open the resume event
+  // and not create it, we shouldn't see any problems where two broadcasters
+  // deadlock each other.
+  namebuf.Format(RESUME_EVENT_TEMPLATE, name);
+  resume_event_ = OpenEvent(EVENT_ALL_ACCESS, FALSE, namebuf);
+  if (resume_event_ != NULL) {
+    is_someone_listening_ = true;
+
+    namebuf.Format(STEP_REACHED_EVENT_TEMPLATE, name);
+    step_reached_event_ = OpenEvent(EVENT_ALL_ACCESS, FALSE, namebuf);
+
+    namebuf.Format(STATE_REG_KEY_TEMPLATE, name);
+    RegCreateKeyEx(HKEY_CURRENT_USER, namebuf, 0, NULL, REG_OPTION_VOLATILE,
+      KEY_READ | KEY_WRITE, NULL, &state_key_, NULL);
+  } else {
+    Terminate();
+  }
+}
+
+StepTestStepper::~StepTestStepper() {
+  Terminate();
+}
+
+void StepTestStepper::Step(DWORD step) {
+  if (!is_someone_listening_) {
+    return;
+  }
+  RegSetValueEx(state_key_, STATE_REG_VALUE_NAME, 0, REG_DWORD,
+    reinterpret_cast<BYTE*>(&step), sizeof(step));
+  SetEvent(step_reached_event_);
+  WaitForSingleObject(resume_event_, INFINITE);
+}
+
+StepTestWatcher::StepTestWatcher(const TCHAR* name) : StepTestBase(name),
+  name_(name) {
+}
+
+StepTestWatcher::~StepTestWatcher() {
+  Terminate();
+}
+
+void StepTestWatcher::Go() {
+  DWORD step = 0;
+  bool done = false;
+
+  PrintIntroduction();
+
+  printf("Verifying preconditions...\r\n");
+  bool passed = VerifyStep(0, &done);
+  if (passed) {
+    _tprintf(_T("Preconditions OK.\r\n"));
+  } else {
+    _tprintf(_T("*** Preconditions FAILED. ***\r\n"));
+  }
+
+  CString namebuf;
+
+  namebuf.Format(RESUME_EVENT_TEMPLATE, name_);
+  resume_event_ = CreateEvent(NULL, FALSE, FALSE, namebuf);
+  namebuf.Format(STEP_REACHED_EVENT_TEMPLATE, name_);
+  step_reached_event_ = CreateEvent(NULL, FALSE, FALSE, namebuf);
+
+  namebuf.Format(STATE_REG_KEY_TEMPLATE, name_);
+  RegCreateKeyEx(HKEY_CURRENT_USER, namebuf, 0, NULL, REG_OPTION_VOLATILE,
+    KEY_READ, NULL, &state_key_, NULL);
+
+  printf("Begin test now.\r\n");
+
+  done = false;
+  while (!done) {
+    WaitForSingleObject(step_reached_event_, INFINITE);
+    DWORD step_size = sizeof(step);
+    RegQueryValueEx(state_key_, STATE_REG_VALUE_NAME, NULL, NULL,
+      reinterpret_cast<BYTE*>(&step), &step_size);
+    printf("Testing step %d.\r\n", step);
+    passed = VerifyStep(step, &done);
+    if (!passed) {
+      _tprintf(_T("\r\n\r\n*** TEST FAILURE: Step %d. ***\r\nr\n"), step);
+    }
+    SetEvent(resume_event_);
+  }
+
+  PrintConclusion();
+}
+
+bool StepTestWatcher::RegistryKeyExists(HKEY root, const TCHAR* name) {
+  HKEY key;
+  LONG result = RegOpenKeyEx(root, name, 0, KEY_READ, &key);
+  if (ERROR_SUCCESS == result) {
+    RegCloseKey(key);
+    return true;
+  }
+  return false;
+}
+
+bool StepTestWatcher::RegistryValueExists(HKEY root, const TCHAR* key_name,
+                                          const TCHAR* value_name) {
+  bool result = false;
+  HKEY key;
+  LONG reg_result = RegOpenKeyEx(root, key_name, 0, KEY_READ, &key);
+  if (ERROR_SUCCESS == reg_result) {
+    DWORD dummy_size = 0;
+    reg_result = RegQueryValueEx(key, value_name, NULL, NULL, NULL,
+      &dummy_size);
+    if (reg_result == ERROR_SUCCESS && dummy_size > 0) {
+      result = true;
+    }
+    RegCloseKey(key);
+  }
+  return result;
+}
diff --git a/test/step_test.h b/test/step_test.h
index 15ba6ae..2905a9c 100644
--- a/test/step_test.h
+++ b/test/step_test.h
@@ -1,95 +1,95 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#pragma warning(push)

-// C4548: expression before comma has no effect

-#pragma warning(disable : 4548)

-#include <atlstr.h>

-#pragma warning(pop)

-

-// Overview

-//

-// The program to be tested instantiates a StepTestStepper, passing in a

-// unique identifier (by convention, a GUID in registry format). It then

-// calls StepTestStepper::Step() with values representing specific points in

-// execution of the program.

-//

-// Then in test/omaha_system_test.cpp, derive a concrete subclass of

-// StepTestWatcher. In particular, implement VerifyStep(), which takes each of

-// the values passed in through the tested program's StepTestStepper::Step()

-// function, and verifies that the state of the system matches what it should

-// be.

-

-class StepTestBase {

-public:

-  StepTestBase(const TCHAR *name);

-  virtual ~StepTestBase();

-

-protected:

-  HANDLE step_reached_event_;

-  HANDLE resume_event_;

-  HKEY state_key_;

-

-  static const TCHAR *RESUME_EVENT_TEMPLATE;

-  static const TCHAR *STEP_REACHED_EVENT_TEMPLATE;

-  static const TCHAR *STATE_REG_KEY_TEMPLATE;

-  static const TCHAR *STATE_REG_VALUE_NAME;

-

-  void Terminate();

-};

-

-class StepTestStepper : public StepTestBase {

-public:

-  StepTestStepper(const TCHAR *name);

-  virtual ~StepTestStepper();

-

-  void Step(DWORD step);

-private:

-  bool is_someone_listening_;

-};

-

-class StepTestWatcher : public StepTestBase {

-public:

-  StepTestWatcher(const TCHAR *name);

-  virtual ~StepTestWatcher();

-

-  void Go();

-

-protected:

-  // Checks the state of the machine once the tested program has reached the

-  // given step.

-  //

-  // @param step: the step to be verified

-  // @param testing_complete: pointer to bool that should be set to true iff

-  // the testing instance is done testing and should now terminate.

-  // @return true iff the test of this step passed.

-  virtual bool VerifyStep(DWORD step, bool *testing_complete) = 0;

-

-  // Prints instructions to the console telling the human tester what the

-  // expected setup of the system should be.

-  virtual void PrintIntroduction() = 0;

-

-  // Prints a statement to the console indicating that testing is complete.

-  virtual void PrintConclusion() = 0;

-

-  // Returns true iff the given registry key exists on this machine.

-  bool RegistryKeyExists(HKEY root, const TCHAR *name);

-

-  // Returns true iff the given registry value exists on this machine.

-  bool RegistryValueExists(HKEY root, const TCHAR *key_name,

-    const TCHAR *value_name);

-

-  CString name_;

-};

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#pragma warning(push)
+// C4548: expression before comma has no effect
+#pragma warning(disable : 4548)
+#include <atlstr.h>
+#pragma warning(pop)
+
+// Overview
+//
+// The program to be tested instantiates a StepTestStepper, passing in a
+// unique identifier (by convention, a GUID in registry format). It then
+// calls StepTestStepper::Step() with values representing specific points in
+// execution of the program.
+//
+// Then in test/omaha_system_test.cpp, derive a concrete subclass of
+// StepTestWatcher. In particular, implement VerifyStep(), which takes each of
+// the values passed in through the tested program's StepTestStepper::Step()
+// function, and verifies that the state of the system matches what it should
+// be.
+
+class StepTestBase {
+public:
+  StepTestBase(const TCHAR *name);
+  virtual ~StepTestBase();
+
+protected:
+  HANDLE step_reached_event_;
+  HANDLE resume_event_;
+  HKEY state_key_;
+
+  static const TCHAR *RESUME_EVENT_TEMPLATE;
+  static const TCHAR *STEP_REACHED_EVENT_TEMPLATE;
+  static const TCHAR *STATE_REG_KEY_TEMPLATE;
+  static const TCHAR *STATE_REG_VALUE_NAME;
+
+  void Terminate();
+};
+
+class StepTestStepper : public StepTestBase {
+public:
+  StepTestStepper(const TCHAR *name);
+  virtual ~StepTestStepper();
+
+  void Step(DWORD step);
+private:
+  bool is_someone_listening_;
+};
+
+class StepTestWatcher : public StepTestBase {
+public:
+  StepTestWatcher(const TCHAR *name);
+  virtual ~StepTestWatcher();
+
+  void Go();
+
+protected:
+  // Checks the state of the machine once the tested program has reached the
+  // given step.
+  //
+  // @param step: the step to be verified
+  // @param testing_complete: pointer to bool that should be set to true iff
+  // the testing instance is done testing and should now terminate.
+  // @return true iff the test of this step passed.
+  virtual bool VerifyStep(DWORD step, bool *testing_complete) = 0;
+
+  // Prints instructions to the console telling the human tester what the
+  // expected setup of the system should be.
+  virtual void PrintIntroduction() = 0;
+
+  // Prints a statement to the console indicating that testing is complete.
+  virtual void PrintConclusion() = 0;
+
+  // Returns true iff the given registry key exists on this machine.
+  bool RegistryKeyExists(HKEY root, const TCHAR *name);
+
+  // Returns true iff the given registry value exists on this machine.
+  bool RegistryValueExists(HKEY root, const TCHAR *key_name,
+    const TCHAR *value_name);
+
+  CString name_;
+};
diff --git a/test/test_bar.cc b/test/test_bar.cc
index f2fa1ad..6236249 100644
--- a/test/test_bar.cc
+++ b/test/test_bar.cc
@@ -1,24 +1,24 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <tchar.h>

-

-// This file implements a tiny program that puts up a MessageBox and exits.

-// It's useful for generating test installation targets.

-int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {

-  MessageBox(NULL, _T("I am bar"), _T("bar"), MB_OK | MB_ICONINFORMATION);

-  return 0;

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <tchar.h>
+
+// This file implements a tiny program that puts up a MessageBox and exits.
+// It's useful for generating test installation targets.
+int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
+  MessageBox(NULL, _T("I am bar"), _T("bar"), MB_OK | MB_ICONINFORMATION);
+  return 0;
+}
diff --git a/test/test_foo.cc b/test/test_foo.cc
index 7cd9c6a..905c492 100644
--- a/test/test_foo.cc
+++ b/test/test_foo.cc
@@ -1,39 +1,39 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include <windows.h>

-#include <tchar.h>

-

-// This file implements a tiny program that puts up a MessageBox and exits.

-// It's useful for generating test installation targets.

-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) {

-  TCHAR my_path[MAX_PATH];

-  char ver_buf[2048];

-  VS_FIXEDFILEINFO *ffi = NULL;

-  UINT ver_len = 0;

-  GetModuleFileName(hInstance, my_path, MAX_PATH);

-  GetFileVersionInfo(my_path, NULL, 2048, ver_buf);

-  VerQueryValue(ver_buf, _T("\\"), reinterpret_cast<LPVOID *>(&ffi), &ver_len);

-

-  TCHAR msgbuf[256];

-  _sntprintf(msgbuf, 256, _T("I am foo v. %d.%d.%d.%d!"),

-    HIWORD(ffi->dwFileVersionMS),

-    LOWORD(ffi->dwFileVersionMS),

-    HIWORD(ffi->dwFileVersionLS),

-    LOWORD(ffi->dwFileVersionLS));

-  MessageBox(NULL, msgbuf, _T("foo"), MB_OK | MB_ICONINFORMATION);

-  return 0;

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include <windows.h>
+#include <tchar.h>
+
+// This file implements a tiny program that puts up a MessageBox and exits.
+// It's useful for generating test installation targets.
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) {
+  TCHAR my_path[MAX_PATH];
+  char ver_buf[2048];
+  VS_FIXEDFILEINFO *ffi = NULL;
+  UINT ver_len = 0;
+  GetModuleFileName(hInstance, my_path, MAX_PATH);
+  GetFileVersionInfo(my_path, NULL, 2048, ver_buf);
+  VerQueryValue(ver_buf, _T("\\"), reinterpret_cast<LPVOID *>(&ffi), &ver_len);
+
+  TCHAR msgbuf[256];
+  _sntprintf(msgbuf, 256, _T("I am foo v. %d.%d.%d.%d!"),
+    HIWORD(ffi->dwFileVersionMS),
+    LOWORD(ffi->dwFileVersionMS),
+    HIWORD(ffi->dwFileVersionLS),
+    LOWORD(ffi->dwFileVersionLS));
+  MessageBox(NULL, msgbuf, _T("foo"), MB_OK | MB_ICONINFORMATION);
+  return 0;
+}
diff --git a/test/test_foo.rc b/test/test_foo.rc
index 46a0107..1c462d7 100644
--- a/test/test_foo.rc
+++ b/test/test_foo.rc
@@ -1,101 +1,101 @@
-// Microsoft Visual C++ generated resource script.

-//

-#include "test/test_foo_resource.h"

-

-#define APSTUDIO_READONLY_SYMBOLS

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

-//

-// Generated from the TEXTINCLUDE 2 resource.

-//

-#include "afxres.h"

-

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

-#undef APSTUDIO_READONLY_SYMBOLS

-

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

-// English (U.S.) resources

-

-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)

-#ifdef _WIN32

-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

-#pragma code_page(1252)

-#endif //_WIN32

-

-#ifdef APSTUDIO_INVOKED

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

-//

-// TEXTINCLUDE

-//

-

-1 TEXTINCLUDE

-BEGIN

-    "test/test_foo_resource.h\0"

-END

-

-2 TEXTINCLUDE

-BEGIN

-    "#include ""afxres.h""\r\n"

-    "\0"

-END

-

-3 TEXTINCLUDE

-BEGIN

-    "\r\n"

-    "\0"

-END

-

-#endif    // APSTUDIO_INVOKED

-

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

-//

-// Version

-//

-

-VS_VERSION_INFO VERSIONINFO

- FILEVERSION MAJOR,MINOR,BUILD,PATCH

- PRODUCTVERSION MAJOR,MINOR,BUILD,PATCH

- FILEFLAGSMASK 0x3fL

-#ifdef _DEBUG

- FILEFLAGS 0x1L

-#else

- FILEFLAGS 0x0L

-#endif

- FILEOS 0x4L

- FILETYPE 0x2L

- FILESUBTYPE 0x0L

-BEGIN

-    BLOCK "StringFileInfo"

-    BEGIN

-        BLOCK "040904e4"

-        BEGIN

-            VALUE "CompanyName", "Google Inc."

-            VALUE "FileDescription", "test_foo.exe"

-            VALUE "FileVersion", VERSION_STRING

-            VALUE "LegalCopyright", "Copyright 2007 Google Inc. All rights reserved."

-            VALUE "InternalName", "test_foo.exe"

-            VALUE "OriginalFilename", "test_foo.exe"

-            VALUE "ProductName", "test_foo.exe"

-            VALUE "ProductVersion", VERSION_STRING

-        END

-    END

-    BLOCK "VarFileInfo"

-    BEGIN

-        VALUE "Translation", 0x409, 1252

-    END

-END

-

-#endif    // English (U.S.) resources

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

-

-

-

-#ifndef APSTUDIO_INVOKED

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

-//

-// Generated from the TEXTINCLUDE 3 resource.

-//

-

-

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

-#endif    // not APSTUDIO_INVOKED

-

+// Microsoft Visual C++ generated resource script.
+//
+#include "test/test_foo_resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+    "test/test_foo_resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MAJOR,MINOR,BUILD,PATCH
+ PRODUCTVERSION MAJOR,MINOR,BUILD,PATCH
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "CompanyName", "Google Inc."
+            VALUE "FileDescription", "test_foo.exe"
+            VALUE "FileVersion", VERSION_STRING
+            VALUE "LegalCopyright", "Copyright 2007 Google Inc. All rights reserved."
+            VALUE "InternalName", "test_foo.exe"
+            VALUE "OriginalFilename", "test_foo.exe"
+            VALUE "ProductName", "test_foo.exe"
+            VALUE "ProductVersion", VERSION_STRING
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252
+    END
+END
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/test/test_foo.wxs.xml b/test/test_foo.wxs.xml
index 92a001d..127475a 100644
--- a/test/test_foo.wxs.xml
+++ b/test/test_foo.wxs.xml
@@ -1,179 +1,179 @@
-<?xml version='1.0'?>

-<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>

-  <?define UpgradeCode='96E1371A-A5A1-45cc-8E67-2EF6ABDE054D' ?>

-

-   <Product Id='$(var.FooProductGuid)' Name='!!! Test Foo' Language='1033'

-     Version='$(var.FooVersion)' Manufacturer='Google, Inc.'

-     UpgradeCode='$(var.UpgradeCode)'>

-

-        <!--

-        This file has all the values necessary to report success or failure.

-        It can also be made to report neither (for testing failure cases).

-        Note that the way failure is generated is NOT how it should be done for

-        real installers. See FooNotifyFailed for details.

-

-        This file supports several scenarios. Enabling each one is described below.

-        * Success (default)

-          - Do not specify any properties

-        * Success and tell Omaha to launch Foo

-          - Specify REGISTER_LAUNCH_COMMAND property (any value)

-        * Failure

-          - Specify the NOTIFY_FAILURE property (any value)

-        * No result reported (Omaha will use exit code)

-          - Specify the DO_NOT_NOTIFY_SUCCESS property (any value)

-

-        The registry value propbar can be written.

-          - Specify the PROPBAR property with value 7.

-

-        This file also supports failing product condtions. In this case, no

-        success or failure value is written, as would happen with real

-        installers.

-          - Specify the FAIL_PRODUCT_CONDITION property (any value)

-        -->

-

-        <Package Id='*'

-           Description='Test Foo' Comments='Test Foo'

-           Manufacturer='Google, Inc.' InstallerVersion='200' Compressed='yes' />

-

-        <Upgrade Id='$(var.UpgradeCode)'>

-          <UpgradeVersion Property='UPGRADING'

-                          OnlyDetect='no'

-                          Minimum='0.0.0.0' IncludeMinimum='yes'

-                          Maximum='$(var.FooVersion)' IncludeMaximum='no' />

-          <UpgradeVersion Property='NEWERVERSIONDETECTED'

-                          OnlyDetect='yes'

-                          Minimum='$(var.FooVersion)' IncludeMinimum='yes' />

-        </Upgrade>

-

-        <!-- Omaha id -->

-        <Property Id='UPDATE2_ID'>{D6B08267-B440-4c85-9F79-E195E80D9937}</Property>

-

-        <InstallExecuteSequence>

-          <!--  We can either put RemoveExistingProducts after InstallValidate

-            or InstallFinalize.

-            1) After InstallValidate

-               * The old verion goes away anyway no matter if the new version

-                 has been installed successfully.

-            2) After InstallFinalize

-               * Might leave both old version and new version in the system if

-                 MSI fails to uninstall the old version.

-               * Will remove files and registry entries, including Omaha

-                 registration, for the new version. Thus, we cannot use this

-                 option without adding complexity. Reference:

-                 http://blogs.msdn.com/astebner/archive/2007/09/06/4798334.aspx

-          -->

-          <RemoveExistingProducts After='InstallValidate'>UPGRADING</RemoveExistingProducts>

-          <Custom Action="NewerVersionError" After="FindRelatedProducts">NEWERVERSIONDETECTED</Custom>

-        </InstallExecuteSequence>

-

-        <CustomAction Id="NewerVersionError" Error="4000"/>

-

-        <Property Id="ALLUSERS"><![CDATA[1]]></Property>

-

-        <Media Id='1' Cabinet='product.cab' EmbedCab='yes' CompressionLevel='high' />

-

-        <Directory Id='TARGETDIR' Name='SourceDir'>

-          <Directory Id='ProgramFilesFolder'>

-            <Directory Id='FooDir' Name='Test Foo'>

-              <Directory Id='FooVersion' Name='$(var.FooVersion)'>

-                <Component Id='FooFiles' Guid='$(var.FooComponentGuid)'>

-                  <File Id='test_foo' Vital='yes' Name='test_foo.exe'

-                    DiskId='1' Source="$(var.FooExePath)"/>

-                </Component>

-              </Directory>

-              <Component Id='FooReg' Guid='$(var.FooComponentGuidRegistry)'>

-                <RegistryValue Root='HKLM'

-                  Key='Software\Google\Update\Clients\[UPDATE2_ID]'

-                  Name='name' Value="test_foo"

-                  Action='write' Type='string' />

-                <RegistryValue Root='HKLM'

-                  Key='Software\Google\Update\Clients\[UPDATE2_ID]'

-                  Name='pv' Value="$(var.FooVersion)"

-                  Action='write' Type='string' />

-              </Component>

-              <Component Id='FooNotifySuccess' Guid='$(var.FooComponentGuidNotifySuccess)'>

-                <!-- Controls whether to notify success. -->

-                <Condition>NOT NOTIFY_FAILURE AND NOT DO_NOT_NOTIFY_SUCCESS</Condition>

-                <RegistryValue Root='HKLM'

-                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'

-                  Name='InstallerResult' Value="0"

-                  Action='write' Type='integer' />

-                <RegistryValue Root='HKLM'

-                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'

-                  Name='InstallerError' Value="1234"

-                  Action='write' Type='integer' />

-              </Component>

-              <Component Id='FooRegisterLaunchCommand'

-                         Guid='$(var.FooComponentRegisterLaunchCommand)'>

-                <!-- Controls whether to notify success. -->

-                <Condition>REGISTER_LAUNCH_COMMAND AND NOT DO_NOT_NOTIFY_SUCCESS</Condition>

-                <RegistryValue Root='HKLM'

-                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'

-                  Name='InstallerSuccessLaunchCmdLine' Value="&quot;[#test_foo]&quot;"

-                  Action='write' Type='string' />

-              </Component>

-              <!--

-              Writes the registry entries that indicate failure.

-              This method of writing the registry for failures is only useful

-              for simple testing.

-              Real installers will NOT report failure in this way.

-              They would report the failure in custom action code.

-              The reason is that this component will only get run and the

-              side effects left in place if success succeeds.

-              -->

-              <Component Id='FooNotifyFailed' Guid='$(var.FooComponentGuidNotifyFailed)'>

-                <!-- Controls whether to notify failure. -->

-                <Condition>NOTIFY_FAILURE</Condition>

-                <RegistryValue Root='HKLM'

-                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'

-                  Name='InstallerResult' Value="1"

-                  Action='write' Type='integer' />

-                <RegistryValue Root='HKLM'

-                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'

-                  Name='InstallerError' Value="99"

-                  Action='write' Type='integer' />

-                <RegistryValue Root='HKLM'

-                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'

-                  Name='InstallerResultUIString' Value="&lt;b&gt;Test Foo&lt;/b&gt; installation failed because it wanted to! For more information visit &lt;a=http://labs.google.com/&gt;http://labs.google.com/&lt;/a&gt;."

-                  Action='write' Type='string' />

-              </Component>

-              <Component Id='FooPropBar' Guid='$(var.FooComponentGuidPropertyBar)'>

-                <!-- Controls whether to write propbar. -->

-                <Condition>PROPBAR=7</Condition>

-                <RegistryValue Root='HKLM'

-                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'

-                  Name='propbar' Value="7"

-                  Action='write' Type='integer' />

-              </Component>

-            </Directory>

-         </Directory>

-      </Directory>

-

-      <Feature Id='Foo' Title='Foo' Level='1'>

-        <ComponentRef Id='FooFiles' />

-        <ComponentRef Id='FooReg' />

-        <ComponentRef Id='FooNotifySuccess' />

-        <ComponentRef Id='FooRegisterLaunchCommand' />

-        <ComponentRef Id='FooNotifyFailed' />

-        <ComponentRef Id='FooPropBar' />

-<?if $(var.IsEnterprise) = 1 ?>

-        <ComponentRef Id='ComponentGoogleUpdate' />

-<?endif?>

-      </Feature>

-      <Property Id="UILevel"><![CDATA[1]]></Property>

-

-      <Condition Message='Test Foo runs only on Windows 2000 Service Pack 3 and later.'>

-        (VersionNT = 500 AND ServicePackLevel = 3) OR VersionNT >= 501

-      </Condition>

-

-     <Condition Message='The FAIL_PRODUCT_CONDITION property was specified.'>

-       NOT FAIL_PRODUCT_CONDITION

-     </Condition>

-

-     <UI>

-       <Error Id="4000">A newer version of this product is already installed.</Error>

-     </UI>

-

-   </Product>

-</Wix>

-

+<?xml version='1.0'?>
+<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
+  <?define UpgradeCode='96E1371A-A5A1-45cc-8E67-2EF6ABDE054D' ?>
+
+   <Product Id='$(var.FooProductGuid)' Name='!!! Test Foo' Language='1033'
+     Version='$(var.FooVersion)' Manufacturer='Google, Inc.'
+     UpgradeCode='$(var.UpgradeCode)'>
+
+        <!--
+        This file has all the values necessary to report success or failure.
+        It can also be made to report neither (for testing failure cases).
+        Note that the way failure is generated is NOT how it should be done for
+        real installers. See FooNotifyFailed for details.
+
+        This file supports several scenarios. Enabling each one is described below.
+        * Success (default)
+          - Do not specify any properties
+        * Success and tell Omaha to launch Foo
+          - Specify REGISTER_LAUNCH_COMMAND property (any value)
+        * Failure
+          - Specify the NOTIFY_FAILURE property (any value)
+        * No result reported (Omaha will use exit code)
+          - Specify the DO_NOT_NOTIFY_SUCCESS property (any value)
+
+        The registry value propbar can be written.
+          - Specify the PROPBAR property with value 7.
+
+        This file also supports failing product condtions. In this case, no
+        success or failure value is written, as would happen with real
+        installers.
+          - Specify the FAIL_PRODUCT_CONDITION property (any value)
+        -->
+
+        <Package Id='*'
+           Description='Test Foo' Comments='Test Foo'
+           Manufacturer='Google, Inc.' InstallerVersion='200' Compressed='yes' />
+
+        <Upgrade Id='$(var.UpgradeCode)'>
+          <UpgradeVersion Property='UPGRADING'
+                          OnlyDetect='no'
+                          Minimum='0.0.0.0' IncludeMinimum='yes'
+                          Maximum='$(var.FooVersion)' IncludeMaximum='no' />
+          <UpgradeVersion Property='NEWERVERSIONDETECTED'
+                          OnlyDetect='yes'
+                          Minimum='$(var.FooVersion)' IncludeMinimum='yes' />
+        </Upgrade>
+
+        <!-- Omaha id -->
+        <Property Id='UPDATE2_ID'>{D6B08267-B440-4c85-9F79-E195E80D9937}</Property>
+
+        <InstallExecuteSequence>
+          <!--  We can either put RemoveExistingProducts after InstallValidate
+            or InstallFinalize.
+            1) After InstallValidate
+               * The old verion goes away anyway no matter if the new version
+                 has been installed successfully.
+            2) After InstallFinalize
+               * Might leave both old version and new version in the system if
+                 MSI fails to uninstall the old version.
+               * Will remove files and registry entries, including Omaha
+                 registration, for the new version. Thus, we cannot use this
+                 option without adding complexity. Reference:
+                 http://blogs.msdn.com/astebner/archive/2007/09/06/4798334.aspx
+          -->
+          <RemoveExistingProducts After='InstallValidate'>UPGRADING</RemoveExistingProducts>
+          <Custom Action="NewerVersionError" After="FindRelatedProducts">NEWERVERSIONDETECTED</Custom>
+        </InstallExecuteSequence>
+
+        <CustomAction Id="NewerVersionError" Error="4000"/>
+
+        <Property Id="ALLUSERS"><![CDATA[1]]></Property>
+
+        <Media Id='1' Cabinet='product.cab' EmbedCab='yes' CompressionLevel='high' />
+
+        <Directory Id='TARGETDIR' Name='SourceDir'>
+          <Directory Id='ProgramFilesFolder'>
+            <Directory Id='FooDir' Name='Test Foo'>
+              <Directory Id='FooVersion' Name='$(var.FooVersion)'>
+                <Component Id='FooFiles' Guid='$(var.FooComponentGuid)'>
+                  <File Id='test_foo' Vital='yes' Name='test_foo.exe'
+                    DiskId='1' Source="$(var.FooExePath)"/>
+                </Component>
+              </Directory>
+              <Component Id='FooReg' Guid='$(var.FooComponentGuidRegistry)'>
+                <RegistryValue Root='HKLM'
+                  Key='Software\Google\Update\Clients\[UPDATE2_ID]'
+                  Name='name' Value="test_foo"
+                  Action='write' Type='string' />
+                <RegistryValue Root='HKLM'
+                  Key='Software\Google\Update\Clients\[UPDATE2_ID]'
+                  Name='pv' Value="$(var.FooVersion)"
+                  Action='write' Type='string' />
+              </Component>
+              <Component Id='FooNotifySuccess' Guid='$(var.FooComponentGuidNotifySuccess)'>
+                <!-- Controls whether to notify success. -->
+                <Condition>NOT NOTIFY_FAILURE AND NOT DO_NOT_NOTIFY_SUCCESS</Condition>
+                <RegistryValue Root='HKLM'
+                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'
+                  Name='InstallerResult' Value="0"
+                  Action='write' Type='integer' />
+                <RegistryValue Root='HKLM'
+                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'
+                  Name='InstallerError' Value="1234"
+                  Action='write' Type='integer' />
+              </Component>
+              <Component Id='FooRegisterLaunchCommand'
+                         Guid='$(var.FooComponentRegisterLaunchCommand)'>
+                <!-- Controls whether to notify success. -->
+                <Condition>REGISTER_LAUNCH_COMMAND AND NOT DO_NOT_NOTIFY_SUCCESS</Condition>
+                <RegistryValue Root='HKLM'
+                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'
+                  Name='InstallerSuccessLaunchCmdLine' Value="&quot;[#test_foo]&quot;"
+                  Action='write' Type='string' />
+              </Component>
+              <!--
+              Writes the registry entries that indicate failure.
+              This method of writing the registry for failures is only useful
+              for simple testing.
+              Real installers will NOT report failure in this way.
+              They would report the failure in custom action code.
+              The reason is that this component will only get run and the
+              side effects left in place if success succeeds.
+              -->
+              <Component Id='FooNotifyFailed' Guid='$(var.FooComponentGuidNotifyFailed)'>
+                <!-- Controls whether to notify failure. -->
+                <Condition>NOTIFY_FAILURE</Condition>
+                <RegistryValue Root='HKLM'
+                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'
+                  Name='InstallerResult' Value="1"
+                  Action='write' Type='integer' />
+                <RegistryValue Root='HKLM'
+                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'
+                  Name='InstallerError' Value="99"
+                  Action='write' Type='integer' />
+                <RegistryValue Root='HKLM'
+                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'
+                  Name='InstallerResultUIString' Value="&lt;b&gt;Test Foo&lt;/b&gt; installation failed because it wanted to! For more information visit &lt;a=http://labs.google.com/&gt;http://labs.google.com/&lt;/a&gt;."
+                  Action='write' Type='string' />
+              </Component>
+              <Component Id='FooPropBar' Guid='$(var.FooComponentGuidPropertyBar)'>
+                <!-- Controls whether to write propbar. -->
+                <Condition>PROPBAR=7</Condition>
+                <RegistryValue Root='HKLM'
+                  Key='Software\Google\Update\ClientState\[UPDATE2_ID]'
+                  Name='propbar' Value="7"
+                  Action='write' Type='integer' />
+              </Component>
+            </Directory>
+         </Directory>
+      </Directory>
+
+      <Feature Id='Foo' Title='Foo' Level='1'>
+        <ComponentRef Id='FooFiles' />
+        <ComponentRef Id='FooReg' />
+        <ComponentRef Id='FooNotifySuccess' />
+        <ComponentRef Id='FooRegisterLaunchCommand' />
+        <ComponentRef Id='FooNotifyFailed' />
+        <ComponentRef Id='FooPropBar' />
+<?if $(var.IsEnterprise) = 1 ?>
+        <ComponentRef Id='ComponentGoogleUpdate' />
+<?endif?>
+      </Feature>
+      <Property Id="UILevel"><![CDATA[1]]></Property>
+
+      <Condition Message='Test Foo runs only on Windows 2000 Service Pack 3 and later.'>
+        (VersionNT = 500 AND ServicePackLevel = 3) OR VersionNT >= 501
+      </Condition>
+
+     <Condition Message='The FAIL_PRODUCT_CONDITION property was specified.'>
+       NOT FAIL_PRODUCT_CONDITION
+     </Condition>
+
+     <UI>
+       <Error Id="4000">A newer version of this product is already installed.</Error>
+     </UI>
+
+   </Product>
+</Wix>
+
diff --git a/test/test_foo_resource.h b/test/test_foo_resource.h
index 310b571..731ce08 100644
--- a/test/test_foo_resource.h
+++ b/test/test_foo_resource.h
@@ -1,29 +1,29 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//{{NO_DEPENDENCIES}}

-// Microsoft Visual C++ generated include file.

-// Used by setup_grp.rc

-//

-

-// Next default values for new objects

-// 

-#ifdef APSTUDIO_INVOKED

-#ifndef APSTUDIO_READONLY_SYMBOLS

-#define _APS_NEXT_RESOURCE_VALUE        101

-#define _APS_NEXT_COMMAND_VALUE         40001

-#define _APS_NEXT_CONTROL_VALUE         1001

-#define _APS_NEXT_SYMED_VALUE           101

-#endif

-#endif

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by setup_grp.rc
+//
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        101
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/test/user_app.wxs.xml b/test/user_app.wxs.xml
index b7f71dd..2e4ffcc 100644
--- a/test/user_app.wxs.xml
+++ b/test/user_app.wxs.xml
@@ -1,69 +1,69 @@
-<?xml version='1.0'?>

-<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>

-   <Product Id='$(var.FooProductGuid)' Name='!!! User Test Foo' Language='1033'

-     Version="$(var.FooVersion)" Manufacturer='Google'

-     UpgradeCode='97781963-8283-4602-A9DA-CAE7A5536C75'>

-     <Package Id='*'

-       Description='User Test Foo' Comments='User Test Foo'

-       Manufacturer='Google' InstallerVersion='200' Compressed='yes' />

-

-      <Upgrade Id='97781963-8283-4602-A9DA-CAE7A5536C75'>

-        <UpgradeVersion Property='UPGRADING'

-                        OnlyDetect='no'

-                        Minimum='0.0.0.0' IncludeMinimum='yes'

-                        Maximum='$(var.FooVersion)' IncludeMaximum='no' />

-        <UpgradeVersion Property='NEWERVERSIONDETECTED' 

-                        OnlyDetect='yes'

-                        Minimum='$(var.FooVersion)' IncludeMinimum='yes' />

-      </Upgrade>

-

-     <InstallExecuteSequence>

-       <RemoveExistingProducts After='InstallValidate'>UPGRADING</RemoveExistingProducts>

-     </InstallExecuteSequence>

-

-     <Media Id='1' Cabinet='product.cab' EmbedCab='yes' CompressionLevel='high' />

-

-     <Directory Id='TARGETDIR' Name='SourceDir'>

-       <Directory Id='LocalAppDataFolder' Name='PFiles'>

-          <Directory Id='UserFooDir' Name='UserTestFoo'>

-            <Directory Id='UserFooVersion' Name='$(var.FooVersion)'>

-              <Component Id='UserFooFiles' Guid='$(var.FooComponentGuid)'>

-                <File Id='test_foo' Vital='yes' Name='test_foo.exe'

-                  DiskId='1' Source="$(var.FooExePath)"/>

-                <RegistryValue Id='test_foo' Root='HKCU' Key='Software\Microsoft\RunAs\KeyPaths' Type='string' Value='test_foo.exe' KeyPath='yes' />

-                <RemoveFolder Id='UserFooVersion' Directory='UserFooVersion' On='uninstall'/>

-                <RemoveFolder Id='UserFooDir' Directory='UserFooDir' On='uninstall'/>

-                <Condition>NOT (ALLUSERS)</Condition>

-              </Component>

-            </Directory>

-            <Component Id='UserFooReg' Guid='$(var.FooComponentGuidRegistry)'>

-              <RegistryValue Root='HKCU'

-                Key='Software\Google\Update\Clients\{104844D6-7DDA-460b-89F0-FBF8AFDD0A67}'

-                Name='name' Value="user_test_foo"

-                Action='write' Type='string' />

-              <RegistryValue Root='HKCU'

-                Key='Software\Google\Update\Clients\{104844D6-7DDA-460b-89F0-FBF8AFDD0A67}'

-                Name='pv' Value="$(var.FooVersion)"

-                Action='write' Type='string' />

-              <Condition>NOT (ALLUSERS)</Condition>

-            </Component>

-          </Directory>

-       </Directory>

-     </Directory>

- 

-     <Feature Id='Foo' Title='Foo' Level='1'>

-       <ComponentRef Id='UserFooFiles' />

-       <ComponentRef Id='UserFooReg' />

-     </Feature>

-     <Property Id="UILevel"><![CDATA[1]]></Property>

-

-     <Condition Message='Test Foo runs only on Windows 2000 Service Pack 3 and later.'>

-       (VersionNT = 500 AND ServicePackLevel = 3) OR VersionNT >= 501

-     </Condition>

-

-     <Condition Message='User Test Foo only runs as a non admin'>

-       NOT ALLUSERS

-     </Condition>  

-   </Product>

-</Wix>

-

+<?xml version='1.0'?>
+<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
+   <Product Id='$(var.FooProductGuid)' Name='!!! User Test Foo' Language='1033'
+     Version="$(var.FooVersion)" Manufacturer='Google'
+     UpgradeCode='97781963-8283-4602-A9DA-CAE7A5536C75'>
+     <Package Id='*'
+       Description='User Test Foo' Comments='User Test Foo'
+       Manufacturer='Google' InstallerVersion='200' Compressed='yes' />
+
+      <Upgrade Id='97781963-8283-4602-A9DA-CAE7A5536C75'>
+        <UpgradeVersion Property='UPGRADING'
+                        OnlyDetect='no'
+                        Minimum='0.0.0.0' IncludeMinimum='yes'
+                        Maximum='$(var.FooVersion)' IncludeMaximum='no' />
+        <UpgradeVersion Property='NEWERVERSIONDETECTED' 
+                        OnlyDetect='yes'
+                        Minimum='$(var.FooVersion)' IncludeMinimum='yes' />
+      </Upgrade>
+
+     <InstallExecuteSequence>
+       <RemoveExistingProducts After='InstallValidate'>UPGRADING</RemoveExistingProducts>
+     </InstallExecuteSequence>
+
+     <Media Id='1' Cabinet='product.cab' EmbedCab='yes' CompressionLevel='high' />
+
+     <Directory Id='TARGETDIR' Name='SourceDir'>
+       <Directory Id='LocalAppDataFolder' Name='PFiles'>
+          <Directory Id='UserFooDir' Name='UserTestFoo'>
+            <Directory Id='UserFooVersion' Name='$(var.FooVersion)'>
+              <Component Id='UserFooFiles' Guid='$(var.FooComponentGuid)'>
+                <File Id='test_foo' Vital='yes' Name='test_foo.exe'
+                  DiskId='1' Source="$(var.FooExePath)"/>
+                <RegistryValue Id='test_foo' Root='HKCU' Key='Software\Microsoft\RunAs\KeyPaths' Type='string' Value='test_foo.exe' KeyPath='yes' />
+                <RemoveFolder Id='UserFooVersion' Directory='UserFooVersion' On='uninstall'/>
+                <RemoveFolder Id='UserFooDir' Directory='UserFooDir' On='uninstall'/>
+                <Condition>NOT (ALLUSERS)</Condition>
+              </Component>
+            </Directory>
+            <Component Id='UserFooReg' Guid='$(var.FooComponentGuidRegistry)'>
+              <RegistryValue Root='HKCU'
+                Key='Software\Google\Update\Clients\{104844D6-7DDA-460b-89F0-FBF8AFDD0A67}'
+                Name='name' Value="user_test_foo"
+                Action='write' Type='string' />
+              <RegistryValue Root='HKCU'
+                Key='Software\Google\Update\Clients\{104844D6-7DDA-460b-89F0-FBF8AFDD0A67}'
+                Name='pv' Value="$(var.FooVersion)"
+                Action='write' Type='string' />
+              <Condition>NOT (ALLUSERS)</Condition>
+            </Component>
+          </Directory>
+       </Directory>
+     </Directory>
+ 
+     <Feature Id='Foo' Title='Foo' Level='1'>
+       <ComponentRef Id='UserFooFiles' />
+       <ComponentRef Id='UserFooReg' />
+     </Feature>
+     <Property Id="UILevel"><![CDATA[1]]></Property>
+
+     <Condition Message='Test Foo runs only on Windows 2000 Service Pack 3 and later.'>
+       (VersionNT = 500 AND ServicePackLevel = 3) OR VersionNT >= 501
+     </Condition>
+
+     <Condition Message='User Test Foo only runs as a non admin'>
+       NOT ALLUSERS
+     </Condition>  
+   </Product>
+</Wix>
+
diff --git a/testing/build.scons b/testing/build.scons
index 8206393..a56b204 100644
--- a/testing/build.scons
+++ b/testing/build.scons
@@ -1,515 +1,515 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-def _AddCommonOptions(local_env):

-  local_env['CPPDEFINES'] += [

-      '_ATL_APARTMENT_THREADED',

-      'UNITTEST',

-      ]

-

-  # A test is a console application, so we tell mk to link to

-  # main() as opposed to WinMain().

-  local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-  local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-

-#env.BuildSconscript('runtime')

-env.BuildSConscript('ui')

-

-#=============UnitTests========================================================

-

-

-v = env['product_version'][0]

-version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-#

-# Builds omaha_unittest

-#

-omaha_unittest_env = env.Clone()

-_AddCommonOptions(omaha_unittest_env)

-

-omaha_unittest_env.FilterOut(LINKFLAGS = ['/NODEFAULTLIB'])

-

-omaha_unittest_env.Append(

-    CPPPATH = [

-        '$OBJ_ROOT',                        # Needed for the generated files

-        '$MAIN_DIR/goopdate/resources',     # Needed for success.ico

-        '$MAIN_DIR/third_party/breakpad/src',

-        '$MAIN_DIR/third_party/c99/include',  # C99 inttypes.h for security

-        '$MAIN_DIR/third_party/gtest/include',

-        ],

-    CCFLAGS = [

-        '/wd4389',        # signed/unsigned mismatch

-        '/wd4510',        # default constructor could not be generated

-        '/wd4610',        # object 'class' can never be instantiated

-        ],

-    CPPDEFINES = [

-        'OMAHA_BUILD_VERSION=0x%.4x%.4x%.4x%.4x' % (v[0], v[1], v[2], v[3]),

-        'OMAHA_BUILD_VERSION_STRING=_T(\\"%s\\")' % version_string,

-        ],

-    LIBS = [

-        ('atls.lib', 'atlsd.lib')[omaha_unittest_env.Bit('debug')],

-

-        '$LIB_DIR/breakpad.lib',

-        '$LIB_DIR/common.lib',

-        '$LIB_DIR/core.lib',

-        '$LIB_DIR/goopdate_dll.lib',

-        '$LIB_DIR/google_update_ps.lib',

-        '$LIB_DIR/logging.lib',

-        '$LIB_DIR/net.lib',

-        '$LIB_DIR/google_update_recovery.lib',

-        '$LIB_DIR/repair_goopdate.lib',

-        '$LIB_DIR/security.lib',

-        '$LIB_DIR/service.lib',

-        '$LIB_DIR/setup.lib',

-        '$LIB_DIR/statsreport.lib',

-        '$LIB_DIR/gtest.lib',

-        '$LIB_DIR/worker.lib',

-        '$LIB_DIR/goopdump.lib',

-

-        'advapi32.lib',

-        'comctl32.lib',

-        'crypt32.lib',

-        'dbghelp.lib',

-        'delayimp.lib',       # For delay loading

-        'iphlpapi.lib',

-        'msi.lib',

-        'mstask.lib',

-        'netapi32.lib',

-        'ole32.lib',

-        'oleaut32.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'rpcns4.lib',

-        'rpcrt4.lib',

-        'shlwapi.lib',

-        'urlmon.lib',

-        'userenv.lib',

-        'version.lib',

-        'wbemuuid.lib',

-        'wininet.lib',

-        'ws2_32.lib',

-        'wtsapi32.lib',

-        'wintrust.lib',

-        ],

-    LINKFLAGS = [

-        '/DELAYLOAD:shlwapi.dll',

-        '/DELAYLOAD:shell32.dll',

-        '/DELAYLOAD:psapi.dll',

-        '/DELAYLOAD:netapi32.dll',

-        '/DELAYLOAD:Wtsapi32.dll',

-        ],

-    RCFLAGS = [

-        '/DVERSION_MAJOR=%d' % v[0],

-        '/DVERSION_MINOR=%d' % v[1],

-        '/DVERSION_BUILD=%d' % v[2],

-        '/DVERSION_PATCH=%d' % v[3],

-        '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,

-        '/DLANGUAGE_STRING=\\"en\\"'

-        ],

-)

-

-omaha_unittest_inputs = [

-    'omaha_unittest.cc',

-    '../common/app_util_unittest.cc',

-    '../common/apply_tag.cc',

-    '../common/atlassert_unittest.cc',

-    '../common/atl_regexp_unittest.cc',

-    '../common/browser_utils_unittest.cc',

-    '../common/cgi_unittest.cc',

-    '../common/commands_unittest.cc',

-    '../common/disk_unittest.cc',

-    '../common/dynamic_link_kernel32_unittest.cc',

-    '../common/encrypt_test.cc',

-    '../common/error_unittest.cc',

-    '../common/extractor_unittest.cc',

-    '../common/file_reader_unittest.cc',

-    '../common/file_store_unittest.cc',

-    '../common/file_unittest.cc',

-    '../common/firewall_product_detection_unittest.cc',

-    '../common/highres_timer_unittest.cc',

-    '../common/localization_unittest.cc',

-    '../common/lock_ptr_unittest.cc',

-    '../common/logging_unittest.cc',

-    '../common/md5_unittest.cc',

-    '../common/module_utils_unittest.cc',

-    '../common/omaha_version_unittest.cc',

-    '../common/path_unittest.cc',

-    '../common/pe_utils_unittest.cc',

-    '../common/proc_utils_unittest.cc',

-    '../common/process_unittest.cc',

-    '../common/queue_timer_unittest.cc',

-    '../common/reactor_unittest.cc',

-    '../common/reg_key_unittest.cc',

-    '../common/registry_monitor_manager_unittest.cc',

-    '../common/registry_store_unittest.cc',

-    '../common/scoped_impersonation_unittest.cc',

-    '../common/scoped_ptr_cotask_unittest.cc',

-    '../common/serializable_object_unittest.cc',

-    '../common/service_utils_unittest.cc',

-    '../common/sha_unittest.cc',

-    '../common/shell_unittest.cc',

-    '../common/signatures_unittest.cc',

-    '../common/signaturevalidator_unittest.cc',

-    '../common/sta_unittest.cc',

-    '../common/string_unittest.cc',

-    '../common/system_unittest.cc',

-    '../common/system_info_unittest.cc',

-    '../common/thread_pool_unittest.cc',

-    '../common/time_unittest.cc',

-    '../common/timer_unittest.cc',

-    '../common/tr_rand_unittest.cc',

-    '../common/user_info_unittest.cc',

-    '../common/user_rights_unittest.cc',

-    '../common/utils_unittest.cc',

-    '../common/vistautil_unittest.cc',

-    '../common/vista_utils_unittest.cc',

-    '../common/wmi_query_unittest.cc',

-    '../common/xml_utils_unittest.cc',

-

-    # Core unit tests

-    '../core/core_unittest.cc',

-    '../core/system_monitor_unittest.cc',

-    '../core/google_update_core_unittest.cc',

-

-    # Google Update unit tests.

-    '../google_update/google_update_unittest.cc',

-

-    # Goopdate unit tests.

-    '../goopdate/command_line_builder_unittest.cc',

-    '../goopdate/command_line_unittest.cc',

-    '../goopdate/command_line_parser_unittest.cc',

-    '../goopdate/command_line_validator_unittest.cc',

-    '../goopdate/config_manager_unittest.cc',

-    '../goopdate/crash_unittest.cc',

-    '../goopdate/extra_args_parser_unittest.cc',

-    '../goopdate/event_logger_unittest.cc',

-    '../goopdate/goopdate_unittest.cc',

-    '../goopdate/goopdate_utils_unittest.cc',

-    '../goopdate/goopdate_xml_parser_unittest.cc',

-    '../goopdate/main_unittest.cc',

-    '../goopdate/resource_manager_unittest.cc',

-    '../goopdate/stats_uploader_unittest.cc',

-    '../goopdate/webplugin_utils_unittest.cc',

-

-    # Net unit tests

-    '../net/bits_request_unittest.cc',

-    '../net/bits_utils_unittest.cc',

-    '../net/browser_request_unittest.cc',

-    '../net/cup_request_unittest.cc',

-    '../net/cup_utils_unittest.cc',

-    '../net/detector_unittest.cc',

-    '../net/http_client_unittest.cc',

-    '../net/net_utils_unittest.cc',

-    '../net/network_config_unittest.cc',

-    '../net/network_request_unittest.cc',

-    '../net/simple_request_unittest.cc',

-    '../net/winhttp_vtable_unittest.cc',

-

-    # Code Red-related unit tests.

-    '../common/google_update_recovery_unittest.cc',

-    '../recovery/repair_exe/mspexecutableelevator_unittest.cc',

-    '../recovery/repair_exe/repair_goopdate_unittest.cc',

-    '../recovery/repair_exe/custom_action/execute_repair_file_unittest.cc',

-    '../recovery/repair_exe/custom_action/execute_repair_file.cc',

-

-    # Setup unit tests.

-    '../setup/msi_test_utils.cc',

-    '../setup/setup_unittest.cc',

-    '../setup/setup_files_unittest.cc',

-    '../setup/setup_google_update_unittest.cc',

-    '../setup/setup_service_unittest.cc',

-

-    # Statsreport unit tests.

-    '../statsreport/aggregator_unittest.cc',

-    '../statsreport/aggregator-win32_unittest.cc',

-    '../statsreport/formatter_unittest.cc',

-    '../statsreport/metrics_unittest.cc',

-    '../statsreport/persistent_iterator-win32_unittest.cc',

-

-    # Resource files.

-    omaha_unittest_env.RES('../testing/omaha_unittest.rc'),

-

-    # Testing unit tests

-    '../testing/unit_test.cc',

-    '../testing/unittest_debug_helper_unittest.cc',

-

-    # Worker unit tests.

-    '../worker/application_data_unittest.cc',

-    '../worker/application_manager_unittest.cc',

-    '../worker/application_usage_data_unittest.cc',

-    '../worker/download_manager_unittest.cc',

-    '../worker/install_manager_unittest.cc',

-    '../worker/job_creator_unittest.cc',

-    '../worker/job_unittest.cc',

-    '../worker/ping_unittest.cc',

-    '../worker/ping_utils_unittest.cc',

-    '../worker/worker_job_unittest.cc',

-    '../worker/worker_unittest.cc',

-

-    # Goopdump unit tests

-    # TODO(Omaha): This unit test is failing for some reason. Fix and uncomment.

-    # '../tools/goopdump/process_monitor_unittest.cc',

-    '../tools/goopdump/process_commandline_unittest.cc',

-    ]

-

-# Force a rebuild when the version changes.

-# Also force a dependency on the RC files included in omaha_unittest.rc as these

-# do not appear to be picked up automatically.

-omaha_unittest_env.Depends('$OBJ_ROOT/testing/omaha_unittest.res', [

-    '$MAIN_DIR/VERSION',

-    '$MAIN_DIR/goopdate/goopdate.rc',

-    '$MAIN_DIR/goopdate/resources/goopdateres/generated_resources_en.rc',

-    ]

-)

-

-# Ensure that obj files don't collide with ones from non-test build

-omaha_unittest_env['OBJPREFIX'] = omaha_unittest_env['OBJPREFIX'] + 'testing/'

-

-target_name = 'omaha_unittest.exe'

-

-if env.Bit('use_precompiled_headers'):

-  omaha_unittest_inputs += omaha_unittest_env.EnablePrecompile(target_name)

-

-

-omaha_unittest_env.ComponentProgram(target_name, omaha_unittest_inputs)

-

-

-

-# This builds and signs an executable used by unit tests. Because the tests

-# require an official build signed by Google Inc we do not need to build it

-# at other times.

-if env.Bit('build_server'):

-  official_env = env.Clone()

-  official_env.Append(

-      CPPPATH = [

-          '$OBJ_ROOT',    # Needed for the generated files

-          ],

-      LIBS = [

-          ('atls.lib', 'atlsd.lib')[official_env.Bit('debug')],

-          ('libcmt.lib', 'libcmtd.lib')[official_env.Bit('debug')],

-          ('libcpmt.lib', 'libcpmtd.lib')[official_env.Bit('debug')],

-          '$LIB_DIR/common.lib',

-

-          # These are required by common_lib

-          'netapi32.lib',

-          'psapi.lib',

-          'rasapi32.lib',

-          'shlwapi.lib',

-          'userenv.lib',

-          'version.lib',

-          'wtsapi32.lib',

-          ],

-      RCFLAGS = [

-          '/DVERSION_MAJOR=%d' % v[0],

-          '/DVERSION_MINOR=%d' % v[1],

-          '/DVERSION_BUILD=%d' % v[2],

-          '/DVERSION_PATCH=%d' % v[3],

-          '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,

-          '/DLANGUAGE_STRING=\\"en\\"'

-          ],

-  )

-

-  official_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-  official_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-  target_name = 'SaveArguments_unsigned.exe'

-

-  unsigned_inputs = [

-      'save_arguments.cc',

-      official_env.RES('run_as_invoker.res',

-                       '$MAIN_DIR/common/run_as_invoker.rc'),

-      official_env.RES('recovery_markup.res',

-                       '$MAIN_DIR/recovery/recovery_markup.rc'),

-      '$OBJ_ROOT/goopdate/resources/generated_resources_en.res',

-      ]

-  if env.Bit('use_precompiled_headers'):

-    unsigned_inputs += official_env.EnablePrecompile(target_name)

-

-  # Build the *unsigned* executeable

-  unsigned_output = official_env.ComponentProgram(

-      prog_name=target_name,

-      source=unsigned_inputs,

-  )

-

-  signed_output = official_env.SignedBinary(

-      target='SaveArguments.exe',

-      source=unsigned_output,

-  )

-

-  official_env.Replicate('$STAGING_DIR', signed_output)

-

-

-# Copy a few test files needed by the unit test.

-# The files are installed side by side with the unit test executable

-# in the build directory.

-env.Replicate('$STAGING_DIR', [

-    # signatures_unittest files.

-    # (download_manager_unittest also uses declaration.txt.)

-    '$MAIN_DIR/data/declaration.txt',

-    '$MAIN_DIR/data/certificate-with-private-key.pfx',

-    '$MAIN_DIR/data/certificate-without-private-key.cer',

-

-    # xml_utils_unittest files.

-    '$MAIN_DIR/data/manifest.xml',

-

-    # goopdate_xml_parser_unittest files.

-    '$MAIN_DIR/data/seed_manifest_v1.xml',

-    '$MAIN_DIR/data/seed_manifest.xml',

-    '$MAIN_DIR/data/seed_manifest_v9.xml',

-    '$MAIN_DIR/data/server_manifest.xml',

-    '$MAIN_DIR/data/server_manifest_components.xml',

-

-    # goopdate_unittest files.

-    '$MAIN_DIR/data/seed_manifest_with_args.xml',

-    '$MAIN_DIR/data/server_manifest_one_app.xml',

-    '$MAIN_DIR/data/seed_manifest_with_argsV3.xml',

-    '$MAIN_DIR/data/server_manifest_one_app.xml'

-    ])

-

-# Install files from the testing/unittest_support/ directory.

-env.Replicate('$STAGING_DIR/unittest_support/', [

-    # Installer files used by the Install Manager unit tests.

-    'unittest_support/test_foo_v1.0.101.0.msi',

-

-    # Files used by the Recovery unit tests.

-    'unittest_support/GoogleUpdate_corrupted.exe',

-    'unittest_support/GoogleUpdate_now_expired_cert.exe',

-    'unittest_support/GoogleUpdate_old_signature.exe',

-    'unittest_support/GoogleUpdateHelper.msi',

-    'unittest_support/SaveArguments.exe',

-    'unittest_support/SaveArguments_OmahaTestSigned.exe',

-    'unittest_support/SaveArguments_unsigned_wrong_markup_size.exe',

-    'unittest_support/SaveArguments_unsigned_wrong_markup_value.exe',

-    'unittest_support/SaveArguments_unsigned_wrong_resource_name.exe',

-

-    # Minidump file for the crash unit test.

-    'unittest_support/minidump.dmp',

-    'unittest_support/minidump.txt',

-    ])

-

-# Saved versions of Google Update for the Setup tests.

-env.Replicate('$STAGING_DIR/unittest_support/omaha_1.0.x/', [

-    'unittest_support/omaha_1.0.x/GoogleUpdate.exe',

-    'unittest_support/omaha_1.0.x/goopdate.dll',

-    ])

-env.Replicate('$STAGING_DIR/unittest_support/omaha_1.1.x/', [

-    'unittest_support/omaha_1.1.x/GoogleUpdate.exe',

-    'unittest_support/omaha_1.1.x/goopdate.dll',

-    'unittest_support/omaha_1.1.x/goopdateres_en.dll',

-    ])

-env.Replicate('$STAGING_DIR/unittest_support/omaha_1.2.x/', [

-    'unittest_support/omaha_1.2.x/GoogleUpdate.exe',

-    'unittest_support/omaha_1.2.x/goopdate.dll',

-    'unittest_support/omaha_1.2.x/goopdateres_en.dll',

-    ])

-

-# Newer versions of Google Update for the Setup tests.

-env.Replicate('$STAGING_DIR/unittest_support/omaha_1.2.x_newer/',

-              'unittest_support/omaha_1.2.x_newer/GoogleUpdate.exe')

-

-# Copy longrunning.exe to GoogleUpdate.exe for use in Setup and WorkerJob tests.

-env.Replicate(

-    target='$STAGING_DIR/unittest_support/does_not_shutdown/',

-    source='$MAIN_DIR/testing/unittest_support/LongRunningSilent.exe',

-    REPLICATE_REPLACE=[('LongRunningSilent\\.exe', 'GoogleUpdate.exe')],

-)

-

-# Copy over the files for resource manager test.

-env.Replicate('$STAGING_DIR/unittest_support/omaha_1.2.x_resources/',

-              'unittest_support/omaha_1.2.x_resources/goopdateres_ar.dll')

-env.Replicate('$STAGING_DIR/unittest_support/omaha_1.2.x_resources/',

-              'unittest_support/omaha_1.2.x_resources/goopdateres_bg.dll')

-env.Replicate('$STAGING_DIR/unittest_support/omaha_1.2.x_resources/',

-              'unittest_support/omaha_1.2.x_resources/goopdateres_ca.dll')

-

-

-# download_cache test files

-loc_guid = 'download_cache_test/{7101D597-3481-4971-AD23-455542964072}'

-env.Replicate('$STAGING_DIR/unittest_support/' + loc_guid,

-              'unittest_support/%s/livelysetup.exe' % loc_guid)

-

-loc_guid = 'download_cache_test/{89640431-FE64-4da8-9860-1A1085A60E13}'

-env.Replicate('$STAGING_DIR/unittest_support/' + loc_guid,

-              'unittest_support/%s/gears-win32-opt.msi' % loc_guid)

-

-loc_guid = 'download_cache_test/{C5CC8735-9BE0-45c5-804C-F117E96047C7}'

-env.Replicate('$STAGING_DIR/unittest_support/' + loc_guid,

-              'unittest_support/%s/GoogleUpdateSetup.exe' % loc_guid)

-

-#

-# On Demand system level test.

-#

-ondemandsystem_unittest_env = env.Clone()

-_AddCommonOptions(ondemandsystem_unittest_env)

-

-ondemandsystem_unittest_env.FilterOut(LINKFLAGS = ['/NODEFAULTLIB'])

-ondemandsystem_unittest_env.Append(

-    CPPPATH = [

-        '$MAIN_DIR/third_party/gtest/include',

-        '$OBJ_ROOT',                # Needed for generated files

-        ],

-    CPPDEFINES = [

-        'UNICODE',

-        '_UNICODE'

-        ],

-    LIBS = [

-        ('atls.lib', 'atlsd.lib')[env.Bit('debug')],

-        'comctl32.lib',

-        'crypt32.lib',

-        'Iphlpapi.lib',

-        'mstask.lib',

-        'netapi32.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'shlwapi.lib',

-        'urlmon.lib',

-        'userenv.lib',

-        'version.lib',

-        'wininet.lib',

-        'wtsapi32.lib',

-        '$LIB_DIR/common.lib',

-        '$LIB_DIR/goopdate_dll.lib',

-        '$LIB_DIR/logging.lib',

-        '$LIB_DIR/net.lib',

-        '$LIB_DIR/gtest.lib',

-        '$LIB_DIR/statsreport.lib',

-        ],

-)

-

-# Exe is console application

-ondemandsystem_unittest_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-ondemandsystem_unittest_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-target_name = 'ondemandsystem_unittest.exe'

-

-ondemandsystem_unittest_inputs = [

-    'ondemandsystem_unittest.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  ondemandsystem_unittest_inputs += (

-      ondemandsystem_unittest_env.EnablePrecompile(target_name))

-

-

-ondemandsystem_unittest_env.ComponentProgram(

-    prog_name=target_name,

-    source=ondemandsystem_unittest_inputs,

-)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+def _AddCommonOptions(local_env):
+  local_env['CPPDEFINES'] += [
+      '_ATL_APARTMENT_THREADED',
+      'UNITTEST',
+      ]
+
+  # A test is a console application, so we tell mk to link to
+  # main() as opposed to WinMain().
+  local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+  local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+
+#env.BuildSconscript('runtime')
+env.BuildSConscript('ui')
+
+#=============UnitTests========================================================
+
+
+v = env['product_version'][0]
+version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+#
+# Builds omaha_unittest
+#
+omaha_unittest_env = env.Clone()
+_AddCommonOptions(omaha_unittest_env)
+
+omaha_unittest_env.FilterOut(LINKFLAGS = ['/NODEFAULTLIB'])
+
+omaha_unittest_env.Append(
+    CPPPATH = [
+        '$OBJ_ROOT',                        # Needed for the generated files
+        '$MAIN_DIR/goopdate/resources',     # Needed for success.ico
+        '$MAIN_DIR/third_party/breakpad/src',
+        '$MAIN_DIR/third_party/c99/include',  # C99 inttypes.h for security
+        '$MAIN_DIR/third_party/gtest/include',
+        ],
+    CCFLAGS = [
+        '/wd4389',        # signed/unsigned mismatch
+        '/wd4510',        # default constructor could not be generated
+        '/wd4610',        # object 'class' can never be instantiated
+        ],
+    CPPDEFINES = [
+        'OMAHA_BUILD_VERSION=0x%.4x%.4x%.4x%.4x' % (v[0], v[1], v[2], v[3]),
+        'OMAHA_BUILD_VERSION_STRING=_T(\\"%s\\")' % version_string,
+        ],
+    LIBS = [
+        ('atls.lib', 'atlsd.lib')[omaha_unittest_env.Bit('debug')],
+
+        '$LIB_DIR/breakpad.lib',
+        '$LIB_DIR/common.lib',
+        '$LIB_DIR/core.lib',
+        '$LIB_DIR/goopdate_dll.lib',
+        '$LIB_DIR/google_update_ps.lib',
+        '$LIB_DIR/logging.lib',
+        '$LIB_DIR/net.lib',
+        '$LIB_DIR/google_update_recovery.lib',
+        '$LIB_DIR/repair_goopdate.lib',
+        '$LIB_DIR/security.lib',
+        '$LIB_DIR/service.lib',
+        '$LIB_DIR/setup.lib',
+        '$LIB_DIR/statsreport.lib',
+        '$LIB_DIR/gtest.lib',
+        '$LIB_DIR/worker.lib',
+        '$LIB_DIR/goopdump.lib',
+
+        'advapi32.lib',
+        'comctl32.lib',
+        'crypt32.lib',
+        'dbghelp.lib',
+        'delayimp.lib',       # For delay loading
+        'iphlpapi.lib',
+        'msi.lib',
+        'mstask.lib',
+        'netapi32.lib',
+        'ole32.lib',
+        'oleaut32.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'rpcns4.lib',
+        'rpcrt4.lib',
+        'shlwapi.lib',
+        'urlmon.lib',
+        'userenv.lib',
+        'version.lib',
+        'wbemuuid.lib',
+        'wininet.lib',
+        'ws2_32.lib',
+        'wtsapi32.lib',
+        'wintrust.lib',
+        ],
+    LINKFLAGS = [
+        '/DELAYLOAD:shlwapi.dll',
+        '/DELAYLOAD:shell32.dll',
+        '/DELAYLOAD:psapi.dll',
+        '/DELAYLOAD:netapi32.dll',
+        '/DELAYLOAD:Wtsapi32.dll',
+        ],
+    RCFLAGS = [
+        '/DVERSION_MAJOR=%d' % v[0],
+        '/DVERSION_MINOR=%d' % v[1],
+        '/DVERSION_BUILD=%d' % v[2],
+        '/DVERSION_PATCH=%d' % v[3],
+        '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,
+        '/DLANGUAGE_STRING=\\"en\\"'
+        ],
+)
+
+omaha_unittest_inputs = [
+    'omaha_unittest.cc',
+    '../common/app_util_unittest.cc',
+    '../common/apply_tag.cc',
+    '../common/atlassert_unittest.cc',
+    '../common/atl_regexp_unittest.cc',
+    '../common/browser_utils_unittest.cc',
+    '../common/cgi_unittest.cc',
+    '../common/commands_unittest.cc',
+    '../common/disk_unittest.cc',
+    '../common/dynamic_link_kernel32_unittest.cc',
+    '../common/encrypt_test.cc',
+    '../common/error_unittest.cc',
+    '../common/extractor_unittest.cc',
+    '../common/file_reader_unittest.cc',
+    '../common/file_store_unittest.cc',
+    '../common/file_unittest.cc',
+    '../common/firewall_product_detection_unittest.cc',
+    '../common/highres_timer_unittest.cc',
+    '../common/localization_unittest.cc',
+    '../common/lock_ptr_unittest.cc',
+    '../common/logging_unittest.cc',
+    '../common/md5_unittest.cc',
+    '../common/module_utils_unittest.cc',
+    '../common/omaha_version_unittest.cc',
+    '../common/path_unittest.cc',
+    '../common/pe_utils_unittest.cc',
+    '../common/proc_utils_unittest.cc',
+    '../common/process_unittest.cc',
+    '../common/queue_timer_unittest.cc',
+    '../common/reactor_unittest.cc',
+    '../common/reg_key_unittest.cc',
+    '../common/registry_monitor_manager_unittest.cc',
+    '../common/registry_store_unittest.cc',
+    '../common/scoped_impersonation_unittest.cc',
+    '../common/scoped_ptr_cotask_unittest.cc',
+    '../common/serializable_object_unittest.cc',
+    '../common/service_utils_unittest.cc',
+    '../common/sha_unittest.cc',
+    '../common/shell_unittest.cc',
+    '../common/signatures_unittest.cc',
+    '../common/signaturevalidator_unittest.cc',
+    '../common/sta_unittest.cc',
+    '../common/string_unittest.cc',
+    '../common/system_unittest.cc',
+    '../common/system_info_unittest.cc',
+    '../common/thread_pool_unittest.cc',
+    '../common/time_unittest.cc',
+    '../common/timer_unittest.cc',
+    '../common/tr_rand_unittest.cc',
+    '../common/user_info_unittest.cc',
+    '../common/user_rights_unittest.cc',
+    '../common/utils_unittest.cc',
+    '../common/vistautil_unittest.cc',
+    '../common/vista_utils_unittest.cc',
+    '../common/wmi_query_unittest.cc',
+    '../common/xml_utils_unittest.cc',
+
+    # Core unit tests
+    '../core/core_unittest.cc',
+    '../core/system_monitor_unittest.cc',
+    '../core/google_update_core_unittest.cc',
+
+    # Google Update unit tests.
+    '../google_update/google_update_unittest.cc',
+
+    # Goopdate unit tests.
+    '../goopdate/command_line_builder_unittest.cc',
+    '../goopdate/command_line_unittest.cc',
+    '../goopdate/command_line_parser_unittest.cc',
+    '../goopdate/command_line_validator_unittest.cc',
+    '../goopdate/config_manager_unittest.cc',
+    '../goopdate/crash_unittest.cc',
+    '../goopdate/extra_args_parser_unittest.cc',
+    '../goopdate/event_logger_unittest.cc',
+    '../goopdate/goopdate_unittest.cc',
+    '../goopdate/goopdate_utils_unittest.cc',
+    '../goopdate/goopdate_xml_parser_unittest.cc',
+    '../goopdate/main_unittest.cc',
+    '../goopdate/resource_manager_unittest.cc',
+    '../goopdate/stats_uploader_unittest.cc',
+    '../goopdate/webplugin_utils_unittest.cc',
+
+    # Net unit tests
+    '../net/bits_request_unittest.cc',
+    '../net/bits_utils_unittest.cc',
+    '../net/browser_request_unittest.cc',
+    '../net/cup_request_unittest.cc',
+    '../net/cup_utils_unittest.cc',
+    '../net/detector_unittest.cc',
+    '../net/http_client_unittest.cc',
+    '../net/net_utils_unittest.cc',
+    '../net/network_config_unittest.cc',
+    '../net/network_request_unittest.cc',
+    '../net/simple_request_unittest.cc',
+    '../net/winhttp_vtable_unittest.cc',
+
+    # Code Red-related unit tests.
+    '../common/google_update_recovery_unittest.cc',
+    '../recovery/repair_exe/mspexecutableelevator_unittest.cc',
+    '../recovery/repair_exe/repair_goopdate_unittest.cc',
+    '../recovery/repair_exe/custom_action/execute_repair_file_unittest.cc',
+    '../recovery/repair_exe/custom_action/execute_repair_file.cc',
+
+    # Setup unit tests.
+    '../setup/msi_test_utils.cc',
+    '../setup/setup_unittest.cc',
+    '../setup/setup_files_unittest.cc',
+    '../setup/setup_google_update_unittest.cc',
+    '../setup/setup_service_unittest.cc',
+
+    # Statsreport unit tests.
+    '../statsreport/aggregator_unittest.cc',
+    '../statsreport/aggregator-win32_unittest.cc',
+    '../statsreport/formatter_unittest.cc',
+    '../statsreport/metrics_unittest.cc',
+    '../statsreport/persistent_iterator-win32_unittest.cc',
+
+    # Resource files.
+    omaha_unittest_env.RES('../testing/omaha_unittest.rc'),
+
+    # Testing unit tests
+    '../testing/unit_test.cc',
+    '../testing/unittest_debug_helper_unittest.cc',
+
+    # Worker unit tests.
+    '../worker/application_data_unittest.cc',
+    '../worker/application_manager_unittest.cc',
+    '../worker/application_usage_data_unittest.cc',
+    '../worker/download_manager_unittest.cc',
+    '../worker/install_manager_unittest.cc',
+    '../worker/job_creator_unittest.cc',
+    '../worker/job_unittest.cc',
+    '../worker/ping_unittest.cc',
+    '../worker/ping_utils_unittest.cc',
+    '../worker/worker_job_unittest.cc',
+    '../worker/worker_unittest.cc',
+
+    # Goopdump unit tests
+    # TODO(Omaha): This unit test is failing for some reason. Fix and uncomment.
+    # '../tools/goopdump/process_monitor_unittest.cc',
+    '../tools/goopdump/process_commandline_unittest.cc',
+    ]
+
+# Force a rebuild when the version changes.
+# Also force a dependency on the RC files included in omaha_unittest.rc as these
+# do not appear to be picked up automatically.
+omaha_unittest_env.Depends('$OBJ_ROOT/testing/omaha_unittest.res', [
+    '$MAIN_DIR/VERSION',
+    '$MAIN_DIR/goopdate/goopdate.rc',
+    '$MAIN_DIR/goopdate/resources/goopdateres/generated_resources_en.rc',
+    ]
+)
+
+# Ensure that obj files don't collide with ones from non-test build
+omaha_unittest_env['OBJPREFIX'] = omaha_unittest_env['OBJPREFIX'] + 'testing/'
+
+target_name = 'omaha_unittest.exe'
+
+if env.Bit('use_precompiled_headers'):
+  omaha_unittest_inputs += omaha_unittest_env.EnablePrecompile(target_name)
+
+
+omaha_unittest_env.ComponentProgram(target_name, omaha_unittest_inputs)
+
+
+
+# This builds and signs an executable used by unit tests. Because the tests
+# require an official build signed by Google Inc we do not need to build it
+# at other times.
+if env.Bit('build_server'):
+  official_env = env.Clone()
+  official_env.Append(
+      CPPPATH = [
+          '$OBJ_ROOT',    # Needed for the generated files
+          ],
+      LIBS = [
+          ('atls.lib', 'atlsd.lib')[official_env.Bit('debug')],
+          ('libcmt.lib', 'libcmtd.lib')[official_env.Bit('debug')],
+          ('libcpmt.lib', 'libcpmtd.lib')[official_env.Bit('debug')],
+          '$LIB_DIR/common.lib',
+
+          # These are required by common_lib
+          'netapi32.lib',
+          'psapi.lib',
+          'rasapi32.lib',
+          'shlwapi.lib',
+          'userenv.lib',
+          'version.lib',
+          'wtsapi32.lib',
+          ],
+      RCFLAGS = [
+          '/DVERSION_MAJOR=%d' % v[0],
+          '/DVERSION_MINOR=%d' % v[1],
+          '/DVERSION_BUILD=%d' % v[2],
+          '/DVERSION_PATCH=%d' % v[3],
+          '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,
+          '/DLANGUAGE_STRING=\\"en\\"'
+          ],
+  )
+
+  official_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+  official_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+  target_name = 'SaveArguments_unsigned.exe'
+
+  unsigned_inputs = [
+      'save_arguments.cc',
+      official_env.RES('run_as_invoker.res',
+                       '$MAIN_DIR/common/run_as_invoker.rc'),
+      official_env.RES('recovery_markup.res',
+                       '$MAIN_DIR/recovery/recovery_markup.rc'),
+      '$OBJ_ROOT/goopdate/resources/generated_resources_en.res',
+      ]
+  if env.Bit('use_precompiled_headers'):
+    unsigned_inputs += official_env.EnablePrecompile(target_name)
+
+  # Build the *unsigned* executeable
+  unsigned_output = official_env.ComponentProgram(
+      prog_name=target_name,
+      source=unsigned_inputs,
+  )
+
+  signed_output = official_env.SignedBinary(
+      target='SaveArguments.exe',
+      source=unsigned_output,
+  )
+
+  official_env.Replicate('$STAGING_DIR', signed_output)
+
+
+# Copy a few test files needed by the unit test.
+# The files are installed side by side with the unit test executable
+# in the build directory.
+env.Replicate('$STAGING_DIR', [
+    # signatures_unittest files.
+    # (download_manager_unittest also uses declaration.txt.)
+    '$MAIN_DIR/data/declaration.txt',
+    '$MAIN_DIR/data/certificate-with-private-key.pfx',
+    '$MAIN_DIR/data/certificate-without-private-key.cer',
+
+    # xml_utils_unittest files.
+    '$MAIN_DIR/data/manifest.xml',
+
+    # goopdate_xml_parser_unittest files.
+    '$MAIN_DIR/data/seed_manifest_v1.xml',
+    '$MAIN_DIR/data/seed_manifest.xml',
+    '$MAIN_DIR/data/seed_manifest_v9.xml',
+    '$MAIN_DIR/data/server_manifest.xml',
+    '$MAIN_DIR/data/server_manifest_components.xml',
+
+    # goopdate_unittest files.
+    '$MAIN_DIR/data/seed_manifest_with_args.xml',
+    '$MAIN_DIR/data/server_manifest_one_app.xml',
+    '$MAIN_DIR/data/seed_manifest_with_argsV3.xml',
+    '$MAIN_DIR/data/server_manifest_one_app.xml'
+    ])
+
+# Install files from the testing/unittest_support/ directory.
+env.Replicate('$STAGING_DIR/unittest_support/', [
+    # Installer files used by the Install Manager unit tests.
+    'unittest_support/test_foo_v1.0.101.0.msi',
+
+    # Files used by the Recovery unit tests.
+    'unittest_support/GoogleUpdate_corrupted.exe',
+    'unittest_support/GoogleUpdate_now_expired_cert.exe',
+    'unittest_support/GoogleUpdate_old_signature.exe',
+    'unittest_support/GoogleUpdateHelper.msi',
+    'unittest_support/SaveArguments.exe',
+    'unittest_support/SaveArguments_OmahaTestSigned.exe',
+    'unittest_support/SaveArguments_unsigned_wrong_markup_size.exe',
+    'unittest_support/SaveArguments_unsigned_wrong_markup_value.exe',
+    'unittest_support/SaveArguments_unsigned_wrong_resource_name.exe',
+
+    # Minidump file for the crash unit test.
+    'unittest_support/minidump.dmp',
+    'unittest_support/minidump.txt',
+    ])
+
+# Saved versions of Google Update for the Setup tests.
+env.Replicate('$STAGING_DIR/unittest_support/omaha_1.0.x/', [
+    'unittest_support/omaha_1.0.x/GoogleUpdate.exe',
+    'unittest_support/omaha_1.0.x/goopdate.dll',
+    ])
+env.Replicate('$STAGING_DIR/unittest_support/omaha_1.1.x/', [
+    'unittest_support/omaha_1.1.x/GoogleUpdate.exe',
+    'unittest_support/omaha_1.1.x/goopdate.dll',
+    'unittest_support/omaha_1.1.x/goopdateres_en.dll',
+    ])
+env.Replicate('$STAGING_DIR/unittest_support/omaha_1.2.x/', [
+    'unittest_support/omaha_1.2.x/GoogleUpdate.exe',
+    'unittest_support/omaha_1.2.x/goopdate.dll',
+    'unittest_support/omaha_1.2.x/goopdateres_en.dll',
+    ])
+
+# Newer versions of Google Update for the Setup tests.
+env.Replicate('$STAGING_DIR/unittest_support/omaha_1.2.x_newer/',
+              'unittest_support/omaha_1.2.x_newer/GoogleUpdate.exe')
+
+# Copy longrunning.exe to GoogleUpdate.exe for use in Setup and WorkerJob tests.
+env.Replicate(
+    target='$STAGING_DIR/unittest_support/does_not_shutdown/',
+    source='$MAIN_DIR/testing/unittest_support/LongRunningSilent.exe',
+    REPLICATE_REPLACE=[('LongRunningSilent\\.exe', 'GoogleUpdate.exe')],
+)
+
+# Copy over the files for resource manager test.
+env.Replicate('$STAGING_DIR/unittest_support/omaha_1.2.x_resources/',
+              'unittest_support/omaha_1.2.x_resources/goopdateres_ar.dll')
+env.Replicate('$STAGING_DIR/unittest_support/omaha_1.2.x_resources/',
+              'unittest_support/omaha_1.2.x_resources/goopdateres_bg.dll')
+env.Replicate('$STAGING_DIR/unittest_support/omaha_1.2.x_resources/',
+              'unittest_support/omaha_1.2.x_resources/goopdateres_ca.dll')
+
+
+# download_cache test files
+loc_guid = 'download_cache_test/{7101D597-3481-4971-AD23-455542964072}'
+env.Replicate('$STAGING_DIR/unittest_support/' + loc_guid,
+              'unittest_support/%s/livelysetup.exe' % loc_guid)
+
+loc_guid = 'download_cache_test/{89640431-FE64-4da8-9860-1A1085A60E13}'
+env.Replicate('$STAGING_DIR/unittest_support/' + loc_guid,
+              'unittest_support/%s/gears-win32-opt.msi' % loc_guid)
+
+loc_guid = 'download_cache_test/{C5CC8735-9BE0-45c5-804C-F117E96047C7}'
+env.Replicate('$STAGING_DIR/unittest_support/' + loc_guid,
+              'unittest_support/%s/GoogleUpdateSetup.exe' % loc_guid)
+
+#
+# On Demand system level test.
+#
+ondemandsystem_unittest_env = env.Clone()
+_AddCommonOptions(ondemandsystem_unittest_env)
+
+ondemandsystem_unittest_env.FilterOut(LINKFLAGS = ['/NODEFAULTLIB'])
+ondemandsystem_unittest_env.Append(
+    CPPPATH = [
+        '$MAIN_DIR/third_party/gtest/include',
+        '$OBJ_ROOT',                # Needed for generated files
+        ],
+    CPPDEFINES = [
+        'UNICODE',
+        '_UNICODE'
+        ],
+    LIBS = [
+        ('atls.lib', 'atlsd.lib')[env.Bit('debug')],
+        'comctl32.lib',
+        'crypt32.lib',
+        'Iphlpapi.lib',
+        'mstask.lib',
+        'netapi32.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'shlwapi.lib',
+        'urlmon.lib',
+        'userenv.lib',
+        'version.lib',
+        'wininet.lib',
+        'wtsapi32.lib',
+        '$LIB_DIR/common.lib',
+        '$LIB_DIR/goopdate_dll.lib',
+        '$LIB_DIR/logging.lib',
+        '$LIB_DIR/net.lib',
+        '$LIB_DIR/gtest.lib',
+        '$LIB_DIR/statsreport.lib',
+        ],
+)
+
+# Exe is console application
+ondemandsystem_unittest_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+ondemandsystem_unittest_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+target_name = 'ondemandsystem_unittest.exe'
+
+ondemandsystem_unittest_inputs = [
+    'ondemandsystem_unittest.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  ondemandsystem_unittest_inputs += (
+      ondemandsystem_unittest_env.EnablePrecompile(target_name))
+
+
+ondemandsystem_unittest_env.ComponentProgram(
+    prog_name=target_name,
+    source=ondemandsystem_unittest_inputs,
+)
diff --git a/testing/omaha_unittest.cc b/testing/omaha_unittest.cc
index b920b83..34ca24c 100644
--- a/testing/omaha_unittest.cc
+++ b/testing/omaha_unittest.cc
@@ -1,133 +1,133 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The entry point for the omaha unit tests.

-

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/net/network_config.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-#define kUnitTestFilter _T("--gtest_filter")

-#define kUnitTestBreakOnFailure _T("--gtest_break_on_failure")

-

-int g_assert_count = 0;

-

-void ListTests() {

-  TCHAR* list_tests[3] = {

-    _T(""),

-    _T("--gtest_list_tests"),

-    NULL,

-  };

-  int list_test_argc = arraysize(list_tests) - 1;

-

-  testing::InitGoogleTest(&list_test_argc, list_tests);

-  RUN_ALL_TESTS();

-}

-

-// Parse args. Print help message if invalid arguments.

-bool ParseUnitTestArgs(int argc, TCHAR** argv) {

-  testing::InitGoogleTest(&argc, argv);

-

-  if (argc <= 1) {

-    return true;

-  }

-

-  // Parse the arguments

-  if (argc > 1) {

-    _tprintf(_T("\nTest Cases:\n"));

-    ListTests();

-

-    _tprintf(_T("First invalid command option: %s\n\n"), argv[1]);

-    _tprintf(_T("Valid options:\n"));

-    _tprintf(_T("%25s Cause an av when a test fails (for use with debugger)\n"),

-             kUnitTestBreakOnFailure);

-    _tprintf(_T("%25s Sets a filter on the unit tests.\n")

-             _T("%25s Format: %s=Filter[:Filter] where\n")

-             _T("%25s Filter is TestCase[.Test] and * is a wildcard.\n"),

-             kUnitTestFilter, _T(""), kUnitTestFilter, _T(""));

-    return false;

-  }

-

-  return true;

-}

-

-int RunTests(int argc, TCHAR** argv) {

-  InitializeVersionFromModule(NULL);

-  if (!ParseUnitTestArgs(argc, argv)) {

-    return -1;

-  }

-  FailOnAssert fail_on_assert;

-

-  scoped_co_init co_init(COINIT_MULTITHREADED);

-  VERIFY1(SUCCEEDED(co_init.hresult()));

-

-  const bool is_build_system = IsBuildSystem();

-  if (is_build_system) {

-    // Some tests only run as admin. We want to know if the build system is no

-    // longer running unit tests as admin.

-    ASSERT1(vista_util::IsUserAdmin());

-

-    SetBuildSystemTestSource();

-  }

-  TerminateAllGoogleUpdateProcesses();

-

-  // Ensure that any system running unittests has testsource set.

-  // Some unit tests generate pings, and these must be filtered.

-  CString value;

-  HRESULT hr =

-      RegKey::GetValue(MACHINE_REG_UPDATE_DEV, kRegValueTestSource, &value);

-  if (FAILED(hr) || value.IsEmpty()) {

-    ADD_FAILURE() << _T("'") << kRegValueTestSource << _T("'")

-                  << _T(" is not present in ")

-                  << _T("'") << MACHINE_REG_UPDATE_DEV << _T("'")

-                  << _T(" or it is empty. Since you are running Omaha unit ")

-                  << _T("tests, it should probably be set to 'dev' or 'qa'.");

-    return -1;

-  }

-

-  // Many unit tests require the network configuration be initialized.

-  // On Windows Vista only admins can write to HKLM therefore the

-  // initialization of the NetworkConfig must correspond to the integrity

-  // level the user is running as.

-  bool is_machine = vista_util::IsUserAdmin();

-  VERIFY1(SUCCEEDED(goopdate_utils::ConfigureNetwork(is_machine, false)));

-

-  int result = RUN_ALL_TESTS();

-

-  NetworkConfig::DeleteInstance();

-

-  if (is_build_system) {

-    TerminateAllGoogleUpdateProcesses();

-  }

-

-  return result;

-}

-

-}  // namespace omaha

-

-int _tmain(int argc, TCHAR** argv) {

-  return omaha::RunTests(argc, argv);

-}

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The entry point for the omaha unit tests.
+
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/net/network_config.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+#define kUnitTestFilter _T("--gtest_filter")
+#define kUnitTestBreakOnFailure _T("--gtest_break_on_failure")
+
+int g_assert_count = 0;
+
+void ListTests() {
+  TCHAR* list_tests[3] = {
+    _T(""),
+    _T("--gtest_list_tests"),
+    NULL,
+  };
+  int list_test_argc = arraysize(list_tests) - 1;
+
+  testing::InitGoogleTest(&list_test_argc, list_tests);
+  RUN_ALL_TESTS();
+}
+
+// Parse args. Print help message if invalid arguments.
+bool ParseUnitTestArgs(int argc, TCHAR** argv) {
+  testing::InitGoogleTest(&argc, argv);
+
+  if (argc <= 1) {
+    return true;
+  }
+
+  // Parse the arguments
+  if (argc > 1) {
+    _tprintf(_T("\nTest Cases:\n"));
+    ListTests();
+
+    _tprintf(_T("First invalid command option: %s\n\n"), argv[1]);
+    _tprintf(_T("Valid options:\n"));
+    _tprintf(_T("%25s Cause an av when a test fails (for use with debugger)\n"),
+             kUnitTestBreakOnFailure);
+    _tprintf(_T("%25s Sets a filter on the unit tests.\n")
+             _T("%25s Format: %s=Filter[:Filter] where\n")
+             _T("%25s Filter is TestCase[.Test] and * is a wildcard.\n"),
+             kUnitTestFilter, _T(""), kUnitTestFilter, _T(""));
+    return false;
+  }
+
+  return true;
+}
+
+int RunTests(int argc, TCHAR** argv) {
+  InitializeVersionFromModule(NULL);
+  if (!ParseUnitTestArgs(argc, argv)) {
+    return -1;
+  }
+  FailOnAssert fail_on_assert;
+
+  scoped_co_init co_init(COINIT_MULTITHREADED);
+  VERIFY1(SUCCEEDED(co_init.hresult()));
+
+  const bool is_build_system = IsBuildSystem();
+  if (is_build_system) {
+    // Some tests only run as admin. We want to know if the build system is no
+    // longer running unit tests as admin.
+    ASSERT1(vista_util::IsUserAdmin());
+
+    SetBuildSystemTestSource();
+  }
+  TerminateAllGoogleUpdateProcesses();
+
+  // Ensure that any system running unittests has testsource set.
+  // Some unit tests generate pings, and these must be filtered.
+  CString value;
+  HRESULT hr =
+      RegKey::GetValue(MACHINE_REG_UPDATE_DEV, kRegValueTestSource, &value);
+  if (FAILED(hr) || value.IsEmpty()) {
+    ADD_FAILURE() << _T("'") << kRegValueTestSource << _T("'")
+                  << _T(" is not present in ")
+                  << _T("'") << MACHINE_REG_UPDATE_DEV << _T("'")
+                  << _T(" or it is empty. Since you are running Omaha unit ")
+                  << _T("tests, it should probably be set to 'dev' or 'qa'.");
+    return -1;
+  }
+
+  // Many unit tests require the network configuration be initialized.
+  // On Windows Vista only admins can write to HKLM therefore the
+  // initialization of the NetworkConfig must correspond to the integrity
+  // level the user is running as.
+  bool is_machine = vista_util::IsUserAdmin();
+  VERIFY1(SUCCEEDED(goopdate_utils::ConfigureNetwork(is_machine, false)));
+
+  int result = RUN_ALL_TESTS();
+
+  NetworkConfig::DeleteInstance();
+
+  if (is_build_system) {
+    TerminateAllGoogleUpdateProcesses();
+  }
+
+  return result;
+}
+
+}  // namespace omaha
+
+int _tmain(int argc, TCHAR** argv) {
+  return omaha::RunTests(argc, argv);
+}
+
diff --git a/testing/ondemandsystem_unittest.cc b/testing/ondemandsystem_unittest.cc
index fe14c10..604f9f5 100644
--- a/testing/ondemandsystem_unittest.cc
+++ b/testing/ondemandsystem_unittest.cc
@@ -1,294 +1,294 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// System level tests for On Demand.  Unlike omaha_unittest.cpp, this test

-// should be run one test at a time view --gtest_filter.  The tests all assume

-// that there is an update available for the app (specified via guid as the

-// first argument).

-

-#include "base/basictypes.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/third_party/gtest/include/gtest/gtest.h"

-#include "omaha/tools/performondemand/performondemand.h"

-#include "omaha/common/utils.h"

-#include <windows.h>

-#include <atltime.h>

-

-namespace omaha {

-

-// Lazily define the guid and is_machine (passed in at the command line) global.

-CString guid;

-bool is_machine;

-const int UPDATE_TIMEOUT = 60;

-

-class OnDemandTest : public testing::Test {

- protected:

-

-  virtual void SetUp() {

-    wprintf(_T("Initializing\n"));

-    HRESULT hr = CComObject<JobObserver>::CreateInstance(&job_observer);

-    ASSERT_EQ(S_OK, hr);

-    job_holder = job_observer;

-    ASSERT_EQ(Reconnect(), S_OK);

-  }

-

-  virtual HRESULT Reconnect() {

-    on_demand = NULL;

-    if (is_machine) {

-      return on_demand.CoCreateInstance(

-          L"GoogleUpdate.OnDemandCOMClassMachine");

-    } else {

-      return on_demand.CoCreateInstance(

-          L"GoogleUpdate.OnDemandCOMClassUser");

-    }

-  }

-

-  virtual void TearDown() {

-    job_holder = NULL;

-    on_demand = NULL;

-  }

-

-  void WaitForUpdateCompletion(int timeout) {

-    MSG msg;

-    SYSTEMTIME start_system_time = {0};

-    SYSTEMTIME current_system_time = {0};

-    ::GetSystemTime(&start_system_time);

-    CTime start_time(start_system_time);

-    CTimeSpan timeout_period(0, 0, 0, timeout);

-

-    while (::GetMessage(&msg, NULL, 0, 0))

-    {

-      ::TranslateMessage(&msg);

-      ::DispatchMessage(&msg);

-      ::GetSystemTime(&current_system_time);

-      CTime current_time(current_system_time);

-      CTimeSpan elapsed_time = current_time - start_time;

-      if (timeout_period < elapsed_time) {

-        wprintf(_T("Timed out.\n"));

-        break;

-      }

-    }

-

-    PrintSummary();

-  }

-

-  void PrintSummary() {

-    wprintf(_T("Observed: [0x%x]\n"), job_observer->observed);

-  }

-

-  void ExpectSuccessful() {

-    // Make sure we got a succesfful install.

-    char* err_msg = "Did not observe a complete, successful install!";

-    EXPECT_TRUE(job_observer->observed & (

-        // Complete codes we don't expect are intentially commented out.

-        ON_COMPLETE_SUCCESS |

-        //ON_COMPLETE_SUCCESS_CLOSE_UI |

-        //ON_COMPLETE_RESTART_ALL_BROWSERS |

-        //ON_COMPLETE_REBOOT |

-        //ON_COMPLETE_RESTART_BROWSER |

-        ON_COMPLETE_RESTART_ALL_BROWSERS_NOTICE_ONLY

-        //ON_COMPLETE_REBOOT_NOTICE_ONLY |

-        //ON_COMPLETE_RESTART_BROWSER_NOTICE_ONLY |

-        //ON_COMPLETE_RUN_COMMAND

-        )) << err_msg;

-  }

-

-  CComObject<JobObserver>* job_observer;

-  CComPtr<IJobObserver> job_holder;

-  CComPtr<IGoogleUpdate> on_demand;

-};

-

-TEST_F(OnDemandTest, BasicUpdate) {

-  wprintf(_T("Starting Update\n"));

-  HRESULT hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(S_OK, hr);

-  WaitForUpdateCompletion(UPDATE_TIMEOUT);

-

-  ExpectSuccessful();

-  char* err_msg = "Did not observe a complete, successful install!";

-  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;

-}

-

-TEST_F(OnDemandTest, OnDemandDuringAutoUpdate) {

-  wprintf(_T("Starting Update\n"));

-  HRESULT hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(S_OK, hr);

-  WaitForUpdateCompletion(UPDATE_TIMEOUT);

-

-  ExpectSuccessful();

-  char* err_msg = "Did not observe a complete, successful install!";

-  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;

-}

-

-

-TEST_F(OnDemandTest, UpdateThenNoUpdate) {

-  wprintf(_T("Starting Update\n"));

-  HRESULT hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(S_OK, hr);

-  WaitForUpdateCompletion(UPDATE_TIMEOUT);

-

-  ExpectSuccessful();

-  char* err_msg = "Did not observe a complete, successful install!";

-  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;

-

-

-  wprintf(_T("Starting Second Update Request\n"));

-  // Reset the memory of observed actions.

-  job_observer->Reset();

-  hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(S_OK, hr);

-  WaitForUpdateCompletion(UPDATE_TIMEOUT);

-

-  ExpectSuccessful();

-  EXPECT_FALSE(job_observer->observed & ON_INSTALLING) << err_msg;

-}

-

-

-TEST_F(OnDemandTest, CloseDuringCheckingForUpdates) {

-  wprintf(_T("Starting Update\n"));

-

-  job_observer->AddCloseMode(ON_CHECKING_FOR_UPDATES);

-

-  HRESULT hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(S_OK, hr);

-  WaitForUpdateCompletion(UPDATE_TIMEOUT);

-

-  char* err_msg = "Observed a complete install when should have closed!";

-  EXPECT_TRUE(job_observer->observed & ON_COMPLETE_ERROR) << err_msg;

-  EXPECT_FALSE(job_observer->observed & ON_INSTALLING) << err_msg;

-}

-

-

-TEST_F(OnDemandTest, CloseDuringDownload) {

-  wprintf(_T("Starting Update\n"));

-

-  job_observer->AddCloseMode(ON_DOWNLOADING);

-

-  HRESULT hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(S_OK, hr);

-  WaitForUpdateCompletion(UPDATE_TIMEOUT);

-

-  char* err_msg = "Observed an install when should have closed!";

-  EXPECT_FALSE(job_observer->observed & ON_INSTALLING) << err_msg;

-}

-

-

-TEST_F(OnDemandTest, CloseDuringDownloadAndTryAgain) {

-  wprintf(_T("Starting Update\n"));

-

-  job_observer->AddCloseMode(ON_DOWNLOADING);

-

-  HRESULT hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(S_OK, hr);

-  WaitForUpdateCompletion(UPDATE_TIMEOUT);

-

-  char* err_msg = "Observed a complete, install when should have closed!";

-  EXPECT_FALSE(job_observer->observed & ON_INSTALLING) << err_msg;

-

-  wprintf(_T("Requesting update.\n"));

-  // Try a second time, but this time don't interfere.  An update should ensue.

-  job_observer->Reset();

-  hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(S_OK, hr);

-  WaitForUpdateCompletion(UPDATE_TIMEOUT);

-

-  ExpectSuccessful();

-  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;

-}

-

-

-TEST_F(OnDemandTest, UpdateWithOmahaUpdateAvailable) {

-  wprintf(_T("Starting Update\n"));

-  HRESULT hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(S_OK, hr);

-  WaitForUpdateCompletion(UPDATE_TIMEOUT);

-

-  ExpectSuccessful();

-  char* err_msg = "Did not observe a complete, successful install!";

-  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;

-}

-

-

-TEST_F(OnDemandTest, UpdateAfterOmahaUpdate) {

-  // Test shutdown code by first connecting the the com instance, waiting around

-  // for Omaha to update (done by OnDemandTestFactory.py), and then updating.

-  wprintf(_T("Waiting 60 seconds for omaha to update itself.\n"));

-  ::SleepEx(60000, true);

-

-  wprintf(_T("Attempting update on shut-down server.\n"));

-  HRESULT hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(hr, HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)) <<

-      "Goopdate should have shutdown.";

-

-  wprintf(_T("Reconnecting to COM\n"));

-  ASSERT_EQ(Reconnect(), S_OK);

-

-  wprintf(_T("Starting Update\n"));

-  hr = on_demand->Update(guid, job_observer);

-  ASSERT_EQ(S_OK, hr);

-

-  WaitForUpdateCompletion(UPDATE_TIMEOUT);

-

-  ExpectSuccessful();

-  char* err_msg = "Did not observe a complete, successful install!";

-  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;

-}

-

-

-

-bool ParseParams(int argc, TCHAR* argv[], CString* guid, bool* is_machine) {

-  ASSERT1(argv);

-  ASSERT1(guid);

-  if (argc < 3) {

-    return false;

-  }

-  *guid = argv[1];

-  // NOTE(cnygaard): I tried static casting from int to bool but it gave me a

-  // nasty warning about losing efficiency.

-  if (0 == _ttoi(argv[2])) {

-    *is_machine = false;

-  } else {

-    *is_machine = true;

-  }

-

-  // Verify that the guid is valid.

-  GUID parsed = StringToGuid(*guid);

-  if (parsed == GUID_NULL) {

-    return false;

-  }

-

-  argc -= 2;

-  testing::InitGoogleTest(&argc, argv+2);

-  return true;

-}

-

-}  // namespace omaha

-

-int _tmain(int argc, TCHAR** argv) {

-

-  if (!omaha::ParseParams(argc, argv, &omaha::guid, &omaha::is_machine)) {

-    wprintf(_T("Usage: ondemandsystem_unittest.exe \n"));

-    wprintf(_T("  [{GUID}] [is_machine (0|1)] --gtest_filter=<testname>\n"));

-    return 0;

-  }

-  omaha::FailOnAssert fail_on_assert;

-  CComModule module;

-  scoped_co_init com_apt;

-

-  int result = RUN_ALL_TESTS();

-  return result;

-}

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// System level tests for On Demand.  Unlike omaha_unittest.cpp, this test
+// should be run one test at a time view --gtest_filter.  The tests all assume
+// that there is an update available for the app (specified via guid as the
+// first argument).
+
+#include "base/basictypes.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/third_party/gtest/include/gtest/gtest.h"
+#include "omaha/tools/performondemand/performondemand.h"
+#include "omaha/common/utils.h"
+#include <windows.h>
+#include <atltime.h>
+
+namespace omaha {
+
+// Lazily define the guid and is_machine (passed in at the command line) global.
+CString guid;
+bool is_machine;
+const int UPDATE_TIMEOUT = 60;
+
+class OnDemandTest : public testing::Test {
+ protected:
+
+  virtual void SetUp() {
+    wprintf(_T("Initializing\n"));
+    HRESULT hr = CComObject<JobObserver>::CreateInstance(&job_observer);
+    ASSERT_EQ(S_OK, hr);
+    job_holder = job_observer;
+    ASSERT_EQ(Reconnect(), S_OK);
+  }
+
+  virtual HRESULT Reconnect() {
+    on_demand = NULL;
+    if (is_machine) {
+      return on_demand.CoCreateInstance(
+          L"GoogleUpdate.OnDemandCOMClassMachine");
+    } else {
+      return on_demand.CoCreateInstance(
+          L"GoogleUpdate.OnDemandCOMClassUser");
+    }
+  }
+
+  virtual void TearDown() {
+    job_holder = NULL;
+    on_demand = NULL;
+  }
+
+  void WaitForUpdateCompletion(int timeout) {
+    MSG msg;
+    SYSTEMTIME start_system_time = {0};
+    SYSTEMTIME current_system_time = {0};
+    ::GetSystemTime(&start_system_time);
+    CTime start_time(start_system_time);
+    CTimeSpan timeout_period(0, 0, 0, timeout);
+
+    while (::GetMessage(&msg, NULL, 0, 0))
+    {
+      ::TranslateMessage(&msg);
+      ::DispatchMessage(&msg);
+      ::GetSystemTime(&current_system_time);
+      CTime current_time(current_system_time);
+      CTimeSpan elapsed_time = current_time - start_time;
+      if (timeout_period < elapsed_time) {
+        wprintf(_T("Timed out.\n"));
+        break;
+      }
+    }
+
+    PrintSummary();
+  }
+
+  void PrintSummary() {
+    wprintf(_T("Observed: [0x%x]\n"), job_observer->observed);
+  }
+
+  void ExpectSuccessful() {
+    // Make sure we got a succesfful install.
+    char* err_msg = "Did not observe a complete, successful install!";
+    EXPECT_TRUE(job_observer->observed & (
+        // Complete codes we don't expect are intentially commented out.
+        ON_COMPLETE_SUCCESS |
+        //ON_COMPLETE_SUCCESS_CLOSE_UI |
+        //ON_COMPLETE_RESTART_ALL_BROWSERS |
+        //ON_COMPLETE_REBOOT |
+        //ON_COMPLETE_RESTART_BROWSER |
+        ON_COMPLETE_RESTART_ALL_BROWSERS_NOTICE_ONLY
+        //ON_COMPLETE_REBOOT_NOTICE_ONLY |
+        //ON_COMPLETE_RESTART_BROWSER_NOTICE_ONLY |
+        //ON_COMPLETE_RUN_COMMAND
+        )) << err_msg;
+  }
+
+  CComObject<JobObserver>* job_observer;
+  CComPtr<IJobObserver> job_holder;
+  CComPtr<IGoogleUpdate> on_demand;
+};
+
+TEST_F(OnDemandTest, BasicUpdate) {
+  wprintf(_T("Starting Update\n"));
+  HRESULT hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(S_OK, hr);
+  WaitForUpdateCompletion(UPDATE_TIMEOUT);
+
+  ExpectSuccessful();
+  char* err_msg = "Did not observe a complete, successful install!";
+  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;
+}
+
+TEST_F(OnDemandTest, OnDemandDuringAutoUpdate) {
+  wprintf(_T("Starting Update\n"));
+  HRESULT hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(S_OK, hr);
+  WaitForUpdateCompletion(UPDATE_TIMEOUT);
+
+  ExpectSuccessful();
+  char* err_msg = "Did not observe a complete, successful install!";
+  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;
+}
+
+
+TEST_F(OnDemandTest, UpdateThenNoUpdate) {
+  wprintf(_T("Starting Update\n"));
+  HRESULT hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(S_OK, hr);
+  WaitForUpdateCompletion(UPDATE_TIMEOUT);
+
+  ExpectSuccessful();
+  char* err_msg = "Did not observe a complete, successful install!";
+  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;
+
+
+  wprintf(_T("Starting Second Update Request\n"));
+  // Reset the memory of observed actions.
+  job_observer->Reset();
+  hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(S_OK, hr);
+  WaitForUpdateCompletion(UPDATE_TIMEOUT);
+
+  ExpectSuccessful();
+  EXPECT_FALSE(job_observer->observed & ON_INSTALLING) << err_msg;
+}
+
+
+TEST_F(OnDemandTest, CloseDuringCheckingForUpdates) {
+  wprintf(_T("Starting Update\n"));
+
+  job_observer->AddCloseMode(ON_CHECKING_FOR_UPDATES);
+
+  HRESULT hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(S_OK, hr);
+  WaitForUpdateCompletion(UPDATE_TIMEOUT);
+
+  char* err_msg = "Observed a complete install when should have closed!";
+  EXPECT_TRUE(job_observer->observed & ON_COMPLETE_ERROR) << err_msg;
+  EXPECT_FALSE(job_observer->observed & ON_INSTALLING) << err_msg;
+}
+
+
+TEST_F(OnDemandTest, CloseDuringDownload) {
+  wprintf(_T("Starting Update\n"));
+
+  job_observer->AddCloseMode(ON_DOWNLOADING);
+
+  HRESULT hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(S_OK, hr);
+  WaitForUpdateCompletion(UPDATE_TIMEOUT);
+
+  char* err_msg = "Observed an install when should have closed!";
+  EXPECT_FALSE(job_observer->observed & ON_INSTALLING) << err_msg;
+}
+
+
+TEST_F(OnDemandTest, CloseDuringDownloadAndTryAgain) {
+  wprintf(_T("Starting Update\n"));
+
+  job_observer->AddCloseMode(ON_DOWNLOADING);
+
+  HRESULT hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(S_OK, hr);
+  WaitForUpdateCompletion(UPDATE_TIMEOUT);
+
+  char* err_msg = "Observed a complete, install when should have closed!";
+  EXPECT_FALSE(job_observer->observed & ON_INSTALLING) << err_msg;
+
+  wprintf(_T("Requesting update.\n"));
+  // Try a second time, but this time don't interfere.  An update should ensue.
+  job_observer->Reset();
+  hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(S_OK, hr);
+  WaitForUpdateCompletion(UPDATE_TIMEOUT);
+
+  ExpectSuccessful();
+  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;
+}
+
+
+TEST_F(OnDemandTest, UpdateWithOmahaUpdateAvailable) {
+  wprintf(_T("Starting Update\n"));
+  HRESULT hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(S_OK, hr);
+  WaitForUpdateCompletion(UPDATE_TIMEOUT);
+
+  ExpectSuccessful();
+  char* err_msg = "Did not observe a complete, successful install!";
+  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;
+}
+
+
+TEST_F(OnDemandTest, UpdateAfterOmahaUpdate) {
+  // Test shutdown code by first connecting the the com instance, waiting around
+  // for Omaha to update (done by OnDemandTestFactory.py), and then updating.
+  wprintf(_T("Waiting 60 seconds for omaha to update itself.\n"));
+  ::SleepEx(60000, true);
+
+  wprintf(_T("Attempting update on shut-down server.\n"));
+  HRESULT hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(hr, HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)) <<
+      "Goopdate should have shutdown.";
+
+  wprintf(_T("Reconnecting to COM\n"));
+  ASSERT_EQ(Reconnect(), S_OK);
+
+  wprintf(_T("Starting Update\n"));
+  hr = on_demand->Update(guid, job_observer);
+  ASSERT_EQ(S_OK, hr);
+
+  WaitForUpdateCompletion(UPDATE_TIMEOUT);
+
+  ExpectSuccessful();
+  char* err_msg = "Did not observe a complete, successful install!";
+  EXPECT_TRUE(job_observer->observed & ON_INSTALLING) << err_msg;
+}
+
+
+
+bool ParseParams(int argc, TCHAR* argv[], CString* guid, bool* is_machine) {
+  ASSERT1(argv);
+  ASSERT1(guid);
+  if (argc < 3) {
+    return false;
+  }
+  *guid = argv[1];
+  // NOTE(cnygaard): I tried static casting from int to bool but it gave me a
+  // nasty warning about losing efficiency.
+  if (0 == _ttoi(argv[2])) {
+    *is_machine = false;
+  } else {
+    *is_machine = true;
+  }
+
+  // Verify that the guid is valid.
+  GUID parsed = StringToGuid(*guid);
+  if (parsed == GUID_NULL) {
+    return false;
+  }
+
+  argc -= 2;
+  testing::InitGoogleTest(&argc, argv+2);
+  return true;
+}
+
+}  // namespace omaha
+
+int _tmain(int argc, TCHAR** argv) {
+
+  if (!omaha::ParseParams(argc, argv, &omaha::guid, &omaha::is_machine)) {
+    wprintf(_T("Usage: ondemandsystem_unittest.exe \n"));
+    wprintf(_T("  [{GUID}] [is_machine (0|1)] --gtest_filter=<testname>\n"));
+    return 0;
+  }
+  omaha::FailOnAssert fail_on_assert;
+  CComModule module;
+  scoped_co_init com_apt;
+
+  int result = RUN_ALL_TESTS();
+  return result;
+}
+
diff --git a/testing/resource.h b/testing/resource.h
index 7e568f9..76a970b 100644
--- a/testing/resource.h
+++ b/testing/resource.h
@@ -1,29 +1,29 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TESTING_RESOURCE_H__

-#define OMAHA_TESTING_RESOURCE_H__

-

-#define IDS_EXPECTED_UPDATE_REQUEST1                8102

-#define IDS_EXPECTED_UPDATE_REQUEST_TTTOKEN         8103

-#define IDS_EXPECTED_UPDATE_REQUEST_UPDATE_DISABLED 8104

-#define IDS_EXPECTED_UPDATE_REQUEST2                8105

-#define IDS_EXPECTED_UPDATE_REQUEST3                8106

-#define IDS_EXPECTED_UPDATE_REQUEST4                8107

-#define IDS_ESCAPE_TEST                             8120

-#define IDS_ESCAPE_TEST1                            8121

-

-#endif  // OMAHA_TESTING_RESOURCE_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TESTING_RESOURCE_H__
+#define OMAHA_TESTING_RESOURCE_H__
+
+#define IDS_EXPECTED_UPDATE_REQUEST1                8102
+#define IDS_EXPECTED_UPDATE_REQUEST_TTTOKEN         8103
+#define IDS_EXPECTED_UPDATE_REQUEST_UPDATE_DISABLED 8104
+#define IDS_EXPECTED_UPDATE_REQUEST2                8105
+#define IDS_EXPECTED_UPDATE_REQUEST3                8106
+#define IDS_EXPECTED_UPDATE_REQUEST4                8107
+#define IDS_ESCAPE_TEST                             8120
+#define IDS_ESCAPE_TEST1                            8121
+
+#endif  // OMAHA_TESTING_RESOURCE_H__
+
diff --git a/testing/save_arguments.cc b/testing/save_arguments.cc
index 659ee33..adb9fd0 100644
--- a/testing/save_arguments.cc
+++ b/testing/save_arguments.cc
@@ -1,125 +1,125 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Saves the arguments passed to this application to saved_arguments.txt in the

-// same directory as the executable.

-

-#include <atlstr.h>

-#include <stdio.h>

-#include <tchar.h>

-#include <windows.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/scoped_any.h"

-

-namespace {

-

-

-const TCHAR kSavedArgumentsFileName[] = _T("saved_arguments.txt");

-

-// Reports a Win32 error to the command line and debug output then exits the

-// process. Call immediately after the failed Win32 API call.

-void HandleWin32ErrorAndExit(const TCHAR* method) {

-  _ASSERTE(method);

-  int res = ::GetLastError();

-  CString error_message;

-  error_message.Format(_T("%s failed with error %i."), method, res);

-

-

-  _tprintf(_T("%s\n"), error_message);

-

-  CString debug_message;

-  debug_message.Format(_T("[SaveArguments.exe][%s]"), error_message);

-  ::OutputDebugString(debug_message);

-

-  exit(res);

-}

-

-// Performs actions that are useful for debugging.

-void DoDebugHelper() {

-  // This is useful for debugging Code Red.

-  CString message;

-  message.AppendFormat(_T("[SaveArguments.exe][Temp directory: %s]"),

-                       omaha::app_util::GetTempDir());

-  ::OutputDebugString(message);

-}

-

-// Performs actions that are helpful or required for Omaha unit tests.

-void DoUnitTestHelpers() {

-  // The following code adapted from mi.cpp allows unit test to verify that the

-  // executable file still exists and has not been deleted after the process

-  // is created.

-  TCHAR file_name[MAX_PATH] = {0};

-  if (!::GetModuleFileName(NULL, file_name, MAX_PATH)) {

-    HandleWin32ErrorAndExit(_T("GetModuleFileName"));

-  }

-  DWORD handle = 0;

-  DWORD ver_info_size = ::GetFileVersionInfoSize(file_name, &handle);

-  if (ver_info_size == 0) {

-    HandleWin32ErrorAndExit(_T("GetFileVersionInfoSize"));

-  }

-}

-

-// Writes the provided arguments to the file.

-// Returns whether it was successful.

-int WriteArgsToFile(const CString& arguments) {

-  CString file_path(omaha::app_util::GetCurrentModuleDirectory());

-  if (!::PathAppend(CStrBuf(file_path, MAX_PATH), kSavedArgumentsFileName)) {

-    _ASSERTE(false);

-    return -1;

-  }

-

-  scoped_hfile file(::CreateFile(file_path,

-                             GENERIC_READ | GENERIC_WRITE,

-                             0,                        // do not share

-                             NULL,                     // default security

-                             CREATE_ALWAYS,            // overwrite existing

-                             FILE_ATTRIBUTE_NORMAL,

-                             NULL));                    // no template

-  if (get(file) == INVALID_HANDLE_VALUE) {

-    HandleWin32ErrorAndExit(_T("CreateFile"));

-  }

-

-  DWORD bytes_written = 0;

-  if (!::WriteFile(get(file),

-                   arguments.GetString(),

-                   arguments.GetLength() * sizeof(TCHAR),

-                   &bytes_written,

-                   NULL)) {

-    HandleWin32ErrorAndExit(_T("WriteFile"));

-  }

-

-  return 0;

-}

-

-}  // namespace

-

-

-// Returns 0 on success and non-zero otherwise.

-int _tmain(int argc, TCHAR* argv[]) {

-  DoDebugHelper();

-  DoUnitTestHelpers();

-

-  CString arguments;

-

-  // Skip the first argument, which is the executable path.

-  for (int i = 1; i < argc; i++) {

-    arguments += argv[i];

-    if (i < argc - 1) {

-      arguments += " ";

-    }

-  }

-

-  return WriteArgsToFile(arguments);

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Saves the arguments passed to this application to saved_arguments.txt in the
+// same directory as the executable.
+
+#include <atlstr.h>
+#include <stdio.h>
+#include <tchar.h>
+#include <windows.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/scoped_any.h"
+
+namespace {
+
+
+const TCHAR kSavedArgumentsFileName[] = _T("saved_arguments.txt");
+
+// Reports a Win32 error to the command line and debug output then exits the
+// process. Call immediately after the failed Win32 API call.
+void HandleWin32ErrorAndExit(const TCHAR* method) {
+  _ASSERTE(method);
+  int res = ::GetLastError();
+  CString error_message;
+  error_message.Format(_T("%s failed with error %i."), method, res);
+
+
+  _tprintf(_T("%s\n"), error_message);
+
+  CString debug_message;
+  debug_message.Format(_T("[SaveArguments.exe][%s]"), error_message);
+  ::OutputDebugString(debug_message);
+
+  exit(res);
+}
+
+// Performs actions that are useful for debugging.
+void DoDebugHelper() {
+  // This is useful for debugging Code Red.
+  CString message;
+  message.AppendFormat(_T("[SaveArguments.exe][Temp directory: %s]"),
+                       omaha::app_util::GetTempDir());
+  ::OutputDebugString(message);
+}
+
+// Performs actions that are helpful or required for Omaha unit tests.
+void DoUnitTestHelpers() {
+  // The following code adapted from mi.cpp allows unit test to verify that the
+  // executable file still exists and has not been deleted after the process
+  // is created.
+  TCHAR file_name[MAX_PATH] = {0};
+  if (!::GetModuleFileName(NULL, file_name, MAX_PATH)) {
+    HandleWin32ErrorAndExit(_T("GetModuleFileName"));
+  }
+  DWORD handle = 0;
+  DWORD ver_info_size = ::GetFileVersionInfoSize(file_name, &handle);
+  if (ver_info_size == 0) {
+    HandleWin32ErrorAndExit(_T("GetFileVersionInfoSize"));
+  }
+}
+
+// Writes the provided arguments to the file.
+// Returns whether it was successful.
+int WriteArgsToFile(const CString& arguments) {
+  CString file_path(omaha::app_util::GetCurrentModuleDirectory());
+  if (!::PathAppend(CStrBuf(file_path, MAX_PATH), kSavedArgumentsFileName)) {
+    _ASSERTE(false);
+    return -1;
+  }
+
+  scoped_hfile file(::CreateFile(file_path,
+                             GENERIC_READ | GENERIC_WRITE,
+                             0,                        // do not share
+                             NULL,                     // default security
+                             CREATE_ALWAYS,            // overwrite existing
+                             FILE_ATTRIBUTE_NORMAL,
+                             NULL));                    // no template
+  if (get(file) == INVALID_HANDLE_VALUE) {
+    HandleWin32ErrorAndExit(_T("CreateFile"));
+  }
+
+  DWORD bytes_written = 0;
+  if (!::WriteFile(get(file),
+                   arguments.GetString(),
+                   arguments.GetLength() * sizeof(TCHAR),
+                   &bytes_written,
+                   NULL)) {
+    HandleWin32ErrorAndExit(_T("WriteFile"));
+  }
+
+  return 0;
+}
+
+}  // namespace
+
+
+// Returns 0 on success and non-zero otherwise.
+int _tmain(int argc, TCHAR* argv[]) {
+  DoDebugHelper();
+  DoUnitTestHelpers();
+
+  CString arguments;
+
+  // Skip the first argument, which is the executable path.
+  for (int i = 1; i < argc; i++) {
+    arguments += argv[i];
+    if (i < argc - 1) {
+      arguments += " ";
+    }
+  }
+
+  return WriteArgsToFile(arguments);
+}
diff --git a/testing/ui/build.scons b/testing/ui/build.scons
index 5cf1e3c..cf4cb47 100644
--- a/testing/ui/build.scons
+++ b/testing/ui/build.scons
@@ -1,106 +1,106 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-local_env = env.Clone()

-

-v = local_env['product_version'][0]

-version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-local_env.FilterOut(LINKFLAGS = ['/NODEFAULTLIB'])

-

-local_env.Append(

-    CPPPATH = [

-        '$OBJ_ROOT',                    # Needed for the generated files

-        '$MAIN_DIR/goopdate/resources',

-        '$MAIN_DIR/third_party/gtest/include',

-        ],

-    CPPDEFINES = [

-        'UNITTEST',

-        '_ATL_APARTMENT_THREADED',

-        ],

-    LIBS = [

-        '$LIB_DIR/breakpad.lib',

-        '$LIB_DIR/core.lib',

-        '$LIB_DIR/goopdate_dll.lib',

-        '$LIB_DIR/google_update_ps.lib',

-        '$LIB_DIR/google_update_recovery.lib',

-        '$LIB_DIR/logging.lib',

-        '$LIB_DIR/net.lib',

-        '$LIB_DIR/repair_goopdate.lib',

-        '$LIB_DIR/security.lib',

-        '$LIB_DIR/service.lib',

-        '$LIB_DIR/statsreport.lib',

-        '$LIB_DIR/setup.lib',

-        '$LIB_DIR/worker.lib',

-        '$LIB_DIR/gtest.lib',

-        '$LIB_DIR/common.lib',

-        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],

-        'comctl32.lib',

-        'crypt32.lib',

-        'iphlpapi.lib',

-        'msi.lib',

-        'mstask.lib',

-        'netapi32.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'rpcns4.lib',

-        'rpcrt4.lib',

-        'shlwapi.lib',

-        'urlmon.lib',

-        'userenv.lib',

-        'version.lib',

-        'wininet.lib',

-        'wintrust.lib',

-        'wtsapi32.lib',

-        ],

-    RCFLAGS = [

-        '/DVERSION_MAJOR=%d' % v[0],

-        '/DVERSION_MINOR=%d' % v[1],

-        '/DVERSION_BUILD=%d' % v[2],

-        '/DVERSION_PATCH=%d' % v[3],

-        '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,

-        '/DLANGUAGE_STRING=\\"en\\"'

-        ],

-)

-

-unittest_res = local_env.RES('ui_unittest.rc'),

-

-local_env.Depends(unittest_res, '$MAIN_DIR/VERSION')

-

-# A test is a console application, so we tell mk to link to

-# main() as opposed to WinMain().

-local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-# Do not name the output _unittest.exe or _test.exe to avoid the build machine

-# automatically running it after the build. See rut.py for details.

-target_name = 'ui_systemtest.exe'

-

-inputs = [

-    'ui_unittest.cc',

-    '../../worker/progresswnd_unittest.cc',

-    unittest_res,

-    ]

-if env.Bit('use_precompiled_headers'):

-  inputs += local_env.EnablePrecompile(target_name)

-

-local_env.ComponentProgram(target_name, inputs)

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+local_env = env.Clone()
+
+v = local_env['product_version'][0]
+version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+local_env.FilterOut(LINKFLAGS = ['/NODEFAULTLIB'])
+
+local_env.Append(
+    CPPPATH = [
+        '$OBJ_ROOT',                    # Needed for the generated files
+        '$MAIN_DIR/goopdate/resources',
+        '$MAIN_DIR/third_party/gtest/include',
+        ],
+    CPPDEFINES = [
+        'UNITTEST',
+        '_ATL_APARTMENT_THREADED',
+        ],
+    LIBS = [
+        '$LIB_DIR/breakpad.lib',
+        '$LIB_DIR/core.lib',
+        '$LIB_DIR/goopdate_dll.lib',
+        '$LIB_DIR/google_update_ps.lib',
+        '$LIB_DIR/google_update_recovery.lib',
+        '$LIB_DIR/logging.lib',
+        '$LIB_DIR/net.lib',
+        '$LIB_DIR/repair_goopdate.lib',
+        '$LIB_DIR/security.lib',
+        '$LIB_DIR/service.lib',
+        '$LIB_DIR/statsreport.lib',
+        '$LIB_DIR/setup.lib',
+        '$LIB_DIR/worker.lib',
+        '$LIB_DIR/gtest.lib',
+        '$LIB_DIR/common.lib',
+        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],
+        'comctl32.lib',
+        'crypt32.lib',
+        'iphlpapi.lib',
+        'msi.lib',
+        'mstask.lib',
+        'netapi32.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'rpcns4.lib',
+        'rpcrt4.lib',
+        'shlwapi.lib',
+        'urlmon.lib',
+        'userenv.lib',
+        'version.lib',
+        'wininet.lib',
+        'wintrust.lib',
+        'wtsapi32.lib',
+        ],
+    RCFLAGS = [
+        '/DVERSION_MAJOR=%d' % v[0],
+        '/DVERSION_MINOR=%d' % v[1],
+        '/DVERSION_BUILD=%d' % v[2],
+        '/DVERSION_PATCH=%d' % v[3],
+        '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,
+        '/DLANGUAGE_STRING=\\"en\\"'
+        ],
+)
+
+unittest_res = local_env.RES('ui_unittest.rc'),
+
+local_env.Depends(unittest_res, '$MAIN_DIR/VERSION')
+
+# A test is a console application, so we tell mk to link to
+# main() as opposed to WinMain().
+local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+# Do not name the output _unittest.exe or _test.exe to avoid the build machine
+# automatically running it after the build. See rut.py for details.
+target_name = 'ui_systemtest.exe'
+
+inputs = [
+    'ui_unittest.cc',
+    '../../worker/progresswnd_unittest.cc',
+    unittest_res,
+    ]
+if env.Bit('use_precompiled_headers'):
+  inputs += local_env.EnablePrecompile(target_name)
+
+local_env.ComponentProgram(target_name, inputs)
+
diff --git a/testing/ui/ui_unittest.cc b/testing/ui/ui_unittest.cc
index 2851303..3a6b092 100644
--- a/testing/ui/ui_unittest.cc
+++ b/testing/ui/ui_unittest.cc
@@ -1,24 +1,24 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/testing/unit_test.h"

-

-int _tmain(int argc, TCHAR** argv) {

-  testing::InitGoogleTest(&argc, argv);

-  int result = RUN_ALL_TESTS();

-

-  return result;

-}

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/testing/unit_test.h"
+
+int _tmain(int argc, TCHAR** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  int result = RUN_ALL_TESTS();
+
+  return result;
+}
+
diff --git a/testing/ui/ui_unittest.manifest b/testing/ui/ui_unittest.manifest
index ffe74f6..77cba43 100644
--- a/testing/ui/ui_unittest.manifest
+++ b/testing/ui/ui_unittest.manifest
@@ -1,22 +1,22 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

-  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">

-    <security>

-      <requestedPrivileges>

-        <requestedExecutionLevel level="asInvoker" />

-      </requestedPrivileges>

-    </security>

-  </trustInfo>

-  <dependency>

-    <dependentAssembly>

-        <assemblyIdentity

-            type="win32"

-            name="Microsoft.Windows.Common-Controls"

-            version="6.0.0.0"

-            processorArchitecture="X86"

-            publicKeyToken="6595b64144ccf1df"

-            language="*"

-        />

-    </dependentAssembly>

-  </dependency>

-</assembly>

+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+    <security>
+      <requestedPrivileges>
+        <requestedExecutionLevel level="asInvoker" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+  <dependency>
+    <dependentAssembly>
+        <assemblyIdentity
+            type="win32"
+            name="Microsoft.Windows.Common-Controls"
+            version="6.0.0.0"
+            processorArchitecture="X86"
+            publicKeyToken="6595b64144ccf1df"
+            language="*"
+        />
+    </dependentAssembly>
+  </dependency>
+</assembly>
diff --git a/testing/ui/ui_unittest.rc b/testing/ui/ui_unittest.rc
index 966d12b..4b1cdfa 100644
--- a/testing/ui/ui_unittest.rc
+++ b/testing/ui/ui_unittest.rc
@@ -1,25 +1,25 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/goopdate/resource.h"

-

-#include <afxres.h>

-

-#include "omaha/goopdate/resources/goopdateres/generated_resources_en.rc"

-

-1 RT_MANIFEST "ui_unittest.manifest"

-

-IDI_APP   ICON  "omaha/goopdate/goopdate.ico"

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/goopdate/resource.h"
+
+#include <afxres.h>
+
+#include "omaha/goopdate/resources/goopdateres/generated_resources_en.rc"
+
+1 RT_MANIFEST "ui_unittest.manifest"
+
+IDI_APP   ICON  "omaha/goopdate/goopdate.ico"
+
diff --git a/testing/unit_test.cc b/testing/unit_test.cc
index 36309fd..f8ef0ea 100644
--- a/testing/unit_test.cc
+++ b/testing/unit_test.cc
@@ -1,251 +1,251 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "testing/unit_test.h"

-#include "omaha/common/app_util.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/path.h"

-#include "omaha/common/process.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/system.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/const_goopdate.h"

-

-namespace omaha {

-

-CString GetLocalAppDataPath() {

-  CString expected_local_app_data_path;

-  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_LOCAL_APPDATA | CSIDL_FLAG_DONT_VERIFY,

-                                 &expected_local_app_data_path));

-  expected_local_app_data_path.Append(_T("\\"));

-  return expected_local_app_data_path;

-}

-

-CString GetGoogleUserPath() {

-  return GetLocalAppDataPath() + _T("Google\\");

-}

-

-CString GetGoogleUpdateUserPath() {

-  return GetGoogleUserPath() + _T("Update\\");

-}

-

-CString GetGoogleUpdateMachinePath() {

-  CString program_files;

-  GetFolderPath(CSIDL_PROGRAM_FILES, &program_files);

-  return program_files + _T("\\Google\\Update");

-}

-

-DWORD GetDwordValue(const CString& full_key_name, const CString& value_name) {

-  DWORD value = 0;

-  EXPECT_SUCCEEDED(RegKey::GetValue(full_key_name, value_name, &value));

-  return value;

-}

-

-void OverrideRegistryHives(const CString& hive_override_key_name) {

-  OverrideSpecifiedRegistryHives(hive_override_key_name, true, true);

-}

-

-void OverrideSpecifiedRegistryHives(const CString& hive_override_key_name,

-                                    bool override_hklm,

-                                    bool override_hkcu) {

-  // Override the destinations of HKLM and HKCU to use a special location

-  // for the unit tests so that we don't disturb the actual Omaha state.

-  RegKey machine_key;

-  RegKey user_key;

-  ASSERT_SUCCEEDED(machine_key.Create(hive_override_key_name + MACHINE_KEY));

-  ASSERT_SUCCEEDED(user_key.Create(hive_override_key_name + USER_KEY));

-  if (override_hklm) {

-    ASSERT_SUCCEEDED(::RegOverridePredefKey(HKEY_LOCAL_MACHINE,

-                                            machine_key.Key()));

-  }

-  if (override_hkcu) {

-    ASSERT_SUCCEEDED(::RegOverridePredefKey(HKEY_CURRENT_USER,

-                                            user_key.Key()));

-  }

-}

-

-// When tests execute programs (i.e. with ShellExecute or indirectly), Windows

-// looks at kMyComputerSecurityZoneKeyPathL:kMiscSecurityZonesValueName

-// to see if it should run the program.

-// Normally, these reads are not redirected to the override key even though

-// it seems like they should be. In this case, the execution succeeds.

-// In certain cases, the reads are redirected and the program execution

-// fails due to permission denied errors.

-// This has been observed when XmlUtilsTest::LoadSave() is run before such

-// tests. Specifically, the my_xmldoc->load() call in LoadXMLFromFile()

-// appears to somehow cause the redirection to occur.

-//

-// See http://support.microsoft.com/kb/182569 for information on security

-// zones.

-void OverrideRegistryHivesWithExecutionPermissions(

-         const CString& hive_override_key_name) {

-  OverrideRegistryHives(hive_override_key_name);

-

-  const TCHAR kMyComputerSecurityZoneKeyPath[] =

-      _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\")

-      _T("Internet Settings\\Zones\\0");

-  const TCHAR kMiscSecurityZonesValueName[] = _T("1806");

-  const DWORD kPermitAction = 0;

-

-  RegKey my_computer_zone_key;

-  ASSERT_SUCCEEDED(my_computer_zone_key.Create(

-      kMyComputerSecurityZoneKeyPath));

-  ASSERT_SUCCEEDED(my_computer_zone_key.SetValue(kMiscSecurityZonesValueName,

-                                                 kPermitAction));

-}

-

-void RestoreRegistryHives() {

-  ASSERT_SUCCEEDED(::RegOverridePredefKey(HKEY_LOCAL_MACHINE, NULL));

-  ASSERT_SUCCEEDED(::RegOverridePredefKey(HKEY_CURRENT_USER, NULL));

-}

-

-void SetBuildSystemTestSource() {

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                    kRegValueTestSource,

-                                    _T("pulse")));

-}

-

-bool ShouldRunLargeTest() {

-  if (IsBuildSystem()) {

-    return true;

-  }

-  // TODO(omaha): Force enable for coverage builds (BULK_COVERAGE_RUN?).

-

-  TCHAR var[100] = {0};

-  DWORD res = ::GetEnvironmentVariable(_T("OMAHA_RUN_ALL_TESTS"), var, 100);

-  if (0 == res) {

-    ASSERT1(ERROR_ENVVAR_NOT_FOUND == ::GetLastError());

-    std::wcout << _T("\tThis large test did not run because ")

-                  _T("'OMAHA_RUN_ALL_TESTS' is not set in the environment.")

-               << std::endl;

-    return false;

-  } else {

-    return true;

-  }

-}

-

-void TerminateAllProcessesByName(const TCHAR* process_name) {

-  std::vector<uint32> process_pids;

-  ASSERT_SUCCEEDED(Process::FindProcesses(0,  // No flags.

-                                          process_name,

-                                          true,

-                                          &process_pids));

-

-  for (size_t i = 0; i < process_pids.size(); ++i) {

-    scoped_process process(::OpenProcess(PROCESS_TERMINATE,

-                                         FALSE,

-                                         process_pids[i]));

-    EXPECT_TRUE(process);

-    EXPECT_TRUE(::TerminateProcess(get(process), static_cast<uint32>(-3)));

-  }

-}

-

-void TerminateAllGoogleUpdateProcesses() {

-  TerminateAllProcessesByName(kGoopdateFileName);

-  TerminateAllProcessesByName(kGoopdateCrashHandlerFileName);

-}

-

-// The exit code of psexec is the pid it started when -d is used.

-// Wait for psexec to exit, get the exit code, and use it to get a handle

-// to the GoogleUpdate.exe instance.

-void LaunchProcessAsSystem(const CString& launch_cmd, HANDLE* process) {

-  ASSERT_TRUE(process);

-

-  TCHAR psexec_path[MAX_PATH] = {0};

-  EXPECT_TRUE(::GetEnvironmentVariable(_T("OMAHA_PSEXEC_DIR"),

-                                       psexec_path,

-                                       arraysize(psexec_path)));

-

-  CString app_launcher = ConcatenatePath(psexec_path, _T("psexec.exe"));

-  CString cmd_line_args;

-  cmd_line_args.Format(_T("-s -d %s"), launch_cmd);

-

-  PROCESS_INFORMATION pi = {0};

-  EXPECT_SUCCEEDED(System::StartProcessWithArgsAndInfo(app_launcher,

-                                                       cmd_line_args,

-                                                       &pi));

-  ::CloseHandle(pi.hThread);

-  scoped_handle started_process(pi.hProcess);

-  ASSERT_TRUE(started_process);

-

-  DWORD google_update_pid = 0;

-  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(started_process), 30000));

-  EXPECT_TRUE(::GetExitCodeProcess(get(started_process), &google_update_pid));

-  DWORD desired_access =

-      PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE;

-  *process = ::OpenProcess(desired_access, false, google_update_pid);

-  DWORD last_error(::GetLastError());

-

-  // psexec sometimes returns errors instead of PIDs and there is no way to

-  // tell the difference. We see ERROR_SERVICE_MARKED_FOR_DELETE (1072)

-  // intermittently on the build server, but do not expect any other errors.

-  EXPECT_TRUE(*process ||

-              ERROR_SERVICE_MARKED_FOR_DELETE == google_update_pid) <<

-      _T("::OpenProcess failed in a case where psexec did not return ")

-      _T("ERROR_SERVICE_MARKED_FOR_DELETE.") << _T(" The error was ")

-      << last_error << _T(".");

-}

-

-void LaunchProcess(const CString& cmd_line,

-                   const CString& args,

-                   bool as_system,

-                   HANDLE* process) {

-  ASSERT_TRUE(process);

-  *process = NULL;

-

-  CString launch_cmd = cmd_line + (args.IsEmpty() ? _T("") : _T(" ") + args);

-

-  if (as_system) {

-    // Retry the process launch if the process handle is invalid. Hopefully this

-    // is robust against intermittent ERROR_SERVICE_MARKED_FOR_DELETE errors.

-    for (int tries = 0; tries < 10 && !*process; ++tries) {

-      LaunchProcessAsSystem(launch_cmd, process);

-      if (!*process) {

-        ::Sleep(1000);

-      }

-    }

-  } else {

-    PROCESS_INFORMATION pi = {0};

-    EXPECT_SUCCEEDED(System::StartProcess(NULL, launch_cmd.GetBuffer(), &pi));

-    ::CloseHandle(pi.hThread);

-    *process = pi.hProcess;

-  }

-

-  ASSERT_TRUE(*process);

-}

-

-//

-// Unit tests for helper functions in this file.

-//

-

-TEST(UnitTestHelpersTest, GetLocalAppDataPath) {

-  const TCHAR kUserXpLocalAppDataPathFormat[] =

-      _T("C:\\Documents and Settings\\%s\\Local Settings\\Application Data\\");

-  const TCHAR kUserVistaLocalAppDataPathFormat[] =

-      _T("C:\\Users\\%s\\AppData\\Local\\");

-

-  TCHAR username[MAX_PATH] = {0};

-  EXPECT_TRUE(::GetEnvironmentVariable(_T("USERNAME"), username, MAX_PATH));

-  CString expected_path;

-  expected_path.Format(vista_util::IsVistaOrLater() ?

-                           kUserVistaLocalAppDataPathFormat :

-                           kUserXpLocalAppDataPathFormat,

-                       username);

-  EXPECT_STREQ(expected_path, GetLocalAppDataPath());

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "testing/unit_test.h"
+#include "omaha/common/app_util.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/path.h"
+#include "omaha/common/process.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/system.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/const_goopdate.h"
+
+namespace omaha {
+
+CString GetLocalAppDataPath() {
+  CString expected_local_app_data_path;
+  EXPECT_SUCCEEDED(GetFolderPath(CSIDL_LOCAL_APPDATA | CSIDL_FLAG_DONT_VERIFY,
+                                 &expected_local_app_data_path));
+  expected_local_app_data_path.Append(_T("\\"));
+  return expected_local_app_data_path;
+}
+
+CString GetGoogleUserPath() {
+  return GetLocalAppDataPath() + _T("Google\\");
+}
+
+CString GetGoogleUpdateUserPath() {
+  return GetGoogleUserPath() + _T("Update\\");
+}
+
+CString GetGoogleUpdateMachinePath() {
+  CString program_files;
+  GetFolderPath(CSIDL_PROGRAM_FILES, &program_files);
+  return program_files + _T("\\Google\\Update");
+}
+
+DWORD GetDwordValue(const CString& full_key_name, const CString& value_name) {
+  DWORD value = 0;
+  EXPECT_SUCCEEDED(RegKey::GetValue(full_key_name, value_name, &value));
+  return value;
+}
+
+void OverrideRegistryHives(const CString& hive_override_key_name) {
+  OverrideSpecifiedRegistryHives(hive_override_key_name, true, true);
+}
+
+void OverrideSpecifiedRegistryHives(const CString& hive_override_key_name,
+                                    bool override_hklm,
+                                    bool override_hkcu) {
+  // Override the destinations of HKLM and HKCU to use a special location
+  // for the unit tests so that we don't disturb the actual Omaha state.
+  RegKey machine_key;
+  RegKey user_key;
+  ASSERT_SUCCEEDED(machine_key.Create(hive_override_key_name + MACHINE_KEY));
+  ASSERT_SUCCEEDED(user_key.Create(hive_override_key_name + USER_KEY));
+  if (override_hklm) {
+    ASSERT_SUCCEEDED(::RegOverridePredefKey(HKEY_LOCAL_MACHINE,
+                                            machine_key.Key()));
+  }
+  if (override_hkcu) {
+    ASSERT_SUCCEEDED(::RegOverridePredefKey(HKEY_CURRENT_USER,
+                                            user_key.Key()));
+  }
+}
+
+// When tests execute programs (i.e. with ShellExecute or indirectly), Windows
+// looks at kMyComputerSecurityZoneKeyPathL:kMiscSecurityZonesValueName
+// to see if it should run the program.
+// Normally, these reads are not redirected to the override key even though
+// it seems like they should be. In this case, the execution succeeds.
+// In certain cases, the reads are redirected and the program execution
+// fails due to permission denied errors.
+// This has been observed when XmlUtilsTest::LoadSave() is run before such
+// tests. Specifically, the my_xmldoc->load() call in LoadXMLFromFile()
+// appears to somehow cause the redirection to occur.
+//
+// See http://support.microsoft.com/kb/182569 for information on security
+// zones.
+void OverrideRegistryHivesWithExecutionPermissions(
+         const CString& hive_override_key_name) {
+  OverrideRegistryHives(hive_override_key_name);
+
+  const TCHAR kMyComputerSecurityZoneKeyPath[] =
+      _T("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\")
+      _T("Internet Settings\\Zones\\0");
+  const TCHAR kMiscSecurityZonesValueName[] = _T("1806");
+  const DWORD kPermitAction = 0;
+
+  RegKey my_computer_zone_key;
+  ASSERT_SUCCEEDED(my_computer_zone_key.Create(
+      kMyComputerSecurityZoneKeyPath));
+  ASSERT_SUCCEEDED(my_computer_zone_key.SetValue(kMiscSecurityZonesValueName,
+                                                 kPermitAction));
+}
+
+void RestoreRegistryHives() {
+  ASSERT_SUCCEEDED(::RegOverridePredefKey(HKEY_LOCAL_MACHINE, NULL));
+  ASSERT_SUCCEEDED(::RegOverridePredefKey(HKEY_CURRENT_USER, NULL));
+}
+
+void SetBuildSystemTestSource() {
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                    kRegValueTestSource,
+                                    _T("pulse")));
+}
+
+bool ShouldRunLargeTest() {
+  if (IsBuildSystem()) {
+    return true;
+  }
+  // TODO(omaha): Force enable for coverage builds (BULK_COVERAGE_RUN?).
+
+  TCHAR var[100] = {0};
+  DWORD res = ::GetEnvironmentVariable(_T("OMAHA_RUN_ALL_TESTS"), var, 100);
+  if (0 == res) {
+    ASSERT1(ERROR_ENVVAR_NOT_FOUND == ::GetLastError());
+    std::wcout << _T("\tThis large test did not run because ")
+                  _T("'OMAHA_RUN_ALL_TESTS' is not set in the environment.")
+               << std::endl;
+    return false;
+  } else {
+    return true;
+  }
+}
+
+void TerminateAllProcessesByName(const TCHAR* process_name) {
+  std::vector<uint32> process_pids;
+  ASSERT_SUCCEEDED(Process::FindProcesses(0,  // No flags.
+                                          process_name,
+                                          true,
+                                          &process_pids));
+
+  for (size_t i = 0; i < process_pids.size(); ++i) {
+    scoped_process process(::OpenProcess(PROCESS_TERMINATE,
+                                         FALSE,
+                                         process_pids[i]));
+    EXPECT_TRUE(process);
+    EXPECT_TRUE(::TerminateProcess(get(process), static_cast<uint32>(-3)));
+  }
+}
+
+void TerminateAllGoogleUpdateProcesses() {
+  TerminateAllProcessesByName(kGoopdateFileName);
+  TerminateAllProcessesByName(kGoopdateCrashHandlerFileName);
+}
+
+// The exit code of psexec is the pid it started when -d is used.
+// Wait for psexec to exit, get the exit code, and use it to get a handle
+// to the GoogleUpdate.exe instance.
+void LaunchProcessAsSystem(const CString& launch_cmd, HANDLE* process) {
+  ASSERT_TRUE(process);
+
+  TCHAR psexec_path[MAX_PATH] = {0};
+  EXPECT_TRUE(::GetEnvironmentVariable(_T("OMAHA_PSEXEC_DIR"),
+                                       psexec_path,
+                                       arraysize(psexec_path)));
+
+  CString app_launcher = ConcatenatePath(psexec_path, _T("psexec.exe"));
+  CString cmd_line_args;
+  cmd_line_args.Format(_T("-s -d %s"), launch_cmd);
+
+  PROCESS_INFORMATION pi = {0};
+  EXPECT_SUCCEEDED(System::StartProcessWithArgsAndInfo(app_launcher,
+                                                       cmd_line_args,
+                                                       &pi));
+  ::CloseHandle(pi.hThread);
+  scoped_handle started_process(pi.hProcess);
+  ASSERT_TRUE(started_process);
+
+  DWORD google_update_pid = 0;
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(get(started_process), 30000));
+  EXPECT_TRUE(::GetExitCodeProcess(get(started_process), &google_update_pid));
+  DWORD desired_access =
+      PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE;
+  *process = ::OpenProcess(desired_access, false, google_update_pid);
+  DWORD last_error(::GetLastError());
+
+  // psexec sometimes returns errors instead of PIDs and there is no way to
+  // tell the difference. We see ERROR_SERVICE_MARKED_FOR_DELETE (1072)
+  // intermittently on the build server, but do not expect any other errors.
+  EXPECT_TRUE(*process ||
+              ERROR_SERVICE_MARKED_FOR_DELETE == google_update_pid) <<
+      _T("::OpenProcess failed in a case where psexec did not return ")
+      _T("ERROR_SERVICE_MARKED_FOR_DELETE.") << _T(" The error was ")
+      << last_error << _T(".");
+}
+
+void LaunchProcess(const CString& cmd_line,
+                   const CString& args,
+                   bool as_system,
+                   HANDLE* process) {
+  ASSERT_TRUE(process);
+  *process = NULL;
+
+  CString launch_cmd = cmd_line + (args.IsEmpty() ? _T("") : _T(" ") + args);
+
+  if (as_system) {
+    // Retry the process launch if the process handle is invalid. Hopefully this
+    // is robust against intermittent ERROR_SERVICE_MARKED_FOR_DELETE errors.
+    for (int tries = 0; tries < 10 && !*process; ++tries) {
+      LaunchProcessAsSystem(launch_cmd, process);
+      if (!*process) {
+        ::Sleep(1000);
+      }
+    }
+  } else {
+    PROCESS_INFORMATION pi = {0};
+    EXPECT_SUCCEEDED(System::StartProcess(NULL, launch_cmd.GetBuffer(), &pi));
+    ::CloseHandle(pi.hThread);
+    *process = pi.hProcess;
+  }
+
+  ASSERT_TRUE(*process);
+}
+
+//
+// Unit tests for helper functions in this file.
+//
+
+TEST(UnitTestHelpersTest, GetLocalAppDataPath) {
+  const TCHAR kUserXpLocalAppDataPathFormat[] =
+      _T("C:\\Documents and Settings\\%s\\Local Settings\\Application Data\\");
+  const TCHAR kUserVistaLocalAppDataPathFormat[] =
+      _T("C:\\Users\\%s\\AppData\\Local\\");
+
+  TCHAR username[MAX_PATH] = {0};
+  EXPECT_TRUE(::GetEnvironmentVariable(_T("USERNAME"), username, MAX_PATH));
+  CString expected_path;
+  expected_path.Format(vista_util::IsVistaOrLater() ?
+                           kUserVistaLocalAppDataPathFormat :
+                           kUserXpLocalAppDataPathFormat,
+                       username);
+  EXPECT_STREQ(expected_path, GetLocalAppDataPath());
+}
+
+}  // namespace omaha
diff --git a/testing/unit_test.h b/testing/unit_test.h
index 99bb26a..9e3f704 100644
--- a/testing/unit_test.h
+++ b/testing/unit_test.h
@@ -1,149 +1,149 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Common include file for unit testing.

-

-#ifndef OMAHA_TESTING_UNIT_TEST_H__

-#define OMAHA_TESTING_UNIT_TEST_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/scoped_ptr.h"

-#include "omaha/testing/unittest_debug_helper.h"

-#include "omaha/third_party/gtest/include/gtest/gtest.h"

-

-namespace omaha {

-

-// Predicates needed by ASSERT_PRED1 for function returning an HRESULT.

-inline testing::AssertionResult Succeeded(const char* s, HRESULT hr) {

-  if (SUCCEEDED(hr)) {

-    return testing::AssertionSuccess();

-  } else {

-    CStringA text;

-    text.AppendFormat("%s failed with error 0x%08x", s, hr);

-    testing::Message msg;

-    msg << text;

-    return testing::AssertionFailure(msg);

-  }

-}

-

-inline testing::AssertionResult Failed(const char* s, HRESULT hr) {

-  if (FAILED(hr)) {

-    return testing::AssertionSuccess();

-  } else {

-    CStringA text;

-    text.AppendFormat("%s failed with error 0x%08x", s, hr);

-    testing::Message msg;

-    msg << text;

-    return testing::AssertionFailure(msg);

-  }

-}

-

-// Returns whether the tests are running on a Pulse build system.

-inline bool IsBuildSystem() {

-  TCHAR agent[MAX_PATH] = {0};

-  return !!::GetEnvironmentVariable(_T("PULSE_AGENT"), agent, arraysize(agent));

-}

-

-// Returns the path to the base local app data directory for the user on the

-// current OS.

-CString GetLocalAppDataPath();

-

-// Returns the path to the base Google directory for the user on the current OS.

-CString GetGoogleUserPath();

-

-// Returns the path to the base Google Update directory for the user on the

-// current OS.

-CString GetGoogleUpdateUserPath();

-

-// Returns the path to the base Google Update directory for the per-machine

-// install on the current OS.

-CString GetGoogleUpdateMachinePath();

-

-// Returns a DWORD registry value from the registry. Assumes the value exists.

-// Useful for inline comparisons in EXPECT_EQ.

-DWORD GetDwordValue(const CString& full_key_name, const CString& value_name);

-

-const TCHAR* const kRegistryHiveOverrideRoot =

-    _T("HKCU\\Software\\Google\\Update\\UnitTest\\");

-const TCHAR* const kCsidlSystemIdsRegKey =

-    _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion");

-const TCHAR* const kCsidlProgramFilesRegValue =

-    _T("ProgramFilesDir");

-

-// TODO(omaha): consider renaming hive_override_key_name to new_key.

-// TODO(omaha): consider making these utility functions, maybe extend the

-//               RegKey class.

-//

-// Overrides the HKLM and HKCU registry hives so that accesses go to the

-// specified registry key instead. The function creates the

-// hive_override_key_name. In other words, overriding HKCU with

-// "HKCU\\Software\\Google\\Update\\UnitTest\\" and accessing HKCU\\Foo results

-// in an access at "HKCU\\Software\\Google\\Update\\UnitTest\\Foo".

-// This method is most often used in SetUp().

-void OverrideRegistryHives(const CString& hive_override_key_name);

-

-// Overrides only the specified hives.

-// This is useful when modifying registry settings in one hive while using

-// code (e.g. WinHttp) that relies on valid registry entries that are difficult

-// to reproduce.

-//

-// TODO(omaha): Consider renaming to:

-// void OverrideRegistryHive(HKEY hive, const CString& new_key);

-void OverrideSpecifiedRegistryHives(const CString& hive_override_key_name,

-                                    bool override_hklm,

-                                    bool override_hkcu);

-

-// Overrides the HKLM and HKCU registry hives so that accesses go to the

-// specified registry key instead. Provides permissions to execute local files.

-void OverrideRegistryHivesWithExecutionPermissions(

-         const CString& hive_override_key_name);

-

-// Restores HKLM and HKCU registry accesses to the real hives.

-// This method is most often used in TearDown(). It does not cleanup the

-// registry key that is created by OverrideRegistryHives.

-void RestoreRegistryHives();

-

-// Sets TestSource=pulse.

-void SetBuildSystemTestSource();

-

-// Returns whether large tests should be run. Large tests are always run on the

-// build system and if the "OMAHA_RUN_ALL_TESTS" environment variable is set.

-bool ShouldRunLargeTest();

-

-// Terminates all processes named GoogleUpdate.exe or GoogleCrashHandler.exe.

-void TerminateAllGoogleUpdateProcesses();

-

-// Launches a process and returns its handle.

-void LaunchProcess(const CString& cmd_line,

-                   const CString& args,

-                   bool as_system,

-                   HANDLE* process);

-

-// Launches a process as system and returns its handle. The function uses

-// psexec to run the process.

-void LaunchProcessAsSystem(const CString& launch_cmd, HANDLE* process);

-

-}  // namespace omaha

-

-#define ASSERT_SUCCEEDED(x) ASSERT_PRED_FORMAT1(omaha::Succeeded, x)

-#define EXPECT_SUCCEEDED(x) EXPECT_PRED_FORMAT1(omaha::Succeeded, x)

-#define ASSERT_FAILED(x) ASSERT_PRED_FORMAT1(omaha::Failed, x)

-#define EXPECT_FAILED(x) EXPECT_PRED_FORMAT1(omaha::Failed, x)

-

-#define kUnittestName _T("omaha_unittest.exe")

-

-#endif  // OMAHA_TESTING_UNIT_TEST_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Common include file for unit testing.
+
+#ifndef OMAHA_TESTING_UNIT_TEST_H__
+#define OMAHA_TESTING_UNIT_TEST_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/scoped_ptr.h"
+#include "omaha/testing/unittest_debug_helper.h"
+#include "omaha/third_party/gtest/include/gtest/gtest.h"
+
+namespace omaha {
+
+// Predicates needed by ASSERT_PRED1 for function returning an HRESULT.
+inline testing::AssertionResult Succeeded(const char* s, HRESULT hr) {
+  if (SUCCEEDED(hr)) {
+    return testing::AssertionSuccess();
+  } else {
+    CStringA text;
+    text.AppendFormat("%s failed with error 0x%08x", s, hr);
+    testing::Message msg;
+    msg << text;
+    return testing::AssertionFailure(msg);
+  }
+}
+
+inline testing::AssertionResult Failed(const char* s, HRESULT hr) {
+  if (FAILED(hr)) {
+    return testing::AssertionSuccess();
+  } else {
+    CStringA text;
+    text.AppendFormat("%s failed with error 0x%08x", s, hr);
+    testing::Message msg;
+    msg << text;
+    return testing::AssertionFailure(msg);
+  }
+}
+
+// Returns whether the tests are running on a Pulse build system.
+inline bool IsBuildSystem() {
+  TCHAR agent[MAX_PATH] = {0};
+  return !!::GetEnvironmentVariable(_T("PULSE_AGENT"), agent, arraysize(agent));
+}
+
+// Returns the path to the base local app data directory for the user on the
+// current OS.
+CString GetLocalAppDataPath();
+
+// Returns the path to the base Google directory for the user on the current OS.
+CString GetGoogleUserPath();
+
+// Returns the path to the base Google Update directory for the user on the
+// current OS.
+CString GetGoogleUpdateUserPath();
+
+// Returns the path to the base Google Update directory for the per-machine
+// install on the current OS.
+CString GetGoogleUpdateMachinePath();
+
+// Returns a DWORD registry value from the registry. Assumes the value exists.
+// Useful for inline comparisons in EXPECT_EQ.
+DWORD GetDwordValue(const CString& full_key_name, const CString& value_name);
+
+const TCHAR* const kRegistryHiveOverrideRoot =
+    _T("HKCU\\Software\\Google\\Update\\UnitTest\\");
+const TCHAR* const kCsidlSystemIdsRegKey =
+    _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion");
+const TCHAR* const kCsidlProgramFilesRegValue =
+    _T("ProgramFilesDir");
+
+// TODO(omaha): consider renaming hive_override_key_name to new_key.
+// TODO(omaha): consider making these utility functions, maybe extend the
+//               RegKey class.
+//
+// Overrides the HKLM and HKCU registry hives so that accesses go to the
+// specified registry key instead. The function creates the
+// hive_override_key_name. In other words, overriding HKCU with
+// "HKCU\\Software\\Google\\Update\\UnitTest\\" and accessing HKCU\\Foo results
+// in an access at "HKCU\\Software\\Google\\Update\\UnitTest\\Foo".
+// This method is most often used in SetUp().
+void OverrideRegistryHives(const CString& hive_override_key_name);
+
+// Overrides only the specified hives.
+// This is useful when modifying registry settings in one hive while using
+// code (e.g. WinHttp) that relies on valid registry entries that are difficult
+// to reproduce.
+//
+// TODO(omaha): Consider renaming to:
+// void OverrideRegistryHive(HKEY hive, const CString& new_key);
+void OverrideSpecifiedRegistryHives(const CString& hive_override_key_name,
+                                    bool override_hklm,
+                                    bool override_hkcu);
+
+// Overrides the HKLM and HKCU registry hives so that accesses go to the
+// specified registry key instead. Provides permissions to execute local files.
+void OverrideRegistryHivesWithExecutionPermissions(
+         const CString& hive_override_key_name);
+
+// Restores HKLM and HKCU registry accesses to the real hives.
+// This method is most often used in TearDown(). It does not cleanup the
+// registry key that is created by OverrideRegistryHives.
+void RestoreRegistryHives();
+
+// Sets TestSource=pulse.
+void SetBuildSystemTestSource();
+
+// Returns whether large tests should be run. Large tests are always run on the
+// build system and if the "OMAHA_RUN_ALL_TESTS" environment variable is set.
+bool ShouldRunLargeTest();
+
+// Terminates all processes named GoogleUpdate.exe or GoogleCrashHandler.exe.
+void TerminateAllGoogleUpdateProcesses();
+
+// Launches a process and returns its handle.
+void LaunchProcess(const CString& cmd_line,
+                   const CString& args,
+                   bool as_system,
+                   HANDLE* process);
+
+// Launches a process as system and returns its handle. The function uses
+// psexec to run the process.
+void LaunchProcessAsSystem(const CString& launch_cmd, HANDLE* process);
+
+}  // namespace omaha
+
+#define ASSERT_SUCCEEDED(x) ASSERT_PRED_FORMAT1(omaha::Succeeded, x)
+#define EXPECT_SUCCEEDED(x) EXPECT_PRED_FORMAT1(omaha::Succeeded, x)
+#define ASSERT_FAILED(x) ASSERT_PRED_FORMAT1(omaha::Failed, x)
+#define EXPECT_FAILED(x) EXPECT_PRED_FORMAT1(omaha::Failed, x)
+
+#define kUnittestName _T("omaha_unittest.exe")
+
+#endif  // OMAHA_TESTING_UNIT_TEST_H__
+
diff --git a/testing/unittest_debug_helper.h b/testing/unittest_debug_helper.h
index a12ee76..4a95c34 100644
--- a/testing/unittest_debug_helper.h
+++ b/testing/unittest_debug_helper.h
@@ -1,148 +1,148 @@
-// Copyright 2005-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-// Unit Test Debug Helper

-

-// This file contains assert override functions

-// It is meant to be #included only in unittest.cc files.

-

-#ifndef OMAHA_TESTING_UNITTEST_DEBUG_HELPER_H__

-#define OMAHA_TESTING_UNITTEST_DEBUG_HELPER_H__

-

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "third_party/gtest/include/gtest/gtest.h"

-

-namespace omaha {

-

-typedef int AssertResponse;

-#define IGNORE_ALWAYS 0

-#define IGNORE_ONCE   0

-

-extern int g_assert_count;

-

-// A class with no methods which will, once acquired, cause asserts to

-// be routed through the given function; once released, they will return

-// to the previous handler.

-class UseAssertFunction {

- public:

-  explicit UseAssertFunction(DebugAssertFunctionType *function) {

-    function;

-    old_function_ = REPLACE_ASSERT_FUNCTION(function);

-  }

-

-  ~UseAssertFunction() {

-    REPLACE_ASSERT_FUNCTION(old_function_);

-  }

-

-  bool asserts_enabled() {

-    return old_function_ != NULL;  // "!= NULL" fixes the perf warning C4800

-  }

-

- private:

-  DebugAssertFunctionType *old_function_;

-  DISALLOW_EVIL_CONSTRUCTORS(UseAssertFunction);

-};

-

-

-// A class with no methods which will send asserts to GTest as failures;

-// once released, it restores the assert handler to the previous handler.

-// Example usage:

-//  int main() {

-//    // Report asserts to GTest, not a messagebox.

-//    FailOnAssert a;

-//    return RUN_ALL_TESTS();

-//  }

-class FailOnAssert {

- public:

-  FailOnAssert() : inner_(AssertHandler) {

-  }

-

-  static AssertResponse AssertHandler(const char *expression,

-      const char *message, const char *file, int line) {

-    ADD_FAILURE() << "ASSERT in " << file << "(" << line << "): "

-                  << expression << "; \"" << message << "\"";

-    return IGNORE_ALWAYS;

-  }

-

- private:

-  UseAssertFunction inner_;

-  DISALLOW_EVIL_CONSTRUCTORS(FailOnAssert);

-};

-

-// A class with no methods which will cause asserts to be ignored;

-// once released, it restores the assert handler to the previous handler.

-// Example usage:

-//  test1() {

-//    IngoreAssert a;

-//    TestSomethingWhichMayOrMayNotAssert();

-//  }

-class IgnoreAsserts {

- public:

-  IgnoreAsserts() : inner_(AssertHandler) {

-  }

-

-  static AssertResponse AssertHandler(const char *,

-                                      const char *,

-                                      const char *,

-                                      int) {

-    return IGNORE_ALWAYS;

-  }

-

- private:

-  UseAssertFunction inner_;

-  DISALLOW_EVIL_CONSTRUCTORS(IgnoreAsserts);

-};

-

-// A class with no methods which will cause asserts to be counted but otherwise

-// ignored; once released, a GTest assert will be run to see if any asserts

-// were fired, and the assert handler will be restored to the previous handler.

-// Example usage:

-//  test2() {

-//    ExpectAsserts a;

-//    TestSomethingWhichIsKnownToAssert();

-//  }

-class ExpectAsserts {

- public:

-  ExpectAsserts() : inner_(AssertHandler),

-    old_assert_count_(g_assert_count) {

-  }

-

-  ~ExpectAsserts() {

-    DeInit();

-  }

-

-  static AssertResponse AssertHandler(const char *,

-                                      const char *,

-                                      const char *,

-                                      int) {

-    ++g_assert_count;

-    return IGNORE_ONCE;

-  }

- private:

-  void DeInit() {

-    if (inner_.asserts_enabled()) {

-      ASSERT_GT(g_assert_count, old_assert_count_)

-          << "This test was expected to trigger at least one assert.";

-    }

-  }

-

-  int old_assert_count_;

-  UseAssertFunction inner_;

-  DISALLOW_EVIL_CONSTRUCTORS(ExpectAsserts);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TESTING_UNITTEST_DEBUG_HELPER_H__

+// Copyright 2005-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+// Unit Test Debug Helper
+
+// This file contains assert override functions
+// It is meant to be #included only in unittest.cc files.
+
+#ifndef OMAHA_TESTING_UNITTEST_DEBUG_HELPER_H__
+#define OMAHA_TESTING_UNITTEST_DEBUG_HELPER_H__
+
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "third_party/gtest/include/gtest/gtest.h"
+
+namespace omaha {
+
+typedef int AssertResponse;
+#define IGNORE_ALWAYS 0
+#define IGNORE_ONCE   0
+
+extern int g_assert_count;
+
+// A class with no methods which will, once acquired, cause asserts to
+// be routed through the given function; once released, they will return
+// to the previous handler.
+class UseAssertFunction {
+ public:
+  explicit UseAssertFunction(DebugAssertFunctionType *function) {
+    function;
+    old_function_ = REPLACE_ASSERT_FUNCTION(function);
+  }
+
+  ~UseAssertFunction() {
+    REPLACE_ASSERT_FUNCTION(old_function_);
+  }
+
+  bool asserts_enabled() {
+    return old_function_ != NULL;  // "!= NULL" fixes the perf warning C4800
+  }
+
+ private:
+  DebugAssertFunctionType *old_function_;
+  DISALLOW_EVIL_CONSTRUCTORS(UseAssertFunction);
+};
+
+
+// A class with no methods which will send asserts to GTest as failures;
+// once released, it restores the assert handler to the previous handler.
+// Example usage:
+//  int main() {
+//    // Report asserts to GTest, not a messagebox.
+//    FailOnAssert a;
+//    return RUN_ALL_TESTS();
+//  }
+class FailOnAssert {
+ public:
+  FailOnAssert() : inner_(AssertHandler) {
+  }
+
+  static AssertResponse AssertHandler(const char *expression,
+      const char *message, const char *file, int line) {
+    ADD_FAILURE() << "ASSERT in " << file << "(" << line << "): "
+                  << expression << "; \"" << message << "\"";
+    return IGNORE_ALWAYS;
+  }
+
+ private:
+  UseAssertFunction inner_;
+  DISALLOW_EVIL_CONSTRUCTORS(FailOnAssert);
+};
+
+// A class with no methods which will cause asserts to be ignored;
+// once released, it restores the assert handler to the previous handler.
+// Example usage:
+//  test1() {
+//    IngoreAssert a;
+//    TestSomethingWhichMayOrMayNotAssert();
+//  }
+class IgnoreAsserts {
+ public:
+  IgnoreAsserts() : inner_(AssertHandler) {
+  }
+
+  static AssertResponse AssertHandler(const char *,
+                                      const char *,
+                                      const char *,
+                                      int) {
+    return IGNORE_ALWAYS;
+  }
+
+ private:
+  UseAssertFunction inner_;
+  DISALLOW_EVIL_CONSTRUCTORS(IgnoreAsserts);
+};
+
+// A class with no methods which will cause asserts to be counted but otherwise
+// ignored; once released, a GTest assert will be run to see if any asserts
+// were fired, and the assert handler will be restored to the previous handler.
+// Example usage:
+//  test2() {
+//    ExpectAsserts a;
+//    TestSomethingWhichIsKnownToAssert();
+//  }
+class ExpectAsserts {
+ public:
+  ExpectAsserts() : inner_(AssertHandler),
+    old_assert_count_(g_assert_count) {
+  }
+
+  ~ExpectAsserts() {
+    DeInit();
+  }
+
+  static AssertResponse AssertHandler(const char *,
+                                      const char *,
+                                      const char *,
+                                      int) {
+    ++g_assert_count;
+    return IGNORE_ONCE;
+  }
+ private:
+  void DeInit() {
+    if (inner_.asserts_enabled()) {
+      ASSERT_GT(g_assert_count, old_assert_count_)
+          << "This test was expected to trigger at least one assert.";
+    }
+  }
+
+  int old_assert_count_;
+  UseAssertFunction inner_;
+  DISALLOW_EVIL_CONSTRUCTORS(ExpectAsserts);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TESTING_UNITTEST_DEBUG_HELPER_H__
diff --git a/testing/unittest_debug_helper_unittest.cc b/testing/unittest_debug_helper_unittest.cc
index d4f9954..2d5c574 100644
--- a/testing/unittest_debug_helper_unittest.cc
+++ b/testing/unittest_debug_helper_unittest.cc
@@ -1,28 +1,28 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/common/debug.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha{

-

-TEST(DebugHelperTest, ExpectAssert) {

-  ExpectAsserts expect_asserts;

-  ASSERT1(false);

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/common/debug.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha{
+
+TEST(DebugHelperTest, ExpectAssert) {
+  ExpectAsserts expect_asserts;
+  ASSERT1(false);
+}
+
+}  // namespace omaha
+
diff --git a/testing/unittest_support/Readme.txt b/testing/unittest_support/Readme.txt
index b8a1f6c..8354755 100644
--- a/testing/unittest_support/Readme.txt
+++ b/testing/unittest_support/Readme.txt
@@ -1,15 +1,15 @@
-This directory contains binaries, etc. needed for the unit tests.

-

-In particular, the "test" project is not currently built by default, so the test .msi files aren't necessarily available for unit tests.

-setup_foo_v1.0.101.0.msi is built from ..\..\test\test_foo.wxs.xml.

-

-SaveArguments.exe must be updated periodically to keep its signature from being more than N days old where N is defined in google_update_recovery.cpp.

-

-* omaha_1.0.x contains files from the last official release of Omaha 1.0.x.

-  - One use is testing the legacy quiet mode (shutdown) event.

-* omaha_1.1.x contains files from the last version of Omaha 1.1.x.

-  - One use is testing the quiet mode (shutdown) event.

-* omaha_1.2.x contains an older version of Omaha 1.2.x.

-  - One use is testing the shutdown event works with older versions.

-* omaha_1.2.x_newer contains a version that is newer than any expected build.

+This directory contains binaries, etc. needed for the unit tests.
+
+In particular, the "test" project is not currently built by default, so the test .msi files aren't necessarily available for unit tests.
+setup_foo_v1.0.101.0.msi is built from ..\..\test\test_foo.wxs.xml.
+
+SaveArguments.exe must be updated periodically to keep its signature from being more than N days old where N is defined in google_update_recovery.cpp.
+
+* omaha_1.0.x contains files from the last official release of Omaha 1.0.x.
+  - One use is testing the legacy quiet mode (shutdown) event.
+* omaha_1.1.x contains files from the last version of Omaha 1.1.x.
+  - One use is testing the quiet mode (shutdown) event.
+* omaha_1.2.x contains an older version of Omaha 1.2.x.
+  - One use is testing the shutdown event works with older versions.
+* omaha_1.2.x_newer contains a version that is newer than any expected build.
   - GoogleUpdate.exe was generated by hardcoding the four version values in generated_resources_en.rc and building.
\ No newline at end of file
diff --git a/testing/unittest_support/minidump.txt b/testing/unittest_support/minidump.txt
index 09ac6a2..069d681 100644
--- a/testing/unittest_support/minidump.txt
+++ b/testing/unittest_support/minidump.txt
@@ -1,4 +1,4 @@
-; This is a custom info file to report out of process crashes.

-[ClientCustomData]

-prod=Update2

-ver=9.8.7.6

+; This is a custom info file to report out of process crashes.
+[ClientCustomData]
+prod=Update2
+ver=9.8.7.6
diff --git a/third_party/breakpad/build.scons b/third_party/breakpad/build.scons
index f7d0aac..c95c491 100644
--- a/third_party/breakpad/build.scons
+++ b/third_party/breakpad/build.scons
@@ -1,60 +1,60 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-#

-# Build BreakPad library

-#

-

-breakpad_env = env.Clone()

-breakpad_env.Append(

-    CPPPATH = [

-        '$MAIN_DIR/third_party/breakpad/src/',

-        ],

-    CCFLAGS = [

-        # Remove this after submitting breakpad fix.

-        '/wd4706',  # assignment within conditional expression

-        ],

-    CPPDEFINES = [

-        # Make breakpad not use a TerminateThread call to clean up one of its

-        # worker threads. This is required in order to pass App Verifier tests.

-        'BREAKPAD_NO_TERMINATE_THREAD',

-        ],

-)

-

-target_name = 'breakpad.lib'

-

-breakpad_inputs = [

-    'src/common/windows/guid_string.cc',

-    'src/common/windows/http_upload.cc',

-    'src/client/windows/crash_generation/client_info.cc',

-    'src/client/windows/crash_generation/crash_generation_client.cc',

-    'src/client/windows/crash_generation/crash_generation_server.cc',

-    'src/client/windows/crash_generation/minidump_generator.cc',

-    'src/client/windows/handler/exception_handler.cc',

-    'src/client/windows/sender/crash_report_sender.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  breakpad_inputs += breakpad_env.EnablePrecompile(target_name)

-

-breakpad_env.ComponentLibrary(

-    lib_name=target_name,

-    source=breakpad_inputs,

-)

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+#
+# Build BreakPad library
+#
+
+breakpad_env = env.Clone()
+breakpad_env.Append(
+    CPPPATH = [
+        '$MAIN_DIR/third_party/breakpad/src/',
+        ],
+    CCFLAGS = [
+        # Remove this after submitting breakpad fix.
+        '/wd4706',  # assignment within conditional expression
+        ],
+    CPPDEFINES = [
+        # Make breakpad not use a TerminateThread call to clean up one of its
+        # worker threads. This is required in order to pass App Verifier tests.
+        'BREAKPAD_NO_TERMINATE_THREAD',
+        ],
+)
+
+target_name = 'breakpad.lib'
+
+breakpad_inputs = [
+    'src/common/windows/guid_string.cc',
+    'src/common/windows/http_upload.cc',
+    'src/client/windows/crash_generation/client_info.cc',
+    'src/client/windows/crash_generation/crash_generation_client.cc',
+    'src/client/windows/crash_generation/crash_generation_server.cc',
+    'src/client/windows/crash_generation/minidump_generator.cc',
+    'src/client/windows/handler/exception_handler.cc',
+    'src/client/windows/sender/crash_report_sender.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  breakpad_inputs += breakpad_env.EnablePrecompile(target_name)
+
+breakpad_env.ComponentLibrary(
+    lib_name=target_name,
+    source=breakpad_inputs,
+)
+
diff --git a/third_party/breakpad/src/client/windows/common/auto_critical_section.h b/third_party/breakpad/src/client/windows/common/auto_critical_section.h
index 9bf3d49..82c7b7f 100644
--- a/third_party/breakpad/src/client/windows/common/auto_critical_section.h
+++ b/third_party/breakpad/src/client/windows/common/auto_critical_section.h
@@ -1,63 +1,63 @@
-// Copyright (c) 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__

-#define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__

-

-#include <Windows.h>

-

-namespace google_breakpad {

-

-// Automatically enters the critical section in the constructor and leaves

-// the critical section in the destructor.

-class AutoCriticalSection {

- public:

-  // Creates a new instance with the given critical section object

-  // and enters the critical section immediately.

-  explicit AutoCriticalSection(CRITICAL_SECTION* cs) : cs_(cs) {

-    assert(cs_);

-    EnterCriticalSection(cs_);

-  }

-

-  // Destructor: leaves the critical section.

-  ~AutoCriticalSection() {

-    LeaveCriticalSection(cs_);

-  }

-

- private:

-  // Disable copy ctor and operator=.

-  AutoCriticalSection(const AutoCriticalSection&);

-  AutoCriticalSection& operator=(const AutoCriticalSection&);

-

-  CRITICAL_SECTION* cs_;

-};

-

-}  // namespace google_breakpad

-

-#endif  // CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__

+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
+#define CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
+
+#include <Windows.h>
+
+namespace google_breakpad {
+
+// Automatically enters the critical section in the constructor and leaves
+// the critical section in the destructor.
+class AutoCriticalSection {
+ public:
+  // Creates a new instance with the given critical section object
+  // and enters the critical section immediately.
+  explicit AutoCriticalSection(CRITICAL_SECTION* cs) : cs_(cs) {
+    assert(cs_);
+    EnterCriticalSection(cs_);
+  }
+
+  // Destructor: leaves the critical section.
+  ~AutoCriticalSection() {
+    LeaveCriticalSection(cs_);
+  }
+
+ private:
+  // Disable copy ctor and operator=.
+  AutoCriticalSection(const AutoCriticalSection&);
+  AutoCriticalSection& operator=(const AutoCriticalSection&);
+
+  CRITICAL_SECTION* cs_;
+};
+
+}  // namespace google_breakpad
+
+#endif  // CLIENT_WINDOWS_COMMON_AUTO_CRITICAL_SECTION_H__
diff --git a/third_party/breakpad/src/client/windows/common/ipc_protocol.h b/third_party/breakpad/src/client/windows/common/ipc_protocol.h
index bca83b0..cba8699 100644
--- a/third_party/breakpad/src/client/windows/common/ipc_protocol.h
+++ b/third_party/breakpad/src/client/windows/common/ipc_protocol.h
@@ -1,179 +1,179 @@
-// Copyright (c) 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__

-#define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__

-

-#include <Windows.h>

-#include <DbgHelp.h>

-#include <string>

-#include <utility>

-#include "common/windows/string_utils-inl.h"

-#include "google_breakpad/common/minidump_format.h"

-

-namespace google_breakpad {

-

-// Name/value pair for custom client information.

-struct CustomInfoEntry {

-  // Maximum length for name and value for client custom info.

-  static const int kNameMaxLength = 64;

-  static const int kValueMaxLength = 64;

-

-  CustomInfoEntry() {

-    // Putting name and value in initializer list makes VC++ show warning 4351.

-    set_name(NULL);

-    set_value(NULL);

-  }

-

-  CustomInfoEntry(const wchar_t* name_arg, const wchar_t* value_arg) {

-    set_name(name_arg);

-    set_value(value_arg);

-  }

-

-  void set_name(const wchar_t* name_arg) {

-    if (!name_arg) {

-      name[0] = L'\0';

-      return;

-    }

-    WindowsStringUtils::safe_wcscpy(name, kNameMaxLength, name_arg);

-  }

-

-  void set_value(const wchar_t* value_arg) {

-    if (!value_arg) {

-      value[0] = L'\0';

-      return;

-    }

-

-    WindowsStringUtils::safe_wcscpy(value, kValueMaxLength, value_arg);

-  }

-

-  void set(const wchar_t* name_arg, const wchar_t* value_arg) {

-    set_name(name_arg);

-    set_value(value_arg);

-  }

-

-  wchar_t name[kNameMaxLength];

-  wchar_t value[kValueMaxLength];

-};

-

-// Constants for the protocol between client and the server.

-

-// Tags sent with each message indicating the purpose of

-// the message.

-enum MessageTag {

-  MESSAGE_TAG_NONE = 0,

-  MESSAGE_TAG_REGISTRATION_REQUEST = 1,

-  MESSAGE_TAG_REGISTRATION_RESPONSE = 2,

-  MESSAGE_TAG_REGISTRATION_ACK = 3

-};

-

-struct CustomClientInfo {

-  const CustomInfoEntry* entries;

-  int count;

-};

-

-// Message structure for IPC between crash client and crash server.

-struct ProtocolMessage {

-  ProtocolMessage()

-      : tag(MESSAGE_TAG_NONE),

-        pid(0),

-        dump_type(MiniDumpNormal),

-        thread_id(0),

-        exception_pointers(NULL),

-        assert_info(NULL),

-        custom_client_info(),

-        dump_request_handle(NULL),

-        dump_generated_handle(NULL),

-        server_alive_handle(NULL) {

-  }

-

-  // Creates an instance with the given parameters.

-  ProtocolMessage(MessageTag arg_tag,

-                  DWORD arg_pid,

-                  MINIDUMP_TYPE arg_dump_type,

-                  DWORD* arg_thread_id,

-                  EXCEPTION_POINTERS** arg_exception_pointers,

-                  MDRawAssertionInfo* arg_assert_info,

-                  const CustomClientInfo& custom_info,

-                  HANDLE arg_dump_request_handle,

-                  HANDLE arg_dump_generated_handle,

-                  HANDLE arg_server_alive)

-    : tag(arg_tag),

-      pid(arg_pid),

-      dump_type(arg_dump_type),

-      thread_id(arg_thread_id),

-      exception_pointers(arg_exception_pointers),

-      assert_info(arg_assert_info),

-      custom_client_info(custom_info),

-      dump_request_handle(arg_dump_request_handle),

-      dump_generated_handle(arg_dump_generated_handle),

-      server_alive_handle(arg_server_alive) {

-  }

-

-  // Tag in the message.

-  MessageTag tag;

-

-  // Process id.

-  DWORD pid;

-

-  // Dump type requested.

-  MINIDUMP_TYPE dump_type;

-

-  // Client thread id pointer.

-  DWORD* thread_id;

-

-  // Exception information.

-  EXCEPTION_POINTERS** exception_pointers;

-

-  // Assert information in case of an invalid parameter or

-  // pure call failure.

-  MDRawAssertionInfo* assert_info;

-

-  // Custom client information.

-  CustomClientInfo custom_client_info;

-

-  // Handle to signal the crash event.

-  HANDLE dump_request_handle;

-

-  // Handle to check if server is done generating crash.

-  HANDLE dump_generated_handle;

-

-  // Handle to a mutex that becomes signaled (WAIT_ABANDONED)

-  // if server process goes down.

-  HANDLE server_alive_handle;

-

- private:

-  // Disable copy ctor and operator=.

-  ProtocolMessage(const ProtocolMessage& msg);

-  ProtocolMessage& operator=(const ProtocolMessage& msg);

-};

-

-}  // namespace google_breakpad

-

-#endif  // CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__

+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
+#define CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
+
+#include <Windows.h>
+#include <DbgHelp.h>
+#include <string>
+#include <utility>
+#include "common/windows/string_utils-inl.h"
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+// Name/value pair for custom client information.
+struct CustomInfoEntry {
+  // Maximum length for name and value for client custom info.
+  static const int kNameMaxLength = 64;
+  static const int kValueMaxLength = 64;
+
+  CustomInfoEntry() {
+    // Putting name and value in initializer list makes VC++ show warning 4351.
+    set_name(NULL);
+    set_value(NULL);
+  }
+
+  CustomInfoEntry(const wchar_t* name_arg, const wchar_t* value_arg) {
+    set_name(name_arg);
+    set_value(value_arg);
+  }
+
+  void set_name(const wchar_t* name_arg) {
+    if (!name_arg) {
+      name[0] = L'\0';
+      return;
+    }
+    WindowsStringUtils::safe_wcscpy(name, kNameMaxLength, name_arg);
+  }
+
+  void set_value(const wchar_t* value_arg) {
+    if (!value_arg) {
+      value[0] = L'\0';
+      return;
+    }
+
+    WindowsStringUtils::safe_wcscpy(value, kValueMaxLength, value_arg);
+  }
+
+  void set(const wchar_t* name_arg, const wchar_t* value_arg) {
+    set_name(name_arg);
+    set_value(value_arg);
+  }
+
+  wchar_t name[kNameMaxLength];
+  wchar_t value[kValueMaxLength];
+};
+
+// Constants for the protocol between client and the server.
+
+// Tags sent with each message indicating the purpose of
+// the message.
+enum MessageTag {
+  MESSAGE_TAG_NONE = 0,
+  MESSAGE_TAG_REGISTRATION_REQUEST = 1,
+  MESSAGE_TAG_REGISTRATION_RESPONSE = 2,
+  MESSAGE_TAG_REGISTRATION_ACK = 3
+};
+
+struct CustomClientInfo {
+  const CustomInfoEntry* entries;
+  int count;
+};
+
+// Message structure for IPC between crash client and crash server.
+struct ProtocolMessage {
+  ProtocolMessage()
+      : tag(MESSAGE_TAG_NONE),
+        pid(0),
+        dump_type(MiniDumpNormal),
+        thread_id(0),
+        exception_pointers(NULL),
+        assert_info(NULL),
+        custom_client_info(),
+        dump_request_handle(NULL),
+        dump_generated_handle(NULL),
+        server_alive_handle(NULL) {
+  }
+
+  // Creates an instance with the given parameters.
+  ProtocolMessage(MessageTag arg_tag,
+                  DWORD arg_pid,
+                  MINIDUMP_TYPE arg_dump_type,
+                  DWORD* arg_thread_id,
+                  EXCEPTION_POINTERS** arg_exception_pointers,
+                  MDRawAssertionInfo* arg_assert_info,
+                  const CustomClientInfo& custom_info,
+                  HANDLE arg_dump_request_handle,
+                  HANDLE arg_dump_generated_handle,
+                  HANDLE arg_server_alive)
+    : tag(arg_tag),
+      pid(arg_pid),
+      dump_type(arg_dump_type),
+      thread_id(arg_thread_id),
+      exception_pointers(arg_exception_pointers),
+      assert_info(arg_assert_info),
+      custom_client_info(custom_info),
+      dump_request_handle(arg_dump_request_handle),
+      dump_generated_handle(arg_dump_generated_handle),
+      server_alive_handle(arg_server_alive) {
+  }
+
+  // Tag in the message.
+  MessageTag tag;
+
+  // Process id.
+  DWORD pid;
+
+  // Dump type requested.
+  MINIDUMP_TYPE dump_type;
+
+  // Client thread id pointer.
+  DWORD* thread_id;
+
+  // Exception information.
+  EXCEPTION_POINTERS** exception_pointers;
+
+  // Assert information in case of an invalid parameter or
+  // pure call failure.
+  MDRawAssertionInfo* assert_info;
+
+  // Custom client information.
+  CustomClientInfo custom_client_info;
+
+  // Handle to signal the crash event.
+  HANDLE dump_request_handle;
+
+  // Handle to check if server is done generating crash.
+  HANDLE dump_generated_handle;
+
+  // Handle to a mutex that becomes signaled (WAIT_ABANDONED)
+  // if server process goes down.
+  HANDLE server_alive_handle;
+
+ private:
+  // Disable copy ctor and operator=.
+  ProtocolMessage(const ProtocolMessage& msg);
+  ProtocolMessage& operator=(const ProtocolMessage& msg);
+};
+
+}  // namespace google_breakpad
+
+#endif  // CLIENT_WINDOWS_COMMON_IPC_PROTOCOL_H__
diff --git a/third_party/breakpad/src/client/windows/crash_generation/client_info.cc b/third_party/breakpad/src/client/windows/crash_generation/client_info.cc
index 2273539..4752c4a 100644
--- a/third_party/breakpad/src/client/windows/crash_generation/client_info.cc
+++ b/third_party/breakpad/src/client/windows/crash_generation/client_info.cc
@@ -1,210 +1,210 @@
-// Copyright (c) 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#include "client/windows/crash_generation/client_info.h"

-#include "client/windows/common/ipc_protocol.h"

-

-static const wchar_t kCustomInfoProcessUptimeName[] = L"ptime";

-

-namespace google_breakpad {

-

-ClientInfo::ClientInfo(CrashGenerationServer* crash_server,

-                       DWORD pid,

-                       MINIDUMP_TYPE dump_type,

-                       DWORD* thread_id,

-                       EXCEPTION_POINTERS** ex_info,

-                       MDRawAssertionInfo* assert_info,

-                       const CustomClientInfo& custom_client_info)

-    : crash_server_(crash_server),

-      pid_(pid),

-      dump_type_(dump_type),

-      ex_info_(ex_info),

-      assert_info_(assert_info),

-      custom_client_info_(custom_client_info),

-      thread_id_(thread_id),

-      process_handle_(NULL),

-      dump_requested_handle_(NULL),

-      dump_generated_handle_(NULL),

-      dump_request_wait_handle_(NULL),

-      process_exit_wait_handle_(NULL) {

-  GetSystemTimeAsFileTime(&start_time_);

-}

-

-bool ClientInfo::Initialize() {

-  process_handle_ = OpenProcess(GENERIC_ALL, FALSE, pid_);

-  if (!process_handle_) {

-    return false;

-  }

-

-  dump_requested_handle_ = CreateEvent(NULL,    // Security attributes.

-                                       TRUE,    // Manual reset.

-                                       FALSE,   // Initial state.

-                                       NULL);   // Name.

-  if (!dump_requested_handle_) {

-    return false;

-  }

-

-  dump_generated_handle_ = CreateEvent(NULL,    // Security attributes.

-                                       TRUE,    // Manual reset.

-                                       FALSE,   // Initial state.

-                                       NULL);   // Name.

-  return dump_generated_handle_ != NULL;

-}

-

-ClientInfo::~ClientInfo() {

-  if (dump_request_wait_handle_) {

-    // Wait for callbacks that might already be running to finish.

-    UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);

-  }

-

-  if (process_exit_wait_handle_) {

-    // Wait for the callback that might already be running to finish.

-    UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);

-  }

-

-  if (process_handle_) {

-    CloseHandle(process_handle_);

-  }

-

-  if (dump_requested_handle_) {

-    CloseHandle(dump_requested_handle_);

-  }

-

-  if (dump_generated_handle_) {

-    CloseHandle(dump_generated_handle_);

-  }

-}

-

-bool ClientInfo::UnregisterWaits() {

-  bool success = true;

-

-  if (dump_request_wait_handle_) {

-    if (!UnregisterWait(dump_request_wait_handle_)) {

-      success = false;

-    } else {

-      dump_request_wait_handle_ = NULL;

-    }

-  }

-

-  if (process_exit_wait_handle_) {

-    if (!UnregisterWait(process_exit_wait_handle_)) {

-      success = false;

-    } else {

-      process_exit_wait_handle_ = NULL;

-    }

-  }

-

-  return success;

-}

-

-bool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const {

-  SIZE_T bytes_count = 0;

-  if (!ReadProcessMemory(process_handle_,

-                         ex_info_,

-                         ex_info,

-                         sizeof(*ex_info),

-                         &bytes_count)) {

-    return false;

-  }

-

-  return bytes_count == sizeof(*ex_info);

-}

-

-bool ClientInfo::GetClientThreadId(DWORD* thread_id) const {

-  SIZE_T bytes_count = 0;

-  if (!ReadProcessMemory(process_handle_,

-                         thread_id_,

-                         thread_id,

-                         sizeof(*thread_id),

-                         &bytes_count)) {

-    return false;

-  }

-

-  return bytes_count == sizeof(*thread_id);

-}

-

-void ClientInfo::SetProcessUptime() {

-  FILETIME now = {0};

-  GetSystemTimeAsFileTime(&now);

-

-  ULARGE_INTEGER time_start;

-  time_start.HighPart = start_time_.dwHighDateTime;

-  time_start.LowPart = start_time_.dwLowDateTime;

-

-  ULARGE_INTEGER time_now;

-  time_now.HighPart = now.dwHighDateTime;

-  time_now.LowPart = now.dwLowDateTime;

-

-  // Calculate the delay and convert it from 100-nanoseconds to milliseconds.

-  __int64 delay = (time_now.QuadPart - time_start.QuadPart) / 10 / 1000;

-

-  // Convert it to a string.

-  wchar_t* value = custom_info_entries_.get()[custom_client_info_.count].value;

-  _i64tow_s(delay, value, CustomInfoEntry::kValueMaxLength, 10);

-}

-

-bool ClientInfo::PopulateCustomInfo() {

-  SIZE_T bytes_count = 0;

-  SIZE_T read_count = sizeof(CustomInfoEntry) * custom_client_info_.count;

-

-  // If the scoped array for custom info already has an array, it will be

-  // the same size as what we need. This is because the number of custom info

-  // entries is always the same. So allocate memory only if scoped array has

-  // a NULL pointer.

-  if (!custom_info_entries_.get()) {

-    // Allocate an extra entry for reporting uptime for the client process.

-    custom_info_entries_.reset(

-        new CustomInfoEntry[custom_client_info_.count + 1]);

-    // Use the last element in the array for uptime.

-    custom_info_entries_.get()[custom_client_info_.count].set_name(

-        kCustomInfoProcessUptimeName);

-  }

-

-  if (!ReadProcessMemory(process_handle_,

-                         custom_client_info_.entries,

-                         custom_info_entries_.get(),

-                         read_count,

-                         &bytes_count)) {

-    return false;

-  }

-

-  SetProcessUptime();

-  return (bytes_count != read_count);

-}

-

-CustomClientInfo ClientInfo::GetCustomInfo() const {

-  CustomClientInfo custom_info;

-  custom_info.entries = custom_info_entries_.get();

-  // Add 1 to the count from the client process to account for extra entry for

-  // process uptime.

-  custom_info.count = custom_client_info_.count + 1;

-  return custom_info;

-}

-

-}  // namespace google_breakpad

+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/client_info.h"
+#include "client/windows/common/ipc_protocol.h"
+
+static const wchar_t kCustomInfoProcessUptimeName[] = L"ptime";
+
+namespace google_breakpad {
+
+ClientInfo::ClientInfo(CrashGenerationServer* crash_server,
+                       DWORD pid,
+                       MINIDUMP_TYPE dump_type,
+                       DWORD* thread_id,
+                       EXCEPTION_POINTERS** ex_info,
+                       MDRawAssertionInfo* assert_info,
+                       const CustomClientInfo& custom_client_info)
+    : crash_server_(crash_server),
+      pid_(pid),
+      dump_type_(dump_type),
+      ex_info_(ex_info),
+      assert_info_(assert_info),
+      custom_client_info_(custom_client_info),
+      thread_id_(thread_id),
+      process_handle_(NULL),
+      dump_requested_handle_(NULL),
+      dump_generated_handle_(NULL),
+      dump_request_wait_handle_(NULL),
+      process_exit_wait_handle_(NULL) {
+  GetSystemTimeAsFileTime(&start_time_);
+}
+
+bool ClientInfo::Initialize() {
+  process_handle_ = OpenProcess(GENERIC_ALL, FALSE, pid_);
+  if (!process_handle_) {
+    return false;
+  }
+
+  dump_requested_handle_ = CreateEvent(NULL,    // Security attributes.
+                                       TRUE,    // Manual reset.
+                                       FALSE,   // Initial state.
+                                       NULL);   // Name.
+  if (!dump_requested_handle_) {
+    return false;
+  }
+
+  dump_generated_handle_ = CreateEvent(NULL,    // Security attributes.
+                                       TRUE,    // Manual reset.
+                                       FALSE,   // Initial state.
+                                       NULL);   // Name.
+  return dump_generated_handle_ != NULL;
+}
+
+ClientInfo::~ClientInfo() {
+  if (dump_request_wait_handle_) {
+    // Wait for callbacks that might already be running to finish.
+    UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
+  }
+
+  if (process_exit_wait_handle_) {
+    // Wait for the callback that might already be running to finish.
+    UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
+  }
+
+  if (process_handle_) {
+    CloseHandle(process_handle_);
+  }
+
+  if (dump_requested_handle_) {
+    CloseHandle(dump_requested_handle_);
+  }
+
+  if (dump_generated_handle_) {
+    CloseHandle(dump_generated_handle_);
+  }
+}
+
+bool ClientInfo::UnregisterWaits() {
+  bool success = true;
+
+  if (dump_request_wait_handle_) {
+    if (!UnregisterWait(dump_request_wait_handle_)) {
+      success = false;
+    } else {
+      dump_request_wait_handle_ = NULL;
+    }
+  }
+
+  if (process_exit_wait_handle_) {
+    if (!UnregisterWait(process_exit_wait_handle_)) {
+      success = false;
+    } else {
+      process_exit_wait_handle_ = NULL;
+    }
+  }
+
+  return success;
+}
+
+bool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const {
+  SIZE_T bytes_count = 0;
+  if (!ReadProcessMemory(process_handle_,
+                         ex_info_,
+                         ex_info,
+                         sizeof(*ex_info),
+                         &bytes_count)) {
+    return false;
+  }
+
+  return bytes_count == sizeof(*ex_info);
+}
+
+bool ClientInfo::GetClientThreadId(DWORD* thread_id) const {
+  SIZE_T bytes_count = 0;
+  if (!ReadProcessMemory(process_handle_,
+                         thread_id_,
+                         thread_id,
+                         sizeof(*thread_id),
+                         &bytes_count)) {
+    return false;
+  }
+
+  return bytes_count == sizeof(*thread_id);
+}
+
+void ClientInfo::SetProcessUptime() {
+  FILETIME now = {0};
+  GetSystemTimeAsFileTime(&now);
+
+  ULARGE_INTEGER time_start;
+  time_start.HighPart = start_time_.dwHighDateTime;
+  time_start.LowPart = start_time_.dwLowDateTime;
+
+  ULARGE_INTEGER time_now;
+  time_now.HighPart = now.dwHighDateTime;
+  time_now.LowPart = now.dwLowDateTime;
+
+  // Calculate the delay and convert it from 100-nanoseconds to milliseconds.
+  __int64 delay = (time_now.QuadPart - time_start.QuadPart) / 10 / 1000;
+
+  // Convert it to a string.
+  wchar_t* value = custom_info_entries_.get()[custom_client_info_.count].value;
+  _i64tow_s(delay, value, CustomInfoEntry::kValueMaxLength, 10);
+}
+
+bool ClientInfo::PopulateCustomInfo() {
+  SIZE_T bytes_count = 0;
+  SIZE_T read_count = sizeof(CustomInfoEntry) * custom_client_info_.count;
+
+  // If the scoped array for custom info already has an array, it will be
+  // the same size as what we need. This is because the number of custom info
+  // entries is always the same. So allocate memory only if scoped array has
+  // a NULL pointer.
+  if (!custom_info_entries_.get()) {
+    // Allocate an extra entry for reporting uptime for the client process.
+    custom_info_entries_.reset(
+        new CustomInfoEntry[custom_client_info_.count + 1]);
+    // Use the last element in the array for uptime.
+    custom_info_entries_.get()[custom_client_info_.count].set_name(
+        kCustomInfoProcessUptimeName);
+  }
+
+  if (!ReadProcessMemory(process_handle_,
+                         custom_client_info_.entries,
+                         custom_info_entries_.get(),
+                         read_count,
+                         &bytes_count)) {
+    return false;
+  }
+
+  SetProcessUptime();
+  return (bytes_count != read_count);
+}
+
+CustomClientInfo ClientInfo::GetCustomInfo() const {
+  CustomClientInfo custom_info;
+  custom_info.entries = custom_info_entries_.get();
+  // Add 1 to the count from the client process to account for extra entry for
+  // process uptime.
+  custom_info.count = custom_client_info_.count + 1;
+  return custom_info;
+}
+
+}  // namespace google_breakpad
diff --git a/third_party/breakpad/src/client/windows/crash_generation/client_info.h b/third_party/breakpad/src/client/windows/crash_generation/client_info.h
index dbcd4ff..774816f 100644
--- a/third_party/breakpad/src/client/windows/crash_generation/client_info.h
+++ b/third_party/breakpad/src/client/windows/crash_generation/client_info.h
@@ -1,170 +1,170 @@
-// Copyright (c) 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__

-#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__

-

-#include <Windows.h>

-#include <DbgHelp.h>

-#include "client/windows/common/ipc_protocol.h"

-#include "google_breakpad/common/minidump_format.h"

-#include "processor/scoped_ptr.h"

-

-namespace google_breakpad {

-

-class CrashGenerationServer;

-

-// Abstraction for a crash client process.

-class ClientInfo {

- public:

-  // Creates an instance with the given values. Gets the process

-  // handle for the given process id and creates necessary event

-  // objects.

-  ClientInfo(CrashGenerationServer* crash_server,

-             DWORD pid,

-             MINIDUMP_TYPE dump_type,

-             DWORD* thread_id,

-             EXCEPTION_POINTERS** ex_info,

-             MDRawAssertionInfo* assert_info,

-             const CustomClientInfo& custom_client_info);

-

-  ~ClientInfo();

-

-  CrashGenerationServer* crash_server() const { return crash_server_; }

-  DWORD pid() const { return pid_; }

-  MINIDUMP_TYPE dump_type() const { return dump_type_; }

-  EXCEPTION_POINTERS** ex_info() const { return ex_info_; }

-  MDRawAssertionInfo* assert_info() const { return assert_info_; }

-  DWORD* thread_id() const { return thread_id_; }

-  HANDLE process_handle() const { return process_handle_; }

-  HANDLE dump_requested_handle() const { return dump_requested_handle_; }

-  HANDLE dump_generated_handle() const { return dump_generated_handle_; }

-

-  HANDLE dump_request_wait_handle() const {

-    return dump_request_wait_handle_;

-  }

-

-  void set_dump_request_wait_handle(HANDLE value) {

-    dump_request_wait_handle_ = value;

-  }

-

-  HANDLE process_exit_wait_handle() const {

-    return process_exit_wait_handle_;

-  }

-

-  void set_process_exit_wait_handle(HANDLE value) {

-    process_exit_wait_handle_ = value;

-  }

-

-  // Unregister all waits for the client.

-  bool UnregisterWaits();

-

-  bool Initialize();

-  bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const;

-  bool GetClientThreadId(DWORD* thread_id) const;

-

-  // Reads the custom information from the client process address space.

-  bool PopulateCustomInfo();

-

-  // Returns the client custom information.

-  CustomClientInfo GetCustomInfo() const;

-

- private:

-  // Calcualtes the uptime for the client process, converts it to a string and

-  // stores it in the last entry of client custom info.

-  void SetProcessUptime();

-

-  // Crash generation server.

-  CrashGenerationServer* crash_server_;

-

-  // Client process ID.

-  DWORD pid_;

-

-  // Dump type requested by the client.

-  MINIDUMP_TYPE dump_type_;

-

-  // Address of an EXCEPTION_POINTERS* variable in the client

-  // process address space that will point to an instance of

-  // EXCEPTION_POINTERS containing information about crash.

-  //

-  // WARNING: Do not dereference these pointers as they are pointers

-  // in the address space of another process.

-  EXCEPTION_POINTERS** ex_info_;

-

-  // Address of an instance of MDRawAssertionInfo in the client

-  // process address space that will contain information about

-  // non-exception related crashes like invalid parameter assertion

-  // failures and pure calls.

-  //

-  // WARNING: Do not dereference these pointers as they are pointers

-  // in the address space of another process.

-  MDRawAssertionInfo* assert_info_;

-

-  // Custom information about the client.

-  CustomClientInfo custom_client_info_;

-

-  // Contains the custom client info entries read from the client process

-  // memory. This will be populated only if the method GetClientCustomInfo

-  // is called.

-  scoped_array<CustomInfoEntry> custom_info_entries_;

-

-  // Address of a variable in the client process address space that

-  // will contain the thread id of the crashing client thread.

-  //

-  // WARNING: Do not dereference these pointers as they are pointers

-  // in the address space of another process.

-  DWORD* thread_id_;

-

-  // Client process handle.

-  HANDLE process_handle_;

-

-  // Dump request event handle.

-  HANDLE dump_requested_handle_;

-

-  // Dump generated event handle.

-  HANDLE dump_generated_handle_;

-

-  // Wait handle for dump request event.

-  HANDLE dump_request_wait_handle_;

-

-  // Wait handle for process exit event.

-  HANDLE process_exit_wait_handle_;

-

-  // Time when the client process started. It is used to determine the uptime

-  // for the client process when it signals a crash.

-  FILETIME start_time_;

-

-  // Disallow copy ctor and operator=.

-  ClientInfo(const ClientInfo& client_info);

-  ClientInfo& operator=(const ClientInfo& client_info);

-};

-

-}  // namespace google_breakpad

-

-#endif  // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__

+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
+#define CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
+
+#include <Windows.h>
+#include <DbgHelp.h>
+#include "client/windows/common/ipc_protocol.h"
+#include "google_breakpad/common/minidump_format.h"
+#include "processor/scoped_ptr.h"
+
+namespace google_breakpad {
+
+class CrashGenerationServer;
+
+// Abstraction for a crash client process.
+class ClientInfo {
+ public:
+  // Creates an instance with the given values. Gets the process
+  // handle for the given process id and creates necessary event
+  // objects.
+  ClientInfo(CrashGenerationServer* crash_server,
+             DWORD pid,
+             MINIDUMP_TYPE dump_type,
+             DWORD* thread_id,
+             EXCEPTION_POINTERS** ex_info,
+             MDRawAssertionInfo* assert_info,
+             const CustomClientInfo& custom_client_info);
+
+  ~ClientInfo();
+
+  CrashGenerationServer* crash_server() const { return crash_server_; }
+  DWORD pid() const { return pid_; }
+  MINIDUMP_TYPE dump_type() const { return dump_type_; }
+  EXCEPTION_POINTERS** ex_info() const { return ex_info_; }
+  MDRawAssertionInfo* assert_info() const { return assert_info_; }
+  DWORD* thread_id() const { return thread_id_; }
+  HANDLE process_handle() const { return process_handle_; }
+  HANDLE dump_requested_handle() const { return dump_requested_handle_; }
+  HANDLE dump_generated_handle() const { return dump_generated_handle_; }
+
+  HANDLE dump_request_wait_handle() const {
+    return dump_request_wait_handle_;
+  }
+
+  void set_dump_request_wait_handle(HANDLE value) {
+    dump_request_wait_handle_ = value;
+  }
+
+  HANDLE process_exit_wait_handle() const {
+    return process_exit_wait_handle_;
+  }
+
+  void set_process_exit_wait_handle(HANDLE value) {
+    process_exit_wait_handle_ = value;
+  }
+
+  // Unregister all waits for the client.
+  bool UnregisterWaits();
+
+  bool Initialize();
+  bool GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const;
+  bool GetClientThreadId(DWORD* thread_id) const;
+
+  // Reads the custom information from the client process address space.
+  bool PopulateCustomInfo();
+
+  // Returns the client custom information.
+  CustomClientInfo GetCustomInfo() const;
+
+ private:
+  // Calcualtes the uptime for the client process, converts it to a string and
+  // stores it in the last entry of client custom info.
+  void SetProcessUptime();
+
+  // Crash generation server.
+  CrashGenerationServer* crash_server_;
+
+  // Client process ID.
+  DWORD pid_;
+
+  // Dump type requested by the client.
+  MINIDUMP_TYPE dump_type_;
+
+  // Address of an EXCEPTION_POINTERS* variable in the client
+  // process address space that will point to an instance of
+  // EXCEPTION_POINTERS containing information about crash.
+  //
+  // WARNING: Do not dereference these pointers as they are pointers
+  // in the address space of another process.
+  EXCEPTION_POINTERS** ex_info_;
+
+  // Address of an instance of MDRawAssertionInfo in the client
+  // process address space that will contain information about
+  // non-exception related crashes like invalid parameter assertion
+  // failures and pure calls.
+  //
+  // WARNING: Do not dereference these pointers as they are pointers
+  // in the address space of another process.
+  MDRawAssertionInfo* assert_info_;
+
+  // Custom information about the client.
+  CustomClientInfo custom_client_info_;
+
+  // Contains the custom client info entries read from the client process
+  // memory. This will be populated only if the method GetClientCustomInfo
+  // is called.
+  scoped_array<CustomInfoEntry> custom_info_entries_;
+
+  // Address of a variable in the client process address space that
+  // will contain the thread id of the crashing client thread.
+  //
+  // WARNING: Do not dereference these pointers as they are pointers
+  // in the address space of another process.
+  DWORD* thread_id_;
+
+  // Client process handle.
+  HANDLE process_handle_;
+
+  // Dump request event handle.
+  HANDLE dump_requested_handle_;
+
+  // Dump generated event handle.
+  HANDLE dump_generated_handle_;
+
+  // Wait handle for dump request event.
+  HANDLE dump_request_wait_handle_;
+
+  // Wait handle for process exit event.
+  HANDLE process_exit_wait_handle_;
+
+  // Time when the client process started. It is used to determine the uptime
+  // for the client process when it signals a crash.
+  FILETIME start_time_;
+
+  // Disallow copy ctor and operator=.
+  ClientInfo(const ClientInfo& client_info);
+  ClientInfo& operator=(const ClientInfo& client_info);
+};
+
+}  // namespace google_breakpad
+
+#endif  // CLIENT_WINDOWS_CRASH_GENERATION_CLIENT_INFO_H__
diff --git a/third_party/breakpad/src/client/windows/crash_generation/crash_generation_client.cc b/third_party/breakpad/src/client/windows/crash_generation/crash_generation_client.cc
index 3271f72..197807a 100644
--- a/third_party/breakpad/src/client/windows/crash_generation/crash_generation_client.cc
+++ b/third_party/breakpad/src/client/windows/crash_generation/crash_generation_client.cc
@@ -1,337 +1,337 @@
-// Copyright (c) 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#include "client/windows/crash_generation/crash_generation_client.h"

-#include <cassert>

-#include <utility>

-#include "client/windows/common/ipc_protocol.h"

-

-namespace google_breakpad {

-

-const int kPipeBusyWaitTimeoutMs = 2000;

-

-#ifdef _DEBUG

-const DWORD kWaitForServerTimeoutMs = INFINITE;

-#else

-const DWORD kWaitForServerTimeoutMs = 15000;

-#endif

-

-const int kPipeConnectMaxAttempts = 2;

-

-const DWORD kPipeDesiredAccess = FILE_READ_DATA |

-                                 FILE_WRITE_DATA |

-                                 FILE_WRITE_ATTRIBUTES;

-

-const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |

-                                      SECURITY_SQOS_PRESENT;

-

-const DWORD kPipeMode = PIPE_READMODE_MESSAGE;

-

-const size_t kWaitEventCount = 2;

-

-// This function is orphan for production code. It can be used

-// for debugging to help repro some scenarios like the client

-// is slow in writing to the pipe after connecting, the client

-// is slow in reading from the pipe after writing, etc. The parameter

-// overlapped below is not used and it is present to match the signature

-// of this function to TransactNamedPipe Win32 API. Uncomment if needed

-// for debugging.

-/**

-static bool TransactNamedPipeDebugHelper(HANDLE pipe,

-                                         const void* in_buffer,

-                                         DWORD in_size,

-                                         void* out_buffer,

-                                         DWORD out_size,

-                                         DWORD* bytes_count,

-                                         LPOVERLAPPED) {

-  // Uncomment the next sleep to create a gap before writing

-  // to pipe.

-  // Sleep(5000);

-

-  if (!WriteFile(pipe,

-                 in_buffer,

-                 in_size,

-                 bytes_count,

-                 NULL)) {

-    return false;

-  }

-

-  // Uncomment the next sleep to create a gap between write

-  // and read.

-  // Sleep(5000);

-

-  return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE;

-}

-**/

-

-CrashGenerationClient::CrashGenerationClient(

-    const wchar_t* pipe_name,

-    MINIDUMP_TYPE dump_type,

-    const CustomClientInfo* custom_info)

-        : pipe_name_(pipe_name),

-          dump_type_(dump_type),

-          thread_id_(0),

-          server_process_id_(0),

-          crash_event_(NULL),

-          crash_generated_(NULL),

-          server_alive_(NULL),

-          exception_pointers_(NULL),

-          custom_info_() {

-  memset(&assert_info_, 0, sizeof(assert_info_));

-  if (custom_info) {

-    custom_info_ = *custom_info;

-  }

-}

-

-CrashGenerationClient::~CrashGenerationClient() {

-  if (crash_event_) {

-    CloseHandle(crash_event_);

-  }

-

-  if (crash_generated_) {

-    CloseHandle(crash_generated_);

-  }

-

-  if (server_alive_) {

-    CloseHandle(server_alive_);

-  }

-}

-

-// Performs the registration step with the server process.

-// The registration step involves communicating with the server

-// via a named pipe. The client sends the following pieces of

-// data to the server:

-//

-// * Message tag indicating the client is requesting registration.

-// * Process id of the client process.

-// * Address of a DWORD variable in the client address space

-//   that will contain the thread id of the client thread that

-//   caused the crash.

-// * Address of a EXCEPTION_POINTERS* variable in the client

-//   address space that will point to an instance of EXCEPTION_POINTERS

-//   when the crash happens.

-// * Address of an instance of MDRawAssertionInfo that will contain

-//   relevant information in case of non-exception crashes like assertion

-//   failures and pure calls.

-//

-// In return the client expects the following information from the server:

-//

-// * Message tag indicating successful registration.

-// * Server process id.

-// * Handle to an object that client can signal to request dump

-//   generation from the server.

-// * Handle to an object that client can wait on after requesting

-//   dump generation for the server to finish dump generation.

-// * Handle to a mutex object that client can wait on to make sure

-//   server is still alive.

-//

-// If any step of the expected behavior mentioned above fails, the

-// registration step is not considered successful and hence out-of-process

-// dump generation service is not available.

-//

-// Returns true if the registration is successful; false otherwise.

-bool CrashGenerationClient::Register() {

-  HANDLE pipe = ConnectToServer();

-  if (!pipe) {

-    return false;

-  }

-

-  bool success = RegisterClient(pipe);

-  CloseHandle(pipe);

-  return success;

-}

-

-HANDLE CrashGenerationClient::ConnectToServer() {

-  HANDLE pipe = ConnectToPipe(pipe_name_.c_str(),

-                              kPipeDesiredAccess,

-                              kPipeFlagsAndAttributes);

-  if (!pipe) {

-    return NULL;

-  }

-

-  DWORD mode = kPipeMode;

-  if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) {

-    CloseHandle(pipe);

-    pipe = NULL;

-  }

-

-  return pipe;

-}

-

-bool CrashGenerationClient::RegisterClient(HANDLE pipe) {

-  ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST,

-                      GetCurrentProcessId(),

-                      dump_type_,

-                      &thread_id_,

-                      &exception_pointers_,

-                      &assert_info_,

-                      custom_info_,

-                      NULL,

-                      NULL,

-                      NULL);

-  ProtocolMessage reply;

-  DWORD bytes_count = 0;

-  // The call to TransactNamedPipe below can be changed to a call

-  // to TransactNamedPipeDebugHelper to help repro some scenarios.

-  // For details see comments for TransactNamedPipeDebugHelper.

-  if (!TransactNamedPipe(pipe,

-                         &msg,

-                         sizeof(msg),

-                         &reply,

-                         sizeof(ProtocolMessage),

-                         &bytes_count,

-                         NULL)) {

-    return false;

-  }

-

-  if (!ValidateResponse(reply)) {

-    return false;

-  }

-

-  ProtocolMessage ack_msg;

-  ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK;

-

-  if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) {

-    return false;

-  }

-  crash_event_ = reply.dump_request_handle;

-  crash_generated_ = reply.dump_generated_handle;

-  server_alive_ = reply.server_alive_handle;

-  server_process_id_ = reply.pid;

-

-  return true;

-}

-

-HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name,

-                                            DWORD pipe_access,

-                                            DWORD flags_attrs) {

-  for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {

-    HANDLE pipe = CreateFile(pipe_name,

-                             pipe_access,

-                             0,

-                             NULL,

-                             OPEN_EXISTING,

-                             flags_attrs,

-                             NULL);

-    if (pipe != INVALID_HANDLE_VALUE) {

-      return pipe;

-    }

-

-    // Cannot continue retrying if error is something other than

-    // ERROR_PIPE_BUSY.

-    if (GetLastError() != ERROR_PIPE_BUSY) {

-      break;

-    }

-

-    // Cannot continue retrying if wait on pipe fails.

-    if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {

-      break;

-    }

-  }

-

-  return NULL;

-}

-

-bool CrashGenerationClient::ValidateResponse(

-    const ProtocolMessage& msg) const {

-  return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) &&

-         (msg.pid != 0) &&

-         (msg.dump_request_handle != NULL) &&

-         (msg.dump_generated_handle != NULL) &&

-         (msg.server_alive_handle != NULL);

-}

-

-bool CrashGenerationClient::IsRegistered() const {

-  return crash_event_ != NULL;

-}

-

-bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {

-  if (!IsRegistered()) {

-    return false;

-  }

-

-  exception_pointers_ = ex_info;

-  thread_id_ = GetCurrentThreadId();

-

-  assert_info_.line = 0;

-  assert_info_.type = 0;

-  assert_info_.expression[0] = 0;

-  assert_info_.file[0] = 0;

-  assert_info_.function[0] = 0;

-

-  return SignalCrashEventAndWait();

-}

-

-bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {

-  if (!IsRegistered()) {

-    return false;

-  }

-

-  exception_pointers_ = NULL;

-

-  if (assert_info) {

-    memcpy(&assert_info_, assert_info, sizeof(assert_info_));

-  } else {

-    memset(&assert_info_, 0, sizeof(assert_info_));

-  }

-

-  thread_id_ = GetCurrentThreadId();

-

-  return SignalCrashEventAndWait();

-}

-

-bool CrashGenerationClient::SignalCrashEventAndWait() {

-  assert(crash_event_);

-  assert(crash_generated_);

-  assert(server_alive_);

-

-  // Reset the dump generated event before signaling the crash

-  // event so that the server can set the dump generated event

-  // once it is done generating the event.

-  if (!ResetEvent(crash_generated_)) {

-    return false;

-  }

-

-  if (!SetEvent(crash_event_)) {

-    return false;

-  }

-

-  HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_};

-

-  DWORD result = WaitForMultipleObjects(kWaitEventCount,

-                                        wait_handles,

-                                        FALSE,

-                                        kWaitForServerTimeoutMs);

-

-  // Crash dump was successfully generated only if the server

-  // signaled the crash generated event.

-  return result == WAIT_OBJECT_0;

-}

-

-}  // namespace google_breakpad

+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/crash_generation_client.h"
+#include <cassert>
+#include <utility>
+#include "client/windows/common/ipc_protocol.h"
+
+namespace google_breakpad {
+
+const int kPipeBusyWaitTimeoutMs = 2000;
+
+#ifdef _DEBUG
+const DWORD kWaitForServerTimeoutMs = INFINITE;
+#else
+const DWORD kWaitForServerTimeoutMs = 15000;
+#endif
+
+const int kPipeConnectMaxAttempts = 2;
+
+const DWORD kPipeDesiredAccess = FILE_READ_DATA |
+                                 FILE_WRITE_DATA |
+                                 FILE_WRITE_ATTRIBUTES;
+
+const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
+                                      SECURITY_SQOS_PRESENT;
+
+const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
+
+const size_t kWaitEventCount = 2;
+
+// This function is orphan for production code. It can be used
+// for debugging to help repro some scenarios like the client
+// is slow in writing to the pipe after connecting, the client
+// is slow in reading from the pipe after writing, etc. The parameter
+// overlapped below is not used and it is present to match the signature
+// of this function to TransactNamedPipe Win32 API. Uncomment if needed
+// for debugging.
+/**
+static bool TransactNamedPipeDebugHelper(HANDLE pipe,
+                                         const void* in_buffer,
+                                         DWORD in_size,
+                                         void* out_buffer,
+                                         DWORD out_size,
+                                         DWORD* bytes_count,
+                                         LPOVERLAPPED) {
+  // Uncomment the next sleep to create a gap before writing
+  // to pipe.
+  // Sleep(5000);
+
+  if (!WriteFile(pipe,
+                 in_buffer,
+                 in_size,
+                 bytes_count,
+                 NULL)) {
+    return false;
+  }
+
+  // Uncomment the next sleep to create a gap between write
+  // and read.
+  // Sleep(5000);
+
+  return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE;
+}
+**/
+
+CrashGenerationClient::CrashGenerationClient(
+    const wchar_t* pipe_name,
+    MINIDUMP_TYPE dump_type,
+    const CustomClientInfo* custom_info)
+        : pipe_name_(pipe_name),
+          dump_type_(dump_type),
+          thread_id_(0),
+          server_process_id_(0),
+          crash_event_(NULL),
+          crash_generated_(NULL),
+          server_alive_(NULL),
+          exception_pointers_(NULL),
+          custom_info_() {
+  memset(&assert_info_, 0, sizeof(assert_info_));
+  if (custom_info) {
+    custom_info_ = *custom_info;
+  }
+}
+
+CrashGenerationClient::~CrashGenerationClient() {
+  if (crash_event_) {
+    CloseHandle(crash_event_);
+  }
+
+  if (crash_generated_) {
+    CloseHandle(crash_generated_);
+  }
+
+  if (server_alive_) {
+    CloseHandle(server_alive_);
+  }
+}
+
+// Performs the registration step with the server process.
+// The registration step involves communicating with the server
+// via a named pipe. The client sends the following pieces of
+// data to the server:
+//
+// * Message tag indicating the client is requesting registration.
+// * Process id of the client process.
+// * Address of a DWORD variable in the client address space
+//   that will contain the thread id of the client thread that
+//   caused the crash.
+// * Address of a EXCEPTION_POINTERS* variable in the client
+//   address space that will point to an instance of EXCEPTION_POINTERS
+//   when the crash happens.
+// * Address of an instance of MDRawAssertionInfo that will contain
+//   relevant information in case of non-exception crashes like assertion
+//   failures and pure calls.
+//
+// In return the client expects the following information from the server:
+//
+// * Message tag indicating successful registration.
+// * Server process id.
+// * Handle to an object that client can signal to request dump
+//   generation from the server.
+// * Handle to an object that client can wait on after requesting
+//   dump generation for the server to finish dump generation.
+// * Handle to a mutex object that client can wait on to make sure
+//   server is still alive.
+//
+// If any step of the expected behavior mentioned above fails, the
+// registration step is not considered successful and hence out-of-process
+// dump generation service is not available.
+//
+// Returns true if the registration is successful; false otherwise.
+bool CrashGenerationClient::Register() {
+  HANDLE pipe = ConnectToServer();
+  if (!pipe) {
+    return false;
+  }
+
+  bool success = RegisterClient(pipe);
+  CloseHandle(pipe);
+  return success;
+}
+
+HANDLE CrashGenerationClient::ConnectToServer() {
+  HANDLE pipe = ConnectToPipe(pipe_name_.c_str(),
+                              kPipeDesiredAccess,
+                              kPipeFlagsAndAttributes);
+  if (!pipe) {
+    return NULL;
+  }
+
+  DWORD mode = kPipeMode;
+  if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) {
+    CloseHandle(pipe);
+    pipe = NULL;
+  }
+
+  return pipe;
+}
+
+bool CrashGenerationClient::RegisterClient(HANDLE pipe) {
+  ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST,
+                      GetCurrentProcessId(),
+                      dump_type_,
+                      &thread_id_,
+                      &exception_pointers_,
+                      &assert_info_,
+                      custom_info_,
+                      NULL,
+                      NULL,
+                      NULL);
+  ProtocolMessage reply;
+  DWORD bytes_count = 0;
+  // The call to TransactNamedPipe below can be changed to a call
+  // to TransactNamedPipeDebugHelper to help repro some scenarios.
+  // For details see comments for TransactNamedPipeDebugHelper.
+  if (!TransactNamedPipe(pipe,
+                         &msg,
+                         sizeof(msg),
+                         &reply,
+                         sizeof(ProtocolMessage),
+                         &bytes_count,
+                         NULL)) {
+    return false;
+  }
+
+  if (!ValidateResponse(reply)) {
+    return false;
+  }
+
+  ProtocolMessage ack_msg;
+  ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK;
+
+  if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) {
+    return false;
+  }
+  crash_event_ = reply.dump_request_handle;
+  crash_generated_ = reply.dump_generated_handle;
+  server_alive_ = reply.server_alive_handle;
+  server_process_id_ = reply.pid;
+
+  return true;
+}
+
+HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name,
+                                            DWORD pipe_access,
+                                            DWORD flags_attrs) {
+  for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
+    HANDLE pipe = CreateFile(pipe_name,
+                             pipe_access,
+                             0,
+                             NULL,
+                             OPEN_EXISTING,
+                             flags_attrs,
+                             NULL);
+    if (pipe != INVALID_HANDLE_VALUE) {
+      return pipe;
+    }
+
+    // Cannot continue retrying if error is something other than
+    // ERROR_PIPE_BUSY.
+    if (GetLastError() != ERROR_PIPE_BUSY) {
+      break;
+    }
+
+    // Cannot continue retrying if wait on pipe fails.
+    if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {
+      break;
+    }
+  }
+
+  return NULL;
+}
+
+bool CrashGenerationClient::ValidateResponse(
+    const ProtocolMessage& msg) const {
+  return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) &&
+         (msg.pid != 0) &&
+         (msg.dump_request_handle != NULL) &&
+         (msg.dump_generated_handle != NULL) &&
+         (msg.server_alive_handle != NULL);
+}
+
+bool CrashGenerationClient::IsRegistered() const {
+  return crash_event_ != NULL;
+}
+
+bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
+  if (!IsRegistered()) {
+    return false;
+  }
+
+  exception_pointers_ = ex_info;
+  thread_id_ = GetCurrentThreadId();
+
+  assert_info_.line = 0;
+  assert_info_.type = 0;
+  assert_info_.expression[0] = 0;
+  assert_info_.file[0] = 0;
+  assert_info_.function[0] = 0;
+
+  return SignalCrashEventAndWait();
+}
+
+bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {
+  if (!IsRegistered()) {
+    return false;
+  }
+
+  exception_pointers_ = NULL;
+
+  if (assert_info) {
+    memcpy(&assert_info_, assert_info, sizeof(assert_info_));
+  } else {
+    memset(&assert_info_, 0, sizeof(assert_info_));
+  }
+
+  thread_id_ = GetCurrentThreadId();
+
+  return SignalCrashEventAndWait();
+}
+
+bool CrashGenerationClient::SignalCrashEventAndWait() {
+  assert(crash_event_);
+  assert(crash_generated_);
+  assert(server_alive_);
+
+  // Reset the dump generated event before signaling the crash
+  // event so that the server can set the dump generated event
+  // once it is done generating the event.
+  if (!ResetEvent(crash_generated_)) {
+    return false;
+  }
+
+  if (!SetEvent(crash_event_)) {
+    return false;
+  }
+
+  HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_};
+
+  DWORD result = WaitForMultipleObjects(kWaitEventCount,
+                                        wait_handles,
+                                        FALSE,
+                                        kWaitForServerTimeoutMs);
+
+  // Crash dump was successfully generated only if the server
+  // signaled the crash generated event.
+  return result == WAIT_OBJECT_0;
+}
+
+}  // namespace google_breakpad
diff --git a/third_party/breakpad/src/client/windows/crash_generation/crash_generation_client.h b/third_party/breakpad/src/client/windows/crash_generation/crash_generation_client.h
index efb27ac..81b0e6c 100644
--- a/third_party/breakpad/src/client/windows/crash_generation/crash_generation_client.h
+++ b/third_party/breakpad/src/client/windows/crash_generation/crash_generation_client.h
@@ -1,159 +1,159 @@
-// Copyright (c) 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__

-#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__

-

-#include <windows.h>

-#include <dbghelp.h>

-#include <string>

-#include <utility>

-#include "client/windows/common/ipc_protocol.h"

-#include "processor/scoped_ptr.h"

-

-namespace google_breakpad {

-

-struct CustomClientInfo;

-

-// Abstraction of client-side implementation of out of process

-// crash generation.

-//

-// The process that desires to have out-of-process crash dump

-// generation service can use this class in the following way:

-//

-// * Create an instance.

-// * Call Register method so that the client tries to register

-//   with the server process and check the return value. If

-//   registration is not successful, out-of-process crash dump

-//   generation will not be available

-// * Request dump generation by calling either of the two

-//   overloaded RequestDump methods - one in case of exceptions

-//   and the other in case of assertion failures

-//

-// Note that it is the responsibility of the client code of

-// this class to set the unhandled exception filter with the

-// system by calling the SetUnhandledExceptionFilter function

-// and the client code should explicitly request dump generation.

-class CrashGenerationClient {

- public:

-  CrashGenerationClient(const wchar_t* pipe_name,

-                        MINIDUMP_TYPE dump_type,

-                        const CustomClientInfo* custom_info);

-

-  ~CrashGenerationClient();

-

-  // Registers the client process with the crash server.

-  //

-  // Returns true if the registration is successful; false otherwise.

-  bool Register();

-

-  // Requests the crash server to generate a dump with the given

-  // exception information.

-  //

-  // Returns true if the dump was successful; false otherwise. Note that

-  // if the registration step was not performed or it was not successful,

-  // false will be returned.

-  bool RequestDump(EXCEPTION_POINTERS* ex_info);

-

-  // Requests the crash server to generate a dump with the given

-  // assertion information.

-  //

-  // Returns true if the dump was successful; false otherwise. Note that

-  // if the registration step was not performed or it was not successful,

-  // false will be returned.

-  bool RequestDump(MDRawAssertionInfo* assert_info);

-

- private:

-  // Connects to the appropriate pipe and sets the pipe handle state.

-  //

-  // Returns the pipe handle if everything goes well; otherwise Returns NULL.

-  HANDLE ConnectToServer();

-

-  // Performs a handshake with the server over the given pipe which should be

-  // already connected to the server.

-  //

-  // Returns true if handshake with the server was successful; false otherwise.

-  bool RegisterClient(HANDLE pipe);

-

-  // Validates the given server response.

-  bool ValidateResponse(const ProtocolMessage& msg) const;

-

-  // Returns true if the registration step succeeded; false otherwise.

-  bool IsRegistered() const;

-

-  // Connects to the given named pipe with given parameters.

-  //

-  // Returns true if the connection is successful; false otherwise.

-  HANDLE ConnectToPipe(const wchar_t* pipe_name,

-                       DWORD pipe_access,

-                       DWORD flags_attrs);

-

-  // Signals the crash event and wait for the server to generate crash.

-  bool SignalCrashEventAndWait();

-

-  // Pipe name to use to talk to server.

-  std::wstring pipe_name_;

-

-  // Custom client information

-  CustomClientInfo custom_info_;

-

-  // Type of dump to generate.

-  MINIDUMP_TYPE dump_type_;

-

-  // Event to signal in case of a crash.

-  HANDLE crash_event_;

-

-  // Handle to wait on after signaling a crash for the server

-  // to finish generating crash dump.

-  HANDLE crash_generated_;

-

-  // Handle to a mutex that will become signaled with WAIT_ABANDONED

-  // if the server process goes down.

-  HANDLE server_alive_;

-

-  // Server process id.

-  DWORD server_process_id_;

-

-  // Id of the thread that caused the crash.

-  DWORD thread_id_;

-

-  // Exception pointers for an exception crash.

-  EXCEPTION_POINTERS* exception_pointers_;

-

-  // Assertion info for an invalid parameter or pure call crash.

-  MDRawAssertionInfo assert_info_;

-

-  // Disable copy ctor and operator=.

-  CrashGenerationClient(const CrashGenerationClient& crash_client);

-  CrashGenerationClient& operator=(const CrashGenerationClient& crash_client);

-};

-

-}  // namespace google_breakpad

-

-#endif  // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__

+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
+#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
+
+#include <windows.h>
+#include <dbghelp.h>
+#include <string>
+#include <utility>
+#include "client/windows/common/ipc_protocol.h"
+#include "processor/scoped_ptr.h"
+
+namespace google_breakpad {
+
+struct CustomClientInfo;
+
+// Abstraction of client-side implementation of out of process
+// crash generation.
+//
+// The process that desires to have out-of-process crash dump
+// generation service can use this class in the following way:
+//
+// * Create an instance.
+// * Call Register method so that the client tries to register
+//   with the server process and check the return value. If
+//   registration is not successful, out-of-process crash dump
+//   generation will not be available
+// * Request dump generation by calling either of the two
+//   overloaded RequestDump methods - one in case of exceptions
+//   and the other in case of assertion failures
+//
+// Note that it is the responsibility of the client code of
+// this class to set the unhandled exception filter with the
+// system by calling the SetUnhandledExceptionFilter function
+// and the client code should explicitly request dump generation.
+class CrashGenerationClient {
+ public:
+  CrashGenerationClient(const wchar_t* pipe_name,
+                        MINIDUMP_TYPE dump_type,
+                        const CustomClientInfo* custom_info);
+
+  ~CrashGenerationClient();
+
+  // Registers the client process with the crash server.
+  //
+  // Returns true if the registration is successful; false otherwise.
+  bool Register();
+
+  // Requests the crash server to generate a dump with the given
+  // exception information.
+  //
+  // Returns true if the dump was successful; false otherwise. Note that
+  // if the registration step was not performed or it was not successful,
+  // false will be returned.
+  bool RequestDump(EXCEPTION_POINTERS* ex_info);
+
+  // Requests the crash server to generate a dump with the given
+  // assertion information.
+  //
+  // Returns true if the dump was successful; false otherwise. Note that
+  // if the registration step was not performed or it was not successful,
+  // false will be returned.
+  bool RequestDump(MDRawAssertionInfo* assert_info);
+
+ private:
+  // Connects to the appropriate pipe and sets the pipe handle state.
+  //
+  // Returns the pipe handle if everything goes well; otherwise Returns NULL.
+  HANDLE ConnectToServer();
+
+  // Performs a handshake with the server over the given pipe which should be
+  // already connected to the server.
+  //
+  // Returns true if handshake with the server was successful; false otherwise.
+  bool RegisterClient(HANDLE pipe);
+
+  // Validates the given server response.
+  bool ValidateResponse(const ProtocolMessage& msg) const;
+
+  // Returns true if the registration step succeeded; false otherwise.
+  bool IsRegistered() const;
+
+  // Connects to the given named pipe with given parameters.
+  //
+  // Returns true if the connection is successful; false otherwise.
+  HANDLE ConnectToPipe(const wchar_t* pipe_name,
+                       DWORD pipe_access,
+                       DWORD flags_attrs);
+
+  // Signals the crash event and wait for the server to generate crash.
+  bool SignalCrashEventAndWait();
+
+  // Pipe name to use to talk to server.
+  std::wstring pipe_name_;
+
+  // Custom client information
+  CustomClientInfo custom_info_;
+
+  // Type of dump to generate.
+  MINIDUMP_TYPE dump_type_;
+
+  // Event to signal in case of a crash.
+  HANDLE crash_event_;
+
+  // Handle to wait on after signaling a crash for the server
+  // to finish generating crash dump.
+  HANDLE crash_generated_;
+
+  // Handle to a mutex that will become signaled with WAIT_ABANDONED
+  // if the server process goes down.
+  HANDLE server_alive_;
+
+  // Server process id.
+  DWORD server_process_id_;
+
+  // Id of the thread that caused the crash.
+  DWORD thread_id_;
+
+  // Exception pointers for an exception crash.
+  EXCEPTION_POINTERS* exception_pointers_;
+
+  // Assertion info for an invalid parameter or pure call crash.
+  MDRawAssertionInfo assert_info_;
+
+  // Disable copy ctor and operator=.
+  CrashGenerationClient(const CrashGenerationClient& crash_client);
+  CrashGenerationClient& operator=(const CrashGenerationClient& crash_client);
+};
+
+}  // namespace google_breakpad
+
+#endif  // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H__
diff --git a/third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.cc b/third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.cc
index 8441dd0..ac76e59 100644
--- a/third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.cc
+++ b/third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.cc
@@ -1,852 +1,852 @@
-// Copyright (c) 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#include "client/windows/crash_generation/crash_generation_server.h"

-#include <windows.h>

-#include <cassert>

-#include <list>

-#include "client/windows/common/auto_critical_section.h"

-#include "processor/scoped_ptr.h"

-

-namespace google_breakpad {

-

-// Output buffer size.

-static const size_t kOutBufferSize = 64;

-

-// Input buffer size.

-static const size_t kInBufferSize = 64;

-

-// Access flags for the client on the dump request event.

-static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE;

-

-// Access flags for the client on the dump generated event.

-static const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE |

-                                               SYNCHRONIZE;

-

-// Access flags for the client on the mutex.

-static const DWORD kMutexAccess = SYNCHRONIZE;

-

-// Attribute flags for the pipe.

-static const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE |

-                               PIPE_ACCESS_DUPLEX |

-                               FILE_FLAG_OVERLAPPED;

-

-// Mode for the pipe.

-static const DWORD kPipeMode = PIPE_TYPE_MESSAGE |

-                               PIPE_READMODE_MESSAGE |

-                               PIPE_WAIT;

-

-// For pipe I/O, execute the callback in the wait thread itself,

-// since the callback does very little work. The callback executes

-// the code for one of the states of the server state machine and

-// the code for all of the states perform async I/O and hence

-// finish very quickly.

-static const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD;

-

-// Dump request threads will, most likely, generate dumps. That may

-// take some time to finish, so specify WT_EXECUTELONGFUNCTION flag.

-static const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD |

-                                             WT_EXECUTELONGFUNCTION;

-

-// Maximum delay during server shutdown if some work items

-// are still executing.

-static const int kShutdownDelayMs = 10000;

-

-// Interval for each sleep during server shutdown.

-static const int kShutdownSleepIntervalMs = 5;

-

-static bool IsClientRequestValid(const ProtocolMessage& msg) {

-  return msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&

-         msg.pid != 0 &&

-         msg.thread_id != NULL &&

-         msg.exception_pointers != NULL &&

-         msg.assert_info != NULL;

-}

-

-CrashGenerationServer::CrashGenerationServer(

-    const std::wstring& pipe_name,

-    SECURITY_ATTRIBUTES* pipe_sec_attrs,

-    OnClientConnectedCallback connect_callback,

-    void* connect_context,

-    OnClientDumpRequestCallback dump_callback,

-    void* dump_context,

-    OnClientExitedCallback exit_callback,

-    void* exit_context,

-    bool generate_dumps,

-    const std::wstring* dump_path)

-    : pipe_name_(pipe_name),

-      pipe_sec_attrs_(pipe_sec_attrs),

-      pipe_(NULL),

-      pipe_wait_handle_(NULL),

-      server_alive_handle_(NULL),

-      connect_callback_(connect_callback),

-      connect_context_(connect_context),

-      dump_callback_(dump_callback),

-      dump_context_(dump_context),

-      exit_callback_(exit_callback),

-      exit_context_(exit_context),

-      generate_dumps_(generate_dumps),

-      dump_generator_(NULL),

-      server_state_(IPC_SERVER_STATE_INITIAL),

-      shutting_down_(false),

-      overlapped_(),

-      client_info_(NULL),

-      cleanup_item_count_(0) {

-  InitializeCriticalSection(&clients_sync_);

-

-  if (dump_path) {

-    dump_generator_.reset(new MinidumpGenerator(*dump_path));

-  }

-}

-

-CrashGenerationServer::~CrashGenerationServer() {

-  // Indicate to existing threads that server is shutting down.

-  shutting_down_ = true;

-

-  // Even if there are no current worker threads running, it is possible that

-  // an I/O request is pending on the pipe right now but not yet done. In fact,

-  // it's very likely this is the case unless we are in an ERROR state. If we

-  // don't wait for the pending I/O to be done, then when the I/O completes,

-  // it may write to invalid memory. AppVerifier will flag this problem too.

-  // So we disconnect from the pipe and then wait for the server to get into

-  // error state so that the pending I/O will fail and get cleared.

-  DisconnectNamedPipe(pipe_);

-  int num_tries = 100;

-  while (num_tries-- && server_state_ != IPC_SERVER_STATE_ERROR) {

-    Sleep(10);

-  }

-

-  // Unregister wait on the pipe.

-  if (pipe_wait_handle_) {

-    // Wait for already executing callbacks to finish.

-    UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);

-  }

-

-  // Close the pipe to avoid further client connections.

-  if (pipe_) {

-    CloseHandle(pipe_);

-  }

-

-  // Request all ClientInfo objects to unregister all waits.

-  // New scope to hold the lock for the shortest time.

-  {

-    AutoCriticalSection lock(&clients_sync_);

-

-    std::list<ClientInfo*>::iterator iter;

-    for (iter = clients_.begin(); iter != clients_.end(); ++iter) {

-      ClientInfo* client_info = *iter;

-      client_info->UnregisterWaits();

-    }

-  }

-

-  // Now that all waits have been unregistered, wait for some time

-  // for all pending work items to finish.

-  int total_wait = 0;

-  while (cleanup_item_count_ > 0) {

-    Sleep(kShutdownSleepIntervalMs);

-

-    total_wait += kShutdownSleepIntervalMs;

-

-    if (total_wait >= kShutdownDelayMs) {

-      break;

-    }

-  }

-

-  // Clean up all the ClientInfo objects.

-  // New scope to hold the lock for the shortest time.

-  {

-    AutoCriticalSection lock(&clients_sync_);

-

-    std::list<ClientInfo*>::iterator iter;

-    for (iter = clients_.begin(); iter != clients_.end(); ++iter) {

-      ClientInfo* client_info = *iter;

-      delete client_info;

-    }

-  }

-

-  if (server_alive_handle_) {

-    // Release the mutex before closing the handle so that clients requesting

-    // dumps wait for a long time for the server to generate a dump.

-    ReleaseMutex(server_alive_handle_);

-    CloseHandle(server_alive_handle_);

-  }

-

-  DeleteCriticalSection(&clients_sync_);

-}

-

-bool CrashGenerationServer::Start() {

-  server_state_ = IPC_SERVER_STATE_INITIAL;

-

-  server_alive_handle_ = CreateMutex(NULL, TRUE, NULL);

-  if (!server_alive_handle_) {

-    return false;

-  }

-

-  // Event to signal the client connection and pipe reads and writes.

-  overlapped_.hEvent = CreateEvent(NULL,   // Security descriptor.

-                                   TRUE,   // Manual reset.

-                                   FALSE,  // Initially signaled.

-                                   NULL);  // Name.

-  if (!overlapped_.hEvent) {

-    return false;

-  }

-

-  // Register a callback with the thread pool for the client connection.

-  RegisterWaitForSingleObject(&pipe_wait_handle_,

-                              overlapped_.hEvent,

-                              OnPipeConnected,

-                              this,

-                              INFINITE,

-                              kPipeIOThreadFlags);

-

-  pipe_ = CreateNamedPipe(pipe_name_.c_str(),

-                          kPipeAttr,

-                          kPipeMode,

-                          1,

-                          kOutBufferSize,

-                          kInBufferSize,

-                          0,

-                          pipe_sec_attrs_);

-  if (pipe_ == INVALID_HANDLE_VALUE) {

-    return false;

-  }

-

-  // Signal the event to start a separate thread to handle

-  // client connections.

-  return SetEvent(overlapped_.hEvent) != FALSE;

-}

-

-// If the server thread serving clients ever gets into the

-// ERROR state, reset the event, close the pipe and remain

-// in the error state forever. Error state means something

-// that we didn't account for has happened, and it's dangerous

-// to do anything unknowingly.

-void CrashGenerationServer::HandleErrorState() {

-  assert(server_state_ == IPC_SERVER_STATE_ERROR);

-

-  // If the server is shutting down anyway, don't clean up

-  // here since shut down process will clean up.

-  if (shutting_down_) {

-    return;

-  }

-

-  if (pipe_wait_handle_) {

-    UnregisterWait(pipe_wait_handle_);

-    pipe_wait_handle_ = NULL;

-  }

-

-  if (pipe_) {

-    CloseHandle(pipe_);

-    pipe_ = NULL;

-  }

-

-  if (overlapped_.hEvent) {

-    CloseHandle(overlapped_.hEvent);

-    overlapped_.hEvent = NULL;

-  }

-}

-

-// When the server thread serving clients is in the INITIAL state,

-// try to connect to the pipe asynchronously. If the connection

-// finishes synchronously, directly go into the CONNECTED state;

-// otherwise go into the CONNECTING state. For any problems, go

-// into the ERROR state.

-void CrashGenerationServer::HandleInitialState() {

-  assert(server_state_ == IPC_SERVER_STATE_INITIAL);

-

-  if (!ResetEvent(overlapped_.hEvent)) {

-    server_state_ = IPC_SERVER_STATE_ERROR;

-    return;

-  }

-

-  bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE;

-

-  // From MSDN, it is not clear that when ConnectNamedPipe is used

-  // in an overlapped mode, will it ever return non-zero value, and

-  // if so, in what cases.

-  assert(!success);

-

-  DWORD error_code = GetLastError();

-  switch (error_code) {

-    case ERROR_IO_PENDING:

-      server_state_ = IPC_SERVER_STATE_CONNECTING;

-      break;

-

-    case ERROR_PIPE_CONNECTED:

-      if (SetEvent(overlapped_.hEvent)) {

-        server_state_ = IPC_SERVER_STATE_CONNECTED;

-      } else {

-        server_state_ = IPC_SERVER_STATE_ERROR;

-      }

-      break;

-

-    default:

-      server_state_ = IPC_SERVER_STATE_ERROR;

-      break;

-  }

-}

-

-// When the server thread serving the clients is in the CONNECTING state,

-// try to get the result of the asynchronous connection request using

-// the OVERLAPPED object. If the result indicates the connection is done,

-// go into the CONNECTED state. If the result indicates I/O is still

-// INCOMPLETE, remain in the CONNECTING state. For any problems,

-// go into the DISCONNECTING state.

-void CrashGenerationServer::HandleConnectingState() {

-  assert(server_state_ == IPC_SERVER_STATE_CONNECTING);

-

-  DWORD bytes_count = 0;

-  bool success = GetOverlappedResult(pipe_,

-                                     &overlapped_,

-                                     &bytes_count,

-                                     FALSE) != FALSE;

-

-  if (success) {

-    server_state_ = IPC_SERVER_STATE_CONNECTED;

-    return;

-  }

-

-  if (GetLastError() != ERROR_IO_INCOMPLETE) {

-    server_state_ = IPC_SERVER_STATE_DISCONNECTING;

-  }

-}

-

-// When the server thread serving the clients is in the CONNECTED state,

-// try to issue an asynchronous read from the pipe. If read completes

-// synchronously or if I/O is pending then go into the READING state.

-// For any problems, go into the DISCONNECTING state.

-void CrashGenerationServer::HandleConnectedState() {

-  assert(server_state_ == IPC_SERVER_STATE_CONNECTED);

-

-  DWORD bytes_count = 0;

-  memset(&msg_, 0, sizeof(msg_));

-  bool success = ReadFile(pipe_,

-                          &msg_,

-                          sizeof(msg_),

-                          &bytes_count,

-                          &overlapped_) != FALSE;

-

-  // Note that the asynchronous read issued above can finish before the

-  // code below executes. But, it is okay to change state after issuing

-  // the asynchronous read. This is because even if the asynchronous read

-  // is done, the callback for it would not be executed until the current

-  // thread finishes its execution.

-  if (success || GetLastError() == ERROR_IO_PENDING) {

-    server_state_ = IPC_SERVER_STATE_READING;

-  } else {

-    server_state_ = IPC_SERVER_STATE_DISCONNECTING;

-  }

-}

-

-// When the server thread serving the clients is in the READING state,

-// try to get the result of the async read. If async read is done,

-// go into the READ_DONE state. For any problems, go into the

-// DISCONNECTING state.

-void CrashGenerationServer::HandleReadingState() {

-  assert(server_state_ == IPC_SERVER_STATE_READING);

-

-  DWORD bytes_count = 0;

-  bool success = GetOverlappedResult(pipe_,

-                                     &overlapped_,

-                                     &bytes_count,

-                                     FALSE) != FALSE;

-

-  if (success && bytes_count == sizeof(ProtocolMessage)) {

-    server_state_ = IPC_SERVER_STATE_READ_DONE;

-    return;

-  }

-

-  DWORD error_code;

-  error_code = GetLastError();

-

-  // We should never get an I/O incomplete since we should not execute this

-  // unless the Read has finished and the overlapped event is signaled. If

-  // we do get INCOMPLETE, we have a bug in our code.

-  assert(error_code != ERROR_IO_INCOMPLETE);

-

-  server_state_ = IPC_SERVER_STATE_DISCONNECTING;

-}

-

-// When the server thread serving the client is in the READ_DONE state,

-// validate the client's request message, register the client by

-// creating appropriate objects and prepare the response.  Then try to

-// write the response to the pipe asynchronously. If that succeeds,

-// go into the WRITING state. For any problems, go into the DISCONNECTING

-// state.

-void CrashGenerationServer::HandleReadDoneState() {

-  assert(server_state_ == IPC_SERVER_STATE_READ_DONE);

-

-  if (!IsClientRequestValid(msg_)) {

-    server_state_ = IPC_SERVER_STATE_DISCONNECTING;

-    return;

-  }

-

-  scoped_ptr<ClientInfo> client_info(

-      new ClientInfo(this,

-                     msg_.pid,

-                     msg_.dump_type,

-                     msg_.thread_id,

-                     msg_.exception_pointers,

-                     msg_.assert_info,

-                     msg_.custom_client_info));

-

-  if (!client_info->Initialize()) {

-    server_state_ = IPC_SERVER_STATE_DISCONNECTING;

-    return;

-  }

-

-  if (!RespondToClient(client_info.get())) {

-    server_state_ = IPC_SERVER_STATE_DISCONNECTING;

-    return;

-  }

-

-  // Note that the asynchronous write issued by RespondToClient function

-  // can finish before  the code below executes. But it is okay to change

-  // state after issuing the asynchronous write. This is because even if

-  // the asynchronous write is done, the callback for it would not be

-  // executed until the current thread finishes its execution.

-  server_state_ = IPC_SERVER_STATE_WRITING;

-  client_info_ = client_info.release();

-}

-

-// When the server thread serving the clients is in the WRITING state,

-// try to get the result of the async write. If the async write is done,

-// go into the WRITE_DONE state. For any problems, go into the

-// DISONNECTING state.

-void CrashGenerationServer::HandleWritingState() {

-  assert(server_state_ == IPC_SERVER_STATE_WRITING);

-

-  DWORD bytes_count = 0;

-  bool success = GetOverlappedResult(pipe_,

-                                     &overlapped_,

-                                     &bytes_count,

-                                     FALSE) != FALSE;

-

-  if (success) {

-    server_state_ = IPC_SERVER_STATE_WRITE_DONE;

-    return;

-  }

-

-  DWORD error_code;

-  error_code = GetLastError();

-

-  // We should never get an I/O incomplete since we should not execute this

-  // unless the Write has finished and the overlapped event is signaled. If

-  // we do get INCOMPLETE, we have a bug in our code.

-  assert(error_code != ERROR_IO_INCOMPLETE);

-

-  server_state_ = IPC_SERVER_STATE_DISCONNECTING;

-}

-

-// When the server thread serving the clients is in the WRITE_DONE state,

-// try to issue an async read on the pipe. If the read completes synchronously

-// or if I/O is still pending then go into the READING_ACK state. For any

-// issues, go into the DISCONNECTING state.

-void CrashGenerationServer::HandleWriteDoneState() {

-  assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE);

-

-  server_state_ = IPC_SERVER_STATE_READING_ACK;

-

-  DWORD bytes_count = 0;

-  bool success = ReadFile(pipe_,

-                          &msg_,

-                          sizeof(msg_),

-                          &bytes_count,

-                          &overlapped_) != FALSE;

-

-  if (success) {

-    return;

-  }

-

-  DWORD error_code = GetLastError();

-

-  if (error_code != ERROR_IO_PENDING) {

-    server_state_ = IPC_SERVER_STATE_DISCONNECTING;

-  }

-}

-

-// When the server thread serving the clients is in the READING_ACK state,

-// try to get result of async read. Go into the DISCONNECTING state.

-void CrashGenerationServer::HandleReadingAckState() {

-  assert(server_state_ == IPC_SERVER_STATE_READING_ACK);

-

-  DWORD bytes_count = 0;

-  bool success = GetOverlappedResult(pipe_,

-                                     &overlapped_,

-                                     &bytes_count,

-                                     FALSE) != FALSE;

-

-  if (success) {

-    // The connection handshake with the client is now complete; perform

-    // the callback.

-    if (connect_callback_) {

-      connect_callback_(connect_context_, client_info_);

-    }

-  } else {

-    DWORD error_code = GetLastError();

-

-    // We should never get an I/O incomplete since we should not execute this

-    // unless the Read has finished and the overlapped event is signaled. If

-    // we do get INCOMPLETE, we have a bug in our code.

-    assert(error_code != ERROR_IO_INCOMPLETE);

-  }

-

-  server_state_ = IPC_SERVER_STATE_DISCONNECTING;

-}

-

-// When the server thread serving the client is in the DISCONNECTING state,

-// disconnect from the pipe and reset the event. If anything fails, go into

-// the ERROR state. If it goes well, go into the INITIAL state and set the

-// event to start all over again.

-void CrashGenerationServer::HandleDisconnectingState() {

-  assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING);

-

-  // Done serving the client.

-  client_info_ = NULL;

-

-  overlapped_.Internal = NULL;

-  overlapped_.InternalHigh = NULL;

-  overlapped_.Offset = 0;

-  overlapped_.OffsetHigh = 0;

-  overlapped_.Pointer = NULL;

-

-  if (!ResetEvent(overlapped_.hEvent)) {

-    server_state_ = IPC_SERVER_STATE_ERROR;

-    return;

-  }

-

-  if (!DisconnectNamedPipe(pipe_)) {

-    server_state_ = IPC_SERVER_STATE_ERROR;

-    return;

-  }

-

-  // If the server is shutting down do not connect to the

-  // next client.

-  if (shutting_down_) {

-    return;

-  }

-

-  server_state_ = IPC_SERVER_STATE_INITIAL;

-  if (!SetEvent(overlapped_.hEvent)) {

-    server_state_ = IPC_SERVER_STATE_ERROR;

-  }

-}

-

-bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,

-                                         ProtocolMessage* reply) const {

-  reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;

-  reply->pid = GetCurrentProcessId();

-

-  if (CreateClientHandles(client_info, reply)) {

-    return true;

-  }

-

-  if (reply->dump_request_handle) {

-    CloseHandle(reply->dump_request_handle);

-  }

-

-  if (reply->dump_generated_handle) {

-    CloseHandle(reply->dump_generated_handle);

-  }

-

-  if (reply->server_alive_handle) {

-    CloseHandle(reply->server_alive_handle);

-  }

-

-  return false;

-}

-

-bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info,

-                                                ProtocolMessage* reply) const {

-  HANDLE current_process = GetCurrentProcess();

-  if (!DuplicateHandle(current_process,

-                       client_info.dump_requested_handle(),

-                       client_info.process_handle(),

-                       &reply->dump_request_handle,

-                       kDumpRequestEventAccess,

-                       FALSE,

-                       0)) {

-    return false;

-  }

-

-  if (!DuplicateHandle(current_process,

-                       client_info.dump_generated_handle(),

-                       client_info.process_handle(),

-                       &reply->dump_generated_handle,

-                       kDumpGeneratedEventAccess,

-                       FALSE,

-                       0)) {

-    return false;

-  }

-

-  if (!DuplicateHandle(current_process,

-                       server_alive_handle_,

-                       client_info.process_handle(),

-                       &reply->server_alive_handle,

-                       kMutexAccess,

-                       FALSE,

-                       0)) {

-    return false;

-  }

-

-  return true;

-}

-

-bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {

-  ProtocolMessage reply;

-  if (!PrepareReply(*client_info, &reply)) {

-    return false;

-  }

-

-  if (!AddClient(client_info)) {

-    return false;

-  }

-

-  DWORD bytes_count = 0;

-  bool success = WriteFile(pipe_,

-                           &reply,

-                           sizeof(reply),

-                           &bytes_count,

-                           &overlapped_) != FALSE;

-

-  return success || GetLastError() == ERROR_IO_PENDING;

-}

-

-// The server thread servicing the clients runs this method. The method

-// implements the state machine described in ReadMe.txt along with the

-// helper methods HandleXXXState.

-void CrashGenerationServer::HandleConnectionRequest() {

-  // If we are shutting doen then get into ERROR state, reset the event so more

-  // workers don't run and return immediately.

-  if (shutting_down_) {

-    server_state_ = IPC_SERVER_STATE_ERROR;

-    ResetEvent(overlapped_.hEvent);

-    return;

-  }

-

-  switch (server_state_) {

-    case IPC_SERVER_STATE_ERROR:

-      HandleErrorState();

-      break;

-

-    case IPC_SERVER_STATE_INITIAL:

-      HandleInitialState();

-      break;

-

-    case IPC_SERVER_STATE_CONNECTING:

-      HandleConnectingState();

-      break;

-

-    case IPC_SERVER_STATE_CONNECTED:

-      HandleConnectedState();

-      break;

-

-    case IPC_SERVER_STATE_READING:

-      HandleReadingState();

-      break;

-

-    case IPC_SERVER_STATE_READ_DONE:

-      HandleReadDoneState();

-      break;

-

-    case IPC_SERVER_STATE_WRITING:

-      HandleWritingState();

-      break;

-

-    case IPC_SERVER_STATE_WRITE_DONE:

-      HandleWriteDoneState();

-      break;

-

-    case IPC_SERVER_STATE_READING_ACK:

-      HandleReadingAckState();

-      break;

-

-    case IPC_SERVER_STATE_DISCONNECTING:

-      HandleDisconnectingState();

-      break;

-

-    default:

-      assert(false);

-      // This indicates that we added one more state without

-      // adding handling code.

-      server_state_ = IPC_SERVER_STATE_ERROR;

-      break;

-  }

-}

-

-bool CrashGenerationServer::AddClient(ClientInfo* client_info) {

-  HANDLE request_wait_handle = NULL;

-  if (!RegisterWaitForSingleObject(&request_wait_handle,

-                                   client_info->dump_requested_handle(),

-                                   OnDumpRequest,

-                                   client_info,

-                                   INFINITE,

-                                   kDumpRequestThreadFlags)) {

-    return false;

-  }

-

-  client_info->set_dump_request_wait_handle(request_wait_handle);

-

-  // OnClientEnd will be called when the client process terminates.

-  HANDLE process_wait_handle = NULL;

-  if (!RegisterWaitForSingleObject(&process_wait_handle,

-                                   client_info->process_handle(),

-                                   OnClientEnd,

-                                   client_info,

-                                   INFINITE,

-                                   WT_EXECUTEONLYONCE)) {

-    return false;

-  }

-

-  client_info->set_process_exit_wait_handle(process_wait_handle);

-

-  // New scope to hold the lock for the shortest time.

-  {

-    AutoCriticalSection lock(&clients_sync_);

-    clients_.push_back(client_info);

-  }

-

-  return true;

-}

-

-// static

-void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) {

-  assert (context);

-

-  CrashGenerationServer* obj =

-      reinterpret_cast<CrashGenerationServer*>(context);

-  obj->HandleConnectionRequest();

-}

-

-// static

-void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {

-  assert(context);

-  ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);

-  client_info->PopulateCustomInfo();

-

-  CrashGenerationServer* crash_server = client_info->crash_server();

-  assert(crash_server);

-  crash_server->HandleDumpRequest(*client_info);

-

-  ResetEvent(client_info->dump_requested_handle());

-}

-

-// static

-void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) {

-  assert(context);

-  ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);

-

-  CrashGenerationServer* crash_server = client_info->crash_server();

-  assert(crash_server);

-

-  InterlockedIncrement(&crash_server->cleanup_item_count_);

-

-  if (!QueueUserWorkItem(CleanupClient, context, WT_EXECUTEDEFAULT)) {

-    InterlockedDecrement(&crash_server->cleanup_item_count_);

-  }

-}

-

-// static

-DWORD WINAPI CrashGenerationServer::CleanupClient(void* context) {

-  assert(context);

-  ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);

-

-  CrashGenerationServer* crash_server = client_info->crash_server();

-  assert(crash_server);

-

-  if (crash_server->exit_callback_) {

-    crash_server->exit_callback_(crash_server->exit_context_, client_info);

-  }

-

-  crash_server->DoCleanup(client_info);

-

-  InterlockedDecrement(&crash_server->cleanup_item_count_);

-  return 0;

-}

-

-void CrashGenerationServer::DoCleanup(ClientInfo* client_info) {

-  assert(client_info);

-

-  // Start a new scope to release lock automatically.

-  {

-    AutoCriticalSection lock(&clients_sync_);

-    clients_.remove(client_info);

-  }

-

-  delete client_info;

-}

-

-void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) {

-  // Generate the dump only if it's explicitly requested by the

-  // server application; otherwise the server might want to generate

-  // dump in the callback.

-  std::wstring dump_path;

-  if (generate_dumps_) {

-    if (!GenerateDump(client_info, &dump_path)) {

-      return;

-    }

-  }

-

-  if (dump_callback_) {

-    std::wstring* ptr_dump_path = (dump_path == L"") ? NULL : &dump_path;

-    dump_callback_(dump_context_, &client_info, ptr_dump_path);

-  }

-

-  SetEvent(client_info.dump_generated_handle());

-}

-

-bool CrashGenerationServer::GenerateDump(const ClientInfo& client,

-                                         std::wstring* dump_path) {

-  assert(client.pid() != 0);

-  assert(client.process_handle());

-

-  // We have to get the address of EXCEPTION_INFORMATION from

-  // the client process address space.

-  EXCEPTION_POINTERS* client_ex_info = NULL;

-  if (!client.GetClientExceptionInfo(&client_ex_info)) {

-    return false;

-  }

-

-  DWORD client_thread_id = 0;

-  if (!client.GetClientThreadId(&client_thread_id)) {

-    return false;

-  }

-

-  return dump_generator_->WriteMinidump(client.process_handle(),

-                                        client.pid(),

-                                        client_thread_id,

-                                        GetCurrentThreadId(),

-                                        client_ex_info,

-                                        client.assert_info(),

-                                        client.dump_type(),

-                                        true,

-                                        dump_path);

-}

-

-}  // namespace google_breakpad

+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/crash_generation_server.h"
+#include <windows.h>
+#include <cassert>
+#include <list>
+#include "client/windows/common/auto_critical_section.h"
+#include "processor/scoped_ptr.h"
+
+namespace google_breakpad {
+
+// Output buffer size.
+static const size_t kOutBufferSize = 64;
+
+// Input buffer size.
+static const size_t kInBufferSize = 64;
+
+// Access flags for the client on the dump request event.
+static const DWORD kDumpRequestEventAccess = EVENT_MODIFY_STATE;
+
+// Access flags for the client on the dump generated event.
+static const DWORD kDumpGeneratedEventAccess = EVENT_MODIFY_STATE |
+                                               SYNCHRONIZE;
+
+// Access flags for the client on the mutex.
+static const DWORD kMutexAccess = SYNCHRONIZE;
+
+// Attribute flags for the pipe.
+static const DWORD kPipeAttr = FILE_FLAG_FIRST_PIPE_INSTANCE |
+                               PIPE_ACCESS_DUPLEX |
+                               FILE_FLAG_OVERLAPPED;
+
+// Mode for the pipe.
+static const DWORD kPipeMode = PIPE_TYPE_MESSAGE |
+                               PIPE_READMODE_MESSAGE |
+                               PIPE_WAIT;
+
+// For pipe I/O, execute the callback in the wait thread itself,
+// since the callback does very little work. The callback executes
+// the code for one of the states of the server state machine and
+// the code for all of the states perform async I/O and hence
+// finish very quickly.
+static const ULONG kPipeIOThreadFlags = WT_EXECUTEINWAITTHREAD;
+
+// Dump request threads will, most likely, generate dumps. That may
+// take some time to finish, so specify WT_EXECUTELONGFUNCTION flag.
+static const ULONG kDumpRequestThreadFlags = WT_EXECUTEINWAITTHREAD |
+                                             WT_EXECUTELONGFUNCTION;
+
+// Maximum delay during server shutdown if some work items
+// are still executing.
+static const int kShutdownDelayMs = 10000;
+
+// Interval for each sleep during server shutdown.
+static const int kShutdownSleepIntervalMs = 5;
+
+static bool IsClientRequestValid(const ProtocolMessage& msg) {
+  return msg.tag == MESSAGE_TAG_REGISTRATION_REQUEST &&
+         msg.pid != 0 &&
+         msg.thread_id != NULL &&
+         msg.exception_pointers != NULL &&
+         msg.assert_info != NULL;
+}
+
+CrashGenerationServer::CrashGenerationServer(
+    const std::wstring& pipe_name,
+    SECURITY_ATTRIBUTES* pipe_sec_attrs,
+    OnClientConnectedCallback connect_callback,
+    void* connect_context,
+    OnClientDumpRequestCallback dump_callback,
+    void* dump_context,
+    OnClientExitedCallback exit_callback,
+    void* exit_context,
+    bool generate_dumps,
+    const std::wstring* dump_path)
+    : pipe_name_(pipe_name),
+      pipe_sec_attrs_(pipe_sec_attrs),
+      pipe_(NULL),
+      pipe_wait_handle_(NULL),
+      server_alive_handle_(NULL),
+      connect_callback_(connect_callback),
+      connect_context_(connect_context),
+      dump_callback_(dump_callback),
+      dump_context_(dump_context),
+      exit_callback_(exit_callback),
+      exit_context_(exit_context),
+      generate_dumps_(generate_dumps),
+      dump_generator_(NULL),
+      server_state_(IPC_SERVER_STATE_INITIAL),
+      shutting_down_(false),
+      overlapped_(),
+      client_info_(NULL),
+      cleanup_item_count_(0) {
+  InitializeCriticalSection(&clients_sync_);
+
+  if (dump_path) {
+    dump_generator_.reset(new MinidumpGenerator(*dump_path));
+  }
+}
+
+CrashGenerationServer::~CrashGenerationServer() {
+  // Indicate to existing threads that server is shutting down.
+  shutting_down_ = true;
+
+  // Even if there are no current worker threads running, it is possible that
+  // an I/O request is pending on the pipe right now but not yet done. In fact,
+  // it's very likely this is the case unless we are in an ERROR state. If we
+  // don't wait for the pending I/O to be done, then when the I/O completes,
+  // it may write to invalid memory. AppVerifier will flag this problem too.
+  // So we disconnect from the pipe and then wait for the server to get into
+  // error state so that the pending I/O will fail and get cleared.
+  DisconnectNamedPipe(pipe_);
+  int num_tries = 100;
+  while (num_tries-- && server_state_ != IPC_SERVER_STATE_ERROR) {
+    Sleep(10);
+  }
+
+  // Unregister wait on the pipe.
+  if (pipe_wait_handle_) {
+    // Wait for already executing callbacks to finish.
+    UnregisterWaitEx(pipe_wait_handle_, INVALID_HANDLE_VALUE);
+  }
+
+  // Close the pipe to avoid further client connections.
+  if (pipe_) {
+    CloseHandle(pipe_);
+  }
+
+  // Request all ClientInfo objects to unregister all waits.
+  // New scope to hold the lock for the shortest time.
+  {
+    AutoCriticalSection lock(&clients_sync_);
+
+    std::list<ClientInfo*>::iterator iter;
+    for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
+      ClientInfo* client_info = *iter;
+      client_info->UnregisterWaits();
+    }
+  }
+
+  // Now that all waits have been unregistered, wait for some time
+  // for all pending work items to finish.
+  int total_wait = 0;
+  while (cleanup_item_count_ > 0) {
+    Sleep(kShutdownSleepIntervalMs);
+
+    total_wait += kShutdownSleepIntervalMs;
+
+    if (total_wait >= kShutdownDelayMs) {
+      break;
+    }
+  }
+
+  // Clean up all the ClientInfo objects.
+  // New scope to hold the lock for the shortest time.
+  {
+    AutoCriticalSection lock(&clients_sync_);
+
+    std::list<ClientInfo*>::iterator iter;
+    for (iter = clients_.begin(); iter != clients_.end(); ++iter) {
+      ClientInfo* client_info = *iter;
+      delete client_info;
+    }
+  }
+
+  if (server_alive_handle_) {
+    // Release the mutex before closing the handle so that clients requesting
+    // dumps wait for a long time for the server to generate a dump.
+    ReleaseMutex(server_alive_handle_);
+    CloseHandle(server_alive_handle_);
+  }
+
+  DeleteCriticalSection(&clients_sync_);
+}
+
+bool CrashGenerationServer::Start() {
+  server_state_ = IPC_SERVER_STATE_INITIAL;
+
+  server_alive_handle_ = CreateMutex(NULL, TRUE, NULL);
+  if (!server_alive_handle_) {
+    return false;
+  }
+
+  // Event to signal the client connection and pipe reads and writes.
+  overlapped_.hEvent = CreateEvent(NULL,   // Security descriptor.
+                                   TRUE,   // Manual reset.
+                                   FALSE,  // Initially signaled.
+                                   NULL);  // Name.
+  if (!overlapped_.hEvent) {
+    return false;
+  }
+
+  // Register a callback with the thread pool for the client connection.
+  RegisterWaitForSingleObject(&pipe_wait_handle_,
+                              overlapped_.hEvent,
+                              OnPipeConnected,
+                              this,
+                              INFINITE,
+                              kPipeIOThreadFlags);
+
+  pipe_ = CreateNamedPipe(pipe_name_.c_str(),
+                          kPipeAttr,
+                          kPipeMode,
+                          1,
+                          kOutBufferSize,
+                          kInBufferSize,
+                          0,
+                          pipe_sec_attrs_);
+  if (pipe_ == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+
+  // Signal the event to start a separate thread to handle
+  // client connections.
+  return SetEvent(overlapped_.hEvent) != FALSE;
+}
+
+// If the server thread serving clients ever gets into the
+// ERROR state, reset the event, close the pipe and remain
+// in the error state forever. Error state means something
+// that we didn't account for has happened, and it's dangerous
+// to do anything unknowingly.
+void CrashGenerationServer::HandleErrorState() {
+  assert(server_state_ == IPC_SERVER_STATE_ERROR);
+
+  // If the server is shutting down anyway, don't clean up
+  // here since shut down process will clean up.
+  if (shutting_down_) {
+    return;
+  }
+
+  if (pipe_wait_handle_) {
+    UnregisterWait(pipe_wait_handle_);
+    pipe_wait_handle_ = NULL;
+  }
+
+  if (pipe_) {
+    CloseHandle(pipe_);
+    pipe_ = NULL;
+  }
+
+  if (overlapped_.hEvent) {
+    CloseHandle(overlapped_.hEvent);
+    overlapped_.hEvent = NULL;
+  }
+}
+
+// When the server thread serving clients is in the INITIAL state,
+// try to connect to the pipe asynchronously. If the connection
+// finishes synchronously, directly go into the CONNECTED state;
+// otherwise go into the CONNECTING state. For any problems, go
+// into the ERROR state.
+void CrashGenerationServer::HandleInitialState() {
+  assert(server_state_ == IPC_SERVER_STATE_INITIAL);
+
+  if (!ResetEvent(overlapped_.hEvent)) {
+    server_state_ = IPC_SERVER_STATE_ERROR;
+    return;
+  }
+
+  bool success = ConnectNamedPipe(pipe_, &overlapped_) != FALSE;
+
+  // From MSDN, it is not clear that when ConnectNamedPipe is used
+  // in an overlapped mode, will it ever return non-zero value, and
+  // if so, in what cases.
+  assert(!success);
+
+  DWORD error_code = GetLastError();
+  switch (error_code) {
+    case ERROR_IO_PENDING:
+      server_state_ = IPC_SERVER_STATE_CONNECTING;
+      break;
+
+    case ERROR_PIPE_CONNECTED:
+      if (SetEvent(overlapped_.hEvent)) {
+        server_state_ = IPC_SERVER_STATE_CONNECTED;
+      } else {
+        server_state_ = IPC_SERVER_STATE_ERROR;
+      }
+      break;
+
+    default:
+      server_state_ = IPC_SERVER_STATE_ERROR;
+      break;
+  }
+}
+
+// When the server thread serving the clients is in the CONNECTING state,
+// try to get the result of the asynchronous connection request using
+// the OVERLAPPED object. If the result indicates the connection is done,
+// go into the CONNECTED state. If the result indicates I/O is still
+// INCOMPLETE, remain in the CONNECTING state. For any problems,
+// go into the DISCONNECTING state.
+void CrashGenerationServer::HandleConnectingState() {
+  assert(server_state_ == IPC_SERVER_STATE_CONNECTING);
+
+  DWORD bytes_count = 0;
+  bool success = GetOverlappedResult(pipe_,
+                                     &overlapped_,
+                                     &bytes_count,
+                                     FALSE) != FALSE;
+
+  if (success) {
+    server_state_ = IPC_SERVER_STATE_CONNECTED;
+    return;
+  }
+
+  if (GetLastError() != ERROR_IO_INCOMPLETE) {
+    server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+  }
+}
+
+// When the server thread serving the clients is in the CONNECTED state,
+// try to issue an asynchronous read from the pipe. If read completes
+// synchronously or if I/O is pending then go into the READING state.
+// For any problems, go into the DISCONNECTING state.
+void CrashGenerationServer::HandleConnectedState() {
+  assert(server_state_ == IPC_SERVER_STATE_CONNECTED);
+
+  DWORD bytes_count = 0;
+  memset(&msg_, 0, sizeof(msg_));
+  bool success = ReadFile(pipe_,
+                          &msg_,
+                          sizeof(msg_),
+                          &bytes_count,
+                          &overlapped_) != FALSE;
+
+  // Note that the asynchronous read issued above can finish before the
+  // code below executes. But, it is okay to change state after issuing
+  // the asynchronous read. This is because even if the asynchronous read
+  // is done, the callback for it would not be executed until the current
+  // thread finishes its execution.
+  if (success || GetLastError() == ERROR_IO_PENDING) {
+    server_state_ = IPC_SERVER_STATE_READING;
+  } else {
+    server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+  }
+}
+
+// When the server thread serving the clients is in the READING state,
+// try to get the result of the async read. If async read is done,
+// go into the READ_DONE state. For any problems, go into the
+// DISCONNECTING state.
+void CrashGenerationServer::HandleReadingState() {
+  assert(server_state_ == IPC_SERVER_STATE_READING);
+
+  DWORD bytes_count = 0;
+  bool success = GetOverlappedResult(pipe_,
+                                     &overlapped_,
+                                     &bytes_count,
+                                     FALSE) != FALSE;
+
+  if (success && bytes_count == sizeof(ProtocolMessage)) {
+    server_state_ = IPC_SERVER_STATE_READ_DONE;
+    return;
+  }
+
+  DWORD error_code;
+  error_code = GetLastError();
+
+  // We should never get an I/O incomplete since we should not execute this
+  // unless the Read has finished and the overlapped event is signaled. If
+  // we do get INCOMPLETE, we have a bug in our code.
+  assert(error_code != ERROR_IO_INCOMPLETE);
+
+  server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+}
+
+// When the server thread serving the client is in the READ_DONE state,
+// validate the client's request message, register the client by
+// creating appropriate objects and prepare the response.  Then try to
+// write the response to the pipe asynchronously. If that succeeds,
+// go into the WRITING state. For any problems, go into the DISCONNECTING
+// state.
+void CrashGenerationServer::HandleReadDoneState() {
+  assert(server_state_ == IPC_SERVER_STATE_READ_DONE);
+
+  if (!IsClientRequestValid(msg_)) {
+    server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+    return;
+  }
+
+  scoped_ptr<ClientInfo> client_info(
+      new ClientInfo(this,
+                     msg_.pid,
+                     msg_.dump_type,
+                     msg_.thread_id,
+                     msg_.exception_pointers,
+                     msg_.assert_info,
+                     msg_.custom_client_info));
+
+  if (!client_info->Initialize()) {
+    server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+    return;
+  }
+
+  if (!RespondToClient(client_info.get())) {
+    server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+    return;
+  }
+
+  // Note that the asynchronous write issued by RespondToClient function
+  // can finish before  the code below executes. But it is okay to change
+  // state after issuing the asynchronous write. This is because even if
+  // the asynchronous write is done, the callback for it would not be
+  // executed until the current thread finishes its execution.
+  server_state_ = IPC_SERVER_STATE_WRITING;
+  client_info_ = client_info.release();
+}
+
+// When the server thread serving the clients is in the WRITING state,
+// try to get the result of the async write. If the async write is done,
+// go into the WRITE_DONE state. For any problems, go into the
+// DISONNECTING state.
+void CrashGenerationServer::HandleWritingState() {
+  assert(server_state_ == IPC_SERVER_STATE_WRITING);
+
+  DWORD bytes_count = 0;
+  bool success = GetOverlappedResult(pipe_,
+                                     &overlapped_,
+                                     &bytes_count,
+                                     FALSE) != FALSE;
+
+  if (success) {
+    server_state_ = IPC_SERVER_STATE_WRITE_DONE;
+    return;
+  }
+
+  DWORD error_code;
+  error_code = GetLastError();
+
+  // We should never get an I/O incomplete since we should not execute this
+  // unless the Write has finished and the overlapped event is signaled. If
+  // we do get INCOMPLETE, we have a bug in our code.
+  assert(error_code != ERROR_IO_INCOMPLETE);
+
+  server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+}
+
+// When the server thread serving the clients is in the WRITE_DONE state,
+// try to issue an async read on the pipe. If the read completes synchronously
+// or if I/O is still pending then go into the READING_ACK state. For any
+// issues, go into the DISCONNECTING state.
+void CrashGenerationServer::HandleWriteDoneState() {
+  assert(server_state_ == IPC_SERVER_STATE_WRITE_DONE);
+
+  server_state_ = IPC_SERVER_STATE_READING_ACK;
+
+  DWORD bytes_count = 0;
+  bool success = ReadFile(pipe_,
+                          &msg_,
+                          sizeof(msg_),
+                          &bytes_count,
+                          &overlapped_) != FALSE;
+
+  if (success) {
+    return;
+  }
+
+  DWORD error_code = GetLastError();
+
+  if (error_code != ERROR_IO_PENDING) {
+    server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+  }
+}
+
+// When the server thread serving the clients is in the READING_ACK state,
+// try to get result of async read. Go into the DISCONNECTING state.
+void CrashGenerationServer::HandleReadingAckState() {
+  assert(server_state_ == IPC_SERVER_STATE_READING_ACK);
+
+  DWORD bytes_count = 0;
+  bool success = GetOverlappedResult(pipe_,
+                                     &overlapped_,
+                                     &bytes_count,
+                                     FALSE) != FALSE;
+
+  if (success) {
+    // The connection handshake with the client is now complete; perform
+    // the callback.
+    if (connect_callback_) {
+      connect_callback_(connect_context_, client_info_);
+    }
+  } else {
+    DWORD error_code = GetLastError();
+
+    // We should never get an I/O incomplete since we should not execute this
+    // unless the Read has finished and the overlapped event is signaled. If
+    // we do get INCOMPLETE, we have a bug in our code.
+    assert(error_code != ERROR_IO_INCOMPLETE);
+  }
+
+  server_state_ = IPC_SERVER_STATE_DISCONNECTING;
+}
+
+// When the server thread serving the client is in the DISCONNECTING state,
+// disconnect from the pipe and reset the event. If anything fails, go into
+// the ERROR state. If it goes well, go into the INITIAL state and set the
+// event to start all over again.
+void CrashGenerationServer::HandleDisconnectingState() {
+  assert(server_state_ == IPC_SERVER_STATE_DISCONNECTING);
+
+  // Done serving the client.
+  client_info_ = NULL;
+
+  overlapped_.Internal = NULL;
+  overlapped_.InternalHigh = NULL;
+  overlapped_.Offset = 0;
+  overlapped_.OffsetHigh = 0;
+  overlapped_.Pointer = NULL;
+
+  if (!ResetEvent(overlapped_.hEvent)) {
+    server_state_ = IPC_SERVER_STATE_ERROR;
+    return;
+  }
+
+  if (!DisconnectNamedPipe(pipe_)) {
+    server_state_ = IPC_SERVER_STATE_ERROR;
+    return;
+  }
+
+  // If the server is shutting down do not connect to the
+  // next client.
+  if (shutting_down_) {
+    return;
+  }
+
+  server_state_ = IPC_SERVER_STATE_INITIAL;
+  if (!SetEvent(overlapped_.hEvent)) {
+    server_state_ = IPC_SERVER_STATE_ERROR;
+  }
+}
+
+bool CrashGenerationServer::PrepareReply(const ClientInfo& client_info,
+                                         ProtocolMessage* reply) const {
+  reply->tag = MESSAGE_TAG_REGISTRATION_RESPONSE;
+  reply->pid = GetCurrentProcessId();
+
+  if (CreateClientHandles(client_info, reply)) {
+    return true;
+  }
+
+  if (reply->dump_request_handle) {
+    CloseHandle(reply->dump_request_handle);
+  }
+
+  if (reply->dump_generated_handle) {
+    CloseHandle(reply->dump_generated_handle);
+  }
+
+  if (reply->server_alive_handle) {
+    CloseHandle(reply->server_alive_handle);
+  }
+
+  return false;
+}
+
+bool CrashGenerationServer::CreateClientHandles(const ClientInfo& client_info,
+                                                ProtocolMessage* reply) const {
+  HANDLE current_process = GetCurrentProcess();
+  if (!DuplicateHandle(current_process,
+                       client_info.dump_requested_handle(),
+                       client_info.process_handle(),
+                       &reply->dump_request_handle,
+                       kDumpRequestEventAccess,
+                       FALSE,
+                       0)) {
+    return false;
+  }
+
+  if (!DuplicateHandle(current_process,
+                       client_info.dump_generated_handle(),
+                       client_info.process_handle(),
+                       &reply->dump_generated_handle,
+                       kDumpGeneratedEventAccess,
+                       FALSE,
+                       0)) {
+    return false;
+  }
+
+  if (!DuplicateHandle(current_process,
+                       server_alive_handle_,
+                       client_info.process_handle(),
+                       &reply->server_alive_handle,
+                       kMutexAccess,
+                       FALSE,
+                       0)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool CrashGenerationServer::RespondToClient(ClientInfo* client_info) {
+  ProtocolMessage reply;
+  if (!PrepareReply(*client_info, &reply)) {
+    return false;
+  }
+
+  if (!AddClient(client_info)) {
+    return false;
+  }
+
+  DWORD bytes_count = 0;
+  bool success = WriteFile(pipe_,
+                           &reply,
+                           sizeof(reply),
+                           &bytes_count,
+                           &overlapped_) != FALSE;
+
+  return success || GetLastError() == ERROR_IO_PENDING;
+}
+
+// The server thread servicing the clients runs this method. The method
+// implements the state machine described in ReadMe.txt along with the
+// helper methods HandleXXXState.
+void CrashGenerationServer::HandleConnectionRequest() {
+  // If we are shutting doen then get into ERROR state, reset the event so more
+  // workers don't run and return immediately.
+  if (shutting_down_) {
+    server_state_ = IPC_SERVER_STATE_ERROR;
+    ResetEvent(overlapped_.hEvent);
+    return;
+  }
+
+  switch (server_state_) {
+    case IPC_SERVER_STATE_ERROR:
+      HandleErrorState();
+      break;
+
+    case IPC_SERVER_STATE_INITIAL:
+      HandleInitialState();
+      break;
+
+    case IPC_SERVER_STATE_CONNECTING:
+      HandleConnectingState();
+      break;
+
+    case IPC_SERVER_STATE_CONNECTED:
+      HandleConnectedState();
+      break;
+
+    case IPC_SERVER_STATE_READING:
+      HandleReadingState();
+      break;
+
+    case IPC_SERVER_STATE_READ_DONE:
+      HandleReadDoneState();
+      break;
+
+    case IPC_SERVER_STATE_WRITING:
+      HandleWritingState();
+      break;
+
+    case IPC_SERVER_STATE_WRITE_DONE:
+      HandleWriteDoneState();
+      break;
+
+    case IPC_SERVER_STATE_READING_ACK:
+      HandleReadingAckState();
+      break;
+
+    case IPC_SERVER_STATE_DISCONNECTING:
+      HandleDisconnectingState();
+      break;
+
+    default:
+      assert(false);
+      // This indicates that we added one more state without
+      // adding handling code.
+      server_state_ = IPC_SERVER_STATE_ERROR;
+      break;
+  }
+}
+
+bool CrashGenerationServer::AddClient(ClientInfo* client_info) {
+  HANDLE request_wait_handle = NULL;
+  if (!RegisterWaitForSingleObject(&request_wait_handle,
+                                   client_info->dump_requested_handle(),
+                                   OnDumpRequest,
+                                   client_info,
+                                   INFINITE,
+                                   kDumpRequestThreadFlags)) {
+    return false;
+  }
+
+  client_info->set_dump_request_wait_handle(request_wait_handle);
+
+  // OnClientEnd will be called when the client process terminates.
+  HANDLE process_wait_handle = NULL;
+  if (!RegisterWaitForSingleObject(&process_wait_handle,
+                                   client_info->process_handle(),
+                                   OnClientEnd,
+                                   client_info,
+                                   INFINITE,
+                                   WT_EXECUTEONLYONCE)) {
+    return false;
+  }
+
+  client_info->set_process_exit_wait_handle(process_wait_handle);
+
+  // New scope to hold the lock for the shortest time.
+  {
+    AutoCriticalSection lock(&clients_sync_);
+    clients_.push_back(client_info);
+  }
+
+  return true;
+}
+
+// static
+void CALLBACK CrashGenerationServer::OnPipeConnected(void* context, BOOLEAN) {
+  assert (context);
+
+  CrashGenerationServer* obj =
+      reinterpret_cast<CrashGenerationServer*>(context);
+  obj->HandleConnectionRequest();
+}
+
+// static
+void CALLBACK CrashGenerationServer::OnDumpRequest(void* context, BOOLEAN) {
+  assert(context);
+  ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
+  client_info->PopulateCustomInfo();
+
+  CrashGenerationServer* crash_server = client_info->crash_server();
+  assert(crash_server);
+  crash_server->HandleDumpRequest(*client_info);
+
+  ResetEvent(client_info->dump_requested_handle());
+}
+
+// static
+void CALLBACK CrashGenerationServer::OnClientEnd(void* context, BOOLEAN) {
+  assert(context);
+  ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
+
+  CrashGenerationServer* crash_server = client_info->crash_server();
+  assert(crash_server);
+
+  InterlockedIncrement(&crash_server->cleanup_item_count_);
+
+  if (!QueueUserWorkItem(CleanupClient, context, WT_EXECUTEDEFAULT)) {
+    InterlockedDecrement(&crash_server->cleanup_item_count_);
+  }
+}
+
+// static
+DWORD WINAPI CrashGenerationServer::CleanupClient(void* context) {
+  assert(context);
+  ClientInfo* client_info = reinterpret_cast<ClientInfo*>(context);
+
+  CrashGenerationServer* crash_server = client_info->crash_server();
+  assert(crash_server);
+
+  if (crash_server->exit_callback_) {
+    crash_server->exit_callback_(crash_server->exit_context_, client_info);
+  }
+
+  crash_server->DoCleanup(client_info);
+
+  InterlockedDecrement(&crash_server->cleanup_item_count_);
+  return 0;
+}
+
+void CrashGenerationServer::DoCleanup(ClientInfo* client_info) {
+  assert(client_info);
+
+  // Start a new scope to release lock automatically.
+  {
+    AutoCriticalSection lock(&clients_sync_);
+    clients_.remove(client_info);
+  }
+
+  delete client_info;
+}
+
+void CrashGenerationServer::HandleDumpRequest(const ClientInfo& client_info) {
+  // Generate the dump only if it's explicitly requested by the
+  // server application; otherwise the server might want to generate
+  // dump in the callback.
+  std::wstring dump_path;
+  if (generate_dumps_) {
+    if (!GenerateDump(client_info, &dump_path)) {
+      return;
+    }
+  }
+
+  if (dump_callback_) {
+    std::wstring* ptr_dump_path = (dump_path == L"") ? NULL : &dump_path;
+    dump_callback_(dump_context_, &client_info, ptr_dump_path);
+  }
+
+  SetEvent(client_info.dump_generated_handle());
+}
+
+bool CrashGenerationServer::GenerateDump(const ClientInfo& client,
+                                         std::wstring* dump_path) {
+  assert(client.pid() != 0);
+  assert(client.process_handle());
+
+  // We have to get the address of EXCEPTION_INFORMATION from
+  // the client process address space.
+  EXCEPTION_POINTERS* client_ex_info = NULL;
+  if (!client.GetClientExceptionInfo(&client_ex_info)) {
+    return false;
+  }
+
+  DWORD client_thread_id = 0;
+  if (!client.GetClientThreadId(&client_thread_id)) {
+    return false;
+  }
+
+  return dump_generator_->WriteMinidump(client.process_handle(),
+                                        client.pid(),
+                                        client_thread_id,
+                                        GetCurrentThreadId(),
+                                        client_ex_info,
+                                        client.assert_info(),
+                                        client.dump_type(),
+                                        true,
+                                        dump_path);
+}
+
+}  // namespace google_breakpad
diff --git a/third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.h b/third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.h
index 4c483ad..cacb639 100644
--- a/third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.h
+++ b/third_party/breakpad/src/client/windows/crash_generation/crash_generation_server.h
@@ -1,269 +1,269 @@
-// Copyright (c) 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__

-#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__

-

-#include <list>

-#include <string>

-#include "client/windows/common/ipc_protocol.h"

-#include "client/windows/crash_generation/client_info.h"

-#include "client/windows/crash_generation/minidump_generator.h"

-#include "processor/scoped_ptr.h"

-

-namespace google_breakpad {

-

-// Abstraction for server side implementation of out-of-process crash

-// generation protocol for Windows platform only. It generates Windows

-// minidump files for client processes that request dump generation. When

-// the server is requested to start listening for clients (by calling the

-// Start method), it creates a named pipe and waits for the clients to

-// register. In response, it hands them event handles that the client can

-// signal to request dump generation. When the clients request dump

-// generation in this way, the server generates Windows minidump files.

-class CrashGenerationServer {

- public:

-  typedef void (*OnClientConnectedCallback)(void* context,

-                                            const ClientInfo* client_info);

-

-  typedef void (*OnClientDumpRequestCallback)(void* context,

-                                              const ClientInfo* client_info,

-                                              const std::wstring* file_path);

-

-  typedef void (*OnClientExitedCallback)(void* context,

-                                         const ClientInfo* client_info);

-

-  // Creates an instance with the given parameters.

-  //

-  // Parameter pipe_name: Name of the Windows named pipe

-  // Parameter pipe_sec_attrs Security attributes to set on the pipe. Pass

-  //     NULL to use default security on the pipe. By default, the pipe created

-  //     allows Local System, Administrators and the Creator full control and

-  //     the Everyone group read access on the pipe.

-  // Parameter connect_callback: Callback for a new client connection.

-  // Parameter connect_context: Context for client connection callback.

-  // Parameter crash_callback: Callback for a client crash dump request.

-  // Parameter crash_context: Context for client crash dump request callback.

-  // Parameter exit_callback: Callback for client process exit.

-  // Parameter exit_context: Context for client exit callback.

-  // Parameter generate_dumps: Whether to automatically generate dumps.

-  // Client code of this class might want to generate dumps explicitly in the

-  // crash dump request callback. In that case, false can be passed for this

-  // parameter.

-  // Parameter dump_path: Path for generating dumps; required only if true is

-  // passed for generateDumps parameter; NULL can be passed otherwise.

-  CrashGenerationServer(const std::wstring& pipe_name,

-                        SECURITY_ATTRIBUTES* pipe_sec_attrs,

-                        OnClientConnectedCallback connect_callback,

-                        void* connect_context,

-                        OnClientDumpRequestCallback dump_callback,

-                        void* dump_context,

-                        OnClientExitedCallback exit_callback,

-                        void* exit_context,

-                        bool generate_dumps,

-                        const std::wstring* dump_path);

-

-  ~CrashGenerationServer();

-

-  // Performs initialization steps needed to start listening to clients.

-  //

-  // Returns true if initialization is successful; false otherwise.

-  bool Start();

-

- private:

-  // Various states the client can be in during the handshake with

-  // the server.

-  enum IPCServerState {

-    // Server is in error state and it cannot serve any clients.

-    IPC_SERVER_STATE_ERROR,

-

-    // Server starts in this state.

-    IPC_SERVER_STATE_INITIAL,

-

-    // Server has issued an async connect to the pipe and it is waiting

-    // for the connection to be established.

-    IPC_SERVER_STATE_CONNECTING,

-

-    // Server is connected successfully.

-    IPC_SERVER_STATE_CONNECTED,

-

-    // Server has issued an async read from the pipe and it is waiting for

-    // the read to finish.

-    IPC_SERVER_STATE_READING,

-

-    // Server is done reading from the pipe.

-    IPC_SERVER_STATE_READ_DONE,

-

-    // Server has issued an async write to the pipe and it is waiting for

-    // the write to finish.

-    IPC_SERVER_STATE_WRITING,

-

-    // Server is done writing to the pipe.

-    IPC_SERVER_STATE_WRITE_DONE,

-

-    // Server has issued an async read from the pipe for an ack and it

-    // is waiting for the read to finish.

-    IPC_SERVER_STATE_READING_ACK,

-

-    // Server is done writing to the pipe and it is now ready to disconnect

-    // and reconnect.

-    IPC_SERVER_STATE_DISCONNECTING

-  };

-

-  //

-  // Helper methods to handle various server IPC states.

-  //

-  void HandleErrorState();

-  void HandleInitialState();

-  void HandleConnectingState();

-  void HandleConnectedState();

-  void HandleReadingState();

-  void HandleReadDoneState();

-  void HandleWritingState();

-  void HandleWriteDoneState();

-  void HandleReadingAckState();

-  void HandleDisconnectingState();

-

-  // Prepares reply for a client from the given parameters.

-  bool PrepareReply(const ClientInfo& client_info,

-                    ProtocolMessage* reply) const;

-

-  // Duplicates various handles in the ClientInfo object for the client

-  // process and stores them in the given ProtocolMessage instance. If

-  // creating any handle fails, ProtocolMessage will contain the handles

-  // already created successfully, which should be closed by the caller.

-  bool CreateClientHandles(const ClientInfo& client_info,

-                           ProtocolMessage* reply) const;

-

-  // Response to the given client. Return true if all steps of

-  // responding to the client succeed, false otherwise.

-  bool RespondToClient(ClientInfo* client_info);

-

-  // Handles a connection request from the client.

-  void HandleConnectionRequest();

-

-  // Handles a dump request from the client.

-  void HandleDumpRequest(const ClientInfo& client_info);

-

-  // Callback for pipe connected event.

-  static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait);

-

-  // Callback for a dump request.

-  static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait);

-

-  // Callback for client process exit event.

-  static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait);

-

-  // Releases resources for a client.

-  static DWORD WINAPI CleanupClient(void* context);

-

-  // Cleans up for the given client.

-  void DoCleanup(ClientInfo* client_info);

-

-  // Adds the given client to the list of registered clients.

-  bool AddClient(ClientInfo* client_info);

-

-  // Generates dump for the given client.

-  bool GenerateDump(const ClientInfo& client, std::wstring* dump_path);

-

-  // Sync object for thread-safe access to the shared list of clients.

-  CRITICAL_SECTION clients_sync_;

-

-  // List of clients.

-  std::list<ClientInfo*> clients_;

-

-  // Pipe name.

-  std::wstring pipe_name_;

-

-  // Pipe security attributes

-  SECURITY_ATTRIBUTES* pipe_sec_attrs_;

-

-  // Handle to the pipe used for handshake with clients.

-  HANDLE pipe_;

-

-  // Pipe wait handle.

-  HANDLE pipe_wait_handle_;

-

-  // Handle to server-alive mutex.

-  HANDLE server_alive_handle_;

-

-  // Callback for a successful client connection.

-  OnClientConnectedCallback connect_callback_;

-

-  // Context for client connected callback.

-  void* connect_context_;

-

-  // Callback for a client dump request.

-  OnClientDumpRequestCallback dump_callback_;

-

-  // Context for client dump request callback.

-  void* dump_context_;

-

-  // Callback for client process exit.

-  OnClientExitedCallback exit_callback_;

-

-  // Context for client process exit callback.

-  void* exit_context_;

-

-  // Whether to generate dumps.

-  bool generate_dumps_;

-

-  // Instance of a mini dump generator.

-  scoped_ptr<MinidumpGenerator> dump_generator_;

-

-  // State of the server in performing the IPC with the client.

-  // Note that since we restrict the pipe to one instance, we

-  // only need to keep one state of the server. Otherwise, server

-  // would have one state per client it is talking to.

-  volatile IPCServerState server_state_;

-

-  // Whether the server is shutting down.

-  volatile bool shutting_down_;

-

-  // Overlapped instance for async I/O on the pipe.

-  OVERLAPPED overlapped_;

-

-  // Message object used in IPC with the client.

-  ProtocolMessage msg_;

-

-  // Client Info for the client that's connecting to the server.

-  ClientInfo* client_info_;

-

-  // Count of clean-up work items that are currently running or are

-  // already queued to run.

-  volatile LONG cleanup_item_count_;

-

-  // Disable copy ctor and operator=.

-  CrashGenerationServer(const CrashGenerationServer& crash_server);

-  CrashGenerationServer& operator=(const CrashGenerationServer& crash_server);

-};

-

-}  // namespace google_breakpad

-

-#endif  // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__

+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
+#define CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
+
+#include <list>
+#include <string>
+#include "client/windows/common/ipc_protocol.h"
+#include "client/windows/crash_generation/client_info.h"
+#include "client/windows/crash_generation/minidump_generator.h"
+#include "processor/scoped_ptr.h"
+
+namespace google_breakpad {
+
+// Abstraction for server side implementation of out-of-process crash
+// generation protocol for Windows platform only. It generates Windows
+// minidump files for client processes that request dump generation. When
+// the server is requested to start listening for clients (by calling the
+// Start method), it creates a named pipe and waits for the clients to
+// register. In response, it hands them event handles that the client can
+// signal to request dump generation. When the clients request dump
+// generation in this way, the server generates Windows minidump files.
+class CrashGenerationServer {
+ public:
+  typedef void (*OnClientConnectedCallback)(void* context,
+                                            const ClientInfo* client_info);
+
+  typedef void (*OnClientDumpRequestCallback)(void* context,
+                                              const ClientInfo* client_info,
+                                              const std::wstring* file_path);
+
+  typedef void (*OnClientExitedCallback)(void* context,
+                                         const ClientInfo* client_info);
+
+  // Creates an instance with the given parameters.
+  //
+  // Parameter pipe_name: Name of the Windows named pipe
+  // Parameter pipe_sec_attrs Security attributes to set on the pipe. Pass
+  //     NULL to use default security on the pipe. By default, the pipe created
+  //     allows Local System, Administrators and the Creator full control and
+  //     the Everyone group read access on the pipe.
+  // Parameter connect_callback: Callback for a new client connection.
+  // Parameter connect_context: Context for client connection callback.
+  // Parameter crash_callback: Callback for a client crash dump request.
+  // Parameter crash_context: Context for client crash dump request callback.
+  // Parameter exit_callback: Callback for client process exit.
+  // Parameter exit_context: Context for client exit callback.
+  // Parameter generate_dumps: Whether to automatically generate dumps.
+  // Client code of this class might want to generate dumps explicitly in the
+  // crash dump request callback. In that case, false can be passed for this
+  // parameter.
+  // Parameter dump_path: Path for generating dumps; required only if true is
+  // passed for generateDumps parameter; NULL can be passed otherwise.
+  CrashGenerationServer(const std::wstring& pipe_name,
+                        SECURITY_ATTRIBUTES* pipe_sec_attrs,
+                        OnClientConnectedCallback connect_callback,
+                        void* connect_context,
+                        OnClientDumpRequestCallback dump_callback,
+                        void* dump_context,
+                        OnClientExitedCallback exit_callback,
+                        void* exit_context,
+                        bool generate_dumps,
+                        const std::wstring* dump_path);
+
+  ~CrashGenerationServer();
+
+  // Performs initialization steps needed to start listening to clients.
+  //
+  // Returns true if initialization is successful; false otherwise.
+  bool Start();
+
+ private:
+  // Various states the client can be in during the handshake with
+  // the server.
+  enum IPCServerState {
+    // Server is in error state and it cannot serve any clients.
+    IPC_SERVER_STATE_ERROR,
+
+    // Server starts in this state.
+    IPC_SERVER_STATE_INITIAL,
+
+    // Server has issued an async connect to the pipe and it is waiting
+    // for the connection to be established.
+    IPC_SERVER_STATE_CONNECTING,
+
+    // Server is connected successfully.
+    IPC_SERVER_STATE_CONNECTED,
+
+    // Server has issued an async read from the pipe and it is waiting for
+    // the read to finish.
+    IPC_SERVER_STATE_READING,
+
+    // Server is done reading from the pipe.
+    IPC_SERVER_STATE_READ_DONE,
+
+    // Server has issued an async write to the pipe and it is waiting for
+    // the write to finish.
+    IPC_SERVER_STATE_WRITING,
+
+    // Server is done writing to the pipe.
+    IPC_SERVER_STATE_WRITE_DONE,
+
+    // Server has issued an async read from the pipe for an ack and it
+    // is waiting for the read to finish.
+    IPC_SERVER_STATE_READING_ACK,
+
+    // Server is done writing to the pipe and it is now ready to disconnect
+    // and reconnect.
+    IPC_SERVER_STATE_DISCONNECTING
+  };
+
+  //
+  // Helper methods to handle various server IPC states.
+  //
+  void HandleErrorState();
+  void HandleInitialState();
+  void HandleConnectingState();
+  void HandleConnectedState();
+  void HandleReadingState();
+  void HandleReadDoneState();
+  void HandleWritingState();
+  void HandleWriteDoneState();
+  void HandleReadingAckState();
+  void HandleDisconnectingState();
+
+  // Prepares reply for a client from the given parameters.
+  bool PrepareReply(const ClientInfo& client_info,
+                    ProtocolMessage* reply) const;
+
+  // Duplicates various handles in the ClientInfo object for the client
+  // process and stores them in the given ProtocolMessage instance. If
+  // creating any handle fails, ProtocolMessage will contain the handles
+  // already created successfully, which should be closed by the caller.
+  bool CreateClientHandles(const ClientInfo& client_info,
+                           ProtocolMessage* reply) const;
+
+  // Response to the given client. Return true if all steps of
+  // responding to the client succeed, false otherwise.
+  bool RespondToClient(ClientInfo* client_info);
+
+  // Handles a connection request from the client.
+  void HandleConnectionRequest();
+
+  // Handles a dump request from the client.
+  void HandleDumpRequest(const ClientInfo& client_info);
+
+  // Callback for pipe connected event.
+  static void CALLBACK OnPipeConnected(void* context, BOOLEAN timer_or_wait);
+
+  // Callback for a dump request.
+  static void CALLBACK OnDumpRequest(void* context, BOOLEAN timer_or_wait);
+
+  // Callback for client process exit event.
+  static void CALLBACK OnClientEnd(void* context, BOOLEAN timer_or_wait);
+
+  // Releases resources for a client.
+  static DWORD WINAPI CleanupClient(void* context);
+
+  // Cleans up for the given client.
+  void DoCleanup(ClientInfo* client_info);
+
+  // Adds the given client to the list of registered clients.
+  bool AddClient(ClientInfo* client_info);
+
+  // Generates dump for the given client.
+  bool GenerateDump(const ClientInfo& client, std::wstring* dump_path);
+
+  // Sync object for thread-safe access to the shared list of clients.
+  CRITICAL_SECTION clients_sync_;
+
+  // List of clients.
+  std::list<ClientInfo*> clients_;
+
+  // Pipe name.
+  std::wstring pipe_name_;
+
+  // Pipe security attributes
+  SECURITY_ATTRIBUTES* pipe_sec_attrs_;
+
+  // Handle to the pipe used for handshake with clients.
+  HANDLE pipe_;
+
+  // Pipe wait handle.
+  HANDLE pipe_wait_handle_;
+
+  // Handle to server-alive mutex.
+  HANDLE server_alive_handle_;
+
+  // Callback for a successful client connection.
+  OnClientConnectedCallback connect_callback_;
+
+  // Context for client connected callback.
+  void* connect_context_;
+
+  // Callback for a client dump request.
+  OnClientDumpRequestCallback dump_callback_;
+
+  // Context for client dump request callback.
+  void* dump_context_;
+
+  // Callback for client process exit.
+  OnClientExitedCallback exit_callback_;
+
+  // Context for client process exit callback.
+  void* exit_context_;
+
+  // Whether to generate dumps.
+  bool generate_dumps_;
+
+  // Instance of a mini dump generator.
+  scoped_ptr<MinidumpGenerator> dump_generator_;
+
+  // State of the server in performing the IPC with the client.
+  // Note that since we restrict the pipe to one instance, we
+  // only need to keep one state of the server. Otherwise, server
+  // would have one state per client it is talking to.
+  volatile IPCServerState server_state_;
+
+  // Whether the server is shutting down.
+  volatile bool shutting_down_;
+
+  // Overlapped instance for async I/O on the pipe.
+  OVERLAPPED overlapped_;
+
+  // Message object used in IPC with the client.
+  ProtocolMessage msg_;
+
+  // Client Info for the client that's connecting to the server.
+  ClientInfo* client_info_;
+
+  // Count of clean-up work items that are currently running or are
+  // already queued to run.
+  volatile LONG cleanup_item_count_;
+
+  // Disable copy ctor and operator=.
+  CrashGenerationServer(const CrashGenerationServer& crash_server);
+  CrashGenerationServer& operator=(const CrashGenerationServer& crash_server);
+};
+
+}  // namespace google_breakpad
+
+#endif  // CLIENT_WINDOWS_CRASH_GENERATION_CRASH_GENERATION_SERVER_H__
diff --git a/third_party/breakpad/src/client/windows/crash_generation/minidump_generator.cc b/third_party/breakpad/src/client/windows/crash_generation/minidump_generator.cc
index 90a03be..c03b191 100644
--- a/third_party/breakpad/src/client/windows/crash_generation/minidump_generator.cc
+++ b/third_party/breakpad/src/client/windows/crash_generation/minidump_generator.cc
@@ -1,289 +1,289 @@
-// Copyright (c) 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#include "client/windows/crash_generation/minidump_generator.h"

-#include <cassert>

-#include "client/windows/common/auto_critical_section.h"

-#include "common/windows/guid_string.h"

-

-using std::wstring;

-

-namespace google_breakpad {

-

-MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)

-    : dbghelp_module_(NULL),

-      rpcrt4_module_(NULL),

-      dump_path_(dump_path),

-      write_dump_(NULL),

-      create_uuid_(NULL) {

-  InitializeCriticalSection(&module_load_sync_);

-  InitializeCriticalSection(&get_proc_address_sync_);

-}

-

-MinidumpGenerator::~MinidumpGenerator() {

-  if (dbghelp_module_) {

-    FreeLibrary(dbghelp_module_);

-  }

-

-  if (rpcrt4_module_) {

-    FreeLibrary(rpcrt4_module_);

-  }

-

-  DeleteCriticalSection(&get_proc_address_sync_);

-  DeleteCriticalSection(&module_load_sync_);

-}

-

-bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,

-                                      DWORD process_id,

-                                      DWORD thread_id,

-                                      DWORD requesting_thread_id,

-                                      EXCEPTION_POINTERS* exception_pointers,

-                                      MDRawAssertionInfo* assert_info,

-                                      MINIDUMP_TYPE dump_type,

-                                      bool is_client_pointers,

-                                      wstring* dump_path) {

-  MiniDumpWriteDumpType write_dump = GetWriteDump();

-  if (!write_dump) {

-    return false;

-  }

-

-  wstring dump_file_path;

-  if (!GenerateDumpFilePath(&dump_file_path)) {

-    return false;

-  }

-

-  // If the client requests a full memory dump, we will write a normal mini

-  // dump and a full memory dump. Both dump files use the same uuid as file

-  // name prefix.

-  bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0;

-  wstring full_dump_file_path;

-  if (full_memory_dump) {

-    full_dump_file_path.assign(dump_file_path);

-    full_dump_file_path.resize(full_dump_file_path.size() - 4);  // strip .dmp

-    full_dump_file_path.append(TEXT("-full.dmp"));

-  }

-

-  HANDLE dump_file = CreateFile(dump_file_path.c_str(),

-                                GENERIC_WRITE,

-                                0,

-                                NULL,

-                                CREATE_NEW,

-                                FILE_ATTRIBUTE_NORMAL,

-                                NULL);

-

-  if (dump_file == INVALID_HANDLE_VALUE) {

-    return false;

-  }

-

-  HANDLE full_dump_file = INVALID_HANDLE_VALUE;

-  if (full_memory_dump) {

-    full_dump_file = CreateFile(full_dump_file_path.c_str(),

-                                GENERIC_WRITE,

-                                0,

-                                NULL,

-                                CREATE_NEW,

-                                FILE_ATTRIBUTE_NORMAL,

-                                NULL);

-

-    if (full_dump_file == INVALID_HANDLE_VALUE) {

-      CloseHandle(dump_file);

-      return false;

-    }

-  }

-

-  MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;

-  MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;

-

-  // Setup the exception information object only if it's a dump

-  // due to an exception.

-  if (exception_pointers) {

-    dump_exception_pointers = &dump_exception_info;

-    dump_exception_info.ThreadId = thread_id;

-    dump_exception_info.ExceptionPointers = exception_pointers;

-    dump_exception_info.ClientPointers = is_client_pointers;

-  }

-

-  // Add an MDRawBreakpadInfo stream to the minidump, to provide additional

-  // information about the exception handler to the Breakpad processor.

-  // The information will help the processor determine which threads are

-  // relevant. The Breakpad processor does not require this information but

-  // can function better with Breakpad-generated dumps when it is present.

-  // The native debugger is not harmed by the presence of this information.

-  MDRawBreakpadInfo breakpad_info = {0};

-  if (!is_client_pointers) {

-    // Set the dump thread id and requesting thread id only in case of

-    // in-process dump generation.

-    breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |

-                             MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;

-    breakpad_info.dump_thread_id = thread_id;

-    breakpad_info.requesting_thread_id = requesting_thread_id;

-  }

-

-  // Leave room in user_stream_array for a possible assertion info stream.

-  MINIDUMP_USER_STREAM user_stream_array[2];

-  user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;

-  user_stream_array[0].BufferSize = sizeof(breakpad_info);

-  user_stream_array[0].Buffer = &breakpad_info;

-

-  MINIDUMP_USER_STREAM_INFORMATION user_streams;

-  user_streams.UserStreamCount = 1;

-  user_streams.UserStreamArray = user_stream_array;

-

-  MDRawAssertionInfo* actual_assert_info = assert_info;

-  MDRawAssertionInfo client_assert_info = {0};

-

-  if (assert_info) {

-    // If the assertion info object lives in the client process,

-    // read the memory of the client process.

-    if (is_client_pointers) {

-      SIZE_T bytes_read = 0;

-      if (!ReadProcessMemory(process_handle,

-                             assert_info,

-                             &client_assert_info,

-                             sizeof(client_assert_info),

-                             &bytes_read)) {

-        CloseHandle(dump_file);

-        if (full_dump_file != INVALID_HANDLE_VALUE)

-          CloseHandle(full_dump_file);

-        return false;

-      }

-

-      if (bytes_read != sizeof(client_assert_info)) {

-        CloseHandle(dump_file);

-        if (full_dump_file != INVALID_HANDLE_VALUE)

-          CloseHandle(full_dump_file);

-        return false;

-      }

-

-      actual_assert_info  = &client_assert_info;

-    }

-

-    user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;

-    user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);

-    user_stream_array[1].Buffer = actual_assert_info;

-    ++user_streams.UserStreamCount;

-  }

-

-  bool result_minidump = write_dump(

-      process_handle,

-      process_id,

-      dump_file,

-      static_cast<MINIDUMP_TYPE>((dump_type & (~MiniDumpWithFullMemory))

-                                  | MiniDumpNormal),

-      exception_pointers ? &dump_exception_info : NULL,

-      &user_streams,

-      NULL) != FALSE;

-

-  bool result_full_memory = true;

-  if (full_memory_dump) {

-    result_full_memory = write_dump(

-        process_handle,

-        process_id,

-        full_dump_file,

-        static_cast<MINIDUMP_TYPE>(dump_type & (~MiniDumpNormal)),

-        exception_pointers ? &dump_exception_info : NULL,

-        &user_streams,

-        NULL) != FALSE;

-  }

-

-  bool result = result_minidump && result_full_memory;

-

-  CloseHandle(dump_file);

-  if (full_dump_file != INVALID_HANDLE_VALUE)

-    CloseHandle(full_dump_file);

-

-  // Store the path of the dump file in the out parameter if dump generation

-  // succeeded.

-  if (result && dump_path) {

-    *dump_path = dump_file_path;

-  }

-

-  return result;

-}

-

-HMODULE MinidumpGenerator::GetDbghelpModule() {

-  AutoCriticalSection lock(&module_load_sync_);

-  if (!dbghelp_module_) {

-    dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));

-  }

-

-  return dbghelp_module_;

-}

-

-MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {

-  AutoCriticalSection lock(&get_proc_address_sync_);

-  if (!write_dump_) {

-    HMODULE module = GetDbghelpModule();

-    if (module) {

-      FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");

-      write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);

-    }

-  }

-

-  return write_dump_;

-}

-

-HMODULE MinidumpGenerator::GetRpcrt4Module() {

-  AutoCriticalSection lock(&module_load_sync_);

-  if (!rpcrt4_module_) {

-    rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));

-  }

-

-  return rpcrt4_module_;

-}

-

-MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {

-  AutoCriticalSection lock(&module_load_sync_);

-  if (!create_uuid_) {

-    HMODULE module = GetRpcrt4Module();

-    if (module) {

-      FARPROC proc = GetProcAddress(module, "UuidCreate");

-      create_uuid_ = reinterpret_cast<UuidCreateType>(proc);

-    }

-  }

-

-  return create_uuid_;

-}

-

-bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {

-  UUID id = {0};

-

-  UuidCreateType create_uuid = GetCreateUuid();

-  if(!create_uuid) {

-    return false;

-  }

-

-  create_uuid(&id);

-  wstring id_str = GUIDString::GUIDToWString(&id);

-

-  *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");

-  return true;

-}

-

-}  // namespace google_breakpad

+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/windows/crash_generation/minidump_generator.h"
+#include <cassert>
+#include "client/windows/common/auto_critical_section.h"
+#include "common/windows/guid_string.h"
+
+using std::wstring;
+
+namespace google_breakpad {
+
+MinidumpGenerator::MinidumpGenerator(const wstring& dump_path)
+    : dbghelp_module_(NULL),
+      rpcrt4_module_(NULL),
+      dump_path_(dump_path),
+      write_dump_(NULL),
+      create_uuid_(NULL) {
+  InitializeCriticalSection(&module_load_sync_);
+  InitializeCriticalSection(&get_proc_address_sync_);
+}
+
+MinidumpGenerator::~MinidumpGenerator() {
+  if (dbghelp_module_) {
+    FreeLibrary(dbghelp_module_);
+  }
+
+  if (rpcrt4_module_) {
+    FreeLibrary(rpcrt4_module_);
+  }
+
+  DeleteCriticalSection(&get_proc_address_sync_);
+  DeleteCriticalSection(&module_load_sync_);
+}
+
+bool MinidumpGenerator::WriteMinidump(HANDLE process_handle,
+                                      DWORD process_id,
+                                      DWORD thread_id,
+                                      DWORD requesting_thread_id,
+                                      EXCEPTION_POINTERS* exception_pointers,
+                                      MDRawAssertionInfo* assert_info,
+                                      MINIDUMP_TYPE dump_type,
+                                      bool is_client_pointers,
+                                      wstring* dump_path) {
+  MiniDumpWriteDumpType write_dump = GetWriteDump();
+  if (!write_dump) {
+    return false;
+  }
+
+  wstring dump_file_path;
+  if (!GenerateDumpFilePath(&dump_file_path)) {
+    return false;
+  }
+
+  // If the client requests a full memory dump, we will write a normal mini
+  // dump and a full memory dump. Both dump files use the same uuid as file
+  // name prefix.
+  bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0;
+  wstring full_dump_file_path;
+  if (full_memory_dump) {
+    full_dump_file_path.assign(dump_file_path);
+    full_dump_file_path.resize(full_dump_file_path.size() - 4);  // strip .dmp
+    full_dump_file_path.append(TEXT("-full.dmp"));
+  }
+
+  HANDLE dump_file = CreateFile(dump_file_path.c_str(),
+                                GENERIC_WRITE,
+                                0,
+                                NULL,
+                                CREATE_NEW,
+                                FILE_ATTRIBUTE_NORMAL,
+                                NULL);
+
+  if (dump_file == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+
+  HANDLE full_dump_file = INVALID_HANDLE_VALUE;
+  if (full_memory_dump) {
+    full_dump_file = CreateFile(full_dump_file_path.c_str(),
+                                GENERIC_WRITE,
+                                0,
+                                NULL,
+                                CREATE_NEW,
+                                FILE_ATTRIBUTE_NORMAL,
+                                NULL);
+
+    if (full_dump_file == INVALID_HANDLE_VALUE) {
+      CloseHandle(dump_file);
+      return false;
+    }
+  }
+
+  MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL;
+  MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;
+
+  // Setup the exception information object only if it's a dump
+  // due to an exception.
+  if (exception_pointers) {
+    dump_exception_pointers = &dump_exception_info;
+    dump_exception_info.ThreadId = thread_id;
+    dump_exception_info.ExceptionPointers = exception_pointers;
+    dump_exception_info.ClientPointers = is_client_pointers;
+  }
+
+  // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
+  // information about the exception handler to the Breakpad processor.
+  // The information will help the processor determine which threads are
+  // relevant. The Breakpad processor does not require this information but
+  // can function better with Breakpad-generated dumps when it is present.
+  // The native debugger is not harmed by the presence of this information.
+  MDRawBreakpadInfo breakpad_info = {0};
+  if (!is_client_pointers) {
+    // Set the dump thread id and requesting thread id only in case of
+    // in-process dump generation.
+    breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
+                             MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
+    breakpad_info.dump_thread_id = thread_id;
+    breakpad_info.requesting_thread_id = requesting_thread_id;
+  }
+
+  // Leave room in user_stream_array for a possible assertion info stream.
+  MINIDUMP_USER_STREAM user_stream_array[2];
+  user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
+  user_stream_array[0].BufferSize = sizeof(breakpad_info);
+  user_stream_array[0].Buffer = &breakpad_info;
+
+  MINIDUMP_USER_STREAM_INFORMATION user_streams;
+  user_streams.UserStreamCount = 1;
+  user_streams.UserStreamArray = user_stream_array;
+
+  MDRawAssertionInfo* actual_assert_info = assert_info;
+  MDRawAssertionInfo client_assert_info = {0};
+
+  if (assert_info) {
+    // If the assertion info object lives in the client process,
+    // read the memory of the client process.
+    if (is_client_pointers) {
+      SIZE_T bytes_read = 0;
+      if (!ReadProcessMemory(process_handle,
+                             assert_info,
+                             &client_assert_info,
+                             sizeof(client_assert_info),
+                             &bytes_read)) {
+        CloseHandle(dump_file);
+        if (full_dump_file != INVALID_HANDLE_VALUE)
+          CloseHandle(full_dump_file);
+        return false;
+      }
+
+      if (bytes_read != sizeof(client_assert_info)) {
+        CloseHandle(dump_file);
+        if (full_dump_file != INVALID_HANDLE_VALUE)
+          CloseHandle(full_dump_file);
+        return false;
+      }
+
+      actual_assert_info  = &client_assert_info;
+    }
+
+    user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
+    user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
+    user_stream_array[1].Buffer = actual_assert_info;
+    ++user_streams.UserStreamCount;
+  }
+
+  bool result_minidump = write_dump(
+      process_handle,
+      process_id,
+      dump_file,
+      static_cast<MINIDUMP_TYPE>((dump_type & (~MiniDumpWithFullMemory))
+                                  | MiniDumpNormal),
+      exception_pointers ? &dump_exception_info : NULL,
+      &user_streams,
+      NULL) != FALSE;
+
+  bool result_full_memory = true;
+  if (full_memory_dump) {
+    result_full_memory = write_dump(
+        process_handle,
+        process_id,
+        full_dump_file,
+        static_cast<MINIDUMP_TYPE>(dump_type & (~MiniDumpNormal)),
+        exception_pointers ? &dump_exception_info : NULL,
+        &user_streams,
+        NULL) != FALSE;
+  }
+
+  bool result = result_minidump && result_full_memory;
+
+  CloseHandle(dump_file);
+  if (full_dump_file != INVALID_HANDLE_VALUE)
+    CloseHandle(full_dump_file);
+
+  // Store the path of the dump file in the out parameter if dump generation
+  // succeeded.
+  if (result && dump_path) {
+    *dump_path = dump_file_path;
+  }
+
+  return result;
+}
+
+HMODULE MinidumpGenerator::GetDbghelpModule() {
+  AutoCriticalSection lock(&module_load_sync_);
+  if (!dbghelp_module_) {
+    dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll"));
+  }
+
+  return dbghelp_module_;
+}
+
+MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() {
+  AutoCriticalSection lock(&get_proc_address_sync_);
+  if (!write_dump_) {
+    HMODULE module = GetDbghelpModule();
+    if (module) {
+      FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump");
+      write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc);
+    }
+  }
+
+  return write_dump_;
+}
+
+HMODULE MinidumpGenerator::GetRpcrt4Module() {
+  AutoCriticalSection lock(&module_load_sync_);
+  if (!rpcrt4_module_) {
+    rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll"));
+  }
+
+  return rpcrt4_module_;
+}
+
+MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() {
+  AutoCriticalSection lock(&module_load_sync_);
+  if (!create_uuid_) {
+    HMODULE module = GetRpcrt4Module();
+    if (module) {
+      FARPROC proc = GetProcAddress(module, "UuidCreate");
+      create_uuid_ = reinterpret_cast<UuidCreateType>(proc);
+    }
+  }
+
+  return create_uuid_;
+}
+
+bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) {
+  UUID id = {0};
+
+  UuidCreateType create_uuid = GetCreateUuid();
+  if(!create_uuid) {
+    return false;
+  }
+
+  create_uuid(&id);
+  wstring id_str = GUIDString::GUIDToWString(&id);
+
+  *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp");
+  return true;
+}
+
+}  // namespace google_breakpad
diff --git a/third_party/breakpad/src/client/windows/crash_generation/minidump_generator.h b/third_party/breakpad/src/client/windows/crash_generation/minidump_generator.h
index 4ec3401..8ab6a8f 100644
--- a/third_party/breakpad/src/client/windows/crash_generation/minidump_generator.h
+++ b/third_party/breakpad/src/client/windows/crash_generation/minidump_generator.h
@@ -1,121 +1,121 @@
-// Copyright (c) 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__

-#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__

-

-#include <windows.h>

-#include <dbghelp.h>

-#include <list>

-#include "google_breakpad/common/minidump_format.h"

-

-namespace google_breakpad {

-

-// Abstraction for various objects and operations needed to generate

-// minidump on Windows. This abstraction is useful to hide all the gory

-// details for minidump generation and provide a clean interface to

-// the clients to generate minidumps.

-class MinidumpGenerator {

- public:

-  // Creates an instance with the given dump path.

-  explicit MinidumpGenerator(const std::wstring& dump_path);

-

-  ~MinidumpGenerator();

-

-  // Writes the minidump with the given parameters. Stores the

-  // dump file path in the dump_path parameter if dump generation

-  // succeeds.

-  bool WriteMinidump(HANDLE process_handle,

-                     DWORD process_id,

-                     DWORD thread_id,

-                     DWORD requesting_thread_id,

-                     EXCEPTION_POINTERS* exception_pointers,

-                     MDRawAssertionInfo* assert_info,

-                     MINIDUMP_TYPE dump_type,

-                     bool is_client_pointers,

-                     std::wstring* dump_path);

-

- private:

-  // Function pointer type for MiniDumpWriteDump, which is looked up

-  // dynamically.

-  typedef BOOL (WINAPI* MiniDumpWriteDumpType)(

-      HANDLE hProcess,

-      DWORD ProcessId,

-      HANDLE hFile,

-      MINIDUMP_TYPE DumpType,

-      CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,

-      CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,

-      CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);

-

-  // Function pointer type for UuidCreate, which is looked up dynamically.

-  typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid);

-

-  // Loads the appropriate DLL lazily in a thread safe way.

-  HMODULE GetDbghelpModule();

-

-  // Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump

-  // function lazily and in a thread-safe manner.

-  MiniDumpWriteDumpType GetWriteDump();

-

-  // Loads the appropriate DLL lazily in a thread safe way.

-  HMODULE GetRpcrt4Module();

-

-  // Loads the appropriate DLL and gets a pointer to the UuidCreate

-  // function lazily and in a thread-safe manner.

-  UuidCreateType GetCreateUuid();

-

-  // Returns the path for the file to write dump to.

-  bool GenerateDumpFilePath(std::wstring* file_path);

-

-  // Handle to dynamically loaded DbgHelp.dll.

-  HMODULE dbghelp_module_;

-

-  // Pointer to the MiniDumpWriteDump function.

-  MiniDumpWriteDumpType write_dump_;

-

-  // Handle to dynamically loaded rpcrt4.dll.

-  HMODULE rpcrt4_module_;

-

-  // Pointer to the UuidCreate function.

-  UuidCreateType create_uuid_;

-

-  // Folder path to store dump files.

-  std::wstring dump_path_;

-

-  // Critical section to sychronize action of loading modules dynamically.

-  CRITICAL_SECTION module_load_sync_;

-

-  // Critical section to synchronize action of dynamically getting function

-  // addresses from modules.

-  CRITICAL_SECTION get_proc_address_sync_;

-};

-

-}  // namespace google_breakpad

-

-#endif  // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__

+// Copyright (c) 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
+#define CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
+
+#include <windows.h>
+#include <dbghelp.h>
+#include <list>
+#include "google_breakpad/common/minidump_format.h"
+
+namespace google_breakpad {
+
+// Abstraction for various objects and operations needed to generate
+// minidump on Windows. This abstraction is useful to hide all the gory
+// details for minidump generation and provide a clean interface to
+// the clients to generate minidumps.
+class MinidumpGenerator {
+ public:
+  // Creates an instance with the given dump path.
+  explicit MinidumpGenerator(const std::wstring& dump_path);
+
+  ~MinidumpGenerator();
+
+  // Writes the minidump with the given parameters. Stores the
+  // dump file path in the dump_path parameter if dump generation
+  // succeeds.
+  bool WriteMinidump(HANDLE process_handle,
+                     DWORD process_id,
+                     DWORD thread_id,
+                     DWORD requesting_thread_id,
+                     EXCEPTION_POINTERS* exception_pointers,
+                     MDRawAssertionInfo* assert_info,
+                     MINIDUMP_TYPE dump_type,
+                     bool is_client_pointers,
+                     std::wstring* dump_path);
+
+ private:
+  // Function pointer type for MiniDumpWriteDump, which is looked up
+  // dynamically.
+  typedef BOOL (WINAPI* MiniDumpWriteDumpType)(
+      HANDLE hProcess,
+      DWORD ProcessId,
+      HANDLE hFile,
+      MINIDUMP_TYPE DumpType,
+      CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+      CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+      CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+
+  // Function pointer type for UuidCreate, which is looked up dynamically.
+  typedef RPC_STATUS (RPC_ENTRY* UuidCreateType)(UUID* Uuid);
+
+  // Loads the appropriate DLL lazily in a thread safe way.
+  HMODULE GetDbghelpModule();
+
+  // Loads the appropriate DLL and gets a pointer to the MiniDumpWriteDump
+  // function lazily and in a thread-safe manner.
+  MiniDumpWriteDumpType GetWriteDump();
+
+  // Loads the appropriate DLL lazily in a thread safe way.
+  HMODULE GetRpcrt4Module();
+
+  // Loads the appropriate DLL and gets a pointer to the UuidCreate
+  // function lazily and in a thread-safe manner.
+  UuidCreateType GetCreateUuid();
+
+  // Returns the path for the file to write dump to.
+  bool GenerateDumpFilePath(std::wstring* file_path);
+
+  // Handle to dynamically loaded DbgHelp.dll.
+  HMODULE dbghelp_module_;
+
+  // Pointer to the MiniDumpWriteDump function.
+  MiniDumpWriteDumpType write_dump_;
+
+  // Handle to dynamically loaded rpcrt4.dll.
+  HMODULE rpcrt4_module_;
+
+  // Pointer to the UuidCreate function.
+  UuidCreateType create_uuid_;
+
+  // Folder path to store dump files.
+  std::wstring dump_path_;
+
+  // Critical section to sychronize action of loading modules dynamically.
+  CRITICAL_SECTION module_load_sync_;
+
+  // Critical section to synchronize action of dynamically getting function
+  // addresses from modules.
+  CRITICAL_SECTION get_proc_address_sync_;
+};
+
+}  // namespace google_breakpad
+
+#endif  // CLIENT_WINDOWS_CRASH_GENERATION_MINIDUMP_GENERATION_H__
diff --git a/third_party/breakpad/src/client/windows/handler/exception_handler.cc b/third_party/breakpad/src/client/windows/handler/exception_handler.cc
index 698a46f..89e8410 100644
--- a/third_party/breakpad/src/client/windows/handler/exception_handler.cc
+++ b/third_party/breakpad/src/client/windows/handler/exception_handler.cc
@@ -1,748 +1,748 @@
-// Copyright (c) 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#include <ObjBase.h>

-

-#include <cassert>

-#include <cstdio>

-

-#include "common/windows/string_utils-inl.h"

-

-#include "client/windows/common/ipc_protocol.h"

-#include "client/windows/handler/exception_handler.h"

-#include "common/windows/guid_string.h"

-

-namespace google_breakpad {

-

-static const int kWaitForHandlerThreadMs = 60000;

-static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;

-

-vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;

-LONG ExceptionHandler::handler_stack_index_ = 0;

-CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_;

-volatile LONG ExceptionHandler::instance_count_ = 0;

-

-ExceptionHandler::ExceptionHandler(const wstring& dump_path,

-                                   FilterCallback filter,

-                                   MinidumpCallback callback,

-                                   void* callback_context,

-                                   int handler_types,

-                                   MINIDUMP_TYPE dump_type,

-                                   const wchar_t* pipe_name,

-                                   const CustomClientInfo* custom_info) {

-  Initialize(dump_path,

-             filter,

-             callback,

-             callback_context,

-             handler_types,

-             dump_type,

-             pipe_name,

-             custom_info);

-}

-

-ExceptionHandler::ExceptionHandler(const wstring &dump_path,

-                                   FilterCallback filter,

-                                   MinidumpCallback callback,

-                                   void* callback_context,

-                                   int handler_types) {

-  Initialize(dump_path,

-             filter,

-             callback,

-             callback_context,

-             handler_types,

-             MiniDumpNormal,

-             NULL,

-             NULL);

-}

-

-void ExceptionHandler::Initialize(const wstring& dump_path,

-                                  FilterCallback filter,

-                                  MinidumpCallback callback,

-                                  void* callback_context,

-                                  int handler_types,

-                                  MINIDUMP_TYPE dump_type,

-                                  const wchar_t* pipe_name,

-                                  const CustomClientInfo* custom_info) {

-  LONG instance_count = InterlockedIncrement(&instance_count_);

-  filter_ = filter;

-  callback_ = callback;

-  callback_context_ = callback_context;

-  dump_path_c_ = NULL;

-  next_minidump_id_c_ = NULL;

-  next_minidump_path_c_ = NULL;

-  dbghelp_module_ = NULL;

-  minidump_write_dump_ = NULL;

-  dump_type_ = dump_type;

-  rpcrt4_module_ = NULL;

-  uuid_create_ = NULL;

-  handler_types_ = handler_types;

-  previous_filter_ = NULL;

-#if _MSC_VER >= 1400  // MSVC 2005/8

-  previous_iph_ = NULL;

-#endif  // _MSC_VER >= 1400

-  previous_pch_ = NULL;

-  handler_thread_ = NULL;

-  is_shutdown_ = false;

-  handler_start_semaphore_ = NULL;

-  handler_finish_semaphore_ = NULL;

-  requesting_thread_id_ = 0;

-  exception_info_ = NULL;

-  assertion_ = NULL;

-  handler_return_value_ = false;

-  handle_debug_exceptions_ = false;

-

-  // Attempt to use out-of-process if user has specified pipe name.

-  if (pipe_name != NULL) {

-    scoped_ptr<CrashGenerationClient> client(

-        new CrashGenerationClient(pipe_name,

-                                  dump_type_,

-                                  custom_info));

-

-    // If successful in registering with the monitoring process,

-    // there is no need to setup in-process crash generation.

-    if (client->Register()) {

-      crash_generation_client_.reset(client.release());

-    }

-  }

-

-  if (!IsOutOfProcess()) {

-    // Either client did not ask for out-of-process crash generation

-    // or registration with the server process failed. In either case,

-    // setup to do in-process crash generation.

-

-    // Set synchronization primitives and the handler thread.  Each

-    // ExceptionHandler object gets its own handler thread because that's the

-    // only way to reliably guarantee sufficient stack space in an exception,

-    // and it allows an easy way to get a snapshot of the requesting thread's

-    // context outside of an exception.

-    InitializeCriticalSection(&handler_critical_section_);

-    handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);

-    assert(handler_start_semaphore_ != NULL);

-

-    handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);

-    assert(handler_finish_semaphore_ != NULL);

-

-    // Don't attempt to create the thread if we could not create the semaphores.

-    if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) {

-      DWORD thread_id;

-      handler_thread_ = CreateThread(NULL,         // lpThreadAttributes

-                                     kExceptionHandlerThreadInitialStackSize,

-                                     ExceptionHandlerThreadMain,

-                                     this,         // lpParameter

-                                     0,            // dwCreationFlags

-                                     &thread_id);

-      assert(handler_thread_ != NULL);

-    }

-

-    dbghelp_module_ = LoadLibrary(L"dbghelp.dll");

-    if (dbghelp_module_) {

-      minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>(

-          GetProcAddress(dbghelp_module_, "MiniDumpWriteDump"));

-    }

-

-    // Load this library dynamically to not affect existing projects.  Most

-    // projects don't link against this directly, it's usually dynamically

-    // loaded by dependent code.

-    rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll");

-    if (rpcrt4_module_) {

-      uuid_create_ = reinterpret_cast<UuidCreate_type>(

-          GetProcAddress(rpcrt4_module_, "UuidCreate"));

-    }

-

-    // set_dump_path calls UpdateNextID.  This sets up all of the path and id

-    // strings, and their equivalent c_str pointers.

-    set_dump_path(dump_path);

-  }

-

-  // There is a race condition here. If the first instance has not yet

-  // initialized the critical section, the second (and later) instances may

-  // try to use uninitialized critical section object. The feature of multiple

-  // instances in one module is not used much, so leave it as is for now.

-  // One way to solve this in the current design (that is, keeping the static

-  // handler stack) is to use spin locks with volatile bools to synchronize

-  // the handler stack. This works only if the compiler guarantees to generate

-  // cache coherent code for volatile.

-  // TODO(munjal): Fix this in a better way by changing the design if possible.

-

-  // Lazy initialization of the handler_stack_critical_section_

-  if (instance_count == 1) {

-    InitializeCriticalSection(&handler_stack_critical_section_);

-  }

-

-  if (handler_types != HANDLER_NONE) {

-    EnterCriticalSection(&handler_stack_critical_section_);

-

-    // The first time an ExceptionHandler that installs a handler is

-    // created, set up the handler stack.

-    if (!handler_stack_) {

-      handler_stack_ = new vector<ExceptionHandler*>();

-    }

-    handler_stack_->push_back(this);

-

-    if (handler_types & HANDLER_EXCEPTION)

-      previous_filter_ = SetUnhandledExceptionFilter(HandleException);

-

-#if _MSC_VER >= 1400  // MSVC 2005/8

-    if (handler_types & HANDLER_INVALID_PARAMETER)

-      previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter);

-#endif  // _MSC_VER >= 1400

-

-    if (handler_types & HANDLER_PURECALL)

-      previous_pch_ = _set_purecall_handler(HandlePureVirtualCall);

-

-    LeaveCriticalSection(&handler_stack_critical_section_);

-  }

-}

-

-ExceptionHandler::~ExceptionHandler() {

-  if (dbghelp_module_) {

-    FreeLibrary(dbghelp_module_);

-  }

-

-  if (rpcrt4_module_) {

-    FreeLibrary(rpcrt4_module_);

-  }

-

-  if (handler_types_ != HANDLER_NONE) {

-    EnterCriticalSection(&handler_stack_critical_section_);

-

-    if (handler_types_ & HANDLER_EXCEPTION)

-      SetUnhandledExceptionFilter(previous_filter_);

-

-#if _MSC_VER >= 1400  // MSVC 2005/8

-    if (handler_types_ & HANDLER_INVALID_PARAMETER)

-      _set_invalid_parameter_handler(previous_iph_);

-#endif  // _MSC_VER >= 1400

-

-    if (handler_types_ & HANDLER_PURECALL)

-      _set_purecall_handler(previous_pch_);

-

-    if (handler_stack_->back() == this) {

-      handler_stack_->pop_back();

-    } else {

-      // TODO(mmentovai): use advapi32!ReportEvent to log the warning to the

-      // system's application event log.

-      fprintf(stderr, "warning: removing Breakpad handler out of order\n");

-      for (vector<ExceptionHandler*>::iterator iterator =

-               handler_stack_->begin();

-           iterator != handler_stack_->end();

-           ++iterator) {

-        if (*iterator == this) {

-          handler_stack_->erase(iterator);

-        }

-      }

-    }

-

-    if (handler_stack_->empty()) {

-      // When destroying the last ExceptionHandler that installed a handler,

-      // clean up the handler stack.

-      delete handler_stack_;

-      handler_stack_ = NULL;

-    }

-

-    LeaveCriticalSection(&handler_stack_critical_section_);

-  }

-

-  // Some of the objects were only initialized if out of process

-  // registration was not done.

-  if (!IsOutOfProcess()) {

-#ifdef BREAKPAD_NO_TERMINATE_THREAD

-    // Clean up the handler thread and synchronization primitives. The handler

-    // thread is either waiting on the semaphore to handle a crash or it is

-    // handling a crash. Coming out of the wait is fast but wait more in the

-    // eventuality a crash is handled.  This compilation option results in a

-    // deadlock if the exception handler is destroyed while executing code

-    // inside DllMain.

-    is_shutdown_ = true;

-    ReleaseSemaphore(handler_start_semaphore_, 1, NULL);

-    WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs);

-#else

-    TerminateThread(handler_thread_, 1);

-#endif  // BREAKPAD_NO_TERMINATE_THREAD

-    ::CloseHandle(handler_thread_);

-    handler_thread_ = NULL;

-

-    DeleteCriticalSection(&handler_critical_section_);

-    CloseHandle(handler_start_semaphore_);

-    CloseHandle(handler_finish_semaphore_);

-  }

-

-  // There is a race condition in the code below: if this instance is

-  // deleting the static critical section and a new instance of the class

-  // is created, then there is a possibility that the critical section be

-  // initialized while the same critical section is being deleted. Given the

-  // usage pattern for the code, this race condition is unlikely to hit, but it

-  // is a race condition nonetheless.

-  if (InterlockedDecrement(&instance_count_) == 0) {

-    DeleteCriticalSection(&handler_stack_critical_section_);

-  }

-}

-

-// static

-DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) {

-  ExceptionHandler* self = reinterpret_cast<ExceptionHandler *>(lpParameter);

-  assert(self);

-  assert(self->handler_start_semaphore_ != NULL);

-  assert(self->handler_finish_semaphore_ != NULL);

-

-  while (true) {

-    if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) ==

-        WAIT_OBJECT_0) {

-      // Perform the requested action.

-      if (self->is_shutdown_) {

-        // The instance of the exception handler is being destroyed.

-        break;

-      } else {

-        self->handler_return_value_ =

-            self->WriteMinidumpWithException(self->requesting_thread_id_,

-                                             self->exception_info_,

-                                             self->assertion_);

-      }

-

-      // Allow the requesting thread to proceed.

-      ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL);

-    }

-  }

-

-  // This statement is not reached when the thread is unconditionally

-  // terminated by the ExceptionHandler destructor.

-  return 0;

-}

-

-// HandleException and HandleInvalidParameter must create an

-// AutoExceptionHandler object to maintain static state and to determine which

-// ExceptionHandler instance to use.  The constructor locates the correct

-// instance, and makes it available through get_handler().  The destructor

-// restores the state in effect prior to allocating the AutoExceptionHandler.

-class AutoExceptionHandler {

- public:

-  AutoExceptionHandler() {

-    // Increment handler_stack_index_ so that if another Breakpad handler is

-    // registered using this same HandleException function, and it needs to be

-    // called while this handler is running (either becaause this handler

-    // declines to handle the exception, or an exception occurs during

-    // handling), HandleException will find the appropriate ExceptionHandler

-    // object in handler_stack_ to deliver the exception to.

-    //

-    // Because handler_stack_ is addressed in reverse (as |size - index|),

-    // preincrementing handler_stack_index_ avoids needing to subtract 1 from

-    // the argument to |at|.

-    //

-    // The index is maintained instead of popping elements off of the handler

-    // stack and pushing them at the end of this method.  This avoids ruining

-    // the order of elements in the stack in the event that some other thread

-    // decides to manipulate the handler stack (such as creating a new

-    // ExceptionHandler object) while an exception is being handled.

-    EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_);

-    handler_ = ExceptionHandler::handler_stack_->at(

-        ExceptionHandler::handler_stack_->size() -

-        ++ExceptionHandler::handler_stack_index_);

-    LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_);

-

-    // In case another exception occurs while this handler is doing its thing,

-    // it should be delivered to the previous filter.

-    SetUnhandledExceptionFilter(handler_->previous_filter_);

-#if _MSC_VER >= 1400  // MSVC 2005/8

-    _set_invalid_parameter_handler(handler_->previous_iph_);

-#endif  // _MSC_VER >= 1400

-    _set_purecall_handler(handler_->previous_pch_);

-  }

-

-  ~AutoExceptionHandler() {

-    // Put things back the way they were before entering this handler.

-    SetUnhandledExceptionFilter(ExceptionHandler::HandleException);

-#if _MSC_VER >= 1400  // MSVC 2005/8

-    _set_invalid_parameter_handler(ExceptionHandler::HandleInvalidParameter);

-#endif  // _MSC_VER >= 1400

-    _set_purecall_handler(ExceptionHandler::HandlePureVirtualCall);

-

-    EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_);

-    --ExceptionHandler::handler_stack_index_;

-    LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_);

-  }

-

-  ExceptionHandler* get_handler() const { return handler_; }

-

- private:

-  ExceptionHandler* handler_;

-};

-

-// static

-LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) {

-  AutoExceptionHandler auto_exception_handler;

-  ExceptionHandler* current_handler = auto_exception_handler.get_handler();

-

-  // Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions.  This

-  // logic will short-circuit before calling WriteMinidumpOnHandlerThread,

-  // allowing something else to handle the breakpoint without incurring the

-  // overhead transitioning to and from the handler thread.  This behavior

-  // can be overridden by calling ExceptionHandler::set_handle_debug_exceptions.

-  DWORD code = exinfo->ExceptionRecord->ExceptionCode;

-  LONG action;

-  bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) ||

-                            (code == EXCEPTION_SINGLE_STEP);

-

-  bool success = false;

-

-  if (!is_debug_exception ||

-      current_handler->get_handle_debug_exceptions()) {

-    // If out-of-proc crash handler client is available, we have to use that

-    // to generate dump and we cannot fall back on in-proc dump generation

-    // because we never prepared for an in-proc dump generation

-

-    // In case of out-of-process dump generation, directly call

-    // WriteMinidumpWithException since there is no separate thread running.

-    if (current_handler->IsOutOfProcess()) {

-      success = current_handler->WriteMinidumpWithException(

-          GetCurrentThreadId(),

-          exinfo,

-          NULL);

-    } else {

-      success = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL);

-    }

-  }

-

-  // The handler fully handled the exception.  Returning

-  // EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually

-  // results in the application being terminated.

-  //

-  // Note: If the application was launched from within the Cygwin

-  // environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the

-  // application to be restarted.

-  if (success) {

-    action = EXCEPTION_EXECUTE_HANDLER;

-  } else {

-    // There was an exception, it was a breakpoint or something else ignored

-    // above, or it was passed to the handler, which decided not to handle it.

-    // This could be because the filter callback didn't want it, because

-    // minidump writing failed for some reason, or because the post-minidump

-    // callback function indicated failure.  Give the previous handler a

-    // chance to do something with the exception.  If there is no previous

-    // handler, return EXCEPTION_CONTINUE_SEARCH, which will allow a debugger

-    // or native "crashed" dialog to handle the exception.

-    if (current_handler->previous_filter_) {

-      action = current_handler->previous_filter_(exinfo);

-    } else {

-      action = EXCEPTION_CONTINUE_SEARCH;

-    }

-  }

-

-  return action;

-}

-

-#if _MSC_VER >= 1400  // MSVC 2005/8

-// static

-void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression,

-                                              const wchar_t* function,

-                                              const wchar_t* file,

-                                              unsigned int line,

-                                              uintptr_t reserved) {

-  // This is an invalid parameter, not an exception.  It's safe to play with

-  // sprintf here.

-  AutoExceptionHandler auto_exception_handler;

-  ExceptionHandler* current_handler = auto_exception_handler.get_handler();

-

-  MDRawAssertionInfo assertion;

-  memset(&assertion, 0, sizeof(assertion));

-  _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.expression),

-               sizeof(assertion.expression) / sizeof(assertion.expression[0]),

-               _TRUNCATE, L"%s", expression);

-  _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.function),

-               sizeof(assertion.function) / sizeof(assertion.function[0]),

-               _TRUNCATE, L"%s", function);

-  _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.file),

-               sizeof(assertion.file) / sizeof(assertion.file[0]),

-               _TRUNCATE, L"%s", file);

-  assertion.line = line;

-  assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER;

-

-  bool success = false;

-  // In case of out-of-process dump generation, directly call

-  // WriteMinidumpWithException since there is no separate thread running.

-  if (current_handler->IsOutOfProcess()) {

-    success = current_handler->WriteMinidumpWithException(

-        GetCurrentThreadId(),

-        NULL,

-        &assertion);

-  } else {

-    success = current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion);

-  }

-

-  if (!success) {

-    if (current_handler->previous_iph_) {

-      // The handler didn't fully handle the exception.  Give it to the

-      // previous invalid parameter handler.

-      current_handler->previous_iph_(expression,

-                                     function,

-                                     file,

-                                     line,

-                                     reserved);

-    } else {

-      // If there's no previous handler, pass the exception back in to the

-      // invalid parameter handler's core.  That's the routine that called this

-      // function, but now, since this function is no longer registered (and in

-      // fact, no function at all is registered), this will result in the

-      // default code path being taken: _CRT_DEBUGGER_HOOK and _invoke_watson.

-      // Use _invalid_parameter where it exists (in _DEBUG builds) as it passes

-      // more information through.  In non-debug builds, it is not available,

-      // so fall back to using _invalid_parameter_noinfo.  See invarg.c in the

-      // CRT source.

-#ifdef _DEBUG

-      _invalid_parameter(expression, function, file, line, reserved);

-#else  // _DEBUG

-      _invalid_parameter_noinfo();

-#endif  // _DEBUG

-    }

-  }

-

-  // The handler either took care of the invalid parameter problem itself,

-  // or passed it on to another handler.  "Swallow" it by exiting, paralleling

-  // the behavior of "swallowing" exceptions.

-  exit(0);

-}

-#endif  // _MSC_VER >= 1400

-

-// static

-void ExceptionHandler::HandlePureVirtualCall() {

-  AutoExceptionHandler auto_exception_handler;

-  ExceptionHandler* current_handler = auto_exception_handler.get_handler();

-

-  MDRawAssertionInfo assertion;

-  memset(&assertion, 0, sizeof(assertion));

-  assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL;

-

-  bool success = false;

-  // In case of out-of-process dump generation, directly call

-  // WriteMinidumpWithException since there is no separate thread running.

-

-  if (current_handler->IsOutOfProcess()) {

-    success = current_handler->WriteMinidumpWithException(

-        GetCurrentThreadId(),

-        NULL,

-        &assertion);

-  } else {

-    success = current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion);

-  }

-

-  if (!success) {

-    if (current_handler->previous_pch_) {

-      // The handler didn't fully handle the exception.  Give it to the

-      // previous purecall handler.

-      current_handler->previous_pch_();

-    } else {

-      // If there's no previous handler, return and let _purecall handle it.

-      // This will just put up an assertion dialog.

-      return;

-    }

-  }

-

-  // The handler either took care of the invalid parameter problem itself,

-  // or passed it on to another handler.  "Swallow" it by exiting, paralleling

-  // the behavior of "swallowing" exceptions.

-  exit(0);

-}

-

-bool ExceptionHandler::WriteMinidumpOnHandlerThread(

-    EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) {

-  EnterCriticalSection(&handler_critical_section_);

-

-  // There isn't much we can do if the handler thread

-  // was not successfully created.

-  if (handler_thread_ == NULL) {

-    LeaveCriticalSection(&handler_critical_section_);

-    return false;

-  }

-

-  // The handler thread should only be created when the semaphores are valid.

-  assert(handler_start_semaphore_ != NULL);

-  assert(handler_finish_semaphore_ != NULL);

-

-  // Set up data to be passed in to the handler thread.

-  requesting_thread_id_ = GetCurrentThreadId();

-  exception_info_ = exinfo;

-  assertion_ = assertion;

-

-  // This causes the handler thread to call WriteMinidumpWithException.

-  ReleaseSemaphore(handler_start_semaphore_, 1, NULL);

-

-  // Wait until WriteMinidumpWithException is done and collect its return value.

-  WaitForSingleObject(handler_finish_semaphore_, INFINITE);

-  bool status = handler_return_value_;

-

-  // Clean up.

-  requesting_thread_id_ = 0;

-  exception_info_ = NULL;

-  assertion_ = NULL;

-

-  LeaveCriticalSection(&handler_critical_section_);

-

-  return status;

-}

-

-bool ExceptionHandler::WriteMinidump() {

-  return WriteMinidumpForException(NULL);

-}

-

-bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) {

-  // In case of out-of-process dump generation, directly call

-  // WriteMinidumpWithException since there is no separate thread running.

-  if (IsOutOfProcess()) {

-    return WriteMinidumpWithException(GetCurrentThreadId(),

-                                      exinfo,

-                                      NULL);

-  }

-

-  bool success = WriteMinidumpOnHandlerThread(exinfo, NULL);

-  UpdateNextID();

-  return success;

-}

-

-// static

-bool ExceptionHandler::WriteMinidump(const wstring &dump_path,

-                                     MinidumpCallback callback,

-                                     void* callback_context) {

-  ExceptionHandler handler(dump_path, NULL, callback, callback_context,

-                           HANDLER_NONE);

-  return handler.WriteMinidump();

-}

-

-bool ExceptionHandler::WriteMinidumpWithException(

-    DWORD requesting_thread_id,

-    EXCEPTION_POINTERS* exinfo,

-    MDRawAssertionInfo* assertion) {

-  // Give user code a chance to approve or prevent writing a minidump.  If the

-  // filter returns false, don't handle the exception at all.  If this method

-  // was called as a result of an exception, returning false will cause

-  // HandleException to call any previous handler or return

-  // EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear

-  // as though this handler were not present at all.

-  if (filter_ && !filter_(callback_context_, exinfo, assertion)) {

-    return false;

-  }

-

-  bool success = false;

-  if (IsOutOfProcess()) {

-    // Use the EXCEPTION_POINTERS overload for RequestDump if

-    // both exinfo and assertion are NULL.

-    if (!assertion) {

-      success = crash_generation_client_->RequestDump(exinfo);

-    } else {

-      success = crash_generation_client_->RequestDump(assertion);

-    }

-  } else {

-    if (minidump_write_dump_) {

-      HANDLE dump_file = CreateFile(next_minidump_path_c_,

-                                    GENERIC_WRITE,

-                                    0,  // no sharing

-                                    NULL,

-                                    CREATE_NEW,  // fail if exists

-                                    FILE_ATTRIBUTE_NORMAL,

-                                    NULL);

-      if (dump_file != INVALID_HANDLE_VALUE) {

-        MINIDUMP_EXCEPTION_INFORMATION except_info;

-        except_info.ThreadId = requesting_thread_id;

-        except_info.ExceptionPointers = exinfo;

-        except_info.ClientPointers = FALSE;

-

-        // Add an MDRawBreakpadInfo stream to the minidump, to provide additional

-        // information about the exception handler to the Breakpad processor.  The

-        // information will help the processor determine which threads are

-        // relevant.  The Breakpad processor does not require this information but

-        // can function better with Breakpad-generated dumps when it is present.

-        // The native debugger is not harmed by the presence of this information.

-        MDRawBreakpadInfo breakpad_info;

-        breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |

-                               MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;

-        breakpad_info.dump_thread_id = GetCurrentThreadId();

-        breakpad_info.requesting_thread_id = requesting_thread_id;

-

-        // Leave room in user_stream_array for a possible assertion info stream.

-        MINIDUMP_USER_STREAM user_stream_array[2];

-        user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;

-        user_stream_array[0].BufferSize = sizeof(breakpad_info);

-        user_stream_array[0].Buffer = &breakpad_info;

-

-        MINIDUMP_USER_STREAM_INFORMATION user_streams;

-        user_streams.UserStreamCount = 1;

-        user_streams.UserStreamArray = user_stream_array;

-

-        if (assertion) {

-          user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;

-          user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);

-          user_stream_array[1].Buffer = assertion;

-          ++user_streams.UserStreamCount;

-        }

-

-        // The explicit comparison to TRUE avoids a warning (C4800).

-        success = (minidump_write_dump_(GetCurrentProcess(),

-                                        GetCurrentProcessId(),

-                                        dump_file,

-                                        dump_type_,

-                                        exinfo ? &except_info : NULL,

-                                        &user_streams,

-                                        NULL) == TRUE);

-

-        CloseHandle(dump_file);

-      }

-    }

-  }

-

-  if (callback_) {

-    // TODO(munjal): In case of out-of-process dump generation, both

-    // dump_path_c_ and next_minidump_id_ will be NULL. For out-of-process

-    // scenario, the server process ends up creating the dump path and dump

-    // id so they are not known to the client.

-    success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_,

-                        exinfo, assertion, success);

-  }

-

-  return success;

-}

-

-void ExceptionHandler::UpdateNextID() {

-  assert(uuid_create_);

-  UUID id = {0};

-  if (uuid_create_) {

-    uuid_create_(&id);

-  }

-  next_minidump_id_ = GUIDString::GUIDToWString(&id);

-  next_minidump_id_c_ = next_minidump_id_.c_str();

-

-  wchar_t minidump_path[MAX_PATH];

-  swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp",

-           dump_path_c_, next_minidump_id_c_);

-

-  // remove when VC++7.1 is no longer supported

-  minidump_path[MAX_PATH - 1] = L'\0';

-

-  next_minidump_path_ = minidump_path;

-  next_minidump_path_c_ = next_minidump_path_.c_str();

-}

-

-}  // namespace google_breakpad

+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <ObjBase.h>
+
+#include <cassert>
+#include <cstdio>
+
+#include "common/windows/string_utils-inl.h"
+
+#include "client/windows/common/ipc_protocol.h"
+#include "client/windows/handler/exception_handler.h"
+#include "common/windows/guid_string.h"
+
+namespace google_breakpad {
+
+static const int kWaitForHandlerThreadMs = 60000;
+static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
+
+vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
+LONG ExceptionHandler::handler_stack_index_ = 0;
+CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_;
+volatile LONG ExceptionHandler::instance_count_ = 0;
+
+ExceptionHandler::ExceptionHandler(const wstring& dump_path,
+                                   FilterCallback filter,
+                                   MinidumpCallback callback,
+                                   void* callback_context,
+                                   int handler_types,
+                                   MINIDUMP_TYPE dump_type,
+                                   const wchar_t* pipe_name,
+                                   const CustomClientInfo* custom_info) {
+  Initialize(dump_path,
+             filter,
+             callback,
+             callback_context,
+             handler_types,
+             dump_type,
+             pipe_name,
+             custom_info);
+}
+
+ExceptionHandler::ExceptionHandler(const wstring &dump_path,
+                                   FilterCallback filter,
+                                   MinidumpCallback callback,
+                                   void* callback_context,
+                                   int handler_types) {
+  Initialize(dump_path,
+             filter,
+             callback,
+             callback_context,
+             handler_types,
+             MiniDumpNormal,
+             NULL,
+             NULL);
+}
+
+void ExceptionHandler::Initialize(const wstring& dump_path,
+                                  FilterCallback filter,
+                                  MinidumpCallback callback,
+                                  void* callback_context,
+                                  int handler_types,
+                                  MINIDUMP_TYPE dump_type,
+                                  const wchar_t* pipe_name,
+                                  const CustomClientInfo* custom_info) {
+  LONG instance_count = InterlockedIncrement(&instance_count_);
+  filter_ = filter;
+  callback_ = callback;
+  callback_context_ = callback_context;
+  dump_path_c_ = NULL;
+  next_minidump_id_c_ = NULL;
+  next_minidump_path_c_ = NULL;
+  dbghelp_module_ = NULL;
+  minidump_write_dump_ = NULL;
+  dump_type_ = dump_type;
+  rpcrt4_module_ = NULL;
+  uuid_create_ = NULL;
+  handler_types_ = handler_types;
+  previous_filter_ = NULL;
+#if _MSC_VER >= 1400  // MSVC 2005/8
+  previous_iph_ = NULL;
+#endif  // _MSC_VER >= 1400
+  previous_pch_ = NULL;
+  handler_thread_ = NULL;
+  is_shutdown_ = false;
+  handler_start_semaphore_ = NULL;
+  handler_finish_semaphore_ = NULL;
+  requesting_thread_id_ = 0;
+  exception_info_ = NULL;
+  assertion_ = NULL;
+  handler_return_value_ = false;
+  handle_debug_exceptions_ = false;
+
+  // Attempt to use out-of-process if user has specified pipe name.
+  if (pipe_name != NULL) {
+    scoped_ptr<CrashGenerationClient> client(
+        new CrashGenerationClient(pipe_name,
+                                  dump_type_,
+                                  custom_info));
+
+    // If successful in registering with the monitoring process,
+    // there is no need to setup in-process crash generation.
+    if (client->Register()) {
+      crash_generation_client_.reset(client.release());
+    }
+  }
+
+  if (!IsOutOfProcess()) {
+    // Either client did not ask for out-of-process crash generation
+    // or registration with the server process failed. In either case,
+    // setup to do in-process crash generation.
+
+    // Set synchronization primitives and the handler thread.  Each
+    // ExceptionHandler object gets its own handler thread because that's the
+    // only way to reliably guarantee sufficient stack space in an exception,
+    // and it allows an easy way to get a snapshot of the requesting thread's
+    // context outside of an exception.
+    InitializeCriticalSection(&handler_critical_section_);
+    handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
+    assert(handler_start_semaphore_ != NULL);
+
+    handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
+    assert(handler_finish_semaphore_ != NULL);
+
+    // Don't attempt to create the thread if we could not create the semaphores.
+    if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) {
+      DWORD thread_id;
+      handler_thread_ = CreateThread(NULL,         // lpThreadAttributes
+                                     kExceptionHandlerThreadInitialStackSize,
+                                     ExceptionHandlerThreadMain,
+                                     this,         // lpParameter
+                                     0,            // dwCreationFlags
+                                     &thread_id);
+      assert(handler_thread_ != NULL);
+    }
+
+    dbghelp_module_ = LoadLibrary(L"dbghelp.dll");
+    if (dbghelp_module_) {
+      minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>(
+          GetProcAddress(dbghelp_module_, "MiniDumpWriteDump"));
+    }
+
+    // Load this library dynamically to not affect existing projects.  Most
+    // projects don't link against this directly, it's usually dynamically
+    // loaded by dependent code.
+    rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll");
+    if (rpcrt4_module_) {
+      uuid_create_ = reinterpret_cast<UuidCreate_type>(
+          GetProcAddress(rpcrt4_module_, "UuidCreate"));
+    }
+
+    // set_dump_path calls UpdateNextID.  This sets up all of the path and id
+    // strings, and their equivalent c_str pointers.
+    set_dump_path(dump_path);
+  }
+
+  // There is a race condition here. If the first instance has not yet
+  // initialized the critical section, the second (and later) instances may
+  // try to use uninitialized critical section object. The feature of multiple
+  // instances in one module is not used much, so leave it as is for now.
+  // One way to solve this in the current design (that is, keeping the static
+  // handler stack) is to use spin locks with volatile bools to synchronize
+  // the handler stack. This works only if the compiler guarantees to generate
+  // cache coherent code for volatile.
+  // TODO(munjal): Fix this in a better way by changing the design if possible.
+
+  // Lazy initialization of the handler_stack_critical_section_
+  if (instance_count == 1) {
+    InitializeCriticalSection(&handler_stack_critical_section_);
+  }
+
+  if (handler_types != HANDLER_NONE) {
+    EnterCriticalSection(&handler_stack_critical_section_);
+
+    // The first time an ExceptionHandler that installs a handler is
+    // created, set up the handler stack.
+    if (!handler_stack_) {
+      handler_stack_ = new vector<ExceptionHandler*>();
+    }
+    handler_stack_->push_back(this);
+
+    if (handler_types & HANDLER_EXCEPTION)
+      previous_filter_ = SetUnhandledExceptionFilter(HandleException);
+
+#if _MSC_VER >= 1400  // MSVC 2005/8
+    if (handler_types & HANDLER_INVALID_PARAMETER)
+      previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter);
+#endif  // _MSC_VER >= 1400
+
+    if (handler_types & HANDLER_PURECALL)
+      previous_pch_ = _set_purecall_handler(HandlePureVirtualCall);
+
+    LeaveCriticalSection(&handler_stack_critical_section_);
+  }
+}
+
+ExceptionHandler::~ExceptionHandler() {
+  if (dbghelp_module_) {
+    FreeLibrary(dbghelp_module_);
+  }
+
+  if (rpcrt4_module_) {
+    FreeLibrary(rpcrt4_module_);
+  }
+
+  if (handler_types_ != HANDLER_NONE) {
+    EnterCriticalSection(&handler_stack_critical_section_);
+
+    if (handler_types_ & HANDLER_EXCEPTION)
+      SetUnhandledExceptionFilter(previous_filter_);
+
+#if _MSC_VER >= 1400  // MSVC 2005/8
+    if (handler_types_ & HANDLER_INVALID_PARAMETER)
+      _set_invalid_parameter_handler(previous_iph_);
+#endif  // _MSC_VER >= 1400
+
+    if (handler_types_ & HANDLER_PURECALL)
+      _set_purecall_handler(previous_pch_);
+
+    if (handler_stack_->back() == this) {
+      handler_stack_->pop_back();
+    } else {
+      // TODO(mmentovai): use advapi32!ReportEvent to log the warning to the
+      // system's application event log.
+      fprintf(stderr, "warning: removing Breakpad handler out of order\n");
+      for (vector<ExceptionHandler*>::iterator iterator =
+               handler_stack_->begin();
+           iterator != handler_stack_->end();
+           ++iterator) {
+        if (*iterator == this) {
+          handler_stack_->erase(iterator);
+        }
+      }
+    }
+
+    if (handler_stack_->empty()) {
+      // When destroying the last ExceptionHandler that installed a handler,
+      // clean up the handler stack.
+      delete handler_stack_;
+      handler_stack_ = NULL;
+    }
+
+    LeaveCriticalSection(&handler_stack_critical_section_);
+  }
+
+  // Some of the objects were only initialized if out of process
+  // registration was not done.
+  if (!IsOutOfProcess()) {
+#ifdef BREAKPAD_NO_TERMINATE_THREAD
+    // Clean up the handler thread and synchronization primitives. The handler
+    // thread is either waiting on the semaphore to handle a crash or it is
+    // handling a crash. Coming out of the wait is fast but wait more in the
+    // eventuality a crash is handled.  This compilation option results in a
+    // deadlock if the exception handler is destroyed while executing code
+    // inside DllMain.
+    is_shutdown_ = true;
+    ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
+    WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs);
+#else
+    TerminateThread(handler_thread_, 1);
+#endif  // BREAKPAD_NO_TERMINATE_THREAD
+    ::CloseHandle(handler_thread_);
+    handler_thread_ = NULL;
+
+    DeleteCriticalSection(&handler_critical_section_);
+    CloseHandle(handler_start_semaphore_);
+    CloseHandle(handler_finish_semaphore_);
+  }
+
+  // There is a race condition in the code below: if this instance is
+  // deleting the static critical section and a new instance of the class
+  // is created, then there is a possibility that the critical section be
+  // initialized while the same critical section is being deleted. Given the
+  // usage pattern for the code, this race condition is unlikely to hit, but it
+  // is a race condition nonetheless.
+  if (InterlockedDecrement(&instance_count_) == 0) {
+    DeleteCriticalSection(&handler_stack_critical_section_);
+  }
+}
+
+// static
+DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) {
+  ExceptionHandler* self = reinterpret_cast<ExceptionHandler *>(lpParameter);
+  assert(self);
+  assert(self->handler_start_semaphore_ != NULL);
+  assert(self->handler_finish_semaphore_ != NULL);
+
+  while (true) {
+    if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) ==
+        WAIT_OBJECT_0) {
+      // Perform the requested action.
+      if (self->is_shutdown_) {
+        // The instance of the exception handler is being destroyed.
+        break;
+      } else {
+        self->handler_return_value_ =
+            self->WriteMinidumpWithException(self->requesting_thread_id_,
+                                             self->exception_info_,
+                                             self->assertion_);
+      }
+
+      // Allow the requesting thread to proceed.
+      ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL);
+    }
+  }
+
+  // This statement is not reached when the thread is unconditionally
+  // terminated by the ExceptionHandler destructor.
+  return 0;
+}
+
+// HandleException and HandleInvalidParameter must create an
+// AutoExceptionHandler object to maintain static state and to determine which
+// ExceptionHandler instance to use.  The constructor locates the correct
+// instance, and makes it available through get_handler().  The destructor
+// restores the state in effect prior to allocating the AutoExceptionHandler.
+class AutoExceptionHandler {
+ public:
+  AutoExceptionHandler() {
+    // Increment handler_stack_index_ so that if another Breakpad handler is
+    // registered using this same HandleException function, and it needs to be
+    // called while this handler is running (either becaause this handler
+    // declines to handle the exception, or an exception occurs during
+    // handling), HandleException will find the appropriate ExceptionHandler
+    // object in handler_stack_ to deliver the exception to.
+    //
+    // Because handler_stack_ is addressed in reverse (as |size - index|),
+    // preincrementing handler_stack_index_ avoids needing to subtract 1 from
+    // the argument to |at|.
+    //
+    // The index is maintained instead of popping elements off of the handler
+    // stack and pushing them at the end of this method.  This avoids ruining
+    // the order of elements in the stack in the event that some other thread
+    // decides to manipulate the handler stack (such as creating a new
+    // ExceptionHandler object) while an exception is being handled.
+    EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
+    handler_ = ExceptionHandler::handler_stack_->at(
+        ExceptionHandler::handler_stack_->size() -
+        ++ExceptionHandler::handler_stack_index_);
+    LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
+
+    // In case another exception occurs while this handler is doing its thing,
+    // it should be delivered to the previous filter.
+    SetUnhandledExceptionFilter(handler_->previous_filter_);
+#if _MSC_VER >= 1400  // MSVC 2005/8
+    _set_invalid_parameter_handler(handler_->previous_iph_);
+#endif  // _MSC_VER >= 1400
+    _set_purecall_handler(handler_->previous_pch_);
+  }
+
+  ~AutoExceptionHandler() {
+    // Put things back the way they were before entering this handler.
+    SetUnhandledExceptionFilter(ExceptionHandler::HandleException);
+#if _MSC_VER >= 1400  // MSVC 2005/8
+    _set_invalid_parameter_handler(ExceptionHandler::HandleInvalidParameter);
+#endif  // _MSC_VER >= 1400
+    _set_purecall_handler(ExceptionHandler::HandlePureVirtualCall);
+
+    EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
+    --ExceptionHandler::handler_stack_index_;
+    LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
+  }
+
+  ExceptionHandler* get_handler() const { return handler_; }
+
+ private:
+  ExceptionHandler* handler_;
+};
+
+// static
+LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) {
+  AutoExceptionHandler auto_exception_handler;
+  ExceptionHandler* current_handler = auto_exception_handler.get_handler();
+
+  // Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions.  This
+  // logic will short-circuit before calling WriteMinidumpOnHandlerThread,
+  // allowing something else to handle the breakpoint without incurring the
+  // overhead transitioning to and from the handler thread.  This behavior
+  // can be overridden by calling ExceptionHandler::set_handle_debug_exceptions.
+  DWORD code = exinfo->ExceptionRecord->ExceptionCode;
+  LONG action;
+  bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) ||
+                            (code == EXCEPTION_SINGLE_STEP);
+
+  bool success = false;
+
+  if (!is_debug_exception ||
+      current_handler->get_handle_debug_exceptions()) {
+    // If out-of-proc crash handler client is available, we have to use that
+    // to generate dump and we cannot fall back on in-proc dump generation
+    // because we never prepared for an in-proc dump generation
+
+    // In case of out-of-process dump generation, directly call
+    // WriteMinidumpWithException since there is no separate thread running.
+    if (current_handler->IsOutOfProcess()) {
+      success = current_handler->WriteMinidumpWithException(
+          GetCurrentThreadId(),
+          exinfo,
+          NULL);
+    } else {
+      success = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL);
+    }
+  }
+
+  // The handler fully handled the exception.  Returning
+  // EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually
+  // results in the application being terminated.
+  //
+  // Note: If the application was launched from within the Cygwin
+  // environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the
+  // application to be restarted.
+  if (success) {
+    action = EXCEPTION_EXECUTE_HANDLER;
+  } else {
+    // There was an exception, it was a breakpoint or something else ignored
+    // above, or it was passed to the handler, which decided not to handle it.
+    // This could be because the filter callback didn't want it, because
+    // minidump writing failed for some reason, or because the post-minidump
+    // callback function indicated failure.  Give the previous handler a
+    // chance to do something with the exception.  If there is no previous
+    // handler, return EXCEPTION_CONTINUE_SEARCH, which will allow a debugger
+    // or native "crashed" dialog to handle the exception.
+    if (current_handler->previous_filter_) {
+      action = current_handler->previous_filter_(exinfo);
+    } else {
+      action = EXCEPTION_CONTINUE_SEARCH;
+    }
+  }
+
+  return action;
+}
+
+#if _MSC_VER >= 1400  // MSVC 2005/8
+// static
+void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression,
+                                              const wchar_t* function,
+                                              const wchar_t* file,
+                                              unsigned int line,
+                                              uintptr_t reserved) {
+  // This is an invalid parameter, not an exception.  It's safe to play with
+  // sprintf here.
+  AutoExceptionHandler auto_exception_handler;
+  ExceptionHandler* current_handler = auto_exception_handler.get_handler();
+
+  MDRawAssertionInfo assertion;
+  memset(&assertion, 0, sizeof(assertion));
+  _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.expression),
+               sizeof(assertion.expression) / sizeof(assertion.expression[0]),
+               _TRUNCATE, L"%s", expression);
+  _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.function),
+               sizeof(assertion.function) / sizeof(assertion.function[0]),
+               _TRUNCATE, L"%s", function);
+  _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.file),
+               sizeof(assertion.file) / sizeof(assertion.file[0]),
+               _TRUNCATE, L"%s", file);
+  assertion.line = line;
+  assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER;
+
+  bool success = false;
+  // In case of out-of-process dump generation, directly call
+  // WriteMinidumpWithException since there is no separate thread running.
+  if (current_handler->IsOutOfProcess()) {
+    success = current_handler->WriteMinidumpWithException(
+        GetCurrentThreadId(),
+        NULL,
+        &assertion);
+  } else {
+    success = current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion);
+  }
+
+  if (!success) {
+    if (current_handler->previous_iph_) {
+      // The handler didn't fully handle the exception.  Give it to the
+      // previous invalid parameter handler.
+      current_handler->previous_iph_(expression,
+                                     function,
+                                     file,
+                                     line,
+                                     reserved);
+    } else {
+      // If there's no previous handler, pass the exception back in to the
+      // invalid parameter handler's core.  That's the routine that called this
+      // function, but now, since this function is no longer registered (and in
+      // fact, no function at all is registered), this will result in the
+      // default code path being taken: _CRT_DEBUGGER_HOOK and _invoke_watson.
+      // Use _invalid_parameter where it exists (in _DEBUG builds) as it passes
+      // more information through.  In non-debug builds, it is not available,
+      // so fall back to using _invalid_parameter_noinfo.  See invarg.c in the
+      // CRT source.
+#ifdef _DEBUG
+      _invalid_parameter(expression, function, file, line, reserved);
+#else  // _DEBUG
+      _invalid_parameter_noinfo();
+#endif  // _DEBUG
+    }
+  }
+
+  // The handler either took care of the invalid parameter problem itself,
+  // or passed it on to another handler.  "Swallow" it by exiting, paralleling
+  // the behavior of "swallowing" exceptions.
+  exit(0);
+}
+#endif  // _MSC_VER >= 1400
+
+// static
+void ExceptionHandler::HandlePureVirtualCall() {
+  AutoExceptionHandler auto_exception_handler;
+  ExceptionHandler* current_handler = auto_exception_handler.get_handler();
+
+  MDRawAssertionInfo assertion;
+  memset(&assertion, 0, sizeof(assertion));
+  assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL;
+
+  bool success = false;
+  // In case of out-of-process dump generation, directly call
+  // WriteMinidumpWithException since there is no separate thread running.
+
+  if (current_handler->IsOutOfProcess()) {
+    success = current_handler->WriteMinidumpWithException(
+        GetCurrentThreadId(),
+        NULL,
+        &assertion);
+  } else {
+    success = current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion);
+  }
+
+  if (!success) {
+    if (current_handler->previous_pch_) {
+      // The handler didn't fully handle the exception.  Give it to the
+      // previous purecall handler.
+      current_handler->previous_pch_();
+    } else {
+      // If there's no previous handler, return and let _purecall handle it.
+      // This will just put up an assertion dialog.
+      return;
+    }
+  }
+
+  // The handler either took care of the invalid parameter problem itself,
+  // or passed it on to another handler.  "Swallow" it by exiting, paralleling
+  // the behavior of "swallowing" exceptions.
+  exit(0);
+}
+
+bool ExceptionHandler::WriteMinidumpOnHandlerThread(
+    EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) {
+  EnterCriticalSection(&handler_critical_section_);
+
+  // There isn't much we can do if the handler thread
+  // was not successfully created.
+  if (handler_thread_ == NULL) {
+    LeaveCriticalSection(&handler_critical_section_);
+    return false;
+  }
+
+  // The handler thread should only be created when the semaphores are valid.
+  assert(handler_start_semaphore_ != NULL);
+  assert(handler_finish_semaphore_ != NULL);
+
+  // Set up data to be passed in to the handler thread.
+  requesting_thread_id_ = GetCurrentThreadId();
+  exception_info_ = exinfo;
+  assertion_ = assertion;
+
+  // This causes the handler thread to call WriteMinidumpWithException.
+  ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
+
+  // Wait until WriteMinidumpWithException is done and collect its return value.
+  WaitForSingleObject(handler_finish_semaphore_, INFINITE);
+  bool status = handler_return_value_;
+
+  // Clean up.
+  requesting_thread_id_ = 0;
+  exception_info_ = NULL;
+  assertion_ = NULL;
+
+  LeaveCriticalSection(&handler_critical_section_);
+
+  return status;
+}
+
+bool ExceptionHandler::WriteMinidump() {
+  return WriteMinidumpForException(NULL);
+}
+
+bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) {
+  // In case of out-of-process dump generation, directly call
+  // WriteMinidumpWithException since there is no separate thread running.
+  if (IsOutOfProcess()) {
+    return WriteMinidumpWithException(GetCurrentThreadId(),
+                                      exinfo,
+                                      NULL);
+  }
+
+  bool success = WriteMinidumpOnHandlerThread(exinfo, NULL);
+  UpdateNextID();
+  return success;
+}
+
+// static
+bool ExceptionHandler::WriteMinidump(const wstring &dump_path,
+                                     MinidumpCallback callback,
+                                     void* callback_context) {
+  ExceptionHandler handler(dump_path, NULL, callback, callback_context,
+                           HANDLER_NONE);
+  return handler.WriteMinidump();
+}
+
+bool ExceptionHandler::WriteMinidumpWithException(
+    DWORD requesting_thread_id,
+    EXCEPTION_POINTERS* exinfo,
+    MDRawAssertionInfo* assertion) {
+  // Give user code a chance to approve or prevent writing a minidump.  If the
+  // filter returns false, don't handle the exception at all.  If this method
+  // was called as a result of an exception, returning false will cause
+  // HandleException to call any previous handler or return
+  // EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear
+  // as though this handler were not present at all.
+  if (filter_ && !filter_(callback_context_, exinfo, assertion)) {
+    return false;
+  }
+
+  bool success = false;
+  if (IsOutOfProcess()) {
+    // Use the EXCEPTION_POINTERS overload for RequestDump if
+    // both exinfo and assertion are NULL.
+    if (!assertion) {
+      success = crash_generation_client_->RequestDump(exinfo);
+    } else {
+      success = crash_generation_client_->RequestDump(assertion);
+    }
+  } else {
+    if (minidump_write_dump_) {
+      HANDLE dump_file = CreateFile(next_minidump_path_c_,
+                                    GENERIC_WRITE,
+                                    0,  // no sharing
+                                    NULL,
+                                    CREATE_NEW,  // fail if exists
+                                    FILE_ATTRIBUTE_NORMAL,
+                                    NULL);
+      if (dump_file != INVALID_HANDLE_VALUE) {
+        MINIDUMP_EXCEPTION_INFORMATION except_info;
+        except_info.ThreadId = requesting_thread_id;
+        except_info.ExceptionPointers = exinfo;
+        except_info.ClientPointers = FALSE;
+
+        // Add an MDRawBreakpadInfo stream to the minidump, to provide additional
+        // information about the exception handler to the Breakpad processor.  The
+        // information will help the processor determine which threads are
+        // relevant.  The Breakpad processor does not require this information but
+        // can function better with Breakpad-generated dumps when it is present.
+        // The native debugger is not harmed by the presence of this information.
+        MDRawBreakpadInfo breakpad_info;
+        breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
+                               MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
+        breakpad_info.dump_thread_id = GetCurrentThreadId();
+        breakpad_info.requesting_thread_id = requesting_thread_id;
+
+        // Leave room in user_stream_array for a possible assertion info stream.
+        MINIDUMP_USER_STREAM user_stream_array[2];
+        user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
+        user_stream_array[0].BufferSize = sizeof(breakpad_info);
+        user_stream_array[0].Buffer = &breakpad_info;
+
+        MINIDUMP_USER_STREAM_INFORMATION user_streams;
+        user_streams.UserStreamCount = 1;
+        user_streams.UserStreamArray = user_stream_array;
+
+        if (assertion) {
+          user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
+          user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
+          user_stream_array[1].Buffer = assertion;
+          ++user_streams.UserStreamCount;
+        }
+
+        // The explicit comparison to TRUE avoids a warning (C4800).
+        success = (minidump_write_dump_(GetCurrentProcess(),
+                                        GetCurrentProcessId(),
+                                        dump_file,
+                                        dump_type_,
+                                        exinfo ? &except_info : NULL,
+                                        &user_streams,
+                                        NULL) == TRUE);
+
+        CloseHandle(dump_file);
+      }
+    }
+  }
+
+  if (callback_) {
+    // TODO(munjal): In case of out-of-process dump generation, both
+    // dump_path_c_ and next_minidump_id_ will be NULL. For out-of-process
+    // scenario, the server process ends up creating the dump path and dump
+    // id so they are not known to the client.
+    success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
+                        exinfo, assertion, success);
+  }
+
+  return success;
+}
+
+void ExceptionHandler::UpdateNextID() {
+  assert(uuid_create_);
+  UUID id = {0};
+  if (uuid_create_) {
+    uuid_create_(&id);
+  }
+  next_minidump_id_ = GUIDString::GUIDToWString(&id);
+  next_minidump_id_c_ = next_minidump_id_.c_str();
+
+  wchar_t minidump_path[MAX_PATH];
+  swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp",
+           dump_path_c_, next_minidump_id_c_);
+
+  // remove when VC++7.1 is no longer supported
+  minidump_path[MAX_PATH - 1] = L'\0';
+
+  next_minidump_path_ = minidump_path;
+  next_minidump_path_c_ = next_minidump_path_.c_str();
+}
+
+}  // namespace google_breakpad
diff --git a/third_party/breakpad/src/client/windows/handler/exception_handler.h b/third_party/breakpad/src/client/windows/handler/exception_handler.h
index 3f264a9..2cacdc3 100644
--- a/third_party/breakpad/src/client/windows/handler/exception_handler.h
+++ b/third_party/breakpad/src/client/windows/handler/exception_handler.h
@@ -1,415 +1,415 @@
-// Copyright (c) 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-// ExceptionHandler can write a minidump file when an exception occurs,

-// or when WriteMinidump() is called explicitly by your program.

-//

-// To have the exception handler write minidumps when an uncaught exception

-// (crash) occurs, you should create an instance early in the execution

-// of your program, and keep it around for the entire time you want to

-// have crash handling active (typically, until shutdown).

-//

-// If you want to write minidumps without installing the exception handler,

-// you can create an ExceptionHandler with install_handler set to false,

-// then call WriteMinidump.  You can also use this technique if you want to

-// use different minidump callbacks for different call sites.

-//

-// In either case, a callback function is called when a minidump is written,

-// which receives the unqiue id of the minidump.  The caller can use this

-// id to collect and write additional application state, and to launch an

-// external crash-reporting application.

-//

-// It is important that creation and destruction of ExceptionHandler objects

-// be nested cleanly, when using install_handler = true.

-// Avoid the following pattern:

-//   ExceptionHandler *e = new ExceptionHandler(...);

-//   ExceptionHandler *f = new ExceptionHandler(...);

-//   delete e;

-// This will put the exception filter stack into an inconsistent state.

-

-#ifndef CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__

-#define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__

-

-#include <stdlib.h>

-#include <Windows.h>

-#include <DbgHelp.h>

-#include <rpc.h>

-

-#pragma warning( push )

-// Disable exception handler warnings.

-#pragma warning( disable : 4530 )

-

-#include <string>

-#include <vector>

-

-#include "client/windows/common/ipc_protocol.h"

-#include "client/windows/crash_generation/crash_generation_client.h"

-#include "google_breakpad/common/minidump_format.h"

-#include "processor/scoped_ptr.h"

-

-namespace google_breakpad {

-

-using std::vector;

-using std::wstring;

-

-class ExceptionHandler {

- public:

-  // A callback function to run before Breakpad performs any substantial

-  // processing of an exception.  A FilterCallback is called before writing

-  // a minidump.  context is the parameter supplied by the user as

-  // callback_context when the handler was created.  exinfo points to the

-  // exception record, if any; assertion points to assertion information,

-  // if any.

-  //

-  // If a FilterCallback returns true, Breakpad will continue processing,

-  // attempting to write a minidump.  If a FilterCallback returns false, Breakpad

-  // will immediately report the exception as unhandled without writing a

-  // minidump, allowing another handler the opportunity to handle it.

-  typedef bool (*FilterCallback)(void* context, EXCEPTION_POINTERS* exinfo,

-                                 MDRawAssertionInfo* assertion);

-

-  // A callback function to run after the minidump has been written.

-  // minidump_id is a unique id for the dump, so the minidump

-  // file is <dump_path>\<minidump_id>.dmp.  context is the parameter supplied

-  // by the user as callback_context when the handler was created.  exinfo

-  // points to the exception record, or NULL if no exception occurred.

-  // succeeded indicates whether a minidump file was successfully written.

-  // assertion points to information about an assertion if the handler was

-  // invoked by an assertion.

-  //

-  // If an exception occurred and the callback returns true, Breakpad will treat

-  // the exception as fully-handled, suppressing any other handlers from being

-  // notified of the exception.  If the callback returns false, Breakpad will

-  // treat the exception as unhandled, and allow another handler to handle it.

-  // If there are no other handlers, Breakpad will report the exception to the

-  // system as unhandled, allowing a debugger or native crash dialog the

-  // opportunity to handle the exception.  Most callback implementations

-  // should normally return the value of |succeeded|, or when they wish to

-  // not report an exception of handled, false.  Callbacks will rarely want to

-  // return true directly (unless |succeeded| is true).

-  //

-  // For out-of-process dump generation, dump path and minidump ID will always

-  // be NULL. In case of out-of-process dump generation, the dump path and

-  // minidump id are controlled by the server process and are not communicated

-  // back to the crashing process.

-  typedef bool (*MinidumpCallback)(const wchar_t* dump_path,

-                                   const wchar_t* minidump_id,

-                                   void* context,

-                                   EXCEPTION_POINTERS* exinfo,

-                                   MDRawAssertionInfo* assertion,

-                                   bool succeeded);

-

-  // HandlerType specifies which types of handlers should be installed, if

-  // any.  Use HANDLER_NONE for an ExceptionHandler that remains idle,

-  // without catching any failures on its own.  This type of handler may

-  // still be triggered by calling WriteMinidump.  Otherwise, use a

-  // combination of the other HANDLER_ values, or HANDLER_ALL to install

-  // all handlers.

-  enum HandlerType {

-    HANDLER_NONE = 0,

-    HANDLER_EXCEPTION = 1 << 0,          // SetUnhandledExceptionFilter

-    HANDLER_INVALID_PARAMETER = 1 << 1,  // _set_invalid_parameter_handler

-    HANDLER_PURECALL = 1 << 2,           // _set_purecall_handler

-    HANDLER_ALL = HANDLER_EXCEPTION |

-                  HANDLER_INVALID_PARAMETER |

-                  HANDLER_PURECALL

-  };

-

-  // Creates a new ExceptionHandler instance to handle writing minidumps.

-  // Before writing a minidump, the optional filter callback will be called.

-  // Its return value determines whether or not Breakpad should write a

-  // minidump.  Minidump files will be written to dump_path, and the optional

-  // callback is called after writing the dump file, as described above.

-  // handler_types specifies the types of handlers that should be installed.

-  ExceptionHandler(const wstring& dump_path,

-                   FilterCallback filter,

-                   MinidumpCallback callback,

-                   void* callback_context,

-                   int handler_types);

-

-  // Creates a new ExcetpionHandler instance that can attempt to perform

-  // out-of-process dump generation if pipe_name is not NULL. If pipe_name is

-  // NULL, or if out-of-process dump generation registration step fails,

-  // in-process dump generation will be used. This also allows specifying

-  // the dump type to generate.

-  ExceptionHandler(const wstring& dump_path,

-                   FilterCallback filter,

-                   MinidumpCallback callback,

-                   void* callback_context,

-                   int handler_types,

-                   MINIDUMP_TYPE dump_type,

-                   const wchar_t* pipe_name,

-                   const CustomClientInfo* custom_info);

-

-  ~ExceptionHandler();

-

-  // Get and set the minidump path.

-  wstring dump_path() const { return dump_path_; }

-  void set_dump_path(const wstring &dump_path) {

-    dump_path_ = dump_path;

-    dump_path_c_ = dump_path_.c_str();

-    UpdateNextID();  // Necessary to put dump_path_ in next_minidump_path_.

-  }

-

-  // Writes a minidump immediately.  This can be used to capture the

-  // execution state independently of a crash.  Returns true on success.

-  bool WriteMinidump();

-

-  // Writes a minidump immediately, with the user-supplied exception

-  // information.

-  bool WriteMinidumpForException(EXCEPTION_POINTERS* exinfo);

-

-  // Convenience form of WriteMinidump which does not require an

-  // ExceptionHandler instance.

-  static bool WriteMinidump(const wstring &dump_path,

-                            MinidumpCallback callback, void* callback_context);

-

-  // Get the thread ID of the thread requesting the dump (either the exception

-  // thread or any other thread that called WriteMinidump directly).  This

-  // may be useful if you want to include additional thread state in your

-  // dumps.

-  DWORD get_requesting_thread_id() const { return requesting_thread_id_; }

-

-  // Controls behavior of EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP.

-  bool get_handle_debug_exceptions() const { return handle_debug_exceptions_; }

-  void set_handle_debug_exceptions(bool handle_debug_exceptions) {

-    handle_debug_exceptions_ = handle_debug_exceptions;

-  }

-

-  // Returns whether out-of-process dump generation is used or not.

-  bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; }

-

- private:

-  friend class AutoExceptionHandler;

-

-  // Initializes the instance with given values.

-  void Initialize(const wstring& dump_path,

-                  FilterCallback filter,

-                  MinidumpCallback callback,

-                  void* callback_context,

-                  int handler_types,

-                  MINIDUMP_TYPE dump_type,

-                  const wchar_t* pipe_name,

-                  const CustomClientInfo* custom_info);

-

-  // Function pointer type for MiniDumpWriteDump, which is looked up

-  // dynamically.

-  typedef BOOL (WINAPI *MiniDumpWriteDump_type)(

-      HANDLE hProcess,

-      DWORD dwPid,

-      HANDLE hFile,

-      MINIDUMP_TYPE DumpType,

-      CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,

-      CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,

-      CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);

-

-  // Function pointer type for UuidCreate, which is looked up dynamically.

-  typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID* Uuid);

-

-  // Runs the main loop for the exception handler thread.

-  static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter);

-

-  // Called on the exception thread when an unhandled exception occurs.

-  // Signals the exception handler thread to handle the exception.

-  static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo);

-

-#if _MSC_VER >= 1400  // MSVC 2005/8

-  // This function will be called by some CRT functions when they detect

-  // that they were passed an invalid parameter.  Note that in _DEBUG builds,

-  // the CRT may display an assertion dialog before calling this function,

-  // and the function will not be called unless the assertion dialog is

-  // dismissed by clicking "Ignore."

-  static void HandleInvalidParameter(const wchar_t* expression,

-                                     const wchar_t* function,

-                                     const wchar_t* file,

-                                     unsigned int line,

-                                     uintptr_t reserved);

-#endif  // _MSC_VER >= 1400

-

-  // This function will be called by the CRT when a pure virtual

-  // function is called.

-  static void HandlePureVirtualCall();

-

-  // This is called on the exception thread or on another thread that

-  // the user wishes to produce a dump from.  It calls

-  // WriteMinidumpWithException on the handler thread, avoiding stack

-  // overflows and inconsistent dumps due to writing the dump from

-  // the exception thread.  If the dump is requested as a result of an

-  // exception, exinfo contains exception information, otherwise, it

-  // is NULL.  If the dump is requested as a result of an assertion

-  // (such as an invalid parameter being passed to a CRT function),

-  // assertion contains data about the assertion, otherwise, it is NULL.

-  bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS* exinfo,

-                                    MDRawAssertionInfo* assertion);

-

-  // This function does the actual writing of a minidump.  It is called

-  // on the handler thread.  requesting_thread_id is the ID of the thread

-  // that requested the dump.  If the dump is requested as a result of

-  // an exception, exinfo contains exception information, otherwise,

-  // it is NULL.

-  bool WriteMinidumpWithException(DWORD requesting_thread_id,

-                                  EXCEPTION_POINTERS* exinfo,

-                                  MDRawAssertionInfo* assertion);

-

-  // Generates a new ID and stores it in next_minidump_id_, and stores the

-  // path of the next minidump to be written in next_minidump_path_.

-  void UpdateNextID();

-

-  FilterCallback filter_;

-  MinidumpCallback callback_;

-  void* callback_context_;

-

-  scoped_ptr<CrashGenerationClient> crash_generation_client_;

-

-  // The directory in which a minidump will be written, set by the dump_path

-  // argument to the constructor, or set_dump_path.

-  wstring dump_path_;

-

-  // The basename of the next minidump to be written, without the extension.

-  wstring next_minidump_id_;

-

-  // The full pathname of the next minidump to be written, including the file

-  // extension.

-  wstring next_minidump_path_;

-

-  // Pointers to C-string representations of the above.  These are set when

-  // the above wstring versions are set in order to avoid calling c_str during

-  // an exception, as c_str may attempt to allocate heap memory.  These

-  // pointers are not owned by the ExceptionHandler object, but their lifetimes

-  // should be equivalent to the lifetimes of the associated wstring, provided

-  // that the wstrings are not altered.

-  const wchar_t* dump_path_c_;

-  const wchar_t* next_minidump_id_c_;

-  const wchar_t* next_minidump_path_c_;

-

-  HMODULE dbghelp_module_;

-  MiniDumpWriteDump_type minidump_write_dump_;

-  MINIDUMP_TYPE dump_type_;

-

-  HMODULE rpcrt4_module_;

-  UuidCreate_type uuid_create_;

-

-  // Tracks the handler types that were installed according to the

-  // handler_types constructor argument.

-  int handler_types_;

-

-  // When installed_handler_ is true, previous_filter_ is the unhandled

-  // exception filter that was set prior to installing ExceptionHandler as

-  // the unhandled exception filter and pointing it to |this|.  NULL indicates

-  // that there is no previous unhandled exception filter.

-  LPTOP_LEVEL_EXCEPTION_FILTER previous_filter_;

-

-#if _MSC_VER >= 1400  // MSVC 2005/8

-  // Beginning in VC 8, the CRT provides an invalid parameter handler that will

-  // be called when some CRT functions are passed invalid parameters.  In

-  // earlier CRTs, the same conditions would cause unexpected behavior or

-  // crashes.

-  _invalid_parameter_handler previous_iph_;

-#endif  // _MSC_VER >= 1400

-

-  // The CRT allows you to override the default handler for pure

-  // virtual function calls.

-  _purecall_handler previous_pch_;

-

-  // The exception handler thread.

-  HANDLE handler_thread_;

-

-  // True if the exception handler is being destroyed.

-  // Starting with MSVC 2005, Visual C has stronger guarantees on volatile vars.

-  // It has release semantics on write and acquire semantics on reads.

-  // See the msdn documentation.

-  volatile bool is_shutdown_;

-

-  // The critical section enforcing the requirement that only one exception be

-  // handled by a handler at a time.

-  CRITICAL_SECTION handler_critical_section_;

-

-  // Semaphores used to move exception handling between the exception thread

-  // and the handler thread.  handler_start_semaphore_ is signalled by the

-  // exception thread to wake up the handler thread when an exception occurs.

-  // handler_finish_semaphore_ is signalled by the handler thread to wake up

-  // the exception thread when handling is complete.

-  HANDLE handler_start_semaphore_;

-  HANDLE handler_finish_semaphore_;

-

-  // The next 2 fields contain data passed from the requesting thread to

-  // the handler thread.

-

-  // The thread ID of the thread requesting the dump (either the exception

-  // thread or any other thread that called WriteMinidump directly).

-  DWORD requesting_thread_id_;

-

-  // The exception info passed to the exception handler on the exception

-  // thread, if an exception occurred.  NULL for user-requested dumps.

-  EXCEPTION_POINTERS* exception_info_;

-

-  // If the handler is invoked due to an assertion, this will contain a

-  // pointer to the assertion information.  It is NULL at other times.

-  MDRawAssertionInfo* assertion_;

-

-  // The return value of the handler, passed from the handler thread back to

-  // the requesting thread.

-  bool handler_return_value_;

-

-  // If true, the handler will intercept EXCEPTION_BREAKPOINT and

-  // EXCEPTION_SINGLE_STEP exceptions.  Leave this false (the default)

-  // to not interfere with debuggers.

-  bool handle_debug_exceptions_;

-

-  // A stack of ExceptionHandler objects that have installed unhandled

-  // exception filters.  This vector is used by HandleException to determine

-  // which ExceptionHandler object to route an exception to.  When an

-  // ExceptionHandler is created with install_handler true, it will append

-  // itself to this list.

-  static vector<ExceptionHandler*>* handler_stack_;

-

-  // The index of the ExceptionHandler in handler_stack_ that will handle the

-  // next exception.  Note that 0 means the last entry in handler_stack_, 1

-  // means the next-to-last entry, and so on.  This is used by HandleException

-  // to support multiple stacked Breakpad handlers.

-  static LONG handler_stack_index_;

-

-  // handler_stack_critical_section_ guards operations on handler_stack_ and

-  // handler_stack_index_. The critical section is initialized by the

-  // first instance of the class and destroyed by the last instance of it.

-  static CRITICAL_SECTION handler_stack_critical_section_;

-

-  // The number of instances of this class.

-  volatile static LONG instance_count_;

-

-  // disallow copy ctor and operator=

-  explicit ExceptionHandler(const ExceptionHandler &);

-  void operator=(const ExceptionHandler &);

-};

-

-}  // namespace google_breakpad

-

-#pragma warning( pop )

-

-#endif  // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__

+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// ExceptionHandler can write a minidump file when an exception occurs,
+// or when WriteMinidump() is called explicitly by your program.
+//
+// To have the exception handler write minidumps when an uncaught exception
+// (crash) occurs, you should create an instance early in the execution
+// of your program, and keep it around for the entire time you want to
+// have crash handling active (typically, until shutdown).
+//
+// If you want to write minidumps without installing the exception handler,
+// you can create an ExceptionHandler with install_handler set to false,
+// then call WriteMinidump.  You can also use this technique if you want to
+// use different minidump callbacks for different call sites.
+//
+// In either case, a callback function is called when a minidump is written,
+// which receives the unqiue id of the minidump.  The caller can use this
+// id to collect and write additional application state, and to launch an
+// external crash-reporting application.
+//
+// It is important that creation and destruction of ExceptionHandler objects
+// be nested cleanly, when using install_handler = true.
+// Avoid the following pattern:
+//   ExceptionHandler *e = new ExceptionHandler(...);
+//   ExceptionHandler *f = new ExceptionHandler(...);
+//   delete e;
+// This will put the exception filter stack into an inconsistent state.
+
+#ifndef CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
+#define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
+
+#include <stdlib.h>
+#include <Windows.h>
+#include <DbgHelp.h>
+#include <rpc.h>
+
+#pragma warning( push )
+// Disable exception handler warnings.
+#pragma warning( disable : 4530 )
+
+#include <string>
+#include <vector>
+
+#include "client/windows/common/ipc_protocol.h"
+#include "client/windows/crash_generation/crash_generation_client.h"
+#include "google_breakpad/common/minidump_format.h"
+#include "processor/scoped_ptr.h"
+
+namespace google_breakpad {
+
+using std::vector;
+using std::wstring;
+
+class ExceptionHandler {
+ public:
+  // A callback function to run before Breakpad performs any substantial
+  // processing of an exception.  A FilterCallback is called before writing
+  // a minidump.  context is the parameter supplied by the user as
+  // callback_context when the handler was created.  exinfo points to the
+  // exception record, if any; assertion points to assertion information,
+  // if any.
+  //
+  // If a FilterCallback returns true, Breakpad will continue processing,
+  // attempting to write a minidump.  If a FilterCallback returns false, Breakpad
+  // will immediately report the exception as unhandled without writing a
+  // minidump, allowing another handler the opportunity to handle it.
+  typedef bool (*FilterCallback)(void* context, EXCEPTION_POINTERS* exinfo,
+                                 MDRawAssertionInfo* assertion);
+
+  // A callback function to run after the minidump has been written.
+  // minidump_id is a unique id for the dump, so the minidump
+  // file is <dump_path>\<minidump_id>.dmp.  context is the parameter supplied
+  // by the user as callback_context when the handler was created.  exinfo
+  // points to the exception record, or NULL if no exception occurred.
+  // succeeded indicates whether a minidump file was successfully written.
+  // assertion points to information about an assertion if the handler was
+  // invoked by an assertion.
+  //
+  // If an exception occurred and the callback returns true, Breakpad will treat
+  // the exception as fully-handled, suppressing any other handlers from being
+  // notified of the exception.  If the callback returns false, Breakpad will
+  // treat the exception as unhandled, and allow another handler to handle it.
+  // If there are no other handlers, Breakpad will report the exception to the
+  // system as unhandled, allowing a debugger or native crash dialog the
+  // opportunity to handle the exception.  Most callback implementations
+  // should normally return the value of |succeeded|, or when they wish to
+  // not report an exception of handled, false.  Callbacks will rarely want to
+  // return true directly (unless |succeeded| is true).
+  //
+  // For out-of-process dump generation, dump path and minidump ID will always
+  // be NULL. In case of out-of-process dump generation, the dump path and
+  // minidump id are controlled by the server process and are not communicated
+  // back to the crashing process.
+  typedef bool (*MinidumpCallback)(const wchar_t* dump_path,
+                                   const wchar_t* minidump_id,
+                                   void* context,
+                                   EXCEPTION_POINTERS* exinfo,
+                                   MDRawAssertionInfo* assertion,
+                                   bool succeeded);
+
+  // HandlerType specifies which types of handlers should be installed, if
+  // any.  Use HANDLER_NONE for an ExceptionHandler that remains idle,
+  // without catching any failures on its own.  This type of handler may
+  // still be triggered by calling WriteMinidump.  Otherwise, use a
+  // combination of the other HANDLER_ values, or HANDLER_ALL to install
+  // all handlers.
+  enum HandlerType {
+    HANDLER_NONE = 0,
+    HANDLER_EXCEPTION = 1 << 0,          // SetUnhandledExceptionFilter
+    HANDLER_INVALID_PARAMETER = 1 << 1,  // _set_invalid_parameter_handler
+    HANDLER_PURECALL = 1 << 2,           // _set_purecall_handler
+    HANDLER_ALL = HANDLER_EXCEPTION |
+                  HANDLER_INVALID_PARAMETER |
+                  HANDLER_PURECALL
+  };
+
+  // Creates a new ExceptionHandler instance to handle writing minidumps.
+  // Before writing a minidump, the optional filter callback will be called.
+  // Its return value determines whether or not Breakpad should write a
+  // minidump.  Minidump files will be written to dump_path, and the optional
+  // callback is called after writing the dump file, as described above.
+  // handler_types specifies the types of handlers that should be installed.
+  ExceptionHandler(const wstring& dump_path,
+                   FilterCallback filter,
+                   MinidumpCallback callback,
+                   void* callback_context,
+                   int handler_types);
+
+  // Creates a new ExcetpionHandler instance that can attempt to perform
+  // out-of-process dump generation if pipe_name is not NULL. If pipe_name is
+  // NULL, or if out-of-process dump generation registration step fails,
+  // in-process dump generation will be used. This also allows specifying
+  // the dump type to generate.
+  ExceptionHandler(const wstring& dump_path,
+                   FilterCallback filter,
+                   MinidumpCallback callback,
+                   void* callback_context,
+                   int handler_types,
+                   MINIDUMP_TYPE dump_type,
+                   const wchar_t* pipe_name,
+                   const CustomClientInfo* custom_info);
+
+  ~ExceptionHandler();
+
+  // Get and set the minidump path.
+  wstring dump_path() const { return dump_path_; }
+  void set_dump_path(const wstring &dump_path) {
+    dump_path_ = dump_path;
+    dump_path_c_ = dump_path_.c_str();
+    UpdateNextID();  // Necessary to put dump_path_ in next_minidump_path_.
+  }
+
+  // Writes a minidump immediately.  This can be used to capture the
+  // execution state independently of a crash.  Returns true on success.
+  bool WriteMinidump();
+
+  // Writes a minidump immediately, with the user-supplied exception
+  // information.
+  bool WriteMinidumpForException(EXCEPTION_POINTERS* exinfo);
+
+  // Convenience form of WriteMinidump which does not require an
+  // ExceptionHandler instance.
+  static bool WriteMinidump(const wstring &dump_path,
+                            MinidumpCallback callback, void* callback_context);
+
+  // Get the thread ID of the thread requesting the dump (either the exception
+  // thread or any other thread that called WriteMinidump directly).  This
+  // may be useful if you want to include additional thread state in your
+  // dumps.
+  DWORD get_requesting_thread_id() const { return requesting_thread_id_; }
+
+  // Controls behavior of EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP.
+  bool get_handle_debug_exceptions() const { return handle_debug_exceptions_; }
+  void set_handle_debug_exceptions(bool handle_debug_exceptions) {
+    handle_debug_exceptions_ = handle_debug_exceptions;
+  }
+
+  // Returns whether out-of-process dump generation is used or not.
+  bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; }
+
+ private:
+  friend class AutoExceptionHandler;
+
+  // Initializes the instance with given values.
+  void Initialize(const wstring& dump_path,
+                  FilterCallback filter,
+                  MinidumpCallback callback,
+                  void* callback_context,
+                  int handler_types,
+                  MINIDUMP_TYPE dump_type,
+                  const wchar_t* pipe_name,
+                  const CustomClientInfo* custom_info);
+
+  // Function pointer type for MiniDumpWriteDump, which is looked up
+  // dynamically.
+  typedef BOOL (WINAPI *MiniDumpWriteDump_type)(
+      HANDLE hProcess,
+      DWORD dwPid,
+      HANDLE hFile,
+      MINIDUMP_TYPE DumpType,
+      CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+      CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+      CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+
+  // Function pointer type for UuidCreate, which is looked up dynamically.
+  typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID* Uuid);
+
+  // Runs the main loop for the exception handler thread.
+  static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter);
+
+  // Called on the exception thread when an unhandled exception occurs.
+  // Signals the exception handler thread to handle the exception.
+  static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo);
+
+#if _MSC_VER >= 1400  // MSVC 2005/8
+  // This function will be called by some CRT functions when they detect
+  // that they were passed an invalid parameter.  Note that in _DEBUG builds,
+  // the CRT may display an assertion dialog before calling this function,
+  // and the function will not be called unless the assertion dialog is
+  // dismissed by clicking "Ignore."
+  static void HandleInvalidParameter(const wchar_t* expression,
+                                     const wchar_t* function,
+                                     const wchar_t* file,
+                                     unsigned int line,
+                                     uintptr_t reserved);
+#endif  // _MSC_VER >= 1400
+
+  // This function will be called by the CRT when a pure virtual
+  // function is called.
+  static void HandlePureVirtualCall();
+
+  // This is called on the exception thread or on another thread that
+  // the user wishes to produce a dump from.  It calls
+  // WriteMinidumpWithException on the handler thread, avoiding stack
+  // overflows and inconsistent dumps due to writing the dump from
+  // the exception thread.  If the dump is requested as a result of an
+  // exception, exinfo contains exception information, otherwise, it
+  // is NULL.  If the dump is requested as a result of an assertion
+  // (such as an invalid parameter being passed to a CRT function),
+  // assertion contains data about the assertion, otherwise, it is NULL.
+  bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS* exinfo,
+                                    MDRawAssertionInfo* assertion);
+
+  // This function does the actual writing of a minidump.  It is called
+  // on the handler thread.  requesting_thread_id is the ID of the thread
+  // that requested the dump.  If the dump is requested as a result of
+  // an exception, exinfo contains exception information, otherwise,
+  // it is NULL.
+  bool WriteMinidumpWithException(DWORD requesting_thread_id,
+                                  EXCEPTION_POINTERS* exinfo,
+                                  MDRawAssertionInfo* assertion);
+
+  // Generates a new ID and stores it in next_minidump_id_, and stores the
+  // path of the next minidump to be written in next_minidump_path_.
+  void UpdateNextID();
+
+  FilterCallback filter_;
+  MinidumpCallback callback_;
+  void* callback_context_;
+
+  scoped_ptr<CrashGenerationClient> crash_generation_client_;
+
+  // The directory in which a minidump will be written, set by the dump_path
+  // argument to the constructor, or set_dump_path.
+  wstring dump_path_;
+
+  // The basename of the next minidump to be written, without the extension.
+  wstring next_minidump_id_;
+
+  // The full pathname of the next minidump to be written, including the file
+  // extension.
+  wstring next_minidump_path_;
+
+  // Pointers to C-string representations of the above.  These are set when
+  // the above wstring versions are set in order to avoid calling c_str during
+  // an exception, as c_str may attempt to allocate heap memory.  These
+  // pointers are not owned by the ExceptionHandler object, but their lifetimes
+  // should be equivalent to the lifetimes of the associated wstring, provided
+  // that the wstrings are not altered.
+  const wchar_t* dump_path_c_;
+  const wchar_t* next_minidump_id_c_;
+  const wchar_t* next_minidump_path_c_;
+
+  HMODULE dbghelp_module_;
+  MiniDumpWriteDump_type minidump_write_dump_;
+  MINIDUMP_TYPE dump_type_;
+
+  HMODULE rpcrt4_module_;
+  UuidCreate_type uuid_create_;
+
+  // Tracks the handler types that were installed according to the
+  // handler_types constructor argument.
+  int handler_types_;
+
+  // When installed_handler_ is true, previous_filter_ is the unhandled
+  // exception filter that was set prior to installing ExceptionHandler as
+  // the unhandled exception filter and pointing it to |this|.  NULL indicates
+  // that there is no previous unhandled exception filter.
+  LPTOP_LEVEL_EXCEPTION_FILTER previous_filter_;
+
+#if _MSC_VER >= 1400  // MSVC 2005/8
+  // Beginning in VC 8, the CRT provides an invalid parameter handler that will
+  // be called when some CRT functions are passed invalid parameters.  In
+  // earlier CRTs, the same conditions would cause unexpected behavior or
+  // crashes.
+  _invalid_parameter_handler previous_iph_;
+#endif  // _MSC_VER >= 1400
+
+  // The CRT allows you to override the default handler for pure
+  // virtual function calls.
+  _purecall_handler previous_pch_;
+
+  // The exception handler thread.
+  HANDLE handler_thread_;
+
+  // True if the exception handler is being destroyed.
+  // Starting with MSVC 2005, Visual C has stronger guarantees on volatile vars.
+  // It has release semantics on write and acquire semantics on reads.
+  // See the msdn documentation.
+  volatile bool is_shutdown_;
+
+  // The critical section enforcing the requirement that only one exception be
+  // handled by a handler at a time.
+  CRITICAL_SECTION handler_critical_section_;
+
+  // Semaphores used to move exception handling between the exception thread
+  // and the handler thread.  handler_start_semaphore_ is signalled by the
+  // exception thread to wake up the handler thread when an exception occurs.
+  // handler_finish_semaphore_ is signalled by the handler thread to wake up
+  // the exception thread when handling is complete.
+  HANDLE handler_start_semaphore_;
+  HANDLE handler_finish_semaphore_;
+
+  // The next 2 fields contain data passed from the requesting thread to
+  // the handler thread.
+
+  // The thread ID of the thread requesting the dump (either the exception
+  // thread or any other thread that called WriteMinidump directly).
+  DWORD requesting_thread_id_;
+
+  // The exception info passed to the exception handler on the exception
+  // thread, if an exception occurred.  NULL for user-requested dumps.
+  EXCEPTION_POINTERS* exception_info_;
+
+  // If the handler is invoked due to an assertion, this will contain a
+  // pointer to the assertion information.  It is NULL at other times.
+  MDRawAssertionInfo* assertion_;
+
+  // The return value of the handler, passed from the handler thread back to
+  // the requesting thread.
+  bool handler_return_value_;
+
+  // If true, the handler will intercept EXCEPTION_BREAKPOINT and
+  // EXCEPTION_SINGLE_STEP exceptions.  Leave this false (the default)
+  // to not interfere with debuggers.
+  bool handle_debug_exceptions_;
+
+  // A stack of ExceptionHandler objects that have installed unhandled
+  // exception filters.  This vector is used by HandleException to determine
+  // which ExceptionHandler object to route an exception to.  When an
+  // ExceptionHandler is created with install_handler true, it will append
+  // itself to this list.
+  static vector<ExceptionHandler*>* handler_stack_;
+
+  // The index of the ExceptionHandler in handler_stack_ that will handle the
+  // next exception.  Note that 0 means the last entry in handler_stack_, 1
+  // means the next-to-last entry, and so on.  This is used by HandleException
+  // to support multiple stacked Breakpad handlers.
+  static LONG handler_stack_index_;
+
+  // handler_stack_critical_section_ guards operations on handler_stack_ and
+  // handler_stack_index_. The critical section is initialized by the
+  // first instance of the class and destroyed by the last instance of it.
+  static CRITICAL_SECTION handler_stack_critical_section_;
+
+  // The number of instances of this class.
+  volatile static LONG instance_count_;
+
+  // disallow copy ctor and operator=
+  explicit ExceptionHandler(const ExceptionHandler &);
+  void operator=(const ExceptionHandler &);
+};
+
+}  // namespace google_breakpad
+
+#pragma warning( pop )
+
+#endif  // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__
diff --git a/third_party/breakpad/src/client/windows/sender/crash_report_sender.cc b/third_party/breakpad/src/client/windows/sender/crash_report_sender.cc
index 601ac09..3d16ef2 100644
--- a/third_party/breakpad/src/client/windows/sender/crash_report_sender.cc
+++ b/third_party/breakpad/src/client/windows/sender/crash_report_sender.cc
@@ -1,143 +1,143 @@
-// Copyright (c) 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-// Disable exception handler warnings.

-#pragma warning( disable : 4530 )

-

-#include <errno.h>

-

-#include "client/windows/sender/crash_report_sender.h"

-#include "common/windows/http_upload.h"

-

-#if _MSC_VER < 1400  // MSVC 2005/8

-// Older MSVC doesn't have fscanf_s, but they are compatible as long as

-// we don't use the string conversions (%s/%c/%S/%C).

-#define fscanf_s fscanf

-#endif

-

-namespace google_breakpad {

-

-static const char kCheckpointSignature[] = "GBP1\n";

-

-CrashReportSender::CrashReportSender(const wstring &checkpoint_file)

-    : checkpoint_file_(checkpoint_file),

-      max_reports_per_day_(-1),

-      last_sent_date_(-1),

-      reports_sent_(0) {

-  FILE *fd;

-  if (OpenCheckpointFile(L"r", &fd) == 0) {

-    ReadCheckpoint(fd);

-    fclose(fd);

-  }

-}

-

-ReportResult CrashReportSender::SendCrashReport(

-    const wstring &url, const map<wstring, wstring> &parameters,

-    const wstring &dump_file_name, wstring *report_code) {

-  int today = GetCurrentDate();

-  if (today == last_sent_date_ &&

-      max_reports_per_day_ != -1 &&

-      reports_sent_ >= max_reports_per_day_) {

-    return RESULT_THROTTLED;

-  }

-

-  int http_response = 0;

-  bool result = HTTPUpload::SendRequest(

-    url, parameters, dump_file_name, L"upload_file_minidump", NULL, report_code,

-    &http_response);

-

-  if (result) {

-    ReportSent(today);

-    return RESULT_SUCCEEDED;

-  } else if (http_response == 400) {  // TODO: update if/when the server

-                                      //       switches to a different code

-    return RESULT_REJECTED;

-  } else {

-    return RESULT_FAILED;

-  }

-}

-

-void CrashReportSender::ReadCheckpoint(FILE *fd) {

-  char buf[128];

-  if (!fgets(buf, sizeof(buf), fd) ||

-      strcmp(buf, kCheckpointSignature) != 0) {

-    return;

-  }

-

-  if (fscanf_s(fd, "%d\n", &last_sent_date_) != 1) {

-    last_sent_date_ = -1;

-    return;

-  }

-  if (fscanf_s(fd, "%d\n", &reports_sent_) != 1) {

-    reports_sent_ = 0;

-    return;

-  }

-}

-

-void CrashReportSender::ReportSent(int today) {

-  // Update the report stats

-  if (today != last_sent_date_) {

-    last_sent_date_ = today;

-    reports_sent_ = 0;

-  }

-  ++reports_sent_;

-

-  // Update the checkpoint file

-  FILE *fd;

-  if (OpenCheckpointFile(L"w", &fd) == 0) {

-    fputs(kCheckpointSignature, fd);

-    fprintf(fd, "%d\n", last_sent_date_);

-    fprintf(fd, "%d\n", reports_sent_);

-    fclose(fd);

-  }

-}

-

-int CrashReportSender::GetCurrentDate() const {

-  SYSTEMTIME system_time;

-  GetSystemTime(&system_time);

-  return (system_time.wYear * 10000) + (system_time.wMonth * 100) +

-      system_time.wDay;

-}

-

-int CrashReportSender::OpenCheckpointFile(const wchar_t *mode, FILE **fd) {

-  if (checkpoint_file_.empty()) {

-    return ENOENT;

-  }

-#if _MSC_VER >= 1400  // MSVC 2005/8

-  return _wfopen_s(fd, checkpoint_file_.c_str(), mode);

-#else

-  *fd = _wfopen(checkpoint_file_.c_str(), mode);

-  if (*fd == NULL) {

-    return errno;

-  }

-  return 0;

-#endif

-}

-

-}  // namespace google_breakpad

+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Disable exception handler warnings.
+#pragma warning( disable : 4530 )
+
+#include <errno.h>
+
+#include "client/windows/sender/crash_report_sender.h"
+#include "common/windows/http_upload.h"
+
+#if _MSC_VER < 1400  // MSVC 2005/8
+// Older MSVC doesn't have fscanf_s, but they are compatible as long as
+// we don't use the string conversions (%s/%c/%S/%C).
+#define fscanf_s fscanf
+#endif
+
+namespace google_breakpad {
+
+static const char kCheckpointSignature[] = "GBP1\n";
+
+CrashReportSender::CrashReportSender(const wstring &checkpoint_file)
+    : checkpoint_file_(checkpoint_file),
+      max_reports_per_day_(-1),
+      last_sent_date_(-1),
+      reports_sent_(0) {
+  FILE *fd;
+  if (OpenCheckpointFile(L"r", &fd) == 0) {
+    ReadCheckpoint(fd);
+    fclose(fd);
+  }
+}
+
+ReportResult CrashReportSender::SendCrashReport(
+    const wstring &url, const map<wstring, wstring> &parameters,
+    const wstring &dump_file_name, wstring *report_code) {
+  int today = GetCurrentDate();
+  if (today == last_sent_date_ &&
+      max_reports_per_day_ != -1 &&
+      reports_sent_ >= max_reports_per_day_) {
+    return RESULT_THROTTLED;
+  }
+
+  int http_response = 0;
+  bool result = HTTPUpload::SendRequest(
+    url, parameters, dump_file_name, L"upload_file_minidump", NULL, report_code,
+    &http_response);
+
+  if (result) {
+    ReportSent(today);
+    return RESULT_SUCCEEDED;
+  } else if (http_response == 400) {  // TODO: update if/when the server
+                                      //       switches to a different code
+    return RESULT_REJECTED;
+  } else {
+    return RESULT_FAILED;
+  }
+}
+
+void CrashReportSender::ReadCheckpoint(FILE *fd) {
+  char buf[128];
+  if (!fgets(buf, sizeof(buf), fd) ||
+      strcmp(buf, kCheckpointSignature) != 0) {
+    return;
+  }
+
+  if (fscanf_s(fd, "%d\n", &last_sent_date_) != 1) {
+    last_sent_date_ = -1;
+    return;
+  }
+  if (fscanf_s(fd, "%d\n", &reports_sent_) != 1) {
+    reports_sent_ = 0;
+    return;
+  }
+}
+
+void CrashReportSender::ReportSent(int today) {
+  // Update the report stats
+  if (today != last_sent_date_) {
+    last_sent_date_ = today;
+    reports_sent_ = 0;
+  }
+  ++reports_sent_;
+
+  // Update the checkpoint file
+  FILE *fd;
+  if (OpenCheckpointFile(L"w", &fd) == 0) {
+    fputs(kCheckpointSignature, fd);
+    fprintf(fd, "%d\n", last_sent_date_);
+    fprintf(fd, "%d\n", reports_sent_);
+    fclose(fd);
+  }
+}
+
+int CrashReportSender::GetCurrentDate() const {
+  SYSTEMTIME system_time;
+  GetSystemTime(&system_time);
+  return (system_time.wYear * 10000) + (system_time.wMonth * 100) +
+      system_time.wDay;
+}
+
+int CrashReportSender::OpenCheckpointFile(const wchar_t *mode, FILE **fd) {
+  if (checkpoint_file_.empty()) {
+    return ENOENT;
+  }
+#if _MSC_VER >= 1400  // MSVC 2005/8
+  return _wfopen_s(fd, checkpoint_file_.c_str(), mode);
+#else
+  *fd = _wfopen(checkpoint_file_.c_str(), mode);
+  if (*fd == NULL) {
+    return errno;
+  }
+  return 0;
+#endif
+}
+
+}  // namespace google_breakpad
diff --git a/third_party/breakpad/src/client/windows/sender/crash_report_sender.h b/third_party/breakpad/src/client/windows/sender/crash_report_sender.h
index c6976a1..da1ed0a 100644
--- a/third_party/breakpad/src/client/windows/sender/crash_report_sender.h
+++ b/third_party/breakpad/src/client/windows/sender/crash_report_sender.h
@@ -1,125 +1,125 @@
-// Copyright (c) 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#ifndef CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__

-#define CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__

-

-// CrashReportSender is a "static" class which provides an API to upload

-// crash reports via HTTP(S).  A crash report is formatted as a multipart POST

-// request, which contains a set of caller-supplied string key/value pairs,

-// and a minidump file to upload.

-//

-// To use this library in your project, you will need to link against

-// wininet.lib.

-

-#pragma warning( push )

-// Disable exception handler warnings.

-#pragma warning( disable : 4530 ) 

-

-#include <map>

-#include <string>

-

-namespace google_breakpad {

-

-using std::wstring;

-using std::map;

-

-typedef enum {

-  RESULT_FAILED = 0,  // Failed to communicate with the server; try later.

-  RESULT_REJECTED,    // Successfully sent the crash report, but the

-                      // server rejected it; don't resend this report.

-  RESULT_SUCCEEDED,   // The server accepted the crash report.

-  RESULT_THROTTLED    // No attempt was made to send the crash report, because

-                      // we exceeded the maximum reports per day.

-} ReportResult;

-

-class CrashReportSender {

- public:

-  // Initializes a CrashReportSender instance.

-  // If checkpoint_file is non-empty, breakpad will persist crash report

-  // state to this file.  A checkpoint file is required for

-  // set_max_reports_per_day() to function properly.

-  explicit CrashReportSender(const wstring &checkpoint_file);

-  ~CrashReportSender() {}

-

-  // Sets the maximum number of crash reports that will be sent in a 24-hour

-  // period.  This uses the state persisted to the checkpoint file.

-  // The default value of -1 means that there is no limit on reports sent.

-  void set_max_reports_per_day(int reports) {

-    max_reports_per_day_ = reports;

-  }

-

-  int max_reports_per_day() const { return max_reports_per_day_; }

-

-  // Sends the specified minidump file, along with the map of

-  // name value pairs, as a multipart POST request to the given URL.

-  // Parameter names must contain only printable ASCII characters,

-  // and may not contain a quote (") character.

-  // Only HTTP(S) URLs are currently supported.  The return value indicates

-  // the result of the operation (see above for possible results).

-  // If report_code is non-NULL and the report is sent successfully (that is,

-  // the return value is RESULT_SUCCEEDED), a code uniquely identifying the

-  // report will be returned in report_code.

-  // (Otherwise, report_code will be unchanged.)

-  ReportResult SendCrashReport(const wstring &url,

-                               const map<wstring, wstring> &parameters,

-                               const wstring &dump_file_name,

-                               wstring *report_code);

-

- private:

-  // Reads persistent state from a checkpoint file.

-  void ReadCheckpoint(FILE *fd);

-

-  // Called when a new report has been sent, to update the checkpoint state.

-  void ReportSent(int today);

-

-  // Returns today's date (UTC) formatted as YYYYMMDD.

-  int GetCurrentDate() const;

-

-  // Opens the checkpoint file with the specified mode.

-  // Returns zero on success, or an error code on failure.

-  int OpenCheckpointFile(const wchar_t *mode, FILE **fd);

-

-  wstring checkpoint_file_;

-  int max_reports_per_day_;

-  // The last date on which we sent a report, expressed as YYYYMMDD.

-  int last_sent_date_;

-  // Number of reports sent on last_sent_date_

-  int reports_sent_;

-

-  // Disallow copy constructor and operator=

-  explicit CrashReportSender(const CrashReportSender &);

-  void operator=(const CrashReportSender &);

-};

-

-}  // namespace google_breakpad

-

-#pragma warning( pop )

-

-#endif  // CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__

+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__
+#define CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__
+
+// CrashReportSender is a "static" class which provides an API to upload
+// crash reports via HTTP(S).  A crash report is formatted as a multipart POST
+// request, which contains a set of caller-supplied string key/value pairs,
+// and a minidump file to upload.
+//
+// To use this library in your project, you will need to link against
+// wininet.lib.
+
+#pragma warning( push )
+// Disable exception handler warnings.
+#pragma warning( disable : 4530 ) 
+
+#include <map>
+#include <string>
+
+namespace google_breakpad {
+
+using std::wstring;
+using std::map;
+
+typedef enum {
+  RESULT_FAILED = 0,  // Failed to communicate with the server; try later.
+  RESULT_REJECTED,    // Successfully sent the crash report, but the
+                      // server rejected it; don't resend this report.
+  RESULT_SUCCEEDED,   // The server accepted the crash report.
+  RESULT_THROTTLED    // No attempt was made to send the crash report, because
+                      // we exceeded the maximum reports per day.
+} ReportResult;
+
+class CrashReportSender {
+ public:
+  // Initializes a CrashReportSender instance.
+  // If checkpoint_file is non-empty, breakpad will persist crash report
+  // state to this file.  A checkpoint file is required for
+  // set_max_reports_per_day() to function properly.
+  explicit CrashReportSender(const wstring &checkpoint_file);
+  ~CrashReportSender() {}
+
+  // Sets the maximum number of crash reports that will be sent in a 24-hour
+  // period.  This uses the state persisted to the checkpoint file.
+  // The default value of -1 means that there is no limit on reports sent.
+  void set_max_reports_per_day(int reports) {
+    max_reports_per_day_ = reports;
+  }
+
+  int max_reports_per_day() const { return max_reports_per_day_; }
+
+  // Sends the specified minidump file, along with the map of
+  // name value pairs, as a multipart POST request to the given URL.
+  // Parameter names must contain only printable ASCII characters,
+  // and may not contain a quote (") character.
+  // Only HTTP(S) URLs are currently supported.  The return value indicates
+  // the result of the operation (see above for possible results).
+  // If report_code is non-NULL and the report is sent successfully (that is,
+  // the return value is RESULT_SUCCEEDED), a code uniquely identifying the
+  // report will be returned in report_code.
+  // (Otherwise, report_code will be unchanged.)
+  ReportResult SendCrashReport(const wstring &url,
+                               const map<wstring, wstring> &parameters,
+                               const wstring &dump_file_name,
+                               wstring *report_code);
+
+ private:
+  // Reads persistent state from a checkpoint file.
+  void ReadCheckpoint(FILE *fd);
+
+  // Called when a new report has been sent, to update the checkpoint state.
+  void ReportSent(int today);
+
+  // Returns today's date (UTC) formatted as YYYYMMDD.
+  int GetCurrentDate() const;
+
+  // Opens the checkpoint file with the specified mode.
+  // Returns zero on success, or an error code on failure.
+  int OpenCheckpointFile(const wchar_t *mode, FILE **fd);
+
+  wstring checkpoint_file_;
+  int max_reports_per_day_;
+  // The last date on which we sent a report, expressed as YYYYMMDD.
+  int last_sent_date_;
+  // Number of reports sent on last_sent_date_
+  int reports_sent_;
+
+  // Disallow copy constructor and operator=
+  explicit CrashReportSender(const CrashReportSender &);
+  void operator=(const CrashReportSender &);
+};
+
+}  // namespace google_breakpad
+
+#pragma warning( pop )
+
+#endif  // CLIENT_WINDOWS_SENDER_CRASH_REPORT_SENDER_H__
diff --git a/third_party/breakpad/src/common/windows/guid_string.cc b/third_party/breakpad/src/common/windows/guid_string.cc
index e39316d..b7f877e 100644
--- a/third_party/breakpad/src/common/windows/guid_string.cc
+++ b/third_party/breakpad/src/common/windows/guid_string.cc
@@ -1,76 +1,76 @@
-// Copyright (c) 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-// guid_string.cc: Convert GUIDs to strings.

-//

-// See guid_string.h for documentation.

-

-#include <wchar.h>

-

-#include "common/windows/string_utils-inl.h"

-

-#include "common/windows/guid_string.h"

-

-namespace google_breakpad {

-

-// static

-wstring GUIDString::GUIDToWString(GUID *guid) {

-  wchar_t guid_string[37];

-  swprintf(

-      guid_string, sizeof(guid_string) / sizeof(guid_string[0]),

-      L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",

-      guid->Data1, guid->Data2, guid->Data3,

-      guid->Data4[0], guid->Data4[1], guid->Data4[2],

-      guid->Data4[3], guid->Data4[4], guid->Data4[5],

-      guid->Data4[6], guid->Data4[7]);

-

-  // remove when VC++7.1 is no longer supported

-  guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0';

-

-  return wstring(guid_string);

-}

-

-// static

-wstring GUIDString::GUIDToSymbolServerWString(GUID *guid) {

-  wchar_t guid_string[33];

-  swprintf(

-      guid_string, sizeof(guid_string) / sizeof(guid_string[0]),

-      L"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",

-      guid->Data1, guid->Data2, guid->Data3,

-      guid->Data4[0], guid->Data4[1], guid->Data4[2],

-      guid->Data4[3], guid->Data4[4], guid->Data4[5],

-      guid->Data4[6], guid->Data4[7]);

-

-  // remove when VC++7.1 is no longer supported

-  guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0';

-

-  return wstring(guid_string);

-}

-

-}  // namespace google_breakpad

+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// guid_string.cc: Convert GUIDs to strings.
+//
+// See guid_string.h for documentation.
+
+#include <wchar.h>
+
+#include "common/windows/string_utils-inl.h"
+
+#include "common/windows/guid_string.h"
+
+namespace google_breakpad {
+
+// static
+wstring GUIDString::GUIDToWString(GUID *guid) {
+  wchar_t guid_string[37];
+  swprintf(
+      guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
+      L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+      guid->Data1, guid->Data2, guid->Data3,
+      guid->Data4[0], guid->Data4[1], guid->Data4[2],
+      guid->Data4[3], guid->Data4[4], guid->Data4[5],
+      guid->Data4[6], guid->Data4[7]);
+
+  // remove when VC++7.1 is no longer supported
+  guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0';
+
+  return wstring(guid_string);
+}
+
+// static
+wstring GUIDString::GUIDToSymbolServerWString(GUID *guid) {
+  wchar_t guid_string[33];
+  swprintf(
+      guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
+      L"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",
+      guid->Data1, guid->Data2, guid->Data3,
+      guid->Data4[0], guid->Data4[1], guid->Data4[2],
+      guid->Data4[3], guid->Data4[4], guid->Data4[5],
+      guid->Data4[6], guid->Data4[7]);
+
+  // remove when VC++7.1 is no longer supported
+  guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0';
+
+  return wstring(guid_string);
+}
+
+}  // namespace google_breakpad
diff --git a/third_party/breakpad/src/common/windows/guid_string.h b/third_party/breakpad/src/common/windows/guid_string.h
index 34bcad3..f8aa8a2 100644
--- a/third_party/breakpad/src/common/windows/guid_string.h
+++ b/third_party/breakpad/src/common/windows/guid_string.h
@@ -1,58 +1,58 @@
-// Copyright (c) 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-// guid_string.cc: Convert GUIDs to strings.

-

-#ifndef COMMON_WINDOWS_GUID_STRING_H__

-#define COMMON_WINDOWS_GUID_STRING_H__

-

-#include <Guiddef.h>

-

-#include <string>

-

-namespace google_breakpad {

-

-using std::wstring;

-

-class GUIDString {

- public:

-  // Converts guid to a string in the format recommended by RFC 4122 and

-  // returns the string.

-  static wstring GUIDToWString(GUID *guid);

-

-  // Converts guid to a string formatted as uppercase hexadecimal, with

-  // no separators, and returns the string.  This is the format used for

-  // symbol server identifiers, although identifiers have an age tacked

-  // on to the string.

-  static wstring GUIDToSymbolServerWString(GUID *guid);

-};

-

-}  // namespace google_breakpad

-

-#endif  // COMMON_WINDOWS_GUID_STRING_H__

+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// guid_string.cc: Convert GUIDs to strings.
+
+#ifndef COMMON_WINDOWS_GUID_STRING_H__
+#define COMMON_WINDOWS_GUID_STRING_H__
+
+#include <Guiddef.h>
+
+#include <string>
+
+namespace google_breakpad {
+
+using std::wstring;
+
+class GUIDString {
+ public:
+  // Converts guid to a string in the format recommended by RFC 4122 and
+  // returns the string.
+  static wstring GUIDToWString(GUID *guid);
+
+  // Converts guid to a string formatted as uppercase hexadecimal, with
+  // no separators, and returns the string.  This is the format used for
+  // symbol server identifiers, although identifiers have an age tacked
+  // on to the string.
+  static wstring GUIDToSymbolServerWString(GUID *guid);
+};
+
+}  // namespace google_breakpad
+
+#endif  // COMMON_WINDOWS_GUID_STRING_H__
diff --git a/third_party/breakpad/src/common/windows/http_upload.cc b/third_party/breakpad/src/common/windows/http_upload.cc
index 5744f13..686c2ab 100644
--- a/third_party/breakpad/src/common/windows/http_upload.cc
+++ b/third_party/breakpad/src/common/windows/http_upload.cc
@@ -1,410 +1,410 @@
-// Copyright (c) 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-#include <assert.h>

-

-// Disable exception handler warnings.

-#pragma warning( disable : 4530 ) 

-

-#include <fstream>

-

-#include "common/windows/string_utils-inl.h"

-

-#include "common/windows/http_upload.h"

-

-namespace google_breakpad {

-

-using std::ifstream;

-using std::ios;

-

-static const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)";

-

-// Helper class which closes an internet handle when it goes away

-class HTTPUpload::AutoInternetHandle {

- public:

-  explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {}

-  ~AutoInternetHandle() {

-    if (handle_) {

-      InternetCloseHandle(handle_);

-    }

-  }

-

-  HINTERNET get() { return handle_; }

-

- private:

-  HINTERNET handle_;

-};

-

-// static

-bool HTTPUpload::SendRequest(const wstring &url,

-                             const map<wstring, wstring> &parameters,

-                             const wstring &upload_file,

-                             const wstring &file_part_name,

-                             int *timeout,

-                             wstring *response_body,

-                             int *response_code) {

-  if (response_code) {

-    *response_code = 0;

-  }

-

-  // TODO(bryner): support non-ASCII parameter names

-  if (!CheckParameters(parameters)) {

-    return false;

-  }

-

-  // Break up the URL and make sure we can handle it

-  wchar_t scheme[16], host[256], path[256];

-  URL_COMPONENTS components;

-  memset(&components, 0, sizeof(components));

-  components.dwStructSize = sizeof(components);

-  components.lpszScheme = scheme;

-  components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]);

-  components.lpszHostName = host;

-  components.dwHostNameLength = sizeof(host) / sizeof(host[0]);

-  components.lpszUrlPath = path;

-  components.dwUrlPathLength = sizeof(path) / sizeof(path[0]);

-  if (!InternetCrackUrl(url.c_str(), static_cast<DWORD>(url.size()),

-                        0, &components)) {

-    return false;

-  }

-  bool secure = false;

-  if (wcscmp(scheme, L"https") == 0) {

-    secure = true;

-  } else if (wcscmp(scheme, L"http") != 0) {

-    return false;

-  }

-

-  AutoInternetHandle internet(InternetOpen(kUserAgent,

-                                           INTERNET_OPEN_TYPE_PRECONFIG,

-                                           NULL,  // proxy name

-                                           NULL,  // proxy bypass

-                                           0));   // flags

-  if (!internet.get()) {

-    return false;

-  }

-

-  AutoInternetHandle connection(InternetConnect(internet.get(),

-                                                host,

-                                                components.nPort,

-                                                NULL,    // user name

-                                                NULL,    // password

-                                                INTERNET_SERVICE_HTTP,

-                                                0,       // flags

-                                                NULL));  // context

-  if (!connection.get()) {

-    return false;

-  }

-

-  DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0;

-  AutoInternetHandle request(HttpOpenRequest(connection.get(),

-                                             L"POST",

-                                             path,

-                                             NULL,    // version

-                                             NULL,    // referer

-                                             NULL,    // agent type

-                                             http_open_flags,

-                                             NULL));  // context

-  if (!request.get()) {

-    return false;

-  }

-

-  wstring boundary = GenerateMultipartBoundary();

-  wstring content_type_header = GenerateRequestHeader(boundary);

-  HttpAddRequestHeaders(request.get(),

-                        content_type_header.c_str(),

-                        static_cast<DWORD>(-1),

-                        HTTP_ADDREQ_FLAG_ADD);

-

-  string request_body;

-  if (!GenerateRequestBody(parameters, upload_file,

-                           file_part_name, boundary, &request_body)) {

-    return false;

-  }

-

-  if (timeout) {

-    if (!InternetSetOption(request.get(),

-                           INTERNET_OPTION_SEND_TIMEOUT,

-                           timeout,

-                           sizeof(timeout))) {

-      fwprintf(stderr, L"Could not unset send timeout, continuing...\n");

-    }

-

-    if (!InternetSetOption(request.get(),

-                           INTERNET_OPTION_RECEIVE_TIMEOUT,

-                           timeout,

-                           sizeof(timeout))) {

-      fwprintf(stderr, L"Could not unset receive timeout, continuing...\n");

-    }

-  }

-  

-  if (!HttpSendRequest(request.get(), NULL, 0,

-                       const_cast<char *>(request_body.data()),

-                       static_cast<DWORD>(request_body.size()))) {

-    return false;

-  }

-

-  // The server indicates a successful upload with HTTP status 200.

-  wchar_t http_status[4];

-  DWORD http_status_size = sizeof(http_status);

-  if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE,

-                     static_cast<LPVOID>(&http_status), &http_status_size,

-                     0)) {

-    return false;

-  }

-

-  int http_response = wcstol(http_status, NULL, 10);

-  if (response_code) {

-    *response_code = http_response;

-  }

-

-  bool result = (http_response == 200);

-

-  if (result) {

-    result = ReadResponse(request.get(), response_body);

-  }

-

-  return result;

-}

-

-// static

-bool HTTPUpload::ReadResponse(HINTERNET request, wstring *response) {

-  bool has_content_length_header = false;

-  wchar_t content_length[32];

-  DWORD content_length_size = sizeof(content_length);

-  DWORD claimed_size = 0;

-  string response_body;

-

-  if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH,

-                    static_cast<LPVOID>(&content_length),

-                    &content_length_size, 0)) {

-    has_content_length_header = true;

-    claimed_size = wcstol(content_length, NULL, 10);

-    response_body.reserve(claimed_size);

-  }

-

-

-  DWORD bytes_available;

-  DWORD total_read = 0;

-  bool return_code;

-

-  while ((return_code = InternetQueryDataAvailable(request, &bytes_available,

-                                                   0, 0) != 0) &&

-          bytes_available > 0) {

-    vector<char> response_buffer(bytes_available);

-    DWORD size_read;

-

-    if ((return_code = InternetReadFile(request, &response_buffer[0],

-                                        bytes_available, &size_read) != 0) &&

-        size_read > 0) {

-      total_read += size_read;

-      response_body.append(&response_buffer[0], size_read);

-    } else {

-      break;

-    }

-  }

-

-  bool succeeded = return_code && (!has_content_length_header ||

-                                   (total_read == claimed_size));

-  if (succeeded && response) {

-    *response = UTF8ToWide(response_body);

-  }

-

-  return succeeded;

-}

-

-// static

-wstring HTTPUpload::GenerateMultipartBoundary() {

-  // The boundary has 27 '-' characters followed by 16 hex digits

-  static const wchar_t kBoundaryPrefix[] = L"---------------------------";

-  static const int kBoundaryLength = 27 + 16 + 1;

-

-  // Generate some random numbers to fill out the boundary

-  int r0 = rand();

-  int r1 = rand();

-

-  wchar_t temp[kBoundaryLength];

-  swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1);

-

-  // remove when VC++7.1 is no longer supported

-  temp[kBoundaryLength - 1] = L'\0';

-

-  return wstring(temp);

-}

-

-// static

-wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) {

-  wstring header = L"Content-Type: multipart/form-data; boundary=";

-  header += boundary;

-  return header;

-}

-

-// static

-bool HTTPUpload::GenerateRequestBody(const map<wstring, wstring> &parameters,

-                                     const wstring &upload_file,

-                                     const wstring &file_part_name,

-                                     const wstring &boundary,

-                                     string *request_body) {

-  vector<char> contents;

-  GetFileContents(upload_file, &contents);

-  if (contents.empty()) {

-    return false;

-  }

-

-  string boundary_str = WideToUTF8(boundary);

-  if (boundary_str.empty()) {

-    return false;

-  }

-

-  request_body->clear();

-

-  // Append each of the parameter pairs as a form-data part

-  for (map<wstring, wstring>::const_iterator pos = parameters.begin();

-       pos != parameters.end(); ++pos) {

-    request_body->append("--" + boundary_str + "\r\n");

-    request_body->append("Content-Disposition: form-data; name=\"" +

-                         WideToUTF8(pos->first) + "\"\r\n\r\n" +

-                         WideToUTF8(pos->second) + "\r\n");

-  }

-

-  // Now append the upload file as a binary (octet-stream) part

-  string filename_utf8 = WideToUTF8(upload_file);

-  if (filename_utf8.empty()) {

-    return false;

-  }

-

-  string file_part_name_utf8 = WideToUTF8(file_part_name);

-  if (file_part_name_utf8.empty()) {

-    return false;

-  }

-

-  request_body->append("--" + boundary_str + "\r\n");

-  request_body->append("Content-Disposition: form-data; "

-                       "name=\"" + file_part_name_utf8 + "\"; "

-                       "filename=\"" + filename_utf8 + "\"\r\n");

-  request_body->append("Content-Type: application/octet-stream\r\n");

-  request_body->append("\r\n");

-

-  if (!contents.empty()) {

-      request_body->append(&(contents[0]), contents.size());

-  }

-  request_body->append("\r\n");

-  request_body->append("--" + boundary_str + "--\r\n");

-  return true;

-}

-

-// static

-void HTTPUpload::GetFileContents(const wstring &filename,

-                                 vector<char> *contents) {

-  // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a

-  // wchar_t* filename, so use _wfopen directly in that case.  For VC8 and

-  // later, _wfopen has been deprecated in favor of _wfopen_s, which does

-  // not exist in earlier versions, so let the ifstream open the file itself.

-#if _MSC_VER >= 1400  // MSVC 2005/8

-  ifstream file;

-  file.open(filename.c_str(), ios::binary);

-#else  // _MSC_VER >= 1400

-  ifstream file(_wfopen(filename.c_str(), L"rb"));

-#endif  // _MSC_VER >= 1400

-  if (file.is_open()) {

-    file.seekg(0, ios::end);

-    int length = file.tellg();

-    contents->resize(length);

-    if (length != 0) {

-        file.seekg(0, ios::beg);

-        file.read(&((*contents)[0]), length);

-    }

-    file.close();

-  } else {

-    contents->clear();

-  }

-}

-

-// static

-wstring HTTPUpload::UTF8ToWide(const string &utf8) {

-  if (utf8.length() == 0) {

-    return wstring();

-  }

-

-  // compute the length of the buffer we'll need

-  int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0);

-

-  if (charcount == 0) {

-    return wstring();

-  }

-

-  // convert

-  wchar_t* buf = new wchar_t[charcount];

-  MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount);

-  wstring result(buf);

-  delete[] buf;

-  return result;

-}

-

-// static

-string HTTPUpload::WideToUTF8(const wstring &wide) {

-  if (wide.length() == 0) {

-    return string();

-  }

-

-  // compute the length of the buffer we'll need

-  int charcount = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1,

-                                      NULL, 0, NULL, NULL);

-  if (charcount == 0) {

-    return string();

-  }

-

-  // convert

-  char *buf = new char[charcount];

-  WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, buf, charcount,

-                      NULL, NULL);

-

-  string result(buf);

-  delete[] buf;

-  return result;

-}

-

-// static

-bool HTTPUpload::CheckParameters(const map<wstring, wstring> &parameters) {

-  for (map<wstring, wstring>::const_iterator pos = parameters.begin();

-       pos != parameters.end(); ++pos) {

-    const wstring &str = pos->first;

-    if (str.size() == 0) {

-      return false;  // disallow empty parameter names

-    }

-    for (unsigned int i = 0; i < str.size(); ++i) {

-      wchar_t c = str[i];

-      if (c < 32 || c == '"' || c > 127) {

-        return false;

-      }

-    }

-  }

-  return true;

-}

-

-}  // namespace google_breakpad

+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <assert.h>
+
+// Disable exception handler warnings.
+#pragma warning( disable : 4530 ) 
+
+#include <fstream>
+
+#include "common/windows/string_utils-inl.h"
+
+#include "common/windows/http_upload.h"
+
+namespace google_breakpad {
+
+using std::ifstream;
+using std::ios;
+
+static const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)";
+
+// Helper class which closes an internet handle when it goes away
+class HTTPUpload::AutoInternetHandle {
+ public:
+  explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {}
+  ~AutoInternetHandle() {
+    if (handle_) {
+      InternetCloseHandle(handle_);
+    }
+  }
+
+  HINTERNET get() { return handle_; }
+
+ private:
+  HINTERNET handle_;
+};
+
+// static
+bool HTTPUpload::SendRequest(const wstring &url,
+                             const map<wstring, wstring> &parameters,
+                             const wstring &upload_file,
+                             const wstring &file_part_name,
+                             int *timeout,
+                             wstring *response_body,
+                             int *response_code) {
+  if (response_code) {
+    *response_code = 0;
+  }
+
+  // TODO(bryner): support non-ASCII parameter names
+  if (!CheckParameters(parameters)) {
+    return false;
+  }
+
+  // Break up the URL and make sure we can handle it
+  wchar_t scheme[16], host[256], path[256];
+  URL_COMPONENTS components;
+  memset(&components, 0, sizeof(components));
+  components.dwStructSize = sizeof(components);
+  components.lpszScheme = scheme;
+  components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]);
+  components.lpszHostName = host;
+  components.dwHostNameLength = sizeof(host) / sizeof(host[0]);
+  components.lpszUrlPath = path;
+  components.dwUrlPathLength = sizeof(path) / sizeof(path[0]);
+  if (!InternetCrackUrl(url.c_str(), static_cast<DWORD>(url.size()),
+                        0, &components)) {
+    return false;
+  }
+  bool secure = false;
+  if (wcscmp(scheme, L"https") == 0) {
+    secure = true;
+  } else if (wcscmp(scheme, L"http") != 0) {
+    return false;
+  }
+
+  AutoInternetHandle internet(InternetOpen(kUserAgent,
+                                           INTERNET_OPEN_TYPE_PRECONFIG,
+                                           NULL,  // proxy name
+                                           NULL,  // proxy bypass
+                                           0));   // flags
+  if (!internet.get()) {
+    return false;
+  }
+
+  AutoInternetHandle connection(InternetConnect(internet.get(),
+                                                host,
+                                                components.nPort,
+                                                NULL,    // user name
+                                                NULL,    // password
+                                                INTERNET_SERVICE_HTTP,
+                                                0,       // flags
+                                                NULL));  // context
+  if (!connection.get()) {
+    return false;
+  }
+
+  DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0;
+  AutoInternetHandle request(HttpOpenRequest(connection.get(),
+                                             L"POST",
+                                             path,
+                                             NULL,    // version
+                                             NULL,    // referer
+                                             NULL,    // agent type
+                                             http_open_flags,
+                                             NULL));  // context
+  if (!request.get()) {
+    return false;
+  }
+
+  wstring boundary = GenerateMultipartBoundary();
+  wstring content_type_header = GenerateRequestHeader(boundary);
+  HttpAddRequestHeaders(request.get(),
+                        content_type_header.c_str(),
+                        static_cast<DWORD>(-1),
+                        HTTP_ADDREQ_FLAG_ADD);
+
+  string request_body;
+  if (!GenerateRequestBody(parameters, upload_file,
+                           file_part_name, boundary, &request_body)) {
+    return false;
+  }
+
+  if (timeout) {
+    if (!InternetSetOption(request.get(),
+                           INTERNET_OPTION_SEND_TIMEOUT,
+                           timeout,
+                           sizeof(timeout))) {
+      fwprintf(stderr, L"Could not unset send timeout, continuing...\n");
+    }
+
+    if (!InternetSetOption(request.get(),
+                           INTERNET_OPTION_RECEIVE_TIMEOUT,
+                           timeout,
+                           sizeof(timeout))) {
+      fwprintf(stderr, L"Could not unset receive timeout, continuing...\n");
+    }
+  }
+  
+  if (!HttpSendRequest(request.get(), NULL, 0,
+                       const_cast<char *>(request_body.data()),
+                       static_cast<DWORD>(request_body.size()))) {
+    return false;
+  }
+
+  // The server indicates a successful upload with HTTP status 200.
+  wchar_t http_status[4];
+  DWORD http_status_size = sizeof(http_status);
+  if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE,
+                     static_cast<LPVOID>(&http_status), &http_status_size,
+                     0)) {
+    return false;
+  }
+
+  int http_response = wcstol(http_status, NULL, 10);
+  if (response_code) {
+    *response_code = http_response;
+  }
+
+  bool result = (http_response == 200);
+
+  if (result) {
+    result = ReadResponse(request.get(), response_body);
+  }
+
+  return result;
+}
+
+// static
+bool HTTPUpload::ReadResponse(HINTERNET request, wstring *response) {
+  bool has_content_length_header = false;
+  wchar_t content_length[32];
+  DWORD content_length_size = sizeof(content_length);
+  DWORD claimed_size = 0;
+  string response_body;
+
+  if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH,
+                    static_cast<LPVOID>(&content_length),
+                    &content_length_size, 0)) {
+    has_content_length_header = true;
+    claimed_size = wcstol(content_length, NULL, 10);
+    response_body.reserve(claimed_size);
+  }
+
+
+  DWORD bytes_available;
+  DWORD total_read = 0;
+  bool return_code;
+
+  while ((return_code = InternetQueryDataAvailable(request, &bytes_available,
+                                                   0, 0) != 0) &&
+          bytes_available > 0) {
+    vector<char> response_buffer(bytes_available);
+    DWORD size_read;
+
+    if ((return_code = InternetReadFile(request, &response_buffer[0],
+                                        bytes_available, &size_read) != 0) &&
+        size_read > 0) {
+      total_read += size_read;
+      response_body.append(&response_buffer[0], size_read);
+    } else {
+      break;
+    }
+  }
+
+  bool succeeded = return_code && (!has_content_length_header ||
+                                   (total_read == claimed_size));
+  if (succeeded && response) {
+    *response = UTF8ToWide(response_body);
+  }
+
+  return succeeded;
+}
+
+// static
+wstring HTTPUpload::GenerateMultipartBoundary() {
+  // The boundary has 27 '-' characters followed by 16 hex digits
+  static const wchar_t kBoundaryPrefix[] = L"---------------------------";
+  static const int kBoundaryLength = 27 + 16 + 1;
+
+  // Generate some random numbers to fill out the boundary
+  int r0 = rand();
+  int r1 = rand();
+
+  wchar_t temp[kBoundaryLength];
+  swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1);
+
+  // remove when VC++7.1 is no longer supported
+  temp[kBoundaryLength - 1] = L'\0';
+
+  return wstring(temp);
+}
+
+// static
+wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) {
+  wstring header = L"Content-Type: multipart/form-data; boundary=";
+  header += boundary;
+  return header;
+}
+
+// static
+bool HTTPUpload::GenerateRequestBody(const map<wstring, wstring> &parameters,
+                                     const wstring &upload_file,
+                                     const wstring &file_part_name,
+                                     const wstring &boundary,
+                                     string *request_body) {
+  vector<char> contents;
+  GetFileContents(upload_file, &contents);
+  if (contents.empty()) {
+    return false;
+  }
+
+  string boundary_str = WideToUTF8(boundary);
+  if (boundary_str.empty()) {
+    return false;
+  }
+
+  request_body->clear();
+
+  // Append each of the parameter pairs as a form-data part
+  for (map<wstring, wstring>::const_iterator pos = parameters.begin();
+       pos != parameters.end(); ++pos) {
+    request_body->append("--" + boundary_str + "\r\n");
+    request_body->append("Content-Disposition: form-data; name=\"" +
+                         WideToUTF8(pos->first) + "\"\r\n\r\n" +
+                         WideToUTF8(pos->second) + "\r\n");
+  }
+
+  // Now append the upload file as a binary (octet-stream) part
+  string filename_utf8 = WideToUTF8(upload_file);
+  if (filename_utf8.empty()) {
+    return false;
+  }
+
+  string file_part_name_utf8 = WideToUTF8(file_part_name);
+  if (file_part_name_utf8.empty()) {
+    return false;
+  }
+
+  request_body->append("--" + boundary_str + "\r\n");
+  request_body->append("Content-Disposition: form-data; "
+                       "name=\"" + file_part_name_utf8 + "\"; "
+                       "filename=\"" + filename_utf8 + "\"\r\n");
+  request_body->append("Content-Type: application/octet-stream\r\n");
+  request_body->append("\r\n");
+
+  if (!contents.empty()) {
+      request_body->append(&(contents[0]), contents.size());
+  }
+  request_body->append("\r\n");
+  request_body->append("--" + boundary_str + "--\r\n");
+  return true;
+}
+
+// static
+void HTTPUpload::GetFileContents(const wstring &filename,
+                                 vector<char> *contents) {
+  // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
+  // wchar_t* filename, so use _wfopen directly in that case.  For VC8 and
+  // later, _wfopen has been deprecated in favor of _wfopen_s, which does
+  // not exist in earlier versions, so let the ifstream open the file itself.
+#if _MSC_VER >= 1400  // MSVC 2005/8
+  ifstream file;
+  file.open(filename.c_str(), ios::binary);
+#else  // _MSC_VER >= 1400
+  ifstream file(_wfopen(filename.c_str(), L"rb"));
+#endif  // _MSC_VER >= 1400
+  if (file.is_open()) {
+    file.seekg(0, ios::end);
+    int length = file.tellg();
+    contents->resize(length);
+    if (length != 0) {
+        file.seekg(0, ios::beg);
+        file.read(&((*contents)[0]), length);
+    }
+    file.close();
+  } else {
+    contents->clear();
+  }
+}
+
+// static
+wstring HTTPUpload::UTF8ToWide(const string &utf8) {
+  if (utf8.length() == 0) {
+    return wstring();
+  }
+
+  // compute the length of the buffer we'll need
+  int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0);
+
+  if (charcount == 0) {
+    return wstring();
+  }
+
+  // convert
+  wchar_t* buf = new wchar_t[charcount];
+  MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount);
+  wstring result(buf);
+  delete[] buf;
+  return result;
+}
+
+// static
+string HTTPUpload::WideToUTF8(const wstring &wide) {
+  if (wide.length() == 0) {
+    return string();
+  }
+
+  // compute the length of the buffer we'll need
+  int charcount = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1,
+                                      NULL, 0, NULL, NULL);
+  if (charcount == 0) {
+    return string();
+  }
+
+  // convert
+  char *buf = new char[charcount];
+  WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, buf, charcount,
+                      NULL, NULL);
+
+  string result(buf);
+  delete[] buf;
+  return result;
+}
+
+// static
+bool HTTPUpload::CheckParameters(const map<wstring, wstring> &parameters) {
+  for (map<wstring, wstring>::const_iterator pos = parameters.begin();
+       pos != parameters.end(); ++pos) {
+    const wstring &str = pos->first;
+    if (str.size() == 0) {
+      return false;  // disallow empty parameter names
+    }
+    for (unsigned int i = 0; i < str.size(); ++i) {
+      wchar_t c = str[i];
+      if (c < 32 || c == '"' || c > 127) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+}  // namespace google_breakpad
diff --git a/third_party/breakpad/src/common/windows/http_upload.h b/third_party/breakpad/src/common/windows/http_upload.h
index b1fe9b9..f7c69f1 100644
--- a/third_party/breakpad/src/common/windows/http_upload.h
+++ b/third_party/breakpad/src/common/windows/http_upload.h
@@ -1,126 +1,126 @@
-// Copyright (c) 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST

-// request using wininet.  It currently supports requests that contain

-// a set of string parameters (key/value pairs), and a file to upload.

-

-#ifndef COMMON_WINDOWS_HTTP_UPLOAD_H__

-#define COMMON_WINDOWS_HTTP_UPLOAD_H__

-

-#pragma warning( push )

-// Disable exception handler warnings.

-#pragma warning( disable : 4530 ) 

-

-#include <Windows.h>

-#include <WinInet.h>

-

-#include <map>

-#include <string>

-#include <vector>

-

-namespace google_breakpad {

-

-using std::string;

-using std::wstring;

-using std::map;

-using std::vector;

-

-class HTTPUpload {

- public:

-  // Sends the given set of parameters, along with the contents of

-  // upload_file, as a multipart POST request to the given URL.

-  // file_part_name contains the name of the file part of the request

-  // (i.e. it corresponds to the name= attribute on an <input type="file">.

-  // Parameter names must contain only printable ASCII characters,

-  // and may not contain a quote (") character.

-  // Only HTTP(S) URLs are currently supported.  Returns true on success.

-  // If the request is successful and response_body is non-NULL,

-  // the response body will be returned in response_body.

-  // If response_code is non-NULL, it will be set to the HTTP response code

-  // received (or 0 if the request failed before getting an HTTP response).

-  static bool SendRequest(const wstring &url,

-                          const map<wstring, wstring> &parameters,

-                          const wstring &upload_file,

-                          const wstring &file_part_name,

-                          int *timeout,

-                          wstring *response_body,

-                          int *response_code);

-

- private:

-  class AutoInternetHandle;

-

-  // Retrieves the HTTP response.  If NULL is passed in for response,

-  // this merely checks (via the return value) that we were successfully

-  // able to retrieve exactly as many bytes of content in the response as

-  // were specified in the Content-Length header.

-  static bool HTTPUpload::ReadResponse(HINTERNET request, wstring* response);

-

-  // Generates a new multipart boundary for a POST request

-  static wstring GenerateMultipartBoundary();

-

-  // Generates a HTTP request header for a multipart form submit.

-  static wstring GenerateRequestHeader(const wstring &boundary);

-

-  // Given a set of parameters, an upload filename, and a file part name,

-  // generates a multipart request body string with these parameters

-  // and minidump contents.  Returns true on success.

-  static bool GenerateRequestBody(const map<wstring, wstring> &parameters,

-                                  const wstring &upload_file,

-                                  const wstring &file_part_name,

-                                  const wstring &boundary,

-                                  string *request_body);

-

-  // Fills the supplied vector with the contents of filename.

-  static void GetFileContents(const wstring &filename, vector<char> *contents);

-

-  // Converts a UTF8 string to UTF16.

-  static wstring UTF8ToWide(const string &utf8);

-

-  // Converts a UTF16 string to UTF8.

-  static string WideToUTF8(const wstring &wide);

-

-  // Checks that the given list of parameters has only printable

-  // ASCII characters in the parameter name, and does not contain

-  // any quote (") characters.  Returns true if so.

-  static bool CheckParameters(const map<wstring, wstring> &parameters);

-

-  // No instances of this class should be created.

-  // Disallow all constructors, destructors, and operator=.

-  HTTPUpload();

-  explicit HTTPUpload(const HTTPUpload &);

-  void operator=(const HTTPUpload &);

-  ~HTTPUpload();

-};

-

-}  // namespace google_breakpad

-

-#pragma warning( pop )

-

-#endif  // COMMON_WINDOWS_HTTP_UPLOAD_H__

+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST
+// request using wininet.  It currently supports requests that contain
+// a set of string parameters (key/value pairs), and a file to upload.
+
+#ifndef COMMON_WINDOWS_HTTP_UPLOAD_H__
+#define COMMON_WINDOWS_HTTP_UPLOAD_H__
+
+#pragma warning( push )
+// Disable exception handler warnings.
+#pragma warning( disable : 4530 ) 
+
+#include <Windows.h>
+#include <WinInet.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace google_breakpad {
+
+using std::string;
+using std::wstring;
+using std::map;
+using std::vector;
+
+class HTTPUpload {
+ public:
+  // Sends the given set of parameters, along with the contents of
+  // upload_file, as a multipart POST request to the given URL.
+  // file_part_name contains the name of the file part of the request
+  // (i.e. it corresponds to the name= attribute on an <input type="file">.
+  // Parameter names must contain only printable ASCII characters,
+  // and may not contain a quote (") character.
+  // Only HTTP(S) URLs are currently supported.  Returns true on success.
+  // If the request is successful and response_body is non-NULL,
+  // the response body will be returned in response_body.
+  // If response_code is non-NULL, it will be set to the HTTP response code
+  // received (or 0 if the request failed before getting an HTTP response).
+  static bool SendRequest(const wstring &url,
+                          const map<wstring, wstring> &parameters,
+                          const wstring &upload_file,
+                          const wstring &file_part_name,
+                          int *timeout,
+                          wstring *response_body,
+                          int *response_code);
+
+ private:
+  class AutoInternetHandle;
+
+  // Retrieves the HTTP response.  If NULL is passed in for response,
+  // this merely checks (via the return value) that we were successfully
+  // able to retrieve exactly as many bytes of content in the response as
+  // were specified in the Content-Length header.
+  static bool HTTPUpload::ReadResponse(HINTERNET request, wstring* response);
+
+  // Generates a new multipart boundary for a POST request
+  static wstring GenerateMultipartBoundary();
+
+  // Generates a HTTP request header for a multipart form submit.
+  static wstring GenerateRequestHeader(const wstring &boundary);
+
+  // Given a set of parameters, an upload filename, and a file part name,
+  // generates a multipart request body string with these parameters
+  // and minidump contents.  Returns true on success.
+  static bool GenerateRequestBody(const map<wstring, wstring> &parameters,
+                                  const wstring &upload_file,
+                                  const wstring &file_part_name,
+                                  const wstring &boundary,
+                                  string *request_body);
+
+  // Fills the supplied vector with the contents of filename.
+  static void GetFileContents(const wstring &filename, vector<char> *contents);
+
+  // Converts a UTF8 string to UTF16.
+  static wstring UTF8ToWide(const string &utf8);
+
+  // Converts a UTF16 string to UTF8.
+  static string WideToUTF8(const wstring &wide);
+
+  // Checks that the given list of parameters has only printable
+  // ASCII characters in the parameter name, and does not contain
+  // any quote (") characters.  Returns true if so.
+  static bool CheckParameters(const map<wstring, wstring> &parameters);
+
+  // No instances of this class should be created.
+  // Disallow all constructors, destructors, and operator=.
+  HTTPUpload();
+  explicit HTTPUpload(const HTTPUpload &);
+  void operator=(const HTTPUpload &);
+  ~HTTPUpload();
+};
+
+}  // namespace google_breakpad
+
+#pragma warning( pop )
+
+#endif  // COMMON_WINDOWS_HTTP_UPLOAD_H__
diff --git a/third_party/breakpad/src/common/windows/string_utils-inl.h b/third_party/breakpad/src/common/windows/string_utils-inl.h
index bef748a..6f65081 100644
--- a/third_party/breakpad/src/common/windows/string_utils-inl.h
+++ b/third_party/breakpad/src/common/windows/string_utils-inl.h
@@ -1,139 +1,139 @@
-// Copyright (c) 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-// string_utils-inl.h: Safer string manipulation on Windows, supporting

-// pre-MSVC8 environments.

-

-#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H__

-#define COMMON_WINDOWS_STRING_UTILS_INL_H__

-

-#include <stdarg.h>

-#include <wchar.h>

-

-#include <string>

-

-// The "ll" printf format size specifier corresponding to |long long| was

-// intrudced in MSVC8.  Earlier versions did not provide this size specifier,

-// but "I64" can be used to print 64-bit types.  Don't use "I64" where "ll"

-// is available, in the event of oddball systems where |long long| is not

-// 64 bits wide.

-#if _MSC_VER >= 1400  // MSVC 2005/8

-#define WIN_STRING_FORMAT_LL "ll"

-#else  // MSC_VER >= 1400

-#define WIN_STRING_FORMAT_LL "I64"

-#endif  // MSC_VER >= 1400

-

-// A nonconforming version of swprintf, without the length argument, was

-// included with the CRT prior to MSVC8.  Although a conforming version was

-// also available via an overload, it is not reliably chosen.  _snwprintf

-// behaves as a standards-confirming swprintf should, so force the use of

-// _snwprintf when using older CRTs.

-#if _MSC_VER < 1400  // MSVC 2005/8

-#define swprintf _snwprintf

-#else

-// For MSVC8 and newer, swprintf_s is the recommended method. Conveniently,

-// it takes the same argument list as swprintf.

-#define swprintf swprintf_s

-#endif  // MSC_VER < 1400

-

-namespace google_breakpad {

-

-using std::string;

-using std::wstring;

-

-class WindowsStringUtils {

- public:

-  // Roughly equivalent to MSVC8's wcscpy_s, except pre-MSVC8, this does

-  // not fail if source is longer than destination_size.  The destination

-  // buffer is always 0-terminated.

-  static void safe_wcscpy(wchar_t *destination, size_t destination_size,

-                          const wchar_t *source);

-

-  // Roughly equivalent to MSVC8's wcsncpy_s, except that _TRUNCATE cannot

-  // be passed directly, and pre-MSVC8, this will not fail if source or count

-  // are longer than destination_size.  The destination buffer is always

-  // 0-terminated.

-  static void safe_wcsncpy(wchar_t *destination, size_t destination_size,

-                           const wchar_t *source, size_t count);

-

-  // Performs multi-byte to wide character conversion on C++ strings, using

-  // mbstowcs_s (MSVC8) or mbstowcs (pre-MSVC8).  Returns false on failure,

-  // without setting wcs.

-  static bool safe_mbstowcs(const string &mbs, wstring *wcs);

-

-  // Returns the base name of a file, e.g. strips off the path.

-  static wstring GetBaseName(const wstring &filename);

-

- private:

-  // Disallow instantiation and other object-based operations.

-  WindowsStringUtils();

-  WindowsStringUtils(const WindowsStringUtils&);

-  ~WindowsStringUtils();

-  void operator=(const WindowsStringUtils&);

-};

-

-// static

-inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination,

-                                            size_t destination_size,

-                                            const wchar_t *source) {

-#if _MSC_VER >= 1400  // MSVC 2005/8

-  wcscpy_s(destination, destination_size, source);

-#else  // _MSC_VER >= 1400

-  // Pre-MSVC 2005/8 doesn't have wcscpy_s.  Simulate it with wcsncpy.

-  // wcsncpy doesn't 0-terminate the destination buffer if the source string

-  // is longer than size.  Ensure that the destination is 0-terminated.

-  wcsncpy(destination, source, destination_size);

-  if (destination && destination_size)

-    destination[destination_size - 1] = 0;

-#endif  // _MSC_VER >= 1400

-}

-

-// static

-inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination,

-                                             size_t destination_size,

-                                             const wchar_t *source,

-                                             size_t count) {

-#if _MSC_VER >= 1400  // MSVC 2005/8

-  wcsncpy_s(destination, destination_size, source, count);

-#else  // _MSC_VER >= 1400

-  // Pre-MSVC 2005/8 doesn't have wcsncpy_s.  Simulate it with wcsncpy.

-  // wcsncpy doesn't 0-terminate the destination buffer if the source string

-  // is longer than size.  Ensure that the destination is 0-terminated.

-  if (destination_size < count)

-    count = destination_size;

-

-  wcsncpy(destination, source, count);

-  if (destination && count)

-    destination[count - 1] = 0;

-#endif  // _MSC_VER >= 1400

-}

-

-}  // namespace google_breakpad

-

-#endif  // COMMON_WINDOWS_STRING_UTILS_INL_H__

+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// string_utils-inl.h: Safer string manipulation on Windows, supporting
+// pre-MSVC8 environments.
+
+#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H__
+#define COMMON_WINDOWS_STRING_UTILS_INL_H__
+
+#include <stdarg.h>
+#include <wchar.h>
+
+#include <string>
+
+// The "ll" printf format size specifier corresponding to |long long| was
+// intrudced in MSVC8.  Earlier versions did not provide this size specifier,
+// but "I64" can be used to print 64-bit types.  Don't use "I64" where "ll"
+// is available, in the event of oddball systems where |long long| is not
+// 64 bits wide.
+#if _MSC_VER >= 1400  // MSVC 2005/8
+#define WIN_STRING_FORMAT_LL "ll"
+#else  // MSC_VER >= 1400
+#define WIN_STRING_FORMAT_LL "I64"
+#endif  // MSC_VER >= 1400
+
+// A nonconforming version of swprintf, without the length argument, was
+// included with the CRT prior to MSVC8.  Although a conforming version was
+// also available via an overload, it is not reliably chosen.  _snwprintf
+// behaves as a standards-confirming swprintf should, so force the use of
+// _snwprintf when using older CRTs.
+#if _MSC_VER < 1400  // MSVC 2005/8
+#define swprintf _snwprintf
+#else
+// For MSVC8 and newer, swprintf_s is the recommended method. Conveniently,
+// it takes the same argument list as swprintf.
+#define swprintf swprintf_s
+#endif  // MSC_VER < 1400
+
+namespace google_breakpad {
+
+using std::string;
+using std::wstring;
+
+class WindowsStringUtils {
+ public:
+  // Roughly equivalent to MSVC8's wcscpy_s, except pre-MSVC8, this does
+  // not fail if source is longer than destination_size.  The destination
+  // buffer is always 0-terminated.
+  static void safe_wcscpy(wchar_t *destination, size_t destination_size,
+                          const wchar_t *source);
+
+  // Roughly equivalent to MSVC8's wcsncpy_s, except that _TRUNCATE cannot
+  // be passed directly, and pre-MSVC8, this will not fail if source or count
+  // are longer than destination_size.  The destination buffer is always
+  // 0-terminated.
+  static void safe_wcsncpy(wchar_t *destination, size_t destination_size,
+                           const wchar_t *source, size_t count);
+
+  // Performs multi-byte to wide character conversion on C++ strings, using
+  // mbstowcs_s (MSVC8) or mbstowcs (pre-MSVC8).  Returns false on failure,
+  // without setting wcs.
+  static bool safe_mbstowcs(const string &mbs, wstring *wcs);
+
+  // Returns the base name of a file, e.g. strips off the path.
+  static wstring GetBaseName(const wstring &filename);
+
+ private:
+  // Disallow instantiation and other object-based operations.
+  WindowsStringUtils();
+  WindowsStringUtils(const WindowsStringUtils&);
+  ~WindowsStringUtils();
+  void operator=(const WindowsStringUtils&);
+};
+
+// static
+inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination,
+                                            size_t destination_size,
+                                            const wchar_t *source) {
+#if _MSC_VER >= 1400  // MSVC 2005/8
+  wcscpy_s(destination, destination_size, source);
+#else  // _MSC_VER >= 1400
+  // Pre-MSVC 2005/8 doesn't have wcscpy_s.  Simulate it with wcsncpy.
+  // wcsncpy doesn't 0-terminate the destination buffer if the source string
+  // is longer than size.  Ensure that the destination is 0-terminated.
+  wcsncpy(destination, source, destination_size);
+  if (destination && destination_size)
+    destination[destination_size - 1] = 0;
+#endif  // _MSC_VER >= 1400
+}
+
+// static
+inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination,
+                                             size_t destination_size,
+                                             const wchar_t *source,
+                                             size_t count) {
+#if _MSC_VER >= 1400  // MSVC 2005/8
+  wcsncpy_s(destination, destination_size, source, count);
+#else  // _MSC_VER >= 1400
+  // Pre-MSVC 2005/8 doesn't have wcsncpy_s.  Simulate it with wcsncpy.
+  // wcsncpy doesn't 0-terminate the destination buffer if the source string
+  // is longer than size.  Ensure that the destination is 0-terminated.
+  if (destination_size < count)
+    count = destination_size;
+
+  wcsncpy(destination, source, count);
+  if (destination && count)
+    destination[count - 1] = 0;
+#endif  // _MSC_VER >= 1400
+}
+
+}  // namespace google_breakpad
+
+#endif  // COMMON_WINDOWS_STRING_UTILS_INL_H__
diff --git a/third_party/breakpad/src/google_breakpad/common/breakpad_types.h b/third_party/breakpad/src/google_breakpad/common/breakpad_types.h
index 7382026..926b47f 100644
--- a/third_party/breakpad/src/google_breakpad/common/breakpad_types.h
+++ b/third_party/breakpad/src/google_breakpad/common/breakpad_types.h
@@ -1,83 +1,83 @@
-/* Copyright (c) 2006, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* breakpad_types.h: Precise-width types

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * This file ensures that types u_intN_t are defined for N = 8, 16, 32, and

- * 64.  Types of precise widths are crucial to the task of writing data

- * structures on one platform and reading them on another.

- *

- * Author: Mark Mentovai */

-

-#ifndef GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__

-#define GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__

-

-#ifndef _WIN32

-

-#include <sys/types.h>

-#ifndef __STDC_FORMAT_MACROS

-#define __STDC_FORMAT_MACROS

-#endif  /* __STDC_FORMAT_MACROS */

-#include <inttypes.h>

-

-#if defined(__SUNPRO_CC) || (defined(__GNUC__) && defined(__sun__))

-typedef uint8_t u_int8_t;

-typedef uint16_t u_int16_t;

-typedef uint32_t u_int32_t;

-typedef uint64_t u_int64_t;

-#endif

-

-#else  /* !_WIN32 */

-

-#include <WTypes.h>

-

-typedef unsigned __int8  u_int8_t;

-typedef unsigned __int16 u_int16_t;

-typedef unsigned __int32 u_int32_t;

-typedef unsigned __int64 u_int64_t;

-

-#endif  /* !_WIN32 */

-

-typedef struct {

-  u_int64_t high;

-  u_int64_t low;

-} u_int128_t;

-

-typedef u_int64_t breakpad_time_t;

-

-/* Try to get PRIx64 from inttypes.h, but if it's not defined, fall back to

- * llx, which is the format string for "long long" - this is a 64-bit

- * integral type on many systems. */

-#ifndef PRIx64

-#define PRIx64 "llx"

-#endif  /* !PRIx64 */

-

-#endif  /* GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ */

+/* Copyright (c) 2006, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* breakpad_types.h: Precise-width types
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * This file ensures that types u_intN_t are defined for N = 8, 16, 32, and
+ * 64.  Types of precise widths are crucial to the task of writing data
+ * structures on one platform and reading them on another.
+ *
+ * Author: Mark Mentovai */
+
+#ifndef GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__
+#define GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__
+
+#ifndef _WIN32
+
+#include <sys/types.h>
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif  /* __STDC_FORMAT_MACROS */
+#include <inttypes.h>
+
+#if defined(__SUNPRO_CC) || (defined(__GNUC__) && defined(__sun__))
+typedef uint8_t u_int8_t;
+typedef uint16_t u_int16_t;
+typedef uint32_t u_int32_t;
+typedef uint64_t u_int64_t;
+#endif
+
+#else  /* !_WIN32 */
+
+#include <WTypes.h>
+
+typedef unsigned __int8  u_int8_t;
+typedef unsigned __int16 u_int16_t;
+typedef unsigned __int32 u_int32_t;
+typedef unsigned __int64 u_int64_t;
+
+#endif  /* !_WIN32 */
+
+typedef struct {
+  u_int64_t high;
+  u_int64_t low;
+} u_int128_t;
+
+typedef u_int64_t breakpad_time_t;
+
+/* Try to get PRIx64 from inttypes.h, but if it's not defined, fall back to
+ * llx, which is the format string for "long long" - this is a 64-bit
+ * integral type on many systems. */
+#ifndef PRIx64
+#define PRIx64 "llx"
+#endif  /* !PRIx64 */
+
+#endif  /* GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ */
diff --git a/third_party/breakpad/src/google_breakpad/common/minidump_cpu_amd64.h b/third_party/breakpad/src/google_breakpad/common/minidump_cpu_amd64.h
index 4db9adb..75dae7d 100644
--- a/third_party/breakpad/src/google_breakpad/common/minidump_cpu_amd64.h
+++ b/third_party/breakpad/src/google_breakpad/common/minidump_cpu_amd64.h
@@ -1,231 +1,231 @@
-/* Copyright (c) 2006, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* minidump_format.h: A cross-platform reimplementation of minidump-related

- * portions of DbgHelp.h from the Windows Platform SDK.

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * This file contains the necessary definitions to read minidump files

- * produced on amd64.  These files may be read on any platform provided

- * that the alignments of these structures on the processing system are

- * identical to the alignments of these structures on the producing system.

- * For this reason, precise-sized types are used.  The structures defined

- * by this file have been laid out to minimize alignment problems by ensuring

- * ensuring that all members are aligned on their natural boundaries.  In

- * In some cases, tail-padding may be significant when different ABIs specify

- * different tail-padding behaviors.  To avoid problems when reading or

- * writing affected structures, MD_*_SIZE macros are provided where needed,

- * containing the useful size of the structures without padding.

- *

- * Structures that are defined by Microsoft to contain a zero-length array

- * are instead defined here to contain an array with one element, as

- * zero-length arrays are forbidden by standard C and C++.  In these cases,

- * *_minsize constants are provided to be used in place of sizeof.  For a

- * cleaner interface to these sizes when using C++, see minidump_size.h.

- *

- * These structures are also sufficient to populate minidump files.

- *

- * These definitions may be extended to support handling minidump files

- * for other CPUs and other operating systems.

- *

- * Because precise data type sizes are crucial for this implementation to

- * function properly and portably in terms of interoperability with minidumps

- * produced by DbgHelp on Windows, a set of primitive types with known sizes

- * are used as the basis of each structure defined by this file.  DbgHelp

- * on Windows is assumed to be the reference implementation; this file

- * seeks to provide a cross-platform compatible implementation.  To avoid

- * collisions with the types and values defined and used by DbgHelp in the

- * event that this implementation is used on Windows, each type and value

- * defined here is given a new name, beginning with "MD".  Names of the

- * equivalent types and values in the Windows Platform SDK are given in

- * comments.

- *

- * Author: Mark Mentovai 

- * Change to split into its own file: Neal Sidhwaney */

-

-#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__

-#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__

-

-

-/*

- * AMD64 support, see WINNT.H

- */

-

-typedef struct {

-  u_int16_t  control_word;

-  u_int16_t  status_word;

-  u_int8_t   tag_word;

-  u_int8_t   reserved1;

-  u_int16_t  error_opcode;

-  u_int32_t  error_offset;

-  u_int16_t  error_selector;

-  u_int16_t  reserved2;

-  u_int32_t  data_offset;

-  u_int16_t  data_selector;

-  u_int16_t  reserved3;

-  u_int32_t  mx_csr;

-  u_int32_t  mx_csr_mask;

-  u_int128_t float_registers[8];

-  u_int128_t xmm_registers[16];

-  u_int8_t   reserved4[96];

-} MDXmmSaveArea32AMD64;  /* XMM_SAVE_AREA32 */

-

-#define MD_CONTEXT_AMD64_VR_COUNT 26

-

-typedef struct {

-  /*

-   * Register parameter home addresses.

-   */

-  u_int64_t  p1_home;

-  u_int64_t  p2_home;

-  u_int64_t  p3_home;

-  u_int64_t  p4_home;

-  u_int64_t  p5_home;

-  u_int64_t  p6_home;

-

-  /* The next field determines the layout of the structure, and which parts

-   * of it are populated */

-  u_int32_t  context_flags;

-  u_int32_t  mx_csr;

-

-  /* The next register is included with MD_CONTEXT_AMD64_CONTROL */

-  u_int16_t  cs;

-

-  /* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */

-  u_int16_t  ds;

-  u_int16_t  es;

-  u_int16_t  fs;

-  u_int16_t  gs;

-

-  /* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */

-  u_int16_t  ss;

-  u_int32_t  eflags;

-  

-  /* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */

-  u_int64_t  dr0;

-  u_int64_t  dr1;

-  u_int64_t  dr2;

-  u_int64_t  dr3;

-  u_int64_t  dr6;

-  u_int64_t  dr7;

-

-  /* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */

-  u_int64_t  rax;

-  u_int64_t  rcx;

-  u_int64_t  rdx;

-  u_int64_t  rbx;

-

-  /* The next register is included with MD_CONTEXT_AMD64_CONTROL */

-  u_int64_t  rsp;

-

-  /* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */

-  u_int64_t  rbp;

-  u_int64_t  rsi;

-  u_int64_t  rdi;

-  u_int64_t  r8;

-  u_int64_t  r9;

-  u_int64_t  r10;

-  u_int64_t  r11;

-  u_int64_t  r12;

-  u_int64_t  r13;

-  u_int64_t  r14;

-  u_int64_t  r15;

-

-  /* The next register is included with MD_CONTEXT_AMD64_CONTROL */

-  u_int64_t  rip;

-

-  /* The next set of registers are included with

-   * MD_CONTEXT_AMD64_FLOATING_POINT

-   */

-  union {

-    MDXmmSaveArea32AMD64 flt_save;

-    struct {

-      u_int128_t header[2];

-      u_int128_t legacy[8];

-      u_int128_t xmm0;

-      u_int128_t xmm1;

-      u_int128_t xmm2;

-      u_int128_t xmm3;

-      u_int128_t xmm4;

-      u_int128_t xmm5;

-      u_int128_t xmm6;

-      u_int128_t xmm7;

-      u_int128_t xmm8;

-      u_int128_t xmm9;

-      u_int128_t xmm10;

-      u_int128_t xmm11;

-      u_int128_t xmm12;

-      u_int128_t xmm13;

-      u_int128_t xmm14;

-      u_int128_t xmm15;

-    } sse_registers;

-  };

-

-  u_int128_t vector_register[MD_CONTEXT_AMD64_VR_COUNT];

-  u_int64_t  vector_control;

-

-  /* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */

-  u_int64_t debug_control;

-  u_int64_t last_branch_to_rip;

-  u_int64_t last_branch_from_rip;

-  u_int64_t last_exception_to_rip;

-  u_int64_t last_exception_from_rip;

-  

-} MDRawContextAMD64;  /* CONTEXT */

-

-/* For (MDRawContextAMD64).context_flags.  These values indicate the type of

- * context stored in the structure.  The high 26 bits identify the CPU, the

- * low 6 bits identify the type of context saved. */

-#define MD_CONTEXT_AMD64_CONTROL         (MD_CONTEXT_AMD64 | 0x00000001)

-     /* CONTEXT_CONTROL */

-#define MD_CONTEXT_AMD64_INTEGER         (MD_CONTEXT_AMD64 | 0x00000002)

-     /* CONTEXT_INTEGER */

-#define MD_CONTEXT_AMD64_SEGMENTS        (MD_CONTEXT_AMD64 | 0x00000004)

-     /* CONTEXT_SEGMENTS */

-#define MD_CONTEXT_AMD64_FLOATING_POINT  (MD_CONTEXT_AMD64 | 0x00000008)

-     /* CONTEXT_FLOATING_POINT */

-#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010)

-     /* CONTEXT_DEBUG_REGISTERS */

-/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it

- * I think it really means CONTEXT_FLOATING_POINT.

- */

-

-#define MD_CONTEXT_AMD64_FULL            (MD_CONTEXT_AMD64_CONTROL | \

-                                          MD_CONTEXT_AMD64_INTEGER | \

-                                          MD_CONTEXT_AMD64_FLOATING_POINT)

-     /* CONTEXT_FULL */

-

-#define MD_CONTEXT_AMD64_ALL             (MD_CONTEXT_AMD64_FULL | \

-                                          MD_CONTEXT_AMD64_SEGMENTS | \

-                                          MD_CONTEXT_X86_DEBUG_REGISTERS)

-     /* CONTEXT_ALL */

-

-

-#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ */

+/* Copyright (c) 2006, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_format.h: A cross-platform reimplementation of minidump-related
+ * portions of DbgHelp.h from the Windows Platform SDK.
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * This file contains the necessary definitions to read minidump files
+ * produced on amd64.  These files may be read on any platform provided
+ * that the alignments of these structures on the processing system are
+ * identical to the alignments of these structures on the producing system.
+ * For this reason, precise-sized types are used.  The structures defined
+ * by this file have been laid out to minimize alignment problems by ensuring
+ * ensuring that all members are aligned on their natural boundaries.  In
+ * In some cases, tail-padding may be significant when different ABIs specify
+ * different tail-padding behaviors.  To avoid problems when reading or
+ * writing affected structures, MD_*_SIZE macros are provided where needed,
+ * containing the useful size of the structures without padding.
+ *
+ * Structures that are defined by Microsoft to contain a zero-length array
+ * are instead defined here to contain an array with one element, as
+ * zero-length arrays are forbidden by standard C and C++.  In these cases,
+ * *_minsize constants are provided to be used in place of sizeof.  For a
+ * cleaner interface to these sizes when using C++, see minidump_size.h.
+ *
+ * These structures are also sufficient to populate minidump files.
+ *
+ * These definitions may be extended to support handling minidump files
+ * for other CPUs and other operating systems.
+ *
+ * Because precise data type sizes are crucial for this implementation to
+ * function properly and portably in terms of interoperability with minidumps
+ * produced by DbgHelp on Windows, a set of primitive types with known sizes
+ * are used as the basis of each structure defined by this file.  DbgHelp
+ * on Windows is assumed to be the reference implementation; this file
+ * seeks to provide a cross-platform compatible implementation.  To avoid
+ * collisions with the types and values defined and used by DbgHelp in the
+ * event that this implementation is used on Windows, each type and value
+ * defined here is given a new name, beginning with "MD".  Names of the
+ * equivalent types and values in the Windows Platform SDK are given in
+ * comments.
+ *
+ * Author: Mark Mentovai 
+ * Change to split into its own file: Neal Sidhwaney */
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__
+
+
+/*
+ * AMD64 support, see WINNT.H
+ */
+
+typedef struct {
+  u_int16_t  control_word;
+  u_int16_t  status_word;
+  u_int8_t   tag_word;
+  u_int8_t   reserved1;
+  u_int16_t  error_opcode;
+  u_int32_t  error_offset;
+  u_int16_t  error_selector;
+  u_int16_t  reserved2;
+  u_int32_t  data_offset;
+  u_int16_t  data_selector;
+  u_int16_t  reserved3;
+  u_int32_t  mx_csr;
+  u_int32_t  mx_csr_mask;
+  u_int128_t float_registers[8];
+  u_int128_t xmm_registers[16];
+  u_int8_t   reserved4[96];
+} MDXmmSaveArea32AMD64;  /* XMM_SAVE_AREA32 */
+
+#define MD_CONTEXT_AMD64_VR_COUNT 26
+
+typedef struct {
+  /*
+   * Register parameter home addresses.
+   */
+  u_int64_t  p1_home;
+  u_int64_t  p2_home;
+  u_int64_t  p3_home;
+  u_int64_t  p4_home;
+  u_int64_t  p5_home;
+  u_int64_t  p6_home;
+
+  /* The next field determines the layout of the structure, and which parts
+   * of it are populated */
+  u_int32_t  context_flags;
+  u_int32_t  mx_csr;
+
+  /* The next register is included with MD_CONTEXT_AMD64_CONTROL */
+  u_int16_t  cs;
+
+  /* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */
+  u_int16_t  ds;
+  u_int16_t  es;
+  u_int16_t  fs;
+  u_int16_t  gs;
+
+  /* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */
+  u_int16_t  ss;
+  u_int32_t  eflags;
+  
+  /* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
+  u_int64_t  dr0;
+  u_int64_t  dr1;
+  u_int64_t  dr2;
+  u_int64_t  dr3;
+  u_int64_t  dr6;
+  u_int64_t  dr7;
+
+  /* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */
+  u_int64_t  rax;
+  u_int64_t  rcx;
+  u_int64_t  rdx;
+  u_int64_t  rbx;
+
+  /* The next register is included with MD_CONTEXT_AMD64_CONTROL */
+  u_int64_t  rsp;
+
+  /* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */
+  u_int64_t  rbp;
+  u_int64_t  rsi;
+  u_int64_t  rdi;
+  u_int64_t  r8;
+  u_int64_t  r9;
+  u_int64_t  r10;
+  u_int64_t  r11;
+  u_int64_t  r12;
+  u_int64_t  r13;
+  u_int64_t  r14;
+  u_int64_t  r15;
+
+  /* The next register is included with MD_CONTEXT_AMD64_CONTROL */
+  u_int64_t  rip;
+
+  /* The next set of registers are included with
+   * MD_CONTEXT_AMD64_FLOATING_POINT
+   */
+  union {
+    MDXmmSaveArea32AMD64 flt_save;
+    struct {
+      u_int128_t header[2];
+      u_int128_t legacy[8];
+      u_int128_t xmm0;
+      u_int128_t xmm1;
+      u_int128_t xmm2;
+      u_int128_t xmm3;
+      u_int128_t xmm4;
+      u_int128_t xmm5;
+      u_int128_t xmm6;
+      u_int128_t xmm7;
+      u_int128_t xmm8;
+      u_int128_t xmm9;
+      u_int128_t xmm10;
+      u_int128_t xmm11;
+      u_int128_t xmm12;
+      u_int128_t xmm13;
+      u_int128_t xmm14;
+      u_int128_t xmm15;
+    } sse_registers;
+  };
+
+  u_int128_t vector_register[MD_CONTEXT_AMD64_VR_COUNT];
+  u_int64_t  vector_control;
+
+  /* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
+  u_int64_t debug_control;
+  u_int64_t last_branch_to_rip;
+  u_int64_t last_branch_from_rip;
+  u_int64_t last_exception_to_rip;
+  u_int64_t last_exception_from_rip;
+  
+} MDRawContextAMD64;  /* CONTEXT */
+
+/* For (MDRawContextAMD64).context_flags.  These values indicate the type of
+ * context stored in the structure.  The high 26 bits identify the CPU, the
+ * low 6 bits identify the type of context saved. */
+#define MD_CONTEXT_AMD64_CONTROL         (MD_CONTEXT_AMD64 | 0x00000001)
+     /* CONTEXT_CONTROL */
+#define MD_CONTEXT_AMD64_INTEGER         (MD_CONTEXT_AMD64 | 0x00000002)
+     /* CONTEXT_INTEGER */
+#define MD_CONTEXT_AMD64_SEGMENTS        (MD_CONTEXT_AMD64 | 0x00000004)
+     /* CONTEXT_SEGMENTS */
+#define MD_CONTEXT_AMD64_FLOATING_POINT  (MD_CONTEXT_AMD64 | 0x00000008)
+     /* CONTEXT_FLOATING_POINT */
+#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010)
+     /* CONTEXT_DEBUG_REGISTERS */
+/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it
+ * I think it really means CONTEXT_FLOATING_POINT.
+ */
+
+#define MD_CONTEXT_AMD64_FULL            (MD_CONTEXT_AMD64_CONTROL | \
+                                          MD_CONTEXT_AMD64_INTEGER | \
+                                          MD_CONTEXT_AMD64_FLOATING_POINT)
+     /* CONTEXT_FULL */
+
+#define MD_CONTEXT_AMD64_ALL             (MD_CONTEXT_AMD64_FULL | \
+                                          MD_CONTEXT_AMD64_SEGMENTS | \
+                                          MD_CONTEXT_X86_DEBUG_REGISTERS)
+     /* CONTEXT_ALL */
+
+
+#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ */
diff --git a/third_party/breakpad/src/google_breakpad/common/minidump_cpu_ppc.h b/third_party/breakpad/src/google_breakpad/common/minidump_cpu_ppc.h
index ed119a8..038e921 100644
--- a/third_party/breakpad/src/google_breakpad/common/minidump_cpu_ppc.h
+++ b/third_party/breakpad/src/google_breakpad/common/minidump_cpu_ppc.h
@@ -1,163 +1,163 @@
-/* Copyright (c) 2006, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* minidump_format.h: A cross-platform reimplementation of minidump-related

- * portions of DbgHelp.h from the Windows Platform SDK.

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * This file contains the necessary definitions to read minidump files

- * produced on ppc.  These files may be read on any platform provided

- * that the alignments of these structures on the processing system are

- * identical to the alignments of these structures on the producing system.

- * For this reason, precise-sized types are used.  The structures defined

- * by this file have been laid out to minimize alignment problems by ensuring

- * ensuring that all members are aligned on their natural boundaries.  In

- * In some cases, tail-padding may be significant when different ABIs specify

- * different tail-padding behaviors.  To avoid problems when reading or

- * writing affected structures, MD_*_SIZE macros are provided where needed,

- * containing the useful size of the structures without padding.

- *

- * Structures that are defined by Microsoft to contain a zero-length array

- * are instead defined here to contain an array with one element, as

- * zero-length arrays are forbidden by standard C and C++.  In these cases,

- * *_minsize constants are provided to be used in place of sizeof.  For a

- * cleaner interface to these sizes when using C++, see minidump_size.h.

- *

- * These structures are also sufficient to populate minidump files.

- *

- * These definitions may be extended to support handling minidump files

- * for other CPUs and other operating systems.

- *

- * Because precise data type sizes are crucial for this implementation to

- * function properly and portably in terms of interoperability with minidumps

- * produced by DbgHelp on Windows, a set of primitive types with known sizes

- * are used as the basis of each structure defined by this file.  DbgHelp

- * on Windows is assumed to be the reference implementation; this file

- * seeks to provide a cross-platform compatible implementation.  To avoid

- * collisions with the types and values defined and used by DbgHelp in the

- * event that this implementation is used on Windows, each type and value

- * defined here is given a new name, beginning with "MD".  Names of the

- * equivalent types and values in the Windows Platform SDK are given in

- * comments.

- *

- * Author: Mark Mentovai 

- * Change to split into its own file: Neal Sidhwaney */

-

-/*

- * Breakpad minidump extension for PowerPC support.  Based on Darwin/Mac OS X'

- * mach/ppc/_types.h

- */

-

-#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__

-#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__

-

-#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32

-

-typedef struct {

-  /* fpregs is a double[32] in mach/ppc/_types.h, but a u_int64_t is used

-   * here for precise sizing. */

-  u_int64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT];

-  u_int32_t fpscr_pad;

-  u_int32_t fpscr;      /* Status/control */

-} MDFloatingSaveAreaPPC;  /* Based on ppc_float_state */

-

-

-#define MD_VECTORSAVEAREA_PPC_VR_COUNT 32

-

-typedef struct {

-  /* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h

-   * exposes them as four 32-bit quantities. */

-  u_int128_t save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT];

-  u_int128_t save_vscr;  /* Status/control */

-  u_int32_t  save_pad5[4];

-  u_int32_t  save_vrvalid;  /* Identifies which vector registers are saved */

-  u_int32_t  save_pad6[7];

-} MDVectorSaveAreaPPC;  /* ppc_vector_state */

-

-

-#define MD_CONTEXT_PPC_GPR_COUNT 32

-

-/* Use the same 32-bit alignment when accessing this structure from 64-bit code

- * as is used natively in 32-bit code.  #pragma pack is a MSVC extension

- * supported by gcc. */

-#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)

-#pragma pack(4)

-#else

-#pragma pack(push, 4)

-#endif

-

-typedef struct {

-  /* context_flags is not present in ppc_thread_state, but it aids

-   * identification of MDRawContextPPC among other raw context types,

-   * and it guarantees alignment when we get to float_save. */

-  u_int32_t             context_flags;

-

-  u_int32_t             srr0;    /* Machine status save/restore: stores pc

-                                  * (instruction) */

-  u_int32_t             srr1;    /* Machine status save/restore: stores msr

-                                  * (ps, program/machine state) */

-  /* ppc_thread_state contains 32 fields, r0 .. r31.  Here, an array is

-   * used for brevity. */

-  u_int32_t             gpr[MD_CONTEXT_PPC_GPR_COUNT];

-  u_int32_t             cr;      /* Condition */

-  u_int32_t             xer;     /* Integer (fiXed-point) exception */

-  u_int32_t             lr;      /* Link */

-  u_int32_t             ctr;     /* Count */

-  u_int32_t             mq;      /* Multiply/Quotient (PPC 601, POWER only) */

-  u_int32_t             vrsave;  /* Vector save */

-

-  /* float_save and vector_save aren't present in ppc_thread_state, but

-   * are represented in separate structures that still define a thread's

-   * context. */

-  MDFloatingSaveAreaPPC float_save;

-  MDVectorSaveAreaPPC   vector_save;

-} MDRawContextPPC;  /* Based on ppc_thread_state */

-

-#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)

-#pragma pack(0)

-#else

-#pragma pack(pop)

-#endif

-

-/* For (MDRawContextPPC).context_flags.  These values indicate the type of

- * context stored in the structure.  MD_CONTEXT_PPC is Breakpad-defined.  Its

- * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other

- * CPUs. */

-#define MD_CONTEXT_PPC                0x20000000

-#define MD_CONTEXT_PPC_BASE           (MD_CONTEXT_PPC | 0x00000001)

-#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)

-#define MD_CONTEXT_PPC_VECTOR         (MD_CONTEXT_PPC | 0x00000020)

-

-#define MD_CONTEXT_PPC_FULL           MD_CONTEXT_PPC_BASE

-#define MD_CONTEXT_PPC_ALL            (MD_CONTEXT_PPC_FULL | \

-                                       MD_CONTEXT_PPC_FLOATING_POINT | \

-                                       MD_CONTEXT_PPC_VECTOR)

-

-#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ */

+/* Copyright (c) 2006, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_format.h: A cross-platform reimplementation of minidump-related
+ * portions of DbgHelp.h from the Windows Platform SDK.
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * This file contains the necessary definitions to read minidump files
+ * produced on ppc.  These files may be read on any platform provided
+ * that the alignments of these structures on the processing system are
+ * identical to the alignments of these structures on the producing system.
+ * For this reason, precise-sized types are used.  The structures defined
+ * by this file have been laid out to minimize alignment problems by ensuring
+ * ensuring that all members are aligned on their natural boundaries.  In
+ * In some cases, tail-padding may be significant when different ABIs specify
+ * different tail-padding behaviors.  To avoid problems when reading or
+ * writing affected structures, MD_*_SIZE macros are provided where needed,
+ * containing the useful size of the structures without padding.
+ *
+ * Structures that are defined by Microsoft to contain a zero-length array
+ * are instead defined here to contain an array with one element, as
+ * zero-length arrays are forbidden by standard C and C++.  In these cases,
+ * *_minsize constants are provided to be used in place of sizeof.  For a
+ * cleaner interface to these sizes when using C++, see minidump_size.h.
+ *
+ * These structures are also sufficient to populate minidump files.
+ *
+ * These definitions may be extended to support handling minidump files
+ * for other CPUs and other operating systems.
+ *
+ * Because precise data type sizes are crucial for this implementation to
+ * function properly and portably in terms of interoperability with minidumps
+ * produced by DbgHelp on Windows, a set of primitive types with known sizes
+ * are used as the basis of each structure defined by this file.  DbgHelp
+ * on Windows is assumed to be the reference implementation; this file
+ * seeks to provide a cross-platform compatible implementation.  To avoid
+ * collisions with the types and values defined and used by DbgHelp in the
+ * event that this implementation is used on Windows, each type and value
+ * defined here is given a new name, beginning with "MD".  Names of the
+ * equivalent types and values in the Windows Platform SDK are given in
+ * comments.
+ *
+ * Author: Mark Mentovai 
+ * Change to split into its own file: Neal Sidhwaney */
+
+/*
+ * Breakpad minidump extension for PowerPC support.  Based on Darwin/Mac OS X'
+ * mach/ppc/_types.h
+ */
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__
+
+#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32
+
+typedef struct {
+  /* fpregs is a double[32] in mach/ppc/_types.h, but a u_int64_t is used
+   * here for precise sizing. */
+  u_int64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT];
+  u_int32_t fpscr_pad;
+  u_int32_t fpscr;      /* Status/control */
+} MDFloatingSaveAreaPPC;  /* Based on ppc_float_state */
+
+
+#define MD_VECTORSAVEAREA_PPC_VR_COUNT 32
+
+typedef struct {
+  /* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h
+   * exposes them as four 32-bit quantities. */
+  u_int128_t save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT];
+  u_int128_t save_vscr;  /* Status/control */
+  u_int32_t  save_pad5[4];
+  u_int32_t  save_vrvalid;  /* Identifies which vector registers are saved */
+  u_int32_t  save_pad6[7];
+} MDVectorSaveAreaPPC;  /* ppc_vector_state */
+
+
+#define MD_CONTEXT_PPC_GPR_COUNT 32
+
+/* Use the same 32-bit alignment when accessing this structure from 64-bit code
+ * as is used natively in 32-bit code.  #pragma pack is a MSVC extension
+ * supported by gcc. */
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#pragma pack(4)
+#else
+#pragma pack(push, 4)
+#endif
+
+typedef struct {
+  /* context_flags is not present in ppc_thread_state, but it aids
+   * identification of MDRawContextPPC among other raw context types,
+   * and it guarantees alignment when we get to float_save. */
+  u_int32_t             context_flags;
+
+  u_int32_t             srr0;    /* Machine status save/restore: stores pc
+                                  * (instruction) */
+  u_int32_t             srr1;    /* Machine status save/restore: stores msr
+                                  * (ps, program/machine state) */
+  /* ppc_thread_state contains 32 fields, r0 .. r31.  Here, an array is
+   * used for brevity. */
+  u_int32_t             gpr[MD_CONTEXT_PPC_GPR_COUNT];
+  u_int32_t             cr;      /* Condition */
+  u_int32_t             xer;     /* Integer (fiXed-point) exception */
+  u_int32_t             lr;      /* Link */
+  u_int32_t             ctr;     /* Count */
+  u_int32_t             mq;      /* Multiply/Quotient (PPC 601, POWER only) */
+  u_int32_t             vrsave;  /* Vector save */
+
+  /* float_save and vector_save aren't present in ppc_thread_state, but
+   * are represented in separate structures that still define a thread's
+   * context. */
+  MDFloatingSaveAreaPPC float_save;
+  MDVectorSaveAreaPPC   vector_save;
+} MDRawContextPPC;  /* Based on ppc_thread_state */
+
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#pragma pack(0)
+#else
+#pragma pack(pop)
+#endif
+
+/* For (MDRawContextPPC).context_flags.  These values indicate the type of
+ * context stored in the structure.  MD_CONTEXT_PPC is Breakpad-defined.  Its
+ * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
+ * CPUs. */
+#define MD_CONTEXT_PPC                0x20000000
+#define MD_CONTEXT_PPC_BASE           (MD_CONTEXT_PPC | 0x00000001)
+#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)
+#define MD_CONTEXT_PPC_VECTOR         (MD_CONTEXT_PPC | 0x00000020)
+
+#define MD_CONTEXT_PPC_FULL           MD_CONTEXT_PPC_BASE
+#define MD_CONTEXT_PPC_ALL            (MD_CONTEXT_PPC_FULL | \
+                                       MD_CONTEXT_PPC_FLOATING_POINT | \
+                                       MD_CONTEXT_PPC_VECTOR)
+
+#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ */
diff --git a/third_party/breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h b/third_party/breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h
index a959764..a788e5d 100644
--- a/third_party/breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h
+++ b/third_party/breakpad/src/google_breakpad/common/minidump_cpu_ppc64.h
@@ -1,129 +1,129 @@
-/* Copyright (c) 2008, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* minidump_format.h: A cross-platform reimplementation of minidump-related

- * portions of DbgHelp.h from the Windows Platform SDK.

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * This file contains the necessary definitions to read minidump files

- * produced on ppc64.  These files may be read on any platform provided

- * that the alignments of these structures on the processing system are

- * identical to the alignments of these structures on the producing system.

- * For this reason, precise-sized types are used.  The structures defined

- * by this file have been laid out to minimize alignment problems by ensuring

- * ensuring that all members are aligned on their natural boundaries.  In

- * In some cases, tail-padding may be significant when different ABIs specify

- * different tail-padding behaviors.  To avoid problems when reading or

- * writing affected structures, MD_*_SIZE macros are provided where needed,

- * containing the useful size of the structures without padding.

- *

- * Structures that are defined by Microsoft to contain a zero-length array

- * are instead defined here to contain an array with one element, as

- * zero-length arrays are forbidden by standard C and C++.  In these cases,

- * *_minsize constants are provided to be used in place of sizeof.  For a

- * cleaner interface to these sizes when using C++, see minidump_size.h.

- *

- * These structures are also sufficient to populate minidump files.

- *

- * These definitions may be extended to support handling minidump files

- * for other CPUs and other operating systems.

- *

- * Because precise data type sizes are crucial for this implementation to

- * function properly and portably in terms of interoperability with minidumps

- * produced by DbgHelp on Windows, a set of primitive types with known sizes

- * are used as the basis of each structure defined by this file.  DbgHelp

- * on Windows is assumed to be the reference implementation; this file

- * seeks to provide a cross-platform compatible implementation.  To avoid

- * collisions with the types and values defined and used by DbgHelp in the

- * event that this implementation is used on Windows, each type and value

- * defined here is given a new name, beginning with "MD".  Names of the

- * equivalent types and values in the Windows Platform SDK are given in

- * comments.

- *

- * Author: Neal Sidhwaney */

-

-

-/*

- * Breakpad minidump extension for PPC64 support.  Based on Darwin/Mac OS X'

- * mach/ppc/_types.h

- */

-

-#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__

-#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__

-

-#include "minidump_cpu_ppc.h"

-

-// these types are the same in ppc64 & ppc

-typedef MDFloatingSaveAreaPPC MDFloatingSaveAreaPPC64;

-typedef MDVectorSaveAreaPPC MDVectorSaveAreaPPC64;

-

-#define MD_CONTEXT_PPC64_GPR_COUNT MD_CONTEXT_PPC_GPR_COUNT

-

-typedef struct {

-  /* context_flags is not present in ppc_thread_state, but it aids

-   * identification of MDRawContextPPC among other raw context types,

-   * and it guarantees alignment when we get to float_save. */

-  u_int64_t             context_flags;

-

-  u_int64_t             srr0;    /* Machine status save/restore: stores pc

-                                  * (instruction) */

-  u_int64_t             srr1;    /* Machine status save/restore: stores msr

-                                  * (ps, program/machine state) */

-  /* ppc_thread_state contains 32 fields, r0 .. r31.  Here, an array is

-   * used for brevity. */

-  u_int64_t             gpr[MD_CONTEXT_PPC64_GPR_COUNT];

-  u_int64_t             cr;      /* Condition */

-  u_int64_t             xer;     /* Integer (fiXed-point) exception */

-  u_int64_t             lr;      /* Link */

-  u_int64_t             ctr;     /* Count */

-  u_int64_t             vrsave;  /* Vector save */

-

-  /* float_save and vector_save aren't present in ppc_thread_state, but

-   * are represented in separate structures that still define a thread's

-   * context. */

-  MDFloatingSaveAreaPPC float_save;

-  MDVectorSaveAreaPPC   vector_save;

-} MDRawContextPPC64;  /* Based on ppc_thread_state */

-

-/* For (MDRawContextPPC).context_flags.  These values indicate the type of

- * context stored in the structure.  MD_CONTEXT_PPC is Breakpad-defined.  Its

- * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other

- * CPUs. */

-#define MD_CONTEXT_PPC                0x20000000

-#define MD_CONTEXT_PPC_BASE           (MD_CONTEXT_PPC | 0x00000001)

-#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)

-#define MD_CONTEXT_PPC_VECTOR         (MD_CONTEXT_PPC | 0x00000020)

-

-#define MD_CONTEXT_PPC_FULL           MD_CONTEXT_PPC_BASE

-#define MD_CONTEXT_PPC_ALL            (MD_CONTEXT_PPC_FULL | \

-                                       MD_CONTEXT_PPC_FLOATING_POINT | \

-                                       MD_CONTEXT_PPC_VECTOR)

-

-#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */

+/* Copyright (c) 2008, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_format.h: A cross-platform reimplementation of minidump-related
+ * portions of DbgHelp.h from the Windows Platform SDK.
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * This file contains the necessary definitions to read minidump files
+ * produced on ppc64.  These files may be read on any platform provided
+ * that the alignments of these structures on the processing system are
+ * identical to the alignments of these structures on the producing system.
+ * For this reason, precise-sized types are used.  The structures defined
+ * by this file have been laid out to minimize alignment problems by ensuring
+ * ensuring that all members are aligned on their natural boundaries.  In
+ * In some cases, tail-padding may be significant when different ABIs specify
+ * different tail-padding behaviors.  To avoid problems when reading or
+ * writing affected structures, MD_*_SIZE macros are provided where needed,
+ * containing the useful size of the structures without padding.
+ *
+ * Structures that are defined by Microsoft to contain a zero-length array
+ * are instead defined here to contain an array with one element, as
+ * zero-length arrays are forbidden by standard C and C++.  In these cases,
+ * *_minsize constants are provided to be used in place of sizeof.  For a
+ * cleaner interface to these sizes when using C++, see minidump_size.h.
+ *
+ * These structures are also sufficient to populate minidump files.
+ *
+ * These definitions may be extended to support handling minidump files
+ * for other CPUs and other operating systems.
+ *
+ * Because precise data type sizes are crucial for this implementation to
+ * function properly and portably in terms of interoperability with minidumps
+ * produced by DbgHelp on Windows, a set of primitive types with known sizes
+ * are used as the basis of each structure defined by this file.  DbgHelp
+ * on Windows is assumed to be the reference implementation; this file
+ * seeks to provide a cross-platform compatible implementation.  To avoid
+ * collisions with the types and values defined and used by DbgHelp in the
+ * event that this implementation is used on Windows, each type and value
+ * defined here is given a new name, beginning with "MD".  Names of the
+ * equivalent types and values in the Windows Platform SDK are given in
+ * comments.
+ *
+ * Author: Neal Sidhwaney */
+
+
+/*
+ * Breakpad minidump extension for PPC64 support.  Based on Darwin/Mac OS X'
+ * mach/ppc/_types.h
+ */
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__
+
+#include "minidump_cpu_ppc.h"
+
+// these types are the same in ppc64 & ppc
+typedef MDFloatingSaveAreaPPC MDFloatingSaveAreaPPC64;
+typedef MDVectorSaveAreaPPC MDVectorSaveAreaPPC64;
+
+#define MD_CONTEXT_PPC64_GPR_COUNT MD_CONTEXT_PPC_GPR_COUNT
+
+typedef struct {
+  /* context_flags is not present in ppc_thread_state, but it aids
+   * identification of MDRawContextPPC among other raw context types,
+   * and it guarantees alignment when we get to float_save. */
+  u_int64_t             context_flags;
+
+  u_int64_t             srr0;    /* Machine status save/restore: stores pc
+                                  * (instruction) */
+  u_int64_t             srr1;    /* Machine status save/restore: stores msr
+                                  * (ps, program/machine state) */
+  /* ppc_thread_state contains 32 fields, r0 .. r31.  Here, an array is
+   * used for brevity. */
+  u_int64_t             gpr[MD_CONTEXT_PPC64_GPR_COUNT];
+  u_int64_t             cr;      /* Condition */
+  u_int64_t             xer;     /* Integer (fiXed-point) exception */
+  u_int64_t             lr;      /* Link */
+  u_int64_t             ctr;     /* Count */
+  u_int64_t             vrsave;  /* Vector save */
+
+  /* float_save and vector_save aren't present in ppc_thread_state, but
+   * are represented in separate structures that still define a thread's
+   * context. */
+  MDFloatingSaveAreaPPC float_save;
+  MDVectorSaveAreaPPC   vector_save;
+} MDRawContextPPC64;  /* Based on ppc_thread_state */
+
+/* For (MDRawContextPPC).context_flags.  These values indicate the type of
+ * context stored in the structure.  MD_CONTEXT_PPC is Breakpad-defined.  Its
+ * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
+ * CPUs. */
+#define MD_CONTEXT_PPC                0x20000000
+#define MD_CONTEXT_PPC_BASE           (MD_CONTEXT_PPC | 0x00000001)
+#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008)
+#define MD_CONTEXT_PPC_VECTOR         (MD_CONTEXT_PPC | 0x00000020)
+
+#define MD_CONTEXT_PPC_FULL           MD_CONTEXT_PPC_BASE
+#define MD_CONTEXT_PPC_ALL            (MD_CONTEXT_PPC_FULL | \
+                                       MD_CONTEXT_PPC_FLOATING_POINT | \
+                                       MD_CONTEXT_PPC_VECTOR)
+
+#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */
diff --git a/third_party/breakpad/src/google_breakpad/common/minidump_cpu_sparc.h b/third_party/breakpad/src/google_breakpad/common/minidump_cpu_sparc.h
index 26ff0fe..ee95b64 100644
--- a/third_party/breakpad/src/google_breakpad/common/minidump_cpu_sparc.h
+++ b/third_party/breakpad/src/google_breakpad/common/minidump_cpu_sparc.h
@@ -1,158 +1,158 @@
-/* Copyright (c) 2006, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* minidump_format.h: A cross-platform reimplementation of minidump-related

- * portions of DbgHelp.h from the Windows Platform SDK.

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * This file contains the necessary definitions to read minidump files

- * produced on sparc.  These files may be read on any platform provided

- * that the alignments of these structures on the processing system are

- * identical to the alignments of these structures on the producing system.

- * For this reason, precise-sized types are used.  The structures defined

- * by this file have been laid out to minimize alignment problems by ensuring

- * ensuring that all members are aligned on their natural boundaries.  In

- * In some cases, tail-padding may be significant when different ABIs specify

- * different tail-padding behaviors.  To avoid problems when reading or

- * writing affected structures, MD_*_SIZE macros are provided where needed,

- * containing the useful size of the structures without padding.

- *

- * Structures that are defined by Microsoft to contain a zero-length array

- * are instead defined here to contain an array with one element, as

- * zero-length arrays are forbidden by standard C and C++.  In these cases,

- * *_minsize constants are provided to be used in place of sizeof.  For a

- * cleaner interface to these sizes when using C++, see minidump_size.h.

- *

- * These structures are also sufficient to populate minidump files.

- *

- * These definitions may be extended to support handling minidump files

- * for other CPUs and other operating systems.

- *

- * Because precise data type sizes are crucial for this implementation to

- * function properly and portably in terms of interoperability with minidumps

- * produced by DbgHelp on Windows, a set of primitive types with known sizes

- * are used as the basis of each structure defined by this file.  DbgHelp

- * on Windows is assumed to be the reference implementation; this file

- * seeks to provide a cross-platform compatible implementation.  To avoid

- * collisions with the types and values defined and used by DbgHelp in the

- * event that this implementation is used on Windows, each type and value

- * defined here is given a new name, beginning with "MD".  Names of the

- * equivalent types and values in the Windows Platform SDK are given in

- * comments.

- *

- * Author: Mark Mentovai

- * Change to split into its own file: Neal Sidhwaney */

-

-/*

- * SPARC support, see (solaris)sys/procfs_isa.h also

- */

-

-#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__

-#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__

-

-#define MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT 32

-

-typedef struct {

-

-  /* FPU floating point regs */

-  u_int64_t	regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];

-

-  u_int64_t	filler;

-  u_int64_t	fsr;        /* FPU status register */

-} MDFloatingSaveAreaSPARC;  /* FLOATING_SAVE_AREA */

-

-#define MD_CONTEXT_SPARC_GPR_COUNT 32

-

-typedef struct {

-  /* The next field determines the layout of the structure, and which parts

-   * of it are populated

-   */

-  u_int32_t	context_flags;

-  u_int32_t	flag_pad;

-  /*

-   * General register access (SPARC).

-   * Don't confuse definitions here with definitions in <sys/regset.h>.

-   * Registers are 32 bits for ILP32, 64 bits for LP64.

-   * SPARC V7/V8 is for 32bit, SPARC V9 is for 64bit

-   */

-

-  /* 32 Integer working registers */

-

-  /* g_r[0-7]   global registers(g0-g7)

-   * g_r[8-15]  out registers(o0-o7)

-   * g_r[16-23] local registers(l0-l7)

-   * g_r[24-31] in registers(i0-i7)

-   */

-  u_int64_t     g_r[MD_CONTEXT_SPARC_GPR_COUNT];

-

-  /* several control registers */

-

-  /* Processor State register(PSR) for SPARC V7/V8

-   * Condition Code register (CCR) for SPARC V9

-   */

-  u_int64_t     ccr;

-

-  u_int64_t     pc;     /* Program Counter register (PC) */

-  u_int64_t     npc;    /* Next Program Counter register (nPC) */

-  u_int64_t     y;      /* Y register (Y) */

-

-  /* Address Space Identifier register (ASI) for SPARC V9

-   * WIM for SPARC V7/V8

-   */

-  u_int64_t     asi;

-

-  /* Floating-Point Registers State register (FPRS) for SPARC V9

-   * TBR for for SPARC V7/V8

-   */

-  u_int64_t     fprs;

-

-  /* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */

-  MDFloatingSaveAreaSPARC float_save;

-

-} MDRawContextSPARC;  /* CONTEXT_SPARC */

-

-/* For (MDRawContextSPARC).context_flags.  These values indicate the type of

- * context stored in the structure.  MD_CONTEXT_SPARC is Breakpad-defined.  Its

- * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other

- * CPUs. */

-#define MD_CONTEXT_SPARC                 0x10000000

-#define MD_CONTEXT_SPARC_CONTROL         (MD_CONTEXT_SPARC | 0x00000001)

-#define MD_CONTEXT_SPARC_INTEGER         (MD_CONTEXT_SPARC | 0x00000002)

-#define MD_CONTEXT_SAPARC_FLOATING_POINT (MD_CONTEXT_SPARC | 0x00000004)

-#define MD_CONTEXT_SAPARC_EXTRA          (MD_CONTEXT_SPARC | 0x00000008)

-

-#define MD_CONTEXT_SPARC_FULL            (MD_CONTEXT_SPARC_CONTROL | \

-                                          MD_CONTEXT_SPARC_INTEGER)

-

-#define MD_CONTEXT_SPARC_ALL             (MD_CONTEXT_SPARC_FULL | \

-                                          MD_CONTEXT_SAPARC_FLOATING_POINT | \

-                                          MD_CONTEXT_SAPARC_EXTRA)

-

-#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ */

+/* Copyright (c) 2006, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_format.h: A cross-platform reimplementation of minidump-related
+ * portions of DbgHelp.h from the Windows Platform SDK.
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * This file contains the necessary definitions to read minidump files
+ * produced on sparc.  These files may be read on any platform provided
+ * that the alignments of these structures on the processing system are
+ * identical to the alignments of these structures on the producing system.
+ * For this reason, precise-sized types are used.  The structures defined
+ * by this file have been laid out to minimize alignment problems by ensuring
+ * ensuring that all members are aligned on their natural boundaries.  In
+ * In some cases, tail-padding may be significant when different ABIs specify
+ * different tail-padding behaviors.  To avoid problems when reading or
+ * writing affected structures, MD_*_SIZE macros are provided where needed,
+ * containing the useful size of the structures without padding.
+ *
+ * Structures that are defined by Microsoft to contain a zero-length array
+ * are instead defined here to contain an array with one element, as
+ * zero-length arrays are forbidden by standard C and C++.  In these cases,
+ * *_minsize constants are provided to be used in place of sizeof.  For a
+ * cleaner interface to these sizes when using C++, see minidump_size.h.
+ *
+ * These structures are also sufficient to populate minidump files.
+ *
+ * These definitions may be extended to support handling minidump files
+ * for other CPUs and other operating systems.
+ *
+ * Because precise data type sizes are crucial for this implementation to
+ * function properly and portably in terms of interoperability with minidumps
+ * produced by DbgHelp on Windows, a set of primitive types with known sizes
+ * are used as the basis of each structure defined by this file.  DbgHelp
+ * on Windows is assumed to be the reference implementation; this file
+ * seeks to provide a cross-platform compatible implementation.  To avoid
+ * collisions with the types and values defined and used by DbgHelp in the
+ * event that this implementation is used on Windows, each type and value
+ * defined here is given a new name, beginning with "MD".  Names of the
+ * equivalent types and values in the Windows Platform SDK are given in
+ * comments.
+ *
+ * Author: Mark Mentovai
+ * Change to split into its own file: Neal Sidhwaney */
+
+/*
+ * SPARC support, see (solaris)sys/procfs_isa.h also
+ */
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__
+
+#define MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT 32
+
+typedef struct {
+
+  /* FPU floating point regs */
+  u_int64_t	regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];
+
+  u_int64_t	filler;
+  u_int64_t	fsr;        /* FPU status register */
+} MDFloatingSaveAreaSPARC;  /* FLOATING_SAVE_AREA */
+
+#define MD_CONTEXT_SPARC_GPR_COUNT 32
+
+typedef struct {
+  /* The next field determines the layout of the structure, and which parts
+   * of it are populated
+   */
+  u_int32_t	context_flags;
+  u_int32_t	flag_pad;
+  /*
+   * General register access (SPARC).
+   * Don't confuse definitions here with definitions in <sys/regset.h>.
+   * Registers are 32 bits for ILP32, 64 bits for LP64.
+   * SPARC V7/V8 is for 32bit, SPARC V9 is for 64bit
+   */
+
+  /* 32 Integer working registers */
+
+  /* g_r[0-7]   global registers(g0-g7)
+   * g_r[8-15]  out registers(o0-o7)
+   * g_r[16-23] local registers(l0-l7)
+   * g_r[24-31] in registers(i0-i7)
+   */
+  u_int64_t     g_r[MD_CONTEXT_SPARC_GPR_COUNT];
+
+  /* several control registers */
+
+  /* Processor State register(PSR) for SPARC V7/V8
+   * Condition Code register (CCR) for SPARC V9
+   */
+  u_int64_t     ccr;
+
+  u_int64_t     pc;     /* Program Counter register (PC) */
+  u_int64_t     npc;    /* Next Program Counter register (nPC) */
+  u_int64_t     y;      /* Y register (Y) */
+
+  /* Address Space Identifier register (ASI) for SPARC V9
+   * WIM for SPARC V7/V8
+   */
+  u_int64_t     asi;
+
+  /* Floating-Point Registers State register (FPRS) for SPARC V9
+   * TBR for for SPARC V7/V8
+   */
+  u_int64_t     fprs;
+
+  /* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */
+  MDFloatingSaveAreaSPARC float_save;
+
+} MDRawContextSPARC;  /* CONTEXT_SPARC */
+
+/* For (MDRawContextSPARC).context_flags.  These values indicate the type of
+ * context stored in the structure.  MD_CONTEXT_SPARC is Breakpad-defined.  Its
+ * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other
+ * CPUs. */
+#define MD_CONTEXT_SPARC                 0x10000000
+#define MD_CONTEXT_SPARC_CONTROL         (MD_CONTEXT_SPARC | 0x00000001)
+#define MD_CONTEXT_SPARC_INTEGER         (MD_CONTEXT_SPARC | 0x00000002)
+#define MD_CONTEXT_SAPARC_FLOATING_POINT (MD_CONTEXT_SPARC | 0x00000004)
+#define MD_CONTEXT_SAPARC_EXTRA          (MD_CONTEXT_SPARC | 0x00000008)
+
+#define MD_CONTEXT_SPARC_FULL            (MD_CONTEXT_SPARC_CONTROL | \
+                                          MD_CONTEXT_SPARC_INTEGER)
+
+#define MD_CONTEXT_SPARC_ALL             (MD_CONTEXT_SPARC_FULL | \
+                                          MD_CONTEXT_SAPARC_FLOATING_POINT | \
+                                          MD_CONTEXT_SAPARC_EXTRA)
+
+#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ */
diff --git a/third_party/breakpad/src/google_breakpad/common/minidump_cpu_x86.h b/third_party/breakpad/src/google_breakpad/common/minidump_cpu_x86.h
index 076e279..4dbc0e9 100644
--- a/third_party/breakpad/src/google_breakpad/common/minidump_cpu_x86.h
+++ b/third_party/breakpad/src/google_breakpad/common/minidump_cpu_x86.h
@@ -1,172 +1,172 @@
-/* Copyright (c) 2006, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* minidump_format.h: A cross-platform reimplementation of minidump-related

- * portions of DbgHelp.h from the Windows Platform SDK.

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * This file contains the necessary definitions to read minidump files

- * produced on x86.  These files may be read on any platform provided

- * that the alignments of these structures on the processing system are

- * identical to the alignments of these structures on the producing system.

- * For this reason, precise-sized types are used.  The structures defined

- * by this file have been laid out to minimize alignment problems by ensuring

- * ensuring that all members are aligned on their natural boundaries.  In

- * In some cases, tail-padding may be significant when different ABIs specify

- * different tail-padding behaviors.  To avoid problems when reading or

- * writing affected structures, MD_*_SIZE macros are provided where needed,

- * containing the useful size of the structures without padding.

- *

- * Structures that are defined by Microsoft to contain a zero-length array

- * are instead defined here to contain an array with one element, as

- * zero-length arrays are forbidden by standard C and C++.  In these cases,

- * *_minsize constants are provided to be used in place of sizeof.  For a

- * cleaner interface to these sizes when using C++, see minidump_size.h.

- *

- * These structures are also sufficient to populate minidump files.

- *

- * These definitions may be extended to support handling minidump files

- * for other CPUs and other operating systems.

- *

- * Because precise data type sizes are crucial for this implementation to

- * function properly and portably in terms of interoperability with minidumps

- * produced by DbgHelp on Windows, a set of primitive types with known sizes

- * are used as the basis of each structure defined by this file.  DbgHelp

- * on Windows is assumed to be the reference implementation; this file

- * seeks to provide a cross-platform compatible implementation.  To avoid

- * collisions with the types and values defined and used by DbgHelp in the

- * event that this implementation is used on Windows, each type and value

- * defined here is given a new name, beginning with "MD".  Names of the

- * equivalent types and values in the Windows Platform SDK are given in

- * comments.

- *

- * Author: Mark Mentovai */

-

-#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__

-#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__

-

-#define MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE 80

-     /* SIZE_OF_80387_REGISTERS */

-

-typedef struct {

-  u_int32_t control_word;

-  u_int32_t status_word;

-  u_int32_t tag_word;

-  u_int32_t error_offset;

-  u_int32_t error_selector;

-  u_int32_t data_offset;

-  u_int32_t data_selector;

-

-  /* register_area contains eight 80-bit (x87 "long double") quantities for

-   * floating-point registers %st0 (%mm0) through %st7 (%mm7). */

-  u_int8_t  register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE];

-  u_int32_t cr0_npx_state;

-} MDFloatingSaveAreaX86;  /* FLOATING_SAVE_AREA */

-

-

-#define MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE 512

-     /* MAXIMUM_SUPPORTED_EXTENSION */

-

-typedef struct {

-  /* The next field determines the layout of the structure, and which parts

-   * of it are populated */

-  u_int32_t             context_flags;

-

-  /* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */

-  u_int32_t             dr0;

-  u_int32_t             dr1;

-  u_int32_t             dr2;

-  u_int32_t             dr3;

-  u_int32_t             dr6;

-  u_int32_t             dr7;

-

-  /* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */

-  MDFloatingSaveAreaX86 float_save;

-

-  /* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */

-  u_int32_t             gs; 

-  u_int32_t             fs;

-  u_int32_t             es;

-  u_int32_t             ds;

-  /* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */

-  u_int32_t             edi;

-  u_int32_t             esi;

-  u_int32_t             ebx;

-  u_int32_t             edx;

-  u_int32_t             ecx;

-  u_int32_t             eax;

-

-  /* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */

-  u_int32_t             ebp;

-  u_int32_t             eip;

-  u_int32_t             cs;      /* WinNT.h says "must be sanitized" */

-  u_int32_t             eflags;  /* WinNT.h says "must be sanitized" */

-  u_int32_t             esp;

-  u_int32_t             ss;

-

-  /* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS.

-   * It contains vector (MMX/SSE) registers.  It it laid out in the

-   * format used by the fxsave and fsrstor instructions, so it includes

-   * a copy of the x87 floating-point registers as well.  See FXSAVE in

-   * "Intel Architecture Software Developer's Manual, Volume 2." */

-  u_int8_t              extended_registers[

-                         MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE];

-} MDRawContextX86;  /* CONTEXT */

-

-/* For (MDRawContextX86).context_flags.  These values indicate the type of

- * context stored in the structure.  The high 26 bits identify the CPU, the

- * low 6 bits identify the type of context saved. */

-#define MD_CONTEXT_X86                    0x00010000

-     /* CONTEXT_i386, CONTEXT_i486: identifies CPU */

-#define MD_CONTEXT_X86_CONTROL            (MD_CONTEXT_X86 | 0x00000001)

-     /* CONTEXT_CONTROL */

-#define MD_CONTEXT_X86_INTEGER            (MD_CONTEXT_X86 | 0x00000002)

-     /* CONTEXT_INTEGER */

-#define MD_CONTEXT_X86_SEGMENTS           (MD_CONTEXT_X86 | 0x00000004)

-     /* CONTEXT_SEGMENTS */

-#define MD_CONTEXT_X86_FLOATING_POINT     (MD_CONTEXT_X86 | 0x00000008)

-     /* CONTEXT_FLOATING_POINT */

-#define MD_CONTEXT_X86_DEBUG_REGISTERS    (MD_CONTEXT_X86 | 0x00000010)

-     /* CONTEXT_DEBUG_REGISTERS */

-#define MD_CONTEXT_X86_EXTENDED_REGISTERS (MD_CONTEXT_X86 | 0x00000020)

-     /* CONTEXT_EXTENDED_REGISTERS */

-

-#define MD_CONTEXT_X86_FULL              (MD_CONTEXT_X86_CONTROL | \

-                                          MD_CONTEXT_X86_INTEGER | \

-                                          MD_CONTEXT_X86_SEGMENTS)

-     /* CONTEXT_FULL */

-

-#define MD_CONTEXT_X86_ALL               (MD_CONTEXT_X86_FULL | \

-                                          MD_CONTEXT_X86_FLOATING_POINT | \

-                                          MD_CONTEXT_X86_DEBUG_REGISTERS | \

-                                          MD_CONTEXT_X86_EXTENDED_REGISTERS)

-     /* CONTEXT_ALL */

-

-#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ */

+/* Copyright (c) 2006, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_format.h: A cross-platform reimplementation of minidump-related
+ * portions of DbgHelp.h from the Windows Platform SDK.
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * This file contains the necessary definitions to read minidump files
+ * produced on x86.  These files may be read on any platform provided
+ * that the alignments of these structures on the processing system are
+ * identical to the alignments of these structures on the producing system.
+ * For this reason, precise-sized types are used.  The structures defined
+ * by this file have been laid out to minimize alignment problems by ensuring
+ * ensuring that all members are aligned on their natural boundaries.  In
+ * In some cases, tail-padding may be significant when different ABIs specify
+ * different tail-padding behaviors.  To avoid problems when reading or
+ * writing affected structures, MD_*_SIZE macros are provided where needed,
+ * containing the useful size of the structures without padding.
+ *
+ * Structures that are defined by Microsoft to contain a zero-length array
+ * are instead defined here to contain an array with one element, as
+ * zero-length arrays are forbidden by standard C and C++.  In these cases,
+ * *_minsize constants are provided to be used in place of sizeof.  For a
+ * cleaner interface to these sizes when using C++, see minidump_size.h.
+ *
+ * These structures are also sufficient to populate minidump files.
+ *
+ * These definitions may be extended to support handling minidump files
+ * for other CPUs and other operating systems.
+ *
+ * Because precise data type sizes are crucial for this implementation to
+ * function properly and portably in terms of interoperability with minidumps
+ * produced by DbgHelp on Windows, a set of primitive types with known sizes
+ * are used as the basis of each structure defined by this file.  DbgHelp
+ * on Windows is assumed to be the reference implementation; this file
+ * seeks to provide a cross-platform compatible implementation.  To avoid
+ * collisions with the types and values defined and used by DbgHelp in the
+ * event that this implementation is used on Windows, each type and value
+ * defined here is given a new name, beginning with "MD".  Names of the
+ * equivalent types and values in the Windows Platform SDK are given in
+ * comments.
+ *
+ * Author: Mark Mentovai */
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__
+
+#define MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE 80
+     /* SIZE_OF_80387_REGISTERS */
+
+typedef struct {
+  u_int32_t control_word;
+  u_int32_t status_word;
+  u_int32_t tag_word;
+  u_int32_t error_offset;
+  u_int32_t error_selector;
+  u_int32_t data_offset;
+  u_int32_t data_selector;
+
+  /* register_area contains eight 80-bit (x87 "long double") quantities for
+   * floating-point registers %st0 (%mm0) through %st7 (%mm7). */
+  u_int8_t  register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE];
+  u_int32_t cr0_npx_state;
+} MDFloatingSaveAreaX86;  /* FLOATING_SAVE_AREA */
+
+
+#define MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE 512
+     /* MAXIMUM_SUPPORTED_EXTENSION */
+
+typedef struct {
+  /* The next field determines the layout of the structure, and which parts
+   * of it are populated */
+  u_int32_t             context_flags;
+
+  /* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */
+  u_int32_t             dr0;
+  u_int32_t             dr1;
+  u_int32_t             dr2;
+  u_int32_t             dr3;
+  u_int32_t             dr6;
+  u_int32_t             dr7;
+
+  /* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */
+  MDFloatingSaveAreaX86 float_save;
+
+  /* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */
+  u_int32_t             gs; 
+  u_int32_t             fs;
+  u_int32_t             es;
+  u_int32_t             ds;
+  /* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */
+  u_int32_t             edi;
+  u_int32_t             esi;
+  u_int32_t             ebx;
+  u_int32_t             edx;
+  u_int32_t             ecx;
+  u_int32_t             eax;
+
+  /* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */
+  u_int32_t             ebp;
+  u_int32_t             eip;
+  u_int32_t             cs;      /* WinNT.h says "must be sanitized" */
+  u_int32_t             eflags;  /* WinNT.h says "must be sanitized" */
+  u_int32_t             esp;
+  u_int32_t             ss;
+
+  /* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS.
+   * It contains vector (MMX/SSE) registers.  It it laid out in the
+   * format used by the fxsave and fsrstor instructions, so it includes
+   * a copy of the x87 floating-point registers as well.  See FXSAVE in
+   * "Intel Architecture Software Developer's Manual, Volume 2." */
+  u_int8_t              extended_registers[
+                         MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE];
+} MDRawContextX86;  /* CONTEXT */
+
+/* For (MDRawContextX86).context_flags.  These values indicate the type of
+ * context stored in the structure.  The high 26 bits identify the CPU, the
+ * low 6 bits identify the type of context saved. */
+#define MD_CONTEXT_X86                    0x00010000
+     /* CONTEXT_i386, CONTEXT_i486: identifies CPU */
+#define MD_CONTEXT_X86_CONTROL            (MD_CONTEXT_X86 | 0x00000001)
+     /* CONTEXT_CONTROL */
+#define MD_CONTEXT_X86_INTEGER            (MD_CONTEXT_X86 | 0x00000002)
+     /* CONTEXT_INTEGER */
+#define MD_CONTEXT_X86_SEGMENTS           (MD_CONTEXT_X86 | 0x00000004)
+     /* CONTEXT_SEGMENTS */
+#define MD_CONTEXT_X86_FLOATING_POINT     (MD_CONTEXT_X86 | 0x00000008)
+     /* CONTEXT_FLOATING_POINT */
+#define MD_CONTEXT_X86_DEBUG_REGISTERS    (MD_CONTEXT_X86 | 0x00000010)
+     /* CONTEXT_DEBUG_REGISTERS */
+#define MD_CONTEXT_X86_EXTENDED_REGISTERS (MD_CONTEXT_X86 | 0x00000020)
+     /* CONTEXT_EXTENDED_REGISTERS */
+
+#define MD_CONTEXT_X86_FULL              (MD_CONTEXT_X86_CONTROL | \
+                                          MD_CONTEXT_X86_INTEGER | \
+                                          MD_CONTEXT_X86_SEGMENTS)
+     /* CONTEXT_FULL */
+
+#define MD_CONTEXT_X86_ALL               (MD_CONTEXT_X86_FULL | \
+                                          MD_CONTEXT_X86_FLOATING_POINT | \
+                                          MD_CONTEXT_X86_DEBUG_REGISTERS | \
+                                          MD_CONTEXT_X86_EXTENDED_REGISTERS)
+     /* CONTEXT_ALL */
+
+#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ */
diff --git a/third_party/breakpad/src/google_breakpad/common/minidump_exception_linux.h b/third_party/breakpad/src/google_breakpad/common/minidump_exception_linux.h
index a126349..d52c751 100644
--- a/third_party/breakpad/src/google_breakpad/common/minidump_exception_linux.h
+++ b/third_party/breakpad/src/google_breakpad/common/minidump_exception_linux.h
@@ -1,85 +1,85 @@
-/* Copyright (c) 2006, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* minidump_exception_linux.h: A definition of exception codes for

- * Linux

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * Author: Mark Mentovai

- * Split into its own file: Neal Sidhwaney */

- 

-

-#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__

-#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__

-

-#include <stddef.h>

-

-#include "google_breakpad/common/breakpad_types.h"

-

-

-/* For (MDException).exception_code.  These values come from bits/signum.h.

- */

-typedef enum {

-  MD_EXCEPTION_CODE_LIN_SIGHUP = 1,      /* Hangup (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGINT = 2,      /* Interrupt (ANSI) */

-  MD_EXCEPTION_CODE_LIN_SIGQUIT = 3,     /* Quit (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGILL = 4,      /* Illegal instruction (ANSI) */

-  MD_EXCEPTION_CODE_LIN_SIGTRAP = 5,     /* Trace trap (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGABRT = 6,     /* Abort (ANSI) */

-  MD_EXCEPTION_CODE_LIN_SIGBUS = 7,      /* BUS error (4.2 BSD) */

-  MD_EXCEPTION_CODE_LIN_SIGFPE = 8,      /* Floating-point exception (ANSI) */

-  MD_EXCEPTION_CODE_LIN_SIGKILL = 9,     /* Kill, unblockable (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGUSR1 = 10,    /* User-defined signal 1 (POSIX).  */

-  MD_EXCEPTION_CODE_LIN_SIGSEGV = 11,    /* Segmentation violation (ANSI) */

-  MD_EXCEPTION_CODE_LIN_SIGUSR2 = 12,    /* User-defined signal 2 (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGPIPE = 13,    /* Broken pipe (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGALRM = 14,    /* Alarm clock (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGTERM = 15,    /* Termination (ANSI) */

-  MD_EXCEPTION_CODE_LIN_SIGSTKFLT = 16,  /* Stack faultd */

-  MD_EXCEPTION_CODE_LIN_SIGCHLD = 17,    /* Child status has changed (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGCONT = 18,    /* Continue (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGSTOP = 19,    /* Stop, unblockable (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGTSTP = 20,    /* Keyboard stop (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGTTIN = 21,    /* Background read from tty (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGTTOU = 22,    /* Background write to tty (POSIX) */

-  MD_EXCEPTION_CODE_LIN_SIGURG = 23,

-    /* Urgent condition on socket (4.2 BSD) */

-  MD_EXCEPTION_CODE_LIN_SIGXCPU = 24,    /* CPU limit exceeded (4.2 BSD) */

-  MD_EXCEPTION_CODE_LIN_SIGXFSZ = 25,

-    /* File size limit exceeded (4.2 BSD) */

-  MD_EXCEPTION_CODE_LIN_SIGVTALRM = 26,  /* Virtual alarm clock (4.2 BSD) */

-  MD_EXCEPTION_CODE_LIN_SIGPROF = 27,    /* Profiling alarm clock (4.2 BSD) */

-  MD_EXCEPTION_CODE_LIN_SIGWINCH = 28,   /* Window size change (4.3 BSD, Sun) */

-  MD_EXCEPTION_CODE_LIN_SIGIO = 29,      /* I/O now possible (4.2 BSD) */

-  MD_EXCEPTION_CODE_LIN_SIGPWR = 30,     /* Power failure restart (System V) */

-  MD_EXCEPTION_CODE_LIN_SIGSYS = 31      /* Bad system call */

-} MDExceptionCodeLinux;

-

-#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */

+/* Copyright (c) 2006, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_exception_linux.h: A definition of exception codes for
+ * Linux
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * Author: Mark Mentovai
+ * Split into its own file: Neal Sidhwaney */
+ 
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__
+
+#include <stddef.h>
+
+#include "google_breakpad/common/breakpad_types.h"
+
+
+/* For (MDException).exception_code.  These values come from bits/signum.h.
+ */
+typedef enum {
+  MD_EXCEPTION_CODE_LIN_SIGHUP = 1,      /* Hangup (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGINT = 2,      /* Interrupt (ANSI) */
+  MD_EXCEPTION_CODE_LIN_SIGQUIT = 3,     /* Quit (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGILL = 4,      /* Illegal instruction (ANSI) */
+  MD_EXCEPTION_CODE_LIN_SIGTRAP = 5,     /* Trace trap (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGABRT = 6,     /* Abort (ANSI) */
+  MD_EXCEPTION_CODE_LIN_SIGBUS = 7,      /* BUS error (4.2 BSD) */
+  MD_EXCEPTION_CODE_LIN_SIGFPE = 8,      /* Floating-point exception (ANSI) */
+  MD_EXCEPTION_CODE_LIN_SIGKILL = 9,     /* Kill, unblockable (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGUSR1 = 10,    /* User-defined signal 1 (POSIX).  */
+  MD_EXCEPTION_CODE_LIN_SIGSEGV = 11,    /* Segmentation violation (ANSI) */
+  MD_EXCEPTION_CODE_LIN_SIGUSR2 = 12,    /* User-defined signal 2 (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGPIPE = 13,    /* Broken pipe (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGALRM = 14,    /* Alarm clock (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGTERM = 15,    /* Termination (ANSI) */
+  MD_EXCEPTION_CODE_LIN_SIGSTKFLT = 16,  /* Stack faultd */
+  MD_EXCEPTION_CODE_LIN_SIGCHLD = 17,    /* Child status has changed (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGCONT = 18,    /* Continue (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGSTOP = 19,    /* Stop, unblockable (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGTSTP = 20,    /* Keyboard stop (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGTTIN = 21,    /* Background read from tty (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGTTOU = 22,    /* Background write to tty (POSIX) */
+  MD_EXCEPTION_CODE_LIN_SIGURG = 23,
+    /* Urgent condition on socket (4.2 BSD) */
+  MD_EXCEPTION_CODE_LIN_SIGXCPU = 24,    /* CPU limit exceeded (4.2 BSD) */
+  MD_EXCEPTION_CODE_LIN_SIGXFSZ = 25,
+    /* File size limit exceeded (4.2 BSD) */
+  MD_EXCEPTION_CODE_LIN_SIGVTALRM = 26,  /* Virtual alarm clock (4.2 BSD) */
+  MD_EXCEPTION_CODE_LIN_SIGPROF = 27,    /* Profiling alarm clock (4.2 BSD) */
+  MD_EXCEPTION_CODE_LIN_SIGWINCH = 28,   /* Window size change (4.3 BSD, Sun) */
+  MD_EXCEPTION_CODE_LIN_SIGIO = 29,      /* I/O now possible (4.2 BSD) */
+  MD_EXCEPTION_CODE_LIN_SIGPWR = 30,     /* Power failure restart (System V) */
+  MD_EXCEPTION_CODE_LIN_SIGSYS = 31      /* Bad system call */
+} MDExceptionCodeLinux;
+
+#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */
diff --git a/third_party/breakpad/src/google_breakpad/common/minidump_exception_mac.h b/third_party/breakpad/src/google_breakpad/common/minidump_exception_mac.h
index 7b6198d..5fba44c 100644
--- a/third_party/breakpad/src/google_breakpad/common/minidump_exception_mac.h
+++ b/third_party/breakpad/src/google_breakpad/common/minidump_exception_mac.h
@@ -1,193 +1,193 @@
-/* Copyright (c) 2006, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* minidump_exception_mac.h: A definition of exception codes for Mac

- * OS X

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * Author: Mark Mentovai

- * Split into its own file: Neal Sidhwaney */

- 

-

-#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__

-#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__

-

-#include <stddef.h>

-

-#include "google_breakpad/common/breakpad_types.h"

-

-/* For (MDException).exception_code.  Breakpad minidump extension for Mac OS X

- * support.  Based on Darwin/Mac OS X' mach/exception_types.h.  This is

- * what Mac OS X calls an "exception", not a "code". */

-typedef enum {

-  /* Exception code.  The high 16 bits of exception_code contains one of

-   * these values. */

-  MD_EXCEPTION_MAC_BAD_ACCESS      = 1,  /* code can be a kern_return_t */

-      /* EXC_BAD_ACCESS */

-  MD_EXCEPTION_MAC_BAD_INSTRUCTION = 2,  /* code is CPU-specific */

-      /* EXC_BAD_INSTRUCTION */

-  MD_EXCEPTION_MAC_ARITHMETIC      = 3,  /* code is CPU-specific */

-      /* EXC_ARITHMETIC */

-  MD_EXCEPTION_MAC_EMULATION       = 4,  /* code is CPU-specific */

-      /* EXC_EMULATION */

-  MD_EXCEPTION_MAC_SOFTWARE        = 5,

-      /* EXC_SOFTWARE */

-  MD_EXCEPTION_MAC_BREAKPOINT      = 6,  /* code is CPU-specific */

-      /* EXC_BREAKPOINT */

-  MD_EXCEPTION_MAC_SYSCALL         = 7,

-      /* EXC_SYSCALL */

-  MD_EXCEPTION_MAC_MACH_SYSCALL    = 8,

-      /* EXC_MACH_SYSCALL */

-  MD_EXCEPTION_MAC_RPC_ALERT       = 9

-      /* EXC_RPC_ALERT */

-} MDExceptionMac;

-

-/* For (MDException).exception_flags.  Breakpad minidump extension for Mac OS X

- * support.  Based on Darwin/Mac OS X' mach/ppc/exception.h and

- * mach/i386/exception.h.  This is what Mac OS X calls a "code". */

-typedef enum {

-  /* With MD_EXCEPTION_BAD_ACCESS.  These are relevant kern_return_t values

-   * from mach/kern_return.h. */

-  MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS    =  1,

-      /* KERN_INVALID_ADDRESS */

-  MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE =  2,

-      /* KERN_PROTECTION_FAILURE */

-  MD_EXCEPTION_CODE_MAC_NO_ACCESS          =  8,

-      /* KERN_NO_ACCESS */

-  MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE     =  9,

-      /* KERN_MEMORY_FAILURE */

-  MD_EXCEPTION_CODE_MAC_MEMORY_ERROR       = 10,

-      /* KERN_MEMORY_ERROR */

-

-  /* With MD_EXCEPTION_SOFTWARE */

-  MD_EXCEPTION_CODE_MAC_BAD_SYSCALL = 0x00010000,  /* Mach SIGSYS */

-  MD_EXCEPTION_CODE_MAC_BAD_PIPE    = 0x00010001,  /* Mach SIGPIPE */

-  MD_EXCEPTION_CODE_MAC_ABORT       = 0x00010002,  /* Mach SIGABRT */

-

-  /* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */

-  MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101,

-      /* EXC_PPC_VM_PROT_READ */

-  MD_EXCEPTION_CODE_MAC_PPC_BADSPACE     = 0x0102,

-      /* EXC_PPC_BADSPACE */

-  MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED    = 0x0103,

-      /* EXC_PPC_UNALIGNED */

-

-  /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on ppc */

-  MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL           = 1,

-      /* EXC_PPC_INVALID_SYSCALL */

-  MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION = 2,

-      /* EXC_PPC_UNIPL_INST */

-  MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION    = 3,

-      /* EXC_PPC_PRIVINST */

-  MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER       = 4,

-      /* EXC_PPC_PRIVREG */

-  MD_EXCEPTION_CODE_MAC_PPC_TRACE                     = 5,

-      /* EXC_PPC_TRACE */

-  MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR       = 6,

-      /* EXC_PPC_PERFMON */

-

-  /* With MD_EXCEPTION_MAC_ARITHMETIC on ppc */

-  MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW           = 1,

-      /* EXC_PPC_OVERFLOW */

-  MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE        = 2,

-      /* EXC_PPC_ZERO_DIVIDE */

-  MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT      = 3,

-      /* EXC_FLT_INEXACT */

-  MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE  = 4,

-      /* EXC_PPC_FLT_ZERO_DIVIDE */

-  MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW    = 5,

-      /* EXC_PPC_FLT_UNDERFLOW */

-  MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW     = 6,

-      /* EXC_PPC_FLT_OVERFLOW */

-  MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER = 7,

-      /* EXC_PPC_FLT_NOT_A_NUMBER */

-

-  /* With MD_EXCEPTION_MAC_EMULATION on ppc */

-  MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION   = 8,

-      /* EXC_PPC_NOEMULATION */

-  MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST = 9,

-      /* EXC_PPC_ALTIVECASSIST */

-

-  /* With MD_EXCEPTION_MAC_SOFTWARE on ppc */

-  MD_EXCEPTION_CODE_MAC_PPC_TRAP    = 0x00000001,  /* EXC_PPC_TRAP */

-  MD_EXCEPTION_CODE_MAC_PPC_MIGRATE = 0x00010100,  /* EXC_PPC_MIGRATE */

-

-  /* With MD_EXCEPTION_MAC_BREAKPOINT on ppc */

-  MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT = 1,  /* EXC_PPC_BREAKPOINT */

-

-  /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86, see also x86 interrupt

-   * values below. */

-  MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION = 1,  /* EXC_I386_INVOP */

-

-  /* With MD_EXCEPTION_MAC_ARITHMETIC on x86 */

-  MD_EXCEPTION_CODE_MAC_X86_DIV       = 1,  /* EXC_I386_DIV */

-  MD_EXCEPTION_CODE_MAC_X86_INTO      = 2,  /* EXC_I386_INTO */

-  MD_EXCEPTION_CODE_MAC_X86_NOEXT     = 3,  /* EXC_I386_NOEXT */

-  MD_EXCEPTION_CODE_MAC_X86_EXTOVR    = 4,  /* EXC_I386_EXTOVR */

-  MD_EXCEPTION_CODE_MAC_X86_EXTERR    = 5,  /* EXC_I386_EXTERR */

-  MD_EXCEPTION_CODE_MAC_X86_EMERR     = 6,  /* EXC_I386_EMERR */

-  MD_EXCEPTION_CODE_MAC_X86_BOUND     = 7,  /* EXC_I386_BOUND */

-  MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR = 8,  /* EXC_I386_SSEEXTERR */

-

-  /* With MD_EXCEPTION_MAC_BREAKPOINT on x86 */

-  MD_EXCEPTION_CODE_MAC_X86_SGL = 1,  /* EXC_I386_SGL */

-  MD_EXCEPTION_CODE_MAC_X86_BPT = 2,  /* EXC_I386_BPT */

-

-  /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86.  These are the raw

-   * x86 interrupt codes.  Most of these are mapped to other Mach

-   * exceptions and codes, are handled, or should not occur in user space.

-   * A few of these will do occur with MD_EXCEPTION_MAC_BAD_INSTRUCTION. */

-  /* EXC_I386_DIVERR    =  0: mapped to EXC_ARITHMETIC/EXC_I386_DIV */

-  /* EXC_I386_SGLSTP    =  1: mapped to EXC_BREAKPOINT/EXC_I386_SGL */

-  /* EXC_I386_NMIFLT    =  2: should not occur in user space */

-  /* EXC_I386_BPTFLT    =  3: mapped to EXC_BREAKPOINT/EXC_I386_BPT */

-  /* EXC_I386_INTOFLT   =  4: mapped to EXC_ARITHMETIC/EXC_I386_INTO */

-  /* EXC_I386_BOUNDFLT  =  5: mapped to EXC_ARITHMETIC/EXC_I386_BOUND */

-  /* EXC_I386_INVOPFLT  =  6: mapped to EXC_BAD_INSTRUCTION/EXC_I386_INVOP */

-  /* EXC_I386_NOEXTFLT  =  7: should be handled by the kernel */

-  /* EXC_I386_DBLFLT    =  8: should be handled (if possible) by the kernel */

-  /* EXC_I386_EXTOVRFLT =  9: mapped to EXC_BAD_ACCESS/(PROT_READ|PROT_EXEC) */

-  MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT = 10,

-      /* EXC_INVTSSFLT */

-  MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT        = 11,

-      /* EXC_SEGNPFLT */

-  MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT                = 12,

-      /* EXC_STKFLT */

-  MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT   = 13,

-      /* EXC_GPFLT */

-  /* EXC_I386_PGFLT     = 14: should not occur in user space */

-  /* EXC_I386_EXTERRFLT = 16: mapped to EXC_ARITHMETIC/EXC_I386_EXTERR */

-  MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT            = 17

-      /* EXC_ALIGNFLT (for vector operations) */

-  /* EXC_I386_ENOEXTFLT = 32: should be handled by the kernel */

-  /* EXC_I386_ENDPERR   = 33: should not occur */

-} MDExceptionCodeMac;

-

-#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */

+/* Copyright (c) 2006, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_exception_mac.h: A definition of exception codes for Mac
+ * OS X
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * Author: Mark Mentovai
+ * Split into its own file: Neal Sidhwaney */
+ 
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__
+
+#include <stddef.h>
+
+#include "google_breakpad/common/breakpad_types.h"
+
+/* For (MDException).exception_code.  Breakpad minidump extension for Mac OS X
+ * support.  Based on Darwin/Mac OS X' mach/exception_types.h.  This is
+ * what Mac OS X calls an "exception", not a "code". */
+typedef enum {
+  /* Exception code.  The high 16 bits of exception_code contains one of
+   * these values. */
+  MD_EXCEPTION_MAC_BAD_ACCESS      = 1,  /* code can be a kern_return_t */
+      /* EXC_BAD_ACCESS */
+  MD_EXCEPTION_MAC_BAD_INSTRUCTION = 2,  /* code is CPU-specific */
+      /* EXC_BAD_INSTRUCTION */
+  MD_EXCEPTION_MAC_ARITHMETIC      = 3,  /* code is CPU-specific */
+      /* EXC_ARITHMETIC */
+  MD_EXCEPTION_MAC_EMULATION       = 4,  /* code is CPU-specific */
+      /* EXC_EMULATION */
+  MD_EXCEPTION_MAC_SOFTWARE        = 5,
+      /* EXC_SOFTWARE */
+  MD_EXCEPTION_MAC_BREAKPOINT      = 6,  /* code is CPU-specific */
+      /* EXC_BREAKPOINT */
+  MD_EXCEPTION_MAC_SYSCALL         = 7,
+      /* EXC_SYSCALL */
+  MD_EXCEPTION_MAC_MACH_SYSCALL    = 8,
+      /* EXC_MACH_SYSCALL */
+  MD_EXCEPTION_MAC_RPC_ALERT       = 9
+      /* EXC_RPC_ALERT */
+} MDExceptionMac;
+
+/* For (MDException).exception_flags.  Breakpad minidump extension for Mac OS X
+ * support.  Based on Darwin/Mac OS X' mach/ppc/exception.h and
+ * mach/i386/exception.h.  This is what Mac OS X calls a "code". */
+typedef enum {
+  /* With MD_EXCEPTION_BAD_ACCESS.  These are relevant kern_return_t values
+   * from mach/kern_return.h. */
+  MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS    =  1,
+      /* KERN_INVALID_ADDRESS */
+  MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE =  2,
+      /* KERN_PROTECTION_FAILURE */
+  MD_EXCEPTION_CODE_MAC_NO_ACCESS          =  8,
+      /* KERN_NO_ACCESS */
+  MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE     =  9,
+      /* KERN_MEMORY_FAILURE */
+  MD_EXCEPTION_CODE_MAC_MEMORY_ERROR       = 10,
+      /* KERN_MEMORY_ERROR */
+
+  /* With MD_EXCEPTION_SOFTWARE */
+  MD_EXCEPTION_CODE_MAC_BAD_SYSCALL = 0x00010000,  /* Mach SIGSYS */
+  MD_EXCEPTION_CODE_MAC_BAD_PIPE    = 0x00010001,  /* Mach SIGPIPE */
+  MD_EXCEPTION_CODE_MAC_ABORT       = 0x00010002,  /* Mach SIGABRT */
+
+  /* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */
+  MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101,
+      /* EXC_PPC_VM_PROT_READ */
+  MD_EXCEPTION_CODE_MAC_PPC_BADSPACE     = 0x0102,
+      /* EXC_PPC_BADSPACE */
+  MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED    = 0x0103,
+      /* EXC_PPC_UNALIGNED */
+
+  /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on ppc */
+  MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL           = 1,
+      /* EXC_PPC_INVALID_SYSCALL */
+  MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION = 2,
+      /* EXC_PPC_UNIPL_INST */
+  MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION    = 3,
+      /* EXC_PPC_PRIVINST */
+  MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER       = 4,
+      /* EXC_PPC_PRIVREG */
+  MD_EXCEPTION_CODE_MAC_PPC_TRACE                     = 5,
+      /* EXC_PPC_TRACE */
+  MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR       = 6,
+      /* EXC_PPC_PERFMON */
+
+  /* With MD_EXCEPTION_MAC_ARITHMETIC on ppc */
+  MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW           = 1,
+      /* EXC_PPC_OVERFLOW */
+  MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE        = 2,
+      /* EXC_PPC_ZERO_DIVIDE */
+  MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT      = 3,
+      /* EXC_FLT_INEXACT */
+  MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE  = 4,
+      /* EXC_PPC_FLT_ZERO_DIVIDE */
+  MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW    = 5,
+      /* EXC_PPC_FLT_UNDERFLOW */
+  MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW     = 6,
+      /* EXC_PPC_FLT_OVERFLOW */
+  MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER = 7,
+      /* EXC_PPC_FLT_NOT_A_NUMBER */
+
+  /* With MD_EXCEPTION_MAC_EMULATION on ppc */
+  MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION   = 8,
+      /* EXC_PPC_NOEMULATION */
+  MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST = 9,
+      /* EXC_PPC_ALTIVECASSIST */
+
+  /* With MD_EXCEPTION_MAC_SOFTWARE on ppc */
+  MD_EXCEPTION_CODE_MAC_PPC_TRAP    = 0x00000001,  /* EXC_PPC_TRAP */
+  MD_EXCEPTION_CODE_MAC_PPC_MIGRATE = 0x00010100,  /* EXC_PPC_MIGRATE */
+
+  /* With MD_EXCEPTION_MAC_BREAKPOINT on ppc */
+  MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT = 1,  /* EXC_PPC_BREAKPOINT */
+
+  /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86, see also x86 interrupt
+   * values below. */
+  MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION = 1,  /* EXC_I386_INVOP */
+
+  /* With MD_EXCEPTION_MAC_ARITHMETIC on x86 */
+  MD_EXCEPTION_CODE_MAC_X86_DIV       = 1,  /* EXC_I386_DIV */
+  MD_EXCEPTION_CODE_MAC_X86_INTO      = 2,  /* EXC_I386_INTO */
+  MD_EXCEPTION_CODE_MAC_X86_NOEXT     = 3,  /* EXC_I386_NOEXT */
+  MD_EXCEPTION_CODE_MAC_X86_EXTOVR    = 4,  /* EXC_I386_EXTOVR */
+  MD_EXCEPTION_CODE_MAC_X86_EXTERR    = 5,  /* EXC_I386_EXTERR */
+  MD_EXCEPTION_CODE_MAC_X86_EMERR     = 6,  /* EXC_I386_EMERR */
+  MD_EXCEPTION_CODE_MAC_X86_BOUND     = 7,  /* EXC_I386_BOUND */
+  MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR = 8,  /* EXC_I386_SSEEXTERR */
+
+  /* With MD_EXCEPTION_MAC_BREAKPOINT on x86 */
+  MD_EXCEPTION_CODE_MAC_X86_SGL = 1,  /* EXC_I386_SGL */
+  MD_EXCEPTION_CODE_MAC_X86_BPT = 2,  /* EXC_I386_BPT */
+
+  /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86.  These are the raw
+   * x86 interrupt codes.  Most of these are mapped to other Mach
+   * exceptions and codes, are handled, or should not occur in user space.
+   * A few of these will do occur with MD_EXCEPTION_MAC_BAD_INSTRUCTION. */
+  /* EXC_I386_DIVERR    =  0: mapped to EXC_ARITHMETIC/EXC_I386_DIV */
+  /* EXC_I386_SGLSTP    =  1: mapped to EXC_BREAKPOINT/EXC_I386_SGL */
+  /* EXC_I386_NMIFLT    =  2: should not occur in user space */
+  /* EXC_I386_BPTFLT    =  3: mapped to EXC_BREAKPOINT/EXC_I386_BPT */
+  /* EXC_I386_INTOFLT   =  4: mapped to EXC_ARITHMETIC/EXC_I386_INTO */
+  /* EXC_I386_BOUNDFLT  =  5: mapped to EXC_ARITHMETIC/EXC_I386_BOUND */
+  /* EXC_I386_INVOPFLT  =  6: mapped to EXC_BAD_INSTRUCTION/EXC_I386_INVOP */
+  /* EXC_I386_NOEXTFLT  =  7: should be handled by the kernel */
+  /* EXC_I386_DBLFLT    =  8: should be handled (if possible) by the kernel */
+  /* EXC_I386_EXTOVRFLT =  9: mapped to EXC_BAD_ACCESS/(PROT_READ|PROT_EXEC) */
+  MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT = 10,
+      /* EXC_INVTSSFLT */
+  MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT        = 11,
+      /* EXC_SEGNPFLT */
+  MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT                = 12,
+      /* EXC_STKFLT */
+  MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT   = 13,
+      /* EXC_GPFLT */
+  /* EXC_I386_PGFLT     = 14: should not occur in user space */
+  /* EXC_I386_EXTERRFLT = 16: mapped to EXC_ARITHMETIC/EXC_I386_EXTERR */
+  MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT            = 17
+      /* EXC_ALIGNFLT (for vector operations) */
+  /* EXC_I386_ENOEXTFLT = 32: should be handled by the kernel */
+  /* EXC_I386_ENDPERR   = 33: should not occur */
+} MDExceptionCodeMac;
+
+#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */
diff --git a/third_party/breakpad/src/google_breakpad/common/minidump_exception_solaris.h b/third_party/breakpad/src/google_breakpad/common/minidump_exception_solaris.h
index 6397ab0..d48632a 100644
--- a/third_party/breakpad/src/google_breakpad/common/minidump_exception_solaris.h
+++ b/third_party/breakpad/src/google_breakpad/common/minidump_exception_solaris.h
@@ -1,94 +1,94 @@
-/* Copyright (c) 2006, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* minidump_exception_solaris.h: A definition of exception codes for

- * Solaris

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * Author: Mark Mentovai

- * Split into its own file: Neal Sidhwaney */

- 

-

-#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__

-#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__

-

-#include <stddef.h>

-

-#include "google_breakpad/common/breakpad_types.h"

-

-/* For (MDException).exception_code.  These values come from sys/iso/signal_iso.h

- */

-typedef enum {

-  MD_EXCEPTION_CODE_SOL_SIGHUP = 1,      /* Hangup */

-  MD_EXCEPTION_CODE_SOL_SIGINT = 2,      /* interrupt (rubout) */

-  MD_EXCEPTION_CODE_SOL_SIGQUIT = 3,     /* quit (ASCII FS) */

-  MD_EXCEPTION_CODE_SOL_SIGILL = 4,      /* illegal instruction (not reset when caught) */

-  MD_EXCEPTION_CODE_SOL_SIGTRAP = 5,     /* trace trap (not reset when caught) */

-  MD_EXCEPTION_CODE_SOL_SIGIOT = 6,      /* IOT instruction */

-  MD_EXCEPTION_CODE_SOL_SIGABRT = 6,     /* used by abort, replace SIGIOT in the future */

-  MD_EXCEPTION_CODE_SOL_SIGEMT = 7,      /* EMT instruction */

-  MD_EXCEPTION_CODE_SOL_SIGFPE = 8,      /* floating point exception */

-  MD_EXCEPTION_CODE_SOL_SIGKILL = 9,     /* kill (cannot be caught or ignored) */

-  MD_EXCEPTION_CODE_SOL_SIGBUS = 10,     /* bus error */

-  MD_EXCEPTION_CODE_SOL_SIGSEGV = 11,    /* segmentation violation */

-  MD_EXCEPTION_CODE_SOL_SIGSYS = 12,     /* bad argument to system call */

-  MD_EXCEPTION_CODE_SOL_SIGPIPE = 13,    /* write on a pipe with no one to read it */

-  MD_EXCEPTION_CODE_SOL_SIGALRM = 14,    /* alarm clock */

-  MD_EXCEPTION_CODE_SOL_SIGTERM = 15,    /* software termination signal from kill */

-  MD_EXCEPTION_CODE_SOL_SIGUSR1 = 16,    /* user defined signal 1 */

-  MD_EXCEPTION_CODE_SOL_SIGUSR2 = 17,    /* user defined signal 2 */

-  MD_EXCEPTION_CODE_SOL_SIGCLD = 18,     /* child status change */

-  MD_EXCEPTION_CODE_SOL_SIGCHLD = 18,    /* child status change alias (POSIX) */

-  MD_EXCEPTION_CODE_SOL_SIGPWR = 19,     /* power-fail restart */

-  MD_EXCEPTION_CODE_SOL_SIGWINCH = 20,   /* window size change */

-  MD_EXCEPTION_CODE_SOL_SIGURG = 21,     /* urgent socket condition */

-  MD_EXCEPTION_CODE_SOL_SIGPOLL = 22,    /* pollable event occured */

-  MD_EXCEPTION_CODE_SOL_SIGIO = 22,      /* socket I/O possible (SIGPOLL alias) */

-  MD_EXCEPTION_CODE_SOL_SIGSTOP = 23,    /* stop (cannot be caught or ignored) */

-  MD_EXCEPTION_CODE_SOL_SIGTSTP = 24,    /* user stop requested from tty */

-  MD_EXCEPTION_CODE_SOL_SIGCONT = 25,    /* stopped process has been continued */

-  MD_EXCEPTION_CODE_SOL_SIGTTIN = 26,    /* background tty read attempted */

-  MD_EXCEPTION_CODE_SOL_SIGTTOU = 27,    /* background tty write attempted */

-  MD_EXCEPTION_CODE_SOL_SIGVTALRM = 28,  /* virtual timer expired */

-  MD_EXCEPTION_CODE_SOL_SIGPROF = 29,    /* profiling timer expired */

-  MD_EXCEPTION_CODE_SOL_SIGXCPU = 30,    /* exceeded cpu limit */

-  MD_EXCEPTION_CODE_SOL_SIGXFSZ = 31,    /* exceeded file size limit */

-  MD_EXCEPTION_CODE_SOL_SIGWAITING = 32, /* reserved signal no longer used by threading code */

-  MD_EXCEPTION_CODE_SOL_SIGLWP = 33,     /* reserved signal no longer used by threading code */

-  MD_EXCEPTION_CODE_SOL_SIGFREEZE = 34,  /* special signal used by CPR */

-  MD_EXCEPTION_CODE_SOL_SIGTHAW = 35,    /* special signal used by CPR */

-  MD_EXCEPTION_CODE_SOL_SIGCANCEL = 36,  /* reserved signal for thread cancellation */

-  MD_EXCEPTION_CODE_SOL_SIGLOST = 37,    /* resource lost (eg, record-lock lost) */

-  MD_EXCEPTION_CODE_SOL_SIGXRES = 38,    /* resource control exceeded */

-  MD_EXCEPTION_CODE_SOL_SIGJVM1 = 39,    /* reserved signal for Java Virtual Machine */

-  MD_EXCEPTION_CODE_SOL_SIGJVM2 = 40     /* reserved signal for Java Virtual Machine */

-} MDExceptionCodeSolaris;

-

-#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ */

+/* Copyright (c) 2006, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_exception_solaris.h: A definition of exception codes for
+ * Solaris
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * Author: Mark Mentovai
+ * Split into its own file: Neal Sidhwaney */
+ 
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__
+
+#include <stddef.h>
+
+#include "google_breakpad/common/breakpad_types.h"
+
+/* For (MDException).exception_code.  These values come from sys/iso/signal_iso.h
+ */
+typedef enum {
+  MD_EXCEPTION_CODE_SOL_SIGHUP = 1,      /* Hangup */
+  MD_EXCEPTION_CODE_SOL_SIGINT = 2,      /* interrupt (rubout) */
+  MD_EXCEPTION_CODE_SOL_SIGQUIT = 3,     /* quit (ASCII FS) */
+  MD_EXCEPTION_CODE_SOL_SIGILL = 4,      /* illegal instruction (not reset when caught) */
+  MD_EXCEPTION_CODE_SOL_SIGTRAP = 5,     /* trace trap (not reset when caught) */
+  MD_EXCEPTION_CODE_SOL_SIGIOT = 6,      /* IOT instruction */
+  MD_EXCEPTION_CODE_SOL_SIGABRT = 6,     /* used by abort, replace SIGIOT in the future */
+  MD_EXCEPTION_CODE_SOL_SIGEMT = 7,      /* EMT instruction */
+  MD_EXCEPTION_CODE_SOL_SIGFPE = 8,      /* floating point exception */
+  MD_EXCEPTION_CODE_SOL_SIGKILL = 9,     /* kill (cannot be caught or ignored) */
+  MD_EXCEPTION_CODE_SOL_SIGBUS = 10,     /* bus error */
+  MD_EXCEPTION_CODE_SOL_SIGSEGV = 11,    /* segmentation violation */
+  MD_EXCEPTION_CODE_SOL_SIGSYS = 12,     /* bad argument to system call */
+  MD_EXCEPTION_CODE_SOL_SIGPIPE = 13,    /* write on a pipe with no one to read it */
+  MD_EXCEPTION_CODE_SOL_SIGALRM = 14,    /* alarm clock */
+  MD_EXCEPTION_CODE_SOL_SIGTERM = 15,    /* software termination signal from kill */
+  MD_EXCEPTION_CODE_SOL_SIGUSR1 = 16,    /* user defined signal 1 */
+  MD_EXCEPTION_CODE_SOL_SIGUSR2 = 17,    /* user defined signal 2 */
+  MD_EXCEPTION_CODE_SOL_SIGCLD = 18,     /* child status change */
+  MD_EXCEPTION_CODE_SOL_SIGCHLD = 18,    /* child status change alias (POSIX) */
+  MD_EXCEPTION_CODE_SOL_SIGPWR = 19,     /* power-fail restart */
+  MD_EXCEPTION_CODE_SOL_SIGWINCH = 20,   /* window size change */
+  MD_EXCEPTION_CODE_SOL_SIGURG = 21,     /* urgent socket condition */
+  MD_EXCEPTION_CODE_SOL_SIGPOLL = 22,    /* pollable event occured */
+  MD_EXCEPTION_CODE_SOL_SIGIO = 22,      /* socket I/O possible (SIGPOLL alias) */
+  MD_EXCEPTION_CODE_SOL_SIGSTOP = 23,    /* stop (cannot be caught or ignored) */
+  MD_EXCEPTION_CODE_SOL_SIGTSTP = 24,    /* user stop requested from tty */
+  MD_EXCEPTION_CODE_SOL_SIGCONT = 25,    /* stopped process has been continued */
+  MD_EXCEPTION_CODE_SOL_SIGTTIN = 26,    /* background tty read attempted */
+  MD_EXCEPTION_CODE_SOL_SIGTTOU = 27,    /* background tty write attempted */
+  MD_EXCEPTION_CODE_SOL_SIGVTALRM = 28,  /* virtual timer expired */
+  MD_EXCEPTION_CODE_SOL_SIGPROF = 29,    /* profiling timer expired */
+  MD_EXCEPTION_CODE_SOL_SIGXCPU = 30,    /* exceeded cpu limit */
+  MD_EXCEPTION_CODE_SOL_SIGXFSZ = 31,    /* exceeded file size limit */
+  MD_EXCEPTION_CODE_SOL_SIGWAITING = 32, /* reserved signal no longer used by threading code */
+  MD_EXCEPTION_CODE_SOL_SIGLWP = 33,     /* reserved signal no longer used by threading code */
+  MD_EXCEPTION_CODE_SOL_SIGFREEZE = 34,  /* special signal used by CPR */
+  MD_EXCEPTION_CODE_SOL_SIGTHAW = 35,    /* special signal used by CPR */
+  MD_EXCEPTION_CODE_SOL_SIGCANCEL = 36,  /* reserved signal for thread cancellation */
+  MD_EXCEPTION_CODE_SOL_SIGLOST = 37,    /* resource lost (eg, record-lock lost) */
+  MD_EXCEPTION_CODE_SOL_SIGXRES = 38,    /* resource control exceeded */
+  MD_EXCEPTION_CODE_SOL_SIGJVM1 = 39,    /* reserved signal for Java Virtual Machine */
+  MD_EXCEPTION_CODE_SOL_SIGJVM2 = 40     /* reserved signal for Java Virtual Machine */
+} MDExceptionCodeSolaris;
+
+#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ */
diff --git a/third_party/breakpad/src/google_breakpad/common/minidump_exception_win32.h b/third_party/breakpad/src/google_breakpad/common/minidump_exception_win32.h
index a53280b..7fd4bc4 100644
--- a/third_party/breakpad/src/google_breakpad/common/minidump_exception_win32.h
+++ b/third_party/breakpad/src/google_breakpad/common/minidump_exception_win32.h
@@ -1,102 +1,102 @@
-/* Copyright (c) 2006, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* minidump_exception_win32.h: Definitions of exception codes for

- * Win32 platform

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * Author: Mark Mentovai

- * Split into its own file: Neal Sidhwaney */

- 

-

-#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__

-#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__

-

-#include <stddef.h>

-

-#include "google_breakpad/common/breakpad_types.h"

-

-

-/* For (MDException).exception_code.  These values come from WinBase.h

- * and WinNT.h (names beginning with EXCEPTION_ are in WinBase.h,

- * they are STATUS_ in WinNT.h). */

-typedef enum {

-  MD_EXCEPTION_CODE_WIN_CONTROL_C                = 0x40010005,

-      /* DBG_CONTROL_C */

-  MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION     = 0x80000001,

-      /* EXCEPTION_GUARD_PAGE */

-  MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT    = 0x80000002,

-      /* EXCEPTION_DATATYPE_MISALIGNMENT */

-  MD_EXCEPTION_CODE_WIN_BREAKPOINT               = 0x80000003,

-      /* EXCEPTION_BREAKPOINT */

-  MD_EXCEPTION_CODE_WIN_SINGLE_STEP              = 0x80000004,

-      /* EXCEPTION_SINGLE_STEP */

-  MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION         = 0xc0000005,

-      /* EXCEPTION_ACCESS_VIOLATION */

-  MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR            = 0xc0000006,

-      /* EXCEPTION_IN_PAGE_ERROR */

-  MD_EXCEPTION_CODE_WIN_INVALID_HANDLE           = 0xc0000008,

-      /* EXCEPTION_INVALID_HANDLE */

-  MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION      = 0xc000001d,

-      /* EXCEPTION_ILLEGAL_INSTRUCTION */

-  MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION = 0xc0000025,

-      /* EXCEPTION_NONCONTINUABLE_EXCEPTION */

-  MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION      = 0xc0000026,

-      /* EXCEPTION_INVALID_DISPOSITION */

-  MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED    = 0xc000008c,

-      /* EXCEPTION_BOUNDS_EXCEEDED */

-  MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND   = 0xc000008d,

-      /* EXCEPTION_FLT_DENORMAL_OPERAND */

-  MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO     = 0xc000008e,

-      /* EXCEPTION_FLT_DIVIDE_BY_ZERO */

-  MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT     = 0xc000008f,

-      /* EXCEPTION_FLT_INEXACT_RESULT */

-  MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION  = 0xc0000090,

-      /* EXCEPTION_FLT_INVALID_OPERATION */

-  MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW           = 0xc0000091,

-      /* EXCEPTION_FLT_OVERFLOW */

-  MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK        = 0xc0000092,

-      /* EXCEPTION_FLT_STACK_CHECK */

-  MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW          = 0xc0000093,

-      /* EXCEPTION_FLT_UNDERFLOW */

-  MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO   = 0xc0000094,

-      /* EXCEPTION_INT_DIVIDE_BY_ZERO */

-  MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW         = 0xc0000095,

-      /* EXCEPTION_INT_OVERFLOW */

-  MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION   = 0xc0000096,

-      /* EXCEPTION_PRIV_INSTRUCTION */

-  MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW           = 0xc00000fd,

-      /* EXCEPTION_STACK_OVERFLOW */

-  MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK        = 0xc0000194

-      /* EXCEPTION_POSSIBLE_DEADLOCK */

-} MDExceptionCodeWin;

-

-

-#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */

+/* Copyright (c) 2006, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_exception_win32.h: Definitions of exception codes for
+ * Win32 platform
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * Author: Mark Mentovai
+ * Split into its own file: Neal Sidhwaney */
+ 
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__
+
+#include <stddef.h>
+
+#include "google_breakpad/common/breakpad_types.h"
+
+
+/* For (MDException).exception_code.  These values come from WinBase.h
+ * and WinNT.h (names beginning with EXCEPTION_ are in WinBase.h,
+ * they are STATUS_ in WinNT.h). */
+typedef enum {
+  MD_EXCEPTION_CODE_WIN_CONTROL_C                = 0x40010005,
+      /* DBG_CONTROL_C */
+  MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION     = 0x80000001,
+      /* EXCEPTION_GUARD_PAGE */
+  MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT    = 0x80000002,
+      /* EXCEPTION_DATATYPE_MISALIGNMENT */
+  MD_EXCEPTION_CODE_WIN_BREAKPOINT               = 0x80000003,
+      /* EXCEPTION_BREAKPOINT */
+  MD_EXCEPTION_CODE_WIN_SINGLE_STEP              = 0x80000004,
+      /* EXCEPTION_SINGLE_STEP */
+  MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION         = 0xc0000005,
+      /* EXCEPTION_ACCESS_VIOLATION */
+  MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR            = 0xc0000006,
+      /* EXCEPTION_IN_PAGE_ERROR */
+  MD_EXCEPTION_CODE_WIN_INVALID_HANDLE           = 0xc0000008,
+      /* EXCEPTION_INVALID_HANDLE */
+  MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION      = 0xc000001d,
+      /* EXCEPTION_ILLEGAL_INSTRUCTION */
+  MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION = 0xc0000025,
+      /* EXCEPTION_NONCONTINUABLE_EXCEPTION */
+  MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION      = 0xc0000026,
+      /* EXCEPTION_INVALID_DISPOSITION */
+  MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED    = 0xc000008c,
+      /* EXCEPTION_BOUNDS_EXCEEDED */
+  MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND   = 0xc000008d,
+      /* EXCEPTION_FLT_DENORMAL_OPERAND */
+  MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO     = 0xc000008e,
+      /* EXCEPTION_FLT_DIVIDE_BY_ZERO */
+  MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT     = 0xc000008f,
+      /* EXCEPTION_FLT_INEXACT_RESULT */
+  MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION  = 0xc0000090,
+      /* EXCEPTION_FLT_INVALID_OPERATION */
+  MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW           = 0xc0000091,
+      /* EXCEPTION_FLT_OVERFLOW */
+  MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK        = 0xc0000092,
+      /* EXCEPTION_FLT_STACK_CHECK */
+  MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW          = 0xc0000093,
+      /* EXCEPTION_FLT_UNDERFLOW */
+  MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO   = 0xc0000094,
+      /* EXCEPTION_INT_DIVIDE_BY_ZERO */
+  MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW         = 0xc0000095,
+      /* EXCEPTION_INT_OVERFLOW */
+  MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION   = 0xc0000096,
+      /* EXCEPTION_PRIV_INSTRUCTION */
+  MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW           = 0xc00000fd,
+      /* EXCEPTION_STACK_OVERFLOW */
+  MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK        = 0xc0000194
+      /* EXCEPTION_POSSIBLE_DEADLOCK */
+} MDExceptionCodeWin;
+
+
+#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */
diff --git a/third_party/breakpad/src/google_breakpad/common/minidump_format.h b/third_party/breakpad/src/google_breakpad/common/minidump_format.h
index b4659ee..4d9e767 100644
--- a/third_party/breakpad/src/google_breakpad/common/minidump_format.h
+++ b/third_party/breakpad/src/google_breakpad/common/minidump_format.h
@@ -1,721 +1,721 @@
-/* Copyright (c) 2006, Google Inc.

- * All rights reserved.

- *

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- *

- *     * Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- *     * Redistributions in binary form must reproduce the above

- * copyright notice, this list of conditions and the following disclaimer

- * in the documentation and/or other materials provided with the

- * distribution.

- *     * Neither the name of Google Inc. nor the names of its

- * contributors may be used to endorse or promote products derived from

- * this software without specific prior written permission.

- *

- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

-

-/* minidump_format.h: A cross-platform reimplementation of minidump-related

- * portions of DbgHelp.h from the Windows Platform SDK.

- *

- * (This is C99 source, please don't corrupt it with C++.)

- *

- * Structures that are defined by Microsoft to contain a zero-length array

- * are instead defined here to contain an array with one element, as

- * zero-length arrays are forbidden by standard C and C++.  In these cases,

- * *_minsize constants are provided to be used in place of sizeof.  For a

- * cleaner interface to these sizes when using C++, see minidump_size.h.

- *

- * These structures are also sufficient to populate minidump files.

- *

- * These definitions may be extended to support handling minidump files

- * for other CPUs and other operating systems.

- *

- * Because precise data type sizes are crucial for this implementation to

- * function properly and portably in terms of interoperability with minidumps

- * produced by DbgHelp on Windows, a set of primitive types with known sizes

- * are used as the basis of each structure defined by this file.  DbgHelp

- * on Windows is assumed to be the reference implementation; this file

- * seeks to provide a cross-platform compatible implementation.  To avoid

- * collisions with the types and values defined and used by DbgHelp in the

- * event that this implementation is used on Windows, each type and value

- * defined here is given a new name, beginning with "MD".  Names of the

- * equivalent types and values in the Windows Platform SDK are given in

- * comments.

- *

- * Author: Mark Mentovai */

-

-

-#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__

-#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__

-

-#include <stddef.h>

-

-#include "google_breakpad/common/breakpad_types.h"

-

-

-#if defined(_MSC_VER)

-/* Disable "zero-sized array in struct/union" warnings when compiling in

- * MSVC.  DbgHelp.h does this too. */

-#pragma warning(push)

-#pragma warning(disable:4200)

-#endif  /* _MSC_VER */

-

-

-/*

- * guiddef.h

- */

-

-typedef struct {

-  u_int32_t data1;

-  u_int16_t data2;

-  u_int16_t data3;

-  u_int8_t  data4[8];

-} MDGUID;  /* GUID */

-

-

-/*

- * WinNT.h

- */

-

-/* Non-x86 CPU identifiers found in the high 26 bits of

- * (MDRawContext*).context_flags.  These aren't used by Breakpad, but are

- * defined here for reference, to avoid assigning values that conflict

- * (although some values already conflict). */

-#define MD_CONTEXT_IA64  0x00080000  /* CONTEXT_IA64 */

-#define MD_CONTEXT_AMD64 0x00100000  /* CONTEXT_AMD64 */

-/* Additional values from winnt.h in the Windows CE 5.0 SDK: */

-#define MD_CONTEXT_SHX   0x000000c0  /* CONTEXT_SH4 (Super-H, includes SH3) */

-#define MD_CONTEXT_ARM   0x00000040  /* CONTEXT_ARM (0x40 bit set in SHx?) */

-#define MD_CONTEXT_MIPS  0x00010000  /* CONTEXT_R4000 (same value as x86?) */

-#define MD_CONTEXT_ALPHA 0x00020000  /* CONTEXT_ALPHA */

-

-#define MD_CONTEXT_CPU_MASK 0xffffffc0

-

-

-/* This is a base type for MDRawContextX86 and MDRawContextPPC.  This

- * structure should never be allocated directly.  The actual structure type

- * can be determined by examining the context_flags field. */

-typedef struct {

-  u_int32_t context_flags;

-} MDRawContextBase;

-

-#include "minidump_cpu_sparc.h"

-#include "minidump_cpu_x86.h"

-#include "minidump_cpu_ppc.h"

-#include "minidump_cpu_ppc64.h"

-#include "minidump_cpu_amd64.h"

-

-

-/*

- * WinVer.h

- */

-

-

-typedef struct {

-  u_int32_t signature;

-  u_int32_t struct_version;

-  u_int32_t file_version_hi;

-  u_int32_t file_version_lo;

-  u_int32_t product_version_hi;

-  u_int32_t product_version_lo;

-  u_int32_t file_flags_mask;    /* Identifies valid bits in fileFlags */

-  u_int32_t file_flags;

-  u_int32_t file_os;

-  u_int32_t file_type;

-  u_int32_t file_subtype;

-  u_int32_t file_date_hi;

-  u_int32_t file_date_lo;

-} MDVSFixedFileInfo;  /* VS_FIXEDFILEINFO */

-

-/* For (MDVSFixedFileInfo).signature */

-#define MD_VSFIXEDFILEINFO_SIGNATURE 0xfeef04bd

-     /* VS_FFI_SIGNATURE */

-

-/* For (MDVSFixedFileInfo).version */

-#define MD_VSFIXEDFILEINFO_VERSION 0x00010000

-     /* VS_FFI_STRUCVERSION */

-

-/* For (MDVSFixedFileInfo).file_flags_mask and

- * (MDVSFixedFileInfo).file_flags */

-#define MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG        0x00000001

-     /* VS_FF_DEBUG */

-#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRERELEASE   0x00000002

-     /* VS_FF_PRERELEASE */

-#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PATCHED      0x00000004

-     /* VS_FF_PATCHED */

-#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRIVATEBUILD 0x00000008

-     /* VS_FF_PRIVATEBUILD */

-#define MD_VSFIXEDFILEINFO_FILE_FLAGS_INFOINFERRED 0x00000010

-     /* VS_FF_INFOINFERRED */

-#define MD_VSFIXEDFILEINFO_FILE_FLAGS_SPECIALBUILD 0x00000020

-     /* VS_FF_SPECIALBUILD */

-

-/* For (MDVSFixedFileInfo).file_os: high 16 bits */

-#define MD_VSFIXEDFILEINFO_FILE_OS_UNKNOWN    0          /* VOS_UNKNOWN */

-#define MD_VSFIXEDFILEINFO_FILE_OS_DOS        (1 << 16)  /* VOS_DOS */

-#define MD_VSFIXEDFILEINFO_FILE_OS_OS216      (2 << 16)  /* VOS_OS216 */

-#define MD_VSFIXEDFILEINFO_FILE_OS_OS232      (3 << 16)  /* VOS_OS232 */

-#define MD_VSFIXEDFILEINFO_FILE_OS_NT         (4 << 16)  /* VOS_NT */

-#define MD_VSFIXEDFILEINFO_FILE_OS_WINCE      (5 << 16)  /* VOS_WINCE */

-/* Low 16 bits */

-#define MD_VSFIXEDFILEINFO_FILE_OS__BASE      0          /* VOS__BASE */

-#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS16 1          /* VOS__WINDOWS16 */

-#define MD_VSFIXEDFILEINFO_FILE_OS__PM16      2          /* VOS__PM16 */

-#define MD_VSFIXEDFILEINFO_FILE_OS__PM32      3          /* VOS__PM32 */

-#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32 4          /* VOS__WINDOWS32 */

-

-/* For (MDVSFixedFileInfo).file_type */

-#define MD_VSFIXEDFILEINFO_FILE_TYPE_UNKNOWN    0  /* VFT_UNKNOWN */

-#define MD_VSFIXEDFILEINFO_FILE_TYPE_APP        1  /* VFT_APP */

-#define MD_VSFIXEDFILEINFO_FILE_TYPE_DLL        2  /* VFT_DLL */

-#define MD_VSFIXEDFILEINFO_FILE_TYPE_DRV        3  /* VFT_DLL */

-#define MD_VSFIXEDFILEINFO_FILE_TYPE_FONT       4  /* VFT_FONT */

-#define MD_VSFIXEDFILEINFO_FILE_TYPE_VXD        5  /* VFT_VXD */

-#define MD_VSFIXEDFILEINFO_FILE_TYPE_STATIC_LIB 7  /* VFT_STATIC_LIB */

-

-/* For (MDVSFixedFileInfo).file_subtype */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN                0

-     /* VFT2_UNKNOWN */

-/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_DRV */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_PRINTER            1

-     /* VFT2_DRV_PRINTER */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_KEYBOARD           2

-     /* VFT2_DRV_KEYBOARD */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_LANGUAGE           3

-     /* VFT2_DRV_LANGUAGE */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_DISPLAY            4

-     /* VFT2_DRV_DISPLAY */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_MOUSE              5

-     /* VFT2_DRV_MOUSE */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_NETWORK            6

-     /* VFT2_DRV_NETWORK */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SYSTEM             7

-     /* VFT2_DRV_SYSTEM */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INSTALLABLE        8

-     /* VFT2_DRV_INSTALLABLE */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SOUND              9

-     /* VFT2_DRV_SOUND */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_COMM              10

-     /* VFT2_DRV_COMM */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INPUTMETHOD       11

-     /* VFT2_DRV_INPUTMETHOD */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_VERSIONED_PRINTER 12

-     /* VFT2_DRV_VERSIONED_PRINTER */

-/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_FONT */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_RASTER            1

-     /* VFT2_FONT_RASTER */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_VECTOR            2

-     /* VFT2_FONT_VECTOR */

-#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_TRUETYPE          3

-     /* VFT2_FONT_TRUETYPE */

-

-

-/*

- * DbgHelp.h

- */

-

-

-/* An MDRVA is an offset into the minidump file.  The beginning of the

- * MDRawHeader is at offset 0. */

-typedef u_int32_t MDRVA;  /* RVA */

-

-typedef struct {

-  u_int32_t data_size;

-  MDRVA     rva;

-} MDLocationDescriptor;  /* MINIDUMP_LOCATION_DESCRIPTOR */

-

-

-typedef struct {

-  /* The base address of the memory range on the host that produced the

-   * minidump. */

-  u_int64_t            start_of_memory_range;

-

-  MDLocationDescriptor memory;

-} MDMemoryDescriptor;  /* MINIDUMP_MEMORY_DESCRIPTOR */

-

-

-typedef struct {

-  u_int32_t signature;

-  u_int32_t version;

-  u_int32_t stream_count;

-  MDRVA     stream_directory_rva;  /* A |stream_count|-sized array of

-                                    * MDRawDirectory structures. */

-  u_int32_t checksum;              /* Can be 0.  In fact, that's all that's

-                                    * been found in minidump files. */

-  u_int32_t time_date_stamp;       /* time_t */

-  u_int64_t flags;

-} MDRawHeader;  /* MINIDUMP_HEADER */

-

-/* For (MDRawHeader).signature and (MDRawHeader).version.  Note that only the

- * low 16 bits of (MDRawHeader).version are MD_HEADER_VERSION.  Per the

- * documentation, the high 16 bits are implementation-specific. */

-#define MD_HEADER_SIGNATURE 0x504d444d /* 'PMDM' */

-     /* MINIDUMP_SIGNATURE */

-#define MD_HEADER_VERSION   0x0000a793 /* 42899 */

-     /* MINIDUMP_VERSION */

-

-/* For (MDRawHeader).flags: */

-typedef enum {

-  /* MD_NORMAL is the standard type of minidump.  It includes full

-   * streams for the thread list, module list, exception, system info,

-   * and miscellaneous info.  A memory list stream is also present,

-   * pointing to the same stack memory contained in the thread list,

-   * as well as a 256-byte region around the instruction address that

-   * was executing when the exception occurred.  Stack memory is from

-   * 4 bytes below a thread's stack pointer up to the top of the

-   * memory region encompassing the stack. */

-  MD_NORMAL                            = 0x00000000,

-  MD_WITH_DATA_SEGS                    = 0x00000001,

-  MD_WITH_FULL_MEMORY                  = 0x00000002,

-  MD_WITH_HANDLE_DATA                  = 0x00000004,

-  MD_FILTER_MEMORY                     = 0x00000008,

-  MD_SCAN_MEMORY                       = 0x00000010,

-  MD_WITH_UNLOADED_MODULES             = 0x00000020,

-  MD_WITH_INDIRECTLY_REFERENCED_MEMORY = 0x00000040,

-  MD_FILTER_MODULE_PATHS               = 0x00000080,

-  MD_WITH_PROCESS_THREAD_DATA          = 0x00000100,

-  MD_WITH_PRIVATE_READ_WRITE_MEMORY    = 0x00000200,

-  MD_WITHOUT_OPTIONAL_DATA             = 0x00000400,

-  MD_WITH_FULL_MEMORY_INFO             = 0x00000800,

-  MD_WITH_THREAD_INFO                  = 0x00001000,

-  MD_WITH_CODE_SEGS                    = 0x00002000

-} MDType;  /* MINIDUMP_TYPE */

-

-

-typedef struct {

-  u_int32_t            stream_type;

-  MDLocationDescriptor location;

-} MDRawDirectory;  /* MINIDUMP_DIRECTORY */

-

-/* For (MDRawDirectory).stream_type */

-typedef enum {

-  MD_UNUSED_STREAM               =  0,

-  MD_RESERVED_STREAM_0           =  1,

-  MD_RESERVED_STREAM_1           =  2,

-  MD_THREAD_LIST_STREAM          =  3,  /* MDRawThreadList */

-  MD_MODULE_LIST_STREAM          =  4,  /* MDRawModuleList */

-  MD_MEMORY_LIST_STREAM          =  5,  /* MDRawMemoryList */

-  MD_EXCEPTION_STREAM            =  6,  /* MDRawExceptionStream */

-  MD_SYSTEM_INFO_STREAM          =  7,  /* MDRawSystemInfo */

-  MD_THREAD_EX_LIST_STREAM       =  8,

-  MD_MEMORY_64_LIST_STREAM       =  9,

-  MD_COMMENT_STREAM_A            = 10,

-  MD_COMMENT_STREAM_W            = 11,

-  MD_HANDLE_DATA_STREAM          = 12,

-  MD_FUNCTION_TABLE_STREAM       = 13,

-  MD_UNLOADED_MODULE_LIST_STREAM = 14,

-  MD_MISC_INFO_STREAM            = 15,  /* MDRawMiscInfo */

-  MD_LAST_RESERVED_STREAM        = 0x0000ffff,

-

-  /* Breakpad extension types.  0x4767 = "Gg" */

-  MD_BREAKPAD_INFO_STREAM          = 0x47670001,  /* MDRawBreakpadInfo */

-  MD_ASSERTION_INFO_STREAM       = 0x47670002   /* MDRawAssertionInfo */

-} MDStreamType;  /* MINIDUMP_STREAM_TYPE */

-

-

-typedef struct {

-  u_int32_t length;     /* Length of buffer in bytes (not characters),

-                         * excluding 0-terminator */

-  u_int16_t buffer[1];  /* UTF-16-encoded, 0-terminated */

-} MDString;  /* MINIDUMP_STRING */

-

-static const size_t MDString_minsize = offsetof(MDString, buffer[0]);

-

-

-typedef struct {

-  u_int32_t            thread_id;

-  u_int32_t            suspend_count;

-  u_int32_t            priority_class;

-  u_int32_t            priority;

-  u_int64_t            teb;             /* Thread environment block */

-  MDMemoryDescriptor   stack;

-  MDLocationDescriptor thread_context;  /* MDRawContext[CPU] */

-} MDRawThread;  /* MINIDUMP_THREAD */

-

-

-typedef struct {

-  u_int32_t   number_of_threads;

-  MDRawThread threads[1];

-} MDRawThreadList;  /* MINIDUMP_THREAD_LIST */

-

-static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList,

-                                                       threads[0]);

-

-

-typedef struct {

-  u_int64_t            base_of_image;

-  u_int32_t            size_of_image;

-  u_int32_t            checksum;         /* 0 if unknown */

-  u_int32_t            time_date_stamp;  /* time_t */

-  MDRVA                module_name_rva;  /* MDString, pathname or filename */

-  MDVSFixedFileInfo    version_info;

-

-  /* The next field stores a CodeView record and is populated when a module's

-   * debug information resides in a PDB file.  It identifies the PDB file. */

-  MDLocationDescriptor cv_record;

-

-  /* The next field is populated when a module's debug information resides

-   * in a DBG file.  It identifies the DBG file.  This field is effectively

-   * obsolete with modules built by recent toolchains. */

-  MDLocationDescriptor misc_record;

-

-  /* Alignment problem: reserved0 and reserved1 are defined by the platform

-   * SDK as 64-bit quantities.  However, that results in a structure whose

-   * alignment is unpredictable on different CPUs and ABIs.  If the ABI

-   * specifies full alignment of 64-bit quantities in structures (as ppc

-   * does), there will be padding between miscRecord and reserved0.  If

-   * 64-bit quantities can be aligned on 32-bit boundaries (as on x86),

-   * this padding will not exist.  (Note that the structure up to this point

-   * contains 1 64-bit member followed by 21 32-bit members.)

-   * As a workaround, reserved0 and reserved1 are instead defined here as

-   * four 32-bit quantities.  This should be harmless, as there are

-   * currently no known uses for these fields. */

-  u_int32_t            reserved0[2];

-  u_int32_t            reserved1[2];

-} MDRawModule;  /* MINIDUMP_MODULE */

-

-/* The inclusion of a 64-bit type in MINIDUMP_MODULE forces the struct to

- * be tail-padded out to a multiple of 64 bits under some ABIs (such as PPC).

- * This doesn't occur on systems that don't tail-pad in this manner.  Define

- * this macro to be the usable size of the MDRawModule struct, and use it in

- * place of sizeof(MDRawModule). */

-#define MD_MODULE_SIZE 108

-

-

-/* (MDRawModule).cv_record can reference MDCVInfoPDB20 or MDCVInfoPDB70.

- * Ref.: http://www.debuginfo.com/articles/debuginfomatch.html

- * MDCVInfoPDB70 is the expected structure type with recent toolchains. */

-

-typedef struct {

-  u_int32_t signature;

-  u_int32_t offset;     /* Offset to debug data (expect 0 in minidump) */

-} MDCVHeader;

-

-typedef struct {

-  MDCVHeader cv_header;

-  u_int32_t  signature;         /* time_t debug information created */

-  u_int32_t  age;               /* revision of PDB file */

-  u_int8_t   pdb_file_name[1];  /* Pathname or filename of PDB file */

-} MDCVInfoPDB20;

-

-static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20,

-                                                     pdb_file_name[0]);

-

-#define MD_CVINFOPDB20_SIGNATURE 0x3031424e  /* cvHeader.signature = '01BN' */

-

-typedef struct {

-  u_int32_t cv_signature;

-  MDGUID    signature;         /* GUID, identifies PDB file */

-  u_int32_t age;               /* Identifies incremental changes to PDB file */

-  u_int8_t  pdb_file_name[1];  /* Pathname or filename of PDB file,

-                                * 0-terminated 8-bit character data (UTF-8?) */

-} MDCVInfoPDB70;

-

-static const size_t MDCVInfoPDB70_minsize = offsetof(MDCVInfoPDB70,

-                                                     pdb_file_name[0]);

-

-#define MD_CVINFOPDB70_SIGNATURE 0x53445352  /* cvSignature = 'SDSR' */

-

-typedef struct {

-  u_int32_t data1[2];

-  u_int32_t data2;

-  u_int32_t data3;

-  u_int32_t data4;

-  u_int32_t data5[3];

-  u_int8_t extra[2];

-} MDCVInfoELF;

-

-/* In addition to the two CodeView record formats above, used for linking

- * to external pdb files, it is possible for debugging data to be carried

- * directly in the CodeView record itself.  These signature values will

- * be found in the first 4 bytes of the CodeView record.  Additional values

- * not commonly experienced in the wild are given by "Microsoft Symbol and

- * Type Information", http://www.x86.org/ftp/manuals/tools/sym.pdf, section

- * 7.2.  An in-depth description of the CodeView 4.1 format is given by

- * "Undocumented Windows 2000 Secrets", Windows 2000 Debugging Support/

- * Microsoft Symbol File Internals/CodeView Subsections,

- * http://www.rawol.com/features/undocumented/sbs-w2k-1-windows-2000-debugging-support.pdf

- */

-#define MD_CVINFOCV41_SIGNATURE 0x3930424e  /* '90BN', CodeView 4.10. */

-#define MD_CVINFOCV50_SIGNATURE 0x3131424e  /* '11BN', CodeView 5.0,

-                                             * MS C7-format (/Z7). */

-

-#define MD_CVINFOUNKNOWN_SIGNATURE 0xffffffff  /* An unlikely value. */

-

-/* (MDRawModule).miscRecord can reference MDImageDebugMisc.  The Windows

- * structure is actually defined in WinNT.h.  This structure is effectively

- * obsolete with modules built by recent toolchains. */

-

-typedef struct {

-  u_int32_t data_type;    /* IMAGE_DEBUG_TYPE_*, not defined here because

-                           * this debug record type is mostly obsolete. */

-  u_int32_t length;       /* Length of entire MDImageDebugMisc structure */

-  u_int8_t  unicode;      /* True if data is multibyte */

-  u_int8_t  reserved[3];

-  u_int8_t  data[1];

-} MDImageDebugMisc;  /* IMAGE_DEBUG_MISC */

-

-static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc,

-                                                        data[0]);

-

-

-typedef struct {

-  u_int32_t   number_of_modules;

-  MDRawModule modules[1];

-} MDRawModuleList;  /* MINIDUMP_MODULE_LIST */

-

-static const size_t MDRawModuleList_minsize = offsetof(MDRawModuleList,

-                                                       modules[0]);

-

-

-typedef struct {

-  u_int32_t          number_of_memory_ranges;

-  MDMemoryDescriptor memory_ranges[1];

-} MDRawMemoryList;  /* MINIDUMP_MEMORY_LIST */

-

-static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList,

-                                                       memory_ranges[0]);

-

-

-#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15

-

-typedef struct {

-  u_int32_t exception_code;     /* Windows: MDExceptionCodeWin,

-                                 * Mac OS X: MDExceptionMac,

-                                 * Linux: MDExceptionCodeLinux. */

-  u_int32_t exception_flags;    /* Windows: 1 if noncontinuable,

-                                   Mac OS X: MDExceptionCodeMac. */

-  u_int64_t exception_record;   /* Address (in the minidump-producing host's

-                                 * memory) of another MDException, for

-                                 * nested exceptions. */

-  u_int64_t exception_address;  /* The address that caused the exception.

-                                 * Mac OS X: exception subcode (which is

-                                 *           typically the address). */

-  u_int32_t number_parameters;  /* Number of valid elements in

-                                 * exception_information. */

-  u_int32_t __align;

-  u_int64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS];

-} MDException;  /* MINIDUMP_EXCEPTION */

-

-#include "minidump_exception_win32.h"

-#include "minidump_exception_mac.h"

-#include "minidump_exception_linux.h"

-#include "minidump_exception_solaris.h"

-

-typedef struct {

-  u_int32_t            thread_id;         /* Thread in which the exception

-                                           * occurred.  Corresponds to

-                                           * (MDRawThread).thread_id. */

-  u_int32_t            __align;

-  MDException          exception_record;

-  MDLocationDescriptor thread_context;    /* MDRawContext[CPU] */

-} MDRawExceptionStream;  /* MINIDUMP_EXCEPTION_STREAM */

-

-

-typedef union {

-  struct {

-    u_int32_t vendor_id[3];               /* cpuid 0: ebx, edx, ecx */

-    u_int32_t version_information;        /* cpuid 1: eax */

-    u_int32_t feature_information;        /* cpuid 1: edx */

-    u_int32_t amd_extended_cpu_features;  /* cpuid 0x80000001, ebx */

-  } x86_cpu_info;

-  struct {

-    u_int64_t processor_features[2];

-  } other_cpu_info;

-} MDCPUInformation;  /* CPU_INFORMATION */

-

-

-typedef struct {

-  /* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO

-   * structure as returned by GetSystemInfo */

-  u_int16_t        processor_architecture;

-  u_int16_t        processor_level;         /* x86: 5 = 586, 6 = 686, ... */

-  u_int16_t        processor_revision;      /* x86: 0xMMSS, where MM=model,

-                                             *      SS=stepping */

-

-  u_int8_t         number_of_processors;

-  u_int8_t         product_type;            /* Windows: VER_NT_* from WinNT.h */

-

-  /* The next 5 fields are from the OSVERSIONINFO structure as returned

-   * by GetVersionEx */

-  u_int32_t        major_version;

-  u_int32_t        minor_version;

-  u_int32_t        build_number;

-  u_int32_t        platform_id;

-  MDRVA            csd_version_rva;  /* MDString further identifying the

-                                      * host OS.

-                                      * Windows: name of the installed OS

-                                      *          service pack.

-                                      * Mac OS X: the Apple OS build number

-                                      *           (sw_vers -buildVersion).

-                                      * Linux: uname -srvmo */

-

-  u_int16_t        suite_mask;       /* Windows: VER_SUITE_* from WinNT.h */

-  u_int16_t        reserved2;

-

-  MDCPUInformation cpu;

-} MDRawSystemInfo;  /* MINIDUMP_SYSTEM_INFO */

-

-/* For (MDRawSystemInfo).processor_architecture: */

-typedef enum {

-  MD_CPU_ARCHITECTURE_X86       =  0,  /* PROCESSOR_ARCHITECTURE_INTEL */

-  MD_CPU_ARCHITECTURE_MIPS      =  1,  /* PROCESSOR_ARCHITECTURE_MIPS */

-  MD_CPU_ARCHITECTURE_ALPHA     =  2,  /* PROCESSOR_ARCHITECTURE_ALPHA */

-  MD_CPU_ARCHITECTURE_PPC       =  3,  /* PROCESSOR_ARCHITECTURE_PPC */

-  MD_CPU_ARCHITECTURE_SHX       =  4,  /* PROCESSOR_ARCHITECTURE_SHX

-                                        * (Super-H) */

-  MD_CPU_ARCHITECTURE_ARM       =  5,  /* PROCESSOR_ARCHITECTURE_ARM */

-  MD_CPU_ARCHITECTURE_IA64      =  6,  /* PROCESSOR_ARCHITECTURE_IA64 */

-  MD_CPU_ARCHITECTURE_ALPHA64   =  7,  /* PROCESSOR_ARCHITECTURE_ALPHA64 */

-  MD_CPU_ARCHITECTURE_MSIL      =  8,  /* PROCESSOR_ARCHITECTURE_MSIL

-                                        * (Microsoft Intermediate Language) */

-  MD_CPU_ARCHITECTURE_AMD64     =  9,  /* PROCESSOR_ARCHITECTURE_AMD64 */

-  MD_CPU_ARCHITECTURE_X86_WIN64 = 10,

-      /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */

-  MD_CPU_ARCHITECTURE_SPARC     = 0x8001, /* Breakpad-defined value for SPARC */

-  MD_CPU_ARCHITECTURE_UNKNOWN   = 0xffff  /* PROCESSOR_ARCHITECTURE_UNKNOWN */

-} MDCPUArchitecture;

-

-/* For (MDRawSystemInfo).platform_id: */

-typedef enum {

-  MD_OS_WIN32S        = 0,  /* VER_PLATFORM_WIN32s (Windows 3.1) */

-  MD_OS_WIN32_WINDOWS = 1,  /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */

-  MD_OS_WIN32_NT      = 2,  /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */

-  MD_OS_WIN32_CE      = 3,  /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH

-                             * (Windows CE, Windows Mobile, "Handheld") */

-

-  /* The following values are Breakpad-defined. */

-  MD_OS_UNIX          = 0x8000,  /* Generic Unix-ish */

-  MD_OS_MAC_OS_X      = 0x8101,  /* Mac OS X/Darwin */

-  MD_OS_LINUX         = 0x8201,  /* Linux */

-  MD_OS_SOLARIS       = 0x8202   /* Solaris */

-} MDOSPlatform;

-

-

-typedef struct {

-  u_int32_t size_of_info;  /* Length of entire MDRawMiscInfo structure. */

-  u_int32_t flags1;

-

-  /* The next field is only valid if flags1 contains

-   * MD_MISCINFO_FLAGS1_PROCESS_ID. */

-  u_int32_t process_id;

-

-  /* The next 3 fields are only valid if flags1 contains

-   * MD_MISCINFO_FLAGS1_PROCESS_TIMES. */

-  u_int32_t process_create_time;  /* time_t process started */

-  u_int32_t process_user_time;    /* seconds of user CPU time */

-  u_int32_t process_kernel_time;  /* seconds of kernel CPU time */

-

-  /* The following fields are not present in MINIDUMP_MISC_INFO but are

-   * in MINIDUMP_MISC_INFO_2.  When this struct is populated, these values

-   * may not be set.  Use flags1 or sizeOfInfo to determine whether these

-   * values are present.  These are only valid when flags1 contains

-   * MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO. */

-  u_int32_t processor_max_mhz;

-  u_int32_t processor_current_mhz;

-  u_int32_t processor_mhz_limit;

-  u_int32_t processor_max_idle_state;

-  u_int32_t processor_current_idle_state;

-} MDRawMiscInfo;  /* MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO2 */

-

-#define MD_MISCINFO_SIZE 24

-#define MD_MISCINFO2_SIZE 44

-

-/* For (MDRawMiscInfo).flags1.  These values indicate which fields in the

- * MDRawMiscInfoStructure are valid. */

-typedef enum {

-  MD_MISCINFO_FLAGS1_PROCESS_ID           = 0x00000001,

-      /* MINIDUMP_MISC1_PROCESS_ID */

-  MD_MISCINFO_FLAGS1_PROCESS_TIMES        = 0x00000002,

-      /* MINIDUMP_MISC1_PROCESS_TIMES */

-  MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO = 0x00000004

-      /* MINIDUMP_MISC1_PROCESSOR_POWER_INFO */

-} MDMiscInfoFlags1;

-

-

-/*

- * Breakpad extension types

- */

-

-

-typedef struct {

-  /* validity is a bitmask with values from MDBreakpadInfoValidity, indicating

-   * which of the other fields in the structure are valid. */

-  u_int32_t validity;

-

-  /* Thread ID of the handler thread.  dump_thread_id should correspond to

-   * the thread_id of an MDRawThread in the minidump's MDRawThreadList if

-   * a dedicated thread in that list was used to produce the minidump.  If

-   * the MDRawThreadList does not contain a dedicated thread used to produce

-   * the minidump, this field should be set to 0 and the validity field

-   * must not contain MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID. */

-  u_int32_t dump_thread_id;

-

-  /* Thread ID of the thread that requested the minidump be produced.  As

-   * with dump_thread_id, requesting_thread_id should correspond to the

-   * thread_id of an MDRawThread in the minidump's MDRawThreadList.  For

-   * minidumps produced as a result of an exception, requesting_thread_id

-   * will be the same as the MDRawExceptionStream's thread_id field.  For

-   * minidumps produced "manually" at the program's request,

-   * requesting_thread_id will indicate which thread caused the dump to be

-   * written.  If the minidump was produced at the request of something

-   * other than a thread in the MDRawThreadList, this field should be set

-   * to 0 and the validity field must not contain

-   * MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID. */

-  u_int32_t requesting_thread_id;

-} MDRawBreakpadInfo;

-

-/* For (MDRawBreakpadInfo).validity: */

-typedef enum {

-  /* When set, the dump_thread_id field is valid. */

-  MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID       = 1 << 0,

-

-  /* When set, the requesting_thread_id field is valid. */

-  MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID = 1 << 1

-} MDBreakpadInfoValidity;

-

-typedef struct {

-  /* expression, function, and file are 0-terminated UTF-16 strings.  They

-   * may be truncated if necessary, but should always be 0-terminated when

-   * written to a file.

-   * Fixed-length strings are used because MiniDumpWriteDump doesn't offer

-   * a way for user streams to point to arbitrary RVAs for strings. */

-  u_int16_t expression[128];  /* Assertion that failed... */

-  u_int16_t function[128];    /* ...within this function... */

-  u_int16_t file[128];        /* ...in this file... */

-  u_int32_t line;             /* ...at this line. */

-  u_int32_t type;

-} MDRawAssertionInfo;

-

-/* For (MDRawAssertionInfo).type: */

-typedef enum {

-  MD_ASSERTION_INFO_TYPE_UNKNOWN = 0,

-

-  /* Used for assertions that would be raised by the MSVC CRT but are

-   * directed to an invalid parameter handler instead. */

-  MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER,

-

-  /* Used for assertions that would be raised by the MSVC CRT but are

-   * directed to a pure virtual call handler instead. */

-  MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL

-} MDAssertionInfoData;

-

-#if defined(_MSC_VER)

-#pragma warning(pop)

-#endif  /* _MSC_VER */

-

-

-#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ */

+/* Copyright (c) 2006, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+/* minidump_format.h: A cross-platform reimplementation of minidump-related
+ * portions of DbgHelp.h from the Windows Platform SDK.
+ *
+ * (This is C99 source, please don't corrupt it with C++.)
+ *
+ * Structures that are defined by Microsoft to contain a zero-length array
+ * are instead defined here to contain an array with one element, as
+ * zero-length arrays are forbidden by standard C and C++.  In these cases,
+ * *_minsize constants are provided to be used in place of sizeof.  For a
+ * cleaner interface to these sizes when using C++, see minidump_size.h.
+ *
+ * These structures are also sufficient to populate minidump files.
+ *
+ * These definitions may be extended to support handling minidump files
+ * for other CPUs and other operating systems.
+ *
+ * Because precise data type sizes are crucial for this implementation to
+ * function properly and portably in terms of interoperability with minidumps
+ * produced by DbgHelp on Windows, a set of primitive types with known sizes
+ * are used as the basis of each structure defined by this file.  DbgHelp
+ * on Windows is assumed to be the reference implementation; this file
+ * seeks to provide a cross-platform compatible implementation.  To avoid
+ * collisions with the types and values defined and used by DbgHelp in the
+ * event that this implementation is used on Windows, each type and value
+ * defined here is given a new name, beginning with "MD".  Names of the
+ * equivalent types and values in the Windows Platform SDK are given in
+ * comments.
+ *
+ * Author: Mark Mentovai */
+
+
+#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__
+#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__
+
+#include <stddef.h>
+
+#include "google_breakpad/common/breakpad_types.h"
+
+
+#if defined(_MSC_VER)
+/* Disable "zero-sized array in struct/union" warnings when compiling in
+ * MSVC.  DbgHelp.h does this too. */
+#pragma warning(push)
+#pragma warning(disable:4200)
+#endif  /* _MSC_VER */
+
+
+/*
+ * guiddef.h
+ */
+
+typedef struct {
+  u_int32_t data1;
+  u_int16_t data2;
+  u_int16_t data3;
+  u_int8_t  data4[8];
+} MDGUID;  /* GUID */
+
+
+/*
+ * WinNT.h
+ */
+
+/* Non-x86 CPU identifiers found in the high 26 bits of
+ * (MDRawContext*).context_flags.  These aren't used by Breakpad, but are
+ * defined here for reference, to avoid assigning values that conflict
+ * (although some values already conflict). */
+#define MD_CONTEXT_IA64  0x00080000  /* CONTEXT_IA64 */
+#define MD_CONTEXT_AMD64 0x00100000  /* CONTEXT_AMD64 */
+/* Additional values from winnt.h in the Windows CE 5.0 SDK: */
+#define MD_CONTEXT_SHX   0x000000c0  /* CONTEXT_SH4 (Super-H, includes SH3) */
+#define MD_CONTEXT_ARM   0x00000040  /* CONTEXT_ARM (0x40 bit set in SHx?) */
+#define MD_CONTEXT_MIPS  0x00010000  /* CONTEXT_R4000 (same value as x86?) */
+#define MD_CONTEXT_ALPHA 0x00020000  /* CONTEXT_ALPHA */
+
+#define MD_CONTEXT_CPU_MASK 0xffffffc0
+
+
+/* This is a base type for MDRawContextX86 and MDRawContextPPC.  This
+ * structure should never be allocated directly.  The actual structure type
+ * can be determined by examining the context_flags field. */
+typedef struct {
+  u_int32_t context_flags;
+} MDRawContextBase;
+
+#include "minidump_cpu_sparc.h"
+#include "minidump_cpu_x86.h"
+#include "minidump_cpu_ppc.h"
+#include "minidump_cpu_ppc64.h"
+#include "minidump_cpu_amd64.h"
+
+
+/*
+ * WinVer.h
+ */
+
+
+typedef struct {
+  u_int32_t signature;
+  u_int32_t struct_version;
+  u_int32_t file_version_hi;
+  u_int32_t file_version_lo;
+  u_int32_t product_version_hi;
+  u_int32_t product_version_lo;
+  u_int32_t file_flags_mask;    /* Identifies valid bits in fileFlags */
+  u_int32_t file_flags;
+  u_int32_t file_os;
+  u_int32_t file_type;
+  u_int32_t file_subtype;
+  u_int32_t file_date_hi;
+  u_int32_t file_date_lo;
+} MDVSFixedFileInfo;  /* VS_FIXEDFILEINFO */
+
+/* For (MDVSFixedFileInfo).signature */
+#define MD_VSFIXEDFILEINFO_SIGNATURE 0xfeef04bd
+     /* VS_FFI_SIGNATURE */
+
+/* For (MDVSFixedFileInfo).version */
+#define MD_VSFIXEDFILEINFO_VERSION 0x00010000
+     /* VS_FFI_STRUCVERSION */
+
+/* For (MDVSFixedFileInfo).file_flags_mask and
+ * (MDVSFixedFileInfo).file_flags */
+#define MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG        0x00000001
+     /* VS_FF_DEBUG */
+#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRERELEASE   0x00000002
+     /* VS_FF_PRERELEASE */
+#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PATCHED      0x00000004
+     /* VS_FF_PATCHED */
+#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRIVATEBUILD 0x00000008
+     /* VS_FF_PRIVATEBUILD */
+#define MD_VSFIXEDFILEINFO_FILE_FLAGS_INFOINFERRED 0x00000010
+     /* VS_FF_INFOINFERRED */
+#define MD_VSFIXEDFILEINFO_FILE_FLAGS_SPECIALBUILD 0x00000020
+     /* VS_FF_SPECIALBUILD */
+
+/* For (MDVSFixedFileInfo).file_os: high 16 bits */
+#define MD_VSFIXEDFILEINFO_FILE_OS_UNKNOWN    0          /* VOS_UNKNOWN */
+#define MD_VSFIXEDFILEINFO_FILE_OS_DOS        (1 << 16)  /* VOS_DOS */
+#define MD_VSFIXEDFILEINFO_FILE_OS_OS216      (2 << 16)  /* VOS_OS216 */
+#define MD_VSFIXEDFILEINFO_FILE_OS_OS232      (3 << 16)  /* VOS_OS232 */
+#define MD_VSFIXEDFILEINFO_FILE_OS_NT         (4 << 16)  /* VOS_NT */
+#define MD_VSFIXEDFILEINFO_FILE_OS_WINCE      (5 << 16)  /* VOS_WINCE */
+/* Low 16 bits */
+#define MD_VSFIXEDFILEINFO_FILE_OS__BASE      0          /* VOS__BASE */
+#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS16 1          /* VOS__WINDOWS16 */
+#define MD_VSFIXEDFILEINFO_FILE_OS__PM16      2          /* VOS__PM16 */
+#define MD_VSFIXEDFILEINFO_FILE_OS__PM32      3          /* VOS__PM32 */
+#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32 4          /* VOS__WINDOWS32 */
+
+/* For (MDVSFixedFileInfo).file_type */
+#define MD_VSFIXEDFILEINFO_FILE_TYPE_UNKNOWN    0  /* VFT_UNKNOWN */
+#define MD_VSFIXEDFILEINFO_FILE_TYPE_APP        1  /* VFT_APP */
+#define MD_VSFIXEDFILEINFO_FILE_TYPE_DLL        2  /* VFT_DLL */
+#define MD_VSFIXEDFILEINFO_FILE_TYPE_DRV        3  /* VFT_DLL */
+#define MD_VSFIXEDFILEINFO_FILE_TYPE_FONT       4  /* VFT_FONT */
+#define MD_VSFIXEDFILEINFO_FILE_TYPE_VXD        5  /* VFT_VXD */
+#define MD_VSFIXEDFILEINFO_FILE_TYPE_STATIC_LIB 7  /* VFT_STATIC_LIB */
+
+/* For (MDVSFixedFileInfo).file_subtype */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN                0
+     /* VFT2_UNKNOWN */
+/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_DRV */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_PRINTER            1
+     /* VFT2_DRV_PRINTER */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_KEYBOARD           2
+     /* VFT2_DRV_KEYBOARD */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_LANGUAGE           3
+     /* VFT2_DRV_LANGUAGE */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_DISPLAY            4
+     /* VFT2_DRV_DISPLAY */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_MOUSE              5
+     /* VFT2_DRV_MOUSE */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_NETWORK            6
+     /* VFT2_DRV_NETWORK */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SYSTEM             7
+     /* VFT2_DRV_SYSTEM */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INSTALLABLE        8
+     /* VFT2_DRV_INSTALLABLE */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SOUND              9
+     /* VFT2_DRV_SOUND */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_COMM              10
+     /* VFT2_DRV_COMM */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INPUTMETHOD       11
+     /* VFT2_DRV_INPUTMETHOD */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_VERSIONED_PRINTER 12
+     /* VFT2_DRV_VERSIONED_PRINTER */
+/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_FONT */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_RASTER            1
+     /* VFT2_FONT_RASTER */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_VECTOR            2
+     /* VFT2_FONT_VECTOR */
+#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_TRUETYPE          3
+     /* VFT2_FONT_TRUETYPE */
+
+
+/*
+ * DbgHelp.h
+ */
+
+
+/* An MDRVA is an offset into the minidump file.  The beginning of the
+ * MDRawHeader is at offset 0. */
+typedef u_int32_t MDRVA;  /* RVA */
+
+typedef struct {
+  u_int32_t data_size;
+  MDRVA     rva;
+} MDLocationDescriptor;  /* MINIDUMP_LOCATION_DESCRIPTOR */
+
+
+typedef struct {
+  /* The base address of the memory range on the host that produced the
+   * minidump. */
+  u_int64_t            start_of_memory_range;
+
+  MDLocationDescriptor memory;
+} MDMemoryDescriptor;  /* MINIDUMP_MEMORY_DESCRIPTOR */
+
+
+typedef struct {
+  u_int32_t signature;
+  u_int32_t version;
+  u_int32_t stream_count;
+  MDRVA     stream_directory_rva;  /* A |stream_count|-sized array of
+                                    * MDRawDirectory structures. */
+  u_int32_t checksum;              /* Can be 0.  In fact, that's all that's
+                                    * been found in minidump files. */
+  u_int32_t time_date_stamp;       /* time_t */
+  u_int64_t flags;
+} MDRawHeader;  /* MINIDUMP_HEADER */
+
+/* For (MDRawHeader).signature and (MDRawHeader).version.  Note that only the
+ * low 16 bits of (MDRawHeader).version are MD_HEADER_VERSION.  Per the
+ * documentation, the high 16 bits are implementation-specific. */
+#define MD_HEADER_SIGNATURE 0x504d444d /* 'PMDM' */
+     /* MINIDUMP_SIGNATURE */
+#define MD_HEADER_VERSION   0x0000a793 /* 42899 */
+     /* MINIDUMP_VERSION */
+
+/* For (MDRawHeader).flags: */
+typedef enum {
+  /* MD_NORMAL is the standard type of minidump.  It includes full
+   * streams for the thread list, module list, exception, system info,
+   * and miscellaneous info.  A memory list stream is also present,
+   * pointing to the same stack memory contained in the thread list,
+   * as well as a 256-byte region around the instruction address that
+   * was executing when the exception occurred.  Stack memory is from
+   * 4 bytes below a thread's stack pointer up to the top of the
+   * memory region encompassing the stack. */
+  MD_NORMAL                            = 0x00000000,
+  MD_WITH_DATA_SEGS                    = 0x00000001,
+  MD_WITH_FULL_MEMORY                  = 0x00000002,
+  MD_WITH_HANDLE_DATA                  = 0x00000004,
+  MD_FILTER_MEMORY                     = 0x00000008,
+  MD_SCAN_MEMORY                       = 0x00000010,
+  MD_WITH_UNLOADED_MODULES             = 0x00000020,
+  MD_WITH_INDIRECTLY_REFERENCED_MEMORY = 0x00000040,
+  MD_FILTER_MODULE_PATHS               = 0x00000080,
+  MD_WITH_PROCESS_THREAD_DATA          = 0x00000100,
+  MD_WITH_PRIVATE_READ_WRITE_MEMORY    = 0x00000200,
+  MD_WITHOUT_OPTIONAL_DATA             = 0x00000400,
+  MD_WITH_FULL_MEMORY_INFO             = 0x00000800,
+  MD_WITH_THREAD_INFO                  = 0x00001000,
+  MD_WITH_CODE_SEGS                    = 0x00002000
+} MDType;  /* MINIDUMP_TYPE */
+
+
+typedef struct {
+  u_int32_t            stream_type;
+  MDLocationDescriptor location;
+} MDRawDirectory;  /* MINIDUMP_DIRECTORY */
+
+/* For (MDRawDirectory).stream_type */
+typedef enum {
+  MD_UNUSED_STREAM               =  0,
+  MD_RESERVED_STREAM_0           =  1,
+  MD_RESERVED_STREAM_1           =  2,
+  MD_THREAD_LIST_STREAM          =  3,  /* MDRawThreadList */
+  MD_MODULE_LIST_STREAM          =  4,  /* MDRawModuleList */
+  MD_MEMORY_LIST_STREAM          =  5,  /* MDRawMemoryList */
+  MD_EXCEPTION_STREAM            =  6,  /* MDRawExceptionStream */
+  MD_SYSTEM_INFO_STREAM          =  7,  /* MDRawSystemInfo */
+  MD_THREAD_EX_LIST_STREAM       =  8,
+  MD_MEMORY_64_LIST_STREAM       =  9,
+  MD_COMMENT_STREAM_A            = 10,
+  MD_COMMENT_STREAM_W            = 11,
+  MD_HANDLE_DATA_STREAM          = 12,
+  MD_FUNCTION_TABLE_STREAM       = 13,
+  MD_UNLOADED_MODULE_LIST_STREAM = 14,
+  MD_MISC_INFO_STREAM            = 15,  /* MDRawMiscInfo */
+  MD_LAST_RESERVED_STREAM        = 0x0000ffff,
+
+  /* Breakpad extension types.  0x4767 = "Gg" */
+  MD_BREAKPAD_INFO_STREAM          = 0x47670001,  /* MDRawBreakpadInfo */
+  MD_ASSERTION_INFO_STREAM       = 0x47670002   /* MDRawAssertionInfo */
+} MDStreamType;  /* MINIDUMP_STREAM_TYPE */
+
+
+typedef struct {
+  u_int32_t length;     /* Length of buffer in bytes (not characters),
+                         * excluding 0-terminator */
+  u_int16_t buffer[1];  /* UTF-16-encoded, 0-terminated */
+} MDString;  /* MINIDUMP_STRING */
+
+static const size_t MDString_minsize = offsetof(MDString, buffer[0]);
+
+
+typedef struct {
+  u_int32_t            thread_id;
+  u_int32_t            suspend_count;
+  u_int32_t            priority_class;
+  u_int32_t            priority;
+  u_int64_t            teb;             /* Thread environment block */
+  MDMemoryDescriptor   stack;
+  MDLocationDescriptor thread_context;  /* MDRawContext[CPU] */
+} MDRawThread;  /* MINIDUMP_THREAD */
+
+
+typedef struct {
+  u_int32_t   number_of_threads;
+  MDRawThread threads[1];
+} MDRawThreadList;  /* MINIDUMP_THREAD_LIST */
+
+static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList,
+                                                       threads[0]);
+
+
+typedef struct {
+  u_int64_t            base_of_image;
+  u_int32_t            size_of_image;
+  u_int32_t            checksum;         /* 0 if unknown */
+  u_int32_t            time_date_stamp;  /* time_t */
+  MDRVA                module_name_rva;  /* MDString, pathname or filename */
+  MDVSFixedFileInfo    version_info;
+
+  /* The next field stores a CodeView record and is populated when a module's
+   * debug information resides in a PDB file.  It identifies the PDB file. */
+  MDLocationDescriptor cv_record;
+
+  /* The next field is populated when a module's debug information resides
+   * in a DBG file.  It identifies the DBG file.  This field is effectively
+   * obsolete with modules built by recent toolchains. */
+  MDLocationDescriptor misc_record;
+
+  /* Alignment problem: reserved0 and reserved1 are defined by the platform
+   * SDK as 64-bit quantities.  However, that results in a structure whose
+   * alignment is unpredictable on different CPUs and ABIs.  If the ABI
+   * specifies full alignment of 64-bit quantities in structures (as ppc
+   * does), there will be padding between miscRecord and reserved0.  If
+   * 64-bit quantities can be aligned on 32-bit boundaries (as on x86),
+   * this padding will not exist.  (Note that the structure up to this point
+   * contains 1 64-bit member followed by 21 32-bit members.)
+   * As a workaround, reserved0 and reserved1 are instead defined here as
+   * four 32-bit quantities.  This should be harmless, as there are
+   * currently no known uses for these fields. */
+  u_int32_t            reserved0[2];
+  u_int32_t            reserved1[2];
+} MDRawModule;  /* MINIDUMP_MODULE */
+
+/* The inclusion of a 64-bit type in MINIDUMP_MODULE forces the struct to
+ * be tail-padded out to a multiple of 64 bits under some ABIs (such as PPC).
+ * This doesn't occur on systems that don't tail-pad in this manner.  Define
+ * this macro to be the usable size of the MDRawModule struct, and use it in
+ * place of sizeof(MDRawModule). */
+#define MD_MODULE_SIZE 108
+
+
+/* (MDRawModule).cv_record can reference MDCVInfoPDB20 or MDCVInfoPDB70.
+ * Ref.: http://www.debuginfo.com/articles/debuginfomatch.html
+ * MDCVInfoPDB70 is the expected structure type with recent toolchains. */
+
+typedef struct {
+  u_int32_t signature;
+  u_int32_t offset;     /* Offset to debug data (expect 0 in minidump) */
+} MDCVHeader;
+
+typedef struct {
+  MDCVHeader cv_header;
+  u_int32_t  signature;         /* time_t debug information created */
+  u_int32_t  age;               /* revision of PDB file */
+  u_int8_t   pdb_file_name[1];  /* Pathname or filename of PDB file */
+} MDCVInfoPDB20;
+
+static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20,
+                                                     pdb_file_name[0]);
+
+#define MD_CVINFOPDB20_SIGNATURE 0x3031424e  /* cvHeader.signature = '01BN' */
+
+typedef struct {
+  u_int32_t cv_signature;
+  MDGUID    signature;         /* GUID, identifies PDB file */
+  u_int32_t age;               /* Identifies incremental changes to PDB file */
+  u_int8_t  pdb_file_name[1];  /* Pathname or filename of PDB file,
+                                * 0-terminated 8-bit character data (UTF-8?) */
+} MDCVInfoPDB70;
+
+static const size_t MDCVInfoPDB70_minsize = offsetof(MDCVInfoPDB70,
+                                                     pdb_file_name[0]);
+
+#define MD_CVINFOPDB70_SIGNATURE 0x53445352  /* cvSignature = 'SDSR' */
+
+typedef struct {
+  u_int32_t data1[2];
+  u_int32_t data2;
+  u_int32_t data3;
+  u_int32_t data4;
+  u_int32_t data5[3];
+  u_int8_t extra[2];
+} MDCVInfoELF;
+
+/* In addition to the two CodeView record formats above, used for linking
+ * to external pdb files, it is possible for debugging data to be carried
+ * directly in the CodeView record itself.  These signature values will
+ * be found in the first 4 bytes of the CodeView record.  Additional values
+ * not commonly experienced in the wild are given by "Microsoft Symbol and
+ * Type Information", http://www.x86.org/ftp/manuals/tools/sym.pdf, section
+ * 7.2.  An in-depth description of the CodeView 4.1 format is given by
+ * "Undocumented Windows 2000 Secrets", Windows 2000 Debugging Support/
+ * Microsoft Symbol File Internals/CodeView Subsections,
+ * http://www.rawol.com/features/undocumented/sbs-w2k-1-windows-2000-debugging-support.pdf
+ */
+#define MD_CVINFOCV41_SIGNATURE 0x3930424e  /* '90BN', CodeView 4.10. */
+#define MD_CVINFOCV50_SIGNATURE 0x3131424e  /* '11BN', CodeView 5.0,
+                                             * MS C7-format (/Z7). */
+
+#define MD_CVINFOUNKNOWN_SIGNATURE 0xffffffff  /* An unlikely value. */
+
+/* (MDRawModule).miscRecord can reference MDImageDebugMisc.  The Windows
+ * structure is actually defined in WinNT.h.  This structure is effectively
+ * obsolete with modules built by recent toolchains. */
+
+typedef struct {
+  u_int32_t data_type;    /* IMAGE_DEBUG_TYPE_*, not defined here because
+                           * this debug record type is mostly obsolete. */
+  u_int32_t length;       /* Length of entire MDImageDebugMisc structure */
+  u_int8_t  unicode;      /* True if data is multibyte */
+  u_int8_t  reserved[3];
+  u_int8_t  data[1];
+} MDImageDebugMisc;  /* IMAGE_DEBUG_MISC */
+
+static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc,
+                                                        data[0]);
+
+
+typedef struct {
+  u_int32_t   number_of_modules;
+  MDRawModule modules[1];
+} MDRawModuleList;  /* MINIDUMP_MODULE_LIST */
+
+static const size_t MDRawModuleList_minsize = offsetof(MDRawModuleList,
+                                                       modules[0]);
+
+
+typedef struct {
+  u_int32_t          number_of_memory_ranges;
+  MDMemoryDescriptor memory_ranges[1];
+} MDRawMemoryList;  /* MINIDUMP_MEMORY_LIST */
+
+static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList,
+                                                       memory_ranges[0]);
+
+
+#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15
+
+typedef struct {
+  u_int32_t exception_code;     /* Windows: MDExceptionCodeWin,
+                                 * Mac OS X: MDExceptionMac,
+                                 * Linux: MDExceptionCodeLinux. */
+  u_int32_t exception_flags;    /* Windows: 1 if noncontinuable,
+                                   Mac OS X: MDExceptionCodeMac. */
+  u_int64_t exception_record;   /* Address (in the minidump-producing host's
+                                 * memory) of another MDException, for
+                                 * nested exceptions. */
+  u_int64_t exception_address;  /* The address that caused the exception.
+                                 * Mac OS X: exception subcode (which is
+                                 *           typically the address). */
+  u_int32_t number_parameters;  /* Number of valid elements in
+                                 * exception_information. */
+  u_int32_t __align;
+  u_int64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS];
+} MDException;  /* MINIDUMP_EXCEPTION */
+
+#include "minidump_exception_win32.h"
+#include "minidump_exception_mac.h"
+#include "minidump_exception_linux.h"
+#include "minidump_exception_solaris.h"
+
+typedef struct {
+  u_int32_t            thread_id;         /* Thread in which the exception
+                                           * occurred.  Corresponds to
+                                           * (MDRawThread).thread_id. */
+  u_int32_t            __align;
+  MDException          exception_record;
+  MDLocationDescriptor thread_context;    /* MDRawContext[CPU] */
+} MDRawExceptionStream;  /* MINIDUMP_EXCEPTION_STREAM */
+
+
+typedef union {
+  struct {
+    u_int32_t vendor_id[3];               /* cpuid 0: ebx, edx, ecx */
+    u_int32_t version_information;        /* cpuid 1: eax */
+    u_int32_t feature_information;        /* cpuid 1: edx */
+    u_int32_t amd_extended_cpu_features;  /* cpuid 0x80000001, ebx */
+  } x86_cpu_info;
+  struct {
+    u_int64_t processor_features[2];
+  } other_cpu_info;
+} MDCPUInformation;  /* CPU_INFORMATION */
+
+
+typedef struct {
+  /* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO
+   * structure as returned by GetSystemInfo */
+  u_int16_t        processor_architecture;
+  u_int16_t        processor_level;         /* x86: 5 = 586, 6 = 686, ... */
+  u_int16_t        processor_revision;      /* x86: 0xMMSS, where MM=model,
+                                             *      SS=stepping */
+
+  u_int8_t         number_of_processors;
+  u_int8_t         product_type;            /* Windows: VER_NT_* from WinNT.h */
+
+  /* The next 5 fields are from the OSVERSIONINFO structure as returned
+   * by GetVersionEx */
+  u_int32_t        major_version;
+  u_int32_t        minor_version;
+  u_int32_t        build_number;
+  u_int32_t        platform_id;
+  MDRVA            csd_version_rva;  /* MDString further identifying the
+                                      * host OS.
+                                      * Windows: name of the installed OS
+                                      *          service pack.
+                                      * Mac OS X: the Apple OS build number
+                                      *           (sw_vers -buildVersion).
+                                      * Linux: uname -srvmo */
+
+  u_int16_t        suite_mask;       /* Windows: VER_SUITE_* from WinNT.h */
+  u_int16_t        reserved2;
+
+  MDCPUInformation cpu;
+} MDRawSystemInfo;  /* MINIDUMP_SYSTEM_INFO */
+
+/* For (MDRawSystemInfo).processor_architecture: */
+typedef enum {
+  MD_CPU_ARCHITECTURE_X86       =  0,  /* PROCESSOR_ARCHITECTURE_INTEL */
+  MD_CPU_ARCHITECTURE_MIPS      =  1,  /* PROCESSOR_ARCHITECTURE_MIPS */
+  MD_CPU_ARCHITECTURE_ALPHA     =  2,  /* PROCESSOR_ARCHITECTURE_ALPHA */
+  MD_CPU_ARCHITECTURE_PPC       =  3,  /* PROCESSOR_ARCHITECTURE_PPC */
+  MD_CPU_ARCHITECTURE_SHX       =  4,  /* PROCESSOR_ARCHITECTURE_SHX
+                                        * (Super-H) */
+  MD_CPU_ARCHITECTURE_ARM       =  5,  /* PROCESSOR_ARCHITECTURE_ARM */
+  MD_CPU_ARCHITECTURE_IA64      =  6,  /* PROCESSOR_ARCHITECTURE_IA64 */
+  MD_CPU_ARCHITECTURE_ALPHA64   =  7,  /* PROCESSOR_ARCHITECTURE_ALPHA64 */
+  MD_CPU_ARCHITECTURE_MSIL      =  8,  /* PROCESSOR_ARCHITECTURE_MSIL
+                                        * (Microsoft Intermediate Language) */
+  MD_CPU_ARCHITECTURE_AMD64     =  9,  /* PROCESSOR_ARCHITECTURE_AMD64 */
+  MD_CPU_ARCHITECTURE_X86_WIN64 = 10,
+      /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */
+  MD_CPU_ARCHITECTURE_SPARC     = 0x8001, /* Breakpad-defined value for SPARC */
+  MD_CPU_ARCHITECTURE_UNKNOWN   = 0xffff  /* PROCESSOR_ARCHITECTURE_UNKNOWN */
+} MDCPUArchitecture;
+
+/* For (MDRawSystemInfo).platform_id: */
+typedef enum {
+  MD_OS_WIN32S        = 0,  /* VER_PLATFORM_WIN32s (Windows 3.1) */
+  MD_OS_WIN32_WINDOWS = 1,  /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */
+  MD_OS_WIN32_NT      = 2,  /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */
+  MD_OS_WIN32_CE      = 3,  /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH
+                             * (Windows CE, Windows Mobile, "Handheld") */
+
+  /* The following values are Breakpad-defined. */
+  MD_OS_UNIX          = 0x8000,  /* Generic Unix-ish */
+  MD_OS_MAC_OS_X      = 0x8101,  /* Mac OS X/Darwin */
+  MD_OS_LINUX         = 0x8201,  /* Linux */
+  MD_OS_SOLARIS       = 0x8202   /* Solaris */
+} MDOSPlatform;
+
+
+typedef struct {
+  u_int32_t size_of_info;  /* Length of entire MDRawMiscInfo structure. */
+  u_int32_t flags1;
+
+  /* The next field is only valid if flags1 contains
+   * MD_MISCINFO_FLAGS1_PROCESS_ID. */
+  u_int32_t process_id;
+
+  /* The next 3 fields are only valid if flags1 contains
+   * MD_MISCINFO_FLAGS1_PROCESS_TIMES. */
+  u_int32_t process_create_time;  /* time_t process started */
+  u_int32_t process_user_time;    /* seconds of user CPU time */
+  u_int32_t process_kernel_time;  /* seconds of kernel CPU time */
+
+  /* The following fields are not present in MINIDUMP_MISC_INFO but are
+   * in MINIDUMP_MISC_INFO_2.  When this struct is populated, these values
+   * may not be set.  Use flags1 or sizeOfInfo to determine whether these
+   * values are present.  These are only valid when flags1 contains
+   * MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO. */
+  u_int32_t processor_max_mhz;
+  u_int32_t processor_current_mhz;
+  u_int32_t processor_mhz_limit;
+  u_int32_t processor_max_idle_state;
+  u_int32_t processor_current_idle_state;
+} MDRawMiscInfo;  /* MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO2 */
+
+#define MD_MISCINFO_SIZE 24
+#define MD_MISCINFO2_SIZE 44
+
+/* For (MDRawMiscInfo).flags1.  These values indicate which fields in the
+ * MDRawMiscInfoStructure are valid. */
+typedef enum {
+  MD_MISCINFO_FLAGS1_PROCESS_ID           = 0x00000001,
+      /* MINIDUMP_MISC1_PROCESS_ID */
+  MD_MISCINFO_FLAGS1_PROCESS_TIMES        = 0x00000002,
+      /* MINIDUMP_MISC1_PROCESS_TIMES */
+  MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO = 0x00000004
+      /* MINIDUMP_MISC1_PROCESSOR_POWER_INFO */
+} MDMiscInfoFlags1;
+
+
+/*
+ * Breakpad extension types
+ */
+
+
+typedef struct {
+  /* validity is a bitmask with values from MDBreakpadInfoValidity, indicating
+   * which of the other fields in the structure are valid. */
+  u_int32_t validity;
+
+  /* Thread ID of the handler thread.  dump_thread_id should correspond to
+   * the thread_id of an MDRawThread in the minidump's MDRawThreadList if
+   * a dedicated thread in that list was used to produce the minidump.  If
+   * the MDRawThreadList does not contain a dedicated thread used to produce
+   * the minidump, this field should be set to 0 and the validity field
+   * must not contain MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID. */
+  u_int32_t dump_thread_id;
+
+  /* Thread ID of the thread that requested the minidump be produced.  As
+   * with dump_thread_id, requesting_thread_id should correspond to the
+   * thread_id of an MDRawThread in the minidump's MDRawThreadList.  For
+   * minidumps produced as a result of an exception, requesting_thread_id
+   * will be the same as the MDRawExceptionStream's thread_id field.  For
+   * minidumps produced "manually" at the program's request,
+   * requesting_thread_id will indicate which thread caused the dump to be
+   * written.  If the minidump was produced at the request of something
+   * other than a thread in the MDRawThreadList, this field should be set
+   * to 0 and the validity field must not contain
+   * MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID. */
+  u_int32_t requesting_thread_id;
+} MDRawBreakpadInfo;
+
+/* For (MDRawBreakpadInfo).validity: */
+typedef enum {
+  /* When set, the dump_thread_id field is valid. */
+  MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID       = 1 << 0,
+
+  /* When set, the requesting_thread_id field is valid. */
+  MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID = 1 << 1
+} MDBreakpadInfoValidity;
+
+typedef struct {
+  /* expression, function, and file are 0-terminated UTF-16 strings.  They
+   * may be truncated if necessary, but should always be 0-terminated when
+   * written to a file.
+   * Fixed-length strings are used because MiniDumpWriteDump doesn't offer
+   * a way for user streams to point to arbitrary RVAs for strings. */
+  u_int16_t expression[128];  /* Assertion that failed... */
+  u_int16_t function[128];    /* ...within this function... */
+  u_int16_t file[128];        /* ...in this file... */
+  u_int32_t line;             /* ...at this line. */
+  u_int32_t type;
+} MDRawAssertionInfo;
+
+/* For (MDRawAssertionInfo).type: */
+typedef enum {
+  MD_ASSERTION_INFO_TYPE_UNKNOWN = 0,
+
+  /* Used for assertions that would be raised by the MSVC CRT but are
+   * directed to an invalid parameter handler instead. */
+  MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER,
+
+  /* Used for assertions that would be raised by the MSVC CRT but are
+   * directed to a pure virtual call handler instead. */
+  MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL
+} MDAssertionInfoData;
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif  /* _MSC_VER */
+
+
+#endif  /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ */
diff --git a/third_party/breakpad/src/processor/scoped_ptr.h b/third_party/breakpad/src/processor/scoped_ptr.h
index 62e1abb..0d4f7fd 100644
--- a/third_party/breakpad/src/processor/scoped_ptr.h
+++ b/third_party/breakpad/src/processor/scoped_ptr.h
@@ -1,335 +1,335 @@
-//  (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.

-//  Copyright (c) 2001, 2002 Peter Dimov

-//

-//  Permission to copy, use, modify, sell and distribute this software

-//  is granted provided this copyright notice appears in all copies.

-//  This software is provided "as is" without express or implied

-//  warranty, and with no claim as to its suitability for any purpose.

-//

-//  See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.

-//

-

-//  scoped_ptr mimics a built-in pointer except that it guarantees deletion

-//  of the object pointed to, either on destruction of the scoped_ptr or via

-//  an explicit reset(). scoped_ptr is a simple solution for simple needs;

-//  use shared_ptr or std::auto_ptr if your needs are more complex.

-

-//  *** NOTE ***

-//  If your scoped_ptr is a class member of class FOO pointing to a 

-//  forward declared type BAR (as shown below), then you MUST use a non-inlined 

-//  version of the destructor.  The destructor of a scoped_ptr (called from

-//  FOO's destructor) must have a complete definition of BAR in order to 

-//  destroy it.  Example:

-//

-//  -- foo.h --

-//  class BAR;

-//

-//  class FOO {

-//   public:

-//    FOO();

-//    ~FOO();  // Required for sources that instantiate class FOO to compile!

-//    

-//   private:

-//    scoped_ptr<BAR> bar_;

-//  };

-//

-//  -- foo.cc --

-//  #include "foo.h"

-//  FOO::~FOO() {} // Empty, but must be non-inlined to FOO's class definition.

-

-//  scoped_ptr_malloc added by Google

-//  When one of these goes out of scope, instead of doing a delete or

-//  delete[], it calls free().  scoped_ptr_malloc<char> is likely to see

-//  much more use than any other specializations.

-

-//  release() added by Google

-//  Use this to conditionally transfer ownership of a heap-allocated object

-//  to the caller, usually on method success.

-

-#ifndef PROCESSOR_SCOPED_PTR_H__

-#define PROCESSOR_SCOPED_PTR_H__

-

-#include <cstddef>            // for std::ptrdiff_t

-#include <assert.h>           // for assert

-#include <stdlib.h>           // for free() decl

-

-namespace google_breakpad {

-

-template <typename T>

-class scoped_ptr {

- private:

-

-  T* ptr;

-

-  scoped_ptr(scoped_ptr const &);

-  scoped_ptr & operator=(scoped_ptr const &);

-

- public:

-

-  typedef T element_type;

-

-  explicit scoped_ptr(T* p = 0): ptr(p) {}

-

-  ~scoped_ptr() {

-    typedef char type_must_be_complete[sizeof(T)];

-    delete ptr;

-  }

-

-  void reset(T* p = 0) {

-    typedef char type_must_be_complete[sizeof(T)];

-

-    if (ptr != p) {

-      delete ptr;

-      ptr = p;

-    }

-  }

-

-  T& operator*() const {

-    assert(ptr != 0);

-    return *ptr;

-  }

-

-  T* operator->() const  {

-    assert(ptr != 0);

-    return ptr;

-  }

-

-  bool operator==(T* p) const {

-    return ptr == p;

-  }

-

-  bool operator!=(T* p) const {

-    return ptr != p;

-  }

-

-  T* get() const  {

-    return ptr;

-  }

-

-  void swap(scoped_ptr & b) {

-    T* tmp = b.ptr;

-    b.ptr = ptr;

-    ptr = tmp;

-  }

-

-  T* release() {

-    T* tmp = ptr;

-    ptr = 0;

-    return tmp;

-  }

-

- private:

-

-  // no reason to use these: each scoped_ptr should have its own object

-  template <typename U> bool operator==(scoped_ptr<U> const& p) const;

-  template <typename U> bool operator!=(scoped_ptr<U> const& p) const;

-};

-

-template<typename T> inline

-void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {

-  a.swap(b);

-}

-

-template<typename T> inline

-bool operator==(T* p, const scoped_ptr<T>& b) {

-  return p == b.get();

-}

-

-template<typename T> inline

-bool operator!=(T* p, const scoped_ptr<T>& b) {

-  return p != b.get();

-}

-

-//  scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to

-//  is guaranteed, either on destruction of the scoped_array or via an explicit

-//  reset(). Use shared_array or std::vector if your needs are more complex.

-

-template<typename T>

-class scoped_array {

- private:

-

-  T* ptr;

-

-  scoped_array(scoped_array const &);

-  scoped_array & operator=(scoped_array const &);

-

- public:

-

-  typedef T element_type;

-

-  explicit scoped_array(T* p = 0) : ptr(p) {}

-

-  ~scoped_array() {

-    typedef char type_must_be_complete[sizeof(T)];

-    delete[] ptr;

-  }

-

-  void reset(T* p = 0) {

-    typedef char type_must_be_complete[sizeof(T)];

-

-    if (ptr != p) {

-      delete [] ptr;

-      ptr = p;

-    }

-  }

-

-  T& operator[](std::ptrdiff_t i) const {

-    assert(ptr != 0);

-    assert(i >= 0);

-    return ptr[i];

-  }

-

-  bool operator==(T* p) const {

-    return ptr == p;

-  }

-

-  bool operator!=(T* p) const {

-    return ptr != p;

-  }

-

-  T* get() const {

-    return ptr;

-  }

-

-  void swap(scoped_array & b) {

-    T* tmp = b.ptr;

-    b.ptr = ptr;

-    ptr = tmp;

-  }

-

-  T* release() {

-    T* tmp = ptr;

-    ptr = 0;

-    return tmp;

-  }

-

- private:

-

-  // no reason to use these: each scoped_array should have its own object

-  template <typename U> bool operator==(scoped_array<U> const& p) const;

-  template <typename U> bool operator!=(scoped_array<U> const& p) const;

-};

-

-template<class T> inline

-void swap(scoped_array<T>& a, scoped_array<T>& b) {

-  a.swap(b);

-}

-

-template<typename T> inline

-bool operator==(T* p, const scoped_array<T>& b) {

-  return p == b.get();

-}

-

-template<typename T> inline

-bool operator!=(T* p, const scoped_array<T>& b) {

-  return p != b.get();

-}

-

-

-// This class wraps the c library function free() in a class that can be

-// passed as a template argument to scoped_ptr_malloc below.

-class ScopedPtrMallocFree {

- public:

-  inline void operator()(void* x) const {

-    free(x);

-  }

-};

-

-// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a

-// second template argument, the functor used to free the object.

-

-template<typename T, typename FreeProc = ScopedPtrMallocFree>

-class scoped_ptr_malloc {

- private:

-

-  T* ptr;

-

-  scoped_ptr_malloc(scoped_ptr_malloc const &);

-  scoped_ptr_malloc & operator=(scoped_ptr_malloc const &);

-

- public:

-

-  typedef T element_type;

-

-  explicit scoped_ptr_malloc(T* p = 0): ptr(p) {}

-

-  ~scoped_ptr_malloc() {

-    typedef char type_must_be_complete[sizeof(T)];

-    free_((void*) ptr);

-  }

-

-  void reset(T* p = 0) {

-    typedef char type_must_be_complete[sizeof(T)];

-

-    if (ptr != p) {

-      free_((void*) ptr);

-      ptr = p;

-    }

-  }

-

-  T& operator*() const {

-    assert(ptr != 0);

-    return *ptr;

-  }

-

-  T* operator->() const {

-    assert(ptr != 0);

-    return ptr;

-  }

-

-  bool operator==(T* p) const {

-    return ptr == p;

-  }

-

-  bool operator!=(T* p) const {

-    return ptr != p;

-  }

-

-  T* get() const {

-    return ptr;

-  }

-

-  void swap(scoped_ptr_malloc & b) {

-    T* tmp = b.ptr;

-    b.ptr = ptr;

-    ptr = tmp;

-  }

-

-  T* release() {

-    T* tmp = ptr;

-    ptr = 0;

-    return tmp;

-  }

-

- private:

-

-  // no reason to use these: each scoped_ptr_malloc should have its own object

-  template <typename U, typename GP>

-  bool operator==(scoped_ptr_malloc<U, GP> const& p) const;

-  template <typename U, typename GP>

-  bool operator!=(scoped_ptr_malloc<U, GP> const& p) const;

-

-  static FreeProc const free_;

-};

-

-template<typename T, typename FP>

-FP const scoped_ptr_malloc<T,FP>::free_ = FP();

-

-template<typename T, typename FP> inline

-void swap(scoped_ptr_malloc<T,FP>& a, scoped_ptr_malloc<T,FP>& b) {

-  a.swap(b);

-}

-

-template<typename T, typename FP> inline

-bool operator==(T* p, const scoped_ptr_malloc<T,FP>& b) {

-  return p == b.get();

-}

-

-template<typename T, typename FP> inline

-bool operator!=(T* p, const scoped_ptr_malloc<T,FP>& b) {

-  return p != b.get();

-}

-

-}  // namespace google_breakpad

-

-#endif  // PROCESSOR_SCOPED_PTR_H__

+//  (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
+//  Copyright (c) 2001, 2002 Peter Dimov
+//
+//  Permission to copy, use, modify, sell and distribute this software
+//  is granted provided this copyright notice appears in all copies.
+//  This software is provided "as is" without express or implied
+//  warranty, and with no claim as to its suitability for any purpose.
+//
+//  See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation.
+//
+
+//  scoped_ptr mimics a built-in pointer except that it guarantees deletion
+//  of the object pointed to, either on destruction of the scoped_ptr or via
+//  an explicit reset(). scoped_ptr is a simple solution for simple needs;
+//  use shared_ptr or std::auto_ptr if your needs are more complex.
+
+//  *** NOTE ***
+//  If your scoped_ptr is a class member of class FOO pointing to a 
+//  forward declared type BAR (as shown below), then you MUST use a non-inlined 
+//  version of the destructor.  The destructor of a scoped_ptr (called from
+//  FOO's destructor) must have a complete definition of BAR in order to 
+//  destroy it.  Example:
+//
+//  -- foo.h --
+//  class BAR;
+//
+//  class FOO {
+//   public:
+//    FOO();
+//    ~FOO();  // Required for sources that instantiate class FOO to compile!
+//    
+//   private:
+//    scoped_ptr<BAR> bar_;
+//  };
+//
+//  -- foo.cc --
+//  #include "foo.h"
+//  FOO::~FOO() {} // Empty, but must be non-inlined to FOO's class definition.
+
+//  scoped_ptr_malloc added by Google
+//  When one of these goes out of scope, instead of doing a delete or
+//  delete[], it calls free().  scoped_ptr_malloc<char> is likely to see
+//  much more use than any other specializations.
+
+//  release() added by Google
+//  Use this to conditionally transfer ownership of a heap-allocated object
+//  to the caller, usually on method success.
+
+#ifndef PROCESSOR_SCOPED_PTR_H__
+#define PROCESSOR_SCOPED_PTR_H__
+
+#include <cstddef>            // for std::ptrdiff_t
+#include <assert.h>           // for assert
+#include <stdlib.h>           // for free() decl
+
+namespace google_breakpad {
+
+template <typename T>
+class scoped_ptr {
+ private:
+
+  T* ptr;
+
+  scoped_ptr(scoped_ptr const &);
+  scoped_ptr & operator=(scoped_ptr const &);
+
+ public:
+
+  typedef T element_type;
+
+  explicit scoped_ptr(T* p = 0): ptr(p) {}
+
+  ~scoped_ptr() {
+    typedef char type_must_be_complete[sizeof(T)];
+    delete ptr;
+  }
+
+  void reset(T* p = 0) {
+    typedef char type_must_be_complete[sizeof(T)];
+
+    if (ptr != p) {
+      delete ptr;
+      ptr = p;
+    }
+  }
+
+  T& operator*() const {
+    assert(ptr != 0);
+    return *ptr;
+  }
+
+  T* operator->() const  {
+    assert(ptr != 0);
+    return ptr;
+  }
+
+  bool operator==(T* p) const {
+    return ptr == p;
+  }
+
+  bool operator!=(T* p) const {
+    return ptr != p;
+  }
+
+  T* get() const  {
+    return ptr;
+  }
+
+  void swap(scoped_ptr & b) {
+    T* tmp = b.ptr;
+    b.ptr = ptr;
+    ptr = tmp;
+  }
+
+  T* release() {
+    T* tmp = ptr;
+    ptr = 0;
+    return tmp;
+  }
+
+ private:
+
+  // no reason to use these: each scoped_ptr should have its own object
+  template <typename U> bool operator==(scoped_ptr<U> const& p) const;
+  template <typename U> bool operator!=(scoped_ptr<U> const& p) const;
+};
+
+template<typename T> inline
+void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
+  a.swap(b);
+}
+
+template<typename T> inline
+bool operator==(T* p, const scoped_ptr<T>& b) {
+  return p == b.get();
+}
+
+template<typename T> inline
+bool operator!=(T* p, const scoped_ptr<T>& b) {
+  return p != b.get();
+}
+
+//  scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to
+//  is guaranteed, either on destruction of the scoped_array or via an explicit
+//  reset(). Use shared_array or std::vector if your needs are more complex.
+
+template<typename T>
+class scoped_array {
+ private:
+
+  T* ptr;
+
+  scoped_array(scoped_array const &);
+  scoped_array & operator=(scoped_array const &);
+
+ public:
+
+  typedef T element_type;
+
+  explicit scoped_array(T* p = 0) : ptr(p) {}
+
+  ~scoped_array() {
+    typedef char type_must_be_complete[sizeof(T)];
+    delete[] ptr;
+  }
+
+  void reset(T* p = 0) {
+    typedef char type_must_be_complete[sizeof(T)];
+
+    if (ptr != p) {
+      delete [] ptr;
+      ptr = p;
+    }
+  }
+
+  T& operator[](std::ptrdiff_t i) const {
+    assert(ptr != 0);
+    assert(i >= 0);
+    return ptr[i];
+  }
+
+  bool operator==(T* p) const {
+    return ptr == p;
+  }
+
+  bool operator!=(T* p) const {
+    return ptr != p;
+  }
+
+  T* get() const {
+    return ptr;
+  }
+
+  void swap(scoped_array & b) {
+    T* tmp = b.ptr;
+    b.ptr = ptr;
+    ptr = tmp;
+  }
+
+  T* release() {
+    T* tmp = ptr;
+    ptr = 0;
+    return tmp;
+  }
+
+ private:
+
+  // no reason to use these: each scoped_array should have its own object
+  template <typename U> bool operator==(scoped_array<U> const& p) const;
+  template <typename U> bool operator!=(scoped_array<U> const& p) const;
+};
+
+template<class T> inline
+void swap(scoped_array<T>& a, scoped_array<T>& b) {
+  a.swap(b);
+}
+
+template<typename T> inline
+bool operator==(T* p, const scoped_array<T>& b) {
+  return p == b.get();
+}
+
+template<typename T> inline
+bool operator!=(T* p, const scoped_array<T>& b) {
+  return p != b.get();
+}
+
+
+// This class wraps the c library function free() in a class that can be
+// passed as a template argument to scoped_ptr_malloc below.
+class ScopedPtrMallocFree {
+ public:
+  inline void operator()(void* x) const {
+    free(x);
+  }
+};
+
+// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
+// second template argument, the functor used to free the object.
+
+template<typename T, typename FreeProc = ScopedPtrMallocFree>
+class scoped_ptr_malloc {
+ private:
+
+  T* ptr;
+
+  scoped_ptr_malloc(scoped_ptr_malloc const &);
+  scoped_ptr_malloc & operator=(scoped_ptr_malloc const &);
+
+ public:
+
+  typedef T element_type;
+
+  explicit scoped_ptr_malloc(T* p = 0): ptr(p) {}
+
+  ~scoped_ptr_malloc() {
+    typedef char type_must_be_complete[sizeof(T)];
+    free_((void*) ptr);
+  }
+
+  void reset(T* p = 0) {
+    typedef char type_must_be_complete[sizeof(T)];
+
+    if (ptr != p) {
+      free_((void*) ptr);
+      ptr = p;
+    }
+  }
+
+  T& operator*() const {
+    assert(ptr != 0);
+    return *ptr;
+  }
+
+  T* operator->() const {
+    assert(ptr != 0);
+    return ptr;
+  }
+
+  bool operator==(T* p) const {
+    return ptr == p;
+  }
+
+  bool operator!=(T* p) const {
+    return ptr != p;
+  }
+
+  T* get() const {
+    return ptr;
+  }
+
+  void swap(scoped_ptr_malloc & b) {
+    T* tmp = b.ptr;
+    b.ptr = ptr;
+    ptr = tmp;
+  }
+
+  T* release() {
+    T* tmp = ptr;
+    ptr = 0;
+    return tmp;
+  }
+
+ private:
+
+  // no reason to use these: each scoped_ptr_malloc should have its own object
+  template <typename U, typename GP>
+  bool operator==(scoped_ptr_malloc<U, GP> const& p) const;
+  template <typename U, typename GP>
+  bool operator!=(scoped_ptr_malloc<U, GP> const& p) const;
+
+  static FreeProc const free_;
+};
+
+template<typename T, typename FP>
+FP const scoped_ptr_malloc<T,FP>::free_ = FP();
+
+template<typename T, typename FP> inline
+void swap(scoped_ptr_malloc<T,FP>& a, scoped_ptr_malloc<T,FP>& b) {
+  a.swap(b);
+}
+
+template<typename T, typename FP> inline
+bool operator==(T* p, const scoped_ptr_malloc<T,FP>& b) {
+  return p == b.get();
+}
+
+template<typename T, typename FP> inline
+bool operator!=(T* p, const scoped_ptr_malloc<T,FP>& b) {
+  return p != b.get();
+}
+
+}  // namespace google_breakpad
+
+#endif  // PROCESSOR_SCOPED_PTR_H__
diff --git a/third_party/build.scons b/third_party/build.scons
index 67304b3..efe82c6 100644
--- a/third_party/build.scons
+++ b/third_party/build.scons
@@ -1,29 +1,29 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-subdirs = [

-    'breakpad',

-    'gtest',

-    'lzma',

-    'minicrt',

-    ]

-

-for dir in subdirs:

-  env.BuildSConscript(dir)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+subdirs = [
+    'breakpad',
+    'gtest',
+    'lzma',
+    'minicrt',
+    ]
+
+for dir in subdirs:
+  env.BuildSConscript(dir)
diff --git a/third_party/c99/include/inttypes.h b/third_party/c99/include/inttypes.h
index 6bef899..43f2034 100644
--- a/third_party/c99/include/inttypes.h
+++ b/third_party/c99/include/inttypes.h
@@ -1,20 +1,20 @@
-//

-// Posix integer types, defined in terms of native Windows types.

-

-#ifndef __INTTYPES_H_

-#define __INTTYPES_H_

-

-typedef __int8 int8_t;

-typedef __int16 int16_t;

-typedef __int32 int32_t;

-typedef __int64 int64_t;

-typedef unsigned __int8 uint8_t;

-typedef unsigned __int16 uint16_t;

-typedef unsigned __int32 uint32_t;

-typedef unsigned __int64 uint64_t;

-typedef uint8_t u_int8_t;

-typedef uint16_t u_int16_t;

-typedef uint32_t u_int32_t;

-typedef uint64_t u_int64_t;

-

-#endif  // __INTTYPES_H_

+//
+// Posix integer types, defined in terms of native Windows types.
+
+#ifndef __INTTYPES_H_
+#define __INTTYPES_H_
+
+typedef __int8 int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef uint8_t u_int8_t;
+typedef uint16_t u_int16_t;
+typedef uint32_t u_int32_t;
+typedef uint64_t u_int64_t;
+
+#endif  // __INTTYPES_H_
diff --git a/third_party/chrome/base/basictypes.h b/third_party/chrome/base/basictypes.h
index c188dbd..46b8364 100644
--- a/third_party/chrome/base/basictypes.h
+++ b/third_party/chrome/base/basictypes.h
@@ -1,396 +1,396 @@
-// Copyright (c) 2006-2008 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.

-

-#ifndef BASE_BASICTYPES_H_

-#define BASE_BASICTYPES_H_

-

-#include <assert.h>         // for use with down_cast<>

-#include <limits.h>         // So we can set the bounds of our types

-#include <stddef.h>         // For size_t

-#include <string.h>         // for memcpy

-

-#include "base/port.h"    // Types that only need exist on certain systems

-

-#ifndef COMPILER_MSVC

-// stdint.h is part of C99 but MSVC doesn't have it.

-#include <stdint.h>         // For intptr_t.

-#endif

-

-typedef signed char         schar;

-typedef signed char         int8;

-typedef short               int16;

-// TODO(mbelshe) Remove these type guards.  These are

-//               temporary to avoid conflicts with npapi.h.

-#ifndef _INT32

-#define _INT32

-typedef int                 int32;

-#endif

-typedef long long           int64;

-

-// NOTE: unsigned types are DANGEROUS in loops and other arithmetical

-// places.  Use the signed types unless your variable represents a bit

-// pattern (eg a hash value) or you really need the extra bit.  Do NOT

-// use 'unsigned' to express "this value should always be positive";

-// use assertions for this.

-

-typedef unsigned char      uint8;

-typedef unsigned short     uint16;

-// TODO(mbelshe) Remove these type guards.  These are

-//               temporary to avoid conflicts with npapi.h.

-#ifndef _UINT32

-#define _UINT32

-typedef unsigned int       uint32;

-#endif

-typedef unsigned long long uint64;

-

-// A type to represent a Unicode code-point value. As of Unicode 4.0,

-// such values require up to 21 bits.

-// (For type-checking on pointers, make this explicitly signed,

-// and it should always be the signed version of whatever int32 is.)

-typedef signed int         char32;

-

-const uint8  kuint8max  = (( uint8) 0xFF);

-const uint16 kuint16max = ((uint16) 0xFFFF);

-const uint32 kuint32max = ((uint32) 0xFFFFFFFF);

-const uint64 kuint64max = ((uint64) GG_LONGLONG(0xFFFFFFFFFFFFFFFF));

-const  int8  kint8min   = ((  int8) 0x80);

-const  int8  kint8max   = ((  int8) 0x7F);

-const  int16 kint16min  = (( int16) 0x8000);

-const  int16 kint16max  = (( int16) 0x7FFF);

-const  int32 kint32min  = (( int32) 0x80000000);

-const  int32 kint32max  = (( int32) 0x7FFFFFFF);

-const  int64 kint64min  = (( int64) GG_LONGLONG(0x8000000000000000));

-const  int64 kint64max  = (( int64) GG_LONGLONG(0x7FFFFFFFFFFFFFFF));

-

-// id for odp categories

-typedef uint32 CatId;

-const CatId kIllegalCatId = static_cast<CatId>(0);

-

-typedef uint32 TermId;

-const TermId kIllegalTermId = static_cast<TermId>(0);

-

-typedef uint32 HostId;

-const HostId kIllegalHostId = static_cast<HostId>(0);

-

-typedef uint32 DomainId;

-const DomainId kIllegalDomainId = static_cast<DomainId>(0);

-

-// A macro to disallow the copy constructor and operator= functions

-// This should be used in the private: declarations for a class

-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \

-  TypeName(const TypeName&);               \

-  void operator=(const TypeName&)

-

-// An older, deprecated, politically incorrect name for the above.

-#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName)

-

-// A macro to disallow all the implicit constructors, namely the

-// default constructor, copy constructor and operator= functions.

-//

-// This should be used in the private: declarations for a class

-// that wants to prevent anyone from instantiating it. This is

-// especially useful for classes containing only static methods.

-#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \

-  TypeName();                                    \

-  DISALLOW_COPY_AND_ASSIGN(TypeName)

-

-// The arraysize(arr) macro returns the # of elements in an array arr.

-// The expression is a compile-time constant, and therefore can be

-// used in defining new arrays, for example.  If you use arraysize on

-// a pointer by mistake, you will get a compile-time error.

-//

-// One caveat is that arraysize() doesn't accept any array of an

-// anonymous type or a type defined inside a function.  In these rare

-// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below.  This is

-// due to a limitation in C++'s template system.  The limitation might

-// eventually be removed, but it hasn't happened yet.

-

-// This template function declaration is used in defining arraysize.

-// Note that the function doesn't need an implementation, as we only

-// use its type.

-template <typename T, size_t N>

-char (&ArraySizeHelper(T (&array)[N]))[N];

-

-// That gcc wants both of these prototypes seems mysterious. VC, for

-// its part, can't decide which to use (another mystery). Matching of

-// template overloads: the final frontier.

-#ifndef _MSC_VER

-template <typename T, size_t N>

-char (&ArraySizeHelper(const T (&array)[N]))[N];

-#endif

-

-#define arraysize(array) (sizeof(ArraySizeHelper(array)))

-

-// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,

-// but can be used on anonymous types or types defined inside

-// functions.  It's less safe than arraysize as it accepts some

-// (although not all) pointers.  Therefore, you should use arraysize

-// whenever possible.

-//

-// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type

-// size_t.

-//

-// ARRAYSIZE_UNSAFE catches a few type errors.  If you see a compiler error

-//

-//   "warning: division by zero in ..."

-//

-// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.

-// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.

-//

-// The following comments are on the implementation details, and can

-// be ignored by the users.

-//

-// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in

-// the array) and sizeof(*(arr)) (the # of bytes in one array

-// element).  If the former is divisible by the latter, perhaps arr is

-// indeed an array, in which case the division result is the # of

-// elements in the array.  Otherwise, arr cannot possibly be an array,

-// and we generate a compiler error to prevent the code from

-// compiling.

-//

-// Since the size of bool is implementation-defined, we need to cast

-// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final

-// result has type size_t.

-//

-// This macro is not perfect as it wrongfully accepts certain

-// pointers, namely where the pointer size is divisible by the pointee

-// size.  Since all our code has to go through a 32-bit compiler,

-// where a pointer is 4 bytes, this means all pointers to a type whose

-// size is 3 or greater than 4 will be (righteously) rejected.

-

-#define ARRAYSIZE_UNSAFE(a) \

-  ((sizeof(a) / sizeof(*(a))) / \

-   static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))

-

-

-// Use implicit_cast as a safe version of static_cast or const_cast

-// for upcasting in the type hierarchy (i.e. casting a pointer to Foo

-// to a pointer to SuperclassOfFoo or casting a pointer to Foo to

-// a const pointer to Foo).

-// When you use implicit_cast, the compiler checks that the cast is safe.

-// Such explicit implicit_casts are necessary in surprisingly many

-// situations where C++ demands an exact type match instead of an

-// argument type convertable to a target type.

-//

-// The From type can be inferred, so the preferred syntax for using

-// implicit_cast is the same as for static_cast etc.:

-//

-//   implicit_cast<ToType>(expr)

-//

-// implicit_cast would have been part of the C++ standard library,

-// but the proposal was submitted too late.  It will probably make

-// its way into the language in the future.

-template<typename To, typename From>

-inline To implicit_cast(From const &f) {

-  return f;

-}

-

-

-// When you upcast (that is, cast a pointer from type Foo to type

-// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts

-// always succeed.  When you downcast (that is, cast a pointer from

-// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because

-// how do you know the pointer is really of type SubclassOfFoo?  It

-// could be a bare Foo, or of type DifferentSubclassOfFoo.  Thus,

-// when you downcast, you should use this macro.  In debug mode, we

-// use dynamic_cast<> to double-check the downcast is legal (we die

-// if it's not).  In normal mode, we do the efficient static_cast<>

-// instead.  Thus, it's important to test in debug mode to make sure

-// the cast is legal!

-//    This is the only place in the code we should use dynamic_cast<>.

-// In particular, you SHOULDN'T be using dynamic_cast<> in order to

-// do RTTI (eg code like this:

-//    if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);

-//    if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);

-// You should design the code some other way not to need this.

-

-template<typename To, typename From>     // use like this: down_cast<T*>(foo);

-inline To down_cast(From* f) {                   // so we only accept pointers

-  // Ensures that To is a sub-type of From *.  This test is here only

-  // for compile-time type checking, and has no overhead in an

-  // optimized build at run-time, as it will be optimized away

-  // completely.

-  if (false) {

-    implicit_cast<From*, To>(0);

-  }

-

-  assert(f == NULL || dynamic_cast<To>(f) != NULL);  // RTTI: debug mode only!

-  return static_cast<To>(f);

-}

-

-// The COMPILE_ASSERT macro can be used to verify that a compile time

-// expression is true. For example, you could use it to verify the

-// size of a static array:

-//

-//   COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES,

-//                  content_type_names_incorrect_size);

-//

-// or to make sure a struct is smaller than a certain size:

-//

-//   COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);

-//

-// The second argument to the macro is the name of the variable. If

-// the expression is false, most compilers will issue a warning/error

-// containing the name of the variable.

-

-template <bool>

-struct CompileAssert {

-};

-

-#undef COMPILE_ASSERT

-#define COMPILE_ASSERT(expr, msg) \

-  typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]

-

-// Implementation details of COMPILE_ASSERT:

-//

-// - COMPILE_ASSERT works by defining an array type that has -1

-//   elements (and thus is invalid) when the expression is false.

-//

-// - The simpler definition

-//

-//     #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]

-//

-//   does not work, as gcc supports variable-length arrays whose sizes

-//   are determined at run-time (this is gcc's extension and not part

-//   of the C++ standard).  As a result, gcc fails to reject the

-//   following code with the simple definition:

-//

-//     int foo;

-//     COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is

-//                               // not a compile-time constant.

-//

-// - By using the type CompileAssert<(bool(expr))>, we ensures that

-//   expr is a compile-time constant.  (Template arguments must be

-//   determined at compile-time.)

-//

-// - The outter parentheses in CompileAssert<(bool(expr))> are necessary

-//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written

-//

-//     CompileAssert<bool(expr)>

-//

-//   instead, these compilers will refuse to compile

-//

-//     COMPILE_ASSERT(5 > 0, some_message);

-//

-//   (They seem to think the ">" in "5 > 0" marks the end of the

-//   template argument list.)

-//

-// - The array size is (bool(expr) ? 1 : -1), instead of simply

-//

-//     ((expr) ? 1 : -1).

-//

-//   This is to avoid running into a bug in MS VC 7.1, which

-//   causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.

-

-

-// MetatagId refers to metatag-id that we assign to

-// each metatag <name, value> pair..

-typedef uint32 MetatagId;

-

-// Argument type used in interfaces that can optionally take ownership

-// of a passed in argument.  If TAKE_OWNERSHIP is passed, the called

-// object takes ownership of the argument.  Otherwise it does not.

-enum Ownership {

-  DO_NOT_TAKE_OWNERSHIP,

-  TAKE_OWNERSHIP

-};

-

-// Use these as the mlock_bytes parameter to MLock and MLockGeneral

-enum { MLOCK_ALL = -1, MLOCK_NONE = 0 };

-

-// Helper routine to avoid buggy code like the following:

-//      if (pos + N < end) ...

-// If pos is large enough, "pos + N" may overflow.  For example,

-// pos==0xfffff000 and N==1MB.

-//

-// PointerRangeSize(a,b) returns the size of the range [a,b-1]

-inline size_t PointerRangeSize(const char* start, const char* end) {

-  assert(start <= end);

-  return end - start;

-}

-

-// bit_cast<Dest,Source> is a template function that implements the

-// equivalent of "*reinterpret_cast<Dest*>(&source)".  We need this in

-// very low-level functions like the protobuf library and fast math

-// support.

-//

-//   float f = 3.14159265358979;

-//   int i = bit_cast<int32>(f);

-//   // i = 0x40490fdb

-//

-// The classical address-casting method is:

-//

-//   // WRONG

-//   float f = 3.14159265358979;            // WRONG

-//   int i = * reinterpret_cast<int*>(&f);  // WRONG

-//

-// The address-casting method actually produces undefined behavior

-// according to ISO C++ specification section 3.10 -15 -.  Roughly, this

-// section says: if an object in memory has one type, and a program

-// accesses it with a different type, then the result is undefined

-// behavior for most values of "different type".

-//

-// This is true for any cast syntax, either *(int*)&f or

-// *reinterpret_cast<int*>(&f).  And it is particularly true for

-// conversions betweeen integral lvalues and floating-point lvalues.

-//

-// The purpose of 3.10 -15- is to allow optimizing compilers to assume

-// that expressions with different types refer to different memory.  gcc

-// 4.0.1 has an optimizer that takes advantage of this.  So a

-// non-conforming program quietly produces wildly incorrect output.

-//

-// The problem is not the use of reinterpret_cast.  The problem is type

-// punning: holding an object in memory of one type and reading its bits

-// back using a different type.

-//

-// The C++ standard is more subtle and complex than this, but that

-// is the basic idea.

-//

-// Anyways ...

-//

-// bit_cast<> calls memcpy() which is blessed by the standard,

-// especially by the example in section 3.9 .  Also, of course,

-// bit_cast<> wraps up the nasty logic in one place.

-//

-// Fortunately memcpy() is very fast.  In optimized mode, with a

-// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline

-// code with the minimal amount of data movement.  On a 32-bit system,

-// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)

-// compiles to two loads and two stores.

-//

-// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.

-//

-// WARNING: if Dest or Source is a non-POD type, the result of the memcpy

-// is likely to surprise you.

-

-template <class Dest, class Source>

-inline Dest bit_cast(const Source& source) {

-  // Compile time assertion: sizeof(Dest) == sizeof(Source)

-  // A compile error here means your Dest and Source have different sizes.

-  typedef char VerifySizesAreEqual [sizeof(Dest) == sizeof(Source) ? 1 : -1];

-

-  Dest dest;

-  memcpy(&dest, &source, sizeof(dest));

-  return dest;

-}

-

-// The following enum should be used only as a constructor argument to indicate

-// that the variable has static storage class, and that the constructor should

-// do nothing to its state.  It indicates to the reader that it is legal to

-// declare a static instance of the class, provided the constructor is given

-// the base::LINKER_INITIALIZED argument.  Normally, it is unsafe to declare a

-// static variable that has a constructor or a destructor because invocation

-// order is undefined.  However, IF the type can be initialized by filling with

-// zeroes (which the loader does for static variables), AND the destructor also

-// does nothing to the storage, AND there are no virtual methods, then a

-// constructor declared as

-//       explicit MyClass(base::LinkerInitialized x) {}

-// and invoked as

-//       static MyClass my_variable_name(base::LINKER_INITIALIZED);

-namespace base {

-enum LinkerInitialized { LINKER_INITIALIZED };

-}  // base

-

-

-#endif  // BASE_BASICTYPES_H_

+// Copyright (c) 2006-2008 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.
+
+#ifndef BASE_BASICTYPES_H_
+#define BASE_BASICTYPES_H_
+
+#include <assert.h>         // for use with down_cast<>
+#include <limits.h>         // So we can set the bounds of our types
+#include <stddef.h>         // For size_t
+#include <string.h>         // for memcpy
+
+#include "base/port.h"    // Types that only need exist on certain systems
+
+#ifndef COMPILER_MSVC
+// stdint.h is part of C99 but MSVC doesn't have it.
+#include <stdint.h>         // For intptr_t.
+#endif
+
+typedef signed char         schar;
+typedef signed char         int8;
+typedef short               int16;
+// TODO(mbelshe) Remove these type guards.  These are
+//               temporary to avoid conflicts with npapi.h.
+#ifndef _INT32
+#define _INT32
+typedef int                 int32;
+#endif
+typedef long long           int64;
+
+// NOTE: unsigned types are DANGEROUS in loops and other arithmetical
+// places.  Use the signed types unless your variable represents a bit
+// pattern (eg a hash value) or you really need the extra bit.  Do NOT
+// use 'unsigned' to express "this value should always be positive";
+// use assertions for this.
+
+typedef unsigned char      uint8;
+typedef unsigned short     uint16;
+// TODO(mbelshe) Remove these type guards.  These are
+//               temporary to avoid conflicts with npapi.h.
+#ifndef _UINT32
+#define _UINT32
+typedef unsigned int       uint32;
+#endif
+typedef unsigned long long uint64;
+
+// A type to represent a Unicode code-point value. As of Unicode 4.0,
+// such values require up to 21 bits.
+// (For type-checking on pointers, make this explicitly signed,
+// and it should always be the signed version of whatever int32 is.)
+typedef signed int         char32;
+
+const uint8  kuint8max  = (( uint8) 0xFF);
+const uint16 kuint16max = ((uint16) 0xFFFF);
+const uint32 kuint32max = ((uint32) 0xFFFFFFFF);
+const uint64 kuint64max = ((uint64) GG_LONGLONG(0xFFFFFFFFFFFFFFFF));
+const  int8  kint8min   = ((  int8) 0x80);
+const  int8  kint8max   = ((  int8) 0x7F);
+const  int16 kint16min  = (( int16) 0x8000);
+const  int16 kint16max  = (( int16) 0x7FFF);
+const  int32 kint32min  = (( int32) 0x80000000);
+const  int32 kint32max  = (( int32) 0x7FFFFFFF);
+const  int64 kint64min  = (( int64) GG_LONGLONG(0x8000000000000000));
+const  int64 kint64max  = (( int64) GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
+
+// id for odp categories
+typedef uint32 CatId;
+const CatId kIllegalCatId = static_cast<CatId>(0);
+
+typedef uint32 TermId;
+const TermId kIllegalTermId = static_cast<TermId>(0);
+
+typedef uint32 HostId;
+const HostId kIllegalHostId = static_cast<HostId>(0);
+
+typedef uint32 DomainId;
+const DomainId kIllegalDomainId = static_cast<DomainId>(0);
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);               \
+  void operator=(const TypeName&)
+
+// An older, deprecated, politically incorrect name for the above.
+#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                    \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// The arraysize(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example.  If you use arraysize on
+// a pointer by mistake, you will get a compile-time error.
+//
+// One caveat is that arraysize() doesn't accept any array of an
+// anonymous type or a type defined inside a function.  In these rare
+// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below.  This is
+// due to a limitation in C++'s template system.  The limitation might
+// eventually be removed, but it hasn't happened yet.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
+
+// That gcc wants both of these prototypes seems mysterious. VC, for
+// its part, can't decide which to use (another mystery). Matching of
+// template overloads: the final frontier.
+#ifndef _MSC_VER
+template <typename T, size_t N>
+char (&ArraySizeHelper(const T (&array)[N]))[N];
+#endif
+
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
+// but can be used on anonymous types or types defined inside
+// functions.  It's less safe than arraysize as it accepts some
+// (although not all) pointers.  Therefore, you should use arraysize
+// whenever possible.
+//
+// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type
+// size_t.
+//
+// ARRAYSIZE_UNSAFE catches a few type errors.  If you see a compiler error
+//
+//   "warning: division by zero in ..."
+//
+// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.
+// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.
+//
+// The following comments are on the implementation details, and can
+// be ignored by the users.
+//
+// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in
+// the array) and sizeof(*(arr)) (the # of bytes in one array
+// element).  If the former is divisible by the latter, perhaps arr is
+// indeed an array, in which case the division result is the # of
+// elements in the array.  Otherwise, arr cannot possibly be an array,
+// and we generate a compiler error to prevent the code from
+// compiling.
+//
+// Since the size of bool is implementation-defined, we need to cast
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
+// result has type size_t.
+//
+// This macro is not perfect as it wrongfully accepts certain
+// pointers, namely where the pointer size is divisible by the pointee
+// size.  Since all our code has to go through a 32-bit compiler,
+// where a pointer is 4 bytes, this means all pointers to a type whose
+// size is 3 or greater than 4 will be (righteously) rejected.
+
+#define ARRAYSIZE_UNSAFE(a) \
+  ((sizeof(a) / sizeof(*(a))) / \
+   static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+
+// Use implicit_cast as a safe version of static_cast or const_cast
+// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
+// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
+// a const pointer to Foo).
+// When you use implicit_cast, the compiler checks that the cast is safe.
+// Such explicit implicit_casts are necessary in surprisingly many
+// situations where C++ demands an exact type match instead of an
+// argument type convertable to a target type.
+//
+// The From type can be inferred, so the preferred syntax for using
+// implicit_cast is the same as for static_cast etc.:
+//
+//   implicit_cast<ToType>(expr)
+//
+// implicit_cast would have been part of the C++ standard library,
+// but the proposal was submitted too late.  It will probably make
+// its way into the language in the future.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+  return f;
+}
+
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts
+// always succeed.  When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo?  It
+// could be a bare Foo, or of type DifferentSubclassOfFoo.  Thus,
+// when you downcast, you should use this macro.  In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not).  In normal mode, we do the efficient static_cast<>
+// instead.  Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+//    This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+//    if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+//    if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+
+template<typename To, typename From>     // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) {                   // so we only accept pointers
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+  if (false) {
+    implicit_cast<From*, To>(0);
+  }
+
+  assert(f == NULL || dynamic_cast<To>(f) != NULL);  // RTTI: debug mode only!
+  return static_cast<To>(f);
+}
+
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+//   COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES,
+//                  content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+//   COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+template <bool>
+struct CompileAssert {
+};
+
+#undef COMPILE_ASSERT
+#define COMPILE_ASSERT(expr, msg) \
+  typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+// Implementation details of COMPILE_ASSERT:
+//
+// - COMPILE_ASSERT works by defining an array type that has -1
+//   elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+//     #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+//   does not work, as gcc supports variable-length arrays whose sizes
+//   are determined at run-time (this is gcc's extension and not part
+//   of the C++ standard).  As a result, gcc fails to reject the
+//   following code with the simple definition:
+//
+//     int foo;
+//     COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
+//                               // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+//   expr is a compile-time constant.  (Template arguments must be
+//   determined at compile-time.)
+//
+// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
+//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written
+//
+//     CompileAssert<bool(expr)>
+//
+//   instead, these compilers will refuse to compile
+//
+//     COMPILE_ASSERT(5 > 0, some_message);
+//
+//   (They seem to think the ">" in "5 > 0" marks the end of the
+//   template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+//     ((expr) ? 1 : -1).
+//
+//   This is to avoid running into a bug in MS VC 7.1, which
+//   causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+
+// MetatagId refers to metatag-id that we assign to
+// each metatag <name, value> pair..
+typedef uint32 MetatagId;
+
+// Argument type used in interfaces that can optionally take ownership
+// of a passed in argument.  If TAKE_OWNERSHIP is passed, the called
+// object takes ownership of the argument.  Otherwise it does not.
+enum Ownership {
+  DO_NOT_TAKE_OWNERSHIP,
+  TAKE_OWNERSHIP
+};
+
+// Use these as the mlock_bytes parameter to MLock and MLockGeneral
+enum { MLOCK_ALL = -1, MLOCK_NONE = 0 };
+
+// Helper routine to avoid buggy code like the following:
+//      if (pos + N < end) ...
+// If pos is large enough, "pos + N" may overflow.  For example,
+// pos==0xfffff000 and N==1MB.
+//
+// PointerRangeSize(a,b) returns the size of the range [a,b-1]
+inline size_t PointerRangeSize(const char* start, const char* end) {
+  assert(start <= end);
+  return end - start;
+}
+
+// bit_cast<Dest,Source> is a template function that implements the
+// equivalent of "*reinterpret_cast<Dest*>(&source)".  We need this in
+// very low-level functions like the protobuf library and fast math
+// support.
+//
+//   float f = 3.14159265358979;
+//   int i = bit_cast<int32>(f);
+//   // i = 0x40490fdb
+//
+// The classical address-casting method is:
+//
+//   // WRONG
+//   float f = 3.14159265358979;            // WRONG
+//   int i = * reinterpret_cast<int*>(&f);  // WRONG
+//
+// The address-casting method actually produces undefined behavior
+// according to ISO C++ specification section 3.10 -15 -.  Roughly, this
+// section says: if an object in memory has one type, and a program
+// accesses it with a different type, then the result is undefined
+// behavior for most values of "different type".
+//
+// This is true for any cast syntax, either *(int*)&f or
+// *reinterpret_cast<int*>(&f).  And it is particularly true for
+// conversions betweeen integral lvalues and floating-point lvalues.
+//
+// The purpose of 3.10 -15- is to allow optimizing compilers to assume
+// that expressions with different types refer to different memory.  gcc
+// 4.0.1 has an optimizer that takes advantage of this.  So a
+// non-conforming program quietly produces wildly incorrect output.
+//
+// The problem is not the use of reinterpret_cast.  The problem is type
+// punning: holding an object in memory of one type and reading its bits
+// back using a different type.
+//
+// The C++ standard is more subtle and complex than this, but that
+// is the basic idea.
+//
+// Anyways ...
+//
+// bit_cast<> calls memcpy() which is blessed by the standard,
+// especially by the example in section 3.9 .  Also, of course,
+// bit_cast<> wraps up the nasty logic in one place.
+//
+// Fortunately memcpy() is very fast.  In optimized mode, with a
+// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
+// code with the minimal amount of data movement.  On a 32-bit system,
+// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
+// compiles to two loads and two stores.
+//
+// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.
+//
+// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
+// is likely to surprise you.
+
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+  // Compile time assertion: sizeof(Dest) == sizeof(Source)
+  // A compile error here means your Dest and Source have different sizes.
+  typedef char VerifySizesAreEqual [sizeof(Dest) == sizeof(Source) ? 1 : -1];
+
+  Dest dest;
+  memcpy(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+// The following enum should be used only as a constructor argument to indicate
+// that the variable has static storage class, and that the constructor should
+// do nothing to its state.  It indicates to the reader that it is legal to
+// declare a static instance of the class, provided the constructor is given
+// the base::LINKER_INITIALIZED argument.  Normally, it is unsafe to declare a
+// static variable that has a constructor or a destructor because invocation
+// order is undefined.  However, IF the type can be initialized by filling with
+// zeroes (which the loader does for static variables), AND the destructor also
+// does nothing to the storage, AND there are no virtual methods, then a
+// constructor declared as
+//       explicit MyClass(base::LinkerInitialized x) {}
+// and invoked as
+//       static MyClass my_variable_name(base::LINKER_INITIALIZED);
+namespace base {
+enum LinkerInitialized { LINKER_INITIALIZED };
+}  // base
+
+
+#endif  // BASE_BASICTYPES_H_
diff --git a/third_party/chrome/base/port.h b/third_party/chrome/base/port.h
index 4bcc4e1..d077705 100644
--- a/third_party/chrome/base/port.h
+++ b/third_party/chrome/base/port.h
@@ -1,60 +1,60 @@
-// Copyright (c) 2006-2008 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.

-

-#ifndef BASE_PORT_H_

-#define BASE_PORT_H_

-

-#include <stdarg.h>

-#include "build/build_config.h"

-

-#ifdef COMPILER_MSVC

-#define GG_LONGLONG(x) x##I64

-#define GG_ULONGLONG(x) x##UI64

-#else

-#define GG_LONGLONG(x) x##LL

-#define GG_ULONGLONG(x) x##ULL

-#endif

-

-// Per C99 7.8.14, define __STDC_CONSTANT_MACROS before including <stdint.h>

-// to get the INTn_C and UINTn_C macros for integer constants.  It's difficult

-// to guarantee any specific ordering of header includes, so it's difficult to

-// guarantee that the INTn_C macros can be defined by including <stdint.h> at

-// any specific point.  Provide GG_INTn_C macros instead.

-

-#define GG_INT8_C(x)    (x)

-#define GG_INT16_C(x)   (x)

-#define GG_INT32_C(x)   (x)

-#define GG_INT64_C(x)   GG_LONGLONG(x)

-

-#define GG_UINT8_C(x)   (x ## U)

-#define GG_UINT16_C(x)  (x ## U)

-#define GG_UINT32_C(x)  (x ## U)

-#define GG_UINT64_C(x)  GG_ULONGLONG(x)

-

-namespace base {

-

-// It's possible for functions that use a va_list, such as StringPrintf, to

-// invalidate the data in it upon use.  The fix is to make a copy of the

-// structure before using it and use that copy instead.  va_copy is provided

-// for this purpose.  MSVC does not provide va_copy, so define an

-// implementation here.  It is not guaranteed that assignment is a copy, so the

-// StringUtil.VariableArgsFunc unit test tests this capability.

-inline void va_copy(va_list& a, va_list& b) {

-#if defined(COMPILER_GCC)

-  ::va_copy(a, b);

-#elif defined(COMPILER_MSVC)

-  a = b;

-#endif

-}

-

-}  // namespace base

-

-// Define an OS-neutral wrapper for shared library entry points

-#if defined(OS_WIN)

-#define API_CALL __stdcall

-#elif defined(OS_LINUX) || defined(OS_MACOSX)

-#define API_CALL

-#endif

-

-#endif  // BASE_PORT_H_

+// Copyright (c) 2006-2008 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.
+
+#ifndef BASE_PORT_H_
+#define BASE_PORT_H_
+
+#include <stdarg.h>
+#include "build/build_config.h"
+
+#ifdef COMPILER_MSVC
+#define GG_LONGLONG(x) x##I64
+#define GG_ULONGLONG(x) x##UI64
+#else
+#define GG_LONGLONG(x) x##LL
+#define GG_ULONGLONG(x) x##ULL
+#endif
+
+// Per C99 7.8.14, define __STDC_CONSTANT_MACROS before including <stdint.h>
+// to get the INTn_C and UINTn_C macros for integer constants.  It's difficult
+// to guarantee any specific ordering of header includes, so it's difficult to
+// guarantee that the INTn_C macros can be defined by including <stdint.h> at
+// any specific point.  Provide GG_INTn_C macros instead.
+
+#define GG_INT8_C(x)    (x)
+#define GG_INT16_C(x)   (x)
+#define GG_INT32_C(x)   (x)
+#define GG_INT64_C(x)   GG_LONGLONG(x)
+
+#define GG_UINT8_C(x)   (x ## U)
+#define GG_UINT16_C(x)  (x ## U)
+#define GG_UINT32_C(x)  (x ## U)
+#define GG_UINT64_C(x)  GG_ULONGLONG(x)
+
+namespace base {
+
+// It's possible for functions that use a va_list, such as StringPrintf, to
+// invalidate the data in it upon use.  The fix is to make a copy of the
+// structure before using it and use that copy instead.  va_copy is provided
+// for this purpose.  MSVC does not provide va_copy, so define an
+// implementation here.  It is not guaranteed that assignment is a copy, so the
+// StringUtil.VariableArgsFunc unit test tests this capability.
+inline void va_copy(va_list& a, va_list& b) {
+#if defined(COMPILER_GCC)
+  ::va_copy(a, b);
+#elif defined(COMPILER_MSVC)
+  a = b;
+#endif
+}
+
+}  // namespace base
+
+// Define an OS-neutral wrapper for shared library entry points
+#if defined(OS_WIN)
+#define API_CALL __stdcall
+#elif defined(OS_LINUX) || defined(OS_MACOSX)
+#define API_CALL
+#endif
+
+#endif  // BASE_PORT_H_
diff --git a/third_party/chrome/base/scoped_ptr.h b/third_party/chrome/base/scoped_ptr.h
index a4fd44e..4489f2d 100644
--- a/third_party/chrome/base/scoped_ptr.h
+++ b/third_party/chrome/base/scoped_ptr.h
@@ -1,380 +1,380 @@
-// Copyright (c) 2006-2008 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.

-

-// Scopers help you manage ownership of a pointer, helping you easily manage the

-// a pointer within a scope, and automatically destroying the pointer at the

-// end of a scope.  There are two main classes you will use, which coorespond

-// to the operators new/delete and new[]/delete[].

-//

-// Example usage (scoped_ptr):

-//   {

-//     scoped_ptr<Foo> foo(new Foo("wee"));

-//   }  // foo goes out of scope, releasing the pointer with it.

-//

-//   {

-//     scoped_ptr<Foo> foo;          // No pointer managed.

-//     foo.reset(new Foo("wee"));    // Now a pointer is managed.

-//     foo.reset(new Foo("wee2"));   // Foo("wee") was destroyed.

-//     foo.reset(new Foo("wee3"));   // Foo("wee2") was destroyed.

-//     foo->Method();                // Foo::Method() called.

-//     foo.get()->Method();          // Foo::Method() called.

-//     SomeFunc(foo.Release());      // SomeFunc takes owernship, foo no longer

-//                                   // manages a pointer.

-//     foo.reset(new Foo("wee4"));   // foo manages a pointer again.

-//     foo.reset();                  // Foo("wee4") destroyed, foo no longer

-//                                   // manages a pointer.

-//   }  // foo wasn't managing a pointer, so nothing was destroyed.

-//

-// Example usage (scoped_array):

-//   {

-//     scoped_array<Foo> foo(new Foo[100]);

-//     foo.get()->Method();  // Foo::Method on the 0th element.

-//     foo[10].Method();     // Foo::Method on the 10th element.

-//   }

-

-#ifndef BASE_SCOPED_PTR_H_

-#define BASE_SCOPED_PTR_H_

-

-// This is an implementation designed to match the anticipated future TR2

-// implementation of the scoped_ptr class, and its closely-related brethren,

-// scoped_array, scoped_ptr_malloc.

-

-#include <assert.h>

-#include <stdlib.h>

-#include <cstddef>

-

-// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>

-// automatically deletes the pointer it holds (if any).

-// That is, scoped_ptr<T> owns the T object that it points to.

-// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.

-// Also like T*, scoped_ptr<T> is thread-compatible, and once you

-// dereference it, you get the threadsafety guarantees of T.

-//

-// The size of a scoped_ptr is small:

-// sizeof(scoped_ptr<C>) == sizeof(C*)

-template <class C>

-class scoped_ptr {

- public:

-

-  // The element type

-  typedef C element_type;

-

-  // Constructor.  Defaults to intializing with NULL.

-  // There is no way to create an uninitialized scoped_ptr.

-  // The input parameter must be allocated with new.

-  explicit scoped_ptr(C* p = NULL) : ptr_(p) { }

-

-  // Destructor.  If there is a C object, delete it.

-  // We don't need to test ptr_ == NULL because C++ does that for us.

-  ~scoped_ptr() {

-    enum { type_must_be_complete = sizeof(C) };

-    delete ptr_;

-  }

-

-  // Reset.  Deletes the current owned object, if any.

-  // Then takes ownership of a new object, if given.

-  // this->reset(this->get()) works.

-  void reset(C* p = NULL) {

-    if (p != ptr_) {

-      enum { type_must_be_complete = sizeof(C) };

-      delete ptr_;

-      ptr_ = p;

-    }

-  }

-

-  // Accessors to get the owned object.

-  // operator* and operator-> will assert() if there is no current object.

-  C& operator*() const {

-    assert(ptr_ != NULL);

-    return *ptr_;

-  }

-  C* operator->() const  {

-    assert(ptr_ != NULL);

-    return ptr_;

-  }

-  C* get() const { return ptr_; }

-

-  // Comparison operators.

-  // These return whether two scoped_ptr refer to the same object, not just to

-  // two different but equal objects.

-  bool operator==(C* p) const { return ptr_ == p; }

-  bool operator!=(C* p) const { return ptr_ != p; }

-

-  // Swap two scoped pointers.

-  void swap(scoped_ptr& p2) {

-    C* tmp = ptr_;

-    ptr_ = p2.ptr_;

-    p2.ptr_ = tmp;

-  }

-

-  // Release a pointer.

-  // The return value is the current pointer held by this object.

-  // If this object holds a NULL pointer, the return value is NULL.

-  // After this operation, this object will hold a NULL pointer,

-  // and will not own the object any more.

-  C* release() {

-    C* retVal = ptr_;

-    ptr_ = NULL;

-    return retVal;

-  }

-

- private:

-  C* ptr_;

-

-  // Forbid comparison of scoped_ptr types.  If C2 != C, it totally doesn't

-  // make sense, and if C2 == C, it still doesn't make sense because you should

-  // never have the same object owned by two different scoped_ptrs.

-  template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;

-  template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;

-

-  // Disallow evil constructors

-  scoped_ptr(const scoped_ptr&);

-  void operator=(const scoped_ptr&);

-};

-

-// Free functions

-template <class C>

-void swap(scoped_ptr<C>& p1, scoped_ptr<C>& p2) {

-  p1.swap(p2);

-}

-

-template <class C>

-bool operator==(C* p1, const scoped_ptr<C>& p2) {

-  return p1 == p2.get();

-}

-

-template <class C>

-bool operator!=(C* p1, const scoped_ptr<C>& p2) {

-  return p1 != p2.get();

-}

-

-// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate

-// with new [] and the destructor deletes objects with delete [].

-//

-// As with scoped_ptr<C>, a scoped_array<C> either points to an object

-// or is NULL.  A scoped_array<C> owns the object that it points to.

-// scoped_array<T> is thread-compatible, and once you index into it,

-// the returned objects have only the threadsafety guarantees of T.

-//

-// Size: sizeof(scoped_array<C>) == sizeof(C*)

-template <class C>

-class scoped_array {

- public:

-

-  // The element type

-  typedef C element_type;

-

-  // Constructor.  Defaults to intializing with NULL.

-  // There is no way to create an uninitialized scoped_array.

-  // The input parameter must be allocated with new [].

-  explicit scoped_array(C* p = NULL) : array_(p) { }

-

-  // Destructor.  If there is a C object, delete it.

-  // We don't need to test ptr_ == NULL because C++ does that for us.

-  ~scoped_array() {

-    enum { type_must_be_complete = sizeof(C) };

-    delete[] array_;

-  }

-

-  // Reset.  Deletes the current owned object, if any.

-  // Then takes ownership of a new object, if given.

-  // this->reset(this->get()) works.

-  void reset(C* p = NULL) {

-    if (p != array_) {

-      enum { type_must_be_complete = sizeof(C) };

-      delete[] array_;

-      array_ = p;

-    }

-  }

-

-  // Get one element of the current object.

-  // Will assert() if there is no current object, or index i is negative.

-  C& operator[](std::ptrdiff_t i) const {

-    assert(i >= 0);

-    assert(array_ != NULL);

-    return array_[i];

-  }

-

-  // Get a pointer to the zeroth element of the current object.

-  // If there is no current object, return NULL.

-  C* get() const {

-    return array_;

-  }

-

-  // Comparison operators.

-  // These return whether two scoped_array refer to the same object, not just to

-  // two different but equal objects.

-  bool operator==(C* p) const { return array_ == p; }

-  bool operator!=(C* p) const { return array_ != p; }

-

-  // Swap two scoped arrays.

-  void swap(scoped_array& p2) {

-    C* tmp = array_;

-    array_ = p2.array_;

-    p2.array_ = tmp;

-  }

-

-  // Release an array.

-  // The return value is the current pointer held by this object.

-  // If this object holds a NULL pointer, the return value is NULL.

-  // After this operation, this object will hold a NULL pointer,

-  // and will not own the object any more.

-  C* release() {

-    C* retVal = array_;

-    array_ = NULL;

-    return retVal;

-  }

-

- private:

-  C* array_;

-

-  // Forbid comparison of different scoped_array types.

-  template <class C2> bool operator==(scoped_array<C2> const& p2) const;

-  template <class C2> bool operator!=(scoped_array<C2> const& p2) const;

-

-  // Disallow evil constructors

-  scoped_array(const scoped_array&);

-  void operator=(const scoped_array&);

-};

-

-// Free functions

-template <class C>

-void swap(scoped_array<C>& p1, scoped_array<C>& p2) {

-  p1.swap(p2);

-}

-

-template <class C>

-bool operator==(C* p1, const scoped_array<C>& p2) {

-  return p1 == p2.get();

-}

-

-template <class C>

-bool operator!=(C* p1, const scoped_array<C>& p2) {

-  return p1 != p2.get();

-}

-

-// This class wraps the c library function free() in a class that can be

-// passed as a template argument to scoped_ptr_malloc below.

-class ScopedPtrMallocFree {

- public:

-  inline void operator()(void* x) const {

-    free(x);

-  }

-};

-

-// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a

-// second template argument, the functor used to free the object.

-

-template<class C, class FreeProc = ScopedPtrMallocFree>

-class scoped_ptr_malloc {

- public:

-

-  // The element type

-  typedef C element_type;

-

-  // Constructor.  Defaults to intializing with NULL.

-  // There is no way to create an uninitialized scoped_ptr.

-  // The input parameter must be allocated with an allocator that matches the

-  // Free functor.  For the default Free functor, this is malloc, calloc, or

-  // realloc.

-  explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {}

-

-  // Destructor.  If there is a C object, call the Free functor.

-  ~scoped_ptr_malloc() {

-    free_(ptr_);

-  }

-

-  // Reset.  Calls the Free functor on the current owned object, if any.

-  // Then takes ownership of a new object, if given.

-  // this->reset(this->get()) works.

-  void reset(C* p = NULL) {

-    if (ptr_ != p) {

-      free_(ptr_);

-      ptr_ = p;

-    }

-  }

-

-  // Get the current object.

-  // operator* and operator-> will cause an assert() failure if there is

-  // no current object.

-  C& operator*() const {

-    assert(ptr_ != NULL);

-    return *ptr_;

-  }

-

-  C* operator->() const {

-    assert(ptr_ != NULL);

-    return ptr_;

-  }

-

-  C* get() const {

-    return ptr_;

-  }

-

-  // Comparison operators.

-  // These return whether a scoped_ptr_malloc and a plain pointer refer

-  // to the same object, not just to two different but equal objects.

-  // For compatibility wwith the boost-derived implementation, these

-  // take non-const arguments.

-  bool operator==(C* p) const {

-    return ptr_ == p;

-  }

-

-  bool operator!=(C* p) const {

-    return ptr_ != p;

-  }

-

-  // Swap two scoped pointers.

-  void swap(scoped_ptr_malloc & b) {

-    C* tmp = b.ptr_;

-    b.ptr_ = ptr_;

-    ptr_ = tmp;

-  }

-

-  // Release a pointer.

-  // The return value is the current pointer held by this object.

-  // If this object holds a NULL pointer, the return value is NULL.

-  // After this operation, this object will hold a NULL pointer,

-  // and will not own the object any more.

-  C* release() {

-    C* tmp = ptr_;

-    ptr_ = NULL;

-    return tmp;

-  }

-

- private:

-  C* ptr_;

-

-  // no reason to use these: each scoped_ptr_malloc should have its own object

-  template <class C2, class GP>

-  bool operator==(scoped_ptr_malloc<C2, GP> const& p) const;

-  template <class C2, class GP>

-  bool operator!=(scoped_ptr_malloc<C2, GP> const& p) const;

-

-  static FreeProc const free_;

-

-  // Disallow evil constructors

-  scoped_ptr_malloc(const scoped_ptr_malloc&);

-  void operator=(const scoped_ptr_malloc&);

-};

-

-template<class C, class FP>

-FP const scoped_ptr_malloc<C, FP>::free_ = FP();

-

-template<class C, class FP> inline

-void swap(scoped_ptr_malloc<C, FP>& a, scoped_ptr_malloc<C, FP>& b) {

-  a.swap(b);

-}

-

-template<class C, class FP> inline

-bool operator==(C* p, const scoped_ptr_malloc<C, FP>& b) {

-  return p == b.get();

-}

-

-template<class C, class FP> inline

-bool operator!=(C* p, const scoped_ptr_malloc<C, FP>& b) {

-  return p != b.get();

-}

-

-#endif  // BASE_SCOPED_PTR_H_

+// Copyright (c) 2006-2008 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.
+
+// Scopers help you manage ownership of a pointer, helping you easily manage the
+// a pointer within a scope, and automatically destroying the pointer at the
+// end of a scope.  There are two main classes you will use, which coorespond
+// to the operators new/delete and new[]/delete[].
+//
+// Example usage (scoped_ptr):
+//   {
+//     scoped_ptr<Foo> foo(new Foo("wee"));
+//   }  // foo goes out of scope, releasing the pointer with it.
+//
+//   {
+//     scoped_ptr<Foo> foo;          // No pointer managed.
+//     foo.reset(new Foo("wee"));    // Now a pointer is managed.
+//     foo.reset(new Foo("wee2"));   // Foo("wee") was destroyed.
+//     foo.reset(new Foo("wee3"));   // Foo("wee2") was destroyed.
+//     foo->Method();                // Foo::Method() called.
+//     foo.get()->Method();          // Foo::Method() called.
+//     SomeFunc(foo.Release());      // SomeFunc takes owernship, foo no longer
+//                                   // manages a pointer.
+//     foo.reset(new Foo("wee4"));   // foo manages a pointer again.
+//     foo.reset();                  // Foo("wee4") destroyed, foo no longer
+//                                   // manages a pointer.
+//   }  // foo wasn't managing a pointer, so nothing was destroyed.
+//
+// Example usage (scoped_array):
+//   {
+//     scoped_array<Foo> foo(new Foo[100]);
+//     foo.get()->Method();  // Foo::Method on the 0th element.
+//     foo[10].Method();     // Foo::Method on the 10th element.
+//   }
+
+#ifndef BASE_SCOPED_PTR_H_
+#define BASE_SCOPED_PTR_H_
+
+// This is an implementation designed to match the anticipated future TR2
+// implementation of the scoped_ptr class, and its closely-related brethren,
+// scoped_array, scoped_ptr_malloc.
+
+#include <assert.h>
+#include <stdlib.h>
+#include <cstddef>
+
+// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
+// automatically deletes the pointer it holds (if any).
+// That is, scoped_ptr<T> owns the T object that it points to.
+// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
+// Also like T*, scoped_ptr<T> is thread-compatible, and once you
+// dereference it, you get the threadsafety guarantees of T.
+//
+// The size of a scoped_ptr is small:
+// sizeof(scoped_ptr<C>) == sizeof(C*)
+template <class C>
+class scoped_ptr {
+ public:
+
+  // The element type
+  typedef C element_type;
+
+  // Constructor.  Defaults to intializing with NULL.
+  // There is no way to create an uninitialized scoped_ptr.
+  // The input parameter must be allocated with new.
+  explicit scoped_ptr(C* p = NULL) : ptr_(p) { }
+
+  // Destructor.  If there is a C object, delete it.
+  // We don't need to test ptr_ == NULL because C++ does that for us.
+  ~scoped_ptr() {
+    enum { type_must_be_complete = sizeof(C) };
+    delete ptr_;
+  }
+
+  // Reset.  Deletes the current owned object, if any.
+  // Then takes ownership of a new object, if given.
+  // this->reset(this->get()) works.
+  void reset(C* p = NULL) {
+    if (p != ptr_) {
+      enum { type_must_be_complete = sizeof(C) };
+      delete ptr_;
+      ptr_ = p;
+    }
+  }
+
+  // Accessors to get the owned object.
+  // operator* and operator-> will assert() if there is no current object.
+  C& operator*() const {
+    assert(ptr_ != NULL);
+    return *ptr_;
+  }
+  C* operator->() const  {
+    assert(ptr_ != NULL);
+    return ptr_;
+  }
+  C* get() const { return ptr_; }
+
+  // Comparison operators.
+  // These return whether two scoped_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(C* p) const { return ptr_ == p; }
+  bool operator!=(C* p) const { return ptr_ != p; }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr& p2) {
+    C* tmp = ptr_;
+    ptr_ = p2.ptr_;
+    p2.ptr_ = tmp;
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  C* release() {
+    C* retVal = ptr_;
+    ptr_ = NULL;
+    return retVal;
+  }
+
+ private:
+  C* ptr_;
+
+  // Forbid comparison of scoped_ptr types.  If C2 != C, it totally doesn't
+  // make sense, and if C2 == C, it still doesn't make sense because you should
+  // never have the same object owned by two different scoped_ptrs.
+  template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
+  template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
+
+  // Disallow evil constructors
+  scoped_ptr(const scoped_ptr&);
+  void operator=(const scoped_ptr&);
+};
+
+// Free functions
+template <class C>
+void swap(scoped_ptr<C>& p1, scoped_ptr<C>& p2) {
+  p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C* p1, const scoped_ptr<C>& p2) {
+  return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C* p1, const scoped_ptr<C>& p2) {
+  return p1 != p2.get();
+}
+
+// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
+// with new [] and the destructor deletes objects with delete [].
+//
+// As with scoped_ptr<C>, a scoped_array<C> either points to an object
+// or is NULL.  A scoped_array<C> owns the object that it points to.
+// scoped_array<T> is thread-compatible, and once you index into it,
+// the returned objects have only the threadsafety guarantees of T.
+//
+// Size: sizeof(scoped_array<C>) == sizeof(C*)
+template <class C>
+class scoped_array {
+ public:
+
+  // The element type
+  typedef C element_type;
+
+  // Constructor.  Defaults to intializing with NULL.
+  // There is no way to create an uninitialized scoped_array.
+  // The input parameter must be allocated with new [].
+  explicit scoped_array(C* p = NULL) : array_(p) { }
+
+  // Destructor.  If there is a C object, delete it.
+  // We don't need to test ptr_ == NULL because C++ does that for us.
+  ~scoped_array() {
+    enum { type_must_be_complete = sizeof(C) };
+    delete[] array_;
+  }
+
+  // Reset.  Deletes the current owned object, if any.
+  // Then takes ownership of a new object, if given.
+  // this->reset(this->get()) works.
+  void reset(C* p = NULL) {
+    if (p != array_) {
+      enum { type_must_be_complete = sizeof(C) };
+      delete[] array_;
+      array_ = p;
+    }
+  }
+
+  // Get one element of the current object.
+  // Will assert() if there is no current object, or index i is negative.
+  C& operator[](std::ptrdiff_t i) const {
+    assert(i >= 0);
+    assert(array_ != NULL);
+    return array_[i];
+  }
+
+  // Get a pointer to the zeroth element of the current object.
+  // If there is no current object, return NULL.
+  C* get() const {
+    return array_;
+  }
+
+  // Comparison operators.
+  // These return whether two scoped_array refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(C* p) const { return array_ == p; }
+  bool operator!=(C* p) const { return array_ != p; }
+
+  // Swap two scoped arrays.
+  void swap(scoped_array& p2) {
+    C* tmp = array_;
+    array_ = p2.array_;
+    p2.array_ = tmp;
+  }
+
+  // Release an array.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  C* release() {
+    C* retVal = array_;
+    array_ = NULL;
+    return retVal;
+  }
+
+ private:
+  C* array_;
+
+  // Forbid comparison of different scoped_array types.
+  template <class C2> bool operator==(scoped_array<C2> const& p2) const;
+  template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
+
+  // Disallow evil constructors
+  scoped_array(const scoped_array&);
+  void operator=(const scoped_array&);
+};
+
+// Free functions
+template <class C>
+void swap(scoped_array<C>& p1, scoped_array<C>& p2) {
+  p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C* p1, const scoped_array<C>& p2) {
+  return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C* p1, const scoped_array<C>& p2) {
+  return p1 != p2.get();
+}
+
+// This class wraps the c library function free() in a class that can be
+// passed as a template argument to scoped_ptr_malloc below.
+class ScopedPtrMallocFree {
+ public:
+  inline void operator()(void* x) const {
+    free(x);
+  }
+};
+
+// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a
+// second template argument, the functor used to free the object.
+
+template<class C, class FreeProc = ScopedPtrMallocFree>
+class scoped_ptr_malloc {
+ public:
+
+  // The element type
+  typedef C element_type;
+
+  // Constructor.  Defaults to intializing with NULL.
+  // There is no way to create an uninitialized scoped_ptr.
+  // The input parameter must be allocated with an allocator that matches the
+  // Free functor.  For the default Free functor, this is malloc, calloc, or
+  // realloc.
+  explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {}
+
+  // Destructor.  If there is a C object, call the Free functor.
+  ~scoped_ptr_malloc() {
+    free_(ptr_);
+  }
+
+  // Reset.  Calls the Free functor on the current owned object, if any.
+  // Then takes ownership of a new object, if given.
+  // this->reset(this->get()) works.
+  void reset(C* p = NULL) {
+    if (ptr_ != p) {
+      free_(ptr_);
+      ptr_ = p;
+    }
+  }
+
+  // Get the current object.
+  // operator* and operator-> will cause an assert() failure if there is
+  // no current object.
+  C& operator*() const {
+    assert(ptr_ != NULL);
+    return *ptr_;
+  }
+
+  C* operator->() const {
+    assert(ptr_ != NULL);
+    return ptr_;
+  }
+
+  C* get() const {
+    return ptr_;
+  }
+
+  // Comparison operators.
+  // These return whether a scoped_ptr_malloc and a plain pointer refer
+  // to the same object, not just to two different but equal objects.
+  // For compatibility wwith the boost-derived implementation, these
+  // take non-const arguments.
+  bool operator==(C* p) const {
+    return ptr_ == p;
+  }
+
+  bool operator!=(C* p) const {
+    return ptr_ != p;
+  }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr_malloc & b) {
+    C* tmp = b.ptr_;
+    b.ptr_ = ptr_;
+    ptr_ = tmp;
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object.
+  // If this object holds a NULL pointer, the return value is NULL.
+  // After this operation, this object will hold a NULL pointer,
+  // and will not own the object any more.
+  C* release() {
+    C* tmp = ptr_;
+    ptr_ = NULL;
+    return tmp;
+  }
+
+ private:
+  C* ptr_;
+
+  // no reason to use these: each scoped_ptr_malloc should have its own object
+  template <class C2, class GP>
+  bool operator==(scoped_ptr_malloc<C2, GP> const& p) const;
+  template <class C2, class GP>
+  bool operator!=(scoped_ptr_malloc<C2, GP> const& p) const;
+
+  static FreeProc const free_;
+
+  // Disallow evil constructors
+  scoped_ptr_malloc(const scoped_ptr_malloc&);
+  void operator=(const scoped_ptr_malloc&);
+};
+
+template<class C, class FP>
+FP const scoped_ptr_malloc<C, FP>::free_ = FP();
+
+template<class C, class FP> inline
+void swap(scoped_ptr_malloc<C, FP>& a, scoped_ptr_malloc<C, FP>& b) {
+  a.swap(b);
+}
+
+template<class C, class FP> inline
+bool operator==(C* p, const scoped_ptr_malloc<C, FP>& b) {
+  return p == b.get();
+}
+
+template<class C, class FP> inline
+bool operator!=(C* p, const scoped_ptr_malloc<C, FP>& b) {
+  return p != b.get();
+}
+
+#endif  // BASE_SCOPED_PTR_H_
diff --git a/third_party/chrome/build/build_config.h b/third_party/chrome/build/build_config.h
index 5c2c4aa..c4c8ed7 100644
--- a/third_party/chrome/build/build_config.h
+++ b/third_party/chrome/build/build_config.h
@@ -1,68 +1,68 @@
-// Copyright (c) 2006-2008 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 adds defines about the platform we're currently building on.

-//  Operating System:

-//    OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX)

-//  Compiler:

-//    COMPILER_MSVC / COMPILER_GCC

-//  Processor:

-//    ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_X86_FAMILY (X86 or X86_64)

-//    ARCH_CPU_32_BITS / ARCH_CPU_64_BITS

-

-#ifndef BUILD_BUILD_CONFIG_H_

-#define BUILD_BUILD_CONFIG_H_

-

-// A set of macros to use for platform detection.

-#if defined(__APPLE__)

-#define OS_MACOSX 1

-#elif defined(__linux__)

-#define OS_LINUX 1

-#elif defined(_WIN32)

-#define OS_WIN 1

-#else

-#error Please add support for your platform in build/build_config.h

-#endif

-

-// For access to standard POSIX features, use OS_POSIX instead of a more

-// specific macro.

-#if defined(OS_MACOSX) || defined(OS_LINUX)

-#define OS_POSIX 1

-#endif

-

-// Compiler detection.

-#if defined(__GNUC__)

-#define COMPILER_GCC 1

-#elif defined(_MSC_VER)

-#define COMPILER_MSVC 1

-#else

-#error Please add support for your compiler in build/build_config.h

-#endif

-

-// Processor architecture detection.  For more info on what's defined, see:

-//   http://msdn.microsoft.com/en-us/library/b0084kay.aspx

-//   http://www.agner.org/optimize/calling_conventions.pdf

-#if defined(_M_X64) || defined(__x86_64__)

-#define ARCH_CPU_X86_FAMILY 1

-#define ARCH_CPU_X86_64 1

-#define ARCH_CPU_64_BITS 1

-#elif defined(_M_IX86) || defined(__i386__)

-#define ARCH_CPU_X86_FAMILY 1

-#define ARCH_CPU_X86 1

-#define ARCH_CPU_32_BITS 1

-#else

-#error Please add support for your architecture in build/build_config.h

-#endif

-

-// Type detection for wchar_t.

-#if defined(OS_WIN)

-#define WCHAR_T_IS_UTF16

-#elif defined(OS_POSIX) && defined(COMPILER_GCC) && \

-    defined(__WCHAR_MAX__) && __WCHAR_MAX__ == 0x7fffffff

-#define WCHAR_T_IS_UTF32

-#else

-#error Please add support for your compiler in build/build_config.h

-#endif

-

-#endif  // BUILD_BUILD_CONFIG_H_

+// Copyright (c) 2006-2008 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 adds defines about the platform we're currently building on.
+//  Operating System:
+//    OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX)
+//  Compiler:
+//    COMPILER_MSVC / COMPILER_GCC
+//  Processor:
+//    ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_X86_FAMILY (X86 or X86_64)
+//    ARCH_CPU_32_BITS / ARCH_CPU_64_BITS
+
+#ifndef BUILD_BUILD_CONFIG_H_
+#define BUILD_BUILD_CONFIG_H_
+
+// A set of macros to use for platform detection.
+#if defined(__APPLE__)
+#define OS_MACOSX 1
+#elif defined(__linux__)
+#define OS_LINUX 1
+#elif defined(_WIN32)
+#define OS_WIN 1
+#else
+#error Please add support for your platform in build/build_config.h
+#endif
+
+// For access to standard POSIX features, use OS_POSIX instead of a more
+// specific macro.
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+#define OS_POSIX 1
+#endif
+
+// Compiler detection.
+#if defined(__GNUC__)
+#define COMPILER_GCC 1
+#elif defined(_MSC_VER)
+#define COMPILER_MSVC 1
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+// Processor architecture detection.  For more info on what's defined, see:
+//   http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+//   http://www.agner.org/optimize/calling_conventions.pdf
+#if defined(_M_X64) || defined(__x86_64__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86_64 1
+#define ARCH_CPU_64_BITS 1
+#elif defined(_M_IX86) || defined(__i386__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86 1
+#define ARCH_CPU_32_BITS 1
+#else
+#error Please add support for your architecture in build/build_config.h
+#endif
+
+// Type detection for wchar_t.
+#if defined(OS_WIN)
+#define WCHAR_T_IS_UTF16
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && \
+    defined(__WCHAR_MAX__) && __WCHAR_MAX__ == 0x7fffffff
+#define WCHAR_T_IS_UTF32
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+#endif  // BUILD_BUILD_CONFIG_H_
diff --git a/third_party/gecko/README b/third_party/gecko/README
index d44f394..d849908 100644
--- a/third_party/gecko/README
+++ b/third_party/gecko/README
@@ -1,11 +1,11 @@
-This directory contains IDL files from the Mozilla source tree (circa Mozilla

-1.7).  These IDL files are copied here because they do not exist in the Gecko

-SDK.  Eventually, the hope is that the Gecko SDK will expand to include these

-interfaces.  For now, we keep these in a separate directory, with the idea that

-this directory will some day go away.

-

-Some files have been modified slightly, usually to change the name of an

-interface to deal with cases where multiple versions of the same interface are

-needed.  Modified files should include a comment explaining what has changed.

-

--darin

+This directory contains IDL files from the Mozilla source tree (circa Mozilla
+1.7).  These IDL files are copied here because they do not exist in the Gecko
+SDK.  Eventually, the hope is that the Gecko SDK will expand to include these
+interfaces.  For now, we keep these in a separate directory, with the idea that
+this directory will some day go away.
+
+Some files have been modified slightly, usually to change the name of an
+interface to deal with cases where multiple versions of the same interface are
+needed.  Modified files should include a comment explaining what has changed.
+
+-darin
diff --git a/third_party/gecko/imgILoader.idl b/third_party/gecko/imgILoader.idl
index 7ff611b..8fb423c 100644
--- a/third_party/gecko/imgILoader.idl
+++ b/third_party/gecko/imgILoader.idl
@@ -1,112 +1,112 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-

- *

- * ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 2001

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   Stuart Parmenter <pavlov@netscape.com>

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "nsISupports.idl"

-

-interface imgIDecoderObserver;

-interface imgIRequest;

-

-interface nsIChannel;

-interface nsILoadGroup;

-interface nsIStreamListener;

-interface nsIURI;

-

-interface nsISimpleEnumerator;

-

-#include "nsIRequest.idl" // for nsLoadFlags

-

-/**

- * imgILoader interface

- *

- * @author Stuart Parmenter <pavlov@netscape.com>

- * @version 0.3

- * @see imagelib2

- */

-[scriptable, uuid(a32826ff-9e56-4425-a811-97a8dba64ff5)]

-interface imgILoader : nsISupports

-{

-  /**

-   * Start the load and decode of an image.

-   * @param aURI the URI to load

-   * @param aInitialDocumentURI the URI that 'initiated' the load -- used for 3rd party cookie blocking

-   * @param aReferrerURI the 'referring' URI

-   * @param aLoadGroup Loadgroup to put the image load into

-   * @param aObserver the observer

-   * @param aCX some random data

-   * @param aLoadFlags Load flags for the request

-   * @param aCacheKey cache key to use for a load if the original

-   *                  image came from a request that had post data

-   * @param aRequest A newly created, unused imgIRequest object or NULL for one to

-                     be created for you.

-

-

-   * libpr0n does NOT keep a strong ref to the observer; this prevents

-   * reference cycles.  This means that callers of loadImage should

-   * make sure to Cancel() the resulting request before the observer

-   * goes away.

-   */

-  imgIRequest loadImage(in nsIURI aURI,

-                        in nsIURI aInitialDocumentURL,

-                        in nsIURI aReferrerURI,

-                        in nsILoadGroup aLoadGroup,

-                        in imgIDecoderObserver aObserver,

-                        in nsISupports aCX,

-                        in nsLoadFlags aLoadFlags,

-                        in nsISupports cacheKey,

-                        in imgIRequest aRequest);

-

-  /**

-   * Start the load and decode of an image.

-   * @param uri the URI to load

-   * @param aObserver the observer

-   * @param cx some random data

-   *

-   * libpr0n does NOT keep a strong ref to the observer; this prevents

-   * reference cycles.  This means that callers of loadImageWithChannel should

-   * make sure to Cancel() the resulting request before the observer goes away.

-   */

-  imgIRequest loadImageWithChannel(in nsIChannel aChannel, in imgIDecoderObserver aObserver, in nsISupports cx, out nsIStreamListener aListener);

-

-  /**

-   * Checks if a decoder for the an image with the given mime type is available

-   * @param mimeType The type to find a decoder for

-   * @return true if a decoder is available, false otherwise

-   */

-  boolean supportImageWithMimeType(in string mimeType);

-};

+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stuart Parmenter <pavlov@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface imgIDecoderObserver;
+interface imgIRequest;
+
+interface nsIChannel;
+interface nsILoadGroup;
+interface nsIStreamListener;
+interface nsIURI;
+
+interface nsISimpleEnumerator;
+
+#include "nsIRequest.idl" // for nsLoadFlags
+
+/**
+ * imgILoader interface
+ *
+ * @author Stuart Parmenter <pavlov@netscape.com>
+ * @version 0.3
+ * @see imagelib2
+ */
+[scriptable, uuid(a32826ff-9e56-4425-a811-97a8dba64ff5)]
+interface imgILoader : nsISupports
+{
+  /**
+   * Start the load and decode of an image.
+   * @param aURI the URI to load
+   * @param aInitialDocumentURI the URI that 'initiated' the load -- used for 3rd party cookie blocking
+   * @param aReferrerURI the 'referring' URI
+   * @param aLoadGroup Loadgroup to put the image load into
+   * @param aObserver the observer
+   * @param aCX some random data
+   * @param aLoadFlags Load flags for the request
+   * @param aCacheKey cache key to use for a load if the original
+   *                  image came from a request that had post data
+   * @param aRequest A newly created, unused imgIRequest object or NULL for one to
+                     be created for you.
+
+
+   * libpr0n does NOT keep a strong ref to the observer; this prevents
+   * reference cycles.  This means that callers of loadImage should
+   * make sure to Cancel() the resulting request before the observer
+   * goes away.
+   */
+  imgIRequest loadImage(in nsIURI aURI,
+                        in nsIURI aInitialDocumentURL,
+                        in nsIURI aReferrerURI,
+                        in nsILoadGroup aLoadGroup,
+                        in imgIDecoderObserver aObserver,
+                        in nsISupports aCX,
+                        in nsLoadFlags aLoadFlags,
+                        in nsISupports cacheKey,
+                        in imgIRequest aRequest);
+
+  /**
+   * Start the load and decode of an image.
+   * @param uri the URI to load
+   * @param aObserver the observer
+   * @param cx some random data
+   *
+   * libpr0n does NOT keep a strong ref to the observer; this prevents
+   * reference cycles.  This means that callers of loadImageWithChannel should
+   * make sure to Cancel() the resulting request before the observer goes away.
+   */
+  imgIRequest loadImageWithChannel(in nsIChannel aChannel, in imgIDecoderObserver aObserver, in nsISupports cx, out nsIStreamListener aListener);
+
+  /**
+   * Checks if a decoder for the an image with the given mime type is available
+   * @param mimeType The type to find a decoder for
+   * @return true if a decoder is available, false otherwise
+   */
+  boolean supportImageWithMimeType(in string mimeType);
+};
diff --git a/third_party/gecko/imgIRequest.idl b/third_party/gecko/imgIRequest.idl
index 6bdfe7d..beebdc5 100644
--- a/third_party/gecko/imgIRequest.idl
+++ b/third_party/gecko/imgIRequest.idl
@@ -1,97 +1,97 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-

- *

- * ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 2001

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   Stuart Parmenter <pavlov@netscape.com>

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "nsISupports.idl"

-#include "nsIRequest.idl"

-

-interface imgIContainer;

-interface imgIDecoderObserver;

-interface nsIURI;

-

-/**

- * imgIRequest interface

- *

- * @author Stuart Parmenter <pavlov@netscape.com>

- * @version 0.1

- * @see imagelib2

- */

-[scriptable, uuid(ccf705f6-1dd1-11b2-82ef-e18eccf7f7ec)]

-interface imgIRequest : nsIRequest

-{

-  /**

-   * the image container...

-   * @return the image object associated with the request.

-   * @attention NEED DOCS

-   */

-  readonly attribute imgIContainer image;

-

-  /**

-   * Bits set in the return value from imageStatus

-   * @name statusflags

-   */

-  //@{

-  const long STATUS_NONE             = 0x0;

-  const long STATUS_SIZE_AVAILABLE   = 0x1;

-  const long STATUS_LOAD_PARTIAL     = 0x2;

-  const long STATUS_LOAD_COMPLETE    = 0x4;

-  const long STATUS_ERROR            = 0x8;

-  const long STATUS_FRAME_COMPLETE   = 0x10;

-  //@}

-

-  /**

-   * something

-   * @attention NEED DOCS

-   */

-  readonly attribute unsigned long imageStatus;

-

-  readonly attribute nsIURI URI;

-

-  readonly attribute imgIDecoderObserver decoderObserver;

-

-  readonly attribute string mimeType;

-

-  /**

-   * Clone this request; the returned request will have aObserver as the

-   * observer.  aObserver will be notified synchronously (before the clone()

-   * call returns) with all the notifications that have already been dispatched

-   * for this image load.

-   */

-  imgIRequest clone(in imgIDecoderObserver aObserver);

-};

-

+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Stuart Parmenter <pavlov@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+#include "nsIRequest.idl"
+
+interface imgIContainer;
+interface imgIDecoderObserver;
+interface nsIURI;
+
+/**
+ * imgIRequest interface
+ *
+ * @author Stuart Parmenter <pavlov@netscape.com>
+ * @version 0.1
+ * @see imagelib2
+ */
+[scriptable, uuid(ccf705f6-1dd1-11b2-82ef-e18eccf7f7ec)]
+interface imgIRequest : nsIRequest
+{
+  /**
+   * the image container...
+   * @return the image object associated with the request.
+   * @attention NEED DOCS
+   */
+  readonly attribute imgIContainer image;
+
+  /**
+   * Bits set in the return value from imageStatus
+   * @name statusflags
+   */
+  //@{
+  const long STATUS_NONE             = 0x0;
+  const long STATUS_SIZE_AVAILABLE   = 0x1;
+  const long STATUS_LOAD_PARTIAL     = 0x2;
+  const long STATUS_LOAD_COMPLETE    = 0x4;
+  const long STATUS_ERROR            = 0x8;
+  const long STATUS_FRAME_COMPLETE   = 0x10;
+  //@}
+
+  /**
+   * something
+   * @attention NEED DOCS
+   */
+  readonly attribute unsigned long imageStatus;
+
+  readonly attribute nsIURI URI;
+
+  readonly attribute imgIDecoderObserver decoderObserver;
+
+  readonly attribute string mimeType;
+
+  /**
+   * Clone this request; the returned request will have aObserver as the
+   * observer.  aObserver will be notified synchronously (before the clone()
+   * call returns) with all the notifications that have already been dispatched
+   * for this image load.
+   */
+  imgIRequest clone(in imgIDecoderObserver aObserver);
+};
+
diff --git a/third_party/gecko/include/jni.h b/third_party/gecko/include/jni.h
index 2f9b232..863075a 100644
--- a/third_party/gecko/include/jni.h
+++ b/third_party/gecko/include/jni.h
@@ -1,1810 +1,1810 @@
-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is the Java Runtime Interface.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation and Sun Microsystems, Inc.

- * Portions created by the Initial Developer are Copyright (C) 1993-1996

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#ifndef JNI_H

-#define JNI_H

-

-#include <stdio.h>

-#include <stdarg.h>

-

-/* jni_md.h contains the machine-dependent typedefs for jbyte, jint 

-   and jlong */ 

-

-#include "jni_md.h"

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-/*

- * JNI Types

- */

-

-typedef unsigned char	jboolean;

-typedef unsigned short	jchar;

-typedef short		jshort;

-typedef float		jfloat;

-typedef double		jdouble;

-

-typedef jint            jsize;

-

-#ifdef __cplusplus

-

-class _jobject {};

-class _jclass : public _jobject {};

-class _jthrowable : public _jobject {};

-class _jstring : public _jobject {};

-class _jarray : public _jobject {};

-class _jbooleanArray : public _jarray {};

-class _jbyteArray : public _jarray {};

-class _jcharArray : public _jarray {};

-class _jshortArray : public _jarray {};

-class _jintArray : public _jarray {};

-class _jlongArray : public _jarray {};

-class _jfloatArray : public _jarray {};

-class _jdoubleArray : public _jarray {};

-class _jobjectArray : public _jarray {};

-

-typedef _jobject *jobject;

-typedef _jclass *jclass;

-typedef _jthrowable *jthrowable;

-typedef _jstring *jstring;

-typedef _jarray *jarray;

-typedef _jbooleanArray *jbooleanArray;

-typedef _jbyteArray *jbyteArray;

-typedef _jcharArray *jcharArray;

-typedef _jshortArray *jshortArray;

-typedef _jintArray *jintArray;

-typedef _jlongArray *jlongArray;

-typedef _jfloatArray *jfloatArray;

-typedef _jdoubleArray *jdoubleArray;

-typedef _jobjectArray *jobjectArray;

-

-#else

-

-struct _jobject;

-

-typedef struct _jobject *jobject;

-typedef jobject jclass;

-typedef jobject jthrowable;

-typedef jobject jstring;

-typedef jobject jarray;

-typedef jarray jbooleanArray;

-typedef jarray jbyteArray;

-typedef jarray jcharArray;

-typedef jarray jshortArray;

-typedef jarray jintArray;

-typedef jarray jlongArray;

-typedef jarray jfloatArray;

-typedef jarray jdoubleArray;

-typedef jarray jobjectArray;

-

-#endif

-

-#if 0	/* moved to jri_md.h */

-typedef jobject jref; /* For transition---not meant to be part of public 

-			 API anymore.*/

-#endif

-

-typedef union jvalue {

-    jboolean z;

-    jbyte    b;

-    jchar    c;

-    jshort   s;

-    jint     i;

-    jlong    j;

-    jfloat   f;

-    jdouble  d;

-    jobject  l;

-} jvalue;

-

-struct _jfieldID;

-typedef struct _jfieldID *jfieldID;

-

-struct _jmethodID;

-typedef struct _jmethodID *jmethodID;

-

-/*

- * jboolean constants

- */

-

-#define JNI_FALSE 0

-#define JNI_TRUE 1

-

-/*

- * possible return values for JNI functions.

- */

-

-#define JNI_OK 0

-#define JNI_ERR (-1)

-

-/*

- * used in ReleaseScalarArrayElements

- */

-  

-#define JNI_COMMIT 1

-#define JNI_ABORT 2

-

-/*

- * used in RegisterNatives to describe native method name, signature,

- * and function pointer.

- */

-

-typedef struct {

-    char *name;

-    char *signature;

-    void *fnPtr;

-} JNINativeMethod;

-

-/*

- * JNI Native Method Interface.

- */

-

-struct JNINativeInterface_;

-

-struct JNIEnv_;

-

-#ifdef __cplusplus

-typedef JNIEnv_ JNIEnv;

-#else

-typedef const struct JNINativeInterface_ *JNIEnv;

-#endif

-

-/*

- * JNI Invocation Interface.

- */

-

-struct JNIInvokeInterface_;

-

-struct JavaVM_;

-

-#ifdef __cplusplus

-typedef JavaVM_ JavaVM;

-#else

-typedef const struct JNIInvokeInterface_ *JavaVM;

-#endif

-

-struct JNINativeInterface_ {

-    void *reserved0;

-    void *reserved1;

-    void *reserved2;

-

-    void *reserved3;

-    jint (JNICALL *GetVersion)(JNIEnv *env);

-

-    jclass (JNICALL *DefineClass)

-      (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, 

-       jsize len);

-    jclass (JNICALL *FindClass)

-      (JNIEnv *env, const char *name);

-

-    void *reserved4;

-    void *reserved5;

-    void *reserved6;

-

-    jclass (JNICALL *GetSuperclass)

-      (JNIEnv *env, jclass sub);

-    jboolean (JNICALL *IsAssignableFrom)

-      (JNIEnv *env, jclass sub, jclass sup);

-    void *reserved7;

-

-

-    jint (JNICALL *Throw)

-      (JNIEnv *env, jthrowable obj);

-    jint (JNICALL *ThrowNew)

-      (JNIEnv *env, jclass clazz, const char *msg);

-    jthrowable (JNICALL *ExceptionOccurred)

-      (JNIEnv *env);

-    void (JNICALL *ExceptionDescribe)

-      (JNIEnv *env);

-    void (JNICALL *ExceptionClear)

-      (JNIEnv *env);

-    void (JNICALL *FatalError)

-      (JNIEnv *env, const char *msg);

-    void *reserved8;

-    void *reserved9;

-

-    jobject (JNICALL *NewGlobalRef)

-      (JNIEnv *env, jobject lobj);

-    void (JNICALL *DeleteGlobalRef)

-      (JNIEnv *env, jobject gref);

-    void (JNICALL *DeleteLocalRef)

-      (JNIEnv *env, jobject obj);

-    jboolean (JNICALL *IsSameObject)

-      (JNIEnv *env, jobject obj1, jobject obj2);

-    void *reserved10;

-    void *reserved11;

-

-    jobject (JNICALL *AllocObject)

-      (JNIEnv *env, jclass clazz);

-    jobject (JNICALL *NewObject)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);

-    jobject (JNICALL *NewObjectV)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

-    jobject (JNICALL *NewObjectA)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

-

-    jclass (JNICALL *GetObjectClass)

-      (JNIEnv *env, jobject obj);

-    jboolean (JNICALL *IsInstanceOf)

-      (JNIEnv *env, jobject obj, jclass clazz);

-

-    jmethodID (JNICALL *GetMethodID)

-      (JNIEnv *env, jclass clazz, const char *name, const char *sig);

-

-    jobject (JNICALL *CallObjectMethod)

-      (JNIEnv *env, jobject obj, jmethodID methodID, ...);

-    jobject (JNICALL *CallObjectMethodV)

-      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

-    jobject (JNICALL *CallObjectMethodA)

-      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args);

-

-    jboolean (JNICALL *CallBooleanMethod)

-      (JNIEnv *env, jobject obj, jmethodID methodID, ...);

-    jboolean (JNICALL *CallBooleanMethodV)

-      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

-    jboolean (JNICALL *CallBooleanMethodA)

-      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args);

-

-    jbyte (JNICALL *CallByteMethod)

-      (JNIEnv *env, jobject obj, jmethodID methodID, ...);

-    jbyte (JNICALL *CallByteMethodV)

-      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

-    jbyte (JNICALL *CallByteMethodA)

-      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);

-

-    jchar (JNICALL *CallCharMethod)

-      (JNIEnv *env, jobject obj, jmethodID methodID, ...);

-    jchar (JNICALL *CallCharMethodV)

-      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

-    jchar (JNICALL *CallCharMethodA)

-      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);

-

-    jshort (JNICALL *CallShortMethod)

-      (JNIEnv *env, jobject obj, jmethodID methodID, ...);

-    jshort (JNICALL *CallShortMethodV)

-      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

-    jshort (JNICALL *CallShortMethodA)

-      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);

-

-    jint (JNICALL *CallIntMethod)

-      (JNIEnv *env, jobject obj, jmethodID methodID, ...);

-    jint (JNICALL *CallIntMethodV)

-      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

-    jint (JNICALL *CallIntMethodA)

-      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);

-

-    jlong (JNICALL *CallLongMethod)

-      (JNIEnv *env, jobject obj, jmethodID methodID, ...);

-    jlong (JNICALL *CallLongMethodV)

-      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

-    jlong (JNICALL *CallLongMethodA)

-      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);

-

-    jfloat (JNICALL *CallFloatMethod)

-      (JNIEnv *env, jobject obj, jmethodID methodID, ...);

-    jfloat (JNICALL *CallFloatMethodV)

-      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

-    jfloat (JNICALL *CallFloatMethodA)

-      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);

-

-    jdouble (JNICALL *CallDoubleMethod)

-      (JNIEnv *env, jobject obj, jmethodID methodID, ...);

-    jdouble (JNICALL *CallDoubleMethodV)

-      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

-    jdouble (JNICALL *CallDoubleMethodA)

-      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);

-

-    void (JNICALL *CallVoidMethod)

-      (JNIEnv *env, jobject obj, jmethodID methodID, ...);

-    void (JNICALL *CallVoidMethodV)

-      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);

-    void (JNICALL *CallVoidMethodA)

-      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args);

-

-    jobject (JNICALL *CallNonvirtualObjectMethod)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);

-    jobject (JNICALL *CallNonvirtualObjectMethodV)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, 

-       va_list args);

-    jobject (JNICALL *CallNonvirtualObjectMethodA)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, 

-       jvalue * args);

-

-    jboolean (JNICALL *CallNonvirtualBooleanMethod)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);

-    jboolean (JNICALL *CallNonvirtualBooleanMethodV)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       va_list args);

-    jboolean (JNICALL *CallNonvirtualBooleanMethodA)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       jvalue * args);

-

-    jbyte (JNICALL *CallNonvirtualByteMethod)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);

-    jbyte (JNICALL *CallNonvirtualByteMethodV)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       va_list args);

-    jbyte (JNICALL *CallNonvirtualByteMethodA)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, 

-       jvalue *args);

-

-    jchar (JNICALL *CallNonvirtualCharMethod)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);

-    jchar (JNICALL *CallNonvirtualCharMethodV)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       va_list args);

-    jchar (JNICALL *CallNonvirtualCharMethodA)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       jvalue *args);

-

-    jshort (JNICALL *CallNonvirtualShortMethod)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);

-    jshort (JNICALL *CallNonvirtualShortMethodV)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       va_list args);

-    jshort (JNICALL *CallNonvirtualShortMethodA)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       jvalue *args);

-

-    jint (JNICALL *CallNonvirtualIntMethod)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);

-    jint (JNICALL *CallNonvirtualIntMethodV)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       va_list args);

-    jint (JNICALL *CallNonvirtualIntMethodA)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       jvalue *args);

-

-    jlong (JNICALL *CallNonvirtualLongMethod)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);

-    jlong (JNICALL *CallNonvirtualLongMethodV)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       va_list args);

-    jlong (JNICALL *CallNonvirtualLongMethodA)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, 

-       jvalue *args);

-

-    jfloat (JNICALL *CallNonvirtualFloatMethod)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);

-    jfloat (JNICALL *CallNonvirtualFloatMethodV)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       va_list args);

-    jfloat (JNICALL *CallNonvirtualFloatMethodA)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       jvalue *args);

-

-    jdouble (JNICALL *CallNonvirtualDoubleMethod)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);

-    jdouble (JNICALL *CallNonvirtualDoubleMethodV)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       va_list args);

-    jdouble (JNICALL *CallNonvirtualDoubleMethodA)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       jvalue *args);

-

-    void (JNICALL *CallNonvirtualVoidMethod)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);

-    void (JNICALL *CallNonvirtualVoidMethodV)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       va_list args);

-    void (JNICALL *CallNonvirtualVoidMethodA)

-      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,

-       jvalue * args);

-

-    jfieldID (JNICALL *GetFieldID)

-      (JNIEnv *env, jclass clazz, const char *name, const char *sig);

-

-    jobject (JNICALL *GetObjectField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID);

-    jboolean (JNICALL *GetBooleanField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID);

-    jbyte (JNICALL *GetByteField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID);

-    jchar (JNICALL *GetCharField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID);

-    jshort (JNICALL *GetShortField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID);

-    jint (JNICALL *GetIntField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID);

-    jlong (JNICALL *GetLongField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID);

-    jfloat (JNICALL *GetFloatField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID);

-    jdouble (JNICALL *GetDoubleField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID);

-

-    void (JNICALL *SetObjectField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val);

-    void (JNICALL *SetBooleanField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val);

-    void (JNICALL *SetByteField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val);

-    void (JNICALL *SetCharField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val);

-    void (JNICALL *SetShortField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val);

-    void (JNICALL *SetIntField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID, jint val);

-    void (JNICALL *SetLongField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val);

-    void (JNICALL *SetFloatField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val);

-    void (JNICALL *SetDoubleField)

-      (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val);

-

-    jmethodID (JNICALL *GetStaticMethodID)

-      (JNIEnv *env, jclass clazz, const char *name, const char *sig);

-

-    jobject (JNICALL *CallStaticObjectMethod)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);

-    jobject (JNICALL *CallStaticObjectMethodV)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

-    jobject (JNICALL *CallStaticObjectMethodA)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

-

-    jboolean (JNICALL *CallStaticBooleanMethod)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);

-    jboolean (JNICALL *CallStaticBooleanMethodV)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

-    jboolean (JNICALL *CallStaticBooleanMethodA)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

-

-    jbyte (JNICALL *CallStaticByteMethod)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);

-    jbyte (JNICALL *CallStaticByteMethodV)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

-    jbyte (JNICALL *CallStaticByteMethodA)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

-

-    jchar (JNICALL *CallStaticCharMethod)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);

-    jchar (JNICALL *CallStaticCharMethodV)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

-    jchar (JNICALL *CallStaticCharMethodA)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

-

-    jshort (JNICALL *CallStaticShortMethod)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);

-    jshort (JNICALL *CallStaticShortMethodV)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

-    jshort (JNICALL *CallStaticShortMethodA)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

-

-    jint (JNICALL *CallStaticIntMethod)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);

-    jint (JNICALL *CallStaticIntMethodV)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

-    jint (JNICALL *CallStaticIntMethodA)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

-

-    jlong (JNICALL *CallStaticLongMethod)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);

-    jlong (JNICALL *CallStaticLongMethodV)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

-    jlong (JNICALL *CallStaticLongMethodA)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

-

-    jfloat (JNICALL *CallStaticFloatMethod)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);

-    jfloat (JNICALL *CallStaticFloatMethodV)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

-    jfloat (JNICALL *CallStaticFloatMethodA)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

-

-    jdouble (JNICALL *CallStaticDoubleMethod)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);

-    jdouble (JNICALL *CallStaticDoubleMethodV)

-      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);

-    jdouble (JNICALL *CallStaticDoubleMethodA)       

-      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

-

-    void (JNICALL *CallStaticVoidMethod)

-      (JNIEnv *env, jclass cls, jmethodID methodID, ...);

-    void (JNICALL *CallStaticVoidMethodV)

-      (JNIEnv *env, jclass cls, jmethodID methodID, va_list args);

-    void (JNICALL *CallStaticVoidMethodA)

-      (JNIEnv *env, jclass cls, jmethodID methodID, jvalue * args);

-

-    jfieldID (JNICALL *GetStaticFieldID)

-      (JNIEnv *env, jclass clazz, const char *name, const char *sig);

-    jobject (JNICALL *GetStaticObjectField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID);

-    jboolean (JNICALL *GetStaticBooleanField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID);

-    jbyte (JNICALL *GetStaticByteField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID);

-    jchar (JNICALL *GetStaticCharField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID);

-    jshort (JNICALL *GetStaticShortField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID);

-    jint (JNICALL *GetStaticIntField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID);

-    jlong (JNICALL *GetStaticLongField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID);

-    jfloat (JNICALL *GetStaticFloatField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID);

-    jdouble (JNICALL *GetStaticDoubleField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID);

-

-    void (JNICALL *SetStaticObjectField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value);

-    void (JNICALL *SetStaticBooleanField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value);

-    void (JNICALL *SetStaticByteField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value);

-    void (JNICALL *SetStaticCharField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value);

-    void (JNICALL *SetStaticShortField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value);

-    void (JNICALL *SetStaticIntField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value);

-    void (JNICALL *SetStaticLongField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value);

-    void (JNICALL *SetStaticFloatField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value);

-    void (JNICALL *SetStaticDoubleField)

-      (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value);

-

-    jstring (JNICALL *NewString)

-      (JNIEnv *env, const jchar *unicode, jsize len);

-    jsize (JNICALL *GetStringLength)

-      (JNIEnv *env, jstring str);

-    const jchar *(JNICALL *GetStringChars)

-      (JNIEnv *env, jstring str, jboolean *isCopy);

-    void (JNICALL *ReleaseStringChars)

-      (JNIEnv *env, jstring str, const jchar *chars);

-  

-    jstring (JNICALL *NewStringUTF)

-      (JNIEnv *env, const char *utf);

-    jsize (JNICALL *GetStringUTFLength)

-      (JNIEnv *env, jstring str);

-    const char* (JNICALL *GetStringUTFChars)

-      (JNIEnv *env, jstring str, jboolean *isCopy);

-    void (JNICALL *ReleaseStringUTFChars)

-      (JNIEnv *env, jstring str, const char* chars);

-  

-

-    jsize (JNICALL *GetArrayLength)

-      (JNIEnv *env, jarray array);

-

-    jobjectArray (JNICALL *NewObjectArray)

-      (JNIEnv *env, jsize len, jclass clazz, jobject init);

-    jobject (JNICALL *GetObjectArrayElement)

-      (JNIEnv *env, jobjectArray array, jsize index);

-    void (JNICALL *SetObjectArrayElement)

-      (JNIEnv *env, jobjectArray array, jsize index, jobject val);

-

-    jbooleanArray (JNICALL *NewBooleanArray)

-      (JNIEnv *env, jsize len);

-    jbyteArray (JNICALL *NewByteArray)

-      (JNIEnv *env, jsize len);

-    jcharArray (JNICALL *NewCharArray)

-      (JNIEnv *env, jsize len);

-    jshortArray (JNICALL *NewShortArray)

-      (JNIEnv *env, jsize len);

-    jintArray (JNICALL *NewIntArray)

-      (JNIEnv *env, jsize len);

-    jlongArray (JNICALL *NewLongArray)

-      (JNIEnv *env, jsize len);

-    jfloatArray (JNICALL *NewFloatArray)

-      (JNIEnv *env, jsize len);

-    jdoubleArray (JNICALL *NewDoubleArray)

-      (JNIEnv *env, jsize len);

-

-    jboolean * (JNICALL *GetBooleanArrayElements)

-      (JNIEnv *env, jbooleanArray array, jboolean *isCopy);

-    jbyte * (JNICALL *GetByteArrayElements)

-      (JNIEnv *env, jbyteArray array, jboolean *isCopy);

-    jchar * (JNICALL *GetCharArrayElements)

-      (JNIEnv *env, jcharArray array, jboolean *isCopy);

-    jshort * (JNICALL *GetShortArrayElements)

-      (JNIEnv *env, jshortArray array, jboolean *isCopy);

-    jint * (JNICALL *GetIntArrayElements)

-      (JNIEnv *env, jintArray array, jboolean *isCopy);

-    jlong * (JNICALL *GetLongArrayElements)

-      (JNIEnv *env, jlongArray array, jboolean *isCopy);

-    jfloat * (JNICALL *GetFloatArrayElements)

-      (JNIEnv *env, jfloatArray array, jboolean *isCopy);

-    jdouble * (JNICALL *GetDoubleArrayElements)

-      (JNIEnv *env, jdoubleArray array, jboolean *isCopy);

-

-    void (JNICALL *ReleaseBooleanArrayElements)

-      (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode);

-    void (JNICALL *ReleaseByteArrayElements)

-      (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode);

-    void (JNICALL *ReleaseCharArrayElements)

-      (JNIEnv *env, jcharArray array, jchar *elems, jint mode);

-    void (JNICALL *ReleaseShortArrayElements)

-      (JNIEnv *env, jshortArray array, jshort *elems, jint mode);

-    void (JNICALL *ReleaseIntArrayElements)

-      (JNIEnv *env, jintArray array, jint *elems, jint mode);

-    void (JNICALL *ReleaseLongArrayElements)

-      (JNIEnv *env, jlongArray array, jlong *elems, jint mode);

-    void (JNICALL *ReleaseFloatArrayElements)

-      (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode);

-    void (JNICALL *ReleaseDoubleArrayElements)

-      (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode);

-

-    void (JNICALL *GetBooleanArrayRegion)

-      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf);

-    void (JNICALL *GetByteArrayRegion)

-      (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);

-    void (JNICALL *GetCharArrayRegion)

-      (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf);

-    void (JNICALL *GetShortArrayRegion)

-      (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf);

-    void (JNICALL *GetIntArrayRegion)

-      (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf);

-    void (JNICALL *GetLongArrayRegion)

-      (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf);

-    void (JNICALL *GetFloatArrayRegion)

-      (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf);

-    void (JNICALL *GetDoubleArrayRegion)

-      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf);

-

-    void (JNICALL *SetBooleanArrayRegion)

-      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf);

-    void (JNICALL *SetByteArrayRegion)

-      (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);

-    void (JNICALL *SetCharArrayRegion)

-      (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf);

-    void (JNICALL *SetShortArrayRegion)

-      (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf);

-    void (JNICALL *SetIntArrayRegion)

-      (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf);

-    void (JNICALL *SetLongArrayRegion)

-      (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf);

-    void (JNICALL *SetFloatArrayRegion)

-      (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf);

-    void (JNICALL *SetDoubleArrayRegion)

-      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf);

-

-    jint (JNICALL *RegisterNatives)

-      (JNIEnv *env, jclass clazz, const JNINativeMethod *methods, 

-       jint nMethods);

-    jint (JNICALL *UnregisterNatives)

-      (JNIEnv *env, jclass clazz);

-

-    jint (JNICALL *MonitorEnter)

-      (JNIEnv *env, jobject obj);

-    jint (JNICALL *MonitorExit)

-      (JNIEnv *env, jobject obj);

- 

-    jint (JNICALL *GetJavaVM)

-      (JNIEnv *env, JavaVM **vm);

-};

-

-/*

- * We use inlined functions for C++ so that programmers can write:

- * 

- *    env->FindClass("java/lang/String")

- *

- * in C++ rather than:

- *

- *    (*env)->FindClass(env, "java/lang/String")

- *

- * in C.

- */

-

-struct JNIEnv_ {

-    const struct JNINativeInterface_ *functions;

-    void *reserved0;

-    void *reserved1[6];

-#ifdef __cplusplus

-

-    jint GetVersion() {

-        return functions->GetVersion(this);

-    }

-    jclass DefineClass(const char *name, jobject loader, const jbyte *buf,

-		       jsize len) {

-        return functions->DefineClass(this, name, loader, buf, len);

-    }

-    jclass FindClass(const char *name) {

-        return functions->FindClass(this, name);

-    }

-    jclass GetSuperclass(jclass sub) {

-        return functions->GetSuperclass(this, sub);

-    }

-    jboolean IsAssignableFrom(jclass sub, jclass sup) {

-        return functions->IsAssignableFrom(this, sub, sup);

-    }

-

-    jint Throw(jthrowable obj) {

-        return functions->Throw(this, obj);

-    }    

-    jint ThrowNew(jclass clazz, const char *msg) {

-        return functions->ThrowNew(this, clazz, msg);

-    }

-    jthrowable ExceptionOccurred() {

-        return functions->ExceptionOccurred(this);

-    }

-    void ExceptionDescribe() {

-        functions->ExceptionDescribe(this);

-    }

-    void ExceptionClear() {

-        functions->ExceptionClear(this);

-    }

-    void FatalError(const char *msg) {

-        functions->FatalError(this, msg);

-    }

-

-    jobject NewGlobalRef(jobject lobj) {

-        return functions->NewGlobalRef(this,lobj);

-    }

-    void DeleteGlobalRef(jobject gref) {

-        functions->DeleteGlobalRef(this,gref);

-    }

-    void DeleteLocalRef(jobject obj) {

-        functions->DeleteLocalRef(this, obj);

-    }

-

-    jboolean IsSameObject(jobject obj1, jobject obj2) {

-        return functions->IsSameObject(this,obj1,obj2);

-    }

-

-    jobject AllocObject(jclass clazz) {

-        return functions->AllocObject(this,clazz);

-    }

-    jobject NewObject(jclass clazz, jmethodID methodID, ...) {

-        va_list args;

-	jobject result;

-	va_start(args, methodID);

-        result = functions->NewObjectV(this,clazz,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jobject NewObjectV(jclass clazz, jmethodID methodID, 

-		       va_list args) {

-        return functions->NewObjectV(this,clazz,methodID,args);

-    }

-    jobject NewObjectA(jclass clazz, jmethodID methodID, 

-		       jvalue *args) {

-        return functions->NewObjectA(this,clazz,methodID,args);

-    }

-

-    jclass GetObjectClass(jobject obj) {

-        return functions->GetObjectClass(this,obj);

-    }

-    jboolean IsInstanceOf(jobject obj, jclass clazz) {

-        return functions->IsInstanceOf(this,obj,clazz);

-    }

-

-    jmethodID GetMethodID(jclass clazz, const char *name, 

-			  const char *sig) {

-        return functions->GetMethodID(this,clazz,name,sig);

-    }

-

-    jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) {

-        va_list args;

-	jobject result;

-	va_start(args,methodID);

-	result = functions->CallObjectMethodV(this,obj,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jobject CallObjectMethodV(jobject obj, jmethodID methodID, 

-			va_list args) {

-        return functions->CallObjectMethodV(this,obj,methodID,args);

-    }

-    jobject CallObjectMethodA(jobject obj, jmethodID methodID, 

-			jvalue * args) {

-        return functions->CallObjectMethodA(this,obj,methodID,args);

-    }

-

-    jboolean CallBooleanMethod(jobject obj, 

-			       jmethodID methodID, ...) {

-        va_list args;

-	jboolean result;

-	va_start(args,methodID);

-	result = functions->CallBooleanMethodV(this,obj,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, 

-				va_list args) {

-        return functions->CallBooleanMethodV(this,obj,methodID,args);

-    }

-    jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, 

-				jvalue * args) {

-        return functions->CallBooleanMethodA(this,obj,methodID, args);

-    }

-

-    jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) {

-        va_list args;

-	jbyte result;

-	va_start(args,methodID);

-	result = functions->CallByteMethodV(this,obj,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jbyte CallByteMethodV(jobject obj, jmethodID methodID, 

-			  va_list args) {

-        return functions->CallByteMethodV(this,obj,methodID,args);

-    }

-    jbyte CallByteMethodA(jobject obj, jmethodID methodID, 

-			  jvalue * args) {

-        return functions->CallByteMethodA(this,obj,methodID,args);

-    }

-

-    jchar CallCharMethod(jobject obj, jmethodID methodID, ...) {

-        va_list args;

-	jchar result;

-	va_start(args,methodID);

-	result = functions->CallCharMethodV(this,obj,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jchar CallCharMethodV(jobject obj, jmethodID methodID, 

-			  va_list args) {

-        return functions->CallCharMethodV(this,obj,methodID,args);

-    }

-    jchar CallCharMethodA(jobject obj, jmethodID methodID, 

-			  jvalue * args) {

-        return functions->CallCharMethodA(this,obj,methodID,args);

-    }

-

-    jshort CallShortMethod(jobject obj, jmethodID methodID, ...) {

-        va_list args;

-	jshort result;

-	va_start(args,methodID);

-	result = functions->CallShortMethodV(this,obj,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jshort CallShortMethodV(jobject obj, jmethodID methodID, 

-			    va_list args) {

-        return functions->CallShortMethodV(this,obj,methodID,args);

-    }

-    jshort CallShortMethodA(jobject obj, jmethodID methodID, 

-			    jvalue * args) {

-        return functions->CallShortMethodA(this,obj,methodID,args);

-    }

-

-    jint CallIntMethod(jobject obj, jmethodID methodID, ...) {

-        va_list args;

-	jint result;

-	va_start(args,methodID);

-	result = functions->CallIntMethodV(this,obj,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jint CallIntMethodV(jobject obj, jmethodID methodID, 

-			va_list args) {

-        return functions->CallIntMethodV(this,obj,methodID,args);

-    }

-    jint CallIntMethodA(jobject obj, jmethodID methodID, 

-			jvalue * args) {

-        return functions->CallIntMethodA(this,obj,methodID,args);

-    }

-

-    jlong CallLongMethod(jobject obj, jmethodID methodID, ...) {

-        va_list args;

-	jlong result;

-	va_start(args,methodID);

-	result = functions->CallLongMethodV(this,obj,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jlong CallLongMethodV(jobject obj, jmethodID methodID, 

-			  va_list args) {

-        return functions->CallLongMethodV(this,obj,methodID,args);

-    }

-    jlong CallLongMethodA(jobject obj, jmethodID methodID, 

-			  jvalue * args) {

-        return functions->CallLongMethodA(this,obj,methodID,args);

-    }

-

-    jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) {

-        va_list args;

-	jfloat result;

-	va_start(args,methodID);

-	result = functions->CallFloatMethodV(this,obj,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jfloat CallFloatMethodV(jobject obj, jmethodID methodID, 

-			    va_list args) {

-        return functions->CallFloatMethodV(this,obj,methodID,args);

-    }

-    jfloat CallFloatMethodA(jobject obj, jmethodID methodID, 

-			    jvalue * args) {

-        return functions->CallFloatMethodA(this,obj,methodID,args);

-    }

-

-    jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) {

-        va_list args;

-	jdouble result;

-	va_start(args,methodID);

-	result = functions->CallDoubleMethodV(this,obj,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, 

-			va_list args) {

-        return functions->CallDoubleMethodV(this,obj,methodID,args);

-    }

-    jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, 

-			jvalue * args) {

-        return functions->CallDoubleMethodA(this,obj,methodID,args);

-    }

-

-    void CallVoidMethod(jobject obj, jmethodID methodID, ...) {

-        va_list args;

-	va_start(args,methodID);

-	functions->CallVoidMethodV(this,obj,methodID,args);

-	va_end(args);

-    }

-    void CallVoidMethodV(jobject obj, jmethodID methodID, 

-			 va_list args) {

-        functions->CallVoidMethodV(this,obj,methodID,args);

-    }

-    void CallVoidMethodA(jobject obj, jmethodID methodID, 

-			 jvalue * args) {

-        functions->CallVoidMethodA(this,obj,methodID,args);

-    }

-

-    jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz, 

-				       jmethodID methodID, ...) {

-        va_list args;

-	jobject result;

-	va_start(args,methodID);

-	result = functions->CallNonvirtualObjectMethodV(this,obj,clazz,

-							methodID,args);

-	va_end(args);

-	return result;

-    }

-    jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz, 

-					jmethodID methodID, va_list args) {

-        return functions->CallNonvirtualObjectMethodV(this,obj,clazz,

-						      methodID,args);

-    }

-    jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz, 

-					jmethodID methodID, jvalue * args) {

-        return functions->CallNonvirtualObjectMethodA(this,obj,clazz,

-						      methodID,args);

-    }

-

-    jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz, 

-					 jmethodID methodID, ...) {

-        va_list args;

-	jboolean result;

-	va_start(args,methodID);

-	result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz,

-							 methodID,args);

-	va_end(args);

-	return result;

-    }

-    jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, 

-					  jmethodID methodID, va_list args) {

-        return functions->CallNonvirtualBooleanMethodV(this,obj,clazz,

-						       methodID,args);

-    }

-    jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, 

-					  jmethodID methodID, jvalue * args) {

-        return functions->CallNonvirtualBooleanMethodA(this,obj,clazz,

-						       methodID, args);

-    }

-

-    jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz, 

-				   jmethodID methodID, ...) {

-        va_list args;

-	jbyte result;

-	va_start(args,methodID);

-	result = functions->CallNonvirtualByteMethodV(this,obj,clazz,

-						      methodID,args);

-	va_end(args);

-	return result;

-    }

-    jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz, 

-				    jmethodID methodID, va_list args) {

-        return functions->CallNonvirtualByteMethodV(this,obj,clazz,

-						    methodID,args);

-    }

-    jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz, 

-				    jmethodID methodID, jvalue * args) {

-        return functions->CallNonvirtualByteMethodA(this,obj,clazz,

-						    methodID,args);

-    }

-

-    jchar CallNonvirtualCharMethod(jobject obj, jclass clazz, 

-				   jmethodID methodID, ...) {

-        va_list args;

-	jchar result;

-	va_start(args,methodID);

-	result = functions->CallNonvirtualCharMethodV(this,obj,clazz,

-						      methodID,args);

-	va_end(args);

-	return result;

-    }

-    jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz, 

-				    jmethodID methodID, va_list args) {

-        return functions->CallNonvirtualCharMethodV(this,obj,clazz,

-						    methodID,args);

-    }

-    jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz, 

-				    jmethodID methodID, jvalue * args) {

-        return functions->CallNonvirtualCharMethodA(this,obj,clazz,

-						    methodID,args);

-    }

-

-    jshort CallNonvirtualShortMethod(jobject obj, jclass clazz, 

-				     jmethodID methodID, ...) {

-        va_list args;

-	jshort result;

-	va_start(args,methodID);

-	result = functions->CallNonvirtualShortMethodV(this,obj,clazz,

-						       methodID,args);

-	va_end(args);

-	return result;

-    }

-    jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz, 

-				      jmethodID methodID, va_list args) {

-        return functions->CallNonvirtualShortMethodV(this,obj,clazz,

-						     methodID,args);

-    }

-    jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz,

-				      jmethodID methodID, jvalue * args) {

-        return functions->CallNonvirtualShortMethodA(this,obj,clazz,

-						     methodID,args);

-    }

-

-    jint CallNonvirtualIntMethod(jobject obj, jclass clazz, 

-				 jmethodID methodID, ...) {

-        va_list args;

-	jint result;

-	va_start(args,methodID);

-	result = functions->CallNonvirtualIntMethodV(this,obj,clazz,

-						     methodID,args);

-	va_end(args);

-	return result;

-    }

-    jint CallNonvirtualIntMethodV(jobject obj, jclass clazz, 

-				  jmethodID methodID, va_list args) {

-        return functions->CallNonvirtualIntMethodV(this,obj,clazz,

-						   methodID,args);

-    }

-    jint CallNonvirtualIntMethodA(jobject obj, jclass clazz, 

-				  jmethodID methodID, jvalue * args) {

-        return functions->CallNonvirtualIntMethodA(this,obj,clazz,

-						   methodID,args);

-    }

-

-    jlong CallNonvirtualLongMethod(jobject obj, jclass clazz,

-				   jmethodID methodID, ...) {

-        va_list args;

-	jlong result;

-	va_start(args,methodID);

-	result = functions->CallNonvirtualLongMethodV(this,obj,clazz,

-						      methodID,args);

-	va_end(args);

-	return result;

-    }

-    jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz,

-				    jmethodID methodID, va_list args) {

-        return functions->CallNonvirtualLongMethodV(this,obj,clazz,

-						    methodID,args);

-    }

-    jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz, 

-				    jmethodID methodID, jvalue * args) {

-        return functions->CallNonvirtualLongMethodA(this,obj,clazz,

-						    methodID,args);

-    }

-

-    jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz, 

-				     jmethodID methodID, ...) {

-        va_list args;

-	jfloat result;

-	va_start(args,methodID);

-	result = functions->CallNonvirtualFloatMethodV(this,obj,clazz,

-						       methodID,args);

-	va_end(args);

-	return result;

-    }

-    jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz,

-				      jmethodID methodID, 

-				      va_list args) {

-        return functions->CallNonvirtualFloatMethodV(this,obj,clazz,

-						     methodID,args);

-    }

-    jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz, 

-				      jmethodID methodID, 

-				      jvalue * args) {

-        return functions->CallNonvirtualFloatMethodA(this,obj,clazz,

-						     methodID,args);

-    }

-

-    jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz,

-				       jmethodID methodID, ...) {

-        va_list args;

-	jdouble result;

-	va_start(args,methodID);

-	result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz,

-							methodID,args);

-	va_end(args);

-	return result;

-    }

-    jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz,

-					jmethodID methodID, 

-					va_list args) {

-        return functions->CallNonvirtualDoubleMethodV(this,obj,clazz,

-						      methodID,args);

-    }

-    jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, 

-					jmethodID methodID, 

-					jvalue * args) {

-        return functions->CallNonvirtualDoubleMethodA(this,obj,clazz,

-						      methodID,args);

-    }

-

-    void CallNonvirtualVoidMethod(jobject obj, jclass clazz,

-				  jmethodID methodID, ...) {

-        va_list args;

-	va_start(args,methodID);

-	functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args);

-	va_end(args);

-    }

-    void CallNonvirtualVoidMethodV(jobject obj, jclass clazz,

-				   jmethodID methodID, 

-				   va_list args) {

-        functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args);

-    }

-    void CallNonvirtualVoidMethodA(jobject obj, jclass clazz,

-				   jmethodID methodID, 

-				   jvalue * args) {

-        functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args);

-    }

-

-    jfieldID GetFieldID(jclass clazz, const char *name, 

-			const char *sig) {

-        return functions->GetFieldID(this,clazz,name,sig);

-    }

-

-    jobject GetObjectField(jobject obj, jfieldID fieldID) {

-        return functions->GetObjectField(this,obj,fieldID);

-    }

-    jboolean GetBooleanField(jobject obj, jfieldID fieldID) {

-        return functions->GetBooleanField(this,obj,fieldID);

-    }

-    jbyte GetByteField(jobject obj, jfieldID fieldID) {

-        return functions->GetByteField(this,obj,fieldID);

-    }

-    jchar GetCharField(jobject obj, jfieldID fieldID) {

-        return functions->GetCharField(this,obj,fieldID);

-    }

-    jshort GetShortField(jobject obj, jfieldID fieldID) {

-        return functions->GetShortField(this,obj,fieldID);

-    }

-    jint GetIntField(jobject obj, jfieldID fieldID) {

-        return functions->GetIntField(this,obj,fieldID);

-    }

-    jlong GetLongField(jobject obj, jfieldID fieldID) {

-        return functions->GetLongField(this,obj,fieldID);

-    }

-    jfloat GetFloatField(jobject obj, jfieldID fieldID) {

-        return functions->GetFloatField(this,obj,fieldID);

-    }

-    jdouble GetDoubleField(jobject obj, jfieldID fieldID) {

-        return functions->GetDoubleField(this,obj,fieldID);

-    }

-

-    void SetObjectField(jobject obj, jfieldID fieldID, jobject val) {

-        functions->SetObjectField(this,obj,fieldID,val);

-    }

-    void SetBooleanField(jobject obj, jfieldID fieldID, 

-			 jboolean val) {

-        functions->SetBooleanField(this,obj,fieldID,val);

-    }

-    void SetByteField(jobject obj, jfieldID fieldID, 

-		      jbyte val) {

-        functions->SetByteField(this,obj,fieldID,val);

-    }

-    void SetCharField(jobject obj, jfieldID fieldID, 

-		      jchar val) {

-        functions->SetCharField(this,obj,fieldID,val);

-    }

-    void SetShortField(jobject obj, jfieldID fieldID,

-		       jshort val) {

-        functions->SetShortField(this,obj,fieldID,val);

-    }

-    void SetIntField(jobject obj, jfieldID fieldID, 

-		     jint val) {

-        functions->SetIntField(this,obj,fieldID,val);

-    }

-    void SetLongField(jobject obj, jfieldID fieldID, 

-		      jlong val) {

-        functions->SetLongField(this,obj,fieldID,val);

-    }

-    void SetFloatField(jobject obj, jfieldID fieldID, 

-		       jfloat val) {

-        functions->SetFloatField(this,obj,fieldID,val);

-    }

-    void SetDoubleField(jobject obj, jfieldID fieldID, 

-			jdouble val) {

-        functions->SetDoubleField(this,obj,fieldID,val);

-    }

-

-    jmethodID GetStaticMethodID(jclass clazz, const char *name, 

-				const char *sig) {

-        return functions->GetStaticMethodID(this,clazz,name,sig);

-    }

-

-    jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, 

-			     ...) {

-        va_list args;

-	jobject result;

-	va_start(args,methodID);

-	result = functions->CallStaticObjectMethodV(this,clazz,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, 

-			      va_list args) {

-        return functions->CallStaticObjectMethodV(this,clazz,methodID,args);

-    }

-    jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, 

-			      jvalue *args) {

-        return functions->CallStaticObjectMethodA(this,clazz,methodID,args);

-    }

-

-    jboolean CallStaticBooleanMethod(jclass clazz, 

-				     jmethodID methodID, ...) {

-        va_list args;

-	jboolean result;

-	va_start(args,methodID);

-	result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jboolean CallStaticBooleanMethodV(jclass clazz,

-				      jmethodID methodID, va_list args) {

-        return functions->CallStaticBooleanMethodV(this,clazz,methodID,args);

-    }

-    jboolean CallStaticBooleanMethodA(jclass clazz,

-				      jmethodID methodID, jvalue *args) {

-        return functions->CallStaticBooleanMethodA(this,clazz,methodID,args);

-    }

-

-    jbyte CallStaticByteMethod(jclass clazz,

-			       jmethodID methodID, ...) {

-        va_list args;

-	jbyte result;

-	va_start(args,methodID);

-	result = functions->CallStaticByteMethodV(this,clazz,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jbyte CallStaticByteMethodV(jclass clazz,

-				jmethodID methodID, va_list args) {

-        return functions->CallStaticByteMethodV(this,clazz,methodID,args);

-    }

-    jbyte CallStaticByteMethodA(jclass clazz, 

-				jmethodID methodID, jvalue *args) {

-        return functions->CallStaticByteMethodA(this,clazz,methodID,args);

-    }

-

-    jchar CallStaticCharMethod(jclass clazz,

-			       jmethodID methodID, ...) {

-        va_list args;

-	jchar result;

-	va_start(args,methodID);

-	result = functions->CallStaticCharMethodV(this,clazz,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jchar CallStaticCharMethodV(jclass clazz,

-				jmethodID methodID, va_list args) {

-        return functions->CallStaticCharMethodV(this,clazz,methodID,args);

-    }

-    jchar CallStaticCharMethodA(jclass clazz,

-				jmethodID methodID, jvalue *args) {

-        return functions->CallStaticCharMethodA(this,clazz,methodID,args);

-    }

-

-    jshort CallStaticShortMethod(jclass clazz,

-				 jmethodID methodID, ...) {

-        va_list args;

-	jshort result;

-	va_start(args,methodID);

-	result = functions->CallStaticShortMethodV(this,clazz,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jshort CallStaticShortMethodV(jclass clazz,

-				  jmethodID methodID, va_list args) {

-        return functions->CallStaticShortMethodV(this,clazz,methodID,args);

-    }

-    jshort CallStaticShortMethodA(jclass clazz,

-				  jmethodID methodID, jvalue *args) {

-        return functions->CallStaticShortMethodA(this,clazz,methodID,args);

-    }

-

-    jint CallStaticIntMethod(jclass clazz,

-			     jmethodID methodID, ...) {

-        va_list args;

-	jint result;

-	va_start(args,methodID);

-	result = functions->CallStaticIntMethodV(this,clazz,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jint CallStaticIntMethodV(jclass clazz,

-			      jmethodID methodID, va_list args) {

-        return functions->CallStaticIntMethodV(this,clazz,methodID,args);

-    }

-    jint CallStaticIntMethodA(jclass clazz, 

-			      jmethodID methodID, jvalue *args) {

-        return functions->CallStaticIntMethodA(this,clazz,methodID,args);

-    }

-

-    jlong CallStaticLongMethod(jclass clazz,

-			       jmethodID methodID, ...) {

-        va_list args;

-	jlong result;

-	va_start(args,methodID);

-	result = functions->CallStaticLongMethodV(this,clazz,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jlong CallStaticLongMethodV(jclass clazz, 

-				jmethodID methodID, va_list args) {

-        return functions->CallStaticLongMethodV(this,clazz,methodID,args);

-    }

-    jlong CallStaticLongMethodA(jclass clazz, 

-				jmethodID methodID, jvalue *args) {

-        return functions->CallStaticLongMethodA(this,clazz,methodID,args);

-    }

-

-    jfloat CallStaticFloatMethod(jclass clazz, 

-				 jmethodID methodID, ...) {

-        va_list args;

-	jfloat result;

-	va_start(args,methodID);

-	result = functions->CallStaticFloatMethodV(this,clazz,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jfloat CallStaticFloatMethodV(jclass clazz, 

-				  jmethodID methodID, va_list args) {

-        return functions->CallStaticFloatMethodV(this,clazz,methodID,args);

-    }

-    jfloat CallStaticFloatMethodA(jclass clazz, 

-				  jmethodID methodID, jvalue *args) {

-        return functions->CallStaticFloatMethodA(this,clazz,methodID,args);

-    }

-

-    jdouble CallStaticDoubleMethod(jclass clazz, 

-				   jmethodID methodID, ...) {

-        va_list args;

-	jdouble result;

-	va_start(args,methodID);

-	result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args);

-	va_end(args);

-	return result;

-    }

-    jdouble CallStaticDoubleMethodV(jclass clazz, 

-				    jmethodID methodID, va_list args) {

-        return functions->CallStaticDoubleMethodV(this,clazz,methodID,args);

-    }

-    jdouble CallStaticDoubleMethodA(jclass clazz, 

-				    jmethodID methodID, jvalue *args) {

-        return functions->CallStaticDoubleMethodA(this,clazz,methodID,args);

-    }

-

-    void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) {

-        va_list args;

-	va_start(args,methodID);

-	functions->CallStaticVoidMethodV(this,cls,methodID,args);

-	va_end(args);

-    }

-    void CallStaticVoidMethodV(jclass cls, jmethodID methodID, 

-			       va_list args) {

-        functions->CallStaticVoidMethodV(this,cls,methodID,args);

-    }

-    void CallStaticVoidMethodA(jclass cls, jmethodID methodID, 

-			       jvalue * args) {

-        functions->CallStaticVoidMethodA(this,cls,methodID,args);

-    }

-

-    jfieldID GetStaticFieldID(jclass clazz, const char *name, 

-			      const char *sig) {

-        return functions->GetStaticFieldID(this,clazz,name,sig);

-    }

-    jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) {

-        return functions->GetStaticObjectField(this,clazz,fieldID);

-    }

-    jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) {

-        return functions->GetStaticBooleanField(this,clazz,fieldID);

-    }

-    jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) {

-        return functions->GetStaticByteField(this,clazz,fieldID);

-    }

-    jchar GetStaticCharField(jclass clazz, jfieldID fieldID) {

-        return functions->GetStaticCharField(this,clazz,fieldID);

-    }

-    jshort GetStaticShortField(jclass clazz, jfieldID fieldID) {

-        return functions->GetStaticShortField(this,clazz,fieldID);

-    }

-    jint GetStaticIntField(jclass clazz, jfieldID fieldID) {

-        return functions->GetStaticIntField(this,clazz,fieldID);

-    }

-    jlong GetStaticLongField(jclass clazz, jfieldID fieldID) {

-        return functions->GetStaticLongField(this,clazz,fieldID);

-    }

-    jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) {

-        return functions->GetStaticFloatField(this,clazz,fieldID);

-    }

-    jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) {

-        return functions->GetStaticDoubleField(this,clazz,fieldID);

-    }

-

-    void SetStaticObjectField(jclass clazz, jfieldID fieldID,

-			jobject value) {

-      functions->SetStaticObjectField(this,clazz,fieldID,value);

-    }

-    void SetStaticBooleanField(jclass clazz, jfieldID fieldID,

-			jboolean value) {

-      functions->SetStaticBooleanField(this,clazz,fieldID,value);

-    }

-    void SetStaticByteField(jclass clazz, jfieldID fieldID,

-			jbyte value) {

-      functions->SetStaticByteField(this,clazz,fieldID,value);

-    }

-    void SetStaticCharField(jclass clazz, jfieldID fieldID,

-			jchar value) {

-      functions->SetStaticCharField(this,clazz,fieldID,value);

-    }

-    void SetStaticShortField(jclass clazz, jfieldID fieldID,

-			jshort value) {

-      functions->SetStaticShortField(this,clazz,fieldID,value);

-    }

-    void SetStaticIntField(jclass clazz, jfieldID fieldID,

-			jint value) {

-      functions->SetStaticIntField(this,clazz,fieldID,value);

-    }

-    void SetStaticLongField(jclass clazz, jfieldID fieldID,

-			jlong value) {

-      functions->SetStaticLongField(this,clazz,fieldID,value);

-    }

-    void SetStaticFloatField(jclass clazz, jfieldID fieldID,

-			jfloat value) {

-      functions->SetStaticFloatField(this,clazz,fieldID,value);

-    }

-    void SetStaticDoubleField(jclass clazz, jfieldID fieldID,

-			jdouble value) {

-      functions->SetStaticDoubleField(this,clazz,fieldID,value);

-    }

-

-    jstring NewString(const jchar *unicode, jsize len) {

-        return functions->NewString(this,unicode,len);

-    }

-    jsize GetStringLength(jstring str) {

-        return functions->GetStringLength(this,str);

-    }

-    const jchar *GetStringChars(jstring str, jboolean *isCopy) {

-        return functions->GetStringChars(this,str,isCopy);

-    }

-    void ReleaseStringChars(jstring str, const jchar *chars) {

-        functions->ReleaseStringChars(this,str,chars);

-    }

-  

-    jstring NewStringUTF(const char *utf) {

-        return functions->NewStringUTF(this,utf);

-    }

-    jsize GetStringUTFLength(jstring str) {

-        return functions->GetStringUTFLength(this,str);

-    }

-    const char* GetStringUTFChars(jstring str, jboolean *isCopy) {

-        return functions->GetStringUTFChars(this,str,isCopy);

-    }

-    void ReleaseStringUTFChars(jstring str, const char* chars) {

-        functions->ReleaseStringUTFChars(this,str,chars);

-    }

-

-    jsize GetArrayLength(jarray array) {

-        return functions->GetArrayLength(this,array);

-    }

-

-    jobjectArray NewObjectArray(jsize len, jclass clazz, 

-				jobject init) {

-        return functions->NewObjectArray(this,len,clazz,init);

-    }

-    jobject GetObjectArrayElement(jobjectArray array, jsize index) {

-        return functions->GetObjectArrayElement(this,array,index);

-    }

-    void SetObjectArrayElement(jobjectArray array, jsize index, 

-			       jobject val) {

-        functions->SetObjectArrayElement(this,array,index,val);

-    }

-

-    jbooleanArray NewBooleanArray(jsize len) {

-        return functions->NewBooleanArray(this,len);

-    }

-    jbyteArray NewByteArray(jsize len) {

-        return functions->NewByteArray(this,len);

-    }

-    jcharArray NewCharArray(jsize len) {

-        return functions->NewCharArray(this,len);

-    }

-    jshortArray NewShortArray(jsize len) {

-        return functions->NewShortArray(this,len);

-    }

-    jintArray NewIntArray(jsize len) {

-        return functions->NewIntArray(this,len);

-    }

-    jlongArray NewLongArray(jsize len) {

-        return functions->NewLongArray(this,len);

-    }

-    jfloatArray NewFloatArray(jsize len) {

-        return functions->NewFloatArray(this,len);

-    }

-    jdoubleArray NewDoubleArray(jsize len) {

-        return functions->NewDoubleArray(this,len);

-    }

-

-    jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) {

-        return functions->GetBooleanArrayElements(this,array,isCopy);

-    }

-    jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) {

-        return functions->GetByteArrayElements(this,array,isCopy);

-    }

-    jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) {

-        return functions->GetCharArrayElements(this,array,isCopy);

-    }

-    jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) {

-        return functions->GetShortArrayElements(this,array,isCopy);

-    }

-    jint * GetIntArrayElements(jintArray array, jboolean *isCopy) {

-        return functions->GetIntArrayElements(this,array,isCopy);

-    }

-    jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) {

-        return functions->GetLongArrayElements(this,array,isCopy);

-    }

-    jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) {

-        return functions->GetFloatArrayElements(this,array,isCopy);

-    }

-    jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) {

-        return functions->GetDoubleArrayElements(this,array,isCopy);

-    }

-

-    void ReleaseBooleanArrayElements(jbooleanArray array, 

-				     jboolean *elems,

-				     jint mode) {

-        functions->ReleaseBooleanArrayElements(this,array,elems,mode);

-    }

-    void ReleaseByteArrayElements(jbyteArray array, 

-				  jbyte *elems,

-				  jint mode) {

-        functions->ReleaseByteArrayElements(this,array,elems,mode);

-    }

-    void ReleaseCharArrayElements(jcharArray array, 

-				  jchar *elems,

-				  jint mode) {

-        functions->ReleaseCharArrayElements(this,array,elems,mode);

-    }

-    void ReleaseShortArrayElements(jshortArray array, 

-				   jshort *elems,

-				   jint mode) {

-        functions->ReleaseShortArrayElements(this,array,elems,mode);

-    }

-    void ReleaseIntArrayElements(jintArray array, 

-				 jint *elems,

-				 jint mode) {

-        functions->ReleaseIntArrayElements(this,array,elems,mode);

-    }

-    void ReleaseLongArrayElements(jlongArray array, 

-				  jlong *elems,

-				  jint mode) {

-        functions->ReleaseLongArrayElements(this,array,elems,mode);

-    }

-    void ReleaseFloatArrayElements(jfloatArray array, 

-				   jfloat *elems,

-				   jint mode) {

-        functions->ReleaseFloatArrayElements(this,array,elems,mode);

-    }

-    void ReleaseDoubleArrayElements(jdoubleArray array, 

-				    jdouble *elems,

-				    jint mode) {

-        functions->ReleaseDoubleArrayElements(this,array,elems,mode);

-    }

-

-    void GetBooleanArrayRegion(jbooleanArray array, 

-			       jsize start, jsize len, jboolean *buf) {

-        functions->GetBooleanArrayRegion(this,array,start,len,buf);

-    }

-    void GetByteArrayRegion(jbyteArray array, 

-			    jsize start, jsize len, jbyte *buf) {

-        functions->GetByteArrayRegion(this,array,start,len,buf);

-    }

-    void GetCharArrayRegion(jcharArray array, 

-			    jsize start, jsize len, jchar *buf) {

-        functions->GetCharArrayRegion(this,array,start,len,buf);

-    }

-    void GetShortArrayRegion(jshortArray array, 

-			     jsize start, jsize len, jshort *buf) {

-        functions->GetShortArrayRegion(this,array,start,len,buf);

-    }

-    void GetIntArrayRegion(jintArray array, 

-			   jsize start, jsize len, jint *buf) {

-        functions->GetIntArrayRegion(this,array,start,len,buf);

-    }

-    void GetLongArrayRegion(jlongArray array, 

-			    jsize start, jsize len, jlong *buf) {

-        functions->GetLongArrayRegion(this,array,start,len,buf);

-    }

-    void GetFloatArrayRegion(jfloatArray array, 

-			     jsize start, jsize len, jfloat *buf) {

-        functions->GetFloatArrayRegion(this,array,start,len,buf);

-    }

-    void GetDoubleArrayRegion(jdoubleArray array, 

-			      jsize start, jsize len, jdouble *buf) {

-        functions->GetDoubleArrayRegion(this,array,start,len,buf);

-    }

-

-    void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, 

-			       jboolean *buf) {

-        functions->SetBooleanArrayRegion(this,array,start,len,buf);

-    }

-    void SetByteArrayRegion(jbyteArray array, jsize start, jsize len,

-			    jbyte *buf) {

-        functions->SetByteArrayRegion(this,array,start,len,buf);

-    }

-    void SetCharArrayRegion(jcharArray array, jsize start, jsize len, 

-			    jchar *buf) {

-        functions->SetCharArrayRegion(this,array,start,len,buf);

-    }

-    void SetShortArrayRegion(jshortArray array, jsize start, jsize len, 

-			     jshort *buf) {

-        functions->SetShortArrayRegion(this,array,start,len,buf);

-    }

-    void SetIntArrayRegion(jintArray array, jsize start, jsize len,

-			   jint *buf) {

-        functions->SetIntArrayRegion(this,array,start,len,buf);

-    }

-    void SetLongArrayRegion(jlongArray array, jsize start, jsize len,

-			    jlong *buf) {

-        functions->SetLongArrayRegion(this,array,start,len,buf);

-    }

-    void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, 

-			     jfloat *buf) {

-        functions->SetFloatArrayRegion(this,array,start,len,buf);

-    }

-    void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,

-			      jdouble *buf) {

-        functions->SetDoubleArrayRegion(this,array,start,len,buf);

-    }

-

-    jint RegisterNatives(jclass clazz, const JNINativeMethod *methods,

-			 jint nMethods) {

-        return functions->RegisterNatives(this,clazz,methods,nMethods);

-    }

-    jint UnregisterNatives(jclass clazz) {

-        return functions->UnregisterNatives(this,clazz);

-    }  

-   

-    jint MonitorEnter(jobject obj) {

-        return functions->MonitorEnter(this,obj);

-    }

-    jint MonitorExit(jobject obj) {

-        return functions->MonitorExit(this,obj);

-    }

-

-    jint GetJavaVM(JavaVM **vm) {

-        return functions->GetJavaVM(this,vm);

-    }

-  

-#endif /* __cplusplus */

-};

-

-/* These structures will be VM-specific. */

-

-typedef struct JDK1_1InitArgs {

-    jint version;

-

-    char **properties;

-    jint checkSource; 

-    jint nativeStackSize;

-    jint javaStackSize;

-    jint minHeapSize;

-    jint maxHeapSize;

-    jint verifyMode;

-    char *classpath;

-

-    jint (JNICALL *vfprintf)(FILE *fp, const char *format, va_list args);

-    void (JNICALL *exit)(jint code);

-    void (JNICALL *abort)();

-    

-    jint enableClassGC;

-    jint enableVerboseGC;

-    jint disableAsyncGC;

-    jint verbose;

-    jboolean debugging;

-    jint debugPort;

-} JDK1_1InitArgs;

-

-typedef struct JDK1_1AttachArgs {

-    void * __padding; /* C compilers don't allow empty structures. */

-} JDK1_1AttachArgs;

-

-/* End VM-specific. */

-

-struct JNIInvokeInterface_ {

-    void *reserved0;

-    void *reserved1;

-    void *reserved2;

-

-    jint (JNICALL *DestroyJavaVM)(JavaVM *vm);

-

-    jint (JNICALL *AttachCurrentThread)

-      (JavaVM *vm, JNIEnv **penv, void *args);

-

-    jint (JNICALL *DetachCurrentThread)(JavaVM *vm);

-};

-

-struct JavaVM_ {

-    const struct JNIInvokeInterface_ *functions;

-    void *reserved0;

-    void *reserved1;

-    void *reserved2;

-#ifdef __cplusplus

-

-    jint DestroyJavaVM() {

-        return functions->DestroyJavaVM(this);

-    }

-    jint AttachCurrentThread(JNIEnv **penv, void *args) {

-        return functions->AttachCurrentThread(this, penv, args);

-    }

-    jint DetachCurrentThread() {

-        return functions->DetachCurrentThread(this);

-    }

-

-#endif

-};

-

-JNI_PUBLIC_API(void) JNI_GetDefaultJavaVMInitArgs(void *);

-

-JNI_PUBLIC_API(jint) JNI_CreateJavaVM(JavaVM **, JNIEnv **, void *);

-

-JNI_PUBLIC_API(jint) JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *);

-JNI_PUBLIC_API(jref) JNI_MakeLocalRef(JNIEnv *pJNIEnv, void *pHObject);

-

-#ifdef __cplusplus

-} /* extern "C" */

-#endif /* __cplusplus */

-

-#endif /* JNI_H */

-

-

+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Java Runtime Interface.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation and Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 1993-1996
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef JNI_H
+#define JNI_H
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* jni_md.h contains the machine-dependent typedefs for jbyte, jint 
+   and jlong */ 
+
+#include "jni_md.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * JNI Types
+ */
+
+typedef unsigned char	jboolean;
+typedef unsigned short	jchar;
+typedef short		jshort;
+typedef float		jfloat;
+typedef double		jdouble;
+
+typedef jint            jsize;
+
+#ifdef __cplusplus
+
+class _jobject {};
+class _jclass : public _jobject {};
+class _jthrowable : public _jobject {};
+class _jstring : public _jobject {};
+class _jarray : public _jobject {};
+class _jbooleanArray : public _jarray {};
+class _jbyteArray : public _jarray {};
+class _jcharArray : public _jarray {};
+class _jshortArray : public _jarray {};
+class _jintArray : public _jarray {};
+class _jlongArray : public _jarray {};
+class _jfloatArray : public _jarray {};
+class _jdoubleArray : public _jarray {};
+class _jobjectArray : public _jarray {};
+
+typedef _jobject *jobject;
+typedef _jclass *jclass;
+typedef _jthrowable *jthrowable;
+typedef _jstring *jstring;
+typedef _jarray *jarray;
+typedef _jbooleanArray *jbooleanArray;
+typedef _jbyteArray *jbyteArray;
+typedef _jcharArray *jcharArray;
+typedef _jshortArray *jshortArray;
+typedef _jintArray *jintArray;
+typedef _jlongArray *jlongArray;
+typedef _jfloatArray *jfloatArray;
+typedef _jdoubleArray *jdoubleArray;
+typedef _jobjectArray *jobjectArray;
+
+#else
+
+struct _jobject;
+
+typedef struct _jobject *jobject;
+typedef jobject jclass;
+typedef jobject jthrowable;
+typedef jobject jstring;
+typedef jobject jarray;
+typedef jarray jbooleanArray;
+typedef jarray jbyteArray;
+typedef jarray jcharArray;
+typedef jarray jshortArray;
+typedef jarray jintArray;
+typedef jarray jlongArray;
+typedef jarray jfloatArray;
+typedef jarray jdoubleArray;
+typedef jarray jobjectArray;
+
+#endif
+
+#if 0	/* moved to jri_md.h */
+typedef jobject jref; /* For transition---not meant to be part of public 
+			 API anymore.*/
+#endif
+
+typedef union jvalue {
+    jboolean z;
+    jbyte    b;
+    jchar    c;
+    jshort   s;
+    jint     i;
+    jlong    j;
+    jfloat   f;
+    jdouble  d;
+    jobject  l;
+} jvalue;
+
+struct _jfieldID;
+typedef struct _jfieldID *jfieldID;
+
+struct _jmethodID;
+typedef struct _jmethodID *jmethodID;
+
+/*
+ * jboolean constants
+ */
+
+#define JNI_FALSE 0
+#define JNI_TRUE 1
+
+/*
+ * possible return values for JNI functions.
+ */
+
+#define JNI_OK 0
+#define JNI_ERR (-1)
+
+/*
+ * used in ReleaseScalarArrayElements
+ */
+  
+#define JNI_COMMIT 1
+#define JNI_ABORT 2
+
+/*
+ * used in RegisterNatives to describe native method name, signature,
+ * and function pointer.
+ */
+
+typedef struct {
+    char *name;
+    char *signature;
+    void *fnPtr;
+} JNINativeMethod;
+
+/*
+ * JNI Native Method Interface.
+ */
+
+struct JNINativeInterface_;
+
+struct JNIEnv_;
+
+#ifdef __cplusplus
+typedef JNIEnv_ JNIEnv;
+#else
+typedef const struct JNINativeInterface_ *JNIEnv;
+#endif
+
+/*
+ * JNI Invocation Interface.
+ */
+
+struct JNIInvokeInterface_;
+
+struct JavaVM_;
+
+#ifdef __cplusplus
+typedef JavaVM_ JavaVM;
+#else
+typedef const struct JNIInvokeInterface_ *JavaVM;
+#endif
+
+struct JNINativeInterface_ {
+    void *reserved0;
+    void *reserved1;
+    void *reserved2;
+
+    void *reserved3;
+    jint (JNICALL *GetVersion)(JNIEnv *env);
+
+    jclass (JNICALL *DefineClass)
+      (JNIEnv *env, const char *name, jobject loader, const jbyte *buf, 
+       jsize len);
+    jclass (JNICALL *FindClass)
+      (JNIEnv *env, const char *name);
+
+    void *reserved4;
+    void *reserved5;
+    void *reserved6;
+
+    jclass (JNICALL *GetSuperclass)
+      (JNIEnv *env, jclass sub);
+    jboolean (JNICALL *IsAssignableFrom)
+      (JNIEnv *env, jclass sub, jclass sup);
+    void *reserved7;
+
+
+    jint (JNICALL *Throw)
+      (JNIEnv *env, jthrowable obj);
+    jint (JNICALL *ThrowNew)
+      (JNIEnv *env, jclass clazz, const char *msg);
+    jthrowable (JNICALL *ExceptionOccurred)
+      (JNIEnv *env);
+    void (JNICALL *ExceptionDescribe)
+      (JNIEnv *env);
+    void (JNICALL *ExceptionClear)
+      (JNIEnv *env);
+    void (JNICALL *FatalError)
+      (JNIEnv *env, const char *msg);
+    void *reserved8;
+    void *reserved9;
+
+    jobject (JNICALL *NewGlobalRef)
+      (JNIEnv *env, jobject lobj);
+    void (JNICALL *DeleteGlobalRef)
+      (JNIEnv *env, jobject gref);
+    void (JNICALL *DeleteLocalRef)
+      (JNIEnv *env, jobject obj);
+    jboolean (JNICALL *IsSameObject)
+      (JNIEnv *env, jobject obj1, jobject obj2);
+    void *reserved10;
+    void *reserved11;
+
+    jobject (JNICALL *AllocObject)
+      (JNIEnv *env, jclass clazz);
+    jobject (JNICALL *NewObject)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jobject (JNICALL *NewObjectV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jobject (JNICALL *NewObjectA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
+
+    jclass (JNICALL *GetObjectClass)
+      (JNIEnv *env, jobject obj);
+    jboolean (JNICALL *IsInstanceOf)
+      (JNIEnv *env, jobject obj, jclass clazz);
+
+    jmethodID (JNICALL *GetMethodID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+    jobject (JNICALL *CallObjectMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jobject (JNICALL *CallObjectMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jobject (JNICALL *CallObjectMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args);
+
+    jboolean (JNICALL *CallBooleanMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jboolean (JNICALL *CallBooleanMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jboolean (JNICALL *CallBooleanMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args);
+
+    jbyte (JNICALL *CallByteMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jbyte (JNICALL *CallByteMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jbyte (JNICALL *CallByteMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
+
+    jchar (JNICALL *CallCharMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jchar (JNICALL *CallCharMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jchar (JNICALL *CallCharMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
+
+    jshort (JNICALL *CallShortMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jshort (JNICALL *CallShortMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jshort (JNICALL *CallShortMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
+
+    jint (JNICALL *CallIntMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jint (JNICALL *CallIntMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jint (JNICALL *CallIntMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
+
+    jlong (JNICALL *CallLongMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jlong (JNICALL *CallLongMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jlong (JNICALL *CallLongMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
+
+    jfloat (JNICALL *CallFloatMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jfloat (JNICALL *CallFloatMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jfloat (JNICALL *CallFloatMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
+
+    jdouble (JNICALL *CallDoubleMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    jdouble (JNICALL *CallDoubleMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    jdouble (JNICALL *CallDoubleMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args);
+
+    void (JNICALL *CallVoidMethod)
+      (JNIEnv *env, jobject obj, jmethodID methodID, ...);
+    void (JNICALL *CallVoidMethodV)
+      (JNIEnv *env, jobject obj, jmethodID methodID, va_list args);
+    void (JNICALL *CallVoidMethodA)
+      (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args);
+
+    jobject (JNICALL *CallNonvirtualObjectMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jobject (JNICALL *CallNonvirtualObjectMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, 
+       va_list args);
+    jobject (JNICALL *CallNonvirtualObjectMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, 
+       jvalue * args);
+
+    jboolean (JNICALL *CallNonvirtualBooleanMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jboolean (JNICALL *CallNonvirtualBooleanMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jboolean (JNICALL *CallNonvirtualBooleanMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       jvalue * args);
+
+    jbyte (JNICALL *CallNonvirtualByteMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jbyte (JNICALL *CallNonvirtualByteMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jbyte (JNICALL *CallNonvirtualByteMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, 
+       jvalue *args);
+
+    jchar (JNICALL *CallNonvirtualCharMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jchar (JNICALL *CallNonvirtualCharMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jchar (JNICALL *CallNonvirtualCharMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       jvalue *args);
+
+    jshort (JNICALL *CallNonvirtualShortMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jshort (JNICALL *CallNonvirtualShortMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jshort (JNICALL *CallNonvirtualShortMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       jvalue *args);
+
+    jint (JNICALL *CallNonvirtualIntMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jint (JNICALL *CallNonvirtualIntMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jint (JNICALL *CallNonvirtualIntMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       jvalue *args);
+
+    jlong (JNICALL *CallNonvirtualLongMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jlong (JNICALL *CallNonvirtualLongMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jlong (JNICALL *CallNonvirtualLongMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, 
+       jvalue *args);
+
+    jfloat (JNICALL *CallNonvirtualFloatMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jfloat (JNICALL *CallNonvirtualFloatMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jfloat (JNICALL *CallNonvirtualFloatMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       jvalue *args);
+
+    jdouble (JNICALL *CallNonvirtualDoubleMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    jdouble (JNICALL *CallNonvirtualDoubleMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    jdouble (JNICALL *CallNonvirtualDoubleMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       jvalue *args);
+
+    void (JNICALL *CallNonvirtualVoidMethod)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...);
+    void (JNICALL *CallNonvirtualVoidMethodV)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       va_list args);
+    void (JNICALL *CallNonvirtualVoidMethodA)
+      (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID,
+       jvalue * args);
+
+    jfieldID (JNICALL *GetFieldID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+    jobject (JNICALL *GetObjectField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jboolean (JNICALL *GetBooleanField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jbyte (JNICALL *GetByteField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jchar (JNICALL *GetCharField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jshort (JNICALL *GetShortField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jint (JNICALL *GetIntField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jlong (JNICALL *GetLongField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jfloat (JNICALL *GetFloatField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+    jdouble (JNICALL *GetDoubleField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID);
+
+    void (JNICALL *SetObjectField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val);
+    void (JNICALL *SetBooleanField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val);
+    void (JNICALL *SetByteField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val);
+    void (JNICALL *SetCharField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val);
+    void (JNICALL *SetShortField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val);
+    void (JNICALL *SetIntField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jint val);
+    void (JNICALL *SetLongField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val);
+    void (JNICALL *SetFloatField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val);
+    void (JNICALL *SetDoubleField)
+      (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val);
+
+    jmethodID (JNICALL *GetStaticMethodID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+
+    jobject (JNICALL *CallStaticObjectMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jobject (JNICALL *CallStaticObjectMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jobject (JNICALL *CallStaticObjectMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
+
+    jboolean (JNICALL *CallStaticBooleanMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jboolean (JNICALL *CallStaticBooleanMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jboolean (JNICALL *CallStaticBooleanMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
+
+    jbyte (JNICALL *CallStaticByteMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jbyte (JNICALL *CallStaticByteMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jbyte (JNICALL *CallStaticByteMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
+
+    jchar (JNICALL *CallStaticCharMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jchar (JNICALL *CallStaticCharMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jchar (JNICALL *CallStaticCharMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
+
+    jshort (JNICALL *CallStaticShortMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jshort (JNICALL *CallStaticShortMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jshort (JNICALL *CallStaticShortMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
+
+    jint (JNICALL *CallStaticIntMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jint (JNICALL *CallStaticIntMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jint (JNICALL *CallStaticIntMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
+
+    jlong (JNICALL *CallStaticLongMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jlong (JNICALL *CallStaticLongMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jlong (JNICALL *CallStaticLongMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
+
+    jfloat (JNICALL *CallStaticFloatMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jfloat (JNICALL *CallStaticFloatMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jfloat (JNICALL *CallStaticFloatMethodA)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
+
+    jdouble (JNICALL *CallStaticDoubleMethod)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, ...);
+    jdouble (JNICALL *CallStaticDoubleMethodV)
+      (JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
+    jdouble (JNICALL *CallStaticDoubleMethodA)       
+      (JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);
+
+    void (JNICALL *CallStaticVoidMethod)
+      (JNIEnv *env, jclass cls, jmethodID methodID, ...);
+    void (JNICALL *CallStaticVoidMethodV)
+      (JNIEnv *env, jclass cls, jmethodID methodID, va_list args);
+    void (JNICALL *CallStaticVoidMethodA)
+      (JNIEnv *env, jclass cls, jmethodID methodID, jvalue * args);
+
+    jfieldID (JNICALL *GetStaticFieldID)
+      (JNIEnv *env, jclass clazz, const char *name, const char *sig);
+    jobject (JNICALL *GetStaticObjectField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jboolean (JNICALL *GetStaticBooleanField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jbyte (JNICALL *GetStaticByteField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jchar (JNICALL *GetStaticCharField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jshort (JNICALL *GetStaticShortField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jint (JNICALL *GetStaticIntField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jlong (JNICALL *GetStaticLongField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jfloat (JNICALL *GetStaticFloatField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+    jdouble (JNICALL *GetStaticDoubleField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID);
+
+    void (JNICALL *SetStaticObjectField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value);
+    void (JNICALL *SetStaticBooleanField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value);
+    void (JNICALL *SetStaticByteField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value);
+    void (JNICALL *SetStaticCharField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value);
+    void (JNICALL *SetStaticShortField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value);
+    void (JNICALL *SetStaticIntField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value);
+    void (JNICALL *SetStaticLongField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value);
+    void (JNICALL *SetStaticFloatField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value);
+    void (JNICALL *SetStaticDoubleField)
+      (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value);
+
+    jstring (JNICALL *NewString)
+      (JNIEnv *env, const jchar *unicode, jsize len);
+    jsize (JNICALL *GetStringLength)
+      (JNIEnv *env, jstring str);
+    const jchar *(JNICALL *GetStringChars)
+      (JNIEnv *env, jstring str, jboolean *isCopy);
+    void (JNICALL *ReleaseStringChars)
+      (JNIEnv *env, jstring str, const jchar *chars);
+  
+    jstring (JNICALL *NewStringUTF)
+      (JNIEnv *env, const char *utf);
+    jsize (JNICALL *GetStringUTFLength)
+      (JNIEnv *env, jstring str);
+    const char* (JNICALL *GetStringUTFChars)
+      (JNIEnv *env, jstring str, jboolean *isCopy);
+    void (JNICALL *ReleaseStringUTFChars)
+      (JNIEnv *env, jstring str, const char* chars);
+  
+
+    jsize (JNICALL *GetArrayLength)
+      (JNIEnv *env, jarray array);
+
+    jobjectArray (JNICALL *NewObjectArray)
+      (JNIEnv *env, jsize len, jclass clazz, jobject init);
+    jobject (JNICALL *GetObjectArrayElement)
+      (JNIEnv *env, jobjectArray array, jsize index);
+    void (JNICALL *SetObjectArrayElement)
+      (JNIEnv *env, jobjectArray array, jsize index, jobject val);
+
+    jbooleanArray (JNICALL *NewBooleanArray)
+      (JNIEnv *env, jsize len);
+    jbyteArray (JNICALL *NewByteArray)
+      (JNIEnv *env, jsize len);
+    jcharArray (JNICALL *NewCharArray)
+      (JNIEnv *env, jsize len);
+    jshortArray (JNICALL *NewShortArray)
+      (JNIEnv *env, jsize len);
+    jintArray (JNICALL *NewIntArray)
+      (JNIEnv *env, jsize len);
+    jlongArray (JNICALL *NewLongArray)
+      (JNIEnv *env, jsize len);
+    jfloatArray (JNICALL *NewFloatArray)
+      (JNIEnv *env, jsize len);
+    jdoubleArray (JNICALL *NewDoubleArray)
+      (JNIEnv *env, jsize len);
+
+    jboolean * (JNICALL *GetBooleanArrayElements)
+      (JNIEnv *env, jbooleanArray array, jboolean *isCopy);
+    jbyte * (JNICALL *GetByteArrayElements)
+      (JNIEnv *env, jbyteArray array, jboolean *isCopy);
+    jchar * (JNICALL *GetCharArrayElements)
+      (JNIEnv *env, jcharArray array, jboolean *isCopy);
+    jshort * (JNICALL *GetShortArrayElements)
+      (JNIEnv *env, jshortArray array, jboolean *isCopy);
+    jint * (JNICALL *GetIntArrayElements)
+      (JNIEnv *env, jintArray array, jboolean *isCopy);
+    jlong * (JNICALL *GetLongArrayElements)
+      (JNIEnv *env, jlongArray array, jboolean *isCopy);
+    jfloat * (JNICALL *GetFloatArrayElements)
+      (JNIEnv *env, jfloatArray array, jboolean *isCopy);
+    jdouble * (JNICALL *GetDoubleArrayElements)
+      (JNIEnv *env, jdoubleArray array, jboolean *isCopy);
+
+    void (JNICALL *ReleaseBooleanArrayElements)
+      (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode);
+    void (JNICALL *ReleaseByteArrayElements)
+      (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode);
+    void (JNICALL *ReleaseCharArrayElements)
+      (JNIEnv *env, jcharArray array, jchar *elems, jint mode);
+    void (JNICALL *ReleaseShortArrayElements)
+      (JNIEnv *env, jshortArray array, jshort *elems, jint mode);
+    void (JNICALL *ReleaseIntArrayElements)
+      (JNIEnv *env, jintArray array, jint *elems, jint mode);
+    void (JNICALL *ReleaseLongArrayElements)
+      (JNIEnv *env, jlongArray array, jlong *elems, jint mode);
+    void (JNICALL *ReleaseFloatArrayElements)
+      (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode);
+    void (JNICALL *ReleaseDoubleArrayElements)
+      (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode);
+
+    void (JNICALL *GetBooleanArrayRegion)
+      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf);
+    void (JNICALL *GetByteArrayRegion)
+      (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);
+    void (JNICALL *GetCharArrayRegion)
+      (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf);
+    void (JNICALL *GetShortArrayRegion)
+      (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf);
+    void (JNICALL *GetIntArrayRegion)
+      (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf);
+    void (JNICALL *GetLongArrayRegion)
+      (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf);
+    void (JNICALL *GetFloatArrayRegion)
+      (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf);
+    void (JNICALL *GetDoubleArrayRegion)
+      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf);
+
+    void (JNICALL *SetBooleanArrayRegion)
+      (JNIEnv *env, jbooleanArray array, jsize start, jsize l, jboolean *buf);
+    void (JNICALL *SetByteArrayRegion)
+      (JNIEnv *env, jbyteArray array, jsize start, jsize len, jbyte *buf);
+    void (JNICALL *SetCharArrayRegion)
+      (JNIEnv *env, jcharArray array, jsize start, jsize len, jchar *buf);
+    void (JNICALL *SetShortArrayRegion)
+      (JNIEnv *env, jshortArray array, jsize start, jsize len, jshort *buf);
+    void (JNICALL *SetIntArrayRegion)
+      (JNIEnv *env, jintArray array, jsize start, jsize len, jint *buf);
+    void (JNICALL *SetLongArrayRegion)
+      (JNIEnv *env, jlongArray array, jsize start, jsize len, jlong *buf);
+    void (JNICALL *SetFloatArrayRegion)
+      (JNIEnv *env, jfloatArray array, jsize start, jsize len, jfloat *buf);
+    void (JNICALL *SetDoubleArrayRegion)
+      (JNIEnv *env, jdoubleArray array, jsize start, jsize len, jdouble *buf);
+
+    jint (JNICALL *RegisterNatives)
+      (JNIEnv *env, jclass clazz, const JNINativeMethod *methods, 
+       jint nMethods);
+    jint (JNICALL *UnregisterNatives)
+      (JNIEnv *env, jclass clazz);
+
+    jint (JNICALL *MonitorEnter)
+      (JNIEnv *env, jobject obj);
+    jint (JNICALL *MonitorExit)
+      (JNIEnv *env, jobject obj);
+ 
+    jint (JNICALL *GetJavaVM)
+      (JNIEnv *env, JavaVM **vm);
+};
+
+/*
+ * We use inlined functions for C++ so that programmers can write:
+ * 
+ *    env->FindClass("java/lang/String")
+ *
+ * in C++ rather than:
+ *
+ *    (*env)->FindClass(env, "java/lang/String")
+ *
+ * in C.
+ */
+
+struct JNIEnv_ {
+    const struct JNINativeInterface_ *functions;
+    void *reserved0;
+    void *reserved1[6];
+#ifdef __cplusplus
+
+    jint GetVersion() {
+        return functions->GetVersion(this);
+    }
+    jclass DefineClass(const char *name, jobject loader, const jbyte *buf,
+		       jsize len) {
+        return functions->DefineClass(this, name, loader, buf, len);
+    }
+    jclass FindClass(const char *name) {
+        return functions->FindClass(this, name);
+    }
+    jclass GetSuperclass(jclass sub) {
+        return functions->GetSuperclass(this, sub);
+    }
+    jboolean IsAssignableFrom(jclass sub, jclass sup) {
+        return functions->IsAssignableFrom(this, sub, sup);
+    }
+
+    jint Throw(jthrowable obj) {
+        return functions->Throw(this, obj);
+    }    
+    jint ThrowNew(jclass clazz, const char *msg) {
+        return functions->ThrowNew(this, clazz, msg);
+    }
+    jthrowable ExceptionOccurred() {
+        return functions->ExceptionOccurred(this);
+    }
+    void ExceptionDescribe() {
+        functions->ExceptionDescribe(this);
+    }
+    void ExceptionClear() {
+        functions->ExceptionClear(this);
+    }
+    void FatalError(const char *msg) {
+        functions->FatalError(this, msg);
+    }
+
+    jobject NewGlobalRef(jobject lobj) {
+        return functions->NewGlobalRef(this,lobj);
+    }
+    void DeleteGlobalRef(jobject gref) {
+        functions->DeleteGlobalRef(this,gref);
+    }
+    void DeleteLocalRef(jobject obj) {
+        functions->DeleteLocalRef(this, obj);
+    }
+
+    jboolean IsSameObject(jobject obj1, jobject obj2) {
+        return functions->IsSameObject(this,obj1,obj2);
+    }
+
+    jobject AllocObject(jclass clazz) {
+        return functions->AllocObject(this,clazz);
+    }
+    jobject NewObject(jclass clazz, jmethodID methodID, ...) {
+        va_list args;
+	jobject result;
+	va_start(args, methodID);
+        result = functions->NewObjectV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jobject NewObjectV(jclass clazz, jmethodID methodID, 
+		       va_list args) {
+        return functions->NewObjectV(this,clazz,methodID,args);
+    }
+    jobject NewObjectA(jclass clazz, jmethodID methodID, 
+		       jvalue *args) {
+        return functions->NewObjectA(this,clazz,methodID,args);
+    }
+
+    jclass GetObjectClass(jobject obj) {
+        return functions->GetObjectClass(this,obj);
+    }
+    jboolean IsInstanceOf(jobject obj, jclass clazz) {
+        return functions->IsInstanceOf(this,obj,clazz);
+    }
+
+    jmethodID GetMethodID(jclass clazz, const char *name, 
+			  const char *sig) {
+        return functions->GetMethodID(this,clazz,name,sig);
+    }
+
+    jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jobject result;
+	va_start(args,methodID);
+	result = functions->CallObjectMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jobject CallObjectMethodV(jobject obj, jmethodID methodID, 
+			va_list args) {
+        return functions->CallObjectMethodV(this,obj,methodID,args);
+    }
+    jobject CallObjectMethodA(jobject obj, jmethodID methodID, 
+			jvalue * args) {
+        return functions->CallObjectMethodA(this,obj,methodID,args);
+    }
+
+    jboolean CallBooleanMethod(jobject obj, 
+			       jmethodID methodID, ...) {
+        va_list args;
+	jboolean result;
+	va_start(args,methodID);
+	result = functions->CallBooleanMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jboolean CallBooleanMethodV(jobject obj, jmethodID methodID, 
+				va_list args) {
+        return functions->CallBooleanMethodV(this,obj,methodID,args);
+    }
+    jboolean CallBooleanMethodA(jobject obj, jmethodID methodID, 
+				jvalue * args) {
+        return functions->CallBooleanMethodA(this,obj,methodID, args);
+    }
+
+    jbyte CallByteMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jbyte result;
+	va_start(args,methodID);
+	result = functions->CallByteMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jbyte CallByteMethodV(jobject obj, jmethodID methodID, 
+			  va_list args) {
+        return functions->CallByteMethodV(this,obj,methodID,args);
+    }
+    jbyte CallByteMethodA(jobject obj, jmethodID methodID, 
+			  jvalue * args) {
+        return functions->CallByteMethodA(this,obj,methodID,args);
+    }
+
+    jchar CallCharMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jchar result;
+	va_start(args,methodID);
+	result = functions->CallCharMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jchar CallCharMethodV(jobject obj, jmethodID methodID, 
+			  va_list args) {
+        return functions->CallCharMethodV(this,obj,methodID,args);
+    }
+    jchar CallCharMethodA(jobject obj, jmethodID methodID, 
+			  jvalue * args) {
+        return functions->CallCharMethodA(this,obj,methodID,args);
+    }
+
+    jshort CallShortMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jshort result;
+	va_start(args,methodID);
+	result = functions->CallShortMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jshort CallShortMethodV(jobject obj, jmethodID methodID, 
+			    va_list args) {
+        return functions->CallShortMethodV(this,obj,methodID,args);
+    }
+    jshort CallShortMethodA(jobject obj, jmethodID methodID, 
+			    jvalue * args) {
+        return functions->CallShortMethodA(this,obj,methodID,args);
+    }
+
+    jint CallIntMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jint result;
+	va_start(args,methodID);
+	result = functions->CallIntMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jint CallIntMethodV(jobject obj, jmethodID methodID, 
+			va_list args) {
+        return functions->CallIntMethodV(this,obj,methodID,args);
+    }
+    jint CallIntMethodA(jobject obj, jmethodID methodID, 
+			jvalue * args) {
+        return functions->CallIntMethodA(this,obj,methodID,args);
+    }
+
+    jlong CallLongMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jlong result;
+	va_start(args,methodID);
+	result = functions->CallLongMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jlong CallLongMethodV(jobject obj, jmethodID methodID, 
+			  va_list args) {
+        return functions->CallLongMethodV(this,obj,methodID,args);
+    }
+    jlong CallLongMethodA(jobject obj, jmethodID methodID, 
+			  jvalue * args) {
+        return functions->CallLongMethodA(this,obj,methodID,args);
+    }
+
+    jfloat CallFloatMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jfloat result;
+	va_start(args,methodID);
+	result = functions->CallFloatMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jfloat CallFloatMethodV(jobject obj, jmethodID methodID, 
+			    va_list args) {
+        return functions->CallFloatMethodV(this,obj,methodID,args);
+    }
+    jfloat CallFloatMethodA(jobject obj, jmethodID methodID, 
+			    jvalue * args) {
+        return functions->CallFloatMethodA(this,obj,methodID,args);
+    }
+
+    jdouble CallDoubleMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	jdouble result;
+	va_start(args,methodID);
+	result = functions->CallDoubleMethodV(this,obj,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jdouble CallDoubleMethodV(jobject obj, jmethodID methodID, 
+			va_list args) {
+        return functions->CallDoubleMethodV(this,obj,methodID,args);
+    }
+    jdouble CallDoubleMethodA(jobject obj, jmethodID methodID, 
+			jvalue * args) {
+        return functions->CallDoubleMethodA(this,obj,methodID,args);
+    }
+
+    void CallVoidMethod(jobject obj, jmethodID methodID, ...) {
+        va_list args;
+	va_start(args,methodID);
+	functions->CallVoidMethodV(this,obj,methodID,args);
+	va_end(args);
+    }
+    void CallVoidMethodV(jobject obj, jmethodID methodID, 
+			 va_list args) {
+        functions->CallVoidMethodV(this,obj,methodID,args);
+    }
+    void CallVoidMethodA(jobject obj, jmethodID methodID, 
+			 jvalue * args) {
+        functions->CallVoidMethodA(this,obj,methodID,args);
+    }
+
+    jobject CallNonvirtualObjectMethod(jobject obj, jclass clazz, 
+				       jmethodID methodID, ...) {
+        va_list args;
+	jobject result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualObjectMethodV(this,obj,clazz,
+							methodID,args);
+	va_end(args);
+	return result;
+    }
+    jobject CallNonvirtualObjectMethodV(jobject obj, jclass clazz, 
+					jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualObjectMethodV(this,obj,clazz,
+						      methodID,args);
+    }
+    jobject CallNonvirtualObjectMethodA(jobject obj, jclass clazz, 
+					jmethodID methodID, jvalue * args) {
+        return functions->CallNonvirtualObjectMethodA(this,obj,clazz,
+						      methodID,args);
+    }
+
+    jboolean CallNonvirtualBooleanMethod(jobject obj, jclass clazz, 
+					 jmethodID methodID, ...) {
+        va_list args;
+	jboolean result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualBooleanMethodV(this,obj,clazz,
+							 methodID,args);
+	va_end(args);
+	return result;
+    }
+    jboolean CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, 
+					  jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualBooleanMethodV(this,obj,clazz,
+						       methodID,args);
+    }
+    jboolean CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, 
+					  jmethodID methodID, jvalue * args) {
+        return functions->CallNonvirtualBooleanMethodA(this,obj,clazz,
+						       methodID, args);
+    }
+
+    jbyte CallNonvirtualByteMethod(jobject obj, jclass clazz, 
+				   jmethodID methodID, ...) {
+        va_list args;
+	jbyte result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualByteMethodV(this,obj,clazz,
+						      methodID,args);
+	va_end(args);
+	return result;
+    }
+    jbyte CallNonvirtualByteMethodV(jobject obj, jclass clazz, 
+				    jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualByteMethodV(this,obj,clazz,
+						    methodID,args);
+    }
+    jbyte CallNonvirtualByteMethodA(jobject obj, jclass clazz, 
+				    jmethodID methodID, jvalue * args) {
+        return functions->CallNonvirtualByteMethodA(this,obj,clazz,
+						    methodID,args);
+    }
+
+    jchar CallNonvirtualCharMethod(jobject obj, jclass clazz, 
+				   jmethodID methodID, ...) {
+        va_list args;
+	jchar result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualCharMethodV(this,obj,clazz,
+						      methodID,args);
+	va_end(args);
+	return result;
+    }
+    jchar CallNonvirtualCharMethodV(jobject obj, jclass clazz, 
+				    jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualCharMethodV(this,obj,clazz,
+						    methodID,args);
+    }
+    jchar CallNonvirtualCharMethodA(jobject obj, jclass clazz, 
+				    jmethodID methodID, jvalue * args) {
+        return functions->CallNonvirtualCharMethodA(this,obj,clazz,
+						    methodID,args);
+    }
+
+    jshort CallNonvirtualShortMethod(jobject obj, jclass clazz, 
+				     jmethodID methodID, ...) {
+        va_list args;
+	jshort result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualShortMethodV(this,obj,clazz,
+						       methodID,args);
+	va_end(args);
+	return result;
+    }
+    jshort CallNonvirtualShortMethodV(jobject obj, jclass clazz, 
+				      jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualShortMethodV(this,obj,clazz,
+						     methodID,args);
+    }
+    jshort CallNonvirtualShortMethodA(jobject obj, jclass clazz,
+				      jmethodID methodID, jvalue * args) {
+        return functions->CallNonvirtualShortMethodA(this,obj,clazz,
+						     methodID,args);
+    }
+
+    jint CallNonvirtualIntMethod(jobject obj, jclass clazz, 
+				 jmethodID methodID, ...) {
+        va_list args;
+	jint result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualIntMethodV(this,obj,clazz,
+						     methodID,args);
+	va_end(args);
+	return result;
+    }
+    jint CallNonvirtualIntMethodV(jobject obj, jclass clazz, 
+				  jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualIntMethodV(this,obj,clazz,
+						   methodID,args);
+    }
+    jint CallNonvirtualIntMethodA(jobject obj, jclass clazz, 
+				  jmethodID methodID, jvalue * args) {
+        return functions->CallNonvirtualIntMethodA(this,obj,clazz,
+						   methodID,args);
+    }
+
+    jlong CallNonvirtualLongMethod(jobject obj, jclass clazz,
+				   jmethodID methodID, ...) {
+        va_list args;
+	jlong result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualLongMethodV(this,obj,clazz,
+						      methodID,args);
+	va_end(args);
+	return result;
+    }
+    jlong CallNonvirtualLongMethodV(jobject obj, jclass clazz,
+				    jmethodID methodID, va_list args) {
+        return functions->CallNonvirtualLongMethodV(this,obj,clazz,
+						    methodID,args);
+    }
+    jlong CallNonvirtualLongMethodA(jobject obj, jclass clazz, 
+				    jmethodID methodID, jvalue * args) {
+        return functions->CallNonvirtualLongMethodA(this,obj,clazz,
+						    methodID,args);
+    }
+
+    jfloat CallNonvirtualFloatMethod(jobject obj, jclass clazz, 
+				     jmethodID methodID, ...) {
+        va_list args;
+	jfloat result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualFloatMethodV(this,obj,clazz,
+						       methodID,args);
+	va_end(args);
+	return result;
+    }
+    jfloat CallNonvirtualFloatMethodV(jobject obj, jclass clazz,
+				      jmethodID methodID, 
+				      va_list args) {
+        return functions->CallNonvirtualFloatMethodV(this,obj,clazz,
+						     methodID,args);
+    }
+    jfloat CallNonvirtualFloatMethodA(jobject obj, jclass clazz, 
+				      jmethodID methodID, 
+				      jvalue * args) {
+        return functions->CallNonvirtualFloatMethodA(this,obj,clazz,
+						     methodID,args);
+    }
+
+    jdouble CallNonvirtualDoubleMethod(jobject obj, jclass clazz,
+				       jmethodID methodID, ...) {
+        va_list args;
+	jdouble result;
+	va_start(args,methodID);
+	result = functions->CallNonvirtualDoubleMethodV(this,obj,clazz,
+							methodID,args);
+	va_end(args);
+	return result;
+    }
+    jdouble CallNonvirtualDoubleMethodV(jobject obj, jclass clazz,
+					jmethodID methodID, 
+					va_list args) {
+        return functions->CallNonvirtualDoubleMethodV(this,obj,clazz,
+						      methodID,args);
+    }
+    jdouble CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, 
+					jmethodID methodID, 
+					jvalue * args) {
+        return functions->CallNonvirtualDoubleMethodA(this,obj,clazz,
+						      methodID,args);
+    }
+
+    void CallNonvirtualVoidMethod(jobject obj, jclass clazz,
+				  jmethodID methodID, ...) {
+        va_list args;
+	va_start(args,methodID);
+	functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args);
+	va_end(args);
+    }
+    void CallNonvirtualVoidMethodV(jobject obj, jclass clazz,
+				   jmethodID methodID, 
+				   va_list args) {
+        functions->CallNonvirtualVoidMethodV(this,obj,clazz,methodID,args);
+    }
+    void CallNonvirtualVoidMethodA(jobject obj, jclass clazz,
+				   jmethodID methodID, 
+				   jvalue * args) {
+        functions->CallNonvirtualVoidMethodA(this,obj,clazz,methodID,args);
+    }
+
+    jfieldID GetFieldID(jclass clazz, const char *name, 
+			const char *sig) {
+        return functions->GetFieldID(this,clazz,name,sig);
+    }
+
+    jobject GetObjectField(jobject obj, jfieldID fieldID) {
+        return functions->GetObjectField(this,obj,fieldID);
+    }
+    jboolean GetBooleanField(jobject obj, jfieldID fieldID) {
+        return functions->GetBooleanField(this,obj,fieldID);
+    }
+    jbyte GetByteField(jobject obj, jfieldID fieldID) {
+        return functions->GetByteField(this,obj,fieldID);
+    }
+    jchar GetCharField(jobject obj, jfieldID fieldID) {
+        return functions->GetCharField(this,obj,fieldID);
+    }
+    jshort GetShortField(jobject obj, jfieldID fieldID) {
+        return functions->GetShortField(this,obj,fieldID);
+    }
+    jint GetIntField(jobject obj, jfieldID fieldID) {
+        return functions->GetIntField(this,obj,fieldID);
+    }
+    jlong GetLongField(jobject obj, jfieldID fieldID) {
+        return functions->GetLongField(this,obj,fieldID);
+    }
+    jfloat GetFloatField(jobject obj, jfieldID fieldID) {
+        return functions->GetFloatField(this,obj,fieldID);
+    }
+    jdouble GetDoubleField(jobject obj, jfieldID fieldID) {
+        return functions->GetDoubleField(this,obj,fieldID);
+    }
+
+    void SetObjectField(jobject obj, jfieldID fieldID, jobject val) {
+        functions->SetObjectField(this,obj,fieldID,val);
+    }
+    void SetBooleanField(jobject obj, jfieldID fieldID, 
+			 jboolean val) {
+        functions->SetBooleanField(this,obj,fieldID,val);
+    }
+    void SetByteField(jobject obj, jfieldID fieldID, 
+		      jbyte val) {
+        functions->SetByteField(this,obj,fieldID,val);
+    }
+    void SetCharField(jobject obj, jfieldID fieldID, 
+		      jchar val) {
+        functions->SetCharField(this,obj,fieldID,val);
+    }
+    void SetShortField(jobject obj, jfieldID fieldID,
+		       jshort val) {
+        functions->SetShortField(this,obj,fieldID,val);
+    }
+    void SetIntField(jobject obj, jfieldID fieldID, 
+		     jint val) {
+        functions->SetIntField(this,obj,fieldID,val);
+    }
+    void SetLongField(jobject obj, jfieldID fieldID, 
+		      jlong val) {
+        functions->SetLongField(this,obj,fieldID,val);
+    }
+    void SetFloatField(jobject obj, jfieldID fieldID, 
+		       jfloat val) {
+        functions->SetFloatField(this,obj,fieldID,val);
+    }
+    void SetDoubleField(jobject obj, jfieldID fieldID, 
+			jdouble val) {
+        functions->SetDoubleField(this,obj,fieldID,val);
+    }
+
+    jmethodID GetStaticMethodID(jclass clazz, const char *name, 
+				const char *sig) {
+        return functions->GetStaticMethodID(this,clazz,name,sig);
+    }
+
+    jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, 
+			     ...) {
+        va_list args;
+	jobject result;
+	va_start(args,methodID);
+	result = functions->CallStaticObjectMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jobject CallStaticObjectMethodV(jclass clazz, jmethodID methodID, 
+			      va_list args) {
+        return functions->CallStaticObjectMethodV(this,clazz,methodID,args);
+    }
+    jobject CallStaticObjectMethodA(jclass clazz, jmethodID methodID, 
+			      jvalue *args) {
+        return functions->CallStaticObjectMethodA(this,clazz,methodID,args);
+    }
+
+    jboolean CallStaticBooleanMethod(jclass clazz, 
+				     jmethodID methodID, ...) {
+        va_list args;
+	jboolean result;
+	va_start(args,methodID);
+	result = functions->CallStaticBooleanMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jboolean CallStaticBooleanMethodV(jclass clazz,
+				      jmethodID methodID, va_list args) {
+        return functions->CallStaticBooleanMethodV(this,clazz,methodID,args);
+    }
+    jboolean CallStaticBooleanMethodA(jclass clazz,
+				      jmethodID methodID, jvalue *args) {
+        return functions->CallStaticBooleanMethodA(this,clazz,methodID,args);
+    }
+
+    jbyte CallStaticByteMethod(jclass clazz,
+			       jmethodID methodID, ...) {
+        va_list args;
+	jbyte result;
+	va_start(args,methodID);
+	result = functions->CallStaticByteMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jbyte CallStaticByteMethodV(jclass clazz,
+				jmethodID methodID, va_list args) {
+        return functions->CallStaticByteMethodV(this,clazz,methodID,args);
+    }
+    jbyte CallStaticByteMethodA(jclass clazz, 
+				jmethodID methodID, jvalue *args) {
+        return functions->CallStaticByteMethodA(this,clazz,methodID,args);
+    }
+
+    jchar CallStaticCharMethod(jclass clazz,
+			       jmethodID methodID, ...) {
+        va_list args;
+	jchar result;
+	va_start(args,methodID);
+	result = functions->CallStaticCharMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jchar CallStaticCharMethodV(jclass clazz,
+				jmethodID methodID, va_list args) {
+        return functions->CallStaticCharMethodV(this,clazz,methodID,args);
+    }
+    jchar CallStaticCharMethodA(jclass clazz,
+				jmethodID methodID, jvalue *args) {
+        return functions->CallStaticCharMethodA(this,clazz,methodID,args);
+    }
+
+    jshort CallStaticShortMethod(jclass clazz,
+				 jmethodID methodID, ...) {
+        va_list args;
+	jshort result;
+	va_start(args,methodID);
+	result = functions->CallStaticShortMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jshort CallStaticShortMethodV(jclass clazz,
+				  jmethodID methodID, va_list args) {
+        return functions->CallStaticShortMethodV(this,clazz,methodID,args);
+    }
+    jshort CallStaticShortMethodA(jclass clazz,
+				  jmethodID methodID, jvalue *args) {
+        return functions->CallStaticShortMethodA(this,clazz,methodID,args);
+    }
+
+    jint CallStaticIntMethod(jclass clazz,
+			     jmethodID methodID, ...) {
+        va_list args;
+	jint result;
+	va_start(args,methodID);
+	result = functions->CallStaticIntMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jint CallStaticIntMethodV(jclass clazz,
+			      jmethodID methodID, va_list args) {
+        return functions->CallStaticIntMethodV(this,clazz,methodID,args);
+    }
+    jint CallStaticIntMethodA(jclass clazz, 
+			      jmethodID methodID, jvalue *args) {
+        return functions->CallStaticIntMethodA(this,clazz,methodID,args);
+    }
+
+    jlong CallStaticLongMethod(jclass clazz,
+			       jmethodID methodID, ...) {
+        va_list args;
+	jlong result;
+	va_start(args,methodID);
+	result = functions->CallStaticLongMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jlong CallStaticLongMethodV(jclass clazz, 
+				jmethodID methodID, va_list args) {
+        return functions->CallStaticLongMethodV(this,clazz,methodID,args);
+    }
+    jlong CallStaticLongMethodA(jclass clazz, 
+				jmethodID methodID, jvalue *args) {
+        return functions->CallStaticLongMethodA(this,clazz,methodID,args);
+    }
+
+    jfloat CallStaticFloatMethod(jclass clazz, 
+				 jmethodID methodID, ...) {
+        va_list args;
+	jfloat result;
+	va_start(args,methodID);
+	result = functions->CallStaticFloatMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jfloat CallStaticFloatMethodV(jclass clazz, 
+				  jmethodID methodID, va_list args) {
+        return functions->CallStaticFloatMethodV(this,clazz,methodID,args);
+    }
+    jfloat CallStaticFloatMethodA(jclass clazz, 
+				  jmethodID methodID, jvalue *args) {
+        return functions->CallStaticFloatMethodA(this,clazz,methodID,args);
+    }
+
+    jdouble CallStaticDoubleMethod(jclass clazz, 
+				   jmethodID methodID, ...) {
+        va_list args;
+	jdouble result;
+	va_start(args,methodID);
+	result = functions->CallStaticDoubleMethodV(this,clazz,methodID,args);
+	va_end(args);
+	return result;
+    }
+    jdouble CallStaticDoubleMethodV(jclass clazz, 
+				    jmethodID methodID, va_list args) {
+        return functions->CallStaticDoubleMethodV(this,clazz,methodID,args);
+    }
+    jdouble CallStaticDoubleMethodA(jclass clazz, 
+				    jmethodID methodID, jvalue *args) {
+        return functions->CallStaticDoubleMethodA(this,clazz,methodID,args);
+    }
+
+    void CallStaticVoidMethod(jclass cls, jmethodID methodID, ...) {
+        va_list args;
+	va_start(args,methodID);
+	functions->CallStaticVoidMethodV(this,cls,methodID,args);
+	va_end(args);
+    }
+    void CallStaticVoidMethodV(jclass cls, jmethodID methodID, 
+			       va_list args) {
+        functions->CallStaticVoidMethodV(this,cls,methodID,args);
+    }
+    void CallStaticVoidMethodA(jclass cls, jmethodID methodID, 
+			       jvalue * args) {
+        functions->CallStaticVoidMethodA(this,cls,methodID,args);
+    }
+
+    jfieldID GetStaticFieldID(jclass clazz, const char *name, 
+			      const char *sig) {
+        return functions->GetStaticFieldID(this,clazz,name,sig);
+    }
+    jobject GetStaticObjectField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticObjectField(this,clazz,fieldID);
+    }
+    jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticBooleanField(this,clazz,fieldID);
+    }
+    jbyte GetStaticByteField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticByteField(this,clazz,fieldID);
+    }
+    jchar GetStaticCharField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticCharField(this,clazz,fieldID);
+    }
+    jshort GetStaticShortField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticShortField(this,clazz,fieldID);
+    }
+    jint GetStaticIntField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticIntField(this,clazz,fieldID);
+    }
+    jlong GetStaticLongField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticLongField(this,clazz,fieldID);
+    }
+    jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticFloatField(this,clazz,fieldID);
+    }
+    jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID) {
+        return functions->GetStaticDoubleField(this,clazz,fieldID);
+    }
+
+    void SetStaticObjectField(jclass clazz, jfieldID fieldID,
+			jobject value) {
+      functions->SetStaticObjectField(this,clazz,fieldID,value);
+    }
+    void SetStaticBooleanField(jclass clazz, jfieldID fieldID,
+			jboolean value) {
+      functions->SetStaticBooleanField(this,clazz,fieldID,value);
+    }
+    void SetStaticByteField(jclass clazz, jfieldID fieldID,
+			jbyte value) {
+      functions->SetStaticByteField(this,clazz,fieldID,value);
+    }
+    void SetStaticCharField(jclass clazz, jfieldID fieldID,
+			jchar value) {
+      functions->SetStaticCharField(this,clazz,fieldID,value);
+    }
+    void SetStaticShortField(jclass clazz, jfieldID fieldID,
+			jshort value) {
+      functions->SetStaticShortField(this,clazz,fieldID,value);
+    }
+    void SetStaticIntField(jclass clazz, jfieldID fieldID,
+			jint value) {
+      functions->SetStaticIntField(this,clazz,fieldID,value);
+    }
+    void SetStaticLongField(jclass clazz, jfieldID fieldID,
+			jlong value) {
+      functions->SetStaticLongField(this,clazz,fieldID,value);
+    }
+    void SetStaticFloatField(jclass clazz, jfieldID fieldID,
+			jfloat value) {
+      functions->SetStaticFloatField(this,clazz,fieldID,value);
+    }
+    void SetStaticDoubleField(jclass clazz, jfieldID fieldID,
+			jdouble value) {
+      functions->SetStaticDoubleField(this,clazz,fieldID,value);
+    }
+
+    jstring NewString(const jchar *unicode, jsize len) {
+        return functions->NewString(this,unicode,len);
+    }
+    jsize GetStringLength(jstring str) {
+        return functions->GetStringLength(this,str);
+    }
+    const jchar *GetStringChars(jstring str, jboolean *isCopy) {
+        return functions->GetStringChars(this,str,isCopy);
+    }
+    void ReleaseStringChars(jstring str, const jchar *chars) {
+        functions->ReleaseStringChars(this,str,chars);
+    }
+  
+    jstring NewStringUTF(const char *utf) {
+        return functions->NewStringUTF(this,utf);
+    }
+    jsize GetStringUTFLength(jstring str) {
+        return functions->GetStringUTFLength(this,str);
+    }
+    const char* GetStringUTFChars(jstring str, jboolean *isCopy) {
+        return functions->GetStringUTFChars(this,str,isCopy);
+    }
+    void ReleaseStringUTFChars(jstring str, const char* chars) {
+        functions->ReleaseStringUTFChars(this,str,chars);
+    }
+
+    jsize GetArrayLength(jarray array) {
+        return functions->GetArrayLength(this,array);
+    }
+
+    jobjectArray NewObjectArray(jsize len, jclass clazz, 
+				jobject init) {
+        return functions->NewObjectArray(this,len,clazz,init);
+    }
+    jobject GetObjectArrayElement(jobjectArray array, jsize index) {
+        return functions->GetObjectArrayElement(this,array,index);
+    }
+    void SetObjectArrayElement(jobjectArray array, jsize index, 
+			       jobject val) {
+        functions->SetObjectArrayElement(this,array,index,val);
+    }
+
+    jbooleanArray NewBooleanArray(jsize len) {
+        return functions->NewBooleanArray(this,len);
+    }
+    jbyteArray NewByteArray(jsize len) {
+        return functions->NewByteArray(this,len);
+    }
+    jcharArray NewCharArray(jsize len) {
+        return functions->NewCharArray(this,len);
+    }
+    jshortArray NewShortArray(jsize len) {
+        return functions->NewShortArray(this,len);
+    }
+    jintArray NewIntArray(jsize len) {
+        return functions->NewIntArray(this,len);
+    }
+    jlongArray NewLongArray(jsize len) {
+        return functions->NewLongArray(this,len);
+    }
+    jfloatArray NewFloatArray(jsize len) {
+        return functions->NewFloatArray(this,len);
+    }
+    jdoubleArray NewDoubleArray(jsize len) {
+        return functions->NewDoubleArray(this,len);
+    }
+
+    jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy) {
+        return functions->GetBooleanArrayElements(this,array,isCopy);
+    }
+    jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy) {
+        return functions->GetByteArrayElements(this,array,isCopy);
+    }
+    jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) {
+        return functions->GetCharArrayElements(this,array,isCopy);
+    }
+    jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy) {
+        return functions->GetShortArrayElements(this,array,isCopy);
+    }
+    jint * GetIntArrayElements(jintArray array, jboolean *isCopy) {
+        return functions->GetIntArrayElements(this,array,isCopy);
+    }
+    jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy) {
+        return functions->GetLongArrayElements(this,array,isCopy);
+    }
+    jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy) {
+        return functions->GetFloatArrayElements(this,array,isCopy);
+    }
+    jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) {
+        return functions->GetDoubleArrayElements(this,array,isCopy);
+    }
+
+    void ReleaseBooleanArrayElements(jbooleanArray array, 
+				     jboolean *elems,
+				     jint mode) {
+        functions->ReleaseBooleanArrayElements(this,array,elems,mode);
+    }
+    void ReleaseByteArrayElements(jbyteArray array, 
+				  jbyte *elems,
+				  jint mode) {
+        functions->ReleaseByteArrayElements(this,array,elems,mode);
+    }
+    void ReleaseCharArrayElements(jcharArray array, 
+				  jchar *elems,
+				  jint mode) {
+        functions->ReleaseCharArrayElements(this,array,elems,mode);
+    }
+    void ReleaseShortArrayElements(jshortArray array, 
+				   jshort *elems,
+				   jint mode) {
+        functions->ReleaseShortArrayElements(this,array,elems,mode);
+    }
+    void ReleaseIntArrayElements(jintArray array, 
+				 jint *elems,
+				 jint mode) {
+        functions->ReleaseIntArrayElements(this,array,elems,mode);
+    }
+    void ReleaseLongArrayElements(jlongArray array, 
+				  jlong *elems,
+				  jint mode) {
+        functions->ReleaseLongArrayElements(this,array,elems,mode);
+    }
+    void ReleaseFloatArrayElements(jfloatArray array, 
+				   jfloat *elems,
+				   jint mode) {
+        functions->ReleaseFloatArrayElements(this,array,elems,mode);
+    }
+    void ReleaseDoubleArrayElements(jdoubleArray array, 
+				    jdouble *elems,
+				    jint mode) {
+        functions->ReleaseDoubleArrayElements(this,array,elems,mode);
+    }
+
+    void GetBooleanArrayRegion(jbooleanArray array, 
+			       jsize start, jsize len, jboolean *buf) {
+        functions->GetBooleanArrayRegion(this,array,start,len,buf);
+    }
+    void GetByteArrayRegion(jbyteArray array, 
+			    jsize start, jsize len, jbyte *buf) {
+        functions->GetByteArrayRegion(this,array,start,len,buf);
+    }
+    void GetCharArrayRegion(jcharArray array, 
+			    jsize start, jsize len, jchar *buf) {
+        functions->GetCharArrayRegion(this,array,start,len,buf);
+    }
+    void GetShortArrayRegion(jshortArray array, 
+			     jsize start, jsize len, jshort *buf) {
+        functions->GetShortArrayRegion(this,array,start,len,buf);
+    }
+    void GetIntArrayRegion(jintArray array, 
+			   jsize start, jsize len, jint *buf) {
+        functions->GetIntArrayRegion(this,array,start,len,buf);
+    }
+    void GetLongArrayRegion(jlongArray array, 
+			    jsize start, jsize len, jlong *buf) {
+        functions->GetLongArrayRegion(this,array,start,len,buf);
+    }
+    void GetFloatArrayRegion(jfloatArray array, 
+			     jsize start, jsize len, jfloat *buf) {
+        functions->GetFloatArrayRegion(this,array,start,len,buf);
+    }
+    void GetDoubleArrayRegion(jdoubleArray array, 
+			      jsize start, jsize len, jdouble *buf) {
+        functions->GetDoubleArrayRegion(this,array,start,len,buf);
+    }
+
+    void SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, 
+			       jboolean *buf) {
+        functions->SetBooleanArrayRegion(this,array,start,len,buf);
+    }
+    void SetByteArrayRegion(jbyteArray array, jsize start, jsize len,
+			    jbyte *buf) {
+        functions->SetByteArrayRegion(this,array,start,len,buf);
+    }
+    void SetCharArrayRegion(jcharArray array, jsize start, jsize len, 
+			    jchar *buf) {
+        functions->SetCharArrayRegion(this,array,start,len,buf);
+    }
+    void SetShortArrayRegion(jshortArray array, jsize start, jsize len, 
+			     jshort *buf) {
+        functions->SetShortArrayRegion(this,array,start,len,buf);
+    }
+    void SetIntArrayRegion(jintArray array, jsize start, jsize len,
+			   jint *buf) {
+        functions->SetIntArrayRegion(this,array,start,len,buf);
+    }
+    void SetLongArrayRegion(jlongArray array, jsize start, jsize len,
+			    jlong *buf) {
+        functions->SetLongArrayRegion(this,array,start,len,buf);
+    }
+    void SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, 
+			     jfloat *buf) {
+        functions->SetFloatArrayRegion(this,array,start,len,buf);
+    }
+    void SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len,
+			      jdouble *buf) {
+        functions->SetDoubleArrayRegion(this,array,start,len,buf);
+    }
+
+    jint RegisterNatives(jclass clazz, const JNINativeMethod *methods,
+			 jint nMethods) {
+        return functions->RegisterNatives(this,clazz,methods,nMethods);
+    }
+    jint UnregisterNatives(jclass clazz) {
+        return functions->UnregisterNatives(this,clazz);
+    }  
+   
+    jint MonitorEnter(jobject obj) {
+        return functions->MonitorEnter(this,obj);
+    }
+    jint MonitorExit(jobject obj) {
+        return functions->MonitorExit(this,obj);
+    }
+
+    jint GetJavaVM(JavaVM **vm) {
+        return functions->GetJavaVM(this,vm);
+    }
+  
+#endif /* __cplusplus */
+};
+
+/* These structures will be VM-specific. */
+
+typedef struct JDK1_1InitArgs {
+    jint version;
+
+    char **properties;
+    jint checkSource; 
+    jint nativeStackSize;
+    jint javaStackSize;
+    jint minHeapSize;
+    jint maxHeapSize;
+    jint verifyMode;
+    char *classpath;
+
+    jint (JNICALL *vfprintf)(FILE *fp, const char *format, va_list args);
+    void (JNICALL *exit)(jint code);
+    void (JNICALL *abort)();
+    
+    jint enableClassGC;
+    jint enableVerboseGC;
+    jint disableAsyncGC;
+    jint verbose;
+    jboolean debugging;
+    jint debugPort;
+} JDK1_1InitArgs;
+
+typedef struct JDK1_1AttachArgs {
+    void * __padding; /* C compilers don't allow empty structures. */
+} JDK1_1AttachArgs;
+
+/* End VM-specific. */
+
+struct JNIInvokeInterface_ {
+    void *reserved0;
+    void *reserved1;
+    void *reserved2;
+
+    jint (JNICALL *DestroyJavaVM)(JavaVM *vm);
+
+    jint (JNICALL *AttachCurrentThread)
+      (JavaVM *vm, JNIEnv **penv, void *args);
+
+    jint (JNICALL *DetachCurrentThread)(JavaVM *vm);
+};
+
+struct JavaVM_ {
+    const struct JNIInvokeInterface_ *functions;
+    void *reserved0;
+    void *reserved1;
+    void *reserved2;
+#ifdef __cplusplus
+
+    jint DestroyJavaVM() {
+        return functions->DestroyJavaVM(this);
+    }
+    jint AttachCurrentThread(JNIEnv **penv, void *args) {
+        return functions->AttachCurrentThread(this, penv, args);
+    }
+    jint DetachCurrentThread() {
+        return functions->DetachCurrentThread(this);
+    }
+
+#endif
+};
+
+JNI_PUBLIC_API(void) JNI_GetDefaultJavaVMInitArgs(void *);
+
+JNI_PUBLIC_API(jint) JNI_CreateJavaVM(JavaVM **, JNIEnv **, void *);
+
+JNI_PUBLIC_API(jint) JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *);
+JNI_PUBLIC_API(jref) JNI_MakeLocalRef(JNIEnv *pJNIEnv, void *pHObject);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* JNI_H */
+
+
diff --git a/third_party/gecko/include/jni_md.h b/third_party/gecko/include/jni_md.h
index c27e5a8..d3e96ab 100644
--- a/third_party/gecko/include/jni_md.h
+++ b/third_party/gecko/include/jni_md.h
@@ -1,182 +1,182 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-

- *

- * The contents of this file are subject to the Netscape Public

- * License Version 1.1 (the "License"); you may not use this file

- * except in compliance with the License. You may obtain a copy of

- * the License at http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS

- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or

- * implied. See the License for the specific language governing

- * rights and limitations under the License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is Netscape

- * Communications Corporation.  Portions created by Netscape are

- * Copyright (C) 1998 Netscape Communications Corporation. All

- * Rights Reserved.

- *

- * Contributor(s): 

- *

- *

- * This Original Code has been modified by IBM Corporation.

- * Modifications made by IBM described herein are

- * Copyright (c) International Business Machines

- * Corporation, 2000

- *

- * Modifications to Mozilla code or documentation

- * identified per MPL Section 3.3

- *

- * Date         Modified by     Description of modification

- * 03/27/2000   IBM Corp.       Set JNICALL to Optlink for

- *                               use in OS2

- */

-

-/*******************************************************************************

- * Netscape version of jni_md.h -- depends on jri_md.h

- ******************************************************************************/

-

-#ifndef JNI_MD_H

-#define JNI_MD_H

-

-#include "prtypes.h" /* needed for _declspec */

-

-/*******************************************************************************

- * WHAT'S UP WITH THIS FILE?

- * 

- * This is where we define the mystical JNI_PUBLIC_API macro that works on all

- * platforms. If you're running with Visual C++, Symantec C, or Borland's 

- * development environment on the PC, you're all set. Or if you're on the Mac

- * with Metrowerks, Symantec or MPW with SC you're ok too. For UNIX it shouldn't

- * matter.

-

- * Changes by sailesh on 9/26 

-

- * There are two symbols used in the declaration of the JNI functions

- * and native code that uses the JNI:

- * JNICALL - specifies the calling convention 

- * JNIEXPORT - specifies export status of the function 

- * 

- * The syntax to specify calling conventions is different in Win16 and

- * Win32 - the brains at Micro$oft at work here. JavaSoft in their

- * infinite wisdom cares for no platform other than Win32, and so they

- * just define these two symbols as:

-

- #define JNIEXPORT __declspec(dllexport)

- #define JNICALL __stdcall

-

- * We deal with this, in the way JRI defines the JRI_PUBLIC_API, by

- * defining a macro called JNI_PUBLIC_API. Any of our developers who

- * wish to use code for Win16 and Win32, _must_ use JNI_PUBLIC_API to

- * be able to export functions properly.

-

- * Since we must also maintain compatibility with JavaSoft, we

- * continue to define the symbol JNIEXPORT. However, use of this

- * internally is deprecated, since it will cause a mess on Win16.

-

- * We _do not_ need a new symbol called JNICALL. Instead we

- * redefine JNICALL in the same way JRI_CALLBACK was defined.

-

- ******************************************************************************/

-

-/* DLL Entry modifiers... */

-#if defined(XP_OS2)

-#  ifdef XP_OS2_VACPP

-#     define JNI_PUBLIC_API(ResultType)      ResultType _System

-#     define JNI_PUBLIC_VAR(VarType)         VarType

-#     define JNICALL                         _Optlink

-#     define JNIEXPORT

-#  else

-#     define JNI_PUBLIC_API(ResultType)	   ResultType

-#     define JNI_PUBLIC_VAR(VarType)         VarType

-#     define JNICALL

-#     define JNIEXPORT

-#  endif

-/* Win32 */

-#elif defined(XP_WIN) || defined(_WINDOWS) || defined(WIN32) || defined(_WIN32)

-#	include <windows.h>

-#	if defined(_MSC_VER) || defined(__GNUC__)

-#		if defined(WIN32) || defined(_WIN32)

-#			define JNI_PUBLIC_API(ResultType)	_declspec(dllexport) ResultType __stdcall

-#			define JNI_PUBLIC_VAR(VarType)		VarType

-#			define JNI_NATIVE_STUB(ResultType)	_declspec(dllexport) ResultType

-#			define JNICALL                          __stdcall

-#		else /* !_WIN32 */

-#		    if defined(_WINDLL)

-#			define JNI_PUBLIC_API(ResultType)	ResultType __cdecl __export __loadds 

-#			define JNI_PUBLIC_VAR(VarType)		VarType

-#			define JNI_NATIVE_STUB(ResultType)	ResultType __cdecl __loadds

-#			define JNICALL			        __loadds

-#		    else /* !WINDLL */

-#			define JNI_PUBLIC_API(ResultType)	ResultType __cdecl __export

-#			define JNI_PUBLIC_VAR(VarType)		VarType

-#			define JNI_NATIVE_STUB(ResultType)	ResultType __cdecl __export

-#			define JNICALL			        __export

-#                   endif /* !WINDLL */

-#		endif /* !_WIN32 */

-#	elif defined(__BORLANDC__)

-#		if defined(WIN32) || defined(_WIN32)

-#			define JNI_PUBLIC_API(ResultType)	__export ResultType

-#			define JNI_PUBLIC_VAR(VarType)		VarType

-#			define JNI_NATIVE_STUB(ResultType)	 __export ResultType

-#			define JNICALL

-#		else /* !_WIN32 */

-#			define JNI_PUBLIC_API(ResultType)	ResultType _cdecl _export _loadds 

-#			define JNI_PUBLIC_VAR(VarType)		VarType

-#			define JNI_NATIVE_STUB(ResultType)	ResultType _cdecl _loadds

-#			define JNICALL			_loadds

-#		endif

-#	else

-#		error Unsupported PC development environment.	

-#	endif

-#	ifndef IS_LITTLE_ENDIAN

-#		define IS_LITTLE_ENDIAN

-#	endif

-	/*  This is the stuff inherited from JavaSoft .. */

-#	define JNIEXPORT __declspec(dllexport)

-

-

-/* Mac */

-#elif macintosh || Macintosh || THINK_C

-#	if defined(__MWERKS__)				/* Metrowerks */

-#		if !__option(enumsalwaysint)

-#			error You need to define 'Enums Always Int' for your project.

-#		endif

-#		if defined(TARGET_CPU_68K) && !TARGET_RT_MAC_CFM 

-#			if !__option(fourbyteints) 

-#				error You need to define 'Struct Alignment: 68k' for your project.

-#			endif

-#		endif /* !GENERATINGCFM */

-#		define JNI_PUBLIC_API(ResultType)	__declspec(export) ResultType 

-#		define JNI_PUBLIC_VAR(VarType)		JNI_PUBLIC_API(VarType)

-#		define JNI_NATIVE_STUB(ResultType)	JNI_PUBLIC_API(ResultType)

-#	elif defined(__SC__)				/* Symantec */

-#		error What are the Symantec defines? (warren@netscape.com)

-#	elif macintosh && applec			/* MPW */

-#		error Please upgrade to the latest MPW compiler (SC).

-#	else

-#		error Unsupported Mac development environment.

-#	endif

-#	define JNICALL

-	/*  This is the stuff inherited from JavaSoft .. */

-#	define JNIEXPORT

-

-/* Unix or else */

-#else

-#	define JNI_PUBLIC_API(ResultType)		ResultType

-#       define JNI_PUBLIC_VAR(VarType)                  VarType

-#       define JNI_NATIVE_STUB(ResultType)              ResultType

-#	define JNICALL

-	/*  This is the stuff inherited from JavaSoft .. */

-#	define JNIEXPORT

-#endif

-

-#ifndef FAR		/* for non-Win16 */

-#define FAR

-#endif

-

-/* Get the rest of the stuff from jri_md.h */

-#include "jri_md.h"

-

-#endif /* JNI_MD_H */

+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s): 
+ *
+ *
+ * This Original Code has been modified by IBM Corporation.
+ * Modifications made by IBM described herein are
+ * Copyright (c) International Business Machines
+ * Corporation, 2000
+ *
+ * Modifications to Mozilla code or documentation
+ * identified per MPL Section 3.3
+ *
+ * Date         Modified by     Description of modification
+ * 03/27/2000   IBM Corp.       Set JNICALL to Optlink for
+ *                               use in OS2
+ */
+
+/*******************************************************************************
+ * Netscape version of jni_md.h -- depends on jri_md.h
+ ******************************************************************************/
+
+#ifndef JNI_MD_H
+#define JNI_MD_H
+
+#include "prtypes.h" /* needed for _declspec */
+
+/*******************************************************************************
+ * WHAT'S UP WITH THIS FILE?
+ * 
+ * This is where we define the mystical JNI_PUBLIC_API macro that works on all
+ * platforms. If you're running with Visual C++, Symantec C, or Borland's 
+ * development environment on the PC, you're all set. Or if you're on the Mac
+ * with Metrowerks, Symantec or MPW with SC you're ok too. For UNIX it shouldn't
+ * matter.
+
+ * Changes by sailesh on 9/26 
+
+ * There are two symbols used in the declaration of the JNI functions
+ * and native code that uses the JNI:
+ * JNICALL - specifies the calling convention 
+ * JNIEXPORT - specifies export status of the function 
+ * 
+ * The syntax to specify calling conventions is different in Win16 and
+ * Win32 - the brains at Micro$oft at work here. JavaSoft in their
+ * infinite wisdom cares for no platform other than Win32, and so they
+ * just define these two symbols as:
+
+ #define JNIEXPORT __declspec(dllexport)
+ #define JNICALL __stdcall
+
+ * We deal with this, in the way JRI defines the JRI_PUBLIC_API, by
+ * defining a macro called JNI_PUBLIC_API. Any of our developers who
+ * wish to use code for Win16 and Win32, _must_ use JNI_PUBLIC_API to
+ * be able to export functions properly.
+
+ * Since we must also maintain compatibility with JavaSoft, we
+ * continue to define the symbol JNIEXPORT. However, use of this
+ * internally is deprecated, since it will cause a mess on Win16.
+
+ * We _do not_ need a new symbol called JNICALL. Instead we
+ * redefine JNICALL in the same way JRI_CALLBACK was defined.
+
+ ******************************************************************************/
+
+/* DLL Entry modifiers... */
+#if defined(XP_OS2)
+#  ifdef XP_OS2_VACPP
+#     define JNI_PUBLIC_API(ResultType)      ResultType _System
+#     define JNI_PUBLIC_VAR(VarType)         VarType
+#     define JNICALL                         _Optlink
+#     define JNIEXPORT
+#  else
+#     define JNI_PUBLIC_API(ResultType)	   ResultType
+#     define JNI_PUBLIC_VAR(VarType)         VarType
+#     define JNICALL
+#     define JNIEXPORT
+#  endif
+/* Win32 */
+#elif defined(XP_WIN) || defined(_WINDOWS) || defined(WIN32) || defined(_WIN32)
+#	include <windows.h>
+#	if defined(_MSC_VER) || defined(__GNUC__)
+#		if defined(WIN32) || defined(_WIN32)
+#			define JNI_PUBLIC_API(ResultType)	_declspec(dllexport) ResultType __stdcall
+#			define JNI_PUBLIC_VAR(VarType)		VarType
+#			define JNI_NATIVE_STUB(ResultType)	_declspec(dllexport) ResultType
+#			define JNICALL                          __stdcall
+#		else /* !_WIN32 */
+#		    if defined(_WINDLL)
+#			define JNI_PUBLIC_API(ResultType)	ResultType __cdecl __export __loadds 
+#			define JNI_PUBLIC_VAR(VarType)		VarType
+#			define JNI_NATIVE_STUB(ResultType)	ResultType __cdecl __loadds
+#			define JNICALL			        __loadds
+#		    else /* !WINDLL */
+#			define JNI_PUBLIC_API(ResultType)	ResultType __cdecl __export
+#			define JNI_PUBLIC_VAR(VarType)		VarType
+#			define JNI_NATIVE_STUB(ResultType)	ResultType __cdecl __export
+#			define JNICALL			        __export
+#                   endif /* !WINDLL */
+#		endif /* !_WIN32 */
+#	elif defined(__BORLANDC__)
+#		if defined(WIN32) || defined(_WIN32)
+#			define JNI_PUBLIC_API(ResultType)	__export ResultType
+#			define JNI_PUBLIC_VAR(VarType)		VarType
+#			define JNI_NATIVE_STUB(ResultType)	 __export ResultType
+#			define JNICALL
+#		else /* !_WIN32 */
+#			define JNI_PUBLIC_API(ResultType)	ResultType _cdecl _export _loadds 
+#			define JNI_PUBLIC_VAR(VarType)		VarType
+#			define JNI_NATIVE_STUB(ResultType)	ResultType _cdecl _loadds
+#			define JNICALL			_loadds
+#		endif
+#	else
+#		error Unsupported PC development environment.	
+#	endif
+#	ifndef IS_LITTLE_ENDIAN
+#		define IS_LITTLE_ENDIAN
+#	endif
+	/*  This is the stuff inherited from JavaSoft .. */
+#	define JNIEXPORT __declspec(dllexport)
+
+
+/* Mac */
+#elif macintosh || Macintosh || THINK_C
+#	if defined(__MWERKS__)				/* Metrowerks */
+#		if !__option(enumsalwaysint)
+#			error You need to define 'Enums Always Int' for your project.
+#		endif
+#		if defined(TARGET_CPU_68K) && !TARGET_RT_MAC_CFM 
+#			if !__option(fourbyteints) 
+#				error You need to define 'Struct Alignment: 68k' for your project.
+#			endif
+#		endif /* !GENERATINGCFM */
+#		define JNI_PUBLIC_API(ResultType)	__declspec(export) ResultType 
+#		define JNI_PUBLIC_VAR(VarType)		JNI_PUBLIC_API(VarType)
+#		define JNI_NATIVE_STUB(ResultType)	JNI_PUBLIC_API(ResultType)
+#	elif defined(__SC__)				/* Symantec */
+#		error What are the Symantec defines? (warren@netscape.com)
+#	elif macintosh && applec			/* MPW */
+#		error Please upgrade to the latest MPW compiler (SC).
+#	else
+#		error Unsupported Mac development environment.
+#	endif
+#	define JNICALL
+	/*  This is the stuff inherited from JavaSoft .. */
+#	define JNIEXPORT
+
+/* Unix or else */
+#else
+#	define JNI_PUBLIC_API(ResultType)		ResultType
+#       define JNI_PUBLIC_VAR(VarType)                  VarType
+#       define JNI_NATIVE_STUB(ResultType)              ResultType
+#	define JNICALL
+	/*  This is the stuff inherited from JavaSoft .. */
+#	define JNIEXPORT
+#endif
+
+#ifndef FAR		/* for non-Win16 */
+#define FAR
+#endif
+
+/* Get the rest of the stuff from jri_md.h */
+#include "jri_md.h"
+
+#endif /* JNI_MD_H */
diff --git a/third_party/gecko/include/jri.h b/third_party/gecko/include/jri.h
index bb3cef1..f29945b 100644
--- a/third_party/gecko/include/jri.h
+++ b/third_party/gecko/include/jri.h
@@ -1,689 +1,689 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is 

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or 

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/*******************************************************************************

- * Java Runtime Interface

- ******************************************************************************/

-

-#ifndef JRI_H

-#define JRI_H

-

-#include "jritypes.h"

-

-#ifdef __cplusplus

-extern "C" {

-#endif /* __cplusplus */

-

-/*******************************************************************************

- * JRIEnv

- ******************************************************************************/

-

-/* The type of the JRIEnv interface. */

-typedef struct JRIEnvInterface	JRIEnvInterface;

-

-/* The type of a JRIEnv instance. */

-typedef const JRIEnvInterface*	JRIEnv;

-

-/*******************************************************************************

- * JRIEnv Operations

- ******************************************************************************/

-

-#define JRI_DefineClass(env, classLoader, buf, bufLen)	\

-	(((*(env))->DefineClass)(env, JRI_DefineClass_op, classLoader, buf, bufLen))

-

-#define JRI_FindClass(env, name)	\

-	(((*(env))->FindClass)(env, JRI_FindClass_op, name))

-

-#define JRI_Throw(env, obj)	\

-	(((*(env))->Throw)(env, JRI_Throw_op, obj))

-

-#define JRI_ThrowNew(env, clazz, message)	\

-	(((*(env))->ThrowNew)(env, JRI_ThrowNew_op, clazz, message))

-

-#define JRI_ExceptionOccurred(env)	\

-	(((*(env))->ExceptionOccurred)(env, JRI_ExceptionOccurred_op))

-

-#define JRI_ExceptionDescribe(env)	\

-	(((*(env))->ExceptionDescribe)(env, JRI_ExceptionDescribe_op))

-

-#define JRI_ExceptionClear(env)	\

-	(((*(env))->ExceptionClear)(env, JRI_ExceptionClear_op))

-

-#define JRI_NewGlobalRef(env, ref)	\

-	(((*(env))->NewGlobalRef)(env, JRI_NewGlobalRef_op, ref))

-

-#define JRI_DisposeGlobalRef(env, gref)	\

-	(((*(env))->DisposeGlobalRef)(env, JRI_DisposeGlobalRef_op, gref))

-

-#define JRI_GetGlobalRef(env, gref)	\

-	(((*(env))->GetGlobalRef)(env, JRI_GetGlobalRef_op, gref))

-

-#define JRI_SetGlobalRef(env, gref, ref)	\

-	(((*(env))->SetGlobalRef)(env, JRI_SetGlobalRef_op, gref, ref))

-

-#define JRI_IsSameObject(env, a, b)	\

-	(((*(env))->IsSameObject)(env, JRI_IsSameObject_op, a, b))

-

-#define JRI_NewObject(env)	((*(env))->NewObject)

-#define JRI_NewObjectV(env, clazz, methodID, args)	\

-	(((*(env))->NewObjectV)(env, JRI_NewObject_op_va_list, clazz, methodID, args))

-#define JRI_NewObjectA(env, clazz, method, args)	\

-	(((*(env))->NewObjectA)(env, JRI_NewObject_op_array, clazz, methodID, args))

-

-#define JRI_GetObjectClass(env, obj)	\

-	(((*(env))->GetObjectClass)(env, JRI_GetObjectClass_op, obj))

-

-#define JRI_IsInstanceOf(env, obj, clazz)	\

-	(((*(env))->IsInstanceOf)(env, JRI_IsInstanceOf_op, obj, clazz))

-

-#define JRI_GetMethodID(env, clazz, name, sig)	\

-	(((*(env))->GetMethodID)(env, JRI_GetMethodID_op, clazz, name, sig))

-

-#define JRI_CallMethod(env)	((*(env))->CallMethod)

-#define JRI_CallMethodV(env, obj, methodID, args)	\

-	(((*(env))->CallMethodV)(env, JRI_CallMethod_op_va_list, obj, methodID, args))

-#define JRI_CallMethodA(env, obj, methodID, args)	\

-	(((*(env))->CallMethodA)(env, JRI_CallMethod_op_array, obj, methodID, args))

-

-#define JRI_CallMethodBoolean(env)	((*(env))->CallMethodBoolean)

-#define JRI_CallMethodBooleanV(env, obj, methodID, args)	\

-	(((*(env))->CallMethodBooleanV)(env, JRI_CallMethodBoolean_op_va_list, obj, methodID, args))

-#define JRI_CallMethodBooleanA(env, obj, methodID, args)	\

-	(((*(env))->CallMethodBooleanA)(env, JRI_CallMethodBoolean_op_array, obj, methodID, args))

-

-#define JRI_CallMethodByte(env)	((*(env))->CallMethodByte)

-#define JRI_CallMethodByteV(env, obj, methodID, args)	\

-	(((*(env))->CallMethodByteV)(env, JRI_CallMethodByte_op_va_list, obj, methodID, args))

-#define JRI_CallMethodByteA(env, obj, methodID, args)	\

-	(((*(env))->CallMethodByteA)(env, JRI_CallMethodByte_op_array, obj, methodID, args))

-

-#define JRI_CallMethodChar(env)	((*(env))->CallMethodChar)

-#define JRI_CallMethodCharV(env, obj, methodID, args)	\

-	(((*(env))->CallMethodCharV)(env, JRI_CallMethodChar_op_va_list, obj, methodID, args))

-#define JRI_CallMethodCharA(env, obj, methodID, args)	\

-	(((*(env))->CallMethodCharA)(env, JRI_CallMethodChar_op_array, obj, methodID, args))

-

-#define JRI_CallMethodShort(env)	((*(env))->CallMethodShort)

-#define JRI_CallMethodShortV(env, obj, methodID, args)	\

-	(((*(env))->CallMethodShortV)(env, JRI_CallMethodShort_op_va_list, obj, methodID, args))

-#define JRI_CallMethodShortA(env, obj, methodID, args)	\

-	(((*(env))->CallMethodShortA)(env, JRI_CallMethodShort_op_array, obj, methodID, args))

-

-#define JRI_CallMethodInt(env)	((*(env))->CallMethodInt)

-#define JRI_CallMethodIntV(env, obj, methodID, args)	\

-	(((*(env))->CallMethodIntV)(env, JRI_CallMethodInt_op_va_list, obj, methodID, args))

-#define JRI_CallMethodIntA(env, obj, methodID, args)	\

-	(((*(env))->CallMethodIntA)(env, JRI_CallMethodInt_op_array, obj, methodID, args))

-

-#define JRI_CallMethodLong(env)	((*(env))->CallMethodLong)

-#define JRI_CallMethodLongV(env, obj, methodID, args)	\

-	(((*(env))->CallMethodLongV)(env, JRI_CallMethodLong_op_va_list, obj, methodID, args))

-#define JRI_CallMethodLongA(env, obj, methodID, args)	\

-	(((*(env))->CallMethodLongA)(env, JRI_CallMethodLong_op_array, obj, methodID, args))

-

-#define JRI_CallMethodFloat(env)	((*(env))->CallMethodFloat)

-#define JRI_CallMethodFloatV(env, obj, methodID, args)	\

-	(((*(env))->CallMethodFloatV)(env, JRI_CallMethodFloat_op_va_list, obj, methodID, args))

-#define JRI_CallMethodFloatA(env, obj, methodID, args)	\

-	(((*(env))->CallMethodFloatA)(env, JRI_CallMethodFloat_op_array, obj, methodID, args))

-

-#define JRI_CallMethodDouble(env)	((*(env))->CallMethodDouble)

-#define JRI_CallMethodDoubleV(env, obj, methodID, args)	\

-	(((*(env))->CallMethodDoubleV)(env, JRI_CallMethodDouble_op_va_list, obj, methodID, args))

-#define JRI_CallMethodDoubleA(env, obj, methodID, args)	\

-	(((*(env))->CallMethodDoubleA)(env, JRI_CallMethodDouble_op_array, obj, methodID, args))

-

-#define JRI_GetFieldID(env, clazz, name, sig)	\

-	(((*(env))->GetFieldID)(env, JRI_GetFieldID_op, clazz, name, sig))

-

-#define JRI_GetField(env, obj, fieldID)	\

-	(((*(env))->GetField)(env, JRI_GetField_op, obj, fieldID))

-

-#define JRI_GetFieldBoolean(env, obj, fieldID)	\

-	(((*(env))->GetFieldBoolean)(env, JRI_GetFieldBoolean_op, obj, fieldID))

-

-#define JRI_GetFieldByte(env, obj, fieldID)	\

-	(((*(env))->GetFieldByte)(env, JRI_GetFieldByte_op, obj, fieldID))

-

-#define JRI_GetFieldChar(env, obj, fieldID)	\

-	(((*(env))->GetFieldChar)(env, JRI_GetFieldChar_op, obj, fieldID))

-

-#define JRI_GetFieldShort(env, obj, fieldID)	\

-	(((*(env))->GetFieldShort)(env, JRI_GetFieldShort_op, obj, fieldID))

-

-#define JRI_GetFieldInt(env, obj, fieldID)	\

-	(((*(env))->GetFieldInt)(env, JRI_GetFieldInt_op, obj, fieldID))

-

-#define JRI_GetFieldLong(env, obj, fieldID)	\

-	(((*(env))->GetFieldLong)(env, JRI_GetFieldLong_op, obj, fieldID))

-

-#define JRI_GetFieldFloat(env, obj, fieldID)	\

-	(((*(env))->GetFieldFloat)(env, JRI_GetFieldFloat_op, obj, fieldID))

-

-#define JRI_GetFieldDouble(env, obj, fieldID)	\

-	(((*(env))->GetFieldDouble)(env, JRI_GetFieldDouble_op, obj, fieldID))

-

-#define JRI_SetField(env, obj, fieldID, value)	\

-	(((*(env))->SetField)(env, JRI_SetField_op, obj, fieldID, value))

-

-#define JRI_SetFieldBoolean(env, obj, fieldID, value)	\

-	(((*(env))->SetFieldBoolean)(env, JRI_SetFieldBoolean_op, obj, fieldID, value))

-

-#define JRI_SetFieldByte(env, obj, fieldID, value)	\

-	(((*(env))->SetFieldByte)(env, JRI_SetFieldByte_op, obj, fieldID, value))

-

-#define JRI_SetFieldChar(env, obj, fieldID, value)	\

-	(((*(env))->SetFieldChar)(env, JRI_SetFieldChar_op, obj, fieldID, value))

-

-#define JRI_SetFieldShort(env, obj, fieldID, value)	\

-	(((*(env))->SetFieldShort)(env, JRI_SetFieldShort_op, obj, fieldID, value))

-

-#define JRI_SetFieldInt(env, obj, fieldID, value)	\

-	(((*(env))->SetFieldInt)(env, JRI_SetFieldInt_op, obj, fieldID, value))

-

-#define JRI_SetFieldLong(env, obj, fieldID, value)	\

-	(((*(env))->SetFieldLong)(env, JRI_SetFieldLong_op, obj, fieldID, value))

-

-#define JRI_SetFieldFloat(env, obj, fieldID, value)	\

-	(((*(env))->SetFieldFloat)(env, JRI_SetFieldFloat_op, obj, fieldID, value))

-

-#define JRI_SetFieldDouble(env, obj, fieldID, value)	\

-	(((*(env))->SetFieldDouble)(env, JRI_SetFieldDouble_op, obj, fieldID, value))

-

-#define JRI_IsSubclassOf(env, a, b)	\

-	(((*(env))->IsSubclassOf)(env, JRI_IsSubclassOf_op, a, b))

-

-#define JRI_GetStaticMethodID(env, clazz, name, sig)	\

-	(((*(env))->GetStaticMethodID)(env, JRI_GetStaticMethodID_op, clazz, name, sig))

-

-#define JRI_CallStaticMethod(env)	((*(env))->CallStaticMethod)

-#define JRI_CallStaticMethodV(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodV)(env, JRI_CallStaticMethod_op_va_list, clazz, methodID, args))

-#define JRI_CallStaticMethodA(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodA)(env, JRI_CallStaticMethod_op_array, clazz, methodID, args))

-

-#define JRI_CallStaticMethodBoolean(env)	((*(env))->CallStaticMethodBoolean)

-#define JRI_CallStaticMethodBooleanV(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodBooleanV)(env, JRI_CallStaticMethodBoolean_op_va_list, clazz, methodID, args))

-#define JRI_CallStaticMethodBooleanA(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodBooleanA)(env, JRI_CallStaticMethodBoolean_op_array, clazz, methodID, args))

-

-#define JRI_CallStaticMethodByte(env)	((*(env))->CallStaticMethodByte)

-#define JRI_CallStaticMethodByteV(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodByteV)(env, JRI_CallStaticMethodByte_op_va_list, clazz, methodID, args))

-#define JRI_CallStaticMethodByteA(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodByteA)(env, JRI_CallStaticMethodByte_op_array, clazz, methodID, args))

-

-#define JRI_CallStaticMethodChar(env)	((*(env))->CallStaticMethodChar)

-#define JRI_CallStaticMethodCharV(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodCharV)(env, JRI_CallStaticMethodChar_op_va_list, clazz, methodID, args))

-#define JRI_CallStaticMethodCharA(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodCharA)(env, JRI_CallStaticMethodChar_op_array, clazz, methodID, args))

-

-#define JRI_CallStaticMethodShort(env)	((*(env))->CallStaticMethodShort)

-#define JRI_CallStaticMethodShortV(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodShortV)(env, JRI_CallStaticMethodShort_op_va_list, clazz, methodID, args))

-#define JRI_CallStaticMethodShortA(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodShortA)(env, JRI_CallStaticMethodShort_op_array, clazz, methodID, args))

-

-#define JRI_CallStaticMethodInt(env)	((*(env))->CallStaticMethodInt)

-#define JRI_CallStaticMethodIntV(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodIntV)(env, JRI_CallStaticMethodInt_op_va_list, clazz, methodID, args))

-#define JRI_CallStaticMethodIntA(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodIntA)(env, JRI_CallStaticMethodInt_op_array, clazz, methodID, args))

-

-#define JRI_CallStaticMethodLong(env)	((*(env))->CallStaticMethodLong)

-#define JRI_CallStaticMethodLongV(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodLongV)(env, JRI_CallStaticMethodLong_op_va_list, clazz, methodID, args))

-#define JRI_CallStaticMethodLongA(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodLongA)(env, JRI_CallStaticMethodLong_op_array, clazz, methodID, args))

-

-#define JRI_CallStaticMethodFloat(env)	((*(env))->CallStaticMethodFloat)

-#define JRI_CallStaticMethodFloatV(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodFloatV)(env, JRI_CallStaticMethodFloat_op_va_list, clazz, methodID, args))

-#define JRI_CallStaticMethodFloatA(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodFloatA)(env, JRI_CallStaticMethodFloat_op_array, clazz, methodID, args))

-

-#define JRI_CallStaticMethodDouble(env)	((*(env))->CallStaticMethodDouble)

-#define JRI_CallStaticMethodDoubleV(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodDoubleV)(env, JRI_CallStaticMethodDouble_op_va_list, clazz, methodID, args))

-#define JRI_CallStaticMethodDoubleA(env, clazz, methodID, args)	\

-	(((*(env))->CallStaticMethodDoubleA)(env, JRI_CallStaticMethodDouble_op_array, clazz, methodID, args))

-

-#define JRI_GetStaticFieldID(env, clazz, name, sig)	\

-	(((*(env))->GetStaticFieldID)(env, JRI_GetStaticFieldID_op, clazz, name, sig))

-

-#define JRI_GetStaticField(env, clazz, fieldID)	\

-	(((*(env))->GetStaticField)(env, JRI_GetStaticField_op, clazz, fieldID))

-

-#define JRI_GetStaticFieldBoolean(env, clazz, fieldID)	\

-	(((*(env))->GetStaticFieldBoolean)(env, JRI_GetStaticFieldBoolean_op, clazz, fieldID))

-

-#define JRI_GetStaticFieldByte(env, clazz, fieldID)	\

-	(((*(env))->GetStaticFieldByte)(env, JRI_GetStaticFieldByte_op, clazz, fieldID))

-

-#define JRI_GetStaticFieldChar(env, clazz, fieldID)	\

-	(((*(env))->GetStaticFieldChar)(env, JRI_GetStaticFieldChar_op, clazz, fieldID))

-

-#define JRI_GetStaticFieldShort(env, clazz, fieldID)	\

-	(((*(env))->GetStaticFieldShort)(env, JRI_GetStaticFieldShort_op, clazz, fieldID))

-

-#define JRI_GetStaticFieldInt(env, clazz, fieldID)	\

-	(((*(env))->GetStaticFieldInt)(env, JRI_GetStaticFieldInt_op, clazz, fieldID))

-

-#define JRI_GetStaticFieldLong(env, clazz, fieldID)	\

-	(((*(env))->GetStaticFieldLong)(env, JRI_GetStaticFieldLong_op, clazz, fieldID))

-

-#define JRI_GetStaticFieldFloat(env, clazz, fieldID)	\

-	(((*(env))->GetStaticFieldFloat)(env, JRI_GetStaticFieldFloat_op, clazz, fieldID))

-

-#define JRI_GetStaticFieldDouble(env, clazz, fieldID)	\

-	(((*(env))->GetStaticFieldDouble)(env, JRI_GetStaticFieldDouble_op, clazz, fieldID))

-

-#define JRI_SetStaticField(env, clazz, fieldID, value)	\

-	(((*(env))->SetStaticField)(env, JRI_SetStaticField_op, clazz, fieldID, value))

-

-#define JRI_SetStaticFieldBoolean(env, clazz, fieldID, value)	\

-	(((*(env))->SetStaticFieldBoolean)(env, JRI_SetStaticFieldBoolean_op, clazz, fieldID, value))

-

-#define JRI_SetStaticFieldByte(env, clazz, fieldID, value)	\

-	(((*(env))->SetStaticFieldByte)(env, JRI_SetStaticFieldByte_op, clazz, fieldID, value))

-

-#define JRI_SetStaticFieldChar(env, clazz, fieldID, value)	\

-	(((*(env))->SetStaticFieldChar)(env, JRI_SetStaticFieldChar_op, clazz, fieldID, value))

-

-#define JRI_SetStaticFieldShort(env, clazz, fieldID, value)	\

-	(((*(env))->SetStaticFieldShort)(env, JRI_SetStaticFieldShort_op, clazz, fieldID, value))

-

-#define JRI_SetStaticFieldInt(env, clazz, fieldID, value)	\

-	(((*(env))->SetStaticFieldInt)(env, JRI_SetStaticFieldInt_op, clazz, fieldID, value))

-

-#define JRI_SetStaticFieldLong(env, clazz, fieldID, value)	\

-	(((*(env))->SetStaticFieldLong)(env, JRI_SetStaticFieldLong_op, clazz, fieldID, value))

-

-#define JRI_SetStaticFieldFloat(env, clazz, fieldID, value)	\

-	(((*(env))->SetStaticFieldFloat)(env, JRI_SetStaticFieldFloat_op, clazz, fieldID, value))

-

-#define JRI_SetStaticFieldDouble(env, clazz, fieldID, value)	\

-	(((*(env))->SetStaticFieldDouble)(env, JRI_SetStaticFieldDouble_op, clazz, fieldID, value))

-

-#define JRI_NewString(env, unicode, len)	\

-	(((*(env))->NewString)(env, JRI_NewString_op, unicode, len))

-

-#define JRI_GetStringLength(env, string)	\

-	(((*(env))->GetStringLength)(env, JRI_GetStringLength_op, string))

-

-#define JRI_GetStringChars(env, string)	\

-	(((*(env))->GetStringChars)(env, JRI_GetStringChars_op, string))

-

-#define JRI_NewStringUTF(env, utf, len)	\

-	(((*(env))->NewStringUTF)(env, JRI_NewStringUTF_op, utf, len))

-

-#define JRI_GetStringUTFLength(env, string)	\

-	(((*(env))->GetStringUTFLength)(env, JRI_GetStringUTFLength_op, string))

-

-#define JRI_GetStringUTFChars(env, string)	\

-	(((*(env))->GetStringUTFChars)(env, JRI_GetStringUTFChars_op, string))

-

-#define JRI_NewScalarArray(env, length, elementSig, initialElements)	\

-	(((*(env))->NewScalarArray)(env, JRI_NewScalarArray_op, length, elementSig, initialElements))

-

-#define JRI_GetScalarArrayLength(env, array)	\

-	(((*(env))->GetScalarArrayLength)(env, JRI_GetScalarArrayLength_op, array))

-

-#define JRI_GetScalarArrayElements(env, array)	\

-	(((*(env))->GetScalarArrayElements)(env, JRI_GetScalarArrayElements_op, array))

-

-#define JRI_NewObjectArray(env, length, elementClass, initialElement)	\

-	(((*(env))->NewObjectArray)(env, JRI_NewObjectArray_op, length, elementClass, initialElement))

-

-#define JRI_GetObjectArrayLength(env, array)	\

-	(((*(env))->GetObjectArrayLength)(env, JRI_GetObjectArrayLength_op, array))

-

-#define JRI_GetObjectArrayElement(env, array, index)	\

-	(((*(env))->GetObjectArrayElement)(env, JRI_GetObjectArrayElement_op, array, index))

-

-#define JRI_SetObjectArrayElement(env, array, index, value)	\

-	(((*(env))->SetObjectArrayElement)(env, JRI_SetObjectArrayElement_op, array, index, value))

-

-#define JRI_RegisterNatives(env, clazz, nameAndSigArray, nativeProcArray)	\

-	(((*(env))->RegisterNatives)(env, JRI_RegisterNatives_op, clazz, nameAndSigArray, nativeProcArray))

-

-#define JRI_UnregisterNatives(env, clazz)	\

-	(((*(env))->UnregisterNatives)(env, JRI_UnregisterNatives_op, clazz))

-

-#define JRI_NewStringPlatform(env, string, len, encoding, encodingLength)	\

-	(((*(env))->NewStringPlatform)(env, JRI_NewStringPlatform_op, string, len, encoding, encodingLength))

-

-#define JRI_GetStringPlatformChars(env, string, encoding, encodingLength)	\

-	(((*(env))->GetStringPlatformChars)(env, JRI_GetStringPlatformChars_op, string, encoding, encodingLength))

-

-

-/*******************************************************************************

- * JRIEnv Interface

- ******************************************************************************/

-

-struct java_lang_ClassLoader;

-struct java_lang_Class;

-struct java_lang_Throwable;

-struct java_lang_Object;

-struct java_lang_String;

-

-struct JRIEnvInterface {

-	void*	reserved0;

-	void*	reserved1;

-	void*	reserved2;

-	void*	reserved3;

-	struct java_lang_Class*	(*FindClass)(JRIEnv* env, jint op, const char* a);

-	void	(*Throw)(JRIEnv* env, jint op, struct java_lang_Throwable* a);

-	void	(*ThrowNew)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b);

-	struct java_lang_Throwable*	(*ExceptionOccurred)(JRIEnv* env, jint op);

-	void	(*ExceptionDescribe)(JRIEnv* env, jint op);

-	void	(*ExceptionClear)(JRIEnv* env, jint op);

-	jglobal	(*NewGlobalRef)(JRIEnv* env, jint op, void* a);

-	void	(*DisposeGlobalRef)(JRIEnv* env, jint op, jglobal a);

-	void*	(*GetGlobalRef)(JRIEnv* env, jint op, jglobal a);

-	void	(*SetGlobalRef)(JRIEnv* env, jint op, jglobal a, void* b);

-	jbool	(*IsSameObject)(JRIEnv* env, jint op, void* a, void* b);

-	void*	(*NewObject)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);

-	void*	(*NewObjectV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);

-	void*	(*NewObjectA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);

-	struct java_lang_Class*	(*GetObjectClass)(JRIEnv* env, jint op, void* a);

-	jbool	(*IsInstanceOf)(JRIEnv* env, jint op, void* a, struct java_lang_Class* b);

-	jint	(*GetMethodID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c);

-	void*	(*CallMethod)(JRIEnv* env, jint op, void* a, jint b, ...);

-	void*	(*CallMethodV)(JRIEnv* env, jint op, void* a, jint b, va_list c);

-	void*	(*CallMethodA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);

-	jbool	(*CallMethodBoolean)(JRIEnv* env, jint op, void* a, jint b, ...);

-	jbool	(*CallMethodBooleanV)(JRIEnv* env, jint op, void* a, jint b, va_list c);

-	jbool	(*CallMethodBooleanA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);

-	jbyte	(*CallMethodByte)(JRIEnv* env, jint op, void* a, jint b, ...);

-	jbyte	(*CallMethodByteV)(JRIEnv* env, jint op, void* a, jint b, va_list c);

-	jbyte	(*CallMethodByteA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);

-	jchar	(*CallMethodChar)(JRIEnv* env, jint op, void* a, jint b, ...);

-	jchar	(*CallMethodCharV)(JRIEnv* env, jint op, void* a, jint b, va_list c);

-	jchar	(*CallMethodCharA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);

-	jshort	(*CallMethodShort)(JRIEnv* env, jint op, void* a, jint b, ...);

-	jshort	(*CallMethodShortV)(JRIEnv* env, jint op, void* a, jint b, va_list c);

-	jshort	(*CallMethodShortA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);

-	jint	(*CallMethodInt)(JRIEnv* env, jint op, void* a, jint b, ...);

-	jint	(*CallMethodIntV)(JRIEnv* env, jint op, void* a, jint b, va_list c);

-	jint	(*CallMethodIntA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);

-	jlong	(*CallMethodLong)(JRIEnv* env, jint op, void* a, jint b, ...);

-	jlong	(*CallMethodLongV)(JRIEnv* env, jint op, void* a, jint b, va_list c);

-	jlong	(*CallMethodLongA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);

-	jfloat	(*CallMethodFloat)(JRIEnv* env, jint op, void* a, jint b, ...);

-	jfloat	(*CallMethodFloatV)(JRIEnv* env, jint op, void* a, jint b, va_list c);

-	jfloat	(*CallMethodFloatA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);

-	jdouble	(*CallMethodDouble)(JRIEnv* env, jint op, void* a, jint b, ...);

-	jdouble	(*CallMethodDoubleV)(JRIEnv* env, jint op, void* a, jint b, va_list c);

-	jdouble	(*CallMethodDoubleA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);

-	jint	(*GetFieldID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c);

-	void*	(*GetField)(JRIEnv* env, jint op, void* a, jint b);

-	jbool	(*GetFieldBoolean)(JRIEnv* env, jint op, void* a, jint b);

-	jbyte	(*GetFieldByte)(JRIEnv* env, jint op, void* a, jint b);

-	jchar	(*GetFieldChar)(JRIEnv* env, jint op, void* a, jint b);

-	jshort	(*GetFieldShort)(JRIEnv* env, jint op, void* a, jint b);

-	jint	(*GetFieldInt)(JRIEnv* env, jint op, void* a, jint b);

-	jlong	(*GetFieldLong)(JRIEnv* env, jint op, void* a, jint b);

-	jfloat	(*GetFieldFloat)(JRIEnv* env, jint op, void* a, jint b);

-	jdouble	(*GetFieldDouble)(JRIEnv* env, jint op, void* a, jint b);

-	void	(*SetField)(JRIEnv* env, jint op, void* a, jint b, void* c);

-	void	(*SetFieldBoolean)(JRIEnv* env, jint op, void* a, jint b, jbool c);

-	void	(*SetFieldByte)(JRIEnv* env, jint op, void* a, jint b, jbyte c);

-	void	(*SetFieldChar)(JRIEnv* env, jint op, void* a, jint b, jchar c);

-	void	(*SetFieldShort)(JRIEnv* env, jint op, void* a, jint b, jshort c);

-	void	(*SetFieldInt)(JRIEnv* env, jint op, void* a, jint b, jint c);

-	void	(*SetFieldLong)(JRIEnv* env, jint op, void* a, jint b, jlong c);

-	void	(*SetFieldFloat)(JRIEnv* env, jint op, void* a, jint b, jfloat c);

-	void	(*SetFieldDouble)(JRIEnv* env, jint op, void* a, jint b, jdouble c);

-	jbool	(*IsSubclassOf)(JRIEnv* env, jint op, struct java_lang_Class* a, struct java_lang_Class* b);

-	jint	(*GetStaticMethodID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c);

-	void*	(*CallStaticMethod)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);

-	void*	(*CallStaticMethodV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);

-	void*	(*CallStaticMethodA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);

-	jbool	(*CallStaticMethodBoolean)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);

-	jbool	(*CallStaticMethodBooleanV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);

-	jbool	(*CallStaticMethodBooleanA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);

-	jbyte	(*CallStaticMethodByte)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);

-	jbyte	(*CallStaticMethodByteV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);

-	jbyte	(*CallStaticMethodByteA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);

-	jchar	(*CallStaticMethodChar)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);

-	jchar	(*CallStaticMethodCharV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);

-	jchar	(*CallStaticMethodCharA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);

-	jshort	(*CallStaticMethodShort)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);

-	jshort	(*CallStaticMethodShortV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);

-	jshort	(*CallStaticMethodShortA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);

-	jint	(*CallStaticMethodInt)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);

-	jint	(*CallStaticMethodIntV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);

-	jint	(*CallStaticMethodIntA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);

-	jlong	(*CallStaticMethodLong)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);

-	jlong	(*CallStaticMethodLongV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);

-	jlong	(*CallStaticMethodLongA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);

-	jfloat	(*CallStaticMethodFloat)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);

-	jfloat	(*CallStaticMethodFloatV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);

-	jfloat	(*CallStaticMethodFloatA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);

-	jdouble	(*CallStaticMethodDouble)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);

-	jdouble	(*CallStaticMethodDoubleV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);

-	jdouble	(*CallStaticMethodDoubleA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);

-	jint	(*GetStaticFieldID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c);

-	void*	(*GetStaticField)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);

-	jbool	(*GetStaticFieldBoolean)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);

-	jbyte	(*GetStaticFieldByte)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);

-	jchar	(*GetStaticFieldChar)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);

-	jshort	(*GetStaticFieldShort)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);

-	jint	(*GetStaticFieldInt)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);

-	jlong	(*GetStaticFieldLong)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);

-	jfloat	(*GetStaticFieldFloat)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);

-	jdouble	(*GetStaticFieldDouble)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);

-	void	(*SetStaticField)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, void* c);

-	void	(*SetStaticFieldBoolean)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jbool c);

-	void	(*SetStaticFieldByte)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jbyte c);

-	void	(*SetStaticFieldChar)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jchar c);

-	void	(*SetStaticFieldShort)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jshort c);

-	void	(*SetStaticFieldInt)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jint c);

-	void	(*SetStaticFieldLong)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jlong c);

-	void	(*SetStaticFieldFloat)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jfloat c);

-	void	(*SetStaticFieldDouble)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jdouble c);

-	struct java_lang_String*	(*NewString)(JRIEnv* env, jint op, const jchar* a, jint b);

-	jint	(*GetStringLength)(JRIEnv* env, jint op, struct java_lang_String* a);

-	const jchar*	(*GetStringChars)(JRIEnv* env, jint op, struct java_lang_String* a);

-	struct java_lang_String*	(*NewStringUTF)(JRIEnv* env, jint op, const jbyte* a, jint b);

-	jint	(*GetStringUTFLength)(JRIEnv* env, jint op, struct java_lang_String* a);

-	const jbyte*	(*GetStringUTFChars)(JRIEnv* env, jint op, struct java_lang_String* a);

-	void*	(*NewScalarArray)(JRIEnv* env, jint op, jint a, const char* b, const jbyte* c);

-	jint	(*GetScalarArrayLength)(JRIEnv* env, jint op, void* a);

-	jbyte*	(*GetScalarArrayElements)(JRIEnv* env, jint op, void* a);

-	void*	(*NewObjectArray)(JRIEnv* env, jint op, jint a, struct java_lang_Class* b, void* c);

-	jint	(*GetObjectArrayLength)(JRIEnv* env, jint op, void* a);

-	void*	(*GetObjectArrayElement)(JRIEnv* env, jint op, void* a, jint b);

-	void	(*SetObjectArrayElement)(JRIEnv* env, jint op, void* a, jint b, void* c);

-	void	(*RegisterNatives)(JRIEnv* env, jint op, struct java_lang_Class* a, char** b, void** c);

-	void	(*UnregisterNatives)(JRIEnv* env, jint op, struct java_lang_Class* a);

-	struct java_lang_Class*	(*DefineClass)(JRIEnv* env, jint op, struct java_lang_ClassLoader* a, jbyte* b, jsize bLen);

-	struct java_lang_String*	(*NewStringPlatform)(JRIEnv* env, jint op, const jbyte* a, jint b, const jbyte* c, jint d);

-	const jbyte*	(*GetStringPlatformChars)(JRIEnv* env, jint op, struct java_lang_String* a, const jbyte* b, jint c);

-};

-

-/*

-** ****************************************************************************

-** JRIEnv Operation IDs

-** ***************************************************************************

-*/

-

-typedef enum JRIEnvOperations {

-	JRI_Reserved0_op,

-	JRI_Reserved1_op,

-	JRI_Reserved2_op,

-	JRI_Reserved3_op,

-	JRI_FindClass_op,

-	JRI_Throw_op,

-	JRI_ThrowNew_op,

-	JRI_ExceptionOccurred_op,

-	JRI_ExceptionDescribe_op,

-	JRI_ExceptionClear_op,

-	JRI_NewGlobalRef_op,

-	JRI_DisposeGlobalRef_op,

-	JRI_GetGlobalRef_op,

-	JRI_SetGlobalRef_op,

-	JRI_IsSameObject_op,

-	JRI_NewObject_op,

-	JRI_NewObject_op_va_list,

-	JRI_NewObject_op_array,

-	JRI_GetObjectClass_op,

-	JRI_IsInstanceOf_op,

-	JRI_GetMethodID_op,

-	JRI_CallMethod_op,

-	JRI_CallMethod_op_va_list,

-	JRI_CallMethod_op_array,

-	JRI_CallMethodBoolean_op,

-	JRI_CallMethodBoolean_op_va_list,

-	JRI_CallMethodBoolean_op_array,

-	JRI_CallMethodByte_op,

-	JRI_CallMethodByte_op_va_list,

-	JRI_CallMethodByte_op_array,

-	JRI_CallMethodChar_op,

-	JRI_CallMethodChar_op_va_list,

-	JRI_CallMethodChar_op_array,

-	JRI_CallMethodShort_op,

-	JRI_CallMethodShort_op_va_list,

-	JRI_CallMethodShort_op_array,

-	JRI_CallMethodInt_op,

-	JRI_CallMethodInt_op_va_list,

-	JRI_CallMethodInt_op_array,

-	JRI_CallMethodLong_op,

-	JRI_CallMethodLong_op_va_list,

-	JRI_CallMethodLong_op_array,

-	JRI_CallMethodFloat_op,

-	JRI_CallMethodFloat_op_va_list,

-	JRI_CallMethodFloat_op_array,

-	JRI_CallMethodDouble_op,

-	JRI_CallMethodDouble_op_va_list,

-	JRI_CallMethodDouble_op_array,

-	JRI_GetFieldID_op,

-	JRI_GetField_op,

-	JRI_GetFieldBoolean_op,

-	JRI_GetFieldByte_op,

-	JRI_GetFieldChar_op,

-	JRI_GetFieldShort_op,

-	JRI_GetFieldInt_op,

-	JRI_GetFieldLong_op,

-	JRI_GetFieldFloat_op,

-	JRI_GetFieldDouble_op,

-	JRI_SetField_op,

-	JRI_SetFieldBoolean_op,

-	JRI_SetFieldByte_op,

-	JRI_SetFieldChar_op,

-	JRI_SetFieldShort_op,

-	JRI_SetFieldInt_op,

-	JRI_SetFieldLong_op,

-	JRI_SetFieldFloat_op,

-	JRI_SetFieldDouble_op,

-	JRI_IsSubclassOf_op,

-	JRI_GetStaticMethodID_op,

-	JRI_CallStaticMethod_op,

-	JRI_CallStaticMethod_op_va_list,

-	JRI_CallStaticMethod_op_array,

-	JRI_CallStaticMethodBoolean_op,

-	JRI_CallStaticMethodBoolean_op_va_list,

-	JRI_CallStaticMethodBoolean_op_array,

-	JRI_CallStaticMethodByte_op,

-	JRI_CallStaticMethodByte_op_va_list,

-	JRI_CallStaticMethodByte_op_array,

-	JRI_CallStaticMethodChar_op,

-	JRI_CallStaticMethodChar_op_va_list,

-	JRI_CallStaticMethodChar_op_array,

-	JRI_CallStaticMethodShort_op,

-	JRI_CallStaticMethodShort_op_va_list,

-	JRI_CallStaticMethodShort_op_array,

-	JRI_CallStaticMethodInt_op,

-	JRI_CallStaticMethodInt_op_va_list,

-	JRI_CallStaticMethodInt_op_array,

-	JRI_CallStaticMethodLong_op,

-	JRI_CallStaticMethodLong_op_va_list,

-	JRI_CallStaticMethodLong_op_array,

-	JRI_CallStaticMethodFloat_op,

-	JRI_CallStaticMethodFloat_op_va_list,

-	JRI_CallStaticMethodFloat_op_array,

-	JRI_CallStaticMethodDouble_op,

-	JRI_CallStaticMethodDouble_op_va_list,

-	JRI_CallStaticMethodDouble_op_array,

-	JRI_GetStaticFieldID_op,

-	JRI_GetStaticField_op,

-	JRI_GetStaticFieldBoolean_op,

-	JRI_GetStaticFieldByte_op,

-	JRI_GetStaticFieldChar_op,

-	JRI_GetStaticFieldShort_op,

-	JRI_GetStaticFieldInt_op,

-	JRI_GetStaticFieldLong_op,

-	JRI_GetStaticFieldFloat_op,

-	JRI_GetStaticFieldDouble_op,

-	JRI_SetStaticField_op,

-	JRI_SetStaticFieldBoolean_op,

-	JRI_SetStaticFieldByte_op,

-	JRI_SetStaticFieldChar_op,

-	JRI_SetStaticFieldShort_op,

-	JRI_SetStaticFieldInt_op,

-	JRI_SetStaticFieldLong_op,

-	JRI_SetStaticFieldFloat_op,

-	JRI_SetStaticFieldDouble_op,

-	JRI_NewString_op,

-	JRI_GetStringLength_op,

-	JRI_GetStringChars_op,

-	JRI_NewStringUTF_op,

-	JRI_GetStringUTFLength_op,

-	JRI_GetStringUTFChars_op,

-	JRI_NewScalarArray_op,

-	JRI_GetScalarArrayLength_op,

-	JRI_GetScalarArrayElements_op,

-	JRI_NewObjectArray_op,

-	JRI_GetObjectArrayLength_op,

-	JRI_GetObjectArrayElement_op,

-	JRI_SetObjectArrayElement_op,

-	JRI_RegisterNatives_op,

-	JRI_UnregisterNatives_op,

-	JRI_DefineClass_op,

-	JRI_NewStringPlatform_op,

-	JRI_GetStringPlatformChars_op

-} JRIEnvOperations;

-

-#ifdef __cplusplus

-} /* extern "C" */

-#endif /* __cplusplus */

-

-#endif /* JRI_H */

-/******************************************************************************/

+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*******************************************************************************
+ * Java Runtime Interface
+ ******************************************************************************/
+
+#ifndef JRI_H
+#define JRI_H
+
+#include "jritypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*******************************************************************************
+ * JRIEnv
+ ******************************************************************************/
+
+/* The type of the JRIEnv interface. */
+typedef struct JRIEnvInterface	JRIEnvInterface;
+
+/* The type of a JRIEnv instance. */
+typedef const JRIEnvInterface*	JRIEnv;
+
+/*******************************************************************************
+ * JRIEnv Operations
+ ******************************************************************************/
+
+#define JRI_DefineClass(env, classLoader, buf, bufLen)	\
+	(((*(env))->DefineClass)(env, JRI_DefineClass_op, classLoader, buf, bufLen))
+
+#define JRI_FindClass(env, name)	\
+	(((*(env))->FindClass)(env, JRI_FindClass_op, name))
+
+#define JRI_Throw(env, obj)	\
+	(((*(env))->Throw)(env, JRI_Throw_op, obj))
+
+#define JRI_ThrowNew(env, clazz, message)	\
+	(((*(env))->ThrowNew)(env, JRI_ThrowNew_op, clazz, message))
+
+#define JRI_ExceptionOccurred(env)	\
+	(((*(env))->ExceptionOccurred)(env, JRI_ExceptionOccurred_op))
+
+#define JRI_ExceptionDescribe(env)	\
+	(((*(env))->ExceptionDescribe)(env, JRI_ExceptionDescribe_op))
+
+#define JRI_ExceptionClear(env)	\
+	(((*(env))->ExceptionClear)(env, JRI_ExceptionClear_op))
+
+#define JRI_NewGlobalRef(env, ref)	\
+	(((*(env))->NewGlobalRef)(env, JRI_NewGlobalRef_op, ref))
+
+#define JRI_DisposeGlobalRef(env, gref)	\
+	(((*(env))->DisposeGlobalRef)(env, JRI_DisposeGlobalRef_op, gref))
+
+#define JRI_GetGlobalRef(env, gref)	\
+	(((*(env))->GetGlobalRef)(env, JRI_GetGlobalRef_op, gref))
+
+#define JRI_SetGlobalRef(env, gref, ref)	\
+	(((*(env))->SetGlobalRef)(env, JRI_SetGlobalRef_op, gref, ref))
+
+#define JRI_IsSameObject(env, a, b)	\
+	(((*(env))->IsSameObject)(env, JRI_IsSameObject_op, a, b))
+
+#define JRI_NewObject(env)	((*(env))->NewObject)
+#define JRI_NewObjectV(env, clazz, methodID, args)	\
+	(((*(env))->NewObjectV)(env, JRI_NewObject_op_va_list, clazz, methodID, args))
+#define JRI_NewObjectA(env, clazz, method, args)	\
+	(((*(env))->NewObjectA)(env, JRI_NewObject_op_array, clazz, methodID, args))
+
+#define JRI_GetObjectClass(env, obj)	\
+	(((*(env))->GetObjectClass)(env, JRI_GetObjectClass_op, obj))
+
+#define JRI_IsInstanceOf(env, obj, clazz)	\
+	(((*(env))->IsInstanceOf)(env, JRI_IsInstanceOf_op, obj, clazz))
+
+#define JRI_GetMethodID(env, clazz, name, sig)	\
+	(((*(env))->GetMethodID)(env, JRI_GetMethodID_op, clazz, name, sig))
+
+#define JRI_CallMethod(env)	((*(env))->CallMethod)
+#define JRI_CallMethodV(env, obj, methodID, args)	\
+	(((*(env))->CallMethodV)(env, JRI_CallMethod_op_va_list, obj, methodID, args))
+#define JRI_CallMethodA(env, obj, methodID, args)	\
+	(((*(env))->CallMethodA)(env, JRI_CallMethod_op_array, obj, methodID, args))
+
+#define JRI_CallMethodBoolean(env)	((*(env))->CallMethodBoolean)
+#define JRI_CallMethodBooleanV(env, obj, methodID, args)	\
+	(((*(env))->CallMethodBooleanV)(env, JRI_CallMethodBoolean_op_va_list, obj, methodID, args))
+#define JRI_CallMethodBooleanA(env, obj, methodID, args)	\
+	(((*(env))->CallMethodBooleanA)(env, JRI_CallMethodBoolean_op_array, obj, methodID, args))
+
+#define JRI_CallMethodByte(env)	((*(env))->CallMethodByte)
+#define JRI_CallMethodByteV(env, obj, methodID, args)	\
+	(((*(env))->CallMethodByteV)(env, JRI_CallMethodByte_op_va_list, obj, methodID, args))
+#define JRI_CallMethodByteA(env, obj, methodID, args)	\
+	(((*(env))->CallMethodByteA)(env, JRI_CallMethodByte_op_array, obj, methodID, args))
+
+#define JRI_CallMethodChar(env)	((*(env))->CallMethodChar)
+#define JRI_CallMethodCharV(env, obj, methodID, args)	\
+	(((*(env))->CallMethodCharV)(env, JRI_CallMethodChar_op_va_list, obj, methodID, args))
+#define JRI_CallMethodCharA(env, obj, methodID, args)	\
+	(((*(env))->CallMethodCharA)(env, JRI_CallMethodChar_op_array, obj, methodID, args))
+
+#define JRI_CallMethodShort(env)	((*(env))->CallMethodShort)
+#define JRI_CallMethodShortV(env, obj, methodID, args)	\
+	(((*(env))->CallMethodShortV)(env, JRI_CallMethodShort_op_va_list, obj, methodID, args))
+#define JRI_CallMethodShortA(env, obj, methodID, args)	\
+	(((*(env))->CallMethodShortA)(env, JRI_CallMethodShort_op_array, obj, methodID, args))
+
+#define JRI_CallMethodInt(env)	((*(env))->CallMethodInt)
+#define JRI_CallMethodIntV(env, obj, methodID, args)	\
+	(((*(env))->CallMethodIntV)(env, JRI_CallMethodInt_op_va_list, obj, methodID, args))
+#define JRI_CallMethodIntA(env, obj, methodID, args)	\
+	(((*(env))->CallMethodIntA)(env, JRI_CallMethodInt_op_array, obj, methodID, args))
+
+#define JRI_CallMethodLong(env)	((*(env))->CallMethodLong)
+#define JRI_CallMethodLongV(env, obj, methodID, args)	\
+	(((*(env))->CallMethodLongV)(env, JRI_CallMethodLong_op_va_list, obj, methodID, args))
+#define JRI_CallMethodLongA(env, obj, methodID, args)	\
+	(((*(env))->CallMethodLongA)(env, JRI_CallMethodLong_op_array, obj, methodID, args))
+
+#define JRI_CallMethodFloat(env)	((*(env))->CallMethodFloat)
+#define JRI_CallMethodFloatV(env, obj, methodID, args)	\
+	(((*(env))->CallMethodFloatV)(env, JRI_CallMethodFloat_op_va_list, obj, methodID, args))
+#define JRI_CallMethodFloatA(env, obj, methodID, args)	\
+	(((*(env))->CallMethodFloatA)(env, JRI_CallMethodFloat_op_array, obj, methodID, args))
+
+#define JRI_CallMethodDouble(env)	((*(env))->CallMethodDouble)
+#define JRI_CallMethodDoubleV(env, obj, methodID, args)	\
+	(((*(env))->CallMethodDoubleV)(env, JRI_CallMethodDouble_op_va_list, obj, methodID, args))
+#define JRI_CallMethodDoubleA(env, obj, methodID, args)	\
+	(((*(env))->CallMethodDoubleA)(env, JRI_CallMethodDouble_op_array, obj, methodID, args))
+
+#define JRI_GetFieldID(env, clazz, name, sig)	\
+	(((*(env))->GetFieldID)(env, JRI_GetFieldID_op, clazz, name, sig))
+
+#define JRI_GetField(env, obj, fieldID)	\
+	(((*(env))->GetField)(env, JRI_GetField_op, obj, fieldID))
+
+#define JRI_GetFieldBoolean(env, obj, fieldID)	\
+	(((*(env))->GetFieldBoolean)(env, JRI_GetFieldBoolean_op, obj, fieldID))
+
+#define JRI_GetFieldByte(env, obj, fieldID)	\
+	(((*(env))->GetFieldByte)(env, JRI_GetFieldByte_op, obj, fieldID))
+
+#define JRI_GetFieldChar(env, obj, fieldID)	\
+	(((*(env))->GetFieldChar)(env, JRI_GetFieldChar_op, obj, fieldID))
+
+#define JRI_GetFieldShort(env, obj, fieldID)	\
+	(((*(env))->GetFieldShort)(env, JRI_GetFieldShort_op, obj, fieldID))
+
+#define JRI_GetFieldInt(env, obj, fieldID)	\
+	(((*(env))->GetFieldInt)(env, JRI_GetFieldInt_op, obj, fieldID))
+
+#define JRI_GetFieldLong(env, obj, fieldID)	\
+	(((*(env))->GetFieldLong)(env, JRI_GetFieldLong_op, obj, fieldID))
+
+#define JRI_GetFieldFloat(env, obj, fieldID)	\
+	(((*(env))->GetFieldFloat)(env, JRI_GetFieldFloat_op, obj, fieldID))
+
+#define JRI_GetFieldDouble(env, obj, fieldID)	\
+	(((*(env))->GetFieldDouble)(env, JRI_GetFieldDouble_op, obj, fieldID))
+
+#define JRI_SetField(env, obj, fieldID, value)	\
+	(((*(env))->SetField)(env, JRI_SetField_op, obj, fieldID, value))
+
+#define JRI_SetFieldBoolean(env, obj, fieldID, value)	\
+	(((*(env))->SetFieldBoolean)(env, JRI_SetFieldBoolean_op, obj, fieldID, value))
+
+#define JRI_SetFieldByte(env, obj, fieldID, value)	\
+	(((*(env))->SetFieldByte)(env, JRI_SetFieldByte_op, obj, fieldID, value))
+
+#define JRI_SetFieldChar(env, obj, fieldID, value)	\
+	(((*(env))->SetFieldChar)(env, JRI_SetFieldChar_op, obj, fieldID, value))
+
+#define JRI_SetFieldShort(env, obj, fieldID, value)	\
+	(((*(env))->SetFieldShort)(env, JRI_SetFieldShort_op, obj, fieldID, value))
+
+#define JRI_SetFieldInt(env, obj, fieldID, value)	\
+	(((*(env))->SetFieldInt)(env, JRI_SetFieldInt_op, obj, fieldID, value))
+
+#define JRI_SetFieldLong(env, obj, fieldID, value)	\
+	(((*(env))->SetFieldLong)(env, JRI_SetFieldLong_op, obj, fieldID, value))
+
+#define JRI_SetFieldFloat(env, obj, fieldID, value)	\
+	(((*(env))->SetFieldFloat)(env, JRI_SetFieldFloat_op, obj, fieldID, value))
+
+#define JRI_SetFieldDouble(env, obj, fieldID, value)	\
+	(((*(env))->SetFieldDouble)(env, JRI_SetFieldDouble_op, obj, fieldID, value))
+
+#define JRI_IsSubclassOf(env, a, b)	\
+	(((*(env))->IsSubclassOf)(env, JRI_IsSubclassOf_op, a, b))
+
+#define JRI_GetStaticMethodID(env, clazz, name, sig)	\
+	(((*(env))->GetStaticMethodID)(env, JRI_GetStaticMethodID_op, clazz, name, sig))
+
+#define JRI_CallStaticMethod(env)	((*(env))->CallStaticMethod)
+#define JRI_CallStaticMethodV(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodV)(env, JRI_CallStaticMethod_op_va_list, clazz, methodID, args))
+#define JRI_CallStaticMethodA(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodA)(env, JRI_CallStaticMethod_op_array, clazz, methodID, args))
+
+#define JRI_CallStaticMethodBoolean(env)	((*(env))->CallStaticMethodBoolean)
+#define JRI_CallStaticMethodBooleanV(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodBooleanV)(env, JRI_CallStaticMethodBoolean_op_va_list, clazz, methodID, args))
+#define JRI_CallStaticMethodBooleanA(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodBooleanA)(env, JRI_CallStaticMethodBoolean_op_array, clazz, methodID, args))
+
+#define JRI_CallStaticMethodByte(env)	((*(env))->CallStaticMethodByte)
+#define JRI_CallStaticMethodByteV(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodByteV)(env, JRI_CallStaticMethodByte_op_va_list, clazz, methodID, args))
+#define JRI_CallStaticMethodByteA(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodByteA)(env, JRI_CallStaticMethodByte_op_array, clazz, methodID, args))
+
+#define JRI_CallStaticMethodChar(env)	((*(env))->CallStaticMethodChar)
+#define JRI_CallStaticMethodCharV(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodCharV)(env, JRI_CallStaticMethodChar_op_va_list, clazz, methodID, args))
+#define JRI_CallStaticMethodCharA(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodCharA)(env, JRI_CallStaticMethodChar_op_array, clazz, methodID, args))
+
+#define JRI_CallStaticMethodShort(env)	((*(env))->CallStaticMethodShort)
+#define JRI_CallStaticMethodShortV(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodShortV)(env, JRI_CallStaticMethodShort_op_va_list, clazz, methodID, args))
+#define JRI_CallStaticMethodShortA(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodShortA)(env, JRI_CallStaticMethodShort_op_array, clazz, methodID, args))
+
+#define JRI_CallStaticMethodInt(env)	((*(env))->CallStaticMethodInt)
+#define JRI_CallStaticMethodIntV(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodIntV)(env, JRI_CallStaticMethodInt_op_va_list, clazz, methodID, args))
+#define JRI_CallStaticMethodIntA(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodIntA)(env, JRI_CallStaticMethodInt_op_array, clazz, methodID, args))
+
+#define JRI_CallStaticMethodLong(env)	((*(env))->CallStaticMethodLong)
+#define JRI_CallStaticMethodLongV(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodLongV)(env, JRI_CallStaticMethodLong_op_va_list, clazz, methodID, args))
+#define JRI_CallStaticMethodLongA(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodLongA)(env, JRI_CallStaticMethodLong_op_array, clazz, methodID, args))
+
+#define JRI_CallStaticMethodFloat(env)	((*(env))->CallStaticMethodFloat)
+#define JRI_CallStaticMethodFloatV(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodFloatV)(env, JRI_CallStaticMethodFloat_op_va_list, clazz, methodID, args))
+#define JRI_CallStaticMethodFloatA(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodFloatA)(env, JRI_CallStaticMethodFloat_op_array, clazz, methodID, args))
+
+#define JRI_CallStaticMethodDouble(env)	((*(env))->CallStaticMethodDouble)
+#define JRI_CallStaticMethodDoubleV(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodDoubleV)(env, JRI_CallStaticMethodDouble_op_va_list, clazz, methodID, args))
+#define JRI_CallStaticMethodDoubleA(env, clazz, methodID, args)	\
+	(((*(env))->CallStaticMethodDoubleA)(env, JRI_CallStaticMethodDouble_op_array, clazz, methodID, args))
+
+#define JRI_GetStaticFieldID(env, clazz, name, sig)	\
+	(((*(env))->GetStaticFieldID)(env, JRI_GetStaticFieldID_op, clazz, name, sig))
+
+#define JRI_GetStaticField(env, clazz, fieldID)	\
+	(((*(env))->GetStaticField)(env, JRI_GetStaticField_op, clazz, fieldID))
+
+#define JRI_GetStaticFieldBoolean(env, clazz, fieldID)	\
+	(((*(env))->GetStaticFieldBoolean)(env, JRI_GetStaticFieldBoolean_op, clazz, fieldID))
+
+#define JRI_GetStaticFieldByte(env, clazz, fieldID)	\
+	(((*(env))->GetStaticFieldByte)(env, JRI_GetStaticFieldByte_op, clazz, fieldID))
+
+#define JRI_GetStaticFieldChar(env, clazz, fieldID)	\
+	(((*(env))->GetStaticFieldChar)(env, JRI_GetStaticFieldChar_op, clazz, fieldID))
+
+#define JRI_GetStaticFieldShort(env, clazz, fieldID)	\
+	(((*(env))->GetStaticFieldShort)(env, JRI_GetStaticFieldShort_op, clazz, fieldID))
+
+#define JRI_GetStaticFieldInt(env, clazz, fieldID)	\
+	(((*(env))->GetStaticFieldInt)(env, JRI_GetStaticFieldInt_op, clazz, fieldID))
+
+#define JRI_GetStaticFieldLong(env, clazz, fieldID)	\
+	(((*(env))->GetStaticFieldLong)(env, JRI_GetStaticFieldLong_op, clazz, fieldID))
+
+#define JRI_GetStaticFieldFloat(env, clazz, fieldID)	\
+	(((*(env))->GetStaticFieldFloat)(env, JRI_GetStaticFieldFloat_op, clazz, fieldID))
+
+#define JRI_GetStaticFieldDouble(env, clazz, fieldID)	\
+	(((*(env))->GetStaticFieldDouble)(env, JRI_GetStaticFieldDouble_op, clazz, fieldID))
+
+#define JRI_SetStaticField(env, clazz, fieldID, value)	\
+	(((*(env))->SetStaticField)(env, JRI_SetStaticField_op, clazz, fieldID, value))
+
+#define JRI_SetStaticFieldBoolean(env, clazz, fieldID, value)	\
+	(((*(env))->SetStaticFieldBoolean)(env, JRI_SetStaticFieldBoolean_op, clazz, fieldID, value))
+
+#define JRI_SetStaticFieldByte(env, clazz, fieldID, value)	\
+	(((*(env))->SetStaticFieldByte)(env, JRI_SetStaticFieldByte_op, clazz, fieldID, value))
+
+#define JRI_SetStaticFieldChar(env, clazz, fieldID, value)	\
+	(((*(env))->SetStaticFieldChar)(env, JRI_SetStaticFieldChar_op, clazz, fieldID, value))
+
+#define JRI_SetStaticFieldShort(env, clazz, fieldID, value)	\
+	(((*(env))->SetStaticFieldShort)(env, JRI_SetStaticFieldShort_op, clazz, fieldID, value))
+
+#define JRI_SetStaticFieldInt(env, clazz, fieldID, value)	\
+	(((*(env))->SetStaticFieldInt)(env, JRI_SetStaticFieldInt_op, clazz, fieldID, value))
+
+#define JRI_SetStaticFieldLong(env, clazz, fieldID, value)	\
+	(((*(env))->SetStaticFieldLong)(env, JRI_SetStaticFieldLong_op, clazz, fieldID, value))
+
+#define JRI_SetStaticFieldFloat(env, clazz, fieldID, value)	\
+	(((*(env))->SetStaticFieldFloat)(env, JRI_SetStaticFieldFloat_op, clazz, fieldID, value))
+
+#define JRI_SetStaticFieldDouble(env, clazz, fieldID, value)	\
+	(((*(env))->SetStaticFieldDouble)(env, JRI_SetStaticFieldDouble_op, clazz, fieldID, value))
+
+#define JRI_NewString(env, unicode, len)	\
+	(((*(env))->NewString)(env, JRI_NewString_op, unicode, len))
+
+#define JRI_GetStringLength(env, string)	\
+	(((*(env))->GetStringLength)(env, JRI_GetStringLength_op, string))
+
+#define JRI_GetStringChars(env, string)	\
+	(((*(env))->GetStringChars)(env, JRI_GetStringChars_op, string))
+
+#define JRI_NewStringUTF(env, utf, len)	\
+	(((*(env))->NewStringUTF)(env, JRI_NewStringUTF_op, utf, len))
+
+#define JRI_GetStringUTFLength(env, string)	\
+	(((*(env))->GetStringUTFLength)(env, JRI_GetStringUTFLength_op, string))
+
+#define JRI_GetStringUTFChars(env, string)	\
+	(((*(env))->GetStringUTFChars)(env, JRI_GetStringUTFChars_op, string))
+
+#define JRI_NewScalarArray(env, length, elementSig, initialElements)	\
+	(((*(env))->NewScalarArray)(env, JRI_NewScalarArray_op, length, elementSig, initialElements))
+
+#define JRI_GetScalarArrayLength(env, array)	\
+	(((*(env))->GetScalarArrayLength)(env, JRI_GetScalarArrayLength_op, array))
+
+#define JRI_GetScalarArrayElements(env, array)	\
+	(((*(env))->GetScalarArrayElements)(env, JRI_GetScalarArrayElements_op, array))
+
+#define JRI_NewObjectArray(env, length, elementClass, initialElement)	\
+	(((*(env))->NewObjectArray)(env, JRI_NewObjectArray_op, length, elementClass, initialElement))
+
+#define JRI_GetObjectArrayLength(env, array)	\
+	(((*(env))->GetObjectArrayLength)(env, JRI_GetObjectArrayLength_op, array))
+
+#define JRI_GetObjectArrayElement(env, array, index)	\
+	(((*(env))->GetObjectArrayElement)(env, JRI_GetObjectArrayElement_op, array, index))
+
+#define JRI_SetObjectArrayElement(env, array, index, value)	\
+	(((*(env))->SetObjectArrayElement)(env, JRI_SetObjectArrayElement_op, array, index, value))
+
+#define JRI_RegisterNatives(env, clazz, nameAndSigArray, nativeProcArray)	\
+	(((*(env))->RegisterNatives)(env, JRI_RegisterNatives_op, clazz, nameAndSigArray, nativeProcArray))
+
+#define JRI_UnregisterNatives(env, clazz)	\
+	(((*(env))->UnregisterNatives)(env, JRI_UnregisterNatives_op, clazz))
+
+#define JRI_NewStringPlatform(env, string, len, encoding, encodingLength)	\
+	(((*(env))->NewStringPlatform)(env, JRI_NewStringPlatform_op, string, len, encoding, encodingLength))
+
+#define JRI_GetStringPlatformChars(env, string, encoding, encodingLength)	\
+	(((*(env))->GetStringPlatformChars)(env, JRI_GetStringPlatformChars_op, string, encoding, encodingLength))
+
+
+/*******************************************************************************
+ * JRIEnv Interface
+ ******************************************************************************/
+
+struct java_lang_ClassLoader;
+struct java_lang_Class;
+struct java_lang_Throwable;
+struct java_lang_Object;
+struct java_lang_String;
+
+struct JRIEnvInterface {
+	void*	reserved0;
+	void*	reserved1;
+	void*	reserved2;
+	void*	reserved3;
+	struct java_lang_Class*	(*FindClass)(JRIEnv* env, jint op, const char* a);
+	void	(*Throw)(JRIEnv* env, jint op, struct java_lang_Throwable* a);
+	void	(*ThrowNew)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b);
+	struct java_lang_Throwable*	(*ExceptionOccurred)(JRIEnv* env, jint op);
+	void	(*ExceptionDescribe)(JRIEnv* env, jint op);
+	void	(*ExceptionClear)(JRIEnv* env, jint op);
+	jglobal	(*NewGlobalRef)(JRIEnv* env, jint op, void* a);
+	void	(*DisposeGlobalRef)(JRIEnv* env, jint op, jglobal a);
+	void*	(*GetGlobalRef)(JRIEnv* env, jint op, jglobal a);
+	void	(*SetGlobalRef)(JRIEnv* env, jint op, jglobal a, void* b);
+	jbool	(*IsSameObject)(JRIEnv* env, jint op, void* a, void* b);
+	void*	(*NewObject)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);
+	void*	(*NewObjectV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);
+	void*	(*NewObjectA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);
+	struct java_lang_Class*	(*GetObjectClass)(JRIEnv* env, jint op, void* a);
+	jbool	(*IsInstanceOf)(JRIEnv* env, jint op, void* a, struct java_lang_Class* b);
+	jint	(*GetMethodID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c);
+	void*	(*CallMethod)(JRIEnv* env, jint op, void* a, jint b, ...);
+	void*	(*CallMethodV)(JRIEnv* env, jint op, void* a, jint b, va_list c);
+	void*	(*CallMethodA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);
+	jbool	(*CallMethodBoolean)(JRIEnv* env, jint op, void* a, jint b, ...);
+	jbool	(*CallMethodBooleanV)(JRIEnv* env, jint op, void* a, jint b, va_list c);
+	jbool	(*CallMethodBooleanA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);
+	jbyte	(*CallMethodByte)(JRIEnv* env, jint op, void* a, jint b, ...);
+	jbyte	(*CallMethodByteV)(JRIEnv* env, jint op, void* a, jint b, va_list c);
+	jbyte	(*CallMethodByteA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);
+	jchar	(*CallMethodChar)(JRIEnv* env, jint op, void* a, jint b, ...);
+	jchar	(*CallMethodCharV)(JRIEnv* env, jint op, void* a, jint b, va_list c);
+	jchar	(*CallMethodCharA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);
+	jshort	(*CallMethodShort)(JRIEnv* env, jint op, void* a, jint b, ...);
+	jshort	(*CallMethodShortV)(JRIEnv* env, jint op, void* a, jint b, va_list c);
+	jshort	(*CallMethodShortA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);
+	jint	(*CallMethodInt)(JRIEnv* env, jint op, void* a, jint b, ...);
+	jint	(*CallMethodIntV)(JRIEnv* env, jint op, void* a, jint b, va_list c);
+	jint	(*CallMethodIntA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);
+	jlong	(*CallMethodLong)(JRIEnv* env, jint op, void* a, jint b, ...);
+	jlong	(*CallMethodLongV)(JRIEnv* env, jint op, void* a, jint b, va_list c);
+	jlong	(*CallMethodLongA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);
+	jfloat	(*CallMethodFloat)(JRIEnv* env, jint op, void* a, jint b, ...);
+	jfloat	(*CallMethodFloatV)(JRIEnv* env, jint op, void* a, jint b, va_list c);
+	jfloat	(*CallMethodFloatA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);
+	jdouble	(*CallMethodDouble)(JRIEnv* env, jint op, void* a, jint b, ...);
+	jdouble	(*CallMethodDoubleV)(JRIEnv* env, jint op, void* a, jint b, va_list c);
+	jdouble	(*CallMethodDoubleA)(JRIEnv* env, jint op, void* a, jint b, JRIValue* c);
+	jint	(*GetFieldID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c);
+	void*	(*GetField)(JRIEnv* env, jint op, void* a, jint b);
+	jbool	(*GetFieldBoolean)(JRIEnv* env, jint op, void* a, jint b);
+	jbyte	(*GetFieldByte)(JRIEnv* env, jint op, void* a, jint b);
+	jchar	(*GetFieldChar)(JRIEnv* env, jint op, void* a, jint b);
+	jshort	(*GetFieldShort)(JRIEnv* env, jint op, void* a, jint b);
+	jint	(*GetFieldInt)(JRIEnv* env, jint op, void* a, jint b);
+	jlong	(*GetFieldLong)(JRIEnv* env, jint op, void* a, jint b);
+	jfloat	(*GetFieldFloat)(JRIEnv* env, jint op, void* a, jint b);
+	jdouble	(*GetFieldDouble)(JRIEnv* env, jint op, void* a, jint b);
+	void	(*SetField)(JRIEnv* env, jint op, void* a, jint b, void* c);
+	void	(*SetFieldBoolean)(JRIEnv* env, jint op, void* a, jint b, jbool c);
+	void	(*SetFieldByte)(JRIEnv* env, jint op, void* a, jint b, jbyte c);
+	void	(*SetFieldChar)(JRIEnv* env, jint op, void* a, jint b, jchar c);
+	void	(*SetFieldShort)(JRIEnv* env, jint op, void* a, jint b, jshort c);
+	void	(*SetFieldInt)(JRIEnv* env, jint op, void* a, jint b, jint c);
+	void	(*SetFieldLong)(JRIEnv* env, jint op, void* a, jint b, jlong c);
+	void	(*SetFieldFloat)(JRIEnv* env, jint op, void* a, jint b, jfloat c);
+	void	(*SetFieldDouble)(JRIEnv* env, jint op, void* a, jint b, jdouble c);
+	jbool	(*IsSubclassOf)(JRIEnv* env, jint op, struct java_lang_Class* a, struct java_lang_Class* b);
+	jint	(*GetStaticMethodID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c);
+	void*	(*CallStaticMethod)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);
+	void*	(*CallStaticMethodV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);
+	void*	(*CallStaticMethodA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);
+	jbool	(*CallStaticMethodBoolean)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);
+	jbool	(*CallStaticMethodBooleanV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);
+	jbool	(*CallStaticMethodBooleanA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);
+	jbyte	(*CallStaticMethodByte)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);
+	jbyte	(*CallStaticMethodByteV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);
+	jbyte	(*CallStaticMethodByteA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);
+	jchar	(*CallStaticMethodChar)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);
+	jchar	(*CallStaticMethodCharV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);
+	jchar	(*CallStaticMethodCharA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);
+	jshort	(*CallStaticMethodShort)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);
+	jshort	(*CallStaticMethodShortV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);
+	jshort	(*CallStaticMethodShortA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);
+	jint	(*CallStaticMethodInt)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);
+	jint	(*CallStaticMethodIntV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);
+	jint	(*CallStaticMethodIntA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);
+	jlong	(*CallStaticMethodLong)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);
+	jlong	(*CallStaticMethodLongV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);
+	jlong	(*CallStaticMethodLongA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);
+	jfloat	(*CallStaticMethodFloat)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);
+	jfloat	(*CallStaticMethodFloatV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);
+	jfloat	(*CallStaticMethodFloatA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);
+	jdouble	(*CallStaticMethodDouble)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, ...);
+	jdouble	(*CallStaticMethodDoubleV)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, va_list c);
+	jdouble	(*CallStaticMethodDoubleA)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, JRIValue* c);
+	jint	(*GetStaticFieldID)(JRIEnv* env, jint op, struct java_lang_Class* a, const char* b, const char* c);
+	void*	(*GetStaticField)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);
+	jbool	(*GetStaticFieldBoolean)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);
+	jbyte	(*GetStaticFieldByte)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);
+	jchar	(*GetStaticFieldChar)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);
+	jshort	(*GetStaticFieldShort)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);
+	jint	(*GetStaticFieldInt)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);
+	jlong	(*GetStaticFieldLong)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);
+	jfloat	(*GetStaticFieldFloat)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);
+	jdouble	(*GetStaticFieldDouble)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b);
+	void	(*SetStaticField)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, void* c);
+	void	(*SetStaticFieldBoolean)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jbool c);
+	void	(*SetStaticFieldByte)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jbyte c);
+	void	(*SetStaticFieldChar)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jchar c);
+	void	(*SetStaticFieldShort)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jshort c);
+	void	(*SetStaticFieldInt)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jint c);
+	void	(*SetStaticFieldLong)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jlong c);
+	void	(*SetStaticFieldFloat)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jfloat c);
+	void	(*SetStaticFieldDouble)(JRIEnv* env, jint op, struct java_lang_Class* a, jint b, jdouble c);
+	struct java_lang_String*	(*NewString)(JRIEnv* env, jint op, const jchar* a, jint b);
+	jint	(*GetStringLength)(JRIEnv* env, jint op, struct java_lang_String* a);
+	const jchar*	(*GetStringChars)(JRIEnv* env, jint op, struct java_lang_String* a);
+	struct java_lang_String*	(*NewStringUTF)(JRIEnv* env, jint op, const jbyte* a, jint b);
+	jint	(*GetStringUTFLength)(JRIEnv* env, jint op, struct java_lang_String* a);
+	const jbyte*	(*GetStringUTFChars)(JRIEnv* env, jint op, struct java_lang_String* a);
+	void*	(*NewScalarArray)(JRIEnv* env, jint op, jint a, const char* b, const jbyte* c);
+	jint	(*GetScalarArrayLength)(JRIEnv* env, jint op, void* a);
+	jbyte*	(*GetScalarArrayElements)(JRIEnv* env, jint op, void* a);
+	void*	(*NewObjectArray)(JRIEnv* env, jint op, jint a, struct java_lang_Class* b, void* c);
+	jint	(*GetObjectArrayLength)(JRIEnv* env, jint op, void* a);
+	void*	(*GetObjectArrayElement)(JRIEnv* env, jint op, void* a, jint b);
+	void	(*SetObjectArrayElement)(JRIEnv* env, jint op, void* a, jint b, void* c);
+	void	(*RegisterNatives)(JRIEnv* env, jint op, struct java_lang_Class* a, char** b, void** c);
+	void	(*UnregisterNatives)(JRIEnv* env, jint op, struct java_lang_Class* a);
+	struct java_lang_Class*	(*DefineClass)(JRIEnv* env, jint op, struct java_lang_ClassLoader* a, jbyte* b, jsize bLen);
+	struct java_lang_String*	(*NewStringPlatform)(JRIEnv* env, jint op, const jbyte* a, jint b, const jbyte* c, jint d);
+	const jbyte*	(*GetStringPlatformChars)(JRIEnv* env, jint op, struct java_lang_String* a, const jbyte* b, jint c);
+};
+
+/*
+** ****************************************************************************
+** JRIEnv Operation IDs
+** ***************************************************************************
+*/
+
+typedef enum JRIEnvOperations {
+	JRI_Reserved0_op,
+	JRI_Reserved1_op,
+	JRI_Reserved2_op,
+	JRI_Reserved3_op,
+	JRI_FindClass_op,
+	JRI_Throw_op,
+	JRI_ThrowNew_op,
+	JRI_ExceptionOccurred_op,
+	JRI_ExceptionDescribe_op,
+	JRI_ExceptionClear_op,
+	JRI_NewGlobalRef_op,
+	JRI_DisposeGlobalRef_op,
+	JRI_GetGlobalRef_op,
+	JRI_SetGlobalRef_op,
+	JRI_IsSameObject_op,
+	JRI_NewObject_op,
+	JRI_NewObject_op_va_list,
+	JRI_NewObject_op_array,
+	JRI_GetObjectClass_op,
+	JRI_IsInstanceOf_op,
+	JRI_GetMethodID_op,
+	JRI_CallMethod_op,
+	JRI_CallMethod_op_va_list,
+	JRI_CallMethod_op_array,
+	JRI_CallMethodBoolean_op,
+	JRI_CallMethodBoolean_op_va_list,
+	JRI_CallMethodBoolean_op_array,
+	JRI_CallMethodByte_op,
+	JRI_CallMethodByte_op_va_list,
+	JRI_CallMethodByte_op_array,
+	JRI_CallMethodChar_op,
+	JRI_CallMethodChar_op_va_list,
+	JRI_CallMethodChar_op_array,
+	JRI_CallMethodShort_op,
+	JRI_CallMethodShort_op_va_list,
+	JRI_CallMethodShort_op_array,
+	JRI_CallMethodInt_op,
+	JRI_CallMethodInt_op_va_list,
+	JRI_CallMethodInt_op_array,
+	JRI_CallMethodLong_op,
+	JRI_CallMethodLong_op_va_list,
+	JRI_CallMethodLong_op_array,
+	JRI_CallMethodFloat_op,
+	JRI_CallMethodFloat_op_va_list,
+	JRI_CallMethodFloat_op_array,
+	JRI_CallMethodDouble_op,
+	JRI_CallMethodDouble_op_va_list,
+	JRI_CallMethodDouble_op_array,
+	JRI_GetFieldID_op,
+	JRI_GetField_op,
+	JRI_GetFieldBoolean_op,
+	JRI_GetFieldByte_op,
+	JRI_GetFieldChar_op,
+	JRI_GetFieldShort_op,
+	JRI_GetFieldInt_op,
+	JRI_GetFieldLong_op,
+	JRI_GetFieldFloat_op,
+	JRI_GetFieldDouble_op,
+	JRI_SetField_op,
+	JRI_SetFieldBoolean_op,
+	JRI_SetFieldByte_op,
+	JRI_SetFieldChar_op,
+	JRI_SetFieldShort_op,
+	JRI_SetFieldInt_op,
+	JRI_SetFieldLong_op,
+	JRI_SetFieldFloat_op,
+	JRI_SetFieldDouble_op,
+	JRI_IsSubclassOf_op,
+	JRI_GetStaticMethodID_op,
+	JRI_CallStaticMethod_op,
+	JRI_CallStaticMethod_op_va_list,
+	JRI_CallStaticMethod_op_array,
+	JRI_CallStaticMethodBoolean_op,
+	JRI_CallStaticMethodBoolean_op_va_list,
+	JRI_CallStaticMethodBoolean_op_array,
+	JRI_CallStaticMethodByte_op,
+	JRI_CallStaticMethodByte_op_va_list,
+	JRI_CallStaticMethodByte_op_array,
+	JRI_CallStaticMethodChar_op,
+	JRI_CallStaticMethodChar_op_va_list,
+	JRI_CallStaticMethodChar_op_array,
+	JRI_CallStaticMethodShort_op,
+	JRI_CallStaticMethodShort_op_va_list,
+	JRI_CallStaticMethodShort_op_array,
+	JRI_CallStaticMethodInt_op,
+	JRI_CallStaticMethodInt_op_va_list,
+	JRI_CallStaticMethodInt_op_array,
+	JRI_CallStaticMethodLong_op,
+	JRI_CallStaticMethodLong_op_va_list,
+	JRI_CallStaticMethodLong_op_array,
+	JRI_CallStaticMethodFloat_op,
+	JRI_CallStaticMethodFloat_op_va_list,
+	JRI_CallStaticMethodFloat_op_array,
+	JRI_CallStaticMethodDouble_op,
+	JRI_CallStaticMethodDouble_op_va_list,
+	JRI_CallStaticMethodDouble_op_array,
+	JRI_GetStaticFieldID_op,
+	JRI_GetStaticField_op,
+	JRI_GetStaticFieldBoolean_op,
+	JRI_GetStaticFieldByte_op,
+	JRI_GetStaticFieldChar_op,
+	JRI_GetStaticFieldShort_op,
+	JRI_GetStaticFieldInt_op,
+	JRI_GetStaticFieldLong_op,
+	JRI_GetStaticFieldFloat_op,
+	JRI_GetStaticFieldDouble_op,
+	JRI_SetStaticField_op,
+	JRI_SetStaticFieldBoolean_op,
+	JRI_SetStaticFieldByte_op,
+	JRI_SetStaticFieldChar_op,
+	JRI_SetStaticFieldShort_op,
+	JRI_SetStaticFieldInt_op,
+	JRI_SetStaticFieldLong_op,
+	JRI_SetStaticFieldFloat_op,
+	JRI_SetStaticFieldDouble_op,
+	JRI_NewString_op,
+	JRI_GetStringLength_op,
+	JRI_GetStringChars_op,
+	JRI_NewStringUTF_op,
+	JRI_GetStringUTFLength_op,
+	JRI_GetStringUTFChars_op,
+	JRI_NewScalarArray_op,
+	JRI_GetScalarArrayLength_op,
+	JRI_GetScalarArrayElements_op,
+	JRI_NewObjectArray_op,
+	JRI_GetObjectArrayLength_op,
+	JRI_GetObjectArrayElement_op,
+	JRI_SetObjectArrayElement_op,
+	JRI_RegisterNatives_op,
+	JRI_UnregisterNatives_op,
+	JRI_DefineClass_op,
+	JRI_NewStringPlatform_op,
+	JRI_GetStringPlatformChars_op
+} JRIEnvOperations;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* JRI_H */
+/******************************************************************************/
diff --git a/third_party/gecko/include/jri_md.h b/third_party/gecko/include/jri_md.h
index bea8922..f18093c 100644
--- a/third_party/gecko/include/jri_md.h
+++ b/third_party/gecko/include/jri_md.h
@@ -1,565 +1,565 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is 

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or 

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/*******************************************************************************

- * Java Runtime Interface - Machine Dependent Types

- ******************************************************************************/

- 

-#ifndef JRI_MD_H

-#define JRI_MD_H

-

-#include <assert.h>

-#include "prtypes.h" /* Needed for HAS_LONG_LONG ifdefs */

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-/*******************************************************************************

- * WHAT'S UP WITH THIS FILE?

- * 

- * This is where we define the mystical JRI_PUBLIC_API macro that works on all

- * platforms. If you're running with Visual C++, Symantec C, or Borland's 

- * development environment on the PC, you're all set. Or if you're on the Mac

- * with Metrowerks, Symantec or MPW with SC you're ok too. For UNIX it shouldn't

- * matter.

- *

- * On UNIX though you probably care about a couple of other symbols though:

- *	IS_LITTLE_ENDIAN must be defined for little-endian systems

- *	HAVE_LONG_LONG must be defined on systems that have 'long long' integers

- *	HAVE_ALIGNED_LONGLONGS must be defined if long-longs must be 8 byte aligned

- *	HAVE_ALIGNED_DOUBLES must be defined if doubles must be 8 byte aligned

- *	IS_64 must be defined on 64-bit machines (like Dec Alpha)

- ******************************************************************************/

-

-/* DLL Entry modifiers... */

-

-/* PC */

-#if defined(XP_OS2)

-#  ifdef XP_OS2_VACPP

-#	  define JRI_PUBLIC_API(ResultType)	    ResultType _Optlink

-#	  define JRI_PUBLIC_VAR(VarType)        VarType

-#     define JRI_CALLBACK

-#  else

-#	  define JRI_PUBLIC_API(ResultType)	    ResultType

-#	  define JRI_PUBLIC_VAR(VarType)        VarType

-#     define JRI_CALLBACK

-#  endif

-#elif defined(XP_WIN) || defined(_WINDOWS) || defined(WIN32) || defined(_WIN32)

-#	include <windows.h>

-#	if defined(_MSC_VER) || defined(__GNUC__)

-#		if defined(WIN32) || defined(_WIN32)

-#			define JRI_PUBLIC_API(ResultType)  __declspec(dllexport) ResultType

-#			define JRI_PUBLIC_VAR(VarType)	   VarType

-#			define JRI_PUBLIC_VAR_EXP(VarType) __declspec(dllexport) VarType

-#			define JRI_PUBLIC_VAR_IMP(VarType) __declspec(dllimport) VarType

-#			define JRI_NATIVE_STUB(ResultType) __declspec(dllexport) ResultType

-#			define JRI_CALLBACK

-#		else /* !_WIN32 */

-#		    if defined(_WINDLL)

-#			define JRI_PUBLIC_API(ResultType)	ResultType __cdecl __export __loadds 

-#			define JRI_PUBLIC_VAR(VarType)		VarType

-#			define JRI_PUBLIC_VAR_EXP(VarType)	JRI_PUBLIC_VAR(VarType)

-#			define JRI_PUBLIC_VAR_IMP(VarType)	JRI_PUBLIC_VAR(VarType)

-#			define JRI_NATIVE_STUB(ResultType)	ResultType __cdecl __loadds

-#			define JRI_CALLBACK			__loadds

-#		else /* !WINDLL */

-#			define JRI_PUBLIC_API(ResultType)	ResultType __cdecl __export

-#			define JRI_PUBLIC_VAR(VarType)		VarType

-#			define JRI_PUBLIC_VAR_EXP(VarType)	JRI_PUBLIC_VAR(VarType)

-#			define JRI_PUBLIC_VAR_IMP(VarType)	JRI_PUBLIC_VAR(VarType)

-#			define JRI_NATIVE_STUB(ResultType)	ResultType __cdecl __export

-#			define JRI_CALLBACK			__export

-#                   endif /* !WINDLL */

-#		endif /* !_WIN32 */

-#	elif defined(__BORLANDC__)

-#		if defined(WIN32) || defined(_WIN32)

-#			define JRI_PUBLIC_API(ResultType)	__export ResultType

-#			define JRI_PUBLIC_VAR(VarType)		VarType

-#			define JRI_PUBLIC_VAR_EXP(VarType)	__export VarType

-#			define JRI_PUBLIC_VAR_IMP(VarType)	__import VarType

-#			define JRI_NATIVE_STUB(ResultType)	 __export ResultType

-#			define JRI_CALLBACK

-#		else /* !_WIN32 */

-#			define JRI_PUBLIC_API(ResultType)	ResultType _cdecl _export _loadds 

-#			define JRI_PUBLIC_VAR(VarType)		VarType

-#			define JRI_PUBLIC_VAR_EXP(VarType)	__cdecl __export VarType

-#			define JRI_PUBLIC_VAR_IMP(VarType)	__cdecl __import VarType

-#			define JRI_NATIVE_STUB(ResultType)	ResultType _cdecl _loadds

-#			define JRI_CALLBACK			_loadds

-#		endif

-#	else

-#		error Unsupported PC development environment.	

-#	endif

-#	ifndef IS_LITTLE_ENDIAN

-#		define IS_LITTLE_ENDIAN

-#	endif

-

-/* Mac */

-#elif defined (macintosh) || Macintosh || THINK_C

-#	if defined(__MWERKS__)				/* Metrowerks */

-#		if !__option(enumsalwaysint)

-#			error You need to define 'Enums Always Int' for your project.

-#		endif

-#		if defined(TARGET_CPU_68K) && !TARGET_RT_MAC_CFM 

-#			if !__option(fourbyteints) 

-#				error You need to define 'Struct Alignment: 68k' for your project.

-#			endif

-#		endif /* !GENERATINGCFM */

-#		define JRI_PUBLIC_API(ResultType)	__declspec(export) ResultType

-#		define JRI_PUBLIC_VAR(VarType)		JRI_PUBLIC_API(VarType)

-#		define JRI_PUBLIC_VAR_EXP(VarType)	JRI_PUBLIC_API(VarType)

-#		define JRI_PUBLIC_VAR_IMP(VarType)	JRI_PUBLIC_API(VarType)

-#		define JRI_NATIVE_STUB(ResultType)	JRI_PUBLIC_API(ResultType)

-#	elif defined(__SC__)				/* Symantec */

-#		error What are the Symantec defines? (warren@netscape.com)

-#	elif macintosh && applec			/* MPW */

-#		error Please upgrade to the latest MPW compiler (SC).

-#	else

-#		error Unsupported Mac development environment.

-#	endif

-#	define JRI_CALLBACK

-

-/* Unix or else */

-#else

-#	define JRI_PUBLIC_API(ResultType)		ResultType

-#   define JRI_PUBLIC_VAR(VarType)          VarType

-#   define JRI_PUBLIC_VAR_EXP(VarType)		JRI_PUBLIC_VAR(VarType)

-#   define JRI_PUBLIC_VAR_IMP(VarType)		JRI_PUBLIC_VAR(VarType)

-#   define JRI_NATIVE_STUB(ResultType)		ResultType

-#	define JRI_CALLBACK

-#endif

-

-#ifndef FAR		/* for non-Win16 */

-#define FAR

-#endif

-

-/******************************************************************************/

-

-/* Java Scalar Types */

-

-#if 0	/* now in jni.h */

-typedef short			jchar;

-typedef short			jshort;

-typedef float			jfloat;

-typedef double			jdouble;

-typedef juint			jsize;

-#endif

-

-/* moved from jni.h -- Sun's new jni.h doesn't have this anymore */

-#ifdef __cplusplus

-typedef class _jobject *jref;

-#else

-typedef struct _jobject *jref;

-#endif

-

-typedef unsigned char	jbool;

-typedef signed char	jbyte;

-#ifdef IS_64 /* XXX ok for alpha, but not right on all 64-bit architectures */

-typedef unsigned int	juint;

-typedef int				jint;

-#else

-typedef unsigned long	juint;

-typedef long			jint;

-#endif

-

-/*******************************************************************************

- * jlong : long long (64-bit signed integer type) support.

- ******************************************************************************/

-

-/*

-** Bit masking macros.  (n must be <= 31 to be portable)

-*/

-#define JRI_BIT(n)			((juint)1 << (n))

-#define JRI_BITMASK(n)		(JRI_BIT(n) - 1)

-

-#ifdef HAVE_LONG_LONG

-

-#ifdef OSF1

-

-/* long is default 64-bit on OSF1, -std1 does not allow long long */

-typedef long                  jlong;

-typedef unsigned long         julong;

-#define jlong_MAXINT          0x7fffffffffffffffL

-#define jlong_MININT          0x8000000000000000L

-#define jlong_ZERO            0x0L

-

-#elif (defined(WIN32) || defined(_WIN32))

-

-typedef LONGLONG              jlong;

-typedef DWORDLONG             julong;

-#define jlong_MAXINT          0x7fffffffffffffffi64

-#define jlong_MININT          0x8000000000000000i64

-#define jlong_ZERO            0x0i64

-

-#else

-

-typedef long long             jlong;

-typedef unsigned long long    julong;

-#define jlong_MAXINT          0x7fffffffffffffffLL

-#define jlong_MININT          0x8000000000000000LL

-#define jlong_ZERO            0x0LL

-

-#endif

-

-#define jlong_IS_ZERO(a)	((a) == 0)

-#define jlong_EQ(a, b)		((a) == (b))

-#define jlong_NE(a, b)		((a) != (b))

-#define jlong_GE_ZERO(a)	((a) >= 0)

-#define jlong_CMP(a, op, b)	((a) op (b))

-

-#define jlong_AND(r, a, b)	((r) = (a) & (b))

-#define jlong_OR(r, a, b)	((r) = (a) | (b))

-#define jlong_XOR(r, a, b)	((r) = (a) ^ (b))

-#define jlong_OR2(r, a)		((r) = (r) | (a))

-#define jlong_NOT(r, a)		((r) = ~(a))

-

-#define jlong_NEG(r, a)		((r) = -(a))

-#define jlong_ADD(r, a, b)	((r) = (a) + (b))

-#define jlong_SUB(r, a, b)	((r) = (a) - (b))

-

-#define jlong_MUL(r, a, b)	((r) = (a) * (b))

-#define jlong_DIV(r, a, b)	((r) = (a) / (b))

-#define jlong_MOD(r, a, b)	((r) = (a) % (b))

-

-#define jlong_SHL(r, a, b)	((r) = (a) << (b))

-#define jlong_SHR(r, a, b)	((r) = (a) >> (b))

-#define jlong_USHR(r, a, b)	((r) = (julong)(a) >> (b))

-#define jlong_ISHL(r, a, b)	((r) = ((jlong)(a)) << (b))

-

-#define jlong_L2I(i, l)		((i) = (int)(l))

-#define jlong_L2UI(ui, l)	((ui) =(unsigned int)(l))

-#define jlong_L2F(f, l)		((f) = (l))

-#define jlong_L2D(d, l)		((d) = (l))

-

-#define jlong_I2L(l, i)		((l) = (i))

-#define jlong_UI2L(l, ui)	((l) = (ui))

-#define jlong_F2L(l, f)		((l) = (f))

-#define jlong_D2L(l, d)		((l) = (d))

-

-#define jlong_UDIVMOD(qp, rp, a, b)  \

-    (*(qp) = ((julong)(a) / (b)), \

-     *(rp) = ((julong)(a) % (b)))

-

-#else  /* !HAVE_LONG_LONG */

-

-typedef struct {

-#ifdef IS_LITTLE_ENDIAN

-    juint lo, hi;

-#else

-    juint hi, lo;

-#endif

-} jlong;

-typedef jlong				julong;

-

-extern jlong jlong_MAXINT, jlong_MININT, jlong_ZERO;

-

-#define jlong_IS_ZERO(a)	(((a).hi == 0) && ((a).lo == 0))

-#define jlong_EQ(a, b)		(((a).hi == (b).hi) && ((a).lo == (b).lo))

-#define jlong_NE(a, b)		(((a).hi != (b).hi) || ((a).lo != (b).lo))

-#define jlong_GE_ZERO(a)	(((a).hi >> 31) == 0)

-

-/*

- * NB: jlong_CMP and jlong_UCMP work only for strict relationals (<, >).

- */

-#define jlong_CMP(a, op, b)	(((int32)(a).hi op (int32)(b).hi) ||          \

-				 (((a).hi == (b).hi) && ((a).lo op (b).lo)))

-#define jlong_UCMP(a, op, b)	(((a).hi op (b).hi) ||                    \

-				 (((a).hi == (b).hi) && ((a).lo op (b).lo)))

-

-#define jlong_AND(r, a, b)	((r).lo = (a).lo & (b).lo,                    \

-				 (r).hi = (a).hi & (b).hi)

-#define jlong_OR(r, a, b)	((r).lo = (a).lo | (b).lo,                    \

-				 (r).hi = (a).hi | (b).hi)

-#define jlong_XOR(r, a, b)	((r).lo = (a).lo ^ (b).lo,                    \

-				 (r).hi = (a).hi ^ (b).hi)

-#define jlong_OR2(r, a)		((r).lo = (r).lo | (a).lo,                    \

-				 (r).hi = (r).hi | (a).hi)

-#define jlong_NOT(r, a)		((r).lo = ~(a).lo,	                          \

-				 (r).hi = ~(a).hi)

-

-#define jlong_NEG(r, a)		((r).lo = -(int32)(a).lo,                     \

-				 (r).hi = -(int32)(a).hi - ((r).lo != 0))

-#define jlong_ADD(r, a, b) {                                              \

-    jlong _a, _b;                                                         \

-    _a = a; _b = b;                                                       \

-    (r).lo = _a.lo + _b.lo;                                               \

-    (r).hi = _a.hi + _b.hi + ((r).lo < _b.lo);                            \

-}

-

-#define jlong_SUB(r, a, b) {                                              \

-    jlong _a, _b;                                                         \

-    _a = a; _b = b;                                                       \

-    (r).lo = _a.lo - _b.lo;                                               \

-    (r).hi = _a.hi - _b.hi - (_a.lo < _b.lo);                             \

-}                                                                         \

-

-/*

- * Multiply 64-bit operands a and b to get 64-bit result r.

- * First multiply the low 32 bits of a and b to get a 64-bit result in r.

- * Then add the outer and inner products to r.hi.

- */

-#define jlong_MUL(r, a, b) {                                              \

-    jlong _a, _b;                                                         \

-    _a = a; _b = b;                                                       \

-    jlong_MUL32(r, _a.lo, _b.lo);                                         \

-    (r).hi += _a.hi * _b.lo + _a.lo * _b.hi;                              \

-}

-

-/* XXX _jlong_lo16(a) = ((a) << 16 >> 16) is better on some archs (not on mips) */

-#define _jlong_lo16(a)		((a) & JRI_BITMASK(16))

-#define _jlong_hi16(a)		((a) >> 16)

-

-/*

- * Multiply 32-bit operands a and b to get 64-bit result r.

- * Use polynomial expansion based on primitive field element (1 << 16).

- */

-#define jlong_MUL32(r, a, b) {                                            \

-     juint _a1, _a0, _b1, _b0, _y0, _y1, _y2, _y3;                        \

-     _a1 = _jlong_hi16(a), _a0 = _jlong_lo16(a);                          \

-     _b1 = _jlong_hi16(b), _b0 = _jlong_lo16(b);                          \

-     _y0 = _a0 * _b0;                                                     \

-     _y1 = _a0 * _b1;                                                     \

-     _y2 = _a1 * _b0;                                                     \

-     _y3 = _a1 * _b1;                                                     \

-     _y1 += _jlong_hi16(_y0);                   /* can't carry */         \

-     _y1 += _y2;                                /* might carry */         \

-     if (_y1 < _y2) _y3 += 1 << 16;             /* propagate */           \

-     (r).lo = (_jlong_lo16(_y1) << 16) + _jlong_lo16(_y0);                \

-     (r).hi = _y3 + _jlong_hi16(_y1);                                     \

-}

-

-/*

- * Divide 64-bit unsigned operand a by 64-bit unsigned operand b, setting *qp

- * to the 64-bit unsigned quotient, and *rp to the 64-bit unsigned remainder.

- * Minimize effort if one of qp and rp is null.

- */

-#define jlong_UDIVMOD(qp, rp, a, b)	jlong_udivmod(qp, rp, a, b)

-

-extern JRI_PUBLIC_API(void)

-jlong_udivmod(julong *qp, julong *rp, julong a, julong b);

-

-#define jlong_DIV(r, a, b) {                                              \

-    jlong _a, _b;                                                         \

-    juint _negative = (int32)(a).hi < 0;                                  \

-    if (_negative) {                                                      \

-	jlong_NEG(_a, a);                                                     \

-    } else {                                                              \

-	_a = a;                                                               \

-    }                                                                     \

-    if ((int32)(b).hi < 0) {                                              \

-	_negative ^= 1;                                                       \

-	jlong_NEG(_b, b);                                                     \

-    } else {                                                              \

-	_b = b;                                                               \

-    }                                                                     \

-    jlong_UDIVMOD(&(r), 0, _a, _b);                                       \

-    if (_negative)                                                        \

-	jlong_NEG(r, r);                                                      \

-}

-

-#define jlong_MOD(r, a, b) {                                              \

-    jlong _a, _b;                                                         \

-    juint _negative = (int32)(a).hi < 0;                                  \

-    if (_negative) {                                                      \

-	jlong_NEG(_a, a);                                                     \

-    } else {                                                              \

-	_a = a;                                                               \

-    }                                                                     \

-    if ((int32)(b).hi < 0) {                                              \

-	jlong_NEG(_b, b);                                                     \

-    } else {                                                              \

-	_b = b;                                                               \

-    }                                                                     \

-    jlong_UDIVMOD(0, &(r), _a, _b);                                       \

-    if (_negative)                                                        \

-	jlong_NEG(r, r);                                                      \

-}

-

-/*

- * NB: b is a juint, not jlong or julong, for the shift ops.

- */

-#define jlong_SHL(r, a, b) {                                              \

-    if (b) {                                                              \

-	jlong _a;                                                             \

-        _a = a;                                                           \

-        if ((b) < 32) {                                                   \

-	    (r).lo = _a.lo << (b);                                            \

-	    (r).hi = (_a.hi << (b)) | (_a.lo >> (32 - (b)));                  \

-	} else {                                                              \

-	    (r).lo = 0;                                                       \

-	    (r).hi = _a.lo << ((b) & 31);                                     \

-	}                                                                     \

-    } else {                                                              \

-	(r) = (a);                                                            \

-    }                                                                     \

-}

-

-/* a is an int32, b is int32, r is jlong */

-#define jlong_ISHL(r, a, b) {                                             \

-    if (b) {                                                              \

-	jlong _a;                                                             \

-	_a.lo = (a);                                                          \

-	_a.hi = 0;                                                            \

-        if ((b) < 32) {                                                   \

-	    (r).lo = (a) << (b);                                              \

-	    (r).hi = ((a) >> (32 - (b)));                                     \

-	} else {                                                              \

-	    (r).lo = 0;                                                       \

-	    (r).hi = (a) << ((b) & 31);                                       \

-	}                                                                     \

-    } else {                                                              \

-	(r).lo = (a);                                                         \

-	(r).hi = 0;                                                           \

-    }                                                                     \

-}

-

-#define jlong_SHR(r, a, b) {                                              \

-    if (b) {                                                              \

-	jlong _a;                                                             \

-        _a = a;                                                           \

-	if ((b) < 32) {                                                       \

-	    (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> (b));                  \

-	    (r).hi = (int32)_a.hi >> (b);                                     \

-	} else {                                                              \

-	    (r).lo = (int32)_a.hi >> ((b) & 31);                              \

-	    (r).hi = (int32)_a.hi >> 31;                                      \

-	}                                                                     \

-    } else {                                                              \

-	(r) = (a);                                                            \

-    }                                                                     \

-}

-

-#define jlong_USHR(r, a, b) {                                             \

-    if (b) {                                                              \

-	jlong _a;                                                             \

-        _a = a;                                                           \

-	if ((b) < 32) {                                                       \

-	    (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> (b));                  \

-	    (r).hi = _a.hi >> (b);                                            \

-	} else {                                                              \

-	    (r).lo = _a.hi >> ((b) & 31);                                     \

-	    (r).hi = 0;                                                       \

-	}                                                                     \

-    } else {                                                              \

-	(r) = (a);                                                            \

-    }                                                                     \

-}

-

-#define jlong_L2I(i, l)		((i) = (l).lo)

-#define jlong_L2UI(ui, l)	((ui) = (l).lo)

-#define jlong_L2F(f, l)		{ double _d; jlong_L2D(_d, l); (f) = (float) _d; }

-

-#define jlong_L2D(d, l) {                                                 \

-    int32 _negative;                                                      \

-    jlong _absval;                                                        \

-                                                                          \

-    _negative = (l).hi >> 31;                                             \

-    if (_negative) {                                                      \

-	jlong_NEG(_absval, l);                                                \

-    } else {                                                              \

-	_absval = l;                                                          \

-    }                                                                     \

-    (d) = (double)_absval.hi * 4.294967296e9 + _absval.lo;                \

-    if (_negative)                                                        \

-	(d) = -(d);                                                           \

-}

-

-#define jlong_I2L(l, i)		((l).hi = (i) >> 31, (l).lo = (i))

-#define jlong_UI2L(l, ui)	((l).hi = 0, (l).lo = (ui))

-#define jlong_F2L(l, f)		{ double _d = (double) f; jlong_D2L(l, _d); }

-

-#define jlong_D2L(l, d) {                                                 \

-    int _negative;                                                        \

-    double _absval, _d_hi;                                                \

-    jlong _lo_d;                                                          \

-                                                                          \

-    _negative = ((d) < 0);                                                \

-    _absval = _negative ? -(d) : (d);                                     \

-                                                                          \

-    (l).hi = (juint)(_absval / 4.294967296e9);                            \

-    (l).lo = 0;                                                           \

-    jlong_L2D(_d_hi, l);                                                  \

-    _absval -= _d_hi;                                                     \

-    _lo_d.hi = 0;                                                         \

-    if (_absval < 0) {                                                    \

-	_lo_d.lo = (juint) -_absval;                                          \

-	jlong_SUB(l, l, _lo_d);                                               \

-    } else {                                                              \

-	_lo_d.lo = (juint) _absval;                                           \

-	jlong_ADD(l, l, _lo_d);                                               \

-    }                                                                     \

-                                                                          \

-    if (_negative)                                                        \

-	jlong_NEG(l, l);                                                      \

-}

-

-#endif /* !HAVE_LONG_LONG */

-

-/******************************************************************************/

-

-#ifdef HAVE_ALIGNED_LONGLONGS

-#define JRI_GET_INT64(_t,_addr) ( ((_t).x[0] = ((jint*)(_addr))[0]), \

-                              ((_t).x[1] = ((jint*)(_addr))[1]),      \

-                              (_t).l )

-#define JRI_SET_INT64(_t, _addr, _v) ( (_t).l = (_v),                \

-                                   ((jint*)(_addr))[0] = (_t).x[0], \

-                                   ((jint*)(_addr))[1] = (_t).x[1] )

-#else

-#define JRI_GET_INT64(_t,_addr) (*(jlong*)(_addr))

-#define JRI_SET_INT64(_t, _addr, _v) (*(jlong*)(_addr) = (_v))

-#endif

-

-/* If double's must be aligned on doubleword boundaries then define this */

-#ifdef HAVE_ALIGNED_DOUBLES

-#define JRI_GET_DOUBLE(_t,_addr) ( ((_t).x[0] = ((jint*)(_addr))[0]), \

-                               ((_t).x[1] = ((jint*)(_addr))[1]),      \

-                               (_t).d )

-#define JRI_SET_DOUBLE(_t, _addr, _v) ( (_t).d = (_v),                \

-                                    ((jint*)(_addr))[0] = (_t).x[0], \

-                                    ((jint*)(_addr))[1] = (_t).x[1] )

-#else

-#define JRI_GET_DOUBLE(_t,_addr) (*(jdouble*)(_addr))

-#define JRI_SET_DOUBLE(_t, _addr, _v) (*(jdouble*)(_addr) = (_v))

-#endif

-

-/******************************************************************************/

-#ifdef __cplusplus

-}

-#endif

-#endif /* JRI_MD_H */

-/******************************************************************************/

+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*******************************************************************************
+ * Java Runtime Interface - Machine Dependent Types
+ ******************************************************************************/
+ 
+#ifndef JRI_MD_H
+#define JRI_MD_H
+
+#include <assert.h>
+#include "prtypes.h" /* Needed for HAS_LONG_LONG ifdefs */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * WHAT'S UP WITH THIS FILE?
+ * 
+ * This is where we define the mystical JRI_PUBLIC_API macro that works on all
+ * platforms. If you're running with Visual C++, Symantec C, or Borland's 
+ * development environment on the PC, you're all set. Or if you're on the Mac
+ * with Metrowerks, Symantec or MPW with SC you're ok too. For UNIX it shouldn't
+ * matter.
+ *
+ * On UNIX though you probably care about a couple of other symbols though:
+ *	IS_LITTLE_ENDIAN must be defined for little-endian systems
+ *	HAVE_LONG_LONG must be defined on systems that have 'long long' integers
+ *	HAVE_ALIGNED_LONGLONGS must be defined if long-longs must be 8 byte aligned
+ *	HAVE_ALIGNED_DOUBLES must be defined if doubles must be 8 byte aligned
+ *	IS_64 must be defined on 64-bit machines (like Dec Alpha)
+ ******************************************************************************/
+
+/* DLL Entry modifiers... */
+
+/* PC */
+#if defined(XP_OS2)
+#  ifdef XP_OS2_VACPP
+#	  define JRI_PUBLIC_API(ResultType)	    ResultType _Optlink
+#	  define JRI_PUBLIC_VAR(VarType)        VarType
+#     define JRI_CALLBACK
+#  else
+#	  define JRI_PUBLIC_API(ResultType)	    ResultType
+#	  define JRI_PUBLIC_VAR(VarType)        VarType
+#     define JRI_CALLBACK
+#  endif
+#elif defined(XP_WIN) || defined(_WINDOWS) || defined(WIN32) || defined(_WIN32)
+#	include <windows.h>
+#	if defined(_MSC_VER) || defined(__GNUC__)
+#		if defined(WIN32) || defined(_WIN32)
+#			define JRI_PUBLIC_API(ResultType)  __declspec(dllexport) ResultType
+#			define JRI_PUBLIC_VAR(VarType)	   VarType
+#			define JRI_PUBLIC_VAR_EXP(VarType) __declspec(dllexport) VarType
+#			define JRI_PUBLIC_VAR_IMP(VarType) __declspec(dllimport) VarType
+#			define JRI_NATIVE_STUB(ResultType) __declspec(dllexport) ResultType
+#			define JRI_CALLBACK
+#		else /* !_WIN32 */
+#		    if defined(_WINDLL)
+#			define JRI_PUBLIC_API(ResultType)	ResultType __cdecl __export __loadds 
+#			define JRI_PUBLIC_VAR(VarType)		VarType
+#			define JRI_PUBLIC_VAR_EXP(VarType)	JRI_PUBLIC_VAR(VarType)
+#			define JRI_PUBLIC_VAR_IMP(VarType)	JRI_PUBLIC_VAR(VarType)
+#			define JRI_NATIVE_STUB(ResultType)	ResultType __cdecl __loadds
+#			define JRI_CALLBACK			__loadds
+#		else /* !WINDLL */
+#			define JRI_PUBLIC_API(ResultType)	ResultType __cdecl __export
+#			define JRI_PUBLIC_VAR(VarType)		VarType
+#			define JRI_PUBLIC_VAR_EXP(VarType)	JRI_PUBLIC_VAR(VarType)
+#			define JRI_PUBLIC_VAR_IMP(VarType)	JRI_PUBLIC_VAR(VarType)
+#			define JRI_NATIVE_STUB(ResultType)	ResultType __cdecl __export
+#			define JRI_CALLBACK			__export
+#                   endif /* !WINDLL */
+#		endif /* !_WIN32 */
+#	elif defined(__BORLANDC__)
+#		if defined(WIN32) || defined(_WIN32)
+#			define JRI_PUBLIC_API(ResultType)	__export ResultType
+#			define JRI_PUBLIC_VAR(VarType)		VarType
+#			define JRI_PUBLIC_VAR_EXP(VarType)	__export VarType
+#			define JRI_PUBLIC_VAR_IMP(VarType)	__import VarType
+#			define JRI_NATIVE_STUB(ResultType)	 __export ResultType
+#			define JRI_CALLBACK
+#		else /* !_WIN32 */
+#			define JRI_PUBLIC_API(ResultType)	ResultType _cdecl _export _loadds 
+#			define JRI_PUBLIC_VAR(VarType)		VarType
+#			define JRI_PUBLIC_VAR_EXP(VarType)	__cdecl __export VarType
+#			define JRI_PUBLIC_VAR_IMP(VarType)	__cdecl __import VarType
+#			define JRI_NATIVE_STUB(ResultType)	ResultType _cdecl _loadds
+#			define JRI_CALLBACK			_loadds
+#		endif
+#	else
+#		error Unsupported PC development environment.	
+#	endif
+#	ifndef IS_LITTLE_ENDIAN
+#		define IS_LITTLE_ENDIAN
+#	endif
+
+/* Mac */
+#elif defined (macintosh) || Macintosh || THINK_C
+#	if defined(__MWERKS__)				/* Metrowerks */
+#		if !__option(enumsalwaysint)
+#			error You need to define 'Enums Always Int' for your project.
+#		endif
+#		if defined(TARGET_CPU_68K) && !TARGET_RT_MAC_CFM 
+#			if !__option(fourbyteints) 
+#				error You need to define 'Struct Alignment: 68k' for your project.
+#			endif
+#		endif /* !GENERATINGCFM */
+#		define JRI_PUBLIC_API(ResultType)	__declspec(export) ResultType
+#		define JRI_PUBLIC_VAR(VarType)		JRI_PUBLIC_API(VarType)
+#		define JRI_PUBLIC_VAR_EXP(VarType)	JRI_PUBLIC_API(VarType)
+#		define JRI_PUBLIC_VAR_IMP(VarType)	JRI_PUBLIC_API(VarType)
+#		define JRI_NATIVE_STUB(ResultType)	JRI_PUBLIC_API(ResultType)
+#	elif defined(__SC__)				/* Symantec */
+#		error What are the Symantec defines? (warren@netscape.com)
+#	elif macintosh && applec			/* MPW */
+#		error Please upgrade to the latest MPW compiler (SC).
+#	else
+#		error Unsupported Mac development environment.
+#	endif
+#	define JRI_CALLBACK
+
+/* Unix or else */
+#else
+#	define JRI_PUBLIC_API(ResultType)		ResultType
+#   define JRI_PUBLIC_VAR(VarType)          VarType
+#   define JRI_PUBLIC_VAR_EXP(VarType)		JRI_PUBLIC_VAR(VarType)
+#   define JRI_PUBLIC_VAR_IMP(VarType)		JRI_PUBLIC_VAR(VarType)
+#   define JRI_NATIVE_STUB(ResultType)		ResultType
+#	define JRI_CALLBACK
+#endif
+
+#ifndef FAR		/* for non-Win16 */
+#define FAR
+#endif
+
+/******************************************************************************/
+
+/* Java Scalar Types */
+
+#if 0	/* now in jni.h */
+typedef short			jchar;
+typedef short			jshort;
+typedef float			jfloat;
+typedef double			jdouble;
+typedef juint			jsize;
+#endif
+
+/* moved from jni.h -- Sun's new jni.h doesn't have this anymore */
+#ifdef __cplusplus
+typedef class _jobject *jref;
+#else
+typedef struct _jobject *jref;
+#endif
+
+typedef unsigned char	jbool;
+typedef signed char	jbyte;
+#ifdef IS_64 /* XXX ok for alpha, but not right on all 64-bit architectures */
+typedef unsigned int	juint;
+typedef int				jint;
+#else
+typedef unsigned long	juint;
+typedef long			jint;
+#endif
+
+/*******************************************************************************
+ * jlong : long long (64-bit signed integer type) support.
+ ******************************************************************************/
+
+/*
+** Bit masking macros.  (n must be <= 31 to be portable)
+*/
+#define JRI_BIT(n)			((juint)1 << (n))
+#define JRI_BITMASK(n)		(JRI_BIT(n) - 1)
+
+#ifdef HAVE_LONG_LONG
+
+#ifdef OSF1
+
+/* long is default 64-bit on OSF1, -std1 does not allow long long */
+typedef long                  jlong;
+typedef unsigned long         julong;
+#define jlong_MAXINT          0x7fffffffffffffffL
+#define jlong_MININT          0x8000000000000000L
+#define jlong_ZERO            0x0L
+
+#elif (defined(WIN32) || defined(_WIN32))
+
+typedef LONGLONG              jlong;
+typedef DWORDLONG             julong;
+#define jlong_MAXINT          0x7fffffffffffffffi64
+#define jlong_MININT          0x8000000000000000i64
+#define jlong_ZERO            0x0i64
+
+#else
+
+typedef long long             jlong;
+typedef unsigned long long    julong;
+#define jlong_MAXINT          0x7fffffffffffffffLL
+#define jlong_MININT          0x8000000000000000LL
+#define jlong_ZERO            0x0LL
+
+#endif
+
+#define jlong_IS_ZERO(a)	((a) == 0)
+#define jlong_EQ(a, b)		((a) == (b))
+#define jlong_NE(a, b)		((a) != (b))
+#define jlong_GE_ZERO(a)	((a) >= 0)
+#define jlong_CMP(a, op, b)	((a) op (b))
+
+#define jlong_AND(r, a, b)	((r) = (a) & (b))
+#define jlong_OR(r, a, b)	((r) = (a) | (b))
+#define jlong_XOR(r, a, b)	((r) = (a) ^ (b))
+#define jlong_OR2(r, a)		((r) = (r) | (a))
+#define jlong_NOT(r, a)		((r) = ~(a))
+
+#define jlong_NEG(r, a)		((r) = -(a))
+#define jlong_ADD(r, a, b)	((r) = (a) + (b))
+#define jlong_SUB(r, a, b)	((r) = (a) - (b))
+
+#define jlong_MUL(r, a, b)	((r) = (a) * (b))
+#define jlong_DIV(r, a, b)	((r) = (a) / (b))
+#define jlong_MOD(r, a, b)	((r) = (a) % (b))
+
+#define jlong_SHL(r, a, b)	((r) = (a) << (b))
+#define jlong_SHR(r, a, b)	((r) = (a) >> (b))
+#define jlong_USHR(r, a, b)	((r) = (julong)(a) >> (b))
+#define jlong_ISHL(r, a, b)	((r) = ((jlong)(a)) << (b))
+
+#define jlong_L2I(i, l)		((i) = (int)(l))
+#define jlong_L2UI(ui, l)	((ui) =(unsigned int)(l))
+#define jlong_L2F(f, l)		((f) = (l))
+#define jlong_L2D(d, l)		((d) = (l))
+
+#define jlong_I2L(l, i)		((l) = (i))
+#define jlong_UI2L(l, ui)	((l) = (ui))
+#define jlong_F2L(l, f)		((l) = (f))
+#define jlong_D2L(l, d)		((l) = (d))
+
+#define jlong_UDIVMOD(qp, rp, a, b)  \
+    (*(qp) = ((julong)(a) / (b)), \
+     *(rp) = ((julong)(a) % (b)))
+
+#else  /* !HAVE_LONG_LONG */
+
+typedef struct {
+#ifdef IS_LITTLE_ENDIAN
+    juint lo, hi;
+#else
+    juint hi, lo;
+#endif
+} jlong;
+typedef jlong				julong;
+
+extern jlong jlong_MAXINT, jlong_MININT, jlong_ZERO;
+
+#define jlong_IS_ZERO(a)	(((a).hi == 0) && ((a).lo == 0))
+#define jlong_EQ(a, b)		(((a).hi == (b).hi) && ((a).lo == (b).lo))
+#define jlong_NE(a, b)		(((a).hi != (b).hi) || ((a).lo != (b).lo))
+#define jlong_GE_ZERO(a)	(((a).hi >> 31) == 0)
+
+/*
+ * NB: jlong_CMP and jlong_UCMP work only for strict relationals (<, >).
+ */
+#define jlong_CMP(a, op, b)	(((int32)(a).hi op (int32)(b).hi) ||          \
+				 (((a).hi == (b).hi) && ((a).lo op (b).lo)))
+#define jlong_UCMP(a, op, b)	(((a).hi op (b).hi) ||                    \
+				 (((a).hi == (b).hi) && ((a).lo op (b).lo)))
+
+#define jlong_AND(r, a, b)	((r).lo = (a).lo & (b).lo,                    \
+				 (r).hi = (a).hi & (b).hi)
+#define jlong_OR(r, a, b)	((r).lo = (a).lo | (b).lo,                    \
+				 (r).hi = (a).hi | (b).hi)
+#define jlong_XOR(r, a, b)	((r).lo = (a).lo ^ (b).lo,                    \
+				 (r).hi = (a).hi ^ (b).hi)
+#define jlong_OR2(r, a)		((r).lo = (r).lo | (a).lo,                    \
+				 (r).hi = (r).hi | (a).hi)
+#define jlong_NOT(r, a)		((r).lo = ~(a).lo,	                          \
+				 (r).hi = ~(a).hi)
+
+#define jlong_NEG(r, a)		((r).lo = -(int32)(a).lo,                     \
+				 (r).hi = -(int32)(a).hi - ((r).lo != 0))
+#define jlong_ADD(r, a, b) {                                              \
+    jlong _a, _b;                                                         \
+    _a = a; _b = b;                                                       \
+    (r).lo = _a.lo + _b.lo;                                               \
+    (r).hi = _a.hi + _b.hi + ((r).lo < _b.lo);                            \
+}
+
+#define jlong_SUB(r, a, b) {                                              \
+    jlong _a, _b;                                                         \
+    _a = a; _b = b;                                                       \
+    (r).lo = _a.lo - _b.lo;                                               \
+    (r).hi = _a.hi - _b.hi - (_a.lo < _b.lo);                             \
+}                                                                         \
+
+/*
+ * Multiply 64-bit operands a and b to get 64-bit result r.
+ * First multiply the low 32 bits of a and b to get a 64-bit result in r.
+ * Then add the outer and inner products to r.hi.
+ */
+#define jlong_MUL(r, a, b) {                                              \
+    jlong _a, _b;                                                         \
+    _a = a; _b = b;                                                       \
+    jlong_MUL32(r, _a.lo, _b.lo);                                         \
+    (r).hi += _a.hi * _b.lo + _a.lo * _b.hi;                              \
+}
+
+/* XXX _jlong_lo16(a) = ((a) << 16 >> 16) is better on some archs (not on mips) */
+#define _jlong_lo16(a)		((a) & JRI_BITMASK(16))
+#define _jlong_hi16(a)		((a) >> 16)
+
+/*
+ * Multiply 32-bit operands a and b to get 64-bit result r.
+ * Use polynomial expansion based on primitive field element (1 << 16).
+ */
+#define jlong_MUL32(r, a, b) {                                            \
+     juint _a1, _a0, _b1, _b0, _y0, _y1, _y2, _y3;                        \
+     _a1 = _jlong_hi16(a), _a0 = _jlong_lo16(a);                          \
+     _b1 = _jlong_hi16(b), _b0 = _jlong_lo16(b);                          \
+     _y0 = _a0 * _b0;                                                     \
+     _y1 = _a0 * _b1;                                                     \
+     _y2 = _a1 * _b0;                                                     \
+     _y3 = _a1 * _b1;                                                     \
+     _y1 += _jlong_hi16(_y0);                   /* can't carry */         \
+     _y1 += _y2;                                /* might carry */         \
+     if (_y1 < _y2) _y3 += 1 << 16;             /* propagate */           \
+     (r).lo = (_jlong_lo16(_y1) << 16) + _jlong_lo16(_y0);                \
+     (r).hi = _y3 + _jlong_hi16(_y1);                                     \
+}
+
+/*
+ * Divide 64-bit unsigned operand a by 64-bit unsigned operand b, setting *qp
+ * to the 64-bit unsigned quotient, and *rp to the 64-bit unsigned remainder.
+ * Minimize effort if one of qp and rp is null.
+ */
+#define jlong_UDIVMOD(qp, rp, a, b)	jlong_udivmod(qp, rp, a, b)
+
+extern JRI_PUBLIC_API(void)
+jlong_udivmod(julong *qp, julong *rp, julong a, julong b);
+
+#define jlong_DIV(r, a, b) {                                              \
+    jlong _a, _b;                                                         \
+    juint _negative = (int32)(a).hi < 0;                                  \
+    if (_negative) {                                                      \
+	jlong_NEG(_a, a);                                                     \
+    } else {                                                              \
+	_a = a;                                                               \
+    }                                                                     \
+    if ((int32)(b).hi < 0) {                                              \
+	_negative ^= 1;                                                       \
+	jlong_NEG(_b, b);                                                     \
+    } else {                                                              \
+	_b = b;                                                               \
+    }                                                                     \
+    jlong_UDIVMOD(&(r), 0, _a, _b);                                       \
+    if (_negative)                                                        \
+	jlong_NEG(r, r);                                                      \
+}
+
+#define jlong_MOD(r, a, b) {                                              \
+    jlong _a, _b;                                                         \
+    juint _negative = (int32)(a).hi < 0;                                  \
+    if (_negative) {                                                      \
+	jlong_NEG(_a, a);                                                     \
+    } else {                                                              \
+	_a = a;                                                               \
+    }                                                                     \
+    if ((int32)(b).hi < 0) {                                              \
+	jlong_NEG(_b, b);                                                     \
+    } else {                                                              \
+	_b = b;                                                               \
+    }                                                                     \
+    jlong_UDIVMOD(0, &(r), _a, _b);                                       \
+    if (_negative)                                                        \
+	jlong_NEG(r, r);                                                      \
+}
+
+/*
+ * NB: b is a juint, not jlong or julong, for the shift ops.
+ */
+#define jlong_SHL(r, a, b) {                                              \
+    if (b) {                                                              \
+	jlong _a;                                                             \
+        _a = a;                                                           \
+        if ((b) < 32) {                                                   \
+	    (r).lo = _a.lo << (b);                                            \
+	    (r).hi = (_a.hi << (b)) | (_a.lo >> (32 - (b)));                  \
+	} else {                                                              \
+	    (r).lo = 0;                                                       \
+	    (r).hi = _a.lo << ((b) & 31);                                     \
+	}                                                                     \
+    } else {                                                              \
+	(r) = (a);                                                            \
+    }                                                                     \
+}
+
+/* a is an int32, b is int32, r is jlong */
+#define jlong_ISHL(r, a, b) {                                             \
+    if (b) {                                                              \
+	jlong _a;                                                             \
+	_a.lo = (a);                                                          \
+	_a.hi = 0;                                                            \
+        if ((b) < 32) {                                                   \
+	    (r).lo = (a) << (b);                                              \
+	    (r).hi = ((a) >> (32 - (b)));                                     \
+	} else {                                                              \
+	    (r).lo = 0;                                                       \
+	    (r).hi = (a) << ((b) & 31);                                       \
+	}                                                                     \
+    } else {                                                              \
+	(r).lo = (a);                                                         \
+	(r).hi = 0;                                                           \
+    }                                                                     \
+}
+
+#define jlong_SHR(r, a, b) {                                              \
+    if (b) {                                                              \
+	jlong _a;                                                             \
+        _a = a;                                                           \
+	if ((b) < 32) {                                                       \
+	    (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> (b));                  \
+	    (r).hi = (int32)_a.hi >> (b);                                     \
+	} else {                                                              \
+	    (r).lo = (int32)_a.hi >> ((b) & 31);                              \
+	    (r).hi = (int32)_a.hi >> 31;                                      \
+	}                                                                     \
+    } else {                                                              \
+	(r) = (a);                                                            \
+    }                                                                     \
+}
+
+#define jlong_USHR(r, a, b) {                                             \
+    if (b) {                                                              \
+	jlong _a;                                                             \
+        _a = a;                                                           \
+	if ((b) < 32) {                                                       \
+	    (r).lo = (_a.hi << (32 - (b))) | (_a.lo >> (b));                  \
+	    (r).hi = _a.hi >> (b);                                            \
+	} else {                                                              \
+	    (r).lo = _a.hi >> ((b) & 31);                                     \
+	    (r).hi = 0;                                                       \
+	}                                                                     \
+    } else {                                                              \
+	(r) = (a);                                                            \
+    }                                                                     \
+}
+
+#define jlong_L2I(i, l)		((i) = (l).lo)
+#define jlong_L2UI(ui, l)	((ui) = (l).lo)
+#define jlong_L2F(f, l)		{ double _d; jlong_L2D(_d, l); (f) = (float) _d; }
+
+#define jlong_L2D(d, l) {                                                 \
+    int32 _negative;                                                      \
+    jlong _absval;                                                        \
+                                                                          \
+    _negative = (l).hi >> 31;                                             \
+    if (_negative) {                                                      \
+	jlong_NEG(_absval, l);                                                \
+    } else {                                                              \
+	_absval = l;                                                          \
+    }                                                                     \
+    (d) = (double)_absval.hi * 4.294967296e9 + _absval.lo;                \
+    if (_negative)                                                        \
+	(d) = -(d);                                                           \
+}
+
+#define jlong_I2L(l, i)		((l).hi = (i) >> 31, (l).lo = (i))
+#define jlong_UI2L(l, ui)	((l).hi = 0, (l).lo = (ui))
+#define jlong_F2L(l, f)		{ double _d = (double) f; jlong_D2L(l, _d); }
+
+#define jlong_D2L(l, d) {                                                 \
+    int _negative;                                                        \
+    double _absval, _d_hi;                                                \
+    jlong _lo_d;                                                          \
+                                                                          \
+    _negative = ((d) < 0);                                                \
+    _absval = _negative ? -(d) : (d);                                     \
+                                                                          \
+    (l).hi = (juint)(_absval / 4.294967296e9);                            \
+    (l).lo = 0;                                                           \
+    jlong_L2D(_d_hi, l);                                                  \
+    _absval -= _d_hi;                                                     \
+    _lo_d.hi = 0;                                                         \
+    if (_absval < 0) {                                                    \
+	_lo_d.lo = (juint) -_absval;                                          \
+	jlong_SUB(l, l, _lo_d);                                               \
+    } else {                                                              \
+	_lo_d.lo = (juint) _absval;                                           \
+	jlong_ADD(l, l, _lo_d);                                               \
+    }                                                                     \
+                                                                          \
+    if (_negative)                                                        \
+	jlong_NEG(l, l);                                                      \
+}
+
+#endif /* !HAVE_LONG_LONG */
+
+/******************************************************************************/
+
+#ifdef HAVE_ALIGNED_LONGLONGS
+#define JRI_GET_INT64(_t,_addr) ( ((_t).x[0] = ((jint*)(_addr))[0]), \
+                              ((_t).x[1] = ((jint*)(_addr))[1]),      \
+                              (_t).l )
+#define JRI_SET_INT64(_t, _addr, _v) ( (_t).l = (_v),                \
+                                   ((jint*)(_addr))[0] = (_t).x[0], \
+                                   ((jint*)(_addr))[1] = (_t).x[1] )
+#else
+#define JRI_GET_INT64(_t,_addr) (*(jlong*)(_addr))
+#define JRI_SET_INT64(_t, _addr, _v) (*(jlong*)(_addr) = (_v))
+#endif
+
+/* If double's must be aligned on doubleword boundaries then define this */
+#ifdef HAVE_ALIGNED_DOUBLES
+#define JRI_GET_DOUBLE(_t,_addr) ( ((_t).x[0] = ((jint*)(_addr))[0]), \
+                               ((_t).x[1] = ((jint*)(_addr))[1]),      \
+                               (_t).d )
+#define JRI_SET_DOUBLE(_t, _addr, _v) ( (_t).d = (_v),                \
+                                    ((jint*)(_addr))[0] = (_t).x[0], \
+                                    ((jint*)(_addr))[1] = (_t).x[1] )
+#else
+#define JRI_GET_DOUBLE(_t,_addr) (*(jdouble*)(_addr))
+#define JRI_SET_DOUBLE(_t, _addr, _v) (*(jdouble*)(_addr) = (_v))
+#endif
+
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+#endif /* JRI_MD_H */
+/******************************************************************************/
diff --git a/third_party/gecko/include/jritypes.h b/third_party/gecko/include/jritypes.h
index 84436a3..ddeb633 100644
--- a/third_party/gecko/include/jritypes.h
+++ b/third_party/gecko/include/jritypes.h
@@ -1,243 +1,243 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is 

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or 

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/*******************************************************************************

- * Java Runtime Interface

- ******************************************************************************/

-

-#ifndef JRITYPES_H

-#define JRITYPES_H

-

-#include "jri_md.h"

-#include "jni.h"

-#include <stddef.h>

-#include <stdlib.h>

-#include <stdarg.h>

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-/*******************************************************************************

- * Types

- ******************************************************************************/

-

-struct JRIEnvInterface;

-

-typedef void*		JRIRef;

-typedef void*		JRIGlobalRef;

-

-typedef jint		JRIFieldID;

-typedef jint		JRIMethodID;

-

-/* synonyms: */

-typedef JRIGlobalRef	jglobal;

-

-typedef union JRIValue {

-	jbool			z;

-	jbyte			b;

-	jchar			c;

-	jshort			s;

-	jint			i;

-	jlong			l;

-	jfloat			f;

-	jdouble			d;

-	jref			r;

-} JRIValue;

-

-typedef enum JRIBoolean {

-    JRIFalse		= 0,

-    JRITrue			= 1

-} JRIBoolean;

-

-typedef enum JRIConstant {

-	JRIUninitialized	= -1

-} JRIConstant;

-

-/* convenience types (these must be distinct struct types for c++ overloading): */

-#if 0	/* now in jni.h */

-typedef struct jbooleanArrayStruct*		jbooleanArray;

-typedef struct jbyteArrayStruct*		jbyteArray;

-typedef struct jcharArrayStruct*		jcharArray;

-typedef struct jshortArrayStruct*		jshortArray;

-typedef struct jintArrayStruct*			jintArray;

-typedef struct jlongArrayStruct*		jlongArray;

-typedef struct jfloatArrayStruct*		jfloatArray;

-typedef struct jdoubleArrayStruct*		jdoubleArray;

-typedef struct jobjectArrayStruct*		jobjectArray;

-#endif

-typedef struct jstringArrayStruct*		jstringArray;

-typedef struct jarrayArrayStruct*		jarrayArray;

-

-#define JRIConstructorMethodName	"<init>"

-

-/*******************************************************************************

- * Signature Construction Macros

- ******************************************************************************/

-

-/*

-** These macros can be used to construct signature strings. Hopefully their names

-** are a little easier to remember than the single character they correspond to.

-** For example, to specify the signature of the method:

-**

-**	public int read(byte b[], int off, int len);

-**

-** you could write something like this in C:

-**

-**	char* readSig = JRISigMethod(JRISigArray(JRISigByte)

-**								 JRISigInt

-**								 JRISigInt) JRISigInt;

-**

-** Of course, don't put commas between the types.

-*/

-#define JRISigArray(T)		"[" T

-#define JRISigByte			"B"

-#define JRISigChar			"C"

-#define JRISigClass(name)	"L" name ";"

-#define JRISigFloat			"F"

-#define JRISigDouble		"D"

-#define JRISigMethod(args)	"(" args ")"

-#define JRISigNoArgs		""

-#define JRISigInt			"I"

-#define JRISigLong			"J"

-#define JRISigShort			"S"

-#define JRISigVoid			"V"

-#define JRISigBoolean		"Z"

-

-/*******************************************************************************

- * Environments

- ******************************************************************************/

-

-extern JRI_PUBLIC_API(const struct JRIEnvInterface**)

-JRI_GetCurrentEnv(void);

-

-/*******************************************************************************

- * Specific Scalar Array Types

- ******************************************************************************/

-

-/*

-** The JRI Native Method Interface does not support boolean arrays. This

-** is to allow Java runtime implementations to optimize boolean array

-** storage. Using the ScalarArray operations on boolean arrays is bound

-** to fail, so convert any boolean arrays to byte arrays in Java before

-** passing them to a native method.

-*/

-

-#define JRI_NewByteArray(env, length, initialValues)	\

-	JRI_NewScalarArray(env, length, JRISigByte, (jbyte*)(initialValues))

-#define JRI_GetByteArrayLength(env, array)	\

-	JRI_GetScalarArrayLength(env, array)

-#define JRI_GetByteArrayElements(env, array)	\

-	JRI_GetScalarArrayElements(env, array)

-

-#define JRI_NewCharArray(env, length, initialValues)	\

-	JRI_NewScalarArray(env, ((length) * sizeof(jchar)), JRISigChar, (jbyte*)(initialValues))

-#define JRI_GetCharArrayLength(env, array)	\

-	JRI_GetScalarArrayLength(env, array)

-#define JRI_GetCharArrayElements(env, array)		   \

-	((jchar*)JRI_GetScalarArrayElements(env, array))

-

-#define JRI_NewShortArray(env, length, initialValues)	\

-	JRI_NewScalarArray(env, ((length) * sizeof(jshort)), JRISigShort, (jbyte*)(initialValues))

-#define JRI_GetShortArrayLength(env, array)	\

-	JRI_GetScalarArrayLength(env, array)

-#define JRI_GetShortArrayElements(env, array)		   \

-	((jshort*)JRI_GetScalarArrayElements(env, array))

-

-#define JRI_NewIntArray(env, length, initialValues)	\

-	JRI_NewScalarArray(env, ((length) * sizeof(jint)), JRISigInt, (jbyte*)(initialValues))

-#define JRI_GetIntArrayLength(env, array)	\

-	JRI_GetScalarArrayLength(env, array)

-#define JRI_GetIntArrayElements(env, array)		   \

-	((jint*)JRI_GetScalarArrayElements(env, array))

-

-#define JRI_NewLongArray(env, length, initialValues)	\

-	JRI_NewScalarArray(env, ((length) * sizeof(jlong)), JRISigLong, (jbyte*)(initialValues))

-#define JRI_GetLongArrayLength(env, array)	\

-	JRI_GetScalarArrayLength(env, array)

-#define JRI_GetLongArrayElements(env, array)		   \

-	((jlong*)JRI_GetScalarArrayElements(env, array))

-

-#define JRI_NewFloatArray(env, length, initialValues)	\

-	JRI_NewScalarArray(env, ((length) * sizeof(jfloat)), JRISigFloat, (jbyte*)(initialValues))

-#define JRI_GetFloatArrayLength(env, array)	\

-	JRI_GetScalarArrayLength(env, array)

-#define JRI_GetFloatArrayElements(env, array)		   \

-	((jfloat*)JRI_GetScalarArrayElements(env, array))

-

-#define JRI_NewDoubleArray(env, length, initialValues)	\

-	JRI_NewScalarArray(env, ((length) * sizeof(jdouble)), JRISigDouble, (jbyte*)(initialValues))

-#define JRI_GetDoubleArrayLength(env, array)	\

-	JRI_GetScalarArrayLength(env, array)

-#define JRI_GetDoubleArrayElements(env, array)		   \

-	((jdouble*)JRI_GetScalarArrayElements(env, array))

-

-/******************************************************************************/

-/*

-** JDK Stuff -- This stuff is still needed while we're using the JDK

-** dynamic linking strategy to call native methods.

-*/

-

-typedef union JRI_JDK_stack_item {

-    /* Non pointer items */

-    jint           i;

-    jfloat         f;

-    jint           o;

-    /* Pointer items */

-    void          *h;

-    void          *p;

-    unsigned char *addr;

-#ifdef IS_64

-    double         d;

-    long           l;		/* == 64bits! */

-#endif

-} JRI_JDK_stack_item;

-

-typedef union JRI_JDK_Java8Str {

-    jint x[2];

-    jdouble d;

-    jlong l;

-    void *p;

-    float f;

-} JRI_JDK_Java8;

-

-/******************************************************************************/

-#ifdef __cplusplus

-}

-#endif

-#endif /* JRITYPES_H */

-/******************************************************************************/

+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*******************************************************************************
+ * Java Runtime Interface
+ ******************************************************************************/
+
+#ifndef JRITYPES_H
+#define JRITYPES_H
+
+#include "jri_md.h"
+#include "jni.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * Types
+ ******************************************************************************/
+
+struct JRIEnvInterface;
+
+typedef void*		JRIRef;
+typedef void*		JRIGlobalRef;
+
+typedef jint		JRIFieldID;
+typedef jint		JRIMethodID;
+
+/* synonyms: */
+typedef JRIGlobalRef	jglobal;
+
+typedef union JRIValue {
+	jbool			z;
+	jbyte			b;
+	jchar			c;
+	jshort			s;
+	jint			i;
+	jlong			l;
+	jfloat			f;
+	jdouble			d;
+	jref			r;
+} JRIValue;
+
+typedef enum JRIBoolean {
+    JRIFalse		= 0,
+    JRITrue			= 1
+} JRIBoolean;
+
+typedef enum JRIConstant {
+	JRIUninitialized	= -1
+} JRIConstant;
+
+/* convenience types (these must be distinct struct types for c++ overloading): */
+#if 0	/* now in jni.h */
+typedef struct jbooleanArrayStruct*		jbooleanArray;
+typedef struct jbyteArrayStruct*		jbyteArray;
+typedef struct jcharArrayStruct*		jcharArray;
+typedef struct jshortArrayStruct*		jshortArray;
+typedef struct jintArrayStruct*			jintArray;
+typedef struct jlongArrayStruct*		jlongArray;
+typedef struct jfloatArrayStruct*		jfloatArray;
+typedef struct jdoubleArrayStruct*		jdoubleArray;
+typedef struct jobjectArrayStruct*		jobjectArray;
+#endif
+typedef struct jstringArrayStruct*		jstringArray;
+typedef struct jarrayArrayStruct*		jarrayArray;
+
+#define JRIConstructorMethodName	"<init>"
+
+/*******************************************************************************
+ * Signature Construction Macros
+ ******************************************************************************/
+
+/*
+** These macros can be used to construct signature strings. Hopefully their names
+** are a little easier to remember than the single character they correspond to.
+** For example, to specify the signature of the method:
+**
+**	public int read(byte b[], int off, int len);
+**
+** you could write something like this in C:
+**
+**	char* readSig = JRISigMethod(JRISigArray(JRISigByte)
+**								 JRISigInt
+**								 JRISigInt) JRISigInt;
+**
+** Of course, don't put commas between the types.
+*/
+#define JRISigArray(T)		"[" T
+#define JRISigByte			"B"
+#define JRISigChar			"C"
+#define JRISigClass(name)	"L" name ";"
+#define JRISigFloat			"F"
+#define JRISigDouble		"D"
+#define JRISigMethod(args)	"(" args ")"
+#define JRISigNoArgs		""
+#define JRISigInt			"I"
+#define JRISigLong			"J"
+#define JRISigShort			"S"
+#define JRISigVoid			"V"
+#define JRISigBoolean		"Z"
+
+/*******************************************************************************
+ * Environments
+ ******************************************************************************/
+
+extern JRI_PUBLIC_API(const struct JRIEnvInterface**)
+JRI_GetCurrentEnv(void);
+
+/*******************************************************************************
+ * Specific Scalar Array Types
+ ******************************************************************************/
+
+/*
+** The JRI Native Method Interface does not support boolean arrays. This
+** is to allow Java runtime implementations to optimize boolean array
+** storage. Using the ScalarArray operations on boolean arrays is bound
+** to fail, so convert any boolean arrays to byte arrays in Java before
+** passing them to a native method.
+*/
+
+#define JRI_NewByteArray(env, length, initialValues)	\
+	JRI_NewScalarArray(env, length, JRISigByte, (jbyte*)(initialValues))
+#define JRI_GetByteArrayLength(env, array)	\
+	JRI_GetScalarArrayLength(env, array)
+#define JRI_GetByteArrayElements(env, array)	\
+	JRI_GetScalarArrayElements(env, array)
+
+#define JRI_NewCharArray(env, length, initialValues)	\
+	JRI_NewScalarArray(env, ((length) * sizeof(jchar)), JRISigChar, (jbyte*)(initialValues))
+#define JRI_GetCharArrayLength(env, array)	\
+	JRI_GetScalarArrayLength(env, array)
+#define JRI_GetCharArrayElements(env, array)		   \
+	((jchar*)JRI_GetScalarArrayElements(env, array))
+
+#define JRI_NewShortArray(env, length, initialValues)	\
+	JRI_NewScalarArray(env, ((length) * sizeof(jshort)), JRISigShort, (jbyte*)(initialValues))
+#define JRI_GetShortArrayLength(env, array)	\
+	JRI_GetScalarArrayLength(env, array)
+#define JRI_GetShortArrayElements(env, array)		   \
+	((jshort*)JRI_GetScalarArrayElements(env, array))
+
+#define JRI_NewIntArray(env, length, initialValues)	\
+	JRI_NewScalarArray(env, ((length) * sizeof(jint)), JRISigInt, (jbyte*)(initialValues))
+#define JRI_GetIntArrayLength(env, array)	\
+	JRI_GetScalarArrayLength(env, array)
+#define JRI_GetIntArrayElements(env, array)		   \
+	((jint*)JRI_GetScalarArrayElements(env, array))
+
+#define JRI_NewLongArray(env, length, initialValues)	\
+	JRI_NewScalarArray(env, ((length) * sizeof(jlong)), JRISigLong, (jbyte*)(initialValues))
+#define JRI_GetLongArrayLength(env, array)	\
+	JRI_GetScalarArrayLength(env, array)
+#define JRI_GetLongArrayElements(env, array)		   \
+	((jlong*)JRI_GetScalarArrayElements(env, array))
+
+#define JRI_NewFloatArray(env, length, initialValues)	\
+	JRI_NewScalarArray(env, ((length) * sizeof(jfloat)), JRISigFloat, (jbyte*)(initialValues))
+#define JRI_GetFloatArrayLength(env, array)	\
+	JRI_GetScalarArrayLength(env, array)
+#define JRI_GetFloatArrayElements(env, array)		   \
+	((jfloat*)JRI_GetScalarArrayElements(env, array))
+
+#define JRI_NewDoubleArray(env, length, initialValues)	\
+	JRI_NewScalarArray(env, ((length) * sizeof(jdouble)), JRISigDouble, (jbyte*)(initialValues))
+#define JRI_GetDoubleArrayLength(env, array)	\
+	JRI_GetScalarArrayLength(env, array)
+#define JRI_GetDoubleArrayElements(env, array)		   \
+	((jdouble*)JRI_GetScalarArrayElements(env, array))
+
+/******************************************************************************/
+/*
+** JDK Stuff -- This stuff is still needed while we're using the JDK
+** dynamic linking strategy to call native methods.
+*/
+
+typedef union JRI_JDK_stack_item {
+    /* Non pointer items */
+    jint           i;
+    jfloat         f;
+    jint           o;
+    /* Pointer items */
+    void          *h;
+    void          *p;
+    unsigned char *addr;
+#ifdef IS_64
+    double         d;
+    long           l;		/* == 64bits! */
+#endif
+} JRI_JDK_stack_item;
+
+typedef union JRI_JDK_Java8Str {
+    jint x[2];
+    jdouble d;
+    jlong l;
+    void *p;
+    float f;
+} JRI_JDK_Java8;
+
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+#endif /* JRITYPES_H */
+/******************************************************************************/
diff --git a/third_party/gecko/include/npapi.h b/third_party/gecko/include/npapi.h
index a728f9c..ad9795e 100644
--- a/third_party/gecko/include/npapi.h
+++ b/third_party/gecko/include/npapi.h
@@ -1,726 +1,726 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-

-/*

- *  npapi.h $Revision: 3.40 $

- *  Netscape client plug-in API spec

- */

-

-#ifndef _NPAPI_H_

-#define _NPAPI_H_

-

-#ifdef __OS2__

-#pragma pack(1)

-#endif

-

-#include "prtypes.h"

-/* Copied from xp_core.h */

-/* removed #ifdef for hpux defined in /usr/include/model.h */

-#ifndef XP_MAC

-#ifndef _INT16

-#define _INT16

-#endif

-#ifndef _INT32

-#define _INT32

-#endif

-#ifndef _UINT16

-#define _UINT16

-#endif

-#ifndef _UINT32

-#define _UINT32

-#endif

-#endif

-

-/* 

- * NO_NSPR_10_SUPPORT disables the inclusion 

- * of obsolete/protypes.h, whose int16, uint16, 

- * int32, and uint32 typedefs conflict with those 

- * in this file. 

- */ 

-#ifndef NO_NSPR_10_SUPPORT

-#define NO_NSPR_10_SUPPORT

-#endif

-#ifdef OJI

-#include "jri.h"                /* Java Runtime Interface */

-#endif

-

-#if defined (__OS2__ ) || defined (OS2)

-#	ifndef XP_OS2

-#		define XP_OS2 1

-#	endif /* XP_OS2 */

-#endif /* __OS2__ */

-

-#ifdef _WINDOWS

-#	include <windef.h>

-#	ifndef XP_WIN

-#		define XP_WIN 1

-#	endif /* XP_WIN */

-#endif /* _WINDOWS */

-

-#ifdef __MWERKS__

-#	define _declspec __declspec

-#	ifdef macintosh

-#		ifndef XP_MAC

-#			define XP_MAC 1

-#		endif /* XP_MAC */

-#	endif /* macintosh */

-#	ifdef __INTEL__

-#		undef NULL

-#		ifndef XP_WIN

-#			define XP_WIN 1

-#		endif /* XP_WIN */

-#	endif /* __INTEL__ */

-#endif /* __MWERKS__ */

-

-#if defined(XP_MAC) || defined(XP_MACOSX)

-	#include <Quickdraw.h>

-	#include <Events.h>

-#endif

-

-#if defined(XP_UNIX) 

-#	include <stdio.h>

-#	if defined(MOZ_X11)

-#		include <X11/Xlib.h>

-#		include <X11/Xutil.h>

-#	endif

-#endif

-

-/*----------------------------------------------------------------------*/

-/*                        Plugin Version Constants                      */

-/*----------------------------------------------------------------------*/

-

-#define NP_VERSION_MAJOR 0

-#define NP_VERSION_MINOR 16

-

-

-/* The OS/2 version of Netscape uses RC_DATA to define the

-   mime types, file extensions, etc that are required.

-   Use a vertical bar to separate types, end types with \0.

-   FileVersion and ProductVersion are 32bit ints, all other

-   entries are strings the MUST be terminated wwith a \0.

-

-AN EXAMPLE:

-

-RCDATA NP_INFO_ProductVersion { 1,0,0,1,}

-

-RCDATA NP_INFO_MIMEType    { "video/x-video|",

-                             "video/x-flick\0" }

-RCDATA NP_INFO_FileExtents { "avi|",

-                             "flc\0" }

-RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|",

-                             "MMOS2 Flc/Fli player(*.flc)\0" }

-

-RCDATA NP_INFO_FileVersion       { 1,0,0,1 }

-RCDATA NP_INFO_CompanyName       { "Netscape Communications\0" }

-RCDATA NP_INFO_FileDescription   { "NPAVI32 Extension DLL\0"

-RCDATA NP_INFO_InternalName      { "NPAVI32\0" )

-RCDATA NP_INFO_LegalCopyright    { "Copyright Netscape Communications \251 1996\0"

-RCDATA NP_INFO_OriginalFilename  { "NVAPI32.DLL" }

-RCDATA NP_INFO_ProductName       { "NPAVI32 Dynamic Link Library\0" }

-

-*/

-

-

-/* RC_DATA types for version info - required */

-#define NP_INFO_ProductVersion      1

-#define NP_INFO_MIMEType            2

-#define NP_INFO_FileOpenName        3

-#define NP_INFO_FileExtents         4

-

-/* RC_DATA types for version info - used if found */

-#define NP_INFO_FileDescription     5

-#define NP_INFO_ProductName         6

-

-/* RC_DATA types for version info - optional */

-#define NP_INFO_CompanyName         7

-#define NP_INFO_FileVersion         8

-#define NP_INFO_InternalName        9

-#define NP_INFO_LegalCopyright      10

-#define NP_INFO_OriginalFilename    11

-

-#ifndef RC_INVOKED

-

-

-

-/*----------------------------------------------------------------------*/

-/*                       Definition of Basic Types                      */

-/*----------------------------------------------------------------------*/

-

-#ifndef _UINT16

-typedef unsigned short uint16;

-#endif

-

-#ifndef _UINT32

-#    if defined(__alpha) || defined(__amd64__) || defined(__x86_64__)

-typedef unsigned int uint32;

-#    else  /* __alpha */

-typedef unsigned long uint32;

-#    endif /* __alpha */

-#endif

-

-/*

- * AIX defines these in sys/inttypes.h included from sys/types.h

- */

-#ifndef AIX

-#ifndef _INT16

-typedef short int16;

-#endif

-

-#ifndef _INT32

-#    if defined(__alpha) || defined(__amd64__) || defined(__x86_64__)

-typedef int int32;

-#    else  /* __alpha */

-typedef long int32;

-#    endif /* __alpha */

-#endif

-#endif

-

-#ifndef FALSE

-#define FALSE (0)

-#endif

-#ifndef TRUE

-#define TRUE (1)

-#endif

-#ifndef NULL

-#define NULL (0L)

-#endif

-

-typedef unsigned char	NPBool;

-typedef int16			NPError;

-typedef int16			NPReason;

-typedef char*			NPMIMEType;

-

-

-

-/*----------------------------------------------------------------------*/

-/*                       Structures and definitions                     */

-/*----------------------------------------------------------------------*/

-

-#ifdef XP_MAC

-#pragma options align=mac68k

-#endif

-

-/*

- *  NPP is a plug-in's opaque instance handle

- */

-typedef struct _NPP

-{

-  void*	pdata;      /* plug-in private data */

-  void*	ndata;      /* netscape private data */

-} NPP_t;

-

-typedef NPP_t*  NPP;

-

-

-typedef struct _NPStream

-{

-  void*  pdata; /* plug-in private data */

-  void*  ndata; /* netscape private data */

-  const  char* url;

-  uint32 end;

-  uint32 lastmodified;

-  void*  notifyData;

-} NPStream;

-

-

-typedef struct _NPByteRange

-{

-  int32  offset; /* negative offset means from the end */

-  uint32 length;

-  struct _NPByteRange* next;

-} NPByteRange;

-

-

-typedef struct _NPSavedData

-{

-  int32	len;

-  void*	buf;

-} NPSavedData;

-

-

-typedef struct _NPRect

-{

-  uint16 top;

-  uint16 left;

-  uint16 bottom;

-  uint16 right;

-} NPRect;

-

-typedef struct _NPSize 

-{ 

-  int32 width; 

-  int32 height; 

-} NPSize; 

-

-#ifdef XP_UNIX

-/*

- * Unix specific structures and definitions

- */

-

-/*

- * Callback Structures.

- *

- * These are used to pass additional platform specific information.

- */

-enum {

-  NP_SETWINDOW = 1,

-  NP_PRINT

-};

-

-typedef struct

-{

-  int32 type;

-} NPAnyCallbackStruct;

-

-typedef struct

-{

-  int32        type;

-#ifdef MOZ_X11

-  Display*     display;

-  Visual*      visual;

-  Colormap     colormap;

-  unsigned int depth;

-#endif

-} NPSetWindowCallbackStruct;

-

-typedef struct

-{

-  int32 type;

-  FILE* fp;

-} NPPrintCallbackStruct;

-

-#endif /* XP_UNIX */

-

-

-/*

- *   The following masks are applied on certain platforms to NPNV and 

- *   NPPV selectors that pass around pointers to COM interfaces. Newer 

- *   compilers on some platforms may generate vtables that are not 

- *   compatible with older compilers. To prevent older plugins from 

- *   not understanding a new browser's ABI, these masks change the 

- *   values of those selectors on those platforms. To remain backwards

- *   compatible with differenet versions of the browser, plugins can 

- *   use these masks to dynamically determine and use the correct C++

- *   ABI that the browser is expecting. This does not apply to Windows 

- *   as Microsoft's COM ABI will likely not change.

- */

-

-#define NP_ABI_GCC3_MASK  0x10000000

-/*

- *   gcc 3.x generated vtables on UNIX and OSX are incompatible with 

- *   previous compilers.

- */

-#if (defined (XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3))

-#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK

-#else

-#define _NP_ABI_MIXIN_FOR_GCC3 0

-#endif

-

-

-#define NP_ABI_MACHO_MASK 0x01000000

-/*

- *   On OSX, the Mach-O executable format is significantly

- *   different than CFM. In addition to having a different

- *   C++ ABI, it also has has different C calling convention.

- *   You must use glue code when calling between CFM and

- *   Mach-O C functions. 

- */

-#if (defined(TARGET_RT_MAC_MACHO))

-#define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK

-#else

-#define _NP_ABI_MIXIN_FOR_MACHO 0

-#endif

-

-

-#define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO)

-

-/*

- * List of variable names for which NPP_GetValue shall be implemented

- */

-typedef enum {

-  NPPVpluginNameString = 1,

-  NPPVpluginDescriptionString,

-  NPPVpluginWindowBool,

-  NPPVpluginTransparentBool,

-  NPPVjavaClass,                /* Not implemented in Mozilla 1.0 */

-  NPPVpluginWindowSize,

-  NPPVpluginTimerInterval,

-

-  NPPVpluginScriptableInstance = (10 | NP_ABI_MASK),

-  NPPVpluginScriptableIID = 11,

-

-  /* Introduced in Mozilla 0.9.9 */

-  NPPVjavascriptPushCallerBool = 12,

-

-  /* Introduced in Mozilla 1.0 */

-  NPPVpluginKeepLibraryInMemory = 13,

-  NPPVpluginNeedsXEmbed         = 14,

-

-  /* Get the NPObject for scripting the plugin. Introduced in Firefox

-   * 1.0 (NPAPI minor version 14).

-   */

-  NPPVpluginScriptableNPObject  = 15,

-

-  /* Get the plugin value (as \0-terminated UTF-8 string data) for

-   * form submission if the plugin is part of a form. Use

-   * NPN_MemAlloc() to allocate memory for the string data. Introduced

-   * in Mozilla 1.8b2 (NPAPI minor version 15).

-   */

-  NPPVformValue = 16

-} NPPVariable;

-

-/*

- * List of variable names for which NPN_GetValue is implemented by Mozilla

- */

-typedef enum {

-  NPNVxDisplay = 1,

-  NPNVxtAppContext,

-  NPNVnetscapeWindow,

-  NPNVjavascriptEnabledBool,

-  NPNVasdEnabledBool,

-  NPNVisOfflineBool,

-

-  /* 10 and over are available on Mozilla builds starting with 0.9.4 */

-  NPNVserviceManager = (10 | NP_ABI_MASK),

-  NPNVDOMElement     = (11 | NP_ABI_MASK),   /* available in Mozilla 1.2 */

-  NPNVDOMWindow      = (12 | NP_ABI_MASK),

-  NPNVToolkit        = (13 | NP_ABI_MASK),

-  NPNVSupportsXEmbedBool = 14,

-

-  /* Get the NPObject wrapper for the browser window. */

-  NPNVWindowNPObject = 15,

-

-  /* Get the NPObject wrapper for the plugins DOM element. */

-  NPNVPluginElementNPObject = 16

-} NPNVariable;

-

-/*

- * The type of Tookkit the widgets use

- */

-typedef enum {

-  NPNVGtk12 = 1,

-  NPNVGtk2

-} NPNToolkitType;

-

-/*

- * The type of a NPWindow - it specifies the type of the data structure

- * returned in the window field.

- */

-typedef enum {

-  NPWindowTypeWindow = 1,

-  NPWindowTypeDrawable

-} NPWindowType;

-

-typedef struct _NPWindow

-{

-  void* window;  /* Platform specific window handle */

-                 /* OS/2: x - Position of bottom left corner  */

-                 /* OS/2: y - relative to visible netscape window */

-  int32 x;       /* Position of top left corner relative */

-  int32 y;       /* to a netscape page.					*/

-  uint32 width;  /* Maximum window size */

-  uint32 height;

-  NPRect clipRect; /* Clipping rectangle in port coordinates */

-                   /* Used by MAC only.			  */

-#if defined(XP_UNIX) && !defined(XP_MACOSX)

-  void * ws_info; /* Platform-dependent additonal data */

-#endif /* XP_UNIX */

-  NPWindowType type; /* Is this a window or a drawable? */

-} NPWindow;

-

-

-typedef struct _NPFullPrint

-{

-  NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */

-  NPBool printOne;		 /* TRUE if plugin should print one copy to default printer */

-  void* platformPrint; /* Platform-specific printing info */

-} NPFullPrint;

-

-typedef struct _NPEmbedPrint

-{

-  NPWindow window;

-  void* platformPrint; /* Platform-specific printing info */

-} NPEmbedPrint;

-

-typedef struct _NPPrint

-{

-  uint16 mode;               /* NP_FULL or NP_EMBED */

-  union

-  {

-    NPFullPrint fullPrint;   /* if mode is NP_FULL */

-    NPEmbedPrint embedPrint; /* if mode is NP_EMBED */

-  } print;

-} NPPrint;

-

-#if defined(XP_MAC) || defined(XP_MACOSX)

-typedef EventRecord	NPEvent;

-#elif defined(XP_WIN)

-typedef struct _NPEvent

-{

-  uint16 event;

-  uint32 wParam;

-  uint32 lParam;

-} NPEvent;

-#elif defined(XP_OS2)

-typedef struct _NPEvent

-{

-  uint32 event;

-  uint32 wParam;

-  uint32 lParam;

-} NPEvent;

-#elif defined (XP_UNIX) && defined(MOZ_X11)

-typedef XEvent NPEvent;

-#else

-typedef void*			NPEvent;

-#endif /* XP_MAC */

-

-#if defined(XP_MAC) || defined(XP_MACOSX)

-typedef RgnHandle NPRegion;

-#elif defined(XP_WIN)

-typedef HRGN NPRegion;

-#elif defined(XP_UNIX) && defined(MOZ_X11)

-typedef Region NPRegion;

-#else

-typedef void *NPRegion;

-#endif /* XP_MAC */

-

-#if defined(XP_MAC) || defined(XP_MACOSX)

-/*

- *  Mac-specific structures and definitions.

- */

-

-typedef struct NP_Port

-{

-  CGrafPtr port; /* Grafport */

-  int32 portx;   /* position inside the topmost window */

-  int32 porty;

-} NP_Port;

-

-/*

- *  Non-standard event types that can be passed to HandleEvent

- */

-

-enum NPEventType {

-  NPEventType_GetFocusEvent = (osEvt + 16),

-  NPEventType_LoseFocusEvent,

-  NPEventType_AdjustCursorEvent,

-  NPEventType_MenuCommandEvent,

-  NPEventType_ClippingChangedEvent,

-  NPEventType_ScrollingBeginsEvent = 1000,

-  NPEventType_ScrollingEndsEvent

-};

-

-#ifdef OBSOLETE

-#define getFocusEvent     (osEvt + 16)

-#define loseFocusEvent    (osEvt + 17)

-#define adjustCursorEvent (osEvt + 18)

-#endif

-#endif /* XP_MAC */

-

-/*

- * Values for mode passed to NPP_New:

- */

-#define NP_EMBED 1

-#define NP_FULL  2

-

-/*

- * Values for stream type passed to NPP_NewStream:

- */

-#define NP_NORMAL     1

-#define NP_SEEK       2

-#define NP_ASFILE     3

-#define NP_ASFILEONLY 4

-

-#define NP_MAXREADY	(((unsigned)(~0)<<1)>>1)

-

-#ifdef XP_MAC

-#pragma options align=reset

-#endif

-

-

-/*----------------------------------------------------------------------*/

-/*		     Error and Reason Code definitions			*/

-/*----------------------------------------------------------------------*/

-

-/*

- * Values of type NPError:

- */

-#define NPERR_BASE                         0

-#define NPERR_NO_ERROR                    (NPERR_BASE + 0)

-#define NPERR_GENERIC_ERROR               (NPERR_BASE + 1)

-#define NPERR_INVALID_INSTANCE_ERROR      (NPERR_BASE + 2)

-#define NPERR_INVALID_FUNCTABLE_ERROR     (NPERR_BASE + 3)

-#define NPERR_MODULE_LOAD_FAILED_ERROR    (NPERR_BASE + 4)

-#define NPERR_OUT_OF_MEMORY_ERROR         (NPERR_BASE + 5)

-#define NPERR_INVALID_PLUGIN_ERROR        (NPERR_BASE + 6)

-#define NPERR_INVALID_PLUGIN_DIR_ERROR    (NPERR_BASE + 7)

-#define NPERR_INCOMPATIBLE_VERSION_ERROR  (NPERR_BASE + 8)

-#define NPERR_INVALID_PARAM               (NPERR_BASE + 9)

-#define NPERR_INVALID_URL                 (NPERR_BASE + 10)

-#define NPERR_FILE_NOT_FOUND              (NPERR_BASE + 11)

-#define NPERR_NO_DATA                     (NPERR_BASE + 12)

-#define NPERR_STREAM_NOT_SEEKABLE         (NPERR_BASE + 13)

-

-/*

- * Values of type NPReason:

- */

-#define NPRES_BASE          0

-#define NPRES_DONE         (NPRES_BASE + 0)

-#define NPRES_NETWORK_ERR  (NPRES_BASE + 1)

-#define NPRES_USER_BREAK   (NPRES_BASE + 2)

-

-/*

- * Don't use these obsolete error codes any more.

- */

-#define NP_NOERR  NP_NOERR_is_obsolete_use_NPERR_NO_ERROR

-#define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR

-#define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK

-

-/*

- * Version feature information

- */

-#define NPVERS_HAS_STREAMOUTPUT      8

-#define NPVERS_HAS_NOTIFICATION      9

-#define NPVERS_HAS_LIVECONNECT       9

-#define NPVERS_WIN16_HAS_LIVECONNECT 9

-#define NPVERS_68K_HAS_LIVECONNECT   11

-#define NPVERS_HAS_WINDOWLESS        11

-#define NPVERS_HAS_XPCONNECT_SCRIPTING 13

-

-/*----------------------------------------------------------------------*/

-/*                        Function Prototypes                           */

-/*----------------------------------------------------------------------*/

-

-#if defined(_WINDOWS) && !defined(WIN32)

-#define NP_LOADDS  _loadds

-#else

-#if defined(__OS2__)

-#define NP_LOADDS _System

-#else

-#define NP_LOADDS

-#endif

-#endif

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-/*

- * NPP_* functions are provided by the plugin and called by the navigator.

- */

-

-#ifdef XP_UNIX

-char* NPP_GetMIMEDescription(void);

-#endif /* XP_UNIX */

-

-NPError NP_LOADDS NPP_Initialize(void);

-void    NP_LOADDS NPP_Shutdown(void);

-NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance,

-                          uint16 mode, int16 argc, char* argn[],

-                          char* argv[], NPSavedData* saved);

-NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save);

-NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window);

-NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type,

-                                NPStream* stream, NPBool seekable,

-                                uint16* stype);

-NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream,

-                                    NPReason reason);

-int32   NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream);

-int32   NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32 offset,

-                            int32 len, void* buffer);

-void    NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream,

-                                   const char* fname);

-void    NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint);

-int16   NP_LOADDS NPP_HandleEvent(NPP instance, void* event);

-void    NP_LOADDS NPP_URLNotify(NPP instance, const char* url,

-                                NPReason reason, void* notifyData);

-#ifdef OJI

-jref    NP_LOADDS NPP_GetJavaClass(void);

-#endif

-NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value);

-NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value);

-

-/*

- * NPN_* functions are provided by the navigator and called by the plugin.

- */

-void    NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor,

-                              int* netscape_major, int* netscape_minor);

-NPError NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url,

-                                   const char* target, void* notifyData);

-NPError NP_LOADDS NPN_GetURL(NPP instance, const char* url,

-                             const char* target);

-NPError NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url,

-                                    const char* target, uint32 len,

-                                    const char* buf, NPBool file,

-                                    void* notifyData);

-NPError NP_LOADDS NPN_PostURL(NPP instance, const char* url,

-                              const char* target, uint32 len,

-                              const char* buf, NPBool file);

-NPError NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList);

-NPError NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type,

-                                const char* target, NPStream** stream);

-int32   NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32 len, void* buffer);

-NPError NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream, NPReason reason);

-void    NP_LOADDS NPN_Status(NPP instance, const char* message);

-const char* NP_LOADDS	NPN_UserAgent(NPP instance);

-void*   NP_LOADDS NPN_MemAlloc(uint32 size);

-void    NP_LOADDS NPN_MemFree(void* ptr);

-uint32  NP_LOADDS NPN_MemFlush(uint32 size);

-void    NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages);

-#ifdef OJI

-JRIEnv* NP_LOADDS NPN_GetJavaEnv(void);

-jref    NP_LOADDS NPN_GetJavaPeer(NPP instance);

-#endif

-NPError NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable, void *value);

-NPError NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable, void *value);

-void    NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect);

-void    NP_LOADDS NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion);

-void    NP_LOADDS NPN_ForceRedraw(NPP instance);

-void    NP_LOADDS NPN_PushPopupEnabledState(NPP instance, NPBool enabled);

-void    NP_LOADDS NPN_PopPopupEnabledState(NPP instance);

-

-#ifdef __cplusplus

-}  /* end extern "C" */

-#endif

-

-#endif /* RC_INVOKED */

-#ifdef __OS2__

-#pragma pack()

-#endif

-

-#endif /* _NPAPI_H_ */

+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+/*
+ *  npapi.h $Revision: 3.40 $
+ *  Netscape client plug-in API spec
+ */
+
+#ifndef _NPAPI_H_
+#define _NPAPI_H_
+
+#ifdef __OS2__
+#pragma pack(1)
+#endif
+
+#include "prtypes.h"
+/* Copied from xp_core.h */
+/* removed #ifdef for hpux defined in /usr/include/model.h */
+#ifndef XP_MAC
+#ifndef _INT16
+#define _INT16
+#endif
+#ifndef _INT32
+#define _INT32
+#endif
+#ifndef _UINT16
+#define _UINT16
+#endif
+#ifndef _UINT32
+#define _UINT32
+#endif
+#endif
+
+/* 
+ * NO_NSPR_10_SUPPORT disables the inclusion 
+ * of obsolete/protypes.h, whose int16, uint16, 
+ * int32, and uint32 typedefs conflict with those 
+ * in this file. 
+ */ 
+#ifndef NO_NSPR_10_SUPPORT
+#define NO_NSPR_10_SUPPORT
+#endif
+#ifdef OJI
+#include "jri.h"                /* Java Runtime Interface */
+#endif
+
+#if defined (__OS2__ ) || defined (OS2)
+#	ifndef XP_OS2
+#		define XP_OS2 1
+#	endif /* XP_OS2 */
+#endif /* __OS2__ */
+
+#ifdef _WINDOWS
+#	include <windef.h>
+#	ifndef XP_WIN
+#		define XP_WIN 1
+#	endif /* XP_WIN */
+#endif /* _WINDOWS */
+
+#ifdef __MWERKS__
+#	define _declspec __declspec
+#	ifdef macintosh
+#		ifndef XP_MAC
+#			define XP_MAC 1
+#		endif /* XP_MAC */
+#	endif /* macintosh */
+#	ifdef __INTEL__
+#		undef NULL
+#		ifndef XP_WIN
+#			define XP_WIN 1
+#		endif /* XP_WIN */
+#	endif /* __INTEL__ */
+#endif /* __MWERKS__ */
+
+#if defined(XP_MAC) || defined(XP_MACOSX)
+	#include <Quickdraw.h>
+	#include <Events.h>
+#endif
+
+#if defined(XP_UNIX) 
+#	include <stdio.h>
+#	if defined(MOZ_X11)
+#		include <X11/Xlib.h>
+#		include <X11/Xutil.h>
+#	endif
+#endif
+
+/*----------------------------------------------------------------------*/
+/*                        Plugin Version Constants                      */
+/*----------------------------------------------------------------------*/
+
+#define NP_VERSION_MAJOR 0
+#define NP_VERSION_MINOR 16
+
+
+/* The OS/2 version of Netscape uses RC_DATA to define the
+   mime types, file extensions, etc that are required.
+   Use a vertical bar to separate types, end types with \0.
+   FileVersion and ProductVersion are 32bit ints, all other
+   entries are strings the MUST be terminated wwith a \0.
+
+AN EXAMPLE:
+
+RCDATA NP_INFO_ProductVersion { 1,0,0,1,}
+
+RCDATA NP_INFO_MIMEType    { "video/x-video|",
+                             "video/x-flick\0" }
+RCDATA NP_INFO_FileExtents { "avi|",
+                             "flc\0" }
+RCDATA NP_INFO_FileOpenName{ "MMOS2 video player(*.avi)|",
+                             "MMOS2 Flc/Fli player(*.flc)\0" }
+
+RCDATA NP_INFO_FileVersion       { 1,0,0,1 }
+RCDATA NP_INFO_CompanyName       { "Netscape Communications\0" }
+RCDATA NP_INFO_FileDescription   { "NPAVI32 Extension DLL\0"
+RCDATA NP_INFO_InternalName      { "NPAVI32\0" )
+RCDATA NP_INFO_LegalCopyright    { "Copyright Netscape Communications \251 1996\0"
+RCDATA NP_INFO_OriginalFilename  { "NVAPI32.DLL" }
+RCDATA NP_INFO_ProductName       { "NPAVI32 Dynamic Link Library\0" }
+
+*/
+
+
+/* RC_DATA types for version info - required */
+#define NP_INFO_ProductVersion      1
+#define NP_INFO_MIMEType            2
+#define NP_INFO_FileOpenName        3
+#define NP_INFO_FileExtents         4
+
+/* RC_DATA types for version info - used if found */
+#define NP_INFO_FileDescription     5
+#define NP_INFO_ProductName         6
+
+/* RC_DATA types for version info - optional */
+#define NP_INFO_CompanyName         7
+#define NP_INFO_FileVersion         8
+#define NP_INFO_InternalName        9
+#define NP_INFO_LegalCopyright      10
+#define NP_INFO_OriginalFilename    11
+
+#ifndef RC_INVOKED
+
+
+
+/*----------------------------------------------------------------------*/
+/*                       Definition of Basic Types                      */
+/*----------------------------------------------------------------------*/
+
+#ifndef _UINT16
+typedef unsigned short uint16;
+#endif
+
+#ifndef _UINT32
+#    if defined(__alpha) || defined(__amd64__) || defined(__x86_64__)
+typedef unsigned int uint32;
+#    else  /* __alpha */
+typedef unsigned long uint32;
+#    endif /* __alpha */
+#endif
+
+/*
+ * AIX defines these in sys/inttypes.h included from sys/types.h
+ */
+#ifndef AIX
+#ifndef _INT16
+typedef short int16;
+#endif
+
+#ifndef _INT32
+#    if defined(__alpha) || defined(__amd64__) || defined(__x86_64__)
+typedef int int32;
+#    else  /* __alpha */
+typedef long int32;
+#    endif /* __alpha */
+#endif
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef NULL
+#define NULL (0L)
+#endif
+
+typedef unsigned char	NPBool;
+typedef int16			NPError;
+typedef int16			NPReason;
+typedef char*			NPMIMEType;
+
+
+
+/*----------------------------------------------------------------------*/
+/*                       Structures and definitions                     */
+/*----------------------------------------------------------------------*/
+
+#ifdef XP_MAC
+#pragma options align=mac68k
+#endif
+
+/*
+ *  NPP is a plug-in's opaque instance handle
+ */
+typedef struct _NPP
+{
+  void*	pdata;      /* plug-in private data */
+  void*	ndata;      /* netscape private data */
+} NPP_t;
+
+typedef NPP_t*  NPP;
+
+
+typedef struct _NPStream
+{
+  void*  pdata; /* plug-in private data */
+  void*  ndata; /* netscape private data */
+  const  char* url;
+  uint32 end;
+  uint32 lastmodified;
+  void*  notifyData;
+} NPStream;
+
+
+typedef struct _NPByteRange
+{
+  int32  offset; /* negative offset means from the end */
+  uint32 length;
+  struct _NPByteRange* next;
+} NPByteRange;
+
+
+typedef struct _NPSavedData
+{
+  int32	len;
+  void*	buf;
+} NPSavedData;
+
+
+typedef struct _NPRect
+{
+  uint16 top;
+  uint16 left;
+  uint16 bottom;
+  uint16 right;
+} NPRect;
+
+typedef struct _NPSize 
+{ 
+  int32 width; 
+  int32 height; 
+} NPSize; 
+
+#ifdef XP_UNIX
+/*
+ * Unix specific structures and definitions
+ */
+
+/*
+ * Callback Structures.
+ *
+ * These are used to pass additional platform specific information.
+ */
+enum {
+  NP_SETWINDOW = 1,
+  NP_PRINT
+};
+
+typedef struct
+{
+  int32 type;
+} NPAnyCallbackStruct;
+
+typedef struct
+{
+  int32        type;
+#ifdef MOZ_X11
+  Display*     display;
+  Visual*      visual;
+  Colormap     colormap;
+  unsigned int depth;
+#endif
+} NPSetWindowCallbackStruct;
+
+typedef struct
+{
+  int32 type;
+  FILE* fp;
+} NPPrintCallbackStruct;
+
+#endif /* XP_UNIX */
+
+
+/*
+ *   The following masks are applied on certain platforms to NPNV and 
+ *   NPPV selectors that pass around pointers to COM interfaces. Newer 
+ *   compilers on some platforms may generate vtables that are not 
+ *   compatible with older compilers. To prevent older plugins from 
+ *   not understanding a new browser's ABI, these masks change the 
+ *   values of those selectors on those platforms. To remain backwards
+ *   compatible with differenet versions of the browser, plugins can 
+ *   use these masks to dynamically determine and use the correct C++
+ *   ABI that the browser is expecting. This does not apply to Windows 
+ *   as Microsoft's COM ABI will likely not change.
+ */
+
+#define NP_ABI_GCC3_MASK  0x10000000
+/*
+ *   gcc 3.x generated vtables on UNIX and OSX are incompatible with 
+ *   previous compilers.
+ */
+#if (defined (XP_UNIX) && defined(__GNUC__) && (__GNUC__ >= 3))
+#define _NP_ABI_MIXIN_FOR_GCC3 NP_ABI_GCC3_MASK
+#else
+#define _NP_ABI_MIXIN_FOR_GCC3 0
+#endif
+
+
+#define NP_ABI_MACHO_MASK 0x01000000
+/*
+ *   On OSX, the Mach-O executable format is significantly
+ *   different than CFM. In addition to having a different
+ *   C++ ABI, it also has has different C calling convention.
+ *   You must use glue code when calling between CFM and
+ *   Mach-O C functions. 
+ */
+#if (defined(TARGET_RT_MAC_MACHO))
+#define _NP_ABI_MIXIN_FOR_MACHO NP_ABI_MACHO_MASK
+#else
+#define _NP_ABI_MIXIN_FOR_MACHO 0
+#endif
+
+
+#define NP_ABI_MASK (_NP_ABI_MIXIN_FOR_GCC3 | _NP_ABI_MIXIN_FOR_MACHO)
+
+/*
+ * List of variable names for which NPP_GetValue shall be implemented
+ */
+typedef enum {
+  NPPVpluginNameString = 1,
+  NPPVpluginDescriptionString,
+  NPPVpluginWindowBool,
+  NPPVpluginTransparentBool,
+  NPPVjavaClass,                /* Not implemented in Mozilla 1.0 */
+  NPPVpluginWindowSize,
+  NPPVpluginTimerInterval,
+
+  NPPVpluginScriptableInstance = (10 | NP_ABI_MASK),
+  NPPVpluginScriptableIID = 11,
+
+  /* Introduced in Mozilla 0.9.9 */
+  NPPVjavascriptPushCallerBool = 12,
+
+  /* Introduced in Mozilla 1.0 */
+  NPPVpluginKeepLibraryInMemory = 13,
+  NPPVpluginNeedsXEmbed         = 14,
+
+  /* Get the NPObject for scripting the plugin. Introduced in Firefox
+   * 1.0 (NPAPI minor version 14).
+   */
+  NPPVpluginScriptableNPObject  = 15,
+
+  /* Get the plugin value (as \0-terminated UTF-8 string data) for
+   * form submission if the plugin is part of a form. Use
+   * NPN_MemAlloc() to allocate memory for the string data. Introduced
+   * in Mozilla 1.8b2 (NPAPI minor version 15).
+   */
+  NPPVformValue = 16
+} NPPVariable;
+
+/*
+ * List of variable names for which NPN_GetValue is implemented by Mozilla
+ */
+typedef enum {
+  NPNVxDisplay = 1,
+  NPNVxtAppContext,
+  NPNVnetscapeWindow,
+  NPNVjavascriptEnabledBool,
+  NPNVasdEnabledBool,
+  NPNVisOfflineBool,
+
+  /* 10 and over are available on Mozilla builds starting with 0.9.4 */
+  NPNVserviceManager = (10 | NP_ABI_MASK),
+  NPNVDOMElement     = (11 | NP_ABI_MASK),   /* available in Mozilla 1.2 */
+  NPNVDOMWindow      = (12 | NP_ABI_MASK),
+  NPNVToolkit        = (13 | NP_ABI_MASK),
+  NPNVSupportsXEmbedBool = 14,
+
+  /* Get the NPObject wrapper for the browser window. */
+  NPNVWindowNPObject = 15,
+
+  /* Get the NPObject wrapper for the plugins DOM element. */
+  NPNVPluginElementNPObject = 16
+} NPNVariable;
+
+/*
+ * The type of Tookkit the widgets use
+ */
+typedef enum {
+  NPNVGtk12 = 1,
+  NPNVGtk2
+} NPNToolkitType;
+
+/*
+ * The type of a NPWindow - it specifies the type of the data structure
+ * returned in the window field.
+ */
+typedef enum {
+  NPWindowTypeWindow = 1,
+  NPWindowTypeDrawable
+} NPWindowType;
+
+typedef struct _NPWindow
+{
+  void* window;  /* Platform specific window handle */
+                 /* OS/2: x - Position of bottom left corner  */
+                 /* OS/2: y - relative to visible netscape window */
+  int32 x;       /* Position of top left corner relative */
+  int32 y;       /* to a netscape page.					*/
+  uint32 width;  /* Maximum window size */
+  uint32 height;
+  NPRect clipRect; /* Clipping rectangle in port coordinates */
+                   /* Used by MAC only.			  */
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
+  void * ws_info; /* Platform-dependent additonal data */
+#endif /* XP_UNIX */
+  NPWindowType type; /* Is this a window or a drawable? */
+} NPWindow;
+
+
+typedef struct _NPFullPrint
+{
+  NPBool pluginPrinted;/* Set TRUE if plugin handled fullscreen printing */
+  NPBool printOne;		 /* TRUE if plugin should print one copy to default printer */
+  void* platformPrint; /* Platform-specific printing info */
+} NPFullPrint;
+
+typedef struct _NPEmbedPrint
+{
+  NPWindow window;
+  void* platformPrint; /* Platform-specific printing info */
+} NPEmbedPrint;
+
+typedef struct _NPPrint
+{
+  uint16 mode;               /* NP_FULL or NP_EMBED */
+  union
+  {
+    NPFullPrint fullPrint;   /* if mode is NP_FULL */
+    NPEmbedPrint embedPrint; /* if mode is NP_EMBED */
+  } print;
+} NPPrint;
+
+#if defined(XP_MAC) || defined(XP_MACOSX)
+typedef EventRecord	NPEvent;
+#elif defined(XP_WIN)
+typedef struct _NPEvent
+{
+  uint16 event;
+  uint32 wParam;
+  uint32 lParam;
+} NPEvent;
+#elif defined(XP_OS2)
+typedef struct _NPEvent
+{
+  uint32 event;
+  uint32 wParam;
+  uint32 lParam;
+} NPEvent;
+#elif defined (XP_UNIX) && defined(MOZ_X11)
+typedef XEvent NPEvent;
+#else
+typedef void*			NPEvent;
+#endif /* XP_MAC */
+
+#if defined(XP_MAC) || defined(XP_MACOSX)
+typedef RgnHandle NPRegion;
+#elif defined(XP_WIN)
+typedef HRGN NPRegion;
+#elif defined(XP_UNIX) && defined(MOZ_X11)
+typedef Region NPRegion;
+#else
+typedef void *NPRegion;
+#endif /* XP_MAC */
+
+#if defined(XP_MAC) || defined(XP_MACOSX)
+/*
+ *  Mac-specific structures and definitions.
+ */
+
+typedef struct NP_Port
+{
+  CGrafPtr port; /* Grafport */
+  int32 portx;   /* position inside the topmost window */
+  int32 porty;
+} NP_Port;
+
+/*
+ *  Non-standard event types that can be passed to HandleEvent
+ */
+
+enum NPEventType {
+  NPEventType_GetFocusEvent = (osEvt + 16),
+  NPEventType_LoseFocusEvent,
+  NPEventType_AdjustCursorEvent,
+  NPEventType_MenuCommandEvent,
+  NPEventType_ClippingChangedEvent,
+  NPEventType_ScrollingBeginsEvent = 1000,
+  NPEventType_ScrollingEndsEvent
+};
+
+#ifdef OBSOLETE
+#define getFocusEvent     (osEvt + 16)
+#define loseFocusEvent    (osEvt + 17)
+#define adjustCursorEvent (osEvt + 18)
+#endif
+#endif /* XP_MAC */
+
+/*
+ * Values for mode passed to NPP_New:
+ */
+#define NP_EMBED 1
+#define NP_FULL  2
+
+/*
+ * Values for stream type passed to NPP_NewStream:
+ */
+#define NP_NORMAL     1
+#define NP_SEEK       2
+#define NP_ASFILE     3
+#define NP_ASFILEONLY 4
+
+#define NP_MAXREADY	(((unsigned)(~0)<<1)>>1)
+
+#ifdef XP_MAC
+#pragma options align=reset
+#endif
+
+
+/*----------------------------------------------------------------------*/
+/*		     Error and Reason Code definitions			*/
+/*----------------------------------------------------------------------*/
+
+/*
+ * Values of type NPError:
+ */
+#define NPERR_BASE                         0
+#define NPERR_NO_ERROR                    (NPERR_BASE + 0)
+#define NPERR_GENERIC_ERROR               (NPERR_BASE + 1)
+#define NPERR_INVALID_INSTANCE_ERROR      (NPERR_BASE + 2)
+#define NPERR_INVALID_FUNCTABLE_ERROR     (NPERR_BASE + 3)
+#define NPERR_MODULE_LOAD_FAILED_ERROR    (NPERR_BASE + 4)
+#define NPERR_OUT_OF_MEMORY_ERROR         (NPERR_BASE + 5)
+#define NPERR_INVALID_PLUGIN_ERROR        (NPERR_BASE + 6)
+#define NPERR_INVALID_PLUGIN_DIR_ERROR    (NPERR_BASE + 7)
+#define NPERR_INCOMPATIBLE_VERSION_ERROR  (NPERR_BASE + 8)
+#define NPERR_INVALID_PARAM               (NPERR_BASE + 9)
+#define NPERR_INVALID_URL                 (NPERR_BASE + 10)
+#define NPERR_FILE_NOT_FOUND              (NPERR_BASE + 11)
+#define NPERR_NO_DATA                     (NPERR_BASE + 12)
+#define NPERR_STREAM_NOT_SEEKABLE         (NPERR_BASE + 13)
+
+/*
+ * Values of type NPReason:
+ */
+#define NPRES_BASE          0
+#define NPRES_DONE         (NPRES_BASE + 0)
+#define NPRES_NETWORK_ERR  (NPRES_BASE + 1)
+#define NPRES_USER_BREAK   (NPRES_BASE + 2)
+
+/*
+ * Don't use these obsolete error codes any more.
+ */
+#define NP_NOERR  NP_NOERR_is_obsolete_use_NPERR_NO_ERROR
+#define NP_EINVAL NP_EINVAL_is_obsolete_use_NPERR_GENERIC_ERROR
+#define NP_EABORT NP_EABORT_is_obsolete_use_NPRES_USER_BREAK
+
+/*
+ * Version feature information
+ */
+#define NPVERS_HAS_STREAMOUTPUT      8
+#define NPVERS_HAS_NOTIFICATION      9
+#define NPVERS_HAS_LIVECONNECT       9
+#define NPVERS_WIN16_HAS_LIVECONNECT 9
+#define NPVERS_68K_HAS_LIVECONNECT   11
+#define NPVERS_HAS_WINDOWLESS        11
+#define NPVERS_HAS_XPCONNECT_SCRIPTING 13
+
+/*----------------------------------------------------------------------*/
+/*                        Function Prototypes                           */
+/*----------------------------------------------------------------------*/
+
+#if defined(_WINDOWS) && !defined(WIN32)
+#define NP_LOADDS  _loadds
+#else
+#if defined(__OS2__)
+#define NP_LOADDS _System
+#else
+#define NP_LOADDS
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * NPP_* functions are provided by the plugin and called by the navigator.
+ */
+
+#ifdef XP_UNIX
+char* NPP_GetMIMEDescription(void);
+#endif /* XP_UNIX */
+
+NPError NP_LOADDS NPP_Initialize(void);
+void    NP_LOADDS NPP_Shutdown(void);
+NPError NP_LOADDS NPP_New(NPMIMEType pluginType, NPP instance,
+                          uint16 mode, int16 argc, char* argn[],
+                          char* argv[], NPSavedData* saved);
+NPError NP_LOADDS NPP_Destroy(NPP instance, NPSavedData** save);
+NPError NP_LOADDS NPP_SetWindow(NPP instance, NPWindow* window);
+NPError NP_LOADDS NPP_NewStream(NPP instance, NPMIMEType type,
+                                NPStream* stream, NPBool seekable,
+                                uint16* stype);
+NPError NP_LOADDS NPP_DestroyStream(NPP instance, NPStream* stream,
+                                    NPReason reason);
+int32   NP_LOADDS NPP_WriteReady(NPP instance, NPStream* stream);
+int32   NP_LOADDS NPP_Write(NPP instance, NPStream* stream, int32 offset,
+                            int32 len, void* buffer);
+void    NP_LOADDS NPP_StreamAsFile(NPP instance, NPStream* stream,
+                                   const char* fname);
+void    NP_LOADDS NPP_Print(NPP instance, NPPrint* platformPrint);
+int16   NP_LOADDS NPP_HandleEvent(NPP instance, void* event);
+void    NP_LOADDS NPP_URLNotify(NPP instance, const char* url,
+                                NPReason reason, void* notifyData);
+#ifdef OJI
+jref    NP_LOADDS NPP_GetJavaClass(void);
+#endif
+NPError NP_LOADDS NPP_GetValue(NPP instance, NPPVariable variable, void *value);
+NPError NP_LOADDS NPP_SetValue(NPP instance, NPNVariable variable, void *value);
+
+/*
+ * NPN_* functions are provided by the navigator and called by the plugin.
+ */
+void    NP_LOADDS NPN_Version(int* plugin_major, int* plugin_minor,
+                              int* netscape_major, int* netscape_minor);
+NPError NP_LOADDS NPN_GetURLNotify(NPP instance, const char* url,
+                                   const char* target, void* notifyData);
+NPError NP_LOADDS NPN_GetURL(NPP instance, const char* url,
+                             const char* target);
+NPError NP_LOADDS NPN_PostURLNotify(NPP instance, const char* url,
+                                    const char* target, uint32 len,
+                                    const char* buf, NPBool file,
+                                    void* notifyData);
+NPError NP_LOADDS NPN_PostURL(NPP instance, const char* url,
+                              const char* target, uint32 len,
+                              const char* buf, NPBool file);
+NPError NP_LOADDS NPN_RequestRead(NPStream* stream, NPByteRange* rangeList);
+NPError NP_LOADDS NPN_NewStream(NPP instance, NPMIMEType type,
+                                const char* target, NPStream** stream);
+int32   NP_LOADDS NPN_Write(NPP instance, NPStream* stream, int32 len, void* buffer);
+NPError NP_LOADDS NPN_DestroyStream(NPP instance, NPStream* stream, NPReason reason);
+void    NP_LOADDS NPN_Status(NPP instance, const char* message);
+const char* NP_LOADDS	NPN_UserAgent(NPP instance);
+void*   NP_LOADDS NPN_MemAlloc(uint32 size);
+void    NP_LOADDS NPN_MemFree(void* ptr);
+uint32  NP_LOADDS NPN_MemFlush(uint32 size);
+void    NP_LOADDS NPN_ReloadPlugins(NPBool reloadPages);
+#ifdef OJI
+JRIEnv* NP_LOADDS NPN_GetJavaEnv(void);
+jref    NP_LOADDS NPN_GetJavaPeer(NPP instance);
+#endif
+NPError NP_LOADDS NPN_GetValue(NPP instance, NPNVariable variable, void *value);
+NPError NP_LOADDS NPN_SetValue(NPP instance, NPPVariable variable, void *value);
+void    NP_LOADDS NPN_InvalidateRect(NPP instance, NPRect *invalidRect);
+void    NP_LOADDS NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion);
+void    NP_LOADDS NPN_ForceRedraw(NPP instance);
+void    NP_LOADDS NPN_PushPopupEnabledState(NPP instance, NPBool enabled);
+void    NP_LOADDS NPN_PopPopupEnabledState(NPP instance);
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif /* RC_INVOKED */
+#ifdef __OS2__
+#pragma pack()
+#endif
+
+#endif /* _NPAPI_H_ */
diff --git a/third_party/gecko/include/npruntime.h b/third_party/gecko/include/npruntime.h
index 61eb3f5..2d1dc02 100644
--- a/third_party/gecko/include/npruntime.h
+++ b/third_party/gecko/include/npruntime.h
@@ -1,397 +1,397 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/*

- * Copyright © 2004, Apple Computer, Inc. and The Mozilla Foundation. 

- * All rights reserved.

- * 

- * Redistribution and use in source and binary forms, with or without

- * modification, are permitted provided that the following conditions are

- * met:

- * 

- * 1. Redistributions of source code must retain the above copyright

- * notice, this list of conditions and the following disclaimer.

- * 2. Redistributions in binary form must reproduce the above copyright

- * notice, this list of conditions and the following disclaimer in the

- * documentation and/or other materials provided with the distribution.

- * 3. Neither the names of Apple Computer, Inc. ("Apple") or The Mozilla

- * Foundation ("Mozilla") nor the names of their contributors may be used

- * to endorse or promote products derived from this software without

- * specific prior written permission.

- * 

- * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "AS

- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED

- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A

- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, MOZILLA OR

- * THEIR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED

- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR

- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF

- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING

- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS

- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

- *

- * Revision 1 (March 4, 2004):

- * Initial proposal.

- *

- * Revision 2 (March 10, 2004):

- * All calls into script were made asynchronous.  Results are

- * provided via the NPScriptResultFunctionPtr callback.

- *

- * Revision 3 (March 10, 2004):

- * Corrected comments to not refer to class retain/release FunctionPtrs.

- *

- * Revision 4 (March 11, 2004):

- * Added additional convenience NPN_SetExceptionWithUTF8().

- * Changed NPHasPropertyFunctionPtr and NPHasMethodFunctionPtr to take NPClass

- * pointers instead of NPObject pointers.

- * Added NPIsValidIdentifier().

- *

- * Revision 5 (March 17, 2004):

- * Added context parameter to result callbacks from ScriptObject functions.

- *

- * Revision 6 (March 29, 2004):

- * Renamed functions implemented by user agent to NPN_*.  Removed _ from

- * type names.

- * Renamed "JavaScript" types to "Script".

- *

- * Revision 7 (April 21, 2004):

- * NPIdentifier becomes a void*, was int32_t

- * Remove NP_IsValidIdentifier, renamed NP_IdentifierFromUTF8 to NP_GetIdentifier

- * Added NPVariant and modified functions to use this new type.

- *

- * Revision 8 (July 9, 2004):

- * Updated to joint Apple-Mozilla license.

- *

- */

-#ifndef _NP_RUNTIME_H_

-#define _NP_RUNTIME_H_

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-#include "nptypes.h"

-

-/*

-    This API is used to facilitate binding code written in C to script

-    objects.  The API in this header does not assume the presence of a

-    user agent.  That is, it can be used to bind C code to scripting

-    environments outside of the context of a user agent.

-    

-    However, the normal use of the this API is in the context of a

-    scripting environment running in a browser or other user agent.

-    In particular it is used to support the extended Netscape

-    script-ability API for plugins (NP-SAP).  NP-SAP is an extension

-    of the Netscape plugin API.  As such we have adopted the use of

-    the "NP" prefix for this API.

-

-    The following NP{N|P}Variables were added to the Netscape plugin

-    API (in npapi.h):

-

-    NPNVWindowNPObject

-    NPNVPluginElementNPObject

-    NPPVpluginScriptableNPObject

-

-    These variables are exposed through NPN_GetValue() and

-    NPP_GetValue() (respectively) and are used to establish the

-    initial binding between the user agent and native code.  The DOM

-    objects in the user agent can be examined and manipulated using

-    the NPN_ functions that operate on NPObjects described in this

-    header.

-

-    To the extent possible the assumptions about the scripting

-    language used by the scripting environment have been minimized.

-*/

-

-#define NP_BEGIN_MACRO  do {

-#define NP_END_MACRO    } while (0)

-

-/*

-    Objects (non-primitive data) passed between 'C' and script is

-    always wrapped in an NPObject.  The 'interface' of an NPObject is

-    described by an NPClass.

-*/

-typedef struct NPObject NPObject;

-typedef struct NPClass NPClass;

-

-typedef char NPUTF8;

-typedef struct _NPString {

-    const NPUTF8 *utf8characters;

-    uint32_t utf8length;

-} NPString;

-

-typedef enum {

-    NPVariantType_Void,

-    NPVariantType_Null,

-    NPVariantType_Bool,

-    NPVariantType_Int32,

-    NPVariantType_Double,

-    NPVariantType_String,

-    NPVariantType_Object

-} NPVariantType;

-

-typedef struct _NPVariant {

-    NPVariantType type;

-    union {

-        bool boolValue;

-        uint32_t intValue;

-        double doubleValue;

-        NPString stringValue;

-        NPObject *objectValue;

-    } value;

-} NPVariant;

-

-/*

-    NPN_ReleaseVariantValue is called on all 'out' parameters

-    references.  Specifically it is to be called on variants that own

-    their value, as is the case with all non-const NPVariant*

-    arguments after a successful call to any methods (except this one)

-    in this API.

-

-    After calling NPN_ReleaseVariantValue, the type of the variant

-    will be NPVariantType_Void.

-*/

-void NPN_ReleaseVariantValue(NPVariant *variant);

-

-#define NPVARIANT_IS_VOID(_v)    ((_v).type == NPVariantType_Void)

-#define NPVARIANT_IS_NULL(_v)    ((_v).type == NPVariantType_Null)

-#define NPVARIANT_IS_BOOLEAN(_v) ((_v).type == NPVariantType_Bool)

-#define NPVARIANT_IS_INT32(_v)   ((_v).type == NPVariantType_Int32)

-#define NPVARIANT_IS_DOUBLE(_v)  ((_v).type == NPVariantType_Double)

-#define NPVARIANT_IS_STRING(_v)  ((_v).type == NPVariantType_String)

-#define NPVARIANT_IS_OBJECT(_v)  ((_v).type == NPVariantType_Object)

-

-#define NPVARIANT_TO_BOOLEAN(_v) ((_v).value.boolValue)

-#define NPVARIANT_TO_INT32(_v)   ((_v).value.intValue)

-#define NPVARIANT_TO_DOUBLE(_v)  ((_v).value.doubleValue)

-#define NPVARIANT_TO_STRING(_v)  ((_v).value.stringValue)

-#define NPVARIANT_TO_OBJECT(_v)  ((_v).value.objectValue)

-

-#define VOID_TO_NPVARIANT(_v)                                                 \

-NP_BEGIN_MACRO                                                                \

-    (_v).type = NPVariantType_Void;                                           \

-    (_v).value.objectValue = NULL;                                            \

-NP_END_MACRO

-

-#define NULL_TO_NPVARIANT(_v)                                                 \

-NP_BEGIN_MACRO                                                                \

-    (_v).type = NPVariantType_Null;                                           \

-    (_v).value.objectValue = NULL;                                            \

-NP_END_MACRO

-

-#define BOOLEAN_TO_NPVARIANT(_val, _v)                                        \

-NP_BEGIN_MACRO                                                                \

-    (_v).type = NPVariantType_Bool;                                           \

-    (_v).value.boolValue = !!(_val);                                          \

-NP_END_MACRO

-

-#define INT32_TO_NPVARIANT(_val, _v)                                          \

-NP_BEGIN_MACRO                                                                \

-    (_v).type = NPVariantType_Int32;                                          \

-    (_v).value.intValue = _val;                                               \

-NP_END_MACRO

-

-#define DOUBLE_TO_NPVARIANT(_val, _v)                                         \

-NP_BEGIN_MACRO                                                                \

-    (_v).type = NPVariantType_Double;                                         \

-    (_v).value.doubleValue = _val;                                            \

-NP_END_MACRO

-

-#define STRINGZ_TO_NPVARIANT(_val, _v)                                        \

-NP_BEGIN_MACRO                                                                \

-    (_v).type = NPVariantType_String;                                         \

-    NPString str = { _val, strlen(_val) };                                    \

-    (_v).value.stringValue = str;                                             \

-NP_END_MACRO

-

-#define STRINGN_TO_NPVARIANT(_val, _len, _v)                                  \

-NP_BEGIN_MACRO                                                                \

-    (_v).type = NPVariantType_String;                                         \

-    NPString str = { _val, _len };                                            \

-    (_v).value.stringValue = str;                                             \

-NP_END_MACRO

-

-#define OBJECT_TO_NPVARIANT(_val, _v)                                         \

-NP_BEGIN_MACRO                                                                \

-    (_v).type = NPVariantType_Object;                                         \

-    (_v).value.objectValue = _val;                                            \

-NP_END_MACRO

-

-

-/*

-	Type mappings (JavaScript types have been used for illustration

-    purposes):

-

-	JavaScript       to             C (NPVariant with type:)

-	undefined                       NPVariantType_Void

-	null                            NPVariantType_Null

-	Boolean                         NPVariantType_Bool

-	Number                          NPVariantType_Double or NPVariantType_Int32

-	String                          NPVariantType_String

-	Object                          NPVariantType_Object

-

-	C (NPVariant with type:)   to   JavaScript

-	NPVariantType_Void              undefined

-	NPVariantType_Null              null

-	NPVariantType_Bool              Boolean	

-	NPVariantType_Int32             Number

-	NPVariantType_Double            Number

-	NPVariantType_String            String

-	NPVariantType_Object            Object

-*/

-

-typedef void *NPIdentifier;

-

-/*

-    NPObjects have methods and properties.  Methods and properties are

-    identified with NPIdentifiers.  These identifiers may be reflected

-    in script.  NPIdentifiers can be either strings or integers, IOW,

-    methods and properties can be identified by either strings or

-    integers (i.e. foo["bar"] vs foo[1]). NPIdentifiers can be

-    compared using ==.  In case of any errors, the requested

-    NPIdentifier(s) will be NULL.

-*/

-NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name);

-void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount,

-                              NPIdentifier *identifiers);

-NPIdentifier NPN_GetIntIdentifier(int32_t intid);

-bool NPN_IdentifierIsString(NPIdentifier identifier);

-

-/*

-    The NPUTF8 returned from NPN_UTF8FromIdentifier SHOULD be freed.

-*/

-NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier);

-

-/*

-    Get the integer represented by identifier. If identifier is not an

-    integer identifier, the behaviour is undefined.

-*/

-int32_t NPN_IntFromIdentifier(NPIdentifier identifier);

-

-/*

-    NPObject behavior is implemented using the following set of

-    callback functions.

-

-    The NPVariant *result argument of these functions (where

-    applicable) should be released using NPN_ReleaseVariantValue().

-*/

-typedef NPObject *(*NPAllocateFunctionPtr)(NPP npp, NPClass *aClass);

-typedef void (*NPDeallocateFunctionPtr)(NPObject *npobj);

-typedef void (*NPInvalidateFunctionPtr)(NPObject *npobj);

-typedef bool (*NPHasMethodFunctionPtr)(NPObject *npobj, NPIdentifier name);

-typedef bool (*NPInvokeFunctionPtr)(NPObject *npobj, NPIdentifier name,

-                                    const NPVariant *args, uint32_t argCount,

-                                    NPVariant *result);

-typedef bool (*NPInvokeDefaultFunctionPtr)(NPObject *npobj,

-                                           const NPVariant *args,

-                                           uint32_t argCount,

-                                           NPVariant *result);

-typedef bool (*NPHasPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name);

-typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,

-                                         NPVariant *result);

-typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,

-                                         const NPVariant *value);

-typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj,

-                                            NPIdentifier name);

-

-/*

-    NPObjects returned by create, retain, invoke, and getProperty pass

-    a reference count to the caller.  That is, the callee adds a

-    reference count which passes to the caller.  It is the caller's

-    responsibility to release the returned object.

-

-    NPInvokeFunctionPtr function may return 0 to indicate a void

-    result.

-

-    NPInvalidateFunctionPtr is called by the scripting environment

-    when the native code is shutdown.  Any attempt to message a

-    NPObject instance after the invalidate callback has been

-    called will result in undefined behavior, even if the native code

-    is still retaining those NPObject instances.  (The runtime

-    will typically return immediately, with 0 or NULL, from an attempt

-    to dispatch to a NPObject, but this behavior should not be

-    depended upon.)

-*/

-struct NPClass

-{

-    uint32_t structVersion;

-    NPAllocateFunctionPtr allocate;

-    NPDeallocateFunctionPtr deallocate;

-    NPInvalidateFunctionPtr invalidate;

-    NPHasMethodFunctionPtr hasMethod;

-    NPInvokeFunctionPtr invoke;

-    NPInvokeDefaultFunctionPtr invokeDefault;

-    NPHasPropertyFunctionPtr hasProperty;

-    NPGetPropertyFunctionPtr getProperty;

-    NPSetPropertyFunctionPtr setProperty;

-    NPRemovePropertyFunctionPtr removeProperty;

-};

-

-#define NP_CLASS_STRUCT_VERSION 1

-

-struct NPObject {

-    NPClass *_class;

-    uint32_t referenceCount;

-    /*

-     * Additional space may be allocated here by types of NPObjects

-     */

-};

-

-/*

-    If the class has an allocate function, NPN_CreateObject invokes

-    that function, otherwise a NPObject is allocated and

-    returned. This method will initialize the referenceCount member of

-    the NPObject to 1.

-*/

-NPObject *NPN_CreateObject(NPP npp, NPClass *aClass);

-

-/*

-    Increment the NPObject's reference count.

-*/

-NPObject *NPN_RetainObject(NPObject *npobj);

-

-/*

-    Decremented the NPObject's reference count.  If the reference

-    count goes to zero, the class's destroy function is invoke if

-    specified, otherwise the object is freed directly.

-*/

-void NPN_ReleaseObject(NPObject *npobj);

-

-/*

-    Functions to access script objects represented by NPObject.

-

-    Calls to script objects are synchronous.  If a function returns a

-    value, it will be supplied via the result NPVariant

-    argument. Successful calls will return true, false will be

-    returned in case of an error.

-    

-    Calls made from plugin code to script must be made from the thread

-    on which the plugin was initialized.

-*/

-

-bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName,

-                const NPVariant *args, uint32_t argCount, NPVariant *result);

-bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args,

-                       uint32_t argCount, NPVariant *result);

-bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script,

-                  NPVariant *result);

-bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,

-                     NPVariant *result);

-bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,

-                     const NPVariant *value);

-bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);

-bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);

-bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName);

-

-/*

-    NPN_SetException may be called to trigger a script exception upon

-    return from entry points into NPObjects.  Typical usage:

-

-    NPN_SetException (npobj, message);

-*/

-void NPN_SetException(NPObject *npobj, const NPUTF8 *message);

-

-#ifdef __cplusplus

-}

-#endif

-

-#endif

+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * Copyright © 2004, Apple Computer, Inc. and The Mozilla Foundation. 
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of Apple Computer, Inc. ("Apple") or The Mozilla
+ * Foundation ("Mozilla") nor the names of their contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE, MOZILLA OR
+ * THEIR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Revision 1 (March 4, 2004):
+ * Initial proposal.
+ *
+ * Revision 2 (March 10, 2004):
+ * All calls into script were made asynchronous.  Results are
+ * provided via the NPScriptResultFunctionPtr callback.
+ *
+ * Revision 3 (March 10, 2004):
+ * Corrected comments to not refer to class retain/release FunctionPtrs.
+ *
+ * Revision 4 (March 11, 2004):
+ * Added additional convenience NPN_SetExceptionWithUTF8().
+ * Changed NPHasPropertyFunctionPtr and NPHasMethodFunctionPtr to take NPClass
+ * pointers instead of NPObject pointers.
+ * Added NPIsValidIdentifier().
+ *
+ * Revision 5 (March 17, 2004):
+ * Added context parameter to result callbacks from ScriptObject functions.
+ *
+ * Revision 6 (March 29, 2004):
+ * Renamed functions implemented by user agent to NPN_*.  Removed _ from
+ * type names.
+ * Renamed "JavaScript" types to "Script".
+ *
+ * Revision 7 (April 21, 2004):
+ * NPIdentifier becomes a void*, was int32_t
+ * Remove NP_IsValidIdentifier, renamed NP_IdentifierFromUTF8 to NP_GetIdentifier
+ * Added NPVariant and modified functions to use this new type.
+ *
+ * Revision 8 (July 9, 2004):
+ * Updated to joint Apple-Mozilla license.
+ *
+ */
+#ifndef _NP_RUNTIME_H_
+#define _NP_RUNTIME_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "nptypes.h"
+
+/*
+    This API is used to facilitate binding code written in C to script
+    objects.  The API in this header does not assume the presence of a
+    user agent.  That is, it can be used to bind C code to scripting
+    environments outside of the context of a user agent.
+    
+    However, the normal use of the this API is in the context of a
+    scripting environment running in a browser or other user agent.
+    In particular it is used to support the extended Netscape
+    script-ability API for plugins (NP-SAP).  NP-SAP is an extension
+    of the Netscape plugin API.  As such we have adopted the use of
+    the "NP" prefix for this API.
+
+    The following NP{N|P}Variables were added to the Netscape plugin
+    API (in npapi.h):
+
+    NPNVWindowNPObject
+    NPNVPluginElementNPObject
+    NPPVpluginScriptableNPObject
+
+    These variables are exposed through NPN_GetValue() and
+    NPP_GetValue() (respectively) and are used to establish the
+    initial binding between the user agent and native code.  The DOM
+    objects in the user agent can be examined and manipulated using
+    the NPN_ functions that operate on NPObjects described in this
+    header.
+
+    To the extent possible the assumptions about the scripting
+    language used by the scripting environment have been minimized.
+*/
+
+#define NP_BEGIN_MACRO  do {
+#define NP_END_MACRO    } while (0)
+
+/*
+    Objects (non-primitive data) passed between 'C' and script is
+    always wrapped in an NPObject.  The 'interface' of an NPObject is
+    described by an NPClass.
+*/
+typedef struct NPObject NPObject;
+typedef struct NPClass NPClass;
+
+typedef char NPUTF8;
+typedef struct _NPString {
+    const NPUTF8 *utf8characters;
+    uint32_t utf8length;
+} NPString;
+
+typedef enum {
+    NPVariantType_Void,
+    NPVariantType_Null,
+    NPVariantType_Bool,
+    NPVariantType_Int32,
+    NPVariantType_Double,
+    NPVariantType_String,
+    NPVariantType_Object
+} NPVariantType;
+
+typedef struct _NPVariant {
+    NPVariantType type;
+    union {
+        bool boolValue;
+        uint32_t intValue;
+        double doubleValue;
+        NPString stringValue;
+        NPObject *objectValue;
+    } value;
+} NPVariant;
+
+/*
+    NPN_ReleaseVariantValue is called on all 'out' parameters
+    references.  Specifically it is to be called on variants that own
+    their value, as is the case with all non-const NPVariant*
+    arguments after a successful call to any methods (except this one)
+    in this API.
+
+    After calling NPN_ReleaseVariantValue, the type of the variant
+    will be NPVariantType_Void.
+*/
+void NPN_ReleaseVariantValue(NPVariant *variant);
+
+#define NPVARIANT_IS_VOID(_v)    ((_v).type == NPVariantType_Void)
+#define NPVARIANT_IS_NULL(_v)    ((_v).type == NPVariantType_Null)
+#define NPVARIANT_IS_BOOLEAN(_v) ((_v).type == NPVariantType_Bool)
+#define NPVARIANT_IS_INT32(_v)   ((_v).type == NPVariantType_Int32)
+#define NPVARIANT_IS_DOUBLE(_v)  ((_v).type == NPVariantType_Double)
+#define NPVARIANT_IS_STRING(_v)  ((_v).type == NPVariantType_String)
+#define NPVARIANT_IS_OBJECT(_v)  ((_v).type == NPVariantType_Object)
+
+#define NPVARIANT_TO_BOOLEAN(_v) ((_v).value.boolValue)
+#define NPVARIANT_TO_INT32(_v)   ((_v).value.intValue)
+#define NPVARIANT_TO_DOUBLE(_v)  ((_v).value.doubleValue)
+#define NPVARIANT_TO_STRING(_v)  ((_v).value.stringValue)
+#define NPVARIANT_TO_OBJECT(_v)  ((_v).value.objectValue)
+
+#define VOID_TO_NPVARIANT(_v)                                                 \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Void;                                           \
+    (_v).value.objectValue = NULL;                                            \
+NP_END_MACRO
+
+#define NULL_TO_NPVARIANT(_v)                                                 \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Null;                                           \
+    (_v).value.objectValue = NULL;                                            \
+NP_END_MACRO
+
+#define BOOLEAN_TO_NPVARIANT(_val, _v)                                        \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Bool;                                           \
+    (_v).value.boolValue = !!(_val);                                          \
+NP_END_MACRO
+
+#define INT32_TO_NPVARIANT(_val, _v)                                          \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Int32;                                          \
+    (_v).value.intValue = _val;                                               \
+NP_END_MACRO
+
+#define DOUBLE_TO_NPVARIANT(_val, _v)                                         \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Double;                                         \
+    (_v).value.doubleValue = _val;                                            \
+NP_END_MACRO
+
+#define STRINGZ_TO_NPVARIANT(_val, _v)                                        \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_String;                                         \
+    NPString str = { _val, strlen(_val) };                                    \
+    (_v).value.stringValue = str;                                             \
+NP_END_MACRO
+
+#define STRINGN_TO_NPVARIANT(_val, _len, _v)                                  \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_String;                                         \
+    NPString str = { _val, _len };                                            \
+    (_v).value.stringValue = str;                                             \
+NP_END_MACRO
+
+#define OBJECT_TO_NPVARIANT(_val, _v)                                         \
+NP_BEGIN_MACRO                                                                \
+    (_v).type = NPVariantType_Object;                                         \
+    (_v).value.objectValue = _val;                                            \
+NP_END_MACRO
+
+
+/*
+	Type mappings (JavaScript types have been used for illustration
+    purposes):
+
+	JavaScript       to             C (NPVariant with type:)
+	undefined                       NPVariantType_Void
+	null                            NPVariantType_Null
+	Boolean                         NPVariantType_Bool
+	Number                          NPVariantType_Double or NPVariantType_Int32
+	String                          NPVariantType_String
+	Object                          NPVariantType_Object
+
+	C (NPVariant with type:)   to   JavaScript
+	NPVariantType_Void              undefined
+	NPVariantType_Null              null
+	NPVariantType_Bool              Boolean	
+	NPVariantType_Int32             Number
+	NPVariantType_Double            Number
+	NPVariantType_String            String
+	NPVariantType_Object            Object
+*/
+
+typedef void *NPIdentifier;
+
+/*
+    NPObjects have methods and properties.  Methods and properties are
+    identified with NPIdentifiers.  These identifiers may be reflected
+    in script.  NPIdentifiers can be either strings or integers, IOW,
+    methods and properties can be identified by either strings or
+    integers (i.e. foo["bar"] vs foo[1]). NPIdentifiers can be
+    compared using ==.  In case of any errors, the requested
+    NPIdentifier(s) will be NULL.
+*/
+NPIdentifier NPN_GetStringIdentifier(const NPUTF8 *name);
+void NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount,
+                              NPIdentifier *identifiers);
+NPIdentifier NPN_GetIntIdentifier(int32_t intid);
+bool NPN_IdentifierIsString(NPIdentifier identifier);
+
+/*
+    The NPUTF8 returned from NPN_UTF8FromIdentifier SHOULD be freed.
+*/
+NPUTF8 *NPN_UTF8FromIdentifier(NPIdentifier identifier);
+
+/*
+    Get the integer represented by identifier. If identifier is not an
+    integer identifier, the behaviour is undefined.
+*/
+int32_t NPN_IntFromIdentifier(NPIdentifier identifier);
+
+/*
+    NPObject behavior is implemented using the following set of
+    callback functions.
+
+    The NPVariant *result argument of these functions (where
+    applicable) should be released using NPN_ReleaseVariantValue().
+*/
+typedef NPObject *(*NPAllocateFunctionPtr)(NPP npp, NPClass *aClass);
+typedef void (*NPDeallocateFunctionPtr)(NPObject *npobj);
+typedef void (*NPInvalidateFunctionPtr)(NPObject *npobj);
+typedef bool (*NPHasMethodFunctionPtr)(NPObject *npobj, NPIdentifier name);
+typedef bool (*NPInvokeFunctionPtr)(NPObject *npobj, NPIdentifier name,
+                                    const NPVariant *args, uint32_t argCount,
+                                    NPVariant *result);
+typedef bool (*NPInvokeDefaultFunctionPtr)(NPObject *npobj,
+                                           const NPVariant *args,
+                                           uint32_t argCount,
+                                           NPVariant *result);
+typedef bool (*NPHasPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name);
+typedef bool (*NPGetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
+                                         NPVariant *result);
+typedef bool (*NPSetPropertyFunctionPtr)(NPObject *npobj, NPIdentifier name,
+                                         const NPVariant *value);
+typedef bool (*NPRemovePropertyFunctionPtr)(NPObject *npobj,
+                                            NPIdentifier name);
+
+/*
+    NPObjects returned by create, retain, invoke, and getProperty pass
+    a reference count to the caller.  That is, the callee adds a
+    reference count which passes to the caller.  It is the caller's
+    responsibility to release the returned object.
+
+    NPInvokeFunctionPtr function may return 0 to indicate a void
+    result.
+
+    NPInvalidateFunctionPtr is called by the scripting environment
+    when the native code is shutdown.  Any attempt to message a
+    NPObject instance after the invalidate callback has been
+    called will result in undefined behavior, even if the native code
+    is still retaining those NPObject instances.  (The runtime
+    will typically return immediately, with 0 or NULL, from an attempt
+    to dispatch to a NPObject, but this behavior should not be
+    depended upon.)
+*/
+struct NPClass
+{
+    uint32_t structVersion;
+    NPAllocateFunctionPtr allocate;
+    NPDeallocateFunctionPtr deallocate;
+    NPInvalidateFunctionPtr invalidate;
+    NPHasMethodFunctionPtr hasMethod;
+    NPInvokeFunctionPtr invoke;
+    NPInvokeDefaultFunctionPtr invokeDefault;
+    NPHasPropertyFunctionPtr hasProperty;
+    NPGetPropertyFunctionPtr getProperty;
+    NPSetPropertyFunctionPtr setProperty;
+    NPRemovePropertyFunctionPtr removeProperty;
+};
+
+#define NP_CLASS_STRUCT_VERSION 1
+
+struct NPObject {
+    NPClass *_class;
+    uint32_t referenceCount;
+    /*
+     * Additional space may be allocated here by types of NPObjects
+     */
+};
+
+/*
+    If the class has an allocate function, NPN_CreateObject invokes
+    that function, otherwise a NPObject is allocated and
+    returned. This method will initialize the referenceCount member of
+    the NPObject to 1.
+*/
+NPObject *NPN_CreateObject(NPP npp, NPClass *aClass);
+
+/*
+    Increment the NPObject's reference count.
+*/
+NPObject *NPN_RetainObject(NPObject *npobj);
+
+/*
+    Decremented the NPObject's reference count.  If the reference
+    count goes to zero, the class's destroy function is invoke if
+    specified, otherwise the object is freed directly.
+*/
+void NPN_ReleaseObject(NPObject *npobj);
+
+/*
+    Functions to access script objects represented by NPObject.
+
+    Calls to script objects are synchronous.  If a function returns a
+    value, it will be supplied via the result NPVariant
+    argument. Successful calls will return true, false will be
+    returned in case of an error.
+    
+    Calls made from plugin code to script must be made from the thread
+    on which the plugin was initialized.
+*/
+
+bool NPN_Invoke(NPP npp, NPObject *npobj, NPIdentifier methodName,
+                const NPVariant *args, uint32_t argCount, NPVariant *result);
+bool NPN_InvokeDefault(NPP npp, NPObject *npobj, const NPVariant *args,
+                       uint32_t argCount, NPVariant *result);
+bool NPN_Evaluate(NPP npp, NPObject *npobj, NPString *script,
+                  NPVariant *result);
+bool NPN_GetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
+                     NPVariant *result);
+bool NPN_SetProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName,
+                     const NPVariant *value);
+bool NPN_RemoveProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
+bool NPN_HasProperty(NPP npp, NPObject *npobj, NPIdentifier propertyName);
+bool NPN_HasMethod(NPP npp, NPObject *npobj, NPIdentifier methodName);
+
+/*
+    NPN_SetException may be called to trigger a script exception upon
+    return from entry points into NPObjects.  Typical usage:
+
+    NPN_SetException (npobj, message);
+*/
+void NPN_SetException(NPObject *npobj, const NPUTF8 *message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/gecko/include/nptypes.h b/third_party/gecko/include/nptypes.h
index 4d4e7e0..a05d395 100644
--- a/third_party/gecko/include/nptypes.h
+++ b/third_party/gecko/include/nptypes.h
@@ -1,105 +1,105 @@
-/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * mozilla.org.

- * Portions created by the Initial Developer are Copyright (C) 2004

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   Johnny Stenback <jst@mozilla.org> (Original author)

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/*

- * Header file for ensuring that C99 types ([u]int32_t and bool) are

- * available.

- */

-

-#if defined(WIN32) || defined(OS2)

-  /*

-   * Win32 and OS/2 don't know C99, so define [u]int_32 here. The bool

-   * is predefined tho, both in C and C++.

-   */

-  typedef int int32_t;

-  typedef unsigned int uint32_t;

-#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX)

-  /*

-   * AIX and SunOS ship a inttypes.h header that defines [u]int32_t,

-   * but not bool for C.

-   */

-  #include <inttypes.h>

-

-  #ifndef __cplusplus

-    typedef int bool;

-  #endif

-#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD)

-  /*

-   * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and 

-   * u_int32_t.

-   */

-  #include <sys/types.h>

-

-  /*

-   * BSD/OS ships no header that defines uint32_t, nor bool (for C)

-   * OpenBSD ships no header that defines uint32_t and using its bool macro is

-   * unsafe.

-   */

-  #if defined(bsdi) || defined(OPENBSD)

-  typedef u_int32_t uint32_t;

-

-  #if !defined(__cplusplus)

-    typedef int bool;

-  #endif

-  #else

-  /*

-   * FreeBSD defines uint32_t and bool.

-   */

-    #include <inttypes.h>

-    #include <stdbool.h>

-  #endif

-#elif defined(BEOS)

-  #include <inttypes.h>

-#else

-  /*

-   * For those that ship a standard C99 stdint.h header file, include

-   * it. Can't do the same for stdbool.h tho, since some systems ship

-   * with a stdbool.h file that doesn't compile!

-   */

-  #include <stdint.h>

-

-  #if !defined(__GNUC__) || (__GNUC__ > 2 || __GNUC_MINOR__ > 95)

-    #include <stdbool.h>

-  #else

-    /*

-     * GCC 2.91 can't deal with a typedef for bool, but a #define

-     * works.

-     */

-    #define bool int

-  #endif

-#endif

+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * mozilla.org.
+ * Portions created by the Initial Developer are Copyright (C) 2004
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Johnny Stenback <jst@mozilla.org> (Original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Header file for ensuring that C99 types ([u]int32_t and bool) are
+ * available.
+ */
+
+#if defined(WIN32) || defined(OS2)
+  /*
+   * Win32 and OS/2 don't know C99, so define [u]int_32 here. The bool
+   * is predefined tho, both in C and C++.
+   */
+  typedef int int32_t;
+  typedef unsigned int uint32_t;
+#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX)
+  /*
+   * AIX and SunOS ship a inttypes.h header that defines [u]int32_t,
+   * but not bool for C.
+   */
+  #include <inttypes.h>
+
+  #ifndef __cplusplus
+    typedef int bool;
+  #endif
+#elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD)
+  /*
+   * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and 
+   * u_int32_t.
+   */
+  #include <sys/types.h>
+
+  /*
+   * BSD/OS ships no header that defines uint32_t, nor bool (for C)
+   * OpenBSD ships no header that defines uint32_t and using its bool macro is
+   * unsafe.
+   */
+  #if defined(bsdi) || defined(OPENBSD)
+  typedef u_int32_t uint32_t;
+
+  #if !defined(__cplusplus)
+    typedef int bool;
+  #endif
+  #else
+  /*
+   * FreeBSD defines uint32_t and bool.
+   */
+    #include <inttypes.h>
+    #include <stdbool.h>
+  #endif
+#elif defined(BEOS)
+  #include <inttypes.h>
+#else
+  /*
+   * For those that ship a standard C99 stdint.h header file, include
+   * it. Can't do the same for stdbool.h tho, since some systems ship
+   * with a stdbool.h file that doesn't compile!
+   */
+  #include <stdint.h>
+
+  #if !defined(__GNUC__) || (__GNUC__ > 2 || __GNUC_MINOR__ > 95)
+    #include <stdbool.h>
+  #else
+    /*
+     * GCC 2.91 can't deal with a typedef for bool, but a #define
+     * works.
+     */
+    #define bool int
+  #endif
+#endif
diff --git a/third_party/gecko/include/npupp.h b/third_party/gecko/include/npupp.h
index af455ff..f7e8e5d 100644
--- a/third_party/gecko/include/npupp.h
+++ b/third_party/gecko/include/npupp.h
@@ -1,1889 +1,1889 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-

-/*

- *  npupp.h $Revision: 3.20 $

- *  function call mecahnics needed by platform specific glue code.

- */

-

-

-#ifndef _NPUPP_H_

-#define _NPUPP_H_

-

-#if defined(__OS2__)

-#pragma pack(1)

-#endif

-

-#ifndef GENERATINGCFM

-#define GENERATINGCFM 0

-#endif

-

-#ifndef _NPAPI_H_

-#include "npapi.h"

-#endif

-

-#include "npruntime.h"

-

-#include "jri.h"

-

-/******************************************************************************************

-   plug-in function table macros

- 	        for each function in and out of the plugin API we define

-                    typedef NPP_FooUPP

-					#define NewNPP_FooProc

-					#define CallNPP_FooProc

-			for mac, define the UPP magic for PPC/68K calling

- *******************************************************************************************/

-

-

-/* NPP_Initialize */

-

-#define _NPUPP_USE_UPP_ (TARGET_RT_MAC_CFM && !TARGET_API_MAC_CARBON)

-

-#if _NPUPP_USE_UPP_

-typedef UniversalProcPtr NPP_InitializeUPP;

-

-enum {

-	uppNPP_InitializeProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(0))		

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPP_InitializeProc(FUNC)		\

-		(NPP_InitializeUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_InitializeProcInfo, GetCurrentArchitecture())

-#define CallNPP_InitializeProc(FUNC)		\

-		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_InitializeProcInfo)

-		

-#else

-

-typedef void (* NP_LOADDS NPP_InitializeUPP)(void);

-#define NewNPP_InitializeProc(FUNC)		\

-		((NPP_InitializeUPP) (FUNC))

-#define CallNPP_InitializeProc(FUNC)		\

-		(*(FUNC))()

-

-#endif

-

-

-/* NPP_Shutdown */

-

-#if _NPUPP_USE_UPP_

-typedef UniversalProcPtr NPP_ShutdownUPP;

-

-enum {

-	uppNPP_ShutdownProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(0))		

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPP_ShutdownProc(FUNC)		\

-		(NPP_ShutdownUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_ShutdownProcInfo, GetCurrentArchitecture())

-#define CallNPP_ShutdownProc(FUNC)		\

-		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_ShutdownProcInfo)

-		

-#else

-

-typedef void (* NP_LOADDS NPP_ShutdownUPP)(void);

-#define NewNPP_ShutdownProc(FUNC)		\

-		((NPP_ShutdownUPP) (FUNC))

-#define CallNPP_ShutdownProc(FUNC)		\

-		(*(FUNC))()

-

-#endif

-

-

-/* NPP_New */

-

-#if _NPUPP_USE_UPP_

-typedef UniversalProcPtr NPP_NewUPP;

-

-enum {

-	uppNPP_NewProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPMIMEType)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(uint16)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(int16)))

-		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char **)))

-		| STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(char **)))

-		| STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(NPSavedData *)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-

-#define NewNPP_NewProc(FUNC)		\

-		(NPP_NewUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_NewProcInfo, GetCurrentArchitecture())

-#define CallNPP_NewProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_NewProcInfo, \

-								   (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7))

-#else

-

-typedef NPError	(* NP_LOADDS NPP_NewUPP)(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved);

-#define NewNPP_NewProc(FUNC)		\

-		((NPP_NewUPP) (FUNC))

-#define CallNPP_NewProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7))

-

-#endif

-

-

-/* NPP_Destroy */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_DestroyUPP;

-enum {

-	uppNPP_DestroyProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPSavedData **)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPP_DestroyProc(FUNC)		\

-		(NPP_DestroyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_DestroyProcInfo, GetCurrentArchitecture())

-#define CallNPP_DestroyProc(FUNC, ARG1, ARG2)		\

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_DestroyProcInfo, (ARG1), (ARG2))

-#else

-

-typedef NPError	(* NP_LOADDS NPP_DestroyUPP)(NPP instance, NPSavedData** save);

-#define NewNPP_DestroyProc(FUNC)		\

-		((NPP_DestroyUPP) (FUNC))

-#define CallNPP_DestroyProc(FUNC, ARG1, ARG2)		\

-		(*(FUNC))((ARG1), (ARG2))

-

-#endif

-

-

-/* NPP_SetWindow */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_SetWindowUPP;

-enum {

-	uppNPP_SetWindowProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPWindow *)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPP_SetWindowProc(FUNC)		\

-		(NPP_SetWindowUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_SetWindowProcInfo, GetCurrentArchitecture())

-#define CallNPP_SetWindowProc(FUNC, ARG1, ARG2)		\

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_SetWindowProcInfo, (ARG1), (ARG2))

-

-#else

-

-typedef NPError	(* NP_LOADDS NPP_SetWindowUPP)(NPP instance, NPWindow* window);

-#define NewNPP_SetWindowProc(FUNC)		\

-		((NPP_SetWindowUPP) (FUNC))

-#define CallNPP_SetWindowProc(FUNC, ARG1, ARG2)		\

-		(*(FUNC))((ARG1), (ARG2))

-

-#endif

-

-

-/* NPP_NewStream */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_NewStreamUPP;

-enum {

-	uppNPP_NewStreamProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPMIMEType)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPStream *)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPBool)))

-		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(uint16 *)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPP_NewStreamProc(FUNC)		\

-		(NPP_NewStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_NewStreamProcInfo, GetCurrentArchitecture())

-#define CallNPP_NewStreamProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5)		\

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_NewStreamProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5))

-#else

-

-typedef NPError	(* NP_LOADDS NPP_NewStreamUPP)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype);

-#define NewNPP_NewStreamProc(FUNC)		\

-		((NPP_NewStreamUPP) (FUNC))

-#define CallNPP_NewStreamProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5))

-#endif

-

-

-/* NPP_DestroyStream */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_DestroyStreamUPP;

-enum {

-	uppNPP_DestroyStreamProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPReason)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPP_DestroyStreamProc(FUNC)		\

-		(NPP_DestroyStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_DestroyStreamProcInfo, GetCurrentArchitecture())

-#define CallNPP_DestroyStreamProc(FUNC,  NPParg, NPStreamPtr, NPReasonArg)		\

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_DestroyStreamProcInfo, (NPParg), (NPStreamPtr), (NPReasonArg))

-

-#else

-

-typedef NPError	(* NP_LOADDS NPP_DestroyStreamUPP)(NPP instance, NPStream* stream, NPReason reason);

-#define NewNPP_DestroyStreamProc(FUNC)		\

-		((NPP_DestroyStreamUPP) (FUNC))

-#define CallNPP_DestroyStreamProc(FUNC,  NPParg, NPStreamPtr, NPReasonArg)		\

-		(*(FUNC))((NPParg), (NPStreamPtr), (NPReasonArg))

-

-#endif

-

-

-/* NPP_WriteReady */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_WriteReadyUPP;

-enum {

-	uppNPP_WriteReadyProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(int32)))

-};

-#define NewNPP_WriteReadyProc(FUNC)		\

-		(NPP_WriteReadyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_WriteReadyProcInfo, GetCurrentArchitecture())

-#define CallNPP_WriteReadyProc(FUNC,  NPParg, NPStreamPtr)		\

-		(int32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_WriteReadyProcInfo, (NPParg), (NPStreamPtr))

-

-#else

-

-typedef int32 (* NP_LOADDS NPP_WriteReadyUPP)(NPP instance, NPStream* stream);

-#define NewNPP_WriteReadyProc(FUNC)		\

-		((NPP_WriteReadyUPP) (FUNC))

-#define CallNPP_WriteReadyProc(FUNC,  NPParg, NPStreamPtr)		\

-		(*(FUNC))((NPParg), (NPStreamPtr))

-

-#endif

-

-

-/* NPP_Write */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_WriteUPP;

-enum {

-	uppNPP_WriteProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(int32)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(int32)))

-		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(void*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(int32)))

-};

-#define NewNPP_WriteProc(FUNC)		\

-		(NPP_WriteUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_WriteProcInfo, GetCurrentArchitecture())

-#define CallNPP_WriteProc(FUNC,  NPParg, NPStreamPtr, offsetArg, lenArg, bufferPtr)		\

-		(int32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_WriteProcInfo, (NPParg), (NPStreamPtr), (offsetArg), (lenArg), (bufferPtr))

-

-#else

-

-typedef int32 (* NP_LOADDS NPP_WriteUPP)(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer);

-#define NewNPP_WriteProc(FUNC)		\

-		((NPP_WriteUPP) (FUNC))

-#define CallNPP_WriteProc(FUNC,  NPParg, NPStreamPtr, offsetArg, lenArg, bufferPtr)		\

-		(*(FUNC))((NPParg), (NPStreamPtr), (offsetArg), (lenArg), (bufferPtr))

-

-#endif

-

-

-/* NPP_StreamAsFile */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_StreamAsFileUPP;

-enum {

-	uppNPP_StreamAsFileProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char *)))

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-#define NewNPP_StreamAsFileProc(FUNC)		\

-		(NPP_StreamAsFileUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_StreamAsFileProcInfo, GetCurrentArchitecture())

-#define CallNPP_StreamAsFileProc(FUNC, ARG1, ARG2, ARG3)		\

-		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_StreamAsFileProcInfo, (ARG1), (ARG2), (ARG3))

-

-#else

-

-typedef void (* NP_LOADDS NPP_StreamAsFileUPP)(NPP instance, NPStream* stream, const char* fname);

-#define NewNPP_StreamAsFileProc(FUNC)		\

-		((NPP_StreamAsFileUPP) (FUNC))

-#define CallNPP_StreamAsFileProc(FUNC,  ARG1, ARG2, ARG3)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3))

-#endif

-

-

-/* NPP_Print */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_PrintUPP;

-enum {

-	uppNPP_PrintProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPrint *)))

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-#define NewNPP_PrintProc(FUNC)		\

-		(NPP_PrintUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_PrintProcInfo, GetCurrentArchitecture())

-#define CallNPP_PrintProc(FUNC,  NPParg, voidPtr)		\

-		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_PrintProcInfo, (NPParg), (voidPtr))

-

-#else

-

-typedef void (* NP_LOADDS NPP_PrintUPP)(NPP instance, NPPrint* platformPrint);

-#define NewNPP_PrintProc(FUNC)		\

-		((NPP_PrintUPP) (FUNC))

-#define CallNPP_PrintProc(FUNC,  NPParg, NPPrintArg)		\

-		(*(FUNC))((NPParg), (NPPrintArg))

-

-#endif

-

-

-/* NPP_HandleEvent */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_HandleEventUPP;

-enum {

-	uppNPP_HandleEventProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(void *)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(int16)))

-};

-#define NewNPP_HandleEventProc(FUNC)		\

-		(NPP_HandleEventUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_HandleEventProcInfo, GetCurrentArchitecture())

-#define CallNPP_HandleEventProc(FUNC,  NPParg, voidPtr)		\

-		(int16)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_HandleEventProcInfo, (NPParg), (voidPtr))

-

-#else

-

-typedef int16 (* NP_LOADDS NPP_HandleEventUPP)(NPP instance, void* event);

-#define NewNPP_HandleEventProc(FUNC)		\

-		((NPP_HandleEventUPP) (FUNC))

-#define CallNPP_HandleEventProc(FUNC,  NPParg, voidPtr)		\

-		(*(FUNC))((NPParg), (voidPtr))

-

-#endif

-

-

-/* NPP_URLNotify */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_URLNotifyUPP;

-enum {

-	uppNPP_URLNotifyProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPReason)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(void*)))

-		| RESULT_SIZE(SIZE_CODE(SIZE_CODE(0)))

-};

-#define NewNPP_URLNotifyProc(FUNC)		\

-		(NPP_URLNotifyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_URLNotifyProcInfo, GetCurrentArchitecture())

-#define CallNPP_URLNotifyProc(FUNC,  ARG1, ARG2, ARG3, ARG4)		\

-		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_URLNotifyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4))

-

-#else

-

-typedef void (* NP_LOADDS NPP_URLNotifyUPP)(NPP instance, const char* url, NPReason reason, void* notifyData);

-#define NewNPP_URLNotifyProc(FUNC)		\

-		((NPP_URLNotifyUPP) (FUNC))

-#define CallNPP_URLNotifyProc(FUNC,  ARG1, ARG2, ARG3, ARG4)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))

-

-#endif

-

-

-/* NPP_GetValue */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_GetValueUPP;

-enum {

-	uppNPP_GetValueProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPVariable)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPP_GetValueProc(FUNC)		\

-		(NPP_GetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_GetValueProcInfo, GetCurrentArchitecture())

-#define CallNPP_GetValueProc(FUNC, ARG1, ARG2, ARG3) \

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_GetValueProcInfo, (ARG1), (ARG2), (ARG3))

-#else

-

-typedef NPError	(* NP_LOADDS NPP_GetValueUPP)(NPP instance, NPPVariable variable, void *ret_alue);

-#define NewNPP_GetValueProc(FUNC)		\

-		((NPP_GetValueUPP) (FUNC))

-#define CallNPP_GetValueProc(FUNC, ARG1, ARG2, ARG3)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3))

-#endif

-

-

-/* NPP_SetValue */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_SetValueUPP;

-enum {

-	uppNPP_SetValueProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPNVariable)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPP_SetValueProc(FUNC)		\

-		(NPP_SetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_SetValueProcInfo, GetCurrentArchitecture())

-#define CallNPP_SetValueProc(FUNC, ARG1, ARG2, ARG3) \

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_SetValueProcInfo, (ARG1), (ARG2), (ARG3))

-#else

-

-typedef NPError	(* NP_LOADDS NPP_SetValueUPP)(NPP instance, NPNVariable variable, void *ret_alue);

-#define NewNPP_SetValueProc(FUNC)		\

-		((NPP_SetValueUPP) (FUNC))

-#define CallNPP_SetValueProc(FUNC, ARG1, ARG2, ARG3)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3))

-#endif

-

-

-/*

- *  Netscape entry points

- */

-

-

-/* NPN_GetValue */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_GetValueUPP;

-enum {

-	uppNPN_GetValueProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPNVariable)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPN_GetValueProc(FUNC)		\

-		(NPN_GetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetValueProcInfo, GetCurrentArchitecture())

-#define CallNPN_GetValueProc(FUNC, ARG1, ARG2, ARG3) \

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetValueProcInfo, (ARG1), (ARG2), (ARG3))

-#else

-

-typedef NPError	(* NP_LOADDS NPN_GetValueUPP)(NPP instance, NPNVariable variable, void *ret_alue);

-#define NewNPN_GetValueProc(FUNC)		\

-		((NPN_GetValueUPP) (FUNC))

-#define CallNPN_GetValueProc(FUNC, ARG1, ARG2, ARG3)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3))

-#endif

-

-

-/* NPN_SetValue */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_SetValueUPP;

-enum {

-	uppNPN_SetValueProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPVariable)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPN_SetValueProc(FUNC)		\

-		(NPN_SetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_SetValueProcInfo, GetCurrentArchitecture())

-#define CallNPN_SetValueProc(FUNC, ARG1, ARG2, ARG3) \

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_SetValueProcInfo, (ARG1), (ARG2), (ARG3))

-#else

-

-typedef NPError	(* NP_LOADDS NPN_SetValueUPP)(NPP instance, NPPVariable variable, void *ret_alue);

-#define NewNPN_SetValueProc(FUNC)		\

-		((NPN_SetValueUPP) (FUNC))

-#define CallNPN_SetValueProc(FUNC, ARG1, ARG2, ARG3)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3))

-#endif

-

-

-/* NPN_GetUrlNotify */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_GetURLNotifyUPP;

-enum {

-	uppNPN_GetURLNotifyProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(void*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPN_GetURLNotifyProc(FUNC)		\

-		(NPN_GetURLNotifyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetURLNotifyProcInfo, GetCurrentArchitecture())

-#define CallNPN_GetURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetURLNotifyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4))

-#else

-

-typedef NPError	(* NP_LOADDS NPN_GetURLNotifyUPP)(NPP instance, const char* url, const char* window, void* notifyData);

-#define NewNPN_GetURLNotifyProc(FUNC)		\

-		((NPN_GetURLNotifyUPP) (FUNC))

-#define CallNPN_GetURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))

-#endif

-

-

-/* NPN_PostUrlNotify */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_PostURLNotifyUPP;

-enum {

-	uppNPN_PostURLNotifyProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(uint32)))

-		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(const char*)))

-		| STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPBool)))

-		| STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(void*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPN_PostURLNotifyProc(FUNC)		\

-		(NPN_PostURLNotifyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PostURLNotifyProcInfo, GetCurrentArchitecture())

-#define CallNPN_PostURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PostURLNotifyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7))

-#else

-

-typedef NPError (* NP_LOADDS NPN_PostURLNotifyUPP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData);

-#define NewNPN_PostURLNotifyProc(FUNC)		\

-		((NPN_PostURLNotifyUPP) (FUNC))

-#define CallNPN_PostURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7))

-#endif

-

-

-/* NPN_GetUrl */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_GetURLUPP;

-enum {

-	uppNPN_GetURLProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPN_GetURLProc(FUNC)		\

-		(NPN_GetURLUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetURLProcInfo, GetCurrentArchitecture())

-#define CallNPN_GetURLProc(FUNC, ARG1, ARG2, ARG3) \

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetURLProcInfo, (ARG1), (ARG2), (ARG3))

-#else

-

-typedef NPError	(* NP_LOADDS NPN_GetURLUPP)(NPP instance, const char* url, const char* window);

-#define NewNPN_GetURLProc(FUNC)		\

-		((NPN_GetURLUPP) (FUNC))

-#define CallNPN_GetURLProc(FUNC, ARG1, ARG2, ARG3)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3))

-#endif

-

-

-/* NPN_PostUrl */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_PostURLUPP;

-enum {

-	uppNPN_PostURLProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(uint32)))

-		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(const char*)))

-		| STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPBool)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPN_PostURLProc(FUNC)		\

-		(NPN_PostURLUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PostURLProcInfo, GetCurrentArchitecture())

-#define CallNPN_PostURLProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PostURLProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6))

-#else

-

-typedef NPError (* NP_LOADDS NPN_PostURLUPP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file);

-#define NewNPN_PostURLProc(FUNC)		\

-		((NPN_PostURLUPP) (FUNC))

-#define CallNPN_PostURLProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6))

-#endif

-

-

-/* NPN_RequestRead */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_RequestReadUPP;

-enum {

-	uppNPN_RequestReadProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPStream *)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPByteRange *)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPN_RequestReadProc(FUNC)		\

-		(NPN_RequestReadUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_RequestReadProcInfo, GetCurrentArchitecture())

-#define CallNPN_RequestReadProc(FUNC,  stream, range)		\

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_RequestReadProcInfo, (stream), (range))

-

-#else

-

-typedef NPError	(* NP_LOADDS NPN_RequestReadUPP)(NPStream* stream, NPByteRange* rangeList);

-#define NewNPN_RequestReadProc(FUNC)		\

-		((NPN_RequestReadUPP) (FUNC))

-#define CallNPN_RequestReadProc(FUNC, stream, range)		\

-		(*(FUNC))((stream), (range))

-

-#endif

-

-

-/* NPN_NewStream */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_NewStreamUPP;

-enum {

-	uppNPN_NewStreamProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPMIMEType)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char *)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPStream **)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPN_NewStreamProc(FUNC)		\

-		(NPN_NewStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_NewStreamProcInfo, GetCurrentArchitecture())

-#define CallNPN_NewStreamProc(FUNC, npp, type, window, stream)		\

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_NewStreamProcInfo, (npp), (type), (window), (stream))	

-

-#else

-

-typedef NPError	(* NP_LOADDS NPN_NewStreamUPP)(NPP instance, NPMIMEType type, const char* window, NPStream** stream);

-#define NewNPN_NewStreamProc(FUNC)		\

-		((NPN_NewStreamUPP) (FUNC))

-#define CallNPN_NewStreamProc(FUNC, npp, type, window, stream)		\

-		(*(FUNC))((npp), (type), (window), (stream))

-

-#endif

-

-

-/* NPN_Write */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_WriteUPP;

-enum {

-	uppNPN_WriteProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(int32)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(void*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(int32)))

-};

-#define NewNPN_WriteProc(FUNC)		\

-		(NPN_WriteUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_WriteProcInfo, GetCurrentArchitecture())

-#define CallNPN_WriteProc(FUNC, npp, stream, len, buffer)		\

-		(int32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_WriteProcInfo, (npp), (stream), (len), (buffer))	

-

-#else

-

-typedef int32 (* NP_LOADDS NPN_WriteUPP)(NPP instance, NPStream* stream, int32 len, void* buffer);

-#define NewNPN_WriteProc(FUNC)		\

-		((NPN_WriteUPP) (FUNC))

-#define CallNPN_WriteProc(FUNC, npp, stream, len, buffer)		\

-		(*(FUNC))((npp), (stream), (len), (buffer))

-

-#endif

-

-

-/* NPN_DestroyStream */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_DestroyStreamUPP;

-enum {

-	uppNPN_DestroyStreamProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP )))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPReason)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPN_DestroyStreamProc(FUNC)		\

-		(NPN_DestroyStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_DestroyStreamProcInfo, GetCurrentArchitecture())

-#define CallNPN_DestroyStreamProc(FUNC, npp, stream, reason)		\

-		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_DestroyStreamProcInfo, (npp), (stream), (reason))	

-

-#else

-

-typedef NPError (* NP_LOADDS NPN_DestroyStreamUPP)(NPP instance, NPStream* stream, NPReason reason);

-#define NewNPN_DestroyStreamProc(FUNC)		\

-		((NPN_DestroyStreamUPP) (FUNC))

-#define CallNPN_DestroyStreamProc(FUNC, npp, stream, reason)		\

-		(*(FUNC))((npp), (stream), (reason))

-

-#endif

-

-

-/* NPN_Status */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_StatusUPP;

-enum {

-	uppNPN_StatusProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char *)))

-};

-

-#define NewNPN_StatusProc(FUNC)		\

-		(NPN_StatusUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_StatusProcInfo, GetCurrentArchitecture())

-#define CallNPN_StatusProc(FUNC, npp, msg)		\

-		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_StatusProcInfo, (npp), (msg))	

-

-#else

-

-typedef void (* NP_LOADDS NPN_StatusUPP)(NPP instance, const char* message);

-#define NewNPN_StatusProc(FUNC)		\

-		((NPN_StatusUPP) (FUNC))

-#define CallNPN_StatusProc(FUNC, npp, msg)		\

-		(*(FUNC))((npp), (msg))	

-

-#endif

-

-

-/* NPN_UserAgent */

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_UserAgentUPP;

-enum {

-        uppNPN_UserAgentProcInfo = kThinkCStackBased

-                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-                | RESULT_SIZE(SIZE_CODE(sizeof(const char *)))

-};

-

-#define NewNPN_UserAgentProc(FUNC)              \

-                (NPN_UserAgentUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_UserAgentProcInfo, GetCurrentArchitecture())

-#define CallNPN_UserAgentProc(FUNC, ARG1)               \

-                (const char*)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_UserAgentProcInfo, (ARG1))

-

-#else

-

-typedef const char*	(* NP_LOADDS NPN_UserAgentUPP)(NPP instance);

-#define NewNPN_UserAgentProc(FUNC)              \

-                ((NPN_UserAgentUPP) (FUNC))

-#define CallNPN_UserAgentProc(FUNC, ARG1)               \

-                (*(FUNC))((ARG1))

-

-#endif

-

-

-/* NPN_MemAlloc */

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_MemAllocUPP;

-enum {

-	uppNPN_MemAllocProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(uint32)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(void *)))

-};

-

-#define NewNPN_MemAllocProc(FUNC)		\

-		(NPN_MemAllocUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_MemAllocProcInfo, GetCurrentArchitecture())

-#define CallNPN_MemAllocProc(FUNC, ARG1)		\

-		(void*)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_MemAllocProcInfo, (ARG1))	

-

-#else

-

-typedef void* (* NP_LOADDS NPN_MemAllocUPP)(uint32 size);

-#define NewNPN_MemAllocProc(FUNC)		\

-		((NPN_MemAllocUPP) (FUNC))

-#define CallNPN_MemAllocProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))	

-

-#endif

-

-

-/* NPN__MemFree */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_MemFreeUPP;

-enum {

-	uppNPN_MemFreeProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(void *)))

-};

-

-#define NewNPN_MemFreeProc(FUNC)		\

-		(NPN_MemFreeUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_MemFreeProcInfo, GetCurrentArchitecture())

-#define CallNPN_MemFreeProc(FUNC, ARG1)		\

-		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_MemFreeProcInfo, (ARG1))

-

-#else

-

-typedef void (* NP_LOADDS NPN_MemFreeUPP)(void* ptr);

-#define NewNPN_MemFreeProc(FUNC)		\

-		((NPN_MemFreeUPP) (FUNC))

-#define CallNPN_MemFreeProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))	

-

-#endif

-

-

-/* NPN_MemFlush */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_MemFlushUPP;

-enum {

-	uppNPN_MemFlushProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(uint32)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(uint32)))

-};

-

-#define NewNPN_MemFlushProc(FUNC)		\

-		(NPN_MemFlushUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_MemFlushProcInfo, GetCurrentArchitecture())

-#define CallNPN_MemFlushProc(FUNC, ARG1)		\

-		(uint32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_MemFlushProcInfo, (ARG1))	

-

-#else

-

-typedef uint32 (* NP_LOADDS NPN_MemFlushUPP)(uint32 size);

-#define NewNPN_MemFlushProc(FUNC)		\

-		((NPN_MemFlushUPP) (FUNC))

-#define CallNPN_MemFlushProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))	

-

-#endif

-

-

-

-/* NPN_ReloadPlugins */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_ReloadPluginsUPP;

-enum {

-	uppNPN_ReloadPluginsProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPBool)))

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPN_ReloadPluginsProc(FUNC)		\

-		(NPN_ReloadPluginsUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ReloadPluginsProcInfo, GetCurrentArchitecture())

-#define CallNPN_ReloadPluginsProc(FUNC, ARG1)		\

-		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ReloadPluginsProcInfo, (ARG1))	

-

-#else

-

-typedef void (* NP_LOADDS NPN_ReloadPluginsUPP)(NPBool reloadPages);

-#define NewNPN_ReloadPluginsProc(FUNC)		\

-		((NPN_ReloadPluginsUPP) (FUNC))

-#define CallNPN_ReloadPluginsProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))	

-

-#endif

-

-/* NPN_GetJavaEnv */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_GetJavaEnvUPP;

-enum {

-	uppNPN_GetJavaEnvProcInfo = kThinkCStackBased

-		| RESULT_SIZE(SIZE_CODE(sizeof(JRIEnv*)))

-};

-

-#define NewNPN_GetJavaEnvProc(FUNC)		\

-		(NPN_GetJavaEnvUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetJavaEnvProcInfo, GetCurrentArchitecture())

-#define CallNPN_GetJavaEnvProc(FUNC)		\

-		(JRIEnv*)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetJavaEnvProcInfo)	

-

-#else

-typedef JRIEnv* (* NP_LOADDS NPN_GetJavaEnvUPP)(void);

-#define NewNPN_GetJavaEnvProc(FUNC)		\

-		((NPN_GetJavaEnvUPP) (FUNC))

-#define CallNPN_GetJavaEnvProc(FUNC)		\

-		(*(FUNC))()	

-

-#endif

-

-

-/* NPN_GetJavaPeer */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_GetJavaPeerUPP;

-enum {

-	uppNPN_GetJavaPeerProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(jref)))

-};

-

-#define NewNPN_GetJavaPeerProc(FUNC)		\

-		(NPN_GetJavaPeerUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetJavaPeerProcInfo, GetCurrentArchitecture())

-#define CallNPN_GetJavaPeerProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetJavaPeerProcInfo, (ARG1))	

-

-#else

-

-typedef jref (* NP_LOADDS NPN_GetJavaPeerUPP)(NPP instance);

-#define NewNPN_GetJavaPeerProc(FUNC)		\

-		((NPN_GetJavaPeerUPP) (FUNC))

-#define CallNPN_GetJavaPeerProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))	

-

-#endif

-

-/* NPN_InvalidateRect */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_InvalidateRectUPP;

-enum {

-	uppNPN_InvalidateRectProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPRect *)))

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPN_InvalidateRectProc(FUNC)		\

-		(NPN_InvalidateRectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvalidateRectProcInfo, GetCurrentArchitecture())

-#define CallNPN_InvalidateRectProc(FUNC, ARG1, ARG2)		\

-		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvalidateRectProcInfo, (ARG1), (ARG2))	

-

-#else

-

-typedef void (* NP_LOADDS NPN_InvalidateRectUPP)(NPP instance, NPRect *rect);

-#define NewNPN_InvalidateRectProc(FUNC)		\

-		((NPN_InvalidateRectUPP) (FUNC))

-#define CallNPN_InvalidateRectProc(FUNC, ARG1, ARG2)		\

-		(*(FUNC))((ARG1), (ARG2))	

-

-#endif

-

-

-/* NPN_InvalidateRegion */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_InvalidateRegionUPP;

-enum {

-	uppNPN_InvalidateRegionProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPRegion)))

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPN_InvalidateRegionProc(FUNC)		\

-		(NPN_InvalidateRegionUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvalidateRegionProcInfo, GetCurrentArchitecture())

-#define CallNPN_InvalidateRegionProc(FUNC, ARG1, ARG2)		\

-		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvalidateRegionProcInfo, (ARG1), (ARG2))	

-

-#else

-

-typedef void (* NP_LOADDS NPN_InvalidateRegionUPP)(NPP instance, NPRegion region);

-#define NewNPN_InvalidateRegionProc(FUNC)		\

-		((NPN_InvalidateRegionUPP) (FUNC))

-#define CallNPN_InvalidateRegionProc(FUNC, ARG1, ARG2)		\

-		(*(FUNC))((ARG1), (ARG2))	

-

-#endif

-

-/* NPN_ForceRedraw */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_ForceRedrawUPP;

-enum {

-	uppNPN_ForceRedrawProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(0)))

-};

-

-#define NewNPN_ForceRedrawProc(FUNC)		\

-		(NPN_ForceRedrawUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ForceRedrawProcInfo, GetCurrentArchitecture())

-#define CallNPN_ForceRedrawProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ForceRedrawProcInfo, (ARG1))	

-

-#else

-

-typedef void (* NP_LOADDS NPN_ForceRedrawUPP)(NPP instance);

-#define NewNPN_ForceRedrawProc(FUNC)		\

-		((NPN_ForceRedrawUPP) (FUNC))

-#define CallNPN_ForceRedrawProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))	

-

-#endif

-

-/* NPN_GetStringIdentifier */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_GetStringIdentifierUPP;

-enum {

-	uppNPN_GetStringIdentifierProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const NPUTF8*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPIdentifier)))

-};

-

-#define NewNPN_GetStringIdentifierProc(FUNC)		\

-		(NPN_GetStringIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetStringIdentifierProcInfo, GetCurrentArchitecture())

-#define CallNPN_GetStringIdentifierProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetStringIdentifierProcInfo, (ARG1))	

-

-#else

-

-typedef NPIdentifier (* NP_LOADDS NPN_GetStringIdentifierUPP)(const NPUTF8* name);

-#define NewNPN_GetStringIdentifierProc(FUNC)		\

-		((NPN_GetStringIdentifierUPP) (FUNC))

-#define CallNPN_GetStringIdentifierProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))

-

-#endif

-

-/* NPN_GetStringIdentifiers */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_GetStringIdentifiersUPP;

-enum {

-	uppNPN_GetStringIdentifiersProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const NPUTF8**)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(int32_t)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier*)))

-        | RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPN_GetStringIdentifiersProc(FUNC)		\

-		(NPN_GetStringIdentifiersUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetStringIdentifiersProcInfo, GetCurrentArchitecture())

-#define CallNPN_GetStringIdentifiersProc(FUNC, ARG1, ARG2, ARG3)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetStringIdentifiersProcInfo, (ARG1), (ARG2), (ARG3))	

-

-#else

-

-typedef void (* NP_LOADDS NPN_GetStringIdentifiersUPP)(const NPUTF8** names,

-                                                 int32_t nameCount,

-                                                 NPIdentifier* identifiers);

-#define NewNPN_GetStringIdentifiersProc(FUNC)		\

-		((NPN_GetStringIdentifiersUPP) (FUNC))

-#define CallNPN_GetStringIdentifiersProc(FUNC, ARG1, ARG2, ARG3)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3))

-

-#endif

-

-/* NPN_GetIntIdentifier */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_GetIntIdentifierUPP;

-enum {

-	uppNPN_GetIntIdentifierProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(int32_t)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPIdentifier)))

-};

-

-#define NewNPN_GetIntIdentifierProc(FUNC)		\

-		(NPN_GetIntIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetIntIdentifierProcInfo, GetCurrentArchitecture())

-#define CallNPN_GetIntIdentifierProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetIntIdentifierProcInfo, (ARG1))	

-

-#else

-

-typedef NPIdentifier (* NP_LOADDS NPN_GetIntIdentifierUPP)(int32_t intid);

-#define NewNPN_GetIntIdentifierProc(FUNC)		\

-		((NPN_GetIntIdentifierUPP) (FUNC))

-#define CallNPN_GetIntIdentifierProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))

-

-#endif

-

-/* NPN_IdentifierIsString */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_IdentifierIsStringUPP;

-enum {

-	uppNPN_IdentifierIsStringProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPIdentifier identifier)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))

-};

-

-#define NewNPN_IdentifierIsStringProc(FUNC)		\

-		(NPN_IdentifierIsStringUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_IdentifierIsStringProcInfo, GetCurrentArchitecture())

-#define CallNPN_IdentifierIsStringProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_IdentifierIsStringProcInfo, (ARG1))	

-

-#else

-

-typedef bool (* NP_LOADDS NPN_IdentifierIsStringUPP)(NPIdentifier identifier);

-#define NewNPN_IdentifierIsStringProc(FUNC)		\

-		((NPN_IdentifierIsStringUPP) (FUNC))

-#define CallNPN_IdentifierIsStringProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))

-

-#endif

-

-/* NPN_UTF8FromIdentifier */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_UTF8FromIdentifierUPP;

-enum {

-	uppNPN_UTF8FromIdentifierProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPIdentifier)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPUTF8*)))

-};

-

-#define NewNPN_UTF8FromIdentifierProc(FUNC)		\

-		(NPN_UTF8FromIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_UTF8FromIdentifierProcInfo, GetCurrentArchitecture())

-#define CallNPN_UTF8FromIdentifierProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_UTF8FromIdentifierProcInfo, (ARG1))	

-

-#else

-

-typedef NPUTF8* (* NP_LOADDS NPN_UTF8FromIdentifierUPP)(NPIdentifier identifier);

-#define NewNPN_UTF8FromIdentifierProc(FUNC)		\

-		((NPN_UTF8FromIdentifierUPP) (FUNC))

-#define CallNPN_UTF8FromIdentifierProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))

-

-#endif

-

-/* NPN_IntFromIdentifier */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_IntFromIdentifierUPP;

-enum {

-	uppNPN_IntFromIdentifierProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPIdentifier)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(int32_t)))

-};

-

-#define NewNPN_IntFromIdentifierProc(FUNC)		\

-		(NPN_IntFromIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_IntFromIdentifierProcInfo, GetCurrentArchitecture())

-#define CallNPN_IntFromIdentifierProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_IntFromIdentifierProcInfo, (ARG1))	

-

-#else

-

-typedef int32_t (* NP_LOADDS NPN_IntFromIdentifierUPP)(NPIdentifier identifier);

-#define NewNPN_IntFromIdentifierProc(FUNC)		\

-		((NPN_IntFromIdentifierUPP) (FUNC))

-#define CallNPN_IntFromIdentifierProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))

-

-#endif

-

-/* NPN_CreateObject */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_CreateObjectUPP;

-enum {

-	uppNPN_CreateObjectProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPClass*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPObject*)))

-};

-

-#define NewNPN_CreateObjectProc(FUNC)		\

-		(NPN_CreateObjectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_CreateObjectProcInfo, GetCurrentArchitecture())

-#define CallNPN_CreateObjectProc(FUNC, ARG1, ARG2)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_CreateObjectProcInfo, (ARG1), (ARG2))	

-

-#else

-

-typedef NPObject* (* NP_LOADDS NPN_CreateObjectUPP)(NPP npp, NPClass *aClass);

-#define NewNPN_CreateObjectProc(FUNC)		\

-		((NPN_CreateObjectUPP) (FUNC))

-#define CallNPN_CreateObjectProc(FUNC, ARG1, ARG2)		\

-		(*(FUNC))((ARG1), (ARG2))

-

-#endif

-

-/* NPN_RetainObject */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_RetainObjectUPP;

-enum {

-	uppNPN_RetainObjectProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPObject*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPObject*)))

-};

-

-#define NewNPN_RetainObjectProc(FUNC)		\

-		(NPN_RetainObjectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_RetainObjectProcInfo, GetCurrentArchitecture())

-#define CallNPN_RetainObjectProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_RetainObjectProcInfo, (ARG1))	

-

-#else

-

-typedef NPObject* (* NP_LOADDS NPN_RetainObjectUPP)(NPObject *obj);

-#define NewNPN_RetainObjectProc(FUNC)		\

-		((NPN_RetainObjectUPP) (FUNC))

-#define CallNPN_RetainObjectProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))

-

-#endif

-

-/* NPN_ReleaseObject */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_ReleaseObjectUPP;

-enum {

-	uppNPN_ReleaseObjectProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPObject*)))

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPN_ReleaseObjectProc(FUNC)		\

-		(NPN_ReleaseObjectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ReleaseObjectProcInfo, GetCurrentArchitecture())

-#define CallNPN_ReleaseObjectProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ReleaseObjectProcInfo, (ARG1))

-

-#else

-

-typedef void (* NP_LOADDS NPN_ReleaseObjectUPP)(NPObject *obj);

-#define NewNPN_ReleaseObjectProc(FUNC)		\

-		((NPN_ReleaseObjectUPP) (FUNC))

-#define CallNPN_ReleaseObjectProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))

-

-#endif

-

-/* NPN_Invoke */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_InvokeUPP;

-enum {

-	uppNPN_InvokeProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(const NPVariant*)))

-		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(uint32_t)))

-		| STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPVariant*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))

-};

-

-#define NewNPN_InvokeProc(FUNC)		\

-		(NPN_InvokeUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvokeProcInfo, GetCurrentArchitecture())

-#define CallNPN_InvokeProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvokeProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6))

-

-#else

-

-typedef bool (* NP_LOADDS NPN_InvokeUPP)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);

-#define NewNPN_InvokeProc(FUNC)		\

-		((NPN_InvokeUPP) (FUNC))

-#define CallNPN_InvokeProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6))

-

-#endif

-

-/* NPN_InvokeDefault */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_InvokeDefaultUPP;

-enum {

-	uppNPN_InvokeDefaultProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(const NPVariant*)))

-		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(uint32_t)))

-		| STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPVariant*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))

-};

-

-#define NewNPN_InvokeDefaultProc(FUNC)		\

-		(NPN_InvokeDefaultUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvokeDefaultProcInfo, GetCurrentArchitecture())

-#define CallNPN_InvokeDefaultProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvokeDefaultProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5))

-

-#else

-

-typedef bool (* NP_LOADDS NPN_InvokeDefaultUPP)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);

-#define NewNPN_InvokeDefaultProc(FUNC)		\

-		((NPN_InvokeDefaultUPP) (FUNC))

-#define CallNPN_InvokeDefaultProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5))

-

-#endif

-

-/* NPN_Evaluate */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_EvaluateUPP;

-enum {

-	uppNPN_EvaluateProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPString*)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPVariant*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))

-};

-

-#define NewNPN_EvaluateProc(FUNC)		\

-		(NPN_EvaluateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_EvaluateProcInfo, GetCurrentArchitecture())

-#define CallNPN_EvaluateProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_EvaluateProcInfo, (ARG1), (ARG2), (ARG3), (ARG4))

-

-#else

-

-typedef bool (* NP_LOADDS NPN_EvaluateUPP)(NPP npp, NPObject *obj, NPString *script, NPVariant *result);

-#define NewNPN_EvaluateProc(FUNC)		\

-		((NPN_EvaluateUPP) (FUNC))

-#define CallNPN_EvaluateProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))

-

-#endif

-

-/* NPN_GetProperty */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_GetPropertyUPP;

-enum {

-	uppNPN_GetPropertyProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPVariant*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))

-};

-

-#define NewNPN_GetPropertyProc(FUNC)		\

-		(NPN_GetPropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetPropertyProcInfo, GetCurrentArchitecture())

-#define CallNPN_GetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetPropertyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4))

-

-#else

-

-typedef bool (* NP_LOADDS NPN_GetPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result);

-#define NewNPN_GetPropertyProc(FUNC)		\

-		((NPN_GetPropertyUPP) (FUNC))

-#define CallNPN_GetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))

-

-#endif

-

-/* NPN_SetProperty */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_SetPropertyUPP;

-enum {

-	uppNPN_SetPropertyProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))

-		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(const NPVariant*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))

-};

-

-#define NewNPN_SetPropertyProc(FUNC)		\

-		(NPN_SetPropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_SetPropertyProcInfo, GetCurrentArchitecture())

-#define CallNPN_SetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_SetPropertyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4))

-

-#else

-

-typedef bool (* NP_LOADDS NPN_SetPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value);

-#define NewNPN_SetPropertyProc(FUNC)		\

-		((NPN_SetPropertyUPP) (FUNC))

-#define CallNPN_SetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))

-

-#endif

-

-/* NPN_RemoveProperty */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_RemovePropertyUPP;

-enum {

-	uppNPN_RemovePropertyProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))

-};

-

-#define NewNPN_RemovePropertyProc(FUNC)		\

-		(NPN_RemovePropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_RemovePropertyProcInfo, GetCurrentArchitecture())

-#define CallNPN_RemovePropertyProc(FUNC, ARG1, ARG2, ARG3)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_RemovePropertyProcInfo, (ARG1), (ARG2), (ARG3))

-

-#else

-

-typedef bool (* NP_LOADDS NPN_RemovePropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName);

-#define NewNPN_RemovePropertyProc(FUNC)		\

-		((NPN_RemovePropertyUPP) (FUNC))

-#define CallNPN_RemovePropertyProc(FUNC, ARG1, ARG2, ARG3)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3))

-

-#endif

-

-/* NPN_HasProperty */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_HasPropertyUPP;

-enum {

-	uppNPN_HasPropertyProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))

-};

-

-#define NewNPN_HasPropertyProc(FUNC)		\

-		(NPN_HasPropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_HasPropertyProcInfo, GetCurrentArchitecture())

-#define CallNPN_HasPropertyProc(FUNC, ARG1, ARG2, ARG3)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_HasPropertyProcInfo, (ARG1), (ARG2), (ARG3))

-

-#else

-

-typedef bool (* NP_LOADDS NPN_HasPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName);

-#define NewNPN_HasPropertyProc(FUNC)		\

-		((NPN_HasPropertyUPP) (FUNC))

-#define CallNPN_HasPropertyProc(FUNC, ARG1, ARG2, ARG3)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3))

-

-#endif

-

-/* NPN_HasMethod */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_HasMethodUPP;

-enum {

-	uppNPN_HasMethodProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))

-};

-

-#define NewNPN_HasMethodProc(FUNC)		\

-		(NPN_HasMethodUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_HasMethodProcInfo, GetCurrentArchitecture())

-#define CallNPN_HasMethodProc(FUNC, ARG1, ARG2, ARG3)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_HasMethodProcInfo, (ARG1), (ARG2), (ARG3))

-

-#else

-

-typedef bool (* NP_LOADDS NPN_HasMethodUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName);

-#define NewNPN_HasMethodProc(FUNC)		\

-		((NPN_HasMethodUPP) (FUNC))

-#define CallNPN_HasMethodProc(FUNC, ARG1, ARG2, ARG3)		\

-		(*(FUNC))((ARG1), (ARG2), (ARG3))

-

-#endif

-

-/* NPN_ReleaseVariantValue */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_ReleaseVariantValue;

-enum {

-	uppNPN_ReleaseVariantValueProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPVariant*)))

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPN_ReleaseVariantValueProc(FUNC)		\

-		(NPN_ReleaseVariantValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ReleaseVariantValueProcInfo, GetCurrentArchitecture())

-#define CallNPN_ReleaseVariantValueProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ReleaseVariantValueProcInfo, (ARG1))	

-

-#else

-

-typedef void (* NP_LOADDS NPN_ReleaseVariantValueUPP)(NPVariant *variant);

-#define NewNPN_ReleaseVariantValueProc(FUNC)		\

-		((NPN_ReleaseVariantValueUPP) (FUNC))

-#define CallNPN_ReleaseVariantValueProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))

-

-#endif

-

-/* NPN_SetException */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_SetExceptionUPP;

-enum {

-	uppNPN_SetExceptionProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPObject*)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const NPUTF8*)))

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPN_SetExceptionProc(FUNC)		\

-		(NPN_SetExceptionUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_SetExceptionProcInfo, GetCurrentArchitecture())

-#define CallNPN_SetExceptionProc(FUNC, ARG1, ARG2)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_SetExceptionProcInfo, (ARG1), (ARG2))	

-

-#else

-

-typedef void (* NP_LOADDS NPN_SetExceptionUPP)(NPObject *obj, const NPUTF8 *message);

-#define NewNPN_SetExceptionProc(FUNC)		\

-		((NPN_SetExceptionUPP) (FUNC))

-#define CallNPN_SetExceptionProc(FUNC, ARG1, ARG2)		\

-		(*(FUNC))((ARG1), (ARG2))	

-

-#endif

-

-/* NPN_PushPopupsEnabledStateUPP */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_PushPopupsEnabledStateUPP;

-enum {

-	uppNPN_PushPopupsEnabledStateProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-        | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPBool)))

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPN_PushPopupsEnabledStateProc(FUNC)		\

-		(NPN_PushPopupsEnabledStateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PushPopupsEnabledStateProcInfo, GetCurrentArchitecture())

-#define CallNPN_PushPopupsEnabledStateProc(FUNC, ARG1, ARG2)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PushPopupsEnabledStateProcInfo, (ARG1), (ARG2))

-

-#else

-

-typedef bool (* NP_LOADDS NPN_PushPopupsEnabledStateUPP)(NPP npp, NPBool enabled);

-#define NewNPN_PushPopupsEnabledStateProc(FUNC)		\

-		((NPN_PushPopupsEnabledStateUPP) (FUNC))

-#define CallNPN_PushPopupsEnabledStateProc(FUNC, ARG1, ARG2)		\

-		(*(FUNC))((ARG1), (ARG2))

-

-#endif

-

-/* NPN_PopPopupsEnabledState */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPN_PopPopupsEnabledStateUPP;

-enum {

-	uppNPN_PopPopupsEnabledStateProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))

-		| RESULT_SIZE(SIZE_CODE(0))

-};

-

-#define NewNPN_PopPopupsEnabledStateProc(FUNC)		\

-		(NPN_PopPopupsEnabledStateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PopPopupsEnabledStateProcInfo, GetCurrentArchitecture())

-#define CallNPN_PopPopupsEnabledStateProc(FUNC, ARG1)		\

-		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PopPopupsEnabledStateProcInfo, (ARG1))

-

-#else

-

-typedef bool (* NP_LOADDS NPN_PopPopupsEnabledStateUPP)(NPP npp);

-#define NewNPN_PopPopupsEnabledStateProc(FUNC)		\

-		((NPN_PopPopupsEnabledStateUPP) (FUNC))

-#define CallNPN_PopPopupsEnabledStateProc(FUNC, ARG1)		\

-		(*(FUNC))((ARG1))

-

-#endif

-

-

-

-/******************************************************************************************

- * The actual plugin function table definitions

- *******************************************************************************************/

-

-#ifdef XP_MAC

-#if PRAGMA_STRUCT_ALIGN

-#pragma options align=mac68k

-#endif

-#endif

-

-typedef struct _NPPluginFuncs {

-    uint16 size;

-    uint16 version;

-    NPP_NewUPP newp;

-    NPP_DestroyUPP destroy;

-    NPP_SetWindowUPP setwindow;

-    NPP_NewStreamUPP newstream;

-    NPP_DestroyStreamUPP destroystream;

-    NPP_StreamAsFileUPP asfile;

-    NPP_WriteReadyUPP writeready;

-    NPP_WriteUPP write;

-    NPP_PrintUPP print;

-    NPP_HandleEventUPP event;

-    NPP_URLNotifyUPP urlnotify;

-    JRIGlobalRef javaClass;

-    NPP_GetValueUPP getvalue;

-    NPP_SetValueUPP setvalue;

-} NPPluginFuncs;

-

-typedef struct _NPNetscapeFuncs {

-    uint16 size;

-    uint16 version;

-    NPN_GetURLUPP geturl;

-    NPN_PostURLUPP posturl;

-    NPN_RequestReadUPP requestread;

-    NPN_NewStreamUPP newstream;

-    NPN_WriteUPP write;

-    NPN_DestroyStreamUPP destroystream;

-    NPN_StatusUPP status;

-    NPN_UserAgentUPP uagent;

-    NPN_MemAllocUPP memalloc;

-    NPN_MemFreeUPP memfree;

-    NPN_MemFlushUPP memflush;

-    NPN_ReloadPluginsUPP reloadplugins;

-    NPN_GetJavaEnvUPP getJavaEnv;

-    NPN_GetJavaPeerUPP getJavaPeer;

-    NPN_GetURLNotifyUPP geturlnotify;

-    NPN_PostURLNotifyUPP posturlnotify;

-    NPN_GetValueUPP getvalue;

-    NPN_SetValueUPP setvalue;

-    NPN_InvalidateRectUPP invalidaterect;

-    NPN_InvalidateRegionUPP invalidateregion;

-    NPN_ForceRedrawUPP forceredraw;

-    NPN_GetStringIdentifierUPP getstringidentifier;

-    NPN_GetStringIdentifiersUPP getstringidentifiers;

-    NPN_GetIntIdentifierUPP getintidentifier;

-    NPN_IdentifierIsStringUPP identifierisstring;

-    NPN_UTF8FromIdentifierUPP utf8fromidentifier;

-    NPN_IntFromIdentifierUPP intfromidentifier;

-    NPN_CreateObjectUPP createobject;

-    NPN_RetainObjectUPP retainobject;

-    NPN_ReleaseObjectUPP releaseobject;

-    NPN_InvokeUPP invoke;

-    NPN_InvokeDefaultUPP invokeDefault;

-    NPN_EvaluateUPP evaluate;

-    NPN_GetPropertyUPP getproperty;

-    NPN_SetPropertyUPP setproperty;

-    NPN_RemovePropertyUPP removeproperty;

-    NPN_HasPropertyUPP hasproperty;

-    NPN_HasMethodUPP hasmethod;

-    NPN_ReleaseVariantValueUPP releasevariantvalue;

-    NPN_SetExceptionUPP setexception;

-    NPN_PushPopupsEnabledStateUPP pushpopupsenabledstate;

-    NPN_PopPopupsEnabledStateUPP poppopupsenabledstate;

-} NPNetscapeFuncs;

-

-#ifdef XP_MAC

-#if PRAGMA_STRUCT_ALIGN

-#pragma options align=reset

-#endif

-#endif

-

-

-#if defined(XP_MAC) || defined(XP_MACOSX)

-/******************************************************************************************

- * Mac platform-specific plugin glue stuff

- *******************************************************************************************/

-

-/*

- * Main entry point of the plugin.

- * This routine will be called when the plugin is loaded. The function

- * tables are passed in and the plugin fills in the NPPluginFuncs table

- * and NPPShutdownUPP for Netscape's use.

- */

-

-#if _NPUPP_USE_UPP_

-

-typedef UniversalProcPtr NPP_MainEntryUPP;

-enum {

-	uppNPP_MainEntryProcInfo = kThinkCStackBased

-		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPNetscapeFuncs*)))

-		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPluginFuncs*)))

-		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPP_ShutdownUPP*)))

-		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))

-};

-#define NewNPP_MainEntryProc(FUNC)		\

-		(NPP_MainEntryUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_MainEntryProcInfo, GetCurrentArchitecture())

-#define CallNPP_MainEntryProc(FUNC,  netscapeFunc, pluginFunc, shutdownUPP)		\

-		CallUniversalProc((UniversalProcPtr)(FUNC), (ProcInfoType)uppNPP_MainEntryProcInfo, (netscapeFunc), (pluginFunc), (shutdownUPP))

-

-#else

-

-typedef NPError (* NP_LOADDS NPP_MainEntryUPP)(NPNetscapeFuncs*, NPPluginFuncs*, NPP_ShutdownUPP*);

-#define NewNPP_MainEntryProc(FUNC)		\

-		((NPP_MainEntryUPP) (FUNC))

-#define CallNPP_MainEntryProc(FUNC,  netscapeFunc, pluginFunc, shutdownUPP)		\

-		(*(FUNC))((netscapeFunc), (pluginFunc), (shutdownUPP))

-

-#endif

-

-

-/*

- * Mac version(s) of NP_GetMIMEDescription(const char *)

- * These can be called to retreive MIME information from the plugin dynamically

- *

- * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way

- *       to get mime info from the plugin only on OSX and may not be supported 

- *       in furture version--use NP_GetMIMEDescription instead

- */

-

-enum

-{

- kBPSupportedMIMETypesStructVers_1    = 1

-};

-

-typedef struct _BPSupportedMIMETypes

-{

- SInt32    structVersion;      /* struct version */

- Handle    typeStrings;        /* STR# formated handle, allocated by plug-in */

- Handle    infoStrings;        /* STR# formated handle, allocated by plug-in */

-} BPSupportedMIMETypes;

-OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags);

-

-#if _NPUPP_USE_UPP_

-

-#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescriptionRD"

-typedef UniversalProcPtr NP_GetMIMEDescriptionUPP;

-enum {

-	uppNP_GetMIMEDescEntryProc = kThinkCStackBased

-		| RESULT_SIZE(SIZE_CODE(sizeof(const char *)))

-};

-#define NewNP_GetMIMEDescEntryProc(FUNC)		\

-		(NP_GetMIMEDescriptionUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNP_GetMIMEDescEntryProc, GetCurrentArchitecture())

-#define CallNP_GetMIMEDescEntryProc(FUNC)		\

-		(const char *)CallUniversalProc((UniversalProcPtr)(FUNC), (ProcInfoType)uppNP_GetMIMEDescEntryProc)

-

-

-#else  /* !_NPUPP_USE_UPP_ */

-

- /* NP_GetMIMEDescription */

-#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription"

-typedef const char* (* NP_LOADDS NP_GetMIMEDescriptionUPP)();

-#define NewNP_GetMIMEDescEntryProc(FUNC)		\

-		((NP_GetMIMEDescriptionUPP) (FUNC))

-#define CallNP_GetMIMEDescEntryProc(FUNC)		\

-		(*(FUNC))()

-/* BP_GetSupportedMIMETypes */

-typedef OSErr (* NP_LOADDS BP_GetSupportedMIMETypesUPP)(BPSupportedMIMETypes*, UInt32);

-#define NewBP_GetSupportedMIMETypesEntryProc(FUNC)		\

-		((BP_GetSupportedMIMETypesUPP) (FUNC))

-#define CallBP_GetMIMEDescEntryProc(FUNC,  mimeInfo, flags)		\

-		(*(FUNC))((mimeInfo), (flags))

-

-#endif

-#endif /* MAC */

-

-#if defined(_WINDOWS)

-#define OSCALL WINAPI

-#else

-#if defined(__OS2__)

-#define OSCALL _System

-#else

-#define OSCALL

-#endif

-#endif

-

-#if defined( _WINDOWS ) || defined (__OS2__)

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-/* plugin meta member functions */

-#if defined(__OS2__)

-

-typedef struct _NPPluginData {   /* Alternate OS2 Plugin interface */

-    char *pMimeTypes;

-    char *pFileExtents;

-    char *pFileOpenTemplate;

-    char *pProductName;

-    char *pProductDescription;

-    unsigned long dwProductVersionMS;

-    unsigned long dwProductVersionLS;

-} NPPluginData;

-

-NPError OSCALL NP_GetPluginData(NPPluginData * pPluginData);

-

-#endif

-

-NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs);

-

-NPError OSCALL NP_Initialize(NPNetscapeFuncs* pFuncs);

-

-NPError OSCALL NP_Shutdown();

-

-char*	NP_GetMIMEDescription();

-

-#ifdef __cplusplus

-}

-#endif

-

-#endif /* _WINDOWS || __OS2__ */

-

-#if defined(__OS2__)

-#pragma pack()

-#endif

-

-#ifdef XP_UNIX

-

-#ifdef __cplusplus

-extern "C" {

-#endif

-

-/* plugin meta member functions */

-

-char*	NP_GetMIMEDescription(void);

-NPError	NP_Initialize(NPNetscapeFuncs*, NPPluginFuncs*);

-NPError	NP_Shutdown(void);

-NPError NP_GetValue(void *future, NPPVariable aVariable, void *aValue);

-

-#ifdef __cplusplus

-}

-#endif

-

-#endif /* XP_UNIX */

-

-#endif /* _NPUPP_H_ */

+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+/*
+ *  npupp.h $Revision: 3.20 $
+ *  function call mecahnics needed by platform specific glue code.
+ */
+
+
+#ifndef _NPUPP_H_
+#define _NPUPP_H_
+
+#if defined(__OS2__)
+#pragma pack(1)
+#endif
+
+#ifndef GENERATINGCFM
+#define GENERATINGCFM 0
+#endif
+
+#ifndef _NPAPI_H_
+#include "npapi.h"
+#endif
+
+#include "npruntime.h"
+
+#include "jri.h"
+
+/******************************************************************************************
+   plug-in function table macros
+ 	        for each function in and out of the plugin API we define
+                    typedef NPP_FooUPP
+					#define NewNPP_FooProc
+					#define CallNPP_FooProc
+			for mac, define the UPP magic for PPC/68K calling
+ *******************************************************************************************/
+
+
+/* NPP_Initialize */
+
+#define _NPUPP_USE_UPP_ (TARGET_RT_MAC_CFM && !TARGET_API_MAC_CARBON)
+
+#if _NPUPP_USE_UPP_
+typedef UniversalProcPtr NPP_InitializeUPP;
+
+enum {
+	uppNPP_InitializeProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(0))		
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPP_InitializeProc(FUNC)		\
+		(NPP_InitializeUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_InitializeProcInfo, GetCurrentArchitecture())
+#define CallNPP_InitializeProc(FUNC)		\
+		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_InitializeProcInfo)
+		
+#else
+
+typedef void (* NP_LOADDS NPP_InitializeUPP)(void);
+#define NewNPP_InitializeProc(FUNC)		\
+		((NPP_InitializeUPP) (FUNC))
+#define CallNPP_InitializeProc(FUNC)		\
+		(*(FUNC))()
+
+#endif
+
+
+/* NPP_Shutdown */
+
+#if _NPUPP_USE_UPP_
+typedef UniversalProcPtr NPP_ShutdownUPP;
+
+enum {
+	uppNPP_ShutdownProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(0))		
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPP_ShutdownProc(FUNC)		\
+		(NPP_ShutdownUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_ShutdownProcInfo, GetCurrentArchitecture())
+#define CallNPP_ShutdownProc(FUNC)		\
+		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_ShutdownProcInfo)
+		
+#else
+
+typedef void (* NP_LOADDS NPP_ShutdownUPP)(void);
+#define NewNPP_ShutdownProc(FUNC)		\
+		((NPP_ShutdownUPP) (FUNC))
+#define CallNPP_ShutdownProc(FUNC)		\
+		(*(FUNC))()
+
+#endif
+
+
+/* NPP_New */
+
+#if _NPUPP_USE_UPP_
+typedef UniversalProcPtr NPP_NewUPP;
+
+enum {
+	uppNPP_NewProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPMIMEType)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(uint16)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(int16)))
+		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char **)))
+		| STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(char **)))
+		| STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(NPSavedData *)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+
+#define NewNPP_NewProc(FUNC)		\
+		(NPP_NewUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_NewProcInfo, GetCurrentArchitecture())
+#define CallNPP_NewProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_NewProcInfo, \
+								   (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7))
+#else
+
+typedef NPError	(* NP_LOADDS NPP_NewUPP)(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved);
+#define NewNPP_NewProc(FUNC)		\
+		((NPP_NewUPP) (FUNC))
+#define CallNPP_NewProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7))
+
+#endif
+
+
+/* NPP_Destroy */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_DestroyUPP;
+enum {
+	uppNPP_DestroyProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPSavedData **)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPP_DestroyProc(FUNC)		\
+		(NPP_DestroyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_DestroyProcInfo, GetCurrentArchitecture())
+#define CallNPP_DestroyProc(FUNC, ARG1, ARG2)		\
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_DestroyProcInfo, (ARG1), (ARG2))
+#else
+
+typedef NPError	(* NP_LOADDS NPP_DestroyUPP)(NPP instance, NPSavedData** save);
+#define NewNPP_DestroyProc(FUNC)		\
+		((NPP_DestroyUPP) (FUNC))
+#define CallNPP_DestroyProc(FUNC, ARG1, ARG2)		\
+		(*(FUNC))((ARG1), (ARG2))
+
+#endif
+
+
+/* NPP_SetWindow */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_SetWindowUPP;
+enum {
+	uppNPP_SetWindowProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPWindow *)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPP_SetWindowProc(FUNC)		\
+		(NPP_SetWindowUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_SetWindowProcInfo, GetCurrentArchitecture())
+#define CallNPP_SetWindowProc(FUNC, ARG1, ARG2)		\
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_SetWindowProcInfo, (ARG1), (ARG2))
+
+#else
+
+typedef NPError	(* NP_LOADDS NPP_SetWindowUPP)(NPP instance, NPWindow* window);
+#define NewNPP_SetWindowProc(FUNC)		\
+		((NPP_SetWindowUPP) (FUNC))
+#define CallNPP_SetWindowProc(FUNC, ARG1, ARG2)		\
+		(*(FUNC))((ARG1), (ARG2))
+
+#endif
+
+
+/* NPP_NewStream */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_NewStreamUPP;
+enum {
+	uppNPP_NewStreamProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPMIMEType)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPStream *)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPBool)))
+		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(uint16 *)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPP_NewStreamProc(FUNC)		\
+		(NPP_NewStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_NewStreamProcInfo, GetCurrentArchitecture())
+#define CallNPP_NewStreamProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5)		\
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_NewStreamProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5))
+#else
+
+typedef NPError	(* NP_LOADDS NPP_NewStreamUPP)(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16* stype);
+#define NewNPP_NewStreamProc(FUNC)		\
+		((NPP_NewStreamUPP) (FUNC))
+#define CallNPP_NewStreamProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5) \
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5))
+#endif
+
+
+/* NPP_DestroyStream */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_DestroyStreamUPP;
+enum {
+	uppNPP_DestroyStreamProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPReason)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPP_DestroyStreamProc(FUNC)		\
+		(NPP_DestroyStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_DestroyStreamProcInfo, GetCurrentArchitecture())
+#define CallNPP_DestroyStreamProc(FUNC,  NPParg, NPStreamPtr, NPReasonArg)		\
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_DestroyStreamProcInfo, (NPParg), (NPStreamPtr), (NPReasonArg))
+
+#else
+
+typedef NPError	(* NP_LOADDS NPP_DestroyStreamUPP)(NPP instance, NPStream* stream, NPReason reason);
+#define NewNPP_DestroyStreamProc(FUNC)		\
+		((NPP_DestroyStreamUPP) (FUNC))
+#define CallNPP_DestroyStreamProc(FUNC,  NPParg, NPStreamPtr, NPReasonArg)		\
+		(*(FUNC))((NPParg), (NPStreamPtr), (NPReasonArg))
+
+#endif
+
+
+/* NPP_WriteReady */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_WriteReadyUPP;
+enum {
+	uppNPP_WriteReadyProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(int32)))
+};
+#define NewNPP_WriteReadyProc(FUNC)		\
+		(NPP_WriteReadyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_WriteReadyProcInfo, GetCurrentArchitecture())
+#define CallNPP_WriteReadyProc(FUNC,  NPParg, NPStreamPtr)		\
+		(int32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_WriteReadyProcInfo, (NPParg), (NPStreamPtr))
+
+#else
+
+typedef int32 (* NP_LOADDS NPP_WriteReadyUPP)(NPP instance, NPStream* stream);
+#define NewNPP_WriteReadyProc(FUNC)		\
+		((NPP_WriteReadyUPP) (FUNC))
+#define CallNPP_WriteReadyProc(FUNC,  NPParg, NPStreamPtr)		\
+		(*(FUNC))((NPParg), (NPStreamPtr))
+
+#endif
+
+
+/* NPP_Write */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_WriteUPP;
+enum {
+	uppNPP_WriteProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(int32)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(int32)))
+		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(void*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(int32)))
+};
+#define NewNPP_WriteProc(FUNC)		\
+		(NPP_WriteUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_WriteProcInfo, GetCurrentArchitecture())
+#define CallNPP_WriteProc(FUNC,  NPParg, NPStreamPtr, offsetArg, lenArg, bufferPtr)		\
+		(int32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_WriteProcInfo, (NPParg), (NPStreamPtr), (offsetArg), (lenArg), (bufferPtr))
+
+#else
+
+typedef int32 (* NP_LOADDS NPP_WriteUPP)(NPP instance, NPStream* stream, int32 offset, int32 len, void* buffer);
+#define NewNPP_WriteProc(FUNC)		\
+		((NPP_WriteUPP) (FUNC))
+#define CallNPP_WriteProc(FUNC,  NPParg, NPStreamPtr, offsetArg, lenArg, bufferPtr)		\
+		(*(FUNC))((NPParg), (NPStreamPtr), (offsetArg), (lenArg), (bufferPtr))
+
+#endif
+
+
+/* NPP_StreamAsFile */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_StreamAsFileUPP;
+enum {
+	uppNPP_StreamAsFileProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char *)))
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+#define NewNPP_StreamAsFileProc(FUNC)		\
+		(NPP_StreamAsFileUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_StreamAsFileProcInfo, GetCurrentArchitecture())
+#define CallNPP_StreamAsFileProc(FUNC, ARG1, ARG2, ARG3)		\
+		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_StreamAsFileProcInfo, (ARG1), (ARG2), (ARG3))
+
+#else
+
+typedef void (* NP_LOADDS NPP_StreamAsFileUPP)(NPP instance, NPStream* stream, const char* fname);
+#define NewNPP_StreamAsFileProc(FUNC)		\
+		((NPP_StreamAsFileUPP) (FUNC))
+#define CallNPP_StreamAsFileProc(FUNC,  ARG1, ARG2, ARG3)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3))
+#endif
+
+
+/* NPP_Print */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_PrintUPP;
+enum {
+	uppNPP_PrintProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPrint *)))
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+#define NewNPP_PrintProc(FUNC)		\
+		(NPP_PrintUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_PrintProcInfo, GetCurrentArchitecture())
+#define CallNPP_PrintProc(FUNC,  NPParg, voidPtr)		\
+		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_PrintProcInfo, (NPParg), (voidPtr))
+
+#else
+
+typedef void (* NP_LOADDS NPP_PrintUPP)(NPP instance, NPPrint* platformPrint);
+#define NewNPP_PrintProc(FUNC)		\
+		((NPP_PrintUPP) (FUNC))
+#define CallNPP_PrintProc(FUNC,  NPParg, NPPrintArg)		\
+		(*(FUNC))((NPParg), (NPPrintArg))
+
+#endif
+
+
+/* NPP_HandleEvent */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_HandleEventUPP;
+enum {
+	uppNPP_HandleEventProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(void *)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(int16)))
+};
+#define NewNPP_HandleEventProc(FUNC)		\
+		(NPP_HandleEventUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_HandleEventProcInfo, GetCurrentArchitecture())
+#define CallNPP_HandleEventProc(FUNC,  NPParg, voidPtr)		\
+		(int16)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_HandleEventProcInfo, (NPParg), (voidPtr))
+
+#else
+
+typedef int16 (* NP_LOADDS NPP_HandleEventUPP)(NPP instance, void* event);
+#define NewNPP_HandleEventProc(FUNC)		\
+		((NPP_HandleEventUPP) (FUNC))
+#define CallNPP_HandleEventProc(FUNC,  NPParg, voidPtr)		\
+		(*(FUNC))((NPParg), (voidPtr))
+
+#endif
+
+
+/* NPP_URLNotify */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_URLNotifyUPP;
+enum {
+	uppNPP_URLNotifyProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPReason)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(void*)))
+		| RESULT_SIZE(SIZE_CODE(SIZE_CODE(0)))
+};
+#define NewNPP_URLNotifyProc(FUNC)		\
+		(NPP_URLNotifyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_URLNotifyProcInfo, GetCurrentArchitecture())
+#define CallNPP_URLNotifyProc(FUNC,  ARG1, ARG2, ARG3, ARG4)		\
+		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_URLNotifyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4))
+
+#else
+
+typedef void (* NP_LOADDS NPP_URLNotifyUPP)(NPP instance, const char* url, NPReason reason, void* notifyData);
+#define NewNPP_URLNotifyProc(FUNC)		\
+		((NPP_URLNotifyUPP) (FUNC))
+#define CallNPP_URLNotifyProc(FUNC,  ARG1, ARG2, ARG3, ARG4)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))
+
+#endif
+
+
+/* NPP_GetValue */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_GetValueUPP;
+enum {
+	uppNPP_GetValueProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPVariable)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPP_GetValueProc(FUNC)		\
+		(NPP_GetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_GetValueProcInfo, GetCurrentArchitecture())
+#define CallNPP_GetValueProc(FUNC, ARG1, ARG2, ARG3) \
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_GetValueProcInfo, (ARG1), (ARG2), (ARG3))
+#else
+
+typedef NPError	(* NP_LOADDS NPP_GetValueUPP)(NPP instance, NPPVariable variable, void *ret_alue);
+#define NewNPP_GetValueProc(FUNC)		\
+		((NPP_GetValueUPP) (FUNC))
+#define CallNPP_GetValueProc(FUNC, ARG1, ARG2, ARG3)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3))
+#endif
+
+
+/* NPP_SetValue */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_SetValueUPP;
+enum {
+	uppNPP_SetValueProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPNVariable)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPP_SetValueProc(FUNC)		\
+		(NPP_SetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_SetValueProcInfo, GetCurrentArchitecture())
+#define CallNPP_SetValueProc(FUNC, ARG1, ARG2, ARG3) \
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPP_SetValueProcInfo, (ARG1), (ARG2), (ARG3))
+#else
+
+typedef NPError	(* NP_LOADDS NPP_SetValueUPP)(NPP instance, NPNVariable variable, void *ret_alue);
+#define NewNPP_SetValueProc(FUNC)		\
+		((NPP_SetValueUPP) (FUNC))
+#define CallNPP_SetValueProc(FUNC, ARG1, ARG2, ARG3)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3))
+#endif
+
+
+/*
+ *  Netscape entry points
+ */
+
+
+/* NPN_GetValue */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_GetValueUPP;
+enum {
+	uppNPN_GetValueProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPNVariable)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPN_GetValueProc(FUNC)		\
+		(NPN_GetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetValueProcInfo, GetCurrentArchitecture())
+#define CallNPN_GetValueProc(FUNC, ARG1, ARG2, ARG3) \
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetValueProcInfo, (ARG1), (ARG2), (ARG3))
+#else
+
+typedef NPError	(* NP_LOADDS NPN_GetValueUPP)(NPP instance, NPNVariable variable, void *ret_alue);
+#define NewNPN_GetValueProc(FUNC)		\
+		((NPN_GetValueUPP) (FUNC))
+#define CallNPN_GetValueProc(FUNC, ARG1, ARG2, ARG3)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3))
+#endif
+
+
+/* NPN_SetValue */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_SetValueUPP;
+enum {
+	uppNPN_SetValueProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPVariable)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(void *)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPN_SetValueProc(FUNC)		\
+		(NPN_SetValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_SetValueProcInfo, GetCurrentArchitecture())
+#define CallNPN_SetValueProc(FUNC, ARG1, ARG2, ARG3) \
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_SetValueProcInfo, (ARG1), (ARG2), (ARG3))
+#else
+
+typedef NPError	(* NP_LOADDS NPN_SetValueUPP)(NPP instance, NPPVariable variable, void *ret_alue);
+#define NewNPN_SetValueProc(FUNC)		\
+		((NPN_SetValueUPP) (FUNC))
+#define CallNPN_SetValueProc(FUNC, ARG1, ARG2, ARG3)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3))
+#endif
+
+
+/* NPN_GetUrlNotify */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_GetURLNotifyUPP;
+enum {
+	uppNPN_GetURLNotifyProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(void*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPN_GetURLNotifyProc(FUNC)		\
+		(NPN_GetURLNotifyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetURLNotifyProcInfo, GetCurrentArchitecture())
+#define CallNPN_GetURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4) \
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetURLNotifyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4))
+#else
+
+typedef NPError	(* NP_LOADDS NPN_GetURLNotifyUPP)(NPP instance, const char* url, const char* window, void* notifyData);
+#define NewNPN_GetURLNotifyProc(FUNC)		\
+		((NPN_GetURLNotifyUPP) (FUNC))
+#define CallNPN_GetURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))
+#endif
+
+
+/* NPN_PostUrlNotify */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_PostURLNotifyUPP;
+enum {
+	uppNPN_PostURLNotifyProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(uint32)))
+		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(const char*)))
+		| STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPBool)))
+		| STACK_ROUTINE_PARAMETER(7, SIZE_CODE(sizeof(void*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPN_PostURLNotifyProc(FUNC)		\
+		(NPN_PostURLNotifyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PostURLNotifyProcInfo, GetCurrentArchitecture())
+#define CallNPN_PostURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PostURLNotifyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7))
+#else
+
+typedef NPError (* NP_LOADDS NPN_PostURLNotifyUPP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData);
+#define NewNPN_PostURLNotifyProc(FUNC)		\
+		((NPN_PostURLNotifyUPP) (FUNC))
+#define CallNPN_PostURLNotifyProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) \
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6), (ARG7))
+#endif
+
+
+/* NPN_GetUrl */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_GetURLUPP;
+enum {
+	uppNPN_GetURLProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPN_GetURLProc(FUNC)		\
+		(NPN_GetURLUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetURLProcInfo, GetCurrentArchitecture())
+#define CallNPN_GetURLProc(FUNC, ARG1, ARG2, ARG3) \
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetURLProcInfo, (ARG1), (ARG2), (ARG3))
+#else
+
+typedef NPError	(* NP_LOADDS NPN_GetURLUPP)(NPP instance, const char* url, const char* window);
+#define NewNPN_GetURLProc(FUNC)		\
+		((NPN_GetURLUPP) (FUNC))
+#define CallNPN_GetURLProc(FUNC, ARG1, ARG2, ARG3)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3))
+#endif
+
+
+/* NPN_PostUrl */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_PostURLUPP;
+enum {
+	uppNPN_PostURLProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const char*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char*)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(uint32)))
+		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(const char*)))
+		| STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPBool)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPN_PostURLProc(FUNC)		\
+		(NPN_PostURLUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PostURLProcInfo, GetCurrentArchitecture())
+#define CallNPN_PostURLProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PostURLProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6))
+#else
+
+typedef NPError (* NP_LOADDS NPN_PostURLUPP)(NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file);
+#define NewNPN_PostURLProc(FUNC)		\
+		((NPN_PostURLUPP) (FUNC))
+#define CallNPN_PostURLProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6))
+#endif
+
+
+/* NPN_RequestRead */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_RequestReadUPP;
+enum {
+	uppNPN_RequestReadProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPStream *)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPByteRange *)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPN_RequestReadProc(FUNC)		\
+		(NPN_RequestReadUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_RequestReadProcInfo, GetCurrentArchitecture())
+#define CallNPN_RequestReadProc(FUNC,  stream, range)		\
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_RequestReadProcInfo, (stream), (range))
+
+#else
+
+typedef NPError	(* NP_LOADDS NPN_RequestReadUPP)(NPStream* stream, NPByteRange* rangeList);
+#define NewNPN_RequestReadProc(FUNC)		\
+		((NPN_RequestReadUPP) (FUNC))
+#define CallNPN_RequestReadProc(FUNC, stream, range)		\
+		(*(FUNC))((stream), (range))
+
+#endif
+
+
+/* NPN_NewStream */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_NewStreamUPP;
+enum {
+	uppNPN_NewStreamProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPMIMEType)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(const char *)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPStream **)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPN_NewStreamProc(FUNC)		\
+		(NPN_NewStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_NewStreamProcInfo, GetCurrentArchitecture())
+#define CallNPN_NewStreamProc(FUNC, npp, type, window, stream)		\
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_NewStreamProcInfo, (npp), (type), (window), (stream))	
+
+#else
+
+typedef NPError	(* NP_LOADDS NPN_NewStreamUPP)(NPP instance, NPMIMEType type, const char* window, NPStream** stream);
+#define NewNPN_NewStreamProc(FUNC)		\
+		((NPN_NewStreamUPP) (FUNC))
+#define CallNPN_NewStreamProc(FUNC, npp, type, window, stream)		\
+		(*(FUNC))((npp), (type), (window), (stream))
+
+#endif
+
+
+/* NPN_Write */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_WriteUPP;
+enum {
+	uppNPN_WriteProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(int32)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(void*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(int32)))
+};
+#define NewNPN_WriteProc(FUNC)		\
+		(NPN_WriteUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_WriteProcInfo, GetCurrentArchitecture())
+#define CallNPN_WriteProc(FUNC, npp, stream, len, buffer)		\
+		(int32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_WriteProcInfo, (npp), (stream), (len), (buffer))	
+
+#else
+
+typedef int32 (* NP_LOADDS NPN_WriteUPP)(NPP instance, NPStream* stream, int32 len, void* buffer);
+#define NewNPN_WriteProc(FUNC)		\
+		((NPN_WriteUPP) (FUNC))
+#define CallNPN_WriteProc(FUNC, npp, stream, len, buffer)		\
+		(*(FUNC))((npp), (stream), (len), (buffer))
+
+#endif
+
+
+/* NPN_DestroyStream */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_DestroyStreamUPP;
+enum {
+	uppNPN_DestroyStreamProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP )))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPStream *)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPReason)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPN_DestroyStreamProc(FUNC)		\
+		(NPN_DestroyStreamUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_DestroyStreamProcInfo, GetCurrentArchitecture())
+#define CallNPN_DestroyStreamProc(FUNC, npp, stream, reason)		\
+		(NPError)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_DestroyStreamProcInfo, (npp), (stream), (reason))	
+
+#else
+
+typedef NPError (* NP_LOADDS NPN_DestroyStreamUPP)(NPP instance, NPStream* stream, NPReason reason);
+#define NewNPN_DestroyStreamProc(FUNC)		\
+		((NPN_DestroyStreamUPP) (FUNC))
+#define CallNPN_DestroyStreamProc(FUNC, npp, stream, reason)		\
+		(*(FUNC))((npp), (stream), (reason))
+
+#endif
+
+
+/* NPN_Status */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_StatusUPP;
+enum {
+	uppNPN_StatusProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char *)))
+};
+
+#define NewNPN_StatusProc(FUNC)		\
+		(NPN_StatusUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_StatusProcInfo, GetCurrentArchitecture())
+#define CallNPN_StatusProc(FUNC, npp, msg)		\
+		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_StatusProcInfo, (npp), (msg))	
+
+#else
+
+typedef void (* NP_LOADDS NPN_StatusUPP)(NPP instance, const char* message);
+#define NewNPN_StatusProc(FUNC)		\
+		((NPN_StatusUPP) (FUNC))
+#define CallNPN_StatusProc(FUNC, npp, msg)		\
+		(*(FUNC))((npp), (msg))	
+
+#endif
+
+
+/* NPN_UserAgent */
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_UserAgentUPP;
+enum {
+        uppNPN_UserAgentProcInfo = kThinkCStackBased
+                | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+                | RESULT_SIZE(SIZE_CODE(sizeof(const char *)))
+};
+
+#define NewNPN_UserAgentProc(FUNC)              \
+                (NPN_UserAgentUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_UserAgentProcInfo, GetCurrentArchitecture())
+#define CallNPN_UserAgentProc(FUNC, ARG1)               \
+                (const char*)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_UserAgentProcInfo, (ARG1))
+
+#else
+
+typedef const char*	(* NP_LOADDS NPN_UserAgentUPP)(NPP instance);
+#define NewNPN_UserAgentProc(FUNC)              \
+                ((NPN_UserAgentUPP) (FUNC))
+#define CallNPN_UserAgentProc(FUNC, ARG1)               \
+                (*(FUNC))((ARG1))
+
+#endif
+
+
+/* NPN_MemAlloc */
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_MemAllocUPP;
+enum {
+	uppNPN_MemAllocProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(uint32)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(void *)))
+};
+
+#define NewNPN_MemAllocProc(FUNC)		\
+		(NPN_MemAllocUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_MemAllocProcInfo, GetCurrentArchitecture())
+#define CallNPN_MemAllocProc(FUNC, ARG1)		\
+		(void*)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_MemAllocProcInfo, (ARG1))	
+
+#else
+
+typedef void* (* NP_LOADDS NPN_MemAllocUPP)(uint32 size);
+#define NewNPN_MemAllocProc(FUNC)		\
+		((NPN_MemAllocUPP) (FUNC))
+#define CallNPN_MemAllocProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))	
+
+#endif
+
+
+/* NPN__MemFree */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_MemFreeUPP;
+enum {
+	uppNPN_MemFreeProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(void *)))
+};
+
+#define NewNPN_MemFreeProc(FUNC)		\
+		(NPN_MemFreeUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_MemFreeProcInfo, GetCurrentArchitecture())
+#define CallNPN_MemFreeProc(FUNC, ARG1)		\
+		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_MemFreeProcInfo, (ARG1))
+
+#else
+
+typedef void (* NP_LOADDS NPN_MemFreeUPP)(void* ptr);
+#define NewNPN_MemFreeProc(FUNC)		\
+		((NPN_MemFreeUPP) (FUNC))
+#define CallNPN_MemFreeProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))	
+
+#endif
+
+
+/* NPN_MemFlush */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_MemFlushUPP;
+enum {
+	uppNPN_MemFlushProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(uint32)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(uint32)))
+};
+
+#define NewNPN_MemFlushProc(FUNC)		\
+		(NPN_MemFlushUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_MemFlushProcInfo, GetCurrentArchitecture())
+#define CallNPN_MemFlushProc(FUNC, ARG1)		\
+		(uint32)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_MemFlushProcInfo, (ARG1))	
+
+#else
+
+typedef uint32 (* NP_LOADDS NPN_MemFlushUPP)(uint32 size);
+#define NewNPN_MemFlushProc(FUNC)		\
+		((NPN_MemFlushUPP) (FUNC))
+#define CallNPN_MemFlushProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))	
+
+#endif
+
+
+
+/* NPN_ReloadPlugins */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_ReloadPluginsUPP;
+enum {
+	uppNPN_ReloadPluginsProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPBool)))
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPN_ReloadPluginsProc(FUNC)		\
+		(NPN_ReloadPluginsUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ReloadPluginsProcInfo, GetCurrentArchitecture())
+#define CallNPN_ReloadPluginsProc(FUNC, ARG1)		\
+		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ReloadPluginsProcInfo, (ARG1))	
+
+#else
+
+typedef void (* NP_LOADDS NPN_ReloadPluginsUPP)(NPBool reloadPages);
+#define NewNPN_ReloadPluginsProc(FUNC)		\
+		((NPN_ReloadPluginsUPP) (FUNC))
+#define CallNPN_ReloadPluginsProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))	
+
+#endif
+
+/* NPN_GetJavaEnv */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_GetJavaEnvUPP;
+enum {
+	uppNPN_GetJavaEnvProcInfo = kThinkCStackBased
+		| RESULT_SIZE(SIZE_CODE(sizeof(JRIEnv*)))
+};
+
+#define NewNPN_GetJavaEnvProc(FUNC)		\
+		(NPN_GetJavaEnvUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetJavaEnvProcInfo, GetCurrentArchitecture())
+#define CallNPN_GetJavaEnvProc(FUNC)		\
+		(JRIEnv*)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetJavaEnvProcInfo)	
+
+#else
+typedef JRIEnv* (* NP_LOADDS NPN_GetJavaEnvUPP)(void);
+#define NewNPN_GetJavaEnvProc(FUNC)		\
+		((NPN_GetJavaEnvUPP) (FUNC))
+#define CallNPN_GetJavaEnvProc(FUNC)		\
+		(*(FUNC))()	
+
+#endif
+
+
+/* NPN_GetJavaPeer */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_GetJavaPeerUPP;
+enum {
+	uppNPN_GetJavaPeerProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(jref)))
+};
+
+#define NewNPN_GetJavaPeerProc(FUNC)		\
+		(NPN_GetJavaPeerUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetJavaPeerProcInfo, GetCurrentArchitecture())
+#define CallNPN_GetJavaPeerProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetJavaPeerProcInfo, (ARG1))	
+
+#else
+
+typedef jref (* NP_LOADDS NPN_GetJavaPeerUPP)(NPP instance);
+#define NewNPN_GetJavaPeerProc(FUNC)		\
+		((NPN_GetJavaPeerUPP) (FUNC))
+#define CallNPN_GetJavaPeerProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))	
+
+#endif
+
+/* NPN_InvalidateRect */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_InvalidateRectUPP;
+enum {
+	uppNPN_InvalidateRectProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPRect *)))
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPN_InvalidateRectProc(FUNC)		\
+		(NPN_InvalidateRectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvalidateRectProcInfo, GetCurrentArchitecture())
+#define CallNPN_InvalidateRectProc(FUNC, ARG1, ARG2)		\
+		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvalidateRectProcInfo, (ARG1), (ARG2))	
+
+#else
+
+typedef void (* NP_LOADDS NPN_InvalidateRectUPP)(NPP instance, NPRect *rect);
+#define NewNPN_InvalidateRectProc(FUNC)		\
+		((NPN_InvalidateRectUPP) (FUNC))
+#define CallNPN_InvalidateRectProc(FUNC, ARG1, ARG2)		\
+		(*(FUNC))((ARG1), (ARG2))	
+
+#endif
+
+
+/* NPN_InvalidateRegion */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_InvalidateRegionUPP;
+enum {
+	uppNPN_InvalidateRegionProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPRegion)))
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPN_InvalidateRegionProc(FUNC)		\
+		(NPN_InvalidateRegionUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvalidateRegionProcInfo, GetCurrentArchitecture())
+#define CallNPN_InvalidateRegionProc(FUNC, ARG1, ARG2)		\
+		(void)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvalidateRegionProcInfo, (ARG1), (ARG2))	
+
+#else
+
+typedef void (* NP_LOADDS NPN_InvalidateRegionUPP)(NPP instance, NPRegion region);
+#define NewNPN_InvalidateRegionProc(FUNC)		\
+		((NPN_InvalidateRegionUPP) (FUNC))
+#define CallNPN_InvalidateRegionProc(FUNC, ARG1, ARG2)		\
+		(*(FUNC))((ARG1), (ARG2))	
+
+#endif
+
+/* NPN_ForceRedraw */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_ForceRedrawUPP;
+enum {
+	uppNPN_ForceRedrawProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(0)))
+};
+
+#define NewNPN_ForceRedrawProc(FUNC)		\
+		(NPN_ForceRedrawUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ForceRedrawProcInfo, GetCurrentArchitecture())
+#define CallNPN_ForceRedrawProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ForceRedrawProcInfo, (ARG1))	
+
+#else
+
+typedef void (* NP_LOADDS NPN_ForceRedrawUPP)(NPP instance);
+#define NewNPN_ForceRedrawProc(FUNC)		\
+		((NPN_ForceRedrawUPP) (FUNC))
+#define CallNPN_ForceRedrawProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))	
+
+#endif
+
+/* NPN_GetStringIdentifier */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_GetStringIdentifierUPP;
+enum {
+	uppNPN_GetStringIdentifierProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const NPUTF8*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPIdentifier)))
+};
+
+#define NewNPN_GetStringIdentifierProc(FUNC)		\
+		(NPN_GetStringIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetStringIdentifierProcInfo, GetCurrentArchitecture())
+#define CallNPN_GetStringIdentifierProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetStringIdentifierProcInfo, (ARG1))	
+
+#else
+
+typedef NPIdentifier (* NP_LOADDS NPN_GetStringIdentifierUPP)(const NPUTF8* name);
+#define NewNPN_GetStringIdentifierProc(FUNC)		\
+		((NPN_GetStringIdentifierUPP) (FUNC))
+#define CallNPN_GetStringIdentifierProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))
+
+#endif
+
+/* NPN_GetStringIdentifiers */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_GetStringIdentifiersUPP;
+enum {
+	uppNPN_GetStringIdentifiersProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(const NPUTF8**)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(int32_t)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier*)))
+        | RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPN_GetStringIdentifiersProc(FUNC)		\
+		(NPN_GetStringIdentifiersUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetStringIdentifiersProcInfo, GetCurrentArchitecture())
+#define CallNPN_GetStringIdentifiersProc(FUNC, ARG1, ARG2, ARG3)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetStringIdentifiersProcInfo, (ARG1), (ARG2), (ARG3))	
+
+#else
+
+typedef void (* NP_LOADDS NPN_GetStringIdentifiersUPP)(const NPUTF8** names,
+                                                 int32_t nameCount,
+                                                 NPIdentifier* identifiers);
+#define NewNPN_GetStringIdentifiersProc(FUNC)		\
+		((NPN_GetStringIdentifiersUPP) (FUNC))
+#define CallNPN_GetStringIdentifiersProc(FUNC, ARG1, ARG2, ARG3)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3))
+
+#endif
+
+/* NPN_GetIntIdentifier */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_GetIntIdentifierUPP;
+enum {
+	uppNPN_GetIntIdentifierProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(int32_t)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPIdentifier)))
+};
+
+#define NewNPN_GetIntIdentifierProc(FUNC)		\
+		(NPN_GetIntIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetIntIdentifierProcInfo, GetCurrentArchitecture())
+#define CallNPN_GetIntIdentifierProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetIntIdentifierProcInfo, (ARG1))	
+
+#else
+
+typedef NPIdentifier (* NP_LOADDS NPN_GetIntIdentifierUPP)(int32_t intid);
+#define NewNPN_GetIntIdentifierProc(FUNC)		\
+		((NPN_GetIntIdentifierUPP) (FUNC))
+#define CallNPN_GetIntIdentifierProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))
+
+#endif
+
+/* NPN_IdentifierIsString */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_IdentifierIsStringUPP;
+enum {
+	uppNPN_IdentifierIsStringProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPIdentifier identifier)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))
+};
+
+#define NewNPN_IdentifierIsStringProc(FUNC)		\
+		(NPN_IdentifierIsStringUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_IdentifierIsStringProcInfo, GetCurrentArchitecture())
+#define CallNPN_IdentifierIsStringProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_IdentifierIsStringProcInfo, (ARG1))	
+
+#else
+
+typedef bool (* NP_LOADDS NPN_IdentifierIsStringUPP)(NPIdentifier identifier);
+#define NewNPN_IdentifierIsStringProc(FUNC)		\
+		((NPN_IdentifierIsStringUPP) (FUNC))
+#define CallNPN_IdentifierIsStringProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))
+
+#endif
+
+/* NPN_UTF8FromIdentifier */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_UTF8FromIdentifierUPP;
+enum {
+	uppNPN_UTF8FromIdentifierProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPIdentifier)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPUTF8*)))
+};
+
+#define NewNPN_UTF8FromIdentifierProc(FUNC)		\
+		(NPN_UTF8FromIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_UTF8FromIdentifierProcInfo, GetCurrentArchitecture())
+#define CallNPN_UTF8FromIdentifierProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_UTF8FromIdentifierProcInfo, (ARG1))	
+
+#else
+
+typedef NPUTF8* (* NP_LOADDS NPN_UTF8FromIdentifierUPP)(NPIdentifier identifier);
+#define NewNPN_UTF8FromIdentifierProc(FUNC)		\
+		((NPN_UTF8FromIdentifierUPP) (FUNC))
+#define CallNPN_UTF8FromIdentifierProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))
+
+#endif
+
+/* NPN_IntFromIdentifier */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_IntFromIdentifierUPP;
+enum {
+	uppNPN_IntFromIdentifierProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPIdentifier)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(int32_t)))
+};
+
+#define NewNPN_IntFromIdentifierProc(FUNC)		\
+		(NPN_IntFromIdentifierUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_IntFromIdentifierProcInfo, GetCurrentArchitecture())
+#define CallNPN_IntFromIdentifierProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_IntFromIdentifierProcInfo, (ARG1))	
+
+#else
+
+typedef int32_t (* NP_LOADDS NPN_IntFromIdentifierUPP)(NPIdentifier identifier);
+#define NewNPN_IntFromIdentifierProc(FUNC)		\
+		((NPN_IntFromIdentifierUPP) (FUNC))
+#define CallNPN_IntFromIdentifierProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))
+
+#endif
+
+/* NPN_CreateObject */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_CreateObjectUPP;
+enum {
+	uppNPN_CreateObjectProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPClass*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPObject*)))
+};
+
+#define NewNPN_CreateObjectProc(FUNC)		\
+		(NPN_CreateObjectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_CreateObjectProcInfo, GetCurrentArchitecture())
+#define CallNPN_CreateObjectProc(FUNC, ARG1, ARG2)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_CreateObjectProcInfo, (ARG1), (ARG2))	
+
+#else
+
+typedef NPObject* (* NP_LOADDS NPN_CreateObjectUPP)(NPP npp, NPClass *aClass);
+#define NewNPN_CreateObjectProc(FUNC)		\
+		((NPN_CreateObjectUPP) (FUNC))
+#define CallNPN_CreateObjectProc(FUNC, ARG1, ARG2)		\
+		(*(FUNC))((ARG1), (ARG2))
+
+#endif
+
+/* NPN_RetainObject */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_RetainObjectUPP;
+enum {
+	uppNPN_RetainObjectProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPObject*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPObject*)))
+};
+
+#define NewNPN_RetainObjectProc(FUNC)		\
+		(NPN_RetainObjectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_RetainObjectProcInfo, GetCurrentArchitecture())
+#define CallNPN_RetainObjectProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_RetainObjectProcInfo, (ARG1))	
+
+#else
+
+typedef NPObject* (* NP_LOADDS NPN_RetainObjectUPP)(NPObject *obj);
+#define NewNPN_RetainObjectProc(FUNC)		\
+		((NPN_RetainObjectUPP) (FUNC))
+#define CallNPN_RetainObjectProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))
+
+#endif
+
+/* NPN_ReleaseObject */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_ReleaseObjectUPP;
+enum {
+	uppNPN_ReleaseObjectProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPObject*)))
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPN_ReleaseObjectProc(FUNC)		\
+		(NPN_ReleaseObjectUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ReleaseObjectProcInfo, GetCurrentArchitecture())
+#define CallNPN_ReleaseObjectProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ReleaseObjectProcInfo, (ARG1))
+
+#else
+
+typedef void (* NP_LOADDS NPN_ReleaseObjectUPP)(NPObject *obj);
+#define NewNPN_ReleaseObjectProc(FUNC)		\
+		((NPN_ReleaseObjectUPP) (FUNC))
+#define CallNPN_ReleaseObjectProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))
+
+#endif
+
+/* NPN_Invoke */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_InvokeUPP;
+enum {
+	uppNPN_InvokeProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(const NPVariant*)))
+		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(uint32_t)))
+		| STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPVariant*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))
+};
+
+#define NewNPN_InvokeProc(FUNC)		\
+		(NPN_InvokeUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvokeProcInfo, GetCurrentArchitecture())
+#define CallNPN_InvokeProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvokeProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6))
+
+#else
+
+typedef bool (* NP_LOADDS NPN_InvokeUPP)(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
+#define NewNPN_InvokeProc(FUNC)		\
+		((NPN_InvokeUPP) (FUNC))
+#define CallNPN_InvokeProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5), (ARG6))
+
+#endif
+
+/* NPN_InvokeDefault */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_InvokeDefaultUPP;
+enum {
+	uppNPN_InvokeDefaultProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(const NPVariant*)))
+		| STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(uint32_t)))
+		| STACK_ROUTINE_PARAMETER(6, SIZE_CODE(sizeof(NPVariant*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))
+};
+
+#define NewNPN_InvokeDefaultProc(FUNC)		\
+		(NPN_InvokeDefaultUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_InvokeDefaultProcInfo, GetCurrentArchitecture())
+#define CallNPN_InvokeDefaultProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_InvokeDefaultProcInfo, (ARG1), (ARG2), (ARG3), (ARG4), (ARG5))
+
+#else
+
+typedef bool (* NP_LOADDS NPN_InvokeDefaultUPP)(NPP npp, NPObject* obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
+#define NewNPN_InvokeDefaultProc(FUNC)		\
+		((NPN_InvokeDefaultUPP) (FUNC))
+#define CallNPN_InvokeDefaultProc(FUNC, ARG1, ARG2, ARG3, ARG4, ARG5)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4), (ARG5))
+
+#endif
+
+/* NPN_Evaluate */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_EvaluateUPP;
+enum {
+	uppNPN_EvaluateProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPString*)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPVariant*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))
+};
+
+#define NewNPN_EvaluateProc(FUNC)		\
+		(NPN_EvaluateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_EvaluateProcInfo, GetCurrentArchitecture())
+#define CallNPN_EvaluateProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_EvaluateProcInfo, (ARG1), (ARG2), (ARG3), (ARG4))
+
+#else
+
+typedef bool (* NP_LOADDS NPN_EvaluateUPP)(NPP npp, NPObject *obj, NPString *script, NPVariant *result);
+#define NewNPN_EvaluateProc(FUNC)		\
+		((NPN_EvaluateUPP) (FUNC))
+#define CallNPN_EvaluateProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))
+
+#endif
+
+/* NPN_GetProperty */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_GetPropertyUPP;
+enum {
+	uppNPN_GetPropertyProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(NPVariant*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))
+};
+
+#define NewNPN_GetPropertyProc(FUNC)		\
+		(NPN_GetPropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_GetPropertyProcInfo, GetCurrentArchitecture())
+#define CallNPN_GetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_GetPropertyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4))
+
+#else
+
+typedef bool (* NP_LOADDS NPN_GetPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName, NPVariant *result);
+#define NewNPN_GetPropertyProc(FUNC)		\
+		((NPN_GetPropertyUPP) (FUNC))
+#define CallNPN_GetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))
+
+#endif
+
+/* NPN_SetProperty */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_SetPropertyUPP;
+enum {
+	uppNPN_SetPropertyProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))
+		| STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(const NPVariant*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))
+};
+
+#define NewNPN_SetPropertyProc(FUNC)		\
+		(NPN_SetPropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_SetPropertyProcInfo, GetCurrentArchitecture())
+#define CallNPN_SetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_SetPropertyProcInfo, (ARG1), (ARG2), (ARG3), (ARG4))
+
+#else
+
+typedef bool (* NP_LOADDS NPN_SetPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName, const NPVariant *value);
+#define NewNPN_SetPropertyProc(FUNC)		\
+		((NPN_SetPropertyUPP) (FUNC))
+#define CallNPN_SetPropertyProc(FUNC, ARG1, ARG2, ARG3, ARG4)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3), (ARG4))
+
+#endif
+
+/* NPN_RemoveProperty */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_RemovePropertyUPP;
+enum {
+	uppNPN_RemovePropertyProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))
+};
+
+#define NewNPN_RemovePropertyProc(FUNC)		\
+		(NPN_RemovePropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_RemovePropertyProcInfo, GetCurrentArchitecture())
+#define CallNPN_RemovePropertyProc(FUNC, ARG1, ARG2, ARG3)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_RemovePropertyProcInfo, (ARG1), (ARG2), (ARG3))
+
+#else
+
+typedef bool (* NP_LOADDS NPN_RemovePropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName);
+#define NewNPN_RemovePropertyProc(FUNC)		\
+		((NPN_RemovePropertyUPP) (FUNC))
+#define CallNPN_RemovePropertyProc(FUNC, ARG1, ARG2, ARG3)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3))
+
+#endif
+
+/* NPN_HasProperty */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_HasPropertyUPP;
+enum {
+	uppNPN_HasPropertyProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))
+};
+
+#define NewNPN_HasPropertyProc(FUNC)		\
+		(NPN_HasPropertyUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_HasPropertyProcInfo, GetCurrentArchitecture())
+#define CallNPN_HasPropertyProc(FUNC, ARG1, ARG2, ARG3)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_HasPropertyProcInfo, (ARG1), (ARG2), (ARG3))
+
+#else
+
+typedef bool (* NP_LOADDS NPN_HasPropertyUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName);
+#define NewNPN_HasPropertyProc(FUNC)		\
+		((NPN_HasPropertyUPP) (FUNC))
+#define CallNPN_HasPropertyProc(FUNC, ARG1, ARG2, ARG3)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3))
+
+#endif
+
+/* NPN_HasMethod */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_HasMethodUPP;
+enum {
+	uppNPN_HasMethodProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPObject*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPIdentifier)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(bool)))
+};
+
+#define NewNPN_HasMethodProc(FUNC)		\
+		(NPN_HasMethodUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_HasMethodProcInfo, GetCurrentArchitecture())
+#define CallNPN_HasMethodProc(FUNC, ARG1, ARG2, ARG3)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_HasMethodProcInfo, (ARG1), (ARG2), (ARG3))
+
+#else
+
+typedef bool (* NP_LOADDS NPN_HasMethodUPP)(NPP npp, NPObject *obj, NPIdentifier propertyName);
+#define NewNPN_HasMethodProc(FUNC)		\
+		((NPN_HasMethodUPP) (FUNC))
+#define CallNPN_HasMethodProc(FUNC, ARG1, ARG2, ARG3)		\
+		(*(FUNC))((ARG1), (ARG2), (ARG3))
+
+#endif
+
+/* NPN_ReleaseVariantValue */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_ReleaseVariantValue;
+enum {
+	uppNPN_ReleaseVariantValueProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPVariant*)))
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPN_ReleaseVariantValueProc(FUNC)		\
+		(NPN_ReleaseVariantValueUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_ReleaseVariantValueProcInfo, GetCurrentArchitecture())
+#define CallNPN_ReleaseVariantValueProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_ReleaseVariantValueProcInfo, (ARG1))	
+
+#else
+
+typedef void (* NP_LOADDS NPN_ReleaseVariantValueUPP)(NPVariant *variant);
+#define NewNPN_ReleaseVariantValueProc(FUNC)		\
+		((NPN_ReleaseVariantValueUPP) (FUNC))
+#define CallNPN_ReleaseVariantValueProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))
+
+#endif
+
+/* NPN_SetException */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_SetExceptionUPP;
+enum {
+	uppNPN_SetExceptionProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPObject*)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(const NPUTF8*)))
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPN_SetExceptionProc(FUNC)		\
+		(NPN_SetExceptionUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_SetExceptionProcInfo, GetCurrentArchitecture())
+#define CallNPN_SetExceptionProc(FUNC, ARG1, ARG2)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_SetExceptionProcInfo, (ARG1), (ARG2))	
+
+#else
+
+typedef void (* NP_LOADDS NPN_SetExceptionUPP)(NPObject *obj, const NPUTF8 *message);
+#define NewNPN_SetExceptionProc(FUNC)		\
+		((NPN_SetExceptionUPP) (FUNC))
+#define CallNPN_SetExceptionProc(FUNC, ARG1, ARG2)		\
+		(*(FUNC))((ARG1), (ARG2))	
+
+#endif
+
+/* NPN_PushPopupsEnabledStateUPP */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_PushPopupsEnabledStateUPP;
+enum {
+	uppNPN_PushPopupsEnabledStateProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+        | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPBool)))
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPN_PushPopupsEnabledStateProc(FUNC)		\
+		(NPN_PushPopupsEnabledStateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PushPopupsEnabledStateProcInfo, GetCurrentArchitecture())
+#define CallNPN_PushPopupsEnabledStateProc(FUNC, ARG1, ARG2)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PushPopupsEnabledStateProcInfo, (ARG1), (ARG2))
+
+#else
+
+typedef bool (* NP_LOADDS NPN_PushPopupsEnabledStateUPP)(NPP npp, NPBool enabled);
+#define NewNPN_PushPopupsEnabledStateProc(FUNC)		\
+		((NPN_PushPopupsEnabledStateUPP) (FUNC))
+#define CallNPN_PushPopupsEnabledStateProc(FUNC, ARG1, ARG2)		\
+		(*(FUNC))((ARG1), (ARG2))
+
+#endif
+
+/* NPN_PopPopupsEnabledState */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPN_PopPopupsEnabledStateUPP;
+enum {
+	uppNPN_PopPopupsEnabledStateProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPP)))
+		| RESULT_SIZE(SIZE_CODE(0))
+};
+
+#define NewNPN_PopPopupsEnabledStateProc(FUNC)		\
+		(NPN_PopPopupsEnabledStateUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPN_PopPopupsEnabledStateProcInfo, GetCurrentArchitecture())
+#define CallNPN_PopPopupsEnabledStateProc(FUNC, ARG1)		\
+		(jref)CallUniversalProc((UniversalProcPtr)(FUNC), uppNPN_PopPopupsEnabledStateProcInfo, (ARG1))
+
+#else
+
+typedef bool (* NP_LOADDS NPN_PopPopupsEnabledStateUPP)(NPP npp);
+#define NewNPN_PopPopupsEnabledStateProc(FUNC)		\
+		((NPN_PopPopupsEnabledStateUPP) (FUNC))
+#define CallNPN_PopPopupsEnabledStateProc(FUNC, ARG1)		\
+		(*(FUNC))((ARG1))
+
+#endif
+
+
+
+/******************************************************************************************
+ * The actual plugin function table definitions
+ *******************************************************************************************/
+
+#ifdef XP_MAC
+#if PRAGMA_STRUCT_ALIGN
+#pragma options align=mac68k
+#endif
+#endif
+
+typedef struct _NPPluginFuncs {
+    uint16 size;
+    uint16 version;
+    NPP_NewUPP newp;
+    NPP_DestroyUPP destroy;
+    NPP_SetWindowUPP setwindow;
+    NPP_NewStreamUPP newstream;
+    NPP_DestroyStreamUPP destroystream;
+    NPP_StreamAsFileUPP asfile;
+    NPP_WriteReadyUPP writeready;
+    NPP_WriteUPP write;
+    NPP_PrintUPP print;
+    NPP_HandleEventUPP event;
+    NPP_URLNotifyUPP urlnotify;
+    JRIGlobalRef javaClass;
+    NPP_GetValueUPP getvalue;
+    NPP_SetValueUPP setvalue;
+} NPPluginFuncs;
+
+typedef struct _NPNetscapeFuncs {
+    uint16 size;
+    uint16 version;
+    NPN_GetURLUPP geturl;
+    NPN_PostURLUPP posturl;
+    NPN_RequestReadUPP requestread;
+    NPN_NewStreamUPP newstream;
+    NPN_WriteUPP write;
+    NPN_DestroyStreamUPP destroystream;
+    NPN_StatusUPP status;
+    NPN_UserAgentUPP uagent;
+    NPN_MemAllocUPP memalloc;
+    NPN_MemFreeUPP memfree;
+    NPN_MemFlushUPP memflush;
+    NPN_ReloadPluginsUPP reloadplugins;
+    NPN_GetJavaEnvUPP getJavaEnv;
+    NPN_GetJavaPeerUPP getJavaPeer;
+    NPN_GetURLNotifyUPP geturlnotify;
+    NPN_PostURLNotifyUPP posturlnotify;
+    NPN_GetValueUPP getvalue;
+    NPN_SetValueUPP setvalue;
+    NPN_InvalidateRectUPP invalidaterect;
+    NPN_InvalidateRegionUPP invalidateregion;
+    NPN_ForceRedrawUPP forceredraw;
+    NPN_GetStringIdentifierUPP getstringidentifier;
+    NPN_GetStringIdentifiersUPP getstringidentifiers;
+    NPN_GetIntIdentifierUPP getintidentifier;
+    NPN_IdentifierIsStringUPP identifierisstring;
+    NPN_UTF8FromIdentifierUPP utf8fromidentifier;
+    NPN_IntFromIdentifierUPP intfromidentifier;
+    NPN_CreateObjectUPP createobject;
+    NPN_RetainObjectUPP retainobject;
+    NPN_ReleaseObjectUPP releaseobject;
+    NPN_InvokeUPP invoke;
+    NPN_InvokeDefaultUPP invokeDefault;
+    NPN_EvaluateUPP evaluate;
+    NPN_GetPropertyUPP getproperty;
+    NPN_SetPropertyUPP setproperty;
+    NPN_RemovePropertyUPP removeproperty;
+    NPN_HasPropertyUPP hasproperty;
+    NPN_HasMethodUPP hasmethod;
+    NPN_ReleaseVariantValueUPP releasevariantvalue;
+    NPN_SetExceptionUPP setexception;
+    NPN_PushPopupsEnabledStateUPP pushpopupsenabledstate;
+    NPN_PopPopupsEnabledStateUPP poppopupsenabledstate;
+} NPNetscapeFuncs;
+
+#ifdef XP_MAC
+#if PRAGMA_STRUCT_ALIGN
+#pragma options align=reset
+#endif
+#endif
+
+
+#if defined(XP_MAC) || defined(XP_MACOSX)
+/******************************************************************************************
+ * Mac platform-specific plugin glue stuff
+ *******************************************************************************************/
+
+/*
+ * Main entry point of the plugin.
+ * This routine will be called when the plugin is loaded. The function
+ * tables are passed in and the plugin fills in the NPPluginFuncs table
+ * and NPPShutdownUPP for Netscape's use.
+ */
+
+#if _NPUPP_USE_UPP_
+
+typedef UniversalProcPtr NPP_MainEntryUPP;
+enum {
+	uppNPP_MainEntryProcInfo = kThinkCStackBased
+		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(NPNetscapeFuncs*)))
+		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(NPPluginFuncs*)))
+		| STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(NPP_ShutdownUPP*)))
+		| RESULT_SIZE(SIZE_CODE(sizeof(NPError)))
+};
+#define NewNPP_MainEntryProc(FUNC)		\
+		(NPP_MainEntryUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNPP_MainEntryProcInfo, GetCurrentArchitecture())
+#define CallNPP_MainEntryProc(FUNC,  netscapeFunc, pluginFunc, shutdownUPP)		\
+		CallUniversalProc((UniversalProcPtr)(FUNC), (ProcInfoType)uppNPP_MainEntryProcInfo, (netscapeFunc), (pluginFunc), (shutdownUPP))
+
+#else
+
+typedef NPError (* NP_LOADDS NPP_MainEntryUPP)(NPNetscapeFuncs*, NPPluginFuncs*, NPP_ShutdownUPP*);
+#define NewNPP_MainEntryProc(FUNC)		\
+		((NPP_MainEntryUPP) (FUNC))
+#define CallNPP_MainEntryProc(FUNC,  netscapeFunc, pluginFunc, shutdownUPP)		\
+		(*(FUNC))((netscapeFunc), (pluginFunc), (shutdownUPP))
+
+#endif
+
+
+/*
+ * Mac version(s) of NP_GetMIMEDescription(const char *)
+ * These can be called to retreive MIME information from the plugin dynamically
+ *
+ * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way
+ *       to get mime info from the plugin only on OSX and may not be supported 
+ *       in furture version--use NP_GetMIMEDescription instead
+ */
+
+enum
+{
+ kBPSupportedMIMETypesStructVers_1    = 1
+};
+
+typedef struct _BPSupportedMIMETypes
+{
+ SInt32    structVersion;      /* struct version */
+ Handle    typeStrings;        /* STR# formated handle, allocated by plug-in */
+ Handle    infoStrings;        /* STR# formated handle, allocated by plug-in */
+} BPSupportedMIMETypes;
+OSErr BP_GetSupportedMIMETypes(BPSupportedMIMETypes *mimeInfo, UInt32 flags);
+
+#if _NPUPP_USE_UPP_
+
+#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescriptionRD"
+typedef UniversalProcPtr NP_GetMIMEDescriptionUPP;
+enum {
+	uppNP_GetMIMEDescEntryProc = kThinkCStackBased
+		| RESULT_SIZE(SIZE_CODE(sizeof(const char *)))
+};
+#define NewNP_GetMIMEDescEntryProc(FUNC)		\
+		(NP_GetMIMEDescriptionUPP) NewRoutineDescriptor((ProcPtr)(FUNC), uppNP_GetMIMEDescEntryProc, GetCurrentArchitecture())
+#define CallNP_GetMIMEDescEntryProc(FUNC)		\
+		(const char *)CallUniversalProc((UniversalProcPtr)(FUNC), (ProcInfoType)uppNP_GetMIMEDescEntryProc)
+
+
+#else  /* !_NPUPP_USE_UPP_ */
+
+ /* NP_GetMIMEDescription */
+#define NP_GETMIMEDESCRIPTION_NAME "NP_GetMIMEDescription"
+typedef const char* (* NP_LOADDS NP_GetMIMEDescriptionUPP)();
+#define NewNP_GetMIMEDescEntryProc(FUNC)		\
+		((NP_GetMIMEDescriptionUPP) (FUNC))
+#define CallNP_GetMIMEDescEntryProc(FUNC)		\
+		(*(FUNC))()
+/* BP_GetSupportedMIMETypes */
+typedef OSErr (* NP_LOADDS BP_GetSupportedMIMETypesUPP)(BPSupportedMIMETypes*, UInt32);
+#define NewBP_GetSupportedMIMETypesEntryProc(FUNC)		\
+		((BP_GetSupportedMIMETypesUPP) (FUNC))
+#define CallBP_GetMIMEDescEntryProc(FUNC,  mimeInfo, flags)		\
+		(*(FUNC))((mimeInfo), (flags))
+
+#endif
+#endif /* MAC */
+
+#if defined(_WINDOWS)
+#define OSCALL WINAPI
+#else
+#if defined(__OS2__)
+#define OSCALL _System
+#else
+#define OSCALL
+#endif
+#endif
+
+#if defined( _WINDOWS ) || defined (__OS2__)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* plugin meta member functions */
+#if defined(__OS2__)
+
+typedef struct _NPPluginData {   /* Alternate OS2 Plugin interface */
+    char *pMimeTypes;
+    char *pFileExtents;
+    char *pFileOpenTemplate;
+    char *pProductName;
+    char *pProductDescription;
+    unsigned long dwProductVersionMS;
+    unsigned long dwProductVersionLS;
+} NPPluginData;
+
+NPError OSCALL NP_GetPluginData(NPPluginData * pPluginData);
+
+#endif
+
+NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs);
+
+NPError OSCALL NP_Initialize(NPNetscapeFuncs* pFuncs);
+
+NPError OSCALL NP_Shutdown();
+
+char*	NP_GetMIMEDescription();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WINDOWS || __OS2__ */
+
+#if defined(__OS2__)
+#pragma pack()
+#endif
+
+#ifdef XP_UNIX
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* plugin meta member functions */
+
+char*	NP_GetMIMEDescription(void);
+NPError	NP_Initialize(NPNetscapeFuncs*, NPPluginFuncs*);
+NPError	NP_Shutdown(void);
+NPError NP_GetValue(void *future, NPPVariable aVariable, void *aValue);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* XP_UNIX */
+
+#endif /* _NPUPP_H_ */
diff --git a/third_party/gecko/include/obsolete/pralarm.h b/third_party/gecko/include/obsolete/pralarm.h
index 914a36b..20476e4 100644
--- a/third_party/gecko/include/obsolete/pralarm.h
+++ b/third_party/gecko/include/obsolete/pralarm.h
@@ -1,194 +1,194 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is the Netscape Portable Runtime (NSPR).

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998-2000

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/*

-** File:		pralarm.h

-** Description:	API to periodic alarms.

-**

-**

-** Alarms are defined to invoke some client specified function at 

-** a time in the future. The notification may be a one time event

-** or repeated at a fixed interval. The interval at which the next

-** notification takes place may be modified by the client code only

-** during the respective notification.

-**

-** The notification is delivered on a thread that is part of the

-** alarm context (PRAlarm). The thread will inherit the priority

-** of the Alarm creator.

-**

-** Any number of periodic alarms (PRAlarmID) may be created within

-** the context of a single alarm (PRAlarm). The notifications will be

-** scheduled as close to the desired time as possible.

-**

-** Repeating periodic notifies are expected to run at a fixed rate.

-** That rate is expressed as some number of notifies per period where

-** the period is much larger than a PRIntervalTime (see prinrval.h).

-*/

-

-#if !defined(pralarm_h)

-#define pralarm_h

-

-#include "prtypes.h"

-#include "prinrval.h"

-

-

-PR_BEGIN_EXTERN_C

-

-/**********************************************************************/

-/************************* TYPES AND CONSTANTS ************************/

-/**********************************************************************/

-

-typedef struct PRAlarm PRAlarm;

-typedef struct PRAlarmID PRAlarmID;

-

-typedef PRBool (PR_CALLBACK *PRPeriodicAlarmFn)(

-    PRAlarmID *id, void *clientData, PRUint32 late);

-

-/**********************************************************************/

-/****************************** FUNCTIONS *****************************/

-/**********************************************************************/

-

-/***********************************************************************

-** FUNCTION:    PR_CreateAlarm

-** DESCRIPTION:

-**  Create an alarm context.

-** INPUTS:      void

-** OUTPUTS:     None

-** RETURN:      PRAlarm*

-**  

-** SIDE EFFECTS:

-**  This creates an alarm context, which is an object used for subsequent

-**  notification creations. It also creates a thread that will be used to

-** deliver the notifications that are expected to be defined. The client

-** is resposible for destroying the context when appropriate.

-** RESTRICTIONS:

-**  None. 

-** MEMORY:      The object (PRAlarm) and a thread to support notifications.

-** ALGORITHM:   N/A

-***********************************************************************/

-NSPR_API(PRAlarm*) PR_CreateAlarm(void);

-

-/***********************************************************************

-** FUNCTION:    PR_DestroyAlarm

-** DESCRIPTION:

-**  Destroys the context created by PR_CreateAlarm().

-** INPUTS:      PRAlarm*

-** OUTPUTS:     None

-** RETURN:      PRStatus

-**  

-** SIDE EFFECTS:

-**  This destroys the context that was created by PR_CreateAlarm().

-**  If there are any active alarms (PRAlarmID), they will be cancelled.

-**  Once that is done, the thread that was used to deliver the alarms

-**  will be joined. 

-** RESTRICTIONS:

-**  None. 

-** MEMORY:      N/A

-** ALGORITHM:   N/A

-***********************************************************************/

-NSPR_API(PRStatus) PR_DestroyAlarm(PRAlarm *alarm);

-

-/***********************************************************************

-** FUNCTION:    PR_SetAlarm

-** DESCRIPTION:

-**  Creates a periodic notifier that is to be delivered to a specified

-**  function at some fixed interval.

-** INPUTS:      PRAlarm *alarm              Parent alarm context

-**              PRIntervalTime period       Interval over which the notifies

-**                                          are delivered.

-**              PRUint32 rate               The rate within the interval that

-**                                          the notifies will be delivered.

-**              PRPeriodicAlarmFn function  Entry point where the notifies

-**                                          will be delivered.

-** OUTPUTS:     None

-** RETURN:      PRAlarmID*                  Handle to the notifier just created

-**                                          or NULL if the request failed.

-**  

-** SIDE EFFECTS:

-**  A periodic notifier is created. The notifications will be delivered

-**  by the alarm's internal thread at a fixed interval whose rate is the

-**  number of interrupts per interval specified. The first notification

-**  will be delivered as soon as possible, and they will continue until

-**  the notifier routine indicates that they should cease of the alarm

-**  context is destroyed (PR_DestroyAlarm).

-** RESTRICTIONS:

-**  None. 

-** MEMORY:      Memory for the notifier object.

-** ALGORITHM:   The rate at which notifications are delivered are stated

-**              to be "'rate' notifies per 'interval'". The exact time of

-**              the notification is computed based on a epoch established

-**              when the notifier was set. Each notification is delivered

-**              not ealier than the epoch plus the fixed rate times the

-**              notification sequence number. Such notifications have the

-**              potential to be late by not more than 'interval'/'rate'.

-**              The amount of lateness of one notification is taken into

-**              account on the next in an attempt to avoid long term slew.  

-***********************************************************************/

-NSPR_API(PRAlarmID*) PR_SetAlarm(

-    PRAlarm *alarm, PRIntervalTime period, PRUint32 rate,

-    PRPeriodicAlarmFn function, void *clientData);

-

-/***********************************************************************

-** FUNCTION:    PR_ResetAlarm

-** DESCRIPTION:

-**  Resets an existing alarm.

-** INPUTS:      PRAlarmID *id               Identify of the notifier.

-**              PRIntervalTime period       Interval over which the notifies

-**                                          are delivered.

-**              PRUint32 rate               The rate within the interval that

-**                                          the notifies will be delivered.

-** OUTPUTS:     None

-** RETURN:      PRStatus                    Indication of completion.

-**  

-** SIDE EFFECTS:

-**  An existing alarm may have its period and rate redefined. The

-**  additional side effect is that the notifier's epoch is recomputed.

-**  The first notification delivered by the newly refreshed alarm is

-**  defined to be 'interval'/'rate' from the time of the reset.

-** RESTRICTIONS:

-**  This function may only be called in the notifier for that alarm.

-** MEMORY:      N/A.

-** ALGORITHM:   See PR_SetAlarm().  

-***********************************************************************/

-NSPR_API(PRStatus) PR_ResetAlarm(

-	PRAlarmID *id, PRIntervalTime period, PRUint32 rate);

-

-PR_END_EXTERN_C

-

-#endif /* !defined(pralarm_h) */

-

-/* prinrval.h */

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+** File:		pralarm.h
+** Description:	API to periodic alarms.
+**
+**
+** Alarms are defined to invoke some client specified function at 
+** a time in the future. The notification may be a one time event
+** or repeated at a fixed interval. The interval at which the next
+** notification takes place may be modified by the client code only
+** during the respective notification.
+**
+** The notification is delivered on a thread that is part of the
+** alarm context (PRAlarm). The thread will inherit the priority
+** of the Alarm creator.
+**
+** Any number of periodic alarms (PRAlarmID) may be created within
+** the context of a single alarm (PRAlarm). The notifications will be
+** scheduled as close to the desired time as possible.
+**
+** Repeating periodic notifies are expected to run at a fixed rate.
+** That rate is expressed as some number of notifies per period where
+** the period is much larger than a PRIntervalTime (see prinrval.h).
+*/
+
+#if !defined(pralarm_h)
+#define pralarm_h
+
+#include "prtypes.h"
+#include "prinrval.h"
+
+
+PR_BEGIN_EXTERN_C
+
+/**********************************************************************/
+/************************* TYPES AND CONSTANTS ************************/
+/**********************************************************************/
+
+typedef struct PRAlarm PRAlarm;
+typedef struct PRAlarmID PRAlarmID;
+
+typedef PRBool (PR_CALLBACK *PRPeriodicAlarmFn)(
+    PRAlarmID *id, void *clientData, PRUint32 late);
+
+/**********************************************************************/
+/****************************** FUNCTIONS *****************************/
+/**********************************************************************/
+
+/***********************************************************************
+** FUNCTION:    PR_CreateAlarm
+** DESCRIPTION:
+**  Create an alarm context.
+** INPUTS:      void
+** OUTPUTS:     None
+** RETURN:      PRAlarm*
+**  
+** SIDE EFFECTS:
+**  This creates an alarm context, which is an object used for subsequent
+**  notification creations. It also creates a thread that will be used to
+** deliver the notifications that are expected to be defined. The client
+** is resposible for destroying the context when appropriate.
+** RESTRICTIONS:
+**  None. 
+** MEMORY:      The object (PRAlarm) and a thread to support notifications.
+** ALGORITHM:   N/A
+***********************************************************************/
+NSPR_API(PRAlarm*) PR_CreateAlarm(void);
+
+/***********************************************************************
+** FUNCTION:    PR_DestroyAlarm
+** DESCRIPTION:
+**  Destroys the context created by PR_CreateAlarm().
+** INPUTS:      PRAlarm*
+** OUTPUTS:     None
+** RETURN:      PRStatus
+**  
+** SIDE EFFECTS:
+**  This destroys the context that was created by PR_CreateAlarm().
+**  If there are any active alarms (PRAlarmID), they will be cancelled.
+**  Once that is done, the thread that was used to deliver the alarms
+**  will be joined. 
+** RESTRICTIONS:
+**  None. 
+** MEMORY:      N/A
+** ALGORITHM:   N/A
+***********************************************************************/
+NSPR_API(PRStatus) PR_DestroyAlarm(PRAlarm *alarm);
+
+/***********************************************************************
+** FUNCTION:    PR_SetAlarm
+** DESCRIPTION:
+**  Creates a periodic notifier that is to be delivered to a specified
+**  function at some fixed interval.
+** INPUTS:      PRAlarm *alarm              Parent alarm context
+**              PRIntervalTime period       Interval over which the notifies
+**                                          are delivered.
+**              PRUint32 rate               The rate within the interval that
+**                                          the notifies will be delivered.
+**              PRPeriodicAlarmFn function  Entry point where the notifies
+**                                          will be delivered.
+** OUTPUTS:     None
+** RETURN:      PRAlarmID*                  Handle to the notifier just created
+**                                          or NULL if the request failed.
+**  
+** SIDE EFFECTS:
+**  A periodic notifier is created. The notifications will be delivered
+**  by the alarm's internal thread at a fixed interval whose rate is the
+**  number of interrupts per interval specified. The first notification
+**  will be delivered as soon as possible, and they will continue until
+**  the notifier routine indicates that they should cease of the alarm
+**  context is destroyed (PR_DestroyAlarm).
+** RESTRICTIONS:
+**  None. 
+** MEMORY:      Memory for the notifier object.
+** ALGORITHM:   The rate at which notifications are delivered are stated
+**              to be "'rate' notifies per 'interval'". The exact time of
+**              the notification is computed based on a epoch established
+**              when the notifier was set. Each notification is delivered
+**              not ealier than the epoch plus the fixed rate times the
+**              notification sequence number. Such notifications have the
+**              potential to be late by not more than 'interval'/'rate'.
+**              The amount of lateness of one notification is taken into
+**              account on the next in an attempt to avoid long term slew.  
+***********************************************************************/
+NSPR_API(PRAlarmID*) PR_SetAlarm(
+    PRAlarm *alarm, PRIntervalTime period, PRUint32 rate,
+    PRPeriodicAlarmFn function, void *clientData);
+
+/***********************************************************************
+** FUNCTION:    PR_ResetAlarm
+** DESCRIPTION:
+**  Resets an existing alarm.
+** INPUTS:      PRAlarmID *id               Identify of the notifier.
+**              PRIntervalTime period       Interval over which the notifies
+**                                          are delivered.
+**              PRUint32 rate               The rate within the interval that
+**                                          the notifies will be delivered.
+** OUTPUTS:     None
+** RETURN:      PRStatus                    Indication of completion.
+**  
+** SIDE EFFECTS:
+**  An existing alarm may have its period and rate redefined. The
+**  additional side effect is that the notifier's epoch is recomputed.
+**  The first notification delivered by the newly refreshed alarm is
+**  defined to be 'interval'/'rate' from the time of the reset.
+** RESTRICTIONS:
+**  This function may only be called in the notifier for that alarm.
+** MEMORY:      N/A.
+** ALGORITHM:   See PR_SetAlarm().  
+***********************************************************************/
+NSPR_API(PRStatus) PR_ResetAlarm(
+	PRAlarmID *id, PRIntervalTime period, PRUint32 rate);
+
+PR_END_EXTERN_C
+
+#endif /* !defined(pralarm_h) */
+
+/* prinrval.h */
diff --git a/third_party/gecko/include/obsolete/probslet.h b/third_party/gecko/include/obsolete/probslet.h
index 40e4440..374e696 100644
--- a/third_party/gecko/include/obsolete/probslet.h
+++ b/third_party/gecko/include/obsolete/probslet.h
@@ -1,175 +1,175 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is the Netscape Portable Runtime (NSPR).

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998-2000

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/*

-** A collection of things thought to be obsolete

-*/

-

-#if defined(PROBSLET_H)

-#else

-#define PROBSLET_H

-

-#include "prio.h"

-

-PR_BEGIN_EXTERN_C

-

-/*

-** Yield the current thread.  The proper function to use in place of

-** PR_Yield() is PR_Sleep() with an argument of PR_INTERVAL_NO_WAIT.

-*/

-NSPR_API(PRStatus) PR_Yield(void);

-

-/************************************************************************/

-/************* The following definitions are for select *****************/

-/************************************************************************/

-

-/*

-** The following is obsolete and will be deleted in the next release!

-** These are provided for compatibility, but are GUARANTEED to be slow.

-**

-** Override PR_MAX_SELECT_DESC if you need more space in the select set.

-*/

-#ifndef PR_MAX_SELECT_DESC

-#define PR_MAX_SELECT_DESC 1024

-#endif

-typedef struct PR_fd_set {

-    PRUint32      hsize;

-    PRFileDesc   *harray[PR_MAX_SELECT_DESC];

-    PRUint32      nsize;

-    PRInt32       narray[PR_MAX_SELECT_DESC];

-} PR_fd_set;

-

-/*

-*************************************************************************

-** FUNCTION:    PR_Select

-** DESCRIPTION:

-**

-** The call returns as soon as I/O is ready on one or more of the underlying

-** file/socket descriptors or an exceptional condition is pending. A count of the 

-** number of ready descriptors is returned unless a timeout occurs in which case 

-** zero is returned.  On return, PR_Select replaces the given descriptor sets with 

-** subsets consisting of those descriptors that are ready for the requested condition.

-** The total number of ready descriptors in all the sets is the return value.

-**

-** INPUTS:

-**   PRInt32 num             

-**       This argument is unused but is provided for select(unix) interface

-**       compatability.  All input PR_fd_set arguments are self-describing

-**       with its own maximum number of elements in the set.

-**                               

-**   PR_fd_set *readfds

-**       A set describing the io descriptors for which ready for reading

-**       condition is of interest.  

-**                               

-**   PR_fd_set *writefds

-**       A set describing the io descriptors for which ready for writing

-**       condition is of interest.  

-**                               

-**   PR_fd_set *exceptfds

-**       A set describing the io descriptors for which exception pending

-**       condition is of interest.  

-**

-**   Any of the above readfds, writefds or exceptfds may be given as NULL 

-**   pointers if no descriptors are of interest for that particular condition.                          

-**   

-**   PRIntervalTime timeout  

-**       Amount of time the call will block waiting for I/O to become ready. 

-**       If this time expires without any I/O becoming ready, the result will

-**       be zero.

-**

-** OUTPUTS:    

-**   PR_fd_set *readfds

-**       A set describing the io descriptors which are ready for reading.

-**                               

-**   PR_fd_set *writefds

-**       A set describing the io descriptors which are ready for writing.

-**                               

-**   PR_fd_set *exceptfds

-**       A set describing the io descriptors which have pending exception.

-**

-** RETURN:PRInt32

-**   Number of io descriptors with asked for conditions or zero if the function

-**   timed out or -1 on failure.  The reason for the failure is obtained by 

-**   calling PR_GetError().

-** XXX can we implement this on windoze and mac?

-**************************************************************************

-*/

-NSPR_API(PRInt32) PR_Select(

-    PRInt32 num, PR_fd_set *readfds, PR_fd_set *writefds,

-    PR_fd_set *exceptfds, PRIntervalTime timeout);

-

-/* 

-** The following are not thread safe for two threads operating on them at the

-** same time.

-**

-** The following routines are provided for manipulating io descriptor sets.

-** PR_FD_ZERO(&fdset) initializes a descriptor set fdset to the null set.

-** PR_FD_SET(fd, &fdset) includes a particular file descriptor fd in fdset.

-** PR_FD_CLR(fd, &fdset) removes a file descriptor fd from fdset.  

-** PR_FD_ISSET(fd, &fdset) is nonzero if file descriptor fd is a member of 

-** fdset, zero otherwise.

-**

-** PR_FD_NSET(osfd, &fdset) includes a particular native file descriptor osfd

-** in fdset.

-** PR_FD_NCLR(osfd, &fdset) removes a native file descriptor osfd from fdset.  

-** PR_FD_NISSET(osfd, &fdset) is nonzero if native file descriptor osfd is a member of 

-** fdset, zero otherwise.

-*/

-

-NSPR_API(void)        PR_FD_ZERO(PR_fd_set *set);

-NSPR_API(void)        PR_FD_SET(PRFileDesc *fd, PR_fd_set *set);

-NSPR_API(void)        PR_FD_CLR(PRFileDesc *fd, PR_fd_set *set);

-NSPR_API(PRInt32)     PR_FD_ISSET(PRFileDesc *fd, PR_fd_set *set);

-NSPR_API(void)        PR_FD_NSET(PRInt32 osfd, PR_fd_set *set);

-NSPR_API(void)        PR_FD_NCLR(PRInt32 osfd, PR_fd_set *set);

-NSPR_API(PRInt32)     PR_FD_NISSET(PRInt32 osfd, PR_fd_set *set);

-

-#ifndef NO_NSPR_10_SUPPORT

-#ifdef XP_MAC

-#include <stat.h>

-#else

-#include <sys/stat.h>

-#endif

-

-NSPR_API(PRInt32) PR_Stat(const char *path, struct stat *buf);

-#endif /* NO_NSPR_10_SUPPORT */

-

-PR_END_EXTERN_C

-

-#endif /* defined(PROBSLET_H) */

-

-/* probslet.h */

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+** A collection of things thought to be obsolete
+*/
+
+#if defined(PROBSLET_H)
+#else
+#define PROBSLET_H
+
+#include "prio.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+** Yield the current thread.  The proper function to use in place of
+** PR_Yield() is PR_Sleep() with an argument of PR_INTERVAL_NO_WAIT.
+*/
+NSPR_API(PRStatus) PR_Yield(void);
+
+/************************************************************************/
+/************* The following definitions are for select *****************/
+/************************************************************************/
+
+/*
+** The following is obsolete and will be deleted in the next release!
+** These are provided for compatibility, but are GUARANTEED to be slow.
+**
+** Override PR_MAX_SELECT_DESC if you need more space in the select set.
+*/
+#ifndef PR_MAX_SELECT_DESC
+#define PR_MAX_SELECT_DESC 1024
+#endif
+typedef struct PR_fd_set {
+    PRUint32      hsize;
+    PRFileDesc   *harray[PR_MAX_SELECT_DESC];
+    PRUint32      nsize;
+    PRInt32       narray[PR_MAX_SELECT_DESC];
+} PR_fd_set;
+
+/*
+*************************************************************************
+** FUNCTION:    PR_Select
+** DESCRIPTION:
+**
+** The call returns as soon as I/O is ready on one or more of the underlying
+** file/socket descriptors or an exceptional condition is pending. A count of the 
+** number of ready descriptors is returned unless a timeout occurs in which case 
+** zero is returned.  On return, PR_Select replaces the given descriptor sets with 
+** subsets consisting of those descriptors that are ready for the requested condition.
+** The total number of ready descriptors in all the sets is the return value.
+**
+** INPUTS:
+**   PRInt32 num             
+**       This argument is unused but is provided for select(unix) interface
+**       compatability.  All input PR_fd_set arguments are self-describing
+**       with its own maximum number of elements in the set.
+**                               
+**   PR_fd_set *readfds
+**       A set describing the io descriptors for which ready for reading
+**       condition is of interest.  
+**                               
+**   PR_fd_set *writefds
+**       A set describing the io descriptors for which ready for writing
+**       condition is of interest.  
+**                               
+**   PR_fd_set *exceptfds
+**       A set describing the io descriptors for which exception pending
+**       condition is of interest.  
+**
+**   Any of the above readfds, writefds or exceptfds may be given as NULL 
+**   pointers if no descriptors are of interest for that particular condition.                          
+**   
+**   PRIntervalTime timeout  
+**       Amount of time the call will block waiting for I/O to become ready. 
+**       If this time expires without any I/O becoming ready, the result will
+**       be zero.
+**
+** OUTPUTS:    
+**   PR_fd_set *readfds
+**       A set describing the io descriptors which are ready for reading.
+**                               
+**   PR_fd_set *writefds
+**       A set describing the io descriptors which are ready for writing.
+**                               
+**   PR_fd_set *exceptfds
+**       A set describing the io descriptors which have pending exception.
+**
+** RETURN:PRInt32
+**   Number of io descriptors with asked for conditions or zero if the function
+**   timed out or -1 on failure.  The reason for the failure is obtained by 
+**   calling PR_GetError().
+** XXX can we implement this on windoze and mac?
+**************************************************************************
+*/
+NSPR_API(PRInt32) PR_Select(
+    PRInt32 num, PR_fd_set *readfds, PR_fd_set *writefds,
+    PR_fd_set *exceptfds, PRIntervalTime timeout);
+
+/* 
+** The following are not thread safe for two threads operating on them at the
+** same time.
+**
+** The following routines are provided for manipulating io descriptor sets.
+** PR_FD_ZERO(&fdset) initializes a descriptor set fdset to the null set.
+** PR_FD_SET(fd, &fdset) includes a particular file descriptor fd in fdset.
+** PR_FD_CLR(fd, &fdset) removes a file descriptor fd from fdset.  
+** PR_FD_ISSET(fd, &fdset) is nonzero if file descriptor fd is a member of 
+** fdset, zero otherwise.
+**
+** PR_FD_NSET(osfd, &fdset) includes a particular native file descriptor osfd
+** in fdset.
+** PR_FD_NCLR(osfd, &fdset) removes a native file descriptor osfd from fdset.  
+** PR_FD_NISSET(osfd, &fdset) is nonzero if native file descriptor osfd is a member of 
+** fdset, zero otherwise.
+*/
+
+NSPR_API(void)        PR_FD_ZERO(PR_fd_set *set);
+NSPR_API(void)        PR_FD_SET(PRFileDesc *fd, PR_fd_set *set);
+NSPR_API(void)        PR_FD_CLR(PRFileDesc *fd, PR_fd_set *set);
+NSPR_API(PRInt32)     PR_FD_ISSET(PRFileDesc *fd, PR_fd_set *set);
+NSPR_API(void)        PR_FD_NSET(PRInt32 osfd, PR_fd_set *set);
+NSPR_API(void)        PR_FD_NCLR(PRInt32 osfd, PR_fd_set *set);
+NSPR_API(PRInt32)     PR_FD_NISSET(PRInt32 osfd, PR_fd_set *set);
+
+#ifndef NO_NSPR_10_SUPPORT
+#ifdef XP_MAC
+#include <stat.h>
+#else
+#include <sys/stat.h>
+#endif
+
+NSPR_API(PRInt32) PR_Stat(const char *path, struct stat *buf);
+#endif /* NO_NSPR_10_SUPPORT */
+
+PR_END_EXTERN_C
+
+#endif /* defined(PROBSLET_H) */
+
+/* probslet.h */
diff --git a/third_party/gecko/include/obsolete/protypes.h b/third_party/gecko/include/obsolete/protypes.h
index 9b184a0..c2a3c9b 100644
--- a/third_party/gecko/include/obsolete/protypes.h
+++ b/third_party/gecko/include/obsolete/protypes.h
@@ -1,254 +1,254 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is the Netscape Portable Runtime (NSPR).

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998-2000

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/*

- * This header typedefs the old 'native' types to the new PR<type>s.

- * These definitions are scheduled to be eliminated at the earliest

- * possible time. The NSPR API is implemented and documented using

- * the new definitions.

- */

-

-#if !defined(PROTYPES_H)

-#define PROTYPES_H

-

-typedef PRUintn uintn;

-#ifndef _XP_Core_

-typedef PRIntn intn;

-#endif

-

-/*

- * It is trickier to define uint, int8, uint8, int16, uint16,

- * int32, uint32, int64, and uint64 because some of these int

- * types are defined by standard header files on some platforms.

- * Our strategy here is to include all such standard headers

- * first, and then define these int types only if they are not

- * defined by those standard headers.

- */

-

-/*

- * BeOS defines all the int types below in its standard header

- * file SupportDefs.h.

- */

-#ifdef XP_BEOS

-#include <support/SupportDefs.h>

-#endif

-

-/*

- * OpenVMS defines all the int types below in its standard

- * header files ints.h and types.h.

- */

-#ifdef VMS

-#include <ints.h>

-#include <types.h>

-#endif

-

-/*

- * SVR4 typedef of uint is commonly found on UNIX machines.

- *

- * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h)

- * defines the types int8, int16, int32, and int64.

- */

-#ifdef XP_UNIX

-#include <sys/types.h>

-#endif

-

-/* model.h on HP-UX defines int8, int16, and int32. */

-#ifdef HPUX

-#include <model.h>

-#endif

-

-/*

- * uint

- */

-

-#if !defined(XP_BEOS) && !defined(VMS) \

-    && !defined(XP_UNIX) || defined(NTO)

-typedef PRUintn uint;

-#endif

-

-/*

- * uint64

- */

-

-#if !defined(XP_BEOS) && !defined(VMS)

-typedef PRUint64 uint64;

-#endif

-

-/*

- * uint32

- */

-

-#if !defined(XP_BEOS) && !defined(VMS)

-#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO)

-typedef PRUint32 uint32;

-#else

-typedef unsigned long uint32;

-#endif

-#endif

-

-/*

- * uint16

- */

-

-#if !defined(XP_BEOS) && !defined(VMS)

-typedef PRUint16 uint16;

-#endif

-

-/*

- * uint8

- */

-

-#if !defined(XP_BEOS) && !defined(VMS)

-typedef PRUint8 uint8;

-#endif

-

-/*

- * int64

- */

-

-#if !defined(XP_BEOS) && !defined(VMS) \

-    && !defined(_PR_AIX_HAVE_BSD_INT_TYPES)

-typedef PRInt64 int64;

-#endif

-

-/*

- * int32

- */

-

-#if !defined(XP_BEOS) && !defined(VMS) \

-    && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \

-    && !defined(HPUX)

-#if !defined(WIN32) || !defined(_WINSOCK2API_)  /* defines its own "int32" */

-#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO)

-typedef PRInt32 int32;

-#else

-typedef long int32;

-#endif

-#endif

-#endif

-

-/*

- * int16

- */

-

-#if !defined(XP_BEOS) && !defined(VMS) \

-    && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \

-    && !defined(HPUX)

-typedef PRInt16 int16;

-#endif

-

-/*

- * int8

- */

-

-#if !defined(XP_BEOS) && !defined(VMS) \

-    && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \

-    && !defined(HPUX)

-typedef PRInt8 int8;

-#endif

-

-typedef PRFloat64 float64;

-typedef PRUptrdiff uptrdiff_t;

-typedef PRUword uprword_t;

-typedef PRWord prword_t;

-

-

-/* Re: prbit.h */

-#define TEST_BIT	PR_TEST_BIT

-#define SET_BIT		PR_SET_BIT

-#define CLEAR_BIT	PR_CLEAR_BIT

-

-/* Re: prarena.h->plarena.h */

-#define PRArena PLArena

-#define PRArenaPool PLArenaPool

-#define PRArenaStats PLArenaStats

-#define PR_ARENA_ALIGN PL_ARENA_ALIGN

-#define PR_INIT_ARENA_POOL PL_INIT_ARENA_POOL

-#define PR_ARENA_ALLOCATE PL_ARENA_ALLOCATE

-#define PR_ARENA_GROW PL_ARENA_GROW

-#define PR_ARENA_MARK PL_ARENA_MARK

-#define PR_CLEAR_UNUSED PL_CLEAR_UNUSED

-#define PR_CLEAR_ARENA PL_CLEAR_ARENA

-#define PR_ARENA_RELEASE PL_ARENA_RELEASE

-#define PR_COUNT_ARENA PL_COUNT_ARENA

-#define PR_ARENA_DESTROY PL_ARENA_DESTROY

-#define PR_InitArenaPool PL_InitArenaPool

-#define PR_FreeArenaPool PL_FreeArenaPool

-#define PR_FinishArenaPool PL_FinishArenaPool

-#define PR_CompactArenaPool PL_CompactArenaPool

-#define PR_ArenaFinish PL_ArenaFinish

-#define PR_ArenaAllocate PL_ArenaAllocate

-#define PR_ArenaGrow PL_ArenaGrow

-#define PR_ArenaRelease PL_ArenaRelease

-#define PR_ArenaCountAllocation PL_ArenaCountAllocation

-#define PR_ArenaCountInplaceGrowth PL_ArenaCountInplaceGrowth

-#define PR_ArenaCountGrowth PL_ArenaCountGrowth

-#define PR_ArenaCountRelease PL_ArenaCountRelease

-#define PR_ArenaCountRetract PL_ArenaCountRetract

-

-/* Re: prhash.h->plhash.h */

-#define PRHashEntry PLHashEntry

-#define PRHashTable PLHashTable

-#define PRHashNumber PLHashNumber

-#define PRHashFunction PLHashFunction

-#define PRHashComparator PLHashComparator

-#define PRHashEnumerator PLHashEnumerator

-#define PRHashAllocOps PLHashAllocOps

-#define PR_NewHashTable PL_NewHashTable

-#define PR_HashTableDestroy PL_HashTableDestroy

-#define PR_HashTableRawLookup PL_HashTableRawLookup

-#define PR_HashTableRawAdd PL_HashTableRawAdd

-#define PR_HashTableRawRemove PL_HashTableRawRemove

-#define PR_HashTableAdd PL_HashTableAdd

-#define PR_HashTableRemove PL_HashTableRemove

-#define PR_HashTableEnumerateEntries PL_HashTableEnumerateEntries

-#define PR_HashTableLookup PL_HashTableLookup

-#define PR_HashTableDump PL_HashTableDump

-#define PR_HashString PL_HashString

-#define PR_CompareStrings PL_CompareStrings

-#define PR_CompareValues PL_CompareValues

-

-#if defined(XP_MAC)

-#ifndef TRUE				/* Mac standard is lower case true */

-	#define TRUE 1

-#endif

-#ifndef FALSE				/* Mac standard is lower case false */

-	#define FALSE 0

-#endif

-#endif

-

-#endif /* !defined(PROTYPES_H) */

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * This header typedefs the old 'native' types to the new PR<type>s.
+ * These definitions are scheduled to be eliminated at the earliest
+ * possible time. The NSPR API is implemented and documented using
+ * the new definitions.
+ */
+
+#if !defined(PROTYPES_H)
+#define PROTYPES_H
+
+typedef PRUintn uintn;
+#ifndef _XP_Core_
+typedef PRIntn intn;
+#endif
+
+/*
+ * It is trickier to define uint, int8, uint8, int16, uint16,
+ * int32, uint32, int64, and uint64 because some of these int
+ * types are defined by standard header files on some platforms.
+ * Our strategy here is to include all such standard headers
+ * first, and then define these int types only if they are not
+ * defined by those standard headers.
+ */
+
+/*
+ * BeOS defines all the int types below in its standard header
+ * file SupportDefs.h.
+ */
+#ifdef XP_BEOS
+#include <support/SupportDefs.h>
+#endif
+
+/*
+ * OpenVMS defines all the int types below in its standard
+ * header files ints.h and types.h.
+ */
+#ifdef VMS
+#include <ints.h>
+#include <types.h>
+#endif
+
+/*
+ * SVR4 typedef of uint is commonly found on UNIX machines.
+ *
+ * On AIX 4.3, sys/inttypes.h (which is included by sys/types.h)
+ * defines the types int8, int16, int32, and int64.
+ */
+#ifdef XP_UNIX
+#include <sys/types.h>
+#endif
+
+/* model.h on HP-UX defines int8, int16, and int32. */
+#ifdef HPUX
+#include <model.h>
+#endif
+
+/*
+ * uint
+ */
+
+#if !defined(XP_BEOS) && !defined(VMS) \
+    && !defined(XP_UNIX) || defined(NTO)
+typedef PRUintn uint;
+#endif
+
+/*
+ * uint64
+ */
+
+#if !defined(XP_BEOS) && !defined(VMS)
+typedef PRUint64 uint64;
+#endif
+
+/*
+ * uint32
+ */
+
+#if !defined(XP_BEOS) && !defined(VMS)
+#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO)
+typedef PRUint32 uint32;
+#else
+typedef unsigned long uint32;
+#endif
+#endif
+
+/*
+ * uint16
+ */
+
+#if !defined(XP_BEOS) && !defined(VMS)
+typedef PRUint16 uint16;
+#endif
+
+/*
+ * uint8
+ */
+
+#if !defined(XP_BEOS) && !defined(VMS)
+typedef PRUint8 uint8;
+#endif
+
+/*
+ * int64
+ */
+
+#if !defined(XP_BEOS) && !defined(VMS) \
+    && !defined(_PR_AIX_HAVE_BSD_INT_TYPES)
+typedef PRInt64 int64;
+#endif
+
+/*
+ * int32
+ */
+
+#if !defined(XP_BEOS) && !defined(VMS) \
+    && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \
+    && !defined(HPUX)
+#if !defined(WIN32) || !defined(_WINSOCK2API_)  /* defines its own "int32" */
+#if !defined(XP_MAC) && !defined(_WIN32) && !defined(XP_OS2) && !defined(NTO)
+typedef PRInt32 int32;
+#else
+typedef long int32;
+#endif
+#endif
+#endif
+
+/*
+ * int16
+ */
+
+#if !defined(XP_BEOS) && !defined(VMS) \
+    && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \
+    && !defined(HPUX)
+typedef PRInt16 int16;
+#endif
+
+/*
+ * int8
+ */
+
+#if !defined(XP_BEOS) && !defined(VMS) \
+    && !defined(_PR_AIX_HAVE_BSD_INT_TYPES) \
+    && !defined(HPUX)
+typedef PRInt8 int8;
+#endif
+
+typedef PRFloat64 float64;
+typedef PRUptrdiff uptrdiff_t;
+typedef PRUword uprword_t;
+typedef PRWord prword_t;
+
+
+/* Re: prbit.h */
+#define TEST_BIT	PR_TEST_BIT
+#define SET_BIT		PR_SET_BIT
+#define CLEAR_BIT	PR_CLEAR_BIT
+
+/* Re: prarena.h->plarena.h */
+#define PRArena PLArena
+#define PRArenaPool PLArenaPool
+#define PRArenaStats PLArenaStats
+#define PR_ARENA_ALIGN PL_ARENA_ALIGN
+#define PR_INIT_ARENA_POOL PL_INIT_ARENA_POOL
+#define PR_ARENA_ALLOCATE PL_ARENA_ALLOCATE
+#define PR_ARENA_GROW PL_ARENA_GROW
+#define PR_ARENA_MARK PL_ARENA_MARK
+#define PR_CLEAR_UNUSED PL_CLEAR_UNUSED
+#define PR_CLEAR_ARENA PL_CLEAR_ARENA
+#define PR_ARENA_RELEASE PL_ARENA_RELEASE
+#define PR_COUNT_ARENA PL_COUNT_ARENA
+#define PR_ARENA_DESTROY PL_ARENA_DESTROY
+#define PR_InitArenaPool PL_InitArenaPool
+#define PR_FreeArenaPool PL_FreeArenaPool
+#define PR_FinishArenaPool PL_FinishArenaPool
+#define PR_CompactArenaPool PL_CompactArenaPool
+#define PR_ArenaFinish PL_ArenaFinish
+#define PR_ArenaAllocate PL_ArenaAllocate
+#define PR_ArenaGrow PL_ArenaGrow
+#define PR_ArenaRelease PL_ArenaRelease
+#define PR_ArenaCountAllocation PL_ArenaCountAllocation
+#define PR_ArenaCountInplaceGrowth PL_ArenaCountInplaceGrowth
+#define PR_ArenaCountGrowth PL_ArenaCountGrowth
+#define PR_ArenaCountRelease PL_ArenaCountRelease
+#define PR_ArenaCountRetract PL_ArenaCountRetract
+
+/* Re: prhash.h->plhash.h */
+#define PRHashEntry PLHashEntry
+#define PRHashTable PLHashTable
+#define PRHashNumber PLHashNumber
+#define PRHashFunction PLHashFunction
+#define PRHashComparator PLHashComparator
+#define PRHashEnumerator PLHashEnumerator
+#define PRHashAllocOps PLHashAllocOps
+#define PR_NewHashTable PL_NewHashTable
+#define PR_HashTableDestroy PL_HashTableDestroy
+#define PR_HashTableRawLookup PL_HashTableRawLookup
+#define PR_HashTableRawAdd PL_HashTableRawAdd
+#define PR_HashTableRawRemove PL_HashTableRawRemove
+#define PR_HashTableAdd PL_HashTableAdd
+#define PR_HashTableRemove PL_HashTableRemove
+#define PR_HashTableEnumerateEntries PL_HashTableEnumerateEntries
+#define PR_HashTableLookup PL_HashTableLookup
+#define PR_HashTableDump PL_HashTableDump
+#define PR_HashString PL_HashString
+#define PR_CompareStrings PL_CompareStrings
+#define PR_CompareValues PL_CompareValues
+
+#if defined(XP_MAC)
+#ifndef TRUE				/* Mac standard is lower case true */
+	#define TRUE 1
+#endif
+#ifndef FALSE				/* Mac standard is lower case false */
+	#define FALSE 0
+#endif
+#endif
+
+#endif /* !defined(PROTYPES_H) */
diff --git a/third_party/gecko/include/obsolete/prsem.h b/third_party/gecko/include/obsolete/prsem.h
index bdff9d4..fd0863a 100644
--- a/third_party/gecko/include/obsolete/prsem.h
+++ b/third_party/gecko/include/obsolete/prsem.h
@@ -1,96 +1,96 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is the Netscape Portable Runtime (NSPR).

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998-2000

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#ifndef prsem_h___

-#define prsem_h___

-

-/*

-** API for counting semaphores. Semaphores are counting synchronizing 

-** variables based on a lock and a condition variable.  They are lightweight 

-** contention control for a given count of resources.

-*/

-#include "prtypes.h"

-

-PR_BEGIN_EXTERN_C

-

-typedef struct PRSemaphore PRSemaphore;

-

-/*

-** Create a new semaphore object.

-*/

-NSPR_API(PRSemaphore*) PR_NewSem(PRUintn value);

-

-/*

-** Destroy the given semaphore object.

-**

-*/

-NSPR_API(void) PR_DestroySem(PRSemaphore *sem);

-

-/*

-** Wait on a Semaphore.

-** 

-** This routine allows a calling thread to wait or proceed depending upon the 

-** state of the semahore sem. The thread can proceed only if the counter value 

-** of the semaphore sem is currently greater than 0. If the value of semaphore 

-** sem is positive, it is decremented by one and the routine returns immediately 

-** allowing the calling thread to continue. If the value of semaphore sem is 0, 

-** the calling thread blocks awaiting the semaphore to be released by another 

-** thread.

-** 

-** This routine can return PR_PENDING_INTERRUPT if the waiting thread 

-** has been interrupted.

-*/

-NSPR_API(PRStatus) PR_WaitSem(PRSemaphore *sem);

-

-/*

-** This routine increments the counter value of the semaphore. If other threads 

-** are blocked for the semaphore, then the scheduler will determine which ONE 

-** thread will be unblocked.

-*/

-NSPR_API(void) PR_PostSem(PRSemaphore *sem);

-

-/*

-** Returns the value of the semaphore referenced by sem without affecting

-** the state of the semaphore.  The value represents the semaphore vaule

-F** at the time of the call, but may not be the actual value when the

-** caller inspects it.

-*/

-NSPR_API(PRUintn) PR_GetValueSem(PRSemaphore *sem);

-

-PR_END_EXTERN_C

-

-#endif /* prsem_h___ */

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef prsem_h___
+#define prsem_h___
+
+/*
+** API for counting semaphores. Semaphores are counting synchronizing 
+** variables based on a lock and a condition variable.  They are lightweight 
+** contention control for a given count of resources.
+*/
+#include "prtypes.h"
+
+PR_BEGIN_EXTERN_C
+
+typedef struct PRSemaphore PRSemaphore;
+
+/*
+** Create a new semaphore object.
+*/
+NSPR_API(PRSemaphore*) PR_NewSem(PRUintn value);
+
+/*
+** Destroy the given semaphore object.
+**
+*/
+NSPR_API(void) PR_DestroySem(PRSemaphore *sem);
+
+/*
+** Wait on a Semaphore.
+** 
+** This routine allows a calling thread to wait or proceed depending upon the 
+** state of the semahore sem. The thread can proceed only if the counter value 
+** of the semaphore sem is currently greater than 0. If the value of semaphore 
+** sem is positive, it is decremented by one and the routine returns immediately 
+** allowing the calling thread to continue. If the value of semaphore sem is 0, 
+** the calling thread blocks awaiting the semaphore to be released by another 
+** thread.
+** 
+** This routine can return PR_PENDING_INTERRUPT if the waiting thread 
+** has been interrupted.
+*/
+NSPR_API(PRStatus) PR_WaitSem(PRSemaphore *sem);
+
+/*
+** This routine increments the counter value of the semaphore. If other threads 
+** are blocked for the semaphore, then the scheduler will determine which ONE 
+** thread will be unblocked.
+*/
+NSPR_API(void) PR_PostSem(PRSemaphore *sem);
+
+/*
+** Returns the value of the semaphore referenced by sem without affecting
+** the state of the semaphore.  The value represents the semaphore vaule
+F** at the time of the call, but may not be the actual value when the
+** caller inspects it.
+*/
+NSPR_API(PRUintn) PR_GetValueSem(PRSemaphore *sem);
+
+PR_END_EXTERN_C
+
+#endif /* prsem_h___ */
diff --git a/third_party/gecko/include/prcpucfg.h b/third_party/gecko/include/prcpucfg.h
index 7a00f03..310fff8 100644
--- a/third_party/gecko/include/prcpucfg.h
+++ b/third_party/gecko/include/prcpucfg.h
@@ -1,200 +1,200 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is the Netscape Portable Runtime (NSPR).

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998-2000

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#ifndef nspr_cpucfg___

-#define nspr_cpucfg___

-

-#ifndef XP_PC

-#define XP_PC

-#endif

-

-#ifndef WIN32

-#define WIN32

-#endif

-

-#ifndef WIN95

-#define WIN95

-#endif

-

-#define PR_AF_INET6 23  /* same as AF_INET6 */

-

-#if defined(_M_IX86) || defined(_X86_)

-

-#define IS_LITTLE_ENDIAN 1

-#undef  IS_BIG_ENDIAN

-

-#define PR_BYTES_PER_BYTE   1

-#define PR_BYTES_PER_SHORT  2

-#define PR_BYTES_PER_INT    4

-#define PR_BYTES_PER_INT64  8

-#define PR_BYTES_PER_LONG   4

-#define PR_BYTES_PER_FLOAT  4

-#define PR_BYTES_PER_WORD	4

-#define PR_BYTES_PER_DWORD	8

-#define PR_BYTES_PER_DOUBLE 8

-

-#define PR_BITS_PER_BYTE    8

-#define PR_BITS_PER_SHORT   16

-#define PR_BITS_PER_INT     32

-#define PR_BITS_PER_INT64   64

-#define PR_BITS_PER_LONG    32

-#define PR_BITS_PER_FLOAT   32

-#define PR_BITS_PER_WORD	32

-#define PR_BITS_PER_DWORD	64

-#define PR_BITS_PER_DOUBLE  64

-

-#define PR_BITS_PER_BYTE_LOG2   3

-#define PR_BITS_PER_SHORT_LOG2  4

-#define PR_BITS_PER_INT_LOG2    5

-#define PR_BITS_PER_INT64_LOG2  6

-#define PR_BITS_PER_LONG_LOG2   5

-#define PR_BITS_PER_FLOAT_LOG2  5

-#define PR_BITS_PER_WORD_LOG2	5

-#define PR_BITS_PER_DWORD_LOG2	6

-#define PR_BITS_PER_DOUBLE_LOG2 6

-

-#define PR_ALIGN_OF_SHORT   2

-#define PR_ALIGN_OF_INT     4

-#define PR_ALIGN_OF_LONG    4

-#define PR_ALIGN_OF_INT64   8

-#define PR_ALIGN_OF_FLOAT   4

-#define PR_ALIGN_OF_WORD	4

-#define PR_ALIGN_OF_DWORD	8

-#define PR_ALIGN_OF_DOUBLE  4

-#define PR_ALIGN_OF_POINTER 4

-

-#define PR_BYTES_PER_WORD_LOG2	2

-#define PR_BYTES_PER_DWORD_LOG2	2

-

-#elif defined(_ALPHA_)

-

-#define IS_LITTLE_ENDIAN 1

-#undef  IS_BIG_ENDIAN

-

-#define PR_BYTES_PER_BYTE   1

-#define PR_BYTES_PER_SHORT  2

-#define PR_BYTES_PER_INT    4

-#define PR_BYTES_PER_INT64  8

-#define PR_BYTES_PER_LONG   4

-#define PR_BYTES_PER_FLOAT  4

-#define PR_BYTES_PER_DOUBLE 8

-#define PR_BYTES_PER_WORD   4

-#define PR_BYTES_PER_DWORD  8

-

-#define PR_BITS_PER_BYTE    8

-#define PR_BITS_PER_SHORT   16

-#define PR_BITS_PER_INT     32

-#define PR_BITS_PER_INT64   64

-#define PR_BITS_PER_LONG    32

-#define PR_BITS_PER_FLOAT   32

-#define PR_BITS_PER_DOUBLE  64

-#define PR_BITS_PER_WORD    32

-

-#define PR_BITS_PER_BYTE_LOG2   3

-#define PR_BITS_PER_SHORT_LOG2  4

-#define PR_BITS_PER_INT_LOG2    5

-#define PR_BITS_PER_INT64_LOG2  6

-#define PR_BITS_PER_LONG_LOG2   5

-#define PR_BITS_PER_FLOAT_LOG2  5

-#define PR_BITS_PER_DOUBLE_LOG2 6

-#define PR_BITS_PER_WORD_LOG2   5

-

-#define PR_BYTES_PER_WORD_LOG2  2

-#define PR_BYTES_PER_DWORD_LOG2 3

-

-#define PR_ALIGN_OF_SHORT   2

-#define PR_ALIGN_OF_INT     4

-#define PR_ALIGN_OF_LONG    4

-#define PR_ALIGN_OF_INT64   8

-#define PR_ALIGN_OF_FLOAT   4

-#define PR_ALIGN_OF_DOUBLE  8

-#define PR_ALIGN_OF_POINTER 4

-

-#else /* defined(_M_IX86) || defined(_X86_) */

-

-#error unknown processor architecture

-

-#endif /* defined(_M_IX86) || defined(_X86_) */

-

-#define HAVE_LONG_LONG

-

-#ifndef NO_NSPR_10_SUPPORT

-

-#define BYTES_PER_BYTE      PR_BYTES_PER_BYTE

-#define BYTES_PER_SHORT     PR_BYTES_PER_SHORT

-#define BYTES_PER_INT       PR_BYTES_PER_INT

-#define BYTES_PER_INT64     PR_BYTES_PER_INT64

-#define BYTES_PER_LONG      PR_BYTES_PER_LONG

-#define BYTES_PER_FLOAT     PR_BYTES_PER_FLOAT

-#define BYTES_PER_DOUBLE    PR_BYTES_PER_DOUBLE

-#define BYTES_PER_WORD      PR_BYTES_PER_WORD

-#define BYTES_PER_DWORD     PR_BYTES_PER_DWORD

-

-#define BITS_PER_BYTE       PR_BITS_PER_BYTE

-#define BITS_PER_SHORT      PR_BITS_PER_SHORT

-#define BITS_PER_INT        PR_BITS_PER_INT

-#define BITS_PER_INT64      PR_BITS_PER_INT64

-#define BITS_PER_LONG       PR_BITS_PER_LONG

-#define BITS_PER_FLOAT      PR_BITS_PER_FLOAT

-#define BITS_PER_DOUBLE     PR_BITS_PER_DOUBLE

-#define BITS_PER_WORD       PR_BITS_PER_WORD

-

-#define BITS_PER_BYTE_LOG2  PR_BITS_PER_BYTE_LOG2

-#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2

-#define BITS_PER_INT_LOG2   PR_BITS_PER_INT_LOG2

-#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2

-#define BITS_PER_LONG_LOG2  PR_BITS_PER_LONG_LOG2

-#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2

-#define BITS_PER_DOUBLE_LOG2    PR_BITS_PER_DOUBLE_LOG2

-#define BITS_PER_WORD_LOG2  PR_BITS_PER_WORD_LOG2

-

-#define ALIGN_OF_SHORT      PR_ALIGN_OF_SHORT

-#define ALIGN_OF_INT        PR_ALIGN_OF_INT

-#define ALIGN_OF_LONG       PR_ALIGN_OF_LONG

-#define ALIGN_OF_INT64      PR_ALIGN_OF_INT64

-#define ALIGN_OF_FLOAT      PR_ALIGN_OF_FLOAT

-#define ALIGN_OF_DOUBLE     PR_ALIGN_OF_DOUBLE

-#define ALIGN_OF_POINTER    PR_ALIGN_OF_POINTER

-#define ALIGN_OF_WORD       PR_ALIGN_OF_WORD

-

-#define BYTES_PER_WORD_LOG2		PR_BYTES_PER_WORD_LOG2

-#define BYTES_PER_DWORD_LOG2    PR_BYTES_PER_DWORD_LOG2

-#define WORDS_PER_DWORD_LOG2    PR_WORDS_PER_DWORD_LOG2

-

-#endif /* NO_NSPR_10_SUPPORT */

-

-#endif /* nspr_cpucfg___ */

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nspr_cpucfg___
+#define nspr_cpucfg___
+
+#ifndef XP_PC
+#define XP_PC
+#endif
+
+#ifndef WIN32
+#define WIN32
+#endif
+
+#ifndef WIN95
+#define WIN95
+#endif
+
+#define PR_AF_INET6 23  /* same as AF_INET6 */
+
+#if defined(_M_IX86) || defined(_X86_)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_WORD	4
+#define PR_BYTES_PER_DWORD	8
+#define PR_BYTES_PER_DOUBLE 8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_WORD	32
+#define PR_BITS_PER_DWORD	64
+#define PR_BITS_PER_DOUBLE  64
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_WORD_LOG2	5
+#define PR_BITS_PER_DWORD_LOG2	6
+#define PR_BITS_PER_DOUBLE_LOG2 6
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_WORD	4
+#define PR_ALIGN_OF_DWORD	8
+#define PR_ALIGN_OF_DOUBLE  4
+#define PR_ALIGN_OF_POINTER 4
+
+#define PR_BYTES_PER_WORD_LOG2	2
+#define PR_BYTES_PER_DWORD_LOG2	2
+
+#elif defined(_ALPHA_)
+
+#define IS_LITTLE_ENDIAN 1
+#undef  IS_BIG_ENDIAN
+
+#define PR_BYTES_PER_BYTE   1
+#define PR_BYTES_PER_SHORT  2
+#define PR_BYTES_PER_INT    4
+#define PR_BYTES_PER_INT64  8
+#define PR_BYTES_PER_LONG   4
+#define PR_BYTES_PER_FLOAT  4
+#define PR_BYTES_PER_DOUBLE 8
+#define PR_BYTES_PER_WORD   4
+#define PR_BYTES_PER_DWORD  8
+
+#define PR_BITS_PER_BYTE    8
+#define PR_BITS_PER_SHORT   16
+#define PR_BITS_PER_INT     32
+#define PR_BITS_PER_INT64   64
+#define PR_BITS_PER_LONG    32
+#define PR_BITS_PER_FLOAT   32
+#define PR_BITS_PER_DOUBLE  64
+#define PR_BITS_PER_WORD    32
+
+#define PR_BITS_PER_BYTE_LOG2   3
+#define PR_BITS_PER_SHORT_LOG2  4
+#define PR_BITS_PER_INT_LOG2    5
+#define PR_BITS_PER_INT64_LOG2  6
+#define PR_BITS_PER_LONG_LOG2   5
+#define PR_BITS_PER_FLOAT_LOG2  5
+#define PR_BITS_PER_DOUBLE_LOG2 6
+#define PR_BITS_PER_WORD_LOG2   5
+
+#define PR_BYTES_PER_WORD_LOG2  2
+#define PR_BYTES_PER_DWORD_LOG2 3
+
+#define PR_ALIGN_OF_SHORT   2
+#define PR_ALIGN_OF_INT     4
+#define PR_ALIGN_OF_LONG    4
+#define PR_ALIGN_OF_INT64   8
+#define PR_ALIGN_OF_FLOAT   4
+#define PR_ALIGN_OF_DOUBLE  8
+#define PR_ALIGN_OF_POINTER 4
+
+#else /* defined(_M_IX86) || defined(_X86_) */
+
+#error unknown processor architecture
+
+#endif /* defined(_M_IX86) || defined(_X86_) */
+
+#define HAVE_LONG_LONG
+
+#ifndef NO_NSPR_10_SUPPORT
+
+#define BYTES_PER_BYTE      PR_BYTES_PER_BYTE
+#define BYTES_PER_SHORT     PR_BYTES_PER_SHORT
+#define BYTES_PER_INT       PR_BYTES_PER_INT
+#define BYTES_PER_INT64     PR_BYTES_PER_INT64
+#define BYTES_PER_LONG      PR_BYTES_PER_LONG
+#define BYTES_PER_FLOAT     PR_BYTES_PER_FLOAT
+#define BYTES_PER_DOUBLE    PR_BYTES_PER_DOUBLE
+#define BYTES_PER_WORD      PR_BYTES_PER_WORD
+#define BYTES_PER_DWORD     PR_BYTES_PER_DWORD
+
+#define BITS_PER_BYTE       PR_BITS_PER_BYTE
+#define BITS_PER_SHORT      PR_BITS_PER_SHORT
+#define BITS_PER_INT        PR_BITS_PER_INT
+#define BITS_PER_INT64      PR_BITS_PER_INT64
+#define BITS_PER_LONG       PR_BITS_PER_LONG
+#define BITS_PER_FLOAT      PR_BITS_PER_FLOAT
+#define BITS_PER_DOUBLE     PR_BITS_PER_DOUBLE
+#define BITS_PER_WORD       PR_BITS_PER_WORD
+
+#define BITS_PER_BYTE_LOG2  PR_BITS_PER_BYTE_LOG2
+#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2
+#define BITS_PER_INT_LOG2   PR_BITS_PER_INT_LOG2
+#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2
+#define BITS_PER_LONG_LOG2  PR_BITS_PER_LONG_LOG2
+#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2
+#define BITS_PER_DOUBLE_LOG2    PR_BITS_PER_DOUBLE_LOG2
+#define BITS_PER_WORD_LOG2  PR_BITS_PER_WORD_LOG2
+
+#define ALIGN_OF_SHORT      PR_ALIGN_OF_SHORT
+#define ALIGN_OF_INT        PR_ALIGN_OF_INT
+#define ALIGN_OF_LONG       PR_ALIGN_OF_LONG
+#define ALIGN_OF_INT64      PR_ALIGN_OF_INT64
+#define ALIGN_OF_FLOAT      PR_ALIGN_OF_FLOAT
+#define ALIGN_OF_DOUBLE     PR_ALIGN_OF_DOUBLE
+#define ALIGN_OF_POINTER    PR_ALIGN_OF_POINTER
+#define ALIGN_OF_WORD       PR_ALIGN_OF_WORD
+
+#define BYTES_PER_WORD_LOG2		PR_BYTES_PER_WORD_LOG2
+#define BYTES_PER_DWORD_LOG2    PR_BYTES_PER_DWORD_LOG2
+#define WORDS_PER_DWORD_LOG2    PR_WORDS_PER_DWORD_LOG2
+
+#endif /* NO_NSPR_10_SUPPORT */
+
+#endif /* nspr_cpucfg___ */
diff --git a/third_party/gecko/include/prtypes.h b/third_party/gecko/include/prtypes.h
index 9ca9b10..3eb1554 100644
--- a/third_party/gecko/include/prtypes.h
+++ b/third_party/gecko/include/prtypes.h
@@ -1,547 +1,547 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is the Netscape Portable Runtime (NSPR).

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998-2000

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/*

-** File:                prtypes.h

-** Description: Definitions of NSPR's basic types

-**

-** Prototypes and macros used to make up for deficiencies that we have found

-** in ANSI environments.

-**

-** Since we do not wrap <stdlib.h> and all the other standard headers, authors

-** of portable code will not know in general that they need these definitions.

-** Instead of requiring these authors to find the dependent uses in their code

-** and take the following steps only in those C files, we take steps once here

-** for all C files.

-**/

-

-#ifndef prtypes_h___

-#define prtypes_h___

-

-#ifdef MDCPUCFG

-#include MDCPUCFG

-#else

-#include "prcpucfg.h"

-#endif

-

-#include <stddef.h>

-

-/***********************************************************************

-** MACROS:      PR_EXTERN

-**              PR_IMPLEMENT

-** DESCRIPTION:

-**      These are only for externally visible routines and globals.  For

-**      internal routines, just use "extern" for type checking and that

-**      will not export internal cross-file or forward-declared symbols.

-**      Define a macro for declaring procedures return types. We use this to

-**      deal with windoze specific type hackery for DLL definitions. Use

-**      PR_EXTERN when the prototype for the method is declared. Use

-**      PR_IMPLEMENT for the implementation of the method.

-**

-** Example:

-**   in dowhim.h

-**     PR_EXTERN( void ) DoWhatIMean( void );

-**   in dowhim.c

-**     PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; }

-**

-**

-***********************************************************************/

-#if defined(WIN32)

-

-#define PR_EXPORT(__type) extern __declspec(dllexport) __type

-#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type

-#define PR_IMPORT(__type) __declspec(dllimport) __type

-#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type

-

-#define PR_EXTERN(__type) extern __declspec(dllexport) __type

-#define PR_IMPLEMENT(__type) __declspec(dllexport) __type

-#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type

-#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type

-

-#define PR_CALLBACK

-#define PR_CALLBACK_DECL

-#define PR_STATIC_CALLBACK(__x) static __x

-

-#elif defined(XP_BEOS)

-

-#define PR_EXPORT(__type) extern __declspec(dllexport) __type

-#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type

-#define PR_IMPORT(__type) extern __declspec(dllexport) __type

-#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type

-

-#define PR_EXTERN(__type) extern __declspec(dllexport) __type

-#define PR_IMPLEMENT(__type) __declspec(dllexport) __type

-#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type

-#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type

-

-#define PR_CALLBACK

-#define PR_CALLBACK_DECL

-#define PR_STATIC_CALLBACK(__x) static __x

-

-#elif defined(WIN16)

-

-#define PR_CALLBACK_DECL        __cdecl

-

-#if defined(_WINDLL)

-#define PR_EXPORT(__type) extern __type _cdecl _export _loadds

-#define PR_IMPORT(__type) extern __type _cdecl _export _loadds

-#define PR_EXPORT_DATA(__type) extern __type _export

-#define PR_IMPORT_DATA(__type) extern __type _export

-

-#define PR_EXTERN(__type) extern __type _cdecl _export _loadds

-#define PR_IMPLEMENT(__type) __type _cdecl _export _loadds

-#define PR_EXTERN_DATA(__type) extern __type _export

-#define PR_IMPLEMENT_DATA(__type) __type _export

-

-#define PR_CALLBACK             __cdecl __loadds

-#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK

-

-#else /* this must be .EXE */

-#define PR_EXPORT(__type) extern __type _cdecl _export

-#define PR_IMPORT(__type) extern __type _cdecl _export

-#define PR_EXPORT_DATA(__type) extern __type _export

-#define PR_IMPORT_DATA(__type) extern __type _export

-

-#define PR_EXTERN(__type) extern __type _cdecl _export

-#define PR_IMPLEMENT(__type) __type _cdecl _export

-#define PR_EXTERN_DATA(__type) extern __type _export

-#define PR_IMPLEMENT_DATA(__type) __type _export

-

-#define PR_CALLBACK             __cdecl __loadds

-#define PR_STATIC_CALLBACK(__x) __x PR_CALLBACK

-#endif /* _WINDLL */

-

-#elif defined(XP_MAC)

-

-#define PR_EXPORT(__type) extern __declspec(export) __type

-#define PR_EXPORT_DATA(__type) extern __declspec(export) __type

-#define PR_IMPORT(__type) extern __declspec(export) __type

-#define PR_IMPORT_DATA(__type) extern __declspec(export) __type

-

-#define PR_EXTERN(__type) extern __declspec(export) __type

-#define PR_IMPLEMENT(__type) __declspec(export) __type

-#define PR_EXTERN_DATA(__type) extern __declspec(export) __type

-#define PR_IMPLEMENT_DATA(__type) __declspec(export) __type

-

-#define PR_CALLBACK

-#define PR_CALLBACK_DECL

-#define PR_STATIC_CALLBACK(__x) static __x

-

-#elif defined(XP_OS2_VACPP) 

-

-#define PR_EXPORT(__type) extern __type

-#define PR_EXPORT_DATA(__type) extern __type

-#define PR_IMPORT(__type) extern __type

-#define PR_IMPORT_DATA(__type) extern __type

-

-#define PR_EXTERN(__type) extern __type

-#define PR_IMPLEMENT(__type) __type

-#define PR_EXTERN_DATA(__type) extern __type

-#define PR_IMPLEMENT_DATA(__type) __type

-#define PR_CALLBACK _Optlink

-#define PR_CALLBACK_DECL

-#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK

-

-#else /* Unix */

-

-#ifdef HAVE_VISIBILITY_PRAGMA

-#define PR_VISIBILITY_DEFAULT __attribute__((visibility("default")))

-#else

-#define PR_VISIBILITY_DEFAULT

-#endif

-

-#define PR_EXPORT(__type) extern PR_VISIBILITY_DEFAULT __type

-#define PR_EXPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type

-#define PR_IMPORT(__type) extern PR_VISIBILITY_DEFAULT __type

-#define PR_IMPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type

-

-#define PR_EXTERN(__type) extern PR_VISIBILITY_DEFAULT __type

-#define PR_IMPLEMENT(__type) PR_VISIBILITY_DEFAULT __type

-#define PR_EXTERN_DATA(__type) extern PR_VISIBILITY_DEFAULT __type

-#define PR_IMPLEMENT_DATA(__type) PR_VISIBILITY_DEFAULT __type

-#define PR_CALLBACK

-#define PR_CALLBACK_DECL

-#define PR_STATIC_CALLBACK(__x) static __x

-

-#endif

-

-#if defined(_NSPR_BUILD_)

-#define NSPR_API(__type) PR_EXPORT(__type)

-#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type)

-#else

-#define NSPR_API(__type) PR_IMPORT(__type)

-#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type)

-#endif

-

-/***********************************************************************

-** MACROS:      PR_BEGIN_MACRO

-**              PR_END_MACRO

-** DESCRIPTION:

-**      Macro body brackets so that macros with compound statement definitions

-**      behave syntactically more like functions when called.

-***********************************************************************/

-#define PR_BEGIN_MACRO  do {

-#define PR_END_MACRO    } while (0)

-

-/***********************************************************************

-** MACROS:      PR_BEGIN_EXTERN_C

-**              PR_END_EXTERN_C

-** DESCRIPTION:

-**      Macro shorthands for conditional C++ extern block delimiters.

-***********************************************************************/

-#ifdef __cplusplus

-#define PR_BEGIN_EXTERN_C       extern "C" {

-#define PR_END_EXTERN_C         }

-#else

-#define PR_BEGIN_EXTERN_C

-#define PR_END_EXTERN_C

-#endif

-

-/***********************************************************************

-** MACROS:      PR_BIT

-**              PR_BITMASK

-** DESCRIPTION:

-** Bit masking macros.  XXX n must be <= 31 to be portable

-***********************************************************************/

-#define PR_BIT(n)       ((PRUint32)1 << (n))

-#define PR_BITMASK(n)   (PR_BIT(n) - 1)

-

-/***********************************************************************

-** MACROS:      PR_ROUNDUP

-**              PR_MIN

-**              PR_MAX

-**              PR_ABS

-** DESCRIPTION:

-**      Commonly used macros for operations on compatible types.

-***********************************************************************/

-#define PR_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y))

-#define PR_MIN(x,y)     ((x)<(y)?(x):(y))

-#define PR_MAX(x,y)     ((x)>(y)?(x):(y))

-#define PR_ABS(x)       ((x)<0?-(x):(x))

-

-PR_BEGIN_EXTERN_C

-

-/************************************************************************

-** TYPES:       PRUint8

-**              PRInt8

-** DESCRIPTION:

-**  The int8 types are known to be 8 bits each. There is no type that

-**      is equivalent to a plain "char". 

-************************************************************************/

-#if PR_BYTES_PER_BYTE == 1

-typedef unsigned char PRUint8;

-/*

-** Some cfront-based C++ compilers do not like 'signed char' and

-** issue the warning message:

-**     warning: "signed" not implemented (ignored)

-** For these compilers, we have to define PRInt8 as plain 'char'.

-** Make sure that plain 'char' is indeed signed under these compilers.

-*/

-#if (defined(HPUX) && defined(__cplusplus) \

-        && !defined(__GNUC__) && __cplusplus < 199707L) \

-    || (defined(SCO) && defined(__cplusplus) \

-        && !defined(__GNUC__) && __cplusplus == 1L)

-typedef char PRInt8;

-#else

-typedef signed char PRInt8;

-#endif

-#else

-#error No suitable type for PRInt8/PRUint8

-#endif

-

-/************************************************************************

- * MACROS:      PR_INT8_MAX

- *              PR_INT8_MIN

- *              PR_UINT8_MAX

- * DESCRIPTION:

- *  The maximum and minimum values of a PRInt8 or PRUint8.

-************************************************************************/

-

-#define PR_INT8_MAX 127

-#define PR_INT8_MIN (-128)

-#define PR_UINT8_MAX 255U

-

-/************************************************************************

-** TYPES:       PRUint16

-**              PRInt16

-** DESCRIPTION:

-**  The int16 types are known to be 16 bits each. 

-************************************************************************/

-#if PR_BYTES_PER_SHORT == 2

-typedef unsigned short PRUint16;

-typedef short PRInt16;

-#else

-#error No suitable type for PRInt16/PRUint16

-#endif

-

-/************************************************************************

- * MACROS:      PR_INT16_MAX

- *              PR_INT16_MIN

- *              PR_UINT16_MAX

- * DESCRIPTION:

- *  The maximum and minimum values of a PRInt16 or PRUint16.

-************************************************************************/

-

-#define PR_INT16_MAX 32767

-#define PR_INT16_MIN (-32768)

-#define PR_UINT16_MAX 65535U

-

-/************************************************************************

-** TYPES:       PRUint32

-**              PRInt32

-** DESCRIPTION:

-**  The int32 types are known to be 32 bits each. 

-************************************************************************/

-#if PR_BYTES_PER_INT == 4

-typedef unsigned int PRUint32;

-typedef int PRInt32;

-#define PR_INT32(x)  x

-#define PR_UINT32(x) x ## U

-#elif PR_BYTES_PER_LONG == 4

-typedef unsigned long PRUint32;

-typedef long PRInt32;

-#define PR_INT32(x)  x ## L

-#define PR_UINT32(x) x ## UL

-#else

-#error No suitable type for PRInt32/PRUint32

-#endif

-

-/************************************************************************

- * MACROS:      PR_INT32_MAX

- *              PR_INT32_MIN

- *              PR_UINT32_MAX

- * DESCRIPTION:

- *  The maximum and minimum values of a PRInt32 or PRUint32.

-************************************************************************/

-

-#define PR_INT32_MAX PR_INT32(2147483647)

-#define PR_INT32_MIN (-PR_INT32_MAX - 1)

-#define PR_UINT32_MAX PR_UINT32(4294967295)

-

-/************************************************************************

-** TYPES:       PRUint64

-**              PRInt64

-** DESCRIPTION:

-**  The int64 types are known to be 64 bits each. Care must be used when

-**      declaring variables of type PRUint64 or PRInt64. Different hardware

-**      architectures and even different compilers have varying support for

-**      64 bit values. The only guaranteed portability requires the use of

-**      the LL_ macros (see prlong.h).

-************************************************************************/

-#ifdef HAVE_LONG_LONG

-#if PR_BYTES_PER_LONG == 8

-typedef long PRInt64;

-typedef unsigned long PRUint64;

-#elif defined(WIN16)

-typedef __int64 PRInt64;

-typedef unsigned __int64 PRUint64;

-#elif defined(WIN32) && !defined(__GNUC__)

-typedef __int64  PRInt64;

-typedef unsigned __int64 PRUint64;

-#else

-typedef long long PRInt64;

-typedef unsigned long long PRUint64;

-#endif /* PR_BYTES_PER_LONG == 8 */

-#else  /* !HAVE_LONG_LONG */

-typedef struct {

-#ifdef IS_LITTLE_ENDIAN

-    PRUint32 lo, hi;

-#else

-    PRUint32 hi, lo;

-#endif

-} PRInt64;

-typedef PRInt64 PRUint64;

-#endif /* !HAVE_LONG_LONG */

-

-/************************************************************************

-** TYPES:       PRUintn

-**              PRIntn

-** DESCRIPTION:

-**  The PRIntn types are most appropriate for automatic variables. They are

-**      guaranteed to be at least 16 bits, though various architectures may

-**      define them to be wider (e.g., 32 or even 64 bits). These types are

-**      never valid for fields of a structure. 

-************************************************************************/

-#if PR_BYTES_PER_INT >= 2

-typedef int PRIntn;

-typedef unsigned int PRUintn;

-#else

-#error 'sizeof(int)' not sufficient for platform use

-#endif

-

-/************************************************************************

-** TYPES:       PRFloat64

-** DESCRIPTION:

-**  NSPR's floating point type is always 64 bits. 

-************************************************************************/

-typedef double          PRFloat64;

-

-/************************************************************************

-** TYPES:       PRSize

-** DESCRIPTION:

-**  A type for representing the size of objects. 

-************************************************************************/

-typedef size_t PRSize;

-

-

-/************************************************************************

-** TYPES:       PROffset32, PROffset64

-** DESCRIPTION:

-**  A type for representing byte offsets from some location. 

-************************************************************************/

-typedef PRInt32 PROffset32;

-typedef PRInt64 PROffset64;

-

-/************************************************************************

-** TYPES:       PRPtrDiff

-** DESCRIPTION:

-**  A type for pointer difference. Variables of this type are suitable

-**      for storing a pointer or pointer subtraction. 

-************************************************************************/

-typedef ptrdiff_t PRPtrdiff;

-

-/************************************************************************

-** TYPES:       PRUptrdiff

-** DESCRIPTION:

-**  A type for pointer difference. Variables of this type are suitable

-**      for storing a pointer or pointer sutraction. 

-************************************************************************/

-typedef unsigned long PRUptrdiff;

-

-/************************************************************************

-** TYPES:       PRBool

-** DESCRIPTION:

-**  Use PRBool for variables and parameter types. Use PR_FALSE and PR_TRUE

-**      for clarity of target type in assignments and actual arguments. Use

-**      'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans

-**      just as you would C int-valued conditions. 

-************************************************************************/

-typedef PRIntn PRBool;

-#define PR_TRUE 1

-#define PR_FALSE 0

-

-/************************************************************************

-** TYPES:       PRPackedBool

-** DESCRIPTION:

-**  Use PRPackedBool within structs where bitfields are not desirable

-**      but minimum and consistant overhead matters.

-************************************************************************/

-typedef PRUint8 PRPackedBool;

-

-/*

-** Status code used by some routines that have a single point of failure or 

-** special status return.

-*/

-typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;

-

-#ifdef MOZ_UNICODE

-/*

- * EXPERIMENTAL: This type may be removed in a future release.

- */

-#ifndef __PRUNICHAR__

-#define __PRUNICHAR__

-#if defined(WIN32) || defined(XP_MAC)

-typedef wchar_t PRUnichar;

-#else

-typedef PRUint16 PRUnichar;

-#endif

-#endif

-#endif /* MOZ_UNICODE */

-

-/*

-** WARNING: The undocumented data types PRWord and PRUword are

-** only used in the garbage collection and arena code.  Do not

-** use PRWord and PRUword in new code.

-**

-** A PRWord is an integer that is the same size as a void*.

-** It implements the notion of a "word" in the Java Virtual

-** Machine.  (See Sec. 3.4 "Words", The Java Virtual Machine

-** Specification, Addison-Wesley, September 1996.

-** http://java.sun.com/docs/books/vmspec/index.html.)

-*/

-typedef long PRWord;

-typedef unsigned long PRUword;

-

-#if defined(NO_NSPR_10_SUPPORT)

-#else

-/********* ???????????????? FIX ME       ??????????????????????????? *****/

-/********************** Some old definitions until pr=>ds transition is done ***/

-/********************** Also, we are still using NSPR 1.0. GC ******************/

-/*

-** Fundamental NSPR macros, used nearly everywhere.

-*/

-

-#define PR_PUBLIC_API		PR_IMPLEMENT

-

-/*

-** Macro body brackets so that macros with compound statement definitions

-** behave syntactically more like functions when called.

-*/

-#define NSPR_BEGIN_MACRO        do {

-#define NSPR_END_MACRO          } while (0)

-

-/*

-** Macro shorthands for conditional C++ extern block delimiters.

-*/

-#ifdef NSPR_BEGIN_EXTERN_C

-#undef NSPR_BEGIN_EXTERN_C

-#endif

-#ifdef NSPR_END_EXTERN_C

-#undef NSPR_END_EXTERN_C

-#endif

-

-#ifdef __cplusplus

-#define NSPR_BEGIN_EXTERN_C     extern "C" {

-#define NSPR_END_EXTERN_C       }

-#else

-#define NSPR_BEGIN_EXTERN_C

-#define NSPR_END_EXTERN_C

-#endif

-

-#ifdef XP_MAC

-#include "protypes.h"

-#else

-#include "obsolete/protypes.h"

-#endif

-

-/********* ????????????? End Fix me ?????????????????????????????? *****/

-#endif /* NO_NSPR_10_SUPPORT */

-

-PR_END_EXTERN_C

-

-#endif /* prtypes_h___ */

-

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+** File:                prtypes.h
+** Description: Definitions of NSPR's basic types
+**
+** Prototypes and macros used to make up for deficiencies that we have found
+** in ANSI environments.
+**
+** Since we do not wrap <stdlib.h> and all the other standard headers, authors
+** of portable code will not know in general that they need these definitions.
+** Instead of requiring these authors to find the dependent uses in their code
+** and take the following steps only in those C files, we take steps once here
+** for all C files.
+**/
+
+#ifndef prtypes_h___
+#define prtypes_h___
+
+#ifdef MDCPUCFG
+#include MDCPUCFG
+#else
+#include "prcpucfg.h"
+#endif
+
+#include <stddef.h>
+
+/***********************************************************************
+** MACROS:      PR_EXTERN
+**              PR_IMPLEMENT
+** DESCRIPTION:
+**      These are only for externally visible routines and globals.  For
+**      internal routines, just use "extern" for type checking and that
+**      will not export internal cross-file or forward-declared symbols.
+**      Define a macro for declaring procedures return types. We use this to
+**      deal with windoze specific type hackery for DLL definitions. Use
+**      PR_EXTERN when the prototype for the method is declared. Use
+**      PR_IMPLEMENT for the implementation of the method.
+**
+** Example:
+**   in dowhim.h
+**     PR_EXTERN( void ) DoWhatIMean( void );
+**   in dowhim.c
+**     PR_IMPLEMENT( void ) DoWhatIMean( void ) { return; }
+**
+**
+***********************************************************************/
+#if defined(WIN32)
+
+#define PR_EXPORT(__type) extern __declspec(dllexport) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT(__type) __declspec(dllimport) __type
+#define PR_IMPORT_DATA(__type) __declspec(dllimport) __type
+
+#define PR_EXTERN(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT(__type) __declspec(dllexport) __type
+#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(XP_BEOS)
+
+#define PR_EXPORT(__type) extern __declspec(dllexport) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT(__type) extern __declspec(dllexport) __type
+#define PR_IMPORT_DATA(__type) extern __declspec(dllexport) __type
+
+#define PR_EXTERN(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT(__type) __declspec(dllexport) __type
+#define PR_EXTERN_DATA(__type) extern __declspec(dllexport) __type
+#define PR_IMPLEMENT_DATA(__type) __declspec(dllexport) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(WIN16)
+
+#define PR_CALLBACK_DECL        __cdecl
+
+#if defined(_WINDLL)
+#define PR_EXPORT(__type) extern __type _cdecl _export _loadds
+#define PR_IMPORT(__type) extern __type _cdecl _export _loadds
+#define PR_EXPORT_DATA(__type) extern __type _export
+#define PR_IMPORT_DATA(__type) extern __type _export
+
+#define PR_EXTERN(__type) extern __type _cdecl _export _loadds
+#define PR_IMPLEMENT(__type) __type _cdecl _export _loadds
+#define PR_EXTERN_DATA(__type) extern __type _export
+#define PR_IMPLEMENT_DATA(__type) __type _export
+
+#define PR_CALLBACK             __cdecl __loadds
+#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK
+
+#else /* this must be .EXE */
+#define PR_EXPORT(__type) extern __type _cdecl _export
+#define PR_IMPORT(__type) extern __type _cdecl _export
+#define PR_EXPORT_DATA(__type) extern __type _export
+#define PR_IMPORT_DATA(__type) extern __type _export
+
+#define PR_EXTERN(__type) extern __type _cdecl _export
+#define PR_IMPLEMENT(__type) __type _cdecl _export
+#define PR_EXTERN_DATA(__type) extern __type _export
+#define PR_IMPLEMENT_DATA(__type) __type _export
+
+#define PR_CALLBACK             __cdecl __loadds
+#define PR_STATIC_CALLBACK(__x) __x PR_CALLBACK
+#endif /* _WINDLL */
+
+#elif defined(XP_MAC)
+
+#define PR_EXPORT(__type) extern __declspec(export) __type
+#define PR_EXPORT_DATA(__type) extern __declspec(export) __type
+#define PR_IMPORT(__type) extern __declspec(export) __type
+#define PR_IMPORT_DATA(__type) extern __declspec(export) __type
+
+#define PR_EXTERN(__type) extern __declspec(export) __type
+#define PR_IMPLEMENT(__type) __declspec(export) __type
+#define PR_EXTERN_DATA(__type) extern __declspec(export) __type
+#define PR_IMPLEMENT_DATA(__type) __declspec(export) __type
+
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#elif defined(XP_OS2_VACPP) 
+
+#define PR_EXPORT(__type) extern __type
+#define PR_EXPORT_DATA(__type) extern __type
+#define PR_IMPORT(__type) extern __type
+#define PR_IMPORT_DATA(__type) extern __type
+
+#define PR_EXTERN(__type) extern __type
+#define PR_IMPLEMENT(__type) __type
+#define PR_EXTERN_DATA(__type) extern __type
+#define PR_IMPLEMENT_DATA(__type) __type
+#define PR_CALLBACK _Optlink
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x PR_CALLBACK
+
+#else /* Unix */
+
+#ifdef HAVE_VISIBILITY_PRAGMA
+#define PR_VISIBILITY_DEFAULT __attribute__((visibility("default")))
+#else
+#define PR_VISIBILITY_DEFAULT
+#endif
+
+#define PR_EXPORT(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_EXPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPORT(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPORT_DATA(__type) extern PR_VISIBILITY_DEFAULT __type
+
+#define PR_EXTERN(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPLEMENT(__type) PR_VISIBILITY_DEFAULT __type
+#define PR_EXTERN_DATA(__type) extern PR_VISIBILITY_DEFAULT __type
+#define PR_IMPLEMENT_DATA(__type) PR_VISIBILITY_DEFAULT __type
+#define PR_CALLBACK
+#define PR_CALLBACK_DECL
+#define PR_STATIC_CALLBACK(__x) static __x
+
+#endif
+
+#if defined(_NSPR_BUILD_)
+#define NSPR_API(__type) PR_EXPORT(__type)
+#define NSPR_DATA_API(__type) PR_EXPORT_DATA(__type)
+#else
+#define NSPR_API(__type) PR_IMPORT(__type)
+#define NSPR_DATA_API(__type) PR_IMPORT_DATA(__type)
+#endif
+
+/***********************************************************************
+** MACROS:      PR_BEGIN_MACRO
+**              PR_END_MACRO
+** DESCRIPTION:
+**      Macro body brackets so that macros with compound statement definitions
+**      behave syntactically more like functions when called.
+***********************************************************************/
+#define PR_BEGIN_MACRO  do {
+#define PR_END_MACRO    } while (0)
+
+/***********************************************************************
+** MACROS:      PR_BEGIN_EXTERN_C
+**              PR_END_EXTERN_C
+** DESCRIPTION:
+**      Macro shorthands for conditional C++ extern block delimiters.
+***********************************************************************/
+#ifdef __cplusplus
+#define PR_BEGIN_EXTERN_C       extern "C" {
+#define PR_END_EXTERN_C         }
+#else
+#define PR_BEGIN_EXTERN_C
+#define PR_END_EXTERN_C
+#endif
+
+/***********************************************************************
+** MACROS:      PR_BIT
+**              PR_BITMASK
+** DESCRIPTION:
+** Bit masking macros.  XXX n must be <= 31 to be portable
+***********************************************************************/
+#define PR_BIT(n)       ((PRUint32)1 << (n))
+#define PR_BITMASK(n)   (PR_BIT(n) - 1)
+
+/***********************************************************************
+** MACROS:      PR_ROUNDUP
+**              PR_MIN
+**              PR_MAX
+**              PR_ABS
+** DESCRIPTION:
+**      Commonly used macros for operations on compatible types.
+***********************************************************************/
+#define PR_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y))
+#define PR_MIN(x,y)     ((x)<(y)?(x):(y))
+#define PR_MAX(x,y)     ((x)>(y)?(x):(y))
+#define PR_ABS(x)       ((x)<0?-(x):(x))
+
+PR_BEGIN_EXTERN_C
+
+/************************************************************************
+** TYPES:       PRUint8
+**              PRInt8
+** DESCRIPTION:
+**  The int8 types are known to be 8 bits each. There is no type that
+**      is equivalent to a plain "char". 
+************************************************************************/
+#if PR_BYTES_PER_BYTE == 1
+typedef unsigned char PRUint8;
+/*
+** Some cfront-based C++ compilers do not like 'signed char' and
+** issue the warning message:
+**     warning: "signed" not implemented (ignored)
+** For these compilers, we have to define PRInt8 as plain 'char'.
+** Make sure that plain 'char' is indeed signed under these compilers.
+*/
+#if (defined(HPUX) && defined(__cplusplus) \
+        && !defined(__GNUC__) && __cplusplus < 199707L) \
+    || (defined(SCO) && defined(__cplusplus) \
+        && !defined(__GNUC__) && __cplusplus == 1L)
+typedef char PRInt8;
+#else
+typedef signed char PRInt8;
+#endif
+#else
+#error No suitable type for PRInt8/PRUint8
+#endif
+
+/************************************************************************
+ * MACROS:      PR_INT8_MAX
+ *              PR_INT8_MIN
+ *              PR_UINT8_MAX
+ * DESCRIPTION:
+ *  The maximum and minimum values of a PRInt8 or PRUint8.
+************************************************************************/
+
+#define PR_INT8_MAX 127
+#define PR_INT8_MIN (-128)
+#define PR_UINT8_MAX 255U
+
+/************************************************************************
+** TYPES:       PRUint16
+**              PRInt16
+** DESCRIPTION:
+**  The int16 types are known to be 16 bits each. 
+************************************************************************/
+#if PR_BYTES_PER_SHORT == 2
+typedef unsigned short PRUint16;
+typedef short PRInt16;
+#else
+#error No suitable type for PRInt16/PRUint16
+#endif
+
+/************************************************************************
+ * MACROS:      PR_INT16_MAX
+ *              PR_INT16_MIN
+ *              PR_UINT16_MAX
+ * DESCRIPTION:
+ *  The maximum and minimum values of a PRInt16 or PRUint16.
+************************************************************************/
+
+#define PR_INT16_MAX 32767
+#define PR_INT16_MIN (-32768)
+#define PR_UINT16_MAX 65535U
+
+/************************************************************************
+** TYPES:       PRUint32
+**              PRInt32
+** DESCRIPTION:
+**  The int32 types are known to be 32 bits each. 
+************************************************************************/
+#if PR_BYTES_PER_INT == 4
+typedef unsigned int PRUint32;
+typedef int PRInt32;
+#define PR_INT32(x)  x
+#define PR_UINT32(x) x ## U
+#elif PR_BYTES_PER_LONG == 4
+typedef unsigned long PRUint32;
+typedef long PRInt32;
+#define PR_INT32(x)  x ## L
+#define PR_UINT32(x) x ## UL
+#else
+#error No suitable type for PRInt32/PRUint32
+#endif
+
+/************************************************************************
+ * MACROS:      PR_INT32_MAX
+ *              PR_INT32_MIN
+ *              PR_UINT32_MAX
+ * DESCRIPTION:
+ *  The maximum and minimum values of a PRInt32 or PRUint32.
+************************************************************************/
+
+#define PR_INT32_MAX PR_INT32(2147483647)
+#define PR_INT32_MIN (-PR_INT32_MAX - 1)
+#define PR_UINT32_MAX PR_UINT32(4294967295)
+
+/************************************************************************
+** TYPES:       PRUint64
+**              PRInt64
+** DESCRIPTION:
+**  The int64 types are known to be 64 bits each. Care must be used when
+**      declaring variables of type PRUint64 or PRInt64. Different hardware
+**      architectures and even different compilers have varying support for
+**      64 bit values. The only guaranteed portability requires the use of
+**      the LL_ macros (see prlong.h).
+************************************************************************/
+#ifdef HAVE_LONG_LONG
+#if PR_BYTES_PER_LONG == 8
+typedef long PRInt64;
+typedef unsigned long PRUint64;
+#elif defined(WIN16)
+typedef __int64 PRInt64;
+typedef unsigned __int64 PRUint64;
+#elif defined(WIN32) && !defined(__GNUC__)
+typedef __int64  PRInt64;
+typedef unsigned __int64 PRUint64;
+#else
+typedef long long PRInt64;
+typedef unsigned long long PRUint64;
+#endif /* PR_BYTES_PER_LONG == 8 */
+#else  /* !HAVE_LONG_LONG */
+typedef struct {
+#ifdef IS_LITTLE_ENDIAN
+    PRUint32 lo, hi;
+#else
+    PRUint32 hi, lo;
+#endif
+} PRInt64;
+typedef PRInt64 PRUint64;
+#endif /* !HAVE_LONG_LONG */
+
+/************************************************************************
+** TYPES:       PRUintn
+**              PRIntn
+** DESCRIPTION:
+**  The PRIntn types are most appropriate for automatic variables. They are
+**      guaranteed to be at least 16 bits, though various architectures may
+**      define them to be wider (e.g., 32 or even 64 bits). These types are
+**      never valid for fields of a structure. 
+************************************************************************/
+#if PR_BYTES_PER_INT >= 2
+typedef int PRIntn;
+typedef unsigned int PRUintn;
+#else
+#error 'sizeof(int)' not sufficient for platform use
+#endif
+
+/************************************************************************
+** TYPES:       PRFloat64
+** DESCRIPTION:
+**  NSPR's floating point type is always 64 bits. 
+************************************************************************/
+typedef double          PRFloat64;
+
+/************************************************************************
+** TYPES:       PRSize
+** DESCRIPTION:
+**  A type for representing the size of objects. 
+************************************************************************/
+typedef size_t PRSize;
+
+
+/************************************************************************
+** TYPES:       PROffset32, PROffset64
+** DESCRIPTION:
+**  A type for representing byte offsets from some location. 
+************************************************************************/
+typedef PRInt32 PROffset32;
+typedef PRInt64 PROffset64;
+
+/************************************************************************
+** TYPES:       PRPtrDiff
+** DESCRIPTION:
+**  A type for pointer difference. Variables of this type are suitable
+**      for storing a pointer or pointer subtraction. 
+************************************************************************/
+typedef ptrdiff_t PRPtrdiff;
+
+/************************************************************************
+** TYPES:       PRUptrdiff
+** DESCRIPTION:
+**  A type for pointer difference. Variables of this type are suitable
+**      for storing a pointer or pointer sutraction. 
+************************************************************************/
+typedef unsigned long PRUptrdiff;
+
+/************************************************************************
+** TYPES:       PRBool
+** DESCRIPTION:
+**  Use PRBool for variables and parameter types. Use PR_FALSE and PR_TRUE
+**      for clarity of target type in assignments and actual arguments. Use
+**      'if (bool)', 'while (!bool)', '(bool) ? x : y' etc., to test booleans
+**      just as you would C int-valued conditions. 
+************************************************************************/
+typedef PRIntn PRBool;
+#define PR_TRUE 1
+#define PR_FALSE 0
+
+/************************************************************************
+** TYPES:       PRPackedBool
+** DESCRIPTION:
+**  Use PRPackedBool within structs where bitfields are not desirable
+**      but minimum and consistant overhead matters.
+************************************************************************/
+typedef PRUint8 PRPackedBool;
+
+/*
+** Status code used by some routines that have a single point of failure or 
+** special status return.
+*/
+typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
+
+#ifdef MOZ_UNICODE
+/*
+ * EXPERIMENTAL: This type may be removed in a future release.
+ */
+#ifndef __PRUNICHAR__
+#define __PRUNICHAR__
+#if defined(WIN32) || defined(XP_MAC)
+typedef wchar_t PRUnichar;
+#else
+typedef PRUint16 PRUnichar;
+#endif
+#endif
+#endif /* MOZ_UNICODE */
+
+/*
+** WARNING: The undocumented data types PRWord and PRUword are
+** only used in the garbage collection and arena code.  Do not
+** use PRWord and PRUword in new code.
+**
+** A PRWord is an integer that is the same size as a void*.
+** It implements the notion of a "word" in the Java Virtual
+** Machine.  (See Sec. 3.4 "Words", The Java Virtual Machine
+** Specification, Addison-Wesley, September 1996.
+** http://java.sun.com/docs/books/vmspec/index.html.)
+*/
+typedef long PRWord;
+typedef unsigned long PRUword;
+
+#if defined(NO_NSPR_10_SUPPORT)
+#else
+/********* ???????????????? FIX ME       ??????????????????????????? *****/
+/********************** Some old definitions until pr=>ds transition is done ***/
+/********************** Also, we are still using NSPR 1.0. GC ******************/
+/*
+** Fundamental NSPR macros, used nearly everywhere.
+*/
+
+#define PR_PUBLIC_API		PR_IMPLEMENT
+
+/*
+** Macro body brackets so that macros with compound statement definitions
+** behave syntactically more like functions when called.
+*/
+#define NSPR_BEGIN_MACRO        do {
+#define NSPR_END_MACRO          } while (0)
+
+/*
+** Macro shorthands for conditional C++ extern block delimiters.
+*/
+#ifdef NSPR_BEGIN_EXTERN_C
+#undef NSPR_BEGIN_EXTERN_C
+#endif
+#ifdef NSPR_END_EXTERN_C
+#undef NSPR_END_EXTERN_C
+#endif
+
+#ifdef __cplusplus
+#define NSPR_BEGIN_EXTERN_C     extern "C" {
+#define NSPR_END_EXTERN_C       }
+#else
+#define NSPR_BEGIN_EXTERN_C
+#define NSPR_END_EXTERN_C
+#endif
+
+#ifdef XP_MAC
+#include "protypes.h"
+#else
+#include "obsolete/protypes.h"
+#endif
+
+/********* ????????????? End Fix me ?????????????????????????????? *****/
+#endif /* NO_NSPR_10_SUPPORT */
+
+PR_END_EXTERN_C
+
+#endif /* prtypes_h___ */
+
diff --git a/third_party/gecko/nsICookieService.idl b/third_party/gecko/nsICookieService.idl
index fad73be..d0bddd4 100644
--- a/third_party/gecko/nsICookieService.idl
+++ b/third_party/gecko/nsICookieService.idl
@@ -1,169 +1,169 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "nsISupports.idl"

-

-interface nsIURI;

-interface nsIPrompt;

-interface nsIChannel;

-

-/**

- * nsICookieService

- *

- * Provides methods for setting and getting cookies in the context of a

- * page load.  See nsICookieManager for methods to manipulate the cookie

- * database directly.  This separation of interface is mainly historical.

- *

- * This service broadcasts the following notifications when the cookie

- * list is changed, or a cookie is rejected:

- *

- * topic  : "cookie-changed"

- *          broadcast whenever the cookie list changes in some way. there

- *          are four possible data strings for this notification; one

- *          notification will be broadcast for each change, and will involve

- *          a single cookie.

- * subject: an nsICookie2 interface pointer representing the cookie object

- *          that changed.

- * data   : "deleted"

- *          a cookie was deleted. the subject is the deleted cookie.

- *          "added"

- *          a cookie was added. the subject is the added cookie.

- *          "changed"

- *          a cookie was changed. the subject is the new cookie.

- *          "cleared"

- *          the entire cookie list was cleared. the subject is null.

- *

- * topic  : "cookie-rejected"

- *          broadcast whenever a cookie was rejected from being set as a

- *          result of user prefs.

- * subject: an nsIURI interface pointer representing the URI that attempted

- *          to set the cookie.

- * data   : none.

- */

-[scriptable, uuid(011C3190-1434-11d6-A618-0010A401EB10)]

-interface nsICookieService : nsISupports

-{

-  /*

-   * Get the complete cookie string associated with the URI.

-   *

-   * @param aURI

-   *        the URI of the document for which cookies are being queried.

-   * @param aChannel

-   *        the channel used to load the document.  this parameter may be null,

-   *        but it is strongly recommended that a non-null value be provided to

-   *        ensure that the cookie privacy preferences are honored.

-   *

-   * @return the resulting cookie string

-   */

-  string getCookieString(in nsIURI aURI, in nsIChannel aChannel);

-

-  /*

-   * Get the complete cookie string associated with the URI.

-   *

-   * XXX this function is redundant and will most likely be removed in a future

-   * revision of this interface.  GetCookieString will query the documentURI

-   * property off of nsIHttpChannelInternal if supported, so GetCookieString

-   * can be used in place of this method.

-   *

-   * @param aURI

-   *        the URI of the document for which cookies are being queried.

-   * @param aFirstURI

-   *        the URI that the user originally typed in or clicked on to initiate

-   *        the load of the document referenced by aURI.

-   * @param aChannel

-   *        the channel used to load the document.  this parameter may be null,

-   *        but it is strongly recommended that a non-null value be provided to

-   *        ensure that the cookie privacy preferences are honored.

-   *

-   * @return the resulting cookie string

-   */

-  string getCookieStringFromHttp(in nsIURI aURI, in nsIURI aFirstURI, in nsIChannel aChannel);

-

-  /*

-   * Set the cookie string associated with the URI.

-   *

-   * @param aURI

-   *        the URI of the document for which cookies are being set.

-   * @param aPrompt

-   *        the prompt to use for all user-level cookie notifications.

-   * @param aCookie

-   *        the cookie string to set.

-   * @param aChannel

-   *        the channel used to load the document.  this parameter may be null,

-   *        but it is strongly recommended that a non-null value be provided to

-   *        ensure that the cookie privacy preferences are honored.

-   *

-   * XXX should be able to allow null aPrompt, since nsIPrompt can be queryied

-   * from aChannel.

-   */

-  void setCookieString(in nsIURI aURI, in nsIPrompt aPrompt, in string aCookie, in nsIChannel aChannel);

-

-  /*

-   * Set the cookie string and expires associated with the URI.

-   *

-   * XXX this function is redundant and will most likely be removed in a future

-   * revision of this interface.  SetCookieString will query the documentURI

-   * property off of nsIHttpChannelInternal if supported, and SetCookieString

-   * could also query the Date header from the channel if aChannel supports

-   * nsIHttpChannel.

-   *

-   * @param aURI

-   *        the URI of the document for which cookies are being set.

-   * @param aFirstURI

-   *        the URI that the user originally typed in or clicked on to initiate

-   *        the load of the document referenced by aURI.

-   * @param aPrompt

-   *        the prompt to use for all user-level cookie notifications.

-   * @param aCookie

-   *        the cookie string to set.

-   * @param aServerTime

-   *        the expiry information of the cookie (the Date header from the HTTP

-   *        response).

-   * @param aChannel

-   *        the channel used to load the document.  this parameter may be null,

-   *        but it is strongly recommended that a non-null value be provided to

-   *        ensure that the cookie privacy preferences are honored.

-   */

-  void setCookieStringFromHttp(in nsIURI aURI, in nsIURI aFirstURI, in nsIPrompt aPrompt, in string aCookie, in string aServerTime, in nsIChannel aChannel);

-

-  /**

-   * This attribute really doesn't belong on this interface.  CVS blame will

-   * tell you why it is here.  It remains until we can find a better home for

-   * it.  Read the source if you want to know what it does :-(

-   */

-  readonly attribute boolean cookieIconIsVisible;

-};

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIURI;
+interface nsIPrompt;
+interface nsIChannel;
+
+/**
+ * nsICookieService
+ *
+ * Provides methods for setting and getting cookies in the context of a
+ * page load.  See nsICookieManager for methods to manipulate the cookie
+ * database directly.  This separation of interface is mainly historical.
+ *
+ * This service broadcasts the following notifications when the cookie
+ * list is changed, or a cookie is rejected:
+ *
+ * topic  : "cookie-changed"
+ *          broadcast whenever the cookie list changes in some way. there
+ *          are four possible data strings for this notification; one
+ *          notification will be broadcast for each change, and will involve
+ *          a single cookie.
+ * subject: an nsICookie2 interface pointer representing the cookie object
+ *          that changed.
+ * data   : "deleted"
+ *          a cookie was deleted. the subject is the deleted cookie.
+ *          "added"
+ *          a cookie was added. the subject is the added cookie.
+ *          "changed"
+ *          a cookie was changed. the subject is the new cookie.
+ *          "cleared"
+ *          the entire cookie list was cleared. the subject is null.
+ *
+ * topic  : "cookie-rejected"
+ *          broadcast whenever a cookie was rejected from being set as a
+ *          result of user prefs.
+ * subject: an nsIURI interface pointer representing the URI that attempted
+ *          to set the cookie.
+ * data   : none.
+ */
+[scriptable, uuid(011C3190-1434-11d6-A618-0010A401EB10)]
+interface nsICookieService : nsISupports
+{
+  /*
+   * Get the complete cookie string associated with the URI.
+   *
+   * @param aURI
+   *        the URI of the document for which cookies are being queried.
+   * @param aChannel
+   *        the channel used to load the document.  this parameter may be null,
+   *        but it is strongly recommended that a non-null value be provided to
+   *        ensure that the cookie privacy preferences are honored.
+   *
+   * @return the resulting cookie string
+   */
+  string getCookieString(in nsIURI aURI, in nsIChannel aChannel);
+
+  /*
+   * Get the complete cookie string associated with the URI.
+   *
+   * XXX this function is redundant and will most likely be removed in a future
+   * revision of this interface.  GetCookieString will query the documentURI
+   * property off of nsIHttpChannelInternal if supported, so GetCookieString
+   * can be used in place of this method.
+   *
+   * @param aURI
+   *        the URI of the document for which cookies are being queried.
+   * @param aFirstURI
+   *        the URI that the user originally typed in or clicked on to initiate
+   *        the load of the document referenced by aURI.
+   * @param aChannel
+   *        the channel used to load the document.  this parameter may be null,
+   *        but it is strongly recommended that a non-null value be provided to
+   *        ensure that the cookie privacy preferences are honored.
+   *
+   * @return the resulting cookie string
+   */
+  string getCookieStringFromHttp(in nsIURI aURI, in nsIURI aFirstURI, in nsIChannel aChannel);
+
+  /*
+   * Set the cookie string associated with the URI.
+   *
+   * @param aURI
+   *        the URI of the document for which cookies are being set.
+   * @param aPrompt
+   *        the prompt to use for all user-level cookie notifications.
+   * @param aCookie
+   *        the cookie string to set.
+   * @param aChannel
+   *        the channel used to load the document.  this parameter may be null,
+   *        but it is strongly recommended that a non-null value be provided to
+   *        ensure that the cookie privacy preferences are honored.
+   *
+   * XXX should be able to allow null aPrompt, since nsIPrompt can be queryied
+   * from aChannel.
+   */
+  void setCookieString(in nsIURI aURI, in nsIPrompt aPrompt, in string aCookie, in nsIChannel aChannel);
+
+  /*
+   * Set the cookie string and expires associated with the URI.
+   *
+   * XXX this function is redundant and will most likely be removed in a future
+   * revision of this interface.  SetCookieString will query the documentURI
+   * property off of nsIHttpChannelInternal if supported, and SetCookieString
+   * could also query the Date header from the channel if aChannel supports
+   * nsIHttpChannel.
+   *
+   * @param aURI
+   *        the URI of the document for which cookies are being set.
+   * @param aFirstURI
+   *        the URI that the user originally typed in or clicked on to initiate
+   *        the load of the document referenced by aURI.
+   * @param aPrompt
+   *        the prompt to use for all user-level cookie notifications.
+   * @param aCookie
+   *        the cookie string to set.
+   * @param aServerTime
+   *        the expiry information of the cookie (the Date header from the HTTP
+   *        response).
+   * @param aChannel
+   *        the channel used to load the document.  this parameter may be null,
+   *        but it is strongly recommended that a non-null value be provided to
+   *        ensure that the cookie privacy preferences are honored.
+   */
+  void setCookieStringFromHttp(in nsIURI aURI, in nsIURI aFirstURI, in nsIPrompt aPrompt, in string aCookie, in string aServerTime, in nsIChannel aChannel);
+
+  /**
+   * This attribute really doesn't belong on this interface.  CVS blame will
+   * tell you why it is here.  It remains until we can find a better home for
+   * it.  Read the source if you want to know what it does :-(
+   */
+  readonly attribute boolean cookieIconIsVisible;
+};
diff --git a/third_party/gecko/nsIDOM3Document.idl b/third_party/gecko/nsIDOM3Document.idl
index 49477b8..00a5d2e 100644
--- a/third_party/gecko/nsIDOM3Document.idl
+++ b/third_party/gecko/nsIDOM3Document.idl
@@ -1,76 +1,76 @@
-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozila.org Code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 2003

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   Christopher A. Aillon <christopher@aillon.com> (Original Author)

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

- 

-#include "domstubs.idl"

-#include "nsIDOM3Node.idl"

-

-interface nsIDOMDOMConfiguration;

-

-/**

- * For more information on this interface, please see

- * http://www.w3.org/TR/DOM-Level-3-Core/

- */

-[scriptable, uuid(2e0e9ea1-72ab-4d9e-bdeb-ca64e1abeba4)]

-interface nsIDOM3Document : nsIDOM3Node

-{

-  // Introduced in DOM Level 3:

-  readonly attribute DOMString       actualEncoding;

-  // Introduced in DOM Level 3:

-  readonly attribute DOMString       xmlEncoding;

-  // Introduced in DOM Level 3:

-           attribute boolean         xmlStandalone;

-                                        // raises(DOMException) on setting

-  // Introduced in DOM Level 3:

-           attribute DOMString       xmlVersion;

-                                        // raises(DOMException) on setting

-  // Introduced in DOM Level 3:

-           attribute boolean         strictErrorChecking;

-  // Introduced in DOM Level 3:

-           attribute DOMString       documentURI;

-  // Introduced in DOM Level 3:

-  nsIDOMNode         adoptNode(in nsIDOMNode source)

-                                        raises(DOMException);

-  // Introduced in DOM Level 3:

-  readonly attribute nsIDOMDOMConfiguration domConfig;

-  // Introduced in DOM Level 3:

-  void               normalizeDocument();

-  // Introduced in DOM Level 3:

-  nsIDOMNode         renameNode(in nsIDOMNode node, 

-                                in DOMString namespaceURI, 

-                                in DOMString qualifiedName)

-                                        raises(DOMException);

-};

+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozila.org Code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Christopher A. Aillon <christopher@aillon.com> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+ 
+#include "domstubs.idl"
+#include "nsIDOM3Node.idl"
+
+interface nsIDOMDOMConfiguration;
+
+/**
+ * For more information on this interface, please see
+ * http://www.w3.org/TR/DOM-Level-3-Core/
+ */
+[scriptable, uuid(2e0e9ea1-72ab-4d9e-bdeb-ca64e1abeba4)]
+interface nsIDOM3Document : nsIDOM3Node
+{
+  // Introduced in DOM Level 3:
+  readonly attribute DOMString       actualEncoding;
+  // Introduced in DOM Level 3:
+  readonly attribute DOMString       xmlEncoding;
+  // Introduced in DOM Level 3:
+           attribute boolean         xmlStandalone;
+                                        // raises(DOMException) on setting
+  // Introduced in DOM Level 3:
+           attribute DOMString       xmlVersion;
+                                        // raises(DOMException) on setting
+  // Introduced in DOM Level 3:
+           attribute boolean         strictErrorChecking;
+  // Introduced in DOM Level 3:
+           attribute DOMString       documentURI;
+  // Introduced in DOM Level 3:
+  nsIDOMNode         adoptNode(in nsIDOMNode source)
+                                        raises(DOMException);
+  // Introduced in DOM Level 3:
+  readonly attribute nsIDOMDOMConfiguration domConfig;
+  // Introduced in DOM Level 3:
+  void               normalizeDocument();
+  // Introduced in DOM Level 3:
+  nsIDOMNode         renameNode(in nsIDOMNode node, 
+                                in DOMString namespaceURI, 
+                                in DOMString qualifiedName)
+                                        raises(DOMException);
+};
diff --git a/third_party/gecko/nsIDOM3Node.idl b/third_party/gecko/nsIDOM3Node.idl
index ab01d4f..9071ba9 100644
--- a/third_party/gecko/nsIDOM3Node.idl
+++ b/third_party/gecko/nsIDOM3Node.idl
@@ -1,88 +1,88 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is 

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 2000

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   Johnny Stenback <jst@netscape.com> (original author)

- *   Christopher A. Aillon <christopher@aillon.com>

- *

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "domstubs.idl"

-

-interface nsIVariant;

-interface nsIDOMUserDataHandler;

-

-

-[scriptable, uuid(29fb2a18-1dd2-11b2-8dd9-a6fd5d5ad12f)]

-interface nsIDOM3Node : nsISupports

-{

-  // Introduced in DOM Level 3:

-  readonly attribute DOMString       baseURI;

-

-  // DocumentPosition

-  const unsigned short      DOCUMENT_POSITION_DISCONNECTED = 0x01;

-  const unsigned short      DOCUMENT_POSITION_PRECEDING    = 0x02;

-  const unsigned short      DOCUMENT_POSITION_FOLLOWING    = 0x04;

-  const unsigned short      DOCUMENT_POSITION_CONTAINS     = 0x08;

-  const unsigned short      DOCUMENT_POSITION_CONTAINED_BY = 0x10;

-  const unsigned short      DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;

-

-  // Introduced in DOM Level 3:

-  unsigned short     compareDocumentPosition(in nsIDOMNode other)

-                                        raises(DOMException);

-  // Introduced in DOM Level 3:

-           attribute DOMString       textContent;

-                                        // raises(DOMException) on setting

-                                        // raises(DOMException) on retrieval

-

-  // Introduced in DOM Level 3:

-  boolean            isSameNode(in nsIDOMNode other);

-  // Introduced in DOM Level 3:

-  DOMString          lookupPrefix(in DOMString namespaceURI);

-  // Introduced in DOM Level 3:

-  boolean            isDefaultNamespace(in DOMString namespaceURI);

-  // Introduced in DOM Level 3:

-  DOMString          lookupNamespaceURI(in DOMString prefix);

-  // Introduced in DOM Level 3:

-  boolean            isEqualNode(in nsIDOMNode arg);

-  // Introduced in DOM Level 3:

-  nsISupports        getFeature(in DOMString feature, 

-                                in DOMString version);

-  // Introduced in DOM Level 3:

-  nsIVariant         setUserData(in DOMString key, 

-                                 in nsIVariant data, 

-                                 in nsIDOMUserDataHandler handler);

-  // Introduced in DOM Level 3:

-  nsIVariant         getUserData(in DOMString key);

-};

+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Johnny Stenback <jst@netscape.com> (original author)
+ *   Christopher A. Aillon <christopher@aillon.com>
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "domstubs.idl"
+
+interface nsIVariant;
+interface nsIDOMUserDataHandler;
+
+
+[scriptable, uuid(29fb2a18-1dd2-11b2-8dd9-a6fd5d5ad12f)]
+interface nsIDOM3Node : nsISupports
+{
+  // Introduced in DOM Level 3:
+  readonly attribute DOMString       baseURI;
+
+  // DocumentPosition
+  const unsigned short      DOCUMENT_POSITION_DISCONNECTED = 0x01;
+  const unsigned short      DOCUMENT_POSITION_PRECEDING    = 0x02;
+  const unsigned short      DOCUMENT_POSITION_FOLLOWING    = 0x04;
+  const unsigned short      DOCUMENT_POSITION_CONTAINS     = 0x08;
+  const unsigned short      DOCUMENT_POSITION_CONTAINED_BY = 0x10;
+  const unsigned short      DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
+
+  // Introduced in DOM Level 3:
+  unsigned short     compareDocumentPosition(in nsIDOMNode other)
+                                        raises(DOMException);
+  // Introduced in DOM Level 3:
+           attribute DOMString       textContent;
+                                        // raises(DOMException) on setting
+                                        // raises(DOMException) on retrieval
+
+  // Introduced in DOM Level 3:
+  boolean            isSameNode(in nsIDOMNode other);
+  // Introduced in DOM Level 3:
+  DOMString          lookupPrefix(in DOMString namespaceURI);
+  // Introduced in DOM Level 3:
+  boolean            isDefaultNamespace(in DOMString namespaceURI);
+  // Introduced in DOM Level 3:
+  DOMString          lookupNamespaceURI(in DOMString prefix);
+  // Introduced in DOM Level 3:
+  boolean            isEqualNode(in nsIDOMNode arg);
+  // Introduced in DOM Level 3:
+  nsISupports        getFeature(in DOMString feature, 
+                                in DOMString version);
+  // Introduced in DOM Level 3:
+  nsIVariant         setUserData(in DOMString key, 
+                                 in nsIVariant data, 
+                                 in nsIDOMUserDataHandler handler);
+  // Introduced in DOM Level 3:
+  nsIVariant         getUserData(in DOMString key);
+};
diff --git a/third_party/gecko/nsIDOMElementCSSInlineStyle.idl b/third_party/gecko/nsIDOMElementCSSInlineStyle.idl
index d3fd729..ccfe935 100644
--- a/third_party/gecko/nsIDOMElementCSSInlineStyle.idl
+++ b/third_party/gecko/nsIDOMElementCSSInlineStyle.idl
@@ -1,46 +1,46 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is 

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 2000

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   Johnny Stenback <jst@netscape.com> (original author)

- *

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "domstubs.idl"

-

-[scriptable, uuid(99715845-95fc-4a56-aa53-214b65c26e22)]

-interface nsIDOMElementCSSInlineStyle : nsISupports

-{

-  readonly attribute nsIDOMCSSStyleDeclaration  style;

-};

+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Johnny Stenback <jst@netscape.com> (original author)
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "domstubs.idl"
+
+[scriptable, uuid(99715845-95fc-4a56-aa53-214b65c26e22)]
+interface nsIDOMElementCSSInlineStyle : nsISupports
+{
+  readonly attribute nsIDOMCSSStyleDeclaration  style;
+};
diff --git a/third_party/gecko/nsIDOMNSEventTarget.idl b/third_party/gecko/nsIDOMNSEventTarget.idl
index 3e8c14d..df5d66b 100644
--- a/third_party/gecko/nsIDOMNSEventTarget.idl
+++ b/third_party/gecko/nsIDOMNSEventTarget.idl
@@ -1,71 +1,71 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * The Mozilla Foundation.

- * Portions created by the Initial Developer are Copyright (C) 2005

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   Johnny Stenback <jst@mozilla.org> (original author)

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "domstubs.idl"

-

-/**

- * The nsIDOMNSEventTarget interface is an extension to the standard

- * nsIDOMEventTarget interface, implemented by all event targets in

- * the Document Object Model.

- */

-

-[scriptable, uuid(6cbbbf64-212f-4ef8-9ad4-7240dbb8d6ac)]

-interface nsIDOMNSEventTarget : nsISupports

-{

-  /**

-   * This method is the same as the addEventListener() method defined

-   * in nsIDOMEventTarget, but it takes one additional argument which

-   * lets callers control whether or not they want to receive

-   * untrusted events (synthetic events generated by untrusted code)

-   *

-   * @param   type See the type argument to the same method in

-   *               nsIDOMEventTarget.

-   * @param   listener See the listener argument to the same method in

-   *                   nsIDOMEventTarget.

-   * @param   useCapture See the listener argument to the same method in

-   *                     nsIDOMEventTarget.

-   * @param   wantsUntrusted If false, the listener will not receive any

-   *                         untrusted events (see above), if true, the

-   *                         listener will receive events whether or not

-   *                         they're trusted

-   */

-  void                     addEventListener(in DOMString type,

-                                            in nsIDOMEventListener listener,

-                                            in boolean useCapture,

-                                            in boolean wantsUntrusted);

-};

+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Johnny Stenback <jst@mozilla.org> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "domstubs.idl"
+
+/**
+ * The nsIDOMNSEventTarget interface is an extension to the standard
+ * nsIDOMEventTarget interface, implemented by all event targets in
+ * the Document Object Model.
+ */
+
+[scriptable, uuid(6cbbbf64-212f-4ef8-9ad4-7240dbb8d6ac)]
+interface nsIDOMNSEventTarget : nsISupports
+{
+  /**
+   * This method is the same as the addEventListener() method defined
+   * in nsIDOMEventTarget, but it takes one additional argument which
+   * lets callers control whether or not they want to receive
+   * untrusted events (synthetic events generated by untrusted code)
+   *
+   * @param   type See the type argument to the same method in
+   *               nsIDOMEventTarget.
+   * @param   listener See the listener argument to the same method in
+   *                   nsIDOMEventTarget.
+   * @param   useCapture See the listener argument to the same method in
+   *                     nsIDOMEventTarget.
+   * @param   wantsUntrusted If false, the listener will not receive any
+   *                         untrusted events (see above), if true, the
+   *                         listener will receive events whether or not
+   *                         they're trusted
+   */
+  void                     addEventListener(in DOMString type,
+                                            in nsIDOMEventListener listener,
+                                            in boolean useCapture,
+                                            in boolean wantsUntrusted);
+};
diff --git a/third_party/gecko/nsIDocumentLoader.idl b/third_party/gecko/nsIDocumentLoader.idl
index 4726bdc..39c3c4b 100644
--- a/third_party/gecko/nsIDocumentLoader.idl
+++ b/third_party/gecko/nsIDocumentLoader.idl
@@ -1,76 +1,76 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is 

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1999

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or 

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/* nsIDocumentLoader -->

-

-*/

-

-#include "nsISupports.idl"

-interface nsILoadGroup;

-interface nsIContentViewerContainer;

-interface nsIChannel;

-interface nsIURI;

-interface nsIWebProgress;

-interface nsIRequest;

-

-[scriptable, uuid(f43ba260-0737-11d2-beb9-00805f8a66dc)]

-interface nsIDocumentLoader : nsISupports

-{

-  void stop();

-  boolean isBusy();

-  void createDocumentLoader(out nsIDocumentLoader anInstance);

-

-  attribute nsISupports container;

-  

-  [noscript] void getContentViewerContainer(in nsISupports aDocumentID, out nsIContentViewerContainer aResult);

-  nsILoadGroup getLoadGroup();

-

-  void destroy();

-  // this should really be in a private interface as it is only

-  // called between a parent doc loader and it's child.

-  void clearParentDocLoader();

-  readonly attribute nsIChannel documentChannel;

-

-  void fireOnLocationChange(in nsIWebProgress aWebProgress,

-                            in nsIRequest aRequest,

-                            in nsIURI aUri);

-  void fireOnStatusChange(in nsIWebProgress aWebProgress,

-                          in nsIRequest aRequest,

-                          in nsresult aStatus,

-                          in wstring aMessage);

-};

-

+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1999
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* nsIDocumentLoader -->
+
+*/
+
+#include "nsISupports.idl"
+interface nsILoadGroup;
+interface nsIContentViewerContainer;
+interface nsIChannel;
+interface nsIURI;
+interface nsIWebProgress;
+interface nsIRequest;
+
+[scriptable, uuid(f43ba260-0737-11d2-beb9-00805f8a66dc)]
+interface nsIDocumentLoader : nsISupports
+{
+  void stop();
+  boolean isBusy();
+  void createDocumentLoader(out nsIDocumentLoader anInstance);
+
+  attribute nsISupports container;
+  
+  [noscript] void getContentViewerContainer(in nsISupports aDocumentID, out nsIContentViewerContainer aResult);
+  nsILoadGroup getLoadGroup();
+
+  void destroy();
+  // this should really be in a private interface as it is only
+  // called between a parent doc loader and it's child.
+  void clearParentDocLoader();
+  readonly attribute nsIChannel documentChannel;
+
+  void fireOnLocationChange(in nsIWebProgress aWebProgress,
+                            in nsIRequest aRequest,
+                            in nsIURI aUri);
+  void fireOnStatusChange(in nsIWebProgress aWebProgress,
+                          in nsIRequest aRequest,
+                          in nsresult aStatus,
+                          in wstring aMessage);
+};
+
diff --git a/third_party/gecko/nsIHttpProtocolHandler.idl b/third_party/gecko/nsIHttpProtocolHandler.idl
index a0d3e46..8b7f70c 100644
--- a/third_party/gecko/nsIHttpProtocolHandler.idl
+++ b/third_party/gecko/nsIHttpProtocolHandler.idl
@@ -1,143 +1,143 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/*

- * The contents of this file are subject to the Mozilla Public

- * License Version 1.1 (the "License"); you may not use this file

- * except in compliance with the License. You may obtain a copy of

- * the License at http://www.mozilla.org/MPL/

- * 

- * Software distributed under the License is distributed on an "AS

- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or

- * implied. See the License for the specific language governing

- * rights and limitations under the License.

- * 

- * The Original Code is Mozilla.

- * 

- * The Initial Developer of the Original Code is Netscape

- * Communications.  Portions created by Netscape Communications are

- * Copyright (C) 2001 by Netscape Communications.  All

- * Rights Reserved.

- * 

- * Contributor(s): 

- *   Gagan Saksena <gagan@netscape.com> (original author)

- *   Darin Fisher <darin@netscape.com>

- */

-

-#include "nsIProxiedProtocolHandler.idl"

-

-[scriptable, uuid(122c91c0-2485-40ba-89c9-b895934921bc)]

-interface nsIHttpProtocolHandler : nsIProxiedProtocolHandler

-{

-    /**

-     * Get the HTTP advertised user agent string.

-     */

-    readonly attribute ACString userAgent;

-

-    /**

-     * Get the application name.

-	 *

-     * @return The name of this application (eg. "Mozilla").

-     */

-    readonly attribute ACString appName;

-

-    /**

-     * Get the application version string.

-     *

-     * @return The complete version (major and minor) string. (eg. "5.0")

-     */

-    readonly attribute ACString appVersion;

-

-    /**

-     * @return The vendor name.

-     */

-    attribute ACString vendor;

-

-    /**

-     * @return The vendor sub string.

-     */

-    attribute ACString vendorSub;

-    

-    /**

-     * @return The vendor comment.

-     */

-    attribute ACString vendorComment;

-

-    /**

-     * @return The product name.

-     */

-    attribute ACString product;

-

-    /**

-     * @return A product sub string.

-     */

-    attribute ACString productSub;

-

-    /**

-     * @return A product comment.

-     */

-    attribute ACString productComment;

-

-    /**

-     * Get the current platform.

-     *

-     * @return The platform this application is running on

-     *		   (eg. "Windows", "Macintosh", "X11")

-     */

-    readonly attribute ACString platform;

-

-    /**

-     * Get the current oscpu.

-     *

-     * @return The oscpu this application is running on

-     */

-    readonly attribute ACString oscpu;

-

-    /**

-     * Get the translation of the application. The value for language

-     * is usually a 2-letter code such as "en" and occasionally a 

-     * five-character code to indicate a language subtype, such as "zh_CN". 

-     */

-    attribute ACString language;

-

-    /**

-     * Get/Set the application comment misc portion.

-     */

-    attribute ACString misc;

-};

-

-%{C++

-/**

- * At initialization time, the HTTP handler will initialize each service

- * registered under this category:

- */

-#define NS_HTTP_STARTUP_CATEGORY "http-startup-category"

-

-/**

- * nsIObserver notification corresponding to startup category.  Services

- * registered under the startup category will receive this observer topic at

- * startup if they implement nsIObserver.  The "subject" of the notification

- * is the nsIHttpProtocolHandler instance.

- */

-#define NS_HTTP_STARTUP_TOPIC "http-startup"

-

-/**

- * Before an HTTP request is sent to the server, this observer topic is

- * notified.  The observer of this topic can then choose to set any additional

- * headers for this request before the request is actually sent to the server.

- * The "subject" of the notification is the nsIHttpChannel instance.

- */

-#define NS_HTTP_ON_MODIFY_REQUEST_TOPIC "http-on-modify-request"

-

-/**

- * After an HTTP server response is received, this observer topic is notified.

- * The observer of this topic can interrogate the response.  The "subject" of

- * the notification is the nsIHttpChannel instance.

- */

-#define NS_HTTP_ON_EXAMINE_RESPONSE_TOPIC "http-on-examine-response"

-

-/**

- * The observer of this topic is notified after the received HTTP response

- * is merged with data from the browser cache.  This means that, among other

- * things, the Content-Type header will be set correctly.

- */

-#define NS_HTTP_ON_EXAMINE_MERGED_RESPONSE_TOPIC "http-on-examine-merged-response"

-%}

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is Mozilla.
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications.  Portions created by Netscape Communications are
+ * Copyright (C) 2001 by Netscape Communications.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s): 
+ *   Gagan Saksena <gagan@netscape.com> (original author)
+ *   Darin Fisher <darin@netscape.com>
+ */
+
+#include "nsIProxiedProtocolHandler.idl"
+
+[scriptable, uuid(122c91c0-2485-40ba-89c9-b895934921bc)]
+interface nsIHttpProtocolHandler : nsIProxiedProtocolHandler
+{
+    /**
+     * Get the HTTP advertised user agent string.
+     */
+    readonly attribute ACString userAgent;
+
+    /**
+     * Get the application name.
+	 *
+     * @return The name of this application (eg. "Mozilla").
+     */
+    readonly attribute ACString appName;
+
+    /**
+     * Get the application version string.
+     *
+     * @return The complete version (major and minor) string. (eg. "5.0")
+     */
+    readonly attribute ACString appVersion;
+
+    /**
+     * @return The vendor name.
+     */
+    attribute ACString vendor;
+
+    /**
+     * @return The vendor sub string.
+     */
+    attribute ACString vendorSub;
+    
+    /**
+     * @return The vendor comment.
+     */
+    attribute ACString vendorComment;
+
+    /**
+     * @return The product name.
+     */
+    attribute ACString product;
+
+    /**
+     * @return A product sub string.
+     */
+    attribute ACString productSub;
+
+    /**
+     * @return A product comment.
+     */
+    attribute ACString productComment;
+
+    /**
+     * Get the current platform.
+     *
+     * @return The platform this application is running on
+     *		   (eg. "Windows", "Macintosh", "X11")
+     */
+    readonly attribute ACString platform;
+
+    /**
+     * Get the current oscpu.
+     *
+     * @return The oscpu this application is running on
+     */
+    readonly attribute ACString oscpu;
+
+    /**
+     * Get the translation of the application. The value for language
+     * is usually a 2-letter code such as "en" and occasionally a 
+     * five-character code to indicate a language subtype, such as "zh_CN". 
+     */
+    attribute ACString language;
+
+    /**
+     * Get/Set the application comment misc portion.
+     */
+    attribute ACString misc;
+};
+
+%{C++
+/**
+ * At initialization time, the HTTP handler will initialize each service
+ * registered under this category:
+ */
+#define NS_HTTP_STARTUP_CATEGORY "http-startup-category"
+
+/**
+ * nsIObserver notification corresponding to startup category.  Services
+ * registered under the startup category will receive this observer topic at
+ * startup if they implement nsIObserver.  The "subject" of the notification
+ * is the nsIHttpProtocolHandler instance.
+ */
+#define NS_HTTP_STARTUP_TOPIC "http-startup"
+
+/**
+ * Before an HTTP request is sent to the server, this observer topic is
+ * notified.  The observer of this topic can then choose to set any additional
+ * headers for this request before the request is actually sent to the server.
+ * The "subject" of the notification is the nsIHttpChannel instance.
+ */
+#define NS_HTTP_ON_MODIFY_REQUEST_TOPIC "http-on-modify-request"
+
+/**
+ * After an HTTP server response is received, this observer topic is notified.
+ * The observer of this topic can interrogate the response.  The "subject" of
+ * the notification is the nsIHttpChannel instance.
+ */
+#define NS_HTTP_ON_EXAMINE_RESPONSE_TOPIC "http-on-examine-response"
+
+/**
+ * The observer of this topic is notified after the received HTTP response
+ * is merged with data from the browser cache.  This means that, among other
+ * things, the Content-Type header will be set correctly.
+ */
+#define NS_HTTP_ON_EXAMINE_MERGED_RESPONSE_TOPIC "http-on-examine-merged-response"
+%}
diff --git a/third_party/gecko/nsIPrefBranch2.idl b/third_party/gecko/nsIPrefBranch2.idl
index 8e3a352..01968b8 100644
--- a/third_party/gecko/nsIPrefBranch2.idl
+++ b/third_party/gecko/nsIPrefBranch2.idl
@@ -1,114 +1,114 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is Mozilla Communicator client code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   Alec Flett <alecf@netscape.com>

- *   Brian Nesse <bnesse@netscape.com>

- *   Benjamin Smedberg <benjamin@smedbergs.us>

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "nsIPrefBranch.idl"

-

-interface nsIObserver;

-

-/**

- * nsIPrefBranch2 allows clients to observe changes to pref values.

- *

- * @status FROZEN

- * @see nsIPrefBranch

- */

-[scriptable, uuid(74567534-eb94-4b1c-8f45-389643bfc555)]

-interface nsIPrefBranch2 : nsIPrefBranch

-{

-  /**

-   * Add a preference change observer. On preference changes, the following

-   * arguments will be passed to the nsIObserver.observe() method:

-   *   aSubject - The nsIPrefBranch object (this)

-   *   aTopic   - The string defined by NS_PREFBRANCH_PREFCHANGE_TOPIC_ID

-   *   aData    - The preference which has changed

-   *

-   * @param aDomain   The preference on which to listen for changes. This can

-   *                  be the name of an entire branch to observe.

-   *                  e.g. Holding the "root" prefbranch and calling

-   *                  addObserver("foo.bar.", ...) will observe changes to

-   *                  foo.bar.baz and foo.bar.bzip

-   * @param aObserver The object to be notified if the preference changes.

-   * @param aHoldWeak true  Hold a weak reference to |aObserver|. The object

-   *                        must implement the nsISupportsWeakReference

-   *                        interface or this will fail.

-   *                  false Hold a strong reference to |aObserver|.

-   *

-   * @note

-   * Registering as a preference observer can open an object to potential

-   * cyclical references which will cause memory leaks. These cycles generally

-   * occur because an object both registers itself as an observer (causing the

-   * branch to hold a reference to the observer) and holds a reference to the

-   * branch object for the purpose of getting/setting preference values. There

-   * are 3 approaches which have been implemented in an attempt to avoid these

-   * situations.

-   * 1) The nsPrefBranch object supports nsISupportsWeakReference. Any consumer

-   *    may hold a weak reference to it instead of a strong one.

-   * 2) The nsPrefBranch object listens for xpcom-shutdown and frees all of the

-   *    objects currently in its observer list. This insures that long lived

-   *    objects (services for example) will be freed correctly.

-   * 3) The observer can request to be held as a weak reference when it is

-   *    registered. This insures that shorter lived objects (say one tied to an

-   *    open window) will not fall into the cyclical reference trap.

-   *

-   * @see nsIObserver

-   * @see removeObserver

-   */

-  void addObserver(in string aDomain, in nsIObserver aObserver,

-                   in boolean aHoldWeak);

-

-  /**

-   * Remove a preference change observer.

-   *

-   * @param aDomain   The preference which is being observed for changes.

-   * @param aObserver An observer previously registered with addObserver().

-   *

-   * @see nsIObserver

-   * @see addObserver

-   */

-  void removeObserver(in string aDomain, in nsIObserver aObserver);

-};

-

-%{C++

-

-/**

- * Notification sent when a preference changes.

- */

-#define NS_PREFBRANCH_PREFCHANGE_TOPIC_ID "nsPref:changed"

-

-%}

+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alec Flett <alecf@netscape.com>
+ *   Brian Nesse <bnesse@netscape.com>
+ *   Benjamin Smedberg <benjamin@smedbergs.us>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIPrefBranch.idl"
+
+interface nsIObserver;
+
+/**
+ * nsIPrefBranch2 allows clients to observe changes to pref values.
+ *
+ * @status FROZEN
+ * @see nsIPrefBranch
+ */
+[scriptable, uuid(74567534-eb94-4b1c-8f45-389643bfc555)]
+interface nsIPrefBranch2 : nsIPrefBranch
+{
+  /**
+   * Add a preference change observer. On preference changes, the following
+   * arguments will be passed to the nsIObserver.observe() method:
+   *   aSubject - The nsIPrefBranch object (this)
+   *   aTopic   - The string defined by NS_PREFBRANCH_PREFCHANGE_TOPIC_ID
+   *   aData    - The preference which has changed
+   *
+   * @param aDomain   The preference on which to listen for changes. This can
+   *                  be the name of an entire branch to observe.
+   *                  e.g. Holding the "root" prefbranch and calling
+   *                  addObserver("foo.bar.", ...) will observe changes to
+   *                  foo.bar.baz and foo.bar.bzip
+   * @param aObserver The object to be notified if the preference changes.
+   * @param aHoldWeak true  Hold a weak reference to |aObserver|. The object
+   *                        must implement the nsISupportsWeakReference
+   *                        interface or this will fail.
+   *                  false Hold a strong reference to |aObserver|.
+   *
+   * @note
+   * Registering as a preference observer can open an object to potential
+   * cyclical references which will cause memory leaks. These cycles generally
+   * occur because an object both registers itself as an observer (causing the
+   * branch to hold a reference to the observer) and holds a reference to the
+   * branch object for the purpose of getting/setting preference values. There
+   * are 3 approaches which have been implemented in an attempt to avoid these
+   * situations.
+   * 1) The nsPrefBranch object supports nsISupportsWeakReference. Any consumer
+   *    may hold a weak reference to it instead of a strong one.
+   * 2) The nsPrefBranch object listens for xpcom-shutdown and frees all of the
+   *    objects currently in its observer list. This insures that long lived
+   *    objects (services for example) will be freed correctly.
+   * 3) The observer can request to be held as a weak reference when it is
+   *    registered. This insures that shorter lived objects (say one tied to an
+   *    open window) will not fall into the cyclical reference trap.
+   *
+   * @see nsIObserver
+   * @see removeObserver
+   */
+  void addObserver(in string aDomain, in nsIObserver aObserver,
+                   in boolean aHoldWeak);
+
+  /**
+   * Remove a preference change observer.
+   *
+   * @param aDomain   The preference which is being observed for changes.
+   * @param aObserver An observer previously registered with addObserver().
+   *
+   * @see nsIObserver
+   * @see addObserver
+   */
+  void removeObserver(in string aDomain, in nsIObserver aObserver);
+};
+
+%{C++
+
+/**
+ * Notification sent when a preference changes.
+ */
+#define NS_PREFBRANCH_PREFCHANGE_TOPIC_ID "nsPref:changed"
+
+%}
diff --git a/third_party/gecko/nsIPropertyBag.idl b/third_party/gecko/nsIPropertyBag.idl
index 093f7f2..79c3f2f 100644
--- a/third_party/gecko/nsIPropertyBag.idl
+++ b/third_party/gecko/nsIPropertyBag.idl
@@ -1,63 +1,63 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-

- *

- * ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   John Bandhauer <jband@netscape.com>

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either of the GNU General Public License Version 2 or later (the "GPL"),

- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/* nsIVariant based Property Bag support. */

-

-#include "nsISupports.idl"

-

-interface nsIVariant;

-interface nsISimpleEnumerator;

-

-[scriptable, uuid(bfcd37b0-a49f-11d5-910d-0010a4e73d9a)]

-interface nsIPropertyBag : nsISupports

-{

-    /**

-     * Get a nsISimpleEnumerator whose elements are nsIProperty objects.

-     */

-    readonly attribute nsISimpleEnumerator enumerator;

-

-    /**

-     * Get a property value for the given name.

-     * @throws NS_ERROR_FAILURE if a property with that name doesn't

-     * exist.

-     */

-    nsIVariant getProperty(in AString name);

-};

-

-

+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   John Bandhauer <jband@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* nsIVariant based Property Bag support. */
+
+#include "nsISupports.idl"
+
+interface nsIVariant;
+interface nsISimpleEnumerator;
+
+[scriptable, uuid(bfcd37b0-a49f-11d5-910d-0010a4e73d9a)]
+interface nsIPropertyBag : nsISupports
+{
+    /**
+     * Get a nsISimpleEnumerator whose elements are nsIProperty objects.
+     */
+    readonly attribute nsISimpleEnumerator enumerator;
+
+    /**
+     * Get a property value for the given name.
+     * @throws NS_ERROR_FAILURE if a property with that name doesn't
+     * exist.
+     */
+    nsIVariant getProperty(in AString name);
+};
+
+
diff --git a/third_party/gecko/nsIPropertyBag2.idl b/third_party/gecko/nsIPropertyBag2.idl
index fdad59a..19d0070 100644
--- a/third_party/gecko/nsIPropertyBag2.idl
+++ b/third_party/gecko/nsIPropertyBag2.idl
@@ -1,64 +1,64 @@
-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org property bag support.

- *

- * The Initial Developer of the Original Code is

- * Christian Biesinger <cbiesinger@web.de>.

- * Portions created by the Initial Developer are Copyright (C) 2005

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *    Darin Fisher <darin@meer.net>

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/* nsIVariant based Property Bag support. */

-

-#include "nsIPropertyBag.idl"

-

-[scriptable, uuid(9bb35f13-0096-4a31-833a-acd97001132d)]

-interface nsIPropertyBag2 : nsIPropertyBag

-{

-  // Accessing a property as a different type may attempt conversion to the

-  // requested value

-

-  PRInt32     getPropertyAsInt32       (in AString prop);

-  PRUint32    getPropertyAsUint32      (in AString prop);

-  PRInt64     getPropertyAsInt64       (in AString prop);

-  PRUint64    getPropertyAsUint64      (in AString prop);

-  double      getPropertyAsDouble      (in AString prop);

-  AString     getPropertyAsAString     (in AString prop);

-  ACString    getPropertyAsACString    (in AString prop);

-  AUTF8String getPropertyAsAUTF8String (in AString prop);

-  boolean     getPropertyAsBool        (in AString prop);

-

-  /**

-   * This method returns null if the value exists, but is null.

-   */

-  void        getPropertyAsInterface   (in AString prop,

-                                        in nsIIDRef iid,

-                                        [iid_is(iid), retval] out nsQIResult result);

-};

+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org property bag support.
+ *
+ * The Initial Developer of the Original Code is
+ * Christian Biesinger <cbiesinger@web.de>.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *    Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* nsIVariant based Property Bag support. */
+
+#include "nsIPropertyBag.idl"
+
+[scriptable, uuid(9bb35f13-0096-4a31-833a-acd97001132d)]
+interface nsIPropertyBag2 : nsIPropertyBag
+{
+  // Accessing a property as a different type may attempt conversion to the
+  // requested value
+
+  PRInt32     getPropertyAsInt32       (in AString prop);
+  PRUint32    getPropertyAsUint32      (in AString prop);
+  PRInt64     getPropertyAsInt64       (in AString prop);
+  PRUint64    getPropertyAsUint64      (in AString prop);
+  double      getPropertyAsDouble      (in AString prop);
+  AString     getPropertyAsAString     (in AString prop);
+  ACString    getPropertyAsACString    (in AString prop);
+  AUTF8String getPropertyAsAUTF8String (in AString prop);
+  boolean     getPropertyAsBool        (in AString prop);
+
+  /**
+   * This method returns null if the value exists, but is null.
+   */
+  void        getPropertyAsInterface   (in AString prop,
+                                        in nsIIDRef iid,
+                                        [iid_is(iid), retval] out nsQIResult result);
+};
diff --git a/third_party/gecko/nsIProtocolProxyFilter.idl b/third_party/gecko/nsIProtocolProxyFilter.idl
index e3c097c..a00dbfb 100644
--- a/third_party/gecko/nsIProtocolProxyFilter.idl
+++ b/third_party/gecko/nsIProtocolProxyFilter.idl
@@ -1,76 +1,76 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */

-/* vim:set ts=2 sw=2 sts=2 et cindent: */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is Google Inc.

- * Portions created by the Initial Developer are Copyright (C) 2005

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *  Darin Fisher <darin@meer.net>

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "nsISupports.idl"

-

-interface nsIProtocolProxyService;

-interface nsIProxyInfo;

-interface nsIURI;

-

-/**

- * This interface is used to apply filters to the proxies selected for a given

- * URI.  Use nsIProtocolProxyService::registerFilter to hook up instances of

- * this interface.

- *

- * @status UNDER_REVIEW

- */

-[scriptable, uuid(f424abd3-32b4-456c-9f45-b7e3376cb0d1)]

-interface nsIProtocolProxyFilter : nsISupports

-{

-  /**

-   * This method is called to apply proxy filter rules for the given URI

-   * and proxy object (or list of proxy objects).

-   *

-   * @param aProxyService

-   *        A reference to the Protocol Proxy Service.  This is passed so that

-   *        implementations may easily access methods such as newProxyInfo.

-   * @param aURI

-   *        The URI for which these proxy settings apply.

-   * @param aProxy

-   *        The proxy (or list of proxies) that would be used by default for

-   *        the given URI.  This may be null.

-   *

-   * @return The proxy (or list of proxies) that should be used in place of

-   *         aProxy.  This can be just be aProxy if the filter chooses not to

-   *         modify the proxy.  It can also be null to indicate that a direct

-   *         connection should be used.  Use aProxyService.newProxyInfo to

-   *         construct nsIProxyInfo objects.

-   */

-  nsIProxyInfo applyFilter(in nsIProtocolProxyService aProxyService,

-                           in nsIURI aURI, in nsIProxyInfo aProxy);

-};

+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Google Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIProtocolProxyService;
+interface nsIProxyInfo;
+interface nsIURI;
+
+/**
+ * This interface is used to apply filters to the proxies selected for a given
+ * URI.  Use nsIProtocolProxyService::registerFilter to hook up instances of
+ * this interface.
+ *
+ * @status UNDER_REVIEW
+ */
+[scriptable, uuid(f424abd3-32b4-456c-9f45-b7e3376cb0d1)]
+interface nsIProtocolProxyFilter : nsISupports
+{
+  /**
+   * This method is called to apply proxy filter rules for the given URI
+   * and proxy object (or list of proxy objects).
+   *
+   * @param aProxyService
+   *        A reference to the Protocol Proxy Service.  This is passed so that
+   *        implementations may easily access methods such as newProxyInfo.
+   * @param aURI
+   *        The URI for which these proxy settings apply.
+   * @param aProxy
+   *        The proxy (or list of proxies) that would be used by default for
+   *        the given URI.  This may be null.
+   *
+   * @return The proxy (or list of proxies) that should be used in place of
+   *         aProxy.  This can be just be aProxy if the filter chooses not to
+   *         modify the proxy.  It can also be null to indicate that a direct
+   *         connection should be used.  Use aProxyService.newProxyInfo to
+   *         construct nsIProxyInfo objects.
+   */
+  nsIProxyInfo applyFilter(in nsIProtocolProxyService aProxyService,
+                           in nsIURI aURI, in nsIProxyInfo aProxy);
+};
diff --git a/third_party/gecko/nsIProtocolProxyService.idl b/third_party/gecko/nsIProtocolProxyService.idl
index 5d860e7..ae4514c 100644
--- a/third_party/gecko/nsIProtocolProxyService.idl
+++ b/third_party/gecko/nsIProtocolProxyService.idl
@@ -1,220 +1,220 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/* vim:set ts=4 sw=4 sts=4 et: */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   Darin Fisher <darin@meer.net>

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "nsISupports.idl"

-

-interface nsICancelable;

-interface nsIProtocolProxyCallback;

-interface nsIProtocolProxyFilter;

-interface nsIProxyInfo;

-interface nsIChannel;

-interface nsIURI;

-

-/**

- * nsIProtocolProxyService provides methods to access information about

- * various network proxies.

- *

- * @status UNDER_REVIEW

- */

-[scriptable, uuid(e38ab577-786e-4a7f-936b-7ae4c7d877b2)]

-interface nsIProtocolProxyService : nsISupports

-{

-    /**

-     * This flag may be passed to the resolve method to request that it fail

-     * instead of block the calling thread.  Proxy Auto Config (PAC) may

-     * perform a synchronous DNS query, which may not return immediately.  So,

-     * calling resolve without this flag may result in locking up the calling

-     * thread for a lengthy period of time.

-     *

-     * By passing this flag to resolve, one can failover to asyncResolve to

-     * avoid locking up the calling thread if a PAC query is required.

-     *

-     * When this flag is passed to resolve, resolve may throw the exception

-     * NS_BASE_STREAM_WOULD_BLOCK to indicate that it failed due to this flag

-     * being present.

-     */

-    const unsigned long RESOLVE_NON_BLOCKING = 1;

-    

-    /**

-     * This method returns a nsIProxyInfo instance that identifies a proxy to

-     * be used for loading the given URI.  Otherwise, this method returns null

-     * indicating that a direct connection should be used.

-     *

-     * @param aURI

-     *        The URI to test.

-     * @param aFlags

-     *        A bit-wise OR of the RESOLVE_ flags defined above.  Pass 0 to

-     *        specify the default behavior.

-     *

-     * NOTE: If this proxy is unavailable, getFailoverForProxy may be called

-     * to determine the correct secondary proxy to be used.

-     *

-     * NOTE: If the protocol handler for the given URI supports

-     * nsIProxiedProtocolHandler, then the nsIProxyInfo instance returned from

-     * resolve may be passed to the newProxiedChannel method to create a

-     * nsIChannel to the given URI that uses the specified proxy.

-     *

-     * NOTE: However, if the nsIProxyInfo type is "http", then it means that

-     * the given URI should be loaded using the HTTP protocol handler, which

-     * also supports nsIProxiedProtocolHandler.

-     *

-     * @see nsIProxiedProtocolHandler::newProxiedChannel 

-     */

-    nsIProxyInfo resolve(in nsIURI aURI, in unsigned long aFlags);

-

-    /**

-     * This method is an asychronous version of the resolve method.  Unlike

-     * resolve, this method is guaranteed not to block the calling thread

-     * waiting for DNS queries to complete.  This method is intended as a

-     * substitute for resolve when the result is not needed immediately.

-     *

-     * @param aURI

-     *        The URI to test.

-     * @param aFlags

-     *        A bit-wise OR of the RESOLVE_ flags defined above.  Pass 0 to

-     *        specify the default behavior.

-     * @param aCallback

-     *        The object to be notified when the result is available.

-     *

-     * @return An object that can be used to cancel the asychronous operation.

-     */

-    nsICancelable asyncResolve(in nsIURI aURI, in unsigned long aFlags,

-                               in nsIProtocolProxyCallback aCallback);

-

-    /**

-     * This method may be called to construct a nsIProxyInfo instance from

-     * the given parameters.  This method may be useful in conjunction with

-     * nsISocketTransportService::createTransport for creating, for example,

-     * a SOCKS connection.

-     *

-     * @param aType

-     *        The proxy type.  This is a string value that identifies the proxy

-     *        type.  Standard values include:

-     *          "http"   - specifies a HTTP proxy

-     *          "socks"  - specifies a SOCKS version 5 proxy

-     *          "socks4" - specifies a SOCKS version 4 proxy

-     *          "direct" - specifies a direct connection (useful for failover)

-     *        The type name is case-insensitive.  Other string values may be

-     *        possible.

-     * @param aHost

-     *        The proxy hostname or IP address.

-     * @param aPort

-     *        The proxy port.

-     * @param aFlags

-     *        Flags associated with this connection.  See nsIProxyInfo.idl

-     *        for currently defined flags.

-     * @param aFailoverTimeout

-     *        Specifies the length of time (in seconds) to ignore this proxy if

-     *        this proxy fails.  Pass PR_UINT32_MAX to specify the default

-     *        timeout value, causing nsIProxyInfo::failoverTimeout to be

-     *        assigned the default value.

-     * @param aFailoverProxy

-     *        Specifies the next proxy to try if this proxy fails.  This

-     *        parameter may be null.

-     */

-    nsIProxyInfo newProxyInfo(in ACString aType, in AUTF8String aHost,

-                              in long aPort, in unsigned long aFlags,

-                              in unsigned long aFailoverTimeout,

-                              in nsIProxyInfo aFailoverProxy);

-

-    /**

-     * If the proxy identified by aProxyInfo is unavailable for some reason,

-     * this method may be called to access an alternate proxy that may be used

-     * instead.  As a side-effect, this method may affect future result values

-     * from resolve/asyncResolve as well as from getFailoverForProxy.

-     *

-     * @param aProxyInfo

-     *        The proxy that was unavailable.

-     * @param aURI

-     *        The URI that was originally passed to resolve/asyncResolve.

-     * @param aReason

-     *        The error code corresponding to the proxy failure.  This value

-     *        may be used to tune the delay before this proxy is used again.

-     *

-     * @throw NS_ERROR_NOT_AVAILABLE if there is no alternate proxy available.

-     */

-    nsIProxyInfo getFailoverForProxy(in nsIProxyInfo aProxyInfo,

-                                     in nsIURI       aURI,

-                                     in nsresult     aReason);

-

-    /**

-     * This method may be used to register a proxy filter instance.  Each proxy

-     * filter is registered with an associated position that determines the

-     * order in which the filters are applied (starting from position 0).  When

-     * resolve/asyncResolve is called, it generates a list of proxies for the

-     * given URI, and then it applies the proxy filters.  The filters have the

-     * opportunity to modify the list of proxies.

-     *

-     * If two filters register for the same position, then the filters will be

-     * visited in the order in which they were registered.

-     *

-     * If the filter is already registered, then its position will be updated.

-     *

-     * After filters have been run, any disabled or disallowed proxies will be

-     * removed from the list.  A proxy is disabled if it had previously failed-

-     * over to another proxy (see getFailoverForProxy).  A proxy is disallowed,

-     * for example, if it is a HTTP proxy and the nsIProtocolHandler for the

-     * queried URI does not permit proxying via HTTP.

-     *

-     * If a nsIProtocolHandler disallows all proxying, then filters will never

-     * have a chance to intercept proxy requests for such URLs.

-     *

-     * @param aFilter

-     *        The nsIProtocolProxyFilter instance to be registered.

-     * @param aPosition

-     *        The position of the filter.

-     *

-     * NOTE: It is possible to construct filters that compete with one another

-     * in undesirable ways.  This API does not attempt to protect against such

-     * problems.  It is recommended that any extensions that choose to call

-     * this method make their position value configurable at runtime (perhaps

-     * via the preferences service).

-     */

-    void registerFilter(in nsIProtocolProxyFilter aFilter,

-                        in unsigned long aPosition);

-

-    /**

-     * This method may be used to unregister a proxy filter instance.  All

-     * filters will be automatically unregistered at XPCOM shutdown.

-     *

-     * @param aFilter

-     *        The nsIProtocolProxyFilter instance to be unregistered.

-     */

-    void unregisterFilter(in nsIProtocolProxyFilter aFilter);

-};

+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set ts=4 sw=4 sts=4 et: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsICancelable;
+interface nsIProtocolProxyCallback;
+interface nsIProtocolProxyFilter;
+interface nsIProxyInfo;
+interface nsIChannel;
+interface nsIURI;
+
+/**
+ * nsIProtocolProxyService provides methods to access information about
+ * various network proxies.
+ *
+ * @status UNDER_REVIEW
+ */
+[scriptable, uuid(e38ab577-786e-4a7f-936b-7ae4c7d877b2)]
+interface nsIProtocolProxyService : nsISupports
+{
+    /**
+     * This flag may be passed to the resolve method to request that it fail
+     * instead of block the calling thread.  Proxy Auto Config (PAC) may
+     * perform a synchronous DNS query, which may not return immediately.  So,
+     * calling resolve without this flag may result in locking up the calling
+     * thread for a lengthy period of time.
+     *
+     * By passing this flag to resolve, one can failover to asyncResolve to
+     * avoid locking up the calling thread if a PAC query is required.
+     *
+     * When this flag is passed to resolve, resolve may throw the exception
+     * NS_BASE_STREAM_WOULD_BLOCK to indicate that it failed due to this flag
+     * being present.
+     */
+    const unsigned long RESOLVE_NON_BLOCKING = 1;
+    
+    /**
+     * This method returns a nsIProxyInfo instance that identifies a proxy to
+     * be used for loading the given URI.  Otherwise, this method returns null
+     * indicating that a direct connection should be used.
+     *
+     * @param aURI
+     *        The URI to test.
+     * @param aFlags
+     *        A bit-wise OR of the RESOLVE_ flags defined above.  Pass 0 to
+     *        specify the default behavior.
+     *
+     * NOTE: If this proxy is unavailable, getFailoverForProxy may be called
+     * to determine the correct secondary proxy to be used.
+     *
+     * NOTE: If the protocol handler for the given URI supports
+     * nsIProxiedProtocolHandler, then the nsIProxyInfo instance returned from
+     * resolve may be passed to the newProxiedChannel method to create a
+     * nsIChannel to the given URI that uses the specified proxy.
+     *
+     * NOTE: However, if the nsIProxyInfo type is "http", then it means that
+     * the given URI should be loaded using the HTTP protocol handler, which
+     * also supports nsIProxiedProtocolHandler.
+     *
+     * @see nsIProxiedProtocolHandler::newProxiedChannel 
+     */
+    nsIProxyInfo resolve(in nsIURI aURI, in unsigned long aFlags);
+
+    /**
+     * This method is an asychronous version of the resolve method.  Unlike
+     * resolve, this method is guaranteed not to block the calling thread
+     * waiting for DNS queries to complete.  This method is intended as a
+     * substitute for resolve when the result is not needed immediately.
+     *
+     * @param aURI
+     *        The URI to test.
+     * @param aFlags
+     *        A bit-wise OR of the RESOLVE_ flags defined above.  Pass 0 to
+     *        specify the default behavior.
+     * @param aCallback
+     *        The object to be notified when the result is available.
+     *
+     * @return An object that can be used to cancel the asychronous operation.
+     */
+    nsICancelable asyncResolve(in nsIURI aURI, in unsigned long aFlags,
+                               in nsIProtocolProxyCallback aCallback);
+
+    /**
+     * This method may be called to construct a nsIProxyInfo instance from
+     * the given parameters.  This method may be useful in conjunction with
+     * nsISocketTransportService::createTransport for creating, for example,
+     * a SOCKS connection.
+     *
+     * @param aType
+     *        The proxy type.  This is a string value that identifies the proxy
+     *        type.  Standard values include:
+     *          "http"   - specifies a HTTP proxy
+     *          "socks"  - specifies a SOCKS version 5 proxy
+     *          "socks4" - specifies a SOCKS version 4 proxy
+     *          "direct" - specifies a direct connection (useful for failover)
+     *        The type name is case-insensitive.  Other string values may be
+     *        possible.
+     * @param aHost
+     *        The proxy hostname or IP address.
+     * @param aPort
+     *        The proxy port.
+     * @param aFlags
+     *        Flags associated with this connection.  See nsIProxyInfo.idl
+     *        for currently defined flags.
+     * @param aFailoverTimeout
+     *        Specifies the length of time (in seconds) to ignore this proxy if
+     *        this proxy fails.  Pass PR_UINT32_MAX to specify the default
+     *        timeout value, causing nsIProxyInfo::failoverTimeout to be
+     *        assigned the default value.
+     * @param aFailoverProxy
+     *        Specifies the next proxy to try if this proxy fails.  This
+     *        parameter may be null.
+     */
+    nsIProxyInfo newProxyInfo(in ACString aType, in AUTF8String aHost,
+                              in long aPort, in unsigned long aFlags,
+                              in unsigned long aFailoverTimeout,
+                              in nsIProxyInfo aFailoverProxy);
+
+    /**
+     * If the proxy identified by aProxyInfo is unavailable for some reason,
+     * this method may be called to access an alternate proxy that may be used
+     * instead.  As a side-effect, this method may affect future result values
+     * from resolve/asyncResolve as well as from getFailoverForProxy.
+     *
+     * @param aProxyInfo
+     *        The proxy that was unavailable.
+     * @param aURI
+     *        The URI that was originally passed to resolve/asyncResolve.
+     * @param aReason
+     *        The error code corresponding to the proxy failure.  This value
+     *        may be used to tune the delay before this proxy is used again.
+     *
+     * @throw NS_ERROR_NOT_AVAILABLE if there is no alternate proxy available.
+     */
+    nsIProxyInfo getFailoverForProxy(in nsIProxyInfo aProxyInfo,
+                                     in nsIURI       aURI,
+                                     in nsresult     aReason);
+
+    /**
+     * This method may be used to register a proxy filter instance.  Each proxy
+     * filter is registered with an associated position that determines the
+     * order in which the filters are applied (starting from position 0).  When
+     * resolve/asyncResolve is called, it generates a list of proxies for the
+     * given URI, and then it applies the proxy filters.  The filters have the
+     * opportunity to modify the list of proxies.
+     *
+     * If two filters register for the same position, then the filters will be
+     * visited in the order in which they were registered.
+     *
+     * If the filter is already registered, then its position will be updated.
+     *
+     * After filters have been run, any disabled or disallowed proxies will be
+     * removed from the list.  A proxy is disabled if it had previously failed-
+     * over to another proxy (see getFailoverForProxy).  A proxy is disallowed,
+     * for example, if it is a HTTP proxy and the nsIProtocolHandler for the
+     * queried URI does not permit proxying via HTTP.
+     *
+     * If a nsIProtocolHandler disallows all proxying, then filters will never
+     * have a chance to intercept proxy requests for such URLs.
+     *
+     * @param aFilter
+     *        The nsIProtocolProxyFilter instance to be registered.
+     * @param aPosition
+     *        The position of the filter.
+     *
+     * NOTE: It is possible to construct filters that compete with one another
+     * in undesirable ways.  This API does not attempt to protect against such
+     * problems.  It is recommended that any extensions that choose to call
+     * this method make their position value configurable at runtime (perhaps
+     * via the preferences service).
+     */
+    void registerFilter(in nsIProtocolProxyFilter aFilter,
+                        in unsigned long aPosition);
+
+    /**
+     * This method may be used to unregister a proxy filter instance.  All
+     * filters will be automatically unregistered at XPCOM shutdown.
+     *
+     * @param aFilter
+     *        The nsIProtocolProxyFilter instance to be unregistered.
+     */
+    void unregisterFilter(in nsIProtocolProxyFilter aFilter);
+};
diff --git a/third_party/gecko/nsIProtocolProxyService0.idl b/third_party/gecko/nsIProtocolProxyService0.idl
index 891ee27..a045d07 100644
--- a/third_party/gecko/nsIProtocolProxyService0.idl
+++ b/third_party/gecko/nsIProtocolProxyService0.idl
@@ -1,59 +1,59 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is 

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or 

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/**

- * NOTE: This is the version of nsIProtocolProxyService from Mozilla 1.7 --Darin

- */

-

-#include "nsISupports.idl"

-#include "nsIURI.idl"

-

-interface nsIProxyInfo0;

-

-[scriptable, uuid(91c4fe40-76c2-433f-9324-ffdae12df4b4)]

-interface nsIProtocolProxyService0 : nsISupports

-{

-    readonly attribute PRBool proxyEnabled;

-

-    /** Given a uri, return a proxyInfo */

-    nsIProxyInfo0 examineForProxy(in nsIURI aURI);

-

-    /** Return a proxyInfo with the given data */

-    nsIProxyInfo0 newProxyInfo(in string type, in string host, in long port);

-

-    void configureFromPAC(in string url);

-};

+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * NOTE: This is the version of nsIProtocolProxyService from Mozilla 1.7 --Darin
+ */
+
+#include "nsISupports.idl"
+#include "nsIURI.idl"
+
+interface nsIProxyInfo0;
+
+[scriptable, uuid(91c4fe40-76c2-433f-9324-ffdae12df4b4)]
+interface nsIProtocolProxyService0 : nsISupports
+{
+    readonly attribute PRBool proxyEnabled;
+
+    /** Given a uri, return a proxyInfo */
+    nsIProxyInfo0 examineForProxy(in nsIURI aURI);
+
+    /** Return a proxyInfo with the given data */
+    nsIProxyInfo0 newProxyInfo(in string type, in string host, in long port);
+
+    void configureFromPAC(in string url);
+};
diff --git a/third_party/gecko/nsIProxiedProtocolHandler.idl b/third_party/gecko/nsIProxiedProtocolHandler.idl
index a461935..6d6e37f 100644
--- a/third_party/gecko/nsIProxiedProtocolHandler.idl
+++ b/third_party/gecko/nsIProxiedProtocolHandler.idl
@@ -1,42 +1,42 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/*

- * The contents of this file are subject to the Mozilla Public

- * License Version 1.1 (the "License"); you may not use this file

- * except in compliance with the License. You may obtain a copy of

- * the License at http://www.mozilla.org/MPL/

- * 

- * Software distributed under the License is distributed on an "AS

- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or

- * implied. See the License for the specific language governing

- * rights and limitations under the License.

- * 

- * The Original Code is Mozilla.

- * 

- * The Initial Developer of the Original Code is Netscape

- * Communications.  Portions created by Netscape Communications are

- * Copyright (C) 2001 by Netscape Communications.  All

- * Rights Reserved.

- * 

- * Contributor(s): Bradley Baetz <bbaetz@netscape.com> (original author)

- *

- */

-

-/**

- * NOTE: This is the version of nsIProxiedProtocolHandler from Mozilla 1.7 --Darin

- */

-

-#include "nsIProtocolHandler.idl"

-

-interface nsIChannel;

-interface nsIURI;

-interface nsIProxyInfo0;

-

-[scriptable, uuid(0a24fed4-1dd2-11b2-a75c-9f8b9a8f9ba7)]

-interface nsIProxiedProtocolHandler : nsIProtocolHandler

-{

-    /** Create a new channel with the given proxyInfo

-     *

-     */

-    nsIChannel newProxiedChannel(in nsIURI uri, in nsIProxyInfo0 proxyInfo);

-};

-

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is Mozilla.
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications.  Portions created by Netscape Communications are
+ * Copyright (C) 2001 by Netscape Communications.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s): Bradley Baetz <bbaetz@netscape.com> (original author)
+ *
+ */
+
+/**
+ * NOTE: This is the version of nsIProxiedProtocolHandler from Mozilla 1.7 --Darin
+ */
+
+#include "nsIProtocolHandler.idl"
+
+interface nsIChannel;
+interface nsIURI;
+interface nsIProxyInfo0;
+
+[scriptable, uuid(0a24fed4-1dd2-11b2-a75c-9f8b9a8f9ba7)]
+interface nsIProxiedProtocolHandler : nsIProtocolHandler
+{
+    /** Create a new channel with the given proxyInfo
+     *
+     */
+    nsIChannel newProxiedChannel(in nsIURI uri, in nsIProxyInfo0 proxyInfo);
+};
+
diff --git a/third_party/gecko/nsIProxyInfo.idl b/third_party/gecko/nsIProxyInfo.idl
index fc5c9aa..bbe07b8 100644
--- a/third_party/gecko/nsIProxyInfo.idl
+++ b/third_party/gecko/nsIProxyInfo.idl
@@ -1,104 +1,104 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   Bradley Baetz <bbaetz@netscape.com> (Original Developer)

- *   Malcolm Smith <malsmith@cs.rmit.edu.au>

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "nsISupports.idl"

-

-/**

- * This interface identifies a proxy server.

- *

- * @status UNDER_REVIEW

- */

-[scriptable, uuid(3fe9308b-1608-4fa0-933c-c5ec2c6175fd)]

-interface nsIProxyInfo : nsISupports

-{

-  /**

-   * This attribute specifies the hostname of the proxy server.

-   */

-  readonly attribute AUTF8String host;

-

-  /**

-   * This attribute specifies the port number of the proxy server.

-   */

-  readonly attribute long port;

-

-  /**

-   * This attribute specifies the type of the proxy server as an ASCII string.

-   *

-   * Some special values for this attribute include (but are not limited to)

-   * the following:

-   *   "http"     HTTP proxy (or SSL CONNECT for HTTPS)

-   *   "socks"    SOCKS v5 proxy

-   *   "socks4"   SOCKS v4 proxy

-   *   "direct"   no proxy

-   */

-  readonly attribute ACString type; 

-

-  /**

-   * This attribute specifies flags that modify the proxy type.  The value of

-   * this attribute is the bit-wise combination of the Proxy Flags defined

-   * below.  Any undefined bits are reserved for future use.

-   */

-  readonly attribute unsigned long flags;

-

-  /**

-   * This attribute specifies the failover timeout in seconds for this proxy.

-   * If a nsIProxyInfo is reported as failed via nsIProtocolProxyService::

-   * getFailoverForProxy, then the failed proxy will not be used again for this

-   * many seconds.

-   */

-  readonly attribute unsigned long failoverTimeout;

-

-  /**

-   * This attribute specifies the proxy to failover to when this proxy fails.

-   */

-  attribute nsIProxyInfo failoverProxy;

-

-

-  /****************************************************************************

-   * The following "Proxy Flags" may be bit-wise combined to construct the flags

-   * attribute defined on this interface.

-   */

-

-  /**

-   * This flag is set if the proxy is to perform name resolution itself.  If

-   * this is the case, the hostname is used in some fashion, and we shouldn't

-   * do any form of DNS lookup ourselves.

-   */

-  const unsigned short TRANSPARENT_PROXY_RESOLVES_HOST = 1 << 0;

-};

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bradley Baetz <bbaetz@netscape.com> (Original Developer)
+ *   Malcolm Smith <malsmith@cs.rmit.edu.au>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+/**
+ * This interface identifies a proxy server.
+ *
+ * @status UNDER_REVIEW
+ */
+[scriptable, uuid(3fe9308b-1608-4fa0-933c-c5ec2c6175fd)]
+interface nsIProxyInfo : nsISupports
+{
+  /**
+   * This attribute specifies the hostname of the proxy server.
+   */
+  readonly attribute AUTF8String host;
+
+  /**
+   * This attribute specifies the port number of the proxy server.
+   */
+  readonly attribute long port;
+
+  /**
+   * This attribute specifies the type of the proxy server as an ASCII string.
+   *
+   * Some special values for this attribute include (but are not limited to)
+   * the following:
+   *   "http"     HTTP proxy (or SSL CONNECT for HTTPS)
+   *   "socks"    SOCKS v5 proxy
+   *   "socks4"   SOCKS v4 proxy
+   *   "direct"   no proxy
+   */
+  readonly attribute ACString type; 
+
+  /**
+   * This attribute specifies flags that modify the proxy type.  The value of
+   * this attribute is the bit-wise combination of the Proxy Flags defined
+   * below.  Any undefined bits are reserved for future use.
+   */
+  readonly attribute unsigned long flags;
+
+  /**
+   * This attribute specifies the failover timeout in seconds for this proxy.
+   * If a nsIProxyInfo is reported as failed via nsIProtocolProxyService::
+   * getFailoverForProxy, then the failed proxy will not be used again for this
+   * many seconds.
+   */
+  readonly attribute unsigned long failoverTimeout;
+
+  /**
+   * This attribute specifies the proxy to failover to when this proxy fails.
+   */
+  attribute nsIProxyInfo failoverProxy;
+
+
+  /****************************************************************************
+   * The following "Proxy Flags" may be bit-wise combined to construct the flags
+   * attribute defined on this interface.
+   */
+
+  /**
+   * This flag is set if the proxy is to perform name resolution itself.  If
+   * this is the case, the hostname is used in some fashion, and we shouldn't
+   * do any form of DNS lookup ourselves.
+   */
+  const unsigned short TRANSPARENT_PROXY_RESOLVES_HOST = 1 << 0;
+};
diff --git a/third_party/gecko/nsIProxyInfo0.idl b/third_party/gecko/nsIProxyInfo0.idl
index 74e85d7..ef0f45d 100644
--- a/third_party/gecko/nsIProxyInfo0.idl
+++ b/third_party/gecko/nsIProxyInfo0.idl
@@ -1,67 +1,67 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

-/* ***** BEGIN LICENSE BLOCK *****

- * Version: NPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Netscape Public License

- * Version 1.1 (the "License"); you may not use this file except in

- * compliance with the License. You may obtain a copy of the License at

- * http://www.mozilla.org/NPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is 

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *                  Bradley Baetz <bbaetz@netscape.com> (Original Developer)

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or 

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the NPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the NPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/**

- * NOTE: This is the version of nsIProxyInfo from Mozilla 1.7 --Darin

- */

-

-#include "nsISupports.idl"

-

-/* This interface is PRIVATE.

- * It is used as an opaque cookie, and this class may change at

- * any time without notice.

- *

- * @see nsIProtocolProxyService0::GetProxyInfo

- */

-

-native constCharPtr(const char*);

-

-[scriptable, uuid(b65d22b0-1dd1-11b2-8f95-920e5b7b56f0)]

-interface nsIProxyInfo0 : nsISupports

-{

-    [noscript, notxpcom] constCharPtr Host();

-    [noscript, notxpcom] PRInt32 Port();

-    [noscript, notxpcom] constCharPtr Type();

-

-    /**

-     * proxy info objects may be chained if several proxies could be treated

-     * equivalently.  this is used to support proxy failover.

-     */

-    readonly attribute nsIProxyInfo0 next;

-};

-

+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is 
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *                  Bradley Baetz <bbaetz@netscape.com> (Original Developer)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or 
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * NOTE: This is the version of nsIProxyInfo from Mozilla 1.7 --Darin
+ */
+
+#include "nsISupports.idl"
+
+/* This interface is PRIVATE.
+ * It is used as an opaque cookie, and this class may change at
+ * any time without notice.
+ *
+ * @see nsIProtocolProxyService0::GetProxyInfo
+ */
+
+native constCharPtr(const char*);
+
+[scriptable, uuid(b65d22b0-1dd1-11b2-8f95-920e5b7b56f0)]
+interface nsIProxyInfo0 : nsISupports
+{
+    [noscript, notxpcom] constCharPtr Host();
+    [noscript, notxpcom] PRInt32 Port();
+    [noscript, notxpcom] constCharPtr Type();
+
+    /**
+     * proxy info objects may be chained if several proxies could be treated
+     * equivalently.  this is used to support proxy failover.
+     */
+    readonly attribute nsIProxyInfo0 next;
+};
+
diff --git a/third_party/gecko/nsITimer.idl b/third_party/gecko/nsITimer.idl
index 82f91c5..8548938 100644
--- a/third_party/gecko/nsITimer.idl
+++ b/third_party/gecko/nsITimer.idl
@@ -1,196 +1,196 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 2002

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either of the GNU General Public License Version 2 or later (the "GPL"),

- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-#include "nsISupports.idl"

-

-interface nsIObserver;

-

-%{C++

-/**

- * The signature of the timer callback function passed to initWithFuncCallback.

- * This is the function that will get called when the timer expires if the

- * timer is initialized via initWithFuncCallback.

- *

- * @param aTimer the timer which has expired

- * @param aClosure opaque parameter passed to initWithFuncCallback

- *

- * Implementers should return the following:

- *

- * @return NS_OK

- *

- */

-class nsITimer;

-typedef void (*nsTimerCallbackFunc) (nsITimer *aTimer, void *aClosure);

-%}

-

-native nsTimerCallbackFunc(nsTimerCallbackFunc);

-

-/**

- * The callback interface for timers.

- */

-interface nsITimer;

-

-[scriptable, uuid(a796816d-7d47-4348-9ab8-c7aeb3216a7d)]

-interface nsITimerCallback : nsISupports

-{

-  /**

-   * @param aTimer the timer which has expired

-   */

-  void notify(in nsITimer timer);

-};

-

-

-/**

- * nsITimer instances must be initialized by calling one of the "init" methods

- * documented below.  You may also re-initialize an existing instance with new

- * delay to avoid the overhead of destroying and creating a timer.  It is not

- * necessary to cancel the timer in that case.

- */

-[scriptable, uuid(436a83fa-b396-11d9-bcfa-00112478d626)]

-interface nsITimer : nsISupports

-{

-  /* Timer types */

-

-  /**

-   * Type of a timer that fires once only.

-   */

-  const short TYPE_ONE_SHOT           = 0;

-

-  /**

-   * After firing, a TYPE_REPEATING_SLACK timer is stopped and not restarted

-   * until its callback completes.  Specified timer period will be at least

-   * the time between when processing for last firing the callback completes

-   * and when the next firing occurs.

-   *

-   * This is the preferable repeating type for most situations.

-   */

-  const short TYPE_REPEATING_SLACK    = 1;

-  

-  /**

-   * An TYPE_REPEATING_PRECISE repeating timer aims to have constant period

-   * between firings.  The processing time for each timer callback should not

-   * influence the timer period.  However, if the processing for the last

-   * timer firing could not be completed until just before the next firing

-   * occurs, then you could have two timer notification routines being

-   * executed in quick succession.

-   */

-  const short TYPE_REPEATING_PRECISE  = 2;

-

-  /**

-   * Initialize a timer that will fire after the said delay.

-   * A user must keep a reference to this timer till it is 

-   * is no longer needed or has been cancelled.

-   *

-   * @param aObserver   the callback object that observes the 

-   *                    ``timer-callback'' topic with the subject being

-   *                    the timer itself when the timer fires:

-   *

-   *                    observe(nsISupports aSubject, => nsITimer

-   *                            string aTopic,        => ``timer-callback''

-   *                            wstring data          =>  null

-   *

-   * @param aDelay      delay in milliseconds for timer to fire

-   * @param aType       timer type per TYPE* consts defined above

-   */

-  void init(in nsIObserver aObserver, in unsigned long aDelay, 

-            in unsigned long aType);

-

-

-  /**

-   * Initialize a timer to fire after the given millisecond interval.

-   * This version takes a function to call and a closure to pass to

-   * that function.

-   *

-   * @param aFunc      The function to invoke

-   * @param aClosure   An opaque pointer to pass to that function

-   * @param aDelay     The millisecond interval

-   * @param aType      Timer type per TYPE* consts defined above

-   */

-  [noscript] void initWithFuncCallback(in nsTimerCallbackFunc aCallback,

-                                       in voidPtr aClosure,

-                                       in unsigned long aDelay, 

-                                       in unsigned long aType);

-

-  /**

-   * Initialize a timer to fire after the given millisecond interval.

-   * This version takes a function to call and a closure to pass to

-   * that function.

-   *

-   * @param aFunc      nsITimerCallback interface to call when timer expires

-   * @param aDelay     The millisecond interval

-   * @param aType      Timer type per TYPE* consts defined above

-   */

-  void initWithCallback(in nsITimerCallback aCallback,

-                        in unsigned long aDelay, 

-                        in unsigned long aType);

-

-  /**

-   * Cancel the timer.  This method works on all types, not just on repeating

-   * timers -- you might want to cancel a TYPE_ONE_SHOT timer, and even reuse

-   * it by re-initializing it (to avoid object destruction and creation costs

-   * by conserving one timer instance).

-   */

-  void cancel();

-  

-  /**

-   * The millisecond delay of the timeout

-   */

-  attribute unsigned long delay;

-  

-  /**

-   * The timer type : one shot or repeating

-   */  

-  attribute unsigned long type;

-

-  /**

-   * The opaque pointer pass to initWithFuncCallback.

-   */  

-  [noscript] readonly attribute voidPtr closure;

-

-  /**

-   * The nsITimerCallback object passed to initWithCallback.

-   */

-  readonly attribute nsITimerCallback callback;

-};

-

-%{C++

-#define NS_TIMER_CONTRACTID "@mozilla.org/timer;1"

-#define NS_TIMER_CALLBACK_TOPIC "timer-callback"

-%}

-

+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIObserver;
+
+%{C++
+/**
+ * The signature of the timer callback function passed to initWithFuncCallback.
+ * This is the function that will get called when the timer expires if the
+ * timer is initialized via initWithFuncCallback.
+ *
+ * @param aTimer the timer which has expired
+ * @param aClosure opaque parameter passed to initWithFuncCallback
+ *
+ * Implementers should return the following:
+ *
+ * @return NS_OK
+ *
+ */
+class nsITimer;
+typedef void (*nsTimerCallbackFunc) (nsITimer *aTimer, void *aClosure);
+%}
+
+native nsTimerCallbackFunc(nsTimerCallbackFunc);
+
+/**
+ * The callback interface for timers.
+ */
+interface nsITimer;
+
+[scriptable, uuid(a796816d-7d47-4348-9ab8-c7aeb3216a7d)]
+interface nsITimerCallback : nsISupports
+{
+  /**
+   * @param aTimer the timer which has expired
+   */
+  void notify(in nsITimer timer);
+};
+
+
+/**
+ * nsITimer instances must be initialized by calling one of the "init" methods
+ * documented below.  You may also re-initialize an existing instance with new
+ * delay to avoid the overhead of destroying and creating a timer.  It is not
+ * necessary to cancel the timer in that case.
+ */
+[scriptable, uuid(436a83fa-b396-11d9-bcfa-00112478d626)]
+interface nsITimer : nsISupports
+{
+  /* Timer types */
+
+  /**
+   * Type of a timer that fires once only.
+   */
+  const short TYPE_ONE_SHOT           = 0;
+
+  /**
+   * After firing, a TYPE_REPEATING_SLACK timer is stopped and not restarted
+   * until its callback completes.  Specified timer period will be at least
+   * the time between when processing for last firing the callback completes
+   * and when the next firing occurs.
+   *
+   * This is the preferable repeating type for most situations.
+   */
+  const short TYPE_REPEATING_SLACK    = 1;
+  
+  /**
+   * An TYPE_REPEATING_PRECISE repeating timer aims to have constant period
+   * between firings.  The processing time for each timer callback should not
+   * influence the timer period.  However, if the processing for the last
+   * timer firing could not be completed until just before the next firing
+   * occurs, then you could have two timer notification routines being
+   * executed in quick succession.
+   */
+  const short TYPE_REPEATING_PRECISE  = 2;
+
+  /**
+   * Initialize a timer that will fire after the said delay.
+   * A user must keep a reference to this timer till it is 
+   * is no longer needed or has been cancelled.
+   *
+   * @param aObserver   the callback object that observes the 
+   *                    ``timer-callback'' topic with the subject being
+   *                    the timer itself when the timer fires:
+   *
+   *                    observe(nsISupports aSubject, => nsITimer
+   *                            string aTopic,        => ``timer-callback''
+   *                            wstring data          =>  null
+   *
+   * @param aDelay      delay in milliseconds for timer to fire
+   * @param aType       timer type per TYPE* consts defined above
+   */
+  void init(in nsIObserver aObserver, in unsigned long aDelay, 
+            in unsigned long aType);
+
+
+  /**
+   * Initialize a timer to fire after the given millisecond interval.
+   * This version takes a function to call and a closure to pass to
+   * that function.
+   *
+   * @param aFunc      The function to invoke
+   * @param aClosure   An opaque pointer to pass to that function
+   * @param aDelay     The millisecond interval
+   * @param aType      Timer type per TYPE* consts defined above
+   */
+  [noscript] void initWithFuncCallback(in nsTimerCallbackFunc aCallback,
+                                       in voidPtr aClosure,
+                                       in unsigned long aDelay, 
+                                       in unsigned long aType);
+
+  /**
+   * Initialize a timer to fire after the given millisecond interval.
+   * This version takes a function to call and a closure to pass to
+   * that function.
+   *
+   * @param aFunc      nsITimerCallback interface to call when timer expires
+   * @param aDelay     The millisecond interval
+   * @param aType      Timer type per TYPE* consts defined above
+   */
+  void initWithCallback(in nsITimerCallback aCallback,
+                        in unsigned long aDelay, 
+                        in unsigned long aType);
+
+  /**
+   * Cancel the timer.  This method works on all types, not just on repeating
+   * timers -- you might want to cancel a TYPE_ONE_SHOT timer, and even reuse
+   * it by re-initializing it (to avoid object destruction and creation costs
+   * by conserving one timer instance).
+   */
+  void cancel();
+  
+  /**
+   * The millisecond delay of the timeout
+   */
+  attribute unsigned long delay;
+  
+  /**
+   * The timer type : one shot or repeating
+   */  
+  attribute unsigned long type;
+
+  /**
+   * The opaque pointer pass to initWithFuncCallback.
+   */  
+  [noscript] readonly attribute voidPtr closure;
+
+  /**
+   * The nsITimerCallback object passed to initWithCallback.
+   */
+  readonly attribute nsITimerCallback callback;
+};
+
+%{C++
+#define NS_TIMER_CONTRACTID "@mozilla.org/timer;1"
+#define NS_TIMER_CALLBACK_TOPIC "timer-callback"
+%}
+
diff --git a/third_party/gecko/nsITimer0.idl b/third_party/gecko/nsITimer0.idl
index 09ab230..4c042a9 100644
--- a/third_party/gecko/nsITimer0.idl
+++ b/third_party/gecko/nsITimer0.idl
@@ -1,195 +1,195 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 2002

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either of the GNU General Public License Version 2 or later (the "GPL"),

- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/**

- * NOTE: This is the version of nsITimer from Mozilla 1.7 --Darin

- */

-

-#include "nsISupports.idl"

-

-interface nsIObserver;

-

-%{C++

-/**

- * The signature of the timer callback function passed to initWithCallback. This

- * is the function that will get called when the timer expires if the timer is 

- * initialized via initWithCallback.

- *

- * @param aTimer the timer which has expired

- * @param aClosure opaque parameter passed to initWithCallback

- *

- * Implementers should return the following:

- *

- * @return NS_OK

- *

- */

-class nsITimer0;

-typedef void (*nsTimerCallbackFunc0) (nsITimer0 *aTimer, void *aClosure);

-%}

-

-native nsTimerCallbackFunc0(nsTimerCallbackFunc0);

-

-/**

- * The callback interface for timers.

- */

-interface nsITimer0;

-

-[scriptable, uuid(a796816d-7d47-4348-9ab8-c7aeb3216a7d)]

-interface nsITimerCallback0 : nsISupports

-{

-  /**

-   * @param aTimer the timer which has expired

-   */

-  void notify(in nsITimer0 timer);

-};

-

-

-/**

- * nsITimer0 instances must be initialized by calling one of the "init" methods

- * documented below.  You may also re-initialize an existing instance with new

- * delay to avoid the overhead of destroying and creating a timer.  It is not

- * necessary to cancel the timer in that case.

- */

-[scriptable, uuid(29ee628e-a3ea-471f-965d-dc9f11d1c183)]

-interface nsITimer0 : nsISupports

-{

-  /* Timer types */

-

-  /**

-   * Type of a timer that fires once only.

-   */

-  const short TYPE_ONE_SHOT           = 0;

-

-  /**

-   * After firing, a TYPE_REPEATING_SLACK timer is stopped and not restarted

-   * until its callback completes.  Specified timer period will be at least

-   * the time between when processing for last firing the callback completes

-   * and when the next firing occurs.

-   *

-   * This is the preferable repeating type for most situations.

-   */

-  const short TYPE_REPEATING_SLACK    = 1;

-  

-  /**

-   * An TYPE_REPEATING_PRECISE repeating timer aims to have constant period

-   * between firings.  The processing time for each timer callback should not

-   * influence the timer period.  However, if the processing for the last

-   * timer firing could not be completed until just before the next firing

-   * occurs, then you could have two timer notification routines being

-   * executed in quick succession.

-   */

-  const short TYPE_REPEATING_PRECISE  = 2;

-

-  /**

-   * Initialize a timer that will fire after the said delay.

-   * A user must keep a reference to this timer till it is 

-   * is no longer needed or has been cancelled.

-   *

-   * @param aObserver   the callback object that observes the 

-   *                    ``timer-callback'' topic with the subject being

-   *                    the timer itself when the timer fires:

-   *

-   *                    observe(nsISupports aSubject, => nsITimer0

-   *                            string aTopic,        => ``timer-callback''

-   *                            wstring data          =>  null

-   *

-   * @param aDelay      delay in milliseconds for timer to fire

-   * @param aType       timer type per TYPE* consts defined above

-   */

-  void init(in nsIObserver aObserver, in unsigned long aDelay, 

-            in unsigned long aType);

-

-

-  /**

-   * Initialize a timer to fire after the given millisecond interval.

-   * This version takes a function to call and a closure to pass to

-   * that function.

-   *

-   * @param aFunc      The function to invoke

-   * @param aClosure   An opaque pointer to pass to that function

-   * @param aDelay     The millisecond interval

-   * @param aType      Timer type per TYPE* consts defined above

-   */

-  [noscript] void initWithFuncCallback(in nsTimerCallbackFunc0 aCallback,

-                                       in voidPtr aClosure,

-                                       in unsigned long aDelay, 

-                                       in unsigned long aType);

-

-  /**

-   * Initialize a timer to fire after the given millisecond interval.

-   * This version takes a function to call and a closure to pass to

-   * that function.

-   *

-   * @param aFunc      nsITimerCallback0 interface to call when timer expires

-   * @param aDelay     The millisecond interval

-   * @param aType      Timer type per TYPE* consts defined above

-   */

-  void initWithCallback(in nsITimerCallback0 aCallback,

-                        in unsigned long aDelay, 

-                        in unsigned long aType);

-

-  /**

-   * Cancel the timer.  This method works on all types, not just on repeating

-   * timers -- you might want to cancel a TYPE_ONE_SHOT timer, and even reuse

-   * it by re-initializing it (to avoid object destruction and creation costs

-   * by conserving one timer instance).

-   */

-  void cancel();

-  

-  /**

-   * The millisecond delay of the timeout

-   */

-  attribute unsigned long delay;

-  

-  /**

-   * The timer type : one shot or repeating

-   */  

-  attribute unsigned long type;

-

-  /**

-   * The opaque pointer pass to initWithCallback.

-   */  

-  [noscript] readonly attribute voidPtr closure;

-};

-

-%{C++

-#define NS_TIMER_CONTRACTID "@mozilla.org/timer;1"

-#define NS_TIMER_CALLBACK_TOPIC "timer-callback"

-%}

-

+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2002
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/**
+ * NOTE: This is the version of nsITimer from Mozilla 1.7 --Darin
+ */
+
+#include "nsISupports.idl"
+
+interface nsIObserver;
+
+%{C++
+/**
+ * The signature of the timer callback function passed to initWithCallback. This
+ * is the function that will get called when the timer expires if the timer is 
+ * initialized via initWithCallback.
+ *
+ * @param aTimer the timer which has expired
+ * @param aClosure opaque parameter passed to initWithCallback
+ *
+ * Implementers should return the following:
+ *
+ * @return NS_OK
+ *
+ */
+class nsITimer0;
+typedef void (*nsTimerCallbackFunc0) (nsITimer0 *aTimer, void *aClosure);
+%}
+
+native nsTimerCallbackFunc0(nsTimerCallbackFunc0);
+
+/**
+ * The callback interface for timers.
+ */
+interface nsITimer0;
+
+[scriptable, uuid(a796816d-7d47-4348-9ab8-c7aeb3216a7d)]
+interface nsITimerCallback0 : nsISupports
+{
+  /**
+   * @param aTimer the timer which has expired
+   */
+  void notify(in nsITimer0 timer);
+};
+
+
+/**
+ * nsITimer0 instances must be initialized by calling one of the "init" methods
+ * documented below.  You may also re-initialize an existing instance with new
+ * delay to avoid the overhead of destroying and creating a timer.  It is not
+ * necessary to cancel the timer in that case.
+ */
+[scriptable, uuid(29ee628e-a3ea-471f-965d-dc9f11d1c183)]
+interface nsITimer0 : nsISupports
+{
+  /* Timer types */
+
+  /**
+   * Type of a timer that fires once only.
+   */
+  const short TYPE_ONE_SHOT           = 0;
+
+  /**
+   * After firing, a TYPE_REPEATING_SLACK timer is stopped and not restarted
+   * until its callback completes.  Specified timer period will be at least
+   * the time between when processing for last firing the callback completes
+   * and when the next firing occurs.
+   *
+   * This is the preferable repeating type for most situations.
+   */
+  const short TYPE_REPEATING_SLACK    = 1;
+  
+  /**
+   * An TYPE_REPEATING_PRECISE repeating timer aims to have constant period
+   * between firings.  The processing time for each timer callback should not
+   * influence the timer period.  However, if the processing for the last
+   * timer firing could not be completed until just before the next firing
+   * occurs, then you could have two timer notification routines being
+   * executed in quick succession.
+   */
+  const short TYPE_REPEATING_PRECISE  = 2;
+
+  /**
+   * Initialize a timer that will fire after the said delay.
+   * A user must keep a reference to this timer till it is 
+   * is no longer needed or has been cancelled.
+   *
+   * @param aObserver   the callback object that observes the 
+   *                    ``timer-callback'' topic with the subject being
+   *                    the timer itself when the timer fires:
+   *
+   *                    observe(nsISupports aSubject, => nsITimer0
+   *                            string aTopic,        => ``timer-callback''
+   *                            wstring data          =>  null
+   *
+   * @param aDelay      delay in milliseconds for timer to fire
+   * @param aType       timer type per TYPE* consts defined above
+   */
+  void init(in nsIObserver aObserver, in unsigned long aDelay, 
+            in unsigned long aType);
+
+
+  /**
+   * Initialize a timer to fire after the given millisecond interval.
+   * This version takes a function to call and a closure to pass to
+   * that function.
+   *
+   * @param aFunc      The function to invoke
+   * @param aClosure   An opaque pointer to pass to that function
+   * @param aDelay     The millisecond interval
+   * @param aType      Timer type per TYPE* consts defined above
+   */
+  [noscript] void initWithFuncCallback(in nsTimerCallbackFunc0 aCallback,
+                                       in voidPtr aClosure,
+                                       in unsigned long aDelay, 
+                                       in unsigned long aType);
+
+  /**
+   * Initialize a timer to fire after the given millisecond interval.
+   * This version takes a function to call and a closure to pass to
+   * that function.
+   *
+   * @param aFunc      nsITimerCallback0 interface to call when timer expires
+   * @param aDelay     The millisecond interval
+   * @param aType      Timer type per TYPE* consts defined above
+   */
+  void initWithCallback(in nsITimerCallback0 aCallback,
+                        in unsigned long aDelay, 
+                        in unsigned long aType);
+
+  /**
+   * Cancel the timer.  This method works on all types, not just on repeating
+   * timers -- you might want to cancel a TYPE_ONE_SHOT timer, and even reuse
+   * it by re-initializing it (to avoid object destruction and creation costs
+   * by conserving one timer instance).
+   */
+  void cancel();
+  
+  /**
+   * The millisecond delay of the timeout
+   */
+  attribute unsigned long delay;
+  
+  /**
+   * The timer type : one shot or repeating
+   */  
+  attribute unsigned long type;
+
+  /**
+   * The opaque pointer pass to initWithCallback.
+   */  
+  [noscript] readonly attribute voidPtr closure;
+};
+
+%{C++
+#define NS_TIMER_CONTRACTID "@mozilla.org/timer;1"
+#define NS_TIMER_CALLBACK_TOPIC "timer-callback"
+%}
+
diff --git a/third_party/gecko/nsIWebNavigation.idl b/third_party/gecko/nsIWebNavigation.idl
index bd65f19..1de75b2 100644
--- a/third_party/gecko/nsIWebNavigation.idl
+++ b/third_party/gecko/nsIWebNavigation.idl
@@ -1,206 +1,206 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-

- *

- * The contents of this file are subject to the Mozilla Public

- * License Version 1.1 (the "License"); you may not use this file

- * except in compliance with the License. You may obtain a copy of

- * the License at http://www.mozilla.org/MPL/

- * 

- * Software distributed under the License is distributed on an "AS

- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or

- * implied. See the License for the specific language governing

- * rights and limitations under the License.

- * 

- * The Original Code is the Mozilla browser.

- * 

- * The Initial Developer of the Original Code is Netscape

- * Communications, Inc.  Portions created by Netscape are

- * Copyright (C) 1999, Mozilla.  All Rights Reserved.

- * 

- * Contributor(s):

- *   Travis Bogard <travis@netscape.com>

- */

-#include "nsISupports.idl"

-

-

-/**

- * The nsIWebNavigation interface defines an interface for navigating the web.

- * It provides methods and attributes to direct an object to navigate to a new

- * location, stop or restart an in process load or determine where the object,

- * has previously gone.   

- *

- * @status UNDER_REVIEW

- */

-

-interface nsIDOMDocument;

-interface nsIInputStream;

-interface nsISHistory;

-interface nsISHEntry;

-interface nsIURI;

-

-[scriptable, uuid(F5D9E7B0-D930-11d3-B057-00A024FFC08C)]

-interface nsIWebNavigation : nsISupports

-{

- /**

-  * Indicates if the object can go back.  If true this indicates that

-  * there is back session history available for navigation.

-  */

-  readonly attribute boolean canGoBack;

-

- /**

-  * Indicates if the object can go forward.  If true this indicates that

-  * there is forward session history available for navigation

-  */

-  readonly attribute boolean canGoForward;

-

- /**

-  * Tells the object to navigate to the previous session history item.  When

-  * a page is loaded from session history, all content is loaded from the

-  * cache (if available) and page state (such as form values, scroll position)

-  * is restored.

-  *

-  * @return NS_OK               - Backward navigation was successful.

-  *         NS_ERROR_UNEXPECTED - This call was unexpected at this time.  Most

-  *                               likely you can't go back right now.

-  */

-  void goBack();

-

- /**

-  * Tells the object to navigate to the next Forward session history item.

-  * When a page is loaded from session history, all content is loaded from

-  * the cache (if available) and page state (such as form values, scroll

-  * position) is restored.

-  *

-  * @return NS_OK               - Forward was successful.

-  *         NS_ERROR_UNEXPECTED - This call was unexpected at this time.  Most

-  *                               likely you can't go forward right now.

-  */

-  void goForward();

-

- /**

-  * Tells the object to navigate to the session history item at index.

-  *

-  * @return NS_OK -               GotoIndex was successful.

-  *         NS_ERROR_UNEXPECTED - This call was unexpected at this time.  Most

-  *                               likely you can't goto that index

-  */

-  void gotoIndex(in long index);

-

- /**

-  * Load flags for use with loadURI() and reload()

-  */

-  const unsigned long LOAD_FLAGS_MASK            = 0xffff;

-

- /**

-  * loadURI() specific flags

-  */

-

- /**

-  * Normal load flag.

-  */

-  const unsigned long LOAD_FLAGS_NONE            = 0x0000;

-

- /**

-  * Meta-refresh flag.  The cache is bypassed.  This type of load is

-  *                     usually the result of a meta-refresh tag, or a HTTP

-  *                     'refresh' header.

-  */

-  const unsigned long LOAD_FLAGS_IS_REFRESH      = 0x0010;

-

- /**

-  * Link-click flag. 

-  */

-  const unsigned long LOAD_FLAGS_IS_LINK         = 0x0020;

-

- /**

-  * Bypass history flag.

-  */

-  const unsigned long LOAD_FLAGS_BYPASS_HISTORY  = 0x0040;

-

- /**

-  * Replace history entry flag.

-  */

-  const unsigned long LOAD_FLAGS_REPLACE_HISTORY = 0x0080;

-

-  /* loadURI() & reload() specific flags */

-  const unsigned long LOAD_FLAGS_BYPASS_CACHE    = 0x0100; // Bypass the cache

-  const unsigned long LOAD_FLAGS_BYPASS_PROXY    = 0x0200; // Bypass the proxy

-  const unsigned long LOAD_FLAGS_CHARSET_CHANGE  = 0x0400; // Reload because of charset change, 

-

- /**

-  * Loads a given URI.  This will give priority to loading the requested URI

-  * in the object implementing	this interface.  If it can't be loaded here

-  * however, the URL dispatcher will go through its normal process of content

-  * loading.

-  *

-  * @param uri       - The URI string to load.

-  * @param loadFlags - Flags modifying load behaviour. Generally you will pass

-  *                    LOAD_FLAGS_NONE for this parameter.

-  * @param referrer  - The referring URI.  If this argument is NULL, the

-  *                    referring URI will be inferred internally.

-  * @param postData  - nsIInputStream containing POST data for the request.

-  */

-  void loadURI(in wstring uri,

-               in unsigned long loadFlags,

-               in nsIURI referrer,

-               in nsIInputStream postData,

-               in nsIInputStream headers);

-

- /**

-  * Tells the Object to reload the current page.

-  *

-  * @param reloadFlags - Flags modifying reload behaviour. Generally you will

-  *                      pass LOAD_FLAGS_NONE for this parameter.

-  */

-  void reload(in unsigned long reloadFlags);

-

- /**

-  * Stop() flags:

-  */

-

- /**

-  * Stop all network activity.  This includes both active network loads and

-  * pending meta-refreshes.

-  */

-  const unsigned long STOP_NETWORK = 0x01;

-

- /**

-  * Stop all content activity.  This includes animated images, plugins and

-  * pending Javascript timeouts.

-  */

-  const unsigned long STOP_CONTENT = 0x02;

-

- /**

-  * Stop all activity.

-  */

-  const unsigned long STOP_ALL = 0x03;

-

- /**

-  * Stops a load of a URI.

-  *

-  * @param stopFlags - Flags indicating the stop behavior.

-  */

-  void stop(in unsigned long stopFlags);

-

- /**

-  * Retrieves the current DOM document for the frame, or lazily creates a

-  * blank document if there is none. This attribute never returns null except

-  * for unexpected error situations.

-  */

-  readonly attribute nsIDOMDocument document;

-

- /**

-  * The currently loaded URI or null.

-  */

-  readonly attribute nsIURI currentURI;

-

- /**

-  * The referring URI.

-  */

-  readonly attribute nsIURI referringURI;

-

- /**

-  * The session history object used to store the session history for the

-  * session.

-  */

-  attribute nsISHistory sessionHistory;

-};

+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Mozilla browser.
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications, Inc.  Portions created by Netscape are
+ * Copyright (C) 1999, Mozilla.  All Rights Reserved.
+ * 
+ * Contributor(s):
+ *   Travis Bogard <travis@netscape.com>
+ */
+#include "nsISupports.idl"
+
+
+/**
+ * The nsIWebNavigation interface defines an interface for navigating the web.
+ * It provides methods and attributes to direct an object to navigate to a new
+ * location, stop or restart an in process load or determine where the object,
+ * has previously gone.   
+ *
+ * @status UNDER_REVIEW
+ */
+
+interface nsIDOMDocument;
+interface nsIInputStream;
+interface nsISHistory;
+interface nsISHEntry;
+interface nsIURI;
+
+[scriptable, uuid(F5D9E7B0-D930-11d3-B057-00A024FFC08C)]
+interface nsIWebNavigation : nsISupports
+{
+ /**
+  * Indicates if the object can go back.  If true this indicates that
+  * there is back session history available for navigation.
+  */
+  readonly attribute boolean canGoBack;
+
+ /**
+  * Indicates if the object can go forward.  If true this indicates that
+  * there is forward session history available for navigation
+  */
+  readonly attribute boolean canGoForward;
+
+ /**
+  * Tells the object to navigate to the previous session history item.  When
+  * a page is loaded from session history, all content is loaded from the
+  * cache (if available) and page state (such as form values, scroll position)
+  * is restored.
+  *
+  * @return NS_OK               - Backward navigation was successful.
+  *         NS_ERROR_UNEXPECTED - This call was unexpected at this time.  Most
+  *                               likely you can't go back right now.
+  */
+  void goBack();
+
+ /**
+  * Tells the object to navigate to the next Forward session history item.
+  * When a page is loaded from session history, all content is loaded from
+  * the cache (if available) and page state (such as form values, scroll
+  * position) is restored.
+  *
+  * @return NS_OK               - Forward was successful.
+  *         NS_ERROR_UNEXPECTED - This call was unexpected at this time.  Most
+  *                               likely you can't go forward right now.
+  */
+  void goForward();
+
+ /**
+  * Tells the object to navigate to the session history item at index.
+  *
+  * @return NS_OK -               GotoIndex was successful.
+  *         NS_ERROR_UNEXPECTED - This call was unexpected at this time.  Most
+  *                               likely you can't goto that index
+  */
+  void gotoIndex(in long index);
+
+ /**
+  * Load flags for use with loadURI() and reload()
+  */
+  const unsigned long LOAD_FLAGS_MASK            = 0xffff;
+
+ /**
+  * loadURI() specific flags
+  */
+
+ /**
+  * Normal load flag.
+  */
+  const unsigned long LOAD_FLAGS_NONE            = 0x0000;
+
+ /**
+  * Meta-refresh flag.  The cache is bypassed.  This type of load is
+  *                     usually the result of a meta-refresh tag, or a HTTP
+  *                     'refresh' header.
+  */
+  const unsigned long LOAD_FLAGS_IS_REFRESH      = 0x0010;
+
+ /**
+  * Link-click flag. 
+  */
+  const unsigned long LOAD_FLAGS_IS_LINK         = 0x0020;
+
+ /**
+  * Bypass history flag.
+  */
+  const unsigned long LOAD_FLAGS_BYPASS_HISTORY  = 0x0040;
+
+ /**
+  * Replace history entry flag.
+  */
+  const unsigned long LOAD_FLAGS_REPLACE_HISTORY = 0x0080;
+
+  /* loadURI() & reload() specific flags */
+  const unsigned long LOAD_FLAGS_BYPASS_CACHE    = 0x0100; // Bypass the cache
+  const unsigned long LOAD_FLAGS_BYPASS_PROXY    = 0x0200; // Bypass the proxy
+  const unsigned long LOAD_FLAGS_CHARSET_CHANGE  = 0x0400; // Reload because of charset change, 
+
+ /**
+  * Loads a given URI.  This will give priority to loading the requested URI
+  * in the object implementing	this interface.  If it can't be loaded here
+  * however, the URL dispatcher will go through its normal process of content
+  * loading.
+  *
+  * @param uri       - The URI string to load.
+  * @param loadFlags - Flags modifying load behaviour. Generally you will pass
+  *                    LOAD_FLAGS_NONE for this parameter.
+  * @param referrer  - The referring URI.  If this argument is NULL, the
+  *                    referring URI will be inferred internally.
+  * @param postData  - nsIInputStream containing POST data for the request.
+  */
+  void loadURI(in wstring uri,
+               in unsigned long loadFlags,
+               in nsIURI referrer,
+               in nsIInputStream postData,
+               in nsIInputStream headers);
+
+ /**
+  * Tells the Object to reload the current page.
+  *
+  * @param reloadFlags - Flags modifying reload behaviour. Generally you will
+  *                      pass LOAD_FLAGS_NONE for this parameter.
+  */
+  void reload(in unsigned long reloadFlags);
+
+ /**
+  * Stop() flags:
+  */
+
+ /**
+  * Stop all network activity.  This includes both active network loads and
+  * pending meta-refreshes.
+  */
+  const unsigned long STOP_NETWORK = 0x01;
+
+ /**
+  * Stop all content activity.  This includes animated images, plugins and
+  * pending Javascript timeouts.
+  */
+  const unsigned long STOP_CONTENT = 0x02;
+
+ /**
+  * Stop all activity.
+  */
+  const unsigned long STOP_ALL = 0x03;
+
+ /**
+  * Stops a load of a URI.
+  *
+  * @param stopFlags - Flags indicating the stop behavior.
+  */
+  void stop(in unsigned long stopFlags);
+
+ /**
+  * Retrieves the current DOM document for the frame, or lazily creates a
+  * blank document if there is none. This attribute never returns null except
+  * for unexpected error situations.
+  */
+  readonly attribute nsIDOMDocument document;
+
+ /**
+  * The currently loaded URI or null.
+  */
+  readonly attribute nsIURI currentURI;
+
+ /**
+  * The referring URI.
+  */
+  readonly attribute nsIURI referringURI;
+
+ /**
+  * The session history object used to store the session history for the
+  * session.
+  */
+  attribute nsISHistory sessionHistory;
+};
diff --git a/third_party/gecko/nsIWritablePropertyBag.idl b/third_party/gecko/nsIWritablePropertyBag.idl
index ba28730..83bdab0 100644
--- a/third_party/gecko/nsIWritablePropertyBag.idl
+++ b/third_party/gecko/nsIWritablePropertyBag.idl
@@ -1,60 +1,60 @@
-/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-

- *

- * ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org code.

- *

- * The Initial Developer of the Original Code is

- * Netscape Communications Corporation.

- * Portions created by the Initial Developer are Copyright (C) 1998

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *   John Bandhauer <jband@netscape.com>

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either of the GNU General Public License Version 2 or later (the "GPL"),

- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/* nsIVariant based writable Property Bag support. */

-

-#include "nsIPropertyBag.idl"

-

-[scriptable, uuid(96fc4671-eeb4-4823-9421-e50fb70ad353)]

-interface nsIWritablePropertyBag : nsIPropertyBag

-{

-    /**

-     * Set a property with the given name to the given value.  If

-     * a property already exists with the given name, it is

-     * overwritten.

-     */

-    void setProperty(in AString name, in nsIVariant value);

-

-    /**

-     * Delete a property with the given name.

-     * @throws NS_ERROR_FAILURE if a property with that name doesn't

-     * exist.

-     */

-    void deleteProperty(in AString name);

-};

+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   John Bandhauer <jband@netscape.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* nsIVariant based writable Property Bag support. */
+
+#include "nsIPropertyBag.idl"
+
+[scriptable, uuid(96fc4671-eeb4-4823-9421-e50fb70ad353)]
+interface nsIWritablePropertyBag : nsIPropertyBag
+{
+    /**
+     * Set a property with the given name to the given value.  If
+     * a property already exists with the given name, it is
+     * overwritten.
+     */
+    void setProperty(in AString name, in nsIVariant value);
+
+    /**
+     * Delete a property with the given name.
+     * @throws NS_ERROR_FAILURE if a property with that name doesn't
+     * exist.
+     */
+    void deleteProperty(in AString name);
+};
diff --git a/third_party/gecko/nsIWritablePropertyBag2.idl b/third_party/gecko/nsIWritablePropertyBag2.idl
index 2abe2a5..9968015 100644
--- a/third_party/gecko/nsIWritablePropertyBag2.idl
+++ b/third_party/gecko/nsIWritablePropertyBag2.idl
@@ -1,55 +1,55 @@
-/* ***** BEGIN LICENSE BLOCK *****

- * Version: MPL 1.1/GPL 2.0/LGPL 2.1

- *

- * The contents of this file are subject to the Mozilla Public License Version

- * 1.1 (the "License"); you may not use this file except in compliance with

- * the License. You may obtain a copy of the License at

- * http://www.mozilla.org/MPL/

- *

- * Software distributed under the License is distributed on an "AS IS" basis,

- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License

- * for the specific language governing rights and limitations under the

- * License.

- *

- * The Original Code is mozilla.org property bag support.

- *

- * The Initial Developer of the Original Code is

- * Christian Biesinger <cbiesinger@web.de>.

- * Portions created by the Initial Developer are Copyright (C) 2005

- * the Initial Developer. All Rights Reserved.

- *

- * Contributor(s):

- *    Darin Fisher <darin@meer.net>

- *

- * Alternatively, the contents of this file may be used under the terms of

- * either the GNU General Public License Version 2 or later (the "GPL"), or

- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),

- * in which case the provisions of the GPL or the LGPL are applicable instead

- * of those above. If you wish to allow use of your version of this file only

- * under the terms of either the GPL or the LGPL, and not to allow others to

- * use your version of this file under the terms of the MPL, indicate your

- * decision by deleting the provisions above and replace them with the notice

- * and other provisions required by the GPL or the LGPL. If you do not delete

- * the provisions above, a recipient may use your version of this file under

- * the terms of any one of the MPL, the GPL or the LGPL.

- *

- * ***** END LICENSE BLOCK ***** */

-

-/* nsIVariant based Property Bag support. */

-

-#include "nsIPropertyBag2.idl"

-

-[scriptable, uuid(ee42c54a-19d3-472b-8bc3-76318d5ab5f4)]

-interface nsIWritablePropertyBag2 : nsIPropertyBag2

-{

-  void        setPropertyAsInt32       (in AString prop, in PRInt32 value);

-  void        setPropertyAsUint32      (in AString prop, in PRUint32 value);

-  void        setPropertyAsInt64       (in AString prop, in PRInt64 value);

-  void        setPropertyAsUint64      (in AString prop, in PRUint64 value);

-  void        setPropertyAsDouble      (in AString prop, in double value);

-  void        setPropertyAsAString     (in AString prop, in AString value);

-  void        setPropertyAsACString    (in AString prop, in ACString value);

-  void        setPropertyAsAUTF8String (in AString prop, in AUTF8String value);

-  void        setPropertyAsBool        (in AString prop, in boolean value);

-  void        setPropertyAsInterface   (in AString prop, in nsISupports value);

-};

+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org property bag support.
+ *
+ * The Initial Developer of the Original Code is
+ * Christian Biesinger <cbiesinger@web.de>.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *    Darin Fisher <darin@meer.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* nsIVariant based Property Bag support. */
+
+#include "nsIPropertyBag2.idl"
+
+[scriptable, uuid(ee42c54a-19d3-472b-8bc3-76318d5ab5f4)]
+interface nsIWritablePropertyBag2 : nsIPropertyBag2
+{
+  void        setPropertyAsInt32       (in AString prop, in PRInt32 value);
+  void        setPropertyAsUint32      (in AString prop, in PRUint32 value);
+  void        setPropertyAsInt64       (in AString prop, in PRInt64 value);
+  void        setPropertyAsUint64      (in AString prop, in PRUint64 value);
+  void        setPropertyAsDouble      (in AString prop, in double value);
+  void        setPropertyAsAString     (in AString prop, in AString value);
+  void        setPropertyAsACString    (in AString prop, in ACString value);
+  void        setPropertyAsAUTF8String (in AString prop, in AUTF8String value);
+  void        setPropertyAsBool        (in AString prop, in boolean value);
+  void        setPropertyAsInterface   (in AString prop, in nsISupports value);
+};
diff --git a/third_party/gtest/build.scons b/third_party/gtest/build.scons
index 2266736..8c4aaf1 100644
--- a/third_party/gtest/build.scons
+++ b/third_party/gtest/build.scons
@@ -1,55 +1,55 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-gtest_env = env.Clone()

-gtest_env.Append(

-    CPPPATH = [

-        '$MAIN_DIR/third_party/gtest/include',

-        '$MAIN_DIR/third_party/gtest',

-        ],

-    CCFLAGS = [

-        '/wd4061',  # enumerator in switch is not handled by a case label

-        '/wd4100',  # unreferenced formal parameter

-        '/wd4640',  # construction of local static object is not thread-safe

-        '/wd4505',  # unreferenced local function has been removed

-        '/wd4548',  # expression before comma has no effect

-        ],

-    CPPDEFINES = [

-        '_CRT_NONSTDC_NO_DEPRECATE',

-        ],

-)

-

-target_name = 'gtest.lib'

-

-gtest_inputs = [

-    'src/gtest.cc',

-    'src/gtest-death-test.cc',

-    'src/gtest-filepath.cc',

-    'src/gtest-port.cc',

-    'src/gtest-test-part.cc',

-    'src/gtest-typed-test.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  gtest_inputs += gtest_env.EnablePrecompile(target_name)

-

-gtest_env.ComponentLibrary(

-    lib_name=target_name,

-    source=gtest_inputs,

-)

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+gtest_env = env.Clone()
+gtest_env.Append(
+    CPPPATH = [
+        '$MAIN_DIR/third_party/gtest/include',
+        '$MAIN_DIR/third_party/gtest',
+        ],
+    CCFLAGS = [
+        '/wd4061',  # enumerator in switch is not handled by a case label
+        '/wd4100',  # unreferenced formal parameter
+        '/wd4640',  # construction of local static object is not thread-safe
+        '/wd4505',  # unreferenced local function has been removed
+        '/wd4548',  # expression before comma has no effect
+        ],
+    CPPDEFINES = [
+        '_CRT_NONSTDC_NO_DEPRECATE',
+        ],
+)
+
+target_name = 'gtest.lib'
+
+gtest_inputs = [
+    'src/gtest.cc',
+    'src/gtest-death-test.cc',
+    'src/gtest-filepath.cc',
+    'src/gtest-port.cc',
+    'src/gtest-test-part.cc',
+    'src/gtest-typed-test.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  gtest_inputs += gtest_env.EnablePrecompile(target_name)
+
+gtest_env.ComponentLibrary(
+    lib_name=target_name,
+    source=gtest_inputs,
+)
+
diff --git a/third_party/gtest/include/gtest/gtest-death-test.h b/third_party/gtest/include/gtest/gtest-death-test.h
index 7bf6183..dcb2b66 100644
--- a/third_party/gtest/include/gtest/gtest-death-test.h
+++ b/third_party/gtest/include/gtest/gtest-death-test.h
@@ -1,262 +1,262 @@
-// Copyright 2005, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan)

-//

-// The Google C++ Testing Framework (Google Test)

-//

-// This header file defines the public API for death tests.  It is

-// #included by gtest.h so a user doesn't need to include this

-// directly.

-

-#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_

-#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_

-

-#include <gtest/internal/gtest-death-test-internal.h>

-

-namespace testing {

-

-// This flag controls the style of death tests.  Valid values are "threadsafe",

-// meaning that the death test child process will re-execute the test binary

-// from the start, running only a single death test, or "fast",

-// meaning that the child process will execute the test logic immediately

-// after forking.

-GTEST_DECLARE_string_(death_test_style);

-

-#if GTEST_HAS_DEATH_TEST

-

-// The following macros are useful for writing death tests.

-

-// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is

-// executed:

-//

-//   1. It generates a warning if there is more than one active

-//   thread.  This is because it's safe to fork() or clone() only

-//   when there is a single thread.

-//

-//   2. The parent process clone()s a sub-process and runs the death

-//   test in it; the sub-process exits with code 0 at the end of the

-//   death test, if it hasn't exited already.

-//

-//   3. The parent process waits for the sub-process to terminate.

-//

-//   4. The parent process checks the exit code and error message of

-//   the sub-process.

-//

-// Examples:

-//

-//   ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");

-//   for (int i = 0; i < 5; i++) {

-//     EXPECT_DEATH(server.ProcessRequest(i),

-//                  "Invalid request .* in ProcessRequest()")

-//         << "Failed to die on request " << i);

-//   }

-//

-//   ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");

-//

-//   bool KilledBySIGHUP(int exit_code) {

-//     return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;

-//   }

-//

-//   ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");

-//

-// On the regular expressions used in death tests:

-//

-//   On POSIX-compliant systems (*nix), we use the <regex.h> library,

-//   which uses the POSIX extended regex syntax.

-//

-//   On other platforms (e.g. Windows), we only support a simple regex

-//   syntax implemented as part of Google Test.  This limited

-//   implementation should be enough most of the time when writing

-//   death tests; though it lacks many features you can find in PCRE

-//   or POSIX extended regex syntax.  For example, we don't support

-//   union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and

-//   repetition count ("x{5,7}"), among others.

-//

-//   Below is the syntax that we do support.  We chose it to be a

-//   subset of both PCRE and POSIX extended regex, so it's easy to

-//   learn wherever you come from.  In the following: 'A' denotes a

-//   literal character, period (.), or a single \\ escape sequence;

-//   'x' and 'y' denote regular expressions; 'm' and 'n' are for

-//   natural numbers.

-//

-//     c     matches any literal character c

-//     \\d   matches any decimal digit

-//     \\D   matches any character that's not a decimal digit

-//     \\f   matches \f

-//     \\n   matches \n

-//     \\r   matches \r

-//     \\s   matches any ASCII whitespace, including \n

-//     \\S   matches any character that's not a whitespace

-//     \\t   matches \t

-//     \\v   matches \v

-//     \\w   matches any letter, _, or decimal digit

-//     \\W   matches any character that \\w doesn't match

-//     \\c   matches any literal character c, which must be a punctuation

-//     .     matches any single character except \n

-//     A?    matches 0 or 1 occurrences of A

-//     A*    matches 0 or many occurrences of A

-//     A+    matches 1 or many occurrences of A

-//     ^     matches the beginning of a string (not that of each line)

-//     $     matches the end of a string (not that of each line)

-//     xy    matches x followed by y

-//

-//   If you accidentally use PCRE or POSIX extended regex features

-//   not implemented by us, you will get a run-time failure.  In that

-//   case, please try to rewrite your regular expression within the

-//   above syntax.

-//

-//   This implementation is *not* meant to be as highly tuned or robust

-//   as a compiled regex library, but should perform well enough for a

-//   death test, which already incurs significant overhead by launching

-//   a child process.

-//

-// Known caveats:

-//

-//   A "threadsafe" style death test obtains the path to the test

-//   program from argv[0] and re-executes it in the sub-process.  For

-//   simplicity, the current implementation doesn't search the PATH

-//   when launching the sub-process.  This means that the user must

-//   invoke the test program via a path that contains at least one

-//   path separator (e.g. path/to/foo_test and

-//   /absolute/path/to/bar_test are fine, but foo_test is not).  This

-//   is rarely a problem as people usually don't put the test binary

-//   directory in PATH.

-//

-// TODO(wan@google.com): make thread-safe death tests search the PATH.

-

-// Asserts that a given statement causes the program to exit, with an

-// integer exit status that satisfies predicate, and emitting error output

-// that matches regex.

-#define ASSERT_EXIT(statement, predicate, regex) \

-  GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)

-

-// Like ASSERT_EXIT, but continues on to successive tests in the

-// test case, if any:

-#define EXPECT_EXIT(statement, predicate, regex) \

-  GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)

-

-// Asserts that a given statement causes the program to exit, either by

-// explicitly exiting with a nonzero exit code or being killed by a

-// signal, and emitting error output that matches regex.

-#define ASSERT_DEATH(statement, regex) \

-  ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)

-

-// Like ASSERT_DEATH, but continues on to successive tests in the

-// test case, if any:

-#define EXPECT_DEATH(statement, regex) \

-  EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)

-

-// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:

-

-// Tests that an exit code describes a normal exit with a given exit code.

-class ExitedWithCode {

- public:

-  explicit ExitedWithCode(int exit_code);

-  bool operator()(int exit_status) const;

- private:

-  const int exit_code_;

-};

-

-#if !GTEST_OS_WINDOWS

-// Tests that an exit code describes an exit due to termination by a

-// given signal.

-class KilledBySignal {

- public:

-  explicit KilledBySignal(int signum);

-  bool operator()(int exit_status) const;

- private:

-  const int signum_;

-};

-#endif  // !GTEST_OS_WINDOWS

-

-// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.

-// The death testing framework causes this to have interesting semantics,

-// since the sideeffects of the call are only visible in opt mode, and not

-// in debug mode.

-//

-// In practice, this can be used to test functions that utilize the

-// LOG(DFATAL) macro using the following style:

-//

-// int DieInDebugOr12(int* sideeffect) {

-//   if (sideeffect) {

-//     *sideeffect = 12;

-//   }

-//   LOG(DFATAL) << "death";

-//   return 12;

-// }

-//

-// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {

-//   int sideeffect = 0;

-//   // Only asserts in dbg.

-//   EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");

-//

-// #ifdef NDEBUG

-//   // opt-mode has sideeffect visible.

-//   EXPECT_EQ(12, sideeffect);

-// #else

-//   // dbg-mode no visible sideeffect.

-//   EXPECT_EQ(0, sideeffect);

-// #endif

-// }

-//

-// This will assert that DieInDebugReturn12InOpt() crashes in debug

-// mode, usually due to a DCHECK or LOG(DFATAL), but returns the

-// appropriate fallback value (12 in this case) in opt mode. If you

-// need to test that a function has appropriate side-effects in opt

-// mode, include assertions against the side-effects.  A general

-// pattern for this is:

-//

-// EXPECT_DEBUG_DEATH({

-//   // Side-effects here will have an effect after this statement in

-//   // opt mode, but none in debug mode.

-//   EXPECT_EQ(12, DieInDebugOr12(&sideeffect));

-// }, "death");

-//

-#ifdef NDEBUG

-

-#define EXPECT_DEBUG_DEATH(statement, regex) \

-  do { statement; } while (false)

-

-#define ASSERT_DEBUG_DEATH(statement, regex) \

-  do { statement; } while (false)

-

-#else

-

-#define EXPECT_DEBUG_DEATH(statement, regex) \

-  EXPECT_DEATH(statement, regex)

-

-#define ASSERT_DEBUG_DEATH(statement, regex) \

-  ASSERT_DEATH(statement, regex)

-

-#endif  // NDEBUG for EXPECT_DEBUG_DEATH

-#endif  // GTEST_HAS_DEATH_TEST

-}  // namespace testing

-

-#endif  // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_

+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for death tests.  It is
+// #included by gtest.h so a user doesn't need to include this
+// directly.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+
+#include <gtest/internal/gtest-death-test-internal.h>
+
+namespace testing {
+
+// This flag controls the style of death tests.  Valid values are "threadsafe",
+// meaning that the death test child process will re-execute the test binary
+// from the start, running only a single death test, or "fast",
+// meaning that the child process will execute the test logic immediately
+// after forking.
+GTEST_DECLARE_string_(death_test_style);
+
+#if GTEST_HAS_DEATH_TEST
+
+// The following macros are useful for writing death tests.
+
+// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
+// executed:
+//
+//   1. It generates a warning if there is more than one active
+//   thread.  This is because it's safe to fork() or clone() only
+//   when there is a single thread.
+//
+//   2. The parent process clone()s a sub-process and runs the death
+//   test in it; the sub-process exits with code 0 at the end of the
+//   death test, if it hasn't exited already.
+//
+//   3. The parent process waits for the sub-process to terminate.
+//
+//   4. The parent process checks the exit code and error message of
+//   the sub-process.
+//
+// Examples:
+//
+//   ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
+//   for (int i = 0; i < 5; i++) {
+//     EXPECT_DEATH(server.ProcessRequest(i),
+//                  "Invalid request .* in ProcessRequest()")
+//         << "Failed to die on request " << i);
+//   }
+//
+//   ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
+//
+//   bool KilledBySIGHUP(int exit_code) {
+//     return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
+//   }
+//
+//   ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
+//
+// On the regular expressions used in death tests:
+//
+//   On POSIX-compliant systems (*nix), we use the <regex.h> library,
+//   which uses the POSIX extended regex syntax.
+//
+//   On other platforms (e.g. Windows), we only support a simple regex
+//   syntax implemented as part of Google Test.  This limited
+//   implementation should be enough most of the time when writing
+//   death tests; though it lacks many features you can find in PCRE
+//   or POSIX extended regex syntax.  For example, we don't support
+//   union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
+//   repetition count ("x{5,7}"), among others.
+//
+//   Below is the syntax that we do support.  We chose it to be a
+//   subset of both PCRE and POSIX extended regex, so it's easy to
+//   learn wherever you come from.  In the following: 'A' denotes a
+//   literal character, period (.), or a single \\ escape sequence;
+//   'x' and 'y' denote regular expressions; 'm' and 'n' are for
+//   natural numbers.
+//
+//     c     matches any literal character c
+//     \\d   matches any decimal digit
+//     \\D   matches any character that's not a decimal digit
+//     \\f   matches \f
+//     \\n   matches \n
+//     \\r   matches \r
+//     \\s   matches any ASCII whitespace, including \n
+//     \\S   matches any character that's not a whitespace
+//     \\t   matches \t
+//     \\v   matches \v
+//     \\w   matches any letter, _, or decimal digit
+//     \\W   matches any character that \\w doesn't match
+//     \\c   matches any literal character c, which must be a punctuation
+//     .     matches any single character except \n
+//     A?    matches 0 or 1 occurrences of A
+//     A*    matches 0 or many occurrences of A
+//     A+    matches 1 or many occurrences of A
+//     ^     matches the beginning of a string (not that of each line)
+//     $     matches the end of a string (not that of each line)
+//     xy    matches x followed by y
+//
+//   If you accidentally use PCRE or POSIX extended regex features
+//   not implemented by us, you will get a run-time failure.  In that
+//   case, please try to rewrite your regular expression within the
+//   above syntax.
+//
+//   This implementation is *not* meant to be as highly tuned or robust
+//   as a compiled regex library, but should perform well enough for a
+//   death test, which already incurs significant overhead by launching
+//   a child process.
+//
+// Known caveats:
+//
+//   A "threadsafe" style death test obtains the path to the test
+//   program from argv[0] and re-executes it in the sub-process.  For
+//   simplicity, the current implementation doesn't search the PATH
+//   when launching the sub-process.  This means that the user must
+//   invoke the test program via a path that contains at least one
+//   path separator (e.g. path/to/foo_test and
+//   /absolute/path/to/bar_test are fine, but foo_test is not).  This
+//   is rarely a problem as people usually don't put the test binary
+//   directory in PATH.
+//
+// TODO(wan@google.com): make thread-safe death tests search the PATH.
+
+// Asserts that a given statement causes the program to exit, with an
+// integer exit status that satisfies predicate, and emitting error output
+// that matches regex.
+#define ASSERT_EXIT(statement, predicate, regex) \
+  GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
+
+// Like ASSERT_EXIT, but continues on to successive tests in the
+// test case, if any:
+#define EXPECT_EXIT(statement, predicate, regex) \
+  GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
+
+// Asserts that a given statement causes the program to exit, either by
+// explicitly exiting with a nonzero exit code or being killed by a
+// signal, and emitting error output that matches regex.
+#define ASSERT_DEATH(statement, regex) \
+  ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Like ASSERT_DEATH, but continues on to successive tests in the
+// test case, if any:
+#define EXPECT_DEATH(statement, regex) \
+  EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
+
+// Tests that an exit code describes a normal exit with a given exit code.
+class ExitedWithCode {
+ public:
+  explicit ExitedWithCode(int exit_code);
+  bool operator()(int exit_status) const;
+ private:
+  const int exit_code_;
+};
+
+#if !GTEST_OS_WINDOWS
+// Tests that an exit code describes an exit due to termination by a
+// given signal.
+class KilledBySignal {
+ public:
+  explicit KilledBySignal(int signum);
+  bool operator()(int exit_status) const;
+ private:
+  const int signum_;
+};
+#endif  // !GTEST_OS_WINDOWS
+
+// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
+// The death testing framework causes this to have interesting semantics,
+// since the sideeffects of the call are only visible in opt mode, and not
+// in debug mode.
+//
+// In practice, this can be used to test functions that utilize the
+// LOG(DFATAL) macro using the following style:
+//
+// int DieInDebugOr12(int* sideeffect) {
+//   if (sideeffect) {
+//     *sideeffect = 12;
+//   }
+//   LOG(DFATAL) << "death";
+//   return 12;
+// }
+//
+// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
+//   int sideeffect = 0;
+//   // Only asserts in dbg.
+//   EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
+//
+// #ifdef NDEBUG
+//   // opt-mode has sideeffect visible.
+//   EXPECT_EQ(12, sideeffect);
+// #else
+//   // dbg-mode no visible sideeffect.
+//   EXPECT_EQ(0, sideeffect);
+// #endif
+// }
+//
+// This will assert that DieInDebugReturn12InOpt() crashes in debug
+// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
+// appropriate fallback value (12 in this case) in opt mode. If you
+// need to test that a function has appropriate side-effects in opt
+// mode, include assertions against the side-effects.  A general
+// pattern for this is:
+//
+// EXPECT_DEBUG_DEATH({
+//   // Side-effects here will have an effect after this statement in
+//   // opt mode, but none in debug mode.
+//   EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
+// }, "death");
+//
+#ifdef NDEBUG
+
+#define EXPECT_DEBUG_DEATH(statement, regex) \
+  do { statement; } while (false)
+
+#define ASSERT_DEBUG_DEATH(statement, regex) \
+  do { statement; } while (false)
+
+#else
+
+#define EXPECT_DEBUG_DEATH(statement, regex) \
+  EXPECT_DEATH(statement, regex)
+
+#define ASSERT_DEBUG_DEATH(statement, regex) \
+  ASSERT_DEATH(statement, regex)
+
+#endif  // NDEBUG for EXPECT_DEBUG_DEATH
+#endif  // GTEST_HAS_DEATH_TEST
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
diff --git a/third_party/gtest/include/gtest/gtest-message.h b/third_party/gtest/include/gtest/gtest-message.h
index 4e14113..99ae454 100644
--- a/third_party/gtest/include/gtest/gtest-message.h
+++ b/third_party/gtest/include/gtest/gtest-message.h
@@ -1,224 +1,224 @@
-// Copyright 2005, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan)

-//

-// The Google C++ Testing Framework (Google Test)

-//

-// This header file defines the Message class.

-//

-// IMPORTANT NOTE: Due to limitation of the C++ language, we have to

-// leave some internal implementation details in this header file.

-// They are clearly marked by comments like this:

-//

-//   // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-//

-// Such code is NOT meant to be used by a user directly, and is subject

-// to CHANGE WITHOUT NOTICE.  Therefore DO NOT DEPEND ON IT in a user

-// program!

-

-#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_

-#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_

-

-#include <gtest/internal/gtest-string.h>

-#include <gtest/internal/gtest-internal.h>

-

-namespace testing {

-

-// The Message class works like an ostream repeater.

-//

-// Typical usage:

-//

-//   1. You stream a bunch of values to a Message object.

-//      It will remember the text in a StrStream.

-//   2. Then you stream the Message object to an ostream.

-//      This causes the text in the Message to be streamed

-//      to the ostream.

-//

-// For example;

-//

-//   testing::Message foo;

-//   foo << 1 << " != " << 2;

-//   std::cout << foo;

-//

-// will print "1 != 2".

-//

-// Message is not intended to be inherited from.  In particular, its

-// destructor is not virtual.

-//

-// Note that StrStream behaves differently in gcc and in MSVC.  You

-// can stream a NULL char pointer to it in the former, but not in the

-// latter (it causes an access violation if you do).  The Message

-// class hides this difference by treating a NULL char pointer as

-// "(null)".

-class Message {

- private:

-  // The type of basic IO manipulators (endl, ends, and flush) for

-  // narrow streams.

-  typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);

-

- public:

-  // Constructs an empty Message.

-  // We allocate the StrStream separately because it otherwise each use of

-  // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's

-  // stack frame leading to huge stack frames in some cases; gcc does not reuse

-  // the stack space.

-  Message() : ss_(new internal::StrStream) {}

-

-  // Copy constructor.

-  Message(const Message& msg) : ss_(new internal::StrStream) {  // NOLINT

-    *ss_ << msg.GetString();

-  }

-

-  // Constructs a Message from a C-string.

-  explicit Message(const char* str) : ss_(new internal::StrStream) {

-    *ss_ << str;

-  }

-

-  ~Message() { delete ss_; }

-#if GTEST_OS_SYMBIAN

-  // Streams a value (either a pointer or not) to this object.

-  template <typename T>

-  inline Message& operator <<(const T& value) {

-    StreamHelper(typename internal::is_pointer<T>::type(), value);

-    return *this;

-  }

-#else

-  // Streams a non-pointer value to this object.

-  template <typename T>

-  inline Message& operator <<(const T& val) {

-    ::GTestStreamToHelper(ss_, val);

-    return *this;

-  }

-

-  // Streams a pointer value to this object.

-  //

-  // This function is an overload of the previous one.  When you

-  // stream a pointer to a Message, this definition will be used as it

-  // is more specialized.  (The C++ Standard, section

-  // [temp.func.order].)  If you stream a non-pointer, then the

-  // previous definition will be used.

-  //

-  // The reason for this overload is that streaming a NULL pointer to

-  // ostream is undefined behavior.  Depending on the compiler, you

-  // may get "0", "(nil)", "(null)", or an access violation.  To

-  // ensure consistent result across compilers, we always treat NULL

-  // as "(null)".

-  template <typename T>

-  inline Message& operator <<(T* const& pointer) {  // NOLINT

-    if (pointer == NULL) {

-      *ss_ << "(null)";

-    } else {

-      ::GTestStreamToHelper(ss_, pointer);

-    }

-    return *this;

-  }

-#endif  // GTEST_OS_SYMBIAN

-

-  // Since the basic IO manipulators are overloaded for both narrow

-  // and wide streams, we have to provide this specialized definition

-  // of operator <<, even though its body is the same as the

-  // templatized version above.  Without this definition, streaming

-  // endl or other basic IO manipulators to Message will confuse the

-  // compiler.

-  Message& operator <<(BasicNarrowIoManip val) {

-    *ss_ << val;

-    return *this;

-  }

-

-  // Instead of 1/0, we want to see true/false for bool values.

-  Message& operator <<(bool b) {

-    return *this << (b ? "true" : "false");

-  }

-

-  // These two overloads allow streaming a wide C string to a Message

-  // using the UTF-8 encoding.

-  Message& operator <<(const wchar_t* wide_c_str) {

-    return *this << internal::String::ShowWideCString(wide_c_str);

-  }

-  Message& operator <<(wchar_t* wide_c_str) {

-    return *this << internal::String::ShowWideCString(wide_c_str);

-  }

-

-#if GTEST_HAS_STD_WSTRING

-  // Converts the given wide string to a narrow string using the UTF-8

-  // encoding, and streams the result to this Message object.

-  Message& operator <<(const ::std::wstring& wstr);

-#endif  // GTEST_HAS_STD_WSTRING

-

-#if GTEST_HAS_GLOBAL_WSTRING

-  // Converts the given wide string to a narrow string using the UTF-8

-  // encoding, and streams the result to this Message object.

-  Message& operator <<(const ::wstring& wstr);

-#endif  // GTEST_HAS_GLOBAL_WSTRING

-

-  // Gets the text streamed to this object so far as a String.

-  // Each '\0' character in the buffer is replaced with "\\0".

-  //

-  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-  internal::String GetString() const {

-    return internal::StrStreamToString(ss_);

-  }

-

- private:

-#if GTEST_OS_SYMBIAN

-  // These are needed as the Nokia Symbian Compiler cannot decide between

-  // const T& and const T* in a function template. The Nokia compiler _can_

-  // decide between class template specializations for T and T*, so a

-  // tr1::type_traits-like is_pointer works, and we can overload on that.

-  template <typename T>

-  inline void StreamHelper(internal::true_type dummy, T* pointer) {

-    if (pointer == NULL) {

-      *ss_ << "(null)";

-    } else {

-      ::GTestStreamToHelper(ss_, pointer);

-    }

-  }

-  template <typename T>

-  inline void StreamHelper(internal::false_type dummy, const T& value) {

-    ::GTestStreamToHelper(ss_, value);

-  }

-#endif  // GTEST_OS_SYMBIAN

-

-  // We'll hold the text streamed to this object here.

-  internal::StrStream* const ss_;

-

-  // We declare (but don't implement) this to prevent the compiler

-  // from implementing the assignment operator.

-  void operator=(const Message&);

-};

-

-// Streams a Message to an ostream.

-inline std::ostream& operator <<(std::ostream& os, const Message& sb) {

-  return os << sb.GetString();

-}

-

-}  // namespace testing

-

-#endif  // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_

+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the Message class.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+//   // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE.  Therefore DO NOT DEPEND ON IT in a user
+// program!
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+
+#include <gtest/internal/gtest-string.h>
+#include <gtest/internal/gtest-internal.h>
+
+namespace testing {
+
+// The Message class works like an ostream repeater.
+//
+// Typical usage:
+//
+//   1. You stream a bunch of values to a Message object.
+//      It will remember the text in a StrStream.
+//   2. Then you stream the Message object to an ostream.
+//      This causes the text in the Message to be streamed
+//      to the ostream.
+//
+// For example;
+//
+//   testing::Message foo;
+//   foo << 1 << " != " << 2;
+//   std::cout << foo;
+//
+// will print "1 != 2".
+//
+// Message is not intended to be inherited from.  In particular, its
+// destructor is not virtual.
+//
+// Note that StrStream behaves differently in gcc and in MSVC.  You
+// can stream a NULL char pointer to it in the former, but not in the
+// latter (it causes an access violation if you do).  The Message
+// class hides this difference by treating a NULL char pointer as
+// "(null)".
+class Message {
+ private:
+  // The type of basic IO manipulators (endl, ends, and flush) for
+  // narrow streams.
+  typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
+
+ public:
+  // Constructs an empty Message.
+  // We allocate the StrStream separately because it otherwise each use of
+  // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
+  // stack frame leading to huge stack frames in some cases; gcc does not reuse
+  // the stack space.
+  Message() : ss_(new internal::StrStream) {}
+
+  // Copy constructor.
+  Message(const Message& msg) : ss_(new internal::StrStream) {  // NOLINT
+    *ss_ << msg.GetString();
+  }
+
+  // Constructs a Message from a C-string.
+  explicit Message(const char* str) : ss_(new internal::StrStream) {
+    *ss_ << str;
+  }
+
+  ~Message() { delete ss_; }
+#if GTEST_OS_SYMBIAN
+  // Streams a value (either a pointer or not) to this object.
+  template <typename T>
+  inline Message& operator <<(const T& value) {
+    StreamHelper(typename internal::is_pointer<T>::type(), value);
+    return *this;
+  }
+#else
+  // Streams a non-pointer value to this object.
+  template <typename T>
+  inline Message& operator <<(const T& val) {
+    ::GTestStreamToHelper(ss_, val);
+    return *this;
+  }
+
+  // Streams a pointer value to this object.
+  //
+  // This function is an overload of the previous one.  When you
+  // stream a pointer to a Message, this definition will be used as it
+  // is more specialized.  (The C++ Standard, section
+  // [temp.func.order].)  If you stream a non-pointer, then the
+  // previous definition will be used.
+  //
+  // The reason for this overload is that streaming a NULL pointer to
+  // ostream is undefined behavior.  Depending on the compiler, you
+  // may get "0", "(nil)", "(null)", or an access violation.  To
+  // ensure consistent result across compilers, we always treat NULL
+  // as "(null)".
+  template <typename T>
+  inline Message& operator <<(T* const& pointer) {  // NOLINT
+    if (pointer == NULL) {
+      *ss_ << "(null)";
+    } else {
+      ::GTestStreamToHelper(ss_, pointer);
+    }
+    return *this;
+  }
+#endif  // GTEST_OS_SYMBIAN
+
+  // Since the basic IO manipulators are overloaded for both narrow
+  // and wide streams, we have to provide this specialized definition
+  // of operator <<, even though its body is the same as the
+  // templatized version above.  Without this definition, streaming
+  // endl or other basic IO manipulators to Message will confuse the
+  // compiler.
+  Message& operator <<(BasicNarrowIoManip val) {
+    *ss_ << val;
+    return *this;
+  }
+
+  // Instead of 1/0, we want to see true/false for bool values.
+  Message& operator <<(bool b) {
+    return *this << (b ? "true" : "false");
+  }
+
+  // These two overloads allow streaming a wide C string to a Message
+  // using the UTF-8 encoding.
+  Message& operator <<(const wchar_t* wide_c_str) {
+    return *this << internal::String::ShowWideCString(wide_c_str);
+  }
+  Message& operator <<(wchar_t* wide_c_str) {
+    return *this << internal::String::ShowWideCString(wide_c_str);
+  }
+
+#if GTEST_HAS_STD_WSTRING
+  // Converts the given wide string to a narrow string using the UTF-8
+  // encoding, and streams the result to this Message object.
+  Message& operator <<(const ::std::wstring& wstr);
+#endif  // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+  // Converts the given wide string to a narrow string using the UTF-8
+  // encoding, and streams the result to this Message object.
+  Message& operator <<(const ::wstring& wstr);
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+  // Gets the text streamed to this object so far as a String.
+  // Each '\0' character in the buffer is replaced with "\\0".
+  //
+  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+  internal::String GetString() const {
+    return internal::StrStreamToString(ss_);
+  }
+
+ private:
+#if GTEST_OS_SYMBIAN
+  // These are needed as the Nokia Symbian Compiler cannot decide between
+  // const T& and const T* in a function template. The Nokia compiler _can_
+  // decide between class template specializations for T and T*, so a
+  // tr1::type_traits-like is_pointer works, and we can overload on that.
+  template <typename T>
+  inline void StreamHelper(internal::true_type dummy, T* pointer) {
+    if (pointer == NULL) {
+      *ss_ << "(null)";
+    } else {
+      ::GTestStreamToHelper(ss_, pointer);
+    }
+  }
+  template <typename T>
+  inline void StreamHelper(internal::false_type dummy, const T& value) {
+    ::GTestStreamToHelper(ss_, value);
+  }
+#endif  // GTEST_OS_SYMBIAN
+
+  // We'll hold the text streamed to this object here.
+  internal::StrStream* const ss_;
+
+  // We declare (but don't implement) this to prevent the compiler
+  // from implementing the assignment operator.
+  void operator=(const Message&);
+};
+
+// Streams a Message to an ostream.
+inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
+  return os << sb.GetString();
+}
+
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
diff --git a/third_party/gtest/include/gtest/gtest-param-test.h b/third_party/gtest/include/gtest/gtest-param-test.h
index 4227e06..421517d 100644
--- a/third_party/gtest/include/gtest/gtest-param-test.h
+++ b/third_party/gtest/include/gtest/gtest-param-test.h
@@ -1,1385 +1,1385 @@
-// This file was GENERATED by a script.  DO NOT EDIT BY HAND!!!

-

-// Copyright 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Authors: vladl@google.com (Vlad Losev)

-//

-// Macros and functions for implementing parameterized tests

-// in Google C++ Testing Framework (Google Test)

-//

-// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!

-//

-#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_

-#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_

-

-

-// Value-parameterized tests allow you to test your code with different

-// parameters without writing multiple copies of the same test.

-//

-// Here is how you use value-parameterized tests:

-

-#if 0

-

-// To write value-parameterized tests, first you should define a fixture

-// class. It must be derived from testing::TestWithParam<T>, where T is

-// the type of your parameter values. TestWithParam<T> is itself derived

-// from testing::Test. T can be any copyable type. If it's a raw pointer,

-// you are responsible for managing the lifespan of the pointed values.

-

-class FooTest : public ::testing::TestWithParam<const char*> {

-  // You can implement all the usual class fixture members here.

-};

-

-// Then, use the TEST_P macro to define as many parameterized tests

-// for this fixture as you want. The _P suffix is for "parameterized"

-// or "pattern", whichever you prefer to think.

-

-TEST_P(FooTest, DoesBlah) {

-  // Inside a test, access the test parameter with the GetParam() method

-  // of the TestWithParam<T> class:

-  EXPECT_TRUE(foo.Blah(GetParam()));

-  ...

-}

-

-TEST_P(FooTest, HasBlahBlah) {

-  ...

-}

-

-// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test

-// case with any set of parameters you want. Google Test defines a number

-// of functions for generating test parameters. They return what we call

-// (surprise!) parameter generators. Here is a  summary of them, which

-// are all in the testing namespace:

-//

-//

-//  Range(begin, end [, step]) - Yields values {begin, begin+step,

-//                               begin+step+step, ...}. The values do not

-//                               include end. step defaults to 1.

-//  Values(v1, v2, ..., vN)    - Yields values {v1, v2, ..., vN}.

-//  ValuesIn(container)        - Yields values from a C-style array, an STL

-//  ValuesIn(begin,end)          container, or an iterator range [begin, end).

-//  Bool()                     - Yields sequence {false, true}.

-//  Combine(g1, g2, ..., gN)   - Yields all combinations (the Cartesian product

-//                               for the math savvy) of the values generated

-//                               by the N generators.

-//

-// For more details, see comments at the definitions of these functions below

-// in this file.

-//

-// The following statement will instantiate tests from the FooTest test case

-// each with parameter values "meeny", "miny", and "moe".

-

-INSTANTIATE_TEST_CASE_P(InstantiationName,

-                        FooTest,

-                        Values("meeny", "miny", "moe"));

-

-// To distinguish different instances of the pattern, (yes, you

-// can instantiate it more then once) the first argument to the

-// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the

-// actual test case name. Remember to pick unique prefixes for different

-// instantiations. The tests from the instantiation above will have

-// these names:

-//

-//    * InstantiationName/FooTest.DoesBlah/0 for "meeny"

-//    * InstantiationName/FooTest.DoesBlah/1 for "miny"

-//    * InstantiationName/FooTest.DoesBlah/2 for "moe"

-//    * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"

-//    * InstantiationName/FooTest.HasBlahBlah/1 for "miny"

-//    * InstantiationName/FooTest.HasBlahBlah/2 for "moe"

-//

-// You can use these names in --gtest_filter.

-//

-// This statement will instantiate all tests from FooTest again, each

-// with parameter values "cat" and "dog":

-

-const char* pets[] = {"cat", "dog"};

-INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));

-

-// The tests from the instantiation above will have these names:

-//

-//    * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"

-//    * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"

-//    * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"

-//    * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"

-//

-// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests

-// in the given test case, whether their definitions come before or

-// AFTER the INSTANTIATE_TEST_CASE_P statement.

-//

-// Please also note that generator expressions are evaluated in

-// RUN_ALL_TESTS(), after main() has started. This allows evaluation of

-// parameter list based on command line parameters.

-//

-// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc

-// for more examples.

-//

-// In the future, we plan to publish the API for defining new parameter

-// generators. But for now this interface remains part of the internal

-// implementation and is subject to change.

-

-#endif  // 0

-

-

-#include <utility>

-

-#include <gtest/internal/gtest-port.h>

-

-#if GTEST_HAS_PARAM_TEST

-

-#include <gtest/internal/gtest-internal.h>

-#include <gtest/internal/gtest-param-util.h>

-#include <gtest/internal/gtest-param-util-generated.h>

-

-namespace testing {

-

-// Functions producing parameter generators.

-//

-// Google Test uses these generators to produce parameters for value-

-// parameterized tests. When a parameterized test case is instantiated

-// with a particular generator, Google Test creates and runs tests

-// for each element in the sequence produced by the generator.

-//

-// In the following sample, tests from test case FooTest are instantiated

-// each three times with parameter values 3, 5, and 8:

-//

-// class FooTest : public TestWithParam<int> { ... };

-//

-// TEST_P(FooTest, TestThis) {

-// }

-// TEST_P(FooTest, TestThat) {

-// }

-// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));

-//

-

-// Range() returns generators providing sequences of values in a range.

-//

-// Synopsis:

-// Range(start, end)

-//   - returns a generator producing a sequence of values {start, start+1,

-//     start+2, ..., }.

-// Range(start, end, step)

-//   - returns a generator producing a sequence of values {start, start+step,

-//     start+step+step, ..., }.

-// Notes:

-//   * The generated sequences never include end. For example, Range(1, 5)

-//     returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)

-//     returns a generator producing {1, 3, 5, 7}.

-//   * start and end must have the same type. That type may be any integral or

-//     floating-point type or a user defined type satisfying these conditions:

-//     * It must be assignable (have operator=() defined).

-//     * It must have operator+() (operator+(int-compatible type) for

-//       two-operand version).

-//     * It must have operator<() defined.

-//     Elements in the resulting sequences will also have that type.

-//   * Condition start < end must be satisfied in order for resulting sequences

-//     to contain any elements.

-//

-template <typename T, typename IncrementT>

-internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {

-  return internal::ParamGenerator<T>(

-      new internal::RangeGenerator<T, IncrementT>(start, end, step));

-}

-

-template <typename T>

-internal::ParamGenerator<T> Range(T start, T end) {

-  return Range(start, end, 1);

-}

-

-// ValuesIn() function allows generation of tests with parameters coming from

-// a container.

-//

-// Synopsis:

-// ValuesIn(const T (&array)[N])

-//   - returns a generator producing sequences with elements from

-//     a C-style array.

-// ValuesIn(const Container& container)

-//   - returns a generator producing sequences with elements from

-//     an STL-style container.

-// ValuesIn(Iterator begin, Iterator end)

-//   - returns a generator producing sequences with elements from

-//     a range [begin, end) defined by a pair of STL-style iterators. These

-//     iterators can also be plain C pointers.

-//

-// Please note that ValuesIn copies the values from the containers

-// passed in and keeps them to generate tests in RUN_ALL_TESTS().

-//

-// Examples:

-//

-// This instantiates tests from test case StringTest

-// each with C-string values of "foo", "bar", and "baz":

-//

-// const char* strings[] = {"foo", "bar", "baz"};

-// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));

-//

-// This instantiates tests from test case StlStringTest

-// each with STL strings with values "a" and "b":

-//

-// ::std::vector< ::std::string> GetParameterStrings() {

-//   ::std::vector< ::std::string> v;

-//   v.push_back("a");

-//   v.push_back("b");

-//   return v;

-// }

-//

-// INSTANTIATE_TEST_CASE_P(CharSequence,

-//                         StlStringTest,

-//                         ValuesIn(GetParameterStrings()));

-//

-//

-// This will also instantiate tests from CharTest

-// each with parameter values 'a' and 'b':

-//

-// ::std::list<char> GetParameterChars() {

-//   ::std::list<char> list;

-//   list.push_back('a');

-//   list.push_back('b');

-//   return list;

-// }

-// ::std::list<char> l = GetParameterChars();

-// INSTANTIATE_TEST_CASE_P(CharSequence2,

-//                         CharTest,

-//                         ValuesIn(l.begin(), l.end()));

-//

-template <typename ForwardIterator>

-internal::ParamGenerator<

-    typename ::std::iterator_traits<ForwardIterator>::value_type> ValuesIn(

-  ForwardIterator begin,

-  ForwardIterator end) {

-  typedef typename ::std::iterator_traits<ForwardIterator>::value_type

-      ParamType;

-  return internal::ParamGenerator<ParamType>(

-      new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));

-}

-

-template <typename T, size_t N>

-internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {

-  return ValuesIn(array, array + N);

-}

-

-template <class Container>

-internal::ParamGenerator<typename Container::value_type> ValuesIn(

-    const Container& container) {

-  return ValuesIn(container.begin(), container.end());

-}

-

-// Values() allows generating tests from explicitly specified list of

-// parameters.

-//

-// Synopsis:

-// Values(T v1, T v2, ..., T vN)

-//   - returns a generator producing sequences with elements v1, v2, ..., vN.

-//

-// For example, this instantiates tests from test case BarTest each

-// with values "one", "two", and "three":

-//

-// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));

-//

-// This instantiates tests from test case BazTest each with values 1, 2, 3.5.

-// The exact type of values will depend on the type of parameter in BazTest.

-//

-// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));

-//

-// Currently, Values() supports from 1 to 50 parameters.

-//

-template <typename T1>

-internal::ValueArray1<T1> Values(T1 v1) {

-  return internal::ValueArray1<T1>(v1);

-}

-

-template <typename T1, typename T2>

-internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {

-  return internal::ValueArray2<T1, T2>(v1, v2);

-}

-

-template <typename T1, typename T2, typename T3>

-internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) {

-  return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);

-}

-

-template <typename T1, typename T2, typename T3, typename T4>

-internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) {

-  return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5>

-internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,

-    T5 v5) {

-  return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6>

-internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,

-    T4 v4, T5 v5, T6 v6) {

-  return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7>

-internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,

-    T4 v4, T5 v5, T6 v6, T7 v7) {

-  return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,

-      v6, v7);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8>

-internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,

-    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) {

-  return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,

-      v5, v6, v7, v8);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9>

-internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,

-    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) {

-  return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,

-      v4, v5, v6, v7, v8, v9);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10>

-internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,

-    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) {

-  return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,

-      v2, v3, v4, v5, v6, v7, v8, v9, v10);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11>

-internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,

-    T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11) {

-  return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,

-      T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12>

-internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-    T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12) {

-  return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13>

-internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-    T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12, T13 v13) {

-  return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14>

-internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) {

-  return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,

-      v14);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15>

-internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,

-    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) {

-  return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,

-      v13, v14, v15);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16>

-internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,

-    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,

-    T16 v16) {

-  return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,

-      v12, v13, v14, v15, v16);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17>

-internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,

-    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,

-    T16 v16, T17 v17) {

-  return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,

-      v11, v12, v13, v14, v15, v16, v17);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18>

-internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,

-    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,

-    T16 v16, T17 v17, T18 v18) {

-  return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,

-      v10, v11, v12, v13, v14, v15, v16, v17, v18);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19>

-internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,

-    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,

-    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) {

-  return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,

-      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20>

-internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,

-    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,

-    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) {

-  return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,

-      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21>

-internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,

-    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,

-    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) {

-  return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,

-      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22>

-internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,

-    T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,

-    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,

-    T21 v21, T22 v22) {

-  return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,

-      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,

-      v20, v21, v22);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23>

-internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,

-    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,

-    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,

-    T21 v21, T22 v22, T23 v23) {

-  return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,

-      v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,

-      v20, v21, v22, v23);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24>

-internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,

-    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,

-    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,

-    T21 v21, T22 v22, T23 v23, T24 v24) {

-  return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,

-      v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,

-      v19, v20, v21, v22, v23, v24);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25>

-internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,

-    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,

-    T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,

-    T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) {

-  return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1,

-      v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,

-      v18, v19, v20, v21, v22, v23, v24, v25);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26>

-internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-    T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-    T26 v26) {

-  return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,

-      v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27>

-internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-    T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-    T26 v26, T27 v27) {

-  return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,

-      v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28>

-internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-    T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-    T26 v26, T27 v27, T28 v28) {

-  return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,

-      v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,

-      v28);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29>

-internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-    T26 v26, T27 v27, T28 v28, T29 v29) {

-  return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,

-      v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,

-      v27, v28, v29);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30>

-internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,

-    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,

-    T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,

-    T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) {

-  return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,

-      v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,

-      v26, v27, v28, v29, v30);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31>

-internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,

-    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,

-    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,

-    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) {

-  return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,

-      v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,

-      v25, v26, v27, v28, v29, v30, v31);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32>

-internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,

-    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,

-    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,

-    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,

-    T32 v32) {

-  return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9,

-      v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,

-      v24, v25, v26, v27, v28, v29, v30, v31, v32);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33>

-internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,

-    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,

-    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,

-    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,

-    T32 v32, T33 v33) {

-  return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8,

-      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,

-      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34>

-internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,

-    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,

-    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,

-    T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,

-    T31 v31, T32 v32, T33 v33, T34 v34) {

-  return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7,

-      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,

-      v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35>

-internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,

-    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,

-    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,

-    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,

-    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) {

-  return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6,

-      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,

-      v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36>

-internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,

-    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,

-    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,

-    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,

-    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) {

-  return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4,

-      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,

-      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,

-      v34, v35, v36);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37>

-internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,

-    T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,

-    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,

-    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,

-    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,

-    T37 v37) {

-  return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3,

-      v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,

-      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,

-      v34, v35, v36, v37);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38>

-internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,

-    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,

-    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,

-    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,

-    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,

-    T37 v37, T38 v38) {

-  return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2,

-      v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,

-      v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32,

-      v33, v34, v35, v36, v37, v38);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39>

-internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,

-    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,

-    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,

-    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,

-    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,

-    T37 v37, T38 v38, T39 v39) {

-  return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1,

-      v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,

-      v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,

-      v32, v33, v34, v35, v36, v37, v38, v39);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40>

-internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,

-    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,

-    T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,

-    T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,

-    T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,

-    T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) {

-  return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,

-      v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29,

-      v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41>

-internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-    T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) {

-  return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,

-      v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,

-      v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42>

-internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-    T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-    T42 v42) {

-  return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,

-      v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,

-      v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41,

-      v42);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43>

-internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,

-    T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-    T42 v42, T43 v43) {

-  return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,

-      v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,

-      v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,

-      v41, v42, v43);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44>

-internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-    T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-    T42 v42, T43 v43, T44 v44) {

-  return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,

-      v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,

-      v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39,

-      v40, v41, v42, v43, v44);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45>

-internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-    T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,

-    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,

-    T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,

-    T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,

-    T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,

-    T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) {

-  return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,

-      v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,

-      v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38,

-      v39, v40, v41, v42, v43, v44, v45);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46>

-internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-    T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,

-    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,

-    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,

-    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,

-    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,

-    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) {

-  return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9,

-      v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,

-      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,

-      v38, v39, v40, v41, v42, v43, v44, v45, v46);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47>

-internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-    T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,

-    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,

-    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,

-    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,

-    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,

-    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) {

-  return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8,

-      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,

-      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,

-      v38, v39, v40, v41, v42, v43, v44, v45, v46, v47);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48>

-internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-    T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,

-    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,

-    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,

-    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,

-    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,

-    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,

-    T48 v48) {

-  return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7,

-      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,

-      v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36,

-      v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48, typename T49>

-internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-    T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,

-    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,

-    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,

-    T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,

-    T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,

-    T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,

-    T47 v47, T48 v48, T49 v49) {

-  return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6,

-      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,

-      v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35,

-      v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49);

-}

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48, typename T49, typename T50>

-internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-    T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,

-    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,

-    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,

-    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,

-    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,

-    T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,

-    T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) {

-  return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4,

-      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,

-      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,

-      v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,

-      v48, v49, v50);

-}

-

-// Bool() allows generating tests with parameters in a set of (false, true).

-//

-// Synopsis:

-// Bool()

-//   - returns a generator producing sequences with elements {false, true}.

-//

-// It is useful when testing code that depends on Boolean flags. Combinations

-// of multiple flags can be tested when several Bool()'s are combined using

-// Combine() function.

-//

-// In the following example all tests in the test case FlagDependentTest

-// will be instantiated twice with parameters false and true.

-//

-// class FlagDependentTest : public testing::TestWithParam<bool> {

-//   virtual void SetUp() {

-//     external_flag = GetParam();

-//   }

-// }

-// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());

-//

-inline internal::ParamGenerator<bool> Bool() {

-  return Values(false, true);

-}

-

-#if GTEST_HAS_COMBINE

-// Combine() allows the user to combine two or more sequences to produce

-// values of a Cartesian product of those sequences' elements.

-//

-// Synopsis:

-// Combine(gen1, gen2, ..., genN)

-//   - returns a generator producing sequences with elements coming from

-//     the Cartesian product of elements from the sequences generated by

-//     gen1, gen2, ..., genN. The sequence elements will have a type of

-//     tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types

-//     of elements from sequences produces by gen1, gen2, ..., genN.

-//

-// Combine can have up to 10 arguments. This number is currently limited

-// by the maximum number of elements in the tuple implementation used by Google

-// Test.

-//

-// Example:

-//

-// This will instantiate tests in test case AnimalTest each one with

-// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),

-// tuple("dog", BLACK), and tuple("dog", WHITE):

-//

-// enum Color { BLACK, GRAY, WHITE };

-// class AnimalTest

-//     : public testing::TestWithParam<tuple<const char*, Color> > {...};

-//

-// TEST_P(AnimalTest, AnimalLooksNice) {...}

-//

-// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,

-//                         Combine(Values("cat", "dog"),

-//                                 Values(BLACK, WHITE)));

-//

-// This will instantiate tests in FlagDependentTest with all variations of two

-// Boolean flags:

-//

-// class FlagDependentTest

-//     : public testing::TestWithParam<tuple(bool, bool)> > {

-//   virtual void SetUp() {

-//     // Assigns external_flag_1 and external_flag_2 values from the tuple.

-//     tie(external_flag_1, external_flag_2) = GetParam();

-//   }

-// };

-//

-// TEST_P(FlagDependentTest, TestFeature1) {

-//   // Test your code using external_flag_1 and external_flag_2 here.

-// }

-// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,

-//                         Combine(Bool(), Bool()));

-//

-template <typename Generator1, typename Generator2>

-internal::CartesianProductHolder2<Generator1, Generator2> Combine(

-    const Generator1& g1, const Generator2& g2) {

-  return internal::CartesianProductHolder2<Generator1, Generator2>(

-      g1, g2);

-}

-

-template <typename Generator1, typename Generator2, typename Generator3>

-internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(

-    const Generator1& g1, const Generator2& g2, const Generator3& g3) {

-  return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(

-      g1, g2, g3);

-}

-

-template <typename Generator1, typename Generator2, typename Generator3,

-    typename Generator4>

-internal::CartesianProductHolder4<Generator1, Generator2, Generator3,

-    Generator4> Combine(

-    const Generator1& g1, const Generator2& g2, const Generator3& g3,

-        const Generator4& g4) {

-  return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,

-      Generator4>(

-      g1, g2, g3, g4);

-}

-

-template <typename Generator1, typename Generator2, typename Generator3,

-    typename Generator4, typename Generator5>

-internal::CartesianProductHolder5<Generator1, Generator2, Generator3,

-    Generator4, Generator5> Combine(

-    const Generator1& g1, const Generator2& g2, const Generator3& g3,

-        const Generator4& g4, const Generator5& g5) {

-  return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,

-      Generator4, Generator5>(

-      g1, g2, g3, g4, g5);

-}

-

-template <typename Generator1, typename Generator2, typename Generator3,

-    typename Generator4, typename Generator5, typename Generator6>

-internal::CartesianProductHolder6<Generator1, Generator2, Generator3,

-    Generator4, Generator5, Generator6> Combine(

-    const Generator1& g1, const Generator2& g2, const Generator3& g3,

-        const Generator4& g4, const Generator5& g5, const Generator6& g6) {

-  return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,

-      Generator4, Generator5, Generator6>(

-      g1, g2, g3, g4, g5, g6);

-}

-

-template <typename Generator1, typename Generator2, typename Generator3,

-    typename Generator4, typename Generator5, typename Generator6,

-    typename Generator7>

-internal::CartesianProductHolder7<Generator1, Generator2, Generator3,

-    Generator4, Generator5, Generator6, Generator7> Combine(

-    const Generator1& g1, const Generator2& g2, const Generator3& g3,

-        const Generator4& g4, const Generator5& g5, const Generator6& g6,

-        const Generator7& g7) {

-  return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,

-      Generator4, Generator5, Generator6, Generator7>(

-      g1, g2, g3, g4, g5, g6, g7);

-}

-

-template <typename Generator1, typename Generator2, typename Generator3,

-    typename Generator4, typename Generator5, typename Generator6,

-    typename Generator7, typename Generator8>

-internal::CartesianProductHolder8<Generator1, Generator2, Generator3,

-    Generator4, Generator5, Generator6, Generator7, Generator8> Combine(

-    const Generator1& g1, const Generator2& g2, const Generator3& g3,

-        const Generator4& g4, const Generator5& g5, const Generator6& g6,

-        const Generator7& g7, const Generator8& g8) {

-  return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,

-      Generator4, Generator5, Generator6, Generator7, Generator8>(

-      g1, g2, g3, g4, g5, g6, g7, g8);

-}

-

-template <typename Generator1, typename Generator2, typename Generator3,

-    typename Generator4, typename Generator5, typename Generator6,

-    typename Generator7, typename Generator8, typename Generator9>

-internal::CartesianProductHolder9<Generator1, Generator2, Generator3,

-    Generator4, Generator5, Generator6, Generator7, Generator8,

-    Generator9> Combine(

-    const Generator1& g1, const Generator2& g2, const Generator3& g3,

-        const Generator4& g4, const Generator5& g5, const Generator6& g6,

-        const Generator7& g7, const Generator8& g8, const Generator9& g9) {

-  return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,

-      Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(

-      g1, g2, g3, g4, g5, g6, g7, g8, g9);

-}

-

-template <typename Generator1, typename Generator2, typename Generator3,

-    typename Generator4, typename Generator5, typename Generator6,

-    typename Generator7, typename Generator8, typename Generator9,

-    typename Generator10>

-internal::CartesianProductHolder10<Generator1, Generator2, Generator3,

-    Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,

-    Generator10> Combine(

-    const Generator1& g1, const Generator2& g2, const Generator3& g3,

-        const Generator4& g4, const Generator5& g5, const Generator6& g6,

-        const Generator7& g7, const Generator8& g8, const Generator9& g9,

-        const Generator10& g10) {

-  return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,

-      Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,

-      Generator10>(

-      g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);

-}

-#endif  // GTEST_HAS_COMBINE

-

-

-

-#define TEST_P(test_case_name, test_name) \

-  class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \

-      : public test_case_name { \

-   public: \

-    GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \

-    virtual void TestBody(); \

-   private: \

-    static int AddToRegistry() { \

-      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \

-          GetTestCasePatternHolder<test_case_name>(\

-              #test_case_name, __FILE__, __LINE__)->AddTestPattern(\

-                  #test_case_name, \

-                  #test_name, \

-                  new ::testing::internal::TestMetaFactory< \

-                      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \

-      return 0; \

-    } \

-    static int gtest_registering_dummy_; \

-    GTEST_DISALLOW_COPY_AND_ASSIGN_(\

-        GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \

-  }; \

-  int GTEST_TEST_CLASS_NAME_(test_case_name, \

-                             test_name)::gtest_registering_dummy_ = \

-      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \

-  void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()

-

-#define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \

-  ::testing::internal::ParamGenerator<test_case_name::ParamType> \

-      gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \

-  int gtest_##prefix##test_case_name##_dummy_ = \

-      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \

-          GetTestCasePatternHolder<test_case_name>(\

-              #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\

-                  #prefix, \

-                  &gtest_##prefix##test_case_name##_EvalGenerator_, \

-                  __FILE__, __LINE__)

-

-}  // namespace testing

-

-#endif  // GTEST_HAS_PARAM_TEST

-

-#endif  // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_

+// This file was GENERATED by a script.  DO NOT EDIT BY HAND!!!
+
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl@google.com (Vlad Losev)
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing Framework (Google Test)
+//
+// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It must be derived from testing::TestWithParam<T>, where T is
+// the type of your parameter values. TestWithParam<T> is itself derived
+// from testing::Test. T can be any copyable type. If it's a raw pointer,
+// you are responsible for managing the lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*> {
+  // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah) {
+  // Inside a test, access the test parameter with the GetParam() method
+  // of the TestWithParam<T> class:
+  EXPECT_TRUE(foo.Blah(GetParam()));
+  ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+  ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a  summary of them, which
+// are all in the testing namespace:
+//
+//
+//  Range(begin, end [, step]) - Yields values {begin, begin+step,
+//                               begin+step+step, ...}. The values do not
+//                               include end. step defaults to 1.
+//  Values(v1, v2, ..., vN)    - Yields values {v1, v2, ..., vN}.
+//  ValuesIn(container)        - Yields values from a C-style array, an STL
+//  ValuesIn(begin,end)          container, or an iterator range [begin, end).
+//  Bool()                     - Yields sequence {false, true}.
+//  Combine(g1, g2, ..., gN)   - Yields all combinations (the Cartesian product
+//                               for the math savvy) of the values generated
+//                               by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test case
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_CASE_P(InstantiationName,
+                        FooTest,
+                        Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more then once) the first argument to the
+// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
+// actual test case name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+//    * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+//    * InstantiationName/FooTest.DoesBlah/1 for "miny"
+//    * InstantiationName/FooTest.DoesBlah/2 for "moe"
+//    * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+//    * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+//    * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+//    * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+//    * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+//    * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+//    * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
+// in the given test case, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_CASE_P statement.
+//
+// Please also note that generator expressions are evaluated in
+// RUN_ALL_TESTS(), after main() has started. This allows evaluation of
+// parameter list based on command line parameters.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+
+#endif  // 0
+
+
+#include <utility>
+
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-param-util.h>
+#include <gtest/internal/gtest-param-util-generated.h>
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test case is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test case FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+//   - returns a generator producing a sequence of values {start, start+1,
+//     start+2, ..., }.
+// Range(start, end, step)
+//   - returns a generator producing a sequence of values {start, start+step,
+//     start+step+step, ..., }.
+// Notes:
+//   * The generated sequences never include end. For example, Range(1, 5)
+//     returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+//     returns a generator producing {1, 3, 5, 7}.
+//   * start and end must have the same type. That type may be any integral or
+//     floating-point type or a user defined type satisfying these conditions:
+//     * It must be assignable (have operator=() defined).
+//     * It must have operator+() (operator+(int-compatible type) for
+//       two-operand version).
+//     * It must have operator<() defined.
+//     Elements in the resulting sequences will also have that type.
+//   * Condition start < end must be satisfied in order for resulting sequences
+//     to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+  return internal::ParamGenerator<T>(
+      new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end) {
+  return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+//   - returns a generator producing sequences with elements from
+//     a C-style array.
+// ValuesIn(const Container& container)
+//   - returns a generator producing sequences with elements from
+//     an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+//   - returns a generator producing sequences with elements from
+//     a range [begin, end) defined by a pair of STL-style iterators. These
+//     iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test case StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+//
+// This instantiates tests from test case StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+//   ::std::vector< ::std::string> v;
+//   v.push_back("a");
+//   v.push_back("b");
+//   return v;
+// }
+//
+// INSTANTIATE_TEST_CASE_P(CharSequence,
+//                         StlStringTest,
+//                         ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+//   ::std::list<char> list;
+//   list.push_back('a');
+//   list.push_back('b');
+//   return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_CASE_P(CharSequence2,
+//                         CharTest,
+//                         ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+    typename ::std::iterator_traits<ForwardIterator>::value_type> ValuesIn(
+  ForwardIterator begin,
+  ForwardIterator end) {
+  typedef typename ::std::iterator_traits<ForwardIterator>::value_type
+      ParamType;
+  return internal::ParamGenerator<ParamType>(
+      new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+  return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+    const Container& container) {
+  return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+//   - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test case BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+//
+// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+// Currently, Values() supports from 1 to 50 parameters.
+//
+template <typename T1>
+internal::ValueArray1<T1> Values(T1 v1) {
+  return internal::ValueArray1<T1>(v1);
+}
+
+template <typename T1, typename T2>
+internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {
+  return internal::ValueArray2<T1, T2>(v1, v2);
+}
+
+template <typename T1, typename T2, typename T3>
+internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) {
+  return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) {
+  return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5) {
+  return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6) {
+  return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6, T7 v7) {
+  return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,
+      v6, v7);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) {
+  return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,
+      v5, v6, v7, v8);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) {
+  return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,
+      v4, v5, v6, v7, v8, v9);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,
+    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) {
+  return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,
+      v2, v3, v4, v5, v6, v7, v8, v9, v10);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+    T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11) {
+  return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+      T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+    T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12) {
+  return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+    T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13) {
+  return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) {
+  return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+      v14);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) {
+  return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+      v13, v14, v15);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16) {
+  return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+      v12, v13, v14, v15, v16);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17) {
+  return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+      v11, v12, v13, v14, v15, v16, v17);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18) {
+  return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+      v10, v11, v12, v13, v14, v15, v16, v17, v18);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) {
+  return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,
+      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) {
+  return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) {
+  return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,
+      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22) {
+  return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,
+      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23) {
+  return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,
+      v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24) {
+  return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,
+      v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+      v19, v20, v21, v22, v23, v24);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,
+    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+    T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+    T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) {
+  return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1,
+      v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+      v18, v19, v20, v21, v22, v23, v24, v25);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+    T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26) {
+  return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+      v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+    T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27) {
+  return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+      v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+    T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28) {
+  return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+      v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+      v28);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29) {
+  return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+      v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+      v27, v28, v29);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+    T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+    T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) {
+  return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+      v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+      v26, v27, v28, v29, v30);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) {
+  return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+      v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+      v25, v26, v27, v28, v29, v30, v31);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32) {
+  return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+      v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33) {
+  return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8,
+      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+    T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+    T31 v31, T32 v32, T33 v33, T34 v34) {
+  return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+      v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) {
+  return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6,
+      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+      v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) {
+  return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4,
+      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+      v34, v35, v36);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,
+    T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+    T37 v37) {
+  return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3,
+      v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+      v34, v35, v36, v37);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+    T37 v37, T38 v38) {
+  return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2,
+      v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+      v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32,
+      v33, v34, v35, v36, v37, v38);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,
+    T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+    T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+    T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+    T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+    T37 v37, T38 v38, T39 v39) {
+  return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1,
+      v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+      v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+      v32, v33, v34, v35, v36, v37, v38, v39);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,
+    T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+    T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+    T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,
+    T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,
+    T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) {
+  return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+      v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29,
+      v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+    T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) {
+  return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+      v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,
+      v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+    T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+    T42 v42) {
+  return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+      v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+      v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41,
+      v42);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+    T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+    T42 v42, T43 v43) {
+  return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+      v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+      v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
+      v41, v42, v43);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+    T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+    T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+    T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+    T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+    T42 v42, T43 v43, T44 v44) {
+  return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+      v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+      v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39,
+      v40, v41, v42, v43, v44);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+    T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+    T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+    T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+    T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+    T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) {
+  return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+      v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+      v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38,
+      v39, v40, v41, v42, v43, v44, v45);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) {
+  return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+      v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+      v38, v39, v40, v41, v42, v43, v44, v45, v46);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+    T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) {
+  return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8,
+      v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+      v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+      v38, v39, v40, v41, v42, v43, v44, v45, v46, v47);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+    T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+    T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+    T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+    T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+    T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,
+    T48 v48) {
+  return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7,
+      v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+      v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36,
+      v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+    T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+    T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+    T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+    T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,
+    T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,
+    T47 v47, T48 v48, T49 v49) {
+  return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6,
+      v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+      v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35,
+      v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+    T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+    T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+    T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+    T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,
+    T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,
+    T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) {
+  return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4,
+      v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+      v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+      v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
+      v48, v49, v50);
+}
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+//   - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test case FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+//   virtual void SetUp() {
+//     external_flag = GetParam();
+//   }
+// }
+// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() {
+  return Values(false, true);
+}
+
+#if GTEST_HAS_COMBINE
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+//   - returns a generator producing sequences with elements coming from
+//     the Cartesian product of elements from the sequences generated by
+//     gen1, gen2, ..., genN. The sequence elements will have a type of
+//     tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+//     of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Combine can have up to 10 arguments. This number is currently limited
+// by the maximum number of elements in the tuple implementation used by Google
+// Test.
+//
+// Example:
+//
+// This will instantiate tests in test case AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+//     : public testing::TestWithParam<tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
+//                         Combine(Values("cat", "dog"),
+//                                 Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+//     : public testing::TestWithParam<tuple(bool, bool)> > {
+//   virtual void SetUp() {
+//     // Assigns external_flag_1 and external_flag_2 values from the tuple.
+//     tie(external_flag_1, external_flag_2) = GetParam();
+//   }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+//   // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
+//                         Combine(Bool(), Bool()));
+//
+template <typename Generator1, typename Generator2>
+internal::CartesianProductHolder2<Generator1, Generator2> Combine(
+    const Generator1& g1, const Generator2& g2) {
+  return internal::CartesianProductHolder2<Generator1, Generator2>(
+      g1, g2);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3>
+internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3) {
+  return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(
+      g1, g2, g3);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4>
+internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+    Generator4> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4) {
+  return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+      Generator4>(
+      g1, g2, g3, g4);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5>
+internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+    Generator4, Generator5> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5) {
+  return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+      Generator4, Generator5>(
+      g1, g2, g3, g4, g5);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6>
+internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6) {
+  return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6>(
+      g1, g2, g3, g4, g5, g6);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7>
+internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7) {
+  return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7>(
+      g1, g2, g3, g4, g5, g6, g7);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7, typename Generator8>
+internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7, Generator8> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7, const Generator8& g8) {
+  return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7, Generator8>(
+      g1, g2, g3, g4, g5, g6, g7, g8);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7, typename Generator8, typename Generator9>
+internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7, Generator8,
+    Generator9> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7, const Generator8& g8, const Generator9& g9) {
+  return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(
+      g1, g2, g3, g4, g5, g6, g7, g8, g9);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+    typename Generator4, typename Generator5, typename Generator6,
+    typename Generator7, typename Generator8, typename Generator9,
+    typename Generator10>
+internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+    Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+    Generator10> Combine(
+    const Generator1& g1, const Generator2& g2, const Generator3& g3,
+        const Generator4& g4, const Generator5& g5, const Generator6& g6,
+        const Generator7& g7, const Generator8& g8, const Generator9& g9,
+        const Generator10& g10) {
+  return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+      Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+      Generator10>(
+      g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);
+}
+#endif  // GTEST_HAS_COMBINE
+
+
+
+#define TEST_P(test_case_name, test_name) \
+  class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+      : public test_case_name { \
+   public: \
+    GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
+    virtual void TestBody(); \
+   private: \
+    static int AddToRegistry() { \
+      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+          GetTestCasePatternHolder<test_case_name>(\
+              #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
+                  #test_case_name, \
+                  #test_name, \
+                  new ::testing::internal::TestMetaFactory< \
+                      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+      return 0; \
+    } \
+    static int gtest_registering_dummy_; \
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+        GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
+  }; \
+  int GTEST_TEST_CLASS_NAME_(test_case_name, \
+                             test_name)::gtest_registering_dummy_ = \
+      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
+  void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+  ::testing::internal::ParamGenerator<test_case_name::ParamType> \
+      gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
+  int gtest_##prefix##test_case_name##_dummy_ = \
+      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+          GetTestCasePatternHolder<test_case_name>(\
+              #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
+                  #prefix, \
+                  &gtest_##prefix##test_case_name##_EvalGenerator_, \
+                  __FILE__, __LINE__)
+
+}  // namespace testing
+
+#endif  // GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
diff --git a/third_party/gtest/include/gtest/gtest-spi.h b/third_party/gtest/include/gtest/gtest-spi.h
index dc33206..a4e387a 100644
--- a/third_party/gtest/include/gtest/gtest-spi.h
+++ b/third_party/gtest/include/gtest/gtest-spi.h
@@ -1,221 +1,221 @@
-// Copyright 2007, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan)

-//

-// Utilities for testing Google Test itself and code that uses Google Test

-// (e.g. frameworks built on top of Google Test).

-

-#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_

-#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_

-

-#include <gtest/gtest.h>

-

-namespace testing {

-

-// This helper class can be used to mock out Google Test failure reporting

-// so that we can test Google Test or code that builds on Google Test.

-//

-// An object of this class appends a TestPartResult object to the

-// TestPartResultArray object given in the constructor whenever a Google Test

-// failure is reported. It can either intercept only failures that are

-// generated in the same thread that created this object or it can intercept

-// all generated failures. The scope of this mock object can be controlled with

-// the second argument to the two arguments constructor.

-class ScopedFakeTestPartResultReporter

-    : public TestPartResultReporterInterface {

- public:

-  // The two possible mocking modes of this object.

-  enum InterceptMode {

-    INTERCEPT_ONLY_CURRENT_THREAD,  // Intercepts only thread local failures.

-    INTERCEPT_ALL_THREADS           // Intercepts all failures.

-  };

-

-  // The c'tor sets this object as the test part result reporter used

-  // by Google Test.  The 'result' parameter specifies where to report the

-  // results. This reporter will only catch failures generated in the current

-  // thread. DEPRECATED

-  explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);

-

-  // Same as above, but you can choose the interception scope of this object.

-  ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,

-                                   TestPartResultArray* result);

-

-  // The d'tor restores the previous test part result reporter.

-  virtual ~ScopedFakeTestPartResultReporter();

-

-  // Appends the TestPartResult object to the TestPartResultArray

-  // received in the constructor.

-  //

-  // This method is from the TestPartResultReporterInterface

-  // interface.

-  virtual void ReportTestPartResult(const TestPartResult& result);

- private:

-  void Init();

-

-  const InterceptMode intercept_mode_;

-  TestPartResultReporterInterface* old_reporter_;

-  TestPartResultArray* const result_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);

-};

-

-namespace internal {

-

-// A helper class for implementing EXPECT_FATAL_FAILURE() and

-// EXPECT_NONFATAL_FAILURE().  Its destructor verifies that the given

-// TestPartResultArray contains exactly one failure that has the given

-// type and contains the given substring.  If that's not the case, a

-// non-fatal failure will be generated.

-class SingleFailureChecker {

- public:

-  // The constructor remembers the arguments.

-  SingleFailureChecker(const TestPartResultArray* results,

-                       TestPartResultType type,

-                       const char* substr);

-  ~SingleFailureChecker();

- private:

-  const TestPartResultArray* const results_;

-  const TestPartResultType type_;

-  const String substr_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);

-};

-

-}  // namespace internal

-

-}  // namespace testing

-

-// A set of macros for testing Google Test assertions or code that's expected

-// to generate Google Test fatal failures.  It verifies that the given

-// statement will cause exactly one fatal Google Test failure with 'substr'

-// being part of the failure message.

-//

-// There are two different versions of this macro. EXPECT_FATAL_FAILURE only

-// affects and considers failures generated in the current thread and

-// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.

-//

-// The verification of the assertion is done correctly even when the statement

-// throws an exception or aborts the current function.

-//

-// Known restrictions:

-//   - 'statement' cannot reference local non-static variables or

-//     non-static members of the current object.

-//   - 'statement' cannot return a value.

-//   - You cannot stream a failure message to this macro.

-//

-// Note that even though the implementations of the following two

-// macros are much alike, we cannot refactor them to use a common

-// helper macro, due to some peculiarity in how the preprocessor

-// works.  The AcceptsMacroThatExpandsToUnprotectedComma test in

-// gtest_unittest.cc will fail to compile if we do that.

-#define EXPECT_FATAL_FAILURE(statement, substr) \

-  do { \

-    class GTestExpectFatalFailureHelper {\

-     public:\

-      static void Execute() { statement; }\

-    };\

-    ::testing::TestPartResultArray gtest_failures;\

-    ::testing::internal::SingleFailureChecker gtest_checker(\

-        &gtest_failures, ::testing::TPRT_FATAL_FAILURE, (substr));\

-    {\

-      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\

-          ::testing::ScopedFakeTestPartResultReporter:: \

-          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\

-      GTestExpectFatalFailureHelper::Execute();\

-    }\

-  } while (false)

-

-#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \

-  do { \

-    class GTestExpectFatalFailureHelper {\

-     public:\

-      static void Execute() { statement; }\

-    };\

-    ::testing::TestPartResultArray gtest_failures;\

-    ::testing::internal::SingleFailureChecker gtest_checker(\

-        &gtest_failures, ::testing::TPRT_FATAL_FAILURE, (substr));\

-    {\

-      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\

-          ::testing::ScopedFakeTestPartResultReporter:: \

-          INTERCEPT_ALL_THREADS, &gtest_failures);\

-      GTestExpectFatalFailureHelper::Execute();\

-    }\

-  } while (false)

-

-// A macro for testing Google Test assertions or code that's expected to

-// generate Google Test non-fatal failures.  It asserts that the given

-// statement will cause exactly one non-fatal Google Test failure with 'substr'

-// being part of the failure message.

-//

-// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only

-// affects and considers failures generated in the current thread and

-// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.

-//

-// 'statement' is allowed to reference local variables and members of

-// the current object.

-//

-// The verification of the assertion is done correctly even when the statement

-// throws an exception or aborts the current function.

-//

-// Known restrictions:

-//   - You cannot stream a failure message to this macro.

-//

-// Note that even though the implementations of the following two

-// macros are much alike, we cannot refactor them to use a common

-// helper macro, due to some peculiarity in how the preprocessor

-// works.  The AcceptsMacroThatExpandsToUnprotectedComma test in

-// gtest_unittest.cc will fail to compile if we do that.

-#define EXPECT_NONFATAL_FAILURE(statement, substr) \

-  do {\

-    ::testing::TestPartResultArray gtest_failures;\

-    ::testing::internal::SingleFailureChecker gtest_checker(\

-        &gtest_failures, ::testing::TPRT_NONFATAL_FAILURE, (substr));\

-    {\

-      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\

-          ::testing::ScopedFakeTestPartResultReporter:: \

-          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\

-      statement;\

-    }\

-  } while (false)

-

-#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \

-  do {\

-    ::testing::TestPartResultArray gtest_failures;\

-    ::testing::internal::SingleFailureChecker gtest_checker(\

-        &gtest_failures, ::testing::TPRT_NONFATAL_FAILURE, (substr));\

-    {\

-      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\

-          ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\

-          &gtest_failures);\

-      statement;\

-    }\

-  } while (false)

-

-#endif  // GTEST_INCLUDE_GTEST_GTEST_SPI_H_

+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Utilities for testing Google Test itself and code that uses Google Test
+// (e.g. frameworks built on top of Google Test).
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+#include <gtest/gtest.h>
+
+namespace testing {
+
+// This helper class can be used to mock out Google Test failure reporting
+// so that we can test Google Test or code that builds on Google Test.
+//
+// An object of this class appends a TestPartResult object to the
+// TestPartResultArray object given in the constructor whenever a Google Test
+// failure is reported. It can either intercept only failures that are
+// generated in the same thread that created this object or it can intercept
+// all generated failures. The scope of this mock object can be controlled with
+// the second argument to the two arguments constructor.
+class ScopedFakeTestPartResultReporter
+    : public TestPartResultReporterInterface {
+ public:
+  // The two possible mocking modes of this object.
+  enum InterceptMode {
+    INTERCEPT_ONLY_CURRENT_THREAD,  // Intercepts only thread local failures.
+    INTERCEPT_ALL_THREADS           // Intercepts all failures.
+  };
+
+  // The c'tor sets this object as the test part result reporter used
+  // by Google Test.  The 'result' parameter specifies where to report the
+  // results. This reporter will only catch failures generated in the current
+  // thread. DEPRECATED
+  explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
+
+  // Same as above, but you can choose the interception scope of this object.
+  ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
+                                   TestPartResultArray* result);
+
+  // The d'tor restores the previous test part result reporter.
+  virtual ~ScopedFakeTestPartResultReporter();
+
+  // Appends the TestPartResult object to the TestPartResultArray
+  // received in the constructor.
+  //
+  // This method is from the TestPartResultReporterInterface
+  // interface.
+  virtual void ReportTestPartResult(const TestPartResult& result);
+ private:
+  void Init();
+
+  const InterceptMode intercept_mode_;
+  TestPartResultReporterInterface* old_reporter_;
+  TestPartResultArray* const result_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
+};
+
+namespace internal {
+
+// A helper class for implementing EXPECT_FATAL_FAILURE() and
+// EXPECT_NONFATAL_FAILURE().  Its destructor verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring.  If that's not the case, a
+// non-fatal failure will be generated.
+class SingleFailureChecker {
+ public:
+  // The constructor remembers the arguments.
+  SingleFailureChecker(const TestPartResultArray* results,
+                       TestPartResultType type,
+                       const char* substr);
+  ~SingleFailureChecker();
+ private:
+  const TestPartResultArray* const results_;
+  const TestPartResultType type_;
+  const String substr_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
+};
+
+}  // namespace internal
+
+}  // namespace testing
+
+// A set of macros for testing Google Test assertions or code that's expected
+// to generate Google Test fatal failures.  It verifies that the given
+// statement will cause exactly one fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+//   - 'statement' cannot reference local non-static variables or
+//     non-static members of the current object.
+//   - 'statement' cannot return a value.
+//   - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works.  The AcceptsMacroThatExpandsToUnprotectedComma test in
+// gtest_unittest.cc will fail to compile if we do that.
+#define EXPECT_FATAL_FAILURE(statement, substr) \
+  do { \
+    class GTestExpectFatalFailureHelper {\
+     public:\
+      static void Execute() { statement; }\
+    };\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TPRT_FATAL_FAILURE, (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter:: \
+          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+      GTestExpectFatalFailureHelper::Execute();\
+    }\
+  } while (false)
+
+#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+  do { \
+    class GTestExpectFatalFailureHelper {\
+     public:\
+      static void Execute() { statement; }\
+    };\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TPRT_FATAL_FAILURE, (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter:: \
+          INTERCEPT_ALL_THREADS, &gtest_failures);\
+      GTestExpectFatalFailureHelper::Execute();\
+    }\
+  } while (false)
+
+// A macro for testing Google Test assertions or code that's expected to
+// generate Google Test non-fatal failures.  It asserts that the given
+// statement will cause exactly one non-fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// 'statement' is allowed to reference local variables and members of
+// the current object.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+//   - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works.  The AcceptsMacroThatExpandsToUnprotectedComma test in
+// gtest_unittest.cc will fail to compile if we do that.
+#define EXPECT_NONFATAL_FAILURE(statement, substr) \
+  do {\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TPRT_NONFATAL_FAILURE, (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter:: \
+          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+      statement;\
+    }\
+  } while (false)
+
+#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+  do {\
+    ::testing::TestPartResultArray gtest_failures;\
+    ::testing::internal::SingleFailureChecker gtest_checker(\
+        &gtest_failures, ::testing::TPRT_NONFATAL_FAILURE, (substr));\
+    {\
+      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+          ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\
+          &gtest_failures);\
+      statement;\
+    }\
+  } while (false)
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
diff --git a/third_party/gtest/include/gtest/gtest-test-part.h b/third_party/gtest/include/gtest/gtest-test-part.h
index 897a3d6..1a281af 100644
--- a/third_party/gtest/include/gtest/gtest-test-part.h
+++ b/third_party/gtest/include/gtest/gtest-test-part.h
@@ -1,179 +1,179 @@
-// Copyright 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: mheule@google.com (Markus Heule)

-//

-

-#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_

-#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_

-

-#include <iosfwd>

-#include <gtest/internal/gtest-internal.h>

-#include <gtest/internal/gtest-string.h>

-

-namespace testing {

-

-// The possible outcomes of a test part (i.e. an assertion or an

-// explicit SUCCEED(), FAIL(), or ADD_FAILURE()).

-enum TestPartResultType {

-  TPRT_SUCCESS,           // Succeeded.

-  TPRT_NONFATAL_FAILURE,  // Failed but the test can continue.

-  TPRT_FATAL_FAILURE      // Failed and the test should be terminated.

-};

-

-// A copyable object representing the result of a test part (i.e. an

-// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).

-//

-// Don't inherit from TestPartResult as its destructor is not virtual.

-class TestPartResult {

- public:

-  // C'tor.  TestPartResult does NOT have a default constructor.

-  // Always use this constructor (with parameters) to create a

-  // TestPartResult object.

-  TestPartResult(TestPartResultType type,

-                 const char* file_name,

-                 int line_number,

-                 const char* message)

-      : type_(type),

-        file_name_(file_name),

-        line_number_(line_number),

-        summary_(ExtractSummary(message)),

-        message_(message) {

-  }

-

-  // Gets the outcome of the test part.

-  TestPartResultType type() const { return type_; }

-

-  // Gets the name of the source file where the test part took place, or

-  // NULL if it's unknown.

-  const char* file_name() const { return file_name_.c_str(); }

-

-  // Gets the line in the source file where the test part took place,

-  // or -1 if it's unknown.

-  int line_number() const { return line_number_; }

-

-  // Gets the summary of the failure message.

-  const char* summary() const { return summary_.c_str(); }

-

-  // Gets the message associated with the test part.

-  const char* message() const { return message_.c_str(); }

-

-  // Returns true iff the test part passed.

-  bool passed() const { return type_ == TPRT_SUCCESS; }

-

-  // Returns true iff the test part failed.

-  bool failed() const { return type_ != TPRT_SUCCESS; }

-

-  // Returns true iff the test part non-fatally failed.

-  bool nonfatally_failed() const { return type_ == TPRT_NONFATAL_FAILURE; }

-

-  // Returns true iff the test part fatally failed.

-  bool fatally_failed() const { return type_ == TPRT_FATAL_FAILURE; }

- private:

-  TestPartResultType type_;

-

-  // Gets the summary of the failure message by omitting the stack

-  // trace in it.

-  static internal::String ExtractSummary(const char* message);

-

-  // The name of the source file where the test part took place, or

-  // NULL if the source file is unknown.

-  internal::String file_name_;

-  // The line in the source file where the test part took place, or -1

-  // if the line number is unknown.

-  int line_number_;

-  internal::String summary_;  // The test failure summary.

-  internal::String message_;  // The test failure message.

-};

-

-// Prints a TestPartResult object.

-std::ostream& operator<<(std::ostream& os, const TestPartResult& result);

-

-// An array of TestPartResult objects.

-//

-// We define this class as we cannot use STL containers when compiling

-// Google Test with MSVC 7.1 and exceptions disabled.

-//

-// Don't inherit from TestPartResultArray as its destructor is not

-// virtual.

-class TestPartResultArray {

- public:

-  TestPartResultArray();

-  ~TestPartResultArray();

-

-  // Appends the given TestPartResult to the array.

-  void Append(const TestPartResult& result);

-

-  // Returns the TestPartResult at the given index (0-based).

-  const TestPartResult& GetTestPartResult(int index) const;

-

-  // Returns the number of TestPartResult objects in the array.

-  int size() const;

- private:

-  // Internally we use a list to simulate the array.  Yes, this means

-  // that random access is O(N) in time, but it's OK for its purpose.

-  internal::List<TestPartResult>* const list_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);

-};

-

-// This interface knows how to report a test part result.

-class TestPartResultReporterInterface {

- public:

-  virtual ~TestPartResultReporterInterface() {}

-

-  virtual void ReportTestPartResult(const TestPartResult& result) = 0;

-};

-

-namespace internal {

-

-// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a

-// statement generates new fatal failures. To do so it registers itself as the

-// current test part result reporter. Besides checking if fatal failures were

-// reported, it only delegates the reporting to the former result reporter.

-// The original result reporter is restored in the destructor.

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-class HasNewFatalFailureHelper : public TestPartResultReporterInterface {

- public:

-  HasNewFatalFailureHelper();

-  virtual ~HasNewFatalFailureHelper();

-  virtual void ReportTestPartResult(const TestPartResult& result);

-  bool has_new_fatal_failure() const { return has_new_fatal_failure_; }

- private:

-  bool has_new_fatal_failure_;

-  TestPartResultReporterInterface* original_reporter_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);

-};

-

-}  // namespace internal

-

-}  // namespace testing

-

-#endif  // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_

+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+#include <iosfwd>
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+
+// The possible outcomes of a test part (i.e. an assertion or an
+// explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
+enum TestPartResultType {
+  TPRT_SUCCESS,           // Succeeded.
+  TPRT_NONFATAL_FAILURE,  // Failed but the test can continue.
+  TPRT_FATAL_FAILURE      // Failed and the test should be terminated.
+};
+
+// A copyable object representing the result of a test part (i.e. an
+// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
+//
+// Don't inherit from TestPartResult as its destructor is not virtual.
+class TestPartResult {
+ public:
+  // C'tor.  TestPartResult does NOT have a default constructor.
+  // Always use this constructor (with parameters) to create a
+  // TestPartResult object.
+  TestPartResult(TestPartResultType type,
+                 const char* file_name,
+                 int line_number,
+                 const char* message)
+      : type_(type),
+        file_name_(file_name),
+        line_number_(line_number),
+        summary_(ExtractSummary(message)),
+        message_(message) {
+  }
+
+  // Gets the outcome of the test part.
+  TestPartResultType type() const { return type_; }
+
+  // Gets the name of the source file where the test part took place, or
+  // NULL if it's unknown.
+  const char* file_name() const { return file_name_.c_str(); }
+
+  // Gets the line in the source file where the test part took place,
+  // or -1 if it's unknown.
+  int line_number() const { return line_number_; }
+
+  // Gets the summary of the failure message.
+  const char* summary() const { return summary_.c_str(); }
+
+  // Gets the message associated with the test part.
+  const char* message() const { return message_.c_str(); }
+
+  // Returns true iff the test part passed.
+  bool passed() const { return type_ == TPRT_SUCCESS; }
+
+  // Returns true iff the test part failed.
+  bool failed() const { return type_ != TPRT_SUCCESS; }
+
+  // Returns true iff the test part non-fatally failed.
+  bool nonfatally_failed() const { return type_ == TPRT_NONFATAL_FAILURE; }
+
+  // Returns true iff the test part fatally failed.
+  bool fatally_failed() const { return type_ == TPRT_FATAL_FAILURE; }
+ private:
+  TestPartResultType type_;
+
+  // Gets the summary of the failure message by omitting the stack
+  // trace in it.
+  static internal::String ExtractSummary(const char* message);
+
+  // The name of the source file where the test part took place, or
+  // NULL if the source file is unknown.
+  internal::String file_name_;
+  // The line in the source file where the test part took place, or -1
+  // if the line number is unknown.
+  int line_number_;
+  internal::String summary_;  // The test failure summary.
+  internal::String message_;  // The test failure message.
+};
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
+
+// An array of TestPartResult objects.
+//
+// We define this class as we cannot use STL containers when compiling
+// Google Test with MSVC 7.1 and exceptions disabled.
+//
+// Don't inherit from TestPartResultArray as its destructor is not
+// virtual.
+class TestPartResultArray {
+ public:
+  TestPartResultArray();
+  ~TestPartResultArray();
+
+  // Appends the given TestPartResult to the array.
+  void Append(const TestPartResult& result);
+
+  // Returns the TestPartResult at the given index (0-based).
+  const TestPartResult& GetTestPartResult(int index) const;
+
+  // Returns the number of TestPartResult objects in the array.
+  int size() const;
+ private:
+  // Internally we use a list to simulate the array.  Yes, this means
+  // that random access is O(N) in time, but it's OK for its purpose.
+  internal::List<TestPartResult>* const list_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
+};
+
+// This interface knows how to report a test part result.
+class TestPartResultReporterInterface {
+ public:
+  virtual ~TestPartResultReporterInterface() {}
+
+  virtual void ReportTestPartResult(const TestPartResult& result) = 0;
+};
+
+namespace internal {
+
+// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
+// statement generates new fatal failures. To do so it registers itself as the
+// current test part result reporter. Besides checking if fatal failures were
+// reported, it only delegates the reporting to the former result reporter.
+// The original result reporter is restored in the destructor.
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+class HasNewFatalFailureHelper : public TestPartResultReporterInterface {
+ public:
+  HasNewFatalFailureHelper();
+  virtual ~HasNewFatalFailureHelper();
+  virtual void ReportTestPartResult(const TestPartResult& result);
+  bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
+ private:
+  bool has_new_fatal_failure_;
+  TestPartResultReporterInterface* original_reporter_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
+};
+
+}  // namespace internal
+
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
diff --git a/third_party/gtest/include/gtest/gtest-typed-test.h b/third_party/gtest/include/gtest/gtest-typed-test.h
index c96752e..519edfe 100644
--- a/third_party/gtest/include/gtest/gtest-typed-test.h
+++ b/third_party/gtest/include/gtest/gtest-typed-test.h
@@ -1,253 +1,253 @@
-// Copyright 2008 Google Inc.

-// All Rights Reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan)

-

-#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_

-#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_

-

-// This header implements typed tests and type-parameterized tests.

-

-// Typed (aka type-driven) tests repeat the same test for types in a

-// list.  You must know which types you want to test with when writing

-// typed tests. Here's how you do it:

-

-#if 0

-

-// First, define a fixture class template.  It should be parameterized

-// by a type.  Remember to derive it from testing::Test.

-template <typename T>

-class FooTest : public testing::Test {

- public:

-  ...

-  typedef std::list<T> List;

-  static T shared_;

-  T value_;

-};

-

-// Next, associate a list of types with the test case, which will be

-// repeated for each type in the list.  The typedef is necessary for

-// the macro to parse correctly.

-typedef testing::Types<char, int, unsigned int> MyTypes;

-TYPED_TEST_CASE(FooTest, MyTypes);

-

-// If the type list contains only one type, you can write that type

-// directly without Types<...>:

-//   TYPED_TEST_CASE(FooTest, int);

-

-// Then, use TYPED_TEST() instead of TEST_F() to define as many typed

-// tests for this test case as you want.

-TYPED_TEST(FooTest, DoesBlah) {

-  // Inside a test, refer to TypeParam to get the type parameter.

-  // Since we are inside a derived class template, C++ requires use to

-  // visit the members of FooTest via 'this'.

-  TypeParam n = this->value_;

-

-  // To visit static members of the fixture, add the TestFixture::

-  // prefix.

-  n += TestFixture::shared_;

-

-  // To refer to typedefs in the fixture, add the "typename

-  // TestFixture::" prefix.

-  typename TestFixture::List values;

-  values.push_back(n);

-  ...

-}

-

-TYPED_TEST(FooTest, HasPropertyA) { ... }

-

-#endif  // 0

-

-// Type-parameterized tests are abstract test patterns parameterized

-// by a type.  Compared with typed tests, type-parameterized tests

-// allow you to define the test pattern without knowing what the type

-// parameters are.  The defined pattern can be instantiated with

-// different types any number of times, in any number of translation

-// units.

-//

-// If you are designing an interface or concept, you can define a

-// suite of type-parameterized tests to verify properties that any

-// valid implementation of the interface/concept should have.  Then,

-// each implementation can easily instantiate the test suite to verify

-// that it conforms to the requirements, without having to write

-// similar tests repeatedly.  Here's an example:

-

-#if 0

-

-// First, define a fixture class template.  It should be parameterized

-// by a type.  Remember to derive it from testing::Test.

-template <typename T>

-class FooTest : public testing::Test {

-  ...

-};

-

-// Next, declare that you will define a type-parameterized test case

-// (the _P suffix is for "parameterized" or "pattern", whichever you

-// prefer):

-TYPED_TEST_CASE_P(FooTest);

-

-// Then, use TYPED_TEST_P() to define as many type-parameterized tests

-// for this type-parameterized test case as you want.

-TYPED_TEST_P(FooTest, DoesBlah) {

-  // Inside a test, refer to TypeParam to get the type parameter.

-  TypeParam n = 0;

-  ...

-}

-

-TYPED_TEST_P(FooTest, HasPropertyA) { ... }

-

-// Now the tricky part: you need to register all test patterns before

-// you can instantiate them.  The first argument of the macro is the

-// test case name; the rest are the names of the tests in this test

-// case.

-REGISTER_TYPED_TEST_CASE_P(FooTest,

-                           DoesBlah, HasPropertyA);

-

-// Finally, you are free to instantiate the pattern with the types you

-// want.  If you put the above code in a header file, you can #include

-// it in multiple C++ source files and instantiate it multiple times.

-//

-// To distinguish different instances of the pattern, the first

-// argument to the INSTANTIATE_* macro is a prefix that will be added

-// to the actual test case name.  Remember to pick unique prefixes for

-// different instances.

-typedef testing::Types<char, int, unsigned int> MyTypes;

-INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);

-

-// If the type list contains only one type, you can write that type

-// directly without Types<...>:

-//   INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);

-

-#endif  // 0

-

-#include <gtest/internal/gtest-port.h>

-#include <gtest/internal/gtest-type-util.h>

-

-// Implements typed tests.

-

-#if GTEST_HAS_TYPED_TEST

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// Expands to the name of the typedef for the type parameters of the

-// given test case.

-#define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_

-

-#define TYPED_TEST_CASE(CaseName, Types) \

-  typedef ::testing::internal::TypeList<Types>::type \

-      GTEST_TYPE_PARAMS_(CaseName)

-

-#define TYPED_TEST(CaseName, TestName) \

-  template <typename gtest_TypeParam_> \

-  class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \

-      : public CaseName<gtest_TypeParam_> { \

-   private: \

-    typedef CaseName<gtest_TypeParam_> TestFixture; \

-    typedef gtest_TypeParam_ TypeParam; \

-    virtual void TestBody(); \

-  }; \

-  bool gtest_##CaseName##_##TestName##_registered_ = \

-      ::testing::internal::TypeParameterizedTest< \

-          CaseName, \

-          ::testing::internal::TemplateSel< \

-              GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \

-          GTEST_TYPE_PARAMS_(CaseName)>::Register(\

-              "", #CaseName, #TestName, 0); \

-  template <typename gtest_TypeParam_> \

-  void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()

-

-#endif  // GTEST_HAS_TYPED_TEST

-

-// Implements type-parameterized tests.

-

-#if GTEST_HAS_TYPED_TEST_P

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// Expands to the namespace name that the type-parameterized tests for

-// the given type-parameterized test case are defined in.  The exact

-// name of the namespace is subject to change without notice.

-#define GTEST_CASE_NAMESPACE_(TestCaseName) \

-  gtest_case_##TestCaseName##_

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// Expands to the name of the variable used to remember the names of

-// the defined tests in the given test case.

-#define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \

-  gtest_typed_test_case_p_state_##TestCaseName##_

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.

-//

-// Expands to the name of the variable used to remember the names of

-// the registered tests in the given test case.

-#define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \

-  gtest_registered_test_names_##TestCaseName##_

-

-// The variables defined in the type-parameterized test macros are

-// static as typically these macros are used in a .h file that can be

-// #included in multiple translation units linked together.

-#define TYPED_TEST_CASE_P(CaseName) \

-  static ::testing::internal::TypedTestCasePState \

-      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)

-

-#define TYPED_TEST_P(CaseName, TestName) \

-  namespace GTEST_CASE_NAMESPACE_(CaseName) { \

-  template <typename gtest_TypeParam_> \

-  class TestName : public CaseName<gtest_TypeParam_> { \

-   private: \

-    typedef CaseName<gtest_TypeParam_> TestFixture; \

-    typedef gtest_TypeParam_ TypeParam; \

-    virtual void TestBody(); \

-  }; \

-  static bool gtest_##TestName##_defined_ = \

-      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\

-          __FILE__, __LINE__, #CaseName, #TestName); \

-  } \

-  template <typename gtest_TypeParam_> \

-  void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()

-

-#define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \

-  namespace GTEST_CASE_NAMESPACE_(CaseName) { \

-  typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \

-  } \

-  static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \

-      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\

-          __FILE__, __LINE__, #__VA_ARGS__)

-

-#define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \

-  bool gtest_##Prefix##_##CaseName = \

-      ::testing::internal::TypeParameterizedTestCase<CaseName, \

-          GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \

-          ::testing::internal::TypeList<Types>::type>::Register(\

-              #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))

-

-#endif  // GTEST_HAS_TYPED_TEST_P

-

-#endif  // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_

+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+// This header implements typed tests and type-parameterized tests.
+
+// Typed (aka type-driven) tests repeat the same test for types in a
+// list.  You must know which types you want to test with when writing
+// typed tests. Here's how you do it:
+
+#if 0
+
+// First, define a fixture class template.  It should be parameterized
+// by a type.  Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ public:
+  ...
+  typedef std::list<T> List;
+  static T shared_;
+  T value_;
+};
+
+// Next, associate a list of types with the test case, which will be
+// repeated for each type in the list.  The typedef is necessary for
+// the macro to parse correctly.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+TYPED_TEST_CASE(FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+//   TYPED_TEST_CASE(FooTest, int);
+
+// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
+// tests for this test case as you want.
+TYPED_TEST(FooTest, DoesBlah) {
+  // Inside a test, refer to TypeParam to get the type parameter.
+  // Since we are inside a derived class template, C++ requires use to
+  // visit the members of FooTest via 'this'.
+  TypeParam n = this->value_;
+
+  // To visit static members of the fixture, add the TestFixture::
+  // prefix.
+  n += TestFixture::shared_;
+
+  // To refer to typedefs in the fixture, add the "typename
+  // TestFixture::" prefix.
+  typename TestFixture::List values;
+  values.push_back(n);
+  ...
+}
+
+TYPED_TEST(FooTest, HasPropertyA) { ... }
+
+#endif  // 0
+
+// Type-parameterized tests are abstract test patterns parameterized
+// by a type.  Compared with typed tests, type-parameterized tests
+// allow you to define the test pattern without knowing what the type
+// parameters are.  The defined pattern can be instantiated with
+// different types any number of times, in any number of translation
+// units.
+//
+// If you are designing an interface or concept, you can define a
+// suite of type-parameterized tests to verify properties that any
+// valid implementation of the interface/concept should have.  Then,
+// each implementation can easily instantiate the test suite to verify
+// that it conforms to the requirements, without having to write
+// similar tests repeatedly.  Here's an example:
+
+#if 0
+
+// First, define a fixture class template.  It should be parameterized
+// by a type.  Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+  ...
+};
+
+// Next, declare that you will define a type-parameterized test case
+// (the _P suffix is for "parameterized" or "pattern", whichever you
+// prefer):
+TYPED_TEST_CASE_P(FooTest);
+
+// Then, use TYPED_TEST_P() to define as many type-parameterized tests
+// for this type-parameterized test case as you want.
+TYPED_TEST_P(FooTest, DoesBlah) {
+  // Inside a test, refer to TypeParam to get the type parameter.
+  TypeParam n = 0;
+  ...
+}
+
+TYPED_TEST_P(FooTest, HasPropertyA) { ... }
+
+// Now the tricky part: you need to register all test patterns before
+// you can instantiate them.  The first argument of the macro is the
+// test case name; the rest are the names of the tests in this test
+// case.
+REGISTER_TYPED_TEST_CASE_P(FooTest,
+                           DoesBlah, HasPropertyA);
+
+// Finally, you are free to instantiate the pattern with the types you
+// want.  If you put the above code in a header file, you can #include
+// it in multiple C++ source files and instantiate it multiple times.
+//
+// To distinguish different instances of the pattern, the first
+// argument to the INSTANTIATE_* macro is a prefix that will be added
+// to the actual test case name.  Remember to pick unique prefixes for
+// different instances.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+//   INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
+
+#endif  // 0
+
+#include <gtest/internal/gtest-port.h>
+#include <gtest/internal/gtest-type-util.h>
+
+// Implements typed tests.
+
+#if GTEST_HAS_TYPED_TEST
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the typedef for the type parameters of the
+// given test case.
+#define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
+
+#define TYPED_TEST_CASE(CaseName, Types) \
+  typedef ::testing::internal::TypeList<Types>::type \
+      GTEST_TYPE_PARAMS_(CaseName)
+
+#define TYPED_TEST(CaseName, TestName) \
+  template <typename gtest_TypeParam_> \
+  class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
+      : public CaseName<gtest_TypeParam_> { \
+   private: \
+    typedef CaseName<gtest_TypeParam_> TestFixture; \
+    typedef gtest_TypeParam_ TypeParam; \
+    virtual void TestBody(); \
+  }; \
+  bool gtest_##CaseName##_##TestName##_registered_ = \
+      ::testing::internal::TypeParameterizedTest< \
+          CaseName, \
+          ::testing::internal::TemplateSel< \
+              GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
+          GTEST_TYPE_PARAMS_(CaseName)>::Register(\
+              "", #CaseName, #TestName, 0); \
+  template <typename gtest_TypeParam_> \
+  void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
+
+#endif  // GTEST_HAS_TYPED_TEST
+
+// Implements type-parameterized tests.
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the namespace name that the type-parameterized tests for
+// the given type-parameterized test case are defined in.  The exact
+// name of the namespace is subject to change without notice.
+#define GTEST_CASE_NAMESPACE_(TestCaseName) \
+  gtest_case_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the variable used to remember the names of
+// the defined tests in the given test case.
+#define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
+  gtest_typed_test_case_p_state_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
+//
+// Expands to the name of the variable used to remember the names of
+// the registered tests in the given test case.
+#define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
+  gtest_registered_test_names_##TestCaseName##_
+
+// The variables defined in the type-parameterized test macros are
+// static as typically these macros are used in a .h file that can be
+// #included in multiple translation units linked together.
+#define TYPED_TEST_CASE_P(CaseName) \
+  static ::testing::internal::TypedTestCasePState \
+      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
+
+#define TYPED_TEST_P(CaseName, TestName) \
+  namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+  template <typename gtest_TypeParam_> \
+  class TestName : public CaseName<gtest_TypeParam_> { \
+   private: \
+    typedef CaseName<gtest_TypeParam_> TestFixture; \
+    typedef gtest_TypeParam_ TypeParam; \
+    virtual void TestBody(); \
+  }; \
+  static bool gtest_##TestName##_defined_ = \
+      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
+          __FILE__, __LINE__, #CaseName, #TestName); \
+  } \
+  template <typename gtest_TypeParam_> \
+  void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
+
+#define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
+  namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+  typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
+  } \
+  static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
+      GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
+          __FILE__, __LINE__, #__VA_ARGS__)
+
+#define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
+  bool gtest_##Prefix##_##CaseName = \
+      ::testing::internal::TypeParameterizedTestCase<CaseName, \
+          GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
+          ::testing::internal::TypeList<Types>::type>::Register(\
+              #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
+
+#endif  // GTEST_HAS_TYPED_TEST_P
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
diff --git a/third_party/gtest/include/gtest/gtest.h b/third_party/gtest/include/gtest/gtest.h
index dfb4612..f543778 100644
--- a/third_party/gtest/include/gtest/gtest.h
+++ b/third_party/gtest/include/gtest/gtest.h
@@ -1,1420 +1,1420 @@
-// Copyright 2005, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan)

-//

-// The Google C++ Testing Framework (Google Test)

-//

-// This header file defines the public API for Google Test.  It should be

-// included by any test program that uses Google Test.

-//

-// IMPORTANT NOTE: Due to limitation of the C++ language, we have to

-// leave some internal implementation details in this header file.

-// They are clearly marked by comments like this:

-//

-//   // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-//

-// Such code is NOT meant to be used by a user directly, and is subject

-// to CHANGE WITHOUT NOTICE.  Therefore DO NOT DEPEND ON IT in a user

-// program!

-//

-// Acknowledgment: Google Test borrowed the idea of automatic test

-// registration from Barthelemy Dagenais' (barthelemy@prologique.com)

-// easyUnit framework.

-

-#ifndef GTEST_INCLUDE_GTEST_GTEST_H_

-#define GTEST_INCLUDE_GTEST_GTEST_H_

-

-// The following platform macro is used throughout Google Test:

-//   _WIN32_WCE      Windows CE     (set in project files)

-

-#include <limits>

-#include <gtest/internal/gtest-internal.h>

-#include <gtest/internal/gtest-string.h>

-#include <gtest/gtest-death-test.h>

-#include <gtest/gtest-message.h>

-#include <gtest/gtest-param-test.h>

-#include <gtest/gtest_prod.h>

-#include <gtest/gtest-test-part.h>

-#include <gtest/gtest-typed-test.h>

-

-// Depending on the platform, different string classes are available.

-// On Windows, ::std::string compiles only when exceptions are

-// enabled.  On Linux, in addition to ::std::string, Google also makes

-// use of class ::string, which has the same interface as

-// ::std::string, but has a different implementation.

-//

-// The user can tell us whether ::std::string is available in his

-// environment by defining the macro GTEST_HAS_STD_STRING to either 1

-// or 0 on the compiler command line.  He can also define

-// GTEST_HAS_GLOBAL_STRING to 1 to indicate that ::string is available

-// AND is a distinct type to ::std::string, or define it to 0 to

-// indicate otherwise.

-//

-// If the user's ::std::string and ::string are the same class due to

-// aliasing, he should define GTEST_HAS_STD_STRING to 1 and

-// GTEST_HAS_GLOBAL_STRING to 0.

-//

-// If the user doesn't define GTEST_HAS_STD_STRING and/or

-// GTEST_HAS_GLOBAL_STRING, they are defined heuristically.

-

-namespace testing {

-

-// Declares the flags.

-

-// This flag temporary enables the disabled tests.

-GTEST_DECLARE_bool_(also_run_disabled_tests);

-

-// This flag brings the debugger on an assertion failure.

-GTEST_DECLARE_bool_(break_on_failure);

-

-// This flag controls whether Google Test catches all test-thrown exceptions

-// and logs them as failures.

-GTEST_DECLARE_bool_(catch_exceptions);

-

-// This flag enables using colors in terminal output. Available values are

-// "yes" to enable colors, "no" (disable colors), or "auto" (the default)

-// to let Google Test decide.

-GTEST_DECLARE_string_(color);

-

-// This flag sets up the filter to select by name using a glob pattern

-// the tests to run. If the filter is not given all tests are executed.

-GTEST_DECLARE_string_(filter);

-

-// This flag causes the Google Test to list tests. None of the tests listed

-// are actually run if the flag is provided.

-GTEST_DECLARE_bool_(list_tests);

-

-// This flag controls whether Google Test emits a detailed XML report to a file

-// in addition to its normal textual output.

-GTEST_DECLARE_string_(output);

-

-// This flags control whether Google Test prints the elapsed time for each

-// test.

-GTEST_DECLARE_bool_(print_time);

-

-// This flag sets how many times the tests are repeated. The default value

-// is 1. If the value is -1 the tests are repeating forever.

-GTEST_DECLARE_int32_(repeat);

-

-// This flag controls whether Google Test includes Google Test internal

-// stack frames in failure stack traces.

-GTEST_DECLARE_bool_(show_internal_stack_frames);

-

-// This flag specifies the maximum number of stack frames to be

-// printed in a failure message.

-GTEST_DECLARE_int32_(stack_trace_depth);

-

-// When this flag is specified, a failed assertion will throw an

-// exception if exceptions are enabled, or exit the program with a

-// non-zero code otherwise.

-GTEST_DECLARE_bool_(throw_on_failure);

-

-// The upper limit for valid stack trace depths.

-const int kMaxStackTraceDepth = 100;

-

-namespace internal {

-

-class GTestFlagSaver;

-

-// Converts a streamable value to a String.  A NULL pointer is

-// converted to "(null)".  When the input value is a ::string,

-// ::std::string, ::wstring, or ::std::wstring object, each NUL

-// character in it is replaced with "\\0".

-// Declared in gtest-internal.h but defined here, so that it has access

-// to the definition of the Message class, required by the ARM

-// compiler.

-template <typename T>

-String StreamableToString(const T& streamable) {

-  return (Message() << streamable).GetString();

-}

-

-}  // namespace internal

-

-// A class for indicating whether an assertion was successful.  When

-// the assertion wasn't successful, the AssertionResult object

-// remembers a non-empty message that described how it failed.

-//

-// This class is useful for defining predicate-format functions to be

-// used with predicate assertions (ASSERT_PRED_FORMAT*, etc).

-//

-// The constructor of AssertionResult is private.  To create an

-// instance of this class, use one of the factory functions

-// (AssertionSuccess() and AssertionFailure()).

-//

-// For example, in order to be able to write:

-//

-//   // Verifies that Foo() returns an even number.

-//   EXPECT_PRED_FORMAT1(IsEven, Foo());

-//

-// you just need to define:

-//

-//   testing::AssertionResult IsEven(const char* expr, int n) {

-//     if ((n % 2) == 0) return testing::AssertionSuccess();

-//

-//     Message msg;

-//     msg << "Expected: " << expr << " is even\n"

-//         << "  Actual: it's " << n;

-//     return testing::AssertionFailure(msg);

-//   }

-//

-// If Foo() returns 5, you will see the following message:

-//

-//   Expected: Foo() is even

-//     Actual: it's 5

-class AssertionResult {

- public:

-  // Declares factory functions for making successful and failed

-  // assertion results as friends.

-  friend AssertionResult AssertionSuccess();

-  friend AssertionResult AssertionFailure(const Message&);

-

-  // Returns true iff the assertion succeeded.

-  operator bool() const { return failure_message_.c_str() == NULL; }  // NOLINT

-

-  // Returns the assertion's failure message.

-  const char* failure_message() const { return failure_message_.c_str(); }

-

- private:

-  // The default constructor.  It is used when the assertion succeeded.

-  AssertionResult() {}

-

-  // The constructor used when the assertion failed.

-  explicit AssertionResult(const internal::String& failure_message);

-

-  // Stores the assertion's failure message.

-  internal::String failure_message_;

-};

-

-// Makes a successful assertion result.

-AssertionResult AssertionSuccess();

-

-// Makes a failed assertion result with the given failure message.

-AssertionResult AssertionFailure(const Message& msg);

-

-// The abstract class that all tests inherit from.

-//

-// In Google Test, a unit test program contains one or many TestCases, and

-// each TestCase contains one or many Tests.

-//

-// When you define a test using the TEST macro, you don't need to

-// explicitly derive from Test - the TEST macro automatically does

-// this for you.

-//

-// The only time you derive from Test is when defining a test fixture

-// to be used a TEST_F.  For example:

-//

-//   class FooTest : public testing::Test {

-//    protected:

-//     virtual void SetUp() { ... }

-//     virtual void TearDown() { ... }

-//     ...

-//   };

-//

-//   TEST_F(FooTest, Bar) { ... }

-//   TEST_F(FooTest, Baz) { ... }

-//

-// Test is not copyable.

-class Test {

- public:

-  friend class internal::TestInfoImpl;

-

-  // Defines types for pointers to functions that set up and tear down

-  // a test case.

-  typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;

-  typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;

-

-  // The d'tor is virtual as we intend to inherit from Test.

-  virtual ~Test();

-

-  // Sets up the stuff shared by all tests in this test case.

-  //

-  // Google Test will call Foo::SetUpTestCase() before running the first

-  // test in test case Foo.  Hence a sub-class can define its own

-  // SetUpTestCase() method to shadow the one defined in the super

-  // class.

-  static void SetUpTestCase() {}

-

-  // Tears down the stuff shared by all tests in this test case.

-  //

-  // Google Test will call Foo::TearDownTestCase() after running the last

-  // test in test case Foo.  Hence a sub-class can define its own

-  // TearDownTestCase() method to shadow the one defined in the super

-  // class.

-  static void TearDownTestCase() {}

-

-  // Returns true iff the current test has a fatal failure.

-  static bool HasFatalFailure();

-

-  // Returns true iff the current test has a non-fatal failure.

-  static bool HasNonfatalFailure();

-

-  // Returns true iff the current test has a (either fatal or

-  // non-fatal) failure.

-  static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }

-

-  // Logs a property for the current test.  Only the last value for a given

-  // key is remembered.

-  // These are public static so they can be called from utility functions

-  // that are not members of the test fixture.

-  // The arguments are const char* instead strings, as Google Test is used

-  // on platforms where string doesn't compile.

-  //

-  // Note that a driving consideration for these RecordProperty methods

-  // was to produce xml output suited to the Greenspan charting utility,

-  // which at present will only chart values that fit in a 32-bit int. It

-  // is the user's responsibility to restrict their values to 32-bit ints

-  // if they intend them to be used with Greenspan.

-  static void RecordProperty(const char* key, const char* value);

-  static void RecordProperty(const char* key, int value);

-

- protected:

-  // Creates a Test object.

-  Test();

-

-  // Sets up the test fixture.

-  virtual void SetUp();

-

-  // Tears down the test fixture.

-  virtual void TearDown();

-

- private:

-  // Returns true iff the current test has the same fixture class as

-  // the first test in the current test case.

-  static bool HasSameFixtureClass();

-

-  // Runs the test after the test fixture has been set up.

-  //

-  // A sub-class must implement this to define the test logic.

-  //

-  // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.

-  // Instead, use the TEST or TEST_F macro.

-  virtual void TestBody() = 0;

-

-  // Sets up, executes, and tears down the test.

-  void Run();

-

-  // Uses a GTestFlagSaver to save and restore all Google Test flags.

-  const internal::GTestFlagSaver* const gtest_flag_saver_;

-

-  // Often a user mis-spells SetUp() as Setup() and spends a long time

-  // wondering why it is never called by Google Test.  The declaration of

-  // the following method is solely for catching such an error at

-  // compile time:

-  //

-  //   - The return type is deliberately chosen to be not void, so it

-  //   will be a conflict if a user declares void Setup() in his test

-  //   fixture.

-  //

-  //   - This method is private, so it will be another compiler error

-  //   if a user calls it from his test fixture.

-  //

-  // DO NOT OVERRIDE THIS FUNCTION.

-  //

-  // If you see an error about overriding the following function or

-  // about it being private, you have mis-spelled SetUp() as Setup().

-  struct Setup_should_be_spelled_SetUp {};

-  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }

-

-  // We disallow copying Tests.

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);

-};

-

-

-// A TestInfo object stores the following information about a test:

-//

-//   Test case name

-//   Test name

-//   Whether the test should be run

-//   A function pointer that creates the test object when invoked

-//   Test result

-//

-// The constructor of TestInfo registers itself with the UnitTest

-// singleton such that the RUN_ALL_TESTS() macro knows which tests to

-// run.

-class TestInfo {

- public:

-  // Destructs a TestInfo object.  This function is not virtual, so

-  // don't inherit from TestInfo.

-  ~TestInfo();

-

-  // Returns the test case name.

-  const char* test_case_name() const;

-

-  // Returns the test name.

-  const char* name() const;

-

-  // Returns the test case comment.

-  const char* test_case_comment() const;

-

-  // Returns the test comment.

-  const char* comment() const;

-

-  // Returns true if this test matches the user-specified filter.

-  bool matches_filter() const;

-

-  // Returns true if this test should run, that is if the test is not disabled

-  // (or it is disabled but the also_run_disabled_tests flag has been specified)

-  // and its full name matches the user-specified filter.

-  //

-  // Google Test allows the user to filter the tests by their full names.

-  // The full name of a test Bar in test case Foo is defined as

-  // "Foo.Bar".  Only the tests that match the filter will run.

-  //

-  // A filter is a colon-separated list of glob (not regex) patterns,

-  // optionally followed by a '-' and a colon-separated list of

-  // negative patterns (tests to exclude).  A test is run if it

-  // matches one of the positive patterns and does not match any of

-  // the negative patterns.

-  //

-  // For example, *A*:Foo.* is a filter that matches any string that

-  // contains the character 'A' or starts with "Foo.".

-  bool should_run() const;

-

-  // Returns the result of the test.

-  const internal::TestResult* result() const;

- private:

-#if GTEST_HAS_DEATH_TEST

-  friend class internal::DefaultDeathTestFactory;

-#endif  // GTEST_HAS_DEATH_TEST

-  friend class internal::TestInfoImpl;

-  friend class internal::UnitTestImpl;

-  friend class Test;

-  friend class TestCase;

-  friend TestInfo* internal::MakeAndRegisterTestInfo(

-      const char* test_case_name, const char* name,

-      const char* test_case_comment, const char* comment,

-      internal::TypeId fixture_class_id,

-      Test::SetUpTestCaseFunc set_up_tc,

-      Test::TearDownTestCaseFunc tear_down_tc,

-      internal::TestFactoryBase* factory);

-

-  // Increments the number of death tests encountered in this test so

-  // far.

-  int increment_death_test_count();

-

-  // Accessors for the implementation object.

-  internal::TestInfoImpl* impl() { return impl_; }

-  const internal::TestInfoImpl* impl() const { return impl_; }

-

-  // Constructs a TestInfo object. The newly constructed instance assumes

-  // ownership of the factory object.

-  TestInfo(const char* test_case_name, const char* name,

-           const char* test_case_comment, const char* comment,

-           internal::TypeId fixture_class_id,

-           internal::TestFactoryBase* factory);

-

-  // An opaque implementation object.

-  internal::TestInfoImpl* impl_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);

-};

-

-// An Environment object is capable of setting up and tearing down an

-// environment.  The user should subclass this to define his own

-// environment(s).

-//

-// An Environment object does the set-up and tear-down in virtual

-// methods SetUp() and TearDown() instead of the constructor and the

-// destructor, as:

-//

-//   1. You cannot safely throw from a destructor.  This is a problem

-//      as in some cases Google Test is used where exceptions are enabled, and

-//      we may want to implement ASSERT_* using exceptions where they are

-//      available.

-//   2. You cannot use ASSERT_* directly in a constructor or

-//      destructor.

-class Environment {

- public:

-  // The d'tor is virtual as we need to subclass Environment.

-  virtual ~Environment() {}

-

-  // Override this to define how to set up the environment.

-  virtual void SetUp() {}

-

-  // Override this to define how to tear down the environment.

-  virtual void TearDown() {}

- private:

-  // If you see an error about overriding the following function or

-  // about it being private, you have mis-spelled SetUp() as Setup().

-  struct Setup_should_be_spelled_SetUp {};

-  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }

-};

-

-// A UnitTest consists of a list of TestCases.

-//

-// This is a singleton class.  The only instance of UnitTest is

-// created when UnitTest::GetInstance() is first called.  This

-// instance is never deleted.

-//

-// UnitTest is not copyable.

-//

-// This class is thread-safe as long as the methods are called

-// according to their specification.

-class UnitTest {

- public:

-  // Gets the singleton UnitTest object.  The first time this method

-  // is called, a UnitTest object is constructed and returned.

-  // Consecutive calls will return the same object.

-  static UnitTest* GetInstance();

-

-  // Registers and returns a global test environment.  When a test

-  // program is run, all global test environments will be set-up in

-  // the order they were registered.  After all tests in the program

-  // have finished, all global test environments will be torn-down in

-  // the *reverse* order they were registered.

-  //

-  // The UnitTest object takes ownership of the given environment.

-  //

-  // This method can only be called from the main thread.

-  Environment* AddEnvironment(Environment* env);

-

-  // Adds a TestPartResult to the current TestResult object.  All

-  // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)

-  // eventually call this to report their results.  The user code

-  // should use the assertion macros instead of calling this directly.

-  //

-  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-  void AddTestPartResult(TestPartResultType result_type,

-                         const char* file_name,

-                         int line_number,

-                         const internal::String& message,

-                         const internal::String& os_stack_trace);

-

-  // Adds a TestProperty to the current TestResult object. If the result already

-  // contains a property with the same key, the value will be updated.

-  void RecordPropertyForCurrentTest(const char* key, const char* value);

-

-  // Runs all tests in this UnitTest object and prints the result.

-  // Returns 0 if successful, or 1 otherwise.

-  //

-  // This method can only be called from the main thread.

-  //

-  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-  int Run() GTEST_MUST_USE_RESULT_;

-

-  // Returns the working directory when the first TEST() or TEST_F()

-  // was executed.  The UnitTest object owns the string.

-  const char* original_working_dir() const;

-

-  // Returns the TestCase object for the test that's currently running,

-  // or NULL if no test is running.

-  const TestCase* current_test_case() const;

-

-  // Returns the TestInfo object for the test that's currently running,

-  // or NULL if no test is running.

-  const TestInfo* current_test_info() const;

-

-#if GTEST_HAS_PARAM_TEST

-  // Returns the ParameterizedTestCaseRegistry object used to keep track of

-  // value-parameterized tests and instantiate and register them.

-  internal::ParameterizedTestCaseRegistry& parameterized_test_registry();

-#endif  // GTEST_HAS_PARAM_TEST

-

-  // Accessors for the implementation object.

-  internal::UnitTestImpl* impl() { return impl_; }

-  const internal::UnitTestImpl* impl() const { return impl_; }

- private:

-  // ScopedTrace is a friend as it needs to modify the per-thread

-  // trace stack, which is a private member of UnitTest.

-  friend class internal::ScopedTrace;

-

-  // Creates an empty UnitTest.

-  UnitTest();

-

-  // D'tor

-  virtual ~UnitTest();

-

-  // Pushes a trace defined by SCOPED_TRACE() on to the per-thread

-  // Google Test trace stack.

-  void PushGTestTrace(const internal::TraceInfo& trace);

-

-  // Pops a trace from the per-thread Google Test trace stack.

-  void PopGTestTrace();

-

-  // Protects mutable state in *impl_.  This is mutable as some const

-  // methods need to lock it too.

-  mutable internal::Mutex mutex_;

-

-  // Opaque implementation object.  This field is never changed once

-  // the object is constructed.  We don't mark it as const here, as

-  // doing so will cause a warning in the constructor of UnitTest.

-  // Mutable state in *impl_ is protected by mutex_.

-  internal::UnitTestImpl* impl_;

-

-  // We disallow copying UnitTest.

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);

-};

-

-// A convenient wrapper for adding an environment for the test

-// program.

-//

-// You should call this before RUN_ALL_TESTS() is called, probably in

-// main().  If you use gtest_main, you need to call this before main()

-// starts for it to take effect.  For example, you can define a global

-// variable like this:

-//

-//   testing::Environment* const foo_env =

-//       testing::AddGlobalTestEnvironment(new FooEnvironment);

-//

-// However, we strongly recommend you to write your own main() and

-// call AddGlobalTestEnvironment() there, as relying on initialization

-// of global variables makes the code harder to read and may cause

-// problems when you register multiple environments from different

-// translation units and the environments have dependencies among them

-// (remember that the compiler doesn't guarantee the order in which

-// global variables from different translation units are initialized).

-inline Environment* AddGlobalTestEnvironment(Environment* env) {

-  return UnitTest::GetInstance()->AddEnvironment(env);

-}

-

-// Initializes Google Test.  This must be called before calling

-// RUN_ALL_TESTS().  In particular, it parses a command line for the

-// flags that Google Test recognizes.  Whenever a Google Test flag is

-// seen, it is removed from argv, and *argc is decremented.

-//

-// No value is returned.  Instead, the Google Test flag variables are

-// updated.

-//

-// Calling the function for the second time has no user-visible effect.

-void InitGoogleTest(int* argc, char** argv);

-

-// This overloaded version can be used in Windows programs compiled in

-// UNICODE mode.

-void InitGoogleTest(int* argc, wchar_t** argv);

-

-namespace internal {

-

-// These overloaded versions handle ::std::string and ::std::wstring.

-#if GTEST_HAS_STD_STRING

-inline String FormatForFailureMessage(const ::std::string& str) {

-  return (Message() << '"' << str << '"').GetString();

-}

-#endif  // GTEST_HAS_STD_STRING

-

-#if GTEST_HAS_STD_WSTRING

-inline String FormatForFailureMessage(const ::std::wstring& wstr) {

-  return (Message() << "L\"" << wstr << '"').GetString();

-}

-#endif  // GTEST_HAS_STD_WSTRING

-

-// These overloaded versions handle ::string and ::wstring.

-#if GTEST_HAS_GLOBAL_STRING

-inline String FormatForFailureMessage(const ::string& str) {

-  return (Message() << '"' << str << '"').GetString();

-}

-#endif  // GTEST_HAS_GLOBAL_STRING

-

-#if GTEST_HAS_GLOBAL_WSTRING

-inline String FormatForFailureMessage(const ::wstring& wstr) {

-  return (Message() << "L\"" << wstr << '"').GetString();

-}

-#endif  // GTEST_HAS_GLOBAL_WSTRING

-

-// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)

-// operand to be used in a failure message.  The type (but not value)

-// of the other operand may affect the format.  This allows us to

-// print a char* as a raw pointer when it is compared against another

-// char*, and print it as a C string when it is compared against an

-// std::string object, for example.

-//

-// The default implementation ignores the type of the other operand.

-// Some specialized versions are used to handle formatting wide or

-// narrow C strings.

-//

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-template <typename T1, typename T2>

-String FormatForComparisonFailureMessage(const T1& value,

-                                         const T2& /* other_operand */) {

-  return FormatForFailureMessage(value);

-}

-

-// The helper function for {ASSERT|EXPECT}_EQ.

-template <typename T1, typename T2>

-AssertionResult CmpHelperEQ(const char* expected_expression,

-                            const char* actual_expression,

-                            const T1& expected,

-                            const T2& actual) {

-#ifdef _MSC_VER

-#pragma warning(push)          // Saves the current warning state.

-#pragma warning(disable:4389)  // Temporarily disables warning on

-                               // signed/unsigned mismatch.

-#endif

-

-  if (expected == actual) {

-    return AssertionSuccess();

-  }

-

-#ifdef _MSC_VER

-#pragma warning(pop)          // Restores the warning state.

-#endif

-

-  return EqFailure(expected_expression,

-                   actual_expression,

-                   FormatForComparisonFailureMessage(expected, actual),

-                   FormatForComparisonFailureMessage(actual, expected),

-                   false);

-}

-

-// With this overloaded version, we allow anonymous enums to be used

-// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums

-// can be implicitly cast to BiggestInt.

-AssertionResult CmpHelperEQ(const char* expected_expression,

-                            const char* actual_expression,

-                            BiggestInt expected,

-                            BiggestInt actual);

-

-// The helper class for {ASSERT|EXPECT}_EQ.  The template argument

-// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()

-// is a null pointer literal.  The following default implementation is

-// for lhs_is_null_literal being false.

-template <bool lhs_is_null_literal>

-class EqHelper {

- public:

-  // This templatized version is for the general case.

-  template <typename T1, typename T2>

-  static AssertionResult Compare(const char* expected_expression,

-                                 const char* actual_expression,

-                                 const T1& expected,

-                                 const T2& actual) {

-    return CmpHelperEQ(expected_expression, actual_expression, expected,

-                       actual);

-  }

-

-  // With this overloaded version, we allow anonymous enums to be used

-  // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous

-  // enums can be implicitly cast to BiggestInt.

-  //

-  // Even though its body looks the same as the above version, we

-  // cannot merge the two, as it will make anonymous enums unhappy.

-  static AssertionResult Compare(const char* expected_expression,

-                                 const char* actual_expression,

-                                 BiggestInt expected,

-                                 BiggestInt actual) {

-    return CmpHelperEQ(expected_expression, actual_expression, expected,

-                       actual);

-  }

-};

-

-// This specialization is used when the first argument to ASSERT_EQ()

-// is a null pointer literal.

-template <>

-class EqHelper<true> {

- public:

-  // We define two overloaded versions of Compare().  The first

-  // version will be picked when the second argument to ASSERT_EQ() is

-  // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or

-  // EXPECT_EQ(false, a_bool).

-  template <typename T1, typename T2>

-  static AssertionResult Compare(const char* expected_expression,

-                                 const char* actual_expression,

-                                 const T1& expected,

-                                 const T2& actual) {

-    return CmpHelperEQ(expected_expression, actual_expression, expected,

-                       actual);

-  }

-

-  // This version will be picked when the second argument to

-  // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer).

-  template <typename T1, typename T2>

-  static AssertionResult Compare(const char* expected_expression,

-                                 const char* actual_expression,

-                                 const T1& /* expected */,

-                                 T2* actual) {

-    // We already know that 'expected' is a null pointer.

-    return CmpHelperEQ(expected_expression, actual_expression,

-                       static_cast<T2*>(NULL), actual);

-  }

-};

-

-// A macro for implementing the helper functions needed to implement

-// ASSERT_?? and EXPECT_??.  It is here just to avoid copy-and-paste

-// of similar code.

-//

-// For each templatized helper function, we also define an overloaded

-// version for BiggestInt in order to reduce code bloat and allow

-// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled

-// with gcc 4.

-//

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-#define GTEST_IMPL_CMP_HELPER_(op_name, op)\

-template <typename T1, typename T2>\

-AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \

-                                   const T1& val1, const T2& val2) {\

-  if (val1 op val2) {\

-    return AssertionSuccess();\

-  } else {\

-    Message msg;\

-    msg << "Expected: (" << expr1 << ") " #op " (" << expr2\

-        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\

-        << " vs " << FormatForComparisonFailureMessage(val2, val1);\

-    return AssertionFailure(msg);\

-  }\

-}\

-AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \

-                                   BiggestInt val1, BiggestInt val2);

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-

-// Implements the helper function for {ASSERT|EXPECT}_NE

-GTEST_IMPL_CMP_HELPER_(NE, !=)

-// Implements the helper function for {ASSERT|EXPECT}_LE

-GTEST_IMPL_CMP_HELPER_(LE, <=)

-// Implements the helper function for {ASSERT|EXPECT}_LT

-GTEST_IMPL_CMP_HELPER_(LT, < )

-// Implements the helper function for {ASSERT|EXPECT}_GE

-GTEST_IMPL_CMP_HELPER_(GE, >=)

-// Implements the helper function for {ASSERT|EXPECT}_GT

-GTEST_IMPL_CMP_HELPER_(GT, > )

-

-#undef GTEST_IMPL_CMP_HELPER_

-

-// The helper function for {ASSERT|EXPECT}_STREQ.

-//

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-AssertionResult CmpHelperSTREQ(const char* expected_expression,

-                               const char* actual_expression,

-                               const char* expected,

-                               const char* actual);

-

-// The helper function for {ASSERT|EXPECT}_STRCASEEQ.

-//

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,

-                                   const char* actual_expression,

-                                   const char* expected,

-                                   const char* actual);

-

-// The helper function for {ASSERT|EXPECT}_STRNE.

-//

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-AssertionResult CmpHelperSTRNE(const char* s1_expression,

-                               const char* s2_expression,

-                               const char* s1,

-                               const char* s2);

-

-// The helper function for {ASSERT|EXPECT}_STRCASENE.

-//

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-AssertionResult CmpHelperSTRCASENE(const char* s1_expression,

-                                   const char* s2_expression,

-                                   const char* s1,

-                                   const char* s2);

-

-

-// Helper function for *_STREQ on wide strings.

-//

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-AssertionResult CmpHelperSTREQ(const char* expected_expression,

-                               const char* actual_expression,

-                               const wchar_t* expected,

-                               const wchar_t* actual);

-

-// Helper function for *_STRNE on wide strings.

-//

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-AssertionResult CmpHelperSTRNE(const char* s1_expression,

-                               const char* s2_expression,

-                               const wchar_t* s1,

-                               const wchar_t* s2);

-

-}  // namespace internal

-

-// IsSubstring() and IsNotSubstring() are intended to be used as the

-// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by

-// themselves.  They check whether needle is a substring of haystack

-// (NULL is considered a substring of itself only), and return an

-// appropriate error message when they fail.

-//

-// The {needle,haystack}_expr arguments are the stringified

-// expressions that generated the two real arguments.

-AssertionResult IsSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const char* needle, const char* haystack);

-AssertionResult IsSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const wchar_t* needle, const wchar_t* haystack);

-AssertionResult IsNotSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const char* needle, const char* haystack);

-AssertionResult IsNotSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const wchar_t* needle, const wchar_t* haystack);

-#if GTEST_HAS_STD_STRING

-AssertionResult IsSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const ::std::string& needle, const ::std::string& haystack);

-AssertionResult IsNotSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const ::std::string& needle, const ::std::string& haystack);

-#endif  // GTEST_HAS_STD_STRING

-

-#if GTEST_HAS_STD_WSTRING

-AssertionResult IsSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const ::std::wstring& needle, const ::std::wstring& haystack);

-AssertionResult IsNotSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const ::std::wstring& needle, const ::std::wstring& haystack);

-#endif  // GTEST_HAS_STD_WSTRING

-

-namespace internal {

-

-// Helper template function for comparing floating-points.

-//

-// Template parameter:

-//

-//   RawType: the raw floating-point type (either float or double)

-//

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-template <typename RawType>

-AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,

-                                         const char* actual_expression,

-                                         RawType expected,

-                                         RawType actual) {

-  const FloatingPoint<RawType> lhs(expected), rhs(actual);

-

-  if (lhs.AlmostEquals(rhs)) {

-    return AssertionSuccess();

-  }

-

-  StrStream expected_ss;

-  expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)

-              << expected;

-

-  StrStream actual_ss;

-  actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)

-            << actual;

-

-  return EqFailure(expected_expression,

-                   actual_expression,

-                   StrStreamToString(&expected_ss),

-                   StrStreamToString(&actual_ss),

-                   false);

-}

-

-// Helper function for implementing ASSERT_NEAR.

-//

-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

-AssertionResult DoubleNearPredFormat(const char* expr1,

-                                     const char* expr2,

-                                     const char* abs_error_expr,

-                                     double val1,

-                                     double val2,

-                                     double abs_error);

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-// A class that enables one to stream messages to assertion macros

-class AssertHelper {

- public:

-  // Constructor.

-  AssertHelper(TestPartResultType type, const char* file, int line,

-               const char* message);

-  // Message assignment is a semantic trick to enable assertion

-  // streaming; see the GTEST_MESSAGE_ macro below.

-  void operator=(const Message& message) const;

- private:

-  TestPartResultType const type_;

-  const char*        const file_;

-  int                const line_;

-  String             const message_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);

-};

-

-}  // namespace internal

-

-#if GTEST_HAS_PARAM_TEST

-// The abstract base class that all value-parameterized tests inherit from.

-//

-// This class adds support for accessing the test parameter value via

-// the GetParam() method.

-//

-// Use it with one of the parameter generator defining functions, like Range(),

-// Values(), ValuesIn(), Bool(), and Combine().

-//

-// class FooTest : public ::testing::TestWithParam<int> {

-//  protected:

-//   FooTest() {

-//     // Can use GetParam() here.

-//   }

-//   virtual ~FooTest() {

-//     // Can use GetParam() here.

-//   }

-//   virtual void SetUp() {

-//     // Can use GetParam() here.

-//   }

-//   virtual void TearDown {

-//     // Can use GetParam() here.

-//   }

-// };

-// TEST_P(FooTest, DoesBar) {

-//   // Can use GetParam() method here.

-//   Foo foo;

-//   ASSERT_TRUE(foo.DoesBar(GetParam()));

-// }

-// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));

-

-template <typename T>

-class TestWithParam : public Test {

- public:

-  typedef T ParamType;

-

-  // The current parameter value. Is also available in the test fixture's

-  // constructor.

-  const ParamType& GetParam() const { return *parameter_; }

-

- private:

-  // Sets parameter value. The caller is responsible for making sure the value

-  // remains alive and unchanged throughout the current test.

-  static void SetParam(const ParamType* parameter) {

-    parameter_ = parameter;

-  }

-

-  // Static value used for accessing parameter during a test lifetime.

-  static const ParamType* parameter_;

-

-  // TestClass must be a subclass of TestWithParam<T>.

-  template <class TestClass> friend class internal::ParameterizedTestFactory;

-};

-

-template <typename T>

-const T* TestWithParam<T>::parameter_ = NULL;

-

-#endif  // GTEST_HAS_PARAM_TEST

-

-// Macros for indicating success/failure in test code.

-

-// ADD_FAILURE unconditionally adds a failure to the current test.

-// SUCCEED generates a success - it doesn't automatically make the

-// current test successful, as a test is only successful when it has

-// no failure.

-//

-// EXPECT_* verifies that a certain condition is satisfied.  If not,

-// it behaves like ADD_FAILURE.  In particular:

-//

-//   EXPECT_TRUE  verifies that a Boolean condition is true.

-//   EXPECT_FALSE verifies that a Boolean condition is false.

-//

-// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except

-// that they will also abort the current function on failure.  People

-// usually want the fail-fast behavior of FAIL and ASSERT_*, but those

-// writing data-driven tests often find themselves using ADD_FAILURE

-// and EXPECT_* more.

-//

-// Examples:

-//

-//   EXPECT_TRUE(server.StatusIsOK());

-//   ASSERT_FALSE(server.HasPendingRequest(port))

-//       << "There are still pending requests " << "on port " << port;

-

-// Generates a nonfatal failure with a generic message.

-#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")

-

-// Generates a fatal failure with a generic message.

-#define FAIL() GTEST_FATAL_FAILURE_("Failed")

-

-// Generates a success with a generic message.

-#define SUCCEED() GTEST_SUCCESS_("Succeeded")

-

-// Macros for testing exceptions.

-//

-//    * {ASSERT|EXPECT}_THROW(statement, expected_exception):

-//         Tests that the statement throws the expected exception.

-//    * {ASSERT|EXPECT}_NO_THROW(statement):

-//         Tests that the statement doesn't throw any exception.

-//    * {ASSERT|EXPECT}_ANY_THROW(statement):

-//         Tests that the statement throws an exception.

-

-#define EXPECT_THROW(statement, expected_exception) \

-  GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)

-#define EXPECT_NO_THROW(statement) \

-  GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)

-#define EXPECT_ANY_THROW(statement) \

-  GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)

-#define ASSERT_THROW(statement, expected_exception) \

-  GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)

-#define ASSERT_NO_THROW(statement) \

-  GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)

-#define ASSERT_ANY_THROW(statement) \

-  GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)

-

-// Boolean assertions.

-#define EXPECT_TRUE(condition) \

-  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \

-                      GTEST_NONFATAL_FAILURE_)

-#define EXPECT_FALSE(condition) \

-  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \

-                      GTEST_NONFATAL_FAILURE_)

-#define ASSERT_TRUE(condition) \

-  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \

-                      GTEST_FATAL_FAILURE_)

-#define ASSERT_FALSE(condition) \

-  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \

-                      GTEST_FATAL_FAILURE_)

-

-// Includes the auto-generated header that implements a family of

-// generic predicate assertion macros.

-#include <gtest/gtest_pred_impl.h>

-

-// Macros for testing equalities and inequalities.

-//

-//    * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual

-//    * {ASSERT|EXPECT}_NE(v1, v2):           Tests that v1 != v2

-//    * {ASSERT|EXPECT}_LT(v1, v2):           Tests that v1 < v2

-//    * {ASSERT|EXPECT}_LE(v1, v2):           Tests that v1 <= v2

-//    * {ASSERT|EXPECT}_GT(v1, v2):           Tests that v1 > v2

-//    * {ASSERT|EXPECT}_GE(v1, v2):           Tests that v1 >= v2

-//

-// When they are not, Google Test prints both the tested expressions and

-// their actual values.  The values must be compatible built-in types,

-// or you will get a compiler error.  By "compatible" we mean that the

-// values can be compared by the respective operator.

-//

-// Note:

-//

-//   1. It is possible to make a user-defined type work with

-//   {ASSERT|EXPECT}_??(), but that requires overloading the

-//   comparison operators and is thus discouraged by the Google C++

-//   Usage Guide.  Therefore, you are advised to use the

-//   {ASSERT|EXPECT}_TRUE() macro to assert that two objects are

-//   equal.

-//

-//   2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on

-//   pointers (in particular, C strings).  Therefore, if you use it

-//   with two C strings, you are testing how their locations in memory

-//   are related, not how their content is related.  To compare two C

-//   strings by content, use {ASSERT|EXPECT}_STR*().

-//

-//   3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to

-//   {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you

-//   what the actual value is when it fails, and similarly for the

-//   other comparisons.

-//

-//   4. Do not depend on the order in which {ASSERT|EXPECT}_??()

-//   evaluate their arguments, which is undefined.

-//

-//   5. These macros evaluate their arguments exactly once.

-//

-// Examples:

-//

-//   EXPECT_NE(5, Foo());

-//   EXPECT_EQ(NULL, a_pointer);

-//   ASSERT_LT(i, array_size);

-//   ASSERT_GT(records.size(), 0) << "There is no record left.";

-

-#define EXPECT_EQ(expected, actual) \

-  EXPECT_PRED_FORMAT2(::testing::internal:: \

-                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \

-                      expected, actual)

-#define EXPECT_NE(expected, actual) \

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)

-#define EXPECT_LE(val1, val2) \

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)

-#define EXPECT_LT(val1, val2) \

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)

-#define EXPECT_GE(val1, val2) \

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)

-#define EXPECT_GT(val1, val2) \

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)

-

-#define ASSERT_EQ(expected, actual) \

-  ASSERT_PRED_FORMAT2(::testing::internal:: \

-                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \

-                      expected, actual)

-#define ASSERT_NE(val1, val2) \

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)

-#define ASSERT_LE(val1, val2) \

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)

-#define ASSERT_LT(val1, val2) \

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)

-#define ASSERT_GE(val1, val2) \

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)

-#define ASSERT_GT(val1, val2) \

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)

-

-// C String Comparisons.  All tests treat NULL and any non-NULL string

-// as different.  Two NULLs are equal.

-//

-//    * {ASSERT|EXPECT}_STREQ(s1, s2):     Tests that s1 == s2

-//    * {ASSERT|EXPECT}_STRNE(s1, s2):     Tests that s1 != s2

-//    * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case

-//    * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case

-//

-// For wide or narrow string objects, you can use the

-// {ASSERT|EXPECT}_??() macros.

-//

-// Don't depend on the order in which the arguments are evaluated,

-// which is undefined.

-//

-// These macros evaluate their arguments exactly once.

-

-#define EXPECT_STREQ(expected, actual) \

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)

-#define EXPECT_STRNE(s1, s2) \

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)

-#define EXPECT_STRCASEEQ(expected, actual) \

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)

-#define EXPECT_STRCASENE(s1, s2)\

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)

-

-#define ASSERT_STREQ(expected, actual) \

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)

-#define ASSERT_STRNE(s1, s2) \

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)

-#define ASSERT_STRCASEEQ(expected, actual) \

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)

-#define ASSERT_STRCASENE(s1, s2)\

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)

-

-// Macros for comparing floating-point numbers.

-//

-//    * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):

-//         Tests that two float values are almost equal.

-//    * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):

-//         Tests that two double values are almost equal.

-//    * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):

-//         Tests that v1 and v2 are within the given distance to each other.

-//

-// Google Test uses ULP-based comparison to automatically pick a default

-// error bound that is appropriate for the operands.  See the

-// FloatingPoint template class in gtest-internal.h if you are

-// interested in the implementation details.

-

-#define EXPECT_FLOAT_EQ(expected, actual)\

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \

-                      expected, actual)

-

-#define EXPECT_DOUBLE_EQ(expected, actual)\

-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \

-                      expected, actual)

-

-#define ASSERT_FLOAT_EQ(expected, actual)\

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \

-                      expected, actual)

-

-#define ASSERT_DOUBLE_EQ(expected, actual)\

-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \

-                      expected, actual)

-

-#define EXPECT_NEAR(val1, val2, abs_error)\

-  EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \

-                      val1, val2, abs_error)

-

-#define ASSERT_NEAR(val1, val2, abs_error)\

-  ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \

-                      val1, val2, abs_error)

-

-// These predicate format functions work on floating-point values, and

-// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.

-//

-//   EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);

-

-// Asserts that val1 is less than, or almost equal to, val2.  Fails

-// otherwise.  In particular, it fails if either val1 or val2 is NaN.

-AssertionResult FloatLE(const char* expr1, const char* expr2,

-                        float val1, float val2);

-AssertionResult DoubleLE(const char* expr1, const char* expr2,

-                         double val1, double val2);

-

-

-#if GTEST_OS_WINDOWS

-

-// Macros that test for HRESULT failure and success, these are only useful

-// on Windows, and rely on Windows SDK macros and APIs to compile.

-//

-//    * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)

-//

-// When expr unexpectedly fails or succeeds, Google Test prints the

-// expected result and the actual result with both a human-readable

-// string representation of the error, if available, as well as the

-// hex result code.

-#define EXPECT_HRESULT_SUCCEEDED(expr) \

-    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))

-

-#define ASSERT_HRESULT_SUCCEEDED(expr) \

-    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))

-

-#define EXPECT_HRESULT_FAILED(expr) \

-    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))

-

-#define ASSERT_HRESULT_FAILED(expr) \

-    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))

-

-#endif  // GTEST_OS_WINDOWS

-

-// Macros that execute statement and check that it doesn't generate new fatal

-// failures in the current thread.

-//

-//   * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);

-//

-// Examples:

-//

-//   EXPECT_NO_FATAL_FAILURE(Process());

-//   ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";

-//

-#define ASSERT_NO_FATAL_FAILURE(statement) \

-    GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)

-#define EXPECT_NO_FATAL_FAILURE(statement) \

-    GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)

-

-// Causes a trace (including the source file path, the current line

-// number, and the given message) to be included in every test failure

-// message generated by code in the current scope.  The effect is

-// undone when the control leaves the current scope.

-//

-// The message argument can be anything streamable to std::ostream.

-//

-// In the implementation, we include the current line number as part

-// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s

-// to appear in the same block - as long as they are on different

-// lines.

-#define SCOPED_TRACE(message) \

-  ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\

-    __FILE__, __LINE__, ::testing::Message() << (message))

-

-namespace internal {

-

-// This template is declared, but intentionally undefined.

-template <typename T1, typename T2>

-struct StaticAssertTypeEqHelper;

-

-template <typename T>

-struct StaticAssertTypeEqHelper<T, T> {};

-

-}  // namespace internal

-

-// Compile-time assertion for type equality.

-// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are

-// the same type.  The value it returns is not interesting.

-//

-// Instead of making StaticAssertTypeEq a class template, we make it a

-// function template that invokes a helper class template.  This

-// prevents a user from misusing StaticAssertTypeEq<T1, T2> by

-// defining objects of that type.

-//

-// CAVEAT:

-//

-// When used inside a method of a class template,

-// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is

-// instantiated.  For example, given:

-//

-//   template <typename T> class Foo {

-//    public:

-//     void Bar() { testing::StaticAssertTypeEq<int, T>(); }

-//   };

-//

-// the code:

-//

-//   void Test1() { Foo<bool> foo; }

-//

-// will NOT generate a compiler error, as Foo<bool>::Bar() is never

-// actually instantiated.  Instead, you need:

-//

-//   void Test2() { Foo<bool> foo; foo.Bar(); }

-//

-// to cause a compiler error.

-template <typename T1, typename T2>

-bool StaticAssertTypeEq() {

-  internal::StaticAssertTypeEqHelper<T1, T2>();

-  return true;

-}

-

-// Defines a test.

-//

-// The first parameter is the name of the test case, and the second

-// parameter is the name of the test within the test case.

-//

-// The convention is to end the test case name with "Test".  For

-// example, a test case for the Foo class can be named FooTest.

-//

-// The user should put his test code between braces after using this

-// macro.  Example:

-//

-//   TEST(FooTest, InitializesCorrectly) {

-//     Foo foo;

-//     EXPECT_TRUE(foo.StatusIsOK());

-//   }

-

-// Note that we call GetTestTypeId() instead of GetTypeId<

-// ::testing::Test>() here to get the type ID of testing::Test.  This

-// is to work around a suspected linker bug when using Google Test as

-// a framework on Mac OS X.  The bug causes GetTypeId<

-// ::testing::Test>() to return different values depending on whether

-// the call is from the Google Test framework itself or from user test

-// code.  GetTestTypeId() is guaranteed to always return the same

-// value, as it always calls GetTypeId<>() from the Google Test

-// framework.

-#define TEST(test_case_name, test_name)\

-  GTEST_TEST_(test_case_name, test_name, \

-              ::testing::Test, ::testing::internal::GetTestTypeId())

-

-

-// Defines a test that uses a test fixture.

-//

-// The first parameter is the name of the test fixture class, which

-// also doubles as the test case name.  The second parameter is the

-// name of the test within the test case.

-//

-// A test fixture class must be declared earlier.  The user should put

-// his test code between braces after using this macro.  Example:

-//

-//   class FooTest : public testing::Test {

-//    protected:

-//     virtual void SetUp() { b_.AddElement(3); }

-//

-//     Foo a_;

-//     Foo b_;

-//   };

-//

-//   TEST_F(FooTest, InitializesCorrectly) {

-//     EXPECT_TRUE(a_.StatusIsOK());

-//   }

-//

-//   TEST_F(FooTest, ReturnsElementCountCorrectly) {

-//     EXPECT_EQ(0, a_.size());

-//     EXPECT_EQ(1, b_.size());

-//   }

-

-#define TEST_F(test_fixture, test_name)\

-  GTEST_TEST_(test_fixture, test_name, test_fixture, \

-              ::testing::internal::GetTypeId<test_fixture>())

-

-// Use this macro in main() to run all tests.  It returns 0 if all

-// tests are successful, or 1 otherwise.

-//

-// RUN_ALL_TESTS() should be invoked after the command line has been

-// parsed by InitGoogleTest().

-

-#define RUN_ALL_TESTS()\

-  (::testing::UnitTest::GetInstance()->Run())

-

-}  // namespace testing

-

-#endif  // GTEST_INCLUDE_GTEST_GTEST_H_

+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for Google Test.  It should be
+// included by any test program that uses Google Test.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+//   // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE.  Therefore DO NOT DEPEND ON IT in a user
+// program!
+//
+// Acknowledgment: Google Test borrowed the idea of automatic test
+// registration from Barthelemy Dagenais' (barthelemy@prologique.com)
+// easyUnit framework.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_H_
+
+// The following platform macro is used throughout Google Test:
+//   _WIN32_WCE      Windows CE     (set in project files)
+
+#include <limits>
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-string.h>
+#include <gtest/gtest-death-test.h>
+#include <gtest/gtest-message.h>
+#include <gtest/gtest-param-test.h>
+#include <gtest/gtest_prod.h>
+#include <gtest/gtest-test-part.h>
+#include <gtest/gtest-typed-test.h>
+
+// Depending on the platform, different string classes are available.
+// On Windows, ::std::string compiles only when exceptions are
+// enabled.  On Linux, in addition to ::std::string, Google also makes
+// use of class ::string, which has the same interface as
+// ::std::string, but has a different implementation.
+//
+// The user can tell us whether ::std::string is available in his
+// environment by defining the macro GTEST_HAS_STD_STRING to either 1
+// or 0 on the compiler command line.  He can also define
+// GTEST_HAS_GLOBAL_STRING to 1 to indicate that ::string is available
+// AND is a distinct type to ::std::string, or define it to 0 to
+// indicate otherwise.
+//
+// If the user's ::std::string and ::string are the same class due to
+// aliasing, he should define GTEST_HAS_STD_STRING to 1 and
+// GTEST_HAS_GLOBAL_STRING to 0.
+//
+// If the user doesn't define GTEST_HAS_STD_STRING and/or
+// GTEST_HAS_GLOBAL_STRING, they are defined heuristically.
+
+namespace testing {
+
+// Declares the flags.
+
+// This flag temporary enables the disabled tests.
+GTEST_DECLARE_bool_(also_run_disabled_tests);
+
+// This flag brings the debugger on an assertion failure.
+GTEST_DECLARE_bool_(break_on_failure);
+
+// This flag controls whether Google Test catches all test-thrown exceptions
+// and logs them as failures.
+GTEST_DECLARE_bool_(catch_exceptions);
+
+// This flag enables using colors in terminal output. Available values are
+// "yes" to enable colors, "no" (disable colors), or "auto" (the default)
+// to let Google Test decide.
+GTEST_DECLARE_string_(color);
+
+// This flag sets up the filter to select by name using a glob pattern
+// the tests to run. If the filter is not given all tests are executed.
+GTEST_DECLARE_string_(filter);
+
+// This flag causes the Google Test to list tests. None of the tests listed
+// are actually run if the flag is provided.
+GTEST_DECLARE_bool_(list_tests);
+
+// This flag controls whether Google Test emits a detailed XML report to a file
+// in addition to its normal textual output.
+GTEST_DECLARE_string_(output);
+
+// This flags control whether Google Test prints the elapsed time for each
+// test.
+GTEST_DECLARE_bool_(print_time);
+
+// This flag sets how many times the tests are repeated. The default value
+// is 1. If the value is -1 the tests are repeating forever.
+GTEST_DECLARE_int32_(repeat);
+
+// This flag controls whether Google Test includes Google Test internal
+// stack frames in failure stack traces.
+GTEST_DECLARE_bool_(show_internal_stack_frames);
+
+// This flag specifies the maximum number of stack frames to be
+// printed in a failure message.
+GTEST_DECLARE_int32_(stack_trace_depth);
+
+// When this flag is specified, a failed assertion will throw an
+// exception if exceptions are enabled, or exit the program with a
+// non-zero code otherwise.
+GTEST_DECLARE_bool_(throw_on_failure);
+
+// The upper limit for valid stack trace depths.
+const int kMaxStackTraceDepth = 100;
+
+namespace internal {
+
+class GTestFlagSaver;
+
+// Converts a streamable value to a String.  A NULL pointer is
+// converted to "(null)".  When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+// Declared in gtest-internal.h but defined here, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable) {
+  return (Message() << streamable).GetString();
+}
+
+}  // namespace internal
+
+// A class for indicating whether an assertion was successful.  When
+// the assertion wasn't successful, the AssertionResult object
+// remembers a non-empty message that described how it failed.
+//
+// This class is useful for defining predicate-format functions to be
+// used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
+//
+// The constructor of AssertionResult is private.  To create an
+// instance of this class, use one of the factory functions
+// (AssertionSuccess() and AssertionFailure()).
+//
+// For example, in order to be able to write:
+//
+//   // Verifies that Foo() returns an even number.
+//   EXPECT_PRED_FORMAT1(IsEven, Foo());
+//
+// you just need to define:
+//
+//   testing::AssertionResult IsEven(const char* expr, int n) {
+//     if ((n % 2) == 0) return testing::AssertionSuccess();
+//
+//     Message msg;
+//     msg << "Expected: " << expr << " is even\n"
+//         << "  Actual: it's " << n;
+//     return testing::AssertionFailure(msg);
+//   }
+//
+// If Foo() returns 5, you will see the following message:
+//
+//   Expected: Foo() is even
+//     Actual: it's 5
+class AssertionResult {
+ public:
+  // Declares factory functions for making successful and failed
+  // assertion results as friends.
+  friend AssertionResult AssertionSuccess();
+  friend AssertionResult AssertionFailure(const Message&);
+
+  // Returns true iff the assertion succeeded.
+  operator bool() const { return failure_message_.c_str() == NULL; }  // NOLINT
+
+  // Returns the assertion's failure message.
+  const char* failure_message() const { return failure_message_.c_str(); }
+
+ private:
+  // The default constructor.  It is used when the assertion succeeded.
+  AssertionResult() {}
+
+  // The constructor used when the assertion failed.
+  explicit AssertionResult(const internal::String& failure_message);
+
+  // Stores the assertion's failure message.
+  internal::String failure_message_;
+};
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess();
+
+// Makes a failed assertion result with the given failure message.
+AssertionResult AssertionFailure(const Message& msg);
+
+// The abstract class that all tests inherit from.
+//
+// In Google Test, a unit test program contains one or many TestCases, and
+// each TestCase contains one or many Tests.
+//
+// When you define a test using the TEST macro, you don't need to
+// explicitly derive from Test - the TEST macro automatically does
+// this for you.
+//
+// The only time you derive from Test is when defining a test fixture
+// to be used a TEST_F.  For example:
+//
+//   class FooTest : public testing::Test {
+//    protected:
+//     virtual void SetUp() { ... }
+//     virtual void TearDown() { ... }
+//     ...
+//   };
+//
+//   TEST_F(FooTest, Bar) { ... }
+//   TEST_F(FooTest, Baz) { ... }
+//
+// Test is not copyable.
+class Test {
+ public:
+  friend class internal::TestInfoImpl;
+
+  // Defines types for pointers to functions that set up and tear down
+  // a test case.
+  typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
+  typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;
+
+  // The d'tor is virtual as we intend to inherit from Test.
+  virtual ~Test();
+
+  // Sets up the stuff shared by all tests in this test case.
+  //
+  // Google Test will call Foo::SetUpTestCase() before running the first
+  // test in test case Foo.  Hence a sub-class can define its own
+  // SetUpTestCase() method to shadow the one defined in the super
+  // class.
+  static void SetUpTestCase() {}
+
+  // Tears down the stuff shared by all tests in this test case.
+  //
+  // Google Test will call Foo::TearDownTestCase() after running the last
+  // test in test case Foo.  Hence a sub-class can define its own
+  // TearDownTestCase() method to shadow the one defined in the super
+  // class.
+  static void TearDownTestCase() {}
+
+  // Returns true iff the current test has a fatal failure.
+  static bool HasFatalFailure();
+
+  // Returns true iff the current test has a non-fatal failure.
+  static bool HasNonfatalFailure();
+
+  // Returns true iff the current test has a (either fatal or
+  // non-fatal) failure.
+  static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
+
+  // Logs a property for the current test.  Only the last value for a given
+  // key is remembered.
+  // These are public static so they can be called from utility functions
+  // that are not members of the test fixture.
+  // The arguments are const char* instead strings, as Google Test is used
+  // on platforms where string doesn't compile.
+  //
+  // Note that a driving consideration for these RecordProperty methods
+  // was to produce xml output suited to the Greenspan charting utility,
+  // which at present will only chart values that fit in a 32-bit int. It
+  // is the user's responsibility to restrict their values to 32-bit ints
+  // if they intend them to be used with Greenspan.
+  static void RecordProperty(const char* key, const char* value);
+  static void RecordProperty(const char* key, int value);
+
+ protected:
+  // Creates a Test object.
+  Test();
+
+  // Sets up the test fixture.
+  virtual void SetUp();
+
+  // Tears down the test fixture.
+  virtual void TearDown();
+
+ private:
+  // Returns true iff the current test has the same fixture class as
+  // the first test in the current test case.
+  static bool HasSameFixtureClass();
+
+  // Runs the test after the test fixture has been set up.
+  //
+  // A sub-class must implement this to define the test logic.
+  //
+  // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
+  // Instead, use the TEST or TEST_F macro.
+  virtual void TestBody() = 0;
+
+  // Sets up, executes, and tears down the test.
+  void Run();
+
+  // Uses a GTestFlagSaver to save and restore all Google Test flags.
+  const internal::GTestFlagSaver* const gtest_flag_saver_;
+
+  // Often a user mis-spells SetUp() as Setup() and spends a long time
+  // wondering why it is never called by Google Test.  The declaration of
+  // the following method is solely for catching such an error at
+  // compile time:
+  //
+  //   - The return type is deliberately chosen to be not void, so it
+  //   will be a conflict if a user declares void Setup() in his test
+  //   fixture.
+  //
+  //   - This method is private, so it will be another compiler error
+  //   if a user calls it from his test fixture.
+  //
+  // DO NOT OVERRIDE THIS FUNCTION.
+  //
+  // If you see an error about overriding the following function or
+  // about it being private, you have mis-spelled SetUp() as Setup().
+  struct Setup_should_be_spelled_SetUp {};
+  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+
+  // We disallow copying Tests.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
+};
+
+
+// A TestInfo object stores the following information about a test:
+//
+//   Test case name
+//   Test name
+//   Whether the test should be run
+//   A function pointer that creates the test object when invoked
+//   Test result
+//
+// The constructor of TestInfo registers itself with the UnitTest
+// singleton such that the RUN_ALL_TESTS() macro knows which tests to
+// run.
+class TestInfo {
+ public:
+  // Destructs a TestInfo object.  This function is not virtual, so
+  // don't inherit from TestInfo.
+  ~TestInfo();
+
+  // Returns the test case name.
+  const char* test_case_name() const;
+
+  // Returns the test name.
+  const char* name() const;
+
+  // Returns the test case comment.
+  const char* test_case_comment() const;
+
+  // Returns the test comment.
+  const char* comment() const;
+
+  // Returns true if this test matches the user-specified filter.
+  bool matches_filter() const;
+
+  // Returns true if this test should run, that is if the test is not disabled
+  // (or it is disabled but the also_run_disabled_tests flag has been specified)
+  // and its full name matches the user-specified filter.
+  //
+  // Google Test allows the user to filter the tests by their full names.
+  // The full name of a test Bar in test case Foo is defined as
+  // "Foo.Bar".  Only the tests that match the filter will run.
+  //
+  // A filter is a colon-separated list of glob (not regex) patterns,
+  // optionally followed by a '-' and a colon-separated list of
+  // negative patterns (tests to exclude).  A test is run if it
+  // matches one of the positive patterns and does not match any of
+  // the negative patterns.
+  //
+  // For example, *A*:Foo.* is a filter that matches any string that
+  // contains the character 'A' or starts with "Foo.".
+  bool should_run() const;
+
+  // Returns the result of the test.
+  const internal::TestResult* result() const;
+ private:
+#if GTEST_HAS_DEATH_TEST
+  friend class internal::DefaultDeathTestFactory;
+#endif  // GTEST_HAS_DEATH_TEST
+  friend class internal::TestInfoImpl;
+  friend class internal::UnitTestImpl;
+  friend class Test;
+  friend class TestCase;
+  friend TestInfo* internal::MakeAndRegisterTestInfo(
+      const char* test_case_name, const char* name,
+      const char* test_case_comment, const char* comment,
+      internal::TypeId fixture_class_id,
+      Test::SetUpTestCaseFunc set_up_tc,
+      Test::TearDownTestCaseFunc tear_down_tc,
+      internal::TestFactoryBase* factory);
+
+  // Increments the number of death tests encountered in this test so
+  // far.
+  int increment_death_test_count();
+
+  // Accessors for the implementation object.
+  internal::TestInfoImpl* impl() { return impl_; }
+  const internal::TestInfoImpl* impl() const { return impl_; }
+
+  // Constructs a TestInfo object. The newly constructed instance assumes
+  // ownership of the factory object.
+  TestInfo(const char* test_case_name, const char* name,
+           const char* test_case_comment, const char* comment,
+           internal::TypeId fixture_class_id,
+           internal::TestFactoryBase* factory);
+
+  // An opaque implementation object.
+  internal::TestInfoImpl* impl_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
+};
+
+// An Environment object is capable of setting up and tearing down an
+// environment.  The user should subclass this to define his own
+// environment(s).
+//
+// An Environment object does the set-up and tear-down in virtual
+// methods SetUp() and TearDown() instead of the constructor and the
+// destructor, as:
+//
+//   1. You cannot safely throw from a destructor.  This is a problem
+//      as in some cases Google Test is used where exceptions are enabled, and
+//      we may want to implement ASSERT_* using exceptions where they are
+//      available.
+//   2. You cannot use ASSERT_* directly in a constructor or
+//      destructor.
+class Environment {
+ public:
+  // The d'tor is virtual as we need to subclass Environment.
+  virtual ~Environment() {}
+
+  // Override this to define how to set up the environment.
+  virtual void SetUp() {}
+
+  // Override this to define how to tear down the environment.
+  virtual void TearDown() {}
+ private:
+  // If you see an error about overriding the following function or
+  // about it being private, you have mis-spelled SetUp() as Setup().
+  struct Setup_should_be_spelled_SetUp {};
+  virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+};
+
+// A UnitTest consists of a list of TestCases.
+//
+// This is a singleton class.  The only instance of UnitTest is
+// created when UnitTest::GetInstance() is first called.  This
+// instance is never deleted.
+//
+// UnitTest is not copyable.
+//
+// This class is thread-safe as long as the methods are called
+// according to their specification.
+class UnitTest {
+ public:
+  // Gets the singleton UnitTest object.  The first time this method
+  // is called, a UnitTest object is constructed and returned.
+  // Consecutive calls will return the same object.
+  static UnitTest* GetInstance();
+
+  // Registers and returns a global test environment.  When a test
+  // program is run, all global test environments will be set-up in
+  // the order they were registered.  After all tests in the program
+  // have finished, all global test environments will be torn-down in
+  // the *reverse* order they were registered.
+  //
+  // The UnitTest object takes ownership of the given environment.
+  //
+  // This method can only be called from the main thread.
+  Environment* AddEnvironment(Environment* env);
+
+  // Adds a TestPartResult to the current TestResult object.  All
+  // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
+  // eventually call this to report their results.  The user code
+  // should use the assertion macros instead of calling this directly.
+  //
+  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+  void AddTestPartResult(TestPartResultType result_type,
+                         const char* file_name,
+                         int line_number,
+                         const internal::String& message,
+                         const internal::String& os_stack_trace);
+
+  // Adds a TestProperty to the current TestResult object. If the result already
+  // contains a property with the same key, the value will be updated.
+  void RecordPropertyForCurrentTest(const char* key, const char* value);
+
+  // Runs all tests in this UnitTest object and prints the result.
+  // Returns 0 if successful, or 1 otherwise.
+  //
+  // This method can only be called from the main thread.
+  //
+  // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+  int Run() GTEST_MUST_USE_RESULT_;
+
+  // Returns the working directory when the first TEST() or TEST_F()
+  // was executed.  The UnitTest object owns the string.
+  const char* original_working_dir() const;
+
+  // Returns the TestCase object for the test that's currently running,
+  // or NULL if no test is running.
+  const TestCase* current_test_case() const;
+
+  // Returns the TestInfo object for the test that's currently running,
+  // or NULL if no test is running.
+  const TestInfo* current_test_info() const;
+
+#if GTEST_HAS_PARAM_TEST
+  // Returns the ParameterizedTestCaseRegistry object used to keep track of
+  // value-parameterized tests and instantiate and register them.
+  internal::ParameterizedTestCaseRegistry& parameterized_test_registry();
+#endif  // GTEST_HAS_PARAM_TEST
+
+  // Accessors for the implementation object.
+  internal::UnitTestImpl* impl() { return impl_; }
+  const internal::UnitTestImpl* impl() const { return impl_; }
+ private:
+  // ScopedTrace is a friend as it needs to modify the per-thread
+  // trace stack, which is a private member of UnitTest.
+  friend class internal::ScopedTrace;
+
+  // Creates an empty UnitTest.
+  UnitTest();
+
+  // D'tor
+  virtual ~UnitTest();
+
+  // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+  // Google Test trace stack.
+  void PushGTestTrace(const internal::TraceInfo& trace);
+
+  // Pops a trace from the per-thread Google Test trace stack.
+  void PopGTestTrace();
+
+  // Protects mutable state in *impl_.  This is mutable as some const
+  // methods need to lock it too.
+  mutable internal::Mutex mutex_;
+
+  // Opaque implementation object.  This field is never changed once
+  // the object is constructed.  We don't mark it as const here, as
+  // doing so will cause a warning in the constructor of UnitTest.
+  // Mutable state in *impl_ is protected by mutex_.
+  internal::UnitTestImpl* impl_;
+
+  // We disallow copying UnitTest.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);
+};
+
+// A convenient wrapper for adding an environment for the test
+// program.
+//
+// You should call this before RUN_ALL_TESTS() is called, probably in
+// main().  If you use gtest_main, you need to call this before main()
+// starts for it to take effect.  For example, you can define a global
+// variable like this:
+//
+//   testing::Environment* const foo_env =
+//       testing::AddGlobalTestEnvironment(new FooEnvironment);
+//
+// However, we strongly recommend you to write your own main() and
+// call AddGlobalTestEnvironment() there, as relying on initialization
+// of global variables makes the code harder to read and may cause
+// problems when you register multiple environments from different
+// translation units and the environments have dependencies among them
+// (remember that the compiler doesn't guarantee the order in which
+// global variables from different translation units are initialized).
+inline Environment* AddGlobalTestEnvironment(Environment* env) {
+  return UnitTest::GetInstance()->AddEnvironment(env);
+}
+
+// Initializes Google Test.  This must be called before calling
+// RUN_ALL_TESTS().  In particular, it parses a command line for the
+// flags that Google Test recognizes.  Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned.  Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+void InitGoogleTest(int* argc, char** argv);
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv);
+
+namespace internal {
+
+// These overloaded versions handle ::std::string and ::std::wstring.
+#if GTEST_HAS_STD_STRING
+inline String FormatForFailureMessage(const ::std::string& str) {
+  return (Message() << '"' << str << '"').GetString();
+}
+#endif  // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_STD_WSTRING
+inline String FormatForFailureMessage(const ::std::wstring& wstr) {
+  return (Message() << "L\"" << wstr << '"').GetString();
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+// These overloaded versions handle ::string and ::wstring.
+#if GTEST_HAS_GLOBAL_STRING
+inline String FormatForFailureMessage(const ::string& str) {
+  return (Message() << '"' << str << '"').GetString();
+}
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+inline String FormatForFailureMessage(const ::wstring& wstr) {
+  return (Message() << "L\"" << wstr << '"').GetString();
+}
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message.  The type (but not value)
+// of the other operand may affect the format.  This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char*, and print it as a C string when it is compared against an
+// std::string object, for example.
+//
+// The default implementation ignores the type of the other operand.
+// Some specialized versions are used to handle formatting wide or
+// narrow C strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+String FormatForComparisonFailureMessage(const T1& value,
+                                         const T2& /* other_operand */) {
+  return FormatForFailureMessage(value);
+}
+
+// The helper function for {ASSERT|EXPECT}_EQ.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQ(const char* expected_expression,
+                            const char* actual_expression,
+                            const T1& expected,
+                            const T2& actual) {
+#ifdef _MSC_VER
+#pragma warning(push)          // Saves the current warning state.
+#pragma warning(disable:4389)  // Temporarily disables warning on
+                               // signed/unsigned mismatch.
+#endif
+
+  if (expected == actual) {
+    return AssertionSuccess();
+  }
+
+#ifdef _MSC_VER
+#pragma warning(pop)          // Restores the warning state.
+#endif
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   FormatForComparisonFailureMessage(expected, actual),
+                   FormatForComparisonFailureMessage(actual, expected),
+                   false);
+}
+
+// With this overloaded version, we allow anonymous enums to be used
+// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
+// can be implicitly cast to BiggestInt.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+                            const char* actual_expression,
+                            BiggestInt expected,
+                            BiggestInt actual);
+
+// The helper class for {ASSERT|EXPECT}_EQ.  The template argument
+// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
+// is a null pointer literal.  The following default implementation is
+// for lhs_is_null_literal being false.
+template <bool lhs_is_null_literal>
+class EqHelper {
+ public:
+  // This templatized version is for the general case.
+  template <typename T1, typename T2>
+  static AssertionResult Compare(const char* expected_expression,
+                                 const char* actual_expression,
+                                 const T1& expected,
+                                 const T2& actual) {
+    return CmpHelperEQ(expected_expression, actual_expression, expected,
+                       actual);
+  }
+
+  // With this overloaded version, we allow anonymous enums to be used
+  // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
+  // enums can be implicitly cast to BiggestInt.
+  //
+  // Even though its body looks the same as the above version, we
+  // cannot merge the two, as it will make anonymous enums unhappy.
+  static AssertionResult Compare(const char* expected_expression,
+                                 const char* actual_expression,
+                                 BiggestInt expected,
+                                 BiggestInt actual) {
+    return CmpHelperEQ(expected_expression, actual_expression, expected,
+                       actual);
+  }
+};
+
+// This specialization is used when the first argument to ASSERT_EQ()
+// is a null pointer literal.
+template <>
+class EqHelper<true> {
+ public:
+  // We define two overloaded versions of Compare().  The first
+  // version will be picked when the second argument to ASSERT_EQ() is
+  // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
+  // EXPECT_EQ(false, a_bool).
+  template <typename T1, typename T2>
+  static AssertionResult Compare(const char* expected_expression,
+                                 const char* actual_expression,
+                                 const T1& expected,
+                                 const T2& actual) {
+    return CmpHelperEQ(expected_expression, actual_expression, expected,
+                       actual);
+  }
+
+  // This version will be picked when the second argument to
+  // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer).
+  template <typename T1, typename T2>
+  static AssertionResult Compare(const char* expected_expression,
+                                 const char* actual_expression,
+                                 const T1& /* expected */,
+                                 T2* actual) {
+    // We already know that 'expected' is a null pointer.
+    return CmpHelperEQ(expected_expression, actual_expression,
+                       static_cast<T2*>(NULL), actual);
+  }
+};
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_??.  It is here just to avoid copy-and-paste
+// of similar code.
+//
+// For each templatized helper function, we also define an overloaded
+// version for BiggestInt in order to reduce code bloat and allow
+// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
+// with gcc 4.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+template <typename T1, typename T2>\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+                                   const T1& val1, const T2& val2) {\
+  if (val1 op val2) {\
+    return AssertionSuccess();\
+  } else {\
+    Message msg;\
+    msg << "Expected: (" << expr1 << ") " #op " (" << expr2\
+        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+        << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+    return AssertionFailure(msg);\
+  }\
+}\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+                                   BiggestInt val1, BiggestInt val2);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// Implements the helper function for {ASSERT|EXPECT}_NE
+GTEST_IMPL_CMP_HELPER_(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE
+GTEST_IMPL_CMP_HELPER_(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT
+GTEST_IMPL_CMP_HELPER_(LT, < )
+// Implements the helper function for {ASSERT|EXPECT}_GE
+GTEST_IMPL_CMP_HELPER_(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT
+GTEST_IMPL_CMP_HELPER_(GT, > )
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                               const char* actual_expression,
+                               const char* expected,
+                               const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+                                   const char* actual_expression,
+                                   const char* expected,
+                                   const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                               const char* s2_expression,
+                               const char* s1,
+                               const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+                                   const char* s2_expression,
+                                   const char* s1,
+                                   const char* s2);
+
+
+// Helper function for *_STREQ on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                               const char* actual_expression,
+                               const wchar_t* expected,
+                               const wchar_t* actual);
+
+// Helper function for *_STRNE on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                               const char* s2_expression,
+                               const wchar_t* s1,
+                               const wchar_t* s2);
+
+}  // namespace internal
+
+// IsSubstring() and IsNotSubstring() are intended to be used as the
+// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
+// themselves.  They check whether needle is a substring of haystack
+// (NULL is considered a substring of itself only), and return an
+// appropriate error message when they fail.
+//
+// The {needle,haystack}_expr arguments are the stringified
+// expressions that generated the two real arguments.
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack);
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack);
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack);
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack);
+#if GTEST_HAS_STD_STRING
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack);
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack);
+#endif  // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack);
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack);
+#endif  // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+// Helper template function for comparing floating-points.
+//
+// Template parameter:
+//
+//   RawType: the raw floating-point type (either float or double)
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename RawType>
+AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
+                                         const char* actual_expression,
+                                         RawType expected,
+                                         RawType actual) {
+  const FloatingPoint<RawType> lhs(expected), rhs(actual);
+
+  if (lhs.AlmostEquals(rhs)) {
+    return AssertionSuccess();
+  }
+
+  StrStream expected_ss;
+  expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+              << expected;
+
+  StrStream actual_ss;
+  actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+            << actual;
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   StrStreamToString(&expected_ss),
+                   StrStreamToString(&actual_ss),
+                   false);
+}
+
+// Helper function for implementing ASSERT_NEAR.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+                                     const char* expr2,
+                                     const char* abs_error_expr,
+                                     double val1,
+                                     double val2,
+                                     double abs_error);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// A class that enables one to stream messages to assertion macros
+class AssertHelper {
+ public:
+  // Constructor.
+  AssertHelper(TestPartResultType type, const char* file, int line,
+               const char* message);
+  // Message assignment is a semantic trick to enable assertion
+  // streaming; see the GTEST_MESSAGE_ macro below.
+  void operator=(const Message& message) const;
+ private:
+  TestPartResultType const type_;
+  const char*        const file_;
+  int                const line_;
+  String             const message_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
+};
+
+}  // namespace internal
+
+#if GTEST_HAS_PARAM_TEST
+// The abstract base class that all value-parameterized tests inherit from.
+//
+// This class adds support for accessing the test parameter value via
+// the GetParam() method.
+//
+// Use it with one of the parameter generator defining functions, like Range(),
+// Values(), ValuesIn(), Bool(), and Combine().
+//
+// class FooTest : public ::testing::TestWithParam<int> {
+//  protected:
+//   FooTest() {
+//     // Can use GetParam() here.
+//   }
+//   virtual ~FooTest() {
+//     // Can use GetParam() here.
+//   }
+//   virtual void SetUp() {
+//     // Can use GetParam() here.
+//   }
+//   virtual void TearDown {
+//     // Can use GetParam() here.
+//   }
+// };
+// TEST_P(FooTest, DoesBar) {
+//   // Can use GetParam() method here.
+//   Foo foo;
+//   ASSERT_TRUE(foo.DoesBar(GetParam()));
+// }
+// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
+
+template <typename T>
+class TestWithParam : public Test {
+ public:
+  typedef T ParamType;
+
+  // The current parameter value. Is also available in the test fixture's
+  // constructor.
+  const ParamType& GetParam() const { return *parameter_; }
+
+ private:
+  // Sets parameter value. The caller is responsible for making sure the value
+  // remains alive and unchanged throughout the current test.
+  static void SetParam(const ParamType* parameter) {
+    parameter_ = parameter;
+  }
+
+  // Static value used for accessing parameter during a test lifetime.
+  static const ParamType* parameter_;
+
+  // TestClass must be a subclass of TestWithParam<T>.
+  template <class TestClass> friend class internal::ParameterizedTestFactory;
+};
+
+template <typename T>
+const T* TestWithParam<T>::parameter_ = NULL;
+
+#endif  // GTEST_HAS_PARAM_TEST
+
+// Macros for indicating success/failure in test code.
+
+// ADD_FAILURE unconditionally adds a failure to the current test.
+// SUCCEED generates a success - it doesn't automatically make the
+// current test successful, as a test is only successful when it has
+// no failure.
+//
+// EXPECT_* verifies that a certain condition is satisfied.  If not,
+// it behaves like ADD_FAILURE.  In particular:
+//
+//   EXPECT_TRUE  verifies that a Boolean condition is true.
+//   EXPECT_FALSE verifies that a Boolean condition is false.
+//
+// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
+// that they will also abort the current function on failure.  People
+// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
+// writing data-driven tests often find themselves using ADD_FAILURE
+// and EXPECT_* more.
+//
+// Examples:
+//
+//   EXPECT_TRUE(server.StatusIsOK());
+//   ASSERT_FALSE(server.HasPendingRequest(port))
+//       << "There are still pending requests " << "on port " << port;
+
+// Generates a nonfatal failure with a generic message.
+#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
+
+// Generates a fatal failure with a generic message.
+#define FAIL() GTEST_FATAL_FAILURE_("Failed")
+
+// Generates a success with a generic message.
+#define SUCCEED() GTEST_SUCCESS_("Succeeded")
+
+// Macros for testing exceptions.
+//
+//    * {ASSERT|EXPECT}_THROW(statement, expected_exception):
+//         Tests that the statement throws the expected exception.
+//    * {ASSERT|EXPECT}_NO_THROW(statement):
+//         Tests that the statement doesn't throw any exception.
+//    * {ASSERT|EXPECT}_ANY_THROW(statement):
+//         Tests that the statement throws an exception.
+
+#define EXPECT_THROW(statement, expected_exception) \
+  GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_NO_THROW(statement) \
+  GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_ANY_THROW(statement) \
+  GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_THROW(statement, expected_exception) \
+  GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
+#define ASSERT_NO_THROW(statement) \
+  GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
+#define ASSERT_ANY_THROW(statement) \
+  GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
+
+// Boolean assertions.
+#define EXPECT_TRUE(condition) \
+  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+                      GTEST_NONFATAL_FAILURE_)
+#define EXPECT_FALSE(condition) \
+  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+                      GTEST_NONFATAL_FAILURE_)
+#define ASSERT_TRUE(condition) \
+  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+                      GTEST_FATAL_FAILURE_)
+#define ASSERT_FALSE(condition) \
+  GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+                      GTEST_FATAL_FAILURE_)
+
+// Includes the auto-generated header that implements a family of
+// generic predicate assertion macros.
+#include <gtest/gtest_pred_impl.h>
+
+// Macros for testing equalities and inequalities.
+//
+//    * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
+//    * {ASSERT|EXPECT}_NE(v1, v2):           Tests that v1 != v2
+//    * {ASSERT|EXPECT}_LT(v1, v2):           Tests that v1 < v2
+//    * {ASSERT|EXPECT}_LE(v1, v2):           Tests that v1 <= v2
+//    * {ASSERT|EXPECT}_GT(v1, v2):           Tests that v1 > v2
+//    * {ASSERT|EXPECT}_GE(v1, v2):           Tests that v1 >= v2
+//
+// When they are not, Google Test prints both the tested expressions and
+// their actual values.  The values must be compatible built-in types,
+// or you will get a compiler error.  By "compatible" we mean that the
+// values can be compared by the respective operator.
+//
+// Note:
+//
+//   1. It is possible to make a user-defined type work with
+//   {ASSERT|EXPECT}_??(), but that requires overloading the
+//   comparison operators and is thus discouraged by the Google C++
+//   Usage Guide.  Therefore, you are advised to use the
+//   {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
+//   equal.
+//
+//   2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
+//   pointers (in particular, C strings).  Therefore, if you use it
+//   with two C strings, you are testing how their locations in memory
+//   are related, not how their content is related.  To compare two C
+//   strings by content, use {ASSERT|EXPECT}_STR*().
+//
+//   3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
+//   {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
+//   what the actual value is when it fails, and similarly for the
+//   other comparisons.
+//
+//   4. Do not depend on the order in which {ASSERT|EXPECT}_??()
+//   evaluate their arguments, which is undefined.
+//
+//   5. These macros evaluate their arguments exactly once.
+//
+// Examples:
+//
+//   EXPECT_NE(5, Foo());
+//   EXPECT_EQ(NULL, a_pointer);
+//   ASSERT_LT(i, array_size);
+//   ASSERT_GT(records.size(), 0) << "There is no record left.";
+
+#define EXPECT_EQ(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal:: \
+                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+                      expected, actual)
+#define EXPECT_NE(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
+#define EXPECT_LE(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define EXPECT_LT(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define EXPECT_GE(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define EXPECT_GT(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+#define ASSERT_EQ(expected, actual) \
+  ASSERT_PRED_FORMAT2(::testing::internal:: \
+                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+                      expected, actual)
+#define ASSERT_NE(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#define ASSERT_LE(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define ASSERT_LT(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define ASSERT_GE(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define ASSERT_GT(val1, val2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+// C String Comparisons.  All tests treat NULL and any non-NULL string
+// as different.  Two NULLs are equal.
+//
+//    * {ASSERT|EXPECT}_STREQ(s1, s2):     Tests that s1 == s2
+//    * {ASSERT|EXPECT}_STRNE(s1, s2):     Tests that s1 != s2
+//    * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
+//    * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
+//
+// For wide or narrow string objects, you can use the
+// {ASSERT|EXPECT}_??() macros.
+//
+// Don't depend on the order in which the arguments are evaluated,
+// which is undefined.
+//
+// These macros evaluate their arguments exactly once.
+
+#define EXPECT_STREQ(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define EXPECT_STRNE(s1, s2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define EXPECT_STRCASEEQ(expected, actual) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define EXPECT_STRCASENE(s1, s2)\
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+#define ASSERT_STREQ(expected, actual) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define ASSERT_STRNE(s1, s2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define ASSERT_STRCASEEQ(expected, actual) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define ASSERT_STRCASENE(s1, s2)\
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+// Macros for comparing floating-point numbers.
+//
+//    * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
+//         Tests that two float values are almost equal.
+//    * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
+//         Tests that two double values are almost equal.
+//    * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
+//         Tests that v1 and v2 are within the given distance to each other.
+//
+// Google Test uses ULP-based comparison to automatically pick a default
+// error bound that is appropriate for the operands.  See the
+// FloatingPoint template class in gtest-internal.h if you are
+// interested in the implementation details.
+
+#define EXPECT_FLOAT_EQ(expected, actual)\
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+                      expected, actual)
+
+#define EXPECT_DOUBLE_EQ(expected, actual)\
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+                      expected, actual)
+
+#define ASSERT_FLOAT_EQ(expected, actual)\
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+                      expected, actual)
+
+#define ASSERT_DOUBLE_EQ(expected, actual)\
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+                      expected, actual)
+
+#define EXPECT_NEAR(val1, val2, abs_error)\
+  EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+                      val1, val2, abs_error)
+
+#define ASSERT_NEAR(val1, val2, abs_error)\
+  ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+                      val1, val2, abs_error)
+
+// These predicate format functions work on floating-point values, and
+// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
+//
+//   EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);
+
+// Asserts that val1 is less than, or almost equal to, val2.  Fails
+// otherwise.  In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+                        float val1, float val2);
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+                         double val1, double val2);
+
+
+#if GTEST_OS_WINDOWS
+
+// Macros that test for HRESULT failure and success, these are only useful
+// on Windows, and rely on Windows SDK macros and APIs to compile.
+//
+//    * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
+//
+// When expr unexpectedly fails or succeeds, Google Test prints the
+// expected result and the actual result with both a human-readable
+// string representation of the error, if available, as well as the
+// hex result code.
+#define EXPECT_HRESULT_SUCCEEDED(expr) \
+    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+#define ASSERT_HRESULT_SUCCEEDED(expr) \
+    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+#define EXPECT_HRESULT_FAILED(expr) \
+    EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#define ASSERT_HRESULT_FAILED(expr) \
+    ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#endif  // GTEST_OS_WINDOWS
+
+// Macros that execute statement and check that it doesn't generate new fatal
+// failures in the current thread.
+//
+//   * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);
+//
+// Examples:
+//
+//   EXPECT_NO_FATAL_FAILURE(Process());
+//   ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";
+//
+#define ASSERT_NO_FATAL_FAILURE(statement) \
+    GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)
+#define EXPECT_NO_FATAL_FAILURE(statement) \
+    GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
+
+// Causes a trace (including the source file path, the current line
+// number, and the given message) to be included in every test failure
+// message generated by code in the current scope.  The effect is
+// undone when the control leaves the current scope.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// In the implementation, we include the current line number as part
+// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
+// to appear in the same block - as long as they are on different
+// lines.
+#define SCOPED_TRACE(message) \
+  ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
+    __FILE__, __LINE__, ::testing::Message() << (message))
+
+namespace internal {
+
+// This template is declared, but intentionally undefined.
+template <typename T1, typename T2>
+struct StaticAssertTypeEqHelper;
+
+template <typename T>
+struct StaticAssertTypeEqHelper<T, T> {};
+
+}  // namespace internal
+
+// Compile-time assertion for type equality.
+// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
+// the same type.  The value it returns is not interesting.
+//
+// Instead of making StaticAssertTypeEq a class template, we make it a
+// function template that invokes a helper class template.  This
+// prevents a user from misusing StaticAssertTypeEq<T1, T2> by
+// defining objects of that type.
+//
+// CAVEAT:
+//
+// When used inside a method of a class template,
+// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is
+// instantiated.  For example, given:
+//
+//   template <typename T> class Foo {
+//    public:
+//     void Bar() { testing::StaticAssertTypeEq<int, T>(); }
+//   };
+//
+// the code:
+//
+//   void Test1() { Foo<bool> foo; }
+//
+// will NOT generate a compiler error, as Foo<bool>::Bar() is never
+// actually instantiated.  Instead, you need:
+//
+//   void Test2() { Foo<bool> foo; foo.Bar(); }
+//
+// to cause a compiler error.
+template <typename T1, typename T2>
+bool StaticAssertTypeEq() {
+  internal::StaticAssertTypeEqHelper<T1, T2>();
+  return true;
+}
+
+// Defines a test.
+//
+// The first parameter is the name of the test case, and the second
+// parameter is the name of the test within the test case.
+//
+// The convention is to end the test case name with "Test".  For
+// example, a test case for the Foo class can be named FooTest.
+//
+// The user should put his test code between braces after using this
+// macro.  Example:
+//
+//   TEST(FooTest, InitializesCorrectly) {
+//     Foo foo;
+//     EXPECT_TRUE(foo.StatusIsOK());
+//   }
+
+// Note that we call GetTestTypeId() instead of GetTypeId<
+// ::testing::Test>() here to get the type ID of testing::Test.  This
+// is to work around a suspected linker bug when using Google Test as
+// a framework on Mac OS X.  The bug causes GetTypeId<
+// ::testing::Test>() to return different values depending on whether
+// the call is from the Google Test framework itself or from user test
+// code.  GetTestTypeId() is guaranteed to always return the same
+// value, as it always calls GetTypeId<>() from the Google Test
+// framework.
+#define TEST(test_case_name, test_name)\
+  GTEST_TEST_(test_case_name, test_name, \
+              ::testing::Test, ::testing::internal::GetTestTypeId())
+
+
+// Defines a test that uses a test fixture.
+//
+// The first parameter is the name of the test fixture class, which
+// also doubles as the test case name.  The second parameter is the
+// name of the test within the test case.
+//
+// A test fixture class must be declared earlier.  The user should put
+// his test code between braces after using this macro.  Example:
+//
+//   class FooTest : public testing::Test {
+//    protected:
+//     virtual void SetUp() { b_.AddElement(3); }
+//
+//     Foo a_;
+//     Foo b_;
+//   };
+//
+//   TEST_F(FooTest, InitializesCorrectly) {
+//     EXPECT_TRUE(a_.StatusIsOK());
+//   }
+//
+//   TEST_F(FooTest, ReturnsElementCountCorrectly) {
+//     EXPECT_EQ(0, a_.size());
+//     EXPECT_EQ(1, b_.size());
+//   }
+
+#define TEST_F(test_fixture, test_name)\
+  GTEST_TEST_(test_fixture, test_name, test_fixture, \
+              ::testing::internal::GetTypeId<test_fixture>())
+
+// Use this macro in main() to run all tests.  It returns 0 if all
+// tests are successful, or 1 otherwise.
+//
+// RUN_ALL_TESTS() should be invoked after the command line has been
+// parsed by InitGoogleTest().
+
+#define RUN_ALL_TESTS()\
+  (::testing::UnitTest::GetInstance()->Run())
+
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_H_
diff --git a/third_party/gtest/include/gtest/gtest_pred_impl.h b/third_party/gtest/include/gtest/gtest_pred_impl.h
index 9c84729..e1e2f8c 100644
--- a/third_party/gtest/include/gtest/gtest_pred_impl.h
+++ b/third_party/gtest/include/gtest/gtest_pred_impl.h
@@ -1,368 +1,368 @@
-// Copyright 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-// This file is AUTOMATICALLY GENERATED on 10/02/2008 by command

-// 'gen_gtest_pred_impl.py 5'.  DO NOT EDIT BY HAND!

-//

-// Implements a family of generic predicate assertion macros.

-

-#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_

-#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_

-

-// Makes sure this header is not included before gtest.h.

-#ifndef GTEST_INCLUDE_GTEST_GTEST_H_

-#error Do not include gtest_pred_impl.h directly.  Include gtest.h instead.

-#endif  // GTEST_INCLUDE_GTEST_GTEST_H_

-

-// This header implements a family of generic predicate assertion

-// macros:

-//

-//   ASSERT_PRED_FORMAT1(pred_format, v1)

-//   ASSERT_PRED_FORMAT2(pred_format, v1, v2)

-//   ...

-//

-// where pred_format is a function or functor that takes n (in the

-// case of ASSERT_PRED_FORMATn) values and their source expression

-// text, and returns a testing::AssertionResult.  See the definition

-// of ASSERT_EQ in gtest.h for an example.

-//

-// If you don't care about formatting, you can use the more

-// restrictive version:

-//

-//   ASSERT_PRED1(pred, v1)

-//   ASSERT_PRED2(pred, v1, v2)

-//   ...

-//

-// where pred is an n-ary function or functor that returns bool,

-// and the values v1, v2, ..., must support the << operator for

-// streaming to std::ostream.

-//

-// We also define the EXPECT_* variations.

-//

-// For now we only support predicates whose arity is at most 5.

-// Please email googletestframework@googlegroups.com if you need

-// support for higher arities.

-

-// GTEST_ASSERT_ is the basic statement to which all of the assertions

-// in this file reduce.  Don't use this in your code.

-

-#define GTEST_ASSERT_(expression, on_failure) \

-  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \

-  if (const ::testing::AssertionResult gtest_ar = (expression)) \

-    ; \

-  else \

-    on_failure(gtest_ar.failure_message())

-

-

-// Helper function for implementing {EXPECT|ASSERT}_PRED1.  Don't use

-// this in your code.

-template <typename Pred,

-          typename T1>

-AssertionResult AssertPred1Helper(const char* pred_text,

-                                  const char* e1,

-                                  Pred pred,

-                                  const T1& v1) {

-  if (pred(v1)) return AssertionSuccess();

-

-  Message msg;

-  msg << pred_text << "("

-      << e1 << ") evaluates to false, where"

-      << "\n" << e1 << " evaluates to " << v1;

-  return AssertionFailure(msg);

-}

-

-// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.

-// Don't use this in your code.

-#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\

-  GTEST_ASSERT_(pred_format(#v1, v1),\

-                on_failure)

-

-// Internal macro for implementing {EXPECT|ASSERT}_PRED1.  Don't use

-// this in your code.

-#define GTEST_PRED1_(pred, v1, on_failure)\

-  GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \

-                                             #v1, \

-                                             pred, \

-                                             v1), on_failure)

-

-// Unary predicate assertion macros.

-#define EXPECT_PRED_FORMAT1(pred_format, v1) \

-  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)

-#define EXPECT_PRED1(pred, v1) \

-  GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)

-#define ASSERT_PRED_FORMAT1(pred_format, v1) \

-  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)

-#define ASSERT_PRED1(pred, v1) \

-  GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)

-

-

-

-// Helper function for implementing {EXPECT|ASSERT}_PRED2.  Don't use

-// this in your code.

-template <typename Pred,

-          typename T1,

-          typename T2>

-AssertionResult AssertPred2Helper(const char* pred_text,

-                                  const char* e1,

-                                  const char* e2,

-                                  Pred pred,

-                                  const T1& v1,

-                                  const T2& v2) {

-  if (pred(v1, v2)) return AssertionSuccess();

-

-  Message msg;

-  msg << pred_text << "("

-      << e1 << ", "

-      << e2 << ") evaluates to false, where"

-      << "\n" << e1 << " evaluates to " << v1

-      << "\n" << e2 << " evaluates to " << v2;

-  return AssertionFailure(msg);

-}

-

-// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.

-// Don't use this in your code.

-#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\

-  GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\

-                on_failure)

-

-// Internal macro for implementing {EXPECT|ASSERT}_PRED2.  Don't use

-// this in your code.

-#define GTEST_PRED2_(pred, v1, v2, on_failure)\

-  GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \

-                                             #v1, \

-                                             #v2, \

-                                             pred, \

-                                             v1, \

-                                             v2), on_failure)

-

-// Binary predicate assertion macros.

-#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \

-  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)

-#define EXPECT_PRED2(pred, v1, v2) \

-  GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)

-#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \

-  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)

-#define ASSERT_PRED2(pred, v1, v2) \

-  GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)

-

-

-

-// Helper function for implementing {EXPECT|ASSERT}_PRED3.  Don't use

-// this in your code.

-template <typename Pred,

-          typename T1,

-          typename T2,

-          typename T3>

-AssertionResult AssertPred3Helper(const char* pred_text,

-                                  const char* e1,

-                                  const char* e2,

-                                  const char* e3,

-                                  Pred pred,

-                                  const T1& v1,

-                                  const T2& v2,

-                                  const T3& v3) {

-  if (pred(v1, v2, v3)) return AssertionSuccess();

-

-  Message msg;

-  msg << pred_text << "("

-      << e1 << ", "

-      << e2 << ", "

-      << e3 << ") evaluates to false, where"

-      << "\n" << e1 << " evaluates to " << v1

-      << "\n" << e2 << " evaluates to " << v2

-      << "\n" << e3 << " evaluates to " << v3;

-  return AssertionFailure(msg);

-}

-

-// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.

-// Don't use this in your code.

-#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\

-  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\

-                on_failure)

-

-// Internal macro for implementing {EXPECT|ASSERT}_PRED3.  Don't use

-// this in your code.

-#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\

-  GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \

-                                             #v1, \

-                                             #v2, \

-                                             #v3, \

-                                             pred, \

-                                             v1, \

-                                             v2, \

-                                             v3), on_failure)

-

-// Ternary predicate assertion macros.

-#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \

-  GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)

-#define EXPECT_PRED3(pred, v1, v2, v3) \

-  GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)

-#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \

-  GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)

-#define ASSERT_PRED3(pred, v1, v2, v3) \

-  GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)

-

-

-

-// Helper function for implementing {EXPECT|ASSERT}_PRED4.  Don't use

-// this in your code.

-template <typename Pred,

-          typename T1,

-          typename T2,

-          typename T3,

-          typename T4>

-AssertionResult AssertPred4Helper(const char* pred_text,

-                                  const char* e1,

-                                  const char* e2,

-                                  const char* e3,

-                                  const char* e4,

-                                  Pred pred,

-                                  const T1& v1,

-                                  const T2& v2,

-                                  const T3& v3,

-                                  const T4& v4) {

-  if (pred(v1, v2, v3, v4)) return AssertionSuccess();

-

-  Message msg;

-  msg << pred_text << "("

-      << e1 << ", "

-      << e2 << ", "

-      << e3 << ", "

-      << e4 << ") evaluates to false, where"

-      << "\n" << e1 << " evaluates to " << v1

-      << "\n" << e2 << " evaluates to " << v2

-      << "\n" << e3 << " evaluates to " << v3

-      << "\n" << e4 << " evaluates to " << v4;

-  return AssertionFailure(msg);

-}

-

-// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.

-// Don't use this in your code.

-#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\

-  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\

-                on_failure)

-

-// Internal macro for implementing {EXPECT|ASSERT}_PRED4.  Don't use

-// this in your code.

-#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\

-  GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \

-                                             #v1, \

-                                             #v2, \

-                                             #v3, \

-                                             #v4, \

-                                             pred, \

-                                             v1, \

-                                             v2, \

-                                             v3, \

-                                             v4), on_failure)

-

-// 4-ary predicate assertion macros.

-#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \

-  GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)

-#define EXPECT_PRED4(pred, v1, v2, v3, v4) \

-  GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)

-#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \

-  GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)

-#define ASSERT_PRED4(pred, v1, v2, v3, v4) \

-  GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)

-

-

-

-// Helper function for implementing {EXPECT|ASSERT}_PRED5.  Don't use

-// this in your code.

-template <typename Pred,

-          typename T1,

-          typename T2,

-          typename T3,

-          typename T4,

-          typename T5>

-AssertionResult AssertPred5Helper(const char* pred_text,

-                                  const char* e1,

-                                  const char* e2,

-                                  const char* e3,

-                                  const char* e4,

-                                  const char* e5,

-                                  Pred pred,

-                                  const T1& v1,

-                                  const T2& v2,

-                                  const T3& v3,

-                                  const T4& v4,

-                                  const T5& v5) {

-  if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();

-

-  Message msg;

-  msg << pred_text << "("

-      << e1 << ", "

-      << e2 << ", "

-      << e3 << ", "

-      << e4 << ", "

-      << e5 << ") evaluates to false, where"

-      << "\n" << e1 << " evaluates to " << v1

-      << "\n" << e2 << " evaluates to " << v2

-      << "\n" << e3 << " evaluates to " << v3

-      << "\n" << e4 << " evaluates to " << v4

-      << "\n" << e5 << " evaluates to " << v5;

-  return AssertionFailure(msg);

-}

-

-// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.

-// Don't use this in your code.

-#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\

-  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\

-                on_failure)

-

-// Internal macro for implementing {EXPECT|ASSERT}_PRED5.  Don't use

-// this in your code.

-#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\

-  GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \

-                                             #v1, \

-                                             #v2, \

-                                             #v3, \

-                                             #v4, \

-                                             #v5, \

-                                             pred, \

-                                             v1, \

-                                             v2, \

-                                             v3, \

-                                             v4, \

-                                             v5), on_failure)

-

-// 5-ary predicate assertion macros.

-#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \

-  GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)

-#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \

-  GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)

-#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \

-  GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)

-#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \

-  GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)

-

-

-

-#endif  // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_

+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on 10/02/2008 by command
+// 'gen_gtest_pred_impl.py 5'.  DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#error Do not include gtest_pred_impl.h directly.  Include gtest.h instead.
+#endif  // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+//   ASSERT_PRED_FORMAT1(pred_format, v1)
+//   ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+//   ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult.  See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+//   ASSERT_PRED1(pred, v1)
+//   ASSERT_PRED2(pred, v1, v2)
+//   ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most 5.
+// Please email googletestframework@googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT_ is the basic statement to which all of the assertions
+// in this file reduce.  Don't use this in your code.
+
+#define GTEST_ASSERT_(expression, on_failure) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (const ::testing::AssertionResult gtest_ar = (expression)) \
+    ; \
+  else \
+    on_failure(gtest_ar.failure_message())
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED1.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1>
+AssertionResult AssertPred1Helper(const char* pred_text,
+                                  const char* e1,
+                                  Pred pred,
+                                  const T1& v1) {
+  if (pred(v1)) return AssertionSuccess();
+
+  Message msg;
+  msg << pred_text << "("
+      << e1 << ") evaluates to false, where"
+      << "\n" << e1 << " evaluates to " << v1;
+  return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, v1),\
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED1.  Don't use
+// this in your code.
+#define GTEST_PRED1_(pred, v1, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
+                                             #v1, \
+                                             pred, \
+                                             v1), on_failure)
+
+// Unary predicate assertion macros.
+#define EXPECT_PRED_FORMAT1(pred_format, v1) \
+  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED1(pred, v1) \
+  GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT1(pred_format, v1) \
+  GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED1(pred, v1) \
+  GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED2.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2>
+AssertionResult AssertPred2Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2) {
+  if (pred(v1, v2)) return AssertionSuccess();
+
+  Message msg;
+  msg << pred_text << "("
+      << e1 << ", "
+      << e2 << ") evaluates to false, where"
+      << "\n" << e1 << " evaluates to " << v1
+      << "\n" << e2 << " evaluates to " << v2;
+  return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED2.  Don't use
+// this in your code.
+#define GTEST_PRED2_(pred, v1, v2, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             pred, \
+                                             v1, \
+                                             v2), on_failure)
+
+// Binary predicate assertion macros.
+#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
+  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED2(pred, v1, v2) \
+  GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
+  GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED2(pred, v1, v2) \
+  GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED3.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2,
+          typename T3>
+AssertionResult AssertPred3Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  const char* e3,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2,
+                                  const T3& v3) {
+  if (pred(v1, v2, v3)) return AssertionSuccess();
+
+  Message msg;
+  msg << pred_text << "("
+      << e1 << ", "
+      << e2 << ", "
+      << e3 << ") evaluates to false, where"
+      << "\n" << e1 << " evaluates to " << v1
+      << "\n" << e2 << " evaluates to " << v2
+      << "\n" << e3 << " evaluates to " << v3;
+  return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED3.  Don't use
+// this in your code.
+#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             #v3, \
+                                             pred, \
+                                             v1, \
+                                             v2, \
+                                             v3), on_failure)
+
+// Ternary predicate assertion macros.
+#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+  GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED3(pred, v1, v2, v3) \
+  GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+  GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED3(pred, v1, v2, v3) \
+  GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED4.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2,
+          typename T3,
+          typename T4>
+AssertionResult AssertPred4Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  const char* e3,
+                                  const char* e4,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2,
+                                  const T3& v3,
+                                  const T4& v4) {
+  if (pred(v1, v2, v3, v4)) return AssertionSuccess();
+
+  Message msg;
+  msg << pred_text << "("
+      << e1 << ", "
+      << e2 << ", "
+      << e3 << ", "
+      << e4 << ") evaluates to false, where"
+      << "\n" << e1 << " evaluates to " << v1
+      << "\n" << e2 << " evaluates to " << v2
+      << "\n" << e3 << " evaluates to " << v3
+      << "\n" << e4 << " evaluates to " << v4;
+  return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED4.  Don't use
+// this in your code.
+#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             #v3, \
+                                             #v4, \
+                                             pred, \
+                                             v1, \
+                                             v2, \
+                                             v3, \
+                                             v4), on_failure)
+
+// 4-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+  GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
+  GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+  GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
+  GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED5.  Don't use
+// this in your code.
+template <typename Pred,
+          typename T1,
+          typename T2,
+          typename T3,
+          typename T4,
+          typename T5>
+AssertionResult AssertPred5Helper(const char* pred_text,
+                                  const char* e1,
+                                  const char* e2,
+                                  const char* e3,
+                                  const char* e4,
+                                  const char* e5,
+                                  Pred pred,
+                                  const T1& v1,
+                                  const T2& v2,
+                                  const T3& v3,
+                                  const T4& v4,
+                                  const T5& v5) {
+  if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
+
+  Message msg;
+  msg << pred_text << "("
+      << e1 << ", "
+      << e2 << ", "
+      << e3 << ", "
+      << e4 << ", "
+      << e5 << ") evaluates to false, where"
+      << "\n" << e1 << " evaluates to " << v1
+      << "\n" << e2 << " evaluates to " << v2
+      << "\n" << e3 << " evaluates to " << v3
+      << "\n" << e4 << " evaluates to " << v4
+      << "\n" << e5 << " evaluates to " << v5;
+  return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
+  GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\
+                on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED5.  Don't use
+// this in your code.
+#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
+  GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
+                                             #v1, \
+                                             #v2, \
+                                             #v3, \
+                                             #v4, \
+                                             #v5, \
+                                             pred, \
+                                             v1, \
+                                             v2, \
+                                             v3, \
+                                             v4, \
+                                             v5), on_failure)
+
+// 5-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+  GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
+  GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+  GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
+  GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+
+
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
diff --git a/third_party/gtest/include/gtest/gtest_prod.h b/third_party/gtest/include/gtest/gtest_prod.h
index 08755f0..da80ddc 100644
--- a/third_party/gtest/include/gtest/gtest_prod.h
+++ b/third_party/gtest/include/gtest/gtest_prod.h
@@ -1,58 +1,58 @@
-// Copyright 2006, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan)

-//

-// Google C++ Testing Framework definitions useful in production code.

-

-#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_

-#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_

-

-// When you need to test the private or protected members of a class,

-// use the FRIEND_TEST macro to declare your tests as friends of the

-// class.  For example:

-//

-// class MyClass {

-//  private:

-//   void MyMethod();

-//   FRIEND_TEST(MyClassTest, MyMethod);

-// };

-//

-// class MyClassTest : public testing::Test {

-//   // ...

-// };

-//

-// TEST_F(MyClassTest, MyMethod) {

-//   // Can call MyClass::MyMethod() here.

-// }

-

-#define FRIEND_TEST(test_case_name, test_name)\

-friend class test_case_name##_##test_name##_Test

-

-#endif  // GTEST_INCLUDE_GTEST_GTEST_PROD_H_

+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Google C++ Testing Framework definitions useful in production code.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+
+// When you need to test the private or protected members of a class,
+// use the FRIEND_TEST macro to declare your tests as friends of the
+// class.  For example:
+//
+// class MyClass {
+//  private:
+//   void MyMethod();
+//   FRIEND_TEST(MyClassTest, MyMethod);
+// };
+//
+// class MyClassTest : public testing::Test {
+//   // ...
+// };
+//
+// TEST_F(MyClassTest, MyMethod) {
+//   // Can call MyClass::MyMethod() here.
+// }
+
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#endif  // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
diff --git a/third_party/gtest/include/gtest/internal/gtest-death-test-internal.h b/third_party/gtest/include/gtest/internal/gtest-death-test-internal.h
index 05785d8..143e58a 100644
--- a/third_party/gtest/include/gtest/internal/gtest-death-test-internal.h
+++ b/third_party/gtest/include/gtest/internal/gtest-death-test-internal.h
@@ -1,227 +1,227 @@
-// Copyright 2005, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)

-//

-// The Google C++ Testing Framework (Google Test)

-//

-// This header file defines internal utilities needed for implementing

-// death tests.  They are subject to change without notice.

-

-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_

-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_

-

-#include <gtest/internal/gtest-internal.h>

-

-namespace testing {

-namespace internal {

-

-GTEST_DECLARE_string_(internal_run_death_test);

-

-// Names of the flags (needed for parsing Google Test flags).

-const char kDeathTestStyleFlag[] = "death_test_style";

-const char kDeathTestUseFork[] = "death_test_use_fork";

-const char kInternalRunDeathTestFlag[] = "internal_run_death_test";

-

-#if GTEST_HAS_DEATH_TEST

-

-// DeathTest is a class that hides much of the complexity of the

-// GTEST_DEATH_TEST_ macro.  It is abstract; its static Create method

-// returns a concrete class that depends on the prevailing death test

-// style, as defined by the --gtest_death_test_style and/or

-// --gtest_internal_run_death_test flags.

-

-// In describing the results of death tests, these terms are used with

-// the corresponding definitions:

-//

-// exit status:  The integer exit information in the format specified

-//               by wait(2)

-// exit code:    The integer code passed to exit(3), _exit(2), or

-//               returned from main()

-class DeathTest {

- public:

-  // Create returns false if there was an error determining the

-  // appropriate action to take for the current death test; for example,

-  // if the gtest_death_test_style flag is set to an invalid value.

-  // The LastMessage method will return a more detailed message in that

-  // case.  Otherwise, the DeathTest pointer pointed to by the "test"

-  // argument is set.  If the death test should be skipped, the pointer

-  // is set to NULL; otherwise, it is set to the address of a new concrete

-  // DeathTest object that controls the execution of the current test.

-  static bool Create(const char* statement, const RE* regex,

-                     const char* file, int line, DeathTest** test);

-  DeathTest();

-  virtual ~DeathTest() { }

-

-  // A helper class that aborts a death test when it's deleted.

-  class ReturnSentinel {

-   public:

-    explicit ReturnSentinel(DeathTest* test) : test_(test) { }

-    ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }

-   private:

-    DeathTest* const test_;

-    GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);

-  } GTEST_ATTRIBUTE_UNUSED_;

-

-  // An enumeration of possible roles that may be taken when a death

-  // test is encountered.  EXECUTE means that the death test logic should

-  // be executed immediately.  OVERSEE means that the program should prepare

-  // the appropriate environment for a child process to execute the death

-  // test, then wait for it to complete.

-  enum TestRole { OVERSEE_TEST, EXECUTE_TEST };

-

-  // An enumeration of the two reasons that a test might be aborted.

-  enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE };

-

-  // Assumes one of the above roles.

-  virtual TestRole AssumeRole() = 0;

-

-  // Waits for the death test to finish and returns its status.

-  virtual int Wait() = 0;

-

-  // Returns true if the death test passed; that is, the test process

-  // exited during the test, its exit status matches a user-supplied

-  // predicate, and its stderr output matches a user-supplied regular

-  // expression.

-  // The user-supplied predicate may be a macro expression rather

-  // than a function pointer or functor, or else Wait and Passed could

-  // be combined.

-  virtual bool Passed(bool exit_status_ok) = 0;

-

-  // Signals that the death test did not die as expected.

-  virtual void Abort(AbortReason reason) = 0;

-

-  // Returns a human-readable outcome message regarding the outcome of

-  // the last death test.

-  static const char* LastMessage();

-

-  static void set_last_death_test_message(const String& message);

-

- private:

-  // A string containing a description of the outcome of the last death test.

-  static String last_death_test_message_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);

-};

-

-// Factory interface for death tests.  May be mocked out for testing.

-class DeathTestFactory {

- public:

-  virtual ~DeathTestFactory() { }

-  virtual bool Create(const char* statement, const RE* regex,

-                      const char* file, int line, DeathTest** test) = 0;

-};

-

-// A concrete DeathTestFactory implementation for normal use.

-class DefaultDeathTestFactory : public DeathTestFactory {

- public:

-  virtual bool Create(const char* statement, const RE* regex,

-                      const char* file, int line, DeathTest** test);

-};

-

-// Returns true if exit_status describes a process that was terminated

-// by a signal, or exited normally with a nonzero exit code.

-bool ExitedUnsuccessfully(int exit_status);

-

-// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,

-// ASSERT_EXIT*, and EXPECT_EXIT*.

-#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \

-  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \

-  if (true) { \

-    const ::testing::internal::RE& gtest_regex = (regex); \

-    ::testing::internal::DeathTest* gtest_dt; \

-    if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \

-        __FILE__, __LINE__, &gtest_dt)) { \

-      goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \

-    } \

-    if (gtest_dt != NULL) { \

-      ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \

-          gtest_dt_ptr(gtest_dt); \

-      switch (gtest_dt->AssumeRole()) { \

-        case ::testing::internal::DeathTest::OVERSEE_TEST: \

-          if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \

-            goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \

-          } \

-          break; \

-        case ::testing::internal::DeathTest::EXECUTE_TEST: { \

-          ::testing::internal::DeathTest::ReturnSentinel \

-              gtest_sentinel(gtest_dt); \

-          GTEST_HIDE_UNREACHABLE_CODE_(statement); \

-          gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \

-          break; \

-        } \

-      } \

-    } \

-  } else \

-    GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \

-      fail(::testing::internal::DeathTest::LastMessage())

-// The symbol "fail" here expands to something into which a message

-// can be streamed.

-

-// A class representing the parsed contents of the

-// --gtest_internal_run_death_test flag, as it existed when

-// RUN_ALL_TESTS was called.

-class InternalRunDeathTestFlag {

- public:

-  InternalRunDeathTestFlag(const String& file,

-                           int line,

-                           int index,

-                           int write_fd)

-      : file_(file), line_(line), index_(index), write_fd_(write_fd) {}

-

-  ~InternalRunDeathTestFlag() {

-    if (write_fd_ >= 0)

-      posix::Close(write_fd_);

-  }

-

-  String file() const { return file_; }

-  int line() const { return line_; }

-  int index() const { return index_; }

-  int write_fd() const { return write_fd_; }

-

- private:

-  String file_;

-  int line_;

-  int index_;

-  int write_fd_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);

-};

-

-// Returns a newly created InternalRunDeathTestFlag object with fields

-// initialized from the GTEST_FLAG(internal_run_death_test) flag if

-// the flag is specified; otherwise returns NULL.

-InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();

-

-#endif  // GTEST_HAS_DEATH_TEST

-

-}  // namespace internal

-}  // namespace testing

-

-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_

+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines internal utilities needed for implementing
+// death tests.  They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+#include <gtest/internal/gtest-internal.h>
+
+namespace testing {
+namespace internal {
+
+GTEST_DECLARE_string_(internal_run_death_test);
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kDeathTestStyleFlag[] = "death_test_style";
+const char kDeathTestUseFork[] = "death_test_use_fork";
+const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
+
+#if GTEST_HAS_DEATH_TEST
+
+// DeathTest is a class that hides much of the complexity of the
+// GTEST_DEATH_TEST_ macro.  It is abstract; its static Create method
+// returns a concrete class that depends on the prevailing death test
+// style, as defined by the --gtest_death_test_style and/or
+// --gtest_internal_run_death_test flags.
+
+// In describing the results of death tests, these terms are used with
+// the corresponding definitions:
+//
+// exit status:  The integer exit information in the format specified
+//               by wait(2)
+// exit code:    The integer code passed to exit(3), _exit(2), or
+//               returned from main()
+class DeathTest {
+ public:
+  // Create returns false if there was an error determining the
+  // appropriate action to take for the current death test; for example,
+  // if the gtest_death_test_style flag is set to an invalid value.
+  // The LastMessage method will return a more detailed message in that
+  // case.  Otherwise, the DeathTest pointer pointed to by the "test"
+  // argument is set.  If the death test should be skipped, the pointer
+  // is set to NULL; otherwise, it is set to the address of a new concrete
+  // DeathTest object that controls the execution of the current test.
+  static bool Create(const char* statement, const RE* regex,
+                     const char* file, int line, DeathTest** test);
+  DeathTest();
+  virtual ~DeathTest() { }
+
+  // A helper class that aborts a death test when it's deleted.
+  class ReturnSentinel {
+   public:
+    explicit ReturnSentinel(DeathTest* test) : test_(test) { }
+    ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
+   private:
+    DeathTest* const test_;
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
+  } GTEST_ATTRIBUTE_UNUSED_;
+
+  // An enumeration of possible roles that may be taken when a death
+  // test is encountered.  EXECUTE means that the death test logic should
+  // be executed immediately.  OVERSEE means that the program should prepare
+  // the appropriate environment for a child process to execute the death
+  // test, then wait for it to complete.
+  enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
+
+  // An enumeration of the two reasons that a test might be aborted.
+  enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE };
+
+  // Assumes one of the above roles.
+  virtual TestRole AssumeRole() = 0;
+
+  // Waits for the death test to finish and returns its status.
+  virtual int Wait() = 0;
+
+  // Returns true if the death test passed; that is, the test process
+  // exited during the test, its exit status matches a user-supplied
+  // predicate, and its stderr output matches a user-supplied regular
+  // expression.
+  // The user-supplied predicate may be a macro expression rather
+  // than a function pointer or functor, or else Wait and Passed could
+  // be combined.
+  virtual bool Passed(bool exit_status_ok) = 0;
+
+  // Signals that the death test did not die as expected.
+  virtual void Abort(AbortReason reason) = 0;
+
+  // Returns a human-readable outcome message regarding the outcome of
+  // the last death test.
+  static const char* LastMessage();
+
+  static void set_last_death_test_message(const String& message);
+
+ private:
+  // A string containing a description of the outcome of the last death test.
+  static String last_death_test_message_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
+};
+
+// Factory interface for death tests.  May be mocked out for testing.
+class DeathTestFactory {
+ public:
+  virtual ~DeathTestFactory() { }
+  virtual bool Create(const char* statement, const RE* regex,
+                      const char* file, int line, DeathTest** test) = 0;
+};
+
+// A concrete DeathTestFactory implementation for normal use.
+class DefaultDeathTestFactory : public DeathTestFactory {
+ public:
+  virtual bool Create(const char* statement, const RE* regex,
+                      const char* file, int line, DeathTest** test);
+};
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status);
+
+// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
+// ASSERT_EXIT*, and EXPECT_EXIT*.
+#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (true) { \
+    const ::testing::internal::RE& gtest_regex = (regex); \
+    ::testing::internal::DeathTest* gtest_dt; \
+    if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \
+        __FILE__, __LINE__, &gtest_dt)) { \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+    } \
+    if (gtest_dt != NULL) { \
+      ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
+          gtest_dt_ptr(gtest_dt); \
+      switch (gtest_dt->AssumeRole()) { \
+        case ::testing::internal::DeathTest::OVERSEE_TEST: \
+          if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
+            goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+          } \
+          break; \
+        case ::testing::internal::DeathTest::EXECUTE_TEST: { \
+          ::testing::internal::DeathTest::ReturnSentinel \
+              gtest_sentinel(gtest_dt); \
+          GTEST_HIDE_UNREACHABLE_CODE_(statement); \
+          gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
+          break; \
+        } \
+      } \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
+      fail(::testing::internal::DeathTest::LastMessage())
+// The symbol "fail" here expands to something into which a message
+// can be streamed.
+
+// A class representing the parsed contents of the
+// --gtest_internal_run_death_test flag, as it existed when
+// RUN_ALL_TESTS was called.
+class InternalRunDeathTestFlag {
+ public:
+  InternalRunDeathTestFlag(const String& file,
+                           int line,
+                           int index,
+                           int write_fd)
+      : file_(file), line_(line), index_(index), write_fd_(write_fd) {}
+
+  ~InternalRunDeathTestFlag() {
+    if (write_fd_ >= 0)
+      posix::Close(write_fd_);
+  }
+
+  String file() const { return file_; }
+  int line() const { return line_; }
+  int index() const { return index_; }
+  int write_fd() const { return write_fd_; }
+
+ private:
+  String file_;
+  int line_;
+  int index_;
+  int write_fd_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
+};
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
diff --git a/third_party/gtest/include/gtest/internal/gtest-filepath.h b/third_party/gtest/include/gtest/internal/gtest-filepath.h
index d57676e..1b2f586 100644
--- a/third_party/gtest/include/gtest/internal/gtest-filepath.h
+++ b/third_party/gtest/include/gtest/internal/gtest-filepath.h
@@ -1,201 +1,201 @@
-// Copyright 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: keith.ray@gmail.com (Keith Ray)

-//

-// Google Test filepath utilities

-//

-// This header file declares classes and functions used internally by

-// Google Test.  They are subject to change without notice.

-//

-// This file is #included in <gtest/internal/gtest-internal.h>.

-// Do not include this header file separately!

-

-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_

-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_

-

-#include <gtest/internal/gtest-string.h>

-

-namespace testing {

-namespace internal {

-

-// FilePath - a class for file and directory pathname manipulation which

-// handles platform-specific conventions (like the pathname separator).

-// Used for helper functions for naming files in a directory for xml output.

-// Except for Set methods, all methods are const or static, which provides an

-// "immutable value object" -- useful for peace of mind.

-// A FilePath with a value ending in a path separator ("like/this/") represents

-// a directory, otherwise it is assumed to represent a file. In either case,

-// it may or may not represent an actual file or directory in the file system.

-// Names are NOT checked for syntax correctness -- no checking for illegal

-// characters, malformed paths, etc.

-

-class FilePath {

- public:

-  FilePath() : pathname_("") { }

-  FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }

-

-  explicit FilePath(const char* pathname) : pathname_(pathname) {

-    Normalize();

-  }

-

-  explicit FilePath(const String& pathname) : pathname_(pathname) {

-    Normalize();

-  }

-

-  FilePath& operator=(const FilePath& rhs) {

-    Set(rhs);

-    return *this;

-  }

-

-  void Set(const FilePath& rhs) {

-    pathname_ = rhs.pathname_;

-  }

-

-  String ToString() const { return pathname_; }

-  const char* c_str() const { return pathname_.c_str(); }

-

-  // Returns the current working directory, or "" if unsuccessful.

-  static FilePath GetCurrentDir();

-

-  // Given directory = "dir", base_name = "test", number = 0,

-  // extension = "xml", returns "dir/test.xml". If number is greater

-  // than zero (e.g., 12), returns "dir/test_12.xml".

-  // On Windows platform, uses \ as the separator rather than /.

-  static FilePath MakeFileName(const FilePath& directory,

-                               const FilePath& base_name,

-                               int number,

-                               const char* extension);

-

-  // Given directory = "dir", relative_path = "test.xml",

-  // returns "dir/test.xml".

-  // On Windows, uses \ as the separator rather than /.

-  static FilePath ConcatPaths(const FilePath& directory,

-                              const FilePath& relative_path);

-

-  // Returns a pathname for a file that does not currently exist. The pathname

-  // will be directory/base_name.extension or

-  // directory/base_name_<number>.extension if directory/base_name.extension

-  // already exists. The number will be incremented until a pathname is found

-  // that does not already exist.

-  // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.

-  // There could be a race condition if two or more processes are calling this

-  // function at the same time -- they could both pick the same filename.

-  static FilePath GenerateUniqueFileName(const FilePath& directory,

-                                         const FilePath& base_name,

-                                         const char* extension);

-

-  // Returns true iff the path is NULL or "".

-  bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; }

-

-  // If input name has a trailing separator character, removes it and returns

-  // the name, otherwise return the name string unmodified.

-  // On Windows platform, uses \ as the separator, other platforms use /.

-  FilePath RemoveTrailingPathSeparator() const;

-

-  // Returns a copy of the FilePath with the directory part removed.

-  // Example: FilePath("path/to/file").RemoveDirectoryName() returns

-  // FilePath("file"). If there is no directory part ("just_a_file"), it returns

-  // the FilePath unmodified. If there is no file part ("just_a_dir/") it

-  // returns an empty FilePath ("").

-  // On Windows platform, '\' is the path separator, otherwise it is '/'.

-  FilePath RemoveDirectoryName() const;

-

-  // RemoveFileName returns the directory path with the filename removed.

-  // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".

-  // If the FilePath is "a_file" or "/a_file", RemoveFileName returns

-  // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does

-  // not have a file, like "just/a/dir/", it returns the FilePath unmodified.

-  // On Windows platform, '\' is the path separator, otherwise it is '/'.

-  FilePath RemoveFileName() const;

-

-  // Returns a copy of the FilePath with the case-insensitive extension removed.

-  // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns

-  // FilePath("dir/file"). If a case-insensitive extension is not

-  // found, returns a copy of the original FilePath.

-  FilePath RemoveExtension(const char* extension) const;

-

-  // Creates directories so that path exists. Returns true if successful or if

-  // the directories already exist; returns false if unable to create

-  // directories for any reason. Will also return false if the FilePath does

-  // not represent a directory (that is, it doesn't end with a path separator).

-  bool CreateDirectoriesRecursively() const;

-

-  // Create the directory so that path exists. Returns true if successful or

-  // if the directory already exists; returns false if unable to create the

-  // directory for any reason, including if the parent directory does not

-  // exist. Not named "CreateDirectory" because that's a macro on Windows.

-  bool CreateFolder() const;

-

-  // Returns true if FilePath describes something in the file-system,

-  // either a file, directory, or whatever, and that something exists.

-  bool FileOrDirectoryExists() const;

-

-  // Returns true if pathname describes a directory in the file-system

-  // that exists.

-  bool DirectoryExists() const;

-

-  // Returns true if FilePath ends with a path separator, which indicates that

-  // it is intended to represent a directory. Returns false otherwise.

-  // This does NOT check that a directory (or file) actually exists.

-  bool IsDirectory() const;

-

-  // Returns true if pathname describes a root directory. (Windows has one

-  // root directory per disk drive.)

-  bool IsRootDirectory() const;

-

-  // Returns true if pathname describes an absolute path.

-  bool IsAbsolutePath() const;

-

- private:

-  // Replaces multiple consecutive separators with a single separator.

-  // For example, "bar///foo" becomes "bar/foo". Does not eliminate other

-  // redundancies that might be in a pathname involving "." or "..".

-  //

-  // A pathname with multiple consecutive separators may occur either through

-  // user error or as a result of some scripts or APIs that generate a pathname

-  // with a trailing separator. On other platforms the same API or script

-  // may NOT generate a pathname with a trailing "/". Then elsewhere that

-  // pathname may have another "/" and pathname components added to it,

-  // without checking for the separator already being there.

-  // The script language and operating system may allow paths like "foo//bar"

-  // but some of the functions in FilePath will not handle that correctly. In

-  // particular, RemoveTrailingPathSeparator() only removes one separator, and

-  // it is called in CreateDirectoriesRecursively() assuming that it will change

-  // a pathname from directory syntax (trailing separator) to filename syntax.

-

-  void Normalize();

-

-  String pathname_;

-};  // class FilePath

-

-}  // namespace internal

-}  // namespace testing

-

-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_

+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keith.ray@gmail.com (Keith Ray)
+//
+// Google Test filepath utilities
+//
+// This header file declares classes and functions used internally by
+// Google Test.  They are subject to change without notice.
+//
+// This file is #included in <gtest/internal/gtest-internal.h>.
+// Do not include this header file separately!
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+namespace internal {
+
+// FilePath - a class for file and directory pathname manipulation which
+// handles platform-specific conventions (like the pathname separator).
+// Used for helper functions for naming files in a directory for xml output.
+// Except for Set methods, all methods are const or static, which provides an
+// "immutable value object" -- useful for peace of mind.
+// A FilePath with a value ending in a path separator ("like/this/") represents
+// a directory, otherwise it is assumed to represent a file. In either case,
+// it may or may not represent an actual file or directory in the file system.
+// Names are NOT checked for syntax correctness -- no checking for illegal
+// characters, malformed paths, etc.
+
+class FilePath {
+ public:
+  FilePath() : pathname_("") { }
+  FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
+
+  explicit FilePath(const char* pathname) : pathname_(pathname) {
+    Normalize();
+  }
+
+  explicit FilePath(const String& pathname) : pathname_(pathname) {
+    Normalize();
+  }
+
+  FilePath& operator=(const FilePath& rhs) {
+    Set(rhs);
+    return *this;
+  }
+
+  void Set(const FilePath& rhs) {
+    pathname_ = rhs.pathname_;
+  }
+
+  String ToString() const { return pathname_; }
+  const char* c_str() const { return pathname_.c_str(); }
+
+  // Returns the current working directory, or "" if unsuccessful.
+  static FilePath GetCurrentDir();
+
+  // Given directory = "dir", base_name = "test", number = 0,
+  // extension = "xml", returns "dir/test.xml". If number is greater
+  // than zero (e.g., 12), returns "dir/test_12.xml".
+  // On Windows platform, uses \ as the separator rather than /.
+  static FilePath MakeFileName(const FilePath& directory,
+                               const FilePath& base_name,
+                               int number,
+                               const char* extension);
+
+  // Given directory = "dir", relative_path = "test.xml",
+  // returns "dir/test.xml".
+  // On Windows, uses \ as the separator rather than /.
+  static FilePath ConcatPaths(const FilePath& directory,
+                              const FilePath& relative_path);
+
+  // Returns a pathname for a file that does not currently exist. The pathname
+  // will be directory/base_name.extension or
+  // directory/base_name_<number>.extension if directory/base_name.extension
+  // already exists. The number will be incremented until a pathname is found
+  // that does not already exist.
+  // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+  // There could be a race condition if two or more processes are calling this
+  // function at the same time -- they could both pick the same filename.
+  static FilePath GenerateUniqueFileName(const FilePath& directory,
+                                         const FilePath& base_name,
+                                         const char* extension);
+
+  // Returns true iff the path is NULL or "".
+  bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; }
+
+  // If input name has a trailing separator character, removes it and returns
+  // the name, otherwise return the name string unmodified.
+  // On Windows platform, uses \ as the separator, other platforms use /.
+  FilePath RemoveTrailingPathSeparator() const;
+
+  // Returns a copy of the FilePath with the directory part removed.
+  // Example: FilePath("path/to/file").RemoveDirectoryName() returns
+  // FilePath("file"). If there is no directory part ("just_a_file"), it returns
+  // the FilePath unmodified. If there is no file part ("just_a_dir/") it
+  // returns an empty FilePath ("").
+  // On Windows platform, '\' is the path separator, otherwise it is '/'.
+  FilePath RemoveDirectoryName() const;
+
+  // RemoveFileName returns the directory path with the filename removed.
+  // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+  // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+  // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+  // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+  // On Windows platform, '\' is the path separator, otherwise it is '/'.
+  FilePath RemoveFileName() const;
+
+  // Returns a copy of the FilePath with the case-insensitive extension removed.
+  // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+  // FilePath("dir/file"). If a case-insensitive extension is not
+  // found, returns a copy of the original FilePath.
+  FilePath RemoveExtension(const char* extension) const;
+
+  // Creates directories so that path exists. Returns true if successful or if
+  // the directories already exist; returns false if unable to create
+  // directories for any reason. Will also return false if the FilePath does
+  // not represent a directory (that is, it doesn't end with a path separator).
+  bool CreateDirectoriesRecursively() const;
+
+  // Create the directory so that path exists. Returns true if successful or
+  // if the directory already exists; returns false if unable to create the
+  // directory for any reason, including if the parent directory does not
+  // exist. Not named "CreateDirectory" because that's a macro on Windows.
+  bool CreateFolder() const;
+
+  // Returns true if FilePath describes something in the file-system,
+  // either a file, directory, or whatever, and that something exists.
+  bool FileOrDirectoryExists() const;
+
+  // Returns true if pathname describes a directory in the file-system
+  // that exists.
+  bool DirectoryExists() const;
+
+  // Returns true if FilePath ends with a path separator, which indicates that
+  // it is intended to represent a directory. Returns false otherwise.
+  // This does NOT check that a directory (or file) actually exists.
+  bool IsDirectory() const;
+
+  // Returns true if pathname describes a root directory. (Windows has one
+  // root directory per disk drive.)
+  bool IsRootDirectory() const;
+
+  // Returns true if pathname describes an absolute path.
+  bool IsAbsolutePath() const;
+
+ private:
+  // Replaces multiple consecutive separators with a single separator.
+  // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+  // redundancies that might be in a pathname involving "." or "..".
+  //
+  // A pathname with multiple consecutive separators may occur either through
+  // user error or as a result of some scripts or APIs that generate a pathname
+  // with a trailing separator. On other platforms the same API or script
+  // may NOT generate a pathname with a trailing "/". Then elsewhere that
+  // pathname may have another "/" and pathname components added to it,
+  // without checking for the separator already being there.
+  // The script language and operating system may allow paths like "foo//bar"
+  // but some of the functions in FilePath will not handle that correctly. In
+  // particular, RemoveTrailingPathSeparator() only removes one separator, and
+  // it is called in CreateDirectoriesRecursively() assuming that it will change
+  // a pathname from directory syntax (trailing separator) to filename syntax.
+
+  void Normalize();
+
+  String pathname_;
+};  // class FilePath
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
diff --git a/third_party/gtest/include/gtest/internal/gtest-internal.h b/third_party/gtest/include/gtest/internal/gtest-internal.h
index 21103ef..d596b3a 100644
--- a/third_party/gtest/include/gtest/internal/gtest-internal.h
+++ b/third_party/gtest/include/gtest/internal/gtest-internal.h
@@ -1,890 +1,890 @@
-// Copyright 2005, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)

-//

-// The Google C++ Testing Framework (Google Test)

-//

-// This header file declares functions and macros used internally by

-// Google Test.  They are subject to change without notice.

-

-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_

-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_

-

-#include <gtest/internal/gtest-port.h>

-

-#if GTEST_OS_LINUX

-#include <stdlib.h>

-#include <sys/types.h>

-#include <sys/wait.h>

-#include <unistd.h>

-#endif  // GTEST_OS_LINUX

-

-#include <ctype.h>

-#include <string.h>

-#include <iomanip>

-#include <limits>

-#include <set>

-

-#include <gtest/internal/gtest-string.h>

-#include <gtest/internal/gtest-filepath.h>

-#include <gtest/internal/gtest-type-util.h>

-

-// Due to C++ preprocessor weirdness, we need double indirection to

-// concatenate two tokens when one of them is __LINE__.  Writing

-//

-//   foo ## __LINE__

-//

-// will result in the token foo__LINE__, instead of foo followed by

-// the current line number.  For more details, see

-// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6

-#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)

-#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar

-

-// Google Test defines the testing::Message class to allow construction of

-// test messages via the << operator.  The idea is that anything

-// streamable to std::ostream can be streamed to a testing::Message.

-// This allows a user to use his own types in Google Test assertions by

-// overloading the << operator.

-//

-// util/gtl/stl_logging-inl.h overloads << for STL containers.  These

-// overloads cannot be defined in the std namespace, as that will be

-// undefined behavior.  Therefore, they are defined in the global

-// namespace instead.

-//

-// C++'s symbol lookup rule (i.e. Koenig lookup) says that these

-// overloads are visible in either the std namespace or the global

-// namespace, but not other namespaces, including the testing

-// namespace which Google Test's Message class is in.

-//

-// To allow STL containers (and other types that has a << operator

-// defined in the global namespace) to be used in Google Test assertions,

-// testing::Message must access the custom << operator from the global

-// namespace.  Hence this helper function.

-//

-// Note: Jeffrey Yasskin suggested an alternative fix by "using

-// ::operator<<;" in the definition of Message's operator<<.  That fix

-// doesn't require a helper function, but unfortunately doesn't

-// compile with MSVC.

-template <typename T>

-inline void GTestStreamToHelper(std::ostream* os, const T& val) {

-  *os << val;

-}

-

-namespace testing {

-

-// Forward declaration of classes.

-

-class Message;                         // Represents a failure message.

-class Test;                            // Represents a test.

-class TestCase;                        // A collection of related tests.

-class TestPartResult;                  // Result of a test part.

-class TestInfo;                        // Information about a test.

-class UnitTest;                        // A collection of test cases.

-class UnitTestEventListenerInterface;  // Listens to Google Test events.

-class AssertionResult;                 // Result of an assertion.

-

-namespace internal {

-

-struct TraceInfo;                      // Information about a trace point.

-class ScopedTrace;                     // Implements scoped trace.

-class TestInfoImpl;                    // Opaque implementation of TestInfo

-class TestResult;                      // Result of a single Test.

-class UnitTestImpl;                    // Opaque implementation of UnitTest

-

-template <typename E> class List;      // A generic list.

-template <typename E> class ListNode;  // A node in a generic list.

-

-// How many times InitGoogleTest() has been called.

-extern int g_init_gtest_count;

-

-// The text used in failure messages to indicate the start of the

-// stack trace.

-extern const char kStackTraceMarker[];

-

-// A secret type that Google Test users don't know about.  It has no

-// definition on purpose.  Therefore it's impossible to create a

-// Secret object, which is what we want.

-class Secret;

-

-// Two overloaded helpers for checking at compile time whether an

-// expression is a null pointer literal (i.e. NULL or any 0-valued

-// compile-time integral constant).  Their return values have

-// different sizes, so we can use sizeof() to test which version is

-// picked by the compiler.  These helpers have no implementations, as

-// we only need their signatures.

-//

-// Given IsNullLiteralHelper(x), the compiler will pick the first

-// version if x can be implicitly converted to Secret*, and pick the

-// second version otherwise.  Since Secret is a secret and incomplete

-// type, the only expression a user can write that has type Secret* is

-// a null pointer literal.  Therefore, we know that x is a null

-// pointer literal if and only if the first version is picked by the

-// compiler.

-char IsNullLiteralHelper(Secret* p);

-char (&IsNullLiteralHelper(...))[2];  // NOLINT

-

-// A compile-time bool constant that is true if and only if x is a

-// null pointer literal (i.e. NULL or any 0-valued compile-time

-// integral constant).

-#ifdef GTEST_ELLIPSIS_NEEDS_COPY_

-// Passing non-POD classes through ellipsis (...) crashes the ARM

-// compiler.  The Nokia Symbian and the IBM XL C/C++ compiler try to

-// instantiate a copy constructor for objects passed through ellipsis

-// (...), failing for uncopyable objects.  Hence we define this to

-// false (and lose support for NULL detection).

-#define GTEST_IS_NULL_LITERAL_(x) false

-#else

-#define GTEST_IS_NULL_LITERAL_(x) \

-    (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)

-#endif  // GTEST_ELLIPSIS_NEEDS_COPY_

-

-// Appends the user-supplied message to the Google-Test-generated message.

-String AppendUserMessage(const String& gtest_msg,

-                         const Message& user_msg);

-

-// A helper class for creating scoped traces in user programs.

-class ScopedTrace {

- public:

-  // The c'tor pushes the given source file location and message onto

-  // a trace stack maintained by Google Test.

-  ScopedTrace(const char* file, int line, const Message& message);

-

-  // The d'tor pops the info pushed by the c'tor.

-  //

-  // Note that the d'tor is not virtual in order to be efficient.

-  // Don't inherit from ScopedTrace!

-  ~ScopedTrace();

-

- private:

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);

-} GTEST_ATTRIBUTE_UNUSED_;  // A ScopedTrace object does its job in its

-                            // c'tor and d'tor.  Therefore it doesn't

-                            // need to be used otherwise.

-

-// Converts a streamable value to a String.  A NULL pointer is

-// converted to "(null)".  When the input value is a ::string,

-// ::std::string, ::wstring, or ::std::wstring object, each NUL

-// character in it is replaced with "\\0".

-// Declared here but defined in gtest.h, so that it has access

-// to the definition of the Message class, required by the ARM

-// compiler.

-template <typename T>

-String StreamableToString(const T& streamable);

-

-// Formats a value to be used in a failure message.

-

-#ifdef GTEST_NEEDS_IS_POINTER_

-

-// These are needed as the Nokia Symbian and IBM XL C/C++ compilers

-// cannot decide between const T& and const T* in a function template.

-// These compilers _can_ decide between class template specializations

-// for T and T*, so a tr1::type_traits-like is_pointer works, and we

-// can overload on that.

-

-// This overload makes sure that all pointers (including

-// those to char or wchar_t) are printed as raw pointers.

-template <typename T>

-inline String FormatValueForFailureMessage(internal::true_type dummy,

-                                           T* pointer) {

-  return StreamableToString(static_cast<const void*>(pointer));

-}

-

-template <typename T>

-inline String FormatValueForFailureMessage(internal::false_type dummy,

-                                           const T& value) {

-  return StreamableToString(value);

-}

-

-template <typename T>

-inline String FormatForFailureMessage(const T& value) {

-  return FormatValueForFailureMessage(

-      typename internal::is_pointer<T>::type(), value);

-}

-

-#else

-

-// These are needed as the above solution using is_pointer has the

-// limitation that T cannot be a type without external linkage, when

-// compiled using MSVC.

-

-template <typename T>

-inline String FormatForFailureMessage(const T& value) {

-  return StreamableToString(value);

-}

-

-// This overload makes sure that all pointers (including

-// those to char or wchar_t) are printed as raw pointers.

-template <typename T>

-inline String FormatForFailureMessage(T* pointer) {

-  return StreamableToString(static_cast<const void*>(pointer));

-}

-

-#endif  // GTEST_NEEDS_IS_POINTER_

-

-// These overloaded versions handle narrow and wide characters.

-String FormatForFailureMessage(char ch);

-String FormatForFailureMessage(wchar_t wchar);

-

-// When this operand is a const char* or char*, and the other operand

-// is a ::std::string or ::string, we print this operand as a C string

-// rather than a pointer.  We do the same for wide strings.

-

-// This internal macro is used to avoid duplicated code.

-#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\

-inline String FormatForComparisonFailureMessage(\

-    operand2_type::value_type* str, const operand2_type& /*operand2*/) {\

-  return operand1_printer(str);\

-}\

-inline String FormatForComparisonFailureMessage(\

-    const operand2_type::value_type* str, const operand2_type& /*operand2*/) {\

-  return operand1_printer(str);\

-}

-

-#if GTEST_HAS_STD_STRING

-GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted)

-#endif  // GTEST_HAS_STD_STRING

-#if GTEST_HAS_STD_WSTRING

-GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted)

-#endif  // GTEST_HAS_STD_WSTRING

-

-#if GTEST_HAS_GLOBAL_STRING

-GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted)

-#endif  // GTEST_HAS_GLOBAL_STRING

-#if GTEST_HAS_GLOBAL_WSTRING

-GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted)

-#endif  // GTEST_HAS_GLOBAL_WSTRING

-

-#undef GTEST_FORMAT_IMPL_

-

-// Constructs and returns the message for an equality assertion

-// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.

-//

-// The first four parameters are the expressions used in the assertion

-// and their values, as strings.  For example, for ASSERT_EQ(foo, bar)

-// where foo is 5 and bar is 6, we have:

-//

-//   expected_expression: "foo"

-//   actual_expression:   "bar"

-//   expected_value:      "5"

-//   actual_value:        "6"

-//

-// The ignoring_case parameter is true iff the assertion is a

-// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will

-// be inserted into the message.

-AssertionResult EqFailure(const char* expected_expression,

-                          const char* actual_expression,

-                          const String& expected_value,

-                          const String& actual_value,

-                          bool ignoring_case);

-

-

-// This template class represents an IEEE floating-point number

-// (either single-precision or double-precision, depending on the

-// template parameters).

-//

-// The purpose of this class is to do more sophisticated number

-// comparison.  (Due to round-off error, etc, it's very unlikely that

-// two floating-points will be equal exactly.  Hence a naive

-// comparison by the == operation often doesn't work.)

-//

-// Format of IEEE floating-point:

-//

-//   The most-significant bit being the leftmost, an IEEE

-//   floating-point looks like

-//

-//     sign_bit exponent_bits fraction_bits

-//

-//   Here, sign_bit is a single bit that designates the sign of the

-//   number.

-//

-//   For float, there are 8 exponent bits and 23 fraction bits.

-//

-//   For double, there are 11 exponent bits and 52 fraction bits.

-//

-//   More details can be found at

-//   http://en.wikipedia.org/wiki/IEEE_floating-point_standard.

-//

-// Template parameter:

-//

-//   RawType: the raw floating-point type (either float or double)

-template <typename RawType>

-class FloatingPoint {

- public:

-  // Defines the unsigned integer type that has the same size as the

-  // floating point number.

-  typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;

-

-  // Constants.

-

-  // # of bits in a number.

-  static const size_t kBitCount = 8*sizeof(RawType);

-

-  // # of fraction bits in a number.

-  static const size_t kFractionBitCount =

-    std::numeric_limits<RawType>::digits - 1;

-

-  // # of exponent bits in a number.

-  static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;

-

-  // The mask for the sign bit.

-  static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);

-

-  // The mask for the fraction bits.

-  static const Bits kFractionBitMask =

-    ~static_cast<Bits>(0) >> (kExponentBitCount + 1);

-

-  // The mask for the exponent bits.

-  static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);

-

-  // How many ULP's (Units in the Last Place) we want to tolerate when

-  // comparing two numbers.  The larger the value, the more error we

-  // allow.  A 0 value means that two numbers must be exactly the same

-  // to be considered equal.

-  //

-  // The maximum error of a single floating-point operation is 0.5

-  // units in the last place.  On Intel CPU's, all floating-point

-  // calculations are done with 80-bit precision, while double has 64

-  // bits.  Therefore, 4 should be enough for ordinary use.

-  //

-  // See the following article for more details on ULP:

-  // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.

-  static const size_t kMaxUlps = 4;

-

-  // Constructs a FloatingPoint from a raw floating-point number.

-  //

-  // On an Intel CPU, passing a non-normalized NAN (Not a Number)

-  // around may change its bits, although the new value is guaranteed

-  // to be also a NAN.  Therefore, don't expect this constructor to

-  // preserve the bits in x when x is a NAN.

-  explicit FloatingPoint(const RawType& x) { u_.value_ = x; }

-

-  // Static methods

-

-  // Reinterprets a bit pattern as a floating-point number.

-  //

-  // This function is needed to test the AlmostEquals() method.

-  static RawType ReinterpretBits(const Bits bits) {

-    FloatingPoint fp(0);

-    fp.u_.bits_ = bits;

-    return fp.u_.value_;

-  }

-

-  // Returns the floating-point number that represent positive infinity.

-  static RawType Infinity() {

-    return ReinterpretBits(kExponentBitMask);

-  }

-

-  // Non-static methods

-

-  // Returns the bits that represents this number.

-  const Bits &bits() const { return u_.bits_; }

-

-  // Returns the exponent bits of this number.

-  Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }

-

-  // Returns the fraction bits of this number.

-  Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }

-

-  // Returns the sign bit of this number.

-  Bits sign_bit() const { return kSignBitMask & u_.bits_; }

-

-  // Returns true iff this is NAN (not a number).

-  bool is_nan() const {

-    // It's a NAN if the exponent bits are all ones and the fraction

-    // bits are not entirely zeros.

-    return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);

-  }

-

-  // Returns true iff this number is at most kMaxUlps ULP's away from

-  // rhs.  In particular, this function:

-  //

-  //   - returns false if either number is (or both are) NAN.

-  //   - treats really large numbers as almost equal to infinity.

-  //   - thinks +0.0 and -0.0 are 0 DLP's apart.

-  bool AlmostEquals(const FloatingPoint& rhs) const {

-    // The IEEE standard says that any comparison operation involving

-    // a NAN must return false.

-    if (is_nan() || rhs.is_nan()) return false;

-

-    return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)

-        <= kMaxUlps;

-  }

-

- private:

-  // The data type used to store the actual floating-point number.

-  union FloatingPointUnion {

-    RawType value_;  // The raw floating-point number.

-    Bits bits_;      // The bits that represent the number.

-  };

-

-  // Converts an integer from the sign-and-magnitude representation to

-  // the biased representation.  More precisely, let N be 2 to the

-  // power of (kBitCount - 1), an integer x is represented by the

-  // unsigned number x + N.

-  //

-  // For instance,

-  //

-  //   -N + 1 (the most negative number representable using

-  //          sign-and-magnitude) is represented by 1;

-  //   0      is represented by N; and

-  //   N - 1  (the biggest number representable using

-  //          sign-and-magnitude) is represented by 2N - 1.

-  //

-  // Read http://en.wikipedia.org/wiki/Signed_number_representations

-  // for more details on signed number representations.

-  static Bits SignAndMagnitudeToBiased(const Bits &sam) {

-    if (kSignBitMask & sam) {

-      // sam represents a negative number.

-      return ~sam + 1;

-    } else {

-      // sam represents a positive number.

-      return kSignBitMask | sam;

-    }

-  }

-

-  // Given two numbers in the sign-and-magnitude representation,

-  // returns the distance between them as an unsigned number.

-  static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,

-                                                     const Bits &sam2) {

-    const Bits biased1 = SignAndMagnitudeToBiased(sam1);

-    const Bits biased2 = SignAndMagnitudeToBiased(sam2);

-    return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);

-  }

-

-  FloatingPointUnion u_;

-};

-

-// Typedefs the instances of the FloatingPoint template class that we

-// care to use.

-typedef FloatingPoint<float> Float;

-typedef FloatingPoint<double> Double;

-

-// In order to catch the mistake of putting tests that use different

-// test fixture classes in the same test case, we need to assign

-// unique IDs to fixture classes and compare them.  The TypeId type is

-// used to hold such IDs.  The user should treat TypeId as an opaque

-// type: the only operation allowed on TypeId values is to compare

-// them for equality using the == operator.

-typedef const void* TypeId;

-

-template <typename T>

-class TypeIdHelper {

- public:

-  // dummy_ must not have a const type.  Otherwise an overly eager

-  // compiler (e.g. MSVC 7.1 & 8.0) may try to merge

-  // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".

-  static bool dummy_;

-};

-

-template <typename T>

-bool TypeIdHelper<T>::dummy_ = false;

-

-// GetTypeId<T>() returns the ID of type T.  Different values will be

-// returned for different types.  Calling the function twice with the

-// same type argument is guaranteed to return the same ID.

-template <typename T>

-TypeId GetTypeId() {

-  // The compiler is required to allocate a different

-  // TypeIdHelper<T>::dummy_ variable for each T used to instantiate

-  // the template.  Therefore, the address of dummy_ is guaranteed to

-  // be unique.

-  return &(TypeIdHelper<T>::dummy_);

-}

-

-// Returns the type ID of ::testing::Test.  Always call this instead

-// of GetTypeId< ::testing::Test>() to get the type ID of

-// ::testing::Test, as the latter may give the wrong result due to a

-// suspected linker bug when compiling Google Test as a Mac OS X

-// framework.

-TypeId GetTestTypeId();

-

-// Defines the abstract factory interface that creates instances

-// of a Test object.

-class TestFactoryBase {

- public:

-  virtual ~TestFactoryBase() {}

-

-  // Creates a test instance to run. The instance is both created and destroyed

-  // within TestInfoImpl::Run()

-  virtual Test* CreateTest() = 0;

-

- protected:

-  TestFactoryBase() {}

-

- private:

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);

-};

-

-// This class provides implementation of TeastFactoryBase interface.

-// It is used in TEST and TEST_F macros.

-template <class TestClass>

-class TestFactoryImpl : public TestFactoryBase {

- public:

-  virtual Test* CreateTest() { return new TestClass; }

-};

-

-#if GTEST_OS_WINDOWS

-

-// Predicate-formatters for implementing the HRESULT checking macros

-// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}

-// We pass a long instead of HRESULT to avoid causing an

-// include dependency for the HRESULT type.

-AssertionResult IsHRESULTSuccess(const char* expr, long hr);  // NOLINT

-AssertionResult IsHRESULTFailure(const char* expr, long hr);  // NOLINT

-

-#endif  // GTEST_OS_WINDOWS

-

-// Formats a source file path and a line number as they would appear

-// in a compiler error message.

-inline String FormatFileLocation(const char* file, int line) {

-  const char* const file_name = file == NULL ? "unknown file" : file;

-  if (line < 0) {

-    return String::Format("%s:", file_name);

-  }

-#ifdef _MSC_VER

-  return String::Format("%s(%d):", file_name, line);

-#else

-  return String::Format("%s:%d:", file_name, line);

-#endif  // _MSC_VER

-}

-

-// Types of SetUpTestCase() and TearDownTestCase() functions.

-typedef void (*SetUpTestCaseFunc)();

-typedef void (*TearDownTestCaseFunc)();

-

-// Creates a new TestInfo object and registers it with Google Test;

-// returns the created object.

-//

-// Arguments:

-//

-//   test_case_name:   name of the test case

-//   name:             name of the test

-//   test_case_comment: a comment on the test case that will be included in

-//                      the test output

-//   comment:          a comment on the test that will be included in the

-//                     test output

-//   fixture_class_id: ID of the test fixture class

-//   set_up_tc:        pointer to the function that sets up the test case

-//   tear_down_tc:     pointer to the function that tears down the test case

-//   factory:          pointer to the factory that creates a test object.

-//                     The newly created TestInfo instance will assume

-//                     ownership of the factory object.

-TestInfo* MakeAndRegisterTestInfo(

-    const char* test_case_name, const char* name,

-    const char* test_case_comment, const char* comment,

-    TypeId fixture_class_id,

-    SetUpTestCaseFunc set_up_tc,

-    TearDownTestCaseFunc tear_down_tc,

-    TestFactoryBase* factory);

-

-#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P

-

-// State of the definition of a type-parameterized test case.

-class TypedTestCasePState {

- public:

-  TypedTestCasePState() : registered_(false) {}

-

-  // Adds the given test name to defined_test_names_ and return true

-  // if the test case hasn't been registered; otherwise aborts the

-  // program.

-  bool AddTestName(const char* file, int line, const char* case_name,

-                   const char* test_name) {

-    if (registered_) {

-      fprintf(stderr, "%s Test %s must be defined before "

-              "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",

-              FormatFileLocation(file, line).c_str(), test_name, case_name);

-      fflush(stderr);

-      abort();

-    }

-    defined_test_names_.insert(test_name);

-    return true;

-  }

-

-  // Verifies that registered_tests match the test names in

-  // defined_test_names_; returns registered_tests if successful, or

-  // aborts the program otherwise.

-  const char* VerifyRegisteredTestNames(

-      const char* file, int line, const char* registered_tests);

-

- private:

-  bool registered_;

-  ::std::set<const char*> defined_test_names_;

-};

-

-// Skips to the first non-space char after the first comma in 'str';

-// returns NULL if no comma is found in 'str'.

-inline const char* SkipComma(const char* str) {

-  const char* comma = strchr(str, ',');

-  if (comma == NULL) {

-    return NULL;

-  }

-  while (isspace(*(++comma))) {}

-  return comma;

-}

-

-// Returns the prefix of 'str' before the first comma in it; returns

-// the entire string if it contains no comma.

-inline String GetPrefixUntilComma(const char* str) {

-  const char* comma = strchr(str, ',');

-  return comma == NULL ? String(str) : String(str, comma - str);

-}

-

-// TypeParameterizedTest<Fixture, TestSel, Types>::Register()

-// registers a list of type-parameterized tests with Google Test.  The

-// return value is insignificant - we just need to return something

-// such that we can call this function in a namespace scope.

-//

-// Implementation note: The GTEST_TEMPLATE_ macro declares a template

-// template parameter.  It's defined in gtest-type-util.h.

-template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>

-class TypeParameterizedTest {

- public:

-  // 'index' is the index of the test in the type list 'Types'

-  // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,

-  // Types).  Valid values for 'index' are [0, N - 1] where N is the

-  // length of Types.

-  static bool Register(const char* prefix, const char* case_name,

-                       const char* test_names, int index) {

-    typedef typename Types::Head Type;

-    typedef Fixture<Type> FixtureClass;

-    typedef typename GTEST_BIND_(TestSel, Type) TestClass;

-

-    // First, registers the first type-parameterized test in the type

-    // list.

-    MakeAndRegisterTestInfo(

-        String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/",

-                       case_name, index).c_str(),

-        GetPrefixUntilComma(test_names).c_str(),

-        String::Format("TypeParam = %s", GetTypeName<Type>().c_str()).c_str(),

-        "",

-        GetTypeId<FixtureClass>(),

-        TestClass::SetUpTestCase,

-        TestClass::TearDownTestCase,

-        new TestFactoryImpl<TestClass>);

-

-    // Next, recurses (at compile time) with the tail of the type list.

-    return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>

-        ::Register(prefix, case_name, test_names, index + 1);

-  }

-};

-

-// The base case for the compile time recursion.

-template <GTEST_TEMPLATE_ Fixture, class TestSel>

-class TypeParameterizedTest<Fixture, TestSel, Types0> {

- public:

-  static bool Register(const char* /*prefix*/, const char* /*case_name*/,

-                       const char* /*test_names*/, int /*index*/) {

-    return true;

-  }

-};

-

-// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()

-// registers *all combinations* of 'Tests' and 'Types' with Google

-// Test.  The return value is insignificant - we just need to return

-// something such that we can call this function in a namespace scope.

-template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>

-class TypeParameterizedTestCase {

- public:

-  static bool Register(const char* prefix, const char* case_name,

-                       const char* test_names) {

-    typedef typename Tests::Head Head;

-

-    // First, register the first test in 'Test' for each type in 'Types'.

-    TypeParameterizedTest<Fixture, Head, Types>::Register(

-        prefix, case_name, test_names, 0);

-

-    // Next, recurses (at compile time) with the tail of the test list.

-    return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>

-        ::Register(prefix, case_name, SkipComma(test_names));

-  }

-};

-

-// The base case for the compile time recursion.

-template <GTEST_TEMPLATE_ Fixture, typename Types>

-class TypeParameterizedTestCase<Fixture, Templates0, Types> {

- public:

-  static bool Register(const char* prefix, const char* case_name,

-                       const char* test_names) {

-    return true;

-  }

-};

-

-#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P

-

-// Returns the current OS stack trace as a String.

-//

-// The maximum number of stack frames to be included is specified by

-// the gtest_stack_trace_depth flag.  The skip_count parameter

-// specifies the number of top frames to be skipped, which doesn't

-// count against the number of frames to be included.

-//

-// For example, if Foo() calls Bar(), which in turn calls

-// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in

-// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.

-String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count);

-

-// Returns the number of failed test parts in the given test result object.

-int GetFailedPartCount(const TestResult* result);

-

-// A helper for suppressing warnings on unreachable code in some macros.

-bool AlwaysTrue();

-

-}  // namespace internal

-}  // namespace testing

-

-#define GTEST_MESSAGE_(message, result_type) \

-  ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \

-    = ::testing::Message()

-

-#define GTEST_FATAL_FAILURE_(message) \

-  return GTEST_MESSAGE_(message, ::testing::TPRT_FATAL_FAILURE)

-

-#define GTEST_NONFATAL_FAILURE_(message) \

-  GTEST_MESSAGE_(message, ::testing::TPRT_NONFATAL_FAILURE)

-

-#define GTEST_SUCCESS_(message) \

-  GTEST_MESSAGE_(message, ::testing::TPRT_SUCCESS)

-

-// Suppresses MSVC warnings 4072 (unreachable code) for the code following

-// statement if it returns or throws (or doesn't return or throw in some

-// situations).

-#define GTEST_HIDE_UNREACHABLE_CODE_(statement) \

-  if (::testing::internal::AlwaysTrue()) { statement; }

-

-#define GTEST_TEST_THROW_(statement, expected_exception, fail) \

-  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \

-  if (const char* gtest_msg = "") { \

-    bool gtest_caught_expected = false; \

-    try { \

-      GTEST_HIDE_UNREACHABLE_CODE_(statement); \

-    } \

-    catch (expected_exception const&) { \

-      gtest_caught_expected = true; \

-    } \

-    catch (...) { \

-      gtest_msg = "Expected: " #statement " throws an exception of type " \

-                  #expected_exception ".\n  Actual: it throws a different " \

-                  "type."; \

-      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \

-    } \

-    if (!gtest_caught_expected) { \

-      gtest_msg = "Expected: " #statement " throws an exception of type " \

-                  #expected_exception ".\n  Actual: it throws nothing."; \

-      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \

-    } \

-  } else \

-    GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \

-      fail(gtest_msg)

-

-#define GTEST_TEST_NO_THROW_(statement, fail) \

-  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \

-  if (const char* gtest_msg = "") { \

-    try { \

-      GTEST_HIDE_UNREACHABLE_CODE_(statement); \

-    } \

-    catch (...) { \

-      gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \

-                  "  Actual: it throws."; \

-      goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \

-    } \

-  } else \

-    GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \

-      fail(gtest_msg)

-

-#define GTEST_TEST_ANY_THROW_(statement, fail) \

-  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \

-  if (const char* gtest_msg = "") { \

-    bool gtest_caught_any = false; \

-    try { \

-      GTEST_HIDE_UNREACHABLE_CODE_(statement); \

-    } \

-    catch (...) { \

-      gtest_caught_any = true; \

-    } \

-    if (!gtest_caught_any) { \

-      gtest_msg = "Expected: " #statement " throws an exception.\n" \

-                  "  Actual: it doesn't."; \

-      goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \

-    } \

-  } else \

-    GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \

-      fail(gtest_msg)

-

-

-#define GTEST_TEST_BOOLEAN_(boolexpr, booltext, actual, expected, fail) \

-  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \

-  if (boolexpr) \

-    ; \

-  else \

-    fail("Value of: " booltext "\n  Actual: " #actual "\nExpected: " #expected)

-

-#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \

-  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \

-  if (const char* gtest_msg = "") { \

-    ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \

-    GTEST_HIDE_UNREACHABLE_CODE_(statement); \

-    if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \

-      gtest_msg = "Expected: " #statement " doesn't generate new fatal " \

-                  "failures in the current thread.\n" \

-                  "  Actual: it does."; \

-      goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \

-    } \

-  } else \

-    GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \

-      fail(gtest_msg)

-

-// Expands to the name of the class that implements the given test.

-#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \

-  test_case_name##_##test_name##_Test

-

-// Helper macro for defining tests.

-#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\

-class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\

- public:\

-  GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\

- private:\

-  virtual void TestBody();\

-  static ::testing::TestInfo* const test_info_;\

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(\

-      GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\

-};\

-\

-::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\

-  ::test_info_ =\

-    ::testing::internal::MakeAndRegisterTestInfo(\

-        #test_case_name, #test_name, "", "", \

-        (parent_id), \

-        parent_class::SetUpTestCase, \

-        parent_class::TearDownTestCase, \

-        new ::testing::internal::TestFactoryImpl<\

-            GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\

-void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()

-

-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_

+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares functions and macros used internally by
+// Google Test.  They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_OS_LINUX
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif  // GTEST_OS_LINUX
+
+#include <ctype.h>
+#include <string.h>
+#include <iomanip>
+#include <limits>
+#include <set>
+
+#include <gtest/internal/gtest-string.h>
+#include <gtest/internal/gtest-filepath.h>
+#include <gtest/internal/gtest-type-util.h>
+
+// Due to C++ preprocessor weirdness, we need double indirection to
+// concatenate two tokens when one of them is __LINE__.  Writing
+//
+//   foo ## __LINE__
+//
+// will result in the token foo__LINE__, instead of foo followed by
+// the current line number.  For more details, see
+// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
+#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
+#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
+
+// Google Test defines the testing::Message class to allow construction of
+// test messages via the << operator.  The idea is that anything
+// streamable to std::ostream can be streamed to a testing::Message.
+// This allows a user to use his own types in Google Test assertions by
+// overloading the << operator.
+//
+// util/gtl/stl_logging-inl.h overloads << for STL containers.  These
+// overloads cannot be defined in the std namespace, as that will be
+// undefined behavior.  Therefore, they are defined in the global
+// namespace instead.
+//
+// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
+// overloads are visible in either the std namespace or the global
+// namespace, but not other namespaces, including the testing
+// namespace which Google Test's Message class is in.
+//
+// To allow STL containers (and other types that has a << operator
+// defined in the global namespace) to be used in Google Test assertions,
+// testing::Message must access the custom << operator from the global
+// namespace.  Hence this helper function.
+//
+// Note: Jeffrey Yasskin suggested an alternative fix by "using
+// ::operator<<;" in the definition of Message's operator<<.  That fix
+// doesn't require a helper function, but unfortunately doesn't
+// compile with MSVC.
+template <typename T>
+inline void GTestStreamToHelper(std::ostream* os, const T& val) {
+  *os << val;
+}
+
+namespace testing {
+
+// Forward declaration of classes.
+
+class Message;                         // Represents a failure message.
+class Test;                            // Represents a test.
+class TestCase;                        // A collection of related tests.
+class TestPartResult;                  // Result of a test part.
+class TestInfo;                        // Information about a test.
+class UnitTest;                        // A collection of test cases.
+class UnitTestEventListenerInterface;  // Listens to Google Test events.
+class AssertionResult;                 // Result of an assertion.
+
+namespace internal {
+
+struct TraceInfo;                      // Information about a trace point.
+class ScopedTrace;                     // Implements scoped trace.
+class TestInfoImpl;                    // Opaque implementation of TestInfo
+class TestResult;                      // Result of a single Test.
+class UnitTestImpl;                    // Opaque implementation of UnitTest
+
+template <typename E> class List;      // A generic list.
+template <typename E> class ListNode;  // A node in a generic list.
+
+// How many times InitGoogleTest() has been called.
+extern int g_init_gtest_count;
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+extern const char kStackTraceMarker[];
+
+// A secret type that Google Test users don't know about.  It has no
+// definition on purpose.  Therefore it's impossible to create a
+// Secret object, which is what we want.
+class Secret;
+
+// Two overloaded helpers for checking at compile time whether an
+// expression is a null pointer literal (i.e. NULL or any 0-valued
+// compile-time integral constant).  Their return values have
+// different sizes, so we can use sizeof() to test which version is
+// picked by the compiler.  These helpers have no implementations, as
+// we only need their signatures.
+//
+// Given IsNullLiteralHelper(x), the compiler will pick the first
+// version if x can be implicitly converted to Secret*, and pick the
+// second version otherwise.  Since Secret is a secret and incomplete
+// type, the only expression a user can write that has type Secret* is
+// a null pointer literal.  Therefore, we know that x is a null
+// pointer literal if and only if the first version is picked by the
+// compiler.
+char IsNullLiteralHelper(Secret* p);
+char (&IsNullLiteralHelper(...))[2];  // NOLINT
+
+// A compile-time bool constant that is true if and only if x is a
+// null pointer literal (i.e. NULL or any 0-valued compile-time
+// integral constant).
+#ifdef GTEST_ELLIPSIS_NEEDS_COPY_
+// Passing non-POD classes through ellipsis (...) crashes the ARM
+// compiler.  The Nokia Symbian and the IBM XL C/C++ compiler try to
+// instantiate a copy constructor for objects passed through ellipsis
+// (...), failing for uncopyable objects.  Hence we define this to
+// false (and lose support for NULL detection).
+#define GTEST_IS_NULL_LITERAL_(x) false
+#else
+#define GTEST_IS_NULL_LITERAL_(x) \
+    (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
+#endif  // GTEST_ELLIPSIS_NEEDS_COPY_
+
+// Appends the user-supplied message to the Google-Test-generated message.
+String AppendUserMessage(const String& gtest_msg,
+                         const Message& user_msg);
+
+// A helper class for creating scoped traces in user programs.
+class ScopedTrace {
+ public:
+  // The c'tor pushes the given source file location and message onto
+  // a trace stack maintained by Google Test.
+  ScopedTrace(const char* file, int line, const Message& message);
+
+  // The d'tor pops the info pushed by the c'tor.
+  //
+  // Note that the d'tor is not virtual in order to be efficient.
+  // Don't inherit from ScopedTrace!
+  ~ScopedTrace();
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
+} GTEST_ATTRIBUTE_UNUSED_;  // A ScopedTrace object does its job in its
+                            // c'tor and d'tor.  Therefore it doesn't
+                            // need to be used otherwise.
+
+// Converts a streamable value to a String.  A NULL pointer is
+// converted to "(null)".  When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+// Declared here but defined in gtest.h, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable);
+
+// Formats a value to be used in a failure message.
+
+#ifdef GTEST_NEEDS_IS_POINTER_
+
+// These are needed as the Nokia Symbian and IBM XL C/C++ compilers
+// cannot decide between const T& and const T* in a function template.
+// These compilers _can_ decide between class template specializations
+// for T and T*, so a tr1::type_traits-like is_pointer works, and we
+// can overload on that.
+
+// This overload makes sure that all pointers (including
+// those to char or wchar_t) are printed as raw pointers.
+template <typename T>
+inline String FormatValueForFailureMessage(internal::true_type dummy,
+                                           T* pointer) {
+  return StreamableToString(static_cast<const void*>(pointer));
+}
+
+template <typename T>
+inline String FormatValueForFailureMessage(internal::false_type dummy,
+                                           const T& value) {
+  return StreamableToString(value);
+}
+
+template <typename T>
+inline String FormatForFailureMessage(const T& value) {
+  return FormatValueForFailureMessage(
+      typename internal::is_pointer<T>::type(), value);
+}
+
+#else
+
+// These are needed as the above solution using is_pointer has the
+// limitation that T cannot be a type without external linkage, when
+// compiled using MSVC.
+
+template <typename T>
+inline String FormatForFailureMessage(const T& value) {
+  return StreamableToString(value);
+}
+
+// This overload makes sure that all pointers (including
+// those to char or wchar_t) are printed as raw pointers.
+template <typename T>
+inline String FormatForFailureMessage(T* pointer) {
+  return StreamableToString(static_cast<const void*>(pointer));
+}
+
+#endif  // GTEST_NEEDS_IS_POINTER_
+
+// These overloaded versions handle narrow and wide characters.
+String FormatForFailureMessage(char ch);
+String FormatForFailureMessage(wchar_t wchar);
+
+// When this operand is a const char* or char*, and the other operand
+// is a ::std::string or ::string, we print this operand as a C string
+// rather than a pointer.  We do the same for wide strings.
+
+// This internal macro is used to avoid duplicated code.
+#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\
+inline String FormatForComparisonFailureMessage(\
+    operand2_type::value_type* str, const operand2_type& /*operand2*/) {\
+  return operand1_printer(str);\
+}\
+inline String FormatForComparisonFailureMessage(\
+    const operand2_type::value_type* str, const operand2_type& /*operand2*/) {\
+  return operand1_printer(str);\
+}
+
+#if GTEST_HAS_STD_STRING
+GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted)
+#endif  // GTEST_HAS_STD_STRING
+#if GTEST_HAS_STD_WSTRING
+GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted)
+#endif  // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted)
+#endif  // GTEST_HAS_GLOBAL_STRING
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted)
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+#undef GTEST_FORMAT_IMPL_
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings.  For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+//   expected_expression: "foo"
+//   actual_expression:   "bar"
+//   expected_value:      "5"
+//   actual_value:        "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+                          const char* actual_expression,
+                          const String& expected_value,
+                          const String& actual_value,
+                          bool ignoring_case);
+
+
+// This template class represents an IEEE floating-point number
+// (either single-precision or double-precision, depending on the
+// template parameters).
+//
+// The purpose of this class is to do more sophisticated number
+// comparison.  (Due to round-off error, etc, it's very unlikely that
+// two floating-points will be equal exactly.  Hence a naive
+// comparison by the == operation often doesn't work.)
+//
+// Format of IEEE floating-point:
+//
+//   The most-significant bit being the leftmost, an IEEE
+//   floating-point looks like
+//
+//     sign_bit exponent_bits fraction_bits
+//
+//   Here, sign_bit is a single bit that designates the sign of the
+//   number.
+//
+//   For float, there are 8 exponent bits and 23 fraction bits.
+//
+//   For double, there are 11 exponent bits and 52 fraction bits.
+//
+//   More details can be found at
+//   http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
+//
+// Template parameter:
+//
+//   RawType: the raw floating-point type (either float or double)
+template <typename RawType>
+class FloatingPoint {
+ public:
+  // Defines the unsigned integer type that has the same size as the
+  // floating point number.
+  typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
+
+  // Constants.
+
+  // # of bits in a number.
+  static const size_t kBitCount = 8*sizeof(RawType);
+
+  // # of fraction bits in a number.
+  static const size_t kFractionBitCount =
+    std::numeric_limits<RawType>::digits - 1;
+
+  // # of exponent bits in a number.
+  static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
+
+  // The mask for the sign bit.
+  static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
+
+  // The mask for the fraction bits.
+  static const Bits kFractionBitMask =
+    ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
+
+  // The mask for the exponent bits.
+  static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
+
+  // How many ULP's (Units in the Last Place) we want to tolerate when
+  // comparing two numbers.  The larger the value, the more error we
+  // allow.  A 0 value means that two numbers must be exactly the same
+  // to be considered equal.
+  //
+  // The maximum error of a single floating-point operation is 0.5
+  // units in the last place.  On Intel CPU's, all floating-point
+  // calculations are done with 80-bit precision, while double has 64
+  // bits.  Therefore, 4 should be enough for ordinary use.
+  //
+  // See the following article for more details on ULP:
+  // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.
+  static const size_t kMaxUlps = 4;
+
+  // Constructs a FloatingPoint from a raw floating-point number.
+  //
+  // On an Intel CPU, passing a non-normalized NAN (Not a Number)
+  // around may change its bits, although the new value is guaranteed
+  // to be also a NAN.  Therefore, don't expect this constructor to
+  // preserve the bits in x when x is a NAN.
+  explicit FloatingPoint(const RawType& x) { u_.value_ = x; }
+
+  // Static methods
+
+  // Reinterprets a bit pattern as a floating-point number.
+  //
+  // This function is needed to test the AlmostEquals() method.
+  static RawType ReinterpretBits(const Bits bits) {
+    FloatingPoint fp(0);
+    fp.u_.bits_ = bits;
+    return fp.u_.value_;
+  }
+
+  // Returns the floating-point number that represent positive infinity.
+  static RawType Infinity() {
+    return ReinterpretBits(kExponentBitMask);
+  }
+
+  // Non-static methods
+
+  // Returns the bits that represents this number.
+  const Bits &bits() const { return u_.bits_; }
+
+  // Returns the exponent bits of this number.
+  Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }
+
+  // Returns the fraction bits of this number.
+  Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }
+
+  // Returns the sign bit of this number.
+  Bits sign_bit() const { return kSignBitMask & u_.bits_; }
+
+  // Returns true iff this is NAN (not a number).
+  bool is_nan() const {
+    // It's a NAN if the exponent bits are all ones and the fraction
+    // bits are not entirely zeros.
+    return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
+  }
+
+  // Returns true iff this number is at most kMaxUlps ULP's away from
+  // rhs.  In particular, this function:
+  //
+  //   - returns false if either number is (or both are) NAN.
+  //   - treats really large numbers as almost equal to infinity.
+  //   - thinks +0.0 and -0.0 are 0 DLP's apart.
+  bool AlmostEquals(const FloatingPoint& rhs) const {
+    // The IEEE standard says that any comparison operation involving
+    // a NAN must return false.
+    if (is_nan() || rhs.is_nan()) return false;
+
+    return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
+        <= kMaxUlps;
+  }
+
+ private:
+  // The data type used to store the actual floating-point number.
+  union FloatingPointUnion {
+    RawType value_;  // The raw floating-point number.
+    Bits bits_;      // The bits that represent the number.
+  };
+
+  // Converts an integer from the sign-and-magnitude representation to
+  // the biased representation.  More precisely, let N be 2 to the
+  // power of (kBitCount - 1), an integer x is represented by the
+  // unsigned number x + N.
+  //
+  // For instance,
+  //
+  //   -N + 1 (the most negative number representable using
+  //          sign-and-magnitude) is represented by 1;
+  //   0      is represented by N; and
+  //   N - 1  (the biggest number representable using
+  //          sign-and-magnitude) is represented by 2N - 1.
+  //
+  // Read http://en.wikipedia.org/wiki/Signed_number_representations
+  // for more details on signed number representations.
+  static Bits SignAndMagnitudeToBiased(const Bits &sam) {
+    if (kSignBitMask & sam) {
+      // sam represents a negative number.
+      return ~sam + 1;
+    } else {
+      // sam represents a positive number.
+      return kSignBitMask | sam;
+    }
+  }
+
+  // Given two numbers in the sign-and-magnitude representation,
+  // returns the distance between them as an unsigned number.
+  static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
+                                                     const Bits &sam2) {
+    const Bits biased1 = SignAndMagnitudeToBiased(sam1);
+    const Bits biased2 = SignAndMagnitudeToBiased(sam2);
+    return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
+  }
+
+  FloatingPointUnion u_;
+};
+
+// Typedefs the instances of the FloatingPoint template class that we
+// care to use.
+typedef FloatingPoint<float> Float;
+typedef FloatingPoint<double> Double;
+
+// In order to catch the mistake of putting tests that use different
+// test fixture classes in the same test case, we need to assign
+// unique IDs to fixture classes and compare them.  The TypeId type is
+// used to hold such IDs.  The user should treat TypeId as an opaque
+// type: the only operation allowed on TypeId values is to compare
+// them for equality using the == operator.
+typedef const void* TypeId;
+
+template <typename T>
+class TypeIdHelper {
+ public:
+  // dummy_ must not have a const type.  Otherwise an overly eager
+  // compiler (e.g. MSVC 7.1 & 8.0) may try to merge
+  // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".
+  static bool dummy_;
+};
+
+template <typename T>
+bool TypeIdHelper<T>::dummy_ = false;
+
+// GetTypeId<T>() returns the ID of type T.  Different values will be
+// returned for different types.  Calling the function twice with the
+// same type argument is guaranteed to return the same ID.
+template <typename T>
+TypeId GetTypeId() {
+  // The compiler is required to allocate a different
+  // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
+  // the template.  Therefore, the address of dummy_ is guaranteed to
+  // be unique.
+  return &(TypeIdHelper<T>::dummy_);
+}
+
+// Returns the type ID of ::testing::Test.  Always call this instead
+// of GetTypeId< ::testing::Test>() to get the type ID of
+// ::testing::Test, as the latter may give the wrong result due to a
+// suspected linker bug when compiling Google Test as a Mac OS X
+// framework.
+TypeId GetTestTypeId();
+
+// Defines the abstract factory interface that creates instances
+// of a Test object.
+class TestFactoryBase {
+ public:
+  virtual ~TestFactoryBase() {}
+
+  // Creates a test instance to run. The instance is both created and destroyed
+  // within TestInfoImpl::Run()
+  virtual Test* CreateTest() = 0;
+
+ protected:
+  TestFactoryBase() {}
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
+};
+
+// This class provides implementation of TeastFactoryBase interface.
+// It is used in TEST and TEST_F macros.
+template <class TestClass>
+class TestFactoryImpl : public TestFactoryBase {
+ public:
+  virtual Test* CreateTest() { return new TestClass; }
+};
+
+#if GTEST_OS_WINDOWS
+
+// Predicate-formatters for implementing the HRESULT checking macros
+// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
+// We pass a long instead of HRESULT to avoid causing an
+// include dependency for the HRESULT type.
+AssertionResult IsHRESULTSuccess(const char* expr, long hr);  // NOLINT
+AssertionResult IsHRESULTFailure(const char* expr, long hr);  // NOLINT
+
+#endif  // GTEST_OS_WINDOWS
+
+// Formats a source file path and a line number as they would appear
+// in a compiler error message.
+inline String FormatFileLocation(const char* file, int line) {
+  const char* const file_name = file == NULL ? "unknown file" : file;
+  if (line < 0) {
+    return String::Format("%s:", file_name);
+  }
+#ifdef _MSC_VER
+  return String::Format("%s(%d):", file_name, line);
+#else
+  return String::Format("%s:%d:", file_name, line);
+#endif  // _MSC_VER
+}
+
+// Types of SetUpTestCase() and TearDownTestCase() functions.
+typedef void (*SetUpTestCaseFunc)();
+typedef void (*TearDownTestCaseFunc)();
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+//   test_case_name:   name of the test case
+//   name:             name of the test
+//   test_case_comment: a comment on the test case that will be included in
+//                      the test output
+//   comment:          a comment on the test that will be included in the
+//                     test output
+//   fixture_class_id: ID of the test fixture class
+//   set_up_tc:        pointer to the function that sets up the test case
+//   tear_down_tc:     pointer to the function that tears down the test case
+//   factory:          pointer to the factory that creates a test object.
+//                     The newly created TestInfo instance will assume
+//                     ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+    const char* test_case_name, const char* name,
+    const char* test_case_comment, const char* comment,
+    TypeId fixture_class_id,
+    SetUpTestCaseFunc set_up_tc,
+    TearDownTestCaseFunc tear_down_tc,
+    TestFactoryBase* factory);
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// State of the definition of a type-parameterized test case.
+class TypedTestCasePState {
+ public:
+  TypedTestCasePState() : registered_(false) {}
+
+  // Adds the given test name to defined_test_names_ and return true
+  // if the test case hasn't been registered; otherwise aborts the
+  // program.
+  bool AddTestName(const char* file, int line, const char* case_name,
+                   const char* test_name) {
+    if (registered_) {
+      fprintf(stderr, "%s Test %s must be defined before "
+              "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
+              FormatFileLocation(file, line).c_str(), test_name, case_name);
+      fflush(stderr);
+      abort();
+    }
+    defined_test_names_.insert(test_name);
+    return true;
+  }
+
+  // Verifies that registered_tests match the test names in
+  // defined_test_names_; returns registered_tests if successful, or
+  // aborts the program otherwise.
+  const char* VerifyRegisteredTestNames(
+      const char* file, int line, const char* registered_tests);
+
+ private:
+  bool registered_;
+  ::std::set<const char*> defined_test_names_;
+};
+
+// Skips to the first non-space char after the first comma in 'str';
+// returns NULL if no comma is found in 'str'.
+inline const char* SkipComma(const char* str) {
+  const char* comma = strchr(str, ',');
+  if (comma == NULL) {
+    return NULL;
+  }
+  while (isspace(*(++comma))) {}
+  return comma;
+}
+
+// Returns the prefix of 'str' before the first comma in it; returns
+// the entire string if it contains no comma.
+inline String GetPrefixUntilComma(const char* str) {
+  const char* comma = strchr(str, ',');
+  return comma == NULL ? String(str) : String(str, comma - str);
+}
+
+// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
+// registers a list of type-parameterized tests with Google Test.  The
+// return value is insignificant - we just need to return something
+// such that we can call this function in a namespace scope.
+//
+// Implementation note: The GTEST_TEMPLATE_ macro declares a template
+// template parameter.  It's defined in gtest-type-util.h.
+template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
+class TypeParameterizedTest {
+ public:
+  // 'index' is the index of the test in the type list 'Types'
+  // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
+  // Types).  Valid values for 'index' are [0, N - 1] where N is the
+  // length of Types.
+  static bool Register(const char* prefix, const char* case_name,
+                       const char* test_names, int index) {
+    typedef typename Types::Head Type;
+    typedef Fixture<Type> FixtureClass;
+    typedef typename GTEST_BIND_(TestSel, Type) TestClass;
+
+    // First, registers the first type-parameterized test in the type
+    // list.
+    MakeAndRegisterTestInfo(
+        String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/",
+                       case_name, index).c_str(),
+        GetPrefixUntilComma(test_names).c_str(),
+        String::Format("TypeParam = %s", GetTypeName<Type>().c_str()).c_str(),
+        "",
+        GetTypeId<FixtureClass>(),
+        TestClass::SetUpTestCase,
+        TestClass::TearDownTestCase,
+        new TestFactoryImpl<TestClass>);
+
+    // Next, recurses (at compile time) with the tail of the type list.
+    return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
+        ::Register(prefix, case_name, test_names, index + 1);
+  }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, class TestSel>
+class TypeParameterizedTest<Fixture, TestSel, Types0> {
+ public:
+  static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+                       const char* /*test_names*/, int /*index*/) {
+    return true;
+  }
+};
+
+// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
+// registers *all combinations* of 'Tests' and 'Types' with Google
+// Test.  The return value is insignificant - we just need to return
+// something such that we can call this function in a namespace scope.
+template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
+class TypeParameterizedTestCase {
+ public:
+  static bool Register(const char* prefix, const char* case_name,
+                       const char* test_names) {
+    typedef typename Tests::Head Head;
+
+    // First, register the first test in 'Test' for each type in 'Types'.
+    TypeParameterizedTest<Fixture, Head, Types>::Register(
+        prefix, case_name, test_names, 0);
+
+    // Next, recurses (at compile time) with the tail of the test list.
+    return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
+        ::Register(prefix, case_name, SkipComma(test_names));
+  }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, typename Types>
+class TypeParameterizedTestCase<Fixture, Templates0, Types> {
+ public:
+  static bool Register(const char* prefix, const char* case_name,
+                       const char* test_names) {
+    return true;
+  }
+};
+
+#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag.  The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count);
+
+// Returns the number of failed test parts in the given test result object.
+int GetFailedPartCount(const TestResult* result);
+
+// A helper for suppressing warnings on unreachable code in some macros.
+bool AlwaysTrue();
+
+}  // namespace internal
+}  // namespace testing
+
+#define GTEST_MESSAGE_(message, result_type) \
+  ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \
+    = ::testing::Message()
+
+#define GTEST_FATAL_FAILURE_(message) \
+  return GTEST_MESSAGE_(message, ::testing::TPRT_FATAL_FAILURE)
+
+#define GTEST_NONFATAL_FAILURE_(message) \
+  GTEST_MESSAGE_(message, ::testing::TPRT_NONFATAL_FAILURE)
+
+#define GTEST_SUCCESS_(message) \
+  GTEST_MESSAGE_(message, ::testing::TPRT_SUCCESS)
+
+// Suppresses MSVC warnings 4072 (unreachable code) for the code following
+// statement if it returns or throws (or doesn't return or throw in some
+// situations).
+#define GTEST_HIDE_UNREACHABLE_CODE_(statement) \
+  if (::testing::internal::AlwaysTrue()) { statement; }
+
+#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (const char* gtest_msg = "") { \
+    bool gtest_caught_expected = false; \
+    try { \
+      GTEST_HIDE_UNREACHABLE_CODE_(statement); \
+    } \
+    catch (expected_exception const&) { \
+      gtest_caught_expected = true; \
+    } \
+    catch (...) { \
+      gtest_msg = "Expected: " #statement " throws an exception of type " \
+                  #expected_exception ".\n  Actual: it throws a different " \
+                  "type."; \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+    } \
+    if (!gtest_caught_expected) { \
+      gtest_msg = "Expected: " #statement " throws an exception of type " \
+                  #expected_exception ".\n  Actual: it throws nothing."; \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
+      fail(gtest_msg)
+
+#define GTEST_TEST_NO_THROW_(statement, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (const char* gtest_msg = "") { \
+    try { \
+      GTEST_HIDE_UNREACHABLE_CODE_(statement); \
+    } \
+    catch (...) { \
+      gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \
+                  "  Actual: it throws."; \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
+      fail(gtest_msg)
+
+#define GTEST_TEST_ANY_THROW_(statement, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (const char* gtest_msg = "") { \
+    bool gtest_caught_any = false; \
+    try { \
+      GTEST_HIDE_UNREACHABLE_CODE_(statement); \
+    } \
+    catch (...) { \
+      gtest_caught_any = true; \
+    } \
+    if (!gtest_caught_any) { \
+      gtest_msg = "Expected: " #statement " throws an exception.\n" \
+                  "  Actual: it doesn't."; \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
+      fail(gtest_msg)
+
+
+#define GTEST_TEST_BOOLEAN_(boolexpr, booltext, actual, expected, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (boolexpr) \
+    ; \
+  else \
+    fail("Value of: " booltext "\n  Actual: " #actual "\nExpected: " #expected)
+
+#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+  if (const char* gtest_msg = "") { \
+    ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
+    GTEST_HIDE_UNREACHABLE_CODE_(statement); \
+    if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
+      gtest_msg = "Expected: " #statement " doesn't generate new fatal " \
+                  "failures in the current thread.\n" \
+                  "  Actual: it does."; \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
+    } \
+  } else \
+    GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
+      fail(gtest_msg)
+
+// Expands to the name of the class that implements the given test.
+#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+  test_case_name##_##test_name##_Test
+
+// Helper macro for defining tests.
+#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
+class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
+ public:\
+  GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
+ private:\
+  virtual void TestBody();\
+  static ::testing::TestInfo* const test_info_;\
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+      GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
+};\
+\
+::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
+  ::test_info_ =\
+    ::testing::internal::MakeAndRegisterTestInfo(\
+        #test_case_name, #test_name, "", "", \
+        (parent_id), \
+        parent_class::SetUpTestCase, \
+        parent_class::TearDownTestCase, \
+        new ::testing::internal::TestFactoryImpl<\
+            GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
diff --git a/third_party/gtest/include/gtest/internal/gtest-linked_ptr.h b/third_party/gtest/include/gtest/internal/gtest-linked_ptr.h
index 39c4ab6..f98af0b 100644
--- a/third_party/gtest/include/gtest/internal/gtest-linked_ptr.h
+++ b/third_party/gtest/include/gtest/internal/gtest-linked_ptr.h
@@ -1,242 +1,242 @@
-// Copyright 2003 Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Authors: Dan Egnor (egnor@google.com)

-//

-// A "smart" pointer type with reference tracking.  Every pointer to a

-// particular object is kept on a circular linked list.  When the last pointer

-// to an object is destroyed or reassigned, the object is deleted.

-//

-// Used properly, this deletes the object when the last reference goes away.

-// There are several caveats:

-// - Like all reference counting schemes, cycles lead to leaks.

-// - Each smart pointer is actually two pointers (8 bytes instead of 4).

-// - Every time a pointer is assigned, the entire list of pointers to that

-//   object is traversed.  This class is therefore NOT SUITABLE when there

-//   will often be more than two or three pointers to a particular object.

-// - References are only tracked as long as linked_ptr<> objects are copied.

-//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS

-//   will happen (double deletion).

-//

-// A good use of this class is storing object references in STL containers.

-// You can safely put linked_ptr<> in a vector<>.

-// Other uses may not be as good.

-//

-// Note: If you use an incomplete type with linked_ptr<>, the class

-// *containing* linked_ptr<> must have a constructor and destructor (even

-// if they do nothing!).

-//

-// Bill Gibbons suggested we use something like this.

-//

-// Thread Safety:

-//   Unlike other linked_ptr implementations, in this implementation

-//   a linked_ptr object is thread-safe in the sense that:

-//     - it's safe to copy linked_ptr objects concurrently,

-//     - it's safe to copy *from* a linked_ptr and read its underlying

-//       raw pointer (e.g. via get()) concurrently, and

-//     - it's safe to write to two linked_ptrs that point to the same

-//       shared object concurrently.

-// TODO(wan@google.com): rename this to safe_linked_ptr to avoid

-// confusion with normal linked_ptr.

-

-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_

-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_

-

-#include <stdlib.h>

-#include <assert.h>

-

-#include <gtest/internal/gtest-port.h>

-

-namespace testing {

-namespace internal {

-

-// Protects copying of all linked_ptr objects.

-extern Mutex g_linked_ptr_mutex;

-

-// This is used internally by all instances of linked_ptr<>.  It needs to be

-// a non-template class because different types of linked_ptr<> can refer to

-// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).

-// So, it needs to be possible for different types of linked_ptr to participate

-// in the same circular linked list, so we need a single class type here.

-//

-// DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.

-class linked_ptr_internal {

- public:

-  // Create a new circle that includes only this instance.

-  void join_new() {

-    next_ = this;

-  }

-

-  // Many linked_ptr operations may change p.link_ for some linked_ptr

-  // variable p in the same circle as this object.  Therefore we need

-  // to prevent two such operations from occurring concurrently.

-  //

-  // Note that different types of linked_ptr objects can coexist in a

-  // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and

-  // linked_ptr<Derived2>).  Therefore we must use a single mutex to

-  // protect all linked_ptr objects.  This can create serious

-  // contention in production code, but is acceptable in a testing

-  // framework.

-

-  // Join an existing circle.

-  // L < g_linked_ptr_mutex

-  void join(linked_ptr_internal const* ptr) {

-    MutexLock lock(&g_linked_ptr_mutex);

-

-    linked_ptr_internal const* p = ptr;

-    while (p->next_ != ptr) p = p->next_;

-    p->next_ = this;

-    next_ = ptr;

-  }

-

-  // Leave whatever circle we're part of.  Returns true if we were the

-  // last member of the circle.  Once this is done, you can join() another.

-  // L < g_linked_ptr_mutex

-  bool depart() {

-    MutexLock lock(&g_linked_ptr_mutex);

-

-    if (next_ == this) return true;

-    linked_ptr_internal const* p = next_;

-    while (p->next_ != this) p = p->next_;

-    p->next_ = next_;

-    return false;

-  }

-

- private:

-  mutable linked_ptr_internal const* next_;

-};

-

-template <typename T>

-class linked_ptr {

- public:

-  typedef T element_type;

-

-  // Take over ownership of a raw pointer.  This should happen as soon as

-  // possible after the object is created.

-  explicit linked_ptr(T* ptr = NULL) { capture(ptr); }

-  ~linked_ptr() { depart(); }

-

-  // Copy an existing linked_ptr<>, adding ourselves to the list of references.

-  template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }

-  linked_ptr(linked_ptr const& ptr) {  // NOLINT

-    assert(&ptr != this);

-    copy(&ptr);

-  }

-

-  // Assignment releases the old value and acquires the new.

-  template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {

-    depart();

-    copy(&ptr);

-    return *this;

-  }

-

-  linked_ptr& operator=(linked_ptr const& ptr) {

-    if (&ptr != this) {

-      depart();

-      copy(&ptr);

-    }

-    return *this;

-  }

-

-  // Smart pointer members.

-  void reset(T* ptr = NULL) {

-    depart();

-    capture(ptr);

-  }

-  T* get() const { return value_; }

-  T* operator->() const { return value_; }

-  T& operator*() const { return *value_; }

-  // Release ownership of the pointed object and returns it.

-  // Sole ownership by this linked_ptr object is required.

-  T* release() {

-    bool last = link_.depart();

-    assert(last);

-    T* v = value_;

-    value_ = NULL;

-    return v;

-  }

-

-  bool operator==(T* p) const { return value_ == p; }

-  bool operator!=(T* p) const { return value_ != p; }

-  template <typename U>

-  bool operator==(linked_ptr<U> const& ptr) const {

-    return value_ == ptr.get();

-  }

-  template <typename U>

-  bool operator!=(linked_ptr<U> const& ptr) const {

-    return value_ != ptr.get();

-  }

-

- private:

-  template <typename U>

-  friend class linked_ptr;

-

-  T* value_;

-  linked_ptr_internal link_;

-

-  void depart() {

-    if (link_.depart()) delete value_;

-  }

-

-  void capture(T* ptr) {

-    value_ = ptr;

-    link_.join_new();

-  }

-

-  template <typename U> void copy(linked_ptr<U> const* ptr) {

-    value_ = ptr->get();

-    if (value_)

-      link_.join(&ptr->link_);

-    else

-      link_.join_new();

-  }

-};

-

-template<typename T> inline

-bool operator==(T* ptr, const linked_ptr<T>& x) {

-  return ptr == x.get();

-}

-

-template<typename T> inline

-bool operator!=(T* ptr, const linked_ptr<T>& x) {

-  return ptr != x.get();

-}

-

-// A function to convert T* into linked_ptr<T>

-// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation

-// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))

-template <typename T>

-linked_ptr<T> make_linked_ptr(T* ptr) {

-  return linked_ptr<T>(ptr);

-}

-

-}  // namespace internal

-}  // namespace testing

-

-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_

+// Copyright 2003 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Dan Egnor (egnor@google.com)
+//
+// A "smart" pointer type with reference tracking.  Every pointer to a
+// particular object is kept on a circular linked list.  When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is assigned, the entire list of pointers to that
+//   object is traversed.  This class is therefore NOT SUITABLE when there
+//   will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+//   will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Bill Gibbons suggested we use something like this.
+//
+// Thread Safety:
+//   Unlike other linked_ptr implementations, in this implementation
+//   a linked_ptr object is thread-safe in the sense that:
+//     - it's safe to copy linked_ptr objects concurrently,
+//     - it's safe to copy *from* a linked_ptr and read its underlying
+//       raw pointer (e.g. via get()) concurrently, and
+//     - it's safe to write to two linked_ptrs that point to the same
+//       shared object concurrently.
+// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
+// confusion with normal linked_ptr.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include <gtest/internal/gtest-port.h>
+
+namespace testing {
+namespace internal {
+
+// Protects copying of all linked_ptr objects.
+extern Mutex g_linked_ptr_mutex;
+
+// This is used internally by all instances of linked_ptr<>.  It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.
+class linked_ptr_internal {
+ public:
+  // Create a new circle that includes only this instance.
+  void join_new() {
+    next_ = this;
+  }
+
+  // Many linked_ptr operations may change p.link_ for some linked_ptr
+  // variable p in the same circle as this object.  Therefore we need
+  // to prevent two such operations from occurring concurrently.
+  //
+  // Note that different types of linked_ptr objects can coexist in a
+  // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
+  // linked_ptr<Derived2>).  Therefore we must use a single mutex to
+  // protect all linked_ptr objects.  This can create serious
+  // contention in production code, but is acceptable in a testing
+  // framework.
+
+  // Join an existing circle.
+  // L < g_linked_ptr_mutex
+  void join(linked_ptr_internal const* ptr) {
+    MutexLock lock(&g_linked_ptr_mutex);
+
+    linked_ptr_internal const* p = ptr;
+    while (p->next_ != ptr) p = p->next_;
+    p->next_ = this;
+    next_ = ptr;
+  }
+
+  // Leave whatever circle we're part of.  Returns true if we were the
+  // last member of the circle.  Once this is done, you can join() another.
+  // L < g_linked_ptr_mutex
+  bool depart() {
+    MutexLock lock(&g_linked_ptr_mutex);
+
+    if (next_ == this) return true;
+    linked_ptr_internal const* p = next_;
+    while (p->next_ != this) p = p->next_;
+    p->next_ = next_;
+    return false;
+  }
+
+ private:
+  mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr {
+ public:
+  typedef T element_type;
+
+  // Take over ownership of a raw pointer.  This should happen as soon as
+  // possible after the object is created.
+  explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+  ~linked_ptr() { depart(); }
+
+  // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+  template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
+  linked_ptr(linked_ptr const& ptr) {  // NOLINT
+    assert(&ptr != this);
+    copy(&ptr);
+  }
+
+  // Assignment releases the old value and acquires the new.
+  template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
+    depart();
+    copy(&ptr);
+    return *this;
+  }
+
+  linked_ptr& operator=(linked_ptr const& ptr) {
+    if (&ptr != this) {
+      depart();
+      copy(&ptr);
+    }
+    return *this;
+  }
+
+  // Smart pointer members.
+  void reset(T* ptr = NULL) {
+    depart();
+    capture(ptr);
+  }
+  T* get() const { return value_; }
+  T* operator->() const { return value_; }
+  T& operator*() const { return *value_; }
+  // Release ownership of the pointed object and returns it.
+  // Sole ownership by this linked_ptr object is required.
+  T* release() {
+    bool last = link_.depart();
+    assert(last);
+    T* v = value_;
+    value_ = NULL;
+    return v;
+  }
+
+  bool operator==(T* p) const { return value_ == p; }
+  bool operator!=(T* p) const { return value_ != p; }
+  template <typename U>
+  bool operator==(linked_ptr<U> const& ptr) const {
+    return value_ == ptr.get();
+  }
+  template <typename U>
+  bool operator!=(linked_ptr<U> const& ptr) const {
+    return value_ != ptr.get();
+  }
+
+ private:
+  template <typename U>
+  friend class linked_ptr;
+
+  T* value_;
+  linked_ptr_internal link_;
+
+  void depart() {
+    if (link_.depart()) delete value_;
+  }
+
+  void capture(T* ptr) {
+    value_ = ptr;
+    link_.join_new();
+  }
+
+  template <typename U> void copy(linked_ptr<U> const* ptr) {
+    value_ = ptr->get();
+    if (value_)
+      link_.join(&ptr->link_);
+    else
+      link_.join_new();
+  }
+};
+
+template<typename T> inline
+bool operator==(T* ptr, const linked_ptr<T>& x) {
+  return ptr == x.get();
+}
+
+template<typename T> inline
+bool operator!=(T* ptr, const linked_ptr<T>& x) {
+  return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr) {
+  return linked_ptr<T>(ptr);
+}
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
diff --git a/third_party/gtest/include/gtest/internal/gtest-param-util-generated.h b/third_party/gtest/include/gtest/internal/gtest-param-util-generated.h
index f6edda4..ad06e02 100644
--- a/third_party/gtest/include/gtest/internal/gtest-param-util-generated.h
+++ b/third_party/gtest/include/gtest/internal/gtest-param-util-generated.h
@@ -1,4572 +1,4572 @@
-// This file was GENERATED by a script.  DO NOT EDIT BY HAND!!!

-

-// Copyright 2008 Google Inc.

-// All Rights Reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: vladl@google.com (Vlad Losev)

-

-// Type and function utilities for implementing parameterized tests.

-// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!

-//

-// Currently Google Test supports at most 50 arguments in Values,

-// and at most 10 arguments in Combine. Please contact

-// googletestframework@googlegroups.com if you need more.

-// Please note that the number of arguments to Combine is limited

-// by the maximum arity of the implementation of tr1::tuple which is

-// currently set at 10.

-

-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_

-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_

-

-#include <gtest/internal/gtest-port.h>

-

-#if GTEST_HAS_PARAM_TEST

-

-#include <gtest/internal/gtest-param-util.h>

-

-namespace testing {

-namespace internal {

-

-// Used in the Values() function to provide polymorphic capabilities.

-template <typename T1>

-class ValueArray1 {

- public:

-  explicit ValueArray1(T1 v1) : v1_(v1) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }

-

- private:

-  const T1 v1_;

-};

-

-template <typename T1, typename T2>

-class ValueArray2 {

- public:

-  ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-};

-

-template <typename T1, typename T2, typename T3>

-class ValueArray3 {

- public:

-  ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4>

-class ValueArray4 {

- public:

-  ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),

-      v4_(v4) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5>

-class ValueArray5 {

- public:

-  ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),

-      v4_(v4), v5_(v5) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6>

-class ValueArray6 {

- public:

-  ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),

-      v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7>

-class ValueArray7 {

- public:

-  ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),

-      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8>

-class ValueArray8 {

- public:

-  ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,

-      T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9>

-class ValueArray9 {

- public:

-  ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,

-      T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10>

-class ValueArray10 {

- public:

-  ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11>

-class ValueArray11 {

- public:

-  ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),

-      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12>

-class ValueArray12 {

- public:

-  ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),

-      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13>

-class ValueArray13 {

- public:

-  ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),

-      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),

-      v12_(v12), v13_(v13) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14>

-class ValueArray14 {

- public:

-  ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),

-      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),

-      v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15>

-class ValueArray15 {

- public:

-  ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),

-      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),

-      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16>

-class ValueArray16 {

- public:

-  ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),

-      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),

-      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),

-      v16_(v16) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17>

-class ValueArray17 {

- public:

-  ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,

-      T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),

-      v15_(v15), v16_(v16), v17_(v17) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18>

-class ValueArray18 {

- public:

-  ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),

-      v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19>

-class ValueArray19 {

- public:

-  ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),

-      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),

-      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20>

-class ValueArray20 {

- public:

-  ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),

-      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),

-      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),

-      v19_(v19), v20_(v20) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21>

-class ValueArray21 {

- public:

-  ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),

-      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),

-      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),

-      v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22>

-class ValueArray22 {

- public:

-  ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),

-      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),

-      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),

-      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23>

-class ValueArray23 {

- public:

-  ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),

-      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),

-      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),

-      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),

-      v23_(v23) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_,

-        v23_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24>

-class ValueArray24 {

- public:

-  ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),

-      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),

-      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),

-      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),

-      v22_(v22), v23_(v23), v24_(v24) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25>

-class ValueArray25 {

- public:

-  ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,

-      T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),

-      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),

-      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26>

-class ValueArray26 {

- public:

-  ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),

-      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),

-      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27>

-class ValueArray27 {

- public:

-  ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),

-      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),

-      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),

-      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),

-      v26_(v26), v27_(v27) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28>

-class ValueArray28 {

- public:

-  ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),

-      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),

-      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),

-      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),

-      v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29>

-class ValueArray29 {

- public:

-  ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),

-      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),

-      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),

-      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),

-      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30>

-class ValueArray30 {

- public:

-  ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),

-      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),

-      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),

-      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),

-      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),

-      v29_(v29), v30_(v30) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31>

-class ValueArray31 {

- public:

-  ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),

-      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),

-      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),

-      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),

-      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),

-      v29_(v29), v30_(v30), v31_(v31) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32>

-class ValueArray32 {

- public:

-  ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),

-      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),

-      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),

-      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),

-      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),

-      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33>

-class ValueArray33 {

- public:

-  ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,

-      T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),

-      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),

-      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),

-      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),

-      v33_(v33) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34>

-class ValueArray34 {

- public:

-  ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),

-      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),

-      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),

-      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),

-      v33_(v33), v34_(v34) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35>

-class ValueArray35 {

- public:

-  ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),

-      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),

-      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),

-      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),

-      v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),

-      v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_,

-        v35_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36>

-class ValueArray36 {

- public:

-  ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),

-      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),

-      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),

-      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),

-      v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),

-      v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37>

-class ValueArray37 {

- public:

-  ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),

-      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),

-      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),

-      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),

-      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),

-      v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),

-      v36_(v36), v37_(v37) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38>

-class ValueArray38 {

- public:

-  ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),

-      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),

-      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),

-      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),

-      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),

-      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),

-      v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39>

-class ValueArray39 {

- public:

-  ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),

-      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),

-      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),

-      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),

-      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),

-      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),

-      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40>

-class ValueArray40 {

- public:

-  ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),

-      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),

-      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),

-      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),

-      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),

-      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),

-      v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),

-      v40_(v40) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41>

-class ValueArray41 {

- public:

-  ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,

-      T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),

-      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),

-      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),

-      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),

-      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),

-      v39_(v39), v40_(v40), v41_(v41) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_, v41_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-  const T41 v41_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42>

-class ValueArray42 {

- public:

-  ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-      T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),

-      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),

-      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),

-      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),

-      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),

-      v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_, v41_, v42_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-  const T41 v41_;

-  const T42 v42_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43>

-class ValueArray43 {

- public:

-  ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-      T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),

-      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),

-      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),

-      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),

-      v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),

-      v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),

-      v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-  const T41 v41_;

-  const T42 v42_;

-  const T43 v43_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44>

-class ValueArray44 {

- public:

-  ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-      T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),

-      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),

-      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),

-      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),

-      v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),

-      v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),

-      v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),

-      v43_(v43), v44_(v44) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-  const T41 v41_;

-  const T42 v42_;

-  const T43 v43_;

-  const T44 v44_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45>

-class ValueArray45 {

- public:

-  ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-      T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),

-      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),

-      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),

-      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),

-      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),

-      v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),

-      v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),

-      v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-  const T41 v41_;

-  const T42 v42_;

-  const T43 v43_;

-  const T44 v44_;

-  const T45 v45_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46>

-class ValueArray46 {

- public:

-  ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),

-      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),

-      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),

-      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),

-      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),

-      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),

-      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),

-      v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-  const T41 v41_;

-  const T42 v42_;

-  const T43 v43_;

-  const T44 v44_;

-  const T45 v45_;

-  const T46 v46_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47>

-class ValueArray47 {

- public:

-  ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),

-      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),

-      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),

-      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),

-      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),

-      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),

-      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),

-      v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),

-      v47_(v47) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_,

-        v47_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-  const T41 v41_;

-  const T42 v42_;

-  const T43 v43_;

-  const T44 v44_;

-  const T45 v45_;

-  const T46 v46_;

-  const T47 v47_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48>

-class ValueArray48 {

- public:

-  ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),

-      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),

-      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),

-      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),

-      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),

-      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),

-      v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),

-      v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),

-      v46_(v46), v47_(v47), v48_(v48) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,

-        v48_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-  const T41 v41_;

-  const T42 v42_;

-  const T43 v43_;

-  const T44 v44_;

-  const T45 v45_;

-  const T46 v46_;

-  const T47 v47_;

-  const T48 v48_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48, typename T49>

-class ValueArray49 {

- public:

-  ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,

-      T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),

-      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),

-      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),

-      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),

-      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),

-      v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),

-      v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,

-        v48_, v49_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-  const T41 v41_;

-  const T42 v42_;

-  const T43 v43_;

-  const T44 v44_;

-  const T45 v45_;

-  const T46 v46_;

-  const T47 v47_;

-  const T48 v48_;

-  const T49 v49_;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48, typename T49, typename T50>

-class ValueArray50 {

- public:

-  ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,

-      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,

-      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,

-      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,

-      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,

-      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,

-      T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),

-      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),

-      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),

-      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),

-      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),

-      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),

-      v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),

-      v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}

-

-  template <typename T>

-  operator ParamGenerator<T>() const {

-    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,

-        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,

-        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,

-        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,

-        v48_, v49_, v50_};

-    return ValuesIn(array);

-  }

-

- private:

-  const T1 v1_;

-  const T2 v2_;

-  const T3 v3_;

-  const T4 v4_;

-  const T5 v5_;

-  const T6 v6_;

-  const T7 v7_;

-  const T8 v8_;

-  const T9 v9_;

-  const T10 v10_;

-  const T11 v11_;

-  const T12 v12_;

-  const T13 v13_;

-  const T14 v14_;

-  const T15 v15_;

-  const T16 v16_;

-  const T17 v17_;

-  const T18 v18_;

-  const T19 v19_;

-  const T20 v20_;

-  const T21 v21_;

-  const T22 v22_;

-  const T23 v23_;

-  const T24 v24_;

-  const T25 v25_;

-  const T26 v26_;

-  const T27 v27_;

-  const T28 v28_;

-  const T29 v29_;

-  const T30 v30_;

-  const T31 v31_;

-  const T32 v32_;

-  const T33 v33_;

-  const T34 v34_;

-  const T35 v35_;

-  const T36 v36_;

-  const T37 v37_;

-  const T38 v38_;

-  const T39 v39_;

-  const T40 v40_;

-  const T41 v41_;

-  const T42 v42_;

-  const T43 v43_;

-  const T44 v44_;

-  const T45 v45_;

-  const T46 v46_;

-  const T47 v47_;

-  const T48 v48_;

-  const T49 v49_;

-  const T50 v50_;

-};

-

-#if GTEST_HAS_COMBINE

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// Generates values from the Cartesian product of values produced

-// by the argument generators.

-//

-template <typename T1, typename T2>

-class CartesianProductGenerator2

-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {

- public:

-  typedef ::std::tr1::tuple<T1, T2> ParamType;

-

-  CartesianProductGenerator2(const ParamGenerator<T1>& g1,

-      const ParamGenerator<T2>& g2)

-      : g1_(g1), g2_(g2) {}

-  virtual ~CartesianProductGenerator2() {}

-

-  virtual ParamIteratorInterface<ParamType>* Begin() const {

-    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());

-  }

-  virtual ParamIteratorInterface<ParamType>* End() const {

-    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());

-  }

-

- private:

-  class Iterator : public ParamIteratorInterface<ParamType> {

-   public:

-    Iterator(const ParamGeneratorInterface<ParamType>* base,

-      const ParamGenerator<T1>& g1,

-      const typename ParamGenerator<T1>::iterator& current1,

-      const ParamGenerator<T2>& g2,

-      const typename ParamGenerator<T2>::iterator& current2)

-        : base_(base),

-          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),

-          begin2_(g2.begin()), end2_(g2.end()), current2_(current2)    {

-      ComputeCurrentValue();

-    }

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {

-      return base_;

-    }

-    // Advance should not be called on beyond-of-range iterators

-    // so no component iterators must be beyond end of range, either.

-    virtual void Advance() {

-      assert(!AtEnd());

-      ++current2_;

-      if (current2_ == end2_) {

-        current2_ = begin2_;

-        ++current1_;

-      }

-      ComputeCurrentValue();

-    }

-    virtual ParamIteratorInterface<ParamType>* Clone() const {

-      return new Iterator(*this);

-    }

-    virtual const ParamType* Current() const { return &current_value_; }

-    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      const Iterator* typed_other =

-          CheckedDowncastToActualType<const Iterator>(&other);

-      // We must report iterators equal if they both point beyond their

-      // respective ranges. That can happen in a variety of fashions,

-      // so we have to consult AtEnd().

-      return (AtEnd() && typed_other->AtEnd()) ||

-         (

-          current1_ == typed_other->current1_ &&

-          current2_ == typed_other->current2_);

-    }

-

-   private:

-    Iterator(const Iterator& other)

-        : base_(other.base_),

-        begin1_(other.begin1_),

-        end1_(other.end1_),

-        current1_(other.current1_),

-        begin2_(other.begin2_),

-        end2_(other.end2_),

-        current2_(other.current2_) {

-      ComputeCurrentValue();

-    }

-

-    void ComputeCurrentValue() {

-      if (!AtEnd())

-        current_value_ = ParamType(*current1_, *current2_);

-    }

-    bool AtEnd() const {

-      // We must report iterator past the end of the range when either of the

-      // component iterators has reached the end of its range.

-      return

-          current1_ == end1_ ||

-          current2_ == end2_;

-    }

-

-    const ParamGeneratorInterface<ParamType>* const base_;

-    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.

-    // current[i]_ is the actual traversing iterator.

-    const typename ParamGenerator<T1>::iterator begin1_;

-    const typename ParamGenerator<T1>::iterator end1_;

-    typename ParamGenerator<T1>::iterator current1_;

-    const typename ParamGenerator<T2>::iterator begin2_;

-    const typename ParamGenerator<T2>::iterator end2_;

-    typename ParamGenerator<T2>::iterator current2_;

-    ParamType current_value_;

-  };

-

-  const ParamGenerator<T1> g1_;

-  const ParamGenerator<T2> g2_;

-};

-

-

-template <typename T1, typename T2, typename T3>

-class CartesianProductGenerator3

-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {

- public:

-  typedef ::std::tr1::tuple<T1, T2, T3> ParamType;

-

-  CartesianProductGenerator3(const ParamGenerator<T1>& g1,

-      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)

-      : g1_(g1), g2_(g2), g3_(g3) {}

-  virtual ~CartesianProductGenerator3() {}

-

-  virtual ParamIteratorInterface<ParamType>* Begin() const {

-    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,

-        g3_.begin());

-  }

-  virtual ParamIteratorInterface<ParamType>* End() const {

-    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());

-  }

-

- private:

-  class Iterator : public ParamIteratorInterface<ParamType> {

-   public:

-    Iterator(const ParamGeneratorInterface<ParamType>* base,

-      const ParamGenerator<T1>& g1,

-      const typename ParamGenerator<T1>::iterator& current1,

-      const ParamGenerator<T2>& g2,

-      const typename ParamGenerator<T2>::iterator& current2,

-      const ParamGenerator<T3>& g3,

-      const typename ParamGenerator<T3>::iterator& current3)

-        : base_(base),

-          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),

-          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),

-          begin3_(g3.begin()), end3_(g3.end()), current3_(current3)    {

-      ComputeCurrentValue();

-    }

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {

-      return base_;

-    }

-    // Advance should not be called on beyond-of-range iterators

-    // so no component iterators must be beyond end of range, either.

-    virtual void Advance() {

-      assert(!AtEnd());

-      ++current3_;

-      if (current3_ == end3_) {

-        current3_ = begin3_;

-        ++current2_;

-      }

-      if (current2_ == end2_) {

-        current2_ = begin2_;

-        ++current1_;

-      }

-      ComputeCurrentValue();

-    }

-    virtual ParamIteratorInterface<ParamType>* Clone() const {

-      return new Iterator(*this);

-    }

-    virtual const ParamType* Current() const { return &current_value_; }

-    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      const Iterator* typed_other =

-          CheckedDowncastToActualType<const Iterator>(&other);

-      // We must report iterators equal if they both point beyond their

-      // respective ranges. That can happen in a variety of fashions,

-      // so we have to consult AtEnd().

-      return (AtEnd() && typed_other->AtEnd()) ||

-         (

-          current1_ == typed_other->current1_ &&

-          current2_ == typed_other->current2_ &&

-          current3_ == typed_other->current3_);

-    }

-

-   private:

-    Iterator(const Iterator& other)

-        : base_(other.base_),

-        begin1_(other.begin1_),

-        end1_(other.end1_),

-        current1_(other.current1_),

-        begin2_(other.begin2_),

-        end2_(other.end2_),

-        current2_(other.current2_),

-        begin3_(other.begin3_),

-        end3_(other.end3_),

-        current3_(other.current3_) {

-      ComputeCurrentValue();

-    }

-

-    void ComputeCurrentValue() {

-      if (!AtEnd())

-        current_value_ = ParamType(*current1_, *current2_, *current3_);

-    }

-    bool AtEnd() const {

-      // We must report iterator past the end of the range when either of the

-      // component iterators has reached the end of its range.

-      return

-          current1_ == end1_ ||

-          current2_ == end2_ ||

-          current3_ == end3_;

-    }

-

-    const ParamGeneratorInterface<ParamType>* const base_;

-    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.

-    // current[i]_ is the actual traversing iterator.

-    const typename ParamGenerator<T1>::iterator begin1_;

-    const typename ParamGenerator<T1>::iterator end1_;

-    typename ParamGenerator<T1>::iterator current1_;

-    const typename ParamGenerator<T2>::iterator begin2_;

-    const typename ParamGenerator<T2>::iterator end2_;

-    typename ParamGenerator<T2>::iterator current2_;

-    const typename ParamGenerator<T3>::iterator begin3_;

-    const typename ParamGenerator<T3>::iterator end3_;

-    typename ParamGenerator<T3>::iterator current3_;

-    ParamType current_value_;

-  };

-

-  const ParamGenerator<T1> g1_;

-  const ParamGenerator<T2> g2_;

-  const ParamGenerator<T3> g3_;

-};

-

-

-template <typename T1, typename T2, typename T3, typename T4>

-class CartesianProductGenerator4

-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {

- public:

-  typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;

-

-  CartesianProductGenerator4(const ParamGenerator<T1>& g1,

-      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,

-      const ParamGenerator<T4>& g4)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}

-  virtual ~CartesianProductGenerator4() {}

-

-  virtual ParamIteratorInterface<ParamType>* Begin() const {

-    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,

-        g3_.begin(), g4_, g4_.begin());

-  }

-  virtual ParamIteratorInterface<ParamType>* End() const {

-    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),

-        g4_, g4_.end());

-  }

-

- private:

-  class Iterator : public ParamIteratorInterface<ParamType> {

-   public:

-    Iterator(const ParamGeneratorInterface<ParamType>* base,

-      const ParamGenerator<T1>& g1,

-      const typename ParamGenerator<T1>::iterator& current1,

-      const ParamGenerator<T2>& g2,

-      const typename ParamGenerator<T2>::iterator& current2,

-      const ParamGenerator<T3>& g3,

-      const typename ParamGenerator<T3>::iterator& current3,

-      const ParamGenerator<T4>& g4,

-      const typename ParamGenerator<T4>::iterator& current4)

-        : base_(base),

-          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),

-          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),

-          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),

-          begin4_(g4.begin()), end4_(g4.end()), current4_(current4)    {

-      ComputeCurrentValue();

-    }

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {

-      return base_;

-    }

-    // Advance should not be called on beyond-of-range iterators

-    // so no component iterators must be beyond end of range, either.

-    virtual void Advance() {

-      assert(!AtEnd());

-      ++current4_;

-      if (current4_ == end4_) {

-        current4_ = begin4_;

-        ++current3_;

-      }

-      if (current3_ == end3_) {

-        current3_ = begin3_;

-        ++current2_;

-      }

-      if (current2_ == end2_) {

-        current2_ = begin2_;

-        ++current1_;

-      }

-      ComputeCurrentValue();

-    }

-    virtual ParamIteratorInterface<ParamType>* Clone() const {

-      return new Iterator(*this);

-    }

-    virtual const ParamType* Current() const { return &current_value_; }

-    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      const Iterator* typed_other =

-          CheckedDowncastToActualType<const Iterator>(&other);

-      // We must report iterators equal if they both point beyond their

-      // respective ranges. That can happen in a variety of fashions,

-      // so we have to consult AtEnd().

-      return (AtEnd() && typed_other->AtEnd()) ||

-         (

-          current1_ == typed_other->current1_ &&

-          current2_ == typed_other->current2_ &&

-          current3_ == typed_other->current3_ &&

-          current4_ == typed_other->current4_);

-    }

-

-   private:

-    Iterator(const Iterator& other)

-        : base_(other.base_),

-        begin1_(other.begin1_),

-        end1_(other.end1_),

-        current1_(other.current1_),

-        begin2_(other.begin2_),

-        end2_(other.end2_),

-        current2_(other.current2_),

-        begin3_(other.begin3_),

-        end3_(other.end3_),

-        current3_(other.current3_),

-        begin4_(other.begin4_),

-        end4_(other.end4_),

-        current4_(other.current4_) {

-      ComputeCurrentValue();

-    }

-

-    void ComputeCurrentValue() {

-      if (!AtEnd())

-        current_value_ = ParamType(*current1_, *current2_, *current3_,

-            *current4_);

-    }

-    bool AtEnd() const {

-      // We must report iterator past the end of the range when either of the

-      // component iterators has reached the end of its range.

-      return

-          current1_ == end1_ ||

-          current2_ == end2_ ||

-          current3_ == end3_ ||

-          current4_ == end4_;

-    }

-

-    const ParamGeneratorInterface<ParamType>* const base_;

-    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.

-    // current[i]_ is the actual traversing iterator.

-    const typename ParamGenerator<T1>::iterator begin1_;

-    const typename ParamGenerator<T1>::iterator end1_;

-    typename ParamGenerator<T1>::iterator current1_;

-    const typename ParamGenerator<T2>::iterator begin2_;

-    const typename ParamGenerator<T2>::iterator end2_;

-    typename ParamGenerator<T2>::iterator current2_;

-    const typename ParamGenerator<T3>::iterator begin3_;

-    const typename ParamGenerator<T3>::iterator end3_;

-    typename ParamGenerator<T3>::iterator current3_;

-    const typename ParamGenerator<T4>::iterator begin4_;

-    const typename ParamGenerator<T4>::iterator end4_;

-    typename ParamGenerator<T4>::iterator current4_;

-    ParamType current_value_;

-  };

-

-  const ParamGenerator<T1> g1_;

-  const ParamGenerator<T2> g2_;

-  const ParamGenerator<T3> g3_;

-  const ParamGenerator<T4> g4_;

-};

-

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5>

-class CartesianProductGenerator5

-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {

- public:

-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;

-

-  CartesianProductGenerator5(const ParamGenerator<T1>& g1,

-      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,

-      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}

-  virtual ~CartesianProductGenerator5() {}

-

-  virtual ParamIteratorInterface<ParamType>* Begin() const {

-    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,

-        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());

-  }

-  virtual ParamIteratorInterface<ParamType>* End() const {

-    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),

-        g4_, g4_.end(), g5_, g5_.end());

-  }

-

- private:

-  class Iterator : public ParamIteratorInterface<ParamType> {

-   public:

-    Iterator(const ParamGeneratorInterface<ParamType>* base,

-      const ParamGenerator<T1>& g1,

-      const typename ParamGenerator<T1>::iterator& current1,

-      const ParamGenerator<T2>& g2,

-      const typename ParamGenerator<T2>::iterator& current2,

-      const ParamGenerator<T3>& g3,

-      const typename ParamGenerator<T3>::iterator& current3,

-      const ParamGenerator<T4>& g4,

-      const typename ParamGenerator<T4>::iterator& current4,

-      const ParamGenerator<T5>& g5,

-      const typename ParamGenerator<T5>::iterator& current5)

-        : base_(base),

-          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),

-          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),

-          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),

-          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),

-          begin5_(g5.begin()), end5_(g5.end()), current5_(current5)    {

-      ComputeCurrentValue();

-    }

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {

-      return base_;

-    }

-    // Advance should not be called on beyond-of-range iterators

-    // so no component iterators must be beyond end of range, either.

-    virtual void Advance() {

-      assert(!AtEnd());

-      ++current5_;

-      if (current5_ == end5_) {

-        current5_ = begin5_;

-        ++current4_;

-      }

-      if (current4_ == end4_) {

-        current4_ = begin4_;

-        ++current3_;

-      }

-      if (current3_ == end3_) {

-        current3_ = begin3_;

-        ++current2_;

-      }

-      if (current2_ == end2_) {

-        current2_ = begin2_;

-        ++current1_;

-      }

-      ComputeCurrentValue();

-    }

-    virtual ParamIteratorInterface<ParamType>* Clone() const {

-      return new Iterator(*this);

-    }

-    virtual const ParamType* Current() const { return &current_value_; }

-    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      const Iterator* typed_other =

-          CheckedDowncastToActualType<const Iterator>(&other);

-      // We must report iterators equal if they both point beyond their

-      // respective ranges. That can happen in a variety of fashions,

-      // so we have to consult AtEnd().

-      return (AtEnd() && typed_other->AtEnd()) ||

-         (

-          current1_ == typed_other->current1_ &&

-          current2_ == typed_other->current2_ &&

-          current3_ == typed_other->current3_ &&

-          current4_ == typed_other->current4_ &&

-          current5_ == typed_other->current5_);

-    }

-

-   private:

-    Iterator(const Iterator& other)

-        : base_(other.base_),

-        begin1_(other.begin1_),

-        end1_(other.end1_),

-        current1_(other.current1_),

-        begin2_(other.begin2_),

-        end2_(other.end2_),

-        current2_(other.current2_),

-        begin3_(other.begin3_),

-        end3_(other.end3_),

-        current3_(other.current3_),

-        begin4_(other.begin4_),

-        end4_(other.end4_),

-        current4_(other.current4_),

-        begin5_(other.begin5_),

-        end5_(other.end5_),

-        current5_(other.current5_) {

-      ComputeCurrentValue();

-    }

-

-    void ComputeCurrentValue() {

-      if (!AtEnd())

-        current_value_ = ParamType(*current1_, *current2_, *current3_,

-            *current4_, *current5_);

-    }

-    bool AtEnd() const {

-      // We must report iterator past the end of the range when either of the

-      // component iterators has reached the end of its range.

-      return

-          current1_ == end1_ ||

-          current2_ == end2_ ||

-          current3_ == end3_ ||

-          current4_ == end4_ ||

-          current5_ == end5_;

-    }

-

-    const ParamGeneratorInterface<ParamType>* const base_;

-    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.

-    // current[i]_ is the actual traversing iterator.

-    const typename ParamGenerator<T1>::iterator begin1_;

-    const typename ParamGenerator<T1>::iterator end1_;

-    typename ParamGenerator<T1>::iterator current1_;

-    const typename ParamGenerator<T2>::iterator begin2_;

-    const typename ParamGenerator<T2>::iterator end2_;

-    typename ParamGenerator<T2>::iterator current2_;

-    const typename ParamGenerator<T3>::iterator begin3_;

-    const typename ParamGenerator<T3>::iterator end3_;

-    typename ParamGenerator<T3>::iterator current3_;

-    const typename ParamGenerator<T4>::iterator begin4_;

-    const typename ParamGenerator<T4>::iterator end4_;

-    typename ParamGenerator<T4>::iterator current4_;

-    const typename ParamGenerator<T5>::iterator begin5_;

-    const typename ParamGenerator<T5>::iterator end5_;

-    typename ParamGenerator<T5>::iterator current5_;

-    ParamType current_value_;

-  };

-

-  const ParamGenerator<T1> g1_;

-  const ParamGenerator<T2> g2_;

-  const ParamGenerator<T3> g3_;

-  const ParamGenerator<T4> g4_;

-  const ParamGenerator<T5> g5_;

-};

-

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6>

-class CartesianProductGenerator6

-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,

-        T6> > {

- public:

-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;

-

-  CartesianProductGenerator6(const ParamGenerator<T1>& g1,

-      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,

-      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,

-      const ParamGenerator<T6>& g6)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}

-  virtual ~CartesianProductGenerator6() {}

-

-  virtual ParamIteratorInterface<ParamType>* Begin() const {

-    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,

-        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());

-  }

-  virtual ParamIteratorInterface<ParamType>* End() const {

-    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),

-        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());

-  }

-

- private:

-  class Iterator : public ParamIteratorInterface<ParamType> {

-   public:

-    Iterator(const ParamGeneratorInterface<ParamType>* base,

-      const ParamGenerator<T1>& g1,

-      const typename ParamGenerator<T1>::iterator& current1,

-      const ParamGenerator<T2>& g2,

-      const typename ParamGenerator<T2>::iterator& current2,

-      const ParamGenerator<T3>& g3,

-      const typename ParamGenerator<T3>::iterator& current3,

-      const ParamGenerator<T4>& g4,

-      const typename ParamGenerator<T4>::iterator& current4,

-      const ParamGenerator<T5>& g5,

-      const typename ParamGenerator<T5>::iterator& current5,

-      const ParamGenerator<T6>& g6,

-      const typename ParamGenerator<T6>::iterator& current6)

-        : base_(base),

-          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),

-          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),

-          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),

-          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),

-          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),

-          begin6_(g6.begin()), end6_(g6.end()), current6_(current6)    {

-      ComputeCurrentValue();

-    }

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {

-      return base_;

-    }

-    // Advance should not be called on beyond-of-range iterators

-    // so no component iterators must be beyond end of range, either.

-    virtual void Advance() {

-      assert(!AtEnd());

-      ++current6_;

-      if (current6_ == end6_) {

-        current6_ = begin6_;

-        ++current5_;

-      }

-      if (current5_ == end5_) {

-        current5_ = begin5_;

-        ++current4_;

-      }

-      if (current4_ == end4_) {

-        current4_ = begin4_;

-        ++current3_;

-      }

-      if (current3_ == end3_) {

-        current3_ = begin3_;

-        ++current2_;

-      }

-      if (current2_ == end2_) {

-        current2_ = begin2_;

-        ++current1_;

-      }

-      ComputeCurrentValue();

-    }

-    virtual ParamIteratorInterface<ParamType>* Clone() const {

-      return new Iterator(*this);

-    }

-    virtual const ParamType* Current() const { return &current_value_; }

-    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      const Iterator* typed_other =

-          CheckedDowncastToActualType<const Iterator>(&other);

-      // We must report iterators equal if they both point beyond their

-      // respective ranges. That can happen in a variety of fashions,

-      // so we have to consult AtEnd().

-      return (AtEnd() && typed_other->AtEnd()) ||

-         (

-          current1_ == typed_other->current1_ &&

-          current2_ == typed_other->current2_ &&

-          current3_ == typed_other->current3_ &&

-          current4_ == typed_other->current4_ &&

-          current5_ == typed_other->current5_ &&

-          current6_ == typed_other->current6_);

-    }

-

-   private:

-    Iterator(const Iterator& other)

-        : base_(other.base_),

-        begin1_(other.begin1_),

-        end1_(other.end1_),

-        current1_(other.current1_),

-        begin2_(other.begin2_),

-        end2_(other.end2_),

-        current2_(other.current2_),

-        begin3_(other.begin3_),

-        end3_(other.end3_),

-        current3_(other.current3_),

-        begin4_(other.begin4_),

-        end4_(other.end4_),

-        current4_(other.current4_),

-        begin5_(other.begin5_),

-        end5_(other.end5_),

-        current5_(other.current5_),

-        begin6_(other.begin6_),

-        end6_(other.end6_),

-        current6_(other.current6_) {

-      ComputeCurrentValue();

-    }

-

-    void ComputeCurrentValue() {

-      if (!AtEnd())

-        current_value_ = ParamType(*current1_, *current2_, *current3_,

-            *current4_, *current5_, *current6_);

-    }

-    bool AtEnd() const {

-      // We must report iterator past the end of the range when either of the

-      // component iterators has reached the end of its range.

-      return

-          current1_ == end1_ ||

-          current2_ == end2_ ||

-          current3_ == end3_ ||

-          current4_ == end4_ ||

-          current5_ == end5_ ||

-          current6_ == end6_;

-    }

-

-    const ParamGeneratorInterface<ParamType>* const base_;

-    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.

-    // current[i]_ is the actual traversing iterator.

-    const typename ParamGenerator<T1>::iterator begin1_;

-    const typename ParamGenerator<T1>::iterator end1_;

-    typename ParamGenerator<T1>::iterator current1_;

-    const typename ParamGenerator<T2>::iterator begin2_;

-    const typename ParamGenerator<T2>::iterator end2_;

-    typename ParamGenerator<T2>::iterator current2_;

-    const typename ParamGenerator<T3>::iterator begin3_;

-    const typename ParamGenerator<T3>::iterator end3_;

-    typename ParamGenerator<T3>::iterator current3_;

-    const typename ParamGenerator<T4>::iterator begin4_;

-    const typename ParamGenerator<T4>::iterator end4_;

-    typename ParamGenerator<T4>::iterator current4_;

-    const typename ParamGenerator<T5>::iterator begin5_;

-    const typename ParamGenerator<T5>::iterator end5_;

-    typename ParamGenerator<T5>::iterator current5_;

-    const typename ParamGenerator<T6>::iterator begin6_;

-    const typename ParamGenerator<T6>::iterator end6_;

-    typename ParamGenerator<T6>::iterator current6_;

-    ParamType current_value_;

-  };

-

-  const ParamGenerator<T1> g1_;

-  const ParamGenerator<T2> g2_;

-  const ParamGenerator<T3> g3_;

-  const ParamGenerator<T4> g4_;

-  const ParamGenerator<T5> g5_;

-  const ParamGenerator<T6> g6_;

-};

-

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7>

-class CartesianProductGenerator7

-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,

-        T7> > {

- public:

-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;

-

-  CartesianProductGenerator7(const ParamGenerator<T1>& g1,

-      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,

-      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,

-      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}

-  virtual ~CartesianProductGenerator7() {}

-

-  virtual ParamIteratorInterface<ParamType>* Begin() const {

-    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,

-        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,

-        g7_.begin());

-  }

-  virtual ParamIteratorInterface<ParamType>* End() const {

-    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),

-        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());

-  }

-

- private:

-  class Iterator : public ParamIteratorInterface<ParamType> {

-   public:

-    Iterator(const ParamGeneratorInterface<ParamType>* base,

-      const ParamGenerator<T1>& g1,

-      const typename ParamGenerator<T1>::iterator& current1,

-      const ParamGenerator<T2>& g2,

-      const typename ParamGenerator<T2>::iterator& current2,

-      const ParamGenerator<T3>& g3,

-      const typename ParamGenerator<T3>::iterator& current3,

-      const ParamGenerator<T4>& g4,

-      const typename ParamGenerator<T4>::iterator& current4,

-      const ParamGenerator<T5>& g5,

-      const typename ParamGenerator<T5>::iterator& current5,

-      const ParamGenerator<T6>& g6,

-      const typename ParamGenerator<T6>::iterator& current6,

-      const ParamGenerator<T7>& g7,

-      const typename ParamGenerator<T7>::iterator& current7)

-        : base_(base),

-          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),

-          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),

-          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),

-          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),

-          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),

-          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),

-          begin7_(g7.begin()), end7_(g7.end()), current7_(current7)    {

-      ComputeCurrentValue();

-    }

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {

-      return base_;

-    }

-    // Advance should not be called on beyond-of-range iterators

-    // so no component iterators must be beyond end of range, either.

-    virtual void Advance() {

-      assert(!AtEnd());

-      ++current7_;

-      if (current7_ == end7_) {

-        current7_ = begin7_;

-        ++current6_;

-      }

-      if (current6_ == end6_) {

-        current6_ = begin6_;

-        ++current5_;

-      }

-      if (current5_ == end5_) {

-        current5_ = begin5_;

-        ++current4_;

-      }

-      if (current4_ == end4_) {

-        current4_ = begin4_;

-        ++current3_;

-      }

-      if (current3_ == end3_) {

-        current3_ = begin3_;

-        ++current2_;

-      }

-      if (current2_ == end2_) {

-        current2_ = begin2_;

-        ++current1_;

-      }

-      ComputeCurrentValue();

-    }

-    virtual ParamIteratorInterface<ParamType>* Clone() const {

-      return new Iterator(*this);

-    }

-    virtual const ParamType* Current() const { return &current_value_; }

-    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      const Iterator* typed_other =

-          CheckedDowncastToActualType<const Iterator>(&other);

-      // We must report iterators equal if they both point beyond their

-      // respective ranges. That can happen in a variety of fashions,

-      // so we have to consult AtEnd().

-      return (AtEnd() && typed_other->AtEnd()) ||

-         (

-          current1_ == typed_other->current1_ &&

-          current2_ == typed_other->current2_ &&

-          current3_ == typed_other->current3_ &&

-          current4_ == typed_other->current4_ &&

-          current5_ == typed_other->current5_ &&

-          current6_ == typed_other->current6_ &&

-          current7_ == typed_other->current7_);

-    }

-

-   private:

-    Iterator(const Iterator& other)

-        : base_(other.base_),

-        begin1_(other.begin1_),

-        end1_(other.end1_),

-        current1_(other.current1_),

-        begin2_(other.begin2_),

-        end2_(other.end2_),

-        current2_(other.current2_),

-        begin3_(other.begin3_),

-        end3_(other.end3_),

-        current3_(other.current3_),

-        begin4_(other.begin4_),

-        end4_(other.end4_),

-        current4_(other.current4_),

-        begin5_(other.begin5_),

-        end5_(other.end5_),

-        current5_(other.current5_),

-        begin6_(other.begin6_),

-        end6_(other.end6_),

-        current6_(other.current6_),

-        begin7_(other.begin7_),

-        end7_(other.end7_),

-        current7_(other.current7_) {

-      ComputeCurrentValue();

-    }

-

-    void ComputeCurrentValue() {

-      if (!AtEnd())

-        current_value_ = ParamType(*current1_, *current2_, *current3_,

-            *current4_, *current5_, *current6_, *current7_);

-    }

-    bool AtEnd() const {

-      // We must report iterator past the end of the range when either of the

-      // component iterators has reached the end of its range.

-      return

-          current1_ == end1_ ||

-          current2_ == end2_ ||

-          current3_ == end3_ ||

-          current4_ == end4_ ||

-          current5_ == end5_ ||

-          current6_ == end6_ ||

-          current7_ == end7_;

-    }

-

-    const ParamGeneratorInterface<ParamType>* const base_;

-    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.

-    // current[i]_ is the actual traversing iterator.

-    const typename ParamGenerator<T1>::iterator begin1_;

-    const typename ParamGenerator<T1>::iterator end1_;

-    typename ParamGenerator<T1>::iterator current1_;

-    const typename ParamGenerator<T2>::iterator begin2_;

-    const typename ParamGenerator<T2>::iterator end2_;

-    typename ParamGenerator<T2>::iterator current2_;

-    const typename ParamGenerator<T3>::iterator begin3_;

-    const typename ParamGenerator<T3>::iterator end3_;

-    typename ParamGenerator<T3>::iterator current3_;

-    const typename ParamGenerator<T4>::iterator begin4_;

-    const typename ParamGenerator<T4>::iterator end4_;

-    typename ParamGenerator<T4>::iterator current4_;

-    const typename ParamGenerator<T5>::iterator begin5_;

-    const typename ParamGenerator<T5>::iterator end5_;

-    typename ParamGenerator<T5>::iterator current5_;

-    const typename ParamGenerator<T6>::iterator begin6_;

-    const typename ParamGenerator<T6>::iterator end6_;

-    typename ParamGenerator<T6>::iterator current6_;

-    const typename ParamGenerator<T7>::iterator begin7_;

-    const typename ParamGenerator<T7>::iterator end7_;

-    typename ParamGenerator<T7>::iterator current7_;

-    ParamType current_value_;

-  };

-

-  const ParamGenerator<T1> g1_;

-  const ParamGenerator<T2> g2_;

-  const ParamGenerator<T3> g3_;

-  const ParamGenerator<T4> g4_;

-  const ParamGenerator<T5> g5_;

-  const ParamGenerator<T6> g6_;

-  const ParamGenerator<T7> g7_;

-};

-

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8>

-class CartesianProductGenerator8

-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,

-        T7, T8> > {

- public:

-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;

-

-  CartesianProductGenerator8(const ParamGenerator<T1>& g1,

-      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,

-      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,

-      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,

-      const ParamGenerator<T8>& g8)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),

-          g8_(g8) {}

-  virtual ~CartesianProductGenerator8() {}

-

-  virtual ParamIteratorInterface<ParamType>* Begin() const {

-    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,

-        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,

-        g7_.begin(), g8_, g8_.begin());

-  }

-  virtual ParamIteratorInterface<ParamType>* End() const {

-    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),

-        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,

-        g8_.end());

-  }

-

- private:

-  class Iterator : public ParamIteratorInterface<ParamType> {

-   public:

-    Iterator(const ParamGeneratorInterface<ParamType>* base,

-      const ParamGenerator<T1>& g1,

-      const typename ParamGenerator<T1>::iterator& current1,

-      const ParamGenerator<T2>& g2,

-      const typename ParamGenerator<T2>::iterator& current2,

-      const ParamGenerator<T3>& g3,

-      const typename ParamGenerator<T3>::iterator& current3,

-      const ParamGenerator<T4>& g4,

-      const typename ParamGenerator<T4>::iterator& current4,

-      const ParamGenerator<T5>& g5,

-      const typename ParamGenerator<T5>::iterator& current5,

-      const ParamGenerator<T6>& g6,

-      const typename ParamGenerator<T6>::iterator& current6,

-      const ParamGenerator<T7>& g7,

-      const typename ParamGenerator<T7>::iterator& current7,

-      const ParamGenerator<T8>& g8,

-      const typename ParamGenerator<T8>::iterator& current8)

-        : base_(base),

-          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),

-          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),

-          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),

-          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),

-          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),

-          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),

-          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),

-          begin8_(g8.begin()), end8_(g8.end()), current8_(current8)    {

-      ComputeCurrentValue();

-    }

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {

-      return base_;

-    }

-    // Advance should not be called on beyond-of-range iterators

-    // so no component iterators must be beyond end of range, either.

-    virtual void Advance() {

-      assert(!AtEnd());

-      ++current8_;

-      if (current8_ == end8_) {

-        current8_ = begin8_;

-        ++current7_;

-      }

-      if (current7_ == end7_) {

-        current7_ = begin7_;

-        ++current6_;

-      }

-      if (current6_ == end6_) {

-        current6_ = begin6_;

-        ++current5_;

-      }

-      if (current5_ == end5_) {

-        current5_ = begin5_;

-        ++current4_;

-      }

-      if (current4_ == end4_) {

-        current4_ = begin4_;

-        ++current3_;

-      }

-      if (current3_ == end3_) {

-        current3_ = begin3_;

-        ++current2_;

-      }

-      if (current2_ == end2_) {

-        current2_ = begin2_;

-        ++current1_;

-      }

-      ComputeCurrentValue();

-    }

-    virtual ParamIteratorInterface<ParamType>* Clone() const {

-      return new Iterator(*this);

-    }

-    virtual const ParamType* Current() const { return &current_value_; }

-    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      const Iterator* typed_other =

-          CheckedDowncastToActualType<const Iterator>(&other);

-      // We must report iterators equal if they both point beyond their

-      // respective ranges. That can happen in a variety of fashions,

-      // so we have to consult AtEnd().

-      return (AtEnd() && typed_other->AtEnd()) ||

-         (

-          current1_ == typed_other->current1_ &&

-          current2_ == typed_other->current2_ &&

-          current3_ == typed_other->current3_ &&

-          current4_ == typed_other->current4_ &&

-          current5_ == typed_other->current5_ &&

-          current6_ == typed_other->current6_ &&

-          current7_ == typed_other->current7_ &&

-          current8_ == typed_other->current8_);

-    }

-

-   private:

-    Iterator(const Iterator& other)

-        : base_(other.base_),

-        begin1_(other.begin1_),

-        end1_(other.end1_),

-        current1_(other.current1_),

-        begin2_(other.begin2_),

-        end2_(other.end2_),

-        current2_(other.current2_),

-        begin3_(other.begin3_),

-        end3_(other.end3_),

-        current3_(other.current3_),

-        begin4_(other.begin4_),

-        end4_(other.end4_),

-        current4_(other.current4_),

-        begin5_(other.begin5_),

-        end5_(other.end5_),

-        current5_(other.current5_),

-        begin6_(other.begin6_),

-        end6_(other.end6_),

-        current6_(other.current6_),

-        begin7_(other.begin7_),

-        end7_(other.end7_),

-        current7_(other.current7_),

-        begin8_(other.begin8_),

-        end8_(other.end8_),

-        current8_(other.current8_) {

-      ComputeCurrentValue();

-    }

-

-    void ComputeCurrentValue() {

-      if (!AtEnd())

-        current_value_ = ParamType(*current1_, *current2_, *current3_,

-            *current4_, *current5_, *current6_, *current7_, *current8_);

-    }

-    bool AtEnd() const {

-      // We must report iterator past the end of the range when either of the

-      // component iterators has reached the end of its range.

-      return

-          current1_ == end1_ ||

-          current2_ == end2_ ||

-          current3_ == end3_ ||

-          current4_ == end4_ ||

-          current5_ == end5_ ||

-          current6_ == end6_ ||

-          current7_ == end7_ ||

-          current8_ == end8_;

-    }

-

-    const ParamGeneratorInterface<ParamType>* const base_;

-    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.

-    // current[i]_ is the actual traversing iterator.

-    const typename ParamGenerator<T1>::iterator begin1_;

-    const typename ParamGenerator<T1>::iterator end1_;

-    typename ParamGenerator<T1>::iterator current1_;

-    const typename ParamGenerator<T2>::iterator begin2_;

-    const typename ParamGenerator<T2>::iterator end2_;

-    typename ParamGenerator<T2>::iterator current2_;

-    const typename ParamGenerator<T3>::iterator begin3_;

-    const typename ParamGenerator<T3>::iterator end3_;

-    typename ParamGenerator<T3>::iterator current3_;

-    const typename ParamGenerator<T4>::iterator begin4_;

-    const typename ParamGenerator<T4>::iterator end4_;

-    typename ParamGenerator<T4>::iterator current4_;

-    const typename ParamGenerator<T5>::iterator begin5_;

-    const typename ParamGenerator<T5>::iterator end5_;

-    typename ParamGenerator<T5>::iterator current5_;

-    const typename ParamGenerator<T6>::iterator begin6_;

-    const typename ParamGenerator<T6>::iterator end6_;

-    typename ParamGenerator<T6>::iterator current6_;

-    const typename ParamGenerator<T7>::iterator begin7_;

-    const typename ParamGenerator<T7>::iterator end7_;

-    typename ParamGenerator<T7>::iterator current7_;

-    const typename ParamGenerator<T8>::iterator begin8_;

-    const typename ParamGenerator<T8>::iterator end8_;

-    typename ParamGenerator<T8>::iterator current8_;

-    ParamType current_value_;

-  };

-

-  const ParamGenerator<T1> g1_;

-  const ParamGenerator<T2> g2_;

-  const ParamGenerator<T3> g3_;

-  const ParamGenerator<T4> g4_;

-  const ParamGenerator<T5> g5_;

-  const ParamGenerator<T6> g6_;

-  const ParamGenerator<T7> g7_;

-  const ParamGenerator<T8> g8_;

-};

-

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9>

-class CartesianProductGenerator9

-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,

-        T7, T8, T9> > {

- public:

-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;

-

-  CartesianProductGenerator9(const ParamGenerator<T1>& g1,

-      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,

-      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,

-      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,

-      const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),

-          g9_(g9) {}

-  virtual ~CartesianProductGenerator9() {}

-

-  virtual ParamIteratorInterface<ParamType>* Begin() const {

-    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,

-        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,

-        g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());

-  }

-  virtual ParamIteratorInterface<ParamType>* End() const {

-    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),

-        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,

-        g8_.end(), g9_, g9_.end());

-  }

-

- private:

-  class Iterator : public ParamIteratorInterface<ParamType> {

-   public:

-    Iterator(const ParamGeneratorInterface<ParamType>* base,

-      const ParamGenerator<T1>& g1,

-      const typename ParamGenerator<T1>::iterator& current1,

-      const ParamGenerator<T2>& g2,

-      const typename ParamGenerator<T2>::iterator& current2,

-      const ParamGenerator<T3>& g3,

-      const typename ParamGenerator<T3>::iterator& current3,

-      const ParamGenerator<T4>& g4,

-      const typename ParamGenerator<T4>::iterator& current4,

-      const ParamGenerator<T5>& g5,

-      const typename ParamGenerator<T5>::iterator& current5,

-      const ParamGenerator<T6>& g6,

-      const typename ParamGenerator<T6>::iterator& current6,

-      const ParamGenerator<T7>& g7,

-      const typename ParamGenerator<T7>::iterator& current7,

-      const ParamGenerator<T8>& g8,

-      const typename ParamGenerator<T8>::iterator& current8,

-      const ParamGenerator<T9>& g9,

-      const typename ParamGenerator<T9>::iterator& current9)

-        : base_(base),

-          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),

-          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),

-          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),

-          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),

-          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),

-          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),

-          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),

-          begin8_(g8.begin()), end8_(g8.end()), current8_(current8),

-          begin9_(g9.begin()), end9_(g9.end()), current9_(current9)    {

-      ComputeCurrentValue();

-    }

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {

-      return base_;

-    }

-    // Advance should not be called on beyond-of-range iterators

-    // so no component iterators must be beyond end of range, either.

-    virtual void Advance() {

-      assert(!AtEnd());

-      ++current9_;

-      if (current9_ == end9_) {

-        current9_ = begin9_;

-        ++current8_;

-      }

-      if (current8_ == end8_) {

-        current8_ = begin8_;

-        ++current7_;

-      }

-      if (current7_ == end7_) {

-        current7_ = begin7_;

-        ++current6_;

-      }

-      if (current6_ == end6_) {

-        current6_ = begin6_;

-        ++current5_;

-      }

-      if (current5_ == end5_) {

-        current5_ = begin5_;

-        ++current4_;

-      }

-      if (current4_ == end4_) {

-        current4_ = begin4_;

-        ++current3_;

-      }

-      if (current3_ == end3_) {

-        current3_ = begin3_;

-        ++current2_;

-      }

-      if (current2_ == end2_) {

-        current2_ = begin2_;

-        ++current1_;

-      }

-      ComputeCurrentValue();

-    }

-    virtual ParamIteratorInterface<ParamType>* Clone() const {

-      return new Iterator(*this);

-    }

-    virtual const ParamType* Current() const { return &current_value_; }

-    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      const Iterator* typed_other =

-          CheckedDowncastToActualType<const Iterator>(&other);

-      // We must report iterators equal if they both point beyond their

-      // respective ranges. That can happen in a variety of fashions,

-      // so we have to consult AtEnd().

-      return (AtEnd() && typed_other->AtEnd()) ||

-         (

-          current1_ == typed_other->current1_ &&

-          current2_ == typed_other->current2_ &&

-          current3_ == typed_other->current3_ &&

-          current4_ == typed_other->current4_ &&

-          current5_ == typed_other->current5_ &&

-          current6_ == typed_other->current6_ &&

-          current7_ == typed_other->current7_ &&

-          current8_ == typed_other->current8_ &&

-          current9_ == typed_other->current9_);

-    }

-

-   private:

-    Iterator(const Iterator& other)

-        : base_(other.base_),

-        begin1_(other.begin1_),

-        end1_(other.end1_),

-        current1_(other.current1_),

-        begin2_(other.begin2_),

-        end2_(other.end2_),

-        current2_(other.current2_),

-        begin3_(other.begin3_),

-        end3_(other.end3_),

-        current3_(other.current3_),

-        begin4_(other.begin4_),

-        end4_(other.end4_),

-        current4_(other.current4_),

-        begin5_(other.begin5_),

-        end5_(other.end5_),

-        current5_(other.current5_),

-        begin6_(other.begin6_),

-        end6_(other.end6_),

-        current6_(other.current6_),

-        begin7_(other.begin7_),

-        end7_(other.end7_),

-        current7_(other.current7_),

-        begin8_(other.begin8_),

-        end8_(other.end8_),

-        current8_(other.current8_),

-        begin9_(other.begin9_),

-        end9_(other.end9_),

-        current9_(other.current9_) {

-      ComputeCurrentValue();

-    }

-

-    void ComputeCurrentValue() {

-      if (!AtEnd())

-        current_value_ = ParamType(*current1_, *current2_, *current3_,

-            *current4_, *current5_, *current6_, *current7_, *current8_,

-            *current9_);

-    }

-    bool AtEnd() const {

-      // We must report iterator past the end of the range when either of the

-      // component iterators has reached the end of its range.

-      return

-          current1_ == end1_ ||

-          current2_ == end2_ ||

-          current3_ == end3_ ||

-          current4_ == end4_ ||

-          current5_ == end5_ ||

-          current6_ == end6_ ||

-          current7_ == end7_ ||

-          current8_ == end8_ ||

-          current9_ == end9_;

-    }

-

-    const ParamGeneratorInterface<ParamType>* const base_;

-    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.

-    // current[i]_ is the actual traversing iterator.

-    const typename ParamGenerator<T1>::iterator begin1_;

-    const typename ParamGenerator<T1>::iterator end1_;

-    typename ParamGenerator<T1>::iterator current1_;

-    const typename ParamGenerator<T2>::iterator begin2_;

-    const typename ParamGenerator<T2>::iterator end2_;

-    typename ParamGenerator<T2>::iterator current2_;

-    const typename ParamGenerator<T3>::iterator begin3_;

-    const typename ParamGenerator<T3>::iterator end3_;

-    typename ParamGenerator<T3>::iterator current3_;

-    const typename ParamGenerator<T4>::iterator begin4_;

-    const typename ParamGenerator<T4>::iterator end4_;

-    typename ParamGenerator<T4>::iterator current4_;

-    const typename ParamGenerator<T5>::iterator begin5_;

-    const typename ParamGenerator<T5>::iterator end5_;

-    typename ParamGenerator<T5>::iterator current5_;

-    const typename ParamGenerator<T6>::iterator begin6_;

-    const typename ParamGenerator<T6>::iterator end6_;

-    typename ParamGenerator<T6>::iterator current6_;

-    const typename ParamGenerator<T7>::iterator begin7_;

-    const typename ParamGenerator<T7>::iterator end7_;

-    typename ParamGenerator<T7>::iterator current7_;

-    const typename ParamGenerator<T8>::iterator begin8_;

-    const typename ParamGenerator<T8>::iterator end8_;

-    typename ParamGenerator<T8>::iterator current8_;

-    const typename ParamGenerator<T9>::iterator begin9_;

-    const typename ParamGenerator<T9>::iterator end9_;

-    typename ParamGenerator<T9>::iterator current9_;

-    ParamType current_value_;

-  };

-

-  const ParamGenerator<T1> g1_;

-  const ParamGenerator<T2> g2_;

-  const ParamGenerator<T3> g3_;

-  const ParamGenerator<T4> g4_;

-  const ParamGenerator<T5> g5_;

-  const ParamGenerator<T6> g6_;

-  const ParamGenerator<T7> g7_;

-  const ParamGenerator<T8> g8_;

-  const ParamGenerator<T9> g9_;

-};

-

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10>

-class CartesianProductGenerator10

-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,

-        T7, T8, T9, T10> > {

- public:

-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;

-

-  CartesianProductGenerator10(const ParamGenerator<T1>& g1,

-      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,

-      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,

-      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,

-      const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,

-      const ParamGenerator<T10>& g10)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),

-          g9_(g9), g10_(g10) {}

-  virtual ~CartesianProductGenerator10() {}

-

-  virtual ParamIteratorInterface<ParamType>* Begin() const {

-    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,

-        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,

-        g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());

-  }

-  virtual ParamIteratorInterface<ParamType>* End() const {

-    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),

-        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,

-        g8_.end(), g9_, g9_.end(), g10_, g10_.end());

-  }

-

- private:

-  class Iterator : public ParamIteratorInterface<ParamType> {

-   public:

-    Iterator(const ParamGeneratorInterface<ParamType>* base,

-      const ParamGenerator<T1>& g1,

-      const typename ParamGenerator<T1>::iterator& current1,

-      const ParamGenerator<T2>& g2,

-      const typename ParamGenerator<T2>::iterator& current2,

-      const ParamGenerator<T3>& g3,

-      const typename ParamGenerator<T3>::iterator& current3,

-      const ParamGenerator<T4>& g4,

-      const typename ParamGenerator<T4>::iterator& current4,

-      const ParamGenerator<T5>& g5,

-      const typename ParamGenerator<T5>::iterator& current5,

-      const ParamGenerator<T6>& g6,

-      const typename ParamGenerator<T6>::iterator& current6,

-      const ParamGenerator<T7>& g7,

-      const typename ParamGenerator<T7>::iterator& current7,

-      const ParamGenerator<T8>& g8,

-      const typename ParamGenerator<T8>::iterator& current8,

-      const ParamGenerator<T9>& g9,

-      const typename ParamGenerator<T9>::iterator& current9,

-      const ParamGenerator<T10>& g10,

-      const typename ParamGenerator<T10>::iterator& current10)

-        : base_(base),

-          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),

-          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),

-          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),

-          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),

-          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),

-          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),

-          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),

-          begin8_(g8.begin()), end8_(g8.end()), current8_(current8),

-          begin9_(g9.begin()), end9_(g9.end()), current9_(current9),

-          begin10_(g10.begin()), end10_(g10.end()), current10_(current10)    {

-      ComputeCurrentValue();

-    }

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {

-      return base_;

-    }

-    // Advance should not be called on beyond-of-range iterators

-    // so no component iterators must be beyond end of range, either.

-    virtual void Advance() {

-      assert(!AtEnd());

-      ++current10_;

-      if (current10_ == end10_) {

-        current10_ = begin10_;

-        ++current9_;

-      }

-      if (current9_ == end9_) {

-        current9_ = begin9_;

-        ++current8_;

-      }

-      if (current8_ == end8_) {

-        current8_ = begin8_;

-        ++current7_;

-      }

-      if (current7_ == end7_) {

-        current7_ = begin7_;

-        ++current6_;

-      }

-      if (current6_ == end6_) {

-        current6_ = begin6_;

-        ++current5_;

-      }

-      if (current5_ == end5_) {

-        current5_ = begin5_;

-        ++current4_;

-      }

-      if (current4_ == end4_) {

-        current4_ = begin4_;

-        ++current3_;

-      }

-      if (current3_ == end3_) {

-        current3_ = begin3_;

-        ++current2_;

-      }

-      if (current2_ == end2_) {

-        current2_ = begin2_;

-        ++current1_;

-      }

-      ComputeCurrentValue();

-    }

-    virtual ParamIteratorInterface<ParamType>* Clone() const {

-      return new Iterator(*this);

-    }

-    virtual const ParamType* Current() const { return &current_value_; }

-    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      const Iterator* typed_other =

-          CheckedDowncastToActualType<const Iterator>(&other);

-      // We must report iterators equal if they both point beyond their

-      // respective ranges. That can happen in a variety of fashions,

-      // so we have to consult AtEnd().

-      return (AtEnd() && typed_other->AtEnd()) ||

-         (

-          current1_ == typed_other->current1_ &&

-          current2_ == typed_other->current2_ &&

-          current3_ == typed_other->current3_ &&

-          current4_ == typed_other->current4_ &&

-          current5_ == typed_other->current5_ &&

-          current6_ == typed_other->current6_ &&

-          current7_ == typed_other->current7_ &&

-          current8_ == typed_other->current8_ &&

-          current9_ == typed_other->current9_ &&

-          current10_ == typed_other->current10_);

-    }

-

-   private:

-    Iterator(const Iterator& other)

-        : base_(other.base_),

-        begin1_(other.begin1_),

-        end1_(other.end1_),

-        current1_(other.current1_),

-        begin2_(other.begin2_),

-        end2_(other.end2_),

-        current2_(other.current2_),

-        begin3_(other.begin3_),

-        end3_(other.end3_),

-        current3_(other.current3_),

-        begin4_(other.begin4_),

-        end4_(other.end4_),

-        current4_(other.current4_),

-        begin5_(other.begin5_),

-        end5_(other.end5_),

-        current5_(other.current5_),

-        begin6_(other.begin6_),

-        end6_(other.end6_),

-        current6_(other.current6_),

-        begin7_(other.begin7_),

-        end7_(other.end7_),

-        current7_(other.current7_),

-        begin8_(other.begin8_),

-        end8_(other.end8_),

-        current8_(other.current8_),

-        begin9_(other.begin9_),

-        end9_(other.end9_),

-        current9_(other.current9_),

-        begin10_(other.begin10_),

-        end10_(other.end10_),

-        current10_(other.current10_) {

-      ComputeCurrentValue();

-    }

-

-    void ComputeCurrentValue() {

-      if (!AtEnd())

-        current_value_ = ParamType(*current1_, *current2_, *current3_,

-            *current4_, *current5_, *current6_, *current7_, *current8_,

-            *current9_, *current10_);

-    }

-    bool AtEnd() const {

-      // We must report iterator past the end of the range when either of the

-      // component iterators has reached the end of its range.

-      return

-          current1_ == end1_ ||

-          current2_ == end2_ ||

-          current3_ == end3_ ||

-          current4_ == end4_ ||

-          current5_ == end5_ ||

-          current6_ == end6_ ||

-          current7_ == end7_ ||

-          current8_ == end8_ ||

-          current9_ == end9_ ||

-          current10_ == end10_;

-    }

-

-    const ParamGeneratorInterface<ParamType>* const base_;

-    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.

-    // current[i]_ is the actual traversing iterator.

-    const typename ParamGenerator<T1>::iterator begin1_;

-    const typename ParamGenerator<T1>::iterator end1_;

-    typename ParamGenerator<T1>::iterator current1_;

-    const typename ParamGenerator<T2>::iterator begin2_;

-    const typename ParamGenerator<T2>::iterator end2_;

-    typename ParamGenerator<T2>::iterator current2_;

-    const typename ParamGenerator<T3>::iterator begin3_;

-    const typename ParamGenerator<T3>::iterator end3_;

-    typename ParamGenerator<T3>::iterator current3_;

-    const typename ParamGenerator<T4>::iterator begin4_;

-    const typename ParamGenerator<T4>::iterator end4_;

-    typename ParamGenerator<T4>::iterator current4_;

-    const typename ParamGenerator<T5>::iterator begin5_;

-    const typename ParamGenerator<T5>::iterator end5_;

-    typename ParamGenerator<T5>::iterator current5_;

-    const typename ParamGenerator<T6>::iterator begin6_;

-    const typename ParamGenerator<T6>::iterator end6_;

-    typename ParamGenerator<T6>::iterator current6_;

-    const typename ParamGenerator<T7>::iterator begin7_;

-    const typename ParamGenerator<T7>::iterator end7_;

-    typename ParamGenerator<T7>::iterator current7_;

-    const typename ParamGenerator<T8>::iterator begin8_;

-    const typename ParamGenerator<T8>::iterator end8_;

-    typename ParamGenerator<T8>::iterator current8_;

-    const typename ParamGenerator<T9>::iterator begin9_;

-    const typename ParamGenerator<T9>::iterator end9_;

-    typename ParamGenerator<T9>::iterator current9_;

-    const typename ParamGenerator<T10>::iterator begin10_;

-    const typename ParamGenerator<T10>::iterator end10_;

-    typename ParamGenerator<T10>::iterator current10_;

-    ParamType current_value_;

-  };

-

-  const ParamGenerator<T1> g1_;

-  const ParamGenerator<T2> g2_;

-  const ParamGenerator<T3> g3_;

-  const ParamGenerator<T4> g4_;

-  const ParamGenerator<T5> g5_;

-  const ParamGenerator<T6> g6_;

-  const ParamGenerator<T7> g7_;

-  const ParamGenerator<T8> g8_;

-  const ParamGenerator<T9> g9_;

-  const ParamGenerator<T10> g10_;

-};

-

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// Helper classes providing Combine() with polymorphic features. They allow

-// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is

-// convertible to U.

-//

-template <class Generator1, class Generator2>

-class CartesianProductHolder2 {

- public:

-CartesianProductHolder2(const Generator1& g1, const Generator2& g2)

-      : g1_(g1), g2_(g2) {}

-  template <typename T1, typename T2>

-  operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {

-    return ParamGenerator< ::std::tr1::tuple<T1, T2> >(

-        new CartesianProductGenerator2<T1, T2>(

-        static_cast<ParamGenerator<T1> >(g1_),

-        static_cast<ParamGenerator<T2> >(g2_)));

-  }

-

- private:

-  const Generator1 g1_;

-  const Generator2 g2_;

-};

-

-template <class Generator1, class Generator2, class Generator3>

-class CartesianProductHolder3 {

- public:

-CartesianProductHolder3(const Generator1& g1, const Generator2& g2,

-    const Generator3& g3)

-      : g1_(g1), g2_(g2), g3_(g3) {}

-  template <typename T1, typename T2, typename T3>

-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {

-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(

-        new CartesianProductGenerator3<T1, T2, T3>(

-        static_cast<ParamGenerator<T1> >(g1_),

-        static_cast<ParamGenerator<T2> >(g2_),

-        static_cast<ParamGenerator<T3> >(g3_)));

-  }

-

- private:

-  const Generator1 g1_;

-  const Generator2 g2_;

-  const Generator3 g3_;

-};

-

-template <class Generator1, class Generator2, class Generator3,

-    class Generator4>

-class CartesianProductHolder4 {

- public:

-CartesianProductHolder4(const Generator1& g1, const Generator2& g2,

-    const Generator3& g3, const Generator4& g4)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}

-  template <typename T1, typename T2, typename T3, typename T4>

-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {

-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(

-        new CartesianProductGenerator4<T1, T2, T3, T4>(

-        static_cast<ParamGenerator<T1> >(g1_),

-        static_cast<ParamGenerator<T2> >(g2_),

-        static_cast<ParamGenerator<T3> >(g3_),

-        static_cast<ParamGenerator<T4> >(g4_)));

-  }

-

- private:

-  const Generator1 g1_;

-  const Generator2 g2_;

-  const Generator3 g3_;

-  const Generator4 g4_;

-};

-

-template <class Generator1, class Generator2, class Generator3,

-    class Generator4, class Generator5>

-class CartesianProductHolder5 {

- public:

-CartesianProductHolder5(const Generator1& g1, const Generator2& g2,

-    const Generator3& g3, const Generator4& g4, const Generator5& g5)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}

-  template <typename T1, typename T2, typename T3, typename T4, typename T5>

-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {

-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(

-        new CartesianProductGenerator5<T1, T2, T3, T4, T5>(

-        static_cast<ParamGenerator<T1> >(g1_),

-        static_cast<ParamGenerator<T2> >(g2_),

-        static_cast<ParamGenerator<T3> >(g3_),

-        static_cast<ParamGenerator<T4> >(g4_),

-        static_cast<ParamGenerator<T5> >(g5_)));

-  }

-

- private:

-  const Generator1 g1_;

-  const Generator2 g2_;

-  const Generator3 g3_;

-  const Generator4 g4_;

-  const Generator5 g5_;

-};

-

-template <class Generator1, class Generator2, class Generator3,

-    class Generator4, class Generator5, class Generator6>

-class CartesianProductHolder6 {

- public:

-CartesianProductHolder6(const Generator1& g1, const Generator2& g2,

-    const Generator3& g3, const Generator4& g4, const Generator5& g5,

-    const Generator6& g6)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}

-  template <typename T1, typename T2, typename T3, typename T4, typename T5,

-      typename T6>

-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {

-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(

-        new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(

-        static_cast<ParamGenerator<T1> >(g1_),

-        static_cast<ParamGenerator<T2> >(g2_),

-        static_cast<ParamGenerator<T3> >(g3_),

-        static_cast<ParamGenerator<T4> >(g4_),

-        static_cast<ParamGenerator<T5> >(g5_),

-        static_cast<ParamGenerator<T6> >(g6_)));

-  }

-

- private:

-  const Generator1 g1_;

-  const Generator2 g2_;

-  const Generator3 g3_;

-  const Generator4 g4_;

-  const Generator5 g5_;

-  const Generator6 g6_;

-};

-

-template <class Generator1, class Generator2, class Generator3,

-    class Generator4, class Generator5, class Generator6, class Generator7>

-class CartesianProductHolder7 {

- public:

-CartesianProductHolder7(const Generator1& g1, const Generator2& g2,

-    const Generator3& g3, const Generator4& g4, const Generator5& g5,

-    const Generator6& g6, const Generator7& g7)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}

-  template <typename T1, typename T2, typename T3, typename T4, typename T5,

-      typename T6, typename T7>

-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,

-      T7> >() const {

-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(

-        new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(

-        static_cast<ParamGenerator<T1> >(g1_),

-        static_cast<ParamGenerator<T2> >(g2_),

-        static_cast<ParamGenerator<T3> >(g3_),

-        static_cast<ParamGenerator<T4> >(g4_),

-        static_cast<ParamGenerator<T5> >(g5_),

-        static_cast<ParamGenerator<T6> >(g6_),

-        static_cast<ParamGenerator<T7> >(g7_)));

-  }

-

- private:

-  const Generator1 g1_;

-  const Generator2 g2_;

-  const Generator3 g3_;

-  const Generator4 g4_;

-  const Generator5 g5_;

-  const Generator6 g6_;

-  const Generator7 g7_;

-};

-

-template <class Generator1, class Generator2, class Generator3,

-    class Generator4, class Generator5, class Generator6, class Generator7,

-    class Generator8>

-class CartesianProductHolder8 {

- public:

-CartesianProductHolder8(const Generator1& g1, const Generator2& g2,

-    const Generator3& g3, const Generator4& g4, const Generator5& g5,

-    const Generator6& g6, const Generator7& g7, const Generator8& g8)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),

-          g8_(g8) {}

-  template <typename T1, typename T2, typename T3, typename T4, typename T5,

-      typename T6, typename T7, typename T8>

-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,

-      T8> >() const {

-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(

-        new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(

-        static_cast<ParamGenerator<T1> >(g1_),

-        static_cast<ParamGenerator<T2> >(g2_),

-        static_cast<ParamGenerator<T3> >(g3_),

-        static_cast<ParamGenerator<T4> >(g4_),

-        static_cast<ParamGenerator<T5> >(g5_),

-        static_cast<ParamGenerator<T6> >(g6_),

-        static_cast<ParamGenerator<T7> >(g7_),

-        static_cast<ParamGenerator<T8> >(g8_)));

-  }

-

- private:

-  const Generator1 g1_;

-  const Generator2 g2_;

-  const Generator3 g3_;

-  const Generator4 g4_;

-  const Generator5 g5_;

-  const Generator6 g6_;

-  const Generator7 g7_;

-  const Generator8 g8_;

-};

-

-template <class Generator1, class Generator2, class Generator3,

-    class Generator4, class Generator5, class Generator6, class Generator7,

-    class Generator8, class Generator9>

-class CartesianProductHolder9 {

- public:

-CartesianProductHolder9(const Generator1& g1, const Generator2& g2,

-    const Generator3& g3, const Generator4& g4, const Generator5& g5,

-    const Generator6& g6, const Generator7& g7, const Generator8& g8,

-    const Generator9& g9)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),

-          g9_(g9) {}

-  template <typename T1, typename T2, typename T3, typename T4, typename T5,

-      typename T6, typename T7, typename T8, typename T9>

-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,

-      T9> >() const {

-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,

-        T9> >(

-        new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(

-        static_cast<ParamGenerator<T1> >(g1_),

-        static_cast<ParamGenerator<T2> >(g2_),

-        static_cast<ParamGenerator<T3> >(g3_),

-        static_cast<ParamGenerator<T4> >(g4_),

-        static_cast<ParamGenerator<T5> >(g5_),

-        static_cast<ParamGenerator<T6> >(g6_),

-        static_cast<ParamGenerator<T7> >(g7_),

-        static_cast<ParamGenerator<T8> >(g8_),

-        static_cast<ParamGenerator<T9> >(g9_)));

-  }

-

- private:

-  const Generator1 g1_;

-  const Generator2 g2_;

-  const Generator3 g3_;

-  const Generator4 g4_;

-  const Generator5 g5_;

-  const Generator6 g6_;

-  const Generator7 g7_;

-  const Generator8 g8_;

-  const Generator9 g9_;

-};

-

-template <class Generator1, class Generator2, class Generator3,

-    class Generator4, class Generator5, class Generator6, class Generator7,

-    class Generator8, class Generator9, class Generator10>

-class CartesianProductHolder10 {

- public:

-CartesianProductHolder10(const Generator1& g1, const Generator2& g2,

-    const Generator3& g3, const Generator4& g4, const Generator5& g5,

-    const Generator6& g6, const Generator7& g7, const Generator8& g8,

-    const Generator9& g9, const Generator10& g10)

-      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),

-          g9_(g9), g10_(g10) {}

-  template <typename T1, typename T2, typename T3, typename T4, typename T5,

-      typename T6, typename T7, typename T8, typename T9, typename T10>

-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,

-      T9, T10> >() const {

-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,

-        T9, T10> >(

-        new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,

-            T10>(

-        static_cast<ParamGenerator<T1> >(g1_),

-        static_cast<ParamGenerator<T2> >(g2_),

-        static_cast<ParamGenerator<T3> >(g3_),

-        static_cast<ParamGenerator<T4> >(g4_),

-        static_cast<ParamGenerator<T5> >(g5_),

-        static_cast<ParamGenerator<T6> >(g6_),

-        static_cast<ParamGenerator<T7> >(g7_),

-        static_cast<ParamGenerator<T8> >(g8_),

-        static_cast<ParamGenerator<T9> >(g9_),

-        static_cast<ParamGenerator<T10> >(g10_)));

-  }

-

- private:

-  const Generator1 g1_;

-  const Generator2 g2_;

-  const Generator3 g3_;

-  const Generator4 g4_;

-  const Generator5 g5_;

-  const Generator6 g6_;

-  const Generator7 g7_;

-  const Generator8 g8_;

-  const Generator9 g9_;

-  const Generator10 g10_;

-};

-

-#endif  // GTEST_HAS_COMBINE

-

-}  // namespace internal

-}  // namespace testing

-

-#endif  //  GTEST_HAS_PARAM_TEST

-

-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_

+// This file was GENERATED by a script.  DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+// Currently Google Test supports at most 50 arguments in Values,
+// and at most 10 arguments in Combine. Please contact
+// googletestframework@googlegroups.com if you need more.
+// Please note that the number of arguments to Combine is limited
+// by the maximum arity of the implementation of tr1::tuple which is
+// currently set at 10.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+#include <gtest/internal/gtest-param-util.h>
+
+namespace testing {
+namespace internal {
+
+// Used in the Values() function to provide polymorphic capabilities.
+template <typename T1>
+class ValueArray1 {
+ public:
+  explicit ValueArray1(T1 v1) : v1_(v1) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+
+ private:
+  const T1 v1_;
+};
+
+template <typename T1, typename T2>
+class ValueArray2 {
+ public:
+  ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+};
+
+template <typename T1, typename T2, typename T3>
+class ValueArray3 {
+ public:
+  ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+class ValueArray4 {
+ public:
+  ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class ValueArray5 {
+ public:
+  ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+class ValueArray6 {
+ public:
+  ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+class ValueArray7 {
+ public:
+  ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+class ValueArray8 {
+ public:
+  ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+      T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+class ValueArray9 {
+ public:
+  ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+      T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+class ValueArray10 {
+ public:
+  ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+class ValueArray11 {
+ public:
+  ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+class ValueArray12 {
+ public:
+  ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+class ValueArray13 {
+ public:
+  ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+class ValueArray14 {
+ public:
+  ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+class ValueArray15 {
+ public:
+  ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+class ValueArray16 {
+ public:
+  ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+class ValueArray17 {
+ public:
+  ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+      T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+class ValueArray18 {
+ public:
+  ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+class ValueArray19 {
+ public:
+  ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+class ValueArray20 {
+ public:
+  ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+class ValueArray21 {
+ public:
+  ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+class ValueArray22 {
+ public:
+  ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+class ValueArray23 {
+ public:
+  ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_,
+        v23_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+class ValueArray24 {
+ public:
+  ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+class ValueArray25 {
+ public:
+  ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+      T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+class ValueArray26 {
+ public:
+  ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+class ValueArray27 {
+ public:
+  ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+      v26_(v26), v27_(v27) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+class ValueArray28 {
+ public:
+  ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+      v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+class ValueArray29 {
+ public:
+  ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+class ValueArray30 {
+ public:
+  ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+class ValueArray31 {
+ public:
+  ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+class ValueArray32 {
+ public:
+  ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+class ValueArray33 {
+ public:
+  ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+      T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+class ValueArray34 {
+ public:
+  ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+class ValueArray35 {
+ public:
+  ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+      v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+      v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_,
+        v35_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+class ValueArray36 {
+ public:
+  ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+      v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+      v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+class ValueArray37 {
+ public:
+  ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+      v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+      v36_(v36), v37_(v37) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+class ValueArray38 {
+ public:
+  ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+class ValueArray39 {
+ public:
+  ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+class ValueArray40 {
+ public:
+  ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+      v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+      v40_(v40) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+class ValueArray41 {
+ public:
+  ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+      T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_, v41_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+class ValueArray42 {
+ public:
+  ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_, v41_, v42_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+class ValueArray43 {
+ public:
+  ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+      v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+      v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+      v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+      v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+      v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),
+      v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+class ValueArray44 {
+ public:
+  ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+      v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+      v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+      v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+      v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+      v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),
+      v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),
+      v43_(v43), v44_(v44) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+class ValueArray45 {
+ public:
+  ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+      v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+      v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+      v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+      v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+      v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+      v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),
+      v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+class ValueArray46 {
+ public:
+  ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),
+      v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+      v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+class ValueArray47 {
+ public:
+  ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),
+      v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+      v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+      v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+      v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+      v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+      v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+      v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),
+      v47_(v47) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_,
+        v47_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+class ValueArray48 {
+ public:
+  ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),
+      v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+      v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+      v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+      v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+      v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+      v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+      v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),
+      v46_(v46), v47_(v47), v48_(v48) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+        v48_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+  const T48 v48_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+class ValueArray49 {
+ public:
+  ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,
+      T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+      v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+        v48_, v49_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+  const T48 v48_;
+  const T49 v49_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+class ValueArray50 {
+ public:
+  ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+      T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+      T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+      T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+      T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+      T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,
+      T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+      v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+      v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+      v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+      v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+      v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+      v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+      v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}
+
+  template <typename T>
+  operator ParamGenerator<T>() const {
+    const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+        v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+        v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+        v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+        v48_, v49_, v50_};
+    return ValuesIn(array);
+  }
+
+ private:
+  const T1 v1_;
+  const T2 v2_;
+  const T3 v3_;
+  const T4 v4_;
+  const T5 v5_;
+  const T6 v6_;
+  const T7 v7_;
+  const T8 v8_;
+  const T9 v9_;
+  const T10 v10_;
+  const T11 v11_;
+  const T12 v12_;
+  const T13 v13_;
+  const T14 v14_;
+  const T15 v15_;
+  const T16 v16_;
+  const T17 v17_;
+  const T18 v18_;
+  const T19 v19_;
+  const T20 v20_;
+  const T21 v21_;
+  const T22 v22_;
+  const T23 v23_;
+  const T24 v24_;
+  const T25 v25_;
+  const T26 v26_;
+  const T27 v27_;
+  const T28 v28_;
+  const T29 v29_;
+  const T30 v30_;
+  const T31 v31_;
+  const T32 v32_;
+  const T33 v33_;
+  const T34 v34_;
+  const T35 v35_;
+  const T36 v36_;
+  const T37 v37_;
+  const T38 v38_;
+  const T39 v39_;
+  const T40 v40_;
+  const T41 v41_;
+  const T42 v42_;
+  const T43 v43_;
+  const T44 v44_;
+  const T45 v45_;
+  const T46 v46_;
+  const T47 v47_;
+  const T48 v48_;
+  const T49 v49_;
+  const T50 v50_;
+};
+
+#if GTEST_HAS_COMBINE
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Generates values from the Cartesian product of values produced
+// by the argument generators.
+//
+template <typename T1, typename T2>
+class CartesianProductGenerator2
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2> ParamType;
+
+  CartesianProductGenerator2(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2)
+      : g1_(g1), g2_(g2) {}
+  virtual ~CartesianProductGenerator2() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current2_;
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_;
+    }
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    ParamType current_value_;
+  };
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+};
+
+
+template <typename T1, typename T2, typename T3>
+class CartesianProductGenerator3
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3> ParamType;
+
+  CartesianProductGenerator3(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
+      : g1_(g1), g2_(g2), g3_(g3) {}
+  virtual ~CartesianProductGenerator3() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current3_;
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_;
+    }
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    ParamType current_value_;
+  };
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4>
+class CartesianProductGenerator4
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;
+
+  CartesianProductGenerator4(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+  virtual ~CartesianProductGenerator4() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current4_;
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_;
+    }
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    ParamType current_value_;
+  };
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class CartesianProductGenerator5
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;
+
+  CartesianProductGenerator5(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+  virtual ~CartesianProductGenerator5() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current5_;
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_;
+    }
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    ParamType current_value_;
+  };
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+class CartesianProductGenerator6
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
+        T6> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;
+
+  CartesianProductGenerator6(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+  virtual ~CartesianProductGenerator6() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current6_;
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_;
+    }
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    ParamType current_value_;
+  };
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+class CartesianProductGenerator7
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
+
+  CartesianProductGenerator7(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+  virtual ~CartesianProductGenerator7() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current7_;
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_;
+    }
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    ParamType current_value_;
+  };
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+class CartesianProductGenerator8
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7, T8> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
+
+  CartesianProductGenerator8(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+      const ParamGenerator<T8>& g8)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+          g8_(g8) {}
+  virtual ~CartesianProductGenerator8() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin(), g8_, g8_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+        g8_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7,
+      const ParamGenerator<T8>& g8,
+      const typename ParamGenerator<T8>::iterator& current8)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+          begin8_(g8.begin()), end8_(g8.end()), current8_(current8)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current8_;
+      if (current8_ == end8_) {
+        current8_ = begin8_;
+        ++current7_;
+      }
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_ &&
+          current8_ == typed_other->current8_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_),
+        begin8_(other.begin8_),
+        end8_(other.end8_),
+        current8_(other.current8_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_, *current8_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_ ||
+          current8_ == end8_;
+    }
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    const typename ParamGenerator<T8>::iterator begin8_;
+    const typename ParamGenerator<T8>::iterator end8_;
+    typename ParamGenerator<T8>::iterator current8_;
+    ParamType current_value_;
+  };
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+  const ParamGenerator<T8> g8_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+class CartesianProductGenerator9
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7, T8, T9> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
+
+  CartesianProductGenerator9(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+      const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9) {}
+  virtual ~CartesianProductGenerator9() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+        g8_.end(), g9_, g9_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7,
+      const ParamGenerator<T8>& g8,
+      const typename ParamGenerator<T8>::iterator& current8,
+      const ParamGenerator<T9>& g9,
+      const typename ParamGenerator<T9>::iterator& current9)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+          begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+          begin9_(g9.begin()), end9_(g9.end()), current9_(current9)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current9_;
+      if (current9_ == end9_) {
+        current9_ = begin9_;
+        ++current8_;
+      }
+      if (current8_ == end8_) {
+        current8_ = begin8_;
+        ++current7_;
+      }
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_ &&
+          current8_ == typed_other->current8_ &&
+          current9_ == typed_other->current9_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_),
+        begin8_(other.begin8_),
+        end8_(other.end8_),
+        current8_(other.current8_),
+        begin9_(other.begin9_),
+        end9_(other.end9_),
+        current9_(other.current9_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_, *current8_,
+            *current9_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_ ||
+          current8_ == end8_ ||
+          current9_ == end9_;
+    }
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    const typename ParamGenerator<T8>::iterator begin8_;
+    const typename ParamGenerator<T8>::iterator end8_;
+    typename ParamGenerator<T8>::iterator current8_;
+    const typename ParamGenerator<T9>::iterator begin9_;
+    const typename ParamGenerator<T9>::iterator end9_;
+    typename ParamGenerator<T9>::iterator current9_;
+    ParamType current_value_;
+  };
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+  const ParamGenerator<T8> g8_;
+  const ParamGenerator<T9> g9_;
+};
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+class CartesianProductGenerator10
+    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+        T7, T8, T9, T10> > {
+ public:
+  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
+
+  CartesianProductGenerator10(const ParamGenerator<T1>& g1,
+      const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+      const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+      const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+      const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
+      const ParamGenerator<T10>& g10)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9), g10_(g10) {}
+  virtual ~CartesianProductGenerator10() {}
+
+  virtual ParamIteratorInterface<ParamType>* Begin() const {
+    return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+        g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+        g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
+  }
+  virtual ParamIteratorInterface<ParamType>* End() const {
+    return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+        g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+        g8_.end(), g9_, g9_.end(), g10_, g10_.end());
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<ParamType> {
+   public:
+    Iterator(const ParamGeneratorInterface<ParamType>* base,
+      const ParamGenerator<T1>& g1,
+      const typename ParamGenerator<T1>::iterator& current1,
+      const ParamGenerator<T2>& g2,
+      const typename ParamGenerator<T2>::iterator& current2,
+      const ParamGenerator<T3>& g3,
+      const typename ParamGenerator<T3>::iterator& current3,
+      const ParamGenerator<T4>& g4,
+      const typename ParamGenerator<T4>::iterator& current4,
+      const ParamGenerator<T5>& g5,
+      const typename ParamGenerator<T5>::iterator& current5,
+      const ParamGenerator<T6>& g6,
+      const typename ParamGenerator<T6>::iterator& current6,
+      const ParamGenerator<T7>& g7,
+      const typename ParamGenerator<T7>::iterator& current7,
+      const ParamGenerator<T8>& g8,
+      const typename ParamGenerator<T8>::iterator& current8,
+      const ParamGenerator<T9>& g9,
+      const typename ParamGenerator<T9>::iterator& current9,
+      const ParamGenerator<T10>& g10,
+      const typename ParamGenerator<T10>::iterator& current10)
+        : base_(base),
+          begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+          begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+          begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+          begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+          begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+          begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+          begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+          begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+          begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
+          begin10_(g10.begin()), end10_(g10.end()), current10_(current10)    {
+      ComputeCurrentValue();
+    }
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+      return base_;
+    }
+    // Advance should not be called on beyond-of-range iterators
+    // so no component iterators must be beyond end of range, either.
+    virtual void Advance() {
+      assert(!AtEnd());
+      ++current10_;
+      if (current10_ == end10_) {
+        current10_ = begin10_;
+        ++current9_;
+      }
+      if (current9_ == end9_) {
+        current9_ = begin9_;
+        ++current8_;
+      }
+      if (current8_ == end8_) {
+        current8_ = begin8_;
+        ++current7_;
+      }
+      if (current7_ == end7_) {
+        current7_ = begin7_;
+        ++current6_;
+      }
+      if (current6_ == end6_) {
+        current6_ = begin6_;
+        ++current5_;
+      }
+      if (current5_ == end5_) {
+        current5_ = begin5_;
+        ++current4_;
+      }
+      if (current4_ == end4_) {
+        current4_ = begin4_;
+        ++current3_;
+      }
+      if (current3_ == end3_) {
+        current3_ = begin3_;
+        ++current2_;
+      }
+      if (current2_ == end2_) {
+        current2_ = begin2_;
+        ++current1_;
+      }
+      ComputeCurrentValue();
+    }
+    virtual ParamIteratorInterface<ParamType>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const ParamType* Current() const { return &current_value_; }
+    virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const Iterator* typed_other =
+          CheckedDowncastToActualType<const Iterator>(&other);
+      // We must report iterators equal if they both point beyond their
+      // respective ranges. That can happen in a variety of fashions,
+      // so we have to consult AtEnd().
+      return (AtEnd() && typed_other->AtEnd()) ||
+         (
+          current1_ == typed_other->current1_ &&
+          current2_ == typed_other->current2_ &&
+          current3_ == typed_other->current3_ &&
+          current4_ == typed_other->current4_ &&
+          current5_ == typed_other->current5_ &&
+          current6_ == typed_other->current6_ &&
+          current7_ == typed_other->current7_ &&
+          current8_ == typed_other->current8_ &&
+          current9_ == typed_other->current9_ &&
+          current10_ == typed_other->current10_);
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_),
+        begin1_(other.begin1_),
+        end1_(other.end1_),
+        current1_(other.current1_),
+        begin2_(other.begin2_),
+        end2_(other.end2_),
+        current2_(other.current2_),
+        begin3_(other.begin3_),
+        end3_(other.end3_),
+        current3_(other.current3_),
+        begin4_(other.begin4_),
+        end4_(other.end4_),
+        current4_(other.current4_),
+        begin5_(other.begin5_),
+        end5_(other.end5_),
+        current5_(other.current5_),
+        begin6_(other.begin6_),
+        end6_(other.end6_),
+        current6_(other.current6_),
+        begin7_(other.begin7_),
+        end7_(other.end7_),
+        current7_(other.current7_),
+        begin8_(other.begin8_),
+        end8_(other.end8_),
+        current8_(other.current8_),
+        begin9_(other.begin9_),
+        end9_(other.end9_),
+        current9_(other.current9_),
+        begin10_(other.begin10_),
+        end10_(other.end10_),
+        current10_(other.current10_) {
+      ComputeCurrentValue();
+    }
+
+    void ComputeCurrentValue() {
+      if (!AtEnd())
+        current_value_ = ParamType(*current1_, *current2_, *current3_,
+            *current4_, *current5_, *current6_, *current7_, *current8_,
+            *current9_, *current10_);
+    }
+    bool AtEnd() const {
+      // We must report iterator past the end of the range when either of the
+      // component iterators has reached the end of its range.
+      return
+          current1_ == end1_ ||
+          current2_ == end2_ ||
+          current3_ == end3_ ||
+          current4_ == end4_ ||
+          current5_ == end5_ ||
+          current6_ == end6_ ||
+          current7_ == end7_ ||
+          current8_ == end8_ ||
+          current9_ == end9_ ||
+          current10_ == end10_;
+    }
+
+    const ParamGeneratorInterface<ParamType>* const base_;
+    // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+    // current[i]_ is the actual traversing iterator.
+    const typename ParamGenerator<T1>::iterator begin1_;
+    const typename ParamGenerator<T1>::iterator end1_;
+    typename ParamGenerator<T1>::iterator current1_;
+    const typename ParamGenerator<T2>::iterator begin2_;
+    const typename ParamGenerator<T2>::iterator end2_;
+    typename ParamGenerator<T2>::iterator current2_;
+    const typename ParamGenerator<T3>::iterator begin3_;
+    const typename ParamGenerator<T3>::iterator end3_;
+    typename ParamGenerator<T3>::iterator current3_;
+    const typename ParamGenerator<T4>::iterator begin4_;
+    const typename ParamGenerator<T4>::iterator end4_;
+    typename ParamGenerator<T4>::iterator current4_;
+    const typename ParamGenerator<T5>::iterator begin5_;
+    const typename ParamGenerator<T5>::iterator end5_;
+    typename ParamGenerator<T5>::iterator current5_;
+    const typename ParamGenerator<T6>::iterator begin6_;
+    const typename ParamGenerator<T6>::iterator end6_;
+    typename ParamGenerator<T6>::iterator current6_;
+    const typename ParamGenerator<T7>::iterator begin7_;
+    const typename ParamGenerator<T7>::iterator end7_;
+    typename ParamGenerator<T7>::iterator current7_;
+    const typename ParamGenerator<T8>::iterator begin8_;
+    const typename ParamGenerator<T8>::iterator end8_;
+    typename ParamGenerator<T8>::iterator current8_;
+    const typename ParamGenerator<T9>::iterator begin9_;
+    const typename ParamGenerator<T9>::iterator end9_;
+    typename ParamGenerator<T9>::iterator current9_;
+    const typename ParamGenerator<T10>::iterator begin10_;
+    const typename ParamGenerator<T10>::iterator end10_;
+    typename ParamGenerator<T10>::iterator current10_;
+    ParamType current_value_;
+  };
+
+  const ParamGenerator<T1> g1_;
+  const ParamGenerator<T2> g2_;
+  const ParamGenerator<T3> g3_;
+  const ParamGenerator<T4> g4_;
+  const ParamGenerator<T5> g5_;
+  const ParamGenerator<T6> g6_;
+  const ParamGenerator<T7> g7_;
+  const ParamGenerator<T8> g8_;
+  const ParamGenerator<T9> g9_;
+  const ParamGenerator<T10> g10_;
+};
+
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Helper classes providing Combine() with polymorphic features. They allow
+// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
+// convertible to U.
+//
+template <class Generator1, class Generator2>
+class CartesianProductHolder2 {
+ public:
+CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
+      : g1_(g1), g2_(g2) {}
+  template <typename T1, typename T2>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
+        new CartesianProductGenerator2<T1, T2>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_)));
+  }
+
+ private:
+  const Generator1 g1_;
+  const Generator2 g2_;
+};
+
+template <class Generator1, class Generator2, class Generator3>
+class CartesianProductHolder3 {
+ public:
+CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3)
+      : g1_(g1), g2_(g2), g3_(g3) {}
+  template <typename T1, typename T2, typename T3>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
+        new CartesianProductGenerator3<T1, T2, T3>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_)));
+  }
+
+ private:
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4>
+class CartesianProductHolder4 {
+ public:
+CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+  template <typename T1, typename T2, typename T3, typename T4>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
+        new CartesianProductGenerator4<T1, T2, T3, T4>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_)));
+  }
+
+ private:
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5>
+class CartesianProductHolder5 {
+ public:
+CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
+        new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_)));
+  }
+
+ private:
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6>
+class CartesianProductHolder6 {
+ public:
+CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
+        new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_)));
+  }
+
+ private:
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7>
+class CartesianProductHolder7 {
+ public:
+CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+      T7> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
+        new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_)));
+  }
+
+ private:
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7,
+    class Generator8>
+class CartesianProductHolder8 {
+ public:
+CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7, const Generator8& g8)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+          g8_(g8) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7, typename T8>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
+      T8> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
+        new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_),
+        static_cast<ParamGenerator<T8> >(g8_)));
+  }
+
+ private:
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+  const Generator8 g8_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7,
+    class Generator8, class Generator9>
+class CartesianProductHolder9 {
+ public:
+CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7, const Generator8& g8,
+    const Generator9& g9)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7, typename T8, typename T9>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+      T9> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+        T9> >(
+        new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_),
+        static_cast<ParamGenerator<T8> >(g8_),
+        static_cast<ParamGenerator<T9> >(g9_)));
+  }
+
+ private:
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+  const Generator8 g8_;
+  const Generator9 g9_;
+};
+
+template <class Generator1, class Generator2, class Generator3,
+    class Generator4, class Generator5, class Generator6, class Generator7,
+    class Generator8, class Generator9, class Generator10>
+class CartesianProductHolder10 {
+ public:
+CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
+    const Generator3& g3, const Generator4& g4, const Generator5& g5,
+    const Generator6& g6, const Generator7& g7, const Generator8& g8,
+    const Generator9& g9, const Generator10& g10)
+      : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+          g9_(g9), g10_(g10) {}
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+      typename T6, typename T7, typename T8, typename T9, typename T10>
+  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+      T9, T10> >() const {
+    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+        T9, T10> >(
+        new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+            T10>(
+        static_cast<ParamGenerator<T1> >(g1_),
+        static_cast<ParamGenerator<T2> >(g2_),
+        static_cast<ParamGenerator<T3> >(g3_),
+        static_cast<ParamGenerator<T4> >(g4_),
+        static_cast<ParamGenerator<T5> >(g5_),
+        static_cast<ParamGenerator<T6> >(g6_),
+        static_cast<ParamGenerator<T7> >(g7_),
+        static_cast<ParamGenerator<T8> >(g8_),
+        static_cast<ParamGenerator<T9> >(g9_),
+        static_cast<ParamGenerator<T10> >(g10_)));
+  }
+
+ private:
+  const Generator1 g1_;
+  const Generator2 g2_;
+  const Generator3 g3_;
+  const Generator4 g4_;
+  const Generator5 g5_;
+  const Generator6 g6_;
+  const Generator7 g7_;
+  const Generator8 g8_;
+  const Generator9 g9_;
+  const Generator10 g10_;
+};
+
+#endif  // GTEST_HAS_COMBINE
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  //  GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
diff --git a/third_party/gtest/include/gtest/internal/gtest-param-util.h b/third_party/gtest/include/gtest/internal/gtest-param-util.h
index ad47cfd..34361ab 100644
--- a/third_party/gtest/include/gtest/internal/gtest-param-util.h
+++ b/third_party/gtest/include/gtest/internal/gtest-param-util.h
@@ -1,629 +1,629 @@
-// Copyright 2008 Google Inc.

-// All Rights Reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: vladl@google.com (Vlad Losev)

-

-// Type and function utilities for implementing parameterized tests.

-

-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_

-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_

-

-#include <iterator>

-#include <utility>

-#include <vector>

-

-#include <gtest/internal/gtest-port.h>

-

-#if GTEST_HAS_PARAM_TEST

-

-#if GTEST_HAS_RTTI

-#include <typeinfo>

-#endif  // GTEST_HAS_RTTI

-

-#include <gtest/internal/gtest-linked_ptr.h>

-#include <gtest/internal/gtest-internal.h>

-

-namespace testing {

-namespace internal {

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// Outputs a message explaining invalid registration of different

-// fixture class for the same test case. This may happen when

-// TEST_P macro is used to define two tests with the same name

-// but in different namespaces.

-void ReportInvalidTestCaseType(const char* test_case_name,

-                               const char* file, int line);

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// Downcasts the pointer of type Base to Derived.

-// Derived must be a subclass of Base. The parameter MUST

-// point to a class of type Derived, not any subclass of it.

-// When RTTI is available, the function performs a runtime

-// check to enforce this.

-template <class Derived, class Base>

-Derived* CheckedDowncastToActualType(Base* base) {

-#if GTEST_HAS_RTTI

-  GTEST_CHECK_(typeid(*base) == typeid(Derived));

-  Derived* derived = dynamic_cast<Derived*>(base);  // NOLINT

-#else

-  Derived* derived = static_cast<Derived*>(base);  // Poor man's downcast.

-#endif  // GTEST_HAS_RTTI

-  return derived;

-}

-

-template <typename> class ParamGeneratorInterface;

-template <typename> class ParamGenerator;

-

-// Interface for iterating over elements provided by an implementation

-// of ParamGeneratorInterface<T>.

-template <typename T>

-class ParamIteratorInterface {

- public:

-  virtual ~ParamIteratorInterface() {}

-  // A pointer to the base generator instance.

-  // Used only for the purposes of iterator comparison

-  // to make sure that two iterators belong to the same generator.

-  virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;

-  // Advances iterator to point to the next element

-  // provided by the generator. The caller is responsible

-  // for not calling Advance() on an iterator equal to

-  // BaseGenerator()->End().

-  virtual void Advance() = 0;

-  // Clones the iterator object. Used for implementing copy semantics

-  // of ParamIterator<T>.

-  virtual ParamIteratorInterface* Clone() const = 0;

-  // Dereferences the current iterator and provides (read-only) access

-  // to the pointed value. It is the caller's responsibility not to call

-  // Current() on an iterator equal to BaseGenerator()->End().

-  // Used for implementing ParamGenerator<T>::operator*().

-  virtual const T* Current() const = 0;

-  // Determines whether the given iterator and other point to the same

-  // element in the sequence generated by the generator.

-  // Used for implementing ParamGenerator<T>::operator==().

-  virtual bool Equals(const ParamIteratorInterface& other) const = 0;

-};

-

-// Class iterating over elements provided by an implementation of

-// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>

-// and implements the const forward iterator concept.

-template <typename T>

-class ParamIterator {

- public:

-  typedef T value_type;

-  typedef const T& reference;

-  typedef ptrdiff_t difference_type;

-

-  // ParamIterator assumes ownership of the impl_ pointer.

-  ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}

-  ParamIterator& operator=(const ParamIterator& other) {

-    if (this != &other)

-      impl_.reset(other.impl_->Clone());

-    return *this;

-  }

-

-  const T& operator*() const { return *impl_->Current(); }

-  const T* operator->() const { return impl_->Current(); }

-  // Prefix version of operator++.

-  ParamIterator& operator++() {

-    impl_->Advance();

-    return *this;

-  }

-  // Postfix version of operator++.

-  ParamIterator operator++(int /*unused*/) {

-    ParamIteratorInterface<T>* clone = impl_->Clone();

-    impl_->Advance();

-    return ParamIterator(clone);

-  }

-  bool operator==(const ParamIterator& other) const {

-    return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);

-  }

-  bool operator!=(const ParamIterator& other) const {

-    return !(*this == other);

-  }

-

- private:

-  friend class ParamGenerator<T>;

-  explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}

-  scoped_ptr<ParamIteratorInterface<T> > impl_;

-};

-

-// ParamGeneratorInterface<T> is the binary interface to access generators

-// defined in other translation units.

-template <typename T>

-class ParamGeneratorInterface {

- public:

-  typedef T ParamType;

-

-  virtual ~ParamGeneratorInterface() {}

-

-  // Generator interface definition

-  virtual ParamIteratorInterface<T>* Begin() const = 0;

-  virtual ParamIteratorInterface<T>* End() const = 0;

-};

-

-// Wraps ParamGeneratorInetrface<T> and provides general generator syntax

-// compatible with the STL Container concept.

-// This class implements copy initialization semantics and the contained

-// ParamGeneratorInterface<T> instance is shared among all copies

-// of the original object. This is possible because that instance is immutable.

-template<typename T>

-class ParamGenerator {

- public:

-  typedef ParamIterator<T> iterator;

-

-  explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}

-  ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}

-

-  ParamGenerator& operator=(const ParamGenerator& other) {

-    impl_ = other.impl_;

-    return *this;

-  }

-

-  iterator begin() const { return iterator(impl_->Begin()); }

-  iterator end() const { return iterator(impl_->End()); }

-

- private:

-  ::testing::internal::linked_ptr<const ParamGeneratorInterface<T> > impl_;

-};

-

-// Generates values from a range of two comparable values. Can be used to

-// generate sequences of user-defined types that implement operator+() and

-// operator<().

-// This class is used in the Range() function.

-template <typename T, typename IncrementT>

-class RangeGenerator : public ParamGeneratorInterface<T> {

- public:

-  RangeGenerator(T begin, T end, IncrementT step)

-      : begin_(begin), end_(end),

-        step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}

-  virtual ~RangeGenerator() {}

-

-  virtual ParamIteratorInterface<T>* Begin() const {

-    return new Iterator(this, begin_, 0, step_);

-  }

-  virtual ParamIteratorInterface<T>* End() const {

-    return new Iterator(this, end_, end_index_, step_);

-  }

-

- private:

-  class Iterator : public ParamIteratorInterface<T> {

-   public:

-    Iterator(const ParamGeneratorInterface<T>* base, T value, int index,

-             IncrementT step)

-        : base_(base), value_(value), index_(index), step_(step) {}

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {

-      return base_;

-    }

-    virtual void Advance() {

-      value_ = value_ + step_;

-      index_++;

-    }

-    virtual ParamIteratorInterface<T>* Clone() const {

-      return new Iterator(*this);

-    }

-    virtual const T* Current() const { return &value_; }

-    virtual bool Equals(const ParamIteratorInterface<T>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      const int other_index =

-          CheckedDowncastToActualType<const Iterator>(&other)->index_;

-      return index_ == other_index;

-    }

-

-   private:

-    Iterator(const Iterator& other)

-        : base_(other.base_), value_(other.value_), index_(other.index_),

-          step_(other.step_) {}

-

-    const ParamGeneratorInterface<T>* const base_;

-    T value_;

-    int index_;

-    const IncrementT step_;

-  };  // class RangeGenerator::Iterator

-

-  static int CalculateEndIndex(const T& begin,

-                               const T& end,

-                               const IncrementT& step) {

-    int end_index = 0;

-    for (T i = begin; i < end; i = i + step)

-      end_index++;

-    return end_index;

-  }

-

-  const T begin_;

-  const T end_;

-  const IncrementT step_;

-  // The index for the end() iterator. All the elements in the generated

-  // sequence are indexed (0-based) to aid iterator comparison.

-  const int end_index_;

-};  // class RangeGenerator

-

-

-// Generates values from a pair of STL-style iterators. Used in the

-// ValuesIn() function. The elements are copied from the source range

-// since the source can be located on the stack, and the generator

-// is likely to persist beyond that stack frame.

-template <typename T>

-class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {

- public:

-  template <typename ForwardIterator>

-  ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)

-      : container_(begin, end) {}

-  virtual ~ValuesInIteratorRangeGenerator() {}

-

-  virtual ParamIteratorInterface<T>* Begin() const {

-    return new Iterator(this, container_.begin());

-  }

-  virtual ParamIteratorInterface<T>* End() const {

-    return new Iterator(this, container_.end());

-  }

-

- private:

-  typedef typename ::std::vector<T> ContainerType;

-

-  class Iterator : public ParamIteratorInterface<T> {

-   public:

-    Iterator(const ParamGeneratorInterface<T>* base,

-             typename ContainerType::const_iterator iterator)

-        :  base_(base), iterator_(iterator) {}

-    virtual ~Iterator() {}

-

-    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {

-      return base_;

-    }

-    virtual void Advance() {

-      ++iterator_;

-      value_.reset();

-    }

-    virtual ParamIteratorInterface<T>* Clone() const {

-      return new Iterator(*this);

-    }

-    // We need to use cached value referenced by iterator_ because *iterator_

-    // can return a temporary object (and of type other then T), so just

-    // having "return &*iterator_;" doesn't work.

-    // value_ is updated here and not in Advance() because Advance()

-    // can advance iterator_ beyond the end of the range, and we cannot

-    // detect that fact. The client code, on the other hand, is

-    // responsible for not calling Current() on an out-of-range iterator.

-    virtual const T* Current() const {

-      if (value_.get() == NULL)

-        value_.reset(new T(*iterator_));

-      return value_.get();

-    }

-    virtual bool Equals(const ParamIteratorInterface<T>& other) const {

-      // Having the same base generator guarantees that the other

-      // iterator is of the same type and we can downcast.

-      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())

-          << "The program attempted to compare iterators "

-          << "from different generators." << std::endl;

-      return iterator_ ==

-          CheckedDowncastToActualType<const Iterator>(&other)->iterator_;

-    }

-

-   private:

-    Iterator(const Iterator& other)

-          // The explicit constructor call suppresses a false warning

-          // emitted by gcc when supplied with the -Wextra option.

-        : ParamIteratorInterface<T>(),

-          base_(other.base_),

-          iterator_(other.iterator_) {}

-

-    const ParamGeneratorInterface<T>* const base_;

-    typename ContainerType::const_iterator iterator_;

-    // A cached value of *iterator_. We keep it here to allow access by

-    // pointer in the wrapping iterator's operator->().

-    // value_ needs to be mutable to be accessed in Current().

-    // Use of scoped_ptr helps manage cached value's lifetime,

-    // which is bound by the lifespan of the iterator itself.

-    mutable scoped_ptr<const T> value_;

-  };

-

-  const ContainerType container_;

-};  // class ValuesInIteratorRangeGenerator

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// Stores a parameter value and later creates tests parameterized with that

-// value.

-template <class TestClass>

-class ParameterizedTestFactory : public TestFactoryBase {

- public:

-  typedef typename TestClass::ParamType ParamType;

-  explicit ParameterizedTestFactory(ParamType parameter) :

-      parameter_(parameter) {}

-  virtual Test* CreateTest() {

-    TestClass::SetParam(&parameter_);

-    return new TestClass();

-  }

-

- private:

-  const ParamType parameter_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);

-};

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// TestMetaFactoryBase is a base class for meta-factories that create

-// test factories for passing into MakeAndRegisterTestInfo function.

-template <class ParamType>

-class TestMetaFactoryBase {

- public:

-  virtual ~TestMetaFactoryBase() {}

-

-  virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;

-};

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// TestMetaFactory creates test factories for passing into

-// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives

-// ownership of test factory pointer, same factory object cannot be passed

-// into that method twice. But ParameterizedTestCaseInfo is going to call

-// it for each Test/Parameter value combination. Thus it needs meta factory

-// creator class.

-template <class TestCase>

-class TestMetaFactory

-    : public TestMetaFactoryBase<typename TestCase::ParamType> {

- public:

-  typedef typename TestCase::ParamType ParamType;

-

-  TestMetaFactory() {}

-

-  virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {

-    return new ParameterizedTestFactory<TestCase>(parameter);

-  }

-

- private:

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);

-};

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// ParameterizedTestCaseInfoBase is a generic interface

-// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase

-// accumulates test information provided by TEST_P macro invocations

-// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations

-// and uses that information to register all resulting test instances

-// in RegisterTests method. The ParameterizeTestCaseRegistry class holds

-// a collection of pointers to the ParameterizedTestCaseInfo objects

-// and calls RegisterTests() on each of them when asked.

-class ParameterizedTestCaseInfoBase {

- public:

-  virtual ~ParameterizedTestCaseInfoBase() {}

-

-  // Base part of test case name for display purposes.

-  virtual const String& GetTestCaseName() const = 0;

-  // Test case id to verify identity.

-  virtual TypeId GetTestCaseTypeId() const = 0;

-  // UnitTest class invokes this method to register tests in this

-  // test case right before running them in RUN_ALL_TESTS macro.

-  // This method should not be called more then once on any single

-  // instance of a ParameterizedTestCaseInfoBase derived class.

-  virtual void RegisterTests() = 0;

-

- protected:

-  ParameterizedTestCaseInfoBase() {}

-

- private:

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);

-};

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P

-// macro invocations for a particular test case and generators

-// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that

-// test case. It registers tests with all values generated by all

-// generators when asked.

-template <class TestCase>

-class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {

- public:

-  // ParamType and GeneratorCreationFunc are private types but are required

-  // for declarations of public methods AddTestPattern() and

-  // AddTestCaseInstantiation().

-  typedef typename TestCase::ParamType ParamType;

-  // A function that returns an instance of appropriate generator type.

-  typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();

-

-  explicit ParameterizedTestCaseInfo(const char* name)

-      : test_case_name_(name) {}

-

-  // Test case base name for display purposes.

-  virtual const String& GetTestCaseName() const { return test_case_name_; }

-  // Test case id to verify identity.

-  virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }

-  // TEST_P macro uses AddTestPattern() to record information

-  // about a single test in a LocalTestInfo structure.

-  // test_case_name is the base name of the test case (without invocation

-  // prefix). test_base_name is the name of an individual test without

-  // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is

-  // test case base name and DoBar is test base name.

-  void AddTestPattern(const char* test_case_name,

-                      const char* test_base_name,

-                      TestMetaFactoryBase<ParamType>* meta_factory) {

-    tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,

-                                                       test_base_name,

-                                                       meta_factory)));

-  }

-  // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information

-  // about a generator.

-  int AddTestCaseInstantiation(const char* instantiation_name,

-                               GeneratorCreationFunc* func,

-                               const char* /* file */,

-                               int /* line */) {

-    instantiations_.push_back(::std::make_pair(instantiation_name, func));

-    return 0;  // Return value used only to run this method in namespace scope.

-  }

-  // UnitTest class invokes this method to register tests in this test case

-  // test cases right before running tests in RUN_ALL_TESTS macro.

-  // This method should not be called more then once on any single

-  // instance of a ParameterizedTestCaseInfoBase derived class.

-  // UnitTest has a guard to prevent from calling this method more then once.

-  virtual void RegisterTests() {

-    for (typename TestInfoContainer::iterator test_it = tests_.begin();

-         test_it != tests_.end(); ++test_it) {

-      linked_ptr<TestInfo> test_info = *test_it;

-      for (typename InstantiationContainer::iterator gen_it =

-               instantiations_.begin(); gen_it != instantiations_.end();

-               ++gen_it) {

-        const String& instantiation_name = gen_it->first;

-        ParamGenerator<ParamType> generator((*gen_it->second)());

-

-        Message test_case_name_stream;

-        if ( !instantiation_name.empty() )

-          test_case_name_stream << instantiation_name.c_str() << "/";

-        test_case_name_stream << test_info->test_case_base_name.c_str();

-

-        int i = 0;

-        for (typename ParamGenerator<ParamType>::iterator param_it =

-                 generator.begin();

-             param_it != generator.end(); ++param_it, ++i) {

-          Message test_name_stream;

-          test_name_stream << test_info->test_base_name.c_str() << "/" << i;

-          ::testing::internal::MakeAndRegisterTestInfo(

-              test_case_name_stream.GetString().c_str(),

-              test_name_stream.GetString().c_str(),

-              "",  // test_case_comment

-              "",  // comment; TODO(vladl@google.com): provide parameter value

-                   //                                  representation.

-              GetTestCaseTypeId(),

-              TestCase::SetUpTestCase,

-              TestCase::TearDownTestCase,

-              test_info->test_meta_factory->CreateTestFactory(*param_it));

-        }  // for param_it

-      }  // for gen_it

-    }  // for test_it

-  }  // RegisterTests

-

- private:

-  // LocalTestInfo structure keeps information about a single test registered

-  // with TEST_P macro.

-  struct TestInfo {

-    TestInfo(const char* test_case_base_name,

-             const char* test_base_name,

-             TestMetaFactoryBase<ParamType>* test_meta_factory) :

-        test_case_base_name(test_case_base_name),

-        test_base_name(test_base_name),

-        test_meta_factory(test_meta_factory) {}

-

-    const String test_case_base_name;

-    const String test_base_name;

-    const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;

-  };

-  typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;

-  // Keeps pairs of <Instantiation name, Sequence generator creation function>

-  // received from INSTANTIATE_TEST_CASE_P macros.

-  typedef ::std::vector<std::pair<String, GeneratorCreationFunc*> >

-      InstantiationContainer;

-

-  const String test_case_name_;

-  TestInfoContainer tests_;

-  InstantiationContainer instantiations_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);

-};  // class ParameterizedTestCaseInfo

-

-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.

-//

-// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase

-// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P

-// macros use it to locate their corresponding ParameterizedTestCaseInfo

-// descriptors.

-class ParameterizedTestCaseRegistry {

- public:

-  ParameterizedTestCaseRegistry() {}

-  ~ParameterizedTestCaseRegistry() {

-    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();

-         it != test_case_infos_.end(); ++it) {

-      delete *it;

-    }

-  }

-

-  // Looks up or creates and returns a structure containing information about

-  // tests and instantiations of a particular test case.

-  template <class TestCase>

-  ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(

-      const char* test_case_name,

-      const char* file,

-      int line) {

-    ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;

-    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();

-         it != test_case_infos_.end(); ++it) {

-      if ((*it)->GetTestCaseName() == test_case_name) {

-        if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {

-          // Complain about incorrect usage of Google Test facilities

-          // and terminate the program since we cannot guaranty correct

-          // test case setup and tear-down in this case.

-          ReportInvalidTestCaseType(test_case_name,  file, line);

-          abort();

-        } else {

-          // At this point we are sure that the object we found is of the same

-          // type we are looking for, so we downcast it to that type

-          // without further checks.

-          typed_test_info = CheckedDowncastToActualType<

-              ParameterizedTestCaseInfo<TestCase> >(*it);

-        }

-        break;

-      }

-    }

-    if (typed_test_info == NULL) {

-      typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);

-      test_case_infos_.push_back(typed_test_info);

-    }

-    return typed_test_info;

-  }

-  void RegisterTests() {

-    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();

-         it != test_case_infos_.end(); ++it) {

-      (*it)->RegisterTests();

-    }

-  }

-

- private:

-  typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;

-

-  TestCaseInfoContainer test_case_infos_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);

-};

-

-}  // namespace internal

-}  // namespace testing

-

-#endif  //  GTEST_HAS_PARAM_TEST

-

-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_

+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+
+#include <iterator>
+#include <utility>
+#include <vector>
+
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+#if GTEST_HAS_RTTI
+#include <typeinfo>
+#endif  // GTEST_HAS_RTTI
+
+#include <gtest/internal/gtest-linked_ptr.h>
+#include <gtest/internal/gtest-internal.h>
+
+namespace testing {
+namespace internal {
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Outputs a message explaining invalid registration of different
+// fixture class for the same test case. This may happen when
+// TEST_P macro is used to define two tests with the same name
+// but in different namespaces.
+void ReportInvalidTestCaseType(const char* test_case_name,
+                               const char* file, int line);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Downcasts the pointer of type Base to Derived.
+// Derived must be a subclass of Base. The parameter MUST
+// point to a class of type Derived, not any subclass of it.
+// When RTTI is available, the function performs a runtime
+// check to enforce this.
+template <class Derived, class Base>
+Derived* CheckedDowncastToActualType(Base* base) {
+#if GTEST_HAS_RTTI
+  GTEST_CHECK_(typeid(*base) == typeid(Derived));
+  Derived* derived = dynamic_cast<Derived*>(base);  // NOLINT
+#else
+  Derived* derived = static_cast<Derived*>(base);  // Poor man's downcast.
+#endif  // GTEST_HAS_RTTI
+  return derived;
+}
+
+template <typename> class ParamGeneratorInterface;
+template <typename> class ParamGenerator;
+
+// Interface for iterating over elements provided by an implementation
+// of ParamGeneratorInterface<T>.
+template <typename T>
+class ParamIteratorInterface {
+ public:
+  virtual ~ParamIteratorInterface() {}
+  // A pointer to the base generator instance.
+  // Used only for the purposes of iterator comparison
+  // to make sure that two iterators belong to the same generator.
+  virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
+  // Advances iterator to point to the next element
+  // provided by the generator. The caller is responsible
+  // for not calling Advance() on an iterator equal to
+  // BaseGenerator()->End().
+  virtual void Advance() = 0;
+  // Clones the iterator object. Used for implementing copy semantics
+  // of ParamIterator<T>.
+  virtual ParamIteratorInterface* Clone() const = 0;
+  // Dereferences the current iterator and provides (read-only) access
+  // to the pointed value. It is the caller's responsibility not to call
+  // Current() on an iterator equal to BaseGenerator()->End().
+  // Used for implementing ParamGenerator<T>::operator*().
+  virtual const T* Current() const = 0;
+  // Determines whether the given iterator and other point to the same
+  // element in the sequence generated by the generator.
+  // Used for implementing ParamGenerator<T>::operator==().
+  virtual bool Equals(const ParamIteratorInterface& other) const = 0;
+};
+
+// Class iterating over elements provided by an implementation of
+// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
+// and implements the const forward iterator concept.
+template <typename T>
+class ParamIterator {
+ public:
+  typedef T value_type;
+  typedef const T& reference;
+  typedef ptrdiff_t difference_type;
+
+  // ParamIterator assumes ownership of the impl_ pointer.
+  ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
+  ParamIterator& operator=(const ParamIterator& other) {
+    if (this != &other)
+      impl_.reset(other.impl_->Clone());
+    return *this;
+  }
+
+  const T& operator*() const { return *impl_->Current(); }
+  const T* operator->() const { return impl_->Current(); }
+  // Prefix version of operator++.
+  ParamIterator& operator++() {
+    impl_->Advance();
+    return *this;
+  }
+  // Postfix version of operator++.
+  ParamIterator operator++(int /*unused*/) {
+    ParamIteratorInterface<T>* clone = impl_->Clone();
+    impl_->Advance();
+    return ParamIterator(clone);
+  }
+  bool operator==(const ParamIterator& other) const {
+    return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
+  }
+  bool operator!=(const ParamIterator& other) const {
+    return !(*this == other);
+  }
+
+ private:
+  friend class ParamGenerator<T>;
+  explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
+  scoped_ptr<ParamIteratorInterface<T> > impl_;
+};
+
+// ParamGeneratorInterface<T> is the binary interface to access generators
+// defined in other translation units.
+template <typename T>
+class ParamGeneratorInterface {
+ public:
+  typedef T ParamType;
+
+  virtual ~ParamGeneratorInterface() {}
+
+  // Generator interface definition
+  virtual ParamIteratorInterface<T>* Begin() const = 0;
+  virtual ParamIteratorInterface<T>* End() const = 0;
+};
+
+// Wraps ParamGeneratorInetrface<T> and provides general generator syntax
+// compatible with the STL Container concept.
+// This class implements copy initialization semantics and the contained
+// ParamGeneratorInterface<T> instance is shared among all copies
+// of the original object. This is possible because that instance is immutable.
+template<typename T>
+class ParamGenerator {
+ public:
+  typedef ParamIterator<T> iterator;
+
+  explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
+  ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
+
+  ParamGenerator& operator=(const ParamGenerator& other) {
+    impl_ = other.impl_;
+    return *this;
+  }
+
+  iterator begin() const { return iterator(impl_->Begin()); }
+  iterator end() const { return iterator(impl_->End()); }
+
+ private:
+  ::testing::internal::linked_ptr<const ParamGeneratorInterface<T> > impl_;
+};
+
+// Generates values from a range of two comparable values. Can be used to
+// generate sequences of user-defined types that implement operator+() and
+// operator<().
+// This class is used in the Range() function.
+template <typename T, typename IncrementT>
+class RangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+  RangeGenerator(T begin, T end, IncrementT step)
+      : begin_(begin), end_(end),
+        step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
+  virtual ~RangeGenerator() {}
+
+  virtual ParamIteratorInterface<T>* Begin() const {
+    return new Iterator(this, begin_, 0, step_);
+  }
+  virtual ParamIteratorInterface<T>* End() const {
+    return new Iterator(this, end_, end_index_, step_);
+  }
+
+ private:
+  class Iterator : public ParamIteratorInterface<T> {
+   public:
+    Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
+             IncrementT step)
+        : base_(base), value_(value), index_(index), step_(step) {}
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+      return base_;
+    }
+    virtual void Advance() {
+      value_ = value_ + step_;
+      index_++;
+    }
+    virtual ParamIteratorInterface<T>* Clone() const {
+      return new Iterator(*this);
+    }
+    virtual const T* Current() const { return &value_; }
+    virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      const int other_index =
+          CheckedDowncastToActualType<const Iterator>(&other)->index_;
+      return index_ == other_index;
+    }
+
+   private:
+    Iterator(const Iterator& other)
+        : base_(other.base_), value_(other.value_), index_(other.index_),
+          step_(other.step_) {}
+
+    const ParamGeneratorInterface<T>* const base_;
+    T value_;
+    int index_;
+    const IncrementT step_;
+  };  // class RangeGenerator::Iterator
+
+  static int CalculateEndIndex(const T& begin,
+                               const T& end,
+                               const IncrementT& step) {
+    int end_index = 0;
+    for (T i = begin; i < end; i = i + step)
+      end_index++;
+    return end_index;
+  }
+
+  const T begin_;
+  const T end_;
+  const IncrementT step_;
+  // The index for the end() iterator. All the elements in the generated
+  // sequence are indexed (0-based) to aid iterator comparison.
+  const int end_index_;
+};  // class RangeGenerator
+
+
+// Generates values from a pair of STL-style iterators. Used in the
+// ValuesIn() function. The elements are copied from the source range
+// since the source can be located on the stack, and the generator
+// is likely to persist beyond that stack frame.
+template <typename T>
+class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+  template <typename ForwardIterator>
+  ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
+      : container_(begin, end) {}
+  virtual ~ValuesInIteratorRangeGenerator() {}
+
+  virtual ParamIteratorInterface<T>* Begin() const {
+    return new Iterator(this, container_.begin());
+  }
+  virtual ParamIteratorInterface<T>* End() const {
+    return new Iterator(this, container_.end());
+  }
+
+ private:
+  typedef typename ::std::vector<T> ContainerType;
+
+  class Iterator : public ParamIteratorInterface<T> {
+   public:
+    Iterator(const ParamGeneratorInterface<T>* base,
+             typename ContainerType::const_iterator iterator)
+        :  base_(base), iterator_(iterator) {}
+    virtual ~Iterator() {}
+
+    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+      return base_;
+    }
+    virtual void Advance() {
+      ++iterator_;
+      value_.reset();
+    }
+    virtual ParamIteratorInterface<T>* Clone() const {
+      return new Iterator(*this);
+    }
+    // We need to use cached value referenced by iterator_ because *iterator_
+    // can return a temporary object (and of type other then T), so just
+    // having "return &*iterator_;" doesn't work.
+    // value_ is updated here and not in Advance() because Advance()
+    // can advance iterator_ beyond the end of the range, and we cannot
+    // detect that fact. The client code, on the other hand, is
+    // responsible for not calling Current() on an out-of-range iterator.
+    virtual const T* Current() const {
+      if (value_.get() == NULL)
+        value_.reset(new T(*iterator_));
+      return value_.get();
+    }
+    virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+      // Having the same base generator guarantees that the other
+      // iterator is of the same type and we can downcast.
+      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+          << "The program attempted to compare iterators "
+          << "from different generators." << std::endl;
+      return iterator_ ==
+          CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
+    }
+
+   private:
+    Iterator(const Iterator& other)
+          // The explicit constructor call suppresses a false warning
+          // emitted by gcc when supplied with the -Wextra option.
+        : ParamIteratorInterface<T>(),
+          base_(other.base_),
+          iterator_(other.iterator_) {}
+
+    const ParamGeneratorInterface<T>* const base_;
+    typename ContainerType::const_iterator iterator_;
+    // A cached value of *iterator_. We keep it here to allow access by
+    // pointer in the wrapping iterator's operator->().
+    // value_ needs to be mutable to be accessed in Current().
+    // Use of scoped_ptr helps manage cached value's lifetime,
+    // which is bound by the lifespan of the iterator itself.
+    mutable scoped_ptr<const T> value_;
+  };
+
+  const ContainerType container_;
+};  // class ValuesInIteratorRangeGenerator
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Stores a parameter value and later creates tests parameterized with that
+// value.
+template <class TestClass>
+class ParameterizedTestFactory : public TestFactoryBase {
+ public:
+  typedef typename TestClass::ParamType ParamType;
+  explicit ParameterizedTestFactory(ParamType parameter) :
+      parameter_(parameter) {}
+  virtual Test* CreateTest() {
+    TestClass::SetParam(&parameter_);
+    return new TestClass();
+  }
+
+ private:
+  const ParamType parameter_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactoryBase is a base class for meta-factories that create
+// test factories for passing into MakeAndRegisterTestInfo function.
+template <class ParamType>
+class TestMetaFactoryBase {
+ public:
+  virtual ~TestMetaFactoryBase() {}
+
+  virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactory creates test factories for passing into
+// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
+// ownership of test factory pointer, same factory object cannot be passed
+// into that method twice. But ParameterizedTestCaseInfo is going to call
+// it for each Test/Parameter value combination. Thus it needs meta factory
+// creator class.
+template <class TestCase>
+class TestMetaFactory
+    : public TestMetaFactoryBase<typename TestCase::ParamType> {
+ public:
+  typedef typename TestCase::ParamType ParamType;
+
+  TestMetaFactory() {}
+
+  virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
+    return new ParameterizedTestFactory<TestCase>(parameter);
+  }
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfoBase is a generic interface
+// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
+// accumulates test information provided by TEST_P macro invocations
+// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
+// and uses that information to register all resulting test instances
+// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
+// a collection of pointers to the ParameterizedTestCaseInfo objects
+// and calls RegisterTests() on each of them when asked.
+class ParameterizedTestCaseInfoBase {
+ public:
+  virtual ~ParameterizedTestCaseInfoBase() {}
+
+  // Base part of test case name for display purposes.
+  virtual const String& GetTestCaseName() const = 0;
+  // Test case id to verify identity.
+  virtual TypeId GetTestCaseTypeId() const = 0;
+  // UnitTest class invokes this method to register tests in this
+  // test case right before running them in RUN_ALL_TESTS macro.
+  // This method should not be called more then once on any single
+  // instance of a ParameterizedTestCaseInfoBase derived class.
+  virtual void RegisterTests() = 0;
+
+ protected:
+  ParameterizedTestCaseInfoBase() {}
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
+// macro invocations for a particular test case and generators
+// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
+// test case. It registers tests with all values generated by all
+// generators when asked.
+template <class TestCase>
+class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
+ public:
+  // ParamType and GeneratorCreationFunc are private types but are required
+  // for declarations of public methods AddTestPattern() and
+  // AddTestCaseInstantiation().
+  typedef typename TestCase::ParamType ParamType;
+  // A function that returns an instance of appropriate generator type.
+  typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+
+  explicit ParameterizedTestCaseInfo(const char* name)
+      : test_case_name_(name) {}
+
+  // Test case base name for display purposes.
+  virtual const String& GetTestCaseName() const { return test_case_name_; }
+  // Test case id to verify identity.
+  virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
+  // TEST_P macro uses AddTestPattern() to record information
+  // about a single test in a LocalTestInfo structure.
+  // test_case_name is the base name of the test case (without invocation
+  // prefix). test_base_name is the name of an individual test without
+  // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
+  // test case base name and DoBar is test base name.
+  void AddTestPattern(const char* test_case_name,
+                      const char* test_base_name,
+                      TestMetaFactoryBase<ParamType>* meta_factory) {
+    tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
+                                                       test_base_name,
+                                                       meta_factory)));
+  }
+  // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
+  // about a generator.
+  int AddTestCaseInstantiation(const char* instantiation_name,
+                               GeneratorCreationFunc* func,
+                               const char* /* file */,
+                               int /* line */) {
+    instantiations_.push_back(::std::make_pair(instantiation_name, func));
+    return 0;  // Return value used only to run this method in namespace scope.
+  }
+  // UnitTest class invokes this method to register tests in this test case
+  // test cases right before running tests in RUN_ALL_TESTS macro.
+  // This method should not be called more then once on any single
+  // instance of a ParameterizedTestCaseInfoBase derived class.
+  // UnitTest has a guard to prevent from calling this method more then once.
+  virtual void RegisterTests() {
+    for (typename TestInfoContainer::iterator test_it = tests_.begin();
+         test_it != tests_.end(); ++test_it) {
+      linked_ptr<TestInfo> test_info = *test_it;
+      for (typename InstantiationContainer::iterator gen_it =
+               instantiations_.begin(); gen_it != instantiations_.end();
+               ++gen_it) {
+        const String& instantiation_name = gen_it->first;
+        ParamGenerator<ParamType> generator((*gen_it->second)());
+
+        Message test_case_name_stream;
+        if ( !instantiation_name.empty() )
+          test_case_name_stream << instantiation_name.c_str() << "/";
+        test_case_name_stream << test_info->test_case_base_name.c_str();
+
+        int i = 0;
+        for (typename ParamGenerator<ParamType>::iterator param_it =
+                 generator.begin();
+             param_it != generator.end(); ++param_it, ++i) {
+          Message test_name_stream;
+          test_name_stream << test_info->test_base_name.c_str() << "/" << i;
+          ::testing::internal::MakeAndRegisterTestInfo(
+              test_case_name_stream.GetString().c_str(),
+              test_name_stream.GetString().c_str(),
+              "",  // test_case_comment
+              "",  // comment; TODO(vladl@google.com): provide parameter value
+                   //                                  representation.
+              GetTestCaseTypeId(),
+              TestCase::SetUpTestCase,
+              TestCase::TearDownTestCase,
+              test_info->test_meta_factory->CreateTestFactory(*param_it));
+        }  // for param_it
+      }  // for gen_it
+    }  // for test_it
+  }  // RegisterTests
+
+ private:
+  // LocalTestInfo structure keeps information about a single test registered
+  // with TEST_P macro.
+  struct TestInfo {
+    TestInfo(const char* test_case_base_name,
+             const char* test_base_name,
+             TestMetaFactoryBase<ParamType>* test_meta_factory) :
+        test_case_base_name(test_case_base_name),
+        test_base_name(test_base_name),
+        test_meta_factory(test_meta_factory) {}
+
+    const String test_case_base_name;
+    const String test_base_name;
+    const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
+  };
+  typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
+  // Keeps pairs of <Instantiation name, Sequence generator creation function>
+  // received from INSTANTIATE_TEST_CASE_P macros.
+  typedef ::std::vector<std::pair<String, GeneratorCreationFunc*> >
+      InstantiationContainer;
+
+  const String test_case_name_;
+  TestInfoContainer tests_;
+  InstantiationContainer instantiations_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
+};  // class ParameterizedTestCaseInfo
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
+// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
+// macros use it to locate their corresponding ParameterizedTestCaseInfo
+// descriptors.
+class ParameterizedTestCaseRegistry {
+ public:
+  ParameterizedTestCaseRegistry() {}
+  ~ParameterizedTestCaseRegistry() {
+    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+         it != test_case_infos_.end(); ++it) {
+      delete *it;
+    }
+  }
+
+  // Looks up or creates and returns a structure containing information about
+  // tests and instantiations of a particular test case.
+  template <class TestCase>
+  ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
+      const char* test_case_name,
+      const char* file,
+      int line) {
+    ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
+    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+         it != test_case_infos_.end(); ++it) {
+      if ((*it)->GetTestCaseName() == test_case_name) {
+        if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
+          // Complain about incorrect usage of Google Test facilities
+          // and terminate the program since we cannot guaranty correct
+          // test case setup and tear-down in this case.
+          ReportInvalidTestCaseType(test_case_name,  file, line);
+          abort();
+        } else {
+          // At this point we are sure that the object we found is of the same
+          // type we are looking for, so we downcast it to that type
+          // without further checks.
+          typed_test_info = CheckedDowncastToActualType<
+              ParameterizedTestCaseInfo<TestCase> >(*it);
+        }
+        break;
+      }
+    }
+    if (typed_test_info == NULL) {
+      typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
+      test_case_infos_.push_back(typed_test_info);
+    }
+    return typed_test_info;
+  }
+  void RegisterTests() {
+    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+         it != test_case_infos_.end(); ++it) {
+      (*it)->RegisterTests();
+    }
+  }
+
+ private:
+  typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
+
+  TestCaseInfoContainer test_case_infos_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
+};
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  //  GTEST_HAS_PARAM_TEST
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
diff --git a/third_party/gtest/include/gtest/internal/gtest-port.h b/third_party/gtest/include/gtest/internal/gtest-port.h
index 19b2c45..e6b9d14 100644
--- a/third_party/gtest/include/gtest/internal/gtest-port.h
+++ b/third_party/gtest/include/gtest/internal/gtest-port.h
@@ -1,1038 +1,1038 @@
-// Copyright 2005, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Authors: wan@google.com (Zhanyong Wan)

-//

-// Low-level types and utilities for porting Google Test to various

-// platforms.  They are subject to change without notice.  DO NOT USE

-// THEM IN USER CODE.

-

-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_

-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_

-

-// The user can define the following macros in the build script to

-// control Google Test's behavior.  If the user doesn't define a macro

-// in this list, Google Test will define it.

-//

-//   GTEST_HAS_CLONE          - Define it to 1/0 to indicate that clone(2)

-//                              is/isn't available.

-//   GTEST_HAS_GLOBAL_STRING  - Define it to 1/0 to indicate that ::string

-//                              is/isn't available (some systems define

-//                              ::string, which is different to std::string).

-//   GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string

-//                              is/isn't available (some systems define

-//                              ::wstring, which is different to std::wstring).

-//   GTEST_HAS_PTHREAD        - Define it to 1/0 to indicate that <pthread.h>

-//                              is/isn't available.

-//   GTEST_HAS_RTTI           - Define it to 1/0 to indicate that RTTI is/isn't

-//                              enabled.

-//   GTEST_HAS_STD_STRING     - Define it to 1/0 to indicate that

-//                              std::string does/doesn't work (Google Test can

-//                              be used where std::string is unavailable).

-//   GTEST_HAS_STD_WSTRING    - Define it to 1/0 to indicate that

-//                              std::wstring does/doesn't work (Google Test can

-//                              be used where std::wstring is unavailable).

-//   GTEST_HAS_TR1_TUPLE 1    - Define it to 1/0 to indicate tr1::tuple

-//                              is/isn't available.

-//   GTEST_HAS_SEH            - Define it to 1/0 to indicate whether the

-//                              compiler supports Microsoft's "Structured

-//                              Exception Handling".

-

-// This header defines the following utilities:

-//

-// Macros indicating the current platform (defined to 1 if compiled on

-// the given platform; otherwise undefined):

-//   GTEST_OS_CYGWIN   - Cygwin

-//   GTEST_OS_LINUX    - Linux

-//   GTEST_OS_MAC      - Mac OS X

-//   GTEST_OS_SOLARIS  - Sun Solaris

-//   GTEST_OS_SYMBIAN  - Symbian

-//   GTEST_OS_WINDOWS  - Windows

-//   GTEST_OS_ZOS      - z/OS

-//

-// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the

-// most stable support.  Since core members of the Google Test project

-// don't have access to other platforms, support for them may be less

-// stable.  If you notice any problems on your platform, please notify

-// googletestframework@googlegroups.com (patches for fixing them are

-// even more welcome!).

-//

-// Note that it is possible that none of the GTEST_OS_* macros are defined.

-//

-// Macros indicating available Google Test features (defined to 1 if

-// the corresponding feature is supported; otherwise undefined):

-//   GTEST_HAS_COMBINE      - the Combine() function (for value-parameterized

-//                            tests)

-//   GTEST_HAS_DEATH_TEST   - death tests

-//   GTEST_HAS_PARAM_TEST   - value-parameterized tests

-//   GTEST_HAS_TYPED_TEST   - typed tests

-//   GTEST_HAS_TYPED_TEST_P - type-parameterized tests

-//   GTEST_USES_POSIX_RE    - enhanced POSIX regex is used.

-//   GTEST_USES_SIMPLE_RE   - our own simple regex is used;

-//                            the above two are mutually exclusive.

-//

-// Macros for basic C++ coding:

-//   GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.

-//   GTEST_ATTRIBUTE_UNUSED_  - declares that a class' instances or a

-//                              variable don't have to be used.

-//   GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.

-//   GTEST_MUST_USE_RESULT_   - declares that a function's result must be used.

-//

-// Synchronization:

-//   Mutex, MutexLock, ThreadLocal, GetThreadCount()

-//                  - synchronization primitives.

-//   GTEST_IS_THREADSAFE - defined to 1 to indicate that the above

-//                         synchronization primitives have real implementations

-//                         and Google Test is thread-safe; or 0 otherwise.

-//

-// Template meta programming:

-//   is_pointer     - as in TR1; needed on Symbian and IBM XL C/C++ only.

-//

-// Smart pointers:

-//   scoped_ptr     - as in TR2.

-//

-// Regular expressions:

-//   RE             - a simple regular expression class using the POSIX

-//                    Extended Regular Expression syntax.  Not available on

-//                    Windows.

-//

-// Logging:

-//   GTEST_LOG_()   - logs messages at the specified severity level.

-//   LogToStderr()  - directs all log messages to stderr.

-//   FlushInfoLog() - flushes informational log messages.

-//

-// Stderr capturing:

-//   CaptureStderr()     - starts capturing stderr.

-//   GetCapturedStderr() - stops capturing stderr and returns the captured

-//                         string.

-//

-// Integer types:

-//   TypeWithSize   - maps an integer to a int type.

-//   Int32, UInt32, Int64, UInt64, TimeInMillis

-//                  - integers of known sizes.

-//   BiggestInt     - the biggest signed integer type.

-//

-// Command-line utilities:

-//   GTEST_FLAG()       - references a flag.

-//   GTEST_DECLARE_*()  - declares a flag.

-//   GTEST_DEFINE_*()   - defines a flag.

-//   GetArgvs()         - returns the command line as a vector of strings.

-//

-// Environment variable utilities:

-//   GetEnv()             - gets the value of an environment variable.

-//   BoolFromGTestEnv()   - parses a bool environment variable.

-//   Int32FromGTestEnv()  - parses an Int32 environment variable.

-//   StringFromGTestEnv() - parses a string environment variable.

-

-#include <stdlib.h>

-#include <stdio.h>

-#include <string.h>

-#include <sys/stat.h>

-

-#include <iostream>  // NOLINT

-

-#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"

-#define GTEST_FLAG_PREFIX_ "gtest_"

-#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"

-#define GTEST_NAME_ "Google Test"

-#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"

-

-// Determines the version of gcc that is used to compile this.

-#ifdef __GNUC__

-// 40302 means version 4.3.2.

-#define GTEST_GCC_VER_ \

-    (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)

-#endif  // __GNUC__

-

-// Determines the platform on which Google Test is compiled.

-#ifdef __CYGWIN__

-#define GTEST_OS_CYGWIN 1

-#elif __SYMBIAN32__

-#define GTEST_OS_SYMBIAN 1

-#elif defined _WIN32

-#define GTEST_OS_WINDOWS 1

-#elif defined __APPLE__

-#define GTEST_OS_MAC 1

-#elif defined __linux__

-#define GTEST_OS_LINUX 1

-#elif defined __MVS__

-#define GTEST_OS_ZOS 1

-#elif defined(__sun) && defined(__SVR4)

-#define GTEST_OS_SOLARIS 1

-#endif  // __CYGWIN__

-

-#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC

-

-// On some platforms, <regex.h> needs someone to define size_t, and

-// won't compile otherwise.  We can #include it here as we already

-// included <stdlib.h>, which is guaranteed to define size_t through

-// <stddef.h>.

-#include <regex.h>  // NOLINT

-#include <strings.h>  // NOLINT

-#include <sys/types.h>  // NOLINT

-#include <unistd.h>  // NOLINT

-

-#define GTEST_USES_POSIX_RE 1

-

-#elif GTEST_OS_WINDOWS

-

-#include <direct.h>  // NOLINT

-#include <io.h>  // NOLINT

-

-// <regex.h> is not available on Windows.  Use our own simple regex

-// implementation instead.

-#define GTEST_USES_SIMPLE_RE 1

-

-#else

-

-// <regex.h> may not be available on this platform.  Use our own

-// simple regex implementation instead.

-#define GTEST_USES_SIMPLE_RE 1

-

-#endif  // GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC

-

-// Defines GTEST_HAS_EXCEPTIONS to 1 if exceptions are enabled, or 0

-// otherwise.

-

-#if defined(_MSC_VER) || defined(__BORLANDC__)

-// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS

-// macro to enable exceptions, so we'll do the same.

-// Assumes that exceptions are enabled by default.

-#ifndef _HAS_EXCEPTIONS

-#define _HAS_EXCEPTIONS 1

-#endif  // _HAS_EXCEPTIONS

-#define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS

-#else  // The compiler is not MSVC or C++Builder.

-// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.  For

-// other compilers, we assume exceptions are disabled to be

-// conservative.

-#if defined(__GNUC__) && __EXCEPTIONS

-#define GTEST_HAS_EXCEPTIONS 1

-#else

-#define GTEST_HAS_EXCEPTIONS 0

-#endif  // defined(__GNUC__) && __EXCEPTIONS

-#endif  // defined(_MSC_VER) || defined(__BORLANDC__)

-

-// Determines whether ::std::string and ::string are available.

-

-#ifndef GTEST_HAS_STD_STRING

-// The user didn't tell us whether ::std::string is available, so we

-// need to figure it out.  The only environment that we know

-// ::std::string is not available is MSVC 7.1 or lower with exceptions

-// disabled.

-#if defined(_MSC_VER) && (_MSC_VER < 1400) && !GTEST_HAS_EXCEPTIONS

-#define GTEST_HAS_STD_STRING 0

-#else

-#define GTEST_HAS_STD_STRING 1

-#endif

-#endif  // GTEST_HAS_STD_STRING

-

-#ifndef GTEST_HAS_GLOBAL_STRING

-// The user didn't tell us whether ::string is available, so we need

-// to figure it out.

-

-#define GTEST_HAS_GLOBAL_STRING 0

-

-#endif  // GTEST_HAS_GLOBAL_STRING

-

-#ifndef GTEST_HAS_STD_WSTRING

-// The user didn't tell us whether ::std::wstring is available, so we need

-// to figure it out.

-// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring

-//   is available.

-

-#if GTEST_OS_CYGWIN || GTEST_OS_SOLARIS

-// Cygwin 1.5 and below doesn't support ::std::wstring.

-// Cygwin 1.7 might add wstring support; this should be updated when clear.

-// Solaris' libc++ doesn't support it either.

-#define GTEST_HAS_STD_WSTRING 0

-#else

-#define GTEST_HAS_STD_WSTRING GTEST_HAS_STD_STRING

-#endif  // GTEST_OS_CYGWIN || GTEST_OS_SOLARIS

-

-#endif  // GTEST_HAS_STD_WSTRING

-

-#ifndef GTEST_HAS_GLOBAL_WSTRING

-// The user didn't tell us whether ::wstring is available, so we need

-// to figure it out.

-#define GTEST_HAS_GLOBAL_WSTRING \

-    (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)

-#endif  // GTEST_HAS_GLOBAL_WSTRING

-

-#if GTEST_HAS_STD_STRING || GTEST_HAS_GLOBAL_STRING || \

-    GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING

-#include <string>  // NOLINT

-#endif  // GTEST_HAS_STD_STRING || GTEST_HAS_GLOBAL_STRING ||

-        // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING

-

-#if GTEST_HAS_STD_STRING

-#include <sstream>  // NOLINT

-#else

-#include <strstream>  // NOLINT

-#endif  // GTEST_HAS_STD_STRING

-

-// Determines whether RTTI is available.

-#ifndef GTEST_HAS_RTTI

-// The user didn't tell us whether RTTI is enabled, so we need to

-// figure it out.

-

-#ifdef _MSC_VER

-

-#ifdef _CPPRTTI  // MSVC defines this macro iff RTTI is enabled.

-#define GTEST_HAS_RTTI 1

-#else

-#define GTEST_HAS_RTTI 0

-#endif  // _CPPRTTI

-

-#elif defined(__GNUC__)

-

-// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.

-#if GTEST_GCC_VER_ >= 40302

-#ifdef __GXX_RTTI

-#define GTEST_HAS_RTTI 1

-#else

-#define GTEST_HAS_RTTI 0

-#endif  // __GXX_RTTI

-#else

-// For gcc versions smaller than 4.3.2, we assume RTTI is enabled.

-#define GTEST_HAS_RTTI 1

-#endif  // GTEST_GCC_VER >= 40302

-

-#else

-

-// Unknown compiler - assume RTTI is enabled.

-#define GTEST_HAS_RTTI 1

-

-#endif  // _MSC_VER

-

-#endif  // GTEST_HAS_RTTI

-

-// Determines whether <pthread.h> is available.

-#ifndef GTEST_HAS_PTHREAD

-// The user didn't tell us, so we need to figure it out.

-#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC)

-#endif  // GTEST_HAS_PTHREAD

-

-// Determines whether tr1/tuple is available.  If you have tr1/tuple

-// on your platform, define GTEST_HAS_TR1_TUPLE=1 for both the Google

-// Test project and your tests. If you would like Google Test to detect

-// tr1/tuple on your platform automatically, please open an issue

-// ticket at http://code.google.com/p/googletest.

-#ifndef GTEST_HAS_TR1_TUPLE

-// The user didn't tell us, so we need to figure it out.

-

-// GCC provides <tr1/tuple> since 4.0.0.

-#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)

-#define GTEST_HAS_TR1_TUPLE 1

-#else

-#define GTEST_HAS_TR1_TUPLE 0

-#endif  // __GNUC__

-#endif  // GTEST_HAS_TR1_TUPLE

-

-// To avoid conditional compilation everywhere, we make it

-// gtest-port.h's responsibility to #include the header implementing

-// tr1/tuple.

-#if GTEST_HAS_TR1_TUPLE

-

-#if GTEST_OS_SYMBIAN

-

-// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to

-// use STLport's tuple implementation, which unfortunately doesn't

-// work as the copy of STLport distributed with Symbian is incomplete.

-// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to

-// use its own tuple implementation.

-#ifdef BOOST_HAS_TR1_TUPLE

-#undef BOOST_HAS_TR1_TUPLE

-#endif  // BOOST_HAS_TR1_TUPLE

-

-// This prevents <boost/tr1/detail/config.hpp>, which defines

-// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.

-#define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED

-#include <tuple>

-

-#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)

-// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header.  This does

-// not conform to the TR1 spec, which requires the header to be <tuple>.

-

-#if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302

-// Until version 4.3.2, gcc has a bug that causes <tr1/functional>,

-// which is #included by <tr1/tuple>, to not compile when RTTI is

-// disabled.  _TR1_FUNCTIONAL is the header guard for

-// <tr1/functional>.  Hence the following #define is a hack to prevent

-// <tr1/functional> from being included.

-#define _TR1_FUNCTIONAL 1

-#include <tr1/tuple>

-#undef _TR1_FUNCTIONAL  // Allows the user to #include

-                        // <tr1/functional> if he chooses to.

-#else

-#include <tr1/tuple>

-#endif  // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302

-

-#else

-// If the compiler is not GCC 4.0+, we assume the user is using a

-// spec-conforming TR1 implementation.

-#include <tuple>

-#endif  // GTEST_OS_SYMBIAN

-

-#endif  // GTEST_HAS_TR1_TUPLE

-

-// Determines whether clone(2) is supported.

-// Usually it will only be available on Linux, excluding

-// Linux on the Itanium architecture.

-// Also see http://linux.die.net/man/2/clone.

-#ifndef GTEST_HAS_CLONE

-// The user didn't tell us, so we need to figure it out.

-

-#if GTEST_OS_LINUX && !defined(__ia64__)

-#define GTEST_HAS_CLONE 1

-#else

-#define GTEST_HAS_CLONE 0

-#endif  // GTEST_OS_LINUX && !defined(__ia64__)

-

-#endif  // GTEST_HAS_CLONE

-

-// Determines whether to support death tests.

-// Google Test does not support death tests for VC 7.1 and earlier for

-// these reasons:

-//   1. std::vector does not build in VC 7.1 when exceptions are disabled.

-//   2. std::string does not build in VC 7.1 when exceptions are disabled

-//      (this is covered by GTEST_HAS_STD_STRING guard).

-//   3. abort() in a VC 7.1 application compiled as GUI in debug config

-//      pops up a dialog window that cannot be suppressed programmatically.

-#if GTEST_HAS_STD_STRING && (GTEST_OS_LINUX || \

-                             GTEST_OS_MAC || \

-                             GTEST_OS_CYGWIN || \

-                             (GTEST_OS_WINDOWS && _MSC_VER >= 1400))

-#define GTEST_HAS_DEATH_TEST 1

-#include <vector>  // NOLINT

-#endif

-

-// Determines whether to support value-parameterized tests.

-

-#if defined(__GNUC__) || (_MSC_VER >= 1400)

-// TODO(vladl@google.com): get the implementation rid of vector and list

-// to compile on MSVC 7.1.

-#define GTEST_HAS_PARAM_TEST 1

-#endif  // defined(__GNUC__) || (_MSC_VER >= 1400)

-

-// Determines whether to support type-driven tests.

-

-// Typed tests need <typeinfo> and variadic macros, which gcc and VC

-// 8.0+ support.

-#if defined(__GNUC__) || (_MSC_VER >= 1400)

-#define GTEST_HAS_TYPED_TEST 1

-#define GTEST_HAS_TYPED_TEST_P 1

-#endif  // defined(__GNUC__) || (_MSC_VER >= 1400)

-

-// Determines whether to support Combine(). This only makes sense when

-// value-parameterized tests are enabled.

-#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE

-#define GTEST_HAS_COMBINE 1

-#endif  // GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE

-

-// Determines whether the system compiler uses UTF-16 for encoding wide strings.

-#define GTEST_WIDE_STRING_USES_UTF16_ \

-    (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN)

-

-// Defines some utility macros.

-

-// The GNU compiler emits a warning if nested "if" statements are followed by

-// an "else" statement and braces are not used to explicitly disambiguate the

-// "else" binding.  This leads to problems with code like:

-//

-//   if (gate)

-//     ASSERT_*(condition) << "Some message";

-//

-// The "switch (0) case 0:" idiom is used to suppress this.

-#ifdef __INTEL_COMPILER

-#define GTEST_AMBIGUOUS_ELSE_BLOCKER_

-#else

-#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0:  // NOLINT

-#endif

-

-// Use this annotation at the end of a struct/class definition to

-// prevent the compiler from optimizing away instances that are never

-// used.  This is useful when all interesting logic happens inside the

-// c'tor and / or d'tor.  Example:

-//

-//   struct Foo {

-//     Foo() { ... }

-//   } GTEST_ATTRIBUTE_UNUSED_;

-//

-// Also use it after a variable or parameter declaration to tell the

-// compiler the variable/parameter does not have to be used.

-#if defined(__GNUC__) && !defined(COMPILER_ICC)

-#define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))

-#else

-#define GTEST_ATTRIBUTE_UNUSED_

-#endif

-

-// A macro to disallow the evil copy constructor and operator= functions

-// This should be used in the private: declarations for a class.

-#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\

-  type(const type &);\

-  void operator=(const type &)

-

-// Tell the compiler to warn about unused return values for functions declared

-// with this macro.  The macro should be used on function declarations

-// following the argument list:

-//

-//   Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;

-#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)

-#define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))

-#else

-#define GTEST_MUST_USE_RESULT_

-#endif  // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC

-

-// Determine whether the compiler supports Microsoft's Structured Exception

-// Handling.  This is supported by several Windows compilers but generally

-// does not exist on any other system.

-#ifndef GTEST_HAS_SEH

-// The user didn't tell us, so we need to figure it out.

-

-#if defined(_MSC_VER) || defined(__BORLANDC__)

-// These two compilers are known to support SEH.

-#define GTEST_HAS_SEH 1

-#else

-// Assume no SEH.

-#define GTEST_HAS_SEH 0

-#endif

-

-#endif  // GTEST_HAS_SEH

-

-namespace testing {

-

-class Message;

-

-namespace internal {

-

-class String;

-

-// std::strstream is deprecated.  However, we have to use it on

-// Windows as std::stringstream won't compile on Windows when

-// exceptions are disabled.  We use std::stringstream on other

-// platforms to avoid compiler warnings there.

-#if GTEST_HAS_STD_STRING

-typedef ::std::stringstream StrStream;

-#else

-typedef ::std::strstream StrStream;

-#endif  // GTEST_HAS_STD_STRING

-

-// Defines scoped_ptr.

-

-// This implementation of scoped_ptr is PARTIAL - it only contains

-// enough stuff to satisfy Google Test's need.

-template <typename T>

-class scoped_ptr {

- public:

-  explicit scoped_ptr(T* p = NULL) : ptr_(p) {}

-  ~scoped_ptr() { reset(); }

-

-  T& operator*() const { return *ptr_; }

-  T* operator->() const { return ptr_; }

-  T* get() const { return ptr_; }

-

-  T* release() {

-    T* const ptr = ptr_;

-    ptr_ = NULL;

-    return ptr;

-  }

-

-  void reset(T* p = NULL) {

-    if (p != ptr_) {

-      if (sizeof(T) > 0) {  // Makes sure T is a complete type.

-        delete ptr_;

-      }

-      ptr_ = p;

-    }

-  }

- private:

-  T* ptr_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);

-};

-

-// Defines RE.

-

-// A simple C++ wrapper for <regex.h>.  It uses the POSIX Enxtended

-// Regular Expression syntax.

-class RE {

- public:

-  // Constructs an RE from a string.

-#if GTEST_HAS_STD_STRING

-  RE(const ::std::string& regex) { Init(regex.c_str()); }  // NOLINT

-#endif  // GTEST_HAS_STD_STRING

-

-#if GTEST_HAS_GLOBAL_STRING

-  RE(const ::string& regex) { Init(regex.c_str()); }  // NOLINT

-#endif  // GTEST_HAS_GLOBAL_STRING

-

-  RE(const char* regex) { Init(regex); }  // NOLINT

-  ~RE();

-

-  // Returns the string representation of the regex.

-  const char* pattern() const { return pattern_; }

-

-  // FullMatch(str, re) returns true iff regular expression re matches

-  // the entire str.

-  // PartialMatch(str, re) returns true iff regular expression re

-  // matches a substring of str (including str itself).

-  //

-  // TODO(wan@google.com): make FullMatch() and PartialMatch() work

-  // when str contains NUL characters.

-#if GTEST_HAS_STD_STRING

-  static bool FullMatch(const ::std::string& str, const RE& re) {

-    return FullMatch(str.c_str(), re);

-  }

-  static bool PartialMatch(const ::std::string& str, const RE& re) {

-    return PartialMatch(str.c_str(), re);

-  }

-#endif  // GTEST_HAS_STD_STRING

-

-#if GTEST_HAS_GLOBAL_STRING

-  static bool FullMatch(const ::string& str, const RE& re) {

-    return FullMatch(str.c_str(), re);

-  }

-  static bool PartialMatch(const ::string& str, const RE& re) {

-    return PartialMatch(str.c_str(), re);

-  }

-#endif  // GTEST_HAS_GLOBAL_STRING

-

-  static bool FullMatch(const char* str, const RE& re);

-  static bool PartialMatch(const char* str, const RE& re);

-

- private:

-  void Init(const char* regex);

-

-  // We use a const char* instead of a string, as Google Test may be used

-  // where string is not available.  We also do not use Google Test's own

-  // String type here, in order to simplify dependencies between the

-  // files.

-  const char* pattern_;

-  bool is_valid_;

-#if GTEST_USES_POSIX_RE

-  regex_t full_regex_;     // For FullMatch().

-  regex_t partial_regex_;  // For PartialMatch().

-#else  // GTEST_USES_SIMPLE_RE

-  const char* full_pattern_;  // For FullMatch();

-#endif

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(RE);

-};

-

-// Defines logging utilities:

-//   GTEST_LOG_()   - logs messages at the specified severity level.

-//   LogToStderr()  - directs all log messages to stderr.

-//   FlushInfoLog() - flushes informational log messages.

-

-enum GTestLogSeverity {

-  GTEST_INFO,

-  GTEST_WARNING,

-  GTEST_ERROR,

-  GTEST_FATAL

-};

-

-void GTestLog(GTestLogSeverity severity, const char* file,

-              int line, const char* msg);

-

-#define GTEST_LOG_(severity, msg)\

-    ::testing::internal::GTestLog(\

-        ::testing::internal::GTEST_##severity, __FILE__, __LINE__, \

-        (::testing::Message() << (msg)).GetString().c_str())

-

-inline void LogToStderr() {}

-inline void FlushInfoLog() { fflush(NULL); }

-

-// Defines the stderr capturer:

-//   CaptureStderr     - starts capturing stderr.

-//   GetCapturedStderr - stops capturing stderr and returns the captured string.

-

-#if GTEST_HAS_STD_STRING

-void CaptureStderr();

-::std::string GetCapturedStderr();

-#endif  // GTEST_HAS_STD_STRING

-

-#if GTEST_HAS_DEATH_TEST

-

-// A copy of all command line arguments.  Set by InitGoogleTest().

-extern ::std::vector<String> g_argvs;

-

-// GTEST_HAS_DEATH_TEST implies we have ::std::string.

-const ::std::vector<String>& GetArgvs();

-

-#endif  // GTEST_HAS_DEATH_TEST

-

-// Defines synchronization primitives.

-

-// A dummy implementation of synchronization primitives (mutex, lock,

-// and thread-local variable).  Necessary for compiling Google Test where

-// mutex is not supported - using Google Test in multiple threads is not

-// supported on such platforms.

-

-class Mutex {

- public:

-  Mutex() {}

-  explicit Mutex(int /*unused*/) {}

-  void AssertHeld() const {}

-  enum { NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX = 0 };

-};

-

-// We cannot call it MutexLock directly as the ctor declaration would

-// conflict with a macro named MutexLock, which is defined on some

-// platforms.  Hence the typedef trick below.

-class GTestMutexLock {

- public:

-  explicit GTestMutexLock(Mutex*) {}  // NOLINT

-};

-

-typedef GTestMutexLock MutexLock;

-

-template <typename T>

-class ThreadLocal {

- public:

-  ThreadLocal() : value_() {}

-  explicit ThreadLocal(const T& value) : value_(value) {}

-  T* pointer() { return &value_; }

-  const T* pointer() const { return &value_; }

-  const T& get() const { return value_; }

-  void set(const T& value) { value_ = value; }

- private:

-  T value_;

-};

-

-// Returns the number of threads running in the process, or 0 to indicate that

-// we cannot detect it.

-size_t GetThreadCount();

-

-// The above synchronization primitives have dummy implementations.

-// Therefore Google Test is not thread-safe.

-#define GTEST_IS_THREADSAFE 0

-

-#if defined(__SYMBIAN32__) || defined(__IBMCPP__)

-

-// Passing non-POD classes through ellipsis (...) crashes the ARM

-// compiler.  The Nokia Symbian and the IBM XL C/C++ compiler try to

-// instantiate a copy constructor for objects passed through ellipsis

-// (...), failing for uncopyable objects.  We define this to indicate

-// the fact.

-#define GTEST_ELLIPSIS_NEEDS_COPY_ 1

-

-// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between

-// const T& and const T* in a function template.  These compilers

-// _can_ decide between class template specializations for T and T*,

-// so a tr1::type_traits-like is_pointer works.

-#define GTEST_NEEDS_IS_POINTER_ 1

-

-#endif  // defined(__SYMBIAN32__) || defined(__IBMCPP__)

-

-template <bool bool_value>

-struct bool_constant {

-  typedef bool_constant<bool_value> type;

-  static const bool value = bool_value;

-};

-template <bool bool_value> const bool bool_constant<bool_value>::value;

-

-typedef bool_constant<false> false_type;

-typedef bool_constant<true> true_type;

-

-template <typename T>

-struct is_pointer : public false_type {};

-

-template <typename T>

-struct is_pointer<T*> : public true_type {};

-

-#if GTEST_OS_WINDOWS

-#define GTEST_PATH_SEP_ "\\"

-// The biggest signed integer type the compiler supports.

-typedef __int64 BiggestInt;

-#else

-#define GTEST_PATH_SEP_ "/"

-typedef long long BiggestInt;  // NOLINT

-#endif  // GTEST_OS_WINDOWS

-

-// The testing::internal::posix namespace holds wrappers for common

-// POSIX functions.  These wrappers hide the differences between

-// Windows/MSVC and POSIX systems.  Since some compilers define these

-// standard functions as macros, the wrapper cannot have the same name

-// as the wrapped function.

-

-namespace posix {

-

-// Functions with a different name on Windows.

-

-#if GTEST_OS_WINDOWS

-

-typedef struct _stat StatStruct;

-

-#ifdef __BORLANDC__

-inline int IsATTY(int fd) { return isatty(fd); }

-inline int StrCaseCmp(const char* s1, const char* s2) {

-  return stricmp(s1, s2);

-}

-inline char* StrDup(const char* src) { return strdup(src); }

-#else

-inline int IsATTY(int fd) { return _isatty(fd); }

-inline int StrCaseCmp(const char* s1, const char* s2) {

-  return _stricmp(s1, s2);

-}

-inline char* StrDup(const char* src) { return _strdup(src); }

-#endif  // __BORLANDC__

-

-inline int FileNo(FILE* file) { return _fileno(file); }

-inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }

-inline int RmDir(const char* dir) { return _rmdir(dir); }

-inline bool IsDir(const StatStruct& st) {

-  return (_S_IFDIR & st.st_mode) != 0;

-}

-

-#else

-

-typedef struct stat StatStruct;

-

-inline int FileNo(FILE* file) { return fileno(file); }

-inline int IsATTY(int fd) { return isatty(fd); }

-inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }

-inline int StrCaseCmp(const char* s1, const char* s2) {

-  return strcasecmp(s1, s2);

-}

-inline char* StrDup(const char* src) { return strdup(src); }

-inline int RmDir(const char* dir) { return rmdir(dir); }

-inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }

-

-#endif  // GTEST_OS_WINDOWS

-

-// Functions deprecated by MSVC 8.0.

-

-#ifdef _MSC_VER

-// Temporarily disable warning 4996 (deprecated function).

-#pragma warning(push)

-#pragma warning(disable:4996)

-#endif

-

-inline const char* StrNCpy(char* dest, const char* src, size_t n) {

-  return strncpy(dest, src, n);

-}

-inline int ChDir(const char* dir) { return chdir(dir); }

-inline FILE* FOpen(const char* path, const char* mode) {

-  return fopen(path, mode);

-}

-inline FILE *FReopen(const char* path, const char* mode, FILE* stream) {

-  return freopen(path, mode, stream);

-}

-inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); }

-inline int FClose(FILE* fp) { return fclose(fp); }

-inline int Read(int fd, void* buf, unsigned int count) {

-  return static_cast<int>(read(fd, buf, count));

-}

-inline int Write(int fd, const void* buf, unsigned int count) {

-  return static_cast<int>(write(fd, buf, count));

-}

-inline int Close(int fd) { return close(fd); }

-inline const char* StrError(int errnum) { return strerror(errnum); }

-inline const char* GetEnv(const char* name) {

-#ifdef _WIN32_WCE  // We are on Windows CE, which has no environment variables.

-  return NULL;

-#elif defined(__BORLANDC__)

-  // Environment variables which we programmatically clear will be set to the

-  // empty string rather than unset (NULL).  Handle that case.

-  const char* const env = getenv(name);

-  return (env != NULL && env[0] != '\0') ? env : NULL;

-#else

-  return getenv(name);

-#endif

-}

-

-#ifdef _MSC_VER

-#pragma warning(pop)  // Restores the warning state.

-#endif

-

-#ifdef _WIN32_WCE

-// Windows CE has no C library. The abort() function is used in

-// several places in Google Test. This implementation provides a reasonable

-// imitation of standard behaviour.

-void Abort();

-#else

-inline void Abort() { abort(); }

-#endif  // _WIN32_WCE

-

-}  // namespace posix

-

-// The maximum number a BiggestInt can represent.  This definition

-// works no matter BiggestInt is represented in one's complement or

-// two's complement.

-//

-// We cannot rely on numeric_limits in STL, as __int64 and long long

-// are not part of standard C++ and numeric_limits doesn't need to be

-// defined for them.

-const BiggestInt kMaxBiggestInt =

-    ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));

-

-// This template class serves as a compile-time function from size to

-// type.  It maps a size in bytes to a primitive type with that

-// size. e.g.

-//

-//   TypeWithSize<4>::UInt

-//

-// is typedef-ed to be unsigned int (unsigned integer made up of 4

-// bytes).

-//

-// Such functionality should belong to STL, but I cannot find it

-// there.

-//

-// Google Test uses this class in the implementation of floating-point

-// comparison.

-//

-// For now it only handles UInt (unsigned int) as that's all Google Test

-// needs.  Other types can be easily added in the future if need

-// arises.

-template <size_t size>

-class TypeWithSize {

- public:

-  // This prevents the user from using TypeWithSize<N> with incorrect

-  // values of N.

-  typedef void UInt;

-};

-

-// The specialization for size 4.

-template <>

-class TypeWithSize<4> {

- public:

-  // unsigned int has size 4 in both gcc and MSVC.

-  //

-  // As base/basictypes.h doesn't compile on Windows, we cannot use

-  // uint32, uint64, and etc here.

-  typedef int Int;

-  typedef unsigned int UInt;

-};

-

-// The specialization for size 8.

-template <>

-class TypeWithSize<8> {

- public:

-#if GTEST_OS_WINDOWS

-  typedef __int64 Int;

-  typedef unsigned __int64 UInt;

-#else

-  typedef long long Int;  // NOLINT

-  typedef unsigned long long UInt;  // NOLINT

-#endif  // GTEST_OS_WINDOWS

-};

-

-// Integer types of known sizes.

-typedef TypeWithSize<4>::Int Int32;

-typedef TypeWithSize<4>::UInt UInt32;

-typedef TypeWithSize<8>::Int Int64;

-typedef TypeWithSize<8>::UInt UInt64;

-typedef TypeWithSize<8>::Int TimeInMillis;  // Represents time in milliseconds.

-

-// Utilities for command line flags and environment variables.

-

-// INTERNAL IMPLEMENTATION - DO NOT USE.

-//

-// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition

-// is not satisfied.

-//  Synopsys:

-//    GTEST_CHECK_(boolean_condition);

-//     or

-//    GTEST_CHECK_(boolean_condition) << "Additional message";

-//

-//    This checks the condition and if the condition is not satisfied

-//    it prints message about the condition violation, including the

-//    condition itself, plus additional message streamed into it, if any,

-//    and then it aborts the program. It aborts the program irrespective of

-//    whether it is built in the debug mode or not.

-class GTestCheckProvider {

- public:

-  GTestCheckProvider(const char* condition, const char* file, int line) {

-    FormatFileLocation(file, line);

-    ::std::cerr << " ERROR: Condition " << condition << " failed. ";

-  }

-  ~GTestCheckProvider() {

-    ::std::cerr << ::std::endl;

-    abort();

-  }

-  void FormatFileLocation(const char* file, int line) {

-    if (file == NULL)

-      file = "unknown file";

-    if (line < 0) {

-      ::std::cerr << file << ":";

-    } else {

-#if _MSC_VER

-      ::std::cerr << file << "(" << line << "):";

-#else

-      ::std::cerr << file << ":" << line << ":";

-#endif

-    }

-  }

-  ::std::ostream& GetStream() { return ::std::cerr; }

-};

-#define GTEST_CHECK_(condition) \

-    GTEST_AMBIGUOUS_ELSE_BLOCKER_ \

-    if (condition) \

-      ; \

-    else \

-      ::testing::internal::GTestCheckProvider(\

-          #condition, __FILE__, __LINE__).GetStream()

-

-// Macro for referencing flags.

-#define GTEST_FLAG(name) FLAGS_gtest_##name

-

-// Macros for declaring flags.

-#define GTEST_DECLARE_bool_(name) extern bool GTEST_FLAG(name)

-#define GTEST_DECLARE_int32_(name) \

-    extern ::testing::internal::Int32 GTEST_FLAG(name)

-#define GTEST_DECLARE_string_(name) \

-    extern ::testing::internal::String GTEST_FLAG(name)

-

-// Macros for defining flags.

-#define GTEST_DEFINE_bool_(name, default_val, doc) \

-    bool GTEST_FLAG(name) = (default_val)

-#define GTEST_DEFINE_int32_(name, default_val, doc) \

-    ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)

-#define GTEST_DEFINE_string_(name, default_val, doc) \

-    ::testing::internal::String GTEST_FLAG(name) = (default_val)

-

-// Parses 'str' for a 32-bit signed integer.  If successful, writes the result

-// to *value and returns true; otherwise leaves *value unchanged and returns

-// false.

-// TODO(chandlerc): Find a better way to refactor flag and environment parsing

-// out of both gtest-port.cc and gtest.cc to avoid exporting this utility

-// function.

-bool ParseInt32(const Message& src_text, const char* str, Int32* value);

-

-// Parses a bool/Int32/string from the environment variable

-// corresponding to the given Google Test flag.

-bool BoolFromGTestEnv(const char* flag, bool default_val);

-Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);

-const char* StringFromGTestEnv(const char* flag, const char* default_val);

-

-}  // namespace internal

-}  // namespace testing

-

-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_

+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan)
+//
+// Low-level types and utilities for porting Google Test to various
+// platforms.  They are subject to change without notice.  DO NOT USE
+// THEM IN USER CODE.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+// The user can define the following macros in the build script to
+// control Google Test's behavior.  If the user doesn't define a macro
+// in this list, Google Test will define it.
+//
+//   GTEST_HAS_CLONE          - Define it to 1/0 to indicate that clone(2)
+//                              is/isn't available.
+//   GTEST_HAS_GLOBAL_STRING  - Define it to 1/0 to indicate that ::string
+//                              is/isn't available (some systems define
+//                              ::string, which is different to std::string).
+//   GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string
+//                              is/isn't available (some systems define
+//                              ::wstring, which is different to std::wstring).
+//   GTEST_HAS_PTHREAD        - Define it to 1/0 to indicate that <pthread.h>
+//                              is/isn't available.
+//   GTEST_HAS_RTTI           - Define it to 1/0 to indicate that RTTI is/isn't
+//                              enabled.
+//   GTEST_HAS_STD_STRING     - Define it to 1/0 to indicate that
+//                              std::string does/doesn't work (Google Test can
+//                              be used where std::string is unavailable).
+//   GTEST_HAS_STD_WSTRING    - Define it to 1/0 to indicate that
+//                              std::wstring does/doesn't work (Google Test can
+//                              be used where std::wstring is unavailable).
+//   GTEST_HAS_TR1_TUPLE 1    - Define it to 1/0 to indicate tr1::tuple
+//                              is/isn't available.
+//   GTEST_HAS_SEH            - Define it to 1/0 to indicate whether the
+//                              compiler supports Microsoft's "Structured
+//                              Exception Handling".
+
+// This header defines the following utilities:
+//
+// Macros indicating the current platform (defined to 1 if compiled on
+// the given platform; otherwise undefined):
+//   GTEST_OS_CYGWIN   - Cygwin
+//   GTEST_OS_LINUX    - Linux
+//   GTEST_OS_MAC      - Mac OS X
+//   GTEST_OS_SOLARIS  - Sun Solaris
+//   GTEST_OS_SYMBIAN  - Symbian
+//   GTEST_OS_WINDOWS  - Windows
+//   GTEST_OS_ZOS      - z/OS
+//
+// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
+// most stable support.  Since core members of the Google Test project
+// don't have access to other platforms, support for them may be less
+// stable.  If you notice any problems on your platform, please notify
+// googletestframework@googlegroups.com (patches for fixing them are
+// even more welcome!).
+//
+// Note that it is possible that none of the GTEST_OS_* macros are defined.
+//
+// Macros indicating available Google Test features (defined to 1 if
+// the corresponding feature is supported; otherwise undefined):
+//   GTEST_HAS_COMBINE      - the Combine() function (for value-parameterized
+//                            tests)
+//   GTEST_HAS_DEATH_TEST   - death tests
+//   GTEST_HAS_PARAM_TEST   - value-parameterized tests
+//   GTEST_HAS_TYPED_TEST   - typed tests
+//   GTEST_HAS_TYPED_TEST_P - type-parameterized tests
+//   GTEST_USES_POSIX_RE    - enhanced POSIX regex is used.
+//   GTEST_USES_SIMPLE_RE   - our own simple regex is used;
+//                            the above two are mutually exclusive.
+//
+// Macros for basic C++ coding:
+//   GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
+//   GTEST_ATTRIBUTE_UNUSED_  - declares that a class' instances or a
+//                              variable don't have to be used.
+//   GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
+//   GTEST_MUST_USE_RESULT_   - declares that a function's result must be used.
+//
+// Synchronization:
+//   Mutex, MutexLock, ThreadLocal, GetThreadCount()
+//                  - synchronization primitives.
+//   GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
+//                         synchronization primitives have real implementations
+//                         and Google Test is thread-safe; or 0 otherwise.
+//
+// Template meta programming:
+//   is_pointer     - as in TR1; needed on Symbian and IBM XL C/C++ only.
+//
+// Smart pointers:
+//   scoped_ptr     - as in TR2.
+//
+// Regular expressions:
+//   RE             - a simple regular expression class using the POSIX
+//                    Extended Regular Expression syntax.  Not available on
+//                    Windows.
+//
+// Logging:
+//   GTEST_LOG_()   - logs messages at the specified severity level.
+//   LogToStderr()  - directs all log messages to stderr.
+//   FlushInfoLog() - flushes informational log messages.
+//
+// Stderr capturing:
+//   CaptureStderr()     - starts capturing stderr.
+//   GetCapturedStderr() - stops capturing stderr and returns the captured
+//                         string.
+//
+// Integer types:
+//   TypeWithSize   - maps an integer to a int type.
+//   Int32, UInt32, Int64, UInt64, TimeInMillis
+//                  - integers of known sizes.
+//   BiggestInt     - the biggest signed integer type.
+//
+// Command-line utilities:
+//   GTEST_FLAG()       - references a flag.
+//   GTEST_DECLARE_*()  - declares a flag.
+//   GTEST_DEFINE_*()   - defines a flag.
+//   GetArgvs()         - returns the command line as a vector of strings.
+//
+// Environment variable utilities:
+//   GetEnv()             - gets the value of an environment variable.
+//   BoolFromGTestEnv()   - parses a bool environment variable.
+//   Int32FromGTestEnv()  - parses an Int32 environment variable.
+//   StringFromGTestEnv() - parses a string environment variable.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <iostream>  // NOLINT
+
+#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
+#define GTEST_FLAG_PREFIX_ "gtest_"
+#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
+#define GTEST_NAME_ "Google Test"
+#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"
+
+// Determines the version of gcc that is used to compile this.
+#ifdef __GNUC__
+// 40302 means version 4.3.2.
+#define GTEST_GCC_VER_ \
+    (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
+#endif  // __GNUC__
+
+// Determines the platform on which Google Test is compiled.
+#ifdef __CYGWIN__
+#define GTEST_OS_CYGWIN 1
+#elif __SYMBIAN32__
+#define GTEST_OS_SYMBIAN 1
+#elif defined _WIN32
+#define GTEST_OS_WINDOWS 1
+#elif defined __APPLE__
+#define GTEST_OS_MAC 1
+#elif defined __linux__
+#define GTEST_OS_LINUX 1
+#elif defined __MVS__
+#define GTEST_OS_ZOS 1
+#elif defined(__sun) && defined(__SVR4)
+#define GTEST_OS_SOLARIS 1
+#endif  // __CYGWIN__
+
+#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC
+
+// On some platforms, <regex.h> needs someone to define size_t, and
+// won't compile otherwise.  We can #include it here as we already
+// included <stdlib.h>, which is guaranteed to define size_t through
+// <stddef.h>.
+#include <regex.h>  // NOLINT
+#include <strings.h>  // NOLINT
+#include <sys/types.h>  // NOLINT
+#include <unistd.h>  // NOLINT
+
+#define GTEST_USES_POSIX_RE 1
+
+#elif GTEST_OS_WINDOWS
+
+#include <direct.h>  // NOLINT
+#include <io.h>  // NOLINT
+
+// <regex.h> is not available on Windows.  Use our own simple regex
+// implementation instead.
+#define GTEST_USES_SIMPLE_RE 1
+
+#else
+
+// <regex.h> may not be available on this platform.  Use our own
+// simple regex implementation instead.
+#define GTEST_USES_SIMPLE_RE 1
+
+#endif  // GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC
+
+// Defines GTEST_HAS_EXCEPTIONS to 1 if exceptions are enabled, or 0
+// otherwise.
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
+// macro to enable exceptions, so we'll do the same.
+// Assumes that exceptions are enabled by default.
+#ifndef _HAS_EXCEPTIONS
+#define _HAS_EXCEPTIONS 1
+#endif  // _HAS_EXCEPTIONS
+#define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+#else  // The compiler is not MSVC or C++Builder.
+// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.  For
+// other compilers, we assume exceptions are disabled to be
+// conservative.
+#if defined(__GNUC__) && __EXCEPTIONS
+#define GTEST_HAS_EXCEPTIONS 1
+#else
+#define GTEST_HAS_EXCEPTIONS 0
+#endif  // defined(__GNUC__) && __EXCEPTIONS
+#endif  // defined(_MSC_VER) || defined(__BORLANDC__)
+
+// Determines whether ::std::string and ::string are available.
+
+#ifndef GTEST_HAS_STD_STRING
+// The user didn't tell us whether ::std::string is available, so we
+// need to figure it out.  The only environment that we know
+// ::std::string is not available is MSVC 7.1 or lower with exceptions
+// disabled.
+#if defined(_MSC_VER) && (_MSC_VER < 1400) && !GTEST_HAS_EXCEPTIONS
+#define GTEST_HAS_STD_STRING 0
+#else
+#define GTEST_HAS_STD_STRING 1
+#endif
+#endif  // GTEST_HAS_STD_STRING
+
+#ifndef GTEST_HAS_GLOBAL_STRING
+// The user didn't tell us whether ::string is available, so we need
+// to figure it out.
+
+#define GTEST_HAS_GLOBAL_STRING 0
+
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+#ifndef GTEST_HAS_STD_WSTRING
+// The user didn't tell us whether ::std::wstring is available, so we need
+// to figure it out.
+// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring
+//   is available.
+
+#if GTEST_OS_CYGWIN || GTEST_OS_SOLARIS
+// Cygwin 1.5 and below doesn't support ::std::wstring.
+// Cygwin 1.7 might add wstring support; this should be updated when clear.
+// Solaris' libc++ doesn't support it either.
+#define GTEST_HAS_STD_WSTRING 0
+#else
+#define GTEST_HAS_STD_WSTRING GTEST_HAS_STD_STRING
+#endif  // GTEST_OS_CYGWIN || GTEST_OS_SOLARIS
+
+#endif  // GTEST_HAS_STD_WSTRING
+
+#ifndef GTEST_HAS_GLOBAL_WSTRING
+// The user didn't tell us whether ::wstring is available, so we need
+// to figure it out.
+#define GTEST_HAS_GLOBAL_WSTRING \
+    (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_STRING || GTEST_HAS_GLOBAL_STRING || \
+    GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+#include <string>  // NOLINT
+#endif  // GTEST_HAS_STD_STRING || GTEST_HAS_GLOBAL_STRING ||
+        // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+#if GTEST_HAS_STD_STRING
+#include <sstream>  // NOLINT
+#else
+#include <strstream>  // NOLINT
+#endif  // GTEST_HAS_STD_STRING
+
+// Determines whether RTTI is available.
+#ifndef GTEST_HAS_RTTI
+// The user didn't tell us whether RTTI is enabled, so we need to
+// figure it out.
+
+#ifdef _MSC_VER
+
+#ifdef _CPPRTTI  // MSVC defines this macro iff RTTI is enabled.
+#define GTEST_HAS_RTTI 1
+#else
+#define GTEST_HAS_RTTI 0
+#endif  // _CPPRTTI
+
+#elif defined(__GNUC__)
+
+// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
+#if GTEST_GCC_VER_ >= 40302
+#ifdef __GXX_RTTI
+#define GTEST_HAS_RTTI 1
+#else
+#define GTEST_HAS_RTTI 0
+#endif  // __GXX_RTTI
+#else
+// For gcc versions smaller than 4.3.2, we assume RTTI is enabled.
+#define GTEST_HAS_RTTI 1
+#endif  // GTEST_GCC_VER >= 40302
+
+#else
+
+// Unknown compiler - assume RTTI is enabled.
+#define GTEST_HAS_RTTI 1
+
+#endif  // _MSC_VER
+
+#endif  // GTEST_HAS_RTTI
+
+// Determines whether <pthread.h> is available.
+#ifndef GTEST_HAS_PTHREAD
+// The user didn't tell us, so we need to figure it out.
+#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC)
+#endif  // GTEST_HAS_PTHREAD
+
+// Determines whether tr1/tuple is available.  If you have tr1/tuple
+// on your platform, define GTEST_HAS_TR1_TUPLE=1 for both the Google
+// Test project and your tests. If you would like Google Test to detect
+// tr1/tuple on your platform automatically, please open an issue
+// ticket at http://code.google.com/p/googletest.
+#ifndef GTEST_HAS_TR1_TUPLE
+// The user didn't tell us, so we need to figure it out.
+
+// GCC provides <tr1/tuple> since 4.0.0.
+#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
+#define GTEST_HAS_TR1_TUPLE 1
+#else
+#define GTEST_HAS_TR1_TUPLE 0
+#endif  // __GNUC__
+#endif  // GTEST_HAS_TR1_TUPLE
+
+// To avoid conditional compilation everywhere, we make it
+// gtest-port.h's responsibility to #include the header implementing
+// tr1/tuple.
+#if GTEST_HAS_TR1_TUPLE
+
+#if GTEST_OS_SYMBIAN
+
+// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to
+// use STLport's tuple implementation, which unfortunately doesn't
+// work as the copy of STLport distributed with Symbian is incomplete.
+// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to
+// use its own tuple implementation.
+#ifdef BOOST_HAS_TR1_TUPLE
+#undef BOOST_HAS_TR1_TUPLE
+#endif  // BOOST_HAS_TR1_TUPLE
+
+// This prevents <boost/tr1/detail/config.hpp>, which defines
+// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
+#define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
+#include <tuple>
+
+#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
+// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header.  This does
+// not conform to the TR1 spec, which requires the header to be <tuple>.
+
+#if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+// Until version 4.3.2, gcc has a bug that causes <tr1/functional>,
+// which is #included by <tr1/tuple>, to not compile when RTTI is
+// disabled.  _TR1_FUNCTIONAL is the header guard for
+// <tr1/functional>.  Hence the following #define is a hack to prevent
+// <tr1/functional> from being included.
+#define _TR1_FUNCTIONAL 1
+#include <tr1/tuple>
+#undef _TR1_FUNCTIONAL  // Allows the user to #include
+                        // <tr1/functional> if he chooses to.
+#else
+#include <tr1/tuple>
+#endif  // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+
+#else
+// If the compiler is not GCC 4.0+, we assume the user is using a
+// spec-conforming TR1 implementation.
+#include <tuple>
+#endif  // GTEST_OS_SYMBIAN
+
+#endif  // GTEST_HAS_TR1_TUPLE
+
+// Determines whether clone(2) is supported.
+// Usually it will only be available on Linux, excluding
+// Linux on the Itanium architecture.
+// Also see http://linux.die.net/man/2/clone.
+#ifndef GTEST_HAS_CLONE
+// The user didn't tell us, so we need to figure it out.
+
+#if GTEST_OS_LINUX && !defined(__ia64__)
+#define GTEST_HAS_CLONE 1
+#else
+#define GTEST_HAS_CLONE 0
+#endif  // GTEST_OS_LINUX && !defined(__ia64__)
+
+#endif  // GTEST_HAS_CLONE
+
+// Determines whether to support death tests.
+// Google Test does not support death tests for VC 7.1 and earlier for
+// these reasons:
+//   1. std::vector does not build in VC 7.1 when exceptions are disabled.
+//   2. std::string does not build in VC 7.1 when exceptions are disabled
+//      (this is covered by GTEST_HAS_STD_STRING guard).
+//   3. abort() in a VC 7.1 application compiled as GUI in debug config
+//      pops up a dialog window that cannot be suppressed programmatically.
+#if GTEST_HAS_STD_STRING && (GTEST_OS_LINUX || \
+                             GTEST_OS_MAC || \
+                             GTEST_OS_CYGWIN || \
+                             (GTEST_OS_WINDOWS && _MSC_VER >= 1400))
+#define GTEST_HAS_DEATH_TEST 1
+#include <vector>  // NOLINT
+#endif
+
+// Determines whether to support value-parameterized tests.
+
+#if defined(__GNUC__) || (_MSC_VER >= 1400)
+// TODO(vladl@google.com): get the implementation rid of vector and list
+// to compile on MSVC 7.1.
+#define GTEST_HAS_PARAM_TEST 1
+#endif  // defined(__GNUC__) || (_MSC_VER >= 1400)
+
+// Determines whether to support type-driven tests.
+
+// Typed tests need <typeinfo> and variadic macros, which gcc and VC
+// 8.0+ support.
+#if defined(__GNUC__) || (_MSC_VER >= 1400)
+#define GTEST_HAS_TYPED_TEST 1
+#define GTEST_HAS_TYPED_TEST_P 1
+#endif  // defined(__GNUC__) || (_MSC_VER >= 1400)
+
+// Determines whether to support Combine(). This only makes sense when
+// value-parameterized tests are enabled.
+#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE
+#define GTEST_HAS_COMBINE 1
+#endif  // GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE
+
+// Determines whether the system compiler uses UTF-16 for encoding wide strings.
+#define GTEST_WIDE_STRING_USES_UTF16_ \
+    (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN)
+
+// Defines some utility macros.
+
+// The GNU compiler emits a warning if nested "if" statements are followed by
+// an "else" statement and braces are not used to explicitly disambiguate the
+// "else" binding.  This leads to problems with code like:
+//
+//   if (gate)
+//     ASSERT_*(condition) << "Some message";
+//
+// The "switch (0) case 0:" idiom is used to suppress this.
+#ifdef __INTEL_COMPILER
+#define GTEST_AMBIGUOUS_ELSE_BLOCKER_
+#else
+#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0:  // NOLINT
+#endif
+
+// Use this annotation at the end of a struct/class definition to
+// prevent the compiler from optimizing away instances that are never
+// used.  This is useful when all interesting logic happens inside the
+// c'tor and / or d'tor.  Example:
+//
+//   struct Foo {
+//     Foo() { ... }
+//   } GTEST_ATTRIBUTE_UNUSED_;
+//
+// Also use it after a variable or parameter declaration to tell the
+// compiler the variable/parameter does not have to be used.
+#if defined(__GNUC__) && !defined(COMPILER_ICC)
+#define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+#else
+#define GTEST_ATTRIBUTE_UNUSED_
+#endif
+
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\
+  type(const type &);\
+  void operator=(const type &)
+
+// Tell the compiler to warn about unused return values for functions declared
+// with this macro.  The macro should be used on function declarations
+// following the argument list:
+//
+//   Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
+#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
+#define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
+#else
+#define GTEST_MUST_USE_RESULT_
+#endif  // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
+
+// Determine whether the compiler supports Microsoft's Structured Exception
+// Handling.  This is supported by several Windows compilers but generally
+// does not exist on any other system.
+#ifndef GTEST_HAS_SEH
+// The user didn't tell us, so we need to figure it out.
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// These two compilers are known to support SEH.
+#define GTEST_HAS_SEH 1
+#else
+// Assume no SEH.
+#define GTEST_HAS_SEH 0
+#endif
+
+#endif  // GTEST_HAS_SEH
+
+namespace testing {
+
+class Message;
+
+namespace internal {
+
+class String;
+
+// std::strstream is deprecated.  However, we have to use it on
+// Windows as std::stringstream won't compile on Windows when
+// exceptions are disabled.  We use std::stringstream on other
+// platforms to avoid compiler warnings there.
+#if GTEST_HAS_STD_STRING
+typedef ::std::stringstream StrStream;
+#else
+typedef ::std::strstream StrStream;
+#endif  // GTEST_HAS_STD_STRING
+
+// Defines scoped_ptr.
+
+// This implementation of scoped_ptr is PARTIAL - it only contains
+// enough stuff to satisfy Google Test's need.
+template <typename T>
+class scoped_ptr {
+ public:
+  explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
+  ~scoped_ptr() { reset(); }
+
+  T& operator*() const { return *ptr_; }
+  T* operator->() const { return ptr_; }
+  T* get() const { return ptr_; }
+
+  T* release() {
+    T* const ptr = ptr_;
+    ptr_ = NULL;
+    return ptr;
+  }
+
+  void reset(T* p = NULL) {
+    if (p != ptr_) {
+      if (sizeof(T) > 0) {  // Makes sure T is a complete type.
+        delete ptr_;
+      }
+      ptr_ = p;
+    }
+  }
+ private:
+  T* ptr_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
+};
+
+// Defines RE.
+
+// A simple C++ wrapper for <regex.h>.  It uses the POSIX Enxtended
+// Regular Expression syntax.
+class RE {
+ public:
+  // Constructs an RE from a string.
+#if GTEST_HAS_STD_STRING
+  RE(const ::std::string& regex) { Init(regex.c_str()); }  // NOLINT
+#endif  // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_GLOBAL_STRING
+  RE(const ::string& regex) { Init(regex.c_str()); }  // NOLINT
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+  RE(const char* regex) { Init(regex); }  // NOLINT
+  ~RE();
+
+  // Returns the string representation of the regex.
+  const char* pattern() const { return pattern_; }
+
+  // FullMatch(str, re) returns true iff regular expression re matches
+  // the entire str.
+  // PartialMatch(str, re) returns true iff regular expression re
+  // matches a substring of str (including str itself).
+  //
+  // TODO(wan@google.com): make FullMatch() and PartialMatch() work
+  // when str contains NUL characters.
+#if GTEST_HAS_STD_STRING
+  static bool FullMatch(const ::std::string& str, const RE& re) {
+    return FullMatch(str.c_str(), re);
+  }
+  static bool PartialMatch(const ::std::string& str, const RE& re) {
+    return PartialMatch(str.c_str(), re);
+  }
+#endif  // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_GLOBAL_STRING
+  static bool FullMatch(const ::string& str, const RE& re) {
+    return FullMatch(str.c_str(), re);
+  }
+  static bool PartialMatch(const ::string& str, const RE& re) {
+    return PartialMatch(str.c_str(), re);
+  }
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+  static bool FullMatch(const char* str, const RE& re);
+  static bool PartialMatch(const char* str, const RE& re);
+
+ private:
+  void Init(const char* regex);
+
+  // We use a const char* instead of a string, as Google Test may be used
+  // where string is not available.  We also do not use Google Test's own
+  // String type here, in order to simplify dependencies between the
+  // files.
+  const char* pattern_;
+  bool is_valid_;
+#if GTEST_USES_POSIX_RE
+  regex_t full_regex_;     // For FullMatch().
+  regex_t partial_regex_;  // For PartialMatch().
+#else  // GTEST_USES_SIMPLE_RE
+  const char* full_pattern_;  // For FullMatch();
+#endif
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(RE);
+};
+
+// Defines logging utilities:
+//   GTEST_LOG_()   - logs messages at the specified severity level.
+//   LogToStderr()  - directs all log messages to stderr.
+//   FlushInfoLog() - flushes informational log messages.
+
+enum GTestLogSeverity {
+  GTEST_INFO,
+  GTEST_WARNING,
+  GTEST_ERROR,
+  GTEST_FATAL
+};
+
+void GTestLog(GTestLogSeverity severity, const char* file,
+              int line, const char* msg);
+
+#define GTEST_LOG_(severity, msg)\
+    ::testing::internal::GTestLog(\
+        ::testing::internal::GTEST_##severity, __FILE__, __LINE__, \
+        (::testing::Message() << (msg)).GetString().c_str())
+
+inline void LogToStderr() {}
+inline void FlushInfoLog() { fflush(NULL); }
+
+// Defines the stderr capturer:
+//   CaptureStderr     - starts capturing stderr.
+//   GetCapturedStderr - stops capturing stderr and returns the captured string.
+
+#if GTEST_HAS_STD_STRING
+void CaptureStderr();
+::std::string GetCapturedStderr();
+#endif  // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments.  Set by InitGoogleTest().
+extern ::std::vector<String> g_argvs;
+
+// GTEST_HAS_DEATH_TEST implies we have ::std::string.
+const ::std::vector<String>& GetArgvs();
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+// Defines synchronization primitives.
+
+// A dummy implementation of synchronization primitives (mutex, lock,
+// and thread-local variable).  Necessary for compiling Google Test where
+// mutex is not supported - using Google Test in multiple threads is not
+// supported on such platforms.
+
+class Mutex {
+ public:
+  Mutex() {}
+  explicit Mutex(int /*unused*/) {}
+  void AssertHeld() const {}
+  enum { NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX = 0 };
+};
+
+// We cannot call it MutexLock directly as the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms.  Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+  explicit GTestMutexLock(Mutex*) {}  // NOLINT
+};
+
+typedef GTestMutexLock MutexLock;
+
+template <typename T>
+class ThreadLocal {
+ public:
+  ThreadLocal() : value_() {}
+  explicit ThreadLocal(const T& value) : value_(value) {}
+  T* pointer() { return &value_; }
+  const T* pointer() const { return &value_; }
+  const T& get() const { return value_; }
+  void set(const T& value) { value_ = value; }
+ private:
+  T value_;
+};
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount();
+
+// The above synchronization primitives have dummy implementations.
+// Therefore Google Test is not thread-safe.
+#define GTEST_IS_THREADSAFE 0
+
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__)
+
+// Passing non-POD classes through ellipsis (...) crashes the ARM
+// compiler.  The Nokia Symbian and the IBM XL C/C++ compiler try to
+// instantiate a copy constructor for objects passed through ellipsis
+// (...), failing for uncopyable objects.  We define this to indicate
+// the fact.
+#define GTEST_ELLIPSIS_NEEDS_COPY_ 1
+
+// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between
+// const T& and const T* in a function template.  These compilers
+// _can_ decide between class template specializations for T and T*,
+// so a tr1::type_traits-like is_pointer works.
+#define GTEST_NEEDS_IS_POINTER_ 1
+
+#endif  // defined(__SYMBIAN32__) || defined(__IBMCPP__)
+
+template <bool bool_value>
+struct bool_constant {
+  typedef bool_constant<bool_value> type;
+  static const bool value = bool_value;
+};
+template <bool bool_value> const bool bool_constant<bool_value>::value;
+
+typedef bool_constant<false> false_type;
+typedef bool_constant<true> true_type;
+
+template <typename T>
+struct is_pointer : public false_type {};
+
+template <typename T>
+struct is_pointer<T*> : public true_type {};
+
+#if GTEST_OS_WINDOWS
+#define GTEST_PATH_SEP_ "\\"
+// The biggest signed integer type the compiler supports.
+typedef __int64 BiggestInt;
+#else
+#define GTEST_PATH_SEP_ "/"
+typedef long long BiggestInt;  // NOLINT
+#endif  // GTEST_OS_WINDOWS
+
+// The testing::internal::posix namespace holds wrappers for common
+// POSIX functions.  These wrappers hide the differences between
+// Windows/MSVC and POSIX systems.  Since some compilers define these
+// standard functions as macros, the wrapper cannot have the same name
+// as the wrapped function.
+
+namespace posix {
+
+// Functions with a different name on Windows.
+
+#if GTEST_OS_WINDOWS
+
+typedef struct _stat StatStruct;
+
+#ifdef __BORLANDC__
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+  return stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+#else
+inline int IsATTY(int fd) { return _isatty(fd); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+  return _stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return _strdup(src); }
+#endif  // __BORLANDC__
+
+inline int FileNo(FILE* file) { return _fileno(file); }
+inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
+inline int RmDir(const char* dir) { return _rmdir(dir); }
+inline bool IsDir(const StatStruct& st) {
+  return (_S_IFDIR & st.st_mode) != 0;
+}
+
+#else
+
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+  return strcasecmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+inline int RmDir(const char* dir) { return rmdir(dir); }
+inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
+
+#endif  // GTEST_OS_WINDOWS
+
+// Functions deprecated by MSVC 8.0.
+
+#ifdef _MSC_VER
+// Temporarily disable warning 4996 (deprecated function).
+#pragma warning(push)
+#pragma warning(disable:4996)
+#endif
+
+inline const char* StrNCpy(char* dest, const char* src, size_t n) {
+  return strncpy(dest, src, n);
+}
+inline int ChDir(const char* dir) { return chdir(dir); }
+inline FILE* FOpen(const char* path, const char* mode) {
+  return fopen(path, mode);
+}
+inline FILE *FReopen(const char* path, const char* mode, FILE* stream) {
+  return freopen(path, mode, stream);
+}
+inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); }
+inline int FClose(FILE* fp) { return fclose(fp); }
+inline int Read(int fd, void* buf, unsigned int count) {
+  return static_cast<int>(read(fd, buf, count));
+}
+inline int Write(int fd, const void* buf, unsigned int count) {
+  return static_cast<int>(write(fd, buf, count));
+}
+inline int Close(int fd) { return close(fd); }
+inline const char* StrError(int errnum) { return strerror(errnum); }
+inline const char* GetEnv(const char* name) {
+#ifdef _WIN32_WCE  // We are on Windows CE, which has no environment variables.
+  return NULL;
+#elif defined(__BORLANDC__)
+  // Environment variables which we programmatically clear will be set to the
+  // empty string rather than unset (NULL).  Handle that case.
+  const char* const env = getenv(name);
+  return (env != NULL && env[0] != '\0') ? env : NULL;
+#else
+  return getenv(name);
+#endif
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)  // Restores the warning state.
+#endif
+
+#ifdef _WIN32_WCE
+// Windows CE has no C library. The abort() function is used in
+// several places in Google Test. This implementation provides a reasonable
+// imitation of standard behaviour.
+void Abort();
+#else
+inline void Abort() { abort(); }
+#endif  // _WIN32_WCE
+
+}  // namespace posix
+
+// The maximum number a BiggestInt can represent.  This definition
+// works no matter BiggestInt is represented in one's complement or
+// two's complement.
+//
+// We cannot rely on numeric_limits in STL, as __int64 and long long
+// are not part of standard C++ and numeric_limits doesn't need to be
+// defined for them.
+const BiggestInt kMaxBiggestInt =
+    ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));
+
+// This template class serves as a compile-time function from size to
+// type.  It maps a size in bytes to a primitive type with that
+// size. e.g.
+//
+//   TypeWithSize<4>::UInt
+//
+// is typedef-ed to be unsigned int (unsigned integer made up of 4
+// bytes).
+//
+// Such functionality should belong to STL, but I cannot find it
+// there.
+//
+// Google Test uses this class in the implementation of floating-point
+// comparison.
+//
+// For now it only handles UInt (unsigned int) as that's all Google Test
+// needs.  Other types can be easily added in the future if need
+// arises.
+template <size_t size>
+class TypeWithSize {
+ public:
+  // This prevents the user from using TypeWithSize<N> with incorrect
+  // values of N.
+  typedef void UInt;
+};
+
+// The specialization for size 4.
+template <>
+class TypeWithSize<4> {
+ public:
+  // unsigned int has size 4 in both gcc and MSVC.
+  //
+  // As base/basictypes.h doesn't compile on Windows, we cannot use
+  // uint32, uint64, and etc here.
+  typedef int Int;
+  typedef unsigned int UInt;
+};
+
+// The specialization for size 8.
+template <>
+class TypeWithSize<8> {
+ public:
+#if GTEST_OS_WINDOWS
+  typedef __int64 Int;
+  typedef unsigned __int64 UInt;
+#else
+  typedef long long Int;  // NOLINT
+  typedef unsigned long long UInt;  // NOLINT
+#endif  // GTEST_OS_WINDOWS
+};
+
+// Integer types of known sizes.
+typedef TypeWithSize<4>::Int Int32;
+typedef TypeWithSize<4>::UInt UInt32;
+typedef TypeWithSize<8>::Int Int64;
+typedef TypeWithSize<8>::UInt UInt64;
+typedef TypeWithSize<8>::Int TimeInMillis;  // Represents time in milliseconds.
+
+// Utilities for command line flags and environment variables.
+
+// INTERNAL IMPLEMENTATION - DO NOT USE.
+//
+// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
+// is not satisfied.
+//  Synopsys:
+//    GTEST_CHECK_(boolean_condition);
+//     or
+//    GTEST_CHECK_(boolean_condition) << "Additional message";
+//
+//    This checks the condition and if the condition is not satisfied
+//    it prints message about the condition violation, including the
+//    condition itself, plus additional message streamed into it, if any,
+//    and then it aborts the program. It aborts the program irrespective of
+//    whether it is built in the debug mode or not.
+class GTestCheckProvider {
+ public:
+  GTestCheckProvider(const char* condition, const char* file, int line) {
+    FormatFileLocation(file, line);
+    ::std::cerr << " ERROR: Condition " << condition << " failed. ";
+  }
+  ~GTestCheckProvider() {
+    ::std::cerr << ::std::endl;
+    abort();
+  }
+  void FormatFileLocation(const char* file, int line) {
+    if (file == NULL)
+      file = "unknown file";
+    if (line < 0) {
+      ::std::cerr << file << ":";
+    } else {
+#if _MSC_VER
+      ::std::cerr << file << "(" << line << "):";
+#else
+      ::std::cerr << file << ":" << line << ":";
+#endif
+    }
+  }
+  ::std::ostream& GetStream() { return ::std::cerr; }
+};
+#define GTEST_CHECK_(condition) \
+    GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+    if (condition) \
+      ; \
+    else \
+      ::testing::internal::GTestCheckProvider(\
+          #condition, __FILE__, __LINE__).GetStream()
+
+// Macro for referencing flags.
+#define GTEST_FLAG(name) FLAGS_gtest_##name
+
+// Macros for declaring flags.
+#define GTEST_DECLARE_bool_(name) extern bool GTEST_FLAG(name)
+#define GTEST_DECLARE_int32_(name) \
+    extern ::testing::internal::Int32 GTEST_FLAG(name)
+#define GTEST_DECLARE_string_(name) \
+    extern ::testing::internal::String GTEST_FLAG(name)
+
+// Macros for defining flags.
+#define GTEST_DEFINE_bool_(name, default_val, doc) \
+    bool GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_int32_(name, default_val, doc) \
+    ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_string_(name, default_val, doc) \
+    ::testing::internal::String GTEST_FLAG(name) = (default_val)
+
+// Parses 'str' for a 32-bit signed integer.  If successful, writes the result
+// to *value and returns true; otherwise leaves *value unchanged and returns
+// false.
+// TODO(chandlerc): Find a better way to refactor flag and environment parsing
+// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
+// function.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value);
+
+// Parses a bool/Int32/string from the environment variable
+// corresponding to the given Google Test flag.
+bool BoolFromGTestEnv(const char* flag, bool default_val);
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
diff --git a/third_party/gtest/include/gtest/internal/gtest-string.h b/third_party/gtest/include/gtest/internal/gtest-string.h
index 342ff02..566a6b5 100644
--- a/third_party/gtest/include/gtest/internal/gtest-string.h
+++ b/third_party/gtest/include/gtest/internal/gtest-string.h
@@ -1,335 +1,335 @@
-// Copyright 2005, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)

-//

-// The Google C++ Testing Framework (Google Test)

-//

-// This header file declares the String class and functions used internally by

-// Google Test.  They are subject to change without notice. They should not used

-// by code external to Google Test.

-//

-// This header file is #included by <gtest/internal/gtest-internal.h>.

-// It should not be #included by other files.

-

-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_

-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_

-

-#include <string.h>

-#include <gtest/internal/gtest-port.h>

-

-#if GTEST_HAS_GLOBAL_STRING || GTEST_HAS_STD_STRING

-#include <string>

-#endif  // GTEST_HAS_GLOBAL_STRING || GTEST_HAS_STD_STRING

-

-namespace testing {

-namespace internal {

-

-// String - a UTF-8 string class.

-//

-// We cannot use std::string as Microsoft's STL implementation in

-// Visual C++ 7.1 has problems when exception is disabled.  There is a

-// hack to work around this, but we've seen cases where the hack fails

-// to work.

-//

-// Also, String is different from std::string in that it can represent

-// both NULL and the empty string, while std::string cannot represent

-// NULL.

-//

-// NULL and the empty string are considered different.  NULL is less

-// than anything (including the empty string) except itself.

-//

-// This class only provides minimum functionality necessary for

-// implementing Google Test.  We do not intend to implement a full-fledged

-// string class here.

-//

-// Since the purpose of this class is to provide a substitute for

-// std::string on platforms where it cannot be used, we define a copy

-// constructor and assignment operators such that we don't need

-// conditional compilation in a lot of places.

-//

-// In order to make the representation efficient, the d'tor of String

-// is not virtual.  Therefore DO NOT INHERIT FROM String.

-class String {

- public:

-  // Static utility methods

-

-  // Returns the input if it's not NULL, otherwise returns "(null)".

-  // This function serves two purposes:

-  //

-  // 1. ShowCString(NULL) has type 'const char *', instead of the

-  // type of NULL (which is int).

-  //

-  // 2. In MSVC, streaming a null char pointer to StrStream generates

-  // an access violation, so we need to convert NULL to "(null)"

-  // before streaming it.

-  static inline const char* ShowCString(const char* c_str) {

-    return c_str ? c_str : "(null)";

-  }

-

-  // Returns the input enclosed in double quotes if it's not NULL;

-  // otherwise returns "(null)".  For example, "\"Hello\"" is returned

-  // for input "Hello".

-  //

-  // This is useful for printing a C string in the syntax of a literal.

-  //

-  // Known issue: escape sequences are not handled yet.

-  static String ShowCStringQuoted(const char* c_str);

-

-  // Clones a 0-terminated C string, allocating memory using new.  The

-  // caller is responsible for deleting the return value using

-  // delete[].  Returns the cloned string, or NULL if the input is

-  // NULL.

-  //

-  // This is different from strdup() in string.h, which allocates

-  // memory using malloc().

-  static const char* CloneCString(const char* c_str);

-

-#ifdef _WIN32_WCE

-  // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be

-  // able to pass strings to Win32 APIs on CE we need to convert them

-  // to 'Unicode', UTF-16.

-

-  // Creates a UTF-16 wide string from the given ANSI string, allocating

-  // memory using new. The caller is responsible for deleting the return

-  // value using delete[]. Returns the wide string, or NULL if the

-  // input is NULL.

-  //

-  // The wide string is created using the ANSI codepage (CP_ACP) to

-  // match the behaviour of the ANSI versions of Win32 calls and the

-  // C runtime.

-  static LPCWSTR AnsiToUtf16(const char* c_str);

-

-  // Creates an ANSI string from the given wide string, allocating

-  // memory using new. The caller is responsible for deleting the return

-  // value using delete[]. Returns the ANSI string, or NULL if the

-  // input is NULL.

-  //

-  // The returned string is created using the ANSI codepage (CP_ACP) to

-  // match the behaviour of the ANSI versions of Win32 calls and the

-  // C runtime.

-  static const char* Utf16ToAnsi(LPCWSTR utf16_str);

-#endif

-

-  // Compares two C strings.  Returns true iff they have the same content.

-  //

-  // Unlike strcmp(), this function can handle NULL argument(s).  A

-  // NULL C string is considered different to any non-NULL C string,

-  // including the empty string.

-  static bool CStringEquals(const char* lhs, const char* rhs);

-

-  // Converts a wide C string to a String using the UTF-8 encoding.

-  // NULL will be converted to "(null)".  If an error occurred during

-  // the conversion, "(failed to convert from wide string)" is

-  // returned.

-  static String ShowWideCString(const wchar_t* wide_c_str);

-

-  // Similar to ShowWideCString(), except that this function encloses

-  // the converted string in double quotes.

-  static String ShowWideCStringQuoted(const wchar_t* wide_c_str);

-

-  // Compares two wide C strings.  Returns true iff they have the same

-  // content.

-  //

-  // Unlike wcscmp(), this function can handle NULL argument(s).  A

-  // NULL C string is considered different to any non-NULL C string,

-  // including the empty string.

-  static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);

-

-  // Compares two C strings, ignoring case.  Returns true iff they

-  // have the same content.

-  //

-  // Unlike strcasecmp(), this function can handle NULL argument(s).

-  // A NULL C string is considered different to any non-NULL C string,

-  // including the empty string.

-  static bool CaseInsensitiveCStringEquals(const char* lhs,

-                                           const char* rhs);

-

-  // Compares two wide C strings, ignoring case.  Returns true iff they

-  // have the same content.

-  //

-  // Unlike wcscasecmp(), this function can handle NULL argument(s).

-  // A NULL C string is considered different to any non-NULL wide C string,

-  // including the empty string.

-  // NB: The implementations on different platforms slightly differ.

-  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE

-  // environment variable. On GNU platform this method uses wcscasecmp

-  // which compares according to LC_CTYPE category of the current locale.

-  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the

-  // current locale.

-  static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,

-                                               const wchar_t* rhs);

-

-  // Formats a list of arguments to a String, using the same format

-  // spec string as for printf.

-  //

-  // We do not use the StringPrintf class as it is not universally

-  // available.

-  //

-  // The result is limited to 4096 characters (including the tailing

-  // 0).  If 4096 characters are not enough to format the input,

-  // "<buffer exceeded>" is returned.

-  static String Format(const char* format, ...);

-

-  // C'tors

-

-  // The default c'tor constructs a NULL string.

-  String() : c_str_(NULL) {}

-

-  // Constructs a String by cloning a 0-terminated C string.

-  String(const char* c_str) : c_str_(NULL) {  // NOLINT

-    *this = c_str;

-  }

-

-  // Constructs a String by copying a given number of chars from a

-  // buffer.  E.g. String("hello", 3) will create the string "hel".

-  String(const char* buffer, size_t len);

-

-  // The copy c'tor creates a new copy of the string.  The two

-  // String objects do not share content.

-  String(const String& str) : c_str_(NULL) {

-    *this = str;

-  }

-

-  // D'tor.  String is intended to be a final class, so the d'tor

-  // doesn't need to be virtual.

-  ~String() { delete[] c_str_; }

-

-  // Allows a String to be implicitly converted to an ::std::string or

-  // ::string, and vice versa.  Converting a String containing a NULL

-  // pointer to ::std::string or ::string is undefined behavior.

-  // Converting a ::std::string or ::string containing an embedded NUL

-  // character to a String will result in the prefix up to the first

-  // NUL character.

-#if GTEST_HAS_STD_STRING

-  String(const ::std::string& str) : c_str_(NULL) { *this = str.c_str(); }

-

-  operator ::std::string() const { return ::std::string(c_str_); }

-#endif  // GTEST_HAS_STD_STRING

-

-#if GTEST_HAS_GLOBAL_STRING

-  String(const ::string& str) : c_str_(NULL) { *this = str.c_str(); }

-

-  operator ::string() const { return ::string(c_str_); }

-#endif  // GTEST_HAS_GLOBAL_STRING

-

-  // Returns true iff this is an empty string (i.e. "").

-  bool empty() const {

-    return (c_str_ != NULL) && (*c_str_ == '\0');

-  }

-

-  // Compares this with another String.

-  // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0

-  // if this is greater than rhs.

-  int Compare(const String& rhs) const;

-

-  // Returns true iff this String equals the given C string.  A NULL

-  // string and a non-NULL string are considered not equal.

-  bool operator==(const char* c_str) const {

-    return CStringEquals(c_str_, c_str);

-  }

-

-  // Returns true iff this String is less than the given C string.  A NULL

-  // string is considered less than "".

-  bool operator<(const String& rhs) const { return Compare(rhs) < 0; }

-

-  // Returns true iff this String doesn't equal the given C string.  A NULL

-  // string and a non-NULL string are considered not equal.

-  bool operator!=(const char* c_str) const {

-    return !CStringEquals(c_str_, c_str);

-  }

-

-  // Returns true iff this String ends with the given suffix.  *Any*

-  // String is considered to end with a NULL or empty suffix.

-  bool EndsWith(const char* suffix) const;

-

-  // Returns true iff this String ends with the given suffix, not considering

-  // case. Any String is considered to end with a NULL or empty suffix.

-  bool EndsWithCaseInsensitive(const char* suffix) const;

-

-  // Returns the length of the encapsulated string, or -1 if the

-  // string is NULL.

-  int GetLength() const {

-    return c_str_ ? static_cast<int>(strlen(c_str_)) : -1;

-  }

-

-  // Gets the 0-terminated C string this String object represents.

-  // The String object still owns the string.  Therefore the caller

-  // should NOT delete the return value.

-  const char* c_str() const { return c_str_; }

-

-  // Sets the 0-terminated C string this String object represents.

-  // The old string in this object is deleted, and this object will

-  // own a clone of the input string.  This function copies only up to

-  // length bytes (plus a terminating null byte), or until the first

-  // null byte, whichever comes first.

-  //

-  // This function works even when the c_str parameter has the same

-  // value as that of the c_str_ field.

-  void Set(const char* c_str, size_t length);

-

-  // Assigns a C string to this object.  Self-assignment works.

-  const String& operator=(const char* c_str);

-

-  // Assigns a String object to this object.  Self-assignment works.

-  const String& operator=(const String &rhs) {

-    *this = rhs.c_str_;

-    return *this;

-  }

-

- private:

-  const char* c_str_;

-};

-

-// Streams a String to an ostream.

-inline ::std::ostream& operator <<(::std::ostream& os, const String& str) {

-  // We call String::ShowCString() to convert NULL to "(null)".

-  // Otherwise we'll get an access violation on Windows.

-  return os << String::ShowCString(str.c_str());

-}

-

-// Gets the content of the StrStream's buffer as a String.  Each '\0'

-// character in the buffer is replaced with "\\0".

-String StrStreamToString(StrStream* stream);

-

-// Converts a streamable value to a String.  A NULL pointer is

-// converted to "(null)".  When the input value is a ::string,

-// ::std::string, ::wstring, or ::std::wstring object, each NUL

-// character in it is replaced with "\\0".

-

-// Declared here but defined in gtest.h, so that it has access

-// to the definition of the Message class, required by the ARM

-// compiler.

-template <typename T>

-String StreamableToString(const T& streamable);

-

-}  // namespace internal

-}  // namespace testing

-

-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_

+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares the String class and functions used internally by
+// Google Test.  They are subject to change without notice. They should not used
+// by code external to Google Test.
+//
+// This header file is #included by <gtest/internal/gtest-internal.h>.
+// It should not be #included by other files.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+#include <string.h>
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_HAS_GLOBAL_STRING || GTEST_HAS_STD_STRING
+#include <string>
+#endif  // GTEST_HAS_GLOBAL_STRING || GTEST_HAS_STD_STRING
+
+namespace testing {
+namespace internal {
+
+// String - a UTF-8 string class.
+//
+// We cannot use std::string as Microsoft's STL implementation in
+// Visual C++ 7.1 has problems when exception is disabled.  There is a
+// hack to work around this, but we've seen cases where the hack fails
+// to work.
+//
+// Also, String is different from std::string in that it can represent
+// both NULL and the empty string, while std::string cannot represent
+// NULL.
+//
+// NULL and the empty string are considered different.  NULL is less
+// than anything (including the empty string) except itself.
+//
+// This class only provides minimum functionality necessary for
+// implementing Google Test.  We do not intend to implement a full-fledged
+// string class here.
+//
+// Since the purpose of this class is to provide a substitute for
+// std::string on platforms where it cannot be used, we define a copy
+// constructor and assignment operators such that we don't need
+// conditional compilation in a lot of places.
+//
+// In order to make the representation efficient, the d'tor of String
+// is not virtual.  Therefore DO NOT INHERIT FROM String.
+class String {
+ public:
+  // Static utility methods
+
+  // Returns the input if it's not NULL, otherwise returns "(null)".
+  // This function serves two purposes:
+  //
+  // 1. ShowCString(NULL) has type 'const char *', instead of the
+  // type of NULL (which is int).
+  //
+  // 2. In MSVC, streaming a null char pointer to StrStream generates
+  // an access violation, so we need to convert NULL to "(null)"
+  // before streaming it.
+  static inline const char* ShowCString(const char* c_str) {
+    return c_str ? c_str : "(null)";
+  }
+
+  // Returns the input enclosed in double quotes if it's not NULL;
+  // otherwise returns "(null)".  For example, "\"Hello\"" is returned
+  // for input "Hello".
+  //
+  // This is useful for printing a C string in the syntax of a literal.
+  //
+  // Known issue: escape sequences are not handled yet.
+  static String ShowCStringQuoted(const char* c_str);
+
+  // Clones a 0-terminated C string, allocating memory using new.  The
+  // caller is responsible for deleting the return value using
+  // delete[].  Returns the cloned string, or NULL if the input is
+  // NULL.
+  //
+  // This is different from strdup() in string.h, which allocates
+  // memory using malloc().
+  static const char* CloneCString(const char* c_str);
+
+#ifdef _WIN32_WCE
+  // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
+  // able to pass strings to Win32 APIs on CE we need to convert them
+  // to 'Unicode', UTF-16.
+
+  // Creates a UTF-16 wide string from the given ANSI string, allocating
+  // memory using new. The caller is responsible for deleting the return
+  // value using delete[]. Returns the wide string, or NULL if the
+  // input is NULL.
+  //
+  // The wide string is created using the ANSI codepage (CP_ACP) to
+  // match the behaviour of the ANSI versions of Win32 calls and the
+  // C runtime.
+  static LPCWSTR AnsiToUtf16(const char* c_str);
+
+  // Creates an ANSI string from the given wide string, allocating
+  // memory using new. The caller is responsible for deleting the return
+  // value using delete[]. Returns the ANSI string, or NULL if the
+  // input is NULL.
+  //
+  // The returned string is created using the ANSI codepage (CP_ACP) to
+  // match the behaviour of the ANSI versions of Win32 calls and the
+  // C runtime.
+  static const char* Utf16ToAnsi(LPCWSTR utf16_str);
+#endif
+
+  // Compares two C strings.  Returns true iff they have the same content.
+  //
+  // Unlike strcmp(), this function can handle NULL argument(s).  A
+  // NULL C string is considered different to any non-NULL C string,
+  // including the empty string.
+  static bool CStringEquals(const char* lhs, const char* rhs);
+
+  // Converts a wide C string to a String using the UTF-8 encoding.
+  // NULL will be converted to "(null)".  If an error occurred during
+  // the conversion, "(failed to convert from wide string)" is
+  // returned.
+  static String ShowWideCString(const wchar_t* wide_c_str);
+
+  // Similar to ShowWideCString(), except that this function encloses
+  // the converted string in double quotes.
+  static String ShowWideCStringQuoted(const wchar_t* wide_c_str);
+
+  // Compares two wide C strings.  Returns true iff they have the same
+  // content.
+  //
+  // Unlike wcscmp(), this function can handle NULL argument(s).  A
+  // NULL C string is considered different to any non-NULL C string,
+  // including the empty string.
+  static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
+
+  // Compares two C strings, ignoring case.  Returns true iff they
+  // have the same content.
+  //
+  // Unlike strcasecmp(), this function can handle NULL argument(s).
+  // A NULL C string is considered different to any non-NULL C string,
+  // including the empty string.
+  static bool CaseInsensitiveCStringEquals(const char* lhs,
+                                           const char* rhs);
+
+  // Compares two wide C strings, ignoring case.  Returns true iff they
+  // have the same content.
+  //
+  // Unlike wcscasecmp(), this function can handle NULL argument(s).
+  // A NULL C string is considered different to any non-NULL wide C string,
+  // including the empty string.
+  // NB: The implementations on different platforms slightly differ.
+  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+  // environment variable. On GNU platform this method uses wcscasecmp
+  // which compares according to LC_CTYPE category of the current locale.
+  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+  // current locale.
+  static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+                                               const wchar_t* rhs);
+
+  // Formats a list of arguments to a String, using the same format
+  // spec string as for printf.
+  //
+  // We do not use the StringPrintf class as it is not universally
+  // available.
+  //
+  // The result is limited to 4096 characters (including the tailing
+  // 0).  If 4096 characters are not enough to format the input,
+  // "<buffer exceeded>" is returned.
+  static String Format(const char* format, ...);
+
+  // C'tors
+
+  // The default c'tor constructs a NULL string.
+  String() : c_str_(NULL) {}
+
+  // Constructs a String by cloning a 0-terminated C string.
+  String(const char* c_str) : c_str_(NULL) {  // NOLINT
+    *this = c_str;
+  }
+
+  // Constructs a String by copying a given number of chars from a
+  // buffer.  E.g. String("hello", 3) will create the string "hel".
+  String(const char* buffer, size_t len);
+
+  // The copy c'tor creates a new copy of the string.  The two
+  // String objects do not share content.
+  String(const String& str) : c_str_(NULL) {
+    *this = str;
+  }
+
+  // D'tor.  String is intended to be a final class, so the d'tor
+  // doesn't need to be virtual.
+  ~String() { delete[] c_str_; }
+
+  // Allows a String to be implicitly converted to an ::std::string or
+  // ::string, and vice versa.  Converting a String containing a NULL
+  // pointer to ::std::string or ::string is undefined behavior.
+  // Converting a ::std::string or ::string containing an embedded NUL
+  // character to a String will result in the prefix up to the first
+  // NUL character.
+#if GTEST_HAS_STD_STRING
+  String(const ::std::string& str) : c_str_(NULL) { *this = str.c_str(); }
+
+  operator ::std::string() const { return ::std::string(c_str_); }
+#endif  // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_GLOBAL_STRING
+  String(const ::string& str) : c_str_(NULL) { *this = str.c_str(); }
+
+  operator ::string() const { return ::string(c_str_); }
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+  // Returns true iff this is an empty string (i.e. "").
+  bool empty() const {
+    return (c_str_ != NULL) && (*c_str_ == '\0');
+  }
+
+  // Compares this with another String.
+  // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
+  // if this is greater than rhs.
+  int Compare(const String& rhs) const;
+
+  // Returns true iff this String equals the given C string.  A NULL
+  // string and a non-NULL string are considered not equal.
+  bool operator==(const char* c_str) const {
+    return CStringEquals(c_str_, c_str);
+  }
+
+  // Returns true iff this String is less than the given C string.  A NULL
+  // string is considered less than "".
+  bool operator<(const String& rhs) const { return Compare(rhs) < 0; }
+
+  // Returns true iff this String doesn't equal the given C string.  A NULL
+  // string and a non-NULL string are considered not equal.
+  bool operator!=(const char* c_str) const {
+    return !CStringEquals(c_str_, c_str);
+  }
+
+  // Returns true iff this String ends with the given suffix.  *Any*
+  // String is considered to end with a NULL or empty suffix.
+  bool EndsWith(const char* suffix) const;
+
+  // Returns true iff this String ends with the given suffix, not considering
+  // case. Any String is considered to end with a NULL or empty suffix.
+  bool EndsWithCaseInsensitive(const char* suffix) const;
+
+  // Returns the length of the encapsulated string, or -1 if the
+  // string is NULL.
+  int GetLength() const {
+    return c_str_ ? static_cast<int>(strlen(c_str_)) : -1;
+  }
+
+  // Gets the 0-terminated C string this String object represents.
+  // The String object still owns the string.  Therefore the caller
+  // should NOT delete the return value.
+  const char* c_str() const { return c_str_; }
+
+  // Sets the 0-terminated C string this String object represents.
+  // The old string in this object is deleted, and this object will
+  // own a clone of the input string.  This function copies only up to
+  // length bytes (plus a terminating null byte), or until the first
+  // null byte, whichever comes first.
+  //
+  // This function works even when the c_str parameter has the same
+  // value as that of the c_str_ field.
+  void Set(const char* c_str, size_t length);
+
+  // Assigns a C string to this object.  Self-assignment works.
+  const String& operator=(const char* c_str);
+
+  // Assigns a String object to this object.  Self-assignment works.
+  const String& operator=(const String &rhs) {
+    *this = rhs.c_str_;
+    return *this;
+  }
+
+ private:
+  const char* c_str_;
+};
+
+// Streams a String to an ostream.
+inline ::std::ostream& operator <<(::std::ostream& os, const String& str) {
+  // We call String::ShowCString() to convert NULL to "(null)".
+  // Otherwise we'll get an access violation on Windows.
+  return os << String::ShowCString(str.c_str());
+}
+
+// Gets the content of the StrStream's buffer as a String.  Each '\0'
+// character in the buffer is replaced with "\\0".
+String StrStreamToString(StrStream* stream);
+
+// Converts a streamable value to a String.  A NULL pointer is
+// converted to "(null)".  When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+
+// Declared here but defined in gtest.h, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable);
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
diff --git a/third_party/gtest/include/gtest/internal/gtest-type-util.h b/third_party/gtest/include/gtest/internal/gtest-type-util.h
index 0fc6b9e..f1b1bed 100644
--- a/third_party/gtest/include/gtest/internal/gtest-type-util.h
+++ b/third_party/gtest/include/gtest/internal/gtest-type-util.h
@@ -1,3321 +1,3321 @@
-// This file was GENERATED by a script.  DO NOT EDIT BY HAND!!!

-

-// Copyright 2008 Google Inc.

-// All Rights Reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan)

-

-// Type utilities needed for implementing typed and type-parameterized

-// tests.  This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!

-//

-// Currently we support at most 50 types in a list, and at most 50

-// type-parameterized tests in one type-parameterized test case.

-// Please contact googletestframework@googlegroups.com if you need

-// more.

-

-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_

-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_

-

-#include <gtest/internal/gtest-port.h>

-#include <gtest/internal/gtest-string.h>

-

-#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P

-

-// #ifdef __GNUC__ is too general here.  It is possible to use gcc without using

-// libstdc++ (which is where cxxabi.h comes from).

-#ifdef __GLIBCXX__

-#include <cxxabi.h>

-#endif  // __GLIBCXX__

-

-#include <typeinfo>

-

-namespace testing {

-namespace internal {

-

-// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same

-// type.  This can be used as a compile-time assertion to ensure that

-// two types are equal.

-

-template <typename T1, typename T2>

-struct AssertTypeEq;

-

-template <typename T>

-struct AssertTypeEq<T, T> {

-  typedef bool type;

-};

-

-// GetTypeName<T>() returns a human-readable name of type T.

-template <typename T>

-String GetTypeName() {

-#if GTEST_HAS_RTTI

-

-  const char* const name = typeid(T).name();

-#ifdef __GLIBCXX__

-  int status = 0;

-  // gcc's implementation of typeid(T).name() mangles the type name,

-  // so we have to demangle it.

-  char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status);

-  const String name_str(status == 0 ? readable_name : name);

-  free(readable_name);

-  return name_str;

-#else

-  return name;

-#endif  // __GLIBCXX__

-

-#else

-  return "<type>";

-#endif  // GTEST_HAS_RTTI

-}

-

-// A unique type used as the default value for the arguments of class

-// template Types.  This allows us to simulate variadic templates

-// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't

-// support directly.

-struct None {};

-

-// The following family of struct and struct templates are used to

-// represent type lists.  In particular, TypesN<T1, T2, ..., TN>

-// represents a type list with N types (T1, T2, ..., and TN) in it.

-// Except for Types0, every struct in the family has two member types:

-// Head for the first type in the list, and Tail for the rest of the

-// list.

-

-// The empty type list.

-struct Types0 {};

-

-// Type lists of length 1, 2, 3, and so on.

-

-template <typename T1>

-struct Types1 {

-  typedef T1 Head;

-  typedef Types0 Tail;

-};

-template <typename T1, typename T2>

-struct Types2 {

-  typedef T1 Head;

-  typedef Types1<T2> Tail;

-};

-

-template <typename T1, typename T2, typename T3>

-struct Types3 {

-  typedef T1 Head;

-  typedef Types2<T2, T3> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4>

-struct Types4 {

-  typedef T1 Head;

-  typedef Types3<T2, T3, T4> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5>

-struct Types5 {

-  typedef T1 Head;

-  typedef Types4<T2, T3, T4, T5> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6>

-struct Types6 {

-  typedef T1 Head;

-  typedef Types5<T2, T3, T4, T5, T6> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7>

-struct Types7 {

-  typedef T1 Head;

-  typedef Types6<T2, T3, T4, T5, T6, T7> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8>

-struct Types8 {

-  typedef T1 Head;

-  typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9>

-struct Types9 {

-  typedef T1 Head;

-  typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10>

-struct Types10 {

-  typedef T1 Head;

-  typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11>

-struct Types11 {

-  typedef T1 Head;

-  typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12>

-struct Types12 {

-  typedef T1 Head;

-  typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13>

-struct Types13 {

-  typedef T1 Head;

-  typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14>

-struct Types14 {

-  typedef T1 Head;

-  typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15>

-struct Types15 {

-  typedef T1 Head;

-  typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16>

-struct Types16 {

-  typedef T1 Head;

-  typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17>

-struct Types17 {

-  typedef T1 Head;

-  typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18>

-struct Types18 {

-  typedef T1 Head;

-  typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19>

-struct Types19 {

-  typedef T1 Head;

-  typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20>

-struct Types20 {

-  typedef T1 Head;

-  typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21>

-struct Types21 {

-  typedef T1 Head;

-  typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22>

-struct Types22 {

-  typedef T1 Head;

-  typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23>

-struct Types23 {

-  typedef T1 Head;

-  typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24>

-struct Types24 {

-  typedef T1 Head;

-  typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25>

-struct Types25 {

-  typedef T1 Head;

-  typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26>

-struct Types26 {

-  typedef T1 Head;

-  typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27>

-struct Types27 {

-  typedef T1 Head;

-  typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28>

-struct Types28 {

-  typedef T1 Head;

-  typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29>

-struct Types29 {

-  typedef T1 Head;

-  typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30>

-struct Types30 {

-  typedef T1 Head;

-  typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31>

-struct Types31 {

-  typedef T1 Head;

-  typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32>

-struct Types32 {

-  typedef T1 Head;

-  typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33>

-struct Types33 {

-  typedef T1 Head;

-  typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34>

-struct Types34 {

-  typedef T1 Head;

-  typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35>

-struct Types35 {

-  typedef T1 Head;

-  typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36>

-struct Types36 {

-  typedef T1 Head;

-  typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37>

-struct Types37 {

-  typedef T1 Head;

-  typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38>

-struct Types38 {

-  typedef T1 Head;

-  typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39>

-struct Types39 {

-  typedef T1 Head;

-  typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40>

-struct Types40 {

-  typedef T1 Head;

-  typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41>

-struct Types41 {

-  typedef T1 Head;

-  typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42>

-struct Types42 {

-  typedef T1 Head;

-  typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43>

-struct Types43 {

-  typedef T1 Head;

-  typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,

-      T43> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44>

-struct Types44 {

-  typedef T1 Head;

-  typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-      T44> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45>

-struct Types45 {

-  typedef T1 Head;

-  typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-      T44, T45> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46>

-struct Types46 {

-  typedef T1 Head;

-  typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-      T44, T45, T46> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47>

-struct Types47 {

-  typedef T1 Head;

-  typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-      T44, T45, T46, T47> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48>

-struct Types48 {

-  typedef T1 Head;

-  typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-      T44, T45, T46, T47, T48> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48, typename T49>

-struct Types49 {

-  typedef T1 Head;

-  typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-      T44, T45, T46, T47, T48, T49> Tail;

-};

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48, typename T49, typename T50>

-struct Types50 {

-  typedef T1 Head;

-  typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-      T44, T45, T46, T47, T48, T49, T50> Tail;

-};

-

-

-}  // namespace internal

-

-// We don't want to require the users to write TypesN<...> directly,

-// as that would require them to count the length.  Types<...> is much

-// easier to write, but generates horrible messages when there is a

-// compiler error, as gcc insists on printing out each template

-// argument, even if it has the default value (this means Types<int>

-// will appear as Types<int, None, None, ..., None> in the compiler

-// errors).

-//

-// Our solution is to combine the best part of the two approaches: a

-// user would write Types<T1, ..., TN>, and Google Test will translate

-// that to TypesN<T1, ..., TN> internally to make error messages

-// readable.  The translation is done by the 'type' member of the

-// Types template.

-template <typename T1 = internal::None, typename T2 = internal::None,

-    typename T3 = internal::None, typename T4 = internal::None,

-    typename T5 = internal::None, typename T6 = internal::None,

-    typename T7 = internal::None, typename T8 = internal::None,

-    typename T9 = internal::None, typename T10 = internal::None,

-    typename T11 = internal::None, typename T12 = internal::None,

-    typename T13 = internal::None, typename T14 = internal::None,

-    typename T15 = internal::None, typename T16 = internal::None,

-    typename T17 = internal::None, typename T18 = internal::None,

-    typename T19 = internal::None, typename T20 = internal::None,

-    typename T21 = internal::None, typename T22 = internal::None,

-    typename T23 = internal::None, typename T24 = internal::None,

-    typename T25 = internal::None, typename T26 = internal::None,

-    typename T27 = internal::None, typename T28 = internal::None,

-    typename T29 = internal::None, typename T30 = internal::None,

-    typename T31 = internal::None, typename T32 = internal::None,

-    typename T33 = internal::None, typename T34 = internal::None,

-    typename T35 = internal::None, typename T36 = internal::None,

-    typename T37 = internal::None, typename T38 = internal::None,

-    typename T39 = internal::None, typename T40 = internal::None,

-    typename T41 = internal::None, typename T42 = internal::None,

-    typename T43 = internal::None, typename T44 = internal::None,

-    typename T45 = internal::None, typename T46 = internal::None,

-    typename T47 = internal::None, typename T48 = internal::None,

-    typename T49 = internal::None, typename T50 = internal::None>

-struct Types {

-  typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;

-};

-

-template <>

-struct Types<internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types0 type;

-};

-template <typename T1>

-struct Types<T1, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types1<T1> type;

-};

-template <typename T1, typename T2>

-struct Types<T1, T2, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types2<T1, T2> type;

-};

-template <typename T1, typename T2, typename T3>

-struct Types<T1, T2, T3, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types3<T1, T2, T3> type;

-};

-template <typename T1, typename T2, typename T3, typename T4>

-struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types4<T1, T2, T3, T4> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5>

-struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types5<T1, T2, T3, T4, T5> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6>

-struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7>

-struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,

-      T12> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,

-      T26> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,

-      T40> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41, T42> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None, internal::None> {

-  typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41, T42, T43> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None, internal::None> {

-  typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41, T42, T43, T44> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,

-    internal::None, internal::None, internal::None, internal::None,

-    internal::None> {

-  typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41, T42, T43, T44, T45> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,

-    T46, internal::None, internal::None, internal::None, internal::None> {

-  typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41, T42, T43, T44, T45, T46> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,

-    T46, T47, internal::None, internal::None, internal::None> {

-  typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41, T42, T43, T44, T45, T46, T47> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,

-    T46, T47, T48, internal::None, internal::None> {

-  typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41, T42, T43, T44, T45, T46, T47, T48> type;

-};

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48, typename T49>

-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,

-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,

-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,

-    T46, T47, T48, T49, internal::None> {

-  typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41, T42, T43, T44, T45, T46, T47, T48, T49> type;

-};

-

-namespace internal {

-

-#define GTEST_TEMPLATE_ template <typename T> class

-

-// The template "selector" struct TemplateSel<Tmpl> is used to

-// represent Tmpl, which must be a class template with one type

-// parameter, as a type.  TemplateSel<Tmpl>::Bind<T>::type is defined

-// as the type Tmpl<T>.  This allows us to actually instantiate the

-// template "selected" by TemplateSel<Tmpl>.

-//

-// This trick is necessary for simulating typedef for class templates,

-// which C++ doesn't support directly.

-template <GTEST_TEMPLATE_ Tmpl>

-struct TemplateSel {

-  template <typename T>

-  struct Bind {

-    typedef Tmpl<T> type;

-  };

-};

-

-#define GTEST_BIND_(TmplSel, T) \

-  TmplSel::template Bind<T>::type

-

-// A unique struct template used as the default value for the

-// arguments of class template Templates.  This allows us to simulate

-// variadic templates (e.g. Templates<int>, Templates<int, double>,

-// and etc), which C++ doesn't support directly.

-template <typename T>

-struct NoneT {};

-

-// The following family of struct and struct templates are used to

-// represent template lists.  In particular, TemplatesN<T1, T2, ...,

-// TN> represents a list of N templates (T1, T2, ..., and TN).  Except

-// for Templates0, every struct in the family has two member types:

-// Head for the selector of the first template in the list, and Tail

-// for the rest of the list.

-

-// The empty template list.

-struct Templates0 {};

-

-// Template lists of length 1, 2, 3, and so on.

-

-template <GTEST_TEMPLATE_ T1>

-struct Templates1 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates0 Tail;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>

-struct Templates2 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates1<T2> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>

-struct Templates3 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates2<T2, T3> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4>

-struct Templates4 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates3<T2, T3, T4> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>

-struct Templates5 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates4<T2, T3, T4, T5> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>

-struct Templates6 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates5<T2, T3, T4, T5, T6> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7>

-struct Templates7 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>

-struct Templates8 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>

-struct Templates9 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10>

-struct Templates10 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>

-struct Templates11 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>

-struct Templates12 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13>

-struct Templates13 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>

-struct Templates14 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>

-struct Templates15 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16>

-struct Templates16 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>

-struct Templates17 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>

-struct Templates18 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19>

-struct Templates19 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>

-struct Templates20 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>

-struct Templates21 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22>

-struct Templates22 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>

-struct Templates23 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>

-struct Templates24 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25>

-struct Templates25 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>

-struct Templates26 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>

-struct Templates27 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28>

-struct Templates28 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>

-struct Templates29 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>

-struct Templates30 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31>

-struct Templates31 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>

-struct Templates32 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>

-struct Templates33 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34>

-struct Templates34 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>

-struct Templates35 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>

-struct Templates36 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37>

-struct Templates37 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>

-struct Templates38 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>

-struct Templates39 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40>

-struct Templates40 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>

-struct Templates41 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>

-struct Templates42 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-      T42> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43>

-struct Templates43 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,

-      T43> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>

-struct Templates44 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,

-      T43, T44> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>

-struct Templates45 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,

-      T43, T44, T45> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,

-    GTEST_TEMPLATE_ T46>

-struct Templates46 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,

-      T43, T44, T45, T46> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,

-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>

-struct Templates47 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,

-      T43, T44, T45, T46, T47> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,

-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>

-struct Templates48 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,

-      T43, T44, T45, T46, T47, T48> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,

-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,

-    GTEST_TEMPLATE_ T49>

-struct Templates49 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,

-      T43, T44, T45, T46, T47, T48, T49> Tail;

-};

-

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,

-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,

-    GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>

-struct Templates50 {

-  typedef TemplateSel<T1> Head;

-  typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,

-      T43, T44, T45, T46, T47, T48, T49, T50> Tail;

-};

-

-

-// We don't want to require the users to write TemplatesN<...> directly,

-// as that would require them to count the length.  Templates<...> is much

-// easier to write, but generates horrible messages when there is a

-// compiler error, as gcc insists on printing out each template

-// argument, even if it has the default value (this means Templates<list>

-// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler

-// errors).

-//

-// Our solution is to combine the best part of the two approaches: a

-// user would write Templates<T1, ..., TN>, and Google Test will translate

-// that to TemplatesN<T1, ..., TN> internally to make error messages

-// readable.  The translation is done by the 'type' member of the

-// Templates template.

-template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,

-    GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,

-    GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,

-    GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,

-    GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,

-    GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,

-    GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,

-    GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,

-    GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,

-    GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,

-    GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,

-    GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,

-    GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,

-    GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,

-    GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,

-    GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,

-    GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,

-    GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,

-    GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,

-    GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,

-    GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,

-    GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,

-    GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,

-    GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,

-    GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>

-struct Templates {

-  typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-      T42, T43, T44, T45, T46, T47, T48, T49, T50> type;

-};

-

-template <>

-struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT> {

-  typedef Templates0 type;

-};

-template <GTEST_TEMPLATE_ T1>

-struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT> {

-  typedef Templates1<T1> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>

-struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT> {

-  typedef Templates2<T1, T2> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>

-struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates3<T1, T2, T3> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4>

-struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates4<T1, T2, T3, T4> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>

-struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates5<T1, T2, T3, T4, T5> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>

-struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates6<T1, T2, T3, T4, T5, T6> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT> {

-  typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT> {

-  typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT> {

-  typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT> {

-  typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT> {

-  typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT> {

-  typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT> {

-  typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT> {

-  typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-      T42> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-      T42, T43> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,

-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-      T42, T43, T44> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,

-    T45, NoneT, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-      T42, T43, T44, T45> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,

-    GTEST_TEMPLATE_ T46>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,

-    T45, T46, NoneT, NoneT, NoneT, NoneT> {

-  typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-      T42, T43, T44, T45, T46> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,

-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,

-    T45, T46, T47, NoneT, NoneT, NoneT> {

-  typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-      T42, T43, T44, T45, T46, T47> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,

-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,

-    T45, T46, T47, T48, NoneT, NoneT> {

-  typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-      T42, T43, T44, T45, T46, T47, T48> type;

-};

-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,

-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,

-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,

-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,

-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,

-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,

-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,

-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,

-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,

-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,

-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,

-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,

-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,

-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,

-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,

-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,

-    GTEST_TEMPLATE_ T49>

-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,

-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,

-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,

-    T45, T46, T47, T48, T49, NoneT> {

-  typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,

-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,

-      T42, T43, T44, T45, T46, T47, T48, T49> type;

-};

-

-// The TypeList template makes it possible to use either a single type

-// or a Types<...> list in TYPED_TEST_CASE() and

-// INSTANTIATE_TYPED_TEST_CASE_P().

-

-template <typename T>

-struct TypeList { typedef Types1<T> type; };

-

-template <typename T1, typename T2, typename T3, typename T4, typename T5,

-    typename T6, typename T7, typename T8, typename T9, typename T10,

-    typename T11, typename T12, typename T13, typename T14, typename T15,

-    typename T16, typename T17, typename T18, typename T19, typename T20,

-    typename T21, typename T22, typename T23, typename T24, typename T25,

-    typename T26, typename T27, typename T28, typename T29, typename T30,

-    typename T31, typename T32, typename T33, typename T34, typename T35,

-    typename T36, typename T37, typename T38, typename T39, typename T40,

-    typename T41, typename T42, typename T43, typename T44, typename T45,

-    typename T46, typename T47, typename T48, typename T49, typename T50>

-struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,

-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,

-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,

-    T44, T45, T46, T47, T48, T49, T50> > {

-  typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,

-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,

-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,

-      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;

-};

-

-}  // namespace internal

-}  // namespace testing

-

-#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P

-

-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_

+// This file was GENERATED by a script.  DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests.  This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
+//
+// Currently we support at most 50 types in a list, and at most 50
+// type-parameterized tests in one type-parameterized test case.
+// Please contact googletestframework@googlegroups.com if you need
+// more.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+#include <gtest/internal/gtest-port.h>
+#include <gtest/internal/gtest-string.h>
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// #ifdef __GNUC__ is too general here.  It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+#ifdef __GLIBCXX__
+#include <cxxabi.h>
+#endif  // __GLIBCXX__
+
+#include <typeinfo>
+
+namespace testing {
+namespace internal {
+
+// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
+// type.  This can be used as a compile-time assertion to ensure that
+// two types are equal.
+
+template <typename T1, typename T2>
+struct AssertTypeEq;
+
+template <typename T>
+struct AssertTypeEq<T, T> {
+  typedef bool type;
+};
+
+// GetTypeName<T>() returns a human-readable name of type T.
+template <typename T>
+String GetTypeName() {
+#if GTEST_HAS_RTTI
+
+  const char* const name = typeid(T).name();
+#ifdef __GLIBCXX__
+  int status = 0;
+  // gcc's implementation of typeid(T).name() mangles the type name,
+  // so we have to demangle it.
+  char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status);
+  const String name_str(status == 0 ? readable_name : name);
+  free(readable_name);
+  return name_str;
+#else
+  return name;
+#endif  // __GLIBCXX__
+
+#else
+  return "<type>";
+#endif  // GTEST_HAS_RTTI
+}
+
+// A unique type used as the default value for the arguments of class
+// template Types.  This allows us to simulate variadic templates
+// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
+// support directly.
+struct None {};
+
+// The following family of struct and struct templates are used to
+// represent type lists.  In particular, TypesN<T1, T2, ..., TN>
+// represents a type list with N types (T1, T2, ..., and TN) in it.
+// Except for Types0, every struct in the family has two member types:
+// Head for the first type in the list, and Tail for the rest of the
+// list.
+
+// The empty type list.
+struct Types0 {};
+
+// Type lists of length 1, 2, 3, and so on.
+
+template <typename T1>
+struct Types1 {
+  typedef T1 Head;
+  typedef Types0 Tail;
+};
+template <typename T1, typename T2>
+struct Types2 {
+  typedef T1 Head;
+  typedef Types1<T2> Tail;
+};
+
+template <typename T1, typename T2, typename T3>
+struct Types3 {
+  typedef T1 Head;
+  typedef Types2<T2, T3> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types4 {
+  typedef T1 Head;
+  typedef Types3<T2, T3, T4> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types5 {
+  typedef T1 Head;
+  typedef Types4<T2, T3, T4, T5> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+struct Types6 {
+  typedef T1 Head;
+  typedef Types5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+struct Types7 {
+  typedef T1 Head;
+  typedef Types6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+struct Types8 {
+  typedef T1 Head;
+  typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+struct Types9 {
+  typedef T1 Head;
+  typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types10 {
+  typedef T1 Head;
+  typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+struct Types11 {
+  typedef T1 Head;
+  typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+struct Types12 {
+  typedef T1 Head;
+  typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+struct Types13 {
+  typedef T1 Head;
+  typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+struct Types14 {
+  typedef T1 Head;
+  typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types15 {
+  typedef T1 Head;
+  typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+struct Types16 {
+  typedef T1 Head;
+  typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+struct Types17 {
+  typedef T1 Head;
+  typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+struct Types18 {
+  typedef T1 Head;
+  typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+struct Types19 {
+  typedef T1 Head;
+  typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types20 {
+  typedef T1 Head;
+  typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+struct Types21 {
+  typedef T1 Head;
+  typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+struct Types22 {
+  typedef T1 Head;
+  typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+struct Types23 {
+  typedef T1 Head;
+  typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+struct Types24 {
+  typedef T1 Head;
+  typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types25 {
+  typedef T1 Head;
+  typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+struct Types26 {
+  typedef T1 Head;
+  typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+struct Types27 {
+  typedef T1 Head;
+  typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+struct Types28 {
+  typedef T1 Head;
+  typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+struct Types29 {
+  typedef T1 Head;
+  typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types30 {
+  typedef T1 Head;
+  typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+struct Types31 {
+  typedef T1 Head;
+  typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+struct Types32 {
+  typedef T1 Head;
+  typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+struct Types33 {
+  typedef T1 Head;
+  typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+struct Types34 {
+  typedef T1 Head;
+  typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types35 {
+  typedef T1 Head;
+  typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+struct Types36 {
+  typedef T1 Head;
+  typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+struct Types37 {
+  typedef T1 Head;
+  typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+struct Types38 {
+  typedef T1 Head;
+  typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+struct Types39 {
+  typedef T1 Head;
+  typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types40 {
+  typedef T1 Head;
+  typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+struct Types41 {
+  typedef T1 Head;
+  typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+struct Types42 {
+  typedef T1 Head;
+  typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+struct Types43 {
+  typedef T1 Head;
+  typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+struct Types44 {
+  typedef T1 Head;
+  typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types45 {
+  typedef T1 Head;
+  typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+struct Types46 {
+  typedef T1 Head;
+  typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+struct Types47 {
+  typedef T1 Head;
+  typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+struct Types48 {
+  typedef T1 Head;
+  typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47, T48> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+struct Types49 {
+  typedef T1 Head;
+  typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+struct Types50 {
+  typedef T1 Head;
+  typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+      T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+}  // namespace internal
+
+// We don't want to require the users to write TypesN<...> directly,
+// as that would require them to count the length.  Types<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Types<int>
+// will appear as Types<int, None, None, ..., None> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Types<T1, ..., TN>, and Google Test will translate
+// that to TypesN<T1, ..., TN> internally to make error messages
+// readable.  The translation is done by the 'type' member of the
+// Types template.
+template <typename T1 = internal::None, typename T2 = internal::None,
+    typename T3 = internal::None, typename T4 = internal::None,
+    typename T5 = internal::None, typename T6 = internal::None,
+    typename T7 = internal::None, typename T8 = internal::None,
+    typename T9 = internal::None, typename T10 = internal::None,
+    typename T11 = internal::None, typename T12 = internal::None,
+    typename T13 = internal::None, typename T14 = internal::None,
+    typename T15 = internal::None, typename T16 = internal::None,
+    typename T17 = internal::None, typename T18 = internal::None,
+    typename T19 = internal::None, typename T20 = internal::None,
+    typename T21 = internal::None, typename T22 = internal::None,
+    typename T23 = internal::None, typename T24 = internal::None,
+    typename T25 = internal::None, typename T26 = internal::None,
+    typename T27 = internal::None, typename T28 = internal::None,
+    typename T29 = internal::None, typename T30 = internal::None,
+    typename T31 = internal::None, typename T32 = internal::None,
+    typename T33 = internal::None, typename T34 = internal::None,
+    typename T35 = internal::None, typename T36 = internal::None,
+    typename T37 = internal::None, typename T38 = internal::None,
+    typename T39 = internal::None, typename T40 = internal::None,
+    typename T41 = internal::None, typename T42 = internal::None,
+    typename T43 = internal::None, typename T44 = internal::None,
+    typename T45 = internal::None, typename T46 = internal::None,
+    typename T47 = internal::None, typename T48 = internal::None,
+    typename T49 = internal::None, typename T50 = internal::None>
+struct Types {
+  typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Types<internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types0 type;
+};
+template <typename T1>
+struct Types<T1, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types1<T1> type;
+};
+template <typename T1, typename T2>
+struct Types<T1, T2, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types2<T1, T2> type;
+};
+template <typename T1, typename T2, typename T3>
+struct Types<T1, T2, T3, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types3<T1, T2, T3> type;
+};
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types4<T1, T2, T3, T4> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types5<T1, T2, T3, T4, T5> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6>
+struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7>
+struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+      T12> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+      T26> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+      T40> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None, internal::None> {
+  typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None, internal::None> {
+  typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    internal::None, internal::None, internal::None, internal::None,
+    internal::None> {
+  typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, internal::None, internal::None, internal::None, internal::None> {
+  typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, T47, internal::None, internal::None, internal::None> {
+  typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, T47, T48, internal::None, internal::None> {
+  typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+    T46, T47, T48, T49, internal::None> {
+  typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+namespace internal {
+
+#define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type.  TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>.  This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+  template <typename T>
+  struct Bind {
+    typedef Tmpl<T> type;
+  };
+};
+
+#define GTEST_BIND_(TmplSel, T) \
+  TmplSel::template Bind<T>::type
+
+// A unique struct template used as the default value for the
+// arguments of class template Templates.  This allows us to simulate
+// variadic templates (e.g. Templates<int>, Templates<int, double>,
+// and etc), which C++ doesn't support directly.
+template <typename T>
+struct NoneT {};
+
+// The following family of struct and struct templates are used to
+// represent template lists.  In particular, TemplatesN<T1, T2, ...,
+// TN> represents a list of N templates (T1, T2, ..., and TN).  Except
+// for Templates0, every struct in the family has two member types:
+// Head for the selector of the first template in the list, and Tail
+// for the rest of the list.
+
+// The empty template list.
+struct Templates0 {};
+
+// Template lists of length 1, 2, 3, and so on.
+
+template <GTEST_TEMPLATE_ T1>
+struct Templates1 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates0 Tail;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates2 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates1<T2> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates3 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates2<T2, T3> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4>
+struct Templates4 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates3<T2, T3, T4> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates5 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates4<T2, T3, T4, T5> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates6 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7>
+struct Templates7 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates8 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates9 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10>
+struct Templates10 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates11 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates12 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13>
+struct Templates13 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates14 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates15 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16>
+struct Templates16 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates17 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates18 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19>
+struct Templates19 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates20 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates21 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22>
+struct Templates22 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates23 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates24 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25>
+struct Templates25 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates26 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates27 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28>
+struct Templates28 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates29 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates30 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31>
+struct Templates31 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates32 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates33 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34>
+struct Templates34 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates35 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates36 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37>
+struct Templates37 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates38 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates39 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40>
+struct Templates40 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates41 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates42 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43>
+struct Templates43 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates44 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates45 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46>
+struct Templates46 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates47 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates48 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47, T48> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+    GTEST_TEMPLATE_ T49>
+struct Templates49 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+    GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>
+struct Templates50 {
+  typedef TemplateSel<T1> Head;
+  typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+      T43, T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+// We don't want to require the users to write TemplatesN<...> directly,
+// as that would require them to count the length.  Templates<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Templates<list>
+// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Templates<T1, ..., TN>, and Google Test will translate
+// that to TemplatesN<T1, ..., TN> internally to make error messages
+// readable.  The translation is done by the 'type' member of the
+// Templates template.
+template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,
+    GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,
+    GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,
+    GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,
+    GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,
+    GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,
+    GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,
+    GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,
+    GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,
+    GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,
+    GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,
+    GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,
+    GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,
+    GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,
+    GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,
+    GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,
+    GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,
+    GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,
+    GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,
+    GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,
+    GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,
+    GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,
+    GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,
+    GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,
+    GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>
+struct Templates {
+  typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates0 type;
+};
+template <GTEST_TEMPLATE_ T1>
+struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates1<T1> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates2<T1, T2> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates3<T1, T2, T3> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4>
+struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates4<T1, T2, T3, T4> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates5<T1, T2, T3, T4, T5> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates6<T1, T2, T3, T4, T5, T6> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT> {
+  typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT> {
+  typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT> {
+  typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT> {
+  typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT> {
+  typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, NoneT, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, NoneT, NoneT, NoneT, NoneT> {
+  typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, T47, NoneT, NoneT, NoneT> {
+  typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, T47, T48, NoneT, NoneT> {
+  typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+    GTEST_TEMPLATE_ T49>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+    T45, T46, T47, T48, T49, NoneT> {
+  typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+      T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+// The TypeList template makes it possible to use either a single type
+// or a Types<...> list in TYPED_TEST_CASE() and
+// INSTANTIATE_TYPED_TEST_CASE_P().
+
+template <typename T>
+struct TypeList { typedef Types1<T> type; };
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+    typename T6, typename T7, typename T8, typename T9, typename T10,
+    typename T11, typename T12, typename T13, typename T14, typename T15,
+    typename T16, typename T17, typename T18, typename T19, typename T20,
+    typename T21, typename T22, typename T23, typename T24, typename T25,
+    typename T26, typename T27, typename T28, typename T29, typename T30,
+    typename T31, typename T32, typename T33, typename T34, typename T35,
+    typename T36, typename T37, typename T38, typename T39, typename T40,
+    typename T41, typename T42, typename T43, typename T44, typename T45,
+    typename T46, typename T47, typename T48, typename T49, typename T50>
+struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+    T44, T45, T46, T47, T48, T49, T50> > {
+  typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
+};
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
diff --git a/third_party/gtest/src/gtest-death-test.cc b/third_party/gtest/src/gtest-death-test.cc
index a1894d3..0d4110b 100644
--- a/third_party/gtest/src/gtest-death-test.cc
+++ b/third_party/gtest/src/gtest-death-test.cc
@@ -1,1177 +1,1177 @@
-// Copyright 2005, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev)

-//

-// This file implements death tests.

-

-#include <gtest/gtest-death-test.h>

-#include <gtest/internal/gtest-port.h>

-

-#if GTEST_HAS_DEATH_TEST

-

-#if GTEST_OS_MAC

-#include <crt_externs.h>

-#endif  // GTEST_OS_MAC

-

-#include <errno.h>

-#include <fcntl.h>

-#include <limits.h>

-#include <stdarg.h>

-

-#if GTEST_OS_WINDOWS

-#include <windows.h>

-#else

-#include <sys/mman.h>

-#include <sys/wait.h>

-#endif  // GTEST_OS_WINDOWS

-

-#endif  // GTEST_HAS_DEATH_TEST

-

-#include <gtest/gtest-message.h>

-#include <gtest/internal/gtest-string.h>

-

-// Indicates that this translation unit is part of Google Test's

-// implementation.  It must come before gtest-internal-inl.h is

-// included, or there will be a compiler error.  This trick is to

-// prevent a user from accidentally including gtest-internal-inl.h in

-// his code.

-#define GTEST_IMPLEMENTATION_ 1

-#include "src/gtest-internal-inl.h"

-#undef GTEST_IMPLEMENTATION_

-

-namespace testing {

-

-// Constants.

-

-// The default death test style.

-static const char kDefaultDeathTestStyle[] = "fast";

-

-GTEST_DEFINE_string_(

-    death_test_style,

-    internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),

-    "Indicates how to run a death test in a forked child process: "

-    "\"threadsafe\" (child process re-executes the test binary "

-    "from the beginning, running only the specific death test) or "

-    "\"fast\" (child process runs the death test immediately "

-    "after forking).");

-

-GTEST_DEFINE_bool_(

-    death_test_use_fork,

-    internal::BoolFromGTestEnv("death_test_use_fork", false),

-    "Instructs to use fork()/_exit() instead of clone() in death tests. "

-    "Ignored and always uses fork() on POSIX systems where clone() is not "

-    "implemented. Useful when running under valgrind or similar tools if "

-    "those do not support clone(). Valgrind 3.3.1 will just fail if "

-    "it sees an unsupported combination of clone() flags. "

-    "It is not recommended to use this flag w/o valgrind though it will "

-    "work in 99% of the cases. Once valgrind is fixed, this flag will "

-    "most likely be removed.");

-

-namespace internal {

-GTEST_DEFINE_string_(

-    internal_run_death_test, "",

-    "Indicates the file, line number, temporal index of "

-    "the single death test to run, and a file descriptor to "

-    "which a success code may be sent, all separated by "

-    "colons.  This flag is specified if and only if the current "

-    "process is a sub-process launched for running a thread-safe "

-    "death test.  FOR INTERNAL USE ONLY.");

-}  // namespace internal

-

-#if GTEST_HAS_DEATH_TEST

-

-// ExitedWithCode constructor.

-ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {

-}

-

-// ExitedWithCode function-call operator.

-bool ExitedWithCode::operator()(int exit_status) const {

-#if GTEST_OS_WINDOWS

-  return exit_status == exit_code_;

-#else

-  return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;

-#endif  // GTEST_OS_WINDOWS

-}

-

-#if !GTEST_OS_WINDOWS

-// KilledBySignal constructor.

-KilledBySignal::KilledBySignal(int signum) : signum_(signum) {

-}

-

-// KilledBySignal function-call operator.

-bool KilledBySignal::operator()(int exit_status) const {

-  return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;

-}

-#endif  // !GTEST_OS_WINDOWS

-

-namespace internal {

-

-// Utilities needed for death tests.

-

-// Generates a textual description of a given exit code, in the format

-// specified by wait(2).

-static String ExitSummary(int exit_code) {

-  Message m;

-#if GTEST_OS_WINDOWS

-  m << "Exited with exit status " << exit_code;

-#else

-  if (WIFEXITED(exit_code)) {

-    m << "Exited with exit status " << WEXITSTATUS(exit_code);

-  } else if (WIFSIGNALED(exit_code)) {

-    m << "Terminated by signal " << WTERMSIG(exit_code);

-  }

-#ifdef WCOREDUMP

-  if (WCOREDUMP(exit_code)) {

-    m << " (core dumped)";

-  }

-#endif

-#endif  // GTEST_OS_WINDOWS

-  return m.GetString();

-}

-

-// Returns true if exit_status describes a process that was terminated

-// by a signal, or exited normally with a nonzero exit code.

-bool ExitedUnsuccessfully(int exit_status) {

-  return !ExitedWithCode(0)(exit_status);

-}

-

-#if !GTEST_OS_WINDOWS

-// Generates a textual failure message when a death test finds more than

-// one thread running, or cannot determine the number of threads, prior

-// to executing the given statement.  It is the responsibility of the

-// caller not to pass a thread_count of 1.

-static String DeathTestThreadWarning(size_t thread_count) {

-  Message msg;

-  msg << "Death tests use fork(), which is unsafe particularly"

-      << " in a threaded context. For this test, " << GTEST_NAME_ << " ";

-  if (thread_count == 0)

-    msg << "couldn't detect the number of threads.";

-  else

-    msg << "detected " << thread_count << " threads.";

-  return msg.GetString();

-}

-#endif  // !GTEST_OS_WINDOWS

-

-// Flag characters for reporting a death test that did not die.

-static const char kDeathTestLived = 'L';

-static const char kDeathTestReturned = 'R';

-static const char kDeathTestInternalError = 'I';

-

-// An enumeration describing all of the possible ways that a death test

-// can conclude.  DIED means that the process died while executing the

-// test code; LIVED means that process lived beyond the end of the test

-// code; and RETURNED means that the test statement attempted a "return,"

-// which is not allowed.  IN_PROGRESS means the test has not yet

-// concluded.

-enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED };

-

-// Routine for aborting the program which is safe to call from an

-// exec-style death test child process, in which case the error

-// message is propagated back to the parent process.  Otherwise, the

-// message is simply printed to stderr.  In either case, the program

-// then exits with status 1.

-void DeathTestAbort(const String& message) {

-  // On a POSIX system, this function may be called from a threadsafe-style

-  // death test child process, which operates on a very small stack.  Use

-  // the heap for any additional non-minuscule memory requirements.

-  const InternalRunDeathTestFlag* const flag =

-      GetUnitTestImpl()->internal_run_death_test_flag();

-  if (flag != NULL) {

-    FILE* parent = posix::FDOpen(flag->write_fd(), "w");

-    fputc(kDeathTestInternalError, parent);

-    fprintf(parent, "%s", message.c_str());

-    fflush(parent);

-    _exit(1);

-  } else {

-    fprintf(stderr, "%s", message.c_str());

-    fflush(stderr);

-    abort();

-  }

-}

-

-// A replacement for CHECK that calls DeathTestAbort if the assertion

-// fails.

-#define GTEST_DEATH_TEST_CHECK_(expression) \

-  do { \

-    if (!(expression)) { \

-      DeathTestAbort(::testing::internal::String::Format(\

-          "CHECK failed: File %s, line %d: %s", \

-          __FILE__, __LINE__, #expression)); \

-    } \

-  } while (0)

-

-// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for

-// evaluating any system call that fulfills two conditions: it must return

-// -1 on failure, and set errno to EINTR when it is interrupted and

-// should be tried again.  The macro expands to a loop that repeatedly

-// evaluates the expression as long as it evaluates to -1 and sets

-// errno to EINTR.  If the expression evaluates to -1 but errno is

-// something other than EINTR, DeathTestAbort is called.

-#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \

-  do { \

-    int gtest_retval; \

-    do { \

-      gtest_retval = (expression); \

-    } while (gtest_retval == -1 && errno == EINTR); \

-    if (gtest_retval == -1) { \

-      DeathTestAbort(::testing::internal::String::Format(\

-          "CHECK failed: File %s, line %d: %s != -1", \

-          __FILE__, __LINE__, #expression)); \

-    } \

-  } while (0)

-

-// Returns the message describing the last system error in errno.

-String GetLastErrnoDescription() {

-    return String(errno == 0 ? "" : posix::StrError(errno));

-}

-

-// This is called from a death test parent process to read a failure

-// message from the death test child process and log it with the FATAL

-// severity. On Windows, the message is read from a pipe handle. On other

-// platforms, it is read from a file descriptor.

-static void FailFromInternalError(int fd) {

-  Message error;

-  char buffer[256];

-  int num_read;

-

-  do {

-    while ((num_read = posix::Read(fd, buffer, 255)) > 0) {

-      buffer[num_read] = '\0';

-      error << buffer;

-    }

-  } while (num_read == -1 && errno == EINTR);

-

-  if (num_read == 0) {

-    GTEST_LOG_(FATAL, error);

-  } else {

-    const int last_error = errno;

-    const String message = GetLastErrnoDescription();

-    GTEST_LOG_(FATAL,

-               Message() << "Error while reading death test internal: "

-               << message << " [" << last_error << "]");

-  }

-}

-

-// Death test constructor.  Increments the running death test count

-// for the current test.

-DeathTest::DeathTest() {

-  TestInfo* const info = GetUnitTestImpl()->current_test_info();

-  if (info == NULL) {

-    DeathTestAbort("Cannot run a death test outside of a TEST or "

-                   "TEST_F construct");

-  }

-}

-

-// Creates and returns a death test by dispatching to the current

-// death test factory.

-bool DeathTest::Create(const char* statement, const RE* regex,

-                       const char* file, int line, DeathTest** test) {

-  return GetUnitTestImpl()->death_test_factory()->Create(

-      statement, regex, file, line, test);

-}

-

-const char* DeathTest::LastMessage() {

-  return last_death_test_message_.c_str();

-}

-

-void DeathTest::set_last_death_test_message(const String& message) {

-  last_death_test_message_ = message;

-}

-

-String DeathTest::last_death_test_message_;

-

-// Provides cross platform implementation for some death functionality.

-class DeathTestImpl : public DeathTest {

- protected:

-  DeathTestImpl(const char* statement, const RE* regex)

-      : statement_(statement),

-        regex_(regex),

-        spawned_(false),

-        status_(-1),

-        outcome_(IN_PROGRESS),

-        read_fd_(-1),

-        write_fd_(-1) {}

-

-  // read_fd_ is expected to be closed and cleared by a derived class.

-  ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }

-

-  void Abort(AbortReason reason);

-  virtual bool Passed(bool status_ok);

-

-  const char* statement() const { return statement_; }

-  const RE* regex() const { return regex_; }

-  bool spawned() const { return spawned_; }

-  void set_spawned(bool spawned) { spawned_ = spawned; }

-  int status() const { return status_; }

-  void set_status(int status) { status_ = status; }

-  DeathTestOutcome outcome() const { return outcome_; }

-  void set_outcome(DeathTestOutcome outcome) { outcome_ = outcome; }

-  int read_fd() const { return read_fd_; }

-  void set_read_fd(int fd) { read_fd_ = fd; }

-  int write_fd() const { return write_fd_; }

-  void set_write_fd(int fd) { write_fd_ = fd; }

-

-  // Called in the parent process only. Reads the result code of the death

-  // test child process via a pipe, interprets it to set the outcome_

-  // member, and closes read_fd_.  Outputs diagnostics and terminates in

-  // case of unexpected codes.

-  void ReadAndInterpretStatusByte();

-

- private:

-  // The textual content of the code this object is testing.  This class

-  // doesn't own this string and should not attempt to delete it.

-  const char* const statement_;

-  // The regular expression which test output must match.  DeathTestImpl

-  // doesn't own this object and should not attempt to delete it.

-  const RE* const regex_;

-  // True if the death test child process has been successfully spawned.

-  bool spawned_;

-  // The exit status of the child process.

-  int status_;

-  // How the death test concluded.

-  DeathTestOutcome outcome_;

-  // Descriptor to the read end of the pipe to the child process.  It is

-  // always -1 in the child process.  The child keeps its write end of the

-  // pipe in write_fd_.

-  int read_fd_;

-  // Descriptor to the child's write end of the pipe to the parent process.

-  // It is always -1 in the parent process.  The parent keeps its end of the

-  // pipe in read_fd_.

-  int write_fd_;

-};

-

-// Called in the parent process only. Reads the result code of the death

-// test child process via a pipe, interprets it to set the outcome_

-// member, and closes read_fd_.  Outputs diagnostics and terminates in

-// case of unexpected codes.

-void DeathTestImpl::ReadAndInterpretStatusByte() {

-  char flag;

-  int bytes_read;

-

-  // The read() here blocks until data is available (signifying the

-  // failure of the death test) or until the pipe is closed (signifying

-  // its success), so it's okay to call this in the parent before

-  // the child process has exited.

-  do {

-    bytes_read = posix::Read(read_fd(), &flag, 1);

-  } while (bytes_read == -1 && errno == EINTR);

-

-  if (bytes_read == 0) {

-    set_outcome(DIED);

-  } else if (bytes_read == 1) {

-    switch (flag) {

-      case kDeathTestReturned:

-        set_outcome(RETURNED);

-        break;

-      case kDeathTestLived:

-        set_outcome(LIVED);

-        break;

-      case kDeathTestInternalError:

-        FailFromInternalError(read_fd());  // Does not return.

-        break;

-      default:

-        GTEST_LOG_(FATAL,

-                   Message() << "Death test child process reported "

-                   << "unexpected status byte ("

-                   << static_cast<unsigned int>(flag) << ")");

-    }

-  } else {

-    GTEST_LOG_(FATAL,

-               Message() << "Read from death test child process failed: "

-                         << GetLastErrnoDescription());

-  }

-  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));

-  set_read_fd(-1);

-}

-

-// Signals that the death test code which should have exited, didn't.

-// Should be called only in a death test child process.

-// Writes a status byte to the child's status file descriptor, then

-// calls _exit(1).

-void DeathTestImpl::Abort(AbortReason reason) {

-  // The parent process considers the death test to be a failure if

-  // it finds any data in our pipe.  So, here we write a single flag byte

-  // to the pipe, then exit.

-  const char status_ch =

-      reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;

-  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));

-  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd()));

-  _exit(1);  // Exits w/o any normal exit hooks (we were supposed to crash)

-}

-

-// Assesses the success or failure of a death test, using both private

-// members which have previously been set, and one argument:

-//

-// Private data members:

-//   outcome:  An enumeration describing how the death test

-//             concluded: DIED, LIVED, or RETURNED.  The death test fails

-//             in the latter two cases.

-//   status:   The exit status of the child process. On *nix, it is in the

-//             in the format specified by wait(2). On Windows, this is the

-//             value supplied to the ExitProcess() API or a numeric code

-//             of the exception that terminated the program.

-//   regex:    A regular expression object to be applied to

-//             the test's captured standard error output; the death test

-//             fails if it does not match.

-//

-// Argument:

-//   status_ok: true if exit_status is acceptable in the context of

-//              this particular death test, which fails if it is false

-//

-// Returns true iff all of the above conditions are met.  Otherwise, the

-// first failing condition, in the order given above, is the one that is

-// reported. Also sets the last death test message string.

-bool DeathTestImpl::Passed(bool status_ok) {

-  if (!spawned())

-    return false;

-

-#if GTEST_HAS_GLOBAL_STRING

-  const ::string error_message = GetCapturedStderr();

-#else

-  const ::std::string error_message = GetCapturedStderr();

-#endif  // GTEST_HAS_GLOBAL_STRING

-

-  bool success = false;

-  Message buffer;

-

-  buffer << "Death test: " << statement() << "\n";

-  switch (outcome()) {

-    case LIVED:

-      buffer << "    Result: failed to die.\n"

-             << " Error msg: " << error_message;

-      break;

-    case RETURNED:

-      buffer << "    Result: illegal return in test statement.\n"

-             << " Error msg: " << error_message;

-      break;

-    case DIED:

-      if (status_ok) {

-        if (RE::PartialMatch(error_message, *regex())) {

-          success = true;

-        } else {

-          buffer << "    Result: died but not with expected error.\n"

-                 << "  Expected: " << regex()->pattern() << "\n"

-                 << "Actual msg: " << error_message;

-        }

-      } else {

-        buffer << "    Result: died but not with expected exit code:\n"

-               << "            " << ExitSummary(status()) << "\n";

-      }

-      break;

-    case IN_PROGRESS:

-    default:

-      GTEST_LOG_(FATAL,

-                 "DeathTest::Passed somehow called before conclusion of test");

-  }

-

-  DeathTest::set_last_death_test_message(buffer.GetString());

-  return success;

-}

-

-#if GTEST_OS_WINDOWS

-// WindowsDeathTest implements death tests on Windows. Due to the

-// specifics of starting new processes on Windows, death tests there are

-// always threadsafe, and Google Test considers the

-// --gtest_death_test_style=fast setting to be equivalent to

-// --gtest_death_test_style=threadsafe there.

-//

-// A few implementation notes:  Like the Linux version, the Windows

-// implementation uses pipes for child-to-parent communication. But due to

-// the specifics of pipes on Windows, some extra steps are required:

-//

-// 1. The parent creates a communication pipe and stores handles to both

-//    ends of it.

-// 2. The parent starts the child and provides it with the information

-//    necessary to acquire the handle to the write end of the pipe.

-// 3. The child acquires the write end of the pipe and signals the parent

-//    using a Windows event.

-// 4. Now the parent can release the write end of the pipe on its side. If

-//    this is done before step 3, the object's reference count goes down to

-//    0 and it is destroyed, preventing the child from acquiring it. The

-//    parent now has to release it, or read operations on the read end of

-//    the pipe will not return when the child terminates.

-// 5. The parent reads child's output through the pipe (outcome code and

-//    any possible error messages) from the pipe, and its stderr and then

-//    determines whether to fail the test.

-//

-// Note: to distinguish Win32 API calls from the local method and function

-// calls, the former are explicitly resolved in the global namespace.

-//

-class WindowsDeathTest : public DeathTestImpl {

- public:

-  WindowsDeathTest(const char* statement,

-                   const RE* regex,

-                   const char* file,

-                   int line)

-      : DeathTestImpl(statement, regex), file_(file), line_(line) {}

-

-  // All of these virtual functions are inherited from DeathTest.

-  virtual int Wait();

-  virtual TestRole AssumeRole();

-

- private:

-  // The name of the file in which the death test is located.

-  const char* const file_;

-  // The line number on which the death test is located.

-  const int line_;

-  // Handle to the write end of the pipe to the child process.

-  AutoHandle write_handle_;

-  // Child process handle.

-  AutoHandle child_handle_;

-  // Event the child process uses to signal the parent that it has

-  // acquired the handle to the write end of the pipe. After seeing this

-  // event the parent can release its own handles to make sure its

-  // ReadFile() calls return when the child terminates.

-  AutoHandle event_handle_;

-};

-

-// Waits for the child in a death test to exit, returning its exit

-// status, or 0 if no child process exists.  As a side effect, sets the

-// outcome data member.

-int WindowsDeathTest::Wait() {

-  if (!spawned())

-    return 0;

-

-  // Wait until the child either signals that it has acquired the write end

-  // of the pipe or it dies.

-  const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };

-  switch (::WaitForMultipleObjects(2,

-                                   wait_handles,

-                                   FALSE,  // Waits for any of the handles.

-                                   INFINITE)) {

-    case WAIT_OBJECT_0:

-    case WAIT_OBJECT_0 + 1:

-      break;

-    default:

-      GTEST_DEATH_TEST_CHECK_(false);  // Should not get here.

-  }

-

-  // The child has acquired the write end of the pipe or exited.

-  // We release the handle on our side and continue.

-  write_handle_.Reset();

-  event_handle_.Reset();

-

-  ReadAndInterpretStatusByte();

-

-  // Waits for the child process to exit if it haven't already. This

-  // returns immediately if the child has already exited, regardless of

-  // whether previous calls to WaitForMultipleObjects synchronized on this

-  // handle or not.

-  GTEST_DEATH_TEST_CHECK_(

-      WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),

-                                             INFINITE));

-  DWORD status;

-  GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(),

-                                               &status));

-  child_handle_.Reset();

-  set_status(static_cast<int>(status));

-  return this->status();

-}

-

-// The AssumeRole process for a Windows death test.  It creates a child

-// process with the same executable as the current process to run the

-// death test.  The child process is given the --gtest_filter and

-// --gtest_internal_run_death_test flags such that it knows to run the

-// current death test only.

-DeathTest::TestRole WindowsDeathTest::AssumeRole() {

-  const UnitTestImpl* const impl = GetUnitTestImpl();

-  const InternalRunDeathTestFlag* const flag =

-      impl->internal_run_death_test_flag();

-  const TestInfo* const info = impl->current_test_info();

-  const int death_test_index = info->result()->death_test_count();

-

-  if (flag != NULL) {

-    // ParseInternalRunDeathTestFlag() has performed all the necessary

-    // processing.

-    set_write_fd(flag->write_fd());

-    return EXECUTE_TEST;

-  }

-

-  // WindowsDeathTest uses an anonymous pipe to communicate results of

-  // a death test.

-  SECURITY_ATTRIBUTES handles_are_inheritable = {

-    sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };

-  HANDLE read_handle, write_handle;

-  GTEST_DEATH_TEST_CHECK_(::CreatePipe(&read_handle, &write_handle,

-                                       &handles_are_inheritable,

-                                       0));  // Default buffer size.

-  set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),

-                                O_RDONLY));

-  write_handle_.Reset(write_handle);

-  event_handle_.Reset(::CreateEvent(

-      &handles_are_inheritable,

-      TRUE,    // The event will automatically reset to non-signaled state.

-      FALSE,   // The initial state is non-signalled.

-      NULL));  // The even is unnamed.

-  GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);

-  const String filter_flag = String::Format("--%s%s=%s.%s",

-                                            GTEST_FLAG_PREFIX_, kFilterFlag,

-                                            info->test_case_name(),

-                                            info->name());

-  const String internal_flag = String::Format(

-    "--%s%s=%s|%d|%d|%u|%Iu|%Iu",

-      GTEST_FLAG_PREFIX_,

-      kInternalRunDeathTestFlag,

-      file_, line_,

-      death_test_index,

-      static_cast<unsigned int>(::GetCurrentProcessId()),

-      // size_t has the same with as pointers on both 32-bit and 64-bit

-      // Windows platforms.

-      // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.

-      reinterpret_cast<size_t>(write_handle),

-      reinterpret_cast<size_t>(event_handle_.Get()));

-

-  char executable_path[_MAX_PATH + 1];  // NOLINT

-  GTEST_DEATH_TEST_CHECK_(

-      _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,

-                                            executable_path,

-                                            _MAX_PATH));

-

-  String command_line = String::Format("%s %s \"%s\"",

-                                       ::GetCommandLineA(),

-                                       filter_flag.c_str(),

-                                       internal_flag.c_str());

-

-  DeathTest::set_last_death_test_message("");

-

-  CaptureStderr();

-  // Flush the log buffers since the log streams are shared with the child.

-  FlushInfoLog();

-

-  // The child process will share the standard handles with the parent.

-  STARTUPINFOA startup_info;

-  memset(&startup_info, 0, sizeof(STARTUPINFO));

-  startup_info.dwFlags = STARTF_USESTDHANDLES;

-  startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);

-  startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);

-  startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);

-

-  PROCESS_INFORMATION process_info;

-  GTEST_DEATH_TEST_CHECK_(::CreateProcessA(

-      executable_path,

-      const_cast<char*>(command_line.c_str()),

-      NULL,   // Retuned process handle is not inheritable.

-      NULL,   // Retuned thread handle is not inheritable.

-      TRUE,   // Child inherits all inheritable handles (for write_handle_).

-      0x0,    // Default creation flags.

-      NULL,   // Inherit the parent's environment.

-      UnitTest::GetInstance()->original_working_dir(),

-      &startup_info,

-      &process_info));

-  child_handle_.Reset(process_info.hProcess);

-  ::CloseHandle(process_info.hThread);

-  set_spawned(true);

-  return OVERSEE_TEST;

-}

-#else  // We are not on Windows.

-

-// ForkingDeathTest provides implementations for most of the abstract

-// methods of the DeathTest interface.  Only the AssumeRole method is

-// left undefined.

-class ForkingDeathTest : public DeathTestImpl {

- public:

-  ForkingDeathTest(const char* statement, const RE* regex);

-

-  // All of these virtual functions are inherited from DeathTest.

-  virtual int Wait();

-

- protected:

-  void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }

-

- private:

-  // PID of child process during death test; 0 in the child process itself.

-  pid_t child_pid_;

-};

-

-// Constructs a ForkingDeathTest.

-ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex)

-    : DeathTestImpl(statement, regex),

-      child_pid_(-1) {}

-

-// Waits for the child in a death test to exit, returning its exit

-// status, or 0 if no child process exists.  As a side effect, sets the

-// outcome data member.

-int ForkingDeathTest::Wait() {

-  if (!spawned())

-    return 0;

-

-  ReadAndInterpretStatusByte();

-

-  int status;

-  GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status, 0));

-  set_status(status);

-  return status;

-}

-

-// A concrete death test class that forks, then immediately runs the test

-// in the child process.

-class NoExecDeathTest : public ForkingDeathTest {

- public:

-  NoExecDeathTest(const char* statement, const RE* regex) :

-      ForkingDeathTest(statement, regex) { }

-  virtual TestRole AssumeRole();

-};

-

-// The AssumeRole process for a fork-and-run death test.  It implements a

-// straightforward fork, with a simple pipe to transmit the status byte.

-DeathTest::TestRole NoExecDeathTest::AssumeRole() {

-  const size_t thread_count = GetThreadCount();

-  if (thread_count != 1) {

-    GTEST_LOG_(WARNING, DeathTestThreadWarning(thread_count));

-  }

-

-  int pipe_fd[2];

-  GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);

-

-  DeathTest::set_last_death_test_message("");

-  CaptureStderr();

-  // When we fork the process below, the log file buffers are copied, but the

-  // file descriptors are shared.  We flush all log files here so that closing

-  // the file descriptors in the child process doesn't throw off the

-  // synchronization between descriptors and buffers in the parent process.

-  // This is as close to the fork as possible to avoid a race condition in case

-  // there are multiple threads running before the death test, and another

-  // thread writes to the log file.

-  FlushInfoLog();

-

-  const pid_t child_pid = fork();

-  GTEST_DEATH_TEST_CHECK_(child_pid != -1);

-  set_child_pid(child_pid);

-  if (child_pid == 0) {

-    GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));

-    set_write_fd(pipe_fd[1]);

-    // Redirects all logging to stderr in the child process to prevent

-    // concurrent writes to the log files.  We capture stderr in the parent

-    // process and append the child process' output to a log.

-    LogToStderr();

-    return EXECUTE_TEST;

-  } else {

-    GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));

-    set_read_fd(pipe_fd[0]);

-    set_spawned(true);

-    return OVERSEE_TEST;

-  }

-}

-

-// A concrete death test class that forks and re-executes the main

-// program from the beginning, with command-line flags set that cause

-// only this specific death test to be run.

-class ExecDeathTest : public ForkingDeathTest {

- public:

-  ExecDeathTest(const char* statement, const RE* regex,

-                const char* file, int line) :

-      ForkingDeathTest(statement, regex), file_(file), line_(line) { }

-  virtual TestRole AssumeRole();

- private:

-  // The name of the file in which the death test is located.

-  const char* const file_;

-  // The line number on which the death test is located.

-  const int line_;

-};

-

-// Utility class for accumulating command-line arguments.

-class Arguments {

- public:

-  Arguments() {

-    args_.push_back(NULL);

-  }

-

-  ~Arguments() {

-    for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();

-         ++i) {

-      free(*i);

-    }

-  }

-  void AddArgument(const char* argument) {

-    args_.insert(args_.end() - 1, posix::StrDup(argument));

-  }

-

-  template <typename Str>

-  void AddArguments(const ::std::vector<Str>& arguments) {

-    for (typename ::std::vector<Str>::const_iterator i = arguments.begin();

-         i != arguments.end();

-         ++i) {

-      args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));

-    }

-  }

-  char* const* Argv() {

-    return &args_[0];

-  }

- private:

-  std::vector<char*> args_;

-};

-

-// A struct that encompasses the arguments to the child process of a

-// threadsafe-style death test process.

-struct ExecDeathTestArgs {

-  char* const* argv;  // Command-line arguments for the child's call to exec

-  int close_fd;       // File descriptor to close; the read end of a pipe

-};

-

-#if GTEST_OS_MAC

-inline char** GetEnviron() {

-  // When Google Test is built as a framework on MacOS X, the environ variable

-  // is unavailable. Apple's documentation (man environ) recommends using

-  // _NSGetEnviron() instead.

-  return *_NSGetEnviron();

-}

-#else

-// Some POSIX platforms expect you to declare environ. extern "C" makes

-// it reside in the global namespace.

-extern "C" char** environ;

-inline char** GetEnviron() { return environ; }

-#endif  // GTEST_OS_MAC

-

-// The main function for a threadsafe-style death test child process.

-// This function is called in a clone()-ed process and thus must avoid

-// any potentially unsafe operations like malloc or libc functions.

-static int ExecDeathTestChildMain(void* child_arg) {

-  ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);

-  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));

-

-  // We need to execute the test program in the same environment where

-  // it was originally invoked.  Therefore we change to the original

-  // working directory first.

-  const char* const original_dir =

-      UnitTest::GetInstance()->original_working_dir();

-  // We can safely call chdir() as it's a direct system call.

-  if (chdir(original_dir) != 0) {

-    DeathTestAbort(String::Format("chdir(\"%s\") failed: %s",

-                                  original_dir,

-                                  GetLastErrnoDescription().c_str()));

-    return EXIT_FAILURE;

-  }

-

-  // We can safely call execve() as it's a direct system call.  We

-  // cannot use execvp() as it's a libc function and thus potentially

-  // unsafe.  Since execve() doesn't search the PATH, the user must

-  // invoke the test program via a valid path that contains at least

-  // one path separator.

-  execve(args->argv[0], args->argv, GetEnviron());

-  DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s",

-                                args->argv[0],

-                                original_dir,

-                                GetLastErrnoDescription().c_str()));

-  return EXIT_FAILURE;

-}

-

-// Two utility routines that together determine the direction the stack

-// grows.

-// This could be accomplished more elegantly by a single recursive

-// function, but we want to guard against the unlikely possibility of

-// a smart compiler optimizing the recursion away.

-bool StackLowerThanAddress(const void* ptr) {

-  int dummy;

-  return &dummy < ptr;

-}

-

-bool StackGrowsDown() {

-  int dummy;

-  return StackLowerThanAddress(&dummy);

-}

-

-// A threadsafe implementation of fork(2) for threadsafe-style death tests

-// that uses clone(2).  It dies with an error message if anything goes

-// wrong.

-static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {

-  ExecDeathTestArgs args = { argv, close_fd };

-  pid_t child_pid = -1;

-

-#if GTEST_HAS_CLONE

-  const bool use_fork = GTEST_FLAG(death_test_use_fork);

-

-  if (!use_fork) {

-    static const bool stack_grows_down = StackGrowsDown();

-    const size_t stack_size = getpagesize();

-    // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.

-    void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,

-                             MAP_ANON | MAP_PRIVATE, -1, 0);

-    GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);

-    void* const stack_top =

-        static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0);

-

-    child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);

-

-    GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);

-  }

-#else

-  const bool use_fork = true;

-#endif  // GTEST_HAS_CLONE

-

-  if (use_fork && (child_pid = fork()) == 0) {

-      ExecDeathTestChildMain(&args);

-      _exit(0);

-  }

-

-  GTEST_DEATH_TEST_CHECK_(child_pid != -1);

-  return child_pid;

-}

-

-// The AssumeRole process for a fork-and-exec death test.  It re-executes the

-// main program from the beginning, setting the --gtest_filter

-// and --gtest_internal_run_death_test flags to cause only the current

-// death test to be re-run.

-DeathTest::TestRole ExecDeathTest::AssumeRole() {

-  const UnitTestImpl* const impl = GetUnitTestImpl();

-  const InternalRunDeathTestFlag* const flag =

-      impl->internal_run_death_test_flag();

-  const TestInfo* const info = impl->current_test_info();

-  const int death_test_index = info->result()->death_test_count();

-

-  if (flag != NULL) {

-    set_write_fd(flag->write_fd());

-    return EXECUTE_TEST;

-  }

-

-  int pipe_fd[2];

-  GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);

-  // Clear the close-on-exec flag on the write end of the pipe, lest

-  // it be closed when the child process does an exec:

-  GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);

-

-  const String filter_flag =

-      String::Format("--%s%s=%s.%s",

-                     GTEST_FLAG_PREFIX_, kFilterFlag,

-                     info->test_case_name(), info->name());

-  const String internal_flag =

-      String::Format("--%s%s=%s|%d|%d|%d",

-                     GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag,

-                     file_, line_, death_test_index, pipe_fd[1]);

-  Arguments args;

-  args.AddArguments(GetArgvs());

-  args.AddArgument(filter_flag.c_str());

-  args.AddArgument(internal_flag.c_str());

-

-  DeathTest::set_last_death_test_message("");

-

-  CaptureStderr();

-  // See the comment in NoExecDeathTest::AssumeRole for why the next line

-  // is necessary.

-  FlushInfoLog();

-

-  const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]);

-  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));

-  set_child_pid(child_pid);

-  set_read_fd(pipe_fd[0]);

-  set_spawned(true);

-  return OVERSEE_TEST;

-}

-

-#endif  // !GTEST_OS_WINDOWS

-

-// Creates a concrete DeathTest-derived class that depends on the

-// --gtest_death_test_style flag, and sets the pointer pointed to

-// by the "test" argument to its address.  If the test should be

-// skipped, sets that pointer to NULL.  Returns true, unless the

-// flag is set to an invalid value.

-bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,

-                                     const char* file, int line,

-                                     DeathTest** test) {

-  UnitTestImpl* const impl = GetUnitTestImpl();

-  const InternalRunDeathTestFlag* const flag =

-      impl->internal_run_death_test_flag();

-  const int death_test_index = impl->current_test_info()

-      ->increment_death_test_count();

-

-  if (flag != NULL) {

-    if (death_test_index > flag->index()) {

-      DeathTest::set_last_death_test_message(String::Format(

-          "Death test count (%d) somehow exceeded expected maximum (%d)",

-          death_test_index, flag->index()));

-      return false;

-    }

-

-    if (!(flag->file() == file && flag->line() == line &&

-          flag->index() == death_test_index)) {

-      *test = NULL;

-      return true;

-    }

-  }

-

-#if GTEST_OS_WINDOWS

-  if (GTEST_FLAG(death_test_style) == "threadsafe" ||

-      GTEST_FLAG(death_test_style) == "fast") {

-    *test = new WindowsDeathTest(statement, regex, file, line);

-  }

-#else

-  if (GTEST_FLAG(death_test_style) == "threadsafe") {

-    *test = new ExecDeathTest(statement, regex, file, line);

-  } else if (GTEST_FLAG(death_test_style) == "fast") {

-    *test = new NoExecDeathTest(statement, regex);

-  }

-#endif  // GTEST_OS_WINDOWS

-  else {  // NOLINT - this is more readable than unbalanced brackets inside #if.

-    DeathTest::set_last_death_test_message(String::Format(

-        "Unknown death test style \"%s\" encountered",

-        GTEST_FLAG(death_test_style).c_str()));

-    return false;

-  }

-

-  return true;

-}

-

-// Splits a given string on a given delimiter, populating a given

-// vector with the fields.  GTEST_HAS_DEATH_TEST implies that we have

-// ::std::string, so we can use it here.

-// TODO(vladl@google.com): Get rid of std::vector to be able to build on

-// Visual C++ 7.1 with exceptions disabled.

-static void SplitString(const ::std::string& str, char delimiter,

-                        ::std::vector< ::std::string>* dest) {

-  ::std::vector< ::std::string> parsed;

-  ::std::string::size_type pos = 0;

-  while (true) {

-    const ::std::string::size_type colon = str.find(delimiter, pos);

-    if (colon == ::std::string::npos) {

-      parsed.push_back(str.substr(pos));

-      break;

-    } else {

-      parsed.push_back(str.substr(pos, colon - pos));

-      pos = colon + 1;

-    }

-  }

-  dest->swap(parsed);

-}

-

-#if GTEST_OS_WINDOWS

-// Recreates the pipe and event handles from the provided parameters,

-// signals the event, and returns a file descriptor wrapped around the pipe

-// handle. This function is called in the child process only.

-int GetStatusFileDescriptor(unsigned int parent_process_id,

-                            size_t write_handle_as_size_t,

-                            size_t event_handle_as_size_t) {

-  AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,

-                                                   FALSE,  // Non-inheritable.

-                                                   parent_process_id));

-  if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {

-    DeathTestAbort(String::Format("Unable to open parent process %u",

-                                  parent_process_id));

-  }

-

-  // TODO(vladl@google.com): Replace the following check with a

-  // compile-time assertion when available.

-  GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));

-

-  const HANDLE write_handle =

-      reinterpret_cast<HANDLE>(write_handle_as_size_t);

-  HANDLE dup_write_handle;

-

-  // The newly initialized handle is accessible only in in the parent

-  // process. To obtain one accessible within the child, we need to use

-  // DuplicateHandle.

-  if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,

-                         ::GetCurrentProcess(), &dup_write_handle,

-                         0x0,    // Requested privileges ignored since

-                                 // DUPLICATE_SAME_ACCESS is used.

-                         FALSE,  // Request non-inheritable handler.

-                         DUPLICATE_SAME_ACCESS)) {

-    DeathTestAbort(String::Format(

-        "Unable to duplicate the pipe handle %Iu from the parent process %u",

-        write_handle_as_size_t, parent_process_id));

-  }

-

-  const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);

-  HANDLE dup_event_handle;

-

-  if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,

-                         ::GetCurrentProcess(), &dup_event_handle,

-                         0x0,

-                         FALSE,

-                         DUPLICATE_SAME_ACCESS)) {

-    DeathTestAbort(String::Format(

-        "Unable to duplicate the event handle %Iu from the parent process %u",

-        event_handle_as_size_t, parent_process_id));

-  }

-

-  const int write_fd =

-      ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);

-  if (write_fd == -1) {

-    DeathTestAbort(String::Format(

-        "Unable to convert pipe handle %Iu to a file descriptor",

-        write_handle_as_size_t));

-  }

-

-  // Signals the parent that the write end of the pipe has been acquired

-  // so the parent can release its own write end.

-  ::SetEvent(dup_event_handle);

-

-  return write_fd;

-}

-#endif  // GTEST_OS_WINDOWS

-

-// Returns a newly created InternalRunDeathTestFlag object with fields

-// initialized from the GTEST_FLAG(internal_run_death_test) flag if

-// the flag is specified; otherwise returns NULL.

-InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {

-  if (GTEST_FLAG(internal_run_death_test) == "") return NULL;

-

-  // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we

-  // can use it here.

-  int line = -1;

-  int index = -1;

-  ::std::vector< ::std::string> fields;

-  SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);

-  int write_fd = -1;

-

-#if GTEST_OS_WINDOWS

-  unsigned int parent_process_id = 0;

-  size_t write_handle_as_size_t = 0;

-  size_t event_handle_as_size_t = 0;

-

-  if (fields.size() != 6

-      || !ParseNaturalNumber(fields[1], &line)

-      || !ParseNaturalNumber(fields[2], &index)

-      || !ParseNaturalNumber(fields[3], &parent_process_id)

-      || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)

-      || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {

-    DeathTestAbort(String::Format(

-        "Bad --gtest_internal_run_death_test flag: %s",

-        GTEST_FLAG(internal_run_death_test).c_str()));

-  }

-  write_fd = GetStatusFileDescriptor(parent_process_id,

-                                     write_handle_as_size_t,

-                                     event_handle_as_size_t);

-#else

-  if (fields.size() != 4

-      || !ParseNaturalNumber(fields[1], &line)

-      || !ParseNaturalNumber(fields[2], &index)

-      || !ParseNaturalNumber(fields[3], &write_fd)) {

-    DeathTestAbort(String::Format(

-        "Bad --gtest_internal_run_death_test flag: %s",

-        GTEST_FLAG(internal_run_death_test).c_str()));

-  }

-#endif  // GTEST_OS_WINDOWS

-  return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);

-}

-

-}  // namespace internal

-

-#endif  // GTEST_HAS_DEATH_TEST

-

-}  // namespace testing

+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev)
+//
+// This file implements death tests.
+
+#include <gtest/gtest-death-test.h>
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_MAC
+#include <crt_externs.h>
+#endif  // GTEST_OS_MAC
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#if GTEST_OS_WINDOWS
+#include <windows.h>
+#else
+#include <sys/mman.h>
+#include <sys/wait.h>
+#endif  // GTEST_OS_WINDOWS
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+#include <gtest/gtest-message.h>
+#include <gtest/internal/gtest-string.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+// Constants.
+
+// The default death test style.
+static const char kDefaultDeathTestStyle[] = "fast";
+
+GTEST_DEFINE_string_(
+    death_test_style,
+    internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
+    "Indicates how to run a death test in a forked child process: "
+    "\"threadsafe\" (child process re-executes the test binary "
+    "from the beginning, running only the specific death test) or "
+    "\"fast\" (child process runs the death test immediately "
+    "after forking).");
+
+GTEST_DEFINE_bool_(
+    death_test_use_fork,
+    internal::BoolFromGTestEnv("death_test_use_fork", false),
+    "Instructs to use fork()/_exit() instead of clone() in death tests. "
+    "Ignored and always uses fork() on POSIX systems where clone() is not "
+    "implemented. Useful when running under valgrind or similar tools if "
+    "those do not support clone(). Valgrind 3.3.1 will just fail if "
+    "it sees an unsupported combination of clone() flags. "
+    "It is not recommended to use this flag w/o valgrind though it will "
+    "work in 99% of the cases. Once valgrind is fixed, this flag will "
+    "most likely be removed.");
+
+namespace internal {
+GTEST_DEFINE_string_(
+    internal_run_death_test, "",
+    "Indicates the file, line number, temporal index of "
+    "the single death test to run, and a file descriptor to "
+    "which a success code may be sent, all separated by "
+    "colons.  This flag is specified if and only if the current "
+    "process is a sub-process launched for running a thread-safe "
+    "death test.  FOR INTERNAL USE ONLY.");
+}  // namespace internal
+
+#if GTEST_HAS_DEATH_TEST
+
+// ExitedWithCode constructor.
+ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
+}
+
+// ExitedWithCode function-call operator.
+bool ExitedWithCode::operator()(int exit_status) const {
+#if GTEST_OS_WINDOWS
+  return exit_status == exit_code_;
+#else
+  return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+#endif  // GTEST_OS_WINDOWS
+}
+
+#if !GTEST_OS_WINDOWS
+// KilledBySignal constructor.
+KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
+}
+
+// KilledBySignal function-call operator.
+bool KilledBySignal::operator()(int exit_status) const {
+  return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
+}
+#endif  // !GTEST_OS_WINDOWS
+
+namespace internal {
+
+// Utilities needed for death tests.
+
+// Generates a textual description of a given exit code, in the format
+// specified by wait(2).
+static String ExitSummary(int exit_code) {
+  Message m;
+#if GTEST_OS_WINDOWS
+  m << "Exited with exit status " << exit_code;
+#else
+  if (WIFEXITED(exit_code)) {
+    m << "Exited with exit status " << WEXITSTATUS(exit_code);
+  } else if (WIFSIGNALED(exit_code)) {
+    m << "Terminated by signal " << WTERMSIG(exit_code);
+  }
+#ifdef WCOREDUMP
+  if (WCOREDUMP(exit_code)) {
+    m << " (core dumped)";
+  }
+#endif
+#endif  // GTEST_OS_WINDOWS
+  return m.GetString();
+}
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status) {
+  return !ExitedWithCode(0)(exit_status);
+}
+
+#if !GTEST_OS_WINDOWS
+// Generates a textual failure message when a death test finds more than
+// one thread running, or cannot determine the number of threads, prior
+// to executing the given statement.  It is the responsibility of the
+// caller not to pass a thread_count of 1.
+static String DeathTestThreadWarning(size_t thread_count) {
+  Message msg;
+  msg << "Death tests use fork(), which is unsafe particularly"
+      << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
+  if (thread_count == 0)
+    msg << "couldn't detect the number of threads.";
+  else
+    msg << "detected " << thread_count << " threads.";
+  return msg.GetString();
+}
+#endif  // !GTEST_OS_WINDOWS
+
+// Flag characters for reporting a death test that did not die.
+static const char kDeathTestLived = 'L';
+static const char kDeathTestReturned = 'R';
+static const char kDeathTestInternalError = 'I';
+
+// An enumeration describing all of the possible ways that a death test
+// can conclude.  DIED means that the process died while executing the
+// test code; LIVED means that process lived beyond the end of the test
+// code; and RETURNED means that the test statement attempted a "return,"
+// which is not allowed.  IN_PROGRESS means the test has not yet
+// concluded.
+enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED };
+
+// Routine for aborting the program which is safe to call from an
+// exec-style death test child process, in which case the error
+// message is propagated back to the parent process.  Otherwise, the
+// message is simply printed to stderr.  In either case, the program
+// then exits with status 1.
+void DeathTestAbort(const String& message) {
+  // On a POSIX system, this function may be called from a threadsafe-style
+  // death test child process, which operates on a very small stack.  Use
+  // the heap for any additional non-minuscule memory requirements.
+  const InternalRunDeathTestFlag* const flag =
+      GetUnitTestImpl()->internal_run_death_test_flag();
+  if (flag != NULL) {
+    FILE* parent = posix::FDOpen(flag->write_fd(), "w");
+    fputc(kDeathTestInternalError, parent);
+    fprintf(parent, "%s", message.c_str());
+    fflush(parent);
+    _exit(1);
+  } else {
+    fprintf(stderr, "%s", message.c_str());
+    fflush(stderr);
+    abort();
+  }
+}
+
+// A replacement for CHECK that calls DeathTestAbort if the assertion
+// fails.
+#define GTEST_DEATH_TEST_CHECK_(expression) \
+  do { \
+    if (!(expression)) { \
+      DeathTestAbort(::testing::internal::String::Format(\
+          "CHECK failed: File %s, line %d: %s", \
+          __FILE__, __LINE__, #expression)); \
+    } \
+  } while (0)
+
+// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
+// evaluating any system call that fulfills two conditions: it must return
+// -1 on failure, and set errno to EINTR when it is interrupted and
+// should be tried again.  The macro expands to a loop that repeatedly
+// evaluates the expression as long as it evaluates to -1 and sets
+// errno to EINTR.  If the expression evaluates to -1 but errno is
+// something other than EINTR, DeathTestAbort is called.
+#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
+  do { \
+    int gtest_retval; \
+    do { \
+      gtest_retval = (expression); \
+    } while (gtest_retval == -1 && errno == EINTR); \
+    if (gtest_retval == -1) { \
+      DeathTestAbort(::testing::internal::String::Format(\
+          "CHECK failed: File %s, line %d: %s != -1", \
+          __FILE__, __LINE__, #expression)); \
+    } \
+  } while (0)
+
+// Returns the message describing the last system error in errno.
+String GetLastErrnoDescription() {
+    return String(errno == 0 ? "" : posix::StrError(errno));
+}
+
+// This is called from a death test parent process to read a failure
+// message from the death test child process and log it with the FATAL
+// severity. On Windows, the message is read from a pipe handle. On other
+// platforms, it is read from a file descriptor.
+static void FailFromInternalError(int fd) {
+  Message error;
+  char buffer[256];
+  int num_read;
+
+  do {
+    while ((num_read = posix::Read(fd, buffer, 255)) > 0) {
+      buffer[num_read] = '\0';
+      error << buffer;
+    }
+  } while (num_read == -1 && errno == EINTR);
+
+  if (num_read == 0) {
+    GTEST_LOG_(FATAL, error);
+  } else {
+    const int last_error = errno;
+    const String message = GetLastErrnoDescription();
+    GTEST_LOG_(FATAL,
+               Message() << "Error while reading death test internal: "
+               << message << " [" << last_error << "]");
+  }
+}
+
+// Death test constructor.  Increments the running death test count
+// for the current test.
+DeathTest::DeathTest() {
+  TestInfo* const info = GetUnitTestImpl()->current_test_info();
+  if (info == NULL) {
+    DeathTestAbort("Cannot run a death test outside of a TEST or "
+                   "TEST_F construct");
+  }
+}
+
+// Creates and returns a death test by dispatching to the current
+// death test factory.
+bool DeathTest::Create(const char* statement, const RE* regex,
+                       const char* file, int line, DeathTest** test) {
+  return GetUnitTestImpl()->death_test_factory()->Create(
+      statement, regex, file, line, test);
+}
+
+const char* DeathTest::LastMessage() {
+  return last_death_test_message_.c_str();
+}
+
+void DeathTest::set_last_death_test_message(const String& message) {
+  last_death_test_message_ = message;
+}
+
+String DeathTest::last_death_test_message_;
+
+// Provides cross platform implementation for some death functionality.
+class DeathTestImpl : public DeathTest {
+ protected:
+  DeathTestImpl(const char* statement, const RE* regex)
+      : statement_(statement),
+        regex_(regex),
+        spawned_(false),
+        status_(-1),
+        outcome_(IN_PROGRESS),
+        read_fd_(-1),
+        write_fd_(-1) {}
+
+  // read_fd_ is expected to be closed and cleared by a derived class.
+  ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+
+  void Abort(AbortReason reason);
+  virtual bool Passed(bool status_ok);
+
+  const char* statement() const { return statement_; }
+  const RE* regex() const { return regex_; }
+  bool spawned() const { return spawned_; }
+  void set_spawned(bool spawned) { spawned_ = spawned; }
+  int status() const { return status_; }
+  void set_status(int status) { status_ = status; }
+  DeathTestOutcome outcome() const { return outcome_; }
+  void set_outcome(DeathTestOutcome outcome) { outcome_ = outcome; }
+  int read_fd() const { return read_fd_; }
+  void set_read_fd(int fd) { read_fd_ = fd; }
+  int write_fd() const { return write_fd_; }
+  void set_write_fd(int fd) { write_fd_ = fd; }
+
+  // Called in the parent process only. Reads the result code of the death
+  // test child process via a pipe, interprets it to set the outcome_
+  // member, and closes read_fd_.  Outputs diagnostics and terminates in
+  // case of unexpected codes.
+  void ReadAndInterpretStatusByte();
+
+ private:
+  // The textual content of the code this object is testing.  This class
+  // doesn't own this string and should not attempt to delete it.
+  const char* const statement_;
+  // The regular expression which test output must match.  DeathTestImpl
+  // doesn't own this object and should not attempt to delete it.
+  const RE* const regex_;
+  // True if the death test child process has been successfully spawned.
+  bool spawned_;
+  // The exit status of the child process.
+  int status_;
+  // How the death test concluded.
+  DeathTestOutcome outcome_;
+  // Descriptor to the read end of the pipe to the child process.  It is
+  // always -1 in the child process.  The child keeps its write end of the
+  // pipe in write_fd_.
+  int read_fd_;
+  // Descriptor to the child's write end of the pipe to the parent process.
+  // It is always -1 in the parent process.  The parent keeps its end of the
+  // pipe in read_fd_.
+  int write_fd_;
+};
+
+// Called in the parent process only. Reads the result code of the death
+// test child process via a pipe, interprets it to set the outcome_
+// member, and closes read_fd_.  Outputs diagnostics and terminates in
+// case of unexpected codes.
+void DeathTestImpl::ReadAndInterpretStatusByte() {
+  char flag;
+  int bytes_read;
+
+  // The read() here blocks until data is available (signifying the
+  // failure of the death test) or until the pipe is closed (signifying
+  // its success), so it's okay to call this in the parent before
+  // the child process has exited.
+  do {
+    bytes_read = posix::Read(read_fd(), &flag, 1);
+  } while (bytes_read == -1 && errno == EINTR);
+
+  if (bytes_read == 0) {
+    set_outcome(DIED);
+  } else if (bytes_read == 1) {
+    switch (flag) {
+      case kDeathTestReturned:
+        set_outcome(RETURNED);
+        break;
+      case kDeathTestLived:
+        set_outcome(LIVED);
+        break;
+      case kDeathTestInternalError:
+        FailFromInternalError(read_fd());  // Does not return.
+        break;
+      default:
+        GTEST_LOG_(FATAL,
+                   Message() << "Death test child process reported "
+                   << "unexpected status byte ("
+                   << static_cast<unsigned int>(flag) << ")");
+    }
+  } else {
+    GTEST_LOG_(FATAL,
+               Message() << "Read from death test child process failed: "
+                         << GetLastErrnoDescription());
+  }
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
+  set_read_fd(-1);
+}
+
+// Signals that the death test code which should have exited, didn't.
+// Should be called only in a death test child process.
+// Writes a status byte to the child's status file descriptor, then
+// calls _exit(1).
+void DeathTestImpl::Abort(AbortReason reason) {
+  // The parent process considers the death test to be a failure if
+  // it finds any data in our pipe.  So, here we write a single flag byte
+  // to the pipe, then exit.
+  const char status_ch =
+      reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd()));
+  _exit(1);  // Exits w/o any normal exit hooks (we were supposed to crash)
+}
+
+// Assesses the success or failure of a death test, using both private
+// members which have previously been set, and one argument:
+//
+// Private data members:
+//   outcome:  An enumeration describing how the death test
+//             concluded: DIED, LIVED, or RETURNED.  The death test fails
+//             in the latter two cases.
+//   status:   The exit status of the child process. On *nix, it is in the
+//             in the format specified by wait(2). On Windows, this is the
+//             value supplied to the ExitProcess() API or a numeric code
+//             of the exception that terminated the program.
+//   regex:    A regular expression object to be applied to
+//             the test's captured standard error output; the death test
+//             fails if it does not match.
+//
+// Argument:
+//   status_ok: true if exit_status is acceptable in the context of
+//              this particular death test, which fails if it is false
+//
+// Returns true iff all of the above conditions are met.  Otherwise, the
+// first failing condition, in the order given above, is the one that is
+// reported. Also sets the last death test message string.
+bool DeathTestImpl::Passed(bool status_ok) {
+  if (!spawned())
+    return false;
+
+#if GTEST_HAS_GLOBAL_STRING
+  const ::string error_message = GetCapturedStderr();
+#else
+  const ::std::string error_message = GetCapturedStderr();
+#endif  // GTEST_HAS_GLOBAL_STRING
+
+  bool success = false;
+  Message buffer;
+
+  buffer << "Death test: " << statement() << "\n";
+  switch (outcome()) {
+    case LIVED:
+      buffer << "    Result: failed to die.\n"
+             << " Error msg: " << error_message;
+      break;
+    case RETURNED:
+      buffer << "    Result: illegal return in test statement.\n"
+             << " Error msg: " << error_message;
+      break;
+    case DIED:
+      if (status_ok) {
+        if (RE::PartialMatch(error_message, *regex())) {
+          success = true;
+        } else {
+          buffer << "    Result: died but not with expected error.\n"
+                 << "  Expected: " << regex()->pattern() << "\n"
+                 << "Actual msg: " << error_message;
+        }
+      } else {
+        buffer << "    Result: died but not with expected exit code:\n"
+               << "            " << ExitSummary(status()) << "\n";
+      }
+      break;
+    case IN_PROGRESS:
+    default:
+      GTEST_LOG_(FATAL,
+                 "DeathTest::Passed somehow called before conclusion of test");
+  }
+
+  DeathTest::set_last_death_test_message(buffer.GetString());
+  return success;
+}
+
+#if GTEST_OS_WINDOWS
+// WindowsDeathTest implements death tests on Windows. Due to the
+// specifics of starting new processes on Windows, death tests there are
+// always threadsafe, and Google Test considers the
+// --gtest_death_test_style=fast setting to be equivalent to
+// --gtest_death_test_style=threadsafe there.
+//
+// A few implementation notes:  Like the Linux version, the Windows
+// implementation uses pipes for child-to-parent communication. But due to
+// the specifics of pipes on Windows, some extra steps are required:
+//
+// 1. The parent creates a communication pipe and stores handles to both
+//    ends of it.
+// 2. The parent starts the child and provides it with the information
+//    necessary to acquire the handle to the write end of the pipe.
+// 3. The child acquires the write end of the pipe and signals the parent
+//    using a Windows event.
+// 4. Now the parent can release the write end of the pipe on its side. If
+//    this is done before step 3, the object's reference count goes down to
+//    0 and it is destroyed, preventing the child from acquiring it. The
+//    parent now has to release it, or read operations on the read end of
+//    the pipe will not return when the child terminates.
+// 5. The parent reads child's output through the pipe (outcome code and
+//    any possible error messages) from the pipe, and its stderr and then
+//    determines whether to fail the test.
+//
+// Note: to distinguish Win32 API calls from the local method and function
+// calls, the former are explicitly resolved in the global namespace.
+//
+class WindowsDeathTest : public DeathTestImpl {
+ public:
+  WindowsDeathTest(const char* statement,
+                   const RE* regex,
+                   const char* file,
+                   int line)
+      : DeathTestImpl(statement, regex), file_(file), line_(line) {}
+
+  // All of these virtual functions are inherited from DeathTest.
+  virtual int Wait();
+  virtual TestRole AssumeRole();
+
+ private:
+  // The name of the file in which the death test is located.
+  const char* const file_;
+  // The line number on which the death test is located.
+  const int line_;
+  // Handle to the write end of the pipe to the child process.
+  AutoHandle write_handle_;
+  // Child process handle.
+  AutoHandle child_handle_;
+  // Event the child process uses to signal the parent that it has
+  // acquired the handle to the write end of the pipe. After seeing this
+  // event the parent can release its own handles to make sure its
+  // ReadFile() calls return when the child terminates.
+  AutoHandle event_handle_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists.  As a side effect, sets the
+// outcome data member.
+int WindowsDeathTest::Wait() {
+  if (!spawned())
+    return 0;
+
+  // Wait until the child either signals that it has acquired the write end
+  // of the pipe or it dies.
+  const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
+  switch (::WaitForMultipleObjects(2,
+                                   wait_handles,
+                                   FALSE,  // Waits for any of the handles.
+                                   INFINITE)) {
+    case WAIT_OBJECT_0:
+    case WAIT_OBJECT_0 + 1:
+      break;
+    default:
+      GTEST_DEATH_TEST_CHECK_(false);  // Should not get here.
+  }
+
+  // The child has acquired the write end of the pipe or exited.
+  // We release the handle on our side and continue.
+  write_handle_.Reset();
+  event_handle_.Reset();
+
+  ReadAndInterpretStatusByte();
+
+  // Waits for the child process to exit if it haven't already. This
+  // returns immediately if the child has already exited, regardless of
+  // whether previous calls to WaitForMultipleObjects synchronized on this
+  // handle or not.
+  GTEST_DEATH_TEST_CHECK_(
+      WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
+                                             INFINITE));
+  DWORD status;
+  GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(),
+                                               &status));
+  child_handle_.Reset();
+  set_status(static_cast<int>(status));
+  return this->status();
+}
+
+// The AssumeRole process for a Windows death test.  It creates a child
+// process with the same executable as the current process to run the
+// death test.  The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole WindowsDeathTest::AssumeRole() {
+  const UnitTestImpl* const impl = GetUnitTestImpl();
+  const InternalRunDeathTestFlag* const flag =
+      impl->internal_run_death_test_flag();
+  const TestInfo* const info = impl->current_test_info();
+  const int death_test_index = info->result()->death_test_count();
+
+  if (flag != NULL) {
+    // ParseInternalRunDeathTestFlag() has performed all the necessary
+    // processing.
+    set_write_fd(flag->write_fd());
+    return EXECUTE_TEST;
+  }
+
+  // WindowsDeathTest uses an anonymous pipe to communicate results of
+  // a death test.
+  SECURITY_ATTRIBUTES handles_are_inheritable = {
+    sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+  HANDLE read_handle, write_handle;
+  GTEST_DEATH_TEST_CHECK_(::CreatePipe(&read_handle, &write_handle,
+                                       &handles_are_inheritable,
+                                       0));  // Default buffer size.
+  set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
+                                O_RDONLY));
+  write_handle_.Reset(write_handle);
+  event_handle_.Reset(::CreateEvent(
+      &handles_are_inheritable,
+      TRUE,    // The event will automatically reset to non-signaled state.
+      FALSE,   // The initial state is non-signalled.
+      NULL));  // The even is unnamed.
+  GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
+  const String filter_flag = String::Format("--%s%s=%s.%s",
+                                            GTEST_FLAG_PREFIX_, kFilterFlag,
+                                            info->test_case_name(),
+                                            info->name());
+  const String internal_flag = String::Format(
+    "--%s%s=%s|%d|%d|%u|%Iu|%Iu",
+      GTEST_FLAG_PREFIX_,
+      kInternalRunDeathTestFlag,
+      file_, line_,
+      death_test_index,
+      static_cast<unsigned int>(::GetCurrentProcessId()),
+      // size_t has the same with as pointers on both 32-bit and 64-bit
+      // Windows platforms.
+      // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
+      reinterpret_cast<size_t>(write_handle),
+      reinterpret_cast<size_t>(event_handle_.Get()));
+
+  char executable_path[_MAX_PATH + 1];  // NOLINT
+  GTEST_DEATH_TEST_CHECK_(
+      _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
+                                            executable_path,
+                                            _MAX_PATH));
+
+  String command_line = String::Format("%s %s \"%s\"",
+                                       ::GetCommandLineA(),
+                                       filter_flag.c_str(),
+                                       internal_flag.c_str());
+
+  DeathTest::set_last_death_test_message("");
+
+  CaptureStderr();
+  // Flush the log buffers since the log streams are shared with the child.
+  FlushInfoLog();
+
+  // The child process will share the standard handles with the parent.
+  STARTUPINFOA startup_info;
+  memset(&startup_info, 0, sizeof(STARTUPINFO));
+  startup_info.dwFlags = STARTF_USESTDHANDLES;
+  startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
+  startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
+  startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
+
+  PROCESS_INFORMATION process_info;
+  GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
+      executable_path,
+      const_cast<char*>(command_line.c_str()),
+      NULL,   // Retuned process handle is not inheritable.
+      NULL,   // Retuned thread handle is not inheritable.
+      TRUE,   // Child inherits all inheritable handles (for write_handle_).
+      0x0,    // Default creation flags.
+      NULL,   // Inherit the parent's environment.
+      UnitTest::GetInstance()->original_working_dir(),
+      &startup_info,
+      &process_info));
+  child_handle_.Reset(process_info.hProcess);
+  ::CloseHandle(process_info.hThread);
+  set_spawned(true);
+  return OVERSEE_TEST;
+}
+#else  // We are not on Windows.
+
+// ForkingDeathTest provides implementations for most of the abstract
+// methods of the DeathTest interface.  Only the AssumeRole method is
+// left undefined.
+class ForkingDeathTest : public DeathTestImpl {
+ public:
+  ForkingDeathTest(const char* statement, const RE* regex);
+
+  // All of these virtual functions are inherited from DeathTest.
+  virtual int Wait();
+
+ protected:
+  void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+
+ private:
+  // PID of child process during death test; 0 in the child process itself.
+  pid_t child_pid_;
+};
+
+// Constructs a ForkingDeathTest.
+ForkingDeathTest::ForkingDeathTest(const char* statement, const RE* regex)
+    : DeathTestImpl(statement, regex),
+      child_pid_(-1) {}
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists.  As a side effect, sets the
+// outcome data member.
+int ForkingDeathTest::Wait() {
+  if (!spawned())
+    return 0;
+
+  ReadAndInterpretStatusByte();
+
+  int status;
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status, 0));
+  set_status(status);
+  return status;
+}
+
+// A concrete death test class that forks, then immediately runs the test
+// in the child process.
+class NoExecDeathTest : public ForkingDeathTest {
+ public:
+  NoExecDeathTest(const char* statement, const RE* regex) :
+      ForkingDeathTest(statement, regex) { }
+  virtual TestRole AssumeRole();
+};
+
+// The AssumeRole process for a fork-and-run death test.  It implements a
+// straightforward fork, with a simple pipe to transmit the status byte.
+DeathTest::TestRole NoExecDeathTest::AssumeRole() {
+  const size_t thread_count = GetThreadCount();
+  if (thread_count != 1) {
+    GTEST_LOG_(WARNING, DeathTestThreadWarning(thread_count));
+  }
+
+  int pipe_fd[2];
+  GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+
+  DeathTest::set_last_death_test_message("");
+  CaptureStderr();
+  // When we fork the process below, the log file buffers are copied, but the
+  // file descriptors are shared.  We flush all log files here so that closing
+  // the file descriptors in the child process doesn't throw off the
+  // synchronization between descriptors and buffers in the parent process.
+  // This is as close to the fork as possible to avoid a race condition in case
+  // there are multiple threads running before the death test, and another
+  // thread writes to the log file.
+  FlushInfoLog();
+
+  const pid_t child_pid = fork();
+  GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+  set_child_pid(child_pid);
+  if (child_pid == 0) {
+    GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
+    set_write_fd(pipe_fd[1]);
+    // Redirects all logging to stderr in the child process to prevent
+    // concurrent writes to the log files.  We capture stderr in the parent
+    // process and append the child process' output to a log.
+    LogToStderr();
+    return EXECUTE_TEST;
+  } else {
+    GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+    set_read_fd(pipe_fd[0]);
+    set_spawned(true);
+    return OVERSEE_TEST;
+  }
+}
+
+// A concrete death test class that forks and re-executes the main
+// program from the beginning, with command-line flags set that cause
+// only this specific death test to be run.
+class ExecDeathTest : public ForkingDeathTest {
+ public:
+  ExecDeathTest(const char* statement, const RE* regex,
+                const char* file, int line) :
+      ForkingDeathTest(statement, regex), file_(file), line_(line) { }
+  virtual TestRole AssumeRole();
+ private:
+  // The name of the file in which the death test is located.
+  const char* const file_;
+  // The line number on which the death test is located.
+  const int line_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+  Arguments() {
+    args_.push_back(NULL);
+  }
+
+  ~Arguments() {
+    for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+         ++i) {
+      free(*i);
+    }
+  }
+  void AddArgument(const char* argument) {
+    args_.insert(args_.end() - 1, posix::StrDup(argument));
+  }
+
+  template <typename Str>
+  void AddArguments(const ::std::vector<Str>& arguments) {
+    for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+         i != arguments.end();
+         ++i) {
+      args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+    }
+  }
+  char* const* Argv() {
+    return &args_[0];
+  }
+ private:
+  std::vector<char*> args_;
+};
+
+// A struct that encompasses the arguments to the child process of a
+// threadsafe-style death test process.
+struct ExecDeathTestArgs {
+  char* const* argv;  // Command-line arguments for the child's call to exec
+  int close_fd;       // File descriptor to close; the read end of a pipe
+};
+
+#if GTEST_OS_MAC
+inline char** GetEnviron() {
+  // When Google Test is built as a framework on MacOS X, the environ variable
+  // is unavailable. Apple's documentation (man environ) recommends using
+  // _NSGetEnviron() instead.
+  return *_NSGetEnviron();
+}
+#else
+// Some POSIX platforms expect you to declare environ. extern "C" makes
+// it reside in the global namespace.
+extern "C" char** environ;
+inline char** GetEnviron() { return environ; }
+#endif  // GTEST_OS_MAC
+
+// The main function for a threadsafe-style death test child process.
+// This function is called in a clone()-ed process and thus must avoid
+// any potentially unsafe operations like malloc or libc functions.
+static int ExecDeathTestChildMain(void* child_arg) {
+  ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
+
+  // We need to execute the test program in the same environment where
+  // it was originally invoked.  Therefore we change to the original
+  // working directory first.
+  const char* const original_dir =
+      UnitTest::GetInstance()->original_working_dir();
+  // We can safely call chdir() as it's a direct system call.
+  if (chdir(original_dir) != 0) {
+    DeathTestAbort(String::Format("chdir(\"%s\") failed: %s",
+                                  original_dir,
+                                  GetLastErrnoDescription().c_str()));
+    return EXIT_FAILURE;
+  }
+
+  // We can safely call execve() as it's a direct system call.  We
+  // cannot use execvp() as it's a libc function and thus potentially
+  // unsafe.  Since execve() doesn't search the PATH, the user must
+  // invoke the test program via a valid path that contains at least
+  // one path separator.
+  execve(args->argv[0], args->argv, GetEnviron());
+  DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s",
+                                args->argv[0],
+                                original_dir,
+                                GetLastErrnoDescription().c_str()));
+  return EXIT_FAILURE;
+}
+
+// Two utility routines that together determine the direction the stack
+// grows.
+// This could be accomplished more elegantly by a single recursive
+// function, but we want to guard against the unlikely possibility of
+// a smart compiler optimizing the recursion away.
+bool StackLowerThanAddress(const void* ptr) {
+  int dummy;
+  return &dummy < ptr;
+}
+
+bool StackGrowsDown() {
+  int dummy;
+  return StackLowerThanAddress(&dummy);
+}
+
+// A threadsafe implementation of fork(2) for threadsafe-style death tests
+// that uses clone(2).  It dies with an error message if anything goes
+// wrong.
+static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
+  ExecDeathTestArgs args = { argv, close_fd };
+  pid_t child_pid = -1;
+
+#if GTEST_HAS_CLONE
+  const bool use_fork = GTEST_FLAG(death_test_use_fork);
+
+  if (!use_fork) {
+    static const bool stack_grows_down = StackGrowsDown();
+    const size_t stack_size = getpagesize();
+    // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
+    void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
+                             MAP_ANON | MAP_PRIVATE, -1, 0);
+    GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
+    void* const stack_top =
+        static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0);
+
+    child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
+
+    GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
+  }
+#else
+  const bool use_fork = true;
+#endif  // GTEST_HAS_CLONE
+
+  if (use_fork && (child_pid = fork()) == 0) {
+      ExecDeathTestChildMain(&args);
+      _exit(0);
+  }
+
+  GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+  return child_pid;
+}
+
+// The AssumeRole process for a fork-and-exec death test.  It re-executes the
+// main program from the beginning, setting the --gtest_filter
+// and --gtest_internal_run_death_test flags to cause only the current
+// death test to be re-run.
+DeathTest::TestRole ExecDeathTest::AssumeRole() {
+  const UnitTestImpl* const impl = GetUnitTestImpl();
+  const InternalRunDeathTestFlag* const flag =
+      impl->internal_run_death_test_flag();
+  const TestInfo* const info = impl->current_test_info();
+  const int death_test_index = info->result()->death_test_count();
+
+  if (flag != NULL) {
+    set_write_fd(flag->write_fd());
+    return EXECUTE_TEST;
+  }
+
+  int pipe_fd[2];
+  GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+  // Clear the close-on-exec flag on the write end of the pipe, lest
+  // it be closed when the child process does an exec:
+  GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
+
+  const String filter_flag =
+      String::Format("--%s%s=%s.%s",
+                     GTEST_FLAG_PREFIX_, kFilterFlag,
+                     info->test_case_name(), info->name());
+  const String internal_flag =
+      String::Format("--%s%s=%s|%d|%d|%d",
+                     GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag,
+                     file_, line_, death_test_index, pipe_fd[1]);
+  Arguments args;
+  args.AddArguments(GetArgvs());
+  args.AddArgument(filter_flag.c_str());
+  args.AddArgument(internal_flag.c_str());
+
+  DeathTest::set_last_death_test_message("");
+
+  CaptureStderr();
+  // See the comment in NoExecDeathTest::AssumeRole for why the next line
+  // is necessary.
+  FlushInfoLog();
+
+  const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]);
+  GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+  set_child_pid(child_pid);
+  set_read_fd(pipe_fd[0]);
+  set_spawned(true);
+  return OVERSEE_TEST;
+}
+
+#endif  // !GTEST_OS_WINDOWS
+
+// Creates a concrete DeathTest-derived class that depends on the
+// --gtest_death_test_style flag, and sets the pointer pointed to
+// by the "test" argument to its address.  If the test should be
+// skipped, sets that pointer to NULL.  Returns true, unless the
+// flag is set to an invalid value.
+bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
+                                     const char* file, int line,
+                                     DeathTest** test) {
+  UnitTestImpl* const impl = GetUnitTestImpl();
+  const InternalRunDeathTestFlag* const flag =
+      impl->internal_run_death_test_flag();
+  const int death_test_index = impl->current_test_info()
+      ->increment_death_test_count();
+
+  if (flag != NULL) {
+    if (death_test_index > flag->index()) {
+      DeathTest::set_last_death_test_message(String::Format(
+          "Death test count (%d) somehow exceeded expected maximum (%d)",
+          death_test_index, flag->index()));
+      return false;
+    }
+
+    if (!(flag->file() == file && flag->line() == line &&
+          flag->index() == death_test_index)) {
+      *test = NULL;
+      return true;
+    }
+  }
+
+#if GTEST_OS_WINDOWS
+  if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+      GTEST_FLAG(death_test_style) == "fast") {
+    *test = new WindowsDeathTest(statement, regex, file, line);
+  }
+#else
+  if (GTEST_FLAG(death_test_style) == "threadsafe") {
+    *test = new ExecDeathTest(statement, regex, file, line);
+  } else if (GTEST_FLAG(death_test_style) == "fast") {
+    *test = new NoExecDeathTest(statement, regex);
+  }
+#endif  // GTEST_OS_WINDOWS
+  else {  // NOLINT - this is more readable than unbalanced brackets inside #if.
+    DeathTest::set_last_death_test_message(String::Format(
+        "Unknown death test style \"%s\" encountered",
+        GTEST_FLAG(death_test_style).c_str()));
+    return false;
+  }
+
+  return true;
+}
+
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields.  GTEST_HAS_DEATH_TEST implies that we have
+// ::std::string, so we can use it here.
+// TODO(vladl@google.com): Get rid of std::vector to be able to build on
+// Visual C++ 7.1 with exceptions disabled.
+static void SplitString(const ::std::string& str, char delimiter,
+                        ::std::vector< ::std::string>* dest) {
+  ::std::vector< ::std::string> parsed;
+  ::std::string::size_type pos = 0;
+  while (true) {
+    const ::std::string::size_type colon = str.find(delimiter, pos);
+    if (colon == ::std::string::npos) {
+      parsed.push_back(str.substr(pos));
+      break;
+    } else {
+      parsed.push_back(str.substr(pos, colon - pos));
+      pos = colon + 1;
+    }
+  }
+  dest->swap(parsed);
+}
+
+#if GTEST_OS_WINDOWS
+// Recreates the pipe and event handles from the provided parameters,
+// signals the event, and returns a file descriptor wrapped around the pipe
+// handle. This function is called in the child process only.
+int GetStatusFileDescriptor(unsigned int parent_process_id,
+                            size_t write_handle_as_size_t,
+                            size_t event_handle_as_size_t) {
+  AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
+                                                   FALSE,  // Non-inheritable.
+                                                   parent_process_id));
+  if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
+    DeathTestAbort(String::Format("Unable to open parent process %u",
+                                  parent_process_id));
+  }
+
+  // TODO(vladl@google.com): Replace the following check with a
+  // compile-time assertion when available.
+  GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
+
+  const HANDLE write_handle =
+      reinterpret_cast<HANDLE>(write_handle_as_size_t);
+  HANDLE dup_write_handle;
+
+  // The newly initialized handle is accessible only in in the parent
+  // process. To obtain one accessible within the child, we need to use
+  // DuplicateHandle.
+  if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
+                         ::GetCurrentProcess(), &dup_write_handle,
+                         0x0,    // Requested privileges ignored since
+                                 // DUPLICATE_SAME_ACCESS is used.
+                         FALSE,  // Request non-inheritable handler.
+                         DUPLICATE_SAME_ACCESS)) {
+    DeathTestAbort(String::Format(
+        "Unable to duplicate the pipe handle %Iu from the parent process %u",
+        write_handle_as_size_t, parent_process_id));
+  }
+
+  const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
+  HANDLE dup_event_handle;
+
+  if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,
+                         ::GetCurrentProcess(), &dup_event_handle,
+                         0x0,
+                         FALSE,
+                         DUPLICATE_SAME_ACCESS)) {
+    DeathTestAbort(String::Format(
+        "Unable to duplicate the event handle %Iu from the parent process %u",
+        event_handle_as_size_t, parent_process_id));
+  }
+
+  const int write_fd =
+      ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
+  if (write_fd == -1) {
+    DeathTestAbort(String::Format(
+        "Unable to convert pipe handle %Iu to a file descriptor",
+        write_handle_as_size_t));
+  }
+
+  // Signals the parent that the write end of the pipe has been acquired
+  // so the parent can release its own write end.
+  ::SetEvent(dup_event_handle);
+
+  return write_fd;
+}
+#endif  // GTEST_OS_WINDOWS
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
+  if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
+
+  // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+  // can use it here.
+  int line = -1;
+  int index = -1;
+  ::std::vector< ::std::string> fields;
+  SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
+  int write_fd = -1;
+
+#if GTEST_OS_WINDOWS
+  unsigned int parent_process_id = 0;
+  size_t write_handle_as_size_t = 0;
+  size_t event_handle_as_size_t = 0;
+
+  if (fields.size() != 6
+      || !ParseNaturalNumber(fields[1], &line)
+      || !ParseNaturalNumber(fields[2], &index)
+      || !ParseNaturalNumber(fields[3], &parent_process_id)
+      || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
+      || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
+    DeathTestAbort(String::Format(
+        "Bad --gtest_internal_run_death_test flag: %s",
+        GTEST_FLAG(internal_run_death_test).c_str()));
+  }
+  write_fd = GetStatusFileDescriptor(parent_process_id,
+                                     write_handle_as_size_t,
+                                     event_handle_as_size_t);
+#else
+  if (fields.size() != 4
+      || !ParseNaturalNumber(fields[1], &line)
+      || !ParseNaturalNumber(fields[2], &index)
+      || !ParseNaturalNumber(fields[3], &write_fd)) {
+    DeathTestAbort(String::Format(
+        "Bad --gtest_internal_run_death_test flag: %s",
+        GTEST_FLAG(internal_run_death_test).c_str()));
+  }
+#endif  // GTEST_OS_WINDOWS
+  return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
+}
+
+}  // namespace internal
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+}  // namespace testing
diff --git a/third_party/gtest/src/gtest-filepath.cc b/third_party/gtest/src/gtest-filepath.cc
index d3e530c..f966352 100644
--- a/third_party/gtest/src/gtest-filepath.cc
+++ b/third_party/gtest/src/gtest-filepath.cc
@@ -1,341 +1,341 @@
-// Copyright 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Authors: keith.ray@gmail.com (Keith Ray)

-

-#include <gtest/internal/gtest-filepath.h>

-#include <gtest/internal/gtest-port.h>

-

-#include <stdlib.h>

-

-#ifdef _WIN32_WCE

-#include <windows.h>

-#elif GTEST_OS_WINDOWS

-#include <direct.h>

-#include <io.h>

-#elif GTEST_OS_SYMBIAN

-// Symbian OpenC has PATH_MAX in sys/syslimits.h

-#include <sys/syslimits.h>

-#else

-#include <limits.h>

-#include <climits>  // Some Linux distributions define PATH_MAX here.

-#endif  // _WIN32_WCE or _WIN32

-

-#if GTEST_OS_WINDOWS

-#define GTEST_PATH_MAX_ _MAX_PATH

-#elif defined(PATH_MAX)

-#define GTEST_PATH_MAX_ PATH_MAX

-#elif defined(_XOPEN_PATH_MAX)

-#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX

-#else

-#define GTEST_PATH_MAX_ _POSIX_PATH_MAX

-#endif  // GTEST_OS_WINDOWS

-

-#include <gtest/internal/gtest-string.h>

-

-namespace testing {

-namespace internal {

-

-#if GTEST_OS_WINDOWS

-const char kPathSeparator = '\\';

-const char kPathSeparatorString[] = "\\";

-#ifdef _WIN32_WCE

-// Windows CE doesn't have a current directory. You should not use

-// the current directory in tests on Windows CE, but this at least

-// provides a reasonable fallback.

-const char kCurrentDirectoryString[] = "\\";

-// Windows CE doesn't define INVALID_FILE_ATTRIBUTES

-const DWORD kInvalidFileAttributes = 0xffffffff;

-#else

-const char kCurrentDirectoryString[] = ".\\";

-#endif  // _WIN32_WCE

-#else

-const char kPathSeparator = '/';

-const char kPathSeparatorString[] = "/";

-const char kCurrentDirectoryString[] = "./";

-#endif  // GTEST_OS_WINDOWS

-

-// Returns the current working directory, or "" if unsuccessful.

-FilePath FilePath::GetCurrentDir() {

-#ifdef _WIN32_WCE

-// Windows CE doesn't have a current directory, so we just return

-// something reasonable.

-  return FilePath(kCurrentDirectoryString);

-#elif GTEST_OS_WINDOWS

-  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };

-  return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);

-#else

-  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };

-  return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);

-#endif

-}

-

-// Returns a copy of the FilePath with the case-insensitive extension removed.

-// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns

-// FilePath("dir/file"). If a case-insensitive extension is not

-// found, returns a copy of the original FilePath.

-FilePath FilePath::RemoveExtension(const char* extension) const {

-  String dot_extension(String::Format(".%s", extension));

-  if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {

-    return FilePath(String(pathname_.c_str(), pathname_.GetLength() - 4));

-  }

-  return *this;

-}

-

-// Returns a copy of the FilePath with the directory part removed.

-// Example: FilePath("path/to/file").RemoveDirectoryName() returns

-// FilePath("file"). If there is no directory part ("just_a_file"), it returns

-// the FilePath unmodified. If there is no file part ("just_a_dir/") it

-// returns an empty FilePath ("").

-// On Windows platform, '\' is the path separator, otherwise it is '/'.

-FilePath FilePath::RemoveDirectoryName() const {

-  const char* const last_sep = strrchr(c_str(), kPathSeparator);

-  return last_sep ? FilePath(String(last_sep + 1)) : *this;

-}

-

-// RemoveFileName returns the directory path with the filename removed.

-// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".

-// If the FilePath is "a_file" or "/a_file", RemoveFileName returns

-// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does

-// not have a file, like "just/a/dir/", it returns the FilePath unmodified.

-// On Windows platform, '\' is the path separator, otherwise it is '/'.

-FilePath FilePath::RemoveFileName() const {

-  const char* const last_sep = strrchr(c_str(), kPathSeparator);

-  String dir;

-  if (last_sep) {

-    dir = String(c_str(), last_sep + 1 - c_str());

-  } else {

-    dir = kCurrentDirectoryString;

-  }

-  return FilePath(dir);

-}

-

-// Helper functions for naming files in a directory for xml output.

-

-// Given directory = "dir", base_name = "test", number = 0,

-// extension = "xml", returns "dir/test.xml". If number is greater

-// than zero (e.g., 12), returns "dir/test_12.xml".

-// On Windows platform, uses \ as the separator rather than /.

-FilePath FilePath::MakeFileName(const FilePath& directory,

-                                const FilePath& base_name,

-                                int number,

-                                const char* extension) {

-  String file;

-  if (number == 0) {

-    file = String::Format("%s.%s", base_name.c_str(), extension);

-  } else {

-    file = String::Format("%s_%d.%s", base_name.c_str(), number, extension);

-  }

-  return ConcatPaths(directory, FilePath(file));

-}

-

-// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".

-// On Windows, uses \ as the separator rather than /.

-FilePath FilePath::ConcatPaths(const FilePath& directory,

-                               const FilePath& relative_path) {

-  if (directory.IsEmpty())

-    return relative_path;

-  const FilePath dir(directory.RemoveTrailingPathSeparator());

-  return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator,

-                                 relative_path.c_str()));

-}

-

-// Returns true if pathname describes something findable in the file-system,

-// either a file, directory, or whatever.

-bool FilePath::FileOrDirectoryExists() const {

-#ifdef _WIN32_WCE

-  LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());

-  const DWORD attributes = GetFileAttributes(unicode);

-  delete [] unicode;

-  return attributes != kInvalidFileAttributes;

-#else

-  posix::StatStruct file_stat;

-  return posix::Stat(pathname_.c_str(), &file_stat) == 0;

-#endif  // _WIN32_WCE

-}

-

-// Returns true if pathname describes a directory in the file-system

-// that exists.

-bool FilePath::DirectoryExists() const {

-  bool result = false;

-#if GTEST_OS_WINDOWS

-  // Don't strip off trailing separator if path is a root directory on

-  // Windows (like "C:\\").

-  const FilePath& path(IsRootDirectory() ? *this :

-                                           RemoveTrailingPathSeparator());

-#else

-  const FilePath& path(*this);

-#endif

-

-#ifdef _WIN32_WCE

-  LPCWSTR unicode = String::AnsiToUtf16(path.c_str());

-  const DWORD attributes = GetFileAttributes(unicode);

-  delete [] unicode;

-  if ((attributes != kInvalidFileAttributes) &&

-      (attributes & FILE_ATTRIBUTE_DIRECTORY)) {

-    result = true;

-  }

-#else

-  posix::StatStruct file_stat;

-  result = posix::Stat(path.c_str(), &file_stat) == 0 &&

-      posix::IsDir(file_stat);

-#endif  // _WIN32_WCE

-

-  return result;

-}

-

-// Returns true if pathname describes a root directory. (Windows has one

-// root directory per disk drive.)

-bool FilePath::IsRootDirectory() const {

-#if GTEST_OS_WINDOWS

-  // TODO(wan@google.com): on Windows a network share like

-  // \\server\share can be a root directory, although it cannot be the

-  // current directory.  Handle this properly.

-  return pathname_.GetLength() == 3 && IsAbsolutePath();

-#else

-  return pathname_ == kPathSeparatorString;

-#endif

-}

-

-// Returns true if pathname describes an absolute path.

-bool FilePath::IsAbsolutePath() const {

-  const char* const name = pathname_.c_str();

-#if GTEST_OS_WINDOWS

-  return pathname_.GetLength() >= 3 &&

-     ((name[0] >= 'a' && name[0] <= 'z') ||

-      (name[0] >= 'A' && name[0] <= 'Z')) &&

-     name[1] == ':' &&

-     name[2] == kPathSeparator;

-#else

-  return name[0] == kPathSeparator;

-#endif

-}

-

-// Returns a pathname for a file that does not currently exist. The pathname

-// will be directory/base_name.extension or

-// directory/base_name_<number>.extension if directory/base_name.extension

-// already exists. The number will be incremented until a pathname is found

-// that does not already exist.

-// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.

-// There could be a race condition if two or more processes are calling this

-// function at the same time -- they could both pick the same filename.

-FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,

-                                          const FilePath& base_name,

-                                          const char* extension) {

-  FilePath full_pathname;

-  int number = 0;

-  do {

-    full_pathname.Set(MakeFileName(directory, base_name, number++, extension));

-  } while (full_pathname.FileOrDirectoryExists());

-  return full_pathname;

-}

-

-// Returns true if FilePath ends with a path separator, which indicates that

-// it is intended to represent a directory. Returns false otherwise.

-// This does NOT check that a directory (or file) actually exists.

-bool FilePath::IsDirectory() const {

-  return pathname_.EndsWith(kPathSeparatorString);

-}

-

-// Create directories so that path exists. Returns true if successful or if

-// the directories already exist; returns false if unable to create directories

-// for any reason.

-bool FilePath::CreateDirectoriesRecursively() const {

-  if (!this->IsDirectory()) {

-    return false;

-  }

-

-  if (pathname_.GetLength() == 0 || this->DirectoryExists()) {

-    return true;

-  }

-

-  const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());

-  return parent.CreateDirectoriesRecursively() && this->CreateFolder();

-}

-

-// Create the directory so that path exists. Returns true if successful or

-// if the directory already exists; returns false if unable to create the

-// directory for any reason, including if the parent directory does not

-// exist. Not named "CreateDirectory" because that's a macro on Windows.

-bool FilePath::CreateFolder() const {

-#if GTEST_OS_WINDOWS

-#ifdef _WIN32_WCE

-  FilePath removed_sep(this->RemoveTrailingPathSeparator());

-  LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());

-  int result = CreateDirectory(unicode, NULL) ? 0 : -1;

-  delete [] unicode;

-#else

-  int result = _mkdir(pathname_.c_str());

-#endif  // !WIN32_WCE

-#else

-  int result = mkdir(pathname_.c_str(), 0777);

-#endif  // _WIN32

-  if (result == -1) {

-    return this->DirectoryExists();  // An error is OK if the directory exists.

-  }

-  return true;  // No error.

-}

-

-// If input name has a trailing separator character, remove it and return the

-// name, otherwise return the name string unmodified.

-// On Windows platform, uses \ as the separator, other platforms use /.

-FilePath FilePath::RemoveTrailingPathSeparator() const {

-  return pathname_.EndsWith(kPathSeparatorString)

-      ? FilePath(String(pathname_.c_str(), pathname_.GetLength() - 1))

-      : *this;

-}

-

-// Normalize removes any redundant separators that might be in the pathname.

-// For example, "bar///foo" becomes "bar/foo". Does not eliminate other

-// redundancies that might be in a pathname involving "." or "..".

-void FilePath::Normalize() {

-  if (pathname_.c_str() == NULL) {

-    pathname_ = "";

-    return;

-  }

-  const char* src = pathname_.c_str();

-  char* const dest = new char[pathname_.GetLength() + 1];

-  char* dest_ptr = dest;

-  memset(dest_ptr, 0, pathname_.GetLength() + 1);

-

-  while (*src != '\0') {

-    *dest_ptr++ = *src;

-    if (*src != kPathSeparator)

-      src++;

-    else

-      while (*src == kPathSeparator)

-        src++;

-  }

-  *dest_ptr = '\0';

-  pathname_ = dest;

-  delete[] dest;

-}

-

-}  // namespace internal

-}  // namespace testing

+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: keith.ray@gmail.com (Keith Ray)
+
+#include <gtest/internal/gtest-filepath.h>
+#include <gtest/internal/gtest-port.h>
+
+#include <stdlib.h>
+
+#ifdef _WIN32_WCE
+#include <windows.h>
+#elif GTEST_OS_WINDOWS
+#include <direct.h>
+#include <io.h>
+#elif GTEST_OS_SYMBIAN
+// Symbian OpenC has PATH_MAX in sys/syslimits.h
+#include <sys/syslimits.h>
+#else
+#include <limits.h>
+#include <climits>  // Some Linux distributions define PATH_MAX here.
+#endif  // _WIN32_WCE or _WIN32
+
+#if GTEST_OS_WINDOWS
+#define GTEST_PATH_MAX_ _MAX_PATH
+#elif defined(PATH_MAX)
+#define GTEST_PATH_MAX_ PATH_MAX
+#elif defined(_XOPEN_PATH_MAX)
+#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
+#else
+#define GTEST_PATH_MAX_ _POSIX_PATH_MAX
+#endif  // GTEST_OS_WINDOWS
+
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+const char kPathSeparator = '\\';
+const char kPathSeparatorString[] = "\\";
+#ifdef _WIN32_WCE
+// Windows CE doesn't have a current directory. You should not use
+// the current directory in tests on Windows CE, but this at least
+// provides a reasonable fallback.
+const char kCurrentDirectoryString[] = "\\";
+// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
+const DWORD kInvalidFileAttributes = 0xffffffff;
+#else
+const char kCurrentDirectoryString[] = ".\\";
+#endif  // _WIN32_WCE
+#else
+const char kPathSeparator = '/';
+const char kPathSeparatorString[] = "/";
+const char kCurrentDirectoryString[] = "./";
+#endif  // GTEST_OS_WINDOWS
+
+// Returns the current working directory, or "" if unsuccessful.
+FilePath FilePath::GetCurrentDir() {
+#ifdef _WIN32_WCE
+// Windows CE doesn't have a current directory, so we just return
+// something reasonable.
+  return FilePath(kCurrentDirectoryString);
+#elif GTEST_OS_WINDOWS
+  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+  return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#else
+  char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+  return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#endif
+}
+
+// Returns a copy of the FilePath with the case-insensitive extension removed.
+// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+// FilePath("dir/file"). If a case-insensitive extension is not
+// found, returns a copy of the original FilePath.
+FilePath FilePath::RemoveExtension(const char* extension) const {
+  String dot_extension(String::Format(".%s", extension));
+  if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {
+    return FilePath(String(pathname_.c_str(), pathname_.GetLength() - 4));
+  }
+  return *this;
+}
+
+// Returns a copy of the FilePath with the directory part removed.
+// Example: FilePath("path/to/file").RemoveDirectoryName() returns
+// FilePath("file"). If there is no directory part ("just_a_file"), it returns
+// the FilePath unmodified. If there is no file part ("just_a_dir/") it
+// returns an empty FilePath ("").
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveDirectoryName() const {
+  const char* const last_sep = strrchr(c_str(), kPathSeparator);
+  return last_sep ? FilePath(String(last_sep + 1)) : *this;
+}
+
+// RemoveFileName returns the directory path with the filename removed.
+// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveFileName() const {
+  const char* const last_sep = strrchr(c_str(), kPathSeparator);
+  String dir;
+  if (last_sep) {
+    dir = String(c_str(), last_sep + 1 - c_str());
+  } else {
+    dir = kCurrentDirectoryString;
+  }
+  return FilePath(dir);
+}
+
+// Helper functions for naming files in a directory for xml output.
+
+// Given directory = "dir", base_name = "test", number = 0,
+// extension = "xml", returns "dir/test.xml". If number is greater
+// than zero (e.g., 12), returns "dir/test_12.xml".
+// On Windows platform, uses \ as the separator rather than /.
+FilePath FilePath::MakeFileName(const FilePath& directory,
+                                const FilePath& base_name,
+                                int number,
+                                const char* extension) {
+  String file;
+  if (number == 0) {
+    file = String::Format("%s.%s", base_name.c_str(), extension);
+  } else {
+    file = String::Format("%s_%d.%s", base_name.c_str(), number, extension);
+  }
+  return ConcatPaths(directory, FilePath(file));
+}
+
+// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
+// On Windows, uses \ as the separator rather than /.
+FilePath FilePath::ConcatPaths(const FilePath& directory,
+                               const FilePath& relative_path) {
+  if (directory.IsEmpty())
+    return relative_path;
+  const FilePath dir(directory.RemoveTrailingPathSeparator());
+  return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator,
+                                 relative_path.c_str()));
+}
+
+// Returns true if pathname describes something findable in the file-system,
+// either a file, directory, or whatever.
+bool FilePath::FileOrDirectoryExists() const {
+#ifdef _WIN32_WCE
+  LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
+  const DWORD attributes = GetFileAttributes(unicode);
+  delete [] unicode;
+  return attributes != kInvalidFileAttributes;
+#else
+  posix::StatStruct file_stat;
+  return posix::Stat(pathname_.c_str(), &file_stat) == 0;
+#endif  // _WIN32_WCE
+}
+
+// Returns true if pathname describes a directory in the file-system
+// that exists.
+bool FilePath::DirectoryExists() const {
+  bool result = false;
+#if GTEST_OS_WINDOWS
+  // Don't strip off trailing separator if path is a root directory on
+  // Windows (like "C:\\").
+  const FilePath& path(IsRootDirectory() ? *this :
+                                           RemoveTrailingPathSeparator());
+#else
+  const FilePath& path(*this);
+#endif
+
+#ifdef _WIN32_WCE
+  LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
+  const DWORD attributes = GetFileAttributes(unicode);
+  delete [] unicode;
+  if ((attributes != kInvalidFileAttributes) &&
+      (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+    result = true;
+  }
+#else
+  posix::StatStruct file_stat;
+  result = posix::Stat(path.c_str(), &file_stat) == 0 &&
+      posix::IsDir(file_stat);
+#endif  // _WIN32_WCE
+
+  return result;
+}
+
+// Returns true if pathname describes a root directory. (Windows has one
+// root directory per disk drive.)
+bool FilePath::IsRootDirectory() const {
+#if GTEST_OS_WINDOWS
+  // TODO(wan@google.com): on Windows a network share like
+  // \\server\share can be a root directory, although it cannot be the
+  // current directory.  Handle this properly.
+  return pathname_.GetLength() == 3 && IsAbsolutePath();
+#else
+  return pathname_ == kPathSeparatorString;
+#endif
+}
+
+// Returns true if pathname describes an absolute path.
+bool FilePath::IsAbsolutePath() const {
+  const char* const name = pathname_.c_str();
+#if GTEST_OS_WINDOWS
+  return pathname_.GetLength() >= 3 &&
+     ((name[0] >= 'a' && name[0] <= 'z') ||
+      (name[0] >= 'A' && name[0] <= 'Z')) &&
+     name[1] == ':' &&
+     name[2] == kPathSeparator;
+#else
+  return name[0] == kPathSeparator;
+#endif
+}
+
+// Returns a pathname for a file that does not currently exist. The pathname
+// will be directory/base_name.extension or
+// directory/base_name_<number>.extension if directory/base_name.extension
+// already exists. The number will be incremented until a pathname is found
+// that does not already exist.
+// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+// There could be a race condition if two or more processes are calling this
+// function at the same time -- they could both pick the same filename.
+FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
+                                          const FilePath& base_name,
+                                          const char* extension) {
+  FilePath full_pathname;
+  int number = 0;
+  do {
+    full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
+  } while (full_pathname.FileOrDirectoryExists());
+  return full_pathname;
+}
+
+// Returns true if FilePath ends with a path separator, which indicates that
+// it is intended to represent a directory. Returns false otherwise.
+// This does NOT check that a directory (or file) actually exists.
+bool FilePath::IsDirectory() const {
+  return pathname_.EndsWith(kPathSeparatorString);
+}
+
+// Create directories so that path exists. Returns true if successful or if
+// the directories already exist; returns false if unable to create directories
+// for any reason.
+bool FilePath::CreateDirectoriesRecursively() const {
+  if (!this->IsDirectory()) {
+    return false;
+  }
+
+  if (pathname_.GetLength() == 0 || this->DirectoryExists()) {
+    return true;
+  }
+
+  const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
+  return parent.CreateDirectoriesRecursively() && this->CreateFolder();
+}
+
+// Create the directory so that path exists. Returns true if successful or
+// if the directory already exists; returns false if unable to create the
+// directory for any reason, including if the parent directory does not
+// exist. Not named "CreateDirectory" because that's a macro on Windows.
+bool FilePath::CreateFolder() const {
+#if GTEST_OS_WINDOWS
+#ifdef _WIN32_WCE
+  FilePath removed_sep(this->RemoveTrailingPathSeparator());
+  LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
+  int result = CreateDirectory(unicode, NULL) ? 0 : -1;
+  delete [] unicode;
+#else
+  int result = _mkdir(pathname_.c_str());
+#endif  // !WIN32_WCE
+#else
+  int result = mkdir(pathname_.c_str(), 0777);
+#endif  // _WIN32
+  if (result == -1) {
+    return this->DirectoryExists();  // An error is OK if the directory exists.
+  }
+  return true;  // No error.
+}
+
+// If input name has a trailing separator character, remove it and return the
+// name, otherwise return the name string unmodified.
+// On Windows platform, uses \ as the separator, other platforms use /.
+FilePath FilePath::RemoveTrailingPathSeparator() const {
+  return pathname_.EndsWith(kPathSeparatorString)
+      ? FilePath(String(pathname_.c_str(), pathname_.GetLength() - 1))
+      : *this;
+}
+
+// Normalize removes any redundant separators that might be in the pathname.
+// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+// redundancies that might be in a pathname involving "." or "..".
+void FilePath::Normalize() {
+  if (pathname_.c_str() == NULL) {
+    pathname_ = "";
+    return;
+  }
+  const char* src = pathname_.c_str();
+  char* const dest = new char[pathname_.GetLength() + 1];
+  char* dest_ptr = dest;
+  memset(dest_ptr, 0, pathname_.GetLength() + 1);
+
+  while (*src != '\0') {
+    *dest_ptr++ = *src;
+    if (*src != kPathSeparator)
+      src++;
+    else
+      while (*src == kPathSeparator)
+        src++;
+  }
+  *dest_ptr = '\0';
+  pathname_ = dest;
+  delete[] dest;
+}
+
+}  // namespace internal
+}  // namespace testing
diff --git a/third_party/gtest/src/gtest-internal-inl.h b/third_party/gtest/src/gtest-internal-inl.h
index d3282b0..26d1bd1 100644
--- a/third_party/gtest/src/gtest-internal-inl.h
+++ b/third_party/gtest/src/gtest-internal-inl.h
@@ -1,1417 +1,1417 @@
-// Copyright 2005, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-

-// Utility functions and classes used by the Google C++ testing framework.

-//

-// Author: wan@google.com (Zhanyong Wan)

-//

-// This file contains purely Google Test's internal implementation.  Please

-// DO NOT #INCLUDE IT IN A USER PROGRAM.

-

-#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_

-#define GTEST_SRC_GTEST_INTERNAL_INL_H_

-

-// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is

-// part of Google Test's implementation; otherwise it's undefined.

-#if !GTEST_IMPLEMENTATION_

-// A user is trying to include this from his code - just say no.

-#error "gtest-internal-inl.h is part of Google Test's internal implementation."

-#error "It must not be included except by Google Test itself."

-#endif  // GTEST_IMPLEMENTATION_

-

-#include <errno.h>

-#include <stddef.h>

-#include <stdlib.h>   // For strtoll/_strtoul64.

-

-#include <string>

-

-#include <gtest/internal/gtest-port.h>

-

-#if GTEST_OS_WINDOWS

-#include <windows.h>  // For DWORD.

-#endif  // GTEST_OS_WINDOWS

-

-#include <gtest/gtest.h>

-#include <gtest/gtest-spi.h>

-

-namespace testing {

-

-// Declares the flags.

-//

-// We don't want the users to modify this flag in the code, but want

-// Google Test's own unit tests to be able to access it. Therefore we

-// declare it here as opposed to in gtest.h.

-GTEST_DECLARE_bool_(death_test_use_fork);

-

-namespace internal {

-

-// The value of GetTestTypeId() as seen from within the Google Test

-// library.  This is solely for testing GetTestTypeId().

-extern const TypeId kTestTypeIdInGoogleTest;

-

-// Names of the flags (needed for parsing Google Test flags).

-const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";

-const char kBreakOnFailureFlag[] = "break_on_failure";

-const char kCatchExceptionsFlag[] = "catch_exceptions";

-const char kColorFlag[] = "color";

-const char kFilterFlag[] = "filter";

-const char kListTestsFlag[] = "list_tests";

-const char kOutputFlag[] = "output";

-const char kPrintTimeFlag[] = "print_time";

-const char kRepeatFlag[] = "repeat";

-const char kThrowOnFailureFlag[] = "throw_on_failure";

-

-// This class saves the values of all Google Test flags in its c'tor, and

-// restores them in its d'tor.

-class GTestFlagSaver {

- public:

-  // The c'tor.

-  GTestFlagSaver() {

-    also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests);

-    break_on_failure_ = GTEST_FLAG(break_on_failure);

-    catch_exceptions_ = GTEST_FLAG(catch_exceptions);

-    color_ = GTEST_FLAG(color);

-    death_test_style_ = GTEST_FLAG(death_test_style);

-    death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);

-    filter_ = GTEST_FLAG(filter);

-    internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);

-    list_tests_ = GTEST_FLAG(list_tests);

-    output_ = GTEST_FLAG(output);

-    print_time_ = GTEST_FLAG(print_time);

-    repeat_ = GTEST_FLAG(repeat);

-    throw_on_failure_ = GTEST_FLAG(throw_on_failure);

-  }

-

-  // The d'tor is not virtual.  DO NOT INHERIT FROM THIS CLASS.

-  ~GTestFlagSaver() {

-    GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_;

-    GTEST_FLAG(break_on_failure) = break_on_failure_;

-    GTEST_FLAG(catch_exceptions) = catch_exceptions_;

-    GTEST_FLAG(color) = color_;

-    GTEST_FLAG(death_test_style) = death_test_style_;

-    GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;

-    GTEST_FLAG(filter) = filter_;

-    GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;

-    GTEST_FLAG(list_tests) = list_tests_;

-    GTEST_FLAG(output) = output_;

-    GTEST_FLAG(print_time) = print_time_;

-    GTEST_FLAG(repeat) = repeat_;

-    GTEST_FLAG(throw_on_failure) = throw_on_failure_;

-  }

- private:

-  // Fields for saving the original values of flags.

-  bool also_run_disabled_tests_;

-  bool break_on_failure_;

-  bool catch_exceptions_;

-  String color_;

-  String death_test_style_;

-  bool death_test_use_fork_;

-  String filter_;

-  String internal_run_death_test_;

-  bool list_tests_;

-  String output_;

-  bool print_time_;

-  bool pretty_;

-  internal::Int32 repeat_;

-  bool throw_on_failure_;

-} GTEST_ATTRIBUTE_UNUSED_;

-

-// Converts a Unicode code point to a narrow string in UTF-8 encoding.

-// code_point parameter is of type UInt32 because wchar_t may not be

-// wide enough to contain a code point.

-// The output buffer str must containt at least 32 characters.

-// The function returns the address of the output buffer.

-// If the code_point is not a valid Unicode code point

-// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output

-// as '(Invalid Unicode 0xXXXXXXXX)'.

-char* CodePointToUtf8(UInt32 code_point, char* str);

-

-// Converts a wide string to a narrow string in UTF-8 encoding.

-// The wide string is assumed to have the following encoding:

-//   UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)

-//   UTF-32 if sizeof(wchar_t) == 4 (on Linux)

-// Parameter str points to a null-terminated wide string.

-// Parameter num_chars may additionally limit the number

-// of wchar_t characters processed. -1 is used when the entire string

-// should be processed.

-// If the string contains code points that are not valid Unicode code points

-// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output

-// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding

-// and contains invalid UTF-16 surrogate pairs, values in those pairs

-// will be encoded as individual Unicode characters from Basic Normal Plane.

-String WideStringToUtf8(const wchar_t* str, int num_chars);

-

-// Returns the number of active threads, or 0 when there is an error.

-size_t GetThreadCount();

-

-// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file

-// if the variable is present. If a file already exists at this location, this

-// function will write over it. If the variable is present, but the file cannot

-// be created, prints an error and exits.

-void WriteToShardStatusFileIfNeeded();

-

-// Checks whether sharding is enabled by examining the relevant

-// environment variable values. If the variables are present,

-// but inconsistent (e.g., shard_index >= total_shards), prints

-// an error and exits. If in_subprocess_for_death_test, sharding is

-// disabled because it must only be applied to the original test

-// process. Otherwise, we could filter out death tests we intended to execute.

-bool ShouldShard(const char* total_shards_str, const char* shard_index_str,

-                 bool in_subprocess_for_death_test);

-

-// Parses the environment variable var as an Int32. If it is unset,

-// returns default_val. If it is not an Int32, prints an error and

-// and aborts.

-Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);

-

-// Given the total number of shards, the shard index, and the test id,

-// returns true iff the test should be run on this shard. The test id is

-// some arbitrary but unique non-negative integer assigned to each test

-// method. Assumes that 0 <= shard_index < total_shards.

-bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id);

-

-// List is a simple singly-linked list container.

-//

-// We cannot use std::list as Microsoft's implementation of STL has

-// problems when exception is disabled.  There is a hack to work

-// around this, but we've seen cases where the hack fails to work.

-//

-// TODO(wan): switch to std::list when we have a reliable fix for the

-// STL problem, e.g. when we upgrade to the next version of Visual

-// C++, or (more likely) switch to STLport.

-//

-// The element type must support copy constructor.

-

-// Forward declare List

-template <typename E>  // E is the element type.

-class List;

-

-// ListNode is a node in a singly-linked list.  It consists of an

-// element and a pointer to the next node.  The last node in the list

-// has a NULL value for its next pointer.

-template <typename E>  // E is the element type.

-class ListNode {

-  friend class List<E>;

-

- private:

-

-  E element_;

-  ListNode * next_;

-

-  // The c'tor is private s.t. only in the ListNode class and in its

-  // friend class List we can create a ListNode object.

-  //

-  // Creates a node with a given element value.  The next pointer is

-  // set to NULL.

-  //

-  // ListNode does NOT have a default constructor.  Always use this

-  // constructor (with parameter) to create a ListNode object.

-  explicit ListNode(const E & element) : element_(element), next_(NULL) {}

-

-  // We disallow copying ListNode

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(ListNode);

-

- public:

-

-  // Gets the element in this node.

-  E & element() { return element_; }

-  const E & element() const { return element_; }

-

-  // Gets the next node in the list.

-  ListNode * next() { return next_; }

-  const ListNode * next() const { return next_; }

-};

-

-

-// List is a simple singly-linked list container.

-template <typename E>  // E is the element type.

-class List {

- public:

-

-  // Creates an empty list.

-  List() : head_(NULL), last_(NULL), size_(0) {}

-

-  // D'tor.

-  virtual ~List();

-

-  // Clears the list.

-  void Clear() {

-    if ( size_ > 0 ) {

-      // 1. Deletes every node.

-      ListNode<E> * node = head_;

-      ListNode<E> * next = node->next();

-      for ( ; ; ) {

-        delete node;

-        node = next;

-        if ( node == NULL ) break;

-        next = node->next();

-      }

-

-      // 2. Resets the member variables.

-      head_ = last_ = NULL;

-      size_ = 0;

-    }

-  }

-

-  // Gets the number of elements.

-  int size() const { return size_; }

-

-  // Returns true if the list is empty.

-  bool IsEmpty() const { return size() == 0; }

-

-  // Gets the first element of the list, or NULL if the list is empty.

-  ListNode<E> * Head() { return head_; }

-  const ListNode<E> * Head() const { return head_; }

-

-  // Gets the last element of the list, or NULL if the list is empty.

-  ListNode<E> * Last() { return last_; }

-  const ListNode<E> * Last() const { return last_; }

-

-  // Adds an element to the end of the list.  A copy of the element is

-  // created using the copy constructor, and then stored in the list.

-  // Changes made to the element in the list doesn't affect the source

-  // object, and vice versa.

-  void PushBack(const E & element) {

-    ListNode<E> * new_node = new ListNode<E>(element);

-

-    if ( size_ == 0 ) {

-      head_ = last_ = new_node;

-      size_ = 1;

-    } else {

-      last_->next_ = new_node;

-      last_ = new_node;

-      size_++;

-    }

-  }

-

-  // Adds an element to the beginning of this list.

-  void PushFront(const E& element) {

-    ListNode<E>* const new_node = new ListNode<E>(element);

-

-    if ( size_ == 0 ) {

-      head_ = last_ = new_node;

-      size_ = 1;

-    } else {

-      new_node->next_ = head_;

-      head_ = new_node;

-      size_++;

-    }

-  }

-

-  // Removes an element from the beginning of this list.  If the

-  // result argument is not NULL, the removed element is stored in the

-  // memory it points to.  Otherwise the element is thrown away.

-  // Returns true iff the list wasn't empty before the operation.

-  bool PopFront(E* result) {

-    if (size_ == 0) return false;

-

-    if (result != NULL) {

-      *result = head_->element_;

-    }

-

-    ListNode<E>* const old_head = head_;

-    size_--;

-    if (size_ == 0) {

-      head_ = last_ = NULL;

-    } else {

-      head_ = head_->next_;

-    }

-    delete old_head;

-

-    return true;

-  }

-

-  // Inserts an element after a given node in the list.  It's the

-  // caller's responsibility to ensure that the given node is in the

-  // list.  If the given node is NULL, inserts the element at the

-  // front of the list.

-  ListNode<E>* InsertAfter(ListNode<E>* node, const E& element) {

-    if (node == NULL) {

-      PushFront(element);

-      return Head();

-    }

-

-    ListNode<E>* const new_node = new ListNode<E>(element);

-    new_node->next_ = node->next_;

-    node->next_ = new_node;

-    size_++;

-    if (node == last_) {

-      last_ = new_node;

-    }

-

-    return new_node;

-  }

-

-  // Returns the number of elements that satisfy a given predicate.

-  // The parameter 'predicate' is a Boolean function or functor that

-  // accepts a 'const E &', where E is the element type.

-  template <typename P>  // P is the type of the predicate function/functor

-  int CountIf(P predicate) const {

-    int count = 0;

-    for ( const ListNode<E> * node = Head();

-          node != NULL;

-          node = node->next() ) {

-      if ( predicate(node->element()) ) {

-        count++;

-      }

-    }

-

-    return count;

-  }

-

-  // Applies a function/functor to each element in the list.  The

-  // parameter 'functor' is a function/functor that accepts a 'const

-  // E &', where E is the element type.  This method does not change

-  // the elements.

-  template <typename F>  // F is the type of the function/functor

-  void ForEach(F functor) const {

-    for ( const ListNode<E> * node = Head();

-          node != NULL;

-          node = node->next() ) {

-      functor(node->element());

-    }

-  }

-

-  // Returns the first node whose element satisfies a given predicate,

-  // or NULL if none is found.  The parameter 'predicate' is a

-  // function/functor that accepts a 'const E &', where E is the

-  // element type.  This method does not change the elements.

-  template <typename P>  // P is the type of the predicate function/functor.

-  const ListNode<E> * FindIf(P predicate) const {

-    for ( const ListNode<E> * node = Head();

-          node != NULL;

-          node = node->next() ) {

-      if ( predicate(node->element()) ) {

-        return node;

-      }

-    }

-

-    return NULL;

-  }

-

-  template <typename P>

-  ListNode<E> * FindIf(P predicate) {

-    for ( ListNode<E> * node = Head();

-          node != NULL;

-          node = node->next() ) {

-      if ( predicate(node->element() ) ) {

-        return node;

-      }

-    }

-

-    return NULL;

-  }

-

- private:

-  ListNode<E>* head_;  // The first node of the list.

-  ListNode<E>* last_;  // The last node of the list.

-  int size_;           // The number of elements in the list.

-

-  // We disallow copying List.

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(List);

-};

-

-// The virtual destructor of List.

-template <typename E>

-List<E>::~List() {

-  Clear();

-}

-

-// A function for deleting an object.  Handy for being used as a

-// functor.

-template <typename T>

-static void Delete(T * x) {

-  delete x;

-}

-

-// A copyable object representing a user specified test property which can be

-// output as a key/value string pair.

-//

-// Don't inherit from TestProperty as its destructor is not virtual.

-class TestProperty {

- public:

-  // C'tor.  TestProperty does NOT have a default constructor.

-  // Always use this constructor (with parameters) to create a

-  // TestProperty object.

-  TestProperty(const char* key, const char* value) :

-    key_(key), value_(value) {

-  }

-

-  // Gets the user supplied key.

-  const char* key() const {

-    return key_.c_str();

-  }

-

-  // Gets the user supplied value.

-  const char* value() const {

-    return value_.c_str();

-  }

-

-  // Sets a new value, overriding the one supplied in the constructor.

-  void SetValue(const char* new_value) {

-    value_ = new_value;

-  }

-

- private:

-  // The key supplied by the user.

-  String key_;

-  // The value supplied by the user.

-  String value_;

-};

-

-// A predicate that checks the key of a TestProperty against a known key.

-//

-// TestPropertyKeyIs is copyable.

-class TestPropertyKeyIs {

- public:

-  // Constructor.

-  //

-  // TestPropertyKeyIs has NO default constructor.

-  explicit TestPropertyKeyIs(const char* key)

-      : key_(key) {}

-

-  // Returns true iff the test name of test property matches on key_.

-  bool operator()(const TestProperty& test_property) const {

-    return String(test_property.key()).Compare(key_) == 0;

-  }

-

- private:

-  String key_;

-};

-

-// The result of a single Test.  This includes a list of

-// TestPartResults, a list of TestProperties, a count of how many

-// death tests there are in the Test, and how much time it took to run

-// the Test.

-//

-// TestResult is not copyable.

-class TestResult {

- public:

-  // Creates an empty TestResult.

-  TestResult();

-

-  // D'tor.  Do not inherit from TestResult.

-  ~TestResult();

-

-  // Gets the list of TestPartResults.

-  const internal::List<TestPartResult> & test_part_results() const {

-    return test_part_results_;

-  }

-

-  // Gets the list of TestProperties.

-  const internal::List<internal::TestProperty> & test_properties() const {

-    return test_properties_;

-  }

-

-  // Gets the number of successful test parts.

-  int successful_part_count() const;

-

-  // Gets the number of failed test parts.

-  int failed_part_count() const;

-

-  // Gets the number of all test parts.  This is the sum of the number

-  // of successful test parts and the number of failed test parts.

-  int total_part_count() const;

-

-  // Returns true iff the test passed (i.e. no test part failed).

-  bool Passed() const { return !Failed(); }

-

-  // Returns true iff the test failed.

-  bool Failed() const { return failed_part_count() > 0; }

-

-  // Returns true iff the test fatally failed.

-  bool HasFatalFailure() const;

-

-  // Returns true iff the test has a non-fatal failure.

-  bool HasNonfatalFailure() const;

-

-  // Returns the elapsed time, in milliseconds.

-  TimeInMillis elapsed_time() const { return elapsed_time_; }

-

-  // Sets the elapsed time.

-  void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }

-

-  // Adds a test part result to the list.

-  void AddTestPartResult(const TestPartResult& test_part_result);

-

-  // Adds a test property to the list. The property is validated and may add

-  // a non-fatal failure if invalid (e.g., if it conflicts with reserved

-  // key names). If a property is already recorded for the same key, the

-  // value will be updated, rather than storing multiple values for the same

-  // key.

-  void RecordProperty(const internal::TestProperty& test_property);

-

-  // Adds a failure if the key is a reserved attribute of Google Test

-  // testcase tags.  Returns true if the property is valid.

-  // TODO(russr): Validate attribute names are legal and human readable.

-  static bool ValidateTestProperty(const internal::TestProperty& test_property);

-

-  // Returns the death test count.

-  int death_test_count() const { return death_test_count_; }

-

-  // Increments the death test count, returning the new count.

-  int increment_death_test_count() { return ++death_test_count_; }

-

-  // Clears the test part results.

-  void ClearTestPartResults() { test_part_results_.Clear(); }

-

-  // Clears the object.

-  void Clear();

- private:

-  // Protects mutable state of the property list and of owned properties, whose

-  // values may be updated.

-  internal::Mutex test_properites_mutex_;

-

-  // The list of TestPartResults

-  internal::List<TestPartResult> test_part_results_;

-  // The list of TestProperties

-  internal::List<internal::TestProperty> test_properties_;

-  // Running count of death tests.

-  int death_test_count_;

-  // The elapsed time, in milliseconds.

-  TimeInMillis elapsed_time_;

-

-  // We disallow copying TestResult.

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);

-};  // class TestResult

-

-class TestInfoImpl {

- public:

-  TestInfoImpl(TestInfo* parent, const char* test_case_name,

-               const char* name, const char* test_case_comment,

-               const char* comment, TypeId fixture_class_id,

-               internal::TestFactoryBase* factory);

-  ~TestInfoImpl();

-

-  // Returns true if this test should run.

-  bool should_run() const { return should_run_; }

-

-  // Sets the should_run member.

-  void set_should_run(bool should) { should_run_ = should; }

-

-  // Returns true if this test is disabled. Disabled tests are not run.

-  bool is_disabled() const { return is_disabled_; }

-

-  // Sets the is_disabled member.

-  void set_is_disabled(bool is) { is_disabled_ = is; }

-

-  // Returns true if this test matches the filter specified by the user.

-  bool matches_filter() const { return matches_filter_; }

-

-  // Sets the matches_filter member.

-  void set_matches_filter(bool matches) { matches_filter_ = matches; }

-

-  // Returns the test case name.

-  const char* test_case_name() const { return test_case_name_.c_str(); }

-

-  // Returns the test name.

-  const char* name() const { return name_.c_str(); }

-

-  // Returns the test case comment.

-  const char* test_case_comment() const { return test_case_comment_.c_str(); }

-

-  // Returns the test comment.

-  const char* comment() const { return comment_.c_str(); }

-

-  // Returns the ID of the test fixture class.

-  TypeId fixture_class_id() const { return fixture_class_id_; }

-

-  // Returns the test result.

-  internal::TestResult* result() { return &result_; }

-  const internal::TestResult* result() const { return &result_; }

-

-  // Creates the test object, runs it, records its result, and then

-  // deletes it.

-  void Run();

-

-  // Calls the given TestInfo object's Run() method.

-  static void RunTest(TestInfo * test_info) {

-    test_info->impl()->Run();

-  }

-

-  // Clears the test result.

-  void ClearResult() { result_.Clear(); }

-

-  // Clears the test result in the given TestInfo object.

-  static void ClearTestResult(TestInfo * test_info) {

-    test_info->impl()->ClearResult();

-  }

-

- private:

-  // These fields are immutable properties of the test.

-  TestInfo* const parent_;          // The owner of this object

-  const String test_case_name_;     // Test case name

-  const String name_;               // Test name

-  const String test_case_comment_;  // Test case comment

-  const String comment_;            // Test comment

-  const TypeId fixture_class_id_;   // ID of the test fixture class

-  bool should_run_;                 // True iff this test should run

-  bool is_disabled_;                // True iff this test is disabled

-  bool matches_filter_;             // True if this test matches the

-                                    // user-specified filter.

-  internal::TestFactoryBase* const factory_;  // The factory that creates

-                                              // the test object

-

-  // This field is mutable and needs to be reset before running the

-  // test for the second time.

-  internal::TestResult result_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl);

-};

-

-}  // namespace internal

-

-// A test case, which consists of a list of TestInfos.

-//

-// TestCase is not copyable.

-class TestCase {

- public:

-  // Creates a TestCase with the given name.

-  //

-  // TestCase does NOT have a default constructor.  Always use this

-  // constructor to create a TestCase object.

-  //

-  // Arguments:

-  //

-  //   name:         name of the test case

-  //   set_up_tc:    pointer to the function that sets up the test case

-  //   tear_down_tc: pointer to the function that tears down the test case

-  TestCase(const char* name, const char* comment,

-           Test::SetUpTestCaseFunc set_up_tc,

-           Test::TearDownTestCaseFunc tear_down_tc);

-

-  // Destructor of TestCase.

-  virtual ~TestCase();

-

-  // Gets the name of the TestCase.

-  const char* name() const { return name_.c_str(); }

-

-  // Returns the test case comment.

-  const char* comment() const { return comment_.c_str(); }

-

-  // Returns true if any test in this test case should run.

-  bool should_run() const { return should_run_; }

-

-  // Sets the should_run member.

-  void set_should_run(bool should) { should_run_ = should; }

-

-  // Gets the (mutable) list of TestInfos in this TestCase.

-  internal::List<TestInfo*>& test_info_list() { return *test_info_list_; }

-

-  // Gets the (immutable) list of TestInfos in this TestCase.

-  const internal::List<TestInfo *> & test_info_list() const {

-    return *test_info_list_;

-  }

-

-  // Gets the number of successful tests in this test case.

-  int successful_test_count() const;

-

-  // Gets the number of failed tests in this test case.

-  int failed_test_count() const;

-

-  // Gets the number of disabled tests in this test case.

-  int disabled_test_count() const;

-

-  // Get the number of tests in this test case that should run.

-  int test_to_run_count() const;

-

-  // Gets the number of all tests in this test case.

-  int total_test_count() const;

-

-  // Returns true iff the test case passed.

-  bool Passed() const { return !Failed(); }

-

-  // Returns true iff the test case failed.

-  bool Failed() const { return failed_test_count() > 0; }

-

-  // Returns the elapsed time, in milliseconds.

-  internal::TimeInMillis elapsed_time() const { return elapsed_time_; }

-

-  // Adds a TestInfo to this test case.  Will delete the TestInfo upon

-  // destruction of the TestCase object.

-  void AddTestInfo(TestInfo * test_info);

-

-  // Finds and returns a TestInfo with the given name.  If one doesn't

-  // exist, returns NULL.

-  TestInfo* GetTestInfo(const char* test_name);

-

-  // Clears the results of all tests in this test case.

-  void ClearResult();

-

-  // Clears the results of all tests in the given test case.

-  static void ClearTestCaseResult(TestCase* test_case) {

-    test_case->ClearResult();

-  }

-

-  // Runs every test in this TestCase.

-  void Run();

-

-  // Runs every test in the given TestCase.

-  static void RunTestCase(TestCase * test_case) { test_case->Run(); }

-

-  // Returns true iff test passed.

-  static bool TestPassed(const TestInfo * test_info) {

-    const internal::TestInfoImpl* const impl = test_info->impl();

-    return impl->should_run() && impl->result()->Passed();

-  }

-

-  // Returns true iff test failed.

-  static bool TestFailed(const TestInfo * test_info) {

-    const internal::TestInfoImpl* const impl = test_info->impl();

-    return impl->should_run() && impl->result()->Failed();

-  }

-

-  // Returns true iff test is disabled.

-  static bool TestDisabled(const TestInfo * test_info) {

-    return test_info->impl()->is_disabled();

-  }

-

-  // Returns true if the given test should run.

-  static bool ShouldRunTest(const TestInfo *test_info) {

-    return test_info->impl()->should_run();

-  }

-

- private:

-  // Name of the test case.

-  internal::String name_;

-  // Comment on the test case.

-  internal::String comment_;

-  // List of TestInfos.

-  internal::List<TestInfo*>* test_info_list_;

-  // Pointer to the function that sets up the test case.

-  Test::SetUpTestCaseFunc set_up_tc_;

-  // Pointer to the function that tears down the test case.

-  Test::TearDownTestCaseFunc tear_down_tc_;

-  // True iff any test in this test case should run.

-  bool should_run_;

-  // Elapsed time, in milliseconds.

-  internal::TimeInMillis elapsed_time_;

-

-  // We disallow copying TestCases.

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);

-};

-

-namespace internal {

-

-// Class UnitTestOptions.

-//

-// This class contains functions for processing options the user

-// specifies when running the tests.  It has only static members.

-//

-// In most cases, the user can specify an option using either an

-// environment variable or a command line flag.  E.g. you can set the

-// test filter using either GTEST_FILTER or --gtest_filter.  If both

-// the variable and the flag are present, the latter overrides the

-// former.

-class UnitTestOptions {

- public:

-  // Functions for processing the gtest_output flag.

-

-  // Returns the output format, or "" for normal printed output.

-  static String GetOutputFormat();

-

-  // Returns the absolute path of the requested output file, or the

-  // default (test_detail.xml in the original working directory) if

-  // none was explicitly specified.

-  static String GetAbsolutePathToOutputFile();

-

-  // Functions for processing the gtest_filter flag.

-

-  // Returns true iff the wildcard pattern matches the string.  The

-  // first ':' or '\0' character in pattern marks the end of it.

-  //

-  // This recursive algorithm isn't very efficient, but is clear and

-  // works well enough for matching test names, which are short.

-  static bool PatternMatchesString(const char *pattern, const char *str);

-

-  // Returns true iff the user-specified filter matches the test case

-  // name and the test name.

-  static bool FilterMatchesTest(const String &test_case_name,

-                                const String &test_name);

-

-#if GTEST_OS_WINDOWS

-  // Function for supporting the gtest_catch_exception flag.

-

-  // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the

-  // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.

-  // This function is useful as an __except condition.

-  static int GTestShouldProcessSEH(DWORD exception_code);

-#endif  // GTEST_OS_WINDOWS

-

-  // Returns true if "name" matches the ':' separated list of glob-style

-  // filters in "filter".

-  static bool MatchesFilter(const String& name, const char* filter);

-};

-

-// Returns the current application's name, removing directory path if that

-// is present.  Used by UnitTestOptions::GetOutputFile.

-FilePath GetCurrentExecutableName();

-

-// The role interface for getting the OS stack trace as a string.

-class OsStackTraceGetterInterface {

- public:

-  OsStackTraceGetterInterface() {}

-  virtual ~OsStackTraceGetterInterface() {}

-

-  // Returns the current OS stack trace as a String.  Parameters:

-  //

-  //   max_depth  - the maximum number of stack frames to be included

-  //                in the trace.

-  //   skip_count - the number of top frames to be skipped; doesn't count

-  //                against max_depth.

-  virtual String CurrentStackTrace(int max_depth, int skip_count) = 0;

-

-  // UponLeavingGTest() should be called immediately before Google Test calls

-  // user code. It saves some information about the current stack that

-  // CurrentStackTrace() will use to find and hide Google Test stack frames.

-  virtual void UponLeavingGTest() = 0;

-

- private:

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);

-};

-

-// A working implementation of the OsStackTraceGetterInterface interface.

-class OsStackTraceGetter : public OsStackTraceGetterInterface {

- public:

-  OsStackTraceGetter() {}

-  virtual String CurrentStackTrace(int max_depth, int skip_count);

-  virtual void UponLeavingGTest();

-

-  // This string is inserted in place of stack frames that are part of

-  // Google Test's implementation.

-  static const char* const kElidedFramesMarker;

-

- private:

-  Mutex mutex_;  // protects all internal state

-

-  // We save the stack frame below the frame that calls user code.

-  // We do this because the address of the frame immediately below

-  // the user code changes between the call to UponLeavingGTest()

-  // and any calls to CurrentStackTrace() from within the user code.

-  void* caller_frame_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);

-};

-

-// Information about a Google Test trace point.

-struct TraceInfo {

-  const char* file;

-  int line;

-  String message;

-};

-

-// This is the default global test part result reporter used in UnitTestImpl.

-// This class should only be used by UnitTestImpl.

-class DefaultGlobalTestPartResultReporter

-  : public TestPartResultReporterInterface {

- public:

-  explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);

-  // Implements the TestPartResultReporterInterface. Reports the test part

-  // result in the current test.

-  virtual void ReportTestPartResult(const TestPartResult& result);

-

- private:

-  UnitTestImpl* const unit_test_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter);

-};

-

-// This is the default per thread test part result reporter used in

-// UnitTestImpl. This class should only be used by UnitTestImpl.

-class DefaultPerThreadTestPartResultReporter

-    : public TestPartResultReporterInterface {

- public:

-  explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);

-  // Implements the TestPartResultReporterInterface. The implementation just

-  // delegates to the current global test part result reporter of *unit_test_.

-  virtual void ReportTestPartResult(const TestPartResult& result);

-

- private:

-  UnitTestImpl* const unit_test_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter);

-};

-

-// The private implementation of the UnitTest class.  We don't protect

-// the methods under a mutex, as this class is not accessible by a

-// user and the UnitTest class that delegates work to this class does

-// proper locking.

-class UnitTestImpl {

- public:

-  explicit UnitTestImpl(UnitTest* parent);

-  virtual ~UnitTestImpl();

-

-  // There are two different ways to register your own TestPartResultReporter.

-  // You can register your own repoter to listen either only for test results

-  // from the current thread or for results from all threads.

-  // By default, each per-thread test result repoter just passes a new

-  // TestPartResult to the global test result reporter, which registers the

-  // test part result for the currently running test.

-

-  // Returns the global test part result reporter.

-  TestPartResultReporterInterface* GetGlobalTestPartResultReporter();

-

-  // Sets the global test part result reporter.

-  void SetGlobalTestPartResultReporter(

-      TestPartResultReporterInterface* reporter);

-

-  // Returns the test part result reporter for the current thread.

-  TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();

-

-  // Sets the test part result reporter for the current thread.

-  void SetTestPartResultReporterForCurrentThread(

-      TestPartResultReporterInterface* reporter);

-

-  // Gets the number of successful test cases.

-  int successful_test_case_count() const;

-

-  // Gets the number of failed test cases.

-  int failed_test_case_count() const;

-

-  // Gets the number of all test cases.

-  int total_test_case_count() const;

-

-  // Gets the number of all test cases that contain at least one test

-  // that should run.

-  int test_case_to_run_count() const;

-

-  // Gets the number of successful tests.

-  int successful_test_count() const;

-

-  // Gets the number of failed tests.

-  int failed_test_count() const;

-

-  // Gets the number of disabled tests.

-  int disabled_test_count() const;

-

-  // Gets the number of all tests.

-  int total_test_count() const;

-

-  // Gets the number of tests that should run.

-  int test_to_run_count() const;

-

-  // Gets the elapsed time, in milliseconds.

-  TimeInMillis elapsed_time() const { return elapsed_time_; }

-

-  // Returns true iff the unit test passed (i.e. all test cases passed).

-  bool Passed() const { return !Failed(); }

-

-  // Returns true iff the unit test failed (i.e. some test case failed

-  // or something outside of all tests failed).

-  bool Failed() const {

-    return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();

-  }

-

-  // Returns the TestResult for the test that's currently running, or

-  // the TestResult for the ad hoc test if no test is running.

-  internal::TestResult* current_test_result();

-

-  // Returns the TestResult for the ad hoc test.

-  const internal::TestResult* ad_hoc_test_result() const {

-    return &ad_hoc_test_result_;

-  }

-

-  // Sets the unit test result printer.

-  //

-  // Does nothing if the input and the current printer object are the

-  // same; otherwise, deletes the old printer object and makes the

-  // input the current printer.

-  void set_result_printer(UnitTestEventListenerInterface * result_printer);

-

-  // Returns the current unit test result printer if it is not NULL;

-  // otherwise, creates an appropriate result printer, makes it the

-  // current printer, and returns it.

-  UnitTestEventListenerInterface* result_printer();

-

-  // Sets the OS stack trace getter.

-  //

-  // Does nothing if the input and the current OS stack trace getter

-  // are the same; otherwise, deletes the old getter and makes the

-  // input the current getter.

-  void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);

-

-  // Returns the current OS stack trace getter if it is not NULL;

-  // otherwise, creates an OsStackTraceGetter, makes it the current

-  // getter, and returns it.

-  OsStackTraceGetterInterface* os_stack_trace_getter();

-

-  // Returns the current OS stack trace as a String.

-  //

-  // The maximum number of stack frames to be included is specified by

-  // the gtest_stack_trace_depth flag.  The skip_count parameter

-  // specifies the number of top frames to be skipped, which doesn't

-  // count against the number of frames to be included.

-  //

-  // For example, if Foo() calls Bar(), which in turn calls

-  // CurrentOsStackTraceExceptTop(1), Foo() will be included in the

-  // trace but Bar() and CurrentOsStackTraceExceptTop() won't.

-  String CurrentOsStackTraceExceptTop(int skip_count);

-

-  // Finds and returns a TestCase with the given name.  If one doesn't

-  // exist, creates one and returns it.

-  //

-  // Arguments:

-  //

-  //   test_case_name: name of the test case

-  //   set_up_tc:      pointer to the function that sets up the test case

-  //   tear_down_tc:   pointer to the function that tears down the test case

-  TestCase* GetTestCase(const char* test_case_name,

-                        const char* comment,

-                        Test::SetUpTestCaseFunc set_up_tc,

-                        Test::TearDownTestCaseFunc tear_down_tc);

-

-  // Adds a TestInfo to the unit test.

-  //

-  // Arguments:

-  //

-  //   set_up_tc:    pointer to the function that sets up the test case

-  //   tear_down_tc: pointer to the function that tears down the test case

-  //   test_info:    the TestInfo object

-  void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,

-                   Test::TearDownTestCaseFunc tear_down_tc,

-                   TestInfo * test_info) {

-    // In order to support thread-safe death tests, we need to

-    // remember the original working directory when the test program

-    // was first invoked.  We cannot do this in RUN_ALL_TESTS(), as

-    // the user may have changed the current directory before calling

-    // RUN_ALL_TESTS().  Therefore we capture the current directory in

-    // AddTestInfo(), which is called to register a TEST or TEST_F

-    // before main() is reached.

-    if (original_working_dir_.IsEmpty()) {

-      original_working_dir_.Set(FilePath::GetCurrentDir());

-      if (original_working_dir_.IsEmpty()) {

-        printf("%s\n", "Failed to get the current working directory.");

-        abort();

-      }

-    }

-

-    GetTestCase(test_info->test_case_name(),

-                test_info->test_case_comment(),

-                set_up_tc,

-                tear_down_tc)->AddTestInfo(test_info);

-  }

-

-#if GTEST_HAS_PARAM_TEST

-  // Returns ParameterizedTestCaseRegistry object used to keep track of

-  // value-parameterized tests and instantiate and register them.

-  internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {

-    return parameterized_test_registry_;

-  }

-#endif  // GTEST_HAS_PARAM_TEST

-

-  // Sets the TestCase object for the test that's currently running.

-  void set_current_test_case(TestCase* current_test_case) {

-    current_test_case_ = current_test_case;

-  }

-

-  // Sets the TestInfo object for the test that's currently running.  If

-  // current_test_info is NULL, the assertion results will be stored in

-  // ad_hoc_test_result_.

-  void set_current_test_info(TestInfo* current_test_info) {

-    current_test_info_ = current_test_info;

-  }

-

-  // Registers all parameterized tests defined using TEST_P and

-  // INSTANTIATE_TEST_P, creating regular tests for each test/parameter

-  // combination. This method can be called more then once; it has

-  // guards protecting from registering the tests more then once.

-  // If value-parameterized tests are disabled, RegisterParameterizedTests

-  // is present but does nothing.

-  void RegisterParameterizedTests();

-

-  // Runs all tests in this UnitTest object, prints the result, and

-  // returns 0 if all tests are successful, or 1 otherwise.  If any

-  // exception is thrown during a test on Windows, this test is

-  // considered to be failed, but the rest of the tests will still be

-  // run.  (We disable exceptions on Linux and Mac OS X, so the issue

-  // doesn't apply there.)

-  int RunAllTests();

-

-  // Clears the results of all tests, including the ad hoc test.

-  void ClearResult() {

-    test_cases_.ForEach(TestCase::ClearTestCaseResult);

-    ad_hoc_test_result_.Clear();

-  }

-

-  enum ReactionToSharding {

-    HONOR_SHARDING_PROTOCOL,

-    IGNORE_SHARDING_PROTOCOL

-  };

-

-  // Matches the full name of each test against the user-specified

-  // filter to decide whether the test should run, then records the

-  // result in each TestCase and TestInfo object.

-  // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests

-  // based on sharding variables in the environment.

-  // Returns the number of tests that should run.

-  int FilterTests(ReactionToSharding shard_tests);

-

-  // Prints the names of the tests matching the user-specified filter flag.

-  void ListTestsMatchingFilter();

-

-  const TestCase* current_test_case() const { return current_test_case_; }

-  TestInfo* current_test_info() { return current_test_info_; }

-  const TestInfo* current_test_info() const { return current_test_info_; }

-

-  // Returns the list of environments that need to be set-up/torn-down

-  // before/after the tests are run.

-  internal::List<Environment*>* environments() { return &environments_; }

-  internal::List<Environment*>* environments_in_reverse_order() {

-    return &environments_in_reverse_order_;

-  }

-

-  internal::List<TestCase*>* test_cases() { return &test_cases_; }

-  const internal::List<TestCase*>* test_cases() const { return &test_cases_; }

-

-  // Getters for the per-thread Google Test trace stack.

-  internal::List<TraceInfo>* gtest_trace_stack() {

-    return gtest_trace_stack_.pointer();

-  }

-  const internal::List<TraceInfo>* gtest_trace_stack() const {

-    return gtest_trace_stack_.pointer();

-  }

-

-#if GTEST_HAS_DEATH_TEST

-  // Returns a pointer to the parsed --gtest_internal_run_death_test

-  // flag, or NULL if that flag was not specified.

-  // This information is useful only in a death test child process.

-  const InternalRunDeathTestFlag* internal_run_death_test_flag() const {

-    return internal_run_death_test_flag_.get();

-  }

-

-  // Returns a pointer to the current death test factory.

-  internal::DeathTestFactory* death_test_factory() {

-    return death_test_factory_.get();

-  }

-

-  friend class ReplaceDeathTestFactory;

-#endif  // GTEST_HAS_DEATH_TEST

-

- private:

-  friend class ::testing::UnitTest;

-

-  // The UnitTest object that owns this implementation object.

-  UnitTest* const parent_;

-

-  // The working directory when the first TEST() or TEST_F() was

-  // executed.

-  internal::FilePath original_working_dir_;

-

-  // The default test part result reporters.

-  DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;

-  DefaultPerThreadTestPartResultReporter

-      default_per_thread_test_part_result_reporter_;

-

-  // Points to (but doesn't own) the global test part result reporter.

-  TestPartResultReporterInterface* global_test_part_result_repoter_;

-

-  // Protects read and write access to global_test_part_result_reporter_.

-  internal::Mutex global_test_part_result_reporter_mutex_;

-

-  // Points to (but doesn't own) the per-thread test part result reporter.

-  internal::ThreadLocal<TestPartResultReporterInterface*>

-      per_thread_test_part_result_reporter_;

-

-  // The list of environments that need to be set-up/torn-down

-  // before/after the tests are run.  environments_in_reverse_order_

-  // simply mirrors environments_ in reverse order.

-  internal::List<Environment*> environments_;

-  internal::List<Environment*> environments_in_reverse_order_;

-

-  internal::List<TestCase*> test_cases_;  // The list of TestCases.

-

-#if GTEST_HAS_PARAM_TEST

-  // ParameterizedTestRegistry object used to register value-parameterized

-  // tests.

-  internal::ParameterizedTestCaseRegistry parameterized_test_registry_;

-

-  // Indicates whether RegisterParameterizedTests() has been called already.

-  bool parameterized_tests_registered_;

-#endif  // GTEST_HAS_PARAM_TEST

-

-  // Points to the last death test case registered.  Initially NULL.

-  internal::ListNode<TestCase*>* last_death_test_case_;

-

-  // This points to the TestCase for the currently running test.  It

-  // changes as Google Test goes through one test case after another.

-  // When no test is running, this is set to NULL and Google Test

-  // stores assertion results in ad_hoc_test_result_.  Initally NULL.

-  TestCase* current_test_case_;

-

-  // This points to the TestInfo for the currently running test.  It

-  // changes as Google Test goes through one test after another.  When

-  // no test is running, this is set to NULL and Google Test stores

-  // assertion results in ad_hoc_test_result_.  Initially NULL.

-  TestInfo* current_test_info_;

-

-  // Normally, a user only writes assertions inside a TEST or TEST_F,

-  // or inside a function called by a TEST or TEST_F.  Since Google

-  // Test keeps track of which test is current running, it can

-  // associate such an assertion with the test it belongs to.

-  //

-  // If an assertion is encountered when no TEST or TEST_F is running,

-  // Google Test attributes the assertion result to an imaginary "ad hoc"

-  // test, and records the result in ad_hoc_test_result_.

-  internal::TestResult ad_hoc_test_result_;

-

-  // The unit test result printer.  Will be deleted when the UnitTest

-  // object is destructed.  By default, a plain text printer is used,

-  // but the user can set this field to use a custom printer if that

-  // is desired.

-  UnitTestEventListenerInterface* result_printer_;

-

-  // The OS stack trace getter.  Will be deleted when the UnitTest

-  // object is destructed.  By default, an OsStackTraceGetter is used,

-  // but the user can set this field to use a custom getter if that is

-  // desired.

-  OsStackTraceGetterInterface* os_stack_trace_getter_;

-

-  // How long the test took to run, in milliseconds.

-  TimeInMillis elapsed_time_;

-

-#if GTEST_HAS_DEATH_TEST

-  // The decomposed components of the gtest_internal_run_death_test flag,

-  // parsed when RUN_ALL_TESTS is called.

-  internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;

-  internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;

-#endif  // GTEST_HAS_DEATH_TEST

-

-  // A per-thread stack of traces created by the SCOPED_TRACE() macro.

-  internal::ThreadLocal<internal::List<TraceInfo> > gtest_trace_stack_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);

-};  // class UnitTestImpl

-

-// Convenience function for accessing the global UnitTest

-// implementation object.

-inline UnitTestImpl* GetUnitTestImpl() {

-  return UnitTest::GetInstance()->impl();

-}

-

-// Clears all test part results of the current test.

-inline void ClearCurrentTestPartResults() {

-  GetUnitTestImpl()->current_test_result()->ClearTestPartResults();

-}

-

-// Internal helper functions for implementing the simple regular

-// expression matcher.

-bool IsInSet(char ch, const char* str);

-bool IsDigit(char ch);

-bool IsPunct(char ch);

-bool IsRepeat(char ch);

-bool IsWhiteSpace(char ch);

-bool IsWordChar(char ch);

-bool IsValidEscape(char ch);

-bool AtomMatchesChar(bool escaped, char pattern, char ch);

-bool ValidateRegex(const char* regex);

-bool MatchRegexAtHead(const char* regex, const char* str);

-bool MatchRepetitionAndRegexAtHead(

-    bool escaped, char ch, char repeat, const char* regex, const char* str);

-bool MatchRegexAnywhere(const char* regex, const char* str);

-

-// Parses the command line for Google Test flags, without initializing

-// other parts of Google Test.

-void ParseGoogleTestFlagsOnly(int* argc, char** argv);

-void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);

-

-#if GTEST_HAS_DEATH_TEST

-

-// Returns the message describing the last system error, regardless of the

-// platform.

-String GetLastErrnoDescription();

-

-#if GTEST_OS_WINDOWS

-// Provides leak-safe Windows kernel handle ownership.

-class AutoHandle {

- public:

-  AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}

-  explicit AutoHandle(HANDLE handle) : handle_(handle) {}

-

-  ~AutoHandle() { Reset(); }

-

-  HANDLE Get() const { return handle_; }

-  void Reset() { Reset(INVALID_HANDLE_VALUE); }

-  void Reset(HANDLE handle) {

-    if (handle != handle_) {

-      if (handle_ != INVALID_HANDLE_VALUE)

-        ::CloseHandle(handle_);

-      handle_ = handle;

-    }

-  }

-

- private:

-  HANDLE handle_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);

-};

-#endif  // GTEST_OS_WINDOWS

-

-// Attempts to parse a string into a positive integer pointed to by the

-// number parameter.  Returns true if that is possible.

-// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use

-// it here.

-template <typename Integer>

-bool ParseNaturalNumber(const ::std::string& str, Integer* number) {

-  // Fail fast if the given string does not begin with a digit;

-  // this bypasses strtoXXX's "optional leading whitespace and plus

-  // or minus sign" semantics, which are undesirable here.

-  if (str.empty() || !isdigit(str[0])) {

-    return false;

-  }

-  errno = 0;

-

-  char* end;

-  // BiggestConvertible is the largest integer type that system-provided

-  // string-to-number conversion routines can return.

-#if GTEST_OS_WINDOWS

-  typedef unsigned __int64 BiggestConvertible;

-  const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);

-#else

-  typedef unsigned long long BiggestConvertible;  // NOLINT

-  const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);

-#endif  // GTEST_OS_WINDOWS

-  const bool parse_success = *end == '\0' && errno == 0;

-

-  // TODO(vladl@google.com): Convert this to compile time assertion when it is

-  // available.

-  GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));

-

-  const Integer result = static_cast<Integer>(parsed);

-  if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {

-    *number = result;

-    return true;

-  }

-  return false;

-}

-#endif  // GTEST_HAS_DEATH_TEST

-

-}  // namespace internal

-}  // namespace testing

-

-#endif  // GTEST_SRC_GTEST_INTERNAL_INL_H_

+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Utility functions and classes used by the Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// This file contains purely Google Test's internal implementation.  Please
+// DO NOT #INCLUDE IT IN A USER PROGRAM.
+
+#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
+#define GTEST_SRC_GTEST_INTERNAL_INL_H_
+
+// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
+// part of Google Test's implementation; otherwise it's undefined.
+#if !GTEST_IMPLEMENTATION_
+// A user is trying to include this from his code - just say no.
+#error "gtest-internal-inl.h is part of Google Test's internal implementation."
+#error "It must not be included except by Google Test itself."
+#endif  // GTEST_IMPLEMENTATION_
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>   // For strtoll/_strtoul64.
+
+#include <string>
+
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_OS_WINDOWS
+#include <windows.h>  // For DWORD.
+#endif  // GTEST_OS_WINDOWS
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+namespace testing {
+
+// Declares the flags.
+//
+// We don't want the users to modify this flag in the code, but want
+// Google Test's own unit tests to be able to access it. Therefore we
+// declare it here as opposed to in gtest.h.
+GTEST_DECLARE_bool_(death_test_use_fork);
+
+namespace internal {
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library.  This is solely for testing GetTestTypeId().
+extern const TypeId kTestTypeIdInGoogleTest;
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
+const char kBreakOnFailureFlag[] = "break_on_failure";
+const char kCatchExceptionsFlag[] = "catch_exceptions";
+const char kColorFlag[] = "color";
+const char kFilterFlag[] = "filter";
+const char kListTestsFlag[] = "list_tests";
+const char kOutputFlag[] = "output";
+const char kPrintTimeFlag[] = "print_time";
+const char kRepeatFlag[] = "repeat";
+const char kThrowOnFailureFlag[] = "throw_on_failure";
+
+// This class saves the values of all Google Test flags in its c'tor, and
+// restores them in its d'tor.
+class GTestFlagSaver {
+ public:
+  // The c'tor.
+  GTestFlagSaver() {
+    also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests);
+    break_on_failure_ = GTEST_FLAG(break_on_failure);
+    catch_exceptions_ = GTEST_FLAG(catch_exceptions);
+    color_ = GTEST_FLAG(color);
+    death_test_style_ = GTEST_FLAG(death_test_style);
+    death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
+    filter_ = GTEST_FLAG(filter);
+    internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
+    list_tests_ = GTEST_FLAG(list_tests);
+    output_ = GTEST_FLAG(output);
+    print_time_ = GTEST_FLAG(print_time);
+    repeat_ = GTEST_FLAG(repeat);
+    throw_on_failure_ = GTEST_FLAG(throw_on_failure);
+  }
+
+  // The d'tor is not virtual.  DO NOT INHERIT FROM THIS CLASS.
+  ~GTestFlagSaver() {
+    GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_;
+    GTEST_FLAG(break_on_failure) = break_on_failure_;
+    GTEST_FLAG(catch_exceptions) = catch_exceptions_;
+    GTEST_FLAG(color) = color_;
+    GTEST_FLAG(death_test_style) = death_test_style_;
+    GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
+    GTEST_FLAG(filter) = filter_;
+    GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
+    GTEST_FLAG(list_tests) = list_tests_;
+    GTEST_FLAG(output) = output_;
+    GTEST_FLAG(print_time) = print_time_;
+    GTEST_FLAG(repeat) = repeat_;
+    GTEST_FLAG(throw_on_failure) = throw_on_failure_;
+  }
+ private:
+  // Fields for saving the original values of flags.
+  bool also_run_disabled_tests_;
+  bool break_on_failure_;
+  bool catch_exceptions_;
+  String color_;
+  String death_test_style_;
+  bool death_test_use_fork_;
+  String filter_;
+  String internal_run_death_test_;
+  bool list_tests_;
+  String output_;
+  bool print_time_;
+  bool pretty_;
+  internal::Int32 repeat_;
+  bool throw_on_failure_;
+} GTEST_ATTRIBUTE_UNUSED_;
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// The output buffer str must containt at least 32 characters.
+// The function returns the address of the output buffer.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'.
+char* CodePointToUtf8(UInt32 code_point, char* str);
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+//   UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+//   UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+String WideStringToUtf8(const wchar_t* str, int num_chars);
+
+// Returns the number of active threads, or 0 when there is an error.
+size_t GetThreadCount();
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded();
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (e.g., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+bool ShouldShard(const char* total_shards_str, const char* shard_index_str,
+                 bool in_subprocess_for_death_test);
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error and
+// and aborts.
+Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id);
+
+// List is a simple singly-linked list container.
+//
+// We cannot use std::list as Microsoft's implementation of STL has
+// problems when exception is disabled.  There is a hack to work
+// around this, but we've seen cases where the hack fails to work.
+//
+// TODO(wan): switch to std::list when we have a reliable fix for the
+// STL problem, e.g. when we upgrade to the next version of Visual
+// C++, or (more likely) switch to STLport.
+//
+// The element type must support copy constructor.
+
+// Forward declare List
+template <typename E>  // E is the element type.
+class List;
+
+// ListNode is a node in a singly-linked list.  It consists of an
+// element and a pointer to the next node.  The last node in the list
+// has a NULL value for its next pointer.
+template <typename E>  // E is the element type.
+class ListNode {
+  friend class List<E>;
+
+ private:
+
+  E element_;
+  ListNode * next_;
+
+  // The c'tor is private s.t. only in the ListNode class and in its
+  // friend class List we can create a ListNode object.
+  //
+  // Creates a node with a given element value.  The next pointer is
+  // set to NULL.
+  //
+  // ListNode does NOT have a default constructor.  Always use this
+  // constructor (with parameter) to create a ListNode object.
+  explicit ListNode(const E & element) : element_(element), next_(NULL) {}
+
+  // We disallow copying ListNode
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ListNode);
+
+ public:
+
+  // Gets the element in this node.
+  E & element() { return element_; }
+  const E & element() const { return element_; }
+
+  // Gets the next node in the list.
+  ListNode * next() { return next_; }
+  const ListNode * next() const { return next_; }
+};
+
+
+// List is a simple singly-linked list container.
+template <typename E>  // E is the element type.
+class List {
+ public:
+
+  // Creates an empty list.
+  List() : head_(NULL), last_(NULL), size_(0) {}
+
+  // D'tor.
+  virtual ~List();
+
+  // Clears the list.
+  void Clear() {
+    if ( size_ > 0 ) {
+      // 1. Deletes every node.
+      ListNode<E> * node = head_;
+      ListNode<E> * next = node->next();
+      for ( ; ; ) {
+        delete node;
+        node = next;
+        if ( node == NULL ) break;
+        next = node->next();
+      }
+
+      // 2. Resets the member variables.
+      head_ = last_ = NULL;
+      size_ = 0;
+    }
+  }
+
+  // Gets the number of elements.
+  int size() const { return size_; }
+
+  // Returns true if the list is empty.
+  bool IsEmpty() const { return size() == 0; }
+
+  // Gets the first element of the list, or NULL if the list is empty.
+  ListNode<E> * Head() { return head_; }
+  const ListNode<E> * Head() const { return head_; }
+
+  // Gets the last element of the list, or NULL if the list is empty.
+  ListNode<E> * Last() { return last_; }
+  const ListNode<E> * Last() const { return last_; }
+
+  // Adds an element to the end of the list.  A copy of the element is
+  // created using the copy constructor, and then stored in the list.
+  // Changes made to the element in the list doesn't affect the source
+  // object, and vice versa.
+  void PushBack(const E & element) {
+    ListNode<E> * new_node = new ListNode<E>(element);
+
+    if ( size_ == 0 ) {
+      head_ = last_ = new_node;
+      size_ = 1;
+    } else {
+      last_->next_ = new_node;
+      last_ = new_node;
+      size_++;
+    }
+  }
+
+  // Adds an element to the beginning of this list.
+  void PushFront(const E& element) {
+    ListNode<E>* const new_node = new ListNode<E>(element);
+
+    if ( size_ == 0 ) {
+      head_ = last_ = new_node;
+      size_ = 1;
+    } else {
+      new_node->next_ = head_;
+      head_ = new_node;
+      size_++;
+    }
+  }
+
+  // Removes an element from the beginning of this list.  If the
+  // result argument is not NULL, the removed element is stored in the
+  // memory it points to.  Otherwise the element is thrown away.
+  // Returns true iff the list wasn't empty before the operation.
+  bool PopFront(E* result) {
+    if (size_ == 0) return false;
+
+    if (result != NULL) {
+      *result = head_->element_;
+    }
+
+    ListNode<E>* const old_head = head_;
+    size_--;
+    if (size_ == 0) {
+      head_ = last_ = NULL;
+    } else {
+      head_ = head_->next_;
+    }
+    delete old_head;
+
+    return true;
+  }
+
+  // Inserts an element after a given node in the list.  It's the
+  // caller's responsibility to ensure that the given node is in the
+  // list.  If the given node is NULL, inserts the element at the
+  // front of the list.
+  ListNode<E>* InsertAfter(ListNode<E>* node, const E& element) {
+    if (node == NULL) {
+      PushFront(element);
+      return Head();
+    }
+
+    ListNode<E>* const new_node = new ListNode<E>(element);
+    new_node->next_ = node->next_;
+    node->next_ = new_node;
+    size_++;
+    if (node == last_) {
+      last_ = new_node;
+    }
+
+    return new_node;
+  }
+
+  // Returns the number of elements that satisfy a given predicate.
+  // The parameter 'predicate' is a Boolean function or functor that
+  // accepts a 'const E &', where E is the element type.
+  template <typename P>  // P is the type of the predicate function/functor
+  int CountIf(P predicate) const {
+    int count = 0;
+    for ( const ListNode<E> * node = Head();
+          node != NULL;
+          node = node->next() ) {
+      if ( predicate(node->element()) ) {
+        count++;
+      }
+    }
+
+    return count;
+  }
+
+  // Applies a function/functor to each element in the list.  The
+  // parameter 'functor' is a function/functor that accepts a 'const
+  // E &', where E is the element type.  This method does not change
+  // the elements.
+  template <typename F>  // F is the type of the function/functor
+  void ForEach(F functor) const {
+    for ( const ListNode<E> * node = Head();
+          node != NULL;
+          node = node->next() ) {
+      functor(node->element());
+    }
+  }
+
+  // Returns the first node whose element satisfies a given predicate,
+  // or NULL if none is found.  The parameter 'predicate' is a
+  // function/functor that accepts a 'const E &', where E is the
+  // element type.  This method does not change the elements.
+  template <typename P>  // P is the type of the predicate function/functor.
+  const ListNode<E> * FindIf(P predicate) const {
+    for ( const ListNode<E> * node = Head();
+          node != NULL;
+          node = node->next() ) {
+      if ( predicate(node->element()) ) {
+        return node;
+      }
+    }
+
+    return NULL;
+  }
+
+  template <typename P>
+  ListNode<E> * FindIf(P predicate) {
+    for ( ListNode<E> * node = Head();
+          node != NULL;
+          node = node->next() ) {
+      if ( predicate(node->element() ) ) {
+        return node;
+      }
+    }
+
+    return NULL;
+  }
+
+ private:
+  ListNode<E>* head_;  // The first node of the list.
+  ListNode<E>* last_;  // The last node of the list.
+  int size_;           // The number of elements in the list.
+
+  // We disallow copying List.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(List);
+};
+
+// The virtual destructor of List.
+template <typename E>
+List<E>::~List() {
+  Clear();
+}
+
+// A function for deleting an object.  Handy for being used as a
+// functor.
+template <typename T>
+static void Delete(T * x) {
+  delete x;
+}
+
+// A copyable object representing a user specified test property which can be
+// output as a key/value string pair.
+//
+// Don't inherit from TestProperty as its destructor is not virtual.
+class TestProperty {
+ public:
+  // C'tor.  TestProperty does NOT have a default constructor.
+  // Always use this constructor (with parameters) to create a
+  // TestProperty object.
+  TestProperty(const char* key, const char* value) :
+    key_(key), value_(value) {
+  }
+
+  // Gets the user supplied key.
+  const char* key() const {
+    return key_.c_str();
+  }
+
+  // Gets the user supplied value.
+  const char* value() const {
+    return value_.c_str();
+  }
+
+  // Sets a new value, overriding the one supplied in the constructor.
+  void SetValue(const char* new_value) {
+    value_ = new_value;
+  }
+
+ private:
+  // The key supplied by the user.
+  String key_;
+  // The value supplied by the user.
+  String value_;
+};
+
+// A predicate that checks the key of a TestProperty against a known key.
+//
+// TestPropertyKeyIs is copyable.
+class TestPropertyKeyIs {
+ public:
+  // Constructor.
+  //
+  // TestPropertyKeyIs has NO default constructor.
+  explicit TestPropertyKeyIs(const char* key)
+      : key_(key) {}
+
+  // Returns true iff the test name of test property matches on key_.
+  bool operator()(const TestProperty& test_property) const {
+    return String(test_property.key()).Compare(key_) == 0;
+  }
+
+ private:
+  String key_;
+};
+
+// The result of a single Test.  This includes a list of
+// TestPartResults, a list of TestProperties, a count of how many
+// death tests there are in the Test, and how much time it took to run
+// the Test.
+//
+// TestResult is not copyable.
+class TestResult {
+ public:
+  // Creates an empty TestResult.
+  TestResult();
+
+  // D'tor.  Do not inherit from TestResult.
+  ~TestResult();
+
+  // Gets the list of TestPartResults.
+  const internal::List<TestPartResult> & test_part_results() const {
+    return test_part_results_;
+  }
+
+  // Gets the list of TestProperties.
+  const internal::List<internal::TestProperty> & test_properties() const {
+    return test_properties_;
+  }
+
+  // Gets the number of successful test parts.
+  int successful_part_count() const;
+
+  // Gets the number of failed test parts.
+  int failed_part_count() const;
+
+  // Gets the number of all test parts.  This is the sum of the number
+  // of successful test parts and the number of failed test parts.
+  int total_part_count() const;
+
+  // Returns true iff the test passed (i.e. no test part failed).
+  bool Passed() const { return !Failed(); }
+
+  // Returns true iff the test failed.
+  bool Failed() const { return failed_part_count() > 0; }
+
+  // Returns true iff the test fatally failed.
+  bool HasFatalFailure() const;
+
+  // Returns true iff the test has a non-fatal failure.
+  bool HasNonfatalFailure() const;
+
+  // Returns the elapsed time, in milliseconds.
+  TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+  // Sets the elapsed time.
+  void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
+
+  // Adds a test part result to the list.
+  void AddTestPartResult(const TestPartResult& test_part_result);
+
+  // Adds a test property to the list. The property is validated and may add
+  // a non-fatal failure if invalid (e.g., if it conflicts with reserved
+  // key names). If a property is already recorded for the same key, the
+  // value will be updated, rather than storing multiple values for the same
+  // key.
+  void RecordProperty(const internal::TestProperty& test_property);
+
+  // Adds a failure if the key is a reserved attribute of Google Test
+  // testcase tags.  Returns true if the property is valid.
+  // TODO(russr): Validate attribute names are legal and human readable.
+  static bool ValidateTestProperty(const internal::TestProperty& test_property);
+
+  // Returns the death test count.
+  int death_test_count() const { return death_test_count_; }
+
+  // Increments the death test count, returning the new count.
+  int increment_death_test_count() { return ++death_test_count_; }
+
+  // Clears the test part results.
+  void ClearTestPartResults() { test_part_results_.Clear(); }
+
+  // Clears the object.
+  void Clear();
+ private:
+  // Protects mutable state of the property list and of owned properties, whose
+  // values may be updated.
+  internal::Mutex test_properites_mutex_;
+
+  // The list of TestPartResults
+  internal::List<TestPartResult> test_part_results_;
+  // The list of TestProperties
+  internal::List<internal::TestProperty> test_properties_;
+  // Running count of death tests.
+  int death_test_count_;
+  // The elapsed time, in milliseconds.
+  TimeInMillis elapsed_time_;
+
+  // We disallow copying TestResult.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);
+};  // class TestResult
+
+class TestInfoImpl {
+ public:
+  TestInfoImpl(TestInfo* parent, const char* test_case_name,
+               const char* name, const char* test_case_comment,
+               const char* comment, TypeId fixture_class_id,
+               internal::TestFactoryBase* factory);
+  ~TestInfoImpl();
+
+  // Returns true if this test should run.
+  bool should_run() const { return should_run_; }
+
+  // Sets the should_run member.
+  void set_should_run(bool should) { should_run_ = should; }
+
+  // Returns true if this test is disabled. Disabled tests are not run.
+  bool is_disabled() const { return is_disabled_; }
+
+  // Sets the is_disabled member.
+  void set_is_disabled(bool is) { is_disabled_ = is; }
+
+  // Returns true if this test matches the filter specified by the user.
+  bool matches_filter() const { return matches_filter_; }
+
+  // Sets the matches_filter member.
+  void set_matches_filter(bool matches) { matches_filter_ = matches; }
+
+  // Returns the test case name.
+  const char* test_case_name() const { return test_case_name_.c_str(); }
+
+  // Returns the test name.
+  const char* name() const { return name_.c_str(); }
+
+  // Returns the test case comment.
+  const char* test_case_comment() const { return test_case_comment_.c_str(); }
+
+  // Returns the test comment.
+  const char* comment() const { return comment_.c_str(); }
+
+  // Returns the ID of the test fixture class.
+  TypeId fixture_class_id() const { return fixture_class_id_; }
+
+  // Returns the test result.
+  internal::TestResult* result() { return &result_; }
+  const internal::TestResult* result() const { return &result_; }
+
+  // Creates the test object, runs it, records its result, and then
+  // deletes it.
+  void Run();
+
+  // Calls the given TestInfo object's Run() method.
+  static void RunTest(TestInfo * test_info) {
+    test_info->impl()->Run();
+  }
+
+  // Clears the test result.
+  void ClearResult() { result_.Clear(); }
+
+  // Clears the test result in the given TestInfo object.
+  static void ClearTestResult(TestInfo * test_info) {
+    test_info->impl()->ClearResult();
+  }
+
+ private:
+  // These fields are immutable properties of the test.
+  TestInfo* const parent_;          // The owner of this object
+  const String test_case_name_;     // Test case name
+  const String name_;               // Test name
+  const String test_case_comment_;  // Test case comment
+  const String comment_;            // Test comment
+  const TypeId fixture_class_id_;   // ID of the test fixture class
+  bool should_run_;                 // True iff this test should run
+  bool is_disabled_;                // True iff this test is disabled
+  bool matches_filter_;             // True if this test matches the
+                                    // user-specified filter.
+  internal::TestFactoryBase* const factory_;  // The factory that creates
+                                              // the test object
+
+  // This field is mutable and needs to be reset before running the
+  // test for the second time.
+  internal::TestResult result_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl);
+};
+
+}  // namespace internal
+
+// A test case, which consists of a list of TestInfos.
+//
+// TestCase is not copyable.
+class TestCase {
+ public:
+  // Creates a TestCase with the given name.
+  //
+  // TestCase does NOT have a default constructor.  Always use this
+  // constructor to create a TestCase object.
+  //
+  // Arguments:
+  //
+  //   name:         name of the test case
+  //   set_up_tc:    pointer to the function that sets up the test case
+  //   tear_down_tc: pointer to the function that tears down the test case
+  TestCase(const char* name, const char* comment,
+           Test::SetUpTestCaseFunc set_up_tc,
+           Test::TearDownTestCaseFunc tear_down_tc);
+
+  // Destructor of TestCase.
+  virtual ~TestCase();
+
+  // Gets the name of the TestCase.
+  const char* name() const { return name_.c_str(); }
+
+  // Returns the test case comment.
+  const char* comment() const { return comment_.c_str(); }
+
+  // Returns true if any test in this test case should run.
+  bool should_run() const { return should_run_; }
+
+  // Sets the should_run member.
+  void set_should_run(bool should) { should_run_ = should; }
+
+  // Gets the (mutable) list of TestInfos in this TestCase.
+  internal::List<TestInfo*>& test_info_list() { return *test_info_list_; }
+
+  // Gets the (immutable) list of TestInfos in this TestCase.
+  const internal::List<TestInfo *> & test_info_list() const {
+    return *test_info_list_;
+  }
+
+  // Gets the number of successful tests in this test case.
+  int successful_test_count() const;
+
+  // Gets the number of failed tests in this test case.
+  int failed_test_count() const;
+
+  // Gets the number of disabled tests in this test case.
+  int disabled_test_count() const;
+
+  // Get the number of tests in this test case that should run.
+  int test_to_run_count() const;
+
+  // Gets the number of all tests in this test case.
+  int total_test_count() const;
+
+  // Returns true iff the test case passed.
+  bool Passed() const { return !Failed(); }
+
+  // Returns true iff the test case failed.
+  bool Failed() const { return failed_test_count() > 0; }
+
+  // Returns the elapsed time, in milliseconds.
+  internal::TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+  // Adds a TestInfo to this test case.  Will delete the TestInfo upon
+  // destruction of the TestCase object.
+  void AddTestInfo(TestInfo * test_info);
+
+  // Finds and returns a TestInfo with the given name.  If one doesn't
+  // exist, returns NULL.
+  TestInfo* GetTestInfo(const char* test_name);
+
+  // Clears the results of all tests in this test case.
+  void ClearResult();
+
+  // Clears the results of all tests in the given test case.
+  static void ClearTestCaseResult(TestCase* test_case) {
+    test_case->ClearResult();
+  }
+
+  // Runs every test in this TestCase.
+  void Run();
+
+  // Runs every test in the given TestCase.
+  static void RunTestCase(TestCase * test_case) { test_case->Run(); }
+
+  // Returns true iff test passed.
+  static bool TestPassed(const TestInfo * test_info) {
+    const internal::TestInfoImpl* const impl = test_info->impl();
+    return impl->should_run() && impl->result()->Passed();
+  }
+
+  // Returns true iff test failed.
+  static bool TestFailed(const TestInfo * test_info) {
+    const internal::TestInfoImpl* const impl = test_info->impl();
+    return impl->should_run() && impl->result()->Failed();
+  }
+
+  // Returns true iff test is disabled.
+  static bool TestDisabled(const TestInfo * test_info) {
+    return test_info->impl()->is_disabled();
+  }
+
+  // Returns true if the given test should run.
+  static bool ShouldRunTest(const TestInfo *test_info) {
+    return test_info->impl()->should_run();
+  }
+
+ private:
+  // Name of the test case.
+  internal::String name_;
+  // Comment on the test case.
+  internal::String comment_;
+  // List of TestInfos.
+  internal::List<TestInfo*>* test_info_list_;
+  // Pointer to the function that sets up the test case.
+  Test::SetUpTestCaseFunc set_up_tc_;
+  // Pointer to the function that tears down the test case.
+  Test::TearDownTestCaseFunc tear_down_tc_;
+  // True iff any test in this test case should run.
+  bool should_run_;
+  // Elapsed time, in milliseconds.
+  internal::TimeInMillis elapsed_time_;
+
+  // We disallow copying TestCases.
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
+};
+
+namespace internal {
+
+// Class UnitTestOptions.
+//
+// This class contains functions for processing options the user
+// specifies when running the tests.  It has only static members.
+//
+// In most cases, the user can specify an option using either an
+// environment variable or a command line flag.  E.g. you can set the
+// test filter using either GTEST_FILTER or --gtest_filter.  If both
+// the variable and the flag are present, the latter overrides the
+// former.
+class UnitTestOptions {
+ public:
+  // Functions for processing the gtest_output flag.
+
+  // Returns the output format, or "" for normal printed output.
+  static String GetOutputFormat();
+
+  // Returns the absolute path of the requested output file, or the
+  // default (test_detail.xml in the original working directory) if
+  // none was explicitly specified.
+  static String GetAbsolutePathToOutputFile();
+
+  // Functions for processing the gtest_filter flag.
+
+  // Returns true iff the wildcard pattern matches the string.  The
+  // first ':' or '\0' character in pattern marks the end of it.
+  //
+  // This recursive algorithm isn't very efficient, but is clear and
+  // works well enough for matching test names, which are short.
+  static bool PatternMatchesString(const char *pattern, const char *str);
+
+  // Returns true iff the user-specified filter matches the test case
+  // name and the test name.
+  static bool FilterMatchesTest(const String &test_case_name,
+                                const String &test_name);
+
+#if GTEST_OS_WINDOWS
+  // Function for supporting the gtest_catch_exception flag.
+
+  // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+  // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+  // This function is useful as an __except condition.
+  static int GTestShouldProcessSEH(DWORD exception_code);
+#endif  // GTEST_OS_WINDOWS
+
+  // Returns true if "name" matches the ':' separated list of glob-style
+  // filters in "filter".
+  static bool MatchesFilter(const String& name, const char* filter);
+};
+
+// Returns the current application's name, removing directory path if that
+// is present.  Used by UnitTestOptions::GetOutputFile.
+FilePath GetCurrentExecutableName();
+
+// The role interface for getting the OS stack trace as a string.
+class OsStackTraceGetterInterface {
+ public:
+  OsStackTraceGetterInterface() {}
+  virtual ~OsStackTraceGetterInterface() {}
+
+  // Returns the current OS stack trace as a String.  Parameters:
+  //
+  //   max_depth  - the maximum number of stack frames to be included
+  //                in the trace.
+  //   skip_count - the number of top frames to be skipped; doesn't count
+  //                against max_depth.
+  virtual String CurrentStackTrace(int max_depth, int skip_count) = 0;
+
+  // UponLeavingGTest() should be called immediately before Google Test calls
+  // user code. It saves some information about the current stack that
+  // CurrentStackTrace() will use to find and hide Google Test stack frames.
+  virtual void UponLeavingGTest() = 0;
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
+};
+
+// A working implementation of the OsStackTraceGetterInterface interface.
+class OsStackTraceGetter : public OsStackTraceGetterInterface {
+ public:
+  OsStackTraceGetter() {}
+  virtual String CurrentStackTrace(int max_depth, int skip_count);
+  virtual void UponLeavingGTest();
+
+  // This string is inserted in place of stack frames that are part of
+  // Google Test's implementation.
+  static const char* const kElidedFramesMarker;
+
+ private:
+  Mutex mutex_;  // protects all internal state
+
+  // We save the stack frame below the frame that calls user code.
+  // We do this because the address of the frame immediately below
+  // the user code changes between the call to UponLeavingGTest()
+  // and any calls to CurrentStackTrace() from within the user code.
+  void* caller_frame_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
+};
+
+// Information about a Google Test trace point.
+struct TraceInfo {
+  const char* file;
+  int line;
+  String message;
+};
+
+// This is the default global test part result reporter used in UnitTestImpl.
+// This class should only be used by UnitTestImpl.
+class DefaultGlobalTestPartResultReporter
+  : public TestPartResultReporterInterface {
+ public:
+  explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
+  // Implements the TestPartResultReporterInterface. Reports the test part
+  // result in the current test.
+  virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+  UnitTestImpl* const unit_test_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter);
+};
+
+// This is the default per thread test part result reporter used in
+// UnitTestImpl. This class should only be used by UnitTestImpl.
+class DefaultPerThreadTestPartResultReporter
+    : public TestPartResultReporterInterface {
+ public:
+  explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
+  // Implements the TestPartResultReporterInterface. The implementation just
+  // delegates to the current global test part result reporter of *unit_test_.
+  virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+  UnitTestImpl* const unit_test_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter);
+};
+
+// The private implementation of the UnitTest class.  We don't protect
+// the methods under a mutex, as this class is not accessible by a
+// user and the UnitTest class that delegates work to this class does
+// proper locking.
+class UnitTestImpl {
+ public:
+  explicit UnitTestImpl(UnitTest* parent);
+  virtual ~UnitTestImpl();
+
+  // There are two different ways to register your own TestPartResultReporter.
+  // You can register your own repoter to listen either only for test results
+  // from the current thread or for results from all threads.
+  // By default, each per-thread test result repoter just passes a new
+  // TestPartResult to the global test result reporter, which registers the
+  // test part result for the currently running test.
+
+  // Returns the global test part result reporter.
+  TestPartResultReporterInterface* GetGlobalTestPartResultReporter();
+
+  // Sets the global test part result reporter.
+  void SetGlobalTestPartResultReporter(
+      TestPartResultReporterInterface* reporter);
+
+  // Returns the test part result reporter for the current thread.
+  TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();
+
+  // Sets the test part result reporter for the current thread.
+  void SetTestPartResultReporterForCurrentThread(
+      TestPartResultReporterInterface* reporter);
+
+  // Gets the number of successful test cases.
+  int successful_test_case_count() const;
+
+  // Gets the number of failed test cases.
+  int failed_test_case_count() const;
+
+  // Gets the number of all test cases.
+  int total_test_case_count() const;
+
+  // Gets the number of all test cases that contain at least one test
+  // that should run.
+  int test_case_to_run_count() const;
+
+  // Gets the number of successful tests.
+  int successful_test_count() const;
+
+  // Gets the number of failed tests.
+  int failed_test_count() const;
+
+  // Gets the number of disabled tests.
+  int disabled_test_count() const;
+
+  // Gets the number of all tests.
+  int total_test_count() const;
+
+  // Gets the number of tests that should run.
+  int test_to_run_count() const;
+
+  // Gets the elapsed time, in milliseconds.
+  TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+  // Returns true iff the unit test passed (i.e. all test cases passed).
+  bool Passed() const { return !Failed(); }
+
+  // Returns true iff the unit test failed (i.e. some test case failed
+  // or something outside of all tests failed).
+  bool Failed() const {
+    return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
+  }
+
+  // Returns the TestResult for the test that's currently running, or
+  // the TestResult for the ad hoc test if no test is running.
+  internal::TestResult* current_test_result();
+
+  // Returns the TestResult for the ad hoc test.
+  const internal::TestResult* ad_hoc_test_result() const {
+    return &ad_hoc_test_result_;
+  }
+
+  // Sets the unit test result printer.
+  //
+  // Does nothing if the input and the current printer object are the
+  // same; otherwise, deletes the old printer object and makes the
+  // input the current printer.
+  void set_result_printer(UnitTestEventListenerInterface * result_printer);
+
+  // Returns the current unit test result printer if it is not NULL;
+  // otherwise, creates an appropriate result printer, makes it the
+  // current printer, and returns it.
+  UnitTestEventListenerInterface* result_printer();
+
+  // Sets the OS stack trace getter.
+  //
+  // Does nothing if the input and the current OS stack trace getter
+  // are the same; otherwise, deletes the old getter and makes the
+  // input the current getter.
+  void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);
+
+  // Returns the current OS stack trace getter if it is not NULL;
+  // otherwise, creates an OsStackTraceGetter, makes it the current
+  // getter, and returns it.
+  OsStackTraceGetterInterface* os_stack_trace_getter();
+
+  // Returns the current OS stack trace as a String.
+  //
+  // The maximum number of stack frames to be included is specified by
+  // the gtest_stack_trace_depth flag.  The skip_count parameter
+  // specifies the number of top frames to be skipped, which doesn't
+  // count against the number of frames to be included.
+  //
+  // For example, if Foo() calls Bar(), which in turn calls
+  // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+  // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+  String CurrentOsStackTraceExceptTop(int skip_count);
+
+  // Finds and returns a TestCase with the given name.  If one doesn't
+  // exist, creates one and returns it.
+  //
+  // Arguments:
+  //
+  //   test_case_name: name of the test case
+  //   set_up_tc:      pointer to the function that sets up the test case
+  //   tear_down_tc:   pointer to the function that tears down the test case
+  TestCase* GetTestCase(const char* test_case_name,
+                        const char* comment,
+                        Test::SetUpTestCaseFunc set_up_tc,
+                        Test::TearDownTestCaseFunc tear_down_tc);
+
+  // Adds a TestInfo to the unit test.
+  //
+  // Arguments:
+  //
+  //   set_up_tc:    pointer to the function that sets up the test case
+  //   tear_down_tc: pointer to the function that tears down the test case
+  //   test_info:    the TestInfo object
+  void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
+                   Test::TearDownTestCaseFunc tear_down_tc,
+                   TestInfo * test_info) {
+    // In order to support thread-safe death tests, we need to
+    // remember the original working directory when the test program
+    // was first invoked.  We cannot do this in RUN_ALL_TESTS(), as
+    // the user may have changed the current directory before calling
+    // RUN_ALL_TESTS().  Therefore we capture the current directory in
+    // AddTestInfo(), which is called to register a TEST or TEST_F
+    // before main() is reached.
+    if (original_working_dir_.IsEmpty()) {
+      original_working_dir_.Set(FilePath::GetCurrentDir());
+      if (original_working_dir_.IsEmpty()) {
+        printf("%s\n", "Failed to get the current working directory.");
+        abort();
+      }
+    }
+
+    GetTestCase(test_info->test_case_name(),
+                test_info->test_case_comment(),
+                set_up_tc,
+                tear_down_tc)->AddTestInfo(test_info);
+  }
+
+#if GTEST_HAS_PARAM_TEST
+  // Returns ParameterizedTestCaseRegistry object used to keep track of
+  // value-parameterized tests and instantiate and register them.
+  internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
+    return parameterized_test_registry_;
+  }
+#endif  // GTEST_HAS_PARAM_TEST
+
+  // Sets the TestCase object for the test that's currently running.
+  void set_current_test_case(TestCase* current_test_case) {
+    current_test_case_ = current_test_case;
+  }
+
+  // Sets the TestInfo object for the test that's currently running.  If
+  // current_test_info is NULL, the assertion results will be stored in
+  // ad_hoc_test_result_.
+  void set_current_test_info(TestInfo* current_test_info) {
+    current_test_info_ = current_test_info;
+  }
+
+  // Registers all parameterized tests defined using TEST_P and
+  // INSTANTIATE_TEST_P, creating regular tests for each test/parameter
+  // combination. This method can be called more then once; it has
+  // guards protecting from registering the tests more then once.
+  // If value-parameterized tests are disabled, RegisterParameterizedTests
+  // is present but does nothing.
+  void RegisterParameterizedTests();
+
+  // Runs all tests in this UnitTest object, prints the result, and
+  // returns 0 if all tests are successful, or 1 otherwise.  If any
+  // exception is thrown during a test on Windows, this test is
+  // considered to be failed, but the rest of the tests will still be
+  // run.  (We disable exceptions on Linux and Mac OS X, so the issue
+  // doesn't apply there.)
+  int RunAllTests();
+
+  // Clears the results of all tests, including the ad hoc test.
+  void ClearResult() {
+    test_cases_.ForEach(TestCase::ClearTestCaseResult);
+    ad_hoc_test_result_.Clear();
+  }
+
+  enum ReactionToSharding {
+    HONOR_SHARDING_PROTOCOL,
+    IGNORE_SHARDING_PROTOCOL
+  };
+
+  // Matches the full name of each test against the user-specified
+  // filter to decide whether the test should run, then records the
+  // result in each TestCase and TestInfo object.
+  // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
+  // based on sharding variables in the environment.
+  // Returns the number of tests that should run.
+  int FilterTests(ReactionToSharding shard_tests);
+
+  // Prints the names of the tests matching the user-specified filter flag.
+  void ListTestsMatchingFilter();
+
+  const TestCase* current_test_case() const { return current_test_case_; }
+  TestInfo* current_test_info() { return current_test_info_; }
+  const TestInfo* current_test_info() const { return current_test_info_; }
+
+  // Returns the list of environments that need to be set-up/torn-down
+  // before/after the tests are run.
+  internal::List<Environment*>* environments() { return &environments_; }
+  internal::List<Environment*>* environments_in_reverse_order() {
+    return &environments_in_reverse_order_;
+  }
+
+  internal::List<TestCase*>* test_cases() { return &test_cases_; }
+  const internal::List<TestCase*>* test_cases() const { return &test_cases_; }
+
+  // Getters for the per-thread Google Test trace stack.
+  internal::List<TraceInfo>* gtest_trace_stack() {
+    return gtest_trace_stack_.pointer();
+  }
+  const internal::List<TraceInfo>* gtest_trace_stack() const {
+    return gtest_trace_stack_.pointer();
+  }
+
+#if GTEST_HAS_DEATH_TEST
+  // Returns a pointer to the parsed --gtest_internal_run_death_test
+  // flag, or NULL if that flag was not specified.
+  // This information is useful only in a death test child process.
+  const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
+    return internal_run_death_test_flag_.get();
+  }
+
+  // Returns a pointer to the current death test factory.
+  internal::DeathTestFactory* death_test_factory() {
+    return death_test_factory_.get();
+  }
+
+  friend class ReplaceDeathTestFactory;
+#endif  // GTEST_HAS_DEATH_TEST
+
+ private:
+  friend class ::testing::UnitTest;
+
+  // The UnitTest object that owns this implementation object.
+  UnitTest* const parent_;
+
+  // The working directory when the first TEST() or TEST_F() was
+  // executed.
+  internal::FilePath original_working_dir_;
+
+  // The default test part result reporters.
+  DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;
+  DefaultPerThreadTestPartResultReporter
+      default_per_thread_test_part_result_reporter_;
+
+  // Points to (but doesn't own) the global test part result reporter.
+  TestPartResultReporterInterface* global_test_part_result_repoter_;
+
+  // Protects read and write access to global_test_part_result_reporter_.
+  internal::Mutex global_test_part_result_reporter_mutex_;
+
+  // Points to (but doesn't own) the per-thread test part result reporter.
+  internal::ThreadLocal<TestPartResultReporterInterface*>
+      per_thread_test_part_result_reporter_;
+
+  // The list of environments that need to be set-up/torn-down
+  // before/after the tests are run.  environments_in_reverse_order_
+  // simply mirrors environments_ in reverse order.
+  internal::List<Environment*> environments_;
+  internal::List<Environment*> environments_in_reverse_order_;
+
+  internal::List<TestCase*> test_cases_;  // The list of TestCases.
+
+#if GTEST_HAS_PARAM_TEST
+  // ParameterizedTestRegistry object used to register value-parameterized
+  // tests.
+  internal::ParameterizedTestCaseRegistry parameterized_test_registry_;
+
+  // Indicates whether RegisterParameterizedTests() has been called already.
+  bool parameterized_tests_registered_;
+#endif  // GTEST_HAS_PARAM_TEST
+
+  // Points to the last death test case registered.  Initially NULL.
+  internal::ListNode<TestCase*>* last_death_test_case_;
+
+  // This points to the TestCase for the currently running test.  It
+  // changes as Google Test goes through one test case after another.
+  // When no test is running, this is set to NULL and Google Test
+  // stores assertion results in ad_hoc_test_result_.  Initally NULL.
+  TestCase* current_test_case_;
+
+  // This points to the TestInfo for the currently running test.  It
+  // changes as Google Test goes through one test after another.  When
+  // no test is running, this is set to NULL and Google Test stores
+  // assertion results in ad_hoc_test_result_.  Initially NULL.
+  TestInfo* current_test_info_;
+
+  // Normally, a user only writes assertions inside a TEST or TEST_F,
+  // or inside a function called by a TEST or TEST_F.  Since Google
+  // Test keeps track of which test is current running, it can
+  // associate such an assertion with the test it belongs to.
+  //
+  // If an assertion is encountered when no TEST or TEST_F is running,
+  // Google Test attributes the assertion result to an imaginary "ad hoc"
+  // test, and records the result in ad_hoc_test_result_.
+  internal::TestResult ad_hoc_test_result_;
+
+  // The unit test result printer.  Will be deleted when the UnitTest
+  // object is destructed.  By default, a plain text printer is used,
+  // but the user can set this field to use a custom printer if that
+  // is desired.
+  UnitTestEventListenerInterface* result_printer_;
+
+  // The OS stack trace getter.  Will be deleted when the UnitTest
+  // object is destructed.  By default, an OsStackTraceGetter is used,
+  // but the user can set this field to use a custom getter if that is
+  // desired.
+  OsStackTraceGetterInterface* os_stack_trace_getter_;
+
+  // How long the test took to run, in milliseconds.
+  TimeInMillis elapsed_time_;
+
+#if GTEST_HAS_DEATH_TEST
+  // The decomposed components of the gtest_internal_run_death_test flag,
+  // parsed when RUN_ALL_TESTS is called.
+  internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+  internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
+#endif  // GTEST_HAS_DEATH_TEST
+
+  // A per-thread stack of traces created by the SCOPED_TRACE() macro.
+  internal::ThreadLocal<internal::List<TraceInfo> > gtest_trace_stack_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
+};  // class UnitTestImpl
+
+// Convenience function for accessing the global UnitTest
+// implementation object.
+inline UnitTestImpl* GetUnitTestImpl() {
+  return UnitTest::GetInstance()->impl();
+}
+
+// Clears all test part results of the current test.
+inline void ClearCurrentTestPartResults() {
+  GetUnitTestImpl()->current_test_result()->ClearTestPartResults();
+}
+
+// Internal helper functions for implementing the simple regular
+// expression matcher.
+bool IsInSet(char ch, const char* str);
+bool IsDigit(char ch);
+bool IsPunct(char ch);
+bool IsRepeat(char ch);
+bool IsWhiteSpace(char ch);
+bool IsWordChar(char ch);
+bool IsValidEscape(char ch);
+bool AtomMatchesChar(bool escaped, char pattern, char ch);
+bool ValidateRegex(const char* regex);
+bool MatchRegexAtHead(const char* regex, const char* str);
+bool MatchRepetitionAndRegexAtHead(
+    bool escaped, char ch, char repeat, const char* regex, const char* str);
+bool MatchRegexAnywhere(const char* regex, const char* str);
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+void ParseGoogleTestFlagsOnly(int* argc, char** argv);
+void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
+
+#if GTEST_HAS_DEATH_TEST
+
+// Returns the message describing the last system error, regardless of the
+// platform.
+String GetLastErrnoDescription();
+
+#if GTEST_OS_WINDOWS
+// Provides leak-safe Windows kernel handle ownership.
+class AutoHandle {
+ public:
+  AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
+  explicit AutoHandle(HANDLE handle) : handle_(handle) {}
+
+  ~AutoHandle() { Reset(); }
+
+  HANDLE Get() const { return handle_; }
+  void Reset() { Reset(INVALID_HANDLE_VALUE); }
+  void Reset(HANDLE handle) {
+    if (handle != handle_) {
+      if (handle_ != INVALID_HANDLE_VALUE)
+        ::CloseHandle(handle_);
+      handle_ = handle;
+    }
+  }
+
+ private:
+  HANDLE handle_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
+};
+#endif  // GTEST_OS_WINDOWS
+
+// Attempts to parse a string into a positive integer pointed to by the
+// number parameter.  Returns true if that is possible.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
+// it here.
+template <typename Integer>
+bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
+  // Fail fast if the given string does not begin with a digit;
+  // this bypasses strtoXXX's "optional leading whitespace and plus
+  // or minus sign" semantics, which are undesirable here.
+  if (str.empty() || !isdigit(str[0])) {
+    return false;
+  }
+  errno = 0;
+
+  char* end;
+  // BiggestConvertible is the largest integer type that system-provided
+  // string-to-number conversion routines can return.
+#if GTEST_OS_WINDOWS
+  typedef unsigned __int64 BiggestConvertible;
+  const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);
+#else
+  typedef unsigned long long BiggestConvertible;  // NOLINT
+  const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);
+#endif  // GTEST_OS_WINDOWS
+  const bool parse_success = *end == '\0' && errno == 0;
+
+  // TODO(vladl@google.com): Convert this to compile time assertion when it is
+  // available.
+  GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
+
+  const Integer result = static_cast<Integer>(parsed);
+  if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {
+    *number = result;
+    return true;
+  }
+  return false;
+}
+#endif  // GTEST_HAS_DEATH_TEST
+
+}  // namespace internal
+}  // namespace testing
+
+#endif  // GTEST_SRC_GTEST_INTERNAL_INL_H_
diff --git a/third_party/gtest/src/gtest-port.cc b/third_party/gtest/src/gtest-port.cc
index 61129e1..7f6db79 100644
--- a/third_party/gtest/src/gtest-port.cc
+++ b/third_party/gtest/src/gtest-port.cc
@@ -1,672 +1,672 @@
-// Copyright 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan)

-

-#include <gtest/internal/gtest-port.h>

-

-#include <limits.h>

-#include <stdlib.h>

-#include <stdio.h>

-

-#if GTEST_OS_WINDOWS

-#include <io.h>

-#include <sys/stat.h>

-#else

-#include <unistd.h>

-#endif  // GTEST_OS_WINDOWS

-

-#if GTEST_OS_MAC

-#include <mach/mach_init.h>

-#include <mach/task.h>

-#include <mach/vm_map.h>

-#endif  // GTEST_OS_MAC

-

-#ifdef _WIN32_WCE

-#include <windows.h>  // For TerminateProcess()

-#endif  // _WIN32_WCE

-

-#include <gtest/gtest-spi.h>

-#include <gtest/gtest-message.h>

-#include <gtest/internal/gtest-string.h>

-

-// Indicates that this translation unit is part of Google Test's

-// implementation.  It must come before gtest-internal-inl.h is

-// included, or there will be a compiler error.  This trick is to

-// prevent a user from accidentally including gtest-internal-inl.h in

-// his code.

-#define GTEST_IMPLEMENTATION_ 1

-#include "src/gtest-internal-inl.h"

-#undef GTEST_IMPLEMENTATION_

-

-namespace testing {

-namespace internal {

-

-#if defined(_MSC_VER) || defined(__BORLANDC__)

-// MSVC and C++Builder do not provide a definition of STDERR_FILENO.

-const int kStdErrFileno = 2;

-#else

-const int kStdErrFileno = STDERR_FILENO;

-#endif  // _MSC_VER

-

-#if GTEST_OS_MAC

-

-// Returns the number of threads running in the process, or 0 to indicate that

-// we cannot detect it.

-size_t GetThreadCount() {

-  const task_t task = mach_task_self();

-  mach_msg_type_number_t thread_count;

-  thread_act_array_t thread_list;

-  const kern_return_t status = task_threads(task, &thread_list, &thread_count);

-  if (status == KERN_SUCCESS) {

-    // task_threads allocates resources in thread_list and we need to free them

-    // to avoid leaks.

-    vm_deallocate(task,

-                  reinterpret_cast<vm_address_t>(thread_list),

-                  sizeof(thread_t) * thread_count);

-    return static_cast<size_t>(thread_count);

-  } else {

-    return 0;

-  }

-}

-

-#else

-

-size_t GetThreadCount() {

-  // There's no portable way to detect the number of threads, so we just

-  // return 0 to indicate that we cannot detect it.

-  return 0;

-}

-

-#endif  // GTEST_OS_MAC

-

-#if GTEST_USES_POSIX_RE

-

-// Implements RE.  Currently only needed for death tests.

-

-RE::~RE() {

-  regfree(&partial_regex_);

-  regfree(&full_regex_);

-  free(const_cast<char*>(pattern_));

-}

-

-// Returns true iff regular expression re matches the entire str.

-bool RE::FullMatch(const char* str, const RE& re) {

-  if (!re.is_valid_) return false;

-

-  regmatch_t match;

-  return regexec(&re.full_regex_, str, 1, &match, 0) == 0;

-}

-

-// Returns true iff regular expression re matches a substring of str

-// (including str itself).

-bool RE::PartialMatch(const char* str, const RE& re) {

-  if (!re.is_valid_) return false;

-

-  regmatch_t match;

-  return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;

-}

-

-// Initializes an RE from its string representation.

-void RE::Init(const char* regex) {

-  pattern_ = posix::StrDup(regex);

-

-  // Reserves enough bytes to hold the regular expression used for a

-  // full match.

-  const size_t full_regex_len = strlen(regex) + 10;

-  char* const full_pattern = new char[full_regex_len];

-

-  snprintf(full_pattern, full_regex_len, "^(%s)$", regex);

-  is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;

-  // We want to call regcomp(&partial_regex_, ...) even if the

-  // previous expression returns false.  Otherwise partial_regex_ may

-  // not be properly initialized can may cause trouble when it's

-  // freed.

-  //

-  // Some implementation of POSIX regex (e.g. on at least some

-  // versions of Cygwin) doesn't accept the empty string as a valid

-  // regex.  We change it to an equivalent form "()" to be safe.

-  const char* const partial_regex = (*regex == '\0') ? "()" : regex;

-  is_valid_ = (regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0)

-      && is_valid_;

-  EXPECT_TRUE(is_valid_)

-      << "Regular expression \"" << regex

-      << "\" is not a valid POSIX Extended regular expression.";

-

-  delete[] full_pattern;

-}

-

-#elif GTEST_USES_SIMPLE_RE

-

-// Returns true iff ch appears anywhere in str (excluding the

-// terminating '\0' character).

-bool IsInSet(char ch, const char* str) {

-  return ch != '\0' && strchr(str, ch) != NULL;

-}

-

-// Returns true iff ch belongs to the given classification.  Unlike

-// similar functions in <ctype.h>, these aren't affected by the

-// current locale.

-bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; }

-bool IsPunct(char ch) {

-  return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");

-}

-bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }

-bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }

-bool IsWordChar(char ch) {

-  return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||

-      ('0' <= ch && ch <= '9') || ch == '_';

-}

-

-// Returns true iff "\\c" is a supported escape sequence.

-bool IsValidEscape(char c) {

-  return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW"));

-}

-

-// Returns true iff the given atom (specified by escaped and pattern)

-// matches ch.  The result is undefined if the atom is invalid.

-bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {

-  if (escaped) {  // "\\p" where p is pattern_char.

-    switch (pattern_char) {

-      case 'd': return IsDigit(ch);

-      case 'D': return !IsDigit(ch);

-      case 'f': return ch == '\f';

-      case 'n': return ch == '\n';

-      case 'r': return ch == '\r';

-      case 's': return IsWhiteSpace(ch);

-      case 'S': return !IsWhiteSpace(ch);

-      case 't': return ch == '\t';

-      case 'v': return ch == '\v';

-      case 'w': return IsWordChar(ch);

-      case 'W': return !IsWordChar(ch);

-    }

-    return IsPunct(pattern_char) && pattern_char == ch;

-  }

-

-  return (pattern_char == '.' && ch != '\n') || pattern_char == ch;

-}

-

-// Helper function used by ValidateRegex() to format error messages.

-String FormatRegexSyntaxError(const char* regex, int index) {

-  return (Message() << "Syntax error at index " << index

-          << " in simple regular expression \"" << regex << "\": ").GetString();

-}

-

-// Generates non-fatal failures and returns false if regex is invalid;

-// otherwise returns true.

-bool ValidateRegex(const char* regex) {

-  if (regex == NULL) {

-    // TODO(wan@google.com): fix the source file location in the

-    // assertion failures to match where the regex is used in user

-    // code.

-    ADD_FAILURE() << "NULL is not a valid simple regular expression.";

-    return false;

-  }

-

-  bool is_valid = true;

-

-  // True iff ?, *, or + can follow the previous atom.

-  bool prev_repeatable = false;

-  for (int i = 0; regex[i]; i++) {

-    if (regex[i] == '\\') {  // An escape sequence

-      i++;

-      if (regex[i] == '\0') {

-        ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)

-                      << "'\\' cannot appear at the end.";

-        return false;

-      }

-

-      if (!IsValidEscape(regex[i])) {

-        ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)

-                      << "invalid escape sequence \"\\" << regex[i] << "\".";

-        is_valid = false;

-      }

-      prev_repeatable = true;

-    } else {  // Not an escape sequence.

-      const char ch = regex[i];

-

-      if (ch == '^' && i > 0) {

-        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)

-                      << "'^' can only appear at the beginning.";

-        is_valid = false;

-      } else if (ch == '$' && regex[i + 1] != '\0') {

-        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)

-                      << "'$' can only appear at the end.";

-        is_valid = false;

-      } else if (IsInSet(ch, "()[]{}|")) {

-        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)

-                      << "'" << ch << "' is unsupported.";

-        is_valid = false;

-      } else if (IsRepeat(ch) && !prev_repeatable) {

-        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)

-                      << "'" << ch << "' can only follow a repeatable token.";

-        is_valid = false;

-      }

-

-      prev_repeatable = !IsInSet(ch, "^$?*+");

-    }

-  }

-

-  return is_valid;

-}

-

-// Matches a repeated regex atom followed by a valid simple regular

-// expression.  The regex atom is defined as c if escaped is false,

-// or \c otherwise.  repeat is the repetition meta character (?, *,

-// or +).  The behavior is undefined if str contains too many

-// characters to be indexable by size_t, in which case the test will

-// probably time out anyway.  We are fine with this limitation as

-// std::string has it too.

-bool MatchRepetitionAndRegexAtHead(

-    bool escaped, char c, char repeat, const char* regex,

-    const char* str) {

-  const size_t min_count = (repeat == '+') ? 1 : 0;

-  const size_t max_count = (repeat == '?') ? 1 :

-      static_cast<size_t>(-1) - 1;

-  // We cannot call numeric_limits::max() as it conflicts with the

-  // max() macro on Windows.

-

-  for (size_t i = 0; i <= max_count; ++i) {

-    // We know that the atom matches each of the first i characters in str.

-    if (i >= min_count && MatchRegexAtHead(regex, str + i)) {

-      // We have enough matches at the head, and the tail matches too.

-      // Since we only care about *whether* the pattern matches str

-      // (as opposed to *how* it matches), there is no need to find a

-      // greedy match.

-      return true;

-    }

-    if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i]))

-      return false;

-  }

-  return false;

-}

-

-// Returns true iff regex matches a prefix of str.  regex must be a

-// valid simple regular expression and not start with "^", or the

-// result is undefined.

-bool MatchRegexAtHead(const char* regex, const char* str) {

-  if (*regex == '\0')  // An empty regex matches a prefix of anything.

-    return true;

-

-  // "$" only matches the end of a string.  Note that regex being

-  // valid guarantees that there's nothing after "$" in it.

-  if (*regex == '$')

-    return *str == '\0';

-

-  // Is the first thing in regex an escape sequence?

-  const bool escaped = *regex == '\\';

-  if (escaped)

-    ++regex;

-  if (IsRepeat(regex[1])) {

-    // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so

-    // here's an indirect recursion.  It terminates as the regex gets

-    // shorter in each recursion.

-    return MatchRepetitionAndRegexAtHead(

-        escaped, regex[0], regex[1], regex + 2, str);

-  } else {

-    // regex isn't empty, isn't "$", and doesn't start with a

-    // repetition.  We match the first atom of regex with the first

-    // character of str and recurse.

-    return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) &&

-        MatchRegexAtHead(regex + 1, str + 1);

-  }

-}

-

-// Returns true iff regex matches any substring of str.  regex must be

-// a valid simple regular expression, or the result is undefined.

-//

-// The algorithm is recursive, but the recursion depth doesn't exceed

-// the regex length, so we won't need to worry about running out of

-// stack space normally.  In rare cases the time complexity can be

-// exponential with respect to the regex length + the string length,

-// but usually it's must faster (often close to linear).

-bool MatchRegexAnywhere(const char* regex, const char* str) {

-  if (regex == NULL || str == NULL)

-    return false;

-

-  if (*regex == '^')

-    return MatchRegexAtHead(regex + 1, str);

-

-  // A successful match can be anywhere in str.

-  do {

-    if (MatchRegexAtHead(regex, str))

-      return true;

-  } while (*str++ != '\0');

-  return false;

-}

-

-// Implements the RE class.

-

-RE::~RE() {

-  free(const_cast<char*>(pattern_));

-  free(const_cast<char*>(full_pattern_));

-}

-

-// Returns true iff regular expression re matches the entire str.

-bool RE::FullMatch(const char* str, const RE& re) {

-  return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);

-}

-

-// Returns true iff regular expression re matches a substring of str

-// (including str itself).

-bool RE::PartialMatch(const char* str, const RE& re) {

-  return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);

-}

-

-// Initializes an RE from its string representation.

-void RE::Init(const char* regex) {

-  pattern_ = full_pattern_ = NULL;

-  if (regex != NULL) {

-    pattern_ = posix::StrDup(regex);

-  }

-

-  is_valid_ = ValidateRegex(regex);

-  if (!is_valid_) {

-    // No need to calculate the full pattern when the regex is invalid.

-    return;

-  }

-

-  const size_t len = strlen(regex);

-  // Reserves enough bytes to hold the regular expression used for a

-  // full match: we need space to prepend a '^', append a '$', and

-  // terminate the string with '\0'.

-  char* buffer = static_cast<char*>(malloc(len + 3));

-  full_pattern_ = buffer;

-

-  if (*regex != '^')

-    *buffer++ = '^';  // Makes sure full_pattern_ starts with '^'.

-

-  // We don't use snprintf or strncpy, as they trigger a warning when

-  // compiled with VC++ 8.0.

-  memcpy(buffer, regex, len);

-  buffer += len;

-

-  if (len == 0 || regex[len - 1] != '$')

-    *buffer++ = '$';  // Makes sure full_pattern_ ends with '$'.

-

-  *buffer = '\0';

-}

-

-#endif  // GTEST_USES_POSIX_RE

-

-// Logs a message at the given severity level.

-void GTestLog(GTestLogSeverity severity, const char* file,

-              int line, const char* msg) {

-  const char* const marker =

-      severity == GTEST_INFO ?    "[  INFO ]" :

-      severity == GTEST_WARNING ? "[WARNING]" :

-      severity == GTEST_ERROR ?   "[ ERROR ]" : "[ FATAL ]";

-  fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg);

-  if (severity == GTEST_FATAL) {

-    fflush(NULL);  // abort() is not guaranteed to flush open file streams.

-    abort();

-  }

-}

-

-#if GTEST_HAS_STD_STRING

-

-// Disable Microsoft deprecation warnings for POSIX functions called from

-// this class (creat, dup, dup2, and close)

-#ifdef _MSC_VER

-#pragma warning(push)

-#pragma warning(disable: 4996)

-#endif  // _MSC_VER

-

-// Defines the stderr capturer.

-

-class CapturedStderr {

- public:

-  // The ctor redirects stderr to a temporary file.

-  CapturedStderr() {

-    uncaptured_fd_ = dup(kStdErrFileno);

-

-#if GTEST_OS_WINDOWS

-    char temp_dir_path[MAX_PATH + 1] = { '\0' };  // NOLINT

-    char temp_file_path[MAX_PATH + 1] = { '\0' };  // NOLINT

-

-    ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);

-    ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, temp_file_path);

-    const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);

-    filename_ = temp_file_path;

-#else

-    // There's no guarantee that a test has write access to the

-    // current directory, so we create the temporary file in the /tmp

-    // directory instead.

-    char name_template[] = "/tmp/captured_stderr.XXXXXX";

-    const int captured_fd = mkstemp(name_template);

-    filename_ = name_template;

-#endif  // GTEST_OS_WINDOWS

-    fflush(NULL);

-    dup2(captured_fd, kStdErrFileno);

-    close(captured_fd);

-  }

-

-  ~CapturedStderr() {

-    remove(filename_.c_str());

-  }

-

-  // Stops redirecting stderr.

-  void StopCapture() {

-    // Restores the original stream.

-    fflush(NULL);

-    dup2(uncaptured_fd_, kStdErrFileno);

-    close(uncaptured_fd_);

-    uncaptured_fd_ = -1;

-  }

-

-  // Returns the name of the temporary file holding the stderr output.

-  // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we

-  // can use it here.

-  ::std::string filename() const { return filename_; }

-

- private:

-  int uncaptured_fd_;

-  ::std::string filename_;

-};

-

-#ifdef _MSC_VER

-#pragma warning(pop)

-#endif  // _MSC_VER

-

-static CapturedStderr* g_captured_stderr = NULL;

-

-// Returns the size (in bytes) of a file.

-static size_t GetFileSize(FILE * file) {

-  fseek(file, 0, SEEK_END);

-  return static_cast<size_t>(ftell(file));

-}

-

-// Reads the entire content of a file as a string.

-static ::std::string ReadEntireFile(FILE * file) {

-  const size_t file_size = GetFileSize(file);

-  char* const buffer = new char[file_size];

-

-  size_t bytes_last_read = 0;  // # of bytes read in the last fread()

-  size_t bytes_read = 0;       // # of bytes read so far

-

-  fseek(file, 0, SEEK_SET);

-

-  // Keeps reading the file until we cannot read further or the

-  // pre-determined file size is reached.

-  do {

-    bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);

-    bytes_read += bytes_last_read;

-  } while (bytes_last_read > 0 && bytes_read < file_size);

-

-  const ::std::string content(buffer, buffer+bytes_read);

-  delete[] buffer;

-

-  return content;

-}

-

-// Starts capturing stderr.

-void CaptureStderr() {

-  if (g_captured_stderr != NULL) {

-    GTEST_LOG_(FATAL, "Only one stderr capturer can exist at one time.");

-  }

-  g_captured_stderr = new CapturedStderr;

-}

-

-// Stops capturing stderr and returns the captured string.

-// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can

-// use it here.

-::std::string GetCapturedStderr() {

-  g_captured_stderr->StopCapture();

-

-  FILE* const file = posix::FOpen(g_captured_stderr->filename().c_str(), "r");

-  const ::std::string content = ReadEntireFile(file);

-  posix::FClose(file);

-

-  delete g_captured_stderr;

-  g_captured_stderr = NULL;

-

-  return content;

-}

-

-#endif  // GTEST_HAS_STD_STRING

-

-#if GTEST_HAS_DEATH_TEST

-

-// A copy of all command line arguments.  Set by InitGoogleTest().

-::std::vector<String> g_argvs;

-

-// Returns the command line as a vector of strings.

-const ::std::vector<String>& GetArgvs() { return g_argvs; }

-

-#endif  // GTEST_HAS_DEATH_TEST

-

-#ifdef _WIN32_WCE

-namespace posix {

-void Abort() {

-  DebugBreak();

-  TerminateProcess(GetCurrentProcess(), 1);

-}

-}  // namespace posix

-#endif  // _WIN32_WCE

-

-// Returns the name of the environment variable corresponding to the

-// given flag.  For example, FlagToEnvVar("foo") will return

-// "GTEST_FOO" in the open-source version.

-static String FlagToEnvVar(const char* flag) {

-  const String full_flag =

-      (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();

-

-  Message env_var;

-  for (int i = 0; i != full_flag.GetLength(); i++) {

-    env_var << static_cast<char>(toupper(full_flag.c_str()[i]));

-  }

-

-  return env_var.GetString();

-}

-

-// Parses 'str' for a 32-bit signed integer.  If successful, writes

-// the result to *value and returns true; otherwise leaves *value

-// unchanged and returns false.

-bool ParseInt32(const Message& src_text, const char* str, Int32* value) {

-  // Parses the environment variable as a decimal integer.

-  char* end = NULL;

-  const long long_value = strtol(str, &end, 10);  // NOLINT

-

-  // Has strtol() consumed all characters in the string?

-  if (*end != '\0') {

-    // No - an invalid character was encountered.

-    Message msg;

-    msg << "WARNING: " << src_text

-        << " is expected to be a 32-bit integer, but actually"

-        << " has value \"" << str << "\".\n";

-    printf("%s", msg.GetString().c_str());

-    fflush(stdout);

-    return false;

-  }

-

-  // Is the parsed value in the range of an Int32?

-  const Int32 result = static_cast<Int32>(long_value);

-  if (long_value == LONG_MAX || long_value == LONG_MIN ||

-      // The parsed value overflows as a long.  (strtol() returns

-      // LONG_MAX or LONG_MIN when the input overflows.)

-      result != long_value

-      // The parsed value overflows as an Int32.

-      ) {

-    Message msg;

-    msg << "WARNING: " << src_text

-        << " is expected to be a 32-bit integer, but actually"

-        << " has value " << str << ", which overflows.\n";

-    printf("%s", msg.GetString().c_str());

-    fflush(stdout);

-    return false;

-  }

-

-  *value = result;

-  return true;

-}

-

-// Reads and returns the Boolean environment variable corresponding to

-// the given flag; if it's not set, returns default_value.

-//

-// The value is considered true iff it's not "0".

-bool BoolFromGTestEnv(const char* flag, bool default_value) {

-  const String env_var = FlagToEnvVar(flag);

-  const char* const string_value = posix::GetEnv(env_var.c_str());

-  return string_value == NULL ?

-      default_value : strcmp(string_value, "0") != 0;

-}

-

-// Reads and returns a 32-bit integer stored in the environment

-// variable corresponding to the given flag; if it isn't set or

-// doesn't represent a valid 32-bit integer, returns default_value.

-Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {

-  const String env_var = FlagToEnvVar(flag);

-  const char* const string_value = posix::GetEnv(env_var.c_str());

-  if (string_value == NULL) {

-    // The environment variable is not set.

-    return default_value;

-  }

-

-  Int32 result = default_value;

-  if (!ParseInt32(Message() << "Environment variable " << env_var,

-                  string_value, &result)) {

-    printf("The default value %s is used.\n",

-           (Message() << default_value).GetString().c_str());

-    fflush(stdout);

-    return default_value;

-  }

-

-  return result;

-}

-

-// Reads and returns the string environment variable corresponding to

-// the given flag; if it's not set, returns default_value.

-const char* StringFromGTestEnv(const char* flag, const char* default_value) {

-  const String env_var = FlagToEnvVar(flag);

-  const char* const value = posix::GetEnv(env_var.c_str());

-  return value == NULL ? default_value : value;

-}

-

-}  // namespace internal

-}  // namespace testing

+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/internal/gtest-port.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if GTEST_OS_WINDOWS
+#include <io.h>
+#include <sys/stat.h>
+#else
+#include <unistd.h>
+#endif  // GTEST_OS_WINDOWS
+
+#if GTEST_OS_MAC
+#include <mach/mach_init.h>
+#include <mach/task.h>
+#include <mach/vm_map.h>
+#endif  // GTEST_OS_MAC
+
+#ifdef _WIN32_WCE
+#include <windows.h>  // For TerminateProcess()
+#endif  // _WIN32_WCE
+
+#include <gtest/gtest-spi.h>
+#include <gtest/gtest-message.h>
+#include <gtest/internal/gtest-string.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+namespace internal {
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
+const int kStdErrFileno = 2;
+#else
+const int kStdErrFileno = STDERR_FILENO;
+#endif  // _MSC_VER
+
+#if GTEST_OS_MAC
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+  const task_t task = mach_task_self();
+  mach_msg_type_number_t thread_count;
+  thread_act_array_t thread_list;
+  const kern_return_t status = task_threads(task, &thread_list, &thread_count);
+  if (status == KERN_SUCCESS) {
+    // task_threads allocates resources in thread_list and we need to free them
+    // to avoid leaks.
+    vm_deallocate(task,
+                  reinterpret_cast<vm_address_t>(thread_list),
+                  sizeof(thread_t) * thread_count);
+    return static_cast<size_t>(thread_count);
+  } else {
+    return 0;
+  }
+}
+
+#else
+
+size_t GetThreadCount() {
+  // There's no portable way to detect the number of threads, so we just
+  // return 0 to indicate that we cannot detect it.
+  return 0;
+}
+
+#endif  // GTEST_OS_MAC
+
+#if GTEST_USES_POSIX_RE
+
+// Implements RE.  Currently only needed for death tests.
+
+RE::~RE() {
+  regfree(&partial_regex_);
+  regfree(&full_regex_);
+  free(const_cast<char*>(pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+  if (!re.is_valid_) return false;
+
+  regmatch_t match;
+  return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+  if (!re.is_valid_) return false;
+
+  regmatch_t match;
+  return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+  pattern_ = posix::StrDup(regex);
+
+  // Reserves enough bytes to hold the regular expression used for a
+  // full match.
+  const size_t full_regex_len = strlen(regex) + 10;
+  char* const full_pattern = new char[full_regex_len];
+
+  snprintf(full_pattern, full_regex_len, "^(%s)$", regex);
+  is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
+  // We want to call regcomp(&partial_regex_, ...) even if the
+  // previous expression returns false.  Otherwise partial_regex_ may
+  // not be properly initialized can may cause trouble when it's
+  // freed.
+  //
+  // Some implementation of POSIX regex (e.g. on at least some
+  // versions of Cygwin) doesn't accept the empty string as a valid
+  // regex.  We change it to an equivalent form "()" to be safe.
+  const char* const partial_regex = (*regex == '\0') ? "()" : regex;
+  is_valid_ = (regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0)
+      && is_valid_;
+  EXPECT_TRUE(is_valid_)
+      << "Regular expression \"" << regex
+      << "\" is not a valid POSIX Extended regular expression.";
+
+  delete[] full_pattern;
+}
+
+#elif GTEST_USES_SIMPLE_RE
+
+// Returns true iff ch appears anywhere in str (excluding the
+// terminating '\0' character).
+bool IsInSet(char ch, const char* str) {
+  return ch != '\0' && strchr(str, ch) != NULL;
+}
+
+// Returns true iff ch belongs to the given classification.  Unlike
+// similar functions in <ctype.h>, these aren't affected by the
+// current locale.
+bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; }
+bool IsPunct(char ch) {
+  return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
+}
+bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }
+bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
+bool IsWordChar(char ch) {
+  return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
+      ('0' <= ch && ch <= '9') || ch == '_';
+}
+
+// Returns true iff "\\c" is a supported escape sequence.
+bool IsValidEscape(char c) {
+  return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW"));
+}
+
+// Returns true iff the given atom (specified by escaped and pattern)
+// matches ch.  The result is undefined if the atom is invalid.
+bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
+  if (escaped) {  // "\\p" where p is pattern_char.
+    switch (pattern_char) {
+      case 'd': return IsDigit(ch);
+      case 'D': return !IsDigit(ch);
+      case 'f': return ch == '\f';
+      case 'n': return ch == '\n';
+      case 'r': return ch == '\r';
+      case 's': return IsWhiteSpace(ch);
+      case 'S': return !IsWhiteSpace(ch);
+      case 't': return ch == '\t';
+      case 'v': return ch == '\v';
+      case 'w': return IsWordChar(ch);
+      case 'W': return !IsWordChar(ch);
+    }
+    return IsPunct(pattern_char) && pattern_char == ch;
+  }
+
+  return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
+}
+
+// Helper function used by ValidateRegex() to format error messages.
+String FormatRegexSyntaxError(const char* regex, int index) {
+  return (Message() << "Syntax error at index " << index
+          << " in simple regular expression \"" << regex << "\": ").GetString();
+}
+
+// Generates non-fatal failures and returns false if regex is invalid;
+// otherwise returns true.
+bool ValidateRegex(const char* regex) {
+  if (regex == NULL) {
+    // TODO(wan@google.com): fix the source file location in the
+    // assertion failures to match where the regex is used in user
+    // code.
+    ADD_FAILURE() << "NULL is not a valid simple regular expression.";
+    return false;
+  }
+
+  bool is_valid = true;
+
+  // True iff ?, *, or + can follow the previous atom.
+  bool prev_repeatable = false;
+  for (int i = 0; regex[i]; i++) {
+    if (regex[i] == '\\') {  // An escape sequence
+      i++;
+      if (regex[i] == '\0') {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+                      << "'\\' cannot appear at the end.";
+        return false;
+      }
+
+      if (!IsValidEscape(regex[i])) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+                      << "invalid escape sequence \"\\" << regex[i] << "\".";
+        is_valid = false;
+      }
+      prev_repeatable = true;
+    } else {  // Not an escape sequence.
+      const char ch = regex[i];
+
+      if (ch == '^' && i > 0) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'^' can only appear at the beginning.";
+        is_valid = false;
+      } else if (ch == '$' && regex[i + 1] != '\0') {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'$' can only appear at the end.";
+        is_valid = false;
+      } else if (IsInSet(ch, "()[]{}|")) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'" << ch << "' is unsupported.";
+        is_valid = false;
+      } else if (IsRepeat(ch) && !prev_repeatable) {
+        ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+                      << "'" << ch << "' can only follow a repeatable token.";
+        is_valid = false;
+      }
+
+      prev_repeatable = !IsInSet(ch, "^$?*+");
+    }
+  }
+
+  return is_valid;
+}
+
+// Matches a repeated regex atom followed by a valid simple regular
+// expression.  The regex atom is defined as c if escaped is false,
+// or \c otherwise.  repeat is the repetition meta character (?, *,
+// or +).  The behavior is undefined if str contains too many
+// characters to be indexable by size_t, in which case the test will
+// probably time out anyway.  We are fine with this limitation as
+// std::string has it too.
+bool MatchRepetitionAndRegexAtHead(
+    bool escaped, char c, char repeat, const char* regex,
+    const char* str) {
+  const size_t min_count = (repeat == '+') ? 1 : 0;
+  const size_t max_count = (repeat == '?') ? 1 :
+      static_cast<size_t>(-1) - 1;
+  // We cannot call numeric_limits::max() as it conflicts with the
+  // max() macro on Windows.
+
+  for (size_t i = 0; i <= max_count; ++i) {
+    // We know that the atom matches each of the first i characters in str.
+    if (i >= min_count && MatchRegexAtHead(regex, str + i)) {
+      // We have enough matches at the head, and the tail matches too.
+      // Since we only care about *whether* the pattern matches str
+      // (as opposed to *how* it matches), there is no need to find a
+      // greedy match.
+      return true;
+    }
+    if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i]))
+      return false;
+  }
+  return false;
+}
+
+// Returns true iff regex matches a prefix of str.  regex must be a
+// valid simple regular expression and not start with "^", or the
+// result is undefined.
+bool MatchRegexAtHead(const char* regex, const char* str) {
+  if (*regex == '\0')  // An empty regex matches a prefix of anything.
+    return true;
+
+  // "$" only matches the end of a string.  Note that regex being
+  // valid guarantees that there's nothing after "$" in it.
+  if (*regex == '$')
+    return *str == '\0';
+
+  // Is the first thing in regex an escape sequence?
+  const bool escaped = *regex == '\\';
+  if (escaped)
+    ++regex;
+  if (IsRepeat(regex[1])) {
+    // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so
+    // here's an indirect recursion.  It terminates as the regex gets
+    // shorter in each recursion.
+    return MatchRepetitionAndRegexAtHead(
+        escaped, regex[0], regex[1], regex + 2, str);
+  } else {
+    // regex isn't empty, isn't "$", and doesn't start with a
+    // repetition.  We match the first atom of regex with the first
+    // character of str and recurse.
+    return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) &&
+        MatchRegexAtHead(regex + 1, str + 1);
+  }
+}
+
+// Returns true iff regex matches any substring of str.  regex must be
+// a valid simple regular expression, or the result is undefined.
+//
+// The algorithm is recursive, but the recursion depth doesn't exceed
+// the regex length, so we won't need to worry about running out of
+// stack space normally.  In rare cases the time complexity can be
+// exponential with respect to the regex length + the string length,
+// but usually it's must faster (often close to linear).
+bool MatchRegexAnywhere(const char* regex, const char* str) {
+  if (regex == NULL || str == NULL)
+    return false;
+
+  if (*regex == '^')
+    return MatchRegexAtHead(regex + 1, str);
+
+  // A successful match can be anywhere in str.
+  do {
+    if (MatchRegexAtHead(regex, str))
+      return true;
+  } while (*str++ != '\0');
+  return false;
+}
+
+// Implements the RE class.
+
+RE::~RE() {
+  free(const_cast<char*>(pattern_));
+  free(const_cast<char*>(full_pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+  return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+  return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+  pattern_ = full_pattern_ = NULL;
+  if (regex != NULL) {
+    pattern_ = posix::StrDup(regex);
+  }
+
+  is_valid_ = ValidateRegex(regex);
+  if (!is_valid_) {
+    // No need to calculate the full pattern when the regex is invalid.
+    return;
+  }
+
+  const size_t len = strlen(regex);
+  // Reserves enough bytes to hold the regular expression used for a
+  // full match: we need space to prepend a '^', append a '$', and
+  // terminate the string with '\0'.
+  char* buffer = static_cast<char*>(malloc(len + 3));
+  full_pattern_ = buffer;
+
+  if (*regex != '^')
+    *buffer++ = '^';  // Makes sure full_pattern_ starts with '^'.
+
+  // We don't use snprintf or strncpy, as they trigger a warning when
+  // compiled with VC++ 8.0.
+  memcpy(buffer, regex, len);
+  buffer += len;
+
+  if (len == 0 || regex[len - 1] != '$')
+    *buffer++ = '$';  // Makes sure full_pattern_ ends with '$'.
+
+  *buffer = '\0';
+}
+
+#endif  // GTEST_USES_POSIX_RE
+
+// Logs a message at the given severity level.
+void GTestLog(GTestLogSeverity severity, const char* file,
+              int line, const char* msg) {
+  const char* const marker =
+      severity == GTEST_INFO ?    "[  INFO ]" :
+      severity == GTEST_WARNING ? "[WARNING]" :
+      severity == GTEST_ERROR ?   "[ ERROR ]" : "[ FATAL ]";
+  fprintf(stderr, "\n%s %s:%d: %s\n", marker, file, line, msg);
+  if (severity == GTEST_FATAL) {
+    fflush(NULL);  // abort() is not guaranteed to flush open file streams.
+    abort();
+  }
+}
+
+#if GTEST_HAS_STD_STRING
+
+// Disable Microsoft deprecation warnings for POSIX functions called from
+// this class (creat, dup, dup2, and close)
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4996)
+#endif  // _MSC_VER
+
+// Defines the stderr capturer.
+
+class CapturedStderr {
+ public:
+  // The ctor redirects stderr to a temporary file.
+  CapturedStderr() {
+    uncaptured_fd_ = dup(kStdErrFileno);
+
+#if GTEST_OS_WINDOWS
+    char temp_dir_path[MAX_PATH + 1] = { '\0' };  // NOLINT
+    char temp_file_path[MAX_PATH + 1] = { '\0' };  // NOLINT
+
+    ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
+    ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, temp_file_path);
+    const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
+    filename_ = temp_file_path;
+#else
+    // There's no guarantee that a test has write access to the
+    // current directory, so we create the temporary file in the /tmp
+    // directory instead.
+    char name_template[] = "/tmp/captured_stderr.XXXXXX";
+    const int captured_fd = mkstemp(name_template);
+    filename_ = name_template;
+#endif  // GTEST_OS_WINDOWS
+    fflush(NULL);
+    dup2(captured_fd, kStdErrFileno);
+    close(captured_fd);
+  }
+
+  ~CapturedStderr() {
+    remove(filename_.c_str());
+  }
+
+  // Stops redirecting stderr.
+  void StopCapture() {
+    // Restores the original stream.
+    fflush(NULL);
+    dup2(uncaptured_fd_, kStdErrFileno);
+    close(uncaptured_fd_);
+    uncaptured_fd_ = -1;
+  }
+
+  // Returns the name of the temporary file holding the stderr output.
+  // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+  // can use it here.
+  ::std::string filename() const { return filename_; }
+
+ private:
+  int uncaptured_fd_;
+  ::std::string filename_;
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif  // _MSC_VER
+
+static CapturedStderr* g_captured_stderr = NULL;
+
+// Returns the size (in bytes) of a file.
+static size_t GetFileSize(FILE * file) {
+  fseek(file, 0, SEEK_END);
+  return static_cast<size_t>(ftell(file));
+}
+
+// Reads the entire content of a file as a string.
+static ::std::string ReadEntireFile(FILE * file) {
+  const size_t file_size = GetFileSize(file);
+  char* const buffer = new char[file_size];
+
+  size_t bytes_last_read = 0;  // # of bytes read in the last fread()
+  size_t bytes_read = 0;       // # of bytes read so far
+
+  fseek(file, 0, SEEK_SET);
+
+  // Keeps reading the file until we cannot read further or the
+  // pre-determined file size is reached.
+  do {
+    bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+    bytes_read += bytes_last_read;
+  } while (bytes_last_read > 0 && bytes_read < file_size);
+
+  const ::std::string content(buffer, buffer+bytes_read);
+  delete[] buffer;
+
+  return content;
+}
+
+// Starts capturing stderr.
+void CaptureStderr() {
+  if (g_captured_stderr != NULL) {
+    GTEST_LOG_(FATAL, "Only one stderr capturer can exist at one time.");
+  }
+  g_captured_stderr = new CapturedStderr;
+}
+
+// Stops capturing stderr and returns the captured string.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can
+// use it here.
+::std::string GetCapturedStderr() {
+  g_captured_stderr->StopCapture();
+
+  FILE* const file = posix::FOpen(g_captured_stderr->filename().c_str(), "r");
+  const ::std::string content = ReadEntireFile(file);
+  posix::FClose(file);
+
+  delete g_captured_stderr;
+  g_captured_stderr = NULL;
+
+  return content;
+}
+
+#endif  // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments.  Set by InitGoogleTest().
+::std::vector<String> g_argvs;
+
+// Returns the command line as a vector of strings.
+const ::std::vector<String>& GetArgvs() { return g_argvs; }
+
+#endif  // GTEST_HAS_DEATH_TEST
+
+#ifdef _WIN32_WCE
+namespace posix {
+void Abort() {
+  DebugBreak();
+  TerminateProcess(GetCurrentProcess(), 1);
+}
+}  // namespace posix
+#endif  // _WIN32_WCE
+
+// Returns the name of the environment variable corresponding to the
+// given flag.  For example, FlagToEnvVar("foo") will return
+// "GTEST_FOO" in the open-source version.
+static String FlagToEnvVar(const char* flag) {
+  const String full_flag =
+      (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
+
+  Message env_var;
+  for (int i = 0; i != full_flag.GetLength(); i++) {
+    env_var << static_cast<char>(toupper(full_flag.c_str()[i]));
+  }
+
+  return env_var.GetString();
+}
+
+// Parses 'str' for a 32-bit signed integer.  If successful, writes
+// the result to *value and returns true; otherwise leaves *value
+// unchanged and returns false.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
+  // Parses the environment variable as a decimal integer.
+  char* end = NULL;
+  const long long_value = strtol(str, &end, 10);  // NOLINT
+
+  // Has strtol() consumed all characters in the string?
+  if (*end != '\0') {
+    // No - an invalid character was encountered.
+    Message msg;
+    msg << "WARNING: " << src_text
+        << " is expected to be a 32-bit integer, but actually"
+        << " has value \"" << str << "\".\n";
+    printf("%s", msg.GetString().c_str());
+    fflush(stdout);
+    return false;
+  }
+
+  // Is the parsed value in the range of an Int32?
+  const Int32 result = static_cast<Int32>(long_value);
+  if (long_value == LONG_MAX || long_value == LONG_MIN ||
+      // The parsed value overflows as a long.  (strtol() returns
+      // LONG_MAX or LONG_MIN when the input overflows.)
+      result != long_value
+      // The parsed value overflows as an Int32.
+      ) {
+    Message msg;
+    msg << "WARNING: " << src_text
+        << " is expected to be a 32-bit integer, but actually"
+        << " has value " << str << ", which overflows.\n";
+    printf("%s", msg.GetString().c_str());
+    fflush(stdout);
+    return false;
+  }
+
+  *value = result;
+  return true;
+}
+
+// Reads and returns the Boolean environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+//
+// The value is considered true iff it's not "0".
+bool BoolFromGTestEnv(const char* flag, bool default_value) {
+  const String env_var = FlagToEnvVar(flag);
+  const char* const string_value = posix::GetEnv(env_var.c_str());
+  return string_value == NULL ?
+      default_value : strcmp(string_value, "0") != 0;
+}
+
+// Reads and returns a 32-bit integer stored in the environment
+// variable corresponding to the given flag; if it isn't set or
+// doesn't represent a valid 32-bit integer, returns default_value.
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
+  const String env_var = FlagToEnvVar(flag);
+  const char* const string_value = posix::GetEnv(env_var.c_str());
+  if (string_value == NULL) {
+    // The environment variable is not set.
+    return default_value;
+  }
+
+  Int32 result = default_value;
+  if (!ParseInt32(Message() << "Environment variable " << env_var,
+                  string_value, &result)) {
+    printf("The default value %s is used.\n",
+           (Message() << default_value).GetString().c_str());
+    fflush(stdout);
+    return default_value;
+  }
+
+  return result;
+}
+
+// Reads and returns the string environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+const char* StringFromGTestEnv(const char* flag, const char* default_value) {
+  const String env_var = FlagToEnvVar(flag);
+  const char* const value = posix::GetEnv(env_var.c_str());
+  return value == NULL ? default_value : value;
+}
+
+}  // namespace internal
+}  // namespace testing
diff --git a/third_party/gtest/src/gtest-test-part.cc b/third_party/gtest/src/gtest-test-part.cc
index 250a082..9aacd2b 100644
--- a/third_party/gtest/src/gtest-test-part.cc
+++ b/third_party/gtest/src/gtest-test-part.cc
@@ -1,124 +1,124 @@
-// Copyright 2008, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: mheule@google.com (Markus Heule)

-//

-// The Google C++ Testing Framework (Google Test)

-

-#include <gtest/gtest-test-part.h>

-

-// Indicates that this translation unit is part of Google Test's

-// implementation.  It must come before gtest-internal-inl.h is

-// included, or there will be a compiler error.  This trick is to

-// prevent a user from accidentally including gtest-internal-inl.h in

-// his code.

-#define GTEST_IMPLEMENTATION_ 1

-#include "src/gtest-internal-inl.h"

-#undef GTEST_IMPLEMENTATION_

-

-namespace testing {

-

-// Gets the summary of the failure message by omitting the stack trace

-// in it.

-internal::String TestPartResult::ExtractSummary(const char* message) {

-  const char* const stack_trace = strstr(message, internal::kStackTraceMarker);

-  return stack_trace == NULL ? internal::String(message) :

-      internal::String(message, stack_trace - message);

-}

-

-// Prints a TestPartResult object.

-std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {

-  return os << result.file_name() << ":"

-            << result.line_number() << ": "

-            << (result.type() == TPRT_SUCCESS ? "Success" :

-                result.type() == TPRT_FATAL_FAILURE ? "Fatal failure" :

-                "Non-fatal failure") << ":\n"

-            << result.message() << std::endl;

-}

-

-// Constructs an empty TestPartResultArray.

-TestPartResultArray::TestPartResultArray()

-    : list_(new internal::List<TestPartResult>) {

-}

-

-// Destructs a TestPartResultArray.

-TestPartResultArray::~TestPartResultArray() {

-  delete list_;

-}

-

-// Appends a TestPartResult to the array.

-void TestPartResultArray::Append(const TestPartResult& result) {

-  list_->PushBack(result);

-}

-

-// Returns the TestPartResult at the given index (0-based).

-const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {

-  if (index < 0 || index >= size()) {

-    printf("\nInvalid index (%d) into TestPartResultArray.\n", index);

-    internal::posix::Abort();

-  }

-

-  const internal::ListNode<TestPartResult>* p = list_->Head();

-  for (int i = 0; i < index; i++) {

-    p = p->next();

-  }

-

-  return p->element();

-}

-

-// Returns the number of TestPartResult objects in the array.

-int TestPartResultArray::size() const {

-  return list_->size();

-}

-

-namespace internal {

-

-HasNewFatalFailureHelper::HasNewFatalFailureHelper()

-    : has_new_fatal_failure_(false),

-      original_reporter_(UnitTest::GetInstance()->impl()->

-                         GetTestPartResultReporterForCurrentThread()) {

-  UnitTest::GetInstance()->impl()->SetTestPartResultReporterForCurrentThread(

-      this);

-}

-

-HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {

-  UnitTest::GetInstance()->impl()->SetTestPartResultReporterForCurrentThread(

-      original_reporter_);

-}

-

-void HasNewFatalFailureHelper::ReportTestPartResult(

-    const TestPartResult& result) {

-  if (result.fatally_failed())

-    has_new_fatal_failure_ = true;

-  original_reporter_->ReportTestPartResult(result);

-}

-

-}  // namespace internal

-

-}  // namespace testing

+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include <gtest/gtest-test-part.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+// Gets the summary of the failure message by omitting the stack trace
+// in it.
+internal::String TestPartResult::ExtractSummary(const char* message) {
+  const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
+  return stack_trace == NULL ? internal::String(message) :
+      internal::String(message, stack_trace - message);
+}
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
+  return os << result.file_name() << ":"
+            << result.line_number() << ": "
+            << (result.type() == TPRT_SUCCESS ? "Success" :
+                result.type() == TPRT_FATAL_FAILURE ? "Fatal failure" :
+                "Non-fatal failure") << ":\n"
+            << result.message() << std::endl;
+}
+
+// Constructs an empty TestPartResultArray.
+TestPartResultArray::TestPartResultArray()
+    : list_(new internal::List<TestPartResult>) {
+}
+
+// Destructs a TestPartResultArray.
+TestPartResultArray::~TestPartResultArray() {
+  delete list_;
+}
+
+// Appends a TestPartResult to the array.
+void TestPartResultArray::Append(const TestPartResult& result) {
+  list_->PushBack(result);
+}
+
+// Returns the TestPartResult at the given index (0-based).
+const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
+  if (index < 0 || index >= size()) {
+    printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
+    internal::posix::Abort();
+  }
+
+  const internal::ListNode<TestPartResult>* p = list_->Head();
+  for (int i = 0; i < index; i++) {
+    p = p->next();
+  }
+
+  return p->element();
+}
+
+// Returns the number of TestPartResult objects in the array.
+int TestPartResultArray::size() const {
+  return list_->size();
+}
+
+namespace internal {
+
+HasNewFatalFailureHelper::HasNewFatalFailureHelper()
+    : has_new_fatal_failure_(false),
+      original_reporter_(UnitTest::GetInstance()->impl()->
+                         GetTestPartResultReporterForCurrentThread()) {
+  UnitTest::GetInstance()->impl()->SetTestPartResultReporterForCurrentThread(
+      this);
+}
+
+HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {
+  UnitTest::GetInstance()->impl()->SetTestPartResultReporterForCurrentThread(
+      original_reporter_);
+}
+
+void HasNewFatalFailureHelper::ReportTestPartResult(
+    const TestPartResult& result) {
+  if (result.fatally_failed())
+    has_new_fatal_failure_ = true;
+  original_reporter_->ReportTestPartResult(result);
+}
+
+}  // namespace internal
+
+}  // namespace testing
diff --git a/third_party/gtest/src/gtest-typed-test.cc b/third_party/gtest/src/gtest-typed-test.cc
index dd3a596..e45e2ab 100644
--- a/third_party/gtest/src/gtest-typed-test.cc
+++ b/third_party/gtest/src/gtest-typed-test.cc
@@ -1,98 +1,98 @@
-// Copyright 2008 Google Inc.

-// All Rights Reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan)

-

-#include <gtest/gtest-typed-test.h>

-#include <gtest/gtest.h>

-

-namespace testing {

-namespace internal {

-

-#if GTEST_HAS_TYPED_TEST_P

-

-// Verifies that registered_tests match the test names in

-// defined_test_names_; returns registered_tests if successful, or

-// aborts the program otherwise.

-const char* TypedTestCasePState::VerifyRegisteredTestNames(

-    const char* file, int line, const char* registered_tests) {

-  typedef ::std::set<const char*>::const_iterator DefinedTestIter;

-  registered_ = true;

-

-  Message errors;

-  ::std::set<String> tests;

-  for (const char* names = registered_tests; names != NULL;

-       names = SkipComma(names)) {

-    const String name = GetPrefixUntilComma(names);

-    if (tests.count(name) != 0) {

-      errors << "Test " << name << " is listed more than once.\n";

-      continue;

-    }

-

-    bool found = false;

-    for (DefinedTestIter it = defined_test_names_.begin();

-         it != defined_test_names_.end();

-         ++it) {

-      if (name == *it) {

-        found = true;

-        break;

-      }

-    }

-

-    if (found) {

-      tests.insert(name);

-    } else {

-      errors << "No test named " << name

-             << " can be found in this test case.\n";

-    }

-  }

-

-  for (DefinedTestIter it = defined_test_names_.begin();

-       it != defined_test_names_.end();

-       ++it) {

-    if (tests.count(*it) == 0) {

-      errors << "You forgot to list test " << *it << ".\n";

-    }

-  }

-

-  const String& errors_str = errors.GetString();

-  if (errors_str != "") {

-    fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),

-            errors_str.c_str());

-    fflush(stderr);

-    abort();

-  }

-

-  return registered_tests;

-}

-

-#endif  // GTEST_HAS_TYPED_TEST_P

-

-}  // namespace internal

-}  // namespace testing

+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/gtest-typed-test.h>
+#include <gtest/gtest.h>
+
+namespace testing {
+namespace internal {
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// Verifies that registered_tests match the test names in
+// defined_test_names_; returns registered_tests if successful, or
+// aborts the program otherwise.
+const char* TypedTestCasePState::VerifyRegisteredTestNames(
+    const char* file, int line, const char* registered_tests) {
+  typedef ::std::set<const char*>::const_iterator DefinedTestIter;
+  registered_ = true;
+
+  Message errors;
+  ::std::set<String> tests;
+  for (const char* names = registered_tests; names != NULL;
+       names = SkipComma(names)) {
+    const String name = GetPrefixUntilComma(names);
+    if (tests.count(name) != 0) {
+      errors << "Test " << name << " is listed more than once.\n";
+      continue;
+    }
+
+    bool found = false;
+    for (DefinedTestIter it = defined_test_names_.begin();
+         it != defined_test_names_.end();
+         ++it) {
+      if (name == *it) {
+        found = true;
+        break;
+      }
+    }
+
+    if (found) {
+      tests.insert(name);
+    } else {
+      errors << "No test named " << name
+             << " can be found in this test case.\n";
+    }
+  }
+
+  for (DefinedTestIter it = defined_test_names_.begin();
+       it != defined_test_names_.end();
+       ++it) {
+    if (tests.count(*it) == 0) {
+      errors << "You forgot to list test " << *it << ".\n";
+    }
+  }
+
+  const String& errors_str = errors.GetString();
+  if (errors_str != "") {
+    fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+            errors_str.c_str());
+    fflush(stderr);
+    abort();
+  }
+
+  return registered_tests;
+}
+
+#endif  // GTEST_HAS_TYPED_TEST_P
+
+}  // namespace internal
+}  // namespace testing
diff --git a/third_party/gtest/src/gtest.cc b/third_party/gtest/src/gtest.cc
index c413314..c093bce 100644
--- a/third_party/gtest/src/gtest.cc
+++ b/third_party/gtest/src/gtest.cc
@@ -1,4322 +1,4322 @@
-// Copyright 2005, Google Inc.

-// All rights reserved.

-//

-// Redistribution and use in source and binary forms, with or without

-// modification, are permitted provided that the following conditions are

-// met:

-//

-//     * Redistributions of source code must retain the above copyright

-// notice, this list of conditions and the following disclaimer.

-//     * Redistributions in binary form must reproduce the above

-// copyright notice, this list of conditions and the following disclaimer

-// in the documentation and/or other materials provided with the

-// distribution.

-//     * Neither the name of Google Inc. nor the names of its

-// contributors may be used to endorse or promote products derived from

-// this software without specific prior written permission.

-//

-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS

-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT

-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR

-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT

-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,

-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT

-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,

-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY

-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT

-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-//

-// Author: wan@google.com (Zhanyong Wan)

-//

-// The Google C++ Testing Framework (Google Test)

-

-#include <gtest/gtest.h>

-#include <gtest/gtest-spi.h>

-

-#include <ctype.h>

-#include <math.h>

-#include <stdarg.h>

-#include <stdio.h>

-#include <stdlib.h>

-#include <wchar.h>

-#include <wctype.h>

-

-#if GTEST_OS_LINUX

-

-// TODO(kenton@google.com): Use autoconf to detect availability of

-// gettimeofday().

-#define GTEST_HAS_GETTIMEOFDAY_ 1

-

-#include <fcntl.h>

-#include <limits.h>

-#include <sched.h>

-// Declares vsnprintf().  This header is not available on Windows.

-#include <strings.h>

-#include <sys/mman.h>

-#include <sys/time.h>

-#include <unistd.h>

-#include <string>

-#include <vector>

-

-#elif GTEST_OS_SYMBIAN

-#define GTEST_HAS_GETTIMEOFDAY_ 1

-#include <sys/time.h>  // NOLINT

-

-#elif GTEST_OS_ZOS

-#define GTEST_HAS_GETTIMEOFDAY_ 1

-#include <sys/time.h>  // NOLINT

-

-// On z/OS we additionally need strings.h for strcasecmp.

-#include <strings.h>  // NOLINT

-

-#elif defined(_WIN32_WCE)  // We are on Windows CE.

-

-#include <windows.h>  // NOLINT

-

-#elif GTEST_OS_WINDOWS  // We are on Windows proper.

-

-#include <io.h>  // NOLINT

-#include <sys/timeb.h>  // NOLINT

-#include <sys/types.h>  // NOLINT

-#include <sys/stat.h>  // NOLINT

-

-#if defined(__MINGW__) || defined(__MINGW32__)

-// MinGW has gettimeofday() but not _ftime64().

-// TODO(kenton@google.com): Use autoconf to detect availability of

-//   gettimeofday().

-// TODO(kenton@google.com): There are other ways to get the time on

-//   Windows, like GetTickCount() or GetSystemTimeAsFileTime().  MinGW

-//   supports these.  consider using them instead.

-#define GTEST_HAS_GETTIMEOFDAY_ 1

-#include <sys/time.h>  // NOLINT

-#endif  // defined(__MINGW__) || defined(__MINGW32__)

-

-// cpplint thinks that the header is already included, so we want to

-// silence it.

-#include <windows.h>  // NOLINT

-

-#else

-

-// Assume other platforms have gettimeofday().

-// TODO(kenton@google.com): Use autoconf to detect availability of

-//   gettimeofday().

-#define GTEST_HAS_GETTIMEOFDAY_ 1

-

-// cpplint thinks that the header is already included, so we want to

-// silence it.

-#include <sys/time.h>  // NOLINT

-#include <unistd.h>  // NOLINT

-

-#endif  // GTEST_OS_LINUX

-

-#if GTEST_HAS_EXCEPTIONS

-#include <stdexcept>

-#endif

-

-// Indicates that this translation unit is part of Google Test's

-// implementation.  It must come before gtest-internal-inl.h is

-// included, or there will be a compiler error.  This trick is to

-// prevent a user from accidentally including gtest-internal-inl.h in

-// his code.

-#define GTEST_IMPLEMENTATION_ 1

-#include "src/gtest-internal-inl.h"

-#undef GTEST_IMPLEMENTATION_

-

-#if GTEST_OS_WINDOWS

-#define vsnprintf _vsnprintf

-#endif  // GTEST_OS_WINDOWS

-

-namespace testing {

-

-// Constants.

-

-// A test whose test case name or test name matches this filter is

-// disabled and not run.

-static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";

-

-// A test case whose name matches this filter is considered a death

-// test case and will be run before test cases whose name doesn't

-// match this filter.

-static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";

-

-// A test filter that matches everything.

-static const char kUniversalFilter[] = "*";

-

-// The default output file for XML output.

-static const char kDefaultOutputFile[] = "test_detail.xml";

-

-// The environment variable name for the test shard index.

-static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";

-// The environment variable name for the total number of test shards.

-static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";

-// The environment variable name for the test shard status file.

-static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE";

-

-namespace internal {

-

-// The text used in failure messages to indicate the start of the

-// stack trace.

-const char kStackTraceMarker[] = "\nStack trace:\n";

-

-}  // namespace internal

-

-GTEST_DEFINE_bool_(

-    also_run_disabled_tests,

-    internal::BoolFromGTestEnv("also_run_disabled_tests", false),

-    "Run disabled tests too, in addition to the tests normally being run.");

-

-GTEST_DEFINE_bool_(

-    break_on_failure,

-    internal::BoolFromGTestEnv("break_on_failure", false),

-    "True iff a failed assertion should be a debugger break-point.");

-

-GTEST_DEFINE_bool_(

-    catch_exceptions,

-    internal::BoolFromGTestEnv("catch_exceptions", false),

-    "True iff " GTEST_NAME_

-    " should catch exceptions and treat them as test failures.");

-

-GTEST_DEFINE_string_(

-    color,

-    internal::StringFromGTestEnv("color", "auto"),

-    "Whether to use colors in the output.  Valid values: yes, no, "

-    "and auto.  'auto' means to use colors if the output is "

-    "being sent to a terminal and the TERM environment variable "

-    "is set to xterm, xterm-color, xterm-256color or cygwin.");

-

-GTEST_DEFINE_string_(

-    filter,

-    internal::StringFromGTestEnv("filter", kUniversalFilter),

-    "A colon-separated list of glob (not regex) patterns "

-    "for filtering the tests to run, optionally followed by a "

-    "'-' and a : separated list of negative patterns (tests to "

-    "exclude).  A test is run if it matches one of the positive "

-    "patterns and does not match any of the negative patterns.");

-

-GTEST_DEFINE_bool_(list_tests, false,

-                   "List all tests without running them.");

-

-GTEST_DEFINE_string_(

-    output,

-    internal::StringFromGTestEnv("output", ""),

-    "A format (currently must be \"xml\"), optionally followed "

-    "by a colon and an output file name or directory. A directory "

-    "is indicated by a trailing pathname separator. "

-    "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "

-    "If a directory is specified, output files will be created "

-    "within that directory, with file-names based on the test "

-    "executable's name and, if necessary, made unique by adding "

-    "digits.");

-

-GTEST_DEFINE_bool_(

-    print_time,

-    internal::BoolFromGTestEnv("print_time", true),

-    "True iff " GTEST_NAME_

-    " should display elapsed time in text output.");

-

-GTEST_DEFINE_int32_(

-    repeat,

-    internal::Int32FromGTestEnv("repeat", 1),

-    "How many times to repeat each test.  Specify a negative number "

-    "for repeating forever.  Useful for shaking out flaky tests.");

-

-GTEST_DEFINE_int32_(

-    stack_trace_depth,

-        internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),

-    "The maximum number of stack frames to print when an "

-    "assertion fails.  The valid range is 0 through 100, inclusive.");

-

-GTEST_DEFINE_bool_(

-    show_internal_stack_frames, false,

-    "True iff " GTEST_NAME_ " should include internal stack frames when "

-    "printing test failure stack traces.");

-

-GTEST_DEFINE_bool_(

-    throw_on_failure,

-    internal::BoolFromGTestEnv("throw_on_failure", false),

-    "When this flag is specified, a failed assertion will throw an exception "

-    "if exceptions are enabled or exit the program with a non-zero code "

-    "otherwise.");

-

-namespace internal {

-

-// g_help_flag is true iff the --help flag or an equivalent form is

-// specified on the command line.

-static bool g_help_flag = false;

-

-// GTestIsInitialized() returns true iff the user has initialized

-// Google Test.  Useful for catching the user mistake of not initializing

-// Google Test before calling RUN_ALL_TESTS().

-//

-// A user must call testing::InitGoogleTest() to initialize Google

-// Test.  g_init_gtest_count is set to the number of times

-// InitGoogleTest() has been called.  We don't protect this variable

-// under a mutex as it is only accessed in the main thread.

-int g_init_gtest_count = 0;

-static bool GTestIsInitialized() { return g_init_gtest_count != 0; }

-

-// Iterates over a list of TestCases, keeping a running sum of the

-// results of calling a given int-returning method on each.

-// Returns the sum.

-static int SumOverTestCaseList(const internal::List<TestCase*>& case_list,

-                               int (TestCase::*method)() const) {

-  int sum = 0;

-  for (const internal::ListNode<TestCase*>* node = case_list.Head();

-       node != NULL;

-       node = node->next()) {

-    sum += (node->element()->*method)();

-  }

-  return sum;

-}

-

-// Returns true iff the test case passed.

-static bool TestCasePassed(const TestCase* test_case) {

-  return test_case->should_run() && test_case->Passed();

-}

-

-// Returns true iff the test case failed.

-static bool TestCaseFailed(const TestCase* test_case) {

-  return test_case->should_run() && test_case->Failed();

-}

-

-// Returns true iff test_case contains at least one test that should

-// run.

-static bool ShouldRunTestCase(const TestCase* test_case) {

-  return test_case->should_run();

-}

-

-// AssertHelper constructor.

-AssertHelper::AssertHelper(TestPartResultType type, const char* file,

-                           int line, const char* message)

-    : type_(type), file_(file), line_(line), message_(message) {

-}

-

-// Message assignment, for assertion streaming support.

-void AssertHelper::operator=(const Message& message) const {

-  UnitTest::GetInstance()->

-    AddTestPartResult(type_, file_, line_,

-                      AppendUserMessage(message_, message),

-                      UnitTest::GetInstance()->impl()

-                      ->CurrentOsStackTraceExceptTop(1)

-                      // Skips the stack frame for this function itself.

-                      );  // NOLINT

-}

-

-// Mutex for linked pointers.

-Mutex g_linked_ptr_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX);

-

-// Application pathname gotten in InitGoogleTest.

-String g_executable_path;

-

-// Returns the current application's name, removing directory path if that

-// is present.

-FilePath GetCurrentExecutableName() {

-  FilePath result;

-

-#if defined(_WIN32_WCE) || GTEST_OS_WINDOWS

-  result.Set(FilePath(g_executable_path).RemoveExtension("exe"));

-#else

-  result.Set(FilePath(g_executable_path));

-#endif  // _WIN32_WCE || GTEST_OS_WINDOWS

-

-  return result.RemoveDirectoryName();

-}

-

-// Functions for processing the gtest_output flag.

-

-// Returns the output format, or "" for normal printed output.

-String UnitTestOptions::GetOutputFormat() {

-  const char* const gtest_output_flag = GTEST_FLAG(output).c_str();

-  if (gtest_output_flag == NULL) return String("");

-

-  const char* const colon = strchr(gtest_output_flag, ':');

-  return (colon == NULL) ?

-      String(gtest_output_flag) :

-      String(gtest_output_flag, colon - gtest_output_flag);

-}

-

-// Returns the name of the requested output file, or the default if none

-// was explicitly specified.

-String UnitTestOptions::GetAbsolutePathToOutputFile() {

-  const char* const gtest_output_flag = GTEST_FLAG(output).c_str();

-  if (gtest_output_flag == NULL)

-    return String("");

-

-  const char* const colon = strchr(gtest_output_flag, ':');

-  if (colon == NULL)

-    return String(internal::FilePath::ConcatPaths(

-               internal::FilePath(

-                   UnitTest::GetInstance()->original_working_dir()),

-               internal::FilePath(kDefaultOutputFile)).ToString() );

-

-  internal::FilePath output_name(colon + 1);

-  if (!output_name.IsAbsolutePath())

-    // TODO(wan@google.com): on Windows \some\path is not an absolute

-    // path (as its meaning depends on the current drive), yet the

-    // following logic for turning it into an absolute path is wrong.

-    // Fix it.

-    output_name = internal::FilePath::ConcatPaths(

-        internal::FilePath(UnitTest::GetInstance()->original_working_dir()),

-        internal::FilePath(colon + 1));

-

-  if (!output_name.IsDirectory())

-    return output_name.ToString();

-

-  internal::FilePath result(internal::FilePath::GenerateUniqueFileName(

-      output_name, internal::GetCurrentExecutableName(),

-      GetOutputFormat().c_str()));

-  return result.ToString();

-}

-

-// Returns true iff the wildcard pattern matches the string.  The

-// first ':' or '\0' character in pattern marks the end of it.

-//

-// This recursive algorithm isn't very efficient, but is clear and

-// works well enough for matching test names, which are short.

-bool UnitTestOptions::PatternMatchesString(const char *pattern,

-                                           const char *str) {

-  switch (*pattern) {

-    case '\0':

-    case ':':  // Either ':' or '\0' marks the end of the pattern.

-      return *str == '\0';

-    case '?':  // Matches any single character.

-      return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);

-    case '*':  // Matches any string (possibly empty) of characters.

-      return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||

-          PatternMatchesString(pattern + 1, str);

-    default:  // Non-special character.  Matches itself.

-      return *pattern == *str &&

-          PatternMatchesString(pattern + 1, str + 1);

-  }

-}

-

-bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) {

-  const char *cur_pattern = filter;

-  for (;;) {

-    if (PatternMatchesString(cur_pattern, name.c_str())) {

-      return true;

-    }

-

-    // Finds the next pattern in the filter.

-    cur_pattern = strchr(cur_pattern, ':');

-

-    // Returns if no more pattern can be found.

-    if (cur_pattern == NULL) {

-      return false;

-    }

-

-    // Skips the pattern separater (the ':' character).

-    cur_pattern++;

-  }

-}

-

-// TODO(keithray): move String function implementations to gtest-string.cc.

-

-// Returns true iff the user-specified filter matches the test case

-// name and the test name.

-bool UnitTestOptions::FilterMatchesTest(const String &test_case_name,

-                                        const String &test_name) {

-  const String& full_name = String::Format("%s.%s",

-                                           test_case_name.c_str(),

-                                           test_name.c_str());

-

-  // Split --gtest_filter at '-', if there is one, to separate into

-  // positive filter and negative filter portions

-  const char* const p = GTEST_FLAG(filter).c_str();

-  const char* const dash = strchr(p, '-');

-  String positive;

-  String negative;

-  if (dash == NULL) {

-    positive = GTEST_FLAG(filter).c_str();  // Whole string is a positive filter

-    negative = String("");

-  } else {

-    positive.Set(p, dash - p);       // Everything up to the dash

-    negative = String(dash+1);       // Everything after the dash

-    if (positive.empty()) {

-      // Treat '-test1' as the same as '*-test1'

-      positive = kUniversalFilter;

-    }

-  }

-

-  // A filter is a colon-separated list of patterns.  It matches a

-  // test if any pattern in it matches the test.

-  return (MatchesFilter(full_name, positive.c_str()) &&

-          !MatchesFilter(full_name, negative.c_str()));

-}

-

-#if GTEST_OS_WINDOWS

-// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the

-// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.

-// This function is useful as an __except condition.

-int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {

-  // Google Test should handle an exception if:

-  //   1. the user wants it to, AND

-  //   2. this is not a breakpoint exception.

-  return (GTEST_FLAG(catch_exceptions) &&

-          exception_code != EXCEPTION_BREAKPOINT) ?

-      EXCEPTION_EXECUTE_HANDLER :

-      EXCEPTION_CONTINUE_SEARCH;

-}

-#endif  // GTEST_OS_WINDOWS

-

-}  // namespace internal

-

-// The interface for printing the result of a UnitTest

-class UnitTestEventListenerInterface {

- public:

-  // The d'tor is pure virtual as this is an abstract class.

-  virtual ~UnitTestEventListenerInterface() = 0;

-

-  // Called before the unit test starts.

-  virtual void OnUnitTestStart(const UnitTest*) {}

-

-  // Called after the unit test ends.

-  virtual void OnUnitTestEnd(const UnitTest*) {}

-

-  // Called before the test case starts.

-  virtual void OnTestCaseStart(const TestCase*) {}

-

-  // Called after the test case ends.

-  virtual void OnTestCaseEnd(const TestCase*) {}

-

-  // Called before the global set-up starts.

-  virtual void OnGlobalSetUpStart(const UnitTest*) {}

-

-  // Called after the global set-up ends.

-  virtual void OnGlobalSetUpEnd(const UnitTest*) {}

-

-  // Called before the global tear-down starts.

-  virtual void OnGlobalTearDownStart(const UnitTest*) {}

-

-  // Called after the global tear-down ends.

-  virtual void OnGlobalTearDownEnd(const UnitTest*) {}

-

-  // Called before the test starts.

-  virtual void OnTestStart(const TestInfo*) {}

-

-  // Called after the test ends.

-  virtual void OnTestEnd(const TestInfo*) {}

-

-  // Called after an assertion.

-  virtual void OnNewTestPartResult(const TestPartResult*) {}

-};

-

-// The c'tor sets this object as the test part result reporter used by

-// Google Test.  The 'result' parameter specifies where to report the

-// results. Intercepts only failures from the current thread.

-ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(

-    TestPartResultArray* result)

-    : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),

-      result_(result) {

-  Init();

-}

-

-// The c'tor sets this object as the test part result reporter used by

-// Google Test.  The 'result' parameter specifies where to report the

-// results.

-ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(

-    InterceptMode intercept_mode, TestPartResultArray* result)

-    : intercept_mode_(intercept_mode),

-      result_(result) {

-  Init();

-}

-

-void ScopedFakeTestPartResultReporter::Init() {

-  internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl();

-  if (intercept_mode_ == INTERCEPT_ALL_THREADS) {

-    old_reporter_ = impl->GetGlobalTestPartResultReporter();

-    impl->SetGlobalTestPartResultReporter(this);

-  } else {

-    old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();

-    impl->SetTestPartResultReporterForCurrentThread(this);

-  }

-}

-

-// The d'tor restores the test part result reporter used by Google Test

-// before.

-ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {

-  internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl();

-  if (intercept_mode_ == INTERCEPT_ALL_THREADS) {

-    impl->SetGlobalTestPartResultReporter(old_reporter_);

-  } else {

-    impl->SetTestPartResultReporterForCurrentThread(old_reporter_);

-  }

-}

-

-// Increments the test part result count and remembers the result.

-// This method is from the TestPartResultReporterInterface interface.

-void ScopedFakeTestPartResultReporter::ReportTestPartResult(

-    const TestPartResult& result) {

-  result_->Append(result);

-}

-

-namespace internal {

-

-// Returns the type ID of ::testing::Test.  We should always call this

-// instead of GetTypeId< ::testing::Test>() to get the type ID of

-// testing::Test.  This is to work around a suspected linker bug when

-// using Google Test as a framework on Mac OS X.  The bug causes

-// GetTypeId< ::testing::Test>() to return different values depending

-// on whether the call is from the Google Test framework itself or

-// from user test code.  GetTestTypeId() is guaranteed to always

-// return the same value, as it always calls GetTypeId<>() from the

-// gtest.cc, which is within the Google Test framework.

-TypeId GetTestTypeId() {

-  return GetTypeId<Test>();

-}

-

-// The value of GetTestTypeId() as seen from within the Google Test

-// library.  This is solely for testing GetTestTypeId().

-extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();

-

-// This predicate-formatter checks that 'results' contains a test part

-// failure of the given type and that the failure message contains the

-// given substring.

-AssertionResult HasOneFailure(const char* /* results_expr */,

-                              const char* /* type_expr */,

-                              const char* /* substr_expr */,

-                              const TestPartResultArray& results,

-                              TestPartResultType type,

-                              const char* substr) {

-  const String expected(

-      type == TPRT_FATAL_FAILURE ? "1 fatal failure" :

-      "1 non-fatal failure");

-  Message msg;

-  if (results.size() != 1) {

-    msg << "Expected: " << expected << "\n"

-        << "  Actual: " << results.size() << " failures";

-    for (int i = 0; i < results.size(); i++) {

-      msg << "\n" << results.GetTestPartResult(i);

-    }

-    return AssertionFailure(msg);

-  }

-

-  const TestPartResult& r = results.GetTestPartResult(0);

-  if (r.type() != type) {

-    msg << "Expected: " << expected << "\n"

-        << "  Actual:\n"

-        << r;

-    return AssertionFailure(msg);

-  }

-

-  if (strstr(r.message(), substr) == NULL) {

-    msg << "Expected: " << expected << " containing \""

-        << substr << "\"\n"

-        << "  Actual:\n"

-        << r;

-    return AssertionFailure(msg);

-  }

-

-  return AssertionSuccess();

-}

-

-// The constructor of SingleFailureChecker remembers where to look up

-// test part results, what type of failure we expect, and what

-// substring the failure message should contain.

-SingleFailureChecker:: SingleFailureChecker(

-    const TestPartResultArray* results,

-    TestPartResultType type,

-    const char* substr)

-    : results_(results),

-      type_(type),

-      substr_(substr) {}

-

-// The destructor of SingleFailureChecker verifies that the given

-// TestPartResultArray contains exactly one failure that has the given

-// type and contains the given substring.  If that's not the case, a

-// non-fatal failure will be generated.

-SingleFailureChecker::~SingleFailureChecker() {

-  EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str());

-}

-

-DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(

-    UnitTestImpl* unit_test) : unit_test_(unit_test) {}

-

-void DefaultGlobalTestPartResultReporter::ReportTestPartResult(

-    const TestPartResult& result) {

-  unit_test_->current_test_result()->AddTestPartResult(result);

-  unit_test_->result_printer()->OnNewTestPartResult(&result);

-}

-

-DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(

-    UnitTestImpl* unit_test) : unit_test_(unit_test) {}

-

-void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(

-    const TestPartResult& result) {

-  unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);

-}

-

-// Returns the global test part result reporter.

-TestPartResultReporterInterface*

-UnitTestImpl::GetGlobalTestPartResultReporter() {

-  internal::MutexLock lock(&global_test_part_result_reporter_mutex_);

-  return global_test_part_result_repoter_;

-}

-

-// Sets the global test part result reporter.

-void UnitTestImpl::SetGlobalTestPartResultReporter(

-    TestPartResultReporterInterface* reporter) {

-  internal::MutexLock lock(&global_test_part_result_reporter_mutex_);

-  global_test_part_result_repoter_ = reporter;

-}

-

-// Returns the test part result reporter for the current thread.

-TestPartResultReporterInterface*

-UnitTestImpl::GetTestPartResultReporterForCurrentThread() {

-  return per_thread_test_part_result_reporter_.get();

-}

-

-// Sets the test part result reporter for the current thread.

-void UnitTestImpl::SetTestPartResultReporterForCurrentThread(

-    TestPartResultReporterInterface* reporter) {

-  per_thread_test_part_result_reporter_.set(reporter);

-}

-

-// Gets the number of successful test cases.

-int UnitTestImpl::successful_test_case_count() const {

-  return test_cases_.CountIf(TestCasePassed);

-}

-

-// Gets the number of failed test cases.

-int UnitTestImpl::failed_test_case_count() const {

-  return test_cases_.CountIf(TestCaseFailed);

-}

-

-// Gets the number of all test cases.

-int UnitTestImpl::total_test_case_count() const {

-  return test_cases_.size();

-}

-

-// Gets the number of all test cases that contain at least one test

-// that should run.

-int UnitTestImpl::test_case_to_run_count() const {

-  return test_cases_.CountIf(ShouldRunTestCase);

-}

-

-// Gets the number of successful tests.

-int UnitTestImpl::successful_test_count() const {

-  return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);

-}

-

-// Gets the number of failed tests.

-int UnitTestImpl::failed_test_count() const {

-  return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);

-}

-

-// Gets the number of disabled tests.

-int UnitTestImpl::disabled_test_count() const {

-  return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);

-}

-

-// Gets the number of all tests.

-int UnitTestImpl::total_test_count() const {

-  return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);

-}

-

-// Gets the number of tests that should run.

-int UnitTestImpl::test_to_run_count() const {

-  return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);

-}

-

-// Returns the current OS stack trace as a String.

-//

-// The maximum number of stack frames to be included is specified by

-// the gtest_stack_trace_depth flag.  The skip_count parameter

-// specifies the number of top frames to be skipped, which doesn't

-// count against the number of frames to be included.

-//

-// For example, if Foo() calls Bar(), which in turn calls

-// CurrentOsStackTraceExceptTop(1), Foo() will be included in the

-// trace but Bar() and CurrentOsStackTraceExceptTop() won't.

-String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {

-  (void)skip_count;

-  return String("");

-}

-

-static TimeInMillis GetTimeInMillis() {

-#if defined(_WIN32_WCE) || defined(__BORLANDC__)

-  // Difference between 1970-01-01 and 1601-01-01 in miliseconds.

-  // http://analogous.blogspot.com/2005/04/epoch.html

-  const TimeInMillis kJavaEpochToWinFileTimeDelta =

-    static_cast<TimeInMillis>(116444736UL) * 100000UL;

-  const DWORD kTenthMicrosInMilliSecond = 10000;

-

-  SYSTEMTIME now_systime;

-  FILETIME now_filetime;

-  ULARGE_INTEGER now_int64;

-  // TODO(kenton@google.com): Shouldn't this just use

-  //   GetSystemTimeAsFileTime()?

-  GetSystemTime(&now_systime);

-  if (SystemTimeToFileTime(&now_systime, &now_filetime)) {

-    now_int64.LowPart = now_filetime.dwLowDateTime;

-    now_int64.HighPart = now_filetime.dwHighDateTime;

-    now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -

-      kJavaEpochToWinFileTimeDelta;

-    return now_int64.QuadPart;

-  }

-  return 0;

-#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_

-  __timeb64 now;

-#ifdef _MSC_VER

-  // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996

-  // (deprecated function) there.

-  // TODO(kenton@google.com): Use GetTickCount()?  Or use

-  //   SystemTimeToFileTime()

-#pragma warning(push)          // Saves the current warning state.

-#pragma warning(disable:4996)  // Temporarily disables warning 4996.

-  _ftime64(&now);

-#pragma warning(pop)           // Restores the warning state.

-#else

-  _ftime64(&now);

-#endif  // _MSC_VER

-  return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;

-#elif GTEST_HAS_GETTIMEOFDAY_

-  struct timeval now;

-  gettimeofday(&now, NULL);

-  return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;

-#else

-#error "Don't know how to get the current time on your system."

-#endif

-}

-

-// Utilities

-

-// class String

-

-// Returns the input enclosed in double quotes if it's not NULL;

-// otherwise returns "(null)".  For example, "\"Hello\"" is returned

-// for input "Hello".

-//

-// This is useful for printing a C string in the syntax of a literal.

-//

-// Known issue: escape sequences are not handled yet.

-String String::ShowCStringQuoted(const char* c_str) {

-  return c_str ? String::Format("\"%s\"", c_str) : String("(null)");

-}

-

-// Copies at most length characters from str into a newly-allocated

-// piece of memory of size length+1.  The memory is allocated with new[].

-// A terminating null byte is written to the memory, and a pointer to it

-// is returned.  If str is NULL, NULL is returned.

-static char* CloneString(const char* str, size_t length) {

-  if (str == NULL) {

-    return NULL;

-  } else {

-    char* const clone = new char[length + 1];

-    posix::StrNCpy(clone, str, length);

-    clone[length] = '\0';

-    return clone;

-  }

-}

-

-// Clones a 0-terminated C string, allocating memory using new.  The

-// caller is responsible for deleting[] the return value.  Returns the

-// cloned string, or NULL if the input is NULL.

-const char * String::CloneCString(const char* c_str) {

-  return (c_str == NULL) ?

-                    NULL : CloneString(c_str, strlen(c_str));

-}

-

-#ifdef _WIN32_WCE

-// Creates a UTF-16 wide string from the given ANSI string, allocating

-// memory using new. The caller is responsible for deleting the return

-// value using delete[]. Returns the wide string, or NULL if the

-// input is NULL.

-LPCWSTR String::AnsiToUtf16(const char* ansi) {

-  if (!ansi) return NULL;

-  const int length = strlen(ansi);

-  const int unicode_length =

-      MultiByteToWideChar(CP_ACP, 0, ansi, length,

-                          NULL, 0);

-  WCHAR* unicode = new WCHAR[unicode_length + 1];

-  MultiByteToWideChar(CP_ACP, 0, ansi, length,

-                      unicode, unicode_length);

-  unicode[unicode_length] = 0;

-  return unicode;

-}

-

-// Creates an ANSI string from the given wide string, allocating

-// memory using new. The caller is responsible for deleting the return

-// value using delete[]. Returns the ANSI string, or NULL if the

-// input is NULL.

-const char* String::Utf16ToAnsi(LPCWSTR utf16_str)  {

-  if (!utf16_str) return NULL;

-  const int ansi_length =

-      WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,

-                          NULL, 0, NULL, NULL);

-  char* ansi = new char[ansi_length + 1];

-  WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,

-                      ansi, ansi_length, NULL, NULL);

-  ansi[ansi_length] = 0;

-  return ansi;

-}

-

-#endif  // _WIN32_WCE

-

-// Compares two C strings.  Returns true iff they have the same content.

-//

-// Unlike strcmp(), this function can handle NULL argument(s).  A NULL

-// C string is considered different to any non-NULL C string,

-// including the empty string.

-bool String::CStringEquals(const char * lhs, const char * rhs) {

-  if ( lhs == NULL ) return rhs == NULL;

-

-  if ( rhs == NULL ) return false;

-

-  return strcmp(lhs, rhs) == 0;

-}

-

-#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING

-

-// Converts an array of wide chars to a narrow string using the UTF-8

-// encoding, and streams the result to the given Message object.

-static void StreamWideCharsToMessage(const wchar_t* wstr, size_t len,

-                                     Message* msg) {

-  // TODO(wan): consider allowing a testing::String object to

-  // contain '\0'.  This will make it behave more like std::string,

-  // and will allow ToUtf8String() to return the correct encoding

-  // for '\0' s.t. we can get rid of the conditional here (and in

-  // several other places).

-  for (size_t i = 0; i != len; ) {  // NOLINT

-    if (wstr[i] != L'\0') {

-      *msg << WideStringToUtf8(wstr + i, static_cast<int>(len - i));

-      while (i != len && wstr[i] != L'\0')

-        i++;

-    } else {

-      *msg << '\0';

-      i++;

-    }

-  }

-}

-

-#endif  // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING

-

-}  // namespace internal

-

-#if GTEST_HAS_STD_WSTRING

-// Converts the given wide string to a narrow string using the UTF-8

-// encoding, and streams the result to this Message object.

-Message& Message::operator <<(const ::std::wstring& wstr) {

-  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);

-  return *this;

-}

-#endif  // GTEST_HAS_STD_WSTRING

-

-#if GTEST_HAS_GLOBAL_WSTRING

-// Converts the given wide string to a narrow string using the UTF-8

-// encoding, and streams the result to this Message object.

-Message& Message::operator <<(const ::wstring& wstr) {

-  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);

-  return *this;

-}

-#endif  // GTEST_HAS_GLOBAL_WSTRING

-

-namespace internal {

-

-// Formats a value to be used in a failure message.

-

-// For a char value, we print it as a C++ char literal and as an

-// unsigned integer (both in decimal and in hexadecimal).

-String FormatForFailureMessage(char ch) {

-  const unsigned int ch_as_uint = ch;

-  // A String object cannot contain '\0', so we print "\\0" when ch is

-  // '\0'.

-  return String::Format("'%s' (%u, 0x%X)",

-                        ch ? String::Format("%c", ch).c_str() : "\\0",

-                        ch_as_uint, ch_as_uint);

-}

-

-// For a wchar_t value, we print it as a C++ wchar_t literal and as an

-// unsigned integer (both in decimal and in hexidecimal).

-String FormatForFailureMessage(wchar_t wchar) {

-  // The C++ standard doesn't specify the exact size of the wchar_t

-  // type.  It just says that it shall have the same size as another

-  // integral type, called its underlying type.

-  //

-  // Therefore, in order to print a wchar_t value in the numeric form,

-  // we first convert it to the largest integral type (UInt64) and

-  // then print the converted value.

-  //

-  // We use streaming to print the value as "%llu" doesn't work

-  // correctly with MSVC 7.1.

-  const UInt64 wchar_as_uint64 = wchar;

-  Message msg;

-  // A String object cannot contain '\0', so we print "\\0" when wchar is

-  // L'\0'.

-  char buffer[32];  // CodePointToUtf8 requires a buffer that big.

-  msg << "L'"

-      << (wchar ? CodePointToUtf8(static_cast<UInt32>(wchar), buffer) : "\\0")

-      << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16)

-      << wchar_as_uint64 << ")";

-  return msg.GetString();

-}

-

-}  // namespace internal

-

-// AssertionResult constructor.

-AssertionResult::AssertionResult(const internal::String& failure_message)

-    : failure_message_(failure_message) {

-}

-

-

-// Makes a successful assertion result.

-AssertionResult AssertionSuccess() {

-  return AssertionResult();

-}

-

-

-// Makes a failed assertion result with the given failure message.

-AssertionResult AssertionFailure(const Message& message) {

-  return AssertionResult(message.GetString());

-}

-

-namespace internal {

-

-// Constructs and returns the message for an equality assertion

-// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.

-//

-// The first four parameters are the expressions used in the assertion

-// and their values, as strings.  For example, for ASSERT_EQ(foo, bar)

-// where foo is 5 and bar is 6, we have:

-//

-//   expected_expression: "foo"

-//   actual_expression:   "bar"

-//   expected_value:      "5"

-//   actual_value:        "6"

-//

-// The ignoring_case parameter is true iff the assertion is a

-// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will

-// be inserted into the message.

-AssertionResult EqFailure(const char* expected_expression,

-                          const char* actual_expression,

-                          const String& expected_value,

-                          const String& actual_value,

-                          bool ignoring_case) {

-  Message msg;

-  msg << "Value of: " << actual_expression;

-  if (actual_value != actual_expression) {

-    msg << "\n  Actual: " << actual_value;

-  }

-

-  msg << "\nExpected: " << expected_expression;

-  if (ignoring_case) {

-    msg << " (ignoring case)";

-  }

-  if (expected_value != expected_expression) {

-    msg << "\nWhich is: " << expected_value;

-  }

-

-  return AssertionFailure(msg);

-}

-

-

-// Helper function for implementing ASSERT_NEAR.

-AssertionResult DoubleNearPredFormat(const char* expr1,

-                                     const char* expr2,

-                                     const char* abs_error_expr,

-                                     double val1,

-                                     double val2,

-                                     double abs_error) {

-  const double diff = fabs(val1 - val2);

-  if (diff <= abs_error) return AssertionSuccess();

-

-  // TODO(wan): do not print the value of an expression if it's

-  // already a literal.

-  Message msg;

-  msg << "The difference between " << expr1 << " and " << expr2

-      << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"

-      << expr1 << " evaluates to " << val1 << ",\n"

-      << expr2 << " evaluates to " << val2 << ", and\n"

-      << abs_error_expr << " evaluates to " << abs_error << ".";

-  return AssertionFailure(msg);

-}

-

-

-// Helper template for implementing FloatLE() and DoubleLE().

-template <typename RawType>

-AssertionResult FloatingPointLE(const char* expr1,

-                                const char* expr2,

-                                RawType val1,

-                                RawType val2) {

-  // Returns success if val1 is less than val2,

-  if (val1 < val2) {

-    return AssertionSuccess();

-  }

-

-  // or if val1 is almost equal to val2.

-  const FloatingPoint<RawType> lhs(val1), rhs(val2);

-  if (lhs.AlmostEquals(rhs)) {

-    return AssertionSuccess();

-  }

-

-  // Note that the above two checks will both fail if either val1 or

-  // val2 is NaN, as the IEEE floating-point standard requires that

-  // any predicate involving a NaN must return false.

-

-  StrStream val1_ss;

-  val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)

-          << val1;

-

-  StrStream val2_ss;

-  val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)

-          << val2;

-

-  Message msg;

-  msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"

-      << "  Actual: " << StrStreamToString(&val1_ss) << " vs "

-      << StrStreamToString(&val2_ss);

-

-  return AssertionFailure(msg);

-}

-

-}  // namespace internal

-

-// Asserts that val1 is less than, or almost equal to, val2.  Fails

-// otherwise.  In particular, it fails if either val1 or val2 is NaN.

-AssertionResult FloatLE(const char* expr1, const char* expr2,

-                        float val1, float val2) {

-  return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);

-}

-

-// Asserts that val1 is less than, or almost equal to, val2.  Fails

-// otherwise.  In particular, it fails if either val1 or val2 is NaN.

-AssertionResult DoubleLE(const char* expr1, const char* expr2,

-                         double val1, double val2) {

-  return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);

-}

-

-namespace internal {

-

-// The helper function for {ASSERT|EXPECT}_EQ with int or enum

-// arguments.

-AssertionResult CmpHelperEQ(const char* expected_expression,

-                            const char* actual_expression,

-                            BiggestInt expected,

-                            BiggestInt actual) {

-  if (expected == actual) {

-    return AssertionSuccess();

-  }

-

-  return EqFailure(expected_expression,

-                   actual_expression,

-                   FormatForComparisonFailureMessage(expected, actual),

-                   FormatForComparisonFailureMessage(actual, expected),

-                   false);

-}

-

-// A macro for implementing the helper functions needed to implement

-// ASSERT_?? and EXPECT_?? with integer or enum arguments.  It is here

-// just to avoid copy-and-paste of similar code.

-#define GTEST_IMPL_CMP_HELPER_(op_name, op)\

-AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \

-                                   BiggestInt val1, BiggestInt val2) {\

-  if (val1 op val2) {\

-    return AssertionSuccess();\

-  } else {\

-    Message msg;\

-    msg << "Expected: (" << expr1 << ") " #op " (" << expr2\

-        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\

-        << " vs " << FormatForComparisonFailureMessage(val2, val1);\

-    return AssertionFailure(msg);\

-  }\

-}

-

-// Implements the helper function for {ASSERT|EXPECT}_NE with int or

-// enum arguments.

-GTEST_IMPL_CMP_HELPER_(NE, !=)

-// Implements the helper function for {ASSERT|EXPECT}_LE with int or

-// enum arguments.

-GTEST_IMPL_CMP_HELPER_(LE, <=)

-// Implements the helper function for {ASSERT|EXPECT}_LT with int or

-// enum arguments.

-GTEST_IMPL_CMP_HELPER_(LT, < )

-// Implements the helper function for {ASSERT|EXPECT}_GE with int or

-// enum arguments.

-GTEST_IMPL_CMP_HELPER_(GE, >=)

-// Implements the helper function for {ASSERT|EXPECT}_GT with int or

-// enum arguments.

-GTEST_IMPL_CMP_HELPER_(GT, > )

-

-#undef GTEST_IMPL_CMP_HELPER_

-

-// The helper function for {ASSERT|EXPECT}_STREQ.

-AssertionResult CmpHelperSTREQ(const char* expected_expression,

-                               const char* actual_expression,

-                               const char* expected,

-                               const char* actual) {

-  if (String::CStringEquals(expected, actual)) {

-    return AssertionSuccess();

-  }

-

-  return EqFailure(expected_expression,

-                   actual_expression,

-                   String::ShowCStringQuoted(expected),

-                   String::ShowCStringQuoted(actual),

-                   false);

-}

-

-// The helper function for {ASSERT|EXPECT}_STRCASEEQ.

-AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,

-                                   const char* actual_expression,

-                                   const char* expected,

-                                   const char* actual) {

-  if (String::CaseInsensitiveCStringEquals(expected, actual)) {

-    return AssertionSuccess();

-  }

-

-  return EqFailure(expected_expression,

-                   actual_expression,

-                   String::ShowCStringQuoted(expected),

-                   String::ShowCStringQuoted(actual),

-                   true);

-}

-

-// The helper function for {ASSERT|EXPECT}_STRNE.

-AssertionResult CmpHelperSTRNE(const char* s1_expression,

-                               const char* s2_expression,

-                               const char* s1,

-                               const char* s2) {

-  if (!String::CStringEquals(s1, s2)) {

-    return AssertionSuccess();

-  } else {

-    Message msg;

-    msg << "Expected: (" << s1_expression << ") != ("

-        << s2_expression << "), actual: \""

-        << s1 << "\" vs \"" << s2 << "\"";

-    return AssertionFailure(msg);

-  }

-}

-

-// The helper function for {ASSERT|EXPECT}_STRCASENE.

-AssertionResult CmpHelperSTRCASENE(const char* s1_expression,

-                                   const char* s2_expression,

-                                   const char* s1,

-                                   const char* s2) {

-  if (!String::CaseInsensitiveCStringEquals(s1, s2)) {

-    return AssertionSuccess();

-  } else {

-    Message msg;

-    msg << "Expected: (" << s1_expression << ") != ("

-        << s2_expression << ") (ignoring case), actual: \""

-        << s1 << "\" vs \"" << s2 << "\"";

-    return AssertionFailure(msg);

-  }

-}

-

-}  // namespace internal

-

-namespace {

-

-// Helper functions for implementing IsSubString() and IsNotSubstring().

-

-// This group of overloaded functions return true iff needle is a

-// substring of haystack.  NULL is considered a substring of itself

-// only.

-

-bool IsSubstringPred(const char* needle, const char* haystack) {

-  if (needle == NULL || haystack == NULL)

-    return needle == haystack;

-

-  return strstr(haystack, needle) != NULL;

-}

-

-bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {

-  if (needle == NULL || haystack == NULL)

-    return needle == haystack;

-

-  return wcsstr(haystack, needle) != NULL;

-}

-

-// StringType here can be either ::std::string or ::std::wstring.

-template <typename StringType>

-bool IsSubstringPred(const StringType& needle,

-                     const StringType& haystack) {

-  return haystack.find(needle) != StringType::npos;

-}

-

-// This function implements either IsSubstring() or IsNotSubstring(),

-// depending on the value of the expected_to_be_substring parameter.

-// StringType here can be const char*, const wchar_t*, ::std::string,

-// or ::std::wstring.

-template <typename StringType>

-AssertionResult IsSubstringImpl(

-    bool expected_to_be_substring,

-    const char* needle_expr, const char* haystack_expr,

-    const StringType& needle, const StringType& haystack) {

-  if (IsSubstringPred(needle, haystack) == expected_to_be_substring)

-    return AssertionSuccess();

-

-  const bool is_wide_string = sizeof(needle[0]) > 1;

-  const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";

-  return AssertionFailure(

-      Message()

-      << "Value of: " << needle_expr << "\n"

-      << "  Actual: " << begin_string_quote << needle << "\"\n"

-      << "Expected: " << (expected_to_be_substring ? "" : "not ")

-      << "a substring of " << haystack_expr << "\n"

-      << "Which is: " << begin_string_quote << haystack << "\"");

-}

-

-}  // namespace

-

-// IsSubstring() and IsNotSubstring() check whether needle is a

-// substring of haystack (NULL is considered a substring of itself

-// only), and return an appropriate error message when they fail.

-

-AssertionResult IsSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const char* needle, const char* haystack) {

-  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);

-}

-

-AssertionResult IsSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const wchar_t* needle, const wchar_t* haystack) {

-  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);

-}

-

-AssertionResult IsNotSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const char* needle, const char* haystack) {

-  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);

-}

-

-AssertionResult IsNotSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const wchar_t* needle, const wchar_t* haystack) {

-  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);

-}

-

-#if GTEST_HAS_STD_STRING

-AssertionResult IsSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const ::std::string& needle, const ::std::string& haystack) {

-  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);

-}

-

-AssertionResult IsNotSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const ::std::string& needle, const ::std::string& haystack) {

-  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);

-}

-#endif  // GTEST_HAS_STD_STRING

-

-#if GTEST_HAS_STD_WSTRING

-AssertionResult IsSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const ::std::wstring& needle, const ::std::wstring& haystack) {

-  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);

-}

-

-AssertionResult IsNotSubstring(

-    const char* needle_expr, const char* haystack_expr,

-    const ::std::wstring& needle, const ::std::wstring& haystack) {

-  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);

-}

-#endif  // GTEST_HAS_STD_WSTRING

-

-namespace internal {

-

-#if GTEST_OS_WINDOWS

-

-namespace {

-

-// Helper function for IsHRESULT{SuccessFailure} predicates

-AssertionResult HRESULTFailureHelper(const char* expr,

-                                     const char* expected,

-                                     long hr) {  // NOLINT

-#ifdef _WIN32_WCE

-  // Windows CE doesn't support FormatMessage.

-  const char error_text[] = "";

-#else

-  // Looks up the human-readable system message for the HRESULT code

-  // and since we're not passing any params to FormatMessage, we don't

-  // want inserts expanded.

-  const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |

-                       FORMAT_MESSAGE_IGNORE_INSERTS;

-  const DWORD kBufSize = 4096;  // String::Format can't exceed this length.

-  // Gets the system's human readable message string for this HRESULT.

-  char error_text[kBufSize] = { '\0' };

-  DWORD message_length = ::FormatMessageA(kFlags,

-                                          0,  // no source, we're asking system

-                                          hr,  // the error

-                                          0,  // no line width restrictions

-                                          error_text,  // output buffer

-                                          kBufSize,  // buf size

-                                          NULL);  // no arguments for inserts

-  // Trims tailing white space (FormatMessage leaves a trailing cr-lf)

-  for (; message_length && isspace(error_text[message_length - 1]);

-          --message_length) {

-    error_text[message_length - 1] = '\0';

-  }

-#endif  // _WIN32_WCE

-

-  const String error_hex(String::Format("0x%08X ", hr));

-  Message msg;

-  msg << "Expected: " << expr << " " << expected << ".\n"

-      << "  Actual: " << error_hex << error_text << "\n";

-

-  return ::testing::AssertionFailure(msg);

-}

-

-}  // namespace

-

-AssertionResult IsHRESULTSuccess(const char* expr, long hr) {  // NOLINT

-  if (SUCCEEDED(hr)) {

-    return AssertionSuccess();

-  }

-  return HRESULTFailureHelper(expr, "succeeds", hr);

-}

-

-AssertionResult IsHRESULTFailure(const char* expr, long hr) {  // NOLINT

-  if (FAILED(hr)) {

-    return AssertionSuccess();

-  }

-  return HRESULTFailureHelper(expr, "fails", hr);

-}

-

-#endif  // GTEST_OS_WINDOWS

-

-// Utility functions for encoding Unicode text (wide strings) in

-// UTF-8.

-

-// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8

-// like this:

-//

-// Code-point length   Encoding

-//   0 -  7 bits       0xxxxxxx

-//   8 - 11 bits       110xxxxx 10xxxxxx

-//  12 - 16 bits       1110xxxx 10xxxxxx 10xxxxxx

-//  17 - 21 bits       11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

-

-// The maximum code-point a one-byte UTF-8 sequence can represent.

-const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) <<  7) - 1;

-

-// The maximum code-point a two-byte UTF-8 sequence can represent.

-const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;

-

-// The maximum code-point a three-byte UTF-8 sequence can represent.

-const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;

-

-// The maximum code-point a four-byte UTF-8 sequence can represent.

-const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;

-

-// Chops off the n lowest bits from a bit pattern.  Returns the n

-// lowest bits.  As a side effect, the original bit pattern will be

-// shifted to the right by n bits.

-inline UInt32 ChopLowBits(UInt32* bits, int n) {

-  const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);

-  *bits >>= n;

-  return low_bits;

-}

-

-// Converts a Unicode code point to a narrow string in UTF-8 encoding.

-// code_point parameter is of type UInt32 because wchar_t may not be

-// wide enough to contain a code point.

-// The output buffer str must containt at least 32 characters.

-// The function returns the address of the output buffer.

-// If the code_point is not a valid Unicode code point

-// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output

-// as '(Invalid Unicode 0xXXXXXXXX)'.

-char* CodePointToUtf8(UInt32 code_point, char* str) {

-  if (code_point <= kMaxCodePoint1) {

-    str[1] = '\0';

-    str[0] = static_cast<char>(code_point);                          // 0xxxxxxx

-  } else if (code_point <= kMaxCodePoint2) {

-    str[2] = '\0';

-    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx

-    str[0] = static_cast<char>(0xC0 | code_point);                   // 110xxxxx

-  } else if (code_point <= kMaxCodePoint3) {

-    str[3] = '\0';

-    str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx

-    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx

-    str[0] = static_cast<char>(0xE0 | code_point);                   // 1110xxxx

-  } else if (code_point <= kMaxCodePoint4) {

-    str[4] = '\0';

-    str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx

-    str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx

-    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx

-    str[0] = static_cast<char>(0xF0 | code_point);                   // 11110xxx

-  } else {

-    // The longest string String::Format can produce when invoked

-    // with these parameters is 28 character long (not including

-    // the terminating nul character). We are asking for 32 character

-    // buffer just in case. This is also enough for strncpy to

-    // null-terminate the destination string.

-    posix::StrNCpy(

-        str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32);

-    str[31] = '\0';  // Makes sure no change in the format to strncpy leaves

-                     // the result unterminated.

-  }

-  return str;

-}

-

-// The following two functions only make sense if the the system

-// uses UTF-16 for wide string encoding. All supported systems

-// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.

-

-// Determines if the arguments constitute UTF-16 surrogate pair

-// and thus should be combined into a single Unicode code point

-// using CreateCodePointFromUtf16SurrogatePair.

-inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {

-  return sizeof(wchar_t) == 2 &&

-      (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;

-}

-

-// Creates a Unicode code point from UTF16 surrogate pair.

-inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,

-                                                    wchar_t second) {

-  const UInt32 mask = (1 << 10) - 1;

-  return (sizeof(wchar_t) == 2) ?

-      (((first & mask) << 10) | (second & mask)) + 0x10000 :

-      // This function should not be called when the condition is

-      // false, but we provide a sensible default in case it is.

-      static_cast<UInt32>(first);

-}

-

-// Converts a wide string to a narrow string in UTF-8 encoding.

-// The wide string is assumed to have the following encoding:

-//   UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)

-//   UTF-32 if sizeof(wchar_t) == 4 (on Linux)

-// Parameter str points to a null-terminated wide string.

-// Parameter num_chars may additionally limit the number

-// of wchar_t characters processed. -1 is used when the entire string

-// should be processed.

-// If the string contains code points that are not valid Unicode code points

-// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output

-// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding

-// and contains invalid UTF-16 surrogate pairs, values in those pairs

-// will be encoded as individual Unicode characters from Basic Normal Plane.

-String WideStringToUtf8(const wchar_t* str, int num_chars) {

-  if (num_chars == -1)

-    num_chars = static_cast<int>(wcslen(str));

-

-  StrStream stream;

-  for (int i = 0; i < num_chars; ++i) {

-    UInt32 unicode_code_point;

-

-    if (str[i] == L'\0') {

-      break;

-    } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {

-      unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],

-                                                                 str[i + 1]);

-      i++;

-    } else {

-      unicode_code_point = static_cast<UInt32>(str[i]);

-    }

-

-    char buffer[32];  // CodePointToUtf8 requires a buffer this big.

-    stream << CodePointToUtf8(unicode_code_point, buffer);

-  }

-  return StrStreamToString(&stream);

-}

-

-// Converts a wide C string to a String using the UTF-8 encoding.

-// NULL will be converted to "(null)".

-String String::ShowWideCString(const wchar_t * wide_c_str) {

-  if (wide_c_str == NULL) return String("(null)");

-

-  return String(internal::WideStringToUtf8(wide_c_str, -1).c_str());

-}

-

-// Similar to ShowWideCString(), except that this function encloses

-// the converted string in double quotes.

-String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) {

-  if (wide_c_str == NULL) return String("(null)");

-

-  return String::Format("L\"%s\"",

-                        String::ShowWideCString(wide_c_str).c_str());

-}

-

-// Compares two wide C strings.  Returns true iff they have the same

-// content.

-//

-// Unlike wcscmp(), this function can handle NULL argument(s).  A NULL

-// C string is considered different to any non-NULL C string,

-// including the empty string.

-bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {

-  if (lhs == NULL) return rhs == NULL;

-

-  if (rhs == NULL) return false;

-

-  return wcscmp(lhs, rhs) == 0;

-}

-

-// Helper function for *_STREQ on wide strings.

-AssertionResult CmpHelperSTREQ(const char* expected_expression,

-                               const char* actual_expression,

-                               const wchar_t* expected,

-                               const wchar_t* actual) {

-  if (String::WideCStringEquals(expected, actual)) {

-    return AssertionSuccess();

-  }

-

-  return EqFailure(expected_expression,

-                   actual_expression,

-                   String::ShowWideCStringQuoted(expected),

-                   String::ShowWideCStringQuoted(actual),

-                   false);

-}

-

-// Helper function for *_STRNE on wide strings.

-AssertionResult CmpHelperSTRNE(const char* s1_expression,

-                               const char* s2_expression,

-                               const wchar_t* s1,

-                               const wchar_t* s2) {

-  if (!String::WideCStringEquals(s1, s2)) {

-    return AssertionSuccess();

-  }

-

-  Message msg;

-  msg << "Expected: (" << s1_expression << ") != ("

-      << s2_expression << "), actual: "

-      << String::ShowWideCStringQuoted(s1)

-      << " vs " << String::ShowWideCStringQuoted(s2);

-  return AssertionFailure(msg);

-}

-

-// Compares two C strings, ignoring case.  Returns true iff they have

-// the same content.

-//

-// Unlike strcasecmp(), this function can handle NULL argument(s).  A

-// NULL C string is considered different to any non-NULL C string,

-// including the empty string.

-bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {

-  if (lhs == NULL)

-    return rhs == NULL;

-  if (rhs == NULL)

-    return false;

-  return posix::StrCaseCmp(lhs, rhs) == 0;

-}

-

-  // Compares two wide C strings, ignoring case.  Returns true iff they

-  // have the same content.

-  //

-  // Unlike wcscasecmp(), this function can handle NULL argument(s).

-  // A NULL C string is considered different to any non-NULL wide C string,

-  // including the empty string.

-  // NB: The implementations on different platforms slightly differ.

-  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE

-  // environment variable. On GNU platform this method uses wcscasecmp

-  // which compares according to LC_CTYPE category of the current locale.

-  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the

-  // current locale.

-bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,

-                                              const wchar_t* rhs) {

-  if ( lhs == NULL ) return rhs == NULL;

-

-  if ( rhs == NULL ) return false;

-

-#if GTEST_OS_WINDOWS

-  return _wcsicmp(lhs, rhs) == 0;

-#elif GTEST_OS_LINUX

-  return wcscasecmp(lhs, rhs) == 0;

-#else

-  // Mac OS X and Cygwin don't define wcscasecmp.  Other unknown OSes

-  // may not define it either.

-  wint_t left, right;

-  do {

-    left = towlower(*lhs++);

-    right = towlower(*rhs++);

-  } while (left && left == right);

-  return left == right;

-#endif  // OS selector

-}

-

-// Constructs a String by copying a given number of chars from a

-// buffer.  E.g. String("hello", 3) will create the string "hel".

-String::String(const char * buffer, size_t len) {

-  char * const temp = new char[ len + 1 ];

-  memcpy(temp, buffer, len);

-  temp[ len ] = '\0';

-  c_str_ = temp;

-}

-

-// Compares this with another String.

-// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0

-// if this is greater than rhs.

-int String::Compare(const String & rhs) const {

-  if ( c_str_ == NULL ) {

-    return rhs.c_str_ == NULL ? 0 : -1;  // NULL < anything except NULL

-  }

-

-  return rhs.c_str_ == NULL ? 1 : strcmp(c_str_, rhs.c_str_);

-}

-

-// Returns true iff this String ends with the given suffix.  *Any*

-// String is considered to end with a NULL or empty suffix.

-bool String::EndsWith(const char* suffix) const {

-  if (suffix == NULL || CStringEquals(suffix, "")) return true;

-

-  if (c_str_ == NULL) return false;

-

-  const size_t this_len = strlen(c_str_);

-  const size_t suffix_len = strlen(suffix);

-  return (this_len >= suffix_len) &&

-         CStringEquals(c_str_ + this_len - suffix_len, suffix);

-}

-

-// Returns true iff this String ends with the given suffix, ignoring case.

-// Any String is considered to end with a NULL or empty suffix.

-bool String::EndsWithCaseInsensitive(const char* suffix) const {

-  if (suffix == NULL || CStringEquals(suffix, "")) return true;

-

-  if (c_str_ == NULL) return false;

-

-  const size_t this_len = strlen(c_str_);

-  const size_t suffix_len = strlen(suffix);

-  return (this_len >= suffix_len) &&

-         CaseInsensitiveCStringEquals(c_str_ + this_len - suffix_len, suffix);

-}

-

-// Sets the 0-terminated C string this String object represents.  The

-// old string in this object is deleted, and this object will own a

-// clone of the input string.  This function copies only up to length

-// bytes (plus a terminating null byte), or until the first null byte,

-// whichever comes first.

-//

-// This function works even when the c_str parameter has the same

-// value as that of the c_str_ field.

-void String::Set(const char * c_str, size_t length) {

-  // Makes sure this works when c_str == c_str_

-  const char* const temp = CloneString(c_str, length);

-  delete[] c_str_;

-  c_str_ = temp;

-}

-

-// Assigns a C string to this object.  Self-assignment works.

-const String& String::operator=(const char* c_str) {

-  // Makes sure this works when c_str == c_str_

-  if (c_str != c_str_) {

-    delete[] c_str_;

-    c_str_ = CloneCString(c_str);

-  }

-  return *this;

-}

-

-// Formats a list of arguments to a String, using the same format

-// spec string as for printf.

-//

-// We do not use the StringPrintf class as it is not universally

-// available.

-//

-// The result is limited to 4096 characters (including the tailing 0).

-// If 4096 characters are not enough to format the input,

-// "<buffer exceeded>" is returned.

-String String::Format(const char * format, ...) {

-  va_list args;

-  va_start(args, format);

-

-  char buffer[4096];

-  // MSVC 8 deprecates vsnprintf(), so we want to suppress warning

-  // 4996 (deprecated function) there.

-#ifdef _MSC_VER  // We are using MSVC.

-#pragma warning(push)          // Saves the current warning state.

-#pragma warning(disable:4996)  // Temporarily disables warning 4996.

-  const int size =

-    vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args);

-#pragma warning(pop)           // Restores the warning state.

-#else  // We are not using MSVC.

-  const int size =

-    vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args);

-#endif  // _MSC_VER

-  va_end(args);

-

-  return String(size >= 0 ? buffer : "<buffer exceeded>");

-}

-

-// Converts the buffer in a StrStream to a String, converting NUL

-// bytes to "\\0" along the way.

-String StrStreamToString(StrStream* ss) {

-#if GTEST_HAS_STD_STRING

-  const ::std::string& str = ss->str();

-  const char* const start = str.c_str();

-  const char* const end = start + str.length();

-#else

-  const char* const start = ss->str();

-  const char* const end = start + ss->pcount();

-#endif  // GTEST_HAS_STD_STRING

-

-  // We need to use a helper StrStream to do this transformation

-  // because String doesn't support push_back().

-  StrStream helper;

-  for (const char* ch = start; ch != end; ++ch) {

-    if (*ch == '\0') {

-      helper << "\\0";  // Replaces NUL with "\\0";

-    } else {

-      helper.put(*ch);

-    }

-  }

-

-#if GTEST_HAS_STD_STRING

-  return String(helper.str().c_str());

-#else

-  const String str(helper.str(), helper.pcount());

-  helper.freeze(false);

-  ss->freeze(false);

-  return str;

-#endif  // GTEST_HAS_STD_STRING

-}

-

-// Appends the user-supplied message to the Google-Test-generated message.

-String AppendUserMessage(const String& gtest_msg,

-                         const Message& user_msg) {

-  // Appends the user message if it's non-empty.

-  const String user_msg_string = user_msg.GetString();

-  if (user_msg_string.empty()) {

-    return gtest_msg;

-  }

-

-  Message msg;

-  msg << gtest_msg << "\n" << user_msg_string;

-

-  return msg.GetString();

-}

-

-// class TestResult

-

-// Creates an empty TestResult.

-TestResult::TestResult()

-    : death_test_count_(0),

-      elapsed_time_(0) {

-}

-

-// D'tor.

-TestResult::~TestResult() {

-}

-

-// Adds a test part result to the list.

-void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {

-  test_part_results_.PushBack(test_part_result);

-}

-

-// Adds a test property to the list. If a property with the same key as the

-// supplied property is already represented, the value of this test_property

-// replaces the old value for that key.

-void TestResult::RecordProperty(const TestProperty& test_property) {

-  if (!ValidateTestProperty(test_property)) {

-    return;

-  }

-  MutexLock lock(&test_properites_mutex_);

-  ListNode<TestProperty>* const node_with_matching_key =

-      test_properties_.FindIf(TestPropertyKeyIs(test_property.key()));

-  if (node_with_matching_key == NULL) {

-    test_properties_.PushBack(test_property);

-    return;

-  }

-  TestProperty& property_with_matching_key = node_with_matching_key->element();

-  property_with_matching_key.SetValue(test_property.value());

-}

-

-// Adds a failure if the key is a reserved attribute of Google Test

-// testcase tags.  Returns true if the property is valid.

-bool TestResult::ValidateTestProperty(const TestProperty& test_property) {

-  String key(test_property.key());

-  if (key == "name" || key == "status" || key == "time" || key == "classname") {

-    ADD_FAILURE()

-        << "Reserved key used in RecordProperty(): "

-        << key

-        << " ('name', 'status', 'time', and 'classname' are reserved by "

-        << GTEST_NAME_ << ")";

-    return false;

-  }

-  return true;

-}

-

-// Clears the object.

-void TestResult::Clear() {

-  test_part_results_.Clear();

-  test_properties_.Clear();

-  death_test_count_ = 0;

-  elapsed_time_ = 0;

-}

-

-// Returns true iff the test part passed.

-static bool TestPartPassed(const TestPartResult & result) {

-  return result.passed();

-}

-

-// Gets the number of successful test parts.

-int TestResult::successful_part_count() const {

-  return test_part_results_.CountIf(TestPartPassed);

-}

-

-// Returns true iff the test part failed.

-static bool TestPartFailed(const TestPartResult & result) {

-  return result.failed();

-}

-

-// Gets the number of failed test parts.

-int TestResult::failed_part_count() const {

-  return test_part_results_.CountIf(TestPartFailed);

-}

-

-// Returns true iff the test part fatally failed.

-static bool TestPartFatallyFailed(const TestPartResult& result) {

-  return result.fatally_failed();

-}

-

-// Returns true iff the test fatally failed.

-bool TestResult::HasFatalFailure() const {

-  return test_part_results_.CountIf(TestPartFatallyFailed) > 0;

-}

-

-// Returns true iff the test part non-fatally failed.

-static bool TestPartNonfatallyFailed(const TestPartResult& result) {

-  return result.nonfatally_failed();

-}

-

-// Returns true iff the test has a non-fatal failure.

-bool TestResult::HasNonfatalFailure() const {

-  return test_part_results_.CountIf(TestPartNonfatallyFailed) > 0;

-}

-

-// Gets the number of all test parts.  This is the sum of the number

-// of successful test parts and the number of failed test parts.

-int TestResult::total_part_count() const {

-  return test_part_results_.size();

-}

-

-}  // namespace internal

-

-// class Test

-

-// Creates a Test object.

-

-// The c'tor saves the values of all Google Test flags.

-Test::Test()

-    : gtest_flag_saver_(new internal::GTestFlagSaver) {

-}

-

-// The d'tor restores the values of all Google Test flags.

-Test::~Test() {

-  delete gtest_flag_saver_;

-}

-

-// Sets up the test fixture.

-//

-// A sub-class may override this.

-void Test::SetUp() {

-}

-

-// Tears down the test fixture.

-//

-// A sub-class may override this.

-void Test::TearDown() {

-}

-

-// Allows user supplied key value pairs to be recorded for later output.

-void Test::RecordProperty(const char* key, const char* value) {

-  UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value);

-}

-

-// Allows user supplied key value pairs to be recorded for later output.

-void Test::RecordProperty(const char* key, int value) {

-  Message value_message;

-  value_message << value;

-  RecordProperty(key, value_message.GetString().c_str());

-}

-

-#if GTEST_OS_WINDOWS

-// We are on Windows.

-

-// Adds an "exception thrown" fatal failure to the current test.

-static void AddExceptionThrownFailure(DWORD exception_code,

-                                      const char* location) {

-  Message message;

-  message << "Exception thrown with code 0x" << std::setbase(16) <<

-    exception_code << std::setbase(10) << " in " << location << ".";

-

-  UnitTest* const unit_test = UnitTest::GetInstance();

-  unit_test->AddTestPartResult(

-      TPRT_FATAL_FAILURE,

-      static_cast<const char *>(NULL),

-           // We have no info about the source file where the exception

-           // occurred.

-      -1,  // We have no info on which line caused the exception.

-      message.GetString(),

-      internal::String(""));

-}

-

-#endif  // GTEST_OS_WINDOWS

-

-// Google Test requires all tests in the same test case to use the same test

-// fixture class.  This function checks if the current test has the

-// same fixture class as the first test in the current test case.  If

-// yes, it returns true; otherwise it generates a Google Test failure and

-// returns false.

-bool Test::HasSameFixtureClass() {

-  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();

-  const TestCase* const test_case = impl->current_test_case();

-

-  // Info about the first test in the current test case.

-  const internal::TestInfoImpl* const first_test_info =

-      test_case->test_info_list().Head()->element()->impl();

-  const internal::TypeId first_fixture_id = first_test_info->fixture_class_id();

-  const char* const first_test_name = first_test_info->name();

-

-  // Info about the current test.

-  const internal::TestInfoImpl* const this_test_info =

-      impl->current_test_info()->impl();

-  const internal::TypeId this_fixture_id = this_test_info->fixture_class_id();

-  const char* const this_test_name = this_test_info->name();

-

-  if (this_fixture_id != first_fixture_id) {

-    // Is the first test defined using TEST?

-    const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();

-    // Is this test defined using TEST?

-    const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();

-

-    if (first_is_TEST || this_is_TEST) {

-      // The user mixed TEST and TEST_F in this test case - we'll tell

-      // him/her how to fix it.

-

-      // Gets the name of the TEST and the name of the TEST_F.  Note

-      // that first_is_TEST and this_is_TEST cannot both be true, as

-      // the fixture IDs are different for the two tests.

-      const char* const TEST_name =

-          first_is_TEST ? first_test_name : this_test_name;

-      const char* const TEST_F_name =

-          first_is_TEST ? this_test_name : first_test_name;

-

-      ADD_FAILURE()

-          << "All tests in the same test case must use the same test fixture\n"

-          << "class, so mixing TEST_F and TEST in the same test case is\n"

-          << "illegal.  In test case " << this_test_info->test_case_name()

-          << ",\n"

-          << "test " << TEST_F_name << " is defined using TEST_F but\n"

-          << "test " << TEST_name << " is defined using TEST.  You probably\n"

-          << "want to change the TEST to TEST_F or move it to another test\n"

-          << "case.";

-    } else {

-      // The user defined two fixture classes with the same name in

-      // two namespaces - we'll tell him/her how to fix it.

-      ADD_FAILURE()

-          << "All tests in the same test case must use the same test fixture\n"

-          << "class.  However, in test case "

-          << this_test_info->test_case_name() << ",\n"

-          << "you defined test " << first_test_name

-          << " and test " << this_test_name << "\n"

-          << "using two different test fixture classes.  This can happen if\n"

-          << "the two classes are from different namespaces or translation\n"

-          << "units and have the same name.  You should probably rename one\n"

-          << "of the classes to put the tests into different test cases.";

-    }

-    return false;

-  }

-

-  return true;

-}

-

-// Runs the test and updates the test result.

-void Test::Run() {

-  if (!HasSameFixtureClass()) return;

-

-  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();

-#if GTEST_HAS_SEH

-  // Catch SEH-style exceptions.

-  impl->os_stack_trace_getter()->UponLeavingGTest();

-  __try {

-    SetUp();

-  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(

-      GetExceptionCode())) {

-    AddExceptionThrownFailure(GetExceptionCode(), "SetUp()");

-  }

-

-  // We will run the test only if SetUp() had no fatal failure.

-  if (!HasFatalFailure()) {

-    impl->os_stack_trace_getter()->UponLeavingGTest();

-    __try {

-      TestBody();

-    } __except(internal::UnitTestOptions::GTestShouldProcessSEH(

-        GetExceptionCode())) {

-      AddExceptionThrownFailure(GetExceptionCode(), "the test body");

-    }

-  }

-

-  // However, we want to clean up as much as possible.  Hence we will

-  // always call TearDown(), even if SetUp() or the test body has

-  // failed.

-  impl->os_stack_trace_getter()->UponLeavingGTest();

-  __try {

-    TearDown();

-  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(

-      GetExceptionCode())) {

-    AddExceptionThrownFailure(GetExceptionCode(), "TearDown()");

-  }

-

-#else  // We are on a compiler or platform that doesn't support SEH.

-  impl->os_stack_trace_getter()->UponLeavingGTest();

-  SetUp();

-

-  // We will run the test only if SetUp() was successful.

-  if (!HasFatalFailure()) {

-    impl->os_stack_trace_getter()->UponLeavingGTest();

-    TestBody();

-  }

-

-  // However, we want to clean up as much as possible.  Hence we will

-  // always call TearDown(), even if SetUp() or the test body has

-  // failed.

-  impl->os_stack_trace_getter()->UponLeavingGTest();

-  TearDown();

-#endif  // GTEST_HAS_SEH

-}

-

-

-// Returns true iff the current test has a fatal failure.

-bool Test::HasFatalFailure() {

-  return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();

-}

-

-// Returns true iff the current test has a non-fatal failure.

-bool Test::HasNonfatalFailure() {

-  return internal::GetUnitTestImpl()->current_test_result()->

-      HasNonfatalFailure();

-}

-

-// class TestInfo

-

-// Constructs a TestInfo object. It assumes ownership of the test factory

-// object via impl_.

-TestInfo::TestInfo(const char* test_case_name,

-                   const char* name,

-                   const char* test_case_comment,

-                   const char* comment,

-                   internal::TypeId fixture_class_id,

-                   internal::TestFactoryBase* factory) {

-  impl_ = new internal::TestInfoImpl(this, test_case_name, name,

-                                     test_case_comment, comment,

-                                     fixture_class_id, factory);

-}

-

-// Destructs a TestInfo object.

-TestInfo::~TestInfo() {

-  delete impl_;

-}

-

-namespace internal {

-

-// Creates a new TestInfo object and registers it with Google Test;

-// returns the created object.

-//

-// Arguments:

-//

-//   test_case_name:   name of the test case

-//   name:             name of the test

-//   test_case_comment: a comment on the test case that will be included in

-//                      the test output

-//   comment:          a comment on the test that will be included in the

-//                     test output

-//   fixture_class_id: ID of the test fixture class

-//   set_up_tc:        pointer to the function that sets up the test case

-//   tear_down_tc:     pointer to the function that tears down the test case

-//   factory:          pointer to the factory that creates a test object.

-//                     The newly created TestInfo instance will assume

-//                     ownership of the factory object.

-TestInfo* MakeAndRegisterTestInfo(

-    const char* test_case_name, const char* name,

-    const char* test_case_comment, const char* comment,

-    TypeId fixture_class_id,

-    SetUpTestCaseFunc set_up_tc,

-    TearDownTestCaseFunc tear_down_tc,

-    TestFactoryBase* factory) {

-  TestInfo* const test_info =

-      new TestInfo(test_case_name, name, test_case_comment, comment,

-                   fixture_class_id, factory);

-  GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);

-  return test_info;

-}

-

-#if GTEST_HAS_PARAM_TEST

-void ReportInvalidTestCaseType(const char* test_case_name,

-                               const char* file, int line) {

-  Message errors;

-  errors

-      << "Attempted redefinition of test case " << test_case_name << ".\n"

-      << "All tests in the same test case must use the same test fixture\n"

-      << "class.  However, in test case " << test_case_name << ", you tried\n"

-      << "to define a test using a fixture class different from the one\n"

-      << "used earlier. This can happen if the two fixture classes are\n"

-      << "from different namespaces and have the same name. You should\n"

-      << "probably rename one of the classes to put the tests into different\n"

-      << "test cases.";

-

-  fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),

-          errors.GetString().c_str());

-}

-#endif  // GTEST_HAS_PARAM_TEST

-

-}  // namespace internal

-

-// Returns the test case name.

-const char* TestInfo::test_case_name() const {

-  return impl_->test_case_name();

-}

-

-// Returns the test name.

-const char* TestInfo::name() const {

-  return impl_->name();

-}

-

-// Returns the test case comment.

-const char* TestInfo::test_case_comment() const {

-  return impl_->test_case_comment();

-}

-

-// Returns the test comment.

-const char* TestInfo::comment() const {

-  return impl_->comment();

-}

-

-// Returns true if this test should run.

-bool TestInfo::should_run() const { return impl_->should_run(); }

-

-// Returns true if this test matches the user-specified filter.

-bool TestInfo::matches_filter() const { return impl_->matches_filter(); }

-

-// Returns the result of the test.

-const internal::TestResult* TestInfo::result() const { return impl_->result(); }

-

-// Increments the number of death tests encountered in this test so

-// far.

-int TestInfo::increment_death_test_count() {

-  return impl_->result()->increment_death_test_count();

-}

-

-namespace {

-

-// A predicate that checks the test name of a TestInfo against a known

-// value.

-//

-// This is used for implementation of the TestCase class only.  We put

-// it in the anonymous namespace to prevent polluting the outer

-// namespace.

-//

-// TestNameIs is copyable.

-class TestNameIs {

- public:

-  // Constructor.

-  //

-  // TestNameIs has NO default constructor.

-  explicit TestNameIs(const char* name)

-      : name_(name) {}

-

-  // Returns true iff the test name of test_info matches name_.

-  bool operator()(const TestInfo * test_info) const {

-    return test_info && internal::String(test_info->name()).Compare(name_) == 0;

-  }

-

- private:

-  internal::String name_;

-};

-

-}  // namespace

-

-// Finds and returns a TestInfo with the given name.  If one doesn't

-// exist, returns NULL.

-TestInfo * TestCase::GetTestInfo(const char* test_name) {

-  // Can we find a TestInfo with the given name?

-  internal::ListNode<TestInfo *> * const node = test_info_list_->FindIf(

-      TestNameIs(test_name));

-

-  // Returns the TestInfo found.

-  return node ? node->element() : NULL;

-}

-

-namespace internal {

-

-// This method expands all parameterized tests registered with macros TEST_P

-// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.

-// This will be done just once during the program runtime.

-void UnitTestImpl::RegisterParameterizedTests() {

-#if GTEST_HAS_PARAM_TEST

-  if (!parameterized_tests_registered_) {

-    parameterized_test_registry_.RegisterTests();

-    parameterized_tests_registered_ = true;

-  }

-#endif

-}

-

-// Creates the test object, runs it, records its result, and then

-// deletes it.

-void TestInfoImpl::Run() {

-  if (!should_run_) return;

-

-  // Tells UnitTest where to store test result.

-  UnitTestImpl* const impl = internal::GetUnitTestImpl();

-  impl->set_current_test_info(parent_);

-

-  // Notifies the unit test event listener that a test is about to

-  // start.

-  UnitTestEventListenerInterface* const result_printer =

-    impl->result_printer();

-  result_printer->OnTestStart(parent_);

-

-  const TimeInMillis start = GetTimeInMillis();

-

-  impl->os_stack_trace_getter()->UponLeavingGTest();

-#if GTEST_HAS_SEH

-  // Catch SEH-style exceptions.

-  Test* test = NULL;

-

-  __try {

-    // Creates the test object.

-    test = factory_->CreateTest();

-  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(

-      GetExceptionCode())) {

-    AddExceptionThrownFailure(GetExceptionCode(),

-                              "the test fixture's constructor");

-    return;

-  }

-#else  // We are on a compiler or platform that doesn't support SEH.

-

-  // TODO(wan): If test->Run() throws, test won't be deleted.  This is

-  // not a problem now as we don't use exceptions.  If we were to

-  // enable exceptions, we should revise the following to be

-  // exception-safe.

-

-  // Creates the test object.

-  Test* test = factory_->CreateTest();

-#endif  // GTEST_HAS_SEH

-

-  // Runs the test only if the constructor of the test fixture didn't

-  // generate a fatal failure.

-  if (!Test::HasFatalFailure()) {

-    test->Run();

-  }

-

-  // Deletes the test object.

-  impl->os_stack_trace_getter()->UponLeavingGTest();

-  delete test;

-  test = NULL;

-

-  result_.set_elapsed_time(GetTimeInMillis() - start);

-

-  // Notifies the unit test event listener that a test has just finished.

-  result_printer->OnTestEnd(parent_);

-

-  // Tells UnitTest to stop associating assertion results to this

-  // test.

-  impl->set_current_test_info(NULL);

-}

-

-}  // namespace internal

-

-// class TestCase

-

-// Gets the number of successful tests in this test case.

-int TestCase::successful_test_count() const {

-  return test_info_list_->CountIf(TestPassed);

-}

-

-// Gets the number of failed tests in this test case.

-int TestCase::failed_test_count() const {

-  return test_info_list_->CountIf(TestFailed);

-}

-

-int TestCase::disabled_test_count() const {

-  return test_info_list_->CountIf(TestDisabled);

-}

-

-// Get the number of tests in this test case that should run.

-int TestCase::test_to_run_count() const {

-  return test_info_list_->CountIf(ShouldRunTest);

-}

-

-// Gets the number of all tests.

-int TestCase::total_test_count() const {

-  return test_info_list_->size();

-}

-

-// Creates a TestCase with the given name.

-//

-// Arguments:

-//

-//   name:         name of the test case

-//   set_up_tc:    pointer to the function that sets up the test case

-//   tear_down_tc: pointer to the function that tears down the test case

-TestCase::TestCase(const char* name, const char* comment,

-                   Test::SetUpTestCaseFunc set_up_tc,

-                   Test::TearDownTestCaseFunc tear_down_tc)

-    : name_(name),

-      comment_(comment),

-      set_up_tc_(set_up_tc),

-      tear_down_tc_(tear_down_tc),

-      should_run_(false),

-      elapsed_time_(0) {

-  test_info_list_ = new internal::List<TestInfo *>;

-}

-

-// Destructor of TestCase.

-TestCase::~TestCase() {

-  // Deletes every Test in the collection.

-  test_info_list_->ForEach(internal::Delete<TestInfo>);

-

-  // Then deletes the Test collection.

-  delete test_info_list_;

-  test_info_list_ = NULL;

-}

-

-// Adds a test to this test case.  Will delete the test upon

-// destruction of the TestCase object.

-void TestCase::AddTestInfo(TestInfo * test_info) {

-  test_info_list_->PushBack(test_info);

-}

-

-// Runs every test in this TestCase.

-void TestCase::Run() {

-  if (!should_run_) return;

-

-  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();

-  impl->set_current_test_case(this);

-

-  UnitTestEventListenerInterface * const result_printer =

-      impl->result_printer();

-

-  result_printer->OnTestCaseStart(this);

-  impl->os_stack_trace_getter()->UponLeavingGTest();

-  set_up_tc_();

-

-  const internal::TimeInMillis start = internal::GetTimeInMillis();

-  test_info_list_->ForEach(internal::TestInfoImpl::RunTest);

-  elapsed_time_ = internal::GetTimeInMillis() - start;

-

-  impl->os_stack_trace_getter()->UponLeavingGTest();

-  tear_down_tc_();

-  result_printer->OnTestCaseEnd(this);

-  impl->set_current_test_case(NULL);

-}

-

-// Clears the results of all tests in this test case.

-void TestCase::ClearResult() {

-  test_info_list_->ForEach(internal::TestInfoImpl::ClearTestResult);

-}

-

-

-// class UnitTestEventListenerInterface

-

-// The virtual d'tor.

-UnitTestEventListenerInterface::~UnitTestEventListenerInterface() {

-}

-

-// A result printer that never prints anything.  Used in the child process

-// of an exec-style death test to avoid needless output clutter.

-class NullUnitTestResultPrinter : public UnitTestEventListenerInterface {};

-

-// Formats a countable noun.  Depending on its quantity, either the

-// singular form or the plural form is used. e.g.

-//

-// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".

-// FormatCountableNoun(5, "book", "books") returns "5 books".

-static internal::String FormatCountableNoun(int count,

-                                            const char * singular_form,

-                                            const char * plural_form) {

-  return internal::String::Format("%d %s", count,

-                                  count == 1 ? singular_form : plural_form);

-}

-

-// Formats the count of tests.

-static internal::String FormatTestCount(int test_count) {

-  return FormatCountableNoun(test_count, "test", "tests");

-}

-

-// Formats the count of test cases.

-static internal::String FormatTestCaseCount(int test_case_count) {

-  return FormatCountableNoun(test_case_count, "test case", "test cases");

-}

-

-// Converts a TestPartResultType enum to human-friendly string

-// representation.  Both TPRT_NONFATAL_FAILURE and TPRT_FATAL_FAILURE

-// are translated to "Failure", as the user usually doesn't care about

-// the difference between the two when viewing the test result.

-static const char * TestPartResultTypeToString(TestPartResultType type) {

-  switch (type) {

-    case TPRT_SUCCESS:

-      return "Success";

-

-    case TPRT_NONFATAL_FAILURE:

-    case TPRT_FATAL_FAILURE:

-#ifdef _MSC_VER

-      return "error: ";

-#else

-      return "Failure\n";

-#endif

-  }

-

-  return "Unknown result type";

-}

-

-// Prints a TestPartResult to a String.

-static internal::String PrintTestPartResultToString(

-    const TestPartResult& test_part_result) {

-  return (Message()

-          << internal::FormatFileLocation(test_part_result.file_name(),

-                                          test_part_result.line_number())

-          << " " << TestPartResultTypeToString(test_part_result.type())

-          << test_part_result.message()).GetString();

-}

-

-// Prints a TestPartResult.

-static void PrintTestPartResult(

-    const TestPartResult& test_part_result) {

-  printf("%s\n", PrintTestPartResultToString(test_part_result).c_str());

-  fflush(stdout);

-}

-

-// class PrettyUnitTestResultPrinter

-

-namespace internal {

-

-enum GTestColor {

-  COLOR_DEFAULT,

-  COLOR_RED,

-  COLOR_GREEN,

-  COLOR_YELLOW

-};

-

-#if GTEST_OS_WINDOWS && !defined(_WIN32_WCE)

-

-// Returns the character attribute for the given color.

-WORD GetColorAttribute(GTestColor color) {

-  switch (color) {

-    case COLOR_RED:    return FOREGROUND_RED;

-    case COLOR_GREEN:  return FOREGROUND_GREEN;

-    case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;

-    default:           return 0;

-  }

-}

-

-#else

-

-// Returns the ANSI color code for the given color.  COLOR_DEFAULT is

-// an invalid input.

-const char* GetAnsiColorCode(GTestColor color) {

-  switch (color) {

-    case COLOR_RED:     return "1";

-    case COLOR_GREEN:   return "2";

-    case COLOR_YELLOW:  return "3";

-    default:            return NULL;

-  };

-}

-

-#endif  // GTEST_OS_WINDOWS && !_WIN32_WCE

-

-// Returns true iff Google Test should use colors in the output.

-bool ShouldUseColor(bool stdout_is_tty) {

-  const char* const gtest_color = GTEST_FLAG(color).c_str();

-

-  if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {

-#if GTEST_OS_WINDOWS

-    // On Windows the TERM variable is usually not set, but the

-    // console there does support colors.

-    return stdout_is_tty;

-#else

-    // On non-Windows platforms, we rely on the TERM variable.

-    const char* const term = posix::GetEnv("TERM");

-    const bool term_supports_color =

-        String::CStringEquals(term, "xterm") ||

-        String::CStringEquals(term, "xterm-color") ||

-        String::CStringEquals(term, "xterm-256color") ||

-        String::CStringEquals(term, "cygwin");

-    return stdout_is_tty && term_supports_color;

-#endif  // GTEST_OS_WINDOWS

-  }

-

-  return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||

-      String::CaseInsensitiveCStringEquals(gtest_color, "true") ||

-      String::CaseInsensitiveCStringEquals(gtest_color, "t") ||

-      String::CStringEquals(gtest_color, "1");

-  // We take "yes", "true", "t", and "1" as meaning "yes".  If the

-  // value is neither one of these nor "auto", we treat it as "no" to

-  // be conservative.

-}

-

-// Helpers for printing colored strings to stdout. Note that on Windows, we

-// cannot simply emit special characters and have the terminal change colors.

-// This routine must actually emit the characters rather than return a string

-// that would be colored when printed, as can be done on Linux.

-void ColoredPrintf(GTestColor color, const char* fmt, ...) {

-  va_list args;

-  va_start(args, fmt);

-

-#if defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS

-  const bool use_color = false;

-#else

-  static const bool in_color_mode =

-      ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);

-  const bool use_color = in_color_mode && (color != COLOR_DEFAULT);

-#endif  // defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS

-  // The '!= 0' comparison is necessary to satisfy MSVC 7.1.

-

-  if (!use_color) {

-    vprintf(fmt, args);

-    va_end(args);

-    return;

-  }

-

-#if GTEST_OS_WINDOWS && !defined(_WIN32_WCE)

-  const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);

-

-  // Gets the current text color.

-  CONSOLE_SCREEN_BUFFER_INFO buffer_info;

-  GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);

-  const WORD old_color_attrs = buffer_info.wAttributes;

-

-  SetConsoleTextAttribute(stdout_handle,

-                          GetColorAttribute(color) | FOREGROUND_INTENSITY);

-  vprintf(fmt, args);

-

-  // Restores the text color.

-  SetConsoleTextAttribute(stdout_handle, old_color_attrs);

-#else

-  printf("\033[0;3%sm", GetAnsiColorCode(color));

-  vprintf(fmt, args);

-  printf("\033[m");  // Resets the terminal to default.

-#endif  // GTEST_OS_WINDOWS && !defined(_WIN32_WCE)

-  va_end(args);

-}

-

-}  // namespace internal

-

-using internal::ColoredPrintf;

-using internal::COLOR_DEFAULT;

-using internal::COLOR_RED;

-using internal::COLOR_GREEN;

-using internal::COLOR_YELLOW;

-

-// This class implements the UnitTestEventListenerInterface interface.

-//

-// Class PrettyUnitTestResultPrinter is copyable.

-class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface {

- public:

-  PrettyUnitTestResultPrinter() {}

-  static void PrintTestName(const char * test_case, const char * test) {

-    printf("%s.%s", test_case, test);

-  }

-

-  // The following methods override what's in the

-  // UnitTestEventListenerInterface class.

-  virtual void OnUnitTestStart(const UnitTest * unit_test);

-  virtual void OnGlobalSetUpStart(const UnitTest*);

-  virtual void OnTestCaseStart(const TestCase * test_case);

-  virtual void OnTestCaseEnd(const TestCase * test_case);

-  virtual void OnTestStart(const TestInfo * test_info);

-  virtual void OnNewTestPartResult(const TestPartResult * result);

-  virtual void OnTestEnd(const TestInfo * test_info);

-  virtual void OnGlobalTearDownStart(const UnitTest*);

-  virtual void OnUnitTestEnd(const UnitTest * unit_test);

-

- private:

-  internal::String test_case_name_;

-};

-

-// Called before the unit test starts.

-void PrettyUnitTestResultPrinter::OnUnitTestStart(

-    const UnitTest * unit_test) {

-  const char * const filter = GTEST_FLAG(filter).c_str();

-

-  // Prints the filter if it's not *.  This reminds the user that some

-  // tests may be skipped.

-  if (!internal::String::CStringEquals(filter, kUniversalFilter)) {

-    ColoredPrintf(COLOR_YELLOW,

-                  "Note: %s filter = %s\n", GTEST_NAME_, filter);

-  }

-

-  if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {

-    ColoredPrintf(COLOR_YELLOW,

-                  "Note: This is test shard %s of %s.\n",

-                  internal::posix::GetEnv(kTestShardIndex),

-                  internal::posix::GetEnv(kTestTotalShards));

-  }

-

-  const internal::UnitTestImpl* const impl = unit_test->impl();

-  ColoredPrintf(COLOR_GREEN,  "[==========] ");

-  printf("Running %s from %s.\n",

-         FormatTestCount(impl->test_to_run_count()).c_str(),

-         FormatTestCaseCount(impl->test_case_to_run_count()).c_str());

-  fflush(stdout);

-}

-

-void PrettyUnitTestResultPrinter::OnGlobalSetUpStart(const UnitTest*) {

-  ColoredPrintf(COLOR_GREEN,  "[----------] ");

-  printf("Global test environment set-up.\n");

-  fflush(stdout);

-}

-

-void PrettyUnitTestResultPrinter::OnTestCaseStart(

-    const TestCase * test_case) {

-  test_case_name_ = test_case->name();

-  const internal::String counts =

-      FormatCountableNoun(test_case->test_to_run_count(), "test", "tests");

-  ColoredPrintf(COLOR_GREEN, "[----------] ");

-  printf("%s from %s", counts.c_str(), test_case_name_.c_str());

-  if (test_case->comment()[0] == '\0') {

-    printf("\n");

-  } else {

-    printf(", where %s\n", test_case->comment());

-  }

-  fflush(stdout);

-}

-

-void PrettyUnitTestResultPrinter::OnTestCaseEnd(

-    const TestCase * test_case) {

-  if (!GTEST_FLAG(print_time)) return;

-

-  test_case_name_ = test_case->name();

-  const internal::String counts =

-      FormatCountableNoun(test_case->test_to_run_count(), "test", "tests");

-  ColoredPrintf(COLOR_GREEN, "[----------] ");

-  printf("%s from %s (%s ms total)\n\n",

-         counts.c_str(), test_case_name_.c_str(),

-         internal::StreamableToString(test_case->elapsed_time()).c_str());

-  fflush(stdout);

-}

-

-void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo * test_info) {

-  ColoredPrintf(COLOR_GREEN,  "[ RUN      ] ");

-  PrintTestName(test_case_name_.c_str(), test_info->name());

-  if (test_info->comment()[0] == '\0') {

-    printf("\n");

-  } else {

-    printf(", where %s\n", test_info->comment());

-  }

-  fflush(stdout);

-}

-

-void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo * test_info) {

-  if (test_info->result()->Passed()) {

-    ColoredPrintf(COLOR_GREEN, "[       OK ] ");

-  } else {

-    ColoredPrintf(COLOR_RED, "[  FAILED  ] ");

-  }

-  PrintTestName(test_case_name_.c_str(), test_info->name());

-  if (GTEST_FLAG(print_time)) {

-    printf(" (%s ms)\n", internal::StreamableToString(

-           test_info->result()->elapsed_time()).c_str());

-  } else {

-    printf("\n");

-  }

-  fflush(stdout);

-}

-

-// Called after an assertion failure.

-void PrettyUnitTestResultPrinter::OnNewTestPartResult(

-    const TestPartResult * result) {

-  // If the test part succeeded, we don't need to do anything.

-  if (result->type() == TPRT_SUCCESS)

-    return;

-

-  // Print failure message from the assertion (e.g. expected this and got that).

-  PrintTestPartResult(*result);

-  fflush(stdout);

-}

-

-void PrettyUnitTestResultPrinter::OnGlobalTearDownStart(const UnitTest*) {

-  ColoredPrintf(COLOR_GREEN,  "[----------] ");

-  printf("Global test environment tear-down\n");

-  fflush(stdout);

-}

-

-namespace internal {

-

-// Internal helper for printing the list of failed tests.

-static void PrintFailedTestsPretty(const UnitTestImpl* impl) {

-  const int failed_test_count = impl->failed_test_count();

-  if (failed_test_count == 0) {

-    return;

-  }

-

-  for (const internal::ListNode<TestCase*>* node = impl->test_cases()->Head();

-       node != NULL; node = node->next()) {

-    const TestCase* const tc = node->element();

-    if (!tc->should_run() || (tc->failed_test_count() == 0)) {

-      continue;

-    }

-    for (const internal::ListNode<TestInfo*>* tinode =

-         tc->test_info_list().Head();

-         tinode != NULL; tinode = tinode->next()) {

-      const TestInfo* const ti = tinode->element();

-      if (!tc->ShouldRunTest(ti) || tc->TestPassed(ti)) {

-        continue;

-      }

-      ColoredPrintf(COLOR_RED, "[  FAILED  ] ");

-      printf("%s.%s", ti->test_case_name(), ti->name());

-      if (ti->test_case_comment()[0] != '\0' ||

-          ti->comment()[0] != '\0') {

-        printf(", where %s", ti->test_case_comment());

-        if (ti->test_case_comment()[0] != '\0' &&

-            ti->comment()[0] != '\0') {

-          printf(" and ");

-        }

-      }

-      printf("%s\n", ti->comment());

-    }

-  }

-}

-

-}  // namespace internal

-

-void PrettyUnitTestResultPrinter::OnUnitTestEnd(

-    const UnitTest * unit_test) {

-  const internal::UnitTestImpl* const impl = unit_test->impl();

-

-  ColoredPrintf(COLOR_GREEN,  "[==========] ");

-  printf("%s from %s ran.",

-         FormatTestCount(impl->test_to_run_count()).c_str(),

-         FormatTestCaseCount(impl->test_case_to_run_count()).c_str());

-  if (GTEST_FLAG(print_time)) {

-    printf(" (%s ms total)",

-           internal::StreamableToString(impl->elapsed_time()).c_str());

-  }

-  printf("\n");

-  ColoredPrintf(COLOR_GREEN,  "[  PASSED  ] ");

-  printf("%s.\n", FormatTestCount(impl->successful_test_count()).c_str());

-

-  int num_failures = impl->failed_test_count();

-  if (!impl->Passed()) {

-    const int failed_test_count = impl->failed_test_count();

-    ColoredPrintf(COLOR_RED,  "[  FAILED  ] ");

-    printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());

-    internal::PrintFailedTestsPretty(impl);

-    printf("\n%2d FAILED %s\n", num_failures,

-                        num_failures == 1 ? "TEST" : "TESTS");

-  }

-

-  int num_disabled = impl->disabled_test_count();

-  if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {

-    if (!num_failures) {

-      printf("\n");  // Add a spacer if no FAILURE banner is displayed.

-    }

-    ColoredPrintf(COLOR_YELLOW,

-                  "  YOU HAVE %d DISABLED %s\n\n",

-                  num_disabled,

-                  num_disabled == 1 ? "TEST" : "TESTS");

-  }

-  // Ensure that Google Test output is printed before, e.g., heapchecker output.

-  fflush(stdout);

-}

-

-// End PrettyUnitTestResultPrinter

-

-// class UnitTestEventsRepeater

-//

-// This class forwards events to other event listeners.

-class UnitTestEventsRepeater : public UnitTestEventListenerInterface {

- public:

-  typedef internal::List<UnitTestEventListenerInterface *> Listeners;

-  typedef internal::ListNode<UnitTestEventListenerInterface *> ListenersNode;

-  UnitTestEventsRepeater() {}

-  virtual ~UnitTestEventsRepeater();

-  void AddListener(UnitTestEventListenerInterface *listener);

-

-  virtual void OnUnitTestStart(const UnitTest* unit_test);

-  virtual void OnUnitTestEnd(const UnitTest* unit_test);

-  virtual void OnGlobalSetUpStart(const UnitTest* unit_test);

-  virtual void OnGlobalSetUpEnd(const UnitTest* unit_test);

-  virtual void OnGlobalTearDownStart(const UnitTest* unit_test);

-  virtual void OnGlobalTearDownEnd(const UnitTest* unit_test);

-  virtual void OnTestCaseStart(const TestCase* test_case);

-  virtual void OnTestCaseEnd(const TestCase* test_case);

-  virtual void OnTestStart(const TestInfo* test_info);

-  virtual void OnTestEnd(const TestInfo* test_info);

-  virtual void OnNewTestPartResult(const TestPartResult* result);

-

- private:

-  Listeners listeners_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestEventsRepeater);

-};

-

-UnitTestEventsRepeater::~UnitTestEventsRepeater() {

-  for (ListenersNode* listener = listeners_.Head();

-       listener != NULL;

-       listener = listener->next()) {

-    delete listener->element();

-  }

-}

-

-void UnitTestEventsRepeater::AddListener(

-    UnitTestEventListenerInterface *listener) {

-  listeners_.PushBack(listener);

-}

-

-// Since the methods are identical, use a macro to reduce boilerplate.

-// This defines a member that repeats the call to all listeners.

-#define GTEST_REPEATER_METHOD_(Name, Type) \

-void UnitTestEventsRepeater::Name(const Type* parameter) { \

-  for (ListenersNode* listener = listeners_.Head(); \

-       listener != NULL; \

-       listener = listener->next()) { \

-    listener->element()->Name(parameter); \

-  } \

-}

-

-GTEST_REPEATER_METHOD_(OnUnitTestStart, UnitTest)

-GTEST_REPEATER_METHOD_(OnUnitTestEnd, UnitTest)

-GTEST_REPEATER_METHOD_(OnGlobalSetUpStart, UnitTest)

-GTEST_REPEATER_METHOD_(OnGlobalSetUpEnd, UnitTest)

-GTEST_REPEATER_METHOD_(OnGlobalTearDownStart, UnitTest)

-GTEST_REPEATER_METHOD_(OnGlobalTearDownEnd, UnitTest)

-GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)

-GTEST_REPEATER_METHOD_(OnTestCaseEnd, TestCase)

-GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)

-GTEST_REPEATER_METHOD_(OnTestEnd, TestInfo)

-GTEST_REPEATER_METHOD_(OnNewTestPartResult, TestPartResult)

-

-#undef GTEST_REPEATER_METHOD_

-

-// End PrettyUnitTestResultPrinter

-

-// This class generates an XML output file.

-class XmlUnitTestResultPrinter : public UnitTestEventListenerInterface {

- public:

-  explicit XmlUnitTestResultPrinter(const char* output_file);

-

-  virtual void OnUnitTestEnd(const UnitTest* unit_test);

-

- private:

-  // Is c a whitespace character that is normalized to a space character

-  // when it appears in an XML attribute value?

-  static bool IsNormalizableWhitespace(char c) {

-    return c == 0x9 || c == 0xA || c == 0xD;

-  }

-

-  // May c appear in a well-formed XML document?

-  static bool IsValidXmlCharacter(char c) {

-    return IsNormalizableWhitespace(c) || c >= 0x20;

-  }

-

-  // Returns an XML-escaped copy of the input string str.  If

-  // is_attribute is true, the text is meant to appear as an attribute

-  // value, and normalizable whitespace is preserved by replacing it

-  // with character references.

-  static internal::String EscapeXml(const char* str,

-                                    bool is_attribute);

-

-  // Convenience wrapper around EscapeXml when str is an attribute value.

-  static internal::String EscapeXmlAttribute(const char* str) {

-    return EscapeXml(str, true);

-  }

-

-  // Convenience wrapper around EscapeXml when str is not an attribute value.

-  static internal::String EscapeXmlText(const char* str) {

-    return EscapeXml(str, false);

-  }

-

-  // Prints an XML representation of a TestInfo object.

-  static void PrintXmlTestInfo(FILE* out,

-                               const char* test_case_name,

-                               const TestInfo* test_info);

-

-  // Prints an XML representation of a TestCase object

-  static void PrintXmlTestCase(FILE* out, const TestCase* test_case);

-

-  // Prints an XML summary of unit_test to output stream out.

-  static void PrintXmlUnitTest(FILE* out, const UnitTest* unit_test);

-

-  // Produces a string representing the test properties in a result as space

-  // delimited XML attributes based on the property key="value" pairs.

-  // When the String is not empty, it includes a space at the beginning,

-  // to delimit this attribute from prior attributes.

-  static internal::String TestPropertiesAsXmlAttributes(

-      const internal::TestResult* result);

-

-  // The output file.

-  const internal::String output_file_;

-

-  GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);

-};

-

-// Creates a new XmlUnitTestResultPrinter.

-XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)

-    : output_file_(output_file) {

-  if (output_file_.c_str() == NULL || output_file_.empty()) {

-    fprintf(stderr, "XML output file may not be null\n");

-    fflush(stderr);

-    exit(EXIT_FAILURE);

-  }

-}

-

-// Called after the unit test ends.

-void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest* unit_test) {

-  FILE* xmlout = NULL;

-  internal::FilePath output_file(output_file_);

-  internal::FilePath output_dir(output_file.RemoveFileName());

-

-  if (output_dir.CreateDirectoriesRecursively()) {

-    xmlout = internal::posix::FOpen(output_file_.c_str(), "w");

-  }

-  if (xmlout == NULL) {

-    // TODO(wan): report the reason of the failure.

-    //

-    // We don't do it for now as:

-    //

-    //   1. There is no urgent need for it.

-    //   2. It's a bit involved to make the errno variable thread-safe on

-    //      all three operating systems (Linux, Windows, and Mac OS).

-    //   3. To interpret the meaning of errno in a thread-safe way,

-    //      we need the strerror_r() function, which is not available on

-    //      Windows.

-    fprintf(stderr,

-            "Unable to open file \"%s\"\n",

-            output_file_.c_str());

-    fflush(stderr);

-    exit(EXIT_FAILURE);

-  }

-  PrintXmlUnitTest(xmlout, unit_test);

-  fclose(xmlout);

-}

-

-// Returns an XML-escaped copy of the input string str.  If is_attribute

-// is true, the text is meant to appear as an attribute value, and

-// normalizable whitespace is preserved by replacing it with character

-// references.

-//

-// Invalid XML characters in str, if any, are stripped from the output.

-// It is expected that most, if not all, of the text processed by this

-// module will consist of ordinary English text.

-// If this module is ever modified to produce version 1.1 XML output,

-// most invalid characters can be retained using character references.

-// TODO(wan): It might be nice to have a minimally invasive, human-readable

-// escaping scheme for invalid characters, rather than dropping them.

-internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str,

-                                                     bool is_attribute) {

-  Message m;

-

-  if (str != NULL) {

-    for (const char* src = str; *src; ++src) {

-      switch (*src) {

-        case '<':

-          m << "&lt;";

-          break;

-        case '>':

-          m << "&gt;";

-          break;

-        case '&':

-          m << "&amp;";

-          break;

-        case '\'':

-          if (is_attribute)

-            m << "&apos;";

-          else

-            m << '\'';

-          break;

-        case '"':

-          if (is_attribute)

-            m << "&quot;";

-          else

-            m << '"';

-          break;

-        default:

-          if (IsValidXmlCharacter(*src)) {

-            if (is_attribute && IsNormalizableWhitespace(*src))

-              m << internal::String::Format("&#x%02X;", unsigned(*src));

-            else

-              m << *src;

-          }

-          break;

-      }

-    }

-  }

-

-  return m.GetString();

-}

-

-

-// The following routines generate an XML representation of a UnitTest

-// object.

-//

-// This is how Google Test concepts map to the DTD:

-//

-// <testsuites name="AllTests">        <-- corresponds to a UnitTest object

-//   <testsuite name="testcase-name">  <-- corresponds to a TestCase object

-//     <testcase name="test-name">     <-- corresponds to a TestInfo object

-//       <failure message="...">...</failure>

-//       <failure message="...">...</failure>

-//       <failure message="...">...</failure>

-//                                     <-- individual assertion failures

-//     </testcase>

-//   </testsuite>

-// </testsuites>

-

-namespace internal {

-

-// Formats the given time in milliseconds as seconds.  The returned

-// C-string is owned by this function and cannot be released by the

-// caller.  Calling the function again invalidates the previous

-// result.

-const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) {

-  static String str;

-  str = (Message() << (ms/1000.0)).GetString();

-  return str.c_str();

-}

-

-}  // namespace internal

-

-// Prints an XML representation of a TestInfo object.

-// TODO(wan): There is also value in printing properties with the plain printer.

-void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out,

-                                                const char* test_case_name,

-                                                const TestInfo* test_info) {

-  const internal::TestResult * const result = test_info->result();

-  const internal::List<TestPartResult> &results = result->test_part_results();

-  fprintf(out,

-          "    <testcase name=\"%s\" status=\"%s\" time=\"%s\" "

-          "classname=\"%s\"%s",

-          EscapeXmlAttribute(test_info->name()).c_str(),

-          test_info->should_run() ? "run" : "notrun",

-          internal::FormatTimeInMillisAsSeconds(result->elapsed_time()),

-          EscapeXmlAttribute(test_case_name).c_str(),

-          TestPropertiesAsXmlAttributes(result).c_str());

-

-  int failures = 0;

-  for (const internal::ListNode<TestPartResult>* part_node = results.Head();

-       part_node != NULL;

-       part_node = part_node->next()) {

-    const TestPartResult& part = part_node->element();

-    if (part.failed()) {

-      const internal::String message =

-          internal::String::Format("%s:%d\n%s", part.file_name(),

-                                   part.line_number(), part.message());

-      if (++failures == 1)

-        fprintf(out, ">\n");

-      fprintf(out,

-              "      <failure message=\"%s\" type=\"\"><![CDATA[%s]]>"

-              "</failure>\n",

-              EscapeXmlAttribute(part.summary()).c_str(), message.c_str());

-    }

-  }

-

-  if (failures == 0)

-    fprintf(out, " />\n");

-  else

-    fprintf(out, "    </testcase>\n");

-}

-

-// Prints an XML representation of a TestCase object

-void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out,

-                                                const TestCase* test_case) {

-  fprintf(out,

-          "  <testsuite name=\"%s\" tests=\"%d\" failures=\"%d\" "

-          "disabled=\"%d\" ",

-          EscapeXmlAttribute(test_case->name()).c_str(),

-          test_case->total_test_count(),

-          test_case->failed_test_count(),

-          test_case->disabled_test_count());

-  fprintf(out,

-          "errors=\"0\" time=\"%s\">\n",

-          internal::FormatTimeInMillisAsSeconds(test_case->elapsed_time()));

-  for (const internal::ListNode<TestInfo*>* info_node =

-         test_case->test_info_list().Head();

-       info_node != NULL;

-       info_node = info_node->next()) {

-    PrintXmlTestInfo(out, test_case->name(), info_node->element());

-  }

-  fprintf(out, "  </testsuite>\n");

-}

-

-// Prints an XML summary of unit_test to output stream out.

-void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,

-                                                const UnitTest* unit_test) {

-  const internal::UnitTestImpl* const impl = unit_test->impl();

-  fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");

-  fprintf(out,

-          "<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" "

-          "errors=\"0\" time=\"%s\" ",

-          impl->total_test_count(),

-          impl->failed_test_count(),

-          impl->disabled_test_count(),

-          internal::FormatTimeInMillisAsSeconds(impl->elapsed_time()));

-  fprintf(out, "name=\"AllTests\">\n");

-  for (const internal::ListNode<TestCase*>* case_node =

-       impl->test_cases()->Head();

-       case_node != NULL;

-       case_node = case_node->next()) {

-    PrintXmlTestCase(out, case_node->element());

-  }

-  fprintf(out, "</testsuites>\n");

-}

-

-// Produces a string representing the test properties in a result as space

-// delimited XML attributes based on the property key="value" pairs.

-internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(

-    const internal::TestResult* result) {

-  using internal::TestProperty;

-  Message attributes;

-  const internal::List<TestProperty>& properties = result->test_properties();

-  for (const internal::ListNode<TestProperty>* property_node =

-       properties.Head();

-       property_node != NULL;

-       property_node = property_node->next()) {

-    const TestProperty& property = property_node->element();

-    attributes << " " << property.key() << "="

-        << "\"" << EscapeXmlAttribute(property.value()) << "\"";

-  }

-  return attributes.GetString();

-}

-

-// End XmlUnitTestResultPrinter

-

-namespace internal {

-

-// Class ScopedTrace

-

-// Pushes the given source file location and message onto a per-thread

-// trace stack maintained by Google Test.

-// L < UnitTest::mutex_

-ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) {

-  TraceInfo trace;

-  trace.file = file;

-  trace.line = line;

-  trace.message = message.GetString();

-

-  UnitTest::GetInstance()->PushGTestTrace(trace);

-}

-

-// Pops the info pushed by the c'tor.

-// L < UnitTest::mutex_

-ScopedTrace::~ScopedTrace() {

-  UnitTest::GetInstance()->PopGTestTrace();

-}

-

-

-// class OsStackTraceGetter

-

-// Returns the current OS stack trace as a String.  Parameters:

-//

-//   max_depth  - the maximum number of stack frames to be included

-//                in the trace.

-//   skip_count - the number of top frames to be skipped; doesn't count

-//                against max_depth.

-//

-// L < mutex_

-// We use "L < mutex_" to denote that the function may acquire mutex_.

-String OsStackTraceGetter::CurrentStackTrace(int, int) {

-  return String("");

-}

-

-// L < mutex_

-void OsStackTraceGetter::UponLeavingGTest() {

-}

-

-const char* const

-OsStackTraceGetter::kElidedFramesMarker =

-    "... " GTEST_NAME_ " internal frames ...";

-

-}  // namespace internal

-

-// class UnitTest

-

-// Gets the singleton UnitTest object.  The first time this method is

-// called, a UnitTest object is constructed and returned.  Consecutive

-// calls will return the same object.

-//

-// We don't protect this under mutex_ as a user is not supposed to

-// call this before main() starts, from which point on the return

-// value will never change.

-UnitTest * UnitTest::GetInstance() {

-  // When compiled with MSVC 7.1 in optimized mode, destroying the

-  // UnitTest object upon exiting the program messes up the exit code,

-  // causing successful tests to appear failed.  We have to use a

-  // different implementation in this case to bypass the compiler bug.

-  // This implementation makes the compiler happy, at the cost of

-  // leaking the UnitTest object.

-

-  // CodeGear C++Builder insists on a public destructor for the

-  // default implementation.  Use this implementation to keep good OO

-  // design with private destructor.

-

-#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)

-  static UnitTest* const instance = new UnitTest;

-  return instance;

-#else

-  static UnitTest instance;

-  return &instance;

-#endif  // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)

-}

-

-// Registers and returns a global test environment.  When a test

-// program is run, all global test environments will be set-up in the

-// order they were registered.  After all tests in the program have

-// finished, all global test environments will be torn-down in the

-// *reverse* order they were registered.

-//

-// The UnitTest object takes ownership of the given environment.

-//

-// We don't protect this under mutex_, as we only support calling it

-// from the main thread.

-Environment* UnitTest::AddEnvironment(Environment* env) {

-  if (env == NULL) {

-    return NULL;

-  }

-

-  impl_->environments()->PushBack(env);

-  impl_->environments_in_reverse_order()->PushFront(env);

-  return env;

-}

-

-#if GTEST_HAS_EXCEPTIONS

-// A failed Google Test assertion will throw an exception of this type

-// when exceptions are enabled.  We derive it from std::runtime_error,

-// which is for errors presumably detectable only at run time.  Since

-// std::runtime_error inherits from std::exception, many testing

-// frameworks know how to extract and print the message inside it.

-class GoogleTestFailureException : public ::std::runtime_error {

- public:

-  explicit GoogleTestFailureException(const TestPartResult& failure)

-      : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}

-};

-#endif

-

-// Adds a TestPartResult to the current TestResult object.  All Google Test

-// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call

-// this to report their results.  The user code should use the

-// assertion macros instead of calling this directly.

-// L < mutex_

-void UnitTest::AddTestPartResult(TestPartResultType result_type,

-                                 const char* file_name,

-                                 int line_number,

-                                 const internal::String& message,

-                                 const internal::String& os_stack_trace) {

-  Message msg;

-  msg << message;

-

-  internal::MutexLock lock(&mutex_);

-  if (impl_->gtest_trace_stack()->size() > 0) {

-    msg << "\n" << GTEST_NAME_ << " trace:";

-

-    for (internal::ListNode<internal::TraceInfo>* node =

-         impl_->gtest_trace_stack()->Head();

-         node != NULL;

-         node = node->next()) {

-      const internal::TraceInfo& trace = node->element();

-      msg << "\n" << trace.file << ":" << trace.line << ": " << trace.message;

-    }

-  }

-

-  if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {

-    msg << internal::kStackTraceMarker << os_stack_trace;

-  }

-

-  const TestPartResult result =

-    TestPartResult(result_type, file_name, line_number,

-                   msg.GetString().c_str());

-  impl_->GetTestPartResultReporterForCurrentThread()->

-      ReportTestPartResult(result);

-

-  if (result_type != TPRT_SUCCESS) {

-    // gtest_break_on_failure takes precedence over

-    // gtest_throw_on_failure.  This allows a user to set the latter

-    // in the code (perhaps in order to use Google Test assertions

-    // with another testing framework) and specify the former on the

-    // command line for debugging.

-    if (GTEST_FLAG(break_on_failure)) {

-#if GTEST_OS_WINDOWS

-      // Using DebugBreak on Windows allows gtest to still break into a debugger

-      // when a failure happens and both the --gtest_break_on_failure and

-      // the --gtest_catch_exceptions flags are specified.

-      DebugBreak();

-#else

-      *static_cast<int*>(NULL) = 1;

-#endif  // GTEST_OS_WINDOWS

-    } else if (GTEST_FLAG(throw_on_failure)) {

-#if GTEST_HAS_EXCEPTIONS

-      throw GoogleTestFailureException(result);

-#else

-      // We cannot call abort() as it generates a pop-up in debug mode

-      // that cannot be suppressed in VC 7.1 or below.

-      exit(1);

-#endif

-    }

-  }

-}

-

-// Creates and adds a property to the current TestResult. If a property matching

-// the supplied value already exists, updates its value instead.

-void UnitTest::RecordPropertyForCurrentTest(const char* key,

-                                            const char* value) {

-  const internal::TestProperty test_property(key, value);

-  impl_->current_test_result()->RecordProperty(test_property);

-}

-

-// Runs all tests in this UnitTest object and prints the result.

-// Returns 0 if successful, or 1 otherwise.

-//

-// We don't protect this under mutex_, as we only support calling it

-// from the main thread.

-int UnitTest::Run() {

-#if GTEST_HAS_SEH

-  // Catch SEH-style exceptions.

-

-  const bool in_death_test_child_process =

-      internal::GTEST_FLAG(internal_run_death_test).GetLength() > 0;

-

-  // Either the user wants Google Test to catch exceptions thrown by the

-  // tests or this is executing in the context of death test child

-  // process. In either case the user does not want to see pop-up dialogs

-  // about crashes - they are expected..

-  if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) {

-#if !defined(_WIN32_WCE)

-    // SetErrorMode doesn't exist on CE.

-    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |

-                 SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);

-#endif  // _WIN32_WCE

-

-#if defined(_MSC_VER) || defined(__MINGW32__)

-    // Death test children can be terminated with _abort().  On Windows,

-    // _abort() can show a dialog with a warning message.  This forces the

-    // abort message to go to stderr instead.

-    _set_error_mode(_OUT_TO_STDERR);

-#endif

-

-#if _MSC_VER >= 1400

-    // In the debug version, Visual Studio pops up a separate dialog

-    // offering a choice to debug the aborted program. We need to suppress

-    // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement

-    // executed. Google Test will notify the user of any unexpected

-    // failure via stderr.

-    //

-    // VC++ doesn't define _set_abort_behavior() prior to the version 8.0.

-    // Users of prior VC versions shall suffer the agony and pain of

-    // clicking through the countless debug dialogs.

-    // TODO(vladl@google.com): find a way to suppress the abort dialog() in the

-    // debug mode when compiled with VC 7.1 or lower.

-    if (!GTEST_FLAG(break_on_failure))

-      _set_abort_behavior(

-          0x0,                                    // Clear the following flags:

-          _WRITE_ABORT_MSG | _CALL_REPORTFAULT);  // pop-up window, core dump.

-#endif  // _MSC_VER >= 1400

-  }

-

-  __try {

-    return impl_->RunAllTests();

-  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(

-      GetExceptionCode())) {

-    printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode());

-    fflush(stdout);

-    return 1;

-  }

-

-#else  // We are on a compiler or platform that doesn't support SEH.

-

-  return impl_->RunAllTests();

-#endif  // GTEST_HAS_SEH

-}

-

-// Returns the working directory when the first TEST() or TEST_F() was

-// executed.

-const char* UnitTest::original_working_dir() const {

-  return impl_->original_working_dir_.c_str();

-}

-

-// Returns the TestCase object for the test that's currently running,

-// or NULL if no test is running.

-// L < mutex_

-const TestCase* UnitTest::current_test_case() const {

-  internal::MutexLock lock(&mutex_);

-  return impl_->current_test_case();

-}

-

-// Returns the TestInfo object for the test that's currently running,

-// or NULL if no test is running.

-// L < mutex_

-const TestInfo* UnitTest::current_test_info() const {

-  internal::MutexLock lock(&mutex_);

-  return impl_->current_test_info();

-}

-

-#if GTEST_HAS_PARAM_TEST

-// Returns ParameterizedTestCaseRegistry object used to keep track of

-// value-parameterized tests and instantiate and register them.

-// L < mutex_

-internal::ParameterizedTestCaseRegistry&

-    UnitTest::parameterized_test_registry() {

-  return impl_->parameterized_test_registry();

-}

-#endif  // GTEST_HAS_PARAM_TEST

-

-// Creates an empty UnitTest.

-UnitTest::UnitTest() {

-  impl_ = new internal::UnitTestImpl(this);

-}

-

-// Destructor of UnitTest.

-UnitTest::~UnitTest() {

-  delete impl_;

-}

-

-// Pushes a trace defined by SCOPED_TRACE() on to the per-thread

-// Google Test trace stack.

-// L < mutex_

-void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) {

-  internal::MutexLock lock(&mutex_);

-  impl_->gtest_trace_stack()->PushFront(trace);

-}

-

-// Pops a trace from the per-thread Google Test trace stack.

-// L < mutex_

-void UnitTest::PopGTestTrace() {

-  internal::MutexLock lock(&mutex_);

-  impl_->gtest_trace_stack()->PopFront(NULL);

-}

-

-namespace internal {

-

-UnitTestImpl::UnitTestImpl(UnitTest* parent)

-    : parent_(parent),

-#ifdef _MSC_VER

-#pragma warning(push)                    // Saves the current warning state.

-#pragma warning(disable:4355)            // Temporarily disables warning 4355

-                                         // (using this in initializer).

-      default_global_test_part_result_reporter_(this),

-      default_per_thread_test_part_result_reporter_(this),

-#pragma warning(pop)                     // Restores the warning state again.

-#else

-      default_global_test_part_result_reporter_(this),

-      default_per_thread_test_part_result_reporter_(this),

-#endif  // _MSC_VER

-      global_test_part_result_repoter_(

-          &default_global_test_part_result_reporter_),

-      per_thread_test_part_result_reporter_(

-          &default_per_thread_test_part_result_reporter_),

-      test_cases_(),

-#if GTEST_HAS_PARAM_TEST

-      parameterized_test_registry_(),

-      parameterized_tests_registered_(false),

-#endif  // GTEST_HAS_PARAM_TEST

-      last_death_test_case_(NULL),

-      current_test_case_(NULL),

-      current_test_info_(NULL),

-      ad_hoc_test_result_(),

-      result_printer_(NULL),

-      os_stack_trace_getter_(NULL),

-#if GTEST_HAS_DEATH_TEST

-      elapsed_time_(0),

-      internal_run_death_test_flag_(NULL),

-      death_test_factory_(new DefaultDeathTestFactory) {

-#else

-      elapsed_time_(0) {

-#endif  // GTEST_HAS_DEATH_TEST

-}

-

-UnitTestImpl::~UnitTestImpl() {

-  // Deletes every TestCase.

-  test_cases_.ForEach(internal::Delete<TestCase>);

-

-  // Deletes every Environment.

-  environments_.ForEach(internal::Delete<Environment>);

-

-  // Deletes the current test result printer.

-  delete result_printer_;

-

-  delete os_stack_trace_getter_;

-}

-

-// A predicate that checks the name of a TestCase against a known

-// value.

-//

-// This is used for implementation of the UnitTest class only.  We put

-// it in the anonymous namespace to prevent polluting the outer

-// namespace.

-//

-// TestCaseNameIs is copyable.

-class TestCaseNameIs {

- public:

-  // Constructor.

-  explicit TestCaseNameIs(const String& name)

-      : name_(name) {}

-

-  // Returns true iff the name of test_case matches name_.

-  bool operator()(const TestCase* test_case) const {

-    return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;

-  }

-

- private:

-  String name_;

-};

-

-// Finds and returns a TestCase with the given name.  If one doesn't

-// exist, creates one and returns it.

-//

-// Arguments:

-//

-//   test_case_name: name of the test case

-//   set_up_tc:      pointer to the function that sets up the test case

-//   tear_down_tc:   pointer to the function that tears down the test case

-TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,

-                                    const char* comment,

-                                    Test::SetUpTestCaseFunc set_up_tc,

-                                    Test::TearDownTestCaseFunc tear_down_tc) {

-  // Can we find a TestCase with the given name?

-  internal::ListNode<TestCase*>* node = test_cases_.FindIf(

-      TestCaseNameIs(test_case_name));

-

-  if (node == NULL) {

-    // No.  Let's create one.

-    TestCase* const test_case =

-      new TestCase(test_case_name, comment, set_up_tc, tear_down_tc);

-

-    // Is this a death test case?

-    if (internal::UnitTestOptions::MatchesFilter(String(test_case_name),

-                                                 kDeathTestCaseFilter)) {

-      // Yes.  Inserts the test case after the last death test case

-      // defined so far.

-      node = test_cases_.InsertAfter(last_death_test_case_, test_case);

-      last_death_test_case_ = node;

-    } else {

-      // No.  Appends to the end of the list.

-      test_cases_.PushBack(test_case);

-      node = test_cases_.Last();

-    }

-  }

-

-  // Returns the TestCase found.

-  return node->element();

-}

-

-// Helpers for setting up / tearing down the given environment.  They

-// are for use in the List::ForEach() method.

-static void SetUpEnvironment(Environment* env) { env->SetUp(); }

-static void TearDownEnvironment(Environment* env) { env->TearDown(); }

-

-// Runs all tests in this UnitTest object, prints the result, and

-// returns 0 if all tests are successful, or 1 otherwise.  If any

-// exception is thrown during a test on Windows, this test is

-// considered to be failed, but the rest of the tests will still be

-// run.  (We disable exceptions on Linux and Mac OS X, so the issue

-// doesn't apply there.)

-// When parameterized tests are enabled, it explands and registers

-// parameterized tests first in RegisterParameterizedTests().

-// All other functions called from RunAllTests() may safely assume that

-// parameterized tests are ready to be counted and run.

-int UnitTestImpl::RunAllTests() {

-  // Makes sure InitGoogleTest() was called.

-  if (!GTestIsInitialized()) {

-    printf("%s",

-           "\nThis test program did NOT call ::testing::InitGoogleTest "

-           "before calling RUN_ALL_TESTS().  Please fix it.\n");

-    return 1;

-  }

-

-  // Do not run any test if the --help flag was specified.

-  if (g_help_flag)

-    return 0;

-

-  RegisterParameterizedTests();

-

-  // Even if sharding is not on, test runners may want to use the

-  // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding

-  // protocol.

-  internal::WriteToShardStatusFileIfNeeded();

-

-  // True iff we are in a subprocess for running a thread-safe-style

-  // death test.

-  bool in_subprocess_for_death_test = false;

-

-#if GTEST_HAS_DEATH_TEST

-  internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());

-  in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);

-#endif  // GTEST_HAS_DEATH_TEST

-

-  UnitTestEventListenerInterface * const printer = result_printer();

-

-  const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,

-                                        in_subprocess_for_death_test);

-

-  // Compares the full test names with the filter to decide which

-  // tests to run.

-  const bool has_tests_to_run = FilterTests(should_shard

-                                              ? HONOR_SHARDING_PROTOCOL

-                                              : IGNORE_SHARDING_PROTOCOL) > 0;

-

-  // List the tests and exit if the --gtest_list_tests flag was specified.

-  if (GTEST_FLAG(list_tests)) {

-    // This must be called *after* FilterTests() has been called.

-    ListTestsMatchingFilter();

-    return 0;

-  }

-

-  // True iff at least one test has failed.

-  bool failed = false;

-

-  // How many times to repeat the tests?  We don't want to repeat them

-  // when we are inside the subprocess of a death test.

-  const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);

-  // Repeats forever if the repeat count is negative.

-  const bool forever = repeat < 0;

-  for (int i = 0; forever || i != repeat; i++) {

-    if (repeat != 1) {

-      printf("\nRepeating all tests (iteration %d) . . .\n\n", i + 1);

-    }

-

-    // Tells the unit test event listener that the tests are about to

-    // start.

-    printer->OnUnitTestStart(parent_);

-

-    const TimeInMillis start = GetTimeInMillis();

-

-    // Runs each test case if there is at least one test to run.

-    if (has_tests_to_run) {

-      // Sets up all environments beforehand.

-      printer->OnGlobalSetUpStart(parent_);

-      environments_.ForEach(SetUpEnvironment);

-      printer->OnGlobalSetUpEnd(parent_);

-

-      // Runs the tests only if there was no fatal failure during global

-      // set-up.

-      if (!Test::HasFatalFailure()) {

-        test_cases_.ForEach(TestCase::RunTestCase);

-      }

-

-      // Tears down all environments in reverse order afterwards.

-      printer->OnGlobalTearDownStart(parent_);

-      environments_in_reverse_order_.ForEach(TearDownEnvironment);

-      printer->OnGlobalTearDownEnd(parent_);

-    }

-

-    elapsed_time_ = GetTimeInMillis() - start;

-

-    // Tells the unit test event listener that the tests have just

-    // finished.

-    printer->OnUnitTestEnd(parent_);

-

-    // Gets the result and clears it.

-    if (!Passed()) {

-      failed = true;

-    }

-    ClearResult();

-  }

-

-  // Returns 0 if all tests passed, or 1 other wise.

-  return failed ? 1 : 0;

-}

-

-// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file

-// if the variable is present. If a file already exists at this location, this

-// function will write over it. If the variable is present, but the file cannot

-// be created, prints an error and exits.

-void WriteToShardStatusFileIfNeeded() {

-  const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);

-  if (test_shard_file != NULL) {

-    FILE* const file = posix::FOpen(test_shard_file, "w");

-    if (file == NULL) {

-      ColoredPrintf(COLOR_RED,

-                    "Could not write to the test shard status file \"%s\" "

-                    "specified by the %s environment variable.\n",

-                    test_shard_file, kTestShardStatusFile);

-      fflush(stdout);

-      exit(EXIT_FAILURE);

-    }

-    fclose(file);

-  }

-}

-

-// Checks whether sharding is enabled by examining the relevant

-// environment variable values. If the variables are present,

-// but inconsistent (i.e., shard_index >= total_shards), prints

-// an error and exits. If in_subprocess_for_death_test, sharding is

-// disabled because it must only be applied to the original test

-// process. Otherwise, we could filter out death tests we intended to execute.

-bool ShouldShard(const char* total_shards_env,

-                 const char* shard_index_env,

-                 bool in_subprocess_for_death_test) {

-  if (in_subprocess_for_death_test) {

-    return false;

-  }

-

-  const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1);

-  const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1);

-

-  if (total_shards == -1 && shard_index == -1) {

-    return false;

-  } else if (total_shards == -1 && shard_index != -1) {

-    const Message msg = Message()

-      << "Invalid environment variables: you have "

-      << kTestShardIndex << " = " << shard_index

-      << ", but have left " << kTestTotalShards << " unset.\n";

-    ColoredPrintf(COLOR_RED, msg.GetString().c_str());

-    fflush(stdout);

-    exit(EXIT_FAILURE);

-  } else if (total_shards != -1 && shard_index == -1) {

-    const Message msg = Message()

-      << "Invalid environment variables: you have "

-      << kTestTotalShards << " = " << total_shards

-      << ", but have left " << kTestShardIndex << " unset.\n";

-    ColoredPrintf(COLOR_RED, msg.GetString().c_str());

-    fflush(stdout);

-    exit(EXIT_FAILURE);

-  } else if (shard_index < 0 || shard_index >= total_shards) {

-    const Message msg = Message()

-      << "Invalid environment variables: we require 0 <= "

-      << kTestShardIndex << " < " << kTestTotalShards

-      << ", but you have " << kTestShardIndex << "=" << shard_index

-      << ", " << kTestTotalShards << "=" << total_shards << ".\n";

-    ColoredPrintf(COLOR_RED, msg.GetString().c_str());

-    fflush(stdout);

-    exit(EXIT_FAILURE);

-  }

-

-  return total_shards > 1;

-}

-

-// Parses the environment variable var as an Int32. If it is unset,

-// returns default_val. If it is not an Int32, prints an error

-// and aborts.

-Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) {

-  const char* str_val = posix::GetEnv(var);

-  if (str_val == NULL) {

-    return default_val;

-  }

-

-  Int32 result;

-  if (!ParseInt32(Message() << "The value of environment variable " << var,

-                  str_val, &result)) {

-    exit(EXIT_FAILURE);

-  }

-  return result;

-}

-

-// Given the total number of shards, the shard index, and the test id,

-// returns true iff the test should be run on this shard. The test id is

-// some arbitrary but unique non-negative integer assigned to each test

-// method. Assumes that 0 <= shard_index < total_shards.

-bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {

-  return (test_id % total_shards) == shard_index;

-}

-

-// Compares the name of each test with the user-specified filter to

-// decide whether the test should be run, then records the result in

-// each TestCase and TestInfo object.

-// If shard_tests == true, further filters tests based on sharding

-// variables in the environment - see

-// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide.

-// Returns the number of tests that should run.

-int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {

-  const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?

-      Int32FromEnvOrDie(kTestTotalShards, -1) : -1;

-  const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?

-      Int32FromEnvOrDie(kTestShardIndex, -1) : -1;

-

-  // num_runnable_tests are the number of tests that will

-  // run across all shards (i.e., match filter and are not disabled).

-  // num_selected_tests are the number of tests to be run on

-  // this shard.

-  int num_runnable_tests = 0;

-  int num_selected_tests = 0;

-  for (const internal::ListNode<TestCase *> *test_case_node =

-           test_cases_.Head();

-       test_case_node != NULL;

-       test_case_node = test_case_node->next()) {

-    TestCase * const test_case = test_case_node->element();

-    const String &test_case_name = test_case->name();

-    test_case->set_should_run(false);

-

-    for (const internal::ListNode<TestInfo *> *test_info_node =

-             test_case->test_info_list().Head();

-         test_info_node != NULL;

-         test_info_node = test_info_node->next()) {

-      TestInfo * const test_info = test_info_node->element();

-      const String test_name(test_info->name());

-      // A test is disabled if test case name or test name matches

-      // kDisableTestFilter.

-      const bool is_disabled =

-          internal::UnitTestOptions::MatchesFilter(test_case_name,

-                                                   kDisableTestFilter) ||

-          internal::UnitTestOptions::MatchesFilter(test_name,

-                                                   kDisableTestFilter);

-      test_info->impl()->set_is_disabled(is_disabled);

-

-      const bool matches_filter =

-          internal::UnitTestOptions::FilterMatchesTest(test_case_name,

-                                                       test_name);

-      test_info->impl()->set_matches_filter(matches_filter);

-

-      const bool is_runnable =

-          (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&

-          matches_filter;

-

-      const bool is_selected = is_runnable &&

-          (shard_tests == IGNORE_SHARDING_PROTOCOL ||

-           ShouldRunTestOnShard(total_shards, shard_index,

-                                num_runnable_tests));

-

-      num_runnable_tests += is_runnable;

-      num_selected_tests += is_selected;

-

-      test_info->impl()->set_should_run(is_selected);

-      test_case->set_should_run(test_case->should_run() || is_selected);

-    }

-  }

-  return num_selected_tests;

-}

-

-// Prints the names of the tests matching the user-specified filter flag.

-void UnitTestImpl::ListTestsMatchingFilter() {

-  for (const internal::ListNode<TestCase*>* test_case_node = test_cases_.Head();

-       test_case_node != NULL;

-       test_case_node = test_case_node->next()) {

-    const TestCase* const test_case = test_case_node->element();

-    bool printed_test_case_name = false;

-

-    for (const internal::ListNode<TestInfo*>* test_info_node =

-         test_case->test_info_list().Head();

-         test_info_node != NULL;

-         test_info_node = test_info_node->next()) {

-      const TestInfo* const test_info = test_info_node->element();

-      if (test_info->matches_filter()) {

-        if (!printed_test_case_name) {

-          printed_test_case_name = true;

-          printf("%s.\n", test_case->name());

-        }

-        printf("  %s\n", test_info->name());

-      }

-    }

-  }

-  fflush(stdout);

-}

-

-// Sets the unit test result printer.

-//

-// Does nothing if the input and the current printer object are the

-// same; otherwise, deletes the old printer object and makes the

-// input the current printer.

-void UnitTestImpl::set_result_printer(

-    UnitTestEventListenerInterface* result_printer) {

-  if (result_printer_ != result_printer) {

-    delete result_printer_;

-    result_printer_ = result_printer;

-  }

-}

-

-// Returns the current unit test result printer if it is not NULL;

-// otherwise, creates an appropriate result printer, makes it the

-// current printer, and returns it.

-UnitTestEventListenerInterface* UnitTestImpl::result_printer() {

-  if (result_printer_ != NULL) {

-    return result_printer_;

-  }

-

-#if GTEST_HAS_DEATH_TEST

-  if (internal_run_death_test_flag_.get() != NULL) {

-    result_printer_ = new NullUnitTestResultPrinter;

-    return result_printer_;

-  }

-#endif  // GTEST_HAS_DEATH_TEST

-

-  UnitTestEventsRepeater *repeater = new UnitTestEventsRepeater;

-  const String& output_format = internal::UnitTestOptions::GetOutputFormat();

-  if (output_format == "xml") {

-    repeater->AddListener(new XmlUnitTestResultPrinter(

-        internal::UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));

-  } else if (output_format != "") {

-      printf("WARNING: unrecognized output format \"%s\" ignored.\n",

-             output_format.c_str());

-      fflush(stdout);

-  }

-  repeater->AddListener(new PrettyUnitTestResultPrinter);

-  result_printer_ = repeater;

-  return result_printer_;

-}

-

-// Sets the OS stack trace getter.

-//

-// Does nothing if the input and the current OS stack trace getter are

-// the same; otherwise, deletes the old getter and makes the input the

-// current getter.

-void UnitTestImpl::set_os_stack_trace_getter(

-    OsStackTraceGetterInterface* getter) {

-  if (os_stack_trace_getter_ != getter) {

-    delete os_stack_trace_getter_;

-    os_stack_trace_getter_ = getter;

-  }

-}

-

-// Returns the current OS stack trace getter if it is not NULL;

-// otherwise, creates an OsStackTraceGetter, makes it the current

-// getter, and returns it.

-OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {

-  if (os_stack_trace_getter_ == NULL) {

-    os_stack_trace_getter_ = new OsStackTraceGetter;

-  }

-

-  return os_stack_trace_getter_;

-}

-

-// Returns the TestResult for the test that's currently running, or

-// the TestResult for the ad hoc test if no test is running.

-internal::TestResult* UnitTestImpl::current_test_result() {

-  return current_test_info_ ?

-    current_test_info_->impl()->result() : &ad_hoc_test_result_;

-}

-

-// TestInfoImpl constructor. The new instance assumes ownership of the test

-// factory object.

-TestInfoImpl::TestInfoImpl(TestInfo* parent,

-                           const char* test_case_name,

-                           const char* name,

-                           const char* test_case_comment,

-                           const char* comment,

-                           TypeId fixture_class_id,

-                           internal::TestFactoryBase* factory) :

-    parent_(parent),

-    test_case_name_(String(test_case_name)),

-    name_(String(name)),

-    test_case_comment_(String(test_case_comment)),

-    comment_(String(comment)),

-    fixture_class_id_(fixture_class_id),

-    should_run_(false),

-    is_disabled_(false),

-    matches_filter_(false),

-    factory_(factory) {

-}

-

-// TestInfoImpl destructor.

-TestInfoImpl::~TestInfoImpl() {

-  delete factory_;

-}

-

-// Returns the current OS stack trace as a String.

-//

-// The maximum number of stack frames to be included is specified by

-// the gtest_stack_trace_depth flag.  The skip_count parameter

-// specifies the number of top frames to be skipped, which doesn't

-// count against the number of frames to be included.

-//

-// For example, if Foo() calls Bar(), which in turn calls

-// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in

-// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.

-String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count) {

-  // We pass skip_count + 1 to skip this wrapper function in addition

-  // to what the user really wants to skip.

-  return unit_test->impl()->CurrentOsStackTraceExceptTop(skip_count + 1);

-}

-

-// Returns the number of failed test parts in the given test result object.

-int GetFailedPartCount(const TestResult* result) {

-  return result->failed_part_count();

-}

-

-// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable

-// code warnings.

-namespace {

-class ClassUniqueToAlwaysTrue {};

-}

-

-bool AlwaysTrue() {

-#if GTEST_HAS_EXCEPTIONS

-  // This condition is always false so AlwaysTrue() never actually throws,

-  // but it makes the compiler think that it may throw.

-  if (atoi("42") == 36)  // NOLINT

-    throw ClassUniqueToAlwaysTrue();

-#endif  // GTEST_HAS_EXCEPTIONS

-  return true;

-}

-

-// Parses a string as a command line flag.  The string should have

-// the format "--flag=value".  When def_optional is true, the "=value"

-// part can be omitted.

-//

-// Returns the value of the flag, or NULL if the parsing failed.

-const char* ParseFlagValue(const char* str,

-                           const char* flag,

-                           bool def_optional) {

-  // str and flag must not be NULL.

-  if (str == NULL || flag == NULL) return NULL;

-

-  // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.

-  const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag);

-  const size_t flag_len = flag_str.GetLength();

-  if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;

-

-  // Skips the flag name.

-  const char* flag_end = str + flag_len;

-

-  // When def_optional is true, it's OK to not have a "=value" part.

-  if (def_optional && (flag_end[0] == '\0')) {

-    return flag_end;

-  }

-

-  // If def_optional is true and there are more characters after the

-  // flag name, or if def_optional is false, there must be a '=' after

-  // the flag name.

-  if (flag_end[0] != '=') return NULL;

-

-  // Returns the string after "=".

-  return flag_end + 1;

-}

-

-// Parses a string for a bool flag, in the form of either

-// "--flag=value" or "--flag".

-//

-// In the former case, the value is taken as true as long as it does

-// not start with '0', 'f', or 'F'.

-//

-// In the latter case, the value is taken as true.

-//

-// On success, stores the value of the flag in *value, and returns

-// true.  On failure, returns false without changing *value.

-bool ParseBoolFlag(const char* str, const char* flag, bool* value) {

-  // Gets the value of the flag as a string.

-  const char* const value_str = ParseFlagValue(str, flag, true);

-

-  // Aborts if the parsing failed.

-  if (value_str == NULL) return false;

-

-  // Converts the string value to a bool.

-  *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');

-  return true;

-}

-

-// Parses a string for an Int32 flag, in the form of

-// "--flag=value".

-//

-// On success, stores the value of the flag in *value, and returns

-// true.  On failure, returns false without changing *value.

-bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {

-  // Gets the value of the flag as a string.

-  const char* const value_str = ParseFlagValue(str, flag, false);

-

-  // Aborts if the parsing failed.

-  if (value_str == NULL) return false;

-

-  // Sets *value to the value of the flag.

-  return ParseInt32(Message() << "The value of flag --" << flag,

-                    value_str, value);

-}

-

-// Parses a string for a string flag, in the form of

-// "--flag=value".

-//

-// On success, stores the value of the flag in *value, and returns

-// true.  On failure, returns false without changing *value.

-bool ParseStringFlag(const char* str, const char* flag, String* value) {

-  // Gets the value of the flag as a string.

-  const char* const value_str = ParseFlagValue(str, flag, false);

-

-  // Aborts if the parsing failed.

-  if (value_str == NULL) return false;

-

-  // Sets *value to the value of the flag.

-  *value = value_str;

-  return true;

-}

-

-// Prints a string containing code-encoded text.  The following escape

-// sequences can be used in the string to control the text color:

-//

-//   @@    prints a single '@' character.

-//   @R    changes the color to red.

-//   @G    changes the color to green.

-//   @Y    changes the color to yellow.

-//   @D    changes to the default terminal text color.

-//

-// TODO(wan@google.com): Write tests for this once we add stdout

-// capturing to Google Test.

-static void PrintColorEncoded(const char* str) {

-  GTestColor color = COLOR_DEFAULT;  // The current color.

-

-  // Conceptually, we split the string into segments divided by escape

-  // sequences.  Then we print one segment at a time.  At the end of

-  // each iteration, the str pointer advances to the beginning of the

-  // next segment.

-  for (;;) {

-    const char* p = strchr(str, '@');

-    if (p == NULL) {

-      ColoredPrintf(color, "%s", str);

-      return;

-    }

-

-    ColoredPrintf(color, "%s", String(str, p - str).c_str());

-

-    const char ch = p[1];

-    str = p + 2;

-    if (ch == '@') {

-      ColoredPrintf(color, "@");

-    } else if (ch == 'D') {

-      color = COLOR_DEFAULT;

-    } else if (ch == 'R') {

-      color = COLOR_RED;

-    } else if (ch == 'G') {

-      color = COLOR_GREEN;

-    } else if (ch == 'Y') {

-      color = COLOR_YELLOW;

-    } else {

-      --str;

-    }

-  }

-}

-

-static const char kColorEncodedHelpMessage[] =

-"This program contains tests written using " GTEST_NAME_ ". You can use the\n"

-"following command line flags to control its behavior:\n"

-"\n"

-"Test Selection:\n"

-"  @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n"

-"      List the names of all tests instead of running them. The name of\n"

-"      TEST(Foo, Bar) is \"Foo.Bar\".\n"

-"  @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS"

-    "[@G-@YNEGATIVE_PATTERNS]@D\n"

-"      Run only the tests whose name matches one of the positive patterns but\n"

-"      none of the negative patterns. '?' matches any single character; '*'\n"

-"      matches any substring; ':' separates two patterns.\n"

-"  @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n"

-"      Run all disabled tests too.\n"

-"  @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n"

-"      Run the tests repeatedly; use a negative count to repeat forever.\n"

-"\n"

-"Test Output:\n"

-"  @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n"

-"      Enable/disable colored output. The default is @Gauto@D.\n"

-"  -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n"

-"      Don't print the elapsed time of each test.\n"

-"  @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G"

-    GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"

-"      Generate an XML report in the given directory or with the given file\n"

-"      name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n"

-"\n"

-"Assertion Behavior:\n"

-#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS

-"  @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"

-"      Set the default death test style.\n"

-#endif  // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS

-"  @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"

-"      Turn assertion failures into debugger break-points.\n"

-"  @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"

-"      Turn assertion failures into C++ exceptions.\n"

-#if GTEST_OS_WINDOWS

-"  @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n"

-"      Suppress pop-ups caused by exceptions.\n"

-#endif  // GTEST_OS_WINDOWS

-"\n"

-"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set "

-    "the corresponding\n"

-"environment variable of a flag (all letters in upper-case). For example, to\n"

-"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_

-    "color=no@D or set\n"

-"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n"

-"\n"

-"For more information, please read the " GTEST_NAME_ " documentation at\n"

-"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n"

-"(not one in your own code or tests), please report it to\n"

-"@G<" GTEST_DEV_EMAIL_ ">@D.\n";

-

-// Parses the command line for Google Test flags, without initializing

-// other parts of Google Test.  The type parameter CharType can be

-// instantiated to either char or wchar_t.

-template <typename CharType>

-void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {

-  for (int i = 1; i < *argc; i++) {

-    const String arg_string = StreamableToString(argv[i]);

-    const char* const arg = arg_string.c_str();

-

-    using internal::ParseBoolFlag;

-    using internal::ParseInt32Flag;

-    using internal::ParseStringFlag;

-

-    // Do we see a Google Test flag?

-    if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,

-                      &GTEST_FLAG(also_run_disabled_tests)) ||

-        ParseBoolFlag(arg, kBreakOnFailureFlag,

-                      &GTEST_FLAG(break_on_failure)) ||

-        ParseBoolFlag(arg, kCatchExceptionsFlag,

-                      &GTEST_FLAG(catch_exceptions)) ||

-        ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||

-        ParseStringFlag(arg, kDeathTestStyleFlag,

-                        &GTEST_FLAG(death_test_style)) ||

-        ParseBoolFlag(arg, kDeathTestUseFork,

-                      &GTEST_FLAG(death_test_use_fork)) ||

-        ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||

-        ParseStringFlag(arg, kInternalRunDeathTestFlag,

-                        &GTEST_FLAG(internal_run_death_test)) ||

-        ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||

-        ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||

-        ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||

-        ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||

-        ParseBoolFlag(arg, kThrowOnFailureFlag, &GTEST_FLAG(throw_on_failure))

-        ) {

-      // Yes.  Shift the remainder of the argv list left by one.  Note

-      // that argv has (*argc + 1) elements, the last one always being

-      // NULL.  The following loop moves the trailing NULL element as

-      // well.

-      for (int j = i; j != *argc; j++) {

-        argv[j] = argv[j + 1];

-      }

-

-      // Decrements the argument count.

-      (*argc)--;

-

-      // We also need to decrement the iterator as we just removed

-      // an element.

-      i--;

-    } else if (arg_string == "--help" || arg_string == "-h" ||

-               arg_string == "-?" || arg_string == "/?") {

-      g_help_flag = true;

-    }

-  }

-

-  if (g_help_flag) {

-    // We print the help here instead of in RUN_ALL_TESTS(), as the

-    // latter may not be called at all if the user is using Google

-    // Test with another testing framework.

-    PrintColorEncoded(kColorEncodedHelpMessage);

-  }

-}

-

-// Parses the command line for Google Test flags, without initializing

-// other parts of Google Test.

-void ParseGoogleTestFlagsOnly(int* argc, char** argv) {

-  ParseGoogleTestFlagsOnlyImpl(argc, argv);

-}

-void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {

-  ParseGoogleTestFlagsOnlyImpl(argc, argv);

-}

-

-// The internal implementation of InitGoogleTest().

-//

-// The type parameter CharType can be instantiated to either char or

-// wchar_t.

-template <typename CharType>

-void InitGoogleTestImpl(int* argc, CharType** argv) {

-  g_init_gtest_count++;

-

-  // We don't want to run the initialization code twice.

-  if (g_init_gtest_count != 1) return;

-

-  if (*argc <= 0) return;

-

-  internal::g_executable_path = internal::StreamableToString(argv[0]);

-

-#if GTEST_HAS_DEATH_TEST

-  g_argvs.clear();

-  for (int i = 0; i != *argc; i++) {

-    g_argvs.push_back(StreamableToString(argv[i]));

-  }

-#endif  // GTEST_HAS_DEATH_TEST

-

-  ParseGoogleTestFlagsOnly(argc, argv);

-}

-

-}  // namespace internal

-

-// Initializes Google Test.  This must be called before calling

-// RUN_ALL_TESTS().  In particular, it parses a command line for the

-// flags that Google Test recognizes.  Whenever a Google Test flag is

-// seen, it is removed from argv, and *argc is decremented.

-//

-// No value is returned.  Instead, the Google Test flag variables are

-// updated.

-//

-// Calling the function for the second time has no user-visible effect.

-void InitGoogleTest(int* argc, char** argv) {

-  internal::InitGoogleTestImpl(argc, argv);

-}

-

-// This overloaded version can be used in Windows programs compiled in

-// UNICODE mode.

-void InitGoogleTest(int* argc, wchar_t** argv) {

-  internal::InitGoogleTestImpl(argc, argv);

-}

-

-}  // namespace testing

+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#if GTEST_OS_LINUX
+
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+#define GTEST_HAS_GETTIMEOFDAY_ 1
+
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+// Declares vsnprintf().  This header is not available on Windows.
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#elif GTEST_OS_SYMBIAN
+#define GTEST_HAS_GETTIMEOFDAY_ 1
+#include <sys/time.h>  // NOLINT
+
+#elif GTEST_OS_ZOS
+#define GTEST_HAS_GETTIMEOFDAY_ 1
+#include <sys/time.h>  // NOLINT
+
+// On z/OS we additionally need strings.h for strcasecmp.
+#include <strings.h>  // NOLINT
+
+#elif defined(_WIN32_WCE)  // We are on Windows CE.
+
+#include <windows.h>  // NOLINT
+
+#elif GTEST_OS_WINDOWS  // We are on Windows proper.
+
+#include <io.h>  // NOLINT
+#include <sys/timeb.h>  // NOLINT
+#include <sys/types.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
+
+#if defined(__MINGW__) || defined(__MINGW32__)
+// MinGW has gettimeofday() but not _ftime64().
+// TODO(kenton@google.com): Use autoconf to detect availability of
+//   gettimeofday().
+// TODO(kenton@google.com): There are other ways to get the time on
+//   Windows, like GetTickCount() or GetSystemTimeAsFileTime().  MinGW
+//   supports these.  consider using them instead.
+#define GTEST_HAS_GETTIMEOFDAY_ 1
+#include <sys/time.h>  // NOLINT
+#endif  // defined(__MINGW__) || defined(__MINGW32__)
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+#include <windows.h>  // NOLINT
+
+#else
+
+// Assume other platforms have gettimeofday().
+// TODO(kenton@google.com): Use autoconf to detect availability of
+//   gettimeofday().
+#define GTEST_HAS_GETTIMEOFDAY_ 1
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+#include <sys/time.h>  // NOLINT
+#include <unistd.h>  // NOLINT
+
+#endif  // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+#include <stdexcept>
+#endif
+
+// Indicates that this translation unit is part of Google Test's
+// implementation.  It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error.  This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#if GTEST_OS_WINDOWS
+#define vsnprintf _vsnprintf
+#endif  // GTEST_OS_WINDOWS
+
+namespace testing {
+
+// Constants.
+
+// A test whose test case name or test name matches this filter is
+// disabled and not run.
+static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
+
+// A test case whose name matches this filter is considered a death
+// test case and will be run before test cases whose name doesn't
+// match this filter.
+static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";
+
+// A test filter that matches everything.
+static const char kUniversalFilter[] = "*";
+
+// The default output file for XML output.
+static const char kDefaultOutputFile[] = "test_detail.xml";
+
+// The environment variable name for the test shard index.
+static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
+// The environment variable name for the total number of test shards.
+static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
+// The environment variable name for the test shard status file.
+static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE";
+
+namespace internal {
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+const char kStackTraceMarker[] = "\nStack trace:\n";
+
+}  // namespace internal
+
+GTEST_DEFINE_bool_(
+    also_run_disabled_tests,
+    internal::BoolFromGTestEnv("also_run_disabled_tests", false),
+    "Run disabled tests too, in addition to the tests normally being run.");
+
+GTEST_DEFINE_bool_(
+    break_on_failure,
+    internal::BoolFromGTestEnv("break_on_failure", false),
+    "True iff a failed assertion should be a debugger break-point.");
+
+GTEST_DEFINE_bool_(
+    catch_exceptions,
+    internal::BoolFromGTestEnv("catch_exceptions", false),
+    "True iff " GTEST_NAME_
+    " should catch exceptions and treat them as test failures.");
+
+GTEST_DEFINE_string_(
+    color,
+    internal::StringFromGTestEnv("color", "auto"),
+    "Whether to use colors in the output.  Valid values: yes, no, "
+    "and auto.  'auto' means to use colors if the output is "
+    "being sent to a terminal and the TERM environment variable "
+    "is set to xterm, xterm-color, xterm-256color or cygwin.");
+
+GTEST_DEFINE_string_(
+    filter,
+    internal::StringFromGTestEnv("filter", kUniversalFilter),
+    "A colon-separated list of glob (not regex) patterns "
+    "for filtering the tests to run, optionally followed by a "
+    "'-' and a : separated list of negative patterns (tests to "
+    "exclude).  A test is run if it matches one of the positive "
+    "patterns and does not match any of the negative patterns.");
+
+GTEST_DEFINE_bool_(list_tests, false,
+                   "List all tests without running them.");
+
+GTEST_DEFINE_string_(
+    output,
+    internal::StringFromGTestEnv("output", ""),
+    "A format (currently must be \"xml\"), optionally followed "
+    "by a colon and an output file name or directory. A directory "
+    "is indicated by a trailing pathname separator. "
+    "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
+    "If a directory is specified, output files will be created "
+    "within that directory, with file-names based on the test "
+    "executable's name and, if necessary, made unique by adding "
+    "digits.");
+
+GTEST_DEFINE_bool_(
+    print_time,
+    internal::BoolFromGTestEnv("print_time", true),
+    "True iff " GTEST_NAME_
+    " should display elapsed time in text output.");
+
+GTEST_DEFINE_int32_(
+    repeat,
+    internal::Int32FromGTestEnv("repeat", 1),
+    "How many times to repeat each test.  Specify a negative number "
+    "for repeating forever.  Useful for shaking out flaky tests.");
+
+GTEST_DEFINE_int32_(
+    stack_trace_depth,
+        internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
+    "The maximum number of stack frames to print when an "
+    "assertion fails.  The valid range is 0 through 100, inclusive.");
+
+GTEST_DEFINE_bool_(
+    show_internal_stack_frames, false,
+    "True iff " GTEST_NAME_ " should include internal stack frames when "
+    "printing test failure stack traces.");
+
+GTEST_DEFINE_bool_(
+    throw_on_failure,
+    internal::BoolFromGTestEnv("throw_on_failure", false),
+    "When this flag is specified, a failed assertion will throw an exception "
+    "if exceptions are enabled or exit the program with a non-zero code "
+    "otherwise.");
+
+namespace internal {
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+static bool g_help_flag = false;
+
+// GTestIsInitialized() returns true iff the user has initialized
+// Google Test.  Useful for catching the user mistake of not initializing
+// Google Test before calling RUN_ALL_TESTS().
+//
+// A user must call testing::InitGoogleTest() to initialize Google
+// Test.  g_init_gtest_count is set to the number of times
+// InitGoogleTest() has been called.  We don't protect this variable
+// under a mutex as it is only accessed in the main thread.
+int g_init_gtest_count = 0;
+static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
+
+// Iterates over a list of TestCases, keeping a running sum of the
+// results of calling a given int-returning method on each.
+// Returns the sum.
+static int SumOverTestCaseList(const internal::List<TestCase*>& case_list,
+                               int (TestCase::*method)() const) {
+  int sum = 0;
+  for (const internal::ListNode<TestCase*>* node = case_list.Head();
+       node != NULL;
+       node = node->next()) {
+    sum += (node->element()->*method)();
+  }
+  return sum;
+}
+
+// Returns true iff the test case passed.
+static bool TestCasePassed(const TestCase* test_case) {
+  return test_case->should_run() && test_case->Passed();
+}
+
+// Returns true iff the test case failed.
+static bool TestCaseFailed(const TestCase* test_case) {
+  return test_case->should_run() && test_case->Failed();
+}
+
+// Returns true iff test_case contains at least one test that should
+// run.
+static bool ShouldRunTestCase(const TestCase* test_case) {
+  return test_case->should_run();
+}
+
+// AssertHelper constructor.
+AssertHelper::AssertHelper(TestPartResultType type, const char* file,
+                           int line, const char* message)
+    : type_(type), file_(file), line_(line), message_(message) {
+}
+
+// Message assignment, for assertion streaming support.
+void AssertHelper::operator=(const Message& message) const {
+  UnitTest::GetInstance()->
+    AddTestPartResult(type_, file_, line_,
+                      AppendUserMessage(message_, message),
+                      UnitTest::GetInstance()->impl()
+                      ->CurrentOsStackTraceExceptTop(1)
+                      // Skips the stack frame for this function itself.
+                      );  // NOLINT
+}
+
+// Mutex for linked pointers.
+Mutex g_linked_ptr_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX);
+
+// Application pathname gotten in InitGoogleTest.
+String g_executable_path;
+
+// Returns the current application's name, removing directory path if that
+// is present.
+FilePath GetCurrentExecutableName() {
+  FilePath result;
+
+#if defined(_WIN32_WCE) || GTEST_OS_WINDOWS
+  result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
+#else
+  result.Set(FilePath(g_executable_path));
+#endif  // _WIN32_WCE || GTEST_OS_WINDOWS
+
+  return result.RemoveDirectoryName();
+}
+
+// Functions for processing the gtest_output flag.
+
+// Returns the output format, or "" for normal printed output.
+String UnitTestOptions::GetOutputFormat() {
+  const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+  if (gtest_output_flag == NULL) return String("");
+
+  const char* const colon = strchr(gtest_output_flag, ':');
+  return (colon == NULL) ?
+      String(gtest_output_flag) :
+      String(gtest_output_flag, colon - gtest_output_flag);
+}
+
+// Returns the name of the requested output file, or the default if none
+// was explicitly specified.
+String UnitTestOptions::GetAbsolutePathToOutputFile() {
+  const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+  if (gtest_output_flag == NULL)
+    return String("");
+
+  const char* const colon = strchr(gtest_output_flag, ':');
+  if (colon == NULL)
+    return String(internal::FilePath::ConcatPaths(
+               internal::FilePath(
+                   UnitTest::GetInstance()->original_working_dir()),
+               internal::FilePath(kDefaultOutputFile)).ToString() );
+
+  internal::FilePath output_name(colon + 1);
+  if (!output_name.IsAbsolutePath())
+    // TODO(wan@google.com): on Windows \some\path is not an absolute
+    // path (as its meaning depends on the current drive), yet the
+    // following logic for turning it into an absolute path is wrong.
+    // Fix it.
+    output_name = internal::FilePath::ConcatPaths(
+        internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
+        internal::FilePath(colon + 1));
+
+  if (!output_name.IsDirectory())
+    return output_name.ToString();
+
+  internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
+      output_name, internal::GetCurrentExecutableName(),
+      GetOutputFormat().c_str()));
+  return result.ToString();
+}
+
+// Returns true iff the wildcard pattern matches the string.  The
+// first ':' or '\0' character in pattern marks the end of it.
+//
+// This recursive algorithm isn't very efficient, but is clear and
+// works well enough for matching test names, which are short.
+bool UnitTestOptions::PatternMatchesString(const char *pattern,
+                                           const char *str) {
+  switch (*pattern) {
+    case '\0':
+    case ':':  // Either ':' or '\0' marks the end of the pattern.
+      return *str == '\0';
+    case '?':  // Matches any single character.
+      return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
+    case '*':  // Matches any string (possibly empty) of characters.
+      return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
+          PatternMatchesString(pattern + 1, str);
+    default:  // Non-special character.  Matches itself.
+      return *pattern == *str &&
+          PatternMatchesString(pattern + 1, str + 1);
+  }
+}
+
+bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) {
+  const char *cur_pattern = filter;
+  for (;;) {
+    if (PatternMatchesString(cur_pattern, name.c_str())) {
+      return true;
+    }
+
+    // Finds the next pattern in the filter.
+    cur_pattern = strchr(cur_pattern, ':');
+
+    // Returns if no more pattern can be found.
+    if (cur_pattern == NULL) {
+      return false;
+    }
+
+    // Skips the pattern separater (the ':' character).
+    cur_pattern++;
+  }
+}
+
+// TODO(keithray): move String function implementations to gtest-string.cc.
+
+// Returns true iff the user-specified filter matches the test case
+// name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const String &test_case_name,
+                                        const String &test_name) {
+  const String& full_name = String::Format("%s.%s",
+                                           test_case_name.c_str(),
+                                           test_name.c_str());
+
+  // Split --gtest_filter at '-', if there is one, to separate into
+  // positive filter and negative filter portions
+  const char* const p = GTEST_FLAG(filter).c_str();
+  const char* const dash = strchr(p, '-');
+  String positive;
+  String negative;
+  if (dash == NULL) {
+    positive = GTEST_FLAG(filter).c_str();  // Whole string is a positive filter
+    negative = String("");
+  } else {
+    positive.Set(p, dash - p);       // Everything up to the dash
+    negative = String(dash+1);       // Everything after the dash
+    if (positive.empty()) {
+      // Treat '-test1' as the same as '*-test1'
+      positive = kUniversalFilter;
+    }
+  }
+
+  // A filter is a colon-separated list of patterns.  It matches a
+  // test if any pattern in it matches the test.
+  return (MatchesFilter(full_name, positive.c_str()) &&
+          !MatchesFilter(full_name, negative.c_str()));
+}
+
+#if GTEST_OS_WINDOWS
+// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+// This function is useful as an __except condition.
+int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
+  // Google Test should handle an exception if:
+  //   1. the user wants it to, AND
+  //   2. this is not a breakpoint exception.
+  return (GTEST_FLAG(catch_exceptions) &&
+          exception_code != EXCEPTION_BREAKPOINT) ?
+      EXCEPTION_EXECUTE_HANDLER :
+      EXCEPTION_CONTINUE_SEARCH;
+}
+#endif  // GTEST_OS_WINDOWS
+
+}  // namespace internal
+
+// The interface for printing the result of a UnitTest
+class UnitTestEventListenerInterface {
+ public:
+  // The d'tor is pure virtual as this is an abstract class.
+  virtual ~UnitTestEventListenerInterface() = 0;
+
+  // Called before the unit test starts.
+  virtual void OnUnitTestStart(const UnitTest*) {}
+
+  // Called after the unit test ends.
+  virtual void OnUnitTestEnd(const UnitTest*) {}
+
+  // Called before the test case starts.
+  virtual void OnTestCaseStart(const TestCase*) {}
+
+  // Called after the test case ends.
+  virtual void OnTestCaseEnd(const TestCase*) {}
+
+  // Called before the global set-up starts.
+  virtual void OnGlobalSetUpStart(const UnitTest*) {}
+
+  // Called after the global set-up ends.
+  virtual void OnGlobalSetUpEnd(const UnitTest*) {}
+
+  // Called before the global tear-down starts.
+  virtual void OnGlobalTearDownStart(const UnitTest*) {}
+
+  // Called after the global tear-down ends.
+  virtual void OnGlobalTearDownEnd(const UnitTest*) {}
+
+  // Called before the test starts.
+  virtual void OnTestStart(const TestInfo*) {}
+
+  // Called after the test ends.
+  virtual void OnTestEnd(const TestInfo*) {}
+
+  // Called after an assertion.
+  virtual void OnNewTestPartResult(const TestPartResult*) {}
+};
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test.  The 'result' parameter specifies where to report the
+// results. Intercepts only failures from the current thread.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+    TestPartResultArray* result)
+    : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),
+      result_(result) {
+  Init();
+}
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test.  The 'result' parameter specifies where to report the
+// results.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+    InterceptMode intercept_mode, TestPartResultArray* result)
+    : intercept_mode_(intercept_mode),
+      result_(result) {
+  Init();
+}
+
+void ScopedFakeTestPartResultReporter::Init() {
+  internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl();
+  if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+    old_reporter_ = impl->GetGlobalTestPartResultReporter();
+    impl->SetGlobalTestPartResultReporter(this);
+  } else {
+    old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();
+    impl->SetTestPartResultReporterForCurrentThread(this);
+  }
+}
+
+// The d'tor restores the test part result reporter used by Google Test
+// before.
+ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {
+  internal::UnitTestImpl* const impl = UnitTest::GetInstance()->impl();
+  if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+    impl->SetGlobalTestPartResultReporter(old_reporter_);
+  } else {
+    impl->SetTestPartResultReporterForCurrentThread(old_reporter_);
+  }
+}
+
+// Increments the test part result count and remembers the result.
+// This method is from the TestPartResultReporterInterface interface.
+void ScopedFakeTestPartResultReporter::ReportTestPartResult(
+    const TestPartResult& result) {
+  result_->Append(result);
+}
+
+namespace internal {
+
+// Returns the type ID of ::testing::Test.  We should always call this
+// instead of GetTypeId< ::testing::Test>() to get the type ID of
+// testing::Test.  This is to work around a suspected linker bug when
+// using Google Test as a framework on Mac OS X.  The bug causes
+// GetTypeId< ::testing::Test>() to return different values depending
+// on whether the call is from the Google Test framework itself or
+// from user test code.  GetTestTypeId() is guaranteed to always
+// return the same value, as it always calls GetTypeId<>() from the
+// gtest.cc, which is within the Google Test framework.
+TypeId GetTestTypeId() {
+  return GetTypeId<Test>();
+}
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library.  This is solely for testing GetTestTypeId().
+extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();
+
+// This predicate-formatter checks that 'results' contains a test part
+// failure of the given type and that the failure message contains the
+// given substring.
+AssertionResult HasOneFailure(const char* /* results_expr */,
+                              const char* /* type_expr */,
+                              const char* /* substr_expr */,
+                              const TestPartResultArray& results,
+                              TestPartResultType type,
+                              const char* substr) {
+  const String expected(
+      type == TPRT_FATAL_FAILURE ? "1 fatal failure" :
+      "1 non-fatal failure");
+  Message msg;
+  if (results.size() != 1) {
+    msg << "Expected: " << expected << "\n"
+        << "  Actual: " << results.size() << " failures";
+    for (int i = 0; i < results.size(); i++) {
+      msg << "\n" << results.GetTestPartResult(i);
+    }
+    return AssertionFailure(msg);
+  }
+
+  const TestPartResult& r = results.GetTestPartResult(0);
+  if (r.type() != type) {
+    msg << "Expected: " << expected << "\n"
+        << "  Actual:\n"
+        << r;
+    return AssertionFailure(msg);
+  }
+
+  if (strstr(r.message(), substr) == NULL) {
+    msg << "Expected: " << expected << " containing \""
+        << substr << "\"\n"
+        << "  Actual:\n"
+        << r;
+    return AssertionFailure(msg);
+  }
+
+  return AssertionSuccess();
+}
+
+// The constructor of SingleFailureChecker remembers where to look up
+// test part results, what type of failure we expect, and what
+// substring the failure message should contain.
+SingleFailureChecker:: SingleFailureChecker(
+    const TestPartResultArray* results,
+    TestPartResultType type,
+    const char* substr)
+    : results_(results),
+      type_(type),
+      substr_(substr) {}
+
+// The destructor of SingleFailureChecker verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring.  If that's not the case, a
+// non-fatal failure will be generated.
+SingleFailureChecker::~SingleFailureChecker() {
+  EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str());
+}
+
+DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(
+    UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultGlobalTestPartResultReporter::ReportTestPartResult(
+    const TestPartResult& result) {
+  unit_test_->current_test_result()->AddTestPartResult(result);
+  unit_test_->result_printer()->OnNewTestPartResult(&result);
+}
+
+DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(
+    UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
+    const TestPartResult& result) {
+  unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);
+}
+
+// Returns the global test part result reporter.
+TestPartResultReporterInterface*
+UnitTestImpl::GetGlobalTestPartResultReporter() {
+  internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+  return global_test_part_result_repoter_;
+}
+
+// Sets the global test part result reporter.
+void UnitTestImpl::SetGlobalTestPartResultReporter(
+    TestPartResultReporterInterface* reporter) {
+  internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+  global_test_part_result_repoter_ = reporter;
+}
+
+// Returns the test part result reporter for the current thread.
+TestPartResultReporterInterface*
+UnitTestImpl::GetTestPartResultReporterForCurrentThread() {
+  return per_thread_test_part_result_reporter_.get();
+}
+
+// Sets the test part result reporter for the current thread.
+void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
+    TestPartResultReporterInterface* reporter) {
+  per_thread_test_part_result_reporter_.set(reporter);
+}
+
+// Gets the number of successful test cases.
+int UnitTestImpl::successful_test_case_count() const {
+  return test_cases_.CountIf(TestCasePassed);
+}
+
+// Gets the number of failed test cases.
+int UnitTestImpl::failed_test_case_count() const {
+  return test_cases_.CountIf(TestCaseFailed);
+}
+
+// Gets the number of all test cases.
+int UnitTestImpl::total_test_case_count() const {
+  return test_cases_.size();
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTestImpl::test_case_to_run_count() const {
+  return test_cases_.CountIf(ShouldRunTestCase);
+}
+
+// Gets the number of successful tests.
+int UnitTestImpl::successful_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
+}
+
+// Gets the number of failed tests.
+int UnitTestImpl::failed_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
+}
+
+// Gets the number of disabled tests.
+int UnitTestImpl::disabled_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
+}
+
+// Gets the number of all tests.
+int UnitTestImpl::total_test_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
+}
+
+// Gets the number of tests that should run.
+int UnitTestImpl::test_to_run_count() const {
+  return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
+}
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag.  The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
+  (void)skip_count;
+  return String("");
+}
+
+static TimeInMillis GetTimeInMillis() {
+#if defined(_WIN32_WCE) || defined(__BORLANDC__)
+  // Difference between 1970-01-01 and 1601-01-01 in miliseconds.
+  // http://analogous.blogspot.com/2005/04/epoch.html
+  const TimeInMillis kJavaEpochToWinFileTimeDelta =
+    static_cast<TimeInMillis>(116444736UL) * 100000UL;
+  const DWORD kTenthMicrosInMilliSecond = 10000;
+
+  SYSTEMTIME now_systime;
+  FILETIME now_filetime;
+  ULARGE_INTEGER now_int64;
+  // TODO(kenton@google.com): Shouldn't this just use
+  //   GetSystemTimeAsFileTime()?
+  GetSystemTime(&now_systime);
+  if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
+    now_int64.LowPart = now_filetime.dwLowDateTime;
+    now_int64.HighPart = now_filetime.dwHighDateTime;
+    now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
+      kJavaEpochToWinFileTimeDelta;
+    return now_int64.QuadPart;
+  }
+  return 0;
+#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
+  __timeb64 now;
+#ifdef _MSC_VER
+  // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
+  // (deprecated function) there.
+  // TODO(kenton@google.com): Use GetTickCount()?  Or use
+  //   SystemTimeToFileTime()
+#pragma warning(push)          // Saves the current warning state.
+#pragma warning(disable:4996)  // Temporarily disables warning 4996.
+  _ftime64(&now);
+#pragma warning(pop)           // Restores the warning state.
+#else
+  _ftime64(&now);
+#endif  // _MSC_VER
+  return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
+#elif GTEST_HAS_GETTIMEOFDAY_
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
+#else
+#error "Don't know how to get the current time on your system."
+#endif
+}
+
+// Utilities
+
+// class String
+
+// Returns the input enclosed in double quotes if it's not NULL;
+// otherwise returns "(null)".  For example, "\"Hello\"" is returned
+// for input "Hello".
+//
+// This is useful for printing a C string in the syntax of a literal.
+//
+// Known issue: escape sequences are not handled yet.
+String String::ShowCStringQuoted(const char* c_str) {
+  return c_str ? String::Format("\"%s\"", c_str) : String("(null)");
+}
+
+// Copies at most length characters from str into a newly-allocated
+// piece of memory of size length+1.  The memory is allocated with new[].
+// A terminating null byte is written to the memory, and a pointer to it
+// is returned.  If str is NULL, NULL is returned.
+static char* CloneString(const char* str, size_t length) {
+  if (str == NULL) {
+    return NULL;
+  } else {
+    char* const clone = new char[length + 1];
+    posix::StrNCpy(clone, str, length);
+    clone[length] = '\0';
+    return clone;
+  }
+}
+
+// Clones a 0-terminated C string, allocating memory using new.  The
+// caller is responsible for deleting[] the return value.  Returns the
+// cloned string, or NULL if the input is NULL.
+const char * String::CloneCString(const char* c_str) {
+  return (c_str == NULL) ?
+                    NULL : CloneString(c_str, strlen(c_str));
+}
+
+#ifdef _WIN32_WCE
+// Creates a UTF-16 wide string from the given ANSI string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the wide string, or NULL if the
+// input is NULL.
+LPCWSTR String::AnsiToUtf16(const char* ansi) {
+  if (!ansi) return NULL;
+  const int length = strlen(ansi);
+  const int unicode_length =
+      MultiByteToWideChar(CP_ACP, 0, ansi, length,
+                          NULL, 0);
+  WCHAR* unicode = new WCHAR[unicode_length + 1];
+  MultiByteToWideChar(CP_ACP, 0, ansi, length,
+                      unicode, unicode_length);
+  unicode[unicode_length] = 0;
+  return unicode;
+}
+
+// Creates an ANSI string from the given wide string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the ANSI string, or NULL if the
+// input is NULL.
+const char* String::Utf16ToAnsi(LPCWSTR utf16_str)  {
+  if (!utf16_str) return NULL;
+  const int ansi_length =
+      WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+                          NULL, 0, NULL, NULL);
+  char* ansi = new char[ansi_length + 1];
+  WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+                      ansi, ansi_length, NULL, NULL);
+  ansi[ansi_length] = 0;
+  return ansi;
+}
+
+#endif  // _WIN32_WCE
+
+// Compares two C strings.  Returns true iff they have the same content.
+//
+// Unlike strcmp(), this function can handle NULL argument(s).  A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CStringEquals(const char * lhs, const char * rhs) {
+  if ( lhs == NULL ) return rhs == NULL;
+
+  if ( rhs == NULL ) return false;
+
+  return strcmp(lhs, rhs) == 0;
+}
+
+#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+// Converts an array of wide chars to a narrow string using the UTF-8
+// encoding, and streams the result to the given Message object.
+static void StreamWideCharsToMessage(const wchar_t* wstr, size_t len,
+                                     Message* msg) {
+  // TODO(wan): consider allowing a testing::String object to
+  // contain '\0'.  This will make it behave more like std::string,
+  // and will allow ToUtf8String() to return the correct encoding
+  // for '\0' s.t. we can get rid of the conditional here (and in
+  // several other places).
+  for (size_t i = 0; i != len; ) {  // NOLINT
+    if (wstr[i] != L'\0') {
+      *msg << WideStringToUtf8(wstr + i, static_cast<int>(len - i));
+      while (i != len && wstr[i] != L'\0')
+        i++;
+    } else {
+      *msg << '\0';
+      i++;
+    }
+  }
+}
+
+#endif  // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+}  // namespace internal
+
+#if GTEST_HAS_STD_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::std::wstring& wstr) {
+  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+  return *this;
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::wstring& wstr) {
+  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+  return *this;
+}
+#endif  // GTEST_HAS_GLOBAL_WSTRING
+
+namespace internal {
+
+// Formats a value to be used in a failure message.
+
+// For a char value, we print it as a C++ char literal and as an
+// unsigned integer (both in decimal and in hexadecimal).
+String FormatForFailureMessage(char ch) {
+  const unsigned int ch_as_uint = ch;
+  // A String object cannot contain '\0', so we print "\\0" when ch is
+  // '\0'.
+  return String::Format("'%s' (%u, 0x%X)",
+                        ch ? String::Format("%c", ch).c_str() : "\\0",
+                        ch_as_uint, ch_as_uint);
+}
+
+// For a wchar_t value, we print it as a C++ wchar_t literal and as an
+// unsigned integer (both in decimal and in hexidecimal).
+String FormatForFailureMessage(wchar_t wchar) {
+  // The C++ standard doesn't specify the exact size of the wchar_t
+  // type.  It just says that it shall have the same size as another
+  // integral type, called its underlying type.
+  //
+  // Therefore, in order to print a wchar_t value in the numeric form,
+  // we first convert it to the largest integral type (UInt64) and
+  // then print the converted value.
+  //
+  // We use streaming to print the value as "%llu" doesn't work
+  // correctly with MSVC 7.1.
+  const UInt64 wchar_as_uint64 = wchar;
+  Message msg;
+  // A String object cannot contain '\0', so we print "\\0" when wchar is
+  // L'\0'.
+  char buffer[32];  // CodePointToUtf8 requires a buffer that big.
+  msg << "L'"
+      << (wchar ? CodePointToUtf8(static_cast<UInt32>(wchar), buffer) : "\\0")
+      << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16)
+      << wchar_as_uint64 << ")";
+  return msg.GetString();
+}
+
+}  // namespace internal
+
+// AssertionResult constructor.
+AssertionResult::AssertionResult(const internal::String& failure_message)
+    : failure_message_(failure_message) {
+}
+
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess() {
+  return AssertionResult();
+}
+
+
+// Makes a failed assertion result with the given failure message.
+AssertionResult AssertionFailure(const Message& message) {
+  return AssertionResult(message.GetString());
+}
+
+namespace internal {
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings.  For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+//   expected_expression: "foo"
+//   actual_expression:   "bar"
+//   expected_value:      "5"
+//   actual_value:        "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+                          const char* actual_expression,
+                          const String& expected_value,
+                          const String& actual_value,
+                          bool ignoring_case) {
+  Message msg;
+  msg << "Value of: " << actual_expression;
+  if (actual_value != actual_expression) {
+    msg << "\n  Actual: " << actual_value;
+  }
+
+  msg << "\nExpected: " << expected_expression;
+  if (ignoring_case) {
+    msg << " (ignoring case)";
+  }
+  if (expected_value != expected_expression) {
+    msg << "\nWhich is: " << expected_value;
+  }
+
+  return AssertionFailure(msg);
+}
+
+
+// Helper function for implementing ASSERT_NEAR.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+                                     const char* expr2,
+                                     const char* abs_error_expr,
+                                     double val1,
+                                     double val2,
+                                     double abs_error) {
+  const double diff = fabs(val1 - val2);
+  if (diff <= abs_error) return AssertionSuccess();
+
+  // TODO(wan): do not print the value of an expression if it's
+  // already a literal.
+  Message msg;
+  msg << "The difference between " << expr1 << " and " << expr2
+      << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
+      << expr1 << " evaluates to " << val1 << ",\n"
+      << expr2 << " evaluates to " << val2 << ", and\n"
+      << abs_error_expr << " evaluates to " << abs_error << ".";
+  return AssertionFailure(msg);
+}
+
+
+// Helper template for implementing FloatLE() and DoubleLE().
+template <typename RawType>
+AssertionResult FloatingPointLE(const char* expr1,
+                                const char* expr2,
+                                RawType val1,
+                                RawType val2) {
+  // Returns success if val1 is less than val2,
+  if (val1 < val2) {
+    return AssertionSuccess();
+  }
+
+  // or if val1 is almost equal to val2.
+  const FloatingPoint<RawType> lhs(val1), rhs(val2);
+  if (lhs.AlmostEquals(rhs)) {
+    return AssertionSuccess();
+  }
+
+  // Note that the above two checks will both fail if either val1 or
+  // val2 is NaN, as the IEEE floating-point standard requires that
+  // any predicate involving a NaN must return false.
+
+  StrStream val1_ss;
+  val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+          << val1;
+
+  StrStream val2_ss;
+  val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+          << val2;
+
+  Message msg;
+  msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
+      << "  Actual: " << StrStreamToString(&val1_ss) << " vs "
+      << StrStreamToString(&val2_ss);
+
+  return AssertionFailure(msg);
+}
+
+}  // namespace internal
+
+// Asserts that val1 is less than, or almost equal to, val2.  Fails
+// otherwise.  In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+                        float val1, float val2) {
+  return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
+}
+
+// Asserts that val1 is less than, or almost equal to, val2.  Fails
+// otherwise.  In particular, it fails if either val1 or val2 is NaN.
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+                         double val1, double val2) {
+  return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
+}
+
+namespace internal {
+
+// The helper function for {ASSERT|EXPECT}_EQ with int or enum
+// arguments.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+                            const char* actual_expression,
+                            BiggestInt expected,
+                            BiggestInt actual) {
+  if (expected == actual) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   FormatForComparisonFailureMessage(expected, actual),
+                   FormatForComparisonFailureMessage(actual, expected),
+                   false);
+}
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_?? with integer or enum arguments.  It is here
+// just to avoid copy-and-paste of similar code.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+                                   BiggestInt val1, BiggestInt val2) {\
+  if (val1 op val2) {\
+    return AssertionSuccess();\
+  } else {\
+    Message msg;\
+    msg << "Expected: (" << expr1 << ") " #op " (" << expr2\
+        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+        << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+    return AssertionFailure(msg);\
+  }\
+}
+
+// Implements the helper function for {ASSERT|EXPECT}_NE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LT, < )
+// Implements the helper function for {ASSERT|EXPECT}_GE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GT, > )
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                               const char* actual_expression,
+                               const char* expected,
+                               const char* actual) {
+  if (String::CStringEquals(expected, actual)) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   String::ShowCStringQuoted(expected),
+                   String::ShowCStringQuoted(actual),
+                   false);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+                                   const char* actual_expression,
+                                   const char* expected,
+                                   const char* actual) {
+  if (String::CaseInsensitiveCStringEquals(expected, actual)) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   String::ShowCStringQuoted(expected),
+                   String::ShowCStringQuoted(actual),
+                   true);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                               const char* s2_expression,
+                               const char* s1,
+                               const char* s2) {
+  if (!String::CStringEquals(s1, s2)) {
+    return AssertionSuccess();
+  } else {
+    Message msg;
+    msg << "Expected: (" << s1_expression << ") != ("
+        << s2_expression << "), actual: \""
+        << s1 << "\" vs \"" << s2 << "\"";
+    return AssertionFailure(msg);
+  }
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+                                   const char* s2_expression,
+                                   const char* s1,
+                                   const char* s2) {
+  if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
+    return AssertionSuccess();
+  } else {
+    Message msg;
+    msg << "Expected: (" << s1_expression << ") != ("
+        << s2_expression << ") (ignoring case), actual: \""
+        << s1 << "\" vs \"" << s2 << "\"";
+    return AssertionFailure(msg);
+  }
+}
+
+}  // namespace internal
+
+namespace {
+
+// Helper functions for implementing IsSubString() and IsNotSubstring().
+
+// This group of overloaded functions return true iff needle is a
+// substring of haystack.  NULL is considered a substring of itself
+// only.
+
+bool IsSubstringPred(const char* needle, const char* haystack) {
+  if (needle == NULL || haystack == NULL)
+    return needle == haystack;
+
+  return strstr(haystack, needle) != NULL;
+}
+
+bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
+  if (needle == NULL || haystack == NULL)
+    return needle == haystack;
+
+  return wcsstr(haystack, needle) != NULL;
+}
+
+// StringType here can be either ::std::string or ::std::wstring.
+template <typename StringType>
+bool IsSubstringPred(const StringType& needle,
+                     const StringType& haystack) {
+  return haystack.find(needle) != StringType::npos;
+}
+
+// This function implements either IsSubstring() or IsNotSubstring(),
+// depending on the value of the expected_to_be_substring parameter.
+// StringType here can be const char*, const wchar_t*, ::std::string,
+// or ::std::wstring.
+template <typename StringType>
+AssertionResult IsSubstringImpl(
+    bool expected_to_be_substring,
+    const char* needle_expr, const char* haystack_expr,
+    const StringType& needle, const StringType& haystack) {
+  if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
+    return AssertionSuccess();
+
+  const bool is_wide_string = sizeof(needle[0]) > 1;
+  const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
+  return AssertionFailure(
+      Message()
+      << "Value of: " << needle_expr << "\n"
+      << "  Actual: " << begin_string_quote << needle << "\"\n"
+      << "Expected: " << (expected_to_be_substring ? "" : "not ")
+      << "a substring of " << haystack_expr << "\n"
+      << "Which is: " << begin_string_quote << haystack << "\"");
+}
+
+}  // namespace
+
+// IsSubstring() and IsNotSubstring() check whether needle is a
+// substring of haystack (NULL is considered a substring of itself
+// only), and return an appropriate error message when they fail.
+
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const char* needle, const char* haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const wchar_t* needle, const wchar_t* haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+#if GTEST_HAS_STD_STRING
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::string& needle, const ::std::string& haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif  // GTEST_HAS_STD_STRING
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack) {
+  return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+    const char* needle_expr, const char* haystack_expr,
+    const ::std::wstring& needle, const ::std::wstring& haystack) {
+  return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif  // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+
+namespace {
+
+// Helper function for IsHRESULT{SuccessFailure} predicates
+AssertionResult HRESULTFailureHelper(const char* expr,
+                                     const char* expected,
+                                     long hr) {  // NOLINT
+#ifdef _WIN32_WCE
+  // Windows CE doesn't support FormatMessage.
+  const char error_text[] = "";
+#else
+  // Looks up the human-readable system message for the HRESULT code
+  // and since we're not passing any params to FormatMessage, we don't
+  // want inserts expanded.
+  const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS;
+  const DWORD kBufSize = 4096;  // String::Format can't exceed this length.
+  // Gets the system's human readable message string for this HRESULT.
+  char error_text[kBufSize] = { '\0' };
+  DWORD message_length = ::FormatMessageA(kFlags,
+                                          0,  // no source, we're asking system
+                                          hr,  // the error
+                                          0,  // no line width restrictions
+                                          error_text,  // output buffer
+                                          kBufSize,  // buf size
+                                          NULL);  // no arguments for inserts
+  // Trims tailing white space (FormatMessage leaves a trailing cr-lf)
+  for (; message_length && isspace(error_text[message_length - 1]);
+          --message_length) {
+    error_text[message_length - 1] = '\0';
+  }
+#endif  // _WIN32_WCE
+
+  const String error_hex(String::Format("0x%08X ", hr));
+  Message msg;
+  msg << "Expected: " << expr << " " << expected << ".\n"
+      << "  Actual: " << error_hex << error_text << "\n";
+
+  return ::testing::AssertionFailure(msg);
+}
+
+}  // namespace
+
+AssertionResult IsHRESULTSuccess(const char* expr, long hr) {  // NOLINT
+  if (SUCCEEDED(hr)) {
+    return AssertionSuccess();
+  }
+  return HRESULTFailureHelper(expr, "succeeds", hr);
+}
+
+AssertionResult IsHRESULTFailure(const char* expr, long hr) {  // NOLINT
+  if (FAILED(hr)) {
+    return AssertionSuccess();
+  }
+  return HRESULTFailureHelper(expr, "fails", hr);
+}
+
+#endif  // GTEST_OS_WINDOWS
+
+// Utility functions for encoding Unicode text (wide strings) in
+// UTF-8.
+
+// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
+// like this:
+//
+// Code-point length   Encoding
+//   0 -  7 bits       0xxxxxxx
+//   8 - 11 bits       110xxxxx 10xxxxxx
+//  12 - 16 bits       1110xxxx 10xxxxxx 10xxxxxx
+//  17 - 21 bits       11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+// The maximum code-point a one-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) <<  7) - 1;
+
+// The maximum code-point a two-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;
+
+// The maximum code-point a three-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;
+
+// The maximum code-point a four-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;
+
+// Chops off the n lowest bits from a bit pattern.  Returns the n
+// lowest bits.  As a side effect, the original bit pattern will be
+// shifted to the right by n bits.
+inline UInt32 ChopLowBits(UInt32* bits, int n) {
+  const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
+  *bits >>= n;
+  return low_bits;
+}
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// The output buffer str must containt at least 32 characters.
+// The function returns the address of the output buffer.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'.
+char* CodePointToUtf8(UInt32 code_point, char* str) {
+  if (code_point <= kMaxCodePoint1) {
+    str[1] = '\0';
+    str[0] = static_cast<char>(code_point);                          // 0xxxxxxx
+  } else if (code_point <= kMaxCodePoint2) {
+    str[2] = '\0';
+    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[0] = static_cast<char>(0xC0 | code_point);                   // 110xxxxx
+  } else if (code_point <= kMaxCodePoint3) {
+    str[3] = '\0';
+    str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[0] = static_cast<char>(0xE0 | code_point);                   // 1110xxxx
+  } else if (code_point <= kMaxCodePoint4) {
+    str[4] = '\0';
+    str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6));  // 10xxxxxx
+    str[0] = static_cast<char>(0xF0 | code_point);                   // 11110xxx
+  } else {
+    // The longest string String::Format can produce when invoked
+    // with these parameters is 28 character long (not including
+    // the terminating nul character). We are asking for 32 character
+    // buffer just in case. This is also enough for strncpy to
+    // null-terminate the destination string.
+    posix::StrNCpy(
+        str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32);
+    str[31] = '\0';  // Makes sure no change in the format to strncpy leaves
+                     // the result unterminated.
+  }
+  return str;
+}
+
+// The following two functions only make sense if the the system
+// uses UTF-16 for wide string encoding. All supported systems
+// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.
+
+// Determines if the arguments constitute UTF-16 surrogate pair
+// and thus should be combined into a single Unicode code point
+// using CreateCodePointFromUtf16SurrogatePair.
+inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {
+  return sizeof(wchar_t) == 2 &&
+      (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;
+}
+
+// Creates a Unicode code point from UTF16 surrogate pair.
+inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
+                                                    wchar_t second) {
+  const UInt32 mask = (1 << 10) - 1;
+  return (sizeof(wchar_t) == 2) ?
+      (((first & mask) << 10) | (second & mask)) + 0x10000 :
+      // This function should not be called when the condition is
+      // false, but we provide a sensible default in case it is.
+      static_cast<UInt32>(first);
+}
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+//   UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+//   UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+String WideStringToUtf8(const wchar_t* str, int num_chars) {
+  if (num_chars == -1)
+    num_chars = static_cast<int>(wcslen(str));
+
+  StrStream stream;
+  for (int i = 0; i < num_chars; ++i) {
+    UInt32 unicode_code_point;
+
+    if (str[i] == L'\0') {
+      break;
+    } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {
+      unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],
+                                                                 str[i + 1]);
+      i++;
+    } else {
+      unicode_code_point = static_cast<UInt32>(str[i]);
+    }
+
+    char buffer[32];  // CodePointToUtf8 requires a buffer this big.
+    stream << CodePointToUtf8(unicode_code_point, buffer);
+  }
+  return StrStreamToString(&stream);
+}
+
+// Converts a wide C string to a String using the UTF-8 encoding.
+// NULL will be converted to "(null)".
+String String::ShowWideCString(const wchar_t * wide_c_str) {
+  if (wide_c_str == NULL) return String("(null)");
+
+  return String(internal::WideStringToUtf8(wide_c_str, -1).c_str());
+}
+
+// Similar to ShowWideCString(), except that this function encloses
+// the converted string in double quotes.
+String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) {
+  if (wide_c_str == NULL) return String("(null)");
+
+  return String::Format("L\"%s\"",
+                        String::ShowWideCString(wide_c_str).c_str());
+}
+
+// Compares two wide C strings.  Returns true iff they have the same
+// content.
+//
+// Unlike wcscmp(), this function can handle NULL argument(s).  A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
+  if (lhs == NULL) return rhs == NULL;
+
+  if (rhs == NULL) return false;
+
+  return wcscmp(lhs, rhs) == 0;
+}
+
+// Helper function for *_STREQ on wide strings.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+                               const char* actual_expression,
+                               const wchar_t* expected,
+                               const wchar_t* actual) {
+  if (String::WideCStringEquals(expected, actual)) {
+    return AssertionSuccess();
+  }
+
+  return EqFailure(expected_expression,
+                   actual_expression,
+                   String::ShowWideCStringQuoted(expected),
+                   String::ShowWideCStringQuoted(actual),
+                   false);
+}
+
+// Helper function for *_STRNE on wide strings.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+                               const char* s2_expression,
+                               const wchar_t* s1,
+                               const wchar_t* s2) {
+  if (!String::WideCStringEquals(s1, s2)) {
+    return AssertionSuccess();
+  }
+
+  Message msg;
+  msg << "Expected: (" << s1_expression << ") != ("
+      << s2_expression << "), actual: "
+      << String::ShowWideCStringQuoted(s1)
+      << " vs " << String::ShowWideCStringQuoted(s2);
+  return AssertionFailure(msg);
+}
+
+// Compares two C strings, ignoring case.  Returns true iff they have
+// the same content.
+//
+// Unlike strcasecmp(), this function can handle NULL argument(s).  A
+// NULL C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
+  if (lhs == NULL)
+    return rhs == NULL;
+  if (rhs == NULL)
+    return false;
+  return posix::StrCaseCmp(lhs, rhs) == 0;
+}
+
+  // Compares two wide C strings, ignoring case.  Returns true iff they
+  // have the same content.
+  //
+  // Unlike wcscasecmp(), this function can handle NULL argument(s).
+  // A NULL C string is considered different to any non-NULL wide C string,
+  // including the empty string.
+  // NB: The implementations on different platforms slightly differ.
+  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+  // environment variable. On GNU platform this method uses wcscasecmp
+  // which compares according to LC_CTYPE category of the current locale.
+  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+  // current locale.
+bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+                                              const wchar_t* rhs) {
+  if ( lhs == NULL ) return rhs == NULL;
+
+  if ( rhs == NULL ) return false;
+
+#if GTEST_OS_WINDOWS
+  return _wcsicmp(lhs, rhs) == 0;
+#elif GTEST_OS_LINUX
+  return wcscasecmp(lhs, rhs) == 0;
+#else
+  // Mac OS X and Cygwin don't define wcscasecmp.  Other unknown OSes
+  // may not define it either.
+  wint_t left, right;
+  do {
+    left = towlower(*lhs++);
+    right = towlower(*rhs++);
+  } while (left && left == right);
+  return left == right;
+#endif  // OS selector
+}
+
+// Constructs a String by copying a given number of chars from a
+// buffer.  E.g. String("hello", 3) will create the string "hel".
+String::String(const char * buffer, size_t len) {
+  char * const temp = new char[ len + 1 ];
+  memcpy(temp, buffer, len);
+  temp[ len ] = '\0';
+  c_str_ = temp;
+}
+
+// Compares this with another String.
+// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
+// if this is greater than rhs.
+int String::Compare(const String & rhs) const {
+  if ( c_str_ == NULL ) {
+    return rhs.c_str_ == NULL ? 0 : -1;  // NULL < anything except NULL
+  }
+
+  return rhs.c_str_ == NULL ? 1 : strcmp(c_str_, rhs.c_str_);
+}
+
+// Returns true iff this String ends with the given suffix.  *Any*
+// String is considered to end with a NULL or empty suffix.
+bool String::EndsWith(const char* suffix) const {
+  if (suffix == NULL || CStringEquals(suffix, "")) return true;
+
+  if (c_str_ == NULL) return false;
+
+  const size_t this_len = strlen(c_str_);
+  const size_t suffix_len = strlen(suffix);
+  return (this_len >= suffix_len) &&
+         CStringEquals(c_str_ + this_len - suffix_len, suffix);
+}
+
+// Returns true iff this String ends with the given suffix, ignoring case.
+// Any String is considered to end with a NULL or empty suffix.
+bool String::EndsWithCaseInsensitive(const char* suffix) const {
+  if (suffix == NULL || CStringEquals(suffix, "")) return true;
+
+  if (c_str_ == NULL) return false;
+
+  const size_t this_len = strlen(c_str_);
+  const size_t suffix_len = strlen(suffix);
+  return (this_len >= suffix_len) &&
+         CaseInsensitiveCStringEquals(c_str_ + this_len - suffix_len, suffix);
+}
+
+// Sets the 0-terminated C string this String object represents.  The
+// old string in this object is deleted, and this object will own a
+// clone of the input string.  This function copies only up to length
+// bytes (plus a terminating null byte), or until the first null byte,
+// whichever comes first.
+//
+// This function works even when the c_str parameter has the same
+// value as that of the c_str_ field.
+void String::Set(const char * c_str, size_t length) {
+  // Makes sure this works when c_str == c_str_
+  const char* const temp = CloneString(c_str, length);
+  delete[] c_str_;
+  c_str_ = temp;
+}
+
+// Assigns a C string to this object.  Self-assignment works.
+const String& String::operator=(const char* c_str) {
+  // Makes sure this works when c_str == c_str_
+  if (c_str != c_str_) {
+    delete[] c_str_;
+    c_str_ = CloneCString(c_str);
+  }
+  return *this;
+}
+
+// Formats a list of arguments to a String, using the same format
+// spec string as for printf.
+//
+// We do not use the StringPrintf class as it is not universally
+// available.
+//
+// The result is limited to 4096 characters (including the tailing 0).
+// If 4096 characters are not enough to format the input,
+// "<buffer exceeded>" is returned.
+String String::Format(const char * format, ...) {
+  va_list args;
+  va_start(args, format);
+
+  char buffer[4096];
+  // MSVC 8 deprecates vsnprintf(), so we want to suppress warning
+  // 4996 (deprecated function) there.
+#ifdef _MSC_VER  // We are using MSVC.
+#pragma warning(push)          // Saves the current warning state.
+#pragma warning(disable:4996)  // Temporarily disables warning 4996.
+  const int size =
+    vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args);
+#pragma warning(pop)           // Restores the warning state.
+#else  // We are not using MSVC.
+  const int size =
+    vsnprintf(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, format, args);
+#endif  // _MSC_VER
+  va_end(args);
+
+  return String(size >= 0 ? buffer : "<buffer exceeded>");
+}
+
+// Converts the buffer in a StrStream to a String, converting NUL
+// bytes to "\\0" along the way.
+String StrStreamToString(StrStream* ss) {
+#if GTEST_HAS_STD_STRING
+  const ::std::string& str = ss->str();
+  const char* const start = str.c_str();
+  const char* const end = start + str.length();
+#else
+  const char* const start = ss->str();
+  const char* const end = start + ss->pcount();
+#endif  // GTEST_HAS_STD_STRING
+
+  // We need to use a helper StrStream to do this transformation
+  // because String doesn't support push_back().
+  StrStream helper;
+  for (const char* ch = start; ch != end; ++ch) {
+    if (*ch == '\0') {
+      helper << "\\0";  // Replaces NUL with "\\0";
+    } else {
+      helper.put(*ch);
+    }
+  }
+
+#if GTEST_HAS_STD_STRING
+  return String(helper.str().c_str());
+#else
+  const String str(helper.str(), helper.pcount());
+  helper.freeze(false);
+  ss->freeze(false);
+  return str;
+#endif  // GTEST_HAS_STD_STRING
+}
+
+// Appends the user-supplied message to the Google-Test-generated message.
+String AppendUserMessage(const String& gtest_msg,
+                         const Message& user_msg) {
+  // Appends the user message if it's non-empty.
+  const String user_msg_string = user_msg.GetString();
+  if (user_msg_string.empty()) {
+    return gtest_msg;
+  }
+
+  Message msg;
+  msg << gtest_msg << "\n" << user_msg_string;
+
+  return msg.GetString();
+}
+
+// class TestResult
+
+// Creates an empty TestResult.
+TestResult::TestResult()
+    : death_test_count_(0),
+      elapsed_time_(0) {
+}
+
+// D'tor.
+TestResult::~TestResult() {
+}
+
+// Adds a test part result to the list.
+void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
+  test_part_results_.PushBack(test_part_result);
+}
+
+// Adds a test property to the list. If a property with the same key as the
+// supplied property is already represented, the value of this test_property
+// replaces the old value for that key.
+void TestResult::RecordProperty(const TestProperty& test_property) {
+  if (!ValidateTestProperty(test_property)) {
+    return;
+  }
+  MutexLock lock(&test_properites_mutex_);
+  ListNode<TestProperty>* const node_with_matching_key =
+      test_properties_.FindIf(TestPropertyKeyIs(test_property.key()));
+  if (node_with_matching_key == NULL) {
+    test_properties_.PushBack(test_property);
+    return;
+  }
+  TestProperty& property_with_matching_key = node_with_matching_key->element();
+  property_with_matching_key.SetValue(test_property.value());
+}
+
+// Adds a failure if the key is a reserved attribute of Google Test
+// testcase tags.  Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const TestProperty& test_property) {
+  String key(test_property.key());
+  if (key == "name" || key == "status" || key == "time" || key == "classname") {
+    ADD_FAILURE()
+        << "Reserved key used in RecordProperty(): "
+        << key
+        << " ('name', 'status', 'time', and 'classname' are reserved by "
+        << GTEST_NAME_ << ")";
+    return false;
+  }
+  return true;
+}
+
+// Clears the object.
+void TestResult::Clear() {
+  test_part_results_.Clear();
+  test_properties_.Clear();
+  death_test_count_ = 0;
+  elapsed_time_ = 0;
+}
+
+// Returns true iff the test part passed.
+static bool TestPartPassed(const TestPartResult & result) {
+  return result.passed();
+}
+
+// Gets the number of successful test parts.
+int TestResult::successful_part_count() const {
+  return test_part_results_.CountIf(TestPartPassed);
+}
+
+// Returns true iff the test part failed.
+static bool TestPartFailed(const TestPartResult & result) {
+  return result.failed();
+}
+
+// Gets the number of failed test parts.
+int TestResult::failed_part_count() const {
+  return test_part_results_.CountIf(TestPartFailed);
+}
+
+// Returns true iff the test part fatally failed.
+static bool TestPartFatallyFailed(const TestPartResult& result) {
+  return result.fatally_failed();
+}
+
+// Returns true iff the test fatally failed.
+bool TestResult::HasFatalFailure() const {
+  return test_part_results_.CountIf(TestPartFatallyFailed) > 0;
+}
+
+// Returns true iff the test part non-fatally failed.
+static bool TestPartNonfatallyFailed(const TestPartResult& result) {
+  return result.nonfatally_failed();
+}
+
+// Returns true iff the test has a non-fatal failure.
+bool TestResult::HasNonfatalFailure() const {
+  return test_part_results_.CountIf(TestPartNonfatallyFailed) > 0;
+}
+
+// Gets the number of all test parts.  This is the sum of the number
+// of successful test parts and the number of failed test parts.
+int TestResult::total_part_count() const {
+  return test_part_results_.size();
+}
+
+}  // namespace internal
+
+// class Test
+
+// Creates a Test object.
+
+// The c'tor saves the values of all Google Test flags.
+Test::Test()
+    : gtest_flag_saver_(new internal::GTestFlagSaver) {
+}
+
+// The d'tor restores the values of all Google Test flags.
+Test::~Test() {
+  delete gtest_flag_saver_;
+}
+
+// Sets up the test fixture.
+//
+// A sub-class may override this.
+void Test::SetUp() {
+}
+
+// Tears down the test fixture.
+//
+// A sub-class may override this.
+void Test::TearDown() {
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const char* key, const char* value) {
+  UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value);
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const char* key, int value) {
+  Message value_message;
+  value_message << value;
+  RecordProperty(key, value_message.GetString().c_str());
+}
+
+#if GTEST_OS_WINDOWS
+// We are on Windows.
+
+// Adds an "exception thrown" fatal failure to the current test.
+static void AddExceptionThrownFailure(DWORD exception_code,
+                                      const char* location) {
+  Message message;
+  message << "Exception thrown with code 0x" << std::setbase(16) <<
+    exception_code << std::setbase(10) << " in " << location << ".";
+
+  UnitTest* const unit_test = UnitTest::GetInstance();
+  unit_test->AddTestPartResult(
+      TPRT_FATAL_FAILURE,
+      static_cast<const char *>(NULL),
+           // We have no info about the source file where the exception
+           // occurred.
+      -1,  // We have no info on which line caused the exception.
+      message.GetString(),
+      internal::String(""));
+}
+
+#endif  // GTEST_OS_WINDOWS
+
+// Google Test requires all tests in the same test case to use the same test
+// fixture class.  This function checks if the current test has the
+// same fixture class as the first test in the current test case.  If
+// yes, it returns true; otherwise it generates a Google Test failure and
+// returns false.
+bool Test::HasSameFixtureClass() {
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  const TestCase* const test_case = impl->current_test_case();
+
+  // Info about the first test in the current test case.
+  const internal::TestInfoImpl* const first_test_info =
+      test_case->test_info_list().Head()->element()->impl();
+  const internal::TypeId first_fixture_id = first_test_info->fixture_class_id();
+  const char* const first_test_name = first_test_info->name();
+
+  // Info about the current test.
+  const internal::TestInfoImpl* const this_test_info =
+      impl->current_test_info()->impl();
+  const internal::TypeId this_fixture_id = this_test_info->fixture_class_id();
+  const char* const this_test_name = this_test_info->name();
+
+  if (this_fixture_id != first_fixture_id) {
+    // Is the first test defined using TEST?
+    const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();
+    // Is this test defined using TEST?
+    const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
+
+    if (first_is_TEST || this_is_TEST) {
+      // The user mixed TEST and TEST_F in this test case - we'll tell
+      // him/her how to fix it.
+
+      // Gets the name of the TEST and the name of the TEST_F.  Note
+      // that first_is_TEST and this_is_TEST cannot both be true, as
+      // the fixture IDs are different for the two tests.
+      const char* const TEST_name =
+          first_is_TEST ? first_test_name : this_test_name;
+      const char* const TEST_F_name =
+          first_is_TEST ? this_test_name : first_test_name;
+
+      ADD_FAILURE()
+          << "All tests in the same test case must use the same test fixture\n"
+          << "class, so mixing TEST_F and TEST in the same test case is\n"
+          << "illegal.  In test case " << this_test_info->test_case_name()
+          << ",\n"
+          << "test " << TEST_F_name << " is defined using TEST_F but\n"
+          << "test " << TEST_name << " is defined using TEST.  You probably\n"
+          << "want to change the TEST to TEST_F or move it to another test\n"
+          << "case.";
+    } else {
+      // The user defined two fixture classes with the same name in
+      // two namespaces - we'll tell him/her how to fix it.
+      ADD_FAILURE()
+          << "All tests in the same test case must use the same test fixture\n"
+          << "class.  However, in test case "
+          << this_test_info->test_case_name() << ",\n"
+          << "you defined test " << first_test_name
+          << " and test " << this_test_name << "\n"
+          << "using two different test fixture classes.  This can happen if\n"
+          << "the two classes are from different namespaces or translation\n"
+          << "units and have the same name.  You should probably rename one\n"
+          << "of the classes to put the tests into different test cases.";
+    }
+    return false;
+  }
+
+  return true;
+}
+
+// Runs the test and updates the test result.
+void Test::Run() {
+  if (!HasSameFixtureClass()) return;
+
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+#if GTEST_HAS_SEH
+  // Catch SEH-style exceptions.
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  __try {
+    SetUp();
+  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+      GetExceptionCode())) {
+    AddExceptionThrownFailure(GetExceptionCode(), "SetUp()");
+  }
+
+  // We will run the test only if SetUp() had no fatal failure.
+  if (!HasFatalFailure()) {
+    impl->os_stack_trace_getter()->UponLeavingGTest();
+    __try {
+      TestBody();
+    } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+        GetExceptionCode())) {
+      AddExceptionThrownFailure(GetExceptionCode(), "the test body");
+    }
+  }
+
+  // However, we want to clean up as much as possible.  Hence we will
+  // always call TearDown(), even if SetUp() or the test body has
+  // failed.
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  __try {
+    TearDown();
+  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+      GetExceptionCode())) {
+    AddExceptionThrownFailure(GetExceptionCode(), "TearDown()");
+  }
+
+#else  // We are on a compiler or platform that doesn't support SEH.
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  SetUp();
+
+  // We will run the test only if SetUp() was successful.
+  if (!HasFatalFailure()) {
+    impl->os_stack_trace_getter()->UponLeavingGTest();
+    TestBody();
+  }
+
+  // However, we want to clean up as much as possible.  Hence we will
+  // always call TearDown(), even if SetUp() or the test body has
+  // failed.
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  TearDown();
+#endif  // GTEST_HAS_SEH
+}
+
+
+// Returns true iff the current test has a fatal failure.
+bool Test::HasFatalFailure() {
+  return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
+}
+
+// Returns true iff the current test has a non-fatal failure.
+bool Test::HasNonfatalFailure() {
+  return internal::GetUnitTestImpl()->current_test_result()->
+      HasNonfatalFailure();
+}
+
+// class TestInfo
+
+// Constructs a TestInfo object. It assumes ownership of the test factory
+// object via impl_.
+TestInfo::TestInfo(const char* test_case_name,
+                   const char* name,
+                   const char* test_case_comment,
+                   const char* comment,
+                   internal::TypeId fixture_class_id,
+                   internal::TestFactoryBase* factory) {
+  impl_ = new internal::TestInfoImpl(this, test_case_name, name,
+                                     test_case_comment, comment,
+                                     fixture_class_id, factory);
+}
+
+// Destructs a TestInfo object.
+TestInfo::~TestInfo() {
+  delete impl_;
+}
+
+namespace internal {
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+//   test_case_name:   name of the test case
+//   name:             name of the test
+//   test_case_comment: a comment on the test case that will be included in
+//                      the test output
+//   comment:          a comment on the test that will be included in the
+//                     test output
+//   fixture_class_id: ID of the test fixture class
+//   set_up_tc:        pointer to the function that sets up the test case
+//   tear_down_tc:     pointer to the function that tears down the test case
+//   factory:          pointer to the factory that creates a test object.
+//                     The newly created TestInfo instance will assume
+//                     ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+    const char* test_case_name, const char* name,
+    const char* test_case_comment, const char* comment,
+    TypeId fixture_class_id,
+    SetUpTestCaseFunc set_up_tc,
+    TearDownTestCaseFunc tear_down_tc,
+    TestFactoryBase* factory) {
+  TestInfo* const test_info =
+      new TestInfo(test_case_name, name, test_case_comment, comment,
+                   fixture_class_id, factory);
+  GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
+  return test_info;
+}
+
+#if GTEST_HAS_PARAM_TEST
+void ReportInvalidTestCaseType(const char* test_case_name,
+                               const char* file, int line) {
+  Message errors;
+  errors
+      << "Attempted redefinition of test case " << test_case_name << ".\n"
+      << "All tests in the same test case must use the same test fixture\n"
+      << "class.  However, in test case " << test_case_name << ", you tried\n"
+      << "to define a test using a fixture class different from the one\n"
+      << "used earlier. This can happen if the two fixture classes are\n"
+      << "from different namespaces and have the same name. You should\n"
+      << "probably rename one of the classes to put the tests into different\n"
+      << "test cases.";
+
+  fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+          errors.GetString().c_str());
+}
+#endif  // GTEST_HAS_PARAM_TEST
+
+}  // namespace internal
+
+// Returns the test case name.
+const char* TestInfo::test_case_name() const {
+  return impl_->test_case_name();
+}
+
+// Returns the test name.
+const char* TestInfo::name() const {
+  return impl_->name();
+}
+
+// Returns the test case comment.
+const char* TestInfo::test_case_comment() const {
+  return impl_->test_case_comment();
+}
+
+// Returns the test comment.
+const char* TestInfo::comment() const {
+  return impl_->comment();
+}
+
+// Returns true if this test should run.
+bool TestInfo::should_run() const { return impl_->should_run(); }
+
+// Returns true if this test matches the user-specified filter.
+bool TestInfo::matches_filter() const { return impl_->matches_filter(); }
+
+// Returns the result of the test.
+const internal::TestResult* TestInfo::result() const { return impl_->result(); }
+
+// Increments the number of death tests encountered in this test so
+// far.
+int TestInfo::increment_death_test_count() {
+  return impl_->result()->increment_death_test_count();
+}
+
+namespace {
+
+// A predicate that checks the test name of a TestInfo against a known
+// value.
+//
+// This is used for implementation of the TestCase class only.  We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestNameIs is copyable.
+class TestNameIs {
+ public:
+  // Constructor.
+  //
+  // TestNameIs has NO default constructor.
+  explicit TestNameIs(const char* name)
+      : name_(name) {}
+
+  // Returns true iff the test name of test_info matches name_.
+  bool operator()(const TestInfo * test_info) const {
+    return test_info && internal::String(test_info->name()).Compare(name_) == 0;
+  }
+
+ private:
+  internal::String name_;
+};
+
+}  // namespace
+
+// Finds and returns a TestInfo with the given name.  If one doesn't
+// exist, returns NULL.
+TestInfo * TestCase::GetTestInfo(const char* test_name) {
+  // Can we find a TestInfo with the given name?
+  internal::ListNode<TestInfo *> * const node = test_info_list_->FindIf(
+      TestNameIs(test_name));
+
+  // Returns the TestInfo found.
+  return node ? node->element() : NULL;
+}
+
+namespace internal {
+
+// This method expands all parameterized tests registered with macros TEST_P
+// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.
+// This will be done just once during the program runtime.
+void UnitTestImpl::RegisterParameterizedTests() {
+#if GTEST_HAS_PARAM_TEST
+  if (!parameterized_tests_registered_) {
+    parameterized_test_registry_.RegisterTests();
+    parameterized_tests_registered_ = true;
+  }
+#endif
+}
+
+// Creates the test object, runs it, records its result, and then
+// deletes it.
+void TestInfoImpl::Run() {
+  if (!should_run_) return;
+
+  // Tells UnitTest where to store test result.
+  UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->set_current_test_info(parent_);
+
+  // Notifies the unit test event listener that a test is about to
+  // start.
+  UnitTestEventListenerInterface* const result_printer =
+    impl->result_printer();
+  result_printer->OnTestStart(parent_);
+
+  const TimeInMillis start = GetTimeInMillis();
+
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+#if GTEST_HAS_SEH
+  // Catch SEH-style exceptions.
+  Test* test = NULL;
+
+  __try {
+    // Creates the test object.
+    test = factory_->CreateTest();
+  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+      GetExceptionCode())) {
+    AddExceptionThrownFailure(GetExceptionCode(),
+                              "the test fixture's constructor");
+    return;
+  }
+#else  // We are on a compiler or platform that doesn't support SEH.
+
+  // TODO(wan): If test->Run() throws, test won't be deleted.  This is
+  // not a problem now as we don't use exceptions.  If we were to
+  // enable exceptions, we should revise the following to be
+  // exception-safe.
+
+  // Creates the test object.
+  Test* test = factory_->CreateTest();
+#endif  // GTEST_HAS_SEH
+
+  // Runs the test only if the constructor of the test fixture didn't
+  // generate a fatal failure.
+  if (!Test::HasFatalFailure()) {
+    test->Run();
+  }
+
+  // Deletes the test object.
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  delete test;
+  test = NULL;
+
+  result_.set_elapsed_time(GetTimeInMillis() - start);
+
+  // Notifies the unit test event listener that a test has just finished.
+  result_printer->OnTestEnd(parent_);
+
+  // Tells UnitTest to stop associating assertion results to this
+  // test.
+  impl->set_current_test_info(NULL);
+}
+
+}  // namespace internal
+
+// class TestCase
+
+// Gets the number of successful tests in this test case.
+int TestCase::successful_test_count() const {
+  return test_info_list_->CountIf(TestPassed);
+}
+
+// Gets the number of failed tests in this test case.
+int TestCase::failed_test_count() const {
+  return test_info_list_->CountIf(TestFailed);
+}
+
+int TestCase::disabled_test_count() const {
+  return test_info_list_->CountIf(TestDisabled);
+}
+
+// Get the number of tests in this test case that should run.
+int TestCase::test_to_run_count() const {
+  return test_info_list_->CountIf(ShouldRunTest);
+}
+
+// Gets the number of all tests.
+int TestCase::total_test_count() const {
+  return test_info_list_->size();
+}
+
+// Creates a TestCase with the given name.
+//
+// Arguments:
+//
+//   name:         name of the test case
+//   set_up_tc:    pointer to the function that sets up the test case
+//   tear_down_tc: pointer to the function that tears down the test case
+TestCase::TestCase(const char* name, const char* comment,
+                   Test::SetUpTestCaseFunc set_up_tc,
+                   Test::TearDownTestCaseFunc tear_down_tc)
+    : name_(name),
+      comment_(comment),
+      set_up_tc_(set_up_tc),
+      tear_down_tc_(tear_down_tc),
+      should_run_(false),
+      elapsed_time_(0) {
+  test_info_list_ = new internal::List<TestInfo *>;
+}
+
+// Destructor of TestCase.
+TestCase::~TestCase() {
+  // Deletes every Test in the collection.
+  test_info_list_->ForEach(internal::Delete<TestInfo>);
+
+  // Then deletes the Test collection.
+  delete test_info_list_;
+  test_info_list_ = NULL;
+}
+
+// Adds a test to this test case.  Will delete the test upon
+// destruction of the TestCase object.
+void TestCase::AddTestInfo(TestInfo * test_info) {
+  test_info_list_->PushBack(test_info);
+}
+
+// Runs every test in this TestCase.
+void TestCase::Run() {
+  if (!should_run_) return;
+
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->set_current_test_case(this);
+
+  UnitTestEventListenerInterface * const result_printer =
+      impl->result_printer();
+
+  result_printer->OnTestCaseStart(this);
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  set_up_tc_();
+
+  const internal::TimeInMillis start = internal::GetTimeInMillis();
+  test_info_list_->ForEach(internal::TestInfoImpl::RunTest);
+  elapsed_time_ = internal::GetTimeInMillis() - start;
+
+  impl->os_stack_trace_getter()->UponLeavingGTest();
+  tear_down_tc_();
+  result_printer->OnTestCaseEnd(this);
+  impl->set_current_test_case(NULL);
+}
+
+// Clears the results of all tests in this test case.
+void TestCase::ClearResult() {
+  test_info_list_->ForEach(internal::TestInfoImpl::ClearTestResult);
+}
+
+
+// class UnitTestEventListenerInterface
+
+// The virtual d'tor.
+UnitTestEventListenerInterface::~UnitTestEventListenerInterface() {
+}
+
+// A result printer that never prints anything.  Used in the child process
+// of an exec-style death test to avoid needless output clutter.
+class NullUnitTestResultPrinter : public UnitTestEventListenerInterface {};
+
+// Formats a countable noun.  Depending on its quantity, either the
+// singular form or the plural form is used. e.g.
+//
+// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
+// FormatCountableNoun(5, "book", "books") returns "5 books".
+static internal::String FormatCountableNoun(int count,
+                                            const char * singular_form,
+                                            const char * plural_form) {
+  return internal::String::Format("%d %s", count,
+                                  count == 1 ? singular_form : plural_form);
+}
+
+// Formats the count of tests.
+static internal::String FormatTestCount(int test_count) {
+  return FormatCountableNoun(test_count, "test", "tests");
+}
+
+// Formats the count of test cases.
+static internal::String FormatTestCaseCount(int test_case_count) {
+  return FormatCountableNoun(test_case_count, "test case", "test cases");
+}
+
+// Converts a TestPartResultType enum to human-friendly string
+// representation.  Both TPRT_NONFATAL_FAILURE and TPRT_FATAL_FAILURE
+// are translated to "Failure", as the user usually doesn't care about
+// the difference between the two when viewing the test result.
+static const char * TestPartResultTypeToString(TestPartResultType type) {
+  switch (type) {
+    case TPRT_SUCCESS:
+      return "Success";
+
+    case TPRT_NONFATAL_FAILURE:
+    case TPRT_FATAL_FAILURE:
+#ifdef _MSC_VER
+      return "error: ";
+#else
+      return "Failure\n";
+#endif
+  }
+
+  return "Unknown result type";
+}
+
+// Prints a TestPartResult to a String.
+static internal::String PrintTestPartResultToString(
+    const TestPartResult& test_part_result) {
+  return (Message()
+          << internal::FormatFileLocation(test_part_result.file_name(),
+                                          test_part_result.line_number())
+          << " " << TestPartResultTypeToString(test_part_result.type())
+          << test_part_result.message()).GetString();
+}
+
+// Prints a TestPartResult.
+static void PrintTestPartResult(
+    const TestPartResult& test_part_result) {
+  printf("%s\n", PrintTestPartResultToString(test_part_result).c_str());
+  fflush(stdout);
+}
+
+// class PrettyUnitTestResultPrinter
+
+namespace internal {
+
+enum GTestColor {
+  COLOR_DEFAULT,
+  COLOR_RED,
+  COLOR_GREEN,
+  COLOR_YELLOW
+};
+
+#if GTEST_OS_WINDOWS && !defined(_WIN32_WCE)
+
+// Returns the character attribute for the given color.
+WORD GetColorAttribute(GTestColor color) {
+  switch (color) {
+    case COLOR_RED:    return FOREGROUND_RED;
+    case COLOR_GREEN:  return FOREGROUND_GREEN;
+    case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+    default:           return 0;
+  }
+}
+
+#else
+
+// Returns the ANSI color code for the given color.  COLOR_DEFAULT is
+// an invalid input.
+const char* GetAnsiColorCode(GTestColor color) {
+  switch (color) {
+    case COLOR_RED:     return "1";
+    case COLOR_GREEN:   return "2";
+    case COLOR_YELLOW:  return "3";
+    default:            return NULL;
+  };
+}
+
+#endif  // GTEST_OS_WINDOWS && !_WIN32_WCE
+
+// Returns true iff Google Test should use colors in the output.
+bool ShouldUseColor(bool stdout_is_tty) {
+  const char* const gtest_color = GTEST_FLAG(color).c_str();
+
+  if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
+#if GTEST_OS_WINDOWS
+    // On Windows the TERM variable is usually not set, but the
+    // console there does support colors.
+    return stdout_is_tty;
+#else
+    // On non-Windows platforms, we rely on the TERM variable.
+    const char* const term = posix::GetEnv("TERM");
+    const bool term_supports_color =
+        String::CStringEquals(term, "xterm") ||
+        String::CStringEquals(term, "xterm-color") ||
+        String::CStringEquals(term, "xterm-256color") ||
+        String::CStringEquals(term, "cygwin");
+    return stdout_is_tty && term_supports_color;
+#endif  // GTEST_OS_WINDOWS
+  }
+
+  return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
+      String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
+      String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
+      String::CStringEquals(gtest_color, "1");
+  // We take "yes", "true", "t", and "1" as meaning "yes".  If the
+  // value is neither one of these nor "auto", we treat it as "no" to
+  // be conservative.
+}
+
+// Helpers for printing colored strings to stdout. Note that on Windows, we
+// cannot simply emit special characters and have the terminal change colors.
+// This routine must actually emit the characters rather than return a string
+// that would be colored when printed, as can be done on Linux.
+void ColoredPrintf(GTestColor color, const char* fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+
+#if defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
+  const bool use_color = false;
+#else
+  static const bool in_color_mode =
+      ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
+  const bool use_color = in_color_mode && (color != COLOR_DEFAULT);
+#endif  // defined(_WIN32_WCE) || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
+  // The '!= 0' comparison is necessary to satisfy MSVC 7.1.
+
+  if (!use_color) {
+    vprintf(fmt, args);
+    va_end(args);
+    return;
+  }
+
+#if GTEST_OS_WINDOWS && !defined(_WIN32_WCE)
+  const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+  // Gets the current text color.
+  CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+  GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
+  const WORD old_color_attrs = buffer_info.wAttributes;
+
+  SetConsoleTextAttribute(stdout_handle,
+                          GetColorAttribute(color) | FOREGROUND_INTENSITY);
+  vprintf(fmt, args);
+
+  // Restores the text color.
+  SetConsoleTextAttribute(stdout_handle, old_color_attrs);
+#else
+  printf("\033[0;3%sm", GetAnsiColorCode(color));
+  vprintf(fmt, args);
+  printf("\033[m");  // Resets the terminal to default.
+#endif  // GTEST_OS_WINDOWS && !defined(_WIN32_WCE)
+  va_end(args);
+}
+
+}  // namespace internal
+
+using internal::ColoredPrintf;
+using internal::COLOR_DEFAULT;
+using internal::COLOR_RED;
+using internal::COLOR_GREEN;
+using internal::COLOR_YELLOW;
+
+// This class implements the UnitTestEventListenerInterface interface.
+//
+// Class PrettyUnitTestResultPrinter is copyable.
+class PrettyUnitTestResultPrinter : public UnitTestEventListenerInterface {
+ public:
+  PrettyUnitTestResultPrinter() {}
+  static void PrintTestName(const char * test_case, const char * test) {
+    printf("%s.%s", test_case, test);
+  }
+
+  // The following methods override what's in the
+  // UnitTestEventListenerInterface class.
+  virtual void OnUnitTestStart(const UnitTest * unit_test);
+  virtual void OnGlobalSetUpStart(const UnitTest*);
+  virtual void OnTestCaseStart(const TestCase * test_case);
+  virtual void OnTestCaseEnd(const TestCase * test_case);
+  virtual void OnTestStart(const TestInfo * test_info);
+  virtual void OnNewTestPartResult(const TestPartResult * result);
+  virtual void OnTestEnd(const TestInfo * test_info);
+  virtual void OnGlobalTearDownStart(const UnitTest*);
+  virtual void OnUnitTestEnd(const UnitTest * unit_test);
+
+ private:
+  internal::String test_case_name_;
+};
+
+// Called before the unit test starts.
+void PrettyUnitTestResultPrinter::OnUnitTestStart(
+    const UnitTest * unit_test) {
+  const char * const filter = GTEST_FLAG(filter).c_str();
+
+  // Prints the filter if it's not *.  This reminds the user that some
+  // tests may be skipped.
+  if (!internal::String::CStringEquals(filter, kUniversalFilter)) {
+    ColoredPrintf(COLOR_YELLOW,
+                  "Note: %s filter = %s\n", GTEST_NAME_, filter);
+  }
+
+  if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
+    ColoredPrintf(COLOR_YELLOW,
+                  "Note: This is test shard %s of %s.\n",
+                  internal::posix::GetEnv(kTestShardIndex),
+                  internal::posix::GetEnv(kTestTotalShards));
+  }
+
+  const internal::UnitTestImpl* const impl = unit_test->impl();
+  ColoredPrintf(COLOR_GREEN,  "[==========] ");
+  printf("Running %s from %s.\n",
+         FormatTestCount(impl->test_to_run_count()).c_str(),
+         FormatTestCaseCount(impl->test_case_to_run_count()).c_str());
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnGlobalSetUpStart(const UnitTest*) {
+  ColoredPrintf(COLOR_GREEN,  "[----------] ");
+  printf("Global test environment set-up.\n");
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseStart(
+    const TestCase * test_case) {
+  test_case_name_ = test_case->name();
+  const internal::String counts =
+      FormatCountableNoun(test_case->test_to_run_count(), "test", "tests");
+  ColoredPrintf(COLOR_GREEN, "[----------] ");
+  printf("%s from %s", counts.c_str(), test_case_name_.c_str());
+  if (test_case->comment()[0] == '\0') {
+    printf("\n");
+  } else {
+    printf(", where %s\n", test_case->comment());
+  }
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseEnd(
+    const TestCase * test_case) {
+  if (!GTEST_FLAG(print_time)) return;
+
+  test_case_name_ = test_case->name();
+  const internal::String counts =
+      FormatCountableNoun(test_case->test_to_run_count(), "test", "tests");
+  ColoredPrintf(COLOR_GREEN, "[----------] ");
+  printf("%s from %s (%s ms total)\n\n",
+         counts.c_str(), test_case_name_.c_str(),
+         internal::StreamableToString(test_case->elapsed_time()).c_str());
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo * test_info) {
+  ColoredPrintf(COLOR_GREEN,  "[ RUN      ] ");
+  PrintTestName(test_case_name_.c_str(), test_info->name());
+  if (test_info->comment()[0] == '\0') {
+    printf("\n");
+  } else {
+    printf(", where %s\n", test_info->comment());
+  }
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo * test_info) {
+  if (test_info->result()->Passed()) {
+    ColoredPrintf(COLOR_GREEN, "[       OK ] ");
+  } else {
+    ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
+  }
+  PrintTestName(test_case_name_.c_str(), test_info->name());
+  if (GTEST_FLAG(print_time)) {
+    printf(" (%s ms)\n", internal::StreamableToString(
+           test_info->result()->elapsed_time()).c_str());
+  } else {
+    printf("\n");
+  }
+  fflush(stdout);
+}
+
+// Called after an assertion failure.
+void PrettyUnitTestResultPrinter::OnNewTestPartResult(
+    const TestPartResult * result) {
+  // If the test part succeeded, we don't need to do anything.
+  if (result->type() == TPRT_SUCCESS)
+    return;
+
+  // Print failure message from the assertion (e.g. expected this and got that).
+  PrintTestPartResult(*result);
+  fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnGlobalTearDownStart(const UnitTest*) {
+  ColoredPrintf(COLOR_GREEN,  "[----------] ");
+  printf("Global test environment tear-down\n");
+  fflush(stdout);
+}
+
+namespace internal {
+
+// Internal helper for printing the list of failed tests.
+static void PrintFailedTestsPretty(const UnitTestImpl* impl) {
+  const int failed_test_count = impl->failed_test_count();
+  if (failed_test_count == 0) {
+    return;
+  }
+
+  for (const internal::ListNode<TestCase*>* node = impl->test_cases()->Head();
+       node != NULL; node = node->next()) {
+    const TestCase* const tc = node->element();
+    if (!tc->should_run() || (tc->failed_test_count() == 0)) {
+      continue;
+    }
+    for (const internal::ListNode<TestInfo*>* tinode =
+         tc->test_info_list().Head();
+         tinode != NULL; tinode = tinode->next()) {
+      const TestInfo* const ti = tinode->element();
+      if (!tc->ShouldRunTest(ti) || tc->TestPassed(ti)) {
+        continue;
+      }
+      ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
+      printf("%s.%s", ti->test_case_name(), ti->name());
+      if (ti->test_case_comment()[0] != '\0' ||
+          ti->comment()[0] != '\0') {
+        printf(", where %s", ti->test_case_comment());
+        if (ti->test_case_comment()[0] != '\0' &&
+            ti->comment()[0] != '\0') {
+          printf(" and ");
+        }
+      }
+      printf("%s\n", ti->comment());
+    }
+  }
+}
+
+}  // namespace internal
+
+void PrettyUnitTestResultPrinter::OnUnitTestEnd(
+    const UnitTest * unit_test) {
+  const internal::UnitTestImpl* const impl = unit_test->impl();
+
+  ColoredPrintf(COLOR_GREEN,  "[==========] ");
+  printf("%s from %s ran.",
+         FormatTestCount(impl->test_to_run_count()).c_str(),
+         FormatTestCaseCount(impl->test_case_to_run_count()).c_str());
+  if (GTEST_FLAG(print_time)) {
+    printf(" (%s ms total)",
+           internal::StreamableToString(impl->elapsed_time()).c_str());
+  }
+  printf("\n");
+  ColoredPrintf(COLOR_GREEN,  "[  PASSED  ] ");
+  printf("%s.\n", FormatTestCount(impl->successful_test_count()).c_str());
+
+  int num_failures = impl->failed_test_count();
+  if (!impl->Passed()) {
+    const int failed_test_count = impl->failed_test_count();
+    ColoredPrintf(COLOR_RED,  "[  FAILED  ] ");
+    printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
+    internal::PrintFailedTestsPretty(impl);
+    printf("\n%2d FAILED %s\n", num_failures,
+                        num_failures == 1 ? "TEST" : "TESTS");
+  }
+
+  int num_disabled = impl->disabled_test_count();
+  if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
+    if (!num_failures) {
+      printf("\n");  // Add a spacer if no FAILURE banner is displayed.
+    }
+    ColoredPrintf(COLOR_YELLOW,
+                  "  YOU HAVE %d DISABLED %s\n\n",
+                  num_disabled,
+                  num_disabled == 1 ? "TEST" : "TESTS");
+  }
+  // Ensure that Google Test output is printed before, e.g., heapchecker output.
+  fflush(stdout);
+}
+
+// End PrettyUnitTestResultPrinter
+
+// class UnitTestEventsRepeater
+//
+// This class forwards events to other event listeners.
+class UnitTestEventsRepeater : public UnitTestEventListenerInterface {
+ public:
+  typedef internal::List<UnitTestEventListenerInterface *> Listeners;
+  typedef internal::ListNode<UnitTestEventListenerInterface *> ListenersNode;
+  UnitTestEventsRepeater() {}
+  virtual ~UnitTestEventsRepeater();
+  void AddListener(UnitTestEventListenerInterface *listener);
+
+  virtual void OnUnitTestStart(const UnitTest* unit_test);
+  virtual void OnUnitTestEnd(const UnitTest* unit_test);
+  virtual void OnGlobalSetUpStart(const UnitTest* unit_test);
+  virtual void OnGlobalSetUpEnd(const UnitTest* unit_test);
+  virtual void OnGlobalTearDownStart(const UnitTest* unit_test);
+  virtual void OnGlobalTearDownEnd(const UnitTest* unit_test);
+  virtual void OnTestCaseStart(const TestCase* test_case);
+  virtual void OnTestCaseEnd(const TestCase* test_case);
+  virtual void OnTestStart(const TestInfo* test_info);
+  virtual void OnTestEnd(const TestInfo* test_info);
+  virtual void OnNewTestPartResult(const TestPartResult* result);
+
+ private:
+  Listeners listeners_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestEventsRepeater);
+};
+
+UnitTestEventsRepeater::~UnitTestEventsRepeater() {
+  for (ListenersNode* listener = listeners_.Head();
+       listener != NULL;
+       listener = listener->next()) {
+    delete listener->element();
+  }
+}
+
+void UnitTestEventsRepeater::AddListener(
+    UnitTestEventListenerInterface *listener) {
+  listeners_.PushBack(listener);
+}
+
+// Since the methods are identical, use a macro to reduce boilerplate.
+// This defines a member that repeats the call to all listeners.
+#define GTEST_REPEATER_METHOD_(Name, Type) \
+void UnitTestEventsRepeater::Name(const Type* parameter) { \
+  for (ListenersNode* listener = listeners_.Head(); \
+       listener != NULL; \
+       listener = listener->next()) { \
+    listener->element()->Name(parameter); \
+  } \
+}
+
+GTEST_REPEATER_METHOD_(OnUnitTestStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnUnitTestEnd, UnitTest)
+GTEST_REPEATER_METHOD_(OnGlobalSetUpStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnGlobalSetUpEnd, UnitTest)
+GTEST_REPEATER_METHOD_(OnGlobalTearDownStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnGlobalTearDownEnd, UnitTest)
+GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
+GTEST_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
+GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
+GTEST_REPEATER_METHOD_(OnTestEnd, TestInfo)
+GTEST_REPEATER_METHOD_(OnNewTestPartResult, TestPartResult)
+
+#undef GTEST_REPEATER_METHOD_
+
+// End PrettyUnitTestResultPrinter
+
+// This class generates an XML output file.
+class XmlUnitTestResultPrinter : public UnitTestEventListenerInterface {
+ public:
+  explicit XmlUnitTestResultPrinter(const char* output_file);
+
+  virtual void OnUnitTestEnd(const UnitTest* unit_test);
+
+ private:
+  // Is c a whitespace character that is normalized to a space character
+  // when it appears in an XML attribute value?
+  static bool IsNormalizableWhitespace(char c) {
+    return c == 0x9 || c == 0xA || c == 0xD;
+  }
+
+  // May c appear in a well-formed XML document?
+  static bool IsValidXmlCharacter(char c) {
+    return IsNormalizableWhitespace(c) || c >= 0x20;
+  }
+
+  // Returns an XML-escaped copy of the input string str.  If
+  // is_attribute is true, the text is meant to appear as an attribute
+  // value, and normalizable whitespace is preserved by replacing it
+  // with character references.
+  static internal::String EscapeXml(const char* str,
+                                    bool is_attribute);
+
+  // Convenience wrapper around EscapeXml when str is an attribute value.
+  static internal::String EscapeXmlAttribute(const char* str) {
+    return EscapeXml(str, true);
+  }
+
+  // Convenience wrapper around EscapeXml when str is not an attribute value.
+  static internal::String EscapeXmlText(const char* str) {
+    return EscapeXml(str, false);
+  }
+
+  // Prints an XML representation of a TestInfo object.
+  static void PrintXmlTestInfo(FILE* out,
+                               const char* test_case_name,
+                               const TestInfo* test_info);
+
+  // Prints an XML representation of a TestCase object
+  static void PrintXmlTestCase(FILE* out, const TestCase* test_case);
+
+  // Prints an XML summary of unit_test to output stream out.
+  static void PrintXmlUnitTest(FILE* out, const UnitTest* unit_test);
+
+  // Produces a string representing the test properties in a result as space
+  // delimited XML attributes based on the property key="value" pairs.
+  // When the String is not empty, it includes a space at the beginning,
+  // to delimit this attribute from prior attributes.
+  static internal::String TestPropertiesAsXmlAttributes(
+      const internal::TestResult* result);
+
+  // The output file.
+  const internal::String output_file_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);
+};
+
+// Creates a new XmlUnitTestResultPrinter.
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
+    : output_file_(output_file) {
+  if (output_file_.c_str() == NULL || output_file_.empty()) {
+    fprintf(stderr, "XML output file may not be null\n");
+    fflush(stderr);
+    exit(EXIT_FAILURE);
+  }
+}
+
+// Called after the unit test ends.
+void XmlUnitTestResultPrinter::OnUnitTestEnd(const UnitTest* unit_test) {
+  FILE* xmlout = NULL;
+  internal::FilePath output_file(output_file_);
+  internal::FilePath output_dir(output_file.RemoveFileName());
+
+  if (output_dir.CreateDirectoriesRecursively()) {
+    xmlout = internal::posix::FOpen(output_file_.c_str(), "w");
+  }
+  if (xmlout == NULL) {
+    // TODO(wan): report the reason of the failure.
+    //
+    // We don't do it for now as:
+    //
+    //   1. There is no urgent need for it.
+    //   2. It's a bit involved to make the errno variable thread-safe on
+    //      all three operating systems (Linux, Windows, and Mac OS).
+    //   3. To interpret the meaning of errno in a thread-safe way,
+    //      we need the strerror_r() function, which is not available on
+    //      Windows.
+    fprintf(stderr,
+            "Unable to open file \"%s\"\n",
+            output_file_.c_str());
+    fflush(stderr);
+    exit(EXIT_FAILURE);
+  }
+  PrintXmlUnitTest(xmlout, unit_test);
+  fclose(xmlout);
+}
+
+// Returns an XML-escaped copy of the input string str.  If is_attribute
+// is true, the text is meant to appear as an attribute value, and
+// normalizable whitespace is preserved by replacing it with character
+// references.
+//
+// Invalid XML characters in str, if any, are stripped from the output.
+// It is expected that most, if not all, of the text processed by this
+// module will consist of ordinary English text.
+// If this module is ever modified to produce version 1.1 XML output,
+// most invalid characters can be retained using character references.
+// TODO(wan): It might be nice to have a minimally invasive, human-readable
+// escaping scheme for invalid characters, rather than dropping them.
+internal::String XmlUnitTestResultPrinter::EscapeXml(const char* str,
+                                                     bool is_attribute) {
+  Message m;
+
+  if (str != NULL) {
+    for (const char* src = str; *src; ++src) {
+      switch (*src) {
+        case '<':
+          m << "&lt;";
+          break;
+        case '>':
+          m << "&gt;";
+          break;
+        case '&':
+          m << "&amp;";
+          break;
+        case '\'':
+          if (is_attribute)
+            m << "&apos;";
+          else
+            m << '\'';
+          break;
+        case '"':
+          if (is_attribute)
+            m << "&quot;";
+          else
+            m << '"';
+          break;
+        default:
+          if (IsValidXmlCharacter(*src)) {
+            if (is_attribute && IsNormalizableWhitespace(*src))
+              m << internal::String::Format("&#x%02X;", unsigned(*src));
+            else
+              m << *src;
+          }
+          break;
+      }
+    }
+  }
+
+  return m.GetString();
+}
+
+
+// The following routines generate an XML representation of a UnitTest
+// object.
+//
+// This is how Google Test concepts map to the DTD:
+//
+// <testsuites name="AllTests">        <-- corresponds to a UnitTest object
+//   <testsuite name="testcase-name">  <-- corresponds to a TestCase object
+//     <testcase name="test-name">     <-- corresponds to a TestInfo object
+//       <failure message="...">...</failure>
+//       <failure message="...">...</failure>
+//       <failure message="...">...</failure>
+//                                     <-- individual assertion failures
+//     </testcase>
+//   </testsuite>
+// </testsuites>
+
+namespace internal {
+
+// Formats the given time in milliseconds as seconds.  The returned
+// C-string is owned by this function and cannot be released by the
+// caller.  Calling the function again invalidates the previous
+// result.
+const char* FormatTimeInMillisAsSeconds(TimeInMillis ms) {
+  static String str;
+  str = (Message() << (ms/1000.0)).GetString();
+  return str.c_str();
+}
+
+}  // namespace internal
+
+// Prints an XML representation of a TestInfo object.
+// TODO(wan): There is also value in printing properties with the plain printer.
+void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out,
+                                                const char* test_case_name,
+                                                const TestInfo* test_info) {
+  const internal::TestResult * const result = test_info->result();
+  const internal::List<TestPartResult> &results = result->test_part_results();
+  fprintf(out,
+          "    <testcase name=\"%s\" status=\"%s\" time=\"%s\" "
+          "classname=\"%s\"%s",
+          EscapeXmlAttribute(test_info->name()).c_str(),
+          test_info->should_run() ? "run" : "notrun",
+          internal::FormatTimeInMillisAsSeconds(result->elapsed_time()),
+          EscapeXmlAttribute(test_case_name).c_str(),
+          TestPropertiesAsXmlAttributes(result).c_str());
+
+  int failures = 0;
+  for (const internal::ListNode<TestPartResult>* part_node = results.Head();
+       part_node != NULL;
+       part_node = part_node->next()) {
+    const TestPartResult& part = part_node->element();
+    if (part.failed()) {
+      const internal::String message =
+          internal::String::Format("%s:%d\n%s", part.file_name(),
+                                   part.line_number(), part.message());
+      if (++failures == 1)
+        fprintf(out, ">\n");
+      fprintf(out,
+              "      <failure message=\"%s\" type=\"\"><![CDATA[%s]]>"
+              "</failure>\n",
+              EscapeXmlAttribute(part.summary()).c_str(), message.c_str());
+    }
+  }
+
+  if (failures == 0)
+    fprintf(out, " />\n");
+  else
+    fprintf(out, "    </testcase>\n");
+}
+
+// Prints an XML representation of a TestCase object
+void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out,
+                                                const TestCase* test_case) {
+  fprintf(out,
+          "  <testsuite name=\"%s\" tests=\"%d\" failures=\"%d\" "
+          "disabled=\"%d\" ",
+          EscapeXmlAttribute(test_case->name()).c_str(),
+          test_case->total_test_count(),
+          test_case->failed_test_count(),
+          test_case->disabled_test_count());
+  fprintf(out,
+          "errors=\"0\" time=\"%s\">\n",
+          internal::FormatTimeInMillisAsSeconds(test_case->elapsed_time()));
+  for (const internal::ListNode<TestInfo*>* info_node =
+         test_case->test_info_list().Head();
+       info_node != NULL;
+       info_node = info_node->next()) {
+    PrintXmlTestInfo(out, test_case->name(), info_node->element());
+  }
+  fprintf(out, "  </testsuite>\n");
+}
+
+// Prints an XML summary of unit_test to output stream out.
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
+                                                const UnitTest* unit_test) {
+  const internal::UnitTestImpl* const impl = unit_test->impl();
+  fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+  fprintf(out,
+          "<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
+          "errors=\"0\" time=\"%s\" ",
+          impl->total_test_count(),
+          impl->failed_test_count(),
+          impl->disabled_test_count(),
+          internal::FormatTimeInMillisAsSeconds(impl->elapsed_time()));
+  fprintf(out, "name=\"AllTests\">\n");
+  for (const internal::ListNode<TestCase*>* case_node =
+       impl->test_cases()->Head();
+       case_node != NULL;
+       case_node = case_node->next()) {
+    PrintXmlTestCase(out, case_node->element());
+  }
+  fprintf(out, "</testsuites>\n");
+}
+
+// Produces a string representing the test properties in a result as space
+// delimited XML attributes based on the property key="value" pairs.
+internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
+    const internal::TestResult* result) {
+  using internal::TestProperty;
+  Message attributes;
+  const internal::List<TestProperty>& properties = result->test_properties();
+  for (const internal::ListNode<TestProperty>* property_node =
+       properties.Head();
+       property_node != NULL;
+       property_node = property_node->next()) {
+    const TestProperty& property = property_node->element();
+    attributes << " " << property.key() << "="
+        << "\"" << EscapeXmlAttribute(property.value()) << "\"";
+  }
+  return attributes.GetString();
+}
+
+// End XmlUnitTestResultPrinter
+
+namespace internal {
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+// L < UnitTest::mutex_
+ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) {
+  TraceInfo trace;
+  trace.file = file;
+  trace.line = line;
+  trace.message = message.GetString();
+
+  UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+// L < UnitTest::mutex_
+ScopedTrace::~ScopedTrace() {
+  UnitTest::GetInstance()->PopGTestTrace();
+}
+
+
+// class OsStackTraceGetter
+
+// Returns the current OS stack trace as a String.  Parameters:
+//
+//   max_depth  - the maximum number of stack frames to be included
+//                in the trace.
+//   skip_count - the number of top frames to be skipped; doesn't count
+//                against max_depth.
+//
+// L < mutex_
+// We use "L < mutex_" to denote that the function may acquire mutex_.
+String OsStackTraceGetter::CurrentStackTrace(int, int) {
+  return String("");
+}
+
+// L < mutex_
+void OsStackTraceGetter::UponLeavingGTest() {
+}
+
+const char* const
+OsStackTraceGetter::kElidedFramesMarker =
+    "... " GTEST_NAME_ " internal frames ...";
+
+}  // namespace internal
+
+// class UnitTest
+
+// Gets the singleton UnitTest object.  The first time this method is
+// called, a UnitTest object is constructed and returned.  Consecutive
+// calls will return the same object.
+//
+// We don't protect this under mutex_ as a user is not supposed to
+// call this before main() starts, from which point on the return
+// value will never change.
+UnitTest * UnitTest::GetInstance() {
+  // When compiled with MSVC 7.1 in optimized mode, destroying the
+  // UnitTest object upon exiting the program messes up the exit code,
+  // causing successful tests to appear failed.  We have to use a
+  // different implementation in this case to bypass the compiler bug.
+  // This implementation makes the compiler happy, at the cost of
+  // leaking the UnitTest object.
+
+  // CodeGear C++Builder insists on a public destructor for the
+  // default implementation.  Use this implementation to keep good OO
+  // design with private destructor.
+
+#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+  static UnitTest* const instance = new UnitTest;
+  return instance;
+#else
+  static UnitTest instance;
+  return &instance;
+#endif  // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+}
+
+// Registers and returns a global test environment.  When a test
+// program is run, all global test environments will be set-up in the
+// order they were registered.  After all tests in the program have
+// finished, all global test environments will be torn-down in the
+// *reverse* order they were registered.
+//
+// The UnitTest object takes ownership of the given environment.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+Environment* UnitTest::AddEnvironment(Environment* env) {
+  if (env == NULL) {
+    return NULL;
+  }
+
+  impl_->environments()->PushBack(env);
+  impl_->environments_in_reverse_order()->PushFront(env);
+  return env;
+}
+
+#if GTEST_HAS_EXCEPTIONS
+// A failed Google Test assertion will throw an exception of this type
+// when exceptions are enabled.  We derive it from std::runtime_error,
+// which is for errors presumably detectable only at run time.  Since
+// std::runtime_error inherits from std::exception, many testing
+// frameworks know how to extract and print the message inside it.
+class GoogleTestFailureException : public ::std::runtime_error {
+ public:
+  explicit GoogleTestFailureException(const TestPartResult& failure)
+      : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
+};
+#endif
+
+// Adds a TestPartResult to the current TestResult object.  All Google Test
+// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
+// this to report their results.  The user code should use the
+// assertion macros instead of calling this directly.
+// L < mutex_
+void UnitTest::AddTestPartResult(TestPartResultType result_type,
+                                 const char* file_name,
+                                 int line_number,
+                                 const internal::String& message,
+                                 const internal::String& os_stack_trace) {
+  Message msg;
+  msg << message;
+
+  internal::MutexLock lock(&mutex_);
+  if (impl_->gtest_trace_stack()->size() > 0) {
+    msg << "\n" << GTEST_NAME_ << " trace:";
+
+    for (internal::ListNode<internal::TraceInfo>* node =
+         impl_->gtest_trace_stack()->Head();
+         node != NULL;
+         node = node->next()) {
+      const internal::TraceInfo& trace = node->element();
+      msg << "\n" << trace.file << ":" << trace.line << ": " << trace.message;
+    }
+  }
+
+  if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
+    msg << internal::kStackTraceMarker << os_stack_trace;
+  }
+
+  const TestPartResult result =
+    TestPartResult(result_type, file_name, line_number,
+                   msg.GetString().c_str());
+  impl_->GetTestPartResultReporterForCurrentThread()->
+      ReportTestPartResult(result);
+
+  if (result_type != TPRT_SUCCESS) {
+    // gtest_break_on_failure takes precedence over
+    // gtest_throw_on_failure.  This allows a user to set the latter
+    // in the code (perhaps in order to use Google Test assertions
+    // with another testing framework) and specify the former on the
+    // command line for debugging.
+    if (GTEST_FLAG(break_on_failure)) {
+#if GTEST_OS_WINDOWS
+      // Using DebugBreak on Windows allows gtest to still break into a debugger
+      // when a failure happens and both the --gtest_break_on_failure and
+      // the --gtest_catch_exceptions flags are specified.
+      DebugBreak();
+#else
+      *static_cast<int*>(NULL) = 1;
+#endif  // GTEST_OS_WINDOWS
+    } else if (GTEST_FLAG(throw_on_failure)) {
+#if GTEST_HAS_EXCEPTIONS
+      throw GoogleTestFailureException(result);
+#else
+      // We cannot call abort() as it generates a pop-up in debug mode
+      // that cannot be suppressed in VC 7.1 or below.
+      exit(1);
+#endif
+    }
+  }
+}
+
+// Creates and adds a property to the current TestResult. If a property matching
+// the supplied value already exists, updates its value instead.
+void UnitTest::RecordPropertyForCurrentTest(const char* key,
+                                            const char* value) {
+  const internal::TestProperty test_property(key, value);
+  impl_->current_test_result()->RecordProperty(test_property);
+}
+
+// Runs all tests in this UnitTest object and prints the result.
+// Returns 0 if successful, or 1 otherwise.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+int UnitTest::Run() {
+#if GTEST_HAS_SEH
+  // Catch SEH-style exceptions.
+
+  const bool in_death_test_child_process =
+      internal::GTEST_FLAG(internal_run_death_test).GetLength() > 0;
+
+  // Either the user wants Google Test to catch exceptions thrown by the
+  // tests or this is executing in the context of death test child
+  // process. In either case the user does not want to see pop-up dialogs
+  // about crashes - they are expected..
+  if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) {
+#if !defined(_WIN32_WCE)
+    // SetErrorMode doesn't exist on CE.
+    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
+                 SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+#endif  // _WIN32_WCE
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+    // Death test children can be terminated with _abort().  On Windows,
+    // _abort() can show a dialog with a warning message.  This forces the
+    // abort message to go to stderr instead.
+    _set_error_mode(_OUT_TO_STDERR);
+#endif
+
+#if _MSC_VER >= 1400
+    // In the debug version, Visual Studio pops up a separate dialog
+    // offering a choice to debug the aborted program. We need to suppress
+    // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
+    // executed. Google Test will notify the user of any unexpected
+    // failure via stderr.
+    //
+    // VC++ doesn't define _set_abort_behavior() prior to the version 8.0.
+    // Users of prior VC versions shall suffer the agony and pain of
+    // clicking through the countless debug dialogs.
+    // TODO(vladl@google.com): find a way to suppress the abort dialog() in the
+    // debug mode when compiled with VC 7.1 or lower.
+    if (!GTEST_FLAG(break_on_failure))
+      _set_abort_behavior(
+          0x0,                                    // Clear the following flags:
+          _WRITE_ABORT_MSG | _CALL_REPORTFAULT);  // pop-up window, core dump.
+#endif  // _MSC_VER >= 1400
+  }
+
+  __try {
+    return impl_->RunAllTests();
+  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+      GetExceptionCode())) {
+    printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode());
+    fflush(stdout);
+    return 1;
+  }
+
+#else  // We are on a compiler or platform that doesn't support SEH.
+
+  return impl_->RunAllTests();
+#endif  // GTEST_HAS_SEH
+}
+
+// Returns the working directory when the first TEST() or TEST_F() was
+// executed.
+const char* UnitTest::original_working_dir() const {
+  return impl_->original_working_dir_.c_str();
+}
+
+// Returns the TestCase object for the test that's currently running,
+// or NULL if no test is running.
+// L < mutex_
+const TestCase* UnitTest::current_test_case() const {
+  internal::MutexLock lock(&mutex_);
+  return impl_->current_test_case();
+}
+
+// Returns the TestInfo object for the test that's currently running,
+// or NULL if no test is running.
+// L < mutex_
+const TestInfo* UnitTest::current_test_info() const {
+  internal::MutexLock lock(&mutex_);
+  return impl_->current_test_info();
+}
+
+#if GTEST_HAS_PARAM_TEST
+// Returns ParameterizedTestCaseRegistry object used to keep track of
+// value-parameterized tests and instantiate and register them.
+// L < mutex_
+internal::ParameterizedTestCaseRegistry&
+    UnitTest::parameterized_test_registry() {
+  return impl_->parameterized_test_registry();
+}
+#endif  // GTEST_HAS_PARAM_TEST
+
+// Creates an empty UnitTest.
+UnitTest::UnitTest() {
+  impl_ = new internal::UnitTestImpl(this);
+}
+
+// Destructor of UnitTest.
+UnitTest::~UnitTest() {
+  delete impl_;
+}
+
+// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+// Google Test trace stack.
+// L < mutex_
+void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) {
+  internal::MutexLock lock(&mutex_);
+  impl_->gtest_trace_stack()->PushFront(trace);
+}
+
+// Pops a trace from the per-thread Google Test trace stack.
+// L < mutex_
+void UnitTest::PopGTestTrace() {
+  internal::MutexLock lock(&mutex_);
+  impl_->gtest_trace_stack()->PopFront(NULL);
+}
+
+namespace internal {
+
+UnitTestImpl::UnitTestImpl(UnitTest* parent)
+    : parent_(parent),
+#ifdef _MSC_VER
+#pragma warning(push)                    // Saves the current warning state.
+#pragma warning(disable:4355)            // Temporarily disables warning 4355
+                                         // (using this in initializer).
+      default_global_test_part_result_reporter_(this),
+      default_per_thread_test_part_result_reporter_(this),
+#pragma warning(pop)                     // Restores the warning state again.
+#else
+      default_global_test_part_result_reporter_(this),
+      default_per_thread_test_part_result_reporter_(this),
+#endif  // _MSC_VER
+      global_test_part_result_repoter_(
+          &default_global_test_part_result_reporter_),
+      per_thread_test_part_result_reporter_(
+          &default_per_thread_test_part_result_reporter_),
+      test_cases_(),
+#if GTEST_HAS_PARAM_TEST
+      parameterized_test_registry_(),
+      parameterized_tests_registered_(false),
+#endif  // GTEST_HAS_PARAM_TEST
+      last_death_test_case_(NULL),
+      current_test_case_(NULL),
+      current_test_info_(NULL),
+      ad_hoc_test_result_(),
+      result_printer_(NULL),
+      os_stack_trace_getter_(NULL),
+#if GTEST_HAS_DEATH_TEST
+      elapsed_time_(0),
+      internal_run_death_test_flag_(NULL),
+      death_test_factory_(new DefaultDeathTestFactory) {
+#else
+      elapsed_time_(0) {
+#endif  // GTEST_HAS_DEATH_TEST
+}
+
+UnitTestImpl::~UnitTestImpl() {
+  // Deletes every TestCase.
+  test_cases_.ForEach(internal::Delete<TestCase>);
+
+  // Deletes every Environment.
+  environments_.ForEach(internal::Delete<Environment>);
+
+  // Deletes the current test result printer.
+  delete result_printer_;
+
+  delete os_stack_trace_getter_;
+}
+
+// A predicate that checks the name of a TestCase against a known
+// value.
+//
+// This is used for implementation of the UnitTest class only.  We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestCaseNameIs is copyable.
+class TestCaseNameIs {
+ public:
+  // Constructor.
+  explicit TestCaseNameIs(const String& name)
+      : name_(name) {}
+
+  // Returns true iff the name of test_case matches name_.
+  bool operator()(const TestCase* test_case) const {
+    return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
+  }
+
+ private:
+  String name_;
+};
+
+// Finds and returns a TestCase with the given name.  If one doesn't
+// exist, creates one and returns it.
+//
+// Arguments:
+//
+//   test_case_name: name of the test case
+//   set_up_tc:      pointer to the function that sets up the test case
+//   tear_down_tc:   pointer to the function that tears down the test case
+TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
+                                    const char* comment,
+                                    Test::SetUpTestCaseFunc set_up_tc,
+                                    Test::TearDownTestCaseFunc tear_down_tc) {
+  // Can we find a TestCase with the given name?
+  internal::ListNode<TestCase*>* node = test_cases_.FindIf(
+      TestCaseNameIs(test_case_name));
+
+  if (node == NULL) {
+    // No.  Let's create one.
+    TestCase* const test_case =
+      new TestCase(test_case_name, comment, set_up_tc, tear_down_tc);
+
+    // Is this a death test case?
+    if (internal::UnitTestOptions::MatchesFilter(String(test_case_name),
+                                                 kDeathTestCaseFilter)) {
+      // Yes.  Inserts the test case after the last death test case
+      // defined so far.
+      node = test_cases_.InsertAfter(last_death_test_case_, test_case);
+      last_death_test_case_ = node;
+    } else {
+      // No.  Appends to the end of the list.
+      test_cases_.PushBack(test_case);
+      node = test_cases_.Last();
+    }
+  }
+
+  // Returns the TestCase found.
+  return node->element();
+}
+
+// Helpers for setting up / tearing down the given environment.  They
+// are for use in the List::ForEach() method.
+static void SetUpEnvironment(Environment* env) { env->SetUp(); }
+static void TearDownEnvironment(Environment* env) { env->TearDown(); }
+
+// Runs all tests in this UnitTest object, prints the result, and
+// returns 0 if all tests are successful, or 1 otherwise.  If any
+// exception is thrown during a test on Windows, this test is
+// considered to be failed, but the rest of the tests will still be
+// run.  (We disable exceptions on Linux and Mac OS X, so the issue
+// doesn't apply there.)
+// When parameterized tests are enabled, it explands and registers
+// parameterized tests first in RegisterParameterizedTests().
+// All other functions called from RunAllTests() may safely assume that
+// parameterized tests are ready to be counted and run.
+int UnitTestImpl::RunAllTests() {
+  // Makes sure InitGoogleTest() was called.
+  if (!GTestIsInitialized()) {
+    printf("%s",
+           "\nThis test program did NOT call ::testing::InitGoogleTest "
+           "before calling RUN_ALL_TESTS().  Please fix it.\n");
+    return 1;
+  }
+
+  // Do not run any test if the --help flag was specified.
+  if (g_help_flag)
+    return 0;
+
+  RegisterParameterizedTests();
+
+  // Even if sharding is not on, test runners may want to use the
+  // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
+  // protocol.
+  internal::WriteToShardStatusFileIfNeeded();
+
+  // True iff we are in a subprocess for running a thread-safe-style
+  // death test.
+  bool in_subprocess_for_death_test = false;
+
+#if GTEST_HAS_DEATH_TEST
+  internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
+  in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+#endif  // GTEST_HAS_DEATH_TEST
+
+  UnitTestEventListenerInterface * const printer = result_printer();
+
+  const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
+                                        in_subprocess_for_death_test);
+
+  // Compares the full test names with the filter to decide which
+  // tests to run.
+  const bool has_tests_to_run = FilterTests(should_shard
+                                              ? HONOR_SHARDING_PROTOCOL
+                                              : IGNORE_SHARDING_PROTOCOL) > 0;
+
+  // List the tests and exit if the --gtest_list_tests flag was specified.
+  if (GTEST_FLAG(list_tests)) {
+    // This must be called *after* FilterTests() has been called.
+    ListTestsMatchingFilter();
+    return 0;
+  }
+
+  // True iff at least one test has failed.
+  bool failed = false;
+
+  // How many times to repeat the tests?  We don't want to repeat them
+  // when we are inside the subprocess of a death test.
+  const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
+  // Repeats forever if the repeat count is negative.
+  const bool forever = repeat < 0;
+  for (int i = 0; forever || i != repeat; i++) {
+    if (repeat != 1) {
+      printf("\nRepeating all tests (iteration %d) . . .\n\n", i + 1);
+    }
+
+    // Tells the unit test event listener that the tests are about to
+    // start.
+    printer->OnUnitTestStart(parent_);
+
+    const TimeInMillis start = GetTimeInMillis();
+
+    // Runs each test case if there is at least one test to run.
+    if (has_tests_to_run) {
+      // Sets up all environments beforehand.
+      printer->OnGlobalSetUpStart(parent_);
+      environments_.ForEach(SetUpEnvironment);
+      printer->OnGlobalSetUpEnd(parent_);
+
+      // Runs the tests only if there was no fatal failure during global
+      // set-up.
+      if (!Test::HasFatalFailure()) {
+        test_cases_.ForEach(TestCase::RunTestCase);
+      }
+
+      // Tears down all environments in reverse order afterwards.
+      printer->OnGlobalTearDownStart(parent_);
+      environments_in_reverse_order_.ForEach(TearDownEnvironment);
+      printer->OnGlobalTearDownEnd(parent_);
+    }
+
+    elapsed_time_ = GetTimeInMillis() - start;
+
+    // Tells the unit test event listener that the tests have just
+    // finished.
+    printer->OnUnitTestEnd(parent_);
+
+    // Gets the result and clears it.
+    if (!Passed()) {
+      failed = true;
+    }
+    ClearResult();
+  }
+
+  // Returns 0 if all tests passed, or 1 other wise.
+  return failed ? 1 : 0;
+}
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded() {
+  const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);
+  if (test_shard_file != NULL) {
+    FILE* const file = posix::FOpen(test_shard_file, "w");
+    if (file == NULL) {
+      ColoredPrintf(COLOR_RED,
+                    "Could not write to the test shard status file \"%s\" "
+                    "specified by the %s environment variable.\n",
+                    test_shard_file, kTestShardStatusFile);
+      fflush(stdout);
+      exit(EXIT_FAILURE);
+    }
+    fclose(file);
+  }
+}
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (i.e., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+bool ShouldShard(const char* total_shards_env,
+                 const char* shard_index_env,
+                 bool in_subprocess_for_death_test) {
+  if (in_subprocess_for_death_test) {
+    return false;
+  }
+
+  const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1);
+  const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1);
+
+  if (total_shards == -1 && shard_index == -1) {
+    return false;
+  } else if (total_shards == -1 && shard_index != -1) {
+    const Message msg = Message()
+      << "Invalid environment variables: you have "
+      << kTestShardIndex << " = " << shard_index
+      << ", but have left " << kTestTotalShards << " unset.\n";
+    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+    fflush(stdout);
+    exit(EXIT_FAILURE);
+  } else if (total_shards != -1 && shard_index == -1) {
+    const Message msg = Message()
+      << "Invalid environment variables: you have "
+      << kTestTotalShards << " = " << total_shards
+      << ", but have left " << kTestShardIndex << " unset.\n";
+    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+    fflush(stdout);
+    exit(EXIT_FAILURE);
+  } else if (shard_index < 0 || shard_index >= total_shards) {
+    const Message msg = Message()
+      << "Invalid environment variables: we require 0 <= "
+      << kTestShardIndex << " < " << kTestTotalShards
+      << ", but you have " << kTestShardIndex << "=" << shard_index
+      << ", " << kTestTotalShards << "=" << total_shards << ".\n";
+    ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+    fflush(stdout);
+    exit(EXIT_FAILURE);
+  }
+
+  return total_shards > 1;
+}
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error
+// and aborts.
+Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) {
+  const char* str_val = posix::GetEnv(var);
+  if (str_val == NULL) {
+    return default_val;
+  }
+
+  Int32 result;
+  if (!ParseInt32(Message() << "The value of environment variable " << var,
+                  str_val, &result)) {
+    exit(EXIT_FAILURE);
+  }
+  return result;
+}
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
+  return (test_id % total_shards) == shard_index;
+}
+
+// Compares the name of each test with the user-specified filter to
+// decide whether the test should be run, then records the result in
+// each TestCase and TestInfo object.
+// If shard_tests == true, further filters tests based on sharding
+// variables in the environment - see
+// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide.
+// Returns the number of tests that should run.
+int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
+  const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
+      Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
+  const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
+      Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
+
+  // num_runnable_tests are the number of tests that will
+  // run across all shards (i.e., match filter and are not disabled).
+  // num_selected_tests are the number of tests to be run on
+  // this shard.
+  int num_runnable_tests = 0;
+  int num_selected_tests = 0;
+  for (const internal::ListNode<TestCase *> *test_case_node =
+           test_cases_.Head();
+       test_case_node != NULL;
+       test_case_node = test_case_node->next()) {
+    TestCase * const test_case = test_case_node->element();
+    const String &test_case_name = test_case->name();
+    test_case->set_should_run(false);
+
+    for (const internal::ListNode<TestInfo *> *test_info_node =
+             test_case->test_info_list().Head();
+         test_info_node != NULL;
+         test_info_node = test_info_node->next()) {
+      TestInfo * const test_info = test_info_node->element();
+      const String test_name(test_info->name());
+      // A test is disabled if test case name or test name matches
+      // kDisableTestFilter.
+      const bool is_disabled =
+          internal::UnitTestOptions::MatchesFilter(test_case_name,
+                                                   kDisableTestFilter) ||
+          internal::UnitTestOptions::MatchesFilter(test_name,
+                                                   kDisableTestFilter);
+      test_info->impl()->set_is_disabled(is_disabled);
+
+      const bool matches_filter =
+          internal::UnitTestOptions::FilterMatchesTest(test_case_name,
+                                                       test_name);
+      test_info->impl()->set_matches_filter(matches_filter);
+
+      const bool is_runnable =
+          (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
+          matches_filter;
+
+      const bool is_selected = is_runnable &&
+          (shard_tests == IGNORE_SHARDING_PROTOCOL ||
+           ShouldRunTestOnShard(total_shards, shard_index,
+                                num_runnable_tests));
+
+      num_runnable_tests += is_runnable;
+      num_selected_tests += is_selected;
+
+      test_info->impl()->set_should_run(is_selected);
+      test_case->set_should_run(test_case->should_run() || is_selected);
+    }
+  }
+  return num_selected_tests;
+}
+
+// Prints the names of the tests matching the user-specified filter flag.
+void UnitTestImpl::ListTestsMatchingFilter() {
+  for (const internal::ListNode<TestCase*>* test_case_node = test_cases_.Head();
+       test_case_node != NULL;
+       test_case_node = test_case_node->next()) {
+    const TestCase* const test_case = test_case_node->element();
+    bool printed_test_case_name = false;
+
+    for (const internal::ListNode<TestInfo*>* test_info_node =
+         test_case->test_info_list().Head();
+         test_info_node != NULL;
+         test_info_node = test_info_node->next()) {
+      const TestInfo* const test_info = test_info_node->element();
+      if (test_info->matches_filter()) {
+        if (!printed_test_case_name) {
+          printed_test_case_name = true;
+          printf("%s.\n", test_case->name());
+        }
+        printf("  %s\n", test_info->name());
+      }
+    }
+  }
+  fflush(stdout);
+}
+
+// Sets the unit test result printer.
+//
+// Does nothing if the input and the current printer object are the
+// same; otherwise, deletes the old printer object and makes the
+// input the current printer.
+void UnitTestImpl::set_result_printer(
+    UnitTestEventListenerInterface* result_printer) {
+  if (result_printer_ != result_printer) {
+    delete result_printer_;
+    result_printer_ = result_printer;
+  }
+}
+
+// Returns the current unit test result printer if it is not NULL;
+// otherwise, creates an appropriate result printer, makes it the
+// current printer, and returns it.
+UnitTestEventListenerInterface* UnitTestImpl::result_printer() {
+  if (result_printer_ != NULL) {
+    return result_printer_;
+  }
+
+#if GTEST_HAS_DEATH_TEST
+  if (internal_run_death_test_flag_.get() != NULL) {
+    result_printer_ = new NullUnitTestResultPrinter;
+    return result_printer_;
+  }
+#endif  // GTEST_HAS_DEATH_TEST
+
+  UnitTestEventsRepeater *repeater = new UnitTestEventsRepeater;
+  const String& output_format = internal::UnitTestOptions::GetOutputFormat();
+  if (output_format == "xml") {
+    repeater->AddListener(new XmlUnitTestResultPrinter(
+        internal::UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+  } else if (output_format != "") {
+      printf("WARNING: unrecognized output format \"%s\" ignored.\n",
+             output_format.c_str());
+      fflush(stdout);
+  }
+  repeater->AddListener(new PrettyUnitTestResultPrinter);
+  result_printer_ = repeater;
+  return result_printer_;
+}
+
+// Sets the OS stack trace getter.
+//
+// Does nothing if the input and the current OS stack trace getter are
+// the same; otherwise, deletes the old getter and makes the input the
+// current getter.
+void UnitTestImpl::set_os_stack_trace_getter(
+    OsStackTraceGetterInterface* getter) {
+  if (os_stack_trace_getter_ != getter) {
+    delete os_stack_trace_getter_;
+    os_stack_trace_getter_ = getter;
+  }
+}
+
+// Returns the current OS stack trace getter if it is not NULL;
+// otherwise, creates an OsStackTraceGetter, makes it the current
+// getter, and returns it.
+OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
+  if (os_stack_trace_getter_ == NULL) {
+    os_stack_trace_getter_ = new OsStackTraceGetter;
+  }
+
+  return os_stack_trace_getter_;
+}
+
+// Returns the TestResult for the test that's currently running, or
+// the TestResult for the ad hoc test if no test is running.
+internal::TestResult* UnitTestImpl::current_test_result() {
+  return current_test_info_ ?
+    current_test_info_->impl()->result() : &ad_hoc_test_result_;
+}
+
+// TestInfoImpl constructor. The new instance assumes ownership of the test
+// factory object.
+TestInfoImpl::TestInfoImpl(TestInfo* parent,
+                           const char* test_case_name,
+                           const char* name,
+                           const char* test_case_comment,
+                           const char* comment,
+                           TypeId fixture_class_id,
+                           internal::TestFactoryBase* factory) :
+    parent_(parent),
+    test_case_name_(String(test_case_name)),
+    name_(String(name)),
+    test_case_comment_(String(test_case_comment)),
+    comment_(String(comment)),
+    fixture_class_id_(fixture_class_id),
+    should_run_(false),
+    is_disabled_(false),
+    matches_filter_(false),
+    factory_(factory) {
+}
+
+// TestInfoImpl destructor.
+TestInfoImpl::~TestInfoImpl() {
+  delete factory_;
+}
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag.  The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, int skip_count) {
+  // We pass skip_count + 1 to skip this wrapper function in addition
+  // to what the user really wants to skip.
+  return unit_test->impl()->CurrentOsStackTraceExceptTop(skip_count + 1);
+}
+
+// Returns the number of failed test parts in the given test result object.
+int GetFailedPartCount(const TestResult* result) {
+  return result->failed_part_count();
+}
+
+// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable
+// code warnings.
+namespace {
+class ClassUniqueToAlwaysTrue {};
+}
+
+bool AlwaysTrue() {
+#if GTEST_HAS_EXCEPTIONS
+  // This condition is always false so AlwaysTrue() never actually throws,
+  // but it makes the compiler think that it may throw.
+  if (atoi("42") == 36)  // NOLINT
+    throw ClassUniqueToAlwaysTrue();
+#endif  // GTEST_HAS_EXCEPTIONS
+  return true;
+}
+
+// Parses a string as a command line flag.  The string should have
+// the format "--flag=value".  When def_optional is true, the "=value"
+// part can be omitted.
+//
+// Returns the value of the flag, or NULL if the parsing failed.
+const char* ParseFlagValue(const char* str,
+                           const char* flag,
+                           bool def_optional) {
+  // str and flag must not be NULL.
+  if (str == NULL || flag == NULL) return NULL;
+
+  // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
+  const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag);
+  const size_t flag_len = flag_str.GetLength();
+  if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+
+  // Skips the flag name.
+  const char* flag_end = str + flag_len;
+
+  // When def_optional is true, it's OK to not have a "=value" part.
+  if (def_optional && (flag_end[0] == '\0')) {
+    return flag_end;
+  }
+
+  // If def_optional is true and there are more characters after the
+  // flag name, or if def_optional is false, there must be a '=' after
+  // the flag name.
+  if (flag_end[0] != '=') return NULL;
+
+  // Returns the string after "=".
+  return flag_end + 1;
+}
+
+// Parses a string for a bool flag, in the form of either
+// "--flag=value" or "--flag".
+//
+// In the former case, the value is taken as true as long as it does
+// not start with '0', 'f', or 'F'.
+//
+// In the latter case, the value is taken as true.
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
+  // Gets the value of the flag as a string.
+  const char* const value_str = ParseFlagValue(str, flag, true);
+
+  // Aborts if the parsing failed.
+  if (value_str == NULL) return false;
+
+  // Converts the string value to a bool.
+  *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
+  return true;
+}
+
+// Parses a string for an Int32 flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
+  // Gets the value of the flag as a string.
+  const char* const value_str = ParseFlagValue(str, flag, false);
+
+  // Aborts if the parsing failed.
+  if (value_str == NULL) return false;
+
+  // Sets *value to the value of the flag.
+  return ParseInt32(Message() << "The value of flag --" << flag,
+                    value_str, value);
+}
+
+// Parses a string for a string flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true.  On failure, returns false without changing *value.
+bool ParseStringFlag(const char* str, const char* flag, String* value) {
+  // Gets the value of the flag as a string.
+  const char* const value_str = ParseFlagValue(str, flag, false);
+
+  // Aborts if the parsing failed.
+  if (value_str == NULL) return false;
+
+  // Sets *value to the value of the flag.
+  *value = value_str;
+  return true;
+}
+
+// Prints a string containing code-encoded text.  The following escape
+// sequences can be used in the string to control the text color:
+//
+//   @@    prints a single '@' character.
+//   @R    changes the color to red.
+//   @G    changes the color to green.
+//   @Y    changes the color to yellow.
+//   @D    changes to the default terminal text color.
+//
+// TODO(wan@google.com): Write tests for this once we add stdout
+// capturing to Google Test.
+static void PrintColorEncoded(const char* str) {
+  GTestColor color = COLOR_DEFAULT;  // The current color.
+
+  // Conceptually, we split the string into segments divided by escape
+  // sequences.  Then we print one segment at a time.  At the end of
+  // each iteration, the str pointer advances to the beginning of the
+  // next segment.
+  for (;;) {
+    const char* p = strchr(str, '@');
+    if (p == NULL) {
+      ColoredPrintf(color, "%s", str);
+      return;
+    }
+
+    ColoredPrintf(color, "%s", String(str, p - str).c_str());
+
+    const char ch = p[1];
+    str = p + 2;
+    if (ch == '@') {
+      ColoredPrintf(color, "@");
+    } else if (ch == 'D') {
+      color = COLOR_DEFAULT;
+    } else if (ch == 'R') {
+      color = COLOR_RED;
+    } else if (ch == 'G') {
+      color = COLOR_GREEN;
+    } else if (ch == 'Y') {
+      color = COLOR_YELLOW;
+    } else {
+      --str;
+    }
+  }
+}
+
+static const char kColorEncodedHelpMessage[] =
+"This program contains tests written using " GTEST_NAME_ ". You can use the\n"
+"following command line flags to control its behavior:\n"
+"\n"
+"Test Selection:\n"
+"  @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n"
+"      List the names of all tests instead of running them. The name of\n"
+"      TEST(Foo, Bar) is \"Foo.Bar\".\n"
+"  @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS"
+    "[@G-@YNEGATIVE_PATTERNS]@D\n"
+"      Run only the tests whose name matches one of the positive patterns but\n"
+"      none of the negative patterns. '?' matches any single character; '*'\n"
+"      matches any substring; ':' separates two patterns.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n"
+"      Run all disabled tests too.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n"
+"      Run the tests repeatedly; use a negative count to repeat forever.\n"
+"\n"
+"Test Output:\n"
+"  @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n"
+"      Enable/disable colored output. The default is @Gauto@D.\n"
+"  -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n"
+"      Don't print the elapsed time of each test.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G"
+    GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"
+"      Generate an XML report in the given directory or with the given file\n"
+"      name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n"
+"\n"
+"Assertion Behavior:\n"
+#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+"  @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"
+"      Set the default death test style.\n"
+#endif  // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+"  @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"
+"      Turn assertion failures into debugger break-points.\n"
+"  @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"
+"      Turn assertion failures into C++ exceptions.\n"
+#if GTEST_OS_WINDOWS
+"  @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n"
+"      Suppress pop-ups caused by exceptions.\n"
+#endif  // GTEST_OS_WINDOWS
+"\n"
+"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set "
+    "the corresponding\n"
+"environment variable of a flag (all letters in upper-case). For example, to\n"
+"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_
+    "color=no@D or set\n"
+"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n"
+"\n"
+"For more information, please read the " GTEST_NAME_ " documentation at\n"
+"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n"
+"(not one in your own code or tests), please report it to\n"
+"@G<" GTEST_DEV_EMAIL_ ">@D.\n";
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.  The type parameter CharType can be
+// instantiated to either char or wchar_t.
+template <typename CharType>
+void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
+  for (int i = 1; i < *argc; i++) {
+    const String arg_string = StreamableToString(argv[i]);
+    const char* const arg = arg_string.c_str();
+
+    using internal::ParseBoolFlag;
+    using internal::ParseInt32Flag;
+    using internal::ParseStringFlag;
+
+    // Do we see a Google Test flag?
+    if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
+                      &GTEST_FLAG(also_run_disabled_tests)) ||
+        ParseBoolFlag(arg, kBreakOnFailureFlag,
+                      &GTEST_FLAG(break_on_failure)) ||
+        ParseBoolFlag(arg, kCatchExceptionsFlag,
+                      &GTEST_FLAG(catch_exceptions)) ||
+        ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
+        ParseStringFlag(arg, kDeathTestStyleFlag,
+                        &GTEST_FLAG(death_test_style)) ||
+        ParseBoolFlag(arg, kDeathTestUseFork,
+                      &GTEST_FLAG(death_test_use_fork)) ||
+        ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
+        ParseStringFlag(arg, kInternalRunDeathTestFlag,
+                        &GTEST_FLAG(internal_run_death_test)) ||
+        ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
+        ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
+        ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
+        ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
+        ParseBoolFlag(arg, kThrowOnFailureFlag, &GTEST_FLAG(throw_on_failure))
+        ) {
+      // Yes.  Shift the remainder of the argv list left by one.  Note
+      // that argv has (*argc + 1) elements, the last one always being
+      // NULL.  The following loop moves the trailing NULL element as
+      // well.
+      for (int j = i; j != *argc; j++) {
+        argv[j] = argv[j + 1];
+      }
+
+      // Decrements the argument count.
+      (*argc)--;
+
+      // We also need to decrement the iterator as we just removed
+      // an element.
+      i--;
+    } else if (arg_string == "--help" || arg_string == "-h" ||
+               arg_string == "-?" || arg_string == "/?") {
+      g_help_flag = true;
+    }
+  }
+
+  if (g_help_flag) {
+    // We print the help here instead of in RUN_ALL_TESTS(), as the
+    // latter may not be called at all if the user is using Google
+    // Test with another testing framework.
+    PrintColorEncoded(kColorEncodedHelpMessage);
+  }
+}
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
+  ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
+  ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+
+// The internal implementation of InitGoogleTest().
+//
+// The type parameter CharType can be instantiated to either char or
+// wchar_t.
+template <typename CharType>
+void InitGoogleTestImpl(int* argc, CharType** argv) {
+  g_init_gtest_count++;
+
+  // We don't want to run the initialization code twice.
+  if (g_init_gtest_count != 1) return;
+
+  if (*argc <= 0) return;
+
+  internal::g_executable_path = internal::StreamableToString(argv[0]);
+
+#if GTEST_HAS_DEATH_TEST
+  g_argvs.clear();
+  for (int i = 0; i != *argc; i++) {
+    g_argvs.push_back(StreamableToString(argv[i]));
+  }
+#endif  // GTEST_HAS_DEATH_TEST
+
+  ParseGoogleTestFlagsOnly(argc, argv);
+}
+
+}  // namespace internal
+
+// Initializes Google Test.  This must be called before calling
+// RUN_ALL_TESTS().  In particular, it parses a command line for the
+// flags that Google Test recognizes.  Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned.  Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+void InitGoogleTest(int* argc, char** argv) {
+  internal::InitGoogleTestImpl(argc, argv);
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv) {
+  internal::InitGoogleTestImpl(argc, argv);
+}
+
+}  // namespace testing
diff --git a/third_party/lzma/LzmaStateDecode.c b/third_party/lzma/LzmaStateDecode.c
index b516b39..b37ba51 100644
--- a/third_party/lzma/LzmaStateDecode.c
+++ b/third_party/lzma/LzmaStateDecode.c
@@ -1,527 +1,527 @@
-/*

-  LzmaStateDecode.c

-  LZMA Decoder (State version)

-  

-  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)

-  http://www.7-zip.org/

-

-  LZMA SDK is licensed under two licenses:

-  1) GNU Lesser General Public License (GNU LGPL)

-  2) Common Public License (CPL)

-  It means that you can select one of these two licenses and 

-  follow rules of that license.

-

-  SPECIAL EXCEPTION:

-  Igor Pavlov, as the author of this Code, expressly permits you to 

-  statically or dynamically link your Code (or bind by name) to the 

-  interfaces of this file without subjecting your linked Code to the 

-  terms of the CPL or GNU LGPL. Any modifications or additions 

-  to this file, however, are subject to the LGPL or CPL terms.

-*/

-

-#include "LzmaStateDecode.h"

-

-#define kNumTopBits 24

-#define kTopValue ((UInt32)1 << kNumTopBits)

-

-#define kNumBitModelTotalBits 11

-#define kBitModelTotal (1 << kNumBitModelTotalBits)

-#define kNumMoveBits 5

-

-#define RC_READ_BYTE (*Buffer++)

-

-#define RC_INIT Code = 0; Range = 0xFFFFFFFF; \

-  { int i; for(i = 0; i < 5; i++) { Code = (Code << 8) | RC_READ_BYTE; }}

-

-#define RC_NORMALIZE if (Range < kTopValue) { Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }

-

-#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)

-#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;

-#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;

-

-#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \

-  { UpdateBit0(p); mi <<= 1; A0; } else \

-  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 

-  

-#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               

-

-#define RangeDecoderBitTreeDecode(probs, numLevels, res) \

-  { int i = numLevels; res = 1; \

-  do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \

-  res -= (1 << numLevels); }

-

-

-#define kNumPosBitsMax 4

-#define kNumPosStatesMax (1 << kNumPosBitsMax)

-

-#define kLenNumLowBits 3

-#define kLenNumLowSymbols (1 << kLenNumLowBits)

-#define kLenNumMidBits 3

-#define kLenNumMidSymbols (1 << kLenNumMidBits)

-#define kLenNumHighBits 8

-#define kLenNumHighSymbols (1 << kLenNumHighBits)

-

-#define LenChoice 0

-#define LenChoice2 (LenChoice + 1)

-#define LenLow (LenChoice2 + 1)

-#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))

-#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))

-#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 

-

-

-#define kNumStates 12

-#define kNumLitStates 7

-

-#define kStartPosModelIndex 4

-#define kEndPosModelIndex 14

-#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))

-

-#define kNumPosSlotBits 6

-#define kNumLenToPosStates 4

-

-#define kNumAlignBits 4

-#define kAlignTableSize (1 << kNumAlignBits)

-

-#define kMatchMinLen 2

-

-#define IsMatch 0

-#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))

-#define IsRepG0 (IsRep + kNumStates)

-#define IsRepG1 (IsRepG0 + kNumStates)

-#define IsRepG2 (IsRepG1 + kNumStates)

-#define IsRep0Long (IsRepG2 + kNumStates)

-#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))

-#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))

-#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)

-#define LenCoder (Align + kAlignTableSize)

-#define RepLenCoder (LenCoder + kNumLenProbs)

-#define Literal (RepLenCoder + kNumLenProbs)

-

-#if Literal != LZMA_BASE_SIZE

-StopCompilingDueBUG

-#endif

-

-/* kRequiredInBufferSize = number of required input bytes for worst case: 

-   longest match with longest distance.

-   kLzmaInBufferSize must be larger than kRequiredInBufferSize 

-   23 bits = 2 (match select) + 10 (len) + 6 (distance) + 4(align) + 1 (RC_NORMALIZE)

-*/

-

-#define kRequiredInBufferSize ((23 * (kNumBitModelTotalBits - kNumMoveBits + 1) + 26 + 9) / 8)

-

-#define kLzmaStreamWasFinishedId (-1)

-

-int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)

-{

-  unsigned char prop0;

-  if (size < LZMA_PROPERTIES_SIZE)

-    return LZMA_RESULT_DATA_ERROR;

-  prop0 = propsData[0];

-  if (prop0 >= (9 * 5 * 5))

-    return LZMA_RESULT_DATA_ERROR;

-  {

-    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));

-    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);

-    propsRes->lc = prop0;

-    /*

-    unsigned char remainder = (unsigned char)(prop0 / 9);

-    propsRes->lc = prop0 % 9;

-    propsRes->pb = remainder / 5;

-    propsRes->lp = remainder % 5;

-    */

-  }

-

-  {

-    int i;

-    propsRes->DictionarySize = 0;

-    for (i = 0; i < 4; i++)

-      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);

-    if (propsRes->DictionarySize == 0)

-      propsRes->DictionarySize = 1;

-    return LZMA_RESULT_OK;

-  }

-}

-

-int LzmaDecode(

-    CLzmaDecoderState *vs,

-    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,

-    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed,

-    int finishDecoding)

-{

-  UInt32 Range = vs->Range;

-  UInt32 Code = vs->Code;

-

-  unsigned char *Buffer = vs->Buffer;

-  int BufferSize = vs->BufferSize; /* don't change it to unsigned int */

-  CProb *p = vs->Probs;

-

-  int state = vs->State;

-  unsigned char previousByte;

-  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];

-  SizeT nowPos = 0;

-  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;

-  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;

-  int lc = vs->Properties.lc;

-  int len = vs->RemainLen;

-  UInt32 globalPos = vs->GlobalPos;

-  UInt32 distanceLimit = vs->DistanceLimit;

-

-  unsigned char *dictionary = vs->Dictionary;

-  UInt32 dictionarySize = vs->Properties.DictionarySize;

-  UInt32 dictionaryPos = vs->DictionaryPos;

-

-  unsigned char tempDictionary[4];

-  //BEGIN_GOOGLE_ADDITION(jeanluc)

-  int usesInternalTempDictionary = (dictionarySize == 0);

-  //END_GOOGLE_ADDITION(jeanluc)

-

-  (*inSizeProcessed) = 0;

-  (*outSizeProcessed) = 0;

-  if (len == kLzmaStreamWasFinishedId)

-    return LZMA_RESULT_OK;

-

-  if (dictionarySize == 0)

-  {

-    dictionary = tempDictionary;

-    dictionarySize = 1;

-    tempDictionary[0] = vs->TempDictionary[0];

-  }

-

-  if (len == kLzmaNeedInitId)

-  {

-    while (inSize > 0 && BufferSize < kLzmaInBufferSize)

-    {

-      Buffer[BufferSize++] = *inStream++;

-      (*inSizeProcessed)++;

-      inSize--;

-    }

-    if (BufferSize < 5)

-    {

-      vs->BufferSize = BufferSize;

-      return finishDecoding ? LZMA_RESULT_DATA_ERROR : LZMA_RESULT_OK;

-    }

-    {

-      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));

-      UInt32 i;

-      for (i = 0; i < numProbs; i++)

-        p[i] = kBitModelTotal >> 1; 

-      rep0 = rep1 = rep2 = rep3 = 1;

-      state = 0;

-      globalPos = 0;

-      distanceLimit = 0;

-      dictionaryPos = 0;

-      dictionary[dictionarySize - 1] = 0;

-      RC_INIT;

-    }

-    len = 0;

-  }

-  while(len != 0 && nowPos < outSize)

-  {

-    UInt32 pos = dictionaryPos - rep0;

-    if (pos >= dictionarySize)

-      pos += dictionarySize;

-    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];

-    if (++dictionaryPos == dictionarySize)

-      dictionaryPos = 0;

-    len--;

-  }

-  if (dictionaryPos == 0)

-    previousByte = dictionary[dictionarySize - 1];

-  else

-    previousByte = dictionary[dictionaryPos - 1];

-

-  while(1)

-  {

-    int bufferPos = (int)(Buffer - vs->Buffer);

-    if (BufferSize - bufferPos < kRequiredInBufferSize)

-    {

-      int i;

-      BufferSize -= bufferPos;

-      if (BufferSize < 0)

-        return LZMA_RESULT_DATA_ERROR;

-      for (i = 0; i < BufferSize; i++)

-        vs->Buffer[i] = Buffer[i];

-      Buffer = vs->Buffer;

-      while (inSize > 0 && BufferSize < kLzmaInBufferSize)

-      {

-        Buffer[BufferSize++] = *inStream++;

-        (*inSizeProcessed)++;

-        inSize--;

-      }

-      if (BufferSize < kRequiredInBufferSize && !finishDecoding)

-        break;

-    }

-    if (nowPos >= outSize)

-      break;

-    {

-    CProb *prob;

-    UInt32 bound;

-    int posState = (int)((nowPos + globalPos) & posStateMask);

-

-    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;

-    IfBit0(prob)

-    {

-      int symbol = 1;

-      UpdateBit0(prob)

-      prob = p + Literal + (LZMA_LIT_SIZE * 

-        ((((nowPos + globalPos)& literalPosMask) << lc) + (previousByte >> (8 - lc))));

-

-      if (state >= kNumLitStates)

-      {

-        int matchByte;

-        UInt32 pos = dictionaryPos - rep0;

-        if (pos >= dictionarySize)

-          pos += dictionarySize;

-        matchByte = dictionary[pos];

-        do

-        {

-          int bit;

-          CProb *probLit;

-          matchByte <<= 1;

-          bit = (matchByte & 0x100);

-          probLit = prob + 0x100 + bit + symbol;

-          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)

-        }

-        while (symbol < 0x100);

-      }

-      while (symbol < 0x100)

-      {

-        CProb *probLit = prob + symbol;

-        RC_GET_BIT(probLit, symbol)

-      }

-      previousByte = (unsigned char)symbol;

-

-      outStream[nowPos++] = previousByte;

-      if (distanceLimit < dictionarySize)

-        distanceLimit++;

-

-      dictionary[dictionaryPos] = previousByte;

-      if (++dictionaryPos == dictionarySize)

-        dictionaryPos = 0;

-      if (state < 4) state = 0;

-      else if (state < 10) state -= 3;

-      else state -= 6;

-    }

-    else             

-    {

-      UpdateBit1(prob);

-      prob = p + IsRep + state;

-      IfBit0(prob)

-      {

-        UpdateBit0(prob);

-        rep3 = rep2;

-        rep2 = rep1;

-        rep1 = rep0;

-        state = state < kNumLitStates ? 0 : 3;

-        prob = p + LenCoder;

-      }

-      else

-      {

-        UpdateBit1(prob);

-        prob = p + IsRepG0 + state;

-        IfBit0(prob)

-        {

-          UpdateBit0(prob);

-          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;

-          IfBit0(prob)

-          {

-            UInt32 pos;

-            UpdateBit0(prob);

-            if (distanceLimit == 0)

-              return LZMA_RESULT_DATA_ERROR;

-            if (distanceLimit < dictionarySize)

-              distanceLimit++;

-            state = state < kNumLitStates ? 9 : 11;

-            pos = dictionaryPos - rep0;

-            if (pos >= dictionarySize)

-              pos += dictionarySize;

-            previousByte = dictionary[pos];

-            dictionary[dictionaryPos] = previousByte;

-            if (++dictionaryPos == dictionarySize)

-              dictionaryPos = 0;

-            outStream[nowPos++] = previousByte;

-            continue;

-          }

-          else

-          {

-            UpdateBit1(prob);

-          }

-        }

-        else

-        {

-          UInt32 distance;

-          UpdateBit1(prob);

-          prob = p + IsRepG1 + state;

-          IfBit0(prob)

-          {

-            UpdateBit0(prob);

-            distance = rep1;

-          }

-          else 

-          {

-            UpdateBit1(prob);

-            prob = p + IsRepG2 + state;

-            IfBit0(prob)

-            {

-              UpdateBit0(prob);

-              distance = rep2;

-            }

-            else

-            {

-              UpdateBit1(prob);

-              distance = rep3;

-              rep3 = rep2;

-            }

-            rep2 = rep1;

-          }

-          rep1 = rep0;

-          rep0 = distance;

-        }

-        state = state < kNumLitStates ? 8 : 11;

-        prob = p + RepLenCoder;

-      }

-      {

-        int numBits, offset;

-        CProb *probLen = prob + LenChoice;

-        IfBit0(probLen)

-        {

-          UpdateBit0(probLen);

-          probLen = prob + LenLow + (posState << kLenNumLowBits);

-          offset = 0;

-          numBits = kLenNumLowBits;

-        }

-        else

-        {

-          UpdateBit1(probLen);

-          probLen = prob + LenChoice2;

-          IfBit0(probLen)

-          {

-            UpdateBit0(probLen);

-            probLen = prob + LenMid + (posState << kLenNumMidBits);

-            offset = kLenNumLowSymbols;

-            numBits = kLenNumMidBits;

-          }

-          else

-          {

-            UpdateBit1(probLen);

-            probLen = prob + LenHigh;

-            offset = kLenNumLowSymbols + kLenNumMidSymbols;

-            numBits = kLenNumHighBits;

-          }

-        }

-        RangeDecoderBitTreeDecode(probLen, numBits, len);

-        len += offset;

-      }

-

-      if (state < 4)

-      {

-        int posSlot;

-        state += kNumLitStates;

-        prob = p + PosSlot +

-            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 

-            kNumPosSlotBits);

-        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);

-        if (posSlot >= kStartPosModelIndex)

-        {

-          int numDirectBits = ((posSlot >> 1) - 1);

-          rep0 = (2 | ((UInt32)posSlot & 1));

-          if (posSlot < kEndPosModelIndex)

-          {

-            rep0 <<= numDirectBits;

-            prob = p + SpecPos + rep0 - posSlot - 1;

-          }

-          else

-          {

-            numDirectBits -= kNumAlignBits;

-            do

-            {

-              RC_NORMALIZE

-              Range >>= 1;

-              rep0 <<= 1;

-              if (Code >= Range)

-              {

-                Code -= Range;

-                rep0 |= 1;

-              }

-            }

-            while (--numDirectBits != 0);

-            prob = p + Align;

-            rep0 <<= kNumAlignBits;

-            numDirectBits = kNumAlignBits;

-          }

-          {

-            int i = 1;

-            int mi = 1;

-            do

-            {

-              CProb *prob3 = prob + mi;

-              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);

-              i <<= 1;

-            }

-            while(--numDirectBits != 0);

-          }

-        }

-        else

-          rep0 = posSlot;

-        if (++rep0 == (UInt32)(0))

-        {

-          /* it's for stream version */

-          len = kLzmaStreamWasFinishedId;

-          break;

-        }

-      }

-

-      len += kMatchMinLen;

-      if (rep0 > distanceLimit) 

-        return LZMA_RESULT_DATA_ERROR;

-      if (dictionarySize - distanceLimit > (UInt32)len)

-        distanceLimit += len;

-      else

-        distanceLimit = dictionarySize;

-

-      do

-      {

-        UInt32 pos = dictionaryPos - rep0;

-        if (pos >= dictionarySize)

-          pos += dictionarySize;

-        previousByte = dictionary[pos];

-        dictionary[dictionaryPos] = previousByte;

-        if (++dictionaryPos == dictionarySize)

-          dictionaryPos = 0;

-        len--;

-        outStream[nowPos++] = previousByte;

-      }

-      while(len != 0 && nowPos < outSize);

-    }

-    }

-  }

-  RC_NORMALIZE;

-

-  BufferSize -= (int)(Buffer - vs->Buffer);

-  if (BufferSize < 0)

-    return LZMA_RESULT_DATA_ERROR;

-  {

-    int i;

-    for (i = 0; i < BufferSize; i++)

-      vs->Buffer[i] = Buffer[i];

-  }

-  vs->BufferSize = BufferSize;

-  vs->Range = Range;

-  vs->Code = Code;

-  vs->DictionaryPos = dictionaryPos;

-  vs->GlobalPos = (UInt32)(globalPos + nowPos);

-  vs->DistanceLimit = distanceLimit;

-  vs->Reps[0] = rep0;

-  vs->Reps[1] = rep1;

-  vs->Reps[2] = rep2;

-  vs->Reps[3] = rep3;

-  vs->State = state;

-  vs->RemainLen = len;

-  //BEGIN_GOOGLE_ADDITION(jeanluc)

-  if (usesInternalTempDictionary)

-  //END_GOOGLE_ADDITION(jeanluc)

-    vs->TempDictionary[0] = tempDictionary[0];

-

-  (*outSizeProcessed) = nowPos;

-  return LZMA_RESULT_OK;

-}

+/*
+  LzmaStateDecode.c
+  LZMA Decoder (State version)
+  
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this Code, expressly permits you to 
+  statically or dynamically link your Code (or bind by name) to the 
+  interfaces of this file without subjecting your linked Code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaStateDecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT Code = 0; Range = 0xFFFFFFFF; \
+  { int i; for(i = 0; i < 5; i++) { Code = (Code << 8) | RC_READ_BYTE; }}
+
+#define RC_NORMALIZE if (Range < kTopValue) { Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+  { UpdateBit0(p); mi <<= 1; A0; } else \
+  { UpdateBit1(p); mi = (mi + mi) + 1; A1; } 
+  
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)               
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+  { int i = numLevels; res = 1; \
+  do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+  res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols) 
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+/* kRequiredInBufferSize = number of required input bytes for worst case: 
+   longest match with longest distance.
+   kLzmaInBufferSize must be larger than kRequiredInBufferSize 
+   23 bits = 2 (match select) + 10 (len) + 6 (distance) + 4(align) + 1 (RC_NORMALIZE)
+*/
+
+#define kRequiredInBufferSize ((23 * (kNumBitModelTotalBits - kNumMoveBits + 1) + 26 + 9) / 8)
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+  unsigned char prop0;
+  if (size < LZMA_PROPERTIES_SIZE)
+    return LZMA_RESULT_DATA_ERROR;
+  prop0 = propsData[0];
+  if (prop0 >= (9 * 5 * 5))
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+    for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+    propsRes->lc = prop0;
+    /*
+    unsigned char remainder = (unsigned char)(prop0 / 9);
+    propsRes->lc = prop0 % 9;
+    propsRes->pb = remainder / 5;
+    propsRes->lp = remainder % 5;
+    */
+  }
+
+  {
+    int i;
+    propsRes->DictionarySize = 0;
+    for (i = 0; i < 4; i++)
+      propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+    if (propsRes->DictionarySize == 0)
+      propsRes->DictionarySize = 1;
+    return LZMA_RESULT_OK;
+  }
+}
+
+int LzmaDecode(
+    CLzmaDecoderState *vs,
+    const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed,
+    int finishDecoding)
+{
+  UInt32 Range = vs->Range;
+  UInt32 Code = vs->Code;
+
+  unsigned char *Buffer = vs->Buffer;
+  int BufferSize = vs->BufferSize; /* don't change it to unsigned int */
+  CProb *p = vs->Probs;
+
+  int state = vs->State;
+  unsigned char previousByte;
+  UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+  SizeT nowPos = 0;
+  UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+  UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+  int lc = vs->Properties.lc;
+  int len = vs->RemainLen;
+  UInt32 globalPos = vs->GlobalPos;
+  UInt32 distanceLimit = vs->DistanceLimit;
+
+  unsigned char *dictionary = vs->Dictionary;
+  UInt32 dictionarySize = vs->Properties.DictionarySize;
+  UInt32 dictionaryPos = vs->DictionaryPos;
+
+  unsigned char tempDictionary[4];
+  //BEGIN_GOOGLE_ADDITION(jeanluc)
+  int usesInternalTempDictionary = (dictionarySize == 0);
+  //END_GOOGLE_ADDITION(jeanluc)
+
+  (*inSizeProcessed) = 0;
+  (*outSizeProcessed) = 0;
+  if (len == kLzmaStreamWasFinishedId)
+    return LZMA_RESULT_OK;
+
+  if (dictionarySize == 0)
+  {
+    dictionary = tempDictionary;
+    dictionarySize = 1;
+    tempDictionary[0] = vs->TempDictionary[0];
+  }
+
+  if (len == kLzmaNeedInitId)
+  {
+    while (inSize > 0 && BufferSize < kLzmaInBufferSize)
+    {
+      Buffer[BufferSize++] = *inStream++;
+      (*inSizeProcessed)++;
+      inSize--;
+    }
+    if (BufferSize < 5)
+    {
+      vs->BufferSize = BufferSize;
+      return finishDecoding ? LZMA_RESULT_DATA_ERROR : LZMA_RESULT_OK;
+    }
+    {
+      UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+      UInt32 i;
+      for (i = 0; i < numProbs; i++)
+        p[i] = kBitModelTotal >> 1; 
+      rep0 = rep1 = rep2 = rep3 = 1;
+      state = 0;
+      globalPos = 0;
+      distanceLimit = 0;
+      dictionaryPos = 0;
+      dictionary[dictionarySize - 1] = 0;
+      RC_INIT;
+    }
+    len = 0;
+  }
+  while(len != 0 && nowPos < outSize)
+  {
+    UInt32 pos = dictionaryPos - rep0;
+    if (pos >= dictionarySize)
+      pos += dictionarySize;
+    outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+    if (++dictionaryPos == dictionarySize)
+      dictionaryPos = 0;
+    len--;
+  }
+  if (dictionaryPos == 0)
+    previousByte = dictionary[dictionarySize - 1];
+  else
+    previousByte = dictionary[dictionaryPos - 1];
+
+  while(1)
+  {
+    int bufferPos = (int)(Buffer - vs->Buffer);
+    if (BufferSize - bufferPos < kRequiredInBufferSize)
+    {
+      int i;
+      BufferSize -= bufferPos;
+      if (BufferSize < 0)
+        return LZMA_RESULT_DATA_ERROR;
+      for (i = 0; i < BufferSize; i++)
+        vs->Buffer[i] = Buffer[i];
+      Buffer = vs->Buffer;
+      while (inSize > 0 && BufferSize < kLzmaInBufferSize)
+      {
+        Buffer[BufferSize++] = *inStream++;
+        (*inSizeProcessed)++;
+        inSize--;
+      }
+      if (BufferSize < kRequiredInBufferSize && !finishDecoding)
+        break;
+    }
+    if (nowPos >= outSize)
+      break;
+    {
+    CProb *prob;
+    UInt32 bound;
+    int posState = (int)((nowPos + globalPos) & posStateMask);
+
+    prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+    IfBit0(prob)
+    {
+      int symbol = 1;
+      UpdateBit0(prob)
+      prob = p + Literal + (LZMA_LIT_SIZE * 
+        ((((nowPos + globalPos)& literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+      if (state >= kNumLitStates)
+      {
+        int matchByte;
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        matchByte = dictionary[pos];
+        do
+        {
+          int bit;
+          CProb *probLit;
+          matchByte <<= 1;
+          bit = (matchByte & 0x100);
+          probLit = prob + 0x100 + bit + symbol;
+          RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+        }
+        while (symbol < 0x100);
+      }
+      while (symbol < 0x100)
+      {
+        CProb *probLit = prob + symbol;
+        RC_GET_BIT(probLit, symbol)
+      }
+      previousByte = (unsigned char)symbol;
+
+      outStream[nowPos++] = previousByte;
+      if (distanceLimit < dictionarySize)
+        distanceLimit++;
+
+      dictionary[dictionaryPos] = previousByte;
+      if (++dictionaryPos == dictionarySize)
+        dictionaryPos = 0;
+      if (state < 4) state = 0;
+      else if (state < 10) state -= 3;
+      else state -= 6;
+    }
+    else             
+    {
+      UpdateBit1(prob);
+      prob = p + IsRep + state;
+      IfBit0(prob)
+      {
+        UpdateBit0(prob);
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        state = state < kNumLitStates ? 0 : 3;
+        prob = p + LenCoder;
+      }
+      else
+      {
+        UpdateBit1(prob);
+        prob = p + IsRepG0 + state;
+        IfBit0(prob)
+        {
+          UpdateBit0(prob);
+          prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+          IfBit0(prob)
+          {
+            UInt32 pos;
+            UpdateBit0(prob);
+            if (distanceLimit == 0)
+              return LZMA_RESULT_DATA_ERROR;
+            if (distanceLimit < dictionarySize)
+              distanceLimit++;
+            state = state < kNumLitStates ? 9 : 11;
+            pos = dictionaryPos - rep0;
+            if (pos >= dictionarySize)
+              pos += dictionarySize;
+            previousByte = dictionary[pos];
+            dictionary[dictionaryPos] = previousByte;
+            if (++dictionaryPos == dictionarySize)
+              dictionaryPos = 0;
+            outStream[nowPos++] = previousByte;
+            continue;
+          }
+          else
+          {
+            UpdateBit1(prob);
+          }
+        }
+        else
+        {
+          UInt32 distance;
+          UpdateBit1(prob);
+          prob = p + IsRepG1 + state;
+          IfBit0(prob)
+          {
+            UpdateBit0(prob);
+            distance = rep1;
+          }
+          else 
+          {
+            UpdateBit1(prob);
+            prob = p + IsRepG2 + state;
+            IfBit0(prob)
+            {
+              UpdateBit0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UpdateBit1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = p + RepLenCoder;
+      }
+      {
+        int numBits, offset;
+        CProb *probLen = prob + LenChoice;
+        IfBit0(probLen)
+        {
+          UpdateBit0(probLen);
+          probLen = prob + LenLow + (posState << kLenNumLowBits);
+          offset = 0;
+          numBits = kLenNumLowBits;
+        }
+        else
+        {
+          UpdateBit1(probLen);
+          probLen = prob + LenChoice2;
+          IfBit0(probLen)
+          {
+            UpdateBit0(probLen);
+            probLen = prob + LenMid + (posState << kLenNumMidBits);
+            offset = kLenNumLowSymbols;
+            numBits = kLenNumMidBits;
+          }
+          else
+          {
+            UpdateBit1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols + kLenNumMidSymbols;
+            numBits = kLenNumHighBits;
+          }
+        }
+        RangeDecoderBitTreeDecode(probLen, numBits, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        int posSlot;
+        state += kNumLitStates;
+        prob = p + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << 
+            kNumPosSlotBits);
+        RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          int numDirectBits = ((posSlot >> 1) - 1);
+          rep0 = (2 | ((UInt32)posSlot & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            rep0 <<= numDirectBits;
+            prob = p + SpecPos + rep0 - posSlot - 1;
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              RC_NORMALIZE
+              Range >>= 1;
+              rep0 <<= 1;
+              if (Code >= Range)
+              {
+                Code -= Range;
+                rep0 |= 1;
+              }
+            }
+            while (--numDirectBits != 0);
+            prob = p + Align;
+            rep0 <<= kNumAlignBits;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            int i = 1;
+            int mi = 1;
+            do
+            {
+              CProb *prob3 = prob + mi;
+              RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+              i <<= 1;
+            }
+            while(--numDirectBits != 0);
+          }
+        }
+        else
+          rep0 = posSlot;
+        if (++rep0 == (UInt32)(0))
+        {
+          /* it's for stream version */
+          len = kLzmaStreamWasFinishedId;
+          break;
+        }
+      }
+
+      len += kMatchMinLen;
+      if (rep0 > distanceLimit) 
+        return LZMA_RESULT_DATA_ERROR;
+      if (dictionarySize - distanceLimit > (UInt32)len)
+        distanceLimit += len;
+      else
+        distanceLimit = dictionarySize;
+
+      do
+      {
+        UInt32 pos = dictionaryPos - rep0;
+        if (pos >= dictionarySize)
+          pos += dictionarySize;
+        previousByte = dictionary[pos];
+        dictionary[dictionaryPos] = previousByte;
+        if (++dictionaryPos == dictionarySize)
+          dictionaryPos = 0;
+        len--;
+        outStream[nowPos++] = previousByte;
+      }
+      while(len != 0 && nowPos < outSize);
+    }
+    }
+  }
+  RC_NORMALIZE;
+
+  BufferSize -= (int)(Buffer - vs->Buffer);
+  if (BufferSize < 0)
+    return LZMA_RESULT_DATA_ERROR;
+  {
+    int i;
+    for (i = 0; i < BufferSize; i++)
+      vs->Buffer[i] = Buffer[i];
+  }
+  vs->BufferSize = BufferSize;
+  vs->Range = Range;
+  vs->Code = Code;
+  vs->DictionaryPos = dictionaryPos;
+  vs->GlobalPos = (UInt32)(globalPos + nowPos);
+  vs->DistanceLimit = distanceLimit;
+  vs->Reps[0] = rep0;
+  vs->Reps[1] = rep1;
+  vs->Reps[2] = rep2;
+  vs->Reps[3] = rep3;
+  vs->State = state;
+  vs->RemainLen = len;
+  //BEGIN_GOOGLE_ADDITION(jeanluc)
+  if (usesInternalTempDictionary)
+  //END_GOOGLE_ADDITION(jeanluc)
+    vs->TempDictionary[0] = tempDictionary[0];
+
+  (*outSizeProcessed) = nowPos;
+  return LZMA_RESULT_OK;
+}
diff --git a/third_party/lzma/LzmaStateDecode.h b/third_party/lzma/LzmaStateDecode.h
index 39fbcdb..26490d6 100644
--- a/third_party/lzma/LzmaStateDecode.h
+++ b/third_party/lzma/LzmaStateDecode.h
@@ -1,96 +1,96 @@
-/* 

-  LzmaStateDecode.h

-  LZMA Decoder interface (State version)

-

-  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)

-  http://www.7-zip.org/

-

-  LZMA SDK is licensed under two licenses:

-  1) GNU Lesser General Public License (GNU LGPL)

-  2) Common Public License (CPL)

-  It means that you can select one of these two licenses and 

-  follow rules of that license.

-

-  SPECIAL EXCEPTION:

-  Igor Pavlov, as the author of this code, expressly permits you to 

-  statically or dynamically link your code (or bind by name) to the 

-  interfaces of this file without subjecting your linked code to the 

-  terms of the CPL or GNU LGPL. Any modifications or additions 

-  to this file, however, are subject to the LGPL or CPL terms.

-*/

-

-#ifndef __LZMASTATEDECODE_H

-#define __LZMASTATEDECODE_H

-

-#include "LzmaTypes.h"

-

-/* #define _LZMA_PROB32 */

-/* It can increase speed on some 32-bit CPUs, 

-   but memory usage will be doubled in that case */

-

-#ifdef _LZMA_PROB32

-#define CProb UInt32

-#else

-#define CProb UInt16

-#endif

-

-#define LZMA_RESULT_OK 0

-#define LZMA_RESULT_DATA_ERROR 1

-

-#define LZMA_BASE_SIZE 1846

-#define LZMA_LIT_SIZE 768

-

-#define LZMA_PROPERTIES_SIZE 5

-

-typedef struct _CLzmaProperties

-{

-  int lc;

-  int lp;

-  int pb;

-  UInt32 DictionarySize;

-}CLzmaProperties;

-

-int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);

-

-#define LzmaGetNumProbs(lzmaProps) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((lzmaProps)->lc + (lzmaProps)->lp)))

-

-#define kLzmaInBufferSize 64   /* don't change it. it must be larger than kRequiredInBufferSize */

-

-#define kLzmaNeedInitId (-2)

-

-typedef struct _CLzmaDecoderState

-{

-  CLzmaProperties Properties;

-  CProb *Probs;

-  unsigned char *Dictionary;

-

-  unsigned char Buffer[kLzmaInBufferSize];

-  int BufferSize;

-

-  UInt32 Range;

-  UInt32 Code;

-  UInt32 DictionaryPos;

-  UInt32 GlobalPos;

-  UInt32 DistanceLimit;

-  UInt32 Reps[4];

-  int State;

-  int RemainLen;  /* -2: decoder needs internal initialization

-                     -1: stream was finished, 

-                      0: ok

-                    > 0: need to write RemainLen bytes as match Reps[0],

-                  */

-  unsigned char TempDictionary[4];  /* it's required when DictionarySize = 0 */

-} CLzmaDecoderState;

-

-#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; (vs)->BufferSize = 0; }

-

-/* LzmaDecode: decoding from input stream to output stream.

-  If finishDecoding != 0, then there are no more bytes in input stream

-  after inStream[inSize - 1]. */

-

-int LzmaDecode(CLzmaDecoderState *vs,

-    const unsigned char *inStream, SizeT inSize,  SizeT *inSizeProcessed,

-    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed,

-    int finishDecoding);

-

-#endif

+/* 
+  LzmaStateDecode.h
+  LZMA Decoder interface (State version)
+
+  LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+  http://www.7-zip.org/
+
+  LZMA SDK is licensed under two licenses:
+  1) GNU Lesser General Public License (GNU LGPL)
+  2) Common Public License (CPL)
+  It means that you can select one of these two licenses and 
+  follow rules of that license.
+
+  SPECIAL EXCEPTION:
+  Igor Pavlov, as the author of this code, expressly permits you to 
+  statically or dynamically link your code (or bind by name) to the 
+  interfaces of this file without subjecting your linked code to the 
+  terms of the CPL or GNU LGPL. Any modifications or additions 
+  to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMASTATEDECODE_H
+#define __LZMASTATEDECODE_H
+
+#include "LzmaTypes.h"
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs, 
+   but memory usage will be doubled in that case */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+  int lc;
+  int lp;
+  int pb;
+  UInt32 DictionarySize;
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(lzmaProps) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((lzmaProps)->lc + (lzmaProps)->lp)))
+
+#define kLzmaInBufferSize 64   /* don't change it. it must be larger than kRequiredInBufferSize */
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+  CLzmaProperties Properties;
+  CProb *Probs;
+  unsigned char *Dictionary;
+
+  unsigned char Buffer[kLzmaInBufferSize];
+  int BufferSize;
+
+  UInt32 Range;
+  UInt32 Code;
+  UInt32 DictionaryPos;
+  UInt32 GlobalPos;
+  UInt32 DistanceLimit;
+  UInt32 Reps[4];
+  int State;
+  int RemainLen;  /* -2: decoder needs internal initialization
+                     -1: stream was finished, 
+                      0: ok
+                    > 0: need to write RemainLen bytes as match Reps[0],
+                  */
+  unsigned char TempDictionary[4];  /* it's required when DictionarySize = 0 */
+} CLzmaDecoderState;
+
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; (vs)->BufferSize = 0; }
+
+/* LzmaDecode: decoding from input stream to output stream.
+  If finishDecoding != 0, then there are no more bytes in input stream
+  after inStream[inSize - 1]. */
+
+int LzmaDecode(CLzmaDecoderState *vs,
+    const unsigned char *inStream, SizeT inSize,  SizeT *inSizeProcessed,
+    unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed,
+    int finishDecoding);
+
+#endif
diff --git a/third_party/lzma/LzmaTypes.h b/third_party/lzma/LzmaTypes.h
index 4a1f7db..288c5e4 100644
--- a/third_party/lzma/LzmaTypes.h
+++ b/third_party/lzma/LzmaTypes.h
@@ -1,45 +1,45 @@
-/* 

-LzmaTypes.h 

-

-Types for LZMA Decoder

-

-This file written and distributed to public domain by Igor Pavlov.

-This file is part of LZMA SDK 4.40 (2006-05-01)

-*/

-

-#ifndef __LZMATYPES_H

-#define __LZMATYPES_H

-

-#ifndef _7ZIP_BYTE_DEFINED

-#define _7ZIP_BYTE_DEFINED

-typedef unsigned char Byte;

-#endif 

-

-#ifndef _7ZIP_UINT16_DEFINED

-#define _7ZIP_UINT16_DEFINED

-typedef unsigned short UInt16;

-#endif 

-

-#ifndef _7ZIP_UINT32_DEFINED

-#define _7ZIP_UINT32_DEFINED

-#ifdef _LZMA_UINT32_IS_ULONG

-typedef unsigned long UInt32;

-#else

-typedef unsigned int UInt32;

-#endif

-#endif 

-

-/* #define _LZMA_SYSTEM_SIZE_T */

-/* Use system's size_t. You can use it to enable 64-bit sizes supporting */

-

-#ifndef _7ZIP_SIZET_DEFINED

-#define _7ZIP_SIZET_DEFINED

-#ifdef _LZMA_SYSTEM_SIZE_T

-#include <stddef.h>

-typedef size_t SizeT;

-#else

-typedef UInt32 SizeT;

-#endif

-#endif

-

-#endif

+/* 
+LzmaTypes.h 
+
+Types for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.40 (2006-05-01)
+*/
+
+#ifndef __LZMATYPES_H
+#define __LZMATYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif 
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif 
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef unsigned long UInt32;
+#else
+typedef unsigned int UInt32;
+#endif
+#endif 
+
+/* #define _LZMA_SYSTEM_SIZE_T */
+/* Use system's size_t. You can use it to enable 64-bit sizes supporting */
+
+#ifndef _7ZIP_SIZET_DEFINED
+#define _7ZIP_SIZET_DEFINED
+#ifdef _LZMA_SYSTEM_SIZE_T
+#include <stddef.h>
+typedef size_t SizeT;
+#else
+typedef UInt32 SizeT;
+#endif
+#endif
+
+#endif
diff --git a/third_party/lzma/build.scons b/third_party/lzma/build.scons
index 48f6cdc..5cd142d 100644
--- a/third_party/lzma/build.scons
+++ b/third_party/lzma/build.scons
@@ -1,25 +1,25 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-env.ComponentLibrary(

-    lib_name='lzma',

-    source='LzmaStateDecode.c',

-)

-

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+env.ComponentLibrary(
+    lib_name='lzma',
+    source='LzmaStateDecode.c',
+)
+
+
diff --git a/third_party/lzma/setup_env.bat b/third_party/lzma/setup_env.bat
index 801e6ad..8260e2d 100644
--- a/third_party/lzma/setup_env.bat
+++ b/third_party/lzma/setup_env.bat
@@ -1,8 +1,8 @@
-:: This script must not rely on any external tools or PATH values.

-@echo OFF

-

-:: Let advanced users checkout the tools in just one P4 enlistment

-if "%SETUP_ENV_LZMA_4_43%"=="done" goto :EOF

-set  SETUP_ENV_LZMA_4_43=done

-

-set PATH=%PATH%;%~dp0

+:: This script must not rely on any external tools or PATH values.
+@echo OFF
+
+:: Let advanced users checkout the tools in just one P4 enlistment
+if "%SETUP_ENV_LZMA_4_43%"=="done" goto :EOF
+set  SETUP_ENV_LZMA_4_43=done
+
+set PATH=%PATH%;%~dp0
diff --git a/third_party/minicrt/_hello.cc b/third_party/minicrt/_hello.cc
index fadf198..df522ca 100644
--- a/third_party/minicrt/_hello.cc
+++ b/third_party/minicrt/_hello.cc
@@ -1,11 +1,11 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-#include <stdio.h>

-

-void main() {

-// SKIP_LOC_BEGIN

-  printf("Hello World!\n" );

-// SKIP_LOC_END

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+#include <stdio.h>
+
+void main() {
+// SKIP_LOC_BEGIN
+  printf("Hello World!\n" );
+// SKIP_LOC_END
+}
diff --git a/third_party/minicrt/_libctiny.mak b/third_party/minicrt/_libctiny.mak
index b318221..b1ef935 100644
--- a/third_party/minicrt/_libctiny.mak
+++ b/third_party/minicrt/_libctiny.mak
@@ -1,34 +1,34 @@
-#==================================================

-# LIBCTINY - Matt Pietrek 1996

-# Microsoft Systems Journal, October 1996

-# FILE: LIBCTINY.MAK - Makefile for Microsoft version

-#==================================================

-CC = CL

-CC_OPTIONS = /c /W3 /DWIN32_LEAN_AND_MEAN /Gy /GR- /GX- /GF

-

-S=.

-!ifdef DEBUG

-CC_OPTIONS = $(CC_OPTIONS) /Zi

-O=Debug

-!else

-CC_OPTIONS = $(CC_OPTIONS) /Zi /Ogisyb2

-O=Release

-!endif

-

-PROJ = LIBCTINY

-

-OBJS =  $O\CRT0TCON.OBJ $O\CRT0TWIN.OBJ $O\DLLCRT0.OBJ $O\ARGCARGV.OBJ $O\PRINTF.OBJ \

-        $O\SPRINTF.OBJ $O\PUTS.OBJ $O\ALLOC.OBJ $O\ALLOC2.OBJ $O\ALLOCSUP.OBJ $O\STRUPLWR.OBJ \

-        $O\ISCTYPE.OBJ $O\ATOL.OBJ $O\STRICMP.OBJ $O\NEWDEL.OBJ $O\INITTERM.OBJ

-

-all: $O $O\$(PROJ).LIB

-

-$O: ; mkdir $O

-

-$O\$(PROJ).LIB: {$O}$(OBJS)

-    LIB /OUT:$O\$(PROJ).LIB $(OBJS)

-

-{$S}.CPP{$O}.OBJ::

-    $(CC) $(CC_OPTIONS) -Fo$O\ -Fd$O\ $<

-    

-{$O}$(OBJS):

+#==================================================
+# LIBCTINY - Matt Pietrek 1996
+# Microsoft Systems Journal, October 1996
+# FILE: LIBCTINY.MAK - Makefile for Microsoft version
+#==================================================
+CC = CL
+CC_OPTIONS = /c /W3 /DWIN32_LEAN_AND_MEAN /Gy /GR- /GX- /GF
+
+S=.
+!ifdef DEBUG
+CC_OPTIONS = $(CC_OPTIONS) /Zi
+O=Debug
+!else
+CC_OPTIONS = $(CC_OPTIONS) /Zi /Ogisyb2
+O=Release
+!endif
+
+PROJ = LIBCTINY
+
+OBJS =  $O\CRT0TCON.OBJ $O\CRT0TWIN.OBJ $O\DLLCRT0.OBJ $O\ARGCARGV.OBJ $O\PRINTF.OBJ \
+        $O\SPRINTF.OBJ $O\PUTS.OBJ $O\ALLOC.OBJ $O\ALLOC2.OBJ $O\ALLOCSUP.OBJ $O\STRUPLWR.OBJ \
+        $O\ISCTYPE.OBJ $O\ATOL.OBJ $O\STRICMP.OBJ $O\NEWDEL.OBJ $O\INITTERM.OBJ
+
+all: $O $O\$(PROJ).LIB
+
+$O: ; mkdir $O
+
+$O\$(PROJ).LIB: {$O}$(OBJS)
+    LIB /OUT:$O\$(PROJ).LIB $(OBJS)
+
+{$S}.CPP{$O}.OBJ::
+    $(CC) $(CC_OPTIONS) -Fo$O\ -Fd$O\ $<
+    
+{$O}$(OBJS):
diff --git a/third_party/minicrt/alloc.cc b/third_party/minicrt/alloc.cc
index 94abf2d..a90271f 100644
--- a/third_party/minicrt/alloc.cc
+++ b/third_party/minicrt/alloc.cc
@@ -1,23 +1,23 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-#include <malloc.h>

-

-extern "C"

-#if _MSC_VER >= 1400

-__declspec(noalias restrict)

-#endif

-void * __cdecl malloc(size_t size) {

-    return HeapAlloc( GetProcessHeap(), 0, size );

-}

-

-extern "C"

-#if _MSC_VER >= 1400

-__declspec(noalias)

-#endif

-void __cdecl free(void * p) {

-    HeapFree( GetProcessHeap(), 0, p );

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+#include <malloc.h>
+
+extern "C"
+#if _MSC_VER >= 1400
+__declspec(noalias restrict)
+#endif
+void * __cdecl malloc(size_t size) {
+    return HeapAlloc( GetProcessHeap(), 0, size );
+}
+
+extern "C"
+#if _MSC_VER >= 1400
+__declspec(noalias)
+#endif
+void __cdecl free(void * p) {
+    HeapFree( GetProcessHeap(), 0, p );
+}
diff --git a/third_party/minicrt/alloc2.cc b/third_party/minicrt/alloc2.cc
index 10b3d0d..92c954e 100644
--- a/third_party/minicrt/alloc2.cc
+++ b/third_party/minicrt/alloc2.cc
@@ -1,35 +1,35 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-#include <malloc.h>

-

-extern "C"

-#if _MSC_VER >= 1400

-__declspec(noalias restrict)

-#endif

-void * __cdecl realloc(void * p, size_t size) {

-    if (p)

-        return HeapReAlloc( GetProcessHeap(), 0, p, size );

-    else    // 'p' is 0, and HeapReAlloc doesn't act like realloc() here

-        return HeapAlloc( GetProcessHeap(), 0, size );

-}

-

-extern "C"

-#if _MSC_VER >= 1400

-__declspec(noalias restrict)

-#endif

-void * __cdecl calloc(size_t nitems, size_t size) {

-    return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, nitems * size );

-}

-

-extern "C"

-#if _MSC_VER >= 1400

-  __declspec(noalias restrict)

-#endif

-void * __cdecl _recalloc(void * p, size_t nitems, size_t size) {

-    return realloc(p, nitems * size);

-}

-

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+#include <malloc.h>
+
+extern "C"
+#if _MSC_VER >= 1400
+__declspec(noalias restrict)
+#endif
+void * __cdecl realloc(void * p, size_t size) {
+    if (p)
+        return HeapReAlloc( GetProcessHeap(), 0, p, size );
+    else    // 'p' is 0, and HeapReAlloc doesn't act like realloc() here
+        return HeapAlloc( GetProcessHeap(), 0, size );
+}
+
+extern "C"
+#if _MSC_VER >= 1400
+__declspec(noalias restrict)
+#endif
+void * __cdecl calloc(size_t nitems, size_t size) {
+    return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, nitems * size );
+}
+
+extern "C"
+#if _MSC_VER >= 1400
+  __declspec(noalias restrict)
+#endif
+void * __cdecl _recalloc(void * p, size_t nitems, size_t size) {
+    return realloc(p, nitems * size);
+}
+
diff --git a/third_party/minicrt/allocsup.cc b/third_party/minicrt/allocsup.cc
index 5a05585..ca03268 100644
--- a/third_party/minicrt/allocsup.cc
+++ b/third_party/minicrt/allocsup.cc
@@ -1,15 +1,15 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-#include <malloc.h>

-

-extern "C" void * __cdecl _nh_malloc(size_t size, int) {

-    return HeapAlloc( GetProcessHeap(), 0, size );

-}

-

-extern "C" size_t __cdecl _msize(void * p) {

-    return HeapSize( GetProcessHeap(), 0, p );

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+#include <malloc.h>
+
+extern "C" void * __cdecl _nh_malloc(size_t size, int) {
+    return HeapAlloc( GetProcessHeap(), 0, size );
+}
+
+extern "C" size_t __cdecl _msize(void * p) {
+    return HeapSize( GetProcessHeap(), 0, p );
+}
diff --git a/third_party/minicrt/argcargv.cc b/third_party/minicrt/argcargv.cc
index fe455fd..851f8cb 100644
--- a/third_party/minicrt/argcargv.cc
+++ b/third_party/minicrt/argcargv.cc
@@ -1,112 +1,112 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-#include "argcargv.h"

-

-#define _MAX_CMD_LINE_ARGS  128

-

-char * _ppszArgv[_MAX_CMD_LINE_ARGS+1];

-

-int __cdecl _ConvertCommandLineToArgcArgv() {

-    int cbCmdLine;

-    int argc;

-    PSTR pszSysCmdLine, pszCmdLine;

-    

-    // Set to no argv elements, in case we have to bail out

-    _ppszArgv[0] = 0;

-

-    // First get a pointer to the system's version of the command line, and

-    // figure out how long it is.

-    pszSysCmdLine = GetCommandLine();

-    cbCmdLine = lstrlen( pszSysCmdLine );

-

-    // Allocate memory to store a copy of the command line.  We'll modify

-    // this copy, rather than the original command line.  Yes, this memory

-    // currently doesn't explicitly get freed, but it goes away when the

-    // process terminates.

-    pszCmdLine = (PSTR)HeapAlloc( GetProcessHeap(), 0, cbCmdLine+1 );

-    if (!pszCmdLine)

-        return 0;

-

-    // Copy the system version of the command line into our copy

-    lstrcpyn( pszCmdLine, pszSysCmdLine , cbCmdLine+1);

-

-    if ('"' == *pszCmdLine)   // If command line starts with a quote ("),

-    {                           // it's a quoted filename.  Skip to next quote.

-        pszCmdLine++;

-    

-        _ppszArgv[0] = pszCmdLine;  // argv[0] == executable name

-    

-        while (*pszCmdLine && (*pszCmdLine != '"'))

-            pszCmdLine++;

-

-        if (*pszCmdLine)      // Did we see a non-NULL ending?

-            *pszCmdLine++ = 0;  // Null terminate and advance to next char

-        else

-            return 0;           // Oops!  We didn't see the end quote

-    }

-    else    // A regular (non-quoted) filename

-    {

-        _ppszArgv[0] = pszCmdLine;  // argv[0] == executable name

-

-        while (*pszCmdLine && (' ' != *pszCmdLine) && ('\t' != *pszCmdLine))

-            pszCmdLine++;

-

-        if (*pszCmdLine)

-            *pszCmdLine++ = 0;  // Null terminate and advance to next char

-    }

-

-    // Done processing argv[0] (i.e., the executable name).  Now do th

-    // actual arguments

-

-    argc = 1;

-

-    while (1)

-    {

-        // Skip over any whitespace

-        while (*pszCmdLine && (' ' == *pszCmdLine) || ('\t' == *pszCmdLine))

-            pszCmdLine++;

-

-        if (0 == *pszCmdLine) // End of command line???

-            return argc;

-

-        if ('"' == *pszCmdLine)   // Argument starting with a quote???

-        {

-            pszCmdLine++;   // Advance past quote character

-

-            _ppszArgv[ argc++ ] = pszCmdLine;

-            _ppszArgv[ argc ] = 0;

-

-            // Scan to end quote, or NULL terminator

-            while (*pszCmdLine && (*pszCmdLine != '"'))

-                pszCmdLine++;

-                

-            if (0 == *pszCmdLine)

-                return argc;

-            

-            if (*pszCmdLine)

-                *pszCmdLine++ = 0;  // Null terminate and advance to next char

-        }

-        else                        // Non-quoted argument

-        {

-            _ppszArgv[ argc++ ] = pszCmdLine;

-            _ppszArgv[ argc ] = 0;

-

-            // Skip till whitespace or NULL terminator

-            while (*pszCmdLine && (' '!=*pszCmdLine) && ('\t'!=*pszCmdLine))

-                pszCmdLine++;

-            

-            if (0 == *pszCmdLine)

-                return argc;

-            

-            if (*pszCmdLine)

-                *pszCmdLine++ = 0;  // Null terminate and advance to next char

-        }

-

-        if (argc >= (_MAX_CMD_LINE_ARGS))

-            return argc;

-    }

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+#include "argcargv.h"
+
+#define _MAX_CMD_LINE_ARGS  128
+
+char * _ppszArgv[_MAX_CMD_LINE_ARGS+1];
+
+int __cdecl _ConvertCommandLineToArgcArgv() {
+    int cbCmdLine;
+    int argc;
+    PSTR pszSysCmdLine, pszCmdLine;
+    
+    // Set to no argv elements, in case we have to bail out
+    _ppszArgv[0] = 0;
+
+    // First get a pointer to the system's version of the command line, and
+    // figure out how long it is.
+    pszSysCmdLine = GetCommandLine();
+    cbCmdLine = lstrlen( pszSysCmdLine );
+
+    // Allocate memory to store a copy of the command line.  We'll modify
+    // this copy, rather than the original command line.  Yes, this memory
+    // currently doesn't explicitly get freed, but it goes away when the
+    // process terminates.
+    pszCmdLine = (PSTR)HeapAlloc( GetProcessHeap(), 0, cbCmdLine+1 );
+    if (!pszCmdLine)
+        return 0;
+
+    // Copy the system version of the command line into our copy
+    lstrcpyn( pszCmdLine, pszSysCmdLine , cbCmdLine+1);
+
+    if ('"' == *pszCmdLine)   // If command line starts with a quote ("),
+    {                           // it's a quoted filename.  Skip to next quote.
+        pszCmdLine++;
+    
+        _ppszArgv[0] = pszCmdLine;  // argv[0] == executable name
+    
+        while (*pszCmdLine && (*pszCmdLine != '"'))
+            pszCmdLine++;
+
+        if (*pszCmdLine)      // Did we see a non-NULL ending?
+            *pszCmdLine++ = 0;  // Null terminate and advance to next char
+        else
+            return 0;           // Oops!  We didn't see the end quote
+    }
+    else    // A regular (non-quoted) filename
+    {
+        _ppszArgv[0] = pszCmdLine;  // argv[0] == executable name
+
+        while (*pszCmdLine && (' ' != *pszCmdLine) && ('\t' != *pszCmdLine))
+            pszCmdLine++;
+
+        if (*pszCmdLine)
+            *pszCmdLine++ = 0;  // Null terminate and advance to next char
+    }
+
+    // Done processing argv[0] (i.e., the executable name).  Now do th
+    // actual arguments
+
+    argc = 1;
+
+    while (1)
+    {
+        // Skip over any whitespace
+        while (*pszCmdLine && (' ' == *pszCmdLine) || ('\t' == *pszCmdLine))
+            pszCmdLine++;
+
+        if (0 == *pszCmdLine) // End of command line???
+            return argc;
+
+        if ('"' == *pszCmdLine)   // Argument starting with a quote???
+        {
+            pszCmdLine++;   // Advance past quote character
+
+            _ppszArgv[ argc++ ] = pszCmdLine;
+            _ppszArgv[ argc ] = 0;
+
+            // Scan to end quote, or NULL terminator
+            while (*pszCmdLine && (*pszCmdLine != '"'))
+                pszCmdLine++;
+                
+            if (0 == *pszCmdLine)
+                return argc;
+            
+            if (*pszCmdLine)
+                *pszCmdLine++ = 0;  // Null terminate and advance to next char
+        }
+        else                        // Non-quoted argument
+        {
+            _ppszArgv[ argc++ ] = pszCmdLine;
+            _ppszArgv[ argc ] = 0;
+
+            // Skip till whitespace or NULL terminator
+            while (*pszCmdLine && (' '!=*pszCmdLine) && ('\t'!=*pszCmdLine))
+                pszCmdLine++;
+            
+            if (0 == *pszCmdLine)
+                return argc;
+            
+            if (*pszCmdLine)
+                *pszCmdLine++ = 0;  // Null terminate and advance to next char
+        }
+
+        if (argc >= (_MAX_CMD_LINE_ARGS))
+            return argc;
+    }
+}
diff --git a/third_party/minicrt/argcargv.h b/third_party/minicrt/argcargv.h
index 585a170..f62930b 100644
--- a/third_party/minicrt/argcargv.h
+++ b/third_party/minicrt/argcargv.h
@@ -1,10 +1,10 @@
-#ifndef TR_COMMON_MINICRT_ARGCARGV_H_

-#define TR_COMMON_MINICRT_ARGCARGV_H_

-

-#include "libctiny.h"

-

-extern char * _ppszArgv[];

-

-int __cdecl _ConvertCommandLineToArgcArgv();

-

-#endif  // TR_COMMON_MINICRT_ARGCARGV_H_

+#ifndef TR_COMMON_MINICRT_ARGCARGV_H_
+#define TR_COMMON_MINICRT_ARGCARGV_H_
+
+#include "libctiny.h"
+
+extern char * _ppszArgv[];
+
+int __cdecl _ConvertCommandLineToArgcArgv();
+
+#endif  // TR_COMMON_MINICRT_ARGCARGV_H_
diff --git a/third_party/minicrt/bsearch.c b/third_party/minicrt/bsearch.c
index a1192ba..1f80d8c 100644
--- a/third_party/minicrt/bsearch.c
+++ b/third_party/minicrt/bsearch.c
@@ -1,80 +1,80 @@
-#include "libctiny.h"

-#include <windows.h>

-

-/***

-*bsearch.c - do a binary search

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines bsearch() - do a binary search an an array

-*

-*******************************************************************************/

-

-// #include <cruntime.h>

-// #include <stdlib.h>

-// #include <search.h>

-

-/***

-*char *bsearch() - do a binary search on an array

-*

-*Purpose:

-*       Does a binary search of a sorted array for a key.

-*

-*Entry:

-*       const char *key    - key to search for

-*       const char *base   - base of sorted array to search

-*       unsigned int num   - number of elements in array

-*       unsigned int width - number of bytes per element

-*       int (*compare)()   - pointer to function that compares two array

-*               elements, returning neg when #1 < #2, pos when #1 > #2, and

-*               0 when they are equal. Function is passed pointers to two

-*               array elements.

-*

-*Exit:

-*       if key is found:

-*               returns pointer to occurrence of key in array

-*       if key is not found:

-*               returns NULL

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-void * __cdecl bsearch (

-        const void *key,

-        const void *base,

-        size_t num,

-        size_t width,

-        int (__cdecl *compare)(const void *, const void *)

-        )

-{

-        register char *lo = (char *)base;

-        register char *hi = (char *)base + (num - 1) * width;

-        register char *mid;

-        size_t half;

-        int result;

-

-        while (lo <= hi)

-                if (half = num / 2)

-                {

-                        mid = lo + (num & 1 ? half : (half - 1)) * width;

-                        if (!(result = (*compare)(key,mid)))

-                                return(mid);

-                        else if (result < 0)

-                        {

-                                hi = mid - width;

-                                num = num & 1 ? half : half-1;

-                        }

-                        else    {

-                                lo = mid + width;

-                                num = half;

-                        }

-                }

-                else if (num)

-                        return((*compare)(key,lo) ? NULL : lo);

-                else

-                        break;

-

-        return(NULL);

-}

+#include "libctiny.h"
+#include <windows.h>
+
+/***
+*bsearch.c - do a binary search
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines bsearch() - do a binary search an an array
+*
+*******************************************************************************/
+
+// #include <cruntime.h>
+// #include <stdlib.h>
+// #include <search.h>
+
+/***
+*char *bsearch() - do a binary search on an array
+*
+*Purpose:
+*       Does a binary search of a sorted array for a key.
+*
+*Entry:
+*       const char *key    - key to search for
+*       const char *base   - base of sorted array to search
+*       unsigned int num   - number of elements in array
+*       unsigned int width - number of bytes per element
+*       int (*compare)()   - pointer to function that compares two array
+*               elements, returning neg when #1 < #2, pos when #1 > #2, and
+*               0 when they are equal. Function is passed pointers to two
+*               array elements.
+*
+*Exit:
+*       if key is found:
+*               returns pointer to occurrence of key in array
+*       if key is not found:
+*               returns NULL
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+void * __cdecl bsearch (
+        const void *key,
+        const void *base,
+        size_t num,
+        size_t width,
+        int (__cdecl *compare)(const void *, const void *)
+        )
+{
+        register char *lo = (char *)base;
+        register char *hi = (char *)base + (num - 1) * width;
+        register char *mid;
+        size_t half;
+        int result;
+
+        while (lo <= hi)
+                if (half = num / 2)
+                {
+                        mid = lo + (num & 1 ? half : (half - 1)) * width;
+                        if (!(result = (*compare)(key,mid)))
+                                return(mid);
+                        else if (result < 0)
+                        {
+                                hi = mid - width;
+                                num = num & 1 ? half : half-1;
+                        }
+                        else    {
+                                lo = mid + width;
+                                num = half;
+                        }
+                }
+                else if (num)
+                        return((*compare)(key,lo) ? NULL : lo);
+                else
+                        break;
+
+        return(NULL);
+}
diff --git a/third_party/minicrt/build.scons b/third_party/minicrt/build.scons
index 9a2aef0..803b8c2 100644
--- a/third_party/minicrt/build.scons
+++ b/third_party/minicrt/build.scons
@@ -1,88 +1,88 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-

-local_env = env.Clone()

-local_env.Append(

-    CCFLAGS = [

-        '/wd4255',  # no function prototype given: converting '()' to '(void)'

-        '/wd4287',  # unsigned/negative constant mismatch

-        '/wd4706',  # assignment within conditional expression

-        ],

-    CPPDEFINES = [

-        '_MBCS'

-        ],

-)

-

-# Disable runtime error checking.

-local_env.FilterOut(CCFLAGS = ['/RTC1'])

-

-_inputs = [

-    'alloc.cc',

-    'alloc2.cc',

-    'allocsup.cc',

-    'argcargv.cc',

-    'bsearch.c',

-    'charmax.c',

-    'crt0tcon.cc',

-    'crt0twin.cc',

-    'dllcrt0.cc',

-    'fullpath.cc',

-    'initterm.cc',

-    'isctype.cc',

-    'memory.cc',

-    'newdel.cc',

-    'pesect.c',

-    'puts.cc',

-    'resetstk.c',

-    'security.cc',

-    'stricmp.cc',

-    'string.c',

-    'struplwr.cc',

-

-    'alloca16.obj',

-    'chandler4.obj',

-

-    # Structured exception handling.

-    'sehprolg.obj',

-    'sehprolg4.obj',

-    'sehprolg4gs.obj',

-

-    # Exception handlers.

-    'exsup4.obj',

-    'exsup3.obj',

-    'exsup.obj',

-    'eh3valid.obj',

-    'ulldiv.obj',

-    'llmul.obj',

-    'ftol2.obj',

-    'chkstk.obj',

-    'dllsupp.obj',

-    'ullshr.obj',

-    'lldvrm.obj',

-    'ulldvrm.obj',

-    'llshl.obj',

-    'ullrem.obj',

-    'lldiv.obj',

-    'llrem.obj',

-    'llshr.obj',

-    ]

-

-# Build these into a static library.

-local_env.ComponentLibrary('minicrt', _inputs)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+
+local_env = env.Clone()
+local_env.Append(
+    CCFLAGS = [
+        '/wd4255',  # no function prototype given: converting '()' to '(void)'
+        '/wd4287',  # unsigned/negative constant mismatch
+        '/wd4706',  # assignment within conditional expression
+        ],
+    CPPDEFINES = [
+        '_MBCS'
+        ],
+)
+
+# Disable runtime error checking.
+local_env.FilterOut(CCFLAGS = ['/RTC1'])
+
+_inputs = [
+    'alloc.cc',
+    'alloc2.cc',
+    'allocsup.cc',
+    'argcargv.cc',
+    'bsearch.c',
+    'charmax.c',
+    'crt0tcon.cc',
+    'crt0twin.cc',
+    'dllcrt0.cc',
+    'fullpath.cc',
+    'initterm.cc',
+    'isctype.cc',
+    'memory.cc',
+    'newdel.cc',
+    'pesect.c',
+    'puts.cc',
+    'resetstk.c',
+    'security.cc',
+    'stricmp.cc',
+    'string.c',
+    'struplwr.cc',
+
+    'alloca16.obj',
+    'chandler4.obj',
+
+    # Structured exception handling.
+    'sehprolg.obj',
+    'sehprolg4.obj',
+    'sehprolg4gs.obj',
+
+    # Exception handlers.
+    'exsup4.obj',
+    'exsup3.obj',
+    'exsup.obj',
+    'eh3valid.obj',
+    'ulldiv.obj',
+    'llmul.obj',
+    'ftol2.obj',
+    'chkstk.obj',
+    'dllsupp.obj',
+    'ullshr.obj',
+    'lldvrm.obj',
+    'ulldvrm.obj',
+    'llshl.obj',
+    'ullrem.obj',
+    'lldiv.obj',
+    'llrem.obj',
+    'llshr.obj',
+    ]
+
+# Build these into a static library.
+local_env.ComponentLibrary('minicrt', _inputs)
diff --git a/third_party/minicrt/charmax.c b/third_party/minicrt/charmax.c
index 514bbee..f725280 100644
--- a/third_party/minicrt/charmax.c
+++ b/third_party/minicrt/charmax.c
@@ -1,41 +1,41 @@
-/***

-*charmax.c - definition of _charmax variable

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines _charmax

-*

-*       According to ANSI, certain elements of the lconv structure must be

-*       initialized to CHAR_MAX and the value of CHAR_MAX changes when

-*       the user compiles -J.  To reflect this change in the lconv structure,

-*       we initialize the structure to SCHAR_MAX, and when any of the users

-*       modules are compiled -J, the structure is updated.

-*

-*       Note that this is not done for DLLs linked to the CRT DLL, because

-*       we do not want such DLLs to override the -J setting for an EXE

-*       linked to the CRT DLL.  See comments in crtexe.c.

-*

-*       Files involved:

-*

-*       locale.h - if -J, generates an unresolved external to _charmax

-*       charmax.c - defines _charmax and sets to UCHAR_MAX (255), places

-*               _lconv_init in startup initializer table if pulled in by -J

-*       lconv.c - initializes lconv structure to SCHAR_MAX (127),

-*               since libraries built without -J

-*       lcnvinit.c - sets lconv members to 25.

-**

-*******************************************************************************/

-

-#ifdef _MSC_VER

-

-//#include <sect_attribs.h>

-//#include <internal.h>

-

-//int __lconv_init(void);

-

-int _charmax = 255;

-

-//_CRTALLOC(".CRT$XIC") static _PIFV pinit = __lconv_init;

-

-#endif  /* _MSC_VER */

+/***
+*charmax.c - definition of _charmax variable
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines _charmax
+*
+*       According to ANSI, certain elements of the lconv structure must be
+*       initialized to CHAR_MAX and the value of CHAR_MAX changes when
+*       the user compiles -J.  To reflect this change in the lconv structure,
+*       we initialize the structure to SCHAR_MAX, and when any of the users
+*       modules are compiled -J, the structure is updated.
+*
+*       Note that this is not done for DLLs linked to the CRT DLL, because
+*       we do not want such DLLs to override the -J setting for an EXE
+*       linked to the CRT DLL.  See comments in crtexe.c.
+*
+*       Files involved:
+*
+*       locale.h - if -J, generates an unresolved external to _charmax
+*       charmax.c - defines _charmax and sets to UCHAR_MAX (255), places
+*               _lconv_init in startup initializer table if pulled in by -J
+*       lconv.c - initializes lconv structure to SCHAR_MAX (127),
+*               since libraries built without -J
+*       lcnvinit.c - sets lconv members to 25.
+**
+*******************************************************************************/
+
+#ifdef _MSC_VER
+
+//#include <sect_attribs.h>
+//#include <internal.h>
+
+//int __lconv_init(void);
+
+int _charmax = 255;
+
+//_CRTALLOC(".CRT$XIC") static _PIFV pinit = __lconv_init;
+
+#endif  /* _MSC_VER */
diff --git a/third_party/minicrt/crt0tcon.cc b/third_party/minicrt/crt0tcon.cc
index 6d0b0db..a7cd842 100644
--- a/third_party/minicrt/crt0tcon.cc
+++ b/third_party/minicrt/crt0tcon.cc
@@ -1,45 +1,45 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-// FILE: CRT0TCON.CPP

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-#include "argcargv.h"

-#include "initterm.h"

-

-// Force the linker to include KERNEL32.LIB

-#pragma comment(linker, "/defaultlib:kernel32.lib")

-

-//#pragma comment(linker, "/nodefaultlib:libc.lib")

-//#pragma comment(linker, "/nodefaultlib:libcmt.lib")

-

-extern "C" int __cdecl main(int, char **, char **);    // In user's code

-

-extern "C" void DoInitialization();

-extern "C" void DoCleanup();

-

-//

-// Modified version of the Visual C++ startup code.  Simplified to

-// make it easier to read.  Only supports ANSI programs.

-//

-extern "C" void __cdecl mainCRTStartup() {

-    int mainret, argc;

-

-    argc = _ConvertCommandLineToArgcArgv( );

-

-    // set up our minimal cheezy atexit table

-    _atexit_init();

-

-    // Call C++ constructors

-    _initterm( __xc_a, __xc_z );

-

-    // DoInitialization();

-

-    mainret = main( argc, _ppszArgv, 0 );

-

-    _DoExit();

-    // DoCleanup();

-

-    ExitProcess(mainret);

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+// FILE: CRT0TCON.CPP
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+#include "argcargv.h"
+#include "initterm.h"
+
+// Force the linker to include KERNEL32.LIB
+#pragma comment(linker, "/defaultlib:kernel32.lib")
+
+//#pragma comment(linker, "/nodefaultlib:libc.lib")
+//#pragma comment(linker, "/nodefaultlib:libcmt.lib")
+
+extern "C" int __cdecl main(int, char **, char **);    // In user's code
+
+extern "C" void DoInitialization();
+extern "C" void DoCleanup();
+
+//
+// Modified version of the Visual C++ startup code.  Simplified to
+// make it easier to read.  Only supports ANSI programs.
+//
+extern "C" void __cdecl mainCRTStartup() {
+    int mainret, argc;
+
+    argc = _ConvertCommandLineToArgcArgv( );
+
+    // set up our minimal cheezy atexit table
+    _atexit_init();
+
+    // Call C++ constructors
+    _initterm( __xc_a, __xc_z );
+
+    // DoInitialization();
+
+    mainret = main( argc, _ppszArgv, 0 );
+
+    _DoExit();
+    // DoCleanup();
+
+    ExitProcess(mainret);
+}
diff --git a/third_party/minicrt/crt0twin.cc b/third_party/minicrt/crt0twin.cc
index 5f6b708..068be70 100644
--- a/third_party/minicrt/crt0twin.cc
+++ b/third_party/minicrt/crt0twin.cc
@@ -1,75 +1,75 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-// FILE: CRT0TWIN.CPP

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-#include "initterm.h"

-

-// Force the linker to include KERNEL32.LIB

-#pragma comment(linker, "/defaultlib:kernel32.lib")

-

-#pragma comment(linker, "/nodefaultlib:libc.lib")

-#pragma comment(linker, "/nodefaultlib:libcmt.lib")

-

-// Modified version of the Visual C++ startup code.  Simplified to

-// make it easier to read.

-

-extern int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE hinstPrev,

-                   LPSTR pszCmdLine, int nCmdShow);

-

-extern "C" void __cdecl WinMainCRTStartup() {

-    int mainret;

-    char *lpszCommandLine;

-    STARTUPINFO StartupInfo;

-

-    lpszCommandLine = GetCommandLine();

-

-    // Skip past program name (first token in command line).

-

-    if (*lpszCommandLine == '"')  // Check for and handle quoted program name

-    {

-        lpszCommandLine++;  // Get past the first quote

-

-        // Now, scan, and skip over, subsequent characters until  another

-        // double-quote or a null is encountered

-        while (*lpszCommandLine && (*lpszCommandLine != '"'))

-            lpszCommandLine++;

-

-        // If we stopped on a double-quote (usual case), skip over it.

-

-        if (*lpszCommandLine == '"')

-            lpszCommandLine++;

-    }

-    else    // First token wasn't a quote

-    {

-        while (*lpszCommandLine > ' ')

-            lpszCommandLine++;

-    }

-

-    // Skip past any white space preceeding the second token.

-

-    while (*lpszCommandLine && (*lpszCommandLine <= ' '))

-        lpszCommandLine++;

-

-    StartupInfo.dwFlags = 0;

-    GetStartupInfo( &StartupInfo );

-

-    // set up our minimal cheezy atexit table

-    _atexit_init();

-

-    // Call C++ constructors

-    _initterm( __xc_a, __xc_z );

-

-    mainret = WinMain( GetModuleHandle(NULL),

-                       NULL,

-                       lpszCommandLine,

-                       StartupInfo.dwFlags & STARTF_USESHOWWINDOW

-                            ? StartupInfo.wShowWindow : SW_SHOWDEFAULT );

-

-    _DoExit();

-

-    ExitProcess(mainret);

-}

-

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+// FILE: CRT0TWIN.CPP
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+#include "initterm.h"
+
+// Force the linker to include KERNEL32.LIB
+#pragma comment(linker, "/defaultlib:kernel32.lib")
+
+#pragma comment(linker, "/nodefaultlib:libc.lib")
+#pragma comment(linker, "/nodefaultlib:libcmt.lib")
+
+// Modified version of the Visual C++ startup code.  Simplified to
+// make it easier to read.
+
+extern int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE hinstPrev,
+                   LPSTR pszCmdLine, int nCmdShow);
+
+extern "C" void __cdecl WinMainCRTStartup() {
+    int mainret;
+    char *lpszCommandLine;
+    STARTUPINFO StartupInfo;
+
+    lpszCommandLine = GetCommandLine();
+
+    // Skip past program name (first token in command line).
+
+    if (*lpszCommandLine == '"')  // Check for and handle quoted program name
+    {
+        lpszCommandLine++;  // Get past the first quote
+
+        // Now, scan, and skip over, subsequent characters until  another
+        // double-quote or a null is encountered
+        while (*lpszCommandLine && (*lpszCommandLine != '"'))
+            lpszCommandLine++;
+
+        // If we stopped on a double-quote (usual case), skip over it.
+
+        if (*lpszCommandLine == '"')
+            lpszCommandLine++;
+    }
+    else    // First token wasn't a quote
+    {
+        while (*lpszCommandLine > ' ')
+            lpszCommandLine++;
+    }
+
+    // Skip past any white space preceeding the second token.
+
+    while (*lpszCommandLine && (*lpszCommandLine <= ' '))
+        lpszCommandLine++;
+
+    StartupInfo.dwFlags = 0;
+    GetStartupInfo( &StartupInfo );
+
+    // set up our minimal cheezy atexit table
+    _atexit_init();
+
+    // Call C++ constructors
+    _initterm( __xc_a, __xc_z );
+
+    mainret = WinMain( GetModuleHandle(NULL),
+                       NULL,
+                       lpszCommandLine,
+                       StartupInfo.dwFlags & STARTF_USESHOWWINDOW
+                            ? StartupInfo.wShowWindow : SW_SHOWDEFAULT );
+
+    _DoExit();
+
+    ExitProcess(mainret);
+}
+
diff --git a/third_party/minicrt/dllcrt0.cc b/third_party/minicrt/dllcrt0.cc
index 8eebe69..6c5f140 100644
--- a/third_party/minicrt/dllcrt0.cc
+++ b/third_party/minicrt/dllcrt0.cc
@@ -1,57 +1,57 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-// FILE: DLLCRT0.CPP

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-#include "initterm.h"

-

-// Force the linker to include KERNEL32.LIB

-#pragma comment(linker, "/defaultlib:kernel32.lib")

-

-// #pragma comment(linker, "/nodefaultlib:libc.lib")

-// #pragma comment(linker, "/nodefaultlib:libcmt.lib")

-

-// User routine DllMain is called on all notifications

-

-extern BOOL WINAPI DllMain(

-        HANDLE  hDllHandle,

-        DWORD   dwReason,

-        LPVOID  lpreserved

-        ) ;

-

-extern "C" void DoInitialization();

-extern "C" void DoCleanup();

-

-//

-// Modified version of the Visual C++ startup code.  Simplified to

-// make it easier to read.  Only supports ANSI programs.

-//

-extern "C"

-BOOL WINAPI _DllMainCRTStartup(

-        HANDLE  hDllHandle,

-        DWORD   dwReason,

-        LPVOID  lpreserved

-        ) {

-    if (dwReason == DLL_PROCESS_ATTACH)

-    {

-        // set up our minimal cheezy atexit table

-        _atexit_init();

-

-        // Call C++ constructors

-        _initterm( __xc_a, __xc_z );

-

-        // DoInitialization();

-    }

-

-    BOOL retcode = DllMain(hDllHandle, dwReason, lpreserved);

-

-    if (dwReason == DLL_PROCESS_DETACH)

-    {

-        _DoExit();

-        // DoCleanup();

-    }

-

-    return retcode ;

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+// FILE: DLLCRT0.CPP
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+#include "initterm.h"
+
+// Force the linker to include KERNEL32.LIB
+#pragma comment(linker, "/defaultlib:kernel32.lib")
+
+// #pragma comment(linker, "/nodefaultlib:libc.lib")
+// #pragma comment(linker, "/nodefaultlib:libcmt.lib")
+
+// User routine DllMain is called on all notifications
+
+extern BOOL WINAPI DllMain(
+        HANDLE  hDllHandle,
+        DWORD   dwReason,
+        LPVOID  lpreserved
+        ) ;
+
+extern "C" void DoInitialization();
+extern "C" void DoCleanup();
+
+//
+// Modified version of the Visual C++ startup code.  Simplified to
+// make it easier to read.  Only supports ANSI programs.
+//
+extern "C"
+BOOL WINAPI _DllMainCRTStartup(
+        HANDLE  hDllHandle,
+        DWORD   dwReason,
+        LPVOID  lpreserved
+        ) {
+    if (dwReason == DLL_PROCESS_ATTACH)
+    {
+        // set up our minimal cheezy atexit table
+        _atexit_init();
+
+        // Call C++ constructors
+        _initterm( __xc_a, __xc_z );
+
+        // DoInitialization();
+    }
+
+    BOOL retcode = DllMain(hDllHandle, dwReason, lpreserved);
+
+    if (dwReason == DLL_PROCESS_DETACH)
+    {
+        _DoExit();
+        // DoCleanup();
+    }
+
+    return retcode ;
+}
diff --git a/third_party/minicrt/fullpath.cc b/third_party/minicrt/fullpath.cc
index 95930ea..1672492 100644
--- a/third_party/minicrt/fullpath.cc
+++ b/third_party/minicrt/fullpath.cc
@@ -1,93 +1,93 @@
-/*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*_TSCHAR *_fullpath( _TSCHAR *buf, const _TSCHAR *path, maxlen );

-*

-*Purpose:

-*

-*       _fullpath - combines the current directory with path to form

-*       an absolute path. i.e. _fullpath takes care of .\ and ..\

-*       in the path.

-*

-*       The result is placed in buf. If the length of the result

-*       is greater than maxlen NULL is returned, otherwise

-*       the address of buf is returned.

-*

-*       If buf is NULL then a buffer is malloc'ed and maxlen is

-*       ignored. If there are no errors then the address of this

-*       buffer is returned.

-*

-*       If path specifies a drive, the curent directory of this

-*       drive is combined with path. If the drive is not valid

-*       and _fullpath needs the current directory of this drive

-*       then NULL is returned.  If the current directory of this

-*       non existant drive is not needed then a proper value is

-*       returned.

-*       For example:  path = "z:\\pop" does not need z:'s current

-*       directory but path = "z:pop" does.

-*

-*

-*

-*Entry:

-*       _TSCHAR *buf  - pointer to a buffer maintained by the user;

-*       _TSCHAR *path - path to "add" to the current directory

-*       int maxlen - length of the buffer pointed to by buf

-*

-*Exit:

-*       Returns pointer to the buffer containing the absolute path

-*       (same as buf if non-NULL; otherwise, malloc is

-*       used to allocate a buffer)

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-#include <tchar.h>

-#include <malloc.h>

-#include <stdlib.h>

-#include <windows.h>

-

-

-_TSCHAR * __cdecl _tfullpath(_TSCHAR *UserBuf, const _TSCHAR *path, size_t maxlen) {

-        _TSCHAR *buf;

-        _TSCHAR *pfname;

-        unsigned long count;

-

-        // don't handle this case to reduce dependancies, add this later if required

-        if (!path || !*path)  /* no work to do */

-            // return( _tgetcwd( UserBuf, (int)maxlen ) );

-            return( NULL );

-

-        /* allocate buffer if necessary */

-

-        if (!UserBuf)

-            if (!(buf = reinterpret_cast<_TSCHAR*>(malloc(_MAX_PATH * sizeof(_TSCHAR))))) {

-                // errno = ENOMEM;

-                return( NULL );

-            }

-            else

-                maxlen = _MAX_PATH;

-        else

-            buf = UserBuf;

-

-        count = GetFullPathName( path,

-                                  (int)maxlen,

-                                  buf,

-                                  &pfname );

-

-        if (count >= maxlen) {

-            if (!UserBuf)

-                free(buf);

-            // errno = ERANGE;

-            return( NULL );

-        }

-        else if (count == 0) {

-            if (!UserBuf)

-                free(buf);

-            // _dosmaperr( GetLastError() );

-            return( NULL );

-        }

-

-        return( buf );

-

-}

+/*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*_TSCHAR *_fullpath( _TSCHAR *buf, const _TSCHAR *path, maxlen );
+*
+*Purpose:
+*
+*       _fullpath - combines the current directory with path to form
+*       an absolute path. i.e. _fullpath takes care of .\ and ..\
+*       in the path.
+*
+*       The result is placed in buf. If the length of the result
+*       is greater than maxlen NULL is returned, otherwise
+*       the address of buf is returned.
+*
+*       If buf is NULL then a buffer is malloc'ed and maxlen is
+*       ignored. If there are no errors then the address of this
+*       buffer is returned.
+*
+*       If path specifies a drive, the curent directory of this
+*       drive is combined with path. If the drive is not valid
+*       and _fullpath needs the current directory of this drive
+*       then NULL is returned.  If the current directory of this
+*       non existant drive is not needed then a proper value is
+*       returned.
+*       For example:  path = "z:\\pop" does not need z:'s current
+*       directory but path = "z:pop" does.
+*
+*
+*
+*Entry:
+*       _TSCHAR *buf  - pointer to a buffer maintained by the user;
+*       _TSCHAR *path - path to "add" to the current directory
+*       int maxlen - length of the buffer pointed to by buf
+*
+*Exit:
+*       Returns pointer to the buffer containing the absolute path
+*       (same as buf if non-NULL; otherwise, malloc is
+*       used to allocate a buffer)
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#include <tchar.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <windows.h>
+
+
+_TSCHAR * __cdecl _tfullpath(_TSCHAR *UserBuf, const _TSCHAR *path, size_t maxlen) {
+        _TSCHAR *buf;
+        _TSCHAR *pfname;
+        unsigned long count;
+
+        // don't handle this case to reduce dependancies, add this later if required
+        if (!path || !*path)  /* no work to do */
+            // return( _tgetcwd( UserBuf, (int)maxlen ) );
+            return( NULL );
+
+        /* allocate buffer if necessary */
+
+        if (!UserBuf)
+            if (!(buf = reinterpret_cast<_TSCHAR*>(malloc(_MAX_PATH * sizeof(_TSCHAR))))) {
+                // errno = ENOMEM;
+                return( NULL );
+            }
+            else
+                maxlen = _MAX_PATH;
+        else
+            buf = UserBuf;
+
+        count = GetFullPathName( path,
+                                  (int)maxlen,
+                                  buf,
+                                  &pfname );
+
+        if (count >= maxlen) {
+            if (!UserBuf)
+                free(buf);
+            // errno = ERANGE;
+            return( NULL );
+        }
+        else if (count == 0) {
+            if (!UserBuf)
+                free(buf);
+            // _dosmaperr( GetLastError() );
+            return( NULL );
+        }
+
+        return( buf );
+
+}
diff --git a/third_party/minicrt/initterm.cc b/third_party/minicrt/initterm.cc
index 547aeb4..9cb2250 100644
--- a/third_party/minicrt/initterm.cc
+++ b/third_party/minicrt/initterm.cc
@@ -1,230 +1,230 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-// ==========================================

-

-#include "libctiny.h"

-#include <windows.h>

-#include <malloc.h>

-#include "initterm.h"

-

-#pragma data_seg(".CRT$XCA")

-_PVFV __xc_a[] = { NULL };

-#pragma data_seg(".CRT$XCZ")

-_PVFV __xc_z[] = { NULL };

-

-/*

-#pragma data_seg(".CRT$XIA")

-_PVFV __xi_a[] = { NULL };

-#pragma data_seg(".CRT$XIZ")

-_PVFV __xi_z[] = { NULL };

-

-#pragma data_seg(".CRT$XTA")

-_PVFV __xt_a[] = { NULL };

-#pragma data_seg(".CRT$XTZ")

-_PVFV __xt_z[] = { NULL };

-

-#pragma data_seg(".CRT$XPA")

-_PVFV __xp_a[] = { NULL };

-#pragma data_seg(".CRT$XPZ")

-_PVFV __xp_z[] = { NULL };

-*/

-

-#pragma data_seg()  /* reset */

-

-#pragma comment(linker, "/merge:.CRT=.data")

-

-typedef void (__cdecl *_PVFV)();

-

-void __cdecl _initterm(

-        _PVFV * pfbegin,

-        _PVFV * pfend

-        ) {

-    // walk the table of function pointers from the bottom up, until

-    // the end is encountered.  Do not skip the first entry.  The initial

-    // value of pfbegin points to the first valid entry.  Do not try to

-    // execute what pfend points to.  Only entries before pfend are valid.

-    while (pfbegin < pfend)

-    {

-        // if current table entry is non-NULL, call thru it.

-        if (*pfbegin != NULL)

-            (**pfbegin)();

-        ++pfbegin;

-    }

-}

-

-static _PVFV * pf_atexitlist = 0;

-static unsigned max_atexitlist_entries = 0;

-static unsigned cur_atexitlist_entries = 0;

-

-void __cdecl _atexit_init() {

-    max_atexitlist_entries = 32;

-    pf_atexitlist = (_PVFV *)calloc( max_atexitlist_entries,

-                                     sizeof(_PVFV*) );

-}

-

-int __cdecl atexit(_PVFV func ) {

-    if (cur_atexitlist_entries < max_atexitlist_entries)

-    {

-        pf_atexitlist[cur_atexitlist_entries++] = func; 

-        return 0;

-    }

-

-    return -1;

-}

-

-void __cdecl _DoExit() {

-    if (cur_atexitlist_entries)

-    {

-        _initterm(  pf_atexitlist,

-                    // Use ptr math to find the end of the array

-                    pf_atexitlist + cur_atexitlist_entries );

-    }

-}

-

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

-

-/*

-static HANDLE g_hProcessHeap = NULL;

-

-extern "C" _PVFV* __onexitbegin = NULL;

-extern "C" _PVFV* __onexitend = NULL;

-

-extern "C" _PVFV __xi_a[], __xi_z[];    // C initializers 

-extern "C" _PVFV __xc_a[], __xc_z[];    // C++ initializers 

-extern "C" _PVFV __xp_a[], __xp_z[];    // C pre-terminators 

-extern "C" _PVFV __xt_a[], __xt_z[];    // C terminators 

-

-// Critical section to protect initialization/exit code

-static CRITICAL_SECTION g_csInit;

-

-extern "C" void DoInitialization() {

-  _PVFV* pf;

-

-  // memset(&osi, 0, sizeof(OSVERSIONINFO));

-  // osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

-  // GetVersionEx(&osi);

-  // _osplatform = osi.dwPlatformId;

-

-  InitializeCriticalSection( &g_csInit );

-

-  EnterCriticalSection( &g_csInit );

-

-  __try

-  {

-    g_hProcessHeap = GetProcessHeap();

-

-    // Call initialization routines (contructors for globals, etc.)

-    for (pf = __xi_a; pf < __xi_z; pf++)

-    {

-      if (*pf != NULL)

-      {

-        (**pf)();

-      }

-    }

-

-    for (pf = __xc_a; pf < __xc_z; pf++)

-    {

-      if (*pf != NULL)

-      {

-        (**pf)();

-      }

-    }

-  }

-  __finally

-  {

-    LeaveCriticalSection(&g_csInit);

-  }

-}

-

-extern "C" void DoCleanup() {

-  _PVFV* pf;

-

-  EnterCriticalSection(&g_csInit);  // Protect access to the atexit table

-

-  __try

-  {

-    // Call routines registered with atexit() from most recently registered

-    // to least recently registered

-    if (__onexitbegin != NULL)

-    {

-      for (pf = __onexitend-1; pf >= __onexitbegin; pf--)

-      {

-        if (*pf != NULL)

-          (**pf)();

-      }

-    }

-

-    free(__onexitbegin);

-    __onexitbegin = NULL;

-    __onexitend = NULL;

-

-    for (pf = __xp_a; pf < __xp_z; pf++)

-    {

-      if (*pf != NULL)

-      {

-        (**pf)();

-      }

-    }

-

-    for (pf = __xt_a; pf < __xt_z; pf++)

-    {

-      if (*pf != NULL)

-      {

-        (**pf)();

-      }

-    }

-  }

-  __finally

-  {

-    LeaveCriticalSection(&g_csInit);

-    DeleteCriticalSection(&g_csInit);    

-  }

-}

-

-int __cdecl atexit(_PVFV pf) {

-  size_t nCurrentSize;

-  int nRet = 0;  

-

-  EnterCriticalSection(&g_csInit);

-

-  __try

-  {

-    if (__onexitbegin == NULL)

-    {

-      __onexitbegin = (_PVFV*)malloc(16*sizeof(_PVFV));

-      if (__onexitbegin == NULL)

-      {

-        LeaveCriticalSection(&g_csInit);

-        return(-1);

-      }

-      __onexitend = __onexitbegin;

-    }

-

-    nCurrentSize = _msize(__onexitbegin);

-    if ((nCurrentSize+sizeof(_PVFV)) < ULONG(((const byte*)__onexitend-

-      (const byte*)__onexitbegin)))

-    {

-      _PVFV* pNew;

-

-      pNew = (_PVFV*)realloc(__onexitbegin, 2*nCurrentSize);

-      if (pNew == NULL)

-      {

-        LeaveCriticalSection(&g_csInit);    

-        return(-1);

-      }

-    }

-

-    *__onexitend = pf;

-    __onexitend++;

-  }

-  __except (1)

-  {

-    nRet = -1;

-  }

-

-  LeaveCriticalSection(&g_csInit);  

-

-  return(nRet);

-}

-*/

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+// ==========================================
+
+#include "libctiny.h"
+#include <windows.h>
+#include <malloc.h>
+#include "initterm.h"
+
+#pragma data_seg(".CRT$XCA")
+_PVFV __xc_a[] = { NULL };
+#pragma data_seg(".CRT$XCZ")
+_PVFV __xc_z[] = { NULL };
+
+/*
+#pragma data_seg(".CRT$XIA")
+_PVFV __xi_a[] = { NULL };
+#pragma data_seg(".CRT$XIZ")
+_PVFV __xi_z[] = { NULL };
+
+#pragma data_seg(".CRT$XTA")
+_PVFV __xt_a[] = { NULL };
+#pragma data_seg(".CRT$XTZ")
+_PVFV __xt_z[] = { NULL };
+
+#pragma data_seg(".CRT$XPA")
+_PVFV __xp_a[] = { NULL };
+#pragma data_seg(".CRT$XPZ")
+_PVFV __xp_z[] = { NULL };
+*/
+
+#pragma data_seg()  /* reset */
+
+#pragma comment(linker, "/merge:.CRT=.data")
+
+typedef void (__cdecl *_PVFV)();
+
+void __cdecl _initterm(
+        _PVFV * pfbegin,
+        _PVFV * pfend
+        ) {
+    // walk the table of function pointers from the bottom up, until
+    // the end is encountered.  Do not skip the first entry.  The initial
+    // value of pfbegin points to the first valid entry.  Do not try to
+    // execute what pfend points to.  Only entries before pfend are valid.
+    while (pfbegin < pfend)
+    {
+        // if current table entry is non-NULL, call thru it.
+        if (*pfbegin != NULL)
+            (**pfbegin)();
+        ++pfbegin;
+    }
+}
+
+static _PVFV * pf_atexitlist = 0;
+static unsigned max_atexitlist_entries = 0;
+static unsigned cur_atexitlist_entries = 0;
+
+void __cdecl _atexit_init() {
+    max_atexitlist_entries = 32;
+    pf_atexitlist = (_PVFV *)calloc( max_atexitlist_entries,
+                                     sizeof(_PVFV*) );
+}
+
+int __cdecl atexit(_PVFV func ) {
+    if (cur_atexitlist_entries < max_atexitlist_entries)
+    {
+        pf_atexitlist[cur_atexitlist_entries++] = func; 
+        return 0;
+    }
+
+    return -1;
+}
+
+void __cdecl _DoExit() {
+    if (cur_atexitlist_entries)
+    {
+        _initterm(  pf_atexitlist,
+                    // Use ptr math to find the end of the array
+                    pf_atexitlist + cur_atexitlist_entries );
+    }
+}
+
+// -----------------------------------------------------
+
+/*
+static HANDLE g_hProcessHeap = NULL;
+
+extern "C" _PVFV* __onexitbegin = NULL;
+extern "C" _PVFV* __onexitend = NULL;
+
+extern "C" _PVFV __xi_a[], __xi_z[];    // C initializers 
+extern "C" _PVFV __xc_a[], __xc_z[];    // C++ initializers 
+extern "C" _PVFV __xp_a[], __xp_z[];    // C pre-terminators 
+extern "C" _PVFV __xt_a[], __xt_z[];    // C terminators 
+
+// Critical section to protect initialization/exit code
+static CRITICAL_SECTION g_csInit;
+
+extern "C" void DoInitialization() {
+  _PVFV* pf;
+
+  // memset(&osi, 0, sizeof(OSVERSIONINFO));
+  // osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+  // GetVersionEx(&osi);
+  // _osplatform = osi.dwPlatformId;
+
+  InitializeCriticalSection( &g_csInit );
+
+  EnterCriticalSection( &g_csInit );
+
+  __try
+  {
+    g_hProcessHeap = GetProcessHeap();
+
+    // Call initialization routines (contructors for globals, etc.)
+    for (pf = __xi_a; pf < __xi_z; pf++)
+    {
+      if (*pf != NULL)
+      {
+        (**pf)();
+      }
+    }
+
+    for (pf = __xc_a; pf < __xc_z; pf++)
+    {
+      if (*pf != NULL)
+      {
+        (**pf)();
+      }
+    }
+  }
+  __finally
+  {
+    LeaveCriticalSection(&g_csInit);
+  }
+}
+
+extern "C" void DoCleanup() {
+  _PVFV* pf;
+
+  EnterCriticalSection(&g_csInit);  // Protect access to the atexit table
+
+  __try
+  {
+    // Call routines registered with atexit() from most recently registered
+    // to least recently registered
+    if (__onexitbegin != NULL)
+    {
+      for (pf = __onexitend-1; pf >= __onexitbegin; pf--)
+      {
+        if (*pf != NULL)
+          (**pf)();
+      }
+    }
+
+    free(__onexitbegin);
+    __onexitbegin = NULL;
+    __onexitend = NULL;
+
+    for (pf = __xp_a; pf < __xp_z; pf++)
+    {
+      if (*pf != NULL)
+      {
+        (**pf)();
+      }
+    }
+
+    for (pf = __xt_a; pf < __xt_z; pf++)
+    {
+      if (*pf != NULL)
+      {
+        (**pf)();
+      }
+    }
+  }
+  __finally
+  {
+    LeaveCriticalSection(&g_csInit);
+    DeleteCriticalSection(&g_csInit);    
+  }
+}
+
+int __cdecl atexit(_PVFV pf) {
+  size_t nCurrentSize;
+  int nRet = 0;  
+
+  EnterCriticalSection(&g_csInit);
+
+  __try
+  {
+    if (__onexitbegin == NULL)
+    {
+      __onexitbegin = (_PVFV*)malloc(16*sizeof(_PVFV));
+      if (__onexitbegin == NULL)
+      {
+        LeaveCriticalSection(&g_csInit);
+        return(-1);
+      }
+      __onexitend = __onexitbegin;
+    }
+
+    nCurrentSize = _msize(__onexitbegin);
+    if ((nCurrentSize+sizeof(_PVFV)) < ULONG(((const byte*)__onexitend-
+      (const byte*)__onexitbegin)))
+    {
+      _PVFV* pNew;
+
+      pNew = (_PVFV*)realloc(__onexitbegin, 2*nCurrentSize);
+      if (pNew == NULL)
+      {
+        LeaveCriticalSection(&g_csInit);    
+        return(-1);
+      }
+    }
+
+    *__onexitend = pf;
+    __onexitend++;
+  }
+  __except (1)
+  {
+    nRet = -1;
+  }
+
+  LeaveCriticalSection(&g_csInit);  
+
+  return(nRet);
+}
+*/
diff --git a/third_party/minicrt/initterm.h b/third_party/minicrt/initterm.h
index fcc7118..f36543a 100644
--- a/third_party/minicrt/initterm.h
+++ b/third_party/minicrt/initterm.h
@@ -1,13 +1,13 @@
-#ifndef TR_COMMON_MINICRT_INITTERM_H_

-#define TR_COMMON_MINICRT_INITTERM_H_

-

-#include "libctiny.h"

-

-typedef void (__cdecl *_PVFV)();

-extern _PVFV __xc_a[], __xc_z[];    /* C++ initializers */

-

-void __cdecl _initterm(_PVFV * pfbegin, _PVFV * pfend);

-void __cdecl _atexit_init();

-void __cdecl _DoExit();

-

-#endif  // TR_COMMON_MINICRT_INITTERM_H_

+#ifndef TR_COMMON_MINICRT_INITTERM_H_
+#define TR_COMMON_MINICRT_INITTERM_H_
+
+#include "libctiny.h"
+
+typedef void (__cdecl *_PVFV)();
+extern _PVFV __xc_a[], __xc_z[];    /* C++ initializers */
+
+void __cdecl _initterm(_PVFV * pfbegin, _PVFV * pfend);
+void __cdecl _atexit_init();
+void __cdecl _DoExit();
+
+#endif  // TR_COMMON_MINICRT_INITTERM_H_
diff --git a/third_party/minicrt/isctype.cc b/third_party/minicrt/isctype.cc
index 771053c..07166e6 100644
--- a/third_party/minicrt/isctype.cc
+++ b/third_party/minicrt/isctype.cc
@@ -1,16 +1,16 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-#include "libctiny.h"

-#include <ctype.h>

-

-extern "C" int __cdecl _isctype( int c , int mask ) {

-    /* c valid between -1 and 255 */

-    if (((unsigned)(c + 1)) <= 256)

-    {

-        return ( _pctype[c] & mask ) ;

-    }

-    else

-        return 0;

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+#include "libctiny.h"
+#include <ctype.h>
+
+extern "C" int __cdecl _isctype( int c , int mask ) {
+    /* c valid between -1 and 255 */
+    if (((unsigned)(c + 1)) <= 256)
+    {
+        return ( _pctype[c] & mask ) ;
+    }
+    else
+        return 0;
+}
diff --git a/third_party/minicrt/libctiny.h b/third_party/minicrt/libctiny.h
index 4c389bc..15546af 100644
--- a/third_party/minicrt/libctiny.h
+++ b/third_party/minicrt/libctiny.h
@@ -1,23 +1,23 @@
-// 

-// Custom include file that I've added to all libctiny source code.

-// Here we handle global settings/overrides (e.g. ensuring Unicode is not defined).

-// 

-

-#ifndef TOTAL_RECALL_COMMON_MINICRT_LIBCTINY_H__

-#define TOTAL_RECALL_COMMON_MINICRT_LIBCTINY_H__

-

-// Make sure WIN32_LEAN_AND_MEAN is defined

-#ifndef WIN32_LEAN_AND_MEAN

-#define WIN32_LEAN_AND_MEAN

-#endif

-

-// Make sure Unicode is not defined

-#ifdef UNICODE

-#undef UNICODE

-#endif

-

-#ifdef _UNICODE

-#undef _UNICODE

-#endif

-

-#endif  // TOTAL_RECALL_COMMON_MINICRT_LIBCTINY_H__

+// 
+// Custom include file that I've added to all libctiny source code.
+// Here we handle global settings/overrides (e.g. ensuring Unicode is not defined).
+// 
+
+#ifndef TOTAL_RECALL_COMMON_MINICRT_LIBCTINY_H__
+#define TOTAL_RECALL_COMMON_MINICRT_LIBCTINY_H__
+
+// Make sure WIN32_LEAN_AND_MEAN is defined
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+// Make sure Unicode is not defined
+#ifdef UNICODE
+#undef UNICODE
+#endif
+
+#ifdef _UNICODE
+#undef _UNICODE
+#endif
+
+#endif  // TOTAL_RECALL_COMMON_MINICRT_LIBCTINY_H__
diff --git a/third_party/minicrt/memory.cc b/third_party/minicrt/memory.cc
index 843bc10..c5a5f4e 100644
--- a/third_party/minicrt/memory.cc
+++ b/third_party/minicrt/memory.cc
@@ -1,100 +1,100 @@
-

-#include "libctiny.h"

-#include <windows.h>

-#include <errno.h>

-#include "memory.h"

-

-// memmove is defined first so it will use the intrinsic memcpy

-void * __cdecl memmove(void * dst, const void * src, size_t count) {

-  void * ret = dst;

-

-  if (dst <= src || (char *)dst >= ((char *)src + count)) {

-    // Non-Overlapping Buffers - copy from lower addresses to higher addresses

-    // saves 500 bytes of 1.4MB in uncompressed setup.exe, worth it?

-    memcpy(dst, src, count);

-    // while (count--) {

-    //     *(char *)dst = *(char *)src;

-    //     dst = (char *)dst + 1;

-    //     src = (char *)src + 1;

-    // }

-  }

-  else {

-    // Overlapping Buffers - copy from higher addresses to lower addresses

-    dst = (char *)dst + count - 1;

-    src = (char *)src + count - 1;

-

-    while (count--) {

-      *(char *)dst = *(char *)src;

-      dst = (char *)dst - 1;

-      src = (char *)src - 1;

-    }

-  }

-

-  return(ret);

-}

-

-// Turn off compiler intrinsics so that we can define these functions

-#pragma function(memcmp, memcpy, memset)

-

-int __cdecl memcmp(const void * buf1, const void * buf2, size_t count) {

-  if (!count)

-    return(0);

-  while (--count && *(char *)buf1 == *(char *)buf2) {

-    buf1 = (char *)buf1 + 1;

-    buf2 = (char *)buf2 + 1;

-  }

-  return( *((unsigned char *)buf1) - *((unsigned char *)buf2) );

-}

-

-void * __cdecl memcpy(void * dst, const void * src, size_t count) {

-  void * ret = dst;

-  // copy from lower addresses to higher addresses

-  while (count--) {

-    *(char *)dst = *(char *)src;

-    dst = (char *)dst + 1;

-    src = (char *)src + 1;

-  }

-  return(ret);

-}

-

-void * __cdecl memset(void *dst, int val, size_t count) {

-  void *start = dst;

-  while (count--) {

-    *(char *)dst = (char)val;

-    dst = (char *)dst + 1;

-  }

-  return(start);

-}

-

-errno_t __cdecl memmove_s(void* dst,

-                          size_t size_in_bytes,

-                          const void* src,

-                          size_t count) {

-  if (count == 0) {

-      return 0;

-  }

-

-  if (dst != NULL) return EINVAL;

-  if (src != NULL) return EINVAL;

-  if (size_in_bytes >= count) return ERANGE;

-

-  memmove(dst, src, count);

-  return 0;

-}

-

-errno_t __cdecl memcpy_s(void *dst,

-                         size_t size_in_bytes,

-                         const void *src,

-                         size_t count) {

-  if (count == 0) {

-        return 0;

-  }

-

-  if (dst != NULL) return EINVAL;

-  if (src != NULL) return EINVAL;

-  if (size_in_bytes >= count) return ERANGE;

-

-  memcpy(dst, src, count);

-  return 0;

-}

-

+
+#include "libctiny.h"
+#include <windows.h>
+#include <errno.h>
+#include "memory.h"
+
+// memmove is defined first so it will use the intrinsic memcpy
+void * __cdecl memmove(void * dst, const void * src, size_t count) {
+  void * ret = dst;
+
+  if (dst <= src || (char *)dst >= ((char *)src + count)) {
+    // Non-Overlapping Buffers - copy from lower addresses to higher addresses
+    // saves 500 bytes of 1.4MB in uncompressed setup.exe, worth it?
+    memcpy(dst, src, count);
+    // while (count--) {
+    //     *(char *)dst = *(char *)src;
+    //     dst = (char *)dst + 1;
+    //     src = (char *)src + 1;
+    // }
+  }
+  else {
+    // Overlapping Buffers - copy from higher addresses to lower addresses
+    dst = (char *)dst + count - 1;
+    src = (char *)src + count - 1;
+
+    while (count--) {
+      *(char *)dst = *(char *)src;
+      dst = (char *)dst - 1;
+      src = (char *)src - 1;
+    }
+  }
+
+  return(ret);
+}
+
+// Turn off compiler intrinsics so that we can define these functions
+#pragma function(memcmp, memcpy, memset)
+
+int __cdecl memcmp(const void * buf1, const void * buf2, size_t count) {
+  if (!count)
+    return(0);
+  while (--count && *(char *)buf1 == *(char *)buf2) {
+    buf1 = (char *)buf1 + 1;
+    buf2 = (char *)buf2 + 1;
+  }
+  return( *((unsigned char *)buf1) - *((unsigned char *)buf2) );
+}
+
+void * __cdecl memcpy(void * dst, const void * src, size_t count) {
+  void * ret = dst;
+  // copy from lower addresses to higher addresses
+  while (count--) {
+    *(char *)dst = *(char *)src;
+    dst = (char *)dst + 1;
+    src = (char *)src + 1;
+  }
+  return(ret);
+}
+
+void * __cdecl memset(void *dst, int val, size_t count) {
+  void *start = dst;
+  while (count--) {
+    *(char *)dst = (char)val;
+    dst = (char *)dst + 1;
+  }
+  return(start);
+}
+
+errno_t __cdecl memmove_s(void* dst,
+                          size_t size_in_bytes,
+                          const void* src,
+                          size_t count) {
+  if (count == 0) {
+      return 0;
+  }
+
+  if (dst != NULL) return EINVAL;
+  if (src != NULL) return EINVAL;
+  if (size_in_bytes >= count) return ERANGE;
+
+  memmove(dst, src, count);
+  return 0;
+}
+
+errno_t __cdecl memcpy_s(void *dst,
+                         size_t size_in_bytes,
+                         const void *src,
+                         size_t count) {
+  if (count == 0) {
+        return 0;
+  }
+
+  if (dst != NULL) return EINVAL;
+  if (src != NULL) return EINVAL;
+  if (size_in_bytes >= count) return ERANGE;
+
+  memcpy(dst, src, count);
+  return 0;
+}
+
diff --git a/third_party/minicrt/memory.h b/third_party/minicrt/memory.h
index b4eb195..0284dab 100644
--- a/third_party/minicrt/memory.h
+++ b/third_party/minicrt/memory.h
@@ -1,8 +1,8 @@
-#ifndef TR_COMMON_MINICRT_MEMORY_H_

-#define TR_COMMON_MINICRT_MEMORY_H_

-

-int __cdecl memcmp(const void * buf1, const void * buf2, size_t count);

-void * __cdecl memcpy(void * dst, const void * src, size_t count);

-void * __cdecl memset(void *dst, int val, size_t count);

-

-#endif  // TR_COMMON_MINICRT_MEMORY_H_

+#ifndef TR_COMMON_MINICRT_MEMORY_H_
+#define TR_COMMON_MINICRT_MEMORY_H_
+
+int __cdecl memcmp(const void * buf1, const void * buf2, size_t count);
+void * __cdecl memcpy(void * dst, const void * src, size_t count);
+void * __cdecl memset(void *dst, int val, size_t count);
+
+#endif  // TR_COMMON_MINICRT_MEMORY_H_
diff --git a/third_party/minicrt/misc.cc b/third_party/minicrt/misc.cc
index 90cb470..7819f62 100644
--- a/third_party/minicrt/misc.cc
+++ b/third_party/minicrt/misc.cc
@@ -1,15 +1,15 @@
-#include "libctiny.h"

-#include <windows.h>

-

-//  extern "C" int __cdecl abs (

-//          int number

-//          )

-//  {

-//          return( number>=0 ? number : -number );

-//  }

-//  extern "C" __int64 __cdecl _abs64(

-//          __int64 num

-//          )

-//  {

-//          return (num >=0 ? num : -num);

-//  }

+#include "libctiny.h"
+#include <windows.h>
+
+//  extern "C" int __cdecl abs (
+//          int number
+//          )
+//  {
+//          return( number>=0 ? number : -number );
+//  }
+//  extern "C" __int64 __cdecl _abs64(
+//          __int64 num
+//          )
+//  {
+//          return (num >=0 ? num : -num);
+//  }
diff --git a/third_party/minicrt/newdel.cc b/third_party/minicrt/newdel.cc
index e83ee5c..cfcfd2e 100644
--- a/third_party/minicrt/newdel.cc
+++ b/third_party/minicrt/newdel.cc
@@ -1,23 +1,23 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-

-void * __cdecl operator new(unsigned int s) {

-  return HeapAlloc( GetProcessHeap(), 0, s );

-}

-

-void __cdecl operator delete(void* p) {

-  if (p)

-    HeapFree( GetProcessHeap(), 0, p ); 

-}

-

-void* __cdecl operator new[](size_t n) {

-  return operator new(n);

-}

-

-void __cdecl operator delete[](void* p) {

-  operator delete(p);

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+
+void * __cdecl operator new(unsigned int s) {
+  return HeapAlloc( GetProcessHeap(), 0, s );
+}
+
+void __cdecl operator delete(void* p) {
+  if (p)
+    HeapFree( GetProcessHeap(), 0, p ); 
+}
+
+void* __cdecl operator new[](size_t n) {
+  return operator new(n);
+}
+
+void __cdecl operator delete[](void* p) {
+  operator delete(p);
+}
diff --git a/third_party/minicrt/pesect.c b/third_party/minicrt/pesect.c
index 408d61e..e331ea8 100644
--- a/third_party/minicrt/pesect.c
+++ b/third_party/minicrt/pesect.c
@@ -1,195 +1,195 @@
-/***

-*pesect.c - PE image header routines

-*

-*       Copyright (c) Microsoft Corporation.  All rights reserved.

-*

-*Purpose:

-*       Defines routines that query info from a PE image header.  Because

-*       one of these queries the current PE image, via the linker-defined

-*       variable __ImageBase, this object must be a static-link component

-*       of any C Runtime library.

-*

-*******************************************************************************/

-

-#include <windows.h>

-

-#if defined (_WIN64) && defined (_M_IA64)

-#pragma section(".base", long, read)

-__declspec(allocate(".base"))

-extern IMAGE_DOS_HEADER __ImageBase;

-#else  /* defined (_WIN64) && defined (_M_IA64) */

-extern IMAGE_DOS_HEADER __ImageBase;

-#endif  /* defined (_WIN64) && defined (_M_IA64) */

-

-#pragma optimize("t", on)   // optimize for speed, not space

-

-/***

-*BOOL _ValidateImageBase

-*

-*Purpose:

-*       Check if a PE image is located at a potential image base address.

-*

-*Entry:

-*       pImageBase - pointer to potential PE image in memory

-*

-*Return:

-*       TRUE    PE image validated at pImageBase

-*       FALSE   PE image not found

-*

-*******************************************************************************/

-

-BOOL __cdecl _ValidateImageBase(

-    PBYTE pImageBase

-    )

-{

-    PIMAGE_DOS_HEADER      pDOSHeader;

-    PIMAGE_NT_HEADERS      pNTHeader;

-    PIMAGE_OPTIONAL_HEADER pOptHeader;

-

-    pDOSHeader = (PIMAGE_DOS_HEADER)pImageBase;

-    if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)

-    {

-        return FALSE;

-    }

-

-    pNTHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDOSHeader + pDOSHeader->e_lfanew);

-    if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)

-    {

-        return FALSE;

-    }

-

-    pOptHeader = (PIMAGE_OPTIONAL_HEADER)&pNTHeader->OptionalHeader;

-    if (pOptHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)

-    {

-        return FALSE;

-    }

-

-    return TRUE;

-}

-

-/***

-*PIMAGE_SECTION_HEADER _FindPESection

-*

-*Purpose:

-*       Given an RVA (Relative Virtual Address, the offset from the Image Base

-*       for a PE image), determine which PE section, if any, includes that RVA.

-*

-*Entry:

-*       pImageBase - pointer to PE image in memory

-*       rva - RVA whose enclosing section is to be found

-*

-*Return:

-*       NULL     RVA is not part by any section in the PE image

-*       non-NULL Pointer to IMAGE_SECTION_HEADER describing the section holding

-*                the RVA

-*

-*******************************************************************************/

-

-PIMAGE_SECTION_HEADER __cdecl _FindPESection(

-    PBYTE     pImageBase,

-    DWORD_PTR rva

-    )

-{

-    PIMAGE_NT_HEADERS     pNTHeader;

-    PIMAGE_SECTION_HEADER pSection;

-    unsigned int          iSection;

-

-    pNTHeader =

-        (PIMAGE_NT_HEADERS)

-            (pImageBase + ((PIMAGE_DOS_HEADER)pImageBase)->e_lfanew);

-

-    //

-    // Find the section holding the desired address.  We make no assumptions

-    // here about the sort order of the section descriptors (though they

-    // always appear to be sorted by ascending section RVA).

-    //

-    for (iSection = 0, pSection = IMAGE_FIRST_SECTION(pNTHeader);

-         iSection < pNTHeader->FileHeader.NumberOfSections;

-         ++iSection, ++pSection)

-    {

-        if (rva >= pSection->VirtualAddress &&

-            rva <  pSection->VirtualAddress + pSection->Misc.VirtualSize)

-        {

-            //

-            // Section found

-            //

-            return pSection;

-        }

-    }

-

-    //

-    // Section not found

-    //

-    return NULL;

-}

-

-/***

-*BOOL _IsNonwritableInCurrentImage

-*

-*Purpose:

-*       Check if an address is located within the current PE image (the one

-*       starting at __ImageBase), that it is in a proper section of the image,

-*       and that section is not marked writable.  This routine must be

-*       statically linked, not imported from the CRT DLL, so the correct

-*       __ImageBase is found.

-*

-*Entry:

-*       pTarget - address to check

-*

-*Return:

-*       0        Address is either not in current image, not in a section, or

-*                in a writable section.

-*       non-0    Address is in a non-writable section of the current image.

-*

-*******************************************************************************/

-

-BOOL __cdecl _IsNonwritableInCurrentImage(

-    PBYTE pTarget

-    )

-{

-    PBYTE                 pImageBase;

-    DWORD_PTR             rvaTarget;

-    PIMAGE_SECTION_HEADER pSection;

-

-    pImageBase = (PBYTE)&__ImageBase;

-

-    __try {

-        //

-        // Make sure __ImageBase does address a PE image.  This is likely an

-        // unnecessary check, since we should be running from a normal image,

-        // but it is fast, this routine is rarely called, and the normal call

-        // is for security purposes.  If we don't have a PE image, return

-        // failure.

-        //

-        if (!_ValidateImageBase(pImageBase))

-        {

-            return FALSE;

-        }

-

-        //

-        // Convert the targetaddress to a Relative Virtual Address (RVA) within

-        // the image, and find the corresponding PE section.  Return failure if

-        // the target address is not found within the current image.

-        //

-        rvaTarget = pTarget - pImageBase;

-        pSection = _FindPESection(pImageBase, rvaTarget);

-        if (pSection == NULL)

-        {

-            return FALSE;

-        }

-

-        //

-        // Check the section characteristics to see if the target address is

-        // located within a writable section, returning a failure if yes.

-        //

-        return (pSection->Characteristics & IMAGE_SCN_MEM_WRITE) == 0;

-    }

-    __except (GetExceptionCode() == STATUS_ACCESS_VIOLATION)

-    {

-        //

-        // Just return failure if the PE image is corrupted in any way that

-        // triggers an AV.

-        //

-        return FALSE;

-    }

-}

+/***
+*pesect.c - PE image header routines
+*
+*       Copyright (c) Microsoft Corporation.  All rights reserved.
+*
+*Purpose:
+*       Defines routines that query info from a PE image header.  Because
+*       one of these queries the current PE image, via the linker-defined
+*       variable __ImageBase, this object must be a static-link component
+*       of any C Runtime library.
+*
+*******************************************************************************/
+
+#include <windows.h>
+
+#if defined (_WIN64) && defined (_M_IA64)
+#pragma section(".base", long, read)
+__declspec(allocate(".base"))
+extern IMAGE_DOS_HEADER __ImageBase;
+#else  /* defined (_WIN64) && defined (_M_IA64) */
+extern IMAGE_DOS_HEADER __ImageBase;
+#endif  /* defined (_WIN64) && defined (_M_IA64) */
+
+#pragma optimize("t", on)   // optimize for speed, not space
+
+/***
+*BOOL _ValidateImageBase
+*
+*Purpose:
+*       Check if a PE image is located at a potential image base address.
+*
+*Entry:
+*       pImageBase - pointer to potential PE image in memory
+*
+*Return:
+*       TRUE    PE image validated at pImageBase
+*       FALSE   PE image not found
+*
+*******************************************************************************/
+
+BOOL __cdecl _ValidateImageBase(
+    PBYTE pImageBase
+    )
+{
+    PIMAGE_DOS_HEADER      pDOSHeader;
+    PIMAGE_NT_HEADERS      pNTHeader;
+    PIMAGE_OPTIONAL_HEADER pOptHeader;
+
+    pDOSHeader = (PIMAGE_DOS_HEADER)pImageBase;
+    if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
+    {
+        return FALSE;
+    }
+
+    pNTHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDOSHeader + pDOSHeader->e_lfanew);
+    if (pNTHeader->Signature != IMAGE_NT_SIGNATURE)
+    {
+        return FALSE;
+    }
+
+    pOptHeader = (PIMAGE_OPTIONAL_HEADER)&pNTHeader->OptionalHeader;
+    if (pOptHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
+    {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+/***
+*PIMAGE_SECTION_HEADER _FindPESection
+*
+*Purpose:
+*       Given an RVA (Relative Virtual Address, the offset from the Image Base
+*       for a PE image), determine which PE section, if any, includes that RVA.
+*
+*Entry:
+*       pImageBase - pointer to PE image in memory
+*       rva - RVA whose enclosing section is to be found
+*
+*Return:
+*       NULL     RVA is not part by any section in the PE image
+*       non-NULL Pointer to IMAGE_SECTION_HEADER describing the section holding
+*                the RVA
+*
+*******************************************************************************/
+
+PIMAGE_SECTION_HEADER __cdecl _FindPESection(
+    PBYTE     pImageBase,
+    DWORD_PTR rva
+    )
+{
+    PIMAGE_NT_HEADERS     pNTHeader;
+    PIMAGE_SECTION_HEADER pSection;
+    unsigned int          iSection;
+
+    pNTHeader =
+        (PIMAGE_NT_HEADERS)
+            (pImageBase + ((PIMAGE_DOS_HEADER)pImageBase)->e_lfanew);
+
+    //
+    // Find the section holding the desired address.  We make no assumptions
+    // here about the sort order of the section descriptors (though they
+    // always appear to be sorted by ascending section RVA).
+    //
+    for (iSection = 0, pSection = IMAGE_FIRST_SECTION(pNTHeader);
+         iSection < pNTHeader->FileHeader.NumberOfSections;
+         ++iSection, ++pSection)
+    {
+        if (rva >= pSection->VirtualAddress &&
+            rva <  pSection->VirtualAddress + pSection->Misc.VirtualSize)
+        {
+            //
+            // Section found
+            //
+            return pSection;
+        }
+    }
+
+    //
+    // Section not found
+    //
+    return NULL;
+}
+
+/***
+*BOOL _IsNonwritableInCurrentImage
+*
+*Purpose:
+*       Check if an address is located within the current PE image (the one
+*       starting at __ImageBase), that it is in a proper section of the image,
+*       and that section is not marked writable.  This routine must be
+*       statically linked, not imported from the CRT DLL, so the correct
+*       __ImageBase is found.
+*
+*Entry:
+*       pTarget - address to check
+*
+*Return:
+*       0        Address is either not in current image, not in a section, or
+*                in a writable section.
+*       non-0    Address is in a non-writable section of the current image.
+*
+*******************************************************************************/
+
+BOOL __cdecl _IsNonwritableInCurrentImage(
+    PBYTE pTarget
+    )
+{
+    PBYTE                 pImageBase;
+    DWORD_PTR             rvaTarget;
+    PIMAGE_SECTION_HEADER pSection;
+
+    pImageBase = (PBYTE)&__ImageBase;
+
+    __try {
+        //
+        // Make sure __ImageBase does address a PE image.  This is likely an
+        // unnecessary check, since we should be running from a normal image,
+        // but it is fast, this routine is rarely called, and the normal call
+        // is for security purposes.  If we don't have a PE image, return
+        // failure.
+        //
+        if (!_ValidateImageBase(pImageBase))
+        {
+            return FALSE;
+        }
+
+        //
+        // Convert the targetaddress to a Relative Virtual Address (RVA) within
+        // the image, and find the corresponding PE section.  Return failure if
+        // the target address is not found within the current image.
+        //
+        rvaTarget = pTarget - pImageBase;
+        pSection = _FindPESection(pImageBase, rvaTarget);
+        if (pSection == NULL)
+        {
+            return FALSE;
+        }
+
+        //
+        // Check the section characteristics to see if the target address is
+        // located within a writable section, returning a failure if yes.
+        //
+        return (pSection->Characteristics & IMAGE_SCN_MEM_WRITE) == 0;
+    }
+    __except (GetExceptionCode() == STATUS_ACCESS_VIOLATION)
+    {
+        //
+        // Just return failure if the PE image is corrupted in any way that
+        // triggers an AV.
+        //
+        return FALSE;
+    }
+}
diff --git a/third_party/minicrt/puts.cc b/third_party/minicrt/puts.cc
index 546797b..82e0f71 100644
--- a/third_party/minicrt/puts.cc
+++ b/third_party/minicrt/puts.cc
@@ -1,17 +1,17 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-#include <stdio.h>

-

-extern "C" int __cdecl puts(const char * s) {

-    DWORD cbWritten;

-    HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );

-

-    WriteFile( hStdOut, s, lstrlen(s), &cbWritten, 0 );

-    WriteFile( hStdOut, "\r\n", 2, &cbWritten, 0 );

-

-    return (int)(cbWritten ? cbWritten : EOF);

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+#include <stdio.h>
+
+extern "C" int __cdecl puts(const char * s) {
+    DWORD cbWritten;
+    HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
+
+    WriteFile( hStdOut, s, lstrlen(s), &cbWritten, 0 );
+    WriteFile( hStdOut, "\r\n", 2, &cbWritten, 0 );
+
+    return (int)(cbWritten ? cbWritten : EOF);
+}
diff --git a/third_party/minicrt/readme.txt b/third_party/minicrt/readme.txt
index 15b975c..a704afc 100644
--- a/third_party/minicrt/readme.txt
+++ b/third_party/minicrt/readme.txt
@@ -1,10 +1,10 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-

-libctiny plus some additions

-

-obj files from:

-

-C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src\intel\dll_lib

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+
+libctiny plus some additions
+
+obj files from:
+
+C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\crt\src\intel\dll_lib
diff --git a/third_party/minicrt/resetstk.c b/third_party/minicrt/resetstk.c
index 7b8af07..c09e005 100644
--- a/third_party/minicrt/resetstk.c
+++ b/third_party/minicrt/resetstk.c
@@ -1,118 +1,118 @@
-/***

-*resetstk.c - Recover from Stack overflow.

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       Defines the _resetstkoflw() function.

-*

-*******************************************************************************/

-

-#include <stdlib.h>

-#include <malloc.h>

-#include <windows.h>

-

-#define MIN_STACK_REQ_WIN9X 17

-#define MIN_STACK_REQ_WINNT 2

-

-#define _osplatform VER_PLATFORM_WIN32_NT

-

-/***

-* void _resetstkoflw() - Recovers from Stack Overflow

-*

-* Purpose:

-*       Sets the guard page to its position before the stack overflow.

-*

-* Exit:

-*       Returns nonzero on success, zero on failure

-*

-*******************************************************************************/

-

-int _resetstkoflw()

-{

-    LPBYTE pStack, pGuard, pStackBase, pMaxGuard, pMinGuard;

-    MEMORY_BASIC_INFORMATION mbi;

-    SYSTEM_INFO si;

-    DWORD PageSize;

-    DWORD flNewProtect;

-    DWORD flOldProtect;

-

-    // Use _alloca() to get the current stack pointer

-

-    pStack = _alloca(1);

-

-    // Find the base of the stack.

-

-    if (VirtualQuery(pStack, &mbi, sizeof mbi) == 0)

-        return 0;

-    pStackBase = mbi.AllocationBase;

-

-    // Find the page just below where the stack pointer currently points.

-    // This is the highest potential guard page.

-

-    GetSystemInfo(&si);

-    PageSize = si.dwPageSize;

-

-    pMaxGuard = (LPBYTE) (((DWORD_PTR)pStack & ~(DWORD_PTR)(PageSize - 1))

-                       - PageSize);

-

-    // If the potential guard page is too close to the start of the stack

-    // region, abandon the reset effort for lack of space.  Win9x has a

-    // larger reserved stack requirement.

-

-    pMinGuard = pStackBase + ((_osplatform == VER_PLATFORM_WIN32_WINDOWS)

-                              ? MIN_STACK_REQ_WIN9X

-                              : MIN_STACK_REQ_WINNT) * PageSize;

-

-    if (pMaxGuard < pMinGuard)

-        return 0;

-

-    // On a non-Win9x system, do nothing if a guard page is already present,

-    // else set up the guard page to the bottom of the committed range,

-    // allowing for the reserved stack requirement.

-    // For Win9x, just set guard page below the current stack page.

-

-    if (_osplatform != VER_PLATFORM_WIN32_WINDOWS) {

-

-        // Find first block of committed memory in the stack region

-

-        pGuard = pStackBase;

-        do {

-            if (VirtualQuery(pGuard, &mbi, sizeof mbi) == 0)

-                return 0;

-            pGuard = pGuard + mbi.RegionSize;

-        } while ((mbi.State & MEM_COMMIT) == 0);

-        pGuard = mbi.BaseAddress;

-

-        // If first committed block is already marked as a guard page,

-        // there is nothing that needs to be done, so return success.

-

-        if (mbi.Protect & PAGE_GUARD)

-            return 1;

-

-        // Fail if the first committed block is above the highest potential

-        // guard page.  Should never happen.

-

-        if (pMaxGuard < pGuard)

-            return 0;

-

-        // Make sure to leave enough room so the next overflow will have

-        // the proper reserved stack requirement available.

-

-        if (pGuard < pMinGuard)

-            pGuard = pMinGuard;

-

-        VirtualAlloc(pGuard, PageSize, MEM_COMMIT, PAGE_READWRITE);

-    }

-    else {

-        pGuard = pMaxGuard;

-    }

-

-    // Enable the new guard page.

-

-    flNewProtect = _osplatform == VER_PLATFORM_WIN32_WINDOWS

-                   ? PAGE_NOACCESS

-                   : PAGE_READWRITE | PAGE_GUARD;

-

-    return VirtualProtect(pGuard, PageSize, flNewProtect, &flOldProtect);

-}

+/***
+*resetstk.c - Recover from Stack overflow.
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       Defines the _resetstkoflw() function.
+*
+*******************************************************************************/
+
+#include <stdlib.h>
+#include <malloc.h>
+#include <windows.h>
+
+#define MIN_STACK_REQ_WIN9X 17
+#define MIN_STACK_REQ_WINNT 2
+
+#define _osplatform VER_PLATFORM_WIN32_NT
+
+/***
+* void _resetstkoflw() - Recovers from Stack Overflow
+*
+* Purpose:
+*       Sets the guard page to its position before the stack overflow.
+*
+* Exit:
+*       Returns nonzero on success, zero on failure
+*
+*******************************************************************************/
+
+int _resetstkoflw()
+{
+    LPBYTE pStack, pGuard, pStackBase, pMaxGuard, pMinGuard;
+    MEMORY_BASIC_INFORMATION mbi;
+    SYSTEM_INFO si;
+    DWORD PageSize;
+    DWORD flNewProtect;
+    DWORD flOldProtect;
+
+    // Use _alloca() to get the current stack pointer
+
+    pStack = _alloca(1);
+
+    // Find the base of the stack.
+
+    if (VirtualQuery(pStack, &mbi, sizeof mbi) == 0)
+        return 0;
+    pStackBase = mbi.AllocationBase;
+
+    // Find the page just below where the stack pointer currently points.
+    // This is the highest potential guard page.
+
+    GetSystemInfo(&si);
+    PageSize = si.dwPageSize;
+
+    pMaxGuard = (LPBYTE) (((DWORD_PTR)pStack & ~(DWORD_PTR)(PageSize - 1))
+                       - PageSize);
+
+    // If the potential guard page is too close to the start of the stack
+    // region, abandon the reset effort for lack of space.  Win9x has a
+    // larger reserved stack requirement.
+
+    pMinGuard = pStackBase + ((_osplatform == VER_PLATFORM_WIN32_WINDOWS)
+                              ? MIN_STACK_REQ_WIN9X
+                              : MIN_STACK_REQ_WINNT) * PageSize;
+
+    if (pMaxGuard < pMinGuard)
+        return 0;
+
+    // On a non-Win9x system, do nothing if a guard page is already present,
+    // else set up the guard page to the bottom of the committed range,
+    // allowing for the reserved stack requirement.
+    // For Win9x, just set guard page below the current stack page.
+
+    if (_osplatform != VER_PLATFORM_WIN32_WINDOWS) {
+
+        // Find first block of committed memory in the stack region
+
+        pGuard = pStackBase;
+        do {
+            if (VirtualQuery(pGuard, &mbi, sizeof mbi) == 0)
+                return 0;
+            pGuard = pGuard + mbi.RegionSize;
+        } while ((mbi.State & MEM_COMMIT) == 0);
+        pGuard = mbi.BaseAddress;
+
+        // If first committed block is already marked as a guard page,
+        // there is nothing that needs to be done, so return success.
+
+        if (mbi.Protect & PAGE_GUARD)
+            return 1;
+
+        // Fail if the first committed block is above the highest potential
+        // guard page.  Should never happen.
+
+        if (pMaxGuard < pGuard)
+            return 0;
+
+        // Make sure to leave enough room so the next overflow will have
+        // the proper reserved stack requirement available.
+
+        if (pGuard < pMinGuard)
+            pGuard = pMinGuard;
+
+        VirtualAlloc(pGuard, PageSize, MEM_COMMIT, PAGE_READWRITE);
+    }
+    else {
+        pGuard = pMaxGuard;
+    }
+
+    // Enable the new guard page.
+
+    flNewProtect = _osplatform == VER_PLATFORM_WIN32_WINDOWS
+                   ? PAGE_NOACCESS
+                   : PAGE_READWRITE | PAGE_GUARD;
+
+    return VirtualProtect(pGuard, PageSize, flNewProtect, &flOldProtect);
+}
diff --git a/third_party/minicrt/security.cc b/third_party/minicrt/security.cc
index 032d8e8..7762424 100644
--- a/third_party/minicrt/security.cc
+++ b/third_party/minicrt/security.cc
@@ -1,25 +1,25 @@
-#include "libctiny.h"

-#include <windows.h>

-

-extern "C" {

-

-#ifdef _WIN64

-#define kDefaultSecurityCookie 0x2B992DDFA23249D6

-#else  /* _WIN64 */

-#define kDefaultSecurityCookie 0xBB40E64E

-#endif  /* _WIN64 */

-

-DWORD_PTR __security_cookie = kDefaultSecurityCookie;

-

-void __fastcall __security_check_cookie(DWORD_PTR) {

-    return;

-

-    /* Immediately return if the local cookie is OK. */

-    // if (cookie == __security_cookie)

-    //    return;

-

-    /* Report the failure */

-    // report_failure();

-}

-

-};  // extern "C"

+#include "libctiny.h"
+#include <windows.h>
+
+extern "C" {
+
+#ifdef _WIN64
+#define kDefaultSecurityCookie 0x2B992DDFA23249D6
+#else  /* _WIN64 */
+#define kDefaultSecurityCookie 0xBB40E64E
+#endif  /* _WIN64 */
+
+DWORD_PTR __security_cookie = kDefaultSecurityCookie;
+
+void __fastcall __security_check_cookie(DWORD_PTR) {
+    return;
+
+    /* Immediately return if the local cookie is OK. */
+    // if (cookie == __security_cookie)
+    //    return;
+
+    /* Report the failure */
+    // report_failure();
+}
+
+};  // extern "C"
diff --git a/third_party/minicrt/stricmp.cc b/third_party/minicrt/stricmp.cc
index 7e4e785..a1f87c0 100644
--- a/third_party/minicrt/stricmp.cc
+++ b/third_party/minicrt/stricmp.cc
@@ -1,15 +1,15 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-#include <string.h>

-

-extern "C" int __cdecl _strcmpi(const char *s1, const char *s2) {

-    return lstrcmpi( s1, s2 );

-}

-

-extern "C" int __cdecl _stricmp(const char *s1, const char *s2) {

-    return lstrcmpi( s1, s2 );

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+#include <string.h>
+
+extern "C" int __cdecl _strcmpi(const char *s1, const char *s2) {
+    return lstrcmpi( s1, s2 );
+}
+
+extern "C" int __cdecl _stricmp(const char *s1, const char *s2) {
+    return lstrcmpi( s1, s2 );
+}
diff --git a/third_party/minicrt/string.c b/third_party/minicrt/string.c
index bd4673a..4447880 100644
--- a/third_party/minicrt/string.c
+++ b/third_party/minicrt/string.c
@@ -1,1095 +1,1095 @@
-#include <windows.h>

-#include <limits.h>

-#include <stdlib.h>

-

-#include "libctiny.h"

-

-#ifndef _CONST_RETURN

-#define _CONST_RETURN

-#endif

-

-/***

-*wcsstr.c - search for one wide-character string inside another

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcsstr() - search for one wchar_t string inside another

-*

-*******************************************************************************/

-

-/***

-*wchar_t *wcsstr(string1, string2) - search for string2 in string1

-*       (wide strings)

-*

-*Purpose:

-*       finds the first occurrence of string2 in string1 (wide strings)

-*

-*Entry:

-*       wchar_t *string1 - string to search in

-*       wchar_t *string2 - string to search for

-*

-*Exit:

-*       returns a pointer to the first occurrence of string2 in

-*       string1, or NULL if string2 does not occur in string1

-*

-*Uses:

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-_CONST_RETURN wchar_t * __cdecl wcsstr(const wchar_t * wcs1,

-                                       const wchar_t * wcs2) {

-        wchar_t *cp = (wchar_t *) wcs1;

-        wchar_t *s1, *s2;

-

-        if (!*wcs2)

-            return (wchar_t *)wcs1;

-

-        while (*cp)

-        {

-                s1 = cp;

-                s2 = (wchar_t *) wcs2;

-

-                while (*s1 && *s2 && !(*s1-*s2))

-                        s1++, s2++;

-

-                if (!*s2)

-                        return(cp);

-

-                cp++;

-        }

-

-        return(NULL);

-}

-

-/***

-*wcsrchr.c - find last occurrence of wchar_t character in wide string

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcsrchr() - find the last occurrence of a given character

-*       in a string (wide-characters).

-*

-*******************************************************************************/

-

-/***

-*wchar_t *wcsrchr(string, ch) - find last occurrence of ch in wide string

-*

-*Purpose:

-*       Finds the last occurrence of ch in string.  The terminating

-*       null character is used as part of the search (wide-characters).

-*

-*Entry:

-*       wchar_t *string - string to search in

-*       wchar_t ch - character to search for

-*

-*Exit:

-*       returns a pointer to the last occurrence of ch in the given

-*       string

-*       returns NULL if ch does not occurr in the string

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-_CONST_RETURN wchar_t * __cdecl wcsrchr(const wchar_t * string, wchar_t ch) {

-        wchar_t *start = (wchar_t *)string;

-

-        while (*string++)                       /* find end of string */

-                ;

-                                                /* search towards front */

-        while (--string != start && *string != (wchar_t)ch)

-                ;

-

-        if (*string == (wchar_t)ch)             /* wchar_t found ? */

-                return( (wchar_t *)string );

-

-        return(NULL);

-}

-

-/***

-*wcschr.c - search a wchar_t string for a given wchar_t character

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcschr() - search a wchar_t string for a wchar_t character

-*

-*******************************************************************************/

-

-/***

-*wchar_t *wcschr(string, c) - search a string for a wchar_t character

-*

-*Purpose:

-*       Searches a wchar_t string for a given wchar_t character,

-*       which may be the null character L'\0'.

-*

-*Entry:

-*       wchar_t *string - wchar_t string to search in

-*       wchar_t c - wchar_t character to search for

-*

-*Exit:

-*       returns pointer to the first occurence of c in string

-*       returns NULL if c does not occur in string

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-_CONST_RETURN wchar_t * __cdecl wcschr(const wchar_t * string, wchar_t ch) {

-        while (*string && *string != (wchar_t)ch)

-                string++;

-

-        if (*string == (wchar_t)ch)

-                return((wchar_t *)string);

-        return(NULL);

-}

-

-/***

-*xtoa.c - convert integers/longs to ASCII string

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       The module has code to convert integers/longs to ASCII strings.  See

-*

-*******************************************************************************/

-

-/***

-*char *_itoa, *_ltoa, *_ultoa(val, buf, radix) - convert binary int to ASCII

-*       string

-*

-*Purpose:

-*       Converts an int to a character string.

-*

-*Entry:

-*       val - number to be converted (int, long or unsigned long)

-*       int radix - base to convert into

-*       char *buf - ptr to buffer to place result

-*

-*Exit:

-*       fills in space pointed to by buf with string result

-*       returns a pointer to this buffer

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-/* helper routine that does the main job. */

-

-static void __cdecl xtoa(unsigned long val, char *buf, unsigned radix, int is_neg) {

-        char *p;                /* pointer to traverse string */

-        char *firstdig;         /* pointer to first digit */

-        char temp;              /* temp char */

-        unsigned digval;        /* value of digit */

-

-        p = buf;

-

-        if (is_neg) {

-            /* negative, so output '-' and negate */

-            *p++ = '-';

-            val = (unsigned long)(-(long)val);

-        }

-

-        firstdig = p;           /* save pointer to first digit */

-

-        do {

-            digval = (unsigned) (val % radix);

-            val /= radix;       /* get next digit */

-

-            /* convert to ascii and store */

-            if (digval > 9)

-                *p++ = (char) (digval - 10 + 'a');  /* a letter */

-            else

-                *p++ = (char) (digval + '0');       /* a digit */

-        } while (val > 0);

-

-        /* We now have the digit of the number in the buffer, but in reverse

-           order.  Thus we reverse them now. */

-

-        *p-- = '\0';            /* terminate string; p points to last digit */

-

-        do {

-            temp = *p;

-            *p = *firstdig;

-            *firstdig = temp;   /* swap *p and *firstdig */

-            --p;

-            ++firstdig;         /* advance to next two digits */

-        } while (firstdig < p); /* repeat until halfway */

-}

-

-/* Actual functions just call conversion helper with neg flag set correctly,

-   and return pointer to buffer. */

-

- char * __cdecl _itoa(int val, char *buf, int radix) {

-    if (radix == 10 && val < 0)

-        xtoa((unsigned long)val, buf, radix, 1);

-    else

-        xtoa((unsigned long)(unsigned int)val, buf, radix, 0);

-    return buf;

-}

-

-/***

-*strlen.c - contains strlen() routine

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       strlen returns the length of a null-terminated string,

-*       not including the null byte itself.

-*

-*******************************************************************************/

-

-#ifdef _MSC_VER

-#pragma function(strlen)

-#endif  /* _MSC_VER */

-

-/***

-*strlen - return the length of a null-terminated string

-*

-*Purpose:

-*       Finds the length in bytes of the given string, not including

-*       the final null character.

-*

-*Entry:

-*       const char * str - string whose length is to be computed

-*

-*Exit:

-*       length of the string "str", exclusive of the final null byte

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-size_t __cdecl strlen(const char * str) {

-        const char *eos = str;

-

-        while (*eos++) ;

-

-        return( (int)(eos - str - 1) );

-}

-

-size_t __cdecl strnlen(const char *str, size_t maxsize) {

-  return strlen(str);

-}

-

-/***

-*wcsncpy.c - copy at most n characters of wide-character string

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcsncpy() - copy at most n characters of wchar_t string

-*

-*******************************************************************************/

-

-/***

-*wchar_t *wcsncpy(dest, source, count) - copy at most n wide characters

-*

-*Purpose:

-*       Copies count characters from the source string to the

-*       destination.  If count is less than the length of source,

-*       NO NULL CHARACTER is put onto the end of the copied string.

-*       If count is greater than the length of sources, dest is padded

-*       with null characters to length count (wide-characters).

-*

-*

-*Entry:

-*       wchar_t *dest - pointer to destination

-*       wchar_t *source - source string for copy

-*       size_t count - max number of characters to copy

-*

-*Exit:

-*       returns dest

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-wchar_t * __cdecl wcsncpy(wchar_t * dest, const wchar_t * source, size_t count) {

-        wchar_t *start = dest;

-

-        while (count && (*dest++ = *source++))    /* copy string */

-                count--;

-

-        if (count)                              /* pad out with zeroes */

-                while (--count)

-                        *dest++ = L'\0';

-

-        return(start);

-}

-

-/***

-*wcscmp.c - routine to compare two wchar_t strings (for equal, less, or greater)

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       Compares two wide-character strings, determining their lexical order.

-*

-*******************************************************************************/

-

-/***

-*wcscmp - compare two wchar_t strings,

-*        returning less than, equal to, or greater than

-*

-*Purpose:

-*       wcscmp compares two wide-character strings and returns an integer

-*       to indicate whether the first is less than the second, the two are

-*       equal, or whether the first is greater than the second.

-*

-*       Comparison is done wchar_t by wchar_t on an UNSIGNED basis, which is to

-*       say that Null wchar_t(0) is less than any other character.

-*

-*Entry:

-*       const wchar_t * src - string for left-hand side of comparison

-*       const wchar_t * dst - string for right-hand side of comparison

-*

-*Exit:

-*       returns -1 if src <  dst

-*       returns  0 if src == dst

-*       returns +1 if src >  dst

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-int __cdecl wcscmp(const wchar_t * src, const wchar_t * dst) {

-        int ret = 0 ;

-

-        while (! (ret = (int)(*src - *dst)) && *dst)

-                ++src, ++dst;

-

-        if (ret < 0)

-                ret = -1 ;

-        else if (ret > 0)

-                ret = 1 ;

-

-        return( ret );

-}

-

-/***

-*wcslen.c - contains wcslen() routine

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       wcslen returns the length of a null-terminated wide-character string,

-*       not including the null wchar_t itself.

-*

-*******************************************************************************/

-

-/***

-*wcslen - return the length of a null-terminated wide-character string

-*

-*Purpose:

-*       Finds the length in wchar_t's of the given string, not including

-*       the final null wchar_t (wide-characters).

-*

-*Entry:

-*       const wchar_t * wcs - string whose length is to be computed

-*

-*Exit:

-*       length of the string "wcs", exclusive of the final null wchar_t

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-size_t __cdecl wcslen(

-        const wchar_t * wcs

-        ) {

-        const wchar_t *eos = wcs;

-

-        while (*eos++) ;

-

-        return( (size_t)(eos - wcs - 1) );

-}

-

-/***

-*strstr.c - search for one string inside another

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines strstr() - search for one string inside another

-*

-*******************************************************************************/

-

-/***

-*char *strstr(string1, string2) - search for string2 in string1

-*

-*Purpose:

-*       finds the first occurrence of string2 in string1

-*

-*Entry:

-*       char *string1 - string to search in

-*       char *string2 - string to search for

-*

-*Exit:

-*       returns a pointer to the first occurrence of string2 in

-*       string1, or NULL if string2 does not occur in string1

-*

-*Uses:

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-_CONST_RETURN char * __cdecl strstr(

-        const char * str1,

-        const char * str2

-        ) {

-        char *cp = (char *) str1;

-        char *s1, *s2;

-

-        if (!*str2)

-            return((char *)str1);

-

-        while (*cp)

-        {

-                s1 = cp;

-                s2 = (char *) str2;

-

-                while (*s1 && *s2 && !(*s1-*s2))

-                        s1++, s2++;

-

-                if (!*s2)

-                        return(cp);

-

-                cp++;

-        }

-

-        return(NULL);

-

-}

-

-/***

-*strcmp.c - routine to compare two strings (for equal, less, or greater)

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       Compares two string, determining their lexical order.

-*

-*******************************************************************************/

-

-#ifdef _MSC_VER

-#pragma function(strcmp)

-#endif  /* _MSC_VER */

-

-/***

-*strcmp - compare two strings, returning less than, equal to, or greater than

-*

-*Purpose:

-*       STRCMP compares two strings and returns an integer

-*       to indicate whether the first is less than the second, the two are

-*       equal, or whether the first is greater than the second.

-*

-*       Comparison is done byte by byte on an UNSIGNED basis, which is to

-*       say that Null (0) is less than any other character (1-255).

-*

-*Entry:

-*       const char * src - string for left-hand side of comparison

-*       const char * dst - string for right-hand side of comparison

-*

-*Exit:

-*       returns -1 if src <  dst

-*       returns  0 if src == dst

-*       returns +1 if src >  dst

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-int __cdecl strcmp(

-        const char * src,

-        const char * dst

-        ) {

-        int ret = 0 ;

-

-        while (! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)

-                ++src, ++dst;

-

-        if (ret < 0)

-                ret = -1 ;

-        else if (ret > 0)

-                ret = 1 ;

-

-        return( ret );

-}

-

-#ifndef _MBSCAT

-#ifdef _MSC_VER

-#pragma function(strcpy)

-#endif  /* _MSC_VER */

-#endif  /* _MBSCAT */

-

-/***

-*char *strcpy(dst, src) - copy one string over another

-*

-*Purpose:

-*       Copies the string src into the spot specified by

-*       dest; assumes enough room.

-*

-*Entry:

-*       char * dst - string over which "src" is to be copied

-*       const char * src - string to be copied over "dst"

-*

-*Exit:

-*       The address of "dst"

-*

-*Exceptions:

-*******************************************************************************/

-

-char * __cdecl strcpy(char * dst, const char * src) {

-        char * cp = dst;

-

-        while (*cp++ = *src++)

-                ;               /* Copy src over dst */

-

-        return( dst );

-}

-

-errno_t __cdecl strcpy_s(char * dst, size_t num_bytes, const char * src) {

-#pragma warning(push)

-#pragma warning(disable : 4996)

-// 4996: 'function' was declared deprecated

-

-  strcpy(dst, src);

-#pragma warning(pop)

-

-  return 0;

-}

-

-/***

-*strncmp.c - compare first n characters of two strings

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines strncmp() - compare first n characters of two strings

-*       for lexical order.

-*

-*******************************************************************************/

-

-/***

-*int strncmp(first, last, count) - compare first count chars of strings

-*

-*Purpose:

-*       Compares two strings for lexical order.  The comparison stops

-*       after: (1) a difference between the strings is found, (2) the end

-*       of the strings is reached, or (3) count characters have been

-*       compared.

-*

-*Entry:

-*       char *first, *last - strings to compare

-*       unsigned count - maximum number of characters to compare

-*

-*Exit:

-*       returns <0 if first < last

-*       returns  0 if first == last

-*       returns >0 if first > last

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-int __cdecl strncmp(

-        const char * first,

-        const char * last,

-        size_t count

-        ) {

-        if (!count)

-                return(0);

-

-        while (--count && *first && *first == *last)

-        {

-                first++;

-                last++;

-        }

-

-        return( *(unsigned char *)first - *(unsigned char *)last );

-}

-

-/***

-*strchr.c - search a string for a given character

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines strchr() - search a string for a character

-*

-*******************************************************************************/

-

-/***

-*char *strchr(string, c) - search a string for a character

-*

-*Purpose:

-*       Searches a string for a given character, which may be the

-*       null character '\0'.

-*

-*Entry:

-*       char *string - string to search in

-*       char c - character to search for

-*

-*Exit:

-*       returns pointer to the first occurence of c in string

-*       returns NULL if c does not occur in string

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-_CONST_RETURN char * __cdecl strchr(

-        const char * string,

-        int ch

-        ) {

-        while (*string && *string != (char)ch)

-                string++;

-

-        if (*string == (char)ch)

-                return((char *)string);

-        return(NULL);

-}

-

-/***

-*wcsncmp.c - compare first n characters of two wide-character strings

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcsncmp() - compare first n characters of two wchar_t strings

-*       for lexical order.

-*

-*******************************************************************************/

-

-/***

-*int wcsncmp(first, last, count) - compare first count chars of wchar_t strings

-*

-*Purpose:

-*       Compares two strings for lexical order.  The comparison stops

-*       after: (1) a difference between the strings is found, (2) the end

-*       of the strings is reached, or (3) count characters have been

-*       compared (wide-character strings).

-*

-*Entry:

-*       wchar_t *first, *last - strings to compare

-*       size_t count - maximum number of characters to compare

-*

-*Exit:

-*       returns <0 if first < last

-*       returns  0 if first == last

-*       returns >0 if first > last

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-int __cdecl wcsncmp(

-        const wchar_t * first,

-        const wchar_t * last,

-        size_t count

-        ) {

-        if (!count)

-                return(0);

-

-        while (--count && *first && *first == *last)

-        {

-                first++;

-                last++;

-        }

-

-        return((int)(*first - *last));

-}

-

-/***

-*wcsspn.c - find length of initial substring of chars from a control string

-*       (wide-character strings)

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcsspn() - finds the length of the initial substring of

-*       a string consisting entirely of characters from a control string

-*       (wide-character strings).

-*

-*******************************************************************************/

-

-/***

-*int wcsspn(string, control) - find init substring of control chars

-*

-*Purpose:

-*       Finds the index of the first character in string that does belong

-*       to the set of characters specified by control.  This is

-*       equivalent to the length of the initial substring of string that

-*       consists entirely of characters from control.  The L'\0' character

-*       that terminates control is not considered in the matching process

-*       (wide-character strings).

-*

-*Entry:

-*       wchar_t *string - string to search

-*       wchar_t *control - string containing characters not to search for

-*

-*Exit:

-*       returns index of first wchar_t in string not in control

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-size_t __cdecl wcsspn(

-        const wchar_t * string,

-        const wchar_t * control

-        ) {

-        wchar_t *str = (wchar_t *) string;

-        wchar_t *ctl;

-

-        /* 1st char not in control string stops search */

-        while (*str) {

-            for (ctl = (wchar_t *)control; *ctl != *str; ctl++) {

-                if (*ctl == (wchar_t)0) {

-                    /*

-                     * reached end of control string without finding a match

-                     */

-                    return (size_t)(str - string);

-                }

-            }

-            str++;

-        }

-        /*

-         * The whole string consisted of characters from control

-         */

-        return (size_t)(str - string);

-}

-

-/***

-*wcscspn.c - find length of initial substring of wide characters

-*        not in a control string

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcscspn()- finds the length of the initial substring of

-*       a string consisting entirely of characters not in a control string

-*       (wide-character strings).

-*

-*******************************************************************************/

-

-/***

-*size_t wcscspn(string, control) - search for init substring w/o control wchars

-*

-*Purpose:

-*       returns the index of the first character in string that belongs

-*       to the set of characters specified by control.  This is equivalent

-*       to the length of the length of the initial substring of string

-*       composed entirely of characters not in control.  Null chars not

-*       considered (wide-character strings).

-*

-*Entry:

-*       wchar_t *string - string to search

-*       wchar_t *control - set of characters not allowed in init substring

-*

-*Exit:

-*       returns the index of the first wchar_t in string

-*       that is in the set of characters specified by control.

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-size_t __cdecl wcscspn(

-        const wchar_t * string,

-        const wchar_t * control

-        ) {

-        wchar_t *str = (wchar_t *) string;

-        wchar_t *wcset;

-

-        /* 1st char in control string stops search */

-        while (*str) {

-            for (wcset = (wchar_t *)control; *wcset; wcset++) {

-                if (*wcset == *str) {

-                    return (size_t)(str - string);

-                }

-            }

-            str++;

-        }

-        return (size_t)(str - string);

-}

-

-/***

-*wchar_t *wcscpy(dst, src) - copy one wchar_t string over another

-*

-*Purpose:

-*       Copies the wchar_t string src into the spot specified by

-*       dest; assumes enough room.

-*

-*Entry:

-*       wchar_t * dst - wchar_t string over which "src" is to be copied

-*       const wchar_t * src - wchar_t string to be copied over "dst"

-*

-*Exit:

-*       The address of "dst"

-*

-*Exceptions:

-*******************************************************************************/

-

-wchar_t * __cdecl wcscpy(wchar_t * dst, const wchar_t * src)

-{

-        wchar_t * cp = dst;

-

-        while( *cp++ = *src++ )

-                ;               /* Copy src over dst */

-

-        return( dst );

-}

-

-/***

-*strtol, strtoul(nptr,endptr,ibase) - Convert ascii string to long un/signed

-*       int.

-*

-*Purpose:

-*       Convert an ascii string to a long 32-bit value.  The base

-*       used for the caculations is supplied by the caller.  The base

-*       must be in the range 0, 2-36.  If a base of 0 is supplied, the

-*       ascii string must be examined to determine the base of the

-*       number:

-*               (a) First char = '0', second char = 'x' or 'X',

-*                   use base 16.

-*               (b) First char = '0', use base 8

-*               (c) First char in range '1' - '9', use base 10.

-*

-*       If the 'endptr' value is non-NULL, then strtol/strtoul places

-*       a pointer to the terminating character in this value.

-*       See ANSI standard for details

-*

-*Entry:

-*       nptr == NEAR/FAR pointer to the start of string.

-*       endptr == NEAR/FAR pointer to the end of the string.

-*       ibase == integer base to use for the calculations.

-*

-*       string format: [whitespace] [sign] [0] [x] [digits/letters]

-*

-*Exit:

-*       Good return:

-*               result

-*

-*       Overflow return:

-*               strtol -- LONG_MAX or LONG_MIN

-*               strtoul -- ULONG_MAX

-*               strtol/strtoul -- errno == ERANGE

-*

-*       No digits or bad base return:

-*               0

-*               endptr = nptr*

-*

-*Exceptions:

-*       None.

-*******************************************************************************/

-

-/* flag values */

-#define FL_UNSIGNED   1       /* strtoul called */

-#define FL_NEG        2       /* negative sign found */

-#define FL_OVERFLOW   4       /* overflow occured */

-#define FL_READDIGIT  8       /* we've read at least one correct digit */

-

-// __ascii_isdigit returns a non-zero value if c is a decimal digit (0 – 9).

-int __ascii_isdigit(int c)

-{

-  return (c >= '0' && c <= '9');

-}

-

-// __ascii_isalpha returns a nonzero value if c is within

-// the ranges A – Z or a – z.

-int __ascii_isalpha(int c)

-{

-  return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));

-}

-

-// __ascii_toupper converts lowercase character to uppercase.

-int __ascii_toupper(int c)

-{

-  if (c >= 'a' && c <= 'z') return (c - ('a' - 'A'));

-  return c;

-}

-

-int isspace(int c)

-{

-  static unsigned char spaces[256] =

-  {

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  // 0-9

-    1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 10-19

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 20-29

-    0, 0, 1, 0, 0, 0, 0, 0, 0, 0,  // 30-39

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 40-49

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 50-59

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 60-69

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 70-79

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 80-89

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 90-99

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 100-109

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 110-119

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 120-129

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 130-139

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 140-149

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 150-159

-    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 160-169

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 170-179

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 180-189

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 190-199

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 200-209

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 210-219

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 220-229

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 230-239

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 240-249

-    0, 0, 0, 0, 0, 1,              // 250-255

-  };

-

-  return spaces[(unsigned char)c] == 1;

-}

-

-static unsigned long __cdecl strtoxl (

-        const char *nptr,

-        const char **endptr,

-        int ibase,

-        int flags

-        )

-{

-        const char *p;

-        char c;

-        unsigned long number;

-        unsigned digval;

-        unsigned long maxval;

-

-        p = nptr;                       /* p is our scanning pointer */

-        number = 0;                     /* start with zero */

-

-        c = *p++;                       /* read char */

-        while ( isspace((int)(unsigned char)c) )

-                c = *p++;               /* skip whitespace */

-

-        if (c == '-') {

-                flags |= FL_NEG;        /* remember minus sign */

-                c = *p++;

-        }

-        else if (c == '+')

-                c = *p++;               /* skip sign */

-

-        if (ibase < 0 || ibase == 1 || ibase > 36) {

-                /* bad base! */

-                if (endptr)

-                        /* store beginning of string in endptr */

-                        *endptr = nptr;

-                return 0L;              /* return 0 */

-        }

-        else if (ibase == 0) {

-                /* determine base free-lance, based on first two chars of

-                   string */

-                if (c != '0')

-                        ibase = 10;

-                else if (*p == 'x' || *p == 'X')

-                        ibase = 16;

-                else

-                        ibase = 8;

-        }

-

-        if (ibase == 16) {

-                /* we might have 0x in front of number; remove if there */

-                if (c == '0' && (*p == 'x' || *p == 'X')) {

-                        ++p;

-                        c = *p++;       /* advance past prefix */

-                }

-        }

-

-        /* if our number exceeds this, we will overflow on multiply */

-        maxval = ULONG_MAX / ibase;

-

-

-        for (;;) {      /* exit in middle of loop */

-                /* convert c to value */

-                if ( __ascii_isdigit((int)(unsigned char)c) )

-                        digval = c - '0';

-                else if ( __ascii_isalpha((int)(unsigned char)c) )

-                        digval = __ascii_toupper(c) - 'A' + 10;

-                else

-                        break;

-                if (digval >= (unsigned)ibase)

-                        break;          /* exit loop if bad digit found */

-

-                /* record the fact we have read one digit */

-                flags |= FL_READDIGIT;

-

-                /* we now need to compute number = number * base + digval,

-                   but we need to know if overflow occured.  This requires

-                   a tricky pre-check. */

-

-                if (number < maxval || (number == maxval &&

-                (unsigned long)digval <= ULONG_MAX % ibase)) {

-                        /* we won't overflow, go ahead and multiply */

-                        number = number * ibase + digval;

-                }

-                else {

-                        /* we would have overflowed -- set the overflow flag */

-                        flags |= FL_OVERFLOW;

-                }

-

-                c = *p++;               /* read next digit */

-        }

-

-        --p;                            /* point to place that stopped scan */

-

-        if (!(flags & FL_READDIGIT)) {

-                /* no number there; return 0 and point to beginning of

-                   string */

-                if (endptr)

-                        /* store beginning of string in endptr later on */

-                        p = nptr;

-                number = 0L;            /* return 0 */

-        }

-        else if ( (flags & FL_OVERFLOW) ||

-                  ( !(flags & FL_UNSIGNED) &&

-                    ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||

-                      ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )

-        {

-                /* overflow or signed overflow occurred */

-                // errno = ERANGE;

-                if ( flags & FL_UNSIGNED )

-                        number = ULONG_MAX;

-                else if ( flags & FL_NEG )

-                        number = (unsigned long)(-LONG_MIN);

-                else

-                        number = LONG_MAX;

-        }

-

-        if (endptr != NULL)

-                /* store pointer to char that stopped the scan */

-                *endptr = p;

-

-        if (flags & FL_NEG)

-                /* negate result if there was a neg sign */

-                number = (unsigned long)(-(long)number);

-

-        return number;                  /* done. */

-}

-

-long __cdecl strtol (

-        const char *nptr,

-        char **endptr,

-        int ibase

-        )

-{

-        return (long) strtoxl(nptr, (const char**)endptr, ibase, 0);

-}

-

-unsigned long __cdecl strtoul (

-        const char *nptr,

-        char **endptr,

-        int ibase

-        )

-{

-        return strtoxl(nptr, (const char**)endptr, ibase, FL_UNSIGNED);

-}

-

+#include <windows.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "libctiny.h"
+
+#ifndef _CONST_RETURN
+#define _CONST_RETURN
+#endif
+
+/***
+*wcsstr.c - search for one wide-character string inside another
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcsstr() - search for one wchar_t string inside another
+*
+*******************************************************************************/
+
+/***
+*wchar_t *wcsstr(string1, string2) - search for string2 in string1
+*       (wide strings)
+*
+*Purpose:
+*       finds the first occurrence of string2 in string1 (wide strings)
+*
+*Entry:
+*       wchar_t *string1 - string to search in
+*       wchar_t *string2 - string to search for
+*
+*Exit:
+*       returns a pointer to the first occurrence of string2 in
+*       string1, or NULL if string2 does not occur in string1
+*
+*Uses:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_CONST_RETURN wchar_t * __cdecl wcsstr(const wchar_t * wcs1,
+                                       const wchar_t * wcs2) {
+        wchar_t *cp = (wchar_t *) wcs1;
+        wchar_t *s1, *s2;
+
+        if (!*wcs2)
+            return (wchar_t *)wcs1;
+
+        while (*cp)
+        {
+                s1 = cp;
+                s2 = (wchar_t *) wcs2;
+
+                while (*s1 && *s2 && !(*s1-*s2))
+                        s1++, s2++;
+
+                if (!*s2)
+                        return(cp);
+
+                cp++;
+        }
+
+        return(NULL);
+}
+
+/***
+*wcsrchr.c - find last occurrence of wchar_t character in wide string
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcsrchr() - find the last occurrence of a given character
+*       in a string (wide-characters).
+*
+*******************************************************************************/
+
+/***
+*wchar_t *wcsrchr(string, ch) - find last occurrence of ch in wide string
+*
+*Purpose:
+*       Finds the last occurrence of ch in string.  The terminating
+*       null character is used as part of the search (wide-characters).
+*
+*Entry:
+*       wchar_t *string - string to search in
+*       wchar_t ch - character to search for
+*
+*Exit:
+*       returns a pointer to the last occurrence of ch in the given
+*       string
+*       returns NULL if ch does not occurr in the string
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_CONST_RETURN wchar_t * __cdecl wcsrchr(const wchar_t * string, wchar_t ch) {
+        wchar_t *start = (wchar_t *)string;
+
+        while (*string++)                       /* find end of string */
+                ;
+                                                /* search towards front */
+        while (--string != start && *string != (wchar_t)ch)
+                ;
+
+        if (*string == (wchar_t)ch)             /* wchar_t found ? */
+                return( (wchar_t *)string );
+
+        return(NULL);
+}
+
+/***
+*wcschr.c - search a wchar_t string for a given wchar_t character
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcschr() - search a wchar_t string for a wchar_t character
+*
+*******************************************************************************/
+
+/***
+*wchar_t *wcschr(string, c) - search a string for a wchar_t character
+*
+*Purpose:
+*       Searches a wchar_t string for a given wchar_t character,
+*       which may be the null character L'\0'.
+*
+*Entry:
+*       wchar_t *string - wchar_t string to search in
+*       wchar_t c - wchar_t character to search for
+*
+*Exit:
+*       returns pointer to the first occurence of c in string
+*       returns NULL if c does not occur in string
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_CONST_RETURN wchar_t * __cdecl wcschr(const wchar_t * string, wchar_t ch) {
+        while (*string && *string != (wchar_t)ch)
+                string++;
+
+        if (*string == (wchar_t)ch)
+                return((wchar_t *)string);
+        return(NULL);
+}
+
+/***
+*xtoa.c - convert integers/longs to ASCII string
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       The module has code to convert integers/longs to ASCII strings.  See
+*
+*******************************************************************************/
+
+/***
+*char *_itoa, *_ltoa, *_ultoa(val, buf, radix) - convert binary int to ASCII
+*       string
+*
+*Purpose:
+*       Converts an int to a character string.
+*
+*Entry:
+*       val - number to be converted (int, long or unsigned long)
+*       int radix - base to convert into
+*       char *buf - ptr to buffer to place result
+*
+*Exit:
+*       fills in space pointed to by buf with string result
+*       returns a pointer to this buffer
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+/* helper routine that does the main job. */
+
+static void __cdecl xtoa(unsigned long val, char *buf, unsigned radix, int is_neg) {
+        char *p;                /* pointer to traverse string */
+        char *firstdig;         /* pointer to first digit */
+        char temp;              /* temp char */
+        unsigned digval;        /* value of digit */
+
+        p = buf;
+
+        if (is_neg) {
+            /* negative, so output '-' and negate */
+            *p++ = '-';
+            val = (unsigned long)(-(long)val);
+        }
+
+        firstdig = p;           /* save pointer to first digit */
+
+        do {
+            digval = (unsigned) (val % radix);
+            val /= radix;       /* get next digit */
+
+            /* convert to ascii and store */
+            if (digval > 9)
+                *p++ = (char) (digval - 10 + 'a');  /* a letter */
+            else
+                *p++ = (char) (digval + '0');       /* a digit */
+        } while (val > 0);
+
+        /* We now have the digit of the number in the buffer, but in reverse
+           order.  Thus we reverse them now. */
+
+        *p-- = '\0';            /* terminate string; p points to last digit */
+
+        do {
+            temp = *p;
+            *p = *firstdig;
+            *firstdig = temp;   /* swap *p and *firstdig */
+            --p;
+            ++firstdig;         /* advance to next two digits */
+        } while (firstdig < p); /* repeat until halfway */
+}
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+   and return pointer to buffer. */
+
+ char * __cdecl _itoa(int val, char *buf, int radix) {
+    if (radix == 10 && val < 0)
+        xtoa((unsigned long)val, buf, radix, 1);
+    else
+        xtoa((unsigned long)(unsigned int)val, buf, radix, 0);
+    return buf;
+}
+
+/***
+*strlen.c - contains strlen() routine
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       strlen returns the length of a null-terminated string,
+*       not including the null byte itself.
+*
+*******************************************************************************/
+
+#ifdef _MSC_VER
+#pragma function(strlen)
+#endif  /* _MSC_VER */
+
+/***
+*strlen - return the length of a null-terminated string
+*
+*Purpose:
+*       Finds the length in bytes of the given string, not including
+*       the final null character.
+*
+*Entry:
+*       const char * str - string whose length is to be computed
+*
+*Exit:
+*       length of the string "str", exclusive of the final null byte
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl strlen(const char * str) {
+        const char *eos = str;
+
+        while (*eos++) ;
+
+        return( (int)(eos - str - 1) );
+}
+
+size_t __cdecl strnlen(const char *str, size_t maxsize) {
+  return strlen(str);
+}
+
+/***
+*wcsncpy.c - copy at most n characters of wide-character string
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcsncpy() - copy at most n characters of wchar_t string
+*
+*******************************************************************************/
+
+/***
+*wchar_t *wcsncpy(dest, source, count) - copy at most n wide characters
+*
+*Purpose:
+*       Copies count characters from the source string to the
+*       destination.  If count is less than the length of source,
+*       NO NULL CHARACTER is put onto the end of the copied string.
+*       If count is greater than the length of sources, dest is padded
+*       with null characters to length count (wide-characters).
+*
+*
+*Entry:
+*       wchar_t *dest - pointer to destination
+*       wchar_t *source - source string for copy
+*       size_t count - max number of characters to copy
+*
+*Exit:
+*       returns dest
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+wchar_t * __cdecl wcsncpy(wchar_t * dest, const wchar_t * source, size_t count) {
+        wchar_t *start = dest;
+
+        while (count && (*dest++ = *source++))    /* copy string */
+                count--;
+
+        if (count)                              /* pad out with zeroes */
+                while (--count)
+                        *dest++ = L'\0';
+
+        return(start);
+}
+
+/***
+*wcscmp.c - routine to compare two wchar_t strings (for equal, less, or greater)
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       Compares two wide-character strings, determining their lexical order.
+*
+*******************************************************************************/
+
+/***
+*wcscmp - compare two wchar_t strings,
+*        returning less than, equal to, or greater than
+*
+*Purpose:
+*       wcscmp compares two wide-character strings and returns an integer
+*       to indicate whether the first is less than the second, the two are
+*       equal, or whether the first is greater than the second.
+*
+*       Comparison is done wchar_t by wchar_t on an UNSIGNED basis, which is to
+*       say that Null wchar_t(0) is less than any other character.
+*
+*Entry:
+*       const wchar_t * src - string for left-hand side of comparison
+*       const wchar_t * dst - string for right-hand side of comparison
+*
+*Exit:
+*       returns -1 if src <  dst
+*       returns  0 if src == dst
+*       returns +1 if src >  dst
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl wcscmp(const wchar_t * src, const wchar_t * dst) {
+        int ret = 0 ;
+
+        while (! (ret = (int)(*src - *dst)) && *dst)
+                ++src, ++dst;
+
+        if (ret < 0)
+                ret = -1 ;
+        else if (ret > 0)
+                ret = 1 ;
+
+        return( ret );
+}
+
+/***
+*wcslen.c - contains wcslen() routine
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       wcslen returns the length of a null-terminated wide-character string,
+*       not including the null wchar_t itself.
+*
+*******************************************************************************/
+
+/***
+*wcslen - return the length of a null-terminated wide-character string
+*
+*Purpose:
+*       Finds the length in wchar_t's of the given string, not including
+*       the final null wchar_t (wide-characters).
+*
+*Entry:
+*       const wchar_t * wcs - string whose length is to be computed
+*
+*Exit:
+*       length of the string "wcs", exclusive of the final null wchar_t
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl wcslen(
+        const wchar_t * wcs
+        ) {
+        const wchar_t *eos = wcs;
+
+        while (*eos++) ;
+
+        return( (size_t)(eos - wcs - 1) );
+}
+
+/***
+*strstr.c - search for one string inside another
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines strstr() - search for one string inside another
+*
+*******************************************************************************/
+
+/***
+*char *strstr(string1, string2) - search for string2 in string1
+*
+*Purpose:
+*       finds the first occurrence of string2 in string1
+*
+*Entry:
+*       char *string1 - string to search in
+*       char *string2 - string to search for
+*
+*Exit:
+*       returns a pointer to the first occurrence of string2 in
+*       string1, or NULL if string2 does not occur in string1
+*
+*Uses:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_CONST_RETURN char * __cdecl strstr(
+        const char * str1,
+        const char * str2
+        ) {
+        char *cp = (char *) str1;
+        char *s1, *s2;
+
+        if (!*str2)
+            return((char *)str1);
+
+        while (*cp)
+        {
+                s1 = cp;
+                s2 = (char *) str2;
+
+                while (*s1 && *s2 && !(*s1-*s2))
+                        s1++, s2++;
+
+                if (!*s2)
+                        return(cp);
+
+                cp++;
+        }
+
+        return(NULL);
+
+}
+
+/***
+*strcmp.c - routine to compare two strings (for equal, less, or greater)
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       Compares two string, determining their lexical order.
+*
+*******************************************************************************/
+
+#ifdef _MSC_VER
+#pragma function(strcmp)
+#endif  /* _MSC_VER */
+
+/***
+*strcmp - compare two strings, returning less than, equal to, or greater than
+*
+*Purpose:
+*       STRCMP compares two strings and returns an integer
+*       to indicate whether the first is less than the second, the two are
+*       equal, or whether the first is greater than the second.
+*
+*       Comparison is done byte by byte on an UNSIGNED basis, which is to
+*       say that Null (0) is less than any other character (1-255).
+*
+*Entry:
+*       const char * src - string for left-hand side of comparison
+*       const char * dst - string for right-hand side of comparison
+*
+*Exit:
+*       returns -1 if src <  dst
+*       returns  0 if src == dst
+*       returns +1 if src >  dst
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl strcmp(
+        const char * src,
+        const char * dst
+        ) {
+        int ret = 0 ;
+
+        while (! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
+                ++src, ++dst;
+
+        if (ret < 0)
+                ret = -1 ;
+        else if (ret > 0)
+                ret = 1 ;
+
+        return( ret );
+}
+
+#ifndef _MBSCAT
+#ifdef _MSC_VER
+#pragma function(strcpy)
+#endif  /* _MSC_VER */
+#endif  /* _MBSCAT */
+
+/***
+*char *strcpy(dst, src) - copy one string over another
+*
+*Purpose:
+*       Copies the string src into the spot specified by
+*       dest; assumes enough room.
+*
+*Entry:
+*       char * dst - string over which "src" is to be copied
+*       const char * src - string to be copied over "dst"
+*
+*Exit:
+*       The address of "dst"
+*
+*Exceptions:
+*******************************************************************************/
+
+char * __cdecl strcpy(char * dst, const char * src) {
+        char * cp = dst;
+
+        while (*cp++ = *src++)
+                ;               /* Copy src over dst */
+
+        return( dst );
+}
+
+errno_t __cdecl strcpy_s(char * dst, size_t num_bytes, const char * src) {
+#pragma warning(push)
+#pragma warning(disable : 4996)
+// 4996: 'function' was declared deprecated
+
+  strcpy(dst, src);
+#pragma warning(pop)
+
+  return 0;
+}
+
+/***
+*strncmp.c - compare first n characters of two strings
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines strncmp() - compare first n characters of two strings
+*       for lexical order.
+*
+*******************************************************************************/
+
+/***
+*int strncmp(first, last, count) - compare first count chars of strings
+*
+*Purpose:
+*       Compares two strings for lexical order.  The comparison stops
+*       after: (1) a difference between the strings is found, (2) the end
+*       of the strings is reached, or (3) count characters have been
+*       compared.
+*
+*Entry:
+*       char *first, *last - strings to compare
+*       unsigned count - maximum number of characters to compare
+*
+*Exit:
+*       returns <0 if first < last
+*       returns  0 if first == last
+*       returns >0 if first > last
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl strncmp(
+        const char * first,
+        const char * last,
+        size_t count
+        ) {
+        if (!count)
+                return(0);
+
+        while (--count && *first && *first == *last)
+        {
+                first++;
+                last++;
+        }
+
+        return( *(unsigned char *)first - *(unsigned char *)last );
+}
+
+/***
+*strchr.c - search a string for a given character
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines strchr() - search a string for a character
+*
+*******************************************************************************/
+
+/***
+*char *strchr(string, c) - search a string for a character
+*
+*Purpose:
+*       Searches a string for a given character, which may be the
+*       null character '\0'.
+*
+*Entry:
+*       char *string - string to search in
+*       char c - character to search for
+*
+*Exit:
+*       returns pointer to the first occurence of c in string
+*       returns NULL if c does not occur in string
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_CONST_RETURN char * __cdecl strchr(
+        const char * string,
+        int ch
+        ) {
+        while (*string && *string != (char)ch)
+                string++;
+
+        if (*string == (char)ch)
+                return((char *)string);
+        return(NULL);
+}
+
+/***
+*wcsncmp.c - compare first n characters of two wide-character strings
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcsncmp() - compare first n characters of two wchar_t strings
+*       for lexical order.
+*
+*******************************************************************************/
+
+/***
+*int wcsncmp(first, last, count) - compare first count chars of wchar_t strings
+*
+*Purpose:
+*       Compares two strings for lexical order.  The comparison stops
+*       after: (1) a difference between the strings is found, (2) the end
+*       of the strings is reached, or (3) count characters have been
+*       compared (wide-character strings).
+*
+*Entry:
+*       wchar_t *first, *last - strings to compare
+*       size_t count - maximum number of characters to compare
+*
+*Exit:
+*       returns <0 if first < last
+*       returns  0 if first == last
+*       returns >0 if first > last
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl wcsncmp(
+        const wchar_t * first,
+        const wchar_t * last,
+        size_t count
+        ) {
+        if (!count)
+                return(0);
+
+        while (--count && *first && *first == *last)
+        {
+                first++;
+                last++;
+        }
+
+        return((int)(*first - *last));
+}
+
+/***
+*wcsspn.c - find length of initial substring of chars from a control string
+*       (wide-character strings)
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcsspn() - finds the length of the initial substring of
+*       a string consisting entirely of characters from a control string
+*       (wide-character strings).
+*
+*******************************************************************************/
+
+/***
+*int wcsspn(string, control) - find init substring of control chars
+*
+*Purpose:
+*       Finds the index of the first character in string that does belong
+*       to the set of characters specified by control.  This is
+*       equivalent to the length of the initial substring of string that
+*       consists entirely of characters from control.  The L'\0' character
+*       that terminates control is not considered in the matching process
+*       (wide-character strings).
+*
+*Entry:
+*       wchar_t *string - string to search
+*       wchar_t *control - string containing characters not to search for
+*
+*Exit:
+*       returns index of first wchar_t in string not in control
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl wcsspn(
+        const wchar_t * string,
+        const wchar_t * control
+        ) {
+        wchar_t *str = (wchar_t *) string;
+        wchar_t *ctl;
+
+        /* 1st char not in control string stops search */
+        while (*str) {
+            for (ctl = (wchar_t *)control; *ctl != *str; ctl++) {
+                if (*ctl == (wchar_t)0) {
+                    /*
+                     * reached end of control string without finding a match
+                     */
+                    return (size_t)(str - string);
+                }
+            }
+            str++;
+        }
+        /*
+         * The whole string consisted of characters from control
+         */
+        return (size_t)(str - string);
+}
+
+/***
+*wcscspn.c - find length of initial substring of wide characters
+*        not in a control string
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcscspn()- finds the length of the initial substring of
+*       a string consisting entirely of characters not in a control string
+*       (wide-character strings).
+*
+*******************************************************************************/
+
+/***
+*size_t wcscspn(string, control) - search for init substring w/o control wchars
+*
+*Purpose:
+*       returns the index of the first character in string that belongs
+*       to the set of characters specified by control.  This is equivalent
+*       to the length of the length of the initial substring of string
+*       composed entirely of characters not in control.  Null chars not
+*       considered (wide-character strings).
+*
+*Entry:
+*       wchar_t *string - string to search
+*       wchar_t *control - set of characters not allowed in init substring
+*
+*Exit:
+*       returns the index of the first wchar_t in string
+*       that is in the set of characters specified by control.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl wcscspn(
+        const wchar_t * string,
+        const wchar_t * control
+        ) {
+        wchar_t *str = (wchar_t *) string;
+        wchar_t *wcset;
+
+        /* 1st char in control string stops search */
+        while (*str) {
+            for (wcset = (wchar_t *)control; *wcset; wcset++) {
+                if (*wcset == *str) {
+                    return (size_t)(str - string);
+                }
+            }
+            str++;
+        }
+        return (size_t)(str - string);
+}
+
+/***
+*wchar_t *wcscpy(dst, src) - copy one wchar_t string over another
+*
+*Purpose:
+*       Copies the wchar_t string src into the spot specified by
+*       dest; assumes enough room.
+*
+*Entry:
+*       wchar_t * dst - wchar_t string over which "src" is to be copied
+*       const wchar_t * src - wchar_t string to be copied over "dst"
+*
+*Exit:
+*       The address of "dst"
+*
+*Exceptions:
+*******************************************************************************/
+
+wchar_t * __cdecl wcscpy(wchar_t * dst, const wchar_t * src)
+{
+        wchar_t * cp = dst;
+
+        while( *cp++ = *src++ )
+                ;               /* Copy src over dst */
+
+        return( dst );
+}
+
+/***
+*strtol, strtoul(nptr,endptr,ibase) - Convert ascii string to long un/signed
+*       int.
+*
+*Purpose:
+*       Convert an ascii string to a long 32-bit value.  The base
+*       used for the caculations is supplied by the caller.  The base
+*       must be in the range 0, 2-36.  If a base of 0 is supplied, the
+*       ascii string must be examined to determine the base of the
+*       number:
+*               (a) First char = '0', second char = 'x' or 'X',
+*                   use base 16.
+*               (b) First char = '0', use base 8
+*               (c) First char in range '1' - '9', use base 10.
+*
+*       If the 'endptr' value is non-NULL, then strtol/strtoul places
+*       a pointer to the terminating character in this value.
+*       See ANSI standard for details
+*
+*Entry:
+*       nptr == NEAR/FAR pointer to the start of string.
+*       endptr == NEAR/FAR pointer to the end of the string.
+*       ibase == integer base to use for the calculations.
+*
+*       string format: [whitespace] [sign] [0] [x] [digits/letters]
+*
+*Exit:
+*       Good return:
+*               result
+*
+*       Overflow return:
+*               strtol -- LONG_MAX or LONG_MIN
+*               strtoul -- ULONG_MAX
+*               strtol/strtoul -- errno == ERANGE
+*
+*       No digits or bad base return:
+*               0
+*               endptr = nptr*
+*
+*Exceptions:
+*       None.
+*******************************************************************************/
+
+/* flag values */
+#define FL_UNSIGNED   1       /* strtoul called */
+#define FL_NEG        2       /* negative sign found */
+#define FL_OVERFLOW   4       /* overflow occured */
+#define FL_READDIGIT  8       /* we've read at least one correct digit */
+
+// __ascii_isdigit returns a non-zero value if c is a decimal digit (0 – 9).
+int __ascii_isdigit(int c)
+{
+  return (c >= '0' && c <= '9');
+}
+
+// __ascii_isalpha returns a nonzero value if c is within
+// the ranges A – Z or a – z.
+int __ascii_isalpha(int c)
+{
+  return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
+}
+
+// __ascii_toupper converts lowercase character to uppercase.
+int __ascii_toupper(int c)
+{
+  if (c >= 'a' && c <= 'z') return (c - ('a' - 'A'));
+  return c;
+}
+
+int isspace(int c)
+{
+  static unsigned char spaces[256] =
+  {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  // 0-9
+    1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 10-19
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 20-29
+    0, 0, 1, 0, 0, 0, 0, 0, 0, 0,  // 30-39
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 40-49
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 50-59
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 60-69
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 70-79
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 80-89
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 90-99
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 100-109
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 110-119
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 120-129
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 130-139
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 140-149
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 150-159
+    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 160-169
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 170-179
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 180-189
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 190-199
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 200-209
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 210-219
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 220-229
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 230-239
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 240-249
+    0, 0, 0, 0, 0, 1,              // 250-255
+  };
+
+  return spaces[(unsigned char)c] == 1;
+}
+
+static unsigned long __cdecl strtoxl (
+        const char *nptr,
+        const char **endptr,
+        int ibase,
+        int flags
+        )
+{
+        const char *p;
+        char c;
+        unsigned long number;
+        unsigned digval;
+        unsigned long maxval;
+
+        p = nptr;                       /* p is our scanning pointer */
+        number = 0;                     /* start with zero */
+
+        c = *p++;                       /* read char */
+        while ( isspace((int)(unsigned char)c) )
+                c = *p++;               /* skip whitespace */
+
+        if (c == '-') {
+                flags |= FL_NEG;        /* remember minus sign */
+                c = *p++;
+        }
+        else if (c == '+')
+                c = *p++;               /* skip sign */
+
+        if (ibase < 0 || ibase == 1 || ibase > 36) {
+                /* bad base! */
+                if (endptr)
+                        /* store beginning of string in endptr */
+                        *endptr = nptr;
+                return 0L;              /* return 0 */
+        }
+        else if (ibase == 0) {
+                /* determine base free-lance, based on first two chars of
+                   string */
+                if (c != '0')
+                        ibase = 10;
+                else if (*p == 'x' || *p == 'X')
+                        ibase = 16;
+                else
+                        ibase = 8;
+        }
+
+        if (ibase == 16) {
+                /* we might have 0x in front of number; remove if there */
+                if (c == '0' && (*p == 'x' || *p == 'X')) {
+                        ++p;
+                        c = *p++;       /* advance past prefix */
+                }
+        }
+
+        /* if our number exceeds this, we will overflow on multiply */
+        maxval = ULONG_MAX / ibase;
+
+
+        for (;;) {      /* exit in middle of loop */
+                /* convert c to value */
+                if ( __ascii_isdigit((int)(unsigned char)c) )
+                        digval = c - '0';
+                else if ( __ascii_isalpha((int)(unsigned char)c) )
+                        digval = __ascii_toupper(c) - 'A' + 10;
+                else
+                        break;
+                if (digval >= (unsigned)ibase)
+                        break;          /* exit loop if bad digit found */
+
+                /* record the fact we have read one digit */
+                flags |= FL_READDIGIT;
+
+                /* we now need to compute number = number * base + digval,
+                   but we need to know if overflow occured.  This requires
+                   a tricky pre-check. */
+
+                if (number < maxval || (number == maxval &&
+                (unsigned long)digval <= ULONG_MAX % ibase)) {
+                        /* we won't overflow, go ahead and multiply */
+                        number = number * ibase + digval;
+                }
+                else {
+                        /* we would have overflowed -- set the overflow flag */
+                        flags |= FL_OVERFLOW;
+                }
+
+                c = *p++;               /* read next digit */
+        }
+
+        --p;                            /* point to place that stopped scan */
+
+        if (!(flags & FL_READDIGIT)) {
+                /* no number there; return 0 and point to beginning of
+                   string */
+                if (endptr)
+                        /* store beginning of string in endptr later on */
+                        p = nptr;
+                number = 0L;            /* return 0 */
+        }
+        else if ( (flags & FL_OVERFLOW) ||
+                  ( !(flags & FL_UNSIGNED) &&
+                    ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||
+                      ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )
+        {
+                /* overflow or signed overflow occurred */
+                // errno = ERANGE;
+                if ( flags & FL_UNSIGNED )
+                        number = ULONG_MAX;
+                else if ( flags & FL_NEG )
+                        number = (unsigned long)(-LONG_MIN);
+                else
+                        number = LONG_MAX;
+        }
+
+        if (endptr != NULL)
+                /* store pointer to char that stopped the scan */
+                *endptr = p;
+
+        if (flags & FL_NEG)
+                /* negate result if there was a neg sign */
+                number = (unsigned long)(-(long)number);
+
+        return number;                  /* done. */
+}
+
+long __cdecl strtol (
+        const char *nptr,
+        char **endptr,
+        int ibase
+        )
+{
+        return (long) strtoxl(nptr, (const char**)endptr, ibase, 0);
+}
+
+unsigned long __cdecl strtoul (
+        const char *nptr,
+        char **endptr,
+        int ibase
+        )
+{
+        return strtoxl(nptr, (const char**)endptr, ibase, FL_UNSIGNED);
+}
+
diff --git a/third_party/minicrt/string.cc b/third_party/minicrt/string.cc
index 6e08d58..9c2ad0d 100644
--- a/third_party/minicrt/string.cc
+++ b/third_party/minicrt/string.cc
@@ -1,1080 +1,1080 @@
-#include <windows.h>

-#include <limits.h>

-#include <stdlib.h>

-

-#include "libctiny.h"

-

-#ifndef _CONST_RETURN

-#define _CONST_RETURN

-#endif

-

-/***

-*wcsstr.c - search for one wide-character string inside another

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcsstr() - search for one wchar_t string inside another

-*

-*******************************************************************************/

-

-/***

-*wchar_t *wcsstr(string1, string2) - search for string2 in string1

-*       (wide strings)

-*

-*Purpose:

-*       finds the first occurrence of string2 in string1 (wide strings)

-*

-*Entry:

-*       wchar_t *string1 - string to search in

-*       wchar_t *string2 - string to search for

-*

-*Exit:

-*       returns a pointer to the first occurrence of string2 in

-*       string1, or NULL if string2 does not occur in string1

-*

-*Uses:

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-_CONST_RETURN wchar_t * __cdecl wcsstr(const wchar_t * wcs1,

-                                       const wchar_t * wcs2) {

-        wchar_t *cp = (wchar_t *) wcs1;

-        wchar_t *s1, *s2;

-

-        if (!*wcs2)

-            return (wchar_t *)wcs1;

-

-        while (*cp)

-        {

-                s1 = cp;

-                s2 = (wchar_t *) wcs2;

-

-                while (*s1 && *s2 && !(*s1-*s2))

-                        s1++, s2++;

-

-                if (!*s2)

-                        return(cp);

-

-                cp++;

-        }

-

-        return(NULL);

-}

-

-/***

-*wcsrchr.c - find last occurrence of wchar_t character in wide string

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcsrchr() - find the last occurrence of a given character

-*       in a string (wide-characters).

-*

-*******************************************************************************/

-

-/***

-*wchar_t *wcsrchr(string, ch) - find last occurrence of ch in wide string

-*

-*Purpose:

-*       Finds the last occurrence of ch in string.  The terminating

-*       null character is used as part of the search (wide-characters).

-*

-*Entry:

-*       wchar_t *string - string to search in

-*       wchar_t ch - character to search for

-*

-*Exit:

-*       returns a pointer to the last occurrence of ch in the given

-*       string

-*       returns NULL if ch does not occurr in the string

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-_CONST_RETURN wchar_t * __cdecl wcsrchr(const wchar_t * string, wchar_t ch) {

-        wchar_t *start = (wchar_t *)string;

-

-        while (*string++)                       /* find end of string */

-                ;

-                                                /* search towards front */

-        while (--string != start && *string != (wchar_t)ch)

-                ;

-

-        if (*string == (wchar_t)ch)             /* wchar_t found ? */

-                return( (wchar_t *)string );

-

-        return(NULL);

-}

-

-/***

-*wcschr.c - search a wchar_t string for a given wchar_t character

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcschr() - search a wchar_t string for a wchar_t character

-*

-*******************************************************************************/

-

-/***

-*wchar_t *wcschr(string, c) - search a string for a wchar_t character

-*

-*Purpose:

-*       Searches a wchar_t string for a given wchar_t character,

-*       which may be the null character L'\0'.

-*

-*Entry:

-*       wchar_t *string - wchar_t string to search in

-*       wchar_t c - wchar_t character to search for

-*

-*Exit:

-*       returns pointer to the first occurence of c in string

-*       returns NULL if c does not occur in string

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-_CONST_RETURN wchar_t * __cdecl wcschr(const wchar_t * string, wchar_t ch) {

-        while (*string && *string != (wchar_t)ch)

-                string++;

-

-        if (*string == (wchar_t)ch)

-                return((wchar_t *)string);

-        return(NULL);

-}

-

-/***

-*xtoa.c - convert integers/longs to ASCII string

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       The module has code to convert integers/longs to ASCII strings.  See

-*

-*******************************************************************************/

-

-/***

-*char *_itoa, *_ltoa, *_ultoa(val, buf, radix) - convert binary int to ASCII

-*       string

-*

-*Purpose:

-*       Converts an int to a character string.

-*

-*Entry:

-*       val - number to be converted (int, long or unsigned long)

-*       int radix - base to convert into

-*       char *buf - ptr to buffer to place result

-*

-*Exit:

-*       fills in space pointed to by buf with string result

-*       returns a pointer to this buffer

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-/* helper routine that does the main job. */

-

-static void __cdecl xtoa(unsigned long val, char *buf, unsigned radix, int is_neg) {

-        char *p;                /* pointer to traverse string */

-        char *firstdig;         /* pointer to first digit */

-        char temp;              /* temp char */

-        unsigned digval;        /* value of digit */

-

-        p = buf;

-

-        if (is_neg) {

-            /* negative, so output '-' and negate */

-            *p++ = '-';

-            val = (unsigned long)(-(long)val);

-        }

-

-        firstdig = p;           /* save pointer to first digit */

-

-        do {

-            digval = (unsigned) (val % radix);

-            val /= radix;       /* get next digit */

-

-            /* convert to ascii and store */

-            if (digval > 9)

-                *p++ = (char) (digval - 10 + 'a');  /* a letter */

-            else

-                *p++ = (char) (digval + '0');       /* a digit */

-        } while (val > 0);

-

-        /* We now have the digit of the number in the buffer, but in reverse

-           order.  Thus we reverse them now. */

-

-        *p-- = '\0';            /* terminate string; p points to last digit */

-

-        do {

-            temp = *p;

-            *p = *firstdig;

-            *firstdig = temp;   /* swap *p and *firstdig */

-            --p;

-            ++firstdig;         /* advance to next two digits */

-        } while (firstdig < p); /* repeat until halfway */

-}

-

-/* Actual functions just call conversion helper with neg flag set correctly,

-   and return pointer to buffer. */

-

-extern "C" char * __cdecl _itoa(int val, char *buf, int radix) {

-    if (radix == 10 && val < 0)

-        xtoa((unsigned long)val, buf, radix, 1);

-    else

-        xtoa((unsigned long)(unsigned int)val, buf, radix, 0);

-    return buf;

-}

-

-/***

-*strlen.c - contains strlen() routine

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       strlen returns the length of a null-terminated string,

-*       not including the null byte itself.

-*

-*******************************************************************************/

-

-#ifdef _MSC_VER

-#pragma function(strlen)

-#endif  /* _MSC_VER */

-

-/***

-*strlen - return the length of a null-terminated string

-*

-*Purpose:

-*       Finds the length in bytes of the given string, not including

-*       the final null character.

-*

-*Entry:

-*       const char * str - string whose length is to be computed

-*

-*Exit:

-*       length of the string "str", exclusive of the final null byte

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-size_t __cdecl strlen(const char * str) {

-        const char *eos = str;

-

-        while (*eos++) ;

-

-        return( (int)(eos - str - 1) );

-}

-

-/***

-*wcsncpy.c - copy at most n characters of wide-character string

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcsncpy() - copy at most n characters of wchar_t string

-*

-*******************************************************************************/

-

-/***

-*wchar_t *wcsncpy(dest, source, count) - copy at most n wide characters

-*

-*Purpose:

-*       Copies count characters from the source string to the

-*       destination.  If count is less than the length of source,

-*       NO NULL CHARACTER is put onto the end of the copied string.

-*       If count is greater than the length of sources, dest is padded

-*       with null characters to length count (wide-characters).

-*

-*

-*Entry:

-*       wchar_t *dest - pointer to destination

-*       wchar_t *source - source string for copy

-*       size_t count - max number of characters to copy

-*

-*Exit:

-*       returns dest

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-wchar_t * __cdecl wcsncpy(wchar_t * dest, const wchar_t * source, size_t count) {

-        wchar_t *start = dest;

-

-        while (count && (*dest++ = *source++))    /* copy string */

-                count--;

-

-        if (count)                              /* pad out with zeroes */

-                while (--count)

-                        *dest++ = L'\0';

-

-        return(start);

-}

-

-/***

-*wcscmp.c - routine to compare two wchar_t strings (for equal, less, or greater)

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       Compares two wide-character strings, determining their lexical order.

-*

-*******************************************************************************/

-

-/***

-*wcscmp - compare two wchar_t strings,

-*        returning less than, equal to, or greater than

-*

-*Purpose:

-*       wcscmp compares two wide-character strings and returns an integer

-*       to indicate whether the first is less than the second, the two are

-*       equal, or whether the first is greater than the second.

-*

-*       Comparison is done wchar_t by wchar_t on an UNSIGNED basis, which is to

-*       say that Null wchar_t(0) is less than any other character.

-*

-*Entry:

-*       const wchar_t * src - string for left-hand side of comparison

-*       const wchar_t * dst - string for right-hand side of comparison

-*

-*Exit:

-*       returns -1 if src <  dst

-*       returns  0 if src == dst

-*       returns +1 if src >  dst

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-int __cdecl wcscmp(const wchar_t * src, const wchar_t * dst) {

-        int ret = 0 ;

-

-        while (! (ret = (int)(*src - *dst)) && *dst)

-                ++src, ++dst;

-

-        if (ret < 0)

-                ret = -1 ;

-        else if (ret > 0)

-                ret = 1 ;

-

-        return( ret );

-}

-

-/***

-*wcslen.c - contains wcslen() routine

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       wcslen returns the length of a null-terminated wide-character string,

-*       not including the null wchar_t itself.

-*

-*******************************************************************************/

-

-/***

-*wcslen - return the length of a null-terminated wide-character string

-*

-*Purpose:

-*       Finds the length in wchar_t's of the given string, not including

-*       the final null wchar_t (wide-characters).

-*

-*Entry:

-*       const wchar_t * wcs - string whose length is to be computed

-*

-*Exit:

-*       length of the string "wcs", exclusive of the final null wchar_t

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-size_t __cdecl wcslen(

-        const wchar_t * wcs

-        ) {

-        const wchar_t *eos = wcs;

-

-        while (*eos++) ;

-

-        return( (size_t)(eos - wcs - 1) );

-}

-

-/***

-*strstr.c - search for one string inside another

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines strstr() - search for one string inside another

-*

-*******************************************************************************/

-

-/***

-*char *strstr(string1, string2) - search for string2 in string1

-*

-*Purpose:

-*       finds the first occurrence of string2 in string1

-*

-*Entry:

-*       char *string1 - string to search in

-*       char *string2 - string to search for

-*

-*Exit:

-*       returns a pointer to the first occurrence of string2 in

-*       string1, or NULL if string2 does not occur in string1

-*

-*Uses:

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-_CONST_RETURN char * __cdecl strstr(

-        const char * str1,

-        const char * str2

-        ) {

-        char *cp = (char *) str1;

-        char *s1, *s2;

-

-        if (!*str2)

-            return((char *)str1);

-

-        while (*cp)

-        {

-                s1 = cp;

-                s2 = (char *) str2;

-

-                while (*s1 && *s2 && !(*s1-*s2))

-                        s1++, s2++;

-

-                if (!*s2)

-                        return(cp);

-

-                cp++;

-        }

-

-        return(NULL);

-

-}

-

-/***

-*strcmp.c - routine to compare two strings (for equal, less, or greater)

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       Compares two string, determining their lexical order.

-*

-*******************************************************************************/

-

-#ifdef _MSC_VER

-#pragma function(strcmp)

-#endif  /* _MSC_VER */

-

-/***

-*strcmp - compare two strings, returning less than, equal to, or greater than

-*

-*Purpose:

-*       STRCMP compares two strings and returns an integer

-*       to indicate whether the first is less than the second, the two are

-*       equal, or whether the first is greater than the second.

-*

-*       Comparison is done byte by byte on an UNSIGNED basis, which is to

-*       say that Null (0) is less than any other character (1-255).

-*

-*Entry:

-*       const char * src - string for left-hand side of comparison

-*       const char * dst - string for right-hand side of comparison

-*

-*Exit:

-*       returns -1 if src <  dst

-*       returns  0 if src == dst

-*       returns +1 if src >  dst

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-int __cdecl strcmp(

-        const char * src,

-        const char * dst

-        ) {

-        int ret = 0 ;

-

-        while (! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)

-                ++src, ++dst;

-

-        if (ret < 0)

-                ret = -1 ;

-        else if (ret > 0)

-                ret = 1 ;

-

-        return( ret );

-}

-

-#ifndef _MBSCAT

-#ifdef _MSC_VER

-#pragma function(strcpy)

-#endif  /* _MSC_VER */

-#endif  /* _MBSCAT */

-

-/***

-*char *strcpy(dst, src) - copy one string over another

-*

-*Purpose:

-*       Copies the string src into the spot specified by

-*       dest; assumes enough room.

-*

-*Entry:

-*       char * dst - string over which "src" is to be copied

-*       const char * src - string to be copied over "dst"

-*

-*Exit:

-*       The address of "dst"

-*

-*Exceptions:

-*******************************************************************************/

-

-char * __cdecl strcpy(char * dst, const char * src) {

-        char * cp = dst;

-

-        while (*cp++ = *src++)

-                ;               /* Copy src over dst */

-

-        return( dst );

-}

-

-/***

-*strncmp.c - compare first n characters of two strings

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines strncmp() - compare first n characters of two strings

-*       for lexical order.

-*

-*******************************************************************************/

-

-/***

-*int strncmp(first, last, count) - compare first count chars of strings

-*

-*Purpose:

-*       Compares two strings for lexical order.  The comparison stops

-*       after: (1) a difference between the strings is found, (2) the end

-*       of the strings is reached, or (3) count characters have been

-*       compared.

-*

-*Entry:

-*       char *first, *last - strings to compare

-*       unsigned count - maximum number of characters to compare

-*

-*Exit:

-*       returns <0 if first < last

-*       returns  0 if first == last

-*       returns >0 if first > last

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-int __cdecl strncmp(

-        const char * first,

-        const char * last,

-        size_t count

-        ) {

-        if (!count)

-                return(0);

-

-        while (--count && *first && *first == *last)

-        {

-                first++;

-                last++;

-        }

-

-        return( *(unsigned char *)first - *(unsigned char *)last );

-}

-

-/***

-*strchr.c - search a string for a given character

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines strchr() - search a string for a character

-*

-*******************************************************************************/

-

-/***

-*char *strchr(string, c) - search a string for a character

-*

-*Purpose:

-*       Searches a string for a given character, which may be the

-*       null character '\0'.

-*

-*Entry:

-*       char *string - string to search in

-*       char c - character to search for

-*

-*Exit:

-*       returns pointer to the first occurence of c in string

-*       returns NULL if c does not occur in string

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-_CONST_RETURN char * __cdecl strchr(

-        const char * string,

-        int ch

-        ) {

-        while (*string && *string != (char)ch)

-                string++;

-

-        if (*string == (char)ch)

-                return((char *)string);

-        return(NULL);

-}

-

-/***

-*wcsncmp.c - compare first n characters of two wide-character strings

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcsncmp() - compare first n characters of two wchar_t strings

-*       for lexical order.

-*

-*******************************************************************************/

-

-/***

-*int wcsncmp(first, last, count) - compare first count chars of wchar_t strings

-*

-*Purpose:

-*       Compares two strings for lexical order.  The comparison stops

-*       after: (1) a difference between the strings is found, (2) the end

-*       of the strings is reached, or (3) count characters have been

-*       compared (wide-character strings).

-*

-*Entry:

-*       wchar_t *first, *last - strings to compare

-*       size_t count - maximum number of characters to compare

-*

-*Exit:

-*       returns <0 if first < last

-*       returns  0 if first == last

-*       returns >0 if first > last

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-int __cdecl wcsncmp(

-        const wchar_t * first,

-        const wchar_t * last,

-        size_t count

-        ) {

-        if (!count)

-                return(0);

-

-        while (--count && *first && *first == *last)

-        {

-                first++;

-                last++;

-        }

-

-        return((int)(*first - *last));

-}

-

-/***

-*wcsspn.c - find length of initial substring of chars from a control string

-*       (wide-character strings)

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcsspn() - finds the length of the initial substring of

-*       a string consisting entirely of characters from a control string

-*       (wide-character strings).

-*

-*******************************************************************************/

-

-/***

-*int wcsspn(string, control) - find init substring of control chars

-*

-*Purpose:

-*       Finds the index of the first character in string that does belong

-*       to the set of characters specified by control.  This is

-*       equivalent to the length of the initial substring of string that

-*       consists entirely of characters from control.  The L'\0' character

-*       that terminates control is not considered in the matching process

-*       (wide-character strings).

-*

-*Entry:

-*       wchar_t *string - string to search

-*       wchar_t *control - string containing characters not to search for

-*

-*Exit:

-*       returns index of first wchar_t in string not in control

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-size_t __cdecl wcsspn(

-        const wchar_t * string,

-        const wchar_t * control

-        ) {

-        wchar_t *str = (wchar_t *) string;

-        wchar_t *ctl;

-

-        /* 1st char not in control string stops search */

-        while (*str) {

-            for (ctl = (wchar_t *)control; *ctl != *str; ctl++) {

-                if (*ctl == (wchar_t)0) {

-                    /*

-                     * reached end of control string without finding a match

-                     */

-                    return (size_t)(str - string);

-                }

-            }

-            str++;

-        }

-        /*

-         * The whole string consisted of characters from control

-         */

-        return (size_t)(str - string);

-}

-

-/***

-*wcscspn.c - find length of initial substring of wide characters

-*        not in a control string

-*

-*       Copyright (c) Microsoft Corporation. All rights reserved.

-*

-*Purpose:

-*       defines wcscspn()- finds the length of the initial substring of

-*       a string consisting entirely of characters not in a control string

-*       (wide-character strings).

-*

-*******************************************************************************/

-

-/***

-*size_t wcscspn(string, control) - search for init substring w/o control wchars

-*

-*Purpose:

-*       returns the index of the first character in string that belongs

-*       to the set of characters specified by control.  This is equivalent

-*       to the length of the length of the initial substring of string

-*       composed entirely of characters not in control.  Null chars not

-*       considered (wide-character strings).

-*

-*Entry:

-*       wchar_t *string - string to search

-*       wchar_t *control - set of characters not allowed in init substring

-*

-*Exit:

-*       returns the index of the first wchar_t in string

-*       that is in the set of characters specified by control.

-*

-*Exceptions:

-*

-*******************************************************************************/

-

-size_t __cdecl wcscspn(

-        const wchar_t * string,

-        const wchar_t * control

-        ) {

-        wchar_t *str = (wchar_t *) string;

-        wchar_t *wcset;

-

-        /* 1st char in control string stops search */

-        while (*str) {

-            for (wcset = (wchar_t *)control; *wcset; wcset++) {

-                if (*wcset == *str) {

-                    return (size_t)(str - string);

-                }

-            }

-            str++;

-        }

-        return (size_t)(str - string);

-}

-

-/***

-*wchar_t *wcscpy(dst, src) - copy one wchar_t string over another

-*

-*Purpose:

-*       Copies the wchar_t string src into the spot specified by

-*       dest; assumes enough room.

-*

-*Entry:

-*       wchar_t * dst - wchar_t string over which "src" is to be copied

-*       const wchar_t * src - wchar_t string to be copied over "dst"

-*

-*Exit:

-*       The address of "dst"

-*

-*Exceptions:

-*******************************************************************************/

-

-wchar_t * __cdecl wcscpy(wchar_t * dst, const wchar_t * src)

-{

-        wchar_t * cp = dst;

-

-        while( *cp++ = *src++ )

-                ;               /* Copy src over dst */

-

-        return( dst );

-}

-

-/***

-*strtol, strtoul(nptr,endptr,ibase) - Convert ascii string to long un/signed

-*       int.

-*

-*Purpose:

-*       Convert an ascii string to a long 32-bit value.  The base

-*       used for the caculations is supplied by the caller.  The base

-*       must be in the range 0, 2-36.  If a base of 0 is supplied, the

-*       ascii string must be examined to determine the base of the

-*       number:

-*               (a) First char = '0', second char = 'x' or 'X',

-*                   use base 16.

-*               (b) First char = '0', use base 8

-*               (c) First char in range '1' - '9', use base 10.

-*

-*       If the 'endptr' value is non-NULL, then strtol/strtoul places

-*       a pointer to the terminating character in this value.

-*       See ANSI standard for details

-*

-*Entry:

-*       nptr == NEAR/FAR pointer to the start of string.

-*       endptr == NEAR/FAR pointer to the end of the string.

-*       ibase == integer base to use for the calculations.

-*

-*       string format: [whitespace] [sign] [0] [x] [digits/letters]

-*

-*Exit:

-*       Good return:

-*               result

-*

-*       Overflow return:

-*               strtol -- LONG_MAX or LONG_MIN

-*               strtoul -- ULONG_MAX

-*               strtol/strtoul -- errno == ERANGE

-*

-*       No digits or bad base return:

-*               0

-*               endptr = nptr*

-*

-*Exceptions:

-*       None.

-*******************************************************************************/

-

-/* flag values */

-#define FL_UNSIGNED   1       /* strtoul called */

-#define FL_NEG        2       /* negative sign found */

-#define FL_OVERFLOW   4       /* overflow occured */

-#define FL_READDIGIT  8       /* we've read at least one correct digit */

-

-// __ascii_isdigit returns a non-zero value if c is a decimal digit (0 – 9).

-int __ascii_isdigit(int c)

-{

-  return (c >= '0' && c <= '9');

-}

-

-// __ascii_isalpha returns a nonzero value if c is within

-// the ranges A – Z or a – z.

-int __ascii_isalpha(int c)

-{

-  return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));

-}

-

-// __ascii_toupper converts lowercase character to uppercase.

-int __ascii_toupper(int c)

-{

-  if (c >= 'a' && c <= 'z') return (c - ('a' - 'A'));

-  return c;

-}

-

-int isspace(int c)

-{

-  static bool spaces[256] =

-  {

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  // 0-9

-    1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 10-19

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 20-29

-    0, 0, 1, 0, 0, 0, 0, 0, 0, 0,  // 30-39

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 40-49

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 50-59

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 60-69

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 70-79

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 80-89

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 90-99

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 100-109

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 110-119

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 120-129

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 130-139

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 140-149

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 150-159

-    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 160-169

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 170-179

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 180-189

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 190-199

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 200-209

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 210-219

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 220-229

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 230-239

-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 240-249

-    0, 0, 0, 0, 0, 1,              // 250-255

-  };

-

-  return spaces[static_cast<unsigned char>(c)] == 1;

-}

-

-static unsigned long __cdecl strtoxl (

-        const char *nptr,

-        const char **endptr,

-        int ibase,

-        int flags

-        )

-{

-        const char *p;

-        char c;

-        unsigned long number;

-        unsigned digval;

-        unsigned long maxval;

-

-        p = nptr;                       /* p is our scanning pointer */

-        number = 0;                     /* start with zero */

-

-        c = *p++;                       /* read char */

-        while ( isspace((int)(unsigned char)c) )

-                c = *p++;               /* skip whitespace */

-

-        if (c == '-') {

-                flags |= FL_NEG;        /* remember minus sign */

-                c = *p++;

-        }

-        else if (c == '+')

-                c = *p++;               /* skip sign */

-

-        if (ibase < 0 || ibase == 1 || ibase > 36) {

-                /* bad base! */

-                if (endptr)

-                        /* store beginning of string in endptr */

-                        *endptr = nptr;

-                return 0L;              /* return 0 */

-        }

-        else if (ibase == 0) {

-                /* determine base free-lance, based on first two chars of

-                   string */

-                if (c != '0')

-                        ibase = 10;

-                else if (*p == 'x' || *p == 'X')

-                        ibase = 16;

-                else

-                        ibase = 8;

-        }

-

-        if (ibase == 16) {

-                /* we might have 0x in front of number; remove if there */

-                if (c == '0' && (*p == 'x' || *p == 'X')) {

-                        ++p;

-                        c = *p++;       /* advance past prefix */

-                }

-        }

-

-        /* if our number exceeds this, we will overflow on multiply */

-        maxval = ULONG_MAX / ibase;

-

-

-        for (;;) {      /* exit in middle of loop */

-                /* convert c to value */

-                if ( __ascii_isdigit((int)(unsigned char)c) )

-                        digval = c - '0';

-                else if ( __ascii_isalpha((int)(unsigned char)c) )

-                        digval = __ascii_toupper(c) - 'A' + 10;

-                else

-                        break;

-                if (digval >= (unsigned)ibase)

-                        break;          /* exit loop if bad digit found */

-

-                /* record the fact we have read one digit */

-                flags |= FL_READDIGIT;

-

-                /* we now need to compute number = number * base + digval,

-                   but we need to know if overflow occured.  This requires

-                   a tricky pre-check. */

-

-                if (number < maxval || (number == maxval &&

-                (unsigned long)digval <= ULONG_MAX % ibase)) {

-                        /* we won't overflow, go ahead and multiply */

-                        number = number * ibase + digval;

-                }

-                else {

-                        /* we would have overflowed -- set the overflow flag */

-                        flags |= FL_OVERFLOW;

-                }

-

-                c = *p++;               /* read next digit */

-        }

-

-        --p;                            /* point to place that stopped scan */

-

-        if (!(flags & FL_READDIGIT)) {

-                /* no number there; return 0 and point to beginning of

-                   string */

-                if (endptr)

-                        /* store beginning of string in endptr later on */

-                        p = nptr;

-                number = 0L;            /* return 0 */

-        }

-        else if ( (flags & FL_OVERFLOW) ||

-                  ( !(flags & FL_UNSIGNED) &&

-                    ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||

-                      ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )

-        {

-                /* overflow or signed overflow occurred */

-                // errno = ERANGE;

-                if ( flags & FL_UNSIGNED )

-                        number = ULONG_MAX;

-                else if ( flags & FL_NEG )

-                        number = (unsigned long)(-LONG_MIN);

-                else

-                        number = LONG_MAX;

-        }

-

-        if (endptr != NULL)

-                /* store pointer to char that stopped the scan */

-                *endptr = p;

-

-        if (flags & FL_NEG)

-                /* negate result if there was a neg sign */

-                number = (unsigned long)(-(long)number);

-

-        return number;                  /* done. */

-}

-

-long __cdecl strtol (

-        const char *nptr,

-        char **endptr,

-        int ibase

-        )

-{

-        return (long) strtoxl(nptr, (const char**)endptr, ibase, 0);

-}

-

-unsigned long __cdecl strtoul (

-        const char *nptr,

-        char **endptr,

-        int ibase

-        )

-{

-        return strtoxl(nptr, (const char**)endptr, ibase, FL_UNSIGNED);

-}

-

+#include <windows.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "libctiny.h"
+
+#ifndef _CONST_RETURN
+#define _CONST_RETURN
+#endif
+
+/***
+*wcsstr.c - search for one wide-character string inside another
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcsstr() - search for one wchar_t string inside another
+*
+*******************************************************************************/
+
+/***
+*wchar_t *wcsstr(string1, string2) - search for string2 in string1
+*       (wide strings)
+*
+*Purpose:
+*       finds the first occurrence of string2 in string1 (wide strings)
+*
+*Entry:
+*       wchar_t *string1 - string to search in
+*       wchar_t *string2 - string to search for
+*
+*Exit:
+*       returns a pointer to the first occurrence of string2 in
+*       string1, or NULL if string2 does not occur in string1
+*
+*Uses:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_CONST_RETURN wchar_t * __cdecl wcsstr(const wchar_t * wcs1,
+                                       const wchar_t * wcs2) {
+        wchar_t *cp = (wchar_t *) wcs1;
+        wchar_t *s1, *s2;
+
+        if (!*wcs2)
+            return (wchar_t *)wcs1;
+
+        while (*cp)
+        {
+                s1 = cp;
+                s2 = (wchar_t *) wcs2;
+
+                while (*s1 && *s2 && !(*s1-*s2))
+                        s1++, s2++;
+
+                if (!*s2)
+                        return(cp);
+
+                cp++;
+        }
+
+        return(NULL);
+}
+
+/***
+*wcsrchr.c - find last occurrence of wchar_t character in wide string
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcsrchr() - find the last occurrence of a given character
+*       in a string (wide-characters).
+*
+*******************************************************************************/
+
+/***
+*wchar_t *wcsrchr(string, ch) - find last occurrence of ch in wide string
+*
+*Purpose:
+*       Finds the last occurrence of ch in string.  The terminating
+*       null character is used as part of the search (wide-characters).
+*
+*Entry:
+*       wchar_t *string - string to search in
+*       wchar_t ch - character to search for
+*
+*Exit:
+*       returns a pointer to the last occurrence of ch in the given
+*       string
+*       returns NULL if ch does not occurr in the string
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_CONST_RETURN wchar_t * __cdecl wcsrchr(const wchar_t * string, wchar_t ch) {
+        wchar_t *start = (wchar_t *)string;
+
+        while (*string++)                       /* find end of string */
+                ;
+                                                /* search towards front */
+        while (--string != start && *string != (wchar_t)ch)
+                ;
+
+        if (*string == (wchar_t)ch)             /* wchar_t found ? */
+                return( (wchar_t *)string );
+
+        return(NULL);
+}
+
+/***
+*wcschr.c - search a wchar_t string for a given wchar_t character
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcschr() - search a wchar_t string for a wchar_t character
+*
+*******************************************************************************/
+
+/***
+*wchar_t *wcschr(string, c) - search a string for a wchar_t character
+*
+*Purpose:
+*       Searches a wchar_t string for a given wchar_t character,
+*       which may be the null character L'\0'.
+*
+*Entry:
+*       wchar_t *string - wchar_t string to search in
+*       wchar_t c - wchar_t character to search for
+*
+*Exit:
+*       returns pointer to the first occurence of c in string
+*       returns NULL if c does not occur in string
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_CONST_RETURN wchar_t * __cdecl wcschr(const wchar_t * string, wchar_t ch) {
+        while (*string && *string != (wchar_t)ch)
+                string++;
+
+        if (*string == (wchar_t)ch)
+                return((wchar_t *)string);
+        return(NULL);
+}
+
+/***
+*xtoa.c - convert integers/longs to ASCII string
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       The module has code to convert integers/longs to ASCII strings.  See
+*
+*******************************************************************************/
+
+/***
+*char *_itoa, *_ltoa, *_ultoa(val, buf, radix) - convert binary int to ASCII
+*       string
+*
+*Purpose:
+*       Converts an int to a character string.
+*
+*Entry:
+*       val - number to be converted (int, long or unsigned long)
+*       int radix - base to convert into
+*       char *buf - ptr to buffer to place result
+*
+*Exit:
+*       fills in space pointed to by buf with string result
+*       returns a pointer to this buffer
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+/* helper routine that does the main job. */
+
+static void __cdecl xtoa(unsigned long val, char *buf, unsigned radix, int is_neg) {
+        char *p;                /* pointer to traverse string */
+        char *firstdig;         /* pointer to first digit */
+        char temp;              /* temp char */
+        unsigned digval;        /* value of digit */
+
+        p = buf;
+
+        if (is_neg) {
+            /* negative, so output '-' and negate */
+            *p++ = '-';
+            val = (unsigned long)(-(long)val);
+        }
+
+        firstdig = p;           /* save pointer to first digit */
+
+        do {
+            digval = (unsigned) (val % radix);
+            val /= radix;       /* get next digit */
+
+            /* convert to ascii and store */
+            if (digval > 9)
+                *p++ = (char) (digval - 10 + 'a');  /* a letter */
+            else
+                *p++ = (char) (digval + '0');       /* a digit */
+        } while (val > 0);
+
+        /* We now have the digit of the number in the buffer, but in reverse
+           order.  Thus we reverse them now. */
+
+        *p-- = '\0';            /* terminate string; p points to last digit */
+
+        do {
+            temp = *p;
+            *p = *firstdig;
+            *firstdig = temp;   /* swap *p and *firstdig */
+            --p;
+            ++firstdig;         /* advance to next two digits */
+        } while (firstdig < p); /* repeat until halfway */
+}
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+   and return pointer to buffer. */
+
+extern "C" char * __cdecl _itoa(int val, char *buf, int radix) {
+    if (radix == 10 && val < 0)
+        xtoa((unsigned long)val, buf, radix, 1);
+    else
+        xtoa((unsigned long)(unsigned int)val, buf, radix, 0);
+    return buf;
+}
+
+/***
+*strlen.c - contains strlen() routine
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       strlen returns the length of a null-terminated string,
+*       not including the null byte itself.
+*
+*******************************************************************************/
+
+#ifdef _MSC_VER
+#pragma function(strlen)
+#endif  /* _MSC_VER */
+
+/***
+*strlen - return the length of a null-terminated string
+*
+*Purpose:
+*       Finds the length in bytes of the given string, not including
+*       the final null character.
+*
+*Entry:
+*       const char * str - string whose length is to be computed
+*
+*Exit:
+*       length of the string "str", exclusive of the final null byte
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl strlen(const char * str) {
+        const char *eos = str;
+
+        while (*eos++) ;
+
+        return( (int)(eos - str - 1) );
+}
+
+/***
+*wcsncpy.c - copy at most n characters of wide-character string
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcsncpy() - copy at most n characters of wchar_t string
+*
+*******************************************************************************/
+
+/***
+*wchar_t *wcsncpy(dest, source, count) - copy at most n wide characters
+*
+*Purpose:
+*       Copies count characters from the source string to the
+*       destination.  If count is less than the length of source,
+*       NO NULL CHARACTER is put onto the end of the copied string.
+*       If count is greater than the length of sources, dest is padded
+*       with null characters to length count (wide-characters).
+*
+*
+*Entry:
+*       wchar_t *dest - pointer to destination
+*       wchar_t *source - source string for copy
+*       size_t count - max number of characters to copy
+*
+*Exit:
+*       returns dest
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+wchar_t * __cdecl wcsncpy(wchar_t * dest, const wchar_t * source, size_t count) {
+        wchar_t *start = dest;
+
+        while (count && (*dest++ = *source++))    /* copy string */
+                count--;
+
+        if (count)                              /* pad out with zeroes */
+                while (--count)
+                        *dest++ = L'\0';
+
+        return(start);
+}
+
+/***
+*wcscmp.c - routine to compare two wchar_t strings (for equal, less, or greater)
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       Compares two wide-character strings, determining their lexical order.
+*
+*******************************************************************************/
+
+/***
+*wcscmp - compare two wchar_t strings,
+*        returning less than, equal to, or greater than
+*
+*Purpose:
+*       wcscmp compares two wide-character strings and returns an integer
+*       to indicate whether the first is less than the second, the two are
+*       equal, or whether the first is greater than the second.
+*
+*       Comparison is done wchar_t by wchar_t on an UNSIGNED basis, which is to
+*       say that Null wchar_t(0) is less than any other character.
+*
+*Entry:
+*       const wchar_t * src - string for left-hand side of comparison
+*       const wchar_t * dst - string for right-hand side of comparison
+*
+*Exit:
+*       returns -1 if src <  dst
+*       returns  0 if src == dst
+*       returns +1 if src >  dst
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl wcscmp(const wchar_t * src, const wchar_t * dst) {
+        int ret = 0 ;
+
+        while (! (ret = (int)(*src - *dst)) && *dst)
+                ++src, ++dst;
+
+        if (ret < 0)
+                ret = -1 ;
+        else if (ret > 0)
+                ret = 1 ;
+
+        return( ret );
+}
+
+/***
+*wcslen.c - contains wcslen() routine
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       wcslen returns the length of a null-terminated wide-character string,
+*       not including the null wchar_t itself.
+*
+*******************************************************************************/
+
+/***
+*wcslen - return the length of a null-terminated wide-character string
+*
+*Purpose:
+*       Finds the length in wchar_t's of the given string, not including
+*       the final null wchar_t (wide-characters).
+*
+*Entry:
+*       const wchar_t * wcs - string whose length is to be computed
+*
+*Exit:
+*       length of the string "wcs", exclusive of the final null wchar_t
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl wcslen(
+        const wchar_t * wcs
+        ) {
+        const wchar_t *eos = wcs;
+
+        while (*eos++) ;
+
+        return( (size_t)(eos - wcs - 1) );
+}
+
+/***
+*strstr.c - search for one string inside another
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines strstr() - search for one string inside another
+*
+*******************************************************************************/
+
+/***
+*char *strstr(string1, string2) - search for string2 in string1
+*
+*Purpose:
+*       finds the first occurrence of string2 in string1
+*
+*Entry:
+*       char *string1 - string to search in
+*       char *string2 - string to search for
+*
+*Exit:
+*       returns a pointer to the first occurrence of string2 in
+*       string1, or NULL if string2 does not occur in string1
+*
+*Uses:
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_CONST_RETURN char * __cdecl strstr(
+        const char * str1,
+        const char * str2
+        ) {
+        char *cp = (char *) str1;
+        char *s1, *s2;
+
+        if (!*str2)
+            return((char *)str1);
+
+        while (*cp)
+        {
+                s1 = cp;
+                s2 = (char *) str2;
+
+                while (*s1 && *s2 && !(*s1-*s2))
+                        s1++, s2++;
+
+                if (!*s2)
+                        return(cp);
+
+                cp++;
+        }
+
+        return(NULL);
+
+}
+
+/***
+*strcmp.c - routine to compare two strings (for equal, less, or greater)
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       Compares two string, determining their lexical order.
+*
+*******************************************************************************/
+
+#ifdef _MSC_VER
+#pragma function(strcmp)
+#endif  /* _MSC_VER */
+
+/***
+*strcmp - compare two strings, returning less than, equal to, or greater than
+*
+*Purpose:
+*       STRCMP compares two strings and returns an integer
+*       to indicate whether the first is less than the second, the two are
+*       equal, or whether the first is greater than the second.
+*
+*       Comparison is done byte by byte on an UNSIGNED basis, which is to
+*       say that Null (0) is less than any other character (1-255).
+*
+*Entry:
+*       const char * src - string for left-hand side of comparison
+*       const char * dst - string for right-hand side of comparison
+*
+*Exit:
+*       returns -1 if src <  dst
+*       returns  0 if src == dst
+*       returns +1 if src >  dst
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl strcmp(
+        const char * src,
+        const char * dst
+        ) {
+        int ret = 0 ;
+
+        while (! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
+                ++src, ++dst;
+
+        if (ret < 0)
+                ret = -1 ;
+        else if (ret > 0)
+                ret = 1 ;
+
+        return( ret );
+}
+
+#ifndef _MBSCAT
+#ifdef _MSC_VER
+#pragma function(strcpy)
+#endif  /* _MSC_VER */
+#endif  /* _MBSCAT */
+
+/***
+*char *strcpy(dst, src) - copy one string over another
+*
+*Purpose:
+*       Copies the string src into the spot specified by
+*       dest; assumes enough room.
+*
+*Entry:
+*       char * dst - string over which "src" is to be copied
+*       const char * src - string to be copied over "dst"
+*
+*Exit:
+*       The address of "dst"
+*
+*Exceptions:
+*******************************************************************************/
+
+char * __cdecl strcpy(char * dst, const char * src) {
+        char * cp = dst;
+
+        while (*cp++ = *src++)
+                ;               /* Copy src over dst */
+
+        return( dst );
+}
+
+/***
+*strncmp.c - compare first n characters of two strings
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines strncmp() - compare first n characters of two strings
+*       for lexical order.
+*
+*******************************************************************************/
+
+/***
+*int strncmp(first, last, count) - compare first count chars of strings
+*
+*Purpose:
+*       Compares two strings for lexical order.  The comparison stops
+*       after: (1) a difference between the strings is found, (2) the end
+*       of the strings is reached, or (3) count characters have been
+*       compared.
+*
+*Entry:
+*       char *first, *last - strings to compare
+*       unsigned count - maximum number of characters to compare
+*
+*Exit:
+*       returns <0 if first < last
+*       returns  0 if first == last
+*       returns >0 if first > last
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl strncmp(
+        const char * first,
+        const char * last,
+        size_t count
+        ) {
+        if (!count)
+                return(0);
+
+        while (--count && *first && *first == *last)
+        {
+                first++;
+                last++;
+        }
+
+        return( *(unsigned char *)first - *(unsigned char *)last );
+}
+
+/***
+*strchr.c - search a string for a given character
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines strchr() - search a string for a character
+*
+*******************************************************************************/
+
+/***
+*char *strchr(string, c) - search a string for a character
+*
+*Purpose:
+*       Searches a string for a given character, which may be the
+*       null character '\0'.
+*
+*Entry:
+*       char *string - string to search in
+*       char c - character to search for
+*
+*Exit:
+*       returns pointer to the first occurence of c in string
+*       returns NULL if c does not occur in string
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+_CONST_RETURN char * __cdecl strchr(
+        const char * string,
+        int ch
+        ) {
+        while (*string && *string != (char)ch)
+                string++;
+
+        if (*string == (char)ch)
+                return((char *)string);
+        return(NULL);
+}
+
+/***
+*wcsncmp.c - compare first n characters of two wide-character strings
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcsncmp() - compare first n characters of two wchar_t strings
+*       for lexical order.
+*
+*******************************************************************************/
+
+/***
+*int wcsncmp(first, last, count) - compare first count chars of wchar_t strings
+*
+*Purpose:
+*       Compares two strings for lexical order.  The comparison stops
+*       after: (1) a difference between the strings is found, (2) the end
+*       of the strings is reached, or (3) count characters have been
+*       compared (wide-character strings).
+*
+*Entry:
+*       wchar_t *first, *last - strings to compare
+*       size_t count - maximum number of characters to compare
+*
+*Exit:
+*       returns <0 if first < last
+*       returns  0 if first == last
+*       returns >0 if first > last
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl wcsncmp(
+        const wchar_t * first,
+        const wchar_t * last,
+        size_t count
+        ) {
+        if (!count)
+                return(0);
+
+        while (--count && *first && *first == *last)
+        {
+                first++;
+                last++;
+        }
+
+        return((int)(*first - *last));
+}
+
+/***
+*wcsspn.c - find length of initial substring of chars from a control string
+*       (wide-character strings)
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcsspn() - finds the length of the initial substring of
+*       a string consisting entirely of characters from a control string
+*       (wide-character strings).
+*
+*******************************************************************************/
+
+/***
+*int wcsspn(string, control) - find init substring of control chars
+*
+*Purpose:
+*       Finds the index of the first character in string that does belong
+*       to the set of characters specified by control.  This is
+*       equivalent to the length of the initial substring of string that
+*       consists entirely of characters from control.  The L'\0' character
+*       that terminates control is not considered in the matching process
+*       (wide-character strings).
+*
+*Entry:
+*       wchar_t *string - string to search
+*       wchar_t *control - string containing characters not to search for
+*
+*Exit:
+*       returns index of first wchar_t in string not in control
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl wcsspn(
+        const wchar_t * string,
+        const wchar_t * control
+        ) {
+        wchar_t *str = (wchar_t *) string;
+        wchar_t *ctl;
+
+        /* 1st char not in control string stops search */
+        while (*str) {
+            for (ctl = (wchar_t *)control; *ctl != *str; ctl++) {
+                if (*ctl == (wchar_t)0) {
+                    /*
+                     * reached end of control string without finding a match
+                     */
+                    return (size_t)(str - string);
+                }
+            }
+            str++;
+        }
+        /*
+         * The whole string consisted of characters from control
+         */
+        return (size_t)(str - string);
+}
+
+/***
+*wcscspn.c - find length of initial substring of wide characters
+*        not in a control string
+*
+*       Copyright (c) Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+*       defines wcscspn()- finds the length of the initial substring of
+*       a string consisting entirely of characters not in a control string
+*       (wide-character strings).
+*
+*******************************************************************************/
+
+/***
+*size_t wcscspn(string, control) - search for init substring w/o control wchars
+*
+*Purpose:
+*       returns the index of the first character in string that belongs
+*       to the set of characters specified by control.  This is equivalent
+*       to the length of the length of the initial substring of string
+*       composed entirely of characters not in control.  Null chars not
+*       considered (wide-character strings).
+*
+*Entry:
+*       wchar_t *string - string to search
+*       wchar_t *control - set of characters not allowed in init substring
+*
+*Exit:
+*       returns the index of the first wchar_t in string
+*       that is in the set of characters specified by control.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl wcscspn(
+        const wchar_t * string,
+        const wchar_t * control
+        ) {
+        wchar_t *str = (wchar_t *) string;
+        wchar_t *wcset;
+
+        /* 1st char in control string stops search */
+        while (*str) {
+            for (wcset = (wchar_t *)control; *wcset; wcset++) {
+                if (*wcset == *str) {
+                    return (size_t)(str - string);
+                }
+            }
+            str++;
+        }
+        return (size_t)(str - string);
+}
+
+/***
+*wchar_t *wcscpy(dst, src) - copy one wchar_t string over another
+*
+*Purpose:
+*       Copies the wchar_t string src into the spot specified by
+*       dest; assumes enough room.
+*
+*Entry:
+*       wchar_t * dst - wchar_t string over which "src" is to be copied
+*       const wchar_t * src - wchar_t string to be copied over "dst"
+*
+*Exit:
+*       The address of "dst"
+*
+*Exceptions:
+*******************************************************************************/
+
+wchar_t * __cdecl wcscpy(wchar_t * dst, const wchar_t * src)
+{
+        wchar_t * cp = dst;
+
+        while( *cp++ = *src++ )
+                ;               /* Copy src over dst */
+
+        return( dst );
+}
+
+/***
+*strtol, strtoul(nptr,endptr,ibase) - Convert ascii string to long un/signed
+*       int.
+*
+*Purpose:
+*       Convert an ascii string to a long 32-bit value.  The base
+*       used for the caculations is supplied by the caller.  The base
+*       must be in the range 0, 2-36.  If a base of 0 is supplied, the
+*       ascii string must be examined to determine the base of the
+*       number:
+*               (a) First char = '0', second char = 'x' or 'X',
+*                   use base 16.
+*               (b) First char = '0', use base 8
+*               (c) First char in range '1' - '9', use base 10.
+*
+*       If the 'endptr' value is non-NULL, then strtol/strtoul places
+*       a pointer to the terminating character in this value.
+*       See ANSI standard for details
+*
+*Entry:
+*       nptr == NEAR/FAR pointer to the start of string.
+*       endptr == NEAR/FAR pointer to the end of the string.
+*       ibase == integer base to use for the calculations.
+*
+*       string format: [whitespace] [sign] [0] [x] [digits/letters]
+*
+*Exit:
+*       Good return:
+*               result
+*
+*       Overflow return:
+*               strtol -- LONG_MAX or LONG_MIN
+*               strtoul -- ULONG_MAX
+*               strtol/strtoul -- errno == ERANGE
+*
+*       No digits or bad base return:
+*               0
+*               endptr = nptr*
+*
+*Exceptions:
+*       None.
+*******************************************************************************/
+
+/* flag values */
+#define FL_UNSIGNED   1       /* strtoul called */
+#define FL_NEG        2       /* negative sign found */
+#define FL_OVERFLOW   4       /* overflow occured */
+#define FL_READDIGIT  8       /* we've read at least one correct digit */
+
+// __ascii_isdigit returns a non-zero value if c is a decimal digit (0 – 9).
+int __ascii_isdigit(int c)
+{
+  return (c >= '0' && c <= '9');
+}
+
+// __ascii_isalpha returns a nonzero value if c is within
+// the ranges A – Z or a – z.
+int __ascii_isalpha(int c)
+{
+  return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
+}
+
+// __ascii_toupper converts lowercase character to uppercase.
+int __ascii_toupper(int c)
+{
+  if (c >= 'a' && c <= 'z') return (c - ('a' - 'A'));
+  return c;
+}
+
+int isspace(int c)
+{
+  static bool spaces[256] =
+  {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  // 0-9
+    1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  // 10-19
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 20-29
+    0, 0, 1, 0, 0, 0, 0, 0, 0, 0,  // 30-39
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 40-49
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 50-59
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 60-69
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 70-79
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 80-89
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 90-99
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 100-109
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 110-119
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 120-129
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 130-139
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 140-149
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 150-159
+    1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 160-169
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 170-179
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 180-189
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 190-199
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 200-209
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 210-219
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 220-229
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 230-239
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 240-249
+    0, 0, 0, 0, 0, 1,              // 250-255
+  };
+
+  return spaces[static_cast<unsigned char>(c)] == 1;
+}
+
+static unsigned long __cdecl strtoxl (
+        const char *nptr,
+        const char **endptr,
+        int ibase,
+        int flags
+        )
+{
+        const char *p;
+        char c;
+        unsigned long number;
+        unsigned digval;
+        unsigned long maxval;
+
+        p = nptr;                       /* p is our scanning pointer */
+        number = 0;                     /* start with zero */
+
+        c = *p++;                       /* read char */
+        while ( isspace((int)(unsigned char)c) )
+                c = *p++;               /* skip whitespace */
+
+        if (c == '-') {
+                flags |= FL_NEG;        /* remember minus sign */
+                c = *p++;
+        }
+        else if (c == '+')
+                c = *p++;               /* skip sign */
+
+        if (ibase < 0 || ibase == 1 || ibase > 36) {
+                /* bad base! */
+                if (endptr)
+                        /* store beginning of string in endptr */
+                        *endptr = nptr;
+                return 0L;              /* return 0 */
+        }
+        else if (ibase == 0) {
+                /* determine base free-lance, based on first two chars of
+                   string */
+                if (c != '0')
+                        ibase = 10;
+                else if (*p == 'x' || *p == 'X')
+                        ibase = 16;
+                else
+                        ibase = 8;
+        }
+
+        if (ibase == 16) {
+                /* we might have 0x in front of number; remove if there */
+                if (c == '0' && (*p == 'x' || *p == 'X')) {
+                        ++p;
+                        c = *p++;       /* advance past prefix */
+                }
+        }
+
+        /* if our number exceeds this, we will overflow on multiply */
+        maxval = ULONG_MAX / ibase;
+
+
+        for (;;) {      /* exit in middle of loop */
+                /* convert c to value */
+                if ( __ascii_isdigit((int)(unsigned char)c) )
+                        digval = c - '0';
+                else if ( __ascii_isalpha((int)(unsigned char)c) )
+                        digval = __ascii_toupper(c) - 'A' + 10;
+                else
+                        break;
+                if (digval >= (unsigned)ibase)
+                        break;          /* exit loop if bad digit found */
+
+                /* record the fact we have read one digit */
+                flags |= FL_READDIGIT;
+
+                /* we now need to compute number = number * base + digval,
+                   but we need to know if overflow occured.  This requires
+                   a tricky pre-check. */
+
+                if (number < maxval || (number == maxval &&
+                (unsigned long)digval <= ULONG_MAX % ibase)) {
+                        /* we won't overflow, go ahead and multiply */
+                        number = number * ibase + digval;
+                }
+                else {
+                        /* we would have overflowed -- set the overflow flag */
+                        flags |= FL_OVERFLOW;
+                }
+
+                c = *p++;               /* read next digit */
+        }
+
+        --p;                            /* point to place that stopped scan */
+
+        if (!(flags & FL_READDIGIT)) {
+                /* no number there; return 0 and point to beginning of
+                   string */
+                if (endptr)
+                        /* store beginning of string in endptr later on */
+                        p = nptr;
+                number = 0L;            /* return 0 */
+        }
+        else if ( (flags & FL_OVERFLOW) ||
+                  ( !(flags & FL_UNSIGNED) &&
+                    ( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||
+                      ( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )
+        {
+                /* overflow or signed overflow occurred */
+                // errno = ERANGE;
+                if ( flags & FL_UNSIGNED )
+                        number = ULONG_MAX;
+                else if ( flags & FL_NEG )
+                        number = (unsigned long)(-LONG_MIN);
+                else
+                        number = LONG_MAX;
+        }
+
+        if (endptr != NULL)
+                /* store pointer to char that stopped the scan */
+                *endptr = p;
+
+        if (flags & FL_NEG)
+                /* negate result if there was a neg sign */
+                number = (unsigned long)(-(long)number);
+
+        return number;                  /* done. */
+}
+
+long __cdecl strtol (
+        const char *nptr,
+        char **endptr,
+        int ibase
+        )
+{
+        return (long) strtoxl(nptr, (const char**)endptr, ibase, 0);
+}
+
+unsigned long __cdecl strtoul (
+        const char *nptr,
+        char **endptr,
+        int ibase
+        )
+{
+        return strtoxl(nptr, (const char**)endptr, ibase, FL_UNSIGNED);
+}
+
diff --git a/third_party/minicrt/struplwr.cc b/third_party/minicrt/struplwr.cc
index 08e3be4..311f7ab 100644
--- a/third_party/minicrt/struplwr.cc
+++ b/third_party/minicrt/struplwr.cc
@@ -1,20 +1,20 @@
-//==========================================

-// LIBCTINY - Matt Pietrek 2001

-// MSDN Magazine, January 2001

-//==========================================

-#include "libctiny.h"

-#include <windows.h>

-#include <string.h>

-

-// Force the linker to include USER32.LIB

-#pragma comment(linker, "/defaultlib:user32.lib")

-

-extern "C" char *  __cdecl strupr(char *s) {

-    CharUpperBuff( s, lstrlen(s) );

-    return s;

-}

-

-extern "C" char *  __cdecl strlwr(char *s) {

-    CharLowerBuff( s, lstrlen(s) );

-    return s;

-}

+//==========================================
+// LIBCTINY - Matt Pietrek 2001
+// MSDN Magazine, January 2001
+//==========================================
+#include "libctiny.h"
+#include <windows.h>
+#include <string.h>
+
+// Force the linker to include USER32.LIB
+#pragma comment(linker, "/defaultlib:user32.lib")
+
+extern "C" char *  __cdecl strupr(char *s) {
+    CharUpperBuff( s, lstrlen(s) );
+    return s;
+}
+
+extern "C" char *  __cdecl strlwr(char *s) {
+    CharLowerBuff( s, lstrlen(s) );
+    return s;
+}
diff --git a/third_party/smartany/auto_any.h b/third_party/smartany/auto_any.h
index 5968249..7b75726 100644
--- a/third_party/smartany/auto_any.h
+++ b/third_party/smartany/auto_any.h
@@ -1,315 +1,315 @@
-//+---------------------------------------------------------------------------

-//

-//  Copyright ( C ) Microsoft, 2002.

-//

-//  File:       auto_any.h

-//

-//  Contents:   automatic resource management, a-la std::auto_ptr

-//

-//  Classes:    auto_any<> and various typedefs

-//

-//  Functions:  get

-//              reset

-//              release

-//              valid

-//              address

-//

-//  Author:     Eric Niebler ( ericne@microsoft.com )

-//

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

-

-#ifndef AUTO_ANY

-#define AUTO_ANY

-#include <cassert>

-#include "smart_any_fwd.h"

-

-#pragma warning(push)

-

-// 4284 warning for operator-> returning non-pointer;

-//      compiler issues it even if -> is not used for the specific instance

-#pragma warning(disable: 4284) 

-

-namespace detail

-{

-    // friend function definitions go in auto_any_helper

-    template<typename T,class close_policy,class invalid_value,int unique>

-    struct auto_any_helper;

-}

-

-// proxy reference for auto_any copying

-template<typename T,class close_policy,class invalid_value,int unique>

-struct auto_any_ref

-{

-    // construct from compatible auto_any

-    auto_any_ref( auto_any<T,close_policy,invalid_value,unique> & that )

-        : m_that( that )

-    {

-    }

-

-    // reference to constructor argument

-    auto_any<T,close_policy,invalid_value,unique> & m_that;

-

-private:

-    auto_any_ref * operator=( auto_any_ref const & );

-};

-

-// wrap a resource to enforce strict ownership and ensure proper cleanup

-template<typename T,class close_policy,class invalid_value,int unique>

-class auto_any

-{

-    typedef detail::safe_types<T,close_policy>  safe_types;

-

-    // disallow comparison of auto_any's

-    bool operator==( detail::safe_bool ) const;

-    bool operator!=( detail::safe_bool ) const;

-

-public:

-    typedef typename detail::holder<T>::type    element_type;

-    typedef close_policy                        close_policy_type;

-    typedef typename safe_types::pointer_type   pointer_type;

-    typedef typename safe_types::reference_type reference_type;

-

-    // Fix-up the invalid_value type on older compilers

-    typedef typename detail::fixup_invalid_value<invalid_value>::

-        template rebind<T>::type invalid_value_type;

-

-    friend struct detail::auto_any_helper<T,close_policy,invalid_value,unique>;

-

-    // construct from object pointer

-    explicit auto_any( T t = invalid_value_type() )

-        : m_t( t )

-    {

-    }

-

-    // construct by assuming pointer from right auto_any

-    auto_any( auto_any<T,close_policy,invalid_value,unique> & right )

-        : m_t( release( right ) )

-    {

-    }

-

-    // construct by assuming pointer from right auto_any_ref

-    auto_any( auto_any_ref<T,close_policy,invalid_value,unique> right )

-        : m_t( release( right.m_that ) )

-    {

-    }

-

-    // convert to compatible auto_any_ref

-    operator auto_any_ref<T,close_policy,invalid_value,unique>()

-    {

-        return auto_any_ref<T,close_policy,invalid_value,unique>( *this );

-    }

-

-    // assign compatible right

-    auto_any<T,close_policy,invalid_value,unique> & operator=( 

-        auto_any<T,close_policy,invalid_value,unique> & right )

-    {

-        reset( *this, release( right ) );

-        return *this;

-    }

-

-    // assign compatible right.ref

-    auto_any<T,close_policy,invalid_value,unique> & operator=( 

-        auto_any_ref<T,close_policy,invalid_value,unique> & right )

-    {

-        reset( *this, release( right.m_that ) );

-        return *this;

-    }

-

-    // destroy the object

-    ~auto_any()

-    {

-        if( valid() )

-        {

-            close_policy::close( m_t );

-        }

-    }

-

-    // return pointer to class object (assume pointer)

-    pointer_type operator->() const

-    {

-        #ifdef SMART_ANY_PTS

-        // You better not be applying operator-> to a handle!

-        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;

-        #endif

-        assert( valid() );

-        return safe_types::to_pointer( m_t );

-    }

-

-    // for use when auto_any appears in a conditional

-    operator detail::safe_bool() const

-    {

-        return valid() ? detail::safe_true : detail::safe_false;

-    }

-

-    // for use when auto_any appears in a conditional

-    bool operator!() const

-    {

-        return ! valid();

-    }

-

-    #ifdef SMART_ANY_PTS

-    // if this auto_any is managing an array, we can use operator[] to index it

-    typename detail::deref<T>::type operator[]( int i ) const

-    {

-        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;

-        static detail::static_assert<!detail::is_delete<close_policy>::value> const accessed_like_an_array_but_not_deleted_like_an_array;

-        assert( valid() );

-        return m_t[ i ];

-    }

-

-    // unary operator* lets you write code like:

-    // auto_any<foo*,close_delete> pfoo( new foo );

-    // foo & f = *pfoo;

-    reference_type operator*() const

-    {

-        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;

-        assert( valid() );

-        return safe_types::to_reference( m_t );

-    }

-    #endif

-

-private:

-

-    bool valid() const

-    {

-        // see if the managed resource is in the invalid state.

-        return m_t != static_cast<T>( invalid_value_type() );

-    }

-

-    // the wrapped object

-    element_type m_t;

-};

-

-namespace detail

-{

-    // friend function definitions go in auto_any_helper

-    template<typename T,class close_policy,class invalid_value,int unique>

-    struct auto_any_helper

-    {

-        // return wrapped pointer

-        static T get( auto_any<T,close_policy,invalid_value,unique> const & t )

-        {

-            return t.m_t;

-        }

-

-        // return wrapped pointer and give up ownership

-        static T release( auto_any<T,close_policy,invalid_value,unique> & t )

-        {

-            // Fix-up the invalid_value type on older compilers

-            typedef typename detail::fixup_invalid_value<invalid_value>::

-                template rebind<T>::type invalid_value_type;

-

-            T tmpT = t.m_t;

-            t.m_t = static_cast<T>( invalid_value_type() );

-            return tmpT;

-        }

-

-        // destroy designated object and store new pointer

-        static void reset( auto_any<T,close_policy,invalid_value,unique> & t, T newT )

-        {

-            if( t.m_t != newT )

-            {

-                if( t.valid() )

-                {

-                    close_policy::close( t.m_t );

-                }

-                t.m_t = newT;

-            }

-        }

-

-        typedef typename auto_any<T,close_policy,invalid_value,unique>::element_type element_type;

-

-        // return the address of the wrapped pointer

-        static element_type* address( auto_any<T,close_policy,invalid_value,unique> & t )

-        {

-            // check to make sure the wrapped object is in the invalid state

-            assert( !t.valid() );

-            return address_of( t.m_t );

-        }

-    };

-}

-

-// return wrapped resource

-template<typename T,class close_policy,class invalid_value,int unique>

-inline T get( auto_any<T,close_policy,invalid_value,unique> const & t )

-{

-    return detail::auto_any_helper<T,close_policy,invalid_value,unique>::get( t );

-}

-

-// return true if the auto_any contains a currently valid resource

-template<typename T,class close_policy,class invalid_value,int unique>

-inline bool valid( auto_any<T,close_policy,invalid_value,unique> const & t )

-{

-    return t;

-}

-

-// return wrapped resource and give up ownership

-template<typename T,class close_policy,class invalid_value,int unique>

-inline T release( auto_any<T,close_policy,invalid_value,unique> & t )

-{

-    return detail::auto_any_helper<T,close_policy,invalid_value,unique>::release( t );

-}

-

-// destroy designated object and store new resource

-template<typename T,class close_policy,class invalid_value,int unique>

-inline void reset( auto_any<T,close_policy,invalid_value,unique> & t )

-{

-    typedef typename detail::fixup_invalid_value<invalid_value>::

-        template rebind<T>::type invalid_value_type;

-    detail::auto_any_helper<T,close_policy,invalid_value,unique>::reset( t, invalid_value_type() );

-}

-

-// destroy designated object and store new resource

-template<typename T,class close_policy,class invalid_value,int unique,typename U>

-inline void reset( auto_any<T,close_policy,invalid_value,unique> & t, U newT )

-{

-    detail::auto_any_helper<T,close_policy,invalid_value,unique>::reset( t, newT );

-}

-

-// swap the contents of two shared_any objects

-template<typename T,class close_policy,class invalid_value,int unique>

-void swap( auto_any<T,close_policy,invalid_value,unique> & left, 

-           auto_any<T,close_policy,invalid_value,unique> & right )

-{

-    auto_any<T,close_policy,invalid_value,unique> tmp( left );

-    left = right;

-    right = tmp;

-}

-

-// return the address of the wrapped resource

-// WARNING: this will assert if the value of the resource is

-// anything other than invalid_value.

-template<typename T,class close_policy,class invalid_value,int unique>

-inline typename auto_any<T,close_policy,invalid_value,unique>::element_type* 

-    address( auto_any<T,close_policy,invalid_value,unique> & t )

-{

-    return detail::auto_any_helper<T,close_policy,invalid_value,unique>::address( t );

-}

-

-#pragma warning(pop)

-

-#endif

-

-// This causes the auto_* typedefs to be defined

-DECLARE_SMART_ANY_TYPEDEFS(auto)

-

-#if defined(_OBJBASE_H_) & !defined(AUTO_ANY_CO_INIT)

-# define AUTO_ANY_CO_INIT

-  typedef auto_any<HRESULT,close_co,co_not_init>                            auto_co_close;

-

-  // Helper class for balancing calls to CoInitialize and CoUninitialize

-  struct auto_co_init

-  {

-      explicit auto_co_init( DWORD dwCoInit = COINIT_APARTMENTTHREADED )

-          : m_hr( smart_co_init_helper( dwCoInit ) )

-      {

-      }

-      HRESULT hresult() const

-      {

-          return get(m_hr);

-      }

-      auto_co_close const m_hr;

-  private:

-      auto_co_init & operator=( auto_co_init const & );

-  };

-#endif

+//+---------------------------------------------------------------------------
+//
+//  Copyright ( C ) Microsoft, 2002.
+//
+//  File:       auto_any.h
+//
+//  Contents:   automatic resource management, a-la std::auto_ptr
+//
+//  Classes:    auto_any<> and various typedefs
+//
+//  Functions:  get
+//              reset
+//              release
+//              valid
+//              address
+//
+//  Author:     Eric Niebler ( ericne@microsoft.com )
+//
+//----------------------------------------------------------------------------
+
+#ifndef AUTO_ANY
+#define AUTO_ANY
+#include <cassert>
+#include "smart_any_fwd.h"
+
+#pragma warning(push)
+
+// 4284 warning for operator-> returning non-pointer;
+//      compiler issues it even if -> is not used for the specific instance
+#pragma warning(disable: 4284) 
+
+namespace detail
+{
+    // friend function definitions go in auto_any_helper
+    template<typename T,class close_policy,class invalid_value,int unique>
+    struct auto_any_helper;
+}
+
+// proxy reference for auto_any copying
+template<typename T,class close_policy,class invalid_value,int unique>
+struct auto_any_ref
+{
+    // construct from compatible auto_any
+    auto_any_ref( auto_any<T,close_policy,invalid_value,unique> & that )
+        : m_that( that )
+    {
+    }
+
+    // reference to constructor argument
+    auto_any<T,close_policy,invalid_value,unique> & m_that;
+
+private:
+    auto_any_ref * operator=( auto_any_ref const & );
+};
+
+// wrap a resource to enforce strict ownership and ensure proper cleanup
+template<typename T,class close_policy,class invalid_value,int unique>
+class auto_any
+{
+    typedef detail::safe_types<T,close_policy>  safe_types;
+
+    // disallow comparison of auto_any's
+    bool operator==( detail::safe_bool ) const;
+    bool operator!=( detail::safe_bool ) const;
+
+public:
+    typedef typename detail::holder<T>::type    element_type;
+    typedef close_policy                        close_policy_type;
+    typedef typename safe_types::pointer_type   pointer_type;
+    typedef typename safe_types::reference_type reference_type;
+
+    // Fix-up the invalid_value type on older compilers
+    typedef typename detail::fixup_invalid_value<invalid_value>::
+        template rebind<T>::type invalid_value_type;
+
+    friend struct detail::auto_any_helper<T,close_policy,invalid_value,unique>;
+
+    // construct from object pointer
+    explicit auto_any( T t = invalid_value_type() )
+        : m_t( t )
+    {
+    }
+
+    // construct by assuming pointer from right auto_any
+    auto_any( auto_any<T,close_policy,invalid_value,unique> & right )
+        : m_t( release( right ) )
+    {
+    }
+
+    // construct by assuming pointer from right auto_any_ref
+    auto_any( auto_any_ref<T,close_policy,invalid_value,unique> right )
+        : m_t( release( right.m_that ) )
+    {
+    }
+
+    // convert to compatible auto_any_ref
+    operator auto_any_ref<T,close_policy,invalid_value,unique>()
+    {
+        return auto_any_ref<T,close_policy,invalid_value,unique>( *this );
+    }
+
+    // assign compatible right
+    auto_any<T,close_policy,invalid_value,unique> & operator=( 
+        auto_any<T,close_policy,invalid_value,unique> & right )
+    {
+        reset( *this, release( right ) );
+        return *this;
+    }
+
+    // assign compatible right.ref
+    auto_any<T,close_policy,invalid_value,unique> & operator=( 
+        auto_any_ref<T,close_policy,invalid_value,unique> & right )
+    {
+        reset( *this, release( right.m_that ) );
+        return *this;
+    }
+
+    // destroy the object
+    ~auto_any()
+    {
+        if( valid() )
+        {
+            close_policy::close( m_t );
+        }
+    }
+
+    // return pointer to class object (assume pointer)
+    pointer_type operator->() const
+    {
+        #ifdef SMART_ANY_PTS
+        // You better not be applying operator-> to a handle!
+        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;
+        #endif
+        assert( valid() );
+        return safe_types::to_pointer( m_t );
+    }
+
+    // for use when auto_any appears in a conditional
+    operator detail::safe_bool() const
+    {
+        return valid() ? detail::safe_true : detail::safe_false;
+    }
+
+    // for use when auto_any appears in a conditional
+    bool operator!() const
+    {
+        return ! valid();
+    }
+
+    #ifdef SMART_ANY_PTS
+    // if this auto_any is managing an array, we can use operator[] to index it
+    typename detail::deref<T>::type operator[]( int i ) const
+    {
+        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;
+        static detail::static_assert<!detail::is_delete<close_policy>::value> const accessed_like_an_array_but_not_deleted_like_an_array;
+        assert( valid() );
+        return m_t[ i ];
+    }
+
+    // unary operator* lets you write code like:
+    // auto_any<foo*,close_delete> pfoo( new foo );
+    // foo & f = *pfoo;
+    reference_type operator*() const
+    {
+        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;
+        assert( valid() );
+        return safe_types::to_reference( m_t );
+    }
+    #endif
+
+private:
+
+    bool valid() const
+    {
+        // see if the managed resource is in the invalid state.
+        return m_t != static_cast<T>( invalid_value_type() );
+    }
+
+    // the wrapped object
+    element_type m_t;
+};
+
+namespace detail
+{
+    // friend function definitions go in auto_any_helper
+    template<typename T,class close_policy,class invalid_value,int unique>
+    struct auto_any_helper
+    {
+        // return wrapped pointer
+        static T get( auto_any<T,close_policy,invalid_value,unique> const & t )
+        {
+            return t.m_t;
+        }
+
+        // return wrapped pointer and give up ownership
+        static T release( auto_any<T,close_policy,invalid_value,unique> & t )
+        {
+            // Fix-up the invalid_value type on older compilers
+            typedef typename detail::fixup_invalid_value<invalid_value>::
+                template rebind<T>::type invalid_value_type;
+
+            T tmpT = t.m_t;
+            t.m_t = static_cast<T>( invalid_value_type() );
+            return tmpT;
+        }
+
+        // destroy designated object and store new pointer
+        static void reset( auto_any<T,close_policy,invalid_value,unique> & t, T newT )
+        {
+            if( t.m_t != newT )
+            {
+                if( t.valid() )
+                {
+                    close_policy::close( t.m_t );
+                }
+                t.m_t = newT;
+            }
+        }
+
+        typedef typename auto_any<T,close_policy,invalid_value,unique>::element_type element_type;
+
+        // return the address of the wrapped pointer
+        static element_type* address( auto_any<T,close_policy,invalid_value,unique> & t )
+        {
+            // check to make sure the wrapped object is in the invalid state
+            assert( !t.valid() );
+            return address_of( t.m_t );
+        }
+    };
+}
+
+// return wrapped resource
+template<typename T,class close_policy,class invalid_value,int unique>
+inline T get( auto_any<T,close_policy,invalid_value,unique> const & t )
+{
+    return detail::auto_any_helper<T,close_policy,invalid_value,unique>::get( t );
+}
+
+// return true if the auto_any contains a currently valid resource
+template<typename T,class close_policy,class invalid_value,int unique>
+inline bool valid( auto_any<T,close_policy,invalid_value,unique> const & t )
+{
+    return t;
+}
+
+// return wrapped resource and give up ownership
+template<typename T,class close_policy,class invalid_value,int unique>
+inline T release( auto_any<T,close_policy,invalid_value,unique> & t )
+{
+    return detail::auto_any_helper<T,close_policy,invalid_value,unique>::release( t );
+}
+
+// destroy designated object and store new resource
+template<typename T,class close_policy,class invalid_value,int unique>
+inline void reset( auto_any<T,close_policy,invalid_value,unique> & t )
+{
+    typedef typename detail::fixup_invalid_value<invalid_value>::
+        template rebind<T>::type invalid_value_type;
+    detail::auto_any_helper<T,close_policy,invalid_value,unique>::reset( t, invalid_value_type() );
+}
+
+// destroy designated object and store new resource
+template<typename T,class close_policy,class invalid_value,int unique,typename U>
+inline void reset( auto_any<T,close_policy,invalid_value,unique> & t, U newT )
+{
+    detail::auto_any_helper<T,close_policy,invalid_value,unique>::reset( t, newT );
+}
+
+// swap the contents of two shared_any objects
+template<typename T,class close_policy,class invalid_value,int unique>
+void swap( auto_any<T,close_policy,invalid_value,unique> & left, 
+           auto_any<T,close_policy,invalid_value,unique> & right )
+{
+    auto_any<T,close_policy,invalid_value,unique> tmp( left );
+    left = right;
+    right = tmp;
+}
+
+// return the address of the wrapped resource
+// WARNING: this will assert if the value of the resource is
+// anything other than invalid_value.
+template<typename T,class close_policy,class invalid_value,int unique>
+inline typename auto_any<T,close_policy,invalid_value,unique>::element_type* 
+    address( auto_any<T,close_policy,invalid_value,unique> & t )
+{
+    return detail::auto_any_helper<T,close_policy,invalid_value,unique>::address( t );
+}
+
+#pragma warning(pop)
+
+#endif
+
+// This causes the auto_* typedefs to be defined
+DECLARE_SMART_ANY_TYPEDEFS(auto)
+
+#if defined(_OBJBASE_H_) & !defined(AUTO_ANY_CO_INIT)
+# define AUTO_ANY_CO_INIT
+  typedef auto_any<HRESULT,close_co,co_not_init>                            auto_co_close;
+
+  // Helper class for balancing calls to CoInitialize and CoUninitialize
+  struct auto_co_init
+  {
+      explicit auto_co_init( DWORD dwCoInit = COINIT_APARTMENTTHREADED )
+          : m_hr( smart_co_init_helper( dwCoInit ) )
+      {
+      }
+      HRESULT hresult() const
+      {
+          return get(m_hr);
+      }
+      auto_co_close const m_hr;
+  private:
+      auto_co_init & operator=( auto_co_init const & );
+  };
+#endif
diff --git a/third_party/smartany/scoped_any.h b/third_party/smartany/scoped_any.h
index 1c10576..829f7ed 100644
--- a/third_party/smartany/scoped_any.h
+++ b/third_party/smartany/scoped_any.h
@@ -1,257 +1,257 @@
-//+---------------------------------------------------------------------------

-//

-//  Copyright ( C ) Microsoft, 2002.

-//

-//  File:       scoped_any.h

-//

-//  Contents:   automatic resource management, a-la std::scoped_ptr

-//

-//  Classes:    scoped_any<> and various typedefs

-//

-//  Functions:  get

-//              reset

-//              release

-//              valid

-//              address

-//

-//  Author:     Eric Niebler ( ericne@microsoft.com )

-//

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

-

-#ifndef SCOPED_ANY

-#define SCOPED_ANY

-#include <cassert>

-#include "smart_any_fwd.h"

-

-#pragma warning(push)

-

-// 4284 warning for operator-> returning non-pointer;

-//      compiler issues it even if -> is not used for the specific instance

-#pragma warning(disable: 4284) 

-

-namespace detail

-{

-    // friend function definitions go in scoped_any_helper

-    template<typename T,class close_policy,class invalid_value,int unique>

-    struct scoped_any_helper;

-}

-

-// wrap a resource to enforce strict ownership and ensure proper cleanup

-template<typename T,class close_policy,class invalid_value,int unique>

-class scoped_any

-{

-    // disallow copy and assignment

-    scoped_any( scoped_any<T,close_policy,invalid_value,unique> const & );

-    scoped_any<T,close_policy,invalid_value,unique> & operator=( 

-        scoped_any<T,close_policy,invalid_value,unique> const & );

-

-    // disallow comparison of scoped_any's

-    bool operator==( detail::safe_bool ) const;

-    bool operator!=( detail::safe_bool ) const;

-

-    typedef detail::safe_types<T,close_policy>  safe_types;

-

-public:

-    typedef typename detail::holder<T>::type    element_type;

-    typedef close_policy                        close_policy_type;

-    typedef typename safe_types::pointer_type   pointer_type;

-    typedef typename safe_types::reference_type reference_type;

-

-    // Fix-up the invalid_value type on older compilers

-    typedef typename detail::fixup_invalid_value<invalid_value>::

-        template rebind<T>::type invalid_value_type;

-

-    friend struct detail::scoped_any_helper<T,close_policy,invalid_value,unique>;

-

-    // construct from object pointer

-    explicit scoped_any( T t = invalid_value_type() )

-        : m_t( t )

-    {

-    }

-

-    // destroy the object

-    ~scoped_any()

-    {

-        if( valid() )

-        {

-            close_policy::close( m_t );

-        }

-    }

-

-    // return pointer to class object (assume pointer)

-    pointer_type operator->() const

-    {

-        #ifdef SMART_ANY_PTS

-        // You better not be applying operator-> to a handle!

-        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;

-        #endif

-        assert( valid() );

-        return safe_types::to_pointer( m_t );

-    }

-

-    // for use when scoped_any appears in a conditional

-    operator detail::safe_bool() const

-    {

-        return valid() ? detail::safe_true : detail::safe_false;

-    }

-

-    // for use when scoped_any appears in a conditional

-    bool operator!() const

-    {

-        return ! valid();

-    }

-

-    #ifdef SMART_ANY_PTS

-    // if this scoped_any is managing an array, we can use operator[] to index it

-    typename detail::deref<T>::type operator[]( int i ) const

-    {

-        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;

-        static detail::static_assert<!detail::is_delete<close_policy>::value> const accessed_like_an_array_but_not_deleted_like_an_array;

-        assert( valid() );

-        return m_t[ i ];

-    }

-

-    // unary operator* lets you write code like:

-    // scoped_any<foo*,close_delete> pfoo( new foo );

-    // foo & f = *pfoo;

-    reference_type operator*() const

-    {

-        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;

-        assert( valid() );

-        return smart_types::to_reference( m_t );

-    }

-    #endif

-

-private:

-

-    bool valid() const

-    {

-        // see if the managed resource is in the invalid state.

-        return m_t != static_cast<T>( invalid_value_type() );

-    }

-

-    // the wrapped object

-    element_type m_t;

-};

-

-namespace detail

-{

-    // friend function definitions go in scoped_any_helper

-    template<typename T,class close_policy,class invalid_value,int unique>

-    struct scoped_any_helper

-    {

-        // return wrapped pointer

-        static T get( scoped_any<T,close_policy,invalid_value,unique> const & t )

-        {

-            return t.m_t;

-        }

-

-        // return wrapped pointer and give up ownership

-        static T release( scoped_any<T,close_policy,invalid_value,unique> & t )

-        {

-            // Fix-up the invalid_value type on older compilers

-            typedef typename detail::fixup_invalid_value<invalid_value>::

-                template rebind<T>::type invalid_value_type;

-

-            T tmpT = t.m_t;

-            t.m_t = static_cast<T>( invalid_value_type() );

-            return tmpT;

-        }

-

-        // destroy designated object and store new pointer

-        static void reset( scoped_any<T,close_policy,invalid_value,unique> & t, T newT )

-        {

-            if( t.m_t != newT )

-            {

-                if( t.valid() )

-                {

-                    close_policy::close( t.m_t );

-                }

-                t.m_t = newT;

-            }

-        }

-

-        typedef typename scoped_any<T,close_policy,invalid_value,unique>::element_type element_type;

-

-        // return the address of the wrapped pointer

-        static element_type* address( scoped_any<T,close_policy,invalid_value,unique> & t )

-        {

-            // check to make sure the wrapped object is in the invalid state

-            assert( !t.valid() );

-            return address_of( t.m_t );

-        }

-    };

-}

-

-// return wrapped resource

-template<typename T,class close_policy,class invalid_value,int unique>

-inline T get( scoped_any<T,close_policy,invalid_value,unique> const & t )

-{

-    return detail::scoped_any_helper<T,close_policy,invalid_value,unique>::get( t );

-}

-

-// return true if the scoped_any contains a currently valid resource

-template<typename T,class close_policy,class invalid_value,int unique>

-inline bool valid( scoped_any<T,close_policy,invalid_value,unique> const & t )

-{

-    return t;

-}

-

-// return wrapped resource and give up ownership

-template<typename T,class close_policy,class invalid_value,int unique>

-inline T release( scoped_any<T,close_policy,invalid_value,unique> & t )

-{

-    return detail::scoped_any_helper<T,close_policy,invalid_value,unique>::release( t );

-}

-

-// destroy designated object and store new resource

-template<typename T,class close_policy,class invalid_value,int unique>

-inline void reset( scoped_any<T,close_policy,invalid_value,unique> & t )

-{

-    typedef typename detail::fixup_invalid_value<invalid_value>::

-        template rebind<T>::type invalid_value_type;

-    detail::scoped_any_helper<T,close_policy,invalid_value,unique>::reset( t, invalid_value_type() );

-}

-

-// destroy designated object and store new resource

-template<typename T,class close_policy,class invalid_value,int unique,typename U>

-inline void reset( scoped_any<T,close_policy,invalid_value,unique> & t, U newT )

-{

-    detail::scoped_any_helper<T,close_policy,invalid_value,unique>::reset( t, newT );

-}

-

-// return the address of the wrapped resource

-// WARNING: this will assert if the value of the resource is

-// anything other than invalid_value.

-template<typename T,class close_policy,class invalid_value,int unique>

-inline typename scoped_any<T,close_policy,invalid_value,unique>::element_type* 

-    address( scoped_any<T,close_policy,invalid_value,unique> & t )

-{

-    return detail::scoped_any_helper<T,close_policy,invalid_value,unique>::address( t );

-}

-

-#pragma warning(pop)

-

-#endif

-

-// This causes the scoped_* typedefs to be defined

-DECLARE_SMART_ANY_TYPEDEFS(scoped)

-

-#if defined(_OBJBASE_H_) & !defined(SCOPED_ANY_CO_INIT)

-# define SCOPED_ANY_CO_INIT

-  typedef scoped_any<HRESULT,close_co,co_not_init>                            scoped_co_close;

-

-  // Helper class for balancing calls to CoInitialize and CoUninitialize

-  struct scoped_co_init

-  {

-      explicit scoped_co_init( DWORD dwCoInit = COINIT_APARTMENTTHREADED )

-          : m_hr( smart_co_init_helper( dwCoInit ) )

-      {

-      }

-      HRESULT hresult() const

-      {

-          return get(m_hr);

-      }

-      scoped_co_close const m_hr;

-  };

-#endif

+//+---------------------------------------------------------------------------
+//
+//  Copyright ( C ) Microsoft, 2002.
+//
+//  File:       scoped_any.h
+//
+//  Contents:   automatic resource management, a-la std::scoped_ptr
+//
+//  Classes:    scoped_any<> and various typedefs
+//
+//  Functions:  get
+//              reset
+//              release
+//              valid
+//              address
+//
+//  Author:     Eric Niebler ( ericne@microsoft.com )
+//
+//----------------------------------------------------------------------------
+
+#ifndef SCOPED_ANY
+#define SCOPED_ANY
+#include <cassert>
+#include "smart_any_fwd.h"
+
+#pragma warning(push)
+
+// 4284 warning for operator-> returning non-pointer;
+//      compiler issues it even if -> is not used for the specific instance
+#pragma warning(disable: 4284) 
+
+namespace detail
+{
+    // friend function definitions go in scoped_any_helper
+    template<typename T,class close_policy,class invalid_value,int unique>
+    struct scoped_any_helper;
+}
+
+// wrap a resource to enforce strict ownership and ensure proper cleanup
+template<typename T,class close_policy,class invalid_value,int unique>
+class scoped_any
+{
+    // disallow copy and assignment
+    scoped_any( scoped_any<T,close_policy,invalid_value,unique> const & );
+    scoped_any<T,close_policy,invalid_value,unique> & operator=( 
+        scoped_any<T,close_policy,invalid_value,unique> const & );
+
+    // disallow comparison of scoped_any's
+    bool operator==( detail::safe_bool ) const;
+    bool operator!=( detail::safe_bool ) const;
+
+    typedef detail::safe_types<T,close_policy>  safe_types;
+
+public:
+    typedef typename detail::holder<T>::type    element_type;
+    typedef close_policy                        close_policy_type;
+    typedef typename safe_types::pointer_type   pointer_type;
+    typedef typename safe_types::reference_type reference_type;
+
+    // Fix-up the invalid_value type on older compilers
+    typedef typename detail::fixup_invalid_value<invalid_value>::
+        template rebind<T>::type invalid_value_type;
+
+    friend struct detail::scoped_any_helper<T,close_policy,invalid_value,unique>;
+
+    // construct from object pointer
+    explicit scoped_any( T t = invalid_value_type() )
+        : m_t( t )
+    {
+    }
+
+    // destroy the object
+    ~scoped_any()
+    {
+        if( valid() )
+        {
+            close_policy::close( m_t );
+        }
+    }
+
+    // return pointer to class object (assume pointer)
+    pointer_type operator->() const
+    {
+        #ifdef SMART_ANY_PTS
+        // You better not be applying operator-> to a handle!
+        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;
+        #endif
+        assert( valid() );
+        return safe_types::to_pointer( m_t );
+    }
+
+    // for use when scoped_any appears in a conditional
+    operator detail::safe_bool() const
+    {
+        return valid() ? detail::safe_true : detail::safe_false;
+    }
+
+    // for use when scoped_any appears in a conditional
+    bool operator!() const
+    {
+        return ! valid();
+    }
+
+    #ifdef SMART_ANY_PTS
+    // if this scoped_any is managing an array, we can use operator[] to index it
+    typename detail::deref<T>::type operator[]( int i ) const
+    {
+        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;
+        static detail::static_assert<!detail::is_delete<close_policy>::value> const accessed_like_an_array_but_not_deleted_like_an_array;
+        assert( valid() );
+        return m_t[ i ];
+    }
+
+    // unary operator* lets you write code like:
+    // scoped_any<foo*,close_delete> pfoo( new foo );
+    // foo & f = *pfoo;
+    reference_type operator*() const
+    {
+        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;
+        assert( valid() );
+        return smart_types::to_reference( m_t );
+    }
+    #endif
+
+private:
+
+    bool valid() const
+    {
+        // see if the managed resource is in the invalid state.
+        return m_t != static_cast<T>( invalid_value_type() );
+    }
+
+    // the wrapped object
+    element_type m_t;
+};
+
+namespace detail
+{
+    // friend function definitions go in scoped_any_helper
+    template<typename T,class close_policy,class invalid_value,int unique>
+    struct scoped_any_helper
+    {
+        // return wrapped pointer
+        static T get( scoped_any<T,close_policy,invalid_value,unique> const & t )
+        {
+            return t.m_t;
+        }
+
+        // return wrapped pointer and give up ownership
+        static T release( scoped_any<T,close_policy,invalid_value,unique> & t )
+        {
+            // Fix-up the invalid_value type on older compilers
+            typedef typename detail::fixup_invalid_value<invalid_value>::
+                template rebind<T>::type invalid_value_type;
+
+            T tmpT = t.m_t;
+            t.m_t = static_cast<T>( invalid_value_type() );
+            return tmpT;
+        }
+
+        // destroy designated object and store new pointer
+        static void reset( scoped_any<T,close_policy,invalid_value,unique> & t, T newT )
+        {
+            if( t.m_t != newT )
+            {
+                if( t.valid() )
+                {
+                    close_policy::close( t.m_t );
+                }
+                t.m_t = newT;
+            }
+        }
+
+        typedef typename scoped_any<T,close_policy,invalid_value,unique>::element_type element_type;
+
+        // return the address of the wrapped pointer
+        static element_type* address( scoped_any<T,close_policy,invalid_value,unique> & t )
+        {
+            // check to make sure the wrapped object is in the invalid state
+            assert( !t.valid() );
+            return address_of( t.m_t );
+        }
+    };
+}
+
+// return wrapped resource
+template<typename T,class close_policy,class invalid_value,int unique>
+inline T get( scoped_any<T,close_policy,invalid_value,unique> const & t )
+{
+    return detail::scoped_any_helper<T,close_policy,invalid_value,unique>::get( t );
+}
+
+// return true if the scoped_any contains a currently valid resource
+template<typename T,class close_policy,class invalid_value,int unique>
+inline bool valid( scoped_any<T,close_policy,invalid_value,unique> const & t )
+{
+    return t;
+}
+
+// return wrapped resource and give up ownership
+template<typename T,class close_policy,class invalid_value,int unique>
+inline T release( scoped_any<T,close_policy,invalid_value,unique> & t )
+{
+    return detail::scoped_any_helper<T,close_policy,invalid_value,unique>::release( t );
+}
+
+// destroy designated object and store new resource
+template<typename T,class close_policy,class invalid_value,int unique>
+inline void reset( scoped_any<T,close_policy,invalid_value,unique> & t )
+{
+    typedef typename detail::fixup_invalid_value<invalid_value>::
+        template rebind<T>::type invalid_value_type;
+    detail::scoped_any_helper<T,close_policy,invalid_value,unique>::reset( t, invalid_value_type() );
+}
+
+// destroy designated object and store new resource
+template<typename T,class close_policy,class invalid_value,int unique,typename U>
+inline void reset( scoped_any<T,close_policy,invalid_value,unique> & t, U newT )
+{
+    detail::scoped_any_helper<T,close_policy,invalid_value,unique>::reset( t, newT );
+}
+
+// return the address of the wrapped resource
+// WARNING: this will assert if the value of the resource is
+// anything other than invalid_value.
+template<typename T,class close_policy,class invalid_value,int unique>
+inline typename scoped_any<T,close_policy,invalid_value,unique>::element_type* 
+    address( scoped_any<T,close_policy,invalid_value,unique> & t )
+{
+    return detail::scoped_any_helper<T,close_policy,invalid_value,unique>::address( t );
+}
+
+#pragma warning(pop)
+
+#endif
+
+// This causes the scoped_* typedefs to be defined
+DECLARE_SMART_ANY_TYPEDEFS(scoped)
+
+#if defined(_OBJBASE_H_) & !defined(SCOPED_ANY_CO_INIT)
+# define SCOPED_ANY_CO_INIT
+  typedef scoped_any<HRESULT,close_co,co_not_init>                            scoped_co_close;
+
+  // Helper class for balancing calls to CoInitialize and CoUninitialize
+  struct scoped_co_init
+  {
+      explicit scoped_co_init( DWORD dwCoInit = COINIT_APARTMENTTHREADED )
+          : m_hr( smart_co_init_helper( dwCoInit ) )
+      {
+      }
+      HRESULT hresult() const
+      {
+          return get(m_hr);
+      }
+      scoped_co_close const m_hr;
+  };
+#endif
diff --git a/third_party/smartany/shared_any.cc b/third_party/smartany/shared_any.cc
index 068e196..064001d 100644
--- a/third_party/smartany/shared_any.cc
+++ b/third_party/smartany/shared_any.cc
@@ -1,246 +1,246 @@
-//+---------------------------------------------------------------------------

-//

-//  Copyright ( C ) Microsoft, 2002.

-//

-//  File:       shared_any.cpp

-//

-//  Contents:   pool allocator for reference counts

-//

-//  Classes:    ref_count_allocator and helpers

-//

-//  Functions:

-//

-//  Author:     Eric Niebler ( ericne@microsoft.com )

-//

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

-

-#ifdef _MT

-# ifndef _WIN32_WINNT

-#  define _WIN32_WINNT 0x0403

-# endif

-# include <windows.h>

-# include <unknwn.h>

-#endif

-

-#include <cassert>

-#include <functional>  // for std::less

-#include <algorithm>   // for std::swap

-

-#pragma warning(push)

-// C4640: construction of local static object is not thread-safe

-#pragma warning(disable : 4640)

-#include "shared_any.h"

-#include "scoped_any.h"

-#pragma warning(pop)

-

-namespace detail

-{

-    struct critsec

-    {

-#ifdef _MT

-        CRITICAL_SECTION m_cs;

-

-        critsec()

-        {

-            InitializeCriticalSectionAndSpinCount( &m_cs, 4000 );

-        }

-        ~critsec()

-        {

-            DeleteCriticalSection( &m_cs );

-        }

-        void enter()

-        {

-            EnterCriticalSection( &m_cs );

-        }

-        void leave()

-        {

-            LeaveCriticalSection( &m_cs );

-        }

-#endif

-    };

-

-    namespace

-    {

-        critsec g_critsec;

-    }

-

-    struct lock

-    {

-#ifdef _MT

-        critsec & m_cs;

-

-        explicit lock( critsec & cs )

-            : m_cs(cs)

-        {

-            m_cs.enter();

-        }

-        ~lock()

-        {

-            m_cs.leave();

-        }

-#else

-        explicit lock( critsec & )

-        {

-        }

-#endif

-    private:

-        lock( lock const & );

-        lock & operator=( lock const & );

-    };

-

-    struct ref_count_block

-    {

-        static long const s_sizeBlock = 256;

-

-        short m_free_list; // offset to start of freelist

-        short m_available; // count of refcounts in this block that are available

-        long  m_refcounts[ s_sizeBlock ];

-

-        ref_count_block()

-          : m_free_list(0), m_available(s_sizeBlock)

-        {

-            for( long l=0; l<s_sizeBlock; ++l )

-                m_refcounts[l] = l+1;

-        }

-

-        bool empty() const // throw()

-        {

-            return s_sizeBlock == m_available;

-        }

-

-        bool full() const // throw()

-        {

-            return 0 == m_available;

-        }

-

-        long volatile *alloc( lock & )

-        {

-            assert( 0 != m_available );

-            long *refcount = m_refcounts + m_free_list;

-            m_free_list = static_cast<short>( *refcount );

-            --m_available;

-            return refcount;

-        }

-

-        void free( long volatile *refcount, lock & ) // throw()

-        {

-            assert( owns( refcount ) );

-            *refcount = m_free_list;

-            m_free_list = static_cast<short>( refcount - m_refcounts );

-            ++m_available;

-        }

-

-        bool owns( long volatile *refcount ) const // throw()

-        {

-            return ! std::less<void*>()( const_cast<long*>( refcount ), const_cast<long*>( m_refcounts ) ) &&

-                    std::less<void*>()( const_cast<long*>( refcount ), const_cast<long*>( m_refcounts ) + s_sizeBlock );

-        }

-    };

-

-

-    struct ref_count_allocator::node

-    {

-        node           *m_next;

-        node           *m_prev;

-        ref_count_block m_block;

-        explicit node( node *next=0, node *prev=0 )

-        : m_next(next), m_prev(prev), m_block()

-        {

-            if( m_next )

-                m_next->m_prev = this;

-            if( m_prev )

-                m_prev->m_next = this;

-        }

-    };

-

-

-    ref_count_allocator::ref_count_allocator()

-      : m_list_blocks(0), m_last_alloc(0), m_last_free(0)

-    {

-    }

-

-    ref_count_allocator::~ref_count_allocator()

-    {

-        // Just leak the blocks. It's ok, really.

-        // If you need to clean up the blocks and

-        // you are certain that no refcounts are

-        // outstanding, you can use the finalize()

-        // method to force deallocation

-    }

-

-    void ref_count_allocator::finalize()

-    {

-        lock l( g_critsec );

-        for( node *next; m_list_blocks; m_list_blocks=next )

-        {

-            next = m_list_blocks->m_next;

-            delete m_list_blocks;

-        }

-        m_last_alloc = 0;

-        m_last_free = 0;

-    }

-

-    long volatile *ref_count_allocator::alloc()

-    {

-        lock l( g_critsec );

-        if( ! m_last_alloc || m_last_alloc->m_block.full() )

-        {

-            for( m_last_alloc = m_list_blocks;

-                m_last_alloc && m_last_alloc->m_block.full();

-                m_last_alloc = m_last_alloc->m_next );

-            if( ! m_last_alloc )

-            {

-                m_last_alloc = new( std::nothrow ) node( m_list_blocks );

-                if( ! m_last_alloc )

-                    return 0;

-                m_list_blocks = m_last_alloc;

-            }

-        }

-        return m_last_alloc->m_block.alloc( l );

-    }

-

-    long volatile *ref_count_allocator::alloc( long val )

-    {

-        long volatile *refcount = alloc();

-        *refcount = val;

-        return refcount;

-    }

-

-    void ref_count_allocator::free( long volatile *refcount ) // throw()

-    {

-        // don't rearrange the order of these locals!

-        scoped_any<node*,close_delete> scoped_last_free;

-        lock l( g_critsec );

-

-        if( ! m_last_free || ! m_last_free->m_block.owns( refcount ) )

-        {

-            for( m_last_free = m_list_blocks;

-                m_last_free && ! m_last_free->m_block.owns( refcount );

-                m_last_free = m_last_free->m_next );

-        }

-

-        assert( m_last_free && m_last_free->m_block.owns( refcount ) );

-        m_last_free->m_block.free( refcount, l );

-

-        if( m_last_free != m_list_blocks && m_last_free->m_block.empty() )

-        {

-            if( 0 != ( m_last_free->m_prev->m_next = m_last_free->m_next ) )

-                m_last_free->m_next->m_prev = m_last_free->m_prev;

-

-            if( ! m_list_blocks->m_block.empty() )

-            {

-                m_last_free->m_next = m_list_blocks;

-                m_last_free->m_prev = 0;

-                m_list_blocks->m_prev = m_last_free;

-                m_list_blocks = m_last_free;

-            }

-            else

-                reset( scoped_last_free, m_last_free ); // deleted after critsec is released

-

-            m_last_free = 0;

-        }

-    }

-

-    // Here is the global reference count allocator.

-    ref_count_allocator ref_count_allocator::instance;

-}

+//+---------------------------------------------------------------------------
+//
+//  Copyright ( C ) Microsoft, 2002.
+//
+//  File:       shared_any.cpp
+//
+//  Contents:   pool allocator for reference counts
+//
+//  Classes:    ref_count_allocator and helpers
+//
+//  Functions:
+//
+//  Author:     Eric Niebler ( ericne@microsoft.com )
+//
+//----------------------------------------------------------------------------
+
+#ifdef _MT
+# ifndef _WIN32_WINNT
+#  define _WIN32_WINNT 0x0403
+# endif
+# include <windows.h>
+# include <unknwn.h>
+#endif
+
+#include <cassert>
+#include <functional>  // for std::less
+#include <algorithm>   // for std::swap
+
+#pragma warning(push)
+// C4640: construction of local static object is not thread-safe
+#pragma warning(disable : 4640)
+#include "shared_any.h"
+#include "scoped_any.h"
+#pragma warning(pop)
+
+namespace detail
+{
+    struct critsec
+    {
+#ifdef _MT
+        CRITICAL_SECTION m_cs;
+
+        critsec()
+        {
+            InitializeCriticalSectionAndSpinCount( &m_cs, 4000 );
+        }
+        ~critsec()
+        {
+            DeleteCriticalSection( &m_cs );
+        }
+        void enter()
+        {
+            EnterCriticalSection( &m_cs );
+        }
+        void leave()
+        {
+            LeaveCriticalSection( &m_cs );
+        }
+#endif
+    };
+
+    namespace
+    {
+        critsec g_critsec;
+    }
+
+    struct lock
+    {
+#ifdef _MT
+        critsec & m_cs;
+
+        explicit lock( critsec & cs )
+            : m_cs(cs)
+        {
+            m_cs.enter();
+        }
+        ~lock()
+        {
+            m_cs.leave();
+        }
+#else
+        explicit lock( critsec & )
+        {
+        }
+#endif
+    private:
+        lock( lock const & );
+        lock & operator=( lock const & );
+    };
+
+    struct ref_count_block
+    {
+        static long const s_sizeBlock = 256;
+
+        short m_free_list; // offset to start of freelist
+        short m_available; // count of refcounts in this block that are available
+        long  m_refcounts[ s_sizeBlock ];
+
+        ref_count_block()
+          : m_free_list(0), m_available(s_sizeBlock)
+        {
+            for( long l=0; l<s_sizeBlock; ++l )
+                m_refcounts[l] = l+1;
+        }
+
+        bool empty() const // throw()
+        {
+            return s_sizeBlock == m_available;
+        }
+
+        bool full() const // throw()
+        {
+            return 0 == m_available;
+        }
+
+        long volatile *alloc( lock & )
+        {
+            assert( 0 != m_available );
+            long *refcount = m_refcounts + m_free_list;
+            m_free_list = static_cast<short>( *refcount );
+            --m_available;
+            return refcount;
+        }
+
+        void free( long volatile *refcount, lock & ) // throw()
+        {
+            assert( owns( refcount ) );
+            *refcount = m_free_list;
+            m_free_list = static_cast<short>( refcount - m_refcounts );
+            ++m_available;
+        }
+
+        bool owns( long volatile *refcount ) const // throw()
+        {
+            return ! std::less<void*>()( const_cast<long*>( refcount ), const_cast<long*>( m_refcounts ) ) &&
+                    std::less<void*>()( const_cast<long*>( refcount ), const_cast<long*>( m_refcounts ) + s_sizeBlock );
+        }
+    };
+
+
+    struct ref_count_allocator::node
+    {
+        node           *m_next;
+        node           *m_prev;
+        ref_count_block m_block;
+        explicit node( node *next=0, node *prev=0 )
+        : m_next(next), m_prev(prev), m_block()
+        {
+            if( m_next )
+                m_next->m_prev = this;
+            if( m_prev )
+                m_prev->m_next = this;
+        }
+    };
+
+
+    ref_count_allocator::ref_count_allocator()
+      : m_list_blocks(0), m_last_alloc(0), m_last_free(0)
+    {
+    }
+
+    ref_count_allocator::~ref_count_allocator()
+    {
+        // Just leak the blocks. It's ok, really.
+        // If you need to clean up the blocks and
+        // you are certain that no refcounts are
+        // outstanding, you can use the finalize()
+        // method to force deallocation
+    }
+
+    void ref_count_allocator::finalize()
+    {
+        lock l( g_critsec );
+        for( node *next; m_list_blocks; m_list_blocks=next )
+        {
+            next = m_list_blocks->m_next;
+            delete m_list_blocks;
+        }
+        m_last_alloc = 0;
+        m_last_free = 0;
+    }
+
+    long volatile *ref_count_allocator::alloc()
+    {
+        lock l( g_critsec );
+        if( ! m_last_alloc || m_last_alloc->m_block.full() )
+        {
+            for( m_last_alloc = m_list_blocks;
+                m_last_alloc && m_last_alloc->m_block.full();
+                m_last_alloc = m_last_alloc->m_next );
+            if( ! m_last_alloc )
+            {
+                m_last_alloc = new( std::nothrow ) node( m_list_blocks );
+                if( ! m_last_alloc )
+                    return 0;
+                m_list_blocks = m_last_alloc;
+            }
+        }
+        return m_last_alloc->m_block.alloc( l );
+    }
+
+    long volatile *ref_count_allocator::alloc( long val )
+    {
+        long volatile *refcount = alloc();
+        *refcount = val;
+        return refcount;
+    }
+
+    void ref_count_allocator::free( long volatile *refcount ) // throw()
+    {
+        // don't rearrange the order of these locals!
+        scoped_any<node*,close_delete> scoped_last_free;
+        lock l( g_critsec );
+
+        if( ! m_last_free || ! m_last_free->m_block.owns( refcount ) )
+        {
+            for( m_last_free = m_list_blocks;
+                m_last_free && ! m_last_free->m_block.owns( refcount );
+                m_last_free = m_last_free->m_next );
+        }
+
+        assert( m_last_free && m_last_free->m_block.owns( refcount ) );
+        m_last_free->m_block.free( refcount, l );
+
+        if( m_last_free != m_list_blocks && m_last_free->m_block.empty() )
+        {
+            if( 0 != ( m_last_free->m_prev->m_next = m_last_free->m_next ) )
+                m_last_free->m_next->m_prev = m_last_free->m_prev;
+
+            if( ! m_list_blocks->m_block.empty() )
+            {
+                m_last_free->m_next = m_list_blocks;
+                m_last_free->m_prev = 0;
+                m_list_blocks->m_prev = m_last_free;
+                m_list_blocks = m_last_free;
+            }
+            else
+                reset( scoped_last_free, m_last_free ); // deleted after critsec is released
+
+            m_last_free = 0;
+        }
+    }
+
+    // Here is the global reference count allocator.
+    ref_count_allocator ref_count_allocator::instance;
+}
diff --git a/third_party/smartany/shared_any.h b/third_party/smartany/shared_any.h
index 1e737c2..a6a42f4 100644
--- a/third_party/smartany/shared_any.h
+++ b/third_party/smartany/shared_any.h
@@ -1,412 +1,412 @@
-//+---------------------------------------------------------------------------

-//

-//  Copyright ( C ) Microsoft, 2002.

-//

-//  File:       shared_any.h

-//

-//  Contents:   automatic resource management

-//

-//  Classes:    shared_any<> and various typedefs

-//

-//  Functions:  get

-//              reset

-//              valid

-//

-//  Author:     Eric Niebler ( ericne@microsoft.com )

-//

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

-

-

-#ifndef SHARED_ANY

-#define SHARED_ANY

-

-#include <cassert>

-#include <functional>  // for std::less

-#include <algorithm>   // for std::swap

-#include "smart_any_fwd.h"

-

-namespace detail

-{

-    class ref_count_allocator

-    {

-        struct  node;

-        node   *m_list_blocks;

-        node   *m_last_alloc;

-        node   *m_last_free;

-        

-        ref_count_allocator();

-        ~ref_count_allocator();

-    public:

-        void finalize();

-        long volatile *alloc();

-        long volatile *alloc( long val );

-        void free( long volatile *refcount );

-

-        static ref_count_allocator instance;

-    };

-

-    template<typename T,class close_policy,class invalid_value,int unique>

-    struct shared_any_helper;

-

-    template<typename Super>

-    struct shared_holder : Super

-    {

-        explicit shared_holder( typename Super::type t )

-            : Super( t )

-        {

-        }

-

-        shared_holder( shared_holder const & that )

-            : Super( that )

-        {

-            if( Super::valid() )

-            {

-                Super::inc_ref();

-            }

-        }

-

-        ~shared_holder()

-        {

-            if( Super::valid() )

-            {

-                Super::dec_ref();

-            }

-        }

-    };

-

-    template<typename T,class invalid_value_type>

-    struct intrusive

-    {

-        typedef T type;

-

-        explicit intrusive( T t )

-            : m_t( t )

-        {

-        }

-

-        bool valid() const

-        {

-            return m_t != static_cast<T>( invalid_value_type() );

-        }

-        

-        void inc_ref()

-        {

-            m_t->AddRef();

-        }

-        

-        void dec_ref()

-        {

-            if( 0 == m_t->Release() )

-            {

-                m_t = static_cast<T>( invalid_value_type() );

-            }

-        }

-        

-        T m_t;

-    };

-    

-    template<typename T,class close_policy,class invalid_value_type>

-    struct nonintrusive

-    {

-        typedef T type;

-        

-        explicit nonintrusive( T t )

-            : m_t( t ),

-              m_ref( 0 )

-        {

-            if( valid() )

-            {

-                m_ref = ref_count_allocator::instance.alloc(1L);

-                if( ! m_ref )

-                {

-                    m_t = static_cast<T>( invalid_value_type() );

-                    throw std::bad_alloc();

-                }

-            }

-        }

-        

-        bool valid() const

-        {

-            return m_t != static_cast<T>( invalid_value_type() );

-        }

-        

-        void inc_ref()

-        {

-            ::InterlockedIncrement( m_ref );

-        }

-        

-        void dec_ref()

-        {

-            if( 0L == ::InterlockedDecrement( m_ref ) )

-            {

-                ref_count_allocator::instance.free( m_ref );

-                m_ref = 0;

-                close_policy::close( m_t );

-                m_t = static_cast<T>( invalid_value_type() );

-            }

-        }

-        

-        typename holder<T>::type    m_t;

-        long volatile              *m_ref;

-    };

-

-    template<class close_policy>

-    struct is_close_release_com

-    {

-        static bool const value = false;

-    };

-    template<>

-    struct is_close_release_com<close_release_com>

-    {

-        static bool const value = true;

-    };

-

-    // credit Rani Sharoni for showing me how to implement

-    // is_com_ptr on VC7. This is deeply magical code.

-    template<typename T>

-    struct is_com_ptr

-    {

-    private:

-        struct maybe

-        {

-            operator IUnknown*() const;

-            operator T();

-        };

-

-        template<typename U>

-        static yes    check(T, U);    

-        static no     check(IUnknown*, int);

-        static maybe  get();

-    public:

-        static bool const value = sizeof(check(get(),0)) == sizeof(yes);

-    };

-

-    template<>

-    struct is_com_ptr<IUnknown*>

-    {

-        static bool const value = true;

-    };

-}

-

-template<typename T,class close_policy,class invalid_value,int unique>

-class shared_any

-{

-    typedef detail::safe_types<T,close_policy>  safe_types;

-

-    // disallow comparison of shared_any's

-    bool operator==( detail::safe_bool ) const;

-    bool operator!=( detail::safe_bool ) const;

-

-public:

-    typedef typename detail::holder<T>::type    element_type;

-    typedef close_policy                        close_policy_type;

-    typedef typename safe_types::pointer_type   pointer_type;

-    typedef typename safe_types::reference_type reference_type;

-

-    // Fix-up the invalid_value type on older compilers

-    typedef typename detail::fixup_invalid_value<invalid_value>::

-        template rebind<T>::type invalid_value_type;

-

-    friend struct detail::shared_any_helper<T,close_policy,invalid_value,unique>;

-

-    // default construct

-    shared_any()

-        : m_held( static_cast<T>( invalid_value_type() ) )

-    {

-    }

-

-    // construct from object. If we fail to allocate a reference count,

-    // then the T object is closed, and a bad_alloc exception is thrown.

-    explicit shared_any( T t )

-    try : m_held( t )

-    {

-    }

-    catch( std::bad_alloc & )

-    {

-        close_policy::close( t );

-        throw;

-    }

-

-    // construct from another shared_any, incrementing ref count.

-    // Only throws if T's copy-c'tor throws, in which case, ref-count

-    // is unchanged.

-    shared_any( shared_any<T,close_policy,invalid_value,unique> const & right )

-        : m_held( right.m_held )

-    {

-    }

-

-    // construct from an auto_any, taking ownership. If allocation

-    // fails, auto_any retains ownership.

-    shared_any( auto_any<T,close_policy,invalid_value,unique> & right )

-        : m_held( get( right ) )

-    {

-        release( right );

-    }

-

-    // assign from another shared_any

-    shared_any<T,close_policy,invalid_value,unique> & operator=(

-        shared_any<T,close_policy,invalid_value,unique> const & right )

-    {

-        shared_any<T,close_policy,invalid_value,unique>( right ).swap( *this );

-        return *this;

-    }

-

-    // assign from an auto_any

-    shared_any<T,close_policy,invalid_value,unique> & operator=(

-        auto_any<T,close_policy,invalid_value,unique> & right )

-    {

-        shared_any<T,close_policy,invalid_value,unique>( right ).swap( *this );

-        return *this;

-    }

-

-    operator detail::safe_bool() const

-    {

-        return m_held.valid() ? detail::safe_true : detail::safe_false;

-    }

-

-    bool operator!() const

-    {

-        return ! m_held.valid();

-    }

-

-    // return pointer to class object (assume pointer)

-    pointer_type operator->() const

-    {

-        #ifdef SMART_ANY_PTS

-        // You better not be applying operator-> to a handle!

-        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;

-        #endif

-        assert( m_held.valid() );

-        return safe_types::to_pointer( m_held.m_t );

-    }

-

-    #ifdef SMART_ANY_PTS

-    // if this shared_any is managing an array, we can use operator[] to index it

-    typename detail::deref<T>::type operator[]( int i ) const

-    {

-        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;

-        static detail::static_assert<!detail::is_delete<close_policy>::value> const accessed_like_an_array_but_not_deleted_like_an_array;

-        assert( m_held.valid() );

-        return m_held.m_t[ i ];

-    }

-

-    // unary operator* lets you write code like:

-    // shared_any<foo*,close_delete> pfoo( new foo );

-    // foo & f = *pfoo;

-    reference_type operator*() const

-    {

-        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;

-        assert( m_held.valid() );

-        return safe_types::to_reference( m_held.m_t );

-    }

-    #endif

-

-private:

-

-    void swap( shared_any<T,close_policy,invalid_value,unique> & right )

-    {

-        using std::swap;

-        swap( m_held, right.m_held );

-    }

-

-    // if we are wrapping a COM object, then use COM's reference counting.

-    // otherwise, use our own reference counting.

-    typedef typename detail::select<

-        detail::is_com_ptr<T>::value && detail::is_close_release_com<close_policy>::value,

-        detail::intrusive<T,invalid_value_type>,

-        detail::nonintrusive<T,close_policy,invalid_value_type> >::type holder_policy;

-

-    detail::shared_holder<holder_policy> m_held;

-};

-

-namespace detail

-{

-    template<typename T,class close_policy,class invalid_value,int unique>

-    struct shared_any_helper

-    {

-        static T get( shared_any<T,close_policy,invalid_value,unique> const & t )

-        {

-            return t.m_held.m_t;

-        }

-

-        static void reset( shared_any<T,close_policy,invalid_value,unique> & t, T newT )

-        {

-            shared_any<T,close_policy,invalid_value,unique>( newT ).swap( t );

-        }

-

-        static void swap( shared_any<T,close_policy,invalid_value,unique> & left,

-                          shared_any<T,close_policy,invalid_value,unique> & right )

-        {

-            left.swap( right );

-        }

-    };

-}

-

-// return wrapped resource

-template<typename T,class close_policy,class invalid_value,int unique>

-inline T get( shared_any<T,close_policy,invalid_value,unique> const & t )

-{

-    return detail::shared_any_helper<T,close_policy,invalid_value,unique>::get( t );

-}

-

-// return true if the shared_any contains a currently valid resource

-template<typename T,class close_policy,class invalid_value,int unique>

-inline bool valid( shared_any<T,close_policy,invalid_value,unique> const & t )

-{

-    return t;

-}

-

-// destroy designated object

-template<typename T,class close_policy,class invalid_value,int unique>

-inline void reset( shared_any<T,close_policy,invalid_value,unique> & t )

-{

-    typedef typename detail::fixup_invalid_value<invalid_value>::

-        template rebind<T>::type invalid_value_type;

-    detail::shared_any_helper<T,close_policy,invalid_value,unique>::reset( t, invalid_value_type() );

-}

-

-// destroy designated object and store new resource

-template<typename T,class close_policy,class invalid_value,int unique,typename U>

-inline void reset( shared_any<T,close_policy,invalid_value,unique> & t, U newT )

-{

-    detail::shared_any_helper<T,close_policy,invalid_value,unique>::reset( t, newT );

-}

-

-// swap the contents of two shared_any objects

-template<typename T,class close_policy,class invalid_value,int unique>

-inline void swap( shared_any<T,close_policy,invalid_value,unique> & left, 

-                  shared_any<T,close_policy,invalid_value,unique> & right )

-{

-    detail::shared_any_helper<T,close_policy,invalid_value,unique>::swap( left, right );

-}

-

-// Define some relational operators on shared_* types so they

-// can be used in hashes and maps

-template<typename T,class close_policy,class invalid_value,int unique>

-inline bool operator==(

-    shared_any<T,close_policy,invalid_value,unique> const & left, 

-    shared_any<T,close_policy,invalid_value,unique> const & right )

-{

-    return get( left ) == get( right );

-}

-

-template<typename T,class close_policy,class invalid_value,int unique>

-inline bool operator!=(

-    shared_any<T,close_policy,invalid_value,unique> const & left, 

-    shared_any<T,close_policy,invalid_value,unique> const & right )

-{

-    return get( left ) != get( right );

-}

-

-template<typename T,class close_policy,class invalid_value,int unique>

-inline bool operator<(

-    shared_any<T,close_policy,invalid_value,unique> const & left, 

-    shared_any<T,close_policy,invalid_value,unique> const & right )

-{

-    return std::less<T>( get( left ), get( right ) );

-}

-

-#endif // SHARED_ANY

-

-// This causes the shared_* typedefs to be defined

-DECLARE_SMART_ANY_TYPEDEFS(shared)

+//+---------------------------------------------------------------------------
+//
+//  Copyright ( C ) Microsoft, 2002.
+//
+//  File:       shared_any.h
+//
+//  Contents:   automatic resource management
+//
+//  Classes:    shared_any<> and various typedefs
+//
+//  Functions:  get
+//              reset
+//              valid
+//
+//  Author:     Eric Niebler ( ericne@microsoft.com )
+//
+//----------------------------------------------------------------------------
+
+
+#ifndef SHARED_ANY
+#define SHARED_ANY
+
+#include <cassert>
+#include <functional>  // for std::less
+#include <algorithm>   // for std::swap
+#include "smart_any_fwd.h"
+
+namespace detail
+{
+    class ref_count_allocator
+    {
+        struct  node;
+        node   *m_list_blocks;
+        node   *m_last_alloc;
+        node   *m_last_free;
+        
+        ref_count_allocator();
+        ~ref_count_allocator();
+    public:
+        void finalize();
+        long volatile *alloc();
+        long volatile *alloc( long val );
+        void free( long volatile *refcount );
+
+        static ref_count_allocator instance;
+    };
+
+    template<typename T,class close_policy,class invalid_value,int unique>
+    struct shared_any_helper;
+
+    template<typename Super>
+    struct shared_holder : Super
+    {
+        explicit shared_holder( typename Super::type t )
+            : Super( t )
+        {
+        }
+
+        shared_holder( shared_holder const & that )
+            : Super( that )
+        {
+            if( Super::valid() )
+            {
+                Super::inc_ref();
+            }
+        }
+
+        ~shared_holder()
+        {
+            if( Super::valid() )
+            {
+                Super::dec_ref();
+            }
+        }
+    };
+
+    template<typename T,class invalid_value_type>
+    struct intrusive
+    {
+        typedef T type;
+
+        explicit intrusive( T t )
+            : m_t( t )
+        {
+        }
+
+        bool valid() const
+        {
+            return m_t != static_cast<T>( invalid_value_type() );
+        }
+        
+        void inc_ref()
+        {
+            m_t->AddRef();
+        }
+        
+        void dec_ref()
+        {
+            if( 0 == m_t->Release() )
+            {
+                m_t = static_cast<T>( invalid_value_type() );
+            }
+        }
+        
+        T m_t;
+    };
+    
+    template<typename T,class close_policy,class invalid_value_type>
+    struct nonintrusive
+    {
+        typedef T type;
+        
+        explicit nonintrusive( T t )
+            : m_t( t ),
+              m_ref( 0 )
+        {
+            if( valid() )
+            {
+                m_ref = ref_count_allocator::instance.alloc(1L);
+                if( ! m_ref )
+                {
+                    m_t = static_cast<T>( invalid_value_type() );
+                    throw std::bad_alloc();
+                }
+            }
+        }
+        
+        bool valid() const
+        {
+            return m_t != static_cast<T>( invalid_value_type() );
+        }
+        
+        void inc_ref()
+        {
+            ::InterlockedIncrement( m_ref );
+        }
+        
+        void dec_ref()
+        {
+            if( 0L == ::InterlockedDecrement( m_ref ) )
+            {
+                ref_count_allocator::instance.free( m_ref );
+                m_ref = 0;
+                close_policy::close( m_t );
+                m_t = static_cast<T>( invalid_value_type() );
+            }
+        }
+        
+        typename holder<T>::type    m_t;
+        long volatile              *m_ref;
+    };
+
+    template<class close_policy>
+    struct is_close_release_com
+    {
+        static bool const value = false;
+    };
+    template<>
+    struct is_close_release_com<close_release_com>
+    {
+        static bool const value = true;
+    };
+
+    // credit Rani Sharoni for showing me how to implement
+    // is_com_ptr on VC7. This is deeply magical code.
+    template<typename T>
+    struct is_com_ptr
+    {
+    private:
+        struct maybe
+        {
+            operator IUnknown*() const;
+            operator T();
+        };
+
+        template<typename U>
+        static yes    check(T, U);    
+        static no     check(IUnknown*, int);
+        static maybe  get();
+    public:
+        static bool const value = sizeof(check(get(),0)) == sizeof(yes);
+    };
+
+    template<>
+    struct is_com_ptr<IUnknown*>
+    {
+        static bool const value = true;
+    };
+}
+
+template<typename T,class close_policy,class invalid_value,int unique>
+class shared_any
+{
+    typedef detail::safe_types<T,close_policy>  safe_types;
+
+    // disallow comparison of shared_any's
+    bool operator==( detail::safe_bool ) const;
+    bool operator!=( detail::safe_bool ) const;
+
+public:
+    typedef typename detail::holder<T>::type    element_type;
+    typedef close_policy                        close_policy_type;
+    typedef typename safe_types::pointer_type   pointer_type;
+    typedef typename safe_types::reference_type reference_type;
+
+    // Fix-up the invalid_value type on older compilers
+    typedef typename detail::fixup_invalid_value<invalid_value>::
+        template rebind<T>::type invalid_value_type;
+
+    friend struct detail::shared_any_helper<T,close_policy,invalid_value,unique>;
+
+    // default construct
+    shared_any()
+        : m_held( static_cast<T>( invalid_value_type() ) )
+    {
+    }
+
+    // construct from object. If we fail to allocate a reference count,
+    // then the T object is closed, and a bad_alloc exception is thrown.
+    explicit shared_any( T t )
+    try : m_held( t )
+    {
+    }
+    catch( std::bad_alloc & )
+    {
+        close_policy::close( t );
+        throw;
+    }
+
+    // construct from another shared_any, incrementing ref count.
+    // Only throws if T's copy-c'tor throws, in which case, ref-count
+    // is unchanged.
+    shared_any( shared_any<T,close_policy,invalid_value,unique> const & right )
+        : m_held( right.m_held )
+    {
+    }
+
+    // construct from an auto_any, taking ownership. If allocation
+    // fails, auto_any retains ownership.
+    shared_any( auto_any<T,close_policy,invalid_value,unique> & right )
+        : m_held( get( right ) )
+    {
+        release( right );
+    }
+
+    // assign from another shared_any
+    shared_any<T,close_policy,invalid_value,unique> & operator=(
+        shared_any<T,close_policy,invalid_value,unique> const & right )
+    {
+        shared_any<T,close_policy,invalid_value,unique>( right ).swap( *this );
+        return *this;
+    }
+
+    // assign from an auto_any
+    shared_any<T,close_policy,invalid_value,unique> & operator=(
+        auto_any<T,close_policy,invalid_value,unique> & right )
+    {
+        shared_any<T,close_policy,invalid_value,unique>( right ).swap( *this );
+        return *this;
+    }
+
+    operator detail::safe_bool() const
+    {
+        return m_held.valid() ? detail::safe_true : detail::safe_false;
+    }
+
+    bool operator!() const
+    {
+        return ! m_held.valid();
+    }
+
+    // return pointer to class object (assume pointer)
+    pointer_type operator->() const
+    {
+        #ifdef SMART_ANY_PTS
+        // You better not be applying operator-> to a handle!
+        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;
+        #endif
+        assert( m_held.valid() );
+        return safe_types::to_pointer( m_held.m_t );
+    }
+
+    #ifdef SMART_ANY_PTS
+    // if this shared_any is managing an array, we can use operator[] to index it
+    typename detail::deref<T>::type operator[]( int i ) const
+    {
+        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;
+        static detail::static_assert<!detail::is_delete<close_policy>::value> const accessed_like_an_array_but_not_deleted_like_an_array;
+        assert( m_held.valid() );
+        return m_held.m_t[ i ];
+    }
+
+    // unary operator* lets you write code like:
+    // shared_any<foo*,close_delete> pfoo( new foo );
+    // foo & f = *pfoo;
+    reference_type operator*() const
+    {
+        static detail::static_assert<!detail::is_handle<T>::value> const cannot_dereference_a_handle;
+        assert( m_held.valid() );
+        return safe_types::to_reference( m_held.m_t );
+    }
+    #endif
+
+private:
+
+    void swap( shared_any<T,close_policy,invalid_value,unique> & right )
+    {
+        using std::swap;
+        swap( m_held, right.m_held );
+    }
+
+    // if we are wrapping a COM object, then use COM's reference counting.
+    // otherwise, use our own reference counting.
+    typedef typename detail::select<
+        detail::is_com_ptr<T>::value && detail::is_close_release_com<close_policy>::value,
+        detail::intrusive<T,invalid_value_type>,
+        detail::nonintrusive<T,close_policy,invalid_value_type> >::type holder_policy;
+
+    detail::shared_holder<holder_policy> m_held;
+};
+
+namespace detail
+{
+    template<typename T,class close_policy,class invalid_value,int unique>
+    struct shared_any_helper
+    {
+        static T get( shared_any<T,close_policy,invalid_value,unique> const & t )
+        {
+            return t.m_held.m_t;
+        }
+
+        static void reset( shared_any<T,close_policy,invalid_value,unique> & t, T newT )
+        {
+            shared_any<T,close_policy,invalid_value,unique>( newT ).swap( t );
+        }
+
+        static void swap( shared_any<T,close_policy,invalid_value,unique> & left,
+                          shared_any<T,close_policy,invalid_value,unique> & right )
+        {
+            left.swap( right );
+        }
+    };
+}
+
+// return wrapped resource
+template<typename T,class close_policy,class invalid_value,int unique>
+inline T get( shared_any<T,close_policy,invalid_value,unique> const & t )
+{
+    return detail::shared_any_helper<T,close_policy,invalid_value,unique>::get( t );
+}
+
+// return true if the shared_any contains a currently valid resource
+template<typename T,class close_policy,class invalid_value,int unique>
+inline bool valid( shared_any<T,close_policy,invalid_value,unique> const & t )
+{
+    return t;
+}
+
+// destroy designated object
+template<typename T,class close_policy,class invalid_value,int unique>
+inline void reset( shared_any<T,close_policy,invalid_value,unique> & t )
+{
+    typedef typename detail::fixup_invalid_value<invalid_value>::
+        template rebind<T>::type invalid_value_type;
+    detail::shared_any_helper<T,close_policy,invalid_value,unique>::reset( t, invalid_value_type() );
+}
+
+// destroy designated object and store new resource
+template<typename T,class close_policy,class invalid_value,int unique,typename U>
+inline void reset( shared_any<T,close_policy,invalid_value,unique> & t, U newT )
+{
+    detail::shared_any_helper<T,close_policy,invalid_value,unique>::reset( t, newT );
+}
+
+// swap the contents of two shared_any objects
+template<typename T,class close_policy,class invalid_value,int unique>
+inline void swap( shared_any<T,close_policy,invalid_value,unique> & left, 
+                  shared_any<T,close_policy,invalid_value,unique> & right )
+{
+    detail::shared_any_helper<T,close_policy,invalid_value,unique>::swap( left, right );
+}
+
+// Define some relational operators on shared_* types so they
+// can be used in hashes and maps
+template<typename T,class close_policy,class invalid_value,int unique>
+inline bool operator==(
+    shared_any<T,close_policy,invalid_value,unique> const & left, 
+    shared_any<T,close_policy,invalid_value,unique> const & right )
+{
+    return get( left ) == get( right );
+}
+
+template<typename T,class close_policy,class invalid_value,int unique>
+inline bool operator!=(
+    shared_any<T,close_policy,invalid_value,unique> const & left, 
+    shared_any<T,close_policy,invalid_value,unique> const & right )
+{
+    return get( left ) != get( right );
+}
+
+template<typename T,class close_policy,class invalid_value,int unique>
+inline bool operator<(
+    shared_any<T,close_policy,invalid_value,unique> const & left, 
+    shared_any<T,close_policy,invalid_value,unique> const & right )
+{
+    return std::less<T>( get( left ), get( right ) );
+}
+
+#endif // SHARED_ANY
+
+// This causes the shared_* typedefs to be defined
+DECLARE_SMART_ANY_TYPEDEFS(shared)
diff --git a/third_party/smartany/smart_any_fwd.h b/third_party/smartany/smart_any_fwd.h
index d9552a9..17e2571 100644
--- a/third_party/smartany/smart_any_fwd.h
+++ b/third_party/smartany/smart_any_fwd.h
@@ -1,1053 +1,1053 @@
-//+---------------------------------------------------------------------------

-//

-//  Copyright ( C ) Microsoft, 2002.

-//

-//  File:       smart_any_fwd.h

-//

-//  Contents:   automatic resource management

-//

-//  Classes:    auto_any, scoped_any and shared_any

-//

-//  Functions:  get

-//              reset

-//              release

-//              valid

-//              address

-//

-//  Author:     Eric Niebler ( ericne@microsoft.com )

-//

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

-

-#ifndef SMART_ANY_FWD

-#define SMART_ANY_FWD

-

-#ifdef _MANAGED

-#pragma warning( push )

-#pragma warning( disable : 4244 )

-#include <vcclr.h>

-#pragma warning( pop )

-#endif

-

-// Check to see if partial template specialization is available

-#if _MSC_VER >= 1310

-#define SMART_ANY_PTS

-#endif

-

-// forward declare some invalid_value policy classes

-struct null_t;

-

-template<typename T,T value = T(0)>

-struct value_const;

-

-struct close_release_com;

-

-//

-// TEMPLATE CLASS auto_any

-//

-template<typename T,class close_policy,class invalid_value = null_t,int unique = 0>

-class auto_any;

-

-// return wrapped resource

-template<typename T,class close_policy,class invalid_value,int unique>

-T  get( auto_any<T,close_policy,invalid_value,unique> const & t );

-

-// return true if the auto_any contains a currently valid resource

-template<typename T,class close_policy,class invalid_value,int unique>

-bool valid( auto_any<T,close_policy,invalid_value,unique> const & t );

-

-// return wrapped resource and give up ownership

-template<typename T,class close_policy,class invalid_value,int unique>

-T release( auto_any<T,close_policy,invalid_value, unique> & t );

-

-// destroy designated object

-template<typename T,class close_policy,class invalid_value,int unique>

-void reset( auto_any<T,close_policy,invalid_value,unique> & t );

-

-// destroy designated object and store new resource

-template<typename T,class close_policy,class invalid_value,int unique,typename U>

-void reset( auto_any<T,close_policy,invalid_value,unique> & t, U newT );

-

-// swap the contents of two shared_any objects

-template<typename T,class close_policy,class invalid_value,int unique>

-void swap( auto_any<T,close_policy,invalid_value,unique> & left,

-           auto_any<T,close_policy,invalid_value,unique> & right );

-

-// return the address of the wrapped resource

-// WARNING: this will assert if the value of the resource is

-// anything other than invalid_value.

-//template<typename T,class close_policy,class invalid_value,int unique>

-//T* address( auto_any<T,close_policy,invalid_value,unique> & t );

-

-//

-// TEMPLATE CLASS shared_any

-//

-template<typename T,class close_policy,class invalid_value = null_t,int unique = 0>

-class shared_any;

-

-// return wrapped resource

-template<typename T,class close_policy,class invalid_value,int unique>

-T  get( shared_any<T,close_policy,invalid_value,unique> const & t );

-

-// return true if the auto_any contains a currently valid resource

-template<typename T,class close_policy,class invalid_value,int unique>

-bool valid( shared_any<T,close_policy,invalid_value,unique> const & t );

-

-// destroy designated object

-template<typename T,class close_policy,class invalid_value,int unique>

-void reset( shared_any<T,close_policy,invalid_value,unique> & t );

-

-// destroy designated object and store new resource

-template<typename T,class close_policy,class invalid_value,int unique,typename U>

-void reset( shared_any<T,close_policy,invalid_value,unique> & t, U newT );

-

-// swap the contents of two shared_any objects

-template<typename T,class close_policy,class invalid_value,int unique>

-void swap( shared_any<T,close_policy,invalid_value,unique> & left,

-           shared_any<T,close_policy,invalid_value,unique> & right );

-

-

-//

-// TEMPLATE CLASS scoped_any

-//

-template<typename T,class close_policy,class invalid_value = null_t,int unique = 0>

-class scoped_any;

-

-// return wrapped resource

-template<typename T,class close_policy,class invalid_value,int unique>

-T  get( scoped_any<T,close_policy,invalid_value,unique> const & t );

-

-// return true if the auto_any contains a currently valid resource

-template<typename T,class close_policy,class invalid_value,int unique>

-bool valid( scoped_any<T,close_policy,invalid_value,unique> const & t );

-

-// return wrapped resource and give up ownership

-template<typename T,class close_policy,class invalid_value,int unique>

-T release( scoped_any<T,close_policy,invalid_value, unique> & t );

-

-// destroy designated object

-template<typename T,class close_policy,class invalid_value,int unique>

-void reset( scoped_any<T,close_policy,invalid_value,unique> & t );

-

-// destroy designated object and store new resource

-template<typename T,class close_policy,class invalid_value,int unique,typename U>

-void reset( scoped_any<T,close_policy,invalid_value,unique> & t, U newT );

-

-// return the address of the wrapped resource

-// WARNING: this will assert if the value of the resource is

-// anything other than invalid_value.

-//template<typename T,class close_policy,class invalid_value,int unique>

-//T* address( scoped_any<T,close_policy,invalid_value,unique> & t );

-

-// close policy for objects allocated with new

-struct close_delete;

-

-namespace detail

-{

-    typedef char (&yes)[1];

-    typedef char (&no) [2];

-

-    struct dummy_struct

-    {

-        void dummy_method() {}

-    };

-

-    typedef void (dummy_struct::*safe_bool)();

-    safe_bool const safe_true  = &dummy_struct::dummy_method;

-    safe_bool const safe_false = 0;

-

-    // Because of older compilers, we can't always use

-    // null_t when we would like to.

-    template<class invalid_value>

-    struct fixup_invalid_value

-    {

-        template<typename> struct rebind { typedef invalid_value type; };

-    };

-

-    // for compile-time assertions

-    template<bool>

-    struct static_assert;

-

-    template<>

-    struct static_assert<true>

-    {

-        static_assert() {}

-    };

-

-    template<typename T>

-    struct static_init

-    {

-        static T const value;

-    };

-

-    template<typename T>

-    T const static_init<T>::value = T();

-

-    template<bool>

-    struct null_helper // unmanaged

-    {

-        template<typename T>

-        struct inner

-        {

-            static T const get()

-            {

-                return static_init<T>::value;

-            }

-        };

-    };

-

-    template<>

-    struct null_helper<true> // managed

-    {

-        template<typename T>

-        struct inner

-        {

-            static T const get()

-            {

-                return 0;

-            }

-        };

-    };

-

-    typedef char (&yes_t)[1];

-    typedef char (& no_t)[2];

-

-    template<bool>

-    struct select_helper

-    {

-        template<typename T,typename>

-        struct inner { typedef T type; };

-    };

-

-    template<>

-    struct select_helper<false>

-    {

-        template<typename,typename U>

-        struct inner { typedef U type; };

-    };

-

-    template<bool F,typename T,typename U>

-    struct select

-    {

-        typedef typename select_helper<F>::template inner<T,U>::type type;

-    };

-

-

-    template< bool >

-    struct holder_helper

-    {

-        template<typename T>

-        struct inner

-        {

-            typedef T type;

-        };

-    };

-

-    template< typename T >

-    struct remove_ref

-    {

-        typedef T type;

-    };

-

-    #ifdef SMART_ANY_PTS

-    template< typename T >

-    struct remove_ref<T&>

-    {

-        typedef T type;

-    };

-    #endif

-

-    template<typename T>

-    T* address_of( T & v )

-    {

-        return reinterpret_cast<T*>(

-            &const_cast<char&>(

-                reinterpret_cast<char const volatile &>(v)));

-    }

-

-    #ifndef _MANAGED

-

-    template<typename T>

-    struct is_managed

-    {

-        static bool const value = false;

-    };

-

-    #else

-

-    struct managed_convertible

-    {

-        managed_convertible( System::Object const volatile __gc* );

-        managed_convertible( System::Enum const volatile __gc* );

-        managed_convertible( System::ValueType const volatile __gc* );

-        managed_convertible( System::Delegate const volatile __gc* );

-    };

-

-    template<typename T>

-    struct is_managed

-    {

-    private:

-        static yes_t check( managed_convertible );

-        static no_t __cdecl check( ... );

-        static typename remove_ref<T>::type & make();

-    public:

-        static bool const value = sizeof( yes_t ) == sizeof( check( make() ) );

-    };

-

-    #ifdef SMART_ANY_PTS

-    template<typename T>

-    struct is_managed<T __gc&>

-    {

-        static bool const value = true;

-    };

-    template<typename T>

-    struct is_managed<T __gc*>

-    {

-        static bool const value = true;

-    };

-    template<typename T>

-    struct is_managed<T __gc*const>

-    {

-        static bool const value = is_managed<T __gc*>::value;

-    };

-    template<typename T>

-    struct is_managed<T __gc*volatile>

-    {

-        static bool const value = is_managed<T __gc*>::value;

-    };

-    template<typename T>

-    struct is_managed<T __gc*const volatile>

-    {

-        static bool const value = is_managed<T __gc*>::value;

-    };

-    #endif

-    template<>

-    struct is_managed<System::Void __gc*>

-    {

-        static bool const value = true;

-    };

-    template<>

-    struct is_managed<System::Void const __gc*>

-    {

-        static bool const value = true;

-    };

-    template<>

-    struct is_managed<System::Void volatile __gc*>

-    {

-        static bool const value = true;

-    };

-    template<>

-    struct is_managed<System::Void const volatile __gc*>

-    {

-        static bool const value = true;

-    };

-

-    template<>

-    struct holder_helper<true>

-    {

-        template<typename T>

-        struct inner

-        {

-            typedef gcroot<T> type;

-        };

-    };

-    #endif

-

-    template<typename T>

-    struct holder

-    {

-        typedef typename holder_helper<is_managed<T>::value>::template inner<T>::type type;

-    };

-

-    template<typename T>

-    struct is_delete

-    {

-        static bool const value = false;

-    };

-

-    template<>

-    struct is_delete<close_delete>

-    {

-        static bool const value = true;

-    };

-

-    // dummy type, don't define

-    struct smart_any_cannot_dereference;

-

-    // For use in implementing unary operator*

-    template<typename T>

-    struct deref

-    {

-        typedef smart_any_cannot_dereference type; // will cause a compile error by default

-    };

-

-    #ifndef SMART_ANY_PTS

-

-    // Old compiler needs extra help

-    template<>

-    struct fixup_invalid_value<null_t>

-    {

-        template<typename T> struct rebind { typedef value_const<T> type; };

-    };

-

-    #else

-

-    template<typename T,typename U>

-    struct same_type

-    {

-        static const bool value = false;

-    };

-

-    template<typename T>

-    struct same_type<T,T>

-    {

-        static const bool value = true;

-    };

-

-    // Handle reference types

-    template<typename T>

-    struct deref<T&>

-    {

-        typedef typename deref<T>::type type;

-    };

-

-    // Partially specialize for pointer types

-    template<typename T>

-    struct deref<T*>

-    {

-        typedef T& type; // The result of dereferencing a T*

-    };

-

-    // Partially specialize for pointer types

-    template<typename T>

-    struct deref<T*const>

-    {

-        typedef typename deref<T*>::type type; // The result of dereferencing a T*

-    };

-

-    // Partially specialize for pointer types

-    template<typename T>

-    struct deref<T*volatile>

-    {

-        typedef typename deref<T*>::type type; // The result of dereferencing a T*

-    };

-

-    // Partially specialize for pointer types

-    template<typename T>

-    struct deref<T*const volatile>

-    {

-        typedef typename deref<T*>::type type; // The result of dereferencing a T*

-    };

-

-    // Fully specialize for void*

-    template<>

-    struct deref<void*>

-    {

-        typedef smart_any_cannot_dereference type; // cannot dereference a void*

-    };

-

-    // Fully specialize for void const*

-    template<>

-    struct deref<void const*>

-    {

-        typedef smart_any_cannot_dereference type; // cannot dereference a void*

-    };

-

-    // Fully specialize for void volatile*

-    template<>

-    struct deref<void volatile*>

-    {

-        typedef smart_any_cannot_dereference type; // cannot dereference a void*

-    };

-

-    // Fully specialize for void const volatile*

-    template<>

-    struct deref<void const volatile*>

-    {

-        typedef smart_any_cannot_dereference type; // cannot dereference a void*

-    };

-

-    #ifdef _MANAGED

-    // Handle reference types

-    template<typename T>

-    struct deref<T __gc&>

-    {

-        typedef typename deref<T>::type type;

-    };

-

-    // Partially specialize for pointer types

-    template<typename T>

-    struct deref<T __gc*>

-    {

-        typedef T __gc& type; // The result of dereferencing a T __gc*

-    };

-

-    // Partially specialize for pointer types

-    template<typename T>

-    struct deref<T __gc*const>

-    {

-        typedef typename deref<T __gc*>::type type; // The result of dereferencing a T __gc*

-    };

-

-    // Partially specialize for pointer types

-    template<typename T>

-    struct deref<T __gc*volatile>

-    {

-        typedef typename deref<T __gc*>::type type; // The result of dereferencing a T __gc*

-    };

-

-    // Partially specialize for pointer types

-    template<typename T>

-    struct deref<T __gc*const volatile>

-    {

-        typedef typename deref<T __gc*>::type type; // The result of dereferencing a T __gc*

-    };

-

-    // Fully specialize for void*

-    template<>

-    struct deref<System::Void __gc*>

-    {

-        typedef smart_any_cannot_dereference type; // cannot dereference a System::Void __gc*

-    };

-

-    // Fully specialize for void const*

-    template<>

-    struct deref<System::Void const __gc*>

-    {

-        typedef smart_any_cannot_dereference type; // cannot dereference a System::Void __gc*

-    };

-

-    // Fully specialize for void volatile*

-    template<>

-    struct deref<System::Void volatile __gc*>

-    {

-        typedef smart_any_cannot_dereference type; // cannot dereference a System::Void __gc*

-    };

-

-    // Fully specialize for void const volatile*

-    template<>

-    struct deref<System::Void const volatile __gc*>

-    {

-        typedef smart_any_cannot_dereference type; // cannot dereference a System::Void __gc*

-    };

-    #endif

-

-    // The DECLARE_HANDLE macro in winnt.h defines a handle to be a pointer

-    // to a struct containing one member named "unused" of type int. We can

-    // use that information to make auto_any safer by disallowing actions like

-    // dereferencing a handle or calling delete on a handle.

-    template<typename T>

-    struct has_unused

-    {

-    private:

-        template<class U,int U::*> struct wrap_t;

-        template<typename U> static yes_t check( wrap_t<U,&U::unused>* );

-        template<typename U> static no_t  __cdecl check( ... );

-    public:

-        static bool const value = ( sizeof(check<T>(0)) == sizeof(yes_t) );

-    };

-

-    template<typename T>

-    struct is_handle_helper

-    {

-        static bool const value = ( sizeof(T)==sizeof(int) && has_unused<T>::value );

-    };

-

-    #ifdef _MANAGED

-    template<typename T>

-    struct is_handle_helper<T __gc&>

-    {

-        static bool const value = false;

-    };

-    #endif

-

-    template<>

-    struct is_handle_helper<smart_any_cannot_dereference>

-    {

-        static bool const value = false;

-    };

-

-    // used to see whether a given type T is a handle type or not.

-    template<typename T>

-    struct is_handle

-    {

-    private:

-        typedef typename remove_ref<typename deref<T>::type>::type deref_t;

-    public:

-        static bool const value =

-            ( same_type<T,void*>::value || is_handle_helper<deref_t>::value );

-    };

-    #endif

-

-    template<typename T,class close_policy>

-    struct safe_types

-    {

-        typedef T pointer_type;

-        typedef typename deref<T>::type reference_type;

-

-        static pointer_type to_pointer( T t )

-        {

-            return t;

-        }

-        static reference_type to_reference( T t )

-        {

-            return *t;

-        }

-    };

-

-    #ifdef SMART_ANY_PTS

-    template<typename T>

-    class no_addref_release : public T

-    {

-        unsigned long __stdcall AddRef();

-        unsigned long __stdcall Release();

-    };

-

-    // shouldn't be able to call AddRef or Release

-    // through a smart COM wrapper

-    template<typename T>

-    struct safe_types<T*,close_release_com>

-    {

-        typedef no_addref_release<T>* pointer_type;

-        typedef no_addref_release<T>& reference_type;

-

-        static pointer_type to_pointer( T* t )

-        {

-            return static_cast<pointer_type>( t );

-        }

-        static reference_type to_reference( T* t )

-        {

-            return *static_cast<pointer_type>( t );

-        }

-    };

-    #endif

-}

-

-// a generic close policy that uses a ptr to a function

-template<typename Fn, Fn Pfn>

-struct close_fun

-{

-    template<typename T>

-    static void close( T t )

-    {

-        Pfn( t );

-    }

-};

-

-// free an object allocated with new by calling delete

-struct close_delete

-{

-    template<typename T>

-    static void close( T * p )

-    {

-        // This will fail only if T is an incomplete type.

-        static detail::static_assert<0 != sizeof( T )> const cannot_delete_an_incomplete_type;

-

-        #ifdef SMART_ANY_PTS

-        // This checks to make sure we're not calling delete on a HANDLE

-        static detail::static_assert<!detail::is_handle<T*>::value> const cannot_delete_a_handle;

-        #endif

-

-        delete p;

-    }

-

-    #ifdef _MANAGED

-    template<typename T>

-    static void close( gcroot<T __gc*> const & p )

-    {

-        delete static_cast<T __gc*>( p );

-    }

-    #endif

-};

-

-// free an array allocated with new[] by calling delete[]

-struct close_delete_array

-{

-    template<typename T>

-    static void close( T * p )

-    {

-        // This will fail only if T is an incomplete type.

-        static detail::static_assert<0 != sizeof( T )> const cannot_delete_an_incomplete_type;

-

-        #ifdef SMART_ANY_PTS

-        // This checks to make sure we're not calling delete on a HANDLE

-        static detail::static_assert<!detail::is_handle<T*>::value> const cannot_delete_a_handle;

-        #endif

-

-        delete [] p;

-    }

-

-    //#ifdef _MANAGED

-    // This is broken because of compiler bugs

-    //template<typename T>

-    //static void close( gcroot<T __gc* __gc[]> const & p )

-    //{

-    //    delete [] static_cast<T __gc* __gc[]>( p );

-    //}

-    //#endif

-};

-

-// for releasing a COM object

-struct close_release_com

-{

-    template<typename T>

-    static void close( T p )

-    {

-        p->Release();

-    }

-};

-

-// for releasing a __gc IDisposable object

-struct close_dispose

-{

-    template<typename T>

-    static void close( T p )

-    {

-        p->Dispose();

-    }

-};

-

-// some generic invalid_value policies

-

-struct null_t

-{

-    template<typename T>

-    operator T const() const

-    {

-        return detail::null_helper<detail::is_managed<T>::value>::template inner<T>::get();

-    }

-};

-

-template<typename T,T value>

-struct value_const

-{

-    operator T const() const

-    {

-        return value;

-    }

-};

-

-template<typename T,T const* value_ptr>

-struct value_const_ptr

-{

-    operator T const&() const

-    {

-        return *value_ptr;

-    }

-};

-

-#ifdef SMART_ANY_PTS

-template<typename T, T const& value>

-struct value_ref

-{

-    operator T const&() const

-    {

-        return value;

-    }

-};

-#endif

-

-#endif // SMART_ANY_FWD

-

-

-//

-// Define some other useful close polcies

-//

-

-#if defined(_INC_STDLIB) | defined(_INC_MALLOC)

-typedef void (__cdecl *pfn_free_t)( void* );

-typedef close_fun<pfn_free_t,static_cast<pfn_free_t>(&free)>                close_free;

-#endif

-

-#if defined(_INC_STDIO) & !defined(SMART_CLOSE_FILE_PTR)

-# define SMART_CLOSE_FILE_PTR

-  // don't close a FILE* if it is stdin, stdout or stderr

-  struct close_file_ptr

-  {

-      static void close( FILE * pfile )

-      {

-          if( pfile != stdin && pfile != stdout && pfile != stderr )

-          {

-              fclose( pfile );

-          }

-      }

-  };

-#endif

-

-#ifdef _WINDOWS_

-

-# ifndef SMART_VIRTUAL_FREE

-# define SMART_VIRTUAL_FREE

-  // free memory allocated with VirtualAlloc

-  struct close_virtual_free

-  {

-      static void close( void * p )

-      {

-          ::VirtualFree( p, 0, MEM_RELEASE );

-      }

-  };

-# endif

-

-  typedef close_fun<BOOL (__stdcall *)( HANDLE ),CloseHandle>               close_handle;

-  typedef close_fun<BOOL (__stdcall *)( HANDLE ),FindClose>                 close_find;

-  typedef close_fun<BOOL (__stdcall *)( HANDLE ),FindCloseChangeNotification> close_find_change_notification;

-  typedef close_fun<BOOL (__stdcall *)( HINSTANCE ),FreeLibrary>            close_library;

-  typedef close_fun<LONG (__stdcall *)( HKEY ),RegCloseKey>                 close_regkey;

-  typedef close_fun<BOOL (__stdcall *)( LPCVOID ),UnmapViewOfFile>          close_file_view;

-  typedef close_fun<BOOL (__stdcall *)( HICON ),DestroyIcon>                close_hicon;

-  typedef close_fun<BOOL (__stdcall *)( HGDIOBJ ),DeleteObject>             close_hgdiobj;

-  typedef close_fun<BOOL (__stdcall *)( HACCEL ),DestroyAcceleratorTable>   close_haccel;

-  typedef close_fun<BOOL (__stdcall *)( HDC ),DeleteDC>                     close_hdc;

-  typedef close_fun<BOOL (__stdcall *)( HMENU ),DestroyMenu>                close_hmenu;

-  typedef close_fun<BOOL (__stdcall *)( HCURSOR ),DestroyCursor>            close_hcursor;

-  typedef close_fun<BOOL (__stdcall *)( HWND ),DestroyWindow>               close_window;

-  typedef close_fun<BOOL (__stdcall *)( HANDLE ),HeapDestroy>               close_heap_destroy;

-  typedef close_fun<HLOCAL (__stdcall *)( HLOCAL ),LocalFree>               close_local_free;

-  typedef close_fun<BOOL (__stdcall *)( HDESK ),CloseDesktop>               close_hdesk;

-  typedef close_fun<BOOL (__stdcall *)( HHOOK ),UnhookWindowsHookEx>        close_hhook;

-  typedef close_fun<BOOL (__stdcall *)( HWINSTA ),CloseWindowStation>       close_hwinsta;

-  typedef close_fun<BOOL (__stdcall *)( HANDLE ),DeregisterEventSource>     close_event_source;

-  typedef close_fun<HGLOBAL (__stdcall *)( HGLOBAL ),GlobalFree>            close_global_free;

-

-  typedef value_const<HANDLE,INVALID_HANDLE_VALUE>                          invalid_handle_t;

-#endif

-

-#ifdef _OLEAUTO_H_

-  typedef close_fun<void (__stdcall *)(BSTR),SysFreeString>                 close_bstr;

-#endif

-

-#ifdef __MSGQUEUE_H__

-  typedef close_fun<BOOL (__stdcall *)(HANDLE),CloseMsgQueue>               close_msg_queue;

-#endif

-

-#if defined(_WININET_) | defined(_DUBINET_)

-  typedef close_fun<BOOL (__stdcall *)(HINTERNET),InternetCloseHandle>      close_hinternet;

-#endif

-

-#ifdef _RAS_H_

-  typedef close_fun<DWORD (__stdcall *)( HRASCONN ),RasHangUp>              close_hrasconn;

-#endif

-

-#if defined(__RPCDCE_H__) & !defined(SMART_ANY_RPC)

-# define SMART_ANY_RPC

-  // for releaseing an rpc binding

-  struct close_rpc_binding

-  {

-      static void close( RPC_BINDING_HANDLE & h )

-      {

-          ::RpcBindingFree( &h );

-      }

-  };

-  // for releaseing an rpc binding vector

-  struct close_rpc_vector

-  {

-      static void close( RPC_BINDING_VECTOR __RPC_FAR * & p )

-      {

-          ::RpcBindingVectorFree( &p );

-      }

-  };

-  // for releasing a RPC string

-  struct close_rpc_string

-  {

-      static void close( unsigned char __RPC_FAR * & p )

-      {

-          ::RpcStringFreeA(&p);

-      }

-      static void close( unsigned short __RPC_FAR * & p )

-      {

-          ::RpcStringFreeW(&p);

-      }

-  };

-#endif

-

-#ifdef _WINSVC_

-  typedef close_fun<BOOL (__stdcall *)( SC_HANDLE ),CloseServiceHandle>     close_service;

-  typedef close_fun<BOOL (__stdcall *)( SC_LOCK ),UnlockServiceDatabase>    unlock_service;

-#endif

-

-#ifdef _WINSOCKAPI_

-  typedef int (__stdcall *pfn_closock_t)( SOCKET );

-  typedef close_fun<pfn_closock_t,static_cast<pfn_closock_t>(&closesocket)> close_socket;

-  typedef value_const<SOCKET,INVALID_SOCKET>                                invalid_socket_t;

-#endif

-

-#ifdef _OBJBASE_H_

-  // For use when releasing memory allocated with CoTaskMemAlloc

-  typedef close_fun<void (__stdcall*)( LPVOID ),CoTaskMemFree>              close_co_task_free;

-#endif

-

-

-//

-// Below are useful smart typedefs for some common Windows/CRT resource types.

-//

-

-#undef DECLARE_SMART_ANY_TYPEDEFS_STDIO

-#undef DECLARE_SMART_ANY_TYPEDEFS_WINDOWS

-#undef DECLARE_SMART_ANY_TYPEDEFS_OLEAUTO

-#undef DECLARE_SMART_ANY_TYPEDEFS_MSGQUEUE

-#undef DECLARE_SMART_ANY_TYPEDEFS_WININET

-#undef DECLARE_SMART_ANY_TYPEDEFS_RAS

-#undef DECLARE_SMART_ANY_TYPEDEFS_RPCDCE

-#undef DECLARE_SMART_ANY_TYPEDEFS_WINSVC

-#undef DECLARE_SMART_ANY_TYPEDEFS_WINSOCKAPI

-#undef DECLARE_SMART_ANY_TYPEDEFS_OBJBASE

-

-#define DECLARE_SMART_ANY_TYPEDEFS_STDIO(prefix)

-#define DECLARE_SMART_ANY_TYPEDEFS_WINDOWS(prefix)

-#define DECLARE_SMART_ANY_TYPEDEFS_OLEAUTO(prefix)

-#define DECLARE_SMART_ANY_TYPEDEFS_MSGQUEUE(prefix)

-#define DECLARE_SMART_ANY_TYPEDEFS_WININET(prefix)

-#define DECLARE_SMART_ANY_TYPEDEFS_RAS(prefix)

-#define DECLARE_SMART_ANY_TYPEDEFS_RPCDCE(prefix)

-#define DECLARE_SMART_ANY_TYPEDEFS_WINSVC(prefix)

-#define DECLARE_SMART_ANY_TYPEDEFS_WINSOCKAPI(prefix)

-#define DECLARE_SMART_ANY_TYPEDEFS_OBJBASE(prefix)

-

-#ifdef _INC_STDIO

-# undef  DECLARE_SMART_ANY_TYPEDEFS_STDIO

-# define DECLARE_SMART_ANY_TYPEDEFS_STDIO(prefix)                                                                       \

-  typedef prefix ## _any<FILE*,close_file_ptr>                                    prefix ## _file_ptr;

-#endif

-

-#ifdef _WINDOWS_

-# undef  DECLARE_SMART_ANY_TYPEDEFS_WINDOWS

-# define DECLARE_SMART_ANY_TYPEDEFS_WINDOWS(prefix)                                                                     \

-  typedef prefix ## _any<HKEY,close_regkey>                                       prefix ## _hkey;                      \

-  typedef prefix ## _any<HANDLE,close_find,invalid_handle_t>                      prefix ## _hfind;                     \

-  typedef prefix ## _any<HANDLE,close_find_change_notification,invalid_handle_t>  prefix ## _hfind_change_notification; \

-  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t>                    prefix ## _hfile;                     \

-  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,1>                  prefix ## _communications_device;     \

-  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,2>                  prefix ## _console_input;             \

-  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,3>                  prefix ## _console_input_buffer;      \

-  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,4>                  prefix ## _console_output;            \

-  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,5>                  prefix ## _mailslot;                  \

-  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,6>                  prefix ## _pipe;                      \

-  typedef prefix ## _any<HANDLE,close_handle>                                     prefix ## _handle;                    \

-  typedef prefix ## _any<HANDLE,close_handle,null_t,1>                            prefix ## _access_token;              \

-  typedef prefix ## _any<HANDLE,close_handle,null_t,2>                            prefix ## _event;                     \

-  typedef prefix ## _any<HANDLE,close_handle,null_t,3>                            prefix ## _file_mapping;              \

-  typedef prefix ## _any<HANDLE,close_handle,null_t,4>                            prefix ## _job;                       \

-  typedef prefix ## _any<HANDLE,close_handle,null_t,5>                            prefix ## _mutex;                     \

-  typedef prefix ## _any<HANDLE,close_handle,null_t,6>                            prefix ## _process;                   \

-  typedef prefix ## _any<HANDLE,close_handle,null_t,7>                            prefix ## _semaphore;                 \

-  typedef prefix ## _any<HANDLE,close_handle,null_t,8>                            prefix ## _thread;                    \

-  typedef prefix ## _any<HANDLE,close_handle,null_t,9>                            prefix ## _timer;                     \

-  typedef prefix ## _any<HANDLE,close_handle,null_t,10>                           prefix ## _completion_port;           \

-  typedef prefix ## _any<HDC,close_hdc>                                           prefix ## _hdc;                       \

-  typedef prefix ## _any<HICON,close_hicon>                                       prefix ## _hicon;                     \

-  typedef prefix ## _any<HMENU,close_hmenu>                                       prefix ## _hmenu;                     \

-  typedef prefix ## _any<HCURSOR,close_hcursor>                                   prefix ## _hcursor;                   \

-  typedef prefix ## _any<HPEN,close_hgdiobj,null_t,1>                             prefix ## _hpen;                      \

-  typedef prefix ## _any<HRGN,close_hgdiobj,null_t,2>                             prefix ## _hrgn;                      \

-  typedef prefix ## _any<HFONT,close_hgdiobj,null_t,3>                            prefix ## _hfont;                     \

-  typedef prefix ## _any<HBRUSH,close_hgdiobj,null_t,4>                           prefix ## _hbrush;                    \

-  typedef prefix ## _any<HBITMAP,close_hgdiobj,null_t,5>                          prefix ## _hbitmap;                   \

-  typedef prefix ## _any<HPALETTE,close_hgdiobj,null_t,6>                         prefix ## _hpalette;                  \

-  typedef prefix ## _any<HACCEL,close_haccel>                                     prefix ## _haccel;                    \

-  typedef prefix ## _any<HWND,close_window>                                       prefix ## _window;                    \

-  typedef prefix ## _any<HINSTANCE,close_library>                                 prefix ## _library;                   \

-  typedef prefix ## _any<LPVOID,close_file_view>                                  prefix ## _file_view;                 \

-  typedef prefix ## _any<LPVOID,close_virtual_free>                               prefix ## _virtual_ptr;               \

-  typedef prefix ## _any<HANDLE,close_heap_destroy>                               prefix ## _heap;                      \

-  typedef prefix ## _any<HLOCAL,close_local_free>                                 prefix ## _hlocal;                    \

-  typedef prefix ## _any<HDESK,close_hdesk>                                       prefix ## _hdesk;                     \

-  typedef prefix ## _any<HHOOK,close_hhook>                                       prefix ## _hhook;                     \

-  typedef prefix ## _any<HWINSTA,close_hwinsta>                                   prefix ## _hwinsta;                   \

-  typedef prefix ## _any<HANDLE,close_event_source>                               prefix ## _event_source;              \

-  typedef prefix ## _any<HGLOBAL,close_global_free>                               prefix ## _hglobal;

-#endif

-

-//

-// Define some other useful typedefs

-//

-

-#ifdef _OLEAUTO_H_

-# undef  DECLARE_SMART_ANY_TYPEDEFS_OLEAUTO

-# define DECLARE_SMART_ANY_TYPEDEFS_OLEAUTO(prefix)                                                                     \

-  typedef prefix ## _any<BSTR,close_bstr>                                         prefix ## _bstr;

-#endif

-

-#ifdef __MSGQUEUE_H__

-# undef  DECLARE_SMART_ANY_TYPEDEFS_MSGQUEUE

-# define DECLARE_SMART_ANY_TYPEDEFS_MSGQUEUE(prefix)                                                                    \

-  typedef prefix ## _any<HANDLE,close_msg_queue>                                  prefix ## _msg_queue;

-#endif

-

-#if defined(_WININET_) | defined(_DUBINET_)

-# undef  DECLARE_SMART_ANY_TYPEDEFS_WININET

-# define DECLARE_SMART_ANY_TYPEDEFS_WININET(prefix)                                                                     \

-  typedef prefix ## _any<HINTERNET,close_hinternet>                               prefix ## _hinternet;

-#endif

-

-#ifdef _RAS_H_

-# undef  DECLARE_SMART_ANY_TYPEDEFS_RAS

-# define DECLARE_SMART_ANY_TYPEDEFS_RAS(prefix)                                                                         \

-  typedef prefix ## _any<HRASCONN,close_hrasconn>                                 prefix ## _hrasconn;

-#endif

-

-#ifdef __RPCDCE_H__

-# undef DECLARE_SMART_ANY_TYPEDEFS_RPCDCE

-# ifdef UNICODE

-#   define DECLARE_SMART_ANY_TYPEDEFS_RPCDCE(prefix)                                                                    \

-    typedef prefix ## _any<RPC_BINDING_HANDLE,close_rpc_binding>                  prefix ## _rpc_binding;               \

-    typedef prefix ## _any<RPC_BINDING_VECTOR __RPC_FAR*,close_rpc_vector>        prefix ## _rpc_binding_vector;        \

-    typedef prefix ## _any<unsigned char __RPC_FAR*,close_rpc_string>             prefix ## _rpc_string_A;              \

-    typedef prefix ## _any<unsigned short __RPC_FAR*,close_rpc_string>            prefix ## _rpc_string_W;              \

-    typedef prefix ## _rpc_string_W                                               prefix ## _rpc_string;

-# else

-#   define DECLARE_SMART_ANY_TYPEDEFS_RPCDCE(prefix)                                                                    \

-    typedef prefix ## _any<RPC_BINDING_HANDLE,close_rpc_binding>                  prefix ## _rpc_binding;               \

-    typedef prefix ## _any<RPC_BINDING_VECTOR __RPC_FAR*,close_rpc_vector>        prefix ## _rpc_binding_vector;        \

-    typedef prefix ## _any<unsigned char __RPC_FAR*,close_rpc_string>             prefix ## _rpc_string_A;              \

-    typedef prefix ## _any<unsigned short __RPC_FAR*,close_rpc_string>            prefix ## _rpc_string_W;              \

-    typedef prefix ## _rpc_string_A                                               prefix ## _rpc_string;

-# endif

-#endif

-

-#ifdef _WINSVC_

-# undef  DECLARE_SMART_ANY_TYPEDEFS_WINSVC

-# define DECLARE_SMART_ANY_TYPEDEFS_WINSVC(prefix)                                                                      \

-  typedef prefix ## _any<SC_HANDLE,close_service>                                 prefix ## _service;                   \

-  typedef prefix ## _any<SC_LOCK,unlock_service>                                  prefix ## _service_lock;

-#endif

-

-#ifdef _WINSOCKAPI_

-# undef  DECLARE_SMART_ANY_TYPEDEFS_WINSOCKAPI

-# define DECLARE_SMART_ANY_TYPEDEFS_WINSOCKAPI(prefix)                                                                  \

-  typedef prefix ## _any<SOCKET,close_socket,invalid_socket_t>                    prefix ## _socket;

-#endif

-

-#if defined(_OBJBASE_H_) & !defined(SMART_ANY_CO_INIT)

-# define SMART_ANY_CO_INIT

-  inline HRESULT smart_co_init_helper( DWORD dwCoInit )

-  {

-      (void) dwCoInit;

-#     if (_WIN32_WINNT >= 0x0400 ) | defined(_WIN32_DCOM)

-          return ::CoInitializeEx(0,dwCoInit);

-#     else

-          return ::CoInitialize(0);

-#     endif

-  }

-  inline void smart_co_uninit_helper( HRESULT hr )

-  {

-      if (SUCCEEDED(hr))

-          ::CoUninitialize();

-  }

-  typedef close_fun<void(*)(HRESULT),smart_co_uninit_helper>                      close_co;

-  typedef value_const<HRESULT,CO_E_NOTINITIALIZED>                                co_not_init;

-# undef  DECLARE_SMART_ANY_TYPEDEFS_OBJBASE

-# define DECLARE_SMART_ANY_TYPEDEFS_OBJBASE(prefix)                                                                     \

-  typedef prefix ## _any<LPVOID,close_co_task_free>                               prefix ## _co_task_ptr;

-#endif

-

-

-#define DECLARE_SMART_ANY_TYPEDEFS(prefix)                                                                              \

-    DECLARE_SMART_ANY_TYPEDEFS_STDIO(prefix)                                                                            \

-    DECLARE_SMART_ANY_TYPEDEFS_WINDOWS(prefix)                                                                          \

-    DECLARE_SMART_ANY_TYPEDEFS_OLEAUTO(prefix)                                                                          \

-    DECLARE_SMART_ANY_TYPEDEFS_MSGQUEUE(prefix)                                                                         \

-    DECLARE_SMART_ANY_TYPEDEFS_WININET(prefix)                                                                          \

-    DECLARE_SMART_ANY_TYPEDEFS_RAS(prefix)                                                                              \

-    DECLARE_SMART_ANY_TYPEDEFS_RPCDCE(prefix)                                                                           \

-    DECLARE_SMART_ANY_TYPEDEFS_WINSVC(prefix)                                                                           \

-    DECLARE_SMART_ANY_TYPEDEFS_WINSOCKAPI(prefix)                                                                       \

-    DECLARE_SMART_ANY_TYPEDEFS_OBJBASE(prefix)

+//+---------------------------------------------------------------------------
+//
+//  Copyright ( C ) Microsoft, 2002.
+//
+//  File:       smart_any_fwd.h
+//
+//  Contents:   automatic resource management
+//
+//  Classes:    auto_any, scoped_any and shared_any
+//
+//  Functions:  get
+//              reset
+//              release
+//              valid
+//              address
+//
+//  Author:     Eric Niebler ( ericne@microsoft.com )
+//
+//----------------------------------------------------------------------------
+
+#ifndef SMART_ANY_FWD
+#define SMART_ANY_FWD
+
+#ifdef _MANAGED
+#pragma warning( push )
+#pragma warning( disable : 4244 )
+#include <vcclr.h>
+#pragma warning( pop )
+#endif
+
+// Check to see if partial template specialization is available
+#if _MSC_VER >= 1310
+#define SMART_ANY_PTS
+#endif
+
+// forward declare some invalid_value policy classes
+struct null_t;
+
+template<typename T,T value = T(0)>
+struct value_const;
+
+struct close_release_com;
+
+//
+// TEMPLATE CLASS auto_any
+//
+template<typename T,class close_policy,class invalid_value = null_t,int unique = 0>
+class auto_any;
+
+// return wrapped resource
+template<typename T,class close_policy,class invalid_value,int unique>
+T  get( auto_any<T,close_policy,invalid_value,unique> const & t );
+
+// return true if the auto_any contains a currently valid resource
+template<typename T,class close_policy,class invalid_value,int unique>
+bool valid( auto_any<T,close_policy,invalid_value,unique> const & t );
+
+// return wrapped resource and give up ownership
+template<typename T,class close_policy,class invalid_value,int unique>
+T release( auto_any<T,close_policy,invalid_value, unique> & t );
+
+// destroy designated object
+template<typename T,class close_policy,class invalid_value,int unique>
+void reset( auto_any<T,close_policy,invalid_value,unique> & t );
+
+// destroy designated object and store new resource
+template<typename T,class close_policy,class invalid_value,int unique,typename U>
+void reset( auto_any<T,close_policy,invalid_value,unique> & t, U newT );
+
+// swap the contents of two shared_any objects
+template<typename T,class close_policy,class invalid_value,int unique>
+void swap( auto_any<T,close_policy,invalid_value,unique> & left,
+           auto_any<T,close_policy,invalid_value,unique> & right );
+
+// return the address of the wrapped resource
+// WARNING: this will assert if the value of the resource is
+// anything other than invalid_value.
+//template<typename T,class close_policy,class invalid_value,int unique>
+//T* address( auto_any<T,close_policy,invalid_value,unique> & t );
+
+//
+// TEMPLATE CLASS shared_any
+//
+template<typename T,class close_policy,class invalid_value = null_t,int unique = 0>
+class shared_any;
+
+// return wrapped resource
+template<typename T,class close_policy,class invalid_value,int unique>
+T  get( shared_any<T,close_policy,invalid_value,unique> const & t );
+
+// return true if the auto_any contains a currently valid resource
+template<typename T,class close_policy,class invalid_value,int unique>
+bool valid( shared_any<T,close_policy,invalid_value,unique> const & t );
+
+// destroy designated object
+template<typename T,class close_policy,class invalid_value,int unique>
+void reset( shared_any<T,close_policy,invalid_value,unique> & t );
+
+// destroy designated object and store new resource
+template<typename T,class close_policy,class invalid_value,int unique,typename U>
+void reset( shared_any<T,close_policy,invalid_value,unique> & t, U newT );
+
+// swap the contents of two shared_any objects
+template<typename T,class close_policy,class invalid_value,int unique>
+void swap( shared_any<T,close_policy,invalid_value,unique> & left,
+           shared_any<T,close_policy,invalid_value,unique> & right );
+
+
+//
+// TEMPLATE CLASS scoped_any
+//
+template<typename T,class close_policy,class invalid_value = null_t,int unique = 0>
+class scoped_any;
+
+// return wrapped resource
+template<typename T,class close_policy,class invalid_value,int unique>
+T  get( scoped_any<T,close_policy,invalid_value,unique> const & t );
+
+// return true if the auto_any contains a currently valid resource
+template<typename T,class close_policy,class invalid_value,int unique>
+bool valid( scoped_any<T,close_policy,invalid_value,unique> const & t );
+
+// return wrapped resource and give up ownership
+template<typename T,class close_policy,class invalid_value,int unique>
+T release( scoped_any<T,close_policy,invalid_value, unique> & t );
+
+// destroy designated object
+template<typename T,class close_policy,class invalid_value,int unique>
+void reset( scoped_any<T,close_policy,invalid_value,unique> & t );
+
+// destroy designated object and store new resource
+template<typename T,class close_policy,class invalid_value,int unique,typename U>
+void reset( scoped_any<T,close_policy,invalid_value,unique> & t, U newT );
+
+// return the address of the wrapped resource
+// WARNING: this will assert if the value of the resource is
+// anything other than invalid_value.
+//template<typename T,class close_policy,class invalid_value,int unique>
+//T* address( scoped_any<T,close_policy,invalid_value,unique> & t );
+
+// close policy for objects allocated with new
+struct close_delete;
+
+namespace detail
+{
+    typedef char (&yes)[1];
+    typedef char (&no) [2];
+
+    struct dummy_struct
+    {
+        void dummy_method() {}
+    };
+
+    typedef void (dummy_struct::*safe_bool)();
+    safe_bool const safe_true  = &dummy_struct::dummy_method;
+    safe_bool const safe_false = 0;
+
+    // Because of older compilers, we can't always use
+    // null_t when we would like to.
+    template<class invalid_value>
+    struct fixup_invalid_value
+    {
+        template<typename> struct rebind { typedef invalid_value type; };
+    };
+
+    // for compile-time assertions
+    template<bool>
+    struct static_assert;
+
+    template<>
+    struct static_assert<true>
+    {
+        static_assert() {}
+    };
+
+    template<typename T>
+    struct static_init
+    {
+        static T const value;
+    };
+
+    template<typename T>
+    T const static_init<T>::value = T();
+
+    template<bool>
+    struct null_helper // unmanaged
+    {
+        template<typename T>
+        struct inner
+        {
+            static T const get()
+            {
+                return static_init<T>::value;
+            }
+        };
+    };
+
+    template<>
+    struct null_helper<true> // managed
+    {
+        template<typename T>
+        struct inner
+        {
+            static T const get()
+            {
+                return 0;
+            }
+        };
+    };
+
+    typedef char (&yes_t)[1];
+    typedef char (& no_t)[2];
+
+    template<bool>
+    struct select_helper
+    {
+        template<typename T,typename>
+        struct inner { typedef T type; };
+    };
+
+    template<>
+    struct select_helper<false>
+    {
+        template<typename,typename U>
+        struct inner { typedef U type; };
+    };
+
+    template<bool F,typename T,typename U>
+    struct select
+    {
+        typedef typename select_helper<F>::template inner<T,U>::type type;
+    };
+
+
+    template< bool >
+    struct holder_helper
+    {
+        template<typename T>
+        struct inner
+        {
+            typedef T type;
+        };
+    };
+
+    template< typename T >
+    struct remove_ref
+    {
+        typedef T type;
+    };
+
+    #ifdef SMART_ANY_PTS
+    template< typename T >
+    struct remove_ref<T&>
+    {
+        typedef T type;
+    };
+    #endif
+
+    template<typename T>
+    T* address_of( T & v )
+    {
+        return reinterpret_cast<T*>(
+            &const_cast<char&>(
+                reinterpret_cast<char const volatile &>(v)));
+    }
+
+    #ifndef _MANAGED
+
+    template<typename T>
+    struct is_managed
+    {
+        static bool const value = false;
+    };
+
+    #else
+
+    struct managed_convertible
+    {
+        managed_convertible( System::Object const volatile __gc* );
+        managed_convertible( System::Enum const volatile __gc* );
+        managed_convertible( System::ValueType const volatile __gc* );
+        managed_convertible( System::Delegate const volatile __gc* );
+    };
+
+    template<typename T>
+    struct is_managed
+    {
+    private:
+        static yes_t check( managed_convertible );
+        static no_t __cdecl check( ... );
+        static typename remove_ref<T>::type & make();
+    public:
+        static bool const value = sizeof( yes_t ) == sizeof( check( make() ) );
+    };
+
+    #ifdef SMART_ANY_PTS
+    template<typename T>
+    struct is_managed<T __gc&>
+    {
+        static bool const value = true;
+    };
+    template<typename T>
+    struct is_managed<T __gc*>
+    {
+        static bool const value = true;
+    };
+    template<typename T>
+    struct is_managed<T __gc*const>
+    {
+        static bool const value = is_managed<T __gc*>::value;
+    };
+    template<typename T>
+    struct is_managed<T __gc*volatile>
+    {
+        static bool const value = is_managed<T __gc*>::value;
+    };
+    template<typename T>
+    struct is_managed<T __gc*const volatile>
+    {
+        static bool const value = is_managed<T __gc*>::value;
+    };
+    #endif
+    template<>
+    struct is_managed<System::Void __gc*>
+    {
+        static bool const value = true;
+    };
+    template<>
+    struct is_managed<System::Void const __gc*>
+    {
+        static bool const value = true;
+    };
+    template<>
+    struct is_managed<System::Void volatile __gc*>
+    {
+        static bool const value = true;
+    };
+    template<>
+    struct is_managed<System::Void const volatile __gc*>
+    {
+        static bool const value = true;
+    };
+
+    template<>
+    struct holder_helper<true>
+    {
+        template<typename T>
+        struct inner
+        {
+            typedef gcroot<T> type;
+        };
+    };
+    #endif
+
+    template<typename T>
+    struct holder
+    {
+        typedef typename holder_helper<is_managed<T>::value>::template inner<T>::type type;
+    };
+
+    template<typename T>
+    struct is_delete
+    {
+        static bool const value = false;
+    };
+
+    template<>
+    struct is_delete<close_delete>
+    {
+        static bool const value = true;
+    };
+
+    // dummy type, don't define
+    struct smart_any_cannot_dereference;
+
+    // For use in implementing unary operator*
+    template<typename T>
+    struct deref
+    {
+        typedef smart_any_cannot_dereference type; // will cause a compile error by default
+    };
+
+    #ifndef SMART_ANY_PTS
+
+    // Old compiler needs extra help
+    template<>
+    struct fixup_invalid_value<null_t>
+    {
+        template<typename T> struct rebind { typedef value_const<T> type; };
+    };
+
+    #else
+
+    template<typename T,typename U>
+    struct same_type
+    {
+        static const bool value = false;
+    };
+
+    template<typename T>
+    struct same_type<T,T>
+    {
+        static const bool value = true;
+    };
+
+    // Handle reference types
+    template<typename T>
+    struct deref<T&>
+    {
+        typedef typename deref<T>::type type;
+    };
+
+    // Partially specialize for pointer types
+    template<typename T>
+    struct deref<T*>
+    {
+        typedef T& type; // The result of dereferencing a T*
+    };
+
+    // Partially specialize for pointer types
+    template<typename T>
+    struct deref<T*const>
+    {
+        typedef typename deref<T*>::type type; // The result of dereferencing a T*
+    };
+
+    // Partially specialize for pointer types
+    template<typename T>
+    struct deref<T*volatile>
+    {
+        typedef typename deref<T*>::type type; // The result of dereferencing a T*
+    };
+
+    // Partially specialize for pointer types
+    template<typename T>
+    struct deref<T*const volatile>
+    {
+        typedef typename deref<T*>::type type; // The result of dereferencing a T*
+    };
+
+    // Fully specialize for void*
+    template<>
+    struct deref<void*>
+    {
+        typedef smart_any_cannot_dereference type; // cannot dereference a void*
+    };
+
+    // Fully specialize for void const*
+    template<>
+    struct deref<void const*>
+    {
+        typedef smart_any_cannot_dereference type; // cannot dereference a void*
+    };
+
+    // Fully specialize for void volatile*
+    template<>
+    struct deref<void volatile*>
+    {
+        typedef smart_any_cannot_dereference type; // cannot dereference a void*
+    };
+
+    // Fully specialize for void const volatile*
+    template<>
+    struct deref<void const volatile*>
+    {
+        typedef smart_any_cannot_dereference type; // cannot dereference a void*
+    };
+
+    #ifdef _MANAGED
+    // Handle reference types
+    template<typename T>
+    struct deref<T __gc&>
+    {
+        typedef typename deref<T>::type type;
+    };
+
+    // Partially specialize for pointer types
+    template<typename T>
+    struct deref<T __gc*>
+    {
+        typedef T __gc& type; // The result of dereferencing a T __gc*
+    };
+
+    // Partially specialize for pointer types
+    template<typename T>
+    struct deref<T __gc*const>
+    {
+        typedef typename deref<T __gc*>::type type; // The result of dereferencing a T __gc*
+    };
+
+    // Partially specialize for pointer types
+    template<typename T>
+    struct deref<T __gc*volatile>
+    {
+        typedef typename deref<T __gc*>::type type; // The result of dereferencing a T __gc*
+    };
+
+    // Partially specialize for pointer types
+    template<typename T>
+    struct deref<T __gc*const volatile>
+    {
+        typedef typename deref<T __gc*>::type type; // The result of dereferencing a T __gc*
+    };
+
+    // Fully specialize for void*
+    template<>
+    struct deref<System::Void __gc*>
+    {
+        typedef smart_any_cannot_dereference type; // cannot dereference a System::Void __gc*
+    };
+
+    // Fully specialize for void const*
+    template<>
+    struct deref<System::Void const __gc*>
+    {
+        typedef smart_any_cannot_dereference type; // cannot dereference a System::Void __gc*
+    };
+
+    // Fully specialize for void volatile*
+    template<>
+    struct deref<System::Void volatile __gc*>
+    {
+        typedef smart_any_cannot_dereference type; // cannot dereference a System::Void __gc*
+    };
+
+    // Fully specialize for void const volatile*
+    template<>
+    struct deref<System::Void const volatile __gc*>
+    {
+        typedef smart_any_cannot_dereference type; // cannot dereference a System::Void __gc*
+    };
+    #endif
+
+    // The DECLARE_HANDLE macro in winnt.h defines a handle to be a pointer
+    // to a struct containing one member named "unused" of type int. We can
+    // use that information to make auto_any safer by disallowing actions like
+    // dereferencing a handle or calling delete on a handle.
+    template<typename T>
+    struct has_unused
+    {
+    private:
+        template<class U,int U::*> struct wrap_t;
+        template<typename U> static yes_t check( wrap_t<U,&U::unused>* );
+        template<typename U> static no_t  __cdecl check( ... );
+    public:
+        static bool const value = ( sizeof(check<T>(0)) == sizeof(yes_t) );
+    };
+
+    template<typename T>
+    struct is_handle_helper
+    {
+        static bool const value = ( sizeof(T)==sizeof(int) && has_unused<T>::value );
+    };
+
+    #ifdef _MANAGED
+    template<typename T>
+    struct is_handle_helper<T __gc&>
+    {
+        static bool const value = false;
+    };
+    #endif
+
+    template<>
+    struct is_handle_helper<smart_any_cannot_dereference>
+    {
+        static bool const value = false;
+    };
+
+    // used to see whether a given type T is a handle type or not.
+    template<typename T>
+    struct is_handle
+    {
+    private:
+        typedef typename remove_ref<typename deref<T>::type>::type deref_t;
+    public:
+        static bool const value =
+            ( same_type<T,void*>::value || is_handle_helper<deref_t>::value );
+    };
+    #endif
+
+    template<typename T,class close_policy>
+    struct safe_types
+    {
+        typedef T pointer_type;
+        typedef typename deref<T>::type reference_type;
+
+        static pointer_type to_pointer( T t )
+        {
+            return t;
+        }
+        static reference_type to_reference( T t )
+        {
+            return *t;
+        }
+    };
+
+    #ifdef SMART_ANY_PTS
+    template<typename T>
+    class no_addref_release : public T
+    {
+        unsigned long __stdcall AddRef();
+        unsigned long __stdcall Release();
+    };
+
+    // shouldn't be able to call AddRef or Release
+    // through a smart COM wrapper
+    template<typename T>
+    struct safe_types<T*,close_release_com>
+    {
+        typedef no_addref_release<T>* pointer_type;
+        typedef no_addref_release<T>& reference_type;
+
+        static pointer_type to_pointer( T* t )
+        {
+            return static_cast<pointer_type>( t );
+        }
+        static reference_type to_reference( T* t )
+        {
+            return *static_cast<pointer_type>( t );
+        }
+    };
+    #endif
+}
+
+// a generic close policy that uses a ptr to a function
+template<typename Fn, Fn Pfn>
+struct close_fun
+{
+    template<typename T>
+    static void close( T t )
+    {
+        Pfn( t );
+    }
+};
+
+// free an object allocated with new by calling delete
+struct close_delete
+{
+    template<typename T>
+    static void close( T * p )
+    {
+        // This will fail only if T is an incomplete type.
+        static detail::static_assert<0 != sizeof( T )> const cannot_delete_an_incomplete_type;
+
+        #ifdef SMART_ANY_PTS
+        // This checks to make sure we're not calling delete on a HANDLE
+        static detail::static_assert<!detail::is_handle<T*>::value> const cannot_delete_a_handle;
+        #endif
+
+        delete p;
+    }
+
+    #ifdef _MANAGED
+    template<typename T>
+    static void close( gcroot<T __gc*> const & p )
+    {
+        delete static_cast<T __gc*>( p );
+    }
+    #endif
+};
+
+// free an array allocated with new[] by calling delete[]
+struct close_delete_array
+{
+    template<typename T>
+    static void close( T * p )
+    {
+        // This will fail only if T is an incomplete type.
+        static detail::static_assert<0 != sizeof( T )> const cannot_delete_an_incomplete_type;
+
+        #ifdef SMART_ANY_PTS
+        // This checks to make sure we're not calling delete on a HANDLE
+        static detail::static_assert<!detail::is_handle<T*>::value> const cannot_delete_a_handle;
+        #endif
+
+        delete [] p;
+    }
+
+    //#ifdef _MANAGED
+    // This is broken because of compiler bugs
+    //template<typename T>
+    //static void close( gcroot<T __gc* __gc[]> const & p )
+    //{
+    //    delete [] static_cast<T __gc* __gc[]>( p );
+    //}
+    //#endif
+};
+
+// for releasing a COM object
+struct close_release_com
+{
+    template<typename T>
+    static void close( T p )
+    {
+        p->Release();
+    }
+};
+
+// for releasing a __gc IDisposable object
+struct close_dispose
+{
+    template<typename T>
+    static void close( T p )
+    {
+        p->Dispose();
+    }
+};
+
+// some generic invalid_value policies
+
+struct null_t
+{
+    template<typename T>
+    operator T const() const
+    {
+        return detail::null_helper<detail::is_managed<T>::value>::template inner<T>::get();
+    }
+};
+
+template<typename T,T value>
+struct value_const
+{
+    operator T const() const
+    {
+        return value;
+    }
+};
+
+template<typename T,T const* value_ptr>
+struct value_const_ptr
+{
+    operator T const&() const
+    {
+        return *value_ptr;
+    }
+};
+
+#ifdef SMART_ANY_PTS
+template<typename T, T const& value>
+struct value_ref
+{
+    operator T const&() const
+    {
+        return value;
+    }
+};
+#endif
+
+#endif // SMART_ANY_FWD
+
+
+//
+// Define some other useful close polcies
+//
+
+#if defined(_INC_STDLIB) | defined(_INC_MALLOC)
+typedef void (__cdecl *pfn_free_t)( void* );
+typedef close_fun<pfn_free_t,static_cast<pfn_free_t>(&free)>                close_free;
+#endif
+
+#if defined(_INC_STDIO) & !defined(SMART_CLOSE_FILE_PTR)
+# define SMART_CLOSE_FILE_PTR
+  // don't close a FILE* if it is stdin, stdout or stderr
+  struct close_file_ptr
+  {
+      static void close( FILE * pfile )
+      {
+          if( pfile != stdin && pfile != stdout && pfile != stderr )
+          {
+              fclose( pfile );
+          }
+      }
+  };
+#endif
+
+#ifdef _WINDOWS_
+
+# ifndef SMART_VIRTUAL_FREE
+# define SMART_VIRTUAL_FREE
+  // free memory allocated with VirtualAlloc
+  struct close_virtual_free
+  {
+      static void close( void * p )
+      {
+          ::VirtualFree( p, 0, MEM_RELEASE );
+      }
+  };
+# endif
+
+  typedef close_fun<BOOL (__stdcall *)( HANDLE ),CloseHandle>               close_handle;
+  typedef close_fun<BOOL (__stdcall *)( HANDLE ),FindClose>                 close_find;
+  typedef close_fun<BOOL (__stdcall *)( HANDLE ),FindCloseChangeNotification> close_find_change_notification;
+  typedef close_fun<BOOL (__stdcall *)( HINSTANCE ),FreeLibrary>            close_library;
+  typedef close_fun<LONG (__stdcall *)( HKEY ),RegCloseKey>                 close_regkey;
+  typedef close_fun<BOOL (__stdcall *)( LPCVOID ),UnmapViewOfFile>          close_file_view;
+  typedef close_fun<BOOL (__stdcall *)( HICON ),DestroyIcon>                close_hicon;
+  typedef close_fun<BOOL (__stdcall *)( HGDIOBJ ),DeleteObject>             close_hgdiobj;
+  typedef close_fun<BOOL (__stdcall *)( HACCEL ),DestroyAcceleratorTable>   close_haccel;
+  typedef close_fun<BOOL (__stdcall *)( HDC ),DeleteDC>                     close_hdc;
+  typedef close_fun<BOOL (__stdcall *)( HMENU ),DestroyMenu>                close_hmenu;
+  typedef close_fun<BOOL (__stdcall *)( HCURSOR ),DestroyCursor>            close_hcursor;
+  typedef close_fun<BOOL (__stdcall *)( HWND ),DestroyWindow>               close_window;
+  typedef close_fun<BOOL (__stdcall *)( HANDLE ),HeapDestroy>               close_heap_destroy;
+  typedef close_fun<HLOCAL (__stdcall *)( HLOCAL ),LocalFree>               close_local_free;
+  typedef close_fun<BOOL (__stdcall *)( HDESK ),CloseDesktop>               close_hdesk;
+  typedef close_fun<BOOL (__stdcall *)( HHOOK ),UnhookWindowsHookEx>        close_hhook;
+  typedef close_fun<BOOL (__stdcall *)( HWINSTA ),CloseWindowStation>       close_hwinsta;
+  typedef close_fun<BOOL (__stdcall *)( HANDLE ),DeregisterEventSource>     close_event_source;
+  typedef close_fun<HGLOBAL (__stdcall *)( HGLOBAL ),GlobalFree>            close_global_free;
+
+  typedef value_const<HANDLE,INVALID_HANDLE_VALUE>                          invalid_handle_t;
+#endif
+
+#ifdef _OLEAUTO_H_
+  typedef close_fun<void (__stdcall *)(BSTR),SysFreeString>                 close_bstr;
+#endif
+
+#ifdef __MSGQUEUE_H__
+  typedef close_fun<BOOL (__stdcall *)(HANDLE),CloseMsgQueue>               close_msg_queue;
+#endif
+
+#if defined(_WININET_) | defined(_DUBINET_)
+  typedef close_fun<BOOL (__stdcall *)(HINTERNET),InternetCloseHandle>      close_hinternet;
+#endif
+
+#ifdef _RAS_H_
+  typedef close_fun<DWORD (__stdcall *)( HRASCONN ),RasHangUp>              close_hrasconn;
+#endif
+
+#if defined(__RPCDCE_H__) & !defined(SMART_ANY_RPC)
+# define SMART_ANY_RPC
+  // for releaseing an rpc binding
+  struct close_rpc_binding
+  {
+      static void close( RPC_BINDING_HANDLE & h )
+      {
+          ::RpcBindingFree( &h );
+      }
+  };
+  // for releaseing an rpc binding vector
+  struct close_rpc_vector
+  {
+      static void close( RPC_BINDING_VECTOR __RPC_FAR * & p )
+      {
+          ::RpcBindingVectorFree( &p );
+      }
+  };
+  // for releasing a RPC string
+  struct close_rpc_string
+  {
+      static void close( unsigned char __RPC_FAR * & p )
+      {
+          ::RpcStringFreeA(&p);
+      }
+      static void close( unsigned short __RPC_FAR * & p )
+      {
+          ::RpcStringFreeW(&p);
+      }
+  };
+#endif
+
+#ifdef _WINSVC_
+  typedef close_fun<BOOL (__stdcall *)( SC_HANDLE ),CloseServiceHandle>     close_service;
+  typedef close_fun<BOOL (__stdcall *)( SC_LOCK ),UnlockServiceDatabase>    unlock_service;
+#endif
+
+#ifdef _WINSOCKAPI_
+  typedef int (__stdcall *pfn_closock_t)( SOCKET );
+  typedef close_fun<pfn_closock_t,static_cast<pfn_closock_t>(&closesocket)> close_socket;
+  typedef value_const<SOCKET,INVALID_SOCKET>                                invalid_socket_t;
+#endif
+
+#ifdef _OBJBASE_H_
+  // For use when releasing memory allocated with CoTaskMemAlloc
+  typedef close_fun<void (__stdcall*)( LPVOID ),CoTaskMemFree>              close_co_task_free;
+#endif
+
+
+//
+// Below are useful smart typedefs for some common Windows/CRT resource types.
+//
+
+#undef DECLARE_SMART_ANY_TYPEDEFS_STDIO
+#undef DECLARE_SMART_ANY_TYPEDEFS_WINDOWS
+#undef DECLARE_SMART_ANY_TYPEDEFS_OLEAUTO
+#undef DECLARE_SMART_ANY_TYPEDEFS_MSGQUEUE
+#undef DECLARE_SMART_ANY_TYPEDEFS_WININET
+#undef DECLARE_SMART_ANY_TYPEDEFS_RAS
+#undef DECLARE_SMART_ANY_TYPEDEFS_RPCDCE
+#undef DECLARE_SMART_ANY_TYPEDEFS_WINSVC
+#undef DECLARE_SMART_ANY_TYPEDEFS_WINSOCKAPI
+#undef DECLARE_SMART_ANY_TYPEDEFS_OBJBASE
+
+#define DECLARE_SMART_ANY_TYPEDEFS_STDIO(prefix)
+#define DECLARE_SMART_ANY_TYPEDEFS_WINDOWS(prefix)
+#define DECLARE_SMART_ANY_TYPEDEFS_OLEAUTO(prefix)
+#define DECLARE_SMART_ANY_TYPEDEFS_MSGQUEUE(prefix)
+#define DECLARE_SMART_ANY_TYPEDEFS_WININET(prefix)
+#define DECLARE_SMART_ANY_TYPEDEFS_RAS(prefix)
+#define DECLARE_SMART_ANY_TYPEDEFS_RPCDCE(prefix)
+#define DECLARE_SMART_ANY_TYPEDEFS_WINSVC(prefix)
+#define DECLARE_SMART_ANY_TYPEDEFS_WINSOCKAPI(prefix)
+#define DECLARE_SMART_ANY_TYPEDEFS_OBJBASE(prefix)
+
+#ifdef _INC_STDIO
+# undef  DECLARE_SMART_ANY_TYPEDEFS_STDIO
+# define DECLARE_SMART_ANY_TYPEDEFS_STDIO(prefix)                                                                       \
+  typedef prefix ## _any<FILE*,close_file_ptr>                                    prefix ## _file_ptr;
+#endif
+
+#ifdef _WINDOWS_
+# undef  DECLARE_SMART_ANY_TYPEDEFS_WINDOWS
+# define DECLARE_SMART_ANY_TYPEDEFS_WINDOWS(prefix)                                                                     \
+  typedef prefix ## _any<HKEY,close_regkey>                                       prefix ## _hkey;                      \
+  typedef prefix ## _any<HANDLE,close_find,invalid_handle_t>                      prefix ## _hfind;                     \
+  typedef prefix ## _any<HANDLE,close_find_change_notification,invalid_handle_t>  prefix ## _hfind_change_notification; \
+  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t>                    prefix ## _hfile;                     \
+  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,1>                  prefix ## _communications_device;     \
+  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,2>                  prefix ## _console_input;             \
+  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,3>                  prefix ## _console_input_buffer;      \
+  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,4>                  prefix ## _console_output;            \
+  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,5>                  prefix ## _mailslot;                  \
+  typedef prefix ## _any<HANDLE,close_handle,invalid_handle_t,6>                  prefix ## _pipe;                      \
+  typedef prefix ## _any<HANDLE,close_handle>                                     prefix ## _handle;                    \
+  typedef prefix ## _any<HANDLE,close_handle,null_t,1>                            prefix ## _access_token;              \
+  typedef prefix ## _any<HANDLE,close_handle,null_t,2>                            prefix ## _event;                     \
+  typedef prefix ## _any<HANDLE,close_handle,null_t,3>                            prefix ## _file_mapping;              \
+  typedef prefix ## _any<HANDLE,close_handle,null_t,4>                            prefix ## _job;                       \
+  typedef prefix ## _any<HANDLE,close_handle,null_t,5>                            prefix ## _mutex;                     \
+  typedef prefix ## _any<HANDLE,close_handle,null_t,6>                            prefix ## _process;                   \
+  typedef prefix ## _any<HANDLE,close_handle,null_t,7>                            prefix ## _semaphore;                 \
+  typedef prefix ## _any<HANDLE,close_handle,null_t,8>                            prefix ## _thread;                    \
+  typedef prefix ## _any<HANDLE,close_handle,null_t,9>                            prefix ## _timer;                     \
+  typedef prefix ## _any<HANDLE,close_handle,null_t,10>                           prefix ## _completion_port;           \
+  typedef prefix ## _any<HDC,close_hdc>                                           prefix ## _hdc;                       \
+  typedef prefix ## _any<HICON,close_hicon>                                       prefix ## _hicon;                     \
+  typedef prefix ## _any<HMENU,close_hmenu>                                       prefix ## _hmenu;                     \
+  typedef prefix ## _any<HCURSOR,close_hcursor>                                   prefix ## _hcursor;                   \
+  typedef prefix ## _any<HPEN,close_hgdiobj,null_t,1>                             prefix ## _hpen;                      \
+  typedef prefix ## _any<HRGN,close_hgdiobj,null_t,2>                             prefix ## _hrgn;                      \
+  typedef prefix ## _any<HFONT,close_hgdiobj,null_t,3>                            prefix ## _hfont;                     \
+  typedef prefix ## _any<HBRUSH,close_hgdiobj,null_t,4>                           prefix ## _hbrush;                    \
+  typedef prefix ## _any<HBITMAP,close_hgdiobj,null_t,5>                          prefix ## _hbitmap;                   \
+  typedef prefix ## _any<HPALETTE,close_hgdiobj,null_t,6>                         prefix ## _hpalette;                  \
+  typedef prefix ## _any<HACCEL,close_haccel>                                     prefix ## _haccel;                    \
+  typedef prefix ## _any<HWND,close_window>                                       prefix ## _window;                    \
+  typedef prefix ## _any<HINSTANCE,close_library>                                 prefix ## _library;                   \
+  typedef prefix ## _any<LPVOID,close_file_view>                                  prefix ## _file_view;                 \
+  typedef prefix ## _any<LPVOID,close_virtual_free>                               prefix ## _virtual_ptr;               \
+  typedef prefix ## _any<HANDLE,close_heap_destroy>                               prefix ## _heap;                      \
+  typedef prefix ## _any<HLOCAL,close_local_free>                                 prefix ## _hlocal;                    \
+  typedef prefix ## _any<HDESK,close_hdesk>                                       prefix ## _hdesk;                     \
+  typedef prefix ## _any<HHOOK,close_hhook>                                       prefix ## _hhook;                     \
+  typedef prefix ## _any<HWINSTA,close_hwinsta>                                   prefix ## _hwinsta;                   \
+  typedef prefix ## _any<HANDLE,close_event_source>                               prefix ## _event_source;              \
+  typedef prefix ## _any<HGLOBAL,close_global_free>                               prefix ## _hglobal;
+#endif
+
+//
+// Define some other useful typedefs
+//
+
+#ifdef _OLEAUTO_H_
+# undef  DECLARE_SMART_ANY_TYPEDEFS_OLEAUTO
+# define DECLARE_SMART_ANY_TYPEDEFS_OLEAUTO(prefix)                                                                     \
+  typedef prefix ## _any<BSTR,close_bstr>                                         prefix ## _bstr;
+#endif
+
+#ifdef __MSGQUEUE_H__
+# undef  DECLARE_SMART_ANY_TYPEDEFS_MSGQUEUE
+# define DECLARE_SMART_ANY_TYPEDEFS_MSGQUEUE(prefix)                                                                    \
+  typedef prefix ## _any<HANDLE,close_msg_queue>                                  prefix ## _msg_queue;
+#endif
+
+#if defined(_WININET_) | defined(_DUBINET_)
+# undef  DECLARE_SMART_ANY_TYPEDEFS_WININET
+# define DECLARE_SMART_ANY_TYPEDEFS_WININET(prefix)                                                                     \
+  typedef prefix ## _any<HINTERNET,close_hinternet>                               prefix ## _hinternet;
+#endif
+
+#ifdef _RAS_H_
+# undef  DECLARE_SMART_ANY_TYPEDEFS_RAS
+# define DECLARE_SMART_ANY_TYPEDEFS_RAS(prefix)                                                                         \
+  typedef prefix ## _any<HRASCONN,close_hrasconn>                                 prefix ## _hrasconn;
+#endif
+
+#ifdef __RPCDCE_H__
+# undef DECLARE_SMART_ANY_TYPEDEFS_RPCDCE
+# ifdef UNICODE
+#   define DECLARE_SMART_ANY_TYPEDEFS_RPCDCE(prefix)                                                                    \
+    typedef prefix ## _any<RPC_BINDING_HANDLE,close_rpc_binding>                  prefix ## _rpc_binding;               \
+    typedef prefix ## _any<RPC_BINDING_VECTOR __RPC_FAR*,close_rpc_vector>        prefix ## _rpc_binding_vector;        \
+    typedef prefix ## _any<unsigned char __RPC_FAR*,close_rpc_string>             prefix ## _rpc_string_A;              \
+    typedef prefix ## _any<unsigned short __RPC_FAR*,close_rpc_string>            prefix ## _rpc_string_W;              \
+    typedef prefix ## _rpc_string_W                                               prefix ## _rpc_string;
+# else
+#   define DECLARE_SMART_ANY_TYPEDEFS_RPCDCE(prefix)                                                                    \
+    typedef prefix ## _any<RPC_BINDING_HANDLE,close_rpc_binding>                  prefix ## _rpc_binding;               \
+    typedef prefix ## _any<RPC_BINDING_VECTOR __RPC_FAR*,close_rpc_vector>        prefix ## _rpc_binding_vector;        \
+    typedef prefix ## _any<unsigned char __RPC_FAR*,close_rpc_string>             prefix ## _rpc_string_A;              \
+    typedef prefix ## _any<unsigned short __RPC_FAR*,close_rpc_string>            prefix ## _rpc_string_W;              \
+    typedef prefix ## _rpc_string_A                                               prefix ## _rpc_string;
+# endif
+#endif
+
+#ifdef _WINSVC_
+# undef  DECLARE_SMART_ANY_TYPEDEFS_WINSVC
+# define DECLARE_SMART_ANY_TYPEDEFS_WINSVC(prefix)                                                                      \
+  typedef prefix ## _any<SC_HANDLE,close_service>                                 prefix ## _service;                   \
+  typedef prefix ## _any<SC_LOCK,unlock_service>                                  prefix ## _service_lock;
+#endif
+
+#ifdef _WINSOCKAPI_
+# undef  DECLARE_SMART_ANY_TYPEDEFS_WINSOCKAPI
+# define DECLARE_SMART_ANY_TYPEDEFS_WINSOCKAPI(prefix)                                                                  \
+  typedef prefix ## _any<SOCKET,close_socket,invalid_socket_t>                    prefix ## _socket;
+#endif
+
+#if defined(_OBJBASE_H_) & !defined(SMART_ANY_CO_INIT)
+# define SMART_ANY_CO_INIT
+  inline HRESULT smart_co_init_helper( DWORD dwCoInit )
+  {
+      (void) dwCoInit;
+#     if (_WIN32_WINNT >= 0x0400 ) | defined(_WIN32_DCOM)
+          return ::CoInitializeEx(0,dwCoInit);
+#     else
+          return ::CoInitialize(0);
+#     endif
+  }
+  inline void smart_co_uninit_helper( HRESULT hr )
+  {
+      if (SUCCEEDED(hr))
+          ::CoUninitialize();
+  }
+  typedef close_fun<void(*)(HRESULT),smart_co_uninit_helper>                      close_co;
+  typedef value_const<HRESULT,CO_E_NOTINITIALIZED>                                co_not_init;
+# undef  DECLARE_SMART_ANY_TYPEDEFS_OBJBASE
+# define DECLARE_SMART_ANY_TYPEDEFS_OBJBASE(prefix)                                                                     \
+  typedef prefix ## _any<LPVOID,close_co_task_free>                               prefix ## _co_task_ptr;
+#endif
+
+
+#define DECLARE_SMART_ANY_TYPEDEFS(prefix)                                                                              \
+    DECLARE_SMART_ANY_TYPEDEFS_STDIO(prefix)                                                                            \
+    DECLARE_SMART_ANY_TYPEDEFS_WINDOWS(prefix)                                                                          \
+    DECLARE_SMART_ANY_TYPEDEFS_OLEAUTO(prefix)                                                                          \
+    DECLARE_SMART_ANY_TYPEDEFS_MSGQUEUE(prefix)                                                                         \
+    DECLARE_SMART_ANY_TYPEDEFS_WININET(prefix)                                                                          \
+    DECLARE_SMART_ANY_TYPEDEFS_RAS(prefix)                                                                              \
+    DECLARE_SMART_ANY_TYPEDEFS_RPCDCE(prefix)                                                                           \
+    DECLARE_SMART_ANY_TYPEDEFS_WINSVC(prefix)                                                                           \
+    DECLARE_SMART_ANY_TYPEDEFS_WINSOCKAPI(prefix)                                                                       \
+    DECLARE_SMART_ANY_TYPEDEFS_OBJBASE(prefix)
diff --git a/tools/ApplyTag/apply_tag_tool.cc b/tools/ApplyTag/apply_tag_tool.cc
index f66a713..9fd80c1 100644
--- a/tools/ApplyTag/apply_tag_tool.cc
+++ b/tools/ApplyTag/apply_tag_tool.cc
@@ -1,89 +1,89 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The main file for a simple tool to apply a tag to a signed file.

-#include <Windows.h>

-#include <TCHAR.h>

-#include "omaha/common/apply_tag.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/utils.h"

-

-using omaha::CreateDir;

-using omaha::ConcatenatePath;

-using omaha::File;

-using omaha::GetCurrentDir;

-using omaha::GetDirectoryFromPath;

-using omaha::GetFileFromPath;

-

-int _tmain(int argc, TCHAR* argv[]) {

-  if (argc != 4 && argc != 5) {

-    _tprintf(_T("Incorrect number of arguments!\n"));

-    _tprintf(_T("Usage: ApplyTag <signed_file> <outputfile> <tag> [append]\n"));

-    return -1;

-  }

-

-  const TCHAR* file = argv[1];

-  if (!File::Exists(file)) {

-    _tprintf(_T("File \"%s\" not found!\n"), file);

-    return -1;

-  }

-

-  bool append = false;

-  if (argc == 5 && _tcsicmp(argv[4], _T("append")) == 0) {

-    append = true;

-  }

-

-  CString dir = GetDirectoryFromPath(argv[2]);

-  CString path = ConcatenatePath(GetCurrentDir(), dir);

-  ASSERT1(!path.IsEmpty());

-  if (!File::Exists(path)) {

-    HRESULT hr = CreateDir(path, NULL);

-    if (FAILED(hr)) {

-      _tprintf(_T("Could not create dir %s\n"), path);

-      return hr;

-    }

-  }

-

-  CString file_name = GetFileFromPath(argv[2]);

-  CString out_path = ConcatenatePath(path, file_name);

-  ASSERT1(!out_path.IsEmpty());

-  ASSERT1(File::Exists(path));

-  omaha::ApplyTag tag;

-  HRESULT hr = tag.Init(argv[1],

-                        CT2CA(argv[3]),

-                        lstrlenA(CT2CA(argv[3])),

-                        out_path,

-                        append);

-  if (hr == E_INVALIDARG) {

-    _tprintf(_T("The tag_string %s contains invalid characters."), argv[3]);

-    _tprintf(_T("  We accept the following ATL RegEx '[-%{}/\a&=._]*'\n"));

-    return hr;

-  }

-

-  if (FAILED(hr)) {

-    _tprintf(_T("Tag.Init Failed hr = %x\n"), hr);

-    return hr;

-  }

-

-  hr = tag.EmbedTagString();

-  if (hr == APPLYTAG_E_ALREADY_TAGGED) {

-    _tprintf(_T("The binary %s is already tagged."), argv[1]);

-    _tprintf(_T(" In order to append the tag string, use the append flag.\n"));

-    _tprintf(_T("Usage: ApplyTag <signed_file> <outputfile> <tag> [append]\n"));

-  }

-

-  return 0;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The main file for a simple tool to apply a tag to a signed file.
+#include <Windows.h>
+#include <TCHAR.h>
+#include "omaha/common/apply_tag.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/utils.h"
+
+using omaha::CreateDir;
+using omaha::ConcatenatePath;
+using omaha::File;
+using omaha::GetCurrentDir;
+using omaha::GetDirectoryFromPath;
+using omaha::GetFileFromPath;
+
+int _tmain(int argc, TCHAR* argv[]) {
+  if (argc != 4 && argc != 5) {
+    _tprintf(_T("Incorrect number of arguments!\n"));
+    _tprintf(_T("Usage: ApplyTag <signed_file> <outputfile> <tag> [append]\n"));
+    return -1;
+  }
+
+  const TCHAR* file = argv[1];
+  if (!File::Exists(file)) {
+    _tprintf(_T("File \"%s\" not found!\n"), file);
+    return -1;
+  }
+
+  bool append = false;
+  if (argc == 5 && _tcsicmp(argv[4], _T("append")) == 0) {
+    append = true;
+  }
+
+  CString dir = GetDirectoryFromPath(argv[2]);
+  CString path = ConcatenatePath(GetCurrentDir(), dir);
+  ASSERT1(!path.IsEmpty());
+  if (!File::Exists(path)) {
+    HRESULT hr = CreateDir(path, NULL);
+    if (FAILED(hr)) {
+      _tprintf(_T("Could not create dir %s\n"), path);
+      return hr;
+    }
+  }
+
+  CString file_name = GetFileFromPath(argv[2]);
+  CString out_path = ConcatenatePath(path, file_name);
+  ASSERT1(!out_path.IsEmpty());
+  ASSERT1(File::Exists(path));
+  omaha::ApplyTag tag;
+  HRESULT hr = tag.Init(argv[1],
+                        CT2CA(argv[3]),
+                        lstrlenA(CT2CA(argv[3])),
+                        out_path,
+                        append);
+  if (hr == E_INVALIDARG) {
+    _tprintf(_T("The tag_string %s contains invalid characters."), argv[3]);
+    _tprintf(_T("  We accept the following ATL RegEx '[-%{}/\a&=._]*'\n"));
+    return hr;
+  }
+
+  if (FAILED(hr)) {
+    _tprintf(_T("Tag.Init Failed hr = %x\n"), hr);
+    return hr;
+  }
+
+  hr = tag.EmbedTagString();
+  if (hr == APPLYTAG_E_ALREADY_TAGGED) {
+    _tprintf(_T("The binary %s is already tagged."), argv[1]);
+    _tprintf(_T(" In order to append the tag string, use the append flag.\n"));
+    _tprintf(_T("Usage: ApplyTag <signed_file> <outputfile> <tag> [append]\n"));
+  }
+
+  return 0;
+}
diff --git a/tools/ApplyTag/build.scons b/tools/ApplyTag/build.scons
index 1627f60..65ffae3 100644
--- a/tools/ApplyTag/build.scons
+++ b/tools/ApplyTag/build.scons
@@ -1,61 +1,61 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-local_env = env.Clone()

-local_env.Append(

-    LIBS = [

-        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],

-        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[local_env.Bit('debug')],

-        'netapi32.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'shlwapi.lib',

-        'userenv.lib',

-        'version.lib',

-        'wtsapi32.lib',

-        '$LIB_DIR/common.lib',

-        ],

-    CPPDEFINES = [

-        'UNICODE',

-        '_UNICODE'

-        ],

-)

-

-# ApplyTag.exe is a console application

-local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-local_env.Dir('.').addRepository(local_env.Dir('$MAIN_DIR/common'))

-

-target_name = 'ApplyTag.exe'

-

-inputs = [

-    'apply_tag.cc',  # Comes from $MAIN_DIR/common

-    'apply_tag_tool.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  inputs += local_env.EnablePrecompile(target_name)

-

-local_env.ComponentProgram(

-    prog_name=target_name,

-    source=inputs,

-)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+local_env = env.Clone()
+local_env.Append(
+    LIBS = [
+        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],
+        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[local_env.Bit('debug')],
+        'netapi32.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'shlwapi.lib',
+        'userenv.lib',
+        'version.lib',
+        'wtsapi32.lib',
+        '$LIB_DIR/common.lib',
+        ],
+    CPPDEFINES = [
+        'UNICODE',
+        '_UNICODE'
+        ],
+)
+
+# ApplyTag.exe is a console application
+local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+local_env.Dir('.').addRepository(local_env.Dir('$MAIN_DIR/common'))
+
+target_name = 'ApplyTag.exe'
+
+inputs = [
+    'apply_tag.cc',  # Comes from $MAIN_DIR/common
+    'apply_tag_tool.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  inputs += local_env.EnablePrecompile(target_name)
+
+local_env.ComponentProgram(
+    prog_name=target_name,
+    source=inputs,
+)
diff --git a/tools/CrashProcess/build.scons b/tools/CrashProcess/build.scons
index 138c25b..5b25703 100644
--- a/tools/CrashProcess/build.scons
+++ b/tools/CrashProcess/build.scons
@@ -1,39 +1,39 @@
-#!/usr/bin/python2.4

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-local_env = env.Clone()

-

-local_env.Append(

-    LIBS = [

-        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],

-        'psapi.lib',

-        ],

-    CPPDEFINES = [

-        'UNICODE',

-        '_UNICODE'

-        ],

-)

-

-local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-

-local_env.ComponentProgram(

-    prog_name='CrashProcess.exe',

-    source=['crash_process.cc']

-)

+#!/usr/bin/python2.4
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+local_env = env.Clone()
+
+local_env.Append(
+    LIBS = [
+        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],
+        'psapi.lib',
+        ],
+    CPPDEFINES = [
+        'UNICODE',
+        '_UNICODE'
+        ],
+)
+
+local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+
+local_env.ComponentProgram(
+    prog_name='CrashProcess.exe',
+    source=['crash_process.cc']
+)
diff --git a/tools/CrashProcess/crash_process.cc b/tools/CrashProcess/crash_process.cc
index c249005..cb72e79 100644
--- a/tools/CrashProcess/crash_process.cc
+++ b/tools/CrashProcess/crash_process.cc
@@ -1,111 +1,111 @@
-// Copyright 2004-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Tool to crash the specified process.

-// Injects a remote thread into the named process and causes

-// this thread to crash.

-// Options:

-// 1. Crash by injecting a thread that tries to execute a non-existent code

-//    location.

-// 2. Crash by Raising a specific exception.

-// TODO(omaha): Figure out a way to implement:

-// 3. Crash another thread of the process.

-// 4. Crash another thread when it enters a particular function.

-// 5. Crash another thread when it leaves a particular function.

-//

-// For now the process name and the address of the crash are hard coded.

-

-#include <windows.h>

-#include <wtypes.h>

-#include <tchar.h>

-#include <psapi.h>

-

-const int kMaxProcesses = 1024;

-

-int _tmain(int argc, TCHAR* argv[]) {

-  if (2 != argc) {

-    wprintf(_T("Incorrect syntax. The single required argument is the ")

-            _T("executable to crash.\n"));

-    return -1;

-  }

-

-  const TCHAR* target_process_name = argv[1];

-

-  DWORD num_processes = 0;

-  DWORD process_ids[kMaxProcesses] = {0};

-  if (!::EnumProcesses(process_ids, kMaxProcesses, &num_processes)) {

-    wprintf(_T("EnumProcesses failed.\n"));

-    return -1;

-  }

-

-  wprintf(_T("Found %u processes.\n"), num_processes);

-  bool found = false;

-  for (size_t i = 0; i < num_processes && !found; ++i) {

-    const DWORD access_rights = PROCESS_CREATE_THREAD |

-                                PROCESS_QUERY_INFORMATION |

-                                PROCESS_VM_OPERATION |

-                                PROCESS_VM_WRITE |

-                                PROCESS_VM_READ;

-    HANDLE process_handle = ::OpenProcess(access_rights,

-                                          FALSE,

-                                          process_ids[i]);

-    if (process_handle) {

-      TCHAR process_name[1024] = {0};

-      if (::GetProcessImageFileName(process_handle, process_name, 1024) != 0) {

-        size_t len = wcslen(target_process_name);

-        size_t total_len = wcslen(process_name);

-        int offset = total_len - len;

-        if (offset >= 0 &&

-            _wcsicmp(&(process_name[offset]), target_process_name) == 0) {

-          found = true;

-          wprintf(_T("Found %s %u. Injecting a crash.\n"),

-                  target_process_name, process_ids[i]);

-          DWORD thread_id = 0;

-          LPTHREAD_START_ROUTINE func =

-              reinterpret_cast<LPTHREAD_START_ROUTINE>(0x12345678);

-          void* addr_of_param = reinterpret_cast<void*>(0x2491ed8);

-          HANDLE thread_handle = ::CreateRemoteThread(process_handle,

-                                                      NULL,

-                                                      0,

-                                                      func,

-                                                      addr_of_param,

-                                                      CREATE_SUSPENDED,

-                                                      &thread_id);

-          if (!thread_handle) {

-            HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());

-            wprintf(_T("CreateRemoteThread failed.\n"));

-          }

-          if (::ResumeThread(thread_handle) == -1) {

-            wprintf(_T("Resume thread failed.\n"));

-          } else {

-            wprintf(_T("Waiting for process to quit.\n"));

-            ::WaitForSingleObject(thread_handle, 2000);

-          }

-        }

-      }

-

-      ::CloseHandle(process_handle);

-    }

-  }

-

-  if (!found) {

-    wprintf(_T("No %s processes found.\n"), target_process_name);

-  } else {

-    wprintf(_T("Done.\n"));

-  }

-

-  return 0;

-}

-

+// Copyright 2004-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Tool to crash the specified process.
+// Injects a remote thread into the named process and causes
+// this thread to crash.
+// Options:
+// 1. Crash by injecting a thread that tries to execute a non-existent code
+//    location.
+// 2. Crash by Raising a specific exception.
+// TODO(omaha): Figure out a way to implement:
+// 3. Crash another thread of the process.
+// 4. Crash another thread when it enters a particular function.
+// 5. Crash another thread when it leaves a particular function.
+//
+// For now the process name and the address of the crash are hard coded.
+
+#include <windows.h>
+#include <wtypes.h>
+#include <tchar.h>
+#include <psapi.h>
+
+const int kMaxProcesses = 1024;
+
+int _tmain(int argc, TCHAR* argv[]) {
+  if (2 != argc) {
+    wprintf(_T("Incorrect syntax. The single required argument is the ")
+            _T("executable to crash.\n"));
+    return -1;
+  }
+
+  const TCHAR* target_process_name = argv[1];
+
+  DWORD num_processes = 0;
+  DWORD process_ids[kMaxProcesses] = {0};
+  if (!::EnumProcesses(process_ids, kMaxProcesses, &num_processes)) {
+    wprintf(_T("EnumProcesses failed.\n"));
+    return -1;
+  }
+
+  wprintf(_T("Found %u processes.\n"), num_processes);
+  bool found = false;
+  for (size_t i = 0; i < num_processes && !found; ++i) {
+    const DWORD access_rights = PROCESS_CREATE_THREAD |
+                                PROCESS_QUERY_INFORMATION |
+                                PROCESS_VM_OPERATION |
+                                PROCESS_VM_WRITE |
+                                PROCESS_VM_READ;
+    HANDLE process_handle = ::OpenProcess(access_rights,
+                                          FALSE,
+                                          process_ids[i]);
+    if (process_handle) {
+      TCHAR process_name[1024] = {0};
+      if (::GetProcessImageFileName(process_handle, process_name, 1024) != 0) {
+        size_t len = wcslen(target_process_name);
+        size_t total_len = wcslen(process_name);
+        int offset = total_len - len;
+        if (offset >= 0 &&
+            _wcsicmp(&(process_name[offset]), target_process_name) == 0) {
+          found = true;
+          wprintf(_T("Found %s %u. Injecting a crash.\n"),
+                  target_process_name, process_ids[i]);
+          DWORD thread_id = 0;
+          LPTHREAD_START_ROUTINE func =
+              reinterpret_cast<LPTHREAD_START_ROUTINE>(0x12345678);
+          void* addr_of_param = reinterpret_cast<void*>(0x2491ed8);
+          HANDLE thread_handle = ::CreateRemoteThread(process_handle,
+                                                      NULL,
+                                                      0,
+                                                      func,
+                                                      addr_of_param,
+                                                      CREATE_SUSPENDED,
+                                                      &thread_id);
+          if (!thread_handle) {
+            HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());
+            wprintf(_T("CreateRemoteThread failed.\n"));
+          }
+          if (::ResumeThread(thread_handle) == -1) {
+            wprintf(_T("Resume thread failed.\n"));
+          } else {
+            wprintf(_T("Waiting for process to quit.\n"));
+            ::WaitForSingleObject(thread_handle, 2000);
+          }
+        }
+      }
+
+      ::CloseHandle(process_handle);
+    }
+  }
+
+  if (!found) {
+    wprintf(_T("No %s processes found.\n"), target_process_name);
+  } else {
+    wprintf(_T("Done.\n"));
+  }
+
+  return 0;
+}
+
diff --git a/tools/OmahaCompatibility/HttpServer/Request.h b/tools/OmahaCompatibility/HttpServer/Request.h
index 79fa23e..d76559c 100644
--- a/tools/OmahaCompatibility/HttpServer/Request.h
+++ b/tools/OmahaCompatibility/HttpServer/Request.h
@@ -1,56 +1,56 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_REQUEST_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_REQUEST_H_

-

-#include <http.h>

-#include <winhttp.h>

-

-namespace omaha {

-

-// Represents the HttpRequest received by the server.

-class HttpRequest {

- public:

-  HTTP_VERB http_verb() const { return verb_; }

-  void set_http_verb(HTTP_VERB verb) { verb_ = verb; }

-

-  CString path() const { return path_; }

-  void set_path(const CString& path) { path_ = path; }

-

-  CString content() const { return content_; }

-  void set_content(const CString& content) { content_ = content; }

-

-  HTTP_REQUEST http_request() const { return http_request_; }

-  void set_http_request(const HTTP_REQUEST& request) {

-    http_request_ = request;

-  }

-

-  CString query_str() const { return query_str_; }

-  void set_query_str(const CString& query_str) {

-    query_str_ = query_str;

-  }

-

- private:

-  HTTP_REQUEST http_request_;

-  HTTP_VERB verb_;

-  CString path_;

-  CString content_;

-  CString query_str_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_REQUEST_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_REQUEST_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_REQUEST_H_
+
+#include <http.h>
+#include <winhttp.h>
+
+namespace omaha {
+
+// Represents the HttpRequest received by the server.
+class HttpRequest {
+ public:
+  HTTP_VERB http_verb() const { return verb_; }
+  void set_http_verb(HTTP_VERB verb) { verb_ = verb; }
+
+  CString path() const { return path_; }
+  void set_path(const CString& path) { path_ = path; }
+
+  CString content() const { return content_; }
+  void set_content(const CString& content) { content_ = content; }
+
+  HTTP_REQUEST http_request() const { return http_request_; }
+  void set_http_request(const HTTP_REQUEST& request) {
+    http_request_ = request;
+  }
+
+  CString query_str() const { return query_str_; }
+  void set_query_str(const CString& query_str) {
+    query_str_ = query_str;
+  }
+
+ private:
+  HTTP_REQUEST http_request_;
+  HTTP_VERB verb_;
+  CString path_;
+  CString content_;
+  CString query_str_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_REQUEST_H_
diff --git a/tools/OmahaCompatibility/HttpServer/download_handler.cc b/tools/OmahaCompatibility/HttpServer/download_handler.cc
index 922c5dd..eab5eb5 100644
--- a/tools/OmahaCompatibility/HttpServer/download_handler.cc
+++ b/tools/OmahaCompatibility/HttpServer/download_handler.cc
@@ -1,48 +1,48 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/tools/omahacompatibility/httpserver/download_handler.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-

-namespace omaha {

-

-HRESULT DownloadHandler::HandleRequest(const HttpRequest& request,

-                                       HttpResponse* response) {

-  CORE_LOG(L1, (_T("[DownloadHandler::HandleRequest]")));

-  ASSERT1(response);

-

-  for (size_t i = 0; i < responses_.size(); ++i) {

-    CString requested_file = GetFileFromPath(request.path());

-    if (GetFileFromPath(responses_[i].local_file_name) == requested_file) {

-      // We know about the file that was asked for.

-      response->set_size(responses_[i].size);

-      response->set_file_name(responses_[i].local_file_name);

-      return S_OK;

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT DownloadHandler::AddDownloadFile(const ConfigResponse& response) {

-  CORE_LOG(L1, (_T("[DownloadHandler::AddDownloadFile]")));

-  responses_.push_back(response);

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/tools/omahacompatibility/httpserver/download_handler.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+
+namespace omaha {
+
+HRESULT DownloadHandler::HandleRequest(const HttpRequest& request,
+                                       HttpResponse* response) {
+  CORE_LOG(L1, (_T("[DownloadHandler::HandleRequest]")));
+  ASSERT1(response);
+
+  for (size_t i = 0; i < responses_.size(); ++i) {
+    CString requested_file = GetFileFromPath(request.path());
+    if (GetFileFromPath(responses_[i].local_file_name) == requested_file) {
+      // We know about the file that was asked for.
+      response->set_size(responses_[i].size);
+      response->set_file_name(responses_[i].local_file_name);
+      return S_OK;
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT DownloadHandler::AddDownloadFile(const ConfigResponse& response) {
+  CORE_LOG(L1, (_T("[DownloadHandler::AddDownloadFile]")));
+  responses_.push_back(response);
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/tools/OmahaCompatibility/HttpServer/download_handler.h b/tools/OmahaCompatibility/HttpServer/download_handler.h
index 15ec13b..03626a8 100644
--- a/tools/OmahaCompatibility/HttpServer/download_handler.h
+++ b/tools/OmahaCompatibility/HttpServer/download_handler.h
@@ -1,43 +1,43 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_DOWNLOAD_HANDLER_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_DOWNLOAD_HANDLER_H_

-

-#include <windows.h>

-#include <atlstr.h>

-#include "omaha/tools/omahacompatibility/common/config.h"

-#include "omaha/tools/omahacompatibility/httpserver/request.h"

-#include "omaha/tools/omahacompatibility/httpserver/response.h"

-#include "omaha/tools/omahacompatibility/httpserver/url_handler.h"

-

-namespace omaha {

-

-// Handler for the download path on the server. Returns the size and the

-// local path of the file to be returned for the request.

-class DownloadHandler : public UrlHandler {

- public:

-  explicit DownloadHandler(const CString& url_path) : UrlHandler(url_path) {}

-  virtual ~DownloadHandler() {}

-  HRESULT AddDownloadFile(const ConfigResponse& response);

-  virtual HRESULT HandleRequest(const HttpRequest& request,

-                                HttpResponse* response);

- private:

-  ConfigResponses responses_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_DOWNLOAD_HANDLER_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_DOWNLOAD_HANDLER_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_DOWNLOAD_HANDLER_H_
+
+#include <windows.h>
+#include <atlstr.h>
+#include "omaha/tools/omahacompatibility/common/config.h"
+#include "omaha/tools/omahacompatibility/httpserver/request.h"
+#include "omaha/tools/omahacompatibility/httpserver/response.h"
+#include "omaha/tools/omahacompatibility/httpserver/url_handler.h"
+
+namespace omaha {
+
+// Handler for the download path on the server. Returns the size and the
+// local path of the file to be returned for the request.
+class DownloadHandler : public UrlHandler {
+ public:
+  explicit DownloadHandler(const CString& url_path) : UrlHandler(url_path) {}
+  virtual ~DownloadHandler() {}
+  HRESULT AddDownloadFile(const ConfigResponse& response);
+  virtual HRESULT HandleRequest(const HttpRequest& request,
+                                HttpResponse* response);
+ private:
+  ConfigResponses responses_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_DOWNLOAD_HANDLER_H_
diff --git a/tools/OmahaCompatibility/HttpServer/http_server.cc b/tools/OmahaCompatibility/HttpServer/http_server.cc
index 6598599..0370eac 100644
--- a/tools/OmahaCompatibility/HttpServer/http_server.cc
+++ b/tools/OmahaCompatibility/HttpServer/http_server.cc
@@ -1,347 +1,347 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/tools/omahacompatibility/httpserver/http_server.h"

-

-#include <Windows.h>

-#include <http.h>

-#include <winhttp.h>

-#include "omaha/common/error.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/string.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/reg_key.h"

-

-namespace omaha {

-

-#define MAX_BUFFER_SIZE 4048

-#define INTERNET_MAX_PATH_LENGTH 2048

-

-HttpServer::HttpServer(const CString& host, int port)

-    : host_(host),

-      port_(port) {

-  CORE_LOG(L1, (_T("[HttpServer]")));

-  url_prefix_.Format(_T("http://%s:%d"), host, port);

-}

-

-HttpServer::~HttpServer() {

-  CORE_LOG(L1, (_T("[~HttpServer]")));

-  ::HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);

-

-  std::map<CString, UrlHandler*>::iterator iter = handlers_.begin();

-  for (; iter != handlers_.end(); ++iter) {

-    std::pair<CString, UrlHandler*> pair = *iter;

-    VERIFY1(::HttpRemoveUrl(get(request_handle_),

-                            pair.first) != NO_ERROR);

-    delete pair.second;

-  }

-

-  handlers_.clear();

-}

-

-HRESULT HttpServer::Initialize() {

-  CORE_LOG(L1, (_T("[Initialize]")));

-  HTTPAPI_VERSION version = HTTPAPI_VERSION_1;

-  int ret = ::HttpInitialize(version,

-                             HTTP_INITIALIZE_SERVER,

-                             NULL);

-  if (ret != NO_ERROR) {

-    return HRESULT_FROM_WIN32(ret);

-  }

-

-  ret = ::HttpCreateHttpHandle(address(request_handle_), NULL);

-  if (ret != NO_ERROR) {

-    return HRESULT_FROM_WIN32(ret);

-  }

-  ASSERT1(get(request_handle_));

-

-  return S_OK;

-}

-

-HRESULT HttpServer::AddUrlHandler(UrlHandler* handler) {

-  CORE_LOG(L1, (_T("[AddUrlHandler]")));

-  ASSERT1(handler);

-

-  CString full_url = url_prefix_ + handler->get_url_path();

-  int ret = ::HttpAddUrl(get(request_handle_),

-                         full_url, NULL);

-  if (ret != NO_ERROR) {

-    return HRESULT_FROM_WIN32(ret);

-  }

-

-  ASSERT1(handlers_.find(handler->get_url_path()) == handlers_.end());

-  handlers_[handler->get_url_path()] = handler;

-  return S_OK;

-}

-

-UrlHandler* HttpServer::GetHandler(const HttpRequest& req) {

-  std::map<CString, UrlHandler*>::const_iterator iter = handlers_.begin();

-  for (; iter != handlers_.end(); ++iter) {

-    UrlHandler* handler = (*iter).second;

-

-    // Determine if the handler starts with the path that is specified

-    // in the request.

-    if (req.path().Find(handler->get_url_path()) == 0) {

-      return handler;

-    }

-  }

-

-  ASSERT1(false);

-  return NULL;

-}

-

-HRESULT HttpServer::ReadRequest(HttpRequest* request) {

-  ASSERT1(request);

-

-  TCHAR buffer[MAX_BUFFER_SIZE] = {0};

-  HTTP_REQUEST* req = reinterpret_cast<HTTP_REQUEST*>(buffer);

-  int ret = ::HttpReceiveHttpRequest(get(request_handle_),

-    HTTP_NULL_ID,

-    HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,

-    req,

-    MAX_BUFFER_SIZE,

-    NULL,

-    NULL);

-

-  if (ret != NO_ERROR) {

-    HRESULT hr =  HRESULT_FROM_WIN32(ret);

-    CORE_LOG(L1, (_T("[Failed to read request.][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Figure out the query string and the path.

-  CString url_path(req->pRawUrl);

-  int idx = url_path.ReverseFind(_T('?'));

-  CString query_str;

-  CString path;

-  if (idx != -1) {

-    query_str = url_path.Right(url_path.GetLength() - idx - 1);

-    path = url_path.Left(idx);

-  } else {

-    path = url_path;

-  }

-

-  // Set the values on the request.

-  request->set_http_verb(req->Verb);

-  request->set_path(path);

-  request->set_http_request(*req);

-  request->set_query_str(query_str);

-

-  if (req->Verb == HttpVerbPOST) {

-    DWORD bytes_received = 0;

-    char output_buffer[MAX_BUFFER_SIZE] = {0};

-    ret = ::HttpReceiveRequestEntityBody(get(request_handle_),

-      req->RequestId,

-      0,

-      output_buffer,

-      MAX_BUFFER_SIZE,

-      &bytes_received,

-      NULL);

-

-    if (ret != NO_ERROR) {

-      HRESULT hr =  HRESULT_FROM_WIN32(ret);

-      CORE_LOG(L1, (_T("[Failed to read request.][0x%08x]"), hr));

-      return hr;

-    }

-    CString content = Utf8ToWideChar(output_buffer, bytes_received);

-    request->set_content(content);

-  }

-

-  return S_OK;

-}

-

-HRESULT HttpServer::SetHeader(HTTP_RESPONSE* http_response,

-                              HTTP_HEADER_ID header_id,

-                              const char* value) {

-  ASSERT1(http_response);

-

-  http_response->Headers.KnownHeaders[header_id].pRawValue = value;

-  http_response->Headers.KnownHeaders[header_id].RawValueLength =

-        static_cast<USHORT>(strlen(value));

-  return S_OK;

-}

-

-HRESULT HttpServer::SendResponse(const HttpResponse& response) {

-  const HttpRequest& request = response.request();

-  const char* const kOk = "OK";

-

-  HTTP_RESPONSE http_response = {0};

-  http_response.StatusCode = 200;

-

-  // Send back an ok.

-  http_response.pReason = kOk;

-  http_response.ReasonLength = static_cast<USHORT>(strlen(kOk));

-

-  // No special headers for now.

-  HTTP_RESPONSE_HEADERS headers = {0};

-  headers.UnknownHeaderCount = 0;

-  headers.TrailerCount = 0;

-  http_response.Headers = headers;

-

-  scoped_hfile handle;

-  CStringA request_body_utf8;

-  CStringA content_range_header;

-  int http_response_flag = 0;

-

-  HTTP_DATA_CHUNK chunk;

-  memset(&chunk, 0, sizeof(HTTP_DATA_CHUNK));

-

-  // Based on the verb build a response.

-  if (request.http_verb() == HttpVerbPOST) {

-    // Add a known header of content type.

-    SetHeader(&http_response, HttpHeaderContentType, "text/xml; charset=UTF-8");

-

-    // Send back the content.

-    chunk.DataChunkType = HttpDataChunkFromMemory;

-    CString response_str = response.response_str();

-    request_body_utf8 = CT2A(response_str, CP_UTF8);

-

-    chunk.FromMemory.pBuffer = request_body_utf8.GetBuffer();

-    chunk.FromMemory.BufferLength = request_body_utf8.GetLength();

-

-    http_response.EntityChunkCount = 1;

-    http_response.pEntityChunks = &chunk;

-

-  } else if (request.http_verb() == HttpVerbHEAD) {

-    // Add the content length, type, and content range headers.

-    SetHeader(&http_response, HttpHeaderContentType,

-              "application/octet-stream");

-    char size_str[MAX_PATH] = {0};

-    _itoa(response.size(), size_str, 10);

-    SetHeader(&http_response, HttpHeaderContentLength, size_str);

-    SetHeader(&http_response, HttpHeaderAcceptRanges, "bytes");

-

-  } else if (request.http_verb() == HttpVerbGET) {

-    SetHeader(&http_response, HttpHeaderContentType,

-              "application/octet-stream");

-    char size_str[MAX_PATH] = {0};

-    _itoa(response.size(), size_str, 10);

-    SetHeader(&http_response, HttpHeaderAcceptRanges, "bytes");

-

-    reset(handle, ::CreateFile(response.file_name(), GENERIC_READ,

-                               FILE_SHARE_READ, NULL, OPEN_EXISTING,

-                               FILE_ATTRIBUTE_NORMAL, NULL));

-    if (!handle) {

-      return HRESULTFromLastError();

-    }

-

-    chunk.DataChunkType = HttpDataChunkFromFileHandle;

-

-    // Determine the file portion to send back to the client.

-    // If the client has sent a range request, honor that.

-    int start_file_pos = 0;

-    int end_file_pos = 0;

-    HTTP_REQUEST tmp_request = request.http_request();

-    if (tmp_request.Headers.KnownHeaders[HttpHeaderRange].RawValueLength != 0) {

-      // The client send a content length header. We need to honor this.

-      CStringA content_range(

-          tmp_request.Headers.KnownHeaders[HttpHeaderRange].pRawValue);

-

-      int idx = content_range.Find('-');

-      ASSERT1(idx != -1);

-      end_file_pos = atoi(content_range.Right(

-            content_range.GetLength() - idx - 1));

-      int st_idx = content_range.Find('=');

-      ASSERT1(st_idx != -1);

-      start_file_pos = atoi(content_range.Mid(st_idx + 1, idx));

-

-      // Set the Content-range header in the response.

-      content_range_header.Format("bytes %d-%d/%d",

-                                  start_file_pos,

-                                  end_file_pos, response.size());

-      SetHeader(&http_response, HttpHeaderContentRange, content_range_header);

-

-      // Since this is a range request, we set the http response code to

-      // partial response.

-      http_response.StatusCode = 206;

-

-      // Set the value of the human readable text to partial-content.

-      const char* const kPartialContent = "Partial Content";

-      http_response.pReason = kPartialContent;

-      http_response.ReasonLength = static_cast<USHORT>(strlen(kPartialContent));

-    }

-

-    // Send back the entire file or part of it.

-    HTTP_BYTE_RANGE byte_range = {0};

-    byte_range.StartingOffset.HighPart = 0;

-    byte_range.StartingOffset.LowPart = start_file_pos;

-    if (end_file_pos == 0) {

-      byte_range.Length.QuadPart = HTTP_BYTE_RANGE_TO_EOF;

-    } else {

-      byte_range.Length.QuadPart = end_file_pos - start_file_pos + 1;

-    }

-

-    chunk.FromFileHandle.ByteRange = byte_range;

-    chunk.FromFileHandle.FileHandle = get(handle);

-

-    http_response.EntityChunkCount = 1;

-    http_response.pEntityChunks = &chunk;

-  }

-

-  DWORD bytes_sent = 0;

-  int ret = ::HttpSendHttpResponse(

-      get(request_handle_),

-      request.http_request().RequestId,

-      http_response_flag,

-      &http_response,

-      NULL,

-      &bytes_sent,

-      NULL,

-      0,

-      NULL,

-      NULL);

-  if (ret != NO_ERROR) {

-    return HRESULT_FROM_WIN32(ret);

-  }

-

-  return S_OK;

-}

-

-HRESULT HttpServer::Start() {

-  CORE_LOG(L1, (_T("[Start]")));

-

-  while (true) {

-    HttpRequest request;

-    HRESULT hr = ReadRequest(&request);

-    if (FAILED(hr)) {

-      CORE_LOG(L1, (_T("[ReadRequest failed.][0x%08x]"), hr));

-      continue;

-    }

-

-    HttpResponse response(request);

-    UrlHandler* handler = GetHandler(request);

-    if (handler == NULL) {

-      continue;

-    }

-

-    hr = handler->HandleRequest(request, &response);

-    if (FAILED(hr)) {

-      CORE_LOG(L1, (_T("[HandlerRequest failed.][0x%08x]"), hr));

-      continue;

-    }

-

-    hr = SendResponse(response);

-    if (FAILED(hr)) {

-      CORE_LOG(L1, (_T("[SendRequest failed.][0x%08x]"), hr));

-      continue;

-    }

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/tools/omahacompatibility/httpserver/http_server.h"
+
+#include <Windows.h>
+#include <http.h>
+#include <winhttp.h>
+#include "omaha/common/error.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/string.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/reg_key.h"
+
+namespace omaha {
+
+#define MAX_BUFFER_SIZE 4048
+#define INTERNET_MAX_PATH_LENGTH 2048
+
+HttpServer::HttpServer(const CString& host, int port)
+    : host_(host),
+      port_(port) {
+  CORE_LOG(L1, (_T("[HttpServer]")));
+  url_prefix_.Format(_T("http://%s:%d"), host, port);
+}
+
+HttpServer::~HttpServer() {
+  CORE_LOG(L1, (_T("[~HttpServer]")));
+  ::HttpTerminate(HTTP_INITIALIZE_SERVER, NULL);
+
+  std::map<CString, UrlHandler*>::iterator iter = handlers_.begin();
+  for (; iter != handlers_.end(); ++iter) {
+    std::pair<CString, UrlHandler*> pair = *iter;
+    VERIFY1(::HttpRemoveUrl(get(request_handle_),
+                            pair.first) != NO_ERROR);
+    delete pair.second;
+  }
+
+  handlers_.clear();
+}
+
+HRESULT HttpServer::Initialize() {
+  CORE_LOG(L1, (_T("[Initialize]")));
+  HTTPAPI_VERSION version = HTTPAPI_VERSION_1;
+  int ret = ::HttpInitialize(version,
+                             HTTP_INITIALIZE_SERVER,
+                             NULL);
+  if (ret != NO_ERROR) {
+    return HRESULT_FROM_WIN32(ret);
+  }
+
+  ret = ::HttpCreateHttpHandle(address(request_handle_), NULL);
+  if (ret != NO_ERROR) {
+    return HRESULT_FROM_WIN32(ret);
+  }
+  ASSERT1(get(request_handle_));
+
+  return S_OK;
+}
+
+HRESULT HttpServer::AddUrlHandler(UrlHandler* handler) {
+  CORE_LOG(L1, (_T("[AddUrlHandler]")));
+  ASSERT1(handler);
+
+  CString full_url = url_prefix_ + handler->get_url_path();
+  int ret = ::HttpAddUrl(get(request_handle_),
+                         full_url, NULL);
+  if (ret != NO_ERROR) {
+    return HRESULT_FROM_WIN32(ret);
+  }
+
+  ASSERT1(handlers_.find(handler->get_url_path()) == handlers_.end());
+  handlers_[handler->get_url_path()] = handler;
+  return S_OK;
+}
+
+UrlHandler* HttpServer::GetHandler(const HttpRequest& req) {
+  std::map<CString, UrlHandler*>::const_iterator iter = handlers_.begin();
+  for (; iter != handlers_.end(); ++iter) {
+    UrlHandler* handler = (*iter).second;
+
+    // Determine if the handler starts with the path that is specified
+    // in the request.
+    if (req.path().Find(handler->get_url_path()) == 0) {
+      return handler;
+    }
+  }
+
+  ASSERT1(false);
+  return NULL;
+}
+
+HRESULT HttpServer::ReadRequest(HttpRequest* request) {
+  ASSERT1(request);
+
+  TCHAR buffer[MAX_BUFFER_SIZE] = {0};
+  HTTP_REQUEST* req = reinterpret_cast<HTTP_REQUEST*>(buffer);
+  int ret = ::HttpReceiveHttpRequest(get(request_handle_),
+    HTTP_NULL_ID,
+    HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
+    req,
+    MAX_BUFFER_SIZE,
+    NULL,
+    NULL);
+
+  if (ret != NO_ERROR) {
+    HRESULT hr =  HRESULT_FROM_WIN32(ret);
+    CORE_LOG(L1, (_T("[Failed to read request.][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Figure out the query string and the path.
+  CString url_path(req->pRawUrl);
+  int idx = url_path.ReverseFind(_T('?'));
+  CString query_str;
+  CString path;
+  if (idx != -1) {
+    query_str = url_path.Right(url_path.GetLength() - idx - 1);
+    path = url_path.Left(idx);
+  } else {
+    path = url_path;
+  }
+
+  // Set the values on the request.
+  request->set_http_verb(req->Verb);
+  request->set_path(path);
+  request->set_http_request(*req);
+  request->set_query_str(query_str);
+
+  if (req->Verb == HttpVerbPOST) {
+    DWORD bytes_received = 0;
+    char output_buffer[MAX_BUFFER_SIZE] = {0};
+    ret = ::HttpReceiveRequestEntityBody(get(request_handle_),
+      req->RequestId,
+      0,
+      output_buffer,
+      MAX_BUFFER_SIZE,
+      &bytes_received,
+      NULL);
+
+    if (ret != NO_ERROR) {
+      HRESULT hr =  HRESULT_FROM_WIN32(ret);
+      CORE_LOG(L1, (_T("[Failed to read request.][0x%08x]"), hr));
+      return hr;
+    }
+    CString content = Utf8ToWideChar(output_buffer, bytes_received);
+    request->set_content(content);
+  }
+
+  return S_OK;
+}
+
+HRESULT HttpServer::SetHeader(HTTP_RESPONSE* http_response,
+                              HTTP_HEADER_ID header_id,
+                              const char* value) {
+  ASSERT1(http_response);
+
+  http_response->Headers.KnownHeaders[header_id].pRawValue = value;
+  http_response->Headers.KnownHeaders[header_id].RawValueLength =
+        static_cast<USHORT>(strlen(value));
+  return S_OK;
+}
+
+HRESULT HttpServer::SendResponse(const HttpResponse& response) {
+  const HttpRequest& request = response.request();
+  const char* const kOk = "OK";
+
+  HTTP_RESPONSE http_response = {0};
+  http_response.StatusCode = 200;
+
+  // Send back an ok.
+  http_response.pReason = kOk;
+  http_response.ReasonLength = static_cast<USHORT>(strlen(kOk));
+
+  // No special headers for now.
+  HTTP_RESPONSE_HEADERS headers = {0};
+  headers.UnknownHeaderCount = 0;
+  headers.TrailerCount = 0;
+  http_response.Headers = headers;
+
+  scoped_hfile handle;
+  CStringA request_body_utf8;
+  CStringA content_range_header;
+  int http_response_flag = 0;
+
+  HTTP_DATA_CHUNK chunk;
+  memset(&chunk, 0, sizeof(HTTP_DATA_CHUNK));
+
+  // Based on the verb build a response.
+  if (request.http_verb() == HttpVerbPOST) {
+    // Add a known header of content type.
+    SetHeader(&http_response, HttpHeaderContentType, "text/xml; charset=UTF-8");
+
+    // Send back the content.
+    chunk.DataChunkType = HttpDataChunkFromMemory;
+    CString response_str = response.response_str();
+    request_body_utf8 = CT2A(response_str, CP_UTF8);
+
+    chunk.FromMemory.pBuffer = request_body_utf8.GetBuffer();
+    chunk.FromMemory.BufferLength = request_body_utf8.GetLength();
+
+    http_response.EntityChunkCount = 1;
+    http_response.pEntityChunks = &chunk;
+
+  } else if (request.http_verb() == HttpVerbHEAD) {
+    // Add the content length, type, and content range headers.
+    SetHeader(&http_response, HttpHeaderContentType,
+              "application/octet-stream");
+    char size_str[MAX_PATH] = {0};
+    _itoa(response.size(), size_str, 10);
+    SetHeader(&http_response, HttpHeaderContentLength, size_str);
+    SetHeader(&http_response, HttpHeaderAcceptRanges, "bytes");
+
+  } else if (request.http_verb() == HttpVerbGET) {
+    SetHeader(&http_response, HttpHeaderContentType,
+              "application/octet-stream");
+    char size_str[MAX_PATH] = {0};
+    _itoa(response.size(), size_str, 10);
+    SetHeader(&http_response, HttpHeaderAcceptRanges, "bytes");
+
+    reset(handle, ::CreateFile(response.file_name(), GENERIC_READ,
+                               FILE_SHARE_READ, NULL, OPEN_EXISTING,
+                               FILE_ATTRIBUTE_NORMAL, NULL));
+    if (!handle) {
+      return HRESULTFromLastError();
+    }
+
+    chunk.DataChunkType = HttpDataChunkFromFileHandle;
+
+    // Determine the file portion to send back to the client.
+    // If the client has sent a range request, honor that.
+    int start_file_pos = 0;
+    int end_file_pos = 0;
+    HTTP_REQUEST tmp_request = request.http_request();
+    if (tmp_request.Headers.KnownHeaders[HttpHeaderRange].RawValueLength != 0) {
+      // The client send a content length header. We need to honor this.
+      CStringA content_range(
+          tmp_request.Headers.KnownHeaders[HttpHeaderRange].pRawValue);
+
+      int idx = content_range.Find('-');
+      ASSERT1(idx != -1);
+      end_file_pos = atoi(content_range.Right(
+            content_range.GetLength() - idx - 1));
+      int st_idx = content_range.Find('=');
+      ASSERT1(st_idx != -1);
+      start_file_pos = atoi(content_range.Mid(st_idx + 1, idx));
+
+      // Set the Content-range header in the response.
+      content_range_header.Format("bytes %d-%d/%d",
+                                  start_file_pos,
+                                  end_file_pos, response.size());
+      SetHeader(&http_response, HttpHeaderContentRange, content_range_header);
+
+      // Since this is a range request, we set the http response code to
+      // partial response.
+      http_response.StatusCode = 206;
+
+      // Set the value of the human readable text to partial-content.
+      const char* const kPartialContent = "Partial Content";
+      http_response.pReason = kPartialContent;
+      http_response.ReasonLength = static_cast<USHORT>(strlen(kPartialContent));
+    }
+
+    // Send back the entire file or part of it.
+    HTTP_BYTE_RANGE byte_range = {0};
+    byte_range.StartingOffset.HighPart = 0;
+    byte_range.StartingOffset.LowPart = start_file_pos;
+    if (end_file_pos == 0) {
+      byte_range.Length.QuadPart = HTTP_BYTE_RANGE_TO_EOF;
+    } else {
+      byte_range.Length.QuadPart = end_file_pos - start_file_pos + 1;
+    }
+
+    chunk.FromFileHandle.ByteRange = byte_range;
+    chunk.FromFileHandle.FileHandle = get(handle);
+
+    http_response.EntityChunkCount = 1;
+    http_response.pEntityChunks = &chunk;
+  }
+
+  DWORD bytes_sent = 0;
+  int ret = ::HttpSendHttpResponse(
+      get(request_handle_),
+      request.http_request().RequestId,
+      http_response_flag,
+      &http_response,
+      NULL,
+      &bytes_sent,
+      NULL,
+      0,
+      NULL,
+      NULL);
+  if (ret != NO_ERROR) {
+    return HRESULT_FROM_WIN32(ret);
+  }
+
+  return S_OK;
+}
+
+HRESULT HttpServer::Start() {
+  CORE_LOG(L1, (_T("[Start]")));
+
+  while (true) {
+    HttpRequest request;
+    HRESULT hr = ReadRequest(&request);
+    if (FAILED(hr)) {
+      CORE_LOG(L1, (_T("[ReadRequest failed.][0x%08x]"), hr));
+      continue;
+    }
+
+    HttpResponse response(request);
+    UrlHandler* handler = GetHandler(request);
+    if (handler == NULL) {
+      continue;
+    }
+
+    hr = handler->HandleRequest(request, &response);
+    if (FAILED(hr)) {
+      CORE_LOG(L1, (_T("[HandlerRequest failed.][0x%08x]"), hr));
+      continue;
+    }
+
+    hr = SendResponse(response);
+    if (FAILED(hr)) {
+      CORE_LOG(L1, (_T("[SendRequest failed.][0x%08x]"), hr));
+      continue;
+    }
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/tools/OmahaCompatibility/HttpServer/http_server.h b/tools/OmahaCompatibility/HttpServer/http_server.h
index 64e416c..2807cce 100644
--- a/tools/OmahaCompatibility/HttpServer/http_server.h
+++ b/tools/OmahaCompatibility/HttpServer/http_server.h
@@ -1,58 +1,58 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_HTTP_SERVER_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_HTTP_SERVER_H_

-

-#include <windows.h>

-#include <map>

-#include "omaha/common/scoped_any.h"

-#include "omaha/tools/omahacompatibility/httpserver/url_handler.h"

-#include "omaha/tools/omahacompatibility/httpserver/request.h"

-

-namespace omaha {

-

-// The base http server, it takes in a bunch of handlers for

-// the appropriate paths and invokes them based on the requests

-// that are sent to the server. This is NOT a general purpose

-// server, and handles only the requests necessary to enable

-// omaha client to function correctly.

-class HttpServer {

- public:

-  HttpServer(const CString& host, int port);

-  ~HttpServer();

-  HRESULT Initialize();

-  HRESULT AddUrlHandler(UrlHandler* handler);

-  HRESULT Start();

-

- private:

-  HRESULT Terminate();

-  UrlHandler* GetHandler(const HttpRequest& url);

-  HRESULT ReadRequest(HttpRequest* request);

-  HRESULT SendResponse(const HttpResponse& response);

-  HRESULT SetHeader(HTTP_RESPONSE* http_response,

-                    HTTP_HEADER_ID header_id,

-                    const char* value);

-

-  scoped_handle request_handle_;

-  std::map<CString, UrlHandler*> handlers_;

-  CString host_;

-  CString url_prefix_;

-  int port_;

-};

-

-}  // namespace omaha

-

-#endif  //  OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_HTTP_SERVER_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_HTTP_SERVER_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_HTTP_SERVER_H_
+
+#include <windows.h>
+#include <map>
+#include "omaha/common/scoped_any.h"
+#include "omaha/tools/omahacompatibility/httpserver/url_handler.h"
+#include "omaha/tools/omahacompatibility/httpserver/request.h"
+
+namespace omaha {
+
+// The base http server, it takes in a bunch of handlers for
+// the appropriate paths and invokes them based on the requests
+// that are sent to the server. This is NOT a general purpose
+// server, and handles only the requests necessary to enable
+// omaha client to function correctly.
+class HttpServer {
+ public:
+  HttpServer(const CString& host, int port);
+  ~HttpServer();
+  HRESULT Initialize();
+  HRESULT AddUrlHandler(UrlHandler* handler);
+  HRESULT Start();
+
+ private:
+  HRESULT Terminate();
+  UrlHandler* GetHandler(const HttpRequest& url);
+  HRESULT ReadRequest(HttpRequest* request);
+  HRESULT SendResponse(const HttpResponse& response);
+  HRESULT SetHeader(HTTP_RESPONSE* http_response,
+                    HTTP_HEADER_ID header_id,
+                    const char* value);
+
+  scoped_handle request_handle_;
+  std::map<CString, UrlHandler*> handlers_;
+  CString host_;
+  CString url_prefix_;
+  int port_;
+};
+
+}  // namespace omaha
+
+#endif  //  OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_HTTP_SERVER_H_
diff --git a/tools/OmahaCompatibility/HttpServer/response.h b/tools/OmahaCompatibility/HttpServer/response.h
index 31b2b4e..5fa81e8 100644
--- a/tools/OmahaCompatibility/HttpServer/response.h
+++ b/tools/OmahaCompatibility/HttpServer/response.h
@@ -1,59 +1,59 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_RESPONSE_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_RESPONSE_H_

-

-#include <http.h>

-#include <winhttp.h>

-#include "omaha/tools/omahacompatibility/httpserver/request.h"

-

-namespace omaha {

-

-// This class contains the result of the processing.

-// For update responses it contains the response to the post in the

-// string and for downloads it contains the filename and the size.

-// TODO(omaha): Remove the size and filename from here and make this,

-// class derivable. This will allow the http_server to not deal with

-// the specifics of either a download or update check response.

-class HttpResponse {

- public:

-  explicit HttpResponse(const HttpRequest& request) : request_(request) {}

-  ~HttpResponse() {}

-

-  CString response_str() const { return response_str_; }

-  void set_response_str(const CString& response_str) {

-    response_str_  = response_str;

-  }

-  const HttpRequest& request() const { return request_; }

-

-  int size() const { return size_; }

-  void set_size(int size) { size_ = size; }

-

-  CString file_name() const { return file_name_; }

-  void set_file_name(const CString& filename) { file_name_ = filename; }

-

- private:

-  HttpRequest request_;

-  CString response_str_;

-

-  // This is used for the download responses.

-  int size_;

-  CString file_name_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_RESPONSE_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_RESPONSE_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_RESPONSE_H_
+
+#include <http.h>
+#include <winhttp.h>
+#include "omaha/tools/omahacompatibility/httpserver/request.h"
+
+namespace omaha {
+
+// This class contains the result of the processing.
+// For update responses it contains the response to the post in the
+// string and for downloads it contains the filename and the size.
+// TODO(omaha): Remove the size and filename from here and make this,
+// class derivable. This will allow the http_server to not deal with
+// the specifics of either a download or update check response.
+class HttpResponse {
+ public:
+  explicit HttpResponse(const HttpRequest& request) : request_(request) {}
+  ~HttpResponse() {}
+
+  CString response_str() const { return response_str_; }
+  void set_response_str(const CString& response_str) {
+    response_str_  = response_str;
+  }
+  const HttpRequest& request() const { return request_; }
+
+  int size() const { return size_; }
+  void set_size(int size) { size_ = size; }
+
+  CString file_name() const { return file_name_; }
+  void set_file_name(const CString& filename) { file_name_ = filename; }
+
+ private:
+  HttpRequest request_;
+  CString response_str_;
+
+  // This is used for the download responses.
+  int size_;
+  CString file_name_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_RESPONSE_H_
diff --git a/tools/OmahaCompatibility/HttpServer/update_check_handler.cc b/tools/OmahaCompatibility/HttpServer/update_check_handler.cc
index 2f1e0f4..2e41947 100644
--- a/tools/OmahaCompatibility/HttpServer/update_check_handler.cc
+++ b/tools/OmahaCompatibility/HttpServer/update_check_handler.cc
@@ -1,157 +1,157 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/omahacompatibility/httpserver/update_check_handler.h"

-#include <windows.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/tools/omahacompatibility/common/error.h"

-#include "omaha/tools/omahacompatibility/httpserver/request.h"

-#include "omaha/tools/omahacompatibility/httpserver/xml_parser.h"

-

-namespace omaha {

-

-UpdateCheckHandler::UpdateCheckHandler(const CString& url_path,

-                                       PingObserver* observer)

-    : UrlHandler(url_path),

-      ping_observer_(observer) {

-  CORE_LOG(L1, (_T("[UpdateCheckHandler]")));

-}

-

-// Private method that goes over the request, i.e. the update checks or

-// the pings for each application and constructs an appropriate response.

-// For pings we dont do anything, and for update checks we construct the

-// update response based on the config information.

-HRESULT UpdateCheckHandler::BuildResponse(const AppRequestDataVector& request,

-                                          ServerResponses* responses) {

-  ASSERT1(responses);

-

-  for (size_t i = 0; i < request.size(); ++i) {

-    AppData app_data = request[i].app_data();

-    ServerResponse response;

-    response.guid = GuidToString(app_data.app_guid());

-

-    if (request[i].num_ping_events() > 0) {

-      // This is a ping request. We only handle the ping and nothing else.

-      response.is_ping = true;

-      if (ping_observer_) {

-        ping_observer_->Observe(request[i]);

-      }

-    } else {

-      // We assume this is an update check and send back an appropriate

-      // response.

-      ConfigResponse config_app_response;

-      HRESULT hr = FindResponse(app_data.app_guid(),

-                                app_data.version(),

-                                app_data.ap(),

-                                &config_app_response);

-      if (SUCCEEDED(hr)) {

-        response.is_update_response = true;

-        response.response_data.set_url(config_app_response.url);

-        response.response_data.set_hash(config_app_response.hash);

-        response.response_data.set_needs_admin(config_app_response.needs_admin ?

-                                               omaha::NEEDS_ADMIN_YES :

-                                               omaha::NEEDS_ADMIN_NO);

-        response.response_data.set_size(config_app_response.size);

-      }

-      // Continuing here in the failed case will cause the

-      // is_update_response to be false,

-      // causing the server to respond with no-update.

-    }

-    responses->push_back(response);

-  }

-

-  return S_OK;

-}

-

-HRESULT UpdateCheckHandler::HandleRequest(const HttpRequest& http_request,

-                                          HttpResponse* response) {

-  CORE_LOG(L1, (_T("[UpdateCheckHandler::HandleRequest]")));

-  ASSERT1(response);

-  ASSERT1(http_request.http_verb() == HttpVerbPOST);

-

-  // Parse the request.

-  CORE_LOG(L1, (_T("[Request %s]"), http_request.content()));

-  AppRequestDataVector request;

-  HRESULT hr = ParseUpdateCheck(http_request.content(), &request);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[ParseUpdateCheck failed]")));

-    return hr;

-  }

-

-  // Map the request to a response.

-  ServerResponses responses;

-  hr = BuildResponse(request, &responses);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Convert the response into the response string.

-  CString update_response_str;

-  hr = BuildUpdateResponse(responses, &update_response_str);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[BuildUpdateResponse failed]")));

-    return hr;

-  }

-

-  CORE_LOG(L1, (_T("[Response %s]"), update_response_str));

-  response->set_response_str(update_response_str);

-

-  return S_OK;

-}

-

-HRESULT UpdateCheckHandler::AddAppVersionResponse(

-    const ConfigResponse& response) {

-  CORE_LOG(L1, (_T("[UpdateCheckHandler::AddAppVersionResponse]")));

-  // TODO(omaha): Add duplicate checking.

-

-  config_responses_.push_back(response);

-  return S_OK;

-}

-

-HRESULT UpdateCheckHandler::FindResponse(GUID guid,

-                                         const CString& version,

-                                         const CString& ap,

-                                         ConfigResponse* response) {

-  CORE_LOG(L1, (_T("[UpdateCheckHandler::FindResponse]")));

-  ASSERT1(response);

-

-  // The idea here is that we go over the config responses, for a request

-  // that contains 0.0.0.0 in the request, or empty we return the initial

-  // response, i.e. the first installer we read.

-  // If the version is not empty, then we match it with the previous config

-  // version, i.e. the version that should have been installed,

-  // and return a response if there is a match.

-  if (version.IsEmpty() || version == _T("0.0.0.0")) {

-    // This is the initial response.

-    *response = config_responses_[0];

-    return S_OK;

-  }

-

-  for (size_t i = 1; i < config_responses_.size(); ++i) {

-    if (::IsEqualGUID(config_responses_[i].guid, guid) &&

-        _T("update_app") == ap &&

-        version == config_responses_[i - 1].version) {

-      // This is the second response.

-      *response = config_responses_[i];

-      return S_OK;

-    }

-  }

-

-  return E_FAIL;

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/omahacompatibility/httpserver/update_check_handler.h"
+#include <windows.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/tools/omahacompatibility/common/error.h"
+#include "omaha/tools/omahacompatibility/httpserver/request.h"
+#include "omaha/tools/omahacompatibility/httpserver/xml_parser.h"
+
+namespace omaha {
+
+UpdateCheckHandler::UpdateCheckHandler(const CString& url_path,
+                                       PingObserver* observer)
+    : UrlHandler(url_path),
+      ping_observer_(observer) {
+  CORE_LOG(L1, (_T("[UpdateCheckHandler]")));
+}
+
+// Private method that goes over the request, i.e. the update checks or
+// the pings for each application and constructs an appropriate response.
+// For pings we dont do anything, and for update checks we construct the
+// update response based on the config information.
+HRESULT UpdateCheckHandler::BuildResponse(const AppRequestDataVector& request,
+                                          ServerResponses* responses) {
+  ASSERT1(responses);
+
+  for (size_t i = 0; i < request.size(); ++i) {
+    AppData app_data = request[i].app_data();
+    ServerResponse response;
+    response.guid = GuidToString(app_data.app_guid());
+
+    if (request[i].num_ping_events() > 0) {
+      // This is a ping request. We only handle the ping and nothing else.
+      response.is_ping = true;
+      if (ping_observer_) {
+        ping_observer_->Observe(request[i]);
+      }
+    } else {
+      // We assume this is an update check and send back an appropriate
+      // response.
+      ConfigResponse config_app_response;
+      HRESULT hr = FindResponse(app_data.app_guid(),
+                                app_data.version(),
+                                app_data.ap(),
+                                &config_app_response);
+      if (SUCCEEDED(hr)) {
+        response.is_update_response = true;
+        response.response_data.set_url(config_app_response.url);
+        response.response_data.set_hash(config_app_response.hash);
+        response.response_data.set_needs_admin(config_app_response.needs_admin ?
+                                               omaha::NEEDS_ADMIN_YES :
+                                               omaha::NEEDS_ADMIN_NO);
+        response.response_data.set_size(config_app_response.size);
+      }
+      // Continuing here in the failed case will cause the
+      // is_update_response to be false,
+      // causing the server to respond with no-update.
+    }
+    responses->push_back(response);
+  }
+
+  return S_OK;
+}
+
+HRESULT UpdateCheckHandler::HandleRequest(const HttpRequest& http_request,
+                                          HttpResponse* response) {
+  CORE_LOG(L1, (_T("[UpdateCheckHandler::HandleRequest]")));
+  ASSERT1(response);
+  ASSERT1(http_request.http_verb() == HttpVerbPOST);
+
+  // Parse the request.
+  CORE_LOG(L1, (_T("[Request %s]"), http_request.content()));
+  AppRequestDataVector request;
+  HRESULT hr = ParseUpdateCheck(http_request.content(), &request);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[ParseUpdateCheck failed]")));
+    return hr;
+  }
+
+  // Map the request to a response.
+  ServerResponses responses;
+  hr = BuildResponse(request, &responses);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Convert the response into the response string.
+  CString update_response_str;
+  hr = BuildUpdateResponse(responses, &update_response_str);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[BuildUpdateResponse failed]")));
+    return hr;
+  }
+
+  CORE_LOG(L1, (_T("[Response %s]"), update_response_str));
+  response->set_response_str(update_response_str);
+
+  return S_OK;
+}
+
+HRESULT UpdateCheckHandler::AddAppVersionResponse(
+    const ConfigResponse& response) {
+  CORE_LOG(L1, (_T("[UpdateCheckHandler::AddAppVersionResponse]")));
+  // TODO(omaha): Add duplicate checking.
+
+  config_responses_.push_back(response);
+  return S_OK;
+}
+
+HRESULT UpdateCheckHandler::FindResponse(GUID guid,
+                                         const CString& version,
+                                         const CString& ap,
+                                         ConfigResponse* response) {
+  CORE_LOG(L1, (_T("[UpdateCheckHandler::FindResponse]")));
+  ASSERT1(response);
+
+  // The idea here is that we go over the config responses, for a request
+  // that contains 0.0.0.0 in the request, or empty we return the initial
+  // response, i.e. the first installer we read.
+  // If the version is not empty, then we match it with the previous config
+  // version, i.e. the version that should have been installed,
+  // and return a response if there is a match.
+  if (version.IsEmpty() || version == _T("0.0.0.0")) {
+    // This is the initial response.
+    *response = config_responses_[0];
+    return S_OK;
+  }
+
+  for (size_t i = 1; i < config_responses_.size(); ++i) {
+    if (::IsEqualGUID(config_responses_[i].guid, guid) &&
+        _T("update_app") == ap &&
+        version == config_responses_[i - 1].version) {
+      // This is the second response.
+      *response = config_responses_[i];
+      return S_OK;
+    }
+  }
+
+  return E_FAIL;
+}
+
+}  // namespace omaha
diff --git a/tools/OmahaCompatibility/HttpServer/update_check_handler.h b/tools/OmahaCompatibility/HttpServer/update_check_handler.h
index 822cff3..06f3a84 100644
--- a/tools/OmahaCompatibility/HttpServer/update_check_handler.h
+++ b/tools/OmahaCompatibility/HttpServer/update_check_handler.h
@@ -1,61 +1,61 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_UPDATE_CHECK_HANDLER_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_UPDATE_CHECK_HANDLER_H_

-

-#include <windows.h>

-#include <vector>

-#include <atlstr.h>

-#include "omaha/goopdate/request.h"

-#include "omaha/tools/omahacompatibility/common/config.h"

-#include "omaha/tools/omahacompatibility/common/ping_observer.h"

-#include "omaha/tools/omahacompatibility/httpserver/request.h"

-#include "omaha/tools/omahacompatibility/httpserver/response.h"

-#include "omaha/tools/omahacompatibility/httpserver/url_handler.h"

-#include "omaha/tools/omahacompatibility/httpserver/xml_parser.h"

-

-namespace omaha {

-

-// Handles the update check requests.

-// Initially the configuration information that is used to respond

-// to the requests is simple and only contains a few fields: guid and version.

-//

-// Future: Implement reading the server ascii protocol buffers, and use

-// that as the configuration information.

-class UpdateCheckHandler : public UrlHandler {

- public:

-  UpdateCheckHandler(const CString& url_path, PingObserver* observer);

-  virtual ~UpdateCheckHandler() {}

-

-  HRESULT AddAppVersionResponse(const ConfigResponse& response);

-  virtual HRESULT HandleRequest(const HttpRequest& request,

-                                HttpResponse* response);

- private:

-  // Returns the response structure that matches the guid and version

-  // specified.

-  HRESULT FindResponse(GUID guid,

-                       const CString& version,

-                       const CString& ap,

-                       ConfigResponse* response);

-  HRESULT BuildResponse(const AppRequestDataVector& request,

-                        ServerResponses* responses);

-  std::vector<ConfigResponse> config_responses_;

-  PingObserver* ping_observer_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_UPDATE_CHECK_HANDLER_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_UPDATE_CHECK_HANDLER_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_UPDATE_CHECK_HANDLER_H_
+
+#include <windows.h>
+#include <vector>
+#include <atlstr.h>
+#include "omaha/goopdate/request.h"
+#include "omaha/tools/omahacompatibility/common/config.h"
+#include "omaha/tools/omahacompatibility/common/ping_observer.h"
+#include "omaha/tools/omahacompatibility/httpserver/request.h"
+#include "omaha/tools/omahacompatibility/httpserver/response.h"
+#include "omaha/tools/omahacompatibility/httpserver/url_handler.h"
+#include "omaha/tools/omahacompatibility/httpserver/xml_parser.h"
+
+namespace omaha {
+
+// Handles the update check requests.
+// Initially the configuration information that is used to respond
+// to the requests is simple and only contains a few fields: guid and version.
+//
+// Future: Implement reading the server ascii protocol buffers, and use
+// that as the configuration information.
+class UpdateCheckHandler : public UrlHandler {
+ public:
+  UpdateCheckHandler(const CString& url_path, PingObserver* observer);
+  virtual ~UpdateCheckHandler() {}
+
+  HRESULT AddAppVersionResponse(const ConfigResponse& response);
+  virtual HRESULT HandleRequest(const HttpRequest& request,
+                                HttpResponse* response);
+ private:
+  // Returns the response structure that matches the guid and version
+  // specified.
+  HRESULT FindResponse(GUID guid,
+                       const CString& version,
+                       const CString& ap,
+                       ConfigResponse* response);
+  HRESULT BuildResponse(const AppRequestDataVector& request,
+                        ServerResponses* responses);
+  std::vector<ConfigResponse> config_responses_;
+  PingObserver* ping_observer_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_UPDATE_CHECK_HANDLER_H_
diff --git a/tools/OmahaCompatibility/HttpServer/url_handler.h b/tools/OmahaCompatibility/HttpServer/url_handler.h
index 47007fb..7e685ae 100644
--- a/tools/OmahaCompatibility/HttpServer/url_handler.h
+++ b/tools/OmahaCompatibility/HttpServer/url_handler.h
@@ -1,45 +1,45 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_URL_HANDLER_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_URL_HANDLER_H_

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "omaha/tools/omahacompatibility/httpserver/request.h"

-#include "omaha/tools/omahacompatibility/httpserver/response.h"

-

-namespace omaha {

-

-// Base class that represents a handler for a path to the HttpServer.

-class UrlHandler {

- public:

-  explicit UrlHandler(const CString& url_path) : url_path_(url_path) {

-    url_path_.MakeLower();

-  }

-  virtual ~UrlHandler() {}

-  CString get_url_path() const { return url_path_; }

-  virtual HRESULT HandleRequest(const HttpRequest& request,

-                                HttpResponse* response) = 0;

-

- private:

-  CString url_path_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_URL_HANDLER_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_URL_HANDLER_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_URL_HANDLER_H_
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "omaha/tools/omahacompatibility/httpserver/request.h"
+#include "omaha/tools/omahacompatibility/httpserver/response.h"
+
+namespace omaha {
+
+// Base class that represents a handler for a path to the HttpServer.
+class UrlHandler {
+ public:
+  explicit UrlHandler(const CString& url_path) : url_path_(url_path) {
+    url_path_.MakeLower();
+  }
+  virtual ~UrlHandler() {}
+  CString get_url_path() const { return url_path_; }
+  virtual HRESULT HandleRequest(const HttpRequest& request,
+                                HttpResponse* response) = 0;
+
+ private:
+  CString url_path_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_URL_HANDLER_H_
diff --git a/tools/OmahaCompatibility/HttpServer/xml_parser.cc b/tools/OmahaCompatibility/HttpServer/xml_parser.cc
index 85fb581..4efa7ed 100644
--- a/tools/OmahaCompatibility/HttpServer/xml_parser.cc
+++ b/tools/OmahaCompatibility/HttpServer/xml_parser.cc
@@ -1,398 +1,398 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/tools/omahacompatibility/httpserver/xml_parser.h"

-#include <msxml2.h>

-#include "omaha/common/string.h"

-#include "omaha/common/xml_utils.h"

-#include "omaha/goopdate/goopdate_xml_parser.h"

-

-namespace omaha {

-

-// Constant strings to form the server responses.

-const TCHAR* const kResponseXmlHeader = _T("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");  // NOLINT

-const TCHAR* const kResponseXmlGupdateHeader = _T("<gupdate xmlns=\"http://www.google.com/update2/response\" protocol=\"2.0\">"); // NOLINT

-const TCHAR* const kResponseAppEvent = _T("<app appid=\"%s\" status=\"ok\"><event status=\"ok\"/></app>"); // NOLINT

-const TCHAR* const kResponseAppNoUpdate = _T("<app appid=\"%s\" status=\"ok\"><event status=\"no-update\"/></app>"); // NOLINT

-const TCHAR* const kResponseAppUpdate = _T("<app appid=\"%s\" status=\"ok\"><updatecheck codebase=\"%s\" hash=\"%s\" needsadmin=\"%s\" size=\"%d\" status=\"ok\"/></app>"); // NOLINT

-const TCHAR* const kResponseGupdateEndTag = _T("</gupdate>");

-

-// Constants for creating the xml request.

-namespace Xml {

-  const TCHAR* const kHeaderText =

-    _T("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");

-  const TCHAR* const kProcessingText =

-    _T("version=\"1.0\" encoding=\"UTF-8\"");

-

-  namespace Namespace {

-    const TCHAR* const kRequest = _T("http://www.google.com/update2/request");

-    const TCHAR* const kResponse = _T("http://www.google.com/update2/response");

-    const TCHAR* const kSeed = _T("http://www.google.com/update2/install");

-  }  // Namespace.

-

-  namespace Element {

-    const TCHAR* const kXml = _T("xml");

-    const TCHAR* const kRequests = _T("gupdate");

-    const TCHAR* const kOmahaVersion = _T("updaterversion");

-    const TCHAR* const kOs = _T("os");

-    const TCHAR* const kApp = _T("app");

-    const TCHAR* const kUpdateCheck = _T("updatecheck");

-    const TCHAR* const kPing = _T("ping");

-    const TCHAR* const kEvent = _T("event");

-    const TCHAR* const kComponents = _T("components");

-    const TCHAR* const kComponent = _T("component");

-

-    const TCHAR* const kResponses = _T("gupdate");

-  }  // namespace Element.

-

-  namespace Attribute {

-    const TCHAR* const kActive = _T("active");

-    const TCHAR* const kAdditionalParameter = _T("ap");

-    const TCHAR* const kAppGuid = _T("appguid");

-    const TCHAR* const kApplicationName = _T("appname");

-    const TCHAR* const kAppId = _T("appid");

-    const TCHAR* const kArguments = _T("arguments");

-    const TCHAR* const kBrandCode = _T("brand");

-    const TCHAR* const kBrowserType = _T("browser");

-    const TCHAR* const kClientId = _T("client");

-    const TCHAR* const kCodebase = _T("codebase");

-    const TCHAR* const kCountry = _T("country");

-    const TCHAR* const kErrorCode = _T("errorcode");

-    const TCHAR* const kEventResult = _T("eventresult");

-    const TCHAR* const kEventType = _T("eventtype");

-    const TCHAR* const kExtraCode1 = _T("extracode1");

-    const TCHAR* const kHash = _T("hash");

-    const TCHAR* const kIsMachine = _T("ismachine");

-    const TCHAR* const kInstallationId = _T("iid");

-    const TCHAR* const kInstallSource = _T("installsource");

-    const TCHAR* const kLang = _T("lang");

-    const TCHAR* const kMachineId = _T("machineid");

-    const TCHAR* const kNeedsAdmin = _T("needsadmin");

-    const TCHAR* const kParameter = _T("parameter");

-    const TCHAR* const kPlatform = _T("platform");

-    const TCHAR* const kPreviousVersion = _T("previousversion");

-    const TCHAR* const kProtocol = _T("protocol");

-    const TCHAR* const kServicePack = _T("sp");

-    const TCHAR* const kSessionId = _T("sessionid");

-    const TCHAR* const kSignature = _T("signature");

-    const TCHAR* const kSize = _T("size");

-    const TCHAR* const kStatus = _T("status");

-    const TCHAR* const kSuccessAction = _T("onsuccess");

-    const TCHAR* const kSuccessUrl = _T("successurl");

-    const TCHAR* const kTag = _T("tag");

-    const TCHAR* const kTestSource = _T("testsource");

-    const TCHAR* const kTerminateAllBrowsers = _T("terminateallbrowsers");

-    const TCHAR* const kUserId = _T("userid");

-    const TCHAR* const kVersion = _T("version");

-    const TCHAR* const kXmlns = _T("xmlns");

-    const TCHAR* const kTTToken = _T("tttoken");

-  }  // namespace Attribute.

-

-  namespace Value {

-    const TCHAR* const kRequestType = _T("UpdateRequest");

-    const TCHAR* const kProtocol = _T("2.0");

-    const TCHAR* const kVersion2 = _T("2.0");

-    const TCHAR* const kVersion3 = _T("3.0");

-    const TCHAR* const kTrue = _T("true");

-    const TCHAR* const kFalse = _T("false");

-    const TCHAR* const kStatusError = _T("error");

-    const TCHAR* const kSuccessActionDefault = _T("default");

-    const TCHAR* const kSuccessActionExitSilently = _T("exitsilently");

-    const TCHAR* const kWinPlatform = _T("win");

-

-    const TCHAR* const kStatusOk = kResponseStatusOkValue;

-  }  //  namespace value.

-}  // namespace xml.

-

-HRESULT ReadAttribute(IXMLDOMNode* node,

-                      const TCHAR* attr_name,

-                      BSTR* value) {

-  ASSERT1(node != NULL);

-  ASSERT1(attr_name != NULL);

-  ASSERT1(value != NULL);

-

-  // First read the attributes.

-  CComPtr<IXMLDOMNamedNodeMap> attributes;

-  HRESULT hr = node->get_attributes(&attributes);

-  if (FAILED(hr)) { return hr; }

-  if (!attributes) { return E_FAIL; }  // Protect against msxml S_FALSE return.

-

-  CComPtr<IXMLDOMNode> attribute_node;

-  CComVariant node_value;

-  CComBSTR temp_attr_name(attr_name);

-

-  // Get the attribute using a named node.

-  hr = attributes->getNamedItem(static_cast<BSTR>(temp_attr_name),

-                                &attribute_node);

-  if (FAILED(hr)) { return hr; }

-  if (!attribute_node) { return E_FAIL; }  // Protect against msxml S_FALSE

-                                           // return.

-

-  hr = attribute_node->get_nodeValue(&node_value);

-  if (FAILED(hr)) { return hr; }

-  if (node_value.vt == VT_EMPTY) { return E_FAIL; }

-

-  // Extract the variant into a BSTR.

-  node_value.CopyTo(value);

-

-  return S_OK;

-}

-

-HRESULT ReadIntAttribute(IXMLDOMNode* node,

-                         const TCHAR* attr_name,

-                         int* value) {

-  ASSERT1(node != NULL);

-  ASSERT1(attr_name != NULL);

-  ASSERT1(value != NULL);

-

-  CComBSTR node_value;

-  HRESULT hr = ReadAttribute(node, attr_name, &node_value);

-  if (FAILED(hr)) { return hr; }

-  if (!String_StringToDecimalIntChecked(

-          static_cast<const TCHAR*>(node_value), value)) {

-          return E_FAIL;

-  }

-  return S_OK;

-}

-

-HRESULT ReadGuidAttribute(IXMLDOMNode* node,

-                          const TCHAR* attr_name,

-                          GUID* value) {

-  ASSERT1(node != NULL);

-  ASSERT1(attr_name != NULL);

-  ASSERT1(value != NULL);

-

-  CComBSTR node_value;

-  HRESULT hr = ReadAttribute(node, attr_name, &node_value);

-  if (FAILED(hr)) { return hr; }

-  hr = ::CLSIDFromString(static_cast<TCHAR*>(node_value), value);

-  if (FAILED(hr)) { return hr; }

-

-  return S_OK;

-}

-

-HRESULT ReadStringAttribute(IXMLDOMNode* node,

-                            const TCHAR* attr_name,

-                            CString* value) {

-  ASSERT1(node != NULL);

-  ASSERT1(attr_name != NULL);

-  ASSERT1(value != NULL);

-

-  CComBSTR node_value;

-  HRESULT hr = ReadAttribute(node, attr_name, &node_value);

-  if (FAILED(hr)) { return hr; }

-

-  // Will extract the underlying string.

-  *value = static_cast<TCHAR*>(node_value);

-

-  return S_OK;

-}

-

-HRESULT ParseAppUpdateCheckNode(IXMLDOMNode* node, AppData* request) {

-  ASSERT1(node);

-  ASSERT1(request);

-

-  // Read the tag value.

-  CString str;

-  ReadStringAttribute(node, Xml::Attribute::kTag, &str);

-  request->set_ap(str);

-

-  return S_OK;

-}

-

-HRESULT ParseAppPingNode(IXMLDOMNode* node, AppRequestData* request) {

-  ASSERT1(node);

-  ASSERT1(request);

-

-  // Read the event type.

-  int event_type = 0;

-  HRESULT hr = ReadIntAttribute(node, Xml::Attribute::kEventType, &event_type);

-  if (FAILED(hr)) { return hr; }

-

-  // Read the event result.

-  int event_result = 0;

-  hr = ReadIntAttribute(node, Xml::Attribute::kEventResult, &event_result);

-  if (FAILED(hr)) { return hr; }

-

-  // Read the errorcode.

-  int error_code = 0;

-  hr = ReadIntAttribute(node, Xml::Attribute::kErrorCode, &error_code);

-  if (FAILED(hr)) { return hr; }

-

-  // Read the extracode1.

-  int extra_code = 0;

-  hr = ReadIntAttribute(node, Xml::Attribute::kExtraCode1, &extra_code);

-  if (FAILED(hr)) { return hr; }

-

-  PingEvent ping_event(static_cast<PingEvent::Types>(event_type),

-                       static_cast<PingEvent::Results>(event_result),

-                       error_code,

-                       extra_code,

-                       CString());

-  request->AddPingEvent(ping_event);

-

-  return S_OK;

-}

-

-HRESULT ParseAppNode(IXMLDOMNode* node, AppRequestDataVector* request) {

-  ASSERT1(node);

-  ASSERT1(request);

-

-  AppRequest app_request;

-  AppData app_data;

-  AppRequestData app_request_data;

-

-  // Read the app guid.

-  GUID guid = {0};

-  HRESULT hr = ReadGuidAttribute(node, Xml::Attribute::kAppId, &guid);

-  if (FAILED(hr)) { return hr; }

-  app_data.set_app_guid(guid);

-

-  // Read the app version.

-  CString str;

-  hr = ReadStringAttribute(node, Xml::Attribute::kVersion, &str);

-  if (FAILED(hr)) { return hr; }

-  app_data.set_version(str);

-

-  // Read the app language.

-  hr = ReadStringAttribute(node, Xml::Attribute::kLang, &str);

-  if (FAILED(hr)) { return hr; }

-  app_data.set_language(str);

-

-  CComPtr<IXMLDOMNodeList> child_nodes;

-  // Get all the children of the Node.

-  hr = node->get_childNodes(&child_nodes);

-  if (FAILED(hr)) { return hr; }

-  if (!child_nodes) { return E_FAIL; }  // Protect against msxml S_FALSE return.

-

-  // Go Over all the children and read each of them. we will ignore ones that

-  // we dont understand.

-  hr = child_nodes->reset();

-  if (FAILED(hr)) { return hr; }

-

-  CComPtr<IXMLDOMNode> child_node;

-  while (child_nodes->nextNode(&child_node) != S_FALSE) {

-    XMLFQName child_node_name;

-    hr = GetXMLFQName(child_node, &child_node_name);

-    if (FAILED(hr)) { return hr; }

-

-    if (child_node_name.base == Xml::Element::kUpdateCheck) {

-      // Read in the update check request.

-      hr = ParseAppUpdateCheckNode(child_node, &app_data);

-      if (FAILED(hr)) { return hr; }

-    } else if (child_node_name.base == Xml::Element::kEvent) {

-      // Read in the ping request.

-      hr = ParseAppPingNode(child_node, &app_request_data);

-    }

-

-    child_node = NULL;

-  }

-

-  app_request_data.set_app_data(app_data);

-  request->push_back(app_request_data);

-  return S_OK;

-}

-

-HRESULT ParseGupdateNode(IXMLDOMNode* node, AppRequestDataVector* request) {

-  ASSERT1(node);

-  ASSERT1(request);

-

-  CComPtr<IXMLDOMNodeList> child_nodes;

-  // Get all the children of the Node.

-  HRESULT hr = node->get_childNodes(&child_nodes);

-  if (FAILED(hr)) { return hr; }

-  if (!child_nodes) { return E_FAIL; }  // Protect against msxml S_FALSE return.

-

-  // Go Over all the children and read each of them. we will ignore ones that

-  // we dont understand.

-  hr = child_nodes->reset();

-  if (FAILED(hr)) { return hr; }

-

-  CComPtr<IXMLDOMNode> child_node;

-  while (child_nodes->nextNode(&child_node) != S_FALSE) {

-    XMLFQName child_node_name;

-    hr = GetXMLFQName(child_node, &child_node_name);

-    if (FAILED(hr)) { return hr; }

-

-    if (child_node_name.base == Xml::Element::kApp) {

-      // we got a response we should read that in.

-      hr = ParseAppNode(child_node, request);

-      if (FAILED(hr)) { return hr; }

-    }

-    child_node = NULL;

-  }

-  return S_OK;

-}

-

-HRESULT ParseUpdateCheck(const CString& request_str,

-                         AppRequestDataVector* request) {

-  ASSERT1(request);

-

-  CComPtr<IXMLDOMDocument> document;

-  HRESULT hr = LoadXMLFromMemory(request_str, false, &document);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CComPtr<IXMLDOMElement> document_element;

-  hr = document->get_documentElement(&document_element);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (!document_element) {  // Protect against msxml S_FALSE return.

-    return E_FAIL;

-  }

-

-  return ParseGupdateNode(document_element, request);

-}

-

-HRESULT BuildUpdateResponse(const ServerResponses& responses,

-                            CString* response) {

-  ASSERT1(response);

-

-  CString response_str(kResponseXmlHeader);

-  response_str.Append(kResponseXmlGupdateHeader);

-

-  for (size_t i = 0; i < responses.size(); ++i) {

-    CString guid = responses[i].guid;

-

-    if (responses[i].is_ping) {

-      // If the response is to a ping event, then we just add the ok to the

-      // response. The reason this works is because we either have a ping

-      // request or a update check, never both. If this changes, then we need

-      // to change this code.

-      response_str.AppendFormat(kResponseAppEvent, guid);

-    } else if (responses[i].is_update_response) {

-      // respond with the value of the updates.

-      UpdateResponseData data = responses[i].response_data;

-      response_str.AppendFormat(kResponseAppUpdate,

-                                guid,

-                                data.url(),

-                                data.hash(),

-                                data.needs_admin() ? _T("true") : _T("false"),

-                                data.size());

-    } else {

-      // respond with a no-update.

-      response_str.AppendFormat(kResponseAppNoUpdate, guid);

-    }

-  }

-

-  response_str.Append(kResponseGupdateEndTag);

-  *response = response_str;

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/tools/omahacompatibility/httpserver/xml_parser.h"
+#include <msxml2.h>
+#include "omaha/common/string.h"
+#include "omaha/common/xml_utils.h"
+#include "omaha/goopdate/goopdate_xml_parser.h"
+
+namespace omaha {
+
+// Constant strings to form the server responses.
+const TCHAR* const kResponseXmlHeader = _T("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");  // NOLINT
+const TCHAR* const kResponseXmlGupdateHeader = _T("<gupdate xmlns=\"http://www.google.com/update2/response\" protocol=\"2.0\">"); // NOLINT
+const TCHAR* const kResponseAppEvent = _T("<app appid=\"%s\" status=\"ok\"><event status=\"ok\"/></app>"); // NOLINT
+const TCHAR* const kResponseAppNoUpdate = _T("<app appid=\"%s\" status=\"ok\"><event status=\"no-update\"/></app>"); // NOLINT
+const TCHAR* const kResponseAppUpdate = _T("<app appid=\"%s\" status=\"ok\"><updatecheck codebase=\"%s\" hash=\"%s\" needsadmin=\"%s\" size=\"%d\" status=\"ok\"/></app>"); // NOLINT
+const TCHAR* const kResponseGupdateEndTag = _T("</gupdate>");
+
+// Constants for creating the xml request.
+namespace Xml {
+  const TCHAR* const kHeaderText =
+    _T("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+  const TCHAR* const kProcessingText =
+    _T("version=\"1.0\" encoding=\"UTF-8\"");
+
+  namespace Namespace {
+    const TCHAR* const kRequest = _T("http://www.google.com/update2/request");
+    const TCHAR* const kResponse = _T("http://www.google.com/update2/response");
+    const TCHAR* const kSeed = _T("http://www.google.com/update2/install");
+  }  // Namespace.
+
+  namespace Element {
+    const TCHAR* const kXml = _T("xml");
+    const TCHAR* const kRequests = _T("gupdate");
+    const TCHAR* const kOmahaVersion = _T("updaterversion");
+    const TCHAR* const kOs = _T("os");
+    const TCHAR* const kApp = _T("app");
+    const TCHAR* const kUpdateCheck = _T("updatecheck");
+    const TCHAR* const kPing = _T("ping");
+    const TCHAR* const kEvent = _T("event");
+    const TCHAR* const kComponents = _T("components");
+    const TCHAR* const kComponent = _T("component");
+
+    const TCHAR* const kResponses = _T("gupdate");
+  }  // namespace Element.
+
+  namespace Attribute {
+    const TCHAR* const kActive = _T("active");
+    const TCHAR* const kAdditionalParameter = _T("ap");
+    const TCHAR* const kAppGuid = _T("appguid");
+    const TCHAR* const kApplicationName = _T("appname");
+    const TCHAR* const kAppId = _T("appid");
+    const TCHAR* const kArguments = _T("arguments");
+    const TCHAR* const kBrandCode = _T("brand");
+    const TCHAR* const kBrowserType = _T("browser");
+    const TCHAR* const kClientId = _T("client");
+    const TCHAR* const kCodebase = _T("codebase");
+    const TCHAR* const kCountry = _T("country");
+    const TCHAR* const kErrorCode = _T("errorcode");
+    const TCHAR* const kEventResult = _T("eventresult");
+    const TCHAR* const kEventType = _T("eventtype");
+    const TCHAR* const kExtraCode1 = _T("extracode1");
+    const TCHAR* const kHash = _T("hash");
+    const TCHAR* const kIsMachine = _T("ismachine");
+    const TCHAR* const kInstallationId = _T("iid");
+    const TCHAR* const kInstallSource = _T("installsource");
+    const TCHAR* const kLang = _T("lang");
+    const TCHAR* const kMachineId = _T("machineid");
+    const TCHAR* const kNeedsAdmin = _T("needsadmin");
+    const TCHAR* const kParameter = _T("parameter");
+    const TCHAR* const kPlatform = _T("platform");
+    const TCHAR* const kPreviousVersion = _T("previousversion");
+    const TCHAR* const kProtocol = _T("protocol");
+    const TCHAR* const kServicePack = _T("sp");
+    const TCHAR* const kSessionId = _T("sessionid");
+    const TCHAR* const kSignature = _T("signature");
+    const TCHAR* const kSize = _T("size");
+    const TCHAR* const kStatus = _T("status");
+    const TCHAR* const kSuccessAction = _T("onsuccess");
+    const TCHAR* const kSuccessUrl = _T("successurl");
+    const TCHAR* const kTag = _T("tag");
+    const TCHAR* const kTestSource = _T("testsource");
+    const TCHAR* const kTerminateAllBrowsers = _T("terminateallbrowsers");
+    const TCHAR* const kUserId = _T("userid");
+    const TCHAR* const kVersion = _T("version");
+    const TCHAR* const kXmlns = _T("xmlns");
+    const TCHAR* const kTTToken = _T("tttoken");
+  }  // namespace Attribute.
+
+  namespace Value {
+    const TCHAR* const kRequestType = _T("UpdateRequest");
+    const TCHAR* const kProtocol = _T("2.0");
+    const TCHAR* const kVersion2 = _T("2.0");
+    const TCHAR* const kVersion3 = _T("3.0");
+    const TCHAR* const kTrue = _T("true");
+    const TCHAR* const kFalse = _T("false");
+    const TCHAR* const kStatusError = _T("error");
+    const TCHAR* const kSuccessActionDefault = _T("default");
+    const TCHAR* const kSuccessActionExitSilently = _T("exitsilently");
+    const TCHAR* const kWinPlatform = _T("win");
+
+    const TCHAR* const kStatusOk = kResponseStatusOkValue;
+  }  //  namespace value.
+}  // namespace xml.
+
+HRESULT ReadAttribute(IXMLDOMNode* node,
+                      const TCHAR* attr_name,
+                      BSTR* value) {
+  ASSERT1(node != NULL);
+  ASSERT1(attr_name != NULL);
+  ASSERT1(value != NULL);
+
+  // First read the attributes.
+  CComPtr<IXMLDOMNamedNodeMap> attributes;
+  HRESULT hr = node->get_attributes(&attributes);
+  if (FAILED(hr)) { return hr; }
+  if (!attributes) { return E_FAIL; }  // Protect against msxml S_FALSE return.
+
+  CComPtr<IXMLDOMNode> attribute_node;
+  CComVariant node_value;
+  CComBSTR temp_attr_name(attr_name);
+
+  // Get the attribute using a named node.
+  hr = attributes->getNamedItem(static_cast<BSTR>(temp_attr_name),
+                                &attribute_node);
+  if (FAILED(hr)) { return hr; }
+  if (!attribute_node) { return E_FAIL; }  // Protect against msxml S_FALSE
+                                           // return.
+
+  hr = attribute_node->get_nodeValue(&node_value);
+  if (FAILED(hr)) { return hr; }
+  if (node_value.vt == VT_EMPTY) { return E_FAIL; }
+
+  // Extract the variant into a BSTR.
+  node_value.CopyTo(value);
+
+  return S_OK;
+}
+
+HRESULT ReadIntAttribute(IXMLDOMNode* node,
+                         const TCHAR* attr_name,
+                         int* value) {
+  ASSERT1(node != NULL);
+  ASSERT1(attr_name != NULL);
+  ASSERT1(value != NULL);
+
+  CComBSTR node_value;
+  HRESULT hr = ReadAttribute(node, attr_name, &node_value);
+  if (FAILED(hr)) { return hr; }
+  if (!String_StringToDecimalIntChecked(
+          static_cast<const TCHAR*>(node_value), value)) {
+          return E_FAIL;
+  }
+  return S_OK;
+}
+
+HRESULT ReadGuidAttribute(IXMLDOMNode* node,
+                          const TCHAR* attr_name,
+                          GUID* value) {
+  ASSERT1(node != NULL);
+  ASSERT1(attr_name != NULL);
+  ASSERT1(value != NULL);
+
+  CComBSTR node_value;
+  HRESULT hr = ReadAttribute(node, attr_name, &node_value);
+  if (FAILED(hr)) { return hr; }
+  hr = ::CLSIDFromString(static_cast<TCHAR*>(node_value), value);
+  if (FAILED(hr)) { return hr; }
+
+  return S_OK;
+}
+
+HRESULT ReadStringAttribute(IXMLDOMNode* node,
+                            const TCHAR* attr_name,
+                            CString* value) {
+  ASSERT1(node != NULL);
+  ASSERT1(attr_name != NULL);
+  ASSERT1(value != NULL);
+
+  CComBSTR node_value;
+  HRESULT hr = ReadAttribute(node, attr_name, &node_value);
+  if (FAILED(hr)) { return hr; }
+
+  // Will extract the underlying string.
+  *value = static_cast<TCHAR*>(node_value);
+
+  return S_OK;
+}
+
+HRESULT ParseAppUpdateCheckNode(IXMLDOMNode* node, AppData* request) {
+  ASSERT1(node);
+  ASSERT1(request);
+
+  // Read the tag value.
+  CString str;
+  ReadStringAttribute(node, Xml::Attribute::kTag, &str);
+  request->set_ap(str);
+
+  return S_OK;
+}
+
+HRESULT ParseAppPingNode(IXMLDOMNode* node, AppRequestData* request) {
+  ASSERT1(node);
+  ASSERT1(request);
+
+  // Read the event type.
+  int event_type = 0;
+  HRESULT hr = ReadIntAttribute(node, Xml::Attribute::kEventType, &event_type);
+  if (FAILED(hr)) { return hr; }
+
+  // Read the event result.
+  int event_result = 0;
+  hr = ReadIntAttribute(node, Xml::Attribute::kEventResult, &event_result);
+  if (FAILED(hr)) { return hr; }
+
+  // Read the errorcode.
+  int error_code = 0;
+  hr = ReadIntAttribute(node, Xml::Attribute::kErrorCode, &error_code);
+  if (FAILED(hr)) { return hr; }
+
+  // Read the extracode1.
+  int extra_code = 0;
+  hr = ReadIntAttribute(node, Xml::Attribute::kExtraCode1, &extra_code);
+  if (FAILED(hr)) { return hr; }
+
+  PingEvent ping_event(static_cast<PingEvent::Types>(event_type),
+                       static_cast<PingEvent::Results>(event_result),
+                       error_code,
+                       extra_code,
+                       CString());
+  request->AddPingEvent(ping_event);
+
+  return S_OK;
+}
+
+HRESULT ParseAppNode(IXMLDOMNode* node, AppRequestDataVector* request) {
+  ASSERT1(node);
+  ASSERT1(request);
+
+  AppRequest app_request;
+  AppData app_data;
+  AppRequestData app_request_data;
+
+  // Read the app guid.
+  GUID guid = {0};
+  HRESULT hr = ReadGuidAttribute(node, Xml::Attribute::kAppId, &guid);
+  if (FAILED(hr)) { return hr; }
+  app_data.set_app_guid(guid);
+
+  // Read the app version.
+  CString str;
+  hr = ReadStringAttribute(node, Xml::Attribute::kVersion, &str);
+  if (FAILED(hr)) { return hr; }
+  app_data.set_version(str);
+
+  // Read the app language.
+  hr = ReadStringAttribute(node, Xml::Attribute::kLang, &str);
+  if (FAILED(hr)) { return hr; }
+  app_data.set_language(str);
+
+  CComPtr<IXMLDOMNodeList> child_nodes;
+  // Get all the children of the Node.
+  hr = node->get_childNodes(&child_nodes);
+  if (FAILED(hr)) { return hr; }
+  if (!child_nodes) { return E_FAIL; }  // Protect against msxml S_FALSE return.
+
+  // Go Over all the children and read each of them. we will ignore ones that
+  // we dont understand.
+  hr = child_nodes->reset();
+  if (FAILED(hr)) { return hr; }
+
+  CComPtr<IXMLDOMNode> child_node;
+  while (child_nodes->nextNode(&child_node) != S_FALSE) {
+    XMLFQName child_node_name;
+    hr = GetXMLFQName(child_node, &child_node_name);
+    if (FAILED(hr)) { return hr; }
+
+    if (child_node_name.base == Xml::Element::kUpdateCheck) {
+      // Read in the update check request.
+      hr = ParseAppUpdateCheckNode(child_node, &app_data);
+      if (FAILED(hr)) { return hr; }
+    } else if (child_node_name.base == Xml::Element::kEvent) {
+      // Read in the ping request.
+      hr = ParseAppPingNode(child_node, &app_request_data);
+    }
+
+    child_node = NULL;
+  }
+
+  app_request_data.set_app_data(app_data);
+  request->push_back(app_request_data);
+  return S_OK;
+}
+
+HRESULT ParseGupdateNode(IXMLDOMNode* node, AppRequestDataVector* request) {
+  ASSERT1(node);
+  ASSERT1(request);
+
+  CComPtr<IXMLDOMNodeList> child_nodes;
+  // Get all the children of the Node.
+  HRESULT hr = node->get_childNodes(&child_nodes);
+  if (FAILED(hr)) { return hr; }
+  if (!child_nodes) { return E_FAIL; }  // Protect against msxml S_FALSE return.
+
+  // Go Over all the children and read each of them. we will ignore ones that
+  // we dont understand.
+  hr = child_nodes->reset();
+  if (FAILED(hr)) { return hr; }
+
+  CComPtr<IXMLDOMNode> child_node;
+  while (child_nodes->nextNode(&child_node) != S_FALSE) {
+    XMLFQName child_node_name;
+    hr = GetXMLFQName(child_node, &child_node_name);
+    if (FAILED(hr)) { return hr; }
+
+    if (child_node_name.base == Xml::Element::kApp) {
+      // we got a response we should read that in.
+      hr = ParseAppNode(child_node, request);
+      if (FAILED(hr)) { return hr; }
+    }
+    child_node = NULL;
+  }
+  return S_OK;
+}
+
+HRESULT ParseUpdateCheck(const CString& request_str,
+                         AppRequestDataVector* request) {
+  ASSERT1(request);
+
+  CComPtr<IXMLDOMDocument> document;
+  HRESULT hr = LoadXMLFromMemory(request_str, false, &document);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CComPtr<IXMLDOMElement> document_element;
+  hr = document->get_documentElement(&document_element);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (!document_element) {  // Protect against msxml S_FALSE return.
+    return E_FAIL;
+  }
+
+  return ParseGupdateNode(document_element, request);
+}
+
+HRESULT BuildUpdateResponse(const ServerResponses& responses,
+                            CString* response) {
+  ASSERT1(response);
+
+  CString response_str(kResponseXmlHeader);
+  response_str.Append(kResponseXmlGupdateHeader);
+
+  for (size_t i = 0; i < responses.size(); ++i) {
+    CString guid = responses[i].guid;
+
+    if (responses[i].is_ping) {
+      // If the response is to a ping event, then we just add the ok to the
+      // response. The reason this works is because we either have a ping
+      // request or a update check, never both. If this changes, then we need
+      // to change this code.
+      response_str.AppendFormat(kResponseAppEvent, guid);
+    } else if (responses[i].is_update_response) {
+      // respond with the value of the updates.
+      UpdateResponseData data = responses[i].response_data;
+      response_str.AppendFormat(kResponseAppUpdate,
+                                guid,
+                                data.url(),
+                                data.hash(),
+                                data.needs_admin() ? _T("true") : _T("false"),
+                                data.size());
+    } else {
+      // respond with a no-update.
+      response_str.AppendFormat(kResponseAppNoUpdate, guid);
+    }
+  }
+
+  response_str.Append(kResponseGupdateEndTag);
+  *response = response_str;
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/tools/OmahaCompatibility/HttpServer/xml_parser.h b/tools/OmahaCompatibility/HttpServer/xml_parser.h
index 102baed..b5da2b9 100644
--- a/tools/OmahaCompatibility/HttpServer/xml_parser.h
+++ b/tools/OmahaCompatibility/HttpServer/xml_parser.h
@@ -1,52 +1,52 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_XML_PARSER_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_XML_PARSER_H_

-

-#include <vector>

-#include "omaha/goopdate/request.h"

-#include "omaha/goopdate/update_response_data.h"

-#include "omaha/goopdate/update_response.h"

-#include "omaha/worker/app_request.h"

-

-namespace omaha {

-

-// Represents the server response to a get, if the request is a ping,

-// the server just responds with a ok. For now we only support

-// responses for update checks with update or no-update. Later on

-// extend the is_update_response to be a enum

-struct ServerResponse {

-  ServerResponse()

-    : is_ping(false),

-      is_update_response(false) {}

-

-  bool is_ping;

-  bool is_update_response;

-  CString guid;

-  UpdateResponseData response_data;

-};

-

-typedef std::vector<ServerResponse> ServerResponses;

-

-HRESULT ParseUpdateCheck(const CString& post_string,

-                         AppRequestDataVector* request);

-

-HRESULT BuildUpdateResponse(const ServerResponses& update_response,

-                            CString* response);

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_XML_PARSER_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_XML_PARSER_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_XML_PARSER_H_
+
+#include <vector>
+#include "omaha/goopdate/request.h"
+#include "omaha/goopdate/update_response_data.h"
+#include "omaha/goopdate/update_response.h"
+#include "omaha/worker/app_request.h"
+
+namespace omaha {
+
+// Represents the server response to a get, if the request is a ping,
+// the server just responds with a ok. For now we only support
+// responses for update checks with update or no-update. Later on
+// extend the is_update_response to be a enum
+struct ServerResponse {
+  ServerResponse()
+    : is_ping(false),
+      is_update_response(false) {}
+
+  bool is_ping;
+  bool is_update_response;
+  CString guid;
+  UpdateResponseData response_data;
+};
+
+typedef std::vector<ServerResponse> ServerResponses;
+
+HRESULT ParseUpdateCheck(const CString& post_string,
+                         AppRequestDataVector* request);
+
+HRESULT BuildUpdateResponse(const ServerResponses& update_response,
+                            CString* response);
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_HTTPSERVER_XML_PARSER_H_
diff --git a/tools/OmahaCompatibility/build.scons b/tools/OmahaCompatibility/build.scons
index 17136c0..1b57231 100644
--- a/tools/OmahaCompatibility/build.scons
+++ b/tools/OmahaCompatibility/build.scons
@@ -1,95 +1,95 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-local_env = env.Clone()

-local_env.Append(

-    LIBS = [

-        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],

-        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[local_env.Bit('debug')],

-        'comctl32.lib',

-        'crypt32.lib',

-        'delayimp.lib',

-        'httpapi.lib',

-        'iphlpapi.lib',

-        'netapi32.lib',

-        'msi.lib',

-        'mstask.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'rpcns4.lib',

-        'rpcrt4.lib',

-        'shlwapi.lib',

-        'version.lib',

-        'userenv.lib',

-        'wininet.lib',

-        'winhttp.lib',

-        'wintrust.lib',

-        'ws2_32.lib',

-        'wtsapi32.lib',

-

-        '$LIB_DIR/breakpad.lib',

-        '$LIB_DIR/common.lib',

-        '$LIB_DIR/core.lib',

-        '$LIB_DIR/goopdate_dll.lib',

-        '$LIB_DIR/google_update_ps.lib',

-        '$LIB_DIR/google_update_recovery.lib',

-        '$LIB_DIR/logging.lib',

-        '$LIB_DIR/net.lib',

-        '$LIB_DIR/repair_goopdate.lib',

-        '$LIB_DIR/security.lib',

-        '$LIB_DIR/service.lib',

-        '$LIB_DIR/setup.lib',

-        '$LIB_DIR/statsreport.lib',

-        '$LIB_DIR/worker.lib',

-        ],

-    CPPDEFINES = [

-        'UNICODE',

-        '_UNICODE'

-        ],

-)

-

-local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-# Avoid conflict over common/apply_tag.obj

-local_env.Dir('.').addRepository(local_env.Dir('$MAIN_DIR/common'))

-

-target_name = 'gucompat.exe'

-

-inputs = [

-    'main.cc',

-    'console_writer.cc',

-    'compatibility_test.cc',

-    'common/config.cc',

-    'HttpServer/http_server.cc',

-    'HttpServer/download_handler.cc',

-    'HttpServer/update_check_handler.cc',

-    'HttpServer/xml_parser.cc',

-    'apply_tag.cc',  # Comes from $MAIN_DIR/common

-    ]

-if env.Bit('use_precompiled_headers'):

-  inputs += local_env.EnablePrecompile(target_name)

-

-local_env.ComponentProgram(

-    prog_name=target_name,

-    source=inputs,

-)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+local_env = env.Clone()
+local_env.Append(
+    LIBS = [
+        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],
+        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[local_env.Bit('debug')],
+        'comctl32.lib',
+        'crypt32.lib',
+        'delayimp.lib',
+        'httpapi.lib',
+        'iphlpapi.lib',
+        'netapi32.lib',
+        'msi.lib',
+        'mstask.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'rpcns4.lib',
+        'rpcrt4.lib',
+        'shlwapi.lib',
+        'version.lib',
+        'userenv.lib',
+        'wininet.lib',
+        'winhttp.lib',
+        'wintrust.lib',
+        'ws2_32.lib',
+        'wtsapi32.lib',
+
+        '$LIB_DIR/breakpad.lib',
+        '$LIB_DIR/common.lib',
+        '$LIB_DIR/core.lib',
+        '$LIB_DIR/goopdate_dll.lib',
+        '$LIB_DIR/google_update_ps.lib',
+        '$LIB_DIR/google_update_recovery.lib',
+        '$LIB_DIR/logging.lib',
+        '$LIB_DIR/net.lib',
+        '$LIB_DIR/repair_goopdate.lib',
+        '$LIB_DIR/security.lib',
+        '$LIB_DIR/service.lib',
+        '$LIB_DIR/setup.lib',
+        '$LIB_DIR/statsreport.lib',
+        '$LIB_DIR/worker.lib',
+        ],
+    CPPDEFINES = [
+        'UNICODE',
+        '_UNICODE'
+        ],
+)
+
+local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+# Avoid conflict over common/apply_tag.obj
+local_env.Dir('.').addRepository(local_env.Dir('$MAIN_DIR/common'))
+
+target_name = 'gucompat.exe'
+
+inputs = [
+    'main.cc',
+    'console_writer.cc',
+    'compatibility_test.cc',
+    'common/config.cc',
+    'HttpServer/http_server.cc',
+    'HttpServer/download_handler.cc',
+    'HttpServer/update_check_handler.cc',
+    'HttpServer/xml_parser.cc',
+    'apply_tag.cc',  # Comes from $MAIN_DIR/common
+    ]
+if env.Bit('use_precompiled_headers'):
+  inputs += local_env.EnablePrecompile(target_name)
+
+local_env.ComponentProgram(
+    prog_name=target_name,
+    source=inputs,
+)
diff --git a/tools/OmahaCompatibility/common/config.cc b/tools/OmahaCompatibility/common/config.cc
index 8248ef2..d5539c1 100644
--- a/tools/OmahaCompatibility/common/config.cc
+++ b/tools/OmahaCompatibility/common/config.cc
@@ -1,188 +1,188 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/tools/omahacompatibility/common/config.h"

-#include <windows.h>

-#include <wincrypt.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/signatures.h"

-#include "omaha/common/path.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-const TCHAR* const kConfigApplicationProfile = _T("Application");

-const TCHAR* const kConfigAppName = _T("AppName");

-const TCHAR* const kConfigAppGuid = _T("AppGuid");

-const TCHAR* const kConfigAppNeedsAdmin = _T("NeedsAdmin");

-const TCHAR* const kConfigAppLanguage = _T("Language");

-const TCHAR* const kConfigAppVersion1 = _T("Version1");

-const TCHAR* const kConfigAppInstaller1 = _T("Installer1");

-const TCHAR* const kConfigAppVersion2 = _T("Version2");

-const TCHAR* const kConfigAppInstaller2 = _T("Installer2");

-

-bool ComputeSHA(const CString& file_name, ConfigResponse* response) {

-  ASSERT1(response);

-

-  std::vector<CString> files;

-  std::vector<byte> hash_vector;

-  files.push_back(file_name);

-

-  // Check if the file exists

-  WIN32_FILE_ATTRIBUTE_DATA attrs;

-  BOOL success = GetFileAttributesEx(file_name, GetFileExInfoStandard, &attrs);

-  if (!success) {

-    return false;

-  }

-

-  // Calculate the hash

-  CryptoHash crypto;

-  crypto.Compute(files, 512000000L, &hash_vector);

-  CString encoded;

-  Base64::Encode(hash_vector, &encoded);

-  response->hash = encoded;

-  response->size = attrs.nFileSizeLow;

-

-  return true;

-}

-

-HRESULT ReadProfileString(const CString& file_name,

-                          const CString& key_name,

-                          CString* value) {

-  CString val;

-  DWORD ret = ::GetPrivateProfileString(kConfigApplicationProfile,

-                                        key_name,

-                                        _T(""),

-                                        CStrBuf(val, MAX_PATH),

-                                        MAX_PATH,

-                                        file_name);

-  if (ret == MAX_PATH - 1) {

-    return E_FAIL;

-  }

-  *value = val;

-

-  return S_OK;

-}

-

-HRESULT ReadConfigFile(const CString& file_name,

-                       const CString& download_url_prefix,

-                       ConfigResponses* config_responses) {

-  ASSERT1(config_responses);

-

-  ConfigResponse config_response;

-

-  CString app_name;

-  HRESULT hr = ReadProfileString(file_name, kConfigAppName, &app_name);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  config_response.app_name = app_name;

-

-  CString app_guid;

-  hr = ReadProfileString(file_name, kConfigAppGuid, &app_guid);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  config_response.guid = StringToGuid(app_guid);

-

-  CString needs_admin;

-  hr = ReadProfileString(file_name, kConfigAppNeedsAdmin, &needs_admin);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  const TCHAR* const kFalse = _T("false");

-  if (_wcsnicmp(kFalse, needs_admin, wcslen(kFalse)) == 0) {

-    config_response.needs_admin = false;

-  } else {

-    config_response.needs_admin = true;

-  }

-

-  CString language;

-  hr = ReadProfileString(file_name, kConfigAppLanguage, &language);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  config_response.language = language;

-

-

-  // Read the first config.

-  ConfigResponse config_response1 = config_response;

-  CString installer1;

-  hr = ReadProfileString(file_name, kConfigAppInstaller1, &installer1);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (!File::Exists(installer1)) {

-    printf("Error: Could not open file %s\n", installer1);

-    printf("Make sure you specify an absolute path to the file\n");

-    return E_FAIL;

-  }

-

-  if (!ComputeSHA(installer1, &config_response1)) {

-    return E_FAIL;

-  }

-

-  CString version1;

-  hr = ReadProfileString(file_name, kConfigAppVersion1, &version1);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  config_response1.version = version1;

-  config_response1.local_file_name = installer1;

-  config_response1.url = download_url_prefix + _T("/") +

-                         GetFileFromPath(installer1);

-

-  // Read the second config.

-  ConfigResponse config_response2 = config_response;

-  CString installer2;

-  hr = ReadProfileString(file_name, kConfigAppInstaller2, &installer2);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (!File::Exists(installer2)) {

-    printf("Error: Could not open file %s\n", installer1);

-    printf("Make sure you specify an absolute path to the file\n");

-    return E_FAIL;

-  }

-  if (!ComputeSHA(installer2, &config_response2)) {

-    return E_FAIL;

-  }

-

-  CString version2;

-  hr = ReadProfileString(file_name, kConfigAppVersion2, &version2);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  config_response2.version = version2;

-  config_response2.local_file_name = installer2;

-  config_response2.url = download_url_prefix + _T("/") +

-                         GetFileFromPath(installer2);

-

-  // Return the results.

-  config_responses->push_back(config_response1);

-  config_responses->push_back(config_response2);

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/tools/omahacompatibility/common/config.h"
+#include <windows.h>
+#include <wincrypt.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/signatures.h"
+#include "omaha/common/path.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+const TCHAR* const kConfigApplicationProfile = _T("Application");
+const TCHAR* const kConfigAppName = _T("AppName");
+const TCHAR* const kConfigAppGuid = _T("AppGuid");
+const TCHAR* const kConfigAppNeedsAdmin = _T("NeedsAdmin");
+const TCHAR* const kConfigAppLanguage = _T("Language");
+const TCHAR* const kConfigAppVersion1 = _T("Version1");
+const TCHAR* const kConfigAppInstaller1 = _T("Installer1");
+const TCHAR* const kConfigAppVersion2 = _T("Version2");
+const TCHAR* const kConfigAppInstaller2 = _T("Installer2");
+
+bool ComputeSHA(const CString& file_name, ConfigResponse* response) {
+  ASSERT1(response);
+
+  std::vector<CString> files;
+  std::vector<byte> hash_vector;
+  files.push_back(file_name);
+
+  // Check if the file exists
+  WIN32_FILE_ATTRIBUTE_DATA attrs;
+  BOOL success = GetFileAttributesEx(file_name, GetFileExInfoStandard, &attrs);
+  if (!success) {
+    return false;
+  }
+
+  // Calculate the hash
+  CryptoHash crypto;
+  crypto.Compute(files, 512000000L, &hash_vector);
+  CString encoded;
+  Base64::Encode(hash_vector, &encoded);
+  response->hash = encoded;
+  response->size = attrs.nFileSizeLow;
+
+  return true;
+}
+
+HRESULT ReadProfileString(const CString& file_name,
+                          const CString& key_name,
+                          CString* value) {
+  CString val;
+  DWORD ret = ::GetPrivateProfileString(kConfigApplicationProfile,
+                                        key_name,
+                                        _T(""),
+                                        CStrBuf(val, MAX_PATH),
+                                        MAX_PATH,
+                                        file_name);
+  if (ret == MAX_PATH - 1) {
+    return E_FAIL;
+  }
+  *value = val;
+
+  return S_OK;
+}
+
+HRESULT ReadConfigFile(const CString& file_name,
+                       const CString& download_url_prefix,
+                       ConfigResponses* config_responses) {
+  ASSERT1(config_responses);
+
+  ConfigResponse config_response;
+
+  CString app_name;
+  HRESULT hr = ReadProfileString(file_name, kConfigAppName, &app_name);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  config_response.app_name = app_name;
+
+  CString app_guid;
+  hr = ReadProfileString(file_name, kConfigAppGuid, &app_guid);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  config_response.guid = StringToGuid(app_guid);
+
+  CString needs_admin;
+  hr = ReadProfileString(file_name, kConfigAppNeedsAdmin, &needs_admin);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  const TCHAR* const kFalse = _T("false");
+  if (_wcsnicmp(kFalse, needs_admin, wcslen(kFalse)) == 0) {
+    config_response.needs_admin = false;
+  } else {
+    config_response.needs_admin = true;
+  }
+
+  CString language;
+  hr = ReadProfileString(file_name, kConfigAppLanguage, &language);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  config_response.language = language;
+
+
+  // Read the first config.
+  ConfigResponse config_response1 = config_response;
+  CString installer1;
+  hr = ReadProfileString(file_name, kConfigAppInstaller1, &installer1);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (!File::Exists(installer1)) {
+    printf("Error: Could not open file %s\n", installer1);
+    printf("Make sure you specify an absolute path to the file\n");
+    return E_FAIL;
+  }
+
+  if (!ComputeSHA(installer1, &config_response1)) {
+    return E_FAIL;
+  }
+
+  CString version1;
+  hr = ReadProfileString(file_name, kConfigAppVersion1, &version1);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  config_response1.version = version1;
+  config_response1.local_file_name = installer1;
+  config_response1.url = download_url_prefix + _T("/") +
+                         GetFileFromPath(installer1);
+
+  // Read the second config.
+  ConfigResponse config_response2 = config_response;
+  CString installer2;
+  hr = ReadProfileString(file_name, kConfigAppInstaller2, &installer2);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (!File::Exists(installer2)) {
+    printf("Error: Could not open file %s\n", installer1);
+    printf("Make sure you specify an absolute path to the file\n");
+    return E_FAIL;
+  }
+  if (!ComputeSHA(installer2, &config_response2)) {
+    return E_FAIL;
+  }
+
+  CString version2;
+  hr = ReadProfileString(file_name, kConfigAppVersion2, &version2);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  config_response2.version = version2;
+  config_response2.local_file_name = installer2;
+  config_response2.url = download_url_prefix + _T("/") +
+                         GetFileFromPath(installer2);
+
+  // Return the results.
+  config_responses->push_back(config_response1);
+  config_responses->push_back(config_response2);
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/tools/OmahaCompatibility/common/config.h b/tools/OmahaCompatibility/common/config.h
index f5c4f48..935be80 100644
--- a/tools/OmahaCompatibility/common/config.h
+++ b/tools/OmahaCompatibility/common/config.h
@@ -1,66 +1,66 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_CONFIG_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_CONFIG_H_

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-

-namespace omaha {

-

-// This struct is used to hold the responses to give to a particular

-// application. It holds only the very basic information that is needed

-// to accomplish this. The real ascii protocol buffer used by the server

-// contains a lot more fields.

-struct ConfigResponse {

-  ConfigResponse(GUID g, const CString& v, const CString& u,

-                 const CString& h, int s, bool b)

-      : guid(g),

-        version(v),

-        url(u),

-        hash(h),

-        size(s),

-        needs_admin(b) {}

-

-  // The information to match the request against.

-  ConfigResponse() {}

-  CString app_name;

-  GUID guid;

-  CString version;

-  CString language;

-

-  // Response values.

-  CString local_file_name;

-  CString url;

-  CString hash;

-  int size;

-  bool needs_admin;

-};

-

-typedef std::vector<ConfigResponse> ConfigResponses;

-

-

-// Reads a config file that contains the specification

-// of the update responses of the server.

-// For an example of this file see example_config.txt.

-HRESULT ReadConfigFile(const CString& file_name,

-                       const CString& download_url_prefix,

-                       ConfigResponses* config_response);

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_CONFIG_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_CONFIG_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_CONFIG_H_
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+
+namespace omaha {
+
+// This struct is used to hold the responses to give to a particular
+// application. It holds only the very basic information that is needed
+// to accomplish this. The real ascii protocol buffer used by the server
+// contains a lot more fields.
+struct ConfigResponse {
+  ConfigResponse(GUID g, const CString& v, const CString& u,
+                 const CString& h, int s, bool b)
+      : guid(g),
+        version(v),
+        url(u),
+        hash(h),
+        size(s),
+        needs_admin(b) {}
+
+  // The information to match the request against.
+  ConfigResponse() {}
+  CString app_name;
+  GUID guid;
+  CString version;
+  CString language;
+
+  // Response values.
+  CString local_file_name;
+  CString url;
+  CString hash;
+  int size;
+  bool needs_admin;
+};
+
+typedef std::vector<ConfigResponse> ConfigResponses;
+
+
+// Reads a config file that contains the specification
+// of the update responses of the server.
+// For an example of this file see example_config.txt.
+HRESULT ReadConfigFile(const CString& file_name,
+                       const CString& download_url_prefix,
+                       ConfigResponses* config_response);
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_CONFIG_H_
diff --git a/tools/OmahaCompatibility/common/error.h b/tools/OmahaCompatibility/common/error.h
index 9a452ae..49e99dc 100644
--- a/tools/OmahaCompatibility/common/error.h
+++ b/tools/OmahaCompatibility/common/error.h
@@ -1,32 +1,32 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_ERROR_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_ERROR_H_

-

-#include <windows.h>

-

-namespace omaha {

-

-// TODO(omaha): For now not using these, need to start using custom error codes.

-#define COMPATTEST_E_HANDLER_ALREADY_PRESENT            \

-  MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x100)

-

-#define COMPATTEST_E_RESPONSE_NOT_FOUND                 \

-  MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x101)

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_ERROR_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_ERROR_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_ERROR_H_
+
+#include <windows.h>
+
+namespace omaha {
+
+// TODO(omaha): For now not using these, need to start using custom error codes.
+#define COMPATTEST_E_HANDLER_ALREADY_PRESENT            \
+  MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x100)
+
+#define COMPATTEST_E_RESPONSE_NOT_FOUND                 \
+  MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0x101)
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_ERROR_H_
diff --git a/tools/OmahaCompatibility/common/example_config.txt b/tools/OmahaCompatibility/common/example_config.txt
index d3b41ae..65970d9 100644
--- a/tools/OmahaCompatibility/common/example_config.txt
+++ b/tools/OmahaCompatibility/common/example_config.txt
@@ -1,22 +1,22 @@
-; NOTE TO ALL COPYING THIS FILE FOR MODIFICATIONS.

-; 1. Please do not add spaces in the AppName. This tool does not support

-;    it although omaha itself does.

-; 2. For now we only support one application and two versions.

-; 3. Please note that for now we only support this exact format

-;    and nothing else. ONLY change the values below i.e. the 

-;    value part of key=value.

-; 4. The AppName, Appguid, NeedsAdmin, and Language are self explanatory,

-;    Version1, and Version2 indicate the versions that the installers 

-;    pointed by Installer1 and Installer2 Install.

-

-[Application]

-AppName=YouTubeUploader

-AppGuid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}

-NeedsAdmin=False

-Language=en

-

-Version1=1.0.24.0

-Installer1=c:\Builds\youtubeuploader.msi

-

-Version2=2.0.0.0

+; NOTE TO ALL COPYING THIS FILE FOR MODIFICATIONS.
+; 1. Please do not add spaces in the AppName. This tool does not support
+;    it although omaha itself does.
+; 2. For now we only support one application and two versions.
+; 3. Please note that for now we only support this exact format
+;    and nothing else. ONLY change the values below i.e. the 
+;    value part of key=value.
+; 4. The AppName, Appguid, NeedsAdmin, and Language are self explanatory,
+;    Version1, and Version2 indicate the versions that the installers 
+;    pointed by Installer1 and Installer2 Install.
+
+[Application]
+AppName=YouTubeUploader
+AppGuid={A4F7B07B-B9BD-4a33-B136-96D2ADFB60CB}
+NeedsAdmin=False
+Language=en
+
+Version1=1.0.24.0
+Installer1=c:\Builds\youtubeuploader.msi
+
+Version2=2.0.0.0
 Installer2=c:\Builds\youtubeuploader.msi
\ No newline at end of file
diff --git a/tools/OmahaCompatibility/common/ping_observer.h b/tools/OmahaCompatibility/common/ping_observer.h
index 25fc5d5..fbe17f0 100644
--- a/tools/OmahaCompatibility/common/ping_observer.h
+++ b/tools/OmahaCompatibility/common/ping_observer.h
@@ -1,32 +1,32 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_PING_OBSERVER_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_PING_OBSERVER_H_

-

-#include "omaha/worker/app_request_data.h"

-

-namespace omaha {

-

-// Interface for receiving ping events from the http server.

-class PingObserver {

- public:

-  virtual ~PingObserver() {}

-  virtual void Observe(const AppRequestData& data) = 0;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_PING_OBSERVER_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_PING_OBSERVER_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_PING_OBSERVER_H_
+
+#include "omaha/worker/app_request_data.h"
+
+namespace omaha {
+
+// Interface for receiving ping events from the http server.
+class PingObserver {
+ public:
+  virtual ~PingObserver() {}
+  virtual void Observe(const AppRequestData& data) = 0;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMMON_PING_OBSERVER_H_
diff --git a/tools/OmahaCompatibility/compatibility_test.cc b/tools/OmahaCompatibility/compatibility_test.cc
index 2a7769a..573b77b 100644
--- a/tools/OmahaCompatibility/compatibility_test.cc
+++ b/tools/OmahaCompatibility/compatibility_test.cc
@@ -1,479 +1,479 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/omahacompatibility/compatibility_test.h"

-#include <Windows.h>

-#include <tchar.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/apply_tag.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/system.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/tools/omahacompatibility/common/ping_observer.h"

-#include "omaha/tools/omahacompatibility/httpserver/http_server.h"

-#include "omaha/tools/omahacompatibility/httpserver/update_check_handler.h"

-#include "omaha/tools/omahacompatibility/httpserver/download_handler.h"

-

-namespace omaha {

-

-const TCHAR* const kUpdateCheckUrlPath = _T("/service/update2");

-const TCHAR* const kDownloadUrlPath = _T("/download");

-const DWORD kAuCheckPeriodMs = 5 * 60 * 1000;

-const TCHAR* const kHost = _T("localhost");

-const TCHAR* const kUrl = _T("http://localhost:8001/");

-const TCHAR* const kDownloadUrl = _T("http://localhost:8001/download");

-const TCHAR* const kUpdateCheckUrl =

-    _T("http://localhost:8001/service/update2");

-const int kPort = 8001;

-

-int CompatibilityTest::Main(bool test_omaha) {

-  CORE_LOG(L1, (_T("[Main]")));

-

-  if (IsOmahaInstalled()) {

-    printf("\nOmaha is already installed on this machine.\n");

-    printf("The test may not work correctly.\n");

-    printf("Ensure that the version of omaha being pointed to\n");

-    printf("is atleast >= the registered versions reported above.\n");

-    printf("Are you sure you want to run this test (Y/N)?");

-

-    int response = getchar();

-    if (response == 'n' || response == 'N') {

-      return -1;

-    }

-  }

-

-  // Read the config file.

-  HRESULT hr = ReadConfigFile(config_file_,

-                              kDownloadUrl,

-                              &config_responses_);

-  if (FAILED(hr)) {

-    return -1;

-  }

-

-  // Create the observer with the guid.

-  console_writer_.reset(new ConsoleWriter(

-      GuidToString(config_responses_[0].guid)));

-

-  // Setup the registry to make omaha talk to the local server.

-  // TODO(omaha): Warn user about changing user settings.

-  hr = SetupRegistry(config_responses_[0].needs_admin);

-  if (FAILED(hr)) {

-    return -1;

-  }

-  ON_SCOPE_EXIT(&CompatibilityTest::RestoreRegistry);

-

-  printf("\nStarting the local http server.\n");

-  hr = StartHttpServer();

-  if (FAILED(hr)) {

-    printf("\nLocal Http server start failed.\n");

-    return -1;

-  }

-

-  if (test_omaha) {

-    printf("\nStarting Googleupdate to install application.");

-    printf("Please wait .....\n");

-    printf("Omaha UI should show up in a sec.");

-    printf("If it does not, please kill this process and restart test.\n");

-

-    hr = StartGoogleUpdate();

-    if (FAILED(hr)) {

-      // TODO(omaha): Maybe report a verbose error message indicating

-      // what could be wrong.

-      printf("\nThe installation failed.\n");

-      printf("Please refer to the omaha integration documentation\n");

-      printf("for more information, it is possible that when you rerun\n");

-      printf("you get a warning about omaha already running,\n");

-      printf("please choose to continue in this case\n");

-      return -1;

-    }

-

-    // TODO(omaha): Add a wait on the UI process, instead of depending on

-    // the user correctly dismissing the UI.

-    printf("\nThe installation completed successfully.\n");

-    printf("Please dismiss the installer UI.\n");

-    printf("Continue update test (Y/N)?");

-    fflush(stdin);

-    int response = getchar();

-    if (response =='n' || response == 'N') {

-      return -1;

-    }

-

-    hr = StartApplicationUpdate();

-    if (FAILED(hr)) {

-      printf("\nThe update failed.\n");

-      printf("Please take a look at the omaha integration documentation\n");

-      printf("and rerun the test. It is possible that when you rerun\n");

-      printf("you might get a warning about omaha already running,\n");

-      printf("please choose to continue in this case\n");

-      return -1;

-    }

-

-    printf("\nUpdate succeeded. Wee.\n");

-    printf("Congratulations on a successful install and update.\n");

-    printf("Your friendly compatibility assistant will take your leave now.\n");

-    printf("Bye\n");

-  } else {

-    while (true) {

-      ::SleepEx(10000, false);

-    }

-  }

-

-  return 0;

-}

-

-bool CompatibilityTest::IsOmahaInstalled() {

-  bool is_omaha_installed = false;

-  CString goopdate_key_name =

-      ConfigManager::Instance()->registry_clients_goopdate(true);

-  CString machine_version;

-  HRESULT hr = RegKey::GetValue(goopdate_key_name, kRegValueProductVersion,

-                                &machine_version);

-  if (SUCCEEDED(hr)) {

-    is_omaha_installed = true;

-  }

-

-  goopdate_key_name =

-      ConfigManager::Instance()->registry_clients_goopdate(false);

-  CString user_version;

-  hr = RegKey::GetValue(goopdate_key_name,

-                        kRegValueProductVersion,

-                        &user_version);

-  if (SUCCEEDED(hr)) {

-    is_omaha_installed = true;

-  }

-

-  if (is_omaha_installed) {

-    printf("\nOmaha Installed on machine!\n");

-    if (!machine_version.IsEmpty()) {

-      printf("Machine Omaha version: %s\n", CT2A(machine_version));

-    }

-

-    if (!user_version.IsEmpty()) {

-      printf("User Omaha version: %s\n", CT2A(user_version));

-    }

-  }

-

-  return is_omaha_installed;

-}

-

-// Starts the http server on a different thread.

-HRESULT CompatibilityTest::StartHttpServer() {

-  CORE_LOG(L1, (_T("[StartHttpServer]")));

-

-  reset(thread_,

-        ::CreateThread(NULL, 0,

-                       &CompatibilityTest::StartStartHttpServerInternal,

-                       this, 0, &thread_id_));

-  return S_OK;

-}

-

-DWORD WINAPI CompatibilityTest::StartStartHttpServerInternal(

-    void* param) {

-  CompatibilityTest* omaha_compat =

-      static_cast<CompatibilityTest*>(param);

-  omaha_compat->RunHttpServerInternal();

-  return 0;

-}

-

-HRESULT CompatibilityTest::RunHttpServerInternal() {

-  CORE_LOG(L1, (_T("Starting local http server")));

-

-  scoped_co_init init_com_apt(COINIT_MULTITHREADED);

-  HRESULT hr = init_com_apt.hresult();

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[CoInitialize Failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  HttpServer server(kHost, kPort);

-  hr = server.Initialize();

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[HttpServer Initialize failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  scoped_ptr<UpdateCheckHandler> update_handler(

-      new UpdateCheckHandler(kUpdateCheckUrlPath, console_writer_.get()));

-  hr = server.AddUrlHandler(update_handler.get());

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[Failed to add update handler.][0x%08x]"), hr));

-    return hr;

-  }

-

-  scoped_ptr<DownloadHandler> download_handler(

-      new DownloadHandler(kDownloadUrlPath));

-  hr = server.AddUrlHandler(download_handler.get());

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[Failed to add download handler.][0x%08x]"), hr));

-    return hr;

-  }

-

-  for (size_t i = 0; i < config_responses_.size(); ++i) {

-    update_handler->AddAppVersionResponse(config_responses_[i]);

-    download_handler->AddDownloadFile(config_responses_[i]);

-  }

-

-  update_handler.release();

-  download_handler.release();

-  server.Start();

-  return S_OK;

-}

-

-HRESULT CompatibilityTest::RestoreRegistry(void) {

-  CORE_LOG(L1, (_T("[RestoreRegistry]")));

-  HRESULT hr = RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,

-                                   kRegValueMonitorLastChecked);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,

-                           kRegValueNamePingUrl);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,

-                           kRegValueNameUrl);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,

-                           kRegValueAuCheckPeriodMs);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,

-                           kRegValueNameOverInstall);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT CompatibilityTest::SetupRegistry(bool needs_admin) {

-  CORE_LOG(L1, (_T("[SetupRegistry]")));

-

-  // Override the url, pingurl, AuCheckPeriod, overinstall.

-  // Create the lastchecked value monitor.

-  // Also create the last checked key, to allow a /ua launch

-  // on deletion.

-  HRESULT hr = RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                                kRegValueMonitorLastChecked,

-                                static_cast<DWORD>(1));

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                        kRegValueNamePingUrl,

-                        kUpdateCheckUrl);

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                        kRegValueNameUrl,

-                        kUpdateCheckUrl);

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                        kRegValueAuCheckPeriodMs,

-                        kAuCheckPeriodMs);

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = RegKey::SetValue(MACHINE_REG_UPDATE_DEV,

-                        kRegValueNameOverInstall,

-                        static_cast<DWORD>(1));

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  CString update_key_name =

-      ConfigManager::Instance()->registry_update(needs_admin);

-  hr = RegKey::SetValue(update_key_name,

-                        kRegValueLastChecked,

-                        static_cast<DWORD>(0));

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// Builds the googleupdate file name to be run.

-HRESULT CompatibilityTest::BuildTaggedGoogleUpdatePath() {

-  CORE_LOG(L1, (_T("[BuildTaggedGoogleUpdatePath]")));

-

-  GUID guid(GUID_NULL);

-  HRESULT hr = ::CoCreateGuid(&guid);

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[CoCreateGuid failed 0x%08x]"), hr));

-    return hr;

-  }

-

-  CString unique_exe(GuidToString(guid));

-  unique_exe += _T(".exe");

-

-  TCHAR temp_path[MAX_PATH] = {0};

-  if (!::GetTempPath(MAX_PATH, temp_path)) {

-    CORE_LOG(L1, (_T("[GetTempPath failed.]")));

-    return HRESULTFromLastError();

-  }

-

-  tagged_google_update_path_ = ConcatenatePath(temp_path, unique_exe);

-  return S_OK;

-}

-

-// Sets up the correct ap value to cause the server to send back

-// an update response.

-HRESULT CompatibilityTest::StartApplicationUpdate() {

-  CORE_LOG(L1, (_T("[StartApplicationUpdate]")));

-

-  // Set the ap value to "update_app".

-  bool needs_admin = config_responses_[0].needs_admin;

-  CString reg_key_name =

-      ConfigManager::Instance()->registry_client_state(needs_admin);

-  CString app_client_state_key_name = AppendRegKeyPath(

-      reg_key_name,

-      GuidToString(config_responses_[0].guid));

-  HRESULT hr = RegKey::SetValue(app_client_state_key_name,

-                                kRegValueAdditionalParams,

-                                _T("update_app"));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Delete the last checked value to force an update check.

-  CString update_key_name =

-      ConfigManager::Instance()->registry_update(needs_admin);

-  hr = RegKey::DeleteValue(update_key_name, kRegValueLastChecked);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  printf("\nSignaled Googleupdate to start application update.");

-  printf("Waiting for events...\n");

-  while (true) {

-    ::SleepEx(1000, false);

-    if (console_writer_->update_completed()) {

-      PingEvent::Results result = console_writer_->update_result();

-      if (result == PingEvent::EVENT_RESULT_SUCCESS) {

-        CORE_LOG(L1, (_T("[Successfully completed update]")));

-        return S_OK;

-      } else {

-        CORE_LOG(L1, (_T("[Update failed %d]"), result));

-        return E_FAIL;

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-// Stamps googleupdatesetup with the information from the config and

-// runs it.

-HRESULT CompatibilityTest::StartGoogleUpdate() {

-  CORE_LOG(L1, (_T("[StartGoogleUpdate]")));

-

-  // Stamp the googleupdatesetupe.exe with the information from

-  // the config.

-  HRESULT hr = BuildTaggedGoogleUpdatePath();

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[BuildTaggedGoogleUpdatePath failed 0x%08x]"), hr));

-    return hr;

-  }

-

-  // For now we only read the information from the first config and use

-  // that to stamp the binary.

-  CString tag_str;

-  tag_str.Format(

-      _T("appguid=%s&appname=%s&needsadmin=%s&lang=%s"),

-      GuidToString(config_responses_[0].guid),

-      config_responses_[0].app_name,

-      config_responses_[0].needs_admin ? _T("True") : _T("False"),

-      config_responses_[0].language);

-

-  ApplyTag tag;

-  hr = tag.Init(googleupdate_setup_path_,

-                CT2CA(tag_str),

-                lstrlenA(CT2CA(tag_str)),

-                tagged_google_update_path_,

-                false);

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[ApplyTag.Init failed 0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = tag.EmbedTagString();

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[ApplyTag.EmbedTagString failed 0x%08x]"), hr));

-    return hr;

-  }

-

-  // Start omaha to install the application.

-  hr = System::ShellExecuteProcess(tagged_google_update_path_,

-                                   NULL,

-                                   NULL,

-                                   NULL);

-  if (FAILED(hr)) {

-    CORE_LOG(L1, (_T("[Start installer failed 0x%08x]"), hr));

-    return hr;

-  }

-

-  // Now wait for the install to complete. We poll the

-  // observer for a install complete event.

-  while (true) {

-    ::SleepEx(1000, false);

-    if (console_writer_->install_completed()) {

-      PingEvent::Results result = console_writer_->install_result();

-      if (result == PingEvent::EVENT_RESULT_SUCCESS) {

-        CORE_LOG(L1, (_T("[Successfully completed install]")));

-        return S_OK;

-      } else {

-        CORE_LOG(L1, (_T("[Start installer failed %d]"), result));

-        return E_FAIL;

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/omahacompatibility/compatibility_test.h"
+#include <Windows.h>
+#include <tchar.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/apply_tag.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/system.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/tools/omahacompatibility/common/ping_observer.h"
+#include "omaha/tools/omahacompatibility/httpserver/http_server.h"
+#include "omaha/tools/omahacompatibility/httpserver/update_check_handler.h"
+#include "omaha/tools/omahacompatibility/httpserver/download_handler.h"
+
+namespace omaha {
+
+const TCHAR* const kUpdateCheckUrlPath = _T("/service/update2");
+const TCHAR* const kDownloadUrlPath = _T("/download");
+const DWORD kAuCheckPeriodMs = 5 * 60 * 1000;
+const TCHAR* const kHost = _T("localhost");
+const TCHAR* const kUrl = _T("http://localhost:8001/");
+const TCHAR* const kDownloadUrl = _T("http://localhost:8001/download");
+const TCHAR* const kUpdateCheckUrl =
+    _T("http://localhost:8001/service/update2");
+const int kPort = 8001;
+
+int CompatibilityTest::Main(bool test_omaha) {
+  CORE_LOG(L1, (_T("[Main]")));
+
+  if (IsOmahaInstalled()) {
+    printf("\nOmaha is already installed on this machine.\n");
+    printf("The test may not work correctly.\n");
+    printf("Ensure that the version of omaha being pointed to\n");
+    printf("is atleast >= the registered versions reported above.\n");
+    printf("Are you sure you want to run this test (Y/N)?");
+
+    int response = getchar();
+    if (response == 'n' || response == 'N') {
+      return -1;
+    }
+  }
+
+  // Read the config file.
+  HRESULT hr = ReadConfigFile(config_file_,
+                              kDownloadUrl,
+                              &config_responses_);
+  if (FAILED(hr)) {
+    return -1;
+  }
+
+  // Create the observer with the guid.
+  console_writer_.reset(new ConsoleWriter(
+      GuidToString(config_responses_[0].guid)));
+
+  // Setup the registry to make omaha talk to the local server.
+  // TODO(omaha): Warn user about changing user settings.
+  hr = SetupRegistry(config_responses_[0].needs_admin);
+  if (FAILED(hr)) {
+    return -1;
+  }
+  ON_SCOPE_EXIT(&CompatibilityTest::RestoreRegistry);
+
+  printf("\nStarting the local http server.\n");
+  hr = StartHttpServer();
+  if (FAILED(hr)) {
+    printf("\nLocal Http server start failed.\n");
+    return -1;
+  }
+
+  if (test_omaha) {
+    printf("\nStarting Googleupdate to install application.");
+    printf("Please wait .....\n");
+    printf("Omaha UI should show up in a sec.");
+    printf("If it does not, please kill this process and restart test.\n");
+
+    hr = StartGoogleUpdate();
+    if (FAILED(hr)) {
+      // TODO(omaha): Maybe report a verbose error message indicating
+      // what could be wrong.
+      printf("\nThe installation failed.\n");
+      printf("Please refer to the omaha integration documentation\n");
+      printf("for more information, it is possible that when you rerun\n");
+      printf("you get a warning about omaha already running,\n");
+      printf("please choose to continue in this case\n");
+      return -1;
+    }
+
+    // TODO(omaha): Add a wait on the UI process, instead of depending on
+    // the user correctly dismissing the UI.
+    printf("\nThe installation completed successfully.\n");
+    printf("Please dismiss the installer UI.\n");
+    printf("Continue update test (Y/N)?");
+    fflush(stdin);
+    int response = getchar();
+    if (response =='n' || response == 'N') {
+      return -1;
+    }
+
+    hr = StartApplicationUpdate();
+    if (FAILED(hr)) {
+      printf("\nThe update failed.\n");
+      printf("Please take a look at the omaha integration documentation\n");
+      printf("and rerun the test. It is possible that when you rerun\n");
+      printf("you might get a warning about omaha already running,\n");
+      printf("please choose to continue in this case\n");
+      return -1;
+    }
+
+    printf("\nUpdate succeeded. Wee.\n");
+    printf("Congratulations on a successful install and update.\n");
+    printf("Your friendly compatibility assistant will take your leave now.\n");
+    printf("Bye\n");
+  } else {
+    while (true) {
+      ::SleepEx(10000, false);
+    }
+  }
+
+  return 0;
+}
+
+bool CompatibilityTest::IsOmahaInstalled() {
+  bool is_omaha_installed = false;
+  CString goopdate_key_name =
+      ConfigManager::Instance()->registry_clients_goopdate(true);
+  CString machine_version;
+  HRESULT hr = RegKey::GetValue(goopdate_key_name, kRegValueProductVersion,
+                                &machine_version);
+  if (SUCCEEDED(hr)) {
+    is_omaha_installed = true;
+  }
+
+  goopdate_key_name =
+      ConfigManager::Instance()->registry_clients_goopdate(false);
+  CString user_version;
+  hr = RegKey::GetValue(goopdate_key_name,
+                        kRegValueProductVersion,
+                        &user_version);
+  if (SUCCEEDED(hr)) {
+    is_omaha_installed = true;
+  }
+
+  if (is_omaha_installed) {
+    printf("\nOmaha Installed on machine!\n");
+    if (!machine_version.IsEmpty()) {
+      printf("Machine Omaha version: %s\n", CT2A(machine_version));
+    }
+
+    if (!user_version.IsEmpty()) {
+      printf("User Omaha version: %s\n", CT2A(user_version));
+    }
+  }
+
+  return is_omaha_installed;
+}
+
+// Starts the http server on a different thread.
+HRESULT CompatibilityTest::StartHttpServer() {
+  CORE_LOG(L1, (_T("[StartHttpServer]")));
+
+  reset(thread_,
+        ::CreateThread(NULL, 0,
+                       &CompatibilityTest::StartStartHttpServerInternal,
+                       this, 0, &thread_id_));
+  return S_OK;
+}
+
+DWORD WINAPI CompatibilityTest::StartStartHttpServerInternal(
+    void* param) {
+  CompatibilityTest* omaha_compat =
+      static_cast<CompatibilityTest*>(param);
+  omaha_compat->RunHttpServerInternal();
+  return 0;
+}
+
+HRESULT CompatibilityTest::RunHttpServerInternal() {
+  CORE_LOG(L1, (_T("Starting local http server")));
+
+  scoped_co_init init_com_apt(COINIT_MULTITHREADED);
+  HRESULT hr = init_com_apt.hresult();
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[CoInitialize Failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  HttpServer server(kHost, kPort);
+  hr = server.Initialize();
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[HttpServer Initialize failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  scoped_ptr<UpdateCheckHandler> update_handler(
+      new UpdateCheckHandler(kUpdateCheckUrlPath, console_writer_.get()));
+  hr = server.AddUrlHandler(update_handler.get());
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[Failed to add update handler.][0x%08x]"), hr));
+    return hr;
+  }
+
+  scoped_ptr<DownloadHandler> download_handler(
+      new DownloadHandler(kDownloadUrlPath));
+  hr = server.AddUrlHandler(download_handler.get());
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[Failed to add download handler.][0x%08x]"), hr));
+    return hr;
+  }
+
+  for (size_t i = 0; i < config_responses_.size(); ++i) {
+    update_handler->AddAppVersionResponse(config_responses_[i]);
+    download_handler->AddDownloadFile(config_responses_[i]);
+  }
+
+  update_handler.release();
+  download_handler.release();
+  server.Start();
+  return S_OK;
+}
+
+HRESULT CompatibilityTest::RestoreRegistry(void) {
+  CORE_LOG(L1, (_T("[RestoreRegistry]")));
+  HRESULT hr = RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,
+                                   kRegValueMonitorLastChecked);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,
+                           kRegValueNamePingUrl);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,
+                           kRegValueNameUrl);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,
+                           kRegValueAuCheckPeriodMs);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = RegKey::DeleteValue(MACHINE_REG_UPDATE_DEV,
+                           kRegValueNameOverInstall);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT CompatibilityTest::SetupRegistry(bool needs_admin) {
+  CORE_LOG(L1, (_T("[SetupRegistry]")));
+
+  // Override the url, pingurl, AuCheckPeriod, overinstall.
+  // Create the lastchecked value monitor.
+  // Also create the last checked key, to allow a /ua launch
+  // on deletion.
+  HRESULT hr = RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                                kRegValueMonitorLastChecked,
+                                static_cast<DWORD>(1));
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                        kRegValueNamePingUrl,
+                        kUpdateCheckUrl);
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                        kRegValueNameUrl,
+                        kUpdateCheckUrl);
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                        kRegValueAuCheckPeriodMs,
+                        kAuCheckPeriodMs);
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = RegKey::SetValue(MACHINE_REG_UPDATE_DEV,
+                        kRegValueNameOverInstall,
+                        static_cast<DWORD>(1));
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  CString update_key_name =
+      ConfigManager::Instance()->registry_update(needs_admin);
+  hr = RegKey::SetValue(update_key_name,
+                        kRegValueLastChecked,
+                        static_cast<DWORD>(0));
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[SetValue failed.][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// Builds the googleupdate file name to be run.
+HRESULT CompatibilityTest::BuildTaggedGoogleUpdatePath() {
+  CORE_LOG(L1, (_T("[BuildTaggedGoogleUpdatePath]")));
+
+  GUID guid(GUID_NULL);
+  HRESULT hr = ::CoCreateGuid(&guid);
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[CoCreateGuid failed 0x%08x]"), hr));
+    return hr;
+  }
+
+  CString unique_exe(GuidToString(guid));
+  unique_exe += _T(".exe");
+
+  TCHAR temp_path[MAX_PATH] = {0};
+  if (!::GetTempPath(MAX_PATH, temp_path)) {
+    CORE_LOG(L1, (_T("[GetTempPath failed.]")));
+    return HRESULTFromLastError();
+  }
+
+  tagged_google_update_path_ = ConcatenatePath(temp_path, unique_exe);
+  return S_OK;
+}
+
+// Sets up the correct ap value to cause the server to send back
+// an update response.
+HRESULT CompatibilityTest::StartApplicationUpdate() {
+  CORE_LOG(L1, (_T("[StartApplicationUpdate]")));
+
+  // Set the ap value to "update_app".
+  bool needs_admin = config_responses_[0].needs_admin;
+  CString reg_key_name =
+      ConfigManager::Instance()->registry_client_state(needs_admin);
+  CString app_client_state_key_name = AppendRegKeyPath(
+      reg_key_name,
+      GuidToString(config_responses_[0].guid));
+  HRESULT hr = RegKey::SetValue(app_client_state_key_name,
+                                kRegValueAdditionalParams,
+                                _T("update_app"));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Delete the last checked value to force an update check.
+  CString update_key_name =
+      ConfigManager::Instance()->registry_update(needs_admin);
+  hr = RegKey::DeleteValue(update_key_name, kRegValueLastChecked);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  printf("\nSignaled Googleupdate to start application update.");
+  printf("Waiting for events...\n");
+  while (true) {
+    ::SleepEx(1000, false);
+    if (console_writer_->update_completed()) {
+      PingEvent::Results result = console_writer_->update_result();
+      if (result == PingEvent::EVENT_RESULT_SUCCESS) {
+        CORE_LOG(L1, (_T("[Successfully completed update]")));
+        return S_OK;
+      } else {
+        CORE_LOG(L1, (_T("[Update failed %d]"), result));
+        return E_FAIL;
+      }
+    }
+  }
+
+  return S_OK;
+}
+
+// Stamps googleupdatesetup with the information from the config and
+// runs it.
+HRESULT CompatibilityTest::StartGoogleUpdate() {
+  CORE_LOG(L1, (_T("[StartGoogleUpdate]")));
+
+  // Stamp the googleupdatesetupe.exe with the information from
+  // the config.
+  HRESULT hr = BuildTaggedGoogleUpdatePath();
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[BuildTaggedGoogleUpdatePath failed 0x%08x]"), hr));
+    return hr;
+  }
+
+  // For now we only read the information from the first config and use
+  // that to stamp the binary.
+  CString tag_str;
+  tag_str.Format(
+      _T("appguid=%s&appname=%s&needsadmin=%s&lang=%s"),
+      GuidToString(config_responses_[0].guid),
+      config_responses_[0].app_name,
+      config_responses_[0].needs_admin ? _T("True") : _T("False"),
+      config_responses_[0].language);
+
+  ApplyTag tag;
+  hr = tag.Init(googleupdate_setup_path_,
+                CT2CA(tag_str),
+                lstrlenA(CT2CA(tag_str)),
+                tagged_google_update_path_,
+                false);
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[ApplyTag.Init failed 0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = tag.EmbedTagString();
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[ApplyTag.EmbedTagString failed 0x%08x]"), hr));
+    return hr;
+  }
+
+  // Start omaha to install the application.
+  hr = System::ShellExecuteProcess(tagged_google_update_path_,
+                                   NULL,
+                                   NULL,
+                                   NULL);
+  if (FAILED(hr)) {
+    CORE_LOG(L1, (_T("[Start installer failed 0x%08x]"), hr));
+    return hr;
+  }
+
+  // Now wait for the install to complete. We poll the
+  // observer for a install complete event.
+  while (true) {
+    ::SleepEx(1000, false);
+    if (console_writer_->install_completed()) {
+      PingEvent::Results result = console_writer_->install_result();
+      if (result == PingEvent::EVENT_RESULT_SUCCESS) {
+        CORE_LOG(L1, (_T("[Successfully completed install]")));
+        return S_OK;
+      } else {
+        CORE_LOG(L1, (_T("[Start installer failed %d]"), result));
+        return E_FAIL;
+      }
+    }
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/tools/OmahaCompatibility/compatibility_test.h b/tools/OmahaCompatibility/compatibility_test.h
index 228f1c6..d529a2c 100644
--- a/tools/OmahaCompatibility/compatibility_test.h
+++ b/tools/OmahaCompatibility/compatibility_test.h
@@ -1,88 +1,88 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMPATIBILITY_TEST_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMPATIBILITY_TEST_H_

-

-#include <Windows.h>

-#include <tchar.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/apply_tag.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/utils.h"

-#include "omaha/tools/omahacompatibility/console_writer.h"

-#include "omaha/tools/omahacompatibility/HttpServer/http_server.h"

-#include "omaha/tools/omahacompatibility/HttpServer/update_check_handler.h"

-#include "omaha/tools/omahacompatibility/HttpServer/download_handler.h"

-

-namespace omaha {

-

-// This is the main class the starts the HttpServer and stamps GoogleUpdate

-// appropriately and runs the installer.

-class CompatibilityTest {

- public:

-  CompatibilityTest() : thread_id_(0) {}

-  int Main(bool test_omaha);

-  void set_config_file(const CString& config_file) {

-    config_file_ = config_file;

-  }

-  void set_googleupdate_setup_path(const CString& path) {

-    googleupdate_setup_path_ = path;

-  }

-  HRESULT RunHttpServerInternal();

-

- private:

-  static DWORD WINAPI StartStartHttpServerInternal(void* omaha);

-

-  // Returns true of omaha is installer for user or machine.

-  bool IsOmahaInstalled();

-

-  // Starts running the HttpServer.

-  HRESULT StartHttpServer();

-

-  // Overrides the url, pingurl, aucheckperiod, overinstall values.

-  static HRESULT SetupRegistry(bool needs_admin);

-

-  // Restores the values of the registry.

-  static HRESULT RestoreRegistry();

-

-  // Builds a unique path to run the installer from.

-  HRESULT BuildTaggedGoogleUpdatePath();

-

-  // Stamps googleupdate with the correct values and runs the it.

-  HRESULT StartGoogleUpdate();

-

-  // Signals omaha to update the application.

-  HRESULT StartApplicationUpdate();

-

-  scoped_thread thread_;

-  DWORD thread_id_;

-  CString config_file_;

-  CString googleupdate_setup_path_;

-  ConfigResponses config_responses_;

-  CString tagged_google_update_path_;

-  scoped_ptr<ConsoleWriter> console_writer_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMPATIBILITY_TEST_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMPATIBILITY_TEST_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMPATIBILITY_TEST_H_
+
+#include <Windows.h>
+#include <tchar.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/apply_tag.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/utils.h"
+#include "omaha/tools/omahacompatibility/console_writer.h"
+#include "omaha/tools/omahacompatibility/HttpServer/http_server.h"
+#include "omaha/tools/omahacompatibility/HttpServer/update_check_handler.h"
+#include "omaha/tools/omahacompatibility/HttpServer/download_handler.h"
+
+namespace omaha {
+
+// This is the main class the starts the HttpServer and stamps GoogleUpdate
+// appropriately and runs the installer.
+class CompatibilityTest {
+ public:
+  CompatibilityTest() : thread_id_(0) {}
+  int Main(bool test_omaha);
+  void set_config_file(const CString& config_file) {
+    config_file_ = config_file;
+  }
+  void set_googleupdate_setup_path(const CString& path) {
+    googleupdate_setup_path_ = path;
+  }
+  HRESULT RunHttpServerInternal();
+
+ private:
+  static DWORD WINAPI StartStartHttpServerInternal(void* omaha);
+
+  // Returns true of omaha is installer for user or machine.
+  bool IsOmahaInstalled();
+
+  // Starts running the HttpServer.
+  HRESULT StartHttpServer();
+
+  // Overrides the url, pingurl, aucheckperiod, overinstall values.
+  static HRESULT SetupRegistry(bool needs_admin);
+
+  // Restores the values of the registry.
+  static HRESULT RestoreRegistry();
+
+  // Builds a unique path to run the installer from.
+  HRESULT BuildTaggedGoogleUpdatePath();
+
+  // Stamps googleupdate with the correct values and runs the it.
+  HRESULT StartGoogleUpdate();
+
+  // Signals omaha to update the application.
+  HRESULT StartApplicationUpdate();
+
+  scoped_thread thread_;
+  DWORD thread_id_;
+  CString config_file_;
+  CString googleupdate_setup_path_;
+  ConfigResponses config_responses_;
+  CString tagged_google_update_path_;
+  scoped_ptr<ConsoleWriter> console_writer_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_COMPATIBILITY_TEST_H_
diff --git a/tools/OmahaCompatibility/console_writer.cc b/tools/OmahaCompatibility/console_writer.cc
index 056b35a..970e0e6 100644
--- a/tools/OmahaCompatibility/console_writer.cc
+++ b/tools/OmahaCompatibility/console_writer.cc
@@ -1,151 +1,151 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/omahacompatibility/console_writer.h"

-#include <Windows.h>

-#include <tchar.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/utils.h"

-#include "omaha/tools/omahacompatibility/common/ping_observer.h"

-

-namespace omaha {

-

-CString ConsoleWriter::PingTypeToString(PingEvent::Types type)  {

-  switch (type) {

-    case PingEvent::EVENT_UNKNOWN:

-      return _T("EVENT_UNKNOWN");

-    case PingEvent::EVENT_INSTALL_DOWNLOAD_FINISH:

-      return _T("EVENT_INSTALL_DOWNLOAD_FINISH");

-    case PingEvent::EVENT_INSTALL_COMPLETE:

-      return _T("EVENT_INSTALL_COMPLETE");

-    case PingEvent::EVENT_UPDATE_COMPLETE:

-      return _T("EVENT_UPDATE_COMPLETE");

-    case PingEvent::EVENT_UNINSTALL:

-      return _T("EVENT_UNINSTALL");

-    case PingEvent::EVENT_INSTALL_DOWNLOAD_START:

-      return _T("EVENT_INSTALL_DOWNLOAD_START");

-    case PingEvent::EVENT_INSTALL_INSTALLER_START:

-      return _T("EVENT_INSTALL_INSTALLER_START");

-    case PingEvent::EVENT_INSTALL_APPLICATION_BEGIN:

-      return _T("EVENT_INSTALL_APPLICATION_BEGIN");

-

-    // Install Setup events.

-    case PingEvent::EVENT_SETUP_INSTALL_BEGIN:

-      return _T("EVENT_SETUP_INSTALL_BEGIN");

-    case PingEvent::EVENT_SETUP_INSTALL_COMPLETE:

-      return _T("EVENT_SETUP_INSTALL_COMPLETE");

-

-    // Register Product Events.

-    case PingEvent::EVENT_REGISTER_PRODUCT_COMPLETE:

-      return _T("EVENT_REGISTER_PRODUCT_COMPLETE");

-

-    // Update Events.

-    case PingEvent::EVENT_UPDATE_APPLICATION_BEGIN:

-      return _T("EVENT_UPDATE_APPLICATION_BEGIN");

-    case PingEvent::EVENT_UPDATE_DOWNLOAD_START:

-      return _T("EVENT_UPDATE_DOWNLOAD_START");

-    case PingEvent::EVENT_UPDATE_DOWNLOAD_FINISH:

-      return _T("EVENT_UPDATE_DOWNLOAD_FINISH");

-    case PingEvent::EVENT_UPDATE_INSTALLER_START:

-      return _T("EVENT_UPDATE_INSTALLER_START");

-

-    // Self-update Setup events.

-    case PingEvent::EVENT_SETUP_UPDATE_BEGIN:

-      return _T("EVENT_SETUP_UPDATE_BEGIN");

-    case PingEvent::EVENT_SETUP_UPDATE_COMPLETE:

-      return _T("EVENT_SETUP_UPDATE_COMPLETE");

-

-    // Other events.

-    case PingEvent::EVENT_INSTALL_OEM_FIRST_CHECK:

-      return _T("EVENT_INSTALL_OEM_FIRST_CHECK");

-

-    // Failure report events - not part of the normal flow.

-    case PingEvent::EVENT_SETUP_INSTALL_FAILURE:

-      return _T("EVENT_SETUP_INSTALL_FAILURE");

-    case PingEvent::EVENT_SETUP_COM_SERVER_FAILURE:

-      return _T("EVENT_SETUP_COM_SERVER_FAILURE");

-    case PingEvent::EVENT_SETUP_UPDATE_FAILURE:

-      return _T("EVENT_SETUP_UPDATE_FAILURE");

-    default:

-      return _T("Unknown");

-  }

-}

-

-CString ConsoleWriter::PingResultToString(PingEvent::Results result)  {

-  switch (result) {

-    case PingEvent::EVENT_RESULT_ERROR:

-      return _T("EVENT_RESULT_ERROR");

-    case PingEvent::EVENT_RESULT_SUCCESS:

-      return _T("EVENT_RESULT_SUCCESS");

-    case PingEvent::EVENT_RESULT_SUCCESS_REBOOT:

-      return _T("EVENT_RESULT_SUCCESS_REBOOT");

-    case PingEvent::EVENT_RESULT_CANCELLED:

-      return _T("EVENT_RESULT_CANCELLED");

-    case PingEvent::EVENT_RESULT_INSTALLER_ERROR_MSI:

-      return _T("EVENT_RESULT_INSTALLER_ERROR_MSI");

-    case PingEvent::EVENT_RESULT_INSTALLER_ERROR_OTHER:

-      return _T("EVENT_RESULT_INSTALLER_ERROR_OTHER");

-    case PingEvent::EVENT_RESULT_NOUPDATE:

-      return _T("EVENT_RESULT_NOUPDATE");

-    case PingEvent::EVENT_RESULT_INSTALLER_ERROR_SYSTEM:

-      return _T("EVENT_RESULT_INSTALLER_ERROR_SYSTEM");

-    case PingEvent::EVENT_RESULT_UPDATE_DEFERRED:

-      return _T("EVENT_RESULT_UPDATE_DEFERRED");

-    default:

-      return _T("unknown result");

-  }

-}

-

-bool ConsoleWriter::IsUpdateCompletedEvent(const CString& app_guid,

-                                           const PingEvent& ping) {

-  return app_guid == app_guid_ &&

-         ping.event_type() == PingEvent::EVENT_UPDATE_COMPLETE;

-}

-

-bool ConsoleWriter::IsInstallCompletedEvent(const CString& app_guid,

-                                            const PingEvent& ping) {

-  return app_guid == app_guid_ &&

-         ping.event_type() == PingEvent::EVENT_INSTALL_COMPLETE;

-}

-

-void ConsoleWriter::Observe(const AppRequestData& data) {

-  PingEventVector::const_iterator iter = data.ping_events_begin();

-  for (; iter != data.ping_events_end(); ++iter) {

-    PingEvent ping = *iter;

-    CString msg;

-    msg.Format(_T("\nPing App = %s, Type = %s, Result = %s, Error = %d\n"),

-               GuidToString(data.app_data().app_guid()),

-               PingTypeToString(ping.event_type()),

-               PingResultToString(ping.event_result()),

-               ping.error_code());

-    printf("%S", msg);

-    CORE_LOG(L1, (msg));

-

-    if (IsInstallCompletedEvent(GuidToString(data.app_data().app_guid()),

-                                ping)) {

-      __mutexScope(lock_);

-      install_result_ = ping.event_result();

-      install_completed_ = true;

-    } else if (IsUpdateCompletedEvent(GuidToString(data.app_data().app_guid()),

-                                      ping)) {

-      __mutexScope(lock_);

-      update_result_ = ping.event_result();

-      update_completed_ = true;

-    }

-  }

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/omahacompatibility/console_writer.h"
+#include <Windows.h>
+#include <tchar.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/utils.h"
+#include "omaha/tools/omahacompatibility/common/ping_observer.h"
+
+namespace omaha {
+
+CString ConsoleWriter::PingTypeToString(PingEvent::Types type)  {
+  switch (type) {
+    case PingEvent::EVENT_UNKNOWN:
+      return _T("EVENT_UNKNOWN");
+    case PingEvent::EVENT_INSTALL_DOWNLOAD_FINISH:
+      return _T("EVENT_INSTALL_DOWNLOAD_FINISH");
+    case PingEvent::EVENT_INSTALL_COMPLETE:
+      return _T("EVENT_INSTALL_COMPLETE");
+    case PingEvent::EVENT_UPDATE_COMPLETE:
+      return _T("EVENT_UPDATE_COMPLETE");
+    case PingEvent::EVENT_UNINSTALL:
+      return _T("EVENT_UNINSTALL");
+    case PingEvent::EVENT_INSTALL_DOWNLOAD_START:
+      return _T("EVENT_INSTALL_DOWNLOAD_START");
+    case PingEvent::EVENT_INSTALL_INSTALLER_START:
+      return _T("EVENT_INSTALL_INSTALLER_START");
+    case PingEvent::EVENT_INSTALL_APPLICATION_BEGIN:
+      return _T("EVENT_INSTALL_APPLICATION_BEGIN");
+
+    // Install Setup events.
+    case PingEvent::EVENT_SETUP_INSTALL_BEGIN:
+      return _T("EVENT_SETUP_INSTALL_BEGIN");
+    case PingEvent::EVENT_SETUP_INSTALL_COMPLETE:
+      return _T("EVENT_SETUP_INSTALL_COMPLETE");
+
+    // Register Product Events.
+    case PingEvent::EVENT_REGISTER_PRODUCT_COMPLETE:
+      return _T("EVENT_REGISTER_PRODUCT_COMPLETE");
+
+    // Update Events.
+    case PingEvent::EVENT_UPDATE_APPLICATION_BEGIN:
+      return _T("EVENT_UPDATE_APPLICATION_BEGIN");
+    case PingEvent::EVENT_UPDATE_DOWNLOAD_START:
+      return _T("EVENT_UPDATE_DOWNLOAD_START");
+    case PingEvent::EVENT_UPDATE_DOWNLOAD_FINISH:
+      return _T("EVENT_UPDATE_DOWNLOAD_FINISH");
+    case PingEvent::EVENT_UPDATE_INSTALLER_START:
+      return _T("EVENT_UPDATE_INSTALLER_START");
+
+    // Self-update Setup events.
+    case PingEvent::EVENT_SETUP_UPDATE_BEGIN:
+      return _T("EVENT_SETUP_UPDATE_BEGIN");
+    case PingEvent::EVENT_SETUP_UPDATE_COMPLETE:
+      return _T("EVENT_SETUP_UPDATE_COMPLETE");
+
+    // Other events.
+    case PingEvent::EVENT_INSTALL_OEM_FIRST_CHECK:
+      return _T("EVENT_INSTALL_OEM_FIRST_CHECK");
+
+    // Failure report events - not part of the normal flow.
+    case PingEvent::EVENT_SETUP_INSTALL_FAILURE:
+      return _T("EVENT_SETUP_INSTALL_FAILURE");
+    case PingEvent::EVENT_SETUP_COM_SERVER_FAILURE:
+      return _T("EVENT_SETUP_COM_SERVER_FAILURE");
+    case PingEvent::EVENT_SETUP_UPDATE_FAILURE:
+      return _T("EVENT_SETUP_UPDATE_FAILURE");
+    default:
+      return _T("Unknown");
+  }
+}
+
+CString ConsoleWriter::PingResultToString(PingEvent::Results result)  {
+  switch (result) {
+    case PingEvent::EVENT_RESULT_ERROR:
+      return _T("EVENT_RESULT_ERROR");
+    case PingEvent::EVENT_RESULT_SUCCESS:
+      return _T("EVENT_RESULT_SUCCESS");
+    case PingEvent::EVENT_RESULT_SUCCESS_REBOOT:
+      return _T("EVENT_RESULT_SUCCESS_REBOOT");
+    case PingEvent::EVENT_RESULT_CANCELLED:
+      return _T("EVENT_RESULT_CANCELLED");
+    case PingEvent::EVENT_RESULT_INSTALLER_ERROR_MSI:
+      return _T("EVENT_RESULT_INSTALLER_ERROR_MSI");
+    case PingEvent::EVENT_RESULT_INSTALLER_ERROR_OTHER:
+      return _T("EVENT_RESULT_INSTALLER_ERROR_OTHER");
+    case PingEvent::EVENT_RESULT_NOUPDATE:
+      return _T("EVENT_RESULT_NOUPDATE");
+    case PingEvent::EVENT_RESULT_INSTALLER_ERROR_SYSTEM:
+      return _T("EVENT_RESULT_INSTALLER_ERROR_SYSTEM");
+    case PingEvent::EVENT_RESULT_UPDATE_DEFERRED:
+      return _T("EVENT_RESULT_UPDATE_DEFERRED");
+    default:
+      return _T("unknown result");
+  }
+}
+
+bool ConsoleWriter::IsUpdateCompletedEvent(const CString& app_guid,
+                                           const PingEvent& ping) {
+  return app_guid == app_guid_ &&
+         ping.event_type() == PingEvent::EVENT_UPDATE_COMPLETE;
+}
+
+bool ConsoleWriter::IsInstallCompletedEvent(const CString& app_guid,
+                                            const PingEvent& ping) {
+  return app_guid == app_guid_ &&
+         ping.event_type() == PingEvent::EVENT_INSTALL_COMPLETE;
+}
+
+void ConsoleWriter::Observe(const AppRequestData& data) {
+  PingEventVector::const_iterator iter = data.ping_events_begin();
+  for (; iter != data.ping_events_end(); ++iter) {
+    PingEvent ping = *iter;
+    CString msg;
+    msg.Format(_T("\nPing App = %s, Type = %s, Result = %s, Error = %d\n"),
+               GuidToString(data.app_data().app_guid()),
+               PingTypeToString(ping.event_type()),
+               PingResultToString(ping.event_result()),
+               ping.error_code());
+    printf("%S", msg);
+    CORE_LOG(L1, (msg));
+
+    if (IsInstallCompletedEvent(GuidToString(data.app_data().app_guid()),
+                                ping)) {
+      __mutexScope(lock_);
+      install_result_ = ping.event_result();
+      install_completed_ = true;
+    } else if (IsUpdateCompletedEvent(GuidToString(data.app_data().app_guid()),
+                                      ping)) {
+      __mutexScope(lock_);
+      update_result_ = ping.event_result();
+      update_completed_ = true;
+    }
+  }
+}
+
+}  // namespace omaha
diff --git a/tools/OmahaCompatibility/console_writer.h b/tools/OmahaCompatibility/console_writer.h
index 024af2e..21b9342 100644
--- a/tools/OmahaCompatibility/console_writer.h
+++ b/tools/OmahaCompatibility/console_writer.h
@@ -1,76 +1,76 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_CONSOLE_WRITER_H_

-#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_CONSOLE_WRITER_H_

-

-#include <Windows.h>

-#include <tchar.h>

-#include "omaha/common/synchronized.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/worker/ping_event.h"

-#include "omaha/tools/omahacompatibility/common/ping_observer.h"

-

-namespace omaha {

-

-// Observer that writes to the console. It also remembers

-// the result for install and update completed event.

-class ConsoleWriter : public PingObserver {

- public:

-  explicit ConsoleWriter(const CString& app_guid)

-      : app_guid_(app_guid),

-        install_completed_(false),

-        install_result_(PingEvent::EVENT_RESULT_ERROR),

-        update_completed_(false),

-        update_result_(PingEvent::EVENT_RESULT_ERROR) {}

-  virtual ~ConsoleWriter() {}

-  virtual void Observe(const AppRequestData& data);

-

-  // Indicates if a install complete event has been received.

-  bool install_completed() const {

-    return install_completed_;

-  }

-  PingEvent::Results install_result() const {

-    return install_result_;

-  }

-

-  // Indicates if a update complete event has been received.

-  bool update_completed() const {

-    return update_completed_;

-  }

-  PingEvent::Results update_result() const {

-    return update_result_;

-  }

-

- private:

-  bool IsInstallCompletedEvent(const CString& app_guid,

-                               const PingEvent& ping);

-  bool IsUpdateCompletedEvent(const CString& app_guid,

-                              const PingEvent& ping);

-  CString PingResultToString(PingEvent::Results result);

-  CString PingTypeToString(PingEvent::Types type);

-

-  CString app_guid_;

-  LLock lock_;

-  PingEvent::Results install_result_;

-  bool install_completed_;

-  PingEvent::Results update_result_;

-  bool update_completed_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_CONSOLE_WRITER_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_CONSOLE_WRITER_H_
+#define OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_CONSOLE_WRITER_H_
+
+#include <Windows.h>
+#include <tchar.h>
+#include "omaha/common/synchronized.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/worker/ping_event.h"
+#include "omaha/tools/omahacompatibility/common/ping_observer.h"
+
+namespace omaha {
+
+// Observer that writes to the console. It also remembers
+// the result for install and update completed event.
+class ConsoleWriter : public PingObserver {
+ public:
+  explicit ConsoleWriter(const CString& app_guid)
+      : app_guid_(app_guid),
+        install_completed_(false),
+        install_result_(PingEvent::EVENT_RESULT_ERROR),
+        update_completed_(false),
+        update_result_(PingEvent::EVENT_RESULT_ERROR) {}
+  virtual ~ConsoleWriter() {}
+  virtual void Observe(const AppRequestData& data);
+
+  // Indicates if a install complete event has been received.
+  bool install_completed() const {
+    return install_completed_;
+  }
+  PingEvent::Results install_result() const {
+    return install_result_;
+  }
+
+  // Indicates if a update complete event has been received.
+  bool update_completed() const {
+    return update_completed_;
+  }
+  PingEvent::Results update_result() const {
+    return update_result_;
+  }
+
+ private:
+  bool IsInstallCompletedEvent(const CString& app_guid,
+                               const PingEvent& ping);
+  bool IsUpdateCompletedEvent(const CString& app_guid,
+                              const PingEvent& ping);
+  CString PingResultToString(PingEvent::Results result);
+  CString PingTypeToString(PingEvent::Types type);
+
+  CString app_guid_;
+  LLock lock_;
+  PingEvent::Results install_result_;
+  bool install_completed_;
+  PingEvent::Results update_result_;
+  bool update_completed_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_OMAHACOMPATIBILITY_CONSOLE_WRITER_H_
diff --git a/tools/OmahaCompatibility/main.cc b/tools/OmahaCompatibility/main.cc
index ee35b4d..18f1d6a 100644
--- a/tools/OmahaCompatibility/main.cc
+++ b/tools/OmahaCompatibility/main.cc
@@ -1,68 +1,68 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Invoke with:

-// omaha_comtibility_test.exe <path>\example_config.txt

-//                            <path>\GoogleUpdateSetup.exe

-// or if you only want to run the httpserver that reads the config and responds

-// appropriately use

-// OmahaCompatibility.exe <path>\example_config.txt

-//

-

-#include <Windows.h>

-#include <tchar.h>

-#include "omaha/common/vistautil.h"

-#include "omaha/tools/omahacompatibility/compatibility_test.h"

-

-void PrintUsage() {

-  wprintf(_T("Incorrect arguments\n")

-          _T("Usage:\n")

-          _T("OmahaCompatibility <Full path to config file>")

-          _T("                   <Full path to googleupdatesetup.exe>\n")

-          _T("\nor:\n")

-          _T("OmahaCompatibility <Full path to config file>")

-          _T("Note: The debug version of googleupdatesetup is needed.\n")

-          _T("You need to be admin on the machine to run this program,\n")

-          _T("although omaha itself does not need admin to run."));

-}

-

-// Set the appropriate update dev registry keys. Url, AuCheckPeriodMs

-// Start the http server.

-// Launch googleupdate.

-int _tmain(int argc, TCHAR* argv[]) {

-  if (argc < 2 || argc > 3) {

-    PrintUsage();

-    return -1;

-  }

-

-  // TODO(omaha): Remove this requirement. This is needed for now, since we

-  // need permissions to write the updatedev key to override the url that omaha

-  // talks to.

-  if (!omaha::vista_util::IsUserAdmin()) {

-    PrintUsage();

-    return -1;

-  }

-

-  omaha::CompatibilityTest compat_test;

-  compat_test.set_config_file(argv[1]);

-

-  bool test_omaha = false;

-  if (argc == 3) {

-    compat_test.set_googleupdate_setup_path(argv[2]);

-    test_omaha = true;

-  }

-  return compat_test.Main(test_omaha);

-}

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Invoke with:
+// omaha_comtibility_test.exe <path>\example_config.txt
+//                            <path>\GoogleUpdateSetup.exe
+// or if you only want to run the httpserver that reads the config and responds
+// appropriately use
+// OmahaCompatibility.exe <path>\example_config.txt
+//
+
+#include <Windows.h>
+#include <tchar.h>
+#include "omaha/common/vistautil.h"
+#include "omaha/tools/omahacompatibility/compatibility_test.h"
+
+void PrintUsage() {
+  wprintf(_T("Incorrect arguments\n")
+          _T("Usage:\n")
+          _T("OmahaCompatibility <Full path to config file>")
+          _T("                   <Full path to googleupdatesetup.exe>\n")
+          _T("\nor:\n")
+          _T("OmahaCompatibility <Full path to config file>")
+          _T("Note: The debug version of googleupdatesetup is needed.\n")
+          _T("You need to be admin on the machine to run this program,\n")
+          _T("although omaha itself does not need admin to run."));
+}
+
+// Set the appropriate update dev registry keys. Url, AuCheckPeriodMs
+// Start the http server.
+// Launch googleupdate.
+int _tmain(int argc, TCHAR* argv[]) {
+  if (argc < 2 || argc > 3) {
+    PrintUsage();
+    return -1;
+  }
+
+  // TODO(omaha): Remove this requirement. This is needed for now, since we
+  // need permissions to write the updatedev key to override the url that omaha
+  // talks to.
+  if (!omaha::vista_util::IsUserAdmin()) {
+    PrintUsage();
+    return -1;
+  }
+
+  omaha::CompatibilityTest compat_test;
+  compat_test.set_config_file(argv[1]);
+
+  bool test_omaha = false;
+  if (argc == 3) {
+    compat_test.set_googleupdate_setup_path(argv[2]);
+    test_omaha = true;
+  }
+  return compat_test.Main(test_omaha);
+}
+
diff --git a/tools/ReadTag/build.scons b/tools/ReadTag/build.scons
index e5a3746..1bde2d7 100644
--- a/tools/ReadTag/build.scons
+++ b/tools/ReadTag/build.scons
@@ -1,58 +1,58 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-local_env = env.Clone()

-local_env.Append(

-    LIBS = [

-        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],

-        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[local_env.Bit('debug')],

-        'netapi32.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'shlwapi.lib',

-        'userenv.lib',

-        'version.lib',

-        'wtsapi32.lib',

-

-        '$LIB_DIR/common.lib',

-        ],

-    CPPDEFINES = [

-        'UNICODE',

-        '_UNICODE'

-        ],

-)

-

-local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-target_name = 'ReadTag.exe'

-

-inputs = [

-    'read_tag.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  inputs += local_env.EnablePrecompile(target_name)

-

-local_env.ComponentProgram(

-    prog_name=target_name,

-    source=inputs,

-)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+local_env = env.Clone()
+local_env.Append(
+    LIBS = [
+        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],
+        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[local_env.Bit('debug')],
+        'netapi32.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'shlwapi.lib',
+        'userenv.lib',
+        'version.lib',
+        'wtsapi32.lib',
+
+        '$LIB_DIR/common.lib',
+        ],
+    CPPDEFINES = [
+        'UNICODE',
+        '_UNICODE'
+        ],
+)
+
+local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+target_name = 'ReadTag.exe'
+
+inputs = [
+    'read_tag.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  inputs += local_env.EnablePrecompile(target_name)
+
+local_env.ComponentProgram(
+    prog_name=target_name,
+    source=inputs,
+)
diff --git a/tools/ReadTag/read_tag.cc b/tools/ReadTag/read_tag.cc
index 82afd3f..39ccdea 100644
--- a/tools/ReadTag/read_tag.cc
+++ b/tools/ReadTag/read_tag.cc
@@ -1,57 +1,57 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Simple tool to read the stamped tag inside a binary.

-

-#include <Windows.h>

-#include <stdio.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/file.h"

-#include "omaha/common/extractor.h"

-

-int _tmain(int argc, TCHAR* argv[]) {

-  if (argc != 2) {

-    _tprintf(_T("Incorrect number of arguments!\n"));

-    _tprintf(_T("Usage: ReadTag <tagged_file>\n"));

-    return -1;

-  }

-

-  const TCHAR* file = argv[1];

-  if (!omaha::File::Exists(file)) {

-    _tprintf(_T("File \"%s\" not found"), file);

-    return -1;

-  }

-

-  omaha::TagExtractor ext;

-  if (!ext.OpenFile(file)) {

-    _tprintf(_T("Could not open file \"%s\""), file);

-    return -1;

-  }

-

-  int len = 0;

-  if (!ext.ExtractTag(NULL, &len)) {

-    _tprintf(_T("Extract tag failed."));

-    return -1;

-  }

-

-  scoped_array<char> buffer(new char[len]);

-  if (!ext.ExtractTag(buffer.get(), &len)) {

-    _tprintf(_T("Extract tag failed."));

-    return -1;

-  }

-

-  printf("Tag = '%s'", buffer);

-  return 0;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Simple tool to read the stamped tag inside a binary.
+
+#include <Windows.h>
+#include <stdio.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/file.h"
+#include "omaha/common/extractor.h"
+
+int _tmain(int argc, TCHAR* argv[]) {
+  if (argc != 2) {
+    _tprintf(_T("Incorrect number of arguments!\n"));
+    _tprintf(_T("Usage: ReadTag <tagged_file>\n"));
+    return -1;
+  }
+
+  const TCHAR* file = argv[1];
+  if (!omaha::File::Exists(file)) {
+    _tprintf(_T("File \"%s\" not found"), file);
+    return -1;
+  }
+
+  omaha::TagExtractor ext;
+  if (!ext.OpenFile(file)) {
+    _tprintf(_T("Could not open file \"%s\""), file);
+    return -1;
+  }
+
+  int len = 0;
+  if (!ext.ExtractTag(NULL, &len)) {
+    _tprintf(_T("Extract tag failed."));
+    return -1;
+  }
+
+  scoped_array<char> buffer(new char[len]);
+  if (!ext.ExtractTag(buffer.get(), &len)) {
+    _tprintf(_T("Extract tag failed."));
+    return -1;
+  }
+
+  printf("Tag = '%s'", buffer);
+  return 0;
+}
diff --git a/tools/SetShutDownEvent/build.scons b/tools/SetShutDownEvent/build.scons
index 0b3fd5a..5df359a 100644
--- a/tools/SetShutDownEvent/build.scons
+++ b/tools/SetShutDownEvent/build.scons
@@ -1,59 +1,59 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-local_env = env.Clone()

-local_env.Append(

-    LIBS = [

-        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],

-        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[local_env.Bit('debug')],

-        'netapi32.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'shlwapi.lib',

-        'userenv.lib',

-        'version.lib',

-        'wtsapi32.lib',

-

-        '$LIB_DIR/common.lib',

-        ],

-    CPPDEFINES = [

-        'UNICODE',

-        '_UNICODE'

-        ],

-)

-

-local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-target_name = 'SetShutDownEvent.exe'

-

-inputs = [

-    'signal_shutdown.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  inputs += local_env.EnablePrecompile(target_name)

-

-

-local_env.ComponentProgram(

-    prog_name=target_name,

-    source=inputs,

-)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+local_env = env.Clone()
+local_env.Append(
+    LIBS = [
+        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],
+        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[local_env.Bit('debug')],
+        'netapi32.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'shlwapi.lib',
+        'userenv.lib',
+        'version.lib',
+        'wtsapi32.lib',
+
+        '$LIB_DIR/common.lib',
+        ],
+    CPPDEFINES = [
+        'UNICODE',
+        '_UNICODE'
+        ],
+)
+
+local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+target_name = 'SetShutDownEvent.exe'
+
+inputs = [
+    'signal_shutdown.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  inputs += local_env.EnablePrecompile(target_name)
+
+
+local_env.ComponentProgram(
+    prog_name=target_name,
+    source=inputs,
+)
diff --git a/tools/SetShutDownEvent/signal_shutdown.cc b/tools/SetShutDownEvent/signal_shutdown.cc
index 9b5ac7e..f7d5f68 100644
--- a/tools/SetShutDownEvent/signal_shutdown.cc
+++ b/tools/SetShutDownEvent/signal_shutdown.cc
@@ -1,58 +1,58 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Simple tool to signal the shutdownevent.

-

-#include <Windows.h>

-#include <stdio.h>

-

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/utils.h"

-

-int _tmain(int argc, TCHAR* argv[]) {

-  if (argc != 2) {

-    _tprintf(_T("Tool to set the Goopdate ShutdownEvent.\n"));

-    _tprintf(_T("Usage: SetShutDownEvent <true>\n"));

-    _tprintf(_T("If arg=true the machine shutdown event is signalled.\n"));

-    return -1;

-  }

-

-  bool is_machine = false;

-  if (_tcsncmp(_T("true"), argv[1], ARRAYSIZE(_T("true"))) == 0) {

-    is_machine = true;

-  }

-

-  omaha::NamedObjectAttributes attr;

-  GetNamedObjectAttributes(omaha::kShutdownEvent, is_machine, &attr);

-  // Manual reset=true and signaled=false

-  scoped_handle shutdown_event(::CreateEvent(&attr.sa,

-                                             true,

-                                             false,

-                                             attr.name));

-  if (!shutdown_event) {

-    DWORD error = GetLastError();

-    _tprintf(_T("CreateEvent failed. error = %d\n"), error);

-    return error;

-  }

-

-  if (!::SetEvent(get(shutdown_event))) {

-    DWORD error = GetLastError();

-    _tprintf(_T("SetEvent failed. error = %d\n"), error);

-    return error;

-  }

-  _tprintf(_T("Done\n"));

-  return 0;

-}

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Simple tool to signal the shutdownevent.
+
+#include <Windows.h>
+#include <stdio.h>
+
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/utils.h"
+
+int _tmain(int argc, TCHAR* argv[]) {
+  if (argc != 2) {
+    _tprintf(_T("Tool to set the Goopdate ShutdownEvent.\n"));
+    _tprintf(_T("Usage: SetShutDownEvent <true>\n"));
+    _tprintf(_T("If arg=true the machine shutdown event is signalled.\n"));
+    return -1;
+  }
+
+  bool is_machine = false;
+  if (_tcsncmp(_T("true"), argv[1], ARRAYSIZE(_T("true"))) == 0) {
+    is_machine = true;
+  }
+
+  omaha::NamedObjectAttributes attr;
+  GetNamedObjectAttributes(omaha::kShutdownEvent, is_machine, &attr);
+  // Manual reset=true and signaled=false
+  scoped_handle shutdown_event(::CreateEvent(&attr.sa,
+                                             true,
+                                             false,
+                                             attr.name));
+  if (!shutdown_event) {
+    DWORD error = GetLastError();
+    _tprintf(_T("CreateEvent failed. error = %d\n"), error);
+    return error;
+  }
+
+  if (!::SetEvent(get(shutdown_event))) {
+    DWORD error = GetLastError();
+    _tprintf(_T("SetEvent failed. error = %d\n"), error);
+    return error;
+  }
+  _tprintf(_T("Done\n"));
+  return 0;
+}
diff --git a/tools/build.scons b/tools/build.scons
index d7cc916..e4b3640 100644
--- a/tools/build.scons
+++ b/tools/build.scons
@@ -1,33 +1,33 @@
-# Copyright 2008-2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-# Goopdump must always be built because there is a unit test for it.

-subdirs = ['goopdump']

-

-if not env.Bit('min'):

-  subdirs += [

-      'ApplyTag',

-      'CrashProcess',

-      'OmahaCompatibility',

-      'longrunning',

-      'ReadTag',

-      'PerformOnDemand',

-      'SetShutDownEvent',

-      ]

-

-for dir in subdirs:

-  env.BuildSConscript(dir)

+# Copyright 2008-2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+# Goopdump must always be built because there is a unit test for it.
+subdirs = ['goopdump']
+
+if not env.Bit('min'):
+  subdirs += [
+      'ApplyTag',
+      'CrashProcess',
+      'OmahaCompatibility',
+      'longrunning',
+      'ReadTag',
+      'PerformOnDemand',
+      'SetShutDownEvent',
+      ]
+
+for dir in subdirs:
+  env.BuildSConscript(dir)
diff --git a/tools/goopdump/build.scons b/tools/goopdump/build.scons
index 6af5ac4..86709ec 100644
--- a/tools/goopdump/build.scons
+++ b/tools/goopdump/build.scons
@@ -1,139 +1,139 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-# Builds goopdump.exe which is a utility for dumping config info for

-# googleupdate.

-

-

-Import('env')

-

-#

-# Build Goopdump.lib

-#

-lib_env = env.Clone()

-

-target_name = 'goopdump.lib'

-

-lib_inputs = [

-    'data_dumper.cc',

-    'data_dumper_app_manager.cc',

-    'data_dumper_goopdate.cc',

-    'data_dumper_network.cc',

-    'data_dumper_oneclick.cc',

-    'data_dumper_osdata.cc',

-    'dump_log.cc',

-    'goopdump.cc',

-    'goopdump_cmd_line_parser.cc',

-    'process_commandline.cc',

-    'process_monitor.cc',

-    ]

-if env.Bit('use_precompiled_headers'):

-  lib_inputs += lib_env.EnablePrecompile(target_name)

-

-lib_env.ComponentLibrary(

-    lib_name=target_name,

-    source=lib_inputs

-)

-

-

-#

-# Build Goopdump.exe

-#

-exe_env = env.Clone()

-

-v = exe_env['product_version'][0]

-version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])

-

-exe_env.Append(

-    RCFLAGS = [

-        '/DVERSION_MAJOR=%d' % v[0],

-        '/DVERSION_MINOR=%d' % v[1],

-        '/DVERSION_BUILD=%d' % v[2],

-        '/DVERSION_PATCH=%d' % v[3],

-        '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,

-        '/DLANGAUGE_STRING=\\"en\\"',

-        ],

-

-    LIBS = [

-        'delayimp.lib',

-        'kernel32.lib',

-        'pdh.lib',

-        '$LIB_DIR/common.lib',

-        '$LIB_DIR/goopdate_dll.lib',

-        '$LIB_DIR/logging.lib',

-        '$LIB_DIR/net.lib',

-        '$LIB_DIR/statsreport.lib',

-        '$LIB_DIR/goopdump.lib',

-        '$LIB_DIR/worker.lib',

-        ('atls.lib', 'atlsd.lib')[exe_env.Bit('debug')],

-        ('libcmt.lib', 'libcmtd.lib')[exe_env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[exe_env.Bit('debug')],

-        'advapi32.lib',

-        'comctl32.lib',

-        'crypt32.lib',

-        'delayimp.lib',

-        'Iphlpapi.lib',

-        'msi.lib',

-        'mstask.lib',

-        'netapi32.lib',

-        'ole32.lib',

-        'oleaut32.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'secur32.lib',

-        'shell32.lib',

-        'shlwapi.lib',

-        'user32.lib',

-        'version.lib',

-        'urlmon.lib',

-        'userenv.lib',

-        'uuid.lib',

-        'wininet.lib',

-        'wintrust.lib',

-        'wtsapi32.lib',

-        ],

-

-    LINKFLAGS = [

-        '/DELAYLOAD:ole32.dll',

-        '/DELAYLOAD:oleaut32.dll',

-        '/DELAYLOAD:psapi.dll',

-        '/DELAYLOAD:rasapi32.dll',

-        '/DELAYLOAD:shell32.dll',

-        '/DELAYLOAD:shlwapi.dll',

-        '/DELAYLOAD:userenv.dll',

-        '/DELAYLOAD:version.dll',

-        '/DELAYLOAD:wtsapi32.dll',

-        ],

-)

-

-exe_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-exe_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-target_name = 'goopdump.exe'

-

-exe_inputs = [

-    'goopdump_main.cc',

-    exe_env.RES('resource.rc'),

-    ]

-if env.Bit('use_precompiled_headers'):

-  exe_inputs += exe_env.EnablePrecompile(target_name)

-

-exe_env.ComponentProgram(

-    prog_name=target_name,

-    source=exe_inputs

-)

-

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+# Builds goopdump.exe which is a utility for dumping config info for
+# googleupdate.
+
+
+Import('env')
+
+#
+# Build Goopdump.lib
+#
+lib_env = env.Clone()
+
+target_name = 'goopdump.lib'
+
+lib_inputs = [
+    'data_dumper.cc',
+    'data_dumper_app_manager.cc',
+    'data_dumper_goopdate.cc',
+    'data_dumper_network.cc',
+    'data_dumper_oneclick.cc',
+    'data_dumper_osdata.cc',
+    'dump_log.cc',
+    'goopdump.cc',
+    'goopdump_cmd_line_parser.cc',
+    'process_commandline.cc',
+    'process_monitor.cc',
+    ]
+if env.Bit('use_precompiled_headers'):
+  lib_inputs += lib_env.EnablePrecompile(target_name)
+
+lib_env.ComponentLibrary(
+    lib_name=target_name,
+    source=lib_inputs
+)
+
+
+#
+# Build Goopdump.exe
+#
+exe_env = env.Clone()
+
+v = exe_env['product_version'][0]
+version_string = '%d.%d.%d.%d' % (v[0], v[1], v[2], v[3])
+
+exe_env.Append(
+    RCFLAGS = [
+        '/DVERSION_MAJOR=%d' % v[0],
+        '/DVERSION_MINOR=%d' % v[1],
+        '/DVERSION_BUILD=%d' % v[2],
+        '/DVERSION_PATCH=%d' % v[3],
+        '/DVERSION_NUMBER_STRING=\\"%s\\"' % version_string,
+        '/DLANGAUGE_STRING=\\"en\\"',
+        ],
+
+    LIBS = [
+        'delayimp.lib',
+        'kernel32.lib',
+        'pdh.lib',
+        '$LIB_DIR/common.lib',
+        '$LIB_DIR/goopdate_dll.lib',
+        '$LIB_DIR/logging.lib',
+        '$LIB_DIR/net.lib',
+        '$LIB_DIR/statsreport.lib',
+        '$LIB_DIR/goopdump.lib',
+        '$LIB_DIR/worker.lib',
+        ('atls.lib', 'atlsd.lib')[exe_env.Bit('debug')],
+        ('libcmt.lib', 'libcmtd.lib')[exe_env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[exe_env.Bit('debug')],
+        'advapi32.lib',
+        'comctl32.lib',
+        'crypt32.lib',
+        'delayimp.lib',
+        'Iphlpapi.lib',
+        'msi.lib',
+        'mstask.lib',
+        'netapi32.lib',
+        'ole32.lib',
+        'oleaut32.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'secur32.lib',
+        'shell32.lib',
+        'shlwapi.lib',
+        'user32.lib',
+        'version.lib',
+        'urlmon.lib',
+        'userenv.lib',
+        'uuid.lib',
+        'wininet.lib',
+        'wintrust.lib',
+        'wtsapi32.lib',
+        ],
+
+    LINKFLAGS = [
+        '/DELAYLOAD:ole32.dll',
+        '/DELAYLOAD:oleaut32.dll',
+        '/DELAYLOAD:psapi.dll',
+        '/DELAYLOAD:rasapi32.dll',
+        '/DELAYLOAD:shell32.dll',
+        '/DELAYLOAD:shlwapi.dll',
+        '/DELAYLOAD:userenv.dll',
+        '/DELAYLOAD:version.dll',
+        '/DELAYLOAD:wtsapi32.dll',
+        ],
+)
+
+exe_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+exe_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+target_name = 'goopdump.exe'
+
+exe_inputs = [
+    'goopdump_main.cc',
+    exe_env.RES('resource.rc'),
+    ]
+if env.Bit('use_precompiled_headers'):
+  exe_inputs += exe_env.EnablePrecompile(target_name)
+
+exe_env.ComponentProgram(
+    prog_name=target_name,
+    source=exe_inputs
+)
+
diff --git a/tools/goopdump/data_dumper.cc b/tools/goopdump/data_dumper.cc
index fd0e02d..6ee6169 100644
--- a/tools/goopdump/data_dumper.cc
+++ b/tools/goopdump/data_dumper.cc
@@ -1,146 +1,146 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/data_dumper.h"

-

-#include "omaha/common/reg_key.h"

-#include "omaha/tools/goopdump/dump_log.h"

-

-namespace omaha {

-

-DataDumper::DataDumper() {

-}

-

-DataDumper::~DataDumper() {

-}

-

-void DataDumper::DumpRegValueStr(const DumpLog& dump_log,

-                                 const TCHAR* full_key_name,

-                                 const TCHAR* value_name) {

-  DumpRegValueStrRet(dump_log, full_key_name, value_name, NULL);

-}

-

-void DataDumper::DumpRegValueStrRet(const DumpLog& dump_log,

-                                    const TCHAR* full_key_name,

-                                    const TCHAR* value_name,

-                                    CString* str) {

-  CString val;

-  CString key = full_key_name;

-  HRESULT hr = RegKey::GetValue(key, value_name, &val);

-

-  CString value_name_str = value_name ? value_name : _T("default");

-

-  if (SUCCEEDED(hr)) {

-    dump_log.WriteLine(_T("%s[%s] = %s"), key, value_name_str, val);

-  } else {

-    dump_log.WriteLine(_T("%s HAS NO VALUE"), key);

-  }

-

-  if (str) {

-    *str = val;

-  }

-}

-

-DumpHeader::DumpHeader(const DumpLog& dump_log, const TCHAR* header_name)

-    : dump_log_(dump_log) {

-  dump_log_.WriteLine(_T(""));

-  dump_log_.WriteLine(_T("--------------------------------------------------"));

-  dump_log_.WriteLine(header_name);

-  dump_log_.WriteLine(_T("--------------------------------------------------"));

-}

-

-DumpHeader::~DumpHeader() {

-  dump_log_.WriteLine(_T("--------------------------------------------------"));

-  dump_log_.WriteLine(_T(""));

-}

-

-void DataDumper::RecursiveDumpRegistryKey(const DumpLog& dump_log,

-                                          RegKey* key,

-                                          const int indent) {

-  ASSERT1(key);

-  CString indent_string;

-  for (int i = 0; i < indent; ++i) {

-    indent_string.Append(_T(" "));

-  }

-  uint32 value_count = key->GetValueCount();

-  for (uint32 idx = 0; idx < value_count; ++idx) {

-    CString value_name;

-    DWORD value_type = 0;

-    key->GetValueNameAt(idx, &value_name, &value_type);

-    CString value_name_disp =

-        value_name.IsEmpty() ? _T("[default]") : value_name;

-    switch (value_type) {

-      case REG_SZ: {

-        CString value;

-        key->GetValue(value_name, &value);

-        dump_log.WriteLine(_T("%s%s: (REG_SZ): %s"),

-                           indent_string,

-                           value_name_disp,

-                           value);

-        break;

-      }

-      case REG_DWORD: {

-        DWORD value = 0;

-        key->GetValue(value_name, &value);

-        dump_log.WriteLine(_T("%s%s: (REG_DWORD): %d (0x%x)"),

-                           indent_string,

-                           value_name_disp,

-                           value,

-                           value);

-        break;

-      }

-      case REG_BINARY:

-        dump_log.WriteLine(_T("%s%s: (REG_BINARY)"),

-                           indent_string,

-                           value_name_disp);

-        break;

-      case REG_MULTI_SZ:

-        dump_log.WriteLine(_T("%s%s: (REG_MULTI_SZ)"),

-                           indent_string,

-                           value_name_disp);

-        break;

-      default:

-        dump_log.WriteLine(_T("%s%s: (TYPE: %d)"),

-                           indent_string,

-                           value_name_disp,

-                           value_type);

-        break;

-    }

-  }

-

-  uint32 subkey_count = key->GetSubkeyCount();

-  for (uint32 idx = 0; idx < subkey_count; ++idx) {

-    CString subkey_name;

-    key->GetSubkeyNameAt(idx, &subkey_name);

-    RegKey subkey;

-    subkey.Open(key->Key(), subkey_name, KEY_READ);

-    dump_log.WriteLine(_T("%sSUBKEY: %s"), indent_string, subkey_name);

-    RecursiveDumpRegistryKey(dump_log, &subkey, indent+1);

-  }

-}

-

-void DataDumper::DumpRegistryKeyData(const DumpLog& dump_log,

-                                     const CString& key_name) {

-  RegKey key_root;

-  if (FAILED(key_root.Open(key_name, KEY_READ))) {

-    dump_log.WriteLine(_T("Key (%s) could not be opened"), key_name);

-    return;

-  }

-  dump_log.WriteLine(_T("ROOT KEY: %s"), key_name);

-  RecursiveDumpRegistryKey(dump_log, &key_root, 1);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/data_dumper.h"
+
+#include "omaha/common/reg_key.h"
+#include "omaha/tools/goopdump/dump_log.h"
+
+namespace omaha {
+
+DataDumper::DataDumper() {
+}
+
+DataDumper::~DataDumper() {
+}
+
+void DataDumper::DumpRegValueStr(const DumpLog& dump_log,
+                                 const TCHAR* full_key_name,
+                                 const TCHAR* value_name) {
+  DumpRegValueStrRet(dump_log, full_key_name, value_name, NULL);
+}
+
+void DataDumper::DumpRegValueStrRet(const DumpLog& dump_log,
+                                    const TCHAR* full_key_name,
+                                    const TCHAR* value_name,
+                                    CString* str) {
+  CString val;
+  CString key = full_key_name;
+  HRESULT hr = RegKey::GetValue(key, value_name, &val);
+
+  CString value_name_str = value_name ? value_name : _T("default");
+
+  if (SUCCEEDED(hr)) {
+    dump_log.WriteLine(_T("%s[%s] = %s"), key, value_name_str, val);
+  } else {
+    dump_log.WriteLine(_T("%s HAS NO VALUE"), key);
+  }
+
+  if (str) {
+    *str = val;
+  }
+}
+
+DumpHeader::DumpHeader(const DumpLog& dump_log, const TCHAR* header_name)
+    : dump_log_(dump_log) {
+  dump_log_.WriteLine(_T(""));
+  dump_log_.WriteLine(_T("--------------------------------------------------"));
+  dump_log_.WriteLine(header_name);
+  dump_log_.WriteLine(_T("--------------------------------------------------"));
+}
+
+DumpHeader::~DumpHeader() {
+  dump_log_.WriteLine(_T("--------------------------------------------------"));
+  dump_log_.WriteLine(_T(""));
+}
+
+void DataDumper::RecursiveDumpRegistryKey(const DumpLog& dump_log,
+                                          RegKey* key,
+                                          const int indent) {
+  ASSERT1(key);
+  CString indent_string;
+  for (int i = 0; i < indent; ++i) {
+    indent_string.Append(_T(" "));
+  }
+  uint32 value_count = key->GetValueCount();
+  for (uint32 idx = 0; idx < value_count; ++idx) {
+    CString value_name;
+    DWORD value_type = 0;
+    key->GetValueNameAt(idx, &value_name, &value_type);
+    CString value_name_disp =
+        value_name.IsEmpty() ? _T("[default]") : value_name;
+    switch (value_type) {
+      case REG_SZ: {
+        CString value;
+        key->GetValue(value_name, &value);
+        dump_log.WriteLine(_T("%s%s: (REG_SZ): %s"),
+                           indent_string,
+                           value_name_disp,
+                           value);
+        break;
+      }
+      case REG_DWORD: {
+        DWORD value = 0;
+        key->GetValue(value_name, &value);
+        dump_log.WriteLine(_T("%s%s: (REG_DWORD): %d (0x%x)"),
+                           indent_string,
+                           value_name_disp,
+                           value,
+                           value);
+        break;
+      }
+      case REG_BINARY:
+        dump_log.WriteLine(_T("%s%s: (REG_BINARY)"),
+                           indent_string,
+                           value_name_disp);
+        break;
+      case REG_MULTI_SZ:
+        dump_log.WriteLine(_T("%s%s: (REG_MULTI_SZ)"),
+                           indent_string,
+                           value_name_disp);
+        break;
+      default:
+        dump_log.WriteLine(_T("%s%s: (TYPE: %d)"),
+                           indent_string,
+                           value_name_disp,
+                           value_type);
+        break;
+    }
+  }
+
+  uint32 subkey_count = key->GetSubkeyCount();
+  for (uint32 idx = 0; idx < subkey_count; ++idx) {
+    CString subkey_name;
+    key->GetSubkeyNameAt(idx, &subkey_name);
+    RegKey subkey;
+    subkey.Open(key->Key(), subkey_name, KEY_READ);
+    dump_log.WriteLine(_T("%sSUBKEY: %s"), indent_string, subkey_name);
+    RecursiveDumpRegistryKey(dump_log, &subkey, indent+1);
+  }
+}
+
+void DataDumper::DumpRegistryKeyData(const DumpLog& dump_log,
+                                     const CString& key_name) {
+  RegKey key_root;
+  if (FAILED(key_root.Open(key_name, KEY_READ))) {
+    dump_log.WriteLine(_T("Key (%s) could not be opened"), key_name);
+    return;
+  }
+  dump_log.WriteLine(_T("ROOT KEY: %s"), key_name);
+  RecursiveDumpRegistryKey(dump_log, &key_root, 1);
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/data_dumper.h b/tools/goopdump/data_dumper.h
index 164fe64..886ed93 100644
--- a/tools/goopdump/data_dumper.h
+++ b/tools/goopdump/data_dumper.h
@@ -1,72 +1,72 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_H__

-#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class RegKey;

-

-class DumpLog;

-struct GoopdumpCmdLineArgs;

-

-class DataDumper {

- public:

-  DataDumper();

-  virtual ~DataDumper();

-

-  virtual HRESULT Process(const DumpLog& dump_log,

-                          const GoopdumpCmdLineArgs& args) = 0;

-

- protected:

-  void DumpRegValueStr(const DumpLog& dump_log,

-                       const TCHAR* full_key_name,

-                       const TCHAR* value_name);

-

-  void DumpRegValueStrRet(const DumpLog& dump_log,

-                          const TCHAR* full_key_name,

-                          const TCHAR* value_name,

-                          CString* str);

-

-  void DumpRegistryKeyData(const DumpLog& dump_log,

-                           const CString& key_name);

-

- private:

-  void RecursiveDumpRegistryKey(const DumpLog& dump_log,

-                                RegKey* key,

-                                const int indent);

-

-  DISALLOW_EVIL_CONSTRUCTORS(DataDumper);

-};

-

-class DumpHeader {

- public:

-  DumpHeader(const DumpLog& dump_log, const TCHAR* header_name);

-  ~DumpHeader();

-

- private:

-  const DumpLog& dump_log_;

-  DISALLOW_EVIL_CONSTRUCTORS(DumpHeader);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_H__

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_H__
+#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class RegKey;
+
+class DumpLog;
+struct GoopdumpCmdLineArgs;
+
+class DataDumper {
+ public:
+  DataDumper();
+  virtual ~DataDumper();
+
+  virtual HRESULT Process(const DumpLog& dump_log,
+                          const GoopdumpCmdLineArgs& args) = 0;
+
+ protected:
+  void DumpRegValueStr(const DumpLog& dump_log,
+                       const TCHAR* full_key_name,
+                       const TCHAR* value_name);
+
+  void DumpRegValueStrRet(const DumpLog& dump_log,
+                          const TCHAR* full_key_name,
+                          const TCHAR* value_name,
+                          CString* str);
+
+  void DumpRegistryKeyData(const DumpLog& dump_log,
+                           const CString& key_name);
+
+ private:
+  void RecursiveDumpRegistryKey(const DumpLog& dump_log,
+                                RegKey* key,
+                                const int indent);
+
+  DISALLOW_EVIL_CONSTRUCTORS(DataDumper);
+};
+
+class DumpHeader {
+ public:
+  DumpHeader(const DumpLog& dump_log, const TCHAR* header_name);
+  ~DumpHeader();
+
+ private:
+  const DumpLog& dump_log_;
+  DISALLOW_EVIL_CONSTRUCTORS(DumpHeader);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_H__
+
diff --git a/tools/goopdump/data_dumper_app_manager.cc b/tools/goopdump/data_dumper_app_manager.cc
index aea2374..a07c818 100644
--- a/tools/goopdump/data_dumper_app_manager.cc
+++ b/tools/goopdump/data_dumper_app_manager.cc
@@ -1,181 +1,181 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/data_dumper_app_manager.h"

-

-#include <vector>

-

-#include "omaha/common/reg_key.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/application_manager.h"

-#include "omaha/tools/goopdump/dump_log.h"

-#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"

-

-namespace omaha {

-

-namespace {

-

-CString ActiveStateToString(omaha::AppData::ActiveStates state) {

-  CString str = _T("UNDEFINED");

-  switch (state) {

-    case omaha::AppData::ACTIVE_NOTRUN:

-      str = _T("NOT RUN");

-      break;

-    case omaha::AppData::ACTIVE_RUN:

-      str = _T("RUN");

-      break;

-    case omaha::AppData::ACTIVE_UNKNOWN:

-      str = _T("UNKNOWN");

-      break;

-    default:

-      ASSERT1(false);

-      break;

-  }

-  return str;

-}

-

-CString BoolToString(bool val) {

-  return val ? _T("TRUE") : _T("FALSE");

-}

-

-// TODO(omaha): This should use display_name if available. Only Omaha needs to

-// be hard-coded. Maybe write its name during Setup instead.

-CString GuidToFriendlyAppName(const GUID& guid) {

-  struct MapGuidToName {

-    const TCHAR* guid;

-    const TCHAR* name;

-  };

-

-  // IMPORTANT: Only put released products in this list since this tool will go

-  // to customers.

-  MapGuidToName guid_to_name[] = {

-    {_T("{283EAF47-8817-4c2b-A801-AD1FADFB7BAA}"), _T("Gears")},

-    {_T("{430FD4D0-B729-4F61-AA34-91526481799D}"), _T("Google Update")},

-    {_T("{8A69D345-D564-463C-AFF1-A69D9E530F96}"), _T("Chrome")},

-  };

-

-  CString str = _T("unknown");

-

-  for (int i = 0; i < arraysize(guid_to_name); ++i) {

-    if (::IsEqualGUID(guid, StringToGuid(guid_to_name[i].guid))) {

-      str = guid_to_name[i].name;

-      break;

-    }

-  }

-

-  return str;

-}

-

-}  // namespace

-

-DataDumperAppManager::DataDumperAppManager() {

-}

-

-DataDumperAppManager::~DataDumperAppManager() {

-}

-

-HRESULT DataDumperAppManager::Process(const DumpLog& dump_log,

-                                      const GoopdumpCmdLineArgs& args) {

-  UNREFERENCED_PARAMETER(args);

-

-  DumpHeader header(dump_log, _T("AppManager Data"));

-

-  if (args.is_machine) {

-    dump_log.WriteLine(_T("--- MACHINE APPMANAGER DATA ---"));

-    AppManager app_manager(true);

-    DumpAppManagerData(dump_log, app_manager);

-    DumpRawRegistryData(dump_log, true);

-  }

-

-  if (args.is_user) {

-    dump_log.WriteLine(_T("--- USER APPMANAGER DATA ---"));

-    AppManager app_manager(false);

-    DumpAppManagerData(dump_log, app_manager);

-    DumpRawRegistryData(dump_log, false);

-  }

-

-  return S_OK;

-}

-

-void DataDumperAppManager::DumpAppManagerData(const DumpLog& dump_log,

-                                              const AppManager& app_manager) {

-  ProductDataVector products;

-  HRESULT hr = app_manager.GetRegisteredProducts(&products);

-  if (FAILED(hr)) {

-    dump_log.WriteLine(_T("Failed GetRegisteredProducts() hr=0x%x"), hr);

-    return;

-  }

-

-  for (size_t i = 0; i < products.size(); ++i) {

-    const ProductData& product_data = products[i];

-    const AppData& data = product_data.app_data();

-

-    dump_log.WriteLine(_T("---------- APP ----------"));

-    dump_log.WriteLine(_T("app name:\t%s"),

-                       GuidToFriendlyAppName(data.app_guid()));

-    dump_log.WriteLine(_T("guid:\t\t%s"), GuidToString(data.app_guid()));

-    // parent_app_guid is not displayed.

-    dump_log.WriteLine(_T("is_machine_app:\t%s"),

-                       BoolToString(data.is_machine_app()));

-    dump_log.WriteLine(_T("version:\t%s"), data.version());

-    dump_log.WriteLine(_T("prev_version:\t%s"), data.previous_version());

-    dump_log.WriteLine(_T("language:\t%s"), data.language());

-    dump_log.WriteLine(_T("ap:\t\t%s"), data.ap());

-    dump_log.WriteLine(_T("ttt:\t\t%s"), data.tt_token());

-    dump_log.WriteLine(_T("iid:\t\t%s"), GuidToString(data.iid()));

-    dump_log.WriteLine(_T("brand:\t\t%s"), data.brand_code());

-    dump_log.WriteLine(_T("client:\t\t%s"), data.client_id());

-    dump_log.WriteLine(_T("referral:\t\t%s"), data.referral_id());

-    dump_log.WriteLine(_T("install_time_diff_sec:\t%u"),

-                       data.install_time_diff_sec());

-    dump_log.WriteLine(_T("is_oem_install:\t%s"),

-                       BoolToString(data.is_oem_install()));

-    dump_log.WriteLine(_T("is_eula_accepted:\t%s"),

-                       BoolToString(data.is_eula_accepted()));

-    // TODO(omaha): Use display_name above and note its use on this line.

-    dump_log.WriteLine(_T("browser_type:\t\t%u"), data.browser_type());

-

-    // The following are not saved and thus should always have default values.

-    dump_log.WriteLine(_T("install_source:\t\t%s"), data.install_source());

-    dump_log.WriteLine(_T("encoded_installer_data:\t\t%s"),

-                       data.encoded_installer_data());

-    dump_log.WriteLine(_T("install_data_index:\t\t%s"),

-                       data.install_data_index());

-

-    dump_log.WriteLine(_T("usage_stats_enable:\t\t%u"),

-                       data.usage_stats_enable());

-    dump_log.WriteLine(_T("did_run:\t%s"),

-                       ActiveStateToString(data.did_run()));

-

-    // The following are not saved and thus should always have default values.

-    dump_log.WriteLine(_T("is_uninstalled:\t%s"),

-                       BoolToString(data.is_uninstalled()));

-    dump_log.WriteLine(_T("is_update_disabled:\t%s"),

-                       BoolToString(data.is_update_disabled()));

-    dump_log.WriteLine(_T(""));

-  }

-}

-

-void DataDumperAppManager::DumpRawRegistryData(const DumpLog& dump_log,

-                                               bool is_machine) {

-  dump_log.WriteLine(_T("--- RAW REGISTRY DATA ---"));

-  CString key_name = ConfigManager::Instance()->registry_clients(is_machine);

-  DumpRegistryKeyData(dump_log, key_name);

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/data_dumper_app_manager.h"
+
+#include <vector>
+
+#include "omaha/common/reg_key.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/application_manager.h"
+#include "omaha/tools/goopdump/dump_log.h"
+#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"
+
+namespace omaha {
+
+namespace {
+
+CString ActiveStateToString(omaha::AppData::ActiveStates state) {
+  CString str = _T("UNDEFINED");
+  switch (state) {
+    case omaha::AppData::ACTIVE_NOTRUN:
+      str = _T("NOT RUN");
+      break;
+    case omaha::AppData::ACTIVE_RUN:
+      str = _T("RUN");
+      break;
+    case omaha::AppData::ACTIVE_UNKNOWN:
+      str = _T("UNKNOWN");
+      break;
+    default:
+      ASSERT1(false);
+      break;
+  }
+  return str;
+}
+
+CString BoolToString(bool val) {
+  return val ? _T("TRUE") : _T("FALSE");
+}
+
+// TODO(omaha): This should use display_name if available. Only Omaha needs to
+// be hard-coded. Maybe write its name during Setup instead.
+CString GuidToFriendlyAppName(const GUID& guid) {
+  struct MapGuidToName {
+    const TCHAR* guid;
+    const TCHAR* name;
+  };
+
+  // IMPORTANT: Only put released products in this list since this tool will go
+  // to customers.
+  MapGuidToName guid_to_name[] = {
+    {_T("{283EAF47-8817-4c2b-A801-AD1FADFB7BAA}"), _T("Gears")},
+    {_T("{430FD4D0-B729-4F61-AA34-91526481799D}"), _T("Google Update")},
+    {_T("{8A69D345-D564-463C-AFF1-A69D9E530F96}"), _T("Chrome")},
+  };
+
+  CString str = _T("unknown");
+
+  for (int i = 0; i < arraysize(guid_to_name); ++i) {
+    if (::IsEqualGUID(guid, StringToGuid(guid_to_name[i].guid))) {
+      str = guid_to_name[i].name;
+      break;
+    }
+  }
+
+  return str;
+}
+
+}  // namespace
+
+DataDumperAppManager::DataDumperAppManager() {
+}
+
+DataDumperAppManager::~DataDumperAppManager() {
+}
+
+HRESULT DataDumperAppManager::Process(const DumpLog& dump_log,
+                                      const GoopdumpCmdLineArgs& args) {
+  UNREFERENCED_PARAMETER(args);
+
+  DumpHeader header(dump_log, _T("AppManager Data"));
+
+  if (args.is_machine) {
+    dump_log.WriteLine(_T("--- MACHINE APPMANAGER DATA ---"));
+    AppManager app_manager(true);
+    DumpAppManagerData(dump_log, app_manager);
+    DumpRawRegistryData(dump_log, true);
+  }
+
+  if (args.is_user) {
+    dump_log.WriteLine(_T("--- USER APPMANAGER DATA ---"));
+    AppManager app_manager(false);
+    DumpAppManagerData(dump_log, app_manager);
+    DumpRawRegistryData(dump_log, false);
+  }
+
+  return S_OK;
+}
+
+void DataDumperAppManager::DumpAppManagerData(const DumpLog& dump_log,
+                                              const AppManager& app_manager) {
+  ProductDataVector products;
+  HRESULT hr = app_manager.GetRegisteredProducts(&products);
+  if (FAILED(hr)) {
+    dump_log.WriteLine(_T("Failed GetRegisteredProducts() hr=0x%x"), hr);
+    return;
+  }
+
+  for (size_t i = 0; i < products.size(); ++i) {
+    const ProductData& product_data = products[i];
+    const AppData& data = product_data.app_data();
+
+    dump_log.WriteLine(_T("---------- APP ----------"));
+    dump_log.WriteLine(_T("app name:\t%s"),
+                       GuidToFriendlyAppName(data.app_guid()));
+    dump_log.WriteLine(_T("guid:\t\t%s"), GuidToString(data.app_guid()));
+    // parent_app_guid is not displayed.
+    dump_log.WriteLine(_T("is_machine_app:\t%s"),
+                       BoolToString(data.is_machine_app()));
+    dump_log.WriteLine(_T("version:\t%s"), data.version());
+    dump_log.WriteLine(_T("prev_version:\t%s"), data.previous_version());
+    dump_log.WriteLine(_T("language:\t%s"), data.language());
+    dump_log.WriteLine(_T("ap:\t\t%s"), data.ap());
+    dump_log.WriteLine(_T("ttt:\t\t%s"), data.tt_token());
+    dump_log.WriteLine(_T("iid:\t\t%s"), GuidToString(data.iid()));
+    dump_log.WriteLine(_T("brand:\t\t%s"), data.brand_code());
+    dump_log.WriteLine(_T("client:\t\t%s"), data.client_id());
+    dump_log.WriteLine(_T("referral:\t\t%s"), data.referral_id());
+    dump_log.WriteLine(_T("install_time_diff_sec:\t%u"),
+                       data.install_time_diff_sec());
+    dump_log.WriteLine(_T("is_oem_install:\t%s"),
+                       BoolToString(data.is_oem_install()));
+    dump_log.WriteLine(_T("is_eula_accepted:\t%s"),
+                       BoolToString(data.is_eula_accepted()));
+    // TODO(omaha): Use display_name above and note its use on this line.
+    dump_log.WriteLine(_T("browser_type:\t\t%u"), data.browser_type());
+
+    // The following are not saved and thus should always have default values.
+    dump_log.WriteLine(_T("install_source:\t\t%s"), data.install_source());
+    dump_log.WriteLine(_T("encoded_installer_data:\t\t%s"),
+                       data.encoded_installer_data());
+    dump_log.WriteLine(_T("install_data_index:\t\t%s"),
+                       data.install_data_index());
+
+    dump_log.WriteLine(_T("usage_stats_enable:\t\t%u"),
+                       data.usage_stats_enable());
+    dump_log.WriteLine(_T("did_run:\t%s"),
+                       ActiveStateToString(data.did_run()));
+
+    // The following are not saved and thus should always have default values.
+    dump_log.WriteLine(_T("is_uninstalled:\t%s"),
+                       BoolToString(data.is_uninstalled()));
+    dump_log.WriteLine(_T("is_update_disabled:\t%s"),
+                       BoolToString(data.is_update_disabled()));
+    dump_log.WriteLine(_T(""));
+  }
+}
+
+void DataDumperAppManager::DumpRawRegistryData(const DumpLog& dump_log,
+                                               bool is_machine) {
+  dump_log.WriteLine(_T("--- RAW REGISTRY DATA ---"));
+  CString key_name = ConfigManager::Instance()->registry_clients(is_machine);
+  DumpRegistryKeyData(dump_log, key_name);
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/data_dumper_app_manager.h b/tools/goopdump/data_dumper_app_manager.h
index 1c7e886..1f7f842 100644
--- a/tools/goopdump/data_dumper_app_manager.h
+++ b/tools/goopdump/data_dumper_app_manager.h
@@ -1,48 +1,48 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_APP_MANAGER_H__

-#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_APP_MANAGER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-#include "omaha/tools/goopdump/data_dumper.h"

-

-namespace omaha {

-

-class AppManager;

-

-class DataDumperAppManager : public DataDumper {

- public:

-  DataDumperAppManager();

-  virtual ~DataDumperAppManager();

-

-  virtual HRESULT Process(const DumpLog& dump_log,

-                          const GoopdumpCmdLineArgs& args);

-

- private:

-  void DumpAppManagerData(const DumpLog& dump_log,

-                          const AppManager& app_manager);

-  void DumpRawRegistryData(const DumpLog& dump_log, bool is_machine);

-

-  DISALLOW_EVIL_CONSTRUCTORS(DataDumperAppManager);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_APP_MANAGER_H__

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_APP_MANAGER_H__
+#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_APP_MANAGER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+#include "omaha/tools/goopdump/data_dumper.h"
+
+namespace omaha {
+
+class AppManager;
+
+class DataDumperAppManager : public DataDumper {
+ public:
+  DataDumperAppManager();
+  virtual ~DataDumperAppManager();
+
+  virtual HRESULT Process(const DumpLog& dump_log,
+                          const GoopdumpCmdLineArgs& args);
+
+ private:
+  void DumpAppManagerData(const DumpLog& dump_log,
+                          const AppManager& app_manager);
+  void DumpRawRegistryData(const DumpLog& dump_log, bool is_machine);
+
+  DISALLOW_EVIL_CONSTRUCTORS(DataDumperAppManager);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_APP_MANAGER_H__
+
diff --git a/tools/goopdump/data_dumper_goopdate.cc b/tools/goopdump/data_dumper_goopdate.cc
index 5119199..30fde1c 100644
--- a/tools/goopdump/data_dumper_goopdate.cc
+++ b/tools/goopdump/data_dumper_goopdate.cc
@@ -1,607 +1,607 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/tools/goopdump/data_dumper_goopdate.h"

-

-#include <atltime.h>

-#include <mstask.h>

-#include <psapi.h>

-#include <regstr.h>

-#include <tlhelp32.h>

-

-#include <list>

-

-#include "omaha/common/constants.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/file_reader.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_ptr_cotask.h"

-#include "omaha/common/service_utils.h"

-#include "omaha/common/time.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/event_logger.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/tools/goopdump/dump_log.h"

-#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"

-#include "omaha/tools/goopdump/process_commandline.h"

-

-namespace {

-

-CString FormatRunTimeString(SYSTEMTIME* system_time) {

-  SYSTEMTIME local_time = {0};

-  ::SystemTimeToTzSpecificLocalTime(NULL, system_time, &local_time);

-  CString str;

-  str.Format(_T("%02d/%02d/%04d %02d:%02d:%02d"),

-             local_time.wMonth,

-             local_time.wDay,

-             local_time.wYear,

-             local_time.wHour,

-             local_time.wMinute,

-             local_time.wSecond);

-  return str;

-}

-

-}  // namespace

-

-namespace omaha {

-

-DataDumperGoopdate::DataDumperGoopdate() {

-}

-

-DataDumperGoopdate::~DataDumperGoopdate() {

-}

-

-HRESULT DataDumperGoopdate::Process(const DumpLog& dump_log,

-                                    const GoopdumpCmdLineArgs& args) {

-  UNREFERENCED_PARAMETER(args);

-

-  DumpHeader header(dump_log, _T("Goopdate Data"));

-

-  dump_log.WriteLine(_T(""));

-  dump_log.WriteLine(_T("-- GENERAL / GLOBAL DATA --"));

-  DumpHostsFile(dump_log);

-  DumpGoogleUpdateIniFile(dump_log);

-  DumpUpdateDevKeys(dump_log);

-  DumpLogFile(dump_log);

-  DumpEventLog(dump_log);

-  DumpGoogleUpdateProcessInfo(dump_log);

-

-  if (args.is_machine) {

-    dump_log.WriteLine(_T(""));

-    dump_log.WriteLine(_T("-- PER-MACHINE DATA --"));

-    DumpDirContents(dump_log, true);

-    DumpServiceInfo(dump_log);

-  }

-

-  if (args.is_user) {

-    dump_log.WriteLine(_T(""));

-    dump_log.WriteLine(_T("-- PER-USER DATA --"));

-    DumpDirContents(dump_log, false);

-    DumpRunKeys(dump_log);

-  }

-

-  DumpScheduledTaskInfo(dump_log, args.is_machine);

-

-  return S_OK;

-}

-

-void DataDumperGoopdate::DumpDirContents(const DumpLog& dump_log,

-                                         bool is_machine) {

-  DumpHeader header(dump_log, _T("Directory Contents"));

-

-  CString registered_version;

-  if (FAILED(GetRegisteredVersion(is_machine, &registered_version))) {

-    dump_log.WriteLine(_T("Failed to get registered version."));

-    return;

-  }

-

-  CString dll_dir;

-  if (FAILED(GetDllDir(is_machine, &dll_dir))) {

-    dump_log.WriteLine(_T("Failed to get dlldir."));

-    return;

-  }

-

-  dump_log.WriteLine(_T("Version:\t%s"), registered_version);

-  dump_log.WriteLine(_T("Dll Dir:\t%s"), dll_dir);

-

-  // Enumerate all files in the DllPath and log them.

-  std::vector<CString> matching_paths;

-  HRESULT hr = File::GetWildcards(dll_dir, _T("*.*"), &matching_paths);

-  if (SUCCEEDED(hr)) {

-    dump_log.WriteLine(_T(""));

-    dump_log.WriteLine(_T("Files in DllDir:"));

-    for (size_t i = 0; i < matching_paths.size(); ++i) {

-      dump_log.WriteLine(matching_paths[i]);

-    }

-    dump_log.WriteLine(_T(""));

-  } else {

-    dump_log.WriteLine(_T("Failure getting files in DllDir (0x%x)."), hr);

-  }

-}

-

-HRESULT DataDumperGoopdate::GetRegisteredVersion(bool is_machine,

-                                                 CString* version) {

-  HKEY key = NULL;

-  LONG res = ::RegOpenKeyEx(is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,

-                            GOOPDATE_REG_RELATIVE_CLIENTS GOOPDATE_APP_ID,

-                            0,

-                            KEY_READ,

-                            &key);

-  if (ERROR_SUCCESS != res) {

-    return HRESULT_FROM_WIN32(res);

-  }

-

-  DWORD type = 0;

-  DWORD version_length = 50;

-  res = ::SHQueryValueEx(key,

-                         omaha::kRegValueProductVersion,

-                         NULL,

-                         &type,

-                         CStrBuf(*version, version_length),

-                         &version_length);

-  if (ERROR_SUCCESS != res) {

-    return HRESULT_FROM_WIN32(res);

-  }

-

-  if (REG_SZ != type) {

-    return E_UNEXPECTED;

-  }

-

-  return S_OK;

-}

-

-HRESULT DataDumperGoopdate::GetDllDir(bool is_machine, CString* dll_path) {

-  TCHAR path[MAX_PATH] = {0};

-

-  CString base_path = goopdate_utils::BuildGoogleUpdateExeDir(is_machine);

-

-  // Try the side-by-side DLL first.

-  _tcscpy_s(path, arraysize(path), base_path);

-  if (!::PathAppend(path, omaha::kGoopdateDllName)) {

-    return HRESULTFromLastError();

-  }

-  if (File::Exists(path)) {

-    *dll_path = base_path;

-    return S_OK;

-  }

-

-  // Try the version subdirectory.

-  _tcscpy_s(path, arraysize(path), base_path);

-  CString version;

-  HRESULT hr = GetRegisteredVersion(is_machine, &version);

-  if (FAILED(hr)) {

-    return hr;

-  }

-  if (!::PathAppend(path, version)) {

-    return HRESULTFromLastError();

-  }

-  base_path = path;

-  if (!::PathAppend(path, omaha::kGoopdateDllName)) {

-    return HRESULTFromLastError();

-  }

-  if (!File::Exists(path)) {

-    return GOOGLEUPDATE_E_DLL_NOT_FOUND;

-  }

-

-  *dll_path = base_path;

-  return S_OK;

-}

-

-void DataDumperGoopdate::DumpGoogleUpdateIniFile(const DumpLog& dump_log) {

-  DumpHeader header(dump_log, _T("GoogleUpdate.ini File Contents"));

-  DumpFileContents(dump_log, _T("c:\\googleupdate.ini"), 0);

-}

-

-void DataDumperGoopdate::DumpHostsFile(const DumpLog& dump_log) {

-  DumpHeader header(dump_log, _T("Hosts File Contents"));

-  TCHAR system_path[MAX_PATH] = {0};

-  HRESULT hr = ::SHGetFolderPath(NULL,

-                                 CSIDL_SYSTEM,

-                                 NULL,

-                                 SHGFP_TYPE_CURRENT,

-                                 system_path);

-  if (FAILED(hr)) {

-    dump_log.WriteLine(_T("Can't get System folder: 0x%x"), hr);

-    return;

-  }

-

-  CPath full_path = system_path;

-  full_path.Append(_T("drivers\\etc\\hosts"));

-  DumpFileContents(dump_log, full_path, 0);

-}

-

-void DataDumperGoopdate::DumpUpdateDevKeys(const DumpLog& dump_log) {

-  DumpHeader header(dump_log, _T("UpdateDev Keys"));

-

-  DumpRegistryKeyData(dump_log, _T("HKLM\\Software\\Google\\UpdateDev"));

-}

-

-void DataDumperGoopdate::DumpLogFile(const DumpLog& dump_log) {

-  DumpHeader header(dump_log, _T("Debug Log File Contents"));

-

-  Logging logger;

-  CString log_file_path(logger.GetLogFilePath());

-  DumpFileContents(dump_log, log_file_path, 500);

-}

-

-CString EventLogTypeToString(WORD event_log_type) {

-  CString str = _T("Unknown");

-  switch (event_log_type) {

-    case EVENTLOG_ERROR_TYPE:

-      str = _T("ERROR");

-      break;

-    case EVENTLOG_WARNING_TYPE:

-      str = _T("WARNING");

-      break;

-    case EVENTLOG_INFORMATION_TYPE:

-      str = _T("INFORMATION");

-      break;

-    case EVENTLOG_AUDIT_SUCCESS:

-      str = _T("AUDIT_SUCCESS");

-      break;

-    case EVENTLOG_AUDIT_FAILURE:

-      str = _T("AUDIT_FAILURE");

-      break;

-    default:

-      str = _T("Unknown");

-      break;

-  }

-

-  return str;

-}

-

-void DataDumperGoopdate::DumpEventLog(const DumpLog& dump_log) {

-  DumpHeader header(dump_log, _T("Google Update Event Log Entries"));

-

-  HANDLE handle_event_log = ::OpenEventLog(NULL, _T("Application"));

-  if (handle_event_log == NULL) {

-    return;

-  }

-

-  const int kInitialBufferSize = 8192;

-  int buffer_size = kInitialBufferSize;

-  scoped_array<TCHAR> buffer(new TCHAR[buffer_size]);

-

-  while (1) {

-    EVENTLOGRECORD* record = reinterpret_cast<EVENTLOGRECORD*>(buffer.get());

-    DWORD num_bytes_read = 0;

-    DWORD bytes_needed = 0;

-    if (!::ReadEventLog(handle_event_log,

-                        EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ,

-                        0,

-                        record,

-                        buffer_size,

-                        &num_bytes_read,

-                        &bytes_needed)) {

-      const int err = ::GetLastError();

-      if (ERROR_INSUFFICIENT_BUFFER == err) {

-        buffer_size = bytes_needed;

-        buffer.reset(new TCHAR[buffer_size]);

-        continue;

-      } else {

-        if (ERROR_HANDLE_EOF != err) {

-          dump_log.WriteLine(_T("ReadEventLog failed: %d"), err);

-        }

-        break;

-      }

-    }

-

-    while (num_bytes_read > 0) {

-      const TCHAR* source_name = reinterpret_cast<const TCHAR*>(

-          reinterpret_cast<BYTE*>(record) + sizeof(*record));

-

-      if (_tcscmp(source_name, EventLogger::kSourceName) == 0) {

-        CString event_log_type = EventLogTypeToString(record->EventType);

-

-        const TCHAR* message_data_buffer = reinterpret_cast<const TCHAR*>(

-            reinterpret_cast<BYTE*>(record) + record->StringOffset);

-

-        CString message_data(message_data_buffer);

-

-        FILETIME filetime = {0};

-        TimeTToFileTime(record->TimeWritten, &filetime);

-        SYSTEMTIME systemtime = {0};

-        ::FileTimeToSystemTime(&filetime, &systemtime);

-

-        CString message_line;

-        message_line.Format(_T("[%s] (%d)|(%s) %s"),

-                            FormatRunTimeString(&systemtime),

-                            record->EventID,

-                            event_log_type,

-                            message_data);

-        dump_log.WriteLine(message_line);

-      }

-

-      num_bytes_read -= record->Length;

-      record = reinterpret_cast<EVENTLOGRECORD*>(

-          reinterpret_cast<BYTE*>(record) + record->Length);

-    }

-

-    record = reinterpret_cast<EVENTLOGRECORD*>(&buffer);

-  }

-

-  ::CloseEventLog(handle_event_log);

-}

-

-void DataDumperGoopdate::DumpGoogleUpdateProcessInfo(const DumpLog& dump_log) {

-  DumpHeader header(dump_log, _T("GoogleUpdate.exe Process Info"));

-

-  EnableDebugPrivilege();

-

-  scoped_handle handle_snap;

-  reset(handle_snap,

-        ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0));

-  if (!valid(handle_snap)) {

-    return;

-  }

-

-  PROCESSENTRY32 process_entry32 = {0};

-  process_entry32.dwSize = sizeof(PROCESSENTRY32);

-

-  if (!::Process32First(get(handle_snap), &process_entry32)) {

-    return;

-  }

-

-  bool first = true;

-

-  do {

-    CString exe_file_name = process_entry32.szExeFile;

-    exe_file_name.MakeLower();

-

-    if (exe_file_name.Find(_T("googleupdate.exe")) >= 0) {

-      if (first) {

-        first = false;

-      } else {

-        dump_log.WriteLine(_T("-------------------"));

-      }

-      dump_log.WriteLine(_T("Process ID: %d"), process_entry32.th32ProcessID);

-      scoped_handle process_handle;

-      reset(process_handle, ::OpenProcess(PROCESS_ALL_ACCESS,

-                                          FALSE,

-                                          process_entry32.th32ProcessID));

-      if (get(process_handle)) {

-        CString command_line;

-        if (SUCCEEDED(GetProcessCommandLine(process_entry32.th32ProcessID,

-                                            &command_line))) {

-          dump_log.WriteLine(_T("Command Line: %s"), command_line);

-        } else {

-          dump_log.WriteLine(_T("Command Line: Failed to retrieve"));

-        }

-

-        PROCESS_MEMORY_COUNTERS memory_counters = {0};

-        memory_counters.cb = sizeof(memory_counters);

-        if (GetProcessMemoryInfo(get(process_handle),

-                                 &memory_counters,

-                                 sizeof(memory_counters))) {

-          dump_log.WriteLine(_T("Page Fault Count:      %d"),

-                             memory_counters.PageFaultCount);

-          dump_log.WriteLine(_T("Peak Working Set Size: %d"),

-                             memory_counters.PeakWorkingSetSize);

-          dump_log.WriteLine(_T("Working Set Size:      %d"),

-                             memory_counters.WorkingSetSize);

-          dump_log.WriteLine(_T("Page File Usage:       %d"),

-                             memory_counters.PagefileUsage);

-          dump_log.WriteLine(_T("Peak Page File Usage:  %d"),

-                             memory_counters.PeakPagefileUsage);

-        } else {

-          dump_log.WriteLine(_T("Unable to get process memory info"));

-        }

-

-        THREADENTRY32 thread_entry = {0};

-        thread_entry.dwSize = sizeof(thread_entry);

-        int thread_count = 0;

-        if (Thread32First(get(handle_snap), &thread_entry)) {

-          do {

-            if (thread_entry.th32OwnerProcessID ==

-                process_entry32.th32ProcessID) {

-              ++thread_count;

-            }

-          } while (::Thread32Next(get(handle_snap), &thread_entry));

-        }

-

-        dump_log.WriteLine(_T("Thread Count:          %d"), thread_count);

-

-        FILETIME creation_time = {0};

-        FILETIME exit_time = {0};

-        FILETIME kernel_time = {0};

-        FILETIME user_time = {0};

-        if (::GetProcessTimes(get(process_handle),

-                              &creation_time,

-                              &exit_time,

-                              &kernel_time,

-                              &user_time)) {

-          SYSTEMTIME creation_system_time = {0};

-          FileTimeToSystemTime(&creation_time, &creation_system_time);

-          CString creation_str = FormatRunTimeString(&creation_system_time);

-          dump_log.WriteLine(_T("Process Start Time:    %s"), creation_str);

-

-          CTime time_creation(creation_time);

-          CTime time_now = CTime::GetCurrentTime();

-          CTimeSpan time_span = time_now - time_creation;

-          CString time_span_format =

-              time_span.Format(_T("%D days, %H hours, %M minutes, %S seconds"));

-          dump_log.WriteLine(_T("Process Uptime:        %s"), time_span_format);

-        } else {

-          dump_log.WriteLine(_T("Unable to get Process Times"));

-        }

-      }

-    }

-  } while (::Process32Next(get(handle_snap), &process_entry32));

-}

-

-void DataDumperGoopdate::DumpServiceInfo(const DumpLog& dump_log) {

-  DumpHeader header(dump_log, _T("Google Update Service Info"));

-

-  CString current_service_name = ConfigManager::GetCurrentServiceName();

-  bool is_service_installed =

-      ServiceInstall::IsServiceInstalled(current_service_name);

-

-  dump_log.WriteLine(_T("Service Name: %s"), current_service_name);

-  dump_log.WriteLine(_T("Is Installed: %s"),

-                     is_service_installed ? _T("YES") : _T("NO"));

-}

-

-void DataDumperGoopdate::DumpScheduledTaskInfo(const DumpLog& dump_log,

-                                               bool is_machine) {

-  DumpHeader header(dump_log, _T("Scheduled Task Info"));

-

-  CComPtr<ITaskScheduler> scheduler;

-  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,

-                                          NULL,

-                                          CLSCTX_INPROC_SERVER);

-  if (FAILED(hr)) {

-    dump_log.WriteLine(_T("ITaskScheduler.CoCreateInstance failed: 0x%x"),

-                       hr);

-    return;

-  }

-

-  CComPtr<ITask> task;

-  hr = scheduler->Activate(ConfigManager::GetCurrentTaskNameCore(is_machine),

-                           __uuidof(ITask),

-                           reinterpret_cast<IUnknown**>(&task));

-

-  if (FAILED(hr)) {

-    dump_log.WriteLine(_T("ITaskScheduler.Activate failed: 0x%x"), hr);

-    return;

-  }

-

-  scoped_ptr_cotask<TCHAR> app_name;

-  hr = task->GetApplicationName(address(app_name));

-  dump_log.WriteLine(_T("ApplicationName: %s"),

-                     SUCCEEDED(hr) ? app_name.get() : _T("Not Found"));

-

-  scoped_ptr_cotask<TCHAR> creator;

-  hr = task->GetCreator(address(creator));

-  dump_log.WriteLine(_T("Creator: %s"),

-                     SUCCEEDED(hr) ? creator.get() : _T("Not Found"));

-

-  scoped_ptr_cotask<TCHAR> parameters;

-  hr = task->GetParameters(address(parameters));

-  dump_log.WriteLine(_T("Parameters: %s"),

-                     SUCCEEDED(hr) ? parameters.get() : _T("Not Found"));

-

-  scoped_ptr_cotask<TCHAR> comment;

-  hr = task->GetComment(address(comment));

-  dump_log.WriteLine(_T("Comment: %s"),

-                     SUCCEEDED(hr) ? comment.get() : _T("Not Found"));

-

-  scoped_ptr_cotask<TCHAR> working_dir;

-  hr = task->GetWorkingDirectory(address(working_dir));

-  dump_log.WriteLine(_T("Working Directory: %s"),

-                     SUCCEEDED(hr) ? working_dir.get() : _T("Not Found"));

-

-  scoped_ptr_cotask<TCHAR> account_info;

-  hr = task->GetAccountInformation(address(account_info));

-  dump_log.WriteLine(_T("Account Info: %s"),

-                     SUCCEEDED(hr) ? account_info.get() : _T("Not Found"));

-

-  dump_log.WriteLine(_T("Triggers:"));

-  WORD trigger_count = 0;

-  hr = task->GetTriggerCount(&trigger_count);

-  if (SUCCEEDED(hr)) {

-    for (WORD i = 0; i < trigger_count; ++i) {

-      CComPtr<ITaskTrigger> trigger;

-      if (SUCCEEDED(task->GetTrigger(i, &trigger))) {

-        scoped_ptr_cotask<TCHAR> trigger_string;

-        if (SUCCEEDED(trigger->GetTriggerString(address(trigger_string)))) {

-          dump_log.WriteLine(_T("   %s"), trigger_string.get());

-        }

-      }

-    }

-  }

-

-  SYSTEMTIME next_run_time = {0};

-  hr = task->GetNextRunTime(&next_run_time);

-  if (SUCCEEDED(hr)) {

-    dump_log.WriteLine(_T("Next Run Time: %s"),

-                       FormatRunTimeString(&next_run_time));

-  } else {

-    dump_log.WriteLine(_T("Next Run Time: Not Found"));

-  }

-

-  SYSTEMTIME recent_run_time = {0};

-  hr = task->GetMostRecentRunTime(&recent_run_time);

-  if (SUCCEEDED(hr)) {

-    dump_log.WriteLine(_T("Most Recent Run Time: %s"),

-                       FormatRunTimeString(&recent_run_time));

-  } else {

-    dump_log.WriteLine(_T("Most Recent Run Time: Not Found"));

-  }

-

-  DWORD max_run_time = 0;

-  hr = task->GetMaxRunTime(&max_run_time);

-  if (SUCCEEDED(hr)) {

-    dump_log.WriteLine(_T("Max Run Time: %d ms"), max_run_time);

-  } else {

-    dump_log.WriteLine(_T("Max Run Time: [Not Available]"));

-  }

-}

-

-void DataDumperGoopdate::DumpRunKeys(const DumpLog& dump_log) {

-  DumpHeader header(dump_log, _T("Google Update Run Keys"));

-

-  CString key_path = AppendRegKeyPath(USER_KEY_NAME, REGSTR_PATH_RUN);

-  DumpRegValueStr(dump_log, key_path, kRunValueName);

-}

-

-void DataDumperGoopdate::DumpFileContents(const DumpLog& dump_log,

-                                          const CString& file_path,

-                                          int num_tail_lines) {

-  if (num_tail_lines > 0) {

-    dump_log.WriteLine(_T("Tailing last %d lines of file"), num_tail_lines);

-  }

-  dump_log.WriteLine(_T("-------------------------------------"));

-  if (File::Exists(file_path)) {

-    FileReader reader;

-    HRESULT hr = reader.Init(file_path, 2048);

-    if (FAILED(hr)) {

-      dump_log.WriteLine(_T("Unable to open %s: 0x%x."), file_path, hr);

-      return;

-    }

-

-    CString current_line;

-    std::list<CString> tail_lines;

-

-    while (SUCCEEDED(reader.ReadLineString(&current_line))) {

-      if (num_tail_lines == 0) {

-        // We're not doing a tail, so just print the entire file.

-        dump_log.WriteLine(current_line);

-      } else {

-        // Collect the lines in a queue until we're done.

-        tail_lines.push_back(current_line);

-        if (tail_lines.size() > static_cast<size_t>(num_tail_lines)) {

-          tail_lines.pop_front();

-        }

-      }

-    }

-

-    // Print out the tail lines collected from the file, if they exist.

-    if (num_tail_lines > 0) {

-      for (std::list<CString>::const_iterator it = tail_lines.begin();

-           it != tail_lines.end();

-           ++it) {

-        dump_log.WriteLine(*it);

-      }

-    }

-  } else {

-    dump_log.WriteLine(_T("File does not exist."));

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/tools/goopdump/data_dumper_goopdate.h"
+
+#include <atltime.h>
+#include <mstask.h>
+#include <psapi.h>
+#include <regstr.h>
+#include <tlhelp32.h>
+
+#include <list>
+
+#include "omaha/common/constants.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/file_reader.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_ptr_cotask.h"
+#include "omaha/common/service_utils.h"
+#include "omaha/common/time.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/event_logger.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/tools/goopdump/dump_log.h"
+#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"
+#include "omaha/tools/goopdump/process_commandline.h"
+
+namespace {
+
+CString FormatRunTimeString(SYSTEMTIME* system_time) {
+  SYSTEMTIME local_time = {0};
+  ::SystemTimeToTzSpecificLocalTime(NULL, system_time, &local_time);
+  CString str;
+  str.Format(_T("%02d/%02d/%04d %02d:%02d:%02d"),
+             local_time.wMonth,
+             local_time.wDay,
+             local_time.wYear,
+             local_time.wHour,
+             local_time.wMinute,
+             local_time.wSecond);
+  return str;
+}
+
+}  // namespace
+
+namespace omaha {
+
+DataDumperGoopdate::DataDumperGoopdate() {
+}
+
+DataDumperGoopdate::~DataDumperGoopdate() {
+}
+
+HRESULT DataDumperGoopdate::Process(const DumpLog& dump_log,
+                                    const GoopdumpCmdLineArgs& args) {
+  UNREFERENCED_PARAMETER(args);
+
+  DumpHeader header(dump_log, _T("Goopdate Data"));
+
+  dump_log.WriteLine(_T(""));
+  dump_log.WriteLine(_T("-- GENERAL / GLOBAL DATA --"));
+  DumpHostsFile(dump_log);
+  DumpGoogleUpdateIniFile(dump_log);
+  DumpUpdateDevKeys(dump_log);
+  DumpLogFile(dump_log);
+  DumpEventLog(dump_log);
+  DumpGoogleUpdateProcessInfo(dump_log);
+
+  if (args.is_machine) {
+    dump_log.WriteLine(_T(""));
+    dump_log.WriteLine(_T("-- PER-MACHINE DATA --"));
+    DumpDirContents(dump_log, true);
+    DumpServiceInfo(dump_log);
+  }
+
+  if (args.is_user) {
+    dump_log.WriteLine(_T(""));
+    dump_log.WriteLine(_T("-- PER-USER DATA --"));
+    DumpDirContents(dump_log, false);
+    DumpRunKeys(dump_log);
+  }
+
+  DumpScheduledTaskInfo(dump_log, args.is_machine);
+
+  return S_OK;
+}
+
+void DataDumperGoopdate::DumpDirContents(const DumpLog& dump_log,
+                                         bool is_machine) {
+  DumpHeader header(dump_log, _T("Directory Contents"));
+
+  CString registered_version;
+  if (FAILED(GetRegisteredVersion(is_machine, &registered_version))) {
+    dump_log.WriteLine(_T("Failed to get registered version."));
+    return;
+  }
+
+  CString dll_dir;
+  if (FAILED(GetDllDir(is_machine, &dll_dir))) {
+    dump_log.WriteLine(_T("Failed to get dlldir."));
+    return;
+  }
+
+  dump_log.WriteLine(_T("Version:\t%s"), registered_version);
+  dump_log.WriteLine(_T("Dll Dir:\t%s"), dll_dir);
+
+  // Enumerate all files in the DllPath and log them.
+  std::vector<CString> matching_paths;
+  HRESULT hr = File::GetWildcards(dll_dir, _T("*.*"), &matching_paths);
+  if (SUCCEEDED(hr)) {
+    dump_log.WriteLine(_T(""));
+    dump_log.WriteLine(_T("Files in DllDir:"));
+    for (size_t i = 0; i < matching_paths.size(); ++i) {
+      dump_log.WriteLine(matching_paths[i]);
+    }
+    dump_log.WriteLine(_T(""));
+  } else {
+    dump_log.WriteLine(_T("Failure getting files in DllDir (0x%x)."), hr);
+  }
+}
+
+HRESULT DataDumperGoopdate::GetRegisteredVersion(bool is_machine,
+                                                 CString* version) {
+  HKEY key = NULL;
+  LONG res = ::RegOpenKeyEx(is_machine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
+                            GOOPDATE_REG_RELATIVE_CLIENTS GOOPDATE_APP_ID,
+                            0,
+                            KEY_READ,
+                            &key);
+  if (ERROR_SUCCESS != res) {
+    return HRESULT_FROM_WIN32(res);
+  }
+
+  DWORD type = 0;
+  DWORD version_length = 50;
+  res = ::SHQueryValueEx(key,
+                         omaha::kRegValueProductVersion,
+                         NULL,
+                         &type,
+                         CStrBuf(*version, version_length),
+                         &version_length);
+  if (ERROR_SUCCESS != res) {
+    return HRESULT_FROM_WIN32(res);
+  }
+
+  if (REG_SZ != type) {
+    return E_UNEXPECTED;
+  }
+
+  return S_OK;
+}
+
+HRESULT DataDumperGoopdate::GetDllDir(bool is_machine, CString* dll_path) {
+  TCHAR path[MAX_PATH] = {0};
+
+  CString base_path = goopdate_utils::BuildGoogleUpdateExeDir(is_machine);
+
+  // Try the side-by-side DLL first.
+  _tcscpy_s(path, arraysize(path), base_path);
+  if (!::PathAppend(path, omaha::kGoopdateDllName)) {
+    return HRESULTFromLastError();
+  }
+  if (File::Exists(path)) {
+    *dll_path = base_path;
+    return S_OK;
+  }
+
+  // Try the version subdirectory.
+  _tcscpy_s(path, arraysize(path), base_path);
+  CString version;
+  HRESULT hr = GetRegisteredVersion(is_machine, &version);
+  if (FAILED(hr)) {
+    return hr;
+  }
+  if (!::PathAppend(path, version)) {
+    return HRESULTFromLastError();
+  }
+  base_path = path;
+  if (!::PathAppend(path, omaha::kGoopdateDllName)) {
+    return HRESULTFromLastError();
+  }
+  if (!File::Exists(path)) {
+    return GOOGLEUPDATE_E_DLL_NOT_FOUND;
+  }
+
+  *dll_path = base_path;
+  return S_OK;
+}
+
+void DataDumperGoopdate::DumpGoogleUpdateIniFile(const DumpLog& dump_log) {
+  DumpHeader header(dump_log, _T("GoogleUpdate.ini File Contents"));
+  DumpFileContents(dump_log, _T("c:\\googleupdate.ini"), 0);
+}
+
+void DataDumperGoopdate::DumpHostsFile(const DumpLog& dump_log) {
+  DumpHeader header(dump_log, _T("Hosts File Contents"));
+  TCHAR system_path[MAX_PATH] = {0};
+  HRESULT hr = ::SHGetFolderPath(NULL,
+                                 CSIDL_SYSTEM,
+                                 NULL,
+                                 SHGFP_TYPE_CURRENT,
+                                 system_path);
+  if (FAILED(hr)) {
+    dump_log.WriteLine(_T("Can't get System folder: 0x%x"), hr);
+    return;
+  }
+
+  CPath full_path = system_path;
+  full_path.Append(_T("drivers\\etc\\hosts"));
+  DumpFileContents(dump_log, full_path, 0);
+}
+
+void DataDumperGoopdate::DumpUpdateDevKeys(const DumpLog& dump_log) {
+  DumpHeader header(dump_log, _T("UpdateDev Keys"));
+
+  DumpRegistryKeyData(dump_log, _T("HKLM\\Software\\Google\\UpdateDev"));
+}
+
+void DataDumperGoopdate::DumpLogFile(const DumpLog& dump_log) {
+  DumpHeader header(dump_log, _T("Debug Log File Contents"));
+
+  Logging logger;
+  CString log_file_path(logger.GetLogFilePath());
+  DumpFileContents(dump_log, log_file_path, 500);
+}
+
+CString EventLogTypeToString(WORD event_log_type) {
+  CString str = _T("Unknown");
+  switch (event_log_type) {
+    case EVENTLOG_ERROR_TYPE:
+      str = _T("ERROR");
+      break;
+    case EVENTLOG_WARNING_TYPE:
+      str = _T("WARNING");
+      break;
+    case EVENTLOG_INFORMATION_TYPE:
+      str = _T("INFORMATION");
+      break;
+    case EVENTLOG_AUDIT_SUCCESS:
+      str = _T("AUDIT_SUCCESS");
+      break;
+    case EVENTLOG_AUDIT_FAILURE:
+      str = _T("AUDIT_FAILURE");
+      break;
+    default:
+      str = _T("Unknown");
+      break;
+  }
+
+  return str;
+}
+
+void DataDumperGoopdate::DumpEventLog(const DumpLog& dump_log) {
+  DumpHeader header(dump_log, _T("Google Update Event Log Entries"));
+
+  HANDLE handle_event_log = ::OpenEventLog(NULL, _T("Application"));
+  if (handle_event_log == NULL) {
+    return;
+  }
+
+  const int kInitialBufferSize = 8192;
+  int buffer_size = kInitialBufferSize;
+  scoped_array<TCHAR> buffer(new TCHAR[buffer_size]);
+
+  while (1) {
+    EVENTLOGRECORD* record = reinterpret_cast<EVENTLOGRECORD*>(buffer.get());
+    DWORD num_bytes_read = 0;
+    DWORD bytes_needed = 0;
+    if (!::ReadEventLog(handle_event_log,
+                        EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ,
+                        0,
+                        record,
+                        buffer_size,
+                        &num_bytes_read,
+                        &bytes_needed)) {
+      const int err = ::GetLastError();
+      if (ERROR_INSUFFICIENT_BUFFER == err) {
+        buffer_size = bytes_needed;
+        buffer.reset(new TCHAR[buffer_size]);
+        continue;
+      } else {
+        if (ERROR_HANDLE_EOF != err) {
+          dump_log.WriteLine(_T("ReadEventLog failed: %d"), err);
+        }
+        break;
+      }
+    }
+
+    while (num_bytes_read > 0) {
+      const TCHAR* source_name = reinterpret_cast<const TCHAR*>(
+          reinterpret_cast<BYTE*>(record) + sizeof(*record));
+
+      if (_tcscmp(source_name, EventLogger::kSourceName) == 0) {
+        CString event_log_type = EventLogTypeToString(record->EventType);
+
+        const TCHAR* message_data_buffer = reinterpret_cast<const TCHAR*>(
+            reinterpret_cast<BYTE*>(record) + record->StringOffset);
+
+        CString message_data(message_data_buffer);
+
+        FILETIME filetime = {0};
+        TimeTToFileTime(record->TimeWritten, &filetime);
+        SYSTEMTIME systemtime = {0};
+        ::FileTimeToSystemTime(&filetime, &systemtime);
+
+        CString message_line;
+        message_line.Format(_T("[%s] (%d)|(%s) %s"),
+                            FormatRunTimeString(&systemtime),
+                            record->EventID,
+                            event_log_type,
+                            message_data);
+        dump_log.WriteLine(message_line);
+      }
+
+      num_bytes_read -= record->Length;
+      record = reinterpret_cast<EVENTLOGRECORD*>(
+          reinterpret_cast<BYTE*>(record) + record->Length);
+    }
+
+    record = reinterpret_cast<EVENTLOGRECORD*>(&buffer);
+  }
+
+  ::CloseEventLog(handle_event_log);
+}
+
+void DataDumperGoopdate::DumpGoogleUpdateProcessInfo(const DumpLog& dump_log) {
+  DumpHeader header(dump_log, _T("GoogleUpdate.exe Process Info"));
+
+  EnableDebugPrivilege();
+
+  scoped_handle handle_snap;
+  reset(handle_snap,
+        ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD, 0));
+  if (!valid(handle_snap)) {
+    return;
+  }
+
+  PROCESSENTRY32 process_entry32 = {0};
+  process_entry32.dwSize = sizeof(PROCESSENTRY32);
+
+  if (!::Process32First(get(handle_snap), &process_entry32)) {
+    return;
+  }
+
+  bool first = true;
+
+  do {
+    CString exe_file_name = process_entry32.szExeFile;
+    exe_file_name.MakeLower();
+
+    if (exe_file_name.Find(_T("googleupdate.exe")) >= 0) {
+      if (first) {
+        first = false;
+      } else {
+        dump_log.WriteLine(_T("-------------------"));
+      }
+      dump_log.WriteLine(_T("Process ID: %d"), process_entry32.th32ProcessID);
+      scoped_handle process_handle;
+      reset(process_handle, ::OpenProcess(PROCESS_ALL_ACCESS,
+                                          FALSE,
+                                          process_entry32.th32ProcessID));
+      if (get(process_handle)) {
+        CString command_line;
+        if (SUCCEEDED(GetProcessCommandLine(process_entry32.th32ProcessID,
+                                            &command_line))) {
+          dump_log.WriteLine(_T("Command Line: %s"), command_line);
+        } else {
+          dump_log.WriteLine(_T("Command Line: Failed to retrieve"));
+        }
+
+        PROCESS_MEMORY_COUNTERS memory_counters = {0};
+        memory_counters.cb = sizeof(memory_counters);
+        if (GetProcessMemoryInfo(get(process_handle),
+                                 &memory_counters,
+                                 sizeof(memory_counters))) {
+          dump_log.WriteLine(_T("Page Fault Count:      %d"),
+                             memory_counters.PageFaultCount);
+          dump_log.WriteLine(_T("Peak Working Set Size: %d"),
+                             memory_counters.PeakWorkingSetSize);
+          dump_log.WriteLine(_T("Working Set Size:      %d"),
+                             memory_counters.WorkingSetSize);
+          dump_log.WriteLine(_T("Page File Usage:       %d"),
+                             memory_counters.PagefileUsage);
+          dump_log.WriteLine(_T("Peak Page File Usage:  %d"),
+                             memory_counters.PeakPagefileUsage);
+        } else {
+          dump_log.WriteLine(_T("Unable to get process memory info"));
+        }
+
+        THREADENTRY32 thread_entry = {0};
+        thread_entry.dwSize = sizeof(thread_entry);
+        int thread_count = 0;
+        if (Thread32First(get(handle_snap), &thread_entry)) {
+          do {
+            if (thread_entry.th32OwnerProcessID ==
+                process_entry32.th32ProcessID) {
+              ++thread_count;
+            }
+          } while (::Thread32Next(get(handle_snap), &thread_entry));
+        }
+
+        dump_log.WriteLine(_T("Thread Count:          %d"), thread_count);
+
+        FILETIME creation_time = {0};
+        FILETIME exit_time = {0};
+        FILETIME kernel_time = {0};
+        FILETIME user_time = {0};
+        if (::GetProcessTimes(get(process_handle),
+                              &creation_time,
+                              &exit_time,
+                              &kernel_time,
+                              &user_time)) {
+          SYSTEMTIME creation_system_time = {0};
+          FileTimeToSystemTime(&creation_time, &creation_system_time);
+          CString creation_str = FormatRunTimeString(&creation_system_time);
+          dump_log.WriteLine(_T("Process Start Time:    %s"), creation_str);
+
+          CTime time_creation(creation_time);
+          CTime time_now = CTime::GetCurrentTime();
+          CTimeSpan time_span = time_now - time_creation;
+          CString time_span_format =
+              time_span.Format(_T("%D days, %H hours, %M minutes, %S seconds"));
+          dump_log.WriteLine(_T("Process Uptime:        %s"), time_span_format);
+        } else {
+          dump_log.WriteLine(_T("Unable to get Process Times"));
+        }
+      }
+    }
+  } while (::Process32Next(get(handle_snap), &process_entry32));
+}
+
+void DataDumperGoopdate::DumpServiceInfo(const DumpLog& dump_log) {
+  DumpHeader header(dump_log, _T("Google Update Service Info"));
+
+  CString current_service_name = ConfigManager::GetCurrentServiceName();
+  bool is_service_installed =
+      ServiceInstall::IsServiceInstalled(current_service_name);
+
+  dump_log.WriteLine(_T("Service Name: %s"), current_service_name);
+  dump_log.WriteLine(_T("Is Installed: %s"),
+                     is_service_installed ? _T("YES") : _T("NO"));
+}
+
+void DataDumperGoopdate::DumpScheduledTaskInfo(const DumpLog& dump_log,
+                                               bool is_machine) {
+  DumpHeader header(dump_log, _T("Scheduled Task Info"));
+
+  CComPtr<ITaskScheduler> scheduler;
+  HRESULT hr = scheduler.CoCreateInstance(CLSID_CTaskScheduler,
+                                          NULL,
+                                          CLSCTX_INPROC_SERVER);
+  if (FAILED(hr)) {
+    dump_log.WriteLine(_T("ITaskScheduler.CoCreateInstance failed: 0x%x"),
+                       hr);
+    return;
+  }
+
+  CComPtr<ITask> task;
+  hr = scheduler->Activate(ConfigManager::GetCurrentTaskNameCore(is_machine),
+                           __uuidof(ITask),
+                           reinterpret_cast<IUnknown**>(&task));
+
+  if (FAILED(hr)) {
+    dump_log.WriteLine(_T("ITaskScheduler.Activate failed: 0x%x"), hr);
+    return;
+  }
+
+  scoped_ptr_cotask<TCHAR> app_name;
+  hr = task->GetApplicationName(address(app_name));
+  dump_log.WriteLine(_T("ApplicationName: %s"),
+                     SUCCEEDED(hr) ? app_name.get() : _T("Not Found"));
+
+  scoped_ptr_cotask<TCHAR> creator;
+  hr = task->GetCreator(address(creator));
+  dump_log.WriteLine(_T("Creator: %s"),
+                     SUCCEEDED(hr) ? creator.get() : _T("Not Found"));
+
+  scoped_ptr_cotask<TCHAR> parameters;
+  hr = task->GetParameters(address(parameters));
+  dump_log.WriteLine(_T("Parameters: %s"),
+                     SUCCEEDED(hr) ? parameters.get() : _T("Not Found"));
+
+  scoped_ptr_cotask<TCHAR> comment;
+  hr = task->GetComment(address(comment));
+  dump_log.WriteLine(_T("Comment: %s"),
+                     SUCCEEDED(hr) ? comment.get() : _T("Not Found"));
+
+  scoped_ptr_cotask<TCHAR> working_dir;
+  hr = task->GetWorkingDirectory(address(working_dir));
+  dump_log.WriteLine(_T("Working Directory: %s"),
+                     SUCCEEDED(hr) ? working_dir.get() : _T("Not Found"));
+
+  scoped_ptr_cotask<TCHAR> account_info;
+  hr = task->GetAccountInformation(address(account_info));
+  dump_log.WriteLine(_T("Account Info: %s"),
+                     SUCCEEDED(hr) ? account_info.get() : _T("Not Found"));
+
+  dump_log.WriteLine(_T("Triggers:"));
+  WORD trigger_count = 0;
+  hr = task->GetTriggerCount(&trigger_count);
+  if (SUCCEEDED(hr)) {
+    for (WORD i = 0; i < trigger_count; ++i) {
+      CComPtr<ITaskTrigger> trigger;
+      if (SUCCEEDED(task->GetTrigger(i, &trigger))) {
+        scoped_ptr_cotask<TCHAR> trigger_string;
+        if (SUCCEEDED(trigger->GetTriggerString(address(trigger_string)))) {
+          dump_log.WriteLine(_T("   %s"), trigger_string.get());
+        }
+      }
+    }
+  }
+
+  SYSTEMTIME next_run_time = {0};
+  hr = task->GetNextRunTime(&next_run_time);
+  if (SUCCEEDED(hr)) {
+    dump_log.WriteLine(_T("Next Run Time: %s"),
+                       FormatRunTimeString(&next_run_time));
+  } else {
+    dump_log.WriteLine(_T("Next Run Time: Not Found"));
+  }
+
+  SYSTEMTIME recent_run_time = {0};
+  hr = task->GetMostRecentRunTime(&recent_run_time);
+  if (SUCCEEDED(hr)) {
+    dump_log.WriteLine(_T("Most Recent Run Time: %s"),
+                       FormatRunTimeString(&recent_run_time));
+  } else {
+    dump_log.WriteLine(_T("Most Recent Run Time: Not Found"));
+  }
+
+  DWORD max_run_time = 0;
+  hr = task->GetMaxRunTime(&max_run_time);
+  if (SUCCEEDED(hr)) {
+    dump_log.WriteLine(_T("Max Run Time: %d ms"), max_run_time);
+  } else {
+    dump_log.WriteLine(_T("Max Run Time: [Not Available]"));
+  }
+}
+
+void DataDumperGoopdate::DumpRunKeys(const DumpLog& dump_log) {
+  DumpHeader header(dump_log, _T("Google Update Run Keys"));
+
+  CString key_path = AppendRegKeyPath(USER_KEY_NAME, REGSTR_PATH_RUN);
+  DumpRegValueStr(dump_log, key_path, kRunValueName);
+}
+
+void DataDumperGoopdate::DumpFileContents(const DumpLog& dump_log,
+                                          const CString& file_path,
+                                          int num_tail_lines) {
+  if (num_tail_lines > 0) {
+    dump_log.WriteLine(_T("Tailing last %d lines of file"), num_tail_lines);
+  }
+  dump_log.WriteLine(_T("-------------------------------------"));
+  if (File::Exists(file_path)) {
+    FileReader reader;
+    HRESULT hr = reader.Init(file_path, 2048);
+    if (FAILED(hr)) {
+      dump_log.WriteLine(_T("Unable to open %s: 0x%x."), file_path, hr);
+      return;
+    }
+
+    CString current_line;
+    std::list<CString> tail_lines;
+
+    while (SUCCEEDED(reader.ReadLineString(&current_line))) {
+      if (num_tail_lines == 0) {
+        // We're not doing a tail, so just print the entire file.
+        dump_log.WriteLine(current_line);
+      } else {
+        // Collect the lines in a queue until we're done.
+        tail_lines.push_back(current_line);
+        if (tail_lines.size() > static_cast<size_t>(num_tail_lines)) {
+          tail_lines.pop_front();
+        }
+      }
+    }
+
+    // Print out the tail lines collected from the file, if they exist.
+    if (num_tail_lines > 0) {
+      for (std::list<CString>::const_iterator it = tail_lines.begin();
+           it != tail_lines.end();
+           ++it) {
+        dump_log.WriteLine(*it);
+      }
+    }
+  } else {
+    dump_log.WriteLine(_T("File does not exist."));
+  }
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/data_dumper_goopdate.h b/tools/goopdump/data_dumper_goopdate.h
index ca58480..55f5ad5 100644
--- a/tools/goopdump/data_dumper_goopdate.h
+++ b/tools/goopdump/data_dumper_goopdate.h
@@ -1,61 +1,61 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_GOOPDATE_H_

-#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_GOOPDATE_H_

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-#include "omaha/tools/goopdump/data_dumper.h"

-

-namespace omaha {

-

-class DataDumperGoopdate : public DataDumper {

- public:

-  DataDumperGoopdate();

-  virtual ~DataDumperGoopdate();

-

-  virtual HRESULT Process(const DumpLog& dump_log,

-                          const GoopdumpCmdLineArgs& args);

-

- private:

-  void DumpGoogleUpdateIniFile(const DumpLog& dump_log);

-  void DumpHostsFile(const DumpLog& dump_log);

-  void DumpUpdateDevKeys(const DumpLog& dump_log);

-  void DumpLogFile(const DumpLog& dump_log);

-  void DumpEventLog(const DumpLog& dump_log);

-  void DumpGoogleUpdateProcessInfo(const DumpLog& dump_log);

-  void DumpDirContents(const DumpLog& dump_log, bool is_machine);

-  void DumpServiceInfo(const DumpLog& dump_log);

-  void DumpRunKeys(const DumpLog& dump_log);

-  void DumpScheduledTaskInfo(const DumpLog& dump_log, bool is_machine);

-

-  HRESULT GetRegisteredVersion(bool is_machine, CString* version);

-  HRESULT GetDllDir(bool is_machine, CString* dll_path);

-

-  void DumpFileContents(const DumpLog& dump_log,

-                        const CString& file_path,

-                        int num_tail_lines);

-

-

-  DISALLOW_EVIL_CONSTRUCTORS(DataDumperGoopdate);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_GOOPDATE_H_

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_GOOPDATE_H_
+#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_GOOPDATE_H_
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+#include "omaha/tools/goopdump/data_dumper.h"
+
+namespace omaha {
+
+class DataDumperGoopdate : public DataDumper {
+ public:
+  DataDumperGoopdate();
+  virtual ~DataDumperGoopdate();
+
+  virtual HRESULT Process(const DumpLog& dump_log,
+                          const GoopdumpCmdLineArgs& args);
+
+ private:
+  void DumpGoogleUpdateIniFile(const DumpLog& dump_log);
+  void DumpHostsFile(const DumpLog& dump_log);
+  void DumpUpdateDevKeys(const DumpLog& dump_log);
+  void DumpLogFile(const DumpLog& dump_log);
+  void DumpEventLog(const DumpLog& dump_log);
+  void DumpGoogleUpdateProcessInfo(const DumpLog& dump_log);
+  void DumpDirContents(const DumpLog& dump_log, bool is_machine);
+  void DumpServiceInfo(const DumpLog& dump_log);
+  void DumpRunKeys(const DumpLog& dump_log);
+  void DumpScheduledTaskInfo(const DumpLog& dump_log, bool is_machine);
+
+  HRESULT GetRegisteredVersion(bool is_machine, CString* version);
+  HRESULT GetDllDir(bool is_machine, CString* dll_path);
+
+  void DumpFileContents(const DumpLog& dump_log,
+                        const CString& file_path,
+                        int num_tail_lines);
+
+
+  DISALLOW_EVIL_CONSTRUCTORS(DataDumperGoopdate);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_GOOPDATE_H_
+
diff --git a/tools/goopdump/data_dumper_network.cc b/tools/goopdump/data_dumper_network.cc
index a11b5a9..6b342ad 100644
--- a/tools/goopdump/data_dumper_network.cc
+++ b/tools/goopdump/data_dumper_network.cc
@@ -1,62 +1,62 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/data_dumper_network.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/net/network_config.h"

-#include "omaha/tools/goopdump/data_dumper.h"

-#include "omaha/tools/goopdump/dump_log.h"

-#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"

-

-namespace omaha {

-

-DataDumperNetwork::DataDumperNetwork() {

-}

-

-DataDumperNetwork::~DataDumperNetwork() {

-}

-

-void DataDumperNetwork::DumpNetworkConfig(const DumpLog& dump_log) {

-  NetworkConfig& network_config(NetworkConfig::Instance());

-  HRESULT hr = network_config.Detect();

-  if (FAILED(hr)) {

-    dump_log.WriteLine(_T("Can't detect the network configuration."));

-  }

-  std::vector<Config> configs(network_config.GetConfigurations());

-  dump_log.WriteLine(_T("Detected configurations:\r\n"));

-  dump_log.WriteLine(NetworkConfig::ToString(configs));

-}

-

-HRESULT DataDumperNetwork::Process(const DumpLog& dump_log,

-                                   const GoopdumpCmdLineArgs& args) {

-  UNREFERENCED_PARAMETER(args);

-  DumpHeader header(dump_log, _T("Network"));

-

-  const bool is_machine = vista_util::IsUserAdmin();

-  HRESULT hr = omaha::goopdate_utils::ConfigureNetwork(is_machine, false);

-  if (FAILED(hr)) {

-    dump_log.WriteLine(_T("Can't configure the network."));

-  }

-

-  DumpNetworkConfig(dump_log);

-  return S_OK;

-}

-

-}  // namespace omaha

-

-// Register the WinHttp client with the class factory for http clients.

-#pragma comment(linker, "/INCLUDE:_kRegisterWinHttp")

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/data_dumper_network.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/net/network_config.h"
+#include "omaha/tools/goopdump/data_dumper.h"
+#include "omaha/tools/goopdump/dump_log.h"
+#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"
+
+namespace omaha {
+
+DataDumperNetwork::DataDumperNetwork() {
+}
+
+DataDumperNetwork::~DataDumperNetwork() {
+}
+
+void DataDumperNetwork::DumpNetworkConfig(const DumpLog& dump_log) {
+  NetworkConfig& network_config(NetworkConfig::Instance());
+  HRESULT hr = network_config.Detect();
+  if (FAILED(hr)) {
+    dump_log.WriteLine(_T("Can't detect the network configuration."));
+  }
+  std::vector<Config> configs(network_config.GetConfigurations());
+  dump_log.WriteLine(_T("Detected configurations:\r\n"));
+  dump_log.WriteLine(NetworkConfig::ToString(configs));
+}
+
+HRESULT DataDumperNetwork::Process(const DumpLog& dump_log,
+                                   const GoopdumpCmdLineArgs& args) {
+  UNREFERENCED_PARAMETER(args);
+  DumpHeader header(dump_log, _T("Network"));
+
+  const bool is_machine = vista_util::IsUserAdmin();
+  HRESULT hr = omaha::goopdate_utils::ConfigureNetwork(is_machine, false);
+  if (FAILED(hr)) {
+    dump_log.WriteLine(_T("Can't configure the network."));
+  }
+
+  DumpNetworkConfig(dump_log);
+  return S_OK;
+}
+
+}  // namespace omaha
+
+// Register the WinHttp client with the class factory for http clients.
+#pragma comment(linker, "/INCLUDE:_kRegisterWinHttp")
+
diff --git a/tools/goopdump/data_dumper_network.h b/tools/goopdump/data_dumper_network.h
index 9ffe13b..8477598 100644
--- a/tools/goopdump/data_dumper_network.h
+++ b/tools/goopdump/data_dumper_network.h
@@ -1,44 +1,44 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_NETWORK_H__

-#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_NETWORK_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-#include "omaha/tools/goopdump/data_dumper.h"

-

-namespace omaha {

-

-class DataDumperNetwork : public DataDumper {

- public:

-  DataDumperNetwork();

-  virtual ~DataDumperNetwork();

-

-  virtual HRESULT Process(const DumpLog& dump_log,

-                          const GoopdumpCmdLineArgs& args);

-

- private:

-  void DumpNetworkConfig(const DumpLog& dump_log);

-

-  DISALLOW_EVIL_CONSTRUCTORS(DataDumperNetwork);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_NETWORK_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_NETWORK_H__
+#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_NETWORK_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+#include "omaha/tools/goopdump/data_dumper.h"
+
+namespace omaha {
+
+class DataDumperNetwork : public DataDumper {
+ public:
+  DataDumperNetwork();
+  virtual ~DataDumperNetwork();
+
+  virtual HRESULT Process(const DumpLog& dump_log,
+                          const GoopdumpCmdLineArgs& args);
+
+ private:
+  void DumpNetworkConfig(const DumpLog& dump_log);
+
+  DISALLOW_EVIL_CONSTRUCTORS(DataDumperNetwork);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_NETWORK_H__
+
diff --git a/tools/goopdump/data_dumper_oneclick.cc b/tools/goopdump/data_dumper_oneclick.cc
index e6575f4..0af6a5c 100644
--- a/tools/goopdump/data_dumper_oneclick.cc
+++ b/tools/goopdump/data_dumper_oneclick.cc
@@ -1,87 +1,87 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/data_dumper_oneclick.h"

-

-#include "omaha/common/reg_key.h"

-#include "omaha/tools/goopdump/dump_log.h"

-#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"

-

-namespace omaha {

-

-DataDumperOneClick::DataDumperOneClick() {

-}

-

-DataDumperOneClick::~DataDumperOneClick() {

-}

-

-void DataDumperOneClick::DumpOneClickDataForVersion(const DumpLog& dump_log,

-                                                    int plugin_version) {

-

-  dump_log.WriteLine(_T("Trying Plugin Version: %d"), plugin_version);

-

-  CString oneclick_name;

-  oneclick_name.Format(_T("Google.OneClickCtrl.%d"), plugin_version);

-

-  CString reg_str;

-  reg_str.Format(_T("HKCR\\%s"), oneclick_name);

-  DumpRegValueStr(dump_log, reg_str, NULL);

-

-  CString clsid;

-  reg_str.Append(_T("\\CLSID"));

-  DumpRegValueStrRet(dump_log, reg_str, NULL, &clsid);

-

-  reg_str.Format(_T("HKCR\\MIME\\DataBase\\Content Type\\application/%s"),

-                 oneclick_name);

-  DumpRegValueStr(dump_log, reg_str, _T("CLSID"));

-

-  CString key;

-  key.Format(_T("HKCR\\CLSID\\%s"), clsid);

-

-  if (!clsid.IsEmpty()) {

-    DumpRegistryKeyData(dump_log, key);

-  }

-

-  CString typelib;

-  CString key2 = key;

-  key2.Append(_T("\\TypeLib"));

-  if (SUCCEEDED(RegKey::GetValue(key2, NULL, &typelib))) {

-    if (!typelib.IsEmpty()) {

-      key.Format(_T("HKCR\\Typelib\\%s\\1.0\\0\\win32"), typelib);

-      DumpRegistryKeyData(dump_log, key);

-    }

-  }

-

-  dump_log.WriteLine(_T(""));

-}

-

-HRESULT DataDumperOneClick::Process(const DumpLog& dump_log,

-                                    const GoopdumpCmdLineArgs& args) {

-  UNREFERENCED_PARAMETER(args);

-

-  DumpHeader header(dump_log, _T("OneClick Data"));

-

-  CString activex_version_str(ACTIVEX_VERSION_ANSI);

-  int activex_version = _ttoi(activex_version_str);

-

-  for (int i = 1; i <= activex_version; ++i) {

-    DumpOneClickDataForVersion(dump_log, i);

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/data_dumper_oneclick.h"
+
+#include "omaha/common/reg_key.h"
+#include "omaha/tools/goopdump/dump_log.h"
+#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"
+
+namespace omaha {
+
+DataDumperOneClick::DataDumperOneClick() {
+}
+
+DataDumperOneClick::~DataDumperOneClick() {
+}
+
+void DataDumperOneClick::DumpOneClickDataForVersion(const DumpLog& dump_log,
+                                                    int plugin_version) {
+
+  dump_log.WriteLine(_T("Trying Plugin Version: %d"), plugin_version);
+
+  CString oneclick_name;
+  oneclick_name.Format(_T("Google.OneClickCtrl.%d"), plugin_version);
+
+  CString reg_str;
+  reg_str.Format(_T("HKCR\\%s"), oneclick_name);
+  DumpRegValueStr(dump_log, reg_str, NULL);
+
+  CString clsid;
+  reg_str.Append(_T("\\CLSID"));
+  DumpRegValueStrRet(dump_log, reg_str, NULL, &clsid);
+
+  reg_str.Format(_T("HKCR\\MIME\\DataBase\\Content Type\\application/%s"),
+                 oneclick_name);
+  DumpRegValueStr(dump_log, reg_str, _T("CLSID"));
+
+  CString key;
+  key.Format(_T("HKCR\\CLSID\\%s"), clsid);
+
+  if (!clsid.IsEmpty()) {
+    DumpRegistryKeyData(dump_log, key);
+  }
+
+  CString typelib;
+  CString key2 = key;
+  key2.Append(_T("\\TypeLib"));
+  if (SUCCEEDED(RegKey::GetValue(key2, NULL, &typelib))) {
+    if (!typelib.IsEmpty()) {
+      key.Format(_T("HKCR\\Typelib\\%s\\1.0\\0\\win32"), typelib);
+      DumpRegistryKeyData(dump_log, key);
+    }
+  }
+
+  dump_log.WriteLine(_T(""));
+}
+
+HRESULT DataDumperOneClick::Process(const DumpLog& dump_log,
+                                    const GoopdumpCmdLineArgs& args) {
+  UNREFERENCED_PARAMETER(args);
+
+  DumpHeader header(dump_log, _T("OneClick Data"));
+
+  CString activex_version_str(ACTIVEX_VERSION_ANSI);
+  int activex_version = _ttoi(activex_version_str);
+
+  for (int i = 1; i <= activex_version; ++i) {
+    DumpOneClickDataForVersion(dump_log, i);
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/data_dumper_oneclick.h b/tools/goopdump/data_dumper_oneclick.h
index af3087d..66aceb0 100644
--- a/tools/goopdump/data_dumper_oneclick.h
+++ b/tools/goopdump/data_dumper_oneclick.h
@@ -1,45 +1,45 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_ONECLICK_H__

-#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_ONECLICK_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-#include "omaha/tools/goopdump/data_dumper.h"

-

-namespace omaha {

-

-class DataDumperOneClick : public DataDumper {

- public:

-  DataDumperOneClick();

-  virtual ~DataDumperOneClick();

-

-  virtual HRESULT Process(const DumpLog& dump_log,

-                          const GoopdumpCmdLineArgs& args);

-

- private:

-  void DumpOneClickDataForVersion(const DumpLog& dump_log, int plugin_version);

-

-  DISALLOW_EVIL_CONSTRUCTORS(DataDumperOneClick);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_ONECLICK_H__

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_ONECLICK_H__
+#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_ONECLICK_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+#include "omaha/tools/goopdump/data_dumper.h"
+
+namespace omaha {
+
+class DataDumperOneClick : public DataDumper {
+ public:
+  DataDumperOneClick();
+  virtual ~DataDumperOneClick();
+
+  virtual HRESULT Process(const DumpLog& dump_log,
+                          const GoopdumpCmdLineArgs& args);
+
+ private:
+  void DumpOneClickDataForVersion(const DumpLog& dump_log, int plugin_version);
+
+  DISALLOW_EVIL_CONSTRUCTORS(DataDumperOneClick);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_ONECLICK_H__
+
diff --git a/tools/goopdump/data_dumper_osdata.cc b/tools/goopdump/data_dumper_osdata.cc
index b8b47a4..029ced4 100644
--- a/tools/goopdump/data_dumper_osdata.cc
+++ b/tools/goopdump/data_dumper_osdata.cc
@@ -1,155 +1,155 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/data_dumper_osdata.h"

-

-#include <atltime.h>

-#include <pdh.h>

-#include <psapi.h>

-#include <security.h>

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/time.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/tools/goopdump/dump_log.h"

-#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"

-

-namespace omaha {

-

-DataDumperOSData::DataDumperOSData() {

-}

-

-DataDumperOSData::~DataDumperOSData() {

-}

-

-HRESULT DataDumperOSData::Process(const DumpLog& dump_log,

-                                    const GoopdumpCmdLineArgs& args) {

-  UNREFERENCED_PARAMETER(args);

-

-  DumpHeader header(dump_log, _T("Operating System Data"));

-

-  CString os_version;

-  CString service_pack;

-  goopdate_utils::GetOSInfo(&os_version, &service_pack);

-  dump_log.WriteLine(_T("OS Version:\t%s"), os_version);

-  dump_log.WriteLine(_T("Service Pack:\t%s"), service_pack);

-

-  TCHAR computer_name[MAX_PATH] = {0};

-  ULONG computer_name_size = arraysize(computer_name);

-  ::GetComputerNameEx(ComputerNameDnsFullyQualified,

-                      computer_name,

-                      &computer_name_size);

-  dump_log.WriteLine(_T("Computer Name:\t%s"), computer_name);

-

-  TCHAR user_name[MAX_PATH] = {0};

-  ULONG user_name_size = arraysize(user_name);

-  ::GetUserNameEx(NameSamCompatible, user_name, &user_name_size);

-  dump_log.WriteLine(_T("User Name:\t%s"), user_name);

-

-  TCHAR user_friendly_name[MAX_PATH] = {0};

-  ULONG user_friendly_name_size = arraysize(user_friendly_name);

-  ::GetUserNameEx(NameDisplay, user_friendly_name, &user_friendly_name_size);

-  dump_log.WriteLine(_T("Friendly Name:\t%s"), user_friendly_name);

-

-  CString system_uptime;

-  if (SUCCEEDED(GetSystemUptime(&system_uptime))) {

-    dump_log.WriteLine(_T("System Uptime:\t%s"), system_uptime);

-  } else {

-    dump_log.WriteLine(_T("System Uptime:\tNot Available"));

-  }

-

-  PERFORMANCE_INFORMATION perf_info = {0};

-  perf_info.cb = sizeof(perf_info);

-  if (::GetPerformanceInfo(&perf_info, sizeof(perf_info))) {

-    dump_log.WriteLine(_T("Process Count: %d"), perf_info.ProcessCount);

-    dump_log.WriteLine(_T("Handle Count:  %d"), perf_info.HandleCount);

-    dump_log.WriteLine(_T("Thread Count:  %d"), perf_info.ThreadCount);

-

-    size_t page_size = perf_info.PageSize;

-    size_t mb = 1024 * 1024;

-

-    dump_log.WriteLine(_T("Commit Total(MB):     %ld"),

-                       perf_info.CommitTotal * page_size / mb);

-    dump_log.WriteLine(_T("Commit Limit(MB):     %ld"),

-                       perf_info.CommitLimit * page_size / mb);

-    dump_log.WriteLine(_T("Commit Peak(MB):      %ld"),

-                       perf_info.CommitPeak * page_size / mb);

-    dump_log.WriteLine(_T("Kernel Total(MB):     %ld"),

-                       perf_info.KernelTotal * page_size / mb);

-    dump_log.WriteLine(_T("Kernel Paged(MB):     %ld"),

-                       perf_info.KernelPaged * page_size / mb);

-    dump_log.WriteLine(_T("Kernel NonPaged(MB):  %ld"),

-                       perf_info.KernelNonpaged * page_size / mb);

-    dump_log.WriteLine(_T("Page Size (KB):       %ld"),

-                       perf_info.PageSize / 1024);

-    dump_log.WriteLine(_T("Physical Avail(MB):   %ld"),

-                       perf_info.PhysicalAvailable * page_size / mb);

-    dump_log.WriteLine(_T("Physical Total(MB):   %ld"),

-                       perf_info.PhysicalTotal * page_size / mb);

-    dump_log.WriteLine(_T("System Cache(MB):     %ld"),

-                       perf_info.SystemCache * page_size / mb);

-  } else {

-    dump_log.WriteLine(_T("Unable to Get Performance Info"));

-  }

-

-  return S_OK;

-}

-

-HRESULT DataDumperOSData::GetSystemUptime(CString* uptime) {

-  ASSERT1(uptime);

-

-  const TCHAR* kUptimeCounterPath = _T("\\\\.\\System\\System Up Time");

-

-  HRESULT hr = S_OK;

-

-  PDH_HQUERY perf_query = NULL;

-  PDH_STATUS status = ::PdhOpenQuery(NULL, 0, &perf_query);

-  if (status != ERROR_SUCCESS) {

-    return HRESULT_FROM_WIN32(status);

-  }

-

-  ScopeGuard guard = MakeGuard(::PdhCloseQuery, perf_query);

-

-  PDH_HCOUNTER uptime_counter = NULL;

-  status = ::PdhAddCounter(perf_query,

-                           kUptimeCounterPath,

-                           0,

-                           &uptime_counter);

-  if (status != ERROR_SUCCESS) {

-    return HRESULT_FROM_WIN32(status);

-  }

-

-  status = ::PdhCollectQueryData(perf_query);

-  if (status != ERROR_SUCCESS) {

-    return HRESULT_FROM_WIN32(status);

-  }

-

-  PDH_FMT_COUNTERVALUE uptime_value = {0};

-  status = ::PdhGetFormattedCounterValue(uptime_counter,

-                                         PDH_FMT_LARGE,

-                                         NULL,

-                                         &uptime_value);

-  if (status != ERROR_SUCCESS) {

-    return HRESULT_FROM_WIN32(status);

-  }

-

-  CTimeSpan uptime_span(uptime_value.largeValue);

-  *uptime = uptime_span.Format(_T("%D days, %H hours, %M minutes, %S seconds"));

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/data_dumper_osdata.h"
+
+#include <atltime.h>
+#include <pdh.h>
+#include <psapi.h>
+#include <security.h>
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/time.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/tools/goopdump/dump_log.h"
+#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"
+
+namespace omaha {
+
+DataDumperOSData::DataDumperOSData() {
+}
+
+DataDumperOSData::~DataDumperOSData() {
+}
+
+HRESULT DataDumperOSData::Process(const DumpLog& dump_log,
+                                    const GoopdumpCmdLineArgs& args) {
+  UNREFERENCED_PARAMETER(args);
+
+  DumpHeader header(dump_log, _T("Operating System Data"));
+
+  CString os_version;
+  CString service_pack;
+  goopdate_utils::GetOSInfo(&os_version, &service_pack);
+  dump_log.WriteLine(_T("OS Version:\t%s"), os_version);
+  dump_log.WriteLine(_T("Service Pack:\t%s"), service_pack);
+
+  TCHAR computer_name[MAX_PATH] = {0};
+  ULONG computer_name_size = arraysize(computer_name);
+  ::GetComputerNameEx(ComputerNameDnsFullyQualified,
+                      computer_name,
+                      &computer_name_size);
+  dump_log.WriteLine(_T("Computer Name:\t%s"), computer_name);
+
+  TCHAR user_name[MAX_PATH] = {0};
+  ULONG user_name_size = arraysize(user_name);
+  ::GetUserNameEx(NameSamCompatible, user_name, &user_name_size);
+  dump_log.WriteLine(_T("User Name:\t%s"), user_name);
+
+  TCHAR user_friendly_name[MAX_PATH] = {0};
+  ULONG user_friendly_name_size = arraysize(user_friendly_name);
+  ::GetUserNameEx(NameDisplay, user_friendly_name, &user_friendly_name_size);
+  dump_log.WriteLine(_T("Friendly Name:\t%s"), user_friendly_name);
+
+  CString system_uptime;
+  if (SUCCEEDED(GetSystemUptime(&system_uptime))) {
+    dump_log.WriteLine(_T("System Uptime:\t%s"), system_uptime);
+  } else {
+    dump_log.WriteLine(_T("System Uptime:\tNot Available"));
+  }
+
+  PERFORMANCE_INFORMATION perf_info = {0};
+  perf_info.cb = sizeof(perf_info);
+  if (::GetPerformanceInfo(&perf_info, sizeof(perf_info))) {
+    dump_log.WriteLine(_T("Process Count: %d"), perf_info.ProcessCount);
+    dump_log.WriteLine(_T("Handle Count:  %d"), perf_info.HandleCount);
+    dump_log.WriteLine(_T("Thread Count:  %d"), perf_info.ThreadCount);
+
+    size_t page_size = perf_info.PageSize;
+    size_t mb = 1024 * 1024;
+
+    dump_log.WriteLine(_T("Commit Total(MB):     %ld"),
+                       perf_info.CommitTotal * page_size / mb);
+    dump_log.WriteLine(_T("Commit Limit(MB):     %ld"),
+                       perf_info.CommitLimit * page_size / mb);
+    dump_log.WriteLine(_T("Commit Peak(MB):      %ld"),
+                       perf_info.CommitPeak * page_size / mb);
+    dump_log.WriteLine(_T("Kernel Total(MB):     %ld"),
+                       perf_info.KernelTotal * page_size / mb);
+    dump_log.WriteLine(_T("Kernel Paged(MB):     %ld"),
+                       perf_info.KernelPaged * page_size / mb);
+    dump_log.WriteLine(_T("Kernel NonPaged(MB):  %ld"),
+                       perf_info.KernelNonpaged * page_size / mb);
+    dump_log.WriteLine(_T("Page Size (KB):       %ld"),
+                       perf_info.PageSize / 1024);
+    dump_log.WriteLine(_T("Physical Avail(MB):   %ld"),
+                       perf_info.PhysicalAvailable * page_size / mb);
+    dump_log.WriteLine(_T("Physical Total(MB):   %ld"),
+                       perf_info.PhysicalTotal * page_size / mb);
+    dump_log.WriteLine(_T("System Cache(MB):     %ld"),
+                       perf_info.SystemCache * page_size / mb);
+  } else {
+    dump_log.WriteLine(_T("Unable to Get Performance Info"));
+  }
+
+  return S_OK;
+}
+
+HRESULT DataDumperOSData::GetSystemUptime(CString* uptime) {
+  ASSERT1(uptime);
+
+  const TCHAR* kUptimeCounterPath = _T("\\\\.\\System\\System Up Time");
+
+  HRESULT hr = S_OK;
+
+  PDH_HQUERY perf_query = NULL;
+  PDH_STATUS status = ::PdhOpenQuery(NULL, 0, &perf_query);
+  if (status != ERROR_SUCCESS) {
+    return HRESULT_FROM_WIN32(status);
+  }
+
+  ScopeGuard guard = MakeGuard(::PdhCloseQuery, perf_query);
+
+  PDH_HCOUNTER uptime_counter = NULL;
+  status = ::PdhAddCounter(perf_query,
+                           kUptimeCounterPath,
+                           0,
+                           &uptime_counter);
+  if (status != ERROR_SUCCESS) {
+    return HRESULT_FROM_WIN32(status);
+  }
+
+  status = ::PdhCollectQueryData(perf_query);
+  if (status != ERROR_SUCCESS) {
+    return HRESULT_FROM_WIN32(status);
+  }
+
+  PDH_FMT_COUNTERVALUE uptime_value = {0};
+  status = ::PdhGetFormattedCounterValue(uptime_counter,
+                                         PDH_FMT_LARGE,
+                                         NULL,
+                                         &uptime_value);
+  if (status != ERROR_SUCCESS) {
+    return HRESULT_FROM_WIN32(status);
+  }
+
+  CTimeSpan uptime_span(uptime_value.largeValue);
+  *uptime = uptime_span.Format(_T("%D days, %H hours, %M minutes, %S seconds"));
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/data_dumper_osdata.h b/tools/goopdump/data_dumper_osdata.h
index 6123f8a..03bee91 100644
--- a/tools/goopdump/data_dumper_osdata.h
+++ b/tools/goopdump/data_dumper_osdata.h
@@ -1,43 +1,43 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_OSDATA_H_

-#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_OSDATA_H_

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-#include "omaha/tools/goopdump/data_dumper.h"

-

-namespace omaha {

-

-class DataDumperOSData : public DataDumper {

- public:

-  DataDumperOSData();

-  virtual ~DataDumperOSData();

-

-  virtual HRESULT Process(const DumpLog& dump_log,

-                          const GoopdumpCmdLineArgs& args);

-

- private:

-  HRESULT GetSystemUptime(CString* uptime);

-  DISALLOW_EVIL_CONSTRUCTORS(DataDumperOSData);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_OSDATA_H_

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_OSDATA_H_
+#define OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_OSDATA_H_
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+#include "omaha/tools/goopdump/data_dumper.h"
+
+namespace omaha {
+
+class DataDumperOSData : public DataDumper {
+ public:
+  DataDumperOSData();
+  virtual ~DataDumperOSData();
+
+  virtual HRESULT Process(const DumpLog& dump_log,
+                          const GoopdumpCmdLineArgs& args);
+
+ private:
+  HRESULT GetSystemUptime(CString* uptime);
+  DISALLOW_EVIL_CONSTRUCTORS(DataDumperOSData);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DATA_DUMPER_OSDATA_H_
+
diff --git a/tools/goopdump/dump_log.cc b/tools/goopdump/dump_log.cc
index ebd0d6a..878dfb7 100644
--- a/tools/goopdump/dump_log.cc
+++ b/tools/goopdump/dump_log.cc
@@ -1,162 +1,162 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/dump_log.h"

-

-#include <vector>

-

-#include "omaha/common/debug.h"

-#include "omaha/common/file.h"

-

-namespace omaha {

-

-DumpLogHandler::DumpLogHandler() {

-}

-

-DumpLogHandler::~DumpLogHandler() {

-}

-

-

-ConsoleDumpLogHandler::ConsoleDumpLogHandler() {

-}

-

-ConsoleDumpLogHandler::~ConsoleDumpLogHandler() {

-}

-

-void ConsoleDumpLogHandler::WriteLine(const TCHAR* line) {

-  _tprintf(_T("%s"), line);

-}

-

-

-DebugDumpLogHandler::DebugDumpLogHandler() {

-}

-

-DebugDumpLogHandler::~DebugDumpLogHandler() {

-}

-

-void DebugDumpLogHandler::WriteLine(const TCHAR* line) {

-  ::OutputDebugString(line);

-}

-

-

-FileDumpLogHandler::FileDumpLogHandler() {

-}

-

-FileDumpLogHandler::~FileDumpLogHandler() {

-}

-

-void FileDumpLogHandler::set_filename(const TCHAR* filename) {

-  filename_ = filename;

-  if (File::Exists(filename_)) {

-    File::Remove(filename_);

-

-    // Write the UNICODE file marker at the beginning.

-    char buf[2] = {0xff, 0xfe};

-    WriteBufToFile(buf, 2);

-  }

-}

-

-void FileDumpLogHandler::WriteLine(const TCHAR* line) {

-  if (filename_.IsEmpty()) {

-    return;

-  }

-

-  WriteBufToFile(line, _tcslen(line) * sizeof(TCHAR));

-}

-

-void FileDumpLogHandler::WriteBufToFile(const void* buf,

-                                        DWORD num_bytes_to_write) {

-  HANDLE h = ::CreateFile(filename_,

-                          GENERIC_WRITE,

-                          FILE_SHARE_READ,

-                          NULL,

-                          OPEN_ALWAYS,

-                          FILE_ATTRIBUTE_NORMAL,

-                          NULL);

-  if (h == INVALID_HANDLE_VALUE) {

-    return;

-  }

-

-  ::SetFilePointer(h, NULL, NULL, FILE_END);

-  DWORD bytes_written = 0;

-  ::WriteFile(h, buf, num_bytes_to_write, &bytes_written, NULL);

-  ::CloseHandle(h);

-}

-

-

-DumpLog::DumpLog() {

-}

-

-DumpLog::~DumpLog() {

-}

-

-void DumpLog::EnableConsole(bool enable) {

-  if (enable) {

-    AddLogHandler(&console_handler_);

-  } else {

-    RemoveLogHandler(&console_handler_);

-  }

-}

-

-void DumpLog::EnableDebug(bool enable) {

-  if (enable) {

-    AddLogHandler(&debug_handler_);

-  } else {

-    RemoveLogHandler(&debug_handler_);

-  }

-}

-

-void DumpLog::AddLogHandler(DumpLogHandler* log_handler) {

-  ASSERT1(log_handler);

-  std::vector<DumpLogHandler*>::iterator it = log_handlers_.begin();

-  for (; it != log_handlers_.end(); ++it) {

-    DumpLogHandler* handler = *it;

-    if (handler == log_handler) {

-      return;

-    }

-  }

-

-  log_handlers_.push_back(log_handler);

-}

-

-void DumpLog::RemoveLogHandler(DumpLogHandler* log_handler) {

-  ASSERT1(log_handler);

-  std::vector<DumpLogHandler*>::iterator it = log_handlers_.begin();

-  for (; it != log_handlers_.end(); ++it) {

-    DumpLogHandler* handler = *it;

-    if (handler == log_handler) {

-      log_handlers_.erase(it);

-      return;

-    }

-  }

-}

-

-void DumpLog::WriteLine(const TCHAR* format, ...) const {

-  va_list arg_list;

-  va_start(arg_list, format);

-

-  CString line;

-  line.FormatV(format, arg_list);

-  line.Append(_T("\r\n"));

-

-  std::vector<DumpLogHandler*>::const_iterator it = log_handlers_.begin();

-  for (; it != log_handlers_.end(); ++it) {

-    DumpLogHandler* handler = *it;

-    handler->WriteLine(line);

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/dump_log.h"
+
+#include <vector>
+
+#include "omaha/common/debug.h"
+#include "omaha/common/file.h"
+
+namespace omaha {
+
+DumpLogHandler::DumpLogHandler() {
+}
+
+DumpLogHandler::~DumpLogHandler() {
+}
+
+
+ConsoleDumpLogHandler::ConsoleDumpLogHandler() {
+}
+
+ConsoleDumpLogHandler::~ConsoleDumpLogHandler() {
+}
+
+void ConsoleDumpLogHandler::WriteLine(const TCHAR* line) {
+  _tprintf(_T("%s"), line);
+}
+
+
+DebugDumpLogHandler::DebugDumpLogHandler() {
+}
+
+DebugDumpLogHandler::~DebugDumpLogHandler() {
+}
+
+void DebugDumpLogHandler::WriteLine(const TCHAR* line) {
+  ::OutputDebugString(line);
+}
+
+
+FileDumpLogHandler::FileDumpLogHandler() {
+}
+
+FileDumpLogHandler::~FileDumpLogHandler() {
+}
+
+void FileDumpLogHandler::set_filename(const TCHAR* filename) {
+  filename_ = filename;
+  if (File::Exists(filename_)) {
+    File::Remove(filename_);
+
+    // Write the UNICODE file marker at the beginning.
+    char buf[2] = {0xff, 0xfe};
+    WriteBufToFile(buf, 2);
+  }
+}
+
+void FileDumpLogHandler::WriteLine(const TCHAR* line) {
+  if (filename_.IsEmpty()) {
+    return;
+  }
+
+  WriteBufToFile(line, _tcslen(line) * sizeof(TCHAR));
+}
+
+void FileDumpLogHandler::WriteBufToFile(const void* buf,
+                                        DWORD num_bytes_to_write) {
+  HANDLE h = ::CreateFile(filename_,
+                          GENERIC_WRITE,
+                          FILE_SHARE_READ,
+                          NULL,
+                          OPEN_ALWAYS,
+                          FILE_ATTRIBUTE_NORMAL,
+                          NULL);
+  if (h == INVALID_HANDLE_VALUE) {
+    return;
+  }
+
+  ::SetFilePointer(h, NULL, NULL, FILE_END);
+  DWORD bytes_written = 0;
+  ::WriteFile(h, buf, num_bytes_to_write, &bytes_written, NULL);
+  ::CloseHandle(h);
+}
+
+
+DumpLog::DumpLog() {
+}
+
+DumpLog::~DumpLog() {
+}
+
+void DumpLog::EnableConsole(bool enable) {
+  if (enable) {
+    AddLogHandler(&console_handler_);
+  } else {
+    RemoveLogHandler(&console_handler_);
+  }
+}
+
+void DumpLog::EnableDebug(bool enable) {
+  if (enable) {
+    AddLogHandler(&debug_handler_);
+  } else {
+    RemoveLogHandler(&debug_handler_);
+  }
+}
+
+void DumpLog::AddLogHandler(DumpLogHandler* log_handler) {
+  ASSERT1(log_handler);
+  std::vector<DumpLogHandler*>::iterator it = log_handlers_.begin();
+  for (; it != log_handlers_.end(); ++it) {
+    DumpLogHandler* handler = *it;
+    if (handler == log_handler) {
+      return;
+    }
+  }
+
+  log_handlers_.push_back(log_handler);
+}
+
+void DumpLog::RemoveLogHandler(DumpLogHandler* log_handler) {
+  ASSERT1(log_handler);
+  std::vector<DumpLogHandler*>::iterator it = log_handlers_.begin();
+  for (; it != log_handlers_.end(); ++it) {
+    DumpLogHandler* handler = *it;
+    if (handler == log_handler) {
+      log_handlers_.erase(it);
+      return;
+    }
+  }
+}
+
+void DumpLog::WriteLine(const TCHAR* format, ...) const {
+  va_list arg_list;
+  va_start(arg_list, format);
+
+  CString line;
+  line.FormatV(format, arg_list);
+  line.Append(_T("\r\n"));
+
+  std::vector<DumpLogHandler*>::const_iterator it = log_handlers_.begin();
+  for (; it != log_handlers_.end(); ++it) {
+    DumpLogHandler* handler = *it;
+    handler->WriteLine(line);
+  }
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/dump_log.h b/tools/goopdump/dump_log.h
index 4a67506..1e1ce7c 100644
--- a/tools/goopdump/dump_log.h
+++ b/tools/goopdump/dump_log.h
@@ -1,112 +1,112 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DUMP_LOG_H_

-#define OMAHA_TOOLS_SRC_GOOPDUMP_DUMP_LOG_H_

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-

-// TODO(omaha):  Can we use the other Omaha logging classes for this?

-

-namespace omaha {

-

-class DumpLogHandler {

- public:

-  DumpLogHandler();

-  virtual ~DumpLogHandler();

-

-  virtual void WriteLine(const TCHAR* line) = 0;

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(DumpLogHandler);

-};

-

-class ConsoleDumpLogHandler : public DumpLogHandler {

- public:

-  ConsoleDumpLogHandler();

-  virtual ~ConsoleDumpLogHandler();

-

-  virtual void WriteLine(const TCHAR* line);

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(ConsoleDumpLogHandler);

-};

-

-class DebugDumpLogHandler : public DumpLogHandler {

- public:

-  DebugDumpLogHandler();

-  virtual ~DebugDumpLogHandler();

-

-  virtual void WriteLine(const TCHAR* line);

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(DebugDumpLogHandler);

-};

-

-class FileDumpLogHandler : public DumpLogHandler {

- public:

-  FileDumpLogHandler();

-  virtual ~FileDumpLogHandler();

-

-  void set_filename(const TCHAR* filename);

-  virtual void WriteLine(const TCHAR* line);

-

- private:

-  void WriteBufToFile(const void* buf, DWORD num_bytes_to_write);

-

-  CString filename_;

-  DISALLOW_EVIL_CONSTRUCTORS(FileDumpLogHandler);

-};

-

-

-class DumpLog {

- public:

-  DumpLog();

-  ~DumpLog();

-

-  // Enables output to the console.

-  void EnableConsole(bool enable);

-

-  // Enables output to OutputDebugString().

-  void EnableDebug(bool enable);

-

-  // Adds a log handler to pipe content to.

-  // Not needed for console or debug, those are done separately.

-  // The class does not assume ownership of the pointer and the pointer must

-  // live until this class is destroyed.

-  void AddLogHandler(DumpLogHandler* log_handler);

-

-  // Removes the log handler.  Removal is done based on pointer equality.

-  void RemoveLogHandler(DumpLogHandler* log_handler);

-

-  // Writes a line to each of the connected log handlers.

-  void WriteLine(const TCHAR* format, ...) const;

-

- private:

-  std::vector<DumpLogHandler*> log_handlers_;

-

-  ConsoleDumpLogHandler console_handler_;

-  DebugDumpLogHandler debug_handler_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(DumpLog);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DUMP_LOG_H_

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_DUMP_LOG_H_
+#define OMAHA_TOOLS_SRC_GOOPDUMP_DUMP_LOG_H_
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+
+// TODO(omaha):  Can we use the other Omaha logging classes for this?
+
+namespace omaha {
+
+class DumpLogHandler {
+ public:
+  DumpLogHandler();
+  virtual ~DumpLogHandler();
+
+  virtual void WriteLine(const TCHAR* line) = 0;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(DumpLogHandler);
+};
+
+class ConsoleDumpLogHandler : public DumpLogHandler {
+ public:
+  ConsoleDumpLogHandler();
+  virtual ~ConsoleDumpLogHandler();
+
+  virtual void WriteLine(const TCHAR* line);
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(ConsoleDumpLogHandler);
+};
+
+class DebugDumpLogHandler : public DumpLogHandler {
+ public:
+  DebugDumpLogHandler();
+  virtual ~DebugDumpLogHandler();
+
+  virtual void WriteLine(const TCHAR* line);
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(DebugDumpLogHandler);
+};
+
+class FileDumpLogHandler : public DumpLogHandler {
+ public:
+  FileDumpLogHandler();
+  virtual ~FileDumpLogHandler();
+
+  void set_filename(const TCHAR* filename);
+  virtual void WriteLine(const TCHAR* line);
+
+ private:
+  void WriteBufToFile(const void* buf, DWORD num_bytes_to_write);
+
+  CString filename_;
+  DISALLOW_EVIL_CONSTRUCTORS(FileDumpLogHandler);
+};
+
+
+class DumpLog {
+ public:
+  DumpLog();
+  ~DumpLog();
+
+  // Enables output to the console.
+  void EnableConsole(bool enable);
+
+  // Enables output to OutputDebugString().
+  void EnableDebug(bool enable);
+
+  // Adds a log handler to pipe content to.
+  // Not needed for console or debug, those are done separately.
+  // The class does not assume ownership of the pointer and the pointer must
+  // live until this class is destroyed.
+  void AddLogHandler(DumpLogHandler* log_handler);
+
+  // Removes the log handler.  Removal is done based on pointer equality.
+  void RemoveLogHandler(DumpLogHandler* log_handler);
+
+  // Writes a line to each of the connected log handlers.
+  void WriteLine(const TCHAR* format, ...) const;
+
+ private:
+  std::vector<DumpLogHandler*> log_handlers_;
+
+  ConsoleDumpLogHandler console_handler_;
+  DebugDumpLogHandler debug_handler_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(DumpLog);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_DUMP_LOG_H_
+
diff --git a/tools/goopdump/goopdump.cc b/tools/goopdump/goopdump.cc
index 01ba68a..5b4ac18 100644
--- a/tools/goopdump/goopdump.cc
+++ b/tools/goopdump/goopdump.cc
@@ -1,165 +1,165 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/goopdump.h"

-

-#include <stdio.h>

-

-#include <vector>

-

-#include "omaha/common/debug.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/tools/goopdump/data_dumper.h"

-#include "omaha/tools/goopdump/data_dumper_app_manager.h"

-#include "omaha/tools/goopdump/data_dumper_goopdate.h"

-#include "omaha/tools/goopdump/data_dumper_network.h"

-#include "omaha/tools/goopdump/data_dumper_oneclick.h"

-#include "omaha/tools/goopdump/data_dumper_osdata.h"

-#include "omaha/tools/goopdump/process_commandline.h"

-#include "omaha/tools/goopdump/process_monitor.h"

-

-namespace omaha {

-

-class GoopdateProcessMonitorCallback : public ProcessMonitorCallbackInterface {

- public:

-  explicit GoopdateProcessMonitorCallback(const DumpLog& dump_log)

-      : dump_log_(dump_log) {

-  }

-  virtual ~GoopdateProcessMonitorCallback() {}

-

-  virtual void OnProcessAdded(DWORD process_id,

-                              const CString& process_pattern) {

-    CString cmd_line;

-    GetProcessCommandLine(process_id, &cmd_line);

-    dump_log_.WriteLine(_T("Process Added.    ProcessId(%d)  Pattern(%s)  ")

-                        _T("cmd_line(%s)"),

-                        process_id, process_pattern, cmd_line);

-  }

-

-  virtual void OnProcessRemoved(DWORD process_id) {

-    dump_log_.WriteLine(_T("Process Removed.  ProcessId(%d)"), process_id);

-  }

-

- private:

-  const DumpLog& dump_log_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(GoopdateProcessMonitorCallback);

-};

-

-

-Goopdump::Goopdump() {

-}

-

-Goopdump::~Goopdump() {

-}

-

-HRESULT Goopdump::Main(const TCHAR* cmd_line, int argc, TCHAR** argv) {

-  SetNewHandler();

-  dump_log_.EnableConsole(true);

-  FileDumpLogHandler file_dumplog_handler;

-

-  ::CoInitializeEx(NULL, COINIT_MULTITHREADED);

-

-  cmd_line_ = cmd_line;

-

-  PrintProgramHeader();

-  dump_log_.WriteLine(_T("cmd_line_: %s"), cmd_line_);

-

-  if (FAILED(ParseGoopdumpCmdLine(argc, argv, &args_))) {

-    PrintUsage();

-    return E_FAIL;

-  }

-

-  if (args_.is_write_to_file) {

-    file_dumplog_handler.set_filename(args_.log_filename);

-    dump_log_.AddLogHandler(&file_dumplog_handler);

-  }

-

-  // Dump out any requested data.

-  std::vector<DataDumper*> data_dumpers;

-

-  if (args_.is_dump_general) {

-    data_dumpers.push_back(new DataDumperOSData());

-    data_dumpers.push_back(new DataDumperNetwork());

-    data_dumpers.push_back(new DataDumperGoopdate());

-  }

-

-  if (args_.is_dump_oneclick) {

-    data_dumpers.push_back(new DataDumperOneClick());

-  }

-

-  if (args_.is_dump_app_manager) {

-    data_dumpers.push_back(new DataDumperAppManager());

-  }

-

-  std::vector<DataDumper*>::iterator it = data_dumpers.begin();

-  for (; it != data_dumpers.end(); ++it) {

-    DataDumper* dumper = *it;

-

-    dumper->Process(dump_log_, args_);

-    delete dumper;

-  }

-  data_dumpers.clear();

-

-  if (args_.is_monitor) {

-    // We want to monitor activity from GoogleUpdate.exe.

-    // Examples include:

-    // * Process start with arguments

-    // * Process exit

-    // * Others?

-    ProcessMonitor process_monitor;

-    GoopdateProcessMonitorCallback callback(dump_log_);

-    std::vector<CString> patterns;

-    patterns.push_back(CString(_T("googleupdate.exe")));

-    patterns.push_back(CString(_T("notepad.exe")));

-    process_monitor.StartWithPatterns(&callback, patterns);

-    getchar();

-    process_monitor.Stop();

-  }

-

-  ::CoUninitialize();

-

-  return S_OK;

-}

-

-void Goopdump::PrintProgramHeader() {

-  dump_log_.WriteLine(_T(""));

-  dump_log_.WriteLine(_T("Goopdump.exe -- Debug Utility for Google Update"));

-  dump_log_.WriteLine(_T("(c) Google, Inc."));

-  dump_log_.WriteLine(_T(""));

-}

-

-void Goopdump::PrintUsage() {

-  dump_log_.WriteLine(_T("Usage:"));

-  dump_log_.WriteLine(_T(""));

-}

-

-void Goopdump::SetNewHandler() {

-  VERIFY1(set_new_handler(&Goopdump::OutOfMemoryHandler) == 0);

-}

-

-void Goopdump::OutOfMemoryHandler() {

-  ::RaiseException(EXCEPTION_ACCESS_VIOLATION,

-                   EXCEPTION_NONCONTINUABLE,

-                   0,

-                   NULL);

-}

-

-CString Goopdump::cmd_line() const {

-  return cmd_line_;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/goopdump.h"
+
+#include <stdio.h>
+
+#include <vector>
+
+#include "omaha/common/debug.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/tools/goopdump/data_dumper.h"
+#include "omaha/tools/goopdump/data_dumper_app_manager.h"
+#include "omaha/tools/goopdump/data_dumper_goopdate.h"
+#include "omaha/tools/goopdump/data_dumper_network.h"
+#include "omaha/tools/goopdump/data_dumper_oneclick.h"
+#include "omaha/tools/goopdump/data_dumper_osdata.h"
+#include "omaha/tools/goopdump/process_commandline.h"
+#include "omaha/tools/goopdump/process_monitor.h"
+
+namespace omaha {
+
+class GoopdateProcessMonitorCallback : public ProcessMonitorCallbackInterface {
+ public:
+  explicit GoopdateProcessMonitorCallback(const DumpLog& dump_log)
+      : dump_log_(dump_log) {
+  }
+  virtual ~GoopdateProcessMonitorCallback() {}
+
+  virtual void OnProcessAdded(DWORD process_id,
+                              const CString& process_pattern) {
+    CString cmd_line;
+    GetProcessCommandLine(process_id, &cmd_line);
+    dump_log_.WriteLine(_T("Process Added.    ProcessId(%d)  Pattern(%s)  ")
+                        _T("cmd_line(%s)"),
+                        process_id, process_pattern, cmd_line);
+  }
+
+  virtual void OnProcessRemoved(DWORD process_id) {
+    dump_log_.WriteLine(_T("Process Removed.  ProcessId(%d)"), process_id);
+  }
+
+ private:
+  const DumpLog& dump_log_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(GoopdateProcessMonitorCallback);
+};
+
+
+Goopdump::Goopdump() {
+}
+
+Goopdump::~Goopdump() {
+}
+
+HRESULT Goopdump::Main(const TCHAR* cmd_line, int argc, TCHAR** argv) {
+  SetNewHandler();
+  dump_log_.EnableConsole(true);
+  FileDumpLogHandler file_dumplog_handler;
+
+  ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+  cmd_line_ = cmd_line;
+
+  PrintProgramHeader();
+  dump_log_.WriteLine(_T("cmd_line_: %s"), cmd_line_);
+
+  if (FAILED(ParseGoopdumpCmdLine(argc, argv, &args_))) {
+    PrintUsage();
+    return E_FAIL;
+  }
+
+  if (args_.is_write_to_file) {
+    file_dumplog_handler.set_filename(args_.log_filename);
+    dump_log_.AddLogHandler(&file_dumplog_handler);
+  }
+
+  // Dump out any requested data.
+  std::vector<DataDumper*> data_dumpers;
+
+  if (args_.is_dump_general) {
+    data_dumpers.push_back(new DataDumperOSData());
+    data_dumpers.push_back(new DataDumperNetwork());
+    data_dumpers.push_back(new DataDumperGoopdate());
+  }
+
+  if (args_.is_dump_oneclick) {
+    data_dumpers.push_back(new DataDumperOneClick());
+  }
+
+  if (args_.is_dump_app_manager) {
+    data_dumpers.push_back(new DataDumperAppManager());
+  }
+
+  std::vector<DataDumper*>::iterator it = data_dumpers.begin();
+  for (; it != data_dumpers.end(); ++it) {
+    DataDumper* dumper = *it;
+
+    dumper->Process(dump_log_, args_);
+    delete dumper;
+  }
+  data_dumpers.clear();
+
+  if (args_.is_monitor) {
+    // We want to monitor activity from GoogleUpdate.exe.
+    // Examples include:
+    // * Process start with arguments
+    // * Process exit
+    // * Others?
+    ProcessMonitor process_monitor;
+    GoopdateProcessMonitorCallback callback(dump_log_);
+    std::vector<CString> patterns;
+    patterns.push_back(CString(_T("googleupdate.exe")));
+    patterns.push_back(CString(_T("notepad.exe")));
+    process_monitor.StartWithPatterns(&callback, patterns);
+    getchar();
+    process_monitor.Stop();
+  }
+
+  ::CoUninitialize();
+
+  return S_OK;
+}
+
+void Goopdump::PrintProgramHeader() {
+  dump_log_.WriteLine(_T(""));
+  dump_log_.WriteLine(_T("Goopdump.exe -- Debug Utility for Google Update"));
+  dump_log_.WriteLine(_T("(c) Google, Inc."));
+  dump_log_.WriteLine(_T(""));
+}
+
+void Goopdump::PrintUsage() {
+  dump_log_.WriteLine(_T("Usage:"));
+  dump_log_.WriteLine(_T(""));
+}
+
+void Goopdump::SetNewHandler() {
+  VERIFY1(set_new_handler(&Goopdump::OutOfMemoryHandler) == 0);
+}
+
+void Goopdump::OutOfMemoryHandler() {
+  ::RaiseException(EXCEPTION_ACCESS_VIOLATION,
+                   EXCEPTION_NONCONTINUABLE,
+                   0,
+                   NULL);
+}
+
+CString Goopdump::cmd_line() const {
+  return cmd_line_;
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/goopdump.h b/tools/goopdump/goopdump.h
index d0ff3c9..8a34351 100644
--- a/tools/goopdump/goopdump.h
+++ b/tools/goopdump/goopdump.h
@@ -1,65 +1,65 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_H__

-#define OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-#include "omaha/tools/goopdump/dump_log.h"

-#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"

-

-namespace omaha {

-

-class ConfigManager;

-

-class Goopdump {

- public:

-  // Constructor / Destructor

-  Goopdump();

-  ~Goopdump();

-

-  HRESULT Main(const TCHAR* cmd_line, int argc, TCHAR** argv);

-

-  ConfigManager* config_manager() const;

-  CString cmd_line() const;

-

-  GoopdumpCmdLineArgs& cmd_line_args() const;

-

- private:

-  // Installs a user function that is to be called when operator new fails

-  // to allocate memory.

-  static void SetNewHandler();

-

-  // Called by operator new or operator new[] when they cannot satisfy

-  // a request for additional storage.

-  static void OutOfMemoryHandler();

-

-  void PrintProgramHeader();

-  void PrintUsage();

-

-  CString cmd_line_;            // Command line, as provided by the OS.

-  GoopdumpCmdLineArgs args_;

-  DumpLog dump_log_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Goopdump);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_H__

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_H__
+#define OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+#include "omaha/tools/goopdump/dump_log.h"
+#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"
+
+namespace omaha {
+
+class ConfigManager;
+
+class Goopdump {
+ public:
+  // Constructor / Destructor
+  Goopdump();
+  ~Goopdump();
+
+  HRESULT Main(const TCHAR* cmd_line, int argc, TCHAR** argv);
+
+  ConfigManager* config_manager() const;
+  CString cmd_line() const;
+
+  GoopdumpCmdLineArgs& cmd_line_args() const;
+
+ private:
+  // Installs a user function that is to be called when operator new fails
+  // to allocate memory.
+  static void SetNewHandler();
+
+  // Called by operator new or operator new[] when they cannot satisfy
+  // a request for additional storage.
+  static void OutOfMemoryHandler();
+
+  void PrintProgramHeader();
+  void PrintUsage();
+
+  CString cmd_line_;            // Command line, as provided by the OS.
+  GoopdumpCmdLineArgs args_;
+  DumpLog dump_log_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Goopdump);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_H__
+
diff --git a/tools/goopdump/goopdump_cmd_line_parser.cc b/tools/goopdump/goopdump_cmd_line_parser.cc
index ab136d7..12048d5 100644
--- a/tools/goopdump/goopdump_cmd_line_parser.cc
+++ b/tools/goopdump/goopdump_cmd_line_parser.cc
@@ -1,102 +1,102 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"

-

-#include "omaha/common/debug.h"

-#include "omaha/goopdate/command_line_parser.h"

-

-namespace omaha {

-

-HRESULT ParseGoopdumpCmdLine(int argc,

-                             TCHAR** argv,

-                             GoopdumpCmdLineArgs* args) {

-  ASSERT1(argc >= 1);

-  ASSERT1(argv);

-

-  UNREFERENCED_PARAMETER(argc);

-  UNREFERENCED_PARAMETER(argv);

-

-  CommandLineParser parser;

-  HRESULT hr = parser.ParseFromArgv(argc, argv);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  std::vector<CString> valid_params;

-  valid_params.push_back(_T("dumpapps"));

-  valid_params.push_back(_T("oneclick"));

-  valid_params.push_back(_T("monitor"));

-  valid_params.push_back(_T("file"));

-

-  for (int i = 0; i < parser.GetSwitchCount(); ++i) {

-    CString switch_name;

-    parser.GetSwitchNameAtIndex(i, &switch_name);

-    bool found = false;

-    for (size_t i = 0; i < valid_params.size(); ++i) {

-      const CString& valid_param = valid_params[i];

-      if (valid_param.Compare(switch_name) == 0) {

-        found = true;

-      }

-    }

-    if (!found) {

-      return E_INVALIDARG;

-    }

-  }

-

-  if (parser.HasSwitch(_T("file"))) {

-    int arg_count = 0;

-    parser.GetSwitchArgumentCount(_T("file"), &arg_count);

-    if (arg_count != 1) {

-      return E_INVALIDARG;

-    }

-    args->is_write_to_file = true;

-    parser.GetSwitchArgumentValue(_T("file"), 0, &(args->log_filename));

-  }

-

-  if (parser.GetSwitchCount() == 0 ||

-      (parser.HasSwitch(_T("file")) && parser.GetSwitchCount() == 1)) {

-    // If you don't pass anything, give them everything except monitoring.

-    args->is_dump_general = true;

-    args->is_dump_app_manager = true;

-    args->is_dump_oneclick = true;

-    args->is_machine = true;

-    args->is_user = true;

-  }

-

-  if (parser.HasSwitch(_T("dumpapps"))) {

-    args->is_dump_general = true;

-    args->is_dump_app_manager = true;

-    args->is_machine = true;

-    args->is_user = true;

-  }

-

-  if (parser.HasSwitch(_T("oneclick"))) {

-    args->is_dump_general = true;

-    args->is_dump_oneclick = true;

-    args->is_machine = true;

-    args->is_user = true;

-  }

-

-  if (parser.HasSwitch(_T("monitor"))) {

-    args->is_monitor = true;

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/tools/goopdump/goopdump_cmd_line_parser.h"
+
+#include "omaha/common/debug.h"
+#include "omaha/goopdate/command_line_parser.h"
+
+namespace omaha {
+
+HRESULT ParseGoopdumpCmdLine(int argc,
+                             TCHAR** argv,
+                             GoopdumpCmdLineArgs* args) {
+  ASSERT1(argc >= 1);
+  ASSERT1(argv);
+
+  UNREFERENCED_PARAMETER(argc);
+  UNREFERENCED_PARAMETER(argv);
+
+  CommandLineParser parser;
+  HRESULT hr = parser.ParseFromArgv(argc, argv);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  std::vector<CString> valid_params;
+  valid_params.push_back(_T("dumpapps"));
+  valid_params.push_back(_T("oneclick"));
+  valid_params.push_back(_T("monitor"));
+  valid_params.push_back(_T("file"));
+
+  for (int i = 0; i < parser.GetSwitchCount(); ++i) {
+    CString switch_name;
+    parser.GetSwitchNameAtIndex(i, &switch_name);
+    bool found = false;
+    for (size_t i = 0; i < valid_params.size(); ++i) {
+      const CString& valid_param = valid_params[i];
+      if (valid_param.Compare(switch_name) == 0) {
+        found = true;
+      }
+    }
+    if (!found) {
+      return E_INVALIDARG;
+    }
+  }
+
+  if (parser.HasSwitch(_T("file"))) {
+    int arg_count = 0;
+    parser.GetSwitchArgumentCount(_T("file"), &arg_count);
+    if (arg_count != 1) {
+      return E_INVALIDARG;
+    }
+    args->is_write_to_file = true;
+    parser.GetSwitchArgumentValue(_T("file"), 0, &(args->log_filename));
+  }
+
+  if (parser.GetSwitchCount() == 0 ||
+      (parser.HasSwitch(_T("file")) && parser.GetSwitchCount() == 1)) {
+    // If you don't pass anything, give them everything except monitoring.
+    args->is_dump_general = true;
+    args->is_dump_app_manager = true;
+    args->is_dump_oneclick = true;
+    args->is_machine = true;
+    args->is_user = true;
+  }
+
+  if (parser.HasSwitch(_T("dumpapps"))) {
+    args->is_dump_general = true;
+    args->is_dump_app_manager = true;
+    args->is_machine = true;
+    args->is_user = true;
+  }
+
+  if (parser.HasSwitch(_T("oneclick"))) {
+    args->is_dump_general = true;
+    args->is_dump_oneclick = true;
+    args->is_machine = true;
+    args->is_user = true;
+  }
+
+  if (parser.HasSwitch(_T("monitor"))) {
+    args->is_monitor = true;
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/goopdump_cmd_line_parser.h b/tools/goopdump/goopdump_cmd_line_parser.h
index b9ba33d..9610506 100644
--- a/tools/goopdump/goopdump_cmd_line_parser.h
+++ b/tools/goopdump/goopdump_cmd_line_parser.h
@@ -1,50 +1,50 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_CMD_LINE_PARSER_H_

-#define OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_CMD_LINE_PARSER_H_

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-struct GoopdumpCmdLineArgs {

-  GoopdumpCmdLineArgs()

-      : is_machine(false),

-        is_user(false),

-        is_monitor(false),

-        is_dump_app_manager(false),

-        is_dump_oneclick(false),

-        is_dump_general(false),

-        is_write_to_file(false) {}

-  bool is_machine;            // Display per-machine data.

-  bool is_user;               // Display per-user data (for current user only).

-  bool is_monitor;            // Is monitor mode (monitors real time activity).

-  bool is_dump_app_manager;   // Dump AppManager data.

-  bool is_dump_oneclick;      // Dump OneClick data.

-  bool is_dump_general;       // Dump general OS and Omaha data.

-  bool is_write_to_file;      // Dump data to file.

-  CString log_filename;       // Filename of log to write to.

-};

-

-HRESULT ParseGoopdumpCmdLine(int argc, TCHAR** argv, GoopdumpCmdLineArgs* args);

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_CMD_LINE_PARSER_H_

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_CMD_LINE_PARSER_H_
+#define OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_CMD_LINE_PARSER_H_
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+struct GoopdumpCmdLineArgs {
+  GoopdumpCmdLineArgs()
+      : is_machine(false),
+        is_user(false),
+        is_monitor(false),
+        is_dump_app_manager(false),
+        is_dump_oneclick(false),
+        is_dump_general(false),
+        is_write_to_file(false) {}
+  bool is_machine;            // Display per-machine data.
+  bool is_user;               // Display per-user data (for current user only).
+  bool is_monitor;            // Is monitor mode (monitors real time activity).
+  bool is_dump_app_manager;   // Dump AppManager data.
+  bool is_dump_oneclick;      // Dump OneClick data.
+  bool is_dump_general;       // Dump general OS and Omaha data.
+  bool is_write_to_file;      // Dump data to file.
+  CString log_filename;       // Filename of log to write to.
+};
+
+HRESULT ParseGoopdumpCmdLine(int argc, TCHAR** argv, GoopdumpCmdLineArgs* args);
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_GOOPDUMP_CMD_LINE_PARSER_H_
+
diff --git a/tools/goopdump/goopdump_main.cc b/tools/goopdump/goopdump_main.cc
index 1619c30..46ef78a 100644
--- a/tools/goopdump/goopdump_main.cc
+++ b/tools/goopdump/goopdump_main.cc
@@ -1,25 +1,25 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/goopdump.h"

-

-int _tmain(int argc, TCHAR** argv) {

-  UNREFERENCED_PARAMETER(argc);

-  UNREFERENCED_PARAMETER(argv);

-  return static_cast<int>(omaha::Goopdump().Main(::GetCommandLine(),

-                                                 argc,

-                                                 argv));

-}

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/goopdump.h"
+
+int _tmain(int argc, TCHAR** argv) {
+  UNREFERENCED_PARAMETER(argc);
+  UNREFERENCED_PARAMETER(argv);
+  return static_cast<int>(omaha::Goopdump().Main(::GetCommandLine(),
+                                                 argc,
+                                                 argv));
+}
+
diff --git a/tools/goopdump/process_commandline.cc b/tools/goopdump/process_commandline.cc
index ad312d4..62976f6 100644
--- a/tools/goopdump/process_commandline.cc
+++ b/tools/goopdump/process_commandline.cc
@@ -1,278 +1,278 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/process_commandline.h"

-

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/utils.h"

-

-namespace omaha {

-

-namespace {

-

-typedef const wchar_t* (__stdcall *GetCommandLineWFunc)();

-

-const DWORD kMaxInjectSize = 4096;

-const DWORD kCmdLineBufferSize = 2000;

-

-struct SharedBlock {

-  DWORD last_error;  // Last error from remote thread.

-  GetCommandLineWFunc get_commandline_w_ptr;  // Address of GetCommandLineW().

-  wchar_t cmd_line_buffer[kCmdLineBufferSize];  // The command line buffer.

-};

-

-// A number of assumptions are made:

-// * The target process is a Win32 process.

-// * Kernel32.dll is loaded at same address in each process (safe).

-// * InjectFunction() is shorter than kMaxInjectSize

-// * InjectFunction() does not rely on the C/C++ runtime.

-// * Compiler option /GZ is not used. (If it is, the compiler generates calls to

-//   functions which are not injected into the target.  The runtime_checks()

-//   pragma below removes this for debug builds which will have /GZ enabled by

-//   default.

-

-#pragma runtime_checks("", off)

-

-DWORD __stdcall InjectFunction(SharedBlock* shared_block) {

-  const wchar_t* source = shared_block->get_commandline_w_ptr();

-  wchar_t* target = &shared_block->cmd_line_buffer[0];

-  wchar_t* end = &shared_block->cmd_line_buffer[

-      arraysize(shared_block->cmd_line_buffer) - 1];

-  if (source == 0 || target == 0 || end == 0) {

-    shared_block->last_error = ERROR_INVALID_DATA;

-    return 0;

-  }

-

-  // This is effectively a wcscpy but we can't use library functions since this

-  // code will be injected into the target process space and we can't make

-  // assumptions about what's linked into that process.

-  for (; *source != 0 && target < end; ++source, ++target) {

-    *target = *source;

-  }

-

-  *target = 0;

-  shared_block->last_error = 0;

-

-  return 0;

-}

-

-#pragma runtime_checks("", restore)

-

-// Internal helper function to deal with the logic of injecting the

-// function/data into the process without the memory alloc/free since we don't

-// have smart pointers to handle VirtualAllocEx.

-HRESULT GetCommandLineFromHandleWithMemory(HANDLE process_handle,

-                                           void* function_memory,

-                                           SharedBlock* shared_block,

-                                           CString* command_line) {

-  ASSERT1(process_handle);

-  ASSERT1(function_memory);

-  ASSERT1(shared_block);

-

-  // Copy function into other process.

-  if (!::WriteProcessMemory(process_handle,

-                            function_memory,

-                            &InjectFunction,

-                            kMaxInjectSize,

-                            0)) {

-    return HRESULTFromLastError();

-  }

-

-  // Initialize data area for remote process.

-  scoped_library hmodule_kernel32(::LoadLibrary(L"kernel32.dll"));

-  if (!hmodule_kernel32) {

-    return HRESULTFromLastError();

-  }

-

-  SharedBlock shared_block_local;

-  shared_block_local.last_error = 0;

-  if (!GPA(get(hmodule_kernel32),

-           "GetCommandLineW",

-           &shared_block_local.get_commandline_w_ptr)) {

-    return HRESULTFromLastError();

-  }

-

-  shared_block_local.cmd_line_buffer[0] = L'\0';

-

-  if (!::WriteProcessMemory(process_handle,

-                            shared_block,

-                            &shared_block_local,

-                            sizeof(shared_block_local),

-                            0)) {

-    return HRESULTFromLastError();

-  }

-

-  // Create the remote thread.

-  scoped_handle remote_thread;

-  reset(remote_thread, ::CreateRemoteThread(

-      process_handle,

-      0,

-      0,

-      reinterpret_cast<LPTHREAD_START_ROUTINE>(function_memory),

-      shared_block,

-      0,

-      NULL));

-  if (!remote_thread) {

-    return HRESULTFromLastError();

-  }

-

-  const DWORD kWaitTimeoutMs = 3000;

-  DWORD wait_result = ::WaitForSingleObject(get(remote_thread), kWaitTimeoutMs);

-  switch (wait_result) {

-    case WAIT_TIMEOUT:

-      return HRESULT_FROM_WIN32(ERROR_TIMEOUT);

-    case WAIT_FAILED:

-      return HRESULTFromLastError();

-    case WAIT_OBJECT_0:

-      // This might just have worked, pick up the result.

-      if (!::ReadProcessMemory(process_handle,

-                               shared_block,

-                               &shared_block_local,

-                               sizeof(shared_block_local),

-                               0)) {

-        return HRESULTFromLastError();

-      }

-      if (shared_block_local.last_error == 0) {

-        *command_line = shared_block_local.cmd_line_buffer;

-      } else {

-        return HRESULT_FROM_WIN32(shared_block_local.last_error);

-      }

-      break;

-    default:

-      return HRESULTFromLastError();

-  }

-

-  return S_OK;

-}

-

-// Allocates memory in a remote process given the process handle.

-// Returns a block of memory for the function that will be injected and a block

-// of memory to store results in that we copy back out.

-HRESULT AllocateProcessMemory(HANDLE process_handle,

-                              void** function_memory,

-                              void** shared_block) {

-  ASSERT1(process_handle);

-  ASSERT1(function_memory);

-  ASSERT1(shared_block);

-

-  *function_memory = ::VirtualAllocEx(process_handle,

-                                      0,

-                                      kMaxInjectSize,

-                                      MEM_COMMIT,

-                                      PAGE_EXECUTE_READWRITE);

-  if (!(*function_memory)) {

-    return HRESULTFromLastError();

-  }

-

-  *shared_block = ::VirtualAllocEx(process_handle,

-                                  0,

-                                  sizeof(SharedBlock),

-                                  MEM_COMMIT,

-                                  PAGE_READWRITE);

-  if (!(*shared_block)) {

-    ::VirtualFreeEx(process_handle, *function_memory, 0, MEM_RELEASE);

-    *function_memory = NULL;

-    return HRESULTFromLastError();

-  }

-

-  return S_OK;

-}

-

-HRESULT GetCommandLineFromHandle(HANDLE process_handle, CString* command_line) {

-  ASSERT1(command_line);

-  ASSERT1(process_handle != NULL);

-

-  void* function_memory = NULL;

-  void* shared_block = NULL;

-

-  HRESULT hr = AllocateProcessMemory(process_handle,

-                                     &function_memory,

-                                     &shared_block);

-

-  if (SUCCEEDED(hr) && function_memory && shared_block) {

-    hr = GetCommandLineFromHandleWithMemory(

-        process_handle,

-        function_memory,

-        reinterpret_cast<SharedBlock*>(shared_block),

-        command_line);

-  }

-

-  if (function_memory) {

-    ::VirtualFreeEx(process_handle, function_memory, 0, MEM_RELEASE);

-    function_memory = NULL;

-  }

-

-  if (shared_block) {

-    ::VirtualFreeEx(process_handle, shared_block, 0, MEM_RELEASE);

-    shared_block = NULL;

-  }

-

-  return hr;

-}

-

-}  // namespace

-

-HRESULT GetProcessCommandLine(DWORD process_id, CString* command_line) {

-  ASSERT1(command_line);

-

-  EnableDebugPrivilege();

-  scoped_handle process_handle;

-  reset(process_handle, ::OpenProcess(PROCESS_CREATE_THREAD |

-                                      PROCESS_VM_OPERATION |

-                                      PROCESS_VM_WRITE |

-                                      PROCESS_VM_READ,

-                                      FALSE,

-                                      process_id));

-  if (!valid(process_handle)) {

-    return HRESULTFromLastError();

-  }

-  return GetCommandLineFromHandle(get(process_handle), command_line);

-}

-

-bool EnableDebugPrivilege() {

-  scoped_handle token;

-

-  if (!::OpenProcessToken(::GetCurrentProcess(),

-                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,

-                          address(token))) {

-    return false;

-  }

-

-  LUID se_debug_name_value = {0};

-  if (!::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &se_debug_name_value)) {

-    return false;

-  }

-

-  TOKEN_PRIVILEGES token_privs = {0};

-  token_privs.PrivilegeCount = 1;

-  token_privs.Privileges[0].Luid = se_debug_name_value;

-  token_privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

-

-  if (!::AdjustTokenPrivileges(get(token),

-                               FALSE,

-                               &token_privs,

-                               sizeof(token_privs),

-                               NULL,

-                               NULL)) {

-    return false;

-  }

-

-  return true;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/process_commandline.h"
+
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/utils.h"
+
+namespace omaha {
+
+namespace {
+
+typedef const wchar_t* (__stdcall *GetCommandLineWFunc)();
+
+const DWORD kMaxInjectSize = 4096;
+const DWORD kCmdLineBufferSize = 2000;
+
+struct SharedBlock {
+  DWORD last_error;  // Last error from remote thread.
+  GetCommandLineWFunc get_commandline_w_ptr;  // Address of GetCommandLineW().
+  wchar_t cmd_line_buffer[kCmdLineBufferSize];  // The command line buffer.
+};
+
+// A number of assumptions are made:
+// * The target process is a Win32 process.
+// * Kernel32.dll is loaded at same address in each process (safe).
+// * InjectFunction() is shorter than kMaxInjectSize
+// * InjectFunction() does not rely on the C/C++ runtime.
+// * Compiler option /GZ is not used. (If it is, the compiler generates calls to
+//   functions which are not injected into the target.  The runtime_checks()
+//   pragma below removes this for debug builds which will have /GZ enabled by
+//   default.
+
+#pragma runtime_checks("", off)
+
+DWORD __stdcall InjectFunction(SharedBlock* shared_block) {
+  const wchar_t* source = shared_block->get_commandline_w_ptr();
+  wchar_t* target = &shared_block->cmd_line_buffer[0];
+  wchar_t* end = &shared_block->cmd_line_buffer[
+      arraysize(shared_block->cmd_line_buffer) - 1];
+  if (source == 0 || target == 0 || end == 0) {
+    shared_block->last_error = ERROR_INVALID_DATA;
+    return 0;
+  }
+
+  // This is effectively a wcscpy but we can't use library functions since this
+  // code will be injected into the target process space and we can't make
+  // assumptions about what's linked into that process.
+  for (; *source != 0 && target < end; ++source, ++target) {
+    *target = *source;
+  }
+
+  *target = 0;
+  shared_block->last_error = 0;
+
+  return 0;
+}
+
+#pragma runtime_checks("", restore)
+
+// Internal helper function to deal with the logic of injecting the
+// function/data into the process without the memory alloc/free since we don't
+// have smart pointers to handle VirtualAllocEx.
+HRESULT GetCommandLineFromHandleWithMemory(HANDLE process_handle,
+                                           void* function_memory,
+                                           SharedBlock* shared_block,
+                                           CString* command_line) {
+  ASSERT1(process_handle);
+  ASSERT1(function_memory);
+  ASSERT1(shared_block);
+
+  // Copy function into other process.
+  if (!::WriteProcessMemory(process_handle,
+                            function_memory,
+                            &InjectFunction,
+                            kMaxInjectSize,
+                            0)) {
+    return HRESULTFromLastError();
+  }
+
+  // Initialize data area for remote process.
+  scoped_library hmodule_kernel32(::LoadLibrary(L"kernel32.dll"));
+  if (!hmodule_kernel32) {
+    return HRESULTFromLastError();
+  }
+
+  SharedBlock shared_block_local;
+  shared_block_local.last_error = 0;
+  if (!GPA(get(hmodule_kernel32),
+           "GetCommandLineW",
+           &shared_block_local.get_commandline_w_ptr)) {
+    return HRESULTFromLastError();
+  }
+
+  shared_block_local.cmd_line_buffer[0] = L'\0';
+
+  if (!::WriteProcessMemory(process_handle,
+                            shared_block,
+                            &shared_block_local,
+                            sizeof(shared_block_local),
+                            0)) {
+    return HRESULTFromLastError();
+  }
+
+  // Create the remote thread.
+  scoped_handle remote_thread;
+  reset(remote_thread, ::CreateRemoteThread(
+      process_handle,
+      0,
+      0,
+      reinterpret_cast<LPTHREAD_START_ROUTINE>(function_memory),
+      shared_block,
+      0,
+      NULL));
+  if (!remote_thread) {
+    return HRESULTFromLastError();
+  }
+
+  const DWORD kWaitTimeoutMs = 3000;
+  DWORD wait_result = ::WaitForSingleObject(get(remote_thread), kWaitTimeoutMs);
+  switch (wait_result) {
+    case WAIT_TIMEOUT:
+      return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
+    case WAIT_FAILED:
+      return HRESULTFromLastError();
+    case WAIT_OBJECT_0:
+      // This might just have worked, pick up the result.
+      if (!::ReadProcessMemory(process_handle,
+                               shared_block,
+                               &shared_block_local,
+                               sizeof(shared_block_local),
+                               0)) {
+        return HRESULTFromLastError();
+      }
+      if (shared_block_local.last_error == 0) {
+        *command_line = shared_block_local.cmd_line_buffer;
+      } else {
+        return HRESULT_FROM_WIN32(shared_block_local.last_error);
+      }
+      break;
+    default:
+      return HRESULTFromLastError();
+  }
+
+  return S_OK;
+}
+
+// Allocates memory in a remote process given the process handle.
+// Returns a block of memory for the function that will be injected and a block
+// of memory to store results in that we copy back out.
+HRESULT AllocateProcessMemory(HANDLE process_handle,
+                              void** function_memory,
+                              void** shared_block) {
+  ASSERT1(process_handle);
+  ASSERT1(function_memory);
+  ASSERT1(shared_block);
+
+  *function_memory = ::VirtualAllocEx(process_handle,
+                                      0,
+                                      kMaxInjectSize,
+                                      MEM_COMMIT,
+                                      PAGE_EXECUTE_READWRITE);
+  if (!(*function_memory)) {
+    return HRESULTFromLastError();
+  }
+
+  *shared_block = ::VirtualAllocEx(process_handle,
+                                  0,
+                                  sizeof(SharedBlock),
+                                  MEM_COMMIT,
+                                  PAGE_READWRITE);
+  if (!(*shared_block)) {
+    ::VirtualFreeEx(process_handle, *function_memory, 0, MEM_RELEASE);
+    *function_memory = NULL;
+    return HRESULTFromLastError();
+  }
+
+  return S_OK;
+}
+
+HRESULT GetCommandLineFromHandle(HANDLE process_handle, CString* command_line) {
+  ASSERT1(command_line);
+  ASSERT1(process_handle != NULL);
+
+  void* function_memory = NULL;
+  void* shared_block = NULL;
+
+  HRESULT hr = AllocateProcessMemory(process_handle,
+                                     &function_memory,
+                                     &shared_block);
+
+  if (SUCCEEDED(hr) && function_memory && shared_block) {
+    hr = GetCommandLineFromHandleWithMemory(
+        process_handle,
+        function_memory,
+        reinterpret_cast<SharedBlock*>(shared_block),
+        command_line);
+  }
+
+  if (function_memory) {
+    ::VirtualFreeEx(process_handle, function_memory, 0, MEM_RELEASE);
+    function_memory = NULL;
+  }
+
+  if (shared_block) {
+    ::VirtualFreeEx(process_handle, shared_block, 0, MEM_RELEASE);
+    shared_block = NULL;
+  }
+
+  return hr;
+}
+
+}  // namespace
+
+HRESULT GetProcessCommandLine(DWORD process_id, CString* command_line) {
+  ASSERT1(command_line);
+
+  EnableDebugPrivilege();
+  scoped_handle process_handle;
+  reset(process_handle, ::OpenProcess(PROCESS_CREATE_THREAD |
+                                      PROCESS_VM_OPERATION |
+                                      PROCESS_VM_WRITE |
+                                      PROCESS_VM_READ,
+                                      FALSE,
+                                      process_id));
+  if (!valid(process_handle)) {
+    return HRESULTFromLastError();
+  }
+  return GetCommandLineFromHandle(get(process_handle), command_line);
+}
+
+bool EnableDebugPrivilege() {
+  scoped_handle token;
+
+  if (!::OpenProcessToken(::GetCurrentProcess(),
+                          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+                          address(token))) {
+    return false;
+  }
+
+  LUID se_debug_name_value = {0};
+  if (!::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &se_debug_name_value)) {
+    return false;
+  }
+
+  TOKEN_PRIVILEGES token_privs = {0};
+  token_privs.PrivilegeCount = 1;
+  token_privs.Privileges[0].Luid = se_debug_name_value;
+  token_privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+  if (!::AdjustTokenPrivileges(get(token),
+                               FALSE,
+                               &token_privs,
+                               sizeof(token_privs),
+                               NULL,
+                               NULL)) {
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/process_commandline.h b/tools/goopdump/process_commandline.h
index 6d41a86..6bcb63e 100644
--- a/tools/goopdump/process_commandline.h
+++ b/tools/goopdump/process_commandline.h
@@ -1,36 +1,36 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Provides functionality to get the command line of a Win32 process given the

-// process ID.

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_COMMANDLINE_H__

-#define OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_COMMANDLINE_H__

-

-#include <windows.h>

-#include <atlstr.h>

-

-namespace omaha {

-

-// Given a Win32 process ID, returns the command line for that process.

-HRESULT GetProcessCommandLine(DWORD process_id, CString* command_line);

-

-// Enables SE_DEBUG_NAME privilege for the process.

-bool EnableDebugPrivilege();

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_COMMANDLINE_H__

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Provides functionality to get the command line of a Win32 process given the
+// process ID.
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_COMMANDLINE_H__
+#define OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_COMMANDLINE_H__
+
+#include <windows.h>
+#include <atlstr.h>
+
+namespace omaha {
+
+// Given a Win32 process ID, returns the command line for that process.
+HRESULT GetProcessCommandLine(DWORD process_id, CString* command_line);
+
+// Enables SE_DEBUG_NAME privilege for the process.
+bool EnableDebugPrivilege();
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_COMMANDLINE_H__
+
diff --git a/tools/goopdump/process_commandline_unittest.cc b/tools/goopdump/process_commandline_unittest.cc
index ee8ae5b..e605d38 100644
--- a/tools/goopdump/process_commandline_unittest.cc
+++ b/tools/goopdump/process_commandline_unittest.cc
@@ -1,57 +1,57 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/process_commandline.h"

-

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/system.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-TEST(GoopdumpProcessCommandLineTest, TestRunNotepad) {

-  // TODO(omaha): Can we use Process::GetCommandLine() instead of

-  // GetProcessCommandLine? Should be safer than injecting a thread and can

-  // be used in coverage builds.

-#ifdef COVERAGE_ENABLED

-  std::wcout << _T("\tTest does not run in coverage builds because the ")

-             << _T("instrumentation of InjectFunction results in references ")

-             << _T("to invalid memory locations in Notepad.exe.")

-             << std::endl;

-#else

-  TCHAR notepad_path[MAX_PATH] = {0};

-  TCHAR system_directory[MAX_PATH] = {0};

-  ::GetSystemDirectory(system_directory, arraysize(system_directory));

-  _stprintf_s(notepad_path,

-            arraysize(notepad_path),

-            _T("%s\\notepad.exe %s\\loadfix.com"),

-            system_directory, system_directory);

-

-  PROCESS_INFORMATION pi = {0};

-  EXPECT_SUCCEEDED(System::StartProcess(NULL, notepad_path, &pi));

-  ::CloseHandle(pi.hThread);

-  scoped_process process_handle(pi.hProcess);

-

-  CString command_line;

-  EXPECT_SUCCEEDED(GetProcessCommandLine(pi.dwProcessId, &command_line));

-

-  ::TerminateProcess(get(process_handle), 0);

-

-  EXPECT_STREQ(notepad_path, command_line);

-#endif

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/process_commandline.h"
+
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/system.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+TEST(GoopdumpProcessCommandLineTest, TestRunNotepad) {
+  // TODO(omaha): Can we use Process::GetCommandLine() instead of
+  // GetProcessCommandLine? Should be safer than injecting a thread and can
+  // be used in coverage builds.
+#ifdef COVERAGE_ENABLED
+  std::wcout << _T("\tTest does not run in coverage builds because the ")
+             << _T("instrumentation of InjectFunction results in references ")
+             << _T("to invalid memory locations in Notepad.exe.")
+             << std::endl;
+#else
+  TCHAR notepad_path[MAX_PATH] = {0};
+  TCHAR system_directory[MAX_PATH] = {0};
+  ::GetSystemDirectory(system_directory, arraysize(system_directory));
+  _stprintf_s(notepad_path,
+            arraysize(notepad_path),
+            _T("%s\\notepad.exe %s\\loadfix.com"),
+            system_directory, system_directory);
+
+  PROCESS_INFORMATION pi = {0};
+  EXPECT_SUCCEEDED(System::StartProcess(NULL, notepad_path, &pi));
+  ::CloseHandle(pi.hThread);
+  scoped_process process_handle(pi.hProcess);
+
+  CString command_line;
+  EXPECT_SUCCEEDED(GetProcessCommandLine(pi.dwProcessId, &command_line));
+
+  ::TerminateProcess(get(process_handle), 0);
+
+  EXPECT_STREQ(notepad_path, command_line);
+#endif
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/process_monitor.cc b/tools/goopdump/process_monitor.cc
index 552a274..031dc3d 100644
--- a/tools/goopdump/process_monitor.cc
+++ b/tools/goopdump/process_monitor.cc
@@ -1,234 +1,234 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/tools/goopdump/process_monitor.h"

-

-#include <tlhelp32.h>

-#include <map>

-#include <vector>

-

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/tools/goopdump/process_commandline.h"

-

-namespace omaha {

-

-ProcessMonitor::ProcessMonitor() : is_running_(false), callback_(NULL) {

-}

-

-ProcessMonitor::~ProcessMonitor() {

-}

-

-HRESULT ProcessMonitor::Start(ProcessMonitorCallbackInterface* callback,

-                              const TCHAR* process_name_pattern) {

-  std::vector<CString> patterns;

-  patterns.push_back(CString(process_name_pattern));

-  return StartWithPatterns(callback, patterns);

-}

-

-HRESULT ProcessMonitor::StartWithPatterns(

-    ProcessMonitorCallbackInterface* callback,

-    const std::vector<CString>& process_name_patterns) {

-  SingleLock lock(&lock_);

-

-  if (is_running_) {

-    return E_UNEXPECTED;

-  }

-

-  EnableDebugPrivilege();

-

-  std::vector<CString>::const_iterator it = process_name_patterns.begin();

-  for (; it != process_name_patterns.end(); ++it) {

-    CString pattern = *it;

-    pattern.MakeLower();

-    process_name_patterns_.push_back(pattern);

-  }

-

-  callback_ = callback;

-

-  reset(event_thread_exit_, ::CreateEvent(NULL, FALSE, FALSE, NULL));

-  if (!valid(event_thread_exit_)) {

-    return HRESULTFromLastError();

-  }

-

-  reset(monitor_thread_, ::CreateThread(NULL,

-                                        0,

-                                        &ProcessMonitor::MonitorThreadProc,

-                                        this,

-                                        0,

-                                        NULL));

-  if (!valid(monitor_thread_)) {

-    return HRESULTFromLastError();

-  }

-

-  is_running_ = true;

-  return S_OK;

-}

-

-HRESULT ProcessMonitor::Stop() {

-  SingleLock lock(&lock_);

-

-  if (!is_running_) {

-    return E_UNEXPECTED;

-  }

-

-  ::SetEvent(get(event_thread_exit_));

-  ::WaitForSingleObject(get(monitor_thread_), INFINITE);

-

-  is_running_ = false;

-  return S_OK;

-}

-

-DWORD ProcessMonitor::MonitorThreadProc(void* param) {

-  ProcessMonitor* monitor = static_cast<ProcessMonitor*>(param);

-  if (monitor) {

-    return monitor->MonitorProc();

-  }

-  return 1;

-}

-

-DWORD ProcessMonitor::MonitorProc() {

-  // 200ms idle between polling for process creation.

-  const DWORD kWaitTimeoutMs = 200;

-

-  MapHandleToDword map_handle_pid;

-  bool keep_running = true;

-

-  do {

-    size_t map_count = map_handle_pid.size();

-    size_t pids_to_monitor = (map_count < MAXIMUM_WAIT_OBJECTS) ?

-        map_count : MAXIMUM_WAIT_OBJECTS;

-

-    std::vector<HANDLE> handles;

-    handles.push_back(get(event_thread_exit_));

-

-    MapHandleToDwordIterator iter = map_handle_pid.begin();

-    for (; (iter != map_handle_pid.end()) && (handles.size() < pids_to_monitor);

-         ++iter) {

-      handles.push_back(iter->first);

-    }

-

-    DWORD wait_result = ::WaitForMultipleObjects(handles.size(),

-                                                 &handles.front(),

-                                                 FALSE,

-                                                 kWaitTimeoutMs);

-    if (wait_result < (WAIT_OBJECT_0 + handles.size())) {

-      HANDLE signalled = handles[wait_result - WAIT_OBJECT_0];

-

-      if (signalled == get(event_thread_exit_)) {

-        // We've been signalled to exit.

-        keep_running = false;

-      } else {

-        // One of the PIDs exited.

-        MapHandleToDwordIterator iter = map_handle_pid.begin();

-        for (; iter != map_handle_pid.end(); ++iter) {

-          if (iter->first == signalled) {

-            OnProcessRemoved(iter->second);

-            ::CloseHandle(iter->first);

-            map_handle_pid.erase(iter);

-            break;

-          }

-        }

-      }

-    } else if (wait_result == WAIT_TIMEOUT) {

-      // Our polling time is up.  Go look for running instances of the

-      // process we're monitoring and look for differences in the list of PIDs.

-      UpdateProcessList(&map_handle_pid);

-    } else {

-      // Some type of failure occurred.

-      keep_running = false;

-    }

-  } while (keep_running);

-

-  return 0;

-}

-

-void ProcessMonitor::CleanupHandleMap(MapHandleToDword* map_handle_pid) {

-  ASSERT1(map_handle_pid);

-  MapHandleToDwordIterator iter = map_handle_pid->begin();

-  for (; iter != map_handle_pid->end(); ++iter) {

-    ::CloseHandle(iter->first);

-  }

-  map_handle_pid->clear();

-}

-

-bool ProcessMonitor::UpdateProcessList(MapHandleToDword* map_handle_pid) {

-  ASSERT1(map_handle_pid);

-  scoped_handle process_snap;

-  reset(process_snap, ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));

-  if (!valid(process_snap)) {

-    return false;

-  }

-

-  PROCESSENTRY32 process_entry32 = {0};

-  process_entry32.dwSize = sizeof(PROCESSENTRY32);

-

-  if (!::Process32First(get(process_snap), &process_entry32)) {

-    return false;

-  }

-

-  do {

-    CString exe_file_name = process_entry32.szExeFile;

-    exe_file_name.MakeLower();

-

-    typedef std::vector<CString>::iterator VectorIterator;

-    VectorIterator pattern_iter = process_name_patterns_.begin();

-    for (; pattern_iter != process_name_patterns_.end(); ++pattern_iter) {

-      CString process_pattern = *pattern_iter;

-      if (exe_file_name.Find(process_pattern) >= 0) {

-        // We've found a match.  See if this ProcessID is already in our list

-        bool is_found = false;

-        MapHandleToDwordIterator iter = map_handle_pid->begin();

-        for (; iter != map_handle_pid->end(); ++iter) {

-          if (iter->second == process_entry32.th32ProcessID) {

-            is_found = true;

-            break;

-          }

-        }

-

-        if (!is_found) {

-          // Opening this handle and we'll give ownership of this HANDLE to

-          // map_handle_pid.

-          HANDLE process_handle = ::OpenProcess(PROCESS_ALL_ACCESS,

-                                                FALSE,

-                                                process_entry32.th32ProcessID);

-          if (process_handle) {

-            (*map_handle_pid)[process_handle] = process_entry32.th32ProcessID;

-            OnProcessAdded(process_entry32.th32ProcessID, process_pattern);

-          }

-        }

-      }

-    }

-  } while (::Process32Next(get(process_snap), &process_entry32));

-

-  return true;

-}

-

-void ProcessMonitor::OnProcessAdded(DWORD process_id,

-                                    const CString& process_pattern) {

-  if (callback_) {

-    callback_->OnProcessAdded(process_id, process_pattern);

-  }

-}

-

-void ProcessMonitor::OnProcessRemoved(DWORD process_id) {

-  if (callback_) {

-    callback_->OnProcessRemoved(process_id);

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/tools/goopdump/process_monitor.h"
+
+#include <tlhelp32.h>
+#include <map>
+#include <vector>
+
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/tools/goopdump/process_commandline.h"
+
+namespace omaha {
+
+ProcessMonitor::ProcessMonitor() : is_running_(false), callback_(NULL) {
+}
+
+ProcessMonitor::~ProcessMonitor() {
+}
+
+HRESULT ProcessMonitor::Start(ProcessMonitorCallbackInterface* callback,
+                              const TCHAR* process_name_pattern) {
+  std::vector<CString> patterns;
+  patterns.push_back(CString(process_name_pattern));
+  return StartWithPatterns(callback, patterns);
+}
+
+HRESULT ProcessMonitor::StartWithPatterns(
+    ProcessMonitorCallbackInterface* callback,
+    const std::vector<CString>& process_name_patterns) {
+  SingleLock lock(&lock_);
+
+  if (is_running_) {
+    return E_UNEXPECTED;
+  }
+
+  EnableDebugPrivilege();
+
+  std::vector<CString>::const_iterator it = process_name_patterns.begin();
+  for (; it != process_name_patterns.end(); ++it) {
+    CString pattern = *it;
+    pattern.MakeLower();
+    process_name_patterns_.push_back(pattern);
+  }
+
+  callback_ = callback;
+
+  reset(event_thread_exit_, ::CreateEvent(NULL, FALSE, FALSE, NULL));
+  if (!valid(event_thread_exit_)) {
+    return HRESULTFromLastError();
+  }
+
+  reset(monitor_thread_, ::CreateThread(NULL,
+                                        0,
+                                        &ProcessMonitor::MonitorThreadProc,
+                                        this,
+                                        0,
+                                        NULL));
+  if (!valid(monitor_thread_)) {
+    return HRESULTFromLastError();
+  }
+
+  is_running_ = true;
+  return S_OK;
+}
+
+HRESULT ProcessMonitor::Stop() {
+  SingleLock lock(&lock_);
+
+  if (!is_running_) {
+    return E_UNEXPECTED;
+  }
+
+  ::SetEvent(get(event_thread_exit_));
+  ::WaitForSingleObject(get(monitor_thread_), INFINITE);
+
+  is_running_ = false;
+  return S_OK;
+}
+
+DWORD ProcessMonitor::MonitorThreadProc(void* param) {
+  ProcessMonitor* monitor = static_cast<ProcessMonitor*>(param);
+  if (monitor) {
+    return monitor->MonitorProc();
+  }
+  return 1;
+}
+
+DWORD ProcessMonitor::MonitorProc() {
+  // 200ms idle between polling for process creation.
+  const DWORD kWaitTimeoutMs = 200;
+
+  MapHandleToDword map_handle_pid;
+  bool keep_running = true;
+
+  do {
+    size_t map_count = map_handle_pid.size();
+    size_t pids_to_monitor = (map_count < MAXIMUM_WAIT_OBJECTS) ?
+        map_count : MAXIMUM_WAIT_OBJECTS;
+
+    std::vector<HANDLE> handles;
+    handles.push_back(get(event_thread_exit_));
+
+    MapHandleToDwordIterator iter = map_handle_pid.begin();
+    for (; (iter != map_handle_pid.end()) && (handles.size() < pids_to_monitor);
+         ++iter) {
+      handles.push_back(iter->first);
+    }
+
+    DWORD wait_result = ::WaitForMultipleObjects(handles.size(),
+                                                 &handles.front(),
+                                                 FALSE,
+                                                 kWaitTimeoutMs);
+    if (wait_result < (WAIT_OBJECT_0 + handles.size())) {
+      HANDLE signalled = handles[wait_result - WAIT_OBJECT_0];
+
+      if (signalled == get(event_thread_exit_)) {
+        // We've been signalled to exit.
+        keep_running = false;
+      } else {
+        // One of the PIDs exited.
+        MapHandleToDwordIterator iter = map_handle_pid.begin();
+        for (; iter != map_handle_pid.end(); ++iter) {
+          if (iter->first == signalled) {
+            OnProcessRemoved(iter->second);
+            ::CloseHandle(iter->first);
+            map_handle_pid.erase(iter);
+            break;
+          }
+        }
+      }
+    } else if (wait_result == WAIT_TIMEOUT) {
+      // Our polling time is up.  Go look for running instances of the
+      // process we're monitoring and look for differences in the list of PIDs.
+      UpdateProcessList(&map_handle_pid);
+    } else {
+      // Some type of failure occurred.
+      keep_running = false;
+    }
+  } while (keep_running);
+
+  return 0;
+}
+
+void ProcessMonitor::CleanupHandleMap(MapHandleToDword* map_handle_pid) {
+  ASSERT1(map_handle_pid);
+  MapHandleToDwordIterator iter = map_handle_pid->begin();
+  for (; iter != map_handle_pid->end(); ++iter) {
+    ::CloseHandle(iter->first);
+  }
+  map_handle_pid->clear();
+}
+
+bool ProcessMonitor::UpdateProcessList(MapHandleToDword* map_handle_pid) {
+  ASSERT1(map_handle_pid);
+  scoped_handle process_snap;
+  reset(process_snap, ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
+  if (!valid(process_snap)) {
+    return false;
+  }
+
+  PROCESSENTRY32 process_entry32 = {0};
+  process_entry32.dwSize = sizeof(PROCESSENTRY32);
+
+  if (!::Process32First(get(process_snap), &process_entry32)) {
+    return false;
+  }
+
+  do {
+    CString exe_file_name = process_entry32.szExeFile;
+    exe_file_name.MakeLower();
+
+    typedef std::vector<CString>::iterator VectorIterator;
+    VectorIterator pattern_iter = process_name_patterns_.begin();
+    for (; pattern_iter != process_name_patterns_.end(); ++pattern_iter) {
+      CString process_pattern = *pattern_iter;
+      if (exe_file_name.Find(process_pattern) >= 0) {
+        // We've found a match.  See if this ProcessID is already in our list
+        bool is_found = false;
+        MapHandleToDwordIterator iter = map_handle_pid->begin();
+        for (; iter != map_handle_pid->end(); ++iter) {
+          if (iter->second == process_entry32.th32ProcessID) {
+            is_found = true;
+            break;
+          }
+        }
+
+        if (!is_found) {
+          // Opening this handle and we'll give ownership of this HANDLE to
+          // map_handle_pid.
+          HANDLE process_handle = ::OpenProcess(PROCESS_ALL_ACCESS,
+                                                FALSE,
+                                                process_entry32.th32ProcessID);
+          if (process_handle) {
+            (*map_handle_pid)[process_handle] = process_entry32.th32ProcessID;
+            OnProcessAdded(process_entry32.th32ProcessID, process_pattern);
+          }
+        }
+      }
+    }
+  } while (::Process32Next(get(process_snap), &process_entry32));
+
+  return true;
+}
+
+void ProcessMonitor::OnProcessAdded(DWORD process_id,
+                                    const CString& process_pattern) {
+  if (callback_) {
+    callback_->OnProcessAdded(process_id, process_pattern);
+  }
+}
+
+void ProcessMonitor::OnProcessRemoved(DWORD process_id) {
+  if (callback_) {
+    callback_->OnProcessRemoved(process_id);
+  }
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/process_monitor.h b/tools/goopdump/process_monitor.h
index 2d8f159..154a4e7 100644
--- a/tools/goopdump/process_monitor.h
+++ b/tools/goopdump/process_monitor.h
@@ -1,110 +1,110 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Provides a class (ProcessMonitor) to watch for Win32 process names and fire

-// callback events (via the ProcessMonitorCallbackInterface) when processes are

-// created/exited.

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_MONITOR_H__

-#define OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_MONITOR_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <map>

-#include <vector>

-

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/synchronized.h"

-

-namespace omaha {

-

-// Interface for users of the ProcessMonitor class to receive events when a

-// process matching their desired pattern is created or exits.

-class ProcessMonitorCallbackInterface {

- public:

-  ProcessMonitorCallbackInterface() {}

-  virtual ~ProcessMonitorCallbackInterface() {}

-

-  // Called when a new process is found that matches the pattern.  The pattern

-  // that matched is passed in as process_pattern.

-  virtual void OnProcessAdded(DWORD process_id,

-                              const CString& process_pattern) = 0;

-

-  // Called when a process that was previously found has exited.

-  virtual void OnProcessRemoved(DWORD process_id) = 0;

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(ProcessMonitorCallbackInterface);

-};

-

-// This class creates a thread to monitor running processes for particular

-// process names.  Fires events via ProcessMonitorCallbackInterface when a new

-// process is detected that matches a name pattern and also when those processes

-// exit.

-// This class uses polling to look for the processes since the only way to get

-// event notification of process creation is to create a driver.

-class ProcessMonitor {

- public:

-  typedef std::map<HANDLE, DWORD> MapHandleToDword;

-  typedef MapHandleToDword::iterator MapHandleToDwordIterator;

-

-  ProcessMonitor();

-  ~ProcessMonitor();

-

-  // Starts the monitoring process to look for processes that match

-  // process_name_pattern and fire events via the callback.

-  HRESULT Start(ProcessMonitorCallbackInterface* callback,

-                const TCHAR* process_name_pattern);

-

-  // Starts the monitoring process with multiple patterns.

-  HRESULT StartWithPatterns(ProcessMonitorCallbackInterface* callback,

-                            const std::vector<CString>& process_name_patterns);

-

-  // Stops the monitoring process and cleans up.

-  HRESULT Stop();

-

- private:

-  // Thread procedure for monitoring the processes in the background.

-  static DWORD WINAPI MonitorThreadProc(void* param);

-  DWORD MonitorProc();

-

-  // Called when a process matching the process is found.

-  void OnProcessAdded(DWORD process_id, const CString& process_pattern);

-

-  // Called when a previously added process exits.

-  void OnProcessRemoved(DWORD process_id);

-

-  // Walks the active process list to look for matches against the pattern.  If

-  // a process is found to match that's not in the list, it's added to the map

-  // and OnProcessAdded() is called.

-  bool UpdateProcessList(MapHandleToDword* map_handle_pid);

-

-  // Walks through the map and calls CloseHandle() on each handle in the list.

-  void CleanupHandleMap(MapHandleToDword* map_handle_pid);

-

-  bool is_running_;   // Set to true while the process monitoring is running.

-  ProcessMonitorCallbackInterface* callback_;   // Event callback interface.

-  std::vector<CString> process_name_patterns_;  // List of patterns to match.

-  CriticalSection lock_;              // Protects is_running_ flag.

-  scoped_handle event_thread_exit_;   // Signal to exit monitor_thread_.

-  scoped_handle monitor_thread_;      // Handle to the monitoring thread.

-

-  DISALLOW_EVIL_CONSTRUCTORS(ProcessMonitor);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_MONITOR_H__

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Provides a class (ProcessMonitor) to watch for Win32 process names and fire
+// callback events (via the ProcessMonitorCallbackInterface) when processes are
+// created/exited.
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_MONITOR_H__
+#define OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_MONITOR_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <map>
+#include <vector>
+
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/synchronized.h"
+
+namespace omaha {
+
+// Interface for users of the ProcessMonitor class to receive events when a
+// process matching their desired pattern is created or exits.
+class ProcessMonitorCallbackInterface {
+ public:
+  ProcessMonitorCallbackInterface() {}
+  virtual ~ProcessMonitorCallbackInterface() {}
+
+  // Called when a new process is found that matches the pattern.  The pattern
+  // that matched is passed in as process_pattern.
+  virtual void OnProcessAdded(DWORD process_id,
+                              const CString& process_pattern) = 0;
+
+  // Called when a process that was previously found has exited.
+  virtual void OnProcessRemoved(DWORD process_id) = 0;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(ProcessMonitorCallbackInterface);
+};
+
+// This class creates a thread to monitor running processes for particular
+// process names.  Fires events via ProcessMonitorCallbackInterface when a new
+// process is detected that matches a name pattern and also when those processes
+// exit.
+// This class uses polling to look for the processes since the only way to get
+// event notification of process creation is to create a driver.
+class ProcessMonitor {
+ public:
+  typedef std::map<HANDLE, DWORD> MapHandleToDword;
+  typedef MapHandleToDword::iterator MapHandleToDwordIterator;
+
+  ProcessMonitor();
+  ~ProcessMonitor();
+
+  // Starts the monitoring process to look for processes that match
+  // process_name_pattern and fire events via the callback.
+  HRESULT Start(ProcessMonitorCallbackInterface* callback,
+                const TCHAR* process_name_pattern);
+
+  // Starts the monitoring process with multiple patterns.
+  HRESULT StartWithPatterns(ProcessMonitorCallbackInterface* callback,
+                            const std::vector<CString>& process_name_patterns);
+
+  // Stops the monitoring process and cleans up.
+  HRESULT Stop();
+
+ private:
+  // Thread procedure for monitoring the processes in the background.
+  static DWORD WINAPI MonitorThreadProc(void* param);
+  DWORD MonitorProc();
+
+  // Called when a process matching the process is found.
+  void OnProcessAdded(DWORD process_id, const CString& process_pattern);
+
+  // Called when a previously added process exits.
+  void OnProcessRemoved(DWORD process_id);
+
+  // Walks the active process list to look for matches against the pattern.  If
+  // a process is found to match that's not in the list, it's added to the map
+  // and OnProcessAdded() is called.
+  bool UpdateProcessList(MapHandleToDword* map_handle_pid);
+
+  // Walks through the map and calls CloseHandle() on each handle in the list.
+  void CleanupHandleMap(MapHandleToDword* map_handle_pid);
+
+  bool is_running_;   // Set to true while the process monitoring is running.
+  ProcessMonitorCallbackInterface* callback_;   // Event callback interface.
+  std::vector<CString> process_name_patterns_;  // List of patterns to match.
+  CriticalSection lock_;              // Protects is_running_ flag.
+  scoped_handle event_thread_exit_;   // Signal to exit monitor_thread_.
+  scoped_handle monitor_thread_;      // Handle to the monitoring thread.
+
+  DISALLOW_EVIL_CONSTRUCTORS(ProcessMonitor);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_PROCESS_MONITOR_H__
+
diff --git a/tools/goopdump/process_monitor_unittest.cc b/tools/goopdump/process_monitor_unittest.cc
index 55d6de4..6f99bc4 100644
--- a/tools/goopdump/process_monitor_unittest.cc
+++ b/tools/goopdump/process_monitor_unittest.cc
@@ -1,123 +1,123 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <vector>

-

-#include "omaha/common/system.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/tools/goopdump/process_monitor.h"

-

-namespace omaha {

-

-// TODO(omaha): use gMock.

-class MockProcessMonitorCallback : public ProcessMonitorCallbackInterface {

- public:

-  MockProcessMonitorCallback()

-    : num_times_onprocessadded_called_(0),

-      num_times_onprocessremoved_called_(0) {}

-  virtual ~MockProcessMonitorCallback() {}

-

-  virtual void OnProcessAdded(DWORD process_id,

-                              const CString& process_pattern) {

-    ++num_times_onprocessadded_called_;

-    process_ids_added_.push_back(process_id);

-    process_patterns_added_.push_back(process_pattern);

-  }

-

-  virtual void OnProcessRemoved(DWORD process_id) {

-    ++num_times_onprocessremoved_called_;

-    process_ids_removed_.push_back(process_id);

-  }

-

-  int num_times_onprocessadded_called() const {

-    return num_times_onprocessadded_called_;

-  }

-

-  int num_times_onprocessremoved_called() const {

-    return num_times_onprocessremoved_called_;

-  }

-

- private:

-  int num_times_onprocessadded_called_;

-  int num_times_onprocessremoved_called_;

-

-  std::vector<CString> process_patterns_added_;

-  std::vector<DWORD> process_ids_added_;

-  std::vector<DWORD> process_ids_removed_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(MockProcessMonitorCallback);

-};

-

-TEST(GoopdumpProcessMonitorTest, TestStartStopNoop) {

-  ProcessMonitor process_monitor;

-  EXPECT_SUCCEEDED(process_monitor.Start(NULL, _T("some_noop_process.exe")));

-  EXPECT_SUCCEEDED(process_monitor.Stop());

-}

-

-TEST(GoopdumpProcessMonitorTest, TestStartStopNoopPatterns) {

-  ProcessMonitor process_monitor;

-  std::vector<CString> patterns;

-  patterns.push_back(CString(_T("some_noop_process")));

-  patterns.push_back(CString(_T("this_process")));

-  patterns.push_back(CString(_T("that_process")));

-  EXPECT_SUCCEEDED(process_monitor.StartWithPatterns(NULL, patterns));

-  EXPECT_SUCCEEDED(process_monitor.Stop());

-}

-

-TEST(GoopdumpProcessMonitorTest, TestStartStopNoopWithCallback) {

-  ProcessMonitor process_monitor;

-  MockProcessMonitorCallback callback;

-  EXPECT_SUCCEEDED(process_monitor.Start(&callback,

-                                         _T("some_noop_process.exe")));

-  EXPECT_SUCCEEDED(process_monitor.Stop());

-

-  EXPECT_EQ(0, callback.num_times_onprocessadded_called());

-  EXPECT_EQ(0, callback.num_times_onprocessremoved_called());

-}

-

-TEST(GoopdumpProcessMonitorTest, TestStartStopNotepadWithCallback) {

-  ProcessMonitor process_monitor;

-  MockProcessMonitorCallback callback;

-  EXPECT_SUCCEEDED(process_monitor.Start(&callback,

-                                         _T("notepad.exe")));

-  TCHAR notepad_path[MAX_PATH] = {0};

-  TCHAR system_directory[MAX_PATH] = {0};

-  ::GetSystemDirectory(system_directory, arraysize(system_directory));

-  _stprintf(notepad_path,

-            arraysize(notepad_path),

-            _T("%s\\notepad.exe"),

-            system_directory);

-

-  PROCESS_INFORMATION pi = {0};

-  System::StartProcess(NULL, notepad_path, &pi);

-  ::CloseHandle(pi.hThread);

-  scoped_process process_handle(pi.hProcess);

-

-  // Have to sleep since we're polling for process start/exit.

-  // In order to get notified of process start we have to write a driver.

-  ::Sleep(500);

-

-  ::TerminateProcess(get(process_handle), 0);

-

-  ::Sleep(500);

-

-  EXPECT_SUCCEEDED(process_monitor.Stop());

-

-  EXPECT_EQ(1, callback.num_times_onprocessadded_called());

-  EXPECT_EQ(1, callback.num_times_onprocessremoved_called());

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <vector>
+
+#include "omaha/common/system.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/tools/goopdump/process_monitor.h"
+
+namespace omaha {
+
+// TODO(omaha): use gMock.
+class MockProcessMonitorCallback : public ProcessMonitorCallbackInterface {
+ public:
+  MockProcessMonitorCallback()
+    : num_times_onprocessadded_called_(0),
+      num_times_onprocessremoved_called_(0) {}
+  virtual ~MockProcessMonitorCallback() {}
+
+  virtual void OnProcessAdded(DWORD process_id,
+                              const CString& process_pattern) {
+    ++num_times_onprocessadded_called_;
+    process_ids_added_.push_back(process_id);
+    process_patterns_added_.push_back(process_pattern);
+  }
+
+  virtual void OnProcessRemoved(DWORD process_id) {
+    ++num_times_onprocessremoved_called_;
+    process_ids_removed_.push_back(process_id);
+  }
+
+  int num_times_onprocessadded_called() const {
+    return num_times_onprocessadded_called_;
+  }
+
+  int num_times_onprocessremoved_called() const {
+    return num_times_onprocessremoved_called_;
+  }
+
+ private:
+  int num_times_onprocessadded_called_;
+  int num_times_onprocessremoved_called_;
+
+  std::vector<CString> process_patterns_added_;
+  std::vector<DWORD> process_ids_added_;
+  std::vector<DWORD> process_ids_removed_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(MockProcessMonitorCallback);
+};
+
+TEST(GoopdumpProcessMonitorTest, TestStartStopNoop) {
+  ProcessMonitor process_monitor;
+  EXPECT_SUCCEEDED(process_monitor.Start(NULL, _T("some_noop_process.exe")));
+  EXPECT_SUCCEEDED(process_monitor.Stop());
+}
+
+TEST(GoopdumpProcessMonitorTest, TestStartStopNoopPatterns) {
+  ProcessMonitor process_monitor;
+  std::vector<CString> patterns;
+  patterns.push_back(CString(_T("some_noop_process")));
+  patterns.push_back(CString(_T("this_process")));
+  patterns.push_back(CString(_T("that_process")));
+  EXPECT_SUCCEEDED(process_monitor.StartWithPatterns(NULL, patterns));
+  EXPECT_SUCCEEDED(process_monitor.Stop());
+}
+
+TEST(GoopdumpProcessMonitorTest, TestStartStopNoopWithCallback) {
+  ProcessMonitor process_monitor;
+  MockProcessMonitorCallback callback;
+  EXPECT_SUCCEEDED(process_monitor.Start(&callback,
+                                         _T("some_noop_process.exe")));
+  EXPECT_SUCCEEDED(process_monitor.Stop());
+
+  EXPECT_EQ(0, callback.num_times_onprocessadded_called());
+  EXPECT_EQ(0, callback.num_times_onprocessremoved_called());
+}
+
+TEST(GoopdumpProcessMonitorTest, TestStartStopNotepadWithCallback) {
+  ProcessMonitor process_monitor;
+  MockProcessMonitorCallback callback;
+  EXPECT_SUCCEEDED(process_monitor.Start(&callback,
+                                         _T("notepad.exe")));
+  TCHAR notepad_path[MAX_PATH] = {0};
+  TCHAR system_directory[MAX_PATH] = {0};
+  ::GetSystemDirectory(system_directory, arraysize(system_directory));
+  _stprintf(notepad_path,
+            arraysize(notepad_path),
+            _T("%s\\notepad.exe"),
+            system_directory);
+
+  PROCESS_INFORMATION pi = {0};
+  System::StartProcess(NULL, notepad_path, &pi);
+  ::CloseHandle(pi.hThread);
+  scoped_process process_handle(pi.hProcess);
+
+  // Have to sleep since we're polling for process start/exit.
+  // In order to get notified of process start we have to write a driver.
+  ::Sleep(500);
+
+  ::TerminateProcess(get(process_handle), 0);
+
+  ::Sleep(500);
+
+  EXPECT_SUCCEEDED(process_monitor.Stop());
+
+  EXPECT_EQ(1, callback.num_times_onprocessadded_called());
+  EXPECT_EQ(1, callback.num_times_onprocessremoved_called());
+}
+
+}  // namespace omaha
+
diff --git a/tools/goopdump/resource.h b/tools/goopdump/resource.h
index 6422ebe..f2e91f0 100644
--- a/tools/goopdump/resource.h
+++ b/tools/goopdump/resource.h
@@ -1,22 +1,22 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Symbol definitions for the Goopdump EXE resources.

-

-#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_RESOURCE_H__

-#define OMAHA_TOOLS_SRC_GOOPDUMP_RESOURCE_H__

-

-#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_RESOURCE_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Symbol definitions for the Goopdump EXE resources.
+
+#ifndef OMAHA_TOOLS_SRC_GOOPDUMP_RESOURCE_H__
+#define OMAHA_TOOLS_SRC_GOOPDUMP_RESOURCE_H__
+
+#endif  // OMAHA_TOOLS_SRC_GOOPDUMP_RESOURCE_H__
+
diff --git a/tools/goopdump/resource.rc b/tools/goopdump/resource.rc
index d6b5d9d..9ab0c41 100644
--- a/tools/goopdump/resource.rc
+++ b/tools/goopdump/resource.rc
@@ -1,59 +1,59 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Goopdump resource file.

-

-#include <afxres.h>

-

-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

-

-VS_VERSION_INFO VERSIONINFO

- FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH

- FILEFLAGSMASK 0x3FL

- FILEFLAGS 0x0L

- FILEOS 0x4L

- FILETYPE 0x0L

- FILESUBTYPE 0x0L

-BEGIN

-    BLOCK "StringFileInfo"

-    BEGIN

-        BLOCK "040904e4"

-        BEGIN

-            VALUE "CompanyName", "Google Inc."

-            VALUE "FileDescription", "Goopdump"

-            VALUE "FileVersion", VERSION_NUMBER_STRING

-            VALUE "InternalName", "Goopdump"

-            VALUE "LegalCopyright", "Copyright 2008 Google Inc."

-            VALUE "OriginalFilename", "Goopdump"

-            VALUE "ProductName", "Goopdump"

-            VALUE "ProductVersion", VERSION_NUMBER_STRING

-#ifdef _DEBUG

-            VALUE "Debug", ""

-#endif

-#if !OFFICIAL_BUILD

-            VALUE "Privatebuild", ""

-#endif

-

-        END

-    END

-    BLOCK "VarFileInfo"

-    BEGIN

-        VALUE "Translation", 0x409, 1252

-    END

-END

-

-

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Goopdump resource file.
+
+#include <afxres.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD,VERSION_PATCH
+ FILEFLAGSMASK 0x3FL
+ FILEFLAGS 0x0L
+ FILEOS 0x4L
+ FILETYPE 0x0L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "CompanyName", "Google Inc."
+            VALUE "FileDescription", "Goopdump"
+            VALUE "FileVersion", VERSION_NUMBER_STRING
+            VALUE "InternalName", "Goopdump"
+            VALUE "LegalCopyright", "Copyright 2008 Google Inc."
+            VALUE "OriginalFilename", "Goopdump"
+            VALUE "ProductName", "Goopdump"
+            VALUE "ProductVersion", VERSION_NUMBER_STRING
+#ifdef _DEBUG
+            VALUE "Debug", ""
+#endif
+#if !OFFICIAL_BUILD
+            VALUE "Privatebuild", ""
+#endif
+
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252
+    END
+END
+
+
+
diff --git a/tools/longrunning/build.scons b/tools/longrunning/build.scons
index 067a868..633e0d4 100644
--- a/tools/longrunning/build.scons
+++ b/tools/longrunning/build.scons
@@ -1,69 +1,69 @@
-#!/usr/bin/python2.4

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-# Builds two versions of LongRunning. LongRunning.exe is a console app and will

-# result in a console windows when run. LongRunningSilent.exe uses the Windows

-# subsystem so that it does not throw up windows. It is useful for unit tests.

-# There is a resource file, so that we can include a manifest that tells Windows

-# Vista not to elevate this file. We need this when it is renamed to

-# GoogleUpdate.exe for unit tests.

-

-Import('env')

-

-inputs = [

-    'long_running.cc',

-    env.RES('run_as_invoker.res', '$MAIN_DIR/common/run_as_invoker.rc'),

-    ]

-

-base_env = env.Clone()

-

-base_env.Append(

-    LIBS = [

-        ('libcmt.lib', 'libcmtd.lib')[base_env.Bit('debug')],

-        ],

-    CPPDEFINES = [

-        'UNICODE',

-        '_UNICODE'

-        ],

-)

-

-if base_env.Bit('debug'):

-  base_env.FilterOut(CCFLAGS=['/MTd'])

-else:

-  base_env.FilterOut(CCFLAGS=['/MT'])

-

-# Duplicate the common settings then set the unique settings for each build.

-silent_env = base_env.Clone()

-

-# Use different subdirectory to avoid having 2 obj files with the same name.

-silent_env['OBJPREFIX'] = 'silent/' + silent_env['OBJPREFIX']

-

-silent_env.ComponentProgram(

-    prog_name='LongRunningSilent.exe',

-    source=inputs,

-)

-

-

-base_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-base_env['LINKFLAGS'] += [

-    '/SUBSYSTEM:CONSOLE',

-    '/ENTRY:WinMain',

-    ]

-

-base_env.ComponentProgram(

-    prog_name='LongRunning.exe',

-    source=inputs

-)

+#!/usr/bin/python2.4
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+# Builds two versions of LongRunning. LongRunning.exe is a console app and will
+# result in a console windows when run. LongRunningSilent.exe uses the Windows
+# subsystem so that it does not throw up windows. It is useful for unit tests.
+# There is a resource file, so that we can include a manifest that tells Windows
+# Vista not to elevate this file. We need this when it is renamed to
+# GoogleUpdate.exe for unit tests.
+
+Import('env')
+
+inputs = [
+    'long_running.cc',
+    env.RES('run_as_invoker.res', '$MAIN_DIR/common/run_as_invoker.rc'),
+    ]
+
+base_env = env.Clone()
+
+base_env.Append(
+    LIBS = [
+        ('libcmt.lib', 'libcmtd.lib')[base_env.Bit('debug')],
+        ],
+    CPPDEFINES = [
+        'UNICODE',
+        '_UNICODE'
+        ],
+)
+
+if base_env.Bit('debug'):
+  base_env.FilterOut(CCFLAGS=['/MTd'])
+else:
+  base_env.FilterOut(CCFLAGS=['/MT'])
+
+# Duplicate the common settings then set the unique settings for each build.
+silent_env = base_env.Clone()
+
+# Use different subdirectory to avoid having 2 obj files with the same name.
+silent_env['OBJPREFIX'] = 'silent/' + silent_env['OBJPREFIX']
+
+silent_env.ComponentProgram(
+    prog_name='LongRunningSilent.exe',
+    source=inputs,
+)
+
+
+base_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+base_env['LINKFLAGS'] += [
+    '/SUBSYSTEM:CONSOLE',
+    '/ENTRY:WinMain',
+    ]
+
+base_env.ComponentProgram(
+    prog_name='LongRunning.exe',
+    source=inputs
+)
diff --git a/tools/longrunning/long_running.cc b/tools/longrunning/long_running.cc
index d4d8adf..cd13dec 100644
--- a/tools/longrunning/long_running.cc
+++ b/tools/longrunning/long_running.cc
@@ -1,28 +1,28 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Do nothing executable. Sleeps infinitely.

-

-#pragma check_stack(off)

-#pragma runtime_checks("", off)

-#include <windows.h>

-

-int __stdcall WinMain(HINSTANCE,

-                      HINSTANCE,

-                      LPSTR,

-                      int) {

-  ::SleepEx(INFINITE, FALSE);

-  return 0;

-}

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Do nothing executable. Sleeps infinitely.
+
+#pragma check_stack(off)
+#pragma runtime_checks("", off)
+#include <windows.h>
+
+int __stdcall WinMain(HINSTANCE,
+                      HINSTANCE,
+                      LPSTR,
+                      int) {
+  ::SleepEx(INFINITE, FALSE);
+  return 0;
+}
diff --git a/tools/performondemand/build.scons b/tools/performondemand/build.scons
index 654928c..05910f3 100644
--- a/tools/performondemand/build.scons
+++ b/tools/performondemand/build.scons
@@ -1,76 +1,76 @@
-#!/usr/bin/python2.4

-#

-# Copyright 2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-

-Import('env')

-

-

-local_env = env.Clone()

-local_env.Append(

-    CPPDEFINES = [

-        'UNICODE',

-        '_UNICODE'

-        ],

-    CPPPATH = [

-        '$OBJ_ROOT',

-        ],

-    LIBS = [

-        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],

-        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],

-        ('libcpmt.lib', 'libcpmtd.lib')[local_env.Bit('debug')],

-        'comctl32.lib',

-        'crypt32.lib',

-        'Iphlpapi.lib',

-        'mstask.lib',

-        'netapi32.lib',

-        'psapi.lib',

-        'rasapi32.lib',

-        'shlwapi.lib',

-        'urlmon.lib',

-        'userenv.lib',

-        'version.lib',

-        'wininet.lib',

-        'wtsapi32.lib',

-

-        '$LIB_DIR/common.lib',

-        '$LIB_DIR/goopdate_dll.lib',

-        '$LIB_DIR/logging.lib',

-        '$LIB_DIR/net.lib',

-        '$LIB_DIR/statsreport.lib',

-        ],

-)

-

-local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])

-local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']

-

-no_precomp_env = local_env.Clone()

-idl_obj = no_precomp_env.ComponentObject(

-    source='$OBJ_ROOT/goopdate/google_update_idl_i.c')

-

-target_name = 'performondemand.exe'

-

-inputs = [

-    'performondemand.cc',

-    idl_obj,

-    ]

-if env.Bit('use_precompiled_headers'):

-  inputs += local_env.EnablePrecompile(target_name)

-

-local_env.ComponentProgram(

-    prog_name=target_name,

-    source=inputs,

-)

+#!/usr/bin/python2.4
+#
+# Copyright 2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+
+Import('env')
+
+
+local_env = env.Clone()
+local_env.Append(
+    CPPDEFINES = [
+        'UNICODE',
+        '_UNICODE'
+        ],
+    CPPPATH = [
+        '$OBJ_ROOT',
+        ],
+    LIBS = [
+        ('atls.lib', 'atlsd.lib')[local_env.Bit('debug')],
+        ('libcmt.lib', 'libcmtd.lib')[local_env.Bit('debug')],
+        ('libcpmt.lib', 'libcpmtd.lib')[local_env.Bit('debug')],
+        'comctl32.lib',
+        'crypt32.lib',
+        'Iphlpapi.lib',
+        'mstask.lib',
+        'netapi32.lib',
+        'psapi.lib',
+        'rasapi32.lib',
+        'shlwapi.lib',
+        'urlmon.lib',
+        'userenv.lib',
+        'version.lib',
+        'wininet.lib',
+        'wtsapi32.lib',
+
+        '$LIB_DIR/common.lib',
+        '$LIB_DIR/goopdate_dll.lib',
+        '$LIB_DIR/logging.lib',
+        '$LIB_DIR/net.lib',
+        '$LIB_DIR/statsreport.lib',
+        ],
+)
+
+local_env.FilterOut(LINKFLAGS = ['/SUBSYSTEM:WINDOWS'])
+local_env['LINKFLAGS'] += ['/SUBSYSTEM:CONSOLE']
+
+no_precomp_env = local_env.Clone()
+idl_obj = no_precomp_env.ComponentObject(
+    source='$OBJ_ROOT/goopdate/google_update_idl_i.c')
+
+target_name = 'performondemand.exe'
+
+inputs = [
+    'performondemand.cc',
+    idl_obj,
+    ]
+if env.Bit('use_precompiled_headers'):
+  inputs += local_env.EnablePrecompile(target_name)
+
+local_env.ComponentProgram(
+    prog_name=target_name,
+    source=inputs,
+)
diff --git a/tools/performondemand/performondemand.cc b/tools/performondemand/performondemand.cc
index c2a68d4..01baa03 100644
--- a/tools/performondemand/performondemand.cc
+++ b/tools/performondemand/performondemand.cc
@@ -1,377 +1,377 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// A simple tool for performing and interacting with on demand updates.

-#include "performondemand.h"

-#include <windows.h>

-#include <sddl.h>

-#include <shlobj.h>

-#include <atltime.h>

-#include <tchar.h>

-#include "omaha/common/system.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-

-namespace omaha {

-

-bool ParseParams(int argc, TCHAR* argv[], CString* guid, bool* is_machine,

-                 bool* is_update_check_only, int* timeout) {

-  ASSERT1(argv);

-  ASSERT1(guid);

-  ASSERT1(is_machine);

-  ASSERT1(is_update_check_only);

-  ASSERT1(timeout);

-  if (argc < 3 || argc > 5) {

-    return false;

-  }

-  *guid = argv[1];

-

-  // Verify that the guid is valid.

-  GUID parsed = StringToGuid(*guid);

-  if (parsed == GUID_NULL) {

-    return false;

-  }

-

-  *is_machine = !!_ttoi(argv[2]);

-

-  if (argc >= 4) {

-    *is_update_check_only = !!_ttoi(argv[3]);

-  } else {

-    *is_update_check_only = false;

-  }

-

-  if (argc >= 5) {

-    *timeout = _ttoi(argv[4]);

-    if (*timeout == 0) {

-      return false;

-    }

-  } else {

-    *timeout = 60;

-  }

-

-  return true;

-}

-

-

-DWORD SetTokenIntegrityLevelMedium(HANDLE token) {

-  PSID medium_sid = NULL;

-  if (!::ConvertStringSidToSid(SDDL_ML_MEDIUM, &medium_sid)) {

-    return ::GetLastError();

-  }

-

-  TOKEN_MANDATORY_LABEL label = {0};

-  label.Label.Attributes = SE_GROUP_INTEGRITY;

-  label.Label.Sid = medium_sid;

-

-  size_t size = sizeof(TOKEN_MANDATORY_LABEL) + ::GetLengthSid(medium_sid);

-  BOOL success = ::SetTokenInformation(token, TokenIntegrityLevel, &label,

-                                      size);

-  DWORD result = success ? ERROR_SUCCESS : ::GetLastError();

-  ::LocalFree(medium_sid);

-  return result;

-}

-

-// Reads the Proxy information for the given interface from HKCU, and registers

-// it with COM.

-HRESULT RegisterHKCUPSClsid(IID iid,

-                            HMODULE* proxy_module,

-                            DWORD* revoke_cookie) {

-  ASSERT1(proxy_module);

-  ASSERT1(revoke_cookie);

-  *proxy_module = NULL;

-  *revoke_cookie = 0;

-

-  const TCHAR* const hkcu_classes_key = _T("HKCU\\Software\\Classes\\");

-

-  // Get the registered proxy for the interface.

-  CString interface_proxy_clsid_key;

-  interface_proxy_clsid_key.Format(_T("%sInterface\\%s\\ProxyStubClsid32"),

-                                   hkcu_classes_key, GuidToString(iid));

-  CString proxy_clsid32_value;

-  HRESULT hr = RegKey::GetValue(interface_proxy_clsid_key,

-                        NULL,

-                        &proxy_clsid32_value);

-  if (FAILED(hr)) {

-    wprintf(_T("RegKey::GetValue failed [%s][0x%x]\n"),

-            interface_proxy_clsid_key, hr);

-    return hr;

-  }

-

-  // Get the location of the proxy/stub DLL.

-  CString proxy_server32_entry;

-  proxy_server32_entry.Format(_T("%sClsid\\%s\\InprocServer32"),

-                              hkcu_classes_key, proxy_clsid32_value);

-  CString hkcu_proxy_dll_path;

-  hr = RegKey::GetValue(proxy_server32_entry,

-                        NULL,

-                        &hkcu_proxy_dll_path);

-  if (FAILED(hr)) {

-    wprintf(_T("RegKey::GetValue failed [%s][0x%x]\n"),

-            proxy_server32_entry, hr);

-    return hr;

-  }

-

-  // Get the proxy/stub class object.

-  typedef HRESULT (STDAPICALLTYPE *DllGetClassObjectTypedef)(REFCLSID clsid,

-                                                             REFIID iid,

-                                                             void** ptr);

-  *proxy_module = ::LoadLibrary(hkcu_proxy_dll_path);

-  DllGetClassObjectTypedef fn = NULL;

-  if (!GPA(*proxy_module, "DllGetClassObject", &fn)) {

-    hr = HRESULT_FROM_WIN32(::GetLastError());

-    wprintf(_T("GetProcAddress DllGetClassObject failed [0x%x]\n"), hr);

-    return hr;

-  }

-  CComPtr<IPSFactoryBuffer> fb;

-  CLSID proxy_clsid = StringToGuid(proxy_clsid32_value);

-  hr = (*fn)(proxy_clsid, IID_IPSFactoryBuffer, reinterpret_cast<void**>(&fb));

-  if (FAILED(hr)) {

-    wprintf(_T("DllGetClassObject failed [0x%x]\n"), hr);

-    return hr;

-  }

-

-  // Register the proxy/stub class object.

-  hr = ::CoRegisterClassObject(proxy_clsid, fb, CLSCTX_INPROC_SERVER,

-                               REGCLS_MULTIPLEUSE, revoke_cookie);

-  if (FAILED(hr)) {

-    wprintf(_T("CoRegisterClassObject failed [0x%x]\n"), hr);

-    return hr;

-  }

-

-  // Relate the interface with the proxy/stub, so COM does not do a lookup when

-  // unmarshaling the interface.

-  hr = ::CoRegisterPSClsid(iid, proxy_clsid);

-  if (FAILED(hr)) {

-    wprintf(_T("CoRegisterPSClsid failed [0x%x]\n"), hr);

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// A helper class for clients of the Omaha on-demand out-of-proc COM server.

-// An instance of this class is typically created on the stack. The class does

-// nothing for cases where the OS is not Vista RTM with UAC off.

-// This class does the following:

-// * Calls CoInitializeSecurity with cloaking set to dynamic. This makes COM

-//   use the thread token instead of the process token.

-// * Impersonates and sets the thread token to medium integrity. This allows for

-//   out-of-proc HKCU COM server activation.

-// * Reads and registers per-user proxies for the interfaces that on-demand

-//   exposes.

-class VistaProxyRegistrar {

- public:

-  VistaProxyRegistrar()

-      : googleupdate_cookie_(0),

-        jobobserver_cookie_(0),

-        progresswndevents_cookie_(0),

-        is_impersonated(false) {

-    HRESULT hr = VistaProxyRegistrarImpl();

-    if (FAILED(hr)) {

-      wprintf(_T("VistaProxyRegistrarImpl failed [0x%x]\n"), hr);

-    }

-  }

-

-  ~VistaProxyRegistrar() {

-    if (googleupdate_cookie_) {

-      VERIFY1(SUCCEEDED(::CoRevokeClassObject(googleupdate_cookie_)));

-    }

-

-    if (jobobserver_cookie_) {

-      VERIFY1(SUCCEEDED(::CoRevokeClassObject(jobobserver_cookie_)));

-    }

-

-    if (progresswndevents_cookie_) {

-      VERIFY1(SUCCEEDED(::CoRevokeClassObject(progresswndevents_cookie_)));

-    }

-

-    if (is_impersonated) {

-      VERIFY1(::RevertToSelf());

-    }

-  }

-

- private:

-  HRESULT VistaProxyRegistrarImpl() {

-    if (!SystemInfo::IsRunningOnVistaRTM() ||

-        vista_util::IsUserRunningSplitToken() ||

-        !::IsUserAnAdmin()) {

-      return S_OK;

-    }

-

-    // Needs to be called very early on in a process.

-    // Turn on dynamic cloaking so COM picks up the impersonated thread token.

-    HRESULT hr = ::CoInitializeSecurity(

-        NULL,

-        -1,

-        NULL,

-        NULL,

-        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,

-        RPC_C_IMP_LEVEL_IDENTIFY,

-        NULL,

-        EOAC_DYNAMIC_CLOAKING,

-        NULL);

-    if (FAILED(hr)) {

-      wprintf(_T("[CoInitializeSecurity failed][0x%x]"), hr);

-      return hr;

-    }

-

-    is_impersonated = !!::ImpersonateSelf(SecurityImpersonation);

-    if (!is_impersonated) {

-      hr = HRESULT_FROM_WIN32(::GetLastError());

-      wprintf(_T("[main: ImpersonateSelf failed][0x%x]"), hr);

-      return hr;

-    }

-

-    scoped_handle thread_token;

-    if (!::OpenThreadToken(::GetCurrentThread(),

-                           TOKEN_ALL_ACCESS,

-                           false,

-                           address(thread_token))) {

-      hr = HRESULT_FROM_WIN32(::GetLastError());

-      wprintf(_T("[main: OpenThreadToken failed][0x%x]"), hr);

-      return hr;

-    }

-

-    DWORD result = SetTokenIntegrityLevelMedium(get(thread_token));

-    if (result != ERROR_SUCCESS) {

-      wprintf(_T("[main: SetTokenIntegrityLevelMedium failed][0x%x]"), result);

-      return HRESULT_FROM_WIN32(result);

-    }

-

-    hr = RegisterHKCUPSClsid(__uuidof(IGoogleUpdate),

-                             address(googleupdate_library_),

-                             &googleupdate_cookie_);

-    if (FAILED(hr)) {

-      wprintf(_T("RegisterHKCUPSClsid for IGoogleUpdate failed [0x%x]\n"), hr);

-      return hr;

-    }

-

-    hr = RegisterHKCUPSClsid(__uuidof(IJobObserver),

-                             address(jobobserver_library_),

-                             &jobobserver_cookie_);

-    if (FAILED(hr)) {

-      wprintf(_T("RegisterHKCUPSClsid for IJobObserver failed [0x%x]\n"), hr);

-      return hr;

-    }

-

-    hr = RegisterHKCUPSClsid(__uuidof(IProgressWndEvents),

-                             address(progresswndevents_library_),

-                             &progresswndevents_cookie_);

-    if (FAILED(hr)) {

-      wprintf(_T("RegisterHKCUPSClsid for IProgressWndEvents failed [0x%x]\n"),

-              hr);

-      return hr;

-    }

-

-    return S_OK;

-  }

-

- private:

-  scoped_library googleupdate_library_;

-  scoped_library jobobserver_library_;

-  scoped_library progresswndevents_library_;

-

-  DWORD googleupdate_cookie_;

-  DWORD jobobserver_cookie_;

-  DWORD progresswndevents_cookie_;

-  bool is_impersonated;

-};

-

-int DoMain(int argc, TCHAR* argv[]) {

-  CString guid;

-  bool is_machine = false;

-  bool is_update_check_only = false;

-  int timeout = 60;

-  if (!ParseParams(argc, argv, &guid, &is_machine,

-                   &is_update_check_only, &timeout)) {

-    wprintf(_T("Usage: performondemand.exe {GUID} {is_machine: 0|1} ")

-            _T("[is_update_check_only=0] [timeout=60]\n"));

-    return -1;

-  }

-  wprintf(_T("GUID: %s\n"), guid);

-  CComModule module;

-  scoped_co_init com_apt;

-  VistaProxyRegistrar registrar;

-

-  CComObject<JobObserver>* job_observer;

-  HRESULT hr = CComObject<JobObserver>::CreateInstance(&job_observer);

-  if (!SUCCEEDED(hr)) {

-    wprintf(_T("CComObject<JobObserver>::CreateInstance failed [0x%x]\n"), hr);

-    return -1;

-  }

-  CComPtr<IJobObserver> job_holder(job_observer);

-

-  CComPtr<IGoogleUpdate> on_demand;

-  if (is_machine && !is_update_check_only) {

-    hr = System::CoCreateInstanceAsAdmin(NULL,

-                                         __uuidof(OnDemandMachineAppsClass),

-                                         __uuidof(on_demand),

-                                         reinterpret_cast<void**>(&on_demand));

-  } else {

-    hr = on_demand.CoCreateInstance(is_machine ?

-                                    __uuidof(OnDemandMachineAppsClass) :

-                                    __uuidof(OnDemandUserAppsClass));

-  }

-

-  if (!SUCCEEDED(hr)) {

-    wprintf(_T("Could not create COM instance [0x%x]\n"), hr);

-    return -1;

-  }

-

-  if (is_update_check_only) {

-    hr = on_demand->CheckForUpdate(guid, job_observer);

-  } else {

-    hr = on_demand->Update(guid, job_observer);

-  }

-

-  if (!SUCCEEDED(hr)) {

-    wprintf(_T("on_demand->%sUpdate failed [0x%x]\n"),

-            is_update_check_only ? _T("CheckFor") : _T(""), hr);

-    return -1;

-  }

-

-  // Main message loop:

-  MSG msg;

-  SYSTEMTIME start_system_time = {0};

-  SYSTEMTIME current_system_time = {0};

-  ::GetSystemTime(&start_system_time);

-  CTime start_time(start_system_time);

-  CTimeSpan timeout_period(0, 0, 0, timeout);

-

-  while (::GetMessage(&msg, NULL, 0, 0)) {

-    ::TranslateMessage(&msg);

-    ::DispatchMessage(&msg);

-    ::GetSystemTime(&current_system_time);

-    CTime current_time(current_system_time);

-    CTimeSpan elapsed_time = current_time - start_time;

-    if (timeout_period < elapsed_time) {

-      wprintf(_T("Timed out.\n"));

-      // TODO(omaha): Right now the timeout does correctly break, but then

-      // the COM interactions continue on to completion.

-      break;

-    }

-  }

-  int ret_val = job_observer->observed;

-

-  return ret_val;

-}

-

-}  // namespace omaha

-

-int _tmain(int argc, TCHAR* argv[]) {

-  return omaha::DoMain(argc, argv);

-}

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// A simple tool for performing and interacting with on demand updates.
+#include "performondemand.h"
+#include <windows.h>
+#include <sddl.h>
+#include <shlobj.h>
+#include <atltime.h>
+#include <tchar.h>
+#include "omaha/common/system.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+
+namespace omaha {
+
+bool ParseParams(int argc, TCHAR* argv[], CString* guid, bool* is_machine,
+                 bool* is_update_check_only, int* timeout) {
+  ASSERT1(argv);
+  ASSERT1(guid);
+  ASSERT1(is_machine);
+  ASSERT1(is_update_check_only);
+  ASSERT1(timeout);
+  if (argc < 3 || argc > 5) {
+    return false;
+  }
+  *guid = argv[1];
+
+  // Verify that the guid is valid.
+  GUID parsed = StringToGuid(*guid);
+  if (parsed == GUID_NULL) {
+    return false;
+  }
+
+  *is_machine = !!_ttoi(argv[2]);
+
+  if (argc >= 4) {
+    *is_update_check_only = !!_ttoi(argv[3]);
+  } else {
+    *is_update_check_only = false;
+  }
+
+  if (argc >= 5) {
+    *timeout = _ttoi(argv[4]);
+    if (*timeout == 0) {
+      return false;
+    }
+  } else {
+    *timeout = 60;
+  }
+
+  return true;
+}
+
+
+DWORD SetTokenIntegrityLevelMedium(HANDLE token) {
+  PSID medium_sid = NULL;
+  if (!::ConvertStringSidToSid(SDDL_ML_MEDIUM, &medium_sid)) {
+    return ::GetLastError();
+  }
+
+  TOKEN_MANDATORY_LABEL label = {0};
+  label.Label.Attributes = SE_GROUP_INTEGRITY;
+  label.Label.Sid = medium_sid;
+
+  size_t size = sizeof(TOKEN_MANDATORY_LABEL) + ::GetLengthSid(medium_sid);
+  BOOL success = ::SetTokenInformation(token, TokenIntegrityLevel, &label,
+                                      size);
+  DWORD result = success ? ERROR_SUCCESS : ::GetLastError();
+  ::LocalFree(medium_sid);
+  return result;
+}
+
+// Reads the Proxy information for the given interface from HKCU, and registers
+// it with COM.
+HRESULT RegisterHKCUPSClsid(IID iid,
+                            HMODULE* proxy_module,
+                            DWORD* revoke_cookie) {
+  ASSERT1(proxy_module);
+  ASSERT1(revoke_cookie);
+  *proxy_module = NULL;
+  *revoke_cookie = 0;
+
+  const TCHAR* const hkcu_classes_key = _T("HKCU\\Software\\Classes\\");
+
+  // Get the registered proxy for the interface.
+  CString interface_proxy_clsid_key;
+  interface_proxy_clsid_key.Format(_T("%sInterface\\%s\\ProxyStubClsid32"),
+                                   hkcu_classes_key, GuidToString(iid));
+  CString proxy_clsid32_value;
+  HRESULT hr = RegKey::GetValue(interface_proxy_clsid_key,
+                        NULL,
+                        &proxy_clsid32_value);
+  if (FAILED(hr)) {
+    wprintf(_T("RegKey::GetValue failed [%s][0x%x]\n"),
+            interface_proxy_clsid_key, hr);
+    return hr;
+  }
+
+  // Get the location of the proxy/stub DLL.
+  CString proxy_server32_entry;
+  proxy_server32_entry.Format(_T("%sClsid\\%s\\InprocServer32"),
+                              hkcu_classes_key, proxy_clsid32_value);
+  CString hkcu_proxy_dll_path;
+  hr = RegKey::GetValue(proxy_server32_entry,
+                        NULL,
+                        &hkcu_proxy_dll_path);
+  if (FAILED(hr)) {
+    wprintf(_T("RegKey::GetValue failed [%s][0x%x]\n"),
+            proxy_server32_entry, hr);
+    return hr;
+  }
+
+  // Get the proxy/stub class object.
+  typedef HRESULT (STDAPICALLTYPE *DllGetClassObjectTypedef)(REFCLSID clsid,
+                                                             REFIID iid,
+                                                             void** ptr);
+  *proxy_module = ::LoadLibrary(hkcu_proxy_dll_path);
+  DllGetClassObjectTypedef fn = NULL;
+  if (!GPA(*proxy_module, "DllGetClassObject", &fn)) {
+    hr = HRESULT_FROM_WIN32(::GetLastError());
+    wprintf(_T("GetProcAddress DllGetClassObject failed [0x%x]\n"), hr);
+    return hr;
+  }
+  CComPtr<IPSFactoryBuffer> fb;
+  CLSID proxy_clsid = StringToGuid(proxy_clsid32_value);
+  hr = (*fn)(proxy_clsid, IID_IPSFactoryBuffer, reinterpret_cast<void**>(&fb));
+  if (FAILED(hr)) {
+    wprintf(_T("DllGetClassObject failed [0x%x]\n"), hr);
+    return hr;
+  }
+
+  // Register the proxy/stub class object.
+  hr = ::CoRegisterClassObject(proxy_clsid, fb, CLSCTX_INPROC_SERVER,
+                               REGCLS_MULTIPLEUSE, revoke_cookie);
+  if (FAILED(hr)) {
+    wprintf(_T("CoRegisterClassObject failed [0x%x]\n"), hr);
+    return hr;
+  }
+
+  // Relate the interface with the proxy/stub, so COM does not do a lookup when
+  // unmarshaling the interface.
+  hr = ::CoRegisterPSClsid(iid, proxy_clsid);
+  if (FAILED(hr)) {
+    wprintf(_T("CoRegisterPSClsid failed [0x%x]\n"), hr);
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// A helper class for clients of the Omaha on-demand out-of-proc COM server.
+// An instance of this class is typically created on the stack. The class does
+// nothing for cases where the OS is not Vista RTM with UAC off.
+// This class does the following:
+// * Calls CoInitializeSecurity with cloaking set to dynamic. This makes COM
+//   use the thread token instead of the process token.
+// * Impersonates and sets the thread token to medium integrity. This allows for
+//   out-of-proc HKCU COM server activation.
+// * Reads and registers per-user proxies for the interfaces that on-demand
+//   exposes.
+class VistaProxyRegistrar {
+ public:
+  VistaProxyRegistrar()
+      : googleupdate_cookie_(0),
+        jobobserver_cookie_(0),
+        progresswndevents_cookie_(0),
+        is_impersonated(false) {
+    HRESULT hr = VistaProxyRegistrarImpl();
+    if (FAILED(hr)) {
+      wprintf(_T("VistaProxyRegistrarImpl failed [0x%x]\n"), hr);
+    }
+  }
+
+  ~VistaProxyRegistrar() {
+    if (googleupdate_cookie_) {
+      VERIFY1(SUCCEEDED(::CoRevokeClassObject(googleupdate_cookie_)));
+    }
+
+    if (jobobserver_cookie_) {
+      VERIFY1(SUCCEEDED(::CoRevokeClassObject(jobobserver_cookie_)));
+    }
+
+    if (progresswndevents_cookie_) {
+      VERIFY1(SUCCEEDED(::CoRevokeClassObject(progresswndevents_cookie_)));
+    }
+
+    if (is_impersonated) {
+      VERIFY1(::RevertToSelf());
+    }
+  }
+
+ private:
+  HRESULT VistaProxyRegistrarImpl() {
+    if (!SystemInfo::IsRunningOnVistaRTM() ||
+        vista_util::IsUserRunningSplitToken() ||
+        !::IsUserAnAdmin()) {
+      return S_OK;
+    }
+
+    // Needs to be called very early on in a process.
+    // Turn on dynamic cloaking so COM picks up the impersonated thread token.
+    HRESULT hr = ::CoInitializeSecurity(
+        NULL,
+        -1,
+        NULL,
+        NULL,
+        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+        RPC_C_IMP_LEVEL_IDENTIFY,
+        NULL,
+        EOAC_DYNAMIC_CLOAKING,
+        NULL);
+    if (FAILED(hr)) {
+      wprintf(_T("[CoInitializeSecurity failed][0x%x]"), hr);
+      return hr;
+    }
+
+    is_impersonated = !!::ImpersonateSelf(SecurityImpersonation);
+    if (!is_impersonated) {
+      hr = HRESULT_FROM_WIN32(::GetLastError());
+      wprintf(_T("[main: ImpersonateSelf failed][0x%x]"), hr);
+      return hr;
+    }
+
+    scoped_handle thread_token;
+    if (!::OpenThreadToken(::GetCurrentThread(),
+                           TOKEN_ALL_ACCESS,
+                           false,
+                           address(thread_token))) {
+      hr = HRESULT_FROM_WIN32(::GetLastError());
+      wprintf(_T("[main: OpenThreadToken failed][0x%x]"), hr);
+      return hr;
+    }
+
+    DWORD result = SetTokenIntegrityLevelMedium(get(thread_token));
+    if (result != ERROR_SUCCESS) {
+      wprintf(_T("[main: SetTokenIntegrityLevelMedium failed][0x%x]"), result);
+      return HRESULT_FROM_WIN32(result);
+    }
+
+    hr = RegisterHKCUPSClsid(__uuidof(IGoogleUpdate),
+                             address(googleupdate_library_),
+                             &googleupdate_cookie_);
+    if (FAILED(hr)) {
+      wprintf(_T("RegisterHKCUPSClsid for IGoogleUpdate failed [0x%x]\n"), hr);
+      return hr;
+    }
+
+    hr = RegisterHKCUPSClsid(__uuidof(IJobObserver),
+                             address(jobobserver_library_),
+                             &jobobserver_cookie_);
+    if (FAILED(hr)) {
+      wprintf(_T("RegisterHKCUPSClsid for IJobObserver failed [0x%x]\n"), hr);
+      return hr;
+    }
+
+    hr = RegisterHKCUPSClsid(__uuidof(IProgressWndEvents),
+                             address(progresswndevents_library_),
+                             &progresswndevents_cookie_);
+    if (FAILED(hr)) {
+      wprintf(_T("RegisterHKCUPSClsid for IProgressWndEvents failed [0x%x]\n"),
+              hr);
+      return hr;
+    }
+
+    return S_OK;
+  }
+
+ private:
+  scoped_library googleupdate_library_;
+  scoped_library jobobserver_library_;
+  scoped_library progresswndevents_library_;
+
+  DWORD googleupdate_cookie_;
+  DWORD jobobserver_cookie_;
+  DWORD progresswndevents_cookie_;
+  bool is_impersonated;
+};
+
+int DoMain(int argc, TCHAR* argv[]) {
+  CString guid;
+  bool is_machine = false;
+  bool is_update_check_only = false;
+  int timeout = 60;
+  if (!ParseParams(argc, argv, &guid, &is_machine,
+                   &is_update_check_only, &timeout)) {
+    wprintf(_T("Usage: performondemand.exe {GUID} {is_machine: 0|1} ")
+            _T("[is_update_check_only=0] [timeout=60]\n"));
+    return -1;
+  }
+  wprintf(_T("GUID: %s\n"), guid);
+  CComModule module;
+  scoped_co_init com_apt;
+  VistaProxyRegistrar registrar;
+
+  CComObject<JobObserver>* job_observer;
+  HRESULT hr = CComObject<JobObserver>::CreateInstance(&job_observer);
+  if (!SUCCEEDED(hr)) {
+    wprintf(_T("CComObject<JobObserver>::CreateInstance failed [0x%x]\n"), hr);
+    return -1;
+  }
+  CComPtr<IJobObserver> job_holder(job_observer);
+
+  CComPtr<IGoogleUpdate> on_demand;
+  if (is_machine && !is_update_check_only) {
+    hr = System::CoCreateInstanceAsAdmin(NULL,
+                                         __uuidof(OnDemandMachineAppsClass),
+                                         __uuidof(on_demand),
+                                         reinterpret_cast<void**>(&on_demand));
+  } else {
+    hr = on_demand.CoCreateInstance(is_machine ?
+                                    __uuidof(OnDemandMachineAppsClass) :
+                                    __uuidof(OnDemandUserAppsClass));
+  }
+
+  if (!SUCCEEDED(hr)) {
+    wprintf(_T("Could not create COM instance [0x%x]\n"), hr);
+    return -1;
+  }
+
+  if (is_update_check_only) {
+    hr = on_demand->CheckForUpdate(guid, job_observer);
+  } else {
+    hr = on_demand->Update(guid, job_observer);
+  }
+
+  if (!SUCCEEDED(hr)) {
+    wprintf(_T("on_demand->%sUpdate failed [0x%x]\n"),
+            is_update_check_only ? _T("CheckFor") : _T(""), hr);
+    return -1;
+  }
+
+  // Main message loop:
+  MSG msg;
+  SYSTEMTIME start_system_time = {0};
+  SYSTEMTIME current_system_time = {0};
+  ::GetSystemTime(&start_system_time);
+  CTime start_time(start_system_time);
+  CTimeSpan timeout_period(0, 0, 0, timeout);
+
+  while (::GetMessage(&msg, NULL, 0, 0)) {
+    ::TranslateMessage(&msg);
+    ::DispatchMessage(&msg);
+    ::GetSystemTime(&current_system_time);
+    CTime current_time(current_system_time);
+    CTimeSpan elapsed_time = current_time - start_time;
+    if (timeout_period < elapsed_time) {
+      wprintf(_T("Timed out.\n"));
+      // TODO(omaha): Right now the timeout does correctly break, but then
+      // the COM interactions continue on to completion.
+      break;
+    }
+  }
+  int ret_val = job_observer->observed;
+
+  return ret_val;
+}
+
+}  // namespace omaha
+
+int _tmain(int argc, TCHAR* argv[]) {
+  return omaha::DoMain(argc, argv);
+}
+
diff --git a/tools/performondemand/performondemand.h b/tools/performondemand/performondemand.h
index ea7fec9..595d83f 100644
--- a/tools/performondemand/performondemand.h
+++ b/tools/performondemand/performondemand.h
@@ -1,189 +1,189 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_TOOLS_SRC_PERFORMONDEMAND_PERFORMONDEMAND_H_

-#define OMAHA_TOOLS_SRC_PERFORMONDEMAND_PERFORMONDEMAND_H_

-

-#pragma once

-#include <windows.h>

-#include <atlbase.h>

-#include <atlcom.h>

-#include "goopdate\google_update_idl.h"  // NOLINT

-

-// Keep this list syncronized with qa\client\lib\on_demand_lib.py

-#define ON_COMPLETE_SUCCESS                           0x00000001

-#define ON_COMPLETE_SUCCESS_CLOSE_UI                  0x00000002

-#define ON_COMPLETE_ERROR                             0x00000004

-#define ON_COMPLETE_RESTART_ALL_BROWSERS              0x00000008

-#define ON_COMPLETE_REBOOT                            0x00000010

-#define ON_SHOW                                       0x00000020

-#define ON_CHECKING_FOR_UPDATES                       0x00000040

-#define ON_UPDATE_AVAILABLE                           0x00000080

-#define ON_WAITING_TO_DOWNLOAD                        0x00000100

-#define ON_DOWNLOADING                                0x00000200

-#define ON_WAITING_TO_INSTALL                         0x00000400

-#define ON_INSTALLING                                 0x00000800

-#define ON_PAUSE                                      0x00001000

-#define SET_EVENT_SINK                                0x00002000

-#define ON_COMPLETE_RESTART_BROWSER                   0x00004000

-#define ON_COMPLETE_RESTART_ALL_BROWSERS_NOTICE_ONLY  0x00008000

-#define ON_COMPLETE_REBOOT_NOTICE_ONLY                0x00010000

-#define ON_COMPLETE_RESTART_BROWSER_NOTICE_ONLY       0x00020000

-#define ON_COMPLETE_RUN_COMMAND                       0x00040000

-

-class JobObserver

-  : public CComObjectRootEx<CComSingleThreadModel>,

-    public IJobObserver {

- public:

-  BEGIN_COM_MAP(JobObserver)

-    COM_INTERFACE_ENTRY(IJobObserver)

-  END_COM_MAP()

-

-  // Each interaction enables a bit in observed, which is eventually returned as

-  // a return code.

-  int observed;

-

-  // Similar to observed, misbehave_modes_ and close_modes_ take on bits from

-  // the list of all events.  For example, if close_modes_ | ON_DOWNLOADING

-  // is true, then when ON_DOWNLOADING is called, DoClose will be called.

-  int misbehave_modes_;

-  int close_modes_;

-  bool do_closed_called;

-

-  JobObserver()

-    : observed(0), misbehave_modes_(0), close_modes_(0),

-      do_closed_called(false) {

-    wprintf(L"JobObserver\n");

-  }

-  virtual ~JobObserver() {

-    wprintf(L"~JobObserver\n");

-  }

-

-  void Reset() {

-    observed = 0;

-    misbehave_modes_ = 0;

-    close_modes_ = 0;

-    do_closed_called = false;

-  }

-

-  void AddMisbehaveMode(int event_code) {

-    misbehave_modes_ |= event_code;

-  }

-

-  void AddCloseMode(int event_code) {

-    close_modes_ |= event_code;

-  }

-

-  HRESULT HandleEvent(int event_code) {

-    observed |= event_code;

-

-    if ((event_code & close_modes_) && !do_closed_called) {

-      wprintf(L"Calling DoClose()\n");

-      do_closed_called = true;

-      event_sink_->DoClose();

-    }

-

-    if (event_code & misbehave_modes_) {

-      wprintf(L"Misbehaving\n");

-      return E_FAIL;

-    } else {

-      return S_OK;

-    }

-  }

-

-  // JobObserver implementation.

-  STDMETHOD(OnShow)() {

-    wprintf(L"OnShow\n");

-    return HandleEvent(ON_SHOW);

-  }

-  STDMETHOD(OnCheckingForUpdate)() {

-    wprintf(L"OnCheckingForUpdate\n");

-    return HandleEvent(ON_CHECKING_FOR_UPDATES);

-  }

-  STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {

-    wprintf(L"OnUpdateAvailable [%s]\n", version_string);

-    return HandleEvent(ON_UPDATE_AVAILABLE);

-  }

-  STDMETHOD(OnWaitingToDownload)() {

-    wprintf(L"OnWaitingToDownload\n");

-    return HandleEvent(ON_WAITING_TO_INSTALL);

-  }

-  STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {

-    wprintf(L"OnDownloading [%d][%d]\n", time_remaining_ms, pos);

-    return HandleEvent(ON_DOWNLOADING);

-  }

-  STDMETHOD(OnWaitingToInstall)() {

-    wprintf(L"OnWaitingToInstall\n");

-    return HandleEvent(ON_WAITING_TO_INSTALL);

-  }

-  STDMETHOD(OnInstalling)() {

-    wprintf(L"OnInstalling\n");

-    return HandleEvent(ON_INSTALLING);

-  }

-  STDMETHOD(OnPause)() {

-    wprintf(L"OnPause\n");

-    return HandleEvent(ON_PAUSE);

-  }

-  STDMETHOD(OnComplete)(CompletionCodes code, const TCHAR* text) {

-    wprintf(L"OnComplete [%d][%s]\n", code, text);

-    int event_code = 0;

-    switch (code) {

-      case COMPLETION_CODE_SUCCESS:

-        event_code |= ON_COMPLETE_SUCCESS;

-        break;

-      case COMPLETION_CODE_SUCCESS_CLOSE_UI:

-        event_code |= ON_COMPLETE_SUCCESS_CLOSE_UI;

-        break;

-      case COMPLETION_CODE_ERROR:

-        event_code |= ON_COMPLETE_ERROR;

-        break;

-      case COMPLETION_CODE_RESTART_ALL_BROWSERS:

-        event_code |= ON_COMPLETE_RESTART_ALL_BROWSERS;

-        break;

-      case COMPLETION_CODE_REBOOT:

-        event_code |= ON_COMPLETE_REBOOT;

-        break;

-      case COMPLETION_CODE_RESTART_BROWSER:

-        event_code |= ON_COMPLETE_RESTART_BROWSER;

-        break;

-      case COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY:

-        event_code |= ON_COMPLETE_RESTART_ALL_BROWSERS_NOTICE_ONLY;

-        break;

-      case COMPLETION_CODE_REBOOT_NOTICE_ONLY:

-        event_code |= ON_COMPLETE_REBOOT_NOTICE_ONLY;

-        break;

-      case COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY:

-        event_code |= ON_COMPLETE_RESTART_BROWSER_NOTICE_ONLY;

-        break;

-      case COMPLETION_CODE_RUN_COMMAND:

-        event_code |= ON_COMPLETE_RUN_COMMAND;

-        break;

-      default:

-        break;

-    }

-    ::PostThreadMessage(::GetCurrentThreadId(), WM_QUIT, 0, 0);

-    return HandleEvent(event_code);

-  }

-  STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {

-    wprintf(L"SetEventSink [%d]\n", event_sink);

-    event_sink_ = event_sink;

-    return HandleEvent(SET_EVENT_SINK);

-  }

-

-  CComPtr<IProgressWndEvents> event_sink_;

-};

-

-#endif  // OMAHA_TOOLS_SRC_PERFORMONDEMAND_PERFORMONDEMAND_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_TOOLS_SRC_PERFORMONDEMAND_PERFORMONDEMAND_H_
+#define OMAHA_TOOLS_SRC_PERFORMONDEMAND_PERFORMONDEMAND_H_
+
+#pragma once
+#include <windows.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include "goopdate\google_update_idl.h"  // NOLINT
+
+// Keep this list syncronized with qa\client\lib\on_demand_lib.py
+#define ON_COMPLETE_SUCCESS                           0x00000001
+#define ON_COMPLETE_SUCCESS_CLOSE_UI                  0x00000002
+#define ON_COMPLETE_ERROR                             0x00000004
+#define ON_COMPLETE_RESTART_ALL_BROWSERS              0x00000008
+#define ON_COMPLETE_REBOOT                            0x00000010
+#define ON_SHOW                                       0x00000020
+#define ON_CHECKING_FOR_UPDATES                       0x00000040
+#define ON_UPDATE_AVAILABLE                           0x00000080
+#define ON_WAITING_TO_DOWNLOAD                        0x00000100
+#define ON_DOWNLOADING                                0x00000200
+#define ON_WAITING_TO_INSTALL                         0x00000400
+#define ON_INSTALLING                                 0x00000800
+#define ON_PAUSE                                      0x00001000
+#define SET_EVENT_SINK                                0x00002000
+#define ON_COMPLETE_RESTART_BROWSER                   0x00004000
+#define ON_COMPLETE_RESTART_ALL_BROWSERS_NOTICE_ONLY  0x00008000
+#define ON_COMPLETE_REBOOT_NOTICE_ONLY                0x00010000
+#define ON_COMPLETE_RESTART_BROWSER_NOTICE_ONLY       0x00020000
+#define ON_COMPLETE_RUN_COMMAND                       0x00040000
+
+class JobObserver
+  : public CComObjectRootEx<CComSingleThreadModel>,
+    public IJobObserver {
+ public:
+  BEGIN_COM_MAP(JobObserver)
+    COM_INTERFACE_ENTRY(IJobObserver)
+  END_COM_MAP()
+
+  // Each interaction enables a bit in observed, which is eventually returned as
+  // a return code.
+  int observed;
+
+  // Similar to observed, misbehave_modes_ and close_modes_ take on bits from
+  // the list of all events.  For example, if close_modes_ | ON_DOWNLOADING
+  // is true, then when ON_DOWNLOADING is called, DoClose will be called.
+  int misbehave_modes_;
+  int close_modes_;
+  bool do_closed_called;
+
+  JobObserver()
+    : observed(0), misbehave_modes_(0), close_modes_(0),
+      do_closed_called(false) {
+    wprintf(L"JobObserver\n");
+  }
+  virtual ~JobObserver() {
+    wprintf(L"~JobObserver\n");
+  }
+
+  void Reset() {
+    observed = 0;
+    misbehave_modes_ = 0;
+    close_modes_ = 0;
+    do_closed_called = false;
+  }
+
+  void AddMisbehaveMode(int event_code) {
+    misbehave_modes_ |= event_code;
+  }
+
+  void AddCloseMode(int event_code) {
+    close_modes_ |= event_code;
+  }
+
+  HRESULT HandleEvent(int event_code) {
+    observed |= event_code;
+
+    if ((event_code & close_modes_) && !do_closed_called) {
+      wprintf(L"Calling DoClose()\n");
+      do_closed_called = true;
+      event_sink_->DoClose();
+    }
+
+    if (event_code & misbehave_modes_) {
+      wprintf(L"Misbehaving\n");
+      return E_FAIL;
+    } else {
+      return S_OK;
+    }
+  }
+
+  // JobObserver implementation.
+  STDMETHOD(OnShow)() {
+    wprintf(L"OnShow\n");
+    return HandleEvent(ON_SHOW);
+  }
+  STDMETHOD(OnCheckingForUpdate)() {
+    wprintf(L"OnCheckingForUpdate\n");
+    return HandleEvent(ON_CHECKING_FOR_UPDATES);
+  }
+  STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
+    wprintf(L"OnUpdateAvailable [%s]\n", version_string);
+    return HandleEvent(ON_UPDATE_AVAILABLE);
+  }
+  STDMETHOD(OnWaitingToDownload)() {
+    wprintf(L"OnWaitingToDownload\n");
+    return HandleEvent(ON_WAITING_TO_INSTALL);
+  }
+  STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
+    wprintf(L"OnDownloading [%d][%d]\n", time_remaining_ms, pos);
+    return HandleEvent(ON_DOWNLOADING);
+  }
+  STDMETHOD(OnWaitingToInstall)() {
+    wprintf(L"OnWaitingToInstall\n");
+    return HandleEvent(ON_WAITING_TO_INSTALL);
+  }
+  STDMETHOD(OnInstalling)() {
+    wprintf(L"OnInstalling\n");
+    return HandleEvent(ON_INSTALLING);
+  }
+  STDMETHOD(OnPause)() {
+    wprintf(L"OnPause\n");
+    return HandleEvent(ON_PAUSE);
+  }
+  STDMETHOD(OnComplete)(CompletionCodes code, const TCHAR* text) {
+    wprintf(L"OnComplete [%d][%s]\n", code, text);
+    int event_code = 0;
+    switch (code) {
+      case COMPLETION_CODE_SUCCESS:
+        event_code |= ON_COMPLETE_SUCCESS;
+        break;
+      case COMPLETION_CODE_SUCCESS_CLOSE_UI:
+        event_code |= ON_COMPLETE_SUCCESS_CLOSE_UI;
+        break;
+      case COMPLETION_CODE_ERROR:
+        event_code |= ON_COMPLETE_ERROR;
+        break;
+      case COMPLETION_CODE_RESTART_ALL_BROWSERS:
+        event_code |= ON_COMPLETE_RESTART_ALL_BROWSERS;
+        break;
+      case COMPLETION_CODE_REBOOT:
+        event_code |= ON_COMPLETE_REBOOT;
+        break;
+      case COMPLETION_CODE_RESTART_BROWSER:
+        event_code |= ON_COMPLETE_RESTART_BROWSER;
+        break;
+      case COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY:
+        event_code |= ON_COMPLETE_RESTART_ALL_BROWSERS_NOTICE_ONLY;
+        break;
+      case COMPLETION_CODE_REBOOT_NOTICE_ONLY:
+        event_code |= ON_COMPLETE_REBOOT_NOTICE_ONLY;
+        break;
+      case COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY:
+        event_code |= ON_COMPLETE_RESTART_BROWSER_NOTICE_ONLY;
+        break;
+      case COMPLETION_CODE_RUN_COMMAND:
+        event_code |= ON_COMPLETE_RUN_COMMAND;
+        break;
+      default:
+        break;
+    }
+    ::PostThreadMessage(::GetCurrentThreadId(), WM_QUIT, 0, 0);
+    return HandleEvent(event_code);
+  }
+  STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {
+    wprintf(L"SetEventSink [%d]\n", event_sink);
+    event_sink_ = event_sink;
+    return HandleEvent(SET_EVENT_SINK);
+  }
+
+  CComPtr<IProgressWndEvents> event_sink_;
+};
+
+#endif  // OMAHA_TOOLS_SRC_PERFORMONDEMAND_PERFORMONDEMAND_H_
diff --git a/worker/app_request.h b/worker/app_request.h
index 8cd0445..49262ab 100644
--- a/worker/app_request.h
+++ b/worker/app_request.h
@@ -1,69 +1,69 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// app_request.h:  Class that encapsulates a product-level request for

-// install/update that is converted into the XML that goes to the server.  Will

-// hold one AppRequestData for the main product and 0..n AppRequestData objects

-// in a list for the components of the product that we know/care about.

-

-#ifndef OMAHA_WORKER_APP_REQUEST_H__

-#define OMAHA_WORKER_APP_REQUEST_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/worker/app_request_data.h"

-

-namespace omaha {

-

-class AppRequest {

- public:

-  AppRequest() {}

-  explicit AppRequest(const AppRequestData& request_data) {

-    request_data_ = request_data;

-  }

-  ~AppRequest() {}

-

-  void set_request_data(const AppRequestData& request_data) {

-    request_data_ = request_data;

-  }

-  const AppRequestData& request_data() const { return request_data_; }

-  void AddComponentRequest(const AppRequestData& component_data) {

-    components_.push_back(component_data);

-  }

-

-  AppRequestDataVector::const_iterator components_begin() const {

-    return components_.begin();

-  }

-

-  AppRequestDataVector::const_iterator components_end() const {

-    return components_.end();

-  }

-

-  size_t num_components() const { return components_.size(); }

-

- private:

-  AppRequestData request_data_;

-  AppRequestDataVector components_;

-};

-

-typedef std::vector<AppRequest> AppRequestVector;

-

-}  // namespace omaha.

-

-#endif  // OMAHA_WORKER_APP_REQUEST_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// app_request.h:  Class that encapsulates a product-level request for
+// install/update that is converted into the XML that goes to the server.  Will
+// hold one AppRequestData for the main product and 0..n AppRequestData objects
+// in a list for the components of the product that we know/care about.
+
+#ifndef OMAHA_WORKER_APP_REQUEST_H__
+#define OMAHA_WORKER_APP_REQUEST_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/worker/app_request_data.h"
+
+namespace omaha {
+
+class AppRequest {
+ public:
+  AppRequest() {}
+  explicit AppRequest(const AppRequestData& request_data) {
+    request_data_ = request_data;
+  }
+  ~AppRequest() {}
+
+  void set_request_data(const AppRequestData& request_data) {
+    request_data_ = request_data;
+  }
+  const AppRequestData& request_data() const { return request_data_; }
+  void AddComponentRequest(const AppRequestData& component_data) {
+    components_.push_back(component_data);
+  }
+
+  AppRequestDataVector::const_iterator components_begin() const {
+    return components_.begin();
+  }
+
+  AppRequestDataVector::const_iterator components_end() const {
+    return components_.end();
+  }
+
+  size_t num_components() const { return components_.size(); }
+
+ private:
+  AppRequestData request_data_;
+  AppRequestDataVector components_;
+};
+
+typedef std::vector<AppRequest> AppRequestVector;
+
+}  // namespace omaha.
+
+#endif  // OMAHA_WORKER_APP_REQUEST_H__
+
diff --git a/worker/app_request_data.h b/worker/app_request_data.h
index 4e4b432..3607b2d 100644
--- a/worker/app_request_data.h
+++ b/worker/app_request_data.h
@@ -1,70 +1,70 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// app_request_data.h:  The app or component level data required to generate the

-// XML that asks the server about that app or component.  Also used for pings in

-// addition to install/update requests.  These are contained within AppRequest

-// objects to represent the full product hierarchy.

-

-#ifndef OMAHA_WORKER_APP_REQUEST_DATA_H__

-#define OMAHA_WORKER_APP_REQUEST_DATA_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/ping_event.h"

-

-namespace omaha {

-

-class AppRequestData {

- public:

-  AppRequestData() {}

-  explicit AppRequestData(const AppData& app_data) {

-    app_data_ = app_data;

-  }

-

-  void set_app_data(const AppData& app_data) {

-    app_data_ = app_data;

-  }

-  const AppData& app_data() const { return app_data_; }

-

-  void AddPingEvent(const PingEvent& ping_event) {

-    ping_events_.push_back(ping_event);

-  }

-

-  PingEventVector::const_iterator ping_events_begin() const {

-    return ping_events_.begin();

-  }

-

-  PingEventVector::const_iterator ping_events_end() const {

-    return ping_events_.end();

-  }

-

-  size_t num_ping_events() const { return ping_events_.size(); }

-

- private:

-  AppData app_data_;

-  PingEventVector ping_events_;

-};

-

-typedef std::vector<AppRequestData> AppRequestDataVector;

-

-}  // namespace omaha.

-

-#endif  // OMAHA_WORKER_APP_REQUEST_DATA_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// app_request_data.h:  The app or component level data required to generate the
+// XML that asks the server about that app or component.  Also used for pings in
+// addition to install/update requests.  These are contained within AppRequest
+// objects to represent the full product hierarchy.
+
+#ifndef OMAHA_WORKER_APP_REQUEST_DATA_H__
+#define OMAHA_WORKER_APP_REQUEST_DATA_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/ping_event.h"
+
+namespace omaha {
+
+class AppRequestData {
+ public:
+  AppRequestData() {}
+  explicit AppRequestData(const AppData& app_data) {
+    app_data_ = app_data;
+  }
+
+  void set_app_data(const AppData& app_data) {
+    app_data_ = app_data;
+  }
+  const AppData& app_data() const { return app_data_; }
+
+  void AddPingEvent(const PingEvent& ping_event) {
+    ping_events_.push_back(ping_event);
+  }
+
+  PingEventVector::const_iterator ping_events_begin() const {
+    return ping_events_.begin();
+  }
+
+  PingEventVector::const_iterator ping_events_end() const {
+    return ping_events_.end();
+  }
+
+  size_t num_ping_events() const { return ping_events_.size(); }
+
+ private:
+  AppData app_data_;
+  PingEventVector ping_events_;
+};
+
+typedef std::vector<AppRequestData> AppRequestDataVector;
+
+}  // namespace omaha.
+
+#endif  // OMAHA_WORKER_APP_REQUEST_DATA_H__
+
diff --git a/worker/application_data.h b/worker/application_data.h
index 78f9208..36e9cc0 100644
--- a/worker/application_data.h
+++ b/worker/application_data.h
@@ -1,216 +1,216 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// application_data.h: Class encapsulates the application registration

-// and state information.

-

-#ifndef OMAHA_WORKER_APPLICATION_DATA_H__

-#define OMAHA_WORKER_APPLICATION_DATA_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/reg_key.h"

-

-namespace omaha {

-

-// Encapsulates all the knowledge about the application. All the code inside

-// omaha should use this class to query and update information associated with

-// applications.

-// This class represents a snapshot of the information in the registry. This

-// information could have changed after this snap short has been taken.

-// Implementation notes:

-// 1. Think about synchronizing access between two workers.

-// 2. The code should be able to get the values for params that are present

-//    inside client_state. I.e. we should not read from only clients. This is

-//    important for language.

-

-class AppData {

- public:

-  enum ActiveStates {

-    ACTIVE_NOTRUN = 0,

-    ACTIVE_RUN,

-    ACTIVE_UNKNOWN

-  };

-

-  AppData()

-      : app_guid_(GUID_NULL),

-        parent_app_guid_(GUID_NULL),

-        is_machine_app_(false),

-        iid_(GUID_NULL),

-        install_time_diff_sec_(0),

-        is_oem_install_(false),

-        is_eula_accepted_(true),  // Safe default.

-        browser_type_(BROWSER_UNKNOWN),

-        usage_stats_enable_(TRISTATE_NONE),

-        did_run_(ACTIVE_UNKNOWN),

-        is_uninstalled_(false),

-        is_update_disabled_(false) { }

-

-  AppData(const GUID& app_guid, bool is_machine_app)

-      : app_guid_(app_guid),

-        parent_app_guid_(GUID_NULL),

-        is_machine_app_(is_machine_app),

-        iid_(GUID_NULL),

-        install_time_diff_sec_(0),

-        is_oem_install_(false),

-        is_eula_accepted_(true),  // Safe default.

-        browser_type_(BROWSER_UNKNOWN),

-        usage_stats_enable_(TRISTATE_NONE),

-        did_run_(ACTIVE_UNKNOWN),

-        is_uninstalled_(false),

-        is_update_disabled_(false) { }

-

-  GUID app_guid() const { return app_guid_; }

-  void set_app_guid(const GUID& guid) { app_guid_ = guid; }

-

-  GUID parent_app_guid() const { return parent_app_guid_; }

-  void set_parent_app_guid(const GUID& guid) { parent_app_guid_ = guid; }

-

-  bool is_machine_app() const { return is_machine_app_; }

-  void set_is_machine_app(bool is_machine_app) {

-    is_machine_app_ = is_machine_app;

-  }

-

-  CString version() const { return version_; }

-  void set_version(const CString version) { version_ = version; }

-

-  CString previous_version() const { return previous_version_; }

-  void set_previous_version(const CString& previous_version) {

-    previous_version_ = previous_version;

-  }

-

-  CString language() const { return language_; }

-  void set_language(const CString& language) { language_ = language; }

-

-  CString ap() const { return ap_; }

-  void set_ap(const CString& ap) { ap_ = ap; }

-

-  CString tt_token() const { return tt_token_; }

-  void set_tt_token(const CString& tt_token) { tt_token_ = tt_token; }

-

-  GUID iid() const { return iid_; }

-  void set_iid(const GUID& iid) { iid_ = iid; }

-

-  CString brand_code() const { return brand_code_; }

-  void set_brand_code(const CString& brand_code) { brand_code_ = brand_code; }

-

-  CString client_id() const { return client_id_; }

-  void set_client_id(const CString& client_id) { client_id_ = client_id; }

-

-  CString referral_id() const { return referral_id_; }

-  void set_referral_id(const CString& referral_id) {

-      referral_id_ = referral_id;

-  }

-

-  uint32 install_time_diff_sec() const { return install_time_diff_sec_; }

-  void set_install_time_diff_sec(uint32 install_time_diff_sec) {

-      install_time_diff_sec_ = install_time_diff_sec;

-  }

-

-  bool is_oem_install() const { return is_oem_install_; }

-  void set_is_oem_install(bool is_oem_install) {

-    is_oem_install_ = is_oem_install;

-  }

-

-  bool is_eula_accepted() const { return is_eula_accepted_; }

-  void set_is_eula_accepted(bool is_eula_accepted) {

-    is_eula_accepted_ = is_eula_accepted;

-  }

-

-  CString display_name() const { return display_name_; }

-  void set_display_name(const CString& display_name) {

-    display_name_ = display_name;

-  }

-

-  BrowserType browser_type() const { return browser_type_; }

-  void set_browser_type(BrowserType type) { browser_type_ = type; }

-

-  CString install_source() const { return install_source_; }

-  void set_install_source(const CString& install_source) {

-    install_source_ = install_source;

-  }

-

-  CString encoded_installer_data() const { return encoded_installer_data_; }

-  void set_encoded_installer_data(const CString& encoded_installer_data) {

-    encoded_installer_data_ = encoded_installer_data;

-  }

-

-  CString install_data_index() const { return install_data_index_; }

-  void set_install_data_index(const CString& install_data_index) {

-    install_data_index_ = install_data_index;

-  }

-

-  Tristate usage_stats_enable() const { return usage_stats_enable_; }

-  void set_usage_stats_enable(Tristate usage_stats_enable) {

-    usage_stats_enable_ = usage_stats_enable;

-  }

-

-  ActiveStates did_run() const { return did_run_; }

-  void set_did_run(AppData::ActiveStates did_run) {

-    did_run_ = did_run;

-  }

-

-  bool is_uninstalled() const { return is_uninstalled_; }

-  void set_is_uninstalled(bool is_uninstalled) {

-    is_uninstalled_ = is_uninstalled;

-  }

-

-  bool is_update_disabled() const { return is_update_disabled_; }

-  void set_is_update_disabled(bool is_update_disabled) {

-    is_update_disabled_ = is_update_disabled;

-  }

-

- private:

-  GUID app_guid_;

-  GUID parent_app_guid_;

-  bool is_machine_app_;

-

-  CString version_;

-  CString previous_version_;

-  CString language_;

-

-  CString ap_;

-  CString tt_token_;

-  GUID iid_;

-  CString brand_code_;

-  CString client_id_;

-  CString referral_id_;

-  uint32 install_time_diff_sec_;

-  bool is_oem_install_;

-  bool is_eula_accepted_;

-

-  CString display_name_;

-  BrowserType browser_type_;

-  CString install_source_;

-  CString encoded_installer_data_;

-  CString install_data_index_;

-  Tristate usage_stats_enable_;

-

-  ActiveStates did_run_;

-

-  bool is_uninstalled_;

-  bool is_update_disabled_;

-};

-

-typedef std::vector<AppData> AppDataVector;

-

-}  // namespace omaha.

-

-#endif  // OMAHA_WORKER_APPLICATION_DATA_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// application_data.h: Class encapsulates the application registration
+// and state information.
+
+#ifndef OMAHA_WORKER_APPLICATION_DATA_H__
+#define OMAHA_WORKER_APPLICATION_DATA_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/reg_key.h"
+
+namespace omaha {
+
+// Encapsulates all the knowledge about the application. All the code inside
+// omaha should use this class to query and update information associated with
+// applications.
+// This class represents a snapshot of the information in the registry. This
+// information could have changed after this snap short has been taken.
+// Implementation notes:
+// 1. Think about synchronizing access between two workers.
+// 2. The code should be able to get the values for params that are present
+//    inside client_state. I.e. we should not read from only clients. This is
+//    important for language.
+
+class AppData {
+ public:
+  enum ActiveStates {
+    ACTIVE_NOTRUN = 0,
+    ACTIVE_RUN,
+    ACTIVE_UNKNOWN
+  };
+
+  AppData()
+      : app_guid_(GUID_NULL),
+        parent_app_guid_(GUID_NULL),
+        is_machine_app_(false),
+        iid_(GUID_NULL),
+        install_time_diff_sec_(0),
+        is_oem_install_(false),
+        is_eula_accepted_(true),  // Safe default.
+        browser_type_(BROWSER_UNKNOWN),
+        usage_stats_enable_(TRISTATE_NONE),
+        did_run_(ACTIVE_UNKNOWN),
+        is_uninstalled_(false),
+        is_update_disabled_(false) { }
+
+  AppData(const GUID& app_guid, bool is_machine_app)
+      : app_guid_(app_guid),
+        parent_app_guid_(GUID_NULL),
+        is_machine_app_(is_machine_app),
+        iid_(GUID_NULL),
+        install_time_diff_sec_(0),
+        is_oem_install_(false),
+        is_eula_accepted_(true),  // Safe default.
+        browser_type_(BROWSER_UNKNOWN),
+        usage_stats_enable_(TRISTATE_NONE),
+        did_run_(ACTIVE_UNKNOWN),
+        is_uninstalled_(false),
+        is_update_disabled_(false) { }
+
+  GUID app_guid() const { return app_guid_; }
+  void set_app_guid(const GUID& guid) { app_guid_ = guid; }
+
+  GUID parent_app_guid() const { return parent_app_guid_; }
+  void set_parent_app_guid(const GUID& guid) { parent_app_guid_ = guid; }
+
+  bool is_machine_app() const { return is_machine_app_; }
+  void set_is_machine_app(bool is_machine_app) {
+    is_machine_app_ = is_machine_app;
+  }
+
+  CString version() const { return version_; }
+  void set_version(const CString version) { version_ = version; }
+
+  CString previous_version() const { return previous_version_; }
+  void set_previous_version(const CString& previous_version) {
+    previous_version_ = previous_version;
+  }
+
+  CString language() const { return language_; }
+  void set_language(const CString& language) { language_ = language; }
+
+  CString ap() const { return ap_; }
+  void set_ap(const CString& ap) { ap_ = ap; }
+
+  CString tt_token() const { return tt_token_; }
+  void set_tt_token(const CString& tt_token) { tt_token_ = tt_token; }
+
+  GUID iid() const { return iid_; }
+  void set_iid(const GUID& iid) { iid_ = iid; }
+
+  CString brand_code() const { return brand_code_; }
+  void set_brand_code(const CString& brand_code) { brand_code_ = brand_code; }
+
+  CString client_id() const { return client_id_; }
+  void set_client_id(const CString& client_id) { client_id_ = client_id; }
+
+  CString referral_id() const { return referral_id_; }
+  void set_referral_id(const CString& referral_id) {
+      referral_id_ = referral_id;
+  }
+
+  uint32 install_time_diff_sec() const { return install_time_diff_sec_; }
+  void set_install_time_diff_sec(uint32 install_time_diff_sec) {
+      install_time_diff_sec_ = install_time_diff_sec;
+  }
+
+  bool is_oem_install() const { return is_oem_install_; }
+  void set_is_oem_install(bool is_oem_install) {
+    is_oem_install_ = is_oem_install;
+  }
+
+  bool is_eula_accepted() const { return is_eula_accepted_; }
+  void set_is_eula_accepted(bool is_eula_accepted) {
+    is_eula_accepted_ = is_eula_accepted;
+  }
+
+  CString display_name() const { return display_name_; }
+  void set_display_name(const CString& display_name) {
+    display_name_ = display_name;
+  }
+
+  BrowserType browser_type() const { return browser_type_; }
+  void set_browser_type(BrowserType type) { browser_type_ = type; }
+
+  CString install_source() const { return install_source_; }
+  void set_install_source(const CString& install_source) {
+    install_source_ = install_source;
+  }
+
+  CString encoded_installer_data() const { return encoded_installer_data_; }
+  void set_encoded_installer_data(const CString& encoded_installer_data) {
+    encoded_installer_data_ = encoded_installer_data;
+  }
+
+  CString install_data_index() const { return install_data_index_; }
+  void set_install_data_index(const CString& install_data_index) {
+    install_data_index_ = install_data_index;
+  }
+
+  Tristate usage_stats_enable() const { return usage_stats_enable_; }
+  void set_usage_stats_enable(Tristate usage_stats_enable) {
+    usage_stats_enable_ = usage_stats_enable;
+  }
+
+  ActiveStates did_run() const { return did_run_; }
+  void set_did_run(AppData::ActiveStates did_run) {
+    did_run_ = did_run;
+  }
+
+  bool is_uninstalled() const { return is_uninstalled_; }
+  void set_is_uninstalled(bool is_uninstalled) {
+    is_uninstalled_ = is_uninstalled;
+  }
+
+  bool is_update_disabled() const { return is_update_disabled_; }
+  void set_is_update_disabled(bool is_update_disabled) {
+    is_update_disabled_ = is_update_disabled;
+  }
+
+ private:
+  GUID app_guid_;
+  GUID parent_app_guid_;
+  bool is_machine_app_;
+
+  CString version_;
+  CString previous_version_;
+  CString language_;
+
+  CString ap_;
+  CString tt_token_;
+  GUID iid_;
+  CString brand_code_;
+  CString client_id_;
+  CString referral_id_;
+  uint32 install_time_diff_sec_;
+  bool is_oem_install_;
+  bool is_eula_accepted_;
+
+  CString display_name_;
+  BrowserType browser_type_;
+  CString install_source_;
+  CString encoded_installer_data_;
+  CString install_data_index_;
+  Tristate usage_stats_enable_;
+
+  ActiveStates did_run_;
+
+  bool is_uninstalled_;
+  bool is_update_disabled_;
+};
+
+typedef std::vector<AppData> AppDataVector;
+
+}  // namespace omaha.
+
+#endif  // OMAHA_WORKER_APPLICATION_DATA_H__
diff --git a/worker/application_data_unittest.cc b/worker/application_data_unittest.cc
index 7f99b93..2d4393c 100644
--- a/worker/application_data_unittest.cc
+++ b/worker/application_data_unittest.cc
@@ -1,222 +1,222 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// ApplicationData unit tests

-

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/time.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/job.h"

-

-namespace omaha {

-

-const TCHAR* const kGuid1 = _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");

-const TCHAR* const kGuid2 = _T("{A979ACBD-1F55-4b12-A35F-4DBCA5A7CCB8}");

-const TCHAR* const kGuid3 = _T("{661045C5-4429-4140-BC48-8CEA241D1DEF}");

-

-  void ValidateDefaltValues(const AppData& data) {

-    EXPECT_TRUE(::IsEqualGUID(GUID_NULL, data.app_guid()));

-    EXPECT_TRUE(::IsEqualGUID(GUID_NULL, data.parent_app_guid()));

-    EXPECT_FALSE(data.is_machine_app());

-    EXPECT_TRUE(data.version().IsEmpty());

-    EXPECT_TRUE(data.previous_version().IsEmpty());

-    EXPECT_TRUE(data.language().IsEmpty());

-    EXPECT_TRUE(data.ap().IsEmpty());

-    EXPECT_TRUE(data.tt_token().IsEmpty());

-    EXPECT_TRUE(::IsEqualGUID(GUID_NULL, data.iid()));

-    EXPECT_TRUE(data.brand_code().IsEmpty());

-    EXPECT_TRUE(data.client_id().IsEmpty());

-    EXPECT_TRUE(data.referral_id().IsEmpty());

-    EXPECT_EQ(0, data.install_time_diff_sec());

-    EXPECT_FALSE(data.is_oem_install());

-    EXPECT_TRUE(data.is_eula_accepted());

-    EXPECT_TRUE(data.display_name().IsEmpty());

-    EXPECT_EQ(BROWSER_UNKNOWN, data.browser_type());

-    EXPECT_TRUE(data.install_source().IsEmpty());

-    EXPECT_TRUE(data.encoded_installer_data().IsEmpty());

-    EXPECT_TRUE(data.install_data_index().IsEmpty());

-    EXPECT_EQ(TRISTATE_NONE, data.usage_stats_enable());

-    EXPECT_EQ(AppData::ACTIVE_UNKNOWN, data.did_run());

-    EXPECT_FALSE(data.is_uninstalled());

-    EXPECT_FALSE(data.is_update_disabled());

-  }

-

-  void ValidateExpectedValues(const AppData& expected, const AppData& actual) {

-    EXPECT_STREQ(GuidToString(expected.app_guid()),

-                 GuidToString(actual.app_guid()));

-    EXPECT_STREQ(GuidToString(expected.parent_app_guid()),

-                 GuidToString(actual.parent_app_guid()));

-    EXPECT_EQ(expected.is_machine_app(), actual.is_machine_app());

-    EXPECT_STREQ(expected.version(), actual.version());

-    EXPECT_STREQ(expected.previous_version(), actual.previous_version());

-    EXPECT_STREQ(expected.language(), actual.language());

-    EXPECT_STREQ(expected.ap(), actual.ap());

-    EXPECT_STREQ(expected.tt_token(), actual.tt_token());

-    EXPECT_STREQ(GuidToString(expected.iid()), GuidToString(actual.iid()));

-    EXPECT_STREQ(expected.brand_code(), actual.brand_code());

-    EXPECT_STREQ(expected.client_id(), actual.client_id());

-    EXPECT_STREQ(expected.referral_id(), actual.referral_id());

-    EXPECT_EQ(expected.install_time_diff_sec(), actual.install_time_diff_sec());

-    EXPECT_EQ(expected.is_oem_install(), actual.is_oem_install());

-    EXPECT_EQ(expected.is_eula_accepted(), actual.is_eula_accepted());

-    EXPECT_STREQ(expected.display_name(), actual.display_name());

-    EXPECT_EQ(expected.browser_type(), actual.browser_type());

-    EXPECT_STREQ(expected.install_source(), actual.install_source());

-    EXPECT_STREQ(expected.encoded_installer_data(),

-                 actual.encoded_installer_data());

-    EXPECT_STREQ(expected.install_data_index(), actual.install_data_index());

-    EXPECT_EQ(expected.usage_stats_enable(), actual.usage_stats_enable());

-    EXPECT_EQ(expected.did_run(), actual.did_run());

-    EXPECT_EQ(expected.is_uninstalled(), actual.is_uninstalled());

-    EXPECT_EQ(expected.is_update_disabled(), actual.is_update_disabled());

-  }

-

-void FillAppData(AppData* app_data) {

-  const GUID app_id = StringToGuid(kGuid1);

-  const bool is_machine_app = true;

-  const GUID parent_app_id = StringToGuid(kGuid2);

-  const CString version = _T("12345");

-  const CString previous_version = _T("11111");

-  const CString language = _T("en");

-  const AppData::ActiveStates did_run = AppData::ACTIVE_RUN;

-  const CString ap = _T("some_ap_value");

-  const GUID iid = StringToGuid(kGuid3);

-  const CString brand_code = _T("GOOG");

-  const CString client_id = _T("some_client_id");

-  const CString referral_id = _T("ABC987");

-  const uint32 install_time_diff_sec = 98765;

-  const bool is_oem_install = true;

-  const bool is_eula_accepted = false;

-  const CString encoded_installer_data = _T("%20foobar");

-  const CString install_data_index = _T("foobar");

-  const bool is_uninstalled = true;

-  const bool is_update_disabled = false;

-

-  AppData actual(app_id, is_machine_app);

-  app_data->set_parent_app_guid(parent_app_id);

-  app_data->set_version(version);

-  app_data->set_previous_version(previous_version);

-  app_data->set_language(language);

-  app_data->set_did_run(did_run);

-  app_data->set_ap(ap);

-  app_data->set_iid(iid);

-  app_data->set_brand_code(brand_code);

-  app_data->set_client_id(client_id);

-  app_data->set_referral_id(referral_id);

-  app_data->set_install_time_diff_sec(install_time_diff_sec);

-  app_data->set_is_oem_install(is_oem_install);

-  app_data->set_is_eula_accepted(is_eula_accepted);

-  app_data->set_encoded_installer_data(encoded_installer_data);

-  app_data->set_install_data_index(install_data_index);

-  app_data->set_is_uninstalled(is_uninstalled);

-  app_data->set_is_update_disabled(is_update_disabled);

-}

-

-TEST(AppDataTest, TestAllParams) {

-  const GUID app_guid = StringToGuid(kGuid1);

-  const bool is_machine_app = true;

-  const GUID parent_app_guid = StringToGuid(kGuid2);

-  const CString version = _T("12345");

-  const CString previous_version = _T("11111");

-  const CString language = _T("en");

-  const AppData::ActiveStates did_run = AppData::ACTIVE_RUN;

-  const CString ap = _T("some_ap_value");

-  const CString tt_token = _T("some_tt_token_value");

-  const GUID iid = StringToGuid(kGuid3);

-  const CString brand_code = _T("GOOG");

-  const CString client_id = _T("some_client_id");

-  const CString referral_id = _T("123456");

-  const uint32 install_time_diff_sec = 123498;

-  const bool is_oem_install = true;

-  const bool is_eula_accepted = false;

-  const CString encoded_installer_data = _T("%20foobar");

-  const CString install_data_index = _T("foobar");

-  const bool is_uninstalled = true;

-  const bool is_update_disabled = false;

-

-  AppData actual(app_guid, is_machine_app);

-  actual.set_parent_app_guid(parent_app_guid);

-  actual.set_version(version);

-  actual.set_previous_version(previous_version);

-  actual.set_language(language);

-  actual.set_did_run(did_run);

-  actual.set_ap(ap);

-  actual.set_tt_token(tt_token);

-  actual.set_iid(iid);

-  actual.set_brand_code(brand_code);

-  actual.set_client_id(client_id);

-  actual.set_referral_id(referral_id);

-  actual.set_install_time_diff_sec(install_time_diff_sec);

-  actual.set_is_oem_install(is_oem_install);

-  actual.set_is_eula_accepted(is_eula_accepted);

-  actual.set_encoded_installer_data(encoded_installer_data);

-  actual.set_install_data_index(install_data_index);

-  actual.set_is_uninstalled(is_uninstalled);

-  actual.set_is_update_disabled(is_update_disabled);

-

-  EXPECT_TRUE(::IsEqualGUID(app_guid, actual.app_guid()));

-  EXPECT_TRUE(::IsEqualGUID(parent_app_guid, actual.parent_app_guid()));

-  EXPECT_EQ(is_machine_app, actual.is_machine_app());

-  EXPECT_STREQ(version, actual.version());

-  EXPECT_STREQ(previous_version, actual.previous_version());

-  EXPECT_STREQ(language, actual.language());

-  EXPECT_EQ(did_run, actual.did_run());

-  EXPECT_STREQ(ap, actual.ap());

-  EXPECT_STREQ(tt_token, actual.tt_token());

-  EXPECT_TRUE(::IsEqualGUID(iid, actual.iid()));

-  EXPECT_STREQ(brand_code, actual.brand_code());

-  EXPECT_STREQ(client_id, actual.client_id());

-  EXPECT_STREQ(referral_id, actual.referral_id());

-  EXPECT_EQ(install_time_diff_sec, actual.install_time_diff_sec());

-  EXPECT_EQ(is_oem_install, actual.is_oem_install());

-  EXPECT_EQ(is_eula_accepted, actual.is_eula_accepted());

-  EXPECT_STREQ(encoded_installer_data, actual.encoded_installer_data());

-  EXPECT_STREQ(install_data_index, actual.install_data_index());

-  EXPECT_EQ(is_uninstalled, actual.is_uninstalled());

-  EXPECT_EQ(is_update_disabled, actual.is_update_disabled());

-}

-

-TEST(AppDataTest, TestInitialized) {

-  AppData app_data1;

-  ValidateDefaltValues(app_data1);

-

-  AppData app_data2(GUID_NULL, false);

-  ValidateDefaltValues(app_data2);

-}

-

-TEST(AppDataTest, TestAssignment) {

-  AppData app_data;

-  FillAppData(&app_data);

-  AppData app_data2;

-  app_data2 = app_data;

-

-  ValidateExpectedValues(app_data, app_data2);

-}

-

-TEST(AppDataTest, TestCopyConstructor) {

-  AppData app_data;

-  FillAppData(&app_data);

-  AppData app_data2(app_data);

-

-  ValidateExpectedValues(app_data, app_data2);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// ApplicationData unit tests
+
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/time.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/job.h"
+
+namespace omaha {
+
+const TCHAR* const kGuid1 = _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");
+const TCHAR* const kGuid2 = _T("{A979ACBD-1F55-4b12-A35F-4DBCA5A7CCB8}");
+const TCHAR* const kGuid3 = _T("{661045C5-4429-4140-BC48-8CEA241D1DEF}");
+
+  void ValidateDefaltValues(const AppData& data) {
+    EXPECT_TRUE(::IsEqualGUID(GUID_NULL, data.app_guid()));
+    EXPECT_TRUE(::IsEqualGUID(GUID_NULL, data.parent_app_guid()));
+    EXPECT_FALSE(data.is_machine_app());
+    EXPECT_TRUE(data.version().IsEmpty());
+    EXPECT_TRUE(data.previous_version().IsEmpty());
+    EXPECT_TRUE(data.language().IsEmpty());
+    EXPECT_TRUE(data.ap().IsEmpty());
+    EXPECT_TRUE(data.tt_token().IsEmpty());
+    EXPECT_TRUE(::IsEqualGUID(GUID_NULL, data.iid()));
+    EXPECT_TRUE(data.brand_code().IsEmpty());
+    EXPECT_TRUE(data.client_id().IsEmpty());
+    EXPECT_TRUE(data.referral_id().IsEmpty());
+    EXPECT_EQ(0, data.install_time_diff_sec());
+    EXPECT_FALSE(data.is_oem_install());
+    EXPECT_TRUE(data.is_eula_accepted());
+    EXPECT_TRUE(data.display_name().IsEmpty());
+    EXPECT_EQ(BROWSER_UNKNOWN, data.browser_type());
+    EXPECT_TRUE(data.install_source().IsEmpty());
+    EXPECT_TRUE(data.encoded_installer_data().IsEmpty());
+    EXPECT_TRUE(data.install_data_index().IsEmpty());
+    EXPECT_EQ(TRISTATE_NONE, data.usage_stats_enable());
+    EXPECT_EQ(AppData::ACTIVE_UNKNOWN, data.did_run());
+    EXPECT_FALSE(data.is_uninstalled());
+    EXPECT_FALSE(data.is_update_disabled());
+  }
+
+  void ValidateExpectedValues(const AppData& expected, const AppData& actual) {
+    EXPECT_STREQ(GuidToString(expected.app_guid()),
+                 GuidToString(actual.app_guid()));
+    EXPECT_STREQ(GuidToString(expected.parent_app_guid()),
+                 GuidToString(actual.parent_app_guid()));
+    EXPECT_EQ(expected.is_machine_app(), actual.is_machine_app());
+    EXPECT_STREQ(expected.version(), actual.version());
+    EXPECT_STREQ(expected.previous_version(), actual.previous_version());
+    EXPECT_STREQ(expected.language(), actual.language());
+    EXPECT_STREQ(expected.ap(), actual.ap());
+    EXPECT_STREQ(expected.tt_token(), actual.tt_token());
+    EXPECT_STREQ(GuidToString(expected.iid()), GuidToString(actual.iid()));
+    EXPECT_STREQ(expected.brand_code(), actual.brand_code());
+    EXPECT_STREQ(expected.client_id(), actual.client_id());
+    EXPECT_STREQ(expected.referral_id(), actual.referral_id());
+    EXPECT_EQ(expected.install_time_diff_sec(), actual.install_time_diff_sec());
+    EXPECT_EQ(expected.is_oem_install(), actual.is_oem_install());
+    EXPECT_EQ(expected.is_eula_accepted(), actual.is_eula_accepted());
+    EXPECT_STREQ(expected.display_name(), actual.display_name());
+    EXPECT_EQ(expected.browser_type(), actual.browser_type());
+    EXPECT_STREQ(expected.install_source(), actual.install_source());
+    EXPECT_STREQ(expected.encoded_installer_data(),
+                 actual.encoded_installer_data());
+    EXPECT_STREQ(expected.install_data_index(), actual.install_data_index());
+    EXPECT_EQ(expected.usage_stats_enable(), actual.usage_stats_enable());
+    EXPECT_EQ(expected.did_run(), actual.did_run());
+    EXPECT_EQ(expected.is_uninstalled(), actual.is_uninstalled());
+    EXPECT_EQ(expected.is_update_disabled(), actual.is_update_disabled());
+  }
+
+void FillAppData(AppData* app_data) {
+  const GUID app_id = StringToGuid(kGuid1);
+  const bool is_machine_app = true;
+  const GUID parent_app_id = StringToGuid(kGuid2);
+  const CString version = _T("12345");
+  const CString previous_version = _T("11111");
+  const CString language = _T("en");
+  const AppData::ActiveStates did_run = AppData::ACTIVE_RUN;
+  const CString ap = _T("some_ap_value");
+  const GUID iid = StringToGuid(kGuid3);
+  const CString brand_code = _T("GOOG");
+  const CString client_id = _T("some_client_id");
+  const CString referral_id = _T("ABC987");
+  const uint32 install_time_diff_sec = 98765;
+  const bool is_oem_install = true;
+  const bool is_eula_accepted = false;
+  const CString encoded_installer_data = _T("%20foobar");
+  const CString install_data_index = _T("foobar");
+  const bool is_uninstalled = true;
+  const bool is_update_disabled = false;
+
+  AppData actual(app_id, is_machine_app);
+  app_data->set_parent_app_guid(parent_app_id);
+  app_data->set_version(version);
+  app_data->set_previous_version(previous_version);
+  app_data->set_language(language);
+  app_data->set_did_run(did_run);
+  app_data->set_ap(ap);
+  app_data->set_iid(iid);
+  app_data->set_brand_code(brand_code);
+  app_data->set_client_id(client_id);
+  app_data->set_referral_id(referral_id);
+  app_data->set_install_time_diff_sec(install_time_diff_sec);
+  app_data->set_is_oem_install(is_oem_install);
+  app_data->set_is_eula_accepted(is_eula_accepted);
+  app_data->set_encoded_installer_data(encoded_installer_data);
+  app_data->set_install_data_index(install_data_index);
+  app_data->set_is_uninstalled(is_uninstalled);
+  app_data->set_is_update_disabled(is_update_disabled);
+}
+
+TEST(AppDataTest, TestAllParams) {
+  const GUID app_guid = StringToGuid(kGuid1);
+  const bool is_machine_app = true;
+  const GUID parent_app_guid = StringToGuid(kGuid2);
+  const CString version = _T("12345");
+  const CString previous_version = _T("11111");
+  const CString language = _T("en");
+  const AppData::ActiveStates did_run = AppData::ACTIVE_RUN;
+  const CString ap = _T("some_ap_value");
+  const CString tt_token = _T("some_tt_token_value");
+  const GUID iid = StringToGuid(kGuid3);
+  const CString brand_code = _T("GOOG");
+  const CString client_id = _T("some_client_id");
+  const CString referral_id = _T("123456");
+  const uint32 install_time_diff_sec = 123498;
+  const bool is_oem_install = true;
+  const bool is_eula_accepted = false;
+  const CString encoded_installer_data = _T("%20foobar");
+  const CString install_data_index = _T("foobar");
+  const bool is_uninstalled = true;
+  const bool is_update_disabled = false;
+
+  AppData actual(app_guid, is_machine_app);
+  actual.set_parent_app_guid(parent_app_guid);
+  actual.set_version(version);
+  actual.set_previous_version(previous_version);
+  actual.set_language(language);
+  actual.set_did_run(did_run);
+  actual.set_ap(ap);
+  actual.set_tt_token(tt_token);
+  actual.set_iid(iid);
+  actual.set_brand_code(brand_code);
+  actual.set_client_id(client_id);
+  actual.set_referral_id(referral_id);
+  actual.set_install_time_diff_sec(install_time_diff_sec);
+  actual.set_is_oem_install(is_oem_install);
+  actual.set_is_eula_accepted(is_eula_accepted);
+  actual.set_encoded_installer_data(encoded_installer_data);
+  actual.set_install_data_index(install_data_index);
+  actual.set_is_uninstalled(is_uninstalled);
+  actual.set_is_update_disabled(is_update_disabled);
+
+  EXPECT_TRUE(::IsEqualGUID(app_guid, actual.app_guid()));
+  EXPECT_TRUE(::IsEqualGUID(parent_app_guid, actual.parent_app_guid()));
+  EXPECT_EQ(is_machine_app, actual.is_machine_app());
+  EXPECT_STREQ(version, actual.version());
+  EXPECT_STREQ(previous_version, actual.previous_version());
+  EXPECT_STREQ(language, actual.language());
+  EXPECT_EQ(did_run, actual.did_run());
+  EXPECT_STREQ(ap, actual.ap());
+  EXPECT_STREQ(tt_token, actual.tt_token());
+  EXPECT_TRUE(::IsEqualGUID(iid, actual.iid()));
+  EXPECT_STREQ(brand_code, actual.brand_code());
+  EXPECT_STREQ(client_id, actual.client_id());
+  EXPECT_STREQ(referral_id, actual.referral_id());
+  EXPECT_EQ(install_time_diff_sec, actual.install_time_diff_sec());
+  EXPECT_EQ(is_oem_install, actual.is_oem_install());
+  EXPECT_EQ(is_eula_accepted, actual.is_eula_accepted());
+  EXPECT_STREQ(encoded_installer_data, actual.encoded_installer_data());
+  EXPECT_STREQ(install_data_index, actual.install_data_index());
+  EXPECT_EQ(is_uninstalled, actual.is_uninstalled());
+  EXPECT_EQ(is_update_disabled, actual.is_update_disabled());
+}
+
+TEST(AppDataTest, TestInitialized) {
+  AppData app_data1;
+  ValidateDefaltValues(app_data1);
+
+  AppData app_data2(GUID_NULL, false);
+  ValidateDefaltValues(app_data2);
+}
+
+TEST(AppDataTest, TestAssignment) {
+  AppData app_data;
+  FillAppData(&app_data);
+  AppData app_data2;
+  app_data2 = app_data;
+
+  ValidateExpectedValues(app_data, app_data2);
+}
+
+TEST(AppDataTest, TestCopyConstructor) {
+  AppData app_data;
+  FillAppData(&app_data);
+  AppData app_data2(app_data);
+
+  ValidateExpectedValues(app_data, app_data2);
+}
+
+}  // namespace omaha
diff --git a/worker/application_manager.cc b/worker/application_manager.cc
index d1f346f..71ec354 100644
--- a/worker/application_manager.cc
+++ b/worker/application_manager.cc
@@ -1,987 +1,987 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// Contains the logic to encapsulate access to the application data

-// stored in the registry.

-

-#include "omaha/worker/application_manager.h"

-

-#include <algorithm>

-#include <cstdlib>

-#include <functional>

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/worker/application_usage_data.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/job.h"

-

-namespace omaha {

-

-namespace {

-

-// Determines if an application is registered with Google Update.

-class IsAppRegisteredFunc

-    : public std::unary_function<const CString&, HRESULT> {

- public:

-  explicit IsAppRegisteredFunc(const CString& guid)

-      : is_registered_(false),

-        guid_(guid) {}

-

-  bool is_registered() const { return is_registered_; }

-

-  HRESULT operator() (const CString& guid) {

-    if (guid.CompareNoCase(guid_) == 0) {

-      is_registered_ = true;

-    }

-    return S_OK;

-  }

- private:

-  CString guid_;

-  bool is_registered_;

-};

-

-// Accumulates ProductData.

-class CollectProductsFunc

-    : public std::unary_function<const CString&, HRESULT> {

- public:

-  CollectProductsFunc(ProductDataVector* products,

-                      bool is_machine,

-                      bool collect_registered_products)

-      : products_(products),

-        is_machine_(is_machine),

-        collect_registered_products_(collect_registered_products) {

-    ASSERT1(products);

-  }

-

-  // Ignores errors and accumulates as many applications as possible.

-  HRESULT operator() (const CString& guid) {

-    AppManager app_manager(is_machine_);

-    ProductData product_data;

-    if (SUCCEEDED(app_manager.ReadProductDataFromStore(StringToGuid(guid),

-                                                       &product_data))) {

-      ASSERT(!collect_registered_products_ ||

-             !product_data.app_data().is_uninstalled(),

-             (_T("Should not be finding uninstalled apps while looking for ")

-              _T("registered apps; may be enumerating the wrong key.")));

-      if (collect_registered_products_ ||

-          product_data.app_data().is_uninstalled()) {

-        CORE_LOG(L3, (_T("[Found %s product][%s]"),

-                      collect_registered_products_ ? _T("registered") :

-                                                      _T("uninstalled"),

-                      guid));

-        products_->push_back(product_data);

-      }

-    }

-    return S_OK;

-  }

-

- private:

-  bool collect_registered_products_;

-  bool is_machine_;

-  ProductDataVector* products_;

-};

-

-// Accumulates AppData for components of a product.

-class CollectComponentsFunc

-    : public std::unary_function<const CString&, HRESULT> {

- public:

-  CollectComponentsFunc(ProductData* product_data,

-                        bool is_machine)

-      : product_data_(product_data),

-        is_machine_(is_machine) {

-    ASSERT1(product_data);

-  }

-

-  // Ignores errors and accumulates as many components as possible.

-  HRESULT operator() (const CString& guid) {

-    AppManager app_manager(is_machine_);

-    AppData component_data;

-    if (SUCCEEDED(app_manager.ReadAppDataFromStore(

-        product_data_->app_data().app_guid(),

-        StringToGuid(guid),

-        &component_data))) {

-      product_data_->AddComponent(component_data);

-    }

-    return S_OK;

-  }

-

- private:

-  ProductData* product_data_;

-  bool is_machine_;

-};

-

-

-// Enumerates all sub keys of the key and calls the functor for each of them.

-template <typename T>

-HRESULT EnumerateSubKeys(const TCHAR* key_name, T* functor) {

-  RegKey client_key;

-  HRESULT hr = client_key.Open(key_name, KEY_READ);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  int num_sub_keys = client_key.GetSubkeyCount();

-  for (int i = 0; i < num_sub_keys; ++i) {

-    CString sub_key_name;

-    hr = client_key.GetSubkeyNameAt(i, &sub_key_name);

-    if (SUCCEEDED(hr)) {

-      (*functor)(sub_key_name);

-    }

-  }

-

-  return S_OK;

-}

-

-}  // namespace

-

-AppManager::AppManager(bool is_machine)

-    : is_machine_(is_machine) {

-  CORE_LOG(L3, (_T("[AppManager::AppManager][is_machine=%d]"), is_machine));

-}

-

-bool AppManager::IsProductRegistered(const GUID& app_guid) const {

-  IsAppRegisteredFunc func(GuidToString(app_guid));

-  HRESULT hr = EnumerateSubKeys(

-      ConfigManager::Instance()->registry_clients(is_machine_),

-      &func);

-  if (FAILED(hr)) {

-    return false;

-  }

-

-  return func.is_registered();

-}

-

-// TODO(omaha): Consider making AppManager a namespace.

-void AppManager::ConvertCommandLineToProductData(const CommandLineArgs& args,

-                                                 ProductDataVector* products) {

-  ASSERT1(products);

-

-  // TODO(omaha):  Need to update this to read the bundle info to build up

-  // multiple AppData objects (and also to read components) and add unit test.

-  for (size_t i = 0; i < args.extra.apps.size(); ++i) {

-    const CommandLineAppArgs& extra_arg = args.extra.apps[i];

-    AppData app_data(extra_arg.app_guid, is_machine_);

-    app_data.set_language(args.extra.language);

-    app_data.set_ap(extra_arg.ap);

-    app_data.set_tt_token(extra_arg.tt_token);

-    app_data.set_iid(args.extra.installation_id);

-    app_data.set_brand_code(args.extra.brand_code);

-    app_data.set_client_id(args.extra.client_id);

-    app_data.set_referral_id(args.extra.referral_id);

-    // Do not set install_time_diff_sec or is_oem_install because they are not

-    // based on the command line.

-    app_data.set_is_eula_accepted(!args.is_eula_required_set);

-    app_data.set_display_name(extra_arg.app_name);

-    app_data.set_browser_type(args.extra.browser_type);

-    app_data.set_install_source(args.install_source);

-    app_data.set_usage_stats_enable(args.extra.usage_stats_enable);

-    app_data.set_encoded_installer_data(extra_arg.encoded_installer_data);

-    app_data.set_install_data_index(extra_arg.install_data_index);

-

-    ProductData product_data(app_data);

-    products->push_back(product_data);

-  }

-

-  ASSERT1(products->size() == args.extra.apps.size());

-}

-

-

-HRESULT AppManager::GetRegisteredProducts(ProductDataVector* products) const {

-  ASSERT1(products);

-

-  CollectProductsFunc func(products, is_machine_, true);

-  return EnumerateSubKeys(

-      ConfigManager::Instance()->registry_clients(is_machine_),

-      &func);

-}

-

-HRESULT AppManager::GetUnRegisteredProducts(ProductDataVector* products) const {

-  ASSERT1(products);

-

-  CollectProductsFunc func(products, is_machine_, false);

-  return EnumerateSubKeys(

-      ConfigManager::Instance()->registry_client_state(is_machine_),

-      &func);

-}

-

-CString AppManager::GetProductClientKeyName(const GUID& app_guid) {

-  return goopdate_utils::GetAppClientsKey(is_machine_, GuidToString(app_guid));

-}

-

-CString AppManager::GetProductClientComponentsKeyName(const GUID& app_guid) {

-  return AppendRegKeyPath(GetProductClientKeyName(app_guid),

-                          kComponentsRegKeyName);

-}

-

-CString AppManager::GetProductClientStateComponentsKeyName(

-    const GUID& app_guid) {

-  return AppendRegKeyPath(GetProductClientStateKeyName(app_guid),

-                          kComponentsRegKeyName);

-}

-

-CString AppManager::GetComponentClientKeyName(const GUID& parent_app_guid,

-                                              const GUID& app_guid) {

-  return AppendRegKeyPath(GetProductClientComponentsKeyName(parent_app_guid),

-                          GuidToString(app_guid));

-}

-

-CString AppManager::GetProductClientStateKeyName(const GUID& app_guid) {

-  return goopdate_utils::GetAppClientStateKey(is_machine_,

-                                              GuidToString(app_guid));

-}

-

-CString AppManager::GetComponentClientStateKeyName(const GUID& parent_app_guid,

-                                                   const GUID& app_guid) {

-  return AppendRegKeyPath(

-      GetProductClientStateComponentsKeyName(parent_app_guid),

-      GuidToString(app_guid));

-}

-

-CString AppManager::GetProductClientStateMediumKeyName(const GUID& app_guid) {

-  ASSERT1(is_machine_);

-  return goopdate_utils::GetAppClientStateMediumKey(is_machine_,

-                                                    GuidToString(app_guid));

-}

-

-CString AppManager::GetClientKeyName(const GUID& parent_app_guid,

-                                     const GUID& app_guid) {

-  if (::IsEqualGUID(parent_app_guid, GUID_NULL)) {

-    return GetProductClientKeyName(app_guid);

-  } else {

-    return GetComponentClientKeyName(parent_app_guid, app_guid);

-  }

-}

-

-CString AppManager::GetClientStateKeyName(const GUID& parent_app_guid,

-                                          const GUID& app_guid) {

-  if (::IsEqualGUID(parent_app_guid, GUID_NULL)) {

-    return GetProductClientStateKeyName(app_guid);

-  } else {

-    return GetComponentClientStateKeyName(parent_app_guid, app_guid);

-  }

-}

-

-HRESULT AppManager::OpenClientKey(const GUID& parent_app_guid,

-                                  const GUID& app_guid,

-                                  RegKey* client_key) {

-  ASSERT1(client_key);

-  return client_key->Open(GetClientKeyName(parent_app_guid, app_guid),

-                          KEY_READ);

-}

-

-HRESULT AppManager::OpenClientStateKey(const GUID& parent_app_guid,

-                                       const GUID& app_guid,

-                                       REGSAM sam_desired,

-                                       RegKey* client_state_key) {

-  ASSERT1(client_state_key);

-  CString key_name = GetClientStateKeyName(parent_app_guid, app_guid);

-  return client_state_key->Open(key_name, sam_desired);

-}

-

-// Also creates the ClientStateMedium key for machine apps, ensuring it exists

-// whenever ClientState exists.  Does not create ClientStateMedium for Omaha.

-// This method is called for self-updates, so it must explicitly avoid this.

-HRESULT AppManager::CreateClientStateKey(const GUID& parent_app_guid,

-                                         const GUID& app_guid,

-                                         RegKey* client_state_key) {

-  ASSERT(::IsEqualGUID(parent_app_guid, GUID_NULL),

-         (_T("Legacy components not supported; ClientStateMedium ignores.")));

-

-  ASSERT1(client_state_key);

-  const CString key_name = GetClientStateKeyName(parent_app_guid, app_guid);

-  HRESULT hr = client_state_key->Create(key_name);

-  if (FAILED(hr)) {

-    CORE_LOG(L3, (_T("[RegKey::Create failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (!is_machine_) {

-    return S_OK;

-  }

-

-  if (::IsEqualGUID(kGoopdateGuid, app_guid)) {

-    return S_OK;

-  }

-

-  const CString medium_key_name = GetProductClientStateMediumKeyName(app_guid);

-  hr = RegKey::CreateKey(medium_key_name);

-  if (FAILED(hr)) {

-    CORE_LOG(L3, (_T("[RegKey::Create ClientStateMedium failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// Reads the following values from the registry:

-// Clients Key

-//   product version

-//   language

-// Client State Key

-//   previous product version.

-//   last checked

-//   ap

-//   client id

-//   iid

-// Clients key in HKCU/HKLM/Low integrity

-//   did run

-// Note: If the application is uninstalled, the clients key may not exist.

-HRESULT AppManager::ReadProductDataFromStore(const GUID& app_guid,

-                                             ProductData* product_data) {

-  ASSERT1(product_data);

-

-  AppData app_data;

-  HRESULT hr = ReadAppDataFromStore(GUID_NULL, app_guid, &app_data);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[AppManager::ReadAppDataFromStore failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  ProductData product(app_data);

-

-  // Read components for this product from the registry.

-  CollectComponentsFunc func(&product, is_machine_);

-  EnumerateSubKeys(GetProductClientComponentsKeyName(app_data.app_guid()),

-                   &func);

-

-  *product_data = product;

-  return S_OK;

-}

-

-HRESULT AppManager::ReadAppDataFromStore(const GUID& parent_app_guid,

-                                         const GUID& app_guid,

-                                         AppData* app_data) {

-  ASSERT1(app_data);

-  AppData temp_data(app_guid, is_machine_);

-  temp_data.set_parent_app_guid(parent_app_guid);

-

-  bool client_key_exists = false;

-  RegKey client_key;

-  HRESULT hr = OpenClientKey(parent_app_guid, app_guid, &client_key);

-  if (SUCCEEDED(hr)) {

-    CString version;

-    hr = client_key.GetValue(kRegValueProductVersion, &version);

-    temp_data.set_version(version);

-    CORE_LOG(L3, (_T("[AppManager::ReadAppDataFromStore]")

-                  _T("[parent_app_guid=%s]")

-                  _T("[app_guid=%s]")

-                  _T("[version=%s]"),

-                  GuidToString(parent_app_guid),

-                  GuidToString(app_guid),

-                  version));

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    // Language might not be written by an installer, so ignore failures.

-    CString language;

-    client_key.GetValue(kRegValueLanguage, &language);

-    temp_data.set_language(language);

-    client_key_exists = true;

-  }

-

-  RegKey client_state_key;

-  hr = OpenClientStateKey(parent_app_guid,

-                          app_guid,

-                          KEY_READ,

-                          &client_state_key);

-  if (FAILED(hr)) {

-    // It is possible that the client state key has not yet been populated.

-    // In this case just return the information that we have gathered thus far.

-    // However if both keys dont exist, then we are doing something wrong.

-    CORE_LOG(LW, (_T("[AppManager::ReadAppDataFromStore - No ClientState]")));

-    if (client_key_exists) {

-      *app_data = temp_data;

-      return S_OK;

-    } else {

-      return hr;

-    }

-  }

-

-  // The value is not essential for omaha's operation, so ignore errors.

-  CString previous_version;

-  HRESULT previous_version_hr =

-      client_state_key.GetValue(kRegValueProductVersion, &previous_version);

-  temp_data.set_previous_version(previous_version);

-

-  // An app is uninstalled if the Client key exists and the pv value in the

-  // ClientState key does not exist.

-  // Omaha may create the app's ClientState key and write values from the

-  // metainstaller tag before running the installer, which creates the Client

-  // key. Requiring pv in ClientState avoids mistakenly determining that the

-  // Omaha-created key indicates an uninstall.

-  bool app_is_uninstalled =

-      !client_key_exists &&

-      HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != previous_version_hr;

-  temp_data.set_is_uninstalled(app_is_uninstalled);

-

-  CString ap;

-  client_state_key.GetValue(kRegValueAdditionalParams, &ap);

-  temp_data.set_ap(ap);

-

-  CString tt_token;

-  client_state_key.GetValue(kRegValueTTToken, &tt_token);

-  temp_data.set_tt_token(tt_token);

-

-  CString iid;

-  client_state_key.GetValue(kRegValueInstallationId, &iid);

-  temp_data.set_iid(StringToGuid(iid));

-

-  CString brand_code;

-  client_state_key.GetValue(kRegValueBrandCode, &brand_code);

-  ASSERT1(brand_code.GetLength() <= kBrandIdLength);

-  temp_data.set_brand_code(brand_code);

-

-  CString client_id;

-  client_state_key.GetValue(kRegValueClientId, &client_id);

-  temp_data.set_client_id(client_id);

-

-  // We do not need the referral_id.

-

-  // Get the install time and calculate the elapsed time since then if is valid.

-  DWORD install_time(0);

-  if (SUCCEEDED(client_state_key.GetValue(kRegValueInstallTimeSec,

-                                          &install_time))) {

-    const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-    if (0 != install_time && now >= install_time) {

-      temp_data.set_install_time_diff_sec(now - install_time);

-    }

-  }

-

-  temp_data.set_is_oem_install(client_state_key.HasValue(kRegValueOemInstall));

-

-  bool is_eula_accepted = true;

-  DWORD eula_accepted = 0;

-

-  ASSERT(::IsEqualGUID(parent_app_guid, GUID_NULL),

-         (_T("Legacy components not supported; IsAppEulaAccepted ignores.")));

-  temp_data.set_is_eula_accepted(

-      goopdate_utils::IsAppEulaAccepted(is_machine_,

-                                        GuidToString(app_guid),

-                                        false));

-

-  if (temp_data.language().IsEmpty()) {

-    // Read the language from the client state key if we did not find

-    // it in the client key.

-    CString language;

-    client_state_key.GetValue(kRegValueLanguage, &language);

-    temp_data.set_language(language);

-  }

-

-  // Read the did run value.

-  // TODO(omaha): Try to move this logic into the application_usage_data class.

-  ApplicationUsageData app_usage(is_machine_, vista_util::IsVistaOrLater());

-  hr = app_usage.ReadDidRun(GuidToString(app_guid));

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_WARNING, (_T("[ReadDidRun failed][0x%08x]"), hr));

-  }

-  AppData::ActiveStates active = AppData::ACTIVE_NOTRUN;

-  if (app_usage.exists()) {

-    active = app_usage.did_run() ? AppData::ACTIVE_RUN :

-                                   AppData::ACTIVE_NOTRUN;

-  } else {

-    active = AppData::ACTIVE_UNKNOWN;

-  }

-  temp_data.set_did_run(active);

-

-  *app_data = temp_data;

-  return S_OK;

-}

-

-// Sets brand code, client ID, usage stats, browser, ap, and Omaha language in

-// the app's ClientState. Also, sets the installed by OEM flag if appropriate.

-// Sets eulaaccepted=0 if the app is not already registered and the app's EULA

-// has not been accepted. Deletes eulaaccepted if the EULA has been accepted.

-// Only call for initial or over-installs. Do not call for updates to avoid

-// mistakenly replacing data, such as the application's language, and causing

-// unexpected changes to the app during a silent update.

-HRESULT AppManager::WritePreInstallData(const AppData& app_data) {

-  CORE_LOG(L3, (_T("[AppManager::WritePreInstallData]")));

-

-  RegKey client_state_key;

-  HRESULT hr = CreateClientStateKey(app_data.parent_app_guid(),

-                                    app_data.app_guid(),

-                                    &client_state_key);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (app_data.is_eula_accepted()) {

-    hr = goopdate_utils::ClearAppEulaNotAccepted(

-             is_machine_,

-             GuidToString(app_data.app_guid()));

-  } else {

-    if (!IsProductRegistered(app_data.app_guid())) {

-      hr = goopdate_utils::SetAppEulaNotAccepted(

-               is_machine_,

-               GuidToString(app_data.app_guid()));

-    }

-  }

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString state_key_path = GetClientStateKeyName(app_data.parent_app_guid(),

-                                                 app_data.app_guid());

-  VERIFY1(SUCCEEDED(goopdate_utils::SetAppBranding(state_key_path,

-                                                   app_data.brand_code(),

-                                                   app_data.client_id(),

-                                                   app_data.referral_id())));

-

-  ASSERT(::IsEqualGUID(app_data.parent_app_guid(), GUID_NULL),

-         (_T("Legacy components not supported; SetUsageStatsEnable ignores.")));

-  if (TRISTATE_NONE != app_data.usage_stats_enable()) {

-    VERIFY1(SUCCEEDED(goopdate_utils::SetUsageStatsEnable(

-                          is_machine_,

-                          GuidToString(app_data.app_guid()),

-                          app_data.usage_stats_enable())));

-  }

-

-  if (BROWSER_UNKNOWN == app_data.browser_type()) {

-    VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueBrowser)));

-  } else {

-    DWORD browser_type = app_data.browser_type();

-    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueBrowser,

-                                                browser_type)));

-  }

-

-  if (app_data.ap().IsEmpty()) {

-    VERIFY1(SUCCEEDED(

-        client_state_key.DeleteValue(kRegValueAdditionalParams)));

-  } else {

-    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueAdditionalParams,

-                                                app_data.ap())));

-  }

-

-  if (!app_data.language().IsEmpty()) {

-    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueLanguage,

-                                                app_data.language())));

-  }

-

-  if (ConfigManager::Instance()->IsOemInstalling(is_machine_)) {

-    ASSERT1(is_machine_);

-    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueOemInstall, _T("1"))));

-  }

-

-  return S_OK;

-}

-

-// Sets installation ID in the app's ClientState.

-// Copies version and language from clients to client state reg key.

-HRESULT AppManager::InitializeApplicationState(AppData* app_data) {

-  CORE_LOG(L3, (_T("[AppManager::InitializeApplicationState]")));

-  ASSERT1(app_data);

-  RegKey client_state_key;

-  HRESULT hr = CreateClientStateKey(app_data->parent_app_guid(),

-                                    app_data->app_guid(),

-                                    &client_state_key);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  RegKey client_key;

-  hr = OpenClientKey(app_data->parent_app_guid(),

-                     app_data->app_guid(),

-                     &client_key);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (!::IsEqualGUID(app_data->iid(), GUID_NULL)) {

-    VERIFY1(SUCCEEDED(client_state_key.SetValue(

-                          kRegValueInstallationId,

-                          GuidToString(app_data->iid()))));

-  }

-

-  return CopyVersionAndLanguageToClientState(app_data,

-                                             client_state_key,

-                                             client_key);

-}

-

-// Copies language and version from clients into client state reg key.

-// Removes installation id, if did run = true or if goopdate.

-// Clears did run.

-HRESULT AppManager::UpdateApplicationState(AppData* app_data) {

-  ASSERT1(app_data);

-  RegKey client_state_key;

-  HRESULT hr = CreateClientStateKey(app_data->parent_app_guid(),

-                                    app_data->app_guid(),

-                                    &client_state_key);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  RegKey client_key;

-  hr = OpenClientKey(app_data->parent_app_guid(),

-                     app_data->app_guid(),

-                     &client_key);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = CopyVersionAndLanguageToClientState(app_data,

-                                           client_state_key,

-                                           client_key);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Handle the installation id.

-  hr = ClearInstallationId(app_data, client_state_key);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // Clear the did run value.

-  ApplicationUsageData app_usage(app_data->is_machine_app(),

-                                 vista_util::IsVistaOrLater());

-  VERIFY1(SUCCEEDED(app_usage.ResetDidRun(GuidToString(app_data->app_guid()))));

-  app_data->set_did_run(app_usage.exists() ? AppData::ACTIVE_NOTRUN :

-                                             AppData::ACTIVE_UNKNOWN);

-  return S_OK;

-}

-

-HRESULT AppManager::WriteTTToken(const AppData& app_data,

-                                 const UpdateResponseData& response_data) {

-  CORE_LOG(L3, (_T("[WriteTTToken][app_data token=%s][response_data token=%s]"),

-                app_data.tt_token(), response_data.tt_token()));

-  RegKey client_state_key;

-  HRESULT hr = CreateClientStateKey(app_data.parent_app_guid(),

-                                    app_data.app_guid(),

-                                    &client_state_key);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (response_data.tt_token().IsEmpty()) {

-    VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueTTToken)));

-  } else {

-    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueTTToken,

-                                                response_data.tt_token())));

-  }

-

-  return S_OK;

-}

-

-// The registry reads and writes are not thread safe, but there should not be

-// other threads or processes calling this at the same time.

-void AppManager::UpdateUpdateAvailableStats(const GUID& parent_app_guid,

-                                            const GUID& app_guid) {

-  RegKey state_key;

-  HRESULT hr = CreateClientStateKey(parent_app_guid, app_guid, &state_key);

-  if (FAILED(hr)) {

-    ASSERT1(false);

-    return;

-  }

-

-  DWORD update_available_count(0);

-  hr = state_key.GetValue(kRegValueUpdateAvailableCount,

-                          &update_available_count);

-  if (FAILED(hr)) {

-    update_available_count = 0;

-  }

-  ++update_available_count;

-  VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueUpdateAvailableCount,

-                                       update_available_count)));

-

-  DWORD64 update_available_since_time(0);

-  hr = state_key.GetValue(kRegValueUpdateAvailableSince,

-                          &update_available_since_time);

-  if (FAILED(hr)) {

-    // There is no existing value, so this must be the first update notice.

-    VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueUpdateAvailableSince,

-                                         GetCurrent100NSTime())));

-

-    // TODO(omaha): It would be nice to report the version that we were first

-    // told to update to. This is available in UpdateResponse but we do not

-    // currently send it down in update responses. If we start using it, add

-    // kRegValueFirstUpdateResponseVersion.

-  }

-}

-

-void AppManager::ClearUpdateAvailableStats(const GUID& parent_app_guid,

-                                           const GUID& app_guid) {

-  RegKey state_key;

-  HRESULT hr =

-      OpenClientStateKey(parent_app_guid, app_guid, KEY_ALL_ACCESS, &state_key);

-  if (FAILED(hr)) {

-    return;

-  }

-

-  VERIFY1(SUCCEEDED(state_key.DeleteValue(kRegValueUpdateAvailableCount)));

-  VERIFY1(SUCCEEDED(state_key.DeleteValue(kRegValueUpdateAvailableSince)));

-}

-

-void AppManager::ClearOemInstalled(const GUID& parent_app_guid,

-                                   const GUID& app_guid) {

-  RegKey state_key;

-  HRESULT hr =

-      OpenClientStateKey(parent_app_guid, app_guid, KEY_ALL_ACCESS, &state_key);

-  ASSERT1(SUCCEEDED(hr));

-  if (FAILED(hr)) {

-    return;

-  }

-

-  VERIFY1(SUCCEEDED(state_key.DeleteValue(kRegValueOemInstall)));

-}

-

-// Returns 0 for any values that are not found.

-void AppManager::ReadUpdateAvailableStats(

-    const GUID& parent_app_guid,

-    const GUID& app_guid,

-    DWORD* update_responses,

-    DWORD64* time_since_first_response_ms) {

-  ASSERT1(update_responses);

-  ASSERT1(time_since_first_response_ms);

-  *update_responses = 0;

-  *time_since_first_response_ms = 0;

-

-  RegKey state_key;

-  HRESULT hr = OpenClientStateKey(parent_app_guid,

-                                  app_guid,

-                                  KEY_READ,

-                                  &state_key);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[App ClientState key does not exist][%s]"),

-                  GuidToString(app_guid)));

-    return;

-  }

-

-  DWORD update_responses_in_reg(0);

-  hr = state_key.GetValue(kRegValueUpdateAvailableCount,

-                          &update_responses_in_reg);

-  if (SUCCEEDED(hr)) {

-    *update_responses = update_responses_in_reg;

-  }

-

-  DWORD64 update_available_since_time(0);

-  hr = state_key.GetValue(kRegValueUpdateAvailableSince,

-                          &update_available_since_time);

-  if (SUCCEEDED(hr)) {

-    const DWORD64 current_time = GetCurrent100NSTime();

-    ASSERT1(update_available_since_time <= current_time);

-    const DWORD64 time_since_first_response_in_100ns =

-        current_time - update_available_since_time;

-    *time_since_first_response_ms =

-        time_since_first_response_in_100ns / kMillisecsTo100ns;

-  }

-}

-

-// The update success and update check success times are not updated for

-// installs even if it is an over-install. At this point, we do not know for

-// sure that it was an online update.

-void AppManager::RecordSuccessfulInstall(const GUID& parent_app_guid,

-                                         const GUID& app_guid,

-                                         bool is_update,

-                                         bool is_offline) {

-  ASSERT1(!is_update || !is_offline);

-

-  ClearUpdateAvailableStats(parent_app_guid, app_guid);

-

-  if (!is_offline) {

-    // Assumes that all updates are online.

-    RecordSuccessfulUpdateCheck(parent_app_guid, app_guid);

-  }

-

-  if (is_update) {

-    RegKey state_key;

-    HRESULT hr = CreateClientStateKey(parent_app_guid, app_guid, &state_key);

-    if (FAILED(hr)) {

-      ASSERT1(false);

-      return;

-    }

-

-    const DWORD now = Time64ToInt32(GetCurrent100NSTime());

-    VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueLastUpdateTimeSec, now)));

-  }

-}

-

-void AppManager::RecordSuccessfulUpdateCheck(const GUID& parent_app_guid,

-                                             const GUID& app_guid) {

-  RegKey state_key;

-  HRESULT hr = CreateClientStateKey(parent_app_guid, app_guid, &state_key);

-  if (FAILED(hr)) {

-    ASSERT1(false);

-    return;

-  }

-

-  const DWORD now = Time64ToInt32(GetCurrent100NSTime());

-  VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueLastSuccessfulCheckSec, now)));

-}

-

-HRESULT AppManager::ClearInstallationId(AppData* app_data,

-                                        const RegKey& client_state_key) {

-  ASSERT1(app_data);

-  // First run is the last time we want to use the Installation ID.

-  // For apps, delete Installation ID if it is present and DidRun==yes.

-  // For Omaha, always delete Installation ID if it is present because

-  // DidRun does not apply.

-  if (!::IsEqualGUID(app_data->iid(), GUID_NULL) &&

-      ((AppData::ACTIVE_RUN == app_data->did_run()) ||

-       (::IsEqualGUID(kGoopdateGuid, app_data->app_guid())))) {

-    CORE_LOG(L1, (_T("[Deleting iid for app][%s]"),

-                  GuidToString(app_data->app_guid())));

-    // Relies on installation_id not empty to indicate state_key is valid.

-    VERIFY1(S_OK == client_state_key.DeleteValue(kRegValueInstallationId));

-    app_data->set_iid(GUID_NULL);

-  }

-

-  return S_OK;

-}

-

-// Only replaces the language in ClientState and app_data if the language in

-// Clients is not empty.

-HRESULT AppManager::CopyVersionAndLanguageToClientState(

-    AppData* app_data,

-    const RegKey& client_state_key,

-    const RegKey& client_key) {

-  // TODO(omaha):  need to handle components too.

-  ASSERT1(app_data);

-  // Read the version and language from the client key.

-  CString version;

-  HRESULT hr = client_key.GetValue(kRegValueProductVersion, &version);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString language;

-  client_key.GetValue(kRegValueLanguage, &language);

-

-  // Write the version and language in the client state key.

-  hr = client_state_key.SetValue(kRegValueProductVersion, version);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  app_data->set_version(version);

-  app_data->set_previous_version(version);

-

-  if (!language.IsEmpty()) {

-    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueLanguage,

-                                                language)));

-    app_data->set_language(language);

-  }

-

-  return S_OK;

-}

-

-HRESULT AppManager::RemoveClientState(const AppData& app_data) {

-  ASSERT(::IsEqualGUID(app_data.parent_app_guid(), GUID_NULL),

-         (_T("Legacy components not supported; ClientStateMedium ignores.")));

-

-  ASSERT1(app_data.is_uninstalled());

-  const CString state_key = GetClientStateKeyName(app_data.parent_app_guid(),

-                                                  app_data.app_guid());

-  HRESULT state_hr = RegKey::DeleteKey(state_key, true);

-

-  if (!is_machine_) {

-    return state_hr;

-  }

-

-  const CString state_medium_key =

-      GetProductClientStateMediumKeyName(app_data.app_guid());

-  HRESULT state_medium_hr = RegKey::DeleteKey(state_medium_key, true);

-

-  return FAILED(state_hr) ? state_hr : state_medium_hr;

-}

-

-// Returns true if the absolute difference between time moments is greater than

-// the interval between update checks.

-// Deals with clocks rolling backwards, in scenarios where the clock indicates

-// some time in the future, for example next year, last_checked_ is updated to

-// reflect that time, and then the clock is adjusted back to present.

-bool AppManager::ShouldCheckForUpdates() const {

-  ConfigManager* cm = ConfigManager::Instance();

-  bool is_period_overridden = false;

-  const int update_interval = cm->GetLastCheckPeriodSec(&is_period_overridden);

-  if (0 == update_interval) {

-    ASSERT1(is_period_overridden);

-    OPT_LOG(L1, (_T("[ShouldCheckForUpdates returned 0][checks disabled]")));

-    return false;

-  }

-

-  const int time_difference = cm->GetTimeSinceLastCheckedSec(is_machine_);

-

-  const bool result = time_difference >= update_interval ? true : false;

-  CORE_LOG(L3, (_T("[ShouldCheckForUpdates returned %d][%u]"),

-                result, is_period_overridden));

-  return result;

-}

-

-HRESULT AppManager::UpdateLastChecked() {

-  // Set the last check value to the current value.

-  DWORD now = Time64ToInt32(GetCurrent100NSTime());

-  HRESULT hr = ConfigManager::Instance()->SetLastCheckedTime(is_machine_, now);

-  CORE_LOG(L3, (_T("[AppManager::UpdateLastChecked][now %d]"), now));

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[UpdateLastChecked returned 0x%08x]"), hr));

-    return hr;

-  }

-  return S_OK;

-}

-

-HRESULT AppManager::ReadProductDataFromUserOrMachineStore(

-    const GUID& guid,

-    ProductData* product_data) {

-  ASSERT1(product_data);

-  AppManager app_manager_user(false);

-  HRESULT hr = app_manager_user.ReadProductDataFromStore(guid, product_data);

-  if (SUCCEEDED(hr)) {

-    return hr;

-  }

-

-  AppManager app_manager_machine(true);

-  return app_manager_machine.ReadProductDataFromStore(guid, product_data);

-}

-

-// Writes 0.0.0.1 to pv. This value avoids any special cases, such as initial

-// install rules, for 0.0.0.0, while being unlikely to be higher than the

-// product's actual current version.

-HRESULT AppManager::RegisterProduct(const GUID& product_guid,

-                                    const CString& product_name) {

-  const TCHAR* const kRegisterProductVersion = _T("0.0.0.1");

-

-  RegKey client_key;

-  HRESULT hr = client_key.Create(GetClientKeyName(GUID_NULL, product_guid));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = client_key.SetValue(kRegValueProductVersion, kRegisterProductVersion);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // AppName is not a required parameter since it's only used for being able to

-  // easily tell what application is there when reading the registry.

-  VERIFY1(SUCCEEDED(client_key.SetValue(kRegValueAppName, product_name)));

-

-  return S_OK;

-}

-

-HRESULT AppManager::UnregisterProduct(const GUID& product_guid) {

-  return RegKey::DeleteKey(GetClientKeyName(GUID_NULL, product_guid), true);

-}

-

-}  // namespace omaha.

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// Contains the logic to encapsulate access to the application data
+// stored in the registry.
+
+#include "omaha/worker/application_manager.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <functional>
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/worker/application_usage_data.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/job.h"
+
+namespace omaha {
+
+namespace {
+
+// Determines if an application is registered with Google Update.
+class IsAppRegisteredFunc
+    : public std::unary_function<const CString&, HRESULT> {
+ public:
+  explicit IsAppRegisteredFunc(const CString& guid)
+      : is_registered_(false),
+        guid_(guid) {}
+
+  bool is_registered() const { return is_registered_; }
+
+  HRESULT operator() (const CString& guid) {
+    if (guid.CompareNoCase(guid_) == 0) {
+      is_registered_ = true;
+    }
+    return S_OK;
+  }
+ private:
+  CString guid_;
+  bool is_registered_;
+};
+
+// Accumulates ProductData.
+class CollectProductsFunc
+    : public std::unary_function<const CString&, HRESULT> {
+ public:
+  CollectProductsFunc(ProductDataVector* products,
+                      bool is_machine,
+                      bool collect_registered_products)
+      : products_(products),
+        is_machine_(is_machine),
+        collect_registered_products_(collect_registered_products) {
+    ASSERT1(products);
+  }
+
+  // Ignores errors and accumulates as many applications as possible.
+  HRESULT operator() (const CString& guid) {
+    AppManager app_manager(is_machine_);
+    ProductData product_data;
+    if (SUCCEEDED(app_manager.ReadProductDataFromStore(StringToGuid(guid),
+                                                       &product_data))) {
+      ASSERT(!collect_registered_products_ ||
+             !product_data.app_data().is_uninstalled(),
+             (_T("Should not be finding uninstalled apps while looking for ")
+              _T("registered apps; may be enumerating the wrong key.")));
+      if (collect_registered_products_ ||
+          product_data.app_data().is_uninstalled()) {
+        CORE_LOG(L3, (_T("[Found %s product][%s]"),
+                      collect_registered_products_ ? _T("registered") :
+                                                      _T("uninstalled"),
+                      guid));
+        products_->push_back(product_data);
+      }
+    }
+    return S_OK;
+  }
+
+ private:
+  bool collect_registered_products_;
+  bool is_machine_;
+  ProductDataVector* products_;
+};
+
+// Accumulates AppData for components of a product.
+class CollectComponentsFunc
+    : public std::unary_function<const CString&, HRESULT> {
+ public:
+  CollectComponentsFunc(ProductData* product_data,
+                        bool is_machine)
+      : product_data_(product_data),
+        is_machine_(is_machine) {
+    ASSERT1(product_data);
+  }
+
+  // Ignores errors and accumulates as many components as possible.
+  HRESULT operator() (const CString& guid) {
+    AppManager app_manager(is_machine_);
+    AppData component_data;
+    if (SUCCEEDED(app_manager.ReadAppDataFromStore(
+        product_data_->app_data().app_guid(),
+        StringToGuid(guid),
+        &component_data))) {
+      product_data_->AddComponent(component_data);
+    }
+    return S_OK;
+  }
+
+ private:
+  ProductData* product_data_;
+  bool is_machine_;
+};
+
+
+// Enumerates all sub keys of the key and calls the functor for each of them.
+template <typename T>
+HRESULT EnumerateSubKeys(const TCHAR* key_name, T* functor) {
+  RegKey client_key;
+  HRESULT hr = client_key.Open(key_name, KEY_READ);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  int num_sub_keys = client_key.GetSubkeyCount();
+  for (int i = 0; i < num_sub_keys; ++i) {
+    CString sub_key_name;
+    hr = client_key.GetSubkeyNameAt(i, &sub_key_name);
+    if (SUCCEEDED(hr)) {
+      (*functor)(sub_key_name);
+    }
+  }
+
+  return S_OK;
+}
+
+}  // namespace
+
+AppManager::AppManager(bool is_machine)
+    : is_machine_(is_machine) {
+  CORE_LOG(L3, (_T("[AppManager::AppManager][is_machine=%d]"), is_machine));
+}
+
+bool AppManager::IsProductRegistered(const GUID& app_guid) const {
+  IsAppRegisteredFunc func(GuidToString(app_guid));
+  HRESULT hr = EnumerateSubKeys(
+      ConfigManager::Instance()->registry_clients(is_machine_),
+      &func);
+  if (FAILED(hr)) {
+    return false;
+  }
+
+  return func.is_registered();
+}
+
+// TODO(omaha): Consider making AppManager a namespace.
+void AppManager::ConvertCommandLineToProductData(const CommandLineArgs& args,
+                                                 ProductDataVector* products) {
+  ASSERT1(products);
+
+  // TODO(omaha):  Need to update this to read the bundle info to build up
+  // multiple AppData objects (and also to read components) and add unit test.
+  for (size_t i = 0; i < args.extra.apps.size(); ++i) {
+    const CommandLineAppArgs& extra_arg = args.extra.apps[i];
+    AppData app_data(extra_arg.app_guid, is_machine_);
+    app_data.set_language(args.extra.language);
+    app_data.set_ap(extra_arg.ap);
+    app_data.set_tt_token(extra_arg.tt_token);
+    app_data.set_iid(args.extra.installation_id);
+    app_data.set_brand_code(args.extra.brand_code);
+    app_data.set_client_id(args.extra.client_id);
+    app_data.set_referral_id(args.extra.referral_id);
+    // Do not set install_time_diff_sec or is_oem_install because they are not
+    // based on the command line.
+    app_data.set_is_eula_accepted(!args.is_eula_required_set);
+    app_data.set_display_name(extra_arg.app_name);
+    app_data.set_browser_type(args.extra.browser_type);
+    app_data.set_install_source(args.install_source);
+    app_data.set_usage_stats_enable(args.extra.usage_stats_enable);
+    app_data.set_encoded_installer_data(extra_arg.encoded_installer_data);
+    app_data.set_install_data_index(extra_arg.install_data_index);
+
+    ProductData product_data(app_data);
+    products->push_back(product_data);
+  }
+
+  ASSERT1(products->size() == args.extra.apps.size());
+}
+
+
+HRESULT AppManager::GetRegisteredProducts(ProductDataVector* products) const {
+  ASSERT1(products);
+
+  CollectProductsFunc func(products, is_machine_, true);
+  return EnumerateSubKeys(
+      ConfigManager::Instance()->registry_clients(is_machine_),
+      &func);
+}
+
+HRESULT AppManager::GetUnRegisteredProducts(ProductDataVector* products) const {
+  ASSERT1(products);
+
+  CollectProductsFunc func(products, is_machine_, false);
+  return EnumerateSubKeys(
+      ConfigManager::Instance()->registry_client_state(is_machine_),
+      &func);
+}
+
+CString AppManager::GetProductClientKeyName(const GUID& app_guid) {
+  return goopdate_utils::GetAppClientsKey(is_machine_, GuidToString(app_guid));
+}
+
+CString AppManager::GetProductClientComponentsKeyName(const GUID& app_guid) {
+  return AppendRegKeyPath(GetProductClientKeyName(app_guid),
+                          kComponentsRegKeyName);
+}
+
+CString AppManager::GetProductClientStateComponentsKeyName(
+    const GUID& app_guid) {
+  return AppendRegKeyPath(GetProductClientStateKeyName(app_guid),
+                          kComponentsRegKeyName);
+}
+
+CString AppManager::GetComponentClientKeyName(const GUID& parent_app_guid,
+                                              const GUID& app_guid) {
+  return AppendRegKeyPath(GetProductClientComponentsKeyName(parent_app_guid),
+                          GuidToString(app_guid));
+}
+
+CString AppManager::GetProductClientStateKeyName(const GUID& app_guid) {
+  return goopdate_utils::GetAppClientStateKey(is_machine_,
+                                              GuidToString(app_guid));
+}
+
+CString AppManager::GetComponentClientStateKeyName(const GUID& parent_app_guid,
+                                                   const GUID& app_guid) {
+  return AppendRegKeyPath(
+      GetProductClientStateComponentsKeyName(parent_app_guid),
+      GuidToString(app_guid));
+}
+
+CString AppManager::GetProductClientStateMediumKeyName(const GUID& app_guid) {
+  ASSERT1(is_machine_);
+  return goopdate_utils::GetAppClientStateMediumKey(is_machine_,
+                                                    GuidToString(app_guid));
+}
+
+CString AppManager::GetClientKeyName(const GUID& parent_app_guid,
+                                     const GUID& app_guid) {
+  if (::IsEqualGUID(parent_app_guid, GUID_NULL)) {
+    return GetProductClientKeyName(app_guid);
+  } else {
+    return GetComponentClientKeyName(parent_app_guid, app_guid);
+  }
+}
+
+CString AppManager::GetClientStateKeyName(const GUID& parent_app_guid,
+                                          const GUID& app_guid) {
+  if (::IsEqualGUID(parent_app_guid, GUID_NULL)) {
+    return GetProductClientStateKeyName(app_guid);
+  } else {
+    return GetComponentClientStateKeyName(parent_app_guid, app_guid);
+  }
+}
+
+HRESULT AppManager::OpenClientKey(const GUID& parent_app_guid,
+                                  const GUID& app_guid,
+                                  RegKey* client_key) {
+  ASSERT1(client_key);
+  return client_key->Open(GetClientKeyName(parent_app_guid, app_guid),
+                          KEY_READ);
+}
+
+HRESULT AppManager::OpenClientStateKey(const GUID& parent_app_guid,
+                                       const GUID& app_guid,
+                                       REGSAM sam_desired,
+                                       RegKey* client_state_key) {
+  ASSERT1(client_state_key);
+  CString key_name = GetClientStateKeyName(parent_app_guid, app_guid);
+  return client_state_key->Open(key_name, sam_desired);
+}
+
+// Also creates the ClientStateMedium key for machine apps, ensuring it exists
+// whenever ClientState exists.  Does not create ClientStateMedium for Omaha.
+// This method is called for self-updates, so it must explicitly avoid this.
+HRESULT AppManager::CreateClientStateKey(const GUID& parent_app_guid,
+                                         const GUID& app_guid,
+                                         RegKey* client_state_key) {
+  ASSERT(::IsEqualGUID(parent_app_guid, GUID_NULL),
+         (_T("Legacy components not supported; ClientStateMedium ignores.")));
+
+  ASSERT1(client_state_key);
+  const CString key_name = GetClientStateKeyName(parent_app_guid, app_guid);
+  HRESULT hr = client_state_key->Create(key_name);
+  if (FAILED(hr)) {
+    CORE_LOG(L3, (_T("[RegKey::Create failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (!is_machine_) {
+    return S_OK;
+  }
+
+  if (::IsEqualGUID(kGoopdateGuid, app_guid)) {
+    return S_OK;
+  }
+
+  const CString medium_key_name = GetProductClientStateMediumKeyName(app_guid);
+  hr = RegKey::CreateKey(medium_key_name);
+  if (FAILED(hr)) {
+    CORE_LOG(L3, (_T("[RegKey::Create ClientStateMedium failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// Reads the following values from the registry:
+// Clients Key
+//   product version
+//   language
+// Client State Key
+//   previous product version.
+//   last checked
+//   ap
+//   client id
+//   iid
+// Clients key in HKCU/HKLM/Low integrity
+//   did run
+// Note: If the application is uninstalled, the clients key may not exist.
+HRESULT AppManager::ReadProductDataFromStore(const GUID& app_guid,
+                                             ProductData* product_data) {
+  ASSERT1(product_data);
+
+  AppData app_data;
+  HRESULT hr = ReadAppDataFromStore(GUID_NULL, app_guid, &app_data);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[AppManager::ReadAppDataFromStore failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  ProductData product(app_data);
+
+  // Read components for this product from the registry.
+  CollectComponentsFunc func(&product, is_machine_);
+  EnumerateSubKeys(GetProductClientComponentsKeyName(app_data.app_guid()),
+                   &func);
+
+  *product_data = product;
+  return S_OK;
+}
+
+HRESULT AppManager::ReadAppDataFromStore(const GUID& parent_app_guid,
+                                         const GUID& app_guid,
+                                         AppData* app_data) {
+  ASSERT1(app_data);
+  AppData temp_data(app_guid, is_machine_);
+  temp_data.set_parent_app_guid(parent_app_guid);
+
+  bool client_key_exists = false;
+  RegKey client_key;
+  HRESULT hr = OpenClientKey(parent_app_guid, app_guid, &client_key);
+  if (SUCCEEDED(hr)) {
+    CString version;
+    hr = client_key.GetValue(kRegValueProductVersion, &version);
+    temp_data.set_version(version);
+    CORE_LOG(L3, (_T("[AppManager::ReadAppDataFromStore]")
+                  _T("[parent_app_guid=%s]")
+                  _T("[app_guid=%s]")
+                  _T("[version=%s]"),
+                  GuidToString(parent_app_guid),
+                  GuidToString(app_guid),
+                  version));
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    // Language might not be written by an installer, so ignore failures.
+    CString language;
+    client_key.GetValue(kRegValueLanguage, &language);
+    temp_data.set_language(language);
+    client_key_exists = true;
+  }
+
+  RegKey client_state_key;
+  hr = OpenClientStateKey(parent_app_guid,
+                          app_guid,
+                          KEY_READ,
+                          &client_state_key);
+  if (FAILED(hr)) {
+    // It is possible that the client state key has not yet been populated.
+    // In this case just return the information that we have gathered thus far.
+    // However if both keys dont exist, then we are doing something wrong.
+    CORE_LOG(LW, (_T("[AppManager::ReadAppDataFromStore - No ClientState]")));
+    if (client_key_exists) {
+      *app_data = temp_data;
+      return S_OK;
+    } else {
+      return hr;
+    }
+  }
+
+  // The value is not essential for omaha's operation, so ignore errors.
+  CString previous_version;
+  HRESULT previous_version_hr =
+      client_state_key.GetValue(kRegValueProductVersion, &previous_version);
+  temp_data.set_previous_version(previous_version);
+
+  // An app is uninstalled if the Client key exists and the pv value in the
+  // ClientState key does not exist.
+  // Omaha may create the app's ClientState key and write values from the
+  // metainstaller tag before running the installer, which creates the Client
+  // key. Requiring pv in ClientState avoids mistakenly determining that the
+  // Omaha-created key indicates an uninstall.
+  bool app_is_uninstalled =
+      !client_key_exists &&
+      HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != previous_version_hr;
+  temp_data.set_is_uninstalled(app_is_uninstalled);
+
+  CString ap;
+  client_state_key.GetValue(kRegValueAdditionalParams, &ap);
+  temp_data.set_ap(ap);
+
+  CString tt_token;
+  client_state_key.GetValue(kRegValueTTToken, &tt_token);
+  temp_data.set_tt_token(tt_token);
+
+  CString iid;
+  client_state_key.GetValue(kRegValueInstallationId, &iid);
+  temp_data.set_iid(StringToGuid(iid));
+
+  CString brand_code;
+  client_state_key.GetValue(kRegValueBrandCode, &brand_code);
+  ASSERT1(brand_code.GetLength() <= kBrandIdLength);
+  temp_data.set_brand_code(brand_code);
+
+  CString client_id;
+  client_state_key.GetValue(kRegValueClientId, &client_id);
+  temp_data.set_client_id(client_id);
+
+  // We do not need the referral_id.
+
+  // Get the install time and calculate the elapsed time since then if is valid.
+  DWORD install_time(0);
+  if (SUCCEEDED(client_state_key.GetValue(kRegValueInstallTimeSec,
+                                          &install_time))) {
+    const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+    if (0 != install_time && now >= install_time) {
+      temp_data.set_install_time_diff_sec(now - install_time);
+    }
+  }
+
+  temp_data.set_is_oem_install(client_state_key.HasValue(kRegValueOemInstall));
+
+  bool is_eula_accepted = true;
+  DWORD eula_accepted = 0;
+
+  ASSERT(::IsEqualGUID(parent_app_guid, GUID_NULL),
+         (_T("Legacy components not supported; IsAppEulaAccepted ignores.")));
+  temp_data.set_is_eula_accepted(
+      goopdate_utils::IsAppEulaAccepted(is_machine_,
+                                        GuidToString(app_guid),
+                                        false));
+
+  if (temp_data.language().IsEmpty()) {
+    // Read the language from the client state key if we did not find
+    // it in the client key.
+    CString language;
+    client_state_key.GetValue(kRegValueLanguage, &language);
+    temp_data.set_language(language);
+  }
+
+  // Read the did run value.
+  // TODO(omaha): Try to move this logic into the application_usage_data class.
+  ApplicationUsageData app_usage(is_machine_, vista_util::IsVistaOrLater());
+  hr = app_usage.ReadDidRun(GuidToString(app_guid));
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_WARNING, (_T("[ReadDidRun failed][0x%08x]"), hr));
+  }
+  AppData::ActiveStates active = AppData::ACTIVE_NOTRUN;
+  if (app_usage.exists()) {
+    active = app_usage.did_run() ? AppData::ACTIVE_RUN :
+                                   AppData::ACTIVE_NOTRUN;
+  } else {
+    active = AppData::ACTIVE_UNKNOWN;
+  }
+  temp_data.set_did_run(active);
+
+  *app_data = temp_data;
+  return S_OK;
+}
+
+// Sets brand code, client ID, usage stats, browser, ap, and Omaha language in
+// the app's ClientState. Also, sets the installed by OEM flag if appropriate.
+// Sets eulaaccepted=0 if the app is not already registered and the app's EULA
+// has not been accepted. Deletes eulaaccepted if the EULA has been accepted.
+// Only call for initial or over-installs. Do not call for updates to avoid
+// mistakenly replacing data, such as the application's language, and causing
+// unexpected changes to the app during a silent update.
+HRESULT AppManager::WritePreInstallData(const AppData& app_data) {
+  CORE_LOG(L3, (_T("[AppManager::WritePreInstallData]")));
+
+  RegKey client_state_key;
+  HRESULT hr = CreateClientStateKey(app_data.parent_app_guid(),
+                                    app_data.app_guid(),
+                                    &client_state_key);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (app_data.is_eula_accepted()) {
+    hr = goopdate_utils::ClearAppEulaNotAccepted(
+             is_machine_,
+             GuidToString(app_data.app_guid()));
+  } else {
+    if (!IsProductRegistered(app_data.app_guid())) {
+      hr = goopdate_utils::SetAppEulaNotAccepted(
+               is_machine_,
+               GuidToString(app_data.app_guid()));
+    }
+  }
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString state_key_path = GetClientStateKeyName(app_data.parent_app_guid(),
+                                                 app_data.app_guid());
+  VERIFY1(SUCCEEDED(goopdate_utils::SetAppBranding(state_key_path,
+                                                   app_data.brand_code(),
+                                                   app_data.client_id(),
+                                                   app_data.referral_id())));
+
+  ASSERT(::IsEqualGUID(app_data.parent_app_guid(), GUID_NULL),
+         (_T("Legacy components not supported; SetUsageStatsEnable ignores.")));
+  if (TRISTATE_NONE != app_data.usage_stats_enable()) {
+    VERIFY1(SUCCEEDED(goopdate_utils::SetUsageStatsEnable(
+                          is_machine_,
+                          GuidToString(app_data.app_guid()),
+                          app_data.usage_stats_enable())));
+  }
+
+  if (BROWSER_UNKNOWN == app_data.browser_type()) {
+    VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueBrowser)));
+  } else {
+    DWORD browser_type = app_data.browser_type();
+    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueBrowser,
+                                                browser_type)));
+  }
+
+  if (app_data.ap().IsEmpty()) {
+    VERIFY1(SUCCEEDED(
+        client_state_key.DeleteValue(kRegValueAdditionalParams)));
+  } else {
+    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueAdditionalParams,
+                                                app_data.ap())));
+  }
+
+  if (!app_data.language().IsEmpty()) {
+    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueLanguage,
+                                                app_data.language())));
+  }
+
+  if (ConfigManager::Instance()->IsOemInstalling(is_machine_)) {
+    ASSERT1(is_machine_);
+    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueOemInstall, _T("1"))));
+  }
+
+  return S_OK;
+}
+
+// Sets installation ID in the app's ClientState.
+// Copies version and language from clients to client state reg key.
+HRESULT AppManager::InitializeApplicationState(AppData* app_data) {
+  CORE_LOG(L3, (_T("[AppManager::InitializeApplicationState]")));
+  ASSERT1(app_data);
+  RegKey client_state_key;
+  HRESULT hr = CreateClientStateKey(app_data->parent_app_guid(),
+                                    app_data->app_guid(),
+                                    &client_state_key);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  RegKey client_key;
+  hr = OpenClientKey(app_data->parent_app_guid(),
+                     app_data->app_guid(),
+                     &client_key);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (!::IsEqualGUID(app_data->iid(), GUID_NULL)) {
+    VERIFY1(SUCCEEDED(client_state_key.SetValue(
+                          kRegValueInstallationId,
+                          GuidToString(app_data->iid()))));
+  }
+
+  return CopyVersionAndLanguageToClientState(app_data,
+                                             client_state_key,
+                                             client_key);
+}
+
+// Copies language and version from clients into client state reg key.
+// Removes installation id, if did run = true or if goopdate.
+// Clears did run.
+HRESULT AppManager::UpdateApplicationState(AppData* app_data) {
+  ASSERT1(app_data);
+  RegKey client_state_key;
+  HRESULT hr = CreateClientStateKey(app_data->parent_app_guid(),
+                                    app_data->app_guid(),
+                                    &client_state_key);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  RegKey client_key;
+  hr = OpenClientKey(app_data->parent_app_guid(),
+                     app_data->app_guid(),
+                     &client_key);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = CopyVersionAndLanguageToClientState(app_data,
+                                           client_state_key,
+                                           client_key);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Handle the installation id.
+  hr = ClearInstallationId(app_data, client_state_key);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // Clear the did run value.
+  ApplicationUsageData app_usage(app_data->is_machine_app(),
+                                 vista_util::IsVistaOrLater());
+  VERIFY1(SUCCEEDED(app_usage.ResetDidRun(GuidToString(app_data->app_guid()))));
+  app_data->set_did_run(app_usage.exists() ? AppData::ACTIVE_NOTRUN :
+                                             AppData::ACTIVE_UNKNOWN);
+  return S_OK;
+}
+
+HRESULT AppManager::WriteTTToken(const AppData& app_data,
+                                 const UpdateResponseData& response_data) {
+  CORE_LOG(L3, (_T("[WriteTTToken][app_data token=%s][response_data token=%s]"),
+                app_data.tt_token(), response_data.tt_token()));
+  RegKey client_state_key;
+  HRESULT hr = CreateClientStateKey(app_data.parent_app_guid(),
+                                    app_data.app_guid(),
+                                    &client_state_key);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (response_data.tt_token().IsEmpty()) {
+    VERIFY1(SUCCEEDED(client_state_key.DeleteValue(kRegValueTTToken)));
+  } else {
+    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueTTToken,
+                                                response_data.tt_token())));
+  }
+
+  return S_OK;
+}
+
+// The registry reads and writes are not thread safe, but there should not be
+// other threads or processes calling this at the same time.
+void AppManager::UpdateUpdateAvailableStats(const GUID& parent_app_guid,
+                                            const GUID& app_guid) {
+  RegKey state_key;
+  HRESULT hr = CreateClientStateKey(parent_app_guid, app_guid, &state_key);
+  if (FAILED(hr)) {
+    ASSERT1(false);
+    return;
+  }
+
+  DWORD update_available_count(0);
+  hr = state_key.GetValue(kRegValueUpdateAvailableCount,
+                          &update_available_count);
+  if (FAILED(hr)) {
+    update_available_count = 0;
+  }
+  ++update_available_count;
+  VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueUpdateAvailableCount,
+                                       update_available_count)));
+
+  DWORD64 update_available_since_time(0);
+  hr = state_key.GetValue(kRegValueUpdateAvailableSince,
+                          &update_available_since_time);
+  if (FAILED(hr)) {
+    // There is no existing value, so this must be the first update notice.
+    VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueUpdateAvailableSince,
+                                         GetCurrent100NSTime())));
+
+    // TODO(omaha): It would be nice to report the version that we were first
+    // told to update to. This is available in UpdateResponse but we do not
+    // currently send it down in update responses. If we start using it, add
+    // kRegValueFirstUpdateResponseVersion.
+  }
+}
+
+void AppManager::ClearUpdateAvailableStats(const GUID& parent_app_guid,
+                                           const GUID& app_guid) {
+  RegKey state_key;
+  HRESULT hr =
+      OpenClientStateKey(parent_app_guid, app_guid, KEY_ALL_ACCESS, &state_key);
+  if (FAILED(hr)) {
+    return;
+  }
+
+  VERIFY1(SUCCEEDED(state_key.DeleteValue(kRegValueUpdateAvailableCount)));
+  VERIFY1(SUCCEEDED(state_key.DeleteValue(kRegValueUpdateAvailableSince)));
+}
+
+void AppManager::ClearOemInstalled(const GUID& parent_app_guid,
+                                   const GUID& app_guid) {
+  RegKey state_key;
+  HRESULT hr =
+      OpenClientStateKey(parent_app_guid, app_guid, KEY_ALL_ACCESS, &state_key);
+  ASSERT1(SUCCEEDED(hr));
+  if (FAILED(hr)) {
+    return;
+  }
+
+  VERIFY1(SUCCEEDED(state_key.DeleteValue(kRegValueOemInstall)));
+}
+
+// Returns 0 for any values that are not found.
+void AppManager::ReadUpdateAvailableStats(
+    const GUID& parent_app_guid,
+    const GUID& app_guid,
+    DWORD* update_responses,
+    DWORD64* time_since_first_response_ms) {
+  ASSERT1(update_responses);
+  ASSERT1(time_since_first_response_ms);
+  *update_responses = 0;
+  *time_since_first_response_ms = 0;
+
+  RegKey state_key;
+  HRESULT hr = OpenClientStateKey(parent_app_guid,
+                                  app_guid,
+                                  KEY_READ,
+                                  &state_key);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[App ClientState key does not exist][%s]"),
+                  GuidToString(app_guid)));
+    return;
+  }
+
+  DWORD update_responses_in_reg(0);
+  hr = state_key.GetValue(kRegValueUpdateAvailableCount,
+                          &update_responses_in_reg);
+  if (SUCCEEDED(hr)) {
+    *update_responses = update_responses_in_reg;
+  }
+
+  DWORD64 update_available_since_time(0);
+  hr = state_key.GetValue(kRegValueUpdateAvailableSince,
+                          &update_available_since_time);
+  if (SUCCEEDED(hr)) {
+    const DWORD64 current_time = GetCurrent100NSTime();
+    ASSERT1(update_available_since_time <= current_time);
+    const DWORD64 time_since_first_response_in_100ns =
+        current_time - update_available_since_time;
+    *time_since_first_response_ms =
+        time_since_first_response_in_100ns / kMillisecsTo100ns;
+  }
+}
+
+// The update success and update check success times are not updated for
+// installs even if it is an over-install. At this point, we do not know for
+// sure that it was an online update.
+void AppManager::RecordSuccessfulInstall(const GUID& parent_app_guid,
+                                         const GUID& app_guid,
+                                         bool is_update,
+                                         bool is_offline) {
+  ASSERT1(!is_update || !is_offline);
+
+  ClearUpdateAvailableStats(parent_app_guid, app_guid);
+
+  if (!is_offline) {
+    // Assumes that all updates are online.
+    RecordSuccessfulUpdateCheck(parent_app_guid, app_guid);
+  }
+
+  if (is_update) {
+    RegKey state_key;
+    HRESULT hr = CreateClientStateKey(parent_app_guid, app_guid, &state_key);
+    if (FAILED(hr)) {
+      ASSERT1(false);
+      return;
+    }
+
+    const DWORD now = Time64ToInt32(GetCurrent100NSTime());
+    VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueLastUpdateTimeSec, now)));
+  }
+}
+
+void AppManager::RecordSuccessfulUpdateCheck(const GUID& parent_app_guid,
+                                             const GUID& app_guid) {
+  RegKey state_key;
+  HRESULT hr = CreateClientStateKey(parent_app_guid, app_guid, &state_key);
+  if (FAILED(hr)) {
+    ASSERT1(false);
+    return;
+  }
+
+  const DWORD now = Time64ToInt32(GetCurrent100NSTime());
+  VERIFY1(SUCCEEDED(state_key.SetValue(kRegValueLastSuccessfulCheckSec, now)));
+}
+
+HRESULT AppManager::ClearInstallationId(AppData* app_data,
+                                        const RegKey& client_state_key) {
+  ASSERT1(app_data);
+  // First run is the last time we want to use the Installation ID.
+  // For apps, delete Installation ID if it is present and DidRun==yes.
+  // For Omaha, always delete Installation ID if it is present because
+  // DidRun does not apply.
+  if (!::IsEqualGUID(app_data->iid(), GUID_NULL) &&
+      ((AppData::ACTIVE_RUN == app_data->did_run()) ||
+       (::IsEqualGUID(kGoopdateGuid, app_data->app_guid())))) {
+    CORE_LOG(L1, (_T("[Deleting iid for app][%s]"),
+                  GuidToString(app_data->app_guid())));
+    // Relies on installation_id not empty to indicate state_key is valid.
+    VERIFY1(S_OK == client_state_key.DeleteValue(kRegValueInstallationId));
+    app_data->set_iid(GUID_NULL);
+  }
+
+  return S_OK;
+}
+
+// Only replaces the language in ClientState and app_data if the language in
+// Clients is not empty.
+HRESULT AppManager::CopyVersionAndLanguageToClientState(
+    AppData* app_data,
+    const RegKey& client_state_key,
+    const RegKey& client_key) {
+  // TODO(omaha):  need to handle components too.
+  ASSERT1(app_data);
+  // Read the version and language from the client key.
+  CString version;
+  HRESULT hr = client_key.GetValue(kRegValueProductVersion, &version);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString language;
+  client_key.GetValue(kRegValueLanguage, &language);
+
+  // Write the version and language in the client state key.
+  hr = client_state_key.SetValue(kRegValueProductVersion, version);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  app_data->set_version(version);
+  app_data->set_previous_version(version);
+
+  if (!language.IsEmpty()) {
+    VERIFY1(SUCCEEDED(client_state_key.SetValue(kRegValueLanguage,
+                                                language)));
+    app_data->set_language(language);
+  }
+
+  return S_OK;
+}
+
+HRESULT AppManager::RemoveClientState(const AppData& app_data) {
+  ASSERT(::IsEqualGUID(app_data.parent_app_guid(), GUID_NULL),
+         (_T("Legacy components not supported; ClientStateMedium ignores.")));
+
+  ASSERT1(app_data.is_uninstalled());
+  const CString state_key = GetClientStateKeyName(app_data.parent_app_guid(),
+                                                  app_data.app_guid());
+  HRESULT state_hr = RegKey::DeleteKey(state_key, true);
+
+  if (!is_machine_) {
+    return state_hr;
+  }
+
+  const CString state_medium_key =
+      GetProductClientStateMediumKeyName(app_data.app_guid());
+  HRESULT state_medium_hr = RegKey::DeleteKey(state_medium_key, true);
+
+  return FAILED(state_hr) ? state_hr : state_medium_hr;
+}
+
+// Returns true if the absolute difference between time moments is greater than
+// the interval between update checks.
+// Deals with clocks rolling backwards, in scenarios where the clock indicates
+// some time in the future, for example next year, last_checked_ is updated to
+// reflect that time, and then the clock is adjusted back to present.
+bool AppManager::ShouldCheckForUpdates() const {
+  ConfigManager* cm = ConfigManager::Instance();
+  bool is_period_overridden = false;
+  const int update_interval = cm->GetLastCheckPeriodSec(&is_period_overridden);
+  if (0 == update_interval) {
+    ASSERT1(is_period_overridden);
+    OPT_LOG(L1, (_T("[ShouldCheckForUpdates returned 0][checks disabled]")));
+    return false;
+  }
+
+  const int time_difference = cm->GetTimeSinceLastCheckedSec(is_machine_);
+
+  const bool result = time_difference >= update_interval ? true : false;
+  CORE_LOG(L3, (_T("[ShouldCheckForUpdates returned %d][%u]"),
+                result, is_period_overridden));
+  return result;
+}
+
+HRESULT AppManager::UpdateLastChecked() {
+  // Set the last check value to the current value.
+  DWORD now = Time64ToInt32(GetCurrent100NSTime());
+  HRESULT hr = ConfigManager::Instance()->SetLastCheckedTime(is_machine_, now);
+  CORE_LOG(L3, (_T("[AppManager::UpdateLastChecked][now %d]"), now));
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[UpdateLastChecked returned 0x%08x]"), hr));
+    return hr;
+  }
+  return S_OK;
+}
+
+HRESULT AppManager::ReadProductDataFromUserOrMachineStore(
+    const GUID& guid,
+    ProductData* product_data) {
+  ASSERT1(product_data);
+  AppManager app_manager_user(false);
+  HRESULT hr = app_manager_user.ReadProductDataFromStore(guid, product_data);
+  if (SUCCEEDED(hr)) {
+    return hr;
+  }
+
+  AppManager app_manager_machine(true);
+  return app_manager_machine.ReadProductDataFromStore(guid, product_data);
+}
+
+// Writes 0.0.0.1 to pv. This value avoids any special cases, such as initial
+// install rules, for 0.0.0.0, while being unlikely to be higher than the
+// product's actual current version.
+HRESULT AppManager::RegisterProduct(const GUID& product_guid,
+                                    const CString& product_name) {
+  const TCHAR* const kRegisterProductVersion = _T("0.0.0.1");
+
+  RegKey client_key;
+  HRESULT hr = client_key.Create(GetClientKeyName(GUID_NULL, product_guid));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = client_key.SetValue(kRegValueProductVersion, kRegisterProductVersion);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // AppName is not a required parameter since it's only used for being able to
+  // easily tell what application is there when reading the registry.
+  VERIFY1(SUCCEEDED(client_key.SetValue(kRegValueAppName, product_name)));
+
+  return S_OK;
+}
+
+HRESULT AppManager::UnregisterProduct(const GUID& product_guid) {
+  return RegKey::DeleteKey(GetClientKeyName(GUID_NULL, product_guid), true);
+}
+
+}  // namespace omaha.
+
diff --git a/worker/application_manager.h b/worker/application_manager.h
index 06967ed..d96007a 100644
--- a/worker/application_manager.h
+++ b/worker/application_manager.h
@@ -1,168 +1,168 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Class allows the worker to access products and components.

-

-#ifndef OMAHA_WORKER_APPLICATION_MANAGER_H__

-#define OMAHA_WORKER_APPLICATION_MANAGER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/request.h"

-#include "omaha/goopdate/update_response_data.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/product_data.h"

-

-namespace omaha {

-

-// Application manager allows the worker to access registry state.

-class AppManager {

- public:

-  explicit AppManager(bool is_machine);

-

-  bool IsProductRegistered(const GUID& app_guid) const;

-  bool IsComponentRegistered(const GUID& app_guid, const GUID& component_guid);

-

-  void ConvertCommandLineToProductData(const CommandLineArgs& args,

-                                       ProductDataVector* products);

-

-  HRESULT GetRegisteredProducts(ProductDataVector* products) const;

-

-  HRESULT GetUnRegisteredProducts(ProductDataVector* products) const;

-

-  // Reads the application state from the registry.

-  HRESULT ReadProductDataFromStore(const GUID& app_guid,

-                                   ProductData* product_data);

-

-  // Reads an individual AppData from the store.  Will read either product or

-  // component level based on whether there's a parent or not.  This will not

-  // recurse to read children since it's only the AppData portion.

-  HRESULT ReadAppDataFromStore(const GUID& parent_app_guid,

-                               const GUID& component_guid,

-                               AppData* app_data);

-

-  // Sets dynamic install parameters that the installer or app may use.

-  // Call this method before calling the installer.

-  HRESULT WritePreInstallData(const AppData& app_data);

-

-  // Sets the initial state of the application in the registry. Call this

-  // method after the initial install/update has completed.

-  HRESULT InitializeApplicationState(AppData* app_data);

-

-  // Updates the state of the application in the registry. Call this method

-  // to update the state of the application after an update check.

-  HRESULT UpdateApplicationState(AppData* app_data);

-

-  // Write the TT Token with what the server returned.

-  HRESULT WriteTTToken(const AppData& app_data,

-                       const UpdateResponseData& response_data);

-

-  // Stores information about the update available event for the app.

-  // Call each time an update is available.

-  void UpdateUpdateAvailableStats(const GUID& parent_app_guid,

-                                  const GUID& app_guid);

-  // Clears the stored information about update available events for the app.

-  // Call when an update has succeeded.

-  void ClearUpdateAvailableStats(const GUID& parent_app_guid,

-                                 const GUID& app_guid);

-

-  // Clears the OEM-installed flag for the app.

-  void ClearOemInstalled(const GUID& parent_app_guid, const GUID& app_guid);

-

-  // Obtains usage stats information from the stored information about update

-  // available events for the app.

-  void ReadUpdateAvailableStats(const GUID& parent_app_guid,

-                                const GUID& app_guid,

-                                DWORD* update_responses,

-                                DWORD64* time_since_first_response_ms);

-

-  // Updates the application state after a successful install or update.

-  void RecordSuccessfulInstall(const GUID& parent_app_guid,

-                               const GUID& app_guid,

-                               bool is_update,

-                               bool is_offline);

-

-  // Updates the application state after a successful update check event, which

-  // is either a "noupdate" response or a successful online update.

-  void RecordSuccessfulUpdateCheck(const GUID& parent_app_guid,

-                                   const GUID& app_guid);

-

-  // Removes all the registration entries under the client state for the

-  // application.

-  HRESULT RemoveClientState(const AppData& app_data);

-

-  // Returns true if a server update check is due.

-  bool ShouldCheckForUpdates() const;

-  HRESULT UpdateLastChecked();

-

-  static HRESULT ReadProductDataFromUserOrMachineStore(

-      const GUID& guid,

-      ProductData* product_data);

-

-  HRESULT RegisterProduct(const GUID& product_guid,

-                          const CString& product_name);

-  HRESULT UnregisterProduct(const GUID& product_guid);

-

- private:

-  CString GetClientKeyName(const GUID& parent_app_guid, const GUID& app_guid);

-  CString GetClientStateKeyName(const GUID& parent_app_guid,

-                                const GUID& app_guid);

-

-  // Opens the app's Client key for read access.

-  HRESULT OpenClientKey(const GUID& parent_app_guid,

-                        const GUID& app_guid,

-                        RegKey* client_key);

-  // Opens the app's ClientState key with the specified access.

-  HRESULT OpenClientStateKey(const GUID& parent_app_guid,

-                             const GUID& app_guid,

-                             REGSAM sam_desired,

-                             RegKey* client_state_key);

-  // Creates the app's ClientState key.

-  HRESULT CreateClientStateKey(const GUID& parent_app_guid,

-                               const GUID& app_guid,

-                               RegKey* client_state_key);

-

-  CString GetProductClientKeyName(const GUID& app_guid);

-  CString GetProductClientComponentsKeyName(const GUID& app_guid);

-  CString GetProductClientStateComponentsKeyName(const GUID& app_guid);

-  CString GetComponentClientKeyName(const GUID& parent_app_guid,

-                                    const GUID& app_guid);

-  CString GetProductClientStateKeyName(const GUID& app_guid);

-  CString GetProductClientStateMediumKeyName(const GUID& app_guid);

-  CString GetComponentClientStateKeyName(const GUID& parent_app_guid,

-                                         const GUID& app_guid);

-

-  HRESULT ClearInstallationId(AppData* app_data,

-                              const RegKey& client_state_key);

-  HRESULT CopyVersionAndLanguageToClientState(AppData* app_data,

-                                              const RegKey& client_state_key,

-                                              const RegKey& client_key);

-

-  const bool is_machine_;

-

-  friend class AppManagerTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(AppManager);

-};

-

-}  // namespace omaha.

-

-#endif  // OMAHA_WORKER_APPLICATION_MANAGER_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Class allows the worker to access products and components.
+
+#ifndef OMAHA_WORKER_APPLICATION_MANAGER_H__
+#define OMAHA_WORKER_APPLICATION_MANAGER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/request.h"
+#include "omaha/goopdate/update_response_data.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/product_data.h"
+
+namespace omaha {
+
+// Application manager allows the worker to access registry state.
+class AppManager {
+ public:
+  explicit AppManager(bool is_machine);
+
+  bool IsProductRegistered(const GUID& app_guid) const;
+  bool IsComponentRegistered(const GUID& app_guid, const GUID& component_guid);
+
+  void ConvertCommandLineToProductData(const CommandLineArgs& args,
+                                       ProductDataVector* products);
+
+  HRESULT GetRegisteredProducts(ProductDataVector* products) const;
+
+  HRESULT GetUnRegisteredProducts(ProductDataVector* products) const;
+
+  // Reads the application state from the registry.
+  HRESULT ReadProductDataFromStore(const GUID& app_guid,
+                                   ProductData* product_data);
+
+  // Reads an individual AppData from the store.  Will read either product or
+  // component level based on whether there's a parent or not.  This will not
+  // recurse to read children since it's only the AppData portion.
+  HRESULT ReadAppDataFromStore(const GUID& parent_app_guid,
+                               const GUID& component_guid,
+                               AppData* app_data);
+
+  // Sets dynamic install parameters that the installer or app may use.
+  // Call this method before calling the installer.
+  HRESULT WritePreInstallData(const AppData& app_data);
+
+  // Sets the initial state of the application in the registry. Call this
+  // method after the initial install/update has completed.
+  HRESULT InitializeApplicationState(AppData* app_data);
+
+  // Updates the state of the application in the registry. Call this method
+  // to update the state of the application after an update check.
+  HRESULT UpdateApplicationState(AppData* app_data);
+
+  // Write the TT Token with what the server returned.
+  HRESULT WriteTTToken(const AppData& app_data,
+                       const UpdateResponseData& response_data);
+
+  // Stores information about the update available event for the app.
+  // Call each time an update is available.
+  void UpdateUpdateAvailableStats(const GUID& parent_app_guid,
+                                  const GUID& app_guid);
+  // Clears the stored information about update available events for the app.
+  // Call when an update has succeeded.
+  void ClearUpdateAvailableStats(const GUID& parent_app_guid,
+                                 const GUID& app_guid);
+
+  // Clears the OEM-installed flag for the app.
+  void ClearOemInstalled(const GUID& parent_app_guid, const GUID& app_guid);
+
+  // Obtains usage stats information from the stored information about update
+  // available events for the app.
+  void ReadUpdateAvailableStats(const GUID& parent_app_guid,
+                                const GUID& app_guid,
+                                DWORD* update_responses,
+                                DWORD64* time_since_first_response_ms);
+
+  // Updates the application state after a successful install or update.
+  void RecordSuccessfulInstall(const GUID& parent_app_guid,
+                               const GUID& app_guid,
+                               bool is_update,
+                               bool is_offline);
+
+  // Updates the application state after a successful update check event, which
+  // is either a "noupdate" response or a successful online update.
+  void RecordSuccessfulUpdateCheck(const GUID& parent_app_guid,
+                                   const GUID& app_guid);
+
+  // Removes all the registration entries under the client state for the
+  // application.
+  HRESULT RemoveClientState(const AppData& app_data);
+
+  // Returns true if a server update check is due.
+  bool ShouldCheckForUpdates() const;
+  HRESULT UpdateLastChecked();
+
+  static HRESULT ReadProductDataFromUserOrMachineStore(
+      const GUID& guid,
+      ProductData* product_data);
+
+  HRESULT RegisterProduct(const GUID& product_guid,
+                          const CString& product_name);
+  HRESULT UnregisterProduct(const GUID& product_guid);
+
+ private:
+  CString GetClientKeyName(const GUID& parent_app_guid, const GUID& app_guid);
+  CString GetClientStateKeyName(const GUID& parent_app_guid,
+                                const GUID& app_guid);
+
+  // Opens the app's Client key for read access.
+  HRESULT OpenClientKey(const GUID& parent_app_guid,
+                        const GUID& app_guid,
+                        RegKey* client_key);
+  // Opens the app's ClientState key with the specified access.
+  HRESULT OpenClientStateKey(const GUID& parent_app_guid,
+                             const GUID& app_guid,
+                             REGSAM sam_desired,
+                             RegKey* client_state_key);
+  // Creates the app's ClientState key.
+  HRESULT CreateClientStateKey(const GUID& parent_app_guid,
+                               const GUID& app_guid,
+                               RegKey* client_state_key);
+
+  CString GetProductClientKeyName(const GUID& app_guid);
+  CString GetProductClientComponentsKeyName(const GUID& app_guid);
+  CString GetProductClientStateComponentsKeyName(const GUID& app_guid);
+  CString GetComponentClientKeyName(const GUID& parent_app_guid,
+                                    const GUID& app_guid);
+  CString GetProductClientStateKeyName(const GUID& app_guid);
+  CString GetProductClientStateMediumKeyName(const GUID& app_guid);
+  CString GetComponentClientStateKeyName(const GUID& parent_app_guid,
+                                         const GUID& app_guid);
+
+  HRESULT ClearInstallationId(AppData* app_data,
+                              const RegKey& client_state_key);
+  HRESULT CopyVersionAndLanguageToClientState(AppData* app_data,
+                                              const RegKey& client_state_key,
+                                              const RegKey& client_key);
+
+  const bool is_machine_;
+
+  friend class AppManagerTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(AppManager);
+};
+
+}  // namespace omaha.
+
+#endif  // OMAHA_WORKER_APPLICATION_MANAGER_H__
+
diff --git a/worker/application_manager_unittest.cc b/worker/application_manager_unittest.cc
index 7b62fe9..6d8c928 100644
--- a/worker/application_manager_unittest.cc
+++ b/worker/application_manager_unittest.cc
@@ -1,1540 +1,1540 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// ApplicationManager unit tests

-

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/time.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/enterprise/const_group_policy.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/setup/setup_google_update.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/job.h"

-

-namespace omaha {

-

-namespace {

-

-const TCHAR* const kGuid1 = _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");

-const TCHAR* const kGuid2 = _T("{A979ACBD-1F55-4b12-A35F-4DBCA5A7CCB8}");

-const TCHAR* const kGuid3 = _T("{661045C5-4429-4140-BC48-8CEA241D1DEF}");

-const TCHAR* const kGuid4 = _T("{AAFA1CF9-E94F-42e6-A899-4CD27F37D5A7}");

-const TCHAR* const kGuid5 = _T("{3B1A3CCA-0525-4418-93E6-A0DB3398EC9B}");

-const TCHAR* const kGuid6 = _T("{F3F2CFD4-5F98-4bf0-ABB0-BEEEA46C62B4}");

-const TCHAR* const kGuid7 = _T("{6FD2272F-8583-4bbd-895A-E65F8003FC7B}");

-

-const TCHAR* const kGuid1ClientsKeyPathUser =

-    _T("HKCU\\Software\\Google\\Update\\Clients\\")

-    _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");

-const TCHAR* const kGuid1ClientStateKeyPathUser =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\")

-    _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");

-const TCHAR* const kGuid1ClientStateKeyPathMachine =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");

-

-}  // namespace

-

-void ValidateExpectedValues(const AppData& expected, const AppData& actual);

-void VerifyHklmKeyHasMediumIntegrity(const CString& key_full_name);

-void VerifyHklmKeyHasDefaultIntegrity(const CString& key_full_name);

-

-class AppManagerTest : public testing::Test {

- public:

-  // Creates the application registration entries based on the passed in data.

-  // If passed an application that is uninstalled, the method only creates

-  // the registration entries in the client state and no information is written

-  // in the clients.

-  static void CreateAppRegistryState(const AppData& data) {

-    bool is_machine = data.is_machine_app();

-    CString client_key_name = AppendRegKeyPath(

-        ConfigManager::Instance()->registry_clients(is_machine),

-        GuidToString(data.app_guid()));

-    CString client_state_key_name = AppendRegKeyPath(

-        ConfigManager::Instance()->registry_client_state(is_machine),

-        GuidToString(data.app_guid()));

-

-    RegKey client_key;

-    if (!data.is_uninstalled()) {

-      ASSERT_SUCCEEDED(client_key.Create(client_key_name));

-

-      if (!data.version().IsEmpty()) {

-        ASSERT_SUCCEEDED(client_key.SetValue(kRegValueProductVersion,

-                                             data.version()));

-      }

-    }

-

-    RegKey client_state_key;

-    ASSERT_SUCCEEDED(client_state_key.Create(client_state_key_name));

-

-    if (!data.previous_version().IsEmpty()) {

-      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueProductVersion,

-                                                 data.previous_version()));

-    }

-

-    if (!data.language().IsEmpty()) {

-      if (data.is_uninstalled()) {

-        ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueLanguage,

-                                                   data.language()));

-      } else {

-        ASSERT_SUCCEEDED(client_key.SetValue(kRegValueLanguage,

-                                             data.language()));

-      }

-    }

-

-    if (data.did_run() != AppData::ACTIVE_UNKNOWN) {

-      CString dr = (data.did_run() == AppData::ACTIVE_NOTRUN) ? _T("0") :

-                                                                _T("1");

-      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueDidRun,

-                                                 dr));

-    }

-

-    if (!data.ap().IsEmpty()) {

-      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueAdditionalParams,

-                                                 data.ap()));

-    }

-

-    if (!data.tt_token().IsEmpty()) {

-      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueTTToken,

-                                                 data.tt_token()));

-    }

-

-    if (!::IsEqualGUID(data.iid(), GUID_NULL)) {

-      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueInstallationId,

-                                                 GuidToString(data.iid())));

-    }

-

-    if (!data.brand_code().IsEmpty()) {

-      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueBrandCode,

-                                                 data.brand_code()));

-    }

-

-    if (!data.client_id().IsEmpty()) {

-      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueClientId,

-                                                 data.client_id()));

-    }

-

-    if (!data.referral_id().IsEmpty()) {

-      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueReferralId,

-                                                 data.referral_id()));

-    }

-

-    if (!data.referral_id().IsEmpty()) {

-      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueReferralId,

-                                                 data.referral_id()));

-    }

-

-    if (data.install_time_diff_sec()) {

-      const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-      const DWORD install_time = now - data.install_time_diff_sec();

-      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueInstallTimeSec,

-                                                 install_time));

-    }

-

-    if (!data.is_eula_accepted()) {

-      ASSERT_SUCCEEDED(client_state_key.SetValue(_T("eulaaccepted"),

-                                                 static_cast<DWORD>(0)));

-    }

-  }

-

-  static void PopulateExpectedAppData1(AppData* expected_app) {

-    ASSERT_TRUE(expected_app);

-    expected_app->set_version(_T("1.1.1.3"));

-    expected_app->set_previous_version(_T("1.0.0.0"));

-    expected_app->set_language(_T("abc"));

-    expected_app->set_ap(_T("Test ap"));

-    expected_app->set_tt_token(_T("Test TT Token"));

-    expected_app->set_iid(

-        StringToGuid(_T("{F723495F-8ACF-4746-8240-643741C797B5}")));

-    expected_app->set_brand_code(_T("GOOG"));

-    expected_app->set_client_id(_T("someclient"));

-    // Do not set referral_id or install_time_diff_sec because these are not

-    // expected in most cases.

-    // This value must be ACTIVE_RUN for UpdateApplicationStateTest to work.

-    expected_app->set_did_run(AppData::ACTIVE_RUN);

-  }

-

-  static void PopulateExpectedAppData1InvalidBrand(AppData* expected_app) {

-    PopulateExpectedAppData1(expected_app);

-    expected_app->set_brand_code(_T("GOOG1122"));

-  }

-

-  static void PopulateExpectedAppData2(AppData* expected_app) {

-    ASSERT_TRUE(expected_app);

-    expected_app->set_version(_T("1.2.1.3"));

-    expected_app->set_previous_version(_T("1.1.0.0"));

-    expected_app->set_language(_T("de"));

-    expected_app->set_ap(_T("beta"));

-    expected_app->set_tt_token(_T("beta TT Token"));

-    expected_app->set_iid(

-        StringToGuid(_T("{431EC961-CFD8-49ea-AB7B-2B99BCA274AD}")));

-    expected_app->set_brand_code(_T("GooG"));

-    expected_app->set_client_id(_T("anotherclient"));

-    expected_app->set_did_run(AppData::ACTIVE_NOTRUN);

-  }

-

-  static void PopulateExpectedUninstalledAppData(AppData* expected_app) {

-    ASSERT_TRUE(expected_app);

-    PopulateExpectedAppData2(expected_app);

-

-    // Make the AppData represent an uninstall.

-    expected_app->set_version(_T(""));

-    expected_app->set_is_uninstalled(true);

-  }

-

- protected:

-  AppManagerTest()

-      : hive_override_key_name_(kRegistryHiveOverrideRoot),

-        guid1_(StringToGuid(kGuid1)) {}

-

-  virtual void SetUp() {

-    RegKey::DeleteKey(hive_override_key_name_);

-    OverrideRegistryHives(hive_override_key_name_);

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    RegKey::DeleteKey(hive_override_key_name_);

-  }

-

-  void ClearUpdateAvailableStats(const GUID& parent_app_guid,

-                                 const GUID& app_guid,

-                                 AppManager* app_manager) {

-    ASSERT_TRUE(app_manager);

-    app_manager->ClearUpdateAvailableStats(parent_app_guid, app_guid);

-  }

-

-  bool IsClientStateKeyPresent(const AppData& data) {

-    CString client_state_key_name = AppendRegKeyPath(

-        ConfigManager::Instance()->registry_client_state(data.is_machine_app()),

-        GuidToString(data.app_guid()));

-

-    return RegKey::HasKey(client_state_key_name);

-  }

-

-  void InitializeApplicationStateTest(bool is_machine) {

-    // Create the test data.

-    AppData expected_data(guid1_, is_machine);

-    expected_data.set_version(_T("4.5.6.7"));

-    expected_data.set_language(_T("de"));

-    CreateAppRegistryState(expected_data);

-

-    // Create the job that contains the test data.

-

-    CommandLineAppArgs extra;

-    extra.app_guid = guid1_;

-    extra.app_name = _T("foo");

-    extra.ap = _T("test ap");

-    extra.tt_token = _T("test TT Token");

-

-    CommandLineArgs args;

-    args.extra.installation_id =

-        StringToGuid(_T("{64333341-CA93-490d-9FB7-7FC5728721F4}"));

-    args.extra.brand_code = _T("g00g");

-    args.extra.client_id = _T("myclient");

-    args.extra.referral_id = _T("somereferrer");

-    args.extra.language = _T("en");

-    args.extra.apps.push_back(extra);

-

-    AppManager app_manager(is_machine);

-    ProductDataVector products;

-    app_manager.ConvertCommandLineToProductData(args, &products);

-    ASSERT_EQ(1, products.size());

-

-    AppData product_app_data = products[0].app_data();

-

-    EXPECT_TRUE(product_app_data.is_eula_accepted());

-

-    // Test the method.

-    ASSERT_SUCCEEDED(

-        app_manager.InitializeApplicationState(&product_app_data));

-

-    // Validate the results.

-    CString client_state_key_name = AppendRegKeyPath(

-        ConfigManager::Instance()->registry_client_state(is_machine),

-        kGuid1);

-    RegKey client_state_key;

-    ASSERT_SUCCEEDED(client_state_key.Create(client_state_key_name));

-

-    ValidateClientStateMedium(is_machine, kGuid1);

-

-    // Check version is copied to the client state.

-    CString previous_version;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueProductVersion,

-                                               &previous_version));

-    EXPECT_STREQ(_T("4.5.6.7"), product_app_data.version());

-    EXPECT_STREQ(_T("4.5.6.7"), previous_version);

-

-    // Check language is copied to the client state.

-    CString language;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueLanguage, &language));

-    EXPECT_STREQ(_T("de"), product_app_data.language());

-    EXPECT_STREQ(_T("de"), language);

-

-    // Check iid is set correctly in ClientState.

-    CString iid;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueInstallationId, &iid));

-    EXPECT_STREQ(_T("{64333341-CA93-490D-9FB7-7FC5728721F4}"),

-                 GuidToString(product_app_data.iid()));

-    EXPECT_STREQ(_T("{64333341-CA93-490D-9FB7-7FC5728721F4}"), iid);

-

-    // Check other values were not written.

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueAdditionalParams));

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueBrandCode));

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueBrowser));

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueClientId));

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueDidRun));

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueOemInstall));

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueReferralId));

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueEulaAccepted));

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueUsageStats));

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueInstallTimeSec));

-    EXPECT_FALSE(client_state_key.HasValue(kRegValueTTToken));

-  }

-

-  void UpdateApplicationStateTest(bool is_machine, const CString& app_id) {

-    const CString client_state_key_name = AppendRegKeyPath(

-        ConfigManager::Instance()->registry_client_state(is_machine),

-        app_id);

-

-    // Create the test data.

-    AppData expected_data(StringToGuid(app_id), is_machine);

-    PopulateExpectedAppData1(&expected_data);

-    expected_data.set_referral_id(_T("referrer"));

-    expected_data.set_is_eula_accepted(false);

-    expected_data.set_install_time_diff_sec(141516);

-    CreateAppRegistryState(expected_data);

-

-    EXPECT_TRUE(RegKey::HasValue(client_state_key_name, _T("referral")));

-

-    // Call the test method.

-    ProductData product_data;

-    AppManager app_manager(is_machine);

-    EXPECT_SUCCEEDED(app_manager.ReadProductDataFromStore(StringToGuid(app_id),

-                                                          &product_data));

-

-    EXPECT_TRUE(product_data.app_data().referral_id().IsEmpty());

-

-    AppData app_data_temp = product_data.app_data();

-    EXPECT_SUCCEEDED(app_manager.UpdateApplicationState(&app_data_temp));

-    product_data.set_app_data(app_data_temp);

-

-    EXPECT_TRUE(app_data_temp.referral_id().IsEmpty());

-

-    // Need to call again to refresh the values created/copied by

-    // UpdateApplicationState().

-    EXPECT_SUCCEEDED(app_manager.ReadProductDataFromStore(StringToGuid(app_id),

-                                                          &product_data));

-    const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-    EXPECT_TRUE(product_data.app_data().referral_id().IsEmpty());

-

-    // Validate the results.

-    RegKey client_state_key;

-    EXPECT_SUCCEEDED(client_state_key.Open(client_state_key_name));

-

-    // Check version and language have been copied to client state.

-    CString previous_version;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueProductVersion,

-                                               &previous_version));

-    EXPECT_STREQ(expected_data.version(), previous_version);

-

-    CString language;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueLanguage,

-                                               &language));

-    EXPECT_STREQ(expected_data.language(), language);

-

-    // Check installation id removed.

-    CString iid;

-    EXPECT_FAILED(client_state_key.GetValue(kRegValueInstallationId,

-                                            &iid));

-    EXPECT_TRUE(iid.IsEmpty());

-

-    // Check did_run is cleared.

-    CString did_run;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueDidRun,

-                                               &did_run));

-    EXPECT_STREQ(_T("0"), did_run);

-

-    // Check that ap, brand_code, and client_id are not changed.

-    CString ap;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueAdditionalParams,

-                                               &ap));

-    EXPECT_STREQ(expected_data.ap(), ap);

-

-    CString tt_token;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueTTToken,

-                                               &tt_token));

-    EXPECT_STREQ(expected_data.tt_token(), tt_token);

-

-    CString brand_code;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueBrandCode,

-                                               &brand_code));

-    EXPECT_STREQ(expected_data.brand_code(), brand_code);

-

-    CString client_id;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueClientId,

-                                               &client_id));

-    EXPECT_STREQ(expected_data.client_id(), client_id);

-

-    // install_time_diff_sec should be roughly the same as now - installed.

-    DWORD install_time(0);

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueInstallTimeSec,

-                                               &install_time));

-    const DWORD calculated_install_diff = now - install_time;

-    EXPECT_GE(calculated_install_diff, expected_data.install_time_diff_sec());

-    EXPECT_GE(static_cast<uint32>(500),

-              calculated_install_diff - expected_data.install_time_diff_sec());

-

-    DWORD eula_accepted = 0;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(_T("eulaaccepted"),

-                                               &eula_accepted));

-    EXPECT_EQ(0, eula_accepted);

-    EXPECT_FALSE(expected_data.is_eula_accepted());

-  }

-

-  void WritePreInstallDataTest(const AppData& app_data_in) {

-    const bool is_machine = app_data_in.is_machine_app();

-    const CString client_key_name = AppendRegKeyPath(

-        ConfigManager::Instance()->registry_clients(is_machine), kGuid1);

-    const CString client_state_key_name = AppendRegKeyPath(

-        ConfigManager::Instance()->registry_client_state(is_machine),

-        kGuid1);

-

-    const bool expect_has_client_key = RegKey::HasKey(client_key_name);

-

-    // Populate the test data.

-    AppData app_data(app_data_in);

-    app_data.set_brand_code(_T("GGLG"));

-    app_data.set_client_id(_T("someclient"));

-    app_data.set_referral_id(_T("referrer"));

-    app_data.set_install_time_diff_sec(657812);   // Not used.

-    app_data.set_usage_stats_enable(TRISTATE_TRUE);

-    app_data.set_browser_type(BROWSER_FIREFOX);

-    app_data.set_ap(_T("test_ap"));

-    app_data.set_language(_T("en"));

-    app_data.set_version(_T("1.2.3.4"));

-

-    AppManager app_manager(is_machine);

-    app_manager.WritePreInstallData(app_data);

-    const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-    // Validate the results.

-

-    // WritePreInstallData should never write to client_key, so it shouldn't

-    // exist if it did not before the method call.

-    EXPECT_EQ(expect_has_client_key, RegKey::HasKey(client_key_name));

-

-    // ClientStateKey should exist.

-    RegKey client_state_key;

-    EXPECT_SUCCEEDED(client_state_key.Open(client_state_key_name));

-

-    ValidateClientStateMedium(is_machine, kGuid1);

-

-    CString brand_code;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueBrandCode,

-                                               &brand_code));

-    EXPECT_STREQ(_T("GGLG"), brand_code);

-

-    CString client_id;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueClientId, &client_id));

-    EXPECT_STREQ(_T("someclient"), client_id);

-

-    CString referral_id;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueReferralId,

-                                               &referral_id));

-    EXPECT_STREQ(_T("referrer"), referral_id);

-

-    DWORD install_time(0);

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueInstallTimeSec,

-                                               &install_time));

-    EXPECT_GE(now, install_time);

-    EXPECT_GE(static_cast<uint32>(200), now - install_time);

-

-    DWORD usage_stats_enable = 0;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(_T("usagestats"),

-                                               &usage_stats_enable));

-    EXPECT_EQ(TRISTATE_TRUE, usage_stats_enable);

-

-    DWORD browser_type = 0;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueBrowser,

-                                               &browser_type));

-    EXPECT_EQ(BROWSER_FIREFOX, browser_type);

-

-    CString ap;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueAdditionalParams, &ap));

-    EXPECT_STREQ(_T("test_ap"), ap);

-

-    CString lang;

-    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueLanguage, &lang));

-    EXPECT_STREQ(_T("en"), lang);

-

-    // Version should not be written to clientstate by WritePreInstallData().

-    EXPECT_FALSE(RegKey::HasValue(client_state_key_name,

-                                  kRegValueProductVersion));

-  }

-

-  void ValidateClientStateMedium(bool is_machine, const CString& app_guid) {

-    const CString client_state_medium_key_name = AppendRegKeyPath(

-        ConfigManager::Instance()->machine_registry_client_state_medium(),

-        app_guid);

-    if (is_machine) {

-      RegKey client_state_medium_key;

-      EXPECT_SUCCEEDED(

-          client_state_medium_key.Open(client_state_medium_key_name));

-      EXPECT_EQ(0, client_state_medium_key.GetValueCount());

-    } else {

-      EXPECT_FALSE(RegKey::HasKey(client_state_medium_key_name));

-      // There is no such thing as a user ClientStateMedium key.

-      const CString user_client_state_medium_key_name = AppendRegKeyPath(

-          USER_KEY GOOPDATE_REG_RELATIVE_CLIENT_STATE_MEDIUM,

-          app_guid);

-      EXPECT_FALSE(RegKey::HasKey(user_client_state_medium_key_name));

-      return;

-    }

-  }

-

-  // Uses SetupGoogleUpdate to create the ClientStateMedium key with the

-  // appropriate permissions. Used to test that the permissions are inherited.

-  void CreateClientStateMediumKey() {

-    CommandLineArgs args;

-    SetupGoogleUpdate setup_google_update(true, &args);

-    EXPECT_SUCCEEDED(setup_google_update.CreateClientStateMedium());

-  }

-

-  CString hive_override_key_name_;

-  const GUID guid1_;

-};

-

-TEST_F(AppManagerTest, ConvertCommandLineToProductData_Succeeds) {

-  CommandLineAppArgs extra1;

-  extra1.app_guid = guid1_;

-  extra1.app_name = _T("foo");

-  extra1.needs_admin = false;

-  extra1.ap = _T("Test ap");

-  extra1.tt_token = _T("Test TT Token");

-  extra1.encoded_installer_data = _T("%20foobar");

-  extra1.install_data_index = _T("foobar");

-

-  CommandLineAppArgs extra2;

-  extra2.app_guid = StringToGuid(kGuid2);

-  extra2.app_name = _T("bar");

-  extra2.needs_admin = true;    // This gets ignored.

-  extra2.ap = _T("beta");

-  extra2.tt_token = _T("beta TT Token");

-

-  CommandLineArgs args;

-  args.is_interactive_set = true;  // Not used.

-  args.is_machine_set = true;  // Not used.

-  args.is_crash_handler_disabled = true;  // Not used.

-  args.is_eula_required_set = true;

-  args.is_eula_required_set = true;  // Not used.

-  args.webplugin_urldomain = _T("http://nothing.google.com");  // Not used.

-  args.webplugin_args = _T("blah");  // Not used.

-  args.install_source = _T("one_click");

-  args.code_red_metainstaller_path = _T("foo.exe");  // Not used.

-  args.legacy_manifest_path = _T("bar.exe");  // Not used.

-  args.crash_filename = _T("foo.dmp");  // Not used.

-  args.extra.installation_id =

-      StringToGuid(_T("{F723495F-8ACF-4746-8240-643741C797B5}"));

-  args.extra.brand_code = _T("GOOG");

-  args.extra.client_id = _T("someclient");

-  args.extra.referral_id = _T("referrer1");

-  args.extra.browser_type = BROWSER_IE;

-  args.extra.language = _T("abc");

-  args.extra.usage_stats_enable = TRISTATE_TRUE;

-  args.extra.apps.push_back(extra1);

-  args.extra.apps.push_back(extra2);

-

-  AppData expected_data1(guid1_, false);

-  PopulateExpectedAppData1(&expected_data1);

-  expected_data1.set_version(_T(""));  // Clear value.

-  expected_data1.set_previous_version(_T(""));  // Clear value.

-  expected_data1.set_did_run(AppData::ACTIVE_UNKNOWN);  // Clear value.

-  expected_data1.set_display_name(_T("foo"));

-  expected_data1.set_browser_type(BROWSER_IE);

-  expected_data1.set_install_source(_T("one_click"));

-  expected_data1.set_encoded_installer_data(_T("%20foobar"));

-  expected_data1.set_install_data_index(_T("foobar"));

-  expected_data1.set_usage_stats_enable(TRISTATE_TRUE);

-  expected_data1.set_referral_id(_T("referrer1"));

-  expected_data1.set_is_eula_accepted(false);

-

-  AppData expected_data2(StringToGuid(kGuid2), false);

-  PopulateExpectedAppData2(&expected_data2);

-  expected_data2.set_version(_T(""));  // Clear value.

-  expected_data2.set_previous_version(_T(""));  // Clear value.

-  expected_data2.set_did_run(AppData::ACTIVE_UNKNOWN);  // Clear value.

-  expected_data2.set_language(_T("abc"));

-  expected_data2.set_display_name(_T("bar"));

-  expected_data2.set_browser_type(BROWSER_IE);

-  expected_data2.set_install_source(_T("one_click"));

-  expected_data2.set_usage_stats_enable(TRISTATE_TRUE);

-  // Override unique expected data because the args apply to all apps.

-  expected_data2.set_iid(

-      StringToGuid(_T("{F723495F-8ACF-4746-8240-643741C797B5}")));

-  expected_data2.set_brand_code(_T("GOOG"));

-  expected_data2.set_client_id(_T("someclient"));

-  expected_data2.set_referral_id(_T("referrer1"));

-  expected_data2.set_is_eula_accepted(false);

-

-  ProductDataVector products;

-  AppManager app_manager(false);

-  app_manager.ConvertCommandLineToProductData(args, &products);

-

-  ASSERT_EQ(2, products.size());

-  ASSERT_EQ(0, products[0].num_components());

-  ASSERT_EQ(0, products[1].num_components());

-  ValidateExpectedValues(expected_data1, products[0].app_data());

-  ValidateExpectedValues(expected_data2, products[1].app_data());

-}

-

-TEST_F(AppManagerTest, WritePreInstallData_Machine) {

-  AppData app_data(guid1_, true);

-  ASSERT1(app_data.is_eula_accepted());

-  WritePreInstallDataTest(app_data);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathMachine,

-                                _T("oeminstall")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathMachine,

-                                _T("eulaaccepted")));

-}

-

-TEST_F(AppManagerTest, WritePreInstallData_Machine_IsOem) {

-  const DWORD now = Time64ToInt32(GetCurrent100NSTime());

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("OemInstallTime"),

-                                    now));

-  if (vista_util::IsVistaOrLater()) {

-    ASSERT_SUCCEEDED(RegKey::SetValue(

-        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),

-        _T("ImageState"),

-        _T("IMAGE_STATE_UNDEPLOYABLE")));

-  } else {

-    ASSERT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),

-                                      _T("AuditInProgress"),

-                                      static_cast<DWORD>(1)));

-  }

-

-  AppData app_data(guid1_, true);

-  ASSERT1(app_data.is_eula_accepted());

-  WritePreInstallDataTest(app_data);

-

-  CString oeminstall;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathMachine,

-                                    _T("oeminstall"),

-                                    &oeminstall));

-  EXPECT_STREQ(_T("1"), oeminstall);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathMachine,

-                                _T("eulaaccepted")));

-}

-

-// Creates the ClientStateMedium key with the appropriate permissions then

-// verifies that the created app subkey inherits those.

-// The Update key must be created first to avoid applying ClientStateMedium's

-// permissions to all its parent keys.

-// This keys in this test need to inherit the HKLM privileges, so put the

-// override root in HKLM.

-TEST_F(AppManagerTest,

-       WritePreInstallData_Machine_CheckClientStateMediumPermissions) {

-  const TCHAR kRegistryHiveOverrideRootInHklm[] =

-      _T("HKLM\\Software\\Google\\Update\\UnitTest\\");

-  RestoreRegistryHives();

-  hive_override_key_name_ = kRegistryHiveOverrideRootInHklm;

-  RegKey::DeleteKey(hive_override_key_name_);

-  OverrideRegistryHives(hive_override_key_name_);

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(

-      ConfigManager::Instance()->machine_registry_update()));

-  CreateClientStateMediumKey();

-

-  AppData app_data(guid1_, true);

-  ASSERT1(app_data.is_eula_accepted());

-  WritePreInstallDataTest(app_data);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathMachine,

-                                _T("oeminstall")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathMachine,

-                                _T("eulaaccepted")));

-

-  const CString app_client_state_medium_key_name = AppendRegKeyPath(

-      _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\"),

-      kGuid1);

-  VerifyHklmKeyHasMediumIntegrity(app_client_state_medium_key_name);

-  VerifyHklmKeyHasDefaultIntegrity(

-      _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\"));

-}

-

-TEST_F(AppManagerTest,

-       WritePreInstallData_Machine_ClearClientStateMediumUsageStats) {

-  const CString client_state_key_name =

-      AppendRegKeyPath(MACHINE_REG_CLIENT_STATE_MEDIUM, kGuid1);

-  EXPECT_SUCCEEDED(RegKey::SetValue(client_state_key_name,

-                                    _T("usagestats"),

-                                    static_cast<DWORD>(1)));

-

-  AppData app_data(guid1_, true);

-  WritePreInstallDataTest(app_data);

-

-  EXPECT_FALSE(RegKey::HasValue(client_state_key_name, _T("usagestats")));

-}

-

-// Tests the EULA accepted case too.

-TEST_F(AppManagerTest, WritePreInstallData_User) {

-  AppData app_data(guid1_, false);

-  ASSERT1(app_data.is_eula_accepted());

-  WritePreInstallDataTest(app_data);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("oeminstall")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("eulaaccepted")));

-}

-

-TEST_F(AppManagerTest,

-       WritePreInstallData_User_EulaNotAcceptedAppNotRegistered) {

-  AppData app_data(guid1_, false);

-  app_data.set_is_eula_accepted(false);

-

-  WritePreInstallDataTest(app_data);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("oeminstall")));

-

-  DWORD eula_accepted = 99;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("eulaaccepted"),

-                                    &eula_accepted));

-  EXPECT_EQ(0, eula_accepted);

-}

-

-TEST_F(AppManagerTest,

-       WritePreInstallData_User_EulaNotAcceptedAppAlreadyInstalled) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientsKeyPathUser,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  AppData app_data(guid1_, false);

-  app_data.set_is_eula_accepted(false);

-

-  WritePreInstallDataTest(app_data);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("oeminstall")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("eulaaccepted")));

-}

-

-TEST_F(AppManagerTest,

-       WritePreInstallData_User_EulaAcceptedAppAlreadyInstalled) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientsKeyPathUser,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-

-  AppData app_data(guid1_, false);

-  app_data.set_is_eula_accepted(true);

-

-  WritePreInstallDataTest(app_data);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("oeminstall")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("eulaaccepted")));

-}

-

-TEST_F(AppManagerTest,

-       WritePreInstallData_User_EulaAcceptedAppAlreadyInstalledAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientsKeyPathUser,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  AppData app_data(guid1_, false);

-  app_data.set_is_eula_accepted(true);

-

-  WritePreInstallDataTest(app_data);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("oeminstall")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("eulaaccepted")));

-}

-

-TEST_F(AppManagerTest,

-       WritePreInstallData_User_EulaAcceptedAppAlreadyInstalledNotAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientsKeyPathUser,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  AppData app_data(guid1_, false);

-  app_data.set_is_eula_accepted(true);

-

-  WritePreInstallDataTest(app_data);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("oeminstall")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("eulaaccepted")));

-}

-

-TEST_F(AppManagerTest, ReadProductDataFromStore_MachineNoAppTest) {

-  ProductData product_data;

-  AppManager app_manager(true);

-  ASSERT_FAILED(app_manager.ReadProductDataFromStore(guid1_, &product_data));

-}

-

-TEST_F(AppManagerTest, ReadProductDataFromStore_UserAppTest) {

-  AppData expected_data(guid1_, false);

-  PopulateExpectedAppData1(&expected_data);

-  CreateAppRegistryState(expected_data);

-

-  AppManager app_manager(false);

-  ProductData product_data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));

-  ValidateExpectedValues(expected_data, product_data.app_data());

-}

-

-TEST_F(AppManagerTest, ReadProductDataFromStore_MachineAppTest) {

-  AppData expected_data(guid1_, true);

-  PopulateExpectedAppData1(&expected_data);

-  CreateAppRegistryState(expected_data);

-

-  AppManager app_manager(true);

-  ProductData product_data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));

-  ValidateExpectedValues(expected_data, product_data.app_data());

-}

-

-TEST_F(AppManagerTest, ReadProductDataFromStore_UserAppTest_EulaNotAccepted) {

-  AppData expected_data(guid1_, false);

-  PopulateExpectedAppData1(&expected_data);

-  CreateAppRegistryState(expected_data);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  expected_data.set_is_eula_accepted(false);

-

-  AppManager app_manager(false);

-  ProductData product_data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));

-  ValidateExpectedValues(expected_data, product_data.app_data());

-}

-

-TEST_F(AppManagerTest, ReadProductDataFromStore_UserAppTest_EulaAccepted) {

-  AppData expected_data(guid1_, false);

-  PopulateExpectedAppData1(&expected_data);

-  CreateAppRegistryState(expected_data);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  expected_data.set_is_eula_accepted(true);

-

-  AppManager app_manager(false);

-  ProductData product_data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));

-  ValidateExpectedValues(expected_data, product_data.app_data());

-}

-

-TEST_F(AppManagerTest,

-       ReadProductDataFromStore_MachineAppTest_EulaNotAccepted) {

-  AppData expected_data(guid1_, true);

-  PopulateExpectedAppData1(&expected_data);

-  CreateAppRegistryState(expected_data);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathMachine,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  expected_data.set_is_eula_accepted(false);

-

-  AppManager app_manager(true);

-  ProductData product_data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));

-  ValidateExpectedValues(expected_data, product_data.app_data());

-}

-

-TEST_F(AppManagerTest,

-       ReadProductDataFromStore_MachineAppTest_EulaAccepted) {

-  AppData expected_data(guid1_, true);

-  PopulateExpectedAppData1(&expected_data);

-  CreateAppRegistryState(expected_data);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathMachine,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-  expected_data.set_is_eula_accepted(true);

-

-  AppManager app_manager(true);

-  ProductData product_data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));

-  ValidateExpectedValues(expected_data, product_data.app_data());

-}

-

-TEST_F(AppManagerTest, ReadProductDataFromStore_TwoUserAppTest) {

-  AppData expected_data1(guid1_, false);

-  PopulateExpectedAppData1(&expected_data1);

-  CreateAppRegistryState(expected_data1);

-

-  AppData expected_data2(StringToGuid(kGuid2), false);

-  PopulateExpectedAppData1(&expected_data2);

-  CreateAppRegistryState(expected_data2);

-

-  AppManager app_manager(false);

-  ProductData data1;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data1));

-  ValidateExpectedValues(expected_data1, data1.app_data());

-

-  ProductData data2;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(StringToGuid(kGuid2),

-                                                        &data2));

-  ValidateExpectedValues(expected_data2, data2.app_data());

-}

-

-TEST_F(AppManagerTest, ReadProductDataFromStore_UserAppNoClientStateTest) {

-  AppData expected_data(guid1_, false);

-  PopulateExpectedAppData1(&expected_data);

-  CreateAppRegistryState(expected_data);

-

-  AppManager app_manager(false);

-  ProductData data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));

-  ValidateExpectedValues(expected_data, data.app_data());

-}

-

-TEST_F(AppManagerTest, ReadProductDataFromStore_UninstalledUserApp) {

-  AppData expected_data(guid1_, false);

-  PopulateExpectedUninstalledAppData(&expected_data);

-  CreateAppRegistryState(expected_data);

-

-  AppManager app_manager(false);

-  ProductData data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));

-  ValidateExpectedValues(expected_data, data.app_data());

-}

-

-TEST_F(AppManagerTest, ReadProductDataFromStore_UninstalledMachineApp) {

-  AppData expected_data(guid1_, true);

-  PopulateExpectedUninstalledAppData(&expected_data);

-  CreateAppRegistryState(expected_data);

-

-  AppManager app_manager(true);

-  ProductData data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));

-  ValidateExpectedValues(expected_data, data.app_data());

-}

-

-TEST_F(AppManagerTest,

-       ReadProductDataFromStore_UninstalledUserApp_EulaNotAccepted) {

-  AppData expected_data(guid1_, false);

-  PopulateExpectedUninstalledAppData(&expected_data);

-  expected_data.set_is_eula_accepted(false);

-  CreateAppRegistryState(expected_data);

-

-  AppManager app_manager(false);

-  ProductData data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));

-  ValidateExpectedValues(expected_data, data.app_data());

-}

-

-// Tests the case where Omaha has created the Client State key before running

-// the installer. Uses PopulateExpectedUninstalledAppData then clears pv before

-// writing the data to the registry. is_uninstalled_ is not set to false until

-// after CreateAppRegistryState to prevent Client key from being created.

-TEST_F(AppManagerTest,

-       ReadProductDataFromStore_UserClientStateExistsWithoutPvOrClientKey) {

-  AppData expected_data(guid1_, false);

-  PopulateExpectedUninstalledAppData(&expected_data);

-  expected_data.set_previous_version(_T(""));

-  CreateAppRegistryState(expected_data);

-

-  AppManager app_manager(false);

-  ProductData product_data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));

-

-  expected_data.set_is_uninstalled(false);

-  ValidateExpectedValues(expected_data, product_data.app_data());

-}

-

-TEST_F(AppManagerTest,

-       ReadProductDataFromStore_MachineClientStateExistsWithoutPvOrClientKey) {

-  AppData expected_data(guid1_, true);

-  PopulateExpectedUninstalledAppData(&expected_data);

-  expected_data.set_previous_version(_T(""));

-  CreateAppRegistryState(expected_data);

-

-  AppManager app_manager(true);

-  ProductData data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));

-  expected_data.set_is_uninstalled(false);

-  ValidateExpectedValues(expected_data, data.app_data());

-}

-

-// An empty pv value is the same as a populated one for uninstall checks.

-TEST_F(AppManagerTest,

-       ReadProductDataFromStore_UserClientStateExistsWithEmptyPvNoClientKey) {

-  AppData expected_data(guid1_, false);

-  PopulateExpectedUninstalledAppData(&expected_data);

-  expected_data.set_previous_version(_T(""));

-  CreateAppRegistryState(expected_data);

-

-  // Write the empty pv value.

-  CString client_state_key_name = AppendRegKeyPath(

-      ConfigManager::Instance()->registry_client_state(false),

-      kGuid1);

-  ASSERT_SUCCEEDED(RegKey::SetValue(client_state_key_name,

-                                    kRegValueProductVersion,

-                                    _T("")));

-

-  AppManager app_manager(false);

-  ProductData product_data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));

-

-  expected_data.set_is_uninstalled(true);

-  ValidateExpectedValues(expected_data, product_data.app_data());

-}

-

-TEST_F(AppManagerTest, InitializeApplicationState_UserTest) {

-  InitializeApplicationStateTest(false);

-}

-

-TEST_F(AppManagerTest, InitializeApplicationState_MachineTest) {

-  InitializeApplicationStateTest(true);

-}

-

-TEST_F(AppManagerTest, UpdateApplicationState_UserTest) {

-  UpdateApplicationStateTest(false, kGuid1);

-

-  ValidateClientStateMedium(false, kGuid1);

-}

-

-TEST_F(AppManagerTest, UpdateApplicationState_MachineTest) {

-  UpdateApplicationStateTest(true, kGuid1);

-

-  ValidateClientStateMedium(true, kGuid1);

-}

-

-// Should not create ClientStateMedium key.

-TEST_F(AppManagerTest, UpdateApplicationState_MachineTest_Omaha) {

-  UpdateApplicationStateTest(true, kGoogleUpdateAppId);

-

-  const CString client_state_medium_key_name = AppendRegKeyPath(

-    ConfigManager::Instance()->machine_registry_client_state_medium(),

-    kGoogleUpdateAppId);

-  EXPECT_FALSE(RegKey::HasKey(client_state_medium_key_name));

-}

-

-TEST_F(AppManagerTest, UpdateUpdateAvailableStats_NoExistingStats) {

-  const time64 before_time_in_100ns(GetCurrent100NSTime());

-

-  AppManager app_manager(false);

-  app_manager.UpdateUpdateAvailableStats(GUID_NULL, guid1_);

-

-  const time64 after_time_in_100ns(GetCurrent100NSTime());

-

-  DWORD update_available_count(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    &update_available_count));

-  EXPECT_EQ(1, update_available_count);

-

-  DWORD64 update_available_since_time(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    &update_available_since_time));

-  EXPECT_LE(before_time_in_100ns, update_available_since_time);

-  EXPECT_GE(after_time_in_100ns, update_available_since_time);

-  const DWORD64 time_since_first_update_available =

-      after_time_in_100ns - update_available_since_time;

-  EXPECT_GT(10 * kSecsTo100ns, time_since_first_update_available);

-}

-

-TEST_F(AppManagerTest, UpdateUpdateAvailableStats_WithExistingStats) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(123456)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(9876543210)));

-

-  AppManager app_manager(false);

-  app_manager.UpdateUpdateAvailableStats(GUID_NULL, guid1_);

-

-  DWORD update_available_count(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    &update_available_count));

-  EXPECT_EQ(123457, update_available_count);

-

-  DWORD64 update_available_since_time(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    &update_available_since_time));

-  EXPECT_EQ(9876543210, update_available_since_time);

-}

-

-TEST_F(AppManagerTest, ClearUpdateAvailableStats_KeyNotPresent) {

-  AppManager app_manager(false);

-  ClearUpdateAvailableStats(GUID_NULL, guid1_, &app_manager);

-}

-

-TEST_F(AppManagerTest, ClearUpdateAvailableStats_DataPresent) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(123456)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(9876543210)));

-

-  AppManager app_manager(false);

-  ClearUpdateAvailableStats(GUID_NULL, guid1_, &app_manager);

-

-  EXPECT_TRUE(RegKey::HasKey(kGuid1ClientStateKeyPathUser));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("UpdateAvailableCount")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("UpdateAvailableSince")));

-}

-

-TEST_F(AppManagerTest, ReadUpdateAvailableStats_DataNotPresent) {

-  RegKey::CreateKey(kGuid1ClientStateKeyPathUser);

-

-  DWORD update_responses(1);

-  DWORD64 time_since_first_response_ms(1);

-  AppManager app_manager(false);

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       guid1_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-}

-

-TEST_F(AppManagerTest, ReadUpdateAvailableStats_DataPresent) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(123456)));

-  const DWORD64 kUpdateAvailableSince =

-    GetCurrent100NSTime() - 2 * kMillisecsTo100ns;

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    kUpdateAvailableSince));

-

-  DWORD update_responses(0);

-  DWORD64 time_since_first_response_ms(0);

-  AppManager app_manager(false);

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       guid1_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-

-  EXPECT_EQ(123456, update_responses);

-  EXPECT_LE(2, time_since_first_response_ms);

-  EXPECT_GT(10 * kMsPerSec, time_since_first_response_ms);

-}

-

-// TODO(omaha): Add *UpdateAvailableStats tests with components when

-// component design is finalized and implemented

-

-TEST_F(AppManagerTest, RecordSuccessfulInstall_Install_Online) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(123456)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(9876543210)));

-

-  AppManager app_manager(false);

-  app_manager.RecordSuccessfulInstall(GUID_NULL, guid1_, false, false);

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  // Verify ClearUpdateAvailableStats() was called.

-  EXPECT_TRUE(RegKey::HasKey(kGuid1ClientStateKeyPathUser));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("UpdateAvailableCount")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("UpdateAvailableSince")));

-

-  // Verify update check value is written but update value is not.

-  const uint32 last_check_sec = GetDwordValue(kGuid1ClientStateKeyPathUser,

-                                              kRegValueLastSuccessfulCheckSec);

-  EXPECT_GE(now, last_check_sec);

-  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                kRegValueLastUpdateTimeSec));

-}

-

-TEST_F(AppManagerTest, RecordSuccessfulInstall_Install_Offline) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(123456)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(9876543210)));

-

-  AppManager app_manager(false);

-  app_manager.RecordSuccessfulInstall(GUID_NULL, guid1_, false, true);

-

-  // Verify ClearUpdateAvailableStats() was called.

-  EXPECT_TRUE(RegKey::HasKey(kGuid1ClientStateKeyPathUser));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("UpdateAvailableCount")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("UpdateAvailableSince")));

-

-  // Verify update values are not written.

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                kRegValueLastUpdateTimeSec));

-}

-

-TEST_F(AppManagerTest, RecordSuccessfulInstall_Update_ExistingTimes) {

-  const DWORD kExistingUpdateValues = 0x70123456;

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(123456)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(9876543210)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-

-  AppManager app_manager(false);

-  app_manager.RecordSuccessfulInstall(GUID_NULL, guid1_, true, false);

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  // Verify ClearUpdateAvailableStats() was called.

-  EXPECT_TRUE(RegKey::HasKey(kGuid1ClientStateKeyPathUser));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("UpdateAvailableCount")));

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                _T("UpdateAvailableSince")));

-

-  // Verify update values updated.

-  const uint32 last_check_sec = GetDwordValue(kGuid1ClientStateKeyPathUser,

-                                              kRegValueLastSuccessfulCheckSec);

-  EXPECT_NE(kExistingUpdateValues, last_check_sec);

-  EXPECT_GE(now, last_check_sec);

-  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);

-

-  const uint32 last_update_sec =

-      GetDwordValue(kGuid1ClientStateKeyPathUser, kRegValueLastUpdateTimeSec);

-  EXPECT_NE(kExistingUpdateValues, last_update_sec);

-  EXPECT_GE(now, last_update_sec);

-  EXPECT_GE(static_cast<uint32>(200), now - last_update_sec);

-}

-

-TEST_F(AppManagerTest, RecordSuccessfulInstall_Update_StateKeyDoesNotExist) {

-  AppManager app_manager(false);

-  app_manager.RecordSuccessfulInstall(GUID_NULL, guid1_, true, false);

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  // Verify update values updated.

-  const uint32 last_check_sec = GetDwordValue(kGuid1ClientStateKeyPathUser,

-                                              kRegValueLastSuccessfulCheckSec);

-  EXPECT_GE(now, last_check_sec);

-  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);

-

-  const uint32 last_update_sec =

-      GetDwordValue(kGuid1ClientStateKeyPathUser, kRegValueLastUpdateTimeSec);

-  EXPECT_GE(now, last_update_sec);

-  EXPECT_GE(static_cast<uint32>(200), now - last_update_sec);

-}

-

-TEST_F(AppManagerTest, RecordSuccessfulUpdateCheck_ExistingTime) {

-  const DWORD kExistingUpdateValue = 0x12345678;

-  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValue));

-

-  AppManager app_manager(false);

-  app_manager.RecordSuccessfulUpdateCheck(GUID_NULL, guid1_);

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  const uint32 last_check_sec = GetDwordValue(kGuid1ClientStateKeyPathUser,

-                                              kRegValueLastSuccessfulCheckSec);

-  EXPECT_NE(kExistingUpdateValue, last_check_sec);

-  EXPECT_GE(now, last_check_sec);

-  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                kRegValueLastUpdateTimeSec));

-}

-

-TEST_F(AppManagerTest, RecordSuccessfulUpdateCheck_StateKeyDoesNotExist) {

-  AppManager app_manager(false);

-  app_manager.RecordSuccessfulUpdateCheck(GUID_NULL, guid1_);

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  const uint32 last_check_sec = GetDwordValue(kGuid1ClientStateKeyPathUser,

-                                              kRegValueLastSuccessfulCheckSec);

-  EXPECT_GE(now, last_check_sec);

-  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);

-

-  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,

-                                kRegValueLastUpdateTimeSec));

-}

-

-TEST_F(AppManagerTest, RemoveClientState_Uninstalled) {

-  AppData expected_data(guid1_, true);

-  PopulateExpectedUninstalledAppData(&expected_data);

-  CreateAppRegistryState(expected_data);

-

-  AppManager app_manager(true);

-  ProductData data;

-  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));

-  ASSERT_SUCCEEDED(app_manager.RemoveClientState(data.app_data()));

-  ASSERT_FALSE(IsClientStateKeyPresent(expected_data));

-}

-

-class AppManagerTest2 : public testing::Test {

- protected:

-  AppManagerTest2()

-      : hive_override_key_name_(kRegistryHiveOverrideRoot) {}

-

-  virtual void SetUp() {

-    RegKey::DeleteKey(hive_override_key_name_);

-    OverrideRegistryHives(hive_override_key_name_);

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    RegKey::DeleteKey(hive_override_key_name_);

-  }

-

-  CString hive_override_key_name_;

-};

-

-// Create 2 registered app and 1 unregistered app and populates the parameters.

-// Each is written to the registry.

-// Also creates partial Clients and ClientState keys and creates an a registered

-// and unregistered app in the opposite registry hive.

-void PopulateDataAndRegistryForRegisteredAndUnRegisteredApplicationsTests(

-    bool is_machine,

-    AppData* expected_data1,

-    AppData* expected_data2,

-    AppData* expected_data3) {

-

-  expected_data1->set_app_guid(StringToGuid(kGuid1));

-  expected_data1->set_is_machine_app(is_machine);

-  AppManagerTest::PopulateExpectedAppData1(expected_data1);

-  AppManagerTest::CreateAppRegistryState(*expected_data1);

-

-  expected_data2->set_app_guid(StringToGuid(kGuid2));

-  expected_data2->set_is_machine_app(is_machine);

-  AppManagerTest::PopulateExpectedAppData2(expected_data2);

-  AppManagerTest::CreateAppRegistryState(*expected_data2);

-

-  expected_data3->set_app_guid(StringToGuid(kGuid3));

-  expected_data3->set_is_machine_app(is_machine);

-  AppManagerTest::PopulateExpectedUninstalledAppData(expected_data3);

-  AppManagerTest::CreateAppRegistryState(*expected_data3);

-

-  // Add incomplete Clients and ClientState entries.

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(

-      AppendRegKeyPath(is_machine ? MACHINE_REG_CLIENTS : USER_REG_CLIENTS,

-                       kGuid4),

-      _T("name"),

-      _T("foo")));

-

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(

-      AppendRegKeyPath(is_machine ? MACHINE_REG_CLIENT_STATE :

-                                    USER_REG_CLIENT_STATE,

-                       kGuid5),

-      kRegValueDidRun,

-      _T("1")));

-

-  // Add registered and unregistered app to the opposite registry hive.

-  AppData opposite_hive_data1(StringToGuid(kGuid6), !is_machine);

-  AppManagerTest::PopulateExpectedAppData2(&opposite_hive_data1);

-  AppManagerTest::CreateAppRegistryState(opposite_hive_data1);

-

-  AppData opposite_hive_data2(StringToGuid(kGuid7), !is_machine);

-  AppManagerTest::PopulateExpectedUninstalledAppData(&opposite_hive_data2);

-  AppManagerTest::CreateAppRegistryState(opposite_hive_data2);

-}

-

-TEST_F(AppManagerTest2, GetRegisteredApplications_machine) {

-  AppData expected_data1, expected_data2, expected_data3;

-  PopulateDataAndRegistryForRegisteredAndUnRegisteredApplicationsTests(

-      true,

-      &expected_data1,

-      &expected_data2,

-      &expected_data3);

-

-  AppManager app_manager(true);

-

-  ProductDataVector products;

-  ASSERT_HRESULT_SUCCEEDED(app_manager.GetRegisteredProducts(&products));

-  ASSERT_EQ(2, products.size());

-

-  ASSERT_TRUE(::IsEqualGUID(products[0].app_data().app_guid(),

-              StringToGuid(kGuid1)));

-  ValidateExpectedValues(expected_data1, products[0].app_data());

-

-  ASSERT_TRUE(::IsEqualGUID(products[1].app_data().app_guid(),

-              StringToGuid(kGuid2)));

-  ValidateExpectedValues(expected_data2, products[1].app_data());

-}

-

-TEST_F(AppManagerTest2, GetRegisteredApplications_user) {

-  AppData expected_data1, expected_data2, expected_data3;

-  PopulateDataAndRegistryForRegisteredAndUnRegisteredApplicationsTests(

-      false,

-      &expected_data1,

-      &expected_data2,

-      &expected_data3);

-

-  AppManager app_manager(false);

-

-

-  ProductDataVector products;

-  ASSERT_HRESULT_SUCCEEDED(app_manager.GetRegisteredProducts(&products));

-  ASSERT_EQ(2, products.size());

-

-  ASSERT_TRUE(::IsEqualGUID(products[0].app_data().app_guid(),

-              StringToGuid(kGuid1)));

-  ValidateExpectedValues(expected_data1, products[0].app_data());

-

-  ASSERT_TRUE(::IsEqualGUID(products[1].app_data().app_guid(),

-              StringToGuid(kGuid2)));

-  ValidateExpectedValues(expected_data2, products[1].app_data());

-}

-

-TEST_F(AppManagerTest2, GetUnRegisteredApplications_machine) {

-  AppData expected_data1, expected_data2, expected_data3;

-  PopulateDataAndRegistryForRegisteredAndUnRegisteredApplicationsTests(

-      true,

-      &expected_data1,

-      &expected_data2,

-      &expected_data3);

-

-  AppManager app_manager(true);

-

-  ProductDataVector unreg_products;

-  ASSERT_HRESULT_SUCCEEDED(

-      app_manager.GetUnRegisteredProducts(&unreg_products));

-  ASSERT_EQ(1, unreg_products.size());

-

-  ValidateExpectedValues(expected_data3, unreg_products[0].app_data());

-}

-

-TEST_F(AppManagerTest2, GetUnRegisteredApplications_user) {

-  AppData expected_data1, expected_data2, expected_data3;

-  PopulateDataAndRegistryForRegisteredAndUnRegisteredApplicationsTests(

-      false,

-      &expected_data1,

-      &expected_data2,

-      &expected_data3);

-  AppManager app_manager(false);

-

-  ProductDataVector unreg_products;

-  ASSERT_HRESULT_SUCCEEDED(

-      app_manager.GetUnRegisteredProducts(&unreg_products));

-  ASSERT_EQ(1, unreg_products.size());

-

-  ValidateExpectedValues(expected_data3, unreg_products[0].app_data());

-}

-

-TEST_F(AppManagerTest2, UpdateLastChecked) {

-  AppManager app_manager(false);

-

-  EXPECT_SUCCEEDED(app_manager.UpdateLastChecked());

-  EXPECT_FALSE(app_manager.ShouldCheckForUpdates());

-

-  ConfigManager::Instance()->SetLastCheckedTime(false, 0);

-  EXPECT_TRUE(app_manager.ShouldCheckForUpdates());

-}

-

-TEST_F(AppManagerTest, ShouldCheckForUpdates_NoLastCheckedPresent) {

-  AppManager app_manager(false);

-  EXPECT_TRUE(app_manager.ShouldCheckForUpdates());

-}

-

-TEST_F(AppManagerTest, ShouldCheckForUpdates_LastCheckedPresent) {

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-  AppManager app_manager(false);

-

-  ConfigManager::Instance()->SetLastCheckedTime(false, now - 10);

-  EXPECT_FALSE(app_manager.ShouldCheckForUpdates());

-

-  ConfigManager::Instance()->SetLastCheckedTime(false,

-                                                now - kLastCheckPeriodSec - 1);

-  EXPECT_TRUE(app_manager.ShouldCheckForUpdates());

-}

-

-TEST_F(AppManagerTest, ShouldCheckForUpdates_LastCheckedInFuture) {

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-  AppManager app_manager(false);

-

-  // The absolute difference is within the check period.

-  ConfigManager::Instance()->SetLastCheckedTime(false, now + 600);

-  EXPECT_FALSE(app_manager.ShouldCheckForUpdates());

-

-  // The absolute difference is greater than the check period.

-  ConfigManager::Instance()->SetLastCheckedTime(false,

-                                                now + kLastCheckPeriodSec + 1);

-  EXPECT_TRUE(app_manager.ShouldCheckForUpdates());

-}

-

-TEST_F(AppManagerTest, ShouldCheckForUpdates_PeriodZero) {

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,

-                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                       static_cast<DWORD>(0)));

-

-  AppManager app_manager(false);

-  EXPECT_FALSE(app_manager.ShouldCheckForUpdates());

-}

-

-TEST_F(AppManagerTest, ShouldCheckForUpdates_PeriodOverride) {

-  const DWORD kOverrideMinutes = 10;

-  const DWORD kOverrideSeconds = kOverrideMinutes * 60;

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-  AppManager app_manager(false);

-

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,

-                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,

-                       kOverrideMinutes));

-

-  ConfigManager::Instance()->SetLastCheckedTime(false, now - 10);

-  EXPECT_FALSE(app_manager.ShouldCheckForUpdates());

-

-  ConfigManager::Instance()->SetLastCheckedTime(false,

-                                                now - kOverrideSeconds - 1);

-  EXPECT_TRUE(app_manager.ShouldCheckForUpdates());

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// ApplicationManager unit tests
+
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/time.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/enterprise/const_group_policy.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/setup/setup_google_update.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/job.h"
+
+namespace omaha {
+
+namespace {
+
+const TCHAR* const kGuid1 = _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");
+const TCHAR* const kGuid2 = _T("{A979ACBD-1F55-4b12-A35F-4DBCA5A7CCB8}");
+const TCHAR* const kGuid3 = _T("{661045C5-4429-4140-BC48-8CEA241D1DEF}");
+const TCHAR* const kGuid4 = _T("{AAFA1CF9-E94F-42e6-A899-4CD27F37D5A7}");
+const TCHAR* const kGuid5 = _T("{3B1A3CCA-0525-4418-93E6-A0DB3398EC9B}");
+const TCHAR* const kGuid6 = _T("{F3F2CFD4-5F98-4bf0-ABB0-BEEEA46C62B4}");
+const TCHAR* const kGuid7 = _T("{6FD2272F-8583-4bbd-895A-E65F8003FC7B}");
+
+const TCHAR* const kGuid1ClientsKeyPathUser =
+    _T("HKCU\\Software\\Google\\Update\\Clients\\")
+    _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");
+const TCHAR* const kGuid1ClientStateKeyPathUser =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\")
+    _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");
+const TCHAR* const kGuid1ClientStateKeyPathMachine =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");
+
+}  // namespace
+
+void ValidateExpectedValues(const AppData& expected, const AppData& actual);
+void VerifyHklmKeyHasMediumIntegrity(const CString& key_full_name);
+void VerifyHklmKeyHasDefaultIntegrity(const CString& key_full_name);
+
+class AppManagerTest : public testing::Test {
+ public:
+  // Creates the application registration entries based on the passed in data.
+  // If passed an application that is uninstalled, the method only creates
+  // the registration entries in the client state and no information is written
+  // in the clients.
+  static void CreateAppRegistryState(const AppData& data) {
+    bool is_machine = data.is_machine_app();
+    CString client_key_name = AppendRegKeyPath(
+        ConfigManager::Instance()->registry_clients(is_machine),
+        GuidToString(data.app_guid()));
+    CString client_state_key_name = AppendRegKeyPath(
+        ConfigManager::Instance()->registry_client_state(is_machine),
+        GuidToString(data.app_guid()));
+
+    RegKey client_key;
+    if (!data.is_uninstalled()) {
+      ASSERT_SUCCEEDED(client_key.Create(client_key_name));
+
+      if (!data.version().IsEmpty()) {
+        ASSERT_SUCCEEDED(client_key.SetValue(kRegValueProductVersion,
+                                             data.version()));
+      }
+    }
+
+    RegKey client_state_key;
+    ASSERT_SUCCEEDED(client_state_key.Create(client_state_key_name));
+
+    if (!data.previous_version().IsEmpty()) {
+      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueProductVersion,
+                                                 data.previous_version()));
+    }
+
+    if (!data.language().IsEmpty()) {
+      if (data.is_uninstalled()) {
+        ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueLanguage,
+                                                   data.language()));
+      } else {
+        ASSERT_SUCCEEDED(client_key.SetValue(kRegValueLanguage,
+                                             data.language()));
+      }
+    }
+
+    if (data.did_run() != AppData::ACTIVE_UNKNOWN) {
+      CString dr = (data.did_run() == AppData::ACTIVE_NOTRUN) ? _T("0") :
+                                                                _T("1");
+      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueDidRun,
+                                                 dr));
+    }
+
+    if (!data.ap().IsEmpty()) {
+      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueAdditionalParams,
+                                                 data.ap()));
+    }
+
+    if (!data.tt_token().IsEmpty()) {
+      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueTTToken,
+                                                 data.tt_token()));
+    }
+
+    if (!::IsEqualGUID(data.iid(), GUID_NULL)) {
+      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueInstallationId,
+                                                 GuidToString(data.iid())));
+    }
+
+    if (!data.brand_code().IsEmpty()) {
+      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueBrandCode,
+                                                 data.brand_code()));
+    }
+
+    if (!data.client_id().IsEmpty()) {
+      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueClientId,
+                                                 data.client_id()));
+    }
+
+    if (!data.referral_id().IsEmpty()) {
+      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueReferralId,
+                                                 data.referral_id()));
+    }
+
+    if (!data.referral_id().IsEmpty()) {
+      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueReferralId,
+                                                 data.referral_id()));
+    }
+
+    if (data.install_time_diff_sec()) {
+      const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+      const DWORD install_time = now - data.install_time_diff_sec();
+      ASSERT_SUCCEEDED(client_state_key.SetValue(kRegValueInstallTimeSec,
+                                                 install_time));
+    }
+
+    if (!data.is_eula_accepted()) {
+      ASSERT_SUCCEEDED(client_state_key.SetValue(_T("eulaaccepted"),
+                                                 static_cast<DWORD>(0)));
+    }
+  }
+
+  static void PopulateExpectedAppData1(AppData* expected_app) {
+    ASSERT_TRUE(expected_app);
+    expected_app->set_version(_T("1.1.1.3"));
+    expected_app->set_previous_version(_T("1.0.0.0"));
+    expected_app->set_language(_T("abc"));
+    expected_app->set_ap(_T("Test ap"));
+    expected_app->set_tt_token(_T("Test TT Token"));
+    expected_app->set_iid(
+        StringToGuid(_T("{F723495F-8ACF-4746-8240-643741C797B5}")));
+    expected_app->set_brand_code(_T("GOOG"));
+    expected_app->set_client_id(_T("someclient"));
+    // Do not set referral_id or install_time_diff_sec because these are not
+    // expected in most cases.
+    // This value must be ACTIVE_RUN for UpdateApplicationStateTest to work.
+    expected_app->set_did_run(AppData::ACTIVE_RUN);
+  }
+
+  static void PopulateExpectedAppData1InvalidBrand(AppData* expected_app) {
+    PopulateExpectedAppData1(expected_app);
+    expected_app->set_brand_code(_T("GOOG1122"));
+  }
+
+  static void PopulateExpectedAppData2(AppData* expected_app) {
+    ASSERT_TRUE(expected_app);
+    expected_app->set_version(_T("1.2.1.3"));
+    expected_app->set_previous_version(_T("1.1.0.0"));
+    expected_app->set_language(_T("de"));
+    expected_app->set_ap(_T("beta"));
+    expected_app->set_tt_token(_T("beta TT Token"));
+    expected_app->set_iid(
+        StringToGuid(_T("{431EC961-CFD8-49ea-AB7B-2B99BCA274AD}")));
+    expected_app->set_brand_code(_T("GooG"));
+    expected_app->set_client_id(_T("anotherclient"));
+    expected_app->set_did_run(AppData::ACTIVE_NOTRUN);
+  }
+
+  static void PopulateExpectedUninstalledAppData(AppData* expected_app) {
+    ASSERT_TRUE(expected_app);
+    PopulateExpectedAppData2(expected_app);
+
+    // Make the AppData represent an uninstall.
+    expected_app->set_version(_T(""));
+    expected_app->set_is_uninstalled(true);
+  }
+
+ protected:
+  AppManagerTest()
+      : hive_override_key_name_(kRegistryHiveOverrideRoot),
+        guid1_(StringToGuid(kGuid1)) {}
+
+  virtual void SetUp() {
+    RegKey::DeleteKey(hive_override_key_name_);
+    OverrideRegistryHives(hive_override_key_name_);
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    RegKey::DeleteKey(hive_override_key_name_);
+  }
+
+  void ClearUpdateAvailableStats(const GUID& parent_app_guid,
+                                 const GUID& app_guid,
+                                 AppManager* app_manager) {
+    ASSERT_TRUE(app_manager);
+    app_manager->ClearUpdateAvailableStats(parent_app_guid, app_guid);
+  }
+
+  bool IsClientStateKeyPresent(const AppData& data) {
+    CString client_state_key_name = AppendRegKeyPath(
+        ConfigManager::Instance()->registry_client_state(data.is_machine_app()),
+        GuidToString(data.app_guid()));
+
+    return RegKey::HasKey(client_state_key_name);
+  }
+
+  void InitializeApplicationStateTest(bool is_machine) {
+    // Create the test data.
+    AppData expected_data(guid1_, is_machine);
+    expected_data.set_version(_T("4.5.6.7"));
+    expected_data.set_language(_T("de"));
+    CreateAppRegistryState(expected_data);
+
+    // Create the job that contains the test data.
+
+    CommandLineAppArgs extra;
+    extra.app_guid = guid1_;
+    extra.app_name = _T("foo");
+    extra.ap = _T("test ap");
+    extra.tt_token = _T("test TT Token");
+
+    CommandLineArgs args;
+    args.extra.installation_id =
+        StringToGuid(_T("{64333341-CA93-490d-9FB7-7FC5728721F4}"));
+    args.extra.brand_code = _T("g00g");
+    args.extra.client_id = _T("myclient");
+    args.extra.referral_id = _T("somereferrer");
+    args.extra.language = _T("en");
+    args.extra.apps.push_back(extra);
+
+    AppManager app_manager(is_machine);
+    ProductDataVector products;
+    app_manager.ConvertCommandLineToProductData(args, &products);
+    ASSERT_EQ(1, products.size());
+
+    AppData product_app_data = products[0].app_data();
+
+    EXPECT_TRUE(product_app_data.is_eula_accepted());
+
+    // Test the method.
+    ASSERT_SUCCEEDED(
+        app_manager.InitializeApplicationState(&product_app_data));
+
+    // Validate the results.
+    CString client_state_key_name = AppendRegKeyPath(
+        ConfigManager::Instance()->registry_client_state(is_machine),
+        kGuid1);
+    RegKey client_state_key;
+    ASSERT_SUCCEEDED(client_state_key.Create(client_state_key_name));
+
+    ValidateClientStateMedium(is_machine, kGuid1);
+
+    // Check version is copied to the client state.
+    CString previous_version;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueProductVersion,
+                                               &previous_version));
+    EXPECT_STREQ(_T("4.5.6.7"), product_app_data.version());
+    EXPECT_STREQ(_T("4.5.6.7"), previous_version);
+
+    // Check language is copied to the client state.
+    CString language;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueLanguage, &language));
+    EXPECT_STREQ(_T("de"), product_app_data.language());
+    EXPECT_STREQ(_T("de"), language);
+
+    // Check iid is set correctly in ClientState.
+    CString iid;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueInstallationId, &iid));
+    EXPECT_STREQ(_T("{64333341-CA93-490D-9FB7-7FC5728721F4}"),
+                 GuidToString(product_app_data.iid()));
+    EXPECT_STREQ(_T("{64333341-CA93-490D-9FB7-7FC5728721F4}"), iid);
+
+    // Check other values were not written.
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueAdditionalParams));
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueBrandCode));
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueBrowser));
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueClientId));
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueDidRun));
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueOemInstall));
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueReferralId));
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueEulaAccepted));
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueUsageStats));
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueInstallTimeSec));
+    EXPECT_FALSE(client_state_key.HasValue(kRegValueTTToken));
+  }
+
+  void UpdateApplicationStateTest(bool is_machine, const CString& app_id) {
+    const CString client_state_key_name = AppendRegKeyPath(
+        ConfigManager::Instance()->registry_client_state(is_machine),
+        app_id);
+
+    // Create the test data.
+    AppData expected_data(StringToGuid(app_id), is_machine);
+    PopulateExpectedAppData1(&expected_data);
+    expected_data.set_referral_id(_T("referrer"));
+    expected_data.set_is_eula_accepted(false);
+    expected_data.set_install_time_diff_sec(141516);
+    CreateAppRegistryState(expected_data);
+
+    EXPECT_TRUE(RegKey::HasValue(client_state_key_name, _T("referral")));
+
+    // Call the test method.
+    ProductData product_data;
+    AppManager app_manager(is_machine);
+    EXPECT_SUCCEEDED(app_manager.ReadProductDataFromStore(StringToGuid(app_id),
+                                                          &product_data));
+
+    EXPECT_TRUE(product_data.app_data().referral_id().IsEmpty());
+
+    AppData app_data_temp = product_data.app_data();
+    EXPECT_SUCCEEDED(app_manager.UpdateApplicationState(&app_data_temp));
+    product_data.set_app_data(app_data_temp);
+
+    EXPECT_TRUE(app_data_temp.referral_id().IsEmpty());
+
+    // Need to call again to refresh the values created/copied by
+    // UpdateApplicationState().
+    EXPECT_SUCCEEDED(app_manager.ReadProductDataFromStore(StringToGuid(app_id),
+                                                          &product_data));
+    const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+    EXPECT_TRUE(product_data.app_data().referral_id().IsEmpty());
+
+    // Validate the results.
+    RegKey client_state_key;
+    EXPECT_SUCCEEDED(client_state_key.Open(client_state_key_name));
+
+    // Check version and language have been copied to client state.
+    CString previous_version;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueProductVersion,
+                                               &previous_version));
+    EXPECT_STREQ(expected_data.version(), previous_version);
+
+    CString language;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueLanguage,
+                                               &language));
+    EXPECT_STREQ(expected_data.language(), language);
+
+    // Check installation id removed.
+    CString iid;
+    EXPECT_FAILED(client_state_key.GetValue(kRegValueInstallationId,
+                                            &iid));
+    EXPECT_TRUE(iid.IsEmpty());
+
+    // Check did_run is cleared.
+    CString did_run;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueDidRun,
+                                               &did_run));
+    EXPECT_STREQ(_T("0"), did_run);
+
+    // Check that ap, brand_code, and client_id are not changed.
+    CString ap;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueAdditionalParams,
+                                               &ap));
+    EXPECT_STREQ(expected_data.ap(), ap);
+
+    CString tt_token;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueTTToken,
+                                               &tt_token));
+    EXPECT_STREQ(expected_data.tt_token(), tt_token);
+
+    CString brand_code;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueBrandCode,
+                                               &brand_code));
+    EXPECT_STREQ(expected_data.brand_code(), brand_code);
+
+    CString client_id;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueClientId,
+                                               &client_id));
+    EXPECT_STREQ(expected_data.client_id(), client_id);
+
+    // install_time_diff_sec should be roughly the same as now - installed.
+    DWORD install_time(0);
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueInstallTimeSec,
+                                               &install_time));
+    const DWORD calculated_install_diff = now - install_time;
+    EXPECT_GE(calculated_install_diff, expected_data.install_time_diff_sec());
+    EXPECT_GE(static_cast<uint32>(500),
+              calculated_install_diff - expected_data.install_time_diff_sec());
+
+    DWORD eula_accepted = 0;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(_T("eulaaccepted"),
+                                               &eula_accepted));
+    EXPECT_EQ(0, eula_accepted);
+    EXPECT_FALSE(expected_data.is_eula_accepted());
+  }
+
+  void WritePreInstallDataTest(const AppData& app_data_in) {
+    const bool is_machine = app_data_in.is_machine_app();
+    const CString client_key_name = AppendRegKeyPath(
+        ConfigManager::Instance()->registry_clients(is_machine), kGuid1);
+    const CString client_state_key_name = AppendRegKeyPath(
+        ConfigManager::Instance()->registry_client_state(is_machine),
+        kGuid1);
+
+    const bool expect_has_client_key = RegKey::HasKey(client_key_name);
+
+    // Populate the test data.
+    AppData app_data(app_data_in);
+    app_data.set_brand_code(_T("GGLG"));
+    app_data.set_client_id(_T("someclient"));
+    app_data.set_referral_id(_T("referrer"));
+    app_data.set_install_time_diff_sec(657812);   // Not used.
+    app_data.set_usage_stats_enable(TRISTATE_TRUE);
+    app_data.set_browser_type(BROWSER_FIREFOX);
+    app_data.set_ap(_T("test_ap"));
+    app_data.set_language(_T("en"));
+    app_data.set_version(_T("1.2.3.4"));
+
+    AppManager app_manager(is_machine);
+    app_manager.WritePreInstallData(app_data);
+    const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+    // Validate the results.
+
+    // WritePreInstallData should never write to client_key, so it shouldn't
+    // exist if it did not before the method call.
+    EXPECT_EQ(expect_has_client_key, RegKey::HasKey(client_key_name));
+
+    // ClientStateKey should exist.
+    RegKey client_state_key;
+    EXPECT_SUCCEEDED(client_state_key.Open(client_state_key_name));
+
+    ValidateClientStateMedium(is_machine, kGuid1);
+
+    CString brand_code;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueBrandCode,
+                                               &brand_code));
+    EXPECT_STREQ(_T("GGLG"), brand_code);
+
+    CString client_id;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueClientId, &client_id));
+    EXPECT_STREQ(_T("someclient"), client_id);
+
+    CString referral_id;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueReferralId,
+                                               &referral_id));
+    EXPECT_STREQ(_T("referrer"), referral_id);
+
+    DWORD install_time(0);
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueInstallTimeSec,
+                                               &install_time));
+    EXPECT_GE(now, install_time);
+    EXPECT_GE(static_cast<uint32>(200), now - install_time);
+
+    DWORD usage_stats_enable = 0;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(_T("usagestats"),
+                                               &usage_stats_enable));
+    EXPECT_EQ(TRISTATE_TRUE, usage_stats_enable);
+
+    DWORD browser_type = 0;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueBrowser,
+                                               &browser_type));
+    EXPECT_EQ(BROWSER_FIREFOX, browser_type);
+
+    CString ap;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueAdditionalParams, &ap));
+    EXPECT_STREQ(_T("test_ap"), ap);
+
+    CString lang;
+    EXPECT_SUCCEEDED(client_state_key.GetValue(kRegValueLanguage, &lang));
+    EXPECT_STREQ(_T("en"), lang);
+
+    // Version should not be written to clientstate by WritePreInstallData().
+    EXPECT_FALSE(RegKey::HasValue(client_state_key_name,
+                                  kRegValueProductVersion));
+  }
+
+  void ValidateClientStateMedium(bool is_machine, const CString& app_guid) {
+    const CString client_state_medium_key_name = AppendRegKeyPath(
+        ConfigManager::Instance()->machine_registry_client_state_medium(),
+        app_guid);
+    if (is_machine) {
+      RegKey client_state_medium_key;
+      EXPECT_SUCCEEDED(
+          client_state_medium_key.Open(client_state_medium_key_name));
+      EXPECT_EQ(0, client_state_medium_key.GetValueCount());
+    } else {
+      EXPECT_FALSE(RegKey::HasKey(client_state_medium_key_name));
+      // There is no such thing as a user ClientStateMedium key.
+      const CString user_client_state_medium_key_name = AppendRegKeyPath(
+          USER_KEY GOOPDATE_REG_RELATIVE_CLIENT_STATE_MEDIUM,
+          app_guid);
+      EXPECT_FALSE(RegKey::HasKey(user_client_state_medium_key_name));
+      return;
+    }
+  }
+
+  // Uses SetupGoogleUpdate to create the ClientStateMedium key with the
+  // appropriate permissions. Used to test that the permissions are inherited.
+  void CreateClientStateMediumKey() {
+    CommandLineArgs args;
+    SetupGoogleUpdate setup_google_update(true, &args);
+    EXPECT_SUCCEEDED(setup_google_update.CreateClientStateMedium());
+  }
+
+  CString hive_override_key_name_;
+  const GUID guid1_;
+};
+
+TEST_F(AppManagerTest, ConvertCommandLineToProductData_Succeeds) {
+  CommandLineAppArgs extra1;
+  extra1.app_guid = guid1_;
+  extra1.app_name = _T("foo");
+  extra1.needs_admin = false;
+  extra1.ap = _T("Test ap");
+  extra1.tt_token = _T("Test TT Token");
+  extra1.encoded_installer_data = _T("%20foobar");
+  extra1.install_data_index = _T("foobar");
+
+  CommandLineAppArgs extra2;
+  extra2.app_guid = StringToGuid(kGuid2);
+  extra2.app_name = _T("bar");
+  extra2.needs_admin = true;    // This gets ignored.
+  extra2.ap = _T("beta");
+  extra2.tt_token = _T("beta TT Token");
+
+  CommandLineArgs args;
+  args.is_interactive_set = true;  // Not used.
+  args.is_machine_set = true;  // Not used.
+  args.is_crash_handler_disabled = true;  // Not used.
+  args.is_eula_required_set = true;
+  args.is_eula_required_set = true;  // Not used.
+  args.webplugin_urldomain = _T("http://nothing.google.com");  // Not used.
+  args.webplugin_args = _T("blah");  // Not used.
+  args.install_source = _T("one_click");
+  args.code_red_metainstaller_path = _T("foo.exe");  // Not used.
+  args.legacy_manifest_path = _T("bar.exe");  // Not used.
+  args.crash_filename = _T("foo.dmp");  // Not used.
+  args.extra.installation_id =
+      StringToGuid(_T("{F723495F-8ACF-4746-8240-643741C797B5}"));
+  args.extra.brand_code = _T("GOOG");
+  args.extra.client_id = _T("someclient");
+  args.extra.referral_id = _T("referrer1");
+  args.extra.browser_type = BROWSER_IE;
+  args.extra.language = _T("abc");
+  args.extra.usage_stats_enable = TRISTATE_TRUE;
+  args.extra.apps.push_back(extra1);
+  args.extra.apps.push_back(extra2);
+
+  AppData expected_data1(guid1_, false);
+  PopulateExpectedAppData1(&expected_data1);
+  expected_data1.set_version(_T(""));  // Clear value.
+  expected_data1.set_previous_version(_T(""));  // Clear value.
+  expected_data1.set_did_run(AppData::ACTIVE_UNKNOWN);  // Clear value.
+  expected_data1.set_display_name(_T("foo"));
+  expected_data1.set_browser_type(BROWSER_IE);
+  expected_data1.set_install_source(_T("one_click"));
+  expected_data1.set_encoded_installer_data(_T("%20foobar"));
+  expected_data1.set_install_data_index(_T("foobar"));
+  expected_data1.set_usage_stats_enable(TRISTATE_TRUE);
+  expected_data1.set_referral_id(_T("referrer1"));
+  expected_data1.set_is_eula_accepted(false);
+
+  AppData expected_data2(StringToGuid(kGuid2), false);
+  PopulateExpectedAppData2(&expected_data2);
+  expected_data2.set_version(_T(""));  // Clear value.
+  expected_data2.set_previous_version(_T(""));  // Clear value.
+  expected_data2.set_did_run(AppData::ACTIVE_UNKNOWN);  // Clear value.
+  expected_data2.set_language(_T("abc"));
+  expected_data2.set_display_name(_T("bar"));
+  expected_data2.set_browser_type(BROWSER_IE);
+  expected_data2.set_install_source(_T("one_click"));
+  expected_data2.set_usage_stats_enable(TRISTATE_TRUE);
+  // Override unique expected data because the args apply to all apps.
+  expected_data2.set_iid(
+      StringToGuid(_T("{F723495F-8ACF-4746-8240-643741C797B5}")));
+  expected_data2.set_brand_code(_T("GOOG"));
+  expected_data2.set_client_id(_T("someclient"));
+  expected_data2.set_referral_id(_T("referrer1"));
+  expected_data2.set_is_eula_accepted(false);
+
+  ProductDataVector products;
+  AppManager app_manager(false);
+  app_manager.ConvertCommandLineToProductData(args, &products);
+
+  ASSERT_EQ(2, products.size());
+  ASSERT_EQ(0, products[0].num_components());
+  ASSERT_EQ(0, products[1].num_components());
+  ValidateExpectedValues(expected_data1, products[0].app_data());
+  ValidateExpectedValues(expected_data2, products[1].app_data());
+}
+
+TEST_F(AppManagerTest, WritePreInstallData_Machine) {
+  AppData app_data(guid1_, true);
+  ASSERT1(app_data.is_eula_accepted());
+  WritePreInstallDataTest(app_data);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathMachine,
+                                _T("oeminstall")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathMachine,
+                                _T("eulaaccepted")));
+}
+
+TEST_F(AppManagerTest, WritePreInstallData_Machine_IsOem) {
+  const DWORD now = Time64ToInt32(GetCurrent100NSTime());
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("OemInstallTime"),
+                                    now));
+  if (vista_util::IsVistaOrLater()) {
+    ASSERT_SUCCEEDED(RegKey::SetValue(
+        _T("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup\\State"),
+        _T("ImageState"),
+        _T("IMAGE_STATE_UNDEPLOYABLE")));
+  } else {
+    ASSERT_SUCCEEDED(RegKey::SetValue(_T("HKLM\\System\\Setup"),
+                                      _T("AuditInProgress"),
+                                      static_cast<DWORD>(1)));
+  }
+
+  AppData app_data(guid1_, true);
+  ASSERT1(app_data.is_eula_accepted());
+  WritePreInstallDataTest(app_data);
+
+  CString oeminstall;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathMachine,
+                                    _T("oeminstall"),
+                                    &oeminstall));
+  EXPECT_STREQ(_T("1"), oeminstall);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathMachine,
+                                _T("eulaaccepted")));
+}
+
+// Creates the ClientStateMedium key with the appropriate permissions then
+// verifies that the created app subkey inherits those.
+// The Update key must be created first to avoid applying ClientStateMedium's
+// permissions to all its parent keys.
+// This keys in this test need to inherit the HKLM privileges, so put the
+// override root in HKLM.
+TEST_F(AppManagerTest,
+       WritePreInstallData_Machine_CheckClientStateMediumPermissions) {
+  const TCHAR kRegistryHiveOverrideRootInHklm[] =
+      _T("HKLM\\Software\\Google\\Update\\UnitTest\\");
+  RestoreRegistryHives();
+  hive_override_key_name_ = kRegistryHiveOverrideRootInHklm;
+  RegKey::DeleteKey(hive_override_key_name_);
+  OverrideRegistryHives(hive_override_key_name_);
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(
+      ConfigManager::Instance()->machine_registry_update()));
+  CreateClientStateMediumKey();
+
+  AppData app_data(guid1_, true);
+  ASSERT1(app_data.is_eula_accepted());
+  WritePreInstallDataTest(app_data);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathMachine,
+                                _T("oeminstall")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathMachine,
+                                _T("eulaaccepted")));
+
+  const CString app_client_state_medium_key_name = AppendRegKeyPath(
+      _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\"),
+      kGuid1);
+  VerifyHklmKeyHasMediumIntegrity(app_client_state_medium_key_name);
+  VerifyHklmKeyHasDefaultIntegrity(
+      _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\"));
+}
+
+TEST_F(AppManagerTest,
+       WritePreInstallData_Machine_ClearClientStateMediumUsageStats) {
+  const CString client_state_key_name =
+      AppendRegKeyPath(MACHINE_REG_CLIENT_STATE_MEDIUM, kGuid1);
+  EXPECT_SUCCEEDED(RegKey::SetValue(client_state_key_name,
+                                    _T("usagestats"),
+                                    static_cast<DWORD>(1)));
+
+  AppData app_data(guid1_, true);
+  WritePreInstallDataTest(app_data);
+
+  EXPECT_FALSE(RegKey::HasValue(client_state_key_name, _T("usagestats")));
+}
+
+// Tests the EULA accepted case too.
+TEST_F(AppManagerTest, WritePreInstallData_User) {
+  AppData app_data(guid1_, false);
+  ASSERT1(app_data.is_eula_accepted());
+  WritePreInstallDataTest(app_data);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("oeminstall")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("eulaaccepted")));
+}
+
+TEST_F(AppManagerTest,
+       WritePreInstallData_User_EulaNotAcceptedAppNotRegistered) {
+  AppData app_data(guid1_, false);
+  app_data.set_is_eula_accepted(false);
+
+  WritePreInstallDataTest(app_data);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("oeminstall")));
+
+  DWORD eula_accepted = 99;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("eulaaccepted"),
+                                    &eula_accepted));
+  EXPECT_EQ(0, eula_accepted);
+}
+
+TEST_F(AppManagerTest,
+       WritePreInstallData_User_EulaNotAcceptedAppAlreadyInstalled) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientsKeyPathUser,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  AppData app_data(guid1_, false);
+  app_data.set_is_eula_accepted(false);
+
+  WritePreInstallDataTest(app_data);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("oeminstall")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("eulaaccepted")));
+}
+
+TEST_F(AppManagerTest,
+       WritePreInstallData_User_EulaAcceptedAppAlreadyInstalled) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientsKeyPathUser,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+
+  AppData app_data(guid1_, false);
+  app_data.set_is_eula_accepted(true);
+
+  WritePreInstallDataTest(app_data);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("oeminstall")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("eulaaccepted")));
+}
+
+TEST_F(AppManagerTest,
+       WritePreInstallData_User_EulaAcceptedAppAlreadyInstalledAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientsKeyPathUser,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  AppData app_data(guid1_, false);
+  app_data.set_is_eula_accepted(true);
+
+  WritePreInstallDataTest(app_data);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("oeminstall")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("eulaaccepted")));
+}
+
+TEST_F(AppManagerTest,
+       WritePreInstallData_User_EulaAcceptedAppAlreadyInstalledNotAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientsKeyPathUser,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  AppData app_data(guid1_, false);
+  app_data.set_is_eula_accepted(true);
+
+  WritePreInstallDataTest(app_data);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("oeminstall")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("eulaaccepted")));
+}
+
+TEST_F(AppManagerTest, ReadProductDataFromStore_MachineNoAppTest) {
+  ProductData product_data;
+  AppManager app_manager(true);
+  ASSERT_FAILED(app_manager.ReadProductDataFromStore(guid1_, &product_data));
+}
+
+TEST_F(AppManagerTest, ReadProductDataFromStore_UserAppTest) {
+  AppData expected_data(guid1_, false);
+  PopulateExpectedAppData1(&expected_data);
+  CreateAppRegistryState(expected_data);
+
+  AppManager app_manager(false);
+  ProductData product_data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));
+  ValidateExpectedValues(expected_data, product_data.app_data());
+}
+
+TEST_F(AppManagerTest, ReadProductDataFromStore_MachineAppTest) {
+  AppData expected_data(guid1_, true);
+  PopulateExpectedAppData1(&expected_data);
+  CreateAppRegistryState(expected_data);
+
+  AppManager app_manager(true);
+  ProductData product_data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));
+  ValidateExpectedValues(expected_data, product_data.app_data());
+}
+
+TEST_F(AppManagerTest, ReadProductDataFromStore_UserAppTest_EulaNotAccepted) {
+  AppData expected_data(guid1_, false);
+  PopulateExpectedAppData1(&expected_data);
+  CreateAppRegistryState(expected_data);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  expected_data.set_is_eula_accepted(false);
+
+  AppManager app_manager(false);
+  ProductData product_data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));
+  ValidateExpectedValues(expected_data, product_data.app_data());
+}
+
+TEST_F(AppManagerTest, ReadProductDataFromStore_UserAppTest_EulaAccepted) {
+  AppData expected_data(guid1_, false);
+  PopulateExpectedAppData1(&expected_data);
+  CreateAppRegistryState(expected_data);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  expected_data.set_is_eula_accepted(true);
+
+  AppManager app_manager(false);
+  ProductData product_data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));
+  ValidateExpectedValues(expected_data, product_data.app_data());
+}
+
+TEST_F(AppManagerTest,
+       ReadProductDataFromStore_MachineAppTest_EulaNotAccepted) {
+  AppData expected_data(guid1_, true);
+  PopulateExpectedAppData1(&expected_data);
+  CreateAppRegistryState(expected_data);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathMachine,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  expected_data.set_is_eula_accepted(false);
+
+  AppManager app_manager(true);
+  ProductData product_data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));
+  ValidateExpectedValues(expected_data, product_data.app_data());
+}
+
+TEST_F(AppManagerTest,
+       ReadProductDataFromStore_MachineAppTest_EulaAccepted) {
+  AppData expected_data(guid1_, true);
+  PopulateExpectedAppData1(&expected_data);
+  CreateAppRegistryState(expected_data);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathMachine,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+  expected_data.set_is_eula_accepted(true);
+
+  AppManager app_manager(true);
+  ProductData product_data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));
+  ValidateExpectedValues(expected_data, product_data.app_data());
+}
+
+TEST_F(AppManagerTest, ReadProductDataFromStore_TwoUserAppTest) {
+  AppData expected_data1(guid1_, false);
+  PopulateExpectedAppData1(&expected_data1);
+  CreateAppRegistryState(expected_data1);
+
+  AppData expected_data2(StringToGuid(kGuid2), false);
+  PopulateExpectedAppData1(&expected_data2);
+  CreateAppRegistryState(expected_data2);
+
+  AppManager app_manager(false);
+  ProductData data1;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data1));
+  ValidateExpectedValues(expected_data1, data1.app_data());
+
+  ProductData data2;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(StringToGuid(kGuid2),
+                                                        &data2));
+  ValidateExpectedValues(expected_data2, data2.app_data());
+}
+
+TEST_F(AppManagerTest, ReadProductDataFromStore_UserAppNoClientStateTest) {
+  AppData expected_data(guid1_, false);
+  PopulateExpectedAppData1(&expected_data);
+  CreateAppRegistryState(expected_data);
+
+  AppManager app_manager(false);
+  ProductData data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));
+  ValidateExpectedValues(expected_data, data.app_data());
+}
+
+TEST_F(AppManagerTest, ReadProductDataFromStore_UninstalledUserApp) {
+  AppData expected_data(guid1_, false);
+  PopulateExpectedUninstalledAppData(&expected_data);
+  CreateAppRegistryState(expected_data);
+
+  AppManager app_manager(false);
+  ProductData data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));
+  ValidateExpectedValues(expected_data, data.app_data());
+}
+
+TEST_F(AppManagerTest, ReadProductDataFromStore_UninstalledMachineApp) {
+  AppData expected_data(guid1_, true);
+  PopulateExpectedUninstalledAppData(&expected_data);
+  CreateAppRegistryState(expected_data);
+
+  AppManager app_manager(true);
+  ProductData data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));
+  ValidateExpectedValues(expected_data, data.app_data());
+}
+
+TEST_F(AppManagerTest,
+       ReadProductDataFromStore_UninstalledUserApp_EulaNotAccepted) {
+  AppData expected_data(guid1_, false);
+  PopulateExpectedUninstalledAppData(&expected_data);
+  expected_data.set_is_eula_accepted(false);
+  CreateAppRegistryState(expected_data);
+
+  AppManager app_manager(false);
+  ProductData data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));
+  ValidateExpectedValues(expected_data, data.app_data());
+}
+
+// Tests the case where Omaha has created the Client State key before running
+// the installer. Uses PopulateExpectedUninstalledAppData then clears pv before
+// writing the data to the registry. is_uninstalled_ is not set to false until
+// after CreateAppRegistryState to prevent Client key from being created.
+TEST_F(AppManagerTest,
+       ReadProductDataFromStore_UserClientStateExistsWithoutPvOrClientKey) {
+  AppData expected_data(guid1_, false);
+  PopulateExpectedUninstalledAppData(&expected_data);
+  expected_data.set_previous_version(_T(""));
+  CreateAppRegistryState(expected_data);
+
+  AppManager app_manager(false);
+  ProductData product_data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));
+
+  expected_data.set_is_uninstalled(false);
+  ValidateExpectedValues(expected_data, product_data.app_data());
+}
+
+TEST_F(AppManagerTest,
+       ReadProductDataFromStore_MachineClientStateExistsWithoutPvOrClientKey) {
+  AppData expected_data(guid1_, true);
+  PopulateExpectedUninstalledAppData(&expected_data);
+  expected_data.set_previous_version(_T(""));
+  CreateAppRegistryState(expected_data);
+
+  AppManager app_manager(true);
+  ProductData data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));
+  expected_data.set_is_uninstalled(false);
+  ValidateExpectedValues(expected_data, data.app_data());
+}
+
+// An empty pv value is the same as a populated one for uninstall checks.
+TEST_F(AppManagerTest,
+       ReadProductDataFromStore_UserClientStateExistsWithEmptyPvNoClientKey) {
+  AppData expected_data(guid1_, false);
+  PopulateExpectedUninstalledAppData(&expected_data);
+  expected_data.set_previous_version(_T(""));
+  CreateAppRegistryState(expected_data);
+
+  // Write the empty pv value.
+  CString client_state_key_name = AppendRegKeyPath(
+      ConfigManager::Instance()->registry_client_state(false),
+      kGuid1);
+  ASSERT_SUCCEEDED(RegKey::SetValue(client_state_key_name,
+                                    kRegValueProductVersion,
+                                    _T("")));
+
+  AppManager app_manager(false);
+  ProductData product_data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &product_data));
+
+  expected_data.set_is_uninstalled(true);
+  ValidateExpectedValues(expected_data, product_data.app_data());
+}
+
+TEST_F(AppManagerTest, InitializeApplicationState_UserTest) {
+  InitializeApplicationStateTest(false);
+}
+
+TEST_F(AppManagerTest, InitializeApplicationState_MachineTest) {
+  InitializeApplicationStateTest(true);
+}
+
+TEST_F(AppManagerTest, UpdateApplicationState_UserTest) {
+  UpdateApplicationStateTest(false, kGuid1);
+
+  ValidateClientStateMedium(false, kGuid1);
+}
+
+TEST_F(AppManagerTest, UpdateApplicationState_MachineTest) {
+  UpdateApplicationStateTest(true, kGuid1);
+
+  ValidateClientStateMedium(true, kGuid1);
+}
+
+// Should not create ClientStateMedium key.
+TEST_F(AppManagerTest, UpdateApplicationState_MachineTest_Omaha) {
+  UpdateApplicationStateTest(true, kGoogleUpdateAppId);
+
+  const CString client_state_medium_key_name = AppendRegKeyPath(
+    ConfigManager::Instance()->machine_registry_client_state_medium(),
+    kGoogleUpdateAppId);
+  EXPECT_FALSE(RegKey::HasKey(client_state_medium_key_name));
+}
+
+TEST_F(AppManagerTest, UpdateUpdateAvailableStats_NoExistingStats) {
+  const time64 before_time_in_100ns(GetCurrent100NSTime());
+
+  AppManager app_manager(false);
+  app_manager.UpdateUpdateAvailableStats(GUID_NULL, guid1_);
+
+  const time64 after_time_in_100ns(GetCurrent100NSTime());
+
+  DWORD update_available_count(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    &update_available_count));
+  EXPECT_EQ(1, update_available_count);
+
+  DWORD64 update_available_since_time(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    &update_available_since_time));
+  EXPECT_LE(before_time_in_100ns, update_available_since_time);
+  EXPECT_GE(after_time_in_100ns, update_available_since_time);
+  const DWORD64 time_since_first_update_available =
+      after_time_in_100ns - update_available_since_time;
+  EXPECT_GT(10 * kSecsTo100ns, time_since_first_update_available);
+}
+
+TEST_F(AppManagerTest, UpdateUpdateAvailableStats_WithExistingStats) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(123456)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(9876543210)));
+
+  AppManager app_manager(false);
+  app_manager.UpdateUpdateAvailableStats(GUID_NULL, guid1_);
+
+  DWORD update_available_count(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    &update_available_count));
+  EXPECT_EQ(123457, update_available_count);
+
+  DWORD64 update_available_since_time(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    &update_available_since_time));
+  EXPECT_EQ(9876543210, update_available_since_time);
+}
+
+TEST_F(AppManagerTest, ClearUpdateAvailableStats_KeyNotPresent) {
+  AppManager app_manager(false);
+  ClearUpdateAvailableStats(GUID_NULL, guid1_, &app_manager);
+}
+
+TEST_F(AppManagerTest, ClearUpdateAvailableStats_DataPresent) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(123456)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(9876543210)));
+
+  AppManager app_manager(false);
+  ClearUpdateAvailableStats(GUID_NULL, guid1_, &app_manager);
+
+  EXPECT_TRUE(RegKey::HasKey(kGuid1ClientStateKeyPathUser));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("UpdateAvailableCount")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("UpdateAvailableSince")));
+}
+
+TEST_F(AppManagerTest, ReadUpdateAvailableStats_DataNotPresent) {
+  RegKey::CreateKey(kGuid1ClientStateKeyPathUser);
+
+  DWORD update_responses(1);
+  DWORD64 time_since_first_response_ms(1);
+  AppManager app_manager(false);
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       guid1_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+}
+
+TEST_F(AppManagerTest, ReadUpdateAvailableStats_DataPresent) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(123456)));
+  const DWORD64 kUpdateAvailableSince =
+    GetCurrent100NSTime() - 2 * kMillisecsTo100ns;
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    kUpdateAvailableSince));
+
+  DWORD update_responses(0);
+  DWORD64 time_since_first_response_ms(0);
+  AppManager app_manager(false);
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       guid1_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+
+  EXPECT_EQ(123456, update_responses);
+  EXPECT_LE(2, time_since_first_response_ms);
+  EXPECT_GT(10 * kMsPerSec, time_since_first_response_ms);
+}
+
+// TODO(omaha): Add *UpdateAvailableStats tests with components when
+// component design is finalized and implemented
+
+TEST_F(AppManagerTest, RecordSuccessfulInstall_Install_Online) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(123456)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(9876543210)));
+
+  AppManager app_manager(false);
+  app_manager.RecordSuccessfulInstall(GUID_NULL, guid1_, false, false);
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  // Verify ClearUpdateAvailableStats() was called.
+  EXPECT_TRUE(RegKey::HasKey(kGuid1ClientStateKeyPathUser));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("UpdateAvailableCount")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("UpdateAvailableSince")));
+
+  // Verify update check value is written but update value is not.
+  const uint32 last_check_sec = GetDwordValue(kGuid1ClientStateKeyPathUser,
+                                              kRegValueLastSuccessfulCheckSec);
+  EXPECT_GE(now, last_check_sec);
+  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                kRegValueLastUpdateTimeSec));
+}
+
+TEST_F(AppManagerTest, RecordSuccessfulInstall_Install_Offline) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(123456)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(9876543210)));
+
+  AppManager app_manager(false);
+  app_manager.RecordSuccessfulInstall(GUID_NULL, guid1_, false, true);
+
+  // Verify ClearUpdateAvailableStats() was called.
+  EXPECT_TRUE(RegKey::HasKey(kGuid1ClientStateKeyPathUser));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("UpdateAvailableCount")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("UpdateAvailableSince")));
+
+  // Verify update values are not written.
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                kRegValueLastUpdateTimeSec));
+}
+
+TEST_F(AppManagerTest, RecordSuccessfulInstall_Update_ExistingTimes) {
+  const DWORD kExistingUpdateValues = 0x70123456;
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(123456)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(9876543210)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+
+  AppManager app_manager(false);
+  app_manager.RecordSuccessfulInstall(GUID_NULL, guid1_, true, false);
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  // Verify ClearUpdateAvailableStats() was called.
+  EXPECT_TRUE(RegKey::HasKey(kGuid1ClientStateKeyPathUser));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("UpdateAvailableCount")));
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                _T("UpdateAvailableSince")));
+
+  // Verify update values updated.
+  const uint32 last_check_sec = GetDwordValue(kGuid1ClientStateKeyPathUser,
+                                              kRegValueLastSuccessfulCheckSec);
+  EXPECT_NE(kExistingUpdateValues, last_check_sec);
+  EXPECT_GE(now, last_check_sec);
+  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);
+
+  const uint32 last_update_sec =
+      GetDwordValue(kGuid1ClientStateKeyPathUser, kRegValueLastUpdateTimeSec);
+  EXPECT_NE(kExistingUpdateValues, last_update_sec);
+  EXPECT_GE(now, last_update_sec);
+  EXPECT_GE(static_cast<uint32>(200), now - last_update_sec);
+}
+
+TEST_F(AppManagerTest, RecordSuccessfulInstall_Update_StateKeyDoesNotExist) {
+  AppManager app_manager(false);
+  app_manager.RecordSuccessfulInstall(GUID_NULL, guid1_, true, false);
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  // Verify update values updated.
+  const uint32 last_check_sec = GetDwordValue(kGuid1ClientStateKeyPathUser,
+                                              kRegValueLastSuccessfulCheckSec);
+  EXPECT_GE(now, last_check_sec);
+  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);
+
+  const uint32 last_update_sec =
+      GetDwordValue(kGuid1ClientStateKeyPathUser, kRegValueLastUpdateTimeSec);
+  EXPECT_GE(now, last_update_sec);
+  EXPECT_GE(static_cast<uint32>(200), now - last_update_sec);
+}
+
+TEST_F(AppManagerTest, RecordSuccessfulUpdateCheck_ExistingTime) {
+  const DWORD kExistingUpdateValue = 0x12345678;
+  EXPECT_SUCCEEDED(RegKey::SetValue(kGuid1ClientStateKeyPathUser,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValue));
+
+  AppManager app_manager(false);
+  app_manager.RecordSuccessfulUpdateCheck(GUID_NULL, guid1_);
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  const uint32 last_check_sec = GetDwordValue(kGuid1ClientStateKeyPathUser,
+                                              kRegValueLastSuccessfulCheckSec);
+  EXPECT_NE(kExistingUpdateValue, last_check_sec);
+  EXPECT_GE(now, last_check_sec);
+  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                kRegValueLastUpdateTimeSec));
+}
+
+TEST_F(AppManagerTest, RecordSuccessfulUpdateCheck_StateKeyDoesNotExist) {
+  AppManager app_manager(false);
+  app_manager.RecordSuccessfulUpdateCheck(GUID_NULL, guid1_);
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  const uint32 last_check_sec = GetDwordValue(kGuid1ClientStateKeyPathUser,
+                                              kRegValueLastSuccessfulCheckSec);
+  EXPECT_GE(now, last_check_sec);
+  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);
+
+  EXPECT_FALSE(RegKey::HasValue(kGuid1ClientStateKeyPathUser,
+                                kRegValueLastUpdateTimeSec));
+}
+
+TEST_F(AppManagerTest, RemoveClientState_Uninstalled) {
+  AppData expected_data(guid1_, true);
+  PopulateExpectedUninstalledAppData(&expected_data);
+  CreateAppRegistryState(expected_data);
+
+  AppManager app_manager(true);
+  ProductData data;
+  ASSERT_SUCCEEDED(app_manager.ReadProductDataFromStore(guid1_, &data));
+  ASSERT_SUCCEEDED(app_manager.RemoveClientState(data.app_data()));
+  ASSERT_FALSE(IsClientStateKeyPresent(expected_data));
+}
+
+class AppManagerTest2 : public testing::Test {
+ protected:
+  AppManagerTest2()
+      : hive_override_key_name_(kRegistryHiveOverrideRoot) {}
+
+  virtual void SetUp() {
+    RegKey::DeleteKey(hive_override_key_name_);
+    OverrideRegistryHives(hive_override_key_name_);
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    RegKey::DeleteKey(hive_override_key_name_);
+  }
+
+  CString hive_override_key_name_;
+};
+
+// Create 2 registered app and 1 unregistered app and populates the parameters.
+// Each is written to the registry.
+// Also creates partial Clients and ClientState keys and creates an a registered
+// and unregistered app in the opposite registry hive.
+void PopulateDataAndRegistryForRegisteredAndUnRegisteredApplicationsTests(
+    bool is_machine,
+    AppData* expected_data1,
+    AppData* expected_data2,
+    AppData* expected_data3) {
+
+  expected_data1->set_app_guid(StringToGuid(kGuid1));
+  expected_data1->set_is_machine_app(is_machine);
+  AppManagerTest::PopulateExpectedAppData1(expected_data1);
+  AppManagerTest::CreateAppRegistryState(*expected_data1);
+
+  expected_data2->set_app_guid(StringToGuid(kGuid2));
+  expected_data2->set_is_machine_app(is_machine);
+  AppManagerTest::PopulateExpectedAppData2(expected_data2);
+  AppManagerTest::CreateAppRegistryState(*expected_data2);
+
+  expected_data3->set_app_guid(StringToGuid(kGuid3));
+  expected_data3->set_is_machine_app(is_machine);
+  AppManagerTest::PopulateExpectedUninstalledAppData(expected_data3);
+  AppManagerTest::CreateAppRegistryState(*expected_data3);
+
+  // Add incomplete Clients and ClientState entries.
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(
+      AppendRegKeyPath(is_machine ? MACHINE_REG_CLIENTS : USER_REG_CLIENTS,
+                       kGuid4),
+      _T("name"),
+      _T("foo")));
+
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(
+      AppendRegKeyPath(is_machine ? MACHINE_REG_CLIENT_STATE :
+                                    USER_REG_CLIENT_STATE,
+                       kGuid5),
+      kRegValueDidRun,
+      _T("1")));
+
+  // Add registered and unregistered app to the opposite registry hive.
+  AppData opposite_hive_data1(StringToGuid(kGuid6), !is_machine);
+  AppManagerTest::PopulateExpectedAppData2(&opposite_hive_data1);
+  AppManagerTest::CreateAppRegistryState(opposite_hive_data1);
+
+  AppData opposite_hive_data2(StringToGuid(kGuid7), !is_machine);
+  AppManagerTest::PopulateExpectedUninstalledAppData(&opposite_hive_data2);
+  AppManagerTest::CreateAppRegistryState(opposite_hive_data2);
+}
+
+TEST_F(AppManagerTest2, GetRegisteredApplications_machine) {
+  AppData expected_data1, expected_data2, expected_data3;
+  PopulateDataAndRegistryForRegisteredAndUnRegisteredApplicationsTests(
+      true,
+      &expected_data1,
+      &expected_data2,
+      &expected_data3);
+
+  AppManager app_manager(true);
+
+  ProductDataVector products;
+  ASSERT_HRESULT_SUCCEEDED(app_manager.GetRegisteredProducts(&products));
+  ASSERT_EQ(2, products.size());
+
+  ASSERT_TRUE(::IsEqualGUID(products[0].app_data().app_guid(),
+              StringToGuid(kGuid1)));
+  ValidateExpectedValues(expected_data1, products[0].app_data());
+
+  ASSERT_TRUE(::IsEqualGUID(products[1].app_data().app_guid(),
+              StringToGuid(kGuid2)));
+  ValidateExpectedValues(expected_data2, products[1].app_data());
+}
+
+TEST_F(AppManagerTest2, GetRegisteredApplications_user) {
+  AppData expected_data1, expected_data2, expected_data3;
+  PopulateDataAndRegistryForRegisteredAndUnRegisteredApplicationsTests(
+      false,
+      &expected_data1,
+      &expected_data2,
+      &expected_data3);
+
+  AppManager app_manager(false);
+
+
+  ProductDataVector products;
+  ASSERT_HRESULT_SUCCEEDED(app_manager.GetRegisteredProducts(&products));
+  ASSERT_EQ(2, products.size());
+
+  ASSERT_TRUE(::IsEqualGUID(products[0].app_data().app_guid(),
+              StringToGuid(kGuid1)));
+  ValidateExpectedValues(expected_data1, products[0].app_data());
+
+  ASSERT_TRUE(::IsEqualGUID(products[1].app_data().app_guid(),
+              StringToGuid(kGuid2)));
+  ValidateExpectedValues(expected_data2, products[1].app_data());
+}
+
+TEST_F(AppManagerTest2, GetUnRegisteredApplications_machine) {
+  AppData expected_data1, expected_data2, expected_data3;
+  PopulateDataAndRegistryForRegisteredAndUnRegisteredApplicationsTests(
+      true,
+      &expected_data1,
+      &expected_data2,
+      &expected_data3);
+
+  AppManager app_manager(true);
+
+  ProductDataVector unreg_products;
+  ASSERT_HRESULT_SUCCEEDED(
+      app_manager.GetUnRegisteredProducts(&unreg_products));
+  ASSERT_EQ(1, unreg_products.size());
+
+  ValidateExpectedValues(expected_data3, unreg_products[0].app_data());
+}
+
+TEST_F(AppManagerTest2, GetUnRegisteredApplications_user) {
+  AppData expected_data1, expected_data2, expected_data3;
+  PopulateDataAndRegistryForRegisteredAndUnRegisteredApplicationsTests(
+      false,
+      &expected_data1,
+      &expected_data2,
+      &expected_data3);
+  AppManager app_manager(false);
+
+  ProductDataVector unreg_products;
+  ASSERT_HRESULT_SUCCEEDED(
+      app_manager.GetUnRegisteredProducts(&unreg_products));
+  ASSERT_EQ(1, unreg_products.size());
+
+  ValidateExpectedValues(expected_data3, unreg_products[0].app_data());
+}
+
+TEST_F(AppManagerTest2, UpdateLastChecked) {
+  AppManager app_manager(false);
+
+  EXPECT_SUCCEEDED(app_manager.UpdateLastChecked());
+  EXPECT_FALSE(app_manager.ShouldCheckForUpdates());
+
+  ConfigManager::Instance()->SetLastCheckedTime(false, 0);
+  EXPECT_TRUE(app_manager.ShouldCheckForUpdates());
+}
+
+TEST_F(AppManagerTest, ShouldCheckForUpdates_NoLastCheckedPresent) {
+  AppManager app_manager(false);
+  EXPECT_TRUE(app_manager.ShouldCheckForUpdates());
+}
+
+TEST_F(AppManagerTest, ShouldCheckForUpdates_LastCheckedPresent) {
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+  AppManager app_manager(false);
+
+  ConfigManager::Instance()->SetLastCheckedTime(false, now - 10);
+  EXPECT_FALSE(app_manager.ShouldCheckForUpdates());
+
+  ConfigManager::Instance()->SetLastCheckedTime(false,
+                                                now - kLastCheckPeriodSec - 1);
+  EXPECT_TRUE(app_manager.ShouldCheckForUpdates());
+}
+
+TEST_F(AppManagerTest, ShouldCheckForUpdates_LastCheckedInFuture) {
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+  AppManager app_manager(false);
+
+  // The absolute difference is within the check period.
+  ConfigManager::Instance()->SetLastCheckedTime(false, now + 600);
+  EXPECT_FALSE(app_manager.ShouldCheckForUpdates());
+
+  // The absolute difference is greater than the check period.
+  ConfigManager::Instance()->SetLastCheckedTime(false,
+                                                now + kLastCheckPeriodSec + 1);
+  EXPECT_TRUE(app_manager.ShouldCheckForUpdates());
+}
+
+TEST_F(AppManagerTest, ShouldCheckForUpdates_PeriodZero) {
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,
+                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                       static_cast<DWORD>(0)));
+
+  AppManager app_manager(false);
+  EXPECT_FALSE(app_manager.ShouldCheckForUpdates());
+}
+
+TEST_F(AppManagerTest, ShouldCheckForUpdates_PeriodOverride) {
+  const DWORD kOverrideMinutes = 10;
+  const DWORD kOverrideSeconds = kOverrideMinutes * 60;
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+  AppManager app_manager(false);
+
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(kRegKeyGoopdateGroupPolicy,
+                       kRegValueAutoUpdateCheckPeriodOverrideMinutes,
+                       kOverrideMinutes));
+
+  ConfigManager::Instance()->SetLastCheckedTime(false, now - 10);
+  EXPECT_FALSE(app_manager.ShouldCheckForUpdates());
+
+  ConfigManager::Instance()->SetLastCheckedTime(false,
+                                                now - kOverrideSeconds - 1);
+  EXPECT_TRUE(app_manager.ShouldCheckForUpdates());
+}
+
+}  // namespace omaha
diff --git a/worker/application_usage_data.cc b/worker/application_usage_data.cc
index cac3cea..78dcbce 100644
--- a/worker/application_usage_data.cc
+++ b/worker/application_usage_data.cc
@@ -1,288 +1,288 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/worker/application_usage_data.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-

-namespace omaha {

-

-ApplicationUsageData::ApplicationUsageData(bool is_machine,

-                                           bool check_low_integrity)

-    : exists_(false),

-      did_run_(false),

-      is_machine_(is_machine),

-      is_pre_update_check_(true),

-      check_low_integrity_(check_low_integrity) {

-}

-

-ApplicationUsageData::~ApplicationUsageData() {

-}

-

-HRESULT ApplicationUsageData::ReadDidRun(const CString& app_guid) {

-  CORE_LOG(L4, (_T("[ApplicationUsageData::ReadDidRun][%s]"), app_guid));

-  is_pre_update_check_ = true;

-  return ProcessDidRun(app_guid);

-}

-

-HRESULT ApplicationUsageData::ResetDidRun(const CString& app_guid) {

-  CORE_LOG(L4, (_T("[ApplicationUsageData::ResetDidRun][%s]"), app_guid));

-  is_pre_update_check_ = false;

-  return ProcessDidRun(app_guid);

-}

-

-HRESULT ApplicationUsageData::ProcessDidRun(const CString& app_guid) {

-  CORE_LOG(L4, (_T("[ApplicationUsageData::ProcessDidRun][%s]"), app_guid));

-  return is_machine_ ? ProcessMachineDidRun(app_guid) :

-                       ProcessUserDidRun(app_guid);

-}

-

-HRESULT ApplicationUsageData::ProcessMachineDidRun(const CString& app_guid) {

-  ASSERT1(is_machine_);

-

-  // Logic is as follows:

-  // for each user under HKU\<sid>

-  //   pre/post process HKU\<sid>

-  //   if vista

-  //     pre/post process HKU\<lowintegrity IE>\<sid>

-  // pre/post process HKLM

-  RegKey users_key;

-  HRESULT hr = users_key.Open(USERS_KEY, KEY_READ);

-  if (SUCCEEDED(hr)) {

-    uint32 num_users = users_key.GetSubkeyCount();

-    for (uint32 i = 0; i < num_users; ++i) {

-      CString sub_key_name;

-      hr = users_key.GetSubkeyNameAt(i, &sub_key_name);

-      if (FAILED(hr)) {

-        CORE_LOG(LEVEL_WARNING, (_T("[Key enum failed.][0x%08x][%d][%s]"),

-                                 hr, i, USERS_KEY));

-        continue;

-      }

-

-      CString temp_key = AppendRegKeyPath(USERS_KEY,

-                                          sub_key_name,

-                                          GOOPDATE_REG_RELATIVE_CLIENT_STATE);

-      CString user_state_key_name = AppendRegKeyPath(temp_key, app_guid);

-      hr = ProcessKey(user_state_key_name);

-      if (FAILED(hr)) {

-        CORE_LOG(L4, (_T("[ProcessKey failed][%s][0x%08x]"), app_guid, hr));

-      }

-

-      if (check_low_integrity_) {

-        // If we are running on vista we need to also look at the low

-        // integrity IE key where IE can write to. Note that we cannot

-        // use the IEGetWriteableHKCU function since this function assumes

-        // that we are running with the user's credentials.

-        CString temp_key = AppendRegKeyPath(USERS_KEY,

-                                            sub_key_name,

-                                            USER_REG_VISTA_LOW_INTEGRITY_HKCU);

-        CString li_hkcu_name = AppendRegKeyPath(

-                                   AppendRegKeyPath(

-                                       temp_key,

-                                       sub_key_name,

-                                       GOOPDATE_REG_RELATIVE_CLIENT_STATE),

-                                   app_guid);

-        hr = ProcessKey(li_hkcu_name);

-        if (FAILED(hr)) {

-          CORE_LOG(L4, (_T("[ProcessKey failed][%s][0x%08x]"), app_guid, hr));

-        }

-      }

-    }  // End of for

-

-    // Now Process the machine did run value also.

-    CString machine_state_key_name =

-        goopdate_utils::GetAppClientStateKey(true, app_guid);

-    hr = ProcessBackWardCompatKey(machine_state_key_name);

-    if (FAILED(hr)) {

-      CORE_LOG(L4, (_T("[ProcessBackWardCompatKey failed][0x%08x][%s]"),

-                    hr, machine_state_key_name));

-    }

-  } else {

-    CORE_LOG(LW, (_T("[Key open failed.][0x%08x][%s]"), hr, USERS_KEY));

-  }

-

-  return S_OK;

-}

-

-HRESULT ApplicationUsageData::ProcessUserDidRun(const CString& app_guid) {

-  ASSERT1(!is_machine_);

-

-  // Logic:

-  // Pre/Post process HKCU\

-  // if vista:

-  //    Pre/Post process HKCU\LowIntegrity

-  CString state_key_name = goopdate_utils::GetAppClientStateKey(false,

-                                                                app_guid);

-  HRESULT hr = ProcessKey(state_key_name);

-  if (FAILED(hr)) {

-      CORE_LOG(L4, (_T("[ProcessKey failed][0x%08x][%s]"),

-                    hr, state_key_name));

-  }

-

-  if (check_low_integrity_) {

-    // If we are running on vista we need to also look at the low

-    // integrity IE key where IE can write to. To avoid loading

-    // ieframe.dll into our process, we just use the registry

-    // key location directly instead of using IEGetWriteableHKCU

-    CString sid;

-    hr = user_info::GetCurrentUser(NULL, NULL, &sid);

-    if (FAILED(hr)) {

-      CORE_LOG(LEVEL_WARNING, (_T("[GetCurrentUser failed][0x%08x][%s]"),

-                               hr, app_guid));

-      return hr;

-    }

-

-    CString temp_name = AppendRegKeyPath(USER_KEY_NAME,

-                                         USER_REG_VISTA_LOW_INTEGRITY_HKCU,

-                                         sid);

-    CString lowintegrity_hkcu_name = AppendRegKeyPath(

-                                         temp_name,

-                                         GOOPDATE_REG_RELATIVE_CLIENT_STATE,

-                                         app_guid);

-    hr = ProcessKey(lowintegrity_hkcu_name);

-    if (FAILED(hr)) {

-      CORE_LOG(LEVEL_WARNING, (_T("[Could not ProcessKey][0x%08x][%s]"),

-                               hr, app_guid));

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT ApplicationUsageData::ProcessKey(const CString& key_name) {

-  return is_pre_update_check_ ? ProcessPreUpdateCheck(key_name) :

-                                ProcessPostUpdateCheck(key_name);

-}

-

-HRESULT ApplicationUsageData::ProcessPreUpdateCheck(const CString& key_name) {

-  // Read in the regkey value if it exists, and or it with the previous value.

-  RegKey key;

-  HRESULT hr = key.Open(key_name, KEY_READ);

-  if (FAILED(hr)) {

-    CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));

-    return hr;

-  }

-

-  // Now that we have the key, we should try and read the value of the

-  // did run key.

-  CString did_run_str(_T("0"));

-  hr = key.GetValue(kRegValueDidRun, &did_run_str);

-  if (FAILED(hr)) {

-    CORE_LOG(L3, (_T("[RegKey::GetValue failed][0x%08x][%s][%s]"),

-                  hr, key_name, kRegValueDidRun));

-    return hr;

-  }

-

-  if (did_run_str == _T("1")) {

-    did_run_ |= true;

-  }

-  exists_ |= true;

-

-  return hr;

-}

-

-HRESULT ApplicationUsageData::ProcessBackWardCompatKey(

-    const CString& key_name) {

-  // This method exists to support the installers that have not been

-  // updated to write to the HKCU key. Remove when we have all the installers

-  // correcly updated.

-  if (is_pre_update_check_) {

-    // Read in the regkey value if it exists, and or it with the previous value.

-    RegKey key;

-    HRESULT hr = key.Open(key_name, KEY_READ);

-    if (FAILED(hr)) {

-      CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));

-      return hr;

-    }

-

-    // Now that we have the key, we should try and read the value of the

-    // did run key.

-    CString did_run_str(_T("0"));

-    hr = key.GetValue(kRegValueDidRun, &did_run_str);

-    if (FAILED(hr)) {

-      CORE_LOG(L3, (_T("[RegKey::GetValue failed][0x%08x][%s][%s]"),

-                    hr, key_name, kRegValueDidRun));

-      return hr;

-    }

-

-    if (did_run_str == _T("1")) {

-      did_run_ |= true;

-    }

-    exists_ |= true;

-

-    return hr;

-  } else {

-    RegKey key;

-    HRESULT hr = key.Open(key_name);

-    if (FAILED(hr)) {

-      CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));

-      return hr;

-    }

-

-    // If the value exists, then it means that the installer has been updated,

-    // and we delete the machine value.

-    if (exists_) {

-      hr = RegKey::DeleteValue(key_name, kRegValueDidRun);

-      if (FAILED(hr)) {

-        CORE_LOG(LEVEL_WARNING, (_T("[RegKey::DeleteValue failed][0x%08x][%s]"),

-                                 hr, key_name));

-        return hr;

-      }

-    } else {

-      // Since the value does not exist else where, we reset the value in the

-      // HKLM key to zero.

-      exists_ |= true;

-      CString did_run_str(_T("0"));

-      if (SUCCEEDED(key.GetValue(kRegValueDidRun, &did_run_str))) {

-        hr = key.SetValue(kRegValueDidRun, _T("0"));

-        if (FAILED(hr)) {

-          CORE_LOG(LEVEL_WARNING, (_T("[RegKey::SetValue failed][0x%08x][%s]"),

-                                   hr, key_name));

-          return hr;

-        }

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT ApplicationUsageData::ProcessPostUpdateCheck(const CString& key_name) {

-  RegKey key;

-  HRESULT hr = key.Open(key_name);

-  if (FAILED(hr)) {

-    CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));

-    return hr;

-  }

-

-  CString did_run_str(_T("0"));

-  if (SUCCEEDED(key.GetValue(kRegValueDidRun, &did_run_str))) {

-    exists_ |= true;

-    hr = key.SetValue(kRegValueDidRun, _T("0"));

-    if (FAILED(hr)) {

-      CORE_LOG(LEVEL_WARNING, (_T("[RegKey::SetValue failed][0x%08x][%s]"),

-                               hr, key_name));

-      return hr;

-    }

-  }

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/worker/application_usage_data.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+
+namespace omaha {
+
+ApplicationUsageData::ApplicationUsageData(bool is_machine,
+                                           bool check_low_integrity)
+    : exists_(false),
+      did_run_(false),
+      is_machine_(is_machine),
+      is_pre_update_check_(true),
+      check_low_integrity_(check_low_integrity) {
+}
+
+ApplicationUsageData::~ApplicationUsageData() {
+}
+
+HRESULT ApplicationUsageData::ReadDidRun(const CString& app_guid) {
+  CORE_LOG(L4, (_T("[ApplicationUsageData::ReadDidRun][%s]"), app_guid));
+  is_pre_update_check_ = true;
+  return ProcessDidRun(app_guid);
+}
+
+HRESULT ApplicationUsageData::ResetDidRun(const CString& app_guid) {
+  CORE_LOG(L4, (_T("[ApplicationUsageData::ResetDidRun][%s]"), app_guid));
+  is_pre_update_check_ = false;
+  return ProcessDidRun(app_guid);
+}
+
+HRESULT ApplicationUsageData::ProcessDidRun(const CString& app_guid) {
+  CORE_LOG(L4, (_T("[ApplicationUsageData::ProcessDidRun][%s]"), app_guid));
+  return is_machine_ ? ProcessMachineDidRun(app_guid) :
+                       ProcessUserDidRun(app_guid);
+}
+
+HRESULT ApplicationUsageData::ProcessMachineDidRun(const CString& app_guid) {
+  ASSERT1(is_machine_);
+
+  // Logic is as follows:
+  // for each user under HKU\<sid>
+  //   pre/post process HKU\<sid>
+  //   if vista
+  //     pre/post process HKU\<lowintegrity IE>\<sid>
+  // pre/post process HKLM
+  RegKey users_key;
+  HRESULT hr = users_key.Open(USERS_KEY, KEY_READ);
+  if (SUCCEEDED(hr)) {
+    uint32 num_users = users_key.GetSubkeyCount();
+    for (uint32 i = 0; i < num_users; ++i) {
+      CString sub_key_name;
+      hr = users_key.GetSubkeyNameAt(i, &sub_key_name);
+      if (FAILED(hr)) {
+        CORE_LOG(LEVEL_WARNING, (_T("[Key enum failed.][0x%08x][%d][%s]"),
+                                 hr, i, USERS_KEY));
+        continue;
+      }
+
+      CString temp_key = AppendRegKeyPath(USERS_KEY,
+                                          sub_key_name,
+                                          GOOPDATE_REG_RELATIVE_CLIENT_STATE);
+      CString user_state_key_name = AppendRegKeyPath(temp_key, app_guid);
+      hr = ProcessKey(user_state_key_name);
+      if (FAILED(hr)) {
+        CORE_LOG(L4, (_T("[ProcessKey failed][%s][0x%08x]"), app_guid, hr));
+      }
+
+      if (check_low_integrity_) {
+        // If we are running on vista we need to also look at the low
+        // integrity IE key where IE can write to. Note that we cannot
+        // use the IEGetWriteableHKCU function since this function assumes
+        // that we are running with the user's credentials.
+        CString temp_key = AppendRegKeyPath(USERS_KEY,
+                                            sub_key_name,
+                                            USER_REG_VISTA_LOW_INTEGRITY_HKCU);
+        CString li_hkcu_name = AppendRegKeyPath(
+                                   AppendRegKeyPath(
+                                       temp_key,
+                                       sub_key_name,
+                                       GOOPDATE_REG_RELATIVE_CLIENT_STATE),
+                                   app_guid);
+        hr = ProcessKey(li_hkcu_name);
+        if (FAILED(hr)) {
+          CORE_LOG(L4, (_T("[ProcessKey failed][%s][0x%08x]"), app_guid, hr));
+        }
+      }
+    }  // End of for
+
+    // Now Process the machine did run value also.
+    CString machine_state_key_name =
+        goopdate_utils::GetAppClientStateKey(true, app_guid);
+    hr = ProcessBackWardCompatKey(machine_state_key_name);
+    if (FAILED(hr)) {
+      CORE_LOG(L4, (_T("[ProcessBackWardCompatKey failed][0x%08x][%s]"),
+                    hr, machine_state_key_name));
+    }
+  } else {
+    CORE_LOG(LW, (_T("[Key open failed.][0x%08x][%s]"), hr, USERS_KEY));
+  }
+
+  return S_OK;
+}
+
+HRESULT ApplicationUsageData::ProcessUserDidRun(const CString& app_guid) {
+  ASSERT1(!is_machine_);
+
+  // Logic:
+  // Pre/Post process HKCU\
+  // if vista:
+  //    Pre/Post process HKCU\LowIntegrity
+  CString state_key_name = goopdate_utils::GetAppClientStateKey(false,
+                                                                app_guid);
+  HRESULT hr = ProcessKey(state_key_name);
+  if (FAILED(hr)) {
+      CORE_LOG(L4, (_T("[ProcessKey failed][0x%08x][%s]"),
+                    hr, state_key_name));
+  }
+
+  if (check_low_integrity_) {
+    // If we are running on vista we need to also look at the low
+    // integrity IE key where IE can write to. To avoid loading
+    // ieframe.dll into our process, we just use the registry
+    // key location directly instead of using IEGetWriteableHKCU
+    CString sid;
+    hr = user_info::GetCurrentUser(NULL, NULL, &sid);
+    if (FAILED(hr)) {
+      CORE_LOG(LEVEL_WARNING, (_T("[GetCurrentUser failed][0x%08x][%s]"),
+                               hr, app_guid));
+      return hr;
+    }
+
+    CString temp_name = AppendRegKeyPath(USER_KEY_NAME,
+                                         USER_REG_VISTA_LOW_INTEGRITY_HKCU,
+                                         sid);
+    CString lowintegrity_hkcu_name = AppendRegKeyPath(
+                                         temp_name,
+                                         GOOPDATE_REG_RELATIVE_CLIENT_STATE,
+                                         app_guid);
+    hr = ProcessKey(lowintegrity_hkcu_name);
+    if (FAILED(hr)) {
+      CORE_LOG(LEVEL_WARNING, (_T("[Could not ProcessKey][0x%08x][%s]"),
+                               hr, app_guid));
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT ApplicationUsageData::ProcessKey(const CString& key_name) {
+  return is_pre_update_check_ ? ProcessPreUpdateCheck(key_name) :
+                                ProcessPostUpdateCheck(key_name);
+}
+
+HRESULT ApplicationUsageData::ProcessPreUpdateCheck(const CString& key_name) {
+  // Read in the regkey value if it exists, and or it with the previous value.
+  RegKey key;
+  HRESULT hr = key.Open(key_name, KEY_READ);
+  if (FAILED(hr)) {
+    CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));
+    return hr;
+  }
+
+  // Now that we have the key, we should try and read the value of the
+  // did run key.
+  CString did_run_str(_T("0"));
+  hr = key.GetValue(kRegValueDidRun, &did_run_str);
+  if (FAILED(hr)) {
+    CORE_LOG(L3, (_T("[RegKey::GetValue failed][0x%08x][%s][%s]"),
+                  hr, key_name, kRegValueDidRun));
+    return hr;
+  }
+
+  if (did_run_str == _T("1")) {
+    did_run_ |= true;
+  }
+  exists_ |= true;
+
+  return hr;
+}
+
+HRESULT ApplicationUsageData::ProcessBackWardCompatKey(
+    const CString& key_name) {
+  // This method exists to support the installers that have not been
+  // updated to write to the HKCU key. Remove when we have all the installers
+  // correcly updated.
+  if (is_pre_update_check_) {
+    // Read in the regkey value if it exists, and or it with the previous value.
+    RegKey key;
+    HRESULT hr = key.Open(key_name, KEY_READ);
+    if (FAILED(hr)) {
+      CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));
+      return hr;
+    }
+
+    // Now that we have the key, we should try and read the value of the
+    // did run key.
+    CString did_run_str(_T("0"));
+    hr = key.GetValue(kRegValueDidRun, &did_run_str);
+    if (FAILED(hr)) {
+      CORE_LOG(L3, (_T("[RegKey::GetValue failed][0x%08x][%s][%s]"),
+                    hr, key_name, kRegValueDidRun));
+      return hr;
+    }
+
+    if (did_run_str == _T("1")) {
+      did_run_ |= true;
+    }
+    exists_ |= true;
+
+    return hr;
+  } else {
+    RegKey key;
+    HRESULT hr = key.Open(key_name);
+    if (FAILED(hr)) {
+      CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));
+      return hr;
+    }
+
+    // If the value exists, then it means that the installer has been updated,
+    // and we delete the machine value.
+    if (exists_) {
+      hr = RegKey::DeleteValue(key_name, kRegValueDidRun);
+      if (FAILED(hr)) {
+        CORE_LOG(LEVEL_WARNING, (_T("[RegKey::DeleteValue failed][0x%08x][%s]"),
+                                 hr, key_name));
+        return hr;
+      }
+    } else {
+      // Since the value does not exist else where, we reset the value in the
+      // HKLM key to zero.
+      exists_ |= true;
+      CString did_run_str(_T("0"));
+      if (SUCCEEDED(key.GetValue(kRegValueDidRun, &did_run_str))) {
+        hr = key.SetValue(kRegValueDidRun, _T("0"));
+        if (FAILED(hr)) {
+          CORE_LOG(LEVEL_WARNING, (_T("[RegKey::SetValue failed][0x%08x][%s]"),
+                                   hr, key_name));
+          return hr;
+        }
+      }
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT ApplicationUsageData::ProcessPostUpdateCheck(const CString& key_name) {
+  RegKey key;
+  HRESULT hr = key.Open(key_name);
+  if (FAILED(hr)) {
+    CORE_LOG(L4, (_T("[failed to open key][%s][0x%08x]"), key_name, hr));
+    return hr;
+  }
+
+  CString did_run_str(_T("0"));
+  if (SUCCEEDED(key.GetValue(kRegValueDidRun, &did_run_str))) {
+    exists_ |= true;
+    hr = key.SetValue(kRegValueDidRun, _T("0"));
+    if (FAILED(hr)) {
+      CORE_LOG(LEVEL_WARNING, (_T("[RegKey::SetValue failed][0x%08x][%s]"),
+                               hr, key_name));
+      return hr;
+    }
+  }
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/worker/application_usage_data.h b/worker/application_usage_data.h
index 072a02d..d6f5219 100644
--- a/worker/application_usage_data.h
+++ b/worker/application_usage_data.h
@@ -1,83 +1,83 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// application_usage_data.h : Includes methods to deal with application

-// usage data. Currently it only deals with the did_run key.

-// The class provides methods to process the application data, before and

-// after the update check. In case of the did_run key we read the key

-// pre-update check and clear it post-update check.

-

-#ifndef OMAHA_GOOPDATE_APPLICATION_USAGE_DATA_H__

-#define OMAHA_GOOPDATE_APPLICATION_USAGE_DATA_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-

-namespace omaha {

-

-class ApplicationUsageData {

- public:

-  ApplicationUsageData(bool is_machine, bool check_low_integrity);

-  ~ApplicationUsageData();

-

-  // Reads the did run values for the application indentified by the app_guid.

-  HRESULT ReadDidRun(const CString& app_guid);

-

-  // Clears and performs the post processing after an update ckeck for the

-  // did run key.

-  HRESULT ResetDidRun(const CString& app_guid);

-

-  bool exists() const { return exists_; }

-  bool did_run() const { return did_run_; }

-

- private:

-  // Processes the did run value for the machine goopdate.

-  HRESULT ProcessMachineDidRun(const CString& app_guid);

-

-  // Processes the did run value for the user goopdate.

-  HRESULT ProcessUserDidRun(const CString& app_guid);

-

-  // Calls the pre or the post update check methods based on the

-  // is_pre_update_check_ value.

-  HRESULT ProcessDidRun(const CString& app_guid);

-

-  // Pre or post process the key that is passed in.

-  HRESULT ProcessKey(const CString& key_name);

-

-  // Reads the did run value and populates did_run_ and exists_.

-  HRESULT ProcessPreUpdateCheck(const CString& key_name);

-

-  // Clears the did_run value.

-  HRESULT ProcessPostUpdateCheck(const CString& key_name);

-

-  // Reads and updates the did_run key for the machine. This is a backward

-  // compatibility requirement, since applications have not been updated to

-  // write to HKCU yet.

-  HRESULT ProcessBackWardCompatKey(const CString& key_name);

-

-  bool exists_;                // Whether the did_run value exists.

-  bool did_run_;               // The value of did_run.

-  bool is_machine_;            // Whether this is a machine instance.

-  bool is_pre_update_check_;   // Internal state of pre or post update.

-  bool check_low_integrity_;   // Whether to check the low integrity registry

-                               // location.

-

-  DISALLOW_EVIL_CONSTRUCTORS(ApplicationUsageData);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_APPLICATION_USAGE_DATA_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// application_usage_data.h : Includes methods to deal with application
+// usage data. Currently it only deals with the did_run key.
+// The class provides methods to process the application data, before and
+// after the update check. In case of the did_run key we read the key
+// pre-update check and clear it post-update check.
+
+#ifndef OMAHA_GOOPDATE_APPLICATION_USAGE_DATA_H__
+#define OMAHA_GOOPDATE_APPLICATION_USAGE_DATA_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+
+namespace omaha {
+
+class ApplicationUsageData {
+ public:
+  ApplicationUsageData(bool is_machine, bool check_low_integrity);
+  ~ApplicationUsageData();
+
+  // Reads the did run values for the application indentified by the app_guid.
+  HRESULT ReadDidRun(const CString& app_guid);
+
+  // Clears and performs the post processing after an update ckeck for the
+  // did run key.
+  HRESULT ResetDidRun(const CString& app_guid);
+
+  bool exists() const { return exists_; }
+  bool did_run() const { return did_run_; }
+
+ private:
+  // Processes the did run value for the machine goopdate.
+  HRESULT ProcessMachineDidRun(const CString& app_guid);
+
+  // Processes the did run value for the user goopdate.
+  HRESULT ProcessUserDidRun(const CString& app_guid);
+
+  // Calls the pre or the post update check methods based on the
+  // is_pre_update_check_ value.
+  HRESULT ProcessDidRun(const CString& app_guid);
+
+  // Pre or post process the key that is passed in.
+  HRESULT ProcessKey(const CString& key_name);
+
+  // Reads the did run value and populates did_run_ and exists_.
+  HRESULT ProcessPreUpdateCheck(const CString& key_name);
+
+  // Clears the did_run value.
+  HRESULT ProcessPostUpdateCheck(const CString& key_name);
+
+  // Reads and updates the did_run key for the machine. This is a backward
+  // compatibility requirement, since applications have not been updated to
+  // write to HKCU yet.
+  HRESULT ProcessBackWardCompatKey(const CString& key_name);
+
+  bool exists_;                // Whether the did_run value exists.
+  bool did_run_;               // The value of did_run.
+  bool is_machine_;            // Whether this is a machine instance.
+  bool is_pre_update_check_;   // Internal state of pre or post update.
+  bool check_low_integrity_;   // Whether to check the low integrity registry
+                               // location.
+
+  DISALLOW_EVIL_CONSTRUCTORS(ApplicationUsageData);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_APPLICATION_USAGE_DATA_H__
diff --git a/worker/application_usage_data_unittest.cc b/worker/application_usage_data_unittest.cc
index 4f0fb89..26121bd 100644
--- a/worker/application_usage_data_unittest.cc
+++ b/worker/application_usage_data_unittest.cc
@@ -1,593 +1,593 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// ApplicationUsageData unit tests

-

-#include "omaha/common/reg_key.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/application_usage_data.h"

-

-namespace omaha {

-

-const TCHAR kAppDidRunValueName[] = _T("dr");

-const TCHAR kHKCUClientStateKeyName[] =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\")

-    _T("{6ACB7D4D-E5BA-48b0-85FE-A4051500A1BD}");

-const TCHAR kMachineClientState[] =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{6ACB7D4D-E5BA-48b0-85FE-A4051500A1BD}");

-const TCHAR kLowIntegrityIEHKCU[] =

-    _T("HKCU\\Software\\Microsoft\\Internet Explorer\\")

-    _T("InternetRegistry\\REGISTRY\\USER\\");

-const TCHAR kAppGuid[] = _T("{6ACB7D4D-E5BA-48b0-85FE-A4051500A1BD}");

-const TCHAR kRelativeClientState[] =

-    _T("Software\\Google\\Update\\ClientState\\")

-    _T("{6ACB7D4D-E5BA-48b0-85FE-A4051500A1BD}");

-

-// TODO(omaha): Expected and actual are reversed throughout this file. Fix.

-

-class ApplicationUsageDataTest : public testing::Test {

- protected:

-  virtual void SetUp() {

-    CString sid;

-    ASSERT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &sid));

-    low_integrity_key_name_ = AppendRegKeyPath(kLowIntegrityIEHKCU,

-                                               sid,

-                                               kRelativeClientState);

-    TearDown();

-  }

-

-  virtual void TearDown() {

-    RegKey::DeleteKey(kHKCUClientStateKeyName);

-    RegKey::DeleteKey(kMachineClientState);

-    RegKey::DeleteKey(low_integrity_key_name_);

-  }

-

-  void CreateMachineDidRunValue(bool value) {

-    if (!vista_util::IsUserAdmin()) {

-      return;

-    }

-    RegKey key;

-    ASSERT_SUCCEEDED(key.Create(kMachineClientState));

-    ASSERT_SUCCEEDED(key.SetValue(kAppDidRunValueName,

-                                  value == true ? _T("1") : _T("0")));

-  }

-

-  bool MachineDidRunValueExists() {

-    if (!vista_util::IsUserAdmin()) {

-      return true;

-    }

-    RegKey key;

-    if (FAILED(key.Open(kMachineClientState))) {

-      return false;

-    }

-

-    CString did_run_str(_T("0"));

-    if (FAILED(key.GetValue(kAppDidRunValueName, &did_run_str))) {

-      return false;

-    }

-

-    return true;

-  }

-

-  void DeleteMachineDidRunValue() {

-    if (!vista_util::IsUserAdmin()) {

-      return;

-    }

-    ASSERT_SUCCEEDED(RegKey::DeleteValue(kMachineClientState,

-                                         kAppDidRunValueName));

-  }

-

-  void CheckMachineDidRunValue(bool expected) {

-    if (!vista_util::IsUserAdmin()) {

-      return;

-    }

-    RegKey key;

-    ASSERT_SUCCEEDED(key.Open(kMachineClientState));

-

-    CString did_run_str(_T("0"));

-    ASSERT_SUCCEEDED(key.GetValue(kAppDidRunValueName, &did_run_str));

-    bool value = (did_run_str == _T("1")) ? true : false;

-

-    ASSERT_EQ(value, expected);

-  }

-

-  void CreateUserDidRunValue(bool value) {

-    RegKey key;

-    ASSERT_SUCCEEDED(key.Create(kHKCUClientStateKeyName));

-    ASSERT_SUCCEEDED(key.SetValue(kAppDidRunValueName,

-                                  (value == true) ? _T("1") : _T("0")));

-  }

-

-  void DeleteUserDidRunValue() {

-    ASSERT_SUCCEEDED(RegKey::DeleteValue(kHKCUClientStateKeyName,

-                                         kAppDidRunValueName));

-  }

-

-  void CheckUserDidRunValue(bool expected) {

-    RegKey key;

-    ASSERT_SUCCEEDED(key.Open(kHKCUClientStateKeyName));

-

-    CString did_run_str(_T("0"));

-    ASSERT_SUCCEEDED(key.GetValue(kAppDidRunValueName, &did_run_str));

-    bool value = (did_run_str == _T("1")) ? true : false;

-

-    ASSERT_EQ(value, expected);

-  }

-

-  bool UserDidRunValueExists() {

-    RegKey key;

-    if (FAILED(key.Open(kHKCUClientStateKeyName))) {

-      return false;

-    }

-

-    CString did_run_str(_T("0"));

-    if (FAILED(key.GetValue(kAppDidRunValueName, &did_run_str))) {

-      return false;

-    }

-

-    return true;

-  }

-

-  void CreateLowIntegrityUserDidRunValue(bool value) {

-    RegKey key;

-    ASSERT_SUCCEEDED(key.Create(low_integrity_key_name_));

-    ASSERT_SUCCEEDED(key.SetValue(kAppDidRunValueName,

-                                  (value == true) ? _T("1") : _T("0")));

-  }

-

-  void DeleteLowIntegrityUserDidRunValue() {

-    ASSERT_SUCCEEDED(RegKey::DeleteValue(low_integrity_key_name_,

-                                         kAppDidRunValueName));

-  }

-

-  void CheckLowIntegrityUserDidRunValue(bool expected) {

-    RegKey key;

-    ASSERT_SUCCEEDED(key.Open(low_integrity_key_name_));

-

-    CString did_run_str(_T("0"));

-    ASSERT_SUCCEEDED(key.GetValue(kAppDidRunValueName, &did_run_str));

-    bool value = (did_run_str == _T("1")) ? true : false;

-

-    ASSERT_EQ(value, expected);

-  }

-

-  bool LowIntegrityUserDidRunValueExists() {

-    RegKey key;

-    if (FAILED(key.Open(low_integrity_key_name_))) {

-      return false;

-    }

-

-    CString did_run_str(_T("0"));

-    if (FAILED(key.GetValue(kAppDidRunValueName, &did_run_str))) {

-      return false;

-    }

-

-    return true;

-  }

-

-  // This method takes in machine_did_run, user_did_run and

-  // low_user_did_run as int's. The idea is that the test tries to simulate

-  // all of these values as being not-present, and if present then true or

-  // false.

-  // -1 indicates non-presense, 1 indicates true, and 0 false. The caller

-  // then loops over all these values to capture testing all the permutations.

-  void TestUserAndMachineDidRun(int machine_did_run,

-                                int user_did_run,

-                                int low_user_did_run,

-                                bool expected_exists,

-                                bool expected_did_run,

-                                int is_vista) {

-    ApplicationUsageData data(true, is_vista ? true : false);

-

-    // Set up the registry for the test.

-    if (machine_did_run != -1) {

-      CreateMachineDidRunValue((machine_did_run == 1) ? true: false);

-    }

-

-    if (user_did_run != -1) {

-      CreateUserDidRunValue((user_did_run == 1) ? true: false);

-    }

-

-    if (low_user_did_run != -1) {

-      CreateLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);

-    }

-

-    // Perform the test.

-    ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));

-    ASSERT_EQ(data.exists(), expected_exists);

-    ASSERT_EQ(data.did_run(), expected_did_run);

-

-    // Check the return values.

-    if (machine_did_run == -1) {

-      ASSERT_FALSE(MachineDidRunValueExists());

-    } else {

-      CheckMachineDidRunValue((machine_did_run == 1) ? true: false);

-    }

-

-    if (user_did_run == -1) {

-      ASSERT_FALSE(UserDidRunValueExists());

-    } else {

-      CheckUserDidRunValue((user_did_run == 1) ? true: false);

-    }

-

-    if (low_user_did_run == -1) {

-      ASSERT_FALSE(LowIntegrityUserDidRunValueExists());

-    } else {

-      CheckLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);

-    }

-  }

-

-  void TestUserAndMachineDidRunPostProcess(int machine_did_run,

-                                           int user_did_run,

-                                           int low_user_did_run,

-                                           bool expected_exists,

-                                           int is_vista) {

-    ApplicationUsageData data(true, is_vista ? true : false);

-

-    // Setup the registry for the test.

-    if (machine_did_run != -1) {

-      CreateMachineDidRunValue((machine_did_run == 1) ? true: false);

-    }

-

-    if (user_did_run != -1) {

-      CreateUserDidRunValue((user_did_run == 1) ? true: false);

-    }

-

-    if (low_user_did_run != -1) {

-      CreateLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);

-    }

-

-    // Run the test.

-    ASSERT_SUCCEEDED(data.ResetDidRun(kAppGuid));

-    if (user_did_run == -1) {

-      ASSERT_FALSE(UserDidRunValueExists());

-    } else {

-      CheckUserDidRunValue(false);

-    }

-

-    if (low_user_did_run == -1) {

-      ASSERT_FALSE(LowIntegrityUserDidRunValueExists());

-    } else {

-      if (is_vista) {

-        CheckLowIntegrityUserDidRunValue(false);

-      } else {

-        CheckLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);

-      }

-    }

-

-    if (machine_did_run == -1) {

-      ASSERT_FALSE(MachineDidRunValueExists());

-    } else {

-      if (user_did_run != -1 ||  (is_vista && low_user_did_run != -1)) {

-        // This means that the user keys exists for this application

-        // we should have delete the machine key.

-        ASSERT_EQ(MachineDidRunValueExists(), false);

-      } else {

-        CheckMachineDidRunValue(false);

-      }

-    }

-

-    ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));

-    ASSERT_EQ(data.exists(), expected_exists);

-    ASSERT_EQ(data.did_run(), false);

-  }

-

-  void UserTestDidRunPreProcess(int user_did_run,

-                                int low_user_did_run,

-                                int is_vista,

-                                bool expected_exists,

-                                bool expected_did_run) {

-    ApplicationUsageData data(false, is_vista ? true : false);

-

-    // Set up the registry for the test.

-    CreateMachineDidRunValue(true);

-

-    if (user_did_run != -1) {

-      CreateUserDidRunValue((user_did_run == 1) ? true: false);

-    }

-

-    if (low_user_did_run != -1) {

-      CreateLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);

-    }

-

-    // Perform the test.

-    ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));

-    ASSERT_EQ(data.exists(), expected_exists);

-    ASSERT_EQ(data.did_run(), expected_did_run);

-

-    // The machine value should not have changed from what we set it to.

-    CheckMachineDidRunValue(true);

-    if (user_did_run == -1) {

-      // If we did not create the user value it should not exist.

-      ASSERT_FALSE(UserDidRunValueExists());

-    }

-

-    if (low_user_did_run == -1) {

-      // If we did not create the low integrity user value it should not exist.

-      ASSERT_FALSE(LowIntegrityUserDidRunValueExists());

-    }

-  }

-

-  void UserTestDidRunPostProcess(int user_did_run,

-                                 int low_user_did_run,

-                                 int is_vista) {

-    // Create a user ApplicationUsageData class.

-    ApplicationUsageData data(false, is_vista ? true : false);

-

-    // This should not affect the test.

-    CreateMachineDidRunValue(true);

-

-    if (user_did_run != -1) {

-      CreateUserDidRunValue((user_did_run == 1) ? true: false);

-    }

-

-    if (low_user_did_run != -1) {

-      CreateLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);

-    }

-

-    ASSERT_SUCCEEDED(data.ResetDidRun(kAppGuid));

-

-    // The machine did run shold never get affected.

-    CheckMachineDidRunValue(true);

-    if (user_did_run == -1) {

-      ASSERT_FALSE(UserDidRunValueExists());

-    } else {

-      // In all cases if the HKCU did run is set, it should get cleared.

-      CheckUserDidRunValue(false);

-    }

-

-    if (low_user_did_run == -1) {

-      ASSERT_FALSE(LowIntegrityUserDidRunValueExists());

-    } else {

-      // In case of vista, the low integrity user value should get reset.

-      CheckLowIntegrityUserDidRunValue(is_vista ? false :

-                                       (low_user_did_run == 1) ? true : false);

-    }

-  }

-

- private:

-  CString low_integrity_key_name_;

-};

-

-TEST_F(ApplicationUsageDataTest, ReadDidRunUser1) {

-  ApplicationUsageData data(true, false);

-

-  ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data.exists(), false);

-  ASSERT_EQ(data.did_run(), false);

-

-  // Test with false user value.

-  CreateUserDidRunValue(false);

-  ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data.exists(), true);

-  ASSERT_EQ(data.did_run(), false);

-}

-

-TEST_F(ApplicationUsageDataTest, ReadDidRunUser2) {

-  // Test with true user value.

-  ApplicationUsageData data1(true, false);

-  CreateUserDidRunValue(true);

-  ASSERT_SUCCEEDED(data1.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data1.exists(), true);

-  ASSERT_EQ(data1.did_run(), true);

-}

-

-TEST_F(ApplicationUsageDataTest, ReadDidRunUser3) {

-  // low integrity user = false, vista

-  ApplicationUsageData data2(true, true);

-  CreateLowIntegrityUserDidRunValue(false);

-  ASSERT_SUCCEEDED(data2.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data2.exists(), true);

-  ASSERT_EQ(data2.did_run(), false);

-}

-

-TEST_F(ApplicationUsageDataTest, ReadDidRunUser4) {

-  // low integrity user = true, vista

-  ApplicationUsageData data2(true, true);

-  CreateLowIntegrityUserDidRunValue(true);

-  ASSERT_SUCCEEDED(data2.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data2.exists(), true);

-  ASSERT_EQ(data2.did_run(), true);

-}

-

-TEST_F(ApplicationUsageDataTest, ReadDidRunUser5) {

-  // low integrity user = true, not vista

-  ApplicationUsageData data2(true, false);

-  CreateLowIntegrityUserDidRunValue(true);

-  ASSERT_SUCCEEDED(data2.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data2.exists(), false);

-  ASSERT_EQ(data2.did_run(), false);

-}

-

-TEST_F(ApplicationUsageDataTest, ReadDidRunMachine1) {

-  if (!vista_util::IsUserAdmin()) {

-    return;

-  }

-

-  ApplicationUsageData data(true, true);

-

-  // create machine application key and test

-  CreateMachineDidRunValue(false);

-  ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data.exists(), true);

-  ASSERT_EQ(data.did_run(), false);

-}

-

-TEST_F(ApplicationUsageDataTest, ReadDidRunMachine2) {

-  if (!vista_util::IsUserAdmin()) {

-    return;

-  }

-

-  ApplicationUsageData data1(true, true);

-  CreateMachineDidRunValue(true);

-  ASSERT_SUCCEEDED(data1.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data1.exists(), true);

-  ASSERT_EQ(data1.did_run(), true);

-}

-

-TEST_F(ApplicationUsageDataTest, ReadDidRunBoth1) {

-  if (!vista_util::IsUserAdmin()) {

-    return;

-  }

-

-  // We try all combinations of machine, user and low integrity user

-  // registry value for did run. -1 indicates the value does not exist

-  // 1 indicates true and 0 indicates false.

-  for (int vista = 0; vista < 2; ++vista) {

-    for (int machine = -1; machine < 2; ++machine) {

-      for (int user = -1; user < 2; ++user) {

-        for (int lowuser = -1; lowuser < 2; ++lowuser) {

-          bool expected_did_run = false;

-          bool expected_exists = false;

-

-          if (machine > -1 || user > -1 || (vista && lowuser > -1)) {

-            expected_exists = true;

-          }

-

-          if (machine > 0 || user > 0 || (vista && lowuser > 0)) {

-            expected_did_run = true;

-          }

-

-          TestUserAndMachineDidRun(machine, user, lowuser,

-                                   expected_exists,

-                                   expected_did_run,

-                                   vista);

-          TearDown();

-        }

-      }

-    }

-  }

-}

-

-TEST_F(ApplicationUsageDataTest, ResetDidRunUser1) {

-  ApplicationUsageData data(true, true);

-

-  // create user application key and test

-  CreateUserDidRunValue(false);

-  ASSERT_SUCCEEDED(data.ResetDidRun(kAppGuid));

-  CheckUserDidRunValue(false);

-

-  ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data.exists(), true);

-  ASSERT_EQ(data.did_run(), false);

-}

-

-TEST_F(ApplicationUsageDataTest, ResetDidRunUser2) {

-  ApplicationUsageData data1(true, true);

-  CreateUserDidRunValue(true);

-  ASSERT_SUCCEEDED(data1.ResetDidRun(kAppGuid));

-  CheckUserDidRunValue(false);

-

-  ASSERT_SUCCEEDED(data1.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data1.exists(), true);

-  ASSERT_EQ(data1.did_run(), false);

-}

-

-TEST_F(ApplicationUsageDataTest, ResetDidRunMachine1) {

-  if (!vista_util::IsUserAdmin()) {

-    return;

-  }

-

-  ApplicationUsageData data(true, true);

-  CreateMachineDidRunValue(false);

-  ASSERT_SUCCEEDED(data.ResetDidRun(kAppGuid));

-  CheckMachineDidRunValue(false);

-

-  ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data.exists(), true);

-  ASSERT_EQ(data.did_run(), false);

-}

-

-TEST_F(ApplicationUsageDataTest, ResetDidRunMachine2) {

-  if (!vista_util::IsUserAdmin()) {

-    return;

-  }

-

-  ApplicationUsageData data1(true, true);

-  CreateMachineDidRunValue(true);

-  ASSERT_SUCCEEDED(data1.ResetDidRun(kAppGuid));

-  CheckMachineDidRunValue(false);

-

-  ASSERT_SUCCEEDED(data1.ReadDidRun(kAppGuid));

-  ASSERT_EQ(data1.exists(), true);

-  ASSERT_EQ(data1.did_run(), false);

-}

-

-TEST_F(ApplicationUsageDataTest, ResetDidRunBoth) {

-  if (!vista_util::IsUserAdmin()) {

-    return;

-  }

-

-  // We try all combinations of machine, user and low integrity user

-  // registry value for did run. -1 indicates the value does not exist

-  // 1 indicates true and 0 indicates false.

-  for (int vista = 0; vista < 2; ++vista) {

-    for (int machine = -1; machine < 2; ++machine) {

-      for (int user = -1; user < 2; ++user) {

-        for (int lowuser = -1; lowuser < 2; ++lowuser) {

-          bool expected_exists = false;

-          if (machine > -1 || user > -1 || (vista && lowuser > -1)) {

-            expected_exists = true;

-          }

-

-          TestUserAndMachineDidRunPostProcess(machine, user, lowuser,

-                                              expected_exists,

-                                              vista);

-          TearDown();

-        }

-      }

-    }

-  }

-}

-

-TEST_F(ApplicationUsageDataTest, UserReadDidRunUser) {

-  for (int vista = 0; vista < 2; ++vista) {

-      for (int user = -1; user < 2; ++user) {

-        for (int lowuser = -1; lowuser < 2; ++lowuser) {

-          bool expected_exists = false;

-          bool expected_did_run = false;

-

-          if (user != -1 || (vista && lowuser != -1)) {

-            expected_exists = true;

-          }

-

-          if (user > 0 || (vista && lowuser > 0)) {

-            expected_did_run = true;

-          }

-

-          UserTestDidRunPreProcess(user, lowuser, vista, expected_exists,

-                                   expected_did_run);

-          TearDown();

-        }

-      }

-  }

-}

-

-TEST_F(ApplicationUsageDataTest, UserResetDidRunUser1) {

-  for (int vista = 0; vista < 2; ++vista) {

-    for (int user = -1; user < 2; ++user) {

-      for (int lowuser = -1; lowuser < 2; ++lowuser) {

-        UserTestDidRunPostProcess(user, lowuser, vista);

-        TearDown();

-      }

-    }

-  }

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// ApplicationUsageData unit tests
+
+#include "omaha/common/reg_key.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/application_usage_data.h"
+
+namespace omaha {
+
+const TCHAR kAppDidRunValueName[] = _T("dr");
+const TCHAR kHKCUClientStateKeyName[] =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\")
+    _T("{6ACB7D4D-E5BA-48b0-85FE-A4051500A1BD}");
+const TCHAR kMachineClientState[] =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{6ACB7D4D-E5BA-48b0-85FE-A4051500A1BD}");
+const TCHAR kLowIntegrityIEHKCU[] =
+    _T("HKCU\\Software\\Microsoft\\Internet Explorer\\")
+    _T("InternetRegistry\\REGISTRY\\USER\\");
+const TCHAR kAppGuid[] = _T("{6ACB7D4D-E5BA-48b0-85FE-A4051500A1BD}");
+const TCHAR kRelativeClientState[] =
+    _T("Software\\Google\\Update\\ClientState\\")
+    _T("{6ACB7D4D-E5BA-48b0-85FE-A4051500A1BD}");
+
+// TODO(omaha): Expected and actual are reversed throughout this file. Fix.
+
+class ApplicationUsageDataTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    CString sid;
+    ASSERT_SUCCEEDED(user_info::GetCurrentUser(NULL, NULL, &sid));
+    low_integrity_key_name_ = AppendRegKeyPath(kLowIntegrityIEHKCU,
+                                               sid,
+                                               kRelativeClientState);
+    TearDown();
+  }
+
+  virtual void TearDown() {
+    RegKey::DeleteKey(kHKCUClientStateKeyName);
+    RegKey::DeleteKey(kMachineClientState);
+    RegKey::DeleteKey(low_integrity_key_name_);
+  }
+
+  void CreateMachineDidRunValue(bool value) {
+    if (!vista_util::IsUserAdmin()) {
+      return;
+    }
+    RegKey key;
+    ASSERT_SUCCEEDED(key.Create(kMachineClientState));
+    ASSERT_SUCCEEDED(key.SetValue(kAppDidRunValueName,
+                                  value == true ? _T("1") : _T("0")));
+  }
+
+  bool MachineDidRunValueExists() {
+    if (!vista_util::IsUserAdmin()) {
+      return true;
+    }
+    RegKey key;
+    if (FAILED(key.Open(kMachineClientState))) {
+      return false;
+    }
+
+    CString did_run_str(_T("0"));
+    if (FAILED(key.GetValue(kAppDidRunValueName, &did_run_str))) {
+      return false;
+    }
+
+    return true;
+  }
+
+  void DeleteMachineDidRunValue() {
+    if (!vista_util::IsUserAdmin()) {
+      return;
+    }
+    ASSERT_SUCCEEDED(RegKey::DeleteValue(kMachineClientState,
+                                         kAppDidRunValueName));
+  }
+
+  void CheckMachineDidRunValue(bool expected) {
+    if (!vista_util::IsUserAdmin()) {
+      return;
+    }
+    RegKey key;
+    ASSERT_SUCCEEDED(key.Open(kMachineClientState));
+
+    CString did_run_str(_T("0"));
+    ASSERT_SUCCEEDED(key.GetValue(kAppDidRunValueName, &did_run_str));
+    bool value = (did_run_str == _T("1")) ? true : false;
+
+    ASSERT_EQ(value, expected);
+  }
+
+  void CreateUserDidRunValue(bool value) {
+    RegKey key;
+    ASSERT_SUCCEEDED(key.Create(kHKCUClientStateKeyName));
+    ASSERT_SUCCEEDED(key.SetValue(kAppDidRunValueName,
+                                  (value == true) ? _T("1") : _T("0")));
+  }
+
+  void DeleteUserDidRunValue() {
+    ASSERT_SUCCEEDED(RegKey::DeleteValue(kHKCUClientStateKeyName,
+                                         kAppDidRunValueName));
+  }
+
+  void CheckUserDidRunValue(bool expected) {
+    RegKey key;
+    ASSERT_SUCCEEDED(key.Open(kHKCUClientStateKeyName));
+
+    CString did_run_str(_T("0"));
+    ASSERT_SUCCEEDED(key.GetValue(kAppDidRunValueName, &did_run_str));
+    bool value = (did_run_str == _T("1")) ? true : false;
+
+    ASSERT_EQ(value, expected);
+  }
+
+  bool UserDidRunValueExists() {
+    RegKey key;
+    if (FAILED(key.Open(kHKCUClientStateKeyName))) {
+      return false;
+    }
+
+    CString did_run_str(_T("0"));
+    if (FAILED(key.GetValue(kAppDidRunValueName, &did_run_str))) {
+      return false;
+    }
+
+    return true;
+  }
+
+  void CreateLowIntegrityUserDidRunValue(bool value) {
+    RegKey key;
+    ASSERT_SUCCEEDED(key.Create(low_integrity_key_name_));
+    ASSERT_SUCCEEDED(key.SetValue(kAppDidRunValueName,
+                                  (value == true) ? _T("1") : _T("0")));
+  }
+
+  void DeleteLowIntegrityUserDidRunValue() {
+    ASSERT_SUCCEEDED(RegKey::DeleteValue(low_integrity_key_name_,
+                                         kAppDidRunValueName));
+  }
+
+  void CheckLowIntegrityUserDidRunValue(bool expected) {
+    RegKey key;
+    ASSERT_SUCCEEDED(key.Open(low_integrity_key_name_));
+
+    CString did_run_str(_T("0"));
+    ASSERT_SUCCEEDED(key.GetValue(kAppDidRunValueName, &did_run_str));
+    bool value = (did_run_str == _T("1")) ? true : false;
+
+    ASSERT_EQ(value, expected);
+  }
+
+  bool LowIntegrityUserDidRunValueExists() {
+    RegKey key;
+    if (FAILED(key.Open(low_integrity_key_name_))) {
+      return false;
+    }
+
+    CString did_run_str(_T("0"));
+    if (FAILED(key.GetValue(kAppDidRunValueName, &did_run_str))) {
+      return false;
+    }
+
+    return true;
+  }
+
+  // This method takes in machine_did_run, user_did_run and
+  // low_user_did_run as int's. The idea is that the test tries to simulate
+  // all of these values as being not-present, and if present then true or
+  // false.
+  // -1 indicates non-presense, 1 indicates true, and 0 false. The caller
+  // then loops over all these values to capture testing all the permutations.
+  void TestUserAndMachineDidRun(int machine_did_run,
+                                int user_did_run,
+                                int low_user_did_run,
+                                bool expected_exists,
+                                bool expected_did_run,
+                                int is_vista) {
+    ApplicationUsageData data(true, is_vista ? true : false);
+
+    // Set up the registry for the test.
+    if (machine_did_run != -1) {
+      CreateMachineDidRunValue((machine_did_run == 1) ? true: false);
+    }
+
+    if (user_did_run != -1) {
+      CreateUserDidRunValue((user_did_run == 1) ? true: false);
+    }
+
+    if (low_user_did_run != -1) {
+      CreateLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);
+    }
+
+    // Perform the test.
+    ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));
+    ASSERT_EQ(data.exists(), expected_exists);
+    ASSERT_EQ(data.did_run(), expected_did_run);
+
+    // Check the return values.
+    if (machine_did_run == -1) {
+      ASSERT_FALSE(MachineDidRunValueExists());
+    } else {
+      CheckMachineDidRunValue((machine_did_run == 1) ? true: false);
+    }
+
+    if (user_did_run == -1) {
+      ASSERT_FALSE(UserDidRunValueExists());
+    } else {
+      CheckUserDidRunValue((user_did_run == 1) ? true: false);
+    }
+
+    if (low_user_did_run == -1) {
+      ASSERT_FALSE(LowIntegrityUserDidRunValueExists());
+    } else {
+      CheckLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);
+    }
+  }
+
+  void TestUserAndMachineDidRunPostProcess(int machine_did_run,
+                                           int user_did_run,
+                                           int low_user_did_run,
+                                           bool expected_exists,
+                                           int is_vista) {
+    ApplicationUsageData data(true, is_vista ? true : false);
+
+    // Setup the registry for the test.
+    if (machine_did_run != -1) {
+      CreateMachineDidRunValue((machine_did_run == 1) ? true: false);
+    }
+
+    if (user_did_run != -1) {
+      CreateUserDidRunValue((user_did_run == 1) ? true: false);
+    }
+
+    if (low_user_did_run != -1) {
+      CreateLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);
+    }
+
+    // Run the test.
+    ASSERT_SUCCEEDED(data.ResetDidRun(kAppGuid));
+    if (user_did_run == -1) {
+      ASSERT_FALSE(UserDidRunValueExists());
+    } else {
+      CheckUserDidRunValue(false);
+    }
+
+    if (low_user_did_run == -1) {
+      ASSERT_FALSE(LowIntegrityUserDidRunValueExists());
+    } else {
+      if (is_vista) {
+        CheckLowIntegrityUserDidRunValue(false);
+      } else {
+        CheckLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);
+      }
+    }
+
+    if (machine_did_run == -1) {
+      ASSERT_FALSE(MachineDidRunValueExists());
+    } else {
+      if (user_did_run != -1 ||  (is_vista && low_user_did_run != -1)) {
+        // This means that the user keys exists for this application
+        // we should have delete the machine key.
+        ASSERT_EQ(MachineDidRunValueExists(), false);
+      } else {
+        CheckMachineDidRunValue(false);
+      }
+    }
+
+    ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));
+    ASSERT_EQ(data.exists(), expected_exists);
+    ASSERT_EQ(data.did_run(), false);
+  }
+
+  void UserTestDidRunPreProcess(int user_did_run,
+                                int low_user_did_run,
+                                int is_vista,
+                                bool expected_exists,
+                                bool expected_did_run) {
+    ApplicationUsageData data(false, is_vista ? true : false);
+
+    // Set up the registry for the test.
+    CreateMachineDidRunValue(true);
+
+    if (user_did_run != -1) {
+      CreateUserDidRunValue((user_did_run == 1) ? true: false);
+    }
+
+    if (low_user_did_run != -1) {
+      CreateLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);
+    }
+
+    // Perform the test.
+    ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));
+    ASSERT_EQ(data.exists(), expected_exists);
+    ASSERT_EQ(data.did_run(), expected_did_run);
+
+    // The machine value should not have changed from what we set it to.
+    CheckMachineDidRunValue(true);
+    if (user_did_run == -1) {
+      // If we did not create the user value it should not exist.
+      ASSERT_FALSE(UserDidRunValueExists());
+    }
+
+    if (low_user_did_run == -1) {
+      // If we did not create the low integrity user value it should not exist.
+      ASSERT_FALSE(LowIntegrityUserDidRunValueExists());
+    }
+  }
+
+  void UserTestDidRunPostProcess(int user_did_run,
+                                 int low_user_did_run,
+                                 int is_vista) {
+    // Create a user ApplicationUsageData class.
+    ApplicationUsageData data(false, is_vista ? true : false);
+
+    // This should not affect the test.
+    CreateMachineDidRunValue(true);
+
+    if (user_did_run != -1) {
+      CreateUserDidRunValue((user_did_run == 1) ? true: false);
+    }
+
+    if (low_user_did_run != -1) {
+      CreateLowIntegrityUserDidRunValue((low_user_did_run == 1) ? true: false);
+    }
+
+    ASSERT_SUCCEEDED(data.ResetDidRun(kAppGuid));
+
+    // The machine did run shold never get affected.
+    CheckMachineDidRunValue(true);
+    if (user_did_run == -1) {
+      ASSERT_FALSE(UserDidRunValueExists());
+    } else {
+      // In all cases if the HKCU did run is set, it should get cleared.
+      CheckUserDidRunValue(false);
+    }
+
+    if (low_user_did_run == -1) {
+      ASSERT_FALSE(LowIntegrityUserDidRunValueExists());
+    } else {
+      // In case of vista, the low integrity user value should get reset.
+      CheckLowIntegrityUserDidRunValue(is_vista ? false :
+                                       (low_user_did_run == 1) ? true : false);
+    }
+  }
+
+ private:
+  CString low_integrity_key_name_;
+};
+
+TEST_F(ApplicationUsageDataTest, ReadDidRunUser1) {
+  ApplicationUsageData data(true, false);
+
+  ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data.exists(), false);
+  ASSERT_EQ(data.did_run(), false);
+
+  // Test with false user value.
+  CreateUserDidRunValue(false);
+  ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data.exists(), true);
+  ASSERT_EQ(data.did_run(), false);
+}
+
+TEST_F(ApplicationUsageDataTest, ReadDidRunUser2) {
+  // Test with true user value.
+  ApplicationUsageData data1(true, false);
+  CreateUserDidRunValue(true);
+  ASSERT_SUCCEEDED(data1.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data1.exists(), true);
+  ASSERT_EQ(data1.did_run(), true);
+}
+
+TEST_F(ApplicationUsageDataTest, ReadDidRunUser3) {
+  // low integrity user = false, vista
+  ApplicationUsageData data2(true, true);
+  CreateLowIntegrityUserDidRunValue(false);
+  ASSERT_SUCCEEDED(data2.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data2.exists(), true);
+  ASSERT_EQ(data2.did_run(), false);
+}
+
+TEST_F(ApplicationUsageDataTest, ReadDidRunUser4) {
+  // low integrity user = true, vista
+  ApplicationUsageData data2(true, true);
+  CreateLowIntegrityUserDidRunValue(true);
+  ASSERT_SUCCEEDED(data2.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data2.exists(), true);
+  ASSERT_EQ(data2.did_run(), true);
+}
+
+TEST_F(ApplicationUsageDataTest, ReadDidRunUser5) {
+  // low integrity user = true, not vista
+  ApplicationUsageData data2(true, false);
+  CreateLowIntegrityUserDidRunValue(true);
+  ASSERT_SUCCEEDED(data2.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data2.exists(), false);
+  ASSERT_EQ(data2.did_run(), false);
+}
+
+TEST_F(ApplicationUsageDataTest, ReadDidRunMachine1) {
+  if (!vista_util::IsUserAdmin()) {
+    return;
+  }
+
+  ApplicationUsageData data(true, true);
+
+  // create machine application key and test
+  CreateMachineDidRunValue(false);
+  ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data.exists(), true);
+  ASSERT_EQ(data.did_run(), false);
+}
+
+TEST_F(ApplicationUsageDataTest, ReadDidRunMachine2) {
+  if (!vista_util::IsUserAdmin()) {
+    return;
+  }
+
+  ApplicationUsageData data1(true, true);
+  CreateMachineDidRunValue(true);
+  ASSERT_SUCCEEDED(data1.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data1.exists(), true);
+  ASSERT_EQ(data1.did_run(), true);
+}
+
+TEST_F(ApplicationUsageDataTest, ReadDidRunBoth1) {
+  if (!vista_util::IsUserAdmin()) {
+    return;
+  }
+
+  // We try all combinations of machine, user and low integrity user
+  // registry value for did run. -1 indicates the value does not exist
+  // 1 indicates true and 0 indicates false.
+  for (int vista = 0; vista < 2; ++vista) {
+    for (int machine = -1; machine < 2; ++machine) {
+      for (int user = -1; user < 2; ++user) {
+        for (int lowuser = -1; lowuser < 2; ++lowuser) {
+          bool expected_did_run = false;
+          bool expected_exists = false;
+
+          if (machine > -1 || user > -1 || (vista && lowuser > -1)) {
+            expected_exists = true;
+          }
+
+          if (machine > 0 || user > 0 || (vista && lowuser > 0)) {
+            expected_did_run = true;
+          }
+
+          TestUserAndMachineDidRun(machine, user, lowuser,
+                                   expected_exists,
+                                   expected_did_run,
+                                   vista);
+          TearDown();
+        }
+      }
+    }
+  }
+}
+
+TEST_F(ApplicationUsageDataTest, ResetDidRunUser1) {
+  ApplicationUsageData data(true, true);
+
+  // create user application key and test
+  CreateUserDidRunValue(false);
+  ASSERT_SUCCEEDED(data.ResetDidRun(kAppGuid));
+  CheckUserDidRunValue(false);
+
+  ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data.exists(), true);
+  ASSERT_EQ(data.did_run(), false);
+}
+
+TEST_F(ApplicationUsageDataTest, ResetDidRunUser2) {
+  ApplicationUsageData data1(true, true);
+  CreateUserDidRunValue(true);
+  ASSERT_SUCCEEDED(data1.ResetDidRun(kAppGuid));
+  CheckUserDidRunValue(false);
+
+  ASSERT_SUCCEEDED(data1.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data1.exists(), true);
+  ASSERT_EQ(data1.did_run(), false);
+}
+
+TEST_F(ApplicationUsageDataTest, ResetDidRunMachine1) {
+  if (!vista_util::IsUserAdmin()) {
+    return;
+  }
+
+  ApplicationUsageData data(true, true);
+  CreateMachineDidRunValue(false);
+  ASSERT_SUCCEEDED(data.ResetDidRun(kAppGuid));
+  CheckMachineDidRunValue(false);
+
+  ASSERT_SUCCEEDED(data.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data.exists(), true);
+  ASSERT_EQ(data.did_run(), false);
+}
+
+TEST_F(ApplicationUsageDataTest, ResetDidRunMachine2) {
+  if (!vista_util::IsUserAdmin()) {
+    return;
+  }
+
+  ApplicationUsageData data1(true, true);
+  CreateMachineDidRunValue(true);
+  ASSERT_SUCCEEDED(data1.ResetDidRun(kAppGuid));
+  CheckMachineDidRunValue(false);
+
+  ASSERT_SUCCEEDED(data1.ReadDidRun(kAppGuid));
+  ASSERT_EQ(data1.exists(), true);
+  ASSERT_EQ(data1.did_run(), false);
+}
+
+TEST_F(ApplicationUsageDataTest, ResetDidRunBoth) {
+  if (!vista_util::IsUserAdmin()) {
+    return;
+  }
+
+  // We try all combinations of machine, user and low integrity user
+  // registry value for did run. -1 indicates the value does not exist
+  // 1 indicates true and 0 indicates false.
+  for (int vista = 0; vista < 2; ++vista) {
+    for (int machine = -1; machine < 2; ++machine) {
+      for (int user = -1; user < 2; ++user) {
+        for (int lowuser = -1; lowuser < 2; ++lowuser) {
+          bool expected_exists = false;
+          if (machine > -1 || user > -1 || (vista && lowuser > -1)) {
+            expected_exists = true;
+          }
+
+          TestUserAndMachineDidRunPostProcess(machine, user, lowuser,
+                                              expected_exists,
+                                              vista);
+          TearDown();
+        }
+      }
+    }
+  }
+}
+
+TEST_F(ApplicationUsageDataTest, UserReadDidRunUser) {
+  for (int vista = 0; vista < 2; ++vista) {
+      for (int user = -1; user < 2; ++user) {
+        for (int lowuser = -1; lowuser < 2; ++lowuser) {
+          bool expected_exists = false;
+          bool expected_did_run = false;
+
+          if (user != -1 || (vista && lowuser != -1)) {
+            expected_exists = true;
+          }
+
+          if (user > 0 || (vista && lowuser > 0)) {
+            expected_did_run = true;
+          }
+
+          UserTestDidRunPreProcess(user, lowuser, vista, expected_exists,
+                                   expected_did_run);
+          TearDown();
+        }
+      }
+  }
+}
+
+TEST_F(ApplicationUsageDataTest, UserResetDidRunUser1) {
+  for (int vista = 0; vista < 2; ++vista) {
+    for (int user = -1; user < 2; ++user) {
+      for (int lowuser = -1; lowuser < 2; ++lowuser) {
+        UserTestDidRunPostProcess(user, lowuser, vista);
+        TearDown();
+      }
+    }
+  }
+}
+
+}  // namespace omaha
diff --git a/worker/build.scons b/worker/build.scons
index c1a779e..1aadf94 100644
--- a/worker/build.scons
+++ b/worker/build.scons
@@ -1,51 +1,51 @@
-# Copyright 2008-2009 Google Inc.

-#

-# Licensed under the Apache License, Version 2.0 (the "License");

-# you may not use this file except in compliance with the License.

-# You may obtain a copy of the License at

-#

-#      http://www.apache.org/licenses/LICENSE-2.0

-#

-# Unless required by applicable law or agreed to in writing, software

-# distributed under the License is distributed on an "AS IS" BASIS,

-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-# See the License for the specific language governing permissions and

-# limitations under the License.

-# ========================================================================

-

-Import('env')

-

-inputs = [

-    'application_manager.cc',

-    'application_usage_data.cc',

-    'com_wrapper_shutdown_handler.cc',

-    'download_manager.cc',

-    'install_manager.cc',

-    'job.cc',

-    'job_creator.cc',

-    'job_observer.cc',

-    'ping.cc',

-    'ping_utils.cc',

-    'ui.cc',

-    'worker.cc',

-    'worker_com_wrapper.cc',

-    'worker_event_logger.cc',

-    'worker_job.cc',

-    'worker_job_strategy.cc',

-    'worker_metrics.cc',

-

-    'uilib/node_state.cc',

-    'uilib/static_ex.cc',

-    'uilib/static_line.cc',

-    ]

-

-

-local_env = env.Clone()

-

-# Need to look in output dir to find .h files generated by midl compiler.

-# This also allows Hammer to understand dependencies between this subdir

-# and the .idl files in the goopdate folder.

-local_env['CPPPATH'] += ['$OBJ_ROOT']

-

-# Build these into a library.

-local_env.ComponentLibrary('worker', inputs)

+# Copyright 2008-2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ========================================================================
+
+Import('env')
+
+inputs = [
+    'application_manager.cc',
+    'application_usage_data.cc',
+    'com_wrapper_shutdown_handler.cc',
+    'download_manager.cc',
+    'install_manager.cc',
+    'job.cc',
+    'job_creator.cc',
+    'job_observer.cc',
+    'ping.cc',
+    'ping_utils.cc',
+    'ui.cc',
+    'worker.cc',
+    'worker_com_wrapper.cc',
+    'worker_event_logger.cc',
+    'worker_job.cc',
+    'worker_job_strategy.cc',
+    'worker_metrics.cc',
+
+    'uilib/node_state.cc',
+    'uilib/static_ex.cc',
+    'uilib/static_line.cc',
+    ]
+
+
+local_env = env.Clone()
+
+# Need to look in output dir to find .h files generated by midl compiler.
+# This also allows Hammer to understand dependencies between this subdir
+# and the .idl files in the goopdate folder.
+local_env['CPPPATH'] += ['$OBJ_ROOT']
+
+# Build these into a library.
+local_env.ComponentLibrary('worker', inputs)
diff --git a/worker/com_wrapper_shutdown_handler.cc b/worker/com_wrapper_shutdown_handler.cc
index 66b69eb..1825e6c 100644
--- a/worker/com_wrapper_shutdown_handler.cc
+++ b/worker/com_wrapper_shutdown_handler.cc
@@ -1,57 +1,57 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The WorkerComWrapperShutdownCallBack implements the shutdown

-// handler for OnDemandUpdates. The class posts a WM_QUIT message

-// to the main thread. In case of the OnDemandUpdates this

-// main thread loop is running a message loop provided by

-// CAtlExeModuleT::RunMessageLoop().

-

-#include "omaha/worker/com_wrapper_shutdown_handler.h"

-

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/goopdate/google_update.h"

-

-namespace omaha {

-

-int WorkerComWrapperShutdownCallBack::ReleaseIgnoreShutdown() {

-  int release_count = InternalRelease();

-  if (!release_count && shutdown_on_final_release_) {

-    VERIFY1(SUCCEEDED(Shutdown()));

-  }

-

-  return release_count;

-}

-

-HRESULT WorkerComWrapperShutdownCallBack::Shutdown() {

-  if (ShouldIgnoreShutdown()) {

-    return S_OK;

-  }

-

-  GoogleUpdate* google_update = static_cast<GoogleUpdate*>(_pAtlModule);

-  ASSERT1(google_update);

-  if (!::PostThreadMessage(google_update->m_dwMainThreadID, WM_QUIT, 0, 0)) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LE, (_T("[PostThreadMessage failed][0x%08x]"), hr));

-    return hr;

-  }

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The WorkerComWrapperShutdownCallBack implements the shutdown
+// handler for OnDemandUpdates. The class posts a WM_QUIT message
+// to the main thread. In case of the OnDemandUpdates this
+// main thread loop is running a message loop provided by
+// CAtlExeModuleT::RunMessageLoop().
+
+#include "omaha/worker/com_wrapper_shutdown_handler.h"
+
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/goopdate/google_update.h"
+
+namespace omaha {
+
+int WorkerComWrapperShutdownCallBack::ReleaseIgnoreShutdown() {
+  int release_count = InternalRelease();
+  if (!release_count && shutdown_on_final_release_) {
+    VERIFY1(SUCCEEDED(Shutdown()));
+  }
+
+  return release_count;
+}
+
+HRESULT WorkerComWrapperShutdownCallBack::Shutdown() {
+  if (ShouldIgnoreShutdown()) {
+    return S_OK;
+  }
+
+  GoogleUpdate* google_update = static_cast<GoogleUpdate*>(_pAtlModule);
+  ASSERT1(google_update);
+  if (!::PostThreadMessage(google_update->m_dwMainThreadID, WM_QUIT, 0, 0)) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LE, (_T("[PostThreadMessage failed][0x%08x]"), hr));
+    return hr;
+  }
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/worker/com_wrapper_shutdown_handler.h b/worker/com_wrapper_shutdown_handler.h
index f001358..cc93db1 100644
--- a/worker/com_wrapper_shutdown_handler.h
+++ b/worker/com_wrapper_shutdown_handler.h
@@ -1,61 +1,61 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Contains WorkerComWrapperShutdownCallBack which implements the

-// shutdown handling code for the OnDemandUpdate COM Server.

-

-#ifndef OMAHA_GOOPDATE_COM_WRAPPER_SHUTDOWN_HANDLER_H__

-#define OMAHA_GOOPDATE_COM_WRAPPER_SHUTDOWN_HANDLER_H__

-

-#include <windows.h>

-#include <atlbase.h>

-#include <atlcom.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/shutdown_callback.h"

-#include "omaha/common/synchronized.h"

-

-namespace omaha {

-

-class WorkerComWrapperShutdownCallBack

-    : public ShutdownCallback,

-      public CComObjectRootEx<CComMultiThreadModel> {

- public:

-  WorkerComWrapperShutdownCallBack(bool shutdown_on_final_release)

-      : shutdown_on_final_release_(shutdown_on_final_release) {}

-  virtual ~WorkerComWrapperShutdownCallBack() {}

-  virtual HRESULT Shutdown();

-

-  // Clears the ignore shutdown flag.

-  int ReleaseIgnoreShutdown();

-

-  // Atomically sets the ignore shutdown flag and returns its previous value.

-  int AddRefIgnoreShutdown() {

-    return InternalAddRef();

-  }

-

-  // Returns the value of the ignore shutdown flag.

-  bool ShouldIgnoreShutdown() {

-    InternalAddRef();

-    return !!InternalRelease();

-  }

-

- private:

-  bool shutdown_on_final_release_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_GOOPDATE_COM_WRAPPER_SHUTDOWN_HANDLER_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Contains WorkerComWrapperShutdownCallBack which implements the
+// shutdown handling code for the OnDemandUpdate COM Server.
+
+#ifndef OMAHA_GOOPDATE_COM_WRAPPER_SHUTDOWN_HANDLER_H__
+#define OMAHA_GOOPDATE_COM_WRAPPER_SHUTDOWN_HANDLER_H__
+
+#include <windows.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/shutdown_callback.h"
+#include "omaha/common/synchronized.h"
+
+namespace omaha {
+
+class WorkerComWrapperShutdownCallBack
+    : public ShutdownCallback,
+      public CComObjectRootEx<CComMultiThreadModel> {
+ public:
+  WorkerComWrapperShutdownCallBack(bool shutdown_on_final_release)
+      : shutdown_on_final_release_(shutdown_on_final_release) {}
+  virtual ~WorkerComWrapperShutdownCallBack() {}
+  virtual HRESULT Shutdown();
+
+  // Clears the ignore shutdown flag.
+  int ReleaseIgnoreShutdown();
+
+  // Atomically sets the ignore shutdown flag and returns its previous value.
+  int AddRefIgnoreShutdown() {
+    return InternalAddRef();
+  }
+
+  // Returns the value of the ignore shutdown flag.
+  bool ShouldIgnoreShutdown() {
+    InternalAddRef();
+    return !!InternalRelease();
+  }
+
+ private:
+  bool shutdown_on_final_release_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_GOOPDATE_COM_WRAPPER_SHUTDOWN_HANDLER_H__
+
diff --git a/worker/download_manager.cc b/worker/download_manager.cc
index 1cb34f1..668db87 100644
--- a/worker/download_manager.cc
+++ b/worker/download_manager.cc
@@ -1,448 +1,448 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// The download manager uses the network request to download the remote file.

-// When running as local system, the network request impersonates one of the

-// logged on users. To save the file, the network request needs write access to

-// a directory, both when running impersonated and not.

-// The directory is obtained by calling SHGetFolderLocation with

-// CSIDL_COMMON_APPDATA. In order to ensure the directory is accessible

-// even in cases when impersonatation is used, BuildUniqueDownloadFilePath

-// impersonates before calling SHGetFolderLocation.

-//

-// Once the download is complete, The download manager copies the file to either

-// the machine secure location or the user secure location and then

-// it validates the hash.

-

-#include "omaha/worker/download_manager.h"

-

-#include <vector>

-#include <algorithm>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/scoped_impersonation.h"

-#include "omaha/common/string.h"

-#include "omaha/common/user_rights.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource.h"

-#include "omaha/net/bits_request.h"

-#include "omaha/net/browser_request.h"

-#include "omaha/net/http_client.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/net_utils.h"

-#include "omaha/net/simple_request.h"

-#include "omaha/worker/job.h"

-#include "omaha/worker/worker_metrics.h"

-

-namespace omaha {

-

-namespace {

-

-// Creates and initializes an instance of the NetworkRequest for the

-// Downloadmanager to use. Defines a fallback chain: BITS, WinHttp, browser.

-NetworkRequest* CreateNetworkRequest(bool is_logged_on) {

-  const NetworkConfig::Session& session(NetworkConfig::Instance().session());

-  NetworkRequest* network_request(new NetworkRequest(session));

-

-  // TODO(omaha): provide a mechanism for different timeout values in

-  // silent and interactive downloads.

-

-  // TODO(omaha): background downloads are not supported yet.

-

-  // BITS transfers files only when the job owner is logged on. If the

-  // process "Run As" another user, an empty BITS job gets created in suspended

-  // state but there is no way to manipulate the job, nor cancel it.

-  if (is_logged_on) {

-    BitsRequest* bits_request(new BitsRequest);

-    bits_request->set_minimum_retry_delay(60);

-    bits_request->set_no_progress_timeout(15);

-    network_request->AddHttpRequest(bits_request);

-  }

-

-  network_request->AddHttpRequest(new SimpleRequest);

-  network_request->AddHttpRequest(new BrowserRequest);

-

-  network_request->set_num_retries(1);

-  return network_request;

-}

-

-}  // namespace

-

-DownloadManager::DownloadManager(bool is_machine)

-    : job_(NULL),

-      is_machine_(is_machine),

-      impersonation_token_(NULL),

-      is_logged_on_(false) {

-  HRESULT hr = IsUserLoggedOn(&is_logged_on_);

-

-  // Assumes the caller is not logged on if the function failed.

-  ASSERT1(SUCCEEDED(hr) || !is_logged_on_);

-

-  http_client_.reset(CreateHttpClient());

-  ASSERT1(http_client_.get());

-}

-

-void DownloadManager::SetErrorInfo(HRESULT hr) {

-  ASSERT1(job_);

-  CString msg;

-  // TODO(omaha):  job_->app_data().display_name() may not be correct

-  // for bundles.

-  if (!goopdate_utils::FormatMessageForNetworkError(

-          hr,

-          job_->app_data().display_name(),

-          &msg)) {

-    msg.FormatMessage(IDS_DOWNLOAD_ERROR, hr);

-  }

-  error_info_ = CompletionInfo(COMPLETION_ERROR, hr, msg);

-}

-

-HRESULT DownloadManager::DownloadFile(Job* job) {

-  ASSERT1(job);

-  ASSERT1(job_ == NULL);

-

-  ASSERT1(ConfigManager::Instance()->CanUseNetwork(is_machine_));

-

-  ++metric_worker_download_total;

-

-  job_ = job;

-  HRESULT hr = DownloadCurrentJob();

-  if (SUCCEEDED(hr)) {

-    ++metric_worker_download_succeeded;

-  }

-  job_ = NULL;

-  return hr;

-}

-

-HRESULT DownloadManager::DownloadCurrentJob() {

-  ASSERT1(job_);

-

-  HRESULT hr = BuildUniqueDownloadFilePath(&local_download_file_path_);

-  if (FAILED(hr)) {

-    CORE_LOG(LW,

-        (_T("[BuildUniqueDownloadFilePath failed][0x%08x]"), hr));

-    SetErrorInfo(hr);

-    return hr;

-  }

-

-  network_request_.reset(CreateNetworkRequest(is_logged_on_));

-  network_request_->set_low_priority(job_->is_background());

-

-  CString path = is_machine_ ?

-      ConfigManager::Instance()->GetMachineSecureDownloadStorageDir() :

-      ConfigManager::Instance()->GetUserDownloadStorageDir();

-

-  if (IsCached(path)) {

-    OPT_LOG(L1, (_T("[Using cached version of the download file %s]"),

-                 local_download_file_path_));

-    return S_OK;

-  }

-

-  network_request_->set_callback(job_);

-  OPT_LOG(L1, (_T("[Starting file download from %s to %s]"),

-               job_->response_data().url(),

-               local_download_file_path_));

-  hr = network_request_->DownloadFile(job_->response_data().url(),

-                                      local_download_file_path_);

-  if (FAILED(hr)) {

-    goopdate_utils::AddNetworkRequestDataToEventLog(network_request_.get(), hr);

-    SetErrorInfo(hr);

-  }

-  VERIFY1(SUCCEEDED(network_request_->Close()));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = MoveFile();

-  if (FAILED(hr)) {

-    SetErrorInfo(hr);

-    return hr;

-  }

-

-  hr = ValidateDownloadedFile(local_download_file_path_);

-  if (FAILED(hr)) {

-    CString msg;

-    msg.FormatMessage(IDS_DOWNLOAD_HASH_MISMATCH, hr);

-    error_info_ = CompletionInfo(COMPLETION_ERROR, hr, msg);

-    LogValidationFailure();

-    return hr;

-  }

-

-  return S_OK;

-}

-

-void DownloadManager::LogValidationFailure() const {

-  const int kDownloadFileBytesToLog = 256;

-

-  bool exists = File::Exists(local_download_file_path_);

-  uint32 file_size(0);

-  std::vector<char> download_file_bytes(kDownloadFileBytesToLog + 1);

-  if (exists) {

-    if (FAILED(File::GetFileSizeUnopen(local_download_file_path_,

-                                       &file_size))) {

-      return;

-    }

-

-    File downloaded_file;

-    if (SUCCEEDED(downloaded_file.Open(local_download_file_path_,

-                                       false, false))) {

-      uint32 bytes_read = 0;

-      if (SUCCEEDED(downloaded_file.ReadFromStartOfFile(

-              kDownloadFileBytesToLog,

-              reinterpret_cast<unsigned char*>(&download_file_bytes.front()),

-              &bytes_read))) {

-        download_file_bytes.resize(bytes_read);

-        std::replace_if(download_file_bytes.begin(), download_file_bytes.end(),

-                        std::not1(std::ptr_fun(isprint)), '.');

-        download_file_bytes.push_back('\0');

-      }

-    }

-  }

-

-  REPORT_LOG(L1, (_T("[DownloadValidationFail filename=%s exists=%d size=%d ")

-                  _T("expected size=%d expected hash=%s filebytes=%hS]"),

-                  local_download_file_path_,

-                  exists,

-                  file_size,

-                  job_->response_data().size(),

-                  job_->response_data().hash(),

-                  &download_file_bytes.front()));

-}

-

-HRESULT DownloadManager::Cancel() {

-  return network_request_.get() ? network_request_->Cancel() : S_OK;

-}

-

-// The installer is initially downloaded to a temporary unique name.

-// Once the download succeeds the file is copied to

-// DownloadDir\<Guid>\<name> where

-// DownloadDir = User or machine download dir returned by ConfigManager.

-// guid        = Guid used for temp name.

-// name        = Name specified in the update response.

-// The reason to copy the file using a sub-directory structure is to account

-// for the case where the same file is downloaded by multiple processes or

-// threads.

-HRESULT DownloadManager::BuildUniqueDownloadFilePath(CString* file) const {

-  ASSERT1(file);

-

-  // Impersonate the user if a valid impersonation token is presented.

-  // Continue unimpersonated if the impersonation fails. We do the

-  // impersonation here to get the correct download folder for

-  // impersonated clients. (For more information refer to the comment

-  // at the top of the file.)

-  scoped_impersonation impersonate_user(impersonation_token_);

-  if (impersonation_token_) {

-    DWORD result = impersonate_user.result();

-    ASSERT(result == ERROR_SUCCESS, (_T("impersonation failed %d"), result));

-  }

-

-  GUID guid(GUID_NULL);

-  HRESULT hr = ::CoCreateGuid(&guid);

-  if (FAILED(hr)) {

-    CORE_LOG(L3, (_T("[CoCreateGuid failed 0x%08x]"), hr));

-    return hr;

-  }

-

-  CString path(ConfigManager::Instance()->GetTempDownloadDir());

-  *file = ConcatenatePath(path, GuidToString(guid));

-  if (file->IsEmpty()) {

-    ASSERT1(false);

-    return GOOPDATEDOWNLOAD_E_UNIQUE_FILE_PATH_EMPTY;

-  }

-  return S_OK;

-}

-

-HRESULT DownloadManager::GetFileNameFromDownloadUrl(const CString& url,

-                                                    CString* file_name) const {

-  CORE_LOG(L3, (_T("[DownloadManager::GetFileNameFromDownloadUrl]")));

-  ASSERT1(job_);

-  ASSERT1(http_client_.get());

-  ASSERT1(file_name);

-

-  CString url_path;

-  int port = 0;

-  CString extra_info;

-  HRESULT hr = http_client_->CrackUrl(url, 0, NULL, NULL, &port,

-                                      &url_path, &extra_info);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[CrackUrl failed 0x%08x]"), hr));

-    return GOOPDATEDOWNLOAD_E_CRACKURL_FAILED;

-  }

-

-  int start_file_name_idx = url_path.ReverseFind(_T('/'));

-  if (start_file_name_idx == -1) {

-    CORE_LOG(LW, (_T("[No filename found in download url.]")));

-    return GOOPDATEDOWNLOAD_E_INVALID_PATH;

-  }

-  ASSERT1(url_path.GetLength() >= start_file_name_idx - 1);

-  CString dst_file_name =

-      url_path.Right(url_path.GetLength() - start_file_name_idx - 1);

-  if (dst_file_name.IsEmpty()) {

-    OPT_LOG(LE, (_T("[Empty filename in download url]")));

-    return GOOPDATEDOWNLOAD_E_FILE_NAME_EMPTY;

-  }

-  ASSERT1(!dst_file_name.IsEmpty());

-  *file_name = dst_file_name;

-

-  return S_OK;

-}

-

-bool DownloadManager::IsCached(const CString& store) {

-  OPT_LOG(L3, (_T("[DownloadManager::IsCached]")));

-  ASSERT1(job_);

-

-  if (!job_->is_background()) {

-    return false;

-  }

-

-  CString dst_file_name;

-  HRESULT hr = GetFileNameFromDownloadUrl(job_->response_data().url(),

-                                          &dst_file_name);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[GetFileNameFromDownloadUrl failed][0x%08x]"), hr));

-    return false;

-  }

-  ASSERT1(!dst_file_name.IsEmpty());

-

-  std::vector<CString> files;

-  hr = FindFileRecursive(store, dst_file_name, &files);

-  if (FAILED(hr)) {

-    CORE_LOG(L3, (_T("[FindFileRecursive failed][0x%08x]"), hr));

-    return false;

-  }

-

-  for (size_t i = 0; i < files.size(); ++i) {

-    ASSERT1(File::Exists(files[i]));

-    if (SUCCEEDED(ValidateDownloadedFile(files[i]))) {

-      OPT_LOG(L2, (_T("[Found cached file %s.]"), files[i]));

-      local_download_file_path_ = files[i];

-      job_->set_download_file_name(local_download_file_path_);

-      return true;

-    } else {

-      OPT_LOG(L2, (_T("[Found cached file %s validation failed.]"), files[i]));

-    }

-  }

-

-  return false;

-}

-

-HRESULT DownloadManager::ValidateDownloadedFile(

-    const CString& file_name) const {

-  return goopdate_utils::ValidateDownloadedFile(file_name,

-      job_->response_data().hash(),

-      static_cast<uint32>(job_->response_data().size()));

-}

-

-HRESULT DownloadManager::BuildDestinationDirectory(CString* dest_path) const {

-  ASSERT1(dest_path);

-  dest_path->Empty();

-

-  const CString path = is_machine_ ?

-      ConfigManager::Instance()->GetMachineSecureDownloadStorageDir() :

-      ConfigManager::Instance()->GetUserDownloadStorageDir();

-

-  CORE_LOG(L3, (_T("[Download Storage Dir][%s]"), path));

-

-  if (!File::Exists(path)) {

-    return GOOPDATEDOWNLOAD_E_STORAGE_DIR_NOT_EXIST;

-  }

-

-  GUID guid(GUID_NULL);

-  HRESULT hr = ::CoCreateGuid(&guid);

-  if (FAILED(hr)) {

-    OPT_LOG(LW, (_T("[CoCreateGuid failed 0x%08x]"), hr));

-    return hr;

-  }

-

-  CString destination_path = ConcatenatePath(path, GuidToString(guid));

-  if (destination_path.IsEmpty()) {

-    ASSERT1(false);

-    return GOOPDATEDOWNLOAD_E_DEST_PATH_EMPTY;

-  }

-

-  hr = CreateDir(destination_path, NULL);

-  if (FAILED(hr)) {

-    // Since the directory creation failed, we will fall back to the destination

-    // directory returned by the ConfigManager.

-    OPT_LOG(LW, (_T("[CreateDir '%s' failed][0x%08x]"), destination_path, hr));

-    destination_path = path;

-  }

-

-  OPT_LOG(L1, (_T("[The destination directory is '%s']"), destination_path));

-  *dest_path = destination_path;

-

-  return S_OK;

-}

-

-HRESULT DownloadManager::MoveFile() {

-  ++metric_worker_download_move_total;

-

-  CString dest_path;

-  HRESULT hr = BuildDestinationDirectory(&dest_path);

-  if (FAILED(hr)) {

-    OPT_LOG(LW, (_T("[Build destination directory failed][0x%08x]"), hr));

-    return hr;

-  }

-  CORE_LOG(L3, (_T("[Download Directory][%s]"), dest_path));

-  ASSERT1(!dest_path.IsEmpty());

-  ASSERT1(File::Exists(dest_path));

-

-  CString dst_file_name;

-  hr = GetFileNameFromDownloadUrl(job_->response_data().url(),

-                                  &dst_file_name);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[GetFileNameFromDownloadUrl failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (dst_file_name.IsEmpty()) {

-    ASSERT1(false);

-    return GOOPDATEDOWNLOAD_E_DEST_FILENAME_EMPTY;

-  }

-  CORE_LOG(L3, (_T("[Destination filename][%s]"), dst_file_name));

-

-  CString dest_file_path = ConcatenatePath(dest_path, dst_file_name);

-  if (dest_file_path.IsEmpty()) {

-    ASSERT1(false);

-    return GOOPDATEDOWNLOAD_E_DEST_FILE_PATH_EMPTY;

-  }

-

-  OPT_LOG(L1, (_T("[Moving download file from %s to %s]"),

-               local_download_file_path_, dest_file_path));

-  // Uses ::CopyFile. ::CopyFile, done without impersonation, will reset the

-  // ownership of the destination file, and make sure that it inherits ACEs from

-  // the new parent directory.

-  hr = File::Copy(local_download_file_path_, dest_file_path, true);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Could not copy '%s' to '%s'][0x%08x]"),

-                 local_download_file_path_, dest_file_path, hr));

-    job_->set_extra_code1(hr);

-    return GOOPDATEDOWNLOAD_E_FAILED_MOVE;

-  }

-  VERIFY1(SUCCEEDED(File::Remove(local_download_file_path_)));

-

-  local_download_file_path_ = dest_file_path;

-  job_->set_download_file_name(dest_file_path);

-

-  ++metric_worker_download_move_succeeded;

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// The download manager uses the network request to download the remote file.
+// When running as local system, the network request impersonates one of the
+// logged on users. To save the file, the network request needs write access to
+// a directory, both when running impersonated and not.
+// The directory is obtained by calling SHGetFolderLocation with
+// CSIDL_COMMON_APPDATA. In order to ensure the directory is accessible
+// even in cases when impersonatation is used, BuildUniqueDownloadFilePath
+// impersonates before calling SHGetFolderLocation.
+//
+// Once the download is complete, The download manager copies the file to either
+// the machine secure location or the user secure location and then
+// it validates the hash.
+
+#include "omaha/worker/download_manager.h"
+
+#include <vector>
+#include <algorithm>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/scoped_impersonation.h"
+#include "omaha/common/string.h"
+#include "omaha/common/user_rights.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource.h"
+#include "omaha/net/bits_request.h"
+#include "omaha/net/browser_request.h"
+#include "omaha/net/http_client.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/net_utils.h"
+#include "omaha/net/simple_request.h"
+#include "omaha/worker/job.h"
+#include "omaha/worker/worker_metrics.h"
+
+namespace omaha {
+
+namespace {
+
+// Creates and initializes an instance of the NetworkRequest for the
+// Downloadmanager to use. Defines a fallback chain: BITS, WinHttp, browser.
+NetworkRequest* CreateNetworkRequest(bool is_logged_on) {
+  const NetworkConfig::Session& session(NetworkConfig::Instance().session());
+  NetworkRequest* network_request(new NetworkRequest(session));
+
+  // TODO(omaha): provide a mechanism for different timeout values in
+  // silent and interactive downloads.
+
+  // TODO(omaha): background downloads are not supported yet.
+
+  // BITS transfers files only when the job owner is logged on. If the
+  // process "Run As" another user, an empty BITS job gets created in suspended
+  // state but there is no way to manipulate the job, nor cancel it.
+  if (is_logged_on) {
+    BitsRequest* bits_request(new BitsRequest);
+    bits_request->set_minimum_retry_delay(60);
+    bits_request->set_no_progress_timeout(15);
+    network_request->AddHttpRequest(bits_request);
+  }
+
+  network_request->AddHttpRequest(new SimpleRequest);
+  network_request->AddHttpRequest(new BrowserRequest);
+
+  network_request->set_num_retries(1);
+  return network_request;
+}
+
+}  // namespace
+
+DownloadManager::DownloadManager(bool is_machine)
+    : job_(NULL),
+      is_machine_(is_machine),
+      impersonation_token_(NULL),
+      is_logged_on_(false) {
+  HRESULT hr = IsUserLoggedOn(&is_logged_on_);
+
+  // Assumes the caller is not logged on if the function failed.
+  ASSERT1(SUCCEEDED(hr) || !is_logged_on_);
+
+  http_client_.reset(CreateHttpClient());
+  ASSERT1(http_client_.get());
+}
+
+void DownloadManager::SetErrorInfo(HRESULT hr) {
+  ASSERT1(job_);
+  CString msg;
+  // TODO(omaha):  job_->app_data().display_name() may not be correct
+  // for bundles.
+  if (!goopdate_utils::FormatMessageForNetworkError(
+          hr,
+          job_->app_data().display_name(),
+          &msg)) {
+    msg.FormatMessage(IDS_DOWNLOAD_ERROR, hr);
+  }
+  error_info_ = CompletionInfo(COMPLETION_ERROR, hr, msg);
+}
+
+HRESULT DownloadManager::DownloadFile(Job* job) {
+  ASSERT1(job);
+  ASSERT1(job_ == NULL);
+
+  ASSERT1(ConfigManager::Instance()->CanUseNetwork(is_machine_));
+
+  ++metric_worker_download_total;
+
+  job_ = job;
+  HRESULT hr = DownloadCurrentJob();
+  if (SUCCEEDED(hr)) {
+    ++metric_worker_download_succeeded;
+  }
+  job_ = NULL;
+  return hr;
+}
+
+HRESULT DownloadManager::DownloadCurrentJob() {
+  ASSERT1(job_);
+
+  HRESULT hr = BuildUniqueDownloadFilePath(&local_download_file_path_);
+  if (FAILED(hr)) {
+    CORE_LOG(LW,
+        (_T("[BuildUniqueDownloadFilePath failed][0x%08x]"), hr));
+    SetErrorInfo(hr);
+    return hr;
+  }
+
+  network_request_.reset(CreateNetworkRequest(is_logged_on_));
+  network_request_->set_low_priority(job_->is_background());
+
+  CString path = is_machine_ ?
+      ConfigManager::Instance()->GetMachineSecureDownloadStorageDir() :
+      ConfigManager::Instance()->GetUserDownloadStorageDir();
+
+  if (IsCached(path)) {
+    OPT_LOG(L1, (_T("[Using cached version of the download file %s]"),
+                 local_download_file_path_));
+    return S_OK;
+  }
+
+  network_request_->set_callback(job_);
+  OPT_LOG(L1, (_T("[Starting file download from %s to %s]"),
+               job_->response_data().url(),
+               local_download_file_path_));
+  hr = network_request_->DownloadFile(job_->response_data().url(),
+                                      local_download_file_path_);
+  if (FAILED(hr)) {
+    goopdate_utils::AddNetworkRequestDataToEventLog(network_request_.get(), hr);
+    SetErrorInfo(hr);
+  }
+  VERIFY1(SUCCEEDED(network_request_->Close()));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = MoveFile();
+  if (FAILED(hr)) {
+    SetErrorInfo(hr);
+    return hr;
+  }
+
+  hr = ValidateDownloadedFile(local_download_file_path_);
+  if (FAILED(hr)) {
+    CString msg;
+    msg.FormatMessage(IDS_DOWNLOAD_HASH_MISMATCH, hr);
+    error_info_ = CompletionInfo(COMPLETION_ERROR, hr, msg);
+    LogValidationFailure();
+    return hr;
+  }
+
+  return S_OK;
+}
+
+void DownloadManager::LogValidationFailure() const {
+  const int kDownloadFileBytesToLog = 256;
+
+  bool exists = File::Exists(local_download_file_path_);
+  uint32 file_size(0);
+  std::vector<char> download_file_bytes(kDownloadFileBytesToLog + 1);
+  if (exists) {
+    if (FAILED(File::GetFileSizeUnopen(local_download_file_path_,
+                                       &file_size))) {
+      return;
+    }
+
+    File downloaded_file;
+    if (SUCCEEDED(downloaded_file.Open(local_download_file_path_,
+                                       false, false))) {
+      uint32 bytes_read = 0;
+      if (SUCCEEDED(downloaded_file.ReadFromStartOfFile(
+              kDownloadFileBytesToLog,
+              reinterpret_cast<unsigned char*>(&download_file_bytes.front()),
+              &bytes_read))) {
+        download_file_bytes.resize(bytes_read);
+        std::replace_if(download_file_bytes.begin(), download_file_bytes.end(),
+                        std::not1(std::ptr_fun(isprint)), '.');
+        download_file_bytes.push_back('\0');
+      }
+    }
+  }
+
+  REPORT_LOG(L1, (_T("[DownloadValidationFail filename=%s exists=%d size=%d ")
+                  _T("expected size=%d expected hash=%s filebytes=%hS]"),
+                  local_download_file_path_,
+                  exists,
+                  file_size,
+                  job_->response_data().size(),
+                  job_->response_data().hash(),
+                  &download_file_bytes.front()));
+}
+
+HRESULT DownloadManager::Cancel() {
+  return network_request_.get() ? network_request_->Cancel() : S_OK;
+}
+
+// The installer is initially downloaded to a temporary unique name.
+// Once the download succeeds the file is copied to
+// DownloadDir\<Guid>\<name> where
+// DownloadDir = User or machine download dir returned by ConfigManager.
+// guid        = Guid used for temp name.
+// name        = Name specified in the update response.
+// The reason to copy the file using a sub-directory structure is to account
+// for the case where the same file is downloaded by multiple processes or
+// threads.
+HRESULT DownloadManager::BuildUniqueDownloadFilePath(CString* file) const {
+  ASSERT1(file);
+
+  // Impersonate the user if a valid impersonation token is presented.
+  // Continue unimpersonated if the impersonation fails. We do the
+  // impersonation here to get the correct download folder for
+  // impersonated clients. (For more information refer to the comment
+  // at the top of the file.)
+  scoped_impersonation impersonate_user(impersonation_token_);
+  if (impersonation_token_) {
+    DWORD result = impersonate_user.result();
+    ASSERT(result == ERROR_SUCCESS, (_T("impersonation failed %d"), result));
+  }
+
+  GUID guid(GUID_NULL);
+  HRESULT hr = ::CoCreateGuid(&guid);
+  if (FAILED(hr)) {
+    CORE_LOG(L3, (_T("[CoCreateGuid failed 0x%08x]"), hr));
+    return hr;
+  }
+
+  CString path(ConfigManager::Instance()->GetTempDownloadDir());
+  *file = ConcatenatePath(path, GuidToString(guid));
+  if (file->IsEmpty()) {
+    ASSERT1(false);
+    return GOOPDATEDOWNLOAD_E_UNIQUE_FILE_PATH_EMPTY;
+  }
+  return S_OK;
+}
+
+HRESULT DownloadManager::GetFileNameFromDownloadUrl(const CString& url,
+                                                    CString* file_name) const {
+  CORE_LOG(L3, (_T("[DownloadManager::GetFileNameFromDownloadUrl]")));
+  ASSERT1(job_);
+  ASSERT1(http_client_.get());
+  ASSERT1(file_name);
+
+  CString url_path;
+  int port = 0;
+  CString extra_info;
+  HRESULT hr = http_client_->CrackUrl(url, 0, NULL, NULL, &port,
+                                      &url_path, &extra_info);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[CrackUrl failed 0x%08x]"), hr));
+    return GOOPDATEDOWNLOAD_E_CRACKURL_FAILED;
+  }
+
+  int start_file_name_idx = url_path.ReverseFind(_T('/'));
+  if (start_file_name_idx == -1) {
+    CORE_LOG(LW, (_T("[No filename found in download url.]")));
+    return GOOPDATEDOWNLOAD_E_INVALID_PATH;
+  }
+  ASSERT1(url_path.GetLength() >= start_file_name_idx - 1);
+  CString dst_file_name =
+      url_path.Right(url_path.GetLength() - start_file_name_idx - 1);
+  if (dst_file_name.IsEmpty()) {
+    OPT_LOG(LE, (_T("[Empty filename in download url]")));
+    return GOOPDATEDOWNLOAD_E_FILE_NAME_EMPTY;
+  }
+  ASSERT1(!dst_file_name.IsEmpty());
+  *file_name = dst_file_name;
+
+  return S_OK;
+}
+
+bool DownloadManager::IsCached(const CString& store) {
+  OPT_LOG(L3, (_T("[DownloadManager::IsCached]")));
+  ASSERT1(job_);
+
+  if (!job_->is_background()) {
+    return false;
+  }
+
+  CString dst_file_name;
+  HRESULT hr = GetFileNameFromDownloadUrl(job_->response_data().url(),
+                                          &dst_file_name);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[GetFileNameFromDownloadUrl failed][0x%08x]"), hr));
+    return false;
+  }
+  ASSERT1(!dst_file_name.IsEmpty());
+
+  std::vector<CString> files;
+  hr = FindFileRecursive(store, dst_file_name, &files);
+  if (FAILED(hr)) {
+    CORE_LOG(L3, (_T("[FindFileRecursive failed][0x%08x]"), hr));
+    return false;
+  }
+
+  for (size_t i = 0; i < files.size(); ++i) {
+    ASSERT1(File::Exists(files[i]));
+    if (SUCCEEDED(ValidateDownloadedFile(files[i]))) {
+      OPT_LOG(L2, (_T("[Found cached file %s.]"), files[i]));
+      local_download_file_path_ = files[i];
+      job_->set_download_file_name(local_download_file_path_);
+      return true;
+    } else {
+      OPT_LOG(L2, (_T("[Found cached file %s validation failed.]"), files[i]));
+    }
+  }
+
+  return false;
+}
+
+HRESULT DownloadManager::ValidateDownloadedFile(
+    const CString& file_name) const {
+  return goopdate_utils::ValidateDownloadedFile(file_name,
+      job_->response_data().hash(),
+      static_cast<uint32>(job_->response_data().size()));
+}
+
+HRESULT DownloadManager::BuildDestinationDirectory(CString* dest_path) const {
+  ASSERT1(dest_path);
+  dest_path->Empty();
+
+  const CString path = is_machine_ ?
+      ConfigManager::Instance()->GetMachineSecureDownloadStorageDir() :
+      ConfigManager::Instance()->GetUserDownloadStorageDir();
+
+  CORE_LOG(L3, (_T("[Download Storage Dir][%s]"), path));
+
+  if (!File::Exists(path)) {
+    return GOOPDATEDOWNLOAD_E_STORAGE_DIR_NOT_EXIST;
+  }
+
+  GUID guid(GUID_NULL);
+  HRESULT hr = ::CoCreateGuid(&guid);
+  if (FAILED(hr)) {
+    OPT_LOG(LW, (_T("[CoCreateGuid failed 0x%08x]"), hr));
+    return hr;
+  }
+
+  CString destination_path = ConcatenatePath(path, GuidToString(guid));
+  if (destination_path.IsEmpty()) {
+    ASSERT1(false);
+    return GOOPDATEDOWNLOAD_E_DEST_PATH_EMPTY;
+  }
+
+  hr = CreateDir(destination_path, NULL);
+  if (FAILED(hr)) {
+    // Since the directory creation failed, we will fall back to the destination
+    // directory returned by the ConfigManager.
+    OPT_LOG(LW, (_T("[CreateDir '%s' failed][0x%08x]"), destination_path, hr));
+    destination_path = path;
+  }
+
+  OPT_LOG(L1, (_T("[The destination directory is '%s']"), destination_path));
+  *dest_path = destination_path;
+
+  return S_OK;
+}
+
+HRESULT DownloadManager::MoveFile() {
+  ++metric_worker_download_move_total;
+
+  CString dest_path;
+  HRESULT hr = BuildDestinationDirectory(&dest_path);
+  if (FAILED(hr)) {
+    OPT_LOG(LW, (_T("[Build destination directory failed][0x%08x]"), hr));
+    return hr;
+  }
+  CORE_LOG(L3, (_T("[Download Directory][%s]"), dest_path));
+  ASSERT1(!dest_path.IsEmpty());
+  ASSERT1(File::Exists(dest_path));
+
+  CString dst_file_name;
+  hr = GetFileNameFromDownloadUrl(job_->response_data().url(),
+                                  &dst_file_name);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[GetFileNameFromDownloadUrl failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (dst_file_name.IsEmpty()) {
+    ASSERT1(false);
+    return GOOPDATEDOWNLOAD_E_DEST_FILENAME_EMPTY;
+  }
+  CORE_LOG(L3, (_T("[Destination filename][%s]"), dst_file_name));
+
+  CString dest_file_path = ConcatenatePath(dest_path, dst_file_name);
+  if (dest_file_path.IsEmpty()) {
+    ASSERT1(false);
+    return GOOPDATEDOWNLOAD_E_DEST_FILE_PATH_EMPTY;
+  }
+
+  OPT_LOG(L1, (_T("[Moving download file from %s to %s]"),
+               local_download_file_path_, dest_file_path));
+  // Uses ::CopyFile. ::CopyFile, done without impersonation, will reset the
+  // ownership of the destination file, and make sure that it inherits ACEs from
+  // the new parent directory.
+  hr = File::Copy(local_download_file_path_, dest_file_path, true);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Could not copy '%s' to '%s'][0x%08x]"),
+                 local_download_file_path_, dest_file_path, hr));
+    job_->set_extra_code1(hr);
+    return GOOPDATEDOWNLOAD_E_FAILED_MOVE;
+  }
+  VERIFY1(SUCCEEDED(File::Remove(local_download_file_path_)));
+
+  local_download_file_path_ = dest_file_path;
+  job_->set_download_file_name(dest_file_path);
+
+  ++metric_worker_download_move_succeeded;
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/worker/download_manager.h b/worker/download_manager.h
index ef59675..c50e0b8 100644
--- a/worker/download_manager.h
+++ b/worker/download_manager.h
@@ -1,74 +1,74 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// Download manager supports downloading one file at a time.

-// The DownloadFile is a blocking call. All errors are reported through the

-// return value of this method. Progress is reported on the

-// NetworkRequestCallback callback that the job object implements.

-

-#ifndef OMAHA_WORKER_DOWNLOAD_MANAGER_H__

-#define OMAHA_WORKER_DOWNLOAD_MANAGER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "omaha/net/http_client.h"

-#include "base/scoped_ptr.h"

-#include "omaha/worker/job.h"

-

-namespace omaha {

-

-class Job;

-class NetworkRequest;

-

-class DownloadManager {

- public:

-  explicit DownloadManager(bool is_machine);

-  HRESULT DownloadFile(Job* job);

-  HRESULT Cancel();

-  CompletionInfo error_info() const { return error_info_; }

-

-  HANDLE impersonation_token() const { return impersonation_token_; }

-  void set_impersonation_token(HANDLE token) { impersonation_token_ = token; }

- private:

-  HRESULT GetFileNameFromDownloadUrl(const CString& url,

-                                     CString* file_name) const;

-  HRESULT BuildDestinationDirectory(CString* dest_path) const;

-  HRESULT BuildUniqueDownloadFilePath(CString* file) const;

-  HRESULT DownloadCurrentJob();

-  bool IsCached(const CString& store);

-  HRESULT ValidateDownloadedFile(const CString& file_name) const;

-  HRESULT MoveFile();

-  void SetErrorInfo(HRESULT hr);

-  void LogValidationFailure() const;

-

-  CString local_download_file_path_;

-  CompletionInfo error_info_;

-  Job* job_;

-  bool is_machine_;

-  scoped_ptr<NetworkRequest> network_request_;

-  HANDLE impersonation_token_;    // Token to impersonate with, if available.

-

-  // True if the code runs in the current interactive session. BITS only allows

-  // jobs to run when the owner is logged in. Local System is always logged on.

-  bool is_logged_on_;

-  scoped_ptr<HttpClient> http_client_;

-

-  friend class DownloadManagerTest;

-  DISALLOW_EVIL_CONSTRUCTORS(DownloadManager);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_DOWNLOAD_MANAGER_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// Download manager supports downloading one file at a time.
+// The DownloadFile is a blocking call. All errors are reported through the
+// return value of this method. Progress is reported on the
+// NetworkRequestCallback callback that the job object implements.
+
+#ifndef OMAHA_WORKER_DOWNLOAD_MANAGER_H__
+#define OMAHA_WORKER_DOWNLOAD_MANAGER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "omaha/net/http_client.h"
+#include "base/scoped_ptr.h"
+#include "omaha/worker/job.h"
+
+namespace omaha {
+
+class Job;
+class NetworkRequest;
+
+class DownloadManager {
+ public:
+  explicit DownloadManager(bool is_machine);
+  HRESULT DownloadFile(Job* job);
+  HRESULT Cancel();
+  CompletionInfo error_info() const { return error_info_; }
+
+  HANDLE impersonation_token() const { return impersonation_token_; }
+  void set_impersonation_token(HANDLE token) { impersonation_token_ = token; }
+ private:
+  HRESULT GetFileNameFromDownloadUrl(const CString& url,
+                                     CString* file_name) const;
+  HRESULT BuildDestinationDirectory(CString* dest_path) const;
+  HRESULT BuildUniqueDownloadFilePath(CString* file) const;
+  HRESULT DownloadCurrentJob();
+  bool IsCached(const CString& store);
+  HRESULT ValidateDownloadedFile(const CString& file_name) const;
+  HRESULT MoveFile();
+  void SetErrorInfo(HRESULT hr);
+  void LogValidationFailure() const;
+
+  CString local_download_file_path_;
+  CompletionInfo error_info_;
+  Job* job_;
+  bool is_machine_;
+  scoped_ptr<NetworkRequest> network_request_;
+  HANDLE impersonation_token_;    // Token to impersonate with, if available.
+
+  // True if the code runs in the current interactive session. BITS only allows
+  // jobs to run when the owner is logged in. Local System is always logged on.
+  bool is_logged_on_;
+  scoped_ptr<HttpClient> http_client_;
+
+  friend class DownloadManagerTest;
+  DISALLOW_EVIL_CONSTRUCTORS(DownloadManager);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_DOWNLOAD_MANAGER_H__
diff --git a/worker/download_manager_unittest.cc b/worker/download_manager_unittest.cc
index c4a3891..32eefd0 100644
--- a/worker/download_manager_unittest.cc
+++ b/worker/download_manager_unittest.cc
@@ -1,508 +1,508 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include <windows.h>

-#include <atlstr.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/scoped_ptr_cotask.h"

-#include "omaha/common/system.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/download_manager.h"

-#include "omaha/worker/job.h"

-#include "omaha/worker/ping.h"

-

-namespace omaha {

-

-namespace {

-

-// Hash = Igq6bYaeXFJCjH770knXyJ6V53s=, size = 479848

-const TCHAR kTestExeHash[] = _T("Igq6bYaeXFJCjH770knXyJ6V53s=");

-const int kTestExeSize = 479848;

-const TCHAR kWrongTestExeHash[] = _T("F006bYaeXFJCjH770knXyJ6V53s=");

-// Hash = ImV9skETZqGFMjs32vbZTvzAYJU=, size = 870400

-const TCHAR kTestMsiHash[] = _T("ImV9skETZqGFMjs32vbZTvzAYJU=");

-const int kTestMsiSize = 870400;

-

-}  // namespace

-

-class DownloadManagerTest : public testing::Test {

- protected:

-  static void SetUpTestCase() {

-    TCHAR module_path[MAX_PATH] = {0};

-    ASSERT_NE(0, ::GetModuleFileName(NULL, module_path, MAX_PATH));

-    CString path = GetDirectoryFromPath(module_path);

-

-    cache_test_dir_ =

-        ConcatenatePath(path, _T("unittest_support\\download_cache_test"));

-

-    CString expected_path_exe = (_T("{7101D597-3481-4971-AD23-455542964072}")

-                                 _T("\\livelysetup.exe"));

-    expected_file_name_exe_ =

-        ConcatenatePath(cache_test_dir_, expected_path_exe);

-

-    CString expected_path_msi = (_T("{89640431-FE64-4da8-9860-1A1085A60E13}")

-                                 _T("\\gears-win32-opt.msi"));

-    expected_file_name_msi_ =

-        ConcatenatePath(cache_test_dir_, expected_path_msi);

-  }

-

-  virtual void SetUp() {

-    job_.reset(CreateJob());

-  }

-

-  void Initialize(bool is_machine) {

-    download_manager_.reset(new DownloadManager(is_machine));

-  }

-

-  virtual void TearDown() {

-    download_manager_.reset();

-    job_.reset();

-  }

-

-  HRESULT BuildDestinationDirectory(CString* dir) {

-    return download_manager_->BuildDestinationDirectory(dir);

-  }

-

-  HRESULT BuildUniqueDownloadFilePath(CString* file) {

-    return download_manager_->BuildUniqueDownloadFilePath(file);

-  }

-

-  void SetJob(Job* job) {

-    download_manager_->job_ = job;

-  }

-

-  bool IsCached(const CString& path) {

-    return download_manager_->IsCached(path);

-  }

-

-  HRESULT GetFileNameFromDownloadUrl(const CString& url,

-                                     CString* out) {

-    return download_manager_->GetFileNameFromDownloadUrl(url, out);

-  }

-

-  HRESULT ValidateDownloadedFile(const CString& file_name) const {

-    return download_manager_->ValidateDownloadedFile(file_name);

-  }

-

-  void SetErrorInfo(HRESULT hr) {

-    download_manager_->SetErrorInfo(hr);

-  }

-

-  Job* CreateJob() {

-    Initialize(false);

-    UpdateResponseData response_data;

-    response_data.set_url(_T("http://dl.google.com/update2/UpdateData.bin"));

-    response_data.set_hash(_T("YF2z/br/S6E3KTca0MT7qziJN44="));

-    scoped_ptr<Job> job(new Job(true, &ping_));

-    job->set_is_background(true);

-    job->set_update_response_data(response_data);

-    return job.release();

-  }

-

-  Job* CreateJob(const UpdateResponseData& data) {

-    scoped_ptr<Job> job(new Job(true, &ping_));

-    job->set_is_background(true);

-    job->set_update_response_data(data);

-    return job.release();

-  }

-

-  void SetLocalDownloadFilepath(const CString download_file) {

-    download_manager_->local_download_file_path_ = download_file;

-  }

-

-  void VerifyCompletionInfo(JobCompletionStatus status,

-                            DWORD error_code,

-                            const CString& text) {

-    EXPECT_EQ(status, download_manager_->error_info().status);

-    EXPECT_EQ(error_code, download_manager_->error_info().error_code);

-    EXPECT_STREQ(text, download_manager_->error_info().text);

-  }

-

-  scoped_ptr<Job> job_;

-  scoped_ptr<DownloadManager> download_manager_;

-  Ping ping_;

-

-  static CString cache_test_dir_;

-  static CString expected_file_name_exe_;

-  static CString expected_file_name_msi_;

-};

-

-CString DownloadManagerTest::cache_test_dir_;

-CString DownloadManagerTest::expected_file_name_exe_;

-CString DownloadManagerTest::expected_file_name_msi_;

-

-// Download a file via an http: URL.

-TEST_F(DownloadManagerTest, DownloadViaHttp) {

-  Initialize(false);

-  scoped_ptr<Job> job1(CreateJob());

-  EXPECT_HRESULT_SUCCEEDED(job1->Download(download_manager_.get()));

-  EXPECT_TRUE(::DeleteFile(job1->download_file_name()));

-

-  scoped_ptr<Job> job2(CreateJob());

-  EXPECT_HRESULT_SUCCEEDED(job2->Download(download_manager_.get()));

-  EXPECT_TRUE(::DeleteFile(job2->download_file_name()));

-}

-

-TEST_F(DownloadManagerTest, BuildDestinationDirectory_User) {

-  Initialize(false);

-  CString path = ConfigManager::Instance()->GetUserDownloadStorageDir();

-

-  CString dir;

-  EXPECT_HRESULT_SUCCEEDED(BuildDestinationDirectory(&dir));

-

-  CString common_prefix;

-  int common_path_len = ::PathCommonPrefix(dir,

-                                           path,

-                                           CStrBuf(common_prefix, MAX_PATH));

-  EXPECT_EQ(path.GetLength(), common_path_len);

-  EXPECT_STREQ(common_prefix, path);

-

-  CString dir2;

-  EXPECT_HRESULT_SUCCEEDED(BuildDestinationDirectory(&dir2));

-  CString common_prefix2;

-  common_path_len = ::PathCommonPrefix(dir2,

-                                       path,

-                                       CStrBuf(common_prefix2, MAX_PATH));

-  EXPECT_EQ(path.GetLength(), common_path_len);

-  EXPECT_STREQ(common_prefix2, path);

-

-  EXPECT_STRNE(dir, dir2);

-}

-

-TEST_F(DownloadManagerTest, BuildUniqueDownloadFilePath_User) {

-  Initialize(false);

-

-  CString file;

-  EXPECT_HRESULT_SUCCEEDED(BuildUniqueDownloadFilePath(&file));

-  CString str_guid = GetFileFromPath(file);

-  EXPECT_TRUE(!str_guid.IsEmpty());

-  GUID guid = StringToGuid(str_guid);

-  EXPECT_TRUE(!::IsEqualGUID(guid, GUID_NULL));

-}

-

-TEST_F(DownloadManagerTest, BuildDestinationDirectory_Machine) {

-  if (!vista_util::IsUserAdmin()) {

-    return;

-  }

-

-  Initialize(true);

-  CString path =

-      ConfigManager::Instance()->GetMachineSecureDownloadStorageDir();

-

-  CString dir;

-  EXPECT_HRESULT_SUCCEEDED(BuildDestinationDirectory(&dir));

-

-  CString common_prefix;

-  int common_path_len = ::PathCommonPrefix(dir,

-                                           path,

-                                           CStrBuf(common_prefix, MAX_PATH));

-  EXPECT_EQ(path.GetLength(), common_path_len);

-  EXPECT_STREQ(common_prefix, path);

-

-  CString dir2;

-  EXPECT_HRESULT_SUCCEEDED(BuildDestinationDirectory(&dir2));

-  CString common_prefix2;

-  common_path_len = ::PathCommonPrefix(dir2,

-                                       path,

-                                       CStrBuf(common_prefix2, MAX_PATH));

-  EXPECT_EQ(path.GetLength(), common_path_len);

-  EXPECT_STREQ(common_prefix2, path);

-

-  EXPECT_STRNE(dir, dir2);

-}

-

-TEST_F(DownloadManagerTest, BuildUniqueDownloadFilePath_Machine) {

-  if (!vista_util::IsUserAdmin()) {

-    return;

-  }

-

-  Initialize(true);

-  CString file;

-  EXPECT_HRESULT_SUCCEEDED(BuildUniqueDownloadFilePath(&file));

-  CString str_guid = GetFileFromPath(file);

-  EXPECT_TRUE(!str_guid.IsEmpty());

-  GUID guid = StringToGuid(str_guid);

-  EXPECT_TRUE(!::IsEqualGUID(guid, GUID_NULL));

-}

-

-TEST_F(DownloadManagerTest, IsCached_TestExe) {

-  UpdateResponseData response_data;

-  response_data.set_url(_T("http://dl.google.com/livelysetup.exe"));

-  response_data.set_hash(kTestExeHash);

-  response_data.set_size(kTestExeSize);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-

-  EXPECT_TRUE(IsCached(cache_test_dir_));

-  EXPECT_STREQ(expected_file_name_exe_, job->download_file_name());

-}

-

-TEST_F(DownloadManagerTest, IsCached_TestMSI) {

-  UpdateResponseData response_data;

-  response_data.set_url(_T("http://dl.google.com/gears-win32-opt.msi"));

-  response_data.set_hash(kTestMsiHash);

-  response_data.set_size(kTestMsiSize);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-

-  EXPECT_TRUE(IsCached(cache_test_dir_));

-  EXPECT_STREQ(expected_file_name_msi_, job->download_file_name());

-}

-

-TEST_F(DownloadManagerTest, IsCached_FileNotPresent) {

-  UpdateResponseData response_data;

-  response_data.set_url(_T("dl.google.com/not_present.msi"));

-  response_data.set_hash(kTestMsiHash);

-  response_data.set_size(kTestMsiSize);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-

-  EXPECT_FALSE(IsCached(cache_test_dir_));

-  EXPECT_TRUE(job->download_file_name().IsEmpty());

-}

-

-TEST_F(DownloadManagerTest, IsCached_InvalidHash) {

-  UpdateResponseData response_data;

-  response_data.set_url(_T("http://dl.google.com/gears-win32-opt.msi"));

-  response_data.set_hash(_T("BAADBAADBAADMjs32vbZTvzAYJU="));

-  response_data.set_size(kTestMsiSize);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-

-  EXPECT_FALSE(IsCached(cache_test_dir_));

-  EXPECT_TRUE(job->download_file_name().IsEmpty());

-}

-

-TEST_F(DownloadManagerTest, IsCached_NotUpdateJob) {

-  scoped_ptr<Job> job(new Job(false, &ping_));

-  UpdateResponseData response_data;

-  response_data.set_url(_T("dl.google.com/livelysetup.exe"));

-  response_data.set_hash(kTestExeHash);

-  response_data.set_size(kTestExeSize);

-  job->set_update_response_data(response_data);

-  SetJob(job.get());

-

-  EXPECT_FALSE(IsCached(cache_test_dir_));

-  EXPECT_TRUE(job->download_file_name().IsEmpty());

-}

-

-TEST_F(DownloadManagerTest, ValidateDownloadedFile_Valid) {

-  UpdateResponseData response_data;

-  response_data.set_url(_T("dl.google.com/livelysetup.exe"));

-  response_data.set_hash(kTestExeHash);

-  response_data.set_size(kTestExeSize);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-  SetLocalDownloadFilepath(expected_file_name_exe_);

-

-  EXPECT_SUCCEEDED(ValidateDownloadedFile(expected_file_name_exe_));

-}

-

-TEST_F(DownloadManagerTest, ValidateDownloadedFile_HashFailsCorrectSize) {

-  UpdateResponseData response_data;

-  response_data.set_url(_T("dl.google.com/livelysetup.exe"));

-  response_data.set_hash(kWrongTestExeHash);

-  response_data.set_size(kTestExeSize);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-  SetLocalDownloadFilepath(expected_file_name_exe_);

-

-  EXPECT_EQ(SIGS_E_INVALID_SIGNATURE,

-            ValidateDownloadedFile(expected_file_name_exe_));

-}

-

-TEST_F(DownloadManagerTest, ValidateDownloadedFile_ValidHashSizeIncorrect) {

-  UpdateResponseData response_data;

-  response_data.set_url(_T("http://dl.google.com/livelysetup.exe"));

-  response_data.set_hash(kTestExeHash);

-  response_data.set_size(kTestExeSize + 10);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-

-  EXPECT_SUCCEEDED(ValidateDownloadedFile(expected_file_name_exe_));

-}

-

-TEST_F(DownloadManagerTest, ValidateDownloadedFile_HashFailsSizeZero) {

-  const TCHAR kEmtpyFileName[] = _T("emptyfile.txt");

-

-  UpdateResponseData response_data;

-  response_data.set_url(_T("http://dl.google.com/livelysetup.exe"));

-  response_data.set_hash(kWrongTestExeHash);

-  response_data.set_size(kTestExeSize);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-

-  EXPECT_SUCCEEDED(File::Remove(kEmtpyFileName));

-  File empty_file;

-  EXPECT_SUCCEEDED(empty_file.Open(kEmtpyFileName, true, false));

-  EXPECT_SUCCEEDED(empty_file.Close());

-

-  EXPECT_EQ(GOOPDATEDOWNLOAD_E_FILE_SIZE_ZERO,

-            ValidateDownloadedFile(kEmtpyFileName));

-

-  EXPECT_SUCCEEDED(File::Remove(kEmtpyFileName));

-}

-

-TEST_F(DownloadManagerTest, ValidateDownloadedFile_HashFailsSizeSmaller) {

-  UpdateResponseData response_data;

-  response_data.set_url(_T("http://dl.google.com/livelysetup.exe"));

-  response_data.set_hash(kWrongTestExeHash);

-  response_data.set_size(kTestExeSize + 1);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-

-  EXPECT_EQ(GOOPDATEDOWNLOAD_E_FILE_SIZE_SMALLER,

-            ValidateDownloadedFile(expected_file_name_exe_));

-}

-

-TEST_F(DownloadManagerTest, ValidateDownloadedFile_HashFailsSizeLarger) {

-  UpdateResponseData response_data;

-  response_data.set_url(_T("dl.google.com/livelysetup.exe"));

-  response_data.set_hash(kWrongTestExeHash);

-  response_data.set_size(kTestExeSize - 1);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-

-  EXPECT_EQ(GOOPDATEDOWNLOAD_E_FILE_SIZE_LARGER,

-            ValidateDownloadedFile(expected_file_name_exe_));

-}

-

-TEST_F(DownloadManagerTest, ValidateDownloadedFile_FileDoesNotExist) {

-  UpdateResponseData response_data;

-  response_data.set_url(_T("http://dl.google.com/livelysetup.exe"));

-  response_data.set_hash(kWrongTestExeHash);

-  response_data.set_size(kTestExeSize);

-  scoped_ptr<Job> job(CreateJob(response_data));

-  SetJob(job.get());

-

-  ExpectAsserts expect_asserts;

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            ValidateDownloadedFile(_T("nosuchfile.txt")));

-}

-

-TEST_F(DownloadManagerTest, GetFileNameFromDownloadUrl_QueryParams) {

-  SetJob(CreateJob());

-

-  CString url = _T("http://foo10.bar.google.com:26190/update2/test/machinefoo/test.msi?tttoken=1.DQAAA3_cykoeVgF7b8ZT1Ycsv_tfjbAofLplQp3xHrwOOJGZkb1ZakYVTIN0QMJvA5IlMzULa0AEP-JWYZVVKz-gQTD35u30pRAirXjKjsEC5KHKQKqBipa00ni8krbzYawfTKQKAAmlTan_eLHDOnH7NiHcrCLkLSE_5Un1S7p5_DegLgFGfUXffwHS6S-Z5LHCHdqUXCW&test=10&hello"); // NOLINT

-  CString file_name;

-  ASSERT_HRESULT_SUCCEEDED(GetFileNameFromDownloadUrl(url, &file_name));

-  ASSERT_STREQ(_T("test.msi"), file_name);

-}

-

-TEST_F(DownloadManagerTest, GetFileNameFromDownloadUrl_NoQueryParams) {

-  SetJob(CreateJob());

-

-  CString url = _T("http://foo10.google.com:26190/test/machinefoo/test.msi");

-  CString file_name;

-  ASSERT_HRESULT_SUCCEEDED(GetFileNameFromDownloadUrl(url, &file_name));

-  ASSERT_STREQ(_T("test.msi"), file_name);

-

-  url = _T("http://dl.google.com/update2/1.2.121.9/GoogleUpdateSetup.exe");

-  ASSERT_HRESULT_SUCCEEDED(GetFileNameFromDownloadUrl(url, &file_name));

-  ASSERT_STREQ(_T("GoogleUpdateSetup.exe"), file_name);

-

-  url = _T("http://dl.google.com/foo/plugin/4.3.9543.7852/foo-plugin-win.exe");

-  ASSERT_HRESULT_SUCCEEDED(GetFileNameFromDownloadUrl(url, &file_name));

-  ASSERT_STREQ(_T("foo-plugin-win.exe"), file_name);

-}

-

-TEST_F(DownloadManagerTest, GetFileNameFromDownloadUrl_WithOutPath) {

-  SetJob(CreateJob());

-

-  CString url = _T("http://foo10.bar.google.com:26190/test.exe");

-  CString file_name;

-  ASSERT_HRESULT_SUCCEEDED(GetFileNameFromDownloadUrl(url, &file_name));

-  ASSERT_STREQ(_T("test.exe"), file_name);

-}

-

-TEST_F(DownloadManagerTest, GetFileNameFromDownloadUrl_InvalidPaths) {

-  SetJob(CreateJob());

-

-  CString url = _T("http://foo10.bar.google.com:26190/test/");

-  CString file_name;

-  EXPECT_HRESULT_FAILED(GetFileNameFromDownloadUrl(url, &file_name));

-

-  url = _T("http://foo10.bar.google.com:26190/test/?");

-  EXPECT_EQ(GOOPDATEDOWNLOAD_E_FILE_NAME_EMPTY,

-            GetFileNameFromDownloadUrl(url, &file_name));

-

-  url = _T("foo10.bar.google.com:26190test");

-  EXPECT_HRESULT_FAILED(GetFileNameFromDownloadUrl(url, &file_name));

-}

-

-

-TEST_F(DownloadManagerTest, SetErrorInfo) {

-  AppData app_data;

-  app_data.set_display_name(_T("Test App"));

-  Job job(false, &ping_);

-  job.set_app_data(app_data);

-  SetJob(&job);

-

-  SetErrorInfo(GOOPDATE_E_NO_NETWORK);

-  VerifyCompletionInfo(

-      COMPLETION_ERROR,

-      static_cast<DWORD>(GOOPDATE_E_NO_NETWORK),

-      _T("Installation failed. Ensure that your computer is connected to the ")

-      _T("Internet and that your firewall allows GoogleUpdate.exe to connect ")

-      _T("and then try again. Error code = 0x80040801."));

-

-  SetErrorInfo(GOOPDATE_E_NETWORK_UNAUTHORIZED);

-  VerifyCompletionInfo(

-      COMPLETION_ERROR,

-      static_cast<DWORD>(GOOPDATE_E_NETWORK_UNAUTHORIZED),

-      _T("The Test App installer could not connect to the Internet because of ")

-      _T("an HTTP 401 Unauthorized response. This is likely a proxy ")

-      _T("configuration issue.  Please configure the proxy server to allow ")

-      _T("network access and try again or contact your network administrator. ")

-      _T("Error code = 0x80042191"));

-

-  SetErrorInfo(GOOPDATE_E_NETWORK_FORBIDDEN);

-  VerifyCompletionInfo(

-      COMPLETION_ERROR,

-      static_cast<DWORD>(GOOPDATE_E_NETWORK_FORBIDDEN),

-      _T("The Test App installer could not connect to the Internet because of ")

-      _T("an HTTP 403 Forbidden response. This is likely a proxy ")

-      _T("configuration issue.  Please configure the proxy server to allow ")

-      _T("network access and try again or contact your network administrator. ")

-      _T("Error code = 0x80042193"));

-

-  SetErrorInfo(GOOPDATE_E_NETWORK_PROXYAUTHREQUIRED);

-  VerifyCompletionInfo(

-      COMPLETION_ERROR,

-      static_cast<DWORD>(GOOPDATE_E_NETWORK_PROXYAUTHREQUIRED),

-      _T("The Test App installer could not connect to the Internet because a ")

-      _T("proxy server required user authentication. Please configure the ")

-      _T("proxy server to allow network access and try again or contact your ")

-      _T("network administrator. Error code = 0x80042197"));

-

-  SetErrorInfo(E_FAIL);

-  VerifyCompletionInfo(

-      COMPLETION_ERROR,

-      static_cast<DWORD>(E_FAIL),

-      _T("Installer download failed. Error code = 0x80004005"));

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include <windows.h>
+#include <atlstr.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/scoped_ptr_cotask.h"
+#include "omaha/common/system.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/download_manager.h"
+#include "omaha/worker/job.h"
+#include "omaha/worker/ping.h"
+
+namespace omaha {
+
+namespace {
+
+// Hash = Igq6bYaeXFJCjH770knXyJ6V53s=, size = 479848
+const TCHAR kTestExeHash[] = _T("Igq6bYaeXFJCjH770knXyJ6V53s=");
+const int kTestExeSize = 479848;
+const TCHAR kWrongTestExeHash[] = _T("F006bYaeXFJCjH770knXyJ6V53s=");
+// Hash = ImV9skETZqGFMjs32vbZTvzAYJU=, size = 870400
+const TCHAR kTestMsiHash[] = _T("ImV9skETZqGFMjs32vbZTvzAYJU=");
+const int kTestMsiSize = 870400;
+
+}  // namespace
+
+class DownloadManagerTest : public testing::Test {
+ protected:
+  static void SetUpTestCase() {
+    TCHAR module_path[MAX_PATH] = {0};
+    ASSERT_NE(0, ::GetModuleFileName(NULL, module_path, MAX_PATH));
+    CString path = GetDirectoryFromPath(module_path);
+
+    cache_test_dir_ =
+        ConcatenatePath(path, _T("unittest_support\\download_cache_test"));
+
+    CString expected_path_exe = (_T("{7101D597-3481-4971-AD23-455542964072}")
+                                 _T("\\livelysetup.exe"));
+    expected_file_name_exe_ =
+        ConcatenatePath(cache_test_dir_, expected_path_exe);
+
+    CString expected_path_msi = (_T("{89640431-FE64-4da8-9860-1A1085A60E13}")
+                                 _T("\\gears-win32-opt.msi"));
+    expected_file_name_msi_ =
+        ConcatenatePath(cache_test_dir_, expected_path_msi);
+  }
+
+  virtual void SetUp() {
+    job_.reset(CreateJob());
+  }
+
+  void Initialize(bool is_machine) {
+    download_manager_.reset(new DownloadManager(is_machine));
+  }
+
+  virtual void TearDown() {
+    download_manager_.reset();
+    job_.reset();
+  }
+
+  HRESULT BuildDestinationDirectory(CString* dir) {
+    return download_manager_->BuildDestinationDirectory(dir);
+  }
+
+  HRESULT BuildUniqueDownloadFilePath(CString* file) {
+    return download_manager_->BuildUniqueDownloadFilePath(file);
+  }
+
+  void SetJob(Job* job) {
+    download_manager_->job_ = job;
+  }
+
+  bool IsCached(const CString& path) {
+    return download_manager_->IsCached(path);
+  }
+
+  HRESULT GetFileNameFromDownloadUrl(const CString& url,
+                                     CString* out) {
+    return download_manager_->GetFileNameFromDownloadUrl(url, out);
+  }
+
+  HRESULT ValidateDownloadedFile(const CString& file_name) const {
+    return download_manager_->ValidateDownloadedFile(file_name);
+  }
+
+  void SetErrorInfo(HRESULT hr) {
+    download_manager_->SetErrorInfo(hr);
+  }
+
+  Job* CreateJob() {
+    Initialize(false);
+    UpdateResponseData response_data;
+    response_data.set_url(_T("http://dl.google.com/update2/UpdateData.bin"));
+    response_data.set_hash(_T("YF2z/br/S6E3KTca0MT7qziJN44="));
+    scoped_ptr<Job> job(new Job(true, &ping_));
+    job->set_is_background(true);
+    job->set_update_response_data(response_data);
+    return job.release();
+  }
+
+  Job* CreateJob(const UpdateResponseData& data) {
+    scoped_ptr<Job> job(new Job(true, &ping_));
+    job->set_is_background(true);
+    job->set_update_response_data(data);
+    return job.release();
+  }
+
+  void SetLocalDownloadFilepath(const CString download_file) {
+    download_manager_->local_download_file_path_ = download_file;
+  }
+
+  void VerifyCompletionInfo(JobCompletionStatus status,
+                            DWORD error_code,
+                            const CString& text) {
+    EXPECT_EQ(status, download_manager_->error_info().status);
+    EXPECT_EQ(error_code, download_manager_->error_info().error_code);
+    EXPECT_STREQ(text, download_manager_->error_info().text);
+  }
+
+  scoped_ptr<Job> job_;
+  scoped_ptr<DownloadManager> download_manager_;
+  Ping ping_;
+
+  static CString cache_test_dir_;
+  static CString expected_file_name_exe_;
+  static CString expected_file_name_msi_;
+};
+
+CString DownloadManagerTest::cache_test_dir_;
+CString DownloadManagerTest::expected_file_name_exe_;
+CString DownloadManagerTest::expected_file_name_msi_;
+
+// Download a file via an http: URL.
+TEST_F(DownloadManagerTest, DownloadViaHttp) {
+  Initialize(false);
+  scoped_ptr<Job> job1(CreateJob());
+  EXPECT_HRESULT_SUCCEEDED(job1->Download(download_manager_.get()));
+  EXPECT_TRUE(::DeleteFile(job1->download_file_name()));
+
+  scoped_ptr<Job> job2(CreateJob());
+  EXPECT_HRESULT_SUCCEEDED(job2->Download(download_manager_.get()));
+  EXPECT_TRUE(::DeleteFile(job2->download_file_name()));
+}
+
+TEST_F(DownloadManagerTest, BuildDestinationDirectory_User) {
+  Initialize(false);
+  CString path = ConfigManager::Instance()->GetUserDownloadStorageDir();
+
+  CString dir;
+  EXPECT_HRESULT_SUCCEEDED(BuildDestinationDirectory(&dir));
+
+  CString common_prefix;
+  int common_path_len = ::PathCommonPrefix(dir,
+                                           path,
+                                           CStrBuf(common_prefix, MAX_PATH));
+  EXPECT_EQ(path.GetLength(), common_path_len);
+  EXPECT_STREQ(common_prefix, path);
+
+  CString dir2;
+  EXPECT_HRESULT_SUCCEEDED(BuildDestinationDirectory(&dir2));
+  CString common_prefix2;
+  common_path_len = ::PathCommonPrefix(dir2,
+                                       path,
+                                       CStrBuf(common_prefix2, MAX_PATH));
+  EXPECT_EQ(path.GetLength(), common_path_len);
+  EXPECT_STREQ(common_prefix2, path);
+
+  EXPECT_STRNE(dir, dir2);
+}
+
+TEST_F(DownloadManagerTest, BuildUniqueDownloadFilePath_User) {
+  Initialize(false);
+
+  CString file;
+  EXPECT_HRESULT_SUCCEEDED(BuildUniqueDownloadFilePath(&file));
+  CString str_guid = GetFileFromPath(file);
+  EXPECT_TRUE(!str_guid.IsEmpty());
+  GUID guid = StringToGuid(str_guid);
+  EXPECT_TRUE(!::IsEqualGUID(guid, GUID_NULL));
+}
+
+TEST_F(DownloadManagerTest, BuildDestinationDirectory_Machine) {
+  if (!vista_util::IsUserAdmin()) {
+    return;
+  }
+
+  Initialize(true);
+  CString path =
+      ConfigManager::Instance()->GetMachineSecureDownloadStorageDir();
+
+  CString dir;
+  EXPECT_HRESULT_SUCCEEDED(BuildDestinationDirectory(&dir));
+
+  CString common_prefix;
+  int common_path_len = ::PathCommonPrefix(dir,
+                                           path,
+                                           CStrBuf(common_prefix, MAX_PATH));
+  EXPECT_EQ(path.GetLength(), common_path_len);
+  EXPECT_STREQ(common_prefix, path);
+
+  CString dir2;
+  EXPECT_HRESULT_SUCCEEDED(BuildDestinationDirectory(&dir2));
+  CString common_prefix2;
+  common_path_len = ::PathCommonPrefix(dir2,
+                                       path,
+                                       CStrBuf(common_prefix2, MAX_PATH));
+  EXPECT_EQ(path.GetLength(), common_path_len);
+  EXPECT_STREQ(common_prefix2, path);
+
+  EXPECT_STRNE(dir, dir2);
+}
+
+TEST_F(DownloadManagerTest, BuildUniqueDownloadFilePath_Machine) {
+  if (!vista_util::IsUserAdmin()) {
+    return;
+  }
+
+  Initialize(true);
+  CString file;
+  EXPECT_HRESULT_SUCCEEDED(BuildUniqueDownloadFilePath(&file));
+  CString str_guid = GetFileFromPath(file);
+  EXPECT_TRUE(!str_guid.IsEmpty());
+  GUID guid = StringToGuid(str_guid);
+  EXPECT_TRUE(!::IsEqualGUID(guid, GUID_NULL));
+}
+
+TEST_F(DownloadManagerTest, IsCached_TestExe) {
+  UpdateResponseData response_data;
+  response_data.set_url(_T("http://dl.google.com/livelysetup.exe"));
+  response_data.set_hash(kTestExeHash);
+  response_data.set_size(kTestExeSize);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+
+  EXPECT_TRUE(IsCached(cache_test_dir_));
+  EXPECT_STREQ(expected_file_name_exe_, job->download_file_name());
+}
+
+TEST_F(DownloadManagerTest, IsCached_TestMSI) {
+  UpdateResponseData response_data;
+  response_data.set_url(_T("http://dl.google.com/gears-win32-opt.msi"));
+  response_data.set_hash(kTestMsiHash);
+  response_data.set_size(kTestMsiSize);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+
+  EXPECT_TRUE(IsCached(cache_test_dir_));
+  EXPECT_STREQ(expected_file_name_msi_, job->download_file_name());
+}
+
+TEST_F(DownloadManagerTest, IsCached_FileNotPresent) {
+  UpdateResponseData response_data;
+  response_data.set_url(_T("dl.google.com/not_present.msi"));
+  response_data.set_hash(kTestMsiHash);
+  response_data.set_size(kTestMsiSize);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+
+  EXPECT_FALSE(IsCached(cache_test_dir_));
+  EXPECT_TRUE(job->download_file_name().IsEmpty());
+}
+
+TEST_F(DownloadManagerTest, IsCached_InvalidHash) {
+  UpdateResponseData response_data;
+  response_data.set_url(_T("http://dl.google.com/gears-win32-opt.msi"));
+  response_data.set_hash(_T("BAADBAADBAADMjs32vbZTvzAYJU="));
+  response_data.set_size(kTestMsiSize);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+
+  EXPECT_FALSE(IsCached(cache_test_dir_));
+  EXPECT_TRUE(job->download_file_name().IsEmpty());
+}
+
+TEST_F(DownloadManagerTest, IsCached_NotUpdateJob) {
+  scoped_ptr<Job> job(new Job(false, &ping_));
+  UpdateResponseData response_data;
+  response_data.set_url(_T("dl.google.com/livelysetup.exe"));
+  response_data.set_hash(kTestExeHash);
+  response_data.set_size(kTestExeSize);
+  job->set_update_response_data(response_data);
+  SetJob(job.get());
+
+  EXPECT_FALSE(IsCached(cache_test_dir_));
+  EXPECT_TRUE(job->download_file_name().IsEmpty());
+}
+
+TEST_F(DownloadManagerTest, ValidateDownloadedFile_Valid) {
+  UpdateResponseData response_data;
+  response_data.set_url(_T("dl.google.com/livelysetup.exe"));
+  response_data.set_hash(kTestExeHash);
+  response_data.set_size(kTestExeSize);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+  SetLocalDownloadFilepath(expected_file_name_exe_);
+
+  EXPECT_SUCCEEDED(ValidateDownloadedFile(expected_file_name_exe_));
+}
+
+TEST_F(DownloadManagerTest, ValidateDownloadedFile_HashFailsCorrectSize) {
+  UpdateResponseData response_data;
+  response_data.set_url(_T("dl.google.com/livelysetup.exe"));
+  response_data.set_hash(kWrongTestExeHash);
+  response_data.set_size(kTestExeSize);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+  SetLocalDownloadFilepath(expected_file_name_exe_);
+
+  EXPECT_EQ(SIGS_E_INVALID_SIGNATURE,
+            ValidateDownloadedFile(expected_file_name_exe_));
+}
+
+TEST_F(DownloadManagerTest, ValidateDownloadedFile_ValidHashSizeIncorrect) {
+  UpdateResponseData response_data;
+  response_data.set_url(_T("http://dl.google.com/livelysetup.exe"));
+  response_data.set_hash(kTestExeHash);
+  response_data.set_size(kTestExeSize + 10);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+
+  EXPECT_SUCCEEDED(ValidateDownloadedFile(expected_file_name_exe_));
+}
+
+TEST_F(DownloadManagerTest, ValidateDownloadedFile_HashFailsSizeZero) {
+  const TCHAR kEmtpyFileName[] = _T("emptyfile.txt");
+
+  UpdateResponseData response_data;
+  response_data.set_url(_T("http://dl.google.com/livelysetup.exe"));
+  response_data.set_hash(kWrongTestExeHash);
+  response_data.set_size(kTestExeSize);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+
+  EXPECT_SUCCEEDED(File::Remove(kEmtpyFileName));
+  File empty_file;
+  EXPECT_SUCCEEDED(empty_file.Open(kEmtpyFileName, true, false));
+  EXPECT_SUCCEEDED(empty_file.Close());
+
+  EXPECT_EQ(GOOPDATEDOWNLOAD_E_FILE_SIZE_ZERO,
+            ValidateDownloadedFile(kEmtpyFileName));
+
+  EXPECT_SUCCEEDED(File::Remove(kEmtpyFileName));
+}
+
+TEST_F(DownloadManagerTest, ValidateDownloadedFile_HashFailsSizeSmaller) {
+  UpdateResponseData response_data;
+  response_data.set_url(_T("http://dl.google.com/livelysetup.exe"));
+  response_data.set_hash(kWrongTestExeHash);
+  response_data.set_size(kTestExeSize + 1);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+
+  EXPECT_EQ(GOOPDATEDOWNLOAD_E_FILE_SIZE_SMALLER,
+            ValidateDownloadedFile(expected_file_name_exe_));
+}
+
+TEST_F(DownloadManagerTest, ValidateDownloadedFile_HashFailsSizeLarger) {
+  UpdateResponseData response_data;
+  response_data.set_url(_T("dl.google.com/livelysetup.exe"));
+  response_data.set_hash(kWrongTestExeHash);
+  response_data.set_size(kTestExeSize - 1);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+
+  EXPECT_EQ(GOOPDATEDOWNLOAD_E_FILE_SIZE_LARGER,
+            ValidateDownloadedFile(expected_file_name_exe_));
+}
+
+TEST_F(DownloadManagerTest, ValidateDownloadedFile_FileDoesNotExist) {
+  UpdateResponseData response_data;
+  response_data.set_url(_T("http://dl.google.com/livelysetup.exe"));
+  response_data.set_hash(kWrongTestExeHash);
+  response_data.set_size(kTestExeSize);
+  scoped_ptr<Job> job(CreateJob(response_data));
+  SetJob(job.get());
+
+  ExpectAsserts expect_asserts;
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            ValidateDownloadedFile(_T("nosuchfile.txt")));
+}
+
+TEST_F(DownloadManagerTest, GetFileNameFromDownloadUrl_QueryParams) {
+  SetJob(CreateJob());
+
+  CString url = _T("http://foo10.bar.google.com:26190/update2/test/machinefoo/test.msi?tttoken=1.DQAAA3_cykoeVgF7b8ZT1Ycsv_tfjbAofLplQp3xHrwOOJGZkb1ZakYVTIN0QMJvA5IlMzULa0AEP-JWYZVVKz-gQTD35u30pRAirXjKjsEC5KHKQKqBipa00ni8krbzYawfTKQKAAmlTan_eLHDOnH7NiHcrCLkLSE_5Un1S7p5_DegLgFGfUXffwHS6S-Z5LHCHdqUXCW&test=10&hello"); // NOLINT
+  CString file_name;
+  ASSERT_HRESULT_SUCCEEDED(GetFileNameFromDownloadUrl(url, &file_name));
+  ASSERT_STREQ(_T("test.msi"), file_name);
+}
+
+TEST_F(DownloadManagerTest, GetFileNameFromDownloadUrl_NoQueryParams) {
+  SetJob(CreateJob());
+
+  CString url = _T("http://foo10.google.com:26190/test/machinefoo/test.msi");
+  CString file_name;
+  ASSERT_HRESULT_SUCCEEDED(GetFileNameFromDownloadUrl(url, &file_name));
+  ASSERT_STREQ(_T("test.msi"), file_name);
+
+  url = _T("http://dl.google.com/update2/1.2.121.9/GoogleUpdateSetup.exe");
+  ASSERT_HRESULT_SUCCEEDED(GetFileNameFromDownloadUrl(url, &file_name));
+  ASSERT_STREQ(_T("GoogleUpdateSetup.exe"), file_name);
+
+  url = _T("http://dl.google.com/foo/plugin/4.3.9543.7852/foo-plugin-win.exe");
+  ASSERT_HRESULT_SUCCEEDED(GetFileNameFromDownloadUrl(url, &file_name));
+  ASSERT_STREQ(_T("foo-plugin-win.exe"), file_name);
+}
+
+TEST_F(DownloadManagerTest, GetFileNameFromDownloadUrl_WithOutPath) {
+  SetJob(CreateJob());
+
+  CString url = _T("http://foo10.bar.google.com:26190/test.exe");
+  CString file_name;
+  ASSERT_HRESULT_SUCCEEDED(GetFileNameFromDownloadUrl(url, &file_name));
+  ASSERT_STREQ(_T("test.exe"), file_name);
+}
+
+TEST_F(DownloadManagerTest, GetFileNameFromDownloadUrl_InvalidPaths) {
+  SetJob(CreateJob());
+
+  CString url = _T("http://foo10.bar.google.com:26190/test/");
+  CString file_name;
+  EXPECT_HRESULT_FAILED(GetFileNameFromDownloadUrl(url, &file_name));
+
+  url = _T("http://foo10.bar.google.com:26190/test/?");
+  EXPECT_EQ(GOOPDATEDOWNLOAD_E_FILE_NAME_EMPTY,
+            GetFileNameFromDownloadUrl(url, &file_name));
+
+  url = _T("foo10.bar.google.com:26190test");
+  EXPECT_HRESULT_FAILED(GetFileNameFromDownloadUrl(url, &file_name));
+}
+
+
+TEST_F(DownloadManagerTest, SetErrorInfo) {
+  AppData app_data;
+  app_data.set_display_name(_T("Test App"));
+  Job job(false, &ping_);
+  job.set_app_data(app_data);
+  SetJob(&job);
+
+  SetErrorInfo(GOOPDATE_E_NO_NETWORK);
+  VerifyCompletionInfo(
+      COMPLETION_ERROR,
+      static_cast<DWORD>(GOOPDATE_E_NO_NETWORK),
+      _T("Installation failed. Ensure that your computer is connected to the ")
+      _T("Internet and that your firewall allows GoogleUpdate.exe to connect ")
+      _T("and then try again. Error code = 0x80040801."));
+
+  SetErrorInfo(GOOPDATE_E_NETWORK_UNAUTHORIZED);
+  VerifyCompletionInfo(
+      COMPLETION_ERROR,
+      static_cast<DWORD>(GOOPDATE_E_NETWORK_UNAUTHORIZED),
+      _T("The Test App installer could not connect to the Internet because of ")
+      _T("an HTTP 401 Unauthorized response. This is likely a proxy ")
+      _T("configuration issue.  Please configure the proxy server to allow ")
+      _T("network access and try again or contact your network administrator. ")
+      _T("Error code = 0x80042191"));
+
+  SetErrorInfo(GOOPDATE_E_NETWORK_FORBIDDEN);
+  VerifyCompletionInfo(
+      COMPLETION_ERROR,
+      static_cast<DWORD>(GOOPDATE_E_NETWORK_FORBIDDEN),
+      _T("The Test App installer could not connect to the Internet because of ")
+      _T("an HTTP 403 Forbidden response. This is likely a proxy ")
+      _T("configuration issue.  Please configure the proxy server to allow ")
+      _T("network access and try again or contact your network administrator. ")
+      _T("Error code = 0x80042193"));
+
+  SetErrorInfo(GOOPDATE_E_NETWORK_PROXYAUTHREQUIRED);
+  VerifyCompletionInfo(
+      COMPLETION_ERROR,
+      static_cast<DWORD>(GOOPDATE_E_NETWORK_PROXYAUTHREQUIRED),
+      _T("The Test App installer could not connect to the Internet because a ")
+      _T("proxy server required user authentication. Please configure the ")
+      _T("proxy server to allow network access and try again or contact your ")
+      _T("network administrator. Error code = 0x80042197"));
+
+  SetErrorInfo(E_FAIL);
+  VerifyCompletionInfo(
+      COMPLETION_ERROR,
+      static_cast<DWORD>(E_FAIL),
+      _T("Installer download failed. Error code = 0x80004005"));
+}
+
+}  // namespace omaha
+
diff --git a/worker/i_job_observer_mock.h b/worker/i_job_observer_mock.h
index 8c4dab7..0c9a180 100644
--- a/worker/i_job_observer_mock.h
+++ b/worker/i_job_observer_mock.h
@@ -1,103 +1,103 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_WORKER_I_JOB_OBSERVER_MOCK_H_

-#define OMAHA_WORKER_I_JOB_OBSERVER_MOCK_H_

-

-#pragma once

-#include <windows.h>

-#include <atlbase.h>

-#include <atlcom.h>

-#include "goopdate\google_update_idl.h"  // NOLINT

-#include "omaha/worker/job_observer_mock.h"

-

-namespace omaha {

-

-// A basic implementation of the IJobObserver interface for use by unit tests.

-// Wraps JobObserverMock.

-class IJobObserverMock

-  : public CComObjectRootEx<CComSingleThreadModel>,

-    public IJobObserver {

- public:

-  BEGIN_COM_MAP(IJobObserverMock)

-    COM_INTERFACE_ENTRY(IJobObserver)

-  END_COM_MAP()

-

-  virtual ~IJobObserverMock() {

-  }

-

-  // IJobObserver implementation.

-  STDMETHOD(OnShow)() {

-    job_observer_mock.OnShow();

-    return S_OK;

-  }

-

-  STDMETHOD(OnCheckingForUpdate)() {

-    job_observer_mock.OnCheckingForUpdate();

-    return S_OK;

-  }

-

-  STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {

-    UNREFERENCED_PARAMETER(version_string);

-    return S_OK;

-  }

-

-  STDMETHOD(OnWaitingToDownload)() {

-    job_observer_mock.OnWaitingToDownload();

-    return S_OK;

-  }

-

-  STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {

-    job_observer_mock.OnDownloading(time_remaining_ms, pos);

-    return S_OK;

-  }

-

-  STDMETHOD(OnWaitingToInstall)() {

-    job_observer_mock.OnWaitingToInstall();

-    return S_OK;

-  }

-

-  STDMETHOD(OnInstalling)() {

-    job_observer_mock.OnInstalling();

-    return S_OK;

-  }

-

-  STDMETHOD(OnPause)() {

-    job_observer_mock.OnPause();

-    return S_OK;

-  }

-

-  // The COM API does not have an error_code parameter. Pass unexpected error.

-  STDMETHOD(OnComplete)(CompletionCodes code, const TCHAR* text) {

-    job_observer_mock.OnComplete(code, text, static_cast<DWORD>(E_UNEXPECTED));

-    ::PostThreadMessage(::GetCurrentThreadId(), WM_QUIT, 0, 0);

-    return S_OK;

-  }

-

-  // JobObserverMock uses a different sink type, so cannot pass event_sink.

-  // For now, there are not tests that need the sink, so do nothing.

-  STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {

-    UNREFERENCED_PARAMETER(event_sink);

-    return S_OK;

-  }

-

-  // Stores data about events that tests can check.

-  JobObserverMock job_observer_mock;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_I_JOB_OBSERVER_MOCK_H_

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_WORKER_I_JOB_OBSERVER_MOCK_H_
+#define OMAHA_WORKER_I_JOB_OBSERVER_MOCK_H_
+
+#pragma once
+#include <windows.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include "goopdate\google_update_idl.h"  // NOLINT
+#include "omaha/worker/job_observer_mock.h"
+
+namespace omaha {
+
+// A basic implementation of the IJobObserver interface for use by unit tests.
+// Wraps JobObserverMock.
+class IJobObserverMock
+  : public CComObjectRootEx<CComSingleThreadModel>,
+    public IJobObserver {
+ public:
+  BEGIN_COM_MAP(IJobObserverMock)
+    COM_INTERFACE_ENTRY(IJobObserver)
+  END_COM_MAP()
+
+  virtual ~IJobObserverMock() {
+  }
+
+  // IJobObserver implementation.
+  STDMETHOD(OnShow)() {
+    job_observer_mock.OnShow();
+    return S_OK;
+  }
+
+  STDMETHOD(OnCheckingForUpdate)() {
+    job_observer_mock.OnCheckingForUpdate();
+    return S_OK;
+  }
+
+  STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
+    UNREFERENCED_PARAMETER(version_string);
+    return S_OK;
+  }
+
+  STDMETHOD(OnWaitingToDownload)() {
+    job_observer_mock.OnWaitingToDownload();
+    return S_OK;
+  }
+
+  STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
+    job_observer_mock.OnDownloading(time_remaining_ms, pos);
+    return S_OK;
+  }
+
+  STDMETHOD(OnWaitingToInstall)() {
+    job_observer_mock.OnWaitingToInstall();
+    return S_OK;
+  }
+
+  STDMETHOD(OnInstalling)() {
+    job_observer_mock.OnInstalling();
+    return S_OK;
+  }
+
+  STDMETHOD(OnPause)() {
+    job_observer_mock.OnPause();
+    return S_OK;
+  }
+
+  // The COM API does not have an error_code parameter. Pass unexpected error.
+  STDMETHOD(OnComplete)(CompletionCodes code, const TCHAR* text) {
+    job_observer_mock.OnComplete(code, text, static_cast<DWORD>(E_UNEXPECTED));
+    ::PostThreadMessage(::GetCurrentThreadId(), WM_QUIT, 0, 0);
+    return S_OK;
+  }
+
+  // JobObserverMock uses a different sink type, so cannot pass event_sink.
+  // For now, there are not tests that need the sink, so do nothing.
+  STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {
+    UNREFERENCED_PARAMETER(event_sink);
+    return S_OK;
+  }
+
+  // Stores data about events that tests can check.
+  JobObserverMock job_observer_mock;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_I_JOB_OBSERVER_MOCK_H_
diff --git a/worker/install_manager.cc b/worker/install_manager.cc
index 893e89e..fd10c46 100644
--- a/worker/install_manager.cc
+++ b/worker/install_manager.cc
@@ -1,843 +1,843 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/worker/install_manager.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/process.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource.h"

-#include "omaha/worker/job.h"

-#include "omaha/worker/worker_metrics.h"

-

-namespace omaha {

-

-bool GetMessageForSystemErrorCode(DWORD system_error_code, CString* message);

-

-namespace {

-

-// This is the base retry delay between retries when msiexec returns

-// ERROR_INSTALL_ALREADY_RUNNING. We exponentially backoff from this value.

-// Note that there is an additional delay for the MSI call, so the tries may

-// be a few seconds further apart.

-int kMsiAlreadyRunningRetryDelayBaseMs = 5000;

-// Number of retries. Updates are silent so we can wait longer.

-int kNumMsiAlreadyRunningInteractiveMaxTries = 4;  // Up to 35 seconds.

-int kNumMsiAlreadyRunningSilentMaxTries      = 7;  // Up to 6.25 minutes.

-

-// Interval to wait for installer completion.

-const int kInstallManagerCompleteIntervalMs = 15 * 60 * 1000;

-

-// Gets the installer exit code.

-HRESULT GetInstallerExitCode(const Process& p, uint32* exit_code) {

-  ASSERT1(exit_code);

-

-  if (p.Running()) {

-    ASSERT(false,

-           (_T("GetInstallerExitCode called while the process is running.")));

-    return GOOPDATEINSTALL_E_INSTALLER_INTERNAL_ERROR;

-  }

-

-  if (!p.GetExitCode(exit_code)) {

-    ASSERT(false,

-           (_T("[Failed to get the installer exit code for some reason.]")));

-    return GOOPDATEINSTALL_E_INSTALLER_INTERNAL_ERROR;

-  }

-

-  CORE_LOG(L2, (_T("[Installer exit code][%u]"), *exit_code));

-

-  return S_OK;

-}

-

-// Obtains the localized text for Omaha errors that may occur in the

-// DoInstallation path.

-void GetOmahaErrorTextToReport(HRESULT omaha_hr,

-                               const CString& installer_filename,

-                               const CString& app_name,

-                               CString* error_text) {

-  ASSERT1(error_text);

-

-  switch (omaha_hr) {

-    case GOOPDATEINSTALL_E_FILENAME_INVALID:

-      error_text->FormatMessage(IDS_INVALID_INSTALLER_FILENAME,

-                                installer_filename);

-      break;

-    case GOOPDATEINSTALL_E_INSTALLER_FAILED_START:

-      error_text->FormatMessage(IDS_INSTALLER_FAILED_TO_START);

-      break;

-    case GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT:

-      error_text->FormatMessage(IDS_INSTALLER_TIMED_OUT, app_name);

-      break;

-    case GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY:

-    case GOOPDATEINSTALL_E_INSTALLER_DID_NOT_CHANGE_VERSION:

-    case GOOPDATE_E_INVALID_INSTALL_DATA_INDEX:

-    case GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS:

-      error_text->FormatMessage(IDS_INSTALL_FAILED, omaha_hr);

-      break;

-    case GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING:

-      error_text->FormatMessage(IDS_MSI_INSTALL_ALREADY_RUNNING, app_name);

-      break;

-    case GOOPDATEINSTALL_E_INSTALLER_FAILED:

-      ASSERT(false,

-             (_T("[GetOmahaErrorTextToReport]")

-              _T("GOOPDATEINSTALL_E_INSTALLER_FAILED should never be reported ")

-              _T("directly. The installer error string should be reported.")));

-      error_text->FormatMessage(IDS_INSTALL_FAILED, omaha_hr);

-      break;

-    case GOOPDATEINSTALL_E_INSTALLER_INTERNAL_ERROR:

-    default:

-      ASSERT(false, (_T("[GetOmahaErrorTextToReport]")

-                     _T("[An Omaha error occurred that this method does not ")

-                     _T("know how to report.][0x%08x]"), omaha_hr));

-

-      error_text->FormatMessage(IDS_INSTALL_FAILED, omaha_hr);

-      break;

-  }

-

-  ASSERT1(!error_text->IsEmpty());

-}

-

-// Gets the errors string for the specified system error.

-// Assumes error_code represents a system error.

-void GetSystemErrorString(uint32 error_code, CString* error_string) {

-  ASSERT1(error_string);

-  ASSERT1(ERROR_SUCCESS != error_code);

-

-  const CString error_code_string = FormatErrorCode(error_code);

-

-  CString error_message;

-  if (GetMessageForSystemErrorCode(error_code, &error_message)) {

-    ASSERT(!error_message.IsEmpty(),

-           (_T("[GetMessageForSystemErrorCode succeeded ")

-            _T("but the error message is empty.]")));

-

-    error_string->FormatMessage(IDS_INSTALLER_FAILED_WITH_MESSAGE,

-                                error_code_string,

-                                error_message);

-  } else {

-    error_string->FormatMessage(IDS_INSTALLER_FAILED_NO_MESSAGE,

-                                error_code_string);

-  }

-

-  OPT_LOG(LEVEL_ERROR, (_T("[installer system error][%u][%s]"),

-                        error_code, *error_string));

-  ASSERT1(!error_string->IsEmpty());

-}

-

-}  // namespace

-

-// Obtains the message for a System Error Code in the user's language.

-// Returns whether the message was successfully obtained.

-// It does not support "insert sequences". The sequence will be returned in the

-// string.

-bool GetMessageForSystemErrorCode(DWORD system_error_code, CString* message) {

-  CORE_LOG(L3, (_T("[GetMessageForSystemErrorCode][%u]"), system_error_code));

-

-  ASSERT1(message);

-

-  message->Empty();

-

-  TCHAR* system_allocated_buffer = NULL;

-  const DWORD kFormatOptions = FORMAT_MESSAGE_ALLOCATE_BUFFER |

-                               FORMAT_MESSAGE_FROM_SYSTEM |

-                               FORMAT_MESSAGE_IGNORE_INSERTS |

-                               FORMAT_MESSAGE_MAX_WIDTH_MASK;

-  DWORD tchars_written = ::FormatMessage(

-      kFormatOptions,

-      NULL,

-      system_error_code,

-      0,

-      reinterpret_cast<LPWSTR>(&system_allocated_buffer),

-      0,

-      NULL);

-

-  if (0 < tchars_written) {

-    ASSERT1(system_allocated_buffer);

-    *message = system_allocated_buffer;

-

-    VERIFY1(!::LocalFree(system_allocated_buffer));

-    return true;

-  } else {

-    DWORD format_message_error = ::GetLastError();

-    ASSERT(false, (_T("[::FormatMessage failed][%u]"), format_message_error));

-    ASSERT1(!system_allocated_buffer);

-

-    return false;

-  }

-}

-

-InstallManager::InstallManager(bool is_machine)

-    : is_machine_(is_machine) {

-}

-

-HRESULT InstallManager::InstallJob(Job* job) {

-  ASSERT1(job);

-  job_ = job;

-

-  NamedObjectAttributes lock_attr;

-  GetNamedObjectAttributes(kInstallManagerSerializer, is_machine_, &lock_attr);

-  if (!installer_lock_.InitializeWithSecAttr(lock_attr.name, &lock_attr.sa)) {

-    OPT_LOG(LEVEL_ERROR, (_T("[Could not init install manager lock]")));

-    HRESULT hr = GOOPDATEINSTALL_E_CANNOT_GET_INSTALLER_LOCK;

-    error_info_.status = COMPLETION_ERROR;

-    error_info_.error_code = hr;

-    error_info_.text.FormatMessage(IDS_INSTALL_FAILED, hr);

-    return hr;

-  }

-

-  HRESULT hr = InstallDownloadedFile();

-

-  // error_info_ should have the default values unless the installer failed in

-  // which case it is already popluated correctly.

-  ASSERT1(IsCompletionSuccess(error_info_) ||

-          (GOOPDATEINSTALL_E_INSTALLER_FAILED == hr &&

-           IsCompletionInstallerError(error_info_)) ||

-          (GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING == hr &&

-           (COMPLETION_INSTALLER_ERROR_MSI == error_info_.status ||

-            COMPLETION_INSTALLER_ERROR_SYSTEM == error_info_.status)));

-  ASSERT1(!error_info_.text.IsEmpty() ==

-          (GOOPDATEINSTALL_E_INSTALLER_FAILED == hr ||

-          GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING == hr));

-

-  if (SUCCEEDED(hr)) {

-    // Omaha and the installer succeeded.

-    error_info_.text.FormatMessage(IDS_APPLICATION_INSTALLED_SUCCESSFULLY,

-                                   job_->app_data().display_name());

-    return S_OK;

-  } else {

-    CORE_LOG(LEVEL_ERROR, (_T("[InstallDownloadedFile failed][0x%08x]"), hr));

-

-    if (GOOPDATEINSTALL_E_INSTALLER_FAILED != hr) {

-      // Omaha failed.

-      error_info_.status = COMPLETION_ERROR;

-      error_info_.error_code = hr;

-      GetOmahaErrorTextToReport(hr,

-                                job_->download_file_name(),

-                                job_->app_data().display_name(),

-                                &error_info_.text);

-    }

-

-    return hr;

-  }

-}

-

-HRESULT InstallManager::BuildCommandLineFromFilename(

-    const CString& filename,

-    const CString& arguments,

-    const CString& installer_data,

-    CString* executable_name,

-    CString* command_line,

-    InstallerType* installer_type) {

-  CORE_LOG(L3, (_T("[BuildCommandLineFromFilename]")));

-

-  ASSERT1(executable_name);

-  ASSERT1(command_line);

-  ASSERT1(installer_type);

-

-  *executable_name = _T("");

-  *command_line = _T("");

-  *installer_type = UNKNOWN_INSTALLER;

-

-  // The app's installer owns the lifetime of installer data file if it has been

-  // created, so Omaha does not delete it.

-  CString enclosed_installer_data_file_path;

-

-  VERIFY1(SUCCEEDED(goopdate_utils::WriteInstallerDataToTempFile(

-      installer_data,

-      &enclosed_installer_data_file_path)));

-  if (!enclosed_installer_data_file_path.IsEmpty()) {

-    EnclosePath(&enclosed_installer_data_file_path);

-  }

-

-  // PathFindExtension returns the address of the trailing NUL character if an

-  // extension is not found. It does not return NULL.

-  const TCHAR* ext = ::PathFindExtension(filename);

-  ASSERT1(ext);

-  if (*ext != _T('\0')) {

-    ext++;  // Skip the period.

-    if (0 == lstrcmpi(ext, _T("exe"))) {

-      *executable_name = filename;

-      if (enclosed_installer_data_file_path.IsEmpty()) {

-        *command_line = arguments;

-      } else {

-        command_line->Format(_T("%s /installerdata=%s"),

-                             arguments,

-                             enclosed_installer_data_file_path);

-      }

-      *installer_type = CUSTOM_INSTALLER;

-

-      CORE_LOG(L2, (_T("[BuildCommandLineFromFilename][exe][%s][%s]"),

-                    *executable_name, *command_line));

-    } else if (0 == lstrcmpi(ext, _T("msi"))) {

-      *executable_name = _T("msiexec");

-      *command_line = BuildMsiCommandLine(arguments,

-                                          filename,

-                                          enclosed_installer_data_file_path);

-      *installer_type = MSI_INSTALLER;

-

-      CORE_LOG(L2, (_T("[BuildCommandLineFromFilename][msi][%s]"),

-                    *command_line));

-    } else {

-      *executable_name = _T("");

-      *command_line = _T("");

-      *installer_type = UNKNOWN_INSTALLER;

-

-      OPT_LOG(LEVEL_ERROR, (_T("[Unsupported extension '%s' in %s]"),

-                            ext, filename));

-      return GOOPDATEINSTALL_E_FILENAME_INVALID;

-    }

-  } else {

-    OPT_LOG(LEVEL_ERROR, (_T("[No extension found in %s]"), filename));

-    return GOOPDATEINSTALL_E_FILENAME_INVALID;

-  }

-

-  return S_OK;

-}

-

-// Calls DoExecuteAndWaitForInstaller to do the work. If an MSI installer

-// returns, ERROR_INSTALL_ALREADY_RUNNING waits and retries several times or

-// until the installation succeeds.

-HRESULT InstallManager::ExecuteAndWaitForInstaller(

-    const CString& executable_name,

-    const CString& command_line,

-    const CString& app_guid,

-    InstallerType installer_type) {

-  CORE_LOG(L3, (_T("[InstallManager::ExecuteAndWaitForInstaller]")));

-

-  ++metric_worker_install_execute_total;

-  if (MSI_INSTALLER == installer_type) {

-    ++metric_worker_install_execute_msi_total;

-  }

-

-  // Run the installer, retrying if necessary.

-  const int max_tries = job_->is_background() ?

-                        kNumMsiAlreadyRunningSilentMaxTries :

-                        kNumMsiAlreadyRunningInteractiveMaxTries;

-  int retry_delay = kMsiAlreadyRunningRetryDelayBaseMs;

-  int num_tries(0);

-  bool retry(true);

-  for (num_tries = 0; retry && num_tries < max_tries; ++num_tries) {

-    // Reset the completion info - it contains the previous error when retrying.

-    error_info_ = CompletionInfo();

-

-    if (0 < num_tries) {

-      // Retrying - wait between attempts.

-      ASSERT1(MSI_INSTALLER == installer_type);

-      ::Sleep(retry_delay);

-      retry_delay *= 2;  // Double the retry delay next time.

-    }

-

-    HRESULT hr = DoExecuteAndWaitForInstaller(executable_name,

-                                              command_line,

-                                              app_guid,

-                                              installer_type);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    retry = (COMPLETION_INSTALLER_ERROR_MSI == error_info_.status ||

-             COMPLETION_INSTALLER_ERROR_SYSTEM == error_info_.status) &&

-            ERROR_INSTALL_ALREADY_RUNNING == error_info_.error_code;

-  }

-

-  if (1 < num_tries) {

-    // Record metrics about the ERROR_INSTALL_ALREADY_RUNNING retries.

-    ASSERT1(MSI_INSTALLER == installer_type);

-

-    if (!job_->is_update()) {

-      ++metric_worker_install_msi_in_progress_detected_install;

-      if (IsCompletionSuccess(error_info_)) {

-        ++metric_worker_install_msi_in_progress_retry_succeeded_install;

-        metric_worker_install_msi_in_progress_retry_succeeded_tries_install

-            = num_tries;

-      }

-    } else {

-      ++metric_worker_install_msi_in_progress_detected_update;

-      if (IsCompletionSuccess(error_info_)) {

-        ++metric_worker_install_msi_in_progress_retry_succeeded_update;

-        metric_worker_install_msi_in_progress_retry_succeeded_tries_update

-            = num_tries;

-      }

-    }

-  }

-

-  if ((COMPLETION_INSTALLER_ERROR_MSI == error_info_.status ||

-       COMPLETION_INSTALLER_ERROR_SYSTEM == error_info_.status) &&

-      ERROR_INSTALL_ALREADY_RUNNING == error_info_.error_code) {

-    return GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING;

-  }

-

-  if (IsCompletionInstallerError(error_info_)) {

-    return GOOPDATEINSTALL_E_INSTALLER_FAILED;

-  }

-

-  return S_OK;

-}

-

-HRESULT InstallManager::DoExecuteAndWaitForInstaller(

-    const CString& executable_name,

-    const CString& command_line,

-    const CString& app_guid,

-    InstallerType installer_type) {

-  OPT_LOG(L1, (_T("[Running installer]")

-               _T("[%s][%s][%s]"), executable_name, command_line, app_guid));

-

-  CleanupInstallerResultRegistry(app_guid);

-

-  Process p(executable_name, NULL);

-

-  if (!p.Start(command_line)) {

-    OPT_LOG(LEVEL_ERROR, (_T("[Could not start process]")

-                          _T("[%s][%s]"), executable_name, command_line));

-    return GOOPDATEINSTALL_E_INSTALLER_FAILED_START;

-  }

-

-  if (app_guid.CompareNoCase(kGoogleUpdateAppId) == 0) {

-    // Do not wait for the installer when installing Omaha.

-    return S_OK;

-  }

-

-  if (!p.WaitUntilDead(kInstallManagerCompleteIntervalMs)) {

-    OPT_LOG(LEVEL_WARNING, (_T("[Installer has timed out]")

-                            _T("[%s][%s]"), executable_name, command_line));

-    return GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT;

-  }

-

-  HRESULT hr = GetInstallerResult(app_guid, installer_type, p, &error_info_);

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_ERROR, (_T("[GetInstallerResult failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (IsCompletionInstallerError(error_info_)) {

-    OPT_LOG(LE, (_T("[Installer failed][%s][%s][%u]"),

-                 executable_name, command_line, error_info_.error_code));

-  }

-

-  return S_OK;

-}

-

-CString InstallManager::BuildMsiCommandLine(

-    const CString& arguments,

-    const CString& filename,

-    const CString& enclosed_installer_data_file_path) {

-  CORE_LOG(L3, (_T("[InstallManager::CreateMsiCommandLine]")));

-

-  CString command_line;

-  // Suppressing reboots can lead to an inconsistent state until the user

-  // reboots, but automatically rebooting is unacceptable. The user will be

-  // informed by the string for ERROR_SUCCESS_REBOOT_REQUIRED that a reboot is

-  // necessary. See http://b/1184091 for details.

-

-  if (!enclosed_installer_data_file_path.IsEmpty()) {

-    command_line.Format(_T("INSTALLERDATA=%s "),

-                        enclosed_installer_data_file_path);

-  }

-

-  command_line.AppendFormat(_T("%s REBOOT=ReallySuppress /qn /i \"%s\""),

-                            arguments, filename);

-

-  // The msiexec version in XP SP2 (V 3.01) and higher supports the /log switch.

-  if (SystemInfo::OSWinXPSP2OrLater()) {

-    CString logfile(filename);

-    logfile.Append(_T(".log"));

-

-    command_line.AppendFormat(_T(" /log \"%s\""), logfile);

-  }

-

-  CORE_LOG(L2, (_T("[msiexec command line][%s]"), command_line));

-  return command_line;

-}

-

-HRESULT InstallManager::GetInstallerResult(const CString& app_guid,

-                                           InstallerType installer_type,

-                                           const Process& p,

-                                           CompletionInfo* completion_info) {

-  CORE_LOG(L3, (_T("[InstallManager::GetInstallerResult]")));

-  ASSERT1(completion_info);

-

-  uint32 exit_code = 0;

-  HRESULT hr = GetInstallerExitCode(p, &exit_code);

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_ERROR, (_T("[GetInstallerExitCode failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  GetInstallerResultHelper(app_guid,

-                           installer_type,

-                           exit_code,

-                           completion_info);

-  return S_OK;

-}

-

-// The default InstallerResult behavior can be overridden in the registry.

-// By default, error_code is the exit code. For some InstallerResults, it

-// can be overridden by InstallerError in the registry.

-// The success string cannot be overridden.

-void InstallManager::GetInstallerResultHelper(const CString& app_guid,

-                                              InstallerType installer_type,

-                                              uint32 exit_code,

-                                              CompletionInfo* completion_info) {

-  completion_info->error_code = exit_code;

-  completion_info->text.Empty();

-

-  const CString app_client_state_key =

-      goopdate_utils::GetAppClientStateKey(is_machine_, app_guid);

-  const InstallerResult installer_result =

-      GetInstallerResultType(app_client_state_key);

-  OPT_LOG(L1, (_T("[InstallerResult][%s][%u]"), app_guid, installer_result));

-

-

-  switch (installer_result) {

-    case INSTALLER_RESULT_SUCCESS:

-      completion_info->status = COMPLETION_SUCCESS;

-      ReadInstallerErrorOverride(app_client_state_key,

-                                 &completion_info->error_code);

-      break;

-    case INSTALLER_RESULT_FAILED_CUSTOM_ERROR:

-      completion_info->status = COMPLETION_INSTALLER_ERROR_OTHER;

-      ReadInstallerErrorOverride(app_client_state_key,

-                                 &completion_info->error_code);

-      ReadInstallerResultUIStringOverride(app_client_state_key,

-                                          &completion_info->text);

-      break;

-    case INSTALLER_RESULT_FAILED_MSI_ERROR:

-      completion_info->status = COMPLETION_INSTALLER_ERROR_MSI;

-      ReadInstallerErrorOverride(app_client_state_key,

-                                 &completion_info->error_code);

-      break;

-    case INSTALLER_RESULT_FAILED_SYSTEM_ERROR:

-      completion_info->status = COMPLETION_INSTALLER_ERROR_SYSTEM;

-      ReadInstallerErrorOverride(app_client_state_key,

-                                 &completion_info->error_code);

-      break;

-    case INSTALLER_RESULT_EXIT_CODE:

-      if (0 == exit_code) {

-        completion_info->status = COMPLETION_SUCCESS;

-        completion_info->error_code = 0;

-      } else {

-        switch (installer_type) {

-          case MSI_INSTALLER:

-            completion_info->status = COMPLETION_INSTALLER_ERROR_MSI;

-            break;

-          case UNKNOWN_INSTALLER:

-          case CUSTOM_INSTALLER:

-          case MAX_INSTALLER:

-          default:

-            completion_info->status = COMPLETION_INSTALLER_ERROR_OTHER;

-            break;

-        }

-      }

-      break;

-    case INSTALLER_RESULT_MAX:

-    default:

-      ASSERT1(false);

-      break;

-  }

-

-  // Handle the reboot required case.

-  if ((COMPLETION_INSTALLER_ERROR_MSI == completion_info->status ||

-       COMPLETION_INSTALLER_ERROR_SYSTEM == completion_info->status) &&

-      (ERROR_SUCCESS_REBOOT_REQUIRED == completion_info->error_code)) {

-    // This is a success, but the user should be notified.

-    completion_info->status = COMPLETION_SUCCESS_REBOOT_REQUIRED;

-    completion_info->error_code = 0;

-  }

-

-  // CompletionInfo status has been finalized. Handle launch command and make

-  // sure all errors have error strings.

-  switch (completion_info->status) {

-    case COMPLETION_SUCCESS: {

-        CString cmd_line;

-        if (SUCCEEDED(RegKey::GetValue(app_client_state_key,

-                                       kRegValueInstallerSuccessLaunchCmdLine,

-                                       &cmd_line)) &&

-            !cmd_line.IsEmpty()) {

-          job_->set_launch_cmd_line(cmd_line);

-        }

-      }

-      break;

-    case COMPLETION_SUCCESS_REBOOT_REQUIRED:

-      break;

-    case COMPLETION_INSTALLER_ERROR_MSI:

-    case COMPLETION_INSTALLER_ERROR_SYSTEM:

-      ASSERT1(completion_info->text.IsEmpty());

-      GetSystemErrorString(completion_info->error_code, &completion_info->text);

-      break;

-    case COMPLETION_INSTALLER_ERROR_OTHER:

-      if (completion_info->text.IsEmpty()) {

-        completion_info->text.FormatMessage(

-              IDS_INSTALLER_FAILED_NO_MESSAGE,

-              FormatErrorCode(completion_info->error_code));

-      }

-      break;

-    case COMPLETION_ERROR:

-    case COMPLETION_CANCELLED:

-    default:

-      ASSERT1(false);

-  }

-

-  OPT_LOG(L1, (_T("[%s]"), completion_info->ToString()));

-  CleanupInstallerResultRegistry(app_guid);

-}

-

-void InstallManager::CleanupInstallerResultRegistry(const CString& app_guid) {

-  CString app_client_state_key =

-      goopdate_utils::GetAppClientStateKey(is_machine_, app_guid);

-  CString update_key = ConfigManager::Instance()->registry_update(is_machine_);

-

-  // Delete the old LastXXX values.  These may not exist, so don't care if they

-  // fail.

-  RegKey::DeleteValue(app_client_state_key,

-                      kRegValueLastInstallerResult);

-  RegKey::DeleteValue(app_client_state_key,

-                      kRegValueLastInstallerResultUIString);

-  RegKey::DeleteValue(app_client_state_key,

-                      kRegValueLastInstallerError);

-  RegKey::DeleteValue(app_client_state_key,

-                      kRegValueLastInstallerSuccessLaunchCmdLine);

-

-  // Also delete any values from Google\Update.

-  // TODO(Omaha): This is a temporary fix for bug 1539293. Need a better

-  // long-term solution.

-  RegKey::DeleteValue(update_key,

-                      kRegValueLastInstallerResult);

-  RegKey::DeleteValue(update_key,

-                      kRegValueLastInstallerResultUIString);

-  RegKey::DeleteValue(update_key,

-                      kRegValueLastInstallerError);

-  RegKey::DeleteValue(update_key,

-                      kRegValueLastInstallerSuccessLaunchCmdLine);

-

-  // Rename current InstallerResultXXX values to LastXXX.

-  RegKey::RenameValue(app_client_state_key,

-                      kRegValueInstallerResult,

-                      kRegValueLastInstallerResult);

-  RegKey::RenameValue(app_client_state_key,

-                      kRegValueInstallerError,

-                      kRegValueLastInstallerError);

-  RegKey::RenameValue(app_client_state_key,

-                      kRegValueInstallerResultUIString,

-                      kRegValueLastInstallerResultUIString);

-  RegKey::RenameValue(app_client_state_key,

-                      kRegValueInstallerSuccessLaunchCmdLine,

-                      kRegValueLastInstallerSuccessLaunchCmdLine);

-

-  // Copy over to the Google\Update key.

-  // TODO(Omaha): This is a temporary fix for bug 1539293. Need a better

-  // long-term solution.

-  RegKey::CopyValue(app_client_state_key,

-                    update_key,

-                    kRegValueLastInstallerResult);

-  RegKey::CopyValue(app_client_state_key,

-                    update_key,

-                    kRegValueLastInstallerError);

-  RegKey::CopyValue(app_client_state_key,

-                    update_key,

-                    kRegValueLastInstallerResultUIString);

-  RegKey::CopyValue(app_client_state_key,

-                    update_key,

-                    kRegValueLastInstallerSuccessLaunchCmdLine);

-}

-

-HRESULT InstallManager::CheckApplicationRegistration(

-    const CString& previous_version) {

-  CORE_LOG(L2,

-           (_T("[InstallManager::CheckApplicationRegistration][%s]"),

-            GuidToString(job_->app_data().app_guid())));

-  ASSERT1(!::IsEqualGUID(kGoopdateGuid, job_->app_data().app_guid()));

-

-  AppManager app_manager(is_machine_);

-  if (!app_manager.IsProductRegistered(job_->app_data().app_guid())) {

-    OPT_LOG(LE, (_T("[Installer did not register][%s]"),

-                 GuidToString(job_->app_data().app_guid())));

-    job_->set_extra_code1(-1);

-    return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY;

-  }

-

-  ProductData product_data;

-  // TODO(omaha): Should we check that each individual component was registered?

-  HRESULT hr = app_manager.ReadProductDataFromStore(job_->app_data().app_guid(),

-                                                    &product_data);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[CheckApplicationRegistration]")

-                  _T("[ReadProductDataFromStore failed][guid=%s][0x%08x]"),

-                  GuidToString(job_->app_data().app_guid()), hr));

-    job_->set_extra_code1(hr);

-    return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY;

-  }

-

-  CORE_LOG(L2, (_T("[CheckApplicationRegistration]")

-                _T("[guid=%s][version=%s][previous_version=%s]"),

-                GuidToString(job_->app_data().app_guid()),

-                product_data.app_data().version(),

-                previous_version));

-

-  if (product_data.app_data().version().IsEmpty()) {

-    OPT_LOG(LE, (_T("[Installer did not write version][%s]"),

-                 GuidToString(job_->app_data().app_guid())));

-    job_->set_extra_code1(-2);

-    return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY;

-  }

-

-  if (job_->is_update() &&

-      previous_version == product_data.app_data().version()) {

-    OPT_LOG(LE, (_T("[Installer did not change version][%s]"),

-                 GuidToString(job_->app_data().app_guid())));

-    return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_CHANGE_VERSION;

-  }

-

-  // TODO(omaha): Log warning if version does not match version in config when

-  // present.

-

-  return S_OK;

-}

-

-// This method is used extensively for unit testing installation because it

-// is the highest level method that returns an error.

-// Assumes installer_lock_ has been initialized.

-HRESULT InstallManager::DoInstallation() {

-  OPT_LOG(L1, (_T("[InstallManager::DoInstallation][%s][%s][%s][%s]"),

-               job_->app_data().display_name(),

-               GuidToString(job_->app_data().app_guid()),

-               job_->download_file_name(),

-               job_->response_data().arguments()));

-

-  CString executable_name;

-  CString command_line;

-  InstallerType installer_type = UNKNOWN_INSTALLER;

-

-  CString arguments(job_->response_data().arguments());

-  const TCHAR* const kChromeGuid = _T("{8A69D345-D564-463C-AFF1-A69D9E530F96}");

-  const TCHAR* const kChromePerMachineArg = _T("--system-level");

-  if (::IsEqualGUID(StringToGuid(kChromeGuid), job_->app_data().app_guid()) &&

-      is_machine_) {

-    arguments.AppendFormat(_T(" %s"), kChromePerMachineArg);

-  }

-

-  CString installer_data;

-  HRESULT hr = job_->GetInstallerData(&installer_data);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[GetInstallerData failed][0x%x]"), hr));

-    return hr;

-  }

-

-  hr = BuildCommandLineFromFilename(job_->download_file_name(),

-                                    arguments,

-                                    installer_data,

-                                    &executable_name,

-                                    &command_line,

-                                    &installer_type);

-

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[BuildCommandLineFromFilename failed][0x%08x]"), hr));

-    ASSERT1(GOOPDATEINSTALL_E_FILENAME_INVALID == hr);

-    return hr;

-  }

-

-  // We need this scope for the mutex.

-  {

-    // Acquire the global lock here. This will ensure that we are the only

-    // installer running of the multiple goopdates.

-    __mutexScope(installer_lock_);

-

-    hr = ExecuteAndWaitForInstaller(executable_name,

-                                    command_line,

-                                    GuidToString(job_->app_data().app_guid()),

-                                    installer_type);

-    if (FAILED(hr)) {

-      CORE_LOG(LW, (_T("[ExecuteAndWaitForInstaller failed][0x%08x][%s]"),

-                    hr, GuidToString(job_->app_data().app_guid())));

-    }

-  }

-

-  return hr;

-}

-

-HRESULT InstallManager::InstallDownloadedFile() {

-  CString previous_version = job_->app_data().previous_version();

-

-  HRESULT hr = DoInstallation();

-  if (FAILED(hr)) {

-    CORE_LOG(LEVEL_ERROR, (_T("[DoInstallation failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (::IsEqualGUID(kGoopdateGuid, job_->app_data().app_guid())) {

-    // Do not check application registration because the installer has not

-    // completed.

-    return S_OK;

-  }

-

-  // Ensure that the app installer wrote the minimum required registry values.

-  hr = CheckApplicationRegistration(previous_version);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return S_OK;

-}

-

-InstallManager::InstallerResult InstallManager::GetInstallerResultType(

-    const CString& app_client_state_key) {

-  InstallerResult installer_result = INSTALLER_RESULT_DEFAULT;

-  if (SUCCEEDED(RegKey::GetValue(

-      app_client_state_key,

-      kRegValueInstallerResult,

-      reinterpret_cast<DWORD*>(&installer_result)))) {

-    CORE_LOG(L2, (_T("[InstallerResult in registry][%u]"), installer_result));

-  }

-  if (INSTALLER_RESULT_MAX <= installer_result) {

-    CORE_LOG(LW, (_T("[Unsupported InstallerResult value]")));

-    installer_result = INSTALLER_RESULT_DEFAULT;

-  }

-

-  return installer_result;

-}

-

-void InstallManager::ReadInstallerErrorOverride(

-    const CString& app_client_state_key,

-    DWORD* installer_error) {

-  ASSERT1(installer_error);

-  if (FAILED(RegKey::GetValue(app_client_state_key,

-                              kRegValueInstallerError,

-                              installer_error))) {

-    CORE_LOG(LW, (_T("[InstallerError not found in registry]")));

-  }

-}

-

-void InstallManager::ReadInstallerResultUIStringOverride(

-    const CString& app_client_state_key,

-    CString* installer_result_uistring) {

-  ASSERT1(installer_result_uistring);

-  if (FAILED(RegKey::GetValue(app_client_state_key,

-                              kRegValueInstallerResultUIString,

-                              installer_result_uistring))) {

-    CORE_LOG(LW, (_T("[InstallerResultUIString not found in registry]")));

-  }

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/worker/install_manager.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/process.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource.h"
+#include "omaha/worker/job.h"
+#include "omaha/worker/worker_metrics.h"
+
+namespace omaha {
+
+bool GetMessageForSystemErrorCode(DWORD system_error_code, CString* message);
+
+namespace {
+
+// This is the base retry delay between retries when msiexec returns
+// ERROR_INSTALL_ALREADY_RUNNING. We exponentially backoff from this value.
+// Note that there is an additional delay for the MSI call, so the tries may
+// be a few seconds further apart.
+int kMsiAlreadyRunningRetryDelayBaseMs = 5000;
+// Number of retries. Updates are silent so we can wait longer.
+int kNumMsiAlreadyRunningInteractiveMaxTries = 4;  // Up to 35 seconds.
+int kNumMsiAlreadyRunningSilentMaxTries      = 7;  // Up to 6.25 minutes.
+
+// Interval to wait for installer completion.
+const int kInstallManagerCompleteIntervalMs = 15 * 60 * 1000;
+
+// Gets the installer exit code.
+HRESULT GetInstallerExitCode(const Process& p, uint32* exit_code) {
+  ASSERT1(exit_code);
+
+  if (p.Running()) {
+    ASSERT(false,
+           (_T("GetInstallerExitCode called while the process is running.")));
+    return GOOPDATEINSTALL_E_INSTALLER_INTERNAL_ERROR;
+  }
+
+  if (!p.GetExitCode(exit_code)) {
+    ASSERT(false,
+           (_T("[Failed to get the installer exit code for some reason.]")));
+    return GOOPDATEINSTALL_E_INSTALLER_INTERNAL_ERROR;
+  }
+
+  CORE_LOG(L2, (_T("[Installer exit code][%u]"), *exit_code));
+
+  return S_OK;
+}
+
+// Obtains the localized text for Omaha errors that may occur in the
+// DoInstallation path.
+void GetOmahaErrorTextToReport(HRESULT omaha_hr,
+                               const CString& installer_filename,
+                               const CString& app_name,
+                               CString* error_text) {
+  ASSERT1(error_text);
+
+  switch (omaha_hr) {
+    case GOOPDATEINSTALL_E_FILENAME_INVALID:
+      error_text->FormatMessage(IDS_INVALID_INSTALLER_FILENAME,
+                                installer_filename);
+      break;
+    case GOOPDATEINSTALL_E_INSTALLER_FAILED_START:
+      error_text->FormatMessage(IDS_INSTALLER_FAILED_TO_START);
+      break;
+    case GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT:
+      error_text->FormatMessage(IDS_INSTALLER_TIMED_OUT, app_name);
+      break;
+    case GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY:
+    case GOOPDATEINSTALL_E_INSTALLER_DID_NOT_CHANGE_VERSION:
+    case GOOPDATE_E_INVALID_INSTALL_DATA_INDEX:
+    case GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS:
+      error_text->FormatMessage(IDS_INSTALL_FAILED, omaha_hr);
+      break;
+    case GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING:
+      error_text->FormatMessage(IDS_MSI_INSTALL_ALREADY_RUNNING, app_name);
+      break;
+    case GOOPDATEINSTALL_E_INSTALLER_FAILED:
+      ASSERT(false,
+             (_T("[GetOmahaErrorTextToReport]")
+              _T("GOOPDATEINSTALL_E_INSTALLER_FAILED should never be reported ")
+              _T("directly. The installer error string should be reported.")));
+      error_text->FormatMessage(IDS_INSTALL_FAILED, omaha_hr);
+      break;
+    case GOOPDATEINSTALL_E_INSTALLER_INTERNAL_ERROR:
+    default:
+      ASSERT(false, (_T("[GetOmahaErrorTextToReport]")
+                     _T("[An Omaha error occurred that this method does not ")
+                     _T("know how to report.][0x%08x]"), omaha_hr));
+
+      error_text->FormatMessage(IDS_INSTALL_FAILED, omaha_hr);
+      break;
+  }
+
+  ASSERT1(!error_text->IsEmpty());
+}
+
+// Gets the errors string for the specified system error.
+// Assumes error_code represents a system error.
+void GetSystemErrorString(uint32 error_code, CString* error_string) {
+  ASSERT1(error_string);
+  ASSERT1(ERROR_SUCCESS != error_code);
+
+  const CString error_code_string = FormatErrorCode(error_code);
+
+  CString error_message;
+  if (GetMessageForSystemErrorCode(error_code, &error_message)) {
+    ASSERT(!error_message.IsEmpty(),
+           (_T("[GetMessageForSystemErrorCode succeeded ")
+            _T("but the error message is empty.]")));
+
+    error_string->FormatMessage(IDS_INSTALLER_FAILED_WITH_MESSAGE,
+                                error_code_string,
+                                error_message);
+  } else {
+    error_string->FormatMessage(IDS_INSTALLER_FAILED_NO_MESSAGE,
+                                error_code_string);
+  }
+
+  OPT_LOG(LEVEL_ERROR, (_T("[installer system error][%u][%s]"),
+                        error_code, *error_string));
+  ASSERT1(!error_string->IsEmpty());
+}
+
+}  // namespace
+
+// Obtains the message for a System Error Code in the user's language.
+// Returns whether the message was successfully obtained.
+// It does not support "insert sequences". The sequence will be returned in the
+// string.
+bool GetMessageForSystemErrorCode(DWORD system_error_code, CString* message) {
+  CORE_LOG(L3, (_T("[GetMessageForSystemErrorCode][%u]"), system_error_code));
+
+  ASSERT1(message);
+
+  message->Empty();
+
+  TCHAR* system_allocated_buffer = NULL;
+  const DWORD kFormatOptions = FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                               FORMAT_MESSAGE_FROM_SYSTEM |
+                               FORMAT_MESSAGE_IGNORE_INSERTS |
+                               FORMAT_MESSAGE_MAX_WIDTH_MASK;
+  DWORD tchars_written = ::FormatMessage(
+      kFormatOptions,
+      NULL,
+      system_error_code,
+      0,
+      reinterpret_cast<LPWSTR>(&system_allocated_buffer),
+      0,
+      NULL);
+
+  if (0 < tchars_written) {
+    ASSERT1(system_allocated_buffer);
+    *message = system_allocated_buffer;
+
+    VERIFY1(!::LocalFree(system_allocated_buffer));
+    return true;
+  } else {
+    DWORD format_message_error = ::GetLastError();
+    ASSERT(false, (_T("[::FormatMessage failed][%u]"), format_message_error));
+    ASSERT1(!system_allocated_buffer);
+
+    return false;
+  }
+}
+
+InstallManager::InstallManager(bool is_machine)
+    : is_machine_(is_machine) {
+}
+
+HRESULT InstallManager::InstallJob(Job* job) {
+  ASSERT1(job);
+  job_ = job;
+
+  NamedObjectAttributes lock_attr;
+  GetNamedObjectAttributes(kInstallManagerSerializer, is_machine_, &lock_attr);
+  if (!installer_lock_.InitializeWithSecAttr(lock_attr.name, &lock_attr.sa)) {
+    OPT_LOG(LEVEL_ERROR, (_T("[Could not init install manager lock]")));
+    HRESULT hr = GOOPDATEINSTALL_E_CANNOT_GET_INSTALLER_LOCK;
+    error_info_.status = COMPLETION_ERROR;
+    error_info_.error_code = hr;
+    error_info_.text.FormatMessage(IDS_INSTALL_FAILED, hr);
+    return hr;
+  }
+
+  HRESULT hr = InstallDownloadedFile();
+
+  // error_info_ should have the default values unless the installer failed in
+  // which case it is already popluated correctly.
+  ASSERT1(IsCompletionSuccess(error_info_) ||
+          (GOOPDATEINSTALL_E_INSTALLER_FAILED == hr &&
+           IsCompletionInstallerError(error_info_)) ||
+          (GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING == hr &&
+           (COMPLETION_INSTALLER_ERROR_MSI == error_info_.status ||
+            COMPLETION_INSTALLER_ERROR_SYSTEM == error_info_.status)));
+  ASSERT1(!error_info_.text.IsEmpty() ==
+          (GOOPDATEINSTALL_E_INSTALLER_FAILED == hr ||
+          GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING == hr));
+
+  if (SUCCEEDED(hr)) {
+    // Omaha and the installer succeeded.
+    error_info_.text.FormatMessage(IDS_APPLICATION_INSTALLED_SUCCESSFULLY,
+                                   job_->app_data().display_name());
+    return S_OK;
+  } else {
+    CORE_LOG(LEVEL_ERROR, (_T("[InstallDownloadedFile failed][0x%08x]"), hr));
+
+    if (GOOPDATEINSTALL_E_INSTALLER_FAILED != hr) {
+      // Omaha failed.
+      error_info_.status = COMPLETION_ERROR;
+      error_info_.error_code = hr;
+      GetOmahaErrorTextToReport(hr,
+                                job_->download_file_name(),
+                                job_->app_data().display_name(),
+                                &error_info_.text);
+    }
+
+    return hr;
+  }
+}
+
+HRESULT InstallManager::BuildCommandLineFromFilename(
+    const CString& filename,
+    const CString& arguments,
+    const CString& installer_data,
+    CString* executable_name,
+    CString* command_line,
+    InstallerType* installer_type) {
+  CORE_LOG(L3, (_T("[BuildCommandLineFromFilename]")));
+
+  ASSERT1(executable_name);
+  ASSERT1(command_line);
+  ASSERT1(installer_type);
+
+  *executable_name = _T("");
+  *command_line = _T("");
+  *installer_type = UNKNOWN_INSTALLER;
+
+  // The app's installer owns the lifetime of installer data file if it has been
+  // created, so Omaha does not delete it.
+  CString enclosed_installer_data_file_path;
+
+  VERIFY1(SUCCEEDED(goopdate_utils::WriteInstallerDataToTempFile(
+      installer_data,
+      &enclosed_installer_data_file_path)));
+  if (!enclosed_installer_data_file_path.IsEmpty()) {
+    EnclosePath(&enclosed_installer_data_file_path);
+  }
+
+  // PathFindExtension returns the address of the trailing NUL character if an
+  // extension is not found. It does not return NULL.
+  const TCHAR* ext = ::PathFindExtension(filename);
+  ASSERT1(ext);
+  if (*ext != _T('\0')) {
+    ext++;  // Skip the period.
+    if (0 == lstrcmpi(ext, _T("exe"))) {
+      *executable_name = filename;
+      if (enclosed_installer_data_file_path.IsEmpty()) {
+        *command_line = arguments;
+      } else {
+        command_line->Format(_T("%s /installerdata=%s"),
+                             arguments,
+                             enclosed_installer_data_file_path);
+      }
+      *installer_type = CUSTOM_INSTALLER;
+
+      CORE_LOG(L2, (_T("[BuildCommandLineFromFilename][exe][%s][%s]"),
+                    *executable_name, *command_line));
+    } else if (0 == lstrcmpi(ext, _T("msi"))) {
+      *executable_name = _T("msiexec");
+      *command_line = BuildMsiCommandLine(arguments,
+                                          filename,
+                                          enclosed_installer_data_file_path);
+      *installer_type = MSI_INSTALLER;
+
+      CORE_LOG(L2, (_T("[BuildCommandLineFromFilename][msi][%s]"),
+                    *command_line));
+    } else {
+      *executable_name = _T("");
+      *command_line = _T("");
+      *installer_type = UNKNOWN_INSTALLER;
+
+      OPT_LOG(LEVEL_ERROR, (_T("[Unsupported extension '%s' in %s]"),
+                            ext, filename));
+      return GOOPDATEINSTALL_E_FILENAME_INVALID;
+    }
+  } else {
+    OPT_LOG(LEVEL_ERROR, (_T("[No extension found in %s]"), filename));
+    return GOOPDATEINSTALL_E_FILENAME_INVALID;
+  }
+
+  return S_OK;
+}
+
+// Calls DoExecuteAndWaitForInstaller to do the work. If an MSI installer
+// returns, ERROR_INSTALL_ALREADY_RUNNING waits and retries several times or
+// until the installation succeeds.
+HRESULT InstallManager::ExecuteAndWaitForInstaller(
+    const CString& executable_name,
+    const CString& command_line,
+    const CString& app_guid,
+    InstallerType installer_type) {
+  CORE_LOG(L3, (_T("[InstallManager::ExecuteAndWaitForInstaller]")));
+
+  ++metric_worker_install_execute_total;
+  if (MSI_INSTALLER == installer_type) {
+    ++metric_worker_install_execute_msi_total;
+  }
+
+  // Run the installer, retrying if necessary.
+  const int max_tries = job_->is_background() ?
+                        kNumMsiAlreadyRunningSilentMaxTries :
+                        kNumMsiAlreadyRunningInteractiveMaxTries;
+  int retry_delay = kMsiAlreadyRunningRetryDelayBaseMs;
+  int num_tries(0);
+  bool retry(true);
+  for (num_tries = 0; retry && num_tries < max_tries; ++num_tries) {
+    // Reset the completion info - it contains the previous error when retrying.
+    error_info_ = CompletionInfo();
+
+    if (0 < num_tries) {
+      // Retrying - wait between attempts.
+      ASSERT1(MSI_INSTALLER == installer_type);
+      ::Sleep(retry_delay);
+      retry_delay *= 2;  // Double the retry delay next time.
+    }
+
+    HRESULT hr = DoExecuteAndWaitForInstaller(executable_name,
+                                              command_line,
+                                              app_guid,
+                                              installer_type);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    retry = (COMPLETION_INSTALLER_ERROR_MSI == error_info_.status ||
+             COMPLETION_INSTALLER_ERROR_SYSTEM == error_info_.status) &&
+            ERROR_INSTALL_ALREADY_RUNNING == error_info_.error_code;
+  }
+
+  if (1 < num_tries) {
+    // Record metrics about the ERROR_INSTALL_ALREADY_RUNNING retries.
+    ASSERT1(MSI_INSTALLER == installer_type);
+
+    if (!job_->is_update()) {
+      ++metric_worker_install_msi_in_progress_detected_install;
+      if (IsCompletionSuccess(error_info_)) {
+        ++metric_worker_install_msi_in_progress_retry_succeeded_install;
+        metric_worker_install_msi_in_progress_retry_succeeded_tries_install
+            = num_tries;
+      }
+    } else {
+      ++metric_worker_install_msi_in_progress_detected_update;
+      if (IsCompletionSuccess(error_info_)) {
+        ++metric_worker_install_msi_in_progress_retry_succeeded_update;
+        metric_worker_install_msi_in_progress_retry_succeeded_tries_update
+            = num_tries;
+      }
+    }
+  }
+
+  if ((COMPLETION_INSTALLER_ERROR_MSI == error_info_.status ||
+       COMPLETION_INSTALLER_ERROR_SYSTEM == error_info_.status) &&
+      ERROR_INSTALL_ALREADY_RUNNING == error_info_.error_code) {
+    return GOOPDATEINSTALL_E_MSI_INSTALL_ALREADY_RUNNING;
+  }
+
+  if (IsCompletionInstallerError(error_info_)) {
+    return GOOPDATEINSTALL_E_INSTALLER_FAILED;
+  }
+
+  return S_OK;
+}
+
+HRESULT InstallManager::DoExecuteAndWaitForInstaller(
+    const CString& executable_name,
+    const CString& command_line,
+    const CString& app_guid,
+    InstallerType installer_type) {
+  OPT_LOG(L1, (_T("[Running installer]")
+               _T("[%s][%s][%s]"), executable_name, command_line, app_guid));
+
+  CleanupInstallerResultRegistry(app_guid);
+
+  Process p(executable_name, NULL);
+
+  if (!p.Start(command_line)) {
+    OPT_LOG(LEVEL_ERROR, (_T("[Could not start process]")
+                          _T("[%s][%s]"), executable_name, command_line));
+    return GOOPDATEINSTALL_E_INSTALLER_FAILED_START;
+  }
+
+  if (app_guid.CompareNoCase(kGoogleUpdateAppId) == 0) {
+    // Do not wait for the installer when installing Omaha.
+    return S_OK;
+  }
+
+  if (!p.WaitUntilDead(kInstallManagerCompleteIntervalMs)) {
+    OPT_LOG(LEVEL_WARNING, (_T("[Installer has timed out]")
+                            _T("[%s][%s]"), executable_name, command_line));
+    return GOOPDATEINSTALL_E_INSTALLER_TIMED_OUT;
+  }
+
+  HRESULT hr = GetInstallerResult(app_guid, installer_type, p, &error_info_);
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_ERROR, (_T("[GetInstallerResult failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (IsCompletionInstallerError(error_info_)) {
+    OPT_LOG(LE, (_T("[Installer failed][%s][%s][%u]"),
+                 executable_name, command_line, error_info_.error_code));
+  }
+
+  return S_OK;
+}
+
+CString InstallManager::BuildMsiCommandLine(
+    const CString& arguments,
+    const CString& filename,
+    const CString& enclosed_installer_data_file_path) {
+  CORE_LOG(L3, (_T("[InstallManager::CreateMsiCommandLine]")));
+
+  CString command_line;
+  // Suppressing reboots can lead to an inconsistent state until the user
+  // reboots, but automatically rebooting is unacceptable. The user will be
+  // informed by the string for ERROR_SUCCESS_REBOOT_REQUIRED that a reboot is
+  // necessary. See http://b/1184091 for details.
+
+  if (!enclosed_installer_data_file_path.IsEmpty()) {
+    command_line.Format(_T("INSTALLERDATA=%s "),
+                        enclosed_installer_data_file_path);
+  }
+
+  command_line.AppendFormat(_T("%s REBOOT=ReallySuppress /qn /i \"%s\""),
+                            arguments, filename);
+
+  // The msiexec version in XP SP2 (V 3.01) and higher supports the /log switch.
+  if (SystemInfo::OSWinXPSP2OrLater()) {
+    CString logfile(filename);
+    logfile.Append(_T(".log"));
+
+    command_line.AppendFormat(_T(" /log \"%s\""), logfile);
+  }
+
+  CORE_LOG(L2, (_T("[msiexec command line][%s]"), command_line));
+  return command_line;
+}
+
+HRESULT InstallManager::GetInstallerResult(const CString& app_guid,
+                                           InstallerType installer_type,
+                                           const Process& p,
+                                           CompletionInfo* completion_info) {
+  CORE_LOG(L3, (_T("[InstallManager::GetInstallerResult]")));
+  ASSERT1(completion_info);
+
+  uint32 exit_code = 0;
+  HRESULT hr = GetInstallerExitCode(p, &exit_code);
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_ERROR, (_T("[GetInstallerExitCode failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  GetInstallerResultHelper(app_guid,
+                           installer_type,
+                           exit_code,
+                           completion_info);
+  return S_OK;
+}
+
+// The default InstallerResult behavior can be overridden in the registry.
+// By default, error_code is the exit code. For some InstallerResults, it
+// can be overridden by InstallerError in the registry.
+// The success string cannot be overridden.
+void InstallManager::GetInstallerResultHelper(const CString& app_guid,
+                                              InstallerType installer_type,
+                                              uint32 exit_code,
+                                              CompletionInfo* completion_info) {
+  completion_info->error_code = exit_code;
+  completion_info->text.Empty();
+
+  const CString app_client_state_key =
+      goopdate_utils::GetAppClientStateKey(is_machine_, app_guid);
+  const InstallerResult installer_result =
+      GetInstallerResultType(app_client_state_key);
+  OPT_LOG(L1, (_T("[InstallerResult][%s][%u]"), app_guid, installer_result));
+
+
+  switch (installer_result) {
+    case INSTALLER_RESULT_SUCCESS:
+      completion_info->status = COMPLETION_SUCCESS;
+      ReadInstallerErrorOverride(app_client_state_key,
+                                 &completion_info->error_code);
+      break;
+    case INSTALLER_RESULT_FAILED_CUSTOM_ERROR:
+      completion_info->status = COMPLETION_INSTALLER_ERROR_OTHER;
+      ReadInstallerErrorOverride(app_client_state_key,
+                                 &completion_info->error_code);
+      ReadInstallerResultUIStringOverride(app_client_state_key,
+                                          &completion_info->text);
+      break;
+    case INSTALLER_RESULT_FAILED_MSI_ERROR:
+      completion_info->status = COMPLETION_INSTALLER_ERROR_MSI;
+      ReadInstallerErrorOverride(app_client_state_key,
+                                 &completion_info->error_code);
+      break;
+    case INSTALLER_RESULT_FAILED_SYSTEM_ERROR:
+      completion_info->status = COMPLETION_INSTALLER_ERROR_SYSTEM;
+      ReadInstallerErrorOverride(app_client_state_key,
+                                 &completion_info->error_code);
+      break;
+    case INSTALLER_RESULT_EXIT_CODE:
+      if (0 == exit_code) {
+        completion_info->status = COMPLETION_SUCCESS;
+        completion_info->error_code = 0;
+      } else {
+        switch (installer_type) {
+          case MSI_INSTALLER:
+            completion_info->status = COMPLETION_INSTALLER_ERROR_MSI;
+            break;
+          case UNKNOWN_INSTALLER:
+          case CUSTOM_INSTALLER:
+          case MAX_INSTALLER:
+          default:
+            completion_info->status = COMPLETION_INSTALLER_ERROR_OTHER;
+            break;
+        }
+      }
+      break;
+    case INSTALLER_RESULT_MAX:
+    default:
+      ASSERT1(false);
+      break;
+  }
+
+  // Handle the reboot required case.
+  if ((COMPLETION_INSTALLER_ERROR_MSI == completion_info->status ||
+       COMPLETION_INSTALLER_ERROR_SYSTEM == completion_info->status) &&
+      (ERROR_SUCCESS_REBOOT_REQUIRED == completion_info->error_code)) {
+    // This is a success, but the user should be notified.
+    completion_info->status = COMPLETION_SUCCESS_REBOOT_REQUIRED;
+    completion_info->error_code = 0;
+  }
+
+  // CompletionInfo status has been finalized. Handle launch command and make
+  // sure all errors have error strings.
+  switch (completion_info->status) {
+    case COMPLETION_SUCCESS: {
+        CString cmd_line;
+        if (SUCCEEDED(RegKey::GetValue(app_client_state_key,
+                                       kRegValueInstallerSuccessLaunchCmdLine,
+                                       &cmd_line)) &&
+            !cmd_line.IsEmpty()) {
+          job_->set_launch_cmd_line(cmd_line);
+        }
+      }
+      break;
+    case COMPLETION_SUCCESS_REBOOT_REQUIRED:
+      break;
+    case COMPLETION_INSTALLER_ERROR_MSI:
+    case COMPLETION_INSTALLER_ERROR_SYSTEM:
+      ASSERT1(completion_info->text.IsEmpty());
+      GetSystemErrorString(completion_info->error_code, &completion_info->text);
+      break;
+    case COMPLETION_INSTALLER_ERROR_OTHER:
+      if (completion_info->text.IsEmpty()) {
+        completion_info->text.FormatMessage(
+              IDS_INSTALLER_FAILED_NO_MESSAGE,
+              FormatErrorCode(completion_info->error_code));
+      }
+      break;
+    case COMPLETION_ERROR:
+    case COMPLETION_CANCELLED:
+    default:
+      ASSERT1(false);
+  }
+
+  OPT_LOG(L1, (_T("[%s]"), completion_info->ToString()));
+  CleanupInstallerResultRegistry(app_guid);
+}
+
+void InstallManager::CleanupInstallerResultRegistry(const CString& app_guid) {
+  CString app_client_state_key =
+      goopdate_utils::GetAppClientStateKey(is_machine_, app_guid);
+  CString update_key = ConfigManager::Instance()->registry_update(is_machine_);
+
+  // Delete the old LastXXX values.  These may not exist, so don't care if they
+  // fail.
+  RegKey::DeleteValue(app_client_state_key,
+                      kRegValueLastInstallerResult);
+  RegKey::DeleteValue(app_client_state_key,
+                      kRegValueLastInstallerResultUIString);
+  RegKey::DeleteValue(app_client_state_key,
+                      kRegValueLastInstallerError);
+  RegKey::DeleteValue(app_client_state_key,
+                      kRegValueLastInstallerSuccessLaunchCmdLine);
+
+  // Also delete any values from Google\Update.
+  // TODO(Omaha): This is a temporary fix for bug 1539293. Need a better
+  // long-term solution.
+  RegKey::DeleteValue(update_key,
+                      kRegValueLastInstallerResult);
+  RegKey::DeleteValue(update_key,
+                      kRegValueLastInstallerResultUIString);
+  RegKey::DeleteValue(update_key,
+                      kRegValueLastInstallerError);
+  RegKey::DeleteValue(update_key,
+                      kRegValueLastInstallerSuccessLaunchCmdLine);
+
+  // Rename current InstallerResultXXX values to LastXXX.
+  RegKey::RenameValue(app_client_state_key,
+                      kRegValueInstallerResult,
+                      kRegValueLastInstallerResult);
+  RegKey::RenameValue(app_client_state_key,
+                      kRegValueInstallerError,
+                      kRegValueLastInstallerError);
+  RegKey::RenameValue(app_client_state_key,
+                      kRegValueInstallerResultUIString,
+                      kRegValueLastInstallerResultUIString);
+  RegKey::RenameValue(app_client_state_key,
+                      kRegValueInstallerSuccessLaunchCmdLine,
+                      kRegValueLastInstallerSuccessLaunchCmdLine);
+
+  // Copy over to the Google\Update key.
+  // TODO(Omaha): This is a temporary fix for bug 1539293. Need a better
+  // long-term solution.
+  RegKey::CopyValue(app_client_state_key,
+                    update_key,
+                    kRegValueLastInstallerResult);
+  RegKey::CopyValue(app_client_state_key,
+                    update_key,
+                    kRegValueLastInstallerError);
+  RegKey::CopyValue(app_client_state_key,
+                    update_key,
+                    kRegValueLastInstallerResultUIString);
+  RegKey::CopyValue(app_client_state_key,
+                    update_key,
+                    kRegValueLastInstallerSuccessLaunchCmdLine);
+}
+
+HRESULT InstallManager::CheckApplicationRegistration(
+    const CString& previous_version) {
+  CORE_LOG(L2,
+           (_T("[InstallManager::CheckApplicationRegistration][%s]"),
+            GuidToString(job_->app_data().app_guid())));
+  ASSERT1(!::IsEqualGUID(kGoopdateGuid, job_->app_data().app_guid()));
+
+  AppManager app_manager(is_machine_);
+  if (!app_manager.IsProductRegistered(job_->app_data().app_guid())) {
+    OPT_LOG(LE, (_T("[Installer did not register][%s]"),
+                 GuidToString(job_->app_data().app_guid())));
+    job_->set_extra_code1(-1);
+    return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY;
+  }
+
+  ProductData product_data;
+  // TODO(omaha): Should we check that each individual component was registered?
+  HRESULT hr = app_manager.ReadProductDataFromStore(job_->app_data().app_guid(),
+                                                    &product_data);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[CheckApplicationRegistration]")
+                  _T("[ReadProductDataFromStore failed][guid=%s][0x%08x]"),
+                  GuidToString(job_->app_data().app_guid()), hr));
+    job_->set_extra_code1(hr);
+    return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY;
+  }
+
+  CORE_LOG(L2, (_T("[CheckApplicationRegistration]")
+                _T("[guid=%s][version=%s][previous_version=%s]"),
+                GuidToString(job_->app_data().app_guid()),
+                product_data.app_data().version(),
+                previous_version));
+
+  if (product_data.app_data().version().IsEmpty()) {
+    OPT_LOG(LE, (_T("[Installer did not write version][%s]"),
+                 GuidToString(job_->app_data().app_guid())));
+    job_->set_extra_code1(-2);
+    return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY;
+  }
+
+  if (job_->is_update() &&
+      previous_version == product_data.app_data().version()) {
+    OPT_LOG(LE, (_T("[Installer did not change version][%s]"),
+                 GuidToString(job_->app_data().app_guid())));
+    return GOOPDATEINSTALL_E_INSTALLER_DID_NOT_CHANGE_VERSION;
+  }
+
+  // TODO(omaha): Log warning if version does not match version in config when
+  // present.
+
+  return S_OK;
+}
+
+// This method is used extensively for unit testing installation because it
+// is the highest level method that returns an error.
+// Assumes installer_lock_ has been initialized.
+HRESULT InstallManager::DoInstallation() {
+  OPT_LOG(L1, (_T("[InstallManager::DoInstallation][%s][%s][%s][%s]"),
+               job_->app_data().display_name(),
+               GuidToString(job_->app_data().app_guid()),
+               job_->download_file_name(),
+               job_->response_data().arguments()));
+
+  CString executable_name;
+  CString command_line;
+  InstallerType installer_type = UNKNOWN_INSTALLER;
+
+  CString arguments(job_->response_data().arguments());
+  const TCHAR* const kChromeGuid = _T("{8A69D345-D564-463C-AFF1-A69D9E530F96}");
+  const TCHAR* const kChromePerMachineArg = _T("--system-level");
+  if (::IsEqualGUID(StringToGuid(kChromeGuid), job_->app_data().app_guid()) &&
+      is_machine_) {
+    arguments.AppendFormat(_T(" %s"), kChromePerMachineArg);
+  }
+
+  CString installer_data;
+  HRESULT hr = job_->GetInstallerData(&installer_data);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[GetInstallerData failed][0x%x]"), hr));
+    return hr;
+  }
+
+  hr = BuildCommandLineFromFilename(job_->download_file_name(),
+                                    arguments,
+                                    installer_data,
+                                    &executable_name,
+                                    &command_line,
+                                    &installer_type);
+
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[BuildCommandLineFromFilename failed][0x%08x]"), hr));
+    ASSERT1(GOOPDATEINSTALL_E_FILENAME_INVALID == hr);
+    return hr;
+  }
+
+  // We need this scope for the mutex.
+  {
+    // Acquire the global lock here. This will ensure that we are the only
+    // installer running of the multiple goopdates.
+    __mutexScope(installer_lock_);
+
+    hr = ExecuteAndWaitForInstaller(executable_name,
+                                    command_line,
+                                    GuidToString(job_->app_data().app_guid()),
+                                    installer_type);
+    if (FAILED(hr)) {
+      CORE_LOG(LW, (_T("[ExecuteAndWaitForInstaller failed][0x%08x][%s]"),
+                    hr, GuidToString(job_->app_data().app_guid())));
+    }
+  }
+
+  return hr;
+}
+
+HRESULT InstallManager::InstallDownloadedFile() {
+  CString previous_version = job_->app_data().previous_version();
+
+  HRESULT hr = DoInstallation();
+  if (FAILED(hr)) {
+    CORE_LOG(LEVEL_ERROR, (_T("[DoInstallation failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (::IsEqualGUID(kGoopdateGuid, job_->app_data().app_guid())) {
+    // Do not check application registration because the installer has not
+    // completed.
+    return S_OK;
+  }
+
+  // Ensure that the app installer wrote the minimum required registry values.
+  hr = CheckApplicationRegistration(previous_version);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return S_OK;
+}
+
+InstallManager::InstallerResult InstallManager::GetInstallerResultType(
+    const CString& app_client_state_key) {
+  InstallerResult installer_result = INSTALLER_RESULT_DEFAULT;
+  if (SUCCEEDED(RegKey::GetValue(
+      app_client_state_key,
+      kRegValueInstallerResult,
+      reinterpret_cast<DWORD*>(&installer_result)))) {
+    CORE_LOG(L2, (_T("[InstallerResult in registry][%u]"), installer_result));
+  }
+  if (INSTALLER_RESULT_MAX <= installer_result) {
+    CORE_LOG(LW, (_T("[Unsupported InstallerResult value]")));
+    installer_result = INSTALLER_RESULT_DEFAULT;
+  }
+
+  return installer_result;
+}
+
+void InstallManager::ReadInstallerErrorOverride(
+    const CString& app_client_state_key,
+    DWORD* installer_error) {
+  ASSERT1(installer_error);
+  if (FAILED(RegKey::GetValue(app_client_state_key,
+                              kRegValueInstallerError,
+                              installer_error))) {
+    CORE_LOG(LW, (_T("[InstallerError not found in registry]")));
+  }
+}
+
+void InstallManager::ReadInstallerResultUIStringOverride(
+    const CString& app_client_state_key,
+    CString* installer_result_uistring) {
+  ASSERT1(installer_result_uistring);
+  if (FAILED(RegKey::GetValue(app_client_state_key,
+                              kRegValueInstallerResultUIString,
+                              installer_result_uistring))) {
+    CORE_LOG(LW, (_T("[InstallerResultUIString not found in registry]")));
+  }
+}
+
+}  // namespace omaha
diff --git a/worker/install_manager.h b/worker/install_manager.h
index 7623b35..f611852 100644
--- a/worker/install_manager.h
+++ b/worker/install_manager.h
@@ -1,158 +1,158 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-

-#ifndef OMAHA_WORKER_INSTALL_MANAGER_H__

-#define OMAHA_WORKER_INSTALL_MANAGER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <queue>

-#include <utility>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/synchronized.h"

-#include "omaha/worker/job.h"

-

-namespace omaha {

-

-class Process;

-

-class InstallManager {

- public:

-  explicit InstallManager(bool is_machine);

-  HRESULT InstallJob(Job* job);

-  CompletionInfo error_info() const { return error_info_; }

-

- private:

-  // These values are a public API. Do not remove or move existing values.

-  enum InstallerResult {

-    INSTALLER_RESULT_SUCCESS = 0,

-    INSTALLER_RESULT_FAILED_CUSTOM_ERROR = 1,

-    INSTALLER_RESULT_FAILED_MSI_ERROR = 2,

-    INSTALLER_RESULT_FAILED_SYSTEM_ERROR = 3,

-    INSTALLER_RESULT_EXIT_CODE = 4,

-    INSTALLER_RESULT_DEFAULT = INSTALLER_RESULT_EXIT_CODE,

-    INSTALLER_RESULT_MAX,

-  };

-

-  // Types of installers that Omaha supports.

-  enum InstallerType {

-    UNKNOWN_INSTALLER = 0,

-    CUSTOM_INSTALLER,

-    MSI_INSTALLER,

-    MAX_INSTALLER  // Last Installer Type value.

-  };

-

-  // Gets the info about the signaled job and performs the installation.

-  HRESULT StartAndMonitorInstaller();

-

-  // Determines the executable, command line, and installer type for

-  // the installation based on the filename.

-  HRESULT BuildCommandLineFromFilename(const CString& filename,

-                                       const CString& arguments,

-                                       const CString& installer_data,

-                                       CString* executable_name,

-                                       CString* command_line,

-                                       InstallerType* installer_type);

-

-  // Executes the installer and waits for it to complete. Retries if necessary.

-  HRESULT ExecuteAndWaitForInstaller(const CString& executable_name,

-                                     const CString& command_line,

-                                     const CString& app_guid,

-                                     InstallerType installer_type);

-

-  // Executes the installer for ExecuteAndWaitForInstaller.

-  HRESULT DoExecuteAndWaitForInstaller(const CString& executable_name,

-                                       const CString& command_line,

-                                       const CString& app_guid,

-                                       InstallerType installer_type);

-

-  // Builds and returns the command line that is used to launch the msi.

-  CString BuildMsiCommandLine(const CString& arguments,

-                              const CString& filename,

-                              const CString& enclosed_installer_data_file_path);

-

-  // Determines whether the installer succeeded and returns completion info.

-  HRESULT GetInstallerResult(const CString& app_guid,

-                             InstallerType installer_type,

-                             const Process& p,

-                             CompletionInfo* completion_info);

-

-  // Does most of the work for GetInstallerResult.

-  void GetInstallerResultHelper(const CString& app_guid,

-                                InstallerType installer_type,

-                                uint32 exit_code,

-                                CompletionInfo* completion_info);

-

-  // Cleans up the registry from an installer that set custom result values.

-  void CleanupInstallerResultRegistry(const CString& app_guid);

-

-  // Executes the specified installer.

-  HRESULT DoInstallation();

-

-  // Installs the specified application and reports the results.

-  HRESULT InstallDownloadedFile();

-

-  // Validate that the installer wrote the client key and the product version.

-  HRESULT CheckApplicationRegistration(const CString& previous_version);

-

-  // TODO(omaha): consider helpers that take an app_guid and return

-  // the installer results. They might be better since they abstract out

-  // where the values are stored in registry. The current code is less

-  // encapsulated and a lot more calling code needs to change when the physical

-  // location changes in registry. Ideally only a few lines of code should

-  // change, in the event the registry location changes.

-

-  // Gets the InstallerResult type, possibly from the registry.

-  static InstallerResult GetInstallerResultType(

-      const CString& app_client_state_key);

-

-  // Reads the InstallerError value from the registry if present.

-  static void ReadInstallerErrorOverride(const CString& app_client_state_key,

-                                         DWORD* installer_error);

-

-  // Reads the InstallerResultUIString value from the registry if present.

-  static void InstallManager::ReadInstallerResultUIStringOverride(

-      const CString& app_client_state_key,

-      CString* installer_result_uistring);

-

-  // If we are installing an application.

-  bool is_installing_;

-

-  // Whether this object is running in a machine Goopdate instance.

-  bool is_machine_;

-

-  // The error information for the install.

-  CompletionInfo error_info_;

-

-  // Ensures that a single installer is run by us at a time.

-  // Not sure if we can run installers in different sessions without

-  // interference. In that case we can use a local lock instead of a

-  // global lock.

-  GLock installer_lock_;

-

-  // The job instance.

-  Job* job_;

-

-  friend class InstallManagerTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(InstallManager);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_INSTALL_MANAGER_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+
+#ifndef OMAHA_WORKER_INSTALL_MANAGER_H__
+#define OMAHA_WORKER_INSTALL_MANAGER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <queue>
+#include <utility>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/synchronized.h"
+#include "omaha/worker/job.h"
+
+namespace omaha {
+
+class Process;
+
+class InstallManager {
+ public:
+  explicit InstallManager(bool is_machine);
+  HRESULT InstallJob(Job* job);
+  CompletionInfo error_info() const { return error_info_; }
+
+ private:
+  // These values are a public API. Do not remove or move existing values.
+  enum InstallerResult {
+    INSTALLER_RESULT_SUCCESS = 0,
+    INSTALLER_RESULT_FAILED_CUSTOM_ERROR = 1,
+    INSTALLER_RESULT_FAILED_MSI_ERROR = 2,
+    INSTALLER_RESULT_FAILED_SYSTEM_ERROR = 3,
+    INSTALLER_RESULT_EXIT_CODE = 4,
+    INSTALLER_RESULT_DEFAULT = INSTALLER_RESULT_EXIT_CODE,
+    INSTALLER_RESULT_MAX,
+  };
+
+  // Types of installers that Omaha supports.
+  enum InstallerType {
+    UNKNOWN_INSTALLER = 0,
+    CUSTOM_INSTALLER,
+    MSI_INSTALLER,
+    MAX_INSTALLER  // Last Installer Type value.
+  };
+
+  // Gets the info about the signaled job and performs the installation.
+  HRESULT StartAndMonitorInstaller();
+
+  // Determines the executable, command line, and installer type for
+  // the installation based on the filename.
+  HRESULT BuildCommandLineFromFilename(const CString& filename,
+                                       const CString& arguments,
+                                       const CString& installer_data,
+                                       CString* executable_name,
+                                       CString* command_line,
+                                       InstallerType* installer_type);
+
+  // Executes the installer and waits for it to complete. Retries if necessary.
+  HRESULT ExecuteAndWaitForInstaller(const CString& executable_name,
+                                     const CString& command_line,
+                                     const CString& app_guid,
+                                     InstallerType installer_type);
+
+  // Executes the installer for ExecuteAndWaitForInstaller.
+  HRESULT DoExecuteAndWaitForInstaller(const CString& executable_name,
+                                       const CString& command_line,
+                                       const CString& app_guid,
+                                       InstallerType installer_type);
+
+  // Builds and returns the command line that is used to launch the msi.
+  CString BuildMsiCommandLine(const CString& arguments,
+                              const CString& filename,
+                              const CString& enclosed_installer_data_file_path);
+
+  // Determines whether the installer succeeded and returns completion info.
+  HRESULT GetInstallerResult(const CString& app_guid,
+                             InstallerType installer_type,
+                             const Process& p,
+                             CompletionInfo* completion_info);
+
+  // Does most of the work for GetInstallerResult.
+  void GetInstallerResultHelper(const CString& app_guid,
+                                InstallerType installer_type,
+                                uint32 exit_code,
+                                CompletionInfo* completion_info);
+
+  // Cleans up the registry from an installer that set custom result values.
+  void CleanupInstallerResultRegistry(const CString& app_guid);
+
+  // Executes the specified installer.
+  HRESULT DoInstallation();
+
+  // Installs the specified application and reports the results.
+  HRESULT InstallDownloadedFile();
+
+  // Validate that the installer wrote the client key and the product version.
+  HRESULT CheckApplicationRegistration(const CString& previous_version);
+
+  // TODO(omaha): consider helpers that take an app_guid and return
+  // the installer results. They might be better since they abstract out
+  // where the values are stored in registry. The current code is less
+  // encapsulated and a lot more calling code needs to change when the physical
+  // location changes in registry. Ideally only a few lines of code should
+  // change, in the event the registry location changes.
+
+  // Gets the InstallerResult type, possibly from the registry.
+  static InstallerResult GetInstallerResultType(
+      const CString& app_client_state_key);
+
+  // Reads the InstallerError value from the registry if present.
+  static void ReadInstallerErrorOverride(const CString& app_client_state_key,
+                                         DWORD* installer_error);
+
+  // Reads the InstallerResultUIString value from the registry if present.
+  static void InstallManager::ReadInstallerResultUIStringOverride(
+      const CString& app_client_state_key,
+      CString* installer_result_uistring);
+
+  // If we are installing an application.
+  bool is_installing_;
+
+  // Whether this object is running in a machine Goopdate instance.
+  bool is_machine_;
+
+  // The error information for the install.
+  CompletionInfo error_info_;
+
+  // Ensures that a single installer is run by us at a time.
+  // Not sure if we can run installers in different sessions without
+  // interference. In that case we can use a local lock instead of a
+  // global lock.
+  GLock installer_lock_;
+
+  // The job instance.
+  Job* job_;
+
+  friend class InstallManagerTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(InstallManager);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_INSTALL_MANAGER_H__
+
diff --git a/worker/install_manager_unittest.cc b/worker/install_manager_unittest.cc
index 6b13a83..3add208 100644
--- a/worker/install_manager_unittest.cc
+++ b/worker/install_manager_unittest.cc
@@ -1,1404 +1,1404 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <string>

-#include "omaha/common/app_util.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/reg_key.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/sta.h"

-#include "omaha/common/system.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource_manager.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/install_manager.h"

-#include "omaha/worker/ping.h"

-

-namespace {

-

-// Arbitrary values to fill in the job.

-// We use this value for all installers, including test_foo.

-const TCHAR kJobGuid[] = _T("{B18BC01B-E0BD-4BF0-A33E-1133055E5FDE}");

-const int kJobSize = 31415;

-const TCHAR kJobHash[] = _T("InvalidUnusedHashValue");

-const TCHAR kJobUrl[] = _T("invalid://url/to/nowhere/");

-

-const TCHAR kFullJobAppClientsKeyPath[] =

-    _T("HKCU\\Software\\Google\\Update\\Clients\\")

-    _T("{B18BC01B-E0BD-4BF0-A33E-1133055E5FDE}");

-const TCHAR kFullJobAppClientStateKeyPath[] =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\")

-    _T("{B18BC01B-E0BD-4BF0-A33E-1133055E5FDE}");

-const TCHAR kFullFooAppClientKeyPath[] =

-    _T("HKLM\\Software\\Google\\Update\\Clients\\")

-    _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");

-const TCHAR kFullFooAppClientStateKeyPath[] =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");

-

-const TCHAR kSetupFooV1RelativeLocation[] =

-  _T("unittest_support\\test_foo_v1.0.101.0.msi");

-const TCHAR kFooGuid[] = _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");

-const TCHAR kFooInstallerBarPropertyArg[] = _T("PROPBAR=7");

-const TCHAR kFooInstallerBarValueName[] = _T("propbar");

-

-// Meaningful values that we do something with.

-const TCHAR kJobExecutable[] = _T("cmd.exe");

-const TCHAR kExecuteCommandAndTerminateSwitch[] = _T("/c %s");

-

-const TCHAR kMsiLogFormat[] = _T("%s.log");

-

-const TCHAR kMsiUninstallArguments[] = _T("/quiet /uninstall %s");

-const TCHAR kMsiCommand[] = _T("msiexec");

-

-const DWORD kInitialErrorValue = 5;

-const TCHAR kMeaninglessErrorString[] = _T("This is an error string.");

-

-// The US English error string for ERROR_INSTALL_PACKAGE_OPEN_FAILED.

-// It is slightly different on Vista than XP - a space was removed.

-// Therefore, the comparison must ignore that space.

-const TCHAR kMsiPackageOpenFailedStringPartA[] =

-    _T("This installation package could not be opened. ");

-const TCHAR kMsiPackageOpenFailedStringPartB[] =

-    _T("Verify that the package exists and that you can access it, ")

-    _T("or contact the application vendor to verify that this is a ")

-    _T("valid Windows Installer package. ");

-

-void VerifyStringIsMsiPackageOpenFailedString(const CString& str) {

-  EXPECT_STREQ(kMsiPackageOpenFailedStringPartA,

-               str.Left(arraysize(kMsiPackageOpenFailedStringPartA) - 1));

-  EXPECT_STREQ(kMsiPackageOpenFailedStringPartB,

-               str.Right(arraysize(kMsiPackageOpenFailedStringPartB) - 1));

-}

-

-const TCHAR* const kError1603Text =

-    _T("The installer encountered error 1603: Fatal error during ")

-    _T("installation. ");

-

-const TCHAR* const kError0x800B010FText =

-    _T("The installer encountered error 0x800b010f: ")

-    _T("The certificate's CN name does not match the passed value. ");

-

-  const TCHAR* const kLaunchCmdLine =

-      _T("\"C:\\Local\\Google\\Chrome\\Application\\chrome.exe\" -home");

-

-}  // namespace

-

-namespace omaha {

-

-class InstallManagerTest : public testing::Test {

- protected:

-  explicit InstallManagerTest(bool is_machine)

-      : is_machine_(is_machine),

-        hive_override_key_name_(kRegistryHiveOverrideRoot) {

-  }

-

-  virtual void SetUp() {

-    install_manager_.reset(new InstallManager(is_machine_));

-

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    OverrideRegistryHivesWithExecutionPermissions(hive_override_key_name_);

-

-    ResourceManager manager(is_machine_, app_util::GetCurrentModuleDirectory());

-    ASSERT_SUCCEEDED(manager.LoadResourceDll(_T("en")));

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-  }

-

-  void SetInstallManagerJob(Job* job) {

-    ASSERT_TRUE(job);

-    install_manager_->job_ = job;

-  }

-

-  HRESULT CheckApplicationRegistration(const CString& previous_version,

-                                       Job* job) {

-    ASSERT1(job);

-    install_manager_->job_ = job;

-    return install_manager_->CheckApplicationRegistration(previous_version);

-  }

-

-  void SetUpdateResponseDataArguments(const CString& arguments, Job* job) {

-    ASSERT1(job);

-    job->update_response_data_.set_arguments(arguments);

-  }

-

-  void SetupInstallerResultRegistry(const CString& app_guid,

-                                    bool set_installer_result,

-                                    DWORD installer_result,

-                                    bool set_installer_error,

-                                    DWORD installer_error,

-                                    bool set_installer_result_uistring,

-                                    const CString& installer_result_uistring,

-                                    bool set_installer_launch_cmd_line,

-                                    const CString& installer_launch_cmd_line) {

-    CString app_client_state_key =

-        goopdate_utils::GetAppClientStateKey(is_machine_, app_guid);

-    RegKey::CreateKey(app_client_state_key);

-    if (set_installer_result) {

-      RegKey::SetValue(app_client_state_key,

-                       kRegValueInstallerResult,

-                       installer_result);

-    }

-

-    if (set_installer_error) {

-      RegKey::SetValue(app_client_state_key,

-                       kRegValueInstallerError,

-                       installer_error);

-    }

-

-    if (set_installer_result_uistring) {

-      RegKey::SetValue(app_client_state_key,

-                       kRegValueInstallerResultUIString,

-                       installer_result_uistring);

-    }

-

-    if (set_installer_launch_cmd_line) {

-      RegKey::SetValue(app_client_state_key,

-                       kRegValueInstallerSuccessLaunchCmdLine,

-                       installer_launch_cmd_line);

-    }

-  }

-

-  void VerifyLastRegistryValues(const CString& app_guid,

-                                bool expect_installer_result,

-                                DWORD expected_installer_result,

-                                bool expect_installer_error,

-                                DWORD expected_installer_error,

-                                bool expect_installer_result_uistring,

-                                const CString& expected_result_uistring,

-                                bool expect_installer_launch_cmd_line,

-                                const CString& expected_launch_cmd_line) {

-    ASSERT_TRUE(expect_installer_result || !expected_installer_result);

-    ASSERT_TRUE(expect_installer_error || !expected_installer_error);

-    ASSERT_TRUE(expect_installer_result_uistring ||

-                expected_result_uistring.IsEmpty());

-    ASSERT_TRUE(expect_installer_launch_cmd_line ||

-                expected_launch_cmd_line.IsEmpty());

-

-    CString app_client_state_key =

-        goopdate_utils::GetAppClientStateKey(is_machine_, app_guid);

-    EXPECT_FALSE(RegKey::HasValue(app_client_state_key,

-                                  kRegValueInstallerResult));

-    EXPECT_FALSE(RegKey::HasValue(app_client_state_key,

-                                  kRegValueInstallerError));

-    EXPECT_FALSE(RegKey::HasValue(app_client_state_key,

-                                  kRegValueInstallerResultUIString));

-

-    if (expect_installer_result) {

-      EXPECT_TRUE(RegKey::HasValue(app_client_state_key,

-                                   kRegValueLastInstallerResult));

-      DWORD last_installer_result = 0;

-      EXPECT_SUCCEEDED(RegKey::GetValue(app_client_state_key,

-                                        kRegValueLastInstallerResult,

-                                        &last_installer_result));

-      EXPECT_EQ(expected_installer_result, last_installer_result);

-    } else {

-      EXPECT_FALSE(RegKey::HasValue(app_client_state_key,

-                                    kRegValueLastInstallerResult));

-    }

-

-    if (expect_installer_error) {

-      EXPECT_TRUE(RegKey::HasValue(app_client_state_key,

-                                   kRegValueLastInstallerError));

-      DWORD last_installer_error = 0;

-      EXPECT_SUCCEEDED(RegKey::GetValue(app_client_state_key,

-                                        kRegValueLastInstallerError,

-                                        &last_installer_error));

-      EXPECT_EQ(expected_installer_error, last_installer_error);

-    } else {

-      EXPECT_FALSE(RegKey::HasValue(app_client_state_key,

-                                    kRegValueLastInstallerError));

-    }

-

-    if (expect_installer_result_uistring) {

-      EXPECT_TRUE(RegKey::HasValue(app_client_state_key,

-                                   kRegValueLastInstallerResultUIString));

-      CString last_installer_result_uistring;

-      EXPECT_SUCCEEDED(RegKey::GetValue(app_client_state_key,

-                                        kRegValueLastInstallerResultUIString,

-                                        &last_installer_result_uistring));

-      EXPECT_STREQ(expected_result_uistring,

-                   last_installer_result_uistring);

-    } else {

-      EXPECT_FALSE(RegKey::HasValue(app_client_state_key,

-                                    kRegValueLastInstallerResultUIString));

-    }

-

-    if (expect_installer_launch_cmd_line) {

-      EXPECT_TRUE(RegKey::HasValue(app_client_state_key,

-                                   kRegValueLastInstallerSuccessLaunchCmdLine));

-      CString last_installer_launch_cmd_line;

-      EXPECT_SUCCEEDED(

-          RegKey::GetValue(app_client_state_key,

-                           kRegValueLastInstallerSuccessLaunchCmdLine,

-                           &last_installer_launch_cmd_line));

-      EXPECT_STREQ(expected_launch_cmd_line,

-                   last_installer_launch_cmd_line);

-    } else {

-      EXPECT_FALSE(RegKey::HasValue(

-          app_client_state_key,

-          kRegValueLastInstallerSuccessLaunchCmdLine));

-    }

-  }

-

-  void VerifyNoLastRegistryValues(const CString& app_guid) {

-    VerifyLastRegistryValues(app_guid,

-                             false, 0,

-                             false, 0,

-                             false, _T(""),

-                             false, _T(""));

-  }

-

-  void GetInstallerResultHelper(const CString& app_guid,

-                                int installer_type,

-                                uint32 exit_code,

-                                CompletionInfo* completion_info) {

-    install_manager_->GetInstallerResultHelper(

-        app_guid,

-        static_cast<InstallManager::InstallerType>(installer_type),

-        exit_code,

-        completion_info);

-  }

-

-  static const int kResultSuccess = InstallManager::INSTALLER_RESULT_SUCCESS;

-  static const int kResultFailedCustomError =

-      InstallManager::INSTALLER_RESULT_FAILED_CUSTOM_ERROR;

-  static const int kResultFailedMsiError =

-      InstallManager::INSTALLER_RESULT_FAILED_MSI_ERROR;

-  static const int kResultFailedSystemError =

-      InstallManager::INSTALLER_RESULT_FAILED_SYSTEM_ERROR;

-  static const int kResultExitCode = InstallManager::INSTALLER_RESULT_EXIT_CODE;

-

-  static const int kMsiInstaller = InstallManager::MSI_INSTALLER;

-  static const int kOtherInstaller = InstallManager::CUSTOM_INSTALLER;

-

-  bool is_machine_;

-  CString hive_override_key_name_;

-  scoped_ptr<InstallManager> install_manager_;

-  Ping ping_;

-};

-

-class InstallManagerMachineTest : public InstallManagerTest {

- protected:

-  InstallManagerMachineTest()

-    : InstallManagerTest(true) {

-  }

-};

-

-class InstallManagerUserTest : public InstallManagerTest {

- protected:

-  InstallManagerUserTest()

-    : InstallManagerTest(false) {

-  }

-};

-

-class InstallManagerUserGetInstallerResultHelperTest

-    : public InstallManagerUserTest {

- protected:

-  InstallManagerUserGetInstallerResultHelperTest()

-      : InstallManagerUserTest() {

-  }

-

-  virtual void SetUp() {

-    InstallManagerUserTest::SetUp();

-

-    completion_info_.error_code = kInitialErrorValue;

-    completion_info_.text = kMeaninglessErrorString;

-

-    job_.reset(new Job(false, &ping_));

-    SetInstallManagerJob(job_.get());

-  }

-

-  CompletionInfo completion_info_;

-  scoped_ptr<Job> job_;

-};

-

-

-//

-// Helper method tests

-//

-

-bool GetMessageForSystemErrorCode(DWORD system_error_code, CString* message);

-

-TEST(InstallManagerTest, TestGetMessageForSystemErrorCode) {

-  CString message;

-

-  EXPECT_TRUE(GetMessageForSystemErrorCode(ERROR_INSTALL_PACKAGE_OPEN_FAILED,

-                                           &message));

-  VerifyStringIsMsiPackageOpenFailedString(message);

-}

-

-TEST_F(InstallManagerUserTest,

-       CheckApplicationRegistration_InstallFailsWhenClientsKeyAbsent) {

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_app_data(app_data);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY,

-            CheckApplicationRegistration(CString(), &job));

-

-  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientStateKeyPath));

-}

-

-TEST_F(InstallManagerUserTest,

-       CheckApplicationRegistration_InstallFailsWhenVersionValueAbsent) {

-  ASSERT_SUCCEEDED(RegKey::CreateKey(kFullJobAppClientsKeyPath));

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_app_data(app_data);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY,

-            CheckApplicationRegistration(CString(), &job));

-

-  EXPECT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientStateKeyPath));

-}

-

-TEST_F(InstallManagerUserTest,

-       CheckApplicationRegistration_InstallSucceedsWhenStateKeyAbsent) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,

-                                    kRegValueProductVersion,

-                                    _T("0.9.68.4")));

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_app_data(app_data);

-

-  EXPECT_SUCCEEDED(CheckApplicationRegistration(CString(), &job));

-}

-

-TEST_F(InstallManagerUserTest,

-       CheckApplicationRegistration_InstallSucceedsWhenStateKeyPresent) {

-  const TCHAR* keys_to_create[] = {kFullJobAppClientsKeyPath,

-                                   kFullJobAppClientStateKeyPath};

-  ASSERT_SUCCEEDED(RegKey::CreateKeys(keys_to_create, 2));

-  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientStateKeyPath));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,

-                                    kRegValueProductVersion,

-                                    _T("0.9.70.0")));

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_app_data(app_data);

-

-  // The install should succeed even if the version is the same.

-  EXPECT_SUCCEEDED(CheckApplicationRegistration(_T("0.9.70.0"), &job));

-}

-

-TEST_F(InstallManagerUserTest, CheckApplicationRegistration_UpdateSucceeds) {

-  const TCHAR* keys_to_create[] = {kFullJobAppClientsKeyPath,

-                                   kFullJobAppClientStateKeyPath};

-  ASSERT_SUCCEEDED(RegKey::CreateKeys(keys_to_create, 2));

-  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientStateKeyPath));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,

-                                    kRegValueProductVersion,

-                                    _T("0.9.70.0")));

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(true, &ping_);

-  job.set_is_background(true);

-  job.set_app_data(app_data);

-

-  EXPECT_SUCCEEDED(CheckApplicationRegistration(_T("0.9.70.1"), &job));

-}

-

-TEST_F(InstallManagerUserTest,

-       CheckApplicationRegistration_UpdateFailsWhenVersionDoesNotChange) {

-  const TCHAR* keys_to_create[] = {kFullJobAppClientsKeyPath,

-                                   kFullJobAppClientStateKeyPath};

-  ASSERT_SUCCEEDED(RegKey::CreateKeys(keys_to_create,

-                                      arraysize(keys_to_create)));

-  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientStateKeyPath));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,

-                                    kRegValueProductVersion,

-                                    _T("0.9.70.0")));

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(true, &ping_);

-  job.set_is_background(true);

-  job.set_app_data(app_data);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_CHANGE_VERSION,

-            CheckApplicationRegistration(_T("0.9.70.0"), &job));

-}

-

-//

-// Negative Tests

-//

-

-TEST_F(InstallManagerUserTest, InstallJob_InstallerWithoutFilenameExtension) {

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_download_file_name(_T("foo"));

-  job.set_app_data(app_data);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID,

-            install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);

-  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, completion_info.error_code);

-  EXPECT_STREQ(_T("The installer filename foo is invalid or unsupported."),

-               completion_info.text);

-}

-

-TEST_F(InstallManagerUserTest,

-       InstallJob_UnsupportedInstallerFilenameExtension) {

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_download_file_name(_T("foo.bar"));

-  job.set_app_data(app_data);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID,

-            install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);

-  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, completion_info.error_code);

-  EXPECT_STREQ(_T("The installer filename foo.bar is invalid or unsupported."),

-               completion_info.text);

-}

-

-TEST_F(InstallManagerUserTest, InstallJob_InstallerEmtpyFilename) {

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_app_data(app_data);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID,

-            install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);

-  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, completion_info.error_code);

-  EXPECT_STREQ(_T("The installer filename  is invalid or unsupported."),

-               completion_info.text);

-}

-

-TEST_F(InstallManagerUserTest, InstallJob_ExeFileDoesNotExist) {

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_download_file_name(_T("foo.exe"));

-  job.set_app_data(app_data);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START,

-            install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START,

-            completion_info.error_code);

-  EXPECT_STREQ(_T("The installer failed to start."), completion_info.text);

-

-  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientStateKeyPath));

-}

-

-//

-// MSI Installer Fails Tests

-//

-

-TEST_F(InstallManagerUserTest, InstallJob_MsiFileDoesNotExist) {

-  const TCHAR kLogFileName[] = _T("foo.msi.log");

-  const TCHAR kExpectedErrorStringPartA[] =

-      _T("The installer encountered error 1619: ");

-  const int kExpectedErrorStringPartALength =

-      arraysize(kExpectedErrorStringPartA) - 1;

-

-  ASSERT_SUCCEEDED(File::Remove(kLogFileName));

-  ASSERT_FALSE(File::Exists(kLogFileName));

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_download_file_name(_T("foo.msi"));

-  job.set_app_data(app_data);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED,

-            install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info.status);

-  EXPECT_EQ(ERROR_INSTALL_PACKAGE_OPEN_FAILED, completion_info.error_code);

-  EXPECT_STREQ(kExpectedErrorStringPartA,

-               completion_info.text.Left(kExpectedErrorStringPartALength));

-  VerifyStringIsMsiPackageOpenFailedString(

-      completion_info.text.Mid(kExpectedErrorStringPartALength));

-

-  // msiexec creates an empty log file.

-  EXPECT_TRUE(File::Exists(kLogFileName));

-  EXPECT_SUCCEEDED(File::Remove(kLogFileName));

-}

-

-//

-// EXE Installer Tests

-//

-

-// This test uses cmd.exe as an installer that leaves the payload

-// kPayloadFileName.

-TEST_F(InstallManagerUserTest, InstallJob_ExeInstallerWithArgumentsSucceeds) {

-  const TCHAR kPayloadFileName[] = _T("exe_payload.txt");

-  const TCHAR kCommandToExecute[] = _T("echo \"hi\" > %s");

-

-  CString full_command_to_execute;

-  full_command_to_execute.Format(kCommandToExecute, kPayloadFileName);

-  CString arguments;

-  arguments.Format(kExecuteCommandAndTerminateSwitch, full_command_to_execute);

-

-  ASSERT_SUCCEEDED(File::Remove(kPayloadFileName));

-  ASSERT_FALSE(File::Exists(kPayloadFileName));

-

-  // Create the Clients key since this isn't an actual installer.

-  ASSERT_SUCCEEDED(RegKey::CreateKey(kFullJobAppClientsKeyPath));

-  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,

-                                    kRegValueProductVersion,

-                                    _T("0.10.69.5")));

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  app_data.set_display_name(_T("Exe App"));

-  Job job(false, &ping_);

-  job.set_download_file_name(kJobExecutable);

-  job.set_app_data(app_data);

-  SetUpdateResponseDataArguments(arguments, &job);

-

-  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(S_OK, completion_info.error_code);

-  EXPECT_STREQ(_T("Thanks for installing Exe App."), completion_info.text);

-

-  EXPECT_TRUE(File::Exists(kPayloadFileName));

-  EXPECT_SUCCEEDED(File::Remove(kPayloadFileName));

-}

-

-// The command we execute causes an exit code of 1 because the F and B colors

-// are the same.

-TEST_F(InstallManagerUserTest, InstallJob_ExeInstallerReturnsNonZeroExitCode) {

-  const TCHAR kCommandToExecute[] = _T("color 00");

-

-  CString arguments;

-  arguments.Format(kExecuteCommandAndTerminateSwitch, kCommandToExecute);

-

-  // Create the Clients key since this isn't an actual installer.

-  ASSERT_SUCCEEDED(RegKey::CreateKey(kFullJobAppClientsKeyPath));

-  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,

-                                    kRegValueProductVersion,

-                                    _T("0.10.69.5")));

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_download_file_name(kJobExecutable);

-  job.set_app_data(app_data);

-  SetUpdateResponseDataArguments(arguments, &job);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED,

-            install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info.status);

-  EXPECT_EQ(1, completion_info.error_code);

-  EXPECT_STREQ(_T("The installer encountered error 1."),

-               completion_info.text);

-}

-

-/* TODO(omaha): Figure out a way to perform this test.

-   CleanupInstallerResultRegistry clears the result values it sets.

-   TODO(omaha): Add another test that reports an error in using registry API.

-// Also tests that the launch cmd is set.

-TEST_F(InstallManagerUserTest,

-       InstallJob_ExeInstallerReturnsNonZeroExitCode_InstallerResultSuccess) {

-  const TCHAR kCommandToExecute[] = _T("color 00");

-

-  CString arguments;

-  arguments.Format(kExecuteCommandAndTerminateSwitch, kCommandToExecute);

-

-  // Create the Clients key since this isn't an actual installer.

-  ASSERT_SUCCEEDED(RegKey::CreateKey(kFullJobAppClientsKeyPath));

-  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,

-                                    kRegValueProductVersion,

-                                    _T("0.10.69.5")));

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultSuccess,

-                               false, 0,

-                               false, _T(""),

-                               true, kLaunchCmdLine);

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  app_data.set_display_name(_T("color 00"));

-  Job job(false, &ping_);

-  job.set_download_file_name(kJobExecutable);

-  job.set_app_data(app_data);

-  SetUpdateResponseDataArguments(arguments, &job);

-

-  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(1, completion_info.error_code);

-  EXPECT_STREQ(_T("Thanks for installing color 00."), completion_info.text);

-  EXPECT_STREQ(kLaunchCmdLine, job.launch_cmd_line());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultSuccess,

-                           false, 0,

-                           false, _T(""),

-                           true, kLaunchCmdLine);

-}

-*/

-

-TEST_F(InstallManagerMachineTest, InstallJob_MsiInstallerSucceeds) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-  const TCHAR expected_iid_string[] =

-      _T("{BF66411E-8FAC-4E2C-920C-849DF562621C}");

-  const GUID expected_iid = StringToGuid(expected_iid_string);

-

-  // We can't fake the registry keys because we are interacting with a real

-  // installer.

-  RestoreRegistryHives();

-

-  CString installer_full_path(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      kSetupFooV1RelativeLocation));

-  ASSERT_TRUE(File::Exists(installer_full_path));

-

-  CString installer_log_full_path;

-  installer_log_full_path.Format(kMsiLogFormat, installer_full_path);

-

-  ASSERT_SUCCEEDED(File::Remove(installer_log_full_path));

-  ASSERT_FALSE(File::Exists(installer_log_full_path));

-

-  RegKey::DeleteKey(kFullFooAppClientKeyPath);

-  ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath));

-  RegKey::DeleteKey(kFullFooAppClientStateKeyPath);

-  ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));

-

-  AppData app_data(StringToGuid(kFooGuid), is_machine_);

-  app_data.set_display_name(_T("Foo"));

-  app_data.set_language(_T("en"));

-  app_data.set_ap(_T("test_ap"));

-  app_data.set_tt_token(_T("test_tt_token"));

-  app_data.set_iid(expected_iid);

-  app_data.set_brand_code(_T("GOOG"));

-  app_data.set_client_id(_T("_some_partner"));

-

-  Job job(false, &ping_);

-  job.set_download_file_name(installer_full_path);

-  job.set_app_data(app_data);

-

-  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(S_OK, completion_info.error_code);

-  EXPECT_STREQ(_T("Thanks for installing Foo."), completion_info.text);

-

-  EXPECT_TRUE(File::Exists(installer_log_full_path));

-

-  EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientKeyPath));

-  EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));

-  // Verify the value that is written based on an MSI property we didn't

-  // specify wasn't written.

-  EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientKeyPath,

-                                kFooInstallerBarValueName));

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kFullFooAppClientKeyPath));

-

-  CString uninstall_arguments;

-  uninstall_arguments.Format(kMsiUninstallArguments, installer_full_path);

-  EXPECT_SUCCEEDED(System::ShellExecuteProcess(kMsiCommand,

-                                               uninstall_arguments,

-                                               NULL,

-                                               NULL));

-}

-

-TEST_F(InstallManagerMachineTest, InstallJob_MsiInstallerWithArgumentSucceeds) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  // We can't fake the registry keys because we are interacting with a real

-  // installer.

-  RestoreRegistryHives();

-

-  CString installer_full_path(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      kSetupFooV1RelativeLocation));

-  ASSERT_TRUE(File::Exists(installer_full_path));

-

-  CString installer_log_full_path;

-  installer_log_full_path.Format(kMsiLogFormat, installer_full_path);

-

-  ASSERT_SUCCEEDED(File::Remove(installer_log_full_path));

-  ASSERT_FALSE(File::Exists(installer_log_full_path));

-

-  RegKey::DeleteKey(kFullFooAppClientKeyPath);

-  ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath));

-  RegKey::DeleteKey(kFullFooAppClientStateKeyPath);

-  ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));

-

-  AppData app_data(StringToGuid(kFooGuid), is_machine_);

-  app_data.set_display_name(_T("Foo"));

-  app_data.set_language(_T("en"));

-  Job job(false, &ping_);

-  job.set_download_file_name(installer_full_path);

-  job.set_app_data(app_data);

-  SetUpdateResponseDataArguments(kFooInstallerBarPropertyArg, &job);

-

-  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(S_OK, completion_info.error_code);

-  EXPECT_STREQ(_T("Thanks for installing Foo."), completion_info.text);

-

-  EXPECT_TRUE(File::Exists(installer_log_full_path));

-

-  EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientKeyPath));

-  EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));

-  EXPECT_TRUE(RegKey::HasValue(kFullFooAppClientKeyPath,

-                               kFooInstallerBarValueName));

-  DWORD barprop_value;

-  EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientKeyPath,

-                                    kFooInstallerBarValueName,

-                                    &barprop_value));

-  EXPECT_EQ(7, barprop_value);

-

-  EXPECT_SUCCEEDED(RegKey::DeleteKey(kFullFooAppClientKeyPath));

-

-  CString uninstall_arguments;

-  uninstall_arguments.Format(kMsiUninstallArguments, installer_full_path);

-  EXPECT_SUCCEEDED(System::ShellExecuteProcess(kMsiCommand,

-                                               uninstall_arguments,

-                                               NULL,

-                                               NULL));

-}

-

-// The use of kGoogleUpdateAppId is the key to this test.

-// Note that the version is not changed - this is the normal self-update case.

-// Among other things, this test verifies that CheckApplicationRegistration() is

-// not called for self-updates.

-TEST_F(InstallManagerUserTest, InstallJob_UpdateOmahaSucceeds) {

-  CString arguments;

-  arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi"));

-

-  const CString kExistingVersion(_T("0.9.69.5"));

-

-  AppData app_data(kGoopdateGuid, is_machine_);

-  app_data.set_previous_version(kExistingVersion);

-  Job job(true, &ping_);

-  job.set_is_background(true);

-  job.set_download_file_name(kJobExecutable);

-  job.set_app_data(app_data);

-  SetUpdateResponseDataArguments(arguments, &job);

-

-  // Because we don't actually run the Omaha installer, we need to make sure

-  // its Clients key and pv value exist to avoid an error.

-  ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENTS_GOOPDATE));

-  ASSERT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    kExistingVersion));

-

-  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(S_OK, completion_info.error_code);

-  // The user never sees this, but it is odd we put this text in the structure.

-  EXPECT_STREQ(_T("Thanks for installing ."), completion_info.text);

-

-  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));

-  CString version;

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENTS_GOOPDATE,

-                                    kRegValueProductVersion,

-                                    &version));

-  EXPECT_STREQ(kExistingVersion, version);

-}

-

-// The main purpose of this test is to ensure that self-updates don't fail if

-// Omaha's Clients key doesn't exist for some reason.

-// In other words, it tests that CheckApplicationRegistration() is not called.

-TEST_F(InstallManagerUserTest,

-       InstallJob_UpdateOmahaSucceedsWhenClientsKeyAbsent) {

-  CString arguments;

-  arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi"));

-

-  const CString kExistingVersion(_T("0.9.69.5"));

-

-  AppData app_data(kGoopdateGuid, is_machine_);

-  app_data.set_previous_version(kExistingVersion);

-  Job job(true, &ping_);

-  job.set_is_background(true);

-  job.set_download_file_name(kJobExecutable);

-  job.set_app_data(app_data);

-  SetUpdateResponseDataArguments(arguments, &job);

-

-  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));

-

-  EXPECT_FALSE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));

-}

-

-TEST_F(InstallManagerUserTest, InstallJob_InstallerDoesNotWriteClientsKey) {

-  CString arguments;

-  arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi"));

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  app_data.set_display_name(_T("Some App"));

-  Job job(false, &ping_);

-  job.set_download_file_name(kJobExecutable);

-  job.set_app_data(app_data);

-  SetUpdateResponseDataArguments(arguments, &job);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY,

-            install_manager_->InstallJob(&job));

-

-  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientStateKeyPath));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY,

-            completion_info.error_code);

-  EXPECT_STREQ(

-      _T("Installation failed. Please try again. Error code = 0x80040905"),

-      completion_info.text);}

-

-TEST_F(InstallManagerUserTest, InstallJob_InstallerFailureMsiFileDoesNotExist) {

-  const TCHAR kLogFileName[] = _T("foo.msi.log");

-  const TCHAR kExpectedErrorStringPartA[] =

-      _T("The installer encountered error 1619: ");

-  const int kExpectedErrorStringPartALength =

-      arraysize(kExpectedErrorStringPartA) - 1;

-

-  ASSERT_SUCCEEDED(File::Remove(kLogFileName));

-  ASSERT_FALSE(File::Exists(kLogFileName));

-

-  AppData app_data(StringToGuid(kJobGuid), is_machine_);

-  Job job(false, &ping_);

-  job.set_download_file_name(_T("foo.msi"));

-  job.set_app_data(app_data);

-

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED,

-            install_manager_->InstallJob(&job));

-

-  const CompletionInfo completion_info = install_manager_->error_info();

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info.status);

-  EXPECT_EQ(ERROR_INSTALL_PACKAGE_OPEN_FAILED, completion_info.error_code);

-  EXPECT_STREQ(kExpectedErrorStringPartA,

-            completion_info.text.Left(kExpectedErrorStringPartALength));

-  VerifyStringIsMsiPackageOpenFailedString(

-      completion_info.text.Mid(kExpectedErrorStringPartALength));

-

-  // msiexec creates an empty log file.

-  EXPECT_TRUE(File::Exists(kLogFileName));

-  EXPECT_SUCCEEDED(File::Remove(kLogFileName));

-

-  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientsKeyPath));

-  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientStateKeyPath));

-}

-

-//

-// GetInstallerResultHelper tests

-//

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_NoRegistry_MSI_ZeroExitCode) {

-  GetInstallerResultHelper(kJobGuid, kMsiInstaller, 0, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info_.status);

-  EXPECT_EQ(0, completion_info_.error_code);

-  EXPECT_TRUE(completion_info_.text.IsEmpty());

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyNoLastRegistryValues(kJobGuid);

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_NoRegistry_MSI_NonZeroExitCode) {

-  GetInstallerResultHelper(kJobGuid, kMsiInstaller, 1603, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info_.status);

-  EXPECT_EQ(1603, completion_info_.error_code);

-  EXPECT_STREQ(kError1603Text, completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyNoLastRegistryValues(kJobGuid);

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_NoRegistry_EXE_ZeroExitCode) {

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 0, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info_.status);

-  EXPECT_EQ(0, completion_info_.error_code);

-  EXPECT_TRUE(completion_info_.text.IsEmpty());

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyNoLastRegistryValues(kJobGuid);

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_NoRegistry_EXE_NonZeroExitCode_SmallNumber) {

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 8, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info_.status);

-  EXPECT_EQ(8, completion_info_.error_code);

-  EXPECT_STREQ(_T("The installer encountered error 8."), completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyNoLastRegistryValues(kJobGuid);

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_NoRegistry_EXE_NonZeroExitCode_HRESULTFailure) {

-  GetInstallerResultHelper(

-      kJobGuid, kOtherInstaller, 0x80004005, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info_.status);

-  EXPECT_EQ(0x80004005, completion_info_.error_code);

-  EXPECT_STREQ(_T("The installer encountered error 0x80004005."),

-               completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyNoLastRegistryValues(kJobGuid);

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_ExitCode_MSI) {

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultExitCode,

-                               false, 0,

-                               false, _T(""),

-                               false, _T(""));

-

-  GetInstallerResultHelper(kJobGuid, kMsiInstaller, 1603, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info_.status);

-  EXPECT_EQ(1603, completion_info_.error_code);

-  EXPECT_STREQ(kError1603Text, completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultExitCode,

-                           false, 0,

-                           false, _T(""),

-                           false, _T(""));

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_NoRegistry_MSI_RebootRequired) {

-  GetInstallerResultHelper(kJobGuid,

-                           kMsiInstaller,

-                           ERROR_SUCCESS_REBOOT_REQUIRED,

-                           &completion_info_);

-

-  EXPECT_EQ(COMPLETION_SUCCESS_REBOOT_REQUIRED, completion_info_.status);

-  EXPECT_EQ(0, completion_info_.error_code);

-  EXPECT_TRUE(completion_info_.text.IsEmpty());

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyNoLastRegistryValues(kJobGuid);

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_SystemError_EXE_RebootRequired) {

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedSystemError,

-                               true, ERROR_SUCCESS_REBOOT_REQUIRED,

-                               false, _T(""),

-                               true, kLaunchCmdLine);

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_SUCCESS_REBOOT_REQUIRED, completion_info_.status);

-  EXPECT_EQ(0, completion_info_.error_code);

-  EXPECT_TRUE(completion_info_.text.IsEmpty());

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty()) <<

-      _T("Command line is not supported with reboot.");

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedSystemError,

-                           true, ERROR_SUCCESS_REBOOT_REQUIRED,

-                           false, _T(""),

-                           true, kLaunchCmdLine);

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_Success_NoErrorCode) {

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultSuccess,

-                               false, 0,

-                               false, _T(""),

-                               false, _T(""));

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 99, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info_.status);

-  EXPECT_EQ(99, completion_info_.error_code);

-  EXPECT_TRUE(completion_info_.text.IsEmpty());

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultSuccess,

-                           false, 0,

-                           false, _T(""),

-                           false, _T(""));

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_Success_AllValues) {

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultSuccess,

-                               true, 555,

-                               true, _T("an ignored error"),

-                               true, kLaunchCmdLine);

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 99, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info_.status);

-  EXPECT_EQ(555, completion_info_.error_code) <<

-      _T("InstallerError overwrites exit code.");

-  EXPECT_TRUE(completion_info_.text.IsEmpty()) <<

-      _T("UIString is ignored for Success.");

-  EXPECT_STREQ(kLaunchCmdLine, job_->launch_cmd_line());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultSuccess,

-                           true, 555,

-                           true, _T("an ignored error"),

-                           true, kLaunchCmdLine);

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_LaunchCmdOnly_MSI_ZeroExitCode) {

-  SetupInstallerResultRegistry(kJobGuid,

-                               false, 0,

-                               false, 0,

-                               false, _T(""),

-                               true, kLaunchCmdLine);

-

-  GetInstallerResultHelper(kJobGuid, kMsiInstaller, 0, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info_.status);

-  EXPECT_EQ(0, completion_info_.error_code);

-  EXPECT_TRUE(completion_info_.text.IsEmpty());

-  EXPECT_STREQ(kLaunchCmdLine, job_->launch_cmd_line());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           false, 0,

-                           false, 0,

-                           false, _T(""),

-                           true, kLaunchCmdLine);

-}

-

-// Exit code is used when no error code is present. It's interpreted as a system

-// error even though the installer is not an MSI.

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_Failed_NoErrorCodeOrUiString) {

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedCustomError,

-                               false, 0,

-                               false, _T(""),

-                               false, _T(""));

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 8, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info_.status);

-  EXPECT_EQ(8, completion_info_.error_code);

-  EXPECT_STREQ(_T("The installer encountered error 8."), completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedCustomError,

-                           false, 0,

-                           false, _T(""),

-                           false, _T(""));

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_Failed_WithErrorCode) {

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedCustomError,

-                               true, 8,

-                               false, _T(""),

-                               false, _T(""));

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info_.status);

-  EXPECT_EQ(8, completion_info_.error_code);

-  EXPECT_STREQ(_T("The installer encountered error 8."), completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedCustomError,

-                           true, 8,

-                           false, _T(""),

-                           false, _T(""));

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_Failed_AllValues) {

-  const DWORD kInstallerErrorValue = 8;

-  const TCHAR* const kUiString = _T("a message from the installer");

-

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedCustomError,

-                               true, kInstallerErrorValue,

-                               true, kUiString,

-                               true, kLaunchCmdLine);

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info_.status);

-  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);

-  EXPECT_STREQ(kUiString, completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty()) <<

-      _T("Command line is not supported with errors.");

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedCustomError,

-                           true, kInstallerErrorValue,

-                           true, kUiString,

-                           true, kLaunchCmdLine);

-}

-

-// Exit code is used and interpreted as MSI error when no error code present.

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_FailedMsiError_NoErrorCode) {

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedMsiError,

-                               false, 0,

-                               false, _T(""),

-                               false, _T(""));

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1603, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info_.status);

-  EXPECT_EQ(1603, completion_info_.error_code);

-  EXPECT_STREQ(kError1603Text, completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedMsiError,

-                           false, 0,

-                           false, _T(""),

-                           false, _T(""));

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_FailedMsiError_WithErrorCode) {

-  const DWORD kInstallerErrorValue = 1603;

-

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedMsiError,

-                               true, kInstallerErrorValue,

-                               false, _T(""),

-                               false, _T(""));

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info_.status);

-  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);

-  EXPECT_STREQ(kError1603Text, completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedMsiError,

-                           true, kInstallerErrorValue,

-                           false, _T(""),

-                           false, _T(""));

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_FailedMsiError_AllValues) {

-  const DWORD kInstallerErrorValue = 1603;

-

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedMsiError,

-                               true, kInstallerErrorValue,

-                               true, _T("an ignored error"),

-                               true, kLaunchCmdLine);

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info_.status);

-  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);

-  EXPECT_STREQ(kError1603Text, completion_info_.text) <<

-      _T("UIString is ignored.");

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty()) <<

-      _T("Command line is not supported with errors.");

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedMsiError,

-                           true, kInstallerErrorValue,

-                           true, _T("an ignored error"),

-                           true, kLaunchCmdLine);

-}

-

-// Exit code is used and interpreted as system error when no error code present.

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_FailedSystemError_NoErrorCode) {

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedSystemError,

-                               false, 0,

-                               false, _T(""),

-                               false, _T(""));

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1603, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_SYSTEM, completion_info_.status);

-  EXPECT_EQ(1603, completion_info_.error_code);

-  EXPECT_STREQ(kError1603Text, completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedSystemError,

-                           false, 0,

-                           false, _T(""),

-                           false, _T(""));

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_FailedSystemError_WithErrorCode) {

-  const DWORD kInstallerErrorValue = 1603;

-

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedSystemError,

-                               true, kInstallerErrorValue,

-                               false, _T(""),

-                               false, _T(""));

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_SYSTEM, completion_info_.status);

-  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);

-  EXPECT_STREQ(kError1603Text, completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedSystemError,

-                           true, kInstallerErrorValue,

-                           false, _T(""),

-                           false, _T(""));

-}

-

-// INSTALLER_RESULT_FAILED_SYSTEM_ERROR supports values beyond the basic

-// "System Error Codes" and their HRESULT equivalents.

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_FailedSystemError_WithHRESULTSystemError) {

-  const DWORD kInstallerErrorValue = 0x800B010F;

-

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedSystemError,

-                               true, kInstallerErrorValue,

-                               false, _T(""),

-                               false, _T(""));

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_SYSTEM, completion_info_.status);

-  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);

-  EXPECT_STREQ(kError0x800B010FText, completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedSystemError,

-                           true, kInstallerErrorValue,

-                           false, _T(""),

-                           false, _T(""));

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_FailedSystemError_WithUnrecognizedError) {

-  const DWORD kInstallerErrorValue = 0x80040200;

-

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedSystemError,

-                               true, kInstallerErrorValue,

-                               false, _T(""),

-                               false, _T(""));

-

-  // GetMessageForSystemErrorCode expects a valid system error.

-  ExpectAsserts expect_asserts;

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_SYSTEM, completion_info_.status);

-  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);

-  EXPECT_STREQ(_T("The installer encountered error 0x80040200."),

-               completion_info_.text);

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedSystemError,

-                           true, kInstallerErrorValue,

-                           false, _T(""),

-                           false, _T(""));

-}

-

-TEST_F(InstallManagerUserGetInstallerResultHelperTest,

-       GetInstallerResultHelper_FailedSystemError_AllValues) {

-  const DWORD kInstallerErrorValue = 1603;

-

-  SetupInstallerResultRegistry(kJobGuid,

-                               true, kResultFailedSystemError,

-                               true, kInstallerErrorValue,

-                               true, _T("an ignored error"),

-                               true, kLaunchCmdLine);

-

-  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);

-

-  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_SYSTEM, completion_info_.status);

-  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);

-  EXPECT_STREQ(kError1603Text, completion_info_.text) <<

-      _T("UIString is ignored.");

-  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty()) <<

-      _T("Command line is not supported with errors.");

-

-  VerifyLastRegistryValues(kJobGuid,

-                           true, kResultFailedSystemError,

-                           true, kInstallerErrorValue,

-                           true, _T("an ignored error"),

-                           true, kLaunchCmdLine);

-}

-

-// TODO(omaha): Add a machine test.

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <string>
+#include "omaha/common/app_util.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/reg_key.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/sta.h"
+#include "omaha/common/system.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource_manager.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/install_manager.h"
+#include "omaha/worker/ping.h"
+
+namespace {
+
+// Arbitrary values to fill in the job.
+// We use this value for all installers, including test_foo.
+const TCHAR kJobGuid[] = _T("{B18BC01B-E0BD-4BF0-A33E-1133055E5FDE}");
+const int kJobSize = 31415;
+const TCHAR kJobHash[] = _T("InvalidUnusedHashValue");
+const TCHAR kJobUrl[] = _T("invalid://url/to/nowhere/");
+
+const TCHAR kFullJobAppClientsKeyPath[] =
+    _T("HKCU\\Software\\Google\\Update\\Clients\\")
+    _T("{B18BC01B-E0BD-4BF0-A33E-1133055E5FDE}");
+const TCHAR kFullJobAppClientStateKeyPath[] =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\")
+    _T("{B18BC01B-E0BD-4BF0-A33E-1133055E5FDE}");
+const TCHAR kFullFooAppClientKeyPath[] =
+    _T("HKLM\\Software\\Google\\Update\\Clients\\")
+    _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");
+const TCHAR kFullFooAppClientStateKeyPath[] =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");
+
+const TCHAR kSetupFooV1RelativeLocation[] =
+  _T("unittest_support\\test_foo_v1.0.101.0.msi");
+const TCHAR kFooGuid[] = _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");
+const TCHAR kFooInstallerBarPropertyArg[] = _T("PROPBAR=7");
+const TCHAR kFooInstallerBarValueName[] = _T("propbar");
+
+// Meaningful values that we do something with.
+const TCHAR kJobExecutable[] = _T("cmd.exe");
+const TCHAR kExecuteCommandAndTerminateSwitch[] = _T("/c %s");
+
+const TCHAR kMsiLogFormat[] = _T("%s.log");
+
+const TCHAR kMsiUninstallArguments[] = _T("/quiet /uninstall %s");
+const TCHAR kMsiCommand[] = _T("msiexec");
+
+const DWORD kInitialErrorValue = 5;
+const TCHAR kMeaninglessErrorString[] = _T("This is an error string.");
+
+// The US English error string for ERROR_INSTALL_PACKAGE_OPEN_FAILED.
+// It is slightly different on Vista than XP - a space was removed.
+// Therefore, the comparison must ignore that space.
+const TCHAR kMsiPackageOpenFailedStringPartA[] =
+    _T("This installation package could not be opened. ");
+const TCHAR kMsiPackageOpenFailedStringPartB[] =
+    _T("Verify that the package exists and that you can access it, ")
+    _T("or contact the application vendor to verify that this is a ")
+    _T("valid Windows Installer package. ");
+
+void VerifyStringIsMsiPackageOpenFailedString(const CString& str) {
+  EXPECT_STREQ(kMsiPackageOpenFailedStringPartA,
+               str.Left(arraysize(kMsiPackageOpenFailedStringPartA) - 1));
+  EXPECT_STREQ(kMsiPackageOpenFailedStringPartB,
+               str.Right(arraysize(kMsiPackageOpenFailedStringPartB) - 1));
+}
+
+const TCHAR* const kError1603Text =
+    _T("The installer encountered error 1603: Fatal error during ")
+    _T("installation. ");
+
+const TCHAR* const kError0x800B010FText =
+    _T("The installer encountered error 0x800b010f: ")
+    _T("The certificate's CN name does not match the passed value. ");
+
+  const TCHAR* const kLaunchCmdLine =
+      _T("\"C:\\Local\\Google\\Chrome\\Application\\chrome.exe\" -home");
+
+}  // namespace
+
+namespace omaha {
+
+class InstallManagerTest : public testing::Test {
+ protected:
+  explicit InstallManagerTest(bool is_machine)
+      : is_machine_(is_machine),
+        hive_override_key_name_(kRegistryHiveOverrideRoot) {
+  }
+
+  virtual void SetUp() {
+    install_manager_.reset(new InstallManager(is_machine_));
+
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    OverrideRegistryHivesWithExecutionPermissions(hive_override_key_name_);
+
+    ResourceManager manager(is_machine_, app_util::GetCurrentModuleDirectory());
+    ASSERT_SUCCEEDED(manager.LoadResourceDll(_T("en")));
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+  }
+
+  void SetInstallManagerJob(Job* job) {
+    ASSERT_TRUE(job);
+    install_manager_->job_ = job;
+  }
+
+  HRESULT CheckApplicationRegistration(const CString& previous_version,
+                                       Job* job) {
+    ASSERT1(job);
+    install_manager_->job_ = job;
+    return install_manager_->CheckApplicationRegistration(previous_version);
+  }
+
+  void SetUpdateResponseDataArguments(const CString& arguments, Job* job) {
+    ASSERT1(job);
+    job->update_response_data_.set_arguments(arguments);
+  }
+
+  void SetupInstallerResultRegistry(const CString& app_guid,
+                                    bool set_installer_result,
+                                    DWORD installer_result,
+                                    bool set_installer_error,
+                                    DWORD installer_error,
+                                    bool set_installer_result_uistring,
+                                    const CString& installer_result_uistring,
+                                    bool set_installer_launch_cmd_line,
+                                    const CString& installer_launch_cmd_line) {
+    CString app_client_state_key =
+        goopdate_utils::GetAppClientStateKey(is_machine_, app_guid);
+    RegKey::CreateKey(app_client_state_key);
+    if (set_installer_result) {
+      RegKey::SetValue(app_client_state_key,
+                       kRegValueInstallerResult,
+                       installer_result);
+    }
+
+    if (set_installer_error) {
+      RegKey::SetValue(app_client_state_key,
+                       kRegValueInstallerError,
+                       installer_error);
+    }
+
+    if (set_installer_result_uistring) {
+      RegKey::SetValue(app_client_state_key,
+                       kRegValueInstallerResultUIString,
+                       installer_result_uistring);
+    }
+
+    if (set_installer_launch_cmd_line) {
+      RegKey::SetValue(app_client_state_key,
+                       kRegValueInstallerSuccessLaunchCmdLine,
+                       installer_launch_cmd_line);
+    }
+  }
+
+  void VerifyLastRegistryValues(const CString& app_guid,
+                                bool expect_installer_result,
+                                DWORD expected_installer_result,
+                                bool expect_installer_error,
+                                DWORD expected_installer_error,
+                                bool expect_installer_result_uistring,
+                                const CString& expected_result_uistring,
+                                bool expect_installer_launch_cmd_line,
+                                const CString& expected_launch_cmd_line) {
+    ASSERT_TRUE(expect_installer_result || !expected_installer_result);
+    ASSERT_TRUE(expect_installer_error || !expected_installer_error);
+    ASSERT_TRUE(expect_installer_result_uistring ||
+                expected_result_uistring.IsEmpty());
+    ASSERT_TRUE(expect_installer_launch_cmd_line ||
+                expected_launch_cmd_line.IsEmpty());
+
+    CString app_client_state_key =
+        goopdate_utils::GetAppClientStateKey(is_machine_, app_guid);
+    EXPECT_FALSE(RegKey::HasValue(app_client_state_key,
+                                  kRegValueInstallerResult));
+    EXPECT_FALSE(RegKey::HasValue(app_client_state_key,
+                                  kRegValueInstallerError));
+    EXPECT_FALSE(RegKey::HasValue(app_client_state_key,
+                                  kRegValueInstallerResultUIString));
+
+    if (expect_installer_result) {
+      EXPECT_TRUE(RegKey::HasValue(app_client_state_key,
+                                   kRegValueLastInstallerResult));
+      DWORD last_installer_result = 0;
+      EXPECT_SUCCEEDED(RegKey::GetValue(app_client_state_key,
+                                        kRegValueLastInstallerResult,
+                                        &last_installer_result));
+      EXPECT_EQ(expected_installer_result, last_installer_result);
+    } else {
+      EXPECT_FALSE(RegKey::HasValue(app_client_state_key,
+                                    kRegValueLastInstallerResult));
+    }
+
+    if (expect_installer_error) {
+      EXPECT_TRUE(RegKey::HasValue(app_client_state_key,
+                                   kRegValueLastInstallerError));
+      DWORD last_installer_error = 0;
+      EXPECT_SUCCEEDED(RegKey::GetValue(app_client_state_key,
+                                        kRegValueLastInstallerError,
+                                        &last_installer_error));
+      EXPECT_EQ(expected_installer_error, last_installer_error);
+    } else {
+      EXPECT_FALSE(RegKey::HasValue(app_client_state_key,
+                                    kRegValueLastInstallerError));
+    }
+
+    if (expect_installer_result_uistring) {
+      EXPECT_TRUE(RegKey::HasValue(app_client_state_key,
+                                   kRegValueLastInstallerResultUIString));
+      CString last_installer_result_uistring;
+      EXPECT_SUCCEEDED(RegKey::GetValue(app_client_state_key,
+                                        kRegValueLastInstallerResultUIString,
+                                        &last_installer_result_uistring));
+      EXPECT_STREQ(expected_result_uistring,
+                   last_installer_result_uistring);
+    } else {
+      EXPECT_FALSE(RegKey::HasValue(app_client_state_key,
+                                    kRegValueLastInstallerResultUIString));
+    }
+
+    if (expect_installer_launch_cmd_line) {
+      EXPECT_TRUE(RegKey::HasValue(app_client_state_key,
+                                   kRegValueLastInstallerSuccessLaunchCmdLine));
+      CString last_installer_launch_cmd_line;
+      EXPECT_SUCCEEDED(
+          RegKey::GetValue(app_client_state_key,
+                           kRegValueLastInstallerSuccessLaunchCmdLine,
+                           &last_installer_launch_cmd_line));
+      EXPECT_STREQ(expected_launch_cmd_line,
+                   last_installer_launch_cmd_line);
+    } else {
+      EXPECT_FALSE(RegKey::HasValue(
+          app_client_state_key,
+          kRegValueLastInstallerSuccessLaunchCmdLine));
+    }
+  }
+
+  void VerifyNoLastRegistryValues(const CString& app_guid) {
+    VerifyLastRegistryValues(app_guid,
+                             false, 0,
+                             false, 0,
+                             false, _T(""),
+                             false, _T(""));
+  }
+
+  void GetInstallerResultHelper(const CString& app_guid,
+                                int installer_type,
+                                uint32 exit_code,
+                                CompletionInfo* completion_info) {
+    install_manager_->GetInstallerResultHelper(
+        app_guid,
+        static_cast<InstallManager::InstallerType>(installer_type),
+        exit_code,
+        completion_info);
+  }
+
+  static const int kResultSuccess = InstallManager::INSTALLER_RESULT_SUCCESS;
+  static const int kResultFailedCustomError =
+      InstallManager::INSTALLER_RESULT_FAILED_CUSTOM_ERROR;
+  static const int kResultFailedMsiError =
+      InstallManager::INSTALLER_RESULT_FAILED_MSI_ERROR;
+  static const int kResultFailedSystemError =
+      InstallManager::INSTALLER_RESULT_FAILED_SYSTEM_ERROR;
+  static const int kResultExitCode = InstallManager::INSTALLER_RESULT_EXIT_CODE;
+
+  static const int kMsiInstaller = InstallManager::MSI_INSTALLER;
+  static const int kOtherInstaller = InstallManager::CUSTOM_INSTALLER;
+
+  bool is_machine_;
+  CString hive_override_key_name_;
+  scoped_ptr<InstallManager> install_manager_;
+  Ping ping_;
+};
+
+class InstallManagerMachineTest : public InstallManagerTest {
+ protected:
+  InstallManagerMachineTest()
+    : InstallManagerTest(true) {
+  }
+};
+
+class InstallManagerUserTest : public InstallManagerTest {
+ protected:
+  InstallManagerUserTest()
+    : InstallManagerTest(false) {
+  }
+};
+
+class InstallManagerUserGetInstallerResultHelperTest
+    : public InstallManagerUserTest {
+ protected:
+  InstallManagerUserGetInstallerResultHelperTest()
+      : InstallManagerUserTest() {
+  }
+
+  virtual void SetUp() {
+    InstallManagerUserTest::SetUp();
+
+    completion_info_.error_code = kInitialErrorValue;
+    completion_info_.text = kMeaninglessErrorString;
+
+    job_.reset(new Job(false, &ping_));
+    SetInstallManagerJob(job_.get());
+  }
+
+  CompletionInfo completion_info_;
+  scoped_ptr<Job> job_;
+};
+
+
+//
+// Helper method tests
+//
+
+bool GetMessageForSystemErrorCode(DWORD system_error_code, CString* message);
+
+TEST(InstallManagerTest, TestGetMessageForSystemErrorCode) {
+  CString message;
+
+  EXPECT_TRUE(GetMessageForSystemErrorCode(ERROR_INSTALL_PACKAGE_OPEN_FAILED,
+                                           &message));
+  VerifyStringIsMsiPackageOpenFailedString(message);
+}
+
+TEST_F(InstallManagerUserTest,
+       CheckApplicationRegistration_InstallFailsWhenClientsKeyAbsent) {
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_app_data(app_data);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY,
+            CheckApplicationRegistration(CString(), &job));
+
+  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientStateKeyPath));
+}
+
+TEST_F(InstallManagerUserTest,
+       CheckApplicationRegistration_InstallFailsWhenVersionValueAbsent) {
+  ASSERT_SUCCEEDED(RegKey::CreateKey(kFullJobAppClientsKeyPath));
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_app_data(app_data);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY,
+            CheckApplicationRegistration(CString(), &job));
+
+  EXPECT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientStateKeyPath));
+}
+
+TEST_F(InstallManagerUserTest,
+       CheckApplicationRegistration_InstallSucceedsWhenStateKeyAbsent) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,
+                                    kRegValueProductVersion,
+                                    _T("0.9.68.4")));
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_app_data(app_data);
+
+  EXPECT_SUCCEEDED(CheckApplicationRegistration(CString(), &job));
+}
+
+TEST_F(InstallManagerUserTest,
+       CheckApplicationRegistration_InstallSucceedsWhenStateKeyPresent) {
+  const TCHAR* keys_to_create[] = {kFullJobAppClientsKeyPath,
+                                   kFullJobAppClientStateKeyPath};
+  ASSERT_SUCCEEDED(RegKey::CreateKeys(keys_to_create, 2));
+  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientStateKeyPath));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,
+                                    kRegValueProductVersion,
+                                    _T("0.9.70.0")));
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_app_data(app_data);
+
+  // The install should succeed even if the version is the same.
+  EXPECT_SUCCEEDED(CheckApplicationRegistration(_T("0.9.70.0"), &job));
+}
+
+TEST_F(InstallManagerUserTest, CheckApplicationRegistration_UpdateSucceeds) {
+  const TCHAR* keys_to_create[] = {kFullJobAppClientsKeyPath,
+                                   kFullJobAppClientStateKeyPath};
+  ASSERT_SUCCEEDED(RegKey::CreateKeys(keys_to_create, 2));
+  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientStateKeyPath));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,
+                                    kRegValueProductVersion,
+                                    _T("0.9.70.0")));
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(true, &ping_);
+  job.set_is_background(true);
+  job.set_app_data(app_data);
+
+  EXPECT_SUCCEEDED(CheckApplicationRegistration(_T("0.9.70.1"), &job));
+}
+
+TEST_F(InstallManagerUserTest,
+       CheckApplicationRegistration_UpdateFailsWhenVersionDoesNotChange) {
+  const TCHAR* keys_to_create[] = {kFullJobAppClientsKeyPath,
+                                   kFullJobAppClientStateKeyPath};
+  ASSERT_SUCCEEDED(RegKey::CreateKeys(keys_to_create,
+                                      arraysize(keys_to_create)));
+  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientStateKeyPath));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,
+                                    kRegValueProductVersion,
+                                    _T("0.9.70.0")));
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(true, &ping_);
+  job.set_is_background(true);
+  job.set_app_data(app_data);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_CHANGE_VERSION,
+            CheckApplicationRegistration(_T("0.9.70.0"), &job));
+}
+
+//
+// Negative Tests
+//
+
+TEST_F(InstallManagerUserTest, InstallJob_InstallerWithoutFilenameExtension) {
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_download_file_name(_T("foo"));
+  job.set_app_data(app_data);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID,
+            install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);
+  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, completion_info.error_code);
+  EXPECT_STREQ(_T("The installer filename foo is invalid or unsupported."),
+               completion_info.text);
+}
+
+TEST_F(InstallManagerUserTest,
+       InstallJob_UnsupportedInstallerFilenameExtension) {
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_download_file_name(_T("foo.bar"));
+  job.set_app_data(app_data);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID,
+            install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);
+  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, completion_info.error_code);
+  EXPECT_STREQ(_T("The installer filename foo.bar is invalid or unsupported."),
+               completion_info.text);
+}
+
+TEST_F(InstallManagerUserTest, InstallJob_InstallerEmtpyFilename) {
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_app_data(app_data);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID,
+            install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);
+  EXPECT_EQ(GOOPDATEINSTALL_E_FILENAME_INVALID, completion_info.error_code);
+  EXPECT_STREQ(_T("The installer filename  is invalid or unsupported."),
+               completion_info.text);
+}
+
+TEST_F(InstallManagerUserTest, InstallJob_ExeFileDoesNotExist) {
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_download_file_name(_T("foo.exe"));
+  job.set_app_data(app_data);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START,
+            install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START,
+            completion_info.error_code);
+  EXPECT_STREQ(_T("The installer failed to start."), completion_info.text);
+
+  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientStateKeyPath));
+}
+
+//
+// MSI Installer Fails Tests
+//
+
+TEST_F(InstallManagerUserTest, InstallJob_MsiFileDoesNotExist) {
+  const TCHAR kLogFileName[] = _T("foo.msi.log");
+  const TCHAR kExpectedErrorStringPartA[] =
+      _T("The installer encountered error 1619: ");
+  const int kExpectedErrorStringPartALength =
+      arraysize(kExpectedErrorStringPartA) - 1;
+
+  ASSERT_SUCCEEDED(File::Remove(kLogFileName));
+  ASSERT_FALSE(File::Exists(kLogFileName));
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_download_file_name(_T("foo.msi"));
+  job.set_app_data(app_data);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED,
+            install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info.status);
+  EXPECT_EQ(ERROR_INSTALL_PACKAGE_OPEN_FAILED, completion_info.error_code);
+  EXPECT_STREQ(kExpectedErrorStringPartA,
+               completion_info.text.Left(kExpectedErrorStringPartALength));
+  VerifyStringIsMsiPackageOpenFailedString(
+      completion_info.text.Mid(kExpectedErrorStringPartALength));
+
+  // msiexec creates an empty log file.
+  EXPECT_TRUE(File::Exists(kLogFileName));
+  EXPECT_SUCCEEDED(File::Remove(kLogFileName));
+}
+
+//
+// EXE Installer Tests
+//
+
+// This test uses cmd.exe as an installer that leaves the payload
+// kPayloadFileName.
+TEST_F(InstallManagerUserTest, InstallJob_ExeInstallerWithArgumentsSucceeds) {
+  const TCHAR kPayloadFileName[] = _T("exe_payload.txt");
+  const TCHAR kCommandToExecute[] = _T("echo \"hi\" > %s");
+
+  CString full_command_to_execute;
+  full_command_to_execute.Format(kCommandToExecute, kPayloadFileName);
+  CString arguments;
+  arguments.Format(kExecuteCommandAndTerminateSwitch, full_command_to_execute);
+
+  ASSERT_SUCCEEDED(File::Remove(kPayloadFileName));
+  ASSERT_FALSE(File::Exists(kPayloadFileName));
+
+  // Create the Clients key since this isn't an actual installer.
+  ASSERT_SUCCEEDED(RegKey::CreateKey(kFullJobAppClientsKeyPath));
+  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,
+                                    kRegValueProductVersion,
+                                    _T("0.10.69.5")));
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  app_data.set_display_name(_T("Exe App"));
+  Job job(false, &ping_);
+  job.set_download_file_name(kJobExecutable);
+  job.set_app_data(app_data);
+  SetUpdateResponseDataArguments(arguments, &job);
+
+  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(S_OK, completion_info.error_code);
+  EXPECT_STREQ(_T("Thanks for installing Exe App."), completion_info.text);
+
+  EXPECT_TRUE(File::Exists(kPayloadFileName));
+  EXPECT_SUCCEEDED(File::Remove(kPayloadFileName));
+}
+
+// The command we execute causes an exit code of 1 because the F and B colors
+// are the same.
+TEST_F(InstallManagerUserTest, InstallJob_ExeInstallerReturnsNonZeroExitCode) {
+  const TCHAR kCommandToExecute[] = _T("color 00");
+
+  CString arguments;
+  arguments.Format(kExecuteCommandAndTerminateSwitch, kCommandToExecute);
+
+  // Create the Clients key since this isn't an actual installer.
+  ASSERT_SUCCEEDED(RegKey::CreateKey(kFullJobAppClientsKeyPath));
+  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,
+                                    kRegValueProductVersion,
+                                    _T("0.10.69.5")));
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_download_file_name(kJobExecutable);
+  job.set_app_data(app_data);
+  SetUpdateResponseDataArguments(arguments, &job);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED,
+            install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info.status);
+  EXPECT_EQ(1, completion_info.error_code);
+  EXPECT_STREQ(_T("The installer encountered error 1."),
+               completion_info.text);
+}
+
+/* TODO(omaha): Figure out a way to perform this test.
+   CleanupInstallerResultRegistry clears the result values it sets.
+   TODO(omaha): Add another test that reports an error in using registry API.
+// Also tests that the launch cmd is set.
+TEST_F(InstallManagerUserTest,
+       InstallJob_ExeInstallerReturnsNonZeroExitCode_InstallerResultSuccess) {
+  const TCHAR kCommandToExecute[] = _T("color 00");
+
+  CString arguments;
+  arguments.Format(kExecuteCommandAndTerminateSwitch, kCommandToExecute);
+
+  // Create the Clients key since this isn't an actual installer.
+  ASSERT_SUCCEEDED(RegKey::CreateKey(kFullJobAppClientsKeyPath));
+  ASSERT_TRUE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kFullJobAppClientsKeyPath,
+                                    kRegValueProductVersion,
+                                    _T("0.10.69.5")));
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultSuccess,
+                               false, 0,
+                               false, _T(""),
+                               true, kLaunchCmdLine);
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  app_data.set_display_name(_T("color 00"));
+  Job job(false, &ping_);
+  job.set_download_file_name(kJobExecutable);
+  job.set_app_data(app_data);
+  SetUpdateResponseDataArguments(arguments, &job);
+
+  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(1, completion_info.error_code);
+  EXPECT_STREQ(_T("Thanks for installing color 00."), completion_info.text);
+  EXPECT_STREQ(kLaunchCmdLine, job.launch_cmd_line());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultSuccess,
+                           false, 0,
+                           false, _T(""),
+                           true, kLaunchCmdLine);
+}
+*/
+
+TEST_F(InstallManagerMachineTest, InstallJob_MsiInstallerSucceeds) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+  const TCHAR expected_iid_string[] =
+      _T("{BF66411E-8FAC-4E2C-920C-849DF562621C}");
+  const GUID expected_iid = StringToGuid(expected_iid_string);
+
+  // We can't fake the registry keys because we are interacting with a real
+  // installer.
+  RestoreRegistryHives();
+
+  CString installer_full_path(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      kSetupFooV1RelativeLocation));
+  ASSERT_TRUE(File::Exists(installer_full_path));
+
+  CString installer_log_full_path;
+  installer_log_full_path.Format(kMsiLogFormat, installer_full_path);
+
+  ASSERT_SUCCEEDED(File::Remove(installer_log_full_path));
+  ASSERT_FALSE(File::Exists(installer_log_full_path));
+
+  RegKey::DeleteKey(kFullFooAppClientKeyPath);
+  ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath));
+  RegKey::DeleteKey(kFullFooAppClientStateKeyPath);
+  ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));
+
+  AppData app_data(StringToGuid(kFooGuid), is_machine_);
+  app_data.set_display_name(_T("Foo"));
+  app_data.set_language(_T("en"));
+  app_data.set_ap(_T("test_ap"));
+  app_data.set_tt_token(_T("test_tt_token"));
+  app_data.set_iid(expected_iid);
+  app_data.set_brand_code(_T("GOOG"));
+  app_data.set_client_id(_T("_some_partner"));
+
+  Job job(false, &ping_);
+  job.set_download_file_name(installer_full_path);
+  job.set_app_data(app_data);
+
+  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(S_OK, completion_info.error_code);
+  EXPECT_STREQ(_T("Thanks for installing Foo."), completion_info.text);
+
+  EXPECT_TRUE(File::Exists(installer_log_full_path));
+
+  EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientKeyPath));
+  EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));
+  // Verify the value that is written based on an MSI property we didn't
+  // specify wasn't written.
+  EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientKeyPath,
+                                kFooInstallerBarValueName));
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kFullFooAppClientKeyPath));
+
+  CString uninstall_arguments;
+  uninstall_arguments.Format(kMsiUninstallArguments, installer_full_path);
+  EXPECT_SUCCEEDED(System::ShellExecuteProcess(kMsiCommand,
+                                               uninstall_arguments,
+                                               NULL,
+                                               NULL));
+}
+
+TEST_F(InstallManagerMachineTest, InstallJob_MsiInstallerWithArgumentSucceeds) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  // We can't fake the registry keys because we are interacting with a real
+  // installer.
+  RestoreRegistryHives();
+
+  CString installer_full_path(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      kSetupFooV1RelativeLocation));
+  ASSERT_TRUE(File::Exists(installer_full_path));
+
+  CString installer_log_full_path;
+  installer_log_full_path.Format(kMsiLogFormat, installer_full_path);
+
+  ASSERT_SUCCEEDED(File::Remove(installer_log_full_path));
+  ASSERT_FALSE(File::Exists(installer_log_full_path));
+
+  RegKey::DeleteKey(kFullFooAppClientKeyPath);
+  ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath));
+  RegKey::DeleteKey(kFullFooAppClientStateKeyPath);
+  ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));
+
+  AppData app_data(StringToGuid(kFooGuid), is_machine_);
+  app_data.set_display_name(_T("Foo"));
+  app_data.set_language(_T("en"));
+  Job job(false, &ping_);
+  job.set_download_file_name(installer_full_path);
+  job.set_app_data(app_data);
+  SetUpdateResponseDataArguments(kFooInstallerBarPropertyArg, &job);
+
+  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(S_OK, completion_info.error_code);
+  EXPECT_STREQ(_T("Thanks for installing Foo."), completion_info.text);
+
+  EXPECT_TRUE(File::Exists(installer_log_full_path));
+
+  EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientKeyPath));
+  EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));
+  EXPECT_TRUE(RegKey::HasValue(kFullFooAppClientKeyPath,
+                               kFooInstallerBarValueName));
+  DWORD barprop_value;
+  EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientKeyPath,
+                                    kFooInstallerBarValueName,
+                                    &barprop_value));
+  EXPECT_EQ(7, barprop_value);
+
+  EXPECT_SUCCEEDED(RegKey::DeleteKey(kFullFooAppClientKeyPath));
+
+  CString uninstall_arguments;
+  uninstall_arguments.Format(kMsiUninstallArguments, installer_full_path);
+  EXPECT_SUCCEEDED(System::ShellExecuteProcess(kMsiCommand,
+                                               uninstall_arguments,
+                                               NULL,
+                                               NULL));
+}
+
+// The use of kGoogleUpdateAppId is the key to this test.
+// Note that the version is not changed - this is the normal self-update case.
+// Among other things, this test verifies that CheckApplicationRegistration() is
+// not called for self-updates.
+TEST_F(InstallManagerUserTest, InstallJob_UpdateOmahaSucceeds) {
+  CString arguments;
+  arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi"));
+
+  const CString kExistingVersion(_T("0.9.69.5"));
+
+  AppData app_data(kGoopdateGuid, is_machine_);
+  app_data.set_previous_version(kExistingVersion);
+  Job job(true, &ping_);
+  job.set_is_background(true);
+  job.set_download_file_name(kJobExecutable);
+  job.set_app_data(app_data);
+  SetUpdateResponseDataArguments(arguments, &job);
+
+  // Because we don't actually run the Omaha installer, we need to make sure
+  // its Clients key and pv value exist to avoid an error.
+  ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENTS_GOOPDATE));
+  ASSERT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    kExistingVersion));
+
+  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(S_OK, completion_info.error_code);
+  // The user never sees this, but it is odd we put this text in the structure.
+  EXPECT_STREQ(_T("Thanks for installing ."), completion_info.text);
+
+  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));
+  CString version;
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENTS_GOOPDATE,
+                                    kRegValueProductVersion,
+                                    &version));
+  EXPECT_STREQ(kExistingVersion, version);
+}
+
+// The main purpose of this test is to ensure that self-updates don't fail if
+// Omaha's Clients key doesn't exist for some reason.
+// In other words, it tests that CheckApplicationRegistration() is not called.
+TEST_F(InstallManagerUserTest,
+       InstallJob_UpdateOmahaSucceedsWhenClientsKeyAbsent) {
+  CString arguments;
+  arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi"));
+
+  const CString kExistingVersion(_T("0.9.69.5"));
+
+  AppData app_data(kGoopdateGuid, is_machine_);
+  app_data.set_previous_version(kExistingVersion);
+  Job job(true, &ping_);
+  job.set_is_background(true);
+  job.set_download_file_name(kJobExecutable);
+  job.set_app_data(app_data);
+  SetUpdateResponseDataArguments(arguments, &job);
+
+  EXPECT_SUCCEEDED(install_manager_->InstallJob(&job));
+
+  EXPECT_FALSE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));
+}
+
+TEST_F(InstallManagerUserTest, InstallJob_InstallerDoesNotWriteClientsKey) {
+  CString arguments;
+  arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi"));
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  app_data.set_display_name(_T("Some App"));
+  Job job(false, &ping_);
+  job.set_download_file_name(kJobExecutable);
+  job.set_app_data(app_data);
+  SetUpdateResponseDataArguments(arguments, &job);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY,
+            install_manager_->InstallJob(&job));
+
+  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientStateKeyPath));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_DID_NOT_WRITE_CLIENT_KEY,
+            completion_info.error_code);
+  EXPECT_STREQ(
+      _T("Installation failed. Please try again. Error code = 0x80040905"),
+      completion_info.text);}
+
+TEST_F(InstallManagerUserTest, InstallJob_InstallerFailureMsiFileDoesNotExist) {
+  const TCHAR kLogFileName[] = _T("foo.msi.log");
+  const TCHAR kExpectedErrorStringPartA[] =
+      _T("The installer encountered error 1619: ");
+  const int kExpectedErrorStringPartALength =
+      arraysize(kExpectedErrorStringPartA) - 1;
+
+  ASSERT_SUCCEEDED(File::Remove(kLogFileName));
+  ASSERT_FALSE(File::Exists(kLogFileName));
+
+  AppData app_data(StringToGuid(kJobGuid), is_machine_);
+  Job job(false, &ping_);
+  job.set_download_file_name(_T("foo.msi"));
+  job.set_app_data(app_data);
+
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED,
+            install_manager_->InstallJob(&job));
+
+  const CompletionInfo completion_info = install_manager_->error_info();
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info.status);
+  EXPECT_EQ(ERROR_INSTALL_PACKAGE_OPEN_FAILED, completion_info.error_code);
+  EXPECT_STREQ(kExpectedErrorStringPartA,
+            completion_info.text.Left(kExpectedErrorStringPartALength));
+  VerifyStringIsMsiPackageOpenFailedString(
+      completion_info.text.Mid(kExpectedErrorStringPartALength));
+
+  // msiexec creates an empty log file.
+  EXPECT_TRUE(File::Exists(kLogFileName));
+  EXPECT_SUCCEEDED(File::Remove(kLogFileName));
+
+  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientsKeyPath));
+  EXPECT_FALSE(RegKey::HasKey(kFullJobAppClientStateKeyPath));
+}
+
+//
+// GetInstallerResultHelper tests
+//
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_NoRegistry_MSI_ZeroExitCode) {
+  GetInstallerResultHelper(kJobGuid, kMsiInstaller, 0, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info_.status);
+  EXPECT_EQ(0, completion_info_.error_code);
+  EXPECT_TRUE(completion_info_.text.IsEmpty());
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyNoLastRegistryValues(kJobGuid);
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_NoRegistry_MSI_NonZeroExitCode) {
+  GetInstallerResultHelper(kJobGuid, kMsiInstaller, 1603, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info_.status);
+  EXPECT_EQ(1603, completion_info_.error_code);
+  EXPECT_STREQ(kError1603Text, completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyNoLastRegistryValues(kJobGuid);
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_NoRegistry_EXE_ZeroExitCode) {
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 0, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info_.status);
+  EXPECT_EQ(0, completion_info_.error_code);
+  EXPECT_TRUE(completion_info_.text.IsEmpty());
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyNoLastRegistryValues(kJobGuid);
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_NoRegistry_EXE_NonZeroExitCode_SmallNumber) {
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 8, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info_.status);
+  EXPECT_EQ(8, completion_info_.error_code);
+  EXPECT_STREQ(_T("The installer encountered error 8."), completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyNoLastRegistryValues(kJobGuid);
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_NoRegistry_EXE_NonZeroExitCode_HRESULTFailure) {
+  GetInstallerResultHelper(
+      kJobGuid, kOtherInstaller, 0x80004005, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info_.status);
+  EXPECT_EQ(0x80004005, completion_info_.error_code);
+  EXPECT_STREQ(_T("The installer encountered error 0x80004005."),
+               completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyNoLastRegistryValues(kJobGuid);
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_ExitCode_MSI) {
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultExitCode,
+                               false, 0,
+                               false, _T(""),
+                               false, _T(""));
+
+  GetInstallerResultHelper(kJobGuid, kMsiInstaller, 1603, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info_.status);
+  EXPECT_EQ(1603, completion_info_.error_code);
+  EXPECT_STREQ(kError1603Text, completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultExitCode,
+                           false, 0,
+                           false, _T(""),
+                           false, _T(""));
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_NoRegistry_MSI_RebootRequired) {
+  GetInstallerResultHelper(kJobGuid,
+                           kMsiInstaller,
+                           ERROR_SUCCESS_REBOOT_REQUIRED,
+                           &completion_info_);
+
+  EXPECT_EQ(COMPLETION_SUCCESS_REBOOT_REQUIRED, completion_info_.status);
+  EXPECT_EQ(0, completion_info_.error_code);
+  EXPECT_TRUE(completion_info_.text.IsEmpty());
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyNoLastRegistryValues(kJobGuid);
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_SystemError_EXE_RebootRequired) {
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedSystemError,
+                               true, ERROR_SUCCESS_REBOOT_REQUIRED,
+                               false, _T(""),
+                               true, kLaunchCmdLine);
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_SUCCESS_REBOOT_REQUIRED, completion_info_.status);
+  EXPECT_EQ(0, completion_info_.error_code);
+  EXPECT_TRUE(completion_info_.text.IsEmpty());
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty()) <<
+      _T("Command line is not supported with reboot.");
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedSystemError,
+                           true, ERROR_SUCCESS_REBOOT_REQUIRED,
+                           false, _T(""),
+                           true, kLaunchCmdLine);
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_Success_NoErrorCode) {
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultSuccess,
+                               false, 0,
+                               false, _T(""),
+                               false, _T(""));
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 99, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info_.status);
+  EXPECT_EQ(99, completion_info_.error_code);
+  EXPECT_TRUE(completion_info_.text.IsEmpty());
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultSuccess,
+                           false, 0,
+                           false, _T(""),
+                           false, _T(""));
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_Success_AllValues) {
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultSuccess,
+                               true, 555,
+                               true, _T("an ignored error"),
+                               true, kLaunchCmdLine);
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 99, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info_.status);
+  EXPECT_EQ(555, completion_info_.error_code) <<
+      _T("InstallerError overwrites exit code.");
+  EXPECT_TRUE(completion_info_.text.IsEmpty()) <<
+      _T("UIString is ignored for Success.");
+  EXPECT_STREQ(kLaunchCmdLine, job_->launch_cmd_line());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultSuccess,
+                           true, 555,
+                           true, _T("an ignored error"),
+                           true, kLaunchCmdLine);
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_LaunchCmdOnly_MSI_ZeroExitCode) {
+  SetupInstallerResultRegistry(kJobGuid,
+                               false, 0,
+                               false, 0,
+                               false, _T(""),
+                               true, kLaunchCmdLine);
+
+  GetInstallerResultHelper(kJobGuid, kMsiInstaller, 0, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info_.status);
+  EXPECT_EQ(0, completion_info_.error_code);
+  EXPECT_TRUE(completion_info_.text.IsEmpty());
+  EXPECT_STREQ(kLaunchCmdLine, job_->launch_cmd_line());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           false, 0,
+                           false, 0,
+                           false, _T(""),
+                           true, kLaunchCmdLine);
+}
+
+// Exit code is used when no error code is present. It's interpreted as a system
+// error even though the installer is not an MSI.
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_Failed_NoErrorCodeOrUiString) {
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedCustomError,
+                               false, 0,
+                               false, _T(""),
+                               false, _T(""));
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 8, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info_.status);
+  EXPECT_EQ(8, completion_info_.error_code);
+  EXPECT_STREQ(_T("The installer encountered error 8."), completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedCustomError,
+                           false, 0,
+                           false, _T(""),
+                           false, _T(""));
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_Failed_WithErrorCode) {
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedCustomError,
+                               true, 8,
+                               false, _T(""),
+                               false, _T(""));
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info_.status);
+  EXPECT_EQ(8, completion_info_.error_code);
+  EXPECT_STREQ(_T("The installer encountered error 8."), completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedCustomError,
+                           true, 8,
+                           false, _T(""),
+                           false, _T(""));
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_Failed_AllValues) {
+  const DWORD kInstallerErrorValue = 8;
+  const TCHAR* const kUiString = _T("a message from the installer");
+
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedCustomError,
+                               true, kInstallerErrorValue,
+                               true, kUiString,
+                               true, kLaunchCmdLine);
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_OTHER, completion_info_.status);
+  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);
+  EXPECT_STREQ(kUiString, completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty()) <<
+      _T("Command line is not supported with errors.");
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedCustomError,
+                           true, kInstallerErrorValue,
+                           true, kUiString,
+                           true, kLaunchCmdLine);
+}
+
+// Exit code is used and interpreted as MSI error when no error code present.
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_FailedMsiError_NoErrorCode) {
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedMsiError,
+                               false, 0,
+                               false, _T(""),
+                               false, _T(""));
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1603, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info_.status);
+  EXPECT_EQ(1603, completion_info_.error_code);
+  EXPECT_STREQ(kError1603Text, completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedMsiError,
+                           false, 0,
+                           false, _T(""),
+                           false, _T(""));
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_FailedMsiError_WithErrorCode) {
+  const DWORD kInstallerErrorValue = 1603;
+
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedMsiError,
+                               true, kInstallerErrorValue,
+                               false, _T(""),
+                               false, _T(""));
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info_.status);
+  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);
+  EXPECT_STREQ(kError1603Text, completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedMsiError,
+                           true, kInstallerErrorValue,
+                           false, _T(""),
+                           false, _T(""));
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_FailedMsiError_AllValues) {
+  const DWORD kInstallerErrorValue = 1603;
+
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedMsiError,
+                               true, kInstallerErrorValue,
+                               true, _T("an ignored error"),
+                               true, kLaunchCmdLine);
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_MSI, completion_info_.status);
+  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);
+  EXPECT_STREQ(kError1603Text, completion_info_.text) <<
+      _T("UIString is ignored.");
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty()) <<
+      _T("Command line is not supported with errors.");
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedMsiError,
+                           true, kInstallerErrorValue,
+                           true, _T("an ignored error"),
+                           true, kLaunchCmdLine);
+}
+
+// Exit code is used and interpreted as system error when no error code present.
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_FailedSystemError_NoErrorCode) {
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedSystemError,
+                               false, 0,
+                               false, _T(""),
+                               false, _T(""));
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1603, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_SYSTEM, completion_info_.status);
+  EXPECT_EQ(1603, completion_info_.error_code);
+  EXPECT_STREQ(kError1603Text, completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedSystemError,
+                           false, 0,
+                           false, _T(""),
+                           false, _T(""));
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_FailedSystemError_WithErrorCode) {
+  const DWORD kInstallerErrorValue = 1603;
+
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedSystemError,
+                               true, kInstallerErrorValue,
+                               false, _T(""),
+                               false, _T(""));
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_SYSTEM, completion_info_.status);
+  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);
+  EXPECT_STREQ(kError1603Text, completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedSystemError,
+                           true, kInstallerErrorValue,
+                           false, _T(""),
+                           false, _T(""));
+}
+
+// INSTALLER_RESULT_FAILED_SYSTEM_ERROR supports values beyond the basic
+// "System Error Codes" and their HRESULT equivalents.
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_FailedSystemError_WithHRESULTSystemError) {
+  const DWORD kInstallerErrorValue = 0x800B010F;
+
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedSystemError,
+                               true, kInstallerErrorValue,
+                               false, _T(""),
+                               false, _T(""));
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_SYSTEM, completion_info_.status);
+  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);
+  EXPECT_STREQ(kError0x800B010FText, completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedSystemError,
+                           true, kInstallerErrorValue,
+                           false, _T(""),
+                           false, _T(""));
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_FailedSystemError_WithUnrecognizedError) {
+  const DWORD kInstallerErrorValue = 0x80040200;
+
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedSystemError,
+                               true, kInstallerErrorValue,
+                               false, _T(""),
+                               false, _T(""));
+
+  // GetMessageForSystemErrorCode expects a valid system error.
+  ExpectAsserts expect_asserts;
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_SYSTEM, completion_info_.status);
+  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);
+  EXPECT_STREQ(_T("The installer encountered error 0x80040200."),
+               completion_info_.text);
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty());
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedSystemError,
+                           true, kInstallerErrorValue,
+                           false, _T(""),
+                           false, _T(""));
+}
+
+TEST_F(InstallManagerUserGetInstallerResultHelperTest,
+       GetInstallerResultHelper_FailedSystemError_AllValues) {
+  const DWORD kInstallerErrorValue = 1603;
+
+  SetupInstallerResultRegistry(kJobGuid,
+                               true, kResultFailedSystemError,
+                               true, kInstallerErrorValue,
+                               true, _T("an ignored error"),
+                               true, kLaunchCmdLine);
+
+  GetInstallerResultHelper(kJobGuid, kOtherInstaller, 1618, &completion_info_);
+
+  EXPECT_EQ(COMPLETION_INSTALLER_ERROR_SYSTEM, completion_info_.status);
+  EXPECT_EQ(kInstallerErrorValue, completion_info_.error_code);
+  EXPECT_STREQ(kError1603Text, completion_info_.text) <<
+      _T("UIString is ignored.");
+  EXPECT_TRUE(job_->launch_cmd_line().IsEmpty()) <<
+      _T("Command line is not supported with errors.");
+
+  VerifyLastRegistryValues(kJobGuid,
+                           true, kResultFailedSystemError,
+                           true, kInstallerErrorValue,
+                           true, _T("an ignored error"),
+                           true, kLaunchCmdLine);
+}
+
+// TODO(omaha): Add a machine test.
+
+}  // namespace omaha
+
diff --git a/worker/job.cc b/worker/job.cc
index a7dbcee..9e6fe0d 100644
--- a/worker/job.cc
+++ b/worker/job.cc
@@ -1,678 +1,678 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/worker/job.h"

-

-#include <windows.h>

-#include <winhttp.h>

-#include <vector>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/sta_call.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource.h"

-#include "omaha/goopdate/update_response_data.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/application_manager.h"

-#include "omaha/worker/download_manager.h"

-#include "omaha/worker/install_manager.h"

-#include "omaha/worker/job_observer.h"

-#include "omaha/worker/ping.h"

-#include "omaha/worker/ping_utils.h"

-#include "omaha/worker/worker_event_logger.h"

-#include "omaha/worker/worker_metrics.h"

-

-namespace omaha {

-

-// The caller retains ownership of ping. Delete this object before deleting

-// the Ping.

-Job::Job(bool is_update, Ping* ping)

-    : extra_code1_(0),

-      job_state_(JOBSTATE_START),

-      job_observer_(NULL),

-      user_explorer_pid_(0),

-      bytes_downloaded_(0),

-      bytes_total_(0),

-      ping_(ping),

-      is_update_(is_update),

-      is_offline_(false),

-      is_background_(false),

-      is_update_check_only_(false),

-      did_launch_cmd_fail_(false) {

-  CORE_LOG(L1, (_T("[Job::Job]")));

-}

-

-Job::~Job() {

-  CORE_LOG(L1, (_T("[Job::~Job][%s]"), GuidToString(app_data_.app_guid())));

-}

-

-void Job::ChangeState(JobState state, bool send_ping) {

-  CORE_LOG(L1, (_T("[Job::ChangeState moving job from %d to %d.]"),

-                job_state_, state));

-  const JobState previous_state = job_state_;

-  job_state_ = state;

-

-  // Ignore failures.

-  if (send_ping && job_state_ != JOBSTATE_START) {

-    SendStateChangePing(previous_state);

-  }

-  VERIFY1(SUCCEEDED(NotifyUI()));

-}

-

-void Job::NotifyDownloadStarted() {

-  ASSERT1(job_state_ == JOBSTATE_START);

-  ChangeState(JOBSTATE_DOWNLOADSTARTED, true);

-}

-

-void Job::NotifyDownloadComplete() {

-  ASSERT1(job_state_ == JOBSTATE_DOWNLOADSTARTED);

-  ChangeState(JOBSTATE_DOWNLOADCOMPLETED, true);

-}

-

-void Job::NotifyInstallStarted() {

-  ChangeState(JOBSTATE_INSTALLERSTARTED, true);

-}

-

-void Job::NotifyCompleted(const CompletionInfo& info) {

-  info_ = info;

-

-  if (!is_update_check_only_) {

-    WriteJobCompletedEvent(app_data().is_machine_app(), *this);

-  }

-

-  bool is_successful_self_update =

-      is_update_ &&

-      IsCompletionSuccess(info_) &&

-      ::IsEqualGUID(kGoopdateGuid, app_data().app_guid());

-  if (is_successful_self_update) {

-    CORE_LOG(L2, (_T("[self-update successfully invoked; not sending ping]")));

-  }

-

-  // Always send a ping unless:

-  // - the state is successful self-update completed, or

-  // - this is an update check only job.

-  // The exception exists because in the first case we do not know the actual

-  // outcome of the job. The ping will be sent by the installer when setup

-  // completes the self-update.

-  // In the second case, update check only jobs do not actually complete.

-  // They are used as containers for the update check response and they

-  // are not downloaded nor installed.

-  bool send_ping = !(is_successful_self_update || is_update_check_only_);

-  ChangeState(JOBSTATE_COMPLETED, send_ping);

-}

-

-void Job::OnProgress(int bytes, int bytes_total,

-                     int status, const TCHAR* status_text) {

-  UNREFERENCED_PARAMETER(status);

-  UNREFERENCED_PARAMETER(status_text);

-  ASSERT1(status == WINHTTP_CALLBACK_STATUS_READ_COMPLETE ||

-          status == WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER);

-  ASSERT1(job_state_ == JOBSTATE_DOWNLOADSTARTED);

-  bytes_downloaded_ = bytes;

-  bytes_total_ = bytes_total;

-  VERIFY1(SUCCEEDED(NotifyUI()));

-}

-

-HRESULT Job::NotifyUI() {

-  if (!job_observer_) {

-    return S_OK;

-  }

-

-  switch (job_state_) {

-    case JOBSTATE_DOWNLOADSTARTED: {

-      int pos = 0;

-      if (bytes_total_) {

-        pos = static_cast<int>(

-            (static_cast<double>(bytes_downloaded_) / bytes_total_) * 100);

-      }

-      job_observer_->OnDownloading(0, pos);

-      break;

-    }

-    case JOBSTATE_DOWNLOADCOMPLETED:

-      job_observer_->OnWaitingToInstall();

-      break;

-    case JOBSTATE_INSTALLERSTARTED:

-      job_observer_->OnInstalling();

-      break;

-    case JOBSTATE_COMPLETED:

-      return DoCompleteJob();

-    case JOBSTATE_START:

-    default:

-      ASSERT1(false);

-      return E_UNEXPECTED;

-  }

-

-  return S_OK;

-}

-

-HRESULT Job::ShouldRestartBrowser() const {

-  return !update_response_data_.success_url().IsEmpty();

-}

-

-HRESULT Job::DeleteJobDownloadDirectory() const {

-  CORE_LOG(L3, (_T("[DeleteJobDownloadDirectory]")));

-  ASSERT1(IsCompletionSuccess(info_));

-

-  // Do no delete the downloaded file if the installer is omaha.

-  if (::IsEqualGUID(app_data_.app_guid(), kGoopdateGuid)) {

-    CORE_LOG(L3, (_T("[Not deleting goopdate self update.]")));

-    return S_OK;

-  }

-

-  // In case of ondemand updates checks, it is possible that we do not have

-  // a downloaded file.

-  if (download_file_name_.IsEmpty() &&

-      is_update_check_only_) {

-    return S_OK;

-  }

-

-  ASSERT1(!download_file_name_.IsEmpty());

-  ASSERT1(!File::IsDirectory(download_file_name_));

-  CString path = GetDirectoryFromPath(download_file_name_);

-  HRESULT hr = DeleteDirectory(path);

-  if (FAILED(hr)) {

-    CORE_LOG(L3, (_T("[Download file directory delete failed.][%s][0x%08x]"),

-                  path, hr));

-  }

-  return hr;

-}

-

-// The SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD case assumes that

-// the launch command was run and did_launch_cmd_fail_ set correctly if

-// launch_cmd_line_ is not empty.

-CompletionCodes Job::CompletionStatusToCompletionCode(

-    JobCompletionStatus status) const {

-  CompletionCodes code(COMPLETION_CODE_ERROR);

-  switch (status) {

-    case COMPLETION_SUCCESS: {

-      if ((update_response_data_.success_action() ==

-           SUCCESS_ACTION_EXIT_SILENTLY) ||

-          (update_response_data_.success_action() ==

-           SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD &&

-           !launch_cmd_line_.IsEmpty())) {

-        // If launch failed, display the success UI anyway.

-        code = did_launch_cmd_fail_ ? COMPLETION_CODE_SUCCESS :

-                                      COMPLETION_CODE_SUCCESS_CLOSE_UI;

-      } else if (ShouldRestartBrowser()) {

-        if (app_data_.browser_type() == BROWSER_UNKNOWN ||

-            app_data_.browser_type() == BROWSER_DEFAULT ||

-            app_data_.browser_type() > BROWSER_MAX) {

-          code = update_response_data_.terminate_all_browsers() ?

-                     COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY :

-                     COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY;

-        } else {

-          code = update_response_data_.terminate_all_browsers() ?

-                     COMPLETION_CODE_RESTART_ALL_BROWSERS :

-                     COMPLETION_CODE_RESTART_BROWSER;

-        }

-      } else {

-        code = COMPLETION_CODE_SUCCESS;

-      }

-      break;

-    }

-    case COMPLETION_SUCCESS_REBOOT_REQUIRED:

-      code = COMPLETION_CODE_REBOOT_NOTICE_ONLY;

-      break;

-    case COMPLETION_ERROR:

-    case COMPLETION_INSTALLER_ERROR_MSI:

-    case COMPLETION_INSTALLER_ERROR_SYSTEM:

-    case COMPLETION_INSTALLER_ERROR_OTHER:

-      code = COMPLETION_CODE_ERROR;

-      break;

-    case COMPLETION_CANCELLED:

-      code = COMPLETION_CODE_ERROR;

-      break;

-    default:

-      ASSERT1(false);

-  }

-

-  return code;

-}

-

-HRESULT Job::DoCompleteJob() {

-  CompletionCodes completion_code =

-      CompletionStatusToCompletionCode(info_.status);

-

-  if (IsCompletionSuccess(info_)) {

-    VERIFY1(SUCCEEDED(DeleteJobDownloadDirectory()));

-  }

-

-  OPT_LOG(L1, (_T("[job completed]")

-               _T("[status %d][completion code %d][error 0x%08x][text \"%s\"]"),

-               info_.status, completion_code, info_.error_code, info_.text));

-

-  if (job_observer_) {

-    job_observer_->OnComplete(completion_code,

-                              info_.text,

-                              info_.error_code);

-  }

-

-  return S_OK;

-}

-

-HRESULT Job::SendStateChangePing(JobState previous_state) {

-  Request request(app_data().is_machine_app());

-

-  // TODO(omaha): Will need to update this to determine if this is a product or

-  // component level job and create the ProductAppData appropriately.

-

-  AppRequestData app_request_data(app_data());

-

-  PingEvent::Types event_type = JobStateToEventType();

-  PingEvent::Results event_result =

-      ping_utils::CompletionStatusToPingEventResult(info().status);

-  // TODO(omaha): Remove this value when circular log buffer is implemented.

-  // If extra_code1 is not already used and there is an error, specify the state

-  // in which the error occurred in extra_code1.

-  const int extra_code1 = (!extra_code1_ && info().error_code) ?

-                              kJobStateExtraCodeMask | previous_state :

-                              extra_code1_;

-  PingEvent ping_event(event_type,

-                       event_result,

-                       info().error_code,

-                       extra_code1,

-                       app_data().previous_version());

-  app_request_data.AddPingEvent(ping_event);

-

-  AppRequest app_request(app_request_data);

-  request.AddAppRequest(app_request);

-

-  // Clear the extra code for the next state/ping.

-  extra_code1_ = 0;

-

-  if (event_result == COMPLETION_CANCELLED) {

-    // This ping is sending the last ping after the cancel it cannot

-    // be canceled.

-    Ping cancel_ping;

-    return cancel_ping.SendPing(&request);

-  } else {

-    ASSERT1(ping_);

-    return ping_->SendPing(&request);

-  }

-}

-

-PingEvent::Types Job::JobStateToEventType() const {

-  PingEvent::Types type = PingEvent::EVENT_UNKNOWN;

-  switch (job_state_) {

-    case JOBSTATE_START:

-      break;

-    case JOBSTATE_DOWNLOADSTARTED:

-      type = is_update_ ? PingEvent::EVENT_UPDATE_DOWNLOAD_START :

-                          PingEvent::EVENT_INSTALL_DOWNLOAD_START;

-      break;

-    case JOBSTATE_DOWNLOADCOMPLETED:

-      type = is_update_ ? PingEvent::EVENT_UPDATE_DOWNLOAD_FINISH :

-                          PingEvent::EVENT_INSTALL_DOWNLOAD_FINISH;

-      break;

-    case JOBSTATE_INSTALLERSTARTED:

-      type = is_update_ ? PingEvent::EVENT_UPDATE_INSTALLER_START :

-                          PingEvent::EVENT_INSTALL_INSTALLER_START;

-      break;

-    case JOBSTATE_COMPLETED:

-      type = is_update_ ? PingEvent::EVENT_UPDATE_COMPLETE :

-                          PingEvent::EVENT_INSTALL_COMPLETE;

-      break;

-    default:

-      break;

-  }

-  ASSERT1(PingEvent::EVENT_UNKNOWN != type);

-  return type;

-}

-

-void Job::RestartBrowsers() {

-  // CompletionStatusToCompletionCode does not set a restart completion code

-  // if the browser type is not a specific browser, so this method should never

-  // be called in those cases.

-  ASSERT1(app_data_.browser_type() != BROWSER_UNKNOWN &&

-          app_data_.browser_type() != BROWSER_DEFAULT &&

-          app_data_.browser_type() < BROWSER_MAX);

-

-  CORE_LOG(L3, (_T("[Job::RestartBrowsers]")));

-  TerminateBrowserResult browser_res;

-  TerminateBrowserResult default_res;

-  if (update_response_data_.terminate_all_browsers()) {

-    goopdate_utils::TerminateAllBrowsers(app_data_.browser_type(),

-                                         &browser_res,

-                                         &default_res);

-  } else {

-    goopdate_utils::TerminateBrowserProcesses(app_data_.browser_type(),

-                                              &browser_res,

-                                              &default_res);

-  }

-

-  BrowserType default_type = BROWSER_UNKNOWN;

-  HRESULT hr = GetDefaultBrowserType(&default_type);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[GetDefaultBrowserType failed][0x%08x]"), hr));

-    return;

-  }

-

-  BrowserType browser_type = BROWSER_UNKNOWN;

-  if (!goopdate_utils::GetBrowserToRestart(app_data_.browser_type(),

-                                           default_type,

-                                           browser_res,

-                                           default_res,

-                                           &browser_type)) {

-    CORE_LOG(LE, (_T("[GetBrowserToRestart returned false. Not launching.]")));

-    return;

-  }

-

-  ASSERT1(BROWSER_UNKNOWN != browser_type);

-  VERIFY1(SUCCEEDED(goopdate_utils::LaunchBrowser(

-      browser_type,

-      update_response_data_.success_url())));

-}

-

-void Job::LaunchBrowser(const CString& url) {

-  CORE_LOG(L3, (_T("[Job::LaunchBrowser]")));

-  BrowserType browser_type =

-      app_data_.browser_type() == BROWSER_UNKNOWN ?

-                                  BROWSER_DEFAULT :

-                                  app_data_.browser_type();

-  VERIFY1(SUCCEEDED(goopdate_utils::LaunchBrowser(browser_type, url)));

-}

-

-void Job::set_app_data(const AppData& app_data) {

-  app_data_ = app_data;

-}

-

-// On Vista with UAC on for an interactive install, LaunchCmdLine will run the

-// command line at medium integrity even if the installer was running at high

-// integrity.

-HRESULT Job::LaunchCmdLine() {

-  CORE_LOG(L3, (_T("[Job::LaunchCmdLine][%s]"), launch_cmd_line_));

-  ASSERT1(!is_update_);

-

-  if (launch_cmd_line_.IsEmpty()) {

-    return S_OK;

-  }

-

-  // InstallerSuccessLaunchCmdLine should not be set if the install failed.

-  ASSERT1(IsCompletionSuccess(info_));

-

-  HRESULT hr = goopdate_utils::LaunchCmdLine(launch_cmd_line_);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[goopdate_utils::LaunchCmdLine failed][0x%x]"), hr));

-    did_launch_cmd_fail_ = true;

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT Job::Download(DownloadManager* dl_manager) {

-  CORE_LOG(L2, (_T("[Job::DownloadJob][%s]"),

-                GuidToString(app_data_.app_guid())));

-  ASSERT1(dl_manager);

-

-  NotifyDownloadStarted();

-  HRESULT hr = dl_manager->DownloadFile(this);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[Job::DownloadJob DownloadFile failed][0x%08x][%s]"),

-                  hr, GuidToString(app_data_.app_guid())));

-    CompletionInfo info = dl_manager->error_info();

-    if (!IsCompletionSuccess(info)) {

-      NotifyCompleted(info);

-    }

-    return hr;

-  }

-

-  NotifyDownloadComplete();

-  return S_OK;

-}

-

-HRESULT Job::Install() {

-  CORE_LOG(L2, (_T("[Job::InstallJob]")));

-  NotifyInstallStarted();

-

-  CompletionInfo completion_info;

-  AppData new_app_data;

-  HRESULT hr = DoInstall(&completion_info, &new_app_data);

-  // Do not return until after NotifyCompleted() has been called.

-

-  NotifyCompleted(completion_info);

-  app_data_ = new_app_data;

-

-  return hr;

-}

-

-HRESULT Job::DoInstall(CompletionInfo* completion_info,

-                       AppData* new_app_data) {

-  CORE_LOG(L3, (_T("[Job::DoInstall]")));

-  ASSERT1(completion_info);

-  ASSERT1(new_app_data);

-

-  if (!is_update_) {

-    AppManager app_manager(app_data_.is_machine_app());

-    HRESULT hr = app_manager.WritePreInstallData(app_data_);

-    if (FAILED(hr)) {

-      CORE_LOG(LE, (_T("[AppManager::WritePreInstallData failed][0x%08x][%s]"),

-                    hr, GuidToString(app_data_.app_guid())));

-      completion_info->status = COMPLETION_ERROR;

-      completion_info->error_code = hr;

-      completion_info->text.FormatMessage(IDS_INSTALL_FAILED, hr);

-      return hr;

-    }

-  }

-

-  InstallManager install_manager(app_data_.is_machine_app());

-  AppManager app_manager(app_data_.is_machine_app());

-

-  HRESULT hr = install_manager.InstallJob(this);

-  *completion_info = install_manager.error_info();

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[InstallManager::InstallJobs failed][0x%08x][%s]"),

-                  hr, GuidToString(app_data_.app_guid())));

-

-    // If we failed the install job and the product wasn't registered, it's safe

-    // to delete the ClientState key.  We need to remove it because it contains

-    // data like "ap", browsertype, language, etc. that need to be cleaned up in

-    // case user tries to install again in the future.

-    if (!is_update_ &&

-        !app_manager.IsProductRegistered(app_data_.app_guid())) {

-      // Need to set IsUninstalled to true or else we'll assert in

-      // RemoveClientState().

-      app_data_.set_is_uninstalled(true);

-      app_manager.RemoveClientState(app_data_);

-    }

-

-    return hr;

-  }

-

-  hr = UpdateJob();

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[UpdateJobAndRegistry failed][0x%08x][%s]"),

-                  hr, GuidToString(app_data_.app_guid())));

-    completion_info->status = COMPLETION_ERROR;

-    completion_info->error_code = hr;

-    completion_info->text.FormatMessage(IDS_INSTALL_FAILED, hr);

-    return hr;

-  }

-

-  hr = UpdateRegistry(new_app_data);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[UpdateJobAndRegistry failed][0x%08x][%s]"),

-                  hr, GuidToString(app_data_.app_guid())));

-    completion_info->status = COMPLETION_ERROR;

-    completion_info->error_code = hr;

-    completion_info->text.FormatMessage(IDS_INSTALL_FAILED, hr);

-    return hr;

-  }

-

-  // We do not know whether Goopdate has succeeded because its installer has

-  // not completed.

-  if (!::IsEqualGUID(kGoopdateGuid, app_data_.app_guid())) {

-    app_manager.RecordSuccessfulInstall(app_data_.parent_app_guid(),

-                                        app_data_.app_guid(),

-                                        is_update_,

-                                        is_offline_);

-  }

-

-  return S_OK;

-}

-

-// Update the version and the language in the job using the values written by

-// the installer.

-HRESULT Job::UpdateJob() {

-  CORE_LOG(L2, (_T("[Job::UpdateJob]")));

-  AppManager app_manager(app_data_.is_machine_app());

-  AppData data;

-  HRESULT hr = app_manager.ReadAppDataFromStore(app_data_.parent_app_guid(),

-                                                app_data_.app_guid(),

-                                                &data);

-  ASSERT1(SUCCEEDED(hr));

-  if (SUCCEEDED(hr)) {

-    app_data_.set_version(data.version());

-    app_data_.set_language(data.language());

-  } else {

-    CORE_LOG(LW, (_T("[ReadApplicationData failed][0x%08x][%s]"),

-                  hr, GuidToString(app_data_.app_guid())));

-    // Continue without the data from the registry.

-  }

-

-  return S_OK;

-}

-

-// Update the registry with the information from the job.

-HRESULT Job::UpdateRegistry(AppData* new_app_data) {

-  CORE_LOG(L2, (_T("[Job::UpdateRegistry]")));

-  ASSERT1(new_app_data);

-

-  *new_app_data = app_data_;

-  AppManager app_manager(app_data_.is_machine_app());

-  // Update the client registry information and the client state with the

-  // information in this job.

-  HRESULT hr = app_manager.InitializeApplicationState(new_app_data);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[WriteAppParamsToRegistry failed][0x%08x][%s]"),

-                  hr, GuidToString(new_app_data->app_guid())));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT Job::GetInstallerData(CString* installer_data) const {

-  ASSERT1(installer_data);

-  installer_data->Empty();

-

-  if (!app_data().encoded_installer_data().IsEmpty()) {

-    CString decoded_installer_data;

-    HRESULT hr = Utf8UrlEncodedStringToWideString(

-                     app_data().encoded_installer_data(),

-                     &decoded_installer_data);

-    ASSERT(SUCCEEDED(hr), (_T("[Utf8UrlEncodedStringToWideString][0x%x]"), hr));

-

-    if (FAILED(hr) || CString(decoded_installer_data).Trim().IsEmpty()) {

-      return GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS;

-    }

-    *installer_data = decoded_installer_data;

-    return S_OK;

-  }

-

-  if (app_data().install_data_index().IsEmpty()) {

-    return S_OK;

-  }

-

-  CString data(response_data().GetInstallData(app_data().install_data_index()));

-  if (CString(data).Trim().IsEmpty()) {

-    return GOOPDATE_E_INVALID_INSTALL_DATA_INDEX;

-  }

-

-  *installer_data = data;

-  return S_OK;

-}

-

-bool IsCompletionStatusSuccess(JobCompletionStatus status) {

-  switch (status) {

-    case COMPLETION_SUCCESS:

-    case COMPLETION_SUCCESS_REBOOT_REQUIRED:

-      return true;

-    case COMPLETION_ERROR:

-    case COMPLETION_INSTALLER_ERROR_MSI:

-    case COMPLETION_INSTALLER_ERROR_SYSTEM:

-    case COMPLETION_INSTALLER_ERROR_OTHER:

-    case COMPLETION_CANCELLED:

-    default:

-      return false;

-  }

-}

-

-bool IsCompletionStatusInstallerError(JobCompletionStatus status) {

-  switch (status) {

-    case COMPLETION_INSTALLER_ERROR_MSI:

-    case COMPLETION_INSTALLER_ERROR_SYSTEM:

-    case COMPLETION_INSTALLER_ERROR_OTHER:

-      return true;

-    case COMPLETION_SUCCESS:

-    case COMPLETION_SUCCESS_REBOOT_REQUIRED:

-    case COMPLETION_ERROR:

-    case COMPLETION_CANCELLED:

-    default:

-      return false;

-  }

-}

-

-CString CompletionInfo::ToString() const {

-  CString error_code_string = FormatErrorCode(error_code);

-

-  // Get the format string for the status. Must have %s placeholder for code.

-  CString status_format;

-  switch (status) {

-    case COMPLETION_SUCCESS:

-      status_format = _T("Installer succeeded with code %s.");

-      break;

-    case COMPLETION_SUCCESS_REBOOT_REQUIRED:

-      status_format = _T("Installer succeeded but reboot required. Code %s.");

-      break;

-    case COMPLETION_ERROR:

-      status_format = _T("Omaha failed with error code %s.");

-      break;

-    case COMPLETION_INSTALLER_ERROR_MSI:

-      status_format = _T("Installer failed with MSI error %s.");

-      break;

-    case COMPLETION_INSTALLER_ERROR_SYSTEM:

-      status_format = _T("Installer failed with system error %s.");

-      break;

-    case COMPLETION_INSTALLER_ERROR_OTHER:

-      status_format = _T("Installer failed with error code %s.");

-      break;

-    case COMPLETION_CANCELLED:

-      status_format = _T("Operation canceled. Code %s.");

-      break;

-    default:

-      status_format = _T("Unknown status. Code %s.");

-      ASSERT1(false);

-  }

-

-  CString output;

-  output.Format(status_format, error_code_string);

-

-  if (!text.IsEmpty()) {

-    output.Append(_T(" ") + text);

-  }

-

-  return output;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/worker/job.h"
+
+#include <windows.h>
+#include <winhttp.h>
+#include <vector>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/sta_call.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource.h"
+#include "omaha/goopdate/update_response_data.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/application_manager.h"
+#include "omaha/worker/download_manager.h"
+#include "omaha/worker/install_manager.h"
+#include "omaha/worker/job_observer.h"
+#include "omaha/worker/ping.h"
+#include "omaha/worker/ping_utils.h"
+#include "omaha/worker/worker_event_logger.h"
+#include "omaha/worker/worker_metrics.h"
+
+namespace omaha {
+
+// The caller retains ownership of ping. Delete this object before deleting
+// the Ping.
+Job::Job(bool is_update, Ping* ping)
+    : extra_code1_(0),
+      job_state_(JOBSTATE_START),
+      job_observer_(NULL),
+      user_explorer_pid_(0),
+      bytes_downloaded_(0),
+      bytes_total_(0),
+      ping_(ping),
+      is_update_(is_update),
+      is_offline_(false),
+      is_background_(false),
+      is_update_check_only_(false),
+      did_launch_cmd_fail_(false) {
+  CORE_LOG(L1, (_T("[Job::Job]")));
+}
+
+Job::~Job() {
+  CORE_LOG(L1, (_T("[Job::~Job][%s]"), GuidToString(app_data_.app_guid())));
+}
+
+void Job::ChangeState(JobState state, bool send_ping) {
+  CORE_LOG(L1, (_T("[Job::ChangeState moving job from %d to %d.]"),
+                job_state_, state));
+  const JobState previous_state = job_state_;
+  job_state_ = state;
+
+  // Ignore failures.
+  if (send_ping && job_state_ != JOBSTATE_START) {
+    SendStateChangePing(previous_state);
+  }
+  VERIFY1(SUCCEEDED(NotifyUI()));
+}
+
+void Job::NotifyDownloadStarted() {
+  ASSERT1(job_state_ == JOBSTATE_START);
+  ChangeState(JOBSTATE_DOWNLOADSTARTED, true);
+}
+
+void Job::NotifyDownloadComplete() {
+  ASSERT1(job_state_ == JOBSTATE_DOWNLOADSTARTED);
+  ChangeState(JOBSTATE_DOWNLOADCOMPLETED, true);
+}
+
+void Job::NotifyInstallStarted() {
+  ChangeState(JOBSTATE_INSTALLERSTARTED, true);
+}
+
+void Job::NotifyCompleted(const CompletionInfo& info) {
+  info_ = info;
+
+  if (!is_update_check_only_) {
+    WriteJobCompletedEvent(app_data().is_machine_app(), *this);
+  }
+
+  bool is_successful_self_update =
+      is_update_ &&
+      IsCompletionSuccess(info_) &&
+      ::IsEqualGUID(kGoopdateGuid, app_data().app_guid());
+  if (is_successful_self_update) {
+    CORE_LOG(L2, (_T("[self-update successfully invoked; not sending ping]")));
+  }
+
+  // Always send a ping unless:
+  // - the state is successful self-update completed, or
+  // - this is an update check only job.
+  // The exception exists because in the first case we do not know the actual
+  // outcome of the job. The ping will be sent by the installer when setup
+  // completes the self-update.
+  // In the second case, update check only jobs do not actually complete.
+  // They are used as containers for the update check response and they
+  // are not downloaded nor installed.
+  bool send_ping = !(is_successful_self_update || is_update_check_only_);
+  ChangeState(JOBSTATE_COMPLETED, send_ping);
+}
+
+void Job::OnProgress(int bytes, int bytes_total,
+                     int status, const TCHAR* status_text) {
+  UNREFERENCED_PARAMETER(status);
+  UNREFERENCED_PARAMETER(status_text);
+  ASSERT1(status == WINHTTP_CALLBACK_STATUS_READ_COMPLETE ||
+          status == WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER);
+  ASSERT1(job_state_ == JOBSTATE_DOWNLOADSTARTED);
+  bytes_downloaded_ = bytes;
+  bytes_total_ = bytes_total;
+  VERIFY1(SUCCEEDED(NotifyUI()));
+}
+
+HRESULT Job::NotifyUI() {
+  if (!job_observer_) {
+    return S_OK;
+  }
+
+  switch (job_state_) {
+    case JOBSTATE_DOWNLOADSTARTED: {
+      int pos = 0;
+      if (bytes_total_) {
+        pos = static_cast<int>(
+            (static_cast<double>(bytes_downloaded_) / bytes_total_) * 100);
+      }
+      job_observer_->OnDownloading(0, pos);
+      break;
+    }
+    case JOBSTATE_DOWNLOADCOMPLETED:
+      job_observer_->OnWaitingToInstall();
+      break;
+    case JOBSTATE_INSTALLERSTARTED:
+      job_observer_->OnInstalling();
+      break;
+    case JOBSTATE_COMPLETED:
+      return DoCompleteJob();
+    case JOBSTATE_START:
+    default:
+      ASSERT1(false);
+      return E_UNEXPECTED;
+  }
+
+  return S_OK;
+}
+
+HRESULT Job::ShouldRestartBrowser() const {
+  return !update_response_data_.success_url().IsEmpty();
+}
+
+HRESULT Job::DeleteJobDownloadDirectory() const {
+  CORE_LOG(L3, (_T("[DeleteJobDownloadDirectory]")));
+  ASSERT1(IsCompletionSuccess(info_));
+
+  // Do no delete the downloaded file if the installer is omaha.
+  if (::IsEqualGUID(app_data_.app_guid(), kGoopdateGuid)) {
+    CORE_LOG(L3, (_T("[Not deleting goopdate self update.]")));
+    return S_OK;
+  }
+
+  // In case of ondemand updates checks, it is possible that we do not have
+  // a downloaded file.
+  if (download_file_name_.IsEmpty() &&
+      is_update_check_only_) {
+    return S_OK;
+  }
+
+  ASSERT1(!download_file_name_.IsEmpty());
+  ASSERT1(!File::IsDirectory(download_file_name_));
+  CString path = GetDirectoryFromPath(download_file_name_);
+  HRESULT hr = DeleteDirectory(path);
+  if (FAILED(hr)) {
+    CORE_LOG(L3, (_T("[Download file directory delete failed.][%s][0x%08x]"),
+                  path, hr));
+  }
+  return hr;
+}
+
+// The SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD case assumes that
+// the launch command was run and did_launch_cmd_fail_ set correctly if
+// launch_cmd_line_ is not empty.
+CompletionCodes Job::CompletionStatusToCompletionCode(
+    JobCompletionStatus status) const {
+  CompletionCodes code(COMPLETION_CODE_ERROR);
+  switch (status) {
+    case COMPLETION_SUCCESS: {
+      if ((update_response_data_.success_action() ==
+           SUCCESS_ACTION_EXIT_SILENTLY) ||
+          (update_response_data_.success_action() ==
+           SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD &&
+           !launch_cmd_line_.IsEmpty())) {
+        // If launch failed, display the success UI anyway.
+        code = did_launch_cmd_fail_ ? COMPLETION_CODE_SUCCESS :
+                                      COMPLETION_CODE_SUCCESS_CLOSE_UI;
+      } else if (ShouldRestartBrowser()) {
+        if (app_data_.browser_type() == BROWSER_UNKNOWN ||
+            app_data_.browser_type() == BROWSER_DEFAULT ||
+            app_data_.browser_type() > BROWSER_MAX) {
+          code = update_response_data_.terminate_all_browsers() ?
+                     COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY :
+                     COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY;
+        } else {
+          code = update_response_data_.terminate_all_browsers() ?
+                     COMPLETION_CODE_RESTART_ALL_BROWSERS :
+                     COMPLETION_CODE_RESTART_BROWSER;
+        }
+      } else {
+        code = COMPLETION_CODE_SUCCESS;
+      }
+      break;
+    }
+    case COMPLETION_SUCCESS_REBOOT_REQUIRED:
+      code = COMPLETION_CODE_REBOOT_NOTICE_ONLY;
+      break;
+    case COMPLETION_ERROR:
+    case COMPLETION_INSTALLER_ERROR_MSI:
+    case COMPLETION_INSTALLER_ERROR_SYSTEM:
+    case COMPLETION_INSTALLER_ERROR_OTHER:
+      code = COMPLETION_CODE_ERROR;
+      break;
+    case COMPLETION_CANCELLED:
+      code = COMPLETION_CODE_ERROR;
+      break;
+    default:
+      ASSERT1(false);
+  }
+
+  return code;
+}
+
+HRESULT Job::DoCompleteJob() {
+  CompletionCodes completion_code =
+      CompletionStatusToCompletionCode(info_.status);
+
+  if (IsCompletionSuccess(info_)) {
+    VERIFY1(SUCCEEDED(DeleteJobDownloadDirectory()));
+  }
+
+  OPT_LOG(L1, (_T("[job completed]")
+               _T("[status %d][completion code %d][error 0x%08x][text \"%s\"]"),
+               info_.status, completion_code, info_.error_code, info_.text));
+
+  if (job_observer_) {
+    job_observer_->OnComplete(completion_code,
+                              info_.text,
+                              info_.error_code);
+  }
+
+  return S_OK;
+}
+
+HRESULT Job::SendStateChangePing(JobState previous_state) {
+  Request request(app_data().is_machine_app());
+
+  // TODO(omaha): Will need to update this to determine if this is a product or
+  // component level job and create the ProductAppData appropriately.
+
+  AppRequestData app_request_data(app_data());
+
+  PingEvent::Types event_type = JobStateToEventType();
+  PingEvent::Results event_result =
+      ping_utils::CompletionStatusToPingEventResult(info().status);
+  // TODO(omaha): Remove this value when circular log buffer is implemented.
+  // If extra_code1 is not already used and there is an error, specify the state
+  // in which the error occurred in extra_code1.
+  const int extra_code1 = (!extra_code1_ && info().error_code) ?
+                              kJobStateExtraCodeMask | previous_state :
+                              extra_code1_;
+  PingEvent ping_event(event_type,
+                       event_result,
+                       info().error_code,
+                       extra_code1,
+                       app_data().previous_version());
+  app_request_data.AddPingEvent(ping_event);
+
+  AppRequest app_request(app_request_data);
+  request.AddAppRequest(app_request);
+
+  // Clear the extra code for the next state/ping.
+  extra_code1_ = 0;
+
+  if (event_result == COMPLETION_CANCELLED) {
+    // This ping is sending the last ping after the cancel it cannot
+    // be canceled.
+    Ping cancel_ping;
+    return cancel_ping.SendPing(&request);
+  } else {
+    ASSERT1(ping_);
+    return ping_->SendPing(&request);
+  }
+}
+
+PingEvent::Types Job::JobStateToEventType() const {
+  PingEvent::Types type = PingEvent::EVENT_UNKNOWN;
+  switch (job_state_) {
+    case JOBSTATE_START:
+      break;
+    case JOBSTATE_DOWNLOADSTARTED:
+      type = is_update_ ? PingEvent::EVENT_UPDATE_DOWNLOAD_START :
+                          PingEvent::EVENT_INSTALL_DOWNLOAD_START;
+      break;
+    case JOBSTATE_DOWNLOADCOMPLETED:
+      type = is_update_ ? PingEvent::EVENT_UPDATE_DOWNLOAD_FINISH :
+                          PingEvent::EVENT_INSTALL_DOWNLOAD_FINISH;
+      break;
+    case JOBSTATE_INSTALLERSTARTED:
+      type = is_update_ ? PingEvent::EVENT_UPDATE_INSTALLER_START :
+                          PingEvent::EVENT_INSTALL_INSTALLER_START;
+      break;
+    case JOBSTATE_COMPLETED:
+      type = is_update_ ? PingEvent::EVENT_UPDATE_COMPLETE :
+                          PingEvent::EVENT_INSTALL_COMPLETE;
+      break;
+    default:
+      break;
+  }
+  ASSERT1(PingEvent::EVENT_UNKNOWN != type);
+  return type;
+}
+
+void Job::RestartBrowsers() {
+  // CompletionStatusToCompletionCode does not set a restart completion code
+  // if the browser type is not a specific browser, so this method should never
+  // be called in those cases.
+  ASSERT1(app_data_.browser_type() != BROWSER_UNKNOWN &&
+          app_data_.browser_type() != BROWSER_DEFAULT &&
+          app_data_.browser_type() < BROWSER_MAX);
+
+  CORE_LOG(L3, (_T("[Job::RestartBrowsers]")));
+  TerminateBrowserResult browser_res;
+  TerminateBrowserResult default_res;
+  if (update_response_data_.terminate_all_browsers()) {
+    goopdate_utils::TerminateAllBrowsers(app_data_.browser_type(),
+                                         &browser_res,
+                                         &default_res);
+  } else {
+    goopdate_utils::TerminateBrowserProcesses(app_data_.browser_type(),
+                                              &browser_res,
+                                              &default_res);
+  }
+
+  BrowserType default_type = BROWSER_UNKNOWN;
+  HRESULT hr = GetDefaultBrowserType(&default_type);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[GetDefaultBrowserType failed][0x%08x]"), hr));
+    return;
+  }
+
+  BrowserType browser_type = BROWSER_UNKNOWN;
+  if (!goopdate_utils::GetBrowserToRestart(app_data_.browser_type(),
+                                           default_type,
+                                           browser_res,
+                                           default_res,
+                                           &browser_type)) {
+    CORE_LOG(LE, (_T("[GetBrowserToRestart returned false. Not launching.]")));
+    return;
+  }
+
+  ASSERT1(BROWSER_UNKNOWN != browser_type);
+  VERIFY1(SUCCEEDED(goopdate_utils::LaunchBrowser(
+      browser_type,
+      update_response_data_.success_url())));
+}
+
+void Job::LaunchBrowser(const CString& url) {
+  CORE_LOG(L3, (_T("[Job::LaunchBrowser]")));
+  BrowserType browser_type =
+      app_data_.browser_type() == BROWSER_UNKNOWN ?
+                                  BROWSER_DEFAULT :
+                                  app_data_.browser_type();
+  VERIFY1(SUCCEEDED(goopdate_utils::LaunchBrowser(browser_type, url)));
+}
+
+void Job::set_app_data(const AppData& app_data) {
+  app_data_ = app_data;
+}
+
+// On Vista with UAC on for an interactive install, LaunchCmdLine will run the
+// command line at medium integrity even if the installer was running at high
+// integrity.
+HRESULT Job::LaunchCmdLine() {
+  CORE_LOG(L3, (_T("[Job::LaunchCmdLine][%s]"), launch_cmd_line_));
+  ASSERT1(!is_update_);
+
+  if (launch_cmd_line_.IsEmpty()) {
+    return S_OK;
+  }
+
+  // InstallerSuccessLaunchCmdLine should not be set if the install failed.
+  ASSERT1(IsCompletionSuccess(info_));
+
+  HRESULT hr = goopdate_utils::LaunchCmdLine(launch_cmd_line_);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[goopdate_utils::LaunchCmdLine failed][0x%x]"), hr));
+    did_launch_cmd_fail_ = true;
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT Job::Download(DownloadManager* dl_manager) {
+  CORE_LOG(L2, (_T("[Job::DownloadJob][%s]"),
+                GuidToString(app_data_.app_guid())));
+  ASSERT1(dl_manager);
+
+  NotifyDownloadStarted();
+  HRESULT hr = dl_manager->DownloadFile(this);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[Job::DownloadJob DownloadFile failed][0x%08x][%s]"),
+                  hr, GuidToString(app_data_.app_guid())));
+    CompletionInfo info = dl_manager->error_info();
+    if (!IsCompletionSuccess(info)) {
+      NotifyCompleted(info);
+    }
+    return hr;
+  }
+
+  NotifyDownloadComplete();
+  return S_OK;
+}
+
+HRESULT Job::Install() {
+  CORE_LOG(L2, (_T("[Job::InstallJob]")));
+  NotifyInstallStarted();
+
+  CompletionInfo completion_info;
+  AppData new_app_data;
+  HRESULT hr = DoInstall(&completion_info, &new_app_data);
+  // Do not return until after NotifyCompleted() has been called.
+
+  NotifyCompleted(completion_info);
+  app_data_ = new_app_data;
+
+  return hr;
+}
+
+HRESULT Job::DoInstall(CompletionInfo* completion_info,
+                       AppData* new_app_data) {
+  CORE_LOG(L3, (_T("[Job::DoInstall]")));
+  ASSERT1(completion_info);
+  ASSERT1(new_app_data);
+
+  if (!is_update_) {
+    AppManager app_manager(app_data_.is_machine_app());
+    HRESULT hr = app_manager.WritePreInstallData(app_data_);
+    if (FAILED(hr)) {
+      CORE_LOG(LE, (_T("[AppManager::WritePreInstallData failed][0x%08x][%s]"),
+                    hr, GuidToString(app_data_.app_guid())));
+      completion_info->status = COMPLETION_ERROR;
+      completion_info->error_code = hr;
+      completion_info->text.FormatMessage(IDS_INSTALL_FAILED, hr);
+      return hr;
+    }
+  }
+
+  InstallManager install_manager(app_data_.is_machine_app());
+  AppManager app_manager(app_data_.is_machine_app());
+
+  HRESULT hr = install_manager.InstallJob(this);
+  *completion_info = install_manager.error_info();
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[InstallManager::InstallJobs failed][0x%08x][%s]"),
+                  hr, GuidToString(app_data_.app_guid())));
+
+    // If we failed the install job and the product wasn't registered, it's safe
+    // to delete the ClientState key.  We need to remove it because it contains
+    // data like "ap", browsertype, language, etc. that need to be cleaned up in
+    // case user tries to install again in the future.
+    if (!is_update_ &&
+        !app_manager.IsProductRegistered(app_data_.app_guid())) {
+      // Need to set IsUninstalled to true or else we'll assert in
+      // RemoveClientState().
+      app_data_.set_is_uninstalled(true);
+      app_manager.RemoveClientState(app_data_);
+    }
+
+    return hr;
+  }
+
+  hr = UpdateJob();
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[UpdateJobAndRegistry failed][0x%08x][%s]"),
+                  hr, GuidToString(app_data_.app_guid())));
+    completion_info->status = COMPLETION_ERROR;
+    completion_info->error_code = hr;
+    completion_info->text.FormatMessage(IDS_INSTALL_FAILED, hr);
+    return hr;
+  }
+
+  hr = UpdateRegistry(new_app_data);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[UpdateJobAndRegistry failed][0x%08x][%s]"),
+                  hr, GuidToString(app_data_.app_guid())));
+    completion_info->status = COMPLETION_ERROR;
+    completion_info->error_code = hr;
+    completion_info->text.FormatMessage(IDS_INSTALL_FAILED, hr);
+    return hr;
+  }
+
+  // We do not know whether Goopdate has succeeded because its installer has
+  // not completed.
+  if (!::IsEqualGUID(kGoopdateGuid, app_data_.app_guid())) {
+    app_manager.RecordSuccessfulInstall(app_data_.parent_app_guid(),
+                                        app_data_.app_guid(),
+                                        is_update_,
+                                        is_offline_);
+  }
+
+  return S_OK;
+}
+
+// Update the version and the language in the job using the values written by
+// the installer.
+HRESULT Job::UpdateJob() {
+  CORE_LOG(L2, (_T("[Job::UpdateJob]")));
+  AppManager app_manager(app_data_.is_machine_app());
+  AppData data;
+  HRESULT hr = app_manager.ReadAppDataFromStore(app_data_.parent_app_guid(),
+                                                app_data_.app_guid(),
+                                                &data);
+  ASSERT1(SUCCEEDED(hr));
+  if (SUCCEEDED(hr)) {
+    app_data_.set_version(data.version());
+    app_data_.set_language(data.language());
+  } else {
+    CORE_LOG(LW, (_T("[ReadApplicationData failed][0x%08x][%s]"),
+                  hr, GuidToString(app_data_.app_guid())));
+    // Continue without the data from the registry.
+  }
+
+  return S_OK;
+}
+
+// Update the registry with the information from the job.
+HRESULT Job::UpdateRegistry(AppData* new_app_data) {
+  CORE_LOG(L2, (_T("[Job::UpdateRegistry]")));
+  ASSERT1(new_app_data);
+
+  *new_app_data = app_data_;
+  AppManager app_manager(app_data_.is_machine_app());
+  // Update the client registry information and the client state with the
+  // information in this job.
+  HRESULT hr = app_manager.InitializeApplicationState(new_app_data);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[WriteAppParamsToRegistry failed][0x%08x][%s]"),
+                  hr, GuidToString(new_app_data->app_guid())));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT Job::GetInstallerData(CString* installer_data) const {
+  ASSERT1(installer_data);
+  installer_data->Empty();
+
+  if (!app_data().encoded_installer_data().IsEmpty()) {
+    CString decoded_installer_data;
+    HRESULT hr = Utf8UrlEncodedStringToWideString(
+                     app_data().encoded_installer_data(),
+                     &decoded_installer_data);
+    ASSERT(SUCCEEDED(hr), (_T("[Utf8UrlEncodedStringToWideString][0x%x]"), hr));
+
+    if (FAILED(hr) || CString(decoded_installer_data).Trim().IsEmpty()) {
+      return GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS;
+    }
+    *installer_data = decoded_installer_data;
+    return S_OK;
+  }
+
+  if (app_data().install_data_index().IsEmpty()) {
+    return S_OK;
+  }
+
+  CString data(response_data().GetInstallData(app_data().install_data_index()));
+  if (CString(data).Trim().IsEmpty()) {
+    return GOOPDATE_E_INVALID_INSTALL_DATA_INDEX;
+  }
+
+  *installer_data = data;
+  return S_OK;
+}
+
+bool IsCompletionStatusSuccess(JobCompletionStatus status) {
+  switch (status) {
+    case COMPLETION_SUCCESS:
+    case COMPLETION_SUCCESS_REBOOT_REQUIRED:
+      return true;
+    case COMPLETION_ERROR:
+    case COMPLETION_INSTALLER_ERROR_MSI:
+    case COMPLETION_INSTALLER_ERROR_SYSTEM:
+    case COMPLETION_INSTALLER_ERROR_OTHER:
+    case COMPLETION_CANCELLED:
+    default:
+      return false;
+  }
+}
+
+bool IsCompletionStatusInstallerError(JobCompletionStatus status) {
+  switch (status) {
+    case COMPLETION_INSTALLER_ERROR_MSI:
+    case COMPLETION_INSTALLER_ERROR_SYSTEM:
+    case COMPLETION_INSTALLER_ERROR_OTHER:
+      return true;
+    case COMPLETION_SUCCESS:
+    case COMPLETION_SUCCESS_REBOOT_REQUIRED:
+    case COMPLETION_ERROR:
+    case COMPLETION_CANCELLED:
+    default:
+      return false;
+  }
+}
+
+CString CompletionInfo::ToString() const {
+  CString error_code_string = FormatErrorCode(error_code);
+
+  // Get the format string for the status. Must have %s placeholder for code.
+  CString status_format;
+  switch (status) {
+    case COMPLETION_SUCCESS:
+      status_format = _T("Installer succeeded with code %s.");
+      break;
+    case COMPLETION_SUCCESS_REBOOT_REQUIRED:
+      status_format = _T("Installer succeeded but reboot required. Code %s.");
+      break;
+    case COMPLETION_ERROR:
+      status_format = _T("Omaha failed with error code %s.");
+      break;
+    case COMPLETION_INSTALLER_ERROR_MSI:
+      status_format = _T("Installer failed with MSI error %s.");
+      break;
+    case COMPLETION_INSTALLER_ERROR_SYSTEM:
+      status_format = _T("Installer failed with system error %s.");
+      break;
+    case COMPLETION_INSTALLER_ERROR_OTHER:
+      status_format = _T("Installer failed with error code %s.");
+      break;
+    case COMPLETION_CANCELLED:
+      status_format = _T("Operation canceled. Code %s.");
+      break;
+    default:
+      status_format = _T("Unknown status. Code %s.");
+      ASSERT1(false);
+  }
+
+  CString output;
+  output.Format(status_format, error_code_string);
+
+  if (!text.IsEmpty()) {
+    output.Append(_T(" ") + text);
+  }
+
+  return output;
+}
+
+}  // namespace omaha
+
diff --git a/worker/job.h b/worker/job.h
index 2b43bbc..9a0f2c5 100644
--- a/worker/job.h
+++ b/worker/job.h
@@ -1,262 +1,262 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// job.h : Contains the JobList and the Job class.

-// The Job goes through a number of states as represented by the following

-// state diagram for updates and installs.

-//

-//                  START

-//                    |

-//               DOWNLOAD STARTED ----------|

-//                    |                     |-> COMPLETED(ERROR)

-//              DOWNLOAD COMPLETED ---------|

-//                    |                     |

-//              INSTALL STARTED    ---------|

-//                    |

-//          COMPLETED(SUCCESS|RESTART BROWSER)

-//

-

-#ifndef OMAHA_WORKER_JOB_H__

-#define OMAHA_WORKER_JOB_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "goopdate/google_update_idl.h"

-#include "omaha/common/browser_utils.h"

-#include "omaha/common/constants.h"

-#include "omaha/goopdate/update_response.h"

-#include "omaha/net/network_request.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/application_manager.h"

-

-namespace omaha {

-

-class DownloadManager;

-class InstallManager;

-class JobObserver;

-class Ping;

-class UpdateResponse;

-

-enum JobCompletionStatus {

-  COMPLETION_SUCCESS = 0,

-  COMPLETION_SUCCESS_REBOOT_REQUIRED,

-  COMPLETION_ERROR,

-  COMPLETION_INSTALLER_ERROR_MSI,

-  COMPLETION_INSTALLER_ERROR_SYSTEM,

-  COMPLETION_INSTALLER_ERROR_OTHER,

-  COMPLETION_CANCELLED,

-};

-

-// Represents the text and the error code of an error message.

-struct CompletionInfo {

-  CompletionInfo()

-      : status(COMPLETION_SUCCESS),

-        error_code(S_OK) {}

-  CompletionInfo(JobCompletionStatus stat,

-                 DWORD error,

-                 CString txt)

-      : status(stat),

-        error_code(error),

-        text(txt) {}

-

-  CString ToString() const;

-

-  JobCompletionStatus status;  // Job status on completion.

-  DWORD error_code;

-  CString text;                // Success or failure text.

-};

-

-bool IsCompletionStatusSuccess(JobCompletionStatus status);

-bool IsCompletionStatusInstallerError(JobCompletionStatus status);

-inline bool IsCompletionSuccess(CompletionInfo info) {

-  return IsCompletionStatusSuccess(info.status);

-}

-inline bool IsCompletionInstallerError(CompletionInfo info) {

-  return IsCompletionStatusInstallerError(info.status);

-}

-

-

-// These are reported in failure pings. If changing existing values, let the

-// team know and maybe change the kJobStateExtraCodeMask.

-enum JobState {

-  JOBSTATE_START = 1,               // Initial state.

-  JOBSTATE_DOWNLOADSTARTED,         // Started the download of the installer.

-  JOBSTATE_DOWNLOADCOMPLETED,       // Completed the download from the server.

-  JOBSTATE_INSTALLERSTARTED,        // Installer run.

-  JOBSTATE_COMPLETED                // Job completed.

-};

-

-// The job contains information about install or update jobs.

-class Job : public NetworkRequestCallback {

- public:

-  // Differentiates JobState values from other extra_code1 values.

-  static const int kJobStateExtraCodeMask = 0x10000000;

-

-  Job(bool is_update, Ping* ping);

-  virtual ~Job();

-

-  // Transition the job into an completed state.

-  virtual void NotifyCompleted(const CompletionInfo& info);

-

-  // NetworkRequestCallback implementation.

-  virtual void OnProgress(int bytes,

-                          int bytes_total,

-                          int status,

-                          const TCHAR* status_text);

-

-  void RestartBrowsers();

-  void LaunchBrowser(const CString& url);

-

-  // If the installer has set a custom command line in the installer results

-  // registry, we run the command after a successful interactive install.

-  HRESULT LaunchCmdLine();

-

-  virtual HRESULT Download(DownloadManager* manager);

-  virtual HRESULT Install();

-

-

-

-  // Getters and Setters for all the data members.

-

-  const AppData& app_data() const { return app_data_; }

-  void set_app_data(const AppData& app_data);

-

-  CString download_file_name() const { return download_file_name_; }

-  void set_download_file_name(const CString& download_file_name) {

-    download_file_name_ = download_file_name;

-  }

-

-  CString launch_cmd_line() const { return launch_cmd_line_; }

-  void set_launch_cmd_line(const CString& launch_cmd_line) {

-    launch_cmd_line_ = launch_cmd_line;

-  }

-

-  uint32 user_explorer_pid() const { return user_explorer_pid_; }

-  void set_user_explorer_pid(uint32 explorer_pid) {

-    user_explorer_pid_ = explorer_pid;

-  }

-

-  const CompletionInfo& info() const { return info_; }

-  void set_extra_code1(int extra_code1) {

-    extra_code1_ = extra_code1;

-  }

-  JobState job_state() const { return job_state_; }

-  int bytes_downloaded() const { return bytes_downloaded_; }

-  int bytes_total() const { return bytes_total_; }

-  void set_job_observer(JobObserver* job_observer) {

-    job_observer_ = job_observer;

-  }

-  bool is_machine_app() const { return app_data_.is_machine_app(); }

-

-  void set_update_response_data(const UpdateResponseData& response_data) {

-    update_response_data_ = response_data;

-  }

-

-  const UpdateResponseData& response_data() const {

-    return update_response_data_;

-  }

-

-  bool is_update() const {

-    return is_update_;

-  }

-  bool is_offline() const {

-    return is_offline_;

-  }

-  void set_is_offline(bool is_offline) {

-    is_offline_ = is_offline;

-  }

-  bool is_background() const {

-    return is_background_;

-  }

-  void set_is_background(bool is_background) {

-    is_background_ = is_background;

-  }

-  void set_is_update_check_only(bool is_update_check_only) {

-    is_update_check_only_ = is_update_check_only;

-  }

-

-  HRESULT GetInstallerData(CString* installer_data) const;

-

- private:

-  HRESULT ShouldRestartBrowser() const;

-  CompletionCodes CompletionStatusToCompletionCode(

-      JobCompletionStatus status) const;

-  HRESULT DoCompleteJob();

-  HRESULT SendStateChangePing(JobState previous_state);

-  PingEvent::Types JobStateToEventType() const;

-  void ChangeState(JobState state, bool send_ping);

-  HRESULT NotifyUI();

-  void NotifyDownloadStarted();

-  void NotifyDownloadComplete();

-  void NotifyInstallStarted();

-  HRESULT DoInstall(CompletionInfo* completion_info, AppData* new_app_data);

-  HRESULT UpdateJob();

-  HRESULT UpdateRegistry(AppData* new_app_data);

-  HRESULT DeleteJobDownloadDirectory() const;

-

-  AppData app_data_;

-  CString download_file_name_;   // The name of the downloaded file.

-  CString launch_cmd_line_;      // Custom command to run after successful

-                                 // install.

-  CompletionInfo info_;          // The completion info.

-  int extra_code1_;              // Extra info to send in pings.

-                                 // Cleared after each ping.

-  JobState job_state_;           // The state of the job.

-  JobObserver* job_observer_;    // Pointer to an observer for the job

-                                 // events.

-

-  // Other miscellaneous information.

-  uint32 user_explorer_pid_;     // Identifies user that initiated job.

-

-  UpdateResponseData update_response_data_;

-

-  // Represent the job information during download.

-  int bytes_downloaded_;         // The number of bytes downloaded.

-  int bytes_total_;              // The download file size in bytes.

-  Ping* ping_;                   // The Ping object used to send pings.

-

-  // True if the job is any kind of update and false if it is an install.

-  bool is_update_;

-

-  // True if the job is using offline data instead of an online update check.

-  bool is_offline_;

-

-  // True if the job is running silently in the background but not if running

-  // silently at the request of another process.

-  bool is_background_;

-

-  // True if the job is intended to do an update check only, for instance, in

-  // an on demand check for updates case.

-  bool is_update_check_only_;

-

-  // True if the launch command failed to launch. Only set if the launch was

-  // attempted and failed. Does not reflect successful execution or exit code.

-  bool did_launch_cmd_fail_;

-

-  friend class InstallManagerTest;

-  friend class JobTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Job);

-};

-

-typedef std::vector<Job*> Jobs;

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_JOB_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// job.h : Contains the JobList and the Job class.
+// The Job goes through a number of states as represented by the following
+// state diagram for updates and installs.
+//
+//                  START
+//                    |
+//               DOWNLOAD STARTED ----------|
+//                    |                     |-> COMPLETED(ERROR)
+//              DOWNLOAD COMPLETED ---------|
+//                    |                     |
+//              INSTALL STARTED    ---------|
+//                    |
+//          COMPLETED(SUCCESS|RESTART BROWSER)
+//
+
+#ifndef OMAHA_WORKER_JOB_H__
+#define OMAHA_WORKER_JOB_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "goopdate/google_update_idl.h"
+#include "omaha/common/browser_utils.h"
+#include "omaha/common/constants.h"
+#include "omaha/goopdate/update_response.h"
+#include "omaha/net/network_request.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/application_manager.h"
+
+namespace omaha {
+
+class DownloadManager;
+class InstallManager;
+class JobObserver;
+class Ping;
+class UpdateResponse;
+
+enum JobCompletionStatus {
+  COMPLETION_SUCCESS = 0,
+  COMPLETION_SUCCESS_REBOOT_REQUIRED,
+  COMPLETION_ERROR,
+  COMPLETION_INSTALLER_ERROR_MSI,
+  COMPLETION_INSTALLER_ERROR_SYSTEM,
+  COMPLETION_INSTALLER_ERROR_OTHER,
+  COMPLETION_CANCELLED,
+};
+
+// Represents the text and the error code of an error message.
+struct CompletionInfo {
+  CompletionInfo()
+      : status(COMPLETION_SUCCESS),
+        error_code(S_OK) {}
+  CompletionInfo(JobCompletionStatus stat,
+                 DWORD error,
+                 CString txt)
+      : status(stat),
+        error_code(error),
+        text(txt) {}
+
+  CString ToString() const;
+
+  JobCompletionStatus status;  // Job status on completion.
+  DWORD error_code;
+  CString text;                // Success or failure text.
+};
+
+bool IsCompletionStatusSuccess(JobCompletionStatus status);
+bool IsCompletionStatusInstallerError(JobCompletionStatus status);
+inline bool IsCompletionSuccess(CompletionInfo info) {
+  return IsCompletionStatusSuccess(info.status);
+}
+inline bool IsCompletionInstallerError(CompletionInfo info) {
+  return IsCompletionStatusInstallerError(info.status);
+}
+
+
+// These are reported in failure pings. If changing existing values, let the
+// team know and maybe change the kJobStateExtraCodeMask.
+enum JobState {
+  JOBSTATE_START = 1,               // Initial state.
+  JOBSTATE_DOWNLOADSTARTED,         // Started the download of the installer.
+  JOBSTATE_DOWNLOADCOMPLETED,       // Completed the download from the server.
+  JOBSTATE_INSTALLERSTARTED,        // Installer run.
+  JOBSTATE_COMPLETED                // Job completed.
+};
+
+// The job contains information about install or update jobs.
+class Job : public NetworkRequestCallback {
+ public:
+  // Differentiates JobState values from other extra_code1 values.
+  static const int kJobStateExtraCodeMask = 0x10000000;
+
+  Job(bool is_update, Ping* ping);
+  virtual ~Job();
+
+  // Transition the job into an completed state.
+  virtual void NotifyCompleted(const CompletionInfo& info);
+
+  // NetworkRequestCallback implementation.
+  virtual void OnProgress(int bytes,
+                          int bytes_total,
+                          int status,
+                          const TCHAR* status_text);
+
+  void RestartBrowsers();
+  void LaunchBrowser(const CString& url);
+
+  // If the installer has set a custom command line in the installer results
+  // registry, we run the command after a successful interactive install.
+  HRESULT LaunchCmdLine();
+
+  virtual HRESULT Download(DownloadManager* manager);
+  virtual HRESULT Install();
+
+
+
+  // Getters and Setters for all the data members.
+
+  const AppData& app_data() const { return app_data_; }
+  void set_app_data(const AppData& app_data);
+
+  CString download_file_name() const { return download_file_name_; }
+  void set_download_file_name(const CString& download_file_name) {
+    download_file_name_ = download_file_name;
+  }
+
+  CString launch_cmd_line() const { return launch_cmd_line_; }
+  void set_launch_cmd_line(const CString& launch_cmd_line) {
+    launch_cmd_line_ = launch_cmd_line;
+  }
+
+  uint32 user_explorer_pid() const { return user_explorer_pid_; }
+  void set_user_explorer_pid(uint32 explorer_pid) {
+    user_explorer_pid_ = explorer_pid;
+  }
+
+  const CompletionInfo& info() const { return info_; }
+  void set_extra_code1(int extra_code1) {
+    extra_code1_ = extra_code1;
+  }
+  JobState job_state() const { return job_state_; }
+  int bytes_downloaded() const { return bytes_downloaded_; }
+  int bytes_total() const { return bytes_total_; }
+  void set_job_observer(JobObserver* job_observer) {
+    job_observer_ = job_observer;
+  }
+  bool is_machine_app() const { return app_data_.is_machine_app(); }
+
+  void set_update_response_data(const UpdateResponseData& response_data) {
+    update_response_data_ = response_data;
+  }
+
+  const UpdateResponseData& response_data() const {
+    return update_response_data_;
+  }
+
+  bool is_update() const {
+    return is_update_;
+  }
+  bool is_offline() const {
+    return is_offline_;
+  }
+  void set_is_offline(bool is_offline) {
+    is_offline_ = is_offline;
+  }
+  bool is_background() const {
+    return is_background_;
+  }
+  void set_is_background(bool is_background) {
+    is_background_ = is_background;
+  }
+  void set_is_update_check_only(bool is_update_check_only) {
+    is_update_check_only_ = is_update_check_only;
+  }
+
+  HRESULT GetInstallerData(CString* installer_data) const;
+
+ private:
+  HRESULT ShouldRestartBrowser() const;
+  CompletionCodes CompletionStatusToCompletionCode(
+      JobCompletionStatus status) const;
+  HRESULT DoCompleteJob();
+  HRESULT SendStateChangePing(JobState previous_state);
+  PingEvent::Types JobStateToEventType() const;
+  void ChangeState(JobState state, bool send_ping);
+  HRESULT NotifyUI();
+  void NotifyDownloadStarted();
+  void NotifyDownloadComplete();
+  void NotifyInstallStarted();
+  HRESULT DoInstall(CompletionInfo* completion_info, AppData* new_app_data);
+  HRESULT UpdateJob();
+  HRESULT UpdateRegistry(AppData* new_app_data);
+  HRESULT DeleteJobDownloadDirectory() const;
+
+  AppData app_data_;
+  CString download_file_name_;   // The name of the downloaded file.
+  CString launch_cmd_line_;      // Custom command to run after successful
+                                 // install.
+  CompletionInfo info_;          // The completion info.
+  int extra_code1_;              // Extra info to send in pings.
+                                 // Cleared after each ping.
+  JobState job_state_;           // The state of the job.
+  JobObserver* job_observer_;    // Pointer to an observer for the job
+                                 // events.
+
+  // Other miscellaneous information.
+  uint32 user_explorer_pid_;     // Identifies user that initiated job.
+
+  UpdateResponseData update_response_data_;
+
+  // Represent the job information during download.
+  int bytes_downloaded_;         // The number of bytes downloaded.
+  int bytes_total_;              // The download file size in bytes.
+  Ping* ping_;                   // The Ping object used to send pings.
+
+  // True if the job is any kind of update and false if it is an install.
+  bool is_update_;
+
+  // True if the job is using offline data instead of an online update check.
+  bool is_offline_;
+
+  // True if the job is running silently in the background but not if running
+  // silently at the request of another process.
+  bool is_background_;
+
+  // True if the job is intended to do an update check only, for instance, in
+  // an on demand check for updates case.
+  bool is_update_check_only_;
+
+  // True if the launch command failed to launch. Only set if the launch was
+  // attempted and failed. Does not reflect successful execution or exit code.
+  bool did_launch_cmd_fail_;
+
+  friend class InstallManagerTest;
+  friend class JobTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Job);
+};
+
+typedef std::vector<Job*> Jobs;
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_JOB_H__
+
diff --git a/worker/job_creator.cc b/worker/job_creator.cc
index 62e7ac3..a0929f3 100644
--- a/worker/job_creator.cc
+++ b/worker/job_creator.cc
@@ -1,629 +1,629 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/worker/job_creator.h"

-

-#include <windows.h>

-#include <atlcom.h>

-#include <cstring>

-#include <map>

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/path.h"

-#include "omaha/common/time.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_xml_parser.h"

-#include "omaha/goopdate/request.h"

-#include "omaha/goopdate/resource.h"

-#include "omaha/goopdate/update_response_data.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/ping.h"

-#include "omaha/worker/worker_event_logger.h"

-#include "omaha/worker/worker_metrics.h"

-

-namespace omaha {

-

-HRESULT JobCreator::CreateJobsFromResponses(

-    const UpdateResponses& responses,

-    const ProductDataVector& products,

-    Jobs* jobs,

-    Request* ping_request,

-    CString* event_log_text,

-    CompletionInfo* completion_info) {

-  ASSERT1(jobs);

-  ASSERT1(ping_request);

-  ASSERT1(event_log_text);

-  ASSERT1(completion_info);

-  CORE_LOG(L2, (_T("[JobCreator::CreateJobsFromResponses]")));

-

-  // First check to see if GoogleUpdate update is available, if so we only

-  // create the job for googleupdate and don't create jobs for the rest.

-  if (IsGoopdateUpdateAvailable(responses)) {

-    return CreateGoopdateJob(responses,

-                             products,

-                             jobs,

-                             ping_request,

-                             event_log_text,

-                             completion_info);

-  }

-

-  return CreateJobsFromResponsesInternal(responses,

-                                         products,

-                                         jobs,

-                                         ping_request,

-                                         event_log_text,

-                                         completion_info);

-}

-

-bool JobCreator::IsGoopdateUpdateAvailable(const UpdateResponses& responses) {

-  UpdateResponses::const_iterator iter = responses.find(kGoopdateGuid);

-  if (iter == responses.end()) {

-    return false;

-  }

-

-  const UpdateResponse& update_response = iter->second;

-  return (_tcsicmp(kResponseStatusOkValue,

-                   update_response.update_response_data().status()) == 0);

-}

-

-void JobCreator::AddAppUpdateDeferredPing(const AppData& product_data,

-                                          Request* ping_request) {

-  ASSERT1(ping_request);

-

-  AppRequest ping_app_request;

-  AppRequestData ping_app_request_data(product_data);

-  PingEvent ping_event(PingEvent::EVENT_UPDATE_COMPLETE,

-                       PingEvent::EVENT_RESULT_UPDATE_DEFERRED,

-                       0,

-                       0,  // extra code 1

-                       product_data.previous_version());

-  ping_app_request_data.AddPingEvent(ping_event);

-  ping_app_request.set_request_data(ping_app_request_data);

-  ping_request->AddAppRequest(ping_app_request);

-}

-

-HRESULT JobCreator::CreateGoopdateJob(const UpdateResponses& responses,

-                                      const ProductDataVector& products,

-                                      Jobs* jobs,

-                                      Request* ping_request,

-                                      CString* event_log_text,

-                                      CompletionInfo* completion_info) {

-  ASSERT1(jobs);

-  ASSERT1(ping_request);

-  ASSERT1(event_log_text);

-  ASSERT1(completion_info);

-

-  UpdateResponses::const_iterator it = responses.find(kGoopdateGuid);

-  if (it == responses.end()) {

-    return E_INVALIDARG;

-  }

-

-  UpdateResponses goopdate_responses;

-  goopdate_responses[kGoopdateGuid] = it->second;

-

-  // Create a job for GoogleUpdate only and defer updates for other products,

-  // if updates are available.

-  ProductDataVector goopdate_products;

-  bool is_other_app_update_available(false);

-  for (size_t i = 0; i < products.size(); ++i) {

-    const GUID app_id = products[i].app_data().app_guid();

-    if (::IsEqualGUID(app_id, kGoopdateGuid)) {

-      goopdate_products.push_back(products[i]);

-    } else {

-      it = responses.find(app_id);

-      if (it != responses.end() && IsUpdateAvailable(it->second)) {

-        is_other_app_update_available = true;

-        AddAppUpdateDeferredPing(products[i].app_data(), ping_request);

-      }

-    }

-  }

-  ASSERT1(goopdate_products.size() == 1);

-

-  if (is_other_app_update_available) {

-    ++metric_worker_skipped_app_update_for_self_update;

-  }

-

-  return CreateJobsFromResponsesInternal(goopdate_responses,

-                                         goopdate_products,

-                                         jobs,

-                                         ping_request,

-                                         event_log_text,

-                                         completion_info);

-}

-

-HRESULT JobCreator::ReadOfflineManifest(const CString& offline_dir,

-                                        const CString& app_guid,

-                                        UpdateResponse* response) {

-  ASSERT1(response);

-

-  CString manifest_filename = app_guid + _T(".gup");

-  CString manifest_path = ConcatenatePath(offline_dir, manifest_filename);

-  if (!File::Exists(manifest_path)) {

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-

-  UpdateResponses responses;

-  HRESULT hr = GoopdateXmlParser::ParseManifestFile(manifest_path, &responses);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[Could not parse manifest][%s]"), manifest_path));

-    return hr;

-  }

-  ASSERT1(!responses.empty());

-  ASSERT1(1 == responses.size());

-

-  UpdateResponses::const_iterator iter = responses.begin();

-  *response = iter->second;

-  ASSERT1(!app_guid.CompareNoCase(GuidToString(

-      response->update_response_data().guid())));

-  return S_OK;

-}

-

-HRESULT JobCreator::FindOfflineFilePath(const CString& offline_dir,

-                                        const CString& app_guid,

-                                        CString* file_path) {

-  ASSERT1(file_path);

-  file_path->Empty();

-

-  CString offline_app_dir = ConcatenatePath(offline_dir, app_guid);

-  CString pattern(_T("*"));

-  std::vector<CString> files;

-  HRESULT hr = FindFiles(offline_app_dir, pattern, &files);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  CString local_file_path;

-  // Skip over "." and "..".

-  size_t i = 0;

-  for (; i < files.size(); ++i) {

-    local_file_path = ConcatenatePath(offline_app_dir, files[i]);

-    if (!File::IsDirectory(local_file_path)) {

-      break;

-    }

-  }

-  if (i == files.size()) {

-    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);

-  }

-

-  *file_path = local_file_path;

-  return S_OK;

-}

-

-HRESULT JobCreator::CreateOfflineJobs(const CString& offline_dir,

-                                      const ProductDataVector& products,

-                                      Jobs* jobs,

-                                      Request* ping_request,

-                                      CString* event_log_text,

-                                      CompletionInfo* completion_info) {

-  CORE_LOG(L2, (_T("[JobCreator::CreateOfflineJobs]")));

-  ASSERT1(jobs);

-  ASSERT1(ping_request);

-  ASSERT1(event_log_text);

-  ASSERT1(completion_info);

-

-  ProductDataVector::const_iterator products_it = products.begin();

-  for (; products_it != products.end(); ++products_it) {

-    const ProductData& product_data = *products_it;

-    CString guid(GuidToString(product_data.app_data().app_guid()));

-    UpdateResponse response;

-    CString file_path;

-

-    HRESULT hr = ReadOfflineManifest(offline_dir, guid, &response);

-    if (SUCCEEDED(hr)) {

-      hr = FindOfflineFilePath(offline_dir, guid, &file_path);

-    }

-    if (SUCCEEDED(hr)) {

-      hr = goopdate_utils::ValidateDownloadedFile(

-               file_path,

-               response.update_response_data().hash(),

-               static_cast<uint32>(response.update_response_data().size()));

-    }

-    if (FAILED(hr)) {

-      *completion_info = CompletionInfo(COMPLETION_ERROR, hr, _T(""));

-      return hr;

-    }

-

-    Job* product_job = NULL;

-    hr = HandleProductUpdateIsAvailable(product_data,

-                                        response,

-                                        &product_job,

-                                        ping_request,

-                                        event_log_text,

-                                        completion_info);

-    if (FAILED(hr)) {

-      return hr;

-    }

-

-    product_job->set_download_file_name(file_path);

-    product_job->set_is_offline(true);

-    jobs->push_back(product_job);

-  }

-

-  return S_OK;

-}

-

-HRESULT JobCreator::CreateJobsFromResponsesInternal(

-    const UpdateResponses& responses,

-    const ProductDataVector& products,

-    Jobs* jobs,

-    Request* ping_request,

-    CString* event_log_text,

-    CompletionInfo* completion_info) {

-  ASSERT1(jobs);

-  ASSERT1(ping_request);

-  ASSERT1(event_log_text);

-  ASSERT1(completion_info);

-  CORE_LOG(L2, (_T("[JobCreator::CreateJobsFromResponsesInternal]")));

-

-  // The ordering needs to be done based on the products array, instead of

-  // basing this on the responses. This is because the first element in the

-  // job that is created is considered the primary app.

-  ProductDataVector::const_iterator products_it = products.begin();

-  for (; products_it != products.end(); ++products_it) {

-    const ProductData& product_data = *products_it;

-    AppData product_app_data = product_data.app_data();

-

-    UpdateResponses::const_iterator iter =

-        responses.find(product_app_data.app_guid());

-    if (iter == responses.end()) {

-      AppRequestData ping_app_request_data(product_app_data);

-      HandleResponseNotFound(product_app_data,

-                             &ping_app_request_data,

-                             event_log_text);

-      continue;

-    }

-

-    const UpdateResponse& response = iter->second;

-

-    AppManager app_manager(is_machine_);

-    // If this is an update job, need to call

-    // AppManager::UpdateApplicationState() to make sure the registry is

-    // initialized properly.

-    if (is_update_) {

-      app_manager.UpdateApplicationState(&product_app_data);

-    }

-

-    // Write the TT Token, if any, with what the server returned. The server

-    // may ask us to clear the token as well.

-    app_manager.WriteTTToken(product_app_data, response.update_response_data());

-

-    if (IsUpdateAvailable(response)) {

-      if (product_data.app_data().is_update_disabled()) {

-        ASSERT1(is_update_);

-        ASSERT1(!fail_if_update_not_available_);

-        CORE_LOG(L1, (_T("[Update available for update-disabled app][%s]"),

-                      GuidToString(product_data.app_data().app_guid())));

-        app_manager.ClearUpdateAvailableStats(

-            GUID_NULL,

-            product_data.app_data().app_guid());

-      } else {

-        ProductData modified_product_data(product_data);

-        modified_product_data.set_app_data(product_app_data);

-        Job* product_job = NULL;

-        HRESULT hr = HandleProductUpdateIsAvailable(modified_product_data,

-                                                    response,

-                                                    &product_job,

-                                                    ping_request,

-                                                    event_log_text,

-                                                    completion_info);

-        if (FAILED(hr)) {

-          return hr;

-        }

-

-        jobs->push_back(product_job);

-      }

-    } else {

-      AppRequest ping_app_request;

-      AppRequestData ping_app_request_data(product_app_data);

-      HRESULT hr = HandleUpdateNotAvailable(product_app_data,

-                                            response.update_response_data(),

-                                            &ping_app_request_data,

-                                            event_log_text,

-                                            completion_info);

-      // TODO(omaha): It's unclear why the ping is added before the FAILED

-      // check here but after it in HandleProductUpdateIsAvailable(). Is this

-      // intentional?

-      ping_app_request.set_request_data(ping_app_request_data);

-      ping_request->AddAppRequest(ping_app_request);

-      if (FAILED(hr)) {

-        return hr;

-      }

-    }

-  }

-

-  return S_OK;

-}

-

-HRESULT JobCreator::HandleProductUpdateIsAvailable(

-    const ProductData& product_data,

-    const UpdateResponse& response,

-    Job** product_job,

-    Request* ping_request,

-    CString* event_log_text,

-    CompletionInfo* completion_info) {

-  ASSERT1(product_job);

-

-  AppData product_app_data = product_data.app_data();

-  AppRequest ping_app_request;

-  AppRequestData ping_app_request_data(product_app_data);

-

-  if (is_update_) {

-    // previous_version should have been populated above.

-    ASSERT1(!product_app_data.previous_version().IsEmpty());

-  } else {

-    // Copy the current version of app, if available, to previous version

-    // in the AppData object so it is sent in pings.

-    AppData existing_app_data;

-    AppManager app_manager(is_machine_);

-    HRESULT hr = app_manager.ReadAppDataFromStore(

-                     GUID_NULL,

-                     product_app_data.app_guid(),

-                     &existing_app_data);

-    if (SUCCEEDED(hr)) {

-      product_app_data.set_previous_version(existing_app_data.version());

-    }

-  }

-

-  ASSERT1(::IsEqualGUID(GUID_NULL, product_app_data.parent_app_guid()));

-  HandleUpdateIsAvailable(product_app_data,

-                          response.update_response_data(),

-                          &ping_app_request_data,

-                          event_log_text,

-                          product_job);

-  ASSERT1(*product_job);

-  ping_app_request.set_request_data(ping_app_request_data);

-

-  ping_request->AddAppRequest(ping_app_request);

-  return S_OK;

-}

-

-void JobCreator::HandleResponseNotFound(const AppData& app_data,

-                                        AppRequestData* ping_app_request_data,

-                                        CString* event_log_text) {

-  ASSERT1(event_log_text);

-  ASSERT1(ping_app_request_data);

-

-  PingEvent::Types event_type = is_update_ ?

-                                PingEvent::EVENT_UPDATE_COMPLETE :

-                                PingEvent::EVENT_INSTALL_COMPLETE;

-  PingEvent ping_event(event_type,

-                       PingEvent::EVENT_RESULT_ERROR,

-                       GOOPDATE_E_NO_SERVER_RESPONSE,

-                       0,  // extra code 1

-                       app_data.previous_version());

-  ping_app_request_data->AddPingEvent(ping_event);

-

-  event_log_text->AppendFormat(

-      _T("App=%s, Ver=%s, Status=no-response-received\n"),

-      GuidToString(app_data.app_guid()),

-      app_data.version());

-}

-

-void JobCreator::HandleUpdateIsAvailable(

-    const AppData& app_data,

-    const UpdateResponseData& response_data,

-    AppRequestData* ping_app_request_data,

-    CString* event_log_text,

-    Job** job) {

-  ASSERT1(ping_app_request_data);

-  ASSERT1(event_log_text);

-  ASSERT1(job);

-  ASSERT1(!app_data.is_update_disabled());

-

-  if (is_auto_update_) {

-    if (::IsEqualGUID(kGoopdateGuid, app_data.app_guid())) {

-      ++metric_worker_self_updates_available;

-    } else {

-      ++metric_worker_app_updates_available;

-    }

-

-    // Only record an update available event for updates.

-    // We have other mechanisms, including IID, to track install success.

-    AppManager app_manager(is_machine_);

-    app_manager.UpdateUpdateAvailableStats(app_data.parent_app_guid(),

-                                           app_data.app_guid());

-  }

-

-  // Ping and record events only for "real" jobs. On demand update checks only

-  // jobs should not ping, since no update is actually applied.

-  if (!is_update_check_only_) {

-    PingEvent::Types event_type = is_update_ ?

-                                  PingEvent::EVENT_UPDATE_APPLICATION_BEGIN :

-                                  PingEvent::EVENT_INSTALL_APPLICATION_BEGIN;

-    PingEvent ping_event(event_type,

-                         PingEvent::EVENT_RESULT_SUCCESS,

-                         0,  // error code

-                         0,  // extra code 1

-                         app_data.previous_version());

-    ping_app_request_data->AddPingEvent(ping_event);

-  }

-  const TCHAR* status = is_update_check_only_ ? _T("check only") :

-                        is_update_ ? _T("update") : _T("install");

-  event_log_text->AppendFormat(_T("App=%s, Ver=%s, Status=%s\n"),

-                               GuidToString(app_data.app_guid()),

-                               app_data.version(),

-                               status);

-

-  // TODO(omaha): When components are implemented, how do we handle the case

-  // that this is just a place holder and does not really need an update?

-  // We may be in an app that only needs an update here because it's child

-  // components need updates so we'll need to flag the job of that somehow.

-  // Unless it's already tagged in the response_data (which does know that

-  // there's nothing to download) but the job state will need to be updated.

-  scoped_ptr<Job> new_job(new Job(is_update_, ping_));

-  new_job->set_app_data(app_data);

-  new_job->set_update_response_data(response_data);

-  new_job->set_is_background(is_auto_update_);

-  new_job->set_is_update_check_only(is_update_check_only_);

-

-  *job = new_job.release();

-}

-

-HRESULT JobCreator::HandleUpdateNotAvailable(

-    const AppData& app_data,

-    const UpdateResponseData& response_data,

-    AppRequestData* ping_app_request_data,

-    CString* event_log_text,

-    CompletionInfo* completion_info) {

-  ASSERT1(ping_app_request_data);

-  ASSERT1(event_log_text);

-  ASSERT1(completion_info);

-

-  PingEvent::Results result_type = PingEvent::EVENT_RESULT_ERROR;

-  CompletionInfo info = UpdateResponseDataToCompletionInfo(

-      response_data,

-      ping_app_request_data->app_data().display_name());

-  switch (info.error_code) {

-    case static_cast<DWORD>(GOOPDATE_E_NO_UPDATE_RESPONSE):

-      event_log_text->AppendFormat(

-          _T("App=%s, Ver=%s, Status=no-update\n"),

-          GuidToString(app_data.app_guid()),

-          app_data.version());

-      if (is_update_) {

-        // In case of updates, a "noupdate" response is not an error.

-        result_type = PingEvent::EVENT_RESULT_NOUPDATE;

-        info.status = COMPLETION_SUCCESS;

-        info.error_code = NOERROR;

-

-        AppManager app_manager(is_machine_);

-        app_manager.ClearUpdateAvailableStats(app_data.parent_app_guid(),

-                                              app_data.app_guid());

-        app_manager.RecordSuccessfulUpdateCheck(app_data.parent_app_guid(),

-                                                app_data.app_guid());

-      }

-      break;

-    case static_cast<DWORD>(GOOPDATE_E_RESTRICTED_SERVER_RESPONSE):

-      event_log_text->AppendFormat(

-          _T("App=%s, Ver=%s, Status=restricted\n"),

-          GuidToString(app_data.app_guid()),

-          app_data.version());

-      break;

-    case GOOPDATE_E_UNKNOWN_APP_SERVER_RESPONSE:

-    case GOOPDATE_E_INTERNAL_ERROR_SERVER_RESPONSE:

-    case GOOPDATE_E_UNKNOWN_SERVER_RESPONSE:

-    default:

-      event_log_text->AppendFormat(_T("App=%s, Ver=%s, Status=error:0x%08x\n"),

-                                   GuidToString(app_data.app_guid()),

-                                   app_data.version(),

-                                   info.error_code);

-      break;

-  }

-

-  // Only ping for server responses other than "noupdate" or errors.

-  if (result_type != PingEvent::EVENT_RESULT_NOUPDATE ||

-      info.error_code != NOERROR) {

-    PingEvent::Types event_type = is_update_ ?

-                                  PingEvent::EVENT_UPDATE_COMPLETE :

-                                  PingEvent::EVENT_INSTALL_COMPLETE;

-    PingEvent ping_event(event_type,

-                         result_type,

-                         info.error_code,

-                         0,  // extra code 1

-                         app_data.previous_version());

-    ping_app_request_data->AddPingEvent(ping_event);

-  }

-

-  if (fail_if_update_not_available_) {

-    *completion_info = info;

-    return info.error_code;

-  }

-

-  return S_OK;

-}

-

-// app_name in UpdateResponseData is not filled in. See the TODO in that class.

-CompletionInfo JobCreator::UpdateResponseDataToCompletionInfo(

-    const UpdateResponseData& response_data,

-    const CString& display_name) {

-  CompletionInfo info;

-  const CString& status = response_data.status();

-  if (_tcsicmp(kResponseStatusOkValue, status) == 0) {

-    info.status = COMPLETION_SUCCESS;

-    info.error_code = 0;

-  } else if (_tcsicmp(kResponseStatusNoUpdate, status) == 0) {

-    // "noupdate" is considered an error but the calling code can map it to

-    // a successful completion, in the cases of silent and on demand updates.

-    info.status = COMPLETION_ERROR;

-    info.error_code = static_cast<DWORD>(GOOPDATE_E_NO_UPDATE_RESPONSE);

-    VERIFY1(info.text.LoadString(IDS_NO_UPDATE_RESPONSE));

-  } else if (_tcsicmp(kResponseStatusRestrictedExportCountry, status) == 0) {

-    // "restricted"

-    info.status = COMPLETION_ERROR;

-    info.error_code =

-        static_cast<DWORD>(GOOPDATE_E_RESTRICTED_SERVER_RESPONSE);

-    VERIFY1(info.text.LoadString(IDS_RESTRICTED_RESPONSE_FROM_SERVER));

-  } else if (_tcsicmp(kResponseStatusUnKnownApplication, status) == 0) {

-    // "error-UnKnownApplication"

-    info.status = COMPLETION_ERROR;

-    info.error_code =

-        static_cast<DWORD>(GOOPDATE_E_UNKNOWN_APP_SERVER_RESPONSE);

-    VERIFY1(info.text.LoadString(IDS_UNKNOWN_APPLICATION));

-  } else if (_tcsicmp(kResponseStatusOsNotSupported, status) == 0) {

-    // "error-OsNotSupported"

-    info.status = COMPLETION_ERROR;

-    info.error_code = static_cast<DWORD>(GOOPDATE_E_OS_NOT_SUPPORTED);

-    if (response_data.error_url().IsEmpty()) {

-      info.text.FormatMessage(IDS_NON_OK_RESPONSE_FROM_SERVER, status);

-    } else {

-      info.text.FormatMessage(IDS_OS_NOT_SUPPORTED,

-                              display_name,

-                              response_data.error_url());

-    }

-  } else if (_tcsicmp(kResponseStatusInternalError, status) == 0) {

-    // "error-internal"

-    info.status = COMPLETION_ERROR;

-    info.error_code =

-        static_cast<DWORD>(GOOPDATE_E_INTERNAL_ERROR_SERVER_RESPONSE);

-    info.text.FormatMessage(IDS_NON_OK_RESPONSE_FROM_SERVER, status);

-  } else {

-    // Unknown response.

-    info.status = COMPLETION_ERROR;

-    info.error_code =

-        static_cast<DWORD>(GOOPDATE_E_UNKNOWN_SERVER_RESPONSE);

-    info.text.FormatMessage(IDS_NON_OK_RESPONSE_FROM_SERVER, status);

-  }

-

-  return info;

-}

-

-bool JobCreator::IsUpdateAvailable(const UpdateResponseData& response_data) {

-  return _tcsicmp(kResponseStatusOkValue, response_data.status()) == 0;

-}

-

-// Check response and all of its children to see if any of them are in a state

-// that requires an update job to be created.

-bool JobCreator::IsUpdateAvailable(const UpdateResponse& response) {

-  // If the top level response needs updating, short circuit here.

-  if (IsUpdateAvailable(response.update_response_data())) {

-    return true;

-  }

-

-  UpdateResponseDatas::const_iterator it;

-  for (it = response.components_begin();

-       it != response.components_begin();

-       ++it) {

-    if (IsUpdateAvailable(it->second)) {

-      return true;

-    }

-  }

-

-  return false;

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/worker/job_creator.h"
+
+#include <windows.h>
+#include <atlcom.h>
+#include <cstring>
+#include <map>
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/path.h"
+#include "omaha/common/time.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_xml_parser.h"
+#include "omaha/goopdate/request.h"
+#include "omaha/goopdate/resource.h"
+#include "omaha/goopdate/update_response_data.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/ping.h"
+#include "omaha/worker/worker_event_logger.h"
+#include "omaha/worker/worker_metrics.h"
+
+namespace omaha {
+
+HRESULT JobCreator::CreateJobsFromResponses(
+    const UpdateResponses& responses,
+    const ProductDataVector& products,
+    Jobs* jobs,
+    Request* ping_request,
+    CString* event_log_text,
+    CompletionInfo* completion_info) {
+  ASSERT1(jobs);
+  ASSERT1(ping_request);
+  ASSERT1(event_log_text);
+  ASSERT1(completion_info);
+  CORE_LOG(L2, (_T("[JobCreator::CreateJobsFromResponses]")));
+
+  // First check to see if GoogleUpdate update is available, if so we only
+  // create the job for googleupdate and don't create jobs for the rest.
+  if (IsGoopdateUpdateAvailable(responses)) {
+    return CreateGoopdateJob(responses,
+                             products,
+                             jobs,
+                             ping_request,
+                             event_log_text,
+                             completion_info);
+  }
+
+  return CreateJobsFromResponsesInternal(responses,
+                                         products,
+                                         jobs,
+                                         ping_request,
+                                         event_log_text,
+                                         completion_info);
+}
+
+bool JobCreator::IsGoopdateUpdateAvailable(const UpdateResponses& responses) {
+  UpdateResponses::const_iterator iter = responses.find(kGoopdateGuid);
+  if (iter == responses.end()) {
+    return false;
+  }
+
+  const UpdateResponse& update_response = iter->second;
+  return (_tcsicmp(kResponseStatusOkValue,
+                   update_response.update_response_data().status()) == 0);
+}
+
+void JobCreator::AddAppUpdateDeferredPing(const AppData& product_data,
+                                          Request* ping_request) {
+  ASSERT1(ping_request);
+
+  AppRequest ping_app_request;
+  AppRequestData ping_app_request_data(product_data);
+  PingEvent ping_event(PingEvent::EVENT_UPDATE_COMPLETE,
+                       PingEvent::EVENT_RESULT_UPDATE_DEFERRED,
+                       0,
+                       0,  // extra code 1
+                       product_data.previous_version());
+  ping_app_request_data.AddPingEvent(ping_event);
+  ping_app_request.set_request_data(ping_app_request_data);
+  ping_request->AddAppRequest(ping_app_request);
+}
+
+HRESULT JobCreator::CreateGoopdateJob(const UpdateResponses& responses,
+                                      const ProductDataVector& products,
+                                      Jobs* jobs,
+                                      Request* ping_request,
+                                      CString* event_log_text,
+                                      CompletionInfo* completion_info) {
+  ASSERT1(jobs);
+  ASSERT1(ping_request);
+  ASSERT1(event_log_text);
+  ASSERT1(completion_info);
+
+  UpdateResponses::const_iterator it = responses.find(kGoopdateGuid);
+  if (it == responses.end()) {
+    return E_INVALIDARG;
+  }
+
+  UpdateResponses goopdate_responses;
+  goopdate_responses[kGoopdateGuid] = it->second;
+
+  // Create a job for GoogleUpdate only and defer updates for other products,
+  // if updates are available.
+  ProductDataVector goopdate_products;
+  bool is_other_app_update_available(false);
+  for (size_t i = 0; i < products.size(); ++i) {
+    const GUID app_id = products[i].app_data().app_guid();
+    if (::IsEqualGUID(app_id, kGoopdateGuid)) {
+      goopdate_products.push_back(products[i]);
+    } else {
+      it = responses.find(app_id);
+      if (it != responses.end() && IsUpdateAvailable(it->second)) {
+        is_other_app_update_available = true;
+        AddAppUpdateDeferredPing(products[i].app_data(), ping_request);
+      }
+    }
+  }
+  ASSERT1(goopdate_products.size() == 1);
+
+  if (is_other_app_update_available) {
+    ++metric_worker_skipped_app_update_for_self_update;
+  }
+
+  return CreateJobsFromResponsesInternal(goopdate_responses,
+                                         goopdate_products,
+                                         jobs,
+                                         ping_request,
+                                         event_log_text,
+                                         completion_info);
+}
+
+HRESULT JobCreator::ReadOfflineManifest(const CString& offline_dir,
+                                        const CString& app_guid,
+                                        UpdateResponse* response) {
+  ASSERT1(response);
+
+  CString manifest_filename = app_guid + _T(".gup");
+  CString manifest_path = ConcatenatePath(offline_dir, manifest_filename);
+  if (!File::Exists(manifest_path)) {
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+
+  UpdateResponses responses;
+  HRESULT hr = GoopdateXmlParser::ParseManifestFile(manifest_path, &responses);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[Could not parse manifest][%s]"), manifest_path));
+    return hr;
+  }
+  ASSERT1(!responses.empty());
+  ASSERT1(1 == responses.size());
+
+  UpdateResponses::const_iterator iter = responses.begin();
+  *response = iter->second;
+  ASSERT1(!app_guid.CompareNoCase(GuidToString(
+      response->update_response_data().guid())));
+  return S_OK;
+}
+
+HRESULT JobCreator::FindOfflineFilePath(const CString& offline_dir,
+                                        const CString& app_guid,
+                                        CString* file_path) {
+  ASSERT1(file_path);
+  file_path->Empty();
+
+  CString offline_app_dir = ConcatenatePath(offline_dir, app_guid);
+  CString pattern(_T("*"));
+  std::vector<CString> files;
+  HRESULT hr = FindFiles(offline_app_dir, pattern, &files);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  CString local_file_path;
+  // Skip over "." and "..".
+  size_t i = 0;
+  for (; i < files.size(); ++i) {
+    local_file_path = ConcatenatePath(offline_app_dir, files[i]);
+    if (!File::IsDirectory(local_file_path)) {
+      break;
+    }
+  }
+  if (i == files.size()) {
+    return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+  }
+
+  *file_path = local_file_path;
+  return S_OK;
+}
+
+HRESULT JobCreator::CreateOfflineJobs(const CString& offline_dir,
+                                      const ProductDataVector& products,
+                                      Jobs* jobs,
+                                      Request* ping_request,
+                                      CString* event_log_text,
+                                      CompletionInfo* completion_info) {
+  CORE_LOG(L2, (_T("[JobCreator::CreateOfflineJobs]")));
+  ASSERT1(jobs);
+  ASSERT1(ping_request);
+  ASSERT1(event_log_text);
+  ASSERT1(completion_info);
+
+  ProductDataVector::const_iterator products_it = products.begin();
+  for (; products_it != products.end(); ++products_it) {
+    const ProductData& product_data = *products_it;
+    CString guid(GuidToString(product_data.app_data().app_guid()));
+    UpdateResponse response;
+    CString file_path;
+
+    HRESULT hr = ReadOfflineManifest(offline_dir, guid, &response);
+    if (SUCCEEDED(hr)) {
+      hr = FindOfflineFilePath(offline_dir, guid, &file_path);
+    }
+    if (SUCCEEDED(hr)) {
+      hr = goopdate_utils::ValidateDownloadedFile(
+               file_path,
+               response.update_response_data().hash(),
+               static_cast<uint32>(response.update_response_data().size()));
+    }
+    if (FAILED(hr)) {
+      *completion_info = CompletionInfo(COMPLETION_ERROR, hr, _T(""));
+      return hr;
+    }
+
+    Job* product_job = NULL;
+    hr = HandleProductUpdateIsAvailable(product_data,
+                                        response,
+                                        &product_job,
+                                        ping_request,
+                                        event_log_text,
+                                        completion_info);
+    if (FAILED(hr)) {
+      return hr;
+    }
+
+    product_job->set_download_file_name(file_path);
+    product_job->set_is_offline(true);
+    jobs->push_back(product_job);
+  }
+
+  return S_OK;
+}
+
+HRESULT JobCreator::CreateJobsFromResponsesInternal(
+    const UpdateResponses& responses,
+    const ProductDataVector& products,
+    Jobs* jobs,
+    Request* ping_request,
+    CString* event_log_text,
+    CompletionInfo* completion_info) {
+  ASSERT1(jobs);
+  ASSERT1(ping_request);
+  ASSERT1(event_log_text);
+  ASSERT1(completion_info);
+  CORE_LOG(L2, (_T("[JobCreator::CreateJobsFromResponsesInternal]")));
+
+  // The ordering needs to be done based on the products array, instead of
+  // basing this on the responses. This is because the first element in the
+  // job that is created is considered the primary app.
+  ProductDataVector::const_iterator products_it = products.begin();
+  for (; products_it != products.end(); ++products_it) {
+    const ProductData& product_data = *products_it;
+    AppData product_app_data = product_data.app_data();
+
+    UpdateResponses::const_iterator iter =
+        responses.find(product_app_data.app_guid());
+    if (iter == responses.end()) {
+      AppRequestData ping_app_request_data(product_app_data);
+      HandleResponseNotFound(product_app_data,
+                             &ping_app_request_data,
+                             event_log_text);
+      continue;
+    }
+
+    const UpdateResponse& response = iter->second;
+
+    AppManager app_manager(is_machine_);
+    // If this is an update job, need to call
+    // AppManager::UpdateApplicationState() to make sure the registry is
+    // initialized properly.
+    if (is_update_) {
+      app_manager.UpdateApplicationState(&product_app_data);
+    }
+
+    // Write the TT Token, if any, with what the server returned. The server
+    // may ask us to clear the token as well.
+    app_manager.WriteTTToken(product_app_data, response.update_response_data());
+
+    if (IsUpdateAvailable(response)) {
+      if (product_data.app_data().is_update_disabled()) {
+        ASSERT1(is_update_);
+        ASSERT1(!fail_if_update_not_available_);
+        CORE_LOG(L1, (_T("[Update available for update-disabled app][%s]"),
+                      GuidToString(product_data.app_data().app_guid())));
+        app_manager.ClearUpdateAvailableStats(
+            GUID_NULL,
+            product_data.app_data().app_guid());
+      } else {
+        ProductData modified_product_data(product_data);
+        modified_product_data.set_app_data(product_app_data);
+        Job* product_job = NULL;
+        HRESULT hr = HandleProductUpdateIsAvailable(modified_product_data,
+                                                    response,
+                                                    &product_job,
+                                                    ping_request,
+                                                    event_log_text,
+                                                    completion_info);
+        if (FAILED(hr)) {
+          return hr;
+        }
+
+        jobs->push_back(product_job);
+      }
+    } else {
+      AppRequest ping_app_request;
+      AppRequestData ping_app_request_data(product_app_data);
+      HRESULT hr = HandleUpdateNotAvailable(product_app_data,
+                                            response.update_response_data(),
+                                            &ping_app_request_data,
+                                            event_log_text,
+                                            completion_info);
+      // TODO(omaha): It's unclear why the ping is added before the FAILED
+      // check here but after it in HandleProductUpdateIsAvailable(). Is this
+      // intentional?
+      ping_app_request.set_request_data(ping_app_request_data);
+      ping_request->AddAppRequest(ping_app_request);
+      if (FAILED(hr)) {
+        return hr;
+      }
+    }
+  }
+
+  return S_OK;
+}
+
+HRESULT JobCreator::HandleProductUpdateIsAvailable(
+    const ProductData& product_data,
+    const UpdateResponse& response,
+    Job** product_job,
+    Request* ping_request,
+    CString* event_log_text,
+    CompletionInfo* completion_info) {
+  ASSERT1(product_job);
+
+  AppData product_app_data = product_data.app_data();
+  AppRequest ping_app_request;
+  AppRequestData ping_app_request_data(product_app_data);
+
+  if (is_update_) {
+    // previous_version should have been populated above.
+    ASSERT1(!product_app_data.previous_version().IsEmpty());
+  } else {
+    // Copy the current version of app, if available, to previous version
+    // in the AppData object so it is sent in pings.
+    AppData existing_app_data;
+    AppManager app_manager(is_machine_);
+    HRESULT hr = app_manager.ReadAppDataFromStore(
+                     GUID_NULL,
+                     product_app_data.app_guid(),
+                     &existing_app_data);
+    if (SUCCEEDED(hr)) {
+      product_app_data.set_previous_version(existing_app_data.version());
+    }
+  }
+
+  ASSERT1(::IsEqualGUID(GUID_NULL, product_app_data.parent_app_guid()));
+  HandleUpdateIsAvailable(product_app_data,
+                          response.update_response_data(),
+                          &ping_app_request_data,
+                          event_log_text,
+                          product_job);
+  ASSERT1(*product_job);
+  ping_app_request.set_request_data(ping_app_request_data);
+
+  ping_request->AddAppRequest(ping_app_request);
+  return S_OK;
+}
+
+void JobCreator::HandleResponseNotFound(const AppData& app_data,
+                                        AppRequestData* ping_app_request_data,
+                                        CString* event_log_text) {
+  ASSERT1(event_log_text);
+  ASSERT1(ping_app_request_data);
+
+  PingEvent::Types event_type = is_update_ ?
+                                PingEvent::EVENT_UPDATE_COMPLETE :
+                                PingEvent::EVENT_INSTALL_COMPLETE;
+  PingEvent ping_event(event_type,
+                       PingEvent::EVENT_RESULT_ERROR,
+                       GOOPDATE_E_NO_SERVER_RESPONSE,
+                       0,  // extra code 1
+                       app_data.previous_version());
+  ping_app_request_data->AddPingEvent(ping_event);
+
+  event_log_text->AppendFormat(
+      _T("App=%s, Ver=%s, Status=no-response-received\n"),
+      GuidToString(app_data.app_guid()),
+      app_data.version());
+}
+
+void JobCreator::HandleUpdateIsAvailable(
+    const AppData& app_data,
+    const UpdateResponseData& response_data,
+    AppRequestData* ping_app_request_data,
+    CString* event_log_text,
+    Job** job) {
+  ASSERT1(ping_app_request_data);
+  ASSERT1(event_log_text);
+  ASSERT1(job);
+  ASSERT1(!app_data.is_update_disabled());
+
+  if (is_auto_update_) {
+    if (::IsEqualGUID(kGoopdateGuid, app_data.app_guid())) {
+      ++metric_worker_self_updates_available;
+    } else {
+      ++metric_worker_app_updates_available;
+    }
+
+    // Only record an update available event for updates.
+    // We have other mechanisms, including IID, to track install success.
+    AppManager app_manager(is_machine_);
+    app_manager.UpdateUpdateAvailableStats(app_data.parent_app_guid(),
+                                           app_data.app_guid());
+  }
+
+  // Ping and record events only for "real" jobs. On demand update checks only
+  // jobs should not ping, since no update is actually applied.
+  if (!is_update_check_only_) {
+    PingEvent::Types event_type = is_update_ ?
+                                  PingEvent::EVENT_UPDATE_APPLICATION_BEGIN :
+                                  PingEvent::EVENT_INSTALL_APPLICATION_BEGIN;
+    PingEvent ping_event(event_type,
+                         PingEvent::EVENT_RESULT_SUCCESS,
+                         0,  // error code
+                         0,  // extra code 1
+                         app_data.previous_version());
+    ping_app_request_data->AddPingEvent(ping_event);
+  }
+  const TCHAR* status = is_update_check_only_ ? _T("check only") :
+                        is_update_ ? _T("update") : _T("install");
+  event_log_text->AppendFormat(_T("App=%s, Ver=%s, Status=%s\n"),
+                               GuidToString(app_data.app_guid()),
+                               app_data.version(),
+                               status);
+
+  // TODO(omaha): When components are implemented, how do we handle the case
+  // that this is just a place holder and does not really need an update?
+  // We may be in an app that only needs an update here because it's child
+  // components need updates so we'll need to flag the job of that somehow.
+  // Unless it's already tagged in the response_data (which does know that
+  // there's nothing to download) but the job state will need to be updated.
+  scoped_ptr<Job> new_job(new Job(is_update_, ping_));
+  new_job->set_app_data(app_data);
+  new_job->set_update_response_data(response_data);
+  new_job->set_is_background(is_auto_update_);
+  new_job->set_is_update_check_only(is_update_check_only_);
+
+  *job = new_job.release();
+}
+
+HRESULT JobCreator::HandleUpdateNotAvailable(
+    const AppData& app_data,
+    const UpdateResponseData& response_data,
+    AppRequestData* ping_app_request_data,
+    CString* event_log_text,
+    CompletionInfo* completion_info) {
+  ASSERT1(ping_app_request_data);
+  ASSERT1(event_log_text);
+  ASSERT1(completion_info);
+
+  PingEvent::Results result_type = PingEvent::EVENT_RESULT_ERROR;
+  CompletionInfo info = UpdateResponseDataToCompletionInfo(
+      response_data,
+      ping_app_request_data->app_data().display_name());
+  switch (info.error_code) {
+    case static_cast<DWORD>(GOOPDATE_E_NO_UPDATE_RESPONSE):
+      event_log_text->AppendFormat(
+          _T("App=%s, Ver=%s, Status=no-update\n"),
+          GuidToString(app_data.app_guid()),
+          app_data.version());
+      if (is_update_) {
+        // In case of updates, a "noupdate" response is not an error.
+        result_type = PingEvent::EVENT_RESULT_NOUPDATE;
+        info.status = COMPLETION_SUCCESS;
+        info.error_code = NOERROR;
+
+        AppManager app_manager(is_machine_);
+        app_manager.ClearUpdateAvailableStats(app_data.parent_app_guid(),
+                                              app_data.app_guid());
+        app_manager.RecordSuccessfulUpdateCheck(app_data.parent_app_guid(),
+                                                app_data.app_guid());
+      }
+      break;
+    case static_cast<DWORD>(GOOPDATE_E_RESTRICTED_SERVER_RESPONSE):
+      event_log_text->AppendFormat(
+          _T("App=%s, Ver=%s, Status=restricted\n"),
+          GuidToString(app_data.app_guid()),
+          app_data.version());
+      break;
+    case GOOPDATE_E_UNKNOWN_APP_SERVER_RESPONSE:
+    case GOOPDATE_E_INTERNAL_ERROR_SERVER_RESPONSE:
+    case GOOPDATE_E_UNKNOWN_SERVER_RESPONSE:
+    default:
+      event_log_text->AppendFormat(_T("App=%s, Ver=%s, Status=error:0x%08x\n"),
+                                   GuidToString(app_data.app_guid()),
+                                   app_data.version(),
+                                   info.error_code);
+      break;
+  }
+
+  // Only ping for server responses other than "noupdate" or errors.
+  if (result_type != PingEvent::EVENT_RESULT_NOUPDATE ||
+      info.error_code != NOERROR) {
+    PingEvent::Types event_type = is_update_ ?
+                                  PingEvent::EVENT_UPDATE_COMPLETE :
+                                  PingEvent::EVENT_INSTALL_COMPLETE;
+    PingEvent ping_event(event_type,
+                         result_type,
+                         info.error_code,
+                         0,  // extra code 1
+                         app_data.previous_version());
+    ping_app_request_data->AddPingEvent(ping_event);
+  }
+
+  if (fail_if_update_not_available_) {
+    *completion_info = info;
+    return info.error_code;
+  }
+
+  return S_OK;
+}
+
+// app_name in UpdateResponseData is not filled in. See the TODO in that class.
+CompletionInfo JobCreator::UpdateResponseDataToCompletionInfo(
+    const UpdateResponseData& response_data,
+    const CString& display_name) {
+  CompletionInfo info;
+  const CString& status = response_data.status();
+  if (_tcsicmp(kResponseStatusOkValue, status) == 0) {
+    info.status = COMPLETION_SUCCESS;
+    info.error_code = 0;
+  } else if (_tcsicmp(kResponseStatusNoUpdate, status) == 0) {
+    // "noupdate" is considered an error but the calling code can map it to
+    // a successful completion, in the cases of silent and on demand updates.
+    info.status = COMPLETION_ERROR;
+    info.error_code = static_cast<DWORD>(GOOPDATE_E_NO_UPDATE_RESPONSE);
+    VERIFY1(info.text.LoadString(IDS_NO_UPDATE_RESPONSE));
+  } else if (_tcsicmp(kResponseStatusRestrictedExportCountry, status) == 0) {
+    // "restricted"
+    info.status = COMPLETION_ERROR;
+    info.error_code =
+        static_cast<DWORD>(GOOPDATE_E_RESTRICTED_SERVER_RESPONSE);
+    VERIFY1(info.text.LoadString(IDS_RESTRICTED_RESPONSE_FROM_SERVER));
+  } else if (_tcsicmp(kResponseStatusUnKnownApplication, status) == 0) {
+    // "error-UnKnownApplication"
+    info.status = COMPLETION_ERROR;
+    info.error_code =
+        static_cast<DWORD>(GOOPDATE_E_UNKNOWN_APP_SERVER_RESPONSE);
+    VERIFY1(info.text.LoadString(IDS_UNKNOWN_APPLICATION));
+  } else if (_tcsicmp(kResponseStatusOsNotSupported, status) == 0) {
+    // "error-OsNotSupported"
+    info.status = COMPLETION_ERROR;
+    info.error_code = static_cast<DWORD>(GOOPDATE_E_OS_NOT_SUPPORTED);
+    if (response_data.error_url().IsEmpty()) {
+      info.text.FormatMessage(IDS_NON_OK_RESPONSE_FROM_SERVER, status);
+    } else {
+      info.text.FormatMessage(IDS_OS_NOT_SUPPORTED,
+                              display_name,
+                              response_data.error_url());
+    }
+  } else if (_tcsicmp(kResponseStatusInternalError, status) == 0) {
+    // "error-internal"
+    info.status = COMPLETION_ERROR;
+    info.error_code =
+        static_cast<DWORD>(GOOPDATE_E_INTERNAL_ERROR_SERVER_RESPONSE);
+    info.text.FormatMessage(IDS_NON_OK_RESPONSE_FROM_SERVER, status);
+  } else {
+    // Unknown response.
+    info.status = COMPLETION_ERROR;
+    info.error_code =
+        static_cast<DWORD>(GOOPDATE_E_UNKNOWN_SERVER_RESPONSE);
+    info.text.FormatMessage(IDS_NON_OK_RESPONSE_FROM_SERVER, status);
+  }
+
+  return info;
+}
+
+bool JobCreator::IsUpdateAvailable(const UpdateResponseData& response_data) {
+  return _tcsicmp(kResponseStatusOkValue, response_data.status()) == 0;
+}
+
+// Check response and all of its children to see if any of them are in a state
+// that requires an update job to be created.
+bool JobCreator::IsUpdateAvailable(const UpdateResponse& response) {
+  // If the top level response needs updating, short circuit here.
+  if (IsUpdateAvailable(response.update_response_data())) {
+    return true;
+  }
+
+  UpdateResponseDatas::const_iterator it;
+  for (it = response.components_begin();
+       it != response.components_begin();
+       ++it) {
+    if (IsUpdateAvailable(it->second)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+}  // namespace omaha
+
diff --git a/worker/job_creator.h b/worker/job_creator.h
index fd3ffd8..0c92d8c 100644
--- a/worker/job_creator.h
+++ b/worker/job_creator.h
@@ -1,150 +1,150 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// job_creator.h:  Class that handles creating jobs out of ProductData that's

-// being requested to be installed/updated and the UpdateResponse objects

-// received from the server.  Builds up proper job hierarchy, ping data, error

-// handling, and event logging since this overall operation is pretty complex.

-

-#ifndef OMAHA_WORKER_JOB_CREATOR_H__

-#define OMAHA_WORKER_JOB_CREATOR_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/goopdate/request.h"

-#include "omaha/goopdate/update_response.h"

-#include "omaha/worker/job.h"

-#include "omaha/worker/product_data.h"

-

-namespace omaha {

-

-class AppData;

-

-class JobCreator {

- public:

-  // The caller retains ownership of ping. Delete this object and the Jobs it

-  // creates before deleting the Ping.

-  JobCreator(bool is_machine, bool is_update, Ping* ping)

-      : ping_(ping),

-        is_machine_(is_machine),

-        is_update_(is_update),

-        is_auto_update_(false),

-        is_update_check_only_(false),

-        fail_if_update_not_available_(false) {}

-  ~JobCreator() {}

-  HRESULT CreateJobsFromResponses(const UpdateResponses& responses,

-                                  const ProductDataVector& products,

-                                  Jobs* jobs,

-                                  Request* ping_request,

-                                  CString* event_log_text,

-                                  CompletionInfo* completion_info);

-

-  // Creates jobs based on offline installers that are stored in {guid}

-  // subdirectories under offline_dir. offline_dir is typically

-  // Google\Update\Offline\.

-  HRESULT CreateOfflineJobs(const CString& offline_dir,

-                            const ProductDataVector& products,

-                            Jobs* jobs,

-                            Request* ping_request,

-                            CString* event_log_text,

-                            CompletionInfo* completion_info);

-

-  void set_is_auto_update(bool is_auto_update) {

-    is_auto_update_ = is_auto_update;

-  }

-  void set_is_update_check_only(bool is_update_check_only) {

-    is_update_check_only_ = is_update_check_only;

-  }

-  void set_fail_if_update_not_available(bool fail_if_update_not_available) {

-    fail_if_update_not_available_ = fail_if_update_not_available;

-  }

-

- private:

-  // Read offline manifest offline_dir\{guid}.gup.

-  static HRESULT ReadOfflineManifest(const CString& offline_dir,

-                                     const CString& app_guid,

-                                     UpdateResponse* response);

-

-  // Finds offline installer stored under offline_dir\{guid}.

-  static HRESULT FindOfflineFilePath(const CString& offline_dir,

-                                     const CString& app_guid,

-                                     CString* file_path);

-

-  HRESULT CreateJobsFromResponsesInternal(

-      const UpdateResponses& responses,

-      const ProductDataVector& products,

-      Jobs* jobs,

-      Request* ping_request,

-      CString* event_log_text,

-      CompletionInfo* completion_info);

-

-  HRESULT HandleProductUpdateIsAvailable(

-      const ProductData& product_data,

-      const UpdateResponse& response,

-      Job** product_job,

-      Request* ping_request,

-      CString* event_log_text,

-      CompletionInfo* completion_info);

-

-  HRESULT CreateGoopdateJob(const UpdateResponses& responses,

-                            const ProductDataVector& products,

-                            Jobs* jobs,

-                            Request* ping_request,

-                            CString* event_log_text,

-                            CompletionInfo* completion_info);

-

-  bool IsGoopdateUpdateAvailable(const UpdateResponses& responses);

-

-  void HandleResponseNotFound(const AppData& app_data,

-                              AppRequestData* ping_app_request_data,

-                              CString* event_log_text);

-  void HandleUpdateIsAvailable(const AppData& app_data,

-                               const UpdateResponseData& response_data,

-                               AppRequestData* ping_app_request_data,

-                               CString* event_log_text,

-                               Job** job);

-  HRESULT HandleUpdateNotAvailable(const AppData& app_data,

-                                   const UpdateResponseData& response_data,

-                                   AppRequestData* ping_app_request_data,

-                                   CString* event_log_text,

-                                   CompletionInfo* completion_info);

-  CompletionInfo UpdateResponseDataToCompletionInfo(

-      const UpdateResponseData& response_data,

-      const CString& display_name);

-  bool IsUpdateAvailable(const UpdateResponseData& response_data);

-  bool IsUpdateAvailable(const UpdateResponse& response);

-  void AddAppUpdateDeferredPing(const AppData& product_data,

-                                Request* ping_request);

-

-  Ping* ping_;

-  bool is_machine_;

-  bool is_update_;

-  // True, if the jobs is intended to do an update check only, for instance, in

-  // an on demand check for updates case.

-  bool is_auto_update_;

-  bool is_update_check_only_;

-  bool fail_if_update_not_available_;

-

-  friend class JobCreatorTest;

-  DISALLOW_EVIL_CONSTRUCTORS(JobCreator);

-};

-

-}  // namespace omaha.

-

-#endif  // OMAHA_WORKER_JOB_CREATOR_H__

-

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// job_creator.h:  Class that handles creating jobs out of ProductData that's
+// being requested to be installed/updated and the UpdateResponse objects
+// received from the server.  Builds up proper job hierarchy, ping data, error
+// handling, and event logging since this overall operation is pretty complex.
+
+#ifndef OMAHA_WORKER_JOB_CREATOR_H__
+#define OMAHA_WORKER_JOB_CREATOR_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/goopdate/request.h"
+#include "omaha/goopdate/update_response.h"
+#include "omaha/worker/job.h"
+#include "omaha/worker/product_data.h"
+
+namespace omaha {
+
+class AppData;
+
+class JobCreator {
+ public:
+  // The caller retains ownership of ping. Delete this object and the Jobs it
+  // creates before deleting the Ping.
+  JobCreator(bool is_machine, bool is_update, Ping* ping)
+      : ping_(ping),
+        is_machine_(is_machine),
+        is_update_(is_update),
+        is_auto_update_(false),
+        is_update_check_only_(false),
+        fail_if_update_not_available_(false) {}
+  ~JobCreator() {}
+  HRESULT CreateJobsFromResponses(const UpdateResponses& responses,
+                                  const ProductDataVector& products,
+                                  Jobs* jobs,
+                                  Request* ping_request,
+                                  CString* event_log_text,
+                                  CompletionInfo* completion_info);
+
+  // Creates jobs based on offline installers that are stored in {guid}
+  // subdirectories under offline_dir. offline_dir is typically
+  // Google\Update\Offline\.
+  HRESULT CreateOfflineJobs(const CString& offline_dir,
+                            const ProductDataVector& products,
+                            Jobs* jobs,
+                            Request* ping_request,
+                            CString* event_log_text,
+                            CompletionInfo* completion_info);
+
+  void set_is_auto_update(bool is_auto_update) {
+    is_auto_update_ = is_auto_update;
+  }
+  void set_is_update_check_only(bool is_update_check_only) {
+    is_update_check_only_ = is_update_check_only;
+  }
+  void set_fail_if_update_not_available(bool fail_if_update_not_available) {
+    fail_if_update_not_available_ = fail_if_update_not_available;
+  }
+
+ private:
+  // Read offline manifest offline_dir\{guid}.gup.
+  static HRESULT ReadOfflineManifest(const CString& offline_dir,
+                                     const CString& app_guid,
+                                     UpdateResponse* response);
+
+  // Finds offline installer stored under offline_dir\{guid}.
+  static HRESULT FindOfflineFilePath(const CString& offline_dir,
+                                     const CString& app_guid,
+                                     CString* file_path);
+
+  HRESULT CreateJobsFromResponsesInternal(
+      const UpdateResponses& responses,
+      const ProductDataVector& products,
+      Jobs* jobs,
+      Request* ping_request,
+      CString* event_log_text,
+      CompletionInfo* completion_info);
+
+  HRESULT HandleProductUpdateIsAvailable(
+      const ProductData& product_data,
+      const UpdateResponse& response,
+      Job** product_job,
+      Request* ping_request,
+      CString* event_log_text,
+      CompletionInfo* completion_info);
+
+  HRESULT CreateGoopdateJob(const UpdateResponses& responses,
+                            const ProductDataVector& products,
+                            Jobs* jobs,
+                            Request* ping_request,
+                            CString* event_log_text,
+                            CompletionInfo* completion_info);
+
+  bool IsGoopdateUpdateAvailable(const UpdateResponses& responses);
+
+  void HandleResponseNotFound(const AppData& app_data,
+                              AppRequestData* ping_app_request_data,
+                              CString* event_log_text);
+  void HandleUpdateIsAvailable(const AppData& app_data,
+                               const UpdateResponseData& response_data,
+                               AppRequestData* ping_app_request_data,
+                               CString* event_log_text,
+                               Job** job);
+  HRESULT HandleUpdateNotAvailable(const AppData& app_data,
+                                   const UpdateResponseData& response_data,
+                                   AppRequestData* ping_app_request_data,
+                                   CString* event_log_text,
+                                   CompletionInfo* completion_info);
+  CompletionInfo UpdateResponseDataToCompletionInfo(
+      const UpdateResponseData& response_data,
+      const CString& display_name);
+  bool IsUpdateAvailable(const UpdateResponseData& response_data);
+  bool IsUpdateAvailable(const UpdateResponse& response);
+  void AddAppUpdateDeferredPing(const AppData& product_data,
+                                Request* ping_request);
+
+  Ping* ping_;
+  bool is_machine_;
+  bool is_update_;
+  // True, if the jobs is intended to do an update check only, for instance, in
+  // an on demand check for updates case.
+  bool is_auto_update_;
+  bool is_update_check_only_;
+  bool fail_if_update_not_available_;
+
+  friend class JobCreatorTest;
+  DISALLOW_EVIL_CONSTRUCTORS(JobCreator);
+};
+
+}  // namespace omaha.
+
+#endif  // OMAHA_WORKER_JOB_CREATOR_H__
+
+
diff --git a/worker/job_creator_unittest.cc b/worker/job_creator_unittest.cc
index 30edca3..53e0bac 100644
--- a/worker/job_creator_unittest.cc
+++ b/worker/job_creator_unittest.cc
@@ -1,1334 +1,1334 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/time.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/job_creator.h"

-#include "omaha/worker/ping.h"

-#include "omaha/worker/worker_metrics.h"

-

-namespace omaha {

-

-namespace {

-

-const TCHAR* kGuidApp1 = _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");

-const TCHAR* kGuidApp2 = _T("{28A93830-1746-4F0B-90F5-CF44B41169F3}");

-const TCHAR* kGuidApp3 = _T("{E5D3562E-BFAE-48c6-B9C5-4E293F695E0E}");

-const TCHAR* kGuidApp4 = _T("{F9346563-85DA-4dc1-A621-FAF6F869680A}");

-

-const TCHAR* const kApp1ClientStateKeyPathMachine =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");

-const TCHAR* const kApp2ClientStateKeyPathMachine =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{28A93830-1746-4F0B-90F5-CF44B41169F3}");

-const TCHAR* const kApp3ClientStateKeyPathMachine =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{E5D3562E-BFAE-48c6-B9C5-4E293F695E0E}");

-const TCHAR* const kApp4ClientStateKeyPathMachine =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{F9346563-85DA-4dc1-A621-FAF6F869680A}");

-const TCHAR* const kApp1ClientsKeyPathMachine =

-    _T("HKLM\\Software\\Google\\Update\\Clients\\")

-    _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");

-const TCHAR* const kApp2ClientsKeyPathMachine =

-    _T("HKLM\\Software\\Google\\Update\\Clients\\")

-    _T("{28A93830-1746-4F0B-90F5-CF44B41169F3}");

-

-}  // namespace

-

-class JobCreatorTest : public testing::Test {

- protected:

-  JobCreatorTest()

-      : app1_guid_(StringToGuid(kGuidApp1)),

-        app2_guid_(StringToGuid(kGuidApp2)),

-        app3_guid_(StringToGuid(kGuidApp3)),

-        app4_guid_(StringToGuid(kGuidApp4)) {

-  }

-

-  virtual void SetUp() {

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-    OverrideRegistryHives(kRegistryHiveOverrideRoot);

-

-    metric_worker_skipped_app_update_for_self_update.Reset();

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-  }

-

-  CompletionInfo UpdateResponseDataToCompletionInfo(

-      const UpdateResponseData& response_data,

-      const CString& display_name) {

-    JobCreator job_creator(false, false, &ping_);

-    job_creator.set_fail_if_update_not_available(true);

-    return job_creator.UpdateResponseDataToCompletionInfo(response_data,

-                                                          display_name);

-  }

-

-  static HRESULT CallFindOfflineFilePath(const CString& offline_dir,

-                                         const CString& app_guid,

-                                         CString* file_path) {

-    return JobCreator::FindOfflineFilePath(offline_dir, app_guid, file_path);

-  }

-

-  static HRESULT CallReadOfflineManifest(const CString& offline_dir,

-                                         const CString& app_guid,

-                                         UpdateResponse* response) {

-    return JobCreator::ReadOfflineManifest(offline_dir, app_guid, response);

-  }

-

-  Ping ping_;

-  const GUID app1_guid_;

-  const GUID app2_guid_;

-  const GUID app3_guid_;

-  const GUID app4_guid_;

-};

-

-TEST_F(JobCreatorTest, CreateJobsFromResponses_UpdateMultipleAppsAndStatuses) {

-  const CString version_goopdate = _T("1.2.75.3");

-  const CString version_app1 = _T("1.1.2.3");

-  const CString version_app2 = _T("2.0.0.5");

-

-  JobCreator job_creator(true, true, &ping_);

-  job_creator.set_is_auto_update(true);

-  AppManager app_manager(true);

-

-  const DWORD kExistingUpdateValues = 0x70123456;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(kApp2ClientsKeyPathMachine, _T("pv"), version_app2));

-

-  ProductDataVector products;

-

-  AppData app_data_omaha;

-  app_data_omaha.set_app_guid(kGoopdateGuid);

-  app_data_omaha.set_is_machine_app(true);

-  app_data_omaha.set_version(version_goopdate);

-  ProductData product_omaha(app_data_omaha);

-  products.push_back(product_omaha);

-

-  AppData app_data1;

-  app_data1.set_app_guid(app1_guid_);

-  app_data1.set_is_machine_app(true);

-  app_data1.set_version(version_app1);

-  ProductData product1(app_data1);

-  products.push_back(product1);

-

-  AppData app_data2;

-  app_data2.set_app_guid(app2_guid_);

-  app_data2.set_is_machine_app(true);

-  app_data2.set_version(version_app2);

-  ProductData product2(app_data2);

-  products.push_back(product2);

-

-  UpdateResponses responses;

-

-  UpdateResponseData resp_data_omaha;

-  resp_data_omaha.set_guid(kGoopdateGuid);

-  resp_data_omaha.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data_omaha.set_status(kResponseStatusNoUpdate);

-  UpdateResponse resp_omaha(resp_data_omaha);

-  responses.insert(std::pair<GUID, UpdateResponse>(kGoopdateGuid, resp_omaha));

-

-  UpdateResponseData resp_data1;

-  resp_data1.set_guid(app1_guid_);

-  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data1.set_status(kResponseStatusNoUpdate);

-  UpdateResponse resp1(resp_data1);

-  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));

-

-  UpdateResponseData resp_data2;

-  resp_data2.set_guid(app2_guid_);

-  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data2.set_status(kResponseStatusOkValue);

-  // TODO(omaha): Add component responses here.

-  UpdateResponse resp2(resp_data2);

-  responses.insert(std::pair<GUID, UpdateResponse>(app2_guid_, resp2));

-

-  Jobs jobs;

-  Request ping_request(true);

-  CString event_log_text;

-  CompletionInfo completion_info;

-

-  // This should succeed for an update since it's OK to have "no update

-  // available" for updates.

-  EXPECT_SUCCEEDED(job_creator.CreateJobsFromResponses(responses,

-                                                       products,

-                                                       &jobs,

-                                                       &ping_request,

-                                                       &event_log_text,

-                                                       &completion_info));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  // Should be a job for Resp2 since Resp1 was status "No Update".

-  ASSERT_EQ(1, jobs.size());

-  EXPECT_EQ(3, ping_request.get_request_count());

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(0, completion_info.error_code);

-  EXPECT_TRUE(completion_info.text.IsEmpty());

-  EXPECT_FALSE(jobs[0]->is_offline());

-

-  // Sleep so that there is a time difference between the time written in the

-  // registry and now.

-  ::Sleep(20);

-

-  // Omaha.

-  // Update Stats should not have been set because there was no update.

-  // Successful update check set for noupdate but successful update not updated.

-  DWORD update_responses(1);

-  DWORD64 time_since_first_response_ms(1);

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       kGoopdateGuid,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-

-  const uint32 last_check_sec_omaha =

-      GetDwordValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                    kRegValueLastSuccessfulCheckSec);

-  EXPECT_NE(kExistingUpdateValues, last_check_sec_omaha);

-  EXPECT_GE(now, last_check_sec_omaha);

-  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec_omaha);

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                          kRegValueLastUpdateTimeSec));

-

-  // App 1.

-  // Update Stats should not have been set because there was no update.

-  // Successful update check set for noupdate but successful update not updated.

-  update_responses = 1;

-  time_since_first_response_ms = 1;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app1_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-

-  const uint32 last_check_sec_app1 =

-      GetDwordValue(kApp1ClientStateKeyPathMachine,

-                    kRegValueLastSuccessfulCheckSec);

-  EXPECT_NE(kExistingUpdateValues, last_check_sec_app1);

-  EXPECT_GE(now, last_check_sec_app1);

-  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec_app1);

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(kApp1ClientStateKeyPathMachine,

-                          kRegValueLastUpdateTimeSec));

-

-  // App 2.

-  // Update Stats should have been set.

-  // Neither successful update check nor successful update are updated because

-  // the update has not been completed.

-  update_responses = 0;

-  time_since_first_response_ms = 0;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app2_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(1, update_responses);

-  EXPECT_LT(0, time_since_first_response_ms);

-  EXPECT_GT(10 * kMsPerSec, time_since_first_response_ms);

-

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(kApp2ClientStateKeyPathMachine,

-                          kRegValueLastSuccessfulCheckSec));

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(kApp2ClientStateKeyPathMachine,

-                          kRegValueLastUpdateTimeSec));

-}

-

-TEST_F(JobCreatorTest, CreateJobsFromResponses_UpdateForUpdateDisabledApp) {

-  const CString version_goopdate = _T("1.2.75.3");

-  const CString version_app1 = _T("1.1.2.3");

-  const CString version_app2 = _T("2.0.0.5");

-  const CString version_app3 = _T("11.0.0.5");

-  const CString version_app4 = _T("5.0.6.7");

-

-  JobCreator job_creator(true, true, &ping_);

-  job_creator.set_is_auto_update(true);

-  AppManager app_manager(true);

-

-  const DWORD kExistingUpdateValues = 0x70123456;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathMachine,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathMachine,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp4ClientStateKeyPathMachine,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp4ClientStateKeyPathMachine,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(kApp1ClientsKeyPathMachine, _T("pv"), version_app1));

-  EXPECT_SUCCEEDED(

-      RegKey::SetValue(kApp2ClientsKeyPathMachine, _T("pv"), version_app2));

-

-  // Required for testing deletion of this data when updates are disabled (app1)

-  // and noupdate is returned (Omaha and app3).

-  const DWORD64 kUpdateAvailableSince =

-    GetCurrent100NSTime() - 200 * kMsPerSec * kMillisecsTo100ns;

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    kRegValueUpdateAvailableCount,

-                                    static_cast<DWORD>(123456)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                    kRegValueUpdateAvailableSince,

-                                    kUpdateAvailableSince));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,

-                                    kRegValueUpdateAvailableCount,

-                                    static_cast<DWORD>(123)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,

-                                    kRegValueUpdateAvailableSince,

-                                    kUpdateAvailableSince));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,

-                                    kRegValueUpdateAvailableCount,

-                                    static_cast<DWORD>(2345)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,

-                                    kRegValueUpdateAvailableSince,

-                                    kUpdateAvailableSince));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathMachine,

-                                    kRegValueUpdateAvailableCount,

-                                    static_cast<DWORD>(456)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathMachine,

-                                    kRegValueUpdateAvailableSince,

-                                    kUpdateAvailableSince));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp4ClientStateKeyPathMachine,

-                                    kRegValueUpdateAvailableCount,

-                                    static_cast<DWORD>(98)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kApp4ClientStateKeyPathMachine,

-                                    kRegValueUpdateAvailableSince,

-                                    kUpdateAvailableSince));

-  // Verify the data is set correctly.

-  DWORD update_responses(0);

-  DWORD64 time_since_first_response_ms(0);

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       kGoopdateGuid,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(123456, update_responses);

-  EXPECT_LE(200000, time_since_first_response_ms);

-  update_responses = 0;

-  time_since_first_response_ms = 0;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       StringToGuid(kGuidApp1),

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(123, update_responses);

-  EXPECT_LE(200000, time_since_first_response_ms);

-  update_responses = 0;

-  time_since_first_response_ms = 0;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       StringToGuid(kGuidApp2),

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(2345, update_responses);

-  EXPECT_LE(200000, time_since_first_response_ms);

-  update_responses = 0;

-  time_since_first_response_ms = 0;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       StringToGuid(kGuidApp3),

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(456, update_responses);

-  EXPECT_LE(200000, time_since_first_response_ms);

-  update_responses = 0;

-  time_since_first_response_ms = 0;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       StringToGuid(kGuidApp4),

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(98, update_responses);

-  EXPECT_LE(200000, time_since_first_response_ms);

-

-  ProductDataVector products;

-

-  AppData app_data_omaha;

-  app_data_omaha.set_app_guid(kGoopdateGuid);

-  app_data_omaha.set_is_machine_app(true);

-  app_data_omaha.set_version(version_goopdate);

-  ProductData product_omaha(app_data_omaha);

-  products.push_back(product_omaha);

-

-  AppData app_data1;

-  app_data1.set_app_guid(app1_guid_);

-  app_data1.set_is_machine_app(true);

-  app_data1.set_version(version_app1);

-  app_data1.set_is_update_disabled(true);

-  ProductData product1(app_data1);

-  products.push_back(product1);

-

-  AppData app_data2;

-  app_data2.set_app_guid(app2_guid_);

-  app_data2.set_is_machine_app(true);

-  app_data2.set_version(version_app2);

-  ProductData product2(app_data2);

-  products.push_back(product2);

-

-  AppData app_data3;

-  app_data3.set_app_guid(app3_guid_);

-  app_data3.set_is_machine_app(true);

-  app_data3.set_version(version_app3);

-  app_data3.set_is_update_disabled(true);

-  ProductData product3(app_data3);

-  products.push_back(product3);

-

-  AppData app_data4;

-  app_data4.set_app_guid(app4_guid_);

-  app_data4.set_is_machine_app(true);

-  app_data4.set_version(version_app4);

-  ProductData product4(app_data4);

-  products.push_back(product4);

-

-  UpdateResponses responses;

-

-  UpdateResponseData resp_data_omaha;

-  resp_data_omaha.set_guid(kGoopdateGuid);

-  resp_data_omaha.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data_omaha.set_status(kResponseStatusNoUpdate);

-  UpdateResponse resp_omaha(resp_data_omaha);

-  responses.insert(std::pair<GUID, UpdateResponse>(kGoopdateGuid, resp_omaha));

-

-  UpdateResponseData resp_data1;

-  resp_data1.set_guid(app1_guid_);

-  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data1.set_status(kResponseStatusOkValue);

-  UpdateResponse resp1(resp_data1);

-  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));

-

-  UpdateResponseData resp_data2;

-  resp_data2.set_guid(app2_guid_);

-  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data2.set_status(kResponseStatusOkValue);

-  UpdateResponse resp2(resp_data2);

-  responses.insert(std::pair<GUID, UpdateResponse>(app2_guid_, resp2));

-

-  UpdateResponseData resp_data3;

-  resp_data3.set_guid(app3_guid_);

-  resp_data3.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data3.set_status(kResponseStatusNoUpdate);

-  UpdateResponse resp3(resp_data3);

-  responses.insert(std::pair<GUID, UpdateResponse>(app3_guid_, resp3));

-

-  UpdateResponseData resp_data4;

-  resp_data4.set_guid(app4_guid_);

-  resp_data4.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data4.set_status(kResponseStatusInternalError);

-  UpdateResponse resp4(resp_data4);

-  responses.insert(std::pair<GUID, UpdateResponse>(app4_guid_, resp4));

-

-  Jobs jobs;

-  Request ping_request(true);

-  CString event_log_text;

-  CompletionInfo completion_info;

-

-  EXPECT_SUCCEEDED(job_creator.CreateJobsFromResponses(responses,

-                                                       products,

-                                                       &jobs,

-                                                       &ping_request,

-                                                       &event_log_text,

-                                                       &completion_info));

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  // Should be a job for Resp2 only since Resp1 was had updates disabled.

-  ASSERT_EQ(1, jobs.size());

-  // Pings for the update available app, the error-internal app, and the

-  // noupdate apps. No ping for the disabled app with update available.

-  // Not sure why the noupdate apps get a ping.

-  EXPECT_EQ(4, ping_request.get_request_count());

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(0, completion_info.error_code);

-  EXPECT_TRUE(completion_info.text.IsEmpty());

-  EXPECT_FALSE(jobs[0]->is_offline());

-

-  // Sleep so that there is a time difference between the time written in the

-  // registry and now.

-  ::Sleep(20);

-

-  // Omaha.

-  // Update Stats should have been cleared because there was no update - we

-  // should not keep around old data if there is no update to apply.

-  // Successful update check set for noupdate but successful update not updated.

-  update_responses = 1;

-  time_since_first_response_ms = 1;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       kGoopdateGuid,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-

-  const uint32 last_check_sec_omaha =

-      GetDwordValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                    kRegValueLastSuccessfulCheckSec);

-  EXPECT_NE(kExistingUpdateValues, last_check_sec_omaha);

-  EXPECT_GE(now, last_check_sec_omaha);

-  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec_omaha);

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                          kRegValueLastUpdateTimeSec));

-

-  // App 1.

-  // Update Stats should have been cleared because these values are used to

-  // anaylze the success of Omaha and disabled updates would break these stats.

-  // Successful update check and successful update are not set because and

-  // update is available but disabled.

-  update_responses = 1;

-  time_since_first_response_ms = 1;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app1_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(kApp1ClientStateKeyPathMachine,

-                          kRegValueLastSuccessfulCheckSec));

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(kApp1ClientStateKeyPathMachine,

-                          kRegValueLastUpdateTimeSec));

-

-  // App 2.

-  // Update Stats: responses should have been incremented and time since first

-  // response should be based on the value set above.

-  // Neither successful update check nor successful update are updated because

-  // the update has not been completed.

-  update_responses = 0;

-  time_since_first_response_ms = 0;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app2_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(2346, update_responses);

-  EXPECT_LT(200 * kMsPerSec + 20, time_since_first_response_ms);

-  EXPECT_GT(202 * kMsPerSec, time_since_first_response_ms);

-

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(kApp2ClientStateKeyPathMachine,

-                          kRegValueLastSuccessfulCheckSec));

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(kApp2ClientStateKeyPathMachine,

-                          kRegValueLastUpdateTimeSec));

-

-  // App 3.

-  // Update Stats should have been cleared because there was no update - we

-  // should not keep around old data if there is no update to apply.

-  // Successful update check set for noupdate but successful update not updated.

-  update_responses = 1;

-  time_since_first_response_ms = 1;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app3_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-  const uint32 last_check_sec_app3 =

-      GetDwordValue(kApp3ClientStateKeyPathMachine,

-                    kRegValueLastSuccessfulCheckSec);

-  EXPECT_NE(kExistingUpdateValues, last_check_sec_app3);

-  EXPECT_GE(now, last_check_sec_app3);

-  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec_app3);

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(kApp3ClientStateKeyPathMachine,

-                          kRegValueLastUpdateTimeSec));

-

-  // App 4.

-  // Update Stats: responses should have not been incremented and time since

-  // first response should be based on the value set above.

-  // Neither successful update check nor successful update are updated because

-  // the update has not been completed.

-  update_responses = 0;

-  time_since_first_response_ms = 0;

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app4_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(98, update_responses);

-  EXPECT_LT(200 * kMsPerSec + 20, time_since_first_response_ms);

-  EXPECT_GT(202 * kMsPerSec, time_since_first_response_ms);

-

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(kApp4ClientStateKeyPathMachine,

-                          kRegValueLastSuccessfulCheckSec));

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(kApp4ClientStateKeyPathMachine,

-                          kRegValueLastUpdateTimeSec));

-}

-

-// This should fail for an install since it's not OK to have "no update

-// available" for clean installs

-TEST_F(JobCreatorTest, CreateJobsFromResponses_InstallFailure) {

-  const CString version_app1 = _T("1.1.2.3");

-  const CString version_app2 = _T("2.0.0.5");

-

-  JobCreator job_creator(true, false, &ping_);

-  job_creator.set_fail_if_update_not_available(true);

-  AppManager app_manager(true);

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp2ClientStateKeyPathMachine));

-

-  ProductDataVector products;

-  AppData app_data1;

-  app_data1.set_app_guid(app1_guid_);

-  app_data1.set_is_machine_app(true);

-  app_data1.set_version(version_app1);

-  ProductData product1(app_data1);

-  products.push_back(product1);

-

-  AppData app_data2;

-  app_data2.set_app_guid(app2_guid_);

-  app_data2.set_is_machine_app(true);

-  app_data2.set_version(version_app2);

-  ProductData product2(app_data2);

-  products.push_back(product2);

-

-  UpdateResponses responses;

-

-  UpdateResponseData resp_data1;

-  resp_data1.set_guid(app1_guid_);

-  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data1.set_status(kResponseStatusNoUpdate);

-  UpdateResponse resp1(resp_data1);

-  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));

-

-  UpdateResponseData resp_data2;

-  resp_data2.set_guid(app2_guid_);

-  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data2.set_status(kResponseStatusOkValue);

-  // TODO(omaha): Add component responses here.

-  UpdateResponse resp2(resp_data2);

-  responses.insert(std::pair<GUID, UpdateResponse>(app2_guid_, resp2));

-

-  Jobs jobs;

-  Request ping_request(true);

-  CString event_log_text;

-  CompletionInfo completion_info;

-  EXPECT_FAILED(job_creator.CreateJobsFromResponses(responses,

-                                                    products,

-                                                    &jobs,

-                                                    &ping_request,

-                                                    &event_log_text,

-                                                    &completion_info));

-

-  EXPECT_EQ(0, jobs.size());

-  EXPECT_EQ(1, ping_request.get_request_count());

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, completion_info.error_code);

-  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);

-  EXPECT_STREQ(_T("No update is available."), completion_info.text);

-

-  // Sleep so that there would be a time difference between the time written in

-  // the registry and now.

-  ::Sleep(20);

-

-  // There should not be any data because this is an install.

-  DWORD update_responses(1);

-  DWORD64 time_since_first_response_ms(1);

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app1_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app2_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastUpdateTimeSec));

-  EXPECT_FALSE(RegKey::HasValue(kApp2ClientStateKeyPathMachine,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(kApp2ClientStateKeyPathMachine,

-                                kRegValueLastUpdateTimeSec));

-}

-

-TEST_F(JobCreatorTest, CreateJobsFromResponses_InstallSuccess) {

-  const CString version_app1 = _T("1.1.2.3");

-  const CString version_app2 = _T("2.0.0.5");

-

-  JobCreator job_creator(true, false, &ping_);

-  job_creator.set_fail_if_update_not_available(true);

-  AppManager app_manager(true);

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp2ClientStateKeyPathMachine));

-

-  ProductDataVector products;

-  AppData app_data1;

-  app_data1.set_app_guid(app1_guid_);

-  app_data1.set_is_machine_app(true);

-  app_data1.set_version(version_app1);

-  ProductData product1(app_data1);

-  products.push_back(product1);

-

-  AppData app_data2;

-  app_data2.set_app_guid(app2_guid_);

-  app_data2.set_is_machine_app(true);

-  app_data2.set_version(version_app2);

-  ProductData product2(app_data2);

-  products.push_back(product2);

-

-  UpdateResponses responses;

-

-  UpdateResponseData resp_data1;

-  resp_data1.set_guid(app1_guid_);

-  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data1.set_status(kResponseStatusOkValue);

-  UpdateResponse resp1(resp_data1);

-  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));

-

-  UpdateResponseData resp_data2;

-  resp_data2.set_guid(app2_guid_);

-  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data2.set_status(kResponseStatusOkValue);

-  // TODO(omaha): Add component responses here.

-  UpdateResponse resp2(resp_data2);

-  responses.insert(std::pair<GUID, UpdateResponse>(app2_guid_, resp2));

-

-  Jobs jobs;

-  Request ping_request(true);

-  CString event_log_text;

-  CompletionInfo completion_info;

-  EXPECT_SUCCEEDED(job_creator.CreateJobsFromResponses(responses,

-                                                       products,

-                                                       &jobs,

-                                                       &ping_request,

-                                                       &event_log_text,

-                                                       &completion_info));

-

-  ASSERT_EQ(2, jobs.size());

-  EXPECT_EQ(2, ping_request.get_request_count());

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(0, completion_info.error_code);

-  EXPECT_TRUE(completion_info.text.IsEmpty());

-  EXPECT_FALSE(jobs[0]->is_offline());

-  EXPECT_FALSE(jobs[1]->is_offline());

-

-  // Sleep so that there would be a time difference between the time written in

-  // the registry and now.

-  ::Sleep(20);

-

-  // There should not be any data because this is an install.

-  DWORD update_responses(1);

-  DWORD64 time_since_first_response_ms(1);

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app1_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app2_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastUpdateTimeSec));

-  EXPECT_FALSE(RegKey::HasValue(kApp2ClientStateKeyPathMachine,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(kApp2ClientStateKeyPathMachine,

-                                kRegValueLastUpdateTimeSec));

-}

-

-TEST_F(JobCreatorTest, CreateJobsFromResponses_UpdateGoopdateUpdateAvailable) {

-  const CString version_app1 = _T("1.1.2.3");

-  const CString version_goopdate = _T("1.2.75.3");

-

-  JobCreator job_creator(true, true, &ping_);

-  job_creator.set_is_auto_update(true);

-  AppManager app_manager(true);

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,

-                                    _T("pv"),

-                                    version_goopdate));

-

-  ProductDataVector products;

-

-  AppData app_data1;

-  app_data1.set_app_guid(app1_guid_);

-  app_data1.set_is_machine_app(true);

-  app_data1.set_version(version_app1);

-  ProductData product1(app_data1);

-  products.push_back(product1);

-

-  // Add in Goopdate as one of the products.

-  AppData app_data2;

-  app_data2.set_app_guid(kGoopdateGuid);

-  app_data2.set_is_machine_app(true);

-  app_data2.set_version(version_goopdate);

-  ProductData product2(app_data2);

-  products.push_back(product2);

-  UpdateResponses responses;

-

-  // Have the first app have an update available, but it should get deferred

-  // later since there's a Goopdate update available.

-  UpdateResponseData resp_data1;

-  resp_data1.set_guid(app1_guid_);

-  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data1.set_status(kResponseStatusOkValue);

-  UpdateResponse resp1(resp_data1);

-  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));

-

-  // Add in response for Goopdate, making it available.

-  UpdateResponseData resp_data2;

-  resp_data2.set_guid(kGoopdateGuid);

-  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data2.set_status(kResponseStatusOkValue);

-  // TODO(omaha): Add component responses here.

-  UpdateResponse resp2(resp_data2);

-  responses.insert(std::pair<GUID, UpdateResponse>(kGoopdateGuid, resp2));

-

-  Jobs jobs;

-  Request ping_request(true);

-  CString event_log_text;

-  CompletionInfo completion_info;

-

-  EXPECT_SUCCEEDED(job_creator.CreateJobsFromResponses(responses,

-                                                       products,

-                                                       &jobs,

-                                                       &ping_request,

-                                                       &event_log_text,

-                                                       &completion_info));

-

-  // Should be a job for Resp2 since Resp2 was for Goopdate.

-  ASSERT_EQ(1, jobs.size());

-  EXPECT_TRUE(::IsEqualGUID(jobs[0]->app_data().app_guid(), kGoopdateGuid));

-  EXPECT_FALSE(jobs[0]->is_offline());

-

-  // Validate the ping data that is produced by the test method.

-  EXPECT_EQ(2, ping_request.get_request_count());

-  AppRequestData goopdate_request;

-  AppRequestData other_request;

-

-  AppRequestVector::const_iterator iter = ping_request.app_requests_begin();

-  const AppRequest& app_request = *iter;

-  if (::IsEqualGUID(app_request.request_data().app_data().app_guid(),

-                    kGoopdateGuid)) {

-    goopdate_request = app_request.request_data();

-    other_request = (*++iter).request_data();

-  } else {

-    goopdate_request = (*++iter).request_data();

-    other_request = app_request.request_data();

-  }

-

-  EXPECT_EQ(1, goopdate_request.num_ping_events());

-  EXPECT_EQ(PingEvent::EVENT_UPDATE_APPLICATION_BEGIN,

-            (*goopdate_request.ping_events_begin()).event_type());

-  EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS,

-            (*goopdate_request.ping_events_begin()).event_result());

-

-  EXPECT_EQ(1, other_request.num_ping_events());

-  EXPECT_EQ(PingEvent::EVENT_UPDATE_COMPLETE,

-            (*other_request.ping_events_begin()).event_type());

-  EXPECT_EQ(PingEvent::EVENT_RESULT_UPDATE_DEFERRED,

-            (*other_request.ping_events_begin()).event_result());

-  EXPECT_EQ(0, (*other_request.ping_events_begin()).error_code());

-  EXPECT_EQ(0, (*other_request.ping_events_begin()).extra_code1());

-

-  // Validate the completion info generated by the test method.

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(0, completion_info.error_code);

-  EXPECT_TRUE(completion_info.text.IsEmpty());

-

-  EXPECT_EQ(1, metric_worker_skipped_app_update_for_self_update.value());

-

-  // Sleep so that there is a time difference between the time written in the

-  // registry and now.

-  ::Sleep(20);

-

-  // Stats for app1 should not have been set because we did not process it.

-  DWORD update_responses(0);

-  DWORD64 time_since_first_response_ms(0);

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app1_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       kGoopdateGuid,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(1, update_responses);

-  EXPECT_LT(0, time_since_first_response_ms);

-  EXPECT_GT(10 * kMsPerSec, time_since_first_response_ms);

-

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastUpdateTimeSec));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                kRegValueLastUpdateTimeSec));

-}

-

-// Tests that in the case of an update for GoogleUpdate only, there is no

-// ping sent on behalf of other applications that had no update in the

-// first place.

-TEST_F(JobCreatorTest, CreateJobsFromResponses_UpdateGoopdateUpdateOnly) {

-  const CString version_app1 = _T("1.1.2.3");

-  const CString version_goopdate = _T("1.2.75.3");

-

-  JobCreator job_creator(true, true, &ping_);

-  job_creator.set_is_auto_update(true);

-  AppManager app_manager(true);

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,

-                                    _T("pv"),

-                                    version_goopdate));

-

-  ProductDataVector products;

-

-  AppData app_data1;

-  app_data1.set_app_guid(app1_guid_);

-  app_data1.set_is_machine_app(true);

-  app_data1.set_version(version_app1);

-  ProductData product1(app_data1);

-  products.push_back(product1);

-

-  // Add in Goopdate as one of the products.

-  AppData app_data2;

-  app_data2.set_app_guid(kGoopdateGuid);

-  app_data2.set_is_machine_app(true);

-  app_data2.set_version(version_goopdate);

-  ProductData product2(app_data2);

-  products.push_back(product2);

-  UpdateResponses responses;

-

-  // Have the first app have no update available, but it should get ignored

-  // later since there's a Goopdate update available.

-  UpdateResponseData resp_data1;

-  resp_data1.set_guid(app1_guid_);

-  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data1.set_status(kResponseStatusNoUpdate);

-  UpdateResponse resp1(resp_data1);

-  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));

-

-  // Add in response for Goopdate, making it available.

-  UpdateResponseData resp_data2;

-  resp_data2.set_guid(kGoopdateGuid);

-  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);

-  resp_data2.set_status(kResponseStatusOkValue);

-  UpdateResponse resp2(resp_data2);

-  responses.insert(std::pair<GUID, UpdateResponse>(kGoopdateGuid, resp2));

-

-  Jobs jobs;

-  Request ping_request(true);

-  CString event_log_text;

-  CompletionInfo completion_info;

-

-  EXPECT_SUCCEEDED(job_creator.CreateJobsFromResponses(responses,

-                                                       products,

-                                                       &jobs,

-                                                       &ping_request,

-                                                       &event_log_text,

-                                                       &completion_info));

-

-  // Should be a job for Resp2 since Resp2 was for Goopdate.

-  ASSERT_EQ(1, jobs.size());

-  EXPECT_TRUE(::IsEqualGUID(jobs[0]->app_data().app_guid(), kGoopdateGuid));

-  EXPECT_FALSE(jobs[0]->is_offline());

-

-  // Validate the ping data that is produced by the test method.

-  EXPECT_EQ(1, ping_request.get_request_count());

-

-  AppRequestVector::const_iterator iter = ping_request.app_requests_begin();

-  const AppRequest& app_request = *iter;

-  AppRequestData goopdate_request = app_request.request_data();

-

-  EXPECT_EQ(1, goopdate_request.num_ping_events());

-  EXPECT_EQ(PingEvent::EVENT_UPDATE_APPLICATION_BEGIN,

-            (*goopdate_request.ping_events_begin()).event_type());

-  EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS,

-            (*goopdate_request.ping_events_begin()).event_result());

-

-  // Validate the completion info generated by the test method.

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(0, completion_info.error_code);

-  EXPECT_TRUE(completion_info.text.IsEmpty());

-

-  EXPECT_EQ(0, metric_worker_skipped_app_update_for_self_update.value());

-

-  // Sleep so that there is a time difference between the time written in the

-  // registry and now.

-  ::Sleep(20);

-

-  // Stats for app1 should not have been set because we did not process it.

-  DWORD update_responses(0);

-  DWORD64 time_since_first_response_ms(0);

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       app1_guid_,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(0, update_responses);

-  EXPECT_EQ(0, time_since_first_response_ms);

-

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       kGoopdateGuid,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  EXPECT_EQ(1, update_responses);

-  EXPECT_LT(0, time_since_first_response_ms);

-  EXPECT_GT(10 * kMsPerSec, time_since_first_response_ms);

-

-  // kRegValueLastSuccessfulCheckSec is not set for app1's "noupdate" response

-  // because it is not processed due to the Goopdate update available.

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastUpdateTimeSec));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                kRegValueLastUpdateTimeSec));

-}

-

-TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_Ok) {

-  UpdateResponseData response_data;

-  response_data.set_status(_T("ok"));

-  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,

-                                                           _T("foo"));

-  EXPECT_EQ(COMPLETION_SUCCESS, info.status);

-  EXPECT_EQ(0, info.error_code);

-  EXPECT_TRUE(info.text.IsEmpty());

-}

-

-TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_NoUpdate) {

-  UpdateResponseData response_data;

-  response_data.set_status(_T("NoUpDaTe"));

-  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,

-                                                           _T("foo"));

-  EXPECT_EQ(COMPLETION_ERROR, info.status);

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, info.error_code);

-  EXPECT_STREQ(_T("No update is available."), info.text);

-}

-

-TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_Restricted) {

-  UpdateResponseData response_data;

-  response_data.set_status(_T("ReStRiCtEd"));

-  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,

-                                                           _T("foo"));

-  EXPECT_EQ(COMPLETION_ERROR, info.status);

-  EXPECT_EQ(GOOPDATE_E_RESTRICTED_SERVER_RESPONSE, info.error_code);

-  EXPECT_STREQ(_T("Access to this application is restricted."), info.text);

-}

-

-TEST_F(JobCreatorTest,

-       UpdateResponseDataToCompletionInfo_OsNotSupported) {

-  UpdateResponseData response_data;

-  response_data.set_guid(

-      StringToGuid(_T("{563CEB0C-A031-4f77-925D-590B2095DE8D}")));

-  response_data.set_status(_T("ErRoR-OsNoTsUpPoRtEd"));

-  response_data.set_error_url(

-      _T("http://foo.google.com/support/article.py?id=12345"));

-  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,

-                                                           _T("My App"));

-  EXPECT_EQ(COMPLETION_ERROR, info.status);

-  EXPECT_EQ(GOOPDATE_E_OS_NOT_SUPPORTED, info.error_code);

-  EXPECT_STREQ(_T("My App does not support your version of Windows. ")

-               _T("<a=http://foo.google.com/support/article.py?id=12345>")

-               _T("Click here for additional information.</a>"), info.text);

-}

-

-TEST_F(JobCreatorTest,

-       UpdateResponseDataToCompletionInfo_OsNotSupported_NoOsUrl) {

-  UpdateResponseData response_data;

-  response_data.set_status(_T("ErRoR-OsNoTsUpPoRtEd"));

-  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,

-                                                           _T("My App"));

-  EXPECT_EQ(COMPLETION_ERROR, info.status);

-  EXPECT_EQ(GOOPDATE_E_OS_NOT_SUPPORTED, info.error_code);

-  EXPECT_STREQ(_T("Server returned the following error: ErRoR-OsNoTsUpPoRtEd. ")

-               _T("Please try again later."), info.text);

-}

-

-TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_UnknownApp) {

-  UpdateResponseData response_data;

-  response_data.set_status(_T("eRrOr-UnKnOwNaPpLiCaTiOn"));

-  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,

-                                                           _T("My App"));

-  EXPECT_EQ(COMPLETION_ERROR, info.status);

-  EXPECT_EQ(GOOPDATE_E_UNKNOWN_APP_SERVER_RESPONSE, info.error_code);

-  EXPECT_STREQ(_T("The installer could not install the requested application ")

-               _T("due to a server side error. Please try again later. We ")

-               _T("apologize for the inconvenience."), info.text);

-}

-

-TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_InternalError) {

-  UpdateResponseData response_data;

-  response_data.set_status(_T("eRrOr-InTeRnAl"));

-  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,

-                                                           _T("My App"));

-  EXPECT_EQ(COMPLETION_ERROR, info.status);

-  EXPECT_EQ(GOOPDATE_E_INTERNAL_ERROR_SERVER_RESPONSE, info.error_code);

-  EXPECT_STREQ(_T("Server returned the following error: eRrOr-InTeRnAl. ")

-               _T("Please try again later."), info.text);

-}

-

-TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_UnknownResponse) {

-  UpdateResponseData response_data;

-  response_data.set_status(_T("unknown error string"));

-  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,

-                                                           _T("My App"));

-  EXPECT_EQ(COMPLETION_ERROR, info.status);

-  EXPECT_EQ(GOOPDATE_E_UNKNOWN_SERVER_RESPONSE, info.error_code);

-  EXPECT_STREQ(_T("Server returned the following error: unknown error string. ")

-               _T("Please try again later."), info.text);

-}

-

-TEST_F(JobCreatorTest, CreateOfflineJobs_Success) {

-  // This test does not require registry hive overrides.

-  TearDown();

-

-  JobCreator job_creator(true, false, &ping_);

-  job_creator.set_fail_if_update_not_available(true);

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));

-

-  ProductDataVector products;

-  AppData app_data1;

-  app_data1.set_app_guid(app1_guid_);

-  app_data1.set_display_name(_T("Test App 1"));

-  app_data1.set_is_machine_app(true);

-  app_data1.set_language(_T("en"));

-  ProductData product1(app_data1);

-  products.push_back(product1);

-

-  CString offline_manifest_path(kGuidApp1);

-  offline_manifest_path += _T(".gup");

-  offline_manifest_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                          offline_manifest_path);

-  ASSERT_SUCCEEDED(File::Copy(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("server_manifest_one_app.xml")),

-      offline_manifest_path,

-      true));

-

-  CString installer_exe = _T("foo_installer.exe");

-  CString installer_path = ConcatenatePath(

-                                app_util::GetCurrentModuleDirectory(),

-                                kGuidApp1);

-  ASSERT_SUCCEEDED(CreateDir(installer_path, NULL));

-  // The hash of SaveArguments_OmahaTestSigned.exe needs to be kept in sync, in

-  // server_manifest_one_app.xml, for this test to succeed.

-  ASSERT_SUCCEEDED(File::Copy(

-      ConcatenatePath(ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                      _T("unittest_support")),

-                                      _T("SaveArguments_OmahaTestSigned.exe")),

-      ConcatenatePath(installer_path, installer_exe),

-      true));

-

-  Jobs jobs;

-  Request ping_request(true);

-  CString event_log_text;

-  CompletionInfo completion_info;

-  ASSERT_SUCCEEDED(job_creator.CreateOfflineJobs(

-      app_util::GetCurrentModuleDirectory(),

-      products,

-      &jobs,

-      &ping_request,

-      &event_log_text,

-      &completion_info));

-

-  ASSERT_EQ(1, jobs.size());

-  EXPECT_EQ(1, ping_request.get_request_count());

-  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);

-  EXPECT_EQ(0, completion_info.error_code);

-  EXPECT_TRUE(completion_info.text.IsEmpty());

-  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD,

-            jobs[0]->response_data().success_action());

-  EXPECT_TRUE(jobs[0]->is_offline());

-

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastUpdateTimeSec));

-

-  EXPECT_SUCCEEDED(DeleteDirectory(installer_path));

-  EXPECT_SUCCEEDED(File::Remove(offline_manifest_path));

-}

-

-TEST_F(JobCreatorTest, CreateOfflineJobs_Failure) {

-  JobCreator job_creator(true, false, &ping_);

-  job_creator.set_fail_if_update_not_available(true);

-

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));

-

-  ProductDataVector products;

-  AppData app_data1;

-  app_data1.set_app_guid(app1_guid_);

-  app_data1.set_display_name(_T("Test App 1"));

-  app_data1.set_is_machine_app(true);

-  app_data1.set_language(_T("en"));

-  ProductData product1(app_data1);

-  products.push_back(product1);

-

-  Jobs jobs;

-  Request ping_request(true);

-  CString event_log_text;

-  CompletionInfo completion_info;

-  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            job_creator.CreateOfflineJobs(

-                            app_util::GetCurrentModuleDirectory(),

-                            products,

-                            &jobs,

-                            &ping_request,

-                            &event_log_text,

-                            &completion_info));

-

-  EXPECT_EQ(0, jobs.size());

-  EXPECT_EQ(0, ping_request.get_request_count());

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            completion_info.error_code);

-  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);

-  EXPECT_STREQ(_T(""), completion_info.text);

-

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastSuccessfulCheckSec));

-  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,

-                                kRegValueLastUpdateTimeSec));

-}

-

-TEST_F(JobCreatorTest, FindOfflineFilePath_Success) {

-  CString installer_exe = _T("foo_installer.exe");

-  CString installer_path = ConcatenatePath(

-                                app_util::GetCurrentModuleDirectory(),

-                                kGuidApp1);

-  ASSERT_SUCCEEDED(CreateDir(installer_path, NULL));

-  ASSERT_SUCCEEDED(File::Copy(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("LongRunning.exe")),

-      ConcatenatePath(installer_path, installer_exe),

-      true));

-

-  CString file_path;

-  ASSERT_SUCCEEDED(CallFindOfflineFilePath(

-                       app_util::GetCurrentModuleDirectory(),

-                       kGuidApp1,

-                       &file_path));

-  ASSERT_STREQ(ConcatenatePath(installer_path, installer_exe), file_path);

-

-  EXPECT_SUCCEEDED(DeleteDirectory(installer_path));

-}

-

-TEST_F(JobCreatorTest, FindOfflineFilePath_Failure) {

-  CString file_path;

-  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND),

-            CallFindOfflineFilePath(app_util::GetCurrentModuleDirectory(),

-                                    kGuidApp1,

-                                    &file_path));

-  ASSERT_TRUE(file_path.IsEmpty());

-}

-

-TEST_F(JobCreatorTest, ReadOfflineManifest_Success) {

-  // This test does not require registry hive overrides.

-  TearDown();

-

-  CString offline_manifest_path(kGuidApp1);

-  offline_manifest_path += _T(".gup");

-  offline_manifest_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                          offline_manifest_path);

-  ASSERT_SUCCEEDED(File::Copy(

-      ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                      _T("server_manifest_one_app.xml")),

-      offline_manifest_path,

-      true));

-

-  UpdateResponse response;

-  EXPECT_SUCCEEDED(CallReadOfflineManifest(

-                       app_util::GetCurrentModuleDirectory(),

-                       kGuidApp1,

-                       &response));

-

-  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD,

-            response.update_response_data().success_action());

-

-  EXPECT_SUCCEEDED(File::Remove(offline_manifest_path));

-}

-

-TEST_F(JobCreatorTest, ReadOfflineManifest_FileDoesNotExist) {

-  UpdateResponse response;

-  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-            CallReadOfflineManifest(app_util::GetCurrentModuleDirectory(),

-                                    kGuidApp1,

-                                    &response));

-}

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/time.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/job_creator.h"
+#include "omaha/worker/ping.h"
+#include "omaha/worker/worker_metrics.h"
+
+namespace omaha {
+
+namespace {
+
+const TCHAR* kGuidApp1 = _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");
+const TCHAR* kGuidApp2 = _T("{28A93830-1746-4F0B-90F5-CF44B41169F3}");
+const TCHAR* kGuidApp3 = _T("{E5D3562E-BFAE-48c6-B9C5-4E293F695E0E}");
+const TCHAR* kGuidApp4 = _T("{F9346563-85DA-4dc1-A621-FAF6F869680A}");
+
+const TCHAR* const kApp1ClientStateKeyPathMachine =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");
+const TCHAR* const kApp2ClientStateKeyPathMachine =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{28A93830-1746-4F0B-90F5-CF44B41169F3}");
+const TCHAR* const kApp3ClientStateKeyPathMachine =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{E5D3562E-BFAE-48c6-B9C5-4E293F695E0E}");
+const TCHAR* const kApp4ClientStateKeyPathMachine =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{F9346563-85DA-4dc1-A621-FAF6F869680A}");
+const TCHAR* const kApp1ClientsKeyPathMachine =
+    _T("HKLM\\Software\\Google\\Update\\Clients\\")
+    _T("{CDABE316-39CD-43BA-8440-6D1E0547AEE6}");
+const TCHAR* const kApp2ClientsKeyPathMachine =
+    _T("HKLM\\Software\\Google\\Update\\Clients\\")
+    _T("{28A93830-1746-4F0B-90F5-CF44B41169F3}");
+
+}  // namespace
+
+class JobCreatorTest : public testing::Test {
+ protected:
+  JobCreatorTest()
+      : app1_guid_(StringToGuid(kGuidApp1)),
+        app2_guid_(StringToGuid(kGuidApp2)),
+        app3_guid_(StringToGuid(kGuidApp3)),
+        app4_guid_(StringToGuid(kGuidApp4)) {
+  }
+
+  virtual void SetUp() {
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+    OverrideRegistryHives(kRegistryHiveOverrideRoot);
+
+    metric_worker_skipped_app_update_for_self_update.Reset();
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+  }
+
+  CompletionInfo UpdateResponseDataToCompletionInfo(
+      const UpdateResponseData& response_data,
+      const CString& display_name) {
+    JobCreator job_creator(false, false, &ping_);
+    job_creator.set_fail_if_update_not_available(true);
+    return job_creator.UpdateResponseDataToCompletionInfo(response_data,
+                                                          display_name);
+  }
+
+  static HRESULT CallFindOfflineFilePath(const CString& offline_dir,
+                                         const CString& app_guid,
+                                         CString* file_path) {
+    return JobCreator::FindOfflineFilePath(offline_dir, app_guid, file_path);
+  }
+
+  static HRESULT CallReadOfflineManifest(const CString& offline_dir,
+                                         const CString& app_guid,
+                                         UpdateResponse* response) {
+    return JobCreator::ReadOfflineManifest(offline_dir, app_guid, response);
+  }
+
+  Ping ping_;
+  const GUID app1_guid_;
+  const GUID app2_guid_;
+  const GUID app3_guid_;
+  const GUID app4_guid_;
+};
+
+TEST_F(JobCreatorTest, CreateJobsFromResponses_UpdateMultipleAppsAndStatuses) {
+  const CString version_goopdate = _T("1.2.75.3");
+  const CString version_app1 = _T("1.1.2.3");
+  const CString version_app2 = _T("2.0.0.5");
+
+  JobCreator job_creator(true, true, &ping_);
+  job_creator.set_is_auto_update(true);
+  AppManager app_manager(true);
+
+  const DWORD kExistingUpdateValues = 0x70123456;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(kApp2ClientsKeyPathMachine, _T("pv"), version_app2));
+
+  ProductDataVector products;
+
+  AppData app_data_omaha;
+  app_data_omaha.set_app_guid(kGoopdateGuid);
+  app_data_omaha.set_is_machine_app(true);
+  app_data_omaha.set_version(version_goopdate);
+  ProductData product_omaha(app_data_omaha);
+  products.push_back(product_omaha);
+
+  AppData app_data1;
+  app_data1.set_app_guid(app1_guid_);
+  app_data1.set_is_machine_app(true);
+  app_data1.set_version(version_app1);
+  ProductData product1(app_data1);
+  products.push_back(product1);
+
+  AppData app_data2;
+  app_data2.set_app_guid(app2_guid_);
+  app_data2.set_is_machine_app(true);
+  app_data2.set_version(version_app2);
+  ProductData product2(app_data2);
+  products.push_back(product2);
+
+  UpdateResponses responses;
+
+  UpdateResponseData resp_data_omaha;
+  resp_data_omaha.set_guid(kGoopdateGuid);
+  resp_data_omaha.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data_omaha.set_status(kResponseStatusNoUpdate);
+  UpdateResponse resp_omaha(resp_data_omaha);
+  responses.insert(std::pair<GUID, UpdateResponse>(kGoopdateGuid, resp_omaha));
+
+  UpdateResponseData resp_data1;
+  resp_data1.set_guid(app1_guid_);
+  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data1.set_status(kResponseStatusNoUpdate);
+  UpdateResponse resp1(resp_data1);
+  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));
+
+  UpdateResponseData resp_data2;
+  resp_data2.set_guid(app2_guid_);
+  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data2.set_status(kResponseStatusOkValue);
+  // TODO(omaha): Add component responses here.
+  UpdateResponse resp2(resp_data2);
+  responses.insert(std::pair<GUID, UpdateResponse>(app2_guid_, resp2));
+
+  Jobs jobs;
+  Request ping_request(true);
+  CString event_log_text;
+  CompletionInfo completion_info;
+
+  // This should succeed for an update since it's OK to have "no update
+  // available" for updates.
+  EXPECT_SUCCEEDED(job_creator.CreateJobsFromResponses(responses,
+                                                       products,
+                                                       &jobs,
+                                                       &ping_request,
+                                                       &event_log_text,
+                                                       &completion_info));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  // Should be a job for Resp2 since Resp1 was status "No Update".
+  ASSERT_EQ(1, jobs.size());
+  EXPECT_EQ(3, ping_request.get_request_count());
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(0, completion_info.error_code);
+  EXPECT_TRUE(completion_info.text.IsEmpty());
+  EXPECT_FALSE(jobs[0]->is_offline());
+
+  // Sleep so that there is a time difference between the time written in the
+  // registry and now.
+  ::Sleep(20);
+
+  // Omaha.
+  // Update Stats should not have been set because there was no update.
+  // Successful update check set for noupdate but successful update not updated.
+  DWORD update_responses(1);
+  DWORD64 time_since_first_response_ms(1);
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       kGoopdateGuid,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+
+  const uint32 last_check_sec_omaha =
+      GetDwordValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                    kRegValueLastSuccessfulCheckSec);
+  EXPECT_NE(kExistingUpdateValues, last_check_sec_omaha);
+  EXPECT_GE(now, last_check_sec_omaha);
+  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec_omaha);
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                          kRegValueLastUpdateTimeSec));
+
+  // App 1.
+  // Update Stats should not have been set because there was no update.
+  // Successful update check set for noupdate but successful update not updated.
+  update_responses = 1;
+  time_since_first_response_ms = 1;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app1_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+
+  const uint32 last_check_sec_app1 =
+      GetDwordValue(kApp1ClientStateKeyPathMachine,
+                    kRegValueLastSuccessfulCheckSec);
+  EXPECT_NE(kExistingUpdateValues, last_check_sec_app1);
+  EXPECT_GE(now, last_check_sec_app1);
+  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec_app1);
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(kApp1ClientStateKeyPathMachine,
+                          kRegValueLastUpdateTimeSec));
+
+  // App 2.
+  // Update Stats should have been set.
+  // Neither successful update check nor successful update are updated because
+  // the update has not been completed.
+  update_responses = 0;
+  time_since_first_response_ms = 0;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app2_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(1, update_responses);
+  EXPECT_LT(0, time_since_first_response_ms);
+  EXPECT_GT(10 * kMsPerSec, time_since_first_response_ms);
+
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(kApp2ClientStateKeyPathMachine,
+                          kRegValueLastSuccessfulCheckSec));
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(kApp2ClientStateKeyPathMachine,
+                          kRegValueLastUpdateTimeSec));
+}
+
+TEST_F(JobCreatorTest, CreateJobsFromResponses_UpdateForUpdateDisabledApp) {
+  const CString version_goopdate = _T("1.2.75.3");
+  const CString version_app1 = _T("1.1.2.3");
+  const CString version_app2 = _T("2.0.0.5");
+  const CString version_app3 = _T("11.0.0.5");
+  const CString version_app4 = _T("5.0.6.7");
+
+  JobCreator job_creator(true, true, &ping_);
+  job_creator.set_is_auto_update(true);
+  AppManager app_manager(true);
+
+  const DWORD kExistingUpdateValues = 0x70123456;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathMachine,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathMachine,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp4ClientStateKeyPathMachine,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp4ClientStateKeyPathMachine,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(kApp1ClientsKeyPathMachine, _T("pv"), version_app1));
+  EXPECT_SUCCEEDED(
+      RegKey::SetValue(kApp2ClientsKeyPathMachine, _T("pv"), version_app2));
+
+  // Required for testing deletion of this data when updates are disabled (app1)
+  // and noupdate is returned (Omaha and app3).
+  const DWORD64 kUpdateAvailableSince =
+    GetCurrent100NSTime() - 200 * kMsPerSec * kMillisecsTo100ns;
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    kRegValueUpdateAvailableCount,
+                                    static_cast<DWORD>(123456)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                    kRegValueUpdateAvailableSince,
+                                    kUpdateAvailableSince));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,
+                                    kRegValueUpdateAvailableCount,
+                                    static_cast<DWORD>(123)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathMachine,
+                                    kRegValueUpdateAvailableSince,
+                                    kUpdateAvailableSince));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,
+                                    kRegValueUpdateAvailableCount,
+                                    static_cast<DWORD>(2345)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathMachine,
+                                    kRegValueUpdateAvailableSince,
+                                    kUpdateAvailableSince));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathMachine,
+                                    kRegValueUpdateAvailableCount,
+                                    static_cast<DWORD>(456)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathMachine,
+                                    kRegValueUpdateAvailableSince,
+                                    kUpdateAvailableSince));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp4ClientStateKeyPathMachine,
+                                    kRegValueUpdateAvailableCount,
+                                    static_cast<DWORD>(98)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kApp4ClientStateKeyPathMachine,
+                                    kRegValueUpdateAvailableSince,
+                                    kUpdateAvailableSince));
+  // Verify the data is set correctly.
+  DWORD update_responses(0);
+  DWORD64 time_since_first_response_ms(0);
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       kGoopdateGuid,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(123456, update_responses);
+  EXPECT_LE(200000, time_since_first_response_ms);
+  update_responses = 0;
+  time_since_first_response_ms = 0;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       StringToGuid(kGuidApp1),
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(123, update_responses);
+  EXPECT_LE(200000, time_since_first_response_ms);
+  update_responses = 0;
+  time_since_first_response_ms = 0;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       StringToGuid(kGuidApp2),
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(2345, update_responses);
+  EXPECT_LE(200000, time_since_first_response_ms);
+  update_responses = 0;
+  time_since_first_response_ms = 0;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       StringToGuid(kGuidApp3),
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(456, update_responses);
+  EXPECT_LE(200000, time_since_first_response_ms);
+  update_responses = 0;
+  time_since_first_response_ms = 0;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       StringToGuid(kGuidApp4),
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(98, update_responses);
+  EXPECT_LE(200000, time_since_first_response_ms);
+
+  ProductDataVector products;
+
+  AppData app_data_omaha;
+  app_data_omaha.set_app_guid(kGoopdateGuid);
+  app_data_omaha.set_is_machine_app(true);
+  app_data_omaha.set_version(version_goopdate);
+  ProductData product_omaha(app_data_omaha);
+  products.push_back(product_omaha);
+
+  AppData app_data1;
+  app_data1.set_app_guid(app1_guid_);
+  app_data1.set_is_machine_app(true);
+  app_data1.set_version(version_app1);
+  app_data1.set_is_update_disabled(true);
+  ProductData product1(app_data1);
+  products.push_back(product1);
+
+  AppData app_data2;
+  app_data2.set_app_guid(app2_guid_);
+  app_data2.set_is_machine_app(true);
+  app_data2.set_version(version_app2);
+  ProductData product2(app_data2);
+  products.push_back(product2);
+
+  AppData app_data3;
+  app_data3.set_app_guid(app3_guid_);
+  app_data3.set_is_machine_app(true);
+  app_data3.set_version(version_app3);
+  app_data3.set_is_update_disabled(true);
+  ProductData product3(app_data3);
+  products.push_back(product3);
+
+  AppData app_data4;
+  app_data4.set_app_guid(app4_guid_);
+  app_data4.set_is_machine_app(true);
+  app_data4.set_version(version_app4);
+  ProductData product4(app_data4);
+  products.push_back(product4);
+
+  UpdateResponses responses;
+
+  UpdateResponseData resp_data_omaha;
+  resp_data_omaha.set_guid(kGoopdateGuid);
+  resp_data_omaha.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data_omaha.set_status(kResponseStatusNoUpdate);
+  UpdateResponse resp_omaha(resp_data_omaha);
+  responses.insert(std::pair<GUID, UpdateResponse>(kGoopdateGuid, resp_omaha));
+
+  UpdateResponseData resp_data1;
+  resp_data1.set_guid(app1_guid_);
+  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data1.set_status(kResponseStatusOkValue);
+  UpdateResponse resp1(resp_data1);
+  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));
+
+  UpdateResponseData resp_data2;
+  resp_data2.set_guid(app2_guid_);
+  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data2.set_status(kResponseStatusOkValue);
+  UpdateResponse resp2(resp_data2);
+  responses.insert(std::pair<GUID, UpdateResponse>(app2_guid_, resp2));
+
+  UpdateResponseData resp_data3;
+  resp_data3.set_guid(app3_guid_);
+  resp_data3.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data3.set_status(kResponseStatusNoUpdate);
+  UpdateResponse resp3(resp_data3);
+  responses.insert(std::pair<GUID, UpdateResponse>(app3_guid_, resp3));
+
+  UpdateResponseData resp_data4;
+  resp_data4.set_guid(app4_guid_);
+  resp_data4.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data4.set_status(kResponseStatusInternalError);
+  UpdateResponse resp4(resp_data4);
+  responses.insert(std::pair<GUID, UpdateResponse>(app4_guid_, resp4));
+
+  Jobs jobs;
+  Request ping_request(true);
+  CString event_log_text;
+  CompletionInfo completion_info;
+
+  EXPECT_SUCCEEDED(job_creator.CreateJobsFromResponses(responses,
+                                                       products,
+                                                       &jobs,
+                                                       &ping_request,
+                                                       &event_log_text,
+                                                       &completion_info));
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  // Should be a job for Resp2 only since Resp1 was had updates disabled.
+  ASSERT_EQ(1, jobs.size());
+  // Pings for the update available app, the error-internal app, and the
+  // noupdate apps. No ping for the disabled app with update available.
+  // Not sure why the noupdate apps get a ping.
+  EXPECT_EQ(4, ping_request.get_request_count());
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(0, completion_info.error_code);
+  EXPECT_TRUE(completion_info.text.IsEmpty());
+  EXPECT_FALSE(jobs[0]->is_offline());
+
+  // Sleep so that there is a time difference between the time written in the
+  // registry and now.
+  ::Sleep(20);
+
+  // Omaha.
+  // Update Stats should have been cleared because there was no update - we
+  // should not keep around old data if there is no update to apply.
+  // Successful update check set for noupdate but successful update not updated.
+  update_responses = 1;
+  time_since_first_response_ms = 1;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       kGoopdateGuid,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+
+  const uint32 last_check_sec_omaha =
+      GetDwordValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                    kRegValueLastSuccessfulCheckSec);
+  EXPECT_NE(kExistingUpdateValues, last_check_sec_omaha);
+  EXPECT_GE(now, last_check_sec_omaha);
+  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec_omaha);
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                          kRegValueLastUpdateTimeSec));
+
+  // App 1.
+  // Update Stats should have been cleared because these values are used to
+  // anaylze the success of Omaha and disabled updates would break these stats.
+  // Successful update check and successful update are not set because and
+  // update is available but disabled.
+  update_responses = 1;
+  time_since_first_response_ms = 1;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app1_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(kApp1ClientStateKeyPathMachine,
+                          kRegValueLastSuccessfulCheckSec));
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(kApp1ClientStateKeyPathMachine,
+                          kRegValueLastUpdateTimeSec));
+
+  // App 2.
+  // Update Stats: responses should have been incremented and time since first
+  // response should be based on the value set above.
+  // Neither successful update check nor successful update are updated because
+  // the update has not been completed.
+  update_responses = 0;
+  time_since_first_response_ms = 0;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app2_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(2346, update_responses);
+  EXPECT_LT(200 * kMsPerSec + 20, time_since_first_response_ms);
+  EXPECT_GT(202 * kMsPerSec, time_since_first_response_ms);
+
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(kApp2ClientStateKeyPathMachine,
+                          kRegValueLastSuccessfulCheckSec));
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(kApp2ClientStateKeyPathMachine,
+                          kRegValueLastUpdateTimeSec));
+
+  // App 3.
+  // Update Stats should have been cleared because there was no update - we
+  // should not keep around old data if there is no update to apply.
+  // Successful update check set for noupdate but successful update not updated.
+  update_responses = 1;
+  time_since_first_response_ms = 1;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app3_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+  const uint32 last_check_sec_app3 =
+      GetDwordValue(kApp3ClientStateKeyPathMachine,
+                    kRegValueLastSuccessfulCheckSec);
+  EXPECT_NE(kExistingUpdateValues, last_check_sec_app3);
+  EXPECT_GE(now, last_check_sec_app3);
+  EXPECT_GE(static_cast<uint32>(200), now - last_check_sec_app3);
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(kApp3ClientStateKeyPathMachine,
+                          kRegValueLastUpdateTimeSec));
+
+  // App 4.
+  // Update Stats: responses should have not been incremented and time since
+  // first response should be based on the value set above.
+  // Neither successful update check nor successful update are updated because
+  // the update has not been completed.
+  update_responses = 0;
+  time_since_first_response_ms = 0;
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app4_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(98, update_responses);
+  EXPECT_LT(200 * kMsPerSec + 20, time_since_first_response_ms);
+  EXPECT_GT(202 * kMsPerSec, time_since_first_response_ms);
+
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(kApp4ClientStateKeyPathMachine,
+                          kRegValueLastSuccessfulCheckSec));
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(kApp4ClientStateKeyPathMachine,
+                          kRegValueLastUpdateTimeSec));
+}
+
+// This should fail for an install since it's not OK to have "no update
+// available" for clean installs
+TEST_F(JobCreatorTest, CreateJobsFromResponses_InstallFailure) {
+  const CString version_app1 = _T("1.1.2.3");
+  const CString version_app2 = _T("2.0.0.5");
+
+  JobCreator job_creator(true, false, &ping_);
+  job_creator.set_fail_if_update_not_available(true);
+  AppManager app_manager(true);
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp2ClientStateKeyPathMachine));
+
+  ProductDataVector products;
+  AppData app_data1;
+  app_data1.set_app_guid(app1_guid_);
+  app_data1.set_is_machine_app(true);
+  app_data1.set_version(version_app1);
+  ProductData product1(app_data1);
+  products.push_back(product1);
+
+  AppData app_data2;
+  app_data2.set_app_guid(app2_guid_);
+  app_data2.set_is_machine_app(true);
+  app_data2.set_version(version_app2);
+  ProductData product2(app_data2);
+  products.push_back(product2);
+
+  UpdateResponses responses;
+
+  UpdateResponseData resp_data1;
+  resp_data1.set_guid(app1_guid_);
+  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data1.set_status(kResponseStatusNoUpdate);
+  UpdateResponse resp1(resp_data1);
+  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));
+
+  UpdateResponseData resp_data2;
+  resp_data2.set_guid(app2_guid_);
+  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data2.set_status(kResponseStatusOkValue);
+  // TODO(omaha): Add component responses here.
+  UpdateResponse resp2(resp_data2);
+  responses.insert(std::pair<GUID, UpdateResponse>(app2_guid_, resp2));
+
+  Jobs jobs;
+  Request ping_request(true);
+  CString event_log_text;
+  CompletionInfo completion_info;
+  EXPECT_FAILED(job_creator.CreateJobsFromResponses(responses,
+                                                    products,
+                                                    &jobs,
+                                                    &ping_request,
+                                                    &event_log_text,
+                                                    &completion_info));
+
+  EXPECT_EQ(0, jobs.size());
+  EXPECT_EQ(1, ping_request.get_request_count());
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, completion_info.error_code);
+  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);
+  EXPECT_STREQ(_T("No update is available."), completion_info.text);
+
+  // Sleep so that there would be a time difference between the time written in
+  // the registry and now.
+  ::Sleep(20);
+
+  // There should not be any data because this is an install.
+  DWORD update_responses(1);
+  DWORD64 time_since_first_response_ms(1);
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app1_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app2_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastUpdateTimeSec));
+  EXPECT_FALSE(RegKey::HasValue(kApp2ClientStateKeyPathMachine,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(kApp2ClientStateKeyPathMachine,
+                                kRegValueLastUpdateTimeSec));
+}
+
+TEST_F(JobCreatorTest, CreateJobsFromResponses_InstallSuccess) {
+  const CString version_app1 = _T("1.1.2.3");
+  const CString version_app2 = _T("2.0.0.5");
+
+  JobCreator job_creator(true, false, &ping_);
+  job_creator.set_fail_if_update_not_available(true);
+  AppManager app_manager(true);
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp2ClientStateKeyPathMachine));
+
+  ProductDataVector products;
+  AppData app_data1;
+  app_data1.set_app_guid(app1_guid_);
+  app_data1.set_is_machine_app(true);
+  app_data1.set_version(version_app1);
+  ProductData product1(app_data1);
+  products.push_back(product1);
+
+  AppData app_data2;
+  app_data2.set_app_guid(app2_guid_);
+  app_data2.set_is_machine_app(true);
+  app_data2.set_version(version_app2);
+  ProductData product2(app_data2);
+  products.push_back(product2);
+
+  UpdateResponses responses;
+
+  UpdateResponseData resp_data1;
+  resp_data1.set_guid(app1_guid_);
+  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data1.set_status(kResponseStatusOkValue);
+  UpdateResponse resp1(resp_data1);
+  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));
+
+  UpdateResponseData resp_data2;
+  resp_data2.set_guid(app2_guid_);
+  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data2.set_status(kResponseStatusOkValue);
+  // TODO(omaha): Add component responses here.
+  UpdateResponse resp2(resp_data2);
+  responses.insert(std::pair<GUID, UpdateResponse>(app2_guid_, resp2));
+
+  Jobs jobs;
+  Request ping_request(true);
+  CString event_log_text;
+  CompletionInfo completion_info;
+  EXPECT_SUCCEEDED(job_creator.CreateJobsFromResponses(responses,
+                                                       products,
+                                                       &jobs,
+                                                       &ping_request,
+                                                       &event_log_text,
+                                                       &completion_info));
+
+  ASSERT_EQ(2, jobs.size());
+  EXPECT_EQ(2, ping_request.get_request_count());
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(0, completion_info.error_code);
+  EXPECT_TRUE(completion_info.text.IsEmpty());
+  EXPECT_FALSE(jobs[0]->is_offline());
+  EXPECT_FALSE(jobs[1]->is_offline());
+
+  // Sleep so that there would be a time difference between the time written in
+  // the registry and now.
+  ::Sleep(20);
+
+  // There should not be any data because this is an install.
+  DWORD update_responses(1);
+  DWORD64 time_since_first_response_ms(1);
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app1_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app2_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastUpdateTimeSec));
+  EXPECT_FALSE(RegKey::HasValue(kApp2ClientStateKeyPathMachine,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(kApp2ClientStateKeyPathMachine,
+                                kRegValueLastUpdateTimeSec));
+}
+
+TEST_F(JobCreatorTest, CreateJobsFromResponses_UpdateGoopdateUpdateAvailable) {
+  const CString version_app1 = _T("1.1.2.3");
+  const CString version_goopdate = _T("1.2.75.3");
+
+  JobCreator job_creator(true, true, &ping_);
+  job_creator.set_is_auto_update(true);
+  AppManager app_manager(true);
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,
+                                    _T("pv"),
+                                    version_goopdate));
+
+  ProductDataVector products;
+
+  AppData app_data1;
+  app_data1.set_app_guid(app1_guid_);
+  app_data1.set_is_machine_app(true);
+  app_data1.set_version(version_app1);
+  ProductData product1(app_data1);
+  products.push_back(product1);
+
+  // Add in Goopdate as one of the products.
+  AppData app_data2;
+  app_data2.set_app_guid(kGoopdateGuid);
+  app_data2.set_is_machine_app(true);
+  app_data2.set_version(version_goopdate);
+  ProductData product2(app_data2);
+  products.push_back(product2);
+  UpdateResponses responses;
+
+  // Have the first app have an update available, but it should get deferred
+  // later since there's a Goopdate update available.
+  UpdateResponseData resp_data1;
+  resp_data1.set_guid(app1_guid_);
+  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data1.set_status(kResponseStatusOkValue);
+  UpdateResponse resp1(resp_data1);
+  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));
+
+  // Add in response for Goopdate, making it available.
+  UpdateResponseData resp_data2;
+  resp_data2.set_guid(kGoopdateGuid);
+  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data2.set_status(kResponseStatusOkValue);
+  // TODO(omaha): Add component responses here.
+  UpdateResponse resp2(resp_data2);
+  responses.insert(std::pair<GUID, UpdateResponse>(kGoopdateGuid, resp2));
+
+  Jobs jobs;
+  Request ping_request(true);
+  CString event_log_text;
+  CompletionInfo completion_info;
+
+  EXPECT_SUCCEEDED(job_creator.CreateJobsFromResponses(responses,
+                                                       products,
+                                                       &jobs,
+                                                       &ping_request,
+                                                       &event_log_text,
+                                                       &completion_info));
+
+  // Should be a job for Resp2 since Resp2 was for Goopdate.
+  ASSERT_EQ(1, jobs.size());
+  EXPECT_TRUE(::IsEqualGUID(jobs[0]->app_data().app_guid(), kGoopdateGuid));
+  EXPECT_FALSE(jobs[0]->is_offline());
+
+  // Validate the ping data that is produced by the test method.
+  EXPECT_EQ(2, ping_request.get_request_count());
+  AppRequestData goopdate_request;
+  AppRequestData other_request;
+
+  AppRequestVector::const_iterator iter = ping_request.app_requests_begin();
+  const AppRequest& app_request = *iter;
+  if (::IsEqualGUID(app_request.request_data().app_data().app_guid(),
+                    kGoopdateGuid)) {
+    goopdate_request = app_request.request_data();
+    other_request = (*++iter).request_data();
+  } else {
+    goopdate_request = (*++iter).request_data();
+    other_request = app_request.request_data();
+  }
+
+  EXPECT_EQ(1, goopdate_request.num_ping_events());
+  EXPECT_EQ(PingEvent::EVENT_UPDATE_APPLICATION_BEGIN,
+            (*goopdate_request.ping_events_begin()).event_type());
+  EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS,
+            (*goopdate_request.ping_events_begin()).event_result());
+
+  EXPECT_EQ(1, other_request.num_ping_events());
+  EXPECT_EQ(PingEvent::EVENT_UPDATE_COMPLETE,
+            (*other_request.ping_events_begin()).event_type());
+  EXPECT_EQ(PingEvent::EVENT_RESULT_UPDATE_DEFERRED,
+            (*other_request.ping_events_begin()).event_result());
+  EXPECT_EQ(0, (*other_request.ping_events_begin()).error_code());
+  EXPECT_EQ(0, (*other_request.ping_events_begin()).extra_code1());
+
+  // Validate the completion info generated by the test method.
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(0, completion_info.error_code);
+  EXPECT_TRUE(completion_info.text.IsEmpty());
+
+  EXPECT_EQ(1, metric_worker_skipped_app_update_for_self_update.value());
+
+  // Sleep so that there is a time difference between the time written in the
+  // registry and now.
+  ::Sleep(20);
+
+  // Stats for app1 should not have been set because we did not process it.
+  DWORD update_responses(0);
+  DWORD64 time_since_first_response_ms(0);
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app1_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       kGoopdateGuid,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(1, update_responses);
+  EXPECT_LT(0, time_since_first_response_ms);
+  EXPECT_GT(10 * kMsPerSec, time_since_first_response_ms);
+
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastUpdateTimeSec));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                kRegValueLastUpdateTimeSec));
+}
+
+// Tests that in the case of an update for GoogleUpdate only, there is no
+// ping sent on behalf of other applications that had no update in the
+// first place.
+TEST_F(JobCreatorTest, CreateJobsFromResponses_UpdateGoopdateUpdateOnly) {
+  const CString version_app1 = _T("1.1.2.3");
+  const CString version_goopdate = _T("1.2.75.3");
+
+  JobCreator job_creator(true, true, &ping_);
+  job_creator.set_is_auto_update(true);
+  AppManager app_manager(true);
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,
+                                    _T("pv"),
+                                    version_goopdate));
+
+  ProductDataVector products;
+
+  AppData app_data1;
+  app_data1.set_app_guid(app1_guid_);
+  app_data1.set_is_machine_app(true);
+  app_data1.set_version(version_app1);
+  ProductData product1(app_data1);
+  products.push_back(product1);
+
+  // Add in Goopdate as one of the products.
+  AppData app_data2;
+  app_data2.set_app_guid(kGoopdateGuid);
+  app_data2.set_is_machine_app(true);
+  app_data2.set_version(version_goopdate);
+  ProductData product2(app_data2);
+  products.push_back(product2);
+  UpdateResponses responses;
+
+  // Have the first app have no update available, but it should get ignored
+  // later since there's a Goopdate update available.
+  UpdateResponseData resp_data1;
+  resp_data1.set_guid(app1_guid_);
+  resp_data1.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data1.set_status(kResponseStatusNoUpdate);
+  UpdateResponse resp1(resp_data1);
+  responses.insert(std::pair<GUID, UpdateResponse>(app1_guid_, resp1));
+
+  // Add in response for Goopdate, making it available.
+  UpdateResponseData resp_data2;
+  resp_data2.set_guid(kGoopdateGuid);
+  resp_data2.set_needs_admin(NEEDS_ADMIN_YES);
+  resp_data2.set_status(kResponseStatusOkValue);
+  UpdateResponse resp2(resp_data2);
+  responses.insert(std::pair<GUID, UpdateResponse>(kGoopdateGuid, resp2));
+
+  Jobs jobs;
+  Request ping_request(true);
+  CString event_log_text;
+  CompletionInfo completion_info;
+
+  EXPECT_SUCCEEDED(job_creator.CreateJobsFromResponses(responses,
+                                                       products,
+                                                       &jobs,
+                                                       &ping_request,
+                                                       &event_log_text,
+                                                       &completion_info));
+
+  // Should be a job for Resp2 since Resp2 was for Goopdate.
+  ASSERT_EQ(1, jobs.size());
+  EXPECT_TRUE(::IsEqualGUID(jobs[0]->app_data().app_guid(), kGoopdateGuid));
+  EXPECT_FALSE(jobs[0]->is_offline());
+
+  // Validate the ping data that is produced by the test method.
+  EXPECT_EQ(1, ping_request.get_request_count());
+
+  AppRequestVector::const_iterator iter = ping_request.app_requests_begin();
+  const AppRequest& app_request = *iter;
+  AppRequestData goopdate_request = app_request.request_data();
+
+  EXPECT_EQ(1, goopdate_request.num_ping_events());
+  EXPECT_EQ(PingEvent::EVENT_UPDATE_APPLICATION_BEGIN,
+            (*goopdate_request.ping_events_begin()).event_type());
+  EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS,
+            (*goopdate_request.ping_events_begin()).event_result());
+
+  // Validate the completion info generated by the test method.
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(0, completion_info.error_code);
+  EXPECT_TRUE(completion_info.text.IsEmpty());
+
+  EXPECT_EQ(0, metric_worker_skipped_app_update_for_self_update.value());
+
+  // Sleep so that there is a time difference between the time written in the
+  // registry and now.
+  ::Sleep(20);
+
+  // Stats for app1 should not have been set because we did not process it.
+  DWORD update_responses(0);
+  DWORD64 time_since_first_response_ms(0);
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       app1_guid_,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(0, update_responses);
+  EXPECT_EQ(0, time_since_first_response_ms);
+
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       kGoopdateGuid,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  EXPECT_EQ(1, update_responses);
+  EXPECT_LT(0, time_since_first_response_ms);
+  EXPECT_GT(10 * kMsPerSec, time_since_first_response_ms);
+
+  // kRegValueLastSuccessfulCheckSec is not set for app1's "noupdate" response
+  // because it is not processed due to the Goopdate update available.
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastUpdateTimeSec));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                kRegValueLastUpdateTimeSec));
+}
+
+TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_Ok) {
+  UpdateResponseData response_data;
+  response_data.set_status(_T("ok"));
+  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,
+                                                           _T("foo"));
+  EXPECT_EQ(COMPLETION_SUCCESS, info.status);
+  EXPECT_EQ(0, info.error_code);
+  EXPECT_TRUE(info.text.IsEmpty());
+}
+
+TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_NoUpdate) {
+  UpdateResponseData response_data;
+  response_data.set_status(_T("NoUpDaTe"));
+  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,
+                                                           _T("foo"));
+  EXPECT_EQ(COMPLETION_ERROR, info.status);
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, info.error_code);
+  EXPECT_STREQ(_T("No update is available."), info.text);
+}
+
+TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_Restricted) {
+  UpdateResponseData response_data;
+  response_data.set_status(_T("ReStRiCtEd"));
+  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,
+                                                           _T("foo"));
+  EXPECT_EQ(COMPLETION_ERROR, info.status);
+  EXPECT_EQ(GOOPDATE_E_RESTRICTED_SERVER_RESPONSE, info.error_code);
+  EXPECT_STREQ(_T("Access to this application is restricted."), info.text);
+}
+
+TEST_F(JobCreatorTest,
+       UpdateResponseDataToCompletionInfo_OsNotSupported) {
+  UpdateResponseData response_data;
+  response_data.set_guid(
+      StringToGuid(_T("{563CEB0C-A031-4f77-925D-590B2095DE8D}")));
+  response_data.set_status(_T("ErRoR-OsNoTsUpPoRtEd"));
+  response_data.set_error_url(
+      _T("http://foo.google.com/support/article.py?id=12345"));
+  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,
+                                                           _T("My App"));
+  EXPECT_EQ(COMPLETION_ERROR, info.status);
+  EXPECT_EQ(GOOPDATE_E_OS_NOT_SUPPORTED, info.error_code);
+  EXPECT_STREQ(_T("My App does not support your version of Windows. ")
+               _T("<a=http://foo.google.com/support/article.py?id=12345>")
+               _T("Click here for additional information.</a>"), info.text);
+}
+
+TEST_F(JobCreatorTest,
+       UpdateResponseDataToCompletionInfo_OsNotSupported_NoOsUrl) {
+  UpdateResponseData response_data;
+  response_data.set_status(_T("ErRoR-OsNoTsUpPoRtEd"));
+  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,
+                                                           _T("My App"));
+  EXPECT_EQ(COMPLETION_ERROR, info.status);
+  EXPECT_EQ(GOOPDATE_E_OS_NOT_SUPPORTED, info.error_code);
+  EXPECT_STREQ(_T("Server returned the following error: ErRoR-OsNoTsUpPoRtEd. ")
+               _T("Please try again later."), info.text);
+}
+
+TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_UnknownApp) {
+  UpdateResponseData response_data;
+  response_data.set_status(_T("eRrOr-UnKnOwNaPpLiCaTiOn"));
+  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,
+                                                           _T("My App"));
+  EXPECT_EQ(COMPLETION_ERROR, info.status);
+  EXPECT_EQ(GOOPDATE_E_UNKNOWN_APP_SERVER_RESPONSE, info.error_code);
+  EXPECT_STREQ(_T("The installer could not install the requested application ")
+               _T("due to a server side error. Please try again later. We ")
+               _T("apologize for the inconvenience."), info.text);
+}
+
+TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_InternalError) {
+  UpdateResponseData response_data;
+  response_data.set_status(_T("eRrOr-InTeRnAl"));
+  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,
+                                                           _T("My App"));
+  EXPECT_EQ(COMPLETION_ERROR, info.status);
+  EXPECT_EQ(GOOPDATE_E_INTERNAL_ERROR_SERVER_RESPONSE, info.error_code);
+  EXPECT_STREQ(_T("Server returned the following error: eRrOr-InTeRnAl. ")
+               _T("Please try again later."), info.text);
+}
+
+TEST_F(JobCreatorTest, UpdateResponseDataToCompletionInfo_UnknownResponse) {
+  UpdateResponseData response_data;
+  response_data.set_status(_T("unknown error string"));
+  CompletionInfo info = UpdateResponseDataToCompletionInfo(response_data,
+                                                           _T("My App"));
+  EXPECT_EQ(COMPLETION_ERROR, info.status);
+  EXPECT_EQ(GOOPDATE_E_UNKNOWN_SERVER_RESPONSE, info.error_code);
+  EXPECT_STREQ(_T("Server returned the following error: unknown error string. ")
+               _T("Please try again later."), info.text);
+}
+
+TEST_F(JobCreatorTest, CreateOfflineJobs_Success) {
+  // This test does not require registry hive overrides.
+  TearDown();
+
+  JobCreator job_creator(true, false, &ping_);
+  job_creator.set_fail_if_update_not_available(true);
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));
+
+  ProductDataVector products;
+  AppData app_data1;
+  app_data1.set_app_guid(app1_guid_);
+  app_data1.set_display_name(_T("Test App 1"));
+  app_data1.set_is_machine_app(true);
+  app_data1.set_language(_T("en"));
+  ProductData product1(app_data1);
+  products.push_back(product1);
+
+  CString offline_manifest_path(kGuidApp1);
+  offline_manifest_path += _T(".gup");
+  offline_manifest_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                          offline_manifest_path);
+  ASSERT_SUCCEEDED(File::Copy(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("server_manifest_one_app.xml")),
+      offline_manifest_path,
+      true));
+
+  CString installer_exe = _T("foo_installer.exe");
+  CString installer_path = ConcatenatePath(
+                                app_util::GetCurrentModuleDirectory(),
+                                kGuidApp1);
+  ASSERT_SUCCEEDED(CreateDir(installer_path, NULL));
+  // The hash of SaveArguments_OmahaTestSigned.exe needs to be kept in sync, in
+  // server_manifest_one_app.xml, for this test to succeed.
+  ASSERT_SUCCEEDED(File::Copy(
+      ConcatenatePath(ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                      _T("unittest_support")),
+                                      _T("SaveArguments_OmahaTestSigned.exe")),
+      ConcatenatePath(installer_path, installer_exe),
+      true));
+
+  Jobs jobs;
+  Request ping_request(true);
+  CString event_log_text;
+  CompletionInfo completion_info;
+  ASSERT_SUCCEEDED(job_creator.CreateOfflineJobs(
+      app_util::GetCurrentModuleDirectory(),
+      products,
+      &jobs,
+      &ping_request,
+      &event_log_text,
+      &completion_info));
+
+  ASSERT_EQ(1, jobs.size());
+  EXPECT_EQ(1, ping_request.get_request_count());
+  EXPECT_EQ(COMPLETION_SUCCESS, completion_info.status);
+  EXPECT_EQ(0, completion_info.error_code);
+  EXPECT_TRUE(completion_info.text.IsEmpty());
+  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD,
+            jobs[0]->response_data().success_action());
+  EXPECT_TRUE(jobs[0]->is_offline());
+
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastUpdateTimeSec));
+
+  EXPECT_SUCCEEDED(DeleteDirectory(installer_path));
+  EXPECT_SUCCEEDED(File::Remove(offline_manifest_path));
+}
+
+TEST_F(JobCreatorTest, CreateOfflineJobs_Failure) {
+  JobCreator job_creator(true, false, &ping_);
+  job_creator.set_fail_if_update_not_available(true);
+
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathMachine));
+
+  ProductDataVector products;
+  AppData app_data1;
+  app_data1.set_app_guid(app1_guid_);
+  app_data1.set_display_name(_T("Test App 1"));
+  app_data1.set_is_machine_app(true);
+  app_data1.set_language(_T("en"));
+  ProductData product1(app_data1);
+  products.push_back(product1);
+
+  Jobs jobs;
+  Request ping_request(true);
+  CString event_log_text;
+  CompletionInfo completion_info;
+  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            job_creator.CreateOfflineJobs(
+                            app_util::GetCurrentModuleDirectory(),
+                            products,
+                            &jobs,
+                            &ping_request,
+                            &event_log_text,
+                            &completion_info));
+
+  EXPECT_EQ(0, jobs.size());
+  EXPECT_EQ(0, ping_request.get_request_count());
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            completion_info.error_code);
+  EXPECT_EQ(COMPLETION_ERROR, completion_info.status);
+  EXPECT_STREQ(_T(""), completion_info.text);
+
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastSuccessfulCheckSec));
+  EXPECT_FALSE(RegKey::HasValue(kApp1ClientStateKeyPathMachine,
+                                kRegValueLastUpdateTimeSec));
+}
+
+TEST_F(JobCreatorTest, FindOfflineFilePath_Success) {
+  CString installer_exe = _T("foo_installer.exe");
+  CString installer_path = ConcatenatePath(
+                                app_util::GetCurrentModuleDirectory(),
+                                kGuidApp1);
+  ASSERT_SUCCEEDED(CreateDir(installer_path, NULL));
+  ASSERT_SUCCEEDED(File::Copy(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("LongRunning.exe")),
+      ConcatenatePath(installer_path, installer_exe),
+      true));
+
+  CString file_path;
+  ASSERT_SUCCEEDED(CallFindOfflineFilePath(
+                       app_util::GetCurrentModuleDirectory(),
+                       kGuidApp1,
+                       &file_path));
+  ASSERT_STREQ(ConcatenatePath(installer_path, installer_exe), file_path);
+
+  EXPECT_SUCCEEDED(DeleteDirectory(installer_path));
+}
+
+TEST_F(JobCreatorTest, FindOfflineFilePath_Failure) {
+  CString file_path;
+  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND),
+            CallFindOfflineFilePath(app_util::GetCurrentModuleDirectory(),
+                                    kGuidApp1,
+                                    &file_path));
+  ASSERT_TRUE(file_path.IsEmpty());
+}
+
+TEST_F(JobCreatorTest, ReadOfflineManifest_Success) {
+  // This test does not require registry hive overrides.
+  TearDown();
+
+  CString offline_manifest_path(kGuidApp1);
+  offline_manifest_path += _T(".gup");
+  offline_manifest_path = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                          offline_manifest_path);
+  ASSERT_SUCCEEDED(File::Copy(
+      ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                      _T("server_manifest_one_app.xml")),
+      offline_manifest_path,
+      true));
+
+  UpdateResponse response;
+  EXPECT_SUCCEEDED(CallReadOfflineManifest(
+                       app_util::GetCurrentModuleDirectory(),
+                       kGuidApp1,
+                       &response));
+
+  EXPECT_EQ(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD,
+            response.update_response_data().success_action());
+
+  EXPECT_SUCCEEDED(File::Remove(offline_manifest_path));
+}
+
+TEST_F(JobCreatorTest, ReadOfflineManifest_FileDoesNotExist) {
+  UpdateResponse response;
+  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            CallReadOfflineManifest(app_util::GetCurrentModuleDirectory(),
+                                    kGuidApp1,
+                                    &response));
+}
+
+}  // namespace omaha
+
diff --git a/worker/job_observer.cc b/worker/job_observer.cc
index 990728a..a109f2e 100644
--- a/worker/job_observer.cc
+++ b/worker/job_observer.cc
@@ -1,358 +1,358 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/worker/job_observer.h"

-#include "omaha/common/error.h"

-#include "omaha/common/sta_call.h"

-#include "omaha/worker/com_wrapper_shutdown_handler.h"

-#include "omaha/worker/ui.h"

-

-namespace omaha {

-

-JobObserverCallMethodDecorator::JobObserverCallMethodDecorator(

-    ProgressWnd* job_observer)

-      : job_observer_(job_observer),

-        progress_wnd_events_(NULL),

-        ui_thread_id_(::GetCurrentThreadId()),

-        worker_job_thread_id_(0),

-        sta_(0) {

-  ASSERT1(job_observer_);

-}

-

-HRESULT JobObserverCallMethodDecorator::Initialize() {

-  job_observer_->SetEventSink(this);

-  HRESULT hr = sta_.result();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return job_observer_->Initialize();

-}

-

-void JobObserverCallMethodDecorator::OnShow() {

-  worker_job_thread_id_ = ::GetCurrentThreadId();

-

-  if (ui_thread_id_ != ::GetCurrentThreadId()) {

-    CallMethod(job_observer_, &ProgressWnd::OnShow);

-  } else  {

-    job_observer_->OnShow();

-  }

-}

-

-void JobObserverCallMethodDecorator::OnCheckingForUpdate() {

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  if (ui_thread_id_ != ::GetCurrentThreadId()) {

-    CallMethod(job_observer_, &ProgressWnd::OnCheckingForUpdate);

-  } else  {

-    job_observer_->OnCheckingForUpdate();

-  }

-}

-

-void JobObserverCallMethodDecorator::OnUpdateAvailable(

-    const TCHAR* version_string) {

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  if (ui_thread_id_ != ::GetCurrentThreadId()) {

-    CallMethod(job_observer_,

-               &ProgressWnd::OnUpdateAvailable,

-               version_string);

-  } else  {

-    job_observer_->OnUpdateAvailable(version_string);

-  }

-}

-

-void JobObserverCallMethodDecorator::OnWaitingToDownload() {

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  if (ui_thread_id_ != ::GetCurrentThreadId()) {

-    CallMethod(job_observer_, &ProgressWnd::OnWaitingToDownload);

-  } else {

-    job_observer_->OnWaitingToDownload();

-  }

-}

-

-void JobObserverCallMethodDecorator::OnDownloading(int time_remaining_ms,

-                                                   int pos) {

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  if (ui_thread_id_ != ::GetCurrentThreadId()) {

-    CallMethod(job_observer_,

-               &ProgressWnd::OnDownloading,

-               time_remaining_ms,

-               pos);

-  } else {

-    job_observer_->OnDownloading(time_remaining_ms, pos);

-  }

-}

-

-void JobObserverCallMethodDecorator::OnWaitingToInstall() {

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  if (ui_thread_id_ != ::GetCurrentThreadId()) {

-    CallMethod(job_observer_, &ProgressWnd::OnWaitingToInstall);

-  } else {

-    job_observer_->OnWaitingToInstall();

-  }

-}

-

-void JobObserverCallMethodDecorator::OnInstalling() {

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  if (ui_thread_id_ != ::GetCurrentThreadId()) {

-    CallMethod(job_observer_, &ProgressWnd::OnInstalling);

-  } else {

-    job_observer_->OnInstalling();

-  }

-}

-

-void JobObserverCallMethodDecorator::OnPause() {

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  if (ui_thread_id_ != ::GetCurrentThreadId()) {

-    CallMethod(job_observer_, &ProgressWnd::OnPause);

-  } else {

-    job_observer_->OnPause();

-  }

-}

-

-void JobObserverCallMethodDecorator::OnComplete(CompletionCodes code,

-                                                const TCHAR* text,

-                                                DWORD error_code) {

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-  if (!job_observer_) {

-    // This method has been called twice.

-    return;

-  }

-

-  if (ui_thread_id_ != ::GetCurrentThreadId()) {

-    CallMethod(job_observer_,

-               &ProgressWnd::OnComplete,

-               code,

-               text,

-               error_code);

-  } else {

-    job_observer_->OnComplete(code, text, error_code);

-  }

-

-  // Unhook the observer. We do not unhook the progress_wnd_events_, because the

-  // UI can still call restart browsers or close.

-  job_observer_ = NULL;

-}

-

-void JobObserverCallMethodDecorator::SetEventSink(

-    ProgressWndEvents* event_sink) {

-  ASSERT1(event_sink);

-  progress_wnd_events_ = event_sink;

-}

-

-

-void JobObserverCallMethodDecorator::DoPause() {

-  ASSERT1(progress_wnd_events_);

-  progress_wnd_events_->DoPause();

-}

-

-void JobObserverCallMethodDecorator::DoResume() {

-  ASSERT1(progress_wnd_events_);

-  progress_wnd_events_->DoResume();

-}

-

-void JobObserverCallMethodDecorator::DoClose() {

-  if (progress_wnd_events_) {

-    progress_wnd_events_->DoClose();

-  }

-}

-

-void JobObserverCallMethodDecorator::DoRestartBrowsers() {

-  ASSERT1(progress_wnd_events_);

-  progress_wnd_events_->DoRestartBrowsers();

-}

-

-void JobObserverCallMethodDecorator::DoReboot() {

-  ASSERT1(progress_wnd_events_);

-  progress_wnd_events_->DoReboot();

-}

-

-void JobObserverCallMethodDecorator::DoLaunchBrowser(const CString& url) {

-  ASSERT1(progress_wnd_events_);

-  progress_wnd_events_->DoLaunchBrowser(url);

-}

-

-JobObserverCOMDecorator::JobObserverCOMDecorator()

-    : job_observer_(NULL),

-      progress_wnd_events_(NULL),

-      worker_job_thread_id_(0) {

-}

-

-JobObserverCOMDecorator::~JobObserverCOMDecorator() {

-  Uninitialize();

-}

-

-void JobObserverCOMDecorator::Initialize(

-    IJobObserver* job_observer,

-    WorkerComWrapperShutdownCallBack* call_back) {

-  ASSERT1(call_back);

-  ASSERT1(job_observer);

-  shutdown_callback_ = call_back;

-  job_observer_ = job_observer;

-  job_observer->SetEventSink(this);

-}

-

-void JobObserverCOMDecorator::Uninitialize() {

-}

-

-void JobObserverCOMDecorator::OnShow() {

-  ASSERT1(job_observer_);

-  worker_job_thread_id_ = ::GetCurrentThreadId();

-

-  job_observer_->OnShow();

-}

-

-void JobObserverCOMDecorator::OnCheckingForUpdate() {

-  ASSERT1(job_observer_);

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  job_observer_->OnCheckingForUpdate();

-}

-

-void JobObserverCOMDecorator::OnUpdateAvailable(const TCHAR* version_string) {

-  ASSERT1(job_observer_);

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  job_observer_->OnUpdateAvailable(version_string);

-}

-

-void JobObserverCOMDecorator::OnWaitingToDownload() {

-  ASSERT1(job_observer_);

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  job_observer_->OnWaitingToDownload();

-}

-

-void JobObserverCOMDecorator::OnDownloading(int time_remaining_ms, int pos) {

-  ASSERT1(job_observer_);

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  job_observer_->OnDownloading(time_remaining_ms, pos);

-}

-

-void JobObserverCOMDecorator::OnWaitingToInstall() {

-  ASSERT1(job_observer_);

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  job_observer_->OnWaitingToInstall();

-}

-

-void JobObserverCOMDecorator::OnInstalling() {

-  ASSERT1(job_observer_);

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  job_observer_->OnInstalling();

-}

-

-void JobObserverCOMDecorator::OnPause() {

-  ASSERT1(job_observer_);

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  job_observer_->OnPause();

-}

-

-void JobObserverCOMDecorator::OnComplete(CompletionCodes code,

-                                         const TCHAR* text,

-                                         DWORD) {

-  UNREFERENCED_PARAMETER(text);

-  if (!job_observer_) {

-    return;

-  }

-  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());

-

-  SetEventSink(NULL);

-

-  // We do not want to send Omaha strings to the application, so pass an empty

-  // string instead.

-  job_observer_->OnComplete(code, L"");

-  job_observer_ = NULL;

-

-  shutdown_callback_->ReleaseIgnoreShutdown();

-  shutdown_callback_ = NULL;

-}

-

-void JobObserverCOMDecorator::SetEventSink(ProgressWndEvents* event_sink) {

-  set_progress_wnd_events(event_sink);

-}

-

-

-STDMETHODIMP JobObserverCOMDecorator::DoPause() {

-  ProgressWndEvents* progress_events(progress_wnd_events());

-  if (!progress_events) {

-    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;

-  }

-

-  progress_events->DoPause();

-  return S_OK;

-}

-

-STDMETHODIMP JobObserverCOMDecorator::DoResume() {

-  ProgressWndEvents* progress_events(progress_wnd_events());

-  if (!progress_events) {

-    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;

-  }

-

-  progress_events->DoResume();

-  return S_OK;

-}

-

-STDMETHODIMP JobObserverCOMDecorator::DoClose() {

-  ProgressWndEvents* progress_events(progress_wnd_events());

-  if (!progress_events) {

-    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;

-  }

-

-  progress_events->DoClose();

-  return S_OK;

-}

-

-STDMETHODIMP JobObserverCOMDecorator::DoRestartBrowsers() {

-  ProgressWndEvents* progress_events(progress_wnd_events());

-  if (!progress_events) {

-    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;

-  }

-

-  progress_events->DoRestartBrowsers();

-  return S_OK;

-}

-

-STDMETHODIMP JobObserverCOMDecorator::DoReboot() {

-  ProgressWndEvents* progress_events(progress_wnd_events());

-  if (!progress_events) {

-    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;

-  }

-

-  progress_events->DoReboot();

-  return S_OK;

-}

-

-STDMETHODIMP JobObserverCOMDecorator::DoLaunchBrowser(const WCHAR* url) {

-  ProgressWndEvents* progress_events(progress_wnd_events());

-  if (!progress_events) {

-    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;

-  }

-

-  progress_events->DoLaunchBrowser(url);

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/worker/job_observer.h"
+#include "omaha/common/error.h"
+#include "omaha/common/sta_call.h"
+#include "omaha/worker/com_wrapper_shutdown_handler.h"
+#include "omaha/worker/ui.h"
+
+namespace omaha {
+
+JobObserverCallMethodDecorator::JobObserverCallMethodDecorator(
+    ProgressWnd* job_observer)
+      : job_observer_(job_observer),
+        progress_wnd_events_(NULL),
+        ui_thread_id_(::GetCurrentThreadId()),
+        worker_job_thread_id_(0),
+        sta_(0) {
+  ASSERT1(job_observer_);
+}
+
+HRESULT JobObserverCallMethodDecorator::Initialize() {
+  job_observer_->SetEventSink(this);
+  HRESULT hr = sta_.result();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return job_observer_->Initialize();
+}
+
+void JobObserverCallMethodDecorator::OnShow() {
+  worker_job_thread_id_ = ::GetCurrentThreadId();
+
+  if (ui_thread_id_ != ::GetCurrentThreadId()) {
+    CallMethod(job_observer_, &ProgressWnd::OnShow);
+  } else  {
+    job_observer_->OnShow();
+  }
+}
+
+void JobObserverCallMethodDecorator::OnCheckingForUpdate() {
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  if (ui_thread_id_ != ::GetCurrentThreadId()) {
+    CallMethod(job_observer_, &ProgressWnd::OnCheckingForUpdate);
+  } else  {
+    job_observer_->OnCheckingForUpdate();
+  }
+}
+
+void JobObserverCallMethodDecorator::OnUpdateAvailable(
+    const TCHAR* version_string) {
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  if (ui_thread_id_ != ::GetCurrentThreadId()) {
+    CallMethod(job_observer_,
+               &ProgressWnd::OnUpdateAvailable,
+               version_string);
+  } else  {
+    job_observer_->OnUpdateAvailable(version_string);
+  }
+}
+
+void JobObserverCallMethodDecorator::OnWaitingToDownload() {
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  if (ui_thread_id_ != ::GetCurrentThreadId()) {
+    CallMethod(job_observer_, &ProgressWnd::OnWaitingToDownload);
+  } else {
+    job_observer_->OnWaitingToDownload();
+  }
+}
+
+void JobObserverCallMethodDecorator::OnDownloading(int time_remaining_ms,
+                                                   int pos) {
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  if (ui_thread_id_ != ::GetCurrentThreadId()) {
+    CallMethod(job_observer_,
+               &ProgressWnd::OnDownloading,
+               time_remaining_ms,
+               pos);
+  } else {
+    job_observer_->OnDownloading(time_remaining_ms, pos);
+  }
+}
+
+void JobObserverCallMethodDecorator::OnWaitingToInstall() {
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  if (ui_thread_id_ != ::GetCurrentThreadId()) {
+    CallMethod(job_observer_, &ProgressWnd::OnWaitingToInstall);
+  } else {
+    job_observer_->OnWaitingToInstall();
+  }
+}
+
+void JobObserverCallMethodDecorator::OnInstalling() {
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  if (ui_thread_id_ != ::GetCurrentThreadId()) {
+    CallMethod(job_observer_, &ProgressWnd::OnInstalling);
+  } else {
+    job_observer_->OnInstalling();
+  }
+}
+
+void JobObserverCallMethodDecorator::OnPause() {
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  if (ui_thread_id_ != ::GetCurrentThreadId()) {
+    CallMethod(job_observer_, &ProgressWnd::OnPause);
+  } else {
+    job_observer_->OnPause();
+  }
+}
+
+void JobObserverCallMethodDecorator::OnComplete(CompletionCodes code,
+                                                const TCHAR* text,
+                                                DWORD error_code) {
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+  if (!job_observer_) {
+    // This method has been called twice.
+    return;
+  }
+
+  if (ui_thread_id_ != ::GetCurrentThreadId()) {
+    CallMethod(job_observer_,
+               &ProgressWnd::OnComplete,
+               code,
+               text,
+               error_code);
+  } else {
+    job_observer_->OnComplete(code, text, error_code);
+  }
+
+  // Unhook the observer. We do not unhook the progress_wnd_events_, because the
+  // UI can still call restart browsers or close.
+  job_observer_ = NULL;
+}
+
+void JobObserverCallMethodDecorator::SetEventSink(
+    ProgressWndEvents* event_sink) {
+  ASSERT1(event_sink);
+  progress_wnd_events_ = event_sink;
+}
+
+
+void JobObserverCallMethodDecorator::DoPause() {
+  ASSERT1(progress_wnd_events_);
+  progress_wnd_events_->DoPause();
+}
+
+void JobObserverCallMethodDecorator::DoResume() {
+  ASSERT1(progress_wnd_events_);
+  progress_wnd_events_->DoResume();
+}
+
+void JobObserverCallMethodDecorator::DoClose() {
+  if (progress_wnd_events_) {
+    progress_wnd_events_->DoClose();
+  }
+}
+
+void JobObserverCallMethodDecorator::DoRestartBrowsers() {
+  ASSERT1(progress_wnd_events_);
+  progress_wnd_events_->DoRestartBrowsers();
+}
+
+void JobObserverCallMethodDecorator::DoReboot() {
+  ASSERT1(progress_wnd_events_);
+  progress_wnd_events_->DoReboot();
+}
+
+void JobObserverCallMethodDecorator::DoLaunchBrowser(const CString& url) {
+  ASSERT1(progress_wnd_events_);
+  progress_wnd_events_->DoLaunchBrowser(url);
+}
+
+JobObserverCOMDecorator::JobObserverCOMDecorator()
+    : job_observer_(NULL),
+      progress_wnd_events_(NULL),
+      worker_job_thread_id_(0) {
+}
+
+JobObserverCOMDecorator::~JobObserverCOMDecorator() {
+  Uninitialize();
+}
+
+void JobObserverCOMDecorator::Initialize(
+    IJobObserver* job_observer,
+    WorkerComWrapperShutdownCallBack* call_back) {
+  ASSERT1(call_back);
+  ASSERT1(job_observer);
+  shutdown_callback_ = call_back;
+  job_observer_ = job_observer;
+  job_observer->SetEventSink(this);
+}
+
+void JobObserverCOMDecorator::Uninitialize() {
+}
+
+void JobObserverCOMDecorator::OnShow() {
+  ASSERT1(job_observer_);
+  worker_job_thread_id_ = ::GetCurrentThreadId();
+
+  job_observer_->OnShow();
+}
+
+void JobObserverCOMDecorator::OnCheckingForUpdate() {
+  ASSERT1(job_observer_);
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  job_observer_->OnCheckingForUpdate();
+}
+
+void JobObserverCOMDecorator::OnUpdateAvailable(const TCHAR* version_string) {
+  ASSERT1(job_observer_);
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  job_observer_->OnUpdateAvailable(version_string);
+}
+
+void JobObserverCOMDecorator::OnWaitingToDownload() {
+  ASSERT1(job_observer_);
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  job_observer_->OnWaitingToDownload();
+}
+
+void JobObserverCOMDecorator::OnDownloading(int time_remaining_ms, int pos) {
+  ASSERT1(job_observer_);
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  job_observer_->OnDownloading(time_remaining_ms, pos);
+}
+
+void JobObserverCOMDecorator::OnWaitingToInstall() {
+  ASSERT1(job_observer_);
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  job_observer_->OnWaitingToInstall();
+}
+
+void JobObserverCOMDecorator::OnInstalling() {
+  ASSERT1(job_observer_);
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  job_observer_->OnInstalling();
+}
+
+void JobObserverCOMDecorator::OnPause() {
+  ASSERT1(job_observer_);
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  job_observer_->OnPause();
+}
+
+void JobObserverCOMDecorator::OnComplete(CompletionCodes code,
+                                         const TCHAR* text,
+                                         DWORD) {
+  UNREFERENCED_PARAMETER(text);
+  if (!job_observer_) {
+    return;
+  }
+  ASSERT1(worker_job_thread_id_ == ::GetCurrentThreadId());
+
+  SetEventSink(NULL);
+
+  // We do not want to send Omaha strings to the application, so pass an empty
+  // string instead.
+  job_observer_->OnComplete(code, L"");
+  job_observer_ = NULL;
+
+  shutdown_callback_->ReleaseIgnoreShutdown();
+  shutdown_callback_ = NULL;
+}
+
+void JobObserverCOMDecorator::SetEventSink(ProgressWndEvents* event_sink) {
+  set_progress_wnd_events(event_sink);
+}
+
+
+STDMETHODIMP JobObserverCOMDecorator::DoPause() {
+  ProgressWndEvents* progress_events(progress_wnd_events());
+  if (!progress_events) {
+    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;
+  }
+
+  progress_events->DoPause();
+  return S_OK;
+}
+
+STDMETHODIMP JobObserverCOMDecorator::DoResume() {
+  ProgressWndEvents* progress_events(progress_wnd_events());
+  if (!progress_events) {
+    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;
+  }
+
+  progress_events->DoResume();
+  return S_OK;
+}
+
+STDMETHODIMP JobObserverCOMDecorator::DoClose() {
+  ProgressWndEvents* progress_events(progress_wnd_events());
+  if (!progress_events) {
+    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;
+  }
+
+  progress_events->DoClose();
+  return S_OK;
+}
+
+STDMETHODIMP JobObserverCOMDecorator::DoRestartBrowsers() {
+  ProgressWndEvents* progress_events(progress_wnd_events());
+  if (!progress_events) {
+    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;
+  }
+
+  progress_events->DoRestartBrowsers();
+  return S_OK;
+}
+
+STDMETHODIMP JobObserverCOMDecorator::DoReboot() {
+  ProgressWndEvents* progress_events(progress_wnd_events());
+  if (!progress_events) {
+    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;
+  }
+
+  progress_events->DoReboot();
+  return S_OK;
+}
+
+STDMETHODIMP JobObserverCOMDecorator::DoLaunchBrowser(const WCHAR* url) {
+  ProgressWndEvents* progress_events(progress_wnd_events());
+  if (!progress_events) {
+    return GOOPDATE_E_OBSERVER_PROGRESS_WND_EVENTS_NULL;
+  }
+
+  progress_events->DoLaunchBrowser(url);
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/worker/job_observer.h b/worker/job_observer.h
index 3f9b31a..fa106b5 100644
--- a/worker/job_observer.h
+++ b/worker/job_observer.h
@@ -1,170 +1,170 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_JOB_OBSERVER_H__

-#define OMAHA_WORKER_JOB_OBSERVER_H__

-

-#include <windows.h>

-#include <atlbase.h>

-#include <atlcom.h>

-#include "base/scoped_ptr.h"

-#include "goopdate/google_update_idl.h"

-#include "omaha/common/sta.h"

-

-namespace omaha {

-

-class ProgressWnd;

-class WorkerComWrapperShutdownCallBack;

-

-// The UI generates events when interesting things happens with it,

-// mostly due to the user clicking on controls.

-class ProgressWndEvents {

- public:

-  virtual ~ProgressWndEvents() {}

-  virtual void DoPause() = 0;

-  virtual void DoResume() = 0;

-  virtual void DoClose() = 0;

-  virtual void DoRestartBrowsers() = 0;

-  virtual void DoReboot() = 0;

-  virtual void DoLaunchBrowser(const CString& url) = 0;

-};

-

-class JobObserver {

- public:

-  virtual ~JobObserver() {}

-  virtual void OnShow() = 0;

-  virtual void OnCheckingForUpdate() = 0;

-  virtual void OnUpdateAvailable(const TCHAR* version_string) = 0;

-  virtual void OnWaitingToDownload() = 0;

-  virtual void OnDownloading(int time_remaining_ms, int pos) = 0;

-  virtual void OnWaitingToInstall() = 0;

-  virtual void OnInstalling() = 0;

-  virtual void OnPause() = 0;

-  virtual void OnComplete(CompletionCodes code,

-                          const TCHAR* text,

-                          DWORD error_code) = 0;

-  virtual void SetEventSink(ProgressWndEvents* event_sink) = 0;

-  virtual void Uninitialize() = 0;

-};

-

-// Class that delegates Job progress calls to the UI, and delegates UI events

-// to the Job. Handles the case where UI thread is different than the calling

-// thread.

-class JobObserverCallMethodDecorator

-    : public JobObserver,

-      public ProgressWndEvents {

- public:

-  explicit JobObserverCallMethodDecorator(ProgressWnd* observer);

-  virtual ~JobObserverCallMethodDecorator() {}

-  HRESULT Initialize();

-

-  // JobObserver implementation.

-  virtual void OnShow();

-  virtual void OnCheckingForUpdate();

-  virtual void OnUpdateAvailable(const TCHAR* version_string);

-  virtual void OnWaitingToDownload();

-  virtual void OnDownloading(int time_remaining_ms, int pos);

-  virtual void OnWaitingToInstall();

-  virtual void OnInstalling();

-  virtual void OnPause();

-  virtual void OnComplete(CompletionCodes code,

-                          const TCHAR* text,

-                          DWORD error_code);

-  virtual void SetEventSink(ProgressWndEvents* event_sink);

-  virtual void Uninitialize() {}

-

-  // ProgressWndEvents implementation.

-  virtual void DoPause();

-  virtual void DoResume();

-  virtual void DoClose();

-  virtual void DoRestartBrowsers();

-  virtual void DoReboot();

-  virtual void DoLaunchBrowser(const CString& url);

-

- private:

-  scoped_sta sta_;

-  ProgressWnd* job_observer_;

-  ProgressWndEvents* progress_wnd_events_;

-  DWORD ui_thread_id_;

-  DWORD worker_job_thread_id_;

-};

-

-class JobObserverCOMDecorator

-  : public CComObjectRootEx<CComMultiThreadModel>,

-    public JobObserver,

-    public IProgressWndEvents {

- public:

-  BEGIN_COM_MAP(JobObserverCOMDecorator)

-    COM_INTERFACE_ENTRY(IProgressWndEvents)

-  END_COM_MAP()

-

-  JobObserverCOMDecorator();

-  virtual ~JobObserverCOMDecorator();

-  void Initialize(IJobObserver* job_observer,

-                  WorkerComWrapperShutdownCallBack* call_back);

-

-  // JobObserver implementation.

-  virtual void OnShow();

-  virtual void OnCheckingForUpdate();

-  virtual void OnUpdateAvailable(const TCHAR* version_string);

-  virtual void OnWaitingToDownload();

-  virtual void OnDownloading(int time_remaining_ms, int pos);

-  virtual void OnWaitingToInstall();

-  virtual void OnInstalling();

-  virtual void OnPause();

-  virtual void OnComplete(CompletionCodes code,

-                          const TCHAR* text,

-                          DWORD error_code);

-  virtual void SetEventSink(ProgressWndEvents* event_sink);

-  void Uninitialize();

-

-  // IProgressWndEvents.

-  STDMETHOD(DoPause)();

-  STDMETHOD(DoResume)();

-  STDMETHOD(DoClose)();

-  STDMETHOD(DoRestartBrowsers)();

-  STDMETHOD(DoReboot)();

-  STDMETHOD(DoLaunchBrowser)(const WCHAR* url);

-

- private:

-  // The DoXXX() methods can be called from multiple COM threads since the

-  // code is running in an MTA. Write access to progress_wnd_events_ member

-  // must be atomic.

-  // The OnXXX() calls on the other hand are always called from a single

-  // thread, so no synchronization is needed.

-  ProgressWndEvents* progress_wnd_events() {

-    return progress_wnd_events_;

-  }

-

-  void set_progress_wnd_events(ProgressWndEvents* progress_wnd_events) {

-    // InterlockedExchangePointer is broken due to ATL defining a function with

-    // the same name in the global namespace and hiding the Win32 API.

-    // InterlockedExchange introduces a full memory barrier.

-    ::InterlockedExchange(

-        reinterpret_cast<volatile LONG*>(&progress_wnd_events_),

-        reinterpret_cast<LONG>(progress_wnd_events));

-  }

-

-  CComPtr<IJobObserver> job_observer_;

-  ProgressWndEvents* volatile progress_wnd_events_;

-  WorkerComWrapperShutdownCallBack* shutdown_callback_;

-  DWORD thread_id_;

-  DWORD worker_job_thread_id_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_JOB_OBSERVER_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_JOB_OBSERVER_H__
+#define OMAHA_WORKER_JOB_OBSERVER_H__
+
+#include <windows.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include "base/scoped_ptr.h"
+#include "goopdate/google_update_idl.h"
+#include "omaha/common/sta.h"
+
+namespace omaha {
+
+class ProgressWnd;
+class WorkerComWrapperShutdownCallBack;
+
+// The UI generates events when interesting things happens with it,
+// mostly due to the user clicking on controls.
+class ProgressWndEvents {
+ public:
+  virtual ~ProgressWndEvents() {}
+  virtual void DoPause() = 0;
+  virtual void DoResume() = 0;
+  virtual void DoClose() = 0;
+  virtual void DoRestartBrowsers() = 0;
+  virtual void DoReboot() = 0;
+  virtual void DoLaunchBrowser(const CString& url) = 0;
+};
+
+class JobObserver {
+ public:
+  virtual ~JobObserver() {}
+  virtual void OnShow() = 0;
+  virtual void OnCheckingForUpdate() = 0;
+  virtual void OnUpdateAvailable(const TCHAR* version_string) = 0;
+  virtual void OnWaitingToDownload() = 0;
+  virtual void OnDownloading(int time_remaining_ms, int pos) = 0;
+  virtual void OnWaitingToInstall() = 0;
+  virtual void OnInstalling() = 0;
+  virtual void OnPause() = 0;
+  virtual void OnComplete(CompletionCodes code,
+                          const TCHAR* text,
+                          DWORD error_code) = 0;
+  virtual void SetEventSink(ProgressWndEvents* event_sink) = 0;
+  virtual void Uninitialize() = 0;
+};
+
+// Class that delegates Job progress calls to the UI, and delegates UI events
+// to the Job. Handles the case where UI thread is different than the calling
+// thread.
+class JobObserverCallMethodDecorator
+    : public JobObserver,
+      public ProgressWndEvents {
+ public:
+  explicit JobObserverCallMethodDecorator(ProgressWnd* observer);
+  virtual ~JobObserverCallMethodDecorator() {}
+  HRESULT Initialize();
+
+  // JobObserver implementation.
+  virtual void OnShow();
+  virtual void OnCheckingForUpdate();
+  virtual void OnUpdateAvailable(const TCHAR* version_string);
+  virtual void OnWaitingToDownload();
+  virtual void OnDownloading(int time_remaining_ms, int pos);
+  virtual void OnWaitingToInstall();
+  virtual void OnInstalling();
+  virtual void OnPause();
+  virtual void OnComplete(CompletionCodes code,
+                          const TCHAR* text,
+                          DWORD error_code);
+  virtual void SetEventSink(ProgressWndEvents* event_sink);
+  virtual void Uninitialize() {}
+
+  // ProgressWndEvents implementation.
+  virtual void DoPause();
+  virtual void DoResume();
+  virtual void DoClose();
+  virtual void DoRestartBrowsers();
+  virtual void DoReboot();
+  virtual void DoLaunchBrowser(const CString& url);
+
+ private:
+  scoped_sta sta_;
+  ProgressWnd* job_observer_;
+  ProgressWndEvents* progress_wnd_events_;
+  DWORD ui_thread_id_;
+  DWORD worker_job_thread_id_;
+};
+
+class JobObserverCOMDecorator
+  : public CComObjectRootEx<CComMultiThreadModel>,
+    public JobObserver,
+    public IProgressWndEvents {
+ public:
+  BEGIN_COM_MAP(JobObserverCOMDecorator)
+    COM_INTERFACE_ENTRY(IProgressWndEvents)
+  END_COM_MAP()
+
+  JobObserverCOMDecorator();
+  virtual ~JobObserverCOMDecorator();
+  void Initialize(IJobObserver* job_observer,
+                  WorkerComWrapperShutdownCallBack* call_back);
+
+  // JobObserver implementation.
+  virtual void OnShow();
+  virtual void OnCheckingForUpdate();
+  virtual void OnUpdateAvailable(const TCHAR* version_string);
+  virtual void OnWaitingToDownload();
+  virtual void OnDownloading(int time_remaining_ms, int pos);
+  virtual void OnWaitingToInstall();
+  virtual void OnInstalling();
+  virtual void OnPause();
+  virtual void OnComplete(CompletionCodes code,
+                          const TCHAR* text,
+                          DWORD error_code);
+  virtual void SetEventSink(ProgressWndEvents* event_sink);
+  void Uninitialize();
+
+  // IProgressWndEvents.
+  STDMETHOD(DoPause)();
+  STDMETHOD(DoResume)();
+  STDMETHOD(DoClose)();
+  STDMETHOD(DoRestartBrowsers)();
+  STDMETHOD(DoReboot)();
+  STDMETHOD(DoLaunchBrowser)(const WCHAR* url);
+
+ private:
+  // The DoXXX() methods can be called from multiple COM threads since the
+  // code is running in an MTA. Write access to progress_wnd_events_ member
+  // must be atomic.
+  // The OnXXX() calls on the other hand are always called from a single
+  // thread, so no synchronization is needed.
+  ProgressWndEvents* progress_wnd_events() {
+    return progress_wnd_events_;
+  }
+
+  void set_progress_wnd_events(ProgressWndEvents* progress_wnd_events) {
+    // InterlockedExchangePointer is broken due to ATL defining a function with
+    // the same name in the global namespace and hiding the Win32 API.
+    // InterlockedExchange introduces a full memory barrier.
+    ::InterlockedExchange(
+        reinterpret_cast<volatile LONG*>(&progress_wnd_events_),
+        reinterpret_cast<LONG>(progress_wnd_events));
+  }
+
+  CComPtr<IJobObserver> job_observer_;
+  ProgressWndEvents* volatile progress_wnd_events_;
+  WorkerComWrapperShutdownCallBack* shutdown_callback_;
+  DWORD thread_id_;
+  DWORD worker_job_thread_id_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_JOB_OBSERVER_H__
+
diff --git a/worker/job_observer_mock.h b/worker/job_observer_mock.h
index c9bc1bc..88db9b6 100644
--- a/worker/job_observer_mock.h
+++ b/worker/job_observer_mock.h
@@ -1,61 +1,61 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_JOB_OBSERVER_MOCK_H_

-#define OMAHA_WORKER_JOB_OBSERVER_MOCK_H_

-

-#include "omaha/worker/job_observer.h"

-

-namespace omaha {

-

-class JobObserverMock : public JobObserver {

- public:

-  JobObserverMock()

-      : completion_code(static_cast<CompletionCodes>(-1)),

-        completion_error_code(S_OK) {}

-  virtual void OnShow() {}

-  virtual void OnCheckingForUpdate() {}

-  virtual void OnUpdateAvailable(const TCHAR* version_string) {

-    UNREFERENCED_PARAMETER(version_string);

-  }

-  virtual void OnWaitingToDownload() {}

-  virtual void OnDownloading(int time_remaining_ms, int pos) {

-    UNREFERENCED_PARAMETER(time_remaining_ms);

-    UNREFERENCED_PARAMETER(pos);

-  }

-  virtual void OnWaitingToInstall() {}

-  virtual void OnInstalling() {}

-  virtual void OnPause() {}

-  virtual void OnComplete(CompletionCodes code,

-                          const TCHAR* text,

-                          DWORD error_code) {

-    completion_code = code;

-    completion_text = text;

-    completion_error_code = error_code;

-  }

-  virtual void SetEventSink(ProgressWndEvents* event_sink) {

-    UNREFERENCED_PARAMETER(event_sink);

-  }

-  virtual void Uninitialize() {}

-

-  CompletionCodes completion_code;

-  CString completion_text;

-  DWORD completion_error_code;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_JOB_OBSERVER_MOCK_H_

-

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_JOB_OBSERVER_MOCK_H_
+#define OMAHA_WORKER_JOB_OBSERVER_MOCK_H_
+
+#include "omaha/worker/job_observer.h"
+
+namespace omaha {
+
+class JobObserverMock : public JobObserver {
+ public:
+  JobObserverMock()
+      : completion_code(static_cast<CompletionCodes>(-1)),
+        completion_error_code(S_OK) {}
+  virtual void OnShow() {}
+  virtual void OnCheckingForUpdate() {}
+  virtual void OnUpdateAvailable(const TCHAR* version_string) {
+    UNREFERENCED_PARAMETER(version_string);
+  }
+  virtual void OnWaitingToDownload() {}
+  virtual void OnDownloading(int time_remaining_ms, int pos) {
+    UNREFERENCED_PARAMETER(time_remaining_ms);
+    UNREFERENCED_PARAMETER(pos);
+  }
+  virtual void OnWaitingToInstall() {}
+  virtual void OnInstalling() {}
+  virtual void OnPause() {}
+  virtual void OnComplete(CompletionCodes code,
+                          const TCHAR* text,
+                          DWORD error_code) {
+    completion_code = code;
+    completion_text = text;
+    completion_error_code = error_code;
+  }
+  virtual void SetEventSink(ProgressWndEvents* event_sink) {
+    UNREFERENCED_PARAMETER(event_sink);
+  }
+  virtual void Uninitialize() {}
+
+  CompletionCodes completion_code;
+  CString completion_text;
+  DWORD completion_error_code;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_JOB_OBSERVER_MOCK_H_
+
diff --git a/worker/job_unittest.cc b/worker/job_unittest.cc
index c26d8d3..71bcc28 100644
--- a/worker/job_unittest.cc
+++ b/worker/job_unittest.cc
@@ -1,1445 +1,1445 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/app_util.h"

-#include "omaha/common/error.h"

-#include "omaha/common/file.h"

-#include "omaha/common/path.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/system.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/goopdate_xml_parser.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/application_manager.h"

-#include "omaha/worker/job.h"

-#include "omaha/worker/job_observer_mock.h"

-#include "omaha/worker/ping.h"

-

-namespace omaha {

-

-namespace {

-

-/*

-void CreateTestAppData(AppData* app_data) {

-  ASSERT_TRUE(app_data != NULL);

-  app_data->set_version(_T("1.1.1.3"));

-  app_data->set_previous_version(_T("1.0.0.0"));

-  app_data->set_language(_T("abc"));

-  app_data->set_ap(_T("Test ap"));

-  app_data->set_tt_token(_T("Test TT Token"));

-  app_data->set_iid(StringToGuid(_T("{F723495F-8ACF-4746-824d-643741C797B5}")));

-  app_data->set_brand_code(_T("GOOG"));

-  app_data->set_client_id(_T("someclient"));

-  app_data->set_did_run(AppData::ACTIVE_RUN);

-  app_data->set_install_source(_T("twoclick"));

-}

-*/

-

-const TCHAR kFooGuid[] = _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");

-const TCHAR kFullFooAppClientKeyPath[] =

-    _T("HKLM\\Software\\Google\\Update\\Clients\\")

-    _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");

-const TCHAR kFullFooAppClientStateKeyPath[] =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\")

-    _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");

-const TCHAR kSetupFooV1RelativeLocation[] =

-    _T("unittest_support\\test_foo_v1.0.101.0.msi");

-

-const TCHAR kMsiLogFormat[] = _T("%s.log");

-const TCHAR kMsiUninstallArguments[] = _T("/quiet /uninstall %s");

-const TCHAR kMsiCommand[] = _T("msiexec");

-

-const TCHAR kJobExecutable[] = _T("cmd.exe");

-const TCHAR kExecuteCommandAndTerminateSwitch[] = _T("/c %s");

-

-const TCHAR expected_iid_string[] =

-    _T("{BF66411E-8FAC-4E2C-920C-849DF562621C}");

-

-CString CreateUniqueTempDir() {

-  GUID guid(GUID_NULL);

-  EXPECT_HRESULT_SUCCEEDED(::CoCreateGuid(&guid));

-  CString unique_dir_path =

-      ConcatenatePath(app_util::GetTempDir(), GuidToString(guid));

-  EXPECT_HRESULT_SUCCEEDED(CreateDir(unique_dir_path, NULL));

-  return unique_dir_path;

-}

-

-}  // namespace

-

-class JobTest : public testing::Test {

- protected:

-  JobTest() : is_machine_(true) {}

-

-  void SetUp() {

-    // Default to an auto-update job.

-    job_.reset(new Job(true, &ping_));

-    job_->is_background_ = true;

-  }

-

-  void set_info(const CompletionInfo& info) {

-    job_->info_ = info;

-  }

-

-  void set_job_state(JobState job_state) {

-    job_->job_state_ = job_state;

-  }

-

-  void SetIsInstallJob() {

-    job_->is_update_ = false;

-    job_->is_background_ = false;

-  }

-

-  HRESULT DoCompleteJob() {

-    return job_->DoCompleteJob();

-  }

-

-  HRESULT SendStateChangePing(JobState previous_state) {

-    return job_->SendStateChangePing(previous_state);

-  }

-

-  void SetUpdateResponseDataArguments(const CString& arguments) {

-    job_->update_response_data_.set_arguments(arguments);

-  }

-

-  void SetUpdateResponseSuccessAction(SuccessfulInstallAction success_action) {

-    job_->update_response_data_.set_success_action(success_action);

-  }

-

-  void SetAppData(const AppData& app_data) {

-    job_->set_app_data(app_data);

-  }

-

-  void set_download_file_name(const CString& download_file) {

-    job_->download_file_name_ = download_file;

-  }

-

-  HRESULT UpdateRegistry(AppData* data) {

-    return job_->UpdateRegistry(data);

-  }

-

-  HRESULT UpdateJob() {

-    return job_->UpdateJob();

-  }

-

-  HRESULT DeleteJobDownloadDirectory() const {

-    return job_->DeleteJobDownloadDirectory();

-  }

-

-  void set_launch_cmd_line(const CString launch_cmd_line) {

-    job_->launch_cmd_line_ = launch_cmd_line;

-  }

-

-  bool did_launch_cmd_fail() { return job_->did_launch_cmd_fail_; }

-  void set_did_launch_cmd_fail(bool did_launch_cmd_fail) {

-    job_->did_launch_cmd_fail_ = did_launch_cmd_fail;

-  }

-

-  scoped_ptr<Job> job_;

-  Ping ping_;

-  bool is_machine_;

-};

-

-// Does not override registry hives because it would not affect the installer.

-class JobInstallFooTest : public JobTest {

- protected:

-  virtual void SetUp() {

-    JobTest::SetUp();

-

-    foo_installer_path_ = ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                          kSetupFooV1RelativeLocation);

-    ASSERT_TRUE(File::Exists(foo_installer_path_));

-

-    foo_installer_log_path_.Format(kMsiLogFormat, foo_installer_path_);

-

-    ASSERT_HRESULT_SUCCEEDED(File::Remove(foo_installer_log_path_));

-    ASSERT_FALSE(File::Exists(foo_installer_log_path_));

-

-    RegKey::DeleteKey(kFullFooAppClientKeyPath);

-    ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath));

-    RegKey::DeleteKey(kFullFooAppClientStateKeyPath);

-    ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));

-  }

-

-  virtual void TearDown() {

-    RegKey::DeleteKey(kFullFooAppClientKeyPath);

-    RegKey::DeleteKey(kFullFooAppClientStateKeyPath);

-  }

-

-  AppData PopulateFooAppData() {

-    AppData app_data(StringToGuid(kFooGuid), is_machine_);

-    app_data.set_display_name(_T("Foo"));

-    app_data.set_language(_T("en"));

-    app_data.set_ap(_T("test_ap"));

-    app_data.set_iid(StringToGuid(expected_iid_string));

-    app_data.set_brand_code(_T("GOOG"));

-    app_data.set_client_id(_T("_some_partner"));

-    app_data.set_browser_type(BROWSER_IE);

-    app_data.set_usage_stats_enable(TRISTATE_TRUE);

-    return app_data;

-  }

-

-  // Verifies the values that are written to ClientState before installing.

-  // Assumes the is Foo.

-  void VerifyFooClientStateValuesWrittenBeforeInstall(bool is_first_install) {

-    CString str_value;

-    DWORD value;

-

-    if (is_first_install) {

-      EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                                kRegValueBrandCode,

-                                                &str_value));

-      EXPECT_STREQ(_T("GOOG"), str_value);

-      EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                                kRegValueClientId,

-                                                &str_value));

-      EXPECT_STREQ(_T("_some_partner"), str_value);

-      const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-      DWORD install_time(0);

-      EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                        kRegValueInstallTimeSec,

-                                        &install_time));

-      EXPECT_GE(now, install_time);

-      EXPECT_GE(static_cast<uint32>(500), now - install_time);

-    } else {

-      EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                                kRegValueBrandCode,

-                                                &str_value));

-      EXPECT_STREQ(_T("g00g"), str_value);

-      EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,

-                                    kRegValueClientId));

-      EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,

-                                    kRegValueInstallTimeSec));

-    }

-

-    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                              kRegValueAdditionalParams,

-                                              &str_value));

-    EXPECT_STREQ(_T("test_ap"), str_value);

-    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                              kRegValueBrowser,

-                                              &value));

-    EXPECT_EQ(BROWSER_IE, value);

-    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                              _T("usagestats"),

-                                              &value));

-    EXPECT_EQ(TRISTATE_TRUE, value);

-    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                              kRegValueLanguage,

-                                              &str_value));

-    EXPECT_STREQ(_T("en"), str_value);

-  }

-

-  void VerifyFooClientStateValuesWrittenBeforeInstallNotPresent(

-      bool is_brand_code_present) {

-    CString str_value;

-    DWORD value;

-

-    HRESULT hr = RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                  kRegValueBrandCode,

-                                  &str_value);

-    if (is_brand_code_present) {

-      EXPECT_HRESULT_SUCCEEDED(hr);

-    } else {

-      EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);

-    }

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-              RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                               kRegValueClientId,

-                               &str_value));

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-              RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                               kRegValueBrowser,

-                               &value));

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-              RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                               _T("usagestats"),

-                               &value));

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-              RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                               kRegValueLanguage,

-                               &str_value));

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-              RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                               kRegValueAdditionalParams,

-                               &str_value));

-    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),

-              RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                               kRegValueTTToken,

-                               &str_value));

-  }

-

-  // Verifies the values that are written to ClientState after successfully

-  // installing. Assumes the is Foo.

-  void VerifyFooClientStateValuesWrittenAfterSuccessfulInstall() {

-    CString str_value;

-    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                              kRegValueProductVersion,

-                                              &str_value));

-    EXPECT_STREQ(_T("1.0.101.0"), str_value);

-    // TODO(omaha): Verify language. Requires changing the MSI. Make sure the

-    // language the MSI writes is different than in PopulateFooAppData().

-    // When we do this, make sure we also have a test where the app does not

-    // write lang in Client to verify that the ClientState value is not erased.

-    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                              kRegValueInstallationId,

-                                              &str_value));

-    EXPECT_STREQ(expected_iid_string, str_value);

-  }

-

-  void Install_MsiInstallerSucceeds(bool is_update,

-                                    bool is_first_install,

-                                    bool is_offline);

-  void Install_InstallerFailed_WhenNoExistingPreInstallData(bool is_update);

-  void Install_InstallerFailed_WhenExistingPreInstallData(bool is_update);

-

-  CString foo_installer_path_;

-  CString foo_installer_log_path_;

-};

-

-// TODO(omaha): Test all methods of Job

-

-// No attempt is made to delete it the directory in this case.

-TEST_F(JobTest, DeleteJobDownloadDirectory_Omaha_Test) {

-  const TCHAR* kNnonExistantDir = _T("testdirfoo");

-  CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));

-

-  set_info(info);

-  set_download_file_name(ConcatenatePath(kNnonExistantDir, _T("foo.msi")));

-

-  AppData app_data;

-  app_data.set_app_guid(kGoopdateGuid);

-  SetAppData(app_data);

-

-  ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory());

-}

-

-// The download file name is not set and no attempt to delete it is made for

-// update checks only.

-TEST_F(JobTest, DeleteJobDownloadDirectory_OnDemandUpdateCheckOnly) {

-  job_.reset(new Job(true, &ping_));

-  job_->set_is_update_check_only(true);

-

-  CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));

-

-  set_info(info);

-

-  AppData app_data;

-  app_data.set_app_guid(

-      StringToGuid(_T("{55B9A9BD-16FC-4060-B667-892B312CAAA5}")));

-  SetAppData(app_data);

-

-  ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory());

-}

-

-TEST_F(JobTest, DeleteJobDownloadDirectory_OnDemandUpdate) {

-  job_.reset(new Job(true, &ping_));

-

-  CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));

-  set_info(info);

-  const CString destination_path = CreateUniqueTempDir();

-  set_download_file_name(ConcatenatePath(destination_path, _T("foo.msi")));

-

-  AppData app_data;

-  app_data.set_app_guid(

-      StringToGuid(_T("{55B9A9BD-16FC-4060-B667-892B312CAAA5}")));

-  SetAppData(app_data);

-

-  ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory());

-  ASSERT_FALSE(File::Exists(destination_path));

-}

-

-TEST_F(JobTest, DeleteJobDownloadDirectory_Success) {

-  CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));

-  set_info(info);

-  const CString destination_path = CreateUniqueTempDir();

-  set_download_file_name(ConcatenatePath(destination_path, _T("foo.msi")));

-

-  AppData app_data;

-  app_data.set_app_guid(

-      StringToGuid(_T("{55B9A9BD-16FC-4060-B667-892B312CAAA5}")));

-  SetAppData(app_data);

-

-  ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory());

-  ASSERT_FALSE(File::Exists(destination_path));

-}

-

-TEST_F(JobTest, SendStateChangePing) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  AppManager app_manager(is_machine_);

-  AppData app_data(StringToGuid(_T("{4F1A02DC-E965-4518-AED4-E15A3E1B1219}")),

-                   is_machine_);

-

-  app_data.set_language(_T("abc"));

-  app_data.set_ap(_T("Test ap"));

-  app_data.set_tt_token(_T("Test TT Token"));

-  app_data.set_iid(StringToGuid(_T("{C16050EA-6D4C-4275-A8EC-22D4C59E942A}")));

-  app_data.set_brand_code(_T("GOOG"));

-  app_data.set_client_id(_T("otherclient"));

-  app_data.set_display_name(_T("UnitTest"));

-  app_data.set_browser_type(BROWSER_DEFAULT);

-  job_->set_app_data(app_data);

-

-  set_job_state(JOBSTATE_INSTALLERSTARTED);

-  ASSERT_SUCCEEDED(SendStateChangePing(JOBSTATE_DOWNLOADCOMPLETED));

-

-  CompletionInfo info(COMPLETION_ERROR, 123, _T(""));

-

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-  OverrideRegistryHives(kRegistryHiveOverrideRoot);

-  CString app_goopdate_key_name = goopdate_utils::GetAppClientsKey(

-      is_machine_,

-      GOOPDATE_APP_ID);

-

-  RegKey goopdate_key;

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(app_goopdate_key_name,

-                                            kRegValueProductVersion,

-                                            _T("1.2.3.4")));

-  job_->NotifyCompleted(info);

-

-  RestoreRegistryHives();

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-  ASSERT_SUCCEEDED(SendStateChangePing(JOBSTATE_INSTALLERSTARTED));

-}

-

-TEST_F(JobTest, UpdateRegistry) {

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);

-

-  CString app_guid = _T("{4F1A02DC-E965-4518-AED4-E15A3E1B1219}");

-  CString expected_version = _T("1.3.3.3");

-  CString previous_version = _T("1.0.0.0");

-  CString expected_lang = _T("abc");

-  CString reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENTS, app_guid);

-  ASSERT_SUCCEEDED(RegKey::CreateKey(reg_key_path));

-  ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path,

-                                    kRegValueProductVersion,

-                                    expected_version));

-  ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path,

-                                    kRegValueLanguage,

-                                    expected_lang));

-

-  AppManager app_manager(is_machine_);

-  AppData app_data(StringToGuid(app_guid), is_machine_);

-  app_data.set_version(expected_version);

-  app_data.set_previous_version(previous_version);

-  app_data.set_language(expected_lang);

-  app_data.set_ap(_T("Test ap"));

-  app_data.set_tt_token(_T("Test TT Token"));

-  app_data.set_iid(StringToGuid(_T("{C16050EA-6D4C-4275-A8EC-22D4C59E942A}")));

-  app_data.set_brand_code(_T("GOOG"));

-  app_data.set_client_id(_T("otherclient"));

-  app_data.set_display_name(_T("UnitTest"));

-  app_data.set_browser_type(BROWSER_DEFAULT);

-  app_data.set_install_source(_T("install source"));

-  job_->set_app_data(app_data);

-  set_job_state(JOBSTATE_COMPLETED);

-

-  // Call the test method.

-  AppData new_app_data;

-  ASSERT_SUCCEEDED(UpdateRegistry(&new_app_data));

-

-  // Check the results.

-  reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENT_STATE, app_guid);

-  ASSERT_SUCCEEDED(RegKey::HasKey(reg_key_path));

-

-  CString actual_previous_version;

-  ASSERT_SUCCEEDED(RegKey::GetValue(reg_key_path,

-                                    kRegValueProductVersion,

-                                    &actual_previous_version));

-  CString actual_lang;

-  ASSERT_SUCCEEDED(RegKey::GetValue(reg_key_path,

-                                    kRegValueLanguage,

-                                    &actual_lang));

-

-  // The client state registry should have been updated.

-  EXPECT_STREQ(expected_version, actual_previous_version);

-  EXPECT_STREQ(expected_lang, actual_lang);

-

-  // The job's previous version should not have changed.

-  EXPECT_STREQ(expected_version, job_->app_data().version());

-  EXPECT_STREQ(previous_version, job_->app_data().previous_version());

-

-  // new_app_data's previous_version should have been updated.

-  EXPECT_STREQ(expected_version, new_app_data.version());

-  EXPECT_STREQ(expected_version, new_app_data.previous_version());

-

-  RestoreRegistryHives();

-  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-TEST_F(JobTest, UpdateJob) {

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);

-

-  CString app_guid = _T("{4F1A02DC-E965-4518-AED4-E15A3E1B1219}");

-  CString expected_version = _T("1.3.3.3");

-  CString previous_version = _T("1.0.0.0");

-  CString expected_lang = _T("abc");

-  CString reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENTS, app_guid);

-  ASSERT_SUCCEEDED(RegKey::CreateKey(reg_key_path));

-  ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path,

-                                    kRegValueProductVersion,

-                                    expected_version));

-  ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path,

-                                    kRegValueLanguage,

-                                    expected_lang));

-

-  AppManager app_manager(is_machine_);

-  AppData app_data(StringToGuid(app_guid), is_machine_);

-  app_data.set_version(_T("4.5.6.6"));

-  app_data.set_previous_version(previous_version);

-  app_data.set_language(expected_lang);

-  app_data.set_ap(_T("Test ap"));

-  app_data.set_tt_token(_T("Test TT Token"));

-  app_data.set_iid(

-      StringToGuid(_T("{C16050EA-6D4C-4275-A8EC-22D4C59E942A}")));

-  app_data.set_brand_code(_T("GOOG"));

-  app_data.set_client_id(_T("otherclient"));

-  app_data.set_display_name(_T("UnitTest"));

-  app_data.set_browser_type(BROWSER_DEFAULT);

-  app_data.set_install_source(_T("install source"));

-  job_->set_app_data(app_data);

-  set_job_state(JOBSTATE_COMPLETED);

-

-  // Call the test method.

-  ASSERT_SUCCEEDED(UpdateJob());

-

-  // Check the results.

-  reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENT_STATE, app_guid);

-  CString version;

-  EXPECT_HRESULT_FAILED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                         kRegValueProductVersion,

-                                         &version));

-

-  // The job's information should have been changed.

-  EXPECT_STREQ(expected_version, job_->app_data().version());

-  EXPECT_STREQ(previous_version, job_->app_data().previous_version());

-

-  RestoreRegistryHives();

-  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-

-// The use of kGoogleUpdateAppId is the key to this test.

-// Overrides the registry hives.

-TEST_F(JobTest, Install_UpdateOmahaSucceeds) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);

-

-  CString arguments;

-  arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi"));

-

-  AppData app_data(kGoopdateGuid, is_machine_);

-  job_->set_download_file_name(kJobExecutable);

-  job_->set_app_data(app_data);

-  SetUpdateResponseDataArguments(arguments);

-

-  CString expected_version(_T("0.9.69.5"));

-  CString expected_lang(_T("en"));

-

-  // Because we don't actually run the Omaha installer, we need to make sure

-  // its Clients key and pv value exist to avoid an error.

-  ASSERT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENTS_GOOPDATE));

-  ASSERT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS_GOOPDATE));

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,

-                                            kRegValueProductVersion,

-                                            expected_version));

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,

-                                            kRegValueLanguage,

-                                            expected_lang));

-

-  ASSERT_FALSE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));

-

-  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);

-  EXPECT_HRESULT_SUCCEEDED(job_->Install());

-

-  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());

-

-  EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status);

-  EXPECT_EQ(S_OK, job_->info().error_code);

-  // The user never sees this, but it is odd we put this text in the structure.

-  EXPECT_STREQ(_T("Thanks for installing ."), job_->info().text);

-

-  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS_GOOPDATE));

-  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));

-

-  CString version;

-  EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                            kRegValueProductVersion,

-                                            &version));

-  EXPECT_STREQ(expected_version, version);

-

-  RestoreRegistryHives();

-  ASSERT_HRESULT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-// Update values should not be changed because we do not know whether

-// self-updates have succeeded yet.

-// Successful update and check values are not changed either.

-TEST_F(JobTest, Install_SuccessfulOmahaUpdateDoesNotClearUpdateAvailableStats) {

-  is_machine_ = false;

-

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);

-

-  CString arguments;

-  arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi"));

-

-  AppData app_data(kGoopdateGuid, is_machine_);

-  job_->set_download_file_name(kJobExecutable);

-  job_->set_app_data(app_data);

-  SetUpdateResponseDataArguments(arguments);

-

-  CString expected_version(_T("0.9.69.5"));

-  CString expected_lang(_T("en"));

-

-  // Because we don't actually run the Omaha installer, we need to make sure

-  // its Clients key and pv value exist to avoid an error.

-  ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENTS_GOOPDATE));

-  ASSERT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                            kRegValueProductVersion,

-                                            expected_version));

-  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                            kRegValueLanguage,

-                                            expected_lang));

-

-  // Set update values so we can verify they are not modified or deleted.

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(123456)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(9876543210)));

-  const DWORD kExistingUpdateValues = 0x70123456;

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-

-  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);

-  EXPECT_HRESULT_SUCCEEDED(job_->Install());

-

-  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());

-

-  EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status);

-  EXPECT_EQ(S_OK, job_->info().error_code);

-  // The user never sees this, but it is odd we put this text in the structure.

-  EXPECT_STREQ(_T("Thanks for installing ."), job_->info().text);

-

-  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));

-  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENT_STATE_GOOPDATE));

-

-  CString version;

-  EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                            kRegValueProductVersion,

-                                            &version));

-  EXPECT_STREQ(expected_version, version);

-

-  DWORD update_available_count(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("UpdateAvailableCount"),

-                                    &update_available_count));

-  EXPECT_EQ(123456, update_available_count);

-

-  DWORD64 update_available_since_time(0);

-  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("UpdateAvailableSince"),

-                                    &update_available_since_time));

-  EXPECT_EQ(9876543210, update_available_since_time);

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                          kRegValueLastSuccessfulCheckSec));

-  EXPECT_EQ(kExistingUpdateValues,

-            GetDwordValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                          kRegValueLastUpdateTimeSec));

-

-  RestoreRegistryHives();

-  ASSERT_HRESULT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-TEST_F(JobTest, GetInstallerData) {

-  UpdateResponses responses;

-  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                    _T("server_manifest.xml")));

-  GUID guid = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}"));

-

-  const TCHAR* kVerboseLog = _T("\n  {\n    \"distribution\": {\n      ")

-                             _T("\"verbose_logging\": true\n    }\n  }\n  ");

-  const TCHAR* kSkipFirstRun = _T("{\n    \"distribution\": {\n      \"")

-                               _T("skip_first_run_ui\": true,\n    }\n  }\n  ");

-  CString skip_first_run_encoded;

-  EXPECT_SUCCEEDED(WideStringToUtf8UrlEncodedString(kSkipFirstRun,

-                                                    &skip_first_run_encoded));

-

-  ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(file_name, &responses));

-  UpdateResponseData response_data = responses[guid].update_response_data();

-  job_->set_update_response_data(response_data);

-

-  // Only set install_data_index to a valid value.

-  AppData app_data1(guid, is_machine_);

-  app_data1.set_install_data_index(_T("verboselogging"));

-  job_->set_app_data(app_data1);

-

-  CString installer_data1;

-  EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data1));

-  EXPECT_STREQ(kVerboseLog, installer_data1);

-

-  // Set both installer_data and install_data_index to valid values.

-  AppData app_data2(guid, is_machine_);

-  app_data2.set_encoded_installer_data(skip_first_run_encoded);

-  app_data2.set_install_data_index(_T("verboselogging"));

-  job_->set_app_data(app_data2);

-

-  CString installer_data2;

-  EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data2));

-  EXPECT_STREQ(kSkipFirstRun, installer_data2);

-

-  // Set installer_data to invalid value, and install_data_index to valid value.

-  AppData app_data3(guid, is_machine_);

-  app_data3.set_encoded_installer_data(_T("%20%20"));

-  app_data3.set_install_data_index(_T("verboselogging"));

-  job_->set_app_data(app_data3);

-

-  CString installer_data3;

-  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS,

-            job_->GetInstallerData(&installer_data3));

-

-  // Set installer_data to valid value, and install_data_index to invalid value.

-  AppData app_data4(guid, is_machine_);

-  app_data4.set_encoded_installer_data(skip_first_run_encoded);

-  app_data4.set_install_data_index(_T("foobar"));

-  job_->set_app_data(app_data4);

-

-  CString installer_data4;

-  EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data4));

-  EXPECT_STREQ(kSkipFirstRun, installer_data4);

-

-  // Set only install_data_index to invalid value.

-  AppData app_data5(guid, is_machine_);

-  app_data5.set_install_data_index(_T("foobar"));

-  job_->set_app_data(app_data5);

-

-  CString installer_data5;

-  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALL_DATA_INDEX,

-            job_->GetInstallerData(&installer_data5));

-

-  // Set neither installer_data nor install_data_index.

-  AppData app_data6(guid, is_machine_);

-  job_->set_app_data(app_data6);

-

-  CString installer_data6;

-  EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data6));

-  EXPECT_TRUE(installer_data6.IsEmpty());

-}

-

-// It would be nice if the Foo installer actually used the installer data as a

-// way to verify the data file is passed correctly. Alternatively, we could mock

-// the installer execution.

-TEST_F(JobInstallFooTest, InstallerData_ValidIndex) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  UpdateResponses responses;

-  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),

-                                    _T("server_manifest.xml")));

-  GUID guid = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}"));

-

-  ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(file_name, &responses));

-  UpdateResponseData response_data = responses[guid].update_response_data();

-  job_->set_update_response_data(response_data);

-

-  AppData app_data(PopulateFooAppData());

-  app_data.set_install_data_index(_T("verboselogging"));

-  job_->set_download_file_name(foo_installer_path_);

-  job_->set_app_data(app_data);

-

-  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);

-  EXPECT_HRESULT_SUCCEEDED(job_->Install());

-

-  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());

-

-  EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status);

-  EXPECT_EQ(S_OK, job_->info().error_code);

-  EXPECT_STREQ(_T("Thanks for installing Foo."), job_->info().text);

-}

-

-// Set installer_data to invalid value, and install_data_index to valid value.

-TEST_F(JobInstallFooTest, InstallerData_InvalidData) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  AppData app_data(PopulateFooAppData());

-  app_data.set_encoded_installer_data(_T("%20%20"));

-  app_data.set_install_data_index(_T("verboselogging"));

-  job_->set_app_data(app_data);

-

-  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);

-  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS, job_->Install());

-

-  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());

-

-  EXPECT_EQ(COMPLETION_ERROR, job_->info().status);

-  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS,

-            job_->info().error_code);

-  EXPECT_STREQ(

-      _T("Installation failed. Please try again. Error code = 0x8004090a"),

-      job_->info().text);

-}

-

-TEST_F(JobInstallFooTest, InstallerData_NonExistentIndex) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  AppData app_data(PopulateFooAppData());

-  app_data.set_install_data_index(_T("foobar"));

-  job_->set_app_data(app_data);

-

-  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);

-  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALL_DATA_INDEX, job_->Install());

-

-  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());

-

-  EXPECT_EQ(COMPLETION_ERROR, job_->info().status);

-  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALL_DATA_INDEX, job_->info().error_code);

-  EXPECT_STREQ(

-      _T("Installation failed. Please try again. Error code = 0x80040909"),

-      job_->info().text);

-}

-

-/*

-// TODO(omaha): Adapt into a test for SendStateChangePing by mocking ping.

-TEST_F(JobTest, BuildPingRequestFromJob_PopulatesAppRequest) {

-  const TCHAR* const kGuid = _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");

-  AppData app_data(StringToGuid(kGuid), true);

-  CreateTestAppData(&app_data);

-  job_->set_app_data(app_data);

-  set_job_state(JOBSTATE_COMPLETED);

-

-  CompletionInfo info(COMPLETION_INSTALLER_ERROR_MSI, 0x12345678, _T("foo"));

-  set_info(info);

-

-  Request req(true);

-  BuildPingRequestFromJob(&req);

-  ASSERT_EQ(1, req.get_app_count());

-

-  const AppRequest* app_request = req.GetApp(StringToGuid(kGuid));

-  EXPECT_STREQ(_T("{21CD0965-0B0E-47CF-B421-2D191C16C0E2}"),

-               GuidToString(app_request->guid()));

-  EXPECT_EQ(_T("1.1.1.3"), app_request->version());

-  EXPECT_EQ(_T("abc"), app_request->language());

-  EXPECT_EQ(AppData::ACTIVE_UNKNOWN, app_request->active());

-  EXPECT_TRUE(app_request->tag().IsEmpty());

-  EXPECT_STREQ(_T("{F723495F-8ACF-4746-824D-643741C797B5}"),

-               GuidToString(app_request->installation_id()));

-  EXPECT_EQ(_T("GOOG"), app_request->brand_code());

-  EXPECT_EQ(_T("someclient"), app_request->client_id());

-  EXPECT_EQ(_T("twoclick"), app_request->install_source());

-

-  ASSERT_TRUE(app_request->events_end() == ++app_request->events_begin());

-  const AppEvent* app_event = *app_request->events_begin();

-  EXPECT_EQ(AppEvent::EVENT_UPDATE_COMPLETE, app_event->event_type());

-  EXPECT_EQ(AppEvent::EVENT_RESULT_INSTALLER_ERROR_MSI,

-            app_event->event_result());

-  EXPECT_EQ(0x12345678, app_event->error_code());

-  EXPECT_EQ(0, app_event->extra_code1());

-  EXPECT_EQ(_T("1.0.0.0"), app_event->previous_version());

-}

-

-// TODO(omaha): Adapt into a test for CreateRequestFromProducts

-TEST_F(JobTest, BuildRequest_PopulatesAppRequest) {

-  const TCHAR* const kGuid = _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");

-  AppData app_data(StringToGuid(kGuid), true);

-  CreateTestAppData(&app_data);

-  job_->set_app_data(app_data);

-

-  Request req(true);

-  ASSERT_SUCCEEDED(job_->BuildRequest(&req));

-  ASSERT_EQ(1, req.get_app_count());

-

-  const AppRequest* app_request = req.GetApp(StringToGuid(kGuid));

-  EXPECT_STREQ(_T("{21CD0965-0B0E-47CF-B421-2D191C16C0E2}"),

-               GuidToString(app_request->guid()));

-  EXPECT_EQ(_T("1.1.1.3"), app_request->version());

-  EXPECT_EQ(_T("abc"), app_request->language());

-  EXPECT_EQ(AppData::ACTIVE_RUN, app_request->active());

-  EXPECT_EQ(_T("Test ap"), app_request->tag());

-  EXPECT_STREQ(_T("{F723495F-8ACF-4746-824D-643741C797B5}"),

-               GuidToString(app_request->installation_id()));

-  EXPECT_EQ(_T("GOOG"), app_request->brand_code());

-  EXPECT_EQ(_T("someclient"), app_request->client_id());

-  EXPECT_EQ(_T("twoclick"), app_request->install_source());

-}

-

-// TODO(omaha): Move to some other test file.

-TEST(RequestTest, TestInitialized) {

-  AppRequest app_request;

-  EXPECT_TRUE(::IsEqualGUID(GUID_NULL, app_request.guid()));

-  EXPECT_TRUE(app_request.version().IsEmpty());

-  EXPECT_TRUE(app_request.language().IsEmpty());

-  EXPECT_EQ(AppData::ACTIVE_UNKNOWN, app_request.active());

-  EXPECT_TRUE(app_request.tag().IsEmpty());

-  EXPECT_TRUE(::IsEqualGUID(GUID_NULL, app_request.installation_id()));

-  EXPECT_TRUE(app_request.brand_code().IsEmpty());

-  EXPECT_TRUE(app_request.client_id().IsEmpty());

-  EXPECT_TRUE(app_request.install_source().IsEmpty());

-}

-*/

-

-void JobInstallFooTest::Install_MsiInstallerSucceeds(bool is_update,

-                                                     bool is_first_install,

-                                                     bool is_offline) {

-  ASSERT_TRUE(!is_update || !is_offline);

-

-  const DWORD kExistingUpdateValues = 0x70123456;

-

-  // TODO(omaha): Use UserFoo instead, change is_machine in the base class,

-  // and remove all IsUserAdmin checks.

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-#ifdef _DEBUG

-  if (!is_update) {

-    // Event::WriteEvent() expects Omaha's version to exist.

-    // Write it if it doesn't exist.

-    ConfigManager& config_mgr = *ConfigManager::Instance();

-    CString key_name = config_mgr.registry_clients_goopdate(is_machine_);

-    if (!RegKey::HasValue(key_name, kRegValueLanguage)) {

-      EXPECT_HRESULT_SUCCEEDED(

-          RegKey::SetValue(key_name, kRegValueLanguage, _T("it")));

-    }

-    if (!RegKey::HasValue(key_name, kRegValueProductVersion)) {

-      EXPECT_HRESULT_SUCCEEDED(

-          RegKey::SetValue(key_name, kRegValueProductVersion, _T("0.1.0.0")));

-    }

-  }

-#endif

-

-  if (!is_update) {

-    SetIsInstallJob();

-  }

-

-  if (!is_first_install) {

-    // Make it appear to Omaha that Foo was already installed. This does not

-    // affect the installer.

-    EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,

-                                              kRegValueBrandCode,

-                                              _T("g00g")));

-

-    // Set update available stats so can verify they are deleted.

-    EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,

-                                      _T("UpdateAvailableCount"),

-                                      static_cast<DWORD>(123456)));

-    EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,

-                                      _T("UpdateAvailableSince"),

-                                      static_cast<DWORD64>(9876543210)));

-    EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,

-                                      kRegValueLastSuccessfulCheckSec,

-                                      kExistingUpdateValues));

-    EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,

-                                      kRegValueLastUpdateTimeSec,

-                                      kExistingUpdateValues));

-  }

-

-  job_->set_is_offline(is_offline);

-

-  AppData app_data(PopulateFooAppData());

-  job_->set_download_file_name(foo_installer_path_);

-  job_->set_app_data(app_data);

-

-  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);

-  EXPECT_HRESULT_SUCCEEDED(job_->Install());

-  const uint32 now = Time64ToInt32(GetCurrent100NSTime());

-

-  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());

-

-  EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status);

-  EXPECT_EQ(S_OK, job_->info().error_code);

-  EXPECT_STREQ(_T("Thanks for installing Foo."), job_->info().text);

-

-  EXPECT_TRUE(File::Exists(foo_installer_log_path_));

-

-  EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientKeyPath));

-  EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientStateKeyPath));

-

-  if (is_update) {

-    VerifyFooClientStateValuesWrittenBeforeInstallNotPresent(!is_first_install);

-  } else {

-    VerifyFooClientStateValuesWrittenBeforeInstall(is_first_install);

-  }

-  VerifyFooClientStateValuesWrittenAfterSuccessfulInstall();

-

-  EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,

-                                _T("UpdateAvailableCount")));

-  EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,

-                                _T("UpdateAvailableSince")));

-  if (is_update) {

-    // Verify update values updated.

-    const uint32 last_check_sec =

-        GetDwordValue(kFullFooAppClientStateKeyPath,

-                      kRegValueLastSuccessfulCheckSec);

-    EXPECT_NE(kExistingUpdateValues, last_check_sec);

-    EXPECT_GE(now, last_check_sec);

-    EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);

-

-    const uint32 last_update_sec = GetDwordValue(kFullFooAppClientStateKeyPath,

-                                                 kRegValueLastUpdateTimeSec);

-    EXPECT_NE(kExistingUpdateValues, last_update_sec);

-    EXPECT_GE(now, last_update_sec);

-    EXPECT_GE(static_cast<uint32>(200), now - last_update_sec);

-  } else {

-    // LastSuccessfulCheckSec is written for online installs but never cleared.

-    if (!is_offline) {

-      const uint32 last_check_sec =

-          GetDwordValue(kFullFooAppClientStateKeyPath,

-                        kRegValueLastSuccessfulCheckSec);

-      EXPECT_NE(kExistingUpdateValues, last_check_sec);

-      EXPECT_GE(now, last_check_sec);

-      EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);

-    } else if (!is_first_install) {

-      EXPECT_EQ(kExistingUpdateValues,

-                GetDwordValue(kFullFooAppClientStateKeyPath,

-                              kRegValueLastSuccessfulCheckSec));

-    } else {

-      EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,

-                                    kRegValueLastSuccessfulCheckSec));

-    }

-

-    // kRegValueLastUpdateTimeSec is never written for installs.

-    if (!is_first_install) {

-      EXPECT_EQ(kExistingUpdateValues,

-                GetDwordValue(kFullFooAppClientStateKeyPath,

-                              kRegValueLastUpdateTimeSec));

-    } else {

-      EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,

-                                    kRegValueLastUpdateTimeSec));

-    }

-  }

-

-  CString uninstall_arguments;

-  uninstall_arguments.Format(kMsiUninstallArguments, foo_installer_path_);

-  EXPECT_HRESULT_SUCCEEDED(System::ShellExecuteProcess(kMsiCommand,

-                                                       uninstall_arguments,

-                                                       NULL,

-                                                       NULL));

-}

-

-TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_FirstInstall_Online) {

-  Install_MsiInstallerSucceeds(false, true, false);

-}

-

-TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_OverInstall_Online) {

-  Install_MsiInstallerSucceeds(false, false, false);

-}

-

-TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_FirstInstall_Offline) {

-  Install_MsiInstallerSucceeds(false, true, true);

-}

-

-TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_OverInstall_Offline) {

-  Install_MsiInstallerSucceeds(false, false, true);

-}

-

-TEST_F(JobInstallFooTest,

-       Install_MsiInstallerSucceeds_UpdateWhenNoExistingPreInstallData) {

-  // AppManager::ClearUpdateAvailableStats() asserts that key open succeeds.

-  EXPECT_SUCCEEDED(RegKey::CreateKey(kFullFooAppClientStateKeyPath));

-  Install_MsiInstallerSucceeds(true, true, false);

-}

-

-TEST_F(JobInstallFooTest,

-       Install_MsiInstallerSucceeds_UpdateWhenExistingPreInstallData) {

-  Install_MsiInstallerSucceeds(true, false, false);

-}

-

-

-void JobInstallFooTest::Install_InstallerFailed_WhenNoExistingPreInstallData(

-    bool is_update) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  if (!is_update) {

-    SetIsInstallJob();

-  }

-

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);

-#ifdef _DEBUG

-  // Event::WriteEvent() expects Omaha's language and version to exist.

-  ConfigManager& config_mgr = *ConfigManager::Instance();

-  CString key_name = config_mgr.registry_clients_goopdate(is_machine_);

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(key_name, kRegValueLanguage, _T("it")));

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(key_name, kRegValueProductVersion, _T("0.1.2.3")));

-#endif

-

-  AppData app_data(PopulateFooAppData());

-  job_->set_download_file_name(_T("DoesNotExist.exe"));

-  job_->set_app_data(app_data);

-

-  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->Install());

-

-  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());

-

-  EXPECT_EQ(COMPLETION_ERROR, job_->info().status);

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->info().error_code);

-  EXPECT_STREQ(_T("The installer failed to start."), job_->info().text);

-

-  EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath));

-  EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));

-

-  // TODO(omaha): Install the job successfully and verify that the brand data

-  // is replaced by the successful install.

-

-  RestoreRegistryHives();

-  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-// Overrides the registry hives.

-TEST_F(JobInstallFooTest,

-       Install_InstallerFailedFirstInstall_WhenNoExistingPreInstallData) {

-  Install_InstallerFailed_WhenNoExistingPreInstallData(false);

-}

-

-TEST_F(JobInstallFooTest,

-       Install_InstallerFailedUpdate_WhenNoExistingPreInstallData) {

-  Install_InstallerFailed_WhenNoExistingPreInstallData(true);

-}

-

-void JobInstallFooTest::Install_InstallerFailed_WhenExistingPreInstallData(

-    bool is_update) {

-  if (!vista_util::IsUserAdmin()) {

-    std::wcout << _T("\tTest did not run because the user is not an admin.")

-               << std::endl;

-    return;

-  }

-

-  if (!is_update) {

-    SetIsInstallJob();

-  }

-

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);

-  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);

-

-#ifdef _DEBUG

-  // Event::WriteEvent() expects Omaha's language and version to exist.

-  ConfigManager& config_mgr = *ConfigManager::Instance();

-  CString key_name = config_mgr.registry_clients_goopdate(is_machine_);

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(key_name, kRegValueLanguage, _T("it")));

-  EXPECT_HRESULT_SUCCEEDED(

-      RegKey::SetValue(key_name, kRegValueProductVersion, _T("0.1.2.3")));

-#endif

-

-  // Prepopulate data for this app in the ClientState registry

-  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,

-                                            kRegValueProductVersion,

-                                            _T("0.1.2.3")));

-

-  // Set update available stats so can verify they are not modified or deleted.

-  EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(123456)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(9876543210)));

-  const DWORD kExistingUpdateValues = 0x70123456;

-  EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,

-                                    kRegValueLastSuccessfulCheckSec,

-                                    kExistingUpdateValues));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,

-                                    kRegValueLastUpdateTimeSec,

-                                    kExistingUpdateValues));

-

-  AppData app_data(PopulateFooAppData());

-  job_->set_download_file_name(_T("DoesNotExist.exe"));

-  job_->set_app_data(app_data);

-

-  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->Install());

-

-  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());

-

-  EXPECT_EQ(COMPLETION_ERROR, job_->info().status);

-  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->info().error_code);

-  EXPECT_STREQ(_T("The installer failed to start."), job_->info().text);

-

-  EXPECT_EQ(is_update, RegKey::HasKey(kFullFooAppClientStateKeyPath));

-  EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath));

-

-  // When an update fails, data remains. When an install fails, the entire

-  // ClientState key is deleted as verified above.

-  if (is_update) {

-    DWORD update_available_count(0);

-    EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                      _T("UpdateAvailableCount"),

-                                      &update_available_count));

-    EXPECT_EQ(123456, update_available_count);

-

-    DWORD64 update_available_since_time(0);

-    EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,

-                                      _T("UpdateAvailableSince"),

-                                      &update_available_since_time));

-    EXPECT_EQ(9876543210, update_available_since_time);

-    EXPECT_EQ(kExistingUpdateValues,

-              GetDwordValue(kFullFooAppClientStateKeyPath,

-                            kRegValueLastSuccessfulCheckSec));

-    EXPECT_EQ(kExistingUpdateValues,

-              GetDwordValue(kFullFooAppClientStateKeyPath,

-                            kRegValueLastUpdateTimeSec));

-  }

-

-  RestoreRegistryHives();

-  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));

-}

-

-TEST_F(JobInstallFooTest,

-       Install_InstallerFailedFirstInstall_WhenExistingPreInstallData) {

-  Install_InstallerFailed_WhenExistingPreInstallData(false);

-}

-

-TEST_F(JobInstallFooTest,

-       Install_InstallerFailedUpdate_WhenExistingPreInstallData) {

-  Install_InstallerFailed_WhenExistingPreInstallData(true);

-}

-

-TEST_F(JobTest, LaunchCmdLine_EmptyCommand) {

-  SetIsInstallJob();

-  EXPECT_SUCCEEDED(job_->LaunchCmdLine());

-  EXPECT_FALSE(did_launch_cmd_fail());

-}

-

-TEST_F(JobTest, LaunchCmdLine_LaunchFails) {

-  SetIsInstallJob();

-  set_launch_cmd_line(_T("no_such_file.exe"));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), job_->LaunchCmdLine());

-  EXPECT_TRUE(did_launch_cmd_fail());

-}

-

-TEST_F(JobTest, LaunchCmdLine_Succeeds) {

-  SetIsInstallJob();

-  set_launch_cmd_line(_T("cmd /c"));

-  EXPECT_SUCCEEDED(job_->LaunchCmdLine());

-  EXPECT_FALSE(did_launch_cmd_fail());

-}

-

-// LaunchCmdLine should not be called for update jobs.

-TEST_F(JobTest, LaunchCmdLine_IsUpdateJob) {

-  ExpectAsserts expect_asserts;

-  set_launch_cmd_line(_T("cmd /c"));

-  EXPECT_SUCCEEDED(job_->LaunchCmdLine());

-  EXPECT_FALSE(did_launch_cmd_fail());

-}

-

-class JobDoCompleteJobJobSuccessTest : public JobTest {

- protected:

-  virtual void SetUp() {

-    JobTest::SetUp();

-

-    destination_path_ = CreateUniqueTempDir();

-    set_download_file_name(ConcatenatePath(destination_path_, _T("foo.msi")));

-    job_->set_job_observer(&job_observer_);

-

-    CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));

-    set_info(info);

-  }

-

-  CString destination_path_;

-  JobObserverMock job_observer_;

-};

-

-TEST_F(JobDoCompleteJobJobSuccessTest, DefaultSuccessAction) {

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);

-  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());

-  EXPECT_EQ(0, job_observer_.completion_error_code);

-

-  EXPECT_FALSE(File::Exists(destination_path_));

-}

-

-// download_file_name_ is not set. No assert indicates that

-// DeleteJobDownloadDirectory is not called in error cases.

-TEST_F(JobTest, DefaultSuccessAction_Omaha) {

-  JobObserverMock job_observer;

-  job_->set_job_observer(&job_observer);

-

-  CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));

-  set_info(info);

-

-  AppData app_data;

-  app_data.set_app_guid(kGoopdateGuid);

-  SetAppData(app_data);

-

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer.completion_code);

-  EXPECT_TRUE(job_observer.completion_text.IsEmpty());

-  EXPECT_EQ(0, job_observer.completion_error_code);

-}

-

-TEST_F(JobDoCompleteJobJobSuccessTest,

-       DefaultSuccessAction_LaunchCmdNotFailed) {

-  SetIsInstallJob();

-

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);

-  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());

-  EXPECT_EQ(0, job_observer_.completion_error_code);

-}

-

-TEST_F(JobDoCompleteJobJobSuccessTest,

-       DefaultSuccessAction_LaunchCmdFailed) {

-  SetIsInstallJob();

-  set_did_launch_cmd_fail(true);

-

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);

-  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());

-  EXPECT_EQ(0, job_observer_.completion_error_code);

-}

-

-TEST_F(JobDoCompleteJobJobSuccessTest,

-       SuccessActionExitSilently_NoLaunchCmd) {

-  SetIsInstallJob();

-  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY);

-

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_SUCCESS_CLOSE_UI, job_observer_.completion_code);

-  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());

-  EXPECT_EQ(0, job_observer_.completion_error_code);

-}

-

-TEST_F(JobDoCompleteJobJobSuccessTest,

-       SuccessActionExitSilently_LaunchCmdNotFailed) {

-  SetIsInstallJob();

-  set_launch_cmd_line(_T("cmd /c"));

-  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY);

-

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_SUCCESS_CLOSE_UI, job_observer_.completion_code);

-  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());

-  EXPECT_EQ(0, job_observer_.completion_error_code);

-}

-

-TEST_F(JobDoCompleteJobJobSuccessTest,

-       SuccessActionExitSilently_LaunchCmdFailed) {

-  SetIsInstallJob();

-  set_launch_cmd_line(_T("cmd /c"));

-  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY);

-  set_did_launch_cmd_fail(true);

-

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);

-  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());

-  EXPECT_EQ(0, job_observer_.completion_error_code);

-}

-

-TEST_F(JobDoCompleteJobJobSuccessTest,

-       SuccessActionExitSilentlyOnCmd_NoLaunchCmd) {

-  SetIsInstallJob();

-  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD);

-

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);

-  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());

-  EXPECT_EQ(0, job_observer_.completion_error_code);

-}

-

-TEST_F(JobDoCompleteJobJobSuccessTest,

-       SuccessActionExitSilentlyOnCmd_CmdNotFailed) {

-  SetIsInstallJob();

-  set_launch_cmd_line(_T("cmd /c"));

-  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD);

-

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_SUCCESS_CLOSE_UI, job_observer_.completion_code);

-  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());

-  EXPECT_EQ(0, job_observer_.completion_error_code);

-}

-

-TEST_F(JobDoCompleteJobJobSuccessTest,

-       DefaultSuccessActionOnCmd_LaunchCmdFailed) {

-  SetIsInstallJob();

-  set_launch_cmd_line(_T("cmd /c"));

-  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD);

-  set_did_launch_cmd_fail(true);

-

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);

-  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());

-  EXPECT_EQ(0, job_observer_.completion_error_code);

-}

-

-// download_file_name_ is not set. No assert indicates that

-// DeleteJobDownloadDirectory is not called in error cases.

-TEST_F(JobTest, DoCompleteJob_JobError) {

-  JobObserverMock job_observer_;

-  job_->set_job_observer(&job_observer_);

-  CompletionInfo info(COMPLETION_ERROR, static_cast<DWORD>(E_FAIL), _T("blah"));

-  set_info(info);

-

-  EXPECT_SUCCEEDED(DoCompleteJob());

-

-  EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer_.completion_code);

-  EXPECT_STREQ(_T("blah"), job_observer_.completion_text);

-  EXPECT_EQ(E_FAIL, job_observer_.completion_error_code);

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/app_util.h"
+#include "omaha/common/error.h"
+#include "omaha/common/file.h"
+#include "omaha/common/path.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/system.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/goopdate_xml_parser.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/application_manager.h"
+#include "omaha/worker/job.h"
+#include "omaha/worker/job_observer_mock.h"
+#include "omaha/worker/ping.h"
+
+namespace omaha {
+
+namespace {
+
+/*
+void CreateTestAppData(AppData* app_data) {
+  ASSERT_TRUE(app_data != NULL);
+  app_data->set_version(_T("1.1.1.3"));
+  app_data->set_previous_version(_T("1.0.0.0"));
+  app_data->set_language(_T("abc"));
+  app_data->set_ap(_T("Test ap"));
+  app_data->set_tt_token(_T("Test TT Token"));
+  app_data->set_iid(StringToGuid(_T("{F723495F-8ACF-4746-824d-643741C797B5}")));
+  app_data->set_brand_code(_T("GOOG"));
+  app_data->set_client_id(_T("someclient"));
+  app_data->set_did_run(AppData::ACTIVE_RUN);
+  app_data->set_install_source(_T("twoclick"));
+}
+*/
+
+const TCHAR kFooGuid[] = _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");
+const TCHAR kFullFooAppClientKeyPath[] =
+    _T("HKLM\\Software\\Google\\Update\\Clients\\")
+    _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");
+const TCHAR kFullFooAppClientStateKeyPath[] =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\")
+    _T("{D6B08267-B440-4C85-9F79-E195E80D9937}");
+const TCHAR kSetupFooV1RelativeLocation[] =
+    _T("unittest_support\\test_foo_v1.0.101.0.msi");
+
+const TCHAR kMsiLogFormat[] = _T("%s.log");
+const TCHAR kMsiUninstallArguments[] = _T("/quiet /uninstall %s");
+const TCHAR kMsiCommand[] = _T("msiexec");
+
+const TCHAR kJobExecutable[] = _T("cmd.exe");
+const TCHAR kExecuteCommandAndTerminateSwitch[] = _T("/c %s");
+
+const TCHAR expected_iid_string[] =
+    _T("{BF66411E-8FAC-4E2C-920C-849DF562621C}");
+
+CString CreateUniqueTempDir() {
+  GUID guid(GUID_NULL);
+  EXPECT_HRESULT_SUCCEEDED(::CoCreateGuid(&guid));
+  CString unique_dir_path =
+      ConcatenatePath(app_util::GetTempDir(), GuidToString(guid));
+  EXPECT_HRESULT_SUCCEEDED(CreateDir(unique_dir_path, NULL));
+  return unique_dir_path;
+}
+
+}  // namespace
+
+class JobTest : public testing::Test {
+ protected:
+  JobTest() : is_machine_(true) {}
+
+  void SetUp() {
+    // Default to an auto-update job.
+    job_.reset(new Job(true, &ping_));
+    job_->is_background_ = true;
+  }
+
+  void set_info(const CompletionInfo& info) {
+    job_->info_ = info;
+  }
+
+  void set_job_state(JobState job_state) {
+    job_->job_state_ = job_state;
+  }
+
+  void SetIsInstallJob() {
+    job_->is_update_ = false;
+    job_->is_background_ = false;
+  }
+
+  HRESULT DoCompleteJob() {
+    return job_->DoCompleteJob();
+  }
+
+  HRESULT SendStateChangePing(JobState previous_state) {
+    return job_->SendStateChangePing(previous_state);
+  }
+
+  void SetUpdateResponseDataArguments(const CString& arguments) {
+    job_->update_response_data_.set_arguments(arguments);
+  }
+
+  void SetUpdateResponseSuccessAction(SuccessfulInstallAction success_action) {
+    job_->update_response_data_.set_success_action(success_action);
+  }
+
+  void SetAppData(const AppData& app_data) {
+    job_->set_app_data(app_data);
+  }
+
+  void set_download_file_name(const CString& download_file) {
+    job_->download_file_name_ = download_file;
+  }
+
+  HRESULT UpdateRegistry(AppData* data) {
+    return job_->UpdateRegistry(data);
+  }
+
+  HRESULT UpdateJob() {
+    return job_->UpdateJob();
+  }
+
+  HRESULT DeleteJobDownloadDirectory() const {
+    return job_->DeleteJobDownloadDirectory();
+  }
+
+  void set_launch_cmd_line(const CString launch_cmd_line) {
+    job_->launch_cmd_line_ = launch_cmd_line;
+  }
+
+  bool did_launch_cmd_fail() { return job_->did_launch_cmd_fail_; }
+  void set_did_launch_cmd_fail(bool did_launch_cmd_fail) {
+    job_->did_launch_cmd_fail_ = did_launch_cmd_fail;
+  }
+
+  scoped_ptr<Job> job_;
+  Ping ping_;
+  bool is_machine_;
+};
+
+// Does not override registry hives because it would not affect the installer.
+class JobInstallFooTest : public JobTest {
+ protected:
+  virtual void SetUp() {
+    JobTest::SetUp();
+
+    foo_installer_path_ = ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                          kSetupFooV1RelativeLocation);
+    ASSERT_TRUE(File::Exists(foo_installer_path_));
+
+    foo_installer_log_path_.Format(kMsiLogFormat, foo_installer_path_);
+
+    ASSERT_HRESULT_SUCCEEDED(File::Remove(foo_installer_log_path_));
+    ASSERT_FALSE(File::Exists(foo_installer_log_path_));
+
+    RegKey::DeleteKey(kFullFooAppClientKeyPath);
+    ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath));
+    RegKey::DeleteKey(kFullFooAppClientStateKeyPath);
+    ASSERT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));
+  }
+
+  virtual void TearDown() {
+    RegKey::DeleteKey(kFullFooAppClientKeyPath);
+    RegKey::DeleteKey(kFullFooAppClientStateKeyPath);
+  }
+
+  AppData PopulateFooAppData() {
+    AppData app_data(StringToGuid(kFooGuid), is_machine_);
+    app_data.set_display_name(_T("Foo"));
+    app_data.set_language(_T("en"));
+    app_data.set_ap(_T("test_ap"));
+    app_data.set_iid(StringToGuid(expected_iid_string));
+    app_data.set_brand_code(_T("GOOG"));
+    app_data.set_client_id(_T("_some_partner"));
+    app_data.set_browser_type(BROWSER_IE);
+    app_data.set_usage_stats_enable(TRISTATE_TRUE);
+    return app_data;
+  }
+
+  // Verifies the values that are written to ClientState before installing.
+  // Assumes the is Foo.
+  void VerifyFooClientStateValuesWrittenBeforeInstall(bool is_first_install) {
+    CString str_value;
+    DWORD value;
+
+    if (is_first_install) {
+      EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                                kRegValueBrandCode,
+                                                &str_value));
+      EXPECT_STREQ(_T("GOOG"), str_value);
+      EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                                kRegValueClientId,
+                                                &str_value));
+      EXPECT_STREQ(_T("_some_partner"), str_value);
+      const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+      DWORD install_time(0);
+      EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                        kRegValueInstallTimeSec,
+                                        &install_time));
+      EXPECT_GE(now, install_time);
+      EXPECT_GE(static_cast<uint32>(500), now - install_time);
+    } else {
+      EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                                kRegValueBrandCode,
+                                                &str_value));
+      EXPECT_STREQ(_T("g00g"), str_value);
+      EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,
+                                    kRegValueClientId));
+      EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,
+                                    kRegValueInstallTimeSec));
+    }
+
+    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                              kRegValueAdditionalParams,
+                                              &str_value));
+    EXPECT_STREQ(_T("test_ap"), str_value);
+    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                              kRegValueBrowser,
+                                              &value));
+    EXPECT_EQ(BROWSER_IE, value);
+    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                              _T("usagestats"),
+                                              &value));
+    EXPECT_EQ(TRISTATE_TRUE, value);
+    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                              kRegValueLanguage,
+                                              &str_value));
+    EXPECT_STREQ(_T("en"), str_value);
+  }
+
+  void VerifyFooClientStateValuesWrittenBeforeInstallNotPresent(
+      bool is_brand_code_present) {
+    CString str_value;
+    DWORD value;
+
+    HRESULT hr = RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                  kRegValueBrandCode,
+                                  &str_value);
+    if (is_brand_code_present) {
+      EXPECT_HRESULT_SUCCEEDED(hr);
+    } else {
+      EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), hr);
+    }
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+              RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                               kRegValueClientId,
+                               &str_value));
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+              RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                               kRegValueBrowser,
+                               &value));
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+              RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                               _T("usagestats"),
+                               &value));
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+              RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                               kRegValueLanguage,
+                               &str_value));
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+              RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                               kRegValueAdditionalParams,
+                               &str_value));
+    EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+              RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                               kRegValueTTToken,
+                               &str_value));
+  }
+
+  // Verifies the values that are written to ClientState after successfully
+  // installing. Assumes the is Foo.
+  void VerifyFooClientStateValuesWrittenAfterSuccessfulInstall() {
+    CString str_value;
+    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                              kRegValueProductVersion,
+                                              &str_value));
+    EXPECT_STREQ(_T("1.0.101.0"), str_value);
+    // TODO(omaha): Verify language. Requires changing the MSI. Make sure the
+    // language the MSI writes is different than in PopulateFooAppData().
+    // When we do this, make sure we also have a test where the app does not
+    // write lang in Client to verify that the ClientState value is not erased.
+    EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                              kRegValueInstallationId,
+                                              &str_value));
+    EXPECT_STREQ(expected_iid_string, str_value);
+  }
+
+  void Install_MsiInstallerSucceeds(bool is_update,
+                                    bool is_first_install,
+                                    bool is_offline);
+  void Install_InstallerFailed_WhenNoExistingPreInstallData(bool is_update);
+  void Install_InstallerFailed_WhenExistingPreInstallData(bool is_update);
+
+  CString foo_installer_path_;
+  CString foo_installer_log_path_;
+};
+
+// TODO(omaha): Test all methods of Job
+
+// No attempt is made to delete it the directory in this case.
+TEST_F(JobTest, DeleteJobDownloadDirectory_Omaha_Test) {
+  const TCHAR* kNnonExistantDir = _T("testdirfoo");
+  CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));
+
+  set_info(info);
+  set_download_file_name(ConcatenatePath(kNnonExistantDir, _T("foo.msi")));
+
+  AppData app_data;
+  app_data.set_app_guid(kGoopdateGuid);
+  SetAppData(app_data);
+
+  ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory());
+}
+
+// The download file name is not set and no attempt to delete it is made for
+// update checks only.
+TEST_F(JobTest, DeleteJobDownloadDirectory_OnDemandUpdateCheckOnly) {
+  job_.reset(new Job(true, &ping_));
+  job_->set_is_update_check_only(true);
+
+  CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));
+
+  set_info(info);
+
+  AppData app_data;
+  app_data.set_app_guid(
+      StringToGuid(_T("{55B9A9BD-16FC-4060-B667-892B312CAAA5}")));
+  SetAppData(app_data);
+
+  ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory());
+}
+
+TEST_F(JobTest, DeleteJobDownloadDirectory_OnDemandUpdate) {
+  job_.reset(new Job(true, &ping_));
+
+  CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));
+  set_info(info);
+  const CString destination_path = CreateUniqueTempDir();
+  set_download_file_name(ConcatenatePath(destination_path, _T("foo.msi")));
+
+  AppData app_data;
+  app_data.set_app_guid(
+      StringToGuid(_T("{55B9A9BD-16FC-4060-B667-892B312CAAA5}")));
+  SetAppData(app_data);
+
+  ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory());
+  ASSERT_FALSE(File::Exists(destination_path));
+}
+
+TEST_F(JobTest, DeleteJobDownloadDirectory_Success) {
+  CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));
+  set_info(info);
+  const CString destination_path = CreateUniqueTempDir();
+  set_download_file_name(ConcatenatePath(destination_path, _T("foo.msi")));
+
+  AppData app_data;
+  app_data.set_app_guid(
+      StringToGuid(_T("{55B9A9BD-16FC-4060-B667-892B312CAAA5}")));
+  SetAppData(app_data);
+
+  ASSERT_HRESULT_SUCCEEDED(DeleteJobDownloadDirectory());
+  ASSERT_FALSE(File::Exists(destination_path));
+}
+
+TEST_F(JobTest, SendStateChangePing) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  AppManager app_manager(is_machine_);
+  AppData app_data(StringToGuid(_T("{4F1A02DC-E965-4518-AED4-E15A3E1B1219}")),
+                   is_machine_);
+
+  app_data.set_language(_T("abc"));
+  app_data.set_ap(_T("Test ap"));
+  app_data.set_tt_token(_T("Test TT Token"));
+  app_data.set_iid(StringToGuid(_T("{C16050EA-6D4C-4275-A8EC-22D4C59E942A}")));
+  app_data.set_brand_code(_T("GOOG"));
+  app_data.set_client_id(_T("otherclient"));
+  app_data.set_display_name(_T("UnitTest"));
+  app_data.set_browser_type(BROWSER_DEFAULT);
+  job_->set_app_data(app_data);
+
+  set_job_state(JOBSTATE_INSTALLERSTARTED);
+  ASSERT_SUCCEEDED(SendStateChangePing(JOBSTATE_DOWNLOADCOMPLETED));
+
+  CompletionInfo info(COMPLETION_ERROR, 123, _T(""));
+
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+  OverrideRegistryHives(kRegistryHiveOverrideRoot);
+  CString app_goopdate_key_name = goopdate_utils::GetAppClientsKey(
+      is_machine_,
+      GOOPDATE_APP_ID);
+
+  RegKey goopdate_key;
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(app_goopdate_key_name,
+                                            kRegValueProductVersion,
+                                            _T("1.2.3.4")));
+  job_->NotifyCompleted(info);
+
+  RestoreRegistryHives();
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+  ASSERT_SUCCEEDED(SendStateChangePing(JOBSTATE_INSTALLERSTARTED));
+}
+
+TEST_F(JobTest, UpdateRegistry) {
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);
+
+  CString app_guid = _T("{4F1A02DC-E965-4518-AED4-E15A3E1B1219}");
+  CString expected_version = _T("1.3.3.3");
+  CString previous_version = _T("1.0.0.0");
+  CString expected_lang = _T("abc");
+  CString reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENTS, app_guid);
+  ASSERT_SUCCEEDED(RegKey::CreateKey(reg_key_path));
+  ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path,
+                                    kRegValueProductVersion,
+                                    expected_version));
+  ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path,
+                                    kRegValueLanguage,
+                                    expected_lang));
+
+  AppManager app_manager(is_machine_);
+  AppData app_data(StringToGuid(app_guid), is_machine_);
+  app_data.set_version(expected_version);
+  app_data.set_previous_version(previous_version);
+  app_data.set_language(expected_lang);
+  app_data.set_ap(_T("Test ap"));
+  app_data.set_tt_token(_T("Test TT Token"));
+  app_data.set_iid(StringToGuid(_T("{C16050EA-6D4C-4275-A8EC-22D4C59E942A}")));
+  app_data.set_brand_code(_T("GOOG"));
+  app_data.set_client_id(_T("otherclient"));
+  app_data.set_display_name(_T("UnitTest"));
+  app_data.set_browser_type(BROWSER_DEFAULT);
+  app_data.set_install_source(_T("install source"));
+  job_->set_app_data(app_data);
+  set_job_state(JOBSTATE_COMPLETED);
+
+  // Call the test method.
+  AppData new_app_data;
+  ASSERT_SUCCEEDED(UpdateRegistry(&new_app_data));
+
+  // Check the results.
+  reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENT_STATE, app_guid);
+  ASSERT_SUCCEEDED(RegKey::HasKey(reg_key_path));
+
+  CString actual_previous_version;
+  ASSERT_SUCCEEDED(RegKey::GetValue(reg_key_path,
+                                    kRegValueProductVersion,
+                                    &actual_previous_version));
+  CString actual_lang;
+  ASSERT_SUCCEEDED(RegKey::GetValue(reg_key_path,
+                                    kRegValueLanguage,
+                                    &actual_lang));
+
+  // The client state registry should have been updated.
+  EXPECT_STREQ(expected_version, actual_previous_version);
+  EXPECT_STREQ(expected_lang, actual_lang);
+
+  // The job's previous version should not have changed.
+  EXPECT_STREQ(expected_version, job_->app_data().version());
+  EXPECT_STREQ(previous_version, job_->app_data().previous_version());
+
+  // new_app_data's previous_version should have been updated.
+  EXPECT_STREQ(expected_version, new_app_data.version());
+  EXPECT_STREQ(expected_version, new_app_data.previous_version());
+
+  RestoreRegistryHives();
+  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+TEST_F(JobTest, UpdateJob) {
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);
+
+  CString app_guid = _T("{4F1A02DC-E965-4518-AED4-E15A3E1B1219}");
+  CString expected_version = _T("1.3.3.3");
+  CString previous_version = _T("1.0.0.0");
+  CString expected_lang = _T("abc");
+  CString reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENTS, app_guid);
+  ASSERT_SUCCEEDED(RegKey::CreateKey(reg_key_path));
+  ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path,
+                                    kRegValueProductVersion,
+                                    expected_version));
+  ASSERT_SUCCEEDED(RegKey::SetValue(reg_key_path,
+                                    kRegValueLanguage,
+                                    expected_lang));
+
+  AppManager app_manager(is_machine_);
+  AppData app_data(StringToGuid(app_guid), is_machine_);
+  app_data.set_version(_T("4.5.6.6"));
+  app_data.set_previous_version(previous_version);
+  app_data.set_language(expected_lang);
+  app_data.set_ap(_T("Test ap"));
+  app_data.set_tt_token(_T("Test TT Token"));
+  app_data.set_iid(
+      StringToGuid(_T("{C16050EA-6D4C-4275-A8EC-22D4C59E942A}")));
+  app_data.set_brand_code(_T("GOOG"));
+  app_data.set_client_id(_T("otherclient"));
+  app_data.set_display_name(_T("UnitTest"));
+  app_data.set_browser_type(BROWSER_DEFAULT);
+  app_data.set_install_source(_T("install source"));
+  job_->set_app_data(app_data);
+  set_job_state(JOBSTATE_COMPLETED);
+
+  // Call the test method.
+  ASSERT_SUCCEEDED(UpdateJob());
+
+  // Check the results.
+  reg_key_path = AppendRegKeyPath(MACHINE_REG_CLIENT_STATE, app_guid);
+  CString version;
+  EXPECT_HRESULT_FAILED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                         kRegValueProductVersion,
+                                         &version));
+
+  // The job's information should have been changed.
+  EXPECT_STREQ(expected_version, job_->app_data().version());
+  EXPECT_STREQ(previous_version, job_->app_data().previous_version());
+
+  RestoreRegistryHives();
+  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+
+// The use of kGoogleUpdateAppId is the key to this test.
+// Overrides the registry hives.
+TEST_F(JobTest, Install_UpdateOmahaSucceeds) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);
+
+  CString arguments;
+  arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi"));
+
+  AppData app_data(kGoopdateGuid, is_machine_);
+  job_->set_download_file_name(kJobExecutable);
+  job_->set_app_data(app_data);
+  SetUpdateResponseDataArguments(arguments);
+
+  CString expected_version(_T("0.9.69.5"));
+  CString expected_lang(_T("en"));
+
+  // Because we don't actually run the Omaha installer, we need to make sure
+  // its Clients key and pv value exist to avoid an error.
+  ASSERT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENTS_GOOPDATE));
+  ASSERT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS_GOOPDATE));
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,
+                                            kRegValueProductVersion,
+                                            expected_version));
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,
+                                            kRegValueLanguage,
+                                            expected_lang));
+
+  ASSERT_FALSE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));
+
+  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);
+  EXPECT_HRESULT_SUCCEEDED(job_->Install());
+
+  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());
+
+  EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status);
+  EXPECT_EQ(S_OK, job_->info().error_code);
+  // The user never sees this, but it is odd we put this text in the structure.
+  EXPECT_STREQ(_T("Thanks for installing ."), job_->info().text);
+
+  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENTS_GOOPDATE));
+  EXPECT_TRUE(RegKey::HasKey(MACHINE_REG_CLIENT_STATE_GOOPDATE));
+
+  CString version;
+  EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                            kRegValueProductVersion,
+                                            &version));
+  EXPECT_STREQ(expected_version, version);
+
+  RestoreRegistryHives();
+  ASSERT_HRESULT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+// Update values should not be changed because we do not know whether
+// self-updates have succeeded yet.
+// Successful update and check values are not changed either.
+TEST_F(JobTest, Install_SuccessfulOmahaUpdateDoesNotClearUpdateAvailableStats) {
+  is_machine_ = false;
+
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);
+
+  CString arguments;
+  arguments.Format(kExecuteCommandAndTerminateSwitch, _T("echo hi"));
+
+  AppData app_data(kGoopdateGuid, is_machine_);
+  job_->set_download_file_name(kJobExecutable);
+  job_->set_app_data(app_data);
+  SetUpdateResponseDataArguments(arguments);
+
+  CString expected_version(_T("0.9.69.5"));
+  CString expected_lang(_T("en"));
+
+  // Because we don't actually run the Omaha installer, we need to make sure
+  // its Clients key and pv value exist to avoid an error.
+  ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENTS_GOOPDATE));
+  ASSERT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                            kRegValueProductVersion,
+                                            expected_version));
+  ASSERT_HRESULT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                            kRegValueLanguage,
+                                            expected_lang));
+
+  // Set update values so we can verify they are not modified or deleted.
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(123456)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(9876543210)));
+  const DWORD kExistingUpdateValues = 0x70123456;
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+
+  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);
+  EXPECT_HRESULT_SUCCEEDED(job_->Install());
+
+  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());
+
+  EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status);
+  EXPECT_EQ(S_OK, job_->info().error_code);
+  // The user never sees this, but it is odd we put this text in the structure.
+  EXPECT_STREQ(_T("Thanks for installing ."), job_->info().text);
+
+  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENTS_GOOPDATE));
+  EXPECT_TRUE(RegKey::HasKey(USER_REG_CLIENT_STATE_GOOPDATE));
+
+  CString version;
+  EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                            kRegValueProductVersion,
+                                            &version));
+  EXPECT_STREQ(expected_version, version);
+
+  DWORD update_available_count(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("UpdateAvailableCount"),
+                                    &update_available_count));
+  EXPECT_EQ(123456, update_available_count);
+
+  DWORD64 update_available_since_time(0);
+  EXPECT_SUCCEEDED(RegKey::GetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("UpdateAvailableSince"),
+                                    &update_available_since_time));
+  EXPECT_EQ(9876543210, update_available_since_time);
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                          kRegValueLastSuccessfulCheckSec));
+  EXPECT_EQ(kExistingUpdateValues,
+            GetDwordValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                          kRegValueLastUpdateTimeSec));
+
+  RestoreRegistryHives();
+  ASSERT_HRESULT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+TEST_F(JobTest, GetInstallerData) {
+  UpdateResponses responses;
+  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                    _T("server_manifest.xml")));
+  GUID guid = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}"));
+
+  const TCHAR* kVerboseLog = _T("\n  {\n    \"distribution\": {\n      ")
+                             _T("\"verbose_logging\": true\n    }\n  }\n  ");
+  const TCHAR* kSkipFirstRun = _T("{\n    \"distribution\": {\n      \"")
+                               _T("skip_first_run_ui\": true,\n    }\n  }\n  ");
+  CString skip_first_run_encoded;
+  EXPECT_SUCCEEDED(WideStringToUtf8UrlEncodedString(kSkipFirstRun,
+                                                    &skip_first_run_encoded));
+
+  ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(file_name, &responses));
+  UpdateResponseData response_data = responses[guid].update_response_data();
+  job_->set_update_response_data(response_data);
+
+  // Only set install_data_index to a valid value.
+  AppData app_data1(guid, is_machine_);
+  app_data1.set_install_data_index(_T("verboselogging"));
+  job_->set_app_data(app_data1);
+
+  CString installer_data1;
+  EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data1));
+  EXPECT_STREQ(kVerboseLog, installer_data1);
+
+  // Set both installer_data and install_data_index to valid values.
+  AppData app_data2(guid, is_machine_);
+  app_data2.set_encoded_installer_data(skip_first_run_encoded);
+  app_data2.set_install_data_index(_T("verboselogging"));
+  job_->set_app_data(app_data2);
+
+  CString installer_data2;
+  EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data2));
+  EXPECT_STREQ(kSkipFirstRun, installer_data2);
+
+  // Set installer_data to invalid value, and install_data_index to valid value.
+  AppData app_data3(guid, is_machine_);
+  app_data3.set_encoded_installer_data(_T("%20%20"));
+  app_data3.set_install_data_index(_T("verboselogging"));
+  job_->set_app_data(app_data3);
+
+  CString installer_data3;
+  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS,
+            job_->GetInstallerData(&installer_data3));
+
+  // Set installer_data to valid value, and install_data_index to invalid value.
+  AppData app_data4(guid, is_machine_);
+  app_data4.set_encoded_installer_data(skip_first_run_encoded);
+  app_data4.set_install_data_index(_T("foobar"));
+  job_->set_app_data(app_data4);
+
+  CString installer_data4;
+  EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data4));
+  EXPECT_STREQ(kSkipFirstRun, installer_data4);
+
+  // Set only install_data_index to invalid value.
+  AppData app_data5(guid, is_machine_);
+  app_data5.set_install_data_index(_T("foobar"));
+  job_->set_app_data(app_data5);
+
+  CString installer_data5;
+  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALL_DATA_INDEX,
+            job_->GetInstallerData(&installer_data5));
+
+  // Set neither installer_data nor install_data_index.
+  AppData app_data6(guid, is_machine_);
+  job_->set_app_data(app_data6);
+
+  CString installer_data6;
+  EXPECT_SUCCEEDED(job_->GetInstallerData(&installer_data6));
+  EXPECT_TRUE(installer_data6.IsEmpty());
+}
+
+// It would be nice if the Foo installer actually used the installer data as a
+// way to verify the data file is passed correctly. Alternatively, we could mock
+// the installer execution.
+TEST_F(JobInstallFooTest, InstallerData_ValidIndex) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  UpdateResponses responses;
+  CString file_name(ConcatenatePath(app_util::GetCurrentModuleDirectory(),
+                                    _T("server_manifest.xml")));
+  GUID guid = StringToGuid(_T("{D6B08267-B440-4C85-9F79-E195E80D9937}"));
+
+  ASSERT_SUCCEEDED(GoopdateXmlParser::ParseManifestFile(file_name, &responses));
+  UpdateResponseData response_data = responses[guid].update_response_data();
+  job_->set_update_response_data(response_data);
+
+  AppData app_data(PopulateFooAppData());
+  app_data.set_install_data_index(_T("verboselogging"));
+  job_->set_download_file_name(foo_installer_path_);
+  job_->set_app_data(app_data);
+
+  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);
+  EXPECT_HRESULT_SUCCEEDED(job_->Install());
+
+  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());
+
+  EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status);
+  EXPECT_EQ(S_OK, job_->info().error_code);
+  EXPECT_STREQ(_T("Thanks for installing Foo."), job_->info().text);
+}
+
+// Set installer_data to invalid value, and install_data_index to valid value.
+TEST_F(JobInstallFooTest, InstallerData_InvalidData) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  AppData app_data(PopulateFooAppData());
+  app_data.set_encoded_installer_data(_T("%20%20"));
+  app_data.set_install_data_index(_T("verboselogging"));
+  job_->set_app_data(app_data);
+
+  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);
+  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS, job_->Install());
+
+  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());
+
+  EXPECT_EQ(COMPLETION_ERROR, job_->info().status);
+  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALLER_DATA_IN_APPARGS,
+            job_->info().error_code);
+  EXPECT_STREQ(
+      _T("Installation failed. Please try again. Error code = 0x8004090a"),
+      job_->info().text);
+}
+
+TEST_F(JobInstallFooTest, InstallerData_NonExistentIndex) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  AppData app_data(PopulateFooAppData());
+  app_data.set_install_data_index(_T("foobar"));
+  job_->set_app_data(app_data);
+
+  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);
+  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALL_DATA_INDEX, job_->Install());
+
+  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());
+
+  EXPECT_EQ(COMPLETION_ERROR, job_->info().status);
+  EXPECT_EQ(GOOPDATE_E_INVALID_INSTALL_DATA_INDEX, job_->info().error_code);
+  EXPECT_STREQ(
+      _T("Installation failed. Please try again. Error code = 0x80040909"),
+      job_->info().text);
+}
+
+/*
+// TODO(omaha): Adapt into a test for SendStateChangePing by mocking ping.
+TEST_F(JobTest, BuildPingRequestFromJob_PopulatesAppRequest) {
+  const TCHAR* const kGuid = _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");
+  AppData app_data(StringToGuid(kGuid), true);
+  CreateTestAppData(&app_data);
+  job_->set_app_data(app_data);
+  set_job_state(JOBSTATE_COMPLETED);
+
+  CompletionInfo info(COMPLETION_INSTALLER_ERROR_MSI, 0x12345678, _T("foo"));
+  set_info(info);
+
+  Request req(true);
+  BuildPingRequestFromJob(&req);
+  ASSERT_EQ(1, req.get_app_count());
+
+  const AppRequest* app_request = req.GetApp(StringToGuid(kGuid));
+  EXPECT_STREQ(_T("{21CD0965-0B0E-47CF-B421-2D191C16C0E2}"),
+               GuidToString(app_request->guid()));
+  EXPECT_EQ(_T("1.1.1.3"), app_request->version());
+  EXPECT_EQ(_T("abc"), app_request->language());
+  EXPECT_EQ(AppData::ACTIVE_UNKNOWN, app_request->active());
+  EXPECT_TRUE(app_request->tag().IsEmpty());
+  EXPECT_STREQ(_T("{F723495F-8ACF-4746-824D-643741C797B5}"),
+               GuidToString(app_request->installation_id()));
+  EXPECT_EQ(_T("GOOG"), app_request->brand_code());
+  EXPECT_EQ(_T("someclient"), app_request->client_id());
+  EXPECT_EQ(_T("twoclick"), app_request->install_source());
+
+  ASSERT_TRUE(app_request->events_end() == ++app_request->events_begin());
+  const AppEvent* app_event = *app_request->events_begin();
+  EXPECT_EQ(AppEvent::EVENT_UPDATE_COMPLETE, app_event->event_type());
+  EXPECT_EQ(AppEvent::EVENT_RESULT_INSTALLER_ERROR_MSI,
+            app_event->event_result());
+  EXPECT_EQ(0x12345678, app_event->error_code());
+  EXPECT_EQ(0, app_event->extra_code1());
+  EXPECT_EQ(_T("1.0.0.0"), app_event->previous_version());
+}
+
+// TODO(omaha): Adapt into a test for CreateRequestFromProducts
+TEST_F(JobTest, BuildRequest_PopulatesAppRequest) {
+  const TCHAR* const kGuid = _T("{21CD0965-0B0E-47cf-B421-2D191C16C0E2}");
+  AppData app_data(StringToGuid(kGuid), true);
+  CreateTestAppData(&app_data);
+  job_->set_app_data(app_data);
+
+  Request req(true);
+  ASSERT_SUCCEEDED(job_->BuildRequest(&req));
+  ASSERT_EQ(1, req.get_app_count());
+
+  const AppRequest* app_request = req.GetApp(StringToGuid(kGuid));
+  EXPECT_STREQ(_T("{21CD0965-0B0E-47CF-B421-2D191C16C0E2}"),
+               GuidToString(app_request->guid()));
+  EXPECT_EQ(_T("1.1.1.3"), app_request->version());
+  EXPECT_EQ(_T("abc"), app_request->language());
+  EXPECT_EQ(AppData::ACTIVE_RUN, app_request->active());
+  EXPECT_EQ(_T("Test ap"), app_request->tag());
+  EXPECT_STREQ(_T("{F723495F-8ACF-4746-824D-643741C797B5}"),
+               GuidToString(app_request->installation_id()));
+  EXPECT_EQ(_T("GOOG"), app_request->brand_code());
+  EXPECT_EQ(_T("someclient"), app_request->client_id());
+  EXPECT_EQ(_T("twoclick"), app_request->install_source());
+}
+
+// TODO(omaha): Move to some other test file.
+TEST(RequestTest, TestInitialized) {
+  AppRequest app_request;
+  EXPECT_TRUE(::IsEqualGUID(GUID_NULL, app_request.guid()));
+  EXPECT_TRUE(app_request.version().IsEmpty());
+  EXPECT_TRUE(app_request.language().IsEmpty());
+  EXPECT_EQ(AppData::ACTIVE_UNKNOWN, app_request.active());
+  EXPECT_TRUE(app_request.tag().IsEmpty());
+  EXPECT_TRUE(::IsEqualGUID(GUID_NULL, app_request.installation_id()));
+  EXPECT_TRUE(app_request.brand_code().IsEmpty());
+  EXPECT_TRUE(app_request.client_id().IsEmpty());
+  EXPECT_TRUE(app_request.install_source().IsEmpty());
+}
+*/
+
+void JobInstallFooTest::Install_MsiInstallerSucceeds(bool is_update,
+                                                     bool is_first_install,
+                                                     bool is_offline) {
+  ASSERT_TRUE(!is_update || !is_offline);
+
+  const DWORD kExistingUpdateValues = 0x70123456;
+
+  // TODO(omaha): Use UserFoo instead, change is_machine in the base class,
+  // and remove all IsUserAdmin checks.
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+#ifdef _DEBUG
+  if (!is_update) {
+    // Event::WriteEvent() expects Omaha's version to exist.
+    // Write it if it doesn't exist.
+    ConfigManager& config_mgr = *ConfigManager::Instance();
+    CString key_name = config_mgr.registry_clients_goopdate(is_machine_);
+    if (!RegKey::HasValue(key_name, kRegValueLanguage)) {
+      EXPECT_HRESULT_SUCCEEDED(
+          RegKey::SetValue(key_name, kRegValueLanguage, _T("it")));
+    }
+    if (!RegKey::HasValue(key_name, kRegValueProductVersion)) {
+      EXPECT_HRESULT_SUCCEEDED(
+          RegKey::SetValue(key_name, kRegValueProductVersion, _T("0.1.0.0")));
+    }
+  }
+#endif
+
+  if (!is_update) {
+    SetIsInstallJob();
+  }
+
+  if (!is_first_install) {
+    // Make it appear to Omaha that Foo was already installed. This does not
+    // affect the installer.
+    EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,
+                                              kRegValueBrandCode,
+                                              _T("g00g")));
+
+    // Set update available stats so can verify they are deleted.
+    EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,
+                                      _T("UpdateAvailableCount"),
+                                      static_cast<DWORD>(123456)));
+    EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,
+                                      _T("UpdateAvailableSince"),
+                                      static_cast<DWORD64>(9876543210)));
+    EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,
+                                      kRegValueLastSuccessfulCheckSec,
+                                      kExistingUpdateValues));
+    EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,
+                                      kRegValueLastUpdateTimeSec,
+                                      kExistingUpdateValues));
+  }
+
+  job_->set_is_offline(is_offline);
+
+  AppData app_data(PopulateFooAppData());
+  job_->set_download_file_name(foo_installer_path_);
+  job_->set_app_data(app_data);
+
+  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);
+  EXPECT_HRESULT_SUCCEEDED(job_->Install());
+  const uint32 now = Time64ToInt32(GetCurrent100NSTime());
+
+  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());
+
+  EXPECT_EQ(COMPLETION_SUCCESS, job_->info().status);
+  EXPECT_EQ(S_OK, job_->info().error_code);
+  EXPECT_STREQ(_T("Thanks for installing Foo."), job_->info().text);
+
+  EXPECT_TRUE(File::Exists(foo_installer_log_path_));
+
+  EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientKeyPath));
+  EXPECT_TRUE(RegKey::HasKey(kFullFooAppClientStateKeyPath));
+
+  if (is_update) {
+    VerifyFooClientStateValuesWrittenBeforeInstallNotPresent(!is_first_install);
+  } else {
+    VerifyFooClientStateValuesWrittenBeforeInstall(is_first_install);
+  }
+  VerifyFooClientStateValuesWrittenAfterSuccessfulInstall();
+
+  EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,
+                                _T("UpdateAvailableCount")));
+  EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,
+                                _T("UpdateAvailableSince")));
+  if (is_update) {
+    // Verify update values updated.
+    const uint32 last_check_sec =
+        GetDwordValue(kFullFooAppClientStateKeyPath,
+                      kRegValueLastSuccessfulCheckSec);
+    EXPECT_NE(kExistingUpdateValues, last_check_sec);
+    EXPECT_GE(now, last_check_sec);
+    EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);
+
+    const uint32 last_update_sec = GetDwordValue(kFullFooAppClientStateKeyPath,
+                                                 kRegValueLastUpdateTimeSec);
+    EXPECT_NE(kExistingUpdateValues, last_update_sec);
+    EXPECT_GE(now, last_update_sec);
+    EXPECT_GE(static_cast<uint32>(200), now - last_update_sec);
+  } else {
+    // LastSuccessfulCheckSec is written for online installs but never cleared.
+    if (!is_offline) {
+      const uint32 last_check_sec =
+          GetDwordValue(kFullFooAppClientStateKeyPath,
+                        kRegValueLastSuccessfulCheckSec);
+      EXPECT_NE(kExistingUpdateValues, last_check_sec);
+      EXPECT_GE(now, last_check_sec);
+      EXPECT_GE(static_cast<uint32>(200), now - last_check_sec);
+    } else if (!is_first_install) {
+      EXPECT_EQ(kExistingUpdateValues,
+                GetDwordValue(kFullFooAppClientStateKeyPath,
+                              kRegValueLastSuccessfulCheckSec));
+    } else {
+      EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,
+                                    kRegValueLastSuccessfulCheckSec));
+    }
+
+    // kRegValueLastUpdateTimeSec is never written for installs.
+    if (!is_first_install) {
+      EXPECT_EQ(kExistingUpdateValues,
+                GetDwordValue(kFullFooAppClientStateKeyPath,
+                              kRegValueLastUpdateTimeSec));
+    } else {
+      EXPECT_FALSE(RegKey::HasValue(kFullFooAppClientStateKeyPath,
+                                    kRegValueLastUpdateTimeSec));
+    }
+  }
+
+  CString uninstall_arguments;
+  uninstall_arguments.Format(kMsiUninstallArguments, foo_installer_path_);
+  EXPECT_HRESULT_SUCCEEDED(System::ShellExecuteProcess(kMsiCommand,
+                                                       uninstall_arguments,
+                                                       NULL,
+                                                       NULL));
+}
+
+TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_FirstInstall_Online) {
+  Install_MsiInstallerSucceeds(false, true, false);
+}
+
+TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_OverInstall_Online) {
+  Install_MsiInstallerSucceeds(false, false, false);
+}
+
+TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_FirstInstall_Offline) {
+  Install_MsiInstallerSucceeds(false, true, true);
+}
+
+TEST_F(JobInstallFooTest, Install_MsiInstallerSucceeds_OverInstall_Offline) {
+  Install_MsiInstallerSucceeds(false, false, true);
+}
+
+TEST_F(JobInstallFooTest,
+       Install_MsiInstallerSucceeds_UpdateWhenNoExistingPreInstallData) {
+  // AppManager::ClearUpdateAvailableStats() asserts that key open succeeds.
+  EXPECT_SUCCEEDED(RegKey::CreateKey(kFullFooAppClientStateKeyPath));
+  Install_MsiInstallerSucceeds(true, true, false);
+}
+
+TEST_F(JobInstallFooTest,
+       Install_MsiInstallerSucceeds_UpdateWhenExistingPreInstallData) {
+  Install_MsiInstallerSucceeds(true, false, false);
+}
+
+
+void JobInstallFooTest::Install_InstallerFailed_WhenNoExistingPreInstallData(
+    bool is_update) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  if (!is_update) {
+    SetIsInstallJob();
+  }
+
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);
+#ifdef _DEBUG
+  // Event::WriteEvent() expects Omaha's language and version to exist.
+  ConfigManager& config_mgr = *ConfigManager::Instance();
+  CString key_name = config_mgr.registry_clients_goopdate(is_machine_);
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(key_name, kRegValueLanguage, _T("it")));
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(key_name, kRegValueProductVersion, _T("0.1.2.3")));
+#endif
+
+  AppData app_data(PopulateFooAppData());
+  job_->set_download_file_name(_T("DoesNotExist.exe"));
+  job_->set_app_data(app_data);
+
+  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->Install());
+
+  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());
+
+  EXPECT_EQ(COMPLETION_ERROR, job_->info().status);
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->info().error_code);
+  EXPECT_STREQ(_T("The installer failed to start."), job_->info().text);
+
+  EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath));
+  EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientStateKeyPath));
+
+  // TODO(omaha): Install the job successfully and verify that the brand data
+  // is replaced by the successful install.
+
+  RestoreRegistryHives();
+  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+// Overrides the registry hives.
+TEST_F(JobInstallFooTest,
+       Install_InstallerFailedFirstInstall_WhenNoExistingPreInstallData) {
+  Install_InstallerFailed_WhenNoExistingPreInstallData(false);
+}
+
+TEST_F(JobInstallFooTest,
+       Install_InstallerFailedUpdate_WhenNoExistingPreInstallData) {
+  Install_InstallerFailed_WhenNoExistingPreInstallData(true);
+}
+
+void JobInstallFooTest::Install_InstallerFailed_WhenExistingPreInstallData(
+    bool is_update) {
+  if (!vista_util::IsUserAdmin()) {
+    std::wcout << _T("\tTest did not run because the user is not an admin.")
+               << std::endl;
+    return;
+  }
+
+  if (!is_update) {
+    SetIsInstallJob();
+  }
+
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot, true);
+  OverrideRegistryHivesWithExecutionPermissions(kRegistryHiveOverrideRoot);
+
+#ifdef _DEBUG
+  // Event::WriteEvent() expects Omaha's language and version to exist.
+  ConfigManager& config_mgr = *ConfigManager::Instance();
+  CString key_name = config_mgr.registry_clients_goopdate(is_machine_);
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(key_name, kRegValueLanguage, _T("it")));
+  EXPECT_HRESULT_SUCCEEDED(
+      RegKey::SetValue(key_name, kRegValueProductVersion, _T("0.1.2.3")));
+#endif
+
+  // Prepopulate data for this app in the ClientState registry
+  EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,
+                                            kRegValueProductVersion,
+                                            _T("0.1.2.3")));
+
+  // Set update available stats so can verify they are not modified or deleted.
+  EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(123456)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(9876543210)));
+  const DWORD kExistingUpdateValues = 0x70123456;
+  EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,
+                                    kRegValueLastSuccessfulCheckSec,
+                                    kExistingUpdateValues));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kFullFooAppClientStateKeyPath,
+                                    kRegValueLastUpdateTimeSec,
+                                    kExistingUpdateValues));
+
+  AppData app_data(PopulateFooAppData());
+  job_->set_download_file_name(_T("DoesNotExist.exe"));
+  job_->set_app_data(app_data);
+
+  set_job_state(JOBSTATE_DOWNLOADCOMPLETED);
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->Install());
+
+  EXPECT_EQ(JOBSTATE_COMPLETED, job_->job_state());
+
+  EXPECT_EQ(COMPLETION_ERROR, job_->info().status);
+  EXPECT_EQ(GOOPDATEINSTALL_E_INSTALLER_FAILED_START, job_->info().error_code);
+  EXPECT_STREQ(_T("The installer failed to start."), job_->info().text);
+
+  EXPECT_EQ(is_update, RegKey::HasKey(kFullFooAppClientStateKeyPath));
+  EXPECT_FALSE(RegKey::HasKey(kFullFooAppClientKeyPath));
+
+  // When an update fails, data remains. When an install fails, the entire
+  // ClientState key is deleted as verified above.
+  if (is_update) {
+    DWORD update_available_count(0);
+    EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                      _T("UpdateAvailableCount"),
+                                      &update_available_count));
+    EXPECT_EQ(123456, update_available_count);
+
+    DWORD64 update_available_since_time(0);
+    EXPECT_SUCCEEDED(RegKey::GetValue(kFullFooAppClientStateKeyPath,
+                                      _T("UpdateAvailableSince"),
+                                      &update_available_since_time));
+    EXPECT_EQ(9876543210, update_available_since_time);
+    EXPECT_EQ(kExistingUpdateValues,
+              GetDwordValue(kFullFooAppClientStateKeyPath,
+                            kRegValueLastSuccessfulCheckSec));
+    EXPECT_EQ(kExistingUpdateValues,
+              GetDwordValue(kFullFooAppClientStateKeyPath,
+                            kRegValueLastUpdateTimeSec));
+  }
+
+  RestoreRegistryHives();
+  ASSERT_SUCCEEDED(RegKey::DeleteKey(kRegistryHiveOverrideRoot, true));
+}
+
+TEST_F(JobInstallFooTest,
+       Install_InstallerFailedFirstInstall_WhenExistingPreInstallData) {
+  Install_InstallerFailed_WhenExistingPreInstallData(false);
+}
+
+TEST_F(JobInstallFooTest,
+       Install_InstallerFailedUpdate_WhenExistingPreInstallData) {
+  Install_InstallerFailed_WhenExistingPreInstallData(true);
+}
+
+TEST_F(JobTest, LaunchCmdLine_EmptyCommand) {
+  SetIsInstallJob();
+  EXPECT_SUCCEEDED(job_->LaunchCmdLine());
+  EXPECT_FALSE(did_launch_cmd_fail());
+}
+
+TEST_F(JobTest, LaunchCmdLine_LaunchFails) {
+  SetIsInstallJob();
+  set_launch_cmd_line(_T("no_such_file.exe"));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), job_->LaunchCmdLine());
+  EXPECT_TRUE(did_launch_cmd_fail());
+}
+
+TEST_F(JobTest, LaunchCmdLine_Succeeds) {
+  SetIsInstallJob();
+  set_launch_cmd_line(_T("cmd /c"));
+  EXPECT_SUCCEEDED(job_->LaunchCmdLine());
+  EXPECT_FALSE(did_launch_cmd_fail());
+}
+
+// LaunchCmdLine should not be called for update jobs.
+TEST_F(JobTest, LaunchCmdLine_IsUpdateJob) {
+  ExpectAsserts expect_asserts;
+  set_launch_cmd_line(_T("cmd /c"));
+  EXPECT_SUCCEEDED(job_->LaunchCmdLine());
+  EXPECT_FALSE(did_launch_cmd_fail());
+}
+
+class JobDoCompleteJobJobSuccessTest : public JobTest {
+ protected:
+  virtual void SetUp() {
+    JobTest::SetUp();
+
+    destination_path_ = CreateUniqueTempDir();
+    set_download_file_name(ConcatenatePath(destination_path_, _T("foo.msi")));
+    job_->set_job_observer(&job_observer_);
+
+    CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));
+    set_info(info);
+  }
+
+  CString destination_path_;
+  JobObserverMock job_observer_;
+};
+
+TEST_F(JobDoCompleteJobJobSuccessTest, DefaultSuccessAction) {
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);
+  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());
+  EXPECT_EQ(0, job_observer_.completion_error_code);
+
+  EXPECT_FALSE(File::Exists(destination_path_));
+}
+
+// download_file_name_ is not set. No assert indicates that
+// DeleteJobDownloadDirectory is not called in error cases.
+TEST_F(JobTest, DefaultSuccessAction_Omaha) {
+  JobObserverMock job_observer;
+  job_->set_job_observer(&job_observer);
+
+  CompletionInfo info(COMPLETION_SUCCESS, 0, _T(""));
+  set_info(info);
+
+  AppData app_data;
+  app_data.set_app_guid(kGoopdateGuid);
+  SetAppData(app_data);
+
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer.completion_code);
+  EXPECT_TRUE(job_observer.completion_text.IsEmpty());
+  EXPECT_EQ(0, job_observer.completion_error_code);
+}
+
+TEST_F(JobDoCompleteJobJobSuccessTest,
+       DefaultSuccessAction_LaunchCmdNotFailed) {
+  SetIsInstallJob();
+
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);
+  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());
+  EXPECT_EQ(0, job_observer_.completion_error_code);
+}
+
+TEST_F(JobDoCompleteJobJobSuccessTest,
+       DefaultSuccessAction_LaunchCmdFailed) {
+  SetIsInstallJob();
+  set_did_launch_cmd_fail(true);
+
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);
+  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());
+  EXPECT_EQ(0, job_observer_.completion_error_code);
+}
+
+TEST_F(JobDoCompleteJobJobSuccessTest,
+       SuccessActionExitSilently_NoLaunchCmd) {
+  SetIsInstallJob();
+  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY);
+
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_SUCCESS_CLOSE_UI, job_observer_.completion_code);
+  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());
+  EXPECT_EQ(0, job_observer_.completion_error_code);
+}
+
+TEST_F(JobDoCompleteJobJobSuccessTest,
+       SuccessActionExitSilently_LaunchCmdNotFailed) {
+  SetIsInstallJob();
+  set_launch_cmd_line(_T("cmd /c"));
+  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY);
+
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_SUCCESS_CLOSE_UI, job_observer_.completion_code);
+  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());
+  EXPECT_EQ(0, job_observer_.completion_error_code);
+}
+
+TEST_F(JobDoCompleteJobJobSuccessTest,
+       SuccessActionExitSilently_LaunchCmdFailed) {
+  SetIsInstallJob();
+  set_launch_cmd_line(_T("cmd /c"));
+  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY);
+  set_did_launch_cmd_fail(true);
+
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);
+  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());
+  EXPECT_EQ(0, job_observer_.completion_error_code);
+}
+
+TEST_F(JobDoCompleteJobJobSuccessTest,
+       SuccessActionExitSilentlyOnCmd_NoLaunchCmd) {
+  SetIsInstallJob();
+  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD);
+
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);
+  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());
+  EXPECT_EQ(0, job_observer_.completion_error_code);
+}
+
+TEST_F(JobDoCompleteJobJobSuccessTest,
+       SuccessActionExitSilentlyOnCmd_CmdNotFailed) {
+  SetIsInstallJob();
+  set_launch_cmd_line(_T("cmd /c"));
+  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD);
+
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_SUCCESS_CLOSE_UI, job_observer_.completion_code);
+  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());
+  EXPECT_EQ(0, job_observer_.completion_error_code);
+}
+
+TEST_F(JobDoCompleteJobJobSuccessTest,
+       DefaultSuccessActionOnCmd_LaunchCmdFailed) {
+  SetIsInstallJob();
+  set_launch_cmd_line(_T("cmd /c"));
+  SetUpdateResponseSuccessAction(SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD);
+  set_did_launch_cmd_fail(true);
+
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer_.completion_code);
+  EXPECT_TRUE(job_observer_.completion_text.IsEmpty());
+  EXPECT_EQ(0, job_observer_.completion_error_code);
+}
+
+// download_file_name_ is not set. No assert indicates that
+// DeleteJobDownloadDirectory is not called in error cases.
+TEST_F(JobTest, DoCompleteJob_JobError) {
+  JobObserverMock job_observer_;
+  job_->set_job_observer(&job_observer_);
+  CompletionInfo info(COMPLETION_ERROR, static_cast<DWORD>(E_FAIL), _T("blah"));
+  set_info(info);
+
+  EXPECT_SUCCEEDED(DoCompleteJob());
+
+  EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer_.completion_code);
+  EXPECT_STREQ(_T("blah"), job_observer_.completion_text);
+  EXPECT_EQ(E_FAIL, job_observer_.completion_error_code);
+}
+
+}  // namespace omaha
diff --git a/worker/ping.cc b/worker/ping.cc
index e8b988d..90c617b 100644
--- a/worker/ping.cc
+++ b/worker/ping.cc
@@ -1,123 +1,123 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// Ping requests use http protocol. When pinging over http fails, a fallback

-// using https protocol is attempted.

-

-#include "omaha/worker/ping.h"

-

-#include <atlstr.h>

-#include <vector>

-#include "omaha/common/string.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/goopdate_xml_parser.h"

-#include "omaha/goopdate/request.h"

-#include "omaha/net/browser_request.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/simple_request.h"

-#include "omaha/worker/worker_metrics.h"

-

-namespace omaha {

-

-Ping::Ping() {

-  // The ping request does not use CUP since its response does not require

-  // authentication.

-  const NetworkConfig::Session& session(NetworkConfig::Instance().session());

-  network_request_.reset(new NetworkRequest(session));

-  network_request_->AddHttpRequest(new SimpleRequest);

-  network_request_->AddHttpRequest(new BrowserRequest);

-}

-

-Ping::~Ping() {

-}

-

-// Returns S_OK without sending the ping in OEM mode.

-HRESULT Ping::SendPing(Request* req) {

-  CORE_LOG(L2, (_T("[Ping::SendPing]")));

-  ASSERT1(req);

-

-  // Do not access the network during an OEM install.

-  if (!ConfigManager::Instance()->CanUseNetwork(req->is_machine())) {

-    CORE_LOG(L1, (_T("[Ping not sent because network use prohibited]")));

-    return GOOPDATE_E_CANNOT_USE_NETWORK;

-  }

-

-  // Do not send a request which contains no ping events.

-  bool has_ping_events = false;

-  for (AppRequestVector::const_iterator it = req->app_requests_begin();

-       it != req->app_requests_end();

-       ++it) {

-    if ((*it).request_data().num_ping_events() != 0) {

-      has_ping_events = true;

-      break;

-    }

-  }

-  if (!has_ping_events) {

-    return HRESULT_FROM_WIN32(ERROR_NO_DATA);

-  }

-

-  HighresTimer metrics_timer;

-

-  CString request_string;

-  HRESULT hr = GoopdateXmlParser::GenerateRequest(*req,

-                                                  false,

-                                                  &request_string);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[GenerateRequest failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  CString ping_url;

-  hr = ConfigManager::Instance()->GetPingUrl(&ping_url);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = DoSendPing(ping_url, request_string);

-  if (FAILED(hr)) {

-    metric_ping_failed_ms.AddSample(metrics_timer.GetElapsedMs());

-    return hr;

-  }

-

-  metric_ping_succeeded_ms.AddSample(metrics_timer.GetElapsedMs());

-  return S_OK;

-}

-

-HRESULT Ping::DoSendPing(const CString& url,

-                         const CString& request_string) {

-  CString response;

-  return PostRequest(network_request_.get(),

-                     true,                    // Fall back to https.

-                     url,

-                     request_string,

-                     &response);

-}

-

-HRESULT Ping::Cancel() {

-  if (network_request_.get()) {

-    HRESULT hr = network_request_->Cancel();

-    if (FAILED(hr)) {

-      CORE_LOG(LE, (_T("[NetworkRequest::Cancel failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// Ping requests use http protocol. When pinging over http fails, a fallback
+// using https protocol is attempted.
+
+#include "omaha/worker/ping.h"
+
+#include <atlstr.h>
+#include <vector>
+#include "omaha/common/string.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/goopdate_xml_parser.h"
+#include "omaha/goopdate/request.h"
+#include "omaha/net/browser_request.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/simple_request.h"
+#include "omaha/worker/worker_metrics.h"
+
+namespace omaha {
+
+Ping::Ping() {
+  // The ping request does not use CUP since its response does not require
+  // authentication.
+  const NetworkConfig::Session& session(NetworkConfig::Instance().session());
+  network_request_.reset(new NetworkRequest(session));
+  network_request_->AddHttpRequest(new SimpleRequest);
+  network_request_->AddHttpRequest(new BrowserRequest);
+}
+
+Ping::~Ping() {
+}
+
+// Returns S_OK without sending the ping in OEM mode.
+HRESULT Ping::SendPing(Request* req) {
+  CORE_LOG(L2, (_T("[Ping::SendPing]")));
+  ASSERT1(req);
+
+  // Do not access the network during an OEM install.
+  if (!ConfigManager::Instance()->CanUseNetwork(req->is_machine())) {
+    CORE_LOG(L1, (_T("[Ping not sent because network use prohibited]")));
+    return GOOPDATE_E_CANNOT_USE_NETWORK;
+  }
+
+  // Do not send a request which contains no ping events.
+  bool has_ping_events = false;
+  for (AppRequestVector::const_iterator it = req->app_requests_begin();
+       it != req->app_requests_end();
+       ++it) {
+    if ((*it).request_data().num_ping_events() != 0) {
+      has_ping_events = true;
+      break;
+    }
+  }
+  if (!has_ping_events) {
+    return HRESULT_FROM_WIN32(ERROR_NO_DATA);
+  }
+
+  HighresTimer metrics_timer;
+
+  CString request_string;
+  HRESULT hr = GoopdateXmlParser::GenerateRequest(*req,
+                                                  false,
+                                                  &request_string);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[GenerateRequest failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  CString ping_url;
+  hr = ConfigManager::Instance()->GetPingUrl(&ping_url);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = DoSendPing(ping_url, request_string);
+  if (FAILED(hr)) {
+    metric_ping_failed_ms.AddSample(metrics_timer.GetElapsedMs());
+    return hr;
+  }
+
+  metric_ping_succeeded_ms.AddSample(metrics_timer.GetElapsedMs());
+  return S_OK;
+}
+
+HRESULT Ping::DoSendPing(const CString& url,
+                         const CString& request_string) {
+  CString response;
+  return PostRequest(network_request_.get(),
+                     true,                    // Fall back to https.
+                     url,
+                     request_string,
+                     &response);
+}
+
+HRESULT Ping::Cancel() {
+  if (network_request_.get()) {
+    HRESULT hr = network_request_->Cancel();
+    if (FAILED(hr)) {
+      CORE_LOG(LE, (_T("[NetworkRequest::Cancel failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+}  // namespace omaha
diff --git a/worker/ping.h b/worker/ping.h
index 78d5cff..e341906 100644
--- a/worker/ping.h
+++ b/worker/ping.h
@@ -1,49 +1,49 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_PING_H__

-#define OMAHA_WORKER_PING_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-

-namespace omaha {

-

-class Job;

-class NetworkRequest;

-class Request;

-

-class Ping {

- public:

-  Ping();

-  virtual ~Ping();

-

-  // Sends a ping request. Returns an error if the request does not contain

-  // any ping events.

-  virtual HRESULT SendPing(Request* req);

-  virtual HRESULT Cancel();

-

- private:

-  HRESULT DoSendPing(const CString& url,

-                     const CString& request_string);

-  scoped_ptr<NetworkRequest> network_request_;

-  DISALLOW_EVIL_CONSTRUCTORS(Ping);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_PING_H__

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_PING_H__
+#define OMAHA_WORKER_PING_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+
+namespace omaha {
+
+class Job;
+class NetworkRequest;
+class Request;
+
+class Ping {
+ public:
+  Ping();
+  virtual ~Ping();
+
+  // Sends a ping request. Returns an error if the request does not contain
+  // any ping events.
+  virtual HRESULT SendPing(Request* req);
+  virtual HRESULT Cancel();
+
+ private:
+  HRESULT DoSendPing(const CString& url,
+                     const CString& request_string);
+  scoped_ptr<NetworkRequest> network_request_;
+  DISALLOW_EVIL_CONSTRUCTORS(Ping);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_PING_H__
diff --git a/worker/ping_event.h b/worker/ping_event.h
index 2a53773..31d6bc3 100644
--- a/worker/ping_event.h
+++ b/worker/ping_event.h
@@ -1,132 +1,132 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// ping_event.h: Encapsulates events to attach to AppRequests for pings.

-

-#ifndef OMAHA_WORKER_PING_EVENT_H__

-#define OMAHA_WORKER_PING_EVENT_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-

-namespace omaha {

-

-class PingEvent {

- public:

-  // When updating this enum, also update the protocol file on the server.

-  // These values get reported to the server, so do not change existing ones.

-  //

-  // Checkpoints:

-  //  "EVENT_INSTALL_*" events report the progress of initial installs.

-  //  "EVENT_UPDATE_*" events report the progress of silent updates.

-  //  These checkpoints represent the "START" or "FINISH" of a phase.

-  // Actions:

-  //  "EVENT_*_BEGIN" events report the start of a specific action (i.e. job).

-  //  "EVENT_*_COMPLETE" events represent the end of such actions and report

-  // successful completion or the error that occurred during the action.

-  enum Types {

-    EVENT_UNKNOWN = 0,

-    EVENT_INSTALL_DOWNLOAD_FINISH = 1,

-    EVENT_INSTALL_COMPLETE = 2,

-    EVENT_UPDATE_COMPLETE = 3,

-    EVENT_UNINSTALL = 4,

-    EVENT_INSTALL_DOWNLOAD_START = 5,

-    EVENT_INSTALL_INSTALLER_START = 6,

-    // Never used = 7

-    // No longer used - EVENT_INSTALLED_GOOPDATE_STARTED = 8,

-    EVENT_INSTALL_APPLICATION_BEGIN = 9,

-

-    // Install Setup events.

-    EVENT_SETUP_INSTALL_BEGIN = 10,

-    EVENT_SETUP_INSTALL_COMPLETE = 11,

-

-    // Update Events.

-    // The Update Event = 3 above is used for update completion.

-    EVENT_UPDATE_APPLICATION_BEGIN = 12,

-    EVENT_UPDATE_DOWNLOAD_START = 13,

-    EVENT_UPDATE_DOWNLOAD_FINISH = 14,

-    EVENT_UPDATE_INSTALLER_START = 15,

-

-    // Self-update Setup events.

-    EVENT_SETUP_UPDATE_BEGIN = 16,

-    EVENT_SETUP_UPDATE_COMPLETE = 17,

-

-    // Ping when installed via /registerproduct.

-    EVENT_REGISTER_PRODUCT_COMPLETE = 20,

-

-    // Ping when an end user first boots a new system with an OEM-installed app.

-    EVENT_INSTALL_OEM_FIRST_CHECK = 30,

-

-    // Failure report events - not part of the normal flow.

-    EVENT_SETUP_INSTALL_FAILURE = 100,

-    // No longer used - EVENT_GOOPDATE_DLL_FAILURE = 101,

-    EVENT_SETUP_COM_SERVER_FAILURE = 102,

-    EVENT_SETUP_UPDATE_FAILURE = 103,

-  };

-

-  // When updating this enum, also update the identical one in

-  // omaha_extensions.proto.

-  // These values get reported to the server, so do not change existing ones.

-  enum Results {

-    EVENT_RESULT_ERROR = 0,

-    EVENT_RESULT_SUCCESS = 1,

-    EVENT_RESULT_SUCCESS_REBOOT = 2,

-    //  EVENT_RESULT_SUCCESS_RESTART_BROWSER = 3,

-    EVENT_RESULT_CANCELLED = 4,

-    EVENT_RESULT_INSTALLER_ERROR_MSI = 5,

-    EVENT_RESULT_INSTALLER_ERROR_OTHER = 6,

-    EVENT_RESULT_NOUPDATE = 7,

-    EVENT_RESULT_INSTALLER_ERROR_SYSTEM = 8,

-    EVENT_RESULT_UPDATE_DEFERRED = 9,

-  };

-

-  // TODO(omaha): consider making previous_version part of the app element

-  // instead of the event element.

-  PingEvent(Types type,

-            Results result,

-            int error_code,

-            int extra_code1,

-            const CString& previous_version)

-    :  event_type_(type),

-       event_result_(result),

-       error_code_(error_code),

-       extra_code1_(extra_code1),

-       previous_version_(previous_version) {

-    ASSERT1(EVENT_UNKNOWN != event_type_);

-  }

-

-  Types event_type() const { return event_type_; }

-  Results event_result() const { return event_result_; }

-  int error_code() const { return error_code_; }

-  int extra_code1() const { return extra_code1_; }

-  CString previous_version() const { return previous_version_; }

-

- private:

-  Types event_type_;

-  Results event_result_;

-  int error_code_;

-  int extra_code1_;

-  CString previous_version_;

-};

-

-typedef std::vector<PingEvent> PingEventVector;

-

-}  // namespace omaha.

-

-#endif  // OMAHA_WORKER_PING_EVENT_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// ping_event.h: Encapsulates events to attach to AppRequests for pings.
+
+#ifndef OMAHA_WORKER_PING_EVENT_H__
+#define OMAHA_WORKER_PING_EVENT_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+
+namespace omaha {
+
+class PingEvent {
+ public:
+  // When updating this enum, also update the protocol file on the server.
+  // These values get reported to the server, so do not change existing ones.
+  //
+  // Checkpoints:
+  //  "EVENT_INSTALL_*" events report the progress of initial installs.
+  //  "EVENT_UPDATE_*" events report the progress of silent updates.
+  //  These checkpoints represent the "START" or "FINISH" of a phase.
+  // Actions:
+  //  "EVENT_*_BEGIN" events report the start of a specific action (i.e. job).
+  //  "EVENT_*_COMPLETE" events represent the end of such actions and report
+  // successful completion or the error that occurred during the action.
+  enum Types {
+    EVENT_UNKNOWN = 0,
+    EVENT_INSTALL_DOWNLOAD_FINISH = 1,
+    EVENT_INSTALL_COMPLETE = 2,
+    EVENT_UPDATE_COMPLETE = 3,
+    EVENT_UNINSTALL = 4,
+    EVENT_INSTALL_DOWNLOAD_START = 5,
+    EVENT_INSTALL_INSTALLER_START = 6,
+    // Never used = 7
+    // No longer used - EVENT_INSTALLED_GOOPDATE_STARTED = 8,
+    EVENT_INSTALL_APPLICATION_BEGIN = 9,
+
+    // Install Setup events.
+    EVENT_SETUP_INSTALL_BEGIN = 10,
+    EVENT_SETUP_INSTALL_COMPLETE = 11,
+
+    // Update Events.
+    // The Update Event = 3 above is used for update completion.
+    EVENT_UPDATE_APPLICATION_BEGIN = 12,
+    EVENT_UPDATE_DOWNLOAD_START = 13,
+    EVENT_UPDATE_DOWNLOAD_FINISH = 14,
+    EVENT_UPDATE_INSTALLER_START = 15,
+
+    // Self-update Setup events.
+    EVENT_SETUP_UPDATE_BEGIN = 16,
+    EVENT_SETUP_UPDATE_COMPLETE = 17,
+
+    // Ping when installed via /registerproduct.
+    EVENT_REGISTER_PRODUCT_COMPLETE = 20,
+
+    // Ping when an end user first boots a new system with an OEM-installed app.
+    EVENT_INSTALL_OEM_FIRST_CHECK = 30,
+
+    // Failure report events - not part of the normal flow.
+    EVENT_SETUP_INSTALL_FAILURE = 100,
+    // No longer used - EVENT_GOOPDATE_DLL_FAILURE = 101,
+    EVENT_SETUP_COM_SERVER_FAILURE = 102,
+    EVENT_SETUP_UPDATE_FAILURE = 103,
+  };
+
+  // When updating this enum, also update the identical one in
+  // omaha_extensions.proto.
+  // These values get reported to the server, so do not change existing ones.
+  enum Results {
+    EVENT_RESULT_ERROR = 0,
+    EVENT_RESULT_SUCCESS = 1,
+    EVENT_RESULT_SUCCESS_REBOOT = 2,
+    //  EVENT_RESULT_SUCCESS_RESTART_BROWSER = 3,
+    EVENT_RESULT_CANCELLED = 4,
+    EVENT_RESULT_INSTALLER_ERROR_MSI = 5,
+    EVENT_RESULT_INSTALLER_ERROR_OTHER = 6,
+    EVENT_RESULT_NOUPDATE = 7,
+    EVENT_RESULT_INSTALLER_ERROR_SYSTEM = 8,
+    EVENT_RESULT_UPDATE_DEFERRED = 9,
+  };
+
+  // TODO(omaha): consider making previous_version part of the app element
+  // instead of the event element.
+  PingEvent(Types type,
+            Results result,
+            int error_code,
+            int extra_code1,
+            const CString& previous_version)
+    :  event_type_(type),
+       event_result_(result),
+       error_code_(error_code),
+       extra_code1_(extra_code1),
+       previous_version_(previous_version) {
+    ASSERT1(EVENT_UNKNOWN != event_type_);
+  }
+
+  Types event_type() const { return event_type_; }
+  Results event_result() const { return event_result_; }
+  int error_code() const { return error_code_; }
+  int extra_code1() const { return extra_code1_; }
+  CString previous_version() const { return previous_version_; }
+
+ private:
+  Types event_type_;
+  Results event_result_;
+  int error_code_;
+  int extra_code1_;
+  CString previous_version_;
+};
+
+typedef std::vector<PingEvent> PingEventVector;
+
+}  // namespace omaha.
+
+#endif  // OMAHA_WORKER_PING_EVENT_H__
+
diff --git a/worker/ping_mock.h b/worker/ping_mock.h
index 2c32106..82171b4 100644
--- a/worker/ping_mock.h
+++ b/worker/ping_mock.h
@@ -1,106 +1,106 @@
-// Copyright 2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_PING_MOCK_H__

-#define OMAHA_WORKER_PING_MOCK_H__

-

-#include <windows.h>

-#include <vector>

-#include "omaha/goopdate/request.h"

-#include "omaha/worker/ping.h"

-#include "omaha/testing/unit_test.h"

-

-namespace omaha {

-

-class PingMock : public Ping {

- public:

-  PingMock() {}

-

-  virtual ~PingMock() {

-    for (size_t i = 0; i < ping_requests_.size(); ++i) {

-      delete ping_requests_[i];

-    }

-  }

-

-  // Creates a copy of req and stores it in the ping_requests_ vector.

-  // The implementation must be kept in sync with Request's members.

-  virtual HRESULT SendPing(Request* req) {

-    ASSERT1(req);

-

-    Request* request = new Request(req->is_machine());

-    request->machine_id_ = req->machine_id();

-    request->user_id_ = req->user_id();

-    request->version_ = req->version();

-    request->os_version_ = req->os_version();

-    request->os_service_pack_ = req->os_service_pack();

-    request->test_source_ = req->test_source();

-    request->request_id_ = req->request_id();

-    request->app_requests_ = req->app_requests_;

-

-    ping_requests_.push_back(request);

-    return S_OK;

-  }

-

-  const std::vector<Request*>& ping_requests() const { return ping_requests_; }

-

- private:

-  std::vector<Request*> ping_requests_;

-

- private:

-  DISALLOW_EVIL_CONSTRUCTORS(PingMock);

-};

-

-// Returns the event from an AppRequest that contains a single event.

-inline const PingEvent& GetSingleEventFromAppRequest(

-    const AppRequest& app_request,

-    const GUID& expected_app_guid,

-    bool expected_is_machine) {

-  const AppRequestData& app_request_data = app_request.request_data();

-

-  const AppData& app_data = app_request_data.app_data();

-  EXPECT_TRUE(::IsEqualGUID(expected_app_guid, app_data.app_guid()));

-  EXPECT_TRUE(::IsEqualGUID(GUID_NULL, app_data.parent_app_guid()));

-  EXPECT_EQ(expected_is_machine, app_data.is_machine_app());

-  EXPECT_TRUE(!app_data.version().IsEmpty());

-  EXPECT_TRUE(!app_data.previous_version().IsEmpty());

-

-  EXPECT_EQ(1, app_request_data.num_ping_events());

-  return *app_request_data.ping_events_begin();

-}

-

-inline const PingEvent& GetSingleEventFromRequest(const Request& request,

-                                                  const GUID& expected_app_guid,

-                                                  bool expected_is_machine) {

-  EXPECT_EQ(expected_is_machine, request.is_machine());

-  EXPECT_TRUE(!request.machine_id().IsEmpty() || !expected_is_machine);

-  EXPECT_TRUE(!request.user_id().IsEmpty());

-  EXPECT_TRUE(!request.version().IsEmpty());

-  EXPECT_TRUE(!request.os_version().IsEmpty());

-  // Skip checking request.os_service_pack() as it can be empty for RTM.

-#if defined(DEBUG) || !OFFICIAL_BUILD

-  EXPECT_TRUE(!request.test_source().IsEmpty());

-#else

-  EXPECT_TRUE(request.test_source().IsEmpty());

-#endif

-  EXPECT_TRUE(!request.request_id().IsEmpty());

-  EXPECT_EQ(1, request.get_request_count());

-  return GetSingleEventFromAppRequest(*request.app_requests_begin(),

-                                      expected_app_guid,

-                                      expected_is_machine);

-}

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_PING_MOCK_H__

+// Copyright 2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_PING_MOCK_H__
+#define OMAHA_WORKER_PING_MOCK_H__
+
+#include <windows.h>
+#include <vector>
+#include "omaha/goopdate/request.h"
+#include "omaha/worker/ping.h"
+#include "omaha/testing/unit_test.h"
+
+namespace omaha {
+
+class PingMock : public Ping {
+ public:
+  PingMock() {}
+
+  virtual ~PingMock() {
+    for (size_t i = 0; i < ping_requests_.size(); ++i) {
+      delete ping_requests_[i];
+    }
+  }
+
+  // Creates a copy of req and stores it in the ping_requests_ vector.
+  // The implementation must be kept in sync with Request's members.
+  virtual HRESULT SendPing(Request* req) {
+    ASSERT1(req);
+
+    Request* request = new Request(req->is_machine());
+    request->machine_id_ = req->machine_id();
+    request->user_id_ = req->user_id();
+    request->version_ = req->version();
+    request->os_version_ = req->os_version();
+    request->os_service_pack_ = req->os_service_pack();
+    request->test_source_ = req->test_source();
+    request->request_id_ = req->request_id();
+    request->app_requests_ = req->app_requests_;
+
+    ping_requests_.push_back(request);
+    return S_OK;
+  }
+
+  const std::vector<Request*>& ping_requests() const { return ping_requests_; }
+
+ private:
+  std::vector<Request*> ping_requests_;
+
+ private:
+  DISALLOW_EVIL_CONSTRUCTORS(PingMock);
+};
+
+// Returns the event from an AppRequest that contains a single event.
+inline const PingEvent& GetSingleEventFromAppRequest(
+    const AppRequest& app_request,
+    const GUID& expected_app_guid,
+    bool expected_is_machine) {
+  const AppRequestData& app_request_data = app_request.request_data();
+
+  const AppData& app_data = app_request_data.app_data();
+  EXPECT_TRUE(::IsEqualGUID(expected_app_guid, app_data.app_guid()));
+  EXPECT_TRUE(::IsEqualGUID(GUID_NULL, app_data.parent_app_guid()));
+  EXPECT_EQ(expected_is_machine, app_data.is_machine_app());
+  EXPECT_TRUE(!app_data.version().IsEmpty());
+  EXPECT_TRUE(!app_data.previous_version().IsEmpty());
+
+  EXPECT_EQ(1, app_request_data.num_ping_events());
+  return *app_request_data.ping_events_begin();
+}
+
+inline const PingEvent& GetSingleEventFromRequest(const Request& request,
+                                                  const GUID& expected_app_guid,
+                                                  bool expected_is_machine) {
+  EXPECT_EQ(expected_is_machine, request.is_machine());
+  EXPECT_TRUE(!request.machine_id().IsEmpty() || !expected_is_machine);
+  EXPECT_TRUE(!request.user_id().IsEmpty());
+  EXPECT_TRUE(!request.version().IsEmpty());
+  EXPECT_TRUE(!request.os_version().IsEmpty());
+  // Skip checking request.os_service_pack() as it can be empty for RTM.
+#if defined(DEBUG) || !OFFICIAL_BUILD
+  EXPECT_TRUE(!request.test_source().IsEmpty());
+#else
+  EXPECT_TRUE(request.test_source().IsEmpty());
+#endif
+  EXPECT_TRUE(!request.request_id().IsEmpty());
+  EXPECT_EQ(1, request.get_request_count());
+  return GetSingleEventFromAppRequest(*request.app_requests_begin(),
+                                      expected_app_guid,
+                                      expected_is_machine);
+}
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_PING_MOCK_H__
diff --git a/worker/ping_unittest.cc b/worker/ping_unittest.cc
index 5d65796..b3bd353 100644
--- a/worker/ping_unittest.cc
+++ b/worker/ping_unittest.cc
@@ -1,172 +1,172 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <objbase.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/error.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/thread_pool.h"

-#include "omaha/common/timer.h"

-#include "omaha/goopdate/request.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/ping.h"

-

-namespace omaha {

-

-// Sends a ping when run in a thread pool.

-class PingJob : public UserWorkItem {

- public:

-  PingJob(Ping* ping, Request* request, HRESULT* result)

-      : ping_(ping),

-        request_(request),

-        result_(result) {}

-

- private:

-  virtual void DoProcess() {

-    scoped_co_init init_com_apt(COINIT_MULTITHREADED);

-    *result_ = ping_->SendPing(request_);

-  }

-

-  Ping* ping_;

-  Request* request_;

-  HRESULT* result_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(PingJob);

-};

-

-class PingTest : public testing::Test {

- public:

-  PingTest() : ping_result_(E_FAIL) {}

-

- protected:

-  virtual void SetUp() {

-    ping_result_ = E_FAIL;

-    thread_pool_.reset(new ThreadPool);

-    EXPECT_HRESULT_SUCCEEDED(thread_pool_->Initialize(kShutdownDelayMs));

-

-    ping_.reset(new Ping);

-

-    AppData data(StringToGuid(_T("{C6E96DF3-BFEA-4403-BAA7-8920CE0B494A}")),

-                              true);

-    CreateTestAppData(&data);

-    request_.reset(CreateRequest(true,

-                                 data,

-                                 PingEvent::EVENT_INSTALL_DOWNLOAD_FINISH,

-                                 PingEvent::EVENT_RESULT_SUCCESS,

-                                 0));

-    ASSERT_TRUE(request_.get());

-  }

-

-  virtual void TearDown() {

-    // ThreadPool destructor blocks waiting for the work items to complete.

-    thread_pool_.reset();

-    request_.reset();

-    ping_.reset();

-  }

-

-  void CreateTestAppData(AppData* expected_app) {

-    ASSERT_TRUE(expected_app != NULL);

-    expected_app->set_version(_T("1.1.1.3"));

-    expected_app->set_previous_version(_T("1.0.0.0"));

-    expected_app->set_language(_T("abc"));

-    expected_app->set_did_run(AppData::ACTIVE_RUN);

-    expected_app->set_ap(_T("Test ap"));

-    expected_app->set_tt_token(_T("Test TT Token"));

-    expected_app->set_iid(

-        StringToGuid(_T("{F723495F-8ACF-4746-8240-643741C797B5}")));

-    expected_app->set_brand_code(_T("GOOG"));

-    expected_app->set_client_id(_T("someclient"));

-  }

-

-  Request* CreateRequest(bool is_machine,

-                         const AppData& app,

-                         PingEvent::Types type,

-                         PingEvent::Results result,

-                         int error_code) {

-    scoped_ptr<Request> req(new Request(is_machine));

-

-    AppRequestData app_request_data(app);

-    PingEvent ping_event(type,

-                         result,

-                         error_code,

-                         8675309,

-                         app.previous_version());

-    app_request_data.AddPingEvent(ping_event);

-    AppRequest app_request(app_request_data);

-    req->AddAppRequest(app_request);

-    return req.release();

-  }

-

-  HRESULT ping_result_;

-  scoped_ptr<ThreadPool> thread_pool_;

-  scoped_ptr<Ping> ping_;

-  scoped_ptr<Request> request_;

-

-  static const int kShutdownDelayMs = 60 * 1000;  // 60 seconds.

-};

-

-TEST_F(PingTest, SendPing) {

-  // The same Ping instance can send multiple pings.

-  EXPECT_HRESULT_SUCCEEDED(ping_->SendPing(request_.get()));

-  EXPECT_HRESULT_SUCCEEDED(ping_->SendPing(request_.get()));

-}

-

-// Runs a ping instance in a thread pool and attempts to cancel it.

-// Either the ping succeeds or it is canceled.

-TEST_F(PingTest, CancelPing) {

-  scoped_ptr<UserWorkItem> work_item(new PingJob(ping_.get(),

-                                                 request_.get(),

-                                                 &ping_result_));

-  EXPECT_HRESULT_SUCCEEDED(thread_pool_->QueueUserWorkItem(work_item.get(),

-                           WT_EXECUTEDEFAULT));

-  work_item.release();

-

-  // Sleep for a while to give the ping some time to run.

-  ::Sleep(100);

-  EXPECT_HRESULT_SUCCEEDED(ping_->Cancel());

-

-  // Wait for the ping work item to complete.

-  LowResTimer timer(true);

-  while (thread_pool_->HasWorkItems() && timer.GetSeconds() <= 60) {

-    ::Sleep(20);

-  }

-

-  EXPECT_TRUE(SUCCEEDED(ping_result_) ||

-              ping_result_ == OMAHA_NET_E_REQUEST_CANCELLED);

-}

-

-TEST_F(PingTest, SendEmptyPing) {

-  Request req(false);

-  req.AddAppRequest(AppRequest(AppRequestData(AppData())));

-  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_NO_DATA), ping_->SendPing(&req));

-}

-

-TEST_F(PingTest, SendPing_GoogleUpdateEulaNotAccepted) {

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-  OverrideRegistryHives(kRegistryHiveOverrideRoot);

-

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_EQ(GOOPDATE_E_CANNOT_USE_NETWORK, ping_->SendPing(request_.get()));

-

-  RestoreRegistryHives();

-  RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <objbase.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/error.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/thread_pool.h"
+#include "omaha/common/timer.h"
+#include "omaha/goopdate/request.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/ping.h"
+
+namespace omaha {
+
+// Sends a ping when run in a thread pool.
+class PingJob : public UserWorkItem {
+ public:
+  PingJob(Ping* ping, Request* request, HRESULT* result)
+      : ping_(ping),
+        request_(request),
+        result_(result) {}
+
+ private:
+  virtual void DoProcess() {
+    scoped_co_init init_com_apt(COINIT_MULTITHREADED);
+    *result_ = ping_->SendPing(request_);
+  }
+
+  Ping* ping_;
+  Request* request_;
+  HRESULT* result_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(PingJob);
+};
+
+class PingTest : public testing::Test {
+ public:
+  PingTest() : ping_result_(E_FAIL) {}
+
+ protected:
+  virtual void SetUp() {
+    ping_result_ = E_FAIL;
+    thread_pool_.reset(new ThreadPool);
+    EXPECT_HRESULT_SUCCEEDED(thread_pool_->Initialize(kShutdownDelayMs));
+
+    ping_.reset(new Ping);
+
+    AppData data(StringToGuid(_T("{C6E96DF3-BFEA-4403-BAA7-8920CE0B494A}")),
+                              true);
+    CreateTestAppData(&data);
+    request_.reset(CreateRequest(true,
+                                 data,
+                                 PingEvent::EVENT_INSTALL_DOWNLOAD_FINISH,
+                                 PingEvent::EVENT_RESULT_SUCCESS,
+                                 0));
+    ASSERT_TRUE(request_.get());
+  }
+
+  virtual void TearDown() {
+    // ThreadPool destructor blocks waiting for the work items to complete.
+    thread_pool_.reset();
+    request_.reset();
+    ping_.reset();
+  }
+
+  void CreateTestAppData(AppData* expected_app) {
+    ASSERT_TRUE(expected_app != NULL);
+    expected_app->set_version(_T("1.1.1.3"));
+    expected_app->set_previous_version(_T("1.0.0.0"));
+    expected_app->set_language(_T("abc"));
+    expected_app->set_did_run(AppData::ACTIVE_RUN);
+    expected_app->set_ap(_T("Test ap"));
+    expected_app->set_tt_token(_T("Test TT Token"));
+    expected_app->set_iid(
+        StringToGuid(_T("{F723495F-8ACF-4746-8240-643741C797B5}")));
+    expected_app->set_brand_code(_T("GOOG"));
+    expected_app->set_client_id(_T("someclient"));
+  }
+
+  Request* CreateRequest(bool is_machine,
+                         const AppData& app,
+                         PingEvent::Types type,
+                         PingEvent::Results result,
+                         int error_code) {
+    scoped_ptr<Request> req(new Request(is_machine));
+
+    AppRequestData app_request_data(app);
+    PingEvent ping_event(type,
+                         result,
+                         error_code,
+                         8675309,
+                         app.previous_version());
+    app_request_data.AddPingEvent(ping_event);
+    AppRequest app_request(app_request_data);
+    req->AddAppRequest(app_request);
+    return req.release();
+  }
+
+  HRESULT ping_result_;
+  scoped_ptr<ThreadPool> thread_pool_;
+  scoped_ptr<Ping> ping_;
+  scoped_ptr<Request> request_;
+
+  static const int kShutdownDelayMs = 60 * 1000;  // 60 seconds.
+};
+
+TEST_F(PingTest, SendPing) {
+  // The same Ping instance can send multiple pings.
+  EXPECT_HRESULT_SUCCEEDED(ping_->SendPing(request_.get()));
+  EXPECT_HRESULT_SUCCEEDED(ping_->SendPing(request_.get()));
+}
+
+// Runs a ping instance in a thread pool and attempts to cancel it.
+// Either the ping succeeds or it is canceled.
+TEST_F(PingTest, CancelPing) {
+  scoped_ptr<UserWorkItem> work_item(new PingJob(ping_.get(),
+                                                 request_.get(),
+                                                 &ping_result_));
+  EXPECT_HRESULT_SUCCEEDED(thread_pool_->QueueUserWorkItem(work_item.get(),
+                           WT_EXECUTEDEFAULT));
+  work_item.release();
+
+  // Sleep for a while to give the ping some time to run.
+  ::Sleep(100);
+  EXPECT_HRESULT_SUCCEEDED(ping_->Cancel());
+
+  // Wait for the ping work item to complete.
+  LowResTimer timer(true);
+  while (thread_pool_->HasWorkItems() && timer.GetSeconds() <= 60) {
+    ::Sleep(20);
+  }
+
+  EXPECT_TRUE(SUCCEEDED(ping_result_) ||
+              ping_result_ == OMAHA_NET_E_REQUEST_CANCELLED);
+}
+
+TEST_F(PingTest, SendEmptyPing) {
+  Request req(false);
+  req.AddAppRequest(AppRequest(AppRequestData(AppData())));
+  EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_NO_DATA), ping_->SendPing(&req));
+}
+
+TEST_F(PingTest, SendPing_GoogleUpdateEulaNotAccepted) {
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+  OverrideRegistryHives(kRegistryHiveOverrideRoot);
+
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_EQ(GOOPDATE_E_CANNOT_USE_NETWORK, ping_->SendPing(request_.get()));
+
+  RestoreRegistryHives();
+  RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+}
+
+}  // namespace omaha
diff --git a/worker/ping_utils.cc b/worker/ping_utils.cc
index 0f0bebd..a15e779 100644
--- a/worker/ping_utils.cc
+++ b/worker/ping_utils.cc
@@ -1,293 +1,293 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/worker/ping_utils.h"

-#include <atlstr.h>

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/application_manager.h"

-#include "omaha/worker/app_request.h"

-#include "omaha/worker/app_request_data.h"

-#include "omaha/worker/job.h"

-#include "omaha/worker/ping.h"

-#include "omaha/worker/ping_event.h"

-#include "omaha/worker/product_data.h"

-

-namespace omaha {

-

-namespace ping_utils {

-

-// If version is NULL, the current version will be used.

-HRESULT SendGoopdatePing(bool is_machine,

-                         const CommandLineExtraArgs& extra_args,

-                         PingEvent::Types type,

-                         HRESULT result,

-                         int extra_code1,

-                         const TCHAR* version,

-                         Ping* ping) {

-  CORE_LOG(L2, (_T("[SendGoopdatePing]")));

-  ASSERT1(ping);

-

-  CString previous_version;

-  AppRequestData app_request_data_goopdate;

-  BuildGoogleUpdateAppRequestData(is_machine,

-                                  extra_args,

-                                  &previous_version,

-                                  &app_request_data_goopdate);

-

-  PingEvent::Results event_result = (S_OK == result) ?

-                                    PingEvent::EVENT_RESULT_SUCCESS :

-                                    PingEvent::EVENT_RESULT_ERROR;

-

-  PingEvent ping_event(type,

-                       event_result,

-                       result,

-                       extra_code1,

-                       previous_version);

-

-  app_request_data_goopdate.AddPingEvent(ping_event);

-

-  Request request(is_machine);

-  if (version) {

-    request.set_version(version);

-  }

-

-  AppRequest app_request(app_request_data_goopdate);

-  request.AddAppRequest(app_request);

-

-  HRESULT hr = ping->SendPing(&request);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[SendPing failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-// Initializes an AppRequest structure with information about

-// GoogleUpdate. If extra contains data, its values are used. Otherwise,

-// attempts to obtain data from the registry.

-void BuildGoogleUpdateAppRequestData(bool is_machine,

-                                     const CommandLineExtraArgs& extra_args,

-                                     CString* previous_version,

-                                     AppRequestData* app_request_data) {

-  CORE_LOG(L3, (_T("[Ping::BuildGoogleUpdateAppRequest]")));

-

-  ASSERT1(app_request_data);

-

-  if (previous_version) {

-    *previous_version = _T("");

-  }

-

-  AppData app_data_goopdate(kGoopdateGuid, is_machine);

-  app_data_goopdate.set_version(GetVersionString());

-

-  AppManager app_manager(is_machine);

-  ProductData product_data;

-  // TODO(omaha): Should we just call ReadAppDataFromStore?

-  HRESULT hr = app_manager.ReadProductDataFromStore(kGoopdateGuid,

-                                                    &product_data);

-  if (SUCCEEDED(hr)) {

-    if (previous_version) {

-      *previous_version = product_data.app_data().previous_version();

-    }

-    app_data_goopdate.set_iid(product_data.app_data().iid());

-    app_data_goopdate.set_brand_code(product_data.app_data().brand_code());

-    app_data_goopdate.set_client_id(product_data.app_data().client_id());

-    app_data_goopdate.set_did_run(product_data.app_data().did_run());

-  } else {

-    CORE_LOG(LEVEL_WARNING, (_T("[ReadProductDataFromStore failed]")

-                             _T("[0x%x][%s]"), hr, kGoogleUpdateAppId));

-

-    // Use branding data from the command line if present.

-    // We do not want to use branding data from the command line if this is not

-    // the first install of Google Update.

-    if (!extra_args.brand_code.IsEmpty()) {

-      app_data_goopdate.set_brand_code(extra_args.brand_code);

-    }

-    if (!extra_args.client_id.IsEmpty()) {

-      app_data_goopdate.set_client_id(extra_args.client_id);

-    }

-  }

-

-  // Always use the installation ID data from the command line if present.

-  if (GUID_NULL != extra_args.installation_id) {

-    app_data_goopdate.set_iid(extra_args.installation_id);

-  }

-

-  AppRequestData app_request_data_temp(app_data_goopdate);

-  *app_request_data = app_request_data_temp;

-}

-

-HRESULT SendPostSetupPing(HRESULT result,

-                          int extra_code1,

-                          const CString& previous_version,

-                          bool is_machine,

-                          bool is_self_update,

-                          const CommandLineExtraArgs& extra,

-                          Ping* ping) {

-  CORE_LOG(L3, (_T("[Ping::SendPostSetupPing]")));

-  ASSERT1(ping);

-

-  scoped_ptr<Request> request(new Request(is_machine));

-  AppRequestData app_request_data;

-  BuildGoogleUpdateAppRequestData(

-      is_machine,

-      extra,

-      NULL,

-      &app_request_data);

-

-  const PingEvent::Results event_result = (S_OK == result) ?

-                                          PingEvent::EVENT_RESULT_SUCCESS :

-                                          PingEvent::EVENT_RESULT_ERROR;

-  const PingEvent::Types type = is_self_update ?

-                                PingEvent::EVENT_SETUP_UPDATE_COMPLETE :

-                                PingEvent::EVENT_SETUP_INSTALL_COMPLETE;

-

-  PingEvent ping_event(type,

-                       event_result,

-                       result,

-                       extra_code1,

-                       previous_version);

-  app_request_data.AddPingEvent(ping_event);

-

-  if (is_self_update) {

-    // In case of self updates we also indicate that we completed the update

-    // job started by the previous version of Omaha.

-    PingEvent ping_event2(PingEvent::EVENT_UPDATE_COMPLETE,

-                          event_result,

-                          result,

-                          extra_code1,

-                          previous_version);

-    app_request_data.AddPingEvent(ping_event2);

-  }

-

-  AppRequest app_request(app_request_data);

-  request->AddAppRequest(app_request);

-

-  HRESULT hr = ping->SendPing(request.get());

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[SendSetupPing(completed) failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-

-PingEvent::Results CompletionStatusToPingEventResult(

-    JobCompletionStatus status) {

-  PingEvent::Results result = PingEvent::EVENT_RESULT_ERROR;

-  switch (status) {

-    case COMPLETION_SUCCESS:

-      result = PingEvent::EVENT_RESULT_SUCCESS;

-      break;

-    case COMPLETION_SUCCESS_REBOOT_REQUIRED:

-      result = PingEvent::EVENT_RESULT_SUCCESS_REBOOT;

-      break;

-    case COMPLETION_ERROR:

-      result = PingEvent::EVENT_RESULT_ERROR;

-      break;

-    case COMPLETION_INSTALLER_ERROR_MSI:

-      result = PingEvent::EVENT_RESULT_INSTALLER_ERROR_MSI;

-      break;

-    case COMPLETION_INSTALLER_ERROR_SYSTEM:

-      result = PingEvent::EVENT_RESULT_INSTALLER_ERROR_SYSTEM;

-      break;

-    case COMPLETION_INSTALLER_ERROR_OTHER:

-      result = PingEvent::EVENT_RESULT_INSTALLER_ERROR_OTHER;

-      break;

-    case COMPLETION_CANCELLED:

-      result = PingEvent::EVENT_RESULT_CANCELLED;

-      break;

-    default:

-      ASSERT1(false);

-      break;

-  }

-  return result;

-}

-

-HRESULT BuildCompletedPingForAllProducts(const ProductDataVector& products,

-                                         bool is_update,

-                                         const CompletionInfo& info,

-                                         Request* request) {

-  CORE_LOG(L2, (_T("[BuildCompletedPingForAllProducts]")));

-  ASSERT1(request);

-

-  PingEvent::Types type = is_update ? PingEvent::EVENT_UPDATE_COMPLETE :

-                                      PingEvent::EVENT_INSTALL_COMPLETE;

-  PingEvent::Results result = CompletionStatusToPingEventResult(info.status);

-  for (size_t i = 0; i < products.size(); ++i) {

-    const ProductData& product_data = products[i];

-    AppRequestData app_request_data(product_data.app_data());

-

-    // Create and add the ping event.

-    CString previous_version = app_request_data.app_data().previous_version();

-    // TODO(omaha): Remove this value when circular log buffer is implemented.

-    // This value must not be a valid Job::JobState.

-    const int kAppProductsPingJobState = 0xff;

-    PingEvent ping_event(type,

-                         result,

-                         info.error_code,

-                         Job::kJobStateExtraCodeMask | kAppProductsPingJobState,

-                         previous_version);

-    app_request_data.AddPingEvent(ping_event);

-

-    AppRequest app_request(app_request_data);

-    request->AddAppRequest(app_request);

-  }

-  ASSERT1(products.size() ==

-          static_cast<size_t>(request->get_request_count()));

-  return S_OK;

-}

-

-HRESULT SendCompletedPingsForAllProducts(const ProductDataVector& products,

-                                         bool is_machine,

-                                         bool is_update,

-                                         const CompletionInfo& info,

-                                         Ping* ping) {

-  CORE_LOG(L2, (_T("[SendCompletedPingsForAllProducts]")));

-  ASSERT1(ping);

-

-  scoped_ptr<Request> request(new Request(is_machine));

-  HRESULT hr = BuildCompletedPingForAllProducts(products,

-                                                is_update,

-                                                info,

-                                                request.get());

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[BuildCompletedPingForAllProducts failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (!products.empty()) {

-    HRESULT hr = ping->SendPing(request.get());

-    if (FAILED(hr)) {

-      CORE_LOG(LE, (_T("[SendPing failed][0x%08x]"), hr));

-      return hr;

-    }

-  }

-

-  return S_OK;

-}

-

-}  // namespace ping_utils

-

-}  // namespace omaha

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/worker/ping_utils.h"
+#include <atlstr.h>
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/application_manager.h"
+#include "omaha/worker/app_request.h"
+#include "omaha/worker/app_request_data.h"
+#include "omaha/worker/job.h"
+#include "omaha/worker/ping.h"
+#include "omaha/worker/ping_event.h"
+#include "omaha/worker/product_data.h"
+
+namespace omaha {
+
+namespace ping_utils {
+
+// If version is NULL, the current version will be used.
+HRESULT SendGoopdatePing(bool is_machine,
+                         const CommandLineExtraArgs& extra_args,
+                         PingEvent::Types type,
+                         HRESULT result,
+                         int extra_code1,
+                         const TCHAR* version,
+                         Ping* ping) {
+  CORE_LOG(L2, (_T("[SendGoopdatePing]")));
+  ASSERT1(ping);
+
+  CString previous_version;
+  AppRequestData app_request_data_goopdate;
+  BuildGoogleUpdateAppRequestData(is_machine,
+                                  extra_args,
+                                  &previous_version,
+                                  &app_request_data_goopdate);
+
+  PingEvent::Results event_result = (S_OK == result) ?
+                                    PingEvent::EVENT_RESULT_SUCCESS :
+                                    PingEvent::EVENT_RESULT_ERROR;
+
+  PingEvent ping_event(type,
+                       event_result,
+                       result,
+                       extra_code1,
+                       previous_version);
+
+  app_request_data_goopdate.AddPingEvent(ping_event);
+
+  Request request(is_machine);
+  if (version) {
+    request.set_version(version);
+  }
+
+  AppRequest app_request(app_request_data_goopdate);
+  request.AddAppRequest(app_request);
+
+  HRESULT hr = ping->SendPing(&request);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[SendPing failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+// Initializes an AppRequest structure with information about
+// GoogleUpdate. If extra contains data, its values are used. Otherwise,
+// attempts to obtain data from the registry.
+void BuildGoogleUpdateAppRequestData(bool is_machine,
+                                     const CommandLineExtraArgs& extra_args,
+                                     CString* previous_version,
+                                     AppRequestData* app_request_data) {
+  CORE_LOG(L3, (_T("[Ping::BuildGoogleUpdateAppRequest]")));
+
+  ASSERT1(app_request_data);
+
+  if (previous_version) {
+    *previous_version = _T("");
+  }
+
+  AppData app_data_goopdate(kGoopdateGuid, is_machine);
+  app_data_goopdate.set_version(GetVersionString());
+
+  AppManager app_manager(is_machine);
+  ProductData product_data;
+  // TODO(omaha): Should we just call ReadAppDataFromStore?
+  HRESULT hr = app_manager.ReadProductDataFromStore(kGoopdateGuid,
+                                                    &product_data);
+  if (SUCCEEDED(hr)) {
+    if (previous_version) {
+      *previous_version = product_data.app_data().previous_version();
+    }
+    app_data_goopdate.set_iid(product_data.app_data().iid());
+    app_data_goopdate.set_brand_code(product_data.app_data().brand_code());
+    app_data_goopdate.set_client_id(product_data.app_data().client_id());
+    app_data_goopdate.set_did_run(product_data.app_data().did_run());
+  } else {
+    CORE_LOG(LEVEL_WARNING, (_T("[ReadProductDataFromStore failed]")
+                             _T("[0x%x][%s]"), hr, kGoogleUpdateAppId));
+
+    // Use branding data from the command line if present.
+    // We do not want to use branding data from the command line if this is not
+    // the first install of Google Update.
+    if (!extra_args.brand_code.IsEmpty()) {
+      app_data_goopdate.set_brand_code(extra_args.brand_code);
+    }
+    if (!extra_args.client_id.IsEmpty()) {
+      app_data_goopdate.set_client_id(extra_args.client_id);
+    }
+  }
+
+  // Always use the installation ID data from the command line if present.
+  if (GUID_NULL != extra_args.installation_id) {
+    app_data_goopdate.set_iid(extra_args.installation_id);
+  }
+
+  AppRequestData app_request_data_temp(app_data_goopdate);
+  *app_request_data = app_request_data_temp;
+}
+
+HRESULT SendPostSetupPing(HRESULT result,
+                          int extra_code1,
+                          const CString& previous_version,
+                          bool is_machine,
+                          bool is_self_update,
+                          const CommandLineExtraArgs& extra,
+                          Ping* ping) {
+  CORE_LOG(L3, (_T("[Ping::SendPostSetupPing]")));
+  ASSERT1(ping);
+
+  scoped_ptr<Request> request(new Request(is_machine));
+  AppRequestData app_request_data;
+  BuildGoogleUpdateAppRequestData(
+      is_machine,
+      extra,
+      NULL,
+      &app_request_data);
+
+  const PingEvent::Results event_result = (S_OK == result) ?
+                                          PingEvent::EVENT_RESULT_SUCCESS :
+                                          PingEvent::EVENT_RESULT_ERROR;
+  const PingEvent::Types type = is_self_update ?
+                                PingEvent::EVENT_SETUP_UPDATE_COMPLETE :
+                                PingEvent::EVENT_SETUP_INSTALL_COMPLETE;
+
+  PingEvent ping_event(type,
+                       event_result,
+                       result,
+                       extra_code1,
+                       previous_version);
+  app_request_data.AddPingEvent(ping_event);
+
+  if (is_self_update) {
+    // In case of self updates we also indicate that we completed the update
+    // job started by the previous version of Omaha.
+    PingEvent ping_event2(PingEvent::EVENT_UPDATE_COMPLETE,
+                          event_result,
+                          result,
+                          extra_code1,
+                          previous_version);
+    app_request_data.AddPingEvent(ping_event2);
+  }
+
+  AppRequest app_request(app_request_data);
+  request->AddAppRequest(app_request);
+
+  HRESULT hr = ping->SendPing(request.get());
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[SendSetupPing(completed) failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+
+PingEvent::Results CompletionStatusToPingEventResult(
+    JobCompletionStatus status) {
+  PingEvent::Results result = PingEvent::EVENT_RESULT_ERROR;
+  switch (status) {
+    case COMPLETION_SUCCESS:
+      result = PingEvent::EVENT_RESULT_SUCCESS;
+      break;
+    case COMPLETION_SUCCESS_REBOOT_REQUIRED:
+      result = PingEvent::EVENT_RESULT_SUCCESS_REBOOT;
+      break;
+    case COMPLETION_ERROR:
+      result = PingEvent::EVENT_RESULT_ERROR;
+      break;
+    case COMPLETION_INSTALLER_ERROR_MSI:
+      result = PingEvent::EVENT_RESULT_INSTALLER_ERROR_MSI;
+      break;
+    case COMPLETION_INSTALLER_ERROR_SYSTEM:
+      result = PingEvent::EVENT_RESULT_INSTALLER_ERROR_SYSTEM;
+      break;
+    case COMPLETION_INSTALLER_ERROR_OTHER:
+      result = PingEvent::EVENT_RESULT_INSTALLER_ERROR_OTHER;
+      break;
+    case COMPLETION_CANCELLED:
+      result = PingEvent::EVENT_RESULT_CANCELLED;
+      break;
+    default:
+      ASSERT1(false);
+      break;
+  }
+  return result;
+}
+
+HRESULT BuildCompletedPingForAllProducts(const ProductDataVector& products,
+                                         bool is_update,
+                                         const CompletionInfo& info,
+                                         Request* request) {
+  CORE_LOG(L2, (_T("[BuildCompletedPingForAllProducts]")));
+  ASSERT1(request);
+
+  PingEvent::Types type = is_update ? PingEvent::EVENT_UPDATE_COMPLETE :
+                                      PingEvent::EVENT_INSTALL_COMPLETE;
+  PingEvent::Results result = CompletionStatusToPingEventResult(info.status);
+  for (size_t i = 0; i < products.size(); ++i) {
+    const ProductData& product_data = products[i];
+    AppRequestData app_request_data(product_data.app_data());
+
+    // Create and add the ping event.
+    CString previous_version = app_request_data.app_data().previous_version();
+    // TODO(omaha): Remove this value when circular log buffer is implemented.
+    // This value must not be a valid Job::JobState.
+    const int kAppProductsPingJobState = 0xff;
+    PingEvent ping_event(type,
+                         result,
+                         info.error_code,
+                         Job::kJobStateExtraCodeMask | kAppProductsPingJobState,
+                         previous_version);
+    app_request_data.AddPingEvent(ping_event);
+
+    AppRequest app_request(app_request_data);
+    request->AddAppRequest(app_request);
+  }
+  ASSERT1(products.size() ==
+          static_cast<size_t>(request->get_request_count()));
+  return S_OK;
+}
+
+HRESULT SendCompletedPingsForAllProducts(const ProductDataVector& products,
+                                         bool is_machine,
+                                         bool is_update,
+                                         const CompletionInfo& info,
+                                         Ping* ping) {
+  CORE_LOG(L2, (_T("[SendCompletedPingsForAllProducts]")));
+  ASSERT1(ping);
+
+  scoped_ptr<Request> request(new Request(is_machine));
+  HRESULT hr = BuildCompletedPingForAllProducts(products,
+                                                is_update,
+                                                info,
+                                                request.get());
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[BuildCompletedPingForAllProducts failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (!products.empty()) {
+    HRESULT hr = ping->SendPing(request.get());
+    if (FAILED(hr)) {
+      CORE_LOG(LE, (_T("[SendPing failed][0x%08x]"), hr));
+      return hr;
+    }
+  }
+
+  return S_OK;
+}
+
+}  // namespace ping_utils
+
+}  // namespace omaha
+
diff --git a/worker/ping_utils.h b/worker/ping_utils.h
index 6700140..c72b134 100644
--- a/worker/ping_utils.h
+++ b/worker/ping_utils.h
@@ -1,76 +1,76 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_PING_UTILS_H__

-#define OMAHA_WORKER_PING_UTILS_H__

-

-#include <atlstr.h>

-#include <windows.h>

-#include "omaha/worker/ping_event.h"

-#include "omaha/worker/product_data.h"

-

-namespace omaha {

-

-class AppRequestData;

-class Ping;

-class Request;

-enum JobCompletionStatus;

-struct CommandLineExtraArgs;

-struct CompletionInfo;

-

-// Utility functions for Ping.

-namespace ping_utils {

-

-// TODO(omaha): Put common params in the same order.

-HRESULT SendGoopdatePing(bool is_machine,

-                         const CommandLineExtraArgs& extra_args,

-                         PingEvent::Types type,

-                         HRESULT error,

-                         int extra_code1,

-                         const TCHAR* version,

-                         Ping* ping);

-

-HRESULT SendPostSetupPing(HRESULT result,

-                          int extra_code1,

-                          const CString& previous_version,

-                          bool is_machine,

-                          bool is_interactive,

-                          const CommandLineExtraArgs& extra,

-                          Ping* ping);

-

-PingEvent::Results CompletionStatusToPingEventResult(

-    JobCompletionStatus status);

-

-HRESULT BuildCompletedPingForAllProducts(const ProductDataVector& products,

-                                         bool is_update,

-                                         const CompletionInfo& info,

-                                         Request* request);

-

-HRESULT SendCompletedPingsForAllProducts(const ProductDataVector& products,

-                                         bool is_machine,

-                                         bool is_update,

-                                         const CompletionInfo& info,

-                                         Ping* ping);

-

-void BuildGoogleUpdateAppRequestData(bool is_machine,

-                                     const CommandLineExtraArgs& extra_args,

-                                     CString* previous_version,

-                                     AppRequestData* app_request_data);

-

-}  // namespace ping_utils

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_PING_UTILS_H__

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_PING_UTILS_H__
+#define OMAHA_WORKER_PING_UTILS_H__
+
+#include <atlstr.h>
+#include <windows.h>
+#include "omaha/worker/ping_event.h"
+#include "omaha/worker/product_data.h"
+
+namespace omaha {
+
+class AppRequestData;
+class Ping;
+class Request;
+enum JobCompletionStatus;
+struct CommandLineExtraArgs;
+struct CompletionInfo;
+
+// Utility functions for Ping.
+namespace ping_utils {
+
+// TODO(omaha): Put common params in the same order.
+HRESULT SendGoopdatePing(bool is_machine,
+                         const CommandLineExtraArgs& extra_args,
+                         PingEvent::Types type,
+                         HRESULT error,
+                         int extra_code1,
+                         const TCHAR* version,
+                         Ping* ping);
+
+HRESULT SendPostSetupPing(HRESULT result,
+                          int extra_code1,
+                          const CString& previous_version,
+                          bool is_machine,
+                          bool is_interactive,
+                          const CommandLineExtraArgs& extra,
+                          Ping* ping);
+
+PingEvent::Results CompletionStatusToPingEventResult(
+    JobCompletionStatus status);
+
+HRESULT BuildCompletedPingForAllProducts(const ProductDataVector& products,
+                                         bool is_update,
+                                         const CompletionInfo& info,
+                                         Request* request);
+
+HRESULT SendCompletedPingsForAllProducts(const ProductDataVector& products,
+                                         bool is_machine,
+                                         bool is_update,
+                                         const CompletionInfo& info,
+                                         Ping* ping);
+
+void BuildGoogleUpdateAppRequestData(bool is_machine,
+                                     const CommandLineExtraArgs& extra_args,
+                                     CString* previous_version,
+                                     AppRequestData* app_request_data);
+
+}  // namespace ping_utils
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_PING_UTILS_H__
diff --git a/worker/ping_utils_unittest.cc b/worker/ping_utils_unittest.cc
index ceb8f65..8dc57f6 100644
--- a/worker/ping_utils_unittest.cc
+++ b/worker/ping_utils_unittest.cc
@@ -1,277 +1,277 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <windows.h>

-#include <objbase.h>

-#include "base/scoped_ptr.h"

-#include "omaha/common/utils.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/job.h"

-#include "omaha/worker/ping.h"

-#include "omaha/worker/ping_utils.h"

-#include "omaha/worker/product_data.h"

-

-namespace omaha {

-

-class PingUtilsTest : public testing::Test {

- protected:

-  virtual void SetUp() {

-    ping_.reset(new Ping);

-  }

-

-  scoped_ptr<Ping> ping_;

-};

-

-TEST_F(PingUtilsTest, SendGoopdatePing) {

-  CommandLineExtraArgs extra_args;

-

-  // Test with no language.

-  EXPECT_SUCCEEDED(

-      ping_utils::SendGoopdatePing(false,

-                                   extra_args,

-                                   PingEvent::EVENT_SETUP_INSTALL_FAILURE,

-                                   S_OK,

-                                   0,

-                                   NULL,

-                                   ping_.get()));

-

-  // Test with a language.

-  extra_args.language = _T("en");

-  EXPECT_SUCCEEDED(

-      ping_utils::SendGoopdatePing(false,

-                                   extra_args,

-                                   PingEvent::EVENT_SETUP_INSTALL_FAILURE,

-                                   S_OK,

-                                   0,

-                                   NULL,

-                                   ping_.get()));

-

-  // Test with additional data.

-  CommandLineAppArgs extra;

-  extra_args.installation_id = StringToGuid(

-      _T("{98CEC468-9429-4984-AEDE-4F53C6A14869}"));

-  extra_args.language = _T("de");

-  extra_args.brand_code = _T("g00g");

-  extra_args.client_id = _T("_some_partner");

-  extra_args.browser_type = BROWSER_IE;

-  extra_args.usage_stats_enable = TRISTATE_TRUE;

-  extra_args.apps.push_back(extra);

-  EXPECT_SUCCEEDED(ping_utils::SendGoopdatePing(

-                       true,

-                       extra_args,

-                       PingEvent::EVENT_SETUP_UPDATE_FAILURE,

-                       E_FAIL,

-                       1234567890,

-                       NULL,

-                       ping_.get()));

-}

-

-TEST_F(PingUtilsTest, SendCompletedPingsForAllProducts_EmptyProducts) {

-  ProductDataVector products;

-  CompletionInfo info(COMPLETION_ERROR, 10, _T("test"));

-

-  ASSERT_HRESULT_SUCCEEDED(ping_utils::SendCompletedPingsForAllProducts(

-      products,

-      false,

-      false,

-      info,

-      ping_.get()));

-}

-

-TEST_F(PingUtilsTest, SendCompletedPingsForAllProducts) {

-  ProductDataVector products;

-

-  AppData data1(StringToGuid(_T("{E66F2139-5469-BAAD-AC99-7863798E3A0A}")),

-                false);

-  data1.set_version(_T("1.1.1.1"));

-  data1.set_previous_version(_T("1.0.0.0"));

-  data1.set_language(_T("en"));

-

-  ProductData product_data1;

-  product_data1.set_app_data(data1);

-  products.push_back(product_data1);

-

-  AppData data2(StringToGuid(_T("{E66F3140-5179-41ec-BAAD-7863798E3A0A}")),

-                false);

-  data2.set_version(_T("1.1.1.1"));

-  data2.set_previous_version(_T("1.0.0.0"));

-  data2.set_language(_T("de"));

-

-  ProductData product_data2;

-  product_data2.set_app_data(data2);

-  products.push_back(product_data2);

-

-  CompletionInfo info(COMPLETION_ERROR, 10, _T("test"));

-  ASSERT_HRESULT_SUCCEEDED(ping_utils::SendCompletedPingsForAllProducts(

-      products,

-      false,

-      false,

-      info,

-      ping_.get()));

-}

-

-void ValidateRequest(const ProductDataVector& products,

-                     const CompletionInfo& expected_info,

-                     const PingEvent::Types expected_type,

-                     const Request& actual_request) {

-  EXPECT_EQ(2, actual_request.get_request_count());

-  AppRequestVector::const_iterator iter = actual_request.app_requests_begin();

-  for (int i = 0; iter != actual_request.app_requests_end(); ++iter, ++i) {

-    const AppRequest& app_request = *iter;

-    const AppRequestData& app_request_data = app_request.request_data();

-

-    EXPECT_EQ(1, app_request_data.num_ping_events());

-    EXPECT_STREQ(GuidToString(app_request_data.app_data().app_guid()),

-                 GuidToString(products[i].app_data().app_guid()));

-    EXPECT_STREQ(app_request_data.app_data().version(),

-                 products[i].app_data().version());

-    EXPECT_STREQ(app_request_data.app_data().previous_version(),

-                 products[i].app_data().previous_version());

-    EXPECT_STREQ(app_request_data.app_data().language(),

-                 products[i].app_data().language());

-

-    PingEventVector::const_iterator iter =

-        app_request_data.ping_events_begin();

-    const PingEvent& ping_event = *iter;

-

-    EXPECT_EQ(expected_type, ping_event.event_type());

-    EXPECT_EQ(

-        ping_utils::CompletionStatusToPingEventResult(expected_info.status),

-        ping_event.event_result());

-    EXPECT_EQ(expected_info.error_code, ping_event.error_code());

-    EXPECT_EQ(app_request_data.app_data().previous_version(),

-              ping_event.previous_version());

-  }

-}

-

-TEST_F(PingUtilsTest, BuildCompletedPingForAllProducts_Failure) {

-  ProductDataVector products;

-  bool is_machine = false;

-  AppData data1(StringToGuid(_T("{E66F2139-5469-BAAD-AC99-7863798E3A0A}")),

-                is_machine);

-  data1.set_version(_T("1.1.1.1"));

-  data1.set_previous_version(_T("1.0.0.0"));

-  data1.set_language(_T("en"));

-

-  ProductData product_data1;

-  product_data1.set_app_data(data1);

-  products.push_back(product_data1);

-

-  AppData data2(StringToGuid(_T("{E66F3140-5179-41ec-BAAD-7863798E3A0A}")),

-                is_machine);

-  data2.set_version(_T("1.1.1.1"));

-  data2.set_previous_version(_T("1.0.0.0"));

-  data2.set_language(_T("de"));

-

-  ProductData product_data2;

-  product_data2.set_app_data(data2);

-  products.push_back(product_data2);

-

-  CompletionInfo info(COMPLETION_ERROR, 10, _T("test"));

-

-  Request actual_request(is_machine);

-  ASSERT_HRESULT_SUCCEEDED(ping_utils::BuildCompletedPingForAllProducts(

-      products,

-      false,

-      info,

-      &actual_request));

-  ValidateRequest(products,

-                  info,

-                  PingEvent::EVENT_INSTALL_COMPLETE,

-                  actual_request);

-}

-

-TEST_F(PingUtilsTest, BuildCompletedPingForAllProducts_Update) {

-  ProductDataVector products;

-  bool is_machine = false;

-

-  AppData data1(StringToGuid(_T("{E66F2139-5469-BAAD-AC99-7863798E3A0A}")),

-                is_machine);

-  data1.set_version(_T("1.1.1.1"));

-  data1.set_previous_version(_T("1.0.0.0"));

-  data1.set_language(_T("en"));

-

-  ProductData product_data1;

-  product_data1.set_app_data(data1);

-  products.push_back(product_data1);

-

-  AppData data2(StringToGuid(_T("{E66F3140-5179-41ec-BAAD-7863798E3A0A}")),

-                is_machine);

-  data2.set_version(_T("1.1.1.1"));

-  data2.set_previous_version(_T("1.0.0.0"));

-  data2.set_language(_T("de"));

-

-  ProductData product_data2;

-  product_data2.set_app_data(data2);

-  products.push_back(product_data2);

-

-  CompletionInfo info(COMPLETION_ERROR, 10, _T("test"));

-

-  Request actual_request(is_machine);

-  ASSERT_HRESULT_SUCCEEDED(ping_utils::BuildCompletedPingForAllProducts(

-      products,

-      true,

-      info,

-      &actual_request));

-

-  ValidateRequest(products,

-                  info,

-                  PingEvent::EVENT_UPDATE_COMPLETE,

-                  actual_request);

-}

-

-TEST_F(PingUtilsTest, BuildCompletedPingForAllProducts_Success) {

-  ProductDataVector products;

-  bool is_machine = false;

-

-  AppData data1(StringToGuid(_T("{E66F2139-5469-BAAD-AC99-7863798E3A0A}")),

-                is_machine);

-  data1.set_version(_T("1.1.1.1"));

-  data1.set_previous_version(_T("1.0.0.0"));

-  data1.set_language(_T("en"));

-

-  ProductData product_data1;

-  product_data1.set_app_data(data1);

-  products.push_back(product_data1);

-

-  AppData data2(StringToGuid(_T("{E66F3140-5179-41ec-BAAD-7863798E3A0A}")),

-                is_machine);

-  data2.set_version(_T("1.1.1.1"));

-  data2.set_previous_version(_T("1.0.0.0"));

-  data2.set_language(_T("de"));

-

-  ProductData product_data2;

-  product_data2.set_app_data(data2);

-  products.push_back(product_data2);

-

-  CompletionInfo info(COMPLETION_SUCCESS, 0, _T("test"));

-

-  Request actual_request(is_machine);

-  ASSERT_HRESULT_SUCCEEDED(ping_utils::BuildCompletedPingForAllProducts(

-      products,

-      false,

-      info,

-      &actual_request));

-

-  ValidateRequest(products,

-                  info,

-                  PingEvent::EVENT_INSTALL_COMPLETE,

-                  actual_request);

-}

-

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <windows.h>
+#include <objbase.h>
+#include "base/scoped_ptr.h"
+#include "omaha/common/utils.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/job.h"
+#include "omaha/worker/ping.h"
+#include "omaha/worker/ping_utils.h"
+#include "omaha/worker/product_data.h"
+
+namespace omaha {
+
+class PingUtilsTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    ping_.reset(new Ping);
+  }
+
+  scoped_ptr<Ping> ping_;
+};
+
+TEST_F(PingUtilsTest, SendGoopdatePing) {
+  CommandLineExtraArgs extra_args;
+
+  // Test with no language.
+  EXPECT_SUCCEEDED(
+      ping_utils::SendGoopdatePing(false,
+                                   extra_args,
+                                   PingEvent::EVENT_SETUP_INSTALL_FAILURE,
+                                   S_OK,
+                                   0,
+                                   NULL,
+                                   ping_.get()));
+
+  // Test with a language.
+  extra_args.language = _T("en");
+  EXPECT_SUCCEEDED(
+      ping_utils::SendGoopdatePing(false,
+                                   extra_args,
+                                   PingEvent::EVENT_SETUP_INSTALL_FAILURE,
+                                   S_OK,
+                                   0,
+                                   NULL,
+                                   ping_.get()));
+
+  // Test with additional data.
+  CommandLineAppArgs extra;
+  extra_args.installation_id = StringToGuid(
+      _T("{98CEC468-9429-4984-AEDE-4F53C6A14869}"));
+  extra_args.language = _T("de");
+  extra_args.brand_code = _T("g00g");
+  extra_args.client_id = _T("_some_partner");
+  extra_args.browser_type = BROWSER_IE;
+  extra_args.usage_stats_enable = TRISTATE_TRUE;
+  extra_args.apps.push_back(extra);
+  EXPECT_SUCCEEDED(ping_utils::SendGoopdatePing(
+                       true,
+                       extra_args,
+                       PingEvent::EVENT_SETUP_UPDATE_FAILURE,
+                       E_FAIL,
+                       1234567890,
+                       NULL,
+                       ping_.get()));
+}
+
+TEST_F(PingUtilsTest, SendCompletedPingsForAllProducts_EmptyProducts) {
+  ProductDataVector products;
+  CompletionInfo info(COMPLETION_ERROR, 10, _T("test"));
+
+  ASSERT_HRESULT_SUCCEEDED(ping_utils::SendCompletedPingsForAllProducts(
+      products,
+      false,
+      false,
+      info,
+      ping_.get()));
+}
+
+TEST_F(PingUtilsTest, SendCompletedPingsForAllProducts) {
+  ProductDataVector products;
+
+  AppData data1(StringToGuid(_T("{E66F2139-5469-BAAD-AC99-7863798E3A0A}")),
+                false);
+  data1.set_version(_T("1.1.1.1"));
+  data1.set_previous_version(_T("1.0.0.0"));
+  data1.set_language(_T("en"));
+
+  ProductData product_data1;
+  product_data1.set_app_data(data1);
+  products.push_back(product_data1);
+
+  AppData data2(StringToGuid(_T("{E66F3140-5179-41ec-BAAD-7863798E3A0A}")),
+                false);
+  data2.set_version(_T("1.1.1.1"));
+  data2.set_previous_version(_T("1.0.0.0"));
+  data2.set_language(_T("de"));
+
+  ProductData product_data2;
+  product_data2.set_app_data(data2);
+  products.push_back(product_data2);
+
+  CompletionInfo info(COMPLETION_ERROR, 10, _T("test"));
+  ASSERT_HRESULT_SUCCEEDED(ping_utils::SendCompletedPingsForAllProducts(
+      products,
+      false,
+      false,
+      info,
+      ping_.get()));
+}
+
+void ValidateRequest(const ProductDataVector& products,
+                     const CompletionInfo& expected_info,
+                     const PingEvent::Types expected_type,
+                     const Request& actual_request) {
+  EXPECT_EQ(2, actual_request.get_request_count());
+  AppRequestVector::const_iterator iter = actual_request.app_requests_begin();
+  for (int i = 0; iter != actual_request.app_requests_end(); ++iter, ++i) {
+    const AppRequest& app_request = *iter;
+    const AppRequestData& app_request_data = app_request.request_data();
+
+    EXPECT_EQ(1, app_request_data.num_ping_events());
+    EXPECT_STREQ(GuidToString(app_request_data.app_data().app_guid()),
+                 GuidToString(products[i].app_data().app_guid()));
+    EXPECT_STREQ(app_request_data.app_data().version(),
+                 products[i].app_data().version());
+    EXPECT_STREQ(app_request_data.app_data().previous_version(),
+                 products[i].app_data().previous_version());
+    EXPECT_STREQ(app_request_data.app_data().language(),
+                 products[i].app_data().language());
+
+    PingEventVector::const_iterator iter =
+        app_request_data.ping_events_begin();
+    const PingEvent& ping_event = *iter;
+
+    EXPECT_EQ(expected_type, ping_event.event_type());
+    EXPECT_EQ(
+        ping_utils::CompletionStatusToPingEventResult(expected_info.status),
+        ping_event.event_result());
+    EXPECT_EQ(expected_info.error_code, ping_event.error_code());
+    EXPECT_EQ(app_request_data.app_data().previous_version(),
+              ping_event.previous_version());
+  }
+}
+
+TEST_F(PingUtilsTest, BuildCompletedPingForAllProducts_Failure) {
+  ProductDataVector products;
+  bool is_machine = false;
+  AppData data1(StringToGuid(_T("{E66F2139-5469-BAAD-AC99-7863798E3A0A}")),
+                is_machine);
+  data1.set_version(_T("1.1.1.1"));
+  data1.set_previous_version(_T("1.0.0.0"));
+  data1.set_language(_T("en"));
+
+  ProductData product_data1;
+  product_data1.set_app_data(data1);
+  products.push_back(product_data1);
+
+  AppData data2(StringToGuid(_T("{E66F3140-5179-41ec-BAAD-7863798E3A0A}")),
+                is_machine);
+  data2.set_version(_T("1.1.1.1"));
+  data2.set_previous_version(_T("1.0.0.0"));
+  data2.set_language(_T("de"));
+
+  ProductData product_data2;
+  product_data2.set_app_data(data2);
+  products.push_back(product_data2);
+
+  CompletionInfo info(COMPLETION_ERROR, 10, _T("test"));
+
+  Request actual_request(is_machine);
+  ASSERT_HRESULT_SUCCEEDED(ping_utils::BuildCompletedPingForAllProducts(
+      products,
+      false,
+      info,
+      &actual_request));
+  ValidateRequest(products,
+                  info,
+                  PingEvent::EVENT_INSTALL_COMPLETE,
+                  actual_request);
+}
+
+TEST_F(PingUtilsTest, BuildCompletedPingForAllProducts_Update) {
+  ProductDataVector products;
+  bool is_machine = false;
+
+  AppData data1(StringToGuid(_T("{E66F2139-5469-BAAD-AC99-7863798E3A0A}")),
+                is_machine);
+  data1.set_version(_T("1.1.1.1"));
+  data1.set_previous_version(_T("1.0.0.0"));
+  data1.set_language(_T("en"));
+
+  ProductData product_data1;
+  product_data1.set_app_data(data1);
+  products.push_back(product_data1);
+
+  AppData data2(StringToGuid(_T("{E66F3140-5179-41ec-BAAD-7863798E3A0A}")),
+                is_machine);
+  data2.set_version(_T("1.1.1.1"));
+  data2.set_previous_version(_T("1.0.0.0"));
+  data2.set_language(_T("de"));
+
+  ProductData product_data2;
+  product_data2.set_app_data(data2);
+  products.push_back(product_data2);
+
+  CompletionInfo info(COMPLETION_ERROR, 10, _T("test"));
+
+  Request actual_request(is_machine);
+  ASSERT_HRESULT_SUCCEEDED(ping_utils::BuildCompletedPingForAllProducts(
+      products,
+      true,
+      info,
+      &actual_request));
+
+  ValidateRequest(products,
+                  info,
+                  PingEvent::EVENT_UPDATE_COMPLETE,
+                  actual_request);
+}
+
+TEST_F(PingUtilsTest, BuildCompletedPingForAllProducts_Success) {
+  ProductDataVector products;
+  bool is_machine = false;
+
+  AppData data1(StringToGuid(_T("{E66F2139-5469-BAAD-AC99-7863798E3A0A}")),
+                is_machine);
+  data1.set_version(_T("1.1.1.1"));
+  data1.set_previous_version(_T("1.0.0.0"));
+  data1.set_language(_T("en"));
+
+  ProductData product_data1;
+  product_data1.set_app_data(data1);
+  products.push_back(product_data1);
+
+  AppData data2(StringToGuid(_T("{E66F3140-5179-41ec-BAAD-7863798E3A0A}")),
+                is_machine);
+  data2.set_version(_T("1.1.1.1"));
+  data2.set_previous_version(_T("1.0.0.0"));
+  data2.set_language(_T("de"));
+
+  ProductData product_data2;
+  product_data2.set_app_data(data2);
+  products.push_back(product_data2);
+
+  CompletionInfo info(COMPLETION_SUCCESS, 0, _T("test"));
+
+  Request actual_request(is_machine);
+  ASSERT_HRESULT_SUCCEEDED(ping_utils::BuildCompletedPingForAllProducts(
+      products,
+      false,
+      info,
+      &actual_request));
+
+  ValidateRequest(products,
+                  info,
+                  PingEvent::EVENT_INSTALL_COMPLETE,
+                  actual_request);
+}
+
+
+}  // namespace omaha
diff --git a/worker/product_data.h b/worker/product_data.h
index 38601e3..bbbd2b6 100644
--- a/worker/product_data.h
+++ b/worker/product_data.h
@@ -1,66 +1,66 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// product_data.h: Class encapsulates the hierarchy of products and components.

-

-#ifndef OMAHA_WORKER_PRODUCT_DATA_H__

-#define OMAHA_WORKER_PRODUCT_DATA_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "omaha/common/debug.h"

-#include "omaha/worker/application_data.h"

-

-namespace omaha {

-

-// TODO(omaha):  This hierarchy pattern is similar between ProductData,

-// AppRequest, UpdateResponse.  We should make a common class or a template to

-// handle this instead of duplicating the pattern.

-class ProductData {

- public:

-  ProductData() {}

-  explicit ProductData(const AppData& app_data) { app_data_ = app_data; }

-

-  void set_app_data(const AppData& app_data) {

-    app_data_ = app_data;

-  }

-  const AppData& app_data() const { return app_data_; }

-  void AddComponent(const AppData& component_data) {

-    components_.push_back(component_data);

-  }

-

-  AppDataVector::const_iterator components_begin() const {

-    return components_.begin();

-  }

-

-  AppDataVector::const_iterator components_end() const {

-    return components_.end();

-  }

-

-  size_t num_components() const { return components_.size(); }

-

- private:

-  AppData app_data_;

-  AppDataVector components_;

-};

-

-typedef std::vector<ProductData> ProductDataVector;

-

-}  // namespace omaha.

-

-#endif  // OMAHA_WORKER_PRODUCT_DATA_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// product_data.h: Class encapsulates the hierarchy of products and components.
+
+#ifndef OMAHA_WORKER_PRODUCT_DATA_H__
+#define OMAHA_WORKER_PRODUCT_DATA_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "omaha/common/debug.h"
+#include "omaha/worker/application_data.h"
+
+namespace omaha {
+
+// TODO(omaha):  This hierarchy pattern is similar between ProductData,
+// AppRequest, UpdateResponse.  We should make a common class or a template to
+// handle this instead of duplicating the pattern.
+class ProductData {
+ public:
+  ProductData() {}
+  explicit ProductData(const AppData& app_data) { app_data_ = app_data; }
+
+  void set_app_data(const AppData& app_data) {
+    app_data_ = app_data;
+  }
+  const AppData& app_data() const { return app_data_; }
+  void AddComponent(const AppData& component_data) {
+    components_.push_back(component_data);
+  }
+
+  AppDataVector::const_iterator components_begin() const {
+    return components_.begin();
+  }
+
+  AppDataVector::const_iterator components_end() const {
+    return components_.end();
+  }
+
+  size_t num_components() const { return components_.size(); }
+
+ private:
+  AppData app_data_;
+  AppDataVector components_;
+};
+
+typedef std::vector<ProductData> ProductDataVector;
+
+}  // namespace omaha.
+
+#endif  // OMAHA_WORKER_PRODUCT_DATA_H__
+
diff --git a/worker/progresswnd_unittest.cc b/worker/progresswnd_unittest.cc
index d0f010e..55cac82 100644
--- a/worker/progresswnd_unittest.cc
+++ b/worker/progresswnd_unittest.cc
@@ -1,255 +1,255 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// This unit test is driving the UI through its states so that we can

-// visually inspect all the controls are there in their right state and

-// position. To go from state to state, simply close the window on the screen.

-//

-// The unit test is useful for debugging UI states so different tests are

-// enabled/disabled at compile time, depending what needs to be tested.

-

-#include <windows.h>

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/utils.h"

-#include "goopdate/google_update_idl.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/ui.h"

-

-namespace omaha {

-

-class UITest : public testing::Test,

-               public ProgressWndEvents,

-               public WaitCallbackInterface {

- protected:

-  UITest() : progress_wnd_(&progress_wnd_message_loop_, NULL) {

-  }

-

-  static void SetUpTestCase() {

-    message_loop_.set_message_handler(&message_handler_);

-    reset(ev_, ::CreateEvent(NULL, false, false, NULL));

-  }

-

-  virtual void SetUp() {

-    ASSERT_TRUE(::ResetEvent(get(ev_)));

-    ASSERT_TRUE(message_loop_.RegisterWaitForSingleObject(get(ev_), this));

-    progress_wnd_.SetEventSink(this);

-    progress_wnd_.set_product_name(_T("FooBar"));

-    EXPECT_SUCCEEDED(progress_wnd_.Initialize());

-    EXPECT_TRUE(progress_wnd_.CenterWindow(NULL));

-    progress_wnd_.SetVisible(true);

-  }

-

-  virtual void TearDown() {

-    message_loop_.UnregisterWait(get(ev_));

-  }

-

-  //

-  // ProgressWndEvents

-  //

-  virtual void DoPause() {

-  }

-

-  virtual void DoResume() {

-  }

-

-  virtual void DoClose() {

-    ASSERT_TRUE(::SetEvent(get(ev_)));

-  }

-

-  virtual void DoRestartBrowsers() {

-    ASSERT_TRUE(::SetEvent(get(ev_)));

-  }

-

-  virtual void DoReboot() {

-    ASSERT_TRUE(::SetEvent(get(ev_)));

-  }

-

-  virtual void DoLaunchBrowser(const CString&) {

-  }

-

-

-  //

-  // WaitCallbackInterface

-  //

-  virtual bool HandleSignaled(HANDLE) {

-    // Makes the message pump stop.

-    return false;

-  }

-

-  void FormatWindowTitle(const TCHAR* text) {

-    CString title;

-    progress_wnd_.GetWindowText(CStrBuf(title, 256), 256);

-    CString new_title;

-    new_title.Format(_T("%s - %s"), title, text);

-    progress_wnd_.SetWindowText(new_title);

-  }

-

-  static BasicMessageHandler message_handler_;

-  static MessageLoopWithWait message_loop_;

-  ProgressWnd progress_wnd_;

-  CMessageLoop progress_wnd_message_loop_;

-  static scoped_event ev_;

-};

-

-BasicMessageHandler UITest::message_handler_;

-MessageLoopWithWait UITest::message_loop_;

-scoped_event UITest::ev_;

-

-/*

-TEST_F(UITest, Initialize) {

-  FormatWindowTitle(_T("Initialize"));

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnWaitingToDownload) {

-  FormatWindowTitle(_T("Waiting to download"));

-  progress_wnd_.OnWaitingToDownload();

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnDownloading1) {

-  FormatWindowTitle(_T("Downloading"));

-  progress_wnd_.OnDownloading(10000, 0);

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnDownloading2) {

-  FormatWindowTitle(_T("Downloading"));

-  progress_wnd_.OnDownloading(5000, 50);

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnDownloading3) {

-  FormatWindowTitle(_T("Downloading"));

-  progress_wnd_.OnDownloading(0, 100);

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnWaitingToInstall) {

-  FormatWindowTitle(_T("Waiting to install"));

-  progress_wnd_.OnWaitingToInstall();

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnInstall) {

-  FormatWindowTitle(_T("Installing"));

-  progress_wnd_.OnInstalling();

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnPause) {

-  FormatWindowTitle(_T("Paused"));

-  progress_wnd_.OnPause();

-  message_loop_.Process();

-}

-*/

-

-TEST_F(UITest, OnCompleteSuccess) {

-  FormatWindowTitle(_T("Complete success"));

-  progress_wnd_.OnComplete(

-      COMPLETION_CODE_SUCCESS,

-      _T("Thanks for installing Gears. For more information on using ")

-      _T("Gears visit the ")

-      _T("<a=http://www.google.com/gears/>Gears</a> web site."),

-      0);

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnCompleteError) {

-  FormatWindowTitle(_T("Complete error"));

-  progress_wnd_.OnComplete(

-      COMPLETION_CODE_ERROR,

-      _T("An error occured while installing Gears: an existing copy of ")

-      _T("Gears is currently running. Please exit the software and ")

-      _T("retry installation. For more information visit the ")

-      _T("<a=http://www.google.com/gears/>Gears</a> web site."),

-      11);

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnCompleteRestartAllBrowsers) {

-  FormatWindowTitle(_T("Restart browsers"));

-  progress_wnd_.OnComplete(COMPLETION_CODE_RESTART_ALL_BROWSERS, NULL, 0);

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnCompleteReboot) {

-  FormatWindowTitle(_T("Reboot"));

-  progress_wnd_.OnComplete(COMPLETION_CODE_REBOOT, NULL, 0);

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnCompleteRestartBrowser) {

-  FormatWindowTitle(_T("Restart browser"));

-  progress_wnd_.OnComplete(COMPLETION_CODE_RESTART_BROWSER, NULL, 0);

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnCompleteRestartAllBrowsersNoticeOnly) {

-  FormatWindowTitle(_T("Restart browsers"));

-  progress_wnd_.OnComplete(COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY,

-                           NULL,

-                           0);

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnCompleteRebootNoticeOnly) {

-  FormatWindowTitle(_T("Reboot"));

-  progress_wnd_.OnComplete(COMPLETION_CODE_REBOOT_NOTICE_ONLY, NULL, 0);

-  message_loop_.Process();

-}

-

-TEST_F(UITest, OnCompleteRestartBrowserNoticeOnly) {

-  FormatWindowTitle(_T("Restart browser"));

-  progress_wnd_.OnComplete(COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY,

-                           NULL,

-                           0);

-  message_loop_.Process();

-}

-

-// Test the OnComplete can be called multiple times.

-TEST_F(UITest, OnMultipleCompletes) {

-  FormatWindowTitle(_T("Complete success"));

-  progress_wnd_.OnComplete(

-      COMPLETION_CODE_SUCCESS,

-      _T("Thanks for installing Gears. For more information on using ")

-      _T("Gears visit the ")

-      _T("<a=http://www.google.com/gears/>Gears</a> web site."),

-      0);

-

-  FormatWindowTitle(_T("Complete error"));

-  progress_wnd_.OnComplete(

-      COMPLETION_CODE_ERROR,

-      _T("An error occured while installing Gears: an existing copy of ")

-      _T("Gears is currently running. Please exit the software and ")

-      _T("retry installation. For more information visit the ")

-      _T("<a=http://www.google.com/gears/>Gears</a> web site."),

-      0);

-

-  progress_wnd_.OnComplete(

-      COMPLETION_CODE_ERROR,

-      _T("An error occured while installing Gears: an existing copy of ")

-      _T("Gears is currently running. Please exit the software and ")

-      _T("retry installation. For more information visit the ")

-      _T("<a=http://www.google.com/gears/>Gears</a> web site."),

-      0);

-

-  FormatWindowTitle(_T("Restart browsers"));

-  progress_wnd_.OnComplete(COMPLETION_CODE_RESTART_ALL_BROWSERS, NULL, 0);

-  message_loop_.Process();

-}

-

-}   // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// This unit test is driving the UI through its states so that we can
+// visually inspect all the controls are there in their right state and
+// position. To go from state to state, simply close the window on the screen.
+//
+// The unit test is useful for debugging UI states so different tests are
+// enabled/disabled at compile time, depending what needs to be tested.
+
+#include <windows.h>
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/utils.h"
+#include "goopdate/google_update_idl.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/ui.h"
+
+namespace omaha {
+
+class UITest : public testing::Test,
+               public ProgressWndEvents,
+               public WaitCallbackInterface {
+ protected:
+  UITest() : progress_wnd_(&progress_wnd_message_loop_, NULL) {
+  }
+
+  static void SetUpTestCase() {
+    message_loop_.set_message_handler(&message_handler_);
+    reset(ev_, ::CreateEvent(NULL, false, false, NULL));
+  }
+
+  virtual void SetUp() {
+    ASSERT_TRUE(::ResetEvent(get(ev_)));
+    ASSERT_TRUE(message_loop_.RegisterWaitForSingleObject(get(ev_), this));
+    progress_wnd_.SetEventSink(this);
+    progress_wnd_.set_product_name(_T("FooBar"));
+    EXPECT_SUCCEEDED(progress_wnd_.Initialize());
+    EXPECT_TRUE(progress_wnd_.CenterWindow(NULL));
+    progress_wnd_.SetVisible(true);
+  }
+
+  virtual void TearDown() {
+    message_loop_.UnregisterWait(get(ev_));
+  }
+
+  //
+  // ProgressWndEvents
+  //
+  virtual void DoPause() {
+  }
+
+  virtual void DoResume() {
+  }
+
+  virtual void DoClose() {
+    ASSERT_TRUE(::SetEvent(get(ev_)));
+  }
+
+  virtual void DoRestartBrowsers() {
+    ASSERT_TRUE(::SetEvent(get(ev_)));
+  }
+
+  virtual void DoReboot() {
+    ASSERT_TRUE(::SetEvent(get(ev_)));
+  }
+
+  virtual void DoLaunchBrowser(const CString&) {
+  }
+
+
+  //
+  // WaitCallbackInterface
+  //
+  virtual bool HandleSignaled(HANDLE) {
+    // Makes the message pump stop.
+    return false;
+  }
+
+  void FormatWindowTitle(const TCHAR* text) {
+    CString title;
+    progress_wnd_.GetWindowText(CStrBuf(title, 256), 256);
+    CString new_title;
+    new_title.Format(_T("%s - %s"), title, text);
+    progress_wnd_.SetWindowText(new_title);
+  }
+
+  static BasicMessageHandler message_handler_;
+  static MessageLoopWithWait message_loop_;
+  ProgressWnd progress_wnd_;
+  CMessageLoop progress_wnd_message_loop_;
+  static scoped_event ev_;
+};
+
+BasicMessageHandler UITest::message_handler_;
+MessageLoopWithWait UITest::message_loop_;
+scoped_event UITest::ev_;
+
+/*
+TEST_F(UITest, Initialize) {
+  FormatWindowTitle(_T("Initialize"));
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnWaitingToDownload) {
+  FormatWindowTitle(_T("Waiting to download"));
+  progress_wnd_.OnWaitingToDownload();
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnDownloading1) {
+  FormatWindowTitle(_T("Downloading"));
+  progress_wnd_.OnDownloading(10000, 0);
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnDownloading2) {
+  FormatWindowTitle(_T("Downloading"));
+  progress_wnd_.OnDownloading(5000, 50);
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnDownloading3) {
+  FormatWindowTitle(_T("Downloading"));
+  progress_wnd_.OnDownloading(0, 100);
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnWaitingToInstall) {
+  FormatWindowTitle(_T("Waiting to install"));
+  progress_wnd_.OnWaitingToInstall();
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnInstall) {
+  FormatWindowTitle(_T("Installing"));
+  progress_wnd_.OnInstalling();
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnPause) {
+  FormatWindowTitle(_T("Paused"));
+  progress_wnd_.OnPause();
+  message_loop_.Process();
+}
+*/
+
+TEST_F(UITest, OnCompleteSuccess) {
+  FormatWindowTitle(_T("Complete success"));
+  progress_wnd_.OnComplete(
+      COMPLETION_CODE_SUCCESS,
+      _T("Thanks for installing Gears. For more information on using ")
+      _T("Gears visit the ")
+      _T("<a=http://www.google.com/gears/>Gears</a> web site."),
+      0);
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnCompleteError) {
+  FormatWindowTitle(_T("Complete error"));
+  progress_wnd_.OnComplete(
+      COMPLETION_CODE_ERROR,
+      _T("An error occured while installing Gears: an existing copy of ")
+      _T("Gears is currently running. Please exit the software and ")
+      _T("retry installation. For more information visit the ")
+      _T("<a=http://www.google.com/gears/>Gears</a> web site."),
+      11);
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnCompleteRestartAllBrowsers) {
+  FormatWindowTitle(_T("Restart browsers"));
+  progress_wnd_.OnComplete(COMPLETION_CODE_RESTART_ALL_BROWSERS, NULL, 0);
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnCompleteReboot) {
+  FormatWindowTitle(_T("Reboot"));
+  progress_wnd_.OnComplete(COMPLETION_CODE_REBOOT, NULL, 0);
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnCompleteRestartBrowser) {
+  FormatWindowTitle(_T("Restart browser"));
+  progress_wnd_.OnComplete(COMPLETION_CODE_RESTART_BROWSER, NULL, 0);
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnCompleteRestartAllBrowsersNoticeOnly) {
+  FormatWindowTitle(_T("Restart browsers"));
+  progress_wnd_.OnComplete(COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY,
+                           NULL,
+                           0);
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnCompleteRebootNoticeOnly) {
+  FormatWindowTitle(_T("Reboot"));
+  progress_wnd_.OnComplete(COMPLETION_CODE_REBOOT_NOTICE_ONLY, NULL, 0);
+  message_loop_.Process();
+}
+
+TEST_F(UITest, OnCompleteRestartBrowserNoticeOnly) {
+  FormatWindowTitle(_T("Restart browser"));
+  progress_wnd_.OnComplete(COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY,
+                           NULL,
+                           0);
+  message_loop_.Process();
+}
+
+// Test the OnComplete can be called multiple times.
+TEST_F(UITest, OnMultipleCompletes) {
+  FormatWindowTitle(_T("Complete success"));
+  progress_wnd_.OnComplete(
+      COMPLETION_CODE_SUCCESS,
+      _T("Thanks for installing Gears. For more information on using ")
+      _T("Gears visit the ")
+      _T("<a=http://www.google.com/gears/>Gears</a> web site."),
+      0);
+
+  FormatWindowTitle(_T("Complete error"));
+  progress_wnd_.OnComplete(
+      COMPLETION_CODE_ERROR,
+      _T("An error occured while installing Gears: an existing copy of ")
+      _T("Gears is currently running. Please exit the software and ")
+      _T("retry installation. For more information visit the ")
+      _T("<a=http://www.google.com/gears/>Gears</a> web site."),
+      0);
+
+  progress_wnd_.OnComplete(
+      COMPLETION_CODE_ERROR,
+      _T("An error occured while installing Gears: an existing copy of ")
+      _T("Gears is currently running. Please exit the software and ")
+      _T("retry installation. For more information visit the ")
+      _T("<a=http://www.google.com/gears/>Gears</a> web site."),
+      0);
+
+  FormatWindowTitle(_T("Restart browsers"));
+  progress_wnd_.OnComplete(COMPLETION_CODE_RESTART_ALL_BROWSERS, NULL, 0);
+  message_loop_.Process();
+}
+
+}   // namespace omaha
+
diff --git a/worker/ui.cc b/worker/ui.cc
index 8c3d80c..f8889b3 100644
--- a/worker/ui.cc
+++ b/worker/ui.cc
@@ -1,841 +1,841 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/worker/ui.h"

-

-#include "base/basictypes.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/exception_barrier.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/system_info.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/ui_displayed_event.h"

-#include "omaha/worker/ui_ctls.h"

-#include "omaha/worker/worker_metrics.h"

-

-namespace omaha {

-

-InstallStoppedWnd::InstallStoppedWnd(CMessageLoop* message_loop, HWND parent)

-    : message_loop_(message_loop),

-      parent_(parent) {

-  CORE_LOG(L3, (_T("[InstallStoppedWnd::InstallStoppedWnd]")));

-  ASSERT1(message_loop);

-  ASSERT1(::IsWindow(parent));

-}

-

-InstallStoppedWnd::~InstallStoppedWnd() {

-  CORE_LOG(L3, (_T("[InstallStoppedWnd::~InstallStoppedWnd]")));

-  if (IsWindow()) {

-    VERIFY1(SUCCEEDED(CloseWindow()));

-  }

-}

-

-// Enables the parent window and destroys this window.

-// Enabling the parent window before destroying this one causes the parent

-// window to get the focus and avoids a visible momentary lack of focus if we

-// instead call SetFocus for the parent after the window is destroyed.

-HRESULT InstallStoppedWnd::CloseWindow() {

-  ASSERT1(IsWindow());

-  VERIFY1(::EnableWindow(parent_, true));

-

-  return DestroyWindow() ? S_OK : HRESULTFromLastError();

-}

-

-// Disables the parent window.

-LRESULT InstallStoppedWnd::OnInitDialog(UINT,

-                                        WPARAM,

-                                        LPARAM,

-                                        BOOL& handled) {    // NOLINT

-  VERIFY1(!::EnableWindow(parent_, false));

-  VERIFY1(message_loop_->AddMessageFilter(this));

-  handled = true;

-  return 1;

-}

-

-LRESULT InstallStoppedWnd::OnClickButton(WORD,

-                                         WORD id,

-                                         HWND,

-                                         BOOL& handled) {   // NOLINT

-  ExceptionBarrier eb;

-  CORE_LOG(L3, (_T("[InstallStoppedWnd::OnClickButton]")));

-  ASSERT1(id == IDOK || id == IDCANCEL);

-  VERIFY1(::PostMessage(parent_, WM_INSTALL_STOPPED, id, 0));

-  handled = true;

-  return 0;

-}

-

-LRESULT InstallStoppedWnd::OnDestroy(UINT,

-                                     WPARAM,

-                                     LPARAM,

-                                     BOOL& handled) {  // NOLINT

-  VERIFY1(message_loop_->RemoveMessageFilter(this));

-  handled = true;

-  return 0;

-}

-

-ProgressWnd::ProgressWnd(CMessageLoop* message_loop, HWND parent)

-    : message_loop_(message_loop),

-      parent_(parent),

-      thread_id_(::GetCurrentThreadId()),

-      cur_state_(STATE_INIT),

-      is_close_enabled_(true),

-      events_sink_(NULL),

-      is_machine_(false),

-      product_guid_(GUID_NULL) {

-  ASSERT1(message_loop);

-  CORE_LOG(L3, (_T("[ProgressWnd::ProgressWnd]")));

-}

-

-ProgressWnd::~ProgressWnd() {

-  CORE_LOG(L3, (_T("[ProgressWnd::~ProgressWnd]")));

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-  ASSERT1(!IsWindow());

-  cur_state_ = STATE_END;

-}

-

-HRESULT ProgressWnd::Initialize() {

-  CORE_LOG(L3, (_T("[ProgressWnd::Initialize]")));

-  cur_state_ = STATE_INIT;

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-

-  // For the InitCommonControlsEx call to succeed on XP a manifest is

-  // needed to declare "Microsoft.Windows.Common-Controls" as a dependent

-  // assembly. Further work may be needed to ensure W2K compatibility.

-  INITCOMMONCONTROLSEX init_ctrls = { sizeof(INITCOMMONCONTROLSEX), 0 };

-  ASSERT1(init_ctrls.dwSize == sizeof(init_ctrls));

-  init_ctrls.dwICC = ICC_STANDARD_CLASSES | ICC_PROGRESS_CLASS;

-  if (!::InitCommonControlsEx(&init_ctrls)) {

-    // In case of XP RTM and XP SP1, InitCommonControlsEx is failing,

-    // however the UI initializes fine and works correctly. Because of this

-    // we only log the failure and do not error out.

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LEVEL_ERROR, (_T("[InitCommonControlsEx failed][0x%08x]"), hr));

-    ASSERT1(hr == 0x80070582);

-  }

-

-  if (!Create(parent_)) {

-    CORE_LOG(LEVEL_ERROR, (_T("[Failed to create the window]")));

-    return GOOPDATE_E_UI_INTERNAL_ERROR;

-  }

-  VERIFY1(message_loop_->AddMessageFilter(this));

-  return S_OK;

-}

-

-HRESULT ProgressWnd::GetWindowTitle(TCHAR* title, int size) {

-  CORE_LOG(L3, (_T("[ProgressWnd::GetWindowTitle]")));

-  ASSERT1(size);

-  if (!size) return E_INVALIDARG;

-

-  // The text is truncated if there is no enough space in the buffer.

-  int result = GetWindowText(title, size);

-  CORE_LOG(L4, (_T("[title=%s]"), title));

-  return result ? S_OK : HRESULTFromLastError();

-}

-

-HRESULT ProgressWnd::SetWindowTitle(const TCHAR* title) {

-  CORE_LOG(L3, (_T("[ProgressWnd::SetWindowTitle][%s]"), title));

-  return SetWindowText(title) ? S_OK : HRESULTFromLastError();

-}

-

-LRESULT ProgressWnd::OnInitDialog(UINT,

-                                  WPARAM,

-                                  LPARAM,

-                                  BOOL& handled) {    // NOLINT

-  ExceptionBarrier eb;

-  CORE_LOG(L3, (_T("[ProgressWnd::OnInitDialog]")));

-  handled = true;

-  ASSERT1(!product_name_.IsEmpty());

-  CString s;

-  s.FormatMessage(IDS_WINDOW_TITLE, product_name_);

-  VERIFY1(SetWindowText(s));

-  pause_resume_text_.reset(new StaticEx);

-  pause_resume_text_->SubclassWindow(GetDlgItem(IDC_PAUSE_RESUME_TEXT));

-  VERIFY1(CenterWindow(NULL));

-

-  VERIFY1(s.LoadString(IDS_INITIALIZING));

-  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));

-  VERIFY1(SUCCEEDED(SetMarqueeMode(true)));

-  VERIFY1(SUCCEEDED(ChangeControlState()));

-  VERIFY1(SUCCEEDED(SetWindowIcon()));

-

-  metrics_timer_.reset(new HighresTimer);

-  return 1;  // Let the system set the focus.

-}

-

-LRESULT ProgressWnd::OnClose(UINT,

-                             WPARAM,

-                             LPARAM,

-                             BOOL& handled) {         // NOLINT

-  ExceptionBarrier eb;

-  CORE_LOG(L3, (_T("[ProgressWnd::OnClose]")));

-

-  ++metric_worker_ui_click_x;

-

-  MaybeCloseWindow();

-  handled = true;

-  return 0;

-}

-

-HRESULT ProgressWnd::CloseWindow() {

-  HRESULT hr = DestroyWindow() ? S_OK : HRESULTFromLastError();

-  if (events_sink_) {

-    events_sink_->DoClose();

-  }

-  return hr;

-}

-

-void ProgressWnd::MaybeRequestExitProcess() {

-  CORE_LOG(L3, (_T("[ProgressWnd::MaybeRequestExitProcess]")));

-  if (cur_state_ != STATE_COMPLETE_SUCCESS &&

-      cur_state_ != STATE_COMPLETE_ERROR &&

-      cur_state_ != STATE_COMPLETE_RESTART_BROWSER &&

-      cur_state_ != STATE_COMPLETE_RESTART_ALL_BROWSERS &&

-      cur_state_ != STATE_COMPLETE_REBOOT) {

-    return;

-  }

-

-  RequestExitProcess();

-}

-

-void ProgressWnd::RequestExitProcess() {

-  CORE_LOG(L3, (_T("[ProgressWnd::RequestExitProcess]")));

-  ::PostQuitMessage(0);

-}

-

-bool ProgressWnd::MaybeCloseWindow() {

-  if (cur_state_ != STATE_COMPLETE_SUCCESS &&

-      cur_state_ != STATE_COMPLETE_ERROR &&

-      cur_state_ != STATE_COMPLETE_RESTART_BROWSER &&

-      cur_state_ != STATE_COMPLETE_RESTART_ALL_BROWSERS &&

-      cur_state_ != STATE_COMPLETE_REBOOT) {

-    // The UI is not in final state: ask the user to proceed with closing it.

-    // A modal dialog opens and sends a message back to this window to

-    // communicate the user decision.

-    install_stopped_wnd_.reset(new InstallStoppedWnd(message_loop_, *this));

-    HWND hwnd = install_stopped_wnd_->Create(*this);

-    if (hwnd) {

-      CString title;

-      VERIFY1(title.LoadString(IDS_INSTALLATION_STOPPED_WINDOW_TITLE));

-      VERIFY1(install_stopped_wnd_->SetWindowText(title));

-

-      CString button_text;

-      VERIFY1(button_text.LoadString(IDS_RESUME_INSTALLATION));

-      VERIFY1(::SetWindowText(

-          install_stopped_wnd_->GetDlgItem(IDOK), button_text));

-

-      VERIFY1(button_text.LoadString(IDS_CANCEL_INSTALLATION));

-      VERIFY1(::SetWindowText(

-          install_stopped_wnd_->GetDlgItem(IDCANCEL), button_text));

-

-      CString s;

-      s.FormatMessage(IDS_INSTALL_STOPPED, product_name_);

-      VERIFY1(::SetWindowText(

-          install_stopped_wnd_->GetDlgItem(IDC_INSTALL_STOPPED_TEXT), s));

-

-      VERIFY1(install_stopped_wnd_->CenterWindow(*this));

-      VERIFY1(!install_stopped_wnd_->ShowWindow(SW_SHOWDEFAULT));

-      return false;

-    } else {

-      ASSERT1(false);

-    }

-  }

-

-  // The UI is in a final state or the dialog box failed to open: proceed with

-  // closing the UI.

-  VERIFY1(SUCCEEDED(CloseWindow()));

-  return true;

-}

-

-LRESULT ProgressWnd::OnNCDestroy(UINT,

-                                 WPARAM,

-                                 LPARAM,

-                                 BOOL& handled) {         // NOLINT

-  ExceptionBarrier eb;

-  CORE_LOG(L3, (_T("[ProgressWnd::OnNCDestroy]")));

-  VERIFY1(message_loop_->RemoveMessageFilter(this));

-  MaybeRequestExitProcess();

-  handled = false;  // Let ATL default processing handle the WM_NCDESTROY.

-  return 0;

-}

-

-LRESULT ProgressWnd::OnClickedButton(WORD,

-                                     WORD id,

-                                     HWND,

-                                     BOOL& handled) {   // NOLINT

-  ExceptionBarrier eb;

-  CORE_LOG(L3, (_T("[ProgressWnd::OnClickedButton]")));

-  ASSERT1(id == IDC_BUTTON1 || id == IDC_BUTTON2 || id == IDC_CLOSE);

-  handled = true;

-  DestroyWindow();

-

-  if (events_sink_) {

-#pragma warning(push)

-// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by

-// a case label.

-#pragma warning(disable : 4061)

-

-    switch (id) {

-      case IDC_BUTTON1:

-        switch (cur_state_) {

-          case STATE_COMPLETE_RESTART_BROWSER:

-            ++metric_worker_ui_restart_browser_now_click;

-            events_sink_->DoRestartBrowsers();

-            break;

-          case STATE_COMPLETE_RESTART_ALL_BROWSERS:

-            ++metric_worker_ui_restart_all_browsers_now_click;

-            events_sink_->DoRestartBrowsers();

-            break;

-          case STATE_COMPLETE_REBOOT:

-            ++metric_worker_ui_reboot_now_click;

-            events_sink_->DoReboot();

-            break;

-          default:

-            ASSERT1(false);

-        }

-        break;

-      case IDC_BUTTON2:

-        switch (cur_state_) {

-          case STATE_COMPLETE_RESTART_BROWSER:

-          case STATE_COMPLETE_RESTART_ALL_BROWSERS:

-          case STATE_COMPLETE_REBOOT:

-            break;

-          default:

-            ASSERT1(false);

-        }

-        break;

-      case IDC_CLOSE:

-        switch (cur_state_) {

-          case STATE_COMPLETE_SUCCESS:

-          case STATE_COMPLETE_ERROR:

-            break;

-          default:

-            ASSERT1(false);

-        }

-        break;

-      default:

-        ASSERT1(false);

-    }

-

-#pragma warning(pop)

-

-    events_sink_->DoClose();

-  }

-  return 0;

-}

-

-// Called when esc key is hit.

-// If close is disabled, does nothing because we don't want the window to close.

-LRESULT ProgressWnd::OnCancel(WORD, WORD id,

-                              HWND, BOOL& handled) {    // NOLINT

-  ExceptionBarrier eb;

-  VERIFY1(id == IDCANCEL);

-

-  if (!is_close_enabled_) {

-    return 0;

-  }

-

-  ++metric_worker_ui_esc_key_total;

-  MaybeCloseWindow();

-  handled = true;

-  return 0;

-}

-

-LRESULT ProgressWnd::OnUrlClicked(int,

-                                  LPNMHDR params,

-                                  BOOL& handled) {      // NOLINT

-  CORE_LOG(L3, (_T("[ProgressWnd::OnUrlClicked]")));

-  ASSERT1(params);

-  handled = true;

-

-  if (IDC_GET_HELP_TEXT == params->idFrom) {

-    ++metric_worker_ui_get_help_click;

-  }

-

-  NM_STATICEX* notification = reinterpret_cast<NM_STATICEX*>(params);

-  events_sink_->DoLaunchBrowser(notification->action);

-

-  return 1;

-}

-

-LRESULT ProgressWnd::OnInstallStopped(UINT msg,

-                                      WPARAM wparam,

-                                      LPARAM,

-                                      BOOL& handled) {  // NOLINT

-  CORE_LOG(L3, (_T("[ProgressWnd::OnInstallStopped]")));

-  UNREFERENCED_PARAMETER(msg);

-

-  install_stopped_wnd_.reset();

-

-  ASSERT1(msg == WM_INSTALL_STOPPED);

-  ASSERT1(wparam == IDOK || wparam == IDCANCEL);

-  switch (wparam) {

-    case IDOK:

-      // TODO(omaha): Implement "Resume" here.

-      break;

-    case IDCANCEL:

-      // The user has decided to cancel.

-      metric_worker_ui_cancel_ms.AddSample(metrics_timer_->GetElapsedMs());

-      ++metric_worker_ui_cancels;

-      DestroyWindow();

-      if (events_sink_) {

-        events_sink_->DoClose();

-      }

-      break;

-    default:

-      ASSERT1(false);

-      break;

-  }

-

-  handled = true;

-  return 0;

-}

-

-void ProgressWnd::OnCheckingForUpdate() {

-  CORE_LOG(L3, (_T("[ProgressWnd::OnCheckingForUpdate]")));

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-  if (!IsWindow()) {

-    return;

-  }

-

-  cur_state_ = STATE_CHECKING_FOR_UPDATE;

-

-  CString s;

-  VERIFY1(s.LoadString(IDS_WAITING_TO_CONNECT));

-  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));

-

-  VERIFY1(SUCCEEDED(SetMarqueeMode(true)));

-  VERIFY1(SUCCEEDED(ChangeControlState()));

-}

-

-void ProgressWnd::OnUpdateAvailable(const TCHAR* version_string) {

-  UNREFERENCED_PARAMETER(version_string);

-  CORE_LOG(L3, (_T("[ProgressWnd::OnUpdateAvailable][%s]"), version_string));

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-  if (!IsWindow()) {

-    return;

-  }

-}

-

-void ProgressWnd::OnWaitingToDownload() {

-  CORE_LOG(L3, (_T("[ProgressWnd::OnWaitingToDownload]")));

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-  if (!IsWindow()) {

-    return;

-  }

-

-  cur_state_ = STATE_WAITING_TO_DOWNLOAD;

-

-  CString s;

-  s.FormatMessage(IDS_WAITING_TO_DOWNLOAD, product_name_);

-  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));

-

-  VERIFY1(SUCCEEDED(SetMarqueeMode(true)));

-  VERIFY1(SUCCEEDED(ChangeControlState()));

-}

-

-void ProgressWnd::OnDownloading(int time_remaining_ms, int pos) {

-  CORE_LOG(L5, (_T("[ProgressWnd::OnDownloading][pos=%d]"), pos));

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-  if (!IsWindow()) {

-    return;

-  }

-

-  ASSERT1(time_remaining_ms >=0);

-  ASSERT1(0 <= pos && pos <= 100);

-

-  time_remaining_ms;  // unreferenced formal parameter

-

-  cur_state_ = STATE_DOWNLOADING;

-

-  CString s;

-  s.FormatMessage(IDS_DOWNLOADING, product_name_);

-  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));

-

-  VERIFY1(s.LoadString(IDS_PAUSE));

-  VERIFY1(::SetWindowText(GetDlgItem(IDC_PAUSE_RESUME_TEXT), s));

-

-  // TODO(omaha): implement time left.

-

-  // When the network is connecting keep the marquee moving, otherwise

-  // the user has no indication something is still going on.

-  // TODO(omaha): when resuming an incomplete download this will not work.

-  VERIFY1(SUCCEEDED(SetMarqueeMode(pos == 0)));

-  ::SendMessage(GetDlgItem(IDC_PROGRESS), PBM_SETPOS, pos, 0);

-  VERIFY1(SUCCEEDED(ChangeControlState()));

-}

-

-void ProgressWnd::OnWaitingToInstall() {

-  CORE_LOG(L3, (_T("[ProgressWnd::OnWaitingToInstall]")));

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-  if (!IsWindow()) {

-    return;

-  }

-

-  cur_state_ = STATE_WAITING_TO_INSTALL;

-

-  CString s;

-  s.FormatMessage(IDS_WAITING_TO_INSTALL, product_name_);

-  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));

-

-  VERIFY1(SUCCEEDED(SetMarqueeMode(true)));

-  VERIFY1(SUCCEEDED(ChangeControlState()));

-}

-

-void ProgressWnd::OnInstalling() {

-  CORE_LOG(L3, (_T("[ProgressWnd::OnInstalling]")));

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-  if (!IsWindow()) {

-    return;

-  }

-

-  cur_state_ = STATE_INSTALLING;

-

-  // Close the 'Install Stop' window if it is on the screen because the user

-  // cannot cancel an install anyway.

-  CloseInstallStoppedWindow();

-

-  CString s;

-  s.FormatMessage(IDS_INSTALLING, product_name_);

-  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));

-

-  VERIFY1(SUCCEEDED(EnableClose(false)));

-  VERIFY1(SUCCEEDED(SetMarqueeMode(true)));

-  VERIFY1(SUCCEEDED(ChangeControlState()));

-}

-

-void ProgressWnd::OnPause() {

-  CORE_LOG(L3, (_T("[ProgressWnd::OnPause]")));

-  ASSERT(false, (_T("These strings are not translated or in .rc files.")));

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-  if (!IsWindow()) {

-    return;

-  }

-

-  cur_state_ = STATE_PAUSED;

-

-  CString s;

-  s.FormatMessage(IDS_DOWNLOAD_PAUSED, product_name_);

-  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));

-

-  VERIFY1(s.LoadString(IDS_RESUME));

-  VERIFY1(::SetWindowText(GetDlgItem(IDC_PAUSE_RESUME_TEXT), s));

-

-  // TODO(omaha): implement time left.

-

-  VERIFY1(SUCCEEDED(ChangeControlState()));

-}

-

-void ProgressWnd::OnShow() {

-  CORE_LOG(L3, (_T("[ProgressWnd::OnShow]")));

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-  if (!IsWindow() || IsWindowVisible()) {

-    return;

-  }

-

-  CenterWindow(NULL);

-  SetVisible(true);

-

-  if (!::SetForegroundWindow(*this)) {

-    CORE_LOG(LW, (_T("[::SetForegroundWindow failed %d]"), ::GetLastError()));

-  }

-

-  UIDisplayedEventManager::SignalEvent(is_machine_);

-}

-

-// The 'error_code' can contain an HRESULT or an installer error.

-void ProgressWnd::OnComplete(CompletionCodes code,

-                             const TCHAR* text,

-                             DWORD error_code) {

-  CORE_LOG(L3, (_T("[ProgressWnd::OnComplete]")

-                _T("[code=%d][error_code=0x%08x]"), code, error_code));

-  ASSERT1(thread_id_ == ::GetCurrentThreadId());

-

-  if (!IsWindow()) {

-    RequestExitProcess();

-    return;

-  }

-

-  // It is possible for the OnComplete callback to be called multiple times.

-  // Subclassing the control multiple times results in a crash, therefore

-  // unsubclass the control if the control has been created and subclassed

-  // before.

-  if (complete_text_ != NULL) {

-    complete_text_->UnsubclassWindow(true);

-    complete_text_.reset(NULL);

-  }

-

-  // Close the 'Install Stop' window if it is on the screen.

-  CloseInstallStoppedWindow();

-

-  CString s;

-  switch (code) {

-    case COMPLETION_CODE_SUCCESS_CLOSE_UI:

-      cur_state_ = STATE_COMPLETE_SUCCESS;

-      VERIFY1(SUCCEEDED(CloseWindow()));

-      return;

-

-    case COMPLETION_CODE_SUCCESS:

-      cur_state_ = STATE_COMPLETE_SUCCESS;

-      VERIFY1(s.LoadString(IDS_CLOSE));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_CLOSE), s));

-      complete_text_.reset(new StaticEx);

-      complete_text_->SubclassWindow(GetDlgItem(IDC_COMPLETE_TEXT));

-      ASSERT1(text);

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), text));

-      break;

-    case COMPLETION_CODE_ERROR:

-      cur_state_ = STATE_COMPLETE_ERROR;

-      VERIFY1(s.LoadString(IDS_CLOSE));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_CLOSE), s));

-      complete_text_.reset(new StaticEx);

-      complete_text_->SubclassWindow(GetDlgItem(IDC_ERROR_TEXT));

-      ASSERT1(text);

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_ERROR_TEXT), text));

-      VERIFY1(SUCCEEDED(ShowGetHelpLink(error_code)));

-      break;

-    case COMPLETION_CODE_RESTART_ALL_BROWSERS:

-      cur_state_ = STATE_COMPLETE_RESTART_ALL_BROWSERS;

-      VERIFY1(s.LoadString(IDS_RESTART_ALL_BROWSERS_NOW));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON1), s));

-      VERIFY1(s.LoadString(IDS_RESTART_ALL_BROWSERS_LATER));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON2), s));

-      s.FormatMessage(IDS_TEXT_RESTART_ALL_BROWSERS, product_name_);

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));

-      ++metric_worker_ui_restart_all_browsers_buttons_displayed;

-      break;

-    case COMPLETION_CODE_RESTART_BROWSER:

-      cur_state_ = STATE_COMPLETE_RESTART_BROWSER;

-      VERIFY1(s.LoadString(IDS_RESTART_BROWSER_NOW));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON1), s));

-      VERIFY1(s.LoadString(IDS_RESTART_BROWSER_LATER));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON2), s));

-      s.FormatMessage(IDS_TEXT_RESTART_BROWSER, product_name_);

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));

-      ++metric_worker_ui_restart_browser_buttons_displayed;

-      break;

-    case COMPLETION_CODE_REBOOT:

-      ASSERT(false, (_T("The button actions are not implemented.")));

-      cur_state_ = STATE_COMPLETE_REBOOT;

-      VERIFY1(s.LoadString(IDS_RESTART_NOW));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON1), s));

-      VERIFY1(s.LoadString(IDS_RESTART_LATER));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON2), s));

-      s.FormatMessage(IDS_TEXT_REBOOT, product_name_);

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));

-      ++metric_worker_ui_reboot_buttons_displayed;

-      break;

-    case COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY:

-      cur_state_ = STATE_COMPLETE_SUCCESS;

-      VERIFY1(s.LoadString(IDS_CLOSE));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_CLOSE), s));

-      s.FormatMessage(IDS_TEXT_RESTART_ALL_BROWSERS, product_name_);

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));

-      break;

-    case COMPLETION_CODE_REBOOT_NOTICE_ONLY:

-      cur_state_ = STATE_COMPLETE_SUCCESS;

-      VERIFY1(s.LoadString(IDS_CLOSE));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_CLOSE), s));

-      s.FormatMessage(IDS_TEXT_REBOOT, product_name_);

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));

-      break;

-    case COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY:

-      cur_state_ = STATE_COMPLETE_SUCCESS;

-      VERIFY1(s.LoadString(IDS_CLOSE));

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_CLOSE), s));

-      s.FormatMessage(IDS_TEXT_RESTART_BROWSER, product_name_);

-      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));

-      break;

-    case COMPLETION_CODE_RUN_COMMAND:

-    default:

-      ASSERT1(false);

-      break;

-  }

-

-  VERIFY1(SUCCEEDED(EnableClose(true)));

-  VERIFY1(SUCCEEDED(ChangeControlState()));

-}

-

-HRESULT ProgressWnd::ChangeControlState() {

-  for (size_t i = 0; i != arraysize(ProgressWnd::ctls_); ++i) {

-    const ControlState& ctl_state = ctls_[i];

-    HWND hwnd = GetDlgItem(ctls_[i].id_);

-    ASSERT1(hwnd);

-    const ControlAttributes& attr = ctl_state.attr_[cur_state_];

-    ::ShowWindow(hwnd, attr.is_visible_ ? SW_SHOW : SW_HIDE);

-    ::EnableWindow(hwnd, attr.is_enabled_ ? true : false);

-    if (attr.is_button_ && attr.is_default_) {

-      // We ask the dialog manager to give the default push button the focus, so

-      // for instance the <Enter> key works as expected.

-      GotoDlgCtrl(hwnd);

-      LONG style = ::GetWindowLong(hwnd, GWL_STYLE);

-      if (style) {

-        style |= BS_DEFPUSHBUTTON;

-        ::SetWindowLong(hwnd, GWL_STYLE, style);

-      }

-    }

-  }

-  return S_OK;

-}

-

-HRESULT ProgressWnd::SetMarqueeMode(bool is_marquee) {

-  if (!SystemInfo::IsRunningOnXPOrLater()) {

-    // Marquee is not supported on OSes below XP.

-    return S_OK;

-  }

-

-  HWND progress_bar = GetDlgItem(IDC_PROGRESS);

-  if (!progress_bar) {

-    return GOOPDATE_E_UI_INTERNAL_ERROR;

-  }

-

-  LONG style = ::GetWindowLong(progress_bar, GWL_STYLE);

-  if (!style) {

-    return HRESULTFromLastError();

-  }

-

-  if (is_marquee) {

-    if (style & PBS_MARQUEE) {

-      return S_OK;

-    }

-

-    style |= PBS_MARQUEE;

-    style = ::SetWindowLong(progress_bar, GWL_STYLE, style);

-    if (!style) {

-      return HRESULTFromLastError();

-    }

-

-    bool result = ::SendMessage(progress_bar, PBM_SETMARQUEE,

-                                is_marquee, kMarqueeModeUpdatesMs) != 0;

-    return result ? S_OK : GOOPDATE_E_UI_INTERNAL_ERROR;

-  } else {

-    if (!(style & PBS_MARQUEE)) {

-      return S_OK;

-    }

-

-    style &= ~PBS_MARQUEE;

-    style = ::SetWindowLong(progress_bar, GWL_STYLE, style);

-    if (!style) {

-      return HRESULTFromLastError();

-    }

-    return S_OK;

-  }

-}

-

-HRESULT ProgressWnd::EnableClose(bool enable) {

-  is_close_enabled_ = enable;

-  return EnableSystemCloseButton(is_close_enabled_);

-}

-

-HRESULT ProgressWnd::EnableSystemCloseButton(bool enable) {

-  HMENU menu = ::GetSystemMenu(*this, false);

-  ASSERT1(menu);

-  uint32 flags = MF_BYCOMMAND;

-  flags |= enable ? MF_ENABLED : MF_GRAYED;

-  VERIFY1(::EnableMenuItem(menu, SC_CLOSE, flags) != -1);

-  return S_OK;

-}

-

-// The system displays the system large icon in the ALT+TAB dialog box.

-// We do not need any small icon in the window caption. However, setting

-// ICON_BIG has the side effect of the window displaying a scaled down

-// version of it in the window caption. We could not find any way to

-// hide that icon, including setting the icon to NULL or handling WM_GETICON

-// message.

-HRESULT ProgressWnd::SetWindowIcon() {

-  const int cx = ::GetSystemMetrics(SM_CXICON);

-  const int cy = ::GetSystemMetrics(SM_CYICON);

-  HINSTANCE exe_instance = reinterpret_cast<HINSTANCE>(kExeLoadingAddress);

-  reset(hicon_,

-        reinterpret_cast<HICON>(::LoadImage(exe_instance,

-                                            MAKEINTRESOURCE(IDI_APP),

-                                            IMAGE_ICON,

-                                            cx,

-                                            cy,

-                                            LR_DEFAULTCOLOR)));

-  if (!hicon_) {

-    HRESULT hr = HRESULTFromLastError();

-    CORE_LOG(LEVEL_ERROR, (_T("[LoadImage failed 0x%08x]"), hr));

-    return hr;

-  }

-  VERIFY1(SendMessage(WM_SETICON,

-                      ICON_BIG,

-                      reinterpret_cast<LPARAM>(get(hicon_))) == NULL);

-  return S_OK;

-}

-

-HRESULT ProgressWnd::ShowGetHelpLink(HRESULT error_code) {

-  // When running elevated and ProcessLauncherClass is not registered, the

-  // browser launch from the link will fail. Don't display a link that will not

-  // work.

-  // TODO(omaha): Determine if ProcessLauncherClass is registered. Maybe move

-  // this code to the Worker.

-  if (vista_util::IsVistaOrLater() && vista_util::IsUserAdmin()) {

-    return S_OK;

-  }

-

-  // Do not display the link if the error already has a link.

-  if (GOOPDATE_E_OS_NOT_SUPPORTED == error_code) {

-    return S_OK;

-  }

-

-  const TCHAR* const kHelpLinkSourceId = _T("gethelp");

-  CString url;

-  HRESULT hr = goopdate_utils::BuildHttpGetString(

-      kUrlMoreInformation,

-      error_code,

-      0,   // extra code 1

-      0,   // extra code 2

-      GuidToString(product_guid_),

-      GetVersionString(),

-      is_machine_,

-      language_,

-      kHelpLinkSourceId,

-      &url);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  const TCHAR* const kLinkFormat = _T("<a=%s>%s</a>");

-  CString display_text;

-  VERIFY1(display_text.LoadString(IDS_HELP_ME_FIX_THIS_TEXT));

-  CString link_string;

-  link_string.Format(kLinkFormat, url, display_text);

-

-  get_help_text_.reset(new StaticEx);

-  get_help_text_->SubclassWindow(GetDlgItem(IDC_GET_HELP_TEXT));

-  VERIFY1(::SetWindowText(GetDlgItem(IDC_GET_HELP_TEXT), link_string));

-

-  ++metric_worker_ui_get_help_displayed;

-  return S_OK;

-}

-

-bool ProgressWnd::CloseInstallStoppedWindow() {

-  if (install_stopped_wnd_.get() && install_stopped_wnd_->IsWindow()) {

-    VERIFY1(SUCCEEDED(install_stopped_wnd_->CloseWindow()));

-    install_stopped_wnd_.reset();

-    return true;

-  } else {

-    return false;

-  }

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/worker/ui.h"
+
+#include "base/basictypes.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/exception_barrier.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/system_info.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/ui_displayed_event.h"
+#include "omaha/worker/ui_ctls.h"
+#include "omaha/worker/worker_metrics.h"
+
+namespace omaha {
+
+InstallStoppedWnd::InstallStoppedWnd(CMessageLoop* message_loop, HWND parent)
+    : message_loop_(message_loop),
+      parent_(parent) {
+  CORE_LOG(L3, (_T("[InstallStoppedWnd::InstallStoppedWnd]")));
+  ASSERT1(message_loop);
+  ASSERT1(::IsWindow(parent));
+}
+
+InstallStoppedWnd::~InstallStoppedWnd() {
+  CORE_LOG(L3, (_T("[InstallStoppedWnd::~InstallStoppedWnd]")));
+  if (IsWindow()) {
+    VERIFY1(SUCCEEDED(CloseWindow()));
+  }
+}
+
+// Enables the parent window and destroys this window.
+// Enabling the parent window before destroying this one causes the parent
+// window to get the focus and avoids a visible momentary lack of focus if we
+// instead call SetFocus for the parent after the window is destroyed.
+HRESULT InstallStoppedWnd::CloseWindow() {
+  ASSERT1(IsWindow());
+  VERIFY1(::EnableWindow(parent_, true));
+
+  return DestroyWindow() ? S_OK : HRESULTFromLastError();
+}
+
+// Disables the parent window.
+LRESULT InstallStoppedWnd::OnInitDialog(UINT,
+                                        WPARAM,
+                                        LPARAM,
+                                        BOOL& handled) {    // NOLINT
+  VERIFY1(!::EnableWindow(parent_, false));
+  VERIFY1(message_loop_->AddMessageFilter(this));
+  handled = true;
+  return 1;
+}
+
+LRESULT InstallStoppedWnd::OnClickButton(WORD,
+                                         WORD id,
+                                         HWND,
+                                         BOOL& handled) {   // NOLINT
+  ExceptionBarrier eb;
+  CORE_LOG(L3, (_T("[InstallStoppedWnd::OnClickButton]")));
+  ASSERT1(id == IDOK || id == IDCANCEL);
+  VERIFY1(::PostMessage(parent_, WM_INSTALL_STOPPED, id, 0));
+  handled = true;
+  return 0;
+}
+
+LRESULT InstallStoppedWnd::OnDestroy(UINT,
+                                     WPARAM,
+                                     LPARAM,
+                                     BOOL& handled) {  // NOLINT
+  VERIFY1(message_loop_->RemoveMessageFilter(this));
+  handled = true;
+  return 0;
+}
+
+ProgressWnd::ProgressWnd(CMessageLoop* message_loop, HWND parent)
+    : message_loop_(message_loop),
+      parent_(parent),
+      thread_id_(::GetCurrentThreadId()),
+      cur_state_(STATE_INIT),
+      is_close_enabled_(true),
+      events_sink_(NULL),
+      is_machine_(false),
+      product_guid_(GUID_NULL) {
+  ASSERT1(message_loop);
+  CORE_LOG(L3, (_T("[ProgressWnd::ProgressWnd]")));
+}
+
+ProgressWnd::~ProgressWnd() {
+  CORE_LOG(L3, (_T("[ProgressWnd::~ProgressWnd]")));
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+  ASSERT1(!IsWindow());
+  cur_state_ = STATE_END;
+}
+
+HRESULT ProgressWnd::Initialize() {
+  CORE_LOG(L3, (_T("[ProgressWnd::Initialize]")));
+  cur_state_ = STATE_INIT;
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+
+  // For the InitCommonControlsEx call to succeed on XP a manifest is
+  // needed to declare "Microsoft.Windows.Common-Controls" as a dependent
+  // assembly. Further work may be needed to ensure W2K compatibility.
+  INITCOMMONCONTROLSEX init_ctrls = { sizeof(INITCOMMONCONTROLSEX), 0 };
+  ASSERT1(init_ctrls.dwSize == sizeof(init_ctrls));
+  init_ctrls.dwICC = ICC_STANDARD_CLASSES | ICC_PROGRESS_CLASS;
+  if (!::InitCommonControlsEx(&init_ctrls)) {
+    // In case of XP RTM and XP SP1, InitCommonControlsEx is failing,
+    // however the UI initializes fine and works correctly. Because of this
+    // we only log the failure and do not error out.
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LEVEL_ERROR, (_T("[InitCommonControlsEx failed][0x%08x]"), hr));
+    ASSERT1(hr == 0x80070582);
+  }
+
+  if (!Create(parent_)) {
+    CORE_LOG(LEVEL_ERROR, (_T("[Failed to create the window]")));
+    return GOOPDATE_E_UI_INTERNAL_ERROR;
+  }
+  VERIFY1(message_loop_->AddMessageFilter(this));
+  return S_OK;
+}
+
+HRESULT ProgressWnd::GetWindowTitle(TCHAR* title, int size) {
+  CORE_LOG(L3, (_T("[ProgressWnd::GetWindowTitle]")));
+  ASSERT1(size);
+  if (!size) return E_INVALIDARG;
+
+  // The text is truncated if there is no enough space in the buffer.
+  int result = GetWindowText(title, size);
+  CORE_LOG(L4, (_T("[title=%s]"), title));
+  return result ? S_OK : HRESULTFromLastError();
+}
+
+HRESULT ProgressWnd::SetWindowTitle(const TCHAR* title) {
+  CORE_LOG(L3, (_T("[ProgressWnd::SetWindowTitle][%s]"), title));
+  return SetWindowText(title) ? S_OK : HRESULTFromLastError();
+}
+
+LRESULT ProgressWnd::OnInitDialog(UINT,
+                                  WPARAM,
+                                  LPARAM,
+                                  BOOL& handled) {    // NOLINT
+  ExceptionBarrier eb;
+  CORE_LOG(L3, (_T("[ProgressWnd::OnInitDialog]")));
+  handled = true;
+  ASSERT1(!product_name_.IsEmpty());
+  CString s;
+  s.FormatMessage(IDS_WINDOW_TITLE, product_name_);
+  VERIFY1(SetWindowText(s));
+  pause_resume_text_.reset(new StaticEx);
+  pause_resume_text_->SubclassWindow(GetDlgItem(IDC_PAUSE_RESUME_TEXT));
+  VERIFY1(CenterWindow(NULL));
+
+  VERIFY1(s.LoadString(IDS_INITIALIZING));
+  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
+  VERIFY1(SUCCEEDED(SetMarqueeMode(true)));
+  VERIFY1(SUCCEEDED(ChangeControlState()));
+  VERIFY1(SUCCEEDED(SetWindowIcon()));
+
+  metrics_timer_.reset(new HighresTimer);
+  return 1;  // Let the system set the focus.
+}
+
+LRESULT ProgressWnd::OnClose(UINT,
+                             WPARAM,
+                             LPARAM,
+                             BOOL& handled) {         // NOLINT
+  ExceptionBarrier eb;
+  CORE_LOG(L3, (_T("[ProgressWnd::OnClose]")));
+
+  ++metric_worker_ui_click_x;
+
+  MaybeCloseWindow();
+  handled = true;
+  return 0;
+}
+
+HRESULT ProgressWnd::CloseWindow() {
+  HRESULT hr = DestroyWindow() ? S_OK : HRESULTFromLastError();
+  if (events_sink_) {
+    events_sink_->DoClose();
+  }
+  return hr;
+}
+
+void ProgressWnd::MaybeRequestExitProcess() {
+  CORE_LOG(L3, (_T("[ProgressWnd::MaybeRequestExitProcess]")));
+  if (cur_state_ != STATE_COMPLETE_SUCCESS &&
+      cur_state_ != STATE_COMPLETE_ERROR &&
+      cur_state_ != STATE_COMPLETE_RESTART_BROWSER &&
+      cur_state_ != STATE_COMPLETE_RESTART_ALL_BROWSERS &&
+      cur_state_ != STATE_COMPLETE_REBOOT) {
+    return;
+  }
+
+  RequestExitProcess();
+}
+
+void ProgressWnd::RequestExitProcess() {
+  CORE_LOG(L3, (_T("[ProgressWnd::RequestExitProcess]")));
+  ::PostQuitMessage(0);
+}
+
+bool ProgressWnd::MaybeCloseWindow() {
+  if (cur_state_ != STATE_COMPLETE_SUCCESS &&
+      cur_state_ != STATE_COMPLETE_ERROR &&
+      cur_state_ != STATE_COMPLETE_RESTART_BROWSER &&
+      cur_state_ != STATE_COMPLETE_RESTART_ALL_BROWSERS &&
+      cur_state_ != STATE_COMPLETE_REBOOT) {
+    // The UI is not in final state: ask the user to proceed with closing it.
+    // A modal dialog opens and sends a message back to this window to
+    // communicate the user decision.
+    install_stopped_wnd_.reset(new InstallStoppedWnd(message_loop_, *this));
+    HWND hwnd = install_stopped_wnd_->Create(*this);
+    if (hwnd) {
+      CString title;
+      VERIFY1(title.LoadString(IDS_INSTALLATION_STOPPED_WINDOW_TITLE));
+      VERIFY1(install_stopped_wnd_->SetWindowText(title));
+
+      CString button_text;
+      VERIFY1(button_text.LoadString(IDS_RESUME_INSTALLATION));
+      VERIFY1(::SetWindowText(
+          install_stopped_wnd_->GetDlgItem(IDOK), button_text));
+
+      VERIFY1(button_text.LoadString(IDS_CANCEL_INSTALLATION));
+      VERIFY1(::SetWindowText(
+          install_stopped_wnd_->GetDlgItem(IDCANCEL), button_text));
+
+      CString s;
+      s.FormatMessage(IDS_INSTALL_STOPPED, product_name_);
+      VERIFY1(::SetWindowText(
+          install_stopped_wnd_->GetDlgItem(IDC_INSTALL_STOPPED_TEXT), s));
+
+      VERIFY1(install_stopped_wnd_->CenterWindow(*this));
+      VERIFY1(!install_stopped_wnd_->ShowWindow(SW_SHOWDEFAULT));
+      return false;
+    } else {
+      ASSERT1(false);
+    }
+  }
+
+  // The UI is in a final state or the dialog box failed to open: proceed with
+  // closing the UI.
+  VERIFY1(SUCCEEDED(CloseWindow()));
+  return true;
+}
+
+LRESULT ProgressWnd::OnNCDestroy(UINT,
+                                 WPARAM,
+                                 LPARAM,
+                                 BOOL& handled) {         // NOLINT
+  ExceptionBarrier eb;
+  CORE_LOG(L3, (_T("[ProgressWnd::OnNCDestroy]")));
+  VERIFY1(message_loop_->RemoveMessageFilter(this));
+  MaybeRequestExitProcess();
+  handled = false;  // Let ATL default processing handle the WM_NCDESTROY.
+  return 0;
+}
+
+LRESULT ProgressWnd::OnClickedButton(WORD,
+                                     WORD id,
+                                     HWND,
+                                     BOOL& handled) {   // NOLINT
+  ExceptionBarrier eb;
+  CORE_LOG(L3, (_T("[ProgressWnd::OnClickedButton]")));
+  ASSERT1(id == IDC_BUTTON1 || id == IDC_BUTTON2 || id == IDC_CLOSE);
+  handled = true;
+  DestroyWindow();
+
+  if (events_sink_) {
+#pragma warning(push)
+// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by
+// a case label.
+#pragma warning(disable : 4061)
+
+    switch (id) {
+      case IDC_BUTTON1:
+        switch (cur_state_) {
+          case STATE_COMPLETE_RESTART_BROWSER:
+            ++metric_worker_ui_restart_browser_now_click;
+            events_sink_->DoRestartBrowsers();
+            break;
+          case STATE_COMPLETE_RESTART_ALL_BROWSERS:
+            ++metric_worker_ui_restart_all_browsers_now_click;
+            events_sink_->DoRestartBrowsers();
+            break;
+          case STATE_COMPLETE_REBOOT:
+            ++metric_worker_ui_reboot_now_click;
+            events_sink_->DoReboot();
+            break;
+          default:
+            ASSERT1(false);
+        }
+        break;
+      case IDC_BUTTON2:
+        switch (cur_state_) {
+          case STATE_COMPLETE_RESTART_BROWSER:
+          case STATE_COMPLETE_RESTART_ALL_BROWSERS:
+          case STATE_COMPLETE_REBOOT:
+            break;
+          default:
+            ASSERT1(false);
+        }
+        break;
+      case IDC_CLOSE:
+        switch (cur_state_) {
+          case STATE_COMPLETE_SUCCESS:
+          case STATE_COMPLETE_ERROR:
+            break;
+          default:
+            ASSERT1(false);
+        }
+        break;
+      default:
+        ASSERT1(false);
+    }
+
+#pragma warning(pop)
+
+    events_sink_->DoClose();
+  }
+  return 0;
+}
+
+// Called when esc key is hit.
+// If close is disabled, does nothing because we don't want the window to close.
+LRESULT ProgressWnd::OnCancel(WORD, WORD id,
+                              HWND, BOOL& handled) {    // NOLINT
+  ExceptionBarrier eb;
+  VERIFY1(id == IDCANCEL);
+
+  if (!is_close_enabled_) {
+    return 0;
+  }
+
+  ++metric_worker_ui_esc_key_total;
+  MaybeCloseWindow();
+  handled = true;
+  return 0;
+}
+
+LRESULT ProgressWnd::OnUrlClicked(int,
+                                  LPNMHDR params,
+                                  BOOL& handled) {      // NOLINT
+  CORE_LOG(L3, (_T("[ProgressWnd::OnUrlClicked]")));
+  ASSERT1(params);
+  handled = true;
+
+  if (IDC_GET_HELP_TEXT == params->idFrom) {
+    ++metric_worker_ui_get_help_click;
+  }
+
+  NM_STATICEX* notification = reinterpret_cast<NM_STATICEX*>(params);
+  events_sink_->DoLaunchBrowser(notification->action);
+
+  return 1;
+}
+
+LRESULT ProgressWnd::OnInstallStopped(UINT msg,
+                                      WPARAM wparam,
+                                      LPARAM,
+                                      BOOL& handled) {  // NOLINT
+  CORE_LOG(L3, (_T("[ProgressWnd::OnInstallStopped]")));
+  UNREFERENCED_PARAMETER(msg);
+
+  install_stopped_wnd_.reset();
+
+  ASSERT1(msg == WM_INSTALL_STOPPED);
+  ASSERT1(wparam == IDOK || wparam == IDCANCEL);
+  switch (wparam) {
+    case IDOK:
+      // TODO(omaha): Implement "Resume" here.
+      break;
+    case IDCANCEL:
+      // The user has decided to cancel.
+      metric_worker_ui_cancel_ms.AddSample(metrics_timer_->GetElapsedMs());
+      ++metric_worker_ui_cancels;
+      DestroyWindow();
+      if (events_sink_) {
+        events_sink_->DoClose();
+      }
+      break;
+    default:
+      ASSERT1(false);
+      break;
+  }
+
+  handled = true;
+  return 0;
+}
+
+void ProgressWnd::OnCheckingForUpdate() {
+  CORE_LOG(L3, (_T("[ProgressWnd::OnCheckingForUpdate]")));
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+  if (!IsWindow()) {
+    return;
+  }
+
+  cur_state_ = STATE_CHECKING_FOR_UPDATE;
+
+  CString s;
+  VERIFY1(s.LoadString(IDS_WAITING_TO_CONNECT));
+  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
+
+  VERIFY1(SUCCEEDED(SetMarqueeMode(true)));
+  VERIFY1(SUCCEEDED(ChangeControlState()));
+}
+
+void ProgressWnd::OnUpdateAvailable(const TCHAR* version_string) {
+  UNREFERENCED_PARAMETER(version_string);
+  CORE_LOG(L3, (_T("[ProgressWnd::OnUpdateAvailable][%s]"), version_string));
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+  if (!IsWindow()) {
+    return;
+  }
+}
+
+void ProgressWnd::OnWaitingToDownload() {
+  CORE_LOG(L3, (_T("[ProgressWnd::OnWaitingToDownload]")));
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+  if (!IsWindow()) {
+    return;
+  }
+
+  cur_state_ = STATE_WAITING_TO_DOWNLOAD;
+
+  CString s;
+  s.FormatMessage(IDS_WAITING_TO_DOWNLOAD, product_name_);
+  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
+
+  VERIFY1(SUCCEEDED(SetMarqueeMode(true)));
+  VERIFY1(SUCCEEDED(ChangeControlState()));
+}
+
+void ProgressWnd::OnDownloading(int time_remaining_ms, int pos) {
+  CORE_LOG(L5, (_T("[ProgressWnd::OnDownloading][pos=%d]"), pos));
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+  if (!IsWindow()) {
+    return;
+  }
+
+  ASSERT1(time_remaining_ms >=0);
+  ASSERT1(0 <= pos && pos <= 100);
+
+  time_remaining_ms;  // unreferenced formal parameter
+
+  cur_state_ = STATE_DOWNLOADING;
+
+  CString s;
+  s.FormatMessage(IDS_DOWNLOADING, product_name_);
+  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
+
+  VERIFY1(s.LoadString(IDS_PAUSE));
+  VERIFY1(::SetWindowText(GetDlgItem(IDC_PAUSE_RESUME_TEXT), s));
+
+  // TODO(omaha): implement time left.
+
+  // When the network is connecting keep the marquee moving, otherwise
+  // the user has no indication something is still going on.
+  // TODO(omaha): when resuming an incomplete download this will not work.
+  VERIFY1(SUCCEEDED(SetMarqueeMode(pos == 0)));
+  ::SendMessage(GetDlgItem(IDC_PROGRESS), PBM_SETPOS, pos, 0);
+  VERIFY1(SUCCEEDED(ChangeControlState()));
+}
+
+void ProgressWnd::OnWaitingToInstall() {
+  CORE_LOG(L3, (_T("[ProgressWnd::OnWaitingToInstall]")));
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+  if (!IsWindow()) {
+    return;
+  }
+
+  cur_state_ = STATE_WAITING_TO_INSTALL;
+
+  CString s;
+  s.FormatMessage(IDS_WAITING_TO_INSTALL, product_name_);
+  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
+
+  VERIFY1(SUCCEEDED(SetMarqueeMode(true)));
+  VERIFY1(SUCCEEDED(ChangeControlState()));
+}
+
+void ProgressWnd::OnInstalling() {
+  CORE_LOG(L3, (_T("[ProgressWnd::OnInstalling]")));
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+  if (!IsWindow()) {
+    return;
+  }
+
+  cur_state_ = STATE_INSTALLING;
+
+  // Close the 'Install Stop' window if it is on the screen because the user
+  // cannot cancel an install anyway.
+  CloseInstallStoppedWindow();
+
+  CString s;
+  s.FormatMessage(IDS_INSTALLING, product_name_);
+  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
+
+  VERIFY1(SUCCEEDED(EnableClose(false)));
+  VERIFY1(SUCCEEDED(SetMarqueeMode(true)));
+  VERIFY1(SUCCEEDED(ChangeControlState()));
+}
+
+void ProgressWnd::OnPause() {
+  CORE_LOG(L3, (_T("[ProgressWnd::OnPause]")));
+  ASSERT(false, (_T("These strings are not translated or in .rc files.")));
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+  if (!IsWindow()) {
+    return;
+  }
+
+  cur_state_ = STATE_PAUSED;
+
+  CString s;
+  s.FormatMessage(IDS_DOWNLOAD_PAUSED, product_name_);
+  VERIFY1(::SetWindowText(GetDlgItem(IDC_INSTALLER_STATE_TEXT), s));
+
+  VERIFY1(s.LoadString(IDS_RESUME));
+  VERIFY1(::SetWindowText(GetDlgItem(IDC_PAUSE_RESUME_TEXT), s));
+
+  // TODO(omaha): implement time left.
+
+  VERIFY1(SUCCEEDED(ChangeControlState()));
+}
+
+void ProgressWnd::OnShow() {
+  CORE_LOG(L3, (_T("[ProgressWnd::OnShow]")));
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+  if (!IsWindow() || IsWindowVisible()) {
+    return;
+  }
+
+  CenterWindow(NULL);
+  SetVisible(true);
+
+  if (!::SetForegroundWindow(*this)) {
+    CORE_LOG(LW, (_T("[::SetForegroundWindow failed %d]"), ::GetLastError()));
+  }
+
+  UIDisplayedEventManager::SignalEvent(is_machine_);
+}
+
+// The 'error_code' can contain an HRESULT or an installer error.
+void ProgressWnd::OnComplete(CompletionCodes code,
+                             const TCHAR* text,
+                             DWORD error_code) {
+  CORE_LOG(L3, (_T("[ProgressWnd::OnComplete]")
+                _T("[code=%d][error_code=0x%08x]"), code, error_code));
+  ASSERT1(thread_id_ == ::GetCurrentThreadId());
+
+  if (!IsWindow()) {
+    RequestExitProcess();
+    return;
+  }
+
+  // It is possible for the OnComplete callback to be called multiple times.
+  // Subclassing the control multiple times results in a crash, therefore
+  // unsubclass the control if the control has been created and subclassed
+  // before.
+  if (complete_text_ != NULL) {
+    complete_text_->UnsubclassWindow(true);
+    complete_text_.reset(NULL);
+  }
+
+  // Close the 'Install Stop' window if it is on the screen.
+  CloseInstallStoppedWindow();
+
+  CString s;
+  switch (code) {
+    case COMPLETION_CODE_SUCCESS_CLOSE_UI:
+      cur_state_ = STATE_COMPLETE_SUCCESS;
+      VERIFY1(SUCCEEDED(CloseWindow()));
+      return;
+
+    case COMPLETION_CODE_SUCCESS:
+      cur_state_ = STATE_COMPLETE_SUCCESS;
+      VERIFY1(s.LoadString(IDS_CLOSE));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_CLOSE), s));
+      complete_text_.reset(new StaticEx);
+      complete_text_->SubclassWindow(GetDlgItem(IDC_COMPLETE_TEXT));
+      ASSERT1(text);
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), text));
+      break;
+    case COMPLETION_CODE_ERROR:
+      cur_state_ = STATE_COMPLETE_ERROR;
+      VERIFY1(s.LoadString(IDS_CLOSE));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_CLOSE), s));
+      complete_text_.reset(new StaticEx);
+      complete_text_->SubclassWindow(GetDlgItem(IDC_ERROR_TEXT));
+      ASSERT1(text);
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_ERROR_TEXT), text));
+      VERIFY1(SUCCEEDED(ShowGetHelpLink(error_code)));
+      break;
+    case COMPLETION_CODE_RESTART_ALL_BROWSERS:
+      cur_state_ = STATE_COMPLETE_RESTART_ALL_BROWSERS;
+      VERIFY1(s.LoadString(IDS_RESTART_ALL_BROWSERS_NOW));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON1), s));
+      VERIFY1(s.LoadString(IDS_RESTART_ALL_BROWSERS_LATER));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON2), s));
+      s.FormatMessage(IDS_TEXT_RESTART_ALL_BROWSERS, product_name_);
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));
+      ++metric_worker_ui_restart_all_browsers_buttons_displayed;
+      break;
+    case COMPLETION_CODE_RESTART_BROWSER:
+      cur_state_ = STATE_COMPLETE_RESTART_BROWSER;
+      VERIFY1(s.LoadString(IDS_RESTART_BROWSER_NOW));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON1), s));
+      VERIFY1(s.LoadString(IDS_RESTART_BROWSER_LATER));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON2), s));
+      s.FormatMessage(IDS_TEXT_RESTART_BROWSER, product_name_);
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));
+      ++metric_worker_ui_restart_browser_buttons_displayed;
+      break;
+    case COMPLETION_CODE_REBOOT:
+      ASSERT(false, (_T("The button actions are not implemented.")));
+      cur_state_ = STATE_COMPLETE_REBOOT;
+      VERIFY1(s.LoadString(IDS_RESTART_NOW));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON1), s));
+      VERIFY1(s.LoadString(IDS_RESTART_LATER));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_BUTTON2), s));
+      s.FormatMessage(IDS_TEXT_REBOOT, product_name_);
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));
+      ++metric_worker_ui_reboot_buttons_displayed;
+      break;
+    case COMPLETION_CODE_RESTART_ALL_BROWSERS_NOTICE_ONLY:
+      cur_state_ = STATE_COMPLETE_SUCCESS;
+      VERIFY1(s.LoadString(IDS_CLOSE));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_CLOSE), s));
+      s.FormatMessage(IDS_TEXT_RESTART_ALL_BROWSERS, product_name_);
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));
+      break;
+    case COMPLETION_CODE_REBOOT_NOTICE_ONLY:
+      cur_state_ = STATE_COMPLETE_SUCCESS;
+      VERIFY1(s.LoadString(IDS_CLOSE));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_CLOSE), s));
+      s.FormatMessage(IDS_TEXT_REBOOT, product_name_);
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));
+      break;
+    case COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY:
+      cur_state_ = STATE_COMPLETE_SUCCESS;
+      VERIFY1(s.LoadString(IDS_CLOSE));
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_CLOSE), s));
+      s.FormatMessage(IDS_TEXT_RESTART_BROWSER, product_name_);
+      VERIFY1(::SetWindowText(GetDlgItem(IDC_COMPLETE_TEXT), s));
+      break;
+    case COMPLETION_CODE_RUN_COMMAND:
+    default:
+      ASSERT1(false);
+      break;
+  }
+
+  VERIFY1(SUCCEEDED(EnableClose(true)));
+  VERIFY1(SUCCEEDED(ChangeControlState()));
+}
+
+HRESULT ProgressWnd::ChangeControlState() {
+  for (size_t i = 0; i != arraysize(ProgressWnd::ctls_); ++i) {
+    const ControlState& ctl_state = ctls_[i];
+    HWND hwnd = GetDlgItem(ctls_[i].id_);
+    ASSERT1(hwnd);
+    const ControlAttributes& attr = ctl_state.attr_[cur_state_];
+    ::ShowWindow(hwnd, attr.is_visible_ ? SW_SHOW : SW_HIDE);
+    ::EnableWindow(hwnd, attr.is_enabled_ ? true : false);
+    if (attr.is_button_ && attr.is_default_) {
+      // We ask the dialog manager to give the default push button the focus, so
+      // for instance the <Enter> key works as expected.
+      GotoDlgCtrl(hwnd);
+      LONG style = ::GetWindowLong(hwnd, GWL_STYLE);
+      if (style) {
+        style |= BS_DEFPUSHBUTTON;
+        ::SetWindowLong(hwnd, GWL_STYLE, style);
+      }
+    }
+  }
+  return S_OK;
+}
+
+HRESULT ProgressWnd::SetMarqueeMode(bool is_marquee) {
+  if (!SystemInfo::IsRunningOnXPOrLater()) {
+    // Marquee is not supported on OSes below XP.
+    return S_OK;
+  }
+
+  HWND progress_bar = GetDlgItem(IDC_PROGRESS);
+  if (!progress_bar) {
+    return GOOPDATE_E_UI_INTERNAL_ERROR;
+  }
+
+  LONG style = ::GetWindowLong(progress_bar, GWL_STYLE);
+  if (!style) {
+    return HRESULTFromLastError();
+  }
+
+  if (is_marquee) {
+    if (style & PBS_MARQUEE) {
+      return S_OK;
+    }
+
+    style |= PBS_MARQUEE;
+    style = ::SetWindowLong(progress_bar, GWL_STYLE, style);
+    if (!style) {
+      return HRESULTFromLastError();
+    }
+
+    bool result = ::SendMessage(progress_bar, PBM_SETMARQUEE,
+                                is_marquee, kMarqueeModeUpdatesMs) != 0;
+    return result ? S_OK : GOOPDATE_E_UI_INTERNAL_ERROR;
+  } else {
+    if (!(style & PBS_MARQUEE)) {
+      return S_OK;
+    }
+
+    style &= ~PBS_MARQUEE;
+    style = ::SetWindowLong(progress_bar, GWL_STYLE, style);
+    if (!style) {
+      return HRESULTFromLastError();
+    }
+    return S_OK;
+  }
+}
+
+HRESULT ProgressWnd::EnableClose(bool enable) {
+  is_close_enabled_ = enable;
+  return EnableSystemCloseButton(is_close_enabled_);
+}
+
+HRESULT ProgressWnd::EnableSystemCloseButton(bool enable) {
+  HMENU menu = ::GetSystemMenu(*this, false);
+  ASSERT1(menu);
+  uint32 flags = MF_BYCOMMAND;
+  flags |= enable ? MF_ENABLED : MF_GRAYED;
+  VERIFY1(::EnableMenuItem(menu, SC_CLOSE, flags) != -1);
+  return S_OK;
+}
+
+// The system displays the system large icon in the ALT+TAB dialog box.
+// We do not need any small icon in the window caption. However, setting
+// ICON_BIG has the side effect of the window displaying a scaled down
+// version of it in the window caption. We could not find any way to
+// hide that icon, including setting the icon to NULL or handling WM_GETICON
+// message.
+HRESULT ProgressWnd::SetWindowIcon() {
+  const int cx = ::GetSystemMetrics(SM_CXICON);
+  const int cy = ::GetSystemMetrics(SM_CYICON);
+  HINSTANCE exe_instance = reinterpret_cast<HINSTANCE>(kExeLoadingAddress);
+  reset(hicon_,
+        reinterpret_cast<HICON>(::LoadImage(exe_instance,
+                                            MAKEINTRESOURCE(IDI_APP),
+                                            IMAGE_ICON,
+                                            cx,
+                                            cy,
+                                            LR_DEFAULTCOLOR)));
+  if (!hicon_) {
+    HRESULT hr = HRESULTFromLastError();
+    CORE_LOG(LEVEL_ERROR, (_T("[LoadImage failed 0x%08x]"), hr));
+    return hr;
+  }
+  VERIFY1(SendMessage(WM_SETICON,
+                      ICON_BIG,
+                      reinterpret_cast<LPARAM>(get(hicon_))) == NULL);
+  return S_OK;
+}
+
+HRESULT ProgressWnd::ShowGetHelpLink(HRESULT error_code) {
+  // When running elevated and ProcessLauncherClass is not registered, the
+  // browser launch from the link will fail. Don't display a link that will not
+  // work.
+  // TODO(omaha): Determine if ProcessLauncherClass is registered. Maybe move
+  // this code to the Worker.
+  if (vista_util::IsVistaOrLater() && vista_util::IsUserAdmin()) {
+    return S_OK;
+  }
+
+  // Do not display the link if the error already has a link.
+  if (GOOPDATE_E_OS_NOT_SUPPORTED == error_code) {
+    return S_OK;
+  }
+
+  const TCHAR* const kHelpLinkSourceId = _T("gethelp");
+  CString url;
+  HRESULT hr = goopdate_utils::BuildHttpGetString(
+      kUrlMoreInformation,
+      error_code,
+      0,   // extra code 1
+      0,   // extra code 2
+      GuidToString(product_guid_),
+      GetVersionString(),
+      is_machine_,
+      language_,
+      kHelpLinkSourceId,
+      &url);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  const TCHAR* const kLinkFormat = _T("<a=%s>%s</a>");
+  CString display_text;
+  VERIFY1(display_text.LoadString(IDS_HELP_ME_FIX_THIS_TEXT));
+  CString link_string;
+  link_string.Format(kLinkFormat, url, display_text);
+
+  get_help_text_.reset(new StaticEx);
+  get_help_text_->SubclassWindow(GetDlgItem(IDC_GET_HELP_TEXT));
+  VERIFY1(::SetWindowText(GetDlgItem(IDC_GET_HELP_TEXT), link_string));
+
+  ++metric_worker_ui_get_help_displayed;
+  return S_OK;
+}
+
+bool ProgressWnd::CloseInstallStoppedWindow() {
+  if (install_stopped_wnd_.get() && install_stopped_wnd_->IsWindow()) {
+    VERIFY1(SUCCEEDED(install_stopped_wnd_->CloseWindow()));
+    install_stopped_wnd_.reset();
+    return true;
+  } else {
+    return false;
+  }
+}
+
+}  // namespace omaha
+
diff --git a/worker/ui.h b/worker/ui.h
index ecbfbae..dbe9899 100644
--- a/worker/ui.h
+++ b/worker/ui.h
@@ -1,244 +1,244 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_UI_H__

-#define OMAHA_WORKER_UI_H__

-

-#include <atlbase.h>

-#include <vector>

-#include "base/scoped_ptr.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/wtl_atlapp_wrapper.h"

-#include "omaha/goopdate/resource.h"

-#include "omaha/worker/job_observer.h"

-#include "omaha/worker/uilib/static_ex.h"

-

-namespace omaha {

-

-class HighresTimer;

-

-// The message is used to communicate between InstallStoppedWnd and

-// ProgressWnd.

-const DWORD WM_INSTALL_STOPPED = WM_APP;

-

-// Implements the "Installation Stopped" window. InstallStoppedWnd is

-// modal relative to its parent. When InstallStoppedWnd is closed it sends

-// a user message to its parent to notify which button the user has clicked on.

-class InstallStoppedWnd

-    : public CAxDialogImpl<InstallStoppedWnd>,

-      public CMessageFilter {

-  typedef CAxDialogImpl<InstallStoppedWnd> Base;

- public:

-

-  static const int IDD = IDD_INSTALL_STOPPED;

-

-  InstallStoppedWnd(CMessageLoop* message_loop, HWND parent);

-  ~InstallStoppedWnd();

-

-  // Closes the window, handling transition back to the parent window.

-  HRESULT CloseWindow();

-

-  BOOL PreTranslateMessage(MSG* msg) {

-    return CWindow::IsDialogMessage(msg);

-  }

-

-  BEGIN_MSG_MAP(InstallStoppedWnd)

-    MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)

-    MESSAGE_HANDLER(WM_DESTROY, OnDestroy)

-    COMMAND_ID_HANDLER(IDOK, OnClickButton)

-    COMMAND_ID_HANDLER(IDCANCEL, OnClickButton)

-    CHAIN_MSG_MAP(Base)

-  END_MSG_MAP()

-

- private:

-  // Message and command handlers.

-  // All message handlers must be protected by exception barriers.

-  LRESULT OnInitDialog(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);    // NOLINT

-  LRESULT OnClickButton(WORD notify_code, WORD id, HWND wnd_ctl, BOOL& handled);  // NOLINT

-  LRESULT OnDestroy(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);       // NOLINT

-

-  CMessageLoop* message_loop_;

-  HWND parent_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(InstallStoppedWnd);

-};

-

-class ProgressWndEvents;

-

-// Implements the UI progress window.

-class ProgressWnd

-    : public CAxDialogImpl<ProgressWnd>,

-      public CMessageFilter,

-      public JobObserver {

-  typedef CAxDialogImpl<ProgressWnd> Base;

- public:

-  static const int IDD = IDD_PROGRESS;

-

-  ProgressWnd(CMessageLoop* message_loop, HWND parent);

-  ~ProgressWnd();

-

-  HRESULT Initialize();

-

-  void SetVisible(bool visible) {

-    ShowWindow(visible ? SW_SHOWNORMAL : SW_HIDE);

-  }

-

-  BOOL PreTranslateMessage(MSG* msg) {

-    return CWindow::IsDialogMessage(msg);

-  }

-

-  HRESULT GetWindowTitle(TCHAR* title, int size);

-  HRESULT SetWindowTitle(const TCHAR* title);

-

-  void set_is_machine(bool is_machine) { is_machine_ = is_machine; }

-  void set_language(const CString& language) { language_ = language; }

-  void set_product_name(const CString& name) { product_name_ = name; }

-  void set_product_guid(const GUID& guid) { product_guid_ = guid; }

-

-  // These methods are called by the job to transition the UI from

-  // one state to another. The methods are always executed by the thread

-  // that created this window.

-  virtual void OnShow();

-  virtual void OnCheckingForUpdate();

-  virtual void OnUpdateAvailable(const TCHAR* version_string);

-  virtual void OnWaitingToDownload();

-  virtual void OnDownloading(int time_remaining_ms, int pos);

-  virtual void OnWaitingToInstall();

-  virtual void OnInstalling();

-  virtual void OnPause();

-  virtual void OnComplete(CompletionCodes code,

-                          const TCHAR* text,

-                          DWORD error_code);

-  virtual void SetEventSink(ProgressWndEvents* ev) { events_sink_ = ev; }

-  virtual void Uninitialize() {}

-

-  BEGIN_MSG_MAP(ProgressWnd)

-    MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)

-    MESSAGE_HANDLER(WM_CLOSE, OnClose)

-    MESSAGE_HANDLER(WM_NCDESTROY, OnNCDestroy)

-    MESSAGE_HANDLER(WM_INSTALL_STOPPED, OnInstallStopped)

-    NOTIFY_CODE_HANDLER(MK_LBUTTON, OnUrlClicked)

-    COMMAND_HANDLER(IDC_BUTTON1, BN_CLICKED, OnClickedButton)

-    COMMAND_HANDLER(IDC_BUTTON2, BN_CLICKED, OnClickedButton)

-    COMMAND_HANDLER(IDC_CLOSE,   BN_CLICKED, OnClickedButton)

-    COMMAND_ID_HANDLER(IDCANCEL, OnCancel)

-    CHAIN_MSG_MAP(Base)

-  END_MSG_MAP()

-

- private:

-  // Message and command handlers.

-  // All message handlers must be protected by exception barriers.

-  LRESULT OnInitDialog(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);  // NOLINT

-  LRESULT OnClose(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);       // NOLINT

-  LRESULT OnNCDestroy(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);   // NOLINT

-  LRESULT OnInstallStopped(UINT msg, WPARAM wparam,

-                           LPARAM lparam, BOOL& handled);   // NOLINT

-  LRESULT OnClickedButton(WORD notify_code, WORD id,

-                          HWND wnd_ctl, BOOL& handled);     // NOLINT

-  LRESULT OnCancel(WORD notify_code, WORD id, HWND wnd_ctl, BOOL& handled);     // NOLINT

-  LRESULT OnUrlClicked(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);               // NOLINT

-

-  // Helpers.

-  HRESULT ChangeControlState();

-  HRESULT SetMarqueeMode(bool is_marquee);

-  HRESULT EnableClose(bool enable);

-  HRESULT EnableSystemCloseButton(bool enable);

-  HRESULT SetWindowIcon();

-  HRESULT ShowGetHelpLink(HRESULT error_code);

-

-  // Returns true if the window is closed.

-  bool MaybeCloseWindow();

-

-  // Closes the Installation Stopped window if present. Returns true if closed.

-  bool CloseInstallStoppedWindow();

-

-  // Closes the window.

-  HRESULT CloseWindow();

-

-  void MaybeRequestExitProcess();

-  void RequestExitProcess();

-

-  // The states are used as indexes in zero-based arrays so they should

-  // start at 0.

-  enum States {

-    STATE_INIT = 0,

-    STATE_CHECKING_FOR_UPDATE,

-    STATE_WAITING_TO_DOWNLOAD,

-    STATE_DOWNLOADING,

-    STATE_WAITING_TO_INSTALL,

-    STATE_INSTALLING,

-    STATE_PAUSED,

-    STATE_COMPLETE_SUCCESS,

-    STATE_COMPLETE_ERROR,

-    STATE_COMPLETE_RESTART_BROWSER,

-    STATE_COMPLETE_RESTART_ALL_BROWSERS,

-    STATE_COMPLETE_REBOOT,

-    STATE_END,

-  };

-

-#pragma warning(disable : 4510 4610)

-// C4510: default constructor could not be generated

-// C4610: struct can never be instantiated - user defined constructor required

-  struct ControlAttributes {

-    const bool is_visible_;

-    const bool is_enabled_;

-    const bool is_button_;

-    const bool is_default_;

-  };

-

-  struct ControlState {

-    const int id_;

-    const ControlAttributes attr_[ProgressWnd::STATE_END + 1];

-  };

-#pragma warning(default : 4510 4610)

-

-  static const ControlState ctls_[];

-

-  CMessageLoop* message_loop_;

-  HWND parent_;

-  DWORD thread_id_;

-

-  scoped_ptr<HighresTimer> metrics_timer_;

-

-  // Due to a repaint issue in StaticEx we prefer to manage their lifetime

-  // very aggressively so we contain them by reference instead of value.

-  scoped_ptr<StaticEx> pause_resume_text_;

-  scoped_ptr<StaticEx> complete_text_;

-  scoped_ptr<StaticEx> get_help_text_;

-

-  States cur_state_;

-  bool is_close_enabled_;

-

-  ProgressWndEvents* events_sink_;

-

-  bool is_machine_;

-  CString language_;

-  CString product_name_;

-  GUID product_guid_;

-

-  // The speed by which the progress bar moves in marquee mode.

-  static const int kMarqueeModeUpdatesMs = 75;

-

-  scoped_ptr<InstallStoppedWnd> install_stopped_wnd_;

-  scoped_hicon  hicon_;   // Handle to large icon to show when ALT-TAB

-

-  friend class UITest;

-  DISALLOW_EVIL_CONSTRUCTORS(ProgressWnd);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_UI_H__

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_UI_H__
+#define OMAHA_WORKER_UI_H__
+
+#include <atlbase.h>
+#include <vector>
+#include "base/scoped_ptr.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/wtl_atlapp_wrapper.h"
+#include "omaha/goopdate/resource.h"
+#include "omaha/worker/job_observer.h"
+#include "omaha/worker/uilib/static_ex.h"
+
+namespace omaha {
+
+class HighresTimer;
+
+// The message is used to communicate between InstallStoppedWnd and
+// ProgressWnd.
+const DWORD WM_INSTALL_STOPPED = WM_APP;
+
+// Implements the "Installation Stopped" window. InstallStoppedWnd is
+// modal relative to its parent. When InstallStoppedWnd is closed it sends
+// a user message to its parent to notify which button the user has clicked on.
+class InstallStoppedWnd
+    : public CAxDialogImpl<InstallStoppedWnd>,
+      public CMessageFilter {
+  typedef CAxDialogImpl<InstallStoppedWnd> Base;
+ public:
+
+  static const int IDD = IDD_INSTALL_STOPPED;
+
+  InstallStoppedWnd(CMessageLoop* message_loop, HWND parent);
+  ~InstallStoppedWnd();
+
+  // Closes the window, handling transition back to the parent window.
+  HRESULT CloseWindow();
+
+  BOOL PreTranslateMessage(MSG* msg) {
+    return CWindow::IsDialogMessage(msg);
+  }
+
+  BEGIN_MSG_MAP(InstallStoppedWnd)
+    MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
+    MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+    COMMAND_ID_HANDLER(IDOK, OnClickButton)
+    COMMAND_ID_HANDLER(IDCANCEL, OnClickButton)
+    CHAIN_MSG_MAP(Base)
+  END_MSG_MAP()
+
+ private:
+  // Message and command handlers.
+  // All message handlers must be protected by exception barriers.
+  LRESULT OnInitDialog(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);    // NOLINT
+  LRESULT OnClickButton(WORD notify_code, WORD id, HWND wnd_ctl, BOOL& handled);  // NOLINT
+  LRESULT OnDestroy(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);       // NOLINT
+
+  CMessageLoop* message_loop_;
+  HWND parent_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(InstallStoppedWnd);
+};
+
+class ProgressWndEvents;
+
+// Implements the UI progress window.
+class ProgressWnd
+    : public CAxDialogImpl<ProgressWnd>,
+      public CMessageFilter,
+      public JobObserver {
+  typedef CAxDialogImpl<ProgressWnd> Base;
+ public:
+  static const int IDD = IDD_PROGRESS;
+
+  ProgressWnd(CMessageLoop* message_loop, HWND parent);
+  ~ProgressWnd();
+
+  HRESULT Initialize();
+
+  void SetVisible(bool visible) {
+    ShowWindow(visible ? SW_SHOWNORMAL : SW_HIDE);
+  }
+
+  BOOL PreTranslateMessage(MSG* msg) {
+    return CWindow::IsDialogMessage(msg);
+  }
+
+  HRESULT GetWindowTitle(TCHAR* title, int size);
+  HRESULT SetWindowTitle(const TCHAR* title);
+
+  void set_is_machine(bool is_machine) { is_machine_ = is_machine; }
+  void set_language(const CString& language) { language_ = language; }
+  void set_product_name(const CString& name) { product_name_ = name; }
+  void set_product_guid(const GUID& guid) { product_guid_ = guid; }
+
+  // These methods are called by the job to transition the UI from
+  // one state to another. The methods are always executed by the thread
+  // that created this window.
+  virtual void OnShow();
+  virtual void OnCheckingForUpdate();
+  virtual void OnUpdateAvailable(const TCHAR* version_string);
+  virtual void OnWaitingToDownload();
+  virtual void OnDownloading(int time_remaining_ms, int pos);
+  virtual void OnWaitingToInstall();
+  virtual void OnInstalling();
+  virtual void OnPause();
+  virtual void OnComplete(CompletionCodes code,
+                          const TCHAR* text,
+                          DWORD error_code);
+  virtual void SetEventSink(ProgressWndEvents* ev) { events_sink_ = ev; }
+  virtual void Uninitialize() {}
+
+  BEGIN_MSG_MAP(ProgressWnd)
+    MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
+    MESSAGE_HANDLER(WM_CLOSE, OnClose)
+    MESSAGE_HANDLER(WM_NCDESTROY, OnNCDestroy)
+    MESSAGE_HANDLER(WM_INSTALL_STOPPED, OnInstallStopped)
+    NOTIFY_CODE_HANDLER(MK_LBUTTON, OnUrlClicked)
+    COMMAND_HANDLER(IDC_BUTTON1, BN_CLICKED, OnClickedButton)
+    COMMAND_HANDLER(IDC_BUTTON2, BN_CLICKED, OnClickedButton)
+    COMMAND_HANDLER(IDC_CLOSE,   BN_CLICKED, OnClickedButton)
+    COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
+    CHAIN_MSG_MAP(Base)
+  END_MSG_MAP()
+
+ private:
+  // Message and command handlers.
+  // All message handlers must be protected by exception barriers.
+  LRESULT OnInitDialog(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);  // NOLINT
+  LRESULT OnClose(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);       // NOLINT
+  LRESULT OnNCDestroy(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);   // NOLINT
+  LRESULT OnInstallStopped(UINT msg, WPARAM wparam,
+                           LPARAM lparam, BOOL& handled);   // NOLINT
+  LRESULT OnClickedButton(WORD notify_code, WORD id,
+                          HWND wnd_ctl, BOOL& handled);     // NOLINT
+  LRESULT OnCancel(WORD notify_code, WORD id, HWND wnd_ctl, BOOL& handled);     // NOLINT
+  LRESULT OnUrlClicked(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);               // NOLINT
+
+  // Helpers.
+  HRESULT ChangeControlState();
+  HRESULT SetMarqueeMode(bool is_marquee);
+  HRESULT EnableClose(bool enable);
+  HRESULT EnableSystemCloseButton(bool enable);
+  HRESULT SetWindowIcon();
+  HRESULT ShowGetHelpLink(HRESULT error_code);
+
+  // Returns true if the window is closed.
+  bool MaybeCloseWindow();
+
+  // Closes the Installation Stopped window if present. Returns true if closed.
+  bool CloseInstallStoppedWindow();
+
+  // Closes the window.
+  HRESULT CloseWindow();
+
+  void MaybeRequestExitProcess();
+  void RequestExitProcess();
+
+  // The states are used as indexes in zero-based arrays so they should
+  // start at 0.
+  enum States {
+    STATE_INIT = 0,
+    STATE_CHECKING_FOR_UPDATE,
+    STATE_WAITING_TO_DOWNLOAD,
+    STATE_DOWNLOADING,
+    STATE_WAITING_TO_INSTALL,
+    STATE_INSTALLING,
+    STATE_PAUSED,
+    STATE_COMPLETE_SUCCESS,
+    STATE_COMPLETE_ERROR,
+    STATE_COMPLETE_RESTART_BROWSER,
+    STATE_COMPLETE_RESTART_ALL_BROWSERS,
+    STATE_COMPLETE_REBOOT,
+    STATE_END,
+  };
+
+#pragma warning(disable : 4510 4610)
+// C4510: default constructor could not be generated
+// C4610: struct can never be instantiated - user defined constructor required
+  struct ControlAttributes {
+    const bool is_visible_;
+    const bool is_enabled_;
+    const bool is_button_;
+    const bool is_default_;
+  };
+
+  struct ControlState {
+    const int id_;
+    const ControlAttributes attr_[ProgressWnd::STATE_END + 1];
+  };
+#pragma warning(default : 4510 4610)
+
+  static const ControlState ctls_[];
+
+  CMessageLoop* message_loop_;
+  HWND parent_;
+  DWORD thread_id_;
+
+  scoped_ptr<HighresTimer> metrics_timer_;
+
+  // Due to a repaint issue in StaticEx we prefer to manage their lifetime
+  // very aggressively so we contain them by reference instead of value.
+  scoped_ptr<StaticEx> pause_resume_text_;
+  scoped_ptr<StaticEx> complete_text_;
+  scoped_ptr<StaticEx> get_help_text_;
+
+  States cur_state_;
+  bool is_close_enabled_;
+
+  ProgressWndEvents* events_sink_;
+
+  bool is_machine_;
+  CString language_;
+  CString product_name_;
+  GUID product_guid_;
+
+  // The speed by which the progress bar moves in marquee mode.
+  static const int kMarqueeModeUpdatesMs = 75;
+
+  scoped_ptr<InstallStoppedWnd> install_stopped_wnd_;
+  scoped_hicon  hicon_;   // Handle to large icon to show when ALT-TAB
+
+  friend class UITest;
+  DISALLOW_EVIL_CONSTRUCTORS(ProgressWnd);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_UI_H__
+
diff --git a/worker/ui_ctls.h b/worker/ui_ctls.h
index 0032dd7..4e4cc83 100644
--- a/worker/ui_ctls.h
+++ b/worker/ui_ctls.h
@@ -1,211 +1,211 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// This is a description on UI elements for different states of the UI.

-// We have only one dialog which changes between different UI states. Some

-// controls are hidded, some controls are disabled, etc...

-

-#ifndef OMAHA_WORKER_UI_CTLS_H__

-#define OMAHA_WORKER_UI_CTLS_H__

-

-#include "omaha/worker/ui.h"

-

-namespace omaha {

-

-const ProgressWnd::ControlState ProgressWnd::ctls_[] = {

-    // The struct values are:

-    // is_visible, is_enabled, is_button, is_default

-  { IDC_PROGRESS,

-    { { true,  true,  false, false },     // STATE_INIT

-      { true,  true,  false, false },     // STATE_CHECKING_FOR_UPDATE

-      { true,  true,  false, false },     // STATE_WAITING_TO_DOWNLOAD

-      { true,  true,  false, false },     // STATE_DOWNLOADING

-      { true,  true,  false, false },     // STATE_WAITING_TO_INSTALL

-      { true,  true,  false, false },     // STATE_INSTALLING

-      { true,  true,  false, false },     // STATE_PAUSED

-      { false, false, false, false },     // STATE_COMPLETE_SUCCESS

-      { false, false, false, false },     // STATE_COMPLETE_ERROR

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { false, false, false, false },     // STATE_COMPLETE_REBOOT

-      { false, false, false, false },     // STATE_END

-    },

-  },

-  { IDC_PAUSE_RESUME_TEXT,

-    { { false, false, false, false },     // STATE_INIT

-      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE

-      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD

-      { false,  true, false, false },     // STATE_DOWNLOADING

-      { false, false, false, false },     // STATE_WAITING_TO_INSTALL

-      { false, false, false, false },     // STATE_INSTALLING

-      { false,  true, false, false },     // STATE_PAUSED

-      { false, false, false, false },     // STATE_COMPLETE_SUCCESS

-      { false, false, false, false },     // STATE_COMPLETE_ERROR

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { false, false, false, false },     // STATE_COMPLETE_REBOOT

-      { false, false, false, false },     // STATE_END

-    },

-  },

-  { IDC_INFO_TEXT,

-    { { false, false, false, false },     // STATE_INIT

-      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE

-      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD

-      { false, true,  false, false },     // STATE_DOWNLOADING

-      { false, false, false, false },     // STATE_WAITING_TO_INSTALL

-      { false, false, false, false },     // STATE_INSTALLING

-      { false, false, false, false },     // STATE_PAUSED

-      { false, false, false, false },     // STATE_COMPLETE_SUCCESS

-      { false, false, false, false },     // STATE_COMPLETE_ERROR

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { false, false, false, false },     // STATE_COMPLETE_REBOOT

-      { false, false, false, false },     // STATE_END

-    },

-  },

-  { IDC_INSTALLER_STATE_TEXT,

-    { { true,  true,  false, false },     // STATE_INIT

-      { true,  true,  false, false },     // STATE_CHECKING_FOR_UPDATE

-      { true,  true,  false, false },     // STATE_WAITING_TO_DOWNLOAD

-      { true,  true,  false, false },     // STATE_DOWNLOADING

-      { true,  true,  false, false },     // STATE_WAITING_TO_INSTALL

-      { true,  true,  false, false },     // STATE_INSTALLING

-      { true,  true,  false, false },     // STATE_PAUSED

-      { false, false, false, false },     // STATE_COMPLETE_SUCCESS

-      { false, false, false, false },     // STATE_COMPLETE_ERROR

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { false, false, false, false },     // STATE_COMPLETE_REBOOT

-      { false, false, false, false },     // STATE_END

-    },

-  },

-  { IDC_COMPLETE_TEXT,

-    { { false, false, false, false },     // STATE_INIT

-      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE

-      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD

-      { false, false, false, false },     // STATE_DOWNLOADING

-      { false, false, false, false },     // STATE_WAITING_TO_INSTALL

-      { false, false, false, false },     // STATE_INSTALLING

-      { false, false, false, false },     // STATE_PAUSED

-      { true,  true,  false, false },     // STATE_COMPLETE_SUCCESS

-      { false, false, false, false },     // STATE_COMPLETE_ERROR

-      { true,  true,  false, false },     // STATE_COMPLETE_RESTART_BROWSER

-      { true,  true,  false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { true,  true,  false, false },     // STATE_COMPLETE_REBOOT

-      { false, false, false, false },     // STATE_END

-    },

-  },

-  { IDC_ERROR_TEXT,

-    { { false, false, false, false },     // STATE_INIT

-      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE

-      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD

-      { false, false, false, false },     // STATE_DOWNLOADING

-      { false, false, false, false },     // STATE_WAITING_TO_INSTALL

-      { false, false, false, false },     // STATE_INSTALLING

-      { false, false, false, false },     // STATE_PAUSED

-      { false, false, false, false },     // STATE_COMPLETE_SUCCESS

-      { true,  true,  false, false },     // STATE_COMPLETE_ERROR

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { false, false, false, false },     // STATE_COMPLETE_REBOOT

-      { false, false, false, false },     // STATE_END

-    },

-  },

-  { IDC_GET_HELP_TEXT,

-    { { false, false, false, false },     // STATE_INIT

-      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE

-      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD

-      { false, false, false, false },     // STATE_DOWNLOADING

-      { false, false, false, false },     // STATE_WAITING_TO_INSTALL

-      { false, false, false, false },     // STATE_INSTALLING

-      { false, false, false, false },     // STATE_PAUSED

-      { false, false, false, false },     // STATE_COMPLETE_SUCCESS

-      { true,  true,  false, false },     // STATE_COMPLETE_ERROR

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER

-      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { false, false, false, false },     // STATE_COMPLETE_REBOOT

-      { false, false, false, false },     // STATE_END

-    },

-  },

-  { IDC_BUTTON1,

-    { { false, false, true, false },     // STATE_INIT

-      { false, false, true, false },     // STATE_CHECKING_FOR_UPDATE

-      { false, false, true, false },     // STATE_WAITING_TO_DOWNLOAD

-      { false, false, true, false },     // STATE_DOWNLOADING

-      { false, false, true, false },     // STATE_WAITING_TO_INSTALL

-      { false, false, true, false },     // STATE_INSTALLING

-      { false, false, true, false },     // STATE_PAUSED

-      { false, false, true, false },     // STATE_COMPLETE_SUCCESS

-      { false, false, true, false },     // STATE_COMPLETE_ERROR

-      { true,  true,  true, true  },     // STATE_COMPLETE_RESTART_BROWSER

-      { true,  true,  true, true  },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { true,  true,  true, true  },     // STATE_COMPLETE_REBOOT

-      { false, false, true, false },     // STATE_END

-    },

-  },

-  { IDC_BUTTON2,

-    { { false, false, true, false },     // STATE_INIT

-      { false, false, true, false },     // STATE_CHECKING_FOR_UPDATE

-      { false, false, true, false },     // STATE_WAITING_TO_DOWNLOAD

-      { false, false, true, false },     // STATE_DOWNLOADING

-      { false, false, true, false },     // STATE_WAITING_TO_INSTALL

-      { false, false, true, false },     // STATE_INSTALLING

-      { false, false, true, false },     // STATE_PAUSED

-      { false, false, true, false },     // STATE_COMPLETE_SUCCESS

-      { false, false, true, false },     // STATE_COMPLETE_ERROR

-      { true,  true,  true, false },     // STATE_COMPLETE_RESTART_BROWSER

-      { true,  true,  true, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { true,  true,  true, false },     // STATE_COMPLETE_REBOOT

-      { false, false, true, false },     // STATE_END

-    },

-  },

-  { IDC_CLOSE,

-    { { false, false, true, false },     // STATE_INIT

-      { false, false, true, false },     // STATE_CHECKING_FOR_UPDATE

-      { false, false, true, false },     // STATE_WAITING_TO_DOWNLOAD

-      { false, false, true, false },     // STATE_DOWNLOADING

-      { false, false, true, false },     // STATE_WAITING_TO_INSTALL

-      { false, false, true, false },     // STATE_INSTALLING

-      { false, false, true, false },     // STATE_PAUSED

-      { true,  true,  true, true  },     // STATE_COMPLETE_SUCCESS

-      { true,  true,  true, true  },     // STATE_COMPLETE_ERROR

-      { false, false, true, false },     // STATE_COMPLETE_RESTART_BROWSER

-      { false, false, true, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { false, false, true, false },     // STATE_COMPLETE_REBOOT

-      { false, false, true, false },     // STATE_END

-    },

-  },

-  { IDC_IMAGE,

-    { { false, false, false, false },     // STATE_INIT

-      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE

-      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD

-      { false, false, false, false },     // STATE_DOWNLOADING

-      { false, false, false, false },     // STATE_WAITING_TO_INSTALL

-      { false, false, false, false },     // STATE_INSTALLING

-      { false, false, false, false },     // STATE_PAUSED

-      { true,  false, false, false },     // STATE_COMPLETE_SUCCESS

-      { false, false, false, false },     // STATE_COMPLETE_ERROR

-      { true,  false, false, false },     // STATE_COMPLETE_RESTART_BROWSER

-      { true,  false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS

-      { true,  false, false, false },     // STATE_COMPLETE_REBOOT

-      { false, false, false, false },     // STATE_END

-    },

-  },

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_UI_CTLS_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// This is a description on UI elements for different states of the UI.
+// We have only one dialog which changes between different UI states. Some
+// controls are hidded, some controls are disabled, etc...
+
+#ifndef OMAHA_WORKER_UI_CTLS_H__
+#define OMAHA_WORKER_UI_CTLS_H__
+
+#include "omaha/worker/ui.h"
+
+namespace omaha {
+
+const ProgressWnd::ControlState ProgressWnd::ctls_[] = {
+    // The struct values are:
+    // is_visible, is_enabled, is_button, is_default
+  { IDC_PROGRESS,
+    { { true,  true,  false, false },     // STATE_INIT
+      { true,  true,  false, false },     // STATE_CHECKING_FOR_UPDATE
+      { true,  true,  false, false },     // STATE_WAITING_TO_DOWNLOAD
+      { true,  true,  false, false },     // STATE_DOWNLOADING
+      { true,  true,  false, false },     // STATE_WAITING_TO_INSTALL
+      { true,  true,  false, false },     // STATE_INSTALLING
+      { true,  true,  false, false },     // STATE_PAUSED
+      { false, false, false, false },     // STATE_COMPLETE_SUCCESS
+      { false, false, false, false },     // STATE_COMPLETE_ERROR
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { false, false, false, false },     // STATE_COMPLETE_REBOOT
+      { false, false, false, false },     // STATE_END
+    },
+  },
+  { IDC_PAUSE_RESUME_TEXT,
+    { { false, false, false, false },     // STATE_INIT
+      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE
+      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD
+      { false,  true, false, false },     // STATE_DOWNLOADING
+      { false, false, false, false },     // STATE_WAITING_TO_INSTALL
+      { false, false, false, false },     // STATE_INSTALLING
+      { false,  true, false, false },     // STATE_PAUSED
+      { false, false, false, false },     // STATE_COMPLETE_SUCCESS
+      { false, false, false, false },     // STATE_COMPLETE_ERROR
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { false, false, false, false },     // STATE_COMPLETE_REBOOT
+      { false, false, false, false },     // STATE_END
+    },
+  },
+  { IDC_INFO_TEXT,
+    { { false, false, false, false },     // STATE_INIT
+      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE
+      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD
+      { false, true,  false, false },     // STATE_DOWNLOADING
+      { false, false, false, false },     // STATE_WAITING_TO_INSTALL
+      { false, false, false, false },     // STATE_INSTALLING
+      { false, false, false, false },     // STATE_PAUSED
+      { false, false, false, false },     // STATE_COMPLETE_SUCCESS
+      { false, false, false, false },     // STATE_COMPLETE_ERROR
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { false, false, false, false },     // STATE_COMPLETE_REBOOT
+      { false, false, false, false },     // STATE_END
+    },
+  },
+  { IDC_INSTALLER_STATE_TEXT,
+    { { true,  true,  false, false },     // STATE_INIT
+      { true,  true,  false, false },     // STATE_CHECKING_FOR_UPDATE
+      { true,  true,  false, false },     // STATE_WAITING_TO_DOWNLOAD
+      { true,  true,  false, false },     // STATE_DOWNLOADING
+      { true,  true,  false, false },     // STATE_WAITING_TO_INSTALL
+      { true,  true,  false, false },     // STATE_INSTALLING
+      { true,  true,  false, false },     // STATE_PAUSED
+      { false, false, false, false },     // STATE_COMPLETE_SUCCESS
+      { false, false, false, false },     // STATE_COMPLETE_ERROR
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { false, false, false, false },     // STATE_COMPLETE_REBOOT
+      { false, false, false, false },     // STATE_END
+    },
+  },
+  { IDC_COMPLETE_TEXT,
+    { { false, false, false, false },     // STATE_INIT
+      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE
+      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD
+      { false, false, false, false },     // STATE_DOWNLOADING
+      { false, false, false, false },     // STATE_WAITING_TO_INSTALL
+      { false, false, false, false },     // STATE_INSTALLING
+      { false, false, false, false },     // STATE_PAUSED
+      { true,  true,  false, false },     // STATE_COMPLETE_SUCCESS
+      { false, false, false, false },     // STATE_COMPLETE_ERROR
+      { true,  true,  false, false },     // STATE_COMPLETE_RESTART_BROWSER
+      { true,  true,  false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { true,  true,  false, false },     // STATE_COMPLETE_REBOOT
+      { false, false, false, false },     // STATE_END
+    },
+  },
+  { IDC_ERROR_TEXT,
+    { { false, false, false, false },     // STATE_INIT
+      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE
+      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD
+      { false, false, false, false },     // STATE_DOWNLOADING
+      { false, false, false, false },     // STATE_WAITING_TO_INSTALL
+      { false, false, false, false },     // STATE_INSTALLING
+      { false, false, false, false },     // STATE_PAUSED
+      { false, false, false, false },     // STATE_COMPLETE_SUCCESS
+      { true,  true,  false, false },     // STATE_COMPLETE_ERROR
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { false, false, false, false },     // STATE_COMPLETE_REBOOT
+      { false, false, false, false },     // STATE_END
+    },
+  },
+  { IDC_GET_HELP_TEXT,
+    { { false, false, false, false },     // STATE_INIT
+      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE
+      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD
+      { false, false, false, false },     // STATE_DOWNLOADING
+      { false, false, false, false },     // STATE_WAITING_TO_INSTALL
+      { false, false, false, false },     // STATE_INSTALLING
+      { false, false, false, false },     // STATE_PAUSED
+      { false, false, false, false },     // STATE_COMPLETE_SUCCESS
+      { true,  true,  false, false },     // STATE_COMPLETE_ERROR
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_BROWSER
+      { false, false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { false, false, false, false },     // STATE_COMPLETE_REBOOT
+      { false, false, false, false },     // STATE_END
+    },
+  },
+  { IDC_BUTTON1,
+    { { false, false, true, false },     // STATE_INIT
+      { false, false, true, false },     // STATE_CHECKING_FOR_UPDATE
+      { false, false, true, false },     // STATE_WAITING_TO_DOWNLOAD
+      { false, false, true, false },     // STATE_DOWNLOADING
+      { false, false, true, false },     // STATE_WAITING_TO_INSTALL
+      { false, false, true, false },     // STATE_INSTALLING
+      { false, false, true, false },     // STATE_PAUSED
+      { false, false, true, false },     // STATE_COMPLETE_SUCCESS
+      { false, false, true, false },     // STATE_COMPLETE_ERROR
+      { true,  true,  true, true  },     // STATE_COMPLETE_RESTART_BROWSER
+      { true,  true,  true, true  },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { true,  true,  true, true  },     // STATE_COMPLETE_REBOOT
+      { false, false, true, false },     // STATE_END
+    },
+  },
+  { IDC_BUTTON2,
+    { { false, false, true, false },     // STATE_INIT
+      { false, false, true, false },     // STATE_CHECKING_FOR_UPDATE
+      { false, false, true, false },     // STATE_WAITING_TO_DOWNLOAD
+      { false, false, true, false },     // STATE_DOWNLOADING
+      { false, false, true, false },     // STATE_WAITING_TO_INSTALL
+      { false, false, true, false },     // STATE_INSTALLING
+      { false, false, true, false },     // STATE_PAUSED
+      { false, false, true, false },     // STATE_COMPLETE_SUCCESS
+      { false, false, true, false },     // STATE_COMPLETE_ERROR
+      { true,  true,  true, false },     // STATE_COMPLETE_RESTART_BROWSER
+      { true,  true,  true, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { true,  true,  true, false },     // STATE_COMPLETE_REBOOT
+      { false, false, true, false },     // STATE_END
+    },
+  },
+  { IDC_CLOSE,
+    { { false, false, true, false },     // STATE_INIT
+      { false, false, true, false },     // STATE_CHECKING_FOR_UPDATE
+      { false, false, true, false },     // STATE_WAITING_TO_DOWNLOAD
+      { false, false, true, false },     // STATE_DOWNLOADING
+      { false, false, true, false },     // STATE_WAITING_TO_INSTALL
+      { false, false, true, false },     // STATE_INSTALLING
+      { false, false, true, false },     // STATE_PAUSED
+      { true,  true,  true, true  },     // STATE_COMPLETE_SUCCESS
+      { true,  true,  true, true  },     // STATE_COMPLETE_ERROR
+      { false, false, true, false },     // STATE_COMPLETE_RESTART_BROWSER
+      { false, false, true, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { false, false, true, false },     // STATE_COMPLETE_REBOOT
+      { false, false, true, false },     // STATE_END
+    },
+  },
+  { IDC_IMAGE,
+    { { false, false, false, false },     // STATE_INIT
+      { false, false, false, false },     // STATE_CHECKING_FOR_UPDATE
+      { false, false, false, false },     // STATE_WAITING_TO_DOWNLOAD
+      { false, false, false, false },     // STATE_DOWNLOADING
+      { false, false, false, false },     // STATE_WAITING_TO_INSTALL
+      { false, false, false, false },     // STATE_INSTALLING
+      { false, false, false, false },     // STATE_PAUSED
+      { true,  false, false, false },     // STATE_COMPLETE_SUCCESS
+      { false, false, false, false },     // STATE_COMPLETE_ERROR
+      { true,  false, false, false },     // STATE_COMPLETE_RESTART_BROWSER
+      { true,  false, false, false },     // STATE_COMPLETE_RESTART_ALL_BROWSERS
+      { true,  false, false, false },     // STATE_COMPLETE_REBOOT
+      { false, false, false, false },     // STATE_END
+    },
+  },
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_UI_CTLS_H__
+
diff --git a/worker/uilib/node.h b/worker/uilib/node.h
index ece65ad..4521fb2 100644
--- a/worker/uilib/node.h
+++ b/worker/uilib/node.h
@@ -1,40 +1,40 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// node.h : Declaration of the Node

-

-#ifndef OMAHA_WORKER_UILIB_NODE_H_

-#define OMAHA_WORKER_UILIB_NODE_H_

-

-#include "omaha/worker/uilib/node_state.h"

-

-class Node {

- public:

-

-  explicit Node(HWND window) : node_state_(window) {}

-  virtual ~Node() {}

-

-  CString node_text() const { return node_text_; }

-  void AddText(const TCHAR* text) { node_text_ += text; }

-

-  void set_node_state(const NodeState& node_state) { node_state_ = node_state; }

-  const NodeState& node_state() const { return node_state_; }

-

- private:

-  CString       node_text_;

-  NodeState     node_state_;

-};

-

-#endif  // OMAHA_WORKER_UILIB_NODE_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// node.h : Declaration of the Node
+
+#ifndef OMAHA_WORKER_UILIB_NODE_H_
+#define OMAHA_WORKER_UILIB_NODE_H_
+
+#include "omaha/worker/uilib/node_state.h"
+
+class Node {
+ public:
+
+  explicit Node(HWND window) : node_state_(window) {}
+  virtual ~Node() {}
+
+  CString node_text() const { return node_text_; }
+  void AddText(const TCHAR* text) { node_text_ += text; }
+
+  void set_node_state(const NodeState& node_state) { node_state_ = node_state; }
+  const NodeState& node_state() const { return node_state_; }
+
+ private:
+  CString       node_text_;
+  NodeState     node_state_;
+};
+
+#endif  // OMAHA_WORKER_UILIB_NODE_H_
diff --git a/worker/uilib/node_state.cc b/worker/uilib/node_state.cc
index d7d1a2f..90c56d9 100644
--- a/worker/uilib/node_state.cc
+++ b/worker/uilib/node_state.cc
@@ -1,237 +1,237 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-

-#include "omaha/worker/uilib/node_state.h"

-

-// Add a list item tag

-NodeState::Tags NodeState::tags_[] = {

-// name_to_match        length_name_to_match       action      no_parameters;

-  { _T("<b>"),       static_cast<int>(_tcslen(_T("<b>"))),      BOLD_ON,        true  },  // NOLINT

-  { _T("</b>"),      static_cast<int>(_tcslen(_T("</b>"))),     BOLD_OFF,       true  },  // NOLINT

-  { _T("<i>"),       static_cast<int>(_tcslen(_T("<i>"))),      ITALIC_ON,      true  },  // NOLINT

-  { _T("</i>"),      static_cast<int>(_tcslen(_T("</i>"))),     ITALIC_OFF,     true  },  // NOLINT

-  { _T("<u>"),       static_cast<int>(_tcslen(_T("<u>"))),      UNDERLINE_ON,   true  },  // NOLINT

-  { _T("</u>"),      static_cast<int>(_tcslen(_T("</u>"))),     UNDERLINE_OFF,  true  },  // NOLINT

-  { _T("<color="),   static_cast<int>(_tcslen(_T("<color="))),  TEXTCOLOR_ON,   false },  // NOLINT

-  { _T("</color>"),  static_cast<int>(_tcslen(_T("</color>"))), TEXTCOLOR_OFF,  true  },  // NOLINT

-  { _T("<size="),    static_cast<int>(_tcslen(_T("<size="))),   TEXTSIZE_ON,    false },  // NOLINT

-  { _T("</size>"),   static_cast<int>(_tcslen(_T("</size>"))),  TEXTSIZE_OFF,   true  },  // NOLINT

-  { _T("<a="),       static_cast<int>(_tcslen(_T("<a="))),      URL_ON,         false },  // NOLINT

-  { _T("</a>"),      static_cast<int>(_tcslen(_T("</a>"))),     URL_OFF,        true  },  // NOLINT

-};

-

-NodeState::NodeState(HWND window)

-    : default_font_(NULL),

-      font_(NULL),

-      bold_(false),

-      italic_(false),

-      underline_(false),

-      text_color_(0),

-      text_size_(8),

-      owner_window_(window) {

-}

-

-NodeState::~NodeState() {

-}

-

-

-void NodeState::SetStdFont(HFONT font) {

-  default_font_ = font;

-}

-

-

-HFONT NodeState::GetFont() const {

-  if (IsDefaultFont())

-    return default_font_;

-

-  if (font_)

-    return font_;

-

-  if (default_font_) {

-    HDC dc = GetDC(owner_window_);

-

-    LOGFONT log_font;

-    GetObject(default_font_, sizeof(LOGFONT), &log_font);

-    log_font.lfWeight    = bold_ ? FW_BOLD : FW_NORMAL;

-    log_font.lfItalic    = italic_;

-    log_font.lfUnderline = underline_;

-    log_font.lfHeight    =

-        -MulDiv(text_size_, GetDeviceCaps(dc, LOGPIXELSY), 72);

-    font_ = CreateFontIndirect(&log_font);

-  }

-

-  return font_;

-}

-

-

-bool NodeState::IsDefaultFont() const {

-    if (bold_ || italic_ || underline_)

-        return false;

-

-    if (text_size_ != 8)

-        return false;

-

-    return true;

-}

-

-

-int NodeState::ConsumeTag(const TCHAR* string) {

-  int size = sizeof(tags_) / sizeof(tags_[0]);

-  for (int i = 0; i < size; i++) {

-    if (_tcsnicmp(string, tags_[i].name_to_match,

-                  tags_[i].length_name_to_match) == 0) {

-      if (tags_[i].no_parameters) {

-        ApplyAction(tags_[i].action, NULL);

-        return tags_[i].length_name_to_match;

-      } else {

-        return tags_[i].length_name_to_match +

-               ApplyAction(tags_[i].action, string +

-                           tags_[i].length_name_to_match) + 1;

-      }

-    }

-  }

-

-  return 0;

-}

-

-

-int NodeState::ApplyAction(Actions action, const TCHAR* string/*=NULL*/) {

-  int read = 0;

-  switch (action) {

-  case BOLD_ON :

-    bold_ = true;

-    break;

-

-  case BOLD_OFF :

-    bold_ = false;

-    break;

-

-  case ITALIC_ON :

-    italic_ = true;

-    break;

-

-  case ITALIC_OFF :

-    italic_ = false;

-    break;

-

-  case UNDERLINE_ON :

-    underline_ = true;

-    break;

-

-  case UNDERLINE_OFF :

-    underline_ = false;

-    break;

-

-  case TEXTCOLOR_ON :

-    ATLASSERT(string);

-    if (string) {

-      int nParam = 0;

-      read = ReadColorRef(string, &nParam);

-      text_color_ = nParam;

-    }

-    break;

-

-  case TEXTCOLOR_OFF :

-    text_color_ = 0;

-    break;

-

-  case TEXTSIZE_ON :

-    ATLASSERT(string);

-    if (string)

-      read = ReadNumParameter(string, &text_size_);

-    break;

-

-  case TEXTSIZE_OFF :

-    text_size_ = 8;

-    break;

-

-  case URL_ON :

-    underline_ = true;

-    text_color_ = RGB(0, 0, 0xff);

-    ATLASSERT(string);

-    if (string)

-      read = ReadString(string, &url_);

-    break;

-

-  case URL_OFF :

-    underline_ = false;

-    text_color_ = 0;

-    url_ = _T("");

-    break;

-

-  case UNKNOWN:

-    // fall thru

-

-  default:

-    ATLASSERT(false);

-  }

-  return read;

-}

-

-int NodeState::ReadNumParameter(const TCHAR* string, int* param) {

-  if (!param)

-    return 0;

-

-  *param = 0;

-  const TCHAR* current_pos = string;

-  while (current_pos && _istdigit(*current_pos)) {

-    *param *= 10;

-    *param += *current_pos - _T('0');

-    current_pos++;

-  }

-  return static_cast<int>(current_pos - string);

-}

-

-int NodeState::ReadHexParameter(const TCHAR* string, int* param) {

-  if (!param)

-    return 0;

-

-  *param = 0;

-  const TCHAR* current_pos = string;

-  while (current_pos && _istxdigit(*current_pos)) {

-    *param = ((*param) << 4);

-    if (_istdigit(*current_pos))

-      *param += *current_pos - _T('0');

-    else

-      *param += (*current_pos | 0x20) - _T('a') + 10;

-    current_pos++;

-  }

-  return static_cast<int>(current_pos - string);

-}

-

-int NodeState::ReadColorRef(const TCHAR* string, int* param) {

-  if (!param)

-    return 0;

-

-  int read = ReadHexParameter(string, param);

-  *param = RGB((*param) >> 16, ((*param) >> 8) & 0xff, (*param) & 0xff);

-  return read;

-}

-

-int NodeState::ReadString(const TCHAR* string, CString* string_out) {

-  if (!string_out)

-    return 0;

-

-  int length = 0;

-  int position = _tcscspn(string, _T(" >"));

-  if (position >= 0) {

-    *string_out = CString(string, position);

-    length = position;

-  }

-

-  return length;

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+
+#include "omaha/worker/uilib/node_state.h"
+
+// Add a list item tag
+NodeState::Tags NodeState::tags_[] = {
+// name_to_match        length_name_to_match       action      no_parameters;
+  { _T("<b>"),       static_cast<int>(_tcslen(_T("<b>"))),      BOLD_ON,        true  },  // NOLINT
+  { _T("</b>"),      static_cast<int>(_tcslen(_T("</b>"))),     BOLD_OFF,       true  },  // NOLINT
+  { _T("<i>"),       static_cast<int>(_tcslen(_T("<i>"))),      ITALIC_ON,      true  },  // NOLINT
+  { _T("</i>"),      static_cast<int>(_tcslen(_T("</i>"))),     ITALIC_OFF,     true  },  // NOLINT
+  { _T("<u>"),       static_cast<int>(_tcslen(_T("<u>"))),      UNDERLINE_ON,   true  },  // NOLINT
+  { _T("</u>"),      static_cast<int>(_tcslen(_T("</u>"))),     UNDERLINE_OFF,  true  },  // NOLINT
+  { _T("<color="),   static_cast<int>(_tcslen(_T("<color="))),  TEXTCOLOR_ON,   false },  // NOLINT
+  { _T("</color>"),  static_cast<int>(_tcslen(_T("</color>"))), TEXTCOLOR_OFF,  true  },  // NOLINT
+  { _T("<size="),    static_cast<int>(_tcslen(_T("<size="))),   TEXTSIZE_ON,    false },  // NOLINT
+  { _T("</size>"),   static_cast<int>(_tcslen(_T("</size>"))),  TEXTSIZE_OFF,   true  },  // NOLINT
+  { _T("<a="),       static_cast<int>(_tcslen(_T("<a="))),      URL_ON,         false },  // NOLINT
+  { _T("</a>"),      static_cast<int>(_tcslen(_T("</a>"))),     URL_OFF,        true  },  // NOLINT
+};
+
+NodeState::NodeState(HWND window)
+    : default_font_(NULL),
+      font_(NULL),
+      bold_(false),
+      italic_(false),
+      underline_(false),
+      text_color_(0),
+      text_size_(8),
+      owner_window_(window) {
+}
+
+NodeState::~NodeState() {
+}
+
+
+void NodeState::SetStdFont(HFONT font) {
+  default_font_ = font;
+}
+
+
+HFONT NodeState::GetFont() const {
+  if (IsDefaultFont())
+    return default_font_;
+
+  if (font_)
+    return font_;
+
+  if (default_font_) {
+    HDC dc = GetDC(owner_window_);
+
+    LOGFONT log_font;
+    GetObject(default_font_, sizeof(LOGFONT), &log_font);
+    log_font.lfWeight    = bold_ ? FW_BOLD : FW_NORMAL;
+    log_font.lfItalic    = italic_;
+    log_font.lfUnderline = underline_;
+    log_font.lfHeight    =
+        -MulDiv(text_size_, GetDeviceCaps(dc, LOGPIXELSY), 72);
+    font_ = CreateFontIndirect(&log_font);
+  }
+
+  return font_;
+}
+
+
+bool NodeState::IsDefaultFont() const {
+    if (bold_ || italic_ || underline_)
+        return false;
+
+    if (text_size_ != 8)
+        return false;
+
+    return true;
+}
+
+
+int NodeState::ConsumeTag(const TCHAR* string) {
+  int size = sizeof(tags_) / sizeof(tags_[0]);
+  for (int i = 0; i < size; i++) {
+    if (_tcsnicmp(string, tags_[i].name_to_match,
+                  tags_[i].length_name_to_match) == 0) {
+      if (tags_[i].no_parameters) {
+        ApplyAction(tags_[i].action, NULL);
+        return tags_[i].length_name_to_match;
+      } else {
+        return tags_[i].length_name_to_match +
+               ApplyAction(tags_[i].action, string +
+                           tags_[i].length_name_to_match) + 1;
+      }
+    }
+  }
+
+  return 0;
+}
+
+
+int NodeState::ApplyAction(Actions action, const TCHAR* string/*=NULL*/) {
+  int read = 0;
+  switch (action) {
+  case BOLD_ON :
+    bold_ = true;
+    break;
+
+  case BOLD_OFF :
+    bold_ = false;
+    break;
+
+  case ITALIC_ON :
+    italic_ = true;
+    break;
+
+  case ITALIC_OFF :
+    italic_ = false;
+    break;
+
+  case UNDERLINE_ON :
+    underline_ = true;
+    break;
+
+  case UNDERLINE_OFF :
+    underline_ = false;
+    break;
+
+  case TEXTCOLOR_ON :
+    ATLASSERT(string);
+    if (string) {
+      int nParam = 0;
+      read = ReadColorRef(string, &nParam);
+      text_color_ = nParam;
+    }
+    break;
+
+  case TEXTCOLOR_OFF :
+    text_color_ = 0;
+    break;
+
+  case TEXTSIZE_ON :
+    ATLASSERT(string);
+    if (string)
+      read = ReadNumParameter(string, &text_size_);
+    break;
+
+  case TEXTSIZE_OFF :
+    text_size_ = 8;
+    break;
+
+  case URL_ON :
+    underline_ = true;
+    text_color_ = RGB(0, 0, 0xff);
+    ATLASSERT(string);
+    if (string)
+      read = ReadString(string, &url_);
+    break;
+
+  case URL_OFF :
+    underline_ = false;
+    text_color_ = 0;
+    url_ = _T("");
+    break;
+
+  case UNKNOWN:
+    // fall thru
+
+  default:
+    ATLASSERT(false);
+  }
+  return read;
+}
+
+int NodeState::ReadNumParameter(const TCHAR* string, int* param) {
+  if (!param)
+    return 0;
+
+  *param = 0;
+  const TCHAR* current_pos = string;
+  while (current_pos && _istdigit(*current_pos)) {
+    *param *= 10;
+    *param += *current_pos - _T('0');
+    current_pos++;
+  }
+  return static_cast<int>(current_pos - string);
+}
+
+int NodeState::ReadHexParameter(const TCHAR* string, int* param) {
+  if (!param)
+    return 0;
+
+  *param = 0;
+  const TCHAR* current_pos = string;
+  while (current_pos && _istxdigit(*current_pos)) {
+    *param = ((*param) << 4);
+    if (_istdigit(*current_pos))
+      *param += *current_pos - _T('0');
+    else
+      *param += (*current_pos | 0x20) - _T('a') + 10;
+    current_pos++;
+  }
+  return static_cast<int>(current_pos - string);
+}
+
+int NodeState::ReadColorRef(const TCHAR* string, int* param) {
+  if (!param)
+    return 0;
+
+  int read = ReadHexParameter(string, param);
+  *param = RGB((*param) >> 16, ((*param) >> 8) & 0xff, (*param) & 0xff);
+  return read;
+}
+
+int NodeState::ReadString(const TCHAR* string, CString* string_out) {
+  if (!string_out)
+    return 0;
+
+  int length = 0;
+  int position = _tcscspn(string, _T(" >"));
+  if (position >= 0) {
+    *string_out = CString(string, position);
+    length = position;
+  }
+
+  return length;
+}
diff --git a/worker/uilib/node_state.h b/worker/uilib/node_state.h
index 92f3af2..9254dd7 100644
--- a/worker/uilib/node_state.h
+++ b/worker/uilib/node_state.h
@@ -1,81 +1,81 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-

-#ifndef OMAHA_WORKER_UILIB_NODE_STATE_H_

-#define OMAHA_WORKER_UILIB_NODE_STATE_H_

-

-#include <atlstr.h>

-

-class NodeState {

- public:

-  explicit NodeState(HWND window);

-  virtual ~NodeState();

-

-  void SetStdFont(HFONT font);

-  HFONT GetFont() const;

-  COLORREF text_color() const { return text_color_; }

-  bool IsURL() const { return !url_.IsEmpty(); }

-  CString url() const { return url_; }

-

-  int ConsumeTag(const TCHAR* string);

-

- private:

-  enum Actions {

-    UNKNOWN,

-    BOLD_ON,

-    BOLD_OFF,

-    ITALIC_ON,

-    ITALIC_OFF,

-    UNDERLINE_ON,

-    UNDERLINE_OFF,

-    TEXTCOLOR_ON,

-    TEXTCOLOR_OFF,

-    TEXTSIZE_ON,

-    TEXTSIZE_OFF,

-    URL_ON,

-    URL_OFF,

-  };

-

-  struct Tags {

-    const TCHAR*  name_to_match;

-    int           length_name_to_match;

-    Actions       action;

-    bool          no_parameters;

-  };

-

-  int ApplyAction(Actions action, const TCHAR* string);

-  int ReadNumParameter(const TCHAR* string, int* param);

-  int ReadHexParameter(const TCHAR* szString, int* param);

-  int ReadColorRef(const TCHAR* string, int* param);

-  int ReadString(const TCHAR* string, CString* string_out);

-  bool IsDefaultFont() const;

-

-  // Data

-  static Tags    tags_[];

-

-  HWND           owner_window_;

-  HFONT          default_font_;

-  mutable HFONT  font_;

-

-  bool           bold_;

-  bool           italic_;

-  bool           underline_;

-  COLORREF       text_color_;

-  int            text_size_;

-  CString        url_;

-};

-

-#endif  // OMAHA_WORKER_UILIB_NODE_STATE_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+
+#ifndef OMAHA_WORKER_UILIB_NODE_STATE_H_
+#define OMAHA_WORKER_UILIB_NODE_STATE_H_
+
+#include <atlstr.h>
+
+class NodeState {
+ public:
+  explicit NodeState(HWND window);
+  virtual ~NodeState();
+
+  void SetStdFont(HFONT font);
+  HFONT GetFont() const;
+  COLORREF text_color() const { return text_color_; }
+  bool IsURL() const { return !url_.IsEmpty(); }
+  CString url() const { return url_; }
+
+  int ConsumeTag(const TCHAR* string);
+
+ private:
+  enum Actions {
+    UNKNOWN,
+    BOLD_ON,
+    BOLD_OFF,
+    ITALIC_ON,
+    ITALIC_OFF,
+    UNDERLINE_ON,
+    UNDERLINE_OFF,
+    TEXTCOLOR_ON,
+    TEXTCOLOR_OFF,
+    TEXTSIZE_ON,
+    TEXTSIZE_OFF,
+    URL_ON,
+    URL_OFF,
+  };
+
+  struct Tags {
+    const TCHAR*  name_to_match;
+    int           length_name_to_match;
+    Actions       action;
+    bool          no_parameters;
+  };
+
+  int ApplyAction(Actions action, const TCHAR* string);
+  int ReadNumParameter(const TCHAR* string, int* param);
+  int ReadHexParameter(const TCHAR* szString, int* param);
+  int ReadColorRef(const TCHAR* string, int* param);
+  int ReadString(const TCHAR* string, CString* string_out);
+  bool IsDefaultFont() const;
+
+  // Data
+  static Tags    tags_[];
+
+  HWND           owner_window_;
+  HFONT          default_font_;
+  mutable HFONT  font_;
+
+  bool           bold_;
+  bool           italic_;
+  bool           underline_;
+  COLORREF       text_color_;
+  int            text_size_;
+  CString        url_;
+};
+
+#endif  // OMAHA_WORKER_UILIB_NODE_STATE_H_
diff --git a/worker/uilib/static_ex.cc b/worker/uilib/static_ex.cc
index 1ee070a..5474016 100644
--- a/worker/uilib/static_ex.cc
+++ b/worker/uilib/static_ex.cc
@@ -1,595 +1,595 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-

-// TODO(omaha): need to handle WM_GETTEXT

-// TODO(omaha): need to handle WM_SIZE

-// TODO(omaha): nice to have transparent mode

-

-#include "omaha/worker/uilib/static_ex.h"

-

-#include <shellapi.h>

-#include <strsafe.h>

-#include "omaha/worker/uilib/node_state.h"

-

-const int StaticEx::kBorderNone    = 0;

-const int StaticEx::kBorderLeft    = 1;

-const int StaticEx::kBorderTop     = 2;

-const int StaticEx::kBorderRight   = 4;

-const int StaticEx::kBorderBottom  = 8;

-const int StaticEx::kBorderAll     = kBorderLeft | kBorderTop | kBorderRight |

-                                     kBorderBottom;

-

-HCURSOR StaticEx::hand_cursor_ = NULL;

-

-StaticEx::StaticEx()

-    : margins_(1, 0, 1, 0),  // see comment in h file

-      background_color_(0xffffff),

-      use_background_color_(false),

-      ellipsis_(0),

-      border_(kBorderNone),

-      border_color_(0),

-      default_font_(NULL) {

-}

-

-StaticEx::~StaticEx() {

-  EraseNodes();

-  EraseLines(&lines_);

-}

-

-void StaticEx::Reset() {

-  text_.Empty();

-  EraseNodes();

-  EraseLines(&lines_);

-  default_font_ = NULL;

-}

-

-BOOL StaticEx::SubclassWindow(HWND window) {

-  Reset();

-  // first get text from exising control

-  unsigned length = ::SendMessage(window, WM_GETTEXTLENGTH, 0, 0);

-  CString text;

-  if (length > 0) {

-    TCHAR* buffer = text.GetBufferSetLength(length);

-    ::SendMessage(window,

-                  WM_GETTEXT,

-                  length + 1,

-                  reinterpret_cast<LPARAM>(buffer));

-    text.ReleaseBuffer(-1);

-  }

-

-  // then subclass

-  BOOL result = CWindowImpl<StaticEx>::SubclassWindow(window);

-

-  // set text back (it will parse it and replace text in subclassed control

-  // with readble text)

-  if (result && length > 0) {

-    SetWindowText(text);

-  }

-

-  return result;

-}

-

-HWND StaticEx::UnsubclassWindow(BOOL force /*= FALSE*/) {

-  Reset();  // clean up an old state

-  return CWindowImpl<StaticEx>::UnsubclassWindow(force);

-}

-

-LRESULT StaticEx::OnSetText(UINT msg, WPARAM wparam, LPARAM lparam,

-                            BOOL& handled) {

-  // parse text first, because we will need to get "readable" text

-  text_ = reinterpret_cast<const TCHAR*>(lparam);

-  ParseText();

-

-  // set readable text to subclassed control, this text will be return by

-  // GetWindowText() or WM_GETTEXT. (when GetWindowText is called from another

-  // process it doesn't send WM_GETTEXT but reads text directly from contol)

-  // so we need to set text to it.

-  // Disable redraw, without it calling DefWindowProc would redraw control

-  // immediately without sending WM_PAINT message

-  SetRedraw(FALSE);

-  DefWindowProc(msg, wparam,

-      reinterpret_cast<LPARAM>(static_cast<const TCHAR*>(GetReadableText())));

-  SetRedraw(TRUE);

-

-  // now invalidate to display new text

-  Invalidate();

-

-  handled = TRUE;

-  return 1;

-}

-

-LRESULT StaticEx::OnGetText(UINT, WPARAM wparam, LPARAM lparam, BOOL& handled) {  // NOLINT

-  if (!lparam) return 0;

-  unsigned size = static_cast<unsigned>(wparam);

-  TCHAR* buffer = reinterpret_cast<TCHAR*>(lparam);

-

-  handled = TRUE;

-  unsigned my_size = text_.GetLength();

-  if (my_size < size) {

-    StringCchCopy(buffer, size, text_);

-    return my_size;

-  }

-

-  StringCchCopyN(buffer, size, text_, size - 1);

-  buffer[size - 1] = 0;

-

-  return size - 1;

-}

-

-LRESULT StaticEx::OnGetTextLength(UINT, WPARAM, LPARAM, BOOL& handled) {  // NOLINT

-  handled = TRUE;

-  return text_.GetLength();

-}

-

-void StaticEx::set_background_color(COLORREF back_color) {

-  background_color_ = back_color;

-  use_background_color_ = true;

-  Invalidate();

-}

-

-void StaticEx::set_margins(const RECT& rect) {

-  margins_ = rect;

-  Invalidate();

-}

-

-void StaticEx::set_margins(int left, int top, int right, int bottom) {

-  margins_.SetRect(left, top, right, bottom);

-  Invalidate();

-}

-

-

-LRESULT StaticEx::OnLButtonDown(UINT, WPARAM wparam, LPARAM lparam, BOOL&) {

-  if (wparam != MK_LBUTTON)

-    return 0;

-

-  CPoint point(LOWORD(lparam), HIWORD(lparam));

-

-  int height = margins_.top + (border_ & kBorderTop) ? 1 : 0;

-  size_t size = lines_.size();

-  for (size_t i = 0; i < size; i++) {

-    height += lines_[i]->height();

-    if (point.y < height) {

-      CString action;

-      if (lines_[i]->IsUrlUnderMouse(point, &action) && !action.IsEmpty()) {

-        // First let the parent window handle the click.

-        LRESULT handled = 0;

-        NM_STATICEX notification = {0};

-        notification.header.hwndFrom = m_hWnd;

-        notification.header.idFrom = GetDlgCtrlID();

-        notification.header.code = wparam;

-        notification.action = action;

-

-        HWND parent = GetParent();

-        if (parent) {

-          handled = ::SendMessage(parent, WM_NOTIFY, notification.header.idFrom,

-                                  reinterpret_cast<LPARAM>(&notification));

-        }

-

-        // If the parent window did not handle the click, then we should try and

-        // handle the click ourself.

-        if (handled != 1 && _tcsnicmp(action, _T("http"), 4) == 0) {

-          // open URL in a browser

-          ShellExecute(m_hWnd, _T("open"), action, NULL, NULL, SW_SHOWNORMAL);

-        }

-      }

-      break;

-    }

-  }

-  return 0;

-}

-

-

-LRESULT StaticEx::OnSetCursor(UINT, WPARAM, LPARAM lparam, BOOL& handled) {  // NOLINT

-  int hit_test = LOWORD(lparam);

-  handled = FALSE;

-  if (hit_test != HTCLIENT) {

-    return 0;

-  }

-

-  POINT position;

-  if (!GetCursorPos(&position))

-    return 0;

-

-  ScreenToClient(&position);

-

-  int offset = margins_.top + (border_ & kBorderTop) ? 1 : 0;

-  size_t size = lines_.size();

-  for (size_t i = 0; i < size; i++) {

-    offset += lines_[i]->height();

-    if (position.y < offset) {

-      if (lines_[i]->IsUrlUnderMouse(position, NULL)) {

-        ::SetCursor(GetHandCursor());

-        handled = TRUE;

-      }

-      break;

-    }

-  }

-

-  return 0;

-}

-

-void StaticEx::set_ellipsis(int ellipsis) {

-  if (ellipsis == DT_END_ELLIPSIS  ||

-      ellipsis == DT_WORD_ELLIPSIS ||

-      ellipsis == DT_PATH_ELLIPSIS ||

-      ellipsis == 0) {

-    ellipsis_ = ellipsis;

-    if (ellipsis != 0)

-      ModifyStyle(0, SS_LEFTNOWORDWRAP);

-    Invalidate();

-  }

-}

-

-void StaticEx::set_border(int border) {

-  border_ = border;

-  Invalidate();

-}

-

-void StaticEx::set_border_color(COLORREF border_color) {

-  border_color_ = border_color;

-  Invalidate();

-}

-

-void StaticEx::ParseText() {

-  EraseNodes();

-  EraseLines(&lines_);

-

-  if (text_.IsEmpty())

-    return;

-

-  if (!default_font_)

-    default_font_ = GetFont();

-

-  NodeState node_state(m_hWnd);

-  node_state.SetStdFont(default_font_);

-

-  const TCHAR* current_string = text_;

-  int current_offset = 0;

-  bool had_good_tag = true;

-  while (*current_string) {

-    current_offset = 0;

-

-    if (had_good_tag) {

-      // if it was a good tag we consumed it and need to start with a new node

-      Node* node = new Node(m_hWnd);

-      nodes_.push_back(node);

-

-      // -1 if there is no Open Bracket "<"

-      current_offset = FindOpenBracket(current_string);

-

-      if (current_offset < 0) {

-        // no tags left, just plain text

-        node->AddText(current_string);

-        node->set_node_state(node_state);

-        break;

-      }

-

-      if (*current_string != _T('<')) {

-        // has some text before the tag

-        node->AddText(CString(current_string, current_offset));

-        node->set_node_state(node_state);

-        current_string += current_offset;

-        continue;

-      }

-

-      int next_offset = node_state.ConsumeTag(current_string + current_offset);

-

-      if (next_offset > 0) {

-        // it was a known tag

-        had_good_tag = true;

-        current_string += current_offset + next_offset;

-      }  else  {

-        // unknown tag, will keep looking

-        had_good_tag = false;

-        node->AddText(CString(current_string, current_offset + 1));

-        node->set_node_state(node_state);

-        current_string += current_offset + 1;

-        continue;

-      }

-    } else {

-      had_good_tag = true;

-    }

-    delete nodes_.back();

-    nodes_.pop_back();

-  }

-}

-

-CString StaticEx::GetReadableText() {

-  CString text;

-  for (size_t i = 0; i < nodes_.size(); i++) {

-    text += nodes_[i]->node_text();

-  }

-  return text;

-}

-

-void StaticEx::EraseNodes() {

-  for (size_t i = 0; i < nodes_.size(); ++i) {

-    delete nodes_[i];

-  }

-  nodes_.clear();

-}

-

-void StaticEx::EraseLines(std::vector<StaticLine*>* lines) {

-  size_t size = lines->size();

-  for (size_t i = 0; i < size; i++) {

-    delete (*lines)[i];

-  }

-  lines->clear();

-}

-

-int StaticEx::FindOpenBracket(const TCHAR* string) {

-  const TCHAR* left_bracket = _tcschr(string, _T('<'));

-

-  if (left_bracket == NULL)

-    return -1;

-

-  return static_cast<int>(left_bracket - string);

-}

-

-LRESULT StaticEx::OnPaint(UINT, WPARAM, LPARAM, BOOL&) {

-  PAINTSTRUCT paint_struct;

-  HDC hdc = BeginPaint(&paint_struct);

-

-  CRect client_rect;

-  GetClientRect(&client_rect);

-

-  CRect working_rect(client_rect);

-

-  working_rect.DeflateRect(margins_);

-  working_rect.DeflateRect((border_ & kBorderLeft)   ? 1 : 0,

-                           (border_ & kBorderTop)    ? 1 : 0,

-                           (border_ & kBorderRight)  ? 1 : 0,

-                           (border_ & kBorderBottom) ? 1 : 0);

-

-  DWORD style = GetStyle();

-

-  EraseLines(&lines_);

-  PrePaint(hdc, &lines_, nodes_, working_rect, style, ellipsis_);

-

-  if (use_background_color_) {

-    FillRect(hdc, &client_rect, CreateSolidBrush(background_color_));

-  } else {

-    HBRUSH brush = reinterpret_cast<HBRUSH>(::SendMessage(GetParent(),

-        WM_CTLCOLORSTATIC, reinterpret_cast<WPARAM>(hdc),

-        reinterpret_cast<LPARAM>(m_hWnd)));

-    if (brush) {

-      ::FillRect(hdc, &client_rect, brush);

-    }

-  }

-

-  if (border_ != kBorderNone)

-    DrawBorder(hdc, client_rect);

-

-  Paint(hdc, lines_, working_rect, style, ellipsis_);

-

-  EndPaint(&paint_struct);

-  return 0;

-}

-

-void StaticEx::PrePaint(HDC hdc, std::vector<StaticLine*>* lines,

-                        const std::vector<Node*>& nodes, RECT rect, DWORD style,

-                        int ellipsis) {

-  if (nodes.empty())

-    return;

-

-  int x = 0;

-  int width = rect.right - rect.left;

-  StaticLine* line = new StaticLine;

-  lines->push_back(line);

-  bool done = false;

-  size_t size = nodes.size();

-  for (size_t i = 0; i < size; ++i) {

-    Node* node = nodes[i];

-    const NodeState& node_state = node->node_state();

-    CString text = node->node_text();

-    int string_len = text.GetLength();

-

-    HFONT font = node_state.GetFont();

-    if (!font)

-      return;

-

-    HFONT old_font = static_cast<HFONT>(SelectObject(hdc, font));

-

-    TEXTMETRIC text_metrics;

-    GetTextMetrics(hdc, &text_metrics);

-

-    int height    = text_metrics.tmHeight + text_metrics.tmExternalLeading;

-    int base_line = text_metrics.tmHeight + text_metrics.tmExternalLeading -

-                    text_metrics.tmDescent;

-    line->AdjustHeight(height);

-    line->AdjustBaseLine(base_line);

-

-    bool single_line = (style & SS_LEFTNOWORDWRAP) != 0;

-

-    int  current_pos = 0;

-    bool more_left   = false;

-    while (true) {

-      int current_length = string_len - current_pos;

-

-      // find LF if any

-      int lf_position = text.Find(_T('\n'), current_pos);

-      if (lf_position == current_pos) {

-        if (single_line) {

-          if (ellipsis)

-            line->AddEllipses();

-          break;

-        }

-        line = new StaticLine;

-        lines->push_back(line);

-        line->AdjustHeight(height);

-        line->AdjustBaseLine(base_line);

-        x = 0;

-

-        current_pos++;

-

-        continue;

-      } else if (lf_position > 0) {

-        current_length = lf_position - current_pos;

-        more_left = true;

-      }

-

-      // check if it will fit in one line

-      int fit  = 0;

-      SIZE string_size;

-      GetTextExtentExPoint(hdc, static_cast<const TCHAR*>(text) + current_pos,

-                           current_length, width - x, &fit, NULL, &string_size);

-

-      if (fit < current_length) {

-        // string doesn't fit, need to move to the next line

-        // find last space

-        int fit_saved = fit;

-        for (; fit > 0; fit--) {

-          if (text.GetAt(current_pos + fit) == _T(' ')) {

-            break;

-          }

-        }

-

-        // if a first word of a node doesn't fit and it starts in a first half

-        // of control then wrap the word on a last char that fits

-        // otherwise move whole node to the next line

-        if ((fit <= 0) && (x < width / 2))

-          fit = fit_saved;

-

-        if (fit > 0) {

-          line->AddNode(node, current_pos, fit, height, base_line, width - x);

-        }

-

-        if (single_line) {

-          if (ellipsis)

-            line->AddEllipses();

-          done = true;

-          break;

-        }

-        line = new StaticLine;

-        lines->push_back(line);

-        line->AdjustHeight(height);

-        line->AdjustBaseLine(base_line);

-        x = 0;

-

-        current_pos += fit;

-        // skip spaces

-        while (text.GetAt(current_pos) == _T(' '))

-          current_pos++;

-        continue;

-      } else {

-        line->AddNode(node, current_pos, fit, height, base_line,

-                      string_size.cx);

-      }

-

-      // done, it fits

-      x += string_size.cx;

-      if (!more_left)

-        break;

-

-      current_pos += current_length;

-      more_left = false;

-    }

-

-    if (old_font)

-      SelectObject(hdc, old_font);

-

-    if (done)

-      break;

-  }

-}

-

-

-void StaticEx::Paint(HDC hdc, const std::vector<StaticLine*>& lines, RECT rect,

-                     DWORD style, int ellipsis) {

-  if ((style & SS_LEFTNOWORDWRAP) == 0) {

-    ellipsis = 0;

-  }

-

-  size_t size = lines.size();

-  int y = rect.top;

-  for (size_t i = 0; i < size; i++) {

-    int height = lines[i]->Paint(hdc, rect.left, rect.right, y, style,

-                                 ellipsis);

-    y += height;

-  }

-}

-

-LRESULT StaticEx::OnEraseBkgnd(UINT /*msg*/, WPARAM /*wparam*/,

-                               LPARAM /*lparam*/, BOOL& handled) {

-  handled = TRUE;

-  return 0;

-}

-

-void StaticEx::DrawBorder(HDC hdc, const CRect& rect) {

-  HGDIOBJ old_object = SelectObject(hdc, GetStockObject(DC_PEN));

-  SetDCPenColor(hdc, border_color_);

-  if (border_ & kBorderLeft) {

-    MoveToEx(hdc, rect.left, rect.top, NULL);

-    LineTo(hdc, rect.left, rect.bottom);

-  }

-  if (border_ & kBorderTop) {

-    MoveToEx(hdc, rect.left, rect.top, NULL);

-    LineTo(hdc, rect.right, rect.top);

-  }

-  if (border_ & kBorderRight) {

-    MoveToEx(hdc, rect.right - 1, rect.top, NULL);

-    LineTo(hdc, rect.right - 1, rect.bottom);

-  }

-  if (border_ & kBorderBottom) {

-    MoveToEx(hdc, rect.left, rect.bottom - 1, NULL);

-    LineTo(hdc, rect.right, rect.bottom - 1);

-  }

-  SelectObject(hdc, old_object);

-}

-

-int StaticEx::GetMinimumHeight(int width) {

-  HDC device_context = CreateCompatibleDC(NULL);

-

-  CRect client_rect;

-  if (width <= 0)

-    GetClientRect(&client_rect);

-  else

-    client_rect.SetRect(0, 0, width, 100);  // last value is not used

-

-  CRect working_rect(client_rect);

-

-  working_rect.DeflateRect(margins_);

-  working_rect.DeflateRect((border_ & kBorderLeft)   ? 1 : 0,

-                           (border_ & kBorderTop)    ? 1 : 0,

-                           (border_ & kBorderRight)  ? 1 : 0,

-                           (border_ & kBorderBottom) ? 1 : 0);

-

-  DWORD style = GetStyle();

-

-  std::vector<StaticLine*> lines;

-  PrePaint(device_context, &lines, nodes_, working_rect, style, ellipsis_);

-

-  DeleteDC(device_context);

-

-  int height = 0;

-  for (unsigned i = 0; i < lines.size(); i++) {

-    height += lines[i]->height();

-  }

-  height += margins_.top + margins_.bottom;

-  height += (border_ & kBorderTop) ? 1 : 0;

-  height += (border_ & kBorderBottom) ? 1 : 0;

-

-  return height;

-}

-

-

-HCURSOR StaticEx::GetHandCursor() {

-  if (hand_cursor_ == NULL) {

-    // Load cursor resource

-    hand_cursor_ = (HCURSOR)LoadCursor(NULL, IDC_HAND);  // doesn't work on NT4!

-  }

-  return hand_cursor_;

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+
+// TODO(omaha): need to handle WM_GETTEXT
+// TODO(omaha): need to handle WM_SIZE
+// TODO(omaha): nice to have transparent mode
+
+#include "omaha/worker/uilib/static_ex.h"
+
+#include <shellapi.h>
+#include <strsafe.h>
+#include "omaha/worker/uilib/node_state.h"
+
+const int StaticEx::kBorderNone    = 0;
+const int StaticEx::kBorderLeft    = 1;
+const int StaticEx::kBorderTop     = 2;
+const int StaticEx::kBorderRight   = 4;
+const int StaticEx::kBorderBottom  = 8;
+const int StaticEx::kBorderAll     = kBorderLeft | kBorderTop | kBorderRight |
+                                     kBorderBottom;
+
+HCURSOR StaticEx::hand_cursor_ = NULL;
+
+StaticEx::StaticEx()
+    : margins_(1, 0, 1, 0),  // see comment in h file
+      background_color_(0xffffff),
+      use_background_color_(false),
+      ellipsis_(0),
+      border_(kBorderNone),
+      border_color_(0),
+      default_font_(NULL) {
+}
+
+StaticEx::~StaticEx() {
+  EraseNodes();
+  EraseLines(&lines_);
+}
+
+void StaticEx::Reset() {
+  text_.Empty();
+  EraseNodes();
+  EraseLines(&lines_);
+  default_font_ = NULL;
+}
+
+BOOL StaticEx::SubclassWindow(HWND window) {
+  Reset();
+  // first get text from exising control
+  unsigned length = ::SendMessage(window, WM_GETTEXTLENGTH, 0, 0);
+  CString text;
+  if (length > 0) {
+    TCHAR* buffer = text.GetBufferSetLength(length);
+    ::SendMessage(window,
+                  WM_GETTEXT,
+                  length + 1,
+                  reinterpret_cast<LPARAM>(buffer));
+    text.ReleaseBuffer(-1);
+  }
+
+  // then subclass
+  BOOL result = CWindowImpl<StaticEx>::SubclassWindow(window);
+
+  // set text back (it will parse it and replace text in subclassed control
+  // with readble text)
+  if (result && length > 0) {
+    SetWindowText(text);
+  }
+
+  return result;
+}
+
+HWND StaticEx::UnsubclassWindow(BOOL force /*= FALSE*/) {
+  Reset();  // clean up an old state
+  return CWindowImpl<StaticEx>::UnsubclassWindow(force);
+}
+
+LRESULT StaticEx::OnSetText(UINT msg, WPARAM wparam, LPARAM lparam,
+                            BOOL& handled) {
+  // parse text first, because we will need to get "readable" text
+  text_ = reinterpret_cast<const TCHAR*>(lparam);
+  ParseText();
+
+  // set readable text to subclassed control, this text will be return by
+  // GetWindowText() or WM_GETTEXT. (when GetWindowText is called from another
+  // process it doesn't send WM_GETTEXT but reads text directly from contol)
+  // so we need to set text to it.
+  // Disable redraw, without it calling DefWindowProc would redraw control
+  // immediately without sending WM_PAINT message
+  SetRedraw(FALSE);
+  DefWindowProc(msg, wparam,
+      reinterpret_cast<LPARAM>(static_cast<const TCHAR*>(GetReadableText())));
+  SetRedraw(TRUE);
+
+  // now invalidate to display new text
+  Invalidate();
+
+  handled = TRUE;
+  return 1;
+}
+
+LRESULT StaticEx::OnGetText(UINT, WPARAM wparam, LPARAM lparam, BOOL& handled) {  // NOLINT
+  if (!lparam) return 0;
+  unsigned size = static_cast<unsigned>(wparam);
+  TCHAR* buffer = reinterpret_cast<TCHAR*>(lparam);
+
+  handled = TRUE;
+  unsigned my_size = text_.GetLength();
+  if (my_size < size) {
+    StringCchCopy(buffer, size, text_);
+    return my_size;
+  }
+
+  StringCchCopyN(buffer, size, text_, size - 1);
+  buffer[size - 1] = 0;
+
+  return size - 1;
+}
+
+LRESULT StaticEx::OnGetTextLength(UINT, WPARAM, LPARAM, BOOL& handled) {  // NOLINT
+  handled = TRUE;
+  return text_.GetLength();
+}
+
+void StaticEx::set_background_color(COLORREF back_color) {
+  background_color_ = back_color;
+  use_background_color_ = true;
+  Invalidate();
+}
+
+void StaticEx::set_margins(const RECT& rect) {
+  margins_ = rect;
+  Invalidate();
+}
+
+void StaticEx::set_margins(int left, int top, int right, int bottom) {
+  margins_.SetRect(left, top, right, bottom);
+  Invalidate();
+}
+
+
+LRESULT StaticEx::OnLButtonDown(UINT, WPARAM wparam, LPARAM lparam, BOOL&) {
+  if (wparam != MK_LBUTTON)
+    return 0;
+
+  CPoint point(LOWORD(lparam), HIWORD(lparam));
+
+  int height = margins_.top + (border_ & kBorderTop) ? 1 : 0;
+  size_t size = lines_.size();
+  for (size_t i = 0; i < size; i++) {
+    height += lines_[i]->height();
+    if (point.y < height) {
+      CString action;
+      if (lines_[i]->IsUrlUnderMouse(point, &action) && !action.IsEmpty()) {
+        // First let the parent window handle the click.
+        LRESULT handled = 0;
+        NM_STATICEX notification = {0};
+        notification.header.hwndFrom = m_hWnd;
+        notification.header.idFrom = GetDlgCtrlID();
+        notification.header.code = wparam;
+        notification.action = action;
+
+        HWND parent = GetParent();
+        if (parent) {
+          handled = ::SendMessage(parent, WM_NOTIFY, notification.header.idFrom,
+                                  reinterpret_cast<LPARAM>(&notification));
+        }
+
+        // If the parent window did not handle the click, then we should try and
+        // handle the click ourself.
+        if (handled != 1 && _tcsnicmp(action, _T("http"), 4) == 0) {
+          // open URL in a browser
+          ShellExecute(m_hWnd, _T("open"), action, NULL, NULL, SW_SHOWNORMAL);
+        }
+      }
+      break;
+    }
+  }
+  return 0;
+}
+
+
+LRESULT StaticEx::OnSetCursor(UINT, WPARAM, LPARAM lparam, BOOL& handled) {  // NOLINT
+  int hit_test = LOWORD(lparam);
+  handled = FALSE;
+  if (hit_test != HTCLIENT) {
+    return 0;
+  }
+
+  POINT position;
+  if (!GetCursorPos(&position))
+    return 0;
+
+  ScreenToClient(&position);
+
+  int offset = margins_.top + (border_ & kBorderTop) ? 1 : 0;
+  size_t size = lines_.size();
+  for (size_t i = 0; i < size; i++) {
+    offset += lines_[i]->height();
+    if (position.y < offset) {
+      if (lines_[i]->IsUrlUnderMouse(position, NULL)) {
+        ::SetCursor(GetHandCursor());
+        handled = TRUE;
+      }
+      break;
+    }
+  }
+
+  return 0;
+}
+
+void StaticEx::set_ellipsis(int ellipsis) {
+  if (ellipsis == DT_END_ELLIPSIS  ||
+      ellipsis == DT_WORD_ELLIPSIS ||
+      ellipsis == DT_PATH_ELLIPSIS ||
+      ellipsis == 0) {
+    ellipsis_ = ellipsis;
+    if (ellipsis != 0)
+      ModifyStyle(0, SS_LEFTNOWORDWRAP);
+    Invalidate();
+  }
+}
+
+void StaticEx::set_border(int border) {
+  border_ = border;
+  Invalidate();
+}
+
+void StaticEx::set_border_color(COLORREF border_color) {
+  border_color_ = border_color;
+  Invalidate();
+}
+
+void StaticEx::ParseText() {
+  EraseNodes();
+  EraseLines(&lines_);
+
+  if (text_.IsEmpty())
+    return;
+
+  if (!default_font_)
+    default_font_ = GetFont();
+
+  NodeState node_state(m_hWnd);
+  node_state.SetStdFont(default_font_);
+
+  const TCHAR* current_string = text_;
+  int current_offset = 0;
+  bool had_good_tag = true;
+  while (*current_string) {
+    current_offset = 0;
+
+    if (had_good_tag) {
+      // if it was a good tag we consumed it and need to start with a new node
+      Node* node = new Node(m_hWnd);
+      nodes_.push_back(node);
+
+      // -1 if there is no Open Bracket "<"
+      current_offset = FindOpenBracket(current_string);
+
+      if (current_offset < 0) {
+        // no tags left, just plain text
+        node->AddText(current_string);
+        node->set_node_state(node_state);
+        break;
+      }
+
+      if (*current_string != _T('<')) {
+        // has some text before the tag
+        node->AddText(CString(current_string, current_offset));
+        node->set_node_state(node_state);
+        current_string += current_offset;
+        continue;
+      }
+
+      int next_offset = node_state.ConsumeTag(current_string + current_offset);
+
+      if (next_offset > 0) {
+        // it was a known tag
+        had_good_tag = true;
+        current_string += current_offset + next_offset;
+      }  else  {
+        // unknown tag, will keep looking
+        had_good_tag = false;
+        node->AddText(CString(current_string, current_offset + 1));
+        node->set_node_state(node_state);
+        current_string += current_offset + 1;
+        continue;
+      }
+    } else {
+      had_good_tag = true;
+    }
+    delete nodes_.back();
+    nodes_.pop_back();
+  }
+}
+
+CString StaticEx::GetReadableText() {
+  CString text;
+  for (size_t i = 0; i < nodes_.size(); i++) {
+    text += nodes_[i]->node_text();
+  }
+  return text;
+}
+
+void StaticEx::EraseNodes() {
+  for (size_t i = 0; i < nodes_.size(); ++i) {
+    delete nodes_[i];
+  }
+  nodes_.clear();
+}
+
+void StaticEx::EraseLines(std::vector<StaticLine*>* lines) {
+  size_t size = lines->size();
+  for (size_t i = 0; i < size; i++) {
+    delete (*lines)[i];
+  }
+  lines->clear();
+}
+
+int StaticEx::FindOpenBracket(const TCHAR* string) {
+  const TCHAR* left_bracket = _tcschr(string, _T('<'));
+
+  if (left_bracket == NULL)
+    return -1;
+
+  return static_cast<int>(left_bracket - string);
+}
+
+LRESULT StaticEx::OnPaint(UINT, WPARAM, LPARAM, BOOL&) {
+  PAINTSTRUCT paint_struct;
+  HDC hdc = BeginPaint(&paint_struct);
+
+  CRect client_rect;
+  GetClientRect(&client_rect);
+
+  CRect working_rect(client_rect);
+
+  working_rect.DeflateRect(margins_);
+  working_rect.DeflateRect((border_ & kBorderLeft)   ? 1 : 0,
+                           (border_ & kBorderTop)    ? 1 : 0,
+                           (border_ & kBorderRight)  ? 1 : 0,
+                           (border_ & kBorderBottom) ? 1 : 0);
+
+  DWORD style = GetStyle();
+
+  EraseLines(&lines_);
+  PrePaint(hdc, &lines_, nodes_, working_rect, style, ellipsis_);
+
+  if (use_background_color_) {
+    FillRect(hdc, &client_rect, CreateSolidBrush(background_color_));
+  } else {
+    HBRUSH brush = reinterpret_cast<HBRUSH>(::SendMessage(GetParent(),
+        WM_CTLCOLORSTATIC, reinterpret_cast<WPARAM>(hdc),
+        reinterpret_cast<LPARAM>(m_hWnd)));
+    if (brush) {
+      ::FillRect(hdc, &client_rect, brush);
+    }
+  }
+
+  if (border_ != kBorderNone)
+    DrawBorder(hdc, client_rect);
+
+  Paint(hdc, lines_, working_rect, style, ellipsis_);
+
+  EndPaint(&paint_struct);
+  return 0;
+}
+
+void StaticEx::PrePaint(HDC hdc, std::vector<StaticLine*>* lines,
+                        const std::vector<Node*>& nodes, RECT rect, DWORD style,
+                        int ellipsis) {
+  if (nodes.empty())
+    return;
+
+  int x = 0;
+  int width = rect.right - rect.left;
+  StaticLine* line = new StaticLine;
+  lines->push_back(line);
+  bool done = false;
+  size_t size = nodes.size();
+  for (size_t i = 0; i < size; ++i) {
+    Node* node = nodes[i];
+    const NodeState& node_state = node->node_state();
+    CString text = node->node_text();
+    int string_len = text.GetLength();
+
+    HFONT font = node_state.GetFont();
+    if (!font)
+      return;
+
+    HFONT old_font = static_cast<HFONT>(SelectObject(hdc, font));
+
+    TEXTMETRIC text_metrics;
+    GetTextMetrics(hdc, &text_metrics);
+
+    int height    = text_metrics.tmHeight + text_metrics.tmExternalLeading;
+    int base_line = text_metrics.tmHeight + text_metrics.tmExternalLeading -
+                    text_metrics.tmDescent;
+    line->AdjustHeight(height);
+    line->AdjustBaseLine(base_line);
+
+    bool single_line = (style & SS_LEFTNOWORDWRAP) != 0;
+
+    int  current_pos = 0;
+    bool more_left   = false;
+    while (true) {
+      int current_length = string_len - current_pos;
+
+      // find LF if any
+      int lf_position = text.Find(_T('\n'), current_pos);
+      if (lf_position == current_pos) {
+        if (single_line) {
+          if (ellipsis)
+            line->AddEllipses();
+          break;
+        }
+        line = new StaticLine;
+        lines->push_back(line);
+        line->AdjustHeight(height);
+        line->AdjustBaseLine(base_line);
+        x = 0;
+
+        current_pos++;
+
+        continue;
+      } else if (lf_position > 0) {
+        current_length = lf_position - current_pos;
+        more_left = true;
+      }
+
+      // check if it will fit in one line
+      int fit  = 0;
+      SIZE string_size;
+      GetTextExtentExPoint(hdc, static_cast<const TCHAR*>(text) + current_pos,
+                           current_length, width - x, &fit, NULL, &string_size);
+
+      if (fit < current_length) {
+        // string doesn't fit, need to move to the next line
+        // find last space
+        int fit_saved = fit;
+        for (; fit > 0; fit--) {
+          if (text.GetAt(current_pos + fit) == _T(' ')) {
+            break;
+          }
+        }
+
+        // if a first word of a node doesn't fit and it starts in a first half
+        // of control then wrap the word on a last char that fits
+        // otherwise move whole node to the next line
+        if ((fit <= 0) && (x < width / 2))
+          fit = fit_saved;
+
+        if (fit > 0) {
+          line->AddNode(node, current_pos, fit, height, base_line, width - x);
+        }
+
+        if (single_line) {
+          if (ellipsis)
+            line->AddEllipses();
+          done = true;
+          break;
+        }
+        line = new StaticLine;
+        lines->push_back(line);
+        line->AdjustHeight(height);
+        line->AdjustBaseLine(base_line);
+        x = 0;
+
+        current_pos += fit;
+        // skip spaces
+        while (text.GetAt(current_pos) == _T(' '))
+          current_pos++;
+        continue;
+      } else {
+        line->AddNode(node, current_pos, fit, height, base_line,
+                      string_size.cx);
+      }
+
+      // done, it fits
+      x += string_size.cx;
+      if (!more_left)
+        break;
+
+      current_pos += current_length;
+      more_left = false;
+    }
+
+    if (old_font)
+      SelectObject(hdc, old_font);
+
+    if (done)
+      break;
+  }
+}
+
+
+void StaticEx::Paint(HDC hdc, const std::vector<StaticLine*>& lines, RECT rect,
+                     DWORD style, int ellipsis) {
+  if ((style & SS_LEFTNOWORDWRAP) == 0) {
+    ellipsis = 0;
+  }
+
+  size_t size = lines.size();
+  int y = rect.top;
+  for (size_t i = 0; i < size; i++) {
+    int height = lines[i]->Paint(hdc, rect.left, rect.right, y, style,
+                                 ellipsis);
+    y += height;
+  }
+}
+
+LRESULT StaticEx::OnEraseBkgnd(UINT /*msg*/, WPARAM /*wparam*/,
+                               LPARAM /*lparam*/, BOOL& handled) {
+  handled = TRUE;
+  return 0;
+}
+
+void StaticEx::DrawBorder(HDC hdc, const CRect& rect) {
+  HGDIOBJ old_object = SelectObject(hdc, GetStockObject(DC_PEN));
+  SetDCPenColor(hdc, border_color_);
+  if (border_ & kBorderLeft) {
+    MoveToEx(hdc, rect.left, rect.top, NULL);
+    LineTo(hdc, rect.left, rect.bottom);
+  }
+  if (border_ & kBorderTop) {
+    MoveToEx(hdc, rect.left, rect.top, NULL);
+    LineTo(hdc, rect.right, rect.top);
+  }
+  if (border_ & kBorderRight) {
+    MoveToEx(hdc, rect.right - 1, rect.top, NULL);
+    LineTo(hdc, rect.right - 1, rect.bottom);
+  }
+  if (border_ & kBorderBottom) {
+    MoveToEx(hdc, rect.left, rect.bottom - 1, NULL);
+    LineTo(hdc, rect.right, rect.bottom - 1);
+  }
+  SelectObject(hdc, old_object);
+}
+
+int StaticEx::GetMinimumHeight(int width) {
+  HDC device_context = CreateCompatibleDC(NULL);
+
+  CRect client_rect;
+  if (width <= 0)
+    GetClientRect(&client_rect);
+  else
+    client_rect.SetRect(0, 0, width, 100);  // last value is not used
+
+  CRect working_rect(client_rect);
+
+  working_rect.DeflateRect(margins_);
+  working_rect.DeflateRect((border_ & kBorderLeft)   ? 1 : 0,
+                           (border_ & kBorderTop)    ? 1 : 0,
+                           (border_ & kBorderRight)  ? 1 : 0,
+                           (border_ & kBorderBottom) ? 1 : 0);
+
+  DWORD style = GetStyle();
+
+  std::vector<StaticLine*> lines;
+  PrePaint(device_context, &lines, nodes_, working_rect, style, ellipsis_);
+
+  DeleteDC(device_context);
+
+  int height = 0;
+  for (unsigned i = 0; i < lines.size(); i++) {
+    height += lines[i]->height();
+  }
+  height += margins_.top + margins_.bottom;
+  height += (border_ & kBorderTop) ? 1 : 0;
+  height += (border_ & kBorderBottom) ? 1 : 0;
+
+  return height;
+}
+
+
+HCURSOR StaticEx::GetHandCursor() {
+  if (hand_cursor_ == NULL) {
+    // Load cursor resource
+    hand_cursor_ = (HCURSOR)LoadCursor(NULL, IDC_HAND);  // doesn't work on NT4!
+  }
+  return hand_cursor_;
+}
diff --git a/worker/uilib/static_ex.h b/worker/uilib/static_ex.h
index 2655140..def36d3 100644
--- a/worker/uilib/static_ex.h
+++ b/worker/uilib/static_ex.h
@@ -1,154 +1,154 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// static_ex.h : This class extends static control functionality to display

-// formatted text and hyper-links

-//

-// Currently it supports the following formatting options:

-//   bold         - <b>bold</b>

-//   italic       - <i>italic</i>

-//   underscore   - <u>underlined</u>

-//   color        - <color=ff0000>red</color>

-//   size         - <size=14>14 points text</size>

-//   hyperlink    - <a=http://www.google.com>click here</a>

-// formatting options could be nested (except hyperlink)

-//

-// Some fonts (including Tahoma) often overhang one pixel (for example in "W")

-// so StaticEx is created with default 1 pixel margin on the left and right,

-// use set_margins() to overwrite default values if you need to.

-

-

-#ifndef OMAHA_WORKER_UILIB_STATIC_EX_H_

-#define OMAHA_WORKER_UILIB_STATIC_EX_H_

-

-#include <windows.h>

-#include <atlbase.h>

-#include <atlwin.h>

-#include <vector>

-#include "omaha/worker/uilib/node.h"

-#include "omaha/worker/uilib/static_line.h"

-

-

-// extension of NMHDR to provide StaticEx specific info in notification message

-struct NM_STATICEX {

-  NMHDR header;

-  const TCHAR* action;

-};

-

-class StaticEx : public CWindowImpl<StaticEx> {

- public:

-  DECLARE_WND_SUPERCLASS(NULL, _T("STATIC"))

-

-  StaticEx();

-  virtual ~StaticEx();

-

-  void set_margins(const RECT& rect);

-  void set_margins(int left, int top, int right, int bottom);

-  RECT margins() const { return margins_; }

-

-  void set_background_color(COLORREF back_color);

-  COLORREF background_color() const { return background_color_; }

-  void ResetBackgroundColor() { use_background_color_ = false; }

-

-  // set ellipsis style (DT_END_ELLIPSIS | DT_WORD_ELLIPSIS |DT_PATH_ELLIPSIS)

-  // elipsis are supported only in a single line control, calling this function

-  // with not 0 argument will set control style to SS_LEFTNOWORDWRAP

-  void set_ellipsis(int ellipsis);

-  int ellipsis() const { return ellipsis_; }

-

-  static const int kBorderNone;

-  static const int kBorderLeft;

-  static const int kBorderTop;

-  static const int kBorderRight;

-  static const int kBorderBottom;

-  static const int kBorderAll;

-

-  // use constants above to set border, you can combine them using "|"

-  void set_border(int border);

-  int border() const { return border_; }

-

-  void set_border_color(COLORREF border_color);

-  COLORREF border_color() const { return border_color_; }

-

-  // this function doesn't change how control is shown

-  // it just calculates minimum control height to fit the text given

-  // the control width. if width is 0 it will use current control width

-  int GetMinimumHeight(int width);

-

-  BEGIN_MSG_MAP(StaticEx)

-    MESSAGE_HANDLER(WM_SETTEXT, OnSetText)

-    MESSAGE_HANDLER(kGetTextMessage, OnGetText)

-    MESSAGE_HANDLER(kGetTextLengthMessage, OnGetTextLength)

-    MESSAGE_HANDLER(WM_PAINT, OnPaint)

-    MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)

-    MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)

-    MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)

-  END_MSG_MAP()

-

-  LRESULT OnSetText(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);         // NOLINT

-  // OnGetText and OnGetTextLength work with full text including formatting tags

-  // to get readable text (without formatting info) call GetWindowText or

-  // send WM_GETTEXT

-  LRESULT OnGetText(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);         // NOLINT

-  LRESULT OnGetTextLength(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);   // NOLINT

-

-  LRESULT OnPaint(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);           // NOLINT

-  LRESULT OnEraseBkgnd(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);      // NOLINT

-  LRESULT OnLButtonDown(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);     // NOLINT

-  LRESULT OnSetCursor(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);       // NOLINT

-

-  BOOL SubclassWindow(HWND hWnd);

-  HWND UnsubclassWindow(BOOL bForce = FALSE);

-

- private:

-  void Reset();

-  void ParseText();

-  CString GetReadableText();

-  int FindOpenBracket(const TCHAR* string);

-  void EraseNodes();

-  void EraseLines(std::vector<StaticLine*>* lines);

-  HFONT default_font() const { return default_font_; }

-

-  void PrePaint(HDC dc, std::vector<StaticLine*>* lines,

-                const std::vector<Node*>& nodes, RECT rect, DWORD style,

-                int ellipsis);

-  void Paint(HDC hdc, const std::vector<StaticLine*>& lines, RECT rect,

-             DWORD style, int ellipsis);

-  void DrawBorder(HDC hdc, const CRect& rect);

-  HCURSOR GetHandCursor();

-

-  CString               text_;

-

-  CRect                 margins_;

-  COLORREF              background_color_;

-  bool                  use_background_color_;

-  int                   ellipsis_;

-  int                   border_;

-  COLORREF              border_color_;

-

-  std::vector<Node*>         nodes_;

-  std::vector<StaticLine*>   lines_;

-

-  HFONT                 default_font_;

-

-  static HCURSOR hand_cursor_;

-

-  static const UINT kGetTextMessage       = WM_APP + 1;

-  static const UINT kGetTextLengthMessage = WM_APP + 2;

-

-  DISALLOW_EVIL_CONSTRUCTORS(StaticEx);

-};

-

-#endif  // OMAHA_WORKER_UILIB_STATIC_EX_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// static_ex.h : This class extends static control functionality to display
+// formatted text and hyper-links
+//
+// Currently it supports the following formatting options:
+//   bold         - <b>bold</b>
+//   italic       - <i>italic</i>
+//   underscore   - <u>underlined</u>
+//   color        - <color=ff0000>red</color>
+//   size         - <size=14>14 points text</size>
+//   hyperlink    - <a=http://www.google.com>click here</a>
+// formatting options could be nested (except hyperlink)
+//
+// Some fonts (including Tahoma) often overhang one pixel (for example in "W")
+// so StaticEx is created with default 1 pixel margin on the left and right,
+// use set_margins() to overwrite default values if you need to.
+
+
+#ifndef OMAHA_WORKER_UILIB_STATIC_EX_H_
+#define OMAHA_WORKER_UILIB_STATIC_EX_H_
+
+#include <windows.h>
+#include <atlbase.h>
+#include <atlwin.h>
+#include <vector>
+#include "omaha/worker/uilib/node.h"
+#include "omaha/worker/uilib/static_line.h"
+
+
+// extension of NMHDR to provide StaticEx specific info in notification message
+struct NM_STATICEX {
+  NMHDR header;
+  const TCHAR* action;
+};
+
+class StaticEx : public CWindowImpl<StaticEx> {
+ public:
+  DECLARE_WND_SUPERCLASS(NULL, _T("STATIC"))
+
+  StaticEx();
+  virtual ~StaticEx();
+
+  void set_margins(const RECT& rect);
+  void set_margins(int left, int top, int right, int bottom);
+  RECT margins() const { return margins_; }
+
+  void set_background_color(COLORREF back_color);
+  COLORREF background_color() const { return background_color_; }
+  void ResetBackgroundColor() { use_background_color_ = false; }
+
+  // set ellipsis style (DT_END_ELLIPSIS | DT_WORD_ELLIPSIS |DT_PATH_ELLIPSIS)
+  // elipsis are supported only in a single line control, calling this function
+  // with not 0 argument will set control style to SS_LEFTNOWORDWRAP
+  void set_ellipsis(int ellipsis);
+  int ellipsis() const { return ellipsis_; }
+
+  static const int kBorderNone;
+  static const int kBorderLeft;
+  static const int kBorderTop;
+  static const int kBorderRight;
+  static const int kBorderBottom;
+  static const int kBorderAll;
+
+  // use constants above to set border, you can combine them using "|"
+  void set_border(int border);
+  int border() const { return border_; }
+
+  void set_border_color(COLORREF border_color);
+  COLORREF border_color() const { return border_color_; }
+
+  // this function doesn't change how control is shown
+  // it just calculates minimum control height to fit the text given
+  // the control width. if width is 0 it will use current control width
+  int GetMinimumHeight(int width);
+
+  BEGIN_MSG_MAP(StaticEx)
+    MESSAGE_HANDLER(WM_SETTEXT, OnSetText)
+    MESSAGE_HANDLER(kGetTextMessage, OnGetText)
+    MESSAGE_HANDLER(kGetTextLengthMessage, OnGetTextLength)
+    MESSAGE_HANDLER(WM_PAINT, OnPaint)
+    MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
+    MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
+    MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
+  END_MSG_MAP()
+
+  LRESULT OnSetText(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);         // NOLINT
+  // OnGetText and OnGetTextLength work with full text including formatting tags
+  // to get readable text (without formatting info) call GetWindowText or
+  // send WM_GETTEXT
+  LRESULT OnGetText(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);         // NOLINT
+  LRESULT OnGetTextLength(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);   // NOLINT
+
+  LRESULT OnPaint(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);           // NOLINT
+  LRESULT OnEraseBkgnd(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);      // NOLINT
+  LRESULT OnLButtonDown(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);     // NOLINT
+  LRESULT OnSetCursor(UINT msg, WPARAM wparam, LPARAM lparam, BOOL& handled);       // NOLINT
+
+  BOOL SubclassWindow(HWND hWnd);
+  HWND UnsubclassWindow(BOOL bForce = FALSE);
+
+ private:
+  void Reset();
+  void ParseText();
+  CString GetReadableText();
+  int FindOpenBracket(const TCHAR* string);
+  void EraseNodes();
+  void EraseLines(std::vector<StaticLine*>* lines);
+  HFONT default_font() const { return default_font_; }
+
+  void PrePaint(HDC dc, std::vector<StaticLine*>* lines,
+                const std::vector<Node*>& nodes, RECT rect, DWORD style,
+                int ellipsis);
+  void Paint(HDC hdc, const std::vector<StaticLine*>& lines, RECT rect,
+             DWORD style, int ellipsis);
+  void DrawBorder(HDC hdc, const CRect& rect);
+  HCURSOR GetHandCursor();
+
+  CString               text_;
+
+  CRect                 margins_;
+  COLORREF              background_color_;
+  bool                  use_background_color_;
+  int                   ellipsis_;
+  int                   border_;
+  COLORREF              border_color_;
+
+  std::vector<Node*>         nodes_;
+  std::vector<StaticLine*>   lines_;
+
+  HFONT                 default_font_;
+
+  static HCURSOR hand_cursor_;
+
+  static const UINT kGetTextMessage       = WM_APP + 1;
+  static const UINT kGetTextLengthMessage = WM_APP + 2;
+
+  DISALLOW_EVIL_CONSTRUCTORS(StaticEx);
+};
+
+#endif  // OMAHA_WORKER_UILIB_STATIC_EX_H_
diff --git a/worker/uilib/static_line.cc b/worker/uilib/static_line.cc
index 3df81ff..35f812d 100644
--- a/worker/uilib/static_line.cc
+++ b/worker/uilib/static_line.cc
@@ -1,122 +1,122 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-

-#include "omaha/worker/uilib/static_line.h"

-#include "omaha/worker/uilib/node.h"

-#include "omaha/worker/uilib/static_ex.h"

-

-

-StaticLine::StaticLine()

-    : base_line_(0),

-      height_(0),

-      elipses_(false) {

-}

-

-

-StaticLine::~StaticLine() {

-}

-

-

-int StaticLine::AdjustHeight(int height) {

-  height_ = std::max(height_, height);

-  return height_;

-}

-

-

-int StaticLine::AdjustBaseLine(int base_line) {

-  base_line_ = std::max(base_line_, base_line);

-  return base_line_;

-}

-

-

-void StaticLine::AddNode(Node* node, int start, int length, int height,

-                         int base_line, int width) {

-  nodes_.push_back(Nodes(node, start, length, height, base_line, width));

-  AdjustHeight(height);

-  AdjustBaseLine(base_line);

-}

-

-

-int StaticLine::Paint(HDC hdc, int left, int right, int y, DWORD window_style,

-                      int ellipsis) {

-  int old_bk_mode = SetBkMode(hdc, TRANSPARENT);

-  bool single_line = (window_style & SS_LEFTNOWORDWRAP) != 0;

-

-  size_t size = nodes_.size();

-  for (size_t i = 0; i < size; i++) {

-    Node* node    = nodes_[i].node;

-    int start     = nodes_[i].start;

-    int length    = nodes_[i].length;

-    int base_line = nodes_[i].base_line;

-    int width     = nodes_[i].width;

-

-    CString text(static_cast<LPCTSTR>(node->node_text()) + start, length);

-    if (elipses_ && (i == (size - 1)))

-      text += "...";

-

-    CRect rect(left, y + base_line_ - base_line, left + width, y + height_);

-    if (single_line)

-      rect.right = right;

-

-    nodes_[i].rect = rect;

-

-    const NodeState& nodeState = node->node_state();

-    HFONT font = nodeState.GetFont();

-    if (!font)

-      return height_;

-

-    HFONT old_font = static_cast<HFONT>(SelectObject(hdc, font));

-    COLORREF old_text_color = SetTextColor(hdc, nodeState.text_color());

-

-    DWORD draw_style = 0;

-    draw_style = DT_LEFT | DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE;

-    if (ellipsis && (i == (size - 1)))

-      draw_style = draw_style | ellipsis;

-

-    DrawText(hdc, text, text.GetLength(), rect, draw_style);

-    left += width;

-

-    SetTextColor(hdc, old_text_color);

-    if (old_font)

-      SelectObject(hdc, old_font);

-  }

-

-  SetBkMode(hdc, old_bk_mode);

-  return height_;

-}

-

-

-int StaticLine::HitTest(CPoint point) {

-  size_t size = nodes_.size();

-  for (size_t i = 0; i < size; i++) {

-    if (nodes_[i].node->node_state().IsURL()) {

-      if (nodes_[i].rect.PtInRect(point)) {

-        return static_cast<int>(i);

-      }

-    }

-  }

-

-  return -1;

-}

-

-

-bool StaticLine::IsUrlUnderMouse(CPoint point, CString* action) {

-  int index = HitTest(point);

-  if (index >= 0 && action) {

-    *action = nodes_[index].node->node_state().url();

-  }

-  return (index >= 0);

-}

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+
+#include "omaha/worker/uilib/static_line.h"
+#include "omaha/worker/uilib/node.h"
+#include "omaha/worker/uilib/static_ex.h"
+
+
+StaticLine::StaticLine()
+    : base_line_(0),
+      height_(0),
+      elipses_(false) {
+}
+
+
+StaticLine::~StaticLine() {
+}
+
+
+int StaticLine::AdjustHeight(int height) {
+  height_ = std::max(height_, height);
+  return height_;
+}
+
+
+int StaticLine::AdjustBaseLine(int base_line) {
+  base_line_ = std::max(base_line_, base_line);
+  return base_line_;
+}
+
+
+void StaticLine::AddNode(Node* node, int start, int length, int height,
+                         int base_line, int width) {
+  nodes_.push_back(Nodes(node, start, length, height, base_line, width));
+  AdjustHeight(height);
+  AdjustBaseLine(base_line);
+}
+
+
+int StaticLine::Paint(HDC hdc, int left, int right, int y, DWORD window_style,
+                      int ellipsis) {
+  int old_bk_mode = SetBkMode(hdc, TRANSPARENT);
+  bool single_line = (window_style & SS_LEFTNOWORDWRAP) != 0;
+
+  size_t size = nodes_.size();
+  for (size_t i = 0; i < size; i++) {
+    Node* node    = nodes_[i].node;
+    int start     = nodes_[i].start;
+    int length    = nodes_[i].length;
+    int base_line = nodes_[i].base_line;
+    int width     = nodes_[i].width;
+
+    CString text(static_cast<LPCTSTR>(node->node_text()) + start, length);
+    if (elipses_ && (i == (size - 1)))
+      text += "...";
+
+    CRect rect(left, y + base_line_ - base_line, left + width, y + height_);
+    if (single_line)
+      rect.right = right;
+
+    nodes_[i].rect = rect;
+
+    const NodeState& nodeState = node->node_state();
+    HFONT font = nodeState.GetFont();
+    if (!font)
+      return height_;
+
+    HFONT old_font = static_cast<HFONT>(SelectObject(hdc, font));
+    COLORREF old_text_color = SetTextColor(hdc, nodeState.text_color());
+
+    DWORD draw_style = 0;
+    draw_style = DT_LEFT | DT_NOCLIP | DT_NOPREFIX | DT_SINGLELINE;
+    if (ellipsis && (i == (size - 1)))
+      draw_style = draw_style | ellipsis;
+
+    DrawText(hdc, text, text.GetLength(), rect, draw_style);
+    left += width;
+
+    SetTextColor(hdc, old_text_color);
+    if (old_font)
+      SelectObject(hdc, old_font);
+  }
+
+  SetBkMode(hdc, old_bk_mode);
+  return height_;
+}
+
+
+int StaticLine::HitTest(CPoint point) {
+  size_t size = nodes_.size();
+  for (size_t i = 0; i < size; i++) {
+    if (nodes_[i].node->node_state().IsURL()) {
+      if (nodes_[i].rect.PtInRect(point)) {
+        return static_cast<int>(i);
+      }
+    }
+  }
+
+  return -1;
+}
+
+
+bool StaticLine::IsUrlUnderMouse(CPoint point, CString* action) {
+  int index = HitTest(point);
+  if (index >= 0 && action) {
+    *action = nodes_[index].node->node_state().url();
+  }
+  return (index >= 0);
+}
diff --git a/worker/uilib/static_line.h b/worker/uilib/static_line.h
index df50918..df7b355 100644
--- a/worker/uilib/static_line.h
+++ b/worker/uilib/static_line.h
@@ -1,76 +1,76 @@
-// Copyright 2006-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-// static_line.h

-

-#ifndef OMAHA_WORKER_UILIB_STATIC_LINE_H_

-#define OMAHA_WORKER_UILIB_STATIC_LINE_H_

-

-#include <atlstr.h>

-#include <atltypes.h>

-#include <vector>

-#include "base/basictypes.h"

-

-class Node;

-

-class StaticLine {

- public:

-  StaticLine();

-  virtual ~StaticLine();

-

-  int AdjustBaseLine(int base_line);

-  int AdjustHeight(int height);

-

-  int base_line() const { return base_line_; }

-  int height() const { return height_; }

-

-  void AddNode(Node* node, int start, int end, int height, int base_line,

-               int width);

-  void AddEllipses() { elipses_ = true; }

-

-  bool IsUrlUnderMouse(CPoint point, CString* action);

-

-  int  Paint(HDC hdc, int left, int right, int y, DWORD window_style,

-             int ellipsis);

-

- protected:

-  int     HitTest(CPoint point);

-

-  int   base_line_;

-  int   height_;

-

-  struct Nodes {

-    Node*   node;

-    int     start;     // first char to output

-    int     length;    // number of chars

-    int     height;

-    int     base_line;

-    int     width;

-    CRect   rect;

-

-    Nodes(Node* node, int start, int length, int height, int base_line,

-          int width)

-        : node(node), start(start), length(length), height(height),

-          base_line(base_line), width(width), rect(0, 0, 0, 0) {}

-  };

-

-  std::vector<Nodes>   nodes_;

-  bool            elipses_;

-

-  DISALLOW_EVIL_CONSTRUCTORS(StaticLine);

-};

-

-#endif  // OMAHA_WORKER_UILIB_STATIC_LINE_H_

+// Copyright 2006-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+// static_line.h
+
+#ifndef OMAHA_WORKER_UILIB_STATIC_LINE_H_
+#define OMAHA_WORKER_UILIB_STATIC_LINE_H_
+
+#include <atlstr.h>
+#include <atltypes.h>
+#include <vector>
+#include "base/basictypes.h"
+
+class Node;
+
+class StaticLine {
+ public:
+  StaticLine();
+  virtual ~StaticLine();
+
+  int AdjustBaseLine(int base_line);
+  int AdjustHeight(int height);
+
+  int base_line() const { return base_line_; }
+  int height() const { return height_; }
+
+  void AddNode(Node* node, int start, int end, int height, int base_line,
+               int width);
+  void AddEllipses() { elipses_ = true; }
+
+  bool IsUrlUnderMouse(CPoint point, CString* action);
+
+  int  Paint(HDC hdc, int left, int right, int y, DWORD window_style,
+             int ellipsis);
+
+ protected:
+  int     HitTest(CPoint point);
+
+  int   base_line_;
+  int   height_;
+
+  struct Nodes {
+    Node*   node;
+    int     start;     // first char to output
+    int     length;    // number of chars
+    int     height;
+    int     base_line;
+    int     width;
+    CRect   rect;
+
+    Nodes(Node* node, int start, int length, int height, int base_line,
+          int width)
+        : node(node), start(start), length(length), height(height),
+          base_line(base_line), width(width), rect(0, 0, 0, 0) {}
+  };
+
+  std::vector<Nodes>   nodes_;
+  bool            elipses_;
+
+  DISALLOW_EVIL_CONSTRUCTORS(StaticLine);
+};
+
+#endif  // OMAHA_WORKER_UILIB_STATIC_LINE_H_
diff --git a/worker/worker-internal.h b/worker/worker-internal.h
index d6b0b99..36a6746 100644
--- a/worker/worker-internal.h
+++ b/worker/worker-internal.h
@@ -1,37 +1,37 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_WORKER_INTERNAL_H_

-#define OMAHA_WORKER_WORKER_INTERNAL_H_

-

-namespace omaha {

-

-namespace internal {

-

-void RecordUpdateAvailableUsageStats(bool is_machine);

-

-// Sends a ping with self-update failure information if present in the registry.

-void SendSelfUpdateFailurePing(bool is_machine);

-

-// Sends an uninstall ping for any uninstalled products before Google Update

-// uninstalls itself.

-HRESULT SendFinalUninstallPingForApps(bool is_machine);

-

-}  // namespace internal

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_WORKER_INTERNAL_H_

-

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_WORKER_INTERNAL_H_
+#define OMAHA_WORKER_WORKER_INTERNAL_H_
+
+namespace omaha {
+
+namespace internal {
+
+void RecordUpdateAvailableUsageStats(bool is_machine);
+
+// Sends a ping with self-update failure information if present in the registry.
+void SendSelfUpdateFailurePing(bool is_machine);
+
+// Sends an uninstall ping for any uninstalled products before Google Update
+// uninstalls itself.
+HRESULT SendFinalUninstallPingForApps(bool is_machine);
+
+}  // namespace internal
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_WORKER_INTERNAL_H_
+
diff --git a/worker/worker.cc b/worker/worker.cc
index 8cab770..999b807 100644
--- a/worker/worker.cc
+++ b/worker/worker.cc
@@ -1,845 +1,845 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// TODO(omaha): maybe introduce a new logging facility: WORK_LOG.

-

-// TODO(omaha): Dig out the RefHolder in scope_guard.h so we can use const

-// references instead pointers. This TODO was added for some code that no longer

-// exists, but it is still a good idea.

-

-#include "omaha/worker/worker.h"

-

-#include <atlbase.h>

-#include <atlstr.h>

-#include <atlapp.h>

-#include <atlsecurity.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/firewall_product_detection.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/reactor.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/shutdown_handler.h"

-#include "omaha/common/sta_call.h"

-#include "omaha/common/system.h"

-#include "omaha/common/string.h"

-#include "omaha/common/thread_pool.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vistautil.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource.h"

-#include "omaha/goopdate/stats_uploader.h"

-#include "omaha/goopdate/ui_displayed_event.h"

-#include "omaha/net/network_config.h"

-#include "omaha/net/network_request.h"

-#include "omaha/setup/setup.h"

-#include "omaha/worker/application_manager.h"

-#include "omaha/worker/ping.h"

-#include "omaha/worker/ping_utils.h"

-#include "omaha/worker/worker_event_logger.h"

-#include "omaha/worker/worker_job.h"

-#include "omaha/worker/worker_metrics.h"

-#include "omaha/worker/ui.h"

-

-// Since the net code is linked in as a lib, force the registration code to

-// be a dependency, otherwise the linker is optimizing in out.

-//

-// TODO(omaha): fix this clunkiness and require explicit registration of the

-// http creators with the factory. Not ideal but better then linker options.

-//

-// Design Notes:

-// Following are the mutexes that are taken by the worker

-// 1. SingleUpdateWorker. Only taken by the update worker.

-// 2. SingleInstallWorker. This is application specific. Only taken by the

-//    install worker and for the specific application.

-// 3. Before install, the install manager takes the global install lock.

-// 4. A key thing to add to this code is after taking the install lock,

-//    to validate that the version of the applicaion that is present in the

-//    registry is the same as that we queried for. The reason to do this

-//    is to ensure that there are no races between update and install workers.

-// 5. Termination of the worker happens because of four reasons:

-//    a. Shutdown event - Only applicable to the update worker. When this event

-//       is signalled, the main thread comes out of the wait. It then tries to

-//       destroy the contained thread pool, which causes a timed wait for the

-//       worker thread. The worker thread is notified by setting a

-//       cancelled flag on the worker.

-//    b. Install completes, user closes UI - Only applicable for the

-//       interactive installs. In this case the main thread comes out of

-//       the message loop and deletes the thread pool. The delete happens

-//       immediately, since the worker is doing nothing.

-//    c. User cancels install - Only applicable in case if interactive installs.

-//       The main thread sets the cancelled flag on the workerjob and comes out

-//       of the message loop. It then tries to delete the thread pool, causing

-//       a timed wait. The worker job queries the cancelled flag periodically

-//       and quits as soon as possible.

-//    d. The update worker completes - In this case we do not run on a thread

-//       pool.

-

-#pragma comment(linker, "/INCLUDE:_kRegisterWinHttp")

-

-namespace omaha {

-

-namespace {

-

-uint64 GetGuidMostSignificantUint64(const GUID& guid) {

-  return (static_cast<uint64>(guid.Data1) << 32) +

-         (static_cast<uint64>(guid.Data2) << 16) +

-         static_cast<uint64>(guid.Data3);

-}

-

-class WorkItem : public UserWorkItem {

- public:

-  WorkItem(WorkerJob* worker_job, bool delete_after_run)

-      : worker_job_(worker_job),

-        delete_after_run_(delete_after_run) {

-    ASSERT1(worker_job);

-  }

- private:

-  void DoProcess() {

-    worker_job_->DoProcess();

-    if (delete_after_run_) {

-      delete worker_job_;

-      worker_job_ = NULL;

-    }

-  }

-

-  WorkerJob* worker_job_;

-  bool delete_after_run_;

-  DISALLOW_EVIL_CONSTRUCTORS(WorkItem);

-};

-

-class ErrorWndEvents : public ProgressWndEvents {

- public:

-  virtual void DoPause() {}

-  virtual void DoResume() {}

-  virtual void DoClose() {}

-  virtual void DoRestartBrowsers() {}

-  virtual void DoReboot() {}

-  virtual void DoLaunchBrowser(const CString& url) {

-    VERIFY1(SUCCEEDED(goopdate_utils::LaunchBrowser(BROWSER_DEFAULT, url)));

-  }

-};

-

-}  // namespace

-

-namespace internal {

-

-void RecordUpdateAvailableUsageStats(bool is_machine) {

-  AppManager app_manager(is_machine);

-

-  DWORD update_responses(0);

-  DWORD64 time_since_first_response_ms(0);

-  app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                       kGoopdateGuid,

-                                       &update_responses,

-                                       &time_since_first_response_ms);

-  if (update_responses) {

-    metric_worker_self_update_responses = update_responses;

-  }

-  if (time_since_first_response_ms) {

-    metric_worker_self_update_response_time_since_first_ms =

-        time_since_first_response_ms;

-  }

-

-  ProductDataVector products;

-  HRESULT hr = app_manager.GetRegisteredProducts(&products);

-  if (FAILED(hr)) {

-    ASSERT1(false);

-    return;

-  }

-

-  // These store information about the app with the most update responses.

-  GUID max_responses_product(GUID_NULL);

-  DWORD max_responses(0);

-  DWORD64 max_responses_time_since_first_response_ms(0);

-

-  for (size_t i = 0; i < products.size(); ++i) {

-    const ProductData& product_data = products[i];

-    const GUID& product_guid = product_data.app_data().app_guid();

-

-    if (::IsEqualGUID(kGoopdateGuid, product_guid)) {

-      continue;

-    }

-

-    DWORD update_responses(0);

-    DWORD64 time_since_first_response_ms(0);

-    app_manager.ReadUpdateAvailableStats(GUID_NULL,

-                                         product_guid,

-                                         &update_responses,

-                                         &time_since_first_response_ms);

-

-    if (max_responses < update_responses) {

-      max_responses_product = product_guid;

-      max_responses = update_responses;

-      max_responses_time_since_first_response_ms = time_since_first_response_ms;

-    }

-  }

-

-  if (max_responses) {

-    metric_worker_app_max_update_responses_app_high =

-        GetGuidMostSignificantUint64(max_responses_product);

-    metric_worker_app_max_update_responses = max_responses;

-    metric_worker_app_max_update_responses_ms_since_first =

-        max_responses_time_since_first_response_ms;

-  }

-}

-

-void SendSelfUpdateFailurePing(bool is_machine) {

-  DWORD self_update_error_code(0);

-  DWORD self_update_extra_code1(0);

-  CString self_update_version;

-

-  if (!Setup::ReadAndClearUpdateErrorInfo(is_machine,

-                                          &self_update_error_code,

-                                          &self_update_extra_code1,

-                                          &self_update_version)) {

-    return;

-  }

-

-  Ping ping;

-  HRESULT hr = ping_utils::SendGoopdatePing(

-      is_machine,

-      CommandLineExtraArgs(),

-      PingEvent::EVENT_SETUP_UPDATE_FAILURE,

-      self_update_error_code,

-      self_update_extra_code1,

-      self_update_version,

-      &ping);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[SendGoopdatePing failed][0x%08x]"), hr));

-    // TODO(omaha): Consider writing the values back with

-    // Setup::PersistUpdateErrorInfo(so we can try pinging later. This would be

-    // useful if the user happens to be offline when update worker runs.

-  }

-}

-

-HRESULT SendFinalUninstallPingForApps(bool is_machine) {

-  CORE_LOG(L2, (_T("[SendFinalUninstallPingForApps]")));

-  scoped_ptr<Request> uninstall_ping;

-  HRESULT hr = BuildUninstallPing(is_machine, address(uninstall_ping));

-  if (SUCCEEDED(hr) && uninstall_ping->get_request_count()) {

-    Ping ping;

-    hr = ping.SendPing(uninstall_ping.get());

-  }

-  return hr;

-}

-

-}  // namespace internal

-

-Worker::Worker(bool is_machine)

-    : is_machine_(is_machine),

-      is_local_system_(false),

-      has_uninstalled_(false) {

-  CORE_LOG(L1, (_T("[Worker::Worker]")));

-}

-

-Worker::~Worker() {

-  CORE_LOG(L1, (_T("[Worker::~Worker]")));

-

-  // Ensure the threads are cleaned up regardless of the entry point or flow.

-  StopWorker(NULL);

-

-  CollectAmbientUsageStats();

-}

-

-// This method could be called multiple times, and thus needs to be idempotent.

-// worker_job_error_code can be NULL.

-void Worker::StopWorker(HRESULT* worker_job_error_code) {

-  // Stop the concurrent objects to avoid spurious events.

-  shutdown_handler_.reset();

-  reactor_.reset();

-

-  if (worker_job_.get()) {

-    worker_job_->Cancel();

-  }

-

-  // The thread pool destructor waits for any remaining jobs to complete.

-  thread_pool_.reset();

-

-  if (worker_job_.get() && worker_job_error_code) {

-    *worker_job_error_code = worker_job_->error_code();

-  }

-

-  // Uninstall should happen as late as possible. Since uninstall may occur

-  // after this method, destroy all objects now.

-  worker_job_.reset();

-}

-

-// This method must not depend on Omaha being registered because that may not

-// occur until DoRun.

-// Assumes is_machine_ is set correctly.

-HRESULT Worker::Main(Goopdate* goopdate) {

-  ASSERT1(goopdate);

-  args_ = goopdate->args();

-  cmd_line_ = goopdate->cmd_line();

-  is_local_system_ = goopdate->is_local_system();

-

-  HRESULT hr = DoRun();

-  // If this is an interactive instance, UI should have been shown either by

-  // WorkerJob or an error.

-  ASSERT1(UIDisplayedEventManager::HasUIBeenDisplayed(is_machine_) ||

-          (args_.mode != COMMANDLINE_MODE_IG &&

-           args_.mode != COMMANDLINE_MODE_HANDOFF_INSTALL) ||

-          args_.is_silent_set);

-

-  // Stop WorkerJob and thread pool so we can get the final error code.

-  HRESULT worker_job_error_code(S_OK);

-  StopWorker(&worker_job_error_code);

-

-  // Get the error code from WorkerJob thread to return to the caller.

-  if (SUCCEEDED(hr)) {

-    hr = worker_job_error_code;

-  }

-

-  if (FAILED(hr) && args_.mode == COMMANDLINE_MODE_IG) {

-    MaybeUninstallGoogleUpdate();

-  }

-

-  return hr;

-}

-

-// This method must not depend on any Omaha "registration" because Google Update

-// may not be completely installed yet.

-HRESULT Worker::DoRun() {

-  OPT_LOG(L1, (_T("[Worker::DoRun]")));

-

-  HRESULT hr = InitializeThreadPool();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // The /install case does not really use the Worker and needs to be moved

-  // outside. This will be done as part of unifying Setup.

-  if (COMMANDLINE_MODE_INSTALL == args_.mode) {

-    return DoInstallGoogleUpdateAndApp();

-  }

-

-  if ((COMMANDLINE_MODE_IG == args_.mode ||

-       COMMANDLINE_MODE_HANDOFF_INSTALL == args_.mode) &&

-      !args_.is_silent_set) {

-    HRESULT hr = InitializeUI();

-    if (FAILED(hr)) {

-      CString error_text;

-      error_text.FormatMessage(IDS_INSTALL_FAILED, hr);

-      DisplayErrorInMessageBox(error_text);

-      return hr;

-    }

-

-    if (!args_.is_offline_set) {

-      CString caption;

-      caption.FormatMessage(IDS_WINDOW_TITLE, GetPrimaryJobInfo().app_name);

-      CString message;

-      message.LoadString(IDS_PROXY_PROMPT_MESSAGE);

-      const uint32 kProxyMaxPrompts = 1;

-      NetworkConfig::Instance().ConfigureProxyAuth(caption,

-                                                   message,

-                                                   *progress_wnd_,

-                                                   kProxyMaxPrompts);

-    }

-  }

-

-  worker_job_.reset(WorkerJobFactory::CreateWorkerJob(is_machine_,

-                                                      args_,

-                                                      job_observer_.get()));

-

-  // TODO(omaha): It would be nice if we could move all the differences

-  // between installs and updates into the WorkerJobStrategy and just call

-  // StartWorkerJob at this point.

-#pragma warning(push)

-// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by

-// a case label.

-#pragma warning(disable : 4061)

-  switch (args_.mode) {

-    case COMMANDLINE_MODE_IG:

-    case COMMANDLINE_MODE_HANDOFF_INSTALL:

-      hr = DoInstall();

-      break;

-    case COMMANDLINE_MODE_UA:

-      hr = DoUpdateApps();

-      OPT_LOG(L2, (_T("[Update worker finished]")));

-      break;

-    default:

-      ASSERT(false, (_T("Nothing to do in the worker.")));

-      hr = E_UNEXPECTED;

-  }

-#pragma warning(pop)

-

-  return hr;

-}

-

-bool Worker::EnsureSingleAppInstaller(const CString& guid) {

-  // We allow only one instance of interactive install per application.

-  CString mutex_name;

-  mutex_name.Format(kSingleInstallWorker, guid);

-  single_install_worker_.reset(new ProgramInstance(mutex_name));

-  return !single_install_worker_->EnsureSingleInstance();

-}

-

-bool Worker::EnsureSingleUpdateWorker() {

-  // We allow only one instance of the update worker per user.

-  NamedObjectAttributes single_update_worker_attr;

-  GetNamedObjectAttributes(kSingleupdateWorker,

-                           is_machine_,

-                           &single_update_worker_attr);

-

-  single_update_worker_.reset(new ProgramInstance(

-      single_update_worker_attr.name));

-  return !single_update_worker_->EnsureSingleInstance();

-}

-

-HRESULT Worker::InitializeUI() {

-  OPT_LOG(L1, (_T("[InitializeUI]")));

-  ASSERT1((COMMANDLINE_MODE_IG == args_.mode ||

-           COMMANDLINE_MODE_HANDOFF_INSTALL == args_.mode ||

-           COMMANDLINE_MODE_INSTALL == args_.mode) &&

-          !args_.is_silent_set);

-

-  progress_wnd_.reset(new ProgressWnd(&message_loop_, NULL));

-

-  progress_wnd_->set_is_machine(is_machine_);

-  progress_wnd_->set_language(args_.extra.language);

-  ASSERT1(!args_.extra.apps.empty());

-  progress_wnd_->set_product_name(GetPrimaryJobInfo().app_name);

-  progress_wnd_->set_product_guid(GetPrimaryJobInfo().app_guid);

-

-  JobObserverCallMethodDecorator* decorator =

-      new JobObserverCallMethodDecorator(progress_wnd_.get());

-  job_observer_.reset(decorator);

-  HRESULT hr = decorator->Initialize();

-  if (FAILED(hr)) {

-    OPT_LOG(L1, (_T("JobObserver initialize failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT Worker::DoInstall() {

-  OPT_LOG(L1, (_T("[DoInstall]")));

-

-  const bool is_already_installing =

-      EnsureSingleAppInstaller(GuidToString(GetPrimaryJobInfo().app_guid));

-

-  if (is_already_installing) {

-    OPT_LOG(L1, (_T("[Another Install of this application is running in the ")

-                 _T("same session. Exiting.]")));

-    ++metric_worker_another_install_in_progress;

-    HRESULT hr = GOOPDATE_E_APP_BEING_INSTALLED;

-    CString error_text;

-    error_text.FormatMessage(IDS_APPLICATION_ALREADY_INSTALLING,

-                             GetPrimaryJobInfo().app_name);

-    DisplayError(error_text, hr);

-    return hr;

-  }

-

-  HRESULT hr = StartWorkerJob();

-  if (FAILED(hr)) {

-    CString error_text;

-    error_text.FormatMessage(IDS_INSTALL_FAILED, hr);

-

-    DisplayError(error_text, hr);

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT Worker::InitializeShutDownHandler(ShutdownCallback* callback) {

-  CORE_LOG(L3, (_T("[InitializeShutDownHandler]")));

-  ASSERT1(callback);

-

-  reactor_.reset(new Reactor);

-  shutdown_handler_.reset(new ShutdownHandler);

-  return shutdown_handler_->Initialize(reactor_.get(),

-                                       callback,

-                                       is_machine_);

-}

-

-HRESULT Worker::DoUpdateApps() {

-  OPT_LOG(L1, (_T("[DoUpdateApps]")));

-

-  WriteUpdateAppsWorkerStartEvent(is_machine_);

-

-  if (EnsureSingleUpdateWorker()) {

-    OPT_LOG(L1, (_T("[Another worker is already running. Exiting.]")));

-    ++metric_worker_another_update_in_progress;

-    return GOOPDATE_E_WORKER_ALREADY_RUNNING;

-  }

-

-  HRESULT hr = InitializeShutDownHandler(this);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[InitializeShutDownHandler failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  internal::RecordUpdateAvailableUsageStats(is_machine_);

-

-  // A tentative uninstall check is done here. There are stronger checks,

-  // protected by locks, which are done by Setup.

-  size_t num_clients(0);

-  const bool is_uninstall =

-      FAILED(goopdate_utils::GetNumClients(is_machine_, &num_clients)) ||

-      num_clients <= 1;

-  CORE_LOG(L4, (_T("[Worker::DoUpdateApps][%u]"), num_clients));

-

-  if (is_uninstall) {

-    // Attempt a conditional uninstall and always return S_OK to avoid

-    // executing error handling code in the case of an actual uninstall.

-    // Do not attempt to uninstall if MSI is busy to avoid spurious uninstalls.

-    // See http://b/1436223. The call to WaitForMSIExecute blocks with a

-    // timeout. It is better to block here than block while holding the setup

-    // lock.

-    hr = WaitForMSIExecute(kWaitForMSIExecuteMs);

-    CORE_LOG(L2, (_T("[WaitForMSIExecute returned 0x%08x]"), hr));

-    if (SUCCEEDED(hr)) {

-      // Destroy all the objects before uninstalling.

-      StopWorker(NULL);

-      MaybeUninstallGoogleUpdate();

-    }

-    return S_OK;

-  }

-

-  hr = StartWorkerJob();

-

-  internal::SendSelfUpdateFailurePing(is_machine_);

-

-  return hr;

-}

-

-HRESULT Worker::DoInstallGoogleUpdateAndApp() {

-  OPT_LOG(L1, (_T("[DoInstallGoogleUpdateAndApp]")));

-

-  // For machine installs, do not use the UI displayed event in the non-elevated

-  // instance.

-  if (!is_machine_ || vista_util::IsUserAdmin()) {

-    VERIFY1(SUCCEEDED(UIDisplayedEventManager::CreateEvent(is_machine_)));

-  }

-

-  Setup setup(is_machine_, &args_);

-  HRESULT hr = setup.Install(cmd_line_);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[Setup::Install failed][0x%08x]"), hr));

-    VERIFY1(SUCCEEDED(HandleSetupError(hr, setup.extra_code1())));

-    return hr;

-  }

-

-  return S_OK;

-}

-

-HRESULT Worker::InitializeThreadPool() {

-  CORE_LOG(L3, (_T("[Worker::InitializeThreadPool]")));

-  thread_pool_.reset(new ThreadPool);

-  return thread_pool_->Initialize(kThreadPoolShutdownDelayMs);

-}

-

-HRESULT Worker::StartWorkerJob() {

-  CORE_LOG(L2, (_T("[Worker::StartWorker]")));

-  if (args_.is_silent_set || COMMANDLINE_MODE_UA == args_.mode) {

-    return worker_job_->DoProcess();

-  }

-

-  HRESULT hr = QueueWorkerJob(worker_job_.get(), false);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  message_loop_.Run();

-  return S_OK;

-}

-

-HRESULT Worker::QueueWorkerJob(WorkerJob* worker_job, bool delete_after_run) {

-  CORE_LOG(L2, (_T("[Worker::QueueWorkerJob]")));

-  ASSERT1(thread_pool_.get());

-

-  scoped_ptr<WorkItem> work_item;

-  work_item.reset(new WorkItem(worker_job, delete_after_run));

-  HRESULT hr = thread_pool_->QueueUserWorkItem(work_item.get(),

-                                               WT_EXECUTELONGFUNCTION);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  work_item.release();

-  return S_OK;

-}

-

-// Displays an error in the Google Update UI if not silent then sends a ping if

-// allowed If the UI fails, uses a system message box as a fallback.

-HRESULT Worker::HandleSetupError(HRESULT error, int extra_code1) {

-  ASSERT1(FAILED(error));

-

-  CString error_text;

-  ASSERT1(!args_.extra.apps.empty());

-  switch (error) {

-    case GOOPDATE_E_INSTALL_ELEVATED_PROCESS_NEEDS_ELEVATION:

-    case GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP:

-      error_text.FormatMessage(IDS_NEED_ADMIN_TO_INSTALL,

-                               GetPrimaryJobInfo().app_name);

-      break;

-    case GOOPDATE_E_ELEVATION_FAILED_ADMIN:

-    case GOOPDATE_E_ELEVATION_FAILED_NON_ADMIN:

-      error_text.FormatMessage(IDS_ELEVATION_FAILED,

-                               GetPrimaryJobInfo().app_name);

-      break;

-    case GOOPDATE_E_FAILED_TO_GET_LOCK:

-    case GOOPDATE_E_FAILED_TO_GET_LOCK_MATCHING_INSTALL_PROCESS_RUNNING:

-    case GOOPDATE_E_FAILED_TO_GET_LOCK_NONMATCHING_INSTALL_PROCESS_RUNNING:

-    case GOOPDATE_E_FAILED_TO_GET_LOCK_UPDATE_PROCESS_RUNNING:

-      error_text.FormatMessage(IDS_APPLICATION_INSTALLING_GOOGLE_UPDATE,

-                               GetPrimaryJobInfo().app_name);

-      break;

-    case GOOPDATE_E_INSTANCES_RUNNING:

-      error_text.FormatMessage(IDS_INSTANCES_RUNNING_AFTER_SHUTDOWN,

-                               GetPrimaryJobInfo().app_name);

-      break;

-    case GOOPDATE_E_RUNNING_INFERIOR_MSXML:

-      error_text.FormatMessage(IDS_WINDOWS_IS_NOT_UP_TO_DATE,

-                               GetPrimaryJobInfo().app_name);

-      break;

-    case GOOPDATE_E_HANDOFF_FAILED:

-      error_text.FormatMessage(IDS_HANDOFF_FAILED,

-                               GetPrimaryJobInfo().app_name);

-      break;

-    default:

-      error_text.FormatMessage(IDS_SETUP_FAILED, error);

-      break;

-  }

-

-  OPT_LOG(LE, (_T("[Failed to install Google Update][0x%08x][%s]"),

-               error, error_text));

-

-  if (UIDisplayedEventManager::HasUIBeenDisplayed(is_machine_)) {

-    // Do not display another UI, launch the web page, or ping.

-    CORE_LOG(L2, (_T("[second instance has UI; not displaying error UI]")));

-    return S_OK;

-  }

-

-  HRESULT hr = S_OK;

-  if (!args_.is_silent_set) {

-    hr = InitializeUI();

-    if (SUCCEEDED(hr)) {

-      DisplayError(error_text, error);

-    } else {

-      DisplayErrorInMessageBox(error_text);

-    }

-  }

-

-  // Do not ping. Cannot rely on the ping code to not send the ping because

-  // Setup may have failed before it could write eulaccepted=0 to the registry.

-  if (args().is_eula_required_set) {

-    return hr;

-  }

-

-  if (args().is_oem_set) {

-    // Do not ping.

-    // Cannot rely on the ping code to not send the ping because the OEM Mode

-    // value is not set after Setup returns.

-    return hr;

-  }

-

-  // This ping may cause a firewall prompt, but we are willing to cause a prompt

-  // in failure cases.

-  Request request(is_machine_);

-  Ping ping;

-  HRESULT hr_ping = ping_utils::SendGoopdatePing(

-      is_machine_,

-      args().extra,

-      PingEvent::EVENT_SETUP_INSTALL_FAILURE,

-      error,

-      extra_code1,

-      NULL,

-      &ping);

-  if (FAILED(hr_ping)) {

-    CORE_LOG(LW, (_T("[SendGoopdatePing failed][0x%08x]"), hr_ping));

-  }

-

-  return hr;

-}

-

-HRESULT Worker::Shutdown() {

-  CORE_LOG(L2, (_T("[Worker::Shutdown]")));

-  ASSERT1(args_.mode == COMMANDLINE_MODE_UA);

-  if (worker_job_.get()) {

-    worker_job_->Cancel();

-  }

-  return S_OK;

-}

-

-HRESULT Worker::DoOnDemand(const WCHAR* guid,

-                           const CString& lang,

-                           IJobObserver* observer,

-                           bool is_update_check_only) {

-  CORE_LOG(L3, (_T("[Worker::DoOnDemand][%d][%s][%d][%d]"),

-                is_machine_, guid, observer, is_update_check_only));

-  ASSERT1(guid);

-  ASSERT1(observer);

-

-  if (!is_update_check_only && is_machine_ && !vista_util::IsUserAdmin()) {

-    ASSERT(false, (_T("Need to be elevated for machine application.")));

-    return HRESULT_FROM_WIN32(ERROR_ELEVATION_REQUIRED);

-  }

-

-  // Create a fresh WorkerJob for each OnDemand request that comes in.

-  scoped_ptr<WorkerJob> worker_job;

-  HRESULT hr = WorkerJobFactory::CreateOnDemandWorkerJob(

-      is_machine_,

-      is_update_check_only,

-      lang,

-      StringToGuid(guid),

-      observer,

-      shutdown_callback_.get(),

-      address(worker_job));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = QueueWorkerJob(worker_job.get(), true);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[QueueWorkerJob failed][0x%08x]"), hr));

-    return hr;

-  }

-  worker_job.release();

-

-  return S_OK;

-}

-

-void Worker::CollectAmbientUsageStats() {

-  if (args_.mode != COMMANDLINE_MODE_UA) {

-    return;

-  }

-

-  CString name, version;

-  HRESULT hr = firewall_detection::Detect(&name, &version);

-  bool has_software_firewall = SUCCEEDED(hr) && !name.IsEmpty();

-  metric_worker_has_software_firewall.Set(has_software_firewall);

-

-  if (System::IsRunningOnBatteries()) {

-    ++metric_worker_silent_update_running_on_batteries;

-  }

-

-  metric_worker_shell_version = app_util::GetVersionFromModule(NULL);

-

-  metric_worker_is_windows_installing.Set(IsWindowsInstalling());

-  metric_worker_is_uac_disabled.Set(vista_util::IsUACDisabled());

-  metric_worker_is_clickonce_disabled.Set(IsClickOnceDisabled());

-}

-

-// Uninstall is a tricky use case. Uninstall can primarily happen in three cases

-// and there are two mechanisms to uninstall. The cases in which Omaha

-// uninstalls are:

-// 1. The last registered application uninstalls. Omaha monitors the

-// client keys and it will trigger an immediate uninstall in this case.

-// 2. The core starts an update worker, if there are no registered

-// applications, the update worker will do the uninstall.

-// 3. An error, including user cancel, happens during Omaha or app installation

-// and there are no registered applications.

-// The uninstall is implemented in terms of the following mechanisms:

-// * An update worker launched with "/ua /uninstalled" by the core, in the

-// first two cases above.

-// * A direct uninstall, in the case of errors or user cancellations, in the

-// last case above.

-//

-// Omaha can uninstall only if there are no install workers running and no

-// registered applications. This check is done under the setup lock protection.

-// In addition, the uninstall worker takes the update worker lock. Acquiring

-// this lock is important since the silent installers can modify the

-// registration of apps and trigger uninstalls workers. Therefore, both

-// setup lock and the update worker locks are needed.

-//

-// In the direct uninstall case there is a small race condition, since there is

-// no other single lock that can be acquired to prevent changes to the

-// application registration. The code looks for install workers but the test is

-// racy if not protected by locks.

-void Worker::MaybeUninstallGoogleUpdate() {

-  CORE_LOG(L1, (_T("[Worker::MaybeUninstallGoogleUpdate]")));

-  ASSERT1(args_.mode == COMMANDLINE_MODE_UA ||

-          args_.mode == COMMANDLINE_MODE_IG);

-  internal::SendFinalUninstallPingForApps(is_machine_);

-

-  Setup setup(is_machine_, &args_);

-  has_uninstalled_ = !!SUCCEEDED(setup.Uninstall());

-}

-

-const CommandLineAppArgs& Worker::GetPrimaryJobInfo() const {

-  ASSERT1(!args_.extra.apps.empty());

-  return args_.extra.apps[0];

-}

-

-void Worker::DisplayError(const CString& error_text, HRESULT error) {

-  ASSERT1(!UIDisplayedEventManager::HasUIBeenDisplayed(is_machine_));

-

-#pragma warning(push)

-// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by

-// a case label.

-#pragma warning(disable : 4061)

-  switch (args_.mode) {

-    case COMMANDLINE_MODE_INSTALL:

-    case COMMANDLINE_MODE_HANDOFF_INSTALL:

-    case COMMANDLINE_MODE_IG:

-      if (args_.is_silent_set) {

-        return;

-      }

-      break;

-    case COMMANDLINE_MODE_UA:

-    case COMMANDLINE_MODE_UNKNOWN:  // OnDemand

-      return;

-      break;

-    default:

-      ASSERT1(false);

-      return;

-  }

-#pragma warning(pop)

-

-  ASSERT1(job_observer_.get());

-  ErrorWndEvents error_wnd_events;

-

-  // error_wnd_events must not be destroyed until CMessageLoop::Run() returns.

-  job_observer_->SetEventSink(&error_wnd_events);

-  job_observer_->OnShow();

-

-  job_observer_->OnComplete(COMPLETION_CODE_ERROR, error_text, error);

-

-  message_loop_.Run();

-}

-

-void Worker::DisplayErrorInMessageBox(const CString& error_text) {

-  ASSERT1(args_.mode == COMMANDLINE_MODE_INSTALL ||

-          args_.mode == COMMANDLINE_MODE_IG ||

-          args_.mode == COMMANDLINE_MODE_HANDOFF_INSTALL);

-

-  if (args_.is_silent_set) {

-    return;

-  }

-

-  CString primary_app_name;

-  ASSERT1(!args_.extra.apps.empty());

-  if (!args_.extra.apps.empty()) {

-    primary_app_name = GetPrimaryJobInfo().app_name;

-  }

-

-  goopdate_utils::DisplayErrorInMessageBox(error_text, primary_app_name);

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// TODO(omaha): maybe introduce a new logging facility: WORK_LOG.
+
+// TODO(omaha): Dig out the RefHolder in scope_guard.h so we can use const
+// references instead pointers. This TODO was added for some code that no longer
+// exists, but it is still a good idea.
+
+#include "omaha/worker/worker.h"
+
+#include <atlbase.h>
+#include <atlstr.h>
+#include <atlapp.h>
+#include <atlsecurity.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/firewall_product_detection.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/reactor.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/shutdown_handler.h"
+#include "omaha/common/sta_call.h"
+#include "omaha/common/system.h"
+#include "omaha/common/string.h"
+#include "omaha/common/thread_pool.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vistautil.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource.h"
+#include "omaha/goopdate/stats_uploader.h"
+#include "omaha/goopdate/ui_displayed_event.h"
+#include "omaha/net/network_config.h"
+#include "omaha/net/network_request.h"
+#include "omaha/setup/setup.h"
+#include "omaha/worker/application_manager.h"
+#include "omaha/worker/ping.h"
+#include "omaha/worker/ping_utils.h"
+#include "omaha/worker/worker_event_logger.h"
+#include "omaha/worker/worker_job.h"
+#include "omaha/worker/worker_metrics.h"
+#include "omaha/worker/ui.h"
+
+// Since the net code is linked in as a lib, force the registration code to
+// be a dependency, otherwise the linker is optimizing in out.
+//
+// TODO(omaha): fix this clunkiness and require explicit registration of the
+// http creators with the factory. Not ideal but better then linker options.
+//
+// Design Notes:
+// Following are the mutexes that are taken by the worker
+// 1. SingleUpdateWorker. Only taken by the update worker.
+// 2. SingleInstallWorker. This is application specific. Only taken by the
+//    install worker and for the specific application.
+// 3. Before install, the install manager takes the global install lock.
+// 4. A key thing to add to this code is after taking the install lock,
+//    to validate that the version of the applicaion that is present in the
+//    registry is the same as that we queried for. The reason to do this
+//    is to ensure that there are no races between update and install workers.
+// 5. Termination of the worker happens because of four reasons:
+//    a. Shutdown event - Only applicable to the update worker. When this event
+//       is signalled, the main thread comes out of the wait. It then tries to
+//       destroy the contained thread pool, which causes a timed wait for the
+//       worker thread. The worker thread is notified by setting a
+//       cancelled flag on the worker.
+//    b. Install completes, user closes UI - Only applicable for the
+//       interactive installs. In this case the main thread comes out of
+//       the message loop and deletes the thread pool. The delete happens
+//       immediately, since the worker is doing nothing.
+//    c. User cancels install - Only applicable in case if interactive installs.
+//       The main thread sets the cancelled flag on the workerjob and comes out
+//       of the message loop. It then tries to delete the thread pool, causing
+//       a timed wait. The worker job queries the cancelled flag periodically
+//       and quits as soon as possible.
+//    d. The update worker completes - In this case we do not run on a thread
+//       pool.
+
+#pragma comment(linker, "/INCLUDE:_kRegisterWinHttp")
+
+namespace omaha {
+
+namespace {
+
+uint64 GetGuidMostSignificantUint64(const GUID& guid) {
+  return (static_cast<uint64>(guid.Data1) << 32) +
+         (static_cast<uint64>(guid.Data2) << 16) +
+         static_cast<uint64>(guid.Data3);
+}
+
+class WorkItem : public UserWorkItem {
+ public:
+  WorkItem(WorkerJob* worker_job, bool delete_after_run)
+      : worker_job_(worker_job),
+        delete_after_run_(delete_after_run) {
+    ASSERT1(worker_job);
+  }
+ private:
+  void DoProcess() {
+    worker_job_->DoProcess();
+    if (delete_after_run_) {
+      delete worker_job_;
+      worker_job_ = NULL;
+    }
+  }
+
+  WorkerJob* worker_job_;
+  bool delete_after_run_;
+  DISALLOW_EVIL_CONSTRUCTORS(WorkItem);
+};
+
+class ErrorWndEvents : public ProgressWndEvents {
+ public:
+  virtual void DoPause() {}
+  virtual void DoResume() {}
+  virtual void DoClose() {}
+  virtual void DoRestartBrowsers() {}
+  virtual void DoReboot() {}
+  virtual void DoLaunchBrowser(const CString& url) {
+    VERIFY1(SUCCEEDED(goopdate_utils::LaunchBrowser(BROWSER_DEFAULT, url)));
+  }
+};
+
+}  // namespace
+
+namespace internal {
+
+void RecordUpdateAvailableUsageStats(bool is_machine) {
+  AppManager app_manager(is_machine);
+
+  DWORD update_responses(0);
+  DWORD64 time_since_first_response_ms(0);
+  app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                       kGoopdateGuid,
+                                       &update_responses,
+                                       &time_since_first_response_ms);
+  if (update_responses) {
+    metric_worker_self_update_responses = update_responses;
+  }
+  if (time_since_first_response_ms) {
+    metric_worker_self_update_response_time_since_first_ms =
+        time_since_first_response_ms;
+  }
+
+  ProductDataVector products;
+  HRESULT hr = app_manager.GetRegisteredProducts(&products);
+  if (FAILED(hr)) {
+    ASSERT1(false);
+    return;
+  }
+
+  // These store information about the app with the most update responses.
+  GUID max_responses_product(GUID_NULL);
+  DWORD max_responses(0);
+  DWORD64 max_responses_time_since_first_response_ms(0);
+
+  for (size_t i = 0; i < products.size(); ++i) {
+    const ProductData& product_data = products[i];
+    const GUID& product_guid = product_data.app_data().app_guid();
+
+    if (::IsEqualGUID(kGoopdateGuid, product_guid)) {
+      continue;
+    }
+
+    DWORD update_responses(0);
+    DWORD64 time_since_first_response_ms(0);
+    app_manager.ReadUpdateAvailableStats(GUID_NULL,
+                                         product_guid,
+                                         &update_responses,
+                                         &time_since_first_response_ms);
+
+    if (max_responses < update_responses) {
+      max_responses_product = product_guid;
+      max_responses = update_responses;
+      max_responses_time_since_first_response_ms = time_since_first_response_ms;
+    }
+  }
+
+  if (max_responses) {
+    metric_worker_app_max_update_responses_app_high =
+        GetGuidMostSignificantUint64(max_responses_product);
+    metric_worker_app_max_update_responses = max_responses;
+    metric_worker_app_max_update_responses_ms_since_first =
+        max_responses_time_since_first_response_ms;
+  }
+}
+
+void SendSelfUpdateFailurePing(bool is_machine) {
+  DWORD self_update_error_code(0);
+  DWORD self_update_extra_code1(0);
+  CString self_update_version;
+
+  if (!Setup::ReadAndClearUpdateErrorInfo(is_machine,
+                                          &self_update_error_code,
+                                          &self_update_extra_code1,
+                                          &self_update_version)) {
+    return;
+  }
+
+  Ping ping;
+  HRESULT hr = ping_utils::SendGoopdatePing(
+      is_machine,
+      CommandLineExtraArgs(),
+      PingEvent::EVENT_SETUP_UPDATE_FAILURE,
+      self_update_error_code,
+      self_update_extra_code1,
+      self_update_version,
+      &ping);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[SendGoopdatePing failed][0x%08x]"), hr));
+    // TODO(omaha): Consider writing the values back with
+    // Setup::PersistUpdateErrorInfo(so we can try pinging later. This would be
+    // useful if the user happens to be offline when update worker runs.
+  }
+}
+
+HRESULT SendFinalUninstallPingForApps(bool is_machine) {
+  CORE_LOG(L2, (_T("[SendFinalUninstallPingForApps]")));
+  scoped_ptr<Request> uninstall_ping;
+  HRESULT hr = BuildUninstallPing(is_machine, address(uninstall_ping));
+  if (SUCCEEDED(hr) && uninstall_ping->get_request_count()) {
+    Ping ping;
+    hr = ping.SendPing(uninstall_ping.get());
+  }
+  return hr;
+}
+
+}  // namespace internal
+
+Worker::Worker(bool is_machine)
+    : is_machine_(is_machine),
+      is_local_system_(false),
+      has_uninstalled_(false) {
+  CORE_LOG(L1, (_T("[Worker::Worker]")));
+}
+
+Worker::~Worker() {
+  CORE_LOG(L1, (_T("[Worker::~Worker]")));
+
+  // Ensure the threads are cleaned up regardless of the entry point or flow.
+  StopWorker(NULL);
+
+  CollectAmbientUsageStats();
+}
+
+// This method could be called multiple times, and thus needs to be idempotent.
+// worker_job_error_code can be NULL.
+void Worker::StopWorker(HRESULT* worker_job_error_code) {
+  // Stop the concurrent objects to avoid spurious events.
+  shutdown_handler_.reset();
+  reactor_.reset();
+
+  if (worker_job_.get()) {
+    worker_job_->Cancel();
+  }
+
+  // The thread pool destructor waits for any remaining jobs to complete.
+  thread_pool_.reset();
+
+  if (worker_job_.get() && worker_job_error_code) {
+    *worker_job_error_code = worker_job_->error_code();
+  }
+
+  // Uninstall should happen as late as possible. Since uninstall may occur
+  // after this method, destroy all objects now.
+  worker_job_.reset();
+}
+
+// This method must not depend on Omaha being registered because that may not
+// occur until DoRun.
+// Assumes is_machine_ is set correctly.
+HRESULT Worker::Main(Goopdate* goopdate) {
+  ASSERT1(goopdate);
+  args_ = goopdate->args();
+  cmd_line_ = goopdate->cmd_line();
+  is_local_system_ = goopdate->is_local_system();
+
+  HRESULT hr = DoRun();
+  // If this is an interactive instance, UI should have been shown either by
+  // WorkerJob or an error.
+  ASSERT1(UIDisplayedEventManager::HasUIBeenDisplayed(is_machine_) ||
+          (args_.mode != COMMANDLINE_MODE_IG &&
+           args_.mode != COMMANDLINE_MODE_HANDOFF_INSTALL) ||
+          args_.is_silent_set);
+
+  // Stop WorkerJob and thread pool so we can get the final error code.
+  HRESULT worker_job_error_code(S_OK);
+  StopWorker(&worker_job_error_code);
+
+  // Get the error code from WorkerJob thread to return to the caller.
+  if (SUCCEEDED(hr)) {
+    hr = worker_job_error_code;
+  }
+
+  if (FAILED(hr) && args_.mode == COMMANDLINE_MODE_IG) {
+    MaybeUninstallGoogleUpdate();
+  }
+
+  return hr;
+}
+
+// This method must not depend on any Omaha "registration" because Google Update
+// may not be completely installed yet.
+HRESULT Worker::DoRun() {
+  OPT_LOG(L1, (_T("[Worker::DoRun]")));
+
+  HRESULT hr = InitializeThreadPool();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // The /install case does not really use the Worker and needs to be moved
+  // outside. This will be done as part of unifying Setup.
+  if (COMMANDLINE_MODE_INSTALL == args_.mode) {
+    return DoInstallGoogleUpdateAndApp();
+  }
+
+  if ((COMMANDLINE_MODE_IG == args_.mode ||
+       COMMANDLINE_MODE_HANDOFF_INSTALL == args_.mode) &&
+      !args_.is_silent_set) {
+    HRESULT hr = InitializeUI();
+    if (FAILED(hr)) {
+      CString error_text;
+      error_text.FormatMessage(IDS_INSTALL_FAILED, hr);
+      DisplayErrorInMessageBox(error_text);
+      return hr;
+    }
+
+    if (!args_.is_offline_set) {
+      CString caption;
+      caption.FormatMessage(IDS_WINDOW_TITLE, GetPrimaryJobInfo().app_name);
+      CString message;
+      message.LoadString(IDS_PROXY_PROMPT_MESSAGE);
+      const uint32 kProxyMaxPrompts = 1;
+      NetworkConfig::Instance().ConfigureProxyAuth(caption,
+                                                   message,
+                                                   *progress_wnd_,
+                                                   kProxyMaxPrompts);
+    }
+  }
+
+  worker_job_.reset(WorkerJobFactory::CreateWorkerJob(is_machine_,
+                                                      args_,
+                                                      job_observer_.get()));
+
+  // TODO(omaha): It would be nice if we could move all the differences
+  // between installs and updates into the WorkerJobStrategy and just call
+  // StartWorkerJob at this point.
+#pragma warning(push)
+// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by
+// a case label.
+#pragma warning(disable : 4061)
+  switch (args_.mode) {
+    case COMMANDLINE_MODE_IG:
+    case COMMANDLINE_MODE_HANDOFF_INSTALL:
+      hr = DoInstall();
+      break;
+    case COMMANDLINE_MODE_UA:
+      hr = DoUpdateApps();
+      OPT_LOG(L2, (_T("[Update worker finished]")));
+      break;
+    default:
+      ASSERT(false, (_T("Nothing to do in the worker.")));
+      hr = E_UNEXPECTED;
+  }
+#pragma warning(pop)
+
+  return hr;
+}
+
+bool Worker::EnsureSingleAppInstaller(const CString& guid) {
+  // We allow only one instance of interactive install per application.
+  CString mutex_name;
+  mutex_name.Format(kSingleInstallWorker, guid);
+  single_install_worker_.reset(new ProgramInstance(mutex_name));
+  return !single_install_worker_->EnsureSingleInstance();
+}
+
+bool Worker::EnsureSingleUpdateWorker() {
+  // We allow only one instance of the update worker per user.
+  NamedObjectAttributes single_update_worker_attr;
+  GetNamedObjectAttributes(kSingleupdateWorker,
+                           is_machine_,
+                           &single_update_worker_attr);
+
+  single_update_worker_.reset(new ProgramInstance(
+      single_update_worker_attr.name));
+  return !single_update_worker_->EnsureSingleInstance();
+}
+
+HRESULT Worker::InitializeUI() {
+  OPT_LOG(L1, (_T("[InitializeUI]")));
+  ASSERT1((COMMANDLINE_MODE_IG == args_.mode ||
+           COMMANDLINE_MODE_HANDOFF_INSTALL == args_.mode ||
+           COMMANDLINE_MODE_INSTALL == args_.mode) &&
+          !args_.is_silent_set);
+
+  progress_wnd_.reset(new ProgressWnd(&message_loop_, NULL));
+
+  progress_wnd_->set_is_machine(is_machine_);
+  progress_wnd_->set_language(args_.extra.language);
+  ASSERT1(!args_.extra.apps.empty());
+  progress_wnd_->set_product_name(GetPrimaryJobInfo().app_name);
+  progress_wnd_->set_product_guid(GetPrimaryJobInfo().app_guid);
+
+  JobObserverCallMethodDecorator* decorator =
+      new JobObserverCallMethodDecorator(progress_wnd_.get());
+  job_observer_.reset(decorator);
+  HRESULT hr = decorator->Initialize();
+  if (FAILED(hr)) {
+    OPT_LOG(L1, (_T("JobObserver initialize failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT Worker::DoInstall() {
+  OPT_LOG(L1, (_T("[DoInstall]")));
+
+  const bool is_already_installing =
+      EnsureSingleAppInstaller(GuidToString(GetPrimaryJobInfo().app_guid));
+
+  if (is_already_installing) {
+    OPT_LOG(L1, (_T("[Another Install of this application is running in the ")
+                 _T("same session. Exiting.]")));
+    ++metric_worker_another_install_in_progress;
+    HRESULT hr = GOOPDATE_E_APP_BEING_INSTALLED;
+    CString error_text;
+    error_text.FormatMessage(IDS_APPLICATION_ALREADY_INSTALLING,
+                             GetPrimaryJobInfo().app_name);
+    DisplayError(error_text, hr);
+    return hr;
+  }
+
+  HRESULT hr = StartWorkerJob();
+  if (FAILED(hr)) {
+    CString error_text;
+    error_text.FormatMessage(IDS_INSTALL_FAILED, hr);
+
+    DisplayError(error_text, hr);
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT Worker::InitializeShutDownHandler(ShutdownCallback* callback) {
+  CORE_LOG(L3, (_T("[InitializeShutDownHandler]")));
+  ASSERT1(callback);
+
+  reactor_.reset(new Reactor);
+  shutdown_handler_.reset(new ShutdownHandler);
+  return shutdown_handler_->Initialize(reactor_.get(),
+                                       callback,
+                                       is_machine_);
+}
+
+HRESULT Worker::DoUpdateApps() {
+  OPT_LOG(L1, (_T("[DoUpdateApps]")));
+
+  WriteUpdateAppsWorkerStartEvent(is_machine_);
+
+  if (EnsureSingleUpdateWorker()) {
+    OPT_LOG(L1, (_T("[Another worker is already running. Exiting.]")));
+    ++metric_worker_another_update_in_progress;
+    return GOOPDATE_E_WORKER_ALREADY_RUNNING;
+  }
+
+  HRESULT hr = InitializeShutDownHandler(this);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[InitializeShutDownHandler failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  internal::RecordUpdateAvailableUsageStats(is_machine_);
+
+  // A tentative uninstall check is done here. There are stronger checks,
+  // protected by locks, which are done by Setup.
+  size_t num_clients(0);
+  const bool is_uninstall =
+      FAILED(goopdate_utils::GetNumClients(is_machine_, &num_clients)) ||
+      num_clients <= 1;
+  CORE_LOG(L4, (_T("[Worker::DoUpdateApps][%u]"), num_clients));
+
+  if (is_uninstall) {
+    // Attempt a conditional uninstall and always return S_OK to avoid
+    // executing error handling code in the case of an actual uninstall.
+    // Do not attempt to uninstall if MSI is busy to avoid spurious uninstalls.
+    // See http://b/1436223. The call to WaitForMSIExecute blocks with a
+    // timeout. It is better to block here than block while holding the setup
+    // lock.
+    hr = WaitForMSIExecute(kWaitForMSIExecuteMs);
+    CORE_LOG(L2, (_T("[WaitForMSIExecute returned 0x%08x]"), hr));
+    if (SUCCEEDED(hr)) {
+      // Destroy all the objects before uninstalling.
+      StopWorker(NULL);
+      MaybeUninstallGoogleUpdate();
+    }
+    return S_OK;
+  }
+
+  hr = StartWorkerJob();
+
+  internal::SendSelfUpdateFailurePing(is_machine_);
+
+  return hr;
+}
+
+HRESULT Worker::DoInstallGoogleUpdateAndApp() {
+  OPT_LOG(L1, (_T("[DoInstallGoogleUpdateAndApp]")));
+
+  // For machine installs, do not use the UI displayed event in the non-elevated
+  // instance.
+  if (!is_machine_ || vista_util::IsUserAdmin()) {
+    VERIFY1(SUCCEEDED(UIDisplayedEventManager::CreateEvent(is_machine_)));
+  }
+
+  Setup setup(is_machine_, &args_);
+  HRESULT hr = setup.Install(cmd_line_);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[Setup::Install failed][0x%08x]"), hr));
+    VERIFY1(SUCCEEDED(HandleSetupError(hr, setup.extra_code1())));
+    return hr;
+  }
+
+  return S_OK;
+}
+
+HRESULT Worker::InitializeThreadPool() {
+  CORE_LOG(L3, (_T("[Worker::InitializeThreadPool]")));
+  thread_pool_.reset(new ThreadPool);
+  return thread_pool_->Initialize(kThreadPoolShutdownDelayMs);
+}
+
+HRESULT Worker::StartWorkerJob() {
+  CORE_LOG(L2, (_T("[Worker::StartWorker]")));
+  if (args_.is_silent_set || COMMANDLINE_MODE_UA == args_.mode) {
+    return worker_job_->DoProcess();
+  }
+
+  HRESULT hr = QueueWorkerJob(worker_job_.get(), false);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  message_loop_.Run();
+  return S_OK;
+}
+
+HRESULT Worker::QueueWorkerJob(WorkerJob* worker_job, bool delete_after_run) {
+  CORE_LOG(L2, (_T("[Worker::QueueWorkerJob]")));
+  ASSERT1(thread_pool_.get());
+
+  scoped_ptr<WorkItem> work_item;
+  work_item.reset(new WorkItem(worker_job, delete_after_run));
+  HRESULT hr = thread_pool_->QueueUserWorkItem(work_item.get(),
+                                               WT_EXECUTELONGFUNCTION);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  work_item.release();
+  return S_OK;
+}
+
+// Displays an error in the Google Update UI if not silent then sends a ping if
+// allowed If the UI fails, uses a system message box as a fallback.
+HRESULT Worker::HandleSetupError(HRESULT error, int extra_code1) {
+  ASSERT1(FAILED(error));
+
+  CString error_text;
+  ASSERT1(!args_.extra.apps.empty());
+  switch (error) {
+    case GOOPDATE_E_INSTALL_ELEVATED_PROCESS_NEEDS_ELEVATION:
+    case GOOPDATE_E_NONADMIN_INSTALL_ADMIN_APP:
+      error_text.FormatMessage(IDS_NEED_ADMIN_TO_INSTALL,
+                               GetPrimaryJobInfo().app_name);
+      break;
+    case GOOPDATE_E_ELEVATION_FAILED_ADMIN:
+    case GOOPDATE_E_ELEVATION_FAILED_NON_ADMIN:
+      error_text.FormatMessage(IDS_ELEVATION_FAILED,
+                               GetPrimaryJobInfo().app_name);
+      break;
+    case GOOPDATE_E_FAILED_TO_GET_LOCK:
+    case GOOPDATE_E_FAILED_TO_GET_LOCK_MATCHING_INSTALL_PROCESS_RUNNING:
+    case GOOPDATE_E_FAILED_TO_GET_LOCK_NONMATCHING_INSTALL_PROCESS_RUNNING:
+    case GOOPDATE_E_FAILED_TO_GET_LOCK_UPDATE_PROCESS_RUNNING:
+      error_text.FormatMessage(IDS_APPLICATION_INSTALLING_GOOGLE_UPDATE,
+                               GetPrimaryJobInfo().app_name);
+      break;
+    case GOOPDATE_E_INSTANCES_RUNNING:
+      error_text.FormatMessage(IDS_INSTANCES_RUNNING_AFTER_SHUTDOWN,
+                               GetPrimaryJobInfo().app_name);
+      break;
+    case GOOPDATE_E_RUNNING_INFERIOR_MSXML:
+      error_text.FormatMessage(IDS_WINDOWS_IS_NOT_UP_TO_DATE,
+                               GetPrimaryJobInfo().app_name);
+      break;
+    case GOOPDATE_E_HANDOFF_FAILED:
+      error_text.FormatMessage(IDS_HANDOFF_FAILED,
+                               GetPrimaryJobInfo().app_name);
+      break;
+    default:
+      error_text.FormatMessage(IDS_SETUP_FAILED, error);
+      break;
+  }
+
+  OPT_LOG(LE, (_T("[Failed to install Google Update][0x%08x][%s]"),
+               error, error_text));
+
+  if (UIDisplayedEventManager::HasUIBeenDisplayed(is_machine_)) {
+    // Do not display another UI, launch the web page, or ping.
+    CORE_LOG(L2, (_T("[second instance has UI; not displaying error UI]")));
+    return S_OK;
+  }
+
+  HRESULT hr = S_OK;
+  if (!args_.is_silent_set) {
+    hr = InitializeUI();
+    if (SUCCEEDED(hr)) {
+      DisplayError(error_text, error);
+    } else {
+      DisplayErrorInMessageBox(error_text);
+    }
+  }
+
+  // Do not ping. Cannot rely on the ping code to not send the ping because
+  // Setup may have failed before it could write eulaccepted=0 to the registry.
+  if (args().is_eula_required_set) {
+    return hr;
+  }
+
+  if (args().is_oem_set) {
+    // Do not ping.
+    // Cannot rely on the ping code to not send the ping because the OEM Mode
+    // value is not set after Setup returns.
+    return hr;
+  }
+
+  // This ping may cause a firewall prompt, but we are willing to cause a prompt
+  // in failure cases.
+  Request request(is_machine_);
+  Ping ping;
+  HRESULT hr_ping = ping_utils::SendGoopdatePing(
+      is_machine_,
+      args().extra,
+      PingEvent::EVENT_SETUP_INSTALL_FAILURE,
+      error,
+      extra_code1,
+      NULL,
+      &ping);
+  if (FAILED(hr_ping)) {
+    CORE_LOG(LW, (_T("[SendGoopdatePing failed][0x%08x]"), hr_ping));
+  }
+
+  return hr;
+}
+
+HRESULT Worker::Shutdown() {
+  CORE_LOG(L2, (_T("[Worker::Shutdown]")));
+  ASSERT1(args_.mode == COMMANDLINE_MODE_UA);
+  if (worker_job_.get()) {
+    worker_job_->Cancel();
+  }
+  return S_OK;
+}
+
+HRESULT Worker::DoOnDemand(const WCHAR* guid,
+                           const CString& lang,
+                           IJobObserver* observer,
+                           bool is_update_check_only) {
+  CORE_LOG(L3, (_T("[Worker::DoOnDemand][%d][%s][%d][%d]"),
+                is_machine_, guid, observer, is_update_check_only));
+  ASSERT1(guid);
+  ASSERT1(observer);
+
+  if (!is_update_check_only && is_machine_ && !vista_util::IsUserAdmin()) {
+    ASSERT(false, (_T("Need to be elevated for machine application.")));
+    return HRESULT_FROM_WIN32(ERROR_ELEVATION_REQUIRED);
+  }
+
+  // Create a fresh WorkerJob for each OnDemand request that comes in.
+  scoped_ptr<WorkerJob> worker_job;
+  HRESULT hr = WorkerJobFactory::CreateOnDemandWorkerJob(
+      is_machine_,
+      is_update_check_only,
+      lang,
+      StringToGuid(guid),
+      observer,
+      shutdown_callback_.get(),
+      address(worker_job));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = QueueWorkerJob(worker_job.get(), true);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[QueueWorkerJob failed][0x%08x]"), hr));
+    return hr;
+  }
+  worker_job.release();
+
+  return S_OK;
+}
+
+void Worker::CollectAmbientUsageStats() {
+  if (args_.mode != COMMANDLINE_MODE_UA) {
+    return;
+  }
+
+  CString name, version;
+  HRESULT hr = firewall_detection::Detect(&name, &version);
+  bool has_software_firewall = SUCCEEDED(hr) && !name.IsEmpty();
+  metric_worker_has_software_firewall.Set(has_software_firewall);
+
+  if (System::IsRunningOnBatteries()) {
+    ++metric_worker_silent_update_running_on_batteries;
+  }
+
+  metric_worker_shell_version = app_util::GetVersionFromModule(NULL);
+
+  metric_worker_is_windows_installing.Set(IsWindowsInstalling());
+  metric_worker_is_uac_disabled.Set(vista_util::IsUACDisabled());
+  metric_worker_is_clickonce_disabled.Set(IsClickOnceDisabled());
+}
+
+// Uninstall is a tricky use case. Uninstall can primarily happen in three cases
+// and there are two mechanisms to uninstall. The cases in which Omaha
+// uninstalls are:
+// 1. The last registered application uninstalls. Omaha monitors the
+// client keys and it will trigger an immediate uninstall in this case.
+// 2. The core starts an update worker, if there are no registered
+// applications, the update worker will do the uninstall.
+// 3. An error, including user cancel, happens during Omaha or app installation
+// and there are no registered applications.
+// The uninstall is implemented in terms of the following mechanisms:
+// * An update worker launched with "/ua /uninstalled" by the core, in the
+// first two cases above.
+// * A direct uninstall, in the case of errors or user cancellations, in the
+// last case above.
+//
+// Omaha can uninstall only if there are no install workers running and no
+// registered applications. This check is done under the setup lock protection.
+// In addition, the uninstall worker takes the update worker lock. Acquiring
+// this lock is important since the silent installers can modify the
+// registration of apps and trigger uninstalls workers. Therefore, both
+// setup lock and the update worker locks are needed.
+//
+// In the direct uninstall case there is a small race condition, since there is
+// no other single lock that can be acquired to prevent changes to the
+// application registration. The code looks for install workers but the test is
+// racy if not protected by locks.
+void Worker::MaybeUninstallGoogleUpdate() {
+  CORE_LOG(L1, (_T("[Worker::MaybeUninstallGoogleUpdate]")));
+  ASSERT1(args_.mode == COMMANDLINE_MODE_UA ||
+          args_.mode == COMMANDLINE_MODE_IG);
+  internal::SendFinalUninstallPingForApps(is_machine_);
+
+  Setup setup(is_machine_, &args_);
+  has_uninstalled_ = !!SUCCEEDED(setup.Uninstall());
+}
+
+const CommandLineAppArgs& Worker::GetPrimaryJobInfo() const {
+  ASSERT1(!args_.extra.apps.empty());
+  return args_.extra.apps[0];
+}
+
+void Worker::DisplayError(const CString& error_text, HRESULT error) {
+  ASSERT1(!UIDisplayedEventManager::HasUIBeenDisplayed(is_machine_));
+
+#pragma warning(push)
+// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by
+// a case label.
+#pragma warning(disable : 4061)
+  switch (args_.mode) {
+    case COMMANDLINE_MODE_INSTALL:
+    case COMMANDLINE_MODE_HANDOFF_INSTALL:
+    case COMMANDLINE_MODE_IG:
+      if (args_.is_silent_set) {
+        return;
+      }
+      break;
+    case COMMANDLINE_MODE_UA:
+    case COMMANDLINE_MODE_UNKNOWN:  // OnDemand
+      return;
+      break;
+    default:
+      ASSERT1(false);
+      return;
+  }
+#pragma warning(pop)
+
+  ASSERT1(job_observer_.get());
+  ErrorWndEvents error_wnd_events;
+
+  // error_wnd_events must not be destroyed until CMessageLoop::Run() returns.
+  job_observer_->SetEventSink(&error_wnd_events);
+  job_observer_->OnShow();
+
+  job_observer_->OnComplete(COMPLETION_CODE_ERROR, error_text, error);
+
+  message_loop_.Run();
+}
+
+void Worker::DisplayErrorInMessageBox(const CString& error_text) {
+  ASSERT1(args_.mode == COMMANDLINE_MODE_INSTALL ||
+          args_.mode == COMMANDLINE_MODE_IG ||
+          args_.mode == COMMANDLINE_MODE_HANDOFF_INSTALL);
+
+  if (args_.is_silent_set) {
+    return;
+  }
+
+  CString primary_app_name;
+  ASSERT1(!args_.extra.apps.empty());
+  if (!args_.extra.apps.empty()) {
+    primary_app_name = GetPrimaryJobInfo().app_name;
+  }
+
+  goopdate_utils::DisplayErrorInMessageBox(error_text, primary_app_name);
+}
+
+}  // namespace omaha
+
diff --git a/worker/worker.h b/worker/worker.h
index 7c5d015..bf228bf 100644
--- a/worker/worker.h
+++ b/worker/worker.h
@@ -1,144 +1,144 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_WORKER_H__

-#define OMAHA_WORKER_WORKER_H__

-

-#include <atlbase.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/atlregmapex.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/common/shutdown_callback.h"

-#include "omaha/common/shutdown_handler.h"

-#include "omaha/common/thread_pool.h"

-#include "omaha/common/wtl_atlapp_wrapper.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/program_instance.h"

-#include "omaha/goopdate/resource_manager.h"

-#include "omaha/worker/com_wrapper_shutdown_handler.h"

-

-interface IJobObserver;

-

-namespace omaha {

-

-static const int kThreadPoolShutdownDelayMs = 60000;

-

-class Goopdate;

-class JobObserver;

-class ProgressWnd;

-class Reactor;

-class Setup;

-class UserInterface;

-class WorkerJobStrategy;

-class WorkerJob;

-class WorkerShutdownHandler;

-

-class Worker : public ShutdownCallback {

- public:

-  explicit Worker(bool is_machine);

-  virtual ~Worker();

-

-  HRESULT Main(Goopdate* goopdate);

-  HRESULT DoOnDemand(const WCHAR* guid,

-                     const CString& lang,

-                     IJobObserver* observer,

-                     bool is_update_check_only);

-

-  HRESULT Shutdown();

-  HRESULT InitializeThreadPool();

-  HRESULT InitializeShutDownHandler(ShutdownCallback* callback);

-

-  Reactor* reactor() const { return reactor_.get(); }

-  const CommandLineArgs& args() const { return args_; }

-  CString cmd_line() const { return cmd_line_; }

-  bool is_machine() const { return is_machine_; }

-  bool is_local_system() const { return is_local_system_; }

-  bool has_uninstalled() const { return has_uninstalled_; }

-  WorkerComWrapperShutdownCallBack* shutdown_callback() const {

-    return shutdown_callback_.get();

-  }

-  void set_shutdown_callback(WorkerComWrapperShutdownCallBack* callback) {

-    ASSERT1(callback);

-    shutdown_callback_.reset(callback);

-  }

-

- private:

-  HRESULT StartWorkerJob();

-  HRESULT QueueWorkerJob(WorkerJob* worker_job, bool delete_after_run);

-  // Stops and destroys the Worker and its members.

-  void StopWorker(HRESULT* worker_job_error_code);

-  HRESULT DoRun();

-  bool EnsureSingleAppInstaller(const CString& guid);

-  bool EnsureSingleUpdateWorker();

-  HRESULT InitializeUI();

-

-  HRESULT DoInstall();

-  HRESULT DoUpdateApps();

-  HRESULT DoInstallGoogleUpdateAndApp();

-

-  // Uninstalls GoogleUpdate conditionally.

-  void MaybeUninstallGoogleUpdate();

-

-  HRESULT HandleSetupError(HRESULT error, int extra_code1);

-

-  void CollectAmbientUsageStats();

-

-  const CommandLineAppArgs& GetPrimaryJobInfo() const;

-

-  // Displays an error using the normal UI. Does not display a message box when

-  // running silently.

-  void DisplayError(const CString& error_text, HRESULT error);

-

-

-  // Displays an error in a Windows Message Box. Useful when UI initialization

-  // fails. Does not display a message box when running silently.

-  virtual void DisplayErrorInMessageBox(const CString& error_text);

-

-

-  bool is_machine_;

-  bool is_local_system_;

-  bool has_uninstalled_;        // True if the worker has uninstalled Omaha.

-  CString cmd_line_;            // Command line, as provided by the OS.

-  scoped_ptr<ProgramInstance> single_update_worker_;

-  scoped_ptr<ProgramInstance> single_install_worker_;

-  // The ProgressWnd is owned by this class so that

-  // JobObserverCallMethodDecorator can release it without destroying it as

-  // expected in ProgressWnd and required for calling OnComplete in the same

-  // thread as the message loop when displaying an early error.

-  scoped_ptr<ProgressWnd> progress_wnd_;

-  scoped_ptr<JobObserver> job_observer_;

-  scoped_ptr<Reactor>     reactor_;

-  scoped_ptr<ShutdownHandler> shutdown_handler_;

-  CommandLineArgs args_;

-  scoped_ptr<WorkerJob> worker_job_;

-  scoped_ptr<WorkerComWrapperShutdownCallBack> shutdown_callback_;

-

-  // Message loop for non-COM modes.

-  CMessageLoop message_loop_;

-  scoped_ptr<ThreadPool>  thread_pool_;

-

-  friend class WorkerTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(Worker);

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_WORKER_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_WORKER_H__
+#define OMAHA_WORKER_WORKER_H__
+
+#include <atlbase.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/atlregmapex.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/common/shutdown_callback.h"
+#include "omaha/common/shutdown_handler.h"
+#include "omaha/common/thread_pool.h"
+#include "omaha/common/wtl_atlapp_wrapper.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/program_instance.h"
+#include "omaha/goopdate/resource_manager.h"
+#include "omaha/worker/com_wrapper_shutdown_handler.h"
+
+interface IJobObserver;
+
+namespace omaha {
+
+static const int kThreadPoolShutdownDelayMs = 60000;
+
+class Goopdate;
+class JobObserver;
+class ProgressWnd;
+class Reactor;
+class Setup;
+class UserInterface;
+class WorkerJobStrategy;
+class WorkerJob;
+class WorkerShutdownHandler;
+
+class Worker : public ShutdownCallback {
+ public:
+  explicit Worker(bool is_machine);
+  virtual ~Worker();
+
+  HRESULT Main(Goopdate* goopdate);
+  HRESULT DoOnDemand(const WCHAR* guid,
+                     const CString& lang,
+                     IJobObserver* observer,
+                     bool is_update_check_only);
+
+  HRESULT Shutdown();
+  HRESULT InitializeThreadPool();
+  HRESULT InitializeShutDownHandler(ShutdownCallback* callback);
+
+  Reactor* reactor() const { return reactor_.get(); }
+  const CommandLineArgs& args() const { return args_; }
+  CString cmd_line() const { return cmd_line_; }
+  bool is_machine() const { return is_machine_; }
+  bool is_local_system() const { return is_local_system_; }
+  bool has_uninstalled() const { return has_uninstalled_; }
+  WorkerComWrapperShutdownCallBack* shutdown_callback() const {
+    return shutdown_callback_.get();
+  }
+  void set_shutdown_callback(WorkerComWrapperShutdownCallBack* callback) {
+    ASSERT1(callback);
+    shutdown_callback_.reset(callback);
+  }
+
+ private:
+  HRESULT StartWorkerJob();
+  HRESULT QueueWorkerJob(WorkerJob* worker_job, bool delete_after_run);
+  // Stops and destroys the Worker and its members.
+  void StopWorker(HRESULT* worker_job_error_code);
+  HRESULT DoRun();
+  bool EnsureSingleAppInstaller(const CString& guid);
+  bool EnsureSingleUpdateWorker();
+  HRESULT InitializeUI();
+
+  HRESULT DoInstall();
+  HRESULT DoUpdateApps();
+  HRESULT DoInstallGoogleUpdateAndApp();
+
+  // Uninstalls GoogleUpdate conditionally.
+  void MaybeUninstallGoogleUpdate();
+
+  HRESULT HandleSetupError(HRESULT error, int extra_code1);
+
+  void CollectAmbientUsageStats();
+
+  const CommandLineAppArgs& GetPrimaryJobInfo() const;
+
+  // Displays an error using the normal UI. Does not display a message box when
+  // running silently.
+  void DisplayError(const CString& error_text, HRESULT error);
+
+
+  // Displays an error in a Windows Message Box. Useful when UI initialization
+  // fails. Does not display a message box when running silently.
+  virtual void DisplayErrorInMessageBox(const CString& error_text);
+
+
+  bool is_machine_;
+  bool is_local_system_;
+  bool has_uninstalled_;        // True if the worker has uninstalled Omaha.
+  CString cmd_line_;            // Command line, as provided by the OS.
+  scoped_ptr<ProgramInstance> single_update_worker_;
+  scoped_ptr<ProgramInstance> single_install_worker_;
+  // The ProgressWnd is owned by this class so that
+  // JobObserverCallMethodDecorator can release it without destroying it as
+  // expected in ProgressWnd and required for calling OnComplete in the same
+  // thread as the message loop when displaying an early error.
+  scoped_ptr<ProgressWnd> progress_wnd_;
+  scoped_ptr<JobObserver> job_observer_;
+  scoped_ptr<Reactor>     reactor_;
+  scoped_ptr<ShutdownHandler> shutdown_handler_;
+  CommandLineArgs args_;
+  scoped_ptr<WorkerJob> worker_job_;
+  scoped_ptr<WorkerComWrapperShutdownCallBack> shutdown_callback_;
+
+  // Message loop for non-COM modes.
+  CMessageLoop message_loop_;
+  scoped_ptr<ThreadPool>  thread_pool_;
+
+  friend class WorkerTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(Worker);
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_WORKER_H__
+
diff --git a/worker/worker_com_wrapper.cc b/worker/worker_com_wrapper.cc
index e3fb665..b4e1d00 100644
--- a/worker/worker_com_wrapper.cc
+++ b/worker/worker_com_wrapper.cc
@@ -1,127 +1,127 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-#include "omaha/worker/worker_com_wrapper.h"

-

-#include <atlbase.h>

-#include <atlstr.h>

-#include <atlsecurity.h>

-#include "omaha/common/error.h"

-#include "omaha/common/exception_barrier.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/goopdate/google_update.h"

-#include "omaha/worker/com_wrapper_shutdown_handler.h"

-#include "omaha/worker/worker.h"

-

-namespace omaha {

-

-HRESULT OnDemandCOMClass::FinalConstruct() {

-  CORE_LOG(L2, (_T("[OnDemandCOMClass::FinalConstruct]")));

-

-  GoogleUpdate* google_update = static_cast<GoogleUpdate*>(_pAtlModule);

-  worker_ = google_update->worker();

-  ASSERT1(worker_);

-

-  HRESULT hr = worker_->InitializeThreadPool();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  // For update checks on machine applications where the user is not an

-  // administrator, the COM server will shutdown automatically after it returns

-  // from a COM method invocation. Two reasons for this policy:

-  // * Only update checks on a machine app can be done as a non-admin user. To

-  //   call Update requires an elevated instance of the COM server. So this COM

-  //   server is useless after the UpdateCheck call.

-  // * Listening on the shutdown handler requires admin privileges.

-  bool shutdown_after_invocation = worker_->is_machine() && !::IsUserAnAdmin();

-  worker_->set_shutdown_callback(new WorkerComWrapperShutdownCallBack(

-                                         shutdown_after_invocation));

-

-  return shutdown_after_invocation ?

-             S_OK :

-             worker_->InitializeShutDownHandler(worker_->shutdown_callback());

-}

-

-void OnDemandCOMClass::FinalRelease() {

-  CORE_LOG(L2, (_T("[OnDemandCOMClass::FinalRelease]")));

-  worker_ = NULL;

-}

-

-void OnDemandCOMClass::AddRefIgnoreShutdownEvent() const {

-  CORE_LOG(L2, (_T("[OnDemandCOMClass::AddRefIgnoreShutdownEvent]")));

-  ASSERT1(worker_);

-  WorkerComWrapperShutdownCallBack* callback = worker_->shutdown_callback();

-  ASSERT1(callback);

-  callback->AddRefIgnoreShutdown();

-}

-

-void OnDemandCOMClass::ResetStateOnError() const {

-  CORE_LOG(L2, (_T("[OnDemandCOMClass::ResetStateOnError]")));

-  ASSERT1(worker_);

-  WorkerComWrapperShutdownCallBack* callback = worker_->shutdown_callback();

-  ASSERT1(callback);

-  callback->ReleaseIgnoreShutdown();

-}

-

-HRESULT OnDemandCOMClass::DoOnDemand(bool is_update_check_only,

-                                     const WCHAR* guid,

-                                     IJobObserver* observer) {

-  CORE_LOG(L2, (_T("[OnDemandCOMClass::DoOnDemand][%d][%s][%d]"),

-                is_update_check_only, guid, observer));

-  // The exception barrier is needed, because any exceptions that are thrown

-  // in this method will get caught by the COM run time. We compile with

-  // exceptions off, and do not expect to throw any exceptions. This barrier

-  // will treat an exception in this method as a unhandled exception.

-  ExceptionBarrier barrier;

-

-  ASSERT1(guid);

-  ASSERT1(observer);

-  if (!guid || StringToGuid(guid) == GUID_NULL || !observer) {

-    return E_INVALIDARG;

-  }

-

-  AddRefIgnoreShutdownEvent();

-  // Ensure that the reset method is called in all error cases.

-  ScopeGuard guard = MakeObjGuard(*this, &OnDemandCOMClass::ResetStateOnError);

-

-  HRESULT hr = worker_->DoOnDemand(guid,

-                                   CString(),

-                                   observer,

-                                   is_update_check_only);

-  if (FAILED(hr)) {

-    OPT_LOG(LE, (_T("[DoOnDemand failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  // Dismiss the scope guard, since the DoOnDemand succeeded and the worker job

-  // thread is now responsible for the cleanup.

-  guard.Dismiss();

-  return S_OK;

-}

-

-STDMETHODIMP OnDemandCOMClass::Update(const WCHAR* guid,

-                                      IJobObserver* observer) {

-  return DoOnDemand(false, guid, observer);

-}

-

-STDMETHODIMP OnDemandCOMClass::CheckForUpdate(const WCHAR* guid,

-                                              IJobObserver* observer) {

-  return DoOnDemand(true, guid, observer);

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+#include "omaha/worker/worker_com_wrapper.h"
+
+#include <atlbase.h>
+#include <atlstr.h>
+#include <atlsecurity.h>
+#include "omaha/common/error.h"
+#include "omaha/common/exception_barrier.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/goopdate/google_update.h"
+#include "omaha/worker/com_wrapper_shutdown_handler.h"
+#include "omaha/worker/worker.h"
+
+namespace omaha {
+
+HRESULT OnDemandCOMClass::FinalConstruct() {
+  CORE_LOG(L2, (_T("[OnDemandCOMClass::FinalConstruct]")));
+
+  GoogleUpdate* google_update = static_cast<GoogleUpdate*>(_pAtlModule);
+  worker_ = google_update->worker();
+  ASSERT1(worker_);
+
+  HRESULT hr = worker_->InitializeThreadPool();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // For update checks on machine applications where the user is not an
+  // administrator, the COM server will shutdown automatically after it returns
+  // from a COM method invocation. Two reasons for this policy:
+  // * Only update checks on a machine app can be done as a non-admin user. To
+  //   call Update requires an elevated instance of the COM server. So this COM
+  //   server is useless after the UpdateCheck call.
+  // * Listening on the shutdown handler requires admin privileges.
+  bool shutdown_after_invocation = worker_->is_machine() && !::IsUserAnAdmin();
+  worker_->set_shutdown_callback(new WorkerComWrapperShutdownCallBack(
+                                         shutdown_after_invocation));
+
+  return shutdown_after_invocation ?
+             S_OK :
+             worker_->InitializeShutDownHandler(worker_->shutdown_callback());
+}
+
+void OnDemandCOMClass::FinalRelease() {
+  CORE_LOG(L2, (_T("[OnDemandCOMClass::FinalRelease]")));
+  worker_ = NULL;
+}
+
+void OnDemandCOMClass::AddRefIgnoreShutdownEvent() const {
+  CORE_LOG(L2, (_T("[OnDemandCOMClass::AddRefIgnoreShutdownEvent]")));
+  ASSERT1(worker_);
+  WorkerComWrapperShutdownCallBack* callback = worker_->shutdown_callback();
+  ASSERT1(callback);
+  callback->AddRefIgnoreShutdown();
+}
+
+void OnDemandCOMClass::ResetStateOnError() const {
+  CORE_LOG(L2, (_T("[OnDemandCOMClass::ResetStateOnError]")));
+  ASSERT1(worker_);
+  WorkerComWrapperShutdownCallBack* callback = worker_->shutdown_callback();
+  ASSERT1(callback);
+  callback->ReleaseIgnoreShutdown();
+}
+
+HRESULT OnDemandCOMClass::DoOnDemand(bool is_update_check_only,
+                                     const WCHAR* guid,
+                                     IJobObserver* observer) {
+  CORE_LOG(L2, (_T("[OnDemandCOMClass::DoOnDemand][%d][%s][%d]"),
+                is_update_check_only, guid, observer));
+  // The exception barrier is needed, because any exceptions that are thrown
+  // in this method will get caught by the COM run time. We compile with
+  // exceptions off, and do not expect to throw any exceptions. This barrier
+  // will treat an exception in this method as a unhandled exception.
+  ExceptionBarrier barrier;
+
+  ASSERT1(guid);
+  ASSERT1(observer);
+  if (!guid || StringToGuid(guid) == GUID_NULL || !observer) {
+    return E_INVALIDARG;
+  }
+
+  AddRefIgnoreShutdownEvent();
+  // Ensure that the reset method is called in all error cases.
+  ScopeGuard guard = MakeObjGuard(*this, &OnDemandCOMClass::ResetStateOnError);
+
+  HRESULT hr = worker_->DoOnDemand(guid,
+                                   CString(),
+                                   observer,
+                                   is_update_check_only);
+  if (FAILED(hr)) {
+    OPT_LOG(LE, (_T("[DoOnDemand failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  // Dismiss the scope guard, since the DoOnDemand succeeded and the worker job
+  // thread is now responsible for the cleanup.
+  guard.Dismiss();
+  return S_OK;
+}
+
+STDMETHODIMP OnDemandCOMClass::Update(const WCHAR* guid,
+                                      IJobObserver* observer) {
+  return DoOnDemand(false, guid, observer);
+}
+
+STDMETHODIMP OnDemandCOMClass::CheckForUpdate(const WCHAR* guid,
+                                              IJobObserver* observer) {
+  return DoOnDemand(true, guid, observer);
+}
+
+}  // namespace omaha
+
diff --git a/worker/worker_com_wrapper.h b/worker/worker_com_wrapper.h
index ed9f84b..7109661 100644
--- a/worker/worker_com_wrapper.h
+++ b/worker/worker_com_wrapper.h
@@ -1,113 +1,113 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_WORKER_COM_WRAPPER_H__

-#define OMAHA_WORKER_WORKER_COM_WRAPPER_H__

-

-#include <atlbase.h>

-#include <atlcom.h>

-#include <atlstr.h>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "goopdate/google_update_idl.h"

-#include "omaha/common/atlregmapex.h"

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/preprocessor_fun.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource.h"

-#include "omaha/goopdate/resources/goopdate_dll/goopdate_dll.grh"

-

-namespace omaha {

-

-const TCHAR* const kOnDemandCOMClassUserProgId =

-    _T("GoogleUpdate.OnDemandCOMClassUser");

-const TCHAR* const kOnDemandCOMClassMachineProgId =

-    _T("GoogleUpdate.OnDemandCOMClassMachine");

-const TCHAR* const kOnDemandCOMClassDescription =

-    _T("GoogleUpdate.OnDemandCOMClass");

-

-class Worker;

-

-class OnDemandCOMClass

-    : public CComObjectRootEx<CComMultiThreadModel>,

-      public CComCoClass<OnDemandCOMClass>,

-      public IGoogleUpdate {

- public:

-  OnDemandCOMClass()

-      : worker_(NULL) {

-  }

-  virtual ~OnDemandCOMClass() {}

-

-  DECLARE_NOT_AGGREGATABLE(OnDemandCOMClass)

-  DECLARE_PROTECT_FINAL_CONSTRUCT()

-

-  DECLARE_REGISTRY_RESOURCEID_EX(IDR_GOOGLE_UPDATE_WORKER_CLASS)

-

-  #pragma warning(push)

-  // C4640: construction of local static object is not thread-safe

-  #pragma warning(disable : 4640)

-  BEGIN_REGISTRY_MAP()

-    REGMAP_ENTRY(_T("HKROOT"),       goopdate_utils::GetHKRoot())

-    REGMAP_EXE_MODULE(_T("MODULE"))

-    REGMAP_ENTRY(_T("VERSION"),      _T("1.0"))

-    REGMAP_ENTRY(_T("PROGID"),

-                 goopdate_utils::IsRunningFromOfficialGoopdateDir(true) ?

-                     kOnDemandCOMClassMachineProgId :

-                     kOnDemandCOMClassUserProgId)

-    REGMAP_ENTRY(_T("DESCRIPTION"),  kOnDemandCOMClassDescription)

-    REGMAP_UUID(_T("CLSID"),

-                goopdate_utils::IsRunningFromOfficialGoopdateDir(true) ?

-                    __uuidof(OnDemandMachineAppsClass) :

-                    __uuidof(OnDemandUserAppsClass))

-    REGMAP_UUID(_T("LIBID"),         LIBID_GoogleUpdateLib)

-    REGMAP_ENTRY(_T("STRINGRESID"),

-                 PP_STRINGIZE(IDS_ELEVATION_MONIKER_DISPLAYNAME))

-    REGMAP_ENTRY(_T("ICONRESID"), PP_STRINGIZE(IDI_ELEVATION_MONIKER_ICON))

-  END_REGISTRY_MAP()

-  #pragma warning(pop)

-

-  // C4505: unreferenced IUnknown local functions have been removed

-  #pragma warning(disable : 4505)

-  BEGIN_COM_MAP(OnDemandCOMClass)

-    COM_INTERFACE_ENTRY(IGoogleUpdate)

-  END_COM_MAP()

-

-  STDMETHOD(CheckForUpdate)(const WCHAR* guid, IJobObserver* observer);

-  STDMETHOD(Update)(const WCHAR* guid, IJobObserver* observer);

-  HRESULT FinalConstruct();

-  void FinalRelease();

-

- private:

-  void AddRefIgnoreShutdownEvent() const;

-  HRESULT DoOnDemand(bool is_update_check_only,

-                     const TCHAR* guid,

-                     IJobObserver* observer);

-

-  // Uninitializes the observer and allows COM calls.

-  void ResetStateOnError() const;

-

-  Worker* worker_;

-};

-

-class OnDemandCOMClassMachine : public OnDemandCOMClass {

- public:

-  DECLARE_REGISTRY_RESOURCEID_EX(IDR_GOOGLE_UPDATE_WORKER_CLASS_MACHINE)

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_WORKER_COM_WRAPPER_H__

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_WORKER_COM_WRAPPER_H__
+#define OMAHA_WORKER_WORKER_COM_WRAPPER_H__
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlstr.h>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "goopdate/google_update_idl.h"
+#include "omaha/common/atlregmapex.h"
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/preprocessor_fun.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource.h"
+#include "omaha/goopdate/resources/goopdate_dll/goopdate_dll.grh"
+
+namespace omaha {
+
+const TCHAR* const kOnDemandCOMClassUserProgId =
+    _T("GoogleUpdate.OnDemandCOMClassUser");
+const TCHAR* const kOnDemandCOMClassMachineProgId =
+    _T("GoogleUpdate.OnDemandCOMClassMachine");
+const TCHAR* const kOnDemandCOMClassDescription =
+    _T("GoogleUpdate.OnDemandCOMClass");
+
+class Worker;
+
+class OnDemandCOMClass
+    : public CComObjectRootEx<CComMultiThreadModel>,
+      public CComCoClass<OnDemandCOMClass>,
+      public IGoogleUpdate {
+ public:
+  OnDemandCOMClass()
+      : worker_(NULL) {
+  }
+  virtual ~OnDemandCOMClass() {}
+
+  DECLARE_NOT_AGGREGATABLE(OnDemandCOMClass)
+  DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+  DECLARE_REGISTRY_RESOURCEID_EX(IDR_GOOGLE_UPDATE_WORKER_CLASS)
+
+  #pragma warning(push)
+  // C4640: construction of local static object is not thread-safe
+  #pragma warning(disable : 4640)
+  BEGIN_REGISTRY_MAP()
+    REGMAP_ENTRY(_T("HKROOT"),       goopdate_utils::GetHKRoot())
+    REGMAP_EXE_MODULE(_T("MODULE"))
+    REGMAP_ENTRY(_T("VERSION"),      _T("1.0"))
+    REGMAP_ENTRY(_T("PROGID"),
+                 goopdate_utils::IsRunningFromOfficialGoopdateDir(true) ?
+                     kOnDemandCOMClassMachineProgId :
+                     kOnDemandCOMClassUserProgId)
+    REGMAP_ENTRY(_T("DESCRIPTION"),  kOnDemandCOMClassDescription)
+    REGMAP_UUID(_T("CLSID"),
+                goopdate_utils::IsRunningFromOfficialGoopdateDir(true) ?
+                    __uuidof(OnDemandMachineAppsClass) :
+                    __uuidof(OnDemandUserAppsClass))
+    REGMAP_UUID(_T("LIBID"),         LIBID_GoogleUpdateLib)
+    REGMAP_ENTRY(_T("STRINGRESID"),
+                 PP_STRINGIZE(IDS_ELEVATION_MONIKER_DISPLAYNAME))
+    REGMAP_ENTRY(_T("ICONRESID"), PP_STRINGIZE(IDI_ELEVATION_MONIKER_ICON))
+  END_REGISTRY_MAP()
+  #pragma warning(pop)
+
+  // C4505: unreferenced IUnknown local functions have been removed
+  #pragma warning(disable : 4505)
+  BEGIN_COM_MAP(OnDemandCOMClass)
+    COM_INTERFACE_ENTRY(IGoogleUpdate)
+  END_COM_MAP()
+
+  STDMETHOD(CheckForUpdate)(const WCHAR* guid, IJobObserver* observer);
+  STDMETHOD(Update)(const WCHAR* guid, IJobObserver* observer);
+  HRESULT FinalConstruct();
+  void FinalRelease();
+
+ private:
+  void AddRefIgnoreShutdownEvent() const;
+  HRESULT DoOnDemand(bool is_update_check_only,
+                     const TCHAR* guid,
+                     IJobObserver* observer);
+
+  // Uninitializes the observer and allows COM calls.
+  void ResetStateOnError() const;
+
+  Worker* worker_;
+};
+
+class OnDemandCOMClassMachine : public OnDemandCOMClass {
+ public:
+  DECLARE_REGISTRY_RESOURCEID_EX(IDR_GOOGLE_UPDATE_WORKER_CLASS_MACHINE)
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_WORKER_COM_WRAPPER_H__
+
diff --git a/worker/worker_event_logger.cc b/worker/worker_event_logger.cc
index 3cb36e9..57d9b56 100644
--- a/worker/worker_event_logger.cc
+++ b/worker/worker_event_logger.cc
@@ -1,96 +1,96 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/worker/worker_event_logger.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/time.h"

-#include "omaha/common/utils.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/event_logger.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/resource_manager.h"

-#include "omaha/worker/job.h"

-

-namespace omaha {

-

-const TCHAR* const kUpdateCheckEventDesc = _T("Update check. Status = 0x%08x");

-const TCHAR* const kUpdateEventDesc           = _T("Application update");

-const TCHAR* const kInstallEventDesc          = _T("Application install");

-const TCHAR* const kUpdateAppsWorkerEventDesc = _T("Update worker start");

-

-void WriteUpdateCheckEvent(bool is_machine, HRESULT hr, const CString& text) {

-  const int event_type = SUCCEEDED(hr) ? EVENTLOG_INFORMATION_TYPE :

-                                         EVENTLOG_WARNING_TYPE;

-  const int event_id   = kUpdateCheckEventId;

-

-  CString event_description, event_text;

-  event_description.Format(kUpdateCheckEventDesc, hr);

-

-  CString url;

-  VERIFY1(SUCCEEDED(ConfigManager::Instance()->GetUpdateCheckUrl(&url)));

-  event_text.Format(_T("url=%s\n%s"), url, text);

-

-  GoogleUpdateLogEvent update_check_event(event_type, event_id, is_machine);

-  update_check_event.set_event_desc(event_description);

-  update_check_event.set_event_text(event_text);

-  update_check_event.WriteEvent();

-}

-

-void WriteJobCompletedEvent(bool is_machine, const Job& job) {

-  int type = IsCompletionSuccess(job.info()) ? EVENTLOG_INFORMATION_TYPE :

-                                               EVENTLOG_WARNING_TYPE;

-

-  GoogleUpdateLogEvent update_event(type, kUpdateEventId, is_machine);

-  CString desc = job.is_update() ? kUpdateEventDesc :

-                                   kInstallEventDesc;

-  update_event.set_event_desc(desc);

-  CString event_text;

-  event_text.AppendFormat(_T("App=%s, Ver=%s, PrevVer=%s, Status=0x%08x"),

-                          GuidToString(job.app_data().app_guid()),

-                          job.app_data().version(),

-                          job.app_data().previous_version(),

-                          job.info().error_code);

-  update_event.set_event_text(event_text);

-  update_event.WriteEvent();

-}

-

-void WriteUpdateAppsWorkerStartEvent(bool is_machine) {

-  GoogleUpdateLogEvent update_event(EVENTLOG_INFORMATION_TYPE,

-                                    kWorkerStartEventId,

-                                    is_machine);

-  update_event.set_event_desc(kUpdateAppsWorkerEventDesc);

-

-  ConfigManager& cm = *ConfigManager::Instance();

-

-  int au_check_period_ms = cm.GetAutoUpdateTimerIntervalMs();

-  int time_since_last_checked_sec = cm.GetTimeSinceLastCheckedSec(is_machine);

-  bool is_period_overridden = false;

-  int last_check_period_ms = cm.GetLastCheckPeriodSec(&is_period_overridden);

-

-  CString event_text;

-  event_text.Format(

-    _T("AuCheckPeriodMs=%d, TimeSinceLastCheckedSec=%d, ")

-    _T("LastCheckedPeriodSec=%d"),

-    au_check_period_ms, time_since_last_checked_sec, last_check_period_ms);

-

-  update_event.set_event_text(event_text);

-  update_event.WriteEvent();

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/worker/worker_event_logger.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/time.h"
+#include "omaha/common/utils.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/event_logger.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/resource_manager.h"
+#include "omaha/worker/job.h"
+
+namespace omaha {
+
+const TCHAR* const kUpdateCheckEventDesc = _T("Update check. Status = 0x%08x");
+const TCHAR* const kUpdateEventDesc           = _T("Application update");
+const TCHAR* const kInstallEventDesc          = _T("Application install");
+const TCHAR* const kUpdateAppsWorkerEventDesc = _T("Update worker start");
+
+void WriteUpdateCheckEvent(bool is_machine, HRESULT hr, const CString& text) {
+  const int event_type = SUCCEEDED(hr) ? EVENTLOG_INFORMATION_TYPE :
+                                         EVENTLOG_WARNING_TYPE;
+  const int event_id   = kUpdateCheckEventId;
+
+  CString event_description, event_text;
+  event_description.Format(kUpdateCheckEventDesc, hr);
+
+  CString url;
+  VERIFY1(SUCCEEDED(ConfigManager::Instance()->GetUpdateCheckUrl(&url)));
+  event_text.Format(_T("url=%s\n%s"), url, text);
+
+  GoogleUpdateLogEvent update_check_event(event_type, event_id, is_machine);
+  update_check_event.set_event_desc(event_description);
+  update_check_event.set_event_text(event_text);
+  update_check_event.WriteEvent();
+}
+
+void WriteJobCompletedEvent(bool is_machine, const Job& job) {
+  int type = IsCompletionSuccess(job.info()) ? EVENTLOG_INFORMATION_TYPE :
+                                               EVENTLOG_WARNING_TYPE;
+
+  GoogleUpdateLogEvent update_event(type, kUpdateEventId, is_machine);
+  CString desc = job.is_update() ? kUpdateEventDesc :
+                                   kInstallEventDesc;
+  update_event.set_event_desc(desc);
+  CString event_text;
+  event_text.AppendFormat(_T("App=%s, Ver=%s, PrevVer=%s, Status=0x%08x"),
+                          GuidToString(job.app_data().app_guid()),
+                          job.app_data().version(),
+                          job.app_data().previous_version(),
+                          job.info().error_code);
+  update_event.set_event_text(event_text);
+  update_event.WriteEvent();
+}
+
+void WriteUpdateAppsWorkerStartEvent(bool is_machine) {
+  GoogleUpdateLogEvent update_event(EVENTLOG_INFORMATION_TYPE,
+                                    kWorkerStartEventId,
+                                    is_machine);
+  update_event.set_event_desc(kUpdateAppsWorkerEventDesc);
+
+  ConfigManager& cm = *ConfigManager::Instance();
+
+  int au_check_period_ms = cm.GetAutoUpdateTimerIntervalMs();
+  int time_since_last_checked_sec = cm.GetTimeSinceLastCheckedSec(is_machine);
+  bool is_period_overridden = false;
+  int last_check_period_ms = cm.GetLastCheckPeriodSec(&is_period_overridden);
+
+  CString event_text;
+  event_text.Format(
+    _T("AuCheckPeriodMs=%d, TimeSinceLastCheckedSec=%d, ")
+    _T("LastCheckedPeriodSec=%d"),
+    au_check_period_ms, time_since_last_checked_sec, last_check_period_ms);
+
+  update_event.set_event_text(event_text);
+  update_event.WriteEvent();
+}
+
+}  // namespace omaha
diff --git a/worker/worker_event_logger.h b/worker/worker_event_logger.h
index f98e36e..06202ae 100644
--- a/worker/worker_event_logger.h
+++ b/worker/worker_event_logger.h
@@ -1,32 +1,32 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_WORKER_EVENT_LOGGER_H__

-#define OMAHA_WORKER_WORKER_EVENT_LOGGER_H__

-

-#include <windows.h>

-#include <atlstr.h>

-

-namespace omaha {

-

-class Job;

-

-void WriteUpdateAppsWorkerStartEvent(bool is_machine);

-void WriteUpdateCheckEvent(bool is_machine, HRESULT hr, const CString& text);

-void WriteJobCompletedEvent(bool is_machine, const Job& job);

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_WORKER_EVENT_LOGGER_H__

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_WORKER_EVENT_LOGGER_H__
+#define OMAHA_WORKER_WORKER_EVENT_LOGGER_H__
+
+#include <windows.h>
+#include <atlstr.h>
+
+namespace omaha {
+
+class Job;
+
+void WriteUpdateAppsWorkerStartEvent(bool is_machine);
+void WriteUpdateCheckEvent(bool is_machine, HRESULT hr, const CString& text);
+void WriteJobCompletedEvent(bool is_machine, const Job& job);
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_WORKER_EVENT_LOGGER_H__
diff --git a/worker/worker_job.cc b/worker/worker_job.cc
index 698f9ae..e107526 100644
--- a/worker/worker_job.cc
+++ b/worker/worker_job.cc
@@ -1,914 +1,914 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-//

-// TODO(omaha): The jobs are not being moved to the completed state in the

-// cancel/shutdown case.

-// Should be able to ASSERT1(job->job_state() == COMPLETED) in the worker

-// destructor.

-#include "omaha/worker/worker_job.h"

-

-#include <windows.h>

-#include <atlcom.h>

-#include <cstring>

-#include <vector>

-#include "omaha/common/const_addresses.h"

-#include "omaha/common/const_object_names.h"

-#include "omaha/common/constants.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/common/sta_call.h"

-#include "omaha/common/string.h"

-#include "omaha/common/user_info.h"

-#include "omaha/common/utils.h"

-#include "omaha/common/vista_utils.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/goopdate_xml_parser.h"

-#include "omaha/goopdate/request.h"

-#include "omaha/goopdate/resource.h"

-#include "omaha/goopdate/update_response_data.h"

-#include "omaha/net/browser_request.h"

-#include "omaha/net/cup_request.h"

-#include "omaha/net/network_request.h"

-#include "omaha/net/simple_request.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/application_manager.h"

-#include "omaha/worker/download_manager.h"

-#include "omaha/worker/install_manager.h"

-#include "omaha/worker/job.h"

-#include "omaha/worker/job_creator.h"

-#include "omaha/worker/ping.h"

-#include "omaha/worker/ping_utils.h"

-#include "omaha/worker/worker_event_logger.h"

-#include "omaha/worker/worker_job_strategy.h"

-#include "omaha/worker/worker_metrics.h"

-

-// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".

-#include "goopdate/google_update_idl.h"

-

-namespace omaha {

-

-// job_observer can be NULL.

-WorkerJob::WorkerJob(WorkerJobStrategy* strategy, JobObserver* job_observer)

-    : is_canceled_(false),

-      cur_job_(NULL),

-      bundle_dl_size_(0),

-      bundle_bytes_downloaded_(0),

-      job_observer_(job_observer),

-      no_jobs_completed_ping_sent_(false),

-      error_code_(S_OK) {

-  CORE_LOG(L2, (_T("[WorkerJob::WorkerJob]")));

-  ASSERT1(strategy);

-  strategy_.reset(strategy);

-  strategy_->set_worker_job(this);

-

-  is_machine_ = strategy_->is_machine();

-  running_version_  = GetVersionString();

-

-  const NetworkConfig::Session& session(NetworkConfig::Instance().session());

-

-  // The network request used by the update checks that do not require

-  // encryption.

-  network_request_.reset(new NetworkRequest(session));

-  network_request_->AddHttpRequest(new CupRequest(new SimpleRequest));

-  network_request_->AddHttpRequest(new SimpleRequest);

-  network_request_->AddHttpRequest(new CupRequest(new BrowserRequest));

-  network_request_->set_num_retries(1);

-

-  // The network request used by the encrypted update checks. For trusted tester

-  // update requests, because the TT token is a secret but is sent in the clear,

-  // we need https.

-  network_request_encrypted_.reset(new NetworkRequest(session));

-  network_request_encrypted_->AddHttpRequest(new SimpleRequest);

-  network_request_encrypted_->AddHttpRequest(new BrowserRequest);

-  network_request_encrypted_->set_num_retries(1);

-

-  // TODO(omaha): consider providing a download directory where file is

-  // to be downloaded. This directory should be know very early during the

-  // execution of the program and transmited as a parameter to DownloadManager.

-  download_manager_.reset(new DownloadManager(is_machine_));

-  download_manager_->set_impersonation_token(session.impersonation_token);

-

-  ping_.reset(new Ping());

-}

-

-WorkerJob::~WorkerJob() {

-  CORE_LOG(L2, (_T("[WorkerJob::~WorkerJob]")));

-  for (size_t i = 0; i < jobs_.size(); ++i) {

-    delete jobs_[i];

-  }

-}

-

-HRESULT BuildUninstallPing(bool is_machine, Request** uninstall_ping) {

-  CORE_LOG(L2, (_T("[BuildUninstallPing]")));

-  ASSERT1(uninstall_ping);

-

-  AppManager app_manager(is_machine);

-  ProductDataVector products;

-  HRESULT hr = app_manager.GetUnRegisteredProducts(&products);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[GetUnRegisteredProducts failed 0x%08x]"), hr));

-    return hr;

-  }

-

-  scoped_ptr<Request> request(new Request(is_machine));

-  for (size_t i = 0; i < products.size(); ++i) {

-    ProductData& product_data = products[i];

-    ASSERT1(product_data.app_data().is_uninstalled());

-

-    CORE_LOG(L2, (_T("[found uninstalled product][parent %s][app guid %s]"),

-                  GuidToString(product_data.app_data().parent_app_guid()),

-                  GuidToString(product_data.app_data().app_guid())));

-

-    // TODO(omaha): Do we have uninstall pings for components?

-    AppRequestData app_request_data(product_data.app_data());

-    PingEvent ping_event(PingEvent::EVENT_UNINSTALL,

-                         PingEvent::EVENT_RESULT_SUCCESS,

-                         0,  // error code

-                         0,  // extra code 1

-                         product_data.app_data().previous_version());

-    app_request_data.AddPingEvent(ping_event);

-    AppRequest app_request(app_request_data);

-    request->AddAppRequest(app_request);

-

-    VERIFY1(SUCCEEDED(app_manager.RemoveClientState(product_data.app_data())));

-  }

-

-  *uninstall_ping = request.release();

-  return S_OK;

-}

-

-HRESULT WorkerJob::DoProcess() {

-  CORE_LOG(L2, (_T("[WorkerJob::DoProcess]")));

-

-  ProductDataVector products;

-  HRESULT hr = DoProcessInternal(&products);

-

-  if (FAILED(hr)) {

-    CString msg;

-    switch (hr) {

-      case GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY:

-        ASSERT1(!strategy_->first_disallowed_app_name().IsEmpty());

-        msg.FormatMessage(IDS_APP_INSTALL_DISABLED_BY_GROUP_POLICY,

-                          strategy_->first_disallowed_app_name());

-        break;

-

-      case GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY:

-      case GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED:

-      default:

-        msg.FormatMessage(IDS_INSTALL_FAILED, hr);

-        break;

-    }

-    ASSERT1(!msg.IsEmpty());

-    JobCompletionStatus status = (hr == GOOPDATE_E_WORKER_CANCELLED) ?

-                                 COMPLETION_CANCELLED :

-                                 COMPLETION_ERROR;

-    NotifyCompleted(status, hr, msg, products);

-  }

-

-  return hr;

-}

-

-HRESULT WorkerJob::DoProcessInternal(ProductDataVector* products) {

-  CORE_LOG(L2, (_T("[WorkerJob::DoProcessInternal]")));

-  ASSERT1(products);

-  ASSERT1(strategy_.get());

-

-  scoped_co_init init_com_apt(COINIT_MULTITHREADED);

-  HRESULT hr(init_com_apt.hresult());

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[init_com_apt failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (job_observer_) {

-    job_observer_->SetEventSink(this);

-    job_observer_->OnShow();

-  }

-

-  hr = strategy_->PreUpdateCheck(products);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[PreUpdateCheck failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  if (products->empty()) {

-    OPT_LOG(L1, (_T("[No products to check updates for. Exiting.]")));

-    // We should always have products in all cases except for updates.

-    ASSERT1(strategy_->IsAutoUpdate());

-    NotifyCompleted(COMPLETION_SUCCESS, S_OK, _T("No products!"), *products);

-    return S_OK;

-  }

-

-  hr = strategy_->RemoveDisallowedApps(products);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[RemoveDisallowedApps failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = strategy_->DoUpdateCheck(*products);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[DoUpdateCheck failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = strategy_->PostUpdateCheck();

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[PostUpdateCheck failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  hr = strategy_->ProcessApps();

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[ProcessApps failed][0x%08x]"), hr));

-    return hr;

-  }

-

-  return strategy_->PostInstall();

-}

-

-int WorkerJob::CalculateBundleSize() const {

-  CORE_LOG(L2, (_T("[WorkerJob::CalculateBundleSize]")));

-  int bundle_dl_size = 0;

-  for (size_t i = 0; i < jobs_.size(); ++i) {

-    bundle_dl_size += jobs_[i]->response_data().size();

-  }

-  return bundle_dl_size;

-}

-

-HRESULT WorkerJob::DownloadJobs() {

-  CORE_LOG(L2, (_T("[WorkerJob::DownloadJobs]")));

-  bundle_dl_size_ = CalculateBundleSize();

-

-  // Download all jobs.

-  for (size_t i = 0; i < jobs_.size(); ++i) {

-    if (is_canceled_) {

-      return GOOPDATE_E_WORKER_CANCELLED;

-    }

-

-    cur_job_ = jobs_[i];

-    ASSERT1(cur_job_);

-

-    if (cur_job_->job_state() != JOBSTATE_COMPLETED) {

-      cur_job_->set_job_observer(this);

-      HRESULT hr = cur_job_->Download(download_manager_.get());

-      cur_job_->set_job_observer(NULL);

-      cur_job_ = NULL;

-      if (FAILED(hr)) {

-        CORE_LOG(LE, (_T("[DownloadJob failed with 0x%08x]"), hr));

-        continue;

-      }

-    }

-

-    cur_job_ = NULL;

-  }

-

-  return S_OK;

-}

-

-HRESULT WorkerJob::InstallJobs() {

-  CORE_LOG(L2, (_T("[WorkerJob::InstallJobs]")));

-  // Install all jobs. We install the jobs in the reverse order, since we want

-  // the primary job, which is the first in the list to be installed last.

-  // The primary job can then perform user visible actions such as start

-  // the application.

-  Jobs::reverse_iterator iter = jobs_.rbegin();

-  for (; iter != jobs_.rend(); ++iter) {

-    if (is_canceled_) {

-      return GOOPDATE_E_WORKER_CANCELLED;

-    }

-

-    cur_job_ = *iter;

-    ASSERT1(cur_job_);

-

-    if (cur_job_->job_state() != JOBSTATE_COMPLETED) {

-      cur_job_->set_job_observer(this);

-      HRESULT hr = cur_job_->Install();

-

-      if (SUCCEEDED(hr)) {

-        if (!::IsEqualGUID(kGoopdateGuid, cur_job_->app_data().app_guid()) &&

-            strategy_->IsAutoUpdate()) {

-            ++metric_worker_app_updates_succeeded;

-        }

-      }

-

-      cur_job_->set_job_observer(NULL);

-      if (FAILED(hr)) {

-        cur_job_ = NULL;

-        CORE_LOG(LE, (_T("[InstallJob failed with 0x%08x]"), hr));

-        // The error is reported as necessary by Job::Install.

-        continue;

-      }

-    }

-    cur_job_ = NULL;

-  }

-

-  return S_OK;

-}

-

-void WorkerJob::CreateRequestFromProducts(

-    const ProductDataVector& products,

-    Request** request,

-    bool* encrypt_connection) {

-  CORE_LOG(L2, (_T("[WorkerJob::CreateRequestFromProducts]")));

-  ASSERT1(request);

-  ASSERT1(encrypt_connection);

-

-  *encrypt_connection = false;

-  scoped_ptr<Request> req(new Request(is_machine_));

-  for (size_t i = 0; i < products.size(); ++i) {

-    const ProductData& product_data = products[i];

-    if (!product_data.app_data().tt_token().IsEmpty()) {

-      *encrypt_connection = true;

-    }

-    AppRequestData app_request_data(product_data.app_data());

-    AppRequest app_request(app_request_data);

-    for (AppDataVector::const_iterator it = product_data.components_begin();

-         it != product_data.components_end();

-         ++it) {

-      AppRequestData component_request_data(*it);

-      app_request.AddComponentRequest(component_request_data);

-    }

-    req->AddAppRequest(app_request);

-  }

-  ASSERT1(products.size() == static_cast<size_t>(req->get_request_count()));

-

-  *request = req.release();

-}

-

-// If the job is interactive the job will notify the UI.

-// This method could be called multiple times, and thus needs to be idempotent.

-void WorkerJob::NotifyCompleted(JobCompletionStatus status,

-                                DWORD error,

-                                const CString& text,

-                                const ProductDataVector& products) {

-  CORE_LOG(L2, (_T("[WorkerJob::NotifyCompleted][%d][0x%08x]"), status, error));

-  ASSERT1(IsCompletionStatusSuccess(status) || !text.IsEmpty());

-

-  if (IsCompletionStatusSuccess(status)) {

-    ASSERT1(S_OK == error);

-    error_code_ = S_OK;

-  } else {

-    error_code_ = error;

-    ASSERT1(FAILED(error_code_));

-    if (SUCCEEDED(error_code_)) {

-      error_code_ = E_FAIL;

-    }

-  }

-

-  CompletionInfo info(status, error, text);

-  if (jobs_.empty()) {

-    if (job_observer_) {

-      job_observer_->OnComplete(IsCompletionStatusSuccess(status) ?

-                                    COMPLETION_CODE_SUCCESS :

-                                    COMPLETION_CODE_ERROR,

-                                text,

-                                error);

-      if (!no_jobs_completed_ping_sent_) {

-        const bool is_update = strategy_->IsUpdate();

-

-        // This is a pretty big assumption, unfortunately hard to enforce in

-        // the code: since the jobs are empty, it means that the server did

-        // not respond with updates available. In the case of silent and

-        // on demand updates, this is a not an error. There is no need to send

-        // a completion ping in this case.

-        if (is_update &&

-            IsCompletionStatusSuccess(status) &&

-            error == NOERROR) {

-          return;

-        }

-

-        no_jobs_completed_ping_sent_ = true;

-        HRESULT hr = ping_utils::SendCompletedPingsForAllProducts(

-            products,

-            is_machine_,

-            is_update,

-            info,

-            ping_.get());

-        if (FAILED(hr)) {

-          CORE_LOG(LW, (_T("[SendCompletedPingsForAllProducts failed][0x%08x]"),

-                        hr));

-        }

-      }

-    }

-

-    return;

-  }

-

-  // cur_job_->NotifyCompleted will eventually bubble back up to

-  // WorkerJob::OnCompleted which will complete the rest of the jobs.

-  if (cur_job_) {

-    cur_job_->NotifyCompleted(info);

-  } else {

-    // If there is no current job, and we are being asked to complete, then we

-    // set the primary application as the current job and complete it.

-    ASSERT1(!jobs_.empty());

-    cur_job_ = jobs_[0];

-    cur_job_->set_job_observer(this);

-    cur_job_->NotifyCompleted(info);

-    cur_job_->set_job_observer(NULL);

-    cur_job_ = NULL;

-  }

-}

-

-// Does the following:

-// * Performs some pre-processing on the AppData.

-// * Converts Job to Request.

-// * Converts Request into a post string.

-// * Sends the post.

-// * Parses the response.

-// * Saves the result inside the job.

-// * Performs post-processing on the AppData.

-HRESULT WorkerJob::DoUpdateCheck(const ProductDataVector& products) {

-  CORE_LOG(L2, (_T("[WorkerJob::DoUpdateCheck]")));

-

-  if (!ConfigManager::Instance()->CanUseNetwork(is_machine_)) {

-    CORE_LOG(L1, (_T("[Update check failed because network use prohibited]")));

-    return GOOPDATE_E_CANNOT_USE_NETWORK;

-  }

-

-  const bool use_update_metrics = strategy_->IsUpdate();

-

-  if (use_update_metrics) {

-    ++metric_worker_update_check_total;

-  }

-

-  // Google Update setup has completed if necessary before this point.

-  // This binary's version should be the installed version.

-  CString installed_version;

-  ASSERT1(SUCCEEDED(RegKey::GetValue(

-      ConfigManager::Instance()->registry_update(is_machine_),

-      kRegValueInstalledVersion,

-      &installed_version)));

-  ASSERT1(GetVersionString() == installed_version);

-

-  ASSERT1(!products.empty());

-

-  // Notify the UI that we've started.

-  OnCheckingForUpdate();

-

-  Request* request = NULL;

-  bool encrypt_connection = false;

-  CreateRequestFromProducts(products, &request, &encrypt_connection);

-  ASSERT1(request);

-  scoped_ptr<Request> req(request);

-

-  // Serialize the request.

-  // TODO(omaha): the request string can be serialized as UTF-8 to avoid

-  // additional copying of the request buffer when sending.

-  CString request_string;

-  HRESULT hr = GoopdateXmlParser::GenerateRequest(*req.get(),

-                                                  true,

-                                                  &request_string);

-  if (FAILED(hr)) {

-    CString msg;

-    msg.FormatMessage(IDS_INSTALL_FAILED, hr);

-    NotifyCompleted(COMPLETION_ERROR, hr, msg, products);

-    return hr;

-  }

-  ASSERT1(!request_string.IsEmpty());

-

-  // Get the url to send to.

-  CString update_url;

-  hr = ConfigManager::Instance()->GetUpdateCheckUrl(&update_url);

-  if (FAILED(hr)) {

-    CString msg;

-    msg.FormatMessage(IDS_INSTALL_FAILED, hr);

-    NotifyCompleted(COMPLETION_ERROR, hr, msg, products);

-    return hr;

-  }

-

-  if (is_canceled_) {

-    return GOOPDATE_E_WORKER_CANCELLED;

-  }

-

-  // Send the network request.

-  CORE_LOG(L2, (_T("[Sending update check...]")));

-  std::vector<uint8> response_buffer;

-  NetworkRequest* network_request = encrypt_connection ?

-                                    network_request_encrypted_.get() :

-                                    network_request_.get();

-  ASSERT1(network_request);

-  hr = network_request->PostString(update_url,

-                                   request_string,

-                                   &response_buffer);

-  if (hr == OMAHA_NET_E_REQUEST_CANCELLED) {

-    return hr;

-  }

-  if (FAILED(hr)) {

-    goopdate_utils::AddNetworkRequestDataToEventLog(network_request, hr);

-

-    if (strategy_->ShouldLaunchBrowserOnUpdateCheckError()) {

-      const TCHAR* const kUpdateCheckSourceId = _T("updatecheck");

-      CString url;

-      HRESULT hres = goopdate_utils::BuildHttpGetString(

-          kUrlMoreInformation,

-          hr,

-          0,

-          0,

-          GuidToString(products[0].app_data().app_guid()),

-          running_version_,

-          is_machine_,

-          strategy_->language(),

-          kUpdateCheckSourceId,

-          &url);

-      if (SUCCEEDED(hres)) {

-        VERIFY1(SUCCEEDED(goopdate_utils::LaunchBrowser(BROWSER_DEFAULT, url)));

-      } else {

-        CORE_LOG(LW, (_T("[BuildHttpGetString failed][0x%08x]"), hres));

-      }

-    }

-

-    CString msg;

-    // Ignore the return value because the default message is what we want.

-    goopdate_utils::FormatMessageForNetworkError(

-          hr,

-          products[0].app_data().display_name(),

-          &msg);

-

-    NotifyCompleted(COMPLETION_ERROR, hr, msg, products);

-    return hr;

-  }

-  ASSERT1(network_request->http_status_code() == HTTP_STATUS_OK);

-

-  // Parse the response.

-  CString response(Utf8BufferToWideChar(response_buffer));

-  CORE_LOG(L2, (_T("[Parse update check][%s]"), response));

-  UpdateResponses responses;

-  hr = GoopdateXmlParser::ParseManifestString(response, &responses);

-  if (FAILED(hr)) {

-    CString msg;

-    msg.FormatMessage(IDS_INSTALL_FAILED, hr);

-    NotifyCompleted(COMPLETION_ERROR, hr, msg, products);

-    return hr;

-  }

-  ASSERT1(static_cast<size_t>(req->get_request_count()) == responses.size());

-

-  hr = CreateJobs(false, responses, products);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (use_update_metrics) {

-    ++metric_worker_update_check_succeeded;

-  }

-  return S_OK;

-}

-

-HRESULT WorkerJob::CreateJobs(bool is_offline,

-                              const UpdateResponses& responses,

-                              const ProductDataVector& products) {

-  ASSERT1(!products.empty());

-  ASSERT1(is_offline == responses.empty());

-

-  CString event_log_text;

-  Request ping_request(is_machine_);

-  JobCreator job_creator(is_machine_, strategy_->IsUpdate(), ping_.get());

-  job_creator.set_is_auto_update(strategy_->IsAutoUpdate());

-  job_creator.set_is_update_check_only(strategy_->IsUpdateCheckOnly());

-  job_creator.set_fail_if_update_not_available(

-      strategy_->ShouldFailOnUpdateNotAvailable());

-  CompletionInfo completion_info;

-

-  HRESULT hr(S_OK);

-  if (is_offline) {

-    CString offline_dir =

-        is_machine_ ?

-        ConfigManager::Instance()->GetMachineSecureOfflineStorageDir() :

-        ConfigManager::Instance()->GetUserOfflineStorageDir();

-    hr = job_creator.CreateOfflineJobs(offline_dir,

-                                       products,

-                                       &jobs_,

-                                       &ping_request,

-                                       &event_log_text,

-                                       &completion_info);

-  } else {

-    hr = job_creator.CreateJobsFromResponses(responses,

-                                             products,

-                                             &jobs_,

-                                             &ping_request,

-                                             &event_log_text,

-                                             &completion_info);

-  }

-

-  WriteUpdateCheckEvent(is_machine_, hr, event_log_text);

-

-  // Send ping_request to the server to report results of job creation.

-  if (ping_request.get_request_count() > 0) {

-    ping_->SendPing(&ping_request);

-  }

-

-  if (FAILED(hr)) {

-    NotifyCompleted(completion_info.status,

-                    completion_info.error_code,

-                    completion_info.text,

-                    products);

-    return hr;

-  }

-

-  for (size_t i = 0; i < jobs_.size(); ++i) {

-    OnUpdateAvailable(jobs_[i]->response_data().version());

-  }

-

-  return S_OK;

-}

-

-HRESULT WorkerJob::CreateOfflineJobs(const ProductDataVector& products) {

-  CORE_LOG(L2, (_T("[WorkerJob::CreateOfflineJobs]")));

-  UpdateResponses responses;

-  return CreateJobs(true, responses, products);

-}

-

-// ::InterlockedExchange is used to have a memory barrier and flush the caches.

-HRESULT WorkerJob::Cancel() {

-  CORE_LOG(L2, (_T("[WorkerJob::Cancel]")));

-  ASSERT1(ping_.get());

-  ::InterlockedExchange(&is_canceled_, true);

-

-  VERIFY1(SUCCEEDED(network_request_->Cancel()));

-  VERIFY1(SUCCEEDED(network_request_encrypted_->Cancel()));

-  VERIFY1(SUCCEEDED(download_manager_->Cancel()));

-  VERIFY1(SUCCEEDED(ping_->Cancel()));

-  return S_OK;

-}

-

-void WorkerJob::CompleteAllNonCompletedJobs(JobCompletionStatus status,

-                                            DWORD error,

-                                            const CString& text) {

-  CORE_LOG(L2, (_T("[WorkerJob::CompleteAllNonCompletedJobs]")));

-  CompletionInfo info(status, error, text);

-  for (size_t i = 0; i < jobs_.size(); ++i) {

-    Job* job = jobs_[i];

-    ASSERT1(job);

-

-    if (cur_job_ != job && job->job_state() != JOBSTATE_COMPLETED) {

-      job->NotifyCompleted(info);

-    }

-  }

-}

-

-// Observer interface implementation.

-void WorkerJob::OnShow() {

-  CORE_LOG(L2, (_T("[WorkerJob::OnShow]")));

-  if (job_observer_) {

-    job_observer_->OnShow();

-  }

-}

-

-void WorkerJob::OnCheckingForUpdate() {

-  CORE_LOG(L2, (_T("[WorkerJob::OnCheckingForUpdate]")));

-  if (job_observer_) {

-    job_observer_->OnCheckingForUpdate();

-  }

-}

-

-void WorkerJob::OnUpdateAvailable(const TCHAR* version_string) {

-  CORE_LOG(L2, (_T("[WorkerJob::OnUpdateAvailable]")));

-  if (job_observer_) {

-    job_observer_->OnUpdateAvailable(version_string);

-  }

-}

-

-void WorkerJob::OnWaitingToDownload() {

-  CORE_LOG(L2, (_T("[WorkerJob::OnWaitingToDownload]")));

-  if (job_observer_) {

-    job_observer_->OnWaitingToDownload();

-  }

-}

-

-void WorkerJob::OnDownloading(int time_remaining_ms, int pos) {

-  CORE_LOG(L2, (_T("[WorkerJob::OnDownloading %d %d]"),

-                time_remaining_ms, pos));

-  UNREFERENCED_PARAMETER(pos);

-  ASSERT1(cur_job_);

-

-  int bytes_dl = bundle_bytes_downloaded_ + cur_job_->bytes_downloaded();

-  ASSERT1(bytes_dl <= bundle_dl_size_);

-  if (cur_job_->bytes_total() != 0) {

-    int expected_pos = static_cast<int>((

-        static_cast<double>(cur_job_->bytes_downloaded()) /

-         cur_job_->bytes_total()) * 100);

-    ASSERT1(expected_pos == pos);

-  }

-

-  int total_pos = 0;

-  if (bundle_dl_size_) {

-    total_pos = static_cast<int>((static_cast<float>(bytes_dl) /

-                                              bundle_dl_size_) * 100);

-  }

-

-  if (job_observer_) {

-    job_observer_->OnDownloading(time_remaining_ms, total_pos);

-  }

-}

-

-void WorkerJob::OnWaitingToInstall() {

-  CORE_LOG(L2, (_T("[WorkerJob::OnWaitingToInstall]")));

-  ASSERT1(cur_job_);

-  bundle_bytes_downloaded_ += cur_job_->response_data().size();

-

-  // We switch over to waiting for install only when all jobs are downloaded.

-  if (cur_job_ == jobs_.back() && job_observer_) {

-    job_observer_->OnWaitingToInstall();

-  }

-}

-

-void WorkerJob::OnInstalling() {

-  CORE_LOG(L2, (_T("[WorkerJob::OnInstalling]")));

-  ASSERT1(cur_job_);

-

-  if (cur_job_ == jobs_.back() && job_observer_) {

-    job_observer_->OnInstalling();

-  }

-}

-

-void WorkerJob::OnPause() {

-  CORE_LOG(L2, (_T("[WorkerJob::OnPause]")));

-  ASSERT1(cur_job_);

-

-  if (cur_job_ == jobs_.front() && job_observer_) {

-    job_observer_->OnPause();

-  }

-}

-

-void WorkerJob::OnComplete(CompletionCodes code,

-                           const TCHAR* text,

-                           DWORD error_code) {

-  CORE_LOG(L2, (_T("[WorkerJob::OnComplete][%d][0x%08x]"), code, error_code));

-  ASSERT1(cur_job_);

-  ASSERT1(!jobs_.empty());

-

-  if (code == COMPLETION_CODE_ERROR) {

-    if (IsCompletionInstallerError(cur_job_->info())) {

-      error_code_ = GOOPDATEINSTALL_E_INSTALLER_FAILED;

-    } else {

-      error_code_ = error_code;

-    }

-

-    ASSERT1(FAILED(error_code_));

-    if (SUCCEEDED(error_code_)) {

-      error_code_ = E_FAIL;

-    }

-  } else {

-    error_code_ = S_OK;

-  }

-

-  if (strategy_->IsAutoUpdate()) {

-    // TODO(Omaha): Refactor this code for bundles etc. Maybe move to strategy.

-    return;

-  }

-

-  Job* primary_job = jobs_[0];

-  ASSERT1(primary_job);

-

-  if (code == COMPLETION_CODE_ERROR) {

-    CString msg = text;

-    if (primary_job != cur_job_) {

-      // If there is an error because of a non-primary job,

-      // we need to change the error message to reflect this.

-      msg.FormatMessage(IDS_BUNDLE_INSTALL_FAILED,

-                        cur_job_->app_data().display_name(),

-                        text);

-    }

-    if (job_observer_) {

-      job_observer_->OnComplete(code, msg, error_code);

-    }

-

-    // We need to complete all the other jobs in the bundle, since one of the

-    // jobs failed. The jobs that have completed thus far, will not be

-    // altered, however the jobs from this point on will be completed with

-    // COMPLETION_ERROR.

-    CompleteAllNonCompletedJobs(COMPLETION_ERROR,

-                                static_cast<DWORD>(GOOPDATE_E_BUNDLE_ERROR),

-                                msg);

-

-    return;

-  }

-

-  if (cur_job_ == primary_job && job_observer_) {

-    // If we are dealing with the primary application and the result is a

-    // success we need to complete the UI.

-    job_observer_->OnComplete(code, text, error_code);

-  }

-}

-

-void WorkerJob::SetEventSink(ProgressWndEvents* event_sink) {

-  CORE_LOG(L2, (_T("[WorkerJob::SetEventSink]")));

-  UNREFERENCED_PARAMETER(event_sink);

-  return;

-}

-

-// ProgressWndEvents implementation.

-void WorkerJob::DoPause() {

-  ASSERT(false, (_T("Pause is not currently supported")));

-}

-

-void WorkerJob::DoResume() {

-  ASSERT(false, (_T("Pause is not currently supported")));

-}

-

-void WorkerJob::DoClose() {

-  CORE_LOG(L2, (_T("[WorkerJob::DoClose]")));

-  Cancel();

-}

-

-void WorkerJob::DoRestartBrowsers() {

-  CORE_LOG(L2, (_T("[WorkerJob::DoRestartBrowsers]")));

-  ASSERT1(!jobs_.empty());

-  Job* primary_job = jobs_[0];

-  ASSERT1(primary_job);

-  primary_job->RestartBrowsers();

-}

-

-void WorkerJob::DoReboot() {

-  ASSERT(false, (_T("Reboot is not currently supported")));

-}

-

-void WorkerJob::DoLaunchBrowser(const CString& url) {

-  CORE_LOG(L2, (_T("[WorkerJob::DoLaunchBrowser %s]"), url));

-  if (jobs_.empty()) {

-    VERIFY1(SUCCEEDED(goopdate_utils::LaunchBrowser(BROWSER_DEFAULT, url)));

-  } else {

-    Job* primary_job = jobs_[0];

-    ASSERT1(primary_job);

-    primary_job->LaunchBrowser(url);

-  }

-}

-

-// job_observer can be NULL.

-WorkerJob* WorkerJobFactory::CreateWorkerJob(bool is_machine,

-                                             const CommandLineArgs& args,

-                                             JobObserver* job_observer) {

-  WorkerJobStrategy* strategy(NULL);

-#pragma warning(push)

-// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by

-// a case label.

-#pragma warning(disable : 4061)

-

-  switch (args.mode) {

-    case COMMANDLINE_MODE_IG:

-    case COMMANDLINE_MODE_HANDOFF_INSTALL:

-      strategy = WorkerJobStrategyFactory::CreateInstallStrategy(is_machine,

-                                                                 args,

-                                                                 job_observer);

-      break;

-    case COMMANDLINE_MODE_UA:

-      strategy =

-          WorkerJobStrategyFactory::CreateUpdateAppsStrategy(is_machine, args);

-      break;

-    default:

-      ASSERT(false, (_T("Invalid mode for a WorkerJob.")));

-  }

-

-#pragma warning(pop)

-

-  return new WorkerJob(strategy, job_observer);

-}

-

-HRESULT WorkerJobFactory::CreateOnDemandWorkerJob(

-    bool is_machine,

-    bool is_update_check_only,

-    const CString& lang,

-    const GUID& guid,

-    IJobObserver* observer,

-    WorkerComWrapperShutdownCallBack* call_back,

-    WorkerJob** worker_job) {

-  ASSERT1(observer);

-  ASSERT1(call_back);

-  ASSERT1(worker_job);

-  *worker_job = NULL;

-

-  scoped_ptr<OnDemandUpdateStrategy> strategy;

-  strategy.reset(WorkerJobStrategyFactory::CreateOnDemandStrategy(

-      is_update_check_only,

-      lang,

-      is_machine));

-

-  // TODO(omaha): Should all the stuff in Init really be in this class?

-  HRESULT hr = strategy->Init(guid, observer, call_back);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  *worker_job = new WorkerJob(strategy.release(), strategy->GetJobObserver());

-  return S_OK;

-}

-

-}  // namespace omaha

-

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+//
+// TODO(omaha): The jobs are not being moved to the completed state in the
+// cancel/shutdown case.
+// Should be able to ASSERT1(job->job_state() == COMPLETED) in the worker
+// destructor.
+#include "omaha/worker/worker_job.h"
+
+#include <windows.h>
+#include <atlcom.h>
+#include <cstring>
+#include <vector>
+#include "omaha/common/const_addresses.h"
+#include "omaha/common/const_object_names.h"
+#include "omaha/common/constants.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/common/sta_call.h"
+#include "omaha/common/string.h"
+#include "omaha/common/user_info.h"
+#include "omaha/common/utils.h"
+#include "omaha/common/vista_utils.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/goopdate_xml_parser.h"
+#include "omaha/goopdate/request.h"
+#include "omaha/goopdate/resource.h"
+#include "omaha/goopdate/update_response_data.h"
+#include "omaha/net/browser_request.h"
+#include "omaha/net/cup_request.h"
+#include "omaha/net/network_request.h"
+#include "omaha/net/simple_request.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/application_manager.h"
+#include "omaha/worker/download_manager.h"
+#include "omaha/worker/install_manager.h"
+#include "omaha/worker/job.h"
+#include "omaha/worker/job_creator.h"
+#include "omaha/worker/ping.h"
+#include "omaha/worker/ping_utils.h"
+#include "omaha/worker/worker_event_logger.h"
+#include "omaha/worker/worker_job_strategy.h"
+#include "omaha/worker/worker_metrics.h"
+
+// Generated by MIDL in the "BUILD_MODE.OBJ_ROOT + SETTINGS.SUBDIR".
+#include "goopdate/google_update_idl.h"
+
+namespace omaha {
+
+// job_observer can be NULL.
+WorkerJob::WorkerJob(WorkerJobStrategy* strategy, JobObserver* job_observer)
+    : is_canceled_(false),
+      cur_job_(NULL),
+      bundle_dl_size_(0),
+      bundle_bytes_downloaded_(0),
+      job_observer_(job_observer),
+      no_jobs_completed_ping_sent_(false),
+      error_code_(S_OK) {
+  CORE_LOG(L2, (_T("[WorkerJob::WorkerJob]")));
+  ASSERT1(strategy);
+  strategy_.reset(strategy);
+  strategy_->set_worker_job(this);
+
+  is_machine_ = strategy_->is_machine();
+  running_version_  = GetVersionString();
+
+  const NetworkConfig::Session& session(NetworkConfig::Instance().session());
+
+  // The network request used by the update checks that do not require
+  // encryption.
+  network_request_.reset(new NetworkRequest(session));
+  network_request_->AddHttpRequest(new CupRequest(new SimpleRequest));
+  network_request_->AddHttpRequest(new SimpleRequest);
+  network_request_->AddHttpRequest(new CupRequest(new BrowserRequest));
+  network_request_->set_num_retries(1);
+
+  // The network request used by the encrypted update checks. For trusted tester
+  // update requests, because the TT token is a secret but is sent in the clear,
+  // we need https.
+  network_request_encrypted_.reset(new NetworkRequest(session));
+  network_request_encrypted_->AddHttpRequest(new SimpleRequest);
+  network_request_encrypted_->AddHttpRequest(new BrowserRequest);
+  network_request_encrypted_->set_num_retries(1);
+
+  // TODO(omaha): consider providing a download directory where file is
+  // to be downloaded. This directory should be know very early during the
+  // execution of the program and transmited as a parameter to DownloadManager.
+  download_manager_.reset(new DownloadManager(is_machine_));
+  download_manager_->set_impersonation_token(session.impersonation_token);
+
+  ping_.reset(new Ping());
+}
+
+WorkerJob::~WorkerJob() {
+  CORE_LOG(L2, (_T("[WorkerJob::~WorkerJob]")));
+  for (size_t i = 0; i < jobs_.size(); ++i) {
+    delete jobs_[i];
+  }
+}
+
+HRESULT BuildUninstallPing(bool is_machine, Request** uninstall_ping) {
+  CORE_LOG(L2, (_T("[BuildUninstallPing]")));
+  ASSERT1(uninstall_ping);
+
+  AppManager app_manager(is_machine);
+  ProductDataVector products;
+  HRESULT hr = app_manager.GetUnRegisteredProducts(&products);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[GetUnRegisteredProducts failed 0x%08x]"), hr));
+    return hr;
+  }
+
+  scoped_ptr<Request> request(new Request(is_machine));
+  for (size_t i = 0; i < products.size(); ++i) {
+    ProductData& product_data = products[i];
+    ASSERT1(product_data.app_data().is_uninstalled());
+
+    CORE_LOG(L2, (_T("[found uninstalled product][parent %s][app guid %s]"),
+                  GuidToString(product_data.app_data().parent_app_guid()),
+                  GuidToString(product_data.app_data().app_guid())));
+
+    // TODO(omaha): Do we have uninstall pings for components?
+    AppRequestData app_request_data(product_data.app_data());
+    PingEvent ping_event(PingEvent::EVENT_UNINSTALL,
+                         PingEvent::EVENT_RESULT_SUCCESS,
+                         0,  // error code
+                         0,  // extra code 1
+                         product_data.app_data().previous_version());
+    app_request_data.AddPingEvent(ping_event);
+    AppRequest app_request(app_request_data);
+    request->AddAppRequest(app_request);
+
+    VERIFY1(SUCCEEDED(app_manager.RemoveClientState(product_data.app_data())));
+  }
+
+  *uninstall_ping = request.release();
+  return S_OK;
+}
+
+HRESULT WorkerJob::DoProcess() {
+  CORE_LOG(L2, (_T("[WorkerJob::DoProcess]")));
+
+  ProductDataVector products;
+  HRESULT hr = DoProcessInternal(&products);
+
+  if (FAILED(hr)) {
+    CString msg;
+    switch (hr) {
+      case GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY:
+        ASSERT1(!strategy_->first_disallowed_app_name().IsEmpty());
+        msg.FormatMessage(IDS_APP_INSTALL_DISABLED_BY_GROUP_POLICY,
+                          strategy_->first_disallowed_app_name());
+        break;
+
+      case GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY:
+      case GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED:
+      default:
+        msg.FormatMessage(IDS_INSTALL_FAILED, hr);
+        break;
+    }
+    ASSERT1(!msg.IsEmpty());
+    JobCompletionStatus status = (hr == GOOPDATE_E_WORKER_CANCELLED) ?
+                                 COMPLETION_CANCELLED :
+                                 COMPLETION_ERROR;
+    NotifyCompleted(status, hr, msg, products);
+  }
+
+  return hr;
+}
+
+HRESULT WorkerJob::DoProcessInternal(ProductDataVector* products) {
+  CORE_LOG(L2, (_T("[WorkerJob::DoProcessInternal]")));
+  ASSERT1(products);
+  ASSERT1(strategy_.get());
+
+  scoped_co_init init_com_apt(COINIT_MULTITHREADED);
+  HRESULT hr(init_com_apt.hresult());
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[init_com_apt failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (job_observer_) {
+    job_observer_->SetEventSink(this);
+    job_observer_->OnShow();
+  }
+
+  hr = strategy_->PreUpdateCheck(products);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[PreUpdateCheck failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  if (products->empty()) {
+    OPT_LOG(L1, (_T("[No products to check updates for. Exiting.]")));
+    // We should always have products in all cases except for updates.
+    ASSERT1(strategy_->IsAutoUpdate());
+    NotifyCompleted(COMPLETION_SUCCESS, S_OK, _T("No products!"), *products);
+    return S_OK;
+  }
+
+  hr = strategy_->RemoveDisallowedApps(products);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[RemoveDisallowedApps failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = strategy_->DoUpdateCheck(*products);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[DoUpdateCheck failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = strategy_->PostUpdateCheck();
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[PostUpdateCheck failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  hr = strategy_->ProcessApps();
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[ProcessApps failed][0x%08x]"), hr));
+    return hr;
+  }
+
+  return strategy_->PostInstall();
+}
+
+int WorkerJob::CalculateBundleSize() const {
+  CORE_LOG(L2, (_T("[WorkerJob::CalculateBundleSize]")));
+  int bundle_dl_size = 0;
+  for (size_t i = 0; i < jobs_.size(); ++i) {
+    bundle_dl_size += jobs_[i]->response_data().size();
+  }
+  return bundle_dl_size;
+}
+
+HRESULT WorkerJob::DownloadJobs() {
+  CORE_LOG(L2, (_T("[WorkerJob::DownloadJobs]")));
+  bundle_dl_size_ = CalculateBundleSize();
+
+  // Download all jobs.
+  for (size_t i = 0; i < jobs_.size(); ++i) {
+    if (is_canceled_) {
+      return GOOPDATE_E_WORKER_CANCELLED;
+    }
+
+    cur_job_ = jobs_[i];
+    ASSERT1(cur_job_);
+
+    if (cur_job_->job_state() != JOBSTATE_COMPLETED) {
+      cur_job_->set_job_observer(this);
+      HRESULT hr = cur_job_->Download(download_manager_.get());
+      cur_job_->set_job_observer(NULL);
+      cur_job_ = NULL;
+      if (FAILED(hr)) {
+        CORE_LOG(LE, (_T("[DownloadJob failed with 0x%08x]"), hr));
+        continue;
+      }
+    }
+
+    cur_job_ = NULL;
+  }
+
+  return S_OK;
+}
+
+HRESULT WorkerJob::InstallJobs() {
+  CORE_LOG(L2, (_T("[WorkerJob::InstallJobs]")));
+  // Install all jobs. We install the jobs in the reverse order, since we want
+  // the primary job, which is the first in the list to be installed last.
+  // The primary job can then perform user visible actions such as start
+  // the application.
+  Jobs::reverse_iterator iter = jobs_.rbegin();
+  for (; iter != jobs_.rend(); ++iter) {
+    if (is_canceled_) {
+      return GOOPDATE_E_WORKER_CANCELLED;
+    }
+
+    cur_job_ = *iter;
+    ASSERT1(cur_job_);
+
+    if (cur_job_->job_state() != JOBSTATE_COMPLETED) {
+      cur_job_->set_job_observer(this);
+      HRESULT hr = cur_job_->Install();
+
+      if (SUCCEEDED(hr)) {
+        if (!::IsEqualGUID(kGoopdateGuid, cur_job_->app_data().app_guid()) &&
+            strategy_->IsAutoUpdate()) {
+            ++metric_worker_app_updates_succeeded;
+        }
+      }
+
+      cur_job_->set_job_observer(NULL);
+      if (FAILED(hr)) {
+        cur_job_ = NULL;
+        CORE_LOG(LE, (_T("[InstallJob failed with 0x%08x]"), hr));
+        // The error is reported as necessary by Job::Install.
+        continue;
+      }
+    }
+    cur_job_ = NULL;
+  }
+
+  return S_OK;
+}
+
+void WorkerJob::CreateRequestFromProducts(
+    const ProductDataVector& products,
+    Request** request,
+    bool* encrypt_connection) {
+  CORE_LOG(L2, (_T("[WorkerJob::CreateRequestFromProducts]")));
+  ASSERT1(request);
+  ASSERT1(encrypt_connection);
+
+  *encrypt_connection = false;
+  scoped_ptr<Request> req(new Request(is_machine_));
+  for (size_t i = 0; i < products.size(); ++i) {
+    const ProductData& product_data = products[i];
+    if (!product_data.app_data().tt_token().IsEmpty()) {
+      *encrypt_connection = true;
+    }
+    AppRequestData app_request_data(product_data.app_data());
+    AppRequest app_request(app_request_data);
+    for (AppDataVector::const_iterator it = product_data.components_begin();
+         it != product_data.components_end();
+         ++it) {
+      AppRequestData component_request_data(*it);
+      app_request.AddComponentRequest(component_request_data);
+    }
+    req->AddAppRequest(app_request);
+  }
+  ASSERT1(products.size() == static_cast<size_t>(req->get_request_count()));
+
+  *request = req.release();
+}
+
+// If the job is interactive the job will notify the UI.
+// This method could be called multiple times, and thus needs to be idempotent.
+void WorkerJob::NotifyCompleted(JobCompletionStatus status,
+                                DWORD error,
+                                const CString& text,
+                                const ProductDataVector& products) {
+  CORE_LOG(L2, (_T("[WorkerJob::NotifyCompleted][%d][0x%08x]"), status, error));
+  ASSERT1(IsCompletionStatusSuccess(status) || !text.IsEmpty());
+
+  if (IsCompletionStatusSuccess(status)) {
+    ASSERT1(S_OK == error);
+    error_code_ = S_OK;
+  } else {
+    error_code_ = error;
+    ASSERT1(FAILED(error_code_));
+    if (SUCCEEDED(error_code_)) {
+      error_code_ = E_FAIL;
+    }
+  }
+
+  CompletionInfo info(status, error, text);
+  if (jobs_.empty()) {
+    if (job_observer_) {
+      job_observer_->OnComplete(IsCompletionStatusSuccess(status) ?
+                                    COMPLETION_CODE_SUCCESS :
+                                    COMPLETION_CODE_ERROR,
+                                text,
+                                error);
+      if (!no_jobs_completed_ping_sent_) {
+        const bool is_update = strategy_->IsUpdate();
+
+        // This is a pretty big assumption, unfortunately hard to enforce in
+        // the code: since the jobs are empty, it means that the server did
+        // not respond with updates available. In the case of silent and
+        // on demand updates, this is a not an error. There is no need to send
+        // a completion ping in this case.
+        if (is_update &&
+            IsCompletionStatusSuccess(status) &&
+            error == NOERROR) {
+          return;
+        }
+
+        no_jobs_completed_ping_sent_ = true;
+        HRESULT hr = ping_utils::SendCompletedPingsForAllProducts(
+            products,
+            is_machine_,
+            is_update,
+            info,
+            ping_.get());
+        if (FAILED(hr)) {
+          CORE_LOG(LW, (_T("[SendCompletedPingsForAllProducts failed][0x%08x]"),
+                        hr));
+        }
+      }
+    }
+
+    return;
+  }
+
+  // cur_job_->NotifyCompleted will eventually bubble back up to
+  // WorkerJob::OnCompleted which will complete the rest of the jobs.
+  if (cur_job_) {
+    cur_job_->NotifyCompleted(info);
+  } else {
+    // If there is no current job, and we are being asked to complete, then we
+    // set the primary application as the current job and complete it.
+    ASSERT1(!jobs_.empty());
+    cur_job_ = jobs_[0];
+    cur_job_->set_job_observer(this);
+    cur_job_->NotifyCompleted(info);
+    cur_job_->set_job_observer(NULL);
+    cur_job_ = NULL;
+  }
+}
+
+// Does the following:
+// * Performs some pre-processing on the AppData.
+// * Converts Job to Request.
+// * Converts Request into a post string.
+// * Sends the post.
+// * Parses the response.
+// * Saves the result inside the job.
+// * Performs post-processing on the AppData.
+HRESULT WorkerJob::DoUpdateCheck(const ProductDataVector& products) {
+  CORE_LOG(L2, (_T("[WorkerJob::DoUpdateCheck]")));
+
+  if (!ConfigManager::Instance()->CanUseNetwork(is_machine_)) {
+    CORE_LOG(L1, (_T("[Update check failed because network use prohibited]")));
+    return GOOPDATE_E_CANNOT_USE_NETWORK;
+  }
+
+  const bool use_update_metrics = strategy_->IsUpdate();
+
+  if (use_update_metrics) {
+    ++metric_worker_update_check_total;
+  }
+
+  // Google Update setup has completed if necessary before this point.
+  // This binary's version should be the installed version.
+  CString installed_version;
+  ASSERT1(SUCCEEDED(RegKey::GetValue(
+      ConfigManager::Instance()->registry_update(is_machine_),
+      kRegValueInstalledVersion,
+      &installed_version)));
+  ASSERT1(GetVersionString() == installed_version);
+
+  ASSERT1(!products.empty());
+
+  // Notify the UI that we've started.
+  OnCheckingForUpdate();
+
+  Request* request = NULL;
+  bool encrypt_connection = false;
+  CreateRequestFromProducts(products, &request, &encrypt_connection);
+  ASSERT1(request);
+  scoped_ptr<Request> req(request);
+
+  // Serialize the request.
+  // TODO(omaha): the request string can be serialized as UTF-8 to avoid
+  // additional copying of the request buffer when sending.
+  CString request_string;
+  HRESULT hr = GoopdateXmlParser::GenerateRequest(*req.get(),
+                                                  true,
+                                                  &request_string);
+  if (FAILED(hr)) {
+    CString msg;
+    msg.FormatMessage(IDS_INSTALL_FAILED, hr);
+    NotifyCompleted(COMPLETION_ERROR, hr, msg, products);
+    return hr;
+  }
+  ASSERT1(!request_string.IsEmpty());
+
+  // Get the url to send to.
+  CString update_url;
+  hr = ConfigManager::Instance()->GetUpdateCheckUrl(&update_url);
+  if (FAILED(hr)) {
+    CString msg;
+    msg.FormatMessage(IDS_INSTALL_FAILED, hr);
+    NotifyCompleted(COMPLETION_ERROR, hr, msg, products);
+    return hr;
+  }
+
+  if (is_canceled_) {
+    return GOOPDATE_E_WORKER_CANCELLED;
+  }
+
+  // Send the network request.
+  CORE_LOG(L2, (_T("[Sending update check...]")));
+  std::vector<uint8> response_buffer;
+  NetworkRequest* network_request = encrypt_connection ?
+                                    network_request_encrypted_.get() :
+                                    network_request_.get();
+  ASSERT1(network_request);
+  hr = network_request->PostString(update_url,
+                                   request_string,
+                                   &response_buffer);
+  if (hr == OMAHA_NET_E_REQUEST_CANCELLED) {
+    return hr;
+  }
+  if (FAILED(hr)) {
+    goopdate_utils::AddNetworkRequestDataToEventLog(network_request, hr);
+
+    if (strategy_->ShouldLaunchBrowserOnUpdateCheckError()) {
+      const TCHAR* const kUpdateCheckSourceId = _T("updatecheck");
+      CString url;
+      HRESULT hres = goopdate_utils::BuildHttpGetString(
+          kUrlMoreInformation,
+          hr,
+          0,
+          0,
+          GuidToString(products[0].app_data().app_guid()),
+          running_version_,
+          is_machine_,
+          strategy_->language(),
+          kUpdateCheckSourceId,
+          &url);
+      if (SUCCEEDED(hres)) {
+        VERIFY1(SUCCEEDED(goopdate_utils::LaunchBrowser(BROWSER_DEFAULT, url)));
+      } else {
+        CORE_LOG(LW, (_T("[BuildHttpGetString failed][0x%08x]"), hres));
+      }
+    }
+
+    CString msg;
+    // Ignore the return value because the default message is what we want.
+    goopdate_utils::FormatMessageForNetworkError(
+          hr,
+          products[0].app_data().display_name(),
+          &msg);
+
+    NotifyCompleted(COMPLETION_ERROR, hr, msg, products);
+    return hr;
+  }
+  ASSERT1(network_request->http_status_code() == HTTP_STATUS_OK);
+
+  // Parse the response.
+  CString response(Utf8BufferToWideChar(response_buffer));
+  CORE_LOG(L2, (_T("[Parse update check][%s]"), response));
+  UpdateResponses responses;
+  hr = GoopdateXmlParser::ParseManifestString(response, &responses);
+  if (FAILED(hr)) {
+    CString msg;
+    msg.FormatMessage(IDS_INSTALL_FAILED, hr);
+    NotifyCompleted(COMPLETION_ERROR, hr, msg, products);
+    return hr;
+  }
+  ASSERT1(static_cast<size_t>(req->get_request_count()) == responses.size());
+
+  hr = CreateJobs(false, responses, products);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (use_update_metrics) {
+    ++metric_worker_update_check_succeeded;
+  }
+  return S_OK;
+}
+
+HRESULT WorkerJob::CreateJobs(bool is_offline,
+                              const UpdateResponses& responses,
+                              const ProductDataVector& products) {
+  ASSERT1(!products.empty());
+  ASSERT1(is_offline == responses.empty());
+
+  CString event_log_text;
+  Request ping_request(is_machine_);
+  JobCreator job_creator(is_machine_, strategy_->IsUpdate(), ping_.get());
+  job_creator.set_is_auto_update(strategy_->IsAutoUpdate());
+  job_creator.set_is_update_check_only(strategy_->IsUpdateCheckOnly());
+  job_creator.set_fail_if_update_not_available(
+      strategy_->ShouldFailOnUpdateNotAvailable());
+  CompletionInfo completion_info;
+
+  HRESULT hr(S_OK);
+  if (is_offline) {
+    CString offline_dir =
+        is_machine_ ?
+        ConfigManager::Instance()->GetMachineSecureOfflineStorageDir() :
+        ConfigManager::Instance()->GetUserOfflineStorageDir();
+    hr = job_creator.CreateOfflineJobs(offline_dir,
+                                       products,
+                                       &jobs_,
+                                       &ping_request,
+                                       &event_log_text,
+                                       &completion_info);
+  } else {
+    hr = job_creator.CreateJobsFromResponses(responses,
+                                             products,
+                                             &jobs_,
+                                             &ping_request,
+                                             &event_log_text,
+                                             &completion_info);
+  }
+
+  WriteUpdateCheckEvent(is_machine_, hr, event_log_text);
+
+  // Send ping_request to the server to report results of job creation.
+  if (ping_request.get_request_count() > 0) {
+    ping_->SendPing(&ping_request);
+  }
+
+  if (FAILED(hr)) {
+    NotifyCompleted(completion_info.status,
+                    completion_info.error_code,
+                    completion_info.text,
+                    products);
+    return hr;
+  }
+
+  for (size_t i = 0; i < jobs_.size(); ++i) {
+    OnUpdateAvailable(jobs_[i]->response_data().version());
+  }
+
+  return S_OK;
+}
+
+HRESULT WorkerJob::CreateOfflineJobs(const ProductDataVector& products) {
+  CORE_LOG(L2, (_T("[WorkerJob::CreateOfflineJobs]")));
+  UpdateResponses responses;
+  return CreateJobs(true, responses, products);
+}
+
+// ::InterlockedExchange is used to have a memory barrier and flush the caches.
+HRESULT WorkerJob::Cancel() {
+  CORE_LOG(L2, (_T("[WorkerJob::Cancel]")));
+  ASSERT1(ping_.get());
+  ::InterlockedExchange(&is_canceled_, true);
+
+  VERIFY1(SUCCEEDED(network_request_->Cancel()));
+  VERIFY1(SUCCEEDED(network_request_encrypted_->Cancel()));
+  VERIFY1(SUCCEEDED(download_manager_->Cancel()));
+  VERIFY1(SUCCEEDED(ping_->Cancel()));
+  return S_OK;
+}
+
+void WorkerJob::CompleteAllNonCompletedJobs(JobCompletionStatus status,
+                                            DWORD error,
+                                            const CString& text) {
+  CORE_LOG(L2, (_T("[WorkerJob::CompleteAllNonCompletedJobs]")));
+  CompletionInfo info(status, error, text);
+  for (size_t i = 0; i < jobs_.size(); ++i) {
+    Job* job = jobs_[i];
+    ASSERT1(job);
+
+    if (cur_job_ != job && job->job_state() != JOBSTATE_COMPLETED) {
+      job->NotifyCompleted(info);
+    }
+  }
+}
+
+// Observer interface implementation.
+void WorkerJob::OnShow() {
+  CORE_LOG(L2, (_T("[WorkerJob::OnShow]")));
+  if (job_observer_) {
+    job_observer_->OnShow();
+  }
+}
+
+void WorkerJob::OnCheckingForUpdate() {
+  CORE_LOG(L2, (_T("[WorkerJob::OnCheckingForUpdate]")));
+  if (job_observer_) {
+    job_observer_->OnCheckingForUpdate();
+  }
+}
+
+void WorkerJob::OnUpdateAvailable(const TCHAR* version_string) {
+  CORE_LOG(L2, (_T("[WorkerJob::OnUpdateAvailable]")));
+  if (job_observer_) {
+    job_observer_->OnUpdateAvailable(version_string);
+  }
+}
+
+void WorkerJob::OnWaitingToDownload() {
+  CORE_LOG(L2, (_T("[WorkerJob::OnWaitingToDownload]")));
+  if (job_observer_) {
+    job_observer_->OnWaitingToDownload();
+  }
+}
+
+void WorkerJob::OnDownloading(int time_remaining_ms, int pos) {
+  CORE_LOG(L2, (_T("[WorkerJob::OnDownloading %d %d]"),
+                time_remaining_ms, pos));
+  UNREFERENCED_PARAMETER(pos);
+  ASSERT1(cur_job_);
+
+  int bytes_dl = bundle_bytes_downloaded_ + cur_job_->bytes_downloaded();
+  ASSERT1(bytes_dl <= bundle_dl_size_);
+  if (cur_job_->bytes_total() != 0) {
+    int expected_pos = static_cast<int>((
+        static_cast<double>(cur_job_->bytes_downloaded()) /
+         cur_job_->bytes_total()) * 100);
+    ASSERT1(expected_pos == pos);
+  }
+
+  int total_pos = 0;
+  if (bundle_dl_size_) {
+    total_pos = static_cast<int>((static_cast<float>(bytes_dl) /
+                                              bundle_dl_size_) * 100);
+  }
+
+  if (job_observer_) {
+    job_observer_->OnDownloading(time_remaining_ms, total_pos);
+  }
+}
+
+void WorkerJob::OnWaitingToInstall() {
+  CORE_LOG(L2, (_T("[WorkerJob::OnWaitingToInstall]")));
+  ASSERT1(cur_job_);
+  bundle_bytes_downloaded_ += cur_job_->response_data().size();
+
+  // We switch over to waiting for install only when all jobs are downloaded.
+  if (cur_job_ == jobs_.back() && job_observer_) {
+    job_observer_->OnWaitingToInstall();
+  }
+}
+
+void WorkerJob::OnInstalling() {
+  CORE_LOG(L2, (_T("[WorkerJob::OnInstalling]")));
+  ASSERT1(cur_job_);
+
+  if (cur_job_ == jobs_.back() && job_observer_) {
+    job_observer_->OnInstalling();
+  }
+}
+
+void WorkerJob::OnPause() {
+  CORE_LOG(L2, (_T("[WorkerJob::OnPause]")));
+  ASSERT1(cur_job_);
+
+  if (cur_job_ == jobs_.front() && job_observer_) {
+    job_observer_->OnPause();
+  }
+}
+
+void WorkerJob::OnComplete(CompletionCodes code,
+                           const TCHAR* text,
+                           DWORD error_code) {
+  CORE_LOG(L2, (_T("[WorkerJob::OnComplete][%d][0x%08x]"), code, error_code));
+  ASSERT1(cur_job_);
+  ASSERT1(!jobs_.empty());
+
+  if (code == COMPLETION_CODE_ERROR) {
+    if (IsCompletionInstallerError(cur_job_->info())) {
+      error_code_ = GOOPDATEINSTALL_E_INSTALLER_FAILED;
+    } else {
+      error_code_ = error_code;
+    }
+
+    ASSERT1(FAILED(error_code_));
+    if (SUCCEEDED(error_code_)) {
+      error_code_ = E_FAIL;
+    }
+  } else {
+    error_code_ = S_OK;
+  }
+
+  if (strategy_->IsAutoUpdate()) {
+    // TODO(Omaha): Refactor this code for bundles etc. Maybe move to strategy.
+    return;
+  }
+
+  Job* primary_job = jobs_[0];
+  ASSERT1(primary_job);
+
+  if (code == COMPLETION_CODE_ERROR) {
+    CString msg = text;
+    if (primary_job != cur_job_) {
+      // If there is an error because of a non-primary job,
+      // we need to change the error message to reflect this.
+      msg.FormatMessage(IDS_BUNDLE_INSTALL_FAILED,
+                        cur_job_->app_data().display_name(),
+                        text);
+    }
+    if (job_observer_) {
+      job_observer_->OnComplete(code, msg, error_code);
+    }
+
+    // We need to complete all the other jobs in the bundle, since one of the
+    // jobs failed. The jobs that have completed thus far, will not be
+    // altered, however the jobs from this point on will be completed with
+    // COMPLETION_ERROR.
+    CompleteAllNonCompletedJobs(COMPLETION_ERROR,
+                                static_cast<DWORD>(GOOPDATE_E_BUNDLE_ERROR),
+                                msg);
+
+    return;
+  }
+
+  if (cur_job_ == primary_job && job_observer_) {
+    // If we are dealing with the primary application and the result is a
+    // success we need to complete the UI.
+    job_observer_->OnComplete(code, text, error_code);
+  }
+}
+
+void WorkerJob::SetEventSink(ProgressWndEvents* event_sink) {
+  CORE_LOG(L2, (_T("[WorkerJob::SetEventSink]")));
+  UNREFERENCED_PARAMETER(event_sink);
+  return;
+}
+
+// ProgressWndEvents implementation.
+void WorkerJob::DoPause() {
+  ASSERT(false, (_T("Pause is not currently supported")));
+}
+
+void WorkerJob::DoResume() {
+  ASSERT(false, (_T("Pause is not currently supported")));
+}
+
+void WorkerJob::DoClose() {
+  CORE_LOG(L2, (_T("[WorkerJob::DoClose]")));
+  Cancel();
+}
+
+void WorkerJob::DoRestartBrowsers() {
+  CORE_LOG(L2, (_T("[WorkerJob::DoRestartBrowsers]")));
+  ASSERT1(!jobs_.empty());
+  Job* primary_job = jobs_[0];
+  ASSERT1(primary_job);
+  primary_job->RestartBrowsers();
+}
+
+void WorkerJob::DoReboot() {
+  ASSERT(false, (_T("Reboot is not currently supported")));
+}
+
+void WorkerJob::DoLaunchBrowser(const CString& url) {
+  CORE_LOG(L2, (_T("[WorkerJob::DoLaunchBrowser %s]"), url));
+  if (jobs_.empty()) {
+    VERIFY1(SUCCEEDED(goopdate_utils::LaunchBrowser(BROWSER_DEFAULT, url)));
+  } else {
+    Job* primary_job = jobs_[0];
+    ASSERT1(primary_job);
+    primary_job->LaunchBrowser(url);
+  }
+}
+
+// job_observer can be NULL.
+WorkerJob* WorkerJobFactory::CreateWorkerJob(bool is_machine,
+                                             const CommandLineArgs& args,
+                                             JobObserver* job_observer) {
+  WorkerJobStrategy* strategy(NULL);
+#pragma warning(push)
+// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by
+// a case label.
+#pragma warning(disable : 4061)
+
+  switch (args.mode) {
+    case COMMANDLINE_MODE_IG:
+    case COMMANDLINE_MODE_HANDOFF_INSTALL:
+      strategy = WorkerJobStrategyFactory::CreateInstallStrategy(is_machine,
+                                                                 args,
+                                                                 job_observer);
+      break;
+    case COMMANDLINE_MODE_UA:
+      strategy =
+          WorkerJobStrategyFactory::CreateUpdateAppsStrategy(is_machine, args);
+      break;
+    default:
+      ASSERT(false, (_T("Invalid mode for a WorkerJob.")));
+  }
+
+#pragma warning(pop)
+
+  return new WorkerJob(strategy, job_observer);
+}
+
+HRESULT WorkerJobFactory::CreateOnDemandWorkerJob(
+    bool is_machine,
+    bool is_update_check_only,
+    const CString& lang,
+    const GUID& guid,
+    IJobObserver* observer,
+    WorkerComWrapperShutdownCallBack* call_back,
+    WorkerJob** worker_job) {
+  ASSERT1(observer);
+  ASSERT1(call_back);
+  ASSERT1(worker_job);
+  *worker_job = NULL;
+
+  scoped_ptr<OnDemandUpdateStrategy> strategy;
+  strategy.reset(WorkerJobStrategyFactory::CreateOnDemandStrategy(
+      is_update_check_only,
+      lang,
+      is_machine));
+
+  // TODO(omaha): Should all the stuff in Init really be in this class?
+  HRESULT hr = strategy->Init(guid, observer, call_back);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  *worker_job = new WorkerJob(strategy.release(), strategy->GetJobObserver());
+  return S_OK;
+}
+
+}  // namespace omaha
+
diff --git a/worker/worker_job.h b/worker/worker_job.h
index 2236d28..7bc7afb 100644
--- a/worker/worker_job.h
+++ b/worker/worker_job.h
@@ -1,164 +1,164 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#ifndef OMAHA_WORKER_WORKER_JOB_H__

-#define OMAHA_WORKER_WORKER_JOB_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include <vector>

-#include "base/basictypes.h"

-#include "base/scoped_ptr.h"

-#include "omaha/common/scoped_any.h"

-#include "omaha/goopdate/update_response.h"

-#include "omaha/worker/job.h"

-#include "omaha/worker/job_observer.h"

-

-namespace omaha {

-

-class AppData;

-class DownloadManager;

-class Ping;

-class Request;

-class WorkerJobStrategy;

-

-class WorkerJob : public JobObserver,

-                  public ProgressWndEvents {

- public:

-  explicit WorkerJob(WorkerJobStrategy* strategy, JobObserver* job_observer);

-  ~WorkerJob();

-  HRESULT DoProcess();

-  HRESULT Cancel();

-

-  Ping* ping() { return ping_.get(); }

-  bool is_machine() const { return is_machine_; }

-  const Jobs& jobs() const { return jobs_; }

-  WorkerJobStrategy* strategy() const { return strategy_.get(); }

-

-  // Observer interface.

-  virtual void OnShow();

-  virtual void OnCheckingForUpdate();

-  virtual void OnUpdateAvailable(const TCHAR* version_string);

-  virtual void OnWaitingToDownload();

-  virtual void OnDownloading(int time_remaining_ms, int pos);

-  virtual void OnWaitingToInstall();

-  virtual void OnInstalling();

-  virtual void OnPause();

-  virtual void OnComplete(CompletionCodes code,

-                          const TCHAR* text,

-                          DWORD error_code);

-  virtual void SetEventSink(ProgressWndEvents* event_sink);

-  virtual void Uninitialize() {}

-

-  // ProgressWndEvents implementation.

-  virtual void DoPause();

-  virtual void DoResume();

-  virtual void DoClose();

-  virtual void DoRestartBrowsers();

-  virtual void DoReboot();

-  virtual void DoLaunchBrowser(const CString& url);

-

-

-  // TODO(omaha): Consider making these methods private.

-  // The reason we need this bloated interface is because the strategies

-  // call into the workerjob that is treated as the context for the calls.

-  // One way to achieve this is to take in the workerjob in these methods

-  // and make them static non member methods.

-  HRESULT DownloadJobs();

-  HRESULT InstallJobs();

-  void NotifyCompleted(JobCompletionStatus status,

-                       DWORD error,

-                       const CString& text,

-                       const ProductDataVector& products);

-  void CompleteAllNonCompletedJobs(JobCompletionStatus status,

-                                   DWORD error,

-                                   const CString& text);

-  HRESULT DoUpdateCheck(const ProductDataVector& products);

-  HRESULT CreateOfflineJobs(const ProductDataVector& products);

-

-  HRESULT error_code() const { return error_code_; }

-

-  bool is_canceled() const { return !!is_canceled_; }

-

- private:

-  HRESULT CreateJobs(bool is_offline,

-                     const UpdateResponses& responses,

-                     const ProductDataVector& products);

-  HRESULT DoProcessInternal(ProductDataVector* products);

-

-  void UpdateResponseToCompletionInfo(const UpdateResponse& response,

-                                      CompletionInfo* info);

-

-  static bool IsUpdateAvailable(const UpdateResponse& response);

-  HRESULT CreateRequestFromApplications(const AppDataVector& applications,

-                                        Request** request);

-  void CreateRequestFromProducts(const ProductDataVector& products,

-                                 Request** request,

-                                 bool* encrypt_connection);

-

-  // Sets the UI displayed event, telling the other instance not to display an

-  // error UI.

-  void SetUiDisplayedEvent() const;

-

-  // Calculates the size of the download bundle.

-  int CalculateBundleSize() const;

-

-  Job* cur_job_;

-  int bundle_dl_size_;

-  int bundle_bytes_downloaded_;

-

-  bool is_machine_;

-  bool is_update_apps_worker_;

-  std::vector<Job*> jobs_;

-  scoped_ptr<NetworkRequest> network_request_;

-  scoped_ptr<NetworkRequest> network_request_encrypted_;

-  scoped_ptr<DownloadManager> download_manager_;

-  CString running_version_;

-  volatile LONG is_canceled_;

-  bool no_jobs_completed_ping_sent_;

-  scoped_ptr<Ping> ping_;

-  JobObserver* job_observer_;

-  scoped_ptr<WorkerJobStrategy> strategy_;

-  HRESULT error_code_;

-  friend class WorkerJobTest;

-

-  DISALLOW_EVIL_CONSTRUCTORS(WorkerJob);

-};

-

-class WorkerJobFactory {

- public:

-  static WorkerJob* CreateWorkerJob(bool is_machine,

-                                    const CommandLineArgs& args,

-                                    JobObserver* job_observer);

-

-  static HRESULT CreateOnDemandWorkerJob(

-      bool is_machine,

-      bool is_update_check_only,

-      const CString& lang,

-      const GUID& guid,

-      IJobObserver* observer,

-      WorkerComWrapperShutdownCallBack* call_back,

-      WorkerJob** worker_job);

-};

-

-// Creates a request containing the pings for the uninstalled products.

-// The caller has the ownership of the request object. Building the

-// uninstall ping is not an idempotent operation. The client state is

-// cleaned up after building the request.

-HRESULT BuildUninstallPing(bool is_machine, Request** uninstall_ping);

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_WORKER_JOB_H__

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#ifndef OMAHA_WORKER_WORKER_JOB_H__
+#define OMAHA_WORKER_WORKER_JOB_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/scoped_ptr.h"
+#include "omaha/common/scoped_any.h"
+#include "omaha/goopdate/update_response.h"
+#include "omaha/worker/job.h"
+#include "omaha/worker/job_observer.h"
+
+namespace omaha {
+
+class AppData;
+class DownloadManager;
+class Ping;
+class Request;
+class WorkerJobStrategy;
+
+class WorkerJob : public JobObserver,
+                  public ProgressWndEvents {
+ public:
+  explicit WorkerJob(WorkerJobStrategy* strategy, JobObserver* job_observer);
+  ~WorkerJob();
+  HRESULT DoProcess();
+  HRESULT Cancel();
+
+  Ping* ping() { return ping_.get(); }
+  bool is_machine() const { return is_machine_; }
+  const Jobs& jobs() const { return jobs_; }
+  WorkerJobStrategy* strategy() const { return strategy_.get(); }
+
+  // Observer interface.
+  virtual void OnShow();
+  virtual void OnCheckingForUpdate();
+  virtual void OnUpdateAvailable(const TCHAR* version_string);
+  virtual void OnWaitingToDownload();
+  virtual void OnDownloading(int time_remaining_ms, int pos);
+  virtual void OnWaitingToInstall();
+  virtual void OnInstalling();
+  virtual void OnPause();
+  virtual void OnComplete(CompletionCodes code,
+                          const TCHAR* text,
+                          DWORD error_code);
+  virtual void SetEventSink(ProgressWndEvents* event_sink);
+  virtual void Uninitialize() {}
+
+  // ProgressWndEvents implementation.
+  virtual void DoPause();
+  virtual void DoResume();
+  virtual void DoClose();
+  virtual void DoRestartBrowsers();
+  virtual void DoReboot();
+  virtual void DoLaunchBrowser(const CString& url);
+
+
+  // TODO(omaha): Consider making these methods private.
+  // The reason we need this bloated interface is because the strategies
+  // call into the workerjob that is treated as the context for the calls.
+  // One way to achieve this is to take in the workerjob in these methods
+  // and make them static non member methods.
+  HRESULT DownloadJobs();
+  HRESULT InstallJobs();
+  void NotifyCompleted(JobCompletionStatus status,
+                       DWORD error,
+                       const CString& text,
+                       const ProductDataVector& products);
+  void CompleteAllNonCompletedJobs(JobCompletionStatus status,
+                                   DWORD error,
+                                   const CString& text);
+  HRESULT DoUpdateCheck(const ProductDataVector& products);
+  HRESULT CreateOfflineJobs(const ProductDataVector& products);
+
+  HRESULT error_code() const { return error_code_; }
+
+  bool is_canceled() const { return !!is_canceled_; }
+
+ private:
+  HRESULT CreateJobs(bool is_offline,
+                     const UpdateResponses& responses,
+                     const ProductDataVector& products);
+  HRESULT DoProcessInternal(ProductDataVector* products);
+
+  void UpdateResponseToCompletionInfo(const UpdateResponse& response,
+                                      CompletionInfo* info);
+
+  static bool IsUpdateAvailable(const UpdateResponse& response);
+  HRESULT CreateRequestFromApplications(const AppDataVector& applications,
+                                        Request** request);
+  void CreateRequestFromProducts(const ProductDataVector& products,
+                                 Request** request,
+                                 bool* encrypt_connection);
+
+  // Sets the UI displayed event, telling the other instance not to display an
+  // error UI.
+  void SetUiDisplayedEvent() const;
+
+  // Calculates the size of the download bundle.
+  int CalculateBundleSize() const;
+
+  Job* cur_job_;
+  int bundle_dl_size_;
+  int bundle_bytes_downloaded_;
+
+  bool is_machine_;
+  bool is_update_apps_worker_;
+  std::vector<Job*> jobs_;
+  scoped_ptr<NetworkRequest> network_request_;
+  scoped_ptr<NetworkRequest> network_request_encrypted_;
+  scoped_ptr<DownloadManager> download_manager_;
+  CString running_version_;
+  volatile LONG is_canceled_;
+  bool no_jobs_completed_ping_sent_;
+  scoped_ptr<Ping> ping_;
+  JobObserver* job_observer_;
+  scoped_ptr<WorkerJobStrategy> strategy_;
+  HRESULT error_code_;
+  friend class WorkerJobTest;
+
+  DISALLOW_EVIL_CONSTRUCTORS(WorkerJob);
+};
+
+class WorkerJobFactory {
+ public:
+  static WorkerJob* CreateWorkerJob(bool is_machine,
+                                    const CommandLineArgs& args,
+                                    JobObserver* job_observer);
+
+  static HRESULT CreateOnDemandWorkerJob(
+      bool is_machine,
+      bool is_update_check_only,
+      const CString& lang,
+      const GUID& guid,
+      IJobObserver* observer,
+      WorkerComWrapperShutdownCallBack* call_back,
+      WorkerJob** worker_job);
+};
+
+// Creates a request containing the pings for the uninstalled products.
+// The caller has the ownership of the request object. Building the
+// uninstall ping is not an idempotent operation. The client state is
+// cleaned up after building the request.
+HRESULT BuildUninstallPing(bool is_machine, Request** uninstall_ping);
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_WORKER_JOB_H__
diff --git a/worker/worker_job_strategy.cc b/worker/worker_job_strategy.cc
index 31c838d..fe262fa 100644
--- a/worker/worker_job_strategy.cc
+++ b/worker/worker_job_strategy.cc
@@ -1,612 +1,612 @@
-// Copyright 2007-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-//

-

-#include "omaha/worker/worker_job_strategy.h"

-#include <functional>

-#include <algorithm>

-#include "omaha/common/const_cmd_line.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/error.h"

-#include "omaha/common/logging.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/common/scope_guard.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/goopdate_helper.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/stats_uploader.h"

-#include "omaha/setup/setup.h"

-#include "omaha/worker/application_manager.h"

-#include "omaha/worker/application_data.h"

-#include "omaha/worker/job_observer.h"

-#include "omaha/worker/ping.h"

-#include "omaha/worker/ping_utils.h"

-#include "omaha/worker/worker_job.h"

-#include "omaha/worker/worker_metrics.h"

-

-namespace omaha {

-

-namespace {

-

-// Google Update should never be not accepted since its EULA state is kept in

-// the Update key.

-// Uses RefHolder because std::not1 uses a reference to the parameter type,

-// which results in an illegal reference to a reference if the parameter is

-// just a const reference.

-bool IsEulaAccepted(const RefHolder<ProductData> product_holder) {

-  const ProductData& product = product_holder;

-  const bool is_accepted = product.app_data().is_eula_accepted();

-  ASSERT1(is_accepted ||

-          !::IsEqualGUID(kGoopdateGuid, product.app_data().app_guid()));

-  return is_accepted;

-}

-

-bool IsInstallDisabled(const ProductData& product) {

-  return !ConfigManager::Instance()->CanInstallApp(

-      product.app_data().app_guid());

-}

-

-bool IsUpdateDisabled(const ProductData& product, bool is_manual) {

-  return !ConfigManager::Instance()->CanUpdateApp(

-      product.app_data().app_guid(),

-      is_manual);

-}

-

-// Removes apps that are not allowed to be updated because the app's EULA has

-// not been accepted.

-// Returns true if any apps were removed.

-bool RemoveAppsIfUpdateDisallowedByEula(ProductDataVector* products) {

-  ASSERT1(products);

-

-  bool were_apps_removed = false;

-

-  const ProductDataVector::iterator new_end = std::remove_if(

-      products->begin(),

-      products->end(),

-      std::not1(std::ptr_fun(IsEulaAccepted)));

-  if (new_end != products->end()) {

-    const size_t previous_size = products->size();

-    products->erase(new_end, products->end());

-    were_apps_removed = true;

-    metric_worker_apps_not_updated_eula = previous_size - products->size();

-  }

-

-  return were_apps_removed;

-}

-

-// Removes apps that are not allowed to be installed because Group Policy has

-// disabled this.

-// Returns true if any apps were removed.

-bool RemoveAppsDisallowedByInstallGroupPolicy(

-    ProductDataVector* products,

-    CString* first_disallowed_app_name) {

-  ASSERT1(products);

-  ASSERT1(first_disallowed_app_name);

-  ASSERT1(first_disallowed_app_name->IsEmpty());

-

-  bool were_apps_removed = false;

-

-  const ProductDataVector::iterator new_end = std::remove_if(

-      products->begin(),

-      products->end(),

-      IsInstallDisabled);

-  if (new_end != products->end()) {

-    const size_t previous_size = products->size();

-    *first_disallowed_app_name = new_end->app_data().display_name();

-

-    products->erase(new_end, products->end());

-

-    were_apps_removed = true;

-    metric_worker_apps_not_installed_group_policy =

-        previous_size - products->size();

-  }

-

-  return were_apps_removed;

-}

-

-// Disables updates for apps  for which this type of update is disallowed by

-// Group Policy.

-// Returns true if updates were disabled for any app.

-bool DisableUpdateForAppsDisallowedByUpdateGroupPolicy(

-    bool is_manual,

-    ProductDataVector* products,

-    CString* first_disallowed_app_name) {

-  ASSERT1(products);

-  ASSERT1(first_disallowed_app_name);

-  ASSERT1(first_disallowed_app_name->IsEmpty());

-

-  bool were_apps_disabled = false;

-

-  for (ProductDataVector::iterator iter = products->begin();

-       iter != products->end();

-       ++iter) {

-    if (!IsUpdateDisabled(*iter, is_manual)) {

-      continue;

-    }

-

-    if (first_disallowed_app_name->IsEmpty()) {

-      *first_disallowed_app_name = iter->app_data().display_name();

-    }

-

-    AppData modified_app_data = iter->app_data();

-    modified_app_data.set_is_update_disabled(true);

-    iter->set_app_data(modified_app_data);

-

-    were_apps_disabled = true;

-    metric_worker_apps_not_updated_group_policy++;

-  }

-

-  return were_apps_disabled;

-}

-

-class OnlineStrategy : public NetworkStrategy {

- public:

-  explicit OnlineStrategy(WorkerJobStrategy* worker_job_strategy)

-      : NetworkStrategy(worker_job_strategy) {}

-  HRESULT DoUpdateCheck(const ProductDataVector& products) {

-    return worker_job()->DoUpdateCheck(products);

-  }

-  HRESULT DownloadJobs() {

-    return worker_job()->DownloadJobs();

-  }

- private:

-  DISALLOW_IMPLICIT_CONSTRUCTORS(OnlineStrategy);

-};

-

-class OfflineStrategy : public NetworkStrategy {

- public:

-  explicit OfflineStrategy(WorkerJobStrategy* worker_job_strategy)

-      : NetworkStrategy(worker_job_strategy) {}

-  HRESULT DoUpdateCheck(const ProductDataVector& products) {

-    return worker_job()->CreateOfflineJobs(products);

-  }

-  HRESULT DownloadJobs() {

-    return S_OK;

-  }

- private:

-  DISALLOW_IMPLICIT_CONSTRUCTORS(OfflineStrategy);

-};

-

-}  // namespace

-

-WorkerJobStrategy::WorkerJobStrategy(bool is_machine,

-                                     const CString& lang)

-    : is_machine_(is_machine),

-      language_(lang),

-      worker_job_(NULL) {

-}

-

-HRESULT WorkerJobStrategy::ProcessApps() {

-  HRESULT hr = network_strategy()->DownloadJobs();

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return worker_job()->InstallJobs();

-}

-

-HRESULT WorkerJobStrategy::DoUpdateCheck(const ProductDataVector& products) {

-  return network_strategy()->DoUpdateCheck(products);

-}

-

-HRESULT WorkerJobStrategy::PostInstall() {

-  return S_OK;

-}

-

-HRESULT UpdateAppsStrategy::PreUpdateCheck(ProductDataVector* products) {

-  ASSERT1(products);

-  ASSERT1(worker_job());

-

-  HRESULT hr = PingUninstalledProducts();

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[PingUninstalledApps failed][0x%08x]"), hr));

-  }

-

-  // Fill in products from the registered apps database.

-  AppManager app_manager(is_machine());

-  if (!app_manager.ShouldCheckForUpdates()) {

-    OPT_LOG(L1, (_T("[Update check not needed at this time]")));

-    return S_OK;

-  }

-

-  hr = app_manager.GetRegisteredProducts(products);

-

-  if (FAILED(hr) || args_.install_source.IsEmpty()) {

-    return hr;

-  }

-

-  for (size_t i = 0; i < products->size(); ++i) {

-    AppData app_data = (*products)[i].app_data();

-    app_data.set_install_source(args_.install_source);

-    (*products)[i].set_app_data(app_data);

-  }

-

-#ifdef _DEBUG

-  for (size_t i = 0; i < products->size(); ++i) {

-    const GUID& app_guid = (*products)[i].app_data().app_guid();

-    const CString client_state_key_path =

-        goopdate_utils::GetAppClientStateKey(is_machine(),

-                                             GuidToString(app_guid));

-    ASSERT(RegKey::HasKey(client_state_key_path),

-           (_T("[App Clients key does not have matching ClientState key][%s]"),

-            GuidToString(app_guid)));

-  }

-#endif

-

-  return S_OK;

-}

-

-// Not being able to update one or more apps is not an error as long as there is

-// at least one app to update. This should always be the case because Omaha can

-// always be updated.

-HRESULT UpdateAppsStrategy::RemoveDisallowedApps(ProductDataVector* products) {

-  RemoveAppsIfUpdateDisallowedByEula(products);

-  if (products->empty()) {

-    return GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED;

-  }

-

-  DisableUpdateForAppsDisallowedByUpdateGroupPolicy(

-      false,

-      products,

-      &first_disallowed_app_name_);

-  if (products->empty()) {

-    return GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY;

-  }

-

-  return S_OK;

-}

-

-HRESULT UpdateAppsStrategy::DoUpdateCheck(const ProductDataVector& products) {

-  HRESULT hr = SendInstalledByOemPing(products);

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[SendInstalledByOemPing failed][0x%08x]"), hr));

-  }

-

-  return WorkerJobStrategy::DoUpdateCheck(products);

-}

-

-// Updates the LastChecked value; called only after successful update checks.

-HRESULT UpdateAppsStrategy::PostUpdateCheck() {

-  AppManager app_manager(is_machine());

-  HRESULT hr = app_manager.UpdateLastChecked();

-

-  if (FAILED(hr)) {

-    CORE_LOG(LW, (_T("[UpdateLastChecked failed][0x%08x]"), hr));

-  }

-  return S_OK;

-}

-

-HRESULT UpdateAppsStrategy::PingUninstalledProducts() const {

-  CORE_LOG(L2, (_T("[UpdateAppsStrategy::PingUninstalledProducts]")));

-  ASSERT1(worker_job()->ping());

-

-  scoped_ptr<Request> uninstall_ping;

-  HRESULT hr = BuildUninstallPing(is_machine(), address(uninstall_ping));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  if (!uninstall_ping->get_request_count()) {

-    return S_OK;

-  }

-

-  if (worker_job()->is_canceled()) {

-    return GOOPDATE_E_WORKER_CANCELLED;

-  }

-

-  CORE_LOG(L2, (_T("[Sending uninstall ping]")));

-  return worker_job()->ping()->SendPing(uninstall_ping.get());

-}

-

-HRESULT UpdateAppsStrategy::SendInstalledByOemPing(

-    const ProductDataVector& products) const {

-  CORE_LOG(L2, (_T("[UpdateAppsStrategy::SendInstalledByOemPing()]")));

-  ASSERT1(!products.empty());

-

-  Request request(is_machine());

-

-  for (size_t i = 0; i < products.size(); ++i) {

-    const ProductData& product_data = products[i];

-    const AppData& app_data = product_data.app_data();

-    if (app_data.is_oem_install()) {

-      ASSERT1(!::IsEqualGUID(kGoopdateGuid, app_data.app_guid()));

-      AppRequestData app_request_data(app_data);

-      PingEvent ping_event(PingEvent::EVENT_INSTALL_OEM_FIRST_CHECK,

-                           PingEvent::EVENT_RESULT_SUCCESS,

-                           0,  // error code

-                           0,  // extra code 1

-                           app_data.previous_version());

-      app_request_data.AddPingEvent(ping_event);

-      AppRequest app_request(app_request_data);

-      request.AddAppRequest(app_request);

-    }

-  }

-

-  if (!request.get_request_count()) {

-    return S_OK;

-  }

-

-  if (worker_job()->is_canceled()) {

-    return GOOPDATE_E_WORKER_CANCELLED;

-  }

-

-  HRESULT hr = worker_job()->ping()->SendPing(&request);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  AppManager app_manager(is_machine());

-  for (size_t i = 0; i < products.size(); ++i) {

-    const ProductData& product_data = products[i];

-    const AppData& app_data = product_data.app_data();

-    if (app_data.is_oem_install()) {

-      app_manager.ClearOemInstalled(app_data.parent_app_guid(),

-                                    app_data.app_guid());

-    }

-  }

-

-  return S_OK;

-}

-

-InstallAppsStrategy::InstallAppsStrategy(bool is_machine,

-                                         const CommandLineArgs& args)

-    : WorkerJobStrategy(is_machine, args.extra.language),

-      args_(args) {

-}

-

-HRESULT InstallAppsStrategy::PreUpdateCheck(ProductDataVector* products) {

-  ASSERT1(products);

-  ASSERT1(worker_job());

-  AppManager app_manager(is_machine());

-  app_manager.ConvertCommandLineToProductData(args_, products);

-

-  return S_OK;

-}

-

-HRESULT InstallAppsStrategy::RemoveDisallowedApps(ProductDataVector* products) {

-  if (RemoveAppsDisallowedByInstallGroupPolicy(products,

-                                               &first_disallowed_app_name_)) {

-    return GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY;

-  }

-

-  return S_OK;

-}

-

-HRESULT InstallAppsStrategy::PostUpdateCheck() {

-  return S_OK;

-}

-

-HRESULT InstallAppsStrategy::PostInstall() {

-  // TODO(omaha): Maybe move to UI class.

-  if (args_.is_silent_set) {

-    return S_OK;

-  }

-

-  const Jobs& jobs = worker_job()->jobs();

-  if (jobs.empty()) {

-    return S_OK;

-  }

-

-  Job* primary_job = jobs[0];

-

-  // This is a temporary workaround for Earth-Chrome bundles until we implement

-  // better bundle support. Chrome is installed last and is thus the

-  // "primary app", but we want to launch Earth so specify it as primary here.

-  // Earth has two GUIDs that must be supported.

-  // Using StringToGuid below ensure there is no mismatch in upper/lower case.

-  // Note that Chrome's onsuccess value is still used to determine whether to

-  // close the UI.

-  const TCHAR* const kChromeGuid = _T("{8A69D345-D564-463C-AFF1-A69D9E530F96}");

-  const TCHAR* const kEarthMachineGuid =

-      _T("{74AF07D8-FB8F-4D51-8AC7-927721D56EBB}");

-  const TCHAR* const kEarthUserGuid =

-      _T("{0A52903D-0FBF-439A-93E4-CB609A2F63DB}");

-

-  if (jobs.size() == 2 &&

-      jobs[0]->app_data().app_guid() == StringToGuid(kChromeGuid) &&

-      (jobs[1]->app_data().app_guid() == StringToGuid(kEarthMachineGuid) ||

-       jobs[1]->app_data().app_guid() == StringToGuid(kEarthUserGuid))) {

-    primary_job = jobs[1];

-  }

-

-  ASSERT1(primary_job);

-  VERIFY1(SUCCEEDED(primary_job->LaunchCmdLine()));

-

-  return S_OK;

-}

-

-bool InstallAppsStrategy::ShouldLaunchBrowserOnUpdateCheckError() const {

-  return !args_.is_silent_set;

-}

-

-HRESULT InstallGoopdateAndAppsStrategy::PreUpdateCheck(

-    ProductDataVector* products) {

-  ASSERT1(products);

-  HRESULT hr = InstallAppsStrategy::PreUpdateCheck(products);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  hr = FinishGoogleUpdateInstall(args_,

-                                 is_machine(),

-                                 false,

-                                 worker_job()->ping(),

-                                 job_observer_);

-  if (FAILED(hr)) {

-    CORE_LOG(LE, (_T("[FinishGoogleUpdateInstall failed][0x%08x]"), hr));

-    return hr;

-  }

-  return S_OK;

-}

-

-HRESULT OnDemandUpdateStrategy::InitializeDecorator(

-    IJobObserver* observer,

-    WorkerComWrapperShutdownCallBack* call_back) {

-  CORE_LOG(L2, (_T("[OnDemandUpdateStrategy::InitializeDecorator]")));

-  HRESULT hr =

-      CComObject<JobObserverCOMDecorator>::CreateInstance(&job_observer_com_);

-  ASSERT(SUCCEEDED(hr),

-      (_T("[JobObserverCOMDecorator CreateInstance returned 0x%x]"), hr));

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  job_observer_com_scoped_holder_ = job_observer_com_;

-  job_observer_com_->Initialize(observer, call_back);

-  return S_OK;

-}

-

-HRESULT OnDemandUpdateStrategy::Init(

-    GUID guid,

-    IJobObserver* observer,

-    WorkerComWrapperShutdownCallBack* call_back) {

-  CORE_LOG(L3, (_T("[OnDemandUpdateStrategy::Init][%s]"), GuidToString(guid)));

-  AppManager app_manager(is_machine());

-  ProductData product_data;

-

-  HRESULT hr = app_manager.ReadProductDataFromStore(guid, &product_data);

-  if (FAILED(hr)) {

-    ASSERT1(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);

-    return GOOPDATE_E_APP_NOT_REGISTERED;

-  }

-  if (product_data.app_data().is_uninstalled()) {

-    return GOOPDATE_E_APP_UNINSTALLED;

-  }

-

-  AppData app_data = product_data.app_data();

-  app_data.set_install_source(is_update_check_only_ ?

-                              kCmdLineInstallSource_OnDemandCheckForUpdate :

-                              kCmdLineInstallSource_OnDemandUpdate);

-  app_data.set_previous_version(app_data.version());

-  product_data.set_app_data(app_data);

-

-  products_.push_back(product_data);

-

-  hr = InitializeDecorator(observer, call_back);

-  if (FAILED(hr)) {

-    return hr;

-  }

-

-  return S_OK;

-}

-

-JobObserver* OnDemandUpdateStrategy::GetJobObserver() const {

-  return job_observer_com_;

-}

-

-HRESULT OnDemandUpdateStrategy::PreUpdateCheck(ProductDataVector* products) {

-  ASSERT1(products);

-  ASSERT1(worker_job());

-  ASSERT1(!products_.empty());

-  *products = products_;

-  return S_OK;

-}

-

-HRESULT OnDemandUpdateStrategy::RemoveDisallowedApps(

-    ProductDataVector* products) {

-  if (RemoveAppsIfUpdateDisallowedByEula(products)) {

-    return GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED;

-  }

-  if (DisableUpdateForAppsDisallowedByUpdateGroupPolicy(

-          true,

-          products,

-          &first_disallowed_app_name_)) {

-    return GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY;

-  }

-

-  return S_OK;

-}

-

-HRESULT OnDemandUpdateStrategy::PostUpdateCheck() {

-  return S_OK;

-}

-

-HRESULT OnDemandUpdateStrategy::ProcessApps() {

-  HRESULT hr = S_OK;

-  if (!is_update_check_only_ && !worker_job()->jobs().empty()) {

-    // Only call process apps if we have been asked to perform

-    // an update(and not just an update check), and an update is

-    // available.

-    return WorkerJobStrategy::ProcessApps();

-  } else {

-    const TCHAR* const text = _T("Update Check Completed");

-    worker_job()->NotifyCompleted(COMPLETION_SUCCESS, S_OK, text, products_);

-    worker_job()->CompleteAllNonCompletedJobs(COMPLETION_SUCCESS, S_OK, text);

-  }

-

-  return hr;

-}

-

-// job_observer can be NULL.

-// TODO(omaha): Remove job_observer parameter after unifying Setup.

-WorkerJobStrategy* WorkerJobStrategyFactory::CreateInstallStrategy(

-    bool is_machine,

-    const CommandLineArgs& args,

-    JobObserver* job_observer) {

-  WorkerJobStrategy* strategy(NULL);

-

-#pragma warning(push)

-// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by

-// a case label.

-#pragma warning(disable : 4061)

-  switch (args.mode) {

-    // TODO(omaha): Remove Install mode after unifying Setup. It is only here

-    // to support error reporting from DisplaySetupError().

-    case COMMANDLINE_MODE_INSTALL:

-    case COMMANDLINE_MODE_IG:

-      strategy = new InstallGoopdateAndAppsStrategy(is_machine,

-                                                    args,

-                                                    job_observer);

-      break;

-    case COMMANDLINE_MODE_HANDOFF_INSTALL:

-      strategy = new InstallAppsStrategy(is_machine, args);

-      break;

-    default:

-      ASSERT1(false);

-  }

-#pragma warning(pop)

-

-  NetworkStrategy* network_strategy(NULL);

-  if (args.is_offline_set) {

-    network_strategy = new OfflineStrategy(strategy);

-  } else {

-    network_strategy = new OnlineStrategy(strategy);

-  }

-

-  strategy->set_network_strategy(network_strategy);

-

-  return strategy;

-}

-

-WorkerJobStrategy* WorkerJobStrategyFactory::CreateUpdateAppsStrategy(

-    bool is_machine, const CommandLineArgs& args) {

-  WorkerJobStrategy* strategy = new UpdateAppsStrategy(is_machine, args);

-  strategy->set_network_strategy(new OnlineStrategy(strategy));

-  return strategy;

-}

-

-OnDemandUpdateStrategy* WorkerJobStrategyFactory::CreateOnDemandStrategy(

-    bool is_update_check_only,

-    const CString& lang,

-    bool is_machine) {

-  OnDemandUpdateStrategy* strategy =

-      new OnDemandUpdateStrategy(is_update_check_only, lang, is_machine);

-  strategy->set_network_strategy(new OnlineStrategy(strategy));

-  return strategy;

-}

-

-}  // namespace omaha

+// Copyright 2007-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+//
+
+#include "omaha/worker/worker_job_strategy.h"
+#include <functional>
+#include <algorithm>
+#include "omaha/common/const_cmd_line.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/error.h"
+#include "omaha/common/logging.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/common/scope_guard.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/goopdate_helper.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/stats_uploader.h"
+#include "omaha/setup/setup.h"
+#include "omaha/worker/application_manager.h"
+#include "omaha/worker/application_data.h"
+#include "omaha/worker/job_observer.h"
+#include "omaha/worker/ping.h"
+#include "omaha/worker/ping_utils.h"
+#include "omaha/worker/worker_job.h"
+#include "omaha/worker/worker_metrics.h"
+
+namespace omaha {
+
+namespace {
+
+// Google Update should never be not accepted since its EULA state is kept in
+// the Update key.
+// Uses RefHolder because std::not1 uses a reference to the parameter type,
+// which results in an illegal reference to a reference if the parameter is
+// just a const reference.
+bool IsEulaAccepted(const RefHolder<ProductData> product_holder) {
+  const ProductData& product = product_holder;
+  const bool is_accepted = product.app_data().is_eula_accepted();
+  ASSERT1(is_accepted ||
+          !::IsEqualGUID(kGoopdateGuid, product.app_data().app_guid()));
+  return is_accepted;
+}
+
+bool IsInstallDisabled(const ProductData& product) {
+  return !ConfigManager::Instance()->CanInstallApp(
+      product.app_data().app_guid());
+}
+
+bool IsUpdateDisabled(const ProductData& product, bool is_manual) {
+  return !ConfigManager::Instance()->CanUpdateApp(
+      product.app_data().app_guid(),
+      is_manual);
+}
+
+// Removes apps that are not allowed to be updated because the app's EULA has
+// not been accepted.
+// Returns true if any apps were removed.
+bool RemoveAppsIfUpdateDisallowedByEula(ProductDataVector* products) {
+  ASSERT1(products);
+
+  bool were_apps_removed = false;
+
+  const ProductDataVector::iterator new_end = std::remove_if(
+      products->begin(),
+      products->end(),
+      std::not1(std::ptr_fun(IsEulaAccepted)));
+  if (new_end != products->end()) {
+    const size_t previous_size = products->size();
+    products->erase(new_end, products->end());
+    were_apps_removed = true;
+    metric_worker_apps_not_updated_eula = previous_size - products->size();
+  }
+
+  return were_apps_removed;
+}
+
+// Removes apps that are not allowed to be installed because Group Policy has
+// disabled this.
+// Returns true if any apps were removed.
+bool RemoveAppsDisallowedByInstallGroupPolicy(
+    ProductDataVector* products,
+    CString* first_disallowed_app_name) {
+  ASSERT1(products);
+  ASSERT1(first_disallowed_app_name);
+  ASSERT1(first_disallowed_app_name->IsEmpty());
+
+  bool were_apps_removed = false;
+
+  const ProductDataVector::iterator new_end = std::remove_if(
+      products->begin(),
+      products->end(),
+      IsInstallDisabled);
+  if (new_end != products->end()) {
+    const size_t previous_size = products->size();
+    *first_disallowed_app_name = new_end->app_data().display_name();
+
+    products->erase(new_end, products->end());
+
+    were_apps_removed = true;
+    metric_worker_apps_not_installed_group_policy =
+        previous_size - products->size();
+  }
+
+  return were_apps_removed;
+}
+
+// Disables updates for apps  for which this type of update is disallowed by
+// Group Policy.
+// Returns true if updates were disabled for any app.
+bool DisableUpdateForAppsDisallowedByUpdateGroupPolicy(
+    bool is_manual,
+    ProductDataVector* products,
+    CString* first_disallowed_app_name) {
+  ASSERT1(products);
+  ASSERT1(first_disallowed_app_name);
+  ASSERT1(first_disallowed_app_name->IsEmpty());
+
+  bool were_apps_disabled = false;
+
+  for (ProductDataVector::iterator iter = products->begin();
+       iter != products->end();
+       ++iter) {
+    if (!IsUpdateDisabled(*iter, is_manual)) {
+      continue;
+    }
+
+    if (first_disallowed_app_name->IsEmpty()) {
+      *first_disallowed_app_name = iter->app_data().display_name();
+    }
+
+    AppData modified_app_data = iter->app_data();
+    modified_app_data.set_is_update_disabled(true);
+    iter->set_app_data(modified_app_data);
+
+    were_apps_disabled = true;
+    metric_worker_apps_not_updated_group_policy++;
+  }
+
+  return were_apps_disabled;
+}
+
+class OnlineStrategy : public NetworkStrategy {
+ public:
+  explicit OnlineStrategy(WorkerJobStrategy* worker_job_strategy)
+      : NetworkStrategy(worker_job_strategy) {}
+  HRESULT DoUpdateCheck(const ProductDataVector& products) {
+    return worker_job()->DoUpdateCheck(products);
+  }
+  HRESULT DownloadJobs() {
+    return worker_job()->DownloadJobs();
+  }
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(OnlineStrategy);
+};
+
+class OfflineStrategy : public NetworkStrategy {
+ public:
+  explicit OfflineStrategy(WorkerJobStrategy* worker_job_strategy)
+      : NetworkStrategy(worker_job_strategy) {}
+  HRESULT DoUpdateCheck(const ProductDataVector& products) {
+    return worker_job()->CreateOfflineJobs(products);
+  }
+  HRESULT DownloadJobs() {
+    return S_OK;
+  }
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(OfflineStrategy);
+};
+
+}  // namespace
+
+WorkerJobStrategy::WorkerJobStrategy(bool is_machine,
+                                     const CString& lang)
+    : is_machine_(is_machine),
+      language_(lang),
+      worker_job_(NULL) {
+}
+
+HRESULT WorkerJobStrategy::ProcessApps() {
+  HRESULT hr = network_strategy()->DownloadJobs();
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return worker_job()->InstallJobs();
+}
+
+HRESULT WorkerJobStrategy::DoUpdateCheck(const ProductDataVector& products) {
+  return network_strategy()->DoUpdateCheck(products);
+}
+
+HRESULT WorkerJobStrategy::PostInstall() {
+  return S_OK;
+}
+
+HRESULT UpdateAppsStrategy::PreUpdateCheck(ProductDataVector* products) {
+  ASSERT1(products);
+  ASSERT1(worker_job());
+
+  HRESULT hr = PingUninstalledProducts();
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[PingUninstalledApps failed][0x%08x]"), hr));
+  }
+
+  // Fill in products from the registered apps database.
+  AppManager app_manager(is_machine());
+  if (!app_manager.ShouldCheckForUpdates()) {
+    OPT_LOG(L1, (_T("[Update check not needed at this time]")));
+    return S_OK;
+  }
+
+  hr = app_manager.GetRegisteredProducts(products);
+
+  if (FAILED(hr) || args_.install_source.IsEmpty()) {
+    return hr;
+  }
+
+  for (size_t i = 0; i < products->size(); ++i) {
+    AppData app_data = (*products)[i].app_data();
+    app_data.set_install_source(args_.install_source);
+    (*products)[i].set_app_data(app_data);
+  }
+
+#ifdef _DEBUG
+  for (size_t i = 0; i < products->size(); ++i) {
+    const GUID& app_guid = (*products)[i].app_data().app_guid();
+    const CString client_state_key_path =
+        goopdate_utils::GetAppClientStateKey(is_machine(),
+                                             GuidToString(app_guid));
+    ASSERT(RegKey::HasKey(client_state_key_path),
+           (_T("[App Clients key does not have matching ClientState key][%s]"),
+            GuidToString(app_guid)));
+  }
+#endif
+
+  return S_OK;
+}
+
+// Not being able to update one or more apps is not an error as long as there is
+// at least one app to update. This should always be the case because Omaha can
+// always be updated.
+HRESULT UpdateAppsStrategy::RemoveDisallowedApps(ProductDataVector* products) {
+  RemoveAppsIfUpdateDisallowedByEula(products);
+  if (products->empty()) {
+    return GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED;
+  }
+
+  DisableUpdateForAppsDisallowedByUpdateGroupPolicy(
+      false,
+      products,
+      &first_disallowed_app_name_);
+  if (products->empty()) {
+    return GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY;
+  }
+
+  return S_OK;
+}
+
+HRESULT UpdateAppsStrategy::DoUpdateCheck(const ProductDataVector& products) {
+  HRESULT hr = SendInstalledByOemPing(products);
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[SendInstalledByOemPing failed][0x%08x]"), hr));
+  }
+
+  return WorkerJobStrategy::DoUpdateCheck(products);
+}
+
+// Updates the LastChecked value; called only after successful update checks.
+HRESULT UpdateAppsStrategy::PostUpdateCheck() {
+  AppManager app_manager(is_machine());
+  HRESULT hr = app_manager.UpdateLastChecked();
+
+  if (FAILED(hr)) {
+    CORE_LOG(LW, (_T("[UpdateLastChecked failed][0x%08x]"), hr));
+  }
+  return S_OK;
+}
+
+HRESULT UpdateAppsStrategy::PingUninstalledProducts() const {
+  CORE_LOG(L2, (_T("[UpdateAppsStrategy::PingUninstalledProducts]")));
+  ASSERT1(worker_job()->ping());
+
+  scoped_ptr<Request> uninstall_ping;
+  HRESULT hr = BuildUninstallPing(is_machine(), address(uninstall_ping));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  if (!uninstall_ping->get_request_count()) {
+    return S_OK;
+  }
+
+  if (worker_job()->is_canceled()) {
+    return GOOPDATE_E_WORKER_CANCELLED;
+  }
+
+  CORE_LOG(L2, (_T("[Sending uninstall ping]")));
+  return worker_job()->ping()->SendPing(uninstall_ping.get());
+}
+
+HRESULT UpdateAppsStrategy::SendInstalledByOemPing(
+    const ProductDataVector& products) const {
+  CORE_LOG(L2, (_T("[UpdateAppsStrategy::SendInstalledByOemPing()]")));
+  ASSERT1(!products.empty());
+
+  Request request(is_machine());
+
+  for (size_t i = 0; i < products.size(); ++i) {
+    const ProductData& product_data = products[i];
+    const AppData& app_data = product_data.app_data();
+    if (app_data.is_oem_install()) {
+      ASSERT1(!::IsEqualGUID(kGoopdateGuid, app_data.app_guid()));
+      AppRequestData app_request_data(app_data);
+      PingEvent ping_event(PingEvent::EVENT_INSTALL_OEM_FIRST_CHECK,
+                           PingEvent::EVENT_RESULT_SUCCESS,
+                           0,  // error code
+                           0,  // extra code 1
+                           app_data.previous_version());
+      app_request_data.AddPingEvent(ping_event);
+      AppRequest app_request(app_request_data);
+      request.AddAppRequest(app_request);
+    }
+  }
+
+  if (!request.get_request_count()) {
+    return S_OK;
+  }
+
+  if (worker_job()->is_canceled()) {
+    return GOOPDATE_E_WORKER_CANCELLED;
+  }
+
+  HRESULT hr = worker_job()->ping()->SendPing(&request);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  AppManager app_manager(is_machine());
+  for (size_t i = 0; i < products.size(); ++i) {
+    const ProductData& product_data = products[i];
+    const AppData& app_data = product_data.app_data();
+    if (app_data.is_oem_install()) {
+      app_manager.ClearOemInstalled(app_data.parent_app_guid(),
+                                    app_data.app_guid());
+    }
+  }
+
+  return S_OK;
+}
+
+InstallAppsStrategy::InstallAppsStrategy(bool is_machine,
+                                         const CommandLineArgs& args)
+    : WorkerJobStrategy(is_machine, args.extra.language),
+      args_(args) {
+}
+
+HRESULT InstallAppsStrategy::PreUpdateCheck(ProductDataVector* products) {
+  ASSERT1(products);
+  ASSERT1(worker_job());
+  AppManager app_manager(is_machine());
+  app_manager.ConvertCommandLineToProductData(args_, products);
+
+  return S_OK;
+}
+
+HRESULT InstallAppsStrategy::RemoveDisallowedApps(ProductDataVector* products) {
+  if (RemoveAppsDisallowedByInstallGroupPolicy(products,
+                                               &first_disallowed_app_name_)) {
+    return GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY;
+  }
+
+  return S_OK;
+}
+
+HRESULT InstallAppsStrategy::PostUpdateCheck() {
+  return S_OK;
+}
+
+HRESULT InstallAppsStrategy::PostInstall() {
+  // TODO(omaha): Maybe move to UI class.
+  if (args_.is_silent_set) {
+    return S_OK;
+  }
+
+  const Jobs& jobs = worker_job()->jobs();
+  if (jobs.empty()) {
+    return S_OK;
+  }
+
+  Job* primary_job = jobs[0];
+
+  // This is a temporary workaround for Earth-Chrome bundles until we implement
+  // better bundle support. Chrome is installed last and is thus the
+  // "primary app", but we want to launch Earth so specify it as primary here.
+  // Earth has two GUIDs that must be supported.
+  // Using StringToGuid below ensure there is no mismatch in upper/lower case.
+  // Note that Chrome's onsuccess value is still used to determine whether to
+  // close the UI.
+  const TCHAR* const kChromeGuid = _T("{8A69D345-D564-463C-AFF1-A69D9E530F96}");
+  const TCHAR* const kEarthMachineGuid =
+      _T("{74AF07D8-FB8F-4D51-8AC7-927721D56EBB}");
+  const TCHAR* const kEarthUserGuid =
+      _T("{0A52903D-0FBF-439A-93E4-CB609A2F63DB}");
+
+  if (jobs.size() == 2 &&
+      jobs[0]->app_data().app_guid() == StringToGuid(kChromeGuid) &&
+      (jobs[1]->app_data().app_guid() == StringToGuid(kEarthMachineGuid) ||
+       jobs[1]->app_data().app_guid() == StringToGuid(kEarthUserGuid))) {
+    primary_job = jobs[1];
+  }
+
+  ASSERT1(primary_job);
+  VERIFY1(SUCCEEDED(primary_job->LaunchCmdLine()));
+
+  return S_OK;
+}
+
+bool InstallAppsStrategy::ShouldLaunchBrowserOnUpdateCheckError() const {
+  return !args_.is_silent_set;
+}
+
+HRESULT InstallGoopdateAndAppsStrategy::PreUpdateCheck(
+    ProductDataVector* products) {
+  ASSERT1(products);
+  HRESULT hr = InstallAppsStrategy::PreUpdateCheck(products);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  hr = FinishGoogleUpdateInstall(args_,
+                                 is_machine(),
+                                 false,
+                                 worker_job()->ping(),
+                                 job_observer_);
+  if (FAILED(hr)) {
+    CORE_LOG(LE, (_T("[FinishGoogleUpdateInstall failed][0x%08x]"), hr));
+    return hr;
+  }
+  return S_OK;
+}
+
+HRESULT OnDemandUpdateStrategy::InitializeDecorator(
+    IJobObserver* observer,
+    WorkerComWrapperShutdownCallBack* call_back) {
+  CORE_LOG(L2, (_T("[OnDemandUpdateStrategy::InitializeDecorator]")));
+  HRESULT hr =
+      CComObject<JobObserverCOMDecorator>::CreateInstance(&job_observer_com_);
+  ASSERT(SUCCEEDED(hr),
+      (_T("[JobObserverCOMDecorator CreateInstance returned 0x%x]"), hr));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  job_observer_com_scoped_holder_ = job_observer_com_;
+  job_observer_com_->Initialize(observer, call_back);
+  return S_OK;
+}
+
+HRESULT OnDemandUpdateStrategy::Init(
+    GUID guid,
+    IJobObserver* observer,
+    WorkerComWrapperShutdownCallBack* call_back) {
+  CORE_LOG(L3, (_T("[OnDemandUpdateStrategy::Init][%s]"), GuidToString(guid)));
+  AppManager app_manager(is_machine());
+  ProductData product_data;
+
+  HRESULT hr = app_manager.ReadProductDataFromStore(guid, &product_data);
+  if (FAILED(hr)) {
+    ASSERT1(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);
+    return GOOPDATE_E_APP_NOT_REGISTERED;
+  }
+  if (product_data.app_data().is_uninstalled()) {
+    return GOOPDATE_E_APP_UNINSTALLED;
+  }
+
+  AppData app_data = product_data.app_data();
+  app_data.set_install_source(is_update_check_only_ ?
+                              kCmdLineInstallSource_OnDemandCheckForUpdate :
+                              kCmdLineInstallSource_OnDemandUpdate);
+  app_data.set_previous_version(app_data.version());
+  product_data.set_app_data(app_data);
+
+  products_.push_back(product_data);
+
+  hr = InitializeDecorator(observer, call_back);
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  return S_OK;
+}
+
+JobObserver* OnDemandUpdateStrategy::GetJobObserver() const {
+  return job_observer_com_;
+}
+
+HRESULT OnDemandUpdateStrategy::PreUpdateCheck(ProductDataVector* products) {
+  ASSERT1(products);
+  ASSERT1(worker_job());
+  ASSERT1(!products_.empty());
+  *products = products_;
+  return S_OK;
+}
+
+HRESULT OnDemandUpdateStrategy::RemoveDisallowedApps(
+    ProductDataVector* products) {
+  if (RemoveAppsIfUpdateDisallowedByEula(products)) {
+    return GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED;
+  }
+  if (DisableUpdateForAppsDisallowedByUpdateGroupPolicy(
+          true,
+          products,
+          &first_disallowed_app_name_)) {
+    return GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY;
+  }
+
+  return S_OK;
+}
+
+HRESULT OnDemandUpdateStrategy::PostUpdateCheck() {
+  return S_OK;
+}
+
+HRESULT OnDemandUpdateStrategy::ProcessApps() {
+  HRESULT hr = S_OK;
+  if (!is_update_check_only_ && !worker_job()->jobs().empty()) {
+    // Only call process apps if we have been asked to perform
+    // an update(and not just an update check), and an update is
+    // available.
+    return WorkerJobStrategy::ProcessApps();
+  } else {
+    const TCHAR* const text = _T("Update Check Completed");
+    worker_job()->NotifyCompleted(COMPLETION_SUCCESS, S_OK, text, products_);
+    worker_job()->CompleteAllNonCompletedJobs(COMPLETION_SUCCESS, S_OK, text);
+  }
+
+  return hr;
+}
+
+// job_observer can be NULL.
+// TODO(omaha): Remove job_observer parameter after unifying Setup.
+WorkerJobStrategy* WorkerJobStrategyFactory::CreateInstallStrategy(
+    bool is_machine,
+    const CommandLineArgs& args,
+    JobObserver* job_observer) {
+  WorkerJobStrategy* strategy(NULL);
+
+#pragma warning(push)
+// C4061: enumerator 'xxx' in switch of enum 'yyy' is not explicitly handled by
+// a case label.
+#pragma warning(disable : 4061)
+  switch (args.mode) {
+    // TODO(omaha): Remove Install mode after unifying Setup. It is only here
+    // to support error reporting from DisplaySetupError().
+    case COMMANDLINE_MODE_INSTALL:
+    case COMMANDLINE_MODE_IG:
+      strategy = new InstallGoopdateAndAppsStrategy(is_machine,
+                                                    args,
+                                                    job_observer);
+      break;
+    case COMMANDLINE_MODE_HANDOFF_INSTALL:
+      strategy = new InstallAppsStrategy(is_machine, args);
+      break;
+    default:
+      ASSERT1(false);
+  }
+#pragma warning(pop)
+
+  NetworkStrategy* network_strategy(NULL);
+  if (args.is_offline_set) {
+    network_strategy = new OfflineStrategy(strategy);
+  } else {
+    network_strategy = new OnlineStrategy(strategy);
+  }
+
+  strategy->set_network_strategy(network_strategy);
+
+  return strategy;
+}
+
+WorkerJobStrategy* WorkerJobStrategyFactory::CreateUpdateAppsStrategy(
+    bool is_machine, const CommandLineArgs& args) {
+  WorkerJobStrategy* strategy = new UpdateAppsStrategy(is_machine, args);
+  strategy->set_network_strategy(new OnlineStrategy(strategy));
+  return strategy;
+}
+
+OnDemandUpdateStrategy* WorkerJobStrategyFactory::CreateOnDemandStrategy(
+    bool is_update_check_only,
+    const CString& lang,
+    bool is_machine) {
+  OnDemandUpdateStrategy* strategy =
+      new OnDemandUpdateStrategy(is_update_check_only, lang, is_machine);
+  strategy->set_network_strategy(new OnlineStrategy(strategy));
+  return strategy;
+}
+
+}  // namespace omaha
diff --git a/worker/worker_job_strategy.h b/worker/worker_job_strategy.h
index b4c81f2..f6715d1 100644
--- a/worker/worker_job_strategy.h
+++ b/worker/worker_job_strategy.h
@@ -1,211 +1,211 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#ifndef OMAHA_WORKER_WORKER_JOB_STRATEGY_H__

-#define OMAHA_WORKER_WORKER_JOB_STRATEGY_H__

-

-#include <windows.h>

-#include <atlstr.h>

-#include "base/scoped_ptr.h"

-#include "goopdate/google_update_idl.h"

-#include "omaha/common/debug.h"

-#include "omaha/common/logging.h"

-#include "omaha/goopdate/command_line.h"

-#include "omaha/worker/com_wrapper_shutdown_handler.h"

-#include "omaha/worker/product_data.h"

-

-namespace omaha {

-

-class JobObserver;

-class JobObserverCOMDecorator;

-class NetworkStrategy;

-class Ping;

-class WorkerJob;

-struct CommandLineArgs;

-

-class WorkerJobStrategy {

- public:

-  WorkerJobStrategy(bool is_machine, const CString& lang);

-  virtual ~WorkerJobStrategy() {}

-

-  void set_worker_job(WorkerJob* worker_job) {

-    ASSERT1(worker_job);

-    worker_job_ = worker_job;

-  }

-

-  virtual HRESULT PreUpdateCheck(ProductDataVector* products) = 0;

-  virtual HRESULT RemoveDisallowedApps(ProductDataVector* products) = 0;

-  virtual HRESULT DoUpdateCheck(const ProductDataVector& products);

-  virtual HRESULT PostUpdateCheck() = 0;

-  virtual HRESULT ProcessApps();

-  virtual HRESULT PostInstall();

-

-  virtual bool ShouldFailOnUpdateNotAvailable() const { return false; }

-  virtual bool IsAutoUpdate() const { return false; }

-  virtual bool IsUpdate() const { return false; }

-  virtual bool IsUpdateCheckOnly() const { return false; }

-  virtual bool ShouldLaunchBrowserOnUpdateCheckError() const { return false; }

-

-  const CString language() const { return language_; }

-  bool is_machine() const { return is_machine_; }

-  CString first_disallowed_app_name() const {

-      return first_disallowed_app_name_;

-  }

-

- protected:

-  WorkerJob* worker_job() const { return worker_job_; }

-  NetworkStrategy* network_strategy() const { return network_strategy_.get(); }

-  virtual void set_network_strategy(NetworkStrategy* network_strategy) {

-    network_strategy_.reset(network_strategy);

-  }

-  CString first_disallowed_app_name_;

-

- private:

-  bool is_machine_;

-  CString language_;

-  WorkerJob* worker_job_;

-  scoped_ptr<NetworkStrategy> network_strategy_;

-

-  friend class WorkerJobStrategyFactory;

-  friend class NetworkStrategy;

-

-  DISALLOW_EVIL_CONSTRUCTORS(WorkerJobStrategy);

-};

-

-class UpdateAppsStrategy : public WorkerJobStrategy {

- public:

-  virtual HRESULT PreUpdateCheck(ProductDataVector* products);

-  virtual HRESULT RemoveDisallowedApps(ProductDataVector* products_);

-  virtual HRESULT DoUpdateCheck(const ProductDataVector& products);

-  virtual HRESULT PostUpdateCheck();

-

-  virtual bool IsAutoUpdate() const { return true; }

-  virtual bool IsUpdate() const { return true; }

-

- private:

-  explicit UpdateAppsStrategy(bool is_machine, const CommandLineArgs& args)

-      : WorkerJobStrategy(is_machine, args.extra.language),

-        args_(args) {

-  }

-  virtual HRESULT PingUninstalledProducts() const;

-

-  // Sends an "install by OEM" ping for any of the products that were installed

-  // by an OEM. If the ping is sent successfully, the OEM install flag is

-  // deleted so the ping will not be sent again.

-  virtual HRESULT SendInstalledByOemPing(

-      const ProductDataVector& products) const;

-

-  const CommandLineArgs& args_;

-

-  friend class WorkerJobStrategyFactory;

-};

-

-class InstallAppsStrategy : public WorkerJobStrategy {

- public:

-  virtual HRESULT PreUpdateCheck(ProductDataVector* products);

-  virtual HRESULT RemoveDisallowedApps(ProductDataVector* products_);

-  virtual HRESULT PostUpdateCheck();

-  virtual HRESULT PostInstall();

-

-  virtual bool ShouldFailOnUpdateNotAvailable() const { return true; }

-  virtual bool ShouldLaunchBrowserOnUpdateCheckError() const;

-

- protected:

-  InstallAppsStrategy(bool is_machine,

-                      const CommandLineArgs& args);

-  const CommandLineArgs& args_;

-

-  friend class WorkerJobStrategyFactory;

-};

-

-class InstallGoopdateAndAppsStrategy : public InstallAppsStrategy {

- public:

-  virtual HRESULT PreUpdateCheck(ProductDataVector* products);

-

- private:

-  InstallGoopdateAndAppsStrategy(bool is_machine,

-                                 const CommandLineArgs& args,

-                                 JobObserver* job_observer)

-      : InstallAppsStrategy(is_machine, args),

-        job_observer_(job_observer) {}

-  JobObserver* job_observer_;

-

-  friend class WorkerJobStrategyFactory;

-};

-

-class OnDemandUpdateStrategy : public WorkerJobStrategy {

- public:

-  HRESULT Init(GUID guid,

-               IJobObserver* observer,

-               WorkerComWrapperShutdownCallBack* call_back);

-  virtual JobObserver* GetJobObserver() const;

-  virtual HRESULT PreUpdateCheck(ProductDataVector* products);

-  virtual HRESULT RemoveDisallowedApps(ProductDataVector* products_);

-  virtual HRESULT PostUpdateCheck();

-  virtual HRESULT ProcessApps();

-

-  virtual bool ShouldFailOnUpdateNotAvailable() const { return true; }

-  virtual bool IsUpdate() const { return true; }

-  virtual bool IsUpdateCheckOnly() const { return is_update_check_only_; }

-

- private:

-  OnDemandUpdateStrategy(bool is_update_check_only,

-                         const CString& lang,

-                         bool is_machine)

-      : WorkerJobStrategy(is_machine, lang),

-        is_update_check_only_(is_update_check_only),

-        job_observer_com_(NULL) {}

-  HRESULT InitializeDecorator(IJobObserver* observer,

-                              WorkerComWrapperShutdownCallBack* call_back);

-

-  bool is_update_check_only_;

-  CComObject<JobObserverCOMDecorator>* job_observer_com_;

-  CComPtr<IUnknown> job_observer_com_scoped_holder_;

-  ProductDataVector products_;

-

-  friend class WorkerJobStrategyFactory;

-};

-

-class WorkerJobStrategyFactory {

- public:

-  static WorkerJobStrategy* CreateInstallStrategy(bool is_machine,

-                                                  const CommandLineArgs& args,

-                                                  JobObserver* job_observer);

-  static WorkerJobStrategy* CreateUpdateAppsStrategy(

-      bool is_machine, const CommandLineArgs& args);

-  static OnDemandUpdateStrategy* CreateOnDemandStrategy(bool update_check_only,

-                                                        const CString& lang,

-                                                        bool is_machine);

-};

-

-class NetworkStrategy {

- public:

-  virtual ~NetworkStrategy() {}

-  virtual HRESULT DoUpdateCheck(const ProductDataVector& products) = 0;

-  virtual HRESULT DownloadJobs() = 0;

- protected:

-  explicit NetworkStrategy(WorkerJobStrategy* worker_job_strategy)

-      : worker_job_strategy_(worker_job_strategy) {}

-  WorkerJob* worker_job() {

-    return worker_job_strategy_->worker_job();

-  }

-

-  WorkerJobStrategy* worker_job_strategy_;

-};

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_WORKER_JOB_STRATEGY_H__

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#ifndef OMAHA_WORKER_WORKER_JOB_STRATEGY_H__
+#define OMAHA_WORKER_WORKER_JOB_STRATEGY_H__
+
+#include <windows.h>
+#include <atlstr.h>
+#include "base/scoped_ptr.h"
+#include "goopdate/google_update_idl.h"
+#include "omaha/common/debug.h"
+#include "omaha/common/logging.h"
+#include "omaha/goopdate/command_line.h"
+#include "omaha/worker/com_wrapper_shutdown_handler.h"
+#include "omaha/worker/product_data.h"
+
+namespace omaha {
+
+class JobObserver;
+class JobObserverCOMDecorator;
+class NetworkStrategy;
+class Ping;
+class WorkerJob;
+struct CommandLineArgs;
+
+class WorkerJobStrategy {
+ public:
+  WorkerJobStrategy(bool is_machine, const CString& lang);
+  virtual ~WorkerJobStrategy() {}
+
+  void set_worker_job(WorkerJob* worker_job) {
+    ASSERT1(worker_job);
+    worker_job_ = worker_job;
+  }
+
+  virtual HRESULT PreUpdateCheck(ProductDataVector* products) = 0;
+  virtual HRESULT RemoveDisallowedApps(ProductDataVector* products) = 0;
+  virtual HRESULT DoUpdateCheck(const ProductDataVector& products);
+  virtual HRESULT PostUpdateCheck() = 0;
+  virtual HRESULT ProcessApps();
+  virtual HRESULT PostInstall();
+
+  virtual bool ShouldFailOnUpdateNotAvailable() const { return false; }
+  virtual bool IsAutoUpdate() const { return false; }
+  virtual bool IsUpdate() const { return false; }
+  virtual bool IsUpdateCheckOnly() const { return false; }
+  virtual bool ShouldLaunchBrowserOnUpdateCheckError() const { return false; }
+
+  const CString language() const { return language_; }
+  bool is_machine() const { return is_machine_; }
+  CString first_disallowed_app_name() const {
+      return first_disallowed_app_name_;
+  }
+
+ protected:
+  WorkerJob* worker_job() const { return worker_job_; }
+  NetworkStrategy* network_strategy() const { return network_strategy_.get(); }
+  virtual void set_network_strategy(NetworkStrategy* network_strategy) {
+    network_strategy_.reset(network_strategy);
+  }
+  CString first_disallowed_app_name_;
+
+ private:
+  bool is_machine_;
+  CString language_;
+  WorkerJob* worker_job_;
+  scoped_ptr<NetworkStrategy> network_strategy_;
+
+  friend class WorkerJobStrategyFactory;
+  friend class NetworkStrategy;
+
+  DISALLOW_EVIL_CONSTRUCTORS(WorkerJobStrategy);
+};
+
+class UpdateAppsStrategy : public WorkerJobStrategy {
+ public:
+  virtual HRESULT PreUpdateCheck(ProductDataVector* products);
+  virtual HRESULT RemoveDisallowedApps(ProductDataVector* products_);
+  virtual HRESULT DoUpdateCheck(const ProductDataVector& products);
+  virtual HRESULT PostUpdateCheck();
+
+  virtual bool IsAutoUpdate() const { return true; }
+  virtual bool IsUpdate() const { return true; }
+
+ private:
+  explicit UpdateAppsStrategy(bool is_machine, const CommandLineArgs& args)
+      : WorkerJobStrategy(is_machine, args.extra.language),
+        args_(args) {
+  }
+  virtual HRESULT PingUninstalledProducts() const;
+
+  // Sends an "install by OEM" ping for any of the products that were installed
+  // by an OEM. If the ping is sent successfully, the OEM install flag is
+  // deleted so the ping will not be sent again.
+  virtual HRESULT SendInstalledByOemPing(
+      const ProductDataVector& products) const;
+
+  const CommandLineArgs& args_;
+
+  friend class WorkerJobStrategyFactory;
+};
+
+class InstallAppsStrategy : public WorkerJobStrategy {
+ public:
+  virtual HRESULT PreUpdateCheck(ProductDataVector* products);
+  virtual HRESULT RemoveDisallowedApps(ProductDataVector* products_);
+  virtual HRESULT PostUpdateCheck();
+  virtual HRESULT PostInstall();
+
+  virtual bool ShouldFailOnUpdateNotAvailable() const { return true; }
+  virtual bool ShouldLaunchBrowserOnUpdateCheckError() const;
+
+ protected:
+  InstallAppsStrategy(bool is_machine,
+                      const CommandLineArgs& args);
+  const CommandLineArgs& args_;
+
+  friend class WorkerJobStrategyFactory;
+};
+
+class InstallGoopdateAndAppsStrategy : public InstallAppsStrategy {
+ public:
+  virtual HRESULT PreUpdateCheck(ProductDataVector* products);
+
+ private:
+  InstallGoopdateAndAppsStrategy(bool is_machine,
+                                 const CommandLineArgs& args,
+                                 JobObserver* job_observer)
+      : InstallAppsStrategy(is_machine, args),
+        job_observer_(job_observer) {}
+  JobObserver* job_observer_;
+
+  friend class WorkerJobStrategyFactory;
+};
+
+class OnDemandUpdateStrategy : public WorkerJobStrategy {
+ public:
+  HRESULT Init(GUID guid,
+               IJobObserver* observer,
+               WorkerComWrapperShutdownCallBack* call_back);
+  virtual JobObserver* GetJobObserver() const;
+  virtual HRESULT PreUpdateCheck(ProductDataVector* products);
+  virtual HRESULT RemoveDisallowedApps(ProductDataVector* products_);
+  virtual HRESULT PostUpdateCheck();
+  virtual HRESULT ProcessApps();
+
+  virtual bool ShouldFailOnUpdateNotAvailable() const { return true; }
+  virtual bool IsUpdate() const { return true; }
+  virtual bool IsUpdateCheckOnly() const { return is_update_check_only_; }
+
+ private:
+  OnDemandUpdateStrategy(bool is_update_check_only,
+                         const CString& lang,
+                         bool is_machine)
+      : WorkerJobStrategy(is_machine, lang),
+        is_update_check_only_(is_update_check_only),
+        job_observer_com_(NULL) {}
+  HRESULT InitializeDecorator(IJobObserver* observer,
+                              WorkerComWrapperShutdownCallBack* call_back);
+
+  bool is_update_check_only_;
+  CComObject<JobObserverCOMDecorator>* job_observer_com_;
+  CComPtr<IUnknown> job_observer_com_scoped_holder_;
+  ProductDataVector products_;
+
+  friend class WorkerJobStrategyFactory;
+};
+
+class WorkerJobStrategyFactory {
+ public:
+  static WorkerJobStrategy* CreateInstallStrategy(bool is_machine,
+                                                  const CommandLineArgs& args,
+                                                  JobObserver* job_observer);
+  static WorkerJobStrategy* CreateUpdateAppsStrategy(
+      bool is_machine, const CommandLineArgs& args);
+  static OnDemandUpdateStrategy* CreateOnDemandStrategy(bool update_check_only,
+                                                        const CString& lang,
+                                                        bool is_machine);
+};
+
+class NetworkStrategy {
+ public:
+  virtual ~NetworkStrategy() {}
+  virtual HRESULT DoUpdateCheck(const ProductDataVector& products) = 0;
+  virtual HRESULT DownloadJobs() = 0;
+ protected:
+  explicit NetworkStrategy(WorkerJobStrategy* worker_job_strategy)
+      : worker_job_strategy_(worker_job_strategy) {}
+  WorkerJob* worker_job() {
+    return worker_job_strategy_->worker_job();
+  }
+
+  WorkerJobStrategy* worker_job_strategy_;
+};
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_WORKER_JOB_STRATEGY_H__
diff --git a/worker/worker_job_unittest.cc b/worker/worker_job_unittest.cc
index 623de9b..11d3484 100644
--- a/worker/worker_job_unittest.cc
+++ b/worker/worker_job_unittest.cc
@@ -1,1902 +1,1902 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include <atlbase.h>

-#include <msxml2.h>

-#include "omaha/common/app_util.h"

-#include "omaha/common/error.h"

-#include "omaha/common/omaha_version.h"

-#include "omaha/common/path.h"

-#include "omaha/common/process.h"

-#include "omaha/common/scoped_ptr_address.h"

-#include "omaha/goopdate/config_manager.h"

-#include "omaha/goopdate/const_goopdate.h"

-#include "omaha/goopdate/goopdate_utils.h"

-#include "omaha/goopdate/request.h"

-#include "omaha/goopdate/stats_uploader.h"

-#include "omaha/net/cup_request.h"

-#include "omaha/net/simple_request.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/i_job_observer_mock.h"

-#include "omaha/worker/job_creator.h"

-#include "omaha/worker/job_observer_mock.h"

-#include "omaha/worker/ping_event.h"

-#include "omaha/worker/ping_mock.h"

-#include "omaha/worker/worker_job.h"

-#include "omaha/worker/worker_job_strategy.h"

-#include "omaha/worker/worker_metrics.h"

-

-CComModule module;

-

-namespace omaha {

-

-namespace {

-

-#define APP_GUID _T("{2D8F7DCC-86F9-464c-AF80-B986B551927B}")

-#define APP_GUID2 _T("{7234E9E5-3870-4561-9533-B1D91696A8BA}")

-#define APP_GUID3 _T("{5F5FC3BC-A40E-4dfc-AE0B-FD039A343EE8}")

-const TCHAR* const kAppGuid = APP_GUID;

-const TCHAR* const kAppGuid2 = APP_GUID2;

-const TCHAR* const kAppGuid3 = APP_GUID3;

-

-const TCHAR* const kPolicyKey =

-    _T("HKLM\\Software\\Policies\\Google\\Update\\");

-const TCHAR* const kInstallPolicyApp = _T("Install") APP_GUID;

-const TCHAR* const kUpdatePolicyApp = _T("Update") APP_GUID;

-const TCHAR* const kInstallPolicyApp2 = _T("Install") APP_GUID2;

-const TCHAR* const kUpdatePolicyApp2 = _T("Update") APP_GUID2;

-const TCHAR* const kInstallPolicyApp3 = _T("Install") APP_GUID3;

-const TCHAR* const kUpdatePolicyApp3 = _T("Update") APP_GUID3;

-const TCHAR* const kUpdatePolicyGoopdate = _T("Update") GOOPDATE_APP_ID;

-

-const TCHAR* const kMachineClientStatePathApp =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\") APP_GUID;

-const TCHAR* const kMachineClientStatePathApp2 =

-    _T("HKLM\\Software\\Google\\Update\\ClientState\\") APP_GUID2;

-const TCHAR* const kMachineClientStateMediumPathApp =

-    _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\") APP_GUID;

-

-const CString handoff_cmd_line(_T("/handoff /lang en"));

-const CString finish_setup_cmd_line(_T("/ig /lang en"));

-const CString false_extra_args(

-    _T("\"appguid={2D8F7DCC-86F9-464c-AF80-B986B551927B}")

-    _T("&appname=FooBar&needsadmin=False\""));

-const CString true_extra_args(

-    _T("\"appguid={2D8F7DCC-86F9-464c-AF80-B986B551927B}")

-    _T("&appname=FooBar&needsadmin=True\""));

-

-// Helper to write policies to the registry. Eliminates ambiguity of which

-// overload of SetValue to use without the need for static_cast.

-HRESULT SetPolicy(const TCHAR* policy_name, DWORD value) {

-  return RegKey::SetValue(kPolicyKey, policy_name, value);

-}

-

-// Returns E_FAIL from SendPing().

-class PingMockFail : public PingMock {

- public:

-  virtual HRESULT SendPing(Request* req) {

-    VERIFY1(SUCCEEDED(PingMock::SendPing(req)));

-    return E_FAIL;

-  }

-};

-

-// Records the last request buffer and if a request has been sent.

-class MockRequestSave : public SimpleRequest {

- public:

-  MockRequestSave() : is_sent_(false) {}

-

-  // Sets is_sent and performs the send.

-  virtual HRESULT Send() {

-    is_sent_ = true;

-    return SimpleRequest::Send();

-  }

-

-  // Assumes the buffer is valid UTF-8.

-  virtual void set_request_buffer(const void* buffer, size_t buffer_length) {

-    sent_request_utf8_.SetString(static_cast<const char*>(buffer),

-                                 buffer_length);

-    SimpleRequest::set_request_buffer(buffer, buffer_length);

-  }

-

-  const CStringA& sent_request_utf8() const { return sent_request_utf8_; }

-  bool is_sent() const { return is_sent_; }

-

- private:

-  CStringA sent_request_utf8_;

-  bool is_sent_;

-};

-

-

-// Performs the Send(), but always returns true and a response with "noupdate"

-// for the specified apps.

-// The actual return value of Send() is inconsistent behavior due to HKLM being

-// overridden because DNS lookup may or may not fail depending on earlier tests.

-class MockRequestSaveNoUpdate : public MockRequestSave {

- public:

-  explicit MockRequestSaveNoUpdate(

-      const std::vector<CString>& expected_app_guids)

-      : expected_app_guids_(expected_app_guids) {

-  }

-

-  virtual HRESULT Send() {

-    MockRequestSave::Send();

-    return S_OK;

-  }

-

-  virtual int GetHttpStatusCode() const {

-    return 200;

-  }

-

-  virtual std::vector<uint8> GetResponse() const {

-    CStringA no_update_response =

-        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"

-        "<gupdate xmlns=\"http://www.google.com/update2/response\" "

-        "protocol=\"2.0\">";

-    for (size_t i = 0; i < expected_app_guids_.size(); ++i) {

-      no_update_response.Append("<app appid=\"");

-      no_update_response.Append(WideToAnsiDirect(expected_app_guids_[i]));

-      no_update_response.Append(

-        "\" status=\"ok\">"

-        "  <updatecheck status=\"noupdate\"/><ping status=\"ok\"/>"

-        "</app>");

-    }

-    no_update_response.Append("</gupdate>");

-

-    const size_t response_length = strlen(no_update_response) + 1;

-    std::vector<uint8> response;

-    response.resize(response_length);

-    EXPECT_EQ(0, memcpy_s(&response[0],

-                          response_length,

-                          no_update_response,

-                          response_length));

-    return response;

-  }

-

- private:

-  std::vector<CString> expected_app_guids_;

-

-  DISALLOW_IMPLICIT_CONSTRUCTORS(MockRequestSaveNoUpdate);

-};

-

-// Returns kUpdateCheckForcedFailure from Send().

-class MockRequestSaveFail : public MockRequestSave {

- public:

-  // Performs the send and fails with kUpdateCheckForcedFailure regardless of

-  // the result.

-  virtual HRESULT Send() {

-    MockRequestSave::Send();

-    return kUpdateCheckForcedFailure;

-  }

-

-  static const HRESULT kUpdateCheckForcedFailure = 0x81234567;

-};

-

-void VerifyUpdateCheckInRequest(const std::vector<CString>& expected_app_guids,

-                                const std::vector<CString>& disabled_app_guids,

-                                const CStringA& request_utf8,

-                                bool is_install,

-                                bool is_on_demand) {

-  EXPECT_NE(0, expected_app_guids.size());

-  const char* kOmahaRequestUpdate =

-      "<o:app appid=\"{430FD4D0-B729-4F61-AA34-91526481799D}\" "

-      "version=\"5.6.7.8\" lang=\"\" brand=\"\" client=\"\"><o:updatecheck/>"

-      "</o:app>";

-

-  // The 'c' in "464c" element of the app GUID is capitalized in the request.

-  const char* kAppRequestFormat=

-      "<o:app appid=\"%s\" "

-      "version=\"%s\" lang=\"\" brand=\"\" client=\"\"%s><o:updatecheck%s/>"

-      "</o:app>";

-

-  EXPECT_EQ(0, request_utf8.Find(

-      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"

-      "<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" "

-      "protocol=\"2.0\" version=\"1.2."));

-  EXPECT_NE(-1, request_utf8.Find("\" ismachine=\"1\" machineid=\"{"));

-  EXPECT_NE(-1, request_utf8.Find("}\" userid=\"{"));

-  EXPECT_NE(-1, request_utf8.Find("\" requestid=\"{"));

-  EXPECT_NE(-1, request_utf8.Find("}\"><o:os platform=\"win\" version=\""));

-  EXPECT_NE(-1, request_utf8.Find("\" sp=\""));

-  EXPECT_NE(-1, request_utf8.Find("\"/><o:app"));

-

-  // Verify the expected number of app elements.

-  int app_element_index = request_utf8.Find("<o:app");

-  int num_app_elements = 0;

-  while (-1 != app_element_index) {

-    num_app_elements++;

-    app_element_index = request_utf8.Find("<o:app", app_element_index + 1);

-  }

-  EXPECT_EQ(num_app_elements, expected_app_guids.size());

-

-  for (size_t i = 0; i < expected_app_guids.size(); ++i) {

-    const CString& expected_app = expected_app_guids[i];

-

-    bool is_disabled_expected = false;

-    for (size_t j = 0; j < disabled_app_guids.size(); ++j) {

-      if (expected_app == disabled_app_guids[j]) {

-        is_disabled_expected = true;

-        break;

-      }

-    }

-

-    if (expected_app == kGoogleUpdateAppId) {

-      ASSERT1(!is_on_demand && !is_install);

-      EXPECT_NE(-1, request_utf8.Find(kOmahaRequestUpdate));

-    } else {

-      ASSERT1(expected_app == kAppGuid || expected_app == kAppGuid2);

-      const CStringA app_guid = WideToAnsiDirect(expected_app == kAppGuid ?

-                                                 CString(kAppGuid).MakeUpper() :

-                                                 kAppGuid2);

-      CStringA expected_app_element;

-      expected_app_element.Format(

-          kAppRequestFormat,

-          app_guid,

-          is_install ? "" : "1.2.3.4",

-          is_on_demand ? " installsource=\"ondemandupdate\"" : "",

-          is_disabled_expected ? " updatedisabled=\"true\"" : "");

-      EXPECT_NE(-1, request_utf8.Find(expected_app_element)) <<

-          _T("Expected: ") <<

-          Utf8ToWideChar(expected_app_element.GetString(),

-                         expected_app_element.GetLength()).GetString() <<

-          std::endl << _T("In: ") <<

-          Utf8ToWideChar(request_utf8.GetString(),

-                         request_utf8.GetLength()).GetString() << std::endl;

-    }

-  }

-

-  EXPECT_NE(-1, request_utf8.Find("</o:app></o:gupdate>"));

-

-  EXPECT_FALSE(::testing::Test::HasFailure()) <<

-      _T("Actual Request: ") << request_utf8;

-}

-

-}  // namespace

-

-class WorkerJobTest : public testing::Test {

- protected:

-  WorkerJobTest()

-      : mock_network_request_(NULL),

-        mock_encryped_request_(NULL) {

-    exe_to_test_ = ConcatenatePath(

-        app_util::GetCurrentModuleDirectory(),

-        _T("unittest_support\\does_not_shutdown\\GoogleUpdate.exe"));

-  }

-

-  void SetIsMachine(bool is_machine) {

-    worker_job_->is_machine_ = is_machine;

-  }

-

-  bool IsAppInstallWorkerRunning() {

-    return goopdate_utils::IsAppInstallWorkerRunning(worker_job_->is_machine_);

-  }

-

-  PingEvent::Types GetPingType(const Request& request) {

-    const AppRequest& app_request = *(request.app_requests_begin());

-    const AppRequestData& app_request_data = app_request.request_data();

-    const PingEvent& ping_event = *(app_request_data.ping_events_begin());

-    return ping_event.event_type();

-  }

-

-  void SetWorkerJobPing(Ping* ping) {

-    worker_job_->ping_.reset(ping);

-  }

-

-  // Sets WorkerJob to use MockRequestSave for all types of requests.

-  void SetMockMockRequestSave() {

-    SetMockRequest(new MockRequestSave, new MockRequestSave);

-  }

-

-  // Sets WorkerJob to use MockRequestSaveNoUpdate for all types of requests.

-  void SetMockRequestSaveNoUpdate(

-      const std::vector<CString>& expected_app_guids) {

-    SetMockRequest(new MockRequestSaveNoUpdate(expected_app_guids),

-                   new MockRequestSaveNoUpdate(expected_app_guids));

-  }

-

-  // Sets WorkerJob to use MockRequestSaveFail for all types of requests.

-  void SetMockMockRequestSaveFail() {

-    SetMockRequest(new MockRequestSaveFail, new MockRequestSaveFail);

-  }

-

-  // Sets WorkerJob to use the specified HTTP request objects.

-  // Prevents multiple calls to the mock request by specifying the Config and

-  // avoiding auto-detection.

-  void SetMockRequest(MockRequestSave* normal_request,

-                      MockRequestSave* encryped_request) {

-    ASSERT1(worker_job_.get());

-    const NetworkConfig::Session& session(NetworkConfig::Instance().session());

-    const Config config;

-

-    mock_network_request_ = normal_request;

-    mock_encryped_request_ = encryped_request;

-

-    worker_job_->network_request_.reset(new NetworkRequest(session));

-    worker_job_->network_request_->set_network_configuration(&config);

-    worker_job_->network_request_->AddHttpRequest(normal_request);

-

-    worker_job_->network_request_encrypted_.reset(new NetworkRequest(session));

-    worker_job_->network_request_encrypted_->set_network_configuration(&config);

-    worker_job_->network_request_encrypted_->AddHttpRequest(

-        encryped_request);

-  }

-

-  void VerifyInstallUpdateCheck(

-      const std::vector<CString>& expected_app_guids) const {

-    ASSERT1(mock_network_request_ && mock_encryped_request_);

-    EXPECT_TRUE(mock_network_request_->is_sent());

-    VerifyUpdateCheckInRequest(expected_app_guids,

-                               std::vector<CString>(),

-                               mock_network_request_->sent_request_utf8(),

-                               true,

-                               false);

-    EXPECT_FALSE(mock_encryped_request_->is_sent());

-  }

-

-  void VerifyAutoUpdateCheckWithDisabledApps(

-      const std::vector<CString>& expected_app_guids,

-      const std::vector<CString>& disabled_app_guids) const {

-    ASSERT1(mock_network_request_ && mock_encryped_request_);

-    EXPECT_TRUE(mock_network_request_->is_sent());

-    VerifyUpdateCheckInRequest(expected_app_guids,

-                               disabled_app_guids,

-                               mock_network_request_->sent_request_utf8(),

-                               false,

-                               false);

-    EXPECT_FALSE(mock_encryped_request_->is_sent());

-  }

-

-  void VerifyAutoUpdateCheck(

-      const std::vector<CString>& expected_app_guids) const {

-      VerifyAutoUpdateCheckWithDisabledApps(expected_app_guids,

-                                            std::vector<CString>());

-  }

-

-  void VerifyOnDemandUpdateCheck(

-      const std::vector<CString>& expected_app_guids) const {

-    ASSERT1(mock_network_request_ && mock_encryped_request_);

-    EXPECT_TRUE(mock_network_request_->is_sent());

-    VerifyUpdateCheckInRequest(expected_app_guids,

-                               std::vector<CString>(),

-                               mock_network_request_->sent_request_utf8(),

-                               false,

-                               true);

-    EXPECT_FALSE(mock_encryped_request_->is_sent());

-  }

-

-  void VerifyNoUpdateCheckSent() const {

-    ASSERT1(mock_network_request_ && mock_encryped_request_);

-    EXPECT_FALSE(mock_network_request_->is_sent());

-    EXPECT_FALSE(mock_encryped_request_->is_sent());

-  }

-

-  scoped_ptr<WorkerJob> worker_job_;

-  CString exe_to_test_;

-  MockRequestSave* mock_network_request_;

-  MockRequestSave* mock_encryped_request_;

-};

-

-class WorkerJobRegistryProtectedTest : public WorkerJobTest {

- protected:

-  WorkerJobRegistryProtectedTest()

-      : hive_override_key_name_(kRegistryHiveOverrideRoot), xml_cookie_(0) {

-  }

-

-  virtual void SetUp() {

-    // Registers the MSXML CoClass before doing registry redirection. Without

-    // this registration, CoCreation of the DOMDocument2 within the test would

-    // fail on Vista, as a side-effect of the registry redirection.

-    CComPtr<IClassFactory> factory;

-    EXPECT_SUCCEEDED(::CoGetClassObject(__uuidof(DOMDocument2),

-                                        CLSCTX_INPROC_SERVER,

-                                        NULL,

-                                        IID_IClassFactory,

-                                        reinterpret_cast<void**>(&factory)));

-    EXPECT_SUCCEEDED(::CoRegisterClassObject(__uuidof(DOMDocument2),

-                                             factory,

-                                             CLSCTX_INPROC_SERVER,

-                                             REGCLS_MULTIPLEUSE,

-                                             &xml_cookie_));

-    RegKey::DeleteKey(hive_override_key_name_, true);

-    OverrideRegistryHives(hive_override_key_name_);

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    EXPECT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));

-    if (xml_cookie_) {

-      EXPECT_SUCCEEDED(::CoRevokeClassObject(xml_cookie_));

-    }

-  }

-

-  CString hive_override_key_name_;

-  DWORD xml_cookie_;

-};

-

-class WorkerJobDoProcessTest : public WorkerJobRegistryProtectedTest {

- protected:

-  // Must be re-entrant for statics because it is called once for each subclass.

-  static void SetUpTestCase() {

-    // Initialize the global metrics collection.

-    stats_report::g_global_metrics.Initialize();

-

-    if (app_guids_omaha_.empty()) {

-      app_guids_omaha_.push_back(kGoogleUpdateAppId);

-    }

-

-    if (app_guids_omaha_app1_.empty()) {

-      app_guids_omaha_app1_ = app_guids_omaha_;

-      app_guids_omaha_app1_.push_back(kAppGuid);

-    }

-

-    if (app_guids_omaha_app2_.empty()) {

-      app_guids_omaha_app2_ = app_guids_omaha_;

-      app_guids_omaha_app2_.push_back(kAppGuid2);

-    }

-

-    if (app_guids_omaha_app1_app2_.empty()) {

-      app_guids_omaha_app1_app2_ = app_guids_omaha_app1_;

-      app_guids_omaha_app1_app2_ .push_back(kAppGuid2);

-    }

-

-    if (app_guids_app1_.empty()) {

-      app_guids_app1_.push_back(kAppGuid);

-    }

-

-    if (app_guids_app2_.empty()) {

-      app_guids_app2_.push_back(kAppGuid2);

-    }

-  }

-

-  static void TearDownTestCase() {

-    // The global metrics collection must be uninitialized before the metrics

-    // destructors are called.

-    stats_report::g_global_metrics.Uninitialize();

-  }

-

-  virtual void SetUp() {

-    WorkerJobRegistryProtectedTest::SetUp();

-#ifdef _DEBUG

-    // There is an assert that expects this value to be set.

-    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                      kRegValueInstalledVersion,

-                                      GetVersionString()));

-#endif

-    metric_worker_apps_not_updated_eula.Set(0);

-    metric_worker_apps_not_updated_group_policy.Set(0);

-    metric_worker_apps_not_installed_group_policy.Set(0);

-  }

-

-  // These tests cause the action to fail. This method validates the app request

-  // for an individual app generated by

-  // ping_utils::SendCompletedPingsForAllProducts().

-  // The expected ping data depends on whether the WorkerJob was canceled.

-  static void ValidateCompletedPingForProduct(const AppRequest& app_request,

-                                              const GUID& expected_app_id,

-                                              bool is_canceled) {

-    const PingEvent& ping_event = GetSingleEventFromAppRequest(app_request,

-                                                               expected_app_id,

-                                                               true);

-    EXPECT_EQ(PingEvent::EVENT_UPDATE_COMPLETE, ping_event.event_type());

-    EXPECT_EQ(is_canceled ? PingEvent::EVENT_RESULT_CANCELLED :

-                            PingEvent::EVENT_RESULT_ERROR,

-              ping_event.event_result());

-    EXPECT_EQ(is_canceled ? GOOPDATE_E_WORKER_CANCELLED :

-                            MockRequestSaveFail::kUpdateCheckForcedFailure,

-              ping_event.error_code());

-    EXPECT_EQ(0x100000ff, ping_event.extra_code1());

-

-    EXPECT_EQ(::IsEqualGUID(kGoopdateGuid, expected_app_id) ? _T("5.6.7.8") :

-                                                              _T("1.2.3.4"),

-              ping_event.previous_version());

-  }

-

-  // TODO(omaha): I think this is a bug that we ping without an event.

-  // If not, fix this and replace this method with a check for no pings.

-  static void ValidateNoPingEventForProduct(const AppRequest& app_request,

-                                            const GUID& expected_app_id) {

-    const AppRequestData& app_request_data = app_request.request_data();

-

-    const AppData& app_data = app_request_data.app_data();

-    EXPECT_TRUE(::IsEqualGUID(expected_app_id, app_data.app_guid()));

-    EXPECT_TRUE(::IsEqualGUID(GUID_NULL, app_data.parent_app_guid()));

-    EXPECT_EQ(true, app_data.is_machine_app());

-    EXPECT_TRUE(!app_data.version().IsEmpty());

-    EXPECT_TRUE(!app_data.previous_version().IsEmpty());

-

-    EXPECT_EQ(0, app_request_data.num_ping_events());

-  }

-

-  static void ValidateForcedFailureObserved(

-      const JobObserverMock& job_observer) {

-    EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer.completion_code);

-    EXPECT_STREQ(_T("Installation failed. Please try again. Error code = ")

-                 _T("0x81234567"), job_observer.completion_text);

-    EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,

-              job_observer.completion_error_code);

-  }

-

-  static void ValidateNoEventObserved(

-      const JobObserverMock& job_observer) {

-    EXPECT_EQ(static_cast<CompletionCodes>(-1), job_observer.completion_code);

-    EXPECT_TRUE(job_observer.completion_text.IsEmpty());

-    EXPECT_EQ(0, job_observer.completion_error_code);

-  }

-

-  // Only applies to installs.

-  static void ValidateNoUpdateErrorObserved(

-      const JobObserverMock& job_observer) {

-    EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer.completion_code);

-    EXPECT_STREQ(_T("Installation failed. Please try again. Error code = ")

-                 _T("0x80040809"), job_observer.completion_text);

-    EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE,

-              job_observer.completion_error_code);

-  }

-

-  // JobObserverCOMDecorator does not pass along the text and the COM interface

-  // does not support passing the error code so the COM mock sets E_UNEXPECTED.

-  static void ValidateComFailureObserved(

-      const JobObserverMock& job_observer) {

-    EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer.completion_code);

-    EXPECT_TRUE(job_observer.completion_text.IsEmpty());

-    EXPECT_EQ(E_UNEXPECTED, job_observer.completion_error_code);

-  }

-

-  static void ValidateComSuccessObserved(

-      const JobObserverMock& job_observer) {

-    EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer.completion_code);

-    EXPECT_TRUE(job_observer.completion_text.IsEmpty());

-    EXPECT_EQ(E_UNEXPECTED, job_observer.completion_error_code);

-  }

-

-  const std::vector<CString>& app_guids_omaha() const {

-      return app_guids_omaha_;

-  }

-  const std::vector<CString>& app_guids_omaha_app1() const {

-      return app_guids_omaha_app1_;

-  }

-  const std::vector<CString>& app_guids_omaha_app2() const {

-      return app_guids_omaha_app2_;

-  }

-  const std::vector<CString>& app_guids_omaha_app1_app2() const {

-      return app_guids_omaha_app1_app2_;

-  }

-  const std::vector<CString>& app_guids_app1() const { return app_guids_app1_; }

-  const std::vector<CString>& app_guids_app2() const { return app_guids_app2_; }

-

- private:

-  static std::vector<CString> app_guids_omaha_;

-  static std::vector<CString> app_guids_omaha_app1_;

-  static std::vector<CString> app_guids_omaha_app2_;

-  static std::vector<CString> app_guids_omaha_app1_app2_;

-  static std::vector<CString> app_guids_app1_;

-  static std::vector<CString> app_guids_app2_;

-};

-

-std::vector<CString> WorkerJobDoProcessTest::app_guids_omaha_;

-std::vector<CString> WorkerJobDoProcessTest::app_guids_omaha_app1_;

-std::vector<CString> WorkerJobDoProcessTest::app_guids_omaha_app2_;

-std::vector<CString> WorkerJobDoProcessTest::app_guids_omaha_app1_app2_;

-std::vector<CString> WorkerJobDoProcessTest::app_guids_app1_;

-std::vector<CString> WorkerJobDoProcessTest::app_guids_app2_;

-

-class WorkerJobDoProcessUpdateMachineTest : public WorkerJobDoProcessTest {

- protected:

-  virtual void SetUp() {

-    WorkerJobDoProcessTest::SetUp();

-

-    // Omaha is always registered.

-    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,

-                                      _T("pv"),

-                                      _T("5.6.7.8")));

-    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,

-                                      _T("pv"),

-                                      _T("5.6.7.8")));

-

-    // Register the product to check for updates.

-    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID,

-                                      _T("pv"),

-                                      _T("1.2.3.4")));

-    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID,

-                                      _T("pv"),

-                                      _T("1.2.3.4")));

-

-    args_.mode = COMMANDLINE_MODE_UA;

-    worker_job_.reset(

-        WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));

-

-    ping_mock_ = new PingMock;

-    SetWorkerJobPing(ping_mock_);

-  }

-

-  // These tests cause the action to fail. This method validates the ping

-  // generated by ping_utils::SendCompletedPingsForAllProducts().

-  void ValidateCompletedPingsForAllProducts(const Request& ping_request,

-                                            bool is_canceled) {

-    EXPECT_TRUE(ping_request.is_machine());

-    EXPECT_EQ(2, ping_request.get_request_count());

-

-    AppRequestVector::const_iterator iter = ping_request.app_requests_begin();

-    ValidateCompletedPingForProduct(*iter, StringToGuid(kAppGuid), is_canceled);

-

-    ++iter;

-    ValidateCompletedPingForProduct(*iter, kGoopdateGuid, is_canceled);

-    StringToGuid(kAppGuid);

-  }

-

-  // TODO(omaha): I think this is a bug that we ping without an event.

-  // If not, fix this and replace this method with a check for no pings.

-  void ValidateNoPingEventForAllProducts(const Request& ping_request) {

-    EXPECT_TRUE(ping_request.is_machine());

-    EXPECT_EQ(2, ping_request.get_request_count());

-

-    AppRequestVector::const_iterator iter = ping_request.app_requests_begin();

-    ValidateNoPingEventForProduct(*iter, StringToGuid(kAppGuid));

-

-    ++iter;

-    ValidateNoPingEventForProduct(*iter, kGoopdateGuid);

-    StringToGuid(kAppGuid);

-  }

-

-  CommandLineArgs args_;

-  JobObserverMock job_observer_;

-  PingMock* ping_mock_;

-};

-

-class WorkerJobDoProcessInstallMachineTest : public WorkerJobDoProcessTest {

- protected:

-  virtual void SetUp() {

-    WorkerJobDoProcessTest::SetUp();

-

-    args_.is_silent_set = true;  // Prevent browser from launching on errors.

-    args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-    args_.extra.apps.push_back(CommandLineAppArgs());

-    args_.extra.apps[0].app_guid = StringToGuid(kAppGuid);

-    args_.extra.apps[0].app_name = _T("Foo Bar");

-    args_.extra.apps[0].needs_admin = true;

-

-    worker_job_.reset(

-        WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));

-  }

-

-  CommandLineArgs args_;

-  JobObserverMock job_observer_;

-};

-

-class WorkerJobDoProcessInstallGoogleUpdateMachineTest

-    : public WorkerJobDoProcessTest {

- protected:

-  virtual void SetUp() {

-    WorkerJobDoProcessTest::SetUp();

-

-    args_.is_silent_set = true;  // Prevent browser from launching on errors.

-    args_.mode = COMMANDLINE_MODE_IG;

-    args_.extra.apps.push_back(CommandLineAppArgs());

-    args_.extra.apps[0].app_guid = StringToGuid(kAppGuid);

-    args_.extra.apps[0].needs_admin = true;

-

-    AppData app_data;

-    app_data.set_app_guid(StringToGuid(kAppGuid));

-    app_data.set_is_machine_app(true);

-    products_.push_back(ProductData(app_data));

-

-    worker_job_.reset(

-        WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));

-  }

-

-  CommandLineArgs args_;

-  ProductDataVector products_;

-  JobObserverMock job_observer_;

-};

-

-class WorkerJobDoProcessOnDemandUpdateMachineTest

-    : public WorkerJobDoProcessTest {

- protected:

-  virtual void SetUp() {

-    WorkerJobDoProcessTest::SetUp();

-

-    // Register the product as required by OnDemandUpdateStrategy::Init().

-    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID,

-                                      _T("pv"),

-                                      _T("1.2.3.4")));

-

-    HRESULT hr = CComObject<IJobObserverMock>::CreateInstance(&job_observer_);

-    ASSERT_EQ(S_OK, hr);

-    job_holder_ = job_observer_;

-

-    worker_job_.reset();

-    ASSERT_SUCCEEDED(WorkerJobFactory::CreateOnDemandWorkerJob(

-        true,   // is_machine

-        false,  // is_update_check_only

-        _T("en"),

-        StringToGuid(kAppGuid),

-        job_holder_,

-        new WorkerComWrapperShutdownCallBack(false),

-        address(worker_job_)));

-  }

-

-  CComObject<IJobObserverMock>* job_observer_;

-  CComPtr<IJobObserver> job_holder_;

-};

-

-class WorkerJobIsAppInstallWorkerRunningTest : public WorkerJobTest {

- protected:

-  WorkerJobIsAppInstallWorkerRunningTest() {

-    args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-    CommandLineAppArgs app_args;

-    app_args.app_name = _T("WorkerJobIsAppInstallWorkerRunningTest");

-    args_.extra.apps.push_back(app_args);

-  }

-

-  void TestIsAppInstallWorkerRunning(const CString& cmd_line,

-                                     bool is_machine,

-                                     bool expected_running) {

-    Process p(exe_to_test_, NULL);

-    ASSERT_TRUE(p.Start(cmd_line));

-

-    // Wait for the process to be ready. IsAppInstallWorkerRunning uses

-    // Process::GetCommandLine, which fails if it cannot ::ReadProcessMemory().

-    // Waiting for GetCommandLine() to succeed should ensure that the process is

-    // sufficiently initialized for this test.

-    // TODO(omaha): If we change to using Job Objects, we will not need this

-    // if we use ::AssignProcessToJobObject() from this test.

-    HRESULT hr = E_FAIL;

-    CString process_cmd;

-    for (int tries = 0; tries < 100 && FAILED(hr); ++tries) {

-      ::Sleep(50);

-      hr = Process::GetCommandLine(p.GetId(), &process_cmd);

-    }

-    EXPECT_SUCCEEDED(hr);

-

-    SetIsMachine(is_machine);

-    EXPECT_EQ(expected_running, IsAppInstallWorkerRunning());

-    EXPECT_TRUE(p.Terminate(1000));

-  }

-

-  CommandLineArgs args_;

-  CString cmd_line_;

-  JobObserverMock job_observer_;

-};

-

-// TODO(omaha): Test all methods of WorkerJob.

-

-TEST_F(WorkerJobDoProcessTest, OnDemandUpdate_AppNotRegistered) {

-  CComObject<IJobObserverMock>* job_observer;

-  CComPtr<IJobObserver> job_holder;

-

-  HRESULT hr = CComObject<IJobObserverMock>::CreateInstance(&job_observer);

-  ASSERT_EQ(S_OK, hr);

-  job_holder = job_observer;

-

-  worker_job_.reset();

-  EXPECT_EQ(GOOPDATE_E_APP_NOT_REGISTERED,

-      WorkerJobFactory::CreateOnDemandWorkerJob(

-      true,   // is_machine

-      false,  // is_update_check_only

-      _T("en"),

-      StringToGuid(kAppGuid),

-      job_holder,

-      new WorkerComWrapperShutdownCallBack(false),

-      address(worker_job_)));

-}

-

-//

-// Update apps tests.

-//

-

-// Also tests that the OemInstallPing is not sent.

-TEST_F(WorkerJobDoProcessUpdateMachineTest, UpdateCheckFails) {

-  SetMockMockRequestSaveFail();

-

-  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,

-            worker_job_->DoProcess());

-  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,

-            worker_job_->error_code());

-

-  ValidateForcedFailureObserved(job_observer_);

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  ValidateCompletedPingsForAllProducts(*ping_mock_->ping_requests()[0], false);

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// Also tests that the OemInstallPing is not sent.

-TEST_F(WorkerJobDoProcessUpdateMachineTest, GroupPolicy_NoPolicy) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheck(app_guids_omaha_app1());

-  ValidateNoEventObserved(job_observer_);

-

-  // TODO(omaha): I don't think there should be any pings.

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessUpdateMachineTest, GroupPolicy_InstallProhibited) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheck(app_guids_omaha_app1());

-  ValidateNoEventObserved(job_observer_);

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessUpdateMachineTest,

-       GroupPolicy_UpdateProhibitedForSingleApp) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheckWithDisabledApps(app_guids_omaha_app1(),

-                                        app_guids_app1());

-  ValidateNoEventObserved(job_observer_);

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessUpdateMachineTest,

-       GroupPolicy_ManualUpdateOnlyForSingleApp) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 2));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheckWithDisabledApps(app_guids_omaha_app1(),

-                                        app_guids_app1());

-  ValidateNoEventObserved(job_observer_);

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// Use the default behavior when the value is not supported.

-TEST_F(WorkerJobDoProcessUpdateMachineTest, GroupPolicy_InvalidUpdateValue) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 3));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheck(app_guids_omaha_app1());

-  ValidateNoEventObserved(job_observer_);

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// Omaha updates will always be performed.

-TEST_F(WorkerJobDoProcessUpdateMachineTest,

-       GroupPolicy_UpdateProhibitedForOmahaAndAllApps) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyGoopdate, 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheckWithDisabledApps(app_guids_omaha_app1(),

-                                        app_guids_app1());

-  ValidateNoEventObserved(job_observer_);

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// This case should not happen because Omaha is not registered.

-TEST_F(WorkerJobDoProcessUpdateMachineTest,

-       GroupPolicy_UpdateProhibitedForAllRegisteredApps) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-  ASSERT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_CLIENTS_GOOPDATE, _T("pv")));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheckWithDisabledApps(app_guids_app1(), app_guids_app1());

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  const Request& ping_request = *ping_mock_->ping_requests()[0];

-  EXPECT_TRUE(ping_request.is_machine());

-  EXPECT_EQ(1, ping_request.get_request_count());

-  ValidateNoPingEventForProduct(*ping_request.app_requests_begin(),

-                                StringToGuid(kAppGuid));

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// This case should not happen because Omaha is not registered.

-TEST_F(WorkerJobDoProcessUpdateMachineTest,

-       GroupPolicy_UpdateProhibitedForAllAppsByPolicyOrEula) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-  ASSERT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_CLIENTS_GOOPDATE, _T("pv")));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID2,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID2,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp2,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheckWithDisabledApps(app_guids_app1(), app_guids_app1());

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  const Request& ping_request = *ping_mock_->ping_requests()[0];

-  EXPECT_TRUE(ping_request.is_machine());

-  EXPECT_EQ(1, ping_request.get_request_count());

-  ValidateNoPingEventForProduct(*ping_request.app_requests_begin(),

-                                StringToGuid(kAppGuid));

-

-  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// Although a ping request is received, the real Ping object would not send it.

-TEST_F(WorkerJobDoProcessUpdateMachineTest, GoogleUpdateEulaNotAccepted) {

-  SetMockMockRequestSave();

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_EQ(GOOPDATE_E_CANNOT_USE_NETWORK, worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_CANNOT_USE_NETWORK, worker_job_->error_code());

-

-  VerifyNoUpdateCheckSent();

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessUpdateMachineTest, AppEulaNotAccepted) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID2,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID2,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp2,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheck(app_guids_omaha_app1());

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  // Update checks are sent for Omaha and App1 but not App2.

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);

-

-  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessUpdateMachineTest, AppEulaAcceptedInClientState) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheck(app_guids_omaha_app1());

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessUpdateMachineTest,

-       AppEulaNotAcceptedInClientStateButIsInClientStateMedium) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStateMediumPathApp,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(1)));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheck(app_guids_omaha_app1());

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// EULA is checked first.

-TEST_F(WorkerJobDoProcessUpdateMachineTest,

-       AppEulaNotAcceptedAndUpdateProhibited) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha());

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheck(app_guids_omaha());

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-

-  // Only Omaha is in the completed ping because the app is disabled by EULA.

-  const Request& ping_request = *ping_mock_->ping_requests()[0];

-  EXPECT_TRUE(ping_request.is_machine());

-  EXPECT_EQ(1, ping_request.get_request_count());

-  ValidateNoPingEventForProduct(*ping_request.app_requests_begin(),

-                                kGoopdateGuid);

-

-  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessUpdateMachineTest,

-       AppEulaNotAcceptedOtherAppUpdateProhibited) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app2());

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID2,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID2,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 0));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheckWithDisabledApps(app_guids_omaha_app2(),

-                                        app_guids_app2());

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-

-  // Only Omaha is in the completed ping because both apps are disabled.

-  const Request& ping_request = *ping_mock_->ping_requests()[0];

-  EXPECT_TRUE(ping_request.is_machine());

-  EXPECT_EQ(2, ping_request.get_request_count());

-  ValidateNoPingEventForProduct(*ping_request.app_requests_begin(),

-                                kGoopdateGuid);

-  ValidateNoPingEventForProduct(*(++ping_request.app_requests_begin()),

-                                StringToGuid(kAppGuid2));

-

-  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessUpdateMachineTest, OemInstallPing) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID,

-                                    _T("oeminstall"),

-                                    _T("1")));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheck(app_guids_omaha_app1());

-

-  ASSERT_EQ(2, ping_mock_->ping_requests().size());

-

-  const PingEvent& ping_event = GetSingleEventFromRequest(

-      *ping_mock_->ping_requests()[0],

-      StringToGuid(kAppGuid),

-      true);

-  EXPECT_EQ(PingEvent::EVENT_INSTALL_OEM_FIRST_CHECK, ping_event.event_type());

-  EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, ping_event.event_result());

-  EXPECT_EQ(0, ping_event.error_code());

-  EXPECT_EQ(0, ping_event.extra_code1());

-  EXPECT_EQ(_T("1.2.3.4"), ping_event.previous_version());

-

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[1]);

-

-  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE APP_GUID,

-                                _T("oeminstall")));

-}

-

-TEST_F(WorkerJobDoProcessUpdateMachineTest, OemInstallPing_Failed) {

-  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());

-  ping_mock_ = new PingMockFail();

-  SetWorkerJobPing(ping_mock_);

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID,

-                                    _T("oeminstall"),

-                                    _T("1")));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyAutoUpdateCheck(app_guids_omaha_app1());

-

-  ASSERT_EQ(2, ping_mock_->ping_requests().size());

-

-  const PingEvent& ping_event = GetSingleEventFromRequest(

-      *ping_mock_->ping_requests()[0],

-      StringToGuid(kAppGuid),

-      true);

-  EXPECT_EQ(PingEvent::EVENT_INSTALL_OEM_FIRST_CHECK, ping_event.event_type());

-  EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, ping_event.event_result());

-  EXPECT_EQ(0, ping_event.error_code());

-  EXPECT_EQ(0, ping_event.extra_code1());

-  EXPECT_EQ(_T("1.2.3.4"), ping_event.previous_version());

-

-  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[1]);

-

-  EXPECT_TRUE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE APP_GUID,

-                               _T("oeminstall")));

-}

-

-TEST_F(WorkerJobDoProcessUpdateMachineTest, OemInstallPing_WorkerJobCanceled) {

-  SetMockMockRequestSave();

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID,

-                                    _T("oeminstall"),

-                                    _T("1")));

-  worker_job_->Cancel();

-

-  EXPECT_EQ(GOOPDATE_E_WORKER_CANCELLED, worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_WORKER_CANCELLED, worker_job_->error_code());

-

-  VerifyNoUpdateCheckSent();

-

-  ASSERT_EQ(1, ping_mock_->ping_requests().size());

-  ValidateCompletedPingsForAllProducts(*ping_mock_->ping_requests()[0], true);

-

-  EXPECT_TRUE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE APP_GUID,

-                               _T("oeminstall")));

-}

-

-//

-// Install tests.

-//

-

-TEST_F(WorkerJobDoProcessInstallMachineTest, UpdateCheckFails) {

-  SetMockMockRequestSaveFail();

-

-  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,

-            worker_job_->DoProcess());

-  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,

-            worker_job_->error_code());

-

-  ValidateForcedFailureObserved(job_observer_);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallMachineTest, GroupPolicy_NoPolicy) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());

-

-  VerifyInstallUpdateCheck(app_guids_app1());

-  ValidateNoUpdateErrorObserved(job_observer_);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallMachineTest, GroupPolicy_InstallProhibited) {

-  SetMockMockRequestSave();

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));

-

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->error_code());

-

-  EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer_.completion_code);

-  EXPECT_STREQ(_T("Your network administrator has applied a Group Policy that ")

-               _T("prevents installation of Foo Bar."),

-               job_observer_.completion_text);

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            job_observer_.completion_error_code);

-

-  VerifyNoUpdateCheckSent();

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// Use the default behavior when the value is not supported.

-TEST_F(WorkerJobDoProcessInstallMachineTest, GroupPolicy_InvalidInstallValue) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 2));

-

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());

-

-  VerifyInstallUpdateCheck(app_guids_app1());

-  ValidateNoUpdateErrorObserved(job_observer_);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// Tests which app name is displayed.

-TEST_F(WorkerJobDoProcessInstallMachineTest,

-       GroupPolicy_InstallThreeAppsLastTwoProhibited) {

-  SetMockMockRequestSave();

-  args_.extra.apps.push_back(CommandLineAppArgs());

-  args_.extra.apps[1].app_guid = StringToGuid(kAppGuid2);

-  args_.extra.apps[1].app_name = _T("App 2");

-  args_.extra.apps[1].needs_admin = true;

-  args_.extra.apps.push_back(CommandLineAppArgs());

-  args_.extra.apps[2].app_guid = StringToGuid(kAppGuid3);

-  args_.extra.apps[2].app_name = _T("Third App");

-  args_.extra.apps[2].needs_admin = true;

-

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp2, 0));

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp3, 0));

-

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->error_code());

-

-  VerifyNoUpdateCheckSent();

-

-  EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer_.completion_code);

-  EXPECT_STREQ(_T("Your network administrator has applied a Group Policy that ")

-               _T("prevents installation of App 2."),

-               job_observer_.completion_text);

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            job_observer_.completion_error_code);

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(2, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallMachineTest, GroupPolicy_UpdateProhibited) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());

-

-  VerifyInstallUpdateCheck(app_guids_app1());

-  ValidateNoUpdateErrorObserved(job_observer_);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallMachineTest,

-       GroupPolicy_InstallAndUpdateProhibited) {

-  SetMockMockRequestSave();

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->error_code());

-

-  VerifyNoUpdateCheckSent();

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallMachineTest,

-       GroupPolicy_InstallOfDifferentAppProhibited) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp2, 0));

-

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());

-

-  VerifyInstallUpdateCheck(app_guids_app1());

-  ValidateNoUpdateErrorObserved(job_observer_);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallMachineTest,

-       GroupPolicy_InstallTwoAppsOneProhibited) {

-  SetMockMockRequestSave();

-  args_.extra.apps.push_back(CommandLineAppArgs());

-  args_.extra.apps[1].app_guid = StringToGuid(kAppGuid2);

-  args_.extra.apps[1].app_name = _T("App 2");

-  args_.extra.apps[1].needs_admin = true;

-

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));

-

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->error_code());

-

-  VerifyNoUpdateCheckSent();

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallMachineTest, AppEulaNotAccepted) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());

-

-  VerifyInstallUpdateCheck(app_guids_app1());

-  ValidateNoUpdateErrorObserved(job_observer_);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallMachineTest,

-       AppEulaNotAcceptedAndInstallProhibited) {

-  SetMockMockRequestSave();

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->error_code());

-

-  VerifyNoUpdateCheckSent();

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallMachineTest,

-       AppEulaNotAcceptedAndOtherAppInstallProhibited) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID2,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID2,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp2, 0));

-

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());

-

-  VerifyInstallUpdateCheck(app_guids_app1());

-  ValidateNoUpdateErrorObserved(job_observer_);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-//

-// Install Google Update and app tests.

-//

-// We cannot run DoProcess for the InstallGoopdateAndAppsStrategy case because

-// it attempts to install Google Update before checking the Group Policy.

-// Therefore, test RemoveDisallowedApps() directly.

-

-TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest, GroupPolicy_NoPolicy) {

-  EXPECT_SUCCEEDED(worker_job_->strategy()->RemoveDisallowedApps(&products_));

-  EXPECT_EQ(1, products_.size());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest,

-       GroupPolicy_InstallProhibited) {

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));

-

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->strategy()->RemoveDisallowedApps(&products_));

-  EXPECT_TRUE(products_.empty());

-

-  EXPECT_SUCCEEDED(worker_job_->error_code()) <<

-      _T("error_code code does not run.");

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest,

-       GroupPolicy_UpdateProhibited) {

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  EXPECT_SUCCEEDED(worker_job_->strategy()->RemoveDisallowedApps(&products_));

-  EXPECT_EQ(1, products_.size());

-

-  EXPECT_SUCCEEDED(worker_job_->error_code()) <<

-      _T("error_code code does not run.");

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest,

-       GroupPolicy_InstallAndUpdateProhibited) {

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->strategy()->RemoveDisallowedApps(&products_));

-  EXPECT_TRUE(products_.empty());

-

-  EXPECT_SUCCEEDED(worker_job_->error_code()) <<

-      _T("error_code code does not run.");

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest,

-       GroupPolicy_InstallOfDifferentAppProhibited) {

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp2, 0));

-

-  EXPECT_SUCCEEDED(worker_job_->strategy()->RemoveDisallowedApps(&products_));

-  EXPECT_EQ(1, products_.size());

-

-  EXPECT_SUCCEEDED(worker_job_->error_code()) <<

-      _T("error_code code does not run.");

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest,

-       GroupPolicy_InstallTwoAppsOneProhibited) {

-  args_.extra.apps.push_back(CommandLineAppArgs());

-  args_.extra.apps[1].app_guid = StringToGuid(kAppGuid2);

-  args_.extra.apps[1].app_name = _T("App 2");

-  args_.extra.apps[1].needs_admin = true;

-

-  AppData app_data;

-  app_data.set_app_guid(StringToGuid(kAppGuid2));

-  app_data.set_is_machine_app(true);

-  products_.push_back(ProductData(app_data));

-  ASSERT_EQ(2, products_.size());

-

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));

-

-  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,

-            worker_job_->strategy()->RemoveDisallowedApps(&products_));

-  EXPECT_EQ(1, products_.size());  // One of two was removed.

-

-  EXPECT_SUCCEEDED(worker_job_->error_code()) <<

-      _T("error_code code does not run.");

-

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());

-}

-

-//

-// On-demand update tests.

-//

-

-TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest, UpdateCheckFails) {

-  SetMockMockRequestSaveFail();

-

-  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,

-            worker_job_->DoProcess());

-  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,

-            worker_job_->error_code());

-

-  ValidateComFailureObserved(job_observer_->job_observer_mock);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest, GroupPolicy_NoPolicy) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyOnDemandUpdateCheck(app_guids_app1());

-  ValidateComSuccessObserved(job_observer_->job_observer_mock);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,

-       GroupPolicy_InstallProhibited) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyOnDemandUpdateCheck(app_guids_app1());

-  ValidateComSuccessObserved(job_observer_->job_observer_mock);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,

-       GroupPolicy_UpdateProhibited) {

-  SetMockMockRequestSave();

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY, worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY,

-            worker_job_->error_code());

-

-  VerifyNoUpdateCheckSent();

-  ValidateComFailureObserved(job_observer_->job_observer_mock);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,

-       GroupPolicy_ManualUpdateOnly) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 2));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyOnDemandUpdateCheck(app_guids_app1());

-  ValidateComSuccessObserved(job_observer_->job_observer_mock);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,

-       GroupPolicy_InstallAndUpdateProhibited) {

-  SetMockMockRequestSave();

-  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY, worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY,

-            worker_job_->error_code());

-

-  VerifyNoUpdateCheckSent();

-  ValidateComFailureObserved(job_observer_->job_observer_mock);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,

-       GroupPolicy_UpdateOfDifferentAppProhibited) {

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 0));

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyOnDemandUpdateCheck(app_guids_app1());

-  ValidateComSuccessObserved(job_observer_->job_observer_mock);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest, AppEulaNotAccepted) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  worker_job_.reset();

-  EXPECT_SUCCEEDED(WorkerJobFactory::CreateOnDemandWorkerJob(

-      true,   // is_machine

-      false,  // is_update_check_only

-      _T("en"),

-      StringToGuid(kAppGuid),

-      job_holder_,

-      new WorkerComWrapperShutdownCallBack(false),

-      address(worker_job_)));

-  SetMockMockRequestSave();

-

-  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED,

-            worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED,

-            worker_job_->error_code());

-

-  VerifyNoUpdateCheckSent();

-  ValidateComFailureObserved(job_observer_->job_observer_mock);

-  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest, OtherAppEulaNotAccepted) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID2,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID2,

-                                    _T("pv"),

-                                    _T("1.2.3.4")));

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp2,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-

-  worker_job_.reset();

-  EXPECT_SUCCEEDED(WorkerJobFactory::CreateOnDemandWorkerJob(

-      true,   // is_machine

-      false,  // is_update_check_only

-      _T("en"),

-      StringToGuid(kAppGuid),

-      job_holder_,

-      new WorkerComWrapperShutdownCallBack(false),

-      address(worker_job_)));

-  SetMockRequestSaveNoUpdate(app_guids_app1());

-

-  EXPECT_SUCCEEDED(worker_job_->DoProcess());

-  EXPECT_SUCCEEDED(worker_job_->error_code());

-

-  VerifyOnDemandUpdateCheck(app_guids_app1());

-  ValidateComSuccessObserved(job_observer_->job_observer_mock);

-  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// EULA is checked first.

-TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,

-       AppEulaNotAcceptedAndUpdateProhibited) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,

-                                    _T("eulaaccepted"),

-                                    static_cast<DWORD>(0)));

-  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));

-

-  worker_job_.reset();

-  EXPECT_SUCCEEDED(WorkerJobFactory::CreateOnDemandWorkerJob(

-      true,   // is_machine

-      false,  // is_update_check_only

-      _T("en"),

-      StringToGuid(kAppGuid),

-      job_holder_,

-      new WorkerComWrapperShutdownCallBack(false),

-      address(worker_job_)));

-  SetMockMockRequestSave();

-

-  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED,

-            worker_job_->DoProcess());

-  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED,

-            worker_job_->error_code());

-

-  VerifyNoUpdateCheckSent();

-  ValidateComFailureObserved(job_observer_->job_observer_mock);

-  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());

-  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());

-  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());

-}

-

-// TODO(omaha): Add some user tests for the above.

-

-// Create a worker with the /handoff switch and needs_admin=false.

-// Call IsAppInstallWorkerRunning for machine. Should return false.

-TEST_F(WorkerJobIsAppInstallWorkerRunningTest, HandoffNeedsAdminFalseMachine) {

-  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  worker_job_.reset(

-      WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));

-  cmd_line_.Format(_T("%s %s"), handoff_cmd_line, false_extra_args);

-  TestIsAppInstallWorkerRunning(cmd_line_, true, false);

-}

-

-// Create a worker with the /handoff switch and needs_admin=true.

-// Call IsAppInstallWorkerRunning for machine. Should return true.

-TEST_F(WorkerJobIsAppInstallWorkerRunningTest, HandoffNeedsAdminTrueMachine) {

-  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  worker_job_.reset(

-      WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));

-  cmd_line_.Format(_T("%s %s"), handoff_cmd_line, true_extra_args);

-  TestIsAppInstallWorkerRunning(cmd_line_, true, true);

-}

-

-// Create a worker with the /handoff switch and needs_admin=false.

-// Call IsAppInstallWorkerRunning for user. Should return true.

-TEST_F(WorkerJobIsAppInstallWorkerRunningTest, HandoffNeedsAdminFalseUser) {

-  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  worker_job_.reset(

-      WorkerJobFactory::CreateWorkerJob(false, args_, &job_observer_));

-  cmd_line_.Format(_T("%s %s"), handoff_cmd_line, false_extra_args);

-  TestIsAppInstallWorkerRunning(cmd_line_, false, true);

-}

-

-// Create a worker with the /handoff switch and needs_admin=true.

-// Call IsAppInstallWorkerRunning for user. Should return false.

-TEST_F(WorkerJobIsAppInstallWorkerRunningTest, HandoffNeedsAdminTrueUser) {

-  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  worker_job_.reset(

-      WorkerJobFactory::CreateWorkerJob(false, args_, &job_observer_));

-  cmd_line_.Format(_T("%s %s"), handoff_cmd_line, true_extra_args);

-  TestIsAppInstallWorkerRunning(cmd_line_, false, false);

-}

-

-// Create a worker with the /ig switch and needs_admin=false.

-// Call IsAppInstallWorkerRunning for machine. Should return false.

-TEST_F(WorkerJobIsAppInstallWorkerRunningTest, IgNeedsAdminFalseMachine) {

-  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  worker_job_.reset(

-      WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));

-  cmd_line_.Format(_T("%s %s"), finish_setup_cmd_line, false_extra_args);

-  TestIsAppInstallWorkerRunning(cmd_line_, true, false);

-}

-

-// Create a worker with the /ig switch and needs_admin=true.

-// Call IsAppInstallWorkerRunning for machine. Should return true.

-TEST_F(WorkerJobIsAppInstallWorkerRunningTest, IgNeedsAdminTrueMachine) {

-  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  worker_job_.reset(

-      WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));

-  cmd_line_.Format(_T("%s %s"), finish_setup_cmd_line, true_extra_args);

-  TestIsAppInstallWorkerRunning(cmd_line_, true, true);

-}

-

-// Create a worker with the /ig switch and needs_admin=false.

-// Call IsAppInstallWorkerRunning for user. Should return true.

-TEST_F(WorkerJobIsAppInstallWorkerRunningTest, IgNeedsAdminFalseUser) {

-  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  worker_job_.reset(

-      WorkerJobFactory::CreateWorkerJob(false, args_, &job_observer_));

-  cmd_line_.Format(_T("%s %s"), finish_setup_cmd_line, false_extra_args);

-  TestIsAppInstallWorkerRunning(cmd_line_, false, true);

-}

-

-// Create a worker with the /ig switch and needs_admin=true.

-// Call IsAppInstallWorkerRunning for user. Should return false.

-TEST_F(WorkerJobIsAppInstallWorkerRunningTest, IgNeedsAdminTrueUser) {

-  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  worker_job_.reset(

-      WorkerJobFactory::CreateWorkerJob(false, args_, &job_observer_));

-  cmd_line_.Format(_T("%s %s"), finish_setup_cmd_line, true_extra_args);

-  TestIsAppInstallWorkerRunning(cmd_line_, false, false);

-}

-

-TEST_F(WorkerJobIsAppInstallWorkerRunningTest, NoArgsUser) {

-  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  worker_job_.reset(

-      WorkerJobFactory::CreateWorkerJob(false, args_, &job_observer_));

-  TestIsAppInstallWorkerRunning(_T(""), false, false);

-}

-

-TEST_F(WorkerJobIsAppInstallWorkerRunningTest, NoArgsMachine) {

-  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;

-  worker_job_.reset(

-      WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));

-  TestIsAppInstallWorkerRunning(_T(""), true, false);

-}

-

-TEST_F(WorkerJobRegistryProtectedTest,

-       BuildUninstallPing_User_NoUninstalledApp) {

-  ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENT_STATE));

-

-  scoped_ptr<Request> uninstall_ping;

-  EXPECT_HRESULT_SUCCEEDED(BuildUninstallPing(false, address(uninstall_ping)));

-  EXPECT_EQ(0, uninstall_ping->get_request_count());

-}

-

-// Create a mock client state for one app and build an uninstall ping.

-// Expect the client state to be cleared at the end.

-TEST_F(WorkerJobRegistryProtectedTest, BuildUninstallPing_User_UninstalledApp) {

-  CString client_state_appkey(USER_REG_CLIENT_STATE);

-  client_state_appkey.Append(_T("{C78D67E2-D7E9-4b62-9869-FCDCFC4C9323}"));

-  EXPECT_HRESULT_SUCCEEDED(

-    RegKey::SetValue(client_state_appkey, kRegValueProductVersion, _T("1.0")));

-

-  scoped_ptr<Request> uninstall_ping;

-  EXPECT_HRESULT_SUCCEEDED(BuildUninstallPing(false, address(uninstall_ping)));

-  EXPECT_EQ(1, uninstall_ping->get_request_count());

-  EXPECT_EQ(PingEvent::EVENT_UNINSTALL, GetPingType(*uninstall_ping));

-  EXPECT_FALSE(RegKey::HasKey(client_state_appkey));

-}

-

-TEST_F(WorkerJobRegistryProtectedTest,

-       BuildUninstallPing_Machine_NoUninstalledApp) {

-  ASSERT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENT_STATE));

-

-  scoped_ptr<Request> uninstall_ping;

-  EXPECT_HRESULT_SUCCEEDED(BuildUninstallPing(true, address(uninstall_ping)));

-  EXPECT_EQ(0, uninstall_ping->get_request_count());

-}

-

-// Create a mock client state for one app and build an uninstall ping.

-// Expect the client state to be cleared at the end.

-TEST_F(WorkerJobRegistryProtectedTest,

-       BuildUninstallPing_Machine_UninstalledApp) {

-  CString client_state_appkey = MACHINE_REG_CLIENT_STATE;

-  client_state_appkey.Append(_T("{C78D67E2-D7E9-4b62-9869-FCDCFC4C9323}"));

-  EXPECT_HRESULT_SUCCEEDED(

-    RegKey::SetValue(client_state_appkey, kRegValueProductVersion, _T("1.0")));

-

-  scoped_ptr<Request> uninstall_ping;

-  EXPECT_HRESULT_SUCCEEDED(BuildUninstallPing(true, address(uninstall_ping)));

-  EXPECT_EQ(1, uninstall_ping->get_request_count());

-  EXPECT_EQ(PingEvent::EVENT_UNINSTALL, GetPingType(*uninstall_ping));

-  EXPECT_FALSE(RegKey::HasKey(client_state_appkey));

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include <atlbase.h>
+#include <msxml2.h>
+#include "omaha/common/app_util.h"
+#include "omaha/common/error.h"
+#include "omaha/common/omaha_version.h"
+#include "omaha/common/path.h"
+#include "omaha/common/process.h"
+#include "omaha/common/scoped_ptr_address.h"
+#include "omaha/goopdate/config_manager.h"
+#include "omaha/goopdate/const_goopdate.h"
+#include "omaha/goopdate/goopdate_utils.h"
+#include "omaha/goopdate/request.h"
+#include "omaha/goopdate/stats_uploader.h"
+#include "omaha/net/cup_request.h"
+#include "omaha/net/simple_request.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/i_job_observer_mock.h"
+#include "omaha/worker/job_creator.h"
+#include "omaha/worker/job_observer_mock.h"
+#include "omaha/worker/ping_event.h"
+#include "omaha/worker/ping_mock.h"
+#include "omaha/worker/worker_job.h"
+#include "omaha/worker/worker_job_strategy.h"
+#include "omaha/worker/worker_metrics.h"
+
+CComModule module;
+
+namespace omaha {
+
+namespace {
+
+#define APP_GUID _T("{2D8F7DCC-86F9-464c-AF80-B986B551927B}")
+#define APP_GUID2 _T("{7234E9E5-3870-4561-9533-B1D91696A8BA}")
+#define APP_GUID3 _T("{5F5FC3BC-A40E-4dfc-AE0B-FD039A343EE8}")
+const TCHAR* const kAppGuid = APP_GUID;
+const TCHAR* const kAppGuid2 = APP_GUID2;
+const TCHAR* const kAppGuid3 = APP_GUID3;
+
+const TCHAR* const kPolicyKey =
+    _T("HKLM\\Software\\Policies\\Google\\Update\\");
+const TCHAR* const kInstallPolicyApp = _T("Install") APP_GUID;
+const TCHAR* const kUpdatePolicyApp = _T("Update") APP_GUID;
+const TCHAR* const kInstallPolicyApp2 = _T("Install") APP_GUID2;
+const TCHAR* const kUpdatePolicyApp2 = _T("Update") APP_GUID2;
+const TCHAR* const kInstallPolicyApp3 = _T("Install") APP_GUID3;
+const TCHAR* const kUpdatePolicyApp3 = _T("Update") APP_GUID3;
+const TCHAR* const kUpdatePolicyGoopdate = _T("Update") GOOPDATE_APP_ID;
+
+const TCHAR* const kMachineClientStatePathApp =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\") APP_GUID;
+const TCHAR* const kMachineClientStatePathApp2 =
+    _T("HKLM\\Software\\Google\\Update\\ClientState\\") APP_GUID2;
+const TCHAR* const kMachineClientStateMediumPathApp =
+    _T("HKLM\\Software\\Google\\Update\\ClientStateMedium\\") APP_GUID;
+
+const CString handoff_cmd_line(_T("/handoff /lang en"));
+const CString finish_setup_cmd_line(_T("/ig /lang en"));
+const CString false_extra_args(
+    _T("\"appguid={2D8F7DCC-86F9-464c-AF80-B986B551927B}")
+    _T("&appname=FooBar&needsadmin=False\""));
+const CString true_extra_args(
+    _T("\"appguid={2D8F7DCC-86F9-464c-AF80-B986B551927B}")
+    _T("&appname=FooBar&needsadmin=True\""));
+
+// Helper to write policies to the registry. Eliminates ambiguity of which
+// overload of SetValue to use without the need for static_cast.
+HRESULT SetPolicy(const TCHAR* policy_name, DWORD value) {
+  return RegKey::SetValue(kPolicyKey, policy_name, value);
+}
+
+// Returns E_FAIL from SendPing().
+class PingMockFail : public PingMock {
+ public:
+  virtual HRESULT SendPing(Request* req) {
+    VERIFY1(SUCCEEDED(PingMock::SendPing(req)));
+    return E_FAIL;
+  }
+};
+
+// Records the last request buffer and if a request has been sent.
+class MockRequestSave : public SimpleRequest {
+ public:
+  MockRequestSave() : is_sent_(false) {}
+
+  // Sets is_sent and performs the send.
+  virtual HRESULT Send() {
+    is_sent_ = true;
+    return SimpleRequest::Send();
+  }
+
+  // Assumes the buffer is valid UTF-8.
+  virtual void set_request_buffer(const void* buffer, size_t buffer_length) {
+    sent_request_utf8_.SetString(static_cast<const char*>(buffer),
+                                 buffer_length);
+    SimpleRequest::set_request_buffer(buffer, buffer_length);
+  }
+
+  const CStringA& sent_request_utf8() const { return sent_request_utf8_; }
+  bool is_sent() const { return is_sent_; }
+
+ private:
+  CStringA sent_request_utf8_;
+  bool is_sent_;
+};
+
+
+// Performs the Send(), but always returns true and a response with "noupdate"
+// for the specified apps.
+// The actual return value of Send() is inconsistent behavior due to HKLM being
+// overridden because DNS lookup may or may not fail depending on earlier tests.
+class MockRequestSaveNoUpdate : public MockRequestSave {
+ public:
+  explicit MockRequestSaveNoUpdate(
+      const std::vector<CString>& expected_app_guids)
+      : expected_app_guids_(expected_app_guids) {
+  }
+
+  virtual HRESULT Send() {
+    MockRequestSave::Send();
+    return S_OK;
+  }
+
+  virtual int GetHttpStatusCode() const {
+    return 200;
+  }
+
+  virtual std::vector<uint8> GetResponse() const {
+    CStringA no_update_response =
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+        "<gupdate xmlns=\"http://www.google.com/update2/response\" "
+        "protocol=\"2.0\">";
+    for (size_t i = 0; i < expected_app_guids_.size(); ++i) {
+      no_update_response.Append("<app appid=\"");
+      no_update_response.Append(WideToAnsiDirect(expected_app_guids_[i]));
+      no_update_response.Append(
+        "\" status=\"ok\">"
+        "  <updatecheck status=\"noupdate\"/><ping status=\"ok\"/>"
+        "</app>");
+    }
+    no_update_response.Append("</gupdate>");
+
+    const size_t response_length = strlen(no_update_response) + 1;
+    std::vector<uint8> response;
+    response.resize(response_length);
+    EXPECT_EQ(0, memcpy_s(&response[0],
+                          response_length,
+                          no_update_response,
+                          response_length));
+    return response;
+  }
+
+ private:
+  std::vector<CString> expected_app_guids_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MockRequestSaveNoUpdate);
+};
+
+// Returns kUpdateCheckForcedFailure from Send().
+class MockRequestSaveFail : public MockRequestSave {
+ public:
+  // Performs the send and fails with kUpdateCheckForcedFailure regardless of
+  // the result.
+  virtual HRESULT Send() {
+    MockRequestSave::Send();
+    return kUpdateCheckForcedFailure;
+  }
+
+  static const HRESULT kUpdateCheckForcedFailure = 0x81234567;
+};
+
+void VerifyUpdateCheckInRequest(const std::vector<CString>& expected_app_guids,
+                                const std::vector<CString>& disabled_app_guids,
+                                const CStringA& request_utf8,
+                                bool is_install,
+                                bool is_on_demand) {
+  EXPECT_NE(0, expected_app_guids.size());
+  const char* kOmahaRequestUpdate =
+      "<o:app appid=\"{430FD4D0-B729-4F61-AA34-91526481799D}\" "
+      "version=\"5.6.7.8\" lang=\"\" brand=\"\" client=\"\"><o:updatecheck/>"
+      "</o:app>";
+
+  // The 'c' in "464c" element of the app GUID is capitalized in the request.
+  const char* kAppRequestFormat=
+      "<o:app appid=\"%s\" "
+      "version=\"%s\" lang=\"\" brand=\"\" client=\"\"%s><o:updatecheck%s/>"
+      "</o:app>";
+
+  EXPECT_EQ(0, request_utf8.Find(
+      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+      "<o:gupdate xmlns:o=\"http://www.google.com/update2/request\" "
+      "protocol=\"2.0\" version=\"1.2."));
+  EXPECT_NE(-1, request_utf8.Find("\" ismachine=\"1\" machineid=\"{"));
+  EXPECT_NE(-1, request_utf8.Find("}\" userid=\"{"));
+  EXPECT_NE(-1, request_utf8.Find("\" requestid=\"{"));
+  EXPECT_NE(-1, request_utf8.Find("}\"><o:os platform=\"win\" version=\""));
+  EXPECT_NE(-1, request_utf8.Find("\" sp=\""));
+  EXPECT_NE(-1, request_utf8.Find("\"/><o:app"));
+
+  // Verify the expected number of app elements.
+  int app_element_index = request_utf8.Find("<o:app");
+  int num_app_elements = 0;
+  while (-1 != app_element_index) {
+    num_app_elements++;
+    app_element_index = request_utf8.Find("<o:app", app_element_index + 1);
+  }
+  EXPECT_EQ(num_app_elements, expected_app_guids.size());
+
+  for (size_t i = 0; i < expected_app_guids.size(); ++i) {
+    const CString& expected_app = expected_app_guids[i];
+
+    bool is_disabled_expected = false;
+    for (size_t j = 0; j < disabled_app_guids.size(); ++j) {
+      if (expected_app == disabled_app_guids[j]) {
+        is_disabled_expected = true;
+        break;
+      }
+    }
+
+    if (expected_app == kGoogleUpdateAppId) {
+      ASSERT1(!is_on_demand && !is_install);
+      EXPECT_NE(-1, request_utf8.Find(kOmahaRequestUpdate));
+    } else {
+      ASSERT1(expected_app == kAppGuid || expected_app == kAppGuid2);
+      const CStringA app_guid = WideToAnsiDirect(expected_app == kAppGuid ?
+                                                 CString(kAppGuid).MakeUpper() :
+                                                 kAppGuid2);
+      CStringA expected_app_element;
+      expected_app_element.Format(
+          kAppRequestFormat,
+          app_guid,
+          is_install ? "" : "1.2.3.4",
+          is_on_demand ? " installsource=\"ondemandupdate\"" : "",
+          is_disabled_expected ? " updatedisabled=\"true\"" : "");
+      EXPECT_NE(-1, request_utf8.Find(expected_app_element)) <<
+          _T("Expected: ") <<
+          Utf8ToWideChar(expected_app_element.GetString(),
+                         expected_app_element.GetLength()).GetString() <<
+          std::endl << _T("In: ") <<
+          Utf8ToWideChar(request_utf8.GetString(),
+                         request_utf8.GetLength()).GetString() << std::endl;
+    }
+  }
+
+  EXPECT_NE(-1, request_utf8.Find("</o:app></o:gupdate>"));
+
+  EXPECT_FALSE(::testing::Test::HasFailure()) <<
+      _T("Actual Request: ") << request_utf8;
+}
+
+}  // namespace
+
+class WorkerJobTest : public testing::Test {
+ protected:
+  WorkerJobTest()
+      : mock_network_request_(NULL),
+        mock_encryped_request_(NULL) {
+    exe_to_test_ = ConcatenatePath(
+        app_util::GetCurrentModuleDirectory(),
+        _T("unittest_support\\does_not_shutdown\\GoogleUpdate.exe"));
+  }
+
+  void SetIsMachine(bool is_machine) {
+    worker_job_->is_machine_ = is_machine;
+  }
+
+  bool IsAppInstallWorkerRunning() {
+    return goopdate_utils::IsAppInstallWorkerRunning(worker_job_->is_machine_);
+  }
+
+  PingEvent::Types GetPingType(const Request& request) {
+    const AppRequest& app_request = *(request.app_requests_begin());
+    const AppRequestData& app_request_data = app_request.request_data();
+    const PingEvent& ping_event = *(app_request_data.ping_events_begin());
+    return ping_event.event_type();
+  }
+
+  void SetWorkerJobPing(Ping* ping) {
+    worker_job_->ping_.reset(ping);
+  }
+
+  // Sets WorkerJob to use MockRequestSave for all types of requests.
+  void SetMockMockRequestSave() {
+    SetMockRequest(new MockRequestSave, new MockRequestSave);
+  }
+
+  // Sets WorkerJob to use MockRequestSaveNoUpdate for all types of requests.
+  void SetMockRequestSaveNoUpdate(
+      const std::vector<CString>& expected_app_guids) {
+    SetMockRequest(new MockRequestSaveNoUpdate(expected_app_guids),
+                   new MockRequestSaveNoUpdate(expected_app_guids));
+  }
+
+  // Sets WorkerJob to use MockRequestSaveFail for all types of requests.
+  void SetMockMockRequestSaveFail() {
+    SetMockRequest(new MockRequestSaveFail, new MockRequestSaveFail);
+  }
+
+  // Sets WorkerJob to use the specified HTTP request objects.
+  // Prevents multiple calls to the mock request by specifying the Config and
+  // avoiding auto-detection.
+  void SetMockRequest(MockRequestSave* normal_request,
+                      MockRequestSave* encryped_request) {
+    ASSERT1(worker_job_.get());
+    const NetworkConfig::Session& session(NetworkConfig::Instance().session());
+    const Config config;
+
+    mock_network_request_ = normal_request;
+    mock_encryped_request_ = encryped_request;
+
+    worker_job_->network_request_.reset(new NetworkRequest(session));
+    worker_job_->network_request_->set_network_configuration(&config);
+    worker_job_->network_request_->AddHttpRequest(normal_request);
+
+    worker_job_->network_request_encrypted_.reset(new NetworkRequest(session));
+    worker_job_->network_request_encrypted_->set_network_configuration(&config);
+    worker_job_->network_request_encrypted_->AddHttpRequest(
+        encryped_request);
+  }
+
+  void VerifyInstallUpdateCheck(
+      const std::vector<CString>& expected_app_guids) const {
+    ASSERT1(mock_network_request_ && mock_encryped_request_);
+    EXPECT_TRUE(mock_network_request_->is_sent());
+    VerifyUpdateCheckInRequest(expected_app_guids,
+                               std::vector<CString>(),
+                               mock_network_request_->sent_request_utf8(),
+                               true,
+                               false);
+    EXPECT_FALSE(mock_encryped_request_->is_sent());
+  }
+
+  void VerifyAutoUpdateCheckWithDisabledApps(
+      const std::vector<CString>& expected_app_guids,
+      const std::vector<CString>& disabled_app_guids) const {
+    ASSERT1(mock_network_request_ && mock_encryped_request_);
+    EXPECT_TRUE(mock_network_request_->is_sent());
+    VerifyUpdateCheckInRequest(expected_app_guids,
+                               disabled_app_guids,
+                               mock_network_request_->sent_request_utf8(),
+                               false,
+                               false);
+    EXPECT_FALSE(mock_encryped_request_->is_sent());
+  }
+
+  void VerifyAutoUpdateCheck(
+      const std::vector<CString>& expected_app_guids) const {
+      VerifyAutoUpdateCheckWithDisabledApps(expected_app_guids,
+                                            std::vector<CString>());
+  }
+
+  void VerifyOnDemandUpdateCheck(
+      const std::vector<CString>& expected_app_guids) const {
+    ASSERT1(mock_network_request_ && mock_encryped_request_);
+    EXPECT_TRUE(mock_network_request_->is_sent());
+    VerifyUpdateCheckInRequest(expected_app_guids,
+                               std::vector<CString>(),
+                               mock_network_request_->sent_request_utf8(),
+                               false,
+                               true);
+    EXPECT_FALSE(mock_encryped_request_->is_sent());
+  }
+
+  void VerifyNoUpdateCheckSent() const {
+    ASSERT1(mock_network_request_ && mock_encryped_request_);
+    EXPECT_FALSE(mock_network_request_->is_sent());
+    EXPECT_FALSE(mock_encryped_request_->is_sent());
+  }
+
+  scoped_ptr<WorkerJob> worker_job_;
+  CString exe_to_test_;
+  MockRequestSave* mock_network_request_;
+  MockRequestSave* mock_encryped_request_;
+};
+
+class WorkerJobRegistryProtectedTest : public WorkerJobTest {
+ protected:
+  WorkerJobRegistryProtectedTest()
+      : hive_override_key_name_(kRegistryHiveOverrideRoot), xml_cookie_(0) {
+  }
+
+  virtual void SetUp() {
+    // Registers the MSXML CoClass before doing registry redirection. Without
+    // this registration, CoCreation of the DOMDocument2 within the test would
+    // fail on Vista, as a side-effect of the registry redirection.
+    CComPtr<IClassFactory> factory;
+    EXPECT_SUCCEEDED(::CoGetClassObject(__uuidof(DOMDocument2),
+                                        CLSCTX_INPROC_SERVER,
+                                        NULL,
+                                        IID_IClassFactory,
+                                        reinterpret_cast<void**>(&factory)));
+    EXPECT_SUCCEEDED(::CoRegisterClassObject(__uuidof(DOMDocument2),
+                                             factory,
+                                             CLSCTX_INPROC_SERVER,
+                                             REGCLS_MULTIPLEUSE,
+                                             &xml_cookie_));
+    RegKey::DeleteKey(hive_override_key_name_, true);
+    OverrideRegistryHives(hive_override_key_name_);
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    EXPECT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true));
+    if (xml_cookie_) {
+      EXPECT_SUCCEEDED(::CoRevokeClassObject(xml_cookie_));
+    }
+  }
+
+  CString hive_override_key_name_;
+  DWORD xml_cookie_;
+};
+
+class WorkerJobDoProcessTest : public WorkerJobRegistryProtectedTest {
+ protected:
+  // Must be re-entrant for statics because it is called once for each subclass.
+  static void SetUpTestCase() {
+    // Initialize the global metrics collection.
+    stats_report::g_global_metrics.Initialize();
+
+    if (app_guids_omaha_.empty()) {
+      app_guids_omaha_.push_back(kGoogleUpdateAppId);
+    }
+
+    if (app_guids_omaha_app1_.empty()) {
+      app_guids_omaha_app1_ = app_guids_omaha_;
+      app_guids_omaha_app1_.push_back(kAppGuid);
+    }
+
+    if (app_guids_omaha_app2_.empty()) {
+      app_guids_omaha_app2_ = app_guids_omaha_;
+      app_guids_omaha_app2_.push_back(kAppGuid2);
+    }
+
+    if (app_guids_omaha_app1_app2_.empty()) {
+      app_guids_omaha_app1_app2_ = app_guids_omaha_app1_;
+      app_guids_omaha_app1_app2_ .push_back(kAppGuid2);
+    }
+
+    if (app_guids_app1_.empty()) {
+      app_guids_app1_.push_back(kAppGuid);
+    }
+
+    if (app_guids_app2_.empty()) {
+      app_guids_app2_.push_back(kAppGuid2);
+    }
+  }
+
+  static void TearDownTestCase() {
+    // The global metrics collection must be uninitialized before the metrics
+    // destructors are called.
+    stats_report::g_global_metrics.Uninitialize();
+  }
+
+  virtual void SetUp() {
+    WorkerJobRegistryProtectedTest::SetUp();
+#ifdef _DEBUG
+    // There is an assert that expects this value to be set.
+    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                      kRegValueInstalledVersion,
+                                      GetVersionString()));
+#endif
+    metric_worker_apps_not_updated_eula.Set(0);
+    metric_worker_apps_not_updated_group_policy.Set(0);
+    metric_worker_apps_not_installed_group_policy.Set(0);
+  }
+
+  // These tests cause the action to fail. This method validates the app request
+  // for an individual app generated by
+  // ping_utils::SendCompletedPingsForAllProducts().
+  // The expected ping data depends on whether the WorkerJob was canceled.
+  static void ValidateCompletedPingForProduct(const AppRequest& app_request,
+                                              const GUID& expected_app_id,
+                                              bool is_canceled) {
+    const PingEvent& ping_event = GetSingleEventFromAppRequest(app_request,
+                                                               expected_app_id,
+                                                               true);
+    EXPECT_EQ(PingEvent::EVENT_UPDATE_COMPLETE, ping_event.event_type());
+    EXPECT_EQ(is_canceled ? PingEvent::EVENT_RESULT_CANCELLED :
+                            PingEvent::EVENT_RESULT_ERROR,
+              ping_event.event_result());
+    EXPECT_EQ(is_canceled ? GOOPDATE_E_WORKER_CANCELLED :
+                            MockRequestSaveFail::kUpdateCheckForcedFailure,
+              ping_event.error_code());
+    EXPECT_EQ(0x100000ff, ping_event.extra_code1());
+
+    EXPECT_EQ(::IsEqualGUID(kGoopdateGuid, expected_app_id) ? _T("5.6.7.8") :
+                                                              _T("1.2.3.4"),
+              ping_event.previous_version());
+  }
+
+  // TODO(omaha): I think this is a bug that we ping without an event.
+  // If not, fix this and replace this method with a check for no pings.
+  static void ValidateNoPingEventForProduct(const AppRequest& app_request,
+                                            const GUID& expected_app_id) {
+    const AppRequestData& app_request_data = app_request.request_data();
+
+    const AppData& app_data = app_request_data.app_data();
+    EXPECT_TRUE(::IsEqualGUID(expected_app_id, app_data.app_guid()));
+    EXPECT_TRUE(::IsEqualGUID(GUID_NULL, app_data.parent_app_guid()));
+    EXPECT_EQ(true, app_data.is_machine_app());
+    EXPECT_TRUE(!app_data.version().IsEmpty());
+    EXPECT_TRUE(!app_data.previous_version().IsEmpty());
+
+    EXPECT_EQ(0, app_request_data.num_ping_events());
+  }
+
+  static void ValidateForcedFailureObserved(
+      const JobObserverMock& job_observer) {
+    EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer.completion_code);
+    EXPECT_STREQ(_T("Installation failed. Please try again. Error code = ")
+                 _T("0x81234567"), job_observer.completion_text);
+    EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,
+              job_observer.completion_error_code);
+  }
+
+  static void ValidateNoEventObserved(
+      const JobObserverMock& job_observer) {
+    EXPECT_EQ(static_cast<CompletionCodes>(-1), job_observer.completion_code);
+    EXPECT_TRUE(job_observer.completion_text.IsEmpty());
+    EXPECT_EQ(0, job_observer.completion_error_code);
+  }
+
+  // Only applies to installs.
+  static void ValidateNoUpdateErrorObserved(
+      const JobObserverMock& job_observer) {
+    EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer.completion_code);
+    EXPECT_STREQ(_T("Installation failed. Please try again. Error code = ")
+                 _T("0x80040809"), job_observer.completion_text);
+    EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE,
+              job_observer.completion_error_code);
+  }
+
+  // JobObserverCOMDecorator does not pass along the text and the COM interface
+  // does not support passing the error code so the COM mock sets E_UNEXPECTED.
+  static void ValidateComFailureObserved(
+      const JobObserverMock& job_observer) {
+    EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer.completion_code);
+    EXPECT_TRUE(job_observer.completion_text.IsEmpty());
+    EXPECT_EQ(E_UNEXPECTED, job_observer.completion_error_code);
+  }
+
+  static void ValidateComSuccessObserved(
+      const JobObserverMock& job_observer) {
+    EXPECT_EQ(COMPLETION_CODE_SUCCESS, job_observer.completion_code);
+    EXPECT_TRUE(job_observer.completion_text.IsEmpty());
+    EXPECT_EQ(E_UNEXPECTED, job_observer.completion_error_code);
+  }
+
+  const std::vector<CString>& app_guids_omaha() const {
+      return app_guids_omaha_;
+  }
+  const std::vector<CString>& app_guids_omaha_app1() const {
+      return app_guids_omaha_app1_;
+  }
+  const std::vector<CString>& app_guids_omaha_app2() const {
+      return app_guids_omaha_app2_;
+  }
+  const std::vector<CString>& app_guids_omaha_app1_app2() const {
+      return app_guids_omaha_app1_app2_;
+  }
+  const std::vector<CString>& app_guids_app1() const { return app_guids_app1_; }
+  const std::vector<CString>& app_guids_app2() const { return app_guids_app2_; }
+
+ private:
+  static std::vector<CString> app_guids_omaha_;
+  static std::vector<CString> app_guids_omaha_app1_;
+  static std::vector<CString> app_guids_omaha_app2_;
+  static std::vector<CString> app_guids_omaha_app1_app2_;
+  static std::vector<CString> app_guids_app1_;
+  static std::vector<CString> app_guids_app2_;
+};
+
+std::vector<CString> WorkerJobDoProcessTest::app_guids_omaha_;
+std::vector<CString> WorkerJobDoProcessTest::app_guids_omaha_app1_;
+std::vector<CString> WorkerJobDoProcessTest::app_guids_omaha_app2_;
+std::vector<CString> WorkerJobDoProcessTest::app_guids_omaha_app1_app2_;
+std::vector<CString> WorkerJobDoProcessTest::app_guids_app1_;
+std::vector<CString> WorkerJobDoProcessTest::app_guids_app2_;
+
+class WorkerJobDoProcessUpdateMachineTest : public WorkerJobDoProcessTest {
+ protected:
+  virtual void SetUp() {
+    WorkerJobDoProcessTest::SetUp();
+
+    // Omaha is always registered.
+    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS_GOOPDATE,
+                                      _T("pv"),
+                                      _T("5.6.7.8")));
+    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE_GOOPDATE,
+                                      _T("pv"),
+                                      _T("5.6.7.8")));
+
+    // Register the product to check for updates.
+    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID,
+                                      _T("pv"),
+                                      _T("1.2.3.4")));
+    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID,
+                                      _T("pv"),
+                                      _T("1.2.3.4")));
+
+    args_.mode = COMMANDLINE_MODE_UA;
+    worker_job_.reset(
+        WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));
+
+    ping_mock_ = new PingMock;
+    SetWorkerJobPing(ping_mock_);
+  }
+
+  // These tests cause the action to fail. This method validates the ping
+  // generated by ping_utils::SendCompletedPingsForAllProducts().
+  void ValidateCompletedPingsForAllProducts(const Request& ping_request,
+                                            bool is_canceled) {
+    EXPECT_TRUE(ping_request.is_machine());
+    EXPECT_EQ(2, ping_request.get_request_count());
+
+    AppRequestVector::const_iterator iter = ping_request.app_requests_begin();
+    ValidateCompletedPingForProduct(*iter, StringToGuid(kAppGuid), is_canceled);
+
+    ++iter;
+    ValidateCompletedPingForProduct(*iter, kGoopdateGuid, is_canceled);
+    StringToGuid(kAppGuid);
+  }
+
+  // TODO(omaha): I think this is a bug that we ping without an event.
+  // If not, fix this and replace this method with a check for no pings.
+  void ValidateNoPingEventForAllProducts(const Request& ping_request) {
+    EXPECT_TRUE(ping_request.is_machine());
+    EXPECT_EQ(2, ping_request.get_request_count());
+
+    AppRequestVector::const_iterator iter = ping_request.app_requests_begin();
+    ValidateNoPingEventForProduct(*iter, StringToGuid(kAppGuid));
+
+    ++iter;
+    ValidateNoPingEventForProduct(*iter, kGoopdateGuid);
+    StringToGuid(kAppGuid);
+  }
+
+  CommandLineArgs args_;
+  JobObserverMock job_observer_;
+  PingMock* ping_mock_;
+};
+
+class WorkerJobDoProcessInstallMachineTest : public WorkerJobDoProcessTest {
+ protected:
+  virtual void SetUp() {
+    WorkerJobDoProcessTest::SetUp();
+
+    args_.is_silent_set = true;  // Prevent browser from launching on errors.
+    args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+    args_.extra.apps.push_back(CommandLineAppArgs());
+    args_.extra.apps[0].app_guid = StringToGuid(kAppGuid);
+    args_.extra.apps[0].app_name = _T("Foo Bar");
+    args_.extra.apps[0].needs_admin = true;
+
+    worker_job_.reset(
+        WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));
+  }
+
+  CommandLineArgs args_;
+  JobObserverMock job_observer_;
+};
+
+class WorkerJobDoProcessInstallGoogleUpdateMachineTest
+    : public WorkerJobDoProcessTest {
+ protected:
+  virtual void SetUp() {
+    WorkerJobDoProcessTest::SetUp();
+
+    args_.is_silent_set = true;  // Prevent browser from launching on errors.
+    args_.mode = COMMANDLINE_MODE_IG;
+    args_.extra.apps.push_back(CommandLineAppArgs());
+    args_.extra.apps[0].app_guid = StringToGuid(kAppGuid);
+    args_.extra.apps[0].needs_admin = true;
+
+    AppData app_data;
+    app_data.set_app_guid(StringToGuid(kAppGuid));
+    app_data.set_is_machine_app(true);
+    products_.push_back(ProductData(app_data));
+
+    worker_job_.reset(
+        WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));
+  }
+
+  CommandLineArgs args_;
+  ProductDataVector products_;
+  JobObserverMock job_observer_;
+};
+
+class WorkerJobDoProcessOnDemandUpdateMachineTest
+    : public WorkerJobDoProcessTest {
+ protected:
+  virtual void SetUp() {
+    WorkerJobDoProcessTest::SetUp();
+
+    // Register the product as required by OnDemandUpdateStrategy::Init().
+    ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID,
+                                      _T("pv"),
+                                      _T("1.2.3.4")));
+
+    HRESULT hr = CComObject<IJobObserverMock>::CreateInstance(&job_observer_);
+    ASSERT_EQ(S_OK, hr);
+    job_holder_ = job_observer_;
+
+    worker_job_.reset();
+    ASSERT_SUCCEEDED(WorkerJobFactory::CreateOnDemandWorkerJob(
+        true,   // is_machine
+        false,  // is_update_check_only
+        _T("en"),
+        StringToGuid(kAppGuid),
+        job_holder_,
+        new WorkerComWrapperShutdownCallBack(false),
+        address(worker_job_)));
+  }
+
+  CComObject<IJobObserverMock>* job_observer_;
+  CComPtr<IJobObserver> job_holder_;
+};
+
+class WorkerJobIsAppInstallWorkerRunningTest : public WorkerJobTest {
+ protected:
+  WorkerJobIsAppInstallWorkerRunningTest() {
+    args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+    CommandLineAppArgs app_args;
+    app_args.app_name = _T("WorkerJobIsAppInstallWorkerRunningTest");
+    args_.extra.apps.push_back(app_args);
+  }
+
+  void TestIsAppInstallWorkerRunning(const CString& cmd_line,
+                                     bool is_machine,
+                                     bool expected_running) {
+    Process p(exe_to_test_, NULL);
+    ASSERT_TRUE(p.Start(cmd_line));
+
+    // Wait for the process to be ready. IsAppInstallWorkerRunning uses
+    // Process::GetCommandLine, which fails if it cannot ::ReadProcessMemory().
+    // Waiting for GetCommandLine() to succeed should ensure that the process is
+    // sufficiently initialized for this test.
+    // TODO(omaha): If we change to using Job Objects, we will not need this
+    // if we use ::AssignProcessToJobObject() from this test.
+    HRESULT hr = E_FAIL;
+    CString process_cmd;
+    for (int tries = 0; tries < 100 && FAILED(hr); ++tries) {
+      ::Sleep(50);
+      hr = Process::GetCommandLine(p.GetId(), &process_cmd);
+    }
+    EXPECT_SUCCEEDED(hr);
+
+    SetIsMachine(is_machine);
+    EXPECT_EQ(expected_running, IsAppInstallWorkerRunning());
+    EXPECT_TRUE(p.Terminate(1000));
+  }
+
+  CommandLineArgs args_;
+  CString cmd_line_;
+  JobObserverMock job_observer_;
+};
+
+// TODO(omaha): Test all methods of WorkerJob.
+
+TEST_F(WorkerJobDoProcessTest, OnDemandUpdate_AppNotRegistered) {
+  CComObject<IJobObserverMock>* job_observer;
+  CComPtr<IJobObserver> job_holder;
+
+  HRESULT hr = CComObject<IJobObserverMock>::CreateInstance(&job_observer);
+  ASSERT_EQ(S_OK, hr);
+  job_holder = job_observer;
+
+  worker_job_.reset();
+  EXPECT_EQ(GOOPDATE_E_APP_NOT_REGISTERED,
+      WorkerJobFactory::CreateOnDemandWorkerJob(
+      true,   // is_machine
+      false,  // is_update_check_only
+      _T("en"),
+      StringToGuid(kAppGuid),
+      job_holder,
+      new WorkerComWrapperShutdownCallBack(false),
+      address(worker_job_)));
+}
+
+//
+// Update apps tests.
+//
+
+// Also tests that the OemInstallPing is not sent.
+TEST_F(WorkerJobDoProcessUpdateMachineTest, UpdateCheckFails) {
+  SetMockMockRequestSaveFail();
+
+  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,
+            worker_job_->DoProcess());
+  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,
+            worker_job_->error_code());
+
+  ValidateForcedFailureObserved(job_observer_);
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  ValidateCompletedPingsForAllProducts(*ping_mock_->ping_requests()[0], false);
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// Also tests that the OemInstallPing is not sent.
+TEST_F(WorkerJobDoProcessUpdateMachineTest, GroupPolicy_NoPolicy) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheck(app_guids_omaha_app1());
+  ValidateNoEventObserved(job_observer_);
+
+  // TODO(omaha): I don't think there should be any pings.
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessUpdateMachineTest, GroupPolicy_InstallProhibited) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheck(app_guids_omaha_app1());
+  ValidateNoEventObserved(job_observer_);
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessUpdateMachineTest,
+       GroupPolicy_UpdateProhibitedForSingleApp) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheckWithDisabledApps(app_guids_omaha_app1(),
+                                        app_guids_app1());
+  ValidateNoEventObserved(job_observer_);
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessUpdateMachineTest,
+       GroupPolicy_ManualUpdateOnlyForSingleApp) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 2));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheckWithDisabledApps(app_guids_omaha_app1(),
+                                        app_guids_app1());
+  ValidateNoEventObserved(job_observer_);
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// Use the default behavior when the value is not supported.
+TEST_F(WorkerJobDoProcessUpdateMachineTest, GroupPolicy_InvalidUpdateValue) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 3));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheck(app_guids_omaha_app1());
+  ValidateNoEventObserved(job_observer_);
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// Omaha updates will always be performed.
+TEST_F(WorkerJobDoProcessUpdateMachineTest,
+       GroupPolicy_UpdateProhibitedForOmahaAndAllApps) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyGoopdate, 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheckWithDisabledApps(app_guids_omaha_app1(),
+                                        app_guids_app1());
+  ValidateNoEventObserved(job_observer_);
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// This case should not happen because Omaha is not registered.
+TEST_F(WorkerJobDoProcessUpdateMachineTest,
+       GroupPolicy_UpdateProhibitedForAllRegisteredApps) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+  ASSERT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_CLIENTS_GOOPDATE, _T("pv")));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheckWithDisabledApps(app_guids_app1(), app_guids_app1());
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  const Request& ping_request = *ping_mock_->ping_requests()[0];
+  EXPECT_TRUE(ping_request.is_machine());
+  EXPECT_EQ(1, ping_request.get_request_count());
+  ValidateNoPingEventForProduct(*ping_request.app_requests_begin(),
+                                StringToGuid(kAppGuid));
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// This case should not happen because Omaha is not registered.
+TEST_F(WorkerJobDoProcessUpdateMachineTest,
+       GroupPolicy_UpdateProhibitedForAllAppsByPolicyOrEula) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+  ASSERT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_CLIENTS_GOOPDATE, _T("pv")));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID2,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID2,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp2,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheckWithDisabledApps(app_guids_app1(), app_guids_app1());
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  const Request& ping_request = *ping_mock_->ping_requests()[0];
+  EXPECT_TRUE(ping_request.is_machine());
+  EXPECT_EQ(1, ping_request.get_request_count());
+  ValidateNoPingEventForProduct(*ping_request.app_requests_begin(),
+                                StringToGuid(kAppGuid));
+
+  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// Although a ping request is received, the real Ping object would not send it.
+TEST_F(WorkerJobDoProcessUpdateMachineTest, GoogleUpdateEulaNotAccepted) {
+  SetMockMockRequestSave();
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_EQ(GOOPDATE_E_CANNOT_USE_NETWORK, worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_CANNOT_USE_NETWORK, worker_job_->error_code());
+
+  VerifyNoUpdateCheckSent();
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessUpdateMachineTest, AppEulaNotAccepted) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID2,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID2,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp2,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheck(app_guids_omaha_app1());
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  // Update checks are sent for Omaha and App1 but not App2.
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);
+
+  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessUpdateMachineTest, AppEulaAcceptedInClientState) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheck(app_guids_omaha_app1());
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessUpdateMachineTest,
+       AppEulaNotAcceptedInClientStateButIsInClientStateMedium) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStateMediumPathApp,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(1)));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheck(app_guids_omaha_app1());
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[0]);
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// EULA is checked first.
+TEST_F(WorkerJobDoProcessUpdateMachineTest,
+       AppEulaNotAcceptedAndUpdateProhibited) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha());
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheck(app_guids_omaha());
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+
+  // Only Omaha is in the completed ping because the app is disabled by EULA.
+  const Request& ping_request = *ping_mock_->ping_requests()[0];
+  EXPECT_TRUE(ping_request.is_machine());
+  EXPECT_EQ(1, ping_request.get_request_count());
+  ValidateNoPingEventForProduct(*ping_request.app_requests_begin(),
+                                kGoopdateGuid);
+
+  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessUpdateMachineTest,
+       AppEulaNotAcceptedOtherAppUpdateProhibited) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app2());
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID2,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID2,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 0));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheckWithDisabledApps(app_guids_omaha_app2(),
+                                        app_guids_app2());
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+
+  // Only Omaha is in the completed ping because both apps are disabled.
+  const Request& ping_request = *ping_mock_->ping_requests()[0];
+  EXPECT_TRUE(ping_request.is_machine());
+  EXPECT_EQ(2, ping_request.get_request_count());
+  ValidateNoPingEventForProduct(*ping_request.app_requests_begin(),
+                                kGoopdateGuid);
+  ValidateNoPingEventForProduct(*(++ping_request.app_requests_begin()),
+                                StringToGuid(kAppGuid2));
+
+  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessUpdateMachineTest, OemInstallPing) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID,
+                                    _T("oeminstall"),
+                                    _T("1")));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheck(app_guids_omaha_app1());
+
+  ASSERT_EQ(2, ping_mock_->ping_requests().size());
+
+  const PingEvent& ping_event = GetSingleEventFromRequest(
+      *ping_mock_->ping_requests()[0],
+      StringToGuid(kAppGuid),
+      true);
+  EXPECT_EQ(PingEvent::EVENT_INSTALL_OEM_FIRST_CHECK, ping_event.event_type());
+  EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, ping_event.event_result());
+  EXPECT_EQ(0, ping_event.error_code());
+  EXPECT_EQ(0, ping_event.extra_code1());
+  EXPECT_EQ(_T("1.2.3.4"), ping_event.previous_version());
+
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[1]);
+
+  EXPECT_FALSE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE APP_GUID,
+                                _T("oeminstall")));
+}
+
+TEST_F(WorkerJobDoProcessUpdateMachineTest, OemInstallPing_Failed) {
+  SetMockRequestSaveNoUpdate(app_guids_omaha_app1());
+  ping_mock_ = new PingMockFail();
+  SetWorkerJobPing(ping_mock_);
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID,
+                                    _T("oeminstall"),
+                                    _T("1")));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyAutoUpdateCheck(app_guids_omaha_app1());
+
+  ASSERT_EQ(2, ping_mock_->ping_requests().size());
+
+  const PingEvent& ping_event = GetSingleEventFromRequest(
+      *ping_mock_->ping_requests()[0],
+      StringToGuid(kAppGuid),
+      true);
+  EXPECT_EQ(PingEvent::EVENT_INSTALL_OEM_FIRST_CHECK, ping_event.event_type());
+  EXPECT_EQ(PingEvent::EVENT_RESULT_SUCCESS, ping_event.event_result());
+  EXPECT_EQ(0, ping_event.error_code());
+  EXPECT_EQ(0, ping_event.extra_code1());
+  EXPECT_EQ(_T("1.2.3.4"), ping_event.previous_version());
+
+  ValidateNoPingEventForAllProducts(*ping_mock_->ping_requests()[1]);
+
+  EXPECT_TRUE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE APP_GUID,
+                               _T("oeminstall")));
+}
+
+TEST_F(WorkerJobDoProcessUpdateMachineTest, OemInstallPing_WorkerJobCanceled) {
+  SetMockMockRequestSave();
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID,
+                                    _T("oeminstall"),
+                                    _T("1")));
+  worker_job_->Cancel();
+
+  EXPECT_EQ(GOOPDATE_E_WORKER_CANCELLED, worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_WORKER_CANCELLED, worker_job_->error_code());
+
+  VerifyNoUpdateCheckSent();
+
+  ASSERT_EQ(1, ping_mock_->ping_requests().size());
+  ValidateCompletedPingsForAllProducts(*ping_mock_->ping_requests()[0], true);
+
+  EXPECT_TRUE(RegKey::HasValue(MACHINE_REG_CLIENT_STATE APP_GUID,
+                               _T("oeminstall")));
+}
+
+//
+// Install tests.
+//
+
+TEST_F(WorkerJobDoProcessInstallMachineTest, UpdateCheckFails) {
+  SetMockMockRequestSaveFail();
+
+  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,
+            worker_job_->DoProcess());
+  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,
+            worker_job_->error_code());
+
+  ValidateForcedFailureObserved(job_observer_);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallMachineTest, GroupPolicy_NoPolicy) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());
+
+  VerifyInstallUpdateCheck(app_guids_app1());
+  ValidateNoUpdateErrorObserved(job_observer_);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallMachineTest, GroupPolicy_InstallProhibited) {
+  SetMockMockRequestSave();
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));
+
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->error_code());
+
+  EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer_.completion_code);
+  EXPECT_STREQ(_T("Your network administrator has applied a Group Policy that ")
+               _T("prevents installation of Foo Bar."),
+               job_observer_.completion_text);
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            job_observer_.completion_error_code);
+
+  VerifyNoUpdateCheckSent();
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// Use the default behavior when the value is not supported.
+TEST_F(WorkerJobDoProcessInstallMachineTest, GroupPolicy_InvalidInstallValue) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 2));
+
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());
+
+  VerifyInstallUpdateCheck(app_guids_app1());
+  ValidateNoUpdateErrorObserved(job_observer_);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// Tests which app name is displayed.
+TEST_F(WorkerJobDoProcessInstallMachineTest,
+       GroupPolicy_InstallThreeAppsLastTwoProhibited) {
+  SetMockMockRequestSave();
+  args_.extra.apps.push_back(CommandLineAppArgs());
+  args_.extra.apps[1].app_guid = StringToGuid(kAppGuid2);
+  args_.extra.apps[1].app_name = _T("App 2");
+  args_.extra.apps[1].needs_admin = true;
+  args_.extra.apps.push_back(CommandLineAppArgs());
+  args_.extra.apps[2].app_guid = StringToGuid(kAppGuid3);
+  args_.extra.apps[2].app_name = _T("Third App");
+  args_.extra.apps[2].needs_admin = true;
+
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp2, 0));
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp3, 0));
+
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->error_code());
+
+  VerifyNoUpdateCheckSent();
+
+  EXPECT_EQ(COMPLETION_CODE_ERROR, job_observer_.completion_code);
+  EXPECT_STREQ(_T("Your network administrator has applied a Group Policy that ")
+               _T("prevents installation of App 2."),
+               job_observer_.completion_text);
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            job_observer_.completion_error_code);
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(2, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallMachineTest, GroupPolicy_UpdateProhibited) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());
+
+  VerifyInstallUpdateCheck(app_guids_app1());
+  ValidateNoUpdateErrorObserved(job_observer_);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallMachineTest,
+       GroupPolicy_InstallAndUpdateProhibited) {
+  SetMockMockRequestSave();
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->error_code());
+
+  VerifyNoUpdateCheckSent();
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallMachineTest,
+       GroupPolicy_InstallOfDifferentAppProhibited) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp2, 0));
+
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());
+
+  VerifyInstallUpdateCheck(app_guids_app1());
+  ValidateNoUpdateErrorObserved(job_observer_);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallMachineTest,
+       GroupPolicy_InstallTwoAppsOneProhibited) {
+  SetMockMockRequestSave();
+  args_.extra.apps.push_back(CommandLineAppArgs());
+  args_.extra.apps[1].app_guid = StringToGuid(kAppGuid2);
+  args_.extra.apps[1].app_name = _T("App 2");
+  args_.extra.apps[1].needs_admin = true;
+
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));
+
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->error_code());
+
+  VerifyNoUpdateCheckSent();
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallMachineTest, AppEulaNotAccepted) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());
+
+  VerifyInstallUpdateCheck(app_guids_app1());
+  ValidateNoUpdateErrorObserved(job_observer_);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallMachineTest,
+       AppEulaNotAcceptedAndInstallProhibited) {
+  SetMockMockRequestSave();
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->error_code());
+
+  VerifyNoUpdateCheckSent();
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallMachineTest,
+       AppEulaNotAcceptedAndOtherAppInstallProhibited) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID2,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID2,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp2, 0));
+
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_NO_UPDATE_RESPONSE, worker_job_->error_code());
+
+  VerifyInstallUpdateCheck(app_guids_app1());
+  ValidateNoUpdateErrorObserved(job_observer_);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+//
+// Install Google Update and app tests.
+//
+// We cannot run DoProcess for the InstallGoopdateAndAppsStrategy case because
+// it attempts to install Google Update before checking the Group Policy.
+// Therefore, test RemoveDisallowedApps() directly.
+
+TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest, GroupPolicy_NoPolicy) {
+  EXPECT_SUCCEEDED(worker_job_->strategy()->RemoveDisallowedApps(&products_));
+  EXPECT_EQ(1, products_.size());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest,
+       GroupPolicy_InstallProhibited) {
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));
+
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->strategy()->RemoveDisallowedApps(&products_));
+  EXPECT_TRUE(products_.empty());
+
+  EXPECT_SUCCEEDED(worker_job_->error_code()) <<
+      _T("error_code code does not run.");
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest,
+       GroupPolicy_UpdateProhibited) {
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  EXPECT_SUCCEEDED(worker_job_->strategy()->RemoveDisallowedApps(&products_));
+  EXPECT_EQ(1, products_.size());
+
+  EXPECT_SUCCEEDED(worker_job_->error_code()) <<
+      _T("error_code code does not run.");
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest,
+       GroupPolicy_InstallAndUpdateProhibited) {
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->strategy()->RemoveDisallowedApps(&products_));
+  EXPECT_TRUE(products_.empty());
+
+  EXPECT_SUCCEEDED(worker_job_->error_code()) <<
+      _T("error_code code does not run.");
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest,
+       GroupPolicy_InstallOfDifferentAppProhibited) {
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp2, 0));
+
+  EXPECT_SUCCEEDED(worker_job_->strategy()->RemoveDisallowedApps(&products_));
+  EXPECT_EQ(1, products_.size());
+
+  EXPECT_SUCCEEDED(worker_job_->error_code()) <<
+      _T("error_code code does not run.");
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessInstallGoogleUpdateMachineTest,
+       GroupPolicy_InstallTwoAppsOneProhibited) {
+  args_.extra.apps.push_back(CommandLineAppArgs());
+  args_.extra.apps[1].app_guid = StringToGuid(kAppGuid2);
+  args_.extra.apps[1].app_name = _T("App 2");
+  args_.extra.apps[1].needs_admin = true;
+
+  AppData app_data;
+  app_data.set_app_guid(StringToGuid(kAppGuid2));
+  app_data.set_is_machine_app(true);
+  products_.push_back(ProductData(app_data));
+  ASSERT_EQ(2, products_.size());
+
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));
+
+  EXPECT_EQ(GOOPDATE_E_APP_INSTALL_DISABLED_BY_POLICY,
+            worker_job_->strategy()->RemoveDisallowedApps(&products_));
+  EXPECT_EQ(1, products_.size());  // One of two was removed.
+
+  EXPECT_SUCCEEDED(worker_job_->error_code()) <<
+      _T("error_code code does not run.");
+
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(1, metric_worker_apps_not_installed_group_policy.value());
+}
+
+//
+// On-demand update tests.
+//
+
+TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest, UpdateCheckFails) {
+  SetMockMockRequestSaveFail();
+
+  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,
+            worker_job_->DoProcess());
+  EXPECT_EQ(MockRequestSaveFail::kUpdateCheckForcedFailure,
+            worker_job_->error_code());
+
+  ValidateComFailureObserved(job_observer_->job_observer_mock);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest, GroupPolicy_NoPolicy) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyOnDemandUpdateCheck(app_guids_app1());
+  ValidateComSuccessObserved(job_observer_->job_observer_mock);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,
+       GroupPolicy_InstallProhibited) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyOnDemandUpdateCheck(app_guids_app1());
+  ValidateComSuccessObserved(job_observer_->job_observer_mock);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,
+       GroupPolicy_UpdateProhibited) {
+  SetMockMockRequestSave();
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY, worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY,
+            worker_job_->error_code());
+
+  VerifyNoUpdateCheckSent();
+  ValidateComFailureObserved(job_observer_->job_observer_mock);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,
+       GroupPolicy_ManualUpdateOnly) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 2));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyOnDemandUpdateCheck(app_guids_app1());
+  ValidateComSuccessObserved(job_observer_->job_observer_mock);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,
+       GroupPolicy_InstallAndUpdateProhibited) {
+  SetMockMockRequestSave();
+  EXPECT_SUCCEEDED(SetPolicy(kInstallPolicyApp, 0));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY, worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_BY_POLICY,
+            worker_job_->error_code());
+
+  VerifyNoUpdateCheckSent();
+  ValidateComFailureObserved(job_observer_->job_observer_mock);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(1, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,
+       GroupPolicy_UpdateOfDifferentAppProhibited) {
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp2, 0));
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyOnDemandUpdateCheck(app_guids_app1());
+  ValidateComSuccessObserved(job_observer_->job_observer_mock);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest, AppEulaNotAccepted) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  worker_job_.reset();
+  EXPECT_SUCCEEDED(WorkerJobFactory::CreateOnDemandWorkerJob(
+      true,   // is_machine
+      false,  // is_update_check_only
+      _T("en"),
+      StringToGuid(kAppGuid),
+      job_holder_,
+      new WorkerComWrapperShutdownCallBack(false),
+      address(worker_job_)));
+  SetMockMockRequestSave();
+
+  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED,
+            worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED,
+            worker_job_->error_code());
+
+  VerifyNoUpdateCheckSent();
+  ValidateComFailureObserved(job_observer_->job_observer_mock);
+  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest, OtherAppEulaNotAccepted) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENTS APP_GUID2,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_CLIENT_STATE APP_GUID2,
+                                    _T("pv"),
+                                    _T("1.2.3.4")));
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp2,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+
+  worker_job_.reset();
+  EXPECT_SUCCEEDED(WorkerJobFactory::CreateOnDemandWorkerJob(
+      true,   // is_machine
+      false,  // is_update_check_only
+      _T("en"),
+      StringToGuid(kAppGuid),
+      job_holder_,
+      new WorkerComWrapperShutdownCallBack(false),
+      address(worker_job_)));
+  SetMockRequestSaveNoUpdate(app_guids_app1());
+
+  EXPECT_SUCCEEDED(worker_job_->DoProcess());
+  EXPECT_SUCCEEDED(worker_job_->error_code());
+
+  VerifyOnDemandUpdateCheck(app_guids_app1());
+  ValidateComSuccessObserved(job_observer_->job_observer_mock);
+  EXPECT_EQ(0, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// EULA is checked first.
+TEST_F(WorkerJobDoProcessOnDemandUpdateMachineTest,
+       AppEulaNotAcceptedAndUpdateProhibited) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(kMachineClientStatePathApp,
+                                    _T("eulaaccepted"),
+                                    static_cast<DWORD>(0)));
+  EXPECT_SUCCEEDED(SetPolicy(kUpdatePolicyApp, 0));
+
+  worker_job_.reset();
+  EXPECT_SUCCEEDED(WorkerJobFactory::CreateOnDemandWorkerJob(
+      true,   // is_machine
+      false,  // is_update_check_only
+      _T("en"),
+      StringToGuid(kAppGuid),
+      job_holder_,
+      new WorkerComWrapperShutdownCallBack(false),
+      address(worker_job_)));
+  SetMockMockRequestSave();
+
+  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED,
+            worker_job_->DoProcess());
+  EXPECT_EQ(GOOPDATE_E_APP_UPDATE_DISABLED_EULA_NOT_ACCEPTED,
+            worker_job_->error_code());
+
+  VerifyNoUpdateCheckSent();
+  ValidateComFailureObserved(job_observer_->job_observer_mock);
+  EXPECT_EQ(1, metric_worker_apps_not_updated_eula.value());
+  EXPECT_EQ(0, metric_worker_apps_not_updated_group_policy.value());
+  EXPECT_EQ(0, metric_worker_apps_not_installed_group_policy.value());
+}
+
+// TODO(omaha): Add some user tests for the above.
+
+// Create a worker with the /handoff switch and needs_admin=false.
+// Call IsAppInstallWorkerRunning for machine. Should return false.
+TEST_F(WorkerJobIsAppInstallWorkerRunningTest, HandoffNeedsAdminFalseMachine) {
+  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  worker_job_.reset(
+      WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));
+  cmd_line_.Format(_T("%s %s"), handoff_cmd_line, false_extra_args);
+  TestIsAppInstallWorkerRunning(cmd_line_, true, false);
+}
+
+// Create a worker with the /handoff switch and needs_admin=true.
+// Call IsAppInstallWorkerRunning for machine. Should return true.
+TEST_F(WorkerJobIsAppInstallWorkerRunningTest, HandoffNeedsAdminTrueMachine) {
+  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  worker_job_.reset(
+      WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));
+  cmd_line_.Format(_T("%s %s"), handoff_cmd_line, true_extra_args);
+  TestIsAppInstallWorkerRunning(cmd_line_, true, true);
+}
+
+// Create a worker with the /handoff switch and needs_admin=false.
+// Call IsAppInstallWorkerRunning for user. Should return true.
+TEST_F(WorkerJobIsAppInstallWorkerRunningTest, HandoffNeedsAdminFalseUser) {
+  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  worker_job_.reset(
+      WorkerJobFactory::CreateWorkerJob(false, args_, &job_observer_));
+  cmd_line_.Format(_T("%s %s"), handoff_cmd_line, false_extra_args);
+  TestIsAppInstallWorkerRunning(cmd_line_, false, true);
+}
+
+// Create a worker with the /handoff switch and needs_admin=true.
+// Call IsAppInstallWorkerRunning for user. Should return false.
+TEST_F(WorkerJobIsAppInstallWorkerRunningTest, HandoffNeedsAdminTrueUser) {
+  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  worker_job_.reset(
+      WorkerJobFactory::CreateWorkerJob(false, args_, &job_observer_));
+  cmd_line_.Format(_T("%s %s"), handoff_cmd_line, true_extra_args);
+  TestIsAppInstallWorkerRunning(cmd_line_, false, false);
+}
+
+// Create a worker with the /ig switch and needs_admin=false.
+// Call IsAppInstallWorkerRunning for machine. Should return false.
+TEST_F(WorkerJobIsAppInstallWorkerRunningTest, IgNeedsAdminFalseMachine) {
+  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  worker_job_.reset(
+      WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));
+  cmd_line_.Format(_T("%s %s"), finish_setup_cmd_line, false_extra_args);
+  TestIsAppInstallWorkerRunning(cmd_line_, true, false);
+}
+
+// Create a worker with the /ig switch and needs_admin=true.
+// Call IsAppInstallWorkerRunning for machine. Should return true.
+TEST_F(WorkerJobIsAppInstallWorkerRunningTest, IgNeedsAdminTrueMachine) {
+  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  worker_job_.reset(
+      WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));
+  cmd_line_.Format(_T("%s %s"), finish_setup_cmd_line, true_extra_args);
+  TestIsAppInstallWorkerRunning(cmd_line_, true, true);
+}
+
+// Create a worker with the /ig switch and needs_admin=false.
+// Call IsAppInstallWorkerRunning for user. Should return true.
+TEST_F(WorkerJobIsAppInstallWorkerRunningTest, IgNeedsAdminFalseUser) {
+  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  worker_job_.reset(
+      WorkerJobFactory::CreateWorkerJob(false, args_, &job_observer_));
+  cmd_line_.Format(_T("%s %s"), finish_setup_cmd_line, false_extra_args);
+  TestIsAppInstallWorkerRunning(cmd_line_, false, true);
+}
+
+// Create a worker with the /ig switch and needs_admin=true.
+// Call IsAppInstallWorkerRunning for user. Should return false.
+TEST_F(WorkerJobIsAppInstallWorkerRunningTest, IgNeedsAdminTrueUser) {
+  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  worker_job_.reset(
+      WorkerJobFactory::CreateWorkerJob(false, args_, &job_observer_));
+  cmd_line_.Format(_T("%s %s"), finish_setup_cmd_line, true_extra_args);
+  TestIsAppInstallWorkerRunning(cmd_line_, false, false);
+}
+
+TEST_F(WorkerJobIsAppInstallWorkerRunningTest, NoArgsUser) {
+  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  worker_job_.reset(
+      WorkerJobFactory::CreateWorkerJob(false, args_, &job_observer_));
+  TestIsAppInstallWorkerRunning(_T(""), false, false);
+}
+
+TEST_F(WorkerJobIsAppInstallWorkerRunningTest, NoArgsMachine) {
+  args_.mode = COMMANDLINE_MODE_HANDOFF_INSTALL;
+  worker_job_.reset(
+      WorkerJobFactory::CreateWorkerJob(true, args_, &job_observer_));
+  TestIsAppInstallWorkerRunning(_T(""), true, false);
+}
+
+TEST_F(WorkerJobRegistryProtectedTest,
+       BuildUninstallPing_User_NoUninstalledApp) {
+  ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENT_STATE));
+
+  scoped_ptr<Request> uninstall_ping;
+  EXPECT_HRESULT_SUCCEEDED(BuildUninstallPing(false, address(uninstall_ping)));
+  EXPECT_EQ(0, uninstall_ping->get_request_count());
+}
+
+// Create a mock client state for one app and build an uninstall ping.
+// Expect the client state to be cleared at the end.
+TEST_F(WorkerJobRegistryProtectedTest, BuildUninstallPing_User_UninstalledApp) {
+  CString client_state_appkey(USER_REG_CLIENT_STATE);
+  client_state_appkey.Append(_T("{C78D67E2-D7E9-4b62-9869-FCDCFC4C9323}"));
+  EXPECT_HRESULT_SUCCEEDED(
+    RegKey::SetValue(client_state_appkey, kRegValueProductVersion, _T("1.0")));
+
+  scoped_ptr<Request> uninstall_ping;
+  EXPECT_HRESULT_SUCCEEDED(BuildUninstallPing(false, address(uninstall_ping)));
+  EXPECT_EQ(1, uninstall_ping->get_request_count());
+  EXPECT_EQ(PingEvent::EVENT_UNINSTALL, GetPingType(*uninstall_ping));
+  EXPECT_FALSE(RegKey::HasKey(client_state_appkey));
+}
+
+TEST_F(WorkerJobRegistryProtectedTest,
+       BuildUninstallPing_Machine_NoUninstalledApp) {
+  ASSERT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_CLIENT_STATE));
+
+  scoped_ptr<Request> uninstall_ping;
+  EXPECT_HRESULT_SUCCEEDED(BuildUninstallPing(true, address(uninstall_ping)));
+  EXPECT_EQ(0, uninstall_ping->get_request_count());
+}
+
+// Create a mock client state for one app and build an uninstall ping.
+// Expect the client state to be cleared at the end.
+TEST_F(WorkerJobRegistryProtectedTest,
+       BuildUninstallPing_Machine_UninstalledApp) {
+  CString client_state_appkey = MACHINE_REG_CLIENT_STATE;
+  client_state_appkey.Append(_T("{C78D67E2-D7E9-4b62-9869-FCDCFC4C9323}"));
+  EXPECT_HRESULT_SUCCEEDED(
+    RegKey::SetValue(client_state_appkey, kRegValueProductVersion, _T("1.0")));
+
+  scoped_ptr<Request> uninstall_ping;
+  EXPECT_HRESULT_SUCCEEDED(BuildUninstallPing(true, address(uninstall_ping)));
+  EXPECT_EQ(1, uninstall_ping->get_request_count());
+  EXPECT_EQ(PingEvent::EVENT_UNINSTALL, GetPingType(*uninstall_ping));
+  EXPECT_FALSE(RegKey::HasKey(client_state_appkey));
+}
+
+}  // namespace omaha
diff --git a/worker/worker_metrics.cc b/worker/worker_metrics.cc
index 3730106..a9b008d 100644
--- a/worker/worker_metrics.cc
+++ b/worker/worker_metrics.cc
@@ -1,97 +1,97 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-

-#include "omaha/worker/worker_metrics.h"

-

-namespace omaha {

-

-DEFINE_METRIC_count(worker_download_total);

-DEFINE_METRIC_count(worker_download_succeeded);

-

-DEFINE_METRIC_count(worker_download_move_total);

-DEFINE_METRIC_count(worker_download_move_succeeded);

-

-DEFINE_METRIC_count(worker_another_install_in_progress);

-DEFINE_METRIC_count(worker_another_update_in_progress);

-

-DEFINE_METRIC_timing(worker_ui_cancel_ms);

-DEFINE_METRIC_count(worker_ui_cancels);

-

-DEFINE_METRIC_count(worker_ui_click_x);

-

-DEFINE_METRIC_count(worker_ui_esc_key_total);

-

-DEFINE_METRIC_count(worker_ui_restart_browser_buttons_displayed);

-DEFINE_METRIC_count(worker_ui_restart_browser_now_click);

-DEFINE_METRIC_count(worker_ui_restart_all_browsers_buttons_displayed);

-DEFINE_METRIC_count(worker_ui_restart_all_browsers_now_click);

-DEFINE_METRIC_count(worker_ui_reboot_buttons_displayed);

-DEFINE_METRIC_count(worker_ui_reboot_now_click);

-

-DEFINE_METRIC_count(worker_ui_get_help_displayed);

-DEFINE_METRIC_count(worker_ui_get_help_click);

-

-DEFINE_METRIC_count(worker_install_execute_total);

-DEFINE_METRIC_count(worker_install_execute_msi_total);

-

-DEFINE_METRIC_count(worker_install_msi_in_progress_detected_update);

-DEFINE_METRIC_count(worker_install_msi_in_progress_retry_succeeded_update);

-DEFINE_METRIC_integer(

-    worker_install_msi_in_progress_retry_succeeded_tries_update);

-

-DEFINE_METRIC_count(worker_install_msi_in_progress_detected_install);

-DEFINE_METRIC_count(worker_install_msi_in_progress_retry_succeeded_install);

-DEFINE_METRIC_integer(

-    worker_install_msi_in_progress_retry_succeeded_tries_install);

-

-DEFINE_METRIC_integer(worker_shell_version);

-

-DEFINE_METRIC_bool(worker_is_windows_installing);

-

-DEFINE_METRIC_bool(worker_is_uac_disabled);

-

-DEFINE_METRIC_bool(worker_is_clickonce_disabled);

-

-DEFINE_METRIC_bool(worker_has_software_firewall);

-

-DEFINE_METRIC_count(worker_silent_update_running_on_batteries);

-

-DEFINE_METRIC_count(worker_update_check_total);

-DEFINE_METRIC_count(worker_update_check_succeeded);

-

-DEFINE_METRIC_integer(worker_apps_not_updated_eula);

-DEFINE_METRIC_integer(worker_apps_not_updated_group_policy);

-DEFINE_METRIC_integer(worker_apps_not_installed_group_policy);

-

-DEFINE_METRIC_count(worker_skipped_app_update_for_self_update);

-

-DEFINE_METRIC_count(worker_self_updates_available);

-DEFINE_METRIC_count(worker_self_updates_succeeded);

-

-DEFINE_METRIC_count(worker_app_updates_available);

-DEFINE_METRIC_count(worker_app_updates_succeeded);

-

-DEFINE_METRIC_integer(worker_self_update_responses);

-DEFINE_METRIC_integer(worker_self_update_response_time_since_first_ms);

-

-DEFINE_METRIC_integer(worker_app_max_update_responses_app_high);

-DEFINE_METRIC_integer(worker_app_max_update_responses);

-DEFINE_METRIC_integer(worker_app_max_update_responses_ms_since_first);

-

-DEFINE_METRIC_timing(ping_failed_ms);

-DEFINE_METRIC_timing(ping_succeeded_ms);

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+
+#include "omaha/worker/worker_metrics.h"
+
+namespace omaha {
+
+DEFINE_METRIC_count(worker_download_total);
+DEFINE_METRIC_count(worker_download_succeeded);
+
+DEFINE_METRIC_count(worker_download_move_total);
+DEFINE_METRIC_count(worker_download_move_succeeded);
+
+DEFINE_METRIC_count(worker_another_install_in_progress);
+DEFINE_METRIC_count(worker_another_update_in_progress);
+
+DEFINE_METRIC_timing(worker_ui_cancel_ms);
+DEFINE_METRIC_count(worker_ui_cancels);
+
+DEFINE_METRIC_count(worker_ui_click_x);
+
+DEFINE_METRIC_count(worker_ui_esc_key_total);
+
+DEFINE_METRIC_count(worker_ui_restart_browser_buttons_displayed);
+DEFINE_METRIC_count(worker_ui_restart_browser_now_click);
+DEFINE_METRIC_count(worker_ui_restart_all_browsers_buttons_displayed);
+DEFINE_METRIC_count(worker_ui_restart_all_browsers_now_click);
+DEFINE_METRIC_count(worker_ui_reboot_buttons_displayed);
+DEFINE_METRIC_count(worker_ui_reboot_now_click);
+
+DEFINE_METRIC_count(worker_ui_get_help_displayed);
+DEFINE_METRIC_count(worker_ui_get_help_click);
+
+DEFINE_METRIC_count(worker_install_execute_total);
+DEFINE_METRIC_count(worker_install_execute_msi_total);
+
+DEFINE_METRIC_count(worker_install_msi_in_progress_detected_update);
+DEFINE_METRIC_count(worker_install_msi_in_progress_retry_succeeded_update);
+DEFINE_METRIC_integer(
+    worker_install_msi_in_progress_retry_succeeded_tries_update);
+
+DEFINE_METRIC_count(worker_install_msi_in_progress_detected_install);
+DEFINE_METRIC_count(worker_install_msi_in_progress_retry_succeeded_install);
+DEFINE_METRIC_integer(
+    worker_install_msi_in_progress_retry_succeeded_tries_install);
+
+DEFINE_METRIC_integer(worker_shell_version);
+
+DEFINE_METRIC_bool(worker_is_windows_installing);
+
+DEFINE_METRIC_bool(worker_is_uac_disabled);
+
+DEFINE_METRIC_bool(worker_is_clickonce_disabled);
+
+DEFINE_METRIC_bool(worker_has_software_firewall);
+
+DEFINE_METRIC_count(worker_silent_update_running_on_batteries);
+
+DEFINE_METRIC_count(worker_update_check_total);
+DEFINE_METRIC_count(worker_update_check_succeeded);
+
+DEFINE_METRIC_integer(worker_apps_not_updated_eula);
+DEFINE_METRIC_integer(worker_apps_not_updated_group_policy);
+DEFINE_METRIC_integer(worker_apps_not_installed_group_policy);
+
+DEFINE_METRIC_count(worker_skipped_app_update_for_self_update);
+
+DEFINE_METRIC_count(worker_self_updates_available);
+DEFINE_METRIC_count(worker_self_updates_succeeded);
+
+DEFINE_METRIC_count(worker_app_updates_available);
+DEFINE_METRIC_count(worker_app_updates_succeeded);
+
+DEFINE_METRIC_integer(worker_self_update_responses);
+DEFINE_METRIC_integer(worker_self_update_response_time_since_first_ms);
+
+DEFINE_METRIC_integer(worker_app_max_update_responses_app_high);
+DEFINE_METRIC_integer(worker_app_max_update_responses);
+DEFINE_METRIC_integer(worker_app_max_update_responses_ms_since_first);
+
+DEFINE_METRIC_timing(ping_failed_ms);
+DEFINE_METRIC_timing(ping_succeeded_ms);
+
+}  // namespace omaha
diff --git a/worker/worker_metrics.h b/worker/worker_metrics.h
index 9c6aed3..ebe4ed7 100644
--- a/worker/worker_metrics.h
+++ b/worker/worker_metrics.h
@@ -1,174 +1,174 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-// Declares the usage metrics used by the worker module.

-

-#ifndef OMAHA_WORKER_WORKER_METRICS_H__

-#define OMAHA_WORKER_WORKER_METRICS_H__

-

-#include "omaha/statsreport/metrics.h"

-

-namespace omaha {

-

-// How many times the download manager attempted to download a file.

-DECLARE_METRIC_count(worker_download_total);

-// How many times the download manager successfully downloaded a file.

-DECLARE_METRIC_count(worker_download_succeeded);

-

-// How many times the download manager attempted to copy the temporary file

-// to the download directory.

-DECLARE_METRIC_count(worker_download_move_total);

-// How many times the download manager successfully copied the temporary file

-// to the download directory.

-DECLARE_METRIC_count(worker_download_move_succeeded);

-

-// How many times the install worker encountered another worker that

-// is already running.

-DECLARE_METRIC_count(worker_another_install_in_progress);

-

-// How many times the update worker encountered another worker that

-// is already running.

-DECLARE_METRIC_count(worker_another_update_in_progress);

-

-// Time (ms) until the user canceled.

-DECLARE_METRIC_timing(worker_ui_cancel_ms);

-// How many times the user canceled. Only includes confirmed cancels.

-DECLARE_METRIC_count(worker_ui_cancels);

-

-// How many times the user has clicked on the x button of the UI.

-DECLARE_METRIC_count(worker_ui_click_x);

-

-// How many times the user has hit the esc key.

-DECLARE_METRIC_count(worker_ui_esc_key_total);

-

-// How many times the "Restart Browser Now/Later" buttons were displayed.

-DECLARE_METRIC_count(worker_ui_restart_browser_buttons_displayed);

-// How many times the user clicked "Restart Browser Now".

-DECLARE_METRIC_count(worker_ui_restart_browser_now_click);

-// How many times the "Restart Browsers Now/Later" buttons were displayed.

-DECLARE_METRIC_count(worker_ui_restart_all_browsers_buttons_displayed);

-// How many times the user clicked "Restart Browsers Now".

-DECLARE_METRIC_count(worker_ui_restart_all_browsers_now_click);

-// How many times the "Restart Now/Later" (reboot) buttons were displayed.

-DECLARE_METRIC_count(worker_ui_reboot_buttons_displayed);

-// How many times the user clicked "Restart Now" (reboot).

-DECLARE_METRIC_count(worker_ui_reboot_now_click);

-

-// How many times the user was offered the "Help Me Fix This" link.

-DECLARE_METRIC_count(worker_ui_get_help_displayed);

-// How many times the user clicked the "Help Me Fix This" link.

-DECLARE_METRIC_count(worker_ui_get_help_click);

-

-// How many times ExecuteAndWaitForInstaller was called.

-DECLARE_METRIC_count(worker_install_execute_total);

-// How many times ExecuteAndWaitForInstaller was called for an MSI.

-DECLARE_METRIC_count(worker_install_execute_msi_total);

-

-// How many MSI install attempts encountered ERROR_INSTALL_ALREADY_RUNNING

-// during an update.

-DECLARE_METRIC_count(worker_install_msi_in_progress_detected_update);

-// How many times successfully installed MSI in a retry after

-// encountering ERROR_INSTALL_ALREADY_RUNNING during an update.

-DECLARE_METRIC_count(worker_install_msi_in_progress_retry_succeeded_update);

-// Number of retries attempted because of ERROR_INSTALL_ALREADY_RUNNING before

-// succeeded during an update.

-DECLARE_METRIC_integer(

-    worker_install_msi_in_progress_retry_succeeded_tries_update);

-

-// How many MSI install attempts encountered ERROR_INSTALL_ALREADY_RUNNING

-// during an install.

-DECLARE_METRIC_count(worker_install_msi_in_progress_detected_install);

-// How many times successfully installed MSI in a retry after

-// encountering ERROR_INSTALL_ALREADY_RUNNING during an install.

-DECLARE_METRIC_count(worker_install_msi_in_progress_retry_succeeded_install);

-// Number of retries attempted because of ERROR_INSTALL_ALREADY_RUNNING before

-// succeeded during an install.

-DECLARE_METRIC_integer(

-    worker_install_msi_in_progress_retry_succeeded_tries_install);

-

-// Version of the GoogleUpdate.exe shell in use.

-DECLARE_METRIC_integer(worker_shell_version);

-

-// True if Windows is installing (is in audit mode). This should never be true.

-DECLARE_METRIC_bool(worker_is_windows_installing);

-

-// True if UAC is disabled.

-DECLARE_METRIC_bool(worker_is_uac_disabled);

-

-// True if ClickOnce is disabled for the Internet zone for the current user.

-DECLARE_METRIC_bool(worker_is_clickonce_disabled);

-

-// True if a software firewall is detected.

-DECLARE_METRIC_bool(worker_has_software_firewall);

-

-// How many times the computer was on batteries when doing an update check

-// for apps.

-DECLARE_METRIC_count(worker_silent_update_running_on_batteries);

-

-// How many times an update check was attempted. Does not include installs.

-DECLARE_METRIC_count(worker_update_check_total);

-// How many times an update check succeeded. Does not include installs.

-DECLARE_METRIC_count(worker_update_check_succeeded);

-

-// Number of apps for which update checks skipped because EULA is not accepted.

-DECLARE_METRIC_integer(worker_apps_not_updated_eula);

-// Number of apps for which update checks skipped because of Group Policy.

-DECLARE_METRIC_integer(worker_apps_not_updated_group_policy);

-// Number of apps not installed because of Group Policy.

-// In most case, this will be 0 or 1 because it saves only the value from the

-// last install process.

-DECLARE_METRIC_integer(worker_apps_not_installed_group_policy);

-

-// How many times Omaha did not update an app because an Omaha update was

-// available at the same time. Only incremented if both an Omaha and app update

-// are available in the same update check. Max one increment per update check.

-DECLARE_METRIC_count(worker_skipped_app_update_for_self_update);

-

-// How many times a self update was available.

-DECLARE_METRIC_count(worker_self_updates_available);

-// How many times a self update succeeded.

-DECLARE_METRIC_count(worker_self_updates_succeeded);

-

-// How many updates have been available. Each app in an update check is counted.

-// If a self-update was available, no apps are counted.

-DECLARE_METRIC_count(worker_app_updates_available);

-// How many app updates succeeded.

-DECLARE_METRIC_count(worker_app_updates_succeeded);

-

-// Number of times Omaha has received a self-update response without

-// successfully updating.

-DECLARE_METRIC_integer(worker_self_update_responses);

-// The time (ms) since the first time Omaha received a self-update response.

-// Only reported if Omaha fails to update after first such response.

-DECLARE_METRIC_integer(worker_self_update_response_time_since_first_ms);

-

-// The most significant/left half of the GUID for the app for which Omaha has

-// received the most update responses without successfully updating.

-DECLARE_METRIC_integer(worker_app_max_update_responses_app_high);

-// Maximum number of times for any app that Omaha has received an update

-// response without successfully updating.

-DECLARE_METRIC_integer(worker_app_max_update_responses);

-// The time (ms) since the first time Omaha received an update response for the

-// app with the most update failures.

-DECLARE_METRIC_integer(worker_app_max_update_responses_ms_since_first);

-

-// Time (ms) spent in SendPing() when DoSendPing() fails.

-DECLARE_METRIC_timing(ping_failed_ms);

-// Time (ms) spent in SendPing() when the ping succeeds.

-DECLARE_METRIC_timing(ping_succeeded_ms);

-

-}  // namespace omaha

-

-#endif  // OMAHA_WORKER_WORKER_METRICS_H__

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+// Declares the usage metrics used by the worker module.
+
+#ifndef OMAHA_WORKER_WORKER_METRICS_H__
+#define OMAHA_WORKER_WORKER_METRICS_H__
+
+#include "omaha/statsreport/metrics.h"
+
+namespace omaha {
+
+// How many times the download manager attempted to download a file.
+DECLARE_METRIC_count(worker_download_total);
+// How many times the download manager successfully downloaded a file.
+DECLARE_METRIC_count(worker_download_succeeded);
+
+// How many times the download manager attempted to copy the temporary file
+// to the download directory.
+DECLARE_METRIC_count(worker_download_move_total);
+// How many times the download manager successfully copied the temporary file
+// to the download directory.
+DECLARE_METRIC_count(worker_download_move_succeeded);
+
+// How many times the install worker encountered another worker that
+// is already running.
+DECLARE_METRIC_count(worker_another_install_in_progress);
+
+// How many times the update worker encountered another worker that
+// is already running.
+DECLARE_METRIC_count(worker_another_update_in_progress);
+
+// Time (ms) until the user canceled.
+DECLARE_METRIC_timing(worker_ui_cancel_ms);
+// How many times the user canceled. Only includes confirmed cancels.
+DECLARE_METRIC_count(worker_ui_cancels);
+
+// How many times the user has clicked on the x button of the UI.
+DECLARE_METRIC_count(worker_ui_click_x);
+
+// How many times the user has hit the esc key.
+DECLARE_METRIC_count(worker_ui_esc_key_total);
+
+// How many times the "Restart Browser Now/Later" buttons were displayed.
+DECLARE_METRIC_count(worker_ui_restart_browser_buttons_displayed);
+// How many times the user clicked "Restart Browser Now".
+DECLARE_METRIC_count(worker_ui_restart_browser_now_click);
+// How many times the "Restart Browsers Now/Later" buttons were displayed.
+DECLARE_METRIC_count(worker_ui_restart_all_browsers_buttons_displayed);
+// How many times the user clicked "Restart Browsers Now".
+DECLARE_METRIC_count(worker_ui_restart_all_browsers_now_click);
+// How many times the "Restart Now/Later" (reboot) buttons were displayed.
+DECLARE_METRIC_count(worker_ui_reboot_buttons_displayed);
+// How many times the user clicked "Restart Now" (reboot).
+DECLARE_METRIC_count(worker_ui_reboot_now_click);
+
+// How many times the user was offered the "Help Me Fix This" link.
+DECLARE_METRIC_count(worker_ui_get_help_displayed);
+// How many times the user clicked the "Help Me Fix This" link.
+DECLARE_METRIC_count(worker_ui_get_help_click);
+
+// How many times ExecuteAndWaitForInstaller was called.
+DECLARE_METRIC_count(worker_install_execute_total);
+// How many times ExecuteAndWaitForInstaller was called for an MSI.
+DECLARE_METRIC_count(worker_install_execute_msi_total);
+
+// How many MSI install attempts encountered ERROR_INSTALL_ALREADY_RUNNING
+// during an update.
+DECLARE_METRIC_count(worker_install_msi_in_progress_detected_update);
+// How many times successfully installed MSI in a retry after
+// encountering ERROR_INSTALL_ALREADY_RUNNING during an update.
+DECLARE_METRIC_count(worker_install_msi_in_progress_retry_succeeded_update);
+// Number of retries attempted because of ERROR_INSTALL_ALREADY_RUNNING before
+// succeeded during an update.
+DECLARE_METRIC_integer(
+    worker_install_msi_in_progress_retry_succeeded_tries_update);
+
+// How many MSI install attempts encountered ERROR_INSTALL_ALREADY_RUNNING
+// during an install.
+DECLARE_METRIC_count(worker_install_msi_in_progress_detected_install);
+// How many times successfully installed MSI in a retry after
+// encountering ERROR_INSTALL_ALREADY_RUNNING during an install.
+DECLARE_METRIC_count(worker_install_msi_in_progress_retry_succeeded_install);
+// Number of retries attempted because of ERROR_INSTALL_ALREADY_RUNNING before
+// succeeded during an install.
+DECLARE_METRIC_integer(
+    worker_install_msi_in_progress_retry_succeeded_tries_install);
+
+// Version of the GoogleUpdate.exe shell in use.
+DECLARE_METRIC_integer(worker_shell_version);
+
+// True if Windows is installing (is in audit mode). This should never be true.
+DECLARE_METRIC_bool(worker_is_windows_installing);
+
+// True if UAC is disabled.
+DECLARE_METRIC_bool(worker_is_uac_disabled);
+
+// True if ClickOnce is disabled for the Internet zone for the current user.
+DECLARE_METRIC_bool(worker_is_clickonce_disabled);
+
+// True if a software firewall is detected.
+DECLARE_METRIC_bool(worker_has_software_firewall);
+
+// How many times the computer was on batteries when doing an update check
+// for apps.
+DECLARE_METRIC_count(worker_silent_update_running_on_batteries);
+
+// How many times an update check was attempted. Does not include installs.
+DECLARE_METRIC_count(worker_update_check_total);
+// How many times an update check succeeded. Does not include installs.
+DECLARE_METRIC_count(worker_update_check_succeeded);
+
+// Number of apps for which update checks skipped because EULA is not accepted.
+DECLARE_METRIC_integer(worker_apps_not_updated_eula);
+// Number of apps for which update checks skipped because of Group Policy.
+DECLARE_METRIC_integer(worker_apps_not_updated_group_policy);
+// Number of apps not installed because of Group Policy.
+// In most case, this will be 0 or 1 because it saves only the value from the
+// last install process.
+DECLARE_METRIC_integer(worker_apps_not_installed_group_policy);
+
+// How many times Omaha did not update an app because an Omaha update was
+// available at the same time. Only incremented if both an Omaha and app update
+// are available in the same update check. Max one increment per update check.
+DECLARE_METRIC_count(worker_skipped_app_update_for_self_update);
+
+// How many times a self update was available.
+DECLARE_METRIC_count(worker_self_updates_available);
+// How many times a self update succeeded.
+DECLARE_METRIC_count(worker_self_updates_succeeded);
+
+// How many updates have been available. Each app in an update check is counted.
+// If a self-update was available, no apps are counted.
+DECLARE_METRIC_count(worker_app_updates_available);
+// How many app updates succeeded.
+DECLARE_METRIC_count(worker_app_updates_succeeded);
+
+// Number of times Omaha has received a self-update response without
+// successfully updating.
+DECLARE_METRIC_integer(worker_self_update_responses);
+// The time (ms) since the first time Omaha received a self-update response.
+// Only reported if Omaha fails to update after first such response.
+DECLARE_METRIC_integer(worker_self_update_response_time_since_first_ms);
+
+// The most significant/left half of the GUID for the app for which Omaha has
+// received the most update responses without successfully updating.
+DECLARE_METRIC_integer(worker_app_max_update_responses_app_high);
+// Maximum number of times for any app that Omaha has received an update
+// response without successfully updating.
+DECLARE_METRIC_integer(worker_app_max_update_responses);
+// The time (ms) since the first time Omaha received an update response for the
+// app with the most update failures.
+DECLARE_METRIC_integer(worker_app_max_update_responses_ms_since_first);
+
+// Time (ms) spent in SendPing() when DoSendPing() fails.
+DECLARE_METRIC_timing(ping_failed_ms);
+// Time (ms) spent in SendPing() when the ping succeeds.
+DECLARE_METRIC_timing(ping_succeeded_ms);
+
+}  // namespace omaha
+
+#endif  // OMAHA_WORKER_WORKER_METRICS_H__
diff --git a/worker/worker_unittest.cc b/worker/worker_unittest.cc
index 7465467..0576e83 100644
--- a/worker/worker_unittest.cc
+++ b/worker/worker_unittest.cc
@@ -1,330 +1,330 @@
-// Copyright 2008-2009 Google Inc.

-//

-// Licensed under the Apache License, Version 2.0 (the "License");

-// you may not use this file except in compliance with the License.

-// You may obtain a copy of the License at

-//

-//      http://www.apache.org/licenses/LICENSE-2.0

-//

-// Unless required by applicable law or agreed to in writing, software

-// distributed under the License is distributed on an "AS IS" BASIS,

-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

-// See the License for the specific language governing permissions and

-// limitations under the License.

-// ========================================================================

-

-#include "omaha/common/time.h"

-#include "omaha/goopdate/stats_uploader.h"

-#include "omaha/statsreport/aggregator.h"

-#include "omaha/testing/unit_test.h"

-#include "omaha/worker/application_manager.h"

-#include "omaha/worker/worker.h"

-#include "omaha/worker/worker_metrics.h"

-#include "omaha/worker/worker-internal.h"

-

-namespace omaha {

-

-namespace {

-

-const TCHAR* const kDailyUsageStatsKeyPath =

-    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily");

-

-// The alphabetical order of these is important for

-// RecordUpdateAvailableUsageStatsTest.

-const TCHAR* const kApp1 = _T("{0C480772-AC73-418f-9603-66303DA4C7AA}");

-const TCHAR* const kApp2 = _T("{89906BCD-4D12-4c9b-B5BA-8286051CB8D9}");

-const TCHAR* const kApp3 = _T("{F5A1FE97-CF5A-47b8-8B28-2A72F9A57A45}");

-

-const uint64 kApp1GuidUpper = 0x0C480772AC73418f;

-const uint64 kApp2GuidUpper = 0x89906BCD4D124c9b;

-

-const TCHAR* const kApp1ClientsKeyPathUser =

-    _T("HKCU\\Software\\Google\\Update\\Clients\\")

-    _T("{0C480772-AC73-418f-9603-66303DA4C7AA}");

-const TCHAR* const kApp2ClientsKeyPathUser =

-    _T("HKCU\\Software\\Google\\Update\\Clients\\")

-    _T("{89906BCD-4D12-4c9b-B5BA-8286051CB8D9}");

-const TCHAR* const kApp3ClientsKeyPathUser =

-    _T("HKCU\\Software\\Google\\Update\\Clients\\")

-    _T("{F5A1FE97-CF5A-47b8-8B28-2A72F9A57A45}");

-

-const TCHAR* const kApp1ClientStateKeyPathUser =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\")

-    _T("{0C480772-AC73-418f-9603-66303DA4C7AA}");

-const TCHAR* const kApp2ClientStateKeyPathUser =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\")

-    _T("{89906BCD-4D12-4c9b-B5BA-8286051CB8D9}");

-const TCHAR* const kApp3ClientStateKeyPathUser =

-    _T("HKCU\\Software\\Google\\Update\\ClientState\\")

-    _T("{F5A1FE97-CF5A-47b8-8B28-2A72F9A57A45}");

-

-}  // namespace

-

-class WorkerTest : public testing::Test {

- protected:

-  Worker worker_;

-};

-

-// TODO(omaha): Test all methods of Worker

-

-class RecordUpdateAvailableUsageStatsTest : public testing::Test {

- protected:

-  RecordUpdateAvailableUsageStatsTest() : is_machine_(false) {}

-

-  static void SetUpTestCase() {

-    // Initialize the global metrics collection.

-    stats_report::g_global_metrics.Initialize();

-  }

-

-  static void TearDownTestCase() {

-    // The global metrics collection must be uninitialized before the metrics

-    // destructors are called.

-    stats_report::g_global_metrics.Uninitialize();

-  }

-

-  virtual void SetUp() {

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-    OverrideRegistryHives(kRegistryHiveOverrideRoot);

-

-    metric_worker_self_update_responses.Set(0);

-    metric_worker_self_update_response_time_since_first_ms.Set(0);

-    metric_worker_app_max_update_responses_app_high.Set(0);

-    metric_worker_app_max_update_responses.Set(0);

-    metric_worker_app_max_update_responses_ms_since_first.Set(0);

-

-    ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,

-                                      kRegValueProductVersion,

-                                      _T("0.1.0.0")));

-    ASSERT_SUCCEEDED(RegKey::SetValue(kApp1ClientsKeyPathUser,

-                                      kRegValueProductVersion,

-                                      _T("0.1")));

-

-    ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENT_STATE_GOOPDATE));

-    ASSERT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathUser));

-  }

-

-  int GetNumProducts() {

-    AppManager app_manager(is_machine_);

-    ProductDataVector products;

-    VERIFY1(SUCCEEDED(app_manager.GetRegisteredProducts(&products)));

-    return products.size();

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-  }

-

-  bool is_machine_;

-  scoped_ptr<AppManager> app_manager_;

-};

-

-TEST_F(RecordUpdateAvailableUsageStatsTest, NoData) {

-  ASSERT_EQ(2, GetNumProducts());

-

-  internal::RecordUpdateAvailableUsageStats(is_machine_);

-

-  EXPECT_EQ(0, metric_worker_self_update_responses.value());

-  EXPECT_EQ(0, metric_worker_self_update_response_time_since_first_ms.value());

-  EXPECT_EQ(0, metric_worker_app_max_update_responses_app_high.value());

-  EXPECT_EQ(0, metric_worker_app_max_update_responses.value());

-  EXPECT_EQ(0, metric_worker_app_max_update_responses_ms_since_first.value());

-}

-

-TEST_F(RecordUpdateAvailableUsageStatsTest, OmahaDataOnly) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(123456)));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(10)));

-

-  ASSERT_EQ(2, GetNumProducts());

-

-  const time64 current_time_100ns(GetCurrent100NSTime());

-  const uint64 expected_ms_since_first_update =

-      (current_time_100ns - 10) / kMillisecsTo100ns;

-

-  internal::RecordUpdateAvailableUsageStats(is_machine_);

-

-  EXPECT_EQ(123456, metric_worker_self_update_responses.value());

-

-  EXPECT_LE(expected_ms_since_first_update,

-            metric_worker_self_update_response_time_since_first_ms.value());

-  EXPECT_GT(expected_ms_since_first_update + 10 * kMsPerSec,

-            metric_worker_self_update_response_time_since_first_ms.value());

-

-  EXPECT_EQ(0, metric_worker_app_max_update_responses_app_high.value());

-  EXPECT_EQ(0, metric_worker_app_max_update_responses.value());

-  EXPECT_EQ(0, metric_worker_app_max_update_responses_ms_since_first.value());

-}

-

-TEST_F(RecordUpdateAvailableUsageStatsTest, OneAppOnly) {

-  ASSERT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(123456)));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(10)));

-

-  ASSERT_EQ(2, GetNumProducts());

-

-  const time64 current_time_100ns(GetCurrent100NSTime());

-  const uint64 expected_ms_since_first_update =

-      (current_time_100ns - 10) / kMillisecsTo100ns;

-

-  internal::RecordUpdateAvailableUsageStats(is_machine_);

-

-  EXPECT_EQ(0, metric_worker_self_update_responses.value());

-  EXPECT_EQ(0, metric_worker_self_update_response_time_since_first_ms.value());

-

-  EXPECT_EQ(kApp1GuidUpper,

-            metric_worker_app_max_update_responses_app_high.value());

-  EXPECT_EQ(123456, metric_worker_app_max_update_responses.value());

-  EXPECT_LE(expected_ms_since_first_update,

-            metric_worker_app_max_update_responses_ms_since_first.value());

-  EXPECT_GT(expected_ms_since_first_update + 10 * kMsPerSec,

-            metric_worker_app_max_update_responses_ms_since_first.value());

-}

-

-// It is important that Omaha's count is the largest.

-// All app data should be from app 2, which has the greatest count, a middle

-// time, and an alphabetically middle GUID

-TEST_F(RecordUpdateAvailableUsageStatsTest, OmahaAndSeveralApps) {

-  const DWORD64 kApp2SinceTime = 1000 * kSecsTo100ns;

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(kApp2ClientsKeyPathUser,

-                                    kRegValueProductVersion,

-                                    _T("1.2")));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kApp3ClientsKeyPathUser,

-                                    kRegValueProductVersion,

-                                    _T("2.3")));

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(0x99887766)));

-  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(1)));

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(1)));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(1)));

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(9876543)));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    kApp2SinceTime));

-

-  ASSERT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathUser,

-                                    _T("UpdateAvailableCount"),

-                                    static_cast<DWORD>(234)));

-  ASSERT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathUser,

-                                    _T("UpdateAvailableSince"),

-                                    static_cast<DWORD64>(128580000000000000)));

-

-  ASSERT_EQ(4, GetNumProducts());

-

-  const time64 current_time_100ns(GetCurrent100NSTime());

-  const uint64 goopdate_expected_ms_since_first_update =

-      (current_time_100ns - 1) / kMillisecsTo100ns;

-

-  const uint64 app_expected_ms_since_first_update =

-      (current_time_100ns - kApp2SinceTime) / kMillisecsTo100ns;

-

-  internal::RecordUpdateAvailableUsageStats(is_machine_);

-

-  EXPECT_EQ(0x99887766, metric_worker_self_update_responses.value());

-  EXPECT_LE(goopdate_expected_ms_since_first_update,

-            metric_worker_self_update_response_time_since_first_ms.value());

-  EXPECT_GT(goopdate_expected_ms_since_first_update + 10 * kMsPerSec,

-            metric_worker_self_update_response_time_since_first_ms.value());

-

-  EXPECT_EQ(kApp2GuidUpper,

-            metric_worker_app_max_update_responses_app_high.value());

-  EXPECT_EQ(9876543, metric_worker_app_max_update_responses.value());

-  EXPECT_LE(app_expected_ms_since_first_update,

-            metric_worker_app_max_update_responses_ms_since_first.value());

-  EXPECT_GT(app_expected_ms_since_first_update + 10 * kMsPerSec,

-            metric_worker_app_max_update_responses_ms_since_first.value());

-}

-

-class SendSelfUpdateFailurePingTest : public testing::Test {

- protected:

-  virtual void SetUp() {

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-    // Overriding HKLM prevents the Windows DNS resolver from working.

-    // Only override HKCU and run the tests as user.

-    OverrideSpecifiedRegistryHives(kRegistryHiveOverrideRoot, false, true);

-  }

-

-  virtual void TearDown() {

-    RestoreRegistryHives();

-    RegKey::DeleteKey(kRegistryHiveOverrideRoot);

-  }

-};

-

-TEST_F(SendSelfUpdateFailurePingTest, UserKeyDoesNotExist) {

-  ExpectAsserts expect_asserts;

-  internal::SendSelfUpdateFailurePing(false);

-}

-

-TEST_F(SendSelfUpdateFailurePingTest, MachineKeyDoesNotExist) {

-  OverrideRegistryHives(kRegistryHiveOverrideRoot);

-  ExpectAsserts expect_asserts;

-  internal::SendSelfUpdateFailurePing(true);

-}

-

-TEST_F(SendSelfUpdateFailurePingTest, UserUpdateErrorCodeDoesNotExist) {

-  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));

-  internal::SendSelfUpdateFailurePing(false);

-}

-

-TEST_F(SendSelfUpdateFailurePingTest, MachineUpdateErrorCodeDoesNotExist) {

-  OverrideRegistryHives(kRegistryHiveOverrideRoot);

-  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));

-  internal::SendSelfUpdateFailurePing(true);

-}

-

-TEST_F(SendSelfUpdateFailurePingTest, UserAllValuesPresent) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueSelfUpdateErrorCode,

-                                    static_cast<DWORD>(0x87654321)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueSelfUpdateExtraCode1,

-                                    static_cast<DWORD>(55)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,

-                                    kRegValueSelfUpdateVersion,

-                                    _T("0.2.4.8")));

-  internal::SendSelfUpdateFailurePing(false);

-}

-

-TEST_F(SendSelfUpdateFailurePingTest, UserValuesPresentInMachineOnly) {

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateErrorCode,

-                                    static_cast<DWORD>(0x87654321)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateExtraCode1,

-                                    static_cast<DWORD>(55)));

-  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,

-                                    kRegValueSelfUpdateVersion,

-                                    _T("0.2.4.8")));

-

-  ExpectAsserts expect_asserts;

-  internal::SendSelfUpdateFailurePing(false);

-

-  // Clean up HKLM, which isn't overridden.

-  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,

-                                       kRegValueSelfUpdateErrorCode));

-  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,

-                                       kRegValueSelfUpdateExtraCode1));

-  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,

-                                       kRegValueSelfUpdateVersion));

-}

-

-}  // namespace omaha

+// Copyright 2008-2009 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
+
+#include "omaha/common/time.h"
+#include "omaha/goopdate/stats_uploader.h"
+#include "omaha/statsreport/aggregator.h"
+#include "omaha/testing/unit_test.h"
+#include "omaha/worker/application_manager.h"
+#include "omaha/worker/worker.h"
+#include "omaha/worker/worker_metrics.h"
+#include "omaha/worker/worker-internal.h"
+
+namespace omaha {
+
+namespace {
+
+const TCHAR* const kDailyUsageStatsKeyPath =
+    _T("HKCU\\Software\\Google\\Update\\UsageStats\\Daily");
+
+// The alphabetical order of these is important for
+// RecordUpdateAvailableUsageStatsTest.
+const TCHAR* const kApp1 = _T("{0C480772-AC73-418f-9603-66303DA4C7AA}");
+const TCHAR* const kApp2 = _T("{89906BCD-4D12-4c9b-B5BA-8286051CB8D9}");
+const TCHAR* const kApp3 = _T("{F5A1FE97-CF5A-47b8-8B28-2A72F9A57A45}");
+
+const uint64 kApp1GuidUpper = 0x0C480772AC73418f;
+const uint64 kApp2GuidUpper = 0x89906BCD4D124c9b;
+
+const TCHAR* const kApp1ClientsKeyPathUser =
+    _T("HKCU\\Software\\Google\\Update\\Clients\\")
+    _T("{0C480772-AC73-418f-9603-66303DA4C7AA}");
+const TCHAR* const kApp2ClientsKeyPathUser =
+    _T("HKCU\\Software\\Google\\Update\\Clients\\")
+    _T("{89906BCD-4D12-4c9b-B5BA-8286051CB8D9}");
+const TCHAR* const kApp3ClientsKeyPathUser =
+    _T("HKCU\\Software\\Google\\Update\\Clients\\")
+    _T("{F5A1FE97-CF5A-47b8-8B28-2A72F9A57A45}");
+
+const TCHAR* const kApp1ClientStateKeyPathUser =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\")
+    _T("{0C480772-AC73-418f-9603-66303DA4C7AA}");
+const TCHAR* const kApp2ClientStateKeyPathUser =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\")
+    _T("{89906BCD-4D12-4c9b-B5BA-8286051CB8D9}");
+const TCHAR* const kApp3ClientStateKeyPathUser =
+    _T("HKCU\\Software\\Google\\Update\\ClientState\\")
+    _T("{F5A1FE97-CF5A-47b8-8B28-2A72F9A57A45}");
+
+}  // namespace
+
+class WorkerTest : public testing::Test {
+ protected:
+  Worker worker_;
+};
+
+// TODO(omaha): Test all methods of Worker
+
+class RecordUpdateAvailableUsageStatsTest : public testing::Test {
+ protected:
+  RecordUpdateAvailableUsageStatsTest() : is_machine_(false) {}
+
+  static void SetUpTestCase() {
+    // Initialize the global metrics collection.
+    stats_report::g_global_metrics.Initialize();
+  }
+
+  static void TearDownTestCase() {
+    // The global metrics collection must be uninitialized before the metrics
+    // destructors are called.
+    stats_report::g_global_metrics.Uninitialize();
+  }
+
+  virtual void SetUp() {
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+    OverrideRegistryHives(kRegistryHiveOverrideRoot);
+
+    metric_worker_self_update_responses.Set(0);
+    metric_worker_self_update_response_time_since_first_ms.Set(0);
+    metric_worker_app_max_update_responses_app_high.Set(0);
+    metric_worker_app_max_update_responses.Set(0);
+    metric_worker_app_max_update_responses_ms_since_first.Set(0);
+
+    ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENTS_GOOPDATE,
+                                      kRegValueProductVersion,
+                                      _T("0.1.0.0")));
+    ASSERT_SUCCEEDED(RegKey::SetValue(kApp1ClientsKeyPathUser,
+                                      kRegValueProductVersion,
+                                      _T("0.1")));
+
+    ASSERT_SUCCEEDED(RegKey::CreateKey(USER_REG_CLIENT_STATE_GOOPDATE));
+    ASSERT_SUCCEEDED(RegKey::CreateKey(kApp1ClientStateKeyPathUser));
+  }
+
+  int GetNumProducts() {
+    AppManager app_manager(is_machine_);
+    ProductDataVector products;
+    VERIFY1(SUCCEEDED(app_manager.GetRegisteredProducts(&products)));
+    return products.size();
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+  }
+
+  bool is_machine_;
+  scoped_ptr<AppManager> app_manager_;
+};
+
+TEST_F(RecordUpdateAvailableUsageStatsTest, NoData) {
+  ASSERT_EQ(2, GetNumProducts());
+
+  internal::RecordUpdateAvailableUsageStats(is_machine_);
+
+  EXPECT_EQ(0, metric_worker_self_update_responses.value());
+  EXPECT_EQ(0, metric_worker_self_update_response_time_since_first_ms.value());
+  EXPECT_EQ(0, metric_worker_app_max_update_responses_app_high.value());
+  EXPECT_EQ(0, metric_worker_app_max_update_responses.value());
+  EXPECT_EQ(0, metric_worker_app_max_update_responses_ms_since_first.value());
+}
+
+TEST_F(RecordUpdateAvailableUsageStatsTest, OmahaDataOnly) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(123456)));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(10)));
+
+  ASSERT_EQ(2, GetNumProducts());
+
+  const time64 current_time_100ns(GetCurrent100NSTime());
+  const uint64 expected_ms_since_first_update =
+      (current_time_100ns - 10) / kMillisecsTo100ns;
+
+  internal::RecordUpdateAvailableUsageStats(is_machine_);
+
+  EXPECT_EQ(123456, metric_worker_self_update_responses.value());
+
+  EXPECT_LE(expected_ms_since_first_update,
+            metric_worker_self_update_response_time_since_first_ms.value());
+  EXPECT_GT(expected_ms_since_first_update + 10 * kMsPerSec,
+            metric_worker_self_update_response_time_since_first_ms.value());
+
+  EXPECT_EQ(0, metric_worker_app_max_update_responses_app_high.value());
+  EXPECT_EQ(0, metric_worker_app_max_update_responses.value());
+  EXPECT_EQ(0, metric_worker_app_max_update_responses_ms_since_first.value());
+}
+
+TEST_F(RecordUpdateAvailableUsageStatsTest, OneAppOnly) {
+  ASSERT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(123456)));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(10)));
+
+  ASSERT_EQ(2, GetNumProducts());
+
+  const time64 current_time_100ns(GetCurrent100NSTime());
+  const uint64 expected_ms_since_first_update =
+      (current_time_100ns - 10) / kMillisecsTo100ns;
+
+  internal::RecordUpdateAvailableUsageStats(is_machine_);
+
+  EXPECT_EQ(0, metric_worker_self_update_responses.value());
+  EXPECT_EQ(0, metric_worker_self_update_response_time_since_first_ms.value());
+
+  EXPECT_EQ(kApp1GuidUpper,
+            metric_worker_app_max_update_responses_app_high.value());
+  EXPECT_EQ(123456, metric_worker_app_max_update_responses.value());
+  EXPECT_LE(expected_ms_since_first_update,
+            metric_worker_app_max_update_responses_ms_since_first.value());
+  EXPECT_GT(expected_ms_since_first_update + 10 * kMsPerSec,
+            metric_worker_app_max_update_responses_ms_since_first.value());
+}
+
+// It is important that Omaha's count is the largest.
+// All app data should be from app 2, which has the greatest count, a middle
+// time, and an alphabetically middle GUID
+TEST_F(RecordUpdateAvailableUsageStatsTest, OmahaAndSeveralApps) {
+  const DWORD64 kApp2SinceTime = 1000 * kSecsTo100ns;
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(kApp2ClientsKeyPathUser,
+                                    kRegValueProductVersion,
+                                    _T("1.2")));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kApp3ClientsKeyPathUser,
+                                    kRegValueProductVersion,
+                                    _T("2.3")));
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(0x99887766)));
+  ASSERT_SUCCEEDED(RegKey::SetValue(USER_REG_CLIENT_STATE_GOOPDATE,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(1)));
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(1)));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kApp1ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(1)));
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(9876543)));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kApp2ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    kApp2SinceTime));
+
+  ASSERT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathUser,
+                                    _T("UpdateAvailableCount"),
+                                    static_cast<DWORD>(234)));
+  ASSERT_SUCCEEDED(RegKey::SetValue(kApp3ClientStateKeyPathUser,
+                                    _T("UpdateAvailableSince"),
+                                    static_cast<DWORD64>(128580000000000000)));
+
+  ASSERT_EQ(4, GetNumProducts());
+
+  const time64 current_time_100ns(GetCurrent100NSTime());
+  const uint64 goopdate_expected_ms_since_first_update =
+      (current_time_100ns - 1) / kMillisecsTo100ns;
+
+  const uint64 app_expected_ms_since_first_update =
+      (current_time_100ns - kApp2SinceTime) / kMillisecsTo100ns;
+
+  internal::RecordUpdateAvailableUsageStats(is_machine_);
+
+  EXPECT_EQ(0x99887766, metric_worker_self_update_responses.value());
+  EXPECT_LE(goopdate_expected_ms_since_first_update,
+            metric_worker_self_update_response_time_since_first_ms.value());
+  EXPECT_GT(goopdate_expected_ms_since_first_update + 10 * kMsPerSec,
+            metric_worker_self_update_response_time_since_first_ms.value());
+
+  EXPECT_EQ(kApp2GuidUpper,
+            metric_worker_app_max_update_responses_app_high.value());
+  EXPECT_EQ(9876543, metric_worker_app_max_update_responses.value());
+  EXPECT_LE(app_expected_ms_since_first_update,
+            metric_worker_app_max_update_responses_ms_since_first.value());
+  EXPECT_GT(app_expected_ms_since_first_update + 10 * kMsPerSec,
+            metric_worker_app_max_update_responses_ms_since_first.value());
+}
+
+class SendSelfUpdateFailurePingTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+    // Overriding HKLM prevents the Windows DNS resolver from working.
+    // Only override HKCU and run the tests as user.
+    OverrideSpecifiedRegistryHives(kRegistryHiveOverrideRoot, false, true);
+  }
+
+  virtual void TearDown() {
+    RestoreRegistryHives();
+    RegKey::DeleteKey(kRegistryHiveOverrideRoot);
+  }
+};
+
+TEST_F(SendSelfUpdateFailurePingTest, UserKeyDoesNotExist) {
+  ExpectAsserts expect_asserts;
+  internal::SendSelfUpdateFailurePing(false);
+}
+
+TEST_F(SendSelfUpdateFailurePingTest, MachineKeyDoesNotExist) {
+  OverrideRegistryHives(kRegistryHiveOverrideRoot);
+  ExpectAsserts expect_asserts;
+  internal::SendSelfUpdateFailurePing(true);
+}
+
+TEST_F(SendSelfUpdateFailurePingTest, UserUpdateErrorCodeDoesNotExist) {
+  EXPECT_SUCCEEDED(RegKey::CreateKey(USER_REG_UPDATE));
+  internal::SendSelfUpdateFailurePing(false);
+}
+
+TEST_F(SendSelfUpdateFailurePingTest, MachineUpdateErrorCodeDoesNotExist) {
+  OverrideRegistryHives(kRegistryHiveOverrideRoot);
+  EXPECT_SUCCEEDED(RegKey::CreateKey(MACHINE_REG_UPDATE));
+  internal::SendSelfUpdateFailurePing(true);
+}
+
+TEST_F(SendSelfUpdateFailurePingTest, UserAllValuesPresent) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueSelfUpdateErrorCode,
+                                    static_cast<DWORD>(0x87654321)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueSelfUpdateExtraCode1,
+                                    static_cast<DWORD>(55)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(USER_REG_UPDATE,
+                                    kRegValueSelfUpdateVersion,
+                                    _T("0.2.4.8")));
+  internal::SendSelfUpdateFailurePing(false);
+}
+
+TEST_F(SendSelfUpdateFailurePingTest, UserValuesPresentInMachineOnly) {
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateErrorCode,
+                                    static_cast<DWORD>(0x87654321)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateExtraCode1,
+                                    static_cast<DWORD>(55)));
+  EXPECT_SUCCEEDED(RegKey::SetValue(MACHINE_REG_UPDATE,
+                                    kRegValueSelfUpdateVersion,
+                                    _T("0.2.4.8")));
+
+  ExpectAsserts expect_asserts;
+  internal::SendSelfUpdateFailurePing(false);
+
+  // Clean up HKLM, which isn't overridden.
+  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,
+                                       kRegValueSelfUpdateErrorCode));
+  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,
+                                       kRegValueSelfUpdateExtraCode1));
+  EXPECT_SUCCEEDED(RegKey::DeleteValue(MACHINE_REG_UPDATE,
+                                       kRegValueSelfUpdateVersion));
+}
+
+}  // namespace omaha